From 606689e9f8c52b537c85fd4bc1ba5ce7b3ee2678 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 28 Feb 2009 17:33:52 +0000 Subject: ASoC: Add Openmoko Neo FreeRunner (GTA02) audio driver This driver supports the audio subsystem on the Openmoko Neo FreeRunner smartphone, often known by its codename GTA02. The system has a WM8753 connected to a Samsung S3C2442 with an external GPIO controlled speaker amplifier. The driver was originally written by Graeme Gregory and has recieved contributions from Openmoko, myself and members of the Openmoko community. For much of this time the primary Openmoko kernel maintainer was Andy Green. Signed-off-by: Graeme Gregory Signed-off-by: Andy Green Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index df494d1..d1ed0f5 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -38,6 +38,15 @@ config SND_S3C24XX_SOC_NEO1973_WM8753 Say Y if you want to add support for SoC audio on smdk2440 with the WM8753. +config SND_S3C24XX_SOC_NEO1973_GTA02_WM8753 + tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)" + depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA02 + select SND_S3C24XX_SOC_I2S + select SND_SOC_WM8753 + help + This driver provides audio support for the Openmoko Neo FreeRunner + smartphone. + config SND_S3C24XX_SOC_JIVE_WM8750 tristate "SoC I2S Audio support for Jive" depends on SND_S3C24XX_SOC && MACH_JIVE diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 07a93a2..eb219b0 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -16,12 +16,14 @@ obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o # S3C24XX Machine Support snd-soc-jive-wm8750-objs := jive_wm8750.o snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o +snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o +obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c new file mode 100644 index 0000000..1358f6f --- /dev/null +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c @@ -0,0 +1,481 @@ +/* + * neo1973_gta02_wm8753.c -- SoC audio for Neo1973 + * + * Copyright 2007 Openmoko Inc + * Author: Graeme Gregory + * Copyright 2007 Wolfson Microelectronics PLC. + * Author: Graeme Gregory + * Copyright 2009 Wolfson Microelectronics + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include "../codecs/wm8753.h" +#include "s3c24xx-pcm.h" +#include "s3c24xx-i2s.h" + +static struct snd_soc_card neo1973_gta02; + +static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int pll_out = 0, bclk = 0; + int ret = 0; + unsigned long iis_clkrate; + + iis_clkrate = s3c24xx_i2s_get_clockrate(); + + switch (params_rate(params)) { + case 8000: + case 16000: + pll_out = 12288000; + break; + case 48000: + bclk = WM8753_BCLK_DIV_4; + pll_out = 12288000; + break; + case 96000: + bclk = WM8753_BCLK_DIV_2; + pll_out = 12288000; + break; + case 11025: + bclk = WM8753_BCLK_DIV_16; + pll_out = 11289600; + break; + case 22050: + bclk = WM8753_BCLK_DIV_8; + pll_out = 11289600; + break; + case 44100: + bclk = WM8753_BCLK_DIV_4; + pll_out = 11289600; + break; + case 88200: + bclk = WM8753_BCLK_DIV_2; + pll_out = 11289600; + break; + } + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + /* set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* set MCLK division for sample rate */ + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, + S3C2410_IISMOD_32FS); + if (ret < 0) + return ret; + + /* set codec BCLK division for sample rate */ + ret = snd_soc_dai_set_clkdiv(codec_dai, + WM8753_BCLKDIV, bclk); + if (ret < 0) + return ret; + + /* set prescaler division for sample rate */ + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, + S3C24XX_PRESCALE(4, 4)); + if (ret < 0) + return ret; + + /* codec PLL input is PCLK/4 */ + ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, + iis_clkrate / 4, pll_out); + if (ret < 0) + return ret; + + return 0; +} + +static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + + /* disable the PLL */ + return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); +} + +/* + * Neo1973 WM8753 HiFi DAI opserations. + */ +static struct snd_soc_ops neo1973_gta02_hifi_ops = { + .hw_params = neo1973_gta02_hifi_hw_params, + .hw_free = neo1973_gta02_hifi_hw_free, +}; + +static int neo1973_gta02_voice_hw_params( + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + unsigned int pcmdiv = 0; + int ret = 0; + unsigned long iis_clkrate; + + iis_clkrate = s3c24xx_i2s_get_clockrate(); + + if (params_rate(params) != 8000) + return -EINVAL; + if (params_channels(params) != 1) + return -EINVAL; + + pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */ + + /* todo: gg check mode (DSP_B) against CSR datasheet */ + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, + 12288000, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* set codec PCM division for sample rate */ + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, + pcmdiv); + if (ret < 0) + return ret; + + /* configue and enable PLL for 12.288MHz output */ + ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, + iis_clkrate / 4, 12288000); + if (ret < 0) + return ret; + + return 0; +} + +static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + + /* disable the PLL */ + return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); +} + +static struct snd_soc_ops neo1973_gta02_voice_ops = { + .hw_params = neo1973_gta02_voice_hw_params, + .hw_free = neo1973_gta02_voice_hw_free, +}; + +#define LM4853_AMP 1 +#define LM4853_SPK 2 + +static u8 lm4853_state; + +/* This has no effect, it exists only to maintain compatibility with + * existing ALSA state files. + */ +static int lm4853_set_state(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int val = ucontrol->value.integer.value[0]; + + if (val) + lm4853_state |= LM4853_AMP; + else + lm4853_state &= ~LM4853_AMP; + + return 0; +} + +static int lm4853_get_state(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = lm4853_state & LM4853_AMP; + + return 0; +} + +static int lm4853_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int val = ucontrol->value.integer.value[0]; + + if (val) { + lm4853_state |= LM4853_SPK; + s3c2410_gpio_setpin(GTA02_GPIO_HP_IN, 0); + } else { + lm4853_state &= ~LM4853_SPK; + s3c2410_gpio_setpin(GTA02_GPIO_HP_IN, 1); + } + + return 0; +} + +static int lm4853_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = (lm4853_state & LM4853_SPK) >> 1; + + return 0; +} + +static int lm4853_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + s3c2410_gpio_setpin(GTA02_GPIO_AMP_SHUT, 0); + + if (SND_SOC_DAPM_EVENT_OFF(event)) + s3c2410_gpio_setpin(GTA02_GPIO_AMP_SHUT, 1); + + return 0; +} + +static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), + SND_SOC_DAPM_LINE("GSM Line Out", NULL), + SND_SOC_DAPM_LINE("GSM Line In", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Handset Mic", NULL), + SND_SOC_DAPM_SPK("Handset Spk", NULL), +}; + + +/* example machine audio_mapnections */ +static const struct snd_soc_dapm_route audio_map[] = { + + /* Connections to the lm4853 amp */ + {"Stereo Out", NULL, "LOUT1"}, + {"Stereo Out", NULL, "ROUT1"}, + + /* Connections to the GSM Module */ + {"GSM Line Out", NULL, "MONO1"}, + {"GSM Line Out", NULL, "MONO2"}, + {"RXP", NULL, "GSM Line In"}, + {"RXN", NULL, "GSM Line In"}, + + /* Connections to Headset */ + {"MIC1", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Headset Mic"}, + + /* Call Mic */ + {"MIC2", NULL, "Mic Bias"}, + {"MIC2N", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Handset Mic"}, + + /* Call Speaker */ + {"Handset Spk", NULL, "LOUT2"}, + {"Handset Spk", NULL, "ROUT2"}, + + /* Connect the ALC pins */ + {"ACIN", NULL, "ACOP"}, +}; + +static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = { + SOC_DAPM_PIN_SWITCH("Stereo Out"), + SOC_DAPM_PIN_SWITCH("GSM Line Out"), + SOC_DAPM_PIN_SWITCH("GSM Line In"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Handset Mic"), + SOC_DAPM_PIN_SWITCH("Handset Spk"), + + /* This has no effect, it exists only to maintain compatibility with + * existing ALSA state files. + */ + SOC_SINGLE_EXT("Amp State Switch", 6, 0, 1, 0, + lm4853_get_state, + lm4853_set_state), + SOC_SINGLE_EXT("Amp Spk Switch", 7, 0, 1, 0, + lm4853_get_spk, + lm4853_set_spk), +}; + +/* + * This is an example machine initialisation for a wm8753 connected to a + * neo1973 GTA02. + */ +static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) +{ + int i, err; + + /* set up NC codec pins */ + snd_soc_dapm_nc_pin(codec, "OUT3"); + snd_soc_dapm_nc_pin(codec, "OUT4"); + snd_soc_dapm_nc_pin(codec, "LINE1"); + snd_soc_dapm_nc_pin(codec, "LINE2"); + + /* Add neo1973 gta02 specific widgets */ + snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, + ARRAY_SIZE(wm8753_dapm_widgets)); + + /* add neo1973 gta02 specific controls */ + for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_gta02_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8753_neo1973_gta02_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + + /* set up neo1973 gta02 specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + /* set endpoints to default off mode */ + snd_soc_dapm_disable_pin(codec, "Stereo Out"); + snd_soc_dapm_disable_pin(codec, "GSM Line Out"); + snd_soc_dapm_disable_pin(codec, "GSM Line In"); + snd_soc_dapm_disable_pin(codec, "Headset Mic"); + snd_soc_dapm_disable_pin(codec, "Handset Mic"); + snd_soc_dapm_disable_pin(codec, "Handset Spk"); + + snd_soc_dapm_sync(codec); + + return 0; +} + +/* + * BT Codec DAI + */ +static struct snd_soc_dai bt_dai = { + .name = "Bluetooth", + .id = 0, + .playback = { + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .capture = { + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, +}; + +static struct snd_soc_dai_link neo1973_gta02_dai[] = { +{ /* Hifi Playback - for similatious use with voice below */ + .name = "WM8753", + .stream_name = "WM8753 HiFi", + .cpu_dai = &s3c24xx_i2s_dai, + .codec_dai = &wm8753_dai[WM8753_DAI_HIFI], + .init = neo1973_gta02_wm8753_init, + .ops = &neo1973_gta02_hifi_ops, +}, +{ /* Voice via BT */ + .name = "Bluetooth", + .stream_name = "Voice", + .cpu_dai = &bt_dai, + .codec_dai = &wm8753_dai[WM8753_DAI_VOICE], + .ops = &neo1973_gta02_voice_ops, +}, +}; + +static struct snd_soc_card neo1973_gta02 = { + .name = "neo1973-gta02", + .platform = &s3c24xx_soc_platform, + .dai_link = neo1973_gta02_dai, + .num_links = ARRAY_SIZE(neo1973_gta02_dai), +}; + +static struct snd_soc_device neo1973_gta02_snd_devdata = { + .card = &neo1973_gta02, + .codec_dev = &soc_codec_dev_wm8753, +}; + +static struct platform_device *neo1973_gta02_snd_device; + +static int __init neo1973_gta02_init(void) +{ + int ret; + + if (!machine_is_neo1973_gta02()) { + printk(KERN_INFO + "Only GTA02 is supported by this ASoC driver\n"); + return -ENODEV; + } + + /* register bluetooth DAI here */ + ret = snd_soc_register_dai(&bt_dai); + if (ret) + return ret; + + neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1); + if (!neo1973_gta02_snd_device) + return -ENOMEM; + + platform_set_drvdata(neo1973_gta02_snd_device, + &neo1973_gta02_snd_devdata); + neo1973_gta02_snd_devdata.dev = &neo1973_gta02_snd_device->dev; + ret = platform_device_add(neo1973_gta02_snd_device); + + if (ret) { + platform_device_put(neo1973_gta02_snd_device); + return ret; + } + + /* Initialise GPIOs used by amp */ + s3c2410_gpio_cfgpin(GTA02_GPIO_HP_IN, S3C2410_GPIO_OUTPUT); + s3c2410_gpio_cfgpin(GTA02_GPIO_AMP_SHUT, S3C2410_GPIO_OUTPUT); + + /* Amp off by default */ + s3c2410_gpio_setpin(GTA02_GPIO_AMP_SHUT, 1); + + /* Speaker off by default */ + s3c2410_gpio_setpin(GTA02_GPIO_HP_IN, 1); + + return ret; +} +module_init(neo1973_gta02_init); + +static void __exit neo1973_gta02_exit(void) +{ + snd_soc_unregister_dai(&bt_dai); + platform_device_unregister(neo1973_gta02_snd_device); +} +module_exit(neo1973_gta02_exit); + +/* Module information */ +MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org"); +MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 GTA02"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 0a1bf553359013621c8c5cf745354212c6ef51d3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 23 May 2009 11:18:41 +0100 Subject: ASoC: Add WM8974 CODEC driver The WM8974 is a low power, high quality mono CODEC designed for portable applications such as digital still cameras or digital voice recorders. This driver was originally written by Graeme Gregory and Liam Girdwood and has since been maintained by myself with some updates contributed by Brett Saunders and Javier Martin. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7f78b65..91daffd 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -38,6 +38,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8940 if I2C select SND_SOC_WM8960 if I2C select SND_SOC_WM8971 if I2C + select SND_SOC_WM8974 if I2C select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8990 if I2C select SND_SOC_WM9081 if I2C @@ -151,6 +152,9 @@ config SND_SOC_WM8960 config SND_SOC_WM8971 tristate +config SND_SOC_WM8974 + tristate + config SND_SOC_WM8988 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 70c55fa..9c67d66 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -26,6 +26,7 @@ snd-soc-wm8903-objs := wm8903.o snd-soc-wm8940-objs := wm8940.o snd-soc-wm8960-objs := wm8960.o snd-soc-wm8971-objs := wm8971.o +snd-soc-wm8974-objs := wm8974.o snd-soc-wm8988-objs := wm8988.o snd-soc-wm8990-objs := wm8990.o snd-soc-wm9081-objs := wm9081.o @@ -59,6 +60,7 @@ obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o +obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c new file mode 100644 index 0000000..2b0c99c --- /dev/null +++ b/sound/soc/codecs/wm8974.c @@ -0,0 +1,844 @@ +/* + * wm8974.c -- WM8974 ALSA Soc Audio driver + * + * Copyright 2006 Wolfson Microelectronics PLC. + * + * Author: Liam Girdwood + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8974.h" + +#define AUDIO_NAME "wm8974" +#define WM8974_VERSION "0.6" + +struct snd_soc_codec_device soc_codec_dev_wm8974; + +/* + * wm8974 register cache + * We can't read the WM8974 register space when we are + * using 2 wire for device control, so we cache them instead. + */ +static const u16 wm8974_reg[WM8974_CACHEREGNUM] = { + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0050, 0x0000, 0x0140, 0x0000, + 0x0000, 0x0000, 0x0000, 0x00ff, + 0x0000, 0x0000, 0x0100, 0x00ff, + 0x0000, 0x0000, 0x012c, 0x002c, + 0x002c, 0x002c, 0x002c, 0x0000, + 0x0032, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0038, 0x000b, 0x0032, 0x0000, + 0x0008, 0x000c, 0x0093, 0x00e9, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0003, 0x0010, 0x0000, 0x0000, + 0x0000, 0x0002, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0039, 0x0000, + 0x0000, +}; + +/* + * read wm8974 register cache + */ +static inline unsigned int wm8974_read_reg_cache(struct snd_soc_codec * codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg == WM8974_RESET) + return 0; + if (reg >= WM8974_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8974 register cache + */ +static inline void wm8974_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8974_CACHEREGNUM) + return; + cache[reg] = value; +} + +/* + * write to the WM8974 register space + */ +static int wm8974_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8974 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8974_write_reg_cache (codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8974_reset(c) wm8974_write(c, WM8974_RESET, 0) + +static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" }; +static const char *wm8974_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" }; +static const char *wm8974_eqmode[] = {"Capture", "Playback" }; +static const char *wm8974_bw[] = {"Narrow", "Wide" }; +static const char *wm8974_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz" }; +static const char *wm8974_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz" }; +static const char *wm8974_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz" }; +static const char *wm8974_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" }; +static const char *wm8974_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz" }; +static const char *wm8974_alc[] = {"ALC", "Limiter" }; + +static const struct soc_enum wm8974_enum[] = { + SOC_ENUM_SINGLE(WM8974_COMP, 1, 4, wm8974_companding), /* adc */ + SOC_ENUM_SINGLE(WM8974_COMP, 3, 4, wm8974_companding), /* dac */ + SOC_ENUM_SINGLE(WM8974_DAC, 4, 4, wm8974_deemp), + SOC_ENUM_SINGLE(WM8974_EQ1, 8, 2, wm8974_eqmode), + + SOC_ENUM_SINGLE(WM8974_EQ1, 5, 4, wm8974_eq1), + SOC_ENUM_SINGLE(WM8974_EQ2, 8, 2, wm8974_bw), + SOC_ENUM_SINGLE(WM8974_EQ2, 5, 4, wm8974_eq2), + SOC_ENUM_SINGLE(WM8974_EQ3, 8, 2, wm8974_bw), + + SOC_ENUM_SINGLE(WM8974_EQ3, 5, 4, wm8974_eq3), + SOC_ENUM_SINGLE(WM8974_EQ4, 8, 2, wm8974_bw), + SOC_ENUM_SINGLE(WM8974_EQ4, 5, 4, wm8974_eq4), + SOC_ENUM_SINGLE(WM8974_EQ5, 8, 2, wm8974_bw), + + SOC_ENUM_SINGLE(WM8974_EQ5, 5, 4, wm8974_eq5), + SOC_ENUM_SINGLE(WM8974_ALC3, 8, 2, wm8974_alc), +}; + +static const struct snd_kcontrol_new wm8974_snd_controls[] = { + +SOC_SINGLE("Digital Loopback Switch", WM8974_COMP, 0, 1, 0), + +SOC_ENUM("DAC Companding", wm8974_enum[1]), +SOC_ENUM("ADC Companding", wm8974_enum[0]), + +SOC_ENUM("Playback De-emphasis", wm8974_enum[2]), +SOC_SINGLE("DAC Inversion Switch", WM8974_DAC, 0, 1, 0), + +SOC_SINGLE("PCM Volume", WM8974_DACVOL, 0, 127, 0), + +SOC_SINGLE("High Pass Filter Switch", WM8974_ADC, 8, 1, 0), +SOC_SINGLE("High Pass Cut Off", WM8974_ADC, 4, 7, 0), +SOC_SINGLE("ADC Inversion Switch", WM8974_COMP, 0, 1, 0), + +SOC_SINGLE("Capture Volume", WM8974_ADCVOL, 0, 127, 0), + +SOC_ENUM("Equaliser Function", wm8974_enum[3]), +SOC_ENUM("EQ1 Cut Off", wm8974_enum[4]), +SOC_SINGLE("EQ1 Volume", WM8974_EQ1, 0, 31, 1), + +SOC_ENUM("Equaliser EQ2 Bandwith", wm8974_enum[5]), +SOC_ENUM("EQ2 Cut Off", wm8974_enum[6]), +SOC_SINGLE("EQ2 Volume", WM8974_EQ2, 0, 31, 1), + +SOC_ENUM("Equaliser EQ3 Bandwith", wm8974_enum[7]), +SOC_ENUM("EQ3 Cut Off", wm8974_enum[8]), +SOC_SINGLE("EQ3 Volume", WM8974_EQ3, 0, 31, 1), + +SOC_ENUM("Equaliser EQ4 Bandwith", wm8974_enum[9]), +SOC_ENUM("EQ4 Cut Off", wm8974_enum[10]), +SOC_SINGLE("EQ4 Volume", WM8974_EQ4, 0, 31, 1), + +SOC_ENUM("Equaliser EQ5 Bandwith", wm8974_enum[11]), +SOC_ENUM("EQ5 Cut Off", wm8974_enum[12]), +SOC_SINGLE("EQ5 Volume", WM8974_EQ5, 0, 31, 1), + +SOC_SINGLE("DAC Playback Limiter Switch", WM8974_DACLIM1, 8, 1, 0), +SOC_SINGLE("DAC Playback Limiter Decay", WM8974_DACLIM1, 4, 15, 0), +SOC_SINGLE("DAC Playback Limiter Attack", WM8974_DACLIM1, 0, 15, 0), + +SOC_SINGLE("DAC Playback Limiter Threshold", WM8974_DACLIM2, 4, 7, 0), +SOC_SINGLE("DAC Playback Limiter Boost", WM8974_DACLIM2, 0, 15, 0), + +SOC_SINGLE("ALC Enable Switch", WM8974_ALC1, 8, 1, 0), +SOC_SINGLE("ALC Capture Max Gain", WM8974_ALC1, 3, 7, 0), +SOC_SINGLE("ALC Capture Min Gain", WM8974_ALC1, 0, 7, 0), + +SOC_SINGLE("ALC Capture ZC Switch", WM8974_ALC2, 8, 1, 0), +SOC_SINGLE("ALC Capture Hold", WM8974_ALC2, 4, 7, 0), +SOC_SINGLE("ALC Capture Target", WM8974_ALC2, 0, 15, 0), + +SOC_ENUM("ALC Capture Mode", wm8974_enum[13]), +SOC_SINGLE("ALC Capture Decay", WM8974_ALC3, 4, 15, 0), +SOC_SINGLE("ALC Capture Attack", WM8974_ALC3, 0, 15, 0), + +SOC_SINGLE("ALC Capture Noise Gate Switch", WM8974_NGATE, 3, 1, 0), +SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8974_NGATE, 0, 7, 0), + +SOC_SINGLE("Capture PGA ZC Switch", WM8974_INPPGA, 7, 1, 0), +SOC_SINGLE("Capture PGA Volume", WM8974_INPPGA, 0, 63, 0), + +SOC_SINGLE("Speaker Playback ZC Switch", WM8974_SPKVOL, 7, 1, 0), +SOC_SINGLE("Speaker Playback Switch", WM8974_SPKVOL, 6, 1, 1), +SOC_SINGLE("Speaker Playback Volume", WM8974_SPKVOL, 0, 63, 0), + +SOC_SINGLE("Capture Boost(+20dB)", WM8974_ADCBOOST, 8, 1, 0), +SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 0), +}; + +/* add non dapm controls */ +static int wm8974_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm8974_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8974_snd_controls[i],codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +/* Speaker Output Mixer */ +static const struct snd_kcontrol_new wm8974_speaker_mixer_controls[] = { +SOC_DAPM_SINGLE("Line Bypass Switch", WM8974_SPKMIX, 1, 1, 0), +SOC_DAPM_SINGLE("Aux Playback Switch", WM8974_SPKMIX, 5, 1, 0), +SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_SPKMIX, 0, 1, 1), +}; + +/* Mono Output Mixer */ +static const struct snd_kcontrol_new wm8974_mono_mixer_controls[] = { +SOC_DAPM_SINGLE("Line Bypass Switch", WM8974_MONOMIX, 1, 1, 0), +SOC_DAPM_SINGLE("Aux Playback Switch", WM8974_MONOMIX, 2, 1, 0), +SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_MONOMIX, 0, 1, 1), +}; + +/* AUX Input boost vol */ +static const struct snd_kcontrol_new wm8974_aux_boost_controls = +SOC_DAPM_SINGLE("Aux Volume", WM8974_ADCBOOST, 0, 7, 0); + +/* Mic Input boost vol */ +static const struct snd_kcontrol_new wm8974_mic_boost_controls = +SOC_DAPM_SINGLE("Mic Volume", WM8974_ADCBOOST, 4, 7, 0); + +/* Capture boost switch */ +static const struct snd_kcontrol_new wm8974_capture_boost_controls = +SOC_DAPM_SINGLE("Capture Boost Switch", WM8974_INPPGA, 6, 1, 0); + +/* Aux In to PGA */ +static const struct snd_kcontrol_new wm8974_aux_capture_boost_controls = +SOC_DAPM_SINGLE("Aux Capture Boost Switch", WM8974_INPPGA, 2, 1, 0); + +/* Mic P In to PGA */ +static const struct snd_kcontrol_new wm8974_micp_capture_boost_controls = +SOC_DAPM_SINGLE("Mic P Capture Boost Switch", WM8974_INPPGA, 0, 1, 0); + +/* Mic N In to PGA */ +static const struct snd_kcontrol_new wm8974_micn_capture_boost_controls = +SOC_DAPM_SINGLE("Mic N Capture Boost Switch", WM8974_INPPGA, 1, 1, 0); + +static const struct snd_soc_dapm_widget wm8974_dapm_widgets[] = { +SND_SOC_DAPM_MIXER("Speaker Mixer", WM8974_POWER3, 2, 0, + &wm8974_speaker_mixer_controls[0], + ARRAY_SIZE(wm8974_speaker_mixer_controls)), +SND_SOC_DAPM_MIXER("Mono Mixer", WM8974_POWER3, 3, 0, + &wm8974_mono_mixer_controls[0], + ARRAY_SIZE(wm8974_mono_mixer_controls)), +SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8974_POWER3, 0, 0), +SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8974_POWER3, 0, 0), +SND_SOC_DAPM_PGA("Aux Input", WM8974_POWER1, 6, 0, NULL, 0), +SND_SOC_DAPM_PGA("SpkN Out", WM8974_POWER3, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA("SpkP Out", WM8974_POWER3, 6, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mono Out", WM8974_POWER3, 7, 0, NULL, 0), +SND_SOC_DAPM_PGA("Mic PGA", WM8974_POWER2, 2, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Aux Boost", SND_SOC_NOPM, 0, 0, + &wm8974_aux_boost_controls, 1), +SND_SOC_DAPM_PGA("Mic Boost", SND_SOC_NOPM, 0, 0, + &wm8974_mic_boost_controls, 1), +SND_SOC_DAPM_SWITCH("Capture Boost", SND_SOC_NOPM, 0, 0, + &wm8974_capture_boost_controls), + +SND_SOC_DAPM_MIXER("Boost Mixer", WM8974_POWER2, 4, 0, NULL, 0), + +SND_SOC_DAPM_MICBIAS("Mic Bias", WM8974_POWER1, 4, 0), + +SND_SOC_DAPM_INPUT("MICN"), +SND_SOC_DAPM_INPUT("MICP"), +SND_SOC_DAPM_INPUT("AUX"), +SND_SOC_DAPM_OUTPUT("MONOOUT"), +SND_SOC_DAPM_OUTPUT("SPKOUTP"), +SND_SOC_DAPM_OUTPUT("SPKOUTN"), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* Mono output mixer */ + {"Mono Mixer", "PCM Playback Switch", "DAC"}, + {"Mono Mixer", "Aux Playback Switch", "Aux Input"}, + {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"}, + + /* Speaker output mixer */ + {"Speaker Mixer", "PCM Playback Switch", "DAC"}, + {"Speaker Mixer", "Aux Playback Switch", "Aux Input"}, + {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"}, + + /* Outputs */ + {"Mono Out", NULL, "Mono Mixer"}, + {"MONOOUT", NULL, "Mono Out"}, + {"SpkN Out", NULL, "Speaker Mixer"}, + {"SpkP Out", NULL, "Speaker Mixer"}, + {"SPKOUTN", NULL, "SpkN Out"}, + {"SPKOUTP", NULL, "SpkP Out"}, + + /* Boost Mixer */ + {"Boost Mixer", NULL, "ADC"}, + {"Capture Boost Switch", "Aux Capture Boost Switch", "AUX"}, + {"Aux Boost", "Aux Volume", "Boost Mixer"}, + {"Capture Boost", "Capture Switch", "Boost Mixer"}, + {"Mic Boost", "Mic Volume", "Boost Mixer"}, + + /* Inputs */ + {"MICP", NULL, "Mic Boost"}, + {"MICN", NULL, "Mic PGA"}, + {"Mic PGA", NULL, "Capture Boost"}, + {"AUX", NULL, "Aux Input"}, +}; + +static int wm8974_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, wm8974_dapm_widgets, + ARRAY_SIZE(wm8974_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +struct pll_ { + unsigned int in_hz, out_hz; + unsigned int pre:4; /* prescale - 1 */ + unsigned int n:4; + unsigned int k; +}; + +static struct pll_ pll[] = { + {12000000, 11289600, 0, 7, 0x86c220}, + {12000000, 12288000, 0, 8, 0x3126e8}, + {13000000, 11289600, 0, 6, 0xf28bd4}, + {13000000, 12288000, 0, 7, 0x8fd525}, + {12288000, 11289600, 0, 7, 0x59999a}, + {11289600, 12288000, 0, 8, 0x80dee9}, + /* liam - add more entries */ +}; + +static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int i; + u16 reg; + + if(freq_in == 0 || freq_out == 0) { + reg = wm8974_read_reg_cache(codec, WM8974_POWER1); + wm8974_write(codec, WM8974_POWER1, reg & 0x1df); + return 0; + } + + for(i = 0; i < ARRAY_SIZE(pll); i++) { + if (freq_in == pll[i].in_hz && freq_out == pll[i].out_hz) { + wm8974_write(codec, WM8974_PLLN, (pll[i].pre << 4) | pll[i].n); + wm8974_write(codec, WM8974_PLLK1, pll[i].k >> 18); + wm8974_write(codec, WM8974_PLLK2, (pll[i].k >> 9) & 0x1ff); + wm8974_write(codec, WM8974_PLLK3, pll[i].k & 0x1ff); + reg = wm8974_read_reg_cache(codec, WM8974_POWER1); + wm8974_write(codec, WM8974_POWER1, reg | 0x020); + return 0; + } + } + return -EINVAL; +} + +/* + * Configure WM8974 clock dividers. + */ +static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai, + int div_id, int div) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 reg; + + switch (div_id) { + case WM8974_OPCLKDIV: + reg = wm8974_read_reg_cache(codec, WM8974_GPIO) & 0x1cf; + wm8974_write(codec, WM8974_GPIO, reg | div); + break; + case WM8974_MCLKDIV: + reg = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x11f; + wm8974_write(codec, WM8974_CLOCK, reg | div); + break; + case WM8974_ADCCLK: + reg = wm8974_read_reg_cache(codec, WM8974_ADC) & 0x1f7; + wm8974_write(codec, WM8974_ADC, reg | div); + break; + case WM8974_DACCLK: + reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0x1f7; + wm8974_write(codec, WM8974_DAC, reg | div); + break; + case WM8974_BCLKDIV: + reg = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x1e3; + wm8974_write(codec, WM8974_CLOCK, reg | div); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = 0; + u16 clk = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x1fe; + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + clk |= 0x0001; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0010; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0008; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x00018; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x0180; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0100; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x0080; + break; + default: + return -EINVAL; + } + + wm8974_write(codec, WM8974_IFACE, iface); + wm8974_write(codec, WM8974_CLOCK, clk); + return 0; +} + +static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + u16 iface = wm8974_read_reg_cache(codec, WM8974_IFACE) & 0x19f; + u16 adn = wm8974_read_reg_cache(codec, WM8974_ADD) & 0x1f1; + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x0020; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x0040; + break; + case SNDRV_PCM_FORMAT_S32_LE: + iface |= 0x0060; + break; + } + + /* filter coefficient */ + switch (params_rate(params)) { + case SNDRV_PCM_RATE_8000: + adn |= 0x5 << 1; + break; + case SNDRV_PCM_RATE_11025: + adn |= 0x4 << 1; + break; + case SNDRV_PCM_RATE_16000: + adn |= 0x3 << 1; + break; + case SNDRV_PCM_RATE_22050: + adn |= 0x2 << 1; + break; + case SNDRV_PCM_RATE_32000: + adn |= 0x1 << 1; + break; + case SNDRV_PCM_RATE_44100: + break; + } + + wm8974_write(codec, WM8974_IFACE, iface); + wm8974_write(codec, WM8974_ADD, adn); + return 0; +} + +static int wm8974_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf; + + if(mute) + wm8974_write(codec, WM8974_DAC, mute_reg | 0x40); + else + wm8974_write(codec, WM8974_DAC, mute_reg); + return 0; +} + +/* liam need to make this lower power with dapm */ +static int wm8974_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + wm8974_write(codec, WM8974_POWER1, 0x1ff); + wm8974_write(codec, WM8974_POWER2, 0x1ff); + wm8974_write(codec, WM8974_POWER3, 0x1ff); + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + break; + case SND_SOC_BIAS_OFF: + wm8974_write(codec, WM8974_POWER1, 0x0); + wm8974_write(codec, WM8974_POWER2, 0x0); + wm8974_write(codec, WM8974_POWER3, 0x0); + break; + } + codec->bias_level = level; + return 0; +} + +#define WM8974_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000) + +#define WM8974_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops wm8974_ops = { + .hw_params = wm8974_pcm_hw_params, + .digital_mute = wm8974_mute, + .set_fmt = wm8974_set_dai_fmt, + .set_clkdiv = wm8974_set_dai_clkdiv, + .set_pll = wm8974_set_dai_pll, +}; + +struct snd_soc_dai wm8974_dai = { + .name = "WM8974 HiFi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 1, + .rates = WM8974_RATES, + .formats = WM8974_FORMATS,}, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 1, + .rates = WM8974_RATES, + .formats = WM8974_FORMATS,}, + .ops = &wm8974_ops, +}; +EXPORT_SYMBOL_GPL(wm8974_dai); + +static int wm8974_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int wm8974_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int i; + u8 data[2]; + u16 *cache = codec->reg_cache; + + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(wm8974_reg); i++) { + data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); + data[1] = cache[i] & 0x00ff; + codec->hw_write(codec->control_data, data, 2); + } + wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm8974_set_bias_level(codec, codec->suspend_bias_level); + return 0; +} + +/* + * initialise the WM8974 driver + * register the mixer and dsp interfaces with the kernel + */ +static int wm8974_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->card->codec; + int ret = 0; + + codec->name = "WM8974"; + codec->owner = THIS_MODULE; + codec->read = wm8974_read_reg_cache; + codec->write = wm8974_write; + codec->set_bias_level = wm8974_set_bias_level; + codec->dai = &wm8974_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(wm8974_reg); + codec->reg_cache = kmemdup(wm8974_reg, sizeof(wm8974_reg), GFP_KERNEL); + + if (codec->reg_cache == NULL) + return -ENOMEM; + + wm8974_reset(codec); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if(ret < 0) { + printk(KERN_ERR "wm8974: failed to create pcms\n"); + goto pcm_err; + } + + /* power on device */ + wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm8974_add_controls(codec); + wm8974_add_widgets(codec); + ret = snd_soc_init_card(socdev); + if (ret < 0) { + printk(KERN_ERR "wm8974: failed to register card\n"); + goto card_err; + } + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(codec->reg_cache); + return ret; +} + +static struct snd_soc_device *wm8974_socdev; + +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + +/* + * WM8974 2 wire address is 0x1a + */ +#define I2C_DRIVERID_WM8974 0xfefe /* liam - need a proper id */ + +static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; + +/* Magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver wm8974_i2c_driver; +static struct i2c_client client_template; + +/* If the i2c layer weren't so broken, we could pass this kind of data + around */ + +static int wm8974_codec_probe(struct i2c_adapter *adap, int addr, int kind) +{ + struct snd_soc_device *socdev = wm8974_socdev; + struct wm8974_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec = socdev->card->codec; + struct i2c_client *i2c; + int ret; + + if (addr != setup->i2c_address) + return -ENODEV; + + client_template.adapter = adap; + client_template.addr = addr; + + i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); + if (i2c == NULL) { + kfree(codec); + return -ENOMEM; + } + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + ret = i2c_attach_client(i2c); + if (ret < 0) { + pr_err("failed to attach codec at addr %x\n", addr); + goto err; + } + + ret = wm8974_init(socdev); + if (ret < 0) { + pr_err("failed to initialise WM8974\n"); + goto err; + } + return ret; + +err: + kfree(codec); + kfree(i2c); + return ret; +} + +static int wm8974_i2c_detach(struct i2c_client *client) +{ + struct snd_soc_codec *codec = i2c_get_clientdata(client); + i2c_detach_client(client); + kfree(codec->reg_cache); + kfree(client); + return 0; +} + +static int wm8974_i2c_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, wm8974_codec_probe); +} + +/* corgi i2c codec control layer */ +static struct i2c_driver wm8974_i2c_driver = { + .driver = { + .name = "WM8974 I2C Codec", + .owner = THIS_MODULE, + }, + .id = I2C_DRIVERID_WM8974, + .attach_adapter = wm8974_i2c_attach, + .detach_client = wm8974_i2c_detach, + .command = NULL, +}; + +static struct i2c_client client_template = { + .name = "WM8974", + .driver = &wm8974_i2c_driver, +}; +#endif + +static int wm8974_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct wm8974_setup_data *setup; + struct snd_soc_codec *codec; + int ret = 0; + + pr_info("WM8974 Audio Codec %s", WM8974_VERSION); + + setup = socdev->codec_data; + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + socdev->card->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + wm8974_socdev = socdev; +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + if (setup->i2c_address) { + normal_i2c[0] = setup->i2c_address; + codec->hw_write = (hw_write_t)i2c_master_send; + ret = i2c_add_driver(&wm8974_i2c_driver); + if (ret != 0) + printk(KERN_ERR "can't add i2c driver"); + } +#else + /* Add other interfaces here */ +#endif + return ret; +} + +/* power down chip */ +static int wm8974_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + if (codec->control_data) + wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + i2c_del_driver(&wm8974_i2c_driver); +#endif + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8974 = { + .probe = wm8974_probe, + .remove = wm8974_remove, + .suspend = wm8974_suspend, + .resume = wm8974_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8974); + +static int __init wm8974_modinit(void) +{ + return snd_soc_register_dai(&wm8974_dai); +} +module_init(wm8974_modinit); + +static void __exit wm8974_exit(void) +{ + snd_soc_unregister_dai(&wm8974_dai); +} +module_exit(wm8974_exit); + +MODULE_DESCRIPTION("ASoC WM8974 driver"); +MODULE_AUTHOR("Liam Girdwood"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8974.h b/sound/soc/codecs/wm8974.h new file mode 100644 index 0000000..0f5172e --- /dev/null +++ b/sound/soc/codecs/wm8974.h @@ -0,0 +1,104 @@ +/* + * wm8974.h -- WM8974 Soc Audio driver + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef _WM8974_H +#define _WM8974_H + +/* WM8974 register space */ + +#define WM8974_RESET 0x0 +#define WM8974_POWER1 0x1 +#define WM8974_POWER2 0x2 +#define WM8974_POWER3 0x3 +#define WM8974_IFACE 0x4 +#define WM8974_COMP 0x5 +#define WM8974_CLOCK 0x6 +#define WM8974_ADD 0x7 +#define WM8974_GPIO 0x8 +#define WM8974_DAC 0xa +#define WM8974_DACVOL 0xb +#define WM8974_ADC 0xe +#define WM8974_ADCVOL 0xf +#define WM8974_EQ1 0x12 +#define WM8974_EQ2 0x13 +#define WM8974_EQ3 0x14 +#define WM8974_EQ4 0x15 +#define WM8974_EQ5 0x16 +#define WM8974_DACLIM1 0x18 +#define WM8974_DACLIM2 0x19 +#define WM8974_NOTCH1 0x1b +#define WM8974_NOTCH2 0x1c +#define WM8974_NOTCH3 0x1d +#define WM8974_NOTCH4 0x1e +#define WM8974_ALC1 0x20 +#define WM8974_ALC2 0x21 +#define WM8974_ALC3 0x22 +#define WM8974_NGATE 0x23 +#define WM8974_PLLN 0x24 +#define WM8974_PLLK1 0x25 +#define WM8974_PLLK2 0x26 +#define WM8974_PLLK3 0x27 +#define WM8974_ATTEN 0x28 +#define WM8974_INPUT 0x2c +#define WM8974_INPPGA 0x2d +#define WM8974_ADCBOOST 0x2f +#define WM8974_OUTPUT 0x31 +#define WM8974_SPKMIX 0x32 +#define WM8974_SPKVOL 0x36 +#define WM8974_MONOMIX 0x38 + +#define WM8974_CACHEREGNUM 57 + +/* Clock divider Id's */ +#define WM8974_OPCLKDIV 0 +#define WM8974_MCLKDIV 1 +#define WM8974_ADCCLK 2 +#define WM8974_DACCLK 3 +#define WM8974_BCLKDIV 4 + +/* DAC clock dividers */ +#define WM8974_DACCLK_F2 (1 << 3) +#define WM8974_DACCLK_F4 (0 << 3) + +/* ADC clock dividers */ +#define WM8974_ADCCLK_F2 (1 << 3) +#define WM8974_ADCCLK_F4 (0 << 3) + +/* PLL Out dividers */ +#define WM8974_OPCLKDIV_1 (0 << 4) +#define WM8974_OPCLKDIV_2 (1 << 4) +#define WM8974_OPCLKDIV_3 (2 << 4) +#define WM8974_OPCLKDIV_4 (3 << 4) + +/* BCLK clock dividers */ +#define WM8974_BCLKDIV_1 (0 << 2) +#define WM8974_BCLKDIV_2 (1 << 2) +#define WM8974_BCLKDIV_4 (2 << 2) +#define WM8974_BCLKDIV_8 (3 << 2) +#define WM8974_BCLKDIV_16 (4 << 2) +#define WM8974_BCLKDIV_32 (5 << 2) + +/* MCLK clock dividers */ +#define WM8974_MCLKDIV_1 (0 << 5) +#define WM8974_MCLKDIV_1_5 (1 << 5) +#define WM8974_MCLKDIV_2 (2 << 5) +#define WM8974_MCLKDIV_3 (3 << 5) +#define WM8974_MCLKDIV_4 (4 << 5) +#define WM8974_MCLKDIV_6 (5 << 5) +#define WM8974_MCLKDIV_8 (6 << 5) +#define WM8974_MCLKDIV_12 (7 << 5) + + +struct wm8974_setup_data { + unsigned short i2c_address; +}; + +extern struct snd_soc_dai wm8974_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8974; + +#endif -- cgit v0.10.2 From 1a55b3f6ed1d917dd26271dae19dda088d820540 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 23 May 2009 11:31:40 +0100 Subject: ASoC: WM8974 checkpatch cleanups Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 2b0c99c..b5f1a70 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -28,9 +28,6 @@ #include "wm8974.h" -#define AUDIO_NAME "wm8974" -#define WM8974_VERSION "0.6" - struct snd_soc_codec_device soc_codec_dev_wm8974; /* @@ -39,27 +36,27 @@ struct snd_soc_codec_device soc_codec_dev_wm8974; * using 2 wire for device control, so we cache them instead. */ static const u16 wm8974_reg[WM8974_CACHEREGNUM] = { - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0050, 0x0000, 0x0140, 0x0000, - 0x0000, 0x0000, 0x0000, 0x00ff, - 0x0000, 0x0000, 0x0100, 0x00ff, - 0x0000, 0x0000, 0x012c, 0x002c, - 0x002c, 0x002c, 0x002c, 0x0000, - 0x0032, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0038, 0x000b, 0x0032, 0x0000, - 0x0008, 0x000c, 0x0093, 0x00e9, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0003, 0x0010, 0x0000, 0x0000, - 0x0000, 0x0002, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0039, 0x0000, - 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0050, 0x0000, 0x0140, 0x0000, + 0x0000, 0x0000, 0x0000, 0x00ff, + 0x0000, 0x0000, 0x0100, 0x00ff, + 0x0000, 0x0000, 0x012c, 0x002c, + 0x002c, 0x002c, 0x002c, 0x0000, + 0x0032, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0038, 0x000b, 0x0032, 0x0000, + 0x0008, 0x000c, 0x0093, 0x00e9, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0003, 0x0010, 0x0000, 0x0000, + 0x0000, 0x0002, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0039, 0x0000, + 0x0000, }; /* * read wm8974 register cache */ -static inline unsigned int wm8974_read_reg_cache(struct snd_soc_codec * codec, +static inline unsigned int wm8974_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) { u16 *cache = codec->reg_cache; @@ -97,7 +94,7 @@ static int wm8974_write(struct snd_soc_codec *codec, unsigned int reg, data[0] = (reg << 1) | ((value >> 8) & 0x0001); data[1] = value & 0x00ff; - wm8974_write_reg_cache (codec, reg, value); + wm8974_write_reg_cache(codec, reg, value); if (codec->hw_write(codec->control_data, data, 2) == 2) return 0; else @@ -215,7 +212,8 @@ static int wm8974_add_controls(struct snd_soc_codec *codec) for (i = 0; i < ARRAY_SIZE(wm8974_snd_controls); i++) { err = snd_ctl_add(codec->card, - snd_soc_cnew(&wm8974_snd_controls[i],codec, NULL)); + snd_soc_cnew(&wm8974_snd_controls[i], + codec, NULL)); if (err < 0) return err; } @@ -347,13 +345,14 @@ struct pll_ { }; static struct pll_ pll[] = { - {12000000, 11289600, 0, 7, 0x86c220}, - {12000000, 12288000, 0, 8, 0x3126e8}, - {13000000, 11289600, 0, 6, 0xf28bd4}, - {13000000, 12288000, 0, 7, 0x8fd525}, - {12288000, 11289600, 0, 7, 0x59999a}, - {11289600, 12288000, 0, 8, 0x80dee9}, - /* liam - add more entries */ + { 12000000, 11289600, 0, 7, 0x86c220 }, + { 12000000, 12288000, 0, 8, 0x3126e8 }, + { 13000000, 11289600, 0, 6, 0xf28bd4 }, + { 13000000, 12288000, 0, 7, 0x8fd525 }, + { 12288000, 11289600, 0, 7, 0x59999a }, + { 11289600, 12288000, 0, 8, 0x80dee9 }, + { 25000000, 11289600, 1, 7, 0x39B024 }, + { 25000000, 24576000, 1, 7, 0xdd4413 } }; static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, @@ -363,23 +362,26 @@ static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int i; u16 reg; - if(freq_in == 0 || freq_out == 0) { + if (freq_in == 0 || freq_out == 0) { reg = wm8974_read_reg_cache(codec, WM8974_POWER1); wm8974_write(codec, WM8974_POWER1, reg & 0x1df); return 0; } - for(i = 0; i < ARRAY_SIZE(pll); i++) { + for (i = 0; i < ARRAY_SIZE(pll); i++) { if (freq_in == pll[i].in_hz && freq_out == pll[i].out_hz) { - wm8974_write(codec, WM8974_PLLN, (pll[i].pre << 4) | pll[i].n); + wm8974_write(codec, WM8974_PLLN, + (pll[i].pre << 4) | pll[i].n); wm8974_write(codec, WM8974_PLLK1, pll[i].k >> 18); - wm8974_write(codec, WM8974_PLLK2, (pll[i].k >> 9) & 0x1ff); + wm8974_write(codec, WM8974_PLLK2, + (pll[i].k >> 9) & 0x1ff); wm8974_write(codec, WM8974_PLLK3, pll[i].k & 0x1ff); reg = wm8974_read_reg_cache(codec, WM8974_POWER1); wm8974_write(codec, WM8974_POWER1, reg | 0x020); return 0; } } + return -EINVAL; } @@ -394,7 +396,7 @@ static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8974_OPCLKDIV: - reg = wm8974_read_reg_cache(codec, WM8974_GPIO) & 0x1cf; + reg = wm8974_read_reg_cache(codec, WM8974_GPIO) & 0x1cf; wm8974_write(codec, WM8974_GPIO, reg | div); break; case WM8974_MCLKDIV: @@ -531,7 +533,7 @@ static int wm8974_mute(struct snd_soc_dai *dai, int mute) struct snd_soc_codec *codec = dai->codec; u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf; - if(mute) + if (mute) wm8974_write(codec, WM8974_DAC, mute_reg | 0x40); else wm8974_write(codec, WM8974_DAC, mute_reg); @@ -562,9 +564,7 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec, return 0; } -#define WM8974_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000) +#define WM8974_RATES (SNDRV_PCM_RATE_8000_48000) #define WM8974_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE) @@ -649,7 +649,7 @@ static int wm8974_init(struct snd_soc_device *socdev) /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if(ret < 0) { + if (ret < 0) { printk(KERN_ERR "wm8974: failed to create pcms\n"); goto pcm_err; } @@ -773,8 +773,6 @@ static int wm8974_probe(struct platform_device *pdev) struct snd_soc_codec *codec; int ret = 0; - pr_info("WM8974 Audio Codec %s", WM8974_VERSION); - setup = socdev->codec_data; codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); if (codec == NULL) diff --git a/sound/soc/codecs/wm8974.h b/sound/soc/codecs/wm8974.h index 0f5172e..726de96 100644 --- a/sound/soc/codecs/wm8974.h +++ b/sound/soc/codecs/wm8974.h @@ -16,30 +16,30 @@ #define WM8974_POWER2 0x2 #define WM8974_POWER3 0x3 #define WM8974_IFACE 0x4 -#define WM8974_COMP 0x5 +#define WM8974_COMP 0x5 #define WM8974_CLOCK 0x6 -#define WM8974_ADD 0x7 -#define WM8974_GPIO 0x8 -#define WM8974_DAC 0xa +#define WM8974_ADD 0x7 +#define WM8974_GPIO 0x8 +#define WM8974_DAC 0xa #define WM8974_DACVOL 0xb -#define WM8974_ADC 0xe +#define WM8974_ADC 0xe #define WM8974_ADCVOL 0xf -#define WM8974_EQ1 0x12 -#define WM8974_EQ2 0x13 -#define WM8974_EQ3 0x14 -#define WM8974_EQ4 0x15 -#define WM8974_EQ5 0x16 +#define WM8974_EQ1 0x12 +#define WM8974_EQ2 0x13 +#define WM8974_EQ3 0x14 +#define WM8974_EQ4 0x15 +#define WM8974_EQ5 0x16 #define WM8974_DACLIM1 0x18 #define WM8974_DACLIM2 0x19 #define WM8974_NOTCH1 0x1b #define WM8974_NOTCH2 0x1c #define WM8974_NOTCH3 0x1d #define WM8974_NOTCH4 0x1e -#define WM8974_ALC1 0x20 -#define WM8974_ALC2 0x21 -#define WM8974_ALC3 0x22 +#define WM8974_ALC1 0x20 +#define WM8974_ALC2 0x21 +#define WM8974_ALC3 0x22 #define WM8974_NGATE 0x23 -#define WM8974_PLLN 0x24 +#define WM8974_PLLN 0x24 #define WM8974_PLLK1 0x25 #define WM8974_PLLK2 0x26 #define WM8974_PLLK3 0x27 -- cgit v0.10.2 From 4fcbbb67a3cdc7129190a76763480f5ef63e5772 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 23 May 2009 12:27:03 +0100 Subject: ASoC: Update WM8974 to use standard I2C device probe methods Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index b5f1a70..397432a 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -3,7 +3,7 @@ * * Copyright 2006 Wolfson Microelectronics PLC. * - * Author: Liam Girdwood + * Author: Liam Girdwood * * 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 @@ -28,13 +28,6 @@ #include "wm8974.h" -struct snd_soc_codec_device soc_codec_dev_wm8974; - -/* - * wm8974 register cache - * We can't read the WM8974 register space when we are - * using 2 wire for device control, so we cache them instead. - */ static const u16 wm8974_reg[WM8974_CACHEREGNUM] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0050, 0x0000, 0x0140, 0x0000, @@ -53,6 +46,13 @@ static const u16 wm8974_reg[WM8974_CACHEREGNUM] = { 0x0000, }; +struct wm8974_priv { + struct snd_soc_codec codec; + u16 reg_cache[WM8974_CACHEREGNUM]; +}; + +static struct snd_soc_codec *wm8974_codec; + /* * read wm8974 register cache */ @@ -623,217 +623,182 @@ static int wm8974_resume(struct platform_device *pdev) return 0; } -/* - * initialise the WM8974 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8974_init(struct snd_soc_device *socdev) +static int wm8974_probe(struct platform_device *pdev) { - struct snd_soc_codec *codec = socdev->card->codec; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; int ret = 0; - codec->name = "WM8974"; - codec->owner = THIS_MODULE; - codec->read = wm8974_read_reg_cache; - codec->write = wm8974_write; - codec->set_bias_level = wm8974_set_bias_level; - codec->dai = &wm8974_dai; - codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8974_reg); - codec->reg_cache = kmemdup(wm8974_reg, sizeof(wm8974_reg), GFP_KERNEL); - - if (codec->reg_cache == NULL) - return -ENOMEM; + if (wm8974_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } - wm8974_reset(codec); + socdev->card->codec = wm8974_codec; + codec = wm8974_codec; /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { - printk(KERN_ERR "wm8974: failed to create pcms\n"); + dev_err(codec->dev, "failed to create pcms: %d\n", ret); goto pcm_err; } - /* power on device */ - wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - wm8974_add_controls(codec); + snd_soc_add_controls(codec, wm8974_snd_controls, + ARRAY_SIZE(wm8974_snd_controls)); wm8974_add_widgets(codec); ret = snd_soc_init_card(socdev); if (ret < 0) { - printk(KERN_ERR "wm8974: failed to register card\n"); + dev_err(codec->dev, "failed to register card: %d\n", ret); goto card_err; } + return ret; card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); pcm_err: - kfree(codec->reg_cache); return ret; } -static struct snd_soc_device *wm8974_socdev; - -#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) - -/* - * WM8974 2 wire address is 0x1a - */ -#define I2C_DRIVERID_WM8974 0xfefe /* liam - need a proper id */ - -static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; +/* power down chip */ +static int wm8974_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); -/* Magic definition of all other variables and things */ -I2C_CLIENT_INSMOD; + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); -static struct i2c_driver wm8974_i2c_driver; -static struct i2c_client client_template; + return 0; +} -/* If the i2c layer weren't so broken, we could pass this kind of data - around */ +struct snd_soc_codec_device soc_codec_dev_wm8974 = { + .probe = wm8974_probe, + .remove = wm8974_remove, + .suspend = wm8974_suspend, + .resume = wm8974_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8974); -static int wm8974_codec_probe(struct i2c_adapter *adap, int addr, int kind) +static __devinit int wm8974_register(struct wm8974_priv *wm8974) { - struct snd_soc_device *socdev = wm8974_socdev; - struct wm8974_setup_data *setup = socdev->codec_data; - struct snd_soc_codec *codec = socdev->card->codec; - struct i2c_client *i2c; int ret; + struct snd_soc_codec *codec = &wm8974->codec; - if (addr != setup->i2c_address) - return -ENODEV; + if (wm8974_codec) { + dev_err(codec->dev, "Another WM8974 is registered\n"); + return -EINVAL; + } - client_template.adapter = adap; - client_template.addr = addr; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); - i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) { - kfree(codec); - return -ENOMEM; - } - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; + codec->private_data = wm8974; + codec->name = "WM8974"; + codec->owner = THIS_MODULE; + codec->read = wm8974_read_reg_cache; + codec->write = wm8974_write; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8974_set_bias_level; + codec->dai = &wm8974_dai; + codec->num_dai = 1; + codec->reg_cache_size = WM8974_CACHEREGNUM; + codec->reg_cache = &wm8974->reg_cache; - ret = i2c_attach_client(i2c); + memcpy(codec->reg_cache, wm8974_reg, sizeof(wm8974_reg)); + + ret = wm8974_reset(codec); if (ret < 0) { - pr_err("failed to attach codec at addr %x\n", addr); - goto err; + dev_err(codec->dev, "Failed to issue reset\n"); + return ret; } - ret = wm8974_init(socdev); - if (ret < 0) { - pr_err("failed to initialise WM8974\n"); - goto err; + wm8974_dai.dev = codec->dev; + + wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + wm8974_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; } - return ret; -err: - kfree(codec); - kfree(i2c); - return ret; -} + ret = snd_soc_register_dai(&wm8974_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } -static int wm8974_i2c_detach(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); - i2c_detach_client(client); - kfree(codec->reg_cache); - kfree(client); return 0; } -static int wm8974_i2c_attach(struct i2c_adapter *adap) +static __devexit void wm8974_unregister(struct wm8974_priv *wm8974) { - return i2c_probe(adap, &addr_data, wm8974_codec_probe); + wm8974_set_bias_level(&wm8974->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&wm8974_dai); + snd_soc_unregister_codec(&wm8974->codec); + kfree(wm8974); + wm8974_codec = NULL; } -/* corgi i2c codec control layer */ -static struct i2c_driver wm8974_i2c_driver = { - .driver = { - .name = "WM8974 I2C Codec", - .owner = THIS_MODULE, - }, - .id = I2C_DRIVERID_WM8974, - .attach_adapter = wm8974_i2c_attach, - .detach_client = wm8974_i2c_detach, - .command = NULL, -}; - -static struct i2c_client client_template = { - .name = "WM8974", - .driver = &wm8974_i2c_driver, -}; -#endif - -static int wm8974_probe(struct platform_device *pdev) +static __devinit int wm8974_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8974_setup_data *setup; + struct wm8974_priv *wm8974; struct snd_soc_codec *codec; - int ret = 0; - setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) + wm8974 = kzalloc(sizeof(struct wm8974_priv), GFP_KERNEL); + if (wm8974 == NULL) return -ENOMEM; - socdev->card->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); + codec = &wm8974->codec; + codec->hw_write = (hw_write_t)i2c_master_send; - wm8974_socdev = socdev; -#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) - if (setup->i2c_address) { - normal_i2c[0] = setup->i2c_address; - codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&wm8974_i2c_driver); - if (ret != 0) - printk(KERN_ERR "can't add i2c driver"); - } -#else - /* Add other interfaces here */ -#endif - return ret; -} - -/* power down chip */ -static int wm8974_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; + i2c_set_clientdata(i2c, wm8974); + codec->control_data = i2c; - if (codec->control_data) - wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); + codec->dev = &i2c->dev; - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) - i2c_del_driver(&wm8974_i2c_driver); -#endif - kfree(codec); + return wm8974_register(wm8974); +} +static __devexit int wm8974_i2c_remove(struct i2c_client *client) +{ + struct wm8974_priv *wm8974 = i2c_get_clientdata(client); + wm8974_unregister(wm8974); return 0; } -struct snd_soc_codec_device soc_codec_dev_wm8974 = { - .probe = wm8974_probe, - .remove = wm8974_remove, - .suspend = wm8974_suspend, - .resume = wm8974_resume, +static const struct i2c_device_id wm8974_i2c_id[] = { + { "wm8974", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id); + +static struct i2c_driver wm8974_i2c_driver = { + .driver = { + .name = "WM8974 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = wm8974_i2c_probe, + .remove = __devexit_p(wm8974_i2c_remove), + .id_table = wm8974_i2c_id, }; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8974); static int __init wm8974_modinit(void) { - return snd_soc_register_dai(&wm8974_dai); + return i2c_add_driver(&wm8974_i2c_driver); } module_init(wm8974_modinit); static void __exit wm8974_exit(void) { - snd_soc_unregister_dai(&wm8974_dai); + i2c_del_driver(&wm8974_i2c_driver); } module_exit(wm8974_exit); diff --git a/sound/soc/codecs/wm8974.h b/sound/soc/codecs/wm8974.h index 726de96..98de956 100644 --- a/sound/soc/codecs/wm8974.h +++ b/sound/soc/codecs/wm8974.h @@ -93,11 +93,6 @@ #define WM8974_MCLKDIV_8 (6 << 5) #define WM8974_MCLKDIV_12 (7 << 5) - -struct wm8974_setup_data { - unsigned short i2c_address; -}; - extern struct snd_soc_dai wm8974_dai; extern struct snd_soc_codec_device soc_codec_dev_wm8974; -- cgit v0.10.2 From 38357ab2c83631728afa37a783c9b1bd474a0739 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 6 Jun 2009 19:03:23 +0100 Subject: ASoC: Sort DAPM power sequences while building lists In the past the DAPM power sequencing was done by iterating over the list of widgets once for each widget type and powering widgets of that type. Instead of doing that do the sorting at the time we insert the widgets into the lists of widgets to apply power changes to. This reduces the amount of computation required for seqencing still further, though the costs are generally dwarfed by the costs of the register writes implementing them. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 21c6907..1b38e21 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -52,19 +52,37 @@ /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { - snd_soc_dapm_pre, snd_soc_dapm_supply, snd_soc_dapm_micbias, - snd_soc_dapm_mic, snd_soc_dapm_mux, snd_soc_dapm_value_mux, - snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, - snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, - snd_soc_dapm_post + [snd_soc_dapm_pre] = 0, + [snd_soc_dapm_supply] = 1, + [snd_soc_dapm_micbias] = 2, + [snd_soc_dapm_mic] = 3, + [snd_soc_dapm_mux] = 4, + [snd_soc_dapm_value_mux] = 5, + [snd_soc_dapm_dac] = 6, + [snd_soc_dapm_mixer] = 7, + [snd_soc_dapm_mixer_named_ctl] = 8, + [snd_soc_dapm_pga] = 9, + [snd_soc_dapm_adc] = 10, + [snd_soc_dapm_hp] = 11, + [snd_soc_dapm_spk] = 12, + [snd_soc_dapm_post] = 13, }; static int dapm_down_seq[] = { - snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, - snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer, - snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias, - snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_supply, - snd_soc_dapm_post + [snd_soc_dapm_pre] = 0, + [snd_soc_dapm_adc] = 1, + [snd_soc_dapm_hp] = 2, + [snd_soc_dapm_spk] = 3, + [snd_soc_dapm_pga] = 4, + [snd_soc_dapm_mixer_named_ctl] = 5, + [snd_soc_dapm_mixer] = 6, + [snd_soc_dapm_dac] = 7, + [snd_soc_dapm_mic] = 8, + [snd_soc_dapm_micbias] = 9, + [snd_soc_dapm_mux] = 10, + [snd_soc_dapm_value_mux] = 11, + [snd_soc_dapm_supply] = 12, + [snd_soc_dapm_post] = 13, }; static void pop_wait(u32 pop_time) @@ -738,6 +756,32 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event, } } +static int dapm_seq_compare(struct snd_soc_dapm_widget *a, + struct snd_soc_dapm_widget *b, + int sort[]) +{ + if (sort[a->id] != sort[b->id]) + return sort[a->id] - sort[b->id]; + + return 0; +} + +/* Insert a widget in order into a DAPM power sequence. */ +static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, + struct list_head *list, + int sort[]) +{ + struct snd_soc_dapm_widget *w; + + list_for_each_entry(w, list, power_list) + if (dapm_seq_compare(new_widget, w, sort) < 0) { + list_add_tail(&new_widget->power_list, &w->power_list); + return; + } + + list_add_tail(&new_widget->power_list, list); +} + /* * Scan each dapm widget for complete audio path. * A complete path is a route that has valid endpoints i.e.:- @@ -752,7 +796,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) struct snd_soc_device *socdev = codec->socdev; struct snd_soc_dapm_widget *w; int ret = 0; - int i, power; + int power; int sys_power = 0; INIT_LIST_HEAD(&codec->up_list); @@ -764,10 +808,10 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) list_for_each_entry(w, &codec->dapm_widgets, list) { switch (w->id) { case snd_soc_dapm_pre: - list_add_tail(&codec->down_list, &w->power_list); + dapm_seq_insert(w, &codec->down_list, dapm_down_seq); break; case snd_soc_dapm_post: - list_add_tail(&codec->up_list, &w->power_list); + dapm_seq_insert(w, &codec->up_list, dapm_up_seq); break; default: @@ -782,10 +826,11 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) continue; if (power) - list_add_tail(&w->power_list, &codec->up_list); + dapm_seq_insert(w, &codec->up_list, + dapm_up_seq); else - list_add_tail(&w->power_list, - &codec->down_list); + dapm_seq_insert(w, &codec->down_list, + dapm_down_seq); w->power = power; break; @@ -802,31 +847,19 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) } /* Power down widgets first; try to avoid amplifying pops. */ - for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) { - list_for_each_entry(w, &codec->down_list, power_list) { - /* is widget in stream order */ - if (w->id != dapm_down_seq[i]) - continue; - - ret = dapm_power_widget(codec, event, w); - if (ret != 0) - pr_err("Failed to power down %s: %d\n", - w->name, ret); - } + list_for_each_entry(w, &codec->down_list, power_list) { + ret = dapm_power_widget(codec, event, w); + if (ret != 0) + pr_err("Failed to power down %s: %d\n", + w->name, ret); } /* Now power up. */ - for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) { - list_for_each_entry(w, &codec->up_list, power_list) { - /* is widget in stream order */ - if (w->id != dapm_up_seq[i]) - continue; - - ret = dapm_power_widget(codec, event, w); - if (ret != 0) - pr_err("Failed to power up %s: %d\n", - w->name, ret); - } + list_for_each_entry(w, &codec->up_list, power_list) { + ret = dapm_power_widget(codec, event, w); + if (ret != 0) + pr_err("Failed to power up %s: %d\n", + w->name, ret); } /* If we just powered the last thing off drop to standby bias */ -- cgit v0.10.2 From 163cac061c97394d4ef9c89efe5921dac937ddb8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 7 Jun 2009 10:12:52 +0100 Subject: ASoC: Factor out DAPM sequence execution Lump the list walk into a single function, and pull in the power application too so we can do some further refactoring. Pure code motion. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1b38e21..257d4f1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -707,55 +707,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) return power; } -/* - * Scan a single DAPM widget for a complete audio path and update the - * power status appropriately. - */ -static int dapm_power_widget(struct snd_soc_codec *codec, int event, - struct snd_soc_dapm_widget *w) -{ - int ret; - - switch (w->id) { - case snd_soc_dapm_pre: - if (!w->event) - return 0; - - if (event == SND_SOC_DAPM_STREAM_START) { - ret = w->event(w, - NULL, SND_SOC_DAPM_PRE_PMU); - if (ret < 0) - return ret; - } else if (event == SND_SOC_DAPM_STREAM_STOP) { - ret = w->event(w, - NULL, SND_SOC_DAPM_PRE_PMD); - if (ret < 0) - return ret; - } - return 0; - - case snd_soc_dapm_post: - if (!w->event) - return 0; - - if (event == SND_SOC_DAPM_STREAM_START) { - ret = w->event(w, - NULL, SND_SOC_DAPM_POST_PMU); - if (ret < 0) - return ret; - } else if (event == SND_SOC_DAPM_STREAM_STOP) { - ret = w->event(w, - NULL, SND_SOC_DAPM_POST_PMD); - if (ret < 0) - return ret; - } - return 0; - - default: - return dapm_generic_apply_power(w); - } -} - static int dapm_seq_compare(struct snd_soc_dapm_widget *a, struct snd_soc_dapm_widget *b, int sort[]) @@ -782,6 +733,65 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, list_add_tail(&new_widget->power_list, list); } +/* Apply a DAPM power sequence */ +static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list, + int event) +{ + struct snd_soc_dapm_widget *w; + int ret; + + list_for_each_entry(w, list, power_list) { + switch (w->id) { + case snd_soc_dapm_pre: + if (!w->event) + list_for_each_entry_continue(w, list, + power_list); + + if (event == SND_SOC_DAPM_STREAM_START) { + ret = w->event(w, + NULL, SND_SOC_DAPM_PRE_PMU); + if (ret < 0) + pr_err("PRE widget failed: %d\n", + ret); + } else if (event == SND_SOC_DAPM_STREAM_STOP) { + ret = w->event(w, + NULL, SND_SOC_DAPM_PRE_PMD); + if (ret < 0) + pr_err("PRE widget failed: %d\n", + ret); + } + break; + + case snd_soc_dapm_post: + if (!w->event) + list_for_each_entry_continue(w, list, + power_list); + + if (event == SND_SOC_DAPM_STREAM_START) { + ret = w->event(w, + NULL, SND_SOC_DAPM_POST_PMU); + if (ret < 0) + pr_err("POST widget failed: %d\n", + ret); + } else if (event == SND_SOC_DAPM_STREAM_STOP) { + ret = w->event(w, + NULL, SND_SOC_DAPM_POST_PMD); + if (ret < 0) + pr_err("POST widget failed: %d\n", + ret); + } + break; + + default: + ret = dapm_generic_apply_power(w); + if (ret < 0) + pr_err("Failed to apply widget power: %d\n", + ret); + break; + } + } +} + /* * Scan each dapm widget for complete audio path. * A complete path is a route that has valid endpoints i.e.:- @@ -847,20 +857,10 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) } /* Power down widgets first; try to avoid amplifying pops. */ - list_for_each_entry(w, &codec->down_list, power_list) { - ret = dapm_power_widget(codec, event, w); - if (ret != 0) - pr_err("Failed to power down %s: %d\n", - w->name, ret); - } + dapm_seq_run(codec, &codec->down_list, event); /* Now power up. */ - list_for_each_entry(w, &codec->up_list, power_list) { - ret = dapm_power_widget(codec, event, w); - if (ret != 0) - pr_err("Failed to power up %s: %d\n", - w->name, ret); - } + dapm_seq_run(codec, &codec->up_list, event); /* If we just powered the last thing off drop to standby bias */ if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) { -- cgit v0.10.2 From 5204d49676dae3ae1f9dff5b60bf567d24680872 Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Fri, 5 Jun 2009 06:28:23 -0400 Subject: ASoC: Introduce platform driver model for dm644x, dm355 Introduce the platform driver model to get platform data for dm355 and dm644x. Register platform driver and acquire the resources in the probe function Since the platform specific code had been moved from machine driver to dm.c Signed-off-by: Naresh Medisetty Signed-off-by: Chaithrika U S Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index b1ea52f..500d2f5 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -436,16 +436,40 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } -static int davinci_i2s_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) +#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 + +static struct snd_soc_dai_ops davinci_i2s_dai_ops = { + .startup = davinci_i2s_startup, + .trigger = davinci_i2s_trigger, + .hw_params = davinci_i2s_hw_params, + .set_fmt = davinci_i2s_set_dai_fmt, + +}; + +struct snd_soc_dai davinci_i2s_dai = { + .name = "davinci-i2s", + .id = 0, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = DAVINCI_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = DAVINCI_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .ops = &davinci_i2s_dai_ops, + +}; +EXPORT_SYMBOL_GPL(davinci_i2s_dai); + +static int davinci_i2s_probe(struct platform_device *pdev) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_dai *cpu_dai = card->dai_link->cpu_dai; + struct snd_platform_data *pdata = pdev->dev.platform_data; struct davinci_mcbsp_dev *dev; - struct resource *mem, *ioarea; - struct evm_snd_platform_data *pdata; - int ret; + struct resource *mem, *ioarea, *res; + int ret = 0; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { @@ -466,9 +490,7 @@ static int davinci_i2s_probe(struct platform_device *pdev, goto err_release_region; } - cpu_dai->private_data = dev; - - dev->clk = clk_get(&pdev->dev, NULL); + dev->clk = clk_get(&pdev->dev, pdata->clk_name); if (IS_ERR(dev->clk)) { ret = -ENODEV; goto err_free_mem; @@ -476,18 +498,35 @@ static int davinci_i2s_probe(struct platform_device *pdev, clk_enable(dev->clk); dev->base = (void __iomem *)IO_ADDRESS(mem->start); - pdata = pdev->dev.platform_data; dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK] = &davinci_i2s_pcm_out; - dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->channel = pdata->tx_dma_ch; dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->dma_addr = (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DXR_REG); dev->dma_params[SNDRV_PCM_STREAM_CAPTURE] = &davinci_i2s_pcm_in; - dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->channel = pdata->rx_dma_ch; dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->dma_addr = (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DRR_REG); + /* first TX, then RX */ + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!res) { + dev_err(&pdev->dev, "no DMA resource\n"); + goto err_free_mem; + } + dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->channel = res->start; + + res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!res) { + dev_err(&pdev->dev, "no DMA resource\n"); + goto err_free_mem; + } + dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->channel = res->start; + + davinci_i2s_dai.private_data = dev; + ret = snd_soc_register_dai(&davinci_i2s_dai); + if (ret != 0) + goto err_free_mem; + return 0; err_free_mem: @@ -498,62 +537,40 @@ err_release_region: return ret; } -static void davinci_i2s_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int davinci_i2s_remove(struct platform_device *pdev) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_dai *cpu_dai = card->dai_link->cpu_dai; - struct davinci_mcbsp_dev *dev = cpu_dai->private_data; + struct davinci_mcbsp_dev *dev = davinci_i2s_dai.private_data; struct resource *mem; + snd_soc_unregister_dai(&davinci_i2s_dai); clk_disable(dev->clk); clk_put(dev->clk); dev->clk = NULL; - kfree(dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(mem->start, (mem->end - mem->start) + 1); -} -#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 - -static struct snd_soc_dai_ops davinci_i2s_dai_ops = { - .startup = davinci_i2s_startup, - .trigger = davinci_i2s_trigger, - .hw_params = davinci_i2s_hw_params, - .set_fmt = davinci_i2s_set_dai_fmt, -}; + return 0; +} -struct snd_soc_dai davinci_i2s_dai = { - .name = "davinci-i2s", - .id = 0, - .probe = davinci_i2s_probe, - .remove = davinci_i2s_remove, - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = DAVINCI_I2S_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = DAVINCI_I2S_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .ops = &davinci_i2s_dai_ops, +static struct platform_driver davinci_mcbsp_driver = { + .probe = davinci_i2s_probe, + .remove = davinci_i2s_remove, + .driver = { + .name = "davinci-asp", + .owner = THIS_MODULE, + }, }; -EXPORT_SYMBOL_GPL(davinci_i2s_dai); static int __init davinci_i2s_init(void) { - return snd_soc_register_dai(&davinci_i2s_dai); + return platform_driver_register(&davinci_mcbsp_driver); } module_init(davinci_i2s_init); static void __exit davinci_i2s_exit(void) { - snd_soc_unregister_dai(&davinci_i2s_dai); + platform_driver_unregister(&davinci_mcbsp_driver); } module_exit(davinci_i2s_exit); -- cgit v0.10.2 From b67f4487295560599f6cca55fb7e8773ff27f00a Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Fri, 5 Jun 2009 06:28:40 -0400 Subject: ASoC: Add mcasp support for DM646x Adds driver support for the two instances of McASP on TI's DM646x. The multichannel audio serial port (McASP) functions as a general-purpose audio serial port optimized for the needs of multichannel audio application. (http://www.ti.com/litv/pdf/spruer1b). There are two instances of McASP on DM646x. The McASP0 module includes up to 4 serializers that can be individually enabled to either transmit or receive in different modes. The McASP1 module is limited with only 1 pinned-out serializer that can be enabled to only transmit in DIT mode (neither receiving in any mode nor transmitting in either Burst or TDM mode is supported). McASP0 consists of transmit and receive sections that may operate synchronized, or completely independently with separate master clocks, bit clocks, and frame syncs, and using different transmit modes with different bit-stream formats. Signed-off-by: Steve Chen Signed-off-by: Pavel Kiryukhin Signed-off-by: Naresh Medisetty Signed-off-by: Chaithrika U S Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 411a710..6802dd5 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -9,6 +9,9 @@ config SND_DAVINCI_SOC config SND_DAVINCI_SOC_I2S tristate +config SND_DAVINCI_SOC_MCASP + tristate + config SND_DAVINCI_SOC_EVM tristate "SoC Audio support for DaVinci DM6446 or DM355 EVM" depends on SND_DAVINCI_SOC @@ -19,6 +22,16 @@ config SND_DAVINCI_SOC_EVM Say Y if you want to add support for SoC audio on TI DaVinci DM6446 or DM355 EVM platforms. +config SND_DM6467_SOC_EVM + tristate "SoC Audio support for DaVinci DM6467 EVM" + depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM + select SND_DAVINCI_SOC_MCASP + select SND_SOC_TLV320AIC3X + select SND_SOC_SPDIF + + help + Say Y if you want to add support for SoC audio on TI + config SND_DAVINCI_SOC_SFFSDR tristate "SoC Audio support for SFFSDR" depends on SND_DAVINCI_SOC && MACH_SFFSDR diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index ca8bae1..67be54f 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -1,13 +1,16 @@ # DAVINCI Platform Support snd-soc-davinci-objs := davinci-pcm.o snd-soc-davinci-i2s-objs := davinci-i2s.o +snd-soc-davinci-mcasp-objs:= davinci-mcasp.o obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o +obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o # DAVINCI Machine Support snd-soc-evm-objs := davinci-evm.o snd-soc-sffsdr-objs := davinci-sffsdr.o obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o +obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c new file mode 100644 index 0000000..b27aab6 --- /dev/null +++ b/sound/soc/davinci/davinci-mcasp.c @@ -0,0 +1,874 @@ +/* + * ALSA SoC McASP Audio Layer for TI DAVINCI processor + * + * Multi-channel Audio Serial Port Driver + * + * Author: Nirmal Pandey , + * Suresh Rajashekara + * Steve Chen + * + * Copyright: (C) 2009 MontaVista Software, Inc., + * Copyright: (C) 2009 Texas Instruments, India + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "davinci-pcm.h" +#include "davinci-mcasp.h" + +/* + * McASP register definitions + */ +#define DAVINCI_MCASP_PID_REG 0x00 +#define DAVINCI_MCASP_PWREMUMGT_REG 0x04 + +#define DAVINCI_MCASP_PFUNC_REG 0x10 +#define DAVINCI_MCASP_PDIR_REG 0x14 +#define DAVINCI_MCASP_PDOUT_REG 0x18 +#define DAVINCI_MCASP_PDSET_REG 0x1c + +#define DAVINCI_MCASP_PDCLR_REG 0x20 + +#define DAVINCI_MCASP_TLGC_REG 0x30 +#define DAVINCI_MCASP_TLMR_REG 0x34 + +#define DAVINCI_MCASP_GBLCTL_REG 0x44 +#define DAVINCI_MCASP_AMUTE_REG 0x48 +#define DAVINCI_MCASP_LBCTL_REG 0x4c + +#define DAVINCI_MCASP_TXDITCTL_REG 0x50 + +#define DAVINCI_MCASP_GBLCTLR_REG 0x60 +#define DAVINCI_MCASP_RXMASK_REG 0x64 +#define DAVINCI_MCASP_RXFMT_REG 0x68 +#define DAVINCI_MCASP_RXFMCTL_REG 0x6c + +#define DAVINCI_MCASP_ACLKRCTL_REG 0x70 +#define DAVINCI_MCASP_AHCLKRCTL_REG 0x74 +#define DAVINCI_MCASP_RXTDM_REG 0x78 +#define DAVINCI_MCASP_EVTCTLR_REG 0x7c + +#define DAVINCI_MCASP_RXSTAT_REG 0x80 +#define DAVINCI_MCASP_RXTDMSLOT_REG 0x84 +#define DAVINCI_MCASP_RXCLKCHK_REG 0x88 +#define DAVINCI_MCASP_REVTCTL_REG 0x8c + +#define DAVINCI_MCASP_GBLCTLX_REG 0xa0 +#define DAVINCI_MCASP_TXMASK_REG 0xa4 +#define DAVINCI_MCASP_TXFMT_REG 0xa8 +#define DAVINCI_MCASP_TXFMCTL_REG 0xac + +#define DAVINCI_MCASP_ACLKXCTL_REG 0xb0 +#define DAVINCI_MCASP_AHCLKXCTL_REG 0xb4 +#define DAVINCI_MCASP_TXTDM_REG 0xb8 +#define DAVINCI_MCASP_EVTCTLX_REG 0xbc + +#define DAVINCI_MCASP_TXSTAT_REG 0xc0 +#define DAVINCI_MCASP_TXTDMSLOT_REG 0xc4 +#define DAVINCI_MCASP_TXCLKCHK_REG 0xc8 +#define DAVINCI_MCASP_XEVTCTL_REG 0xcc + +/* Left(even TDM Slot) Channel Status Register File */ +#define DAVINCI_MCASP_DITCSRA_REG 0x100 +/* Right(odd TDM slot) Channel Status Register File */ +#define DAVINCI_MCASP_DITCSRB_REG 0x118 +/* Left(even TDM slot) User Data Register File */ +#define DAVINCI_MCASP_DITUDRA_REG 0x130 +/* Right(odd TDM Slot) User Data Register File */ +#define DAVINCI_MCASP_DITUDRB_REG 0x148 + +/* Serializer n Control Register */ +#define DAVINCI_MCASP_XRSRCTL_BASE_REG 0x180 +#define DAVINCI_MCASP_XRSRCTL_REG(n) (DAVINCI_MCASP_XRSRCTL_BASE_REG + \ + (n << 2)) + +/* Transmit Buffer for Serializer n */ +#define DAVINCI_MCASP_TXBUF_REG 0x200 +/* Receive Buffer for Serializer n */ +#define DAVINCI_MCASP_RXBUF_REG 0x280 + + +/* + * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management + * Register Bits + */ +#define MCASP_FREE BIT(0) +#define MCASP_SOFT BIT(1) + +/* + * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits + */ +#define AXR(n) (1<private_data; + cpu_dai->dma_data = dev->dma_params[substream->stream]; + return 0; +} + +static void mcasp_start_rx(struct davinci_audio_dev *dev) +{ + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST); + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); + mcasp_set_reg(dev->base + DAVINCI_MCASP_RXBUF_REG, 0); + + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); + mcasp_set_reg(dev->base + DAVINCI_MCASP_RXBUF_REG, 0); + + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); +} + +static void mcasp_start_tx(struct davinci_audio_dev *dev) +{ + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0); + + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0); + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0); +} + +static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream) +{ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + mcasp_start_tx(dev); + else + mcasp_start_rx(dev); +} + +static void mcasp_stop_rx(struct davinci_audio_dev *dev) +{ + mcasp_set_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, 0); + mcasp_set_reg(dev->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); +} + +static void mcasp_stop_tx(struct davinci_audio_dev *dev) +{ + mcasp_set_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, 0); + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); +} + +static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream) +{ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + mcasp_stop_tx(dev); + else + mcasp_stop_rx(dev); +} + +static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct davinci_audio_dev *dev = cpu_dai->private_data; + void __iomem *base = dev->base; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* codec is clock and frame slave */ + mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); + mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE); + + mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); + mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); + + mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x7 << 26)); + break; + + case SND_SOC_DAIFMT_CBM_CFM: + /* codec is clock and frame master */ + mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); + mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE); + + mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); + mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); + + mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG, (0x3f << 26)); + break; + + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_NF: + mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); + mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); + + mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); + mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + break; + + case SND_SOC_DAIFMT_NB_IF: + mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); + mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); + + mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); + mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + break; + + case SND_SOC_DAIFMT_IB_IF: + mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); + mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); + + mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); + mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + break; + + case SND_SOC_DAIFMT_NB_NF: + mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL); + mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); + + mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL); + mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int davinci_config_channel_size(struct davinci_audio_dev *dev, + int channel_size) +{ + u32 fmt = 0; + + switch (channel_size) { + case DAVINCI_AUDIO_WORD_8: + fmt = 0x03; + break; + + case DAVINCI_AUDIO_WORD_12: + fmt = 0x05; + break; + + case DAVINCI_AUDIO_WORD_16: + fmt = 0x07; + break; + + case DAVINCI_AUDIO_WORD_20: + fmt = 0x09; + break; + + case DAVINCI_AUDIO_WORD_24: + fmt = 0x0B; + break; + + case DAVINCI_AUDIO_WORD_28: + fmt = 0x0D; + break; + + case DAVINCI_AUDIO_WORD_32: + fmt = 0x0F; + break; + + default: + return -EINVAL; + } + + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, + RXSSZ(fmt), RXSSZ(0x0F)); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, + TXSSZ(fmt), TXSSZ(0x0F)); + return 0; +} + +static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) +{ + int i; + + /* Default configuration */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); + + /* All PINS as McASP */ + mcasp_set_reg(dev->base + DAVINCI_MCASP_PFUNC_REG, 0x00000000); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_XEVTCTL_REG, + TXDATADMADIS); + } else { + mcasp_set_reg(dev->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_REVTCTL_REG, + RXDATADMADIS); + } + + for (i = 0; i < dev->num_serializer; i++) { + mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i), + dev->serial_dir[i]); + if (dev->serial_dir[i] == TX_MODE) + mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, + AXR(i)); + else if (dev->serial_dir[i] == RX_MODE) + mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG, + AXR(i)); + } +} + +static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) +{ + int i, active_slots; + u32 mask = 0; + + active_slots = (dev->tdm_slots > 31) ? 32 : dev->tdm_slots; + for (i = 0; i < active_slots; i++) + mask |= (1 << i); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* bit stream is MSB first with no delay */ + /* DSP_B mode */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, + AHCLKXE); + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, mask); + mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXORD); + + if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32)) + mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, + FSXMOD(dev->tdm_slots), FSXMOD(0x1FF)); + else + printk(KERN_ERR "playback tdm slot %d not supported\n", + dev->tdm_slots); + + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0xFFFFFFFF); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + } else { + /* bit stream is MSB first with no delay */ + /* DSP_B mode */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXORD); + mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, + AHCLKRE); + mcasp_set_reg(dev->base + DAVINCI_MCASP_RXTDM_REG, mask); + + if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32)) + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, + FSRMOD(dev->tdm_slots), FSRMOD(0x1FF)); + else + printk(KERN_ERR "capture tdm slot %d not supported\n", + dev->tdm_slots); + + mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, 0xFFFFFFFF); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + } +} + +/* S/PDIF */ +static void davinci_hw_dit_param(struct davinci_audio_dev *dev) +{ + /* Set the PDIR for Serialiser as output */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AFSX); + + /* TXMASK for 24 bits */ + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0x00FFFFFF); + + /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 + and LSB first */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, + TXROT(6) | TXSSZ(15)); + + /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */ + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXFMCTL_REG, + AFSXE | FSXMOD(0x180)); + + /* Set the TX tdm : for all the slots */ + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF); + + /* Set the TX clock controls : div = 1 and internal */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG, + ACLKXE | TX_ASYNC); + + mcasp_clr_bits(dev->base + DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); + + /* Only 44100 and 48000 are valid, both have the same setting */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3)); + + /* Enable the DIT */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_TXDITCTL_REG, DITEN); +} + +static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct davinci_audio_dev *dev = cpu_dai->private_data; + struct davinci_pcm_dma_params *dma_params = + dev->dma_params[substream->stream]; + int word_length; + + davinci_hw_common_param(dev, substream->stream); + + if (dev->op_mode == DAVINCI_MCASP_DIT_MODE) + davinci_hw_dit_param(dev); + else + davinci_hw_param(dev, substream->stream); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + dma_params->data_type = 1; + word_length = DAVINCI_AUDIO_WORD_8; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + dma_params->data_type = 2; + word_length = DAVINCI_AUDIO_WORD_16; + break; + + case SNDRV_PCM_FORMAT_S32_LE: + dma_params->data_type = 4; + word_length = DAVINCI_AUDIO_WORD_32; + break; + + default: + printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); + return -EINVAL; + } + davinci_config_channel_size(dev, word_length); + + return 0; +} + +static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct davinci_audio_dev *dev = rtd->dai->cpu_dai->private_data; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + davinci_mcasp_start(dev, substream->stream); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + davinci_mcasp_stop(dev, substream->stream); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static struct snd_soc_dai_ops davinci_mcasp_dai_ops = { + .startup = davinci_mcasp_startup, + .trigger = davinci_mcasp_trigger, + .hw_params = davinci_mcasp_hw_params, + .set_fmt = davinci_mcasp_set_dai_fmt, + +}; + +struct snd_soc_dai davinci_mcasp_dai[] = { + { + .name = "davinci-i2s", + .id = 0, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = DAVINCI_MCASP_RATES, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = DAVINCI_MCASP_RATES, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &davinci_mcasp_dai_ops, + + }, + { + .name = "davinci-dit", + .id = 1, + .playback = { + .channels_min = 1, + .channels_max = 384, + .rates = DAVINCI_MCASP_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &davinci_mcasp_dai_ops, + }, + +}; +EXPORT_SYMBOL_GPL(davinci_mcasp_dai); + +static int davinci_mcasp_probe(struct platform_device *pdev) +{ + struct davinci_pcm_dma_params *dma_data; + struct resource *mem, *ioarea, *res; + struct snd_platform_data *pdata; + struct davinci_audio_dev *dev; + int count = 0; + int ret = 0; + + dev = kzalloc(sizeof(struct davinci_audio_dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dma_data = kzalloc(sizeof(struct davinci_pcm_dma_params) * 2, + GFP_KERNEL); + if (!dma_data) { + ret = -ENOMEM; + goto err_release_dev; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "no mem resource?\n"); + ret = -ENODEV; + goto err_release_data; + } + + ioarea = request_mem_region(mem->start, + (mem->end - mem->start) + 1, pdev->name); + if (!ioarea) { + dev_err(&pdev->dev, "Audio region already claimed\n"); + ret = -EBUSY; + goto err_release_data; + } + + pdata = pdev->dev.platform_data; + dev->clk = clk_get(&pdev->dev, pdata->clk_name); + if (IS_ERR(dev->clk)) { + ret = -ENODEV; + goto err_release_region; + } + + clk_enable(dev->clk); + + dev->base = (void __iomem *)IO_ADDRESS(mem->start); + dev->op_mode = pdata->op_mode; + dev->tdm_slots = pdata->tdm_slots; + dev->num_serializer = pdata->num_serializer; + dev->serial_dir = pdata->serial_dir; + dev->codec_fmt = pdata->codec_fmt; + + dma_data[count].name = "I2S PCM Stereo out"; + dma_data[count].eventq_no = pdata->eventq_no; + dma_data[count].dma_addr = (dma_addr_t) (pdata->tx_dma_offset + + io_v2p(dev->base)); + dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK] = &dma_data[count]; + + /* first TX, then RX */ + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!res) { + dev_err(&pdev->dev, "no DMA resource\n"); + goto err_release_region; + } + + dma_data[count].channel = res->start; + count++; + dma_data[count].name = "I2S PCM Stereo in"; + dma_data[count].eventq_no = pdata->eventq_no; + dma_data[count].dma_addr = (dma_addr_t)(pdata->rx_dma_offset + + io_v2p(dev->base)); + dev->dma_params[SNDRV_PCM_STREAM_CAPTURE] = &dma_data[count]; + + res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!res) { + dev_err(&pdev->dev, "no DMA resource\n"); + goto err_release_region; + } + + dma_data[count].channel = res->start; + davinci_mcasp_dai[pdev->id].private_data = dev; + davinci_mcasp_dai[pdev->id].dev = &pdev->dev; + ret = snd_soc_register_dai(&davinci_mcasp_dai[pdev->id]); + + if (ret != 0) + goto err_release_region; + return 0; + +err_release_region: + release_mem_region(mem->start, (mem->end - mem->start) + 1); +err_release_data: + kfree(dma_data); +err_release_dev: + kfree(dev); + + return ret; +} + +static int davinci_mcasp_remove(struct platform_device *pdev) +{ + struct davinci_pcm_dma_params *dma_data; + struct davinci_audio_dev *dev; + struct resource *mem; + + snd_soc_unregister_dai(&davinci_mcasp_dai[pdev->id]); + dev = davinci_mcasp_dai[pdev->id].private_data; + clk_disable(dev->clk); + clk_put(dev->clk); + dev->clk = NULL; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, (mem->end - mem->start) + 1); + + dma_data = dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; + kfree(dma_data); + kfree(dev); + + return 0; +} + +static struct platform_driver davinci_mcasp_driver = { + .probe = davinci_mcasp_probe, + .remove = davinci_mcasp_remove, + .driver = { + .name = "davinci-mcasp", + .owner = THIS_MODULE, + }, +}; + +static int __init davinci_mcasp_init(void) +{ + return platform_driver_register(&davinci_mcasp_driver); +} +module_init(davinci_mcasp_init); + +static void __exit davinci_mcasp_exit(void) +{ + platform_driver_unregister(&davinci_mcasp_driver); +} +module_exit(davinci_mcasp_exit); + +MODULE_AUTHOR("Steve Chen"); +MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h new file mode 100644 index 0000000..36b7104 --- /dev/null +++ b/sound/soc/davinci/davinci-mcasp.h @@ -0,0 +1,55 @@ +/* + * ALSA SoC McASP Audio Layer for TI DAVINCI processor + * + * MCASP related definitions + * + * Author: Nirmal Pandey , + * Suresh Rajashekara + * Steve Chen + * + * Copyright: (C) 2009 MontaVista Software, Inc., + * Copyright: (C) 2009 Texas Instruments, India + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef DAVINCI_MCASP_H +#define DAVINCI_MCASP_H + +#include +#include +#include "davinci-pcm.h" + +extern struct snd_soc_dai davinci_mcasp_dai[]; + +#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_96000 +#define DAVINCI_MCASP_I2S_DAI 0 +#define DAVINCI_MCASP_DIT_DAI 1 + +enum { + DAVINCI_AUDIO_WORD_8 = 0, + DAVINCI_AUDIO_WORD_12, + DAVINCI_AUDIO_WORD_16, + DAVINCI_AUDIO_WORD_20, + DAVINCI_AUDIO_WORD_24, + DAVINCI_AUDIO_WORD_32, + DAVINCI_AUDIO_WORD_28, /* This is only valid for McASP */ +}; + +struct davinci_audio_dev { + void __iomem *base; + int sample_rate; + struct clk *clk; + struct davinci_pcm_dma_params *dma_params[2]; + unsigned int codec_fmt; + + /* McASP specific data */ + int tdm_slots; + u8 op_mode; + u8 num_serializer; + u8 *serial_dir; +}; + +#endif /* DAVINCI_MCASP_H */ diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index 62cb4eb..eb4287f 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -12,17 +12,19 @@ #ifndef _DAVINCI_PCM_H #define _DAVINCI_PCM_H +#include +#include + + struct davinci_pcm_dma_params { - char *name; /* stream identifier */ - int channel; /* sync dma channel ID */ - dma_addr_t dma_addr; /* device physical address for DMA */ - unsigned int data_type; /* xfer data type */ + char *name; /* stream identifier */ + int channel; /* sync dma channel ID */ + dma_addr_t dma_addr; /* device physical address for DMA */ + enum dma_event_q eventq_no; /* event queue number */ + unsigned char data_type; /* xfer data type */ + unsigned char convert_mono_stereo; }; -struct evm_snd_platform_data { - int tx_dma_ch; - int rx_dma_ch; -}; extern struct snd_soc_platform davinci_soc_platform; -- cgit v0.10.2 From 04f80f5c486b39446af44e218dba90ec210d61ca Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Fri, 5 Jun 2009 06:28:49 -0400 Subject: ASoC: Add machine driver support for DM646x This patch does the following: (1) Add support for the DM646x machine (2) Modifications required to introduce the platform driver model to get platform data for all the machines including dm355 and dm644x. Signed-off-by: Steve Chen Signed-off-by: Pavel Kiryukhin Signed-off-by: Naresh Medisetty Signed-off-by: Chaithrika U S Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 58fd1cb..f3bb6f6 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -27,9 +27,10 @@ #include #include "../codecs/tlv320aic3x.h" +#include "../codecs/spdif_transciever.h" #include "davinci-pcm.h" #include "davinci-i2s.h" - +#include "davinci-mcasp.h" #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) @@ -43,7 +44,7 @@ static int evm_hw_params(struct snd_pcm_substream *substream, unsigned sysclk; /* ASP1 on DM355 EVM is clocked by an external oscillator */ - if (machine_is_davinci_dm355_evm()) + if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm()) sysclk = 27000000; /* ASP0 in DM6446 EVM is clocked by U55, as configured by @@ -144,6 +145,24 @@ static struct snd_soc_dai_link evm_dai = { .ops = &evm_ops, }; +static struct snd_soc_dai_link dm6467_evm_dai[] = { + { + .name = "TLV320AIC3X", + .stream_name = "AIC3X", + .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI], + .codec_dai = &aic3x_dai, + .init = evm_aic3x_init, + .ops = &evm_ops, + }, + { + .name = "McASP", + .stream_name = "spdif", + .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_DIT_DAI], + .codec_dai = &dit_stub_dai, + .ops = &evm_ops, + }, +}; + /* davinci-evm audio machine driver */ static struct snd_soc_card snd_soc_card_evm = { .name = "DaVinci EVM", @@ -152,12 +171,26 @@ static struct snd_soc_card snd_soc_card_evm = { .num_links = 1, }; +/* davinci dm6467 evm audio machine driver */ +static struct snd_soc_card dm6467_snd_soc_card_evm = { + .name = "DaVinci DM6467 EVM", + .platform = &davinci_soc_platform, + .dai_link = dm6467_evm_dai, + .num_links = ARRAY_SIZE(dm6467_evm_dai), +}; + /* evm audio private data */ static struct aic3x_setup_data evm_aic3x_setup = { .i2c_bus = 1, .i2c_address = 0x1b, }; +/* dm6467 evm audio private data */ +static struct aic3x_setup_data dm6467_evm_aic3x_setup = { + .i2c_bus = 1, + .i2c_address = 0x18, +}; + /* evm audio subsystem */ static struct snd_soc_device evm_snd_devdata = { .card = &snd_soc_card_evm, @@ -165,60 +198,30 @@ static struct snd_soc_device evm_snd_devdata = { .codec_data = &evm_aic3x_setup, }; -/* DM6446 EVM uses ASP0; line-out is a pair of RCA jacks */ -static struct resource evm_snd_resources[] = { - { - .start = DAVINCI_ASP0_BASE, - .end = DAVINCI_ASP0_BASE + SZ_8K - 1, - .flags = IORESOURCE_MEM, - }, -}; - -static struct evm_snd_platform_data evm_snd_data = { - .tx_dma_ch = DAVINCI_DMA_ASP0_TX, - .rx_dma_ch = DAVINCI_DMA_ASP0_RX, -}; - -/* DM335 EVM uses ASP1; line-out is a stereo mini-jack */ -static struct resource dm335evm_snd_resources[] = { - { - .start = DAVINCI_ASP1_BASE, - .end = DAVINCI_ASP1_BASE + SZ_8K - 1, - .flags = IORESOURCE_MEM, - }, -}; - -static struct evm_snd_platform_data dm335evm_snd_data = { - .tx_dma_ch = DAVINCI_DMA_ASP1_TX, - .rx_dma_ch = DAVINCI_DMA_ASP1_RX, +/* evm audio subsystem */ +static struct snd_soc_device dm6467_evm_snd_devdata = { + .card = &dm6467_snd_soc_card_evm, + .codec_dev = &soc_codec_dev_aic3x, + .codec_data = &dm6467_evm_aic3x_setup, }; static struct platform_device *evm_snd_device; static int __init evm_init(void) { - struct resource *resources; - unsigned num_resources; - struct evm_snd_platform_data *data; + struct snd_soc_device *evm_snd_dev_data; int index; int ret; if (machine_is_davinci_evm()) { - davinci_cfg_reg(DM644X_MCBSP); - - resources = evm_snd_resources; - num_resources = ARRAY_SIZE(evm_snd_resources); - data = &evm_snd_data; + evm_snd_dev_data = &evm_snd_devdata; index = 0; } else if (machine_is_davinci_dm355_evm()) { - /* we don't use ASP1 IRQs, or we'd need to mux them ... */ - davinci_cfg_reg(DM355_EVT8_ASP1_TX); - davinci_cfg_reg(DM355_EVT9_ASP1_RX); - - resources = dm335evm_snd_resources; - num_resources = ARRAY_SIZE(dm335evm_snd_resources); - data = &dm335evm_snd_data; + evm_snd_dev_data = &evm_snd_devdata; index = 1; + } else if (machine_is_davinci_dm6467_evm()) { + evm_snd_dev_data = &dm6467_evm_snd_devdata; + index = 0; } else return -EINVAL; @@ -226,17 +229,8 @@ static int __init evm_init(void) if (!evm_snd_device) return -ENOMEM; - platform_set_drvdata(evm_snd_device, &evm_snd_devdata); - evm_snd_devdata.dev = &evm_snd_device->dev; - platform_device_add_data(evm_snd_device, data, sizeof(*data)); - - ret = platform_device_add_resources(evm_snd_device, resources, - num_resources); - if (ret) { - platform_device_put(evm_snd_device); - return ret; - } - + platform_set_drvdata(evm_snd_device, evm_snd_dev_data); + evm_snd_dev_data->dev = &evm_snd_device->dev; ret = platform_device_add(evm_snd_device); if (ret) platform_device_put(evm_snd_device); -- cgit v0.10.2 From 46f5822f7841697d4aedaf4672661d7a765172cd Mon Sep 17 00:00:00 2001 From: Daniel Ribeiro Date: Sun, 7 Jun 2009 02:49:11 -0300 Subject: ASoC: Allow 32 bit registers for DAPM Replace the remaining unsigned shorts with unsigned ints. Tested with pcap2 codec (25 bits registers). Signed-off-by: Daniel Ribeiro Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index cf6111d..a167b49 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -216,9 +216,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, /* codec register bit access */ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, - unsigned short mask, unsigned short value); + unsigned int mask, unsigned int value); int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, - unsigned short mask, unsigned short value); + unsigned int mask, unsigned int value); int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, struct snd_ac97_bus_ops *ops, int num); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3f44150..e1a920c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1264,10 +1264,10 @@ EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); * Returns 1 for change else 0. */ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, - unsigned short mask, unsigned short value) + unsigned int mask, unsigned int value) { int change; - unsigned short old, new; + unsigned int old, new; mutex_lock(&io_mutex); old = snd_soc_read(codec, reg); @@ -1294,10 +1294,10 @@ EXPORT_SYMBOL_GPL(snd_soc_update_bits); * Returns 1 for change else 0. */ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, - unsigned short mask, unsigned short value) + unsigned int mask, unsigned int value) { int change; - unsigned short old, new; + unsigned int old, new; mutex_lock(&io_mutex); old = snd_soc_read(codec, reg); @@ -1583,7 +1583,7 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned short val, bitmask; + unsigned int val, bitmask; for (bitmask = 1; bitmask < e->max; bitmask <<= 1) ; @@ -1612,8 +1612,8 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned short val; - unsigned short mask, bitmask; + unsigned int val; + unsigned int mask, bitmask; for (bitmask = 1; bitmask < e->max; bitmask <<= 1) ; @@ -1649,7 +1649,7 @@ int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned short reg_val, val, mux; + unsigned int reg_val, val, mux; reg_val = snd_soc_read(codec, e->reg); val = (reg_val >> e->shift_l) & e->mask; @@ -1688,8 +1688,8 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned short val; - unsigned short mask; + unsigned int val; + unsigned int mask; if (ucontrol->value.enumerated.item[0] > e->max - 1) return -EINVAL; @@ -1849,7 +1849,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; - unsigned short val, val2, val_mask; + unsigned int val, val2, val_mask; val = (ucontrol->value.integer.value[0] & mask); if (invert) @@ -1915,7 +1915,7 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; int max = mc->max; - unsigned int mask = (1<invert; ucontrol->value.integer.value[0] = @@ -1955,7 +1955,7 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; int err; - unsigned short val, val2, val_mask; + unsigned int val, val2, val_mask; val_mask = mask << shift; val = (ucontrol->value.integer.value[0] & mask); @@ -2047,7 +2047,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; int min = mc->min; - unsigned short val; + unsigned int val; val = (ucontrol->value.integer.value[0]+min) & 0xff; val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 21c6907..7ad8afa 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -268,7 +268,7 @@ static int dapm_connect_mixer(struct snd_soc_codec *codec, static int dapm_update_bits(struct snd_soc_dapm_widget *widget) { int change, power; - unsigned short old, new; + unsigned int old, new; struct snd_soc_codec *codec = widget->codec; /* check for valid widgets */ @@ -1372,7 +1372,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; - unsigned short val, val2, val_mask; + unsigned int val, val2, val_mask; int ret; val = (ucontrol->value.integer.value[0] & mask); @@ -1436,7 +1436,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned short val, bitmask; + unsigned int val, bitmask; for (bitmask = 1; bitmask < e->max; bitmask <<= 1) ; @@ -1464,8 +1464,8 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned short val, mux; - unsigned short mask, bitmask; + unsigned int val, mux; + unsigned int mask, bitmask; int ret = 0; for (bitmask = 1; bitmask < e->max; bitmask <<= 1) @@ -1523,7 +1523,7 @@ int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned short reg_val, val, mux; + unsigned int reg_val, val, mux; reg_val = snd_soc_read(widget->codec, e->reg); val = (reg_val >> e->shift_l) & e->mask; @@ -1563,8 +1563,8 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned short val, mux; - unsigned short mask; + unsigned int val, mux; + unsigned int mask; int ret = 0; if (ucontrol->value.enumerated.item[0] > e->max - 1) -- cgit v0.10.2 From b22ead2a510fdb30440753f90237e86fdac70fae Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 7 Jun 2009 12:51:26 +0100 Subject: ASoC: Coalesce register writes for DAPM sequences Reduce the number of register writes we need to set the power state for a CODEC by coalescing updates to widgets with the same sequence order and same register into a single write. This can be a noticable performance improvement with slow or heavily contended control buses, such as I2C controllers with a low clock frequency, and is particularly noticable when resuming. It can also reduce the noticability of and pops and clicks by ensuring that left and right channels are powered simultaneously if they are in the same register. Currently widgets that have events are not coalesced, including PGAs which may use the volume ramping control. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 257d4f1..66f07cd 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -713,6 +713,8 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, { if (sort[a->id] != sort[b->id]) return sort[a->id] - sort[b->id]; + if (a->reg != b->reg) + return a->reg - b->reg; return 0; } @@ -733,63 +735,133 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, list_add_tail(&new_widget->power_list, list); } -/* Apply a DAPM power sequence */ -static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list, - int event) +/* Apply the coalesced changes from a DAPM sequence */ +static void dapm_seq_run_coalesced(struct snd_soc_codec *codec, + struct list_head *pending) { struct snd_soc_dapm_widget *w; + int reg, power; + unsigned int value = 0; + unsigned int mask = 0; + unsigned int cur_mask; + + reg = list_first_entry(pending, struct snd_soc_dapm_widget, + power_list)->reg; + + list_for_each_entry(w, pending, power_list) { + cur_mask = 1 << w->shift; + BUG_ON(reg != w->reg); + + if (w->invert) + power = !w->power; + else + power = w->power; + + mask |= cur_mask; + if (power) + value |= cur_mask; + + pop_dbg(codec->pop_time, + "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", + w->name, reg, value, mask); + } + + pop_dbg(codec->pop_time, + "pop test : Applying 0x%x/0x%x to %x in %dms\n", + value, mask, reg, codec->pop_time); + pop_wait(codec->pop_time); + snd_soc_update_bits(codec, reg, mask, value); +} + +/* Apply a DAPM power sequence. + * + * We walk over a pre-sorted list of widgets to apply power to. In + * order to minimise the number of writes to the device required + * multiple widgets will be updated in a single write where possible. + * Currently anything that requires more than a single write is not + * handled. + */ +static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list, + int event, int sort[]) +{ + struct snd_soc_dapm_widget *w, *n; + LIST_HEAD(pending); + int cur_sort = -1; + int cur_reg = SND_SOC_NOPM; int ret; - list_for_each_entry(w, list, power_list) { + list_for_each_entry_safe(w, n, list, power_list) { + ret = 0; + + /* Do we need to apply any queued changes? */ + if (sort[w->id] != cur_sort || w->reg != cur_reg) { + if (!list_empty(&pending)) + dapm_seq_run_coalesced(codec, &pending); + + INIT_LIST_HEAD(&pending); + cur_sort = -1; + cur_reg = SND_SOC_NOPM; + } + switch (w->id) { case snd_soc_dapm_pre: if (!w->event) - list_for_each_entry_continue(w, list, - power_list); + list_for_each_entry_safe_continue(w, n, list, + power_list); - if (event == SND_SOC_DAPM_STREAM_START) { + if (event == SND_SOC_DAPM_STREAM_START) ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); - if (ret < 0) - pr_err("PRE widget failed: %d\n", - ret); - } else if (event == SND_SOC_DAPM_STREAM_STOP) { + else if (event == SND_SOC_DAPM_STREAM_STOP) ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); - if (ret < 0) - pr_err("PRE widget failed: %d\n", - ret); - } break; case snd_soc_dapm_post: if (!w->event) - list_for_each_entry_continue(w, list, - power_list); + list_for_each_entry_safe_continue(w, n, list, + power_list); - if (event == SND_SOC_DAPM_STREAM_START) { + if (event == SND_SOC_DAPM_STREAM_START) ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMU); - if (ret < 0) - pr_err("POST widget failed: %d\n", - ret); - } else if (event == SND_SOC_DAPM_STREAM_STOP) { + else if (event == SND_SOC_DAPM_STREAM_STOP) ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); - if (ret < 0) - pr_err("POST widget failed: %d\n", - ret); - } break; - default: + case snd_soc_dapm_input: + case snd_soc_dapm_output: + case snd_soc_dapm_hp: + case snd_soc_dapm_mic: + case snd_soc_dapm_line: + case snd_soc_dapm_spk: + /* No register support currently */ + case snd_soc_dapm_pga: + /* Don't coalsece these yet due to gain ramping */ ret = dapm_generic_apply_power(w); - if (ret < 0) - pr_err("Failed to apply widget power: %d\n", - ret); break; + + default: + /* If there's an event or an invalid register + * then run immediately, otherwise store the + * updates so that we can coalesce. */ + if (w->reg >= 0 && !w->event) { + cur_sort = sort[w->id]; + cur_reg = w->reg; + list_move(&w->power_list, &pending); + } else { + ret = dapm_generic_apply_power(w); + } } + + if (ret < 0) + pr_err("Failed to apply widget power: %d\n", + ret); } + + if (!list_empty(&pending)) + dapm_seq_run_coalesced(codec, &pending); } /* @@ -857,10 +929,10 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) } /* Power down widgets first; try to avoid amplifying pops. */ - dapm_seq_run(codec, &codec->down_list, event); + dapm_seq_run(codec, &codec->down_list, event, dapm_down_seq); /* Now power up. */ - dapm_seq_run(codec, &codec->up_list, event); + dapm_seq_run(codec, &codec->up_list, event, dapm_up_seq); /* If we just powered the last thing off drop to standby bias */ if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) { -- cgit v0.10.2 From e3d4dabd2d9b74778f6f15a830eb3a0027bb3799 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 7 Jun 2009 13:08:45 +0100 Subject: ASoC: Sort specialised mixers and muxes together The more flexible value muxes and named mixers don't need to be sorted differently from a power management point of view, they are different only in terms of the control interface and not in terms of seqencing behaviour. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 66f07cd..9187db1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -57,15 +57,15 @@ static int dapm_up_seq[] = { [snd_soc_dapm_micbias] = 2, [snd_soc_dapm_mic] = 3, [snd_soc_dapm_mux] = 4, - [snd_soc_dapm_value_mux] = 5, - [snd_soc_dapm_dac] = 6, - [snd_soc_dapm_mixer] = 7, - [snd_soc_dapm_mixer_named_ctl] = 8, - [snd_soc_dapm_pga] = 9, - [snd_soc_dapm_adc] = 10, - [snd_soc_dapm_hp] = 11, - [snd_soc_dapm_spk] = 12, - [snd_soc_dapm_post] = 13, + [snd_soc_dapm_value_mux] = 4, + [snd_soc_dapm_dac] = 5, + [snd_soc_dapm_mixer] = 6, + [snd_soc_dapm_mixer_named_ctl] = 6, + [snd_soc_dapm_pga] = 7, + [snd_soc_dapm_adc] = 8, + [snd_soc_dapm_hp] = 9, + [snd_soc_dapm_spk] = 10, + [snd_soc_dapm_post] = 11, }; static int dapm_down_seq[] = { @@ -75,14 +75,14 @@ static int dapm_down_seq[] = { [snd_soc_dapm_spk] = 3, [snd_soc_dapm_pga] = 4, [snd_soc_dapm_mixer_named_ctl] = 5, - [snd_soc_dapm_mixer] = 6, - [snd_soc_dapm_dac] = 7, - [snd_soc_dapm_mic] = 8, - [snd_soc_dapm_micbias] = 9, - [snd_soc_dapm_mux] = 10, - [snd_soc_dapm_value_mux] = 11, - [snd_soc_dapm_supply] = 12, - [snd_soc_dapm_post] = 13, + [snd_soc_dapm_mixer] = 5, + [snd_soc_dapm_dac] = 6, + [snd_soc_dapm_mic] = 7, + [snd_soc_dapm_micbias] = 8, + [snd_soc_dapm_mux] = 9, + [snd_soc_dapm_value_mux] = 9, + [snd_soc_dapm_supply] = 10, + [snd_soc_dapm_post] = 11, }; static void pop_wait(u32 pop_time) -- cgit v0.10.2 From 81628103dd8527d99ea39b054a3f002d5859d7c3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 7 Jun 2009 13:21:24 +0100 Subject: ASoC: Coalesce power updates for DAPM widgets with events Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 9187db1..3fc791c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -740,7 +740,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_codec *codec, struct list_head *pending) { struct snd_soc_dapm_widget *w; - int reg, power; + int reg, power, ret; unsigned int value = 0; unsigned int mask = 0; unsigned int cur_mask; @@ -764,13 +764,62 @@ static void dapm_seq_run_coalesced(struct snd_soc_codec *codec, pop_dbg(codec->pop_time, "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", w->name, reg, value, mask); + + /* power up pre event */ + if (w->power && w->event && + (w->event_flags & SND_SOC_DAPM_PRE_PMU)) { + pop_dbg(codec->pop_time, "pop test : %s PRE_PMU\n", + w->name); + ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); + if (ret < 0) + pr_err("%s: pre event failed: %d\n", + w->name, ret); + } + + /* power down pre event */ + if (!w->power && w->event && + (w->event_flags & SND_SOC_DAPM_PRE_PMD)) { + pop_dbg(codec->pop_time, "pop test : %s PRE_PMD\n", + w->name); + ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); + if (ret < 0) + pr_err("%s: pre event failed: %d\n", + w->name, ret); + } + } + + if (reg >= 0) { + pop_dbg(codec->pop_time, + "pop test : Applying 0x%x/0x%x to %x in %dms\n", + value, mask, reg, codec->pop_time); + pop_wait(codec->pop_time); + snd_soc_update_bits(codec, reg, mask, value); } - pop_dbg(codec->pop_time, - "pop test : Applying 0x%x/0x%x to %x in %dms\n", - value, mask, reg, codec->pop_time); - pop_wait(codec->pop_time); - snd_soc_update_bits(codec, reg, mask, value); + list_for_each_entry(w, pending, power_list) { + /* power up post event */ + if (w->power && w->event && + (w->event_flags & SND_SOC_DAPM_POST_PMU)) { + pop_dbg(codec->pop_time, "pop test : %s POST_PMU\n", + w->name); + ret = w->event(w, + NULL, SND_SOC_DAPM_POST_PMU); + if (ret < 0) + pr_err("%s: post event failed: %d\n", + w->name, ret); + } + + /* power down post event */ + if (!w->power && w->event && + (w->event_flags & SND_SOC_DAPM_POST_PMD)) { + pop_dbg(codec->pop_time, "pop test : %s POST_PMD\n", + w->name); + ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); + if (ret < 0) + pr_err("%s: post event failed: %d\n", + w->name, ret); + } + } } /* Apply a DAPM power sequence. @@ -843,16 +892,11 @@ static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list, break; default: - /* If there's an event or an invalid register - * then run immediately, otherwise store the - * updates so that we can coalesce. */ - if (w->reg >= 0 && !w->event) { - cur_sort = sort[w->id]; - cur_reg = w->reg; - list_move(&w->power_list, &pending); - } else { - ret = dapm_generic_apply_power(w); - } + /* Queue it up for application */ + cur_sort = sort[w->id]; + cur_reg = w->reg; + list_move(&w->power_list, &pending); + break; } if (ret < 0) -- cgit v0.10.2 From 4f1c1923851f9734c972812121e80a3b04ab3af4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 7 Jun 2009 13:37:44 +0100 Subject: ASoC: Coalesce power updates for PGAs Handle gain ramping for PGAs so we can coalesce their power updates too. This is not ideal since we can't cope properly with gain ramping for stereo paths but that was the case without coalescing and gain ramping is relatively infrequently used so the effects are limited. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3fc791c..7299ce4 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -786,6 +786,10 @@ static void dapm_seq_run_coalesced(struct snd_soc_codec *codec, pr_err("%s: pre event failed: %d\n", w->name, ret); } + + /* Lower PGA volume to reduce pops */ + if (w->id == snd_soc_dapm_pga && !w->power) + dapm_set_pga(w, w->power); } if (reg >= 0) { @@ -797,6 +801,10 @@ static void dapm_seq_run_coalesced(struct snd_soc_codec *codec, } list_for_each_entry(w, pending, power_list) { + /* Raise PGA volume to reduce pops */ + if (w->id == snd_soc_dapm_pga && w->power) + dapm_set_pga(w, w->power); + /* power up post event */ if (w->power && w->event && (w->event_flags & SND_SOC_DAPM_POST_PMU)) { @@ -886,8 +894,6 @@ static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list, case snd_soc_dapm_line: case snd_soc_dapm_spk: /* No register support currently */ - case snd_soc_dapm_pga: - /* Don't coalsece these yet due to gain ramping */ ret = dapm_generic_apply_power(w); break; -- cgit v0.10.2 From 291f3bbcacf278726911c713e14cedb71c486b16 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 7 Jun 2009 13:57:17 +0100 Subject: ASoC: Make DAPM power sequence lists local variables They are now only accessed within dapm_power_widgets() so can be local to that function. Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index cf6111d..5964dd6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -369,8 +369,6 @@ struct snd_soc_codec { enum snd_soc_bias_level bias_level; enum snd_soc_bias_level suspend_bias_level; struct delayed_work delayed_work; - struct list_head up_list; - struct list_head down_list; /* codec DAI's */ struct snd_soc_dai *dai; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7299ce4..1c30da1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -927,23 +927,22 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) { struct snd_soc_device *socdev = codec->socdev; struct snd_soc_dapm_widget *w; + LIST_HEAD(up_list); + LIST_HEAD(down_list); int ret = 0; int power; int sys_power = 0; - INIT_LIST_HEAD(&codec->up_list); - INIT_LIST_HEAD(&codec->down_list); - /* Check which widgets we need to power and store them in * lists indicating if they should be powered up or down. */ list_for_each_entry(w, &codec->dapm_widgets, list) { switch (w->id) { case snd_soc_dapm_pre: - dapm_seq_insert(w, &codec->down_list, dapm_down_seq); + dapm_seq_insert(w, &down_list, dapm_down_seq); break; case snd_soc_dapm_post: - dapm_seq_insert(w, &codec->up_list, dapm_up_seq); + dapm_seq_insert(w, &up_list, dapm_up_seq); break; default: @@ -958,11 +957,9 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) continue; if (power) - dapm_seq_insert(w, &codec->up_list, - dapm_up_seq); + dapm_seq_insert(w, &up_list, dapm_up_seq); else - dapm_seq_insert(w, &codec->down_list, - dapm_down_seq); + dapm_seq_insert(w, &down_list, dapm_down_seq); w->power = power; break; @@ -979,10 +976,10 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) } /* Power down widgets first; try to avoid amplifying pops. */ - dapm_seq_run(codec, &codec->down_list, event, dapm_down_seq); + dapm_seq_run(codec, &down_list, event, dapm_down_seq); /* Now power up. */ - dapm_seq_run(codec, &codec->up_list, event, dapm_up_seq); + dapm_seq_run(codec, &up_list, event, dapm_up_seq); /* If we just powered the last thing off drop to standby bias */ if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) { -- cgit v0.10.2 From efd13be09e2db4ac4efa2c6101c4f50ee1ead4b0 Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Mon, 8 Jun 2009 06:49:41 -0400 Subject: ASoC: Minor fixes to DaVinci I2S probe function Assign proper errors when platform resource claims fail. Signed-off-by: Chaithrika U S Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 500d2f5..2f11970 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -469,7 +469,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) struct snd_platform_data *pdata = pdev->dev.platform_data; struct davinci_mcbsp_dev *dev; struct resource *mem, *ioarea, *res; - int ret = 0; + int ret; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { @@ -511,6 +511,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!res) { dev_err(&pdev->dev, "no DMA resource\n"); + ret = -ENXIO; goto err_free_mem; } dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->channel = res->start; @@ -518,6 +519,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (!res) { dev_err(&pdev->dev, "no DMA resource\n"); + ret = -ENXIO; goto err_free_mem; } dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->channel = res->start; -- cgit v0.10.2 From 849620fab413355eff48232eac5a8c53c57615c5 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 14 May 2009 17:10:52 +0200 Subject: Revert "oprofile: discover counters for op ppro too" This reverts commit 59512900baab03c5629f2ff5efad1d5d4e682ece. arch_perfmon_setup_counters() is actually never called for ppro, so there is no code that changes the numbers in op_ppro_spec. The patch as it is has no effect. Cc: Andi Kleen Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 10131fb..2a12399 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -213,9 +213,9 @@ static void ppro_shutdown(struct op_msrs const * const msrs) } -struct op_x86_model_spec op_ppro_spec = { - .num_counters = 2, /* can be overriden */ - .num_controls = 2, /* dito */ +struct op_x86_model_spec const op_ppro_spec = { + .num_counters = 2, + .num_controls = 2, .fill_in_addresses = &ppro_fill_in_addresses, .setup_ctrs = &ppro_setup_ctrs, .check_ctrs = &ppro_check_ctrs, @@ -251,8 +251,6 @@ void arch_perfmon_setup_counters(void) op_arch_perfmon_spec.num_counters = num_counters; op_arch_perfmon_spec.num_controls = num_counters; - op_ppro_spec.num_counters = num_counters; - op_ppro_spec.num_controls = num_counters; } struct op_x86_model_spec op_arch_perfmon_spec = { diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 825e790..2317149 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -45,7 +45,7 @@ struct op_x86_model_spec { void (*shutdown)(struct op_msrs const * const msrs); }; -extern struct op_x86_model_spec op_ppro_spec; +extern struct op_x86_model_spec const op_ppro_spec; extern struct op_x86_model_spec const op_p4_spec; extern struct op_x86_model_spec const op_p4_ht2_spec; extern struct op_x86_model_spec const op_amd_spec; -- cgit v0.10.2 From e419294ed3c98cccc145202e4fe165bfd8099d63 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sun, 12 Oct 2008 15:12:34 -0400 Subject: x86/oprofile: moving arch_perfmon counter setup to op_x86_model_spec.init The function arch_perfmon_init() in nmi_int.c is model specific. This patch moves it to op_model_ppro.c by using the init function pointer in struct op_x86_model_spec. Cc: Andi Kleen Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 3b285e6..dd85153 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -427,7 +427,7 @@ static int __init ppro_init(char **cpu_type) *cpu_type = "i386/core_2"; break; case 26: - arch_perfmon_setup_counters(); + model = &op_arch_perfmon_spec; *cpu_type = "i386/core_i7"; break; case 28: @@ -442,16 +442,6 @@ static int __init ppro_init(char **cpu_type) return 1; } -static int __init arch_perfmon_init(char **cpu_type) -{ - if (!cpu_has_arch_perfmon) - return 0; - *cpu_type = "i386/arch_perfmon"; - model = &op_arch_perfmon_spec; - arch_perfmon_setup_counters(); - return 1; -} - /* in order to get sysfs right */ static int using_nmi; @@ -509,8 +499,15 @@ int __init op_nmi_init(struct oprofile_operations *ops) break; } - if (!cpu_type && !arch_perfmon_init(&cpu_type)) + if (cpu_type) + break; + + if (!cpu_has_arch_perfmon) return -ENODEV; + + /* use arch perfmon as fallback */ + cpu_type = "i386/arch_perfmon"; + model = &op_arch_perfmon_spec; break; default: diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 2a12399..ae58119 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -233,7 +233,7 @@ struct op_x86_model_spec const op_ppro_spec = { * the specific CPU. */ -void arch_perfmon_setup_counters(void) +static void arch_perfmon_setup_counters(void) { union cpuid10_eax eax; @@ -253,7 +253,14 @@ void arch_perfmon_setup_counters(void) op_arch_perfmon_spec.num_controls = num_counters; } +static int arch_perfmon_init(struct oprofile_operations *ignore) +{ + arch_perfmon_setup_counters(); + return 0; +} + struct op_x86_model_spec op_arch_perfmon_spec = { + .init = &arch_perfmon_init, /* num_counters/num_controls filled in at runtime */ .fill_in_addresses = &ppro_fill_in_addresses, /* user space does the cpuid check for available events */ diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 2317149..ed27783 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -51,6 +51,4 @@ extern struct op_x86_model_spec const op_p4_ht2_spec; extern struct op_x86_model_spec const op_amd_spec; extern struct op_x86_model_spec op_arch_perfmon_spec; -extern void arch_perfmon_setup_counters(void); - #endif /* OP_X86_MODEL_H */ -- cgit v0.10.2 From 06552ccc36abeb12e37efc16c384dc7f30794f85 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 28 May 2009 02:12:36 +0200 Subject: x86/oprofile: minor style changes in struct op_x86_model_spec Some vertical alignments. Variables are now located in the beginning of the struct. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index ed27783..bd8157d 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -32,17 +32,17 @@ struct pt_regs; * various x86 CPU models' perfctr support. */ struct op_x86_model_spec { - int (*init)(struct oprofile_operations *ops); - void (*exit)(void); - unsigned int num_counters; - unsigned int num_controls; - void (*fill_in_addresses)(struct op_msrs * const msrs); - void (*setup_ctrs)(struct op_msrs const * const msrs); - int (*check_ctrs)(struct pt_regs * const regs, - struct op_msrs const * const msrs); - void (*start)(struct op_msrs const * const msrs); - void (*stop)(struct op_msrs const * const msrs); - void (*shutdown)(struct op_msrs const * const msrs); + unsigned int num_counters; + unsigned int num_controls; + int (*init)(struct oprofile_operations *ops); + void (*exit)(void); + void (*fill_in_addresses)(struct op_msrs * const msrs); + void (*setup_ctrs)(struct op_msrs const * const msrs); + int (*check_ctrs)(struct pt_regs * const regs, + struct op_msrs const * const msrs); + void (*start)(struct op_msrs const * const msrs); + void (*stop)(struct op_msrs const * const msrs); + void (*shutdown)(struct op_msrs const * const msrs); }; extern struct op_x86_model_spec const op_ppro_spec; -- cgit v0.10.2 From 0dc8335aa3e59f1adbb0fce7c9c0b342146cd036 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 7 May 2009 15:09:33 +0200 Subject: oprofile: remove irq_flags in struct op_entry This became obsolete with this commit: 304cc6a ring_buffer: remove unused flags parameter, fix Signed-off-by: Robert Richter diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index 1d9518b..dbbe2db 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -171,7 +171,6 @@ struct op_sample; struct op_entry { struct ring_buffer_event *event; struct op_sample *sample; - unsigned long irq_flags; unsigned long size; unsigned long *data; }; -- cgit v0.10.2 From fecfe6320ba71eed6d16849683298f0894aa60de Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 7 May 2009 16:07:41 +0200 Subject: oprofile: remove obselete include headers This became obsolete with this commit: 6dad828 oprofile: port to the new ring_buffer Signed-off-by: Robert Richter diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 242257b..50640cc 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -21,7 +21,6 @@ #include #include -#include #include #include "event_buffer.h" -- cgit v0.10.2 From 9063759540daac40cc1f402f83a3be6b489f8583 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 10 Mar 2009 19:15:57 +0100 Subject: x86/oprofile: remove #ifdefs in ibs functions IBS code is moved to separate functions. This allows the removal of #ifdefs in functions. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 8fdf06e..b54c088 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -220,6 +220,50 @@ op_amd_handle_ibs(struct pt_regs * const regs, return 1; } +static inline void op_amd_start_ibs(void) +{ + unsigned int low, high; + if (has_ibs && ibs_config.fetch_enabled) { + low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; + high = ((ibs_config.rand_en & 0x1) << 25) /* bit 57 */ + + IBS_FETCH_HIGH_ENABLE; + wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); + } + + if (has_ibs && ibs_config.op_enabled) { + low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) + + ((ibs_config.dispatched_ops & 0x1) << 19) /* bit 19 */ + + IBS_OP_LOW_ENABLE; + high = 0; + wrmsr(MSR_AMD64_IBSOPCTL, low, high); + } +} + +static void op_amd_stop_ibs(void) +{ + unsigned int low, high; + if (has_ibs && ibs_config.fetch_enabled) { + /* clear max count and enable */ + low = 0; + high = 0; + wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); + } + + if (has_ibs && ibs_config.op_enabled) { + /* clear max count and enable */ + low = 0; + high = 0; + wrmsr(MSR_AMD64_IBSOPCTL, low, high); + } +} + +#else + +static inline int op_amd_handle_ibs(struct pt_regs * const regs, + struct op_msrs const * const msrs) { } +static inline void op_amd_start_ibs(void) { } +static inline void op_amd_stop_ibs(void) { } + #endif static int op_amd_check_ctrs(struct pt_regs * const regs, @@ -238,9 +282,7 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, } } -#ifdef CONFIG_OPROFILE_IBS op_amd_handle_ibs(regs, msrs); -#endif /* See op_model_ppro.c */ return 1; @@ -258,25 +300,9 @@ static void op_amd_start(struct op_msrs const * const msrs) } } -#ifdef CONFIG_OPROFILE_IBS - if (has_ibs && ibs_config.fetch_enabled) { - low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; - high = ((ibs_config.rand_en & 0x1) << 25) /* bit 57 */ - + IBS_FETCH_HIGH_ENABLE; - wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); - } - - if (has_ibs && ibs_config.op_enabled) { - low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) - + ((ibs_config.dispatched_ops & 0x1) << 19) /* bit 19 */ - + IBS_OP_LOW_ENABLE; - high = 0; - wrmsr(MSR_AMD64_IBSOPCTL, low, high); - } -#endif + op_amd_start_ibs(); } - static void op_amd_stop(struct op_msrs const * const msrs) { unsigned int low, high; @@ -294,21 +320,7 @@ static void op_amd_stop(struct op_msrs const * const msrs) CTRL_WRITE(low, high, msrs, i); } -#ifdef CONFIG_OPROFILE_IBS - if (has_ibs && ibs_config.fetch_enabled) { - /* clear max count and enable */ - low = 0; - high = 0; - wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); - } - - if (has_ibs && ibs_config.op_enabled) { - /* clear max count and enable */ - low = 0; - high = 0; - wrmsr(MSR_AMD64_IBSOPCTL, low, high); - } -#endif + op_amd_stop_ibs(); } static void op_amd_shutdown(struct op_msrs const * const msrs) -- cgit v0.10.2 From d20f24c66011f8a397bca6c5d1a6a7c7e612d2d7 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sun, 11 Jan 2009 13:01:16 +0100 Subject: x86/oprofile: simplify AMD cpu init code Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index dd85153..ae0ab03 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -460,27 +460,26 @@ int __init op_nmi_init(struct oprofile_operations *ops) /* Needs to be at least an Athlon (or hammer in 32bit mode) */ switch (family) { - default: - return -ENODEV; case 6: - model = &op_amd_spec; cpu_type = "i386/athlon"; break; case 0xf: - model = &op_amd_spec; - /* Actually it could be i386/hammer too, but give - user space an consistent name. */ + /* + * Actually it could be i386/hammer too, but + * give user space an consistent name. + */ cpu_type = "x86-64/hammer"; break; case 0x10: - model = &op_amd_spec; cpu_type = "x86-64/family10"; break; case 0x11: - model = &op_amd_spec; cpu_type = "x86-64/family11h"; break; + default: + return -ENODEV; } + model = &op_amd_spec; break; case X86_VENDOR_INTEL: -- cgit v0.10.2 From ff9faa8b676e195476b86f03fe58db0f01bda8f3 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 22 May 2009 15:36:29 +0200 Subject: x86/oprofile: move common macros to op_x86_model.h There are duplicate macro implementations in model specific code. This patch moves all common macros to op_x86_model.h. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index b54c088..4b9254a 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -26,22 +26,14 @@ #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 -#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) #define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0) #define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0) #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) -#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) #define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) #define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) -#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) -#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) #define CTRL_CLEAR_LO(x) (x &= (1<<21)) #define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0) -#define CTRL_SET_ENABLE(val) (val |= 1<<20) -#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16)) -#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17)) -#define CTRL_SET_UM(val, m) (val |= (m << 8)) #define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff)) #define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf)) #define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9)) diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 819b131..420c15e 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -366,8 +366,6 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = { #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31)) #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31))) -#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) -#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) #define CTR_READ(l, h, i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h)); } while (0) #define CTR_WRITE(l, i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1); } while (0) #define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000)) diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index ae58119..a922a1a 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -26,19 +26,11 @@ static int num_counters = 2; static int counter_width = 32; -#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) #define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1)))) -#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) #define CTRL_READ(l, h, msrs, c) do {rdmsr((msrs->controls[(c)].addr), (l), (h)); } while (0) #define CTRL_WRITE(l, h, msrs, c) do {wrmsr((msrs->controls[(c)].addr), (l), (h)); } while (0) -#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) -#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) #define CTRL_CLEAR(x) (x &= (1<<21)) -#define CTRL_SET_ENABLE(val) (val |= 1<<20) -#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16)) -#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17)) -#define CTRL_SET_UM(val, m) (val |= (m << 8)) #define CTRL_SET_EVENT(val, e) (val |= e) static u64 *reset_value; diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index bd8157d..c80ec7d 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -11,6 +11,15 @@ #ifndef OP_X86_MODEL_H #define OP_X86_MODEL_H +#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) +#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) +#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) +#define CTRL_SET_ENABLE(val) (val |= 1<<20) +#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) +#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17)) +#define CTRL_SET_UM(val, m) (val |= (m << 8)) +#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16)) + struct op_saved_msr { unsigned int high; unsigned int low; -- cgit v0.10.2 From d2731a4387ad6c6bca07abfe9ed41d450fb6d665 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 22 May 2009 19:47:38 +0200 Subject: x86/oprofile: remove MSR macros for AMD cpus The macros CTRL_READ() and CTRL_WRITE() make the code hard to read and maintain. This patch replaces them by rdmsr()/wrmsr() functions and simplifies the code. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 4b9254a..c6181c2 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -26,12 +26,7 @@ #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 -#define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0) -#define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0) #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) - -#define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) -#define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0) #define CTRL_CLEAR_LO(x) (x &= (1<<21)) #define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0) #define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff)) @@ -101,17 +96,17 @@ static void op_amd_setup_ctrs(struct op_msrs const * const msrs) for (i = 0 ; i < NUM_CONTROLS; ++i) { if (unlikely(!CTRL_IS_RESERVED(msrs, i))) continue; - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_CLEAR_LO(low); CTRL_CLEAR_HI(high); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } /* avoid a false detection of ctr overflows in NMI handler */ for (i = 0; i < NUM_COUNTERS; ++i) { if (unlikely(!CTR_IS_RESERVED(msrs, i))) continue; - CTR_WRITE(1, msrs, i); + wrmsr(msrs->counters[i].addr, -1, -1); } /* enable active counters */ @@ -119,9 +114,9 @@ static void op_amd_setup_ctrs(struct op_msrs const * const msrs) if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { reset_value[i] = counter_config[i].count; - CTR_WRITE(counter_config[i].count, msrs, i); + wrmsr(msrs->counters[i].addr, -(unsigned int)counter_config[i].count, -1); - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_CLEAR_LO(low); CTRL_CLEAR_HI(high); CTRL_SET_ENABLE(low); @@ -133,7 +128,7 @@ static void op_amd_setup_ctrs(struct op_msrs const * const msrs) CTRL_SET_HOST_ONLY(high, 0); CTRL_SET_GUEST_ONLY(high, 0); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } else { reset_value[i] = 0; } @@ -267,10 +262,10 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, for (i = 0 ; i < NUM_COUNTERS; ++i) { if (!reset_value[i]) continue; - CTR_READ(low, high, msrs, i); + rdmsr(msrs->counters[i].addr, low, high); if (CTR_OVERFLOWED(low)) { oprofile_add_sample(regs, i); - CTR_WRITE(reset_value[i], msrs, i); + wrmsr(msrs->counters[i].addr, -(unsigned int)reset_value[i], -1); } } @@ -286,9 +281,9 @@ static void op_amd_start(struct op_msrs const * const msrs) int i; for (i = 0 ; i < NUM_COUNTERS ; ++i) { if (reset_value[i]) { - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_SET_ACTIVE(low); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } } @@ -307,9 +302,9 @@ static void op_amd_stop(struct op_msrs const * const msrs) for (i = 0 ; i < NUM_COUNTERS ; ++i) { if (!reset_value[i]) continue; - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_SET_INACTIVE(low); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } op_amd_stop_ibs(); -- cgit v0.10.2 From 74c9a5c341bb1f6cbb5095b07c77230f19682ce8 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 22 May 2009 19:47:38 +0200 Subject: x86/oprofile: remove MSR macros for ppro cpus The macros CTRL_READ() and CTRL_WRITE() make the code hard to read and maintain. This patch replaces them by rdmsr()/wrmsr() functions and simplifies the code. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index a922a1a..6c5d288 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -27,9 +27,6 @@ static int num_counters = 2; static int counter_width = 32; #define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1)))) - -#define CTRL_READ(l, h, msrs, c) do {rdmsr((msrs->controls[(c)].addr), (l), (h)); } while (0) -#define CTRL_WRITE(l, h, msrs, c) do {wrmsr((msrs->controls[(c)].addr), (l), (h)); } while (0) #define CTRL_CLEAR(x) (x &= (1<<21)) #define CTRL_SET_EVENT(val, e) (val |= e) @@ -88,9 +85,9 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs) for (i = 0 ; i < num_counters; ++i) { if (unlikely(!CTRL_IS_RESERVED(msrs, i))) continue; - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_CLEAR(low); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } /* avoid a false detection of ctr overflows in NMI handler */ @@ -107,14 +104,14 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs) wrmsrl(msrs->counters[i].addr, -reset_value[i]); - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_CLEAR(low); CTRL_SET_ENABLE(low); CTRL_SET_USR(low, counter_config[i].user); CTRL_SET_KERN(low, counter_config[i].kernel); CTRL_SET_UM(low, counter_config[i].unit_mask); CTRL_SET_EVENT(low, counter_config[i].event); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } else { reset_value[i] = 0; } @@ -162,9 +159,9 @@ static void ppro_start(struct op_msrs const * const msrs) return; for (i = 0; i < num_counters; ++i) { if (reset_value[i]) { - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_SET_ACTIVE(low); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } } } @@ -180,9 +177,9 @@ static void ppro_stop(struct op_msrs const * const msrs) for (i = 0; i < num_counters; ++i) { if (!reset_value[i]) continue; - CTRL_READ(low, high, msrs, i); + rdmsr(msrs->controls[i].addr, low, high); CTRL_SET_INACTIVE(low); - CTRL_WRITE(low, high, msrs, i); + wrmsr(msrs->controls[i].addr, low, high); } } -- cgit v0.10.2 From 1131a478245b00664ae2dbc0f68db987b51fa806 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 20:23:23 +0200 Subject: x86/oprofile: remove MSR macros for p4 cpus The macros CTRL_READ() and CTRL_WRITE() make the code hard to read and maintain. This patch replaces them by rdmsr()/wrmsr() functions and simplifies the code. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 420c15e..365d8a9 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -350,8 +350,6 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = { #define ESCR_SET_OS_1(escr, os) ((escr) |= (((os) & 1) << 1)) #define ESCR_SET_EVENT_SELECT(escr, sel) ((escr) |= (((sel) & 0x3f) << 25)) #define ESCR_SET_EVENT_MASK(escr, mask) ((escr) |= (((mask) & 0xffff) << 9)) -#define ESCR_READ(escr, high, ev, i) do {rdmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0) -#define ESCR_WRITE(escr, high, ev, i) do {wrmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0) #define CCCR_RESERVED_BITS 0x38030FFF #define CCCR_CLEAR(cccr) ((cccr) &= CCCR_RESERVED_BITS) @@ -361,13 +359,9 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = { #define CCCR_SET_PMI_OVF_1(cccr) ((cccr) |= (1<<27)) #define CCCR_SET_ENABLE(cccr) ((cccr) |= (1<<12)) #define CCCR_SET_DISABLE(cccr) ((cccr) &= ~(1<<12)) -#define CCCR_READ(low, high, i) do {rdmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0) -#define CCCR_WRITE(low, high, i) do {wrmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0) #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31)) #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31))) -#define CTR_READ(l, h, i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h)); } while (0) -#define CTR_WRITE(l, i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1); } while (0) #define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000)) @@ -513,7 +507,7 @@ static void pmc_setup_one_p4_counter(unsigned int ctr) if (ev->bindings[i].virt_counter & counter_bit) { /* modify ESCR */ - ESCR_READ(escr, high, ev, i); + rdmsr(ev->bindings[i].escr_address, escr, high); ESCR_CLEAR(escr); if (stag == 0) { ESCR_SET_USR_0(escr, counter_config[ctr].user); @@ -524,10 +518,11 @@ static void pmc_setup_one_p4_counter(unsigned int ctr) } ESCR_SET_EVENT_SELECT(escr, ev->event_select); ESCR_SET_EVENT_MASK(escr, counter_config[ctr].unit_mask); - ESCR_WRITE(escr, high, ev, i); + wrmsr(ev->bindings[i].escr_address, escr, high); /* modify CCCR */ - CCCR_READ(cccr, high, VIRT_CTR(stag, ctr)); + rdmsr(p4_counters[VIRT_CTR(stag, ctr)].cccr_address, + cccr, high); CCCR_CLEAR(cccr); CCCR_SET_REQUIRED_BITS(cccr); CCCR_SET_ESCR_SELECT(cccr, ev->escr_select); @@ -535,7 +530,8 @@ static void pmc_setup_one_p4_counter(unsigned int ctr) CCCR_SET_PMI_OVF_0(cccr); else CCCR_SET_PMI_OVF_1(cccr); - CCCR_WRITE(cccr, high, VIRT_CTR(stag, ctr)); + wrmsr(p4_counters[VIRT_CTR(stag, ctr)].cccr_address, + cccr, high); return; } } @@ -582,7 +578,8 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs) if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs, i))) { reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); - CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i)); + wrmsr(p4_counters[VIRT_CTR(stag, i)].counter_address, + -(u32)counter_config[i].count, -1); } else { reset_value[i] = 0; } @@ -622,14 +619,16 @@ static int p4_check_ctrs(struct pt_regs * const regs, real = VIRT_CTR(stag, i); - CCCR_READ(low, high, real); - CTR_READ(ctr, high, real); + rdmsr(p4_counters[real].cccr_address, low, high); + rdmsr(p4_counters[real].counter_address, ctr, high); if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) { oprofile_add_sample(regs, i); - CTR_WRITE(reset_value[i], real); + wrmsr(p4_counters[real].counter_address, + -(u32)reset_value[i], -1); CCCR_CLEAR_OVF(low); - CCCR_WRITE(low, high, real); - CTR_WRITE(reset_value[i], real); + wrmsr(p4_counters[real].cccr_address, low, high); + wrmsr(p4_counters[real].counter_address, + -(u32)reset_value[i], -1); } } @@ -651,9 +650,9 @@ static void p4_start(struct op_msrs const * const msrs) for (i = 0; i < num_counters; ++i) { if (!reset_value[i]) continue; - CCCR_READ(low, high, VIRT_CTR(stag, i)); + rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); CCCR_SET_ENABLE(low); - CCCR_WRITE(low, high, VIRT_CTR(stag, i)); + wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); } } @@ -668,9 +667,9 @@ static void p4_stop(struct op_msrs const * const msrs) for (i = 0; i < num_counters; ++i) { if (!reset_value[i]) continue; - CCCR_READ(low, high, VIRT_CTR(stag, i)); + rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); CCCR_SET_DISABLE(low); - CCCR_WRITE(low, high, VIRT_CTR(stag, i)); + wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); } } -- cgit v0.10.2 From ec064c093e254f4433afb17dcef7f964c76436af Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 15:05:50 +0200 Subject: x86/oprofile: fix and cleanup CTRL_SET_* macros This patch fixes missing braces around macro parameters. Macro definitions from intel_arch_perfmon.h are used where possible. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 6c5d288..61ee8f6 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "op_x86_model.h" #include "op_counter.h" diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index c80ec7d..a207b1c 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -11,14 +11,16 @@ #ifndef OP_X86_MODEL_H #define OP_X86_MODEL_H -#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0) -#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0) -#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) -#define CTRL_SET_ENABLE(val) (val |= 1<<20) -#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) -#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17)) -#define CTRL_SET_UM(val, m) (val |= (m << 8)) -#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16)) +#include + +#define CTR_IS_RESERVED(msrs, c) ((msrs)->counters[(c)].addr ? 1 : 0) +#define CTRL_IS_RESERVED(msrs, c) ((msrs)->controls[(c)].addr ? 1 : 0) +#define CTRL_SET_ACTIVE(val) ((val) |= ARCH_PERFMON_EVENTSEL0_ENABLE) +#define CTRL_SET_ENABLE(val) ((val) |= ARCH_PERFMON_EVENTSEL_INT) +#define CTRL_SET_INACTIVE(val) ((val) &= ~ARCH_PERFMON_EVENTSEL0_ENABLE) +#define CTRL_SET_KERN(val, k) ((val) |= ((k) ? ARCH_PERFMON_EVENTSEL_OS : 0)) +#define CTRL_SET_USR(val, u) ((val) |= ((u) ? ARCH_PERFMON_EVENTSEL_USR : 0)) +#define CTRL_SET_UM(val, m) ((val) |= ((m) << 8)) struct op_saved_msr { unsigned int high; -- cgit v0.10.2 From 9c59354b48ce9cf28048b02fea73dd0236f876ea Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 18:16:43 +0200 Subject: x86/oprofile: remove unused macros for AMD virtualization profiling The use of the macros has no effect. The oprofilefs has to be extended first to support these features. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index c6181c2..aaa7ffa 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -31,8 +31,6 @@ #define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0) #define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff)) #define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf)) -#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9)) -#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8)) static unsigned long reset_value[NUM_COUNTERS]; @@ -125,9 +123,6 @@ static void op_amd_setup_ctrs(struct op_msrs const * const msrs) CTRL_SET_UM(low, counter_config[i].unit_mask); CTRL_SET_EVENT_LOW(low, counter_config[i].event); CTRL_SET_EVENT_HIGH(high, counter_config[i].event); - CTRL_SET_HOST_ONLY(high, 0); - CTRL_SET_GUEST_ONLY(high, 0); - wrmsr(msrs->controls[i].addr, low, high); } else { reset_value[i] = 0; -- cgit v0.10.2 From ef8828ddf828174785421af67c281144d4b8e796 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 19:31:44 +0200 Subject: x86/oprofile: pass the model to setup_ctrs() functions In follow-on patches the setup_ctrs() functions will need data that describes the model. This patch extends the function argument list to pass a pointer of the model to these function. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index ae0ab03..c31f87b 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -125,7 +125,7 @@ static void nmi_cpu_setup(void *dummy) int cpu = smp_processor_id(); struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); spin_lock(&oprofilefs_lock); - model->setup_ctrs(msrs); + model->setup_ctrs(model, msrs); spin_unlock(&oprofilefs_lock); per_cpu(saved_lvtpc, cpu) = apic_read(APIC_LVTPC); apic_write(APIC_LVTPC, APIC_DM_NMI); diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index aaa7ffa..86e0a01 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -85,7 +85,8 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) } -static void op_amd_setup_ctrs(struct op_msrs const * const msrs) +static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs) { unsigned int low, high; int i; diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 365d8a9..05ba028 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -542,7 +542,8 @@ static void pmc_setup_one_p4_counter(unsigned int ctr) } -static void p4_setup_ctrs(struct op_msrs const * const msrs) +static void p4_setup_ctrs(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs) { unsigned int i; unsigned int low, high; diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 61ee8f6..40b44ee 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -51,7 +51,8 @@ static void ppro_fill_in_addresses(struct op_msrs * const msrs) } -static void ppro_setup_ctrs(struct op_msrs const * const msrs) +static void ppro_setup_ctrs(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs) { unsigned int low, high; int i; diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index a207b1c..6161c7f 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -48,7 +48,8 @@ struct op_x86_model_spec { int (*init)(struct oprofile_operations *ops); void (*exit)(void); void (*fill_in_addresses)(struct op_msrs * const msrs); - void (*setup_ctrs)(struct op_msrs const * const msrs); + void (*setup_ctrs)(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs); int (*check_ctrs)(struct pt_regs * const regs, struct op_msrs const * const msrs); void (*start)(struct op_msrs const * const msrs); -- cgit v0.10.2 From 3370d358569755625aba4d9a846a040ce691d9ed Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 15:10:32 +0200 Subject: x86/oprofile: replace macros to calculate control register This patch introduces op_x86_get_ctrl() to calculate the value of the performance control register. This is generic code usable for all models. The event and reserved masks are model specific and stored in struct op_x86_model_spec. 64 bit MSR functions are used now. The patch removes many hard to read macros used for ctrl calculation. The function op_x86_get_ctrl() is common code and the first step to further merge performance counter implementations for x86 models. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index c31f87b..388ee15 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -31,6 +31,26 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc); /* 0 == registered but off, 1 == registered and on */ static int nmi_enabled = 0; +/* common functions */ + +u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, + struct op_counter_config *counter_config) +{ + u64 val = 0; + u16 event = (u16)counter_config->event; + + val |= ARCH_PERFMON_EVENTSEL_INT; + val |= counter_config->user ? ARCH_PERFMON_EVENTSEL_USR : 0; + val |= counter_config->kernel ? ARCH_PERFMON_EVENTSEL_OS : 0; + val |= (counter_config->unit_mask & 0xFF) << 8; + event &= model->event_mask ? model->event_mask : 0xFF; + val |= event & 0xFF; + val |= (event & 0x0F00) << 24; + + return val; +} + + static int profile_exceptions_notify(struct notifier_block *self, unsigned long val, void *data) { diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 86e0a01..2406ab8 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -25,12 +25,11 @@ #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 +#define OP_EVENT_MASK 0x0FFF + +#define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21)) #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) -#define CTRL_CLEAR_LO(x) (x &= (1<<21)) -#define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0) -#define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff)) -#define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf)) static unsigned long reset_value[NUM_COUNTERS]; @@ -84,21 +83,19 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) } } - static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; /* clear all counters */ for (i = 0 ; i < NUM_CONTROLS; ++i) { if (unlikely(!CTRL_IS_RESERVED(msrs, i))) continue; - rdmsr(msrs->controls[i].addr, low, high); - CTRL_CLEAR_LO(low); - CTRL_CLEAR_HI(high); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + wrmsrl(msrs->controls[i].addr, val); } /* avoid a false detection of ctr overflows in NMI handler */ @@ -112,19 +109,11 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, for (i = 0; i < NUM_COUNTERS; ++i) { if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { reset_value[i] = counter_config[i].count; - wrmsr(msrs->counters[i].addr, -(unsigned int)counter_config[i].count, -1); - - rdmsr(msrs->controls[i].addr, low, high); - CTRL_CLEAR_LO(low); - CTRL_CLEAR_HI(high); - CTRL_SET_ENABLE(low); - CTRL_SET_USR(low, counter_config[i].user); - CTRL_SET_KERN(low, counter_config[i].kernel); - CTRL_SET_UM(low, counter_config[i].unit_mask); - CTRL_SET_EVENT_LOW(low, counter_config[i].event); - CTRL_SET_EVENT_HIGH(high, counter_config[i].event); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[i]); + wrmsrl(msrs->controls[i].addr, val); } else { reset_value[i] = 0; } @@ -486,14 +475,16 @@ static void op_amd_exit(void) {} #endif /* CONFIG_OPROFILE_IBS */ struct op_x86_model_spec const op_amd_spec = { - .init = op_amd_init, - .exit = op_amd_exit, .num_counters = NUM_COUNTERS, .num_controls = NUM_CONTROLS, + .reserved = MSR_AMD_EVENTSEL_RESERVED, + .event_mask = OP_EVENT_MASK, + .init = op_amd_init, + .exit = op_amd_exit, .fill_in_addresses = &op_amd_fill_in_addresses, .setup_ctrs = &op_amd_setup_ctrs, .check_ctrs = &op_amd_check_ctrs, .start = &op_amd_start, .stop = &op_amd_stop, - .shutdown = &op_amd_shutdown + .shutdown = &op_amd_shutdown, }; diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 40b44ee..3092f99 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -10,6 +10,7 @@ * @author Philippe Elie * @author Graydon Hoare * @author Andi Kleen + * @author Robert Richter */ #include @@ -26,8 +27,8 @@ static int num_counters = 2; static int counter_width = 32; #define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1)))) -#define CTRL_CLEAR(x) (x &= (1<<21)) -#define CTRL_SET_EVENT(val, e) (val |= e) + +#define MSR_PPRO_EVENTSEL_RESERVED ((0xFFFFFFFFULL<<32)|(1ULL<<21)) static u64 *reset_value; @@ -54,7 +55,7 @@ static void ppro_fill_in_addresses(struct op_msrs * const msrs) static void ppro_setup_ctrs(struct op_x86_model_spec const *model, struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; if (!reset_value) { @@ -85,9 +86,9 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, for (i = 0 ; i < num_counters; ++i) { if (unlikely(!CTRL_IS_RESERVED(msrs, i))) continue; - rdmsr(msrs->controls[i].addr, low, high); - CTRL_CLEAR(low); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + wrmsrl(msrs->controls[i].addr, val); } /* avoid a false detection of ctr overflows in NMI handler */ @@ -101,17 +102,11 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, for (i = 0; i < num_counters; ++i) { if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { reset_value[i] = counter_config[i].count; - wrmsrl(msrs->counters[i].addr, -reset_value[i]); - - rdmsr(msrs->controls[i].addr, low, high); - CTRL_CLEAR(low); - CTRL_SET_ENABLE(low); - CTRL_SET_USR(low, counter_config[i].user); - CTRL_SET_KERN(low, counter_config[i].kernel); - CTRL_SET_UM(low, counter_config[i].unit_mask); - CTRL_SET_EVENT(low, counter_config[i].event); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[i]); + wrmsrl(msrs->controls[i].addr, val); } else { reset_value[i] = 0; } @@ -205,6 +200,7 @@ static void ppro_shutdown(struct op_msrs const * const msrs) struct op_x86_model_spec const op_ppro_spec = { .num_counters = 2, .num_controls = 2, + .reserved = MSR_PPRO_EVENTSEL_RESERVED, .fill_in_addresses = &ppro_fill_in_addresses, .setup_ctrs = &ppro_setup_ctrs, .check_ctrs = &ppro_check_ctrs, @@ -249,6 +245,7 @@ static int arch_perfmon_init(struct oprofile_operations *ignore) } struct op_x86_model_spec op_arch_perfmon_spec = { + .reserved = MSR_PPRO_EVENTSEL_RESERVED, .init = &arch_perfmon_init, /* num_counters/num_controls filled in at runtime */ .fill_in_addresses = &ppro_fill_in_addresses, diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 6161c7f..3220d4c 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -6,21 +6,19 @@ * @remark Read the file COPYING * * @author Graydon Hoare + * @author Robert Richter */ #ifndef OP_X86_MODEL_H #define OP_X86_MODEL_H +#include #include #define CTR_IS_RESERVED(msrs, c) ((msrs)->counters[(c)].addr ? 1 : 0) #define CTRL_IS_RESERVED(msrs, c) ((msrs)->controls[(c)].addr ? 1 : 0) #define CTRL_SET_ACTIVE(val) ((val) |= ARCH_PERFMON_EVENTSEL0_ENABLE) -#define CTRL_SET_ENABLE(val) ((val) |= ARCH_PERFMON_EVENTSEL_INT) #define CTRL_SET_INACTIVE(val) ((val) &= ~ARCH_PERFMON_EVENTSEL0_ENABLE) -#define CTRL_SET_KERN(val, k) ((val) |= ((k) ? ARCH_PERFMON_EVENTSEL_OS : 0)) -#define CTRL_SET_USR(val, u) ((val) |= ((u) ? ARCH_PERFMON_EVENTSEL_USR : 0)) -#define CTRL_SET_UM(val, m) ((val) |= ((m) << 8)) struct op_saved_msr { unsigned int high; @@ -39,12 +37,16 @@ struct op_msrs { struct pt_regs; +struct oprofile_operations; + /* The model vtable abstracts the differences between * various x86 CPU models' perfctr support. */ struct op_x86_model_spec { unsigned int num_counters; unsigned int num_controls; + u64 reserved; + u16 event_mask; int (*init)(struct oprofile_operations *ops); void (*exit)(void); void (*fill_in_addresses)(struct op_msrs * const msrs); @@ -57,6 +59,11 @@ struct op_x86_model_spec { void (*shutdown)(struct op_msrs const * const msrs); }; +struct op_counter_config; + +extern u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, + struct op_counter_config *counter_config); + extern struct op_x86_model_spec const op_ppro_spec; extern struct op_x86_model_spec const op_p4_spec; extern struct op_x86_model_spec const op_p4_ht2_spec; -- cgit v0.10.2 From 42399adb239d4f1413899cc618ecf640779e79df Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 17:59:06 +0200 Subject: x86/oprofile: replace CTR_OVERFLOWED macros The patch replaces all CTR_OVERFLOWED macros. 64 bit MSR functions and 64 bit counter values are used now. Thus, it will be easier to later extend the models to use more than 32 bit width counters. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 2406ab8..b5d678f 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -26,11 +26,10 @@ #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 #define OP_EVENT_MASK 0x0FFF +#define OP_CTR_OVERFLOW (1ULL<<31) #define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21)) -#define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) - static unsigned long reset_value[NUM_COUNTERS]; #ifdef CONFIG_OPROFILE_IBS @@ -241,17 +240,18 @@ static inline void op_amd_stop_ibs(void) { } static int op_amd_check_ctrs(struct pt_regs * const regs, struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; for (i = 0 ; i < NUM_COUNTERS; ++i) { if (!reset_value[i]) continue; - rdmsr(msrs->counters[i].addr, low, high); - if (CTR_OVERFLOWED(low)) { - oprofile_add_sample(regs, i); - wrmsr(msrs->counters[i].addr, -(unsigned int)reset_value[i], -1); - } + rdmsrl(msrs->counters[i].addr, val); + /* bit is clear if overflowed: */ + if (val & OP_CTR_OVERFLOW) + continue; + oprofile_add_sample(regs, i); + wrmsr(msrs->counters[i].addr, -(unsigned int)reset_value[i], -1); } op_amd_handle_ibs(regs, msrs); diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 05ba028..ac4ca28 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -32,6 +32,8 @@ #define NUM_CCCRS_HT2 9 #define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2) +#define OP_CTR_OVERFLOW (1ULL<<31) + static unsigned int num_counters = NUM_COUNTERS_NON_HT; static unsigned int num_controls = NUM_CONTROLS_NON_HT; @@ -362,8 +364,6 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = { #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31)) #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31))) -#define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000)) - /* this assigns a "stagger" to the current CPU, which is used throughout the code in this module as an extra array offset, to select the "even" @@ -622,7 +622,7 @@ static int p4_check_ctrs(struct pt_regs * const regs, rdmsr(p4_counters[real].cccr_address, low, high); rdmsr(p4_counters[real].counter_address, ctr, high); - if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) { + if (CCCR_OVF_P(low) || !(ctr & OP_CTR_OVERFLOW)) { oprofile_add_sample(regs, i); wrmsr(p4_counters[real].counter_address, -(u32)reset_value[i], -1); diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 3092f99..82db396 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -26,8 +26,6 @@ static int num_counters = 2; static int counter_width = 32; -#define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1)))) - #define MSR_PPRO_EVENTSEL_RESERVED ((0xFFFFFFFFULL<<32)|(1ULL<<21)) static u64 *reset_value; @@ -124,10 +122,10 @@ static int ppro_check_ctrs(struct pt_regs * const regs, if (!reset_value[i]) continue; rdmsrl(msrs->counters[i].addr, val); - if (CTR_OVERFLOWED(val)) { - oprofile_add_sample(regs, i); - wrmsrl(msrs->counters[i].addr, -reset_value[i]); - } + if (val & (1ULL << (counter_width - 1))) + continue; + oprofile_add_sample(regs, i); + wrmsrl(msrs->counters[i].addr, -reset_value[i]); } /* Only P6 based Pentium M need to re-unmask the apic vector but it -- cgit v0.10.2 From dea3766ca052a4f572b16a23a322553c064d75af Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 18:11:52 +0200 Subject: x86/oprofile: replace CTRL_SET_*ACTIVE macros The patch replaces all CTRL_SET_*ACTIVE macros. 64 bit MSR functions and 64 bit counter values are used now. The code uses bit masks from . Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index b5d678f..4ac9d28 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -262,13 +262,13 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, static void op_amd_start(struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; for (i = 0 ; i < NUM_COUNTERS ; ++i) { if (reset_value[i]) { - rdmsr(msrs->controls[i].addr, low, high); - CTRL_SET_ACTIVE(low); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val |= ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(msrs->controls[i].addr, val); } } @@ -277,7 +277,7 @@ static void op_amd_start(struct op_msrs const * const msrs) static void op_amd_stop(struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; /* @@ -287,9 +287,9 @@ static void op_amd_stop(struct op_msrs const * const msrs) for (i = 0 ; i < NUM_COUNTERS ; ++i) { if (!reset_value[i]) continue; - rdmsr(msrs->controls[i].addr, low, high); - CTRL_SET_INACTIVE(low); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(msrs->controls[i].addr, val); } op_amd_stop_ibs(); diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 82db396..566b43f 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -145,16 +145,16 @@ static int ppro_check_ctrs(struct pt_regs * const regs, static void ppro_start(struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; if (!reset_value) return; for (i = 0; i < num_counters; ++i) { if (reset_value[i]) { - rdmsr(msrs->controls[i].addr, low, high); - CTRL_SET_ACTIVE(low); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val |= ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(msrs->controls[i].addr, val); } } } @@ -162,7 +162,7 @@ static void ppro_start(struct op_msrs const * const msrs) static void ppro_stop(struct op_msrs const * const msrs) { - unsigned int low, high; + u64 val; int i; if (!reset_value) @@ -170,9 +170,9 @@ static void ppro_stop(struct op_msrs const * const msrs) for (i = 0; i < num_counters; ++i) { if (!reset_value[i]) continue; - rdmsr(msrs->controls[i].addr, low, high); - CTRL_SET_INACTIVE(low); - wrmsr(msrs->controls[i].addr, low, high); + rdmsrl(msrs->controls[i].addr, val); + val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(msrs->controls[i].addr, val); } } diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 3220d4c..1c45777 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -17,8 +17,6 @@ #define CTR_IS_RESERVED(msrs, c) ((msrs)->counters[(c)].addr ? 1 : 0) #define CTRL_IS_RESERVED(msrs, c) ((msrs)->controls[(c)].addr ? 1 : 0) -#define CTRL_SET_ACTIVE(val) ((val) |= ARCH_PERFMON_EVENTSEL0_ENABLE) -#define CTRL_SET_INACTIVE(val) ((val) &= ~ARCH_PERFMON_EVENTSEL0_ENABLE) struct op_saved_msr { unsigned int high; -- cgit v0.10.2 From 217d3cfb959756cb493fc03106c0253baa420ce8 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 4 Jun 2009 02:36:44 +0200 Subject: x86/oprofile: replace CTR*_IS_RESERVED macros The patch replaces all CTR*_IS_RESERVED macros. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 4ac9d28..c5c5eec 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -90,7 +90,7 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, /* clear all counters */ for (i = 0 ; i < NUM_CONTROLS; ++i) { - if (unlikely(!CTRL_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->controls[i].addr)) continue; rdmsrl(msrs->controls[i].addr, val); val &= model->reserved; @@ -99,14 +99,14 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, /* avoid a false detection of ctr overflows in NMI handler */ for (i = 0; i < NUM_COUNTERS; ++i) { - if (unlikely(!CTR_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->counters[i].addr)) continue; wrmsr(msrs->counters[i].addr, -1, -1); } /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { - if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { + if (counter_config[i].enabled && msrs->counters[i].addr) { reset_value[i] = counter_config[i].count; wrmsr(msrs->counters[i].addr, -(unsigned int)counter_config[i].count, -1); rdmsrl(msrs->controls[i].addr, val); @@ -300,11 +300,11 @@ static void op_amd_shutdown(struct op_msrs const * const msrs) int i; for (i = 0 ; i < NUM_COUNTERS ; ++i) { - if (CTR_IS_RESERVED(msrs, i)) + if (msrs->counters[i].addr) release_perfctr_nmi(MSR_K7_PERFCTR0 + i); } for (i = 0 ; i < NUM_CONTROLS ; ++i) { - if (CTRL_IS_RESERVED(msrs, i)) + if (msrs->controls[i].addr) release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); } } diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index ac4ca28..9db0ca9 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -559,7 +559,7 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, /* clear the cccrs we will use */ for (i = 0 ; i < num_counters ; i++) { - if (unlikely(!CTRL_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->controls[i].addr)) continue; rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); CCCR_CLEAR(low); @@ -569,14 +569,14 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, /* clear all escrs (including those outside our concern) */ for (i = num_counters; i < num_controls; i++) { - if (unlikely(!CTRL_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->controls[i].addr)) continue; wrmsr(msrs->controls[i].addr, 0, 0); } /* setup all counters */ for (i = 0 ; i < num_counters ; ++i) { - if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs, i))) { + if (counter_config[i].enabled && msrs->controls[i].addr) { reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); wrmsr(p4_counters[VIRT_CTR(stag, i)].counter_address, @@ -679,7 +679,7 @@ static void p4_shutdown(struct op_msrs const * const msrs) int i; for (i = 0 ; i < num_counters ; ++i) { - if (CTR_IS_RESERVED(msrs, i)) + if (msrs->counters[i].addr) release_perfctr_nmi(msrs->counters[i].addr); } /* @@ -688,7 +688,7 @@ static void p4_shutdown(struct op_msrs const * const msrs) * This saves a few bits. */ for (i = num_counters ; i < num_controls ; ++i) { - if (CTRL_IS_RESERVED(msrs, i)) + if (msrs->controls[i].addr) release_evntsel_nmi(msrs->controls[i].addr); } } diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 566b43f..0a261a5 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -82,7 +82,7 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, /* clear all counters */ for (i = 0 ; i < num_counters; ++i) { - if (unlikely(!CTRL_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->controls[i].addr)) continue; rdmsrl(msrs->controls[i].addr, val); val &= model->reserved; @@ -91,14 +91,14 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, /* avoid a false detection of ctr overflows in NMI handler */ for (i = 0; i < num_counters; ++i) { - if (unlikely(!CTR_IS_RESERVED(msrs, i))) + if (unlikely(!msrs->counters[i].addr)) continue; wrmsrl(msrs->counters[i].addr, -1LL); } /* enable active counters */ for (i = 0; i < num_counters; ++i) { - if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { + if (counter_config[i].enabled && msrs->counters[i].addr) { reset_value[i] = counter_config[i].count; wrmsrl(msrs->counters[i].addr, -reset_value[i]); rdmsrl(msrs->controls[i].addr, val); @@ -181,11 +181,11 @@ static void ppro_shutdown(struct op_msrs const * const msrs) int i; for (i = 0 ; i < num_counters ; ++i) { - if (CTR_IS_RESERVED(msrs, i)) + if (msrs->counters[i].addr) release_perfctr_nmi(MSR_P6_PERFCTR0 + i); } for (i = 0 ; i < num_counters ; ++i) { - if (CTRL_IS_RESERVED(msrs, i)) + if (msrs->controls[i].addr) release_evntsel_nmi(MSR_P6_EVNTSEL0 + i); } if (reset_value) { diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 1c45777..69f1eb4 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -15,9 +15,6 @@ #include #include -#define CTR_IS_RESERVED(msrs, c) ((msrs)->counters[(c)].addr ? 1 : 0) -#define CTRL_IS_RESERVED(msrs, c) ((msrs)->controls[(c)].addr ? 1 : 0) - struct op_saved_msr { unsigned int high; unsigned int low; -- cgit v0.10.2 From bbc5986d2db427fdd61b6116ff8b9ed988e663a8 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 25 May 2009 17:38:19 +0200 Subject: x86/oprofile: use 64 bit wrmsr functions This patch replaces some wrmsr() functions with wrmsrl(). Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index c5c5eec..9bf9017 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -101,14 +101,15 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, for (i = 0; i < NUM_COUNTERS; ++i) { if (unlikely(!msrs->counters[i].addr)) continue; - wrmsr(msrs->counters[i].addr, -1, -1); + wrmsrl(msrs->counters[i].addr, -1LL); } /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { if (counter_config[i].enabled && msrs->counters[i].addr) { reset_value[i] = counter_config[i].count; - wrmsr(msrs->counters[i].addr, -(unsigned int)counter_config[i].count, -1); + wrmsrl(msrs->counters[i].addr, + -(s64)counter_config[i].count); rdmsrl(msrs->controls[i].addr, val); val &= model->reserved; val |= op_x86_get_ctrl(model, &counter_config[i]); @@ -251,7 +252,7 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, if (val & OP_CTR_OVERFLOW) continue; oprofile_add_sample(regs, i); - wrmsr(msrs->counters[i].addr, -(unsigned int)reset_value[i], -1); + wrmsrl(msrs->counters[i].addr, -(s64)reset_value[i]); } op_amd_handle_ibs(regs, msrs); diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 9db0ca9..f01e53b 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -579,8 +579,8 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, if (counter_config[i].enabled && msrs->controls[i].addr) { reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); - wrmsr(p4_counters[VIRT_CTR(stag, i)].counter_address, - -(u32)counter_config[i].count, -1); + wrmsrl(p4_counters[VIRT_CTR(stag, i)].counter_address, + -(s64)counter_config[i].count); } else { reset_value[i] = 0; } @@ -624,12 +624,12 @@ static int p4_check_ctrs(struct pt_regs * const regs, rdmsr(p4_counters[real].counter_address, ctr, high); if (CCCR_OVF_P(low) || !(ctr & OP_CTR_OVERFLOW)) { oprofile_add_sample(regs, i); - wrmsr(p4_counters[real].counter_address, - -(u32)reset_value[i], -1); + wrmsrl(p4_counters[real].counter_address, + -(s64)reset_value[i]); CCCR_CLEAR_OVF(low); wrmsr(p4_counters[real].cccr_address, low, high); - wrmsr(p4_counters[real].counter_address, - -(u32)reset_value[i], -1); + wrmsrl(p4_counters[real].counter_address, + -(s64)reset_value[i]); } } -- cgit v0.10.2 From 95e74e62c1540b1115fe8cec5b592f22960f2bb2 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 3 Jun 2009 19:09:27 +0200 Subject: x86/oprofile: use 64 bit values to save MSR states This patch removes struct op_saved_msr and replaces it by an u64 variable. This makes code easier and it is possible to use 64 bit MSR functions. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 388ee15..3b84b78 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -78,19 +78,13 @@ static void nmi_cpu_save_registers(struct op_msrs *msrs) unsigned int i; for (i = 0; i < nr_ctrs; ++i) { - if (counters[i].addr) { - rdmsr(counters[i].addr, - counters[i].saved.low, - counters[i].saved.high); - } + if (counters[i].addr) + rdmsrl(counters[i].addr, counters[i].saved); } for (i = 0; i < nr_ctrls; ++i) { - if (controls[i].addr) { - rdmsr(controls[i].addr, - controls[i].saved.low, - controls[i].saved.high); - } + if (controls[i].addr) + rdmsrl(controls[i].addr, controls[i].saved); } } @@ -204,19 +198,13 @@ static void nmi_restore_registers(struct op_msrs *msrs) unsigned int i; for (i = 0; i < nr_ctrls; ++i) { - if (controls[i].addr) { - wrmsr(controls[i].addr, - controls[i].saved.low, - controls[i].saved.high); - } + if (controls[i].addr) + wrmsrl(controls[i].addr, controls[i].saved); } for (i = 0; i < nr_ctrs; ++i) { - if (counters[i].addr) { - wrmsr(counters[i].addr, - counters[i].saved.low, - counters[i].saved.high); - } + if (counters[i].addr) + wrmsrl(counters[i].addr, counters[i].saved); } } diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 69f1eb4..fda52b4 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -15,14 +15,9 @@ #include #include -struct op_saved_msr { - unsigned int high; - unsigned int low; -}; - struct op_msr { - unsigned long addr; - struct op_saved_msr saved; + unsigned long addr; + u64 saved; }; struct op_msrs { -- cgit v0.10.2 From 1a245c45343651a87ff63afc5ddeb8e24d731835 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 5 Jun 2009 15:54:24 +0200 Subject: x86/oprofile: remove some local variables in MSR save/restore functions The patch removes some local variables in these functions. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 3b84b78..80b63d5 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -71,18 +71,16 @@ static int profile_exceptions_notify(struct notifier_block *self, static void nmi_cpu_save_registers(struct op_msrs *msrs) { - unsigned int const nr_ctrs = model->num_counters; - unsigned int const nr_ctrls = model->num_controls; struct op_msr *counters = msrs->counters; struct op_msr *controls = msrs->controls; unsigned int i; - for (i = 0; i < nr_ctrs; ++i) { + for (i = 0; i < model->num_counters; ++i) { if (counters[i].addr) rdmsrl(counters[i].addr, counters[i].saved); } - for (i = 0; i < nr_ctrls; ++i) { + for (i = 0; i < model->num_controls; ++i) { if (controls[i].addr) rdmsrl(controls[i].addr, controls[i].saved); } @@ -191,18 +189,16 @@ static int nmi_setup(void) static void nmi_restore_registers(struct op_msrs *msrs) { - unsigned int const nr_ctrs = model->num_counters; - unsigned int const nr_ctrls = model->num_controls; struct op_msr *counters = msrs->counters; struct op_msr *controls = msrs->controls; unsigned int i; - for (i = 0; i < nr_ctrls; ++i) { + for (i = 0; i < model->num_controls; ++i) { if (controls[i].addr) wrmsrl(controls[i].addr, controls[i].saved); } - for (i = 0; i < nr_ctrs; ++i) { + for (i = 0; i < model->num_counters; ++i) { if (counters[i].addr) wrmsrl(counters[i].addr, counters[i].saved); } -- cgit v0.10.2 From c572ae4efd1b0a5cc76c5e6aae05c1b182b6a69c Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 3 Jun 2009 20:10:39 +0200 Subject: x86/oprofile: use 64 bit values in IBS functions The IBS code internally uses 32 bit values (a low and a high value) to represent a 64 bit value. This patch changes this and now 64 bit values are used instead. 64 bit MSR functions can be used now. No functional changes. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 9bf9017..6493ef7 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -35,16 +35,18 @@ static unsigned long reset_value[NUM_COUNTERS]; #ifdef CONFIG_OPROFILE_IBS /* IbsFetchCtl bits/masks */ -#define IBS_FETCH_HIGH_VALID_BIT (1UL << 17) /* bit 49 */ -#define IBS_FETCH_HIGH_ENABLE (1UL << 16) /* bit 48 */ -#define IBS_FETCH_LOW_MAX_CNT_MASK 0x0000FFFFUL /* MaxCnt mask */ +#define IBS_FETCH_RAND_EN (1ULL<<57) +#define IBS_FETCH_VAL (1ULL<<49) +#define IBS_FETCH_ENABLE (1ULL<<48) +#define IBS_FETCH_CNT_MASK 0xFFFF0000ULL /*IbsOpCtl bits */ -#define IBS_OP_LOW_VALID_BIT (1ULL<<18) /* bit 18 */ -#define IBS_OP_LOW_ENABLE (1ULL<<17) /* bit 17 */ +#define IBS_OP_CNT_CTL (1ULL<<19) +#define IBS_OP_VAL (1ULL<<18) +#define IBS_OP_ENABLE (1ULL<<17) -#define IBS_FETCH_SIZE 6 -#define IBS_OP_SIZE 12 +#define IBS_FETCH_SIZE 6 +#define IBS_OP_SIZE 12 static int has_ibs; /* AMD Family10h and later */ @@ -126,66 +128,63 @@ static inline int op_amd_handle_ibs(struct pt_regs * const regs, struct op_msrs const * const msrs) { - u32 low, high; - u64 msr; + u64 val, ctl; struct op_entry entry; if (!has_ibs) return 1; if (ibs_config.fetch_enabled) { - rdmsr(MSR_AMD64_IBSFETCHCTL, low, high); - if (high & IBS_FETCH_HIGH_VALID_BIT) { - rdmsrl(MSR_AMD64_IBSFETCHLINAD, msr); - oprofile_write_reserve(&entry, regs, msr, + rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl); + if (ctl & IBS_FETCH_VAL) { + rdmsrl(MSR_AMD64_IBSFETCHLINAD, val); + oprofile_write_reserve(&entry, regs, val, IBS_FETCH_CODE, IBS_FETCH_SIZE); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - oprofile_add_data(&entry, low); - oprofile_add_data(&entry, high); - rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data(&entry, (u32)ctl); + oprofile_add_data(&entry, (u32)(ctl >> 32)); + rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); oprofile_write_commit(&entry); /* reenable the IRQ */ - high &= ~IBS_FETCH_HIGH_VALID_BIT; - high |= IBS_FETCH_HIGH_ENABLE; - low &= IBS_FETCH_LOW_MAX_CNT_MASK; - wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); + ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT_MASK); + ctl |= IBS_FETCH_ENABLE; + wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl); } } if (ibs_config.op_enabled) { - rdmsr(MSR_AMD64_IBSOPCTL, low, high); - if (low & IBS_OP_LOW_VALID_BIT) { - rdmsrl(MSR_AMD64_IBSOPRIP, msr); - oprofile_write_reserve(&entry, regs, msr, + rdmsrl(MSR_AMD64_IBSOPCTL, ctl); + if (ctl & IBS_OP_VAL) { + rdmsrl(MSR_AMD64_IBSOPRIP, val); + oprofile_write_reserve(&entry, regs, val, IBS_OP_CODE, IBS_OP_SIZE); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - rdmsrl(MSR_AMD64_IBSOPDATA, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - rdmsrl(MSR_AMD64_IBSOPDATA2, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - rdmsrl(MSR_AMD64_IBSOPDATA3, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - rdmsrl(MSR_AMD64_IBSDCLINAD, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); - rdmsrl(MSR_AMD64_IBSDCPHYSAD, msr); - oprofile_add_data(&entry, (u32)msr); - oprofile_add_data(&entry, (u32)(msr >> 32)); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA2, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + rdmsrl(MSR_AMD64_IBSOPDATA3, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + rdmsrl(MSR_AMD64_IBSDCLINAD, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); + rdmsrl(MSR_AMD64_IBSDCPHYSAD, val); + oprofile_add_data(&entry, (u32)val); + oprofile_add_data(&entry, (u32)(val >> 32)); oprofile_write_commit(&entry); /* reenable the IRQ */ - high = 0; - low &= ~IBS_OP_LOW_VALID_BIT; - low |= IBS_OP_LOW_ENABLE; - wrmsr(MSR_AMD64_IBSOPCTL, low, high); + ctl &= ~IBS_OP_VAL & 0xFFFFFFFF; + ctl |= IBS_OP_ENABLE; + wrmsrl(MSR_AMD64_IBSOPCTL, ctl); } } @@ -194,39 +193,31 @@ op_amd_handle_ibs(struct pt_regs * const regs, static inline void op_amd_start_ibs(void) { - unsigned int low, high; + u64 val; if (has_ibs && ibs_config.fetch_enabled) { - low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; - high = ((ibs_config.rand_en & 0x1) << 25) /* bit 57 */ - + IBS_FETCH_HIGH_ENABLE; - wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); + val = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF; + val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0; + val |= IBS_FETCH_ENABLE; + wrmsrl(MSR_AMD64_IBSFETCHCTL, val); } if (has_ibs && ibs_config.op_enabled) { - low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) - + ((ibs_config.dispatched_ops & 0x1) << 19) /* bit 19 */ - + IBS_OP_LOW_ENABLE; - high = 0; - wrmsr(MSR_AMD64_IBSOPCTL, low, high); + val = (ibs_config.max_cnt_op >> 4) & 0xFFFF; + val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0; + val |= IBS_OP_ENABLE; + wrmsrl(MSR_AMD64_IBSOPCTL, val); } } static void op_amd_stop_ibs(void) { - unsigned int low, high; - if (has_ibs && ibs_config.fetch_enabled) { + if (has_ibs && ibs_config.fetch_enabled) /* clear max count and enable */ - low = 0; - high = 0; - wrmsr(MSR_AMD64_IBSFETCHCTL, low, high); - } + wrmsrl(MSR_AMD64_IBSFETCHCTL, 0); - if (has_ibs && ibs_config.op_enabled) { + if (has_ibs && ibs_config.op_enabled) /* clear max count and enable */ - low = 0; - high = 0; - wrmsr(MSR_AMD64_IBSOPCTL, low, high); - } + wrmsrl(MSR_AMD64_IBSOPCTL, 0); } #else -- cgit v0.10.2 From 51563a0e5650d0d76539625388d72d62b34c726e Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 3 Jun 2009 20:54:56 +0200 Subject: x86/oprofile: introduce oprofile_add_data64() The IBS implemention writes 64 bit register values to the cpu buffer by writing two 32 values using oprofile_add_data(). This patch introduces oprofile_add_data64() to write a single 64 bit value to the buffer. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 6493ef7..cc93046 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -140,13 +140,10 @@ op_amd_handle_ibs(struct pt_regs * const regs, rdmsrl(MSR_AMD64_IBSFETCHLINAD, val); oprofile_write_reserve(&entry, regs, val, IBS_FETCH_CODE, IBS_FETCH_SIZE); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); - oprofile_add_data(&entry, (u32)ctl); - oprofile_add_data(&entry, (u32)(ctl >> 32)); + oprofile_add_data64(&entry, val); + oprofile_add_data64(&entry, ctl); rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); oprofile_write_commit(&entry); /* reenable the IRQ */ @@ -162,23 +159,17 @@ op_amd_handle_ibs(struct pt_regs * const regs, rdmsrl(MSR_AMD64_IBSOPRIP, val); oprofile_write_reserve(&entry, regs, val, IBS_OP_CODE, IBS_OP_SIZE); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); rdmsrl(MSR_AMD64_IBSOPDATA, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); rdmsrl(MSR_AMD64_IBSOPDATA2, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); rdmsrl(MSR_AMD64_IBSOPDATA3, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); rdmsrl(MSR_AMD64_IBSDCLINAD, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); rdmsrl(MSR_AMD64_IBSDCPHYSAD, val); - oprofile_add_data(&entry, (u32)val); - oprofile_add_data(&entry, (u32)(val >> 32)); + oprofile_add_data64(&entry, val); oprofile_write_commit(&entry); /* reenable the IRQ */ diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 50640cc..a7aae24 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -406,6 +406,21 @@ int oprofile_add_data(struct op_entry *entry, unsigned long val) return op_cpu_buffer_add_data(entry, val); } +int oprofile_add_data64(struct op_entry *entry, u64 val) +{ + if (!entry->event) + return 0; + if (op_cpu_buffer_get_size(entry) < 2) + /* + * the function returns 0 to indicate a too small + * buffer, even if there is some space left + */ + return 0; + if (!op_cpu_buffer_add_data(entry, (u32)val)) + return 0; + return op_cpu_buffer_add_data(entry, (u32)(val >> 32)); +} + int oprofile_write_commit(struct op_entry *entry) { if (!entry->event) diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index dbbe2db..d68d2ed 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -179,6 +179,7 @@ void oprofile_write_reserve(struct op_entry *entry, struct pt_regs * const regs, unsigned long pc, int code, int size); int oprofile_add_data(struct op_entry *entry, unsigned long val); +int oprofile_add_data64(struct op_entry *entry, u64 val); int oprofile_write_commit(struct op_entry *entry); #endif /* OPROFILE_H */ -- cgit v0.10.2 From fa44c077eb2a17aa6913feceb493d13f45f3fa25 Mon Sep 17 00:00:00 2001 From: Daniel Ribeiro Date: Wed, 10 Jun 2009 15:23:24 -0300 Subject: ASoC: remove duplicated code on pxa-ssp.c * We don't need to write the registers twice, remove the first write. * DAIFMT_INV switch is duplicated inside DAIFMT_FORMAT switch, move it out. (This patch is for Mark's for-2.6.32 branch, I have not checked if the code is duplicated on current 2.6.30) Signed-off-by: Daniel Ribeiro Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 19c4540..e22c5ce 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -457,31 +457,27 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } - ssp_write_reg(ssp, SSCR0, sscr0); - ssp_write_reg(ssp, SSCR1, sscr1); - ssp_write_reg(ssp, SSPSP, sspsp); + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + sspsp |= SSPSP_SFRMP; + break; + case SND_SOC_DAIFMT_NB_IF: + break; + case SND_SOC_DAIFMT_IB_IF: + sspsp |= SSPSP_SCMODE(2); + break; + case SND_SOC_DAIFMT_IB_NF: + sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP; + break; + default: + return -EINVAL; + } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: sscr0 |= SSCR0_PSP; sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; - /* See hw_params() */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - sspsp |= SSPSP_SFRMP; - break; - case SND_SOC_DAIFMT_NB_IF: - break; - case SND_SOC_DAIFMT_IB_IF: - sspsp |= SSPSP_SCMODE(2); - break; - case SND_SOC_DAIFMT_IB_NF: - sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP; - break; - default: - return -EINVAL; - } break; case SND_SOC_DAIFMT_DSP_A: @@ -489,22 +485,6 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, case SND_SOC_DAIFMT_DSP_B: sscr0 |= SSCR0_MOD | SSCR0_PSP; sscr1 |= SSCR1_TRAIL | SSCR1_RWOT; - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - sspsp |= SSPSP_SFRMP; - break; - case SND_SOC_DAIFMT_NB_IF: - break; - case SND_SOC_DAIFMT_IB_IF: - sspsp |= SSPSP_SCMODE(2); - break; - case SND_SOC_DAIFMT_IB_NF: - sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP; - break; - default: - return -EINVAL; - } break; default: -- cgit v0.10.2 From 1cc4ce6f5f89cdc355013aa43f06a14a015766d1 Mon Sep 17 00:00:00 2001 From: Maynard Johnson Date: Wed, 27 May 2009 10:15:08 -0500 Subject: oprofile: reset bt_lost_no_mapping with other stats The bt_lost_no_mapping is not getting reset at the start of a profiling run, thus the oprofiled.log shows erroneous values for this statistic. The attached patch fixes this problem. Signed-off-by: Maynard Johnson Signed-off-by: Robert Richter diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index e1f6ce0..efefae5 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -33,6 +33,7 @@ void oprofile_reset_stats(void) atomic_set(&oprofile_stats.sample_lost_no_mm, 0); atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); + atomic_set(&oprofile_stats.bt_lost_no_mapping,0); } -- cgit v0.10.2 From 74dc55ed5b709e4a2a538252f98ea62358df82ce Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Jun 2009 09:55:51 +0100 Subject: ASoC: Add WM8961 driver The WM8961 is a low power, high quality stereo CODEC designed for portable digital applications with headphone and stereo class D speaker drivers. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index bbc97fd..021dbdf 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -39,6 +39,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8903 if I2C select SND_SOC_WM8940 if I2C select SND_SOC_WM8960 if I2C + select SND_SOC_WM8961 if I2C select SND_SOC_WM8971 if I2C select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8990 if I2C @@ -156,6 +157,9 @@ config SND_SOC_WM8940 config SND_SOC_WM8960 tristate +config SND_SOC_WM8961 + tristate + config SND_SOC_WM8971 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 8b75305..e520c2b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -27,6 +27,7 @@ snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o snd-soc-wm8940-objs := wm8940.o snd-soc-wm8960-objs := wm8960.o +snd-soc-wm8961-objs := wm8961.o snd-soc-wm8971-objs := wm8971.o snd-soc-wm8988-objs := wm8988.o snd-soc-wm8990-objs := wm8990.o @@ -65,6 +66,7 @@ obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o +obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c new file mode 100644 index 0000000..8e78959 --- /dev/null +++ b/sound/soc/codecs/wm8961.c @@ -0,0 +1,1309 @@ +/* + * wm8961.c -- WM8961 ALSA SoC Audio driver + * + * Author: Mark Brown + * + * 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 + * published by the Free Software Foundation. + * + * Currently unimplemented features: + * - ALC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8961.h" + +#define WM8961_MAX_REGISTER 0xFC + +static u16 wm8961_reg_defaults[] = { + 0x009F, /* R0 - Left Input volume */ + 0x009F, /* R1 - Right Input volume */ + 0x0000, /* R2 - LOUT1 volume */ + 0x0000, /* R3 - ROUT1 volume */ + 0x0020, /* R4 - Clocking1 */ + 0x0008, /* R5 - ADC & DAC Control 1 */ + 0x0000, /* R6 - ADC & DAC Control 2 */ + 0x000A, /* R7 - Audio Interface 0 */ + 0x01F4, /* R8 - Clocking2 */ + 0x0000, /* R9 - Audio Interface 1 */ + 0x00FF, /* R10 - Left DAC volume */ + 0x00FF, /* R11 - Right DAC volume */ + 0x0000, /* R12 */ + 0x0000, /* R13 */ + 0x0040, /* R14 - Audio Interface 2 */ + 0x0000, /* R15 - Software Reset */ + 0x0000, /* R16 */ + 0x007B, /* R17 - ALC1 */ + 0x0000, /* R18 - ALC2 */ + 0x0032, /* R19 - ALC3 */ + 0x0000, /* R20 - Noise Gate */ + 0x00C0, /* R21 - Left ADC volume */ + 0x00C0, /* R22 - Right ADC volume */ + 0x0120, /* R23 - Additional control(1) */ + 0x0000, /* R24 - Additional control(2) */ + 0x0000, /* R25 - Pwr Mgmt (1) */ + 0x0000, /* R26 - Pwr Mgmt (2) */ + 0x0000, /* R27 - Additional Control (3) */ + 0x0000, /* R28 - Anti-pop */ + 0x0000, /* R29 */ + 0x005F, /* R30 - Clocking 3 */ + 0x0000, /* R31 */ + 0x0000, /* R32 - ADCL signal path */ + 0x0000, /* R33 - ADCR signal path */ + 0x0000, /* R34 */ + 0x0000, /* R35 */ + 0x0000, /* R36 */ + 0x0000, /* R37 */ + 0x0000, /* R38 */ + 0x0000, /* R39 */ + 0x0000, /* R40 - LOUT2 volume */ + 0x0000, /* R41 - ROUT2 volume */ + 0x0000, /* R42 */ + 0x0000, /* R43 */ + 0x0000, /* R44 */ + 0x0000, /* R45 */ + 0x0000, /* R46 */ + 0x0000, /* R47 - Pwr Mgmt (3) */ + 0x0023, /* R48 - Additional Control (4) */ + 0x0000, /* R49 - Class D Control 1 */ + 0x0000, /* R50 */ + 0x0003, /* R51 - Class D Control 2 */ + 0x0000, /* R52 */ + 0x0000, /* R53 */ + 0x0000, /* R54 */ + 0x0000, /* R55 */ + 0x0106, /* R56 - Clocking 4 */ + 0x0000, /* R57 - DSP Sidetone 0 */ + 0x0000, /* R58 - DSP Sidetone 1 */ + 0x0000, /* R59 */ + 0x0000, /* R60 - DC Servo 0 */ + 0x0000, /* R61 - DC Servo 1 */ + 0x0000, /* R62 */ + 0x015E, /* R63 - DC Servo 3 */ + 0x0010, /* R64 */ + 0x0010, /* R65 - DC Servo 5 */ + 0x0000, /* R66 */ + 0x0001, /* R67 */ + 0x0003, /* R68 - Analogue PGA Bias */ + 0x0000, /* R69 - Analogue HP 0 */ + 0x0060, /* R70 */ + 0x01FB, /* R71 - Analogue HP 2 */ + 0x0000, /* R72 - Charge Pump 1 */ + 0x0065, /* R73 */ + 0x005F, /* R74 */ + 0x0059, /* R75 */ + 0x006B, /* R76 */ + 0x0038, /* R77 */ + 0x000C, /* R78 */ + 0x000A, /* R79 */ + 0x006B, /* R80 */ + 0x0000, /* R81 */ + 0x0000, /* R82 - Charge Pump B */ + 0x0087, /* R83 */ + 0x0000, /* R84 */ + 0x005C, /* R85 */ + 0x0000, /* R86 */ + 0x0000, /* R87 - Write Sequencer 1 */ + 0x0000, /* R88 - Write Sequencer 2 */ + 0x0000, /* R89 - Write Sequencer 3 */ + 0x0000, /* R90 - Write Sequencer 4 */ + 0x0000, /* R91 - Write Sequencer 5 */ + 0x0000, /* R92 - Write Sequencer 6 */ + 0x0000, /* R93 - Write Sequencer 7 */ + 0x0000, /* R94 */ + 0x0000, /* R95 */ + 0x0000, /* R96 */ + 0x0000, /* R97 */ + 0x0000, /* R98 */ + 0x0000, /* R99 */ + 0x0000, /* R100 */ + 0x0000, /* R101 */ + 0x0000, /* R102 */ + 0x0000, /* R103 */ + 0x0000, /* R104 */ + 0x0000, /* R105 */ + 0x0000, /* R106 */ + 0x0000, /* R107 */ + 0x0000, /* R108 */ + 0x0000, /* R109 */ + 0x0000, /* R110 */ + 0x0000, /* R111 */ + 0x0000, /* R112 */ + 0x0000, /* R113 */ + 0x0000, /* R114 */ + 0x0000, /* R115 */ + 0x0000, /* R116 */ + 0x0000, /* R117 */ + 0x0000, /* R118 */ + 0x0000, /* R119 */ + 0x0000, /* R120 */ + 0x0000, /* R121 */ + 0x0000, /* R122 */ + 0x0000, /* R123 */ + 0x0000, /* R124 */ + 0x0000, /* R125 */ + 0x0000, /* R126 */ + 0x0000, /* R127 */ + 0x0000, /* R128 */ + 0x0000, /* R129 */ + 0x0000, /* R130 */ + 0x0000, /* R131 */ + 0x0000, /* R132 */ + 0x0000, /* R133 */ + 0x0000, /* R134 */ + 0x0000, /* R135 */ + 0x0000, /* R136 */ + 0x0000, /* R137 */ + 0x0000, /* R138 */ + 0x0000, /* R139 */ + 0x0000, /* R140 */ + 0x0000, /* R141 */ + 0x0000, /* R142 */ + 0x0000, /* R143 */ + 0x0000, /* R144 */ + 0x0000, /* R145 */ + 0x0000, /* R146 */ + 0x0000, /* R147 */ + 0x0000, /* R148 */ + 0x0000, /* R149 */ + 0x0000, /* R150 */ + 0x0000, /* R151 */ + 0x0000, /* R152 */ + 0x0000, /* R153 */ + 0x0000, /* R154 */ + 0x0000, /* R155 */ + 0x0000, /* R156 */ + 0x0000, /* R157 */ + 0x0000, /* R158 */ + 0x0000, /* R159 */ + 0x0000, /* R160 */ + 0x0000, /* R161 */ + 0x0000, /* R162 */ + 0x0000, /* R163 */ + 0x0000, /* R164 */ + 0x0000, /* R165 */ + 0x0000, /* R166 */ + 0x0000, /* R167 */ + 0x0000, /* R168 */ + 0x0000, /* R169 */ + 0x0000, /* R170 */ + 0x0000, /* R171 */ + 0x0000, /* R172 */ + 0x0000, /* R173 */ + 0x0000, /* R174 */ + 0x0000, /* R175 */ + 0x0000, /* R176 */ + 0x0000, /* R177 */ + 0x0000, /* R178 */ + 0x0000, /* R179 */ + 0x0000, /* R180 */ + 0x0000, /* R181 */ + 0x0000, /* R182 */ + 0x0000, /* R183 */ + 0x0000, /* R184 */ + 0x0000, /* R185 */ + 0x0000, /* R186 */ + 0x0000, /* R187 */ + 0x0000, /* R188 */ + 0x0000, /* R189 */ + 0x0000, /* R190 */ + 0x0000, /* R191 */ + 0x0000, /* R192 */ + 0x0000, /* R193 */ + 0x0000, /* R194 */ + 0x0000, /* R195 */ + 0x0030, /* R196 */ + 0x0006, /* R197 */ + 0x0000, /* R198 */ + 0x0060, /* R199 */ + 0x0000, /* R200 */ + 0x003F, /* R201 */ + 0x0000, /* R202 */ + 0x0000, /* R203 */ + 0x0000, /* R204 */ + 0x0001, /* R205 */ + 0x0000, /* R206 */ + 0x0181, /* R207 */ + 0x0005, /* R208 */ + 0x0008, /* R209 */ + 0x0008, /* R210 */ + 0x0000, /* R211 */ + 0x013B, /* R212 */ + 0x0000, /* R213 */ + 0x0000, /* R214 */ + 0x0000, /* R215 */ + 0x0000, /* R216 */ + 0x0070, /* R217 */ + 0x0000, /* R218 */ + 0x0000, /* R219 */ + 0x0000, /* R220 */ + 0x0000, /* R221 */ + 0x0000, /* R222 */ + 0x0003, /* R223 */ + 0x0000, /* R224 */ + 0x0000, /* R225 */ + 0x0001, /* R226 */ + 0x0008, /* R227 */ + 0x0000, /* R228 */ + 0x0000, /* R229 */ + 0x0000, /* R230 */ + 0x0000, /* R231 */ + 0x0004, /* R232 */ + 0x0000, /* R233 */ + 0x0000, /* R234 */ + 0x0000, /* R235 */ + 0x0000, /* R236 */ + 0x0000, /* R237 */ + 0x0080, /* R238 */ + 0x0000, /* R239 */ + 0x0000, /* R240 */ + 0x0000, /* R241 */ + 0x0000, /* R242 */ + 0x0000, /* R243 */ + 0x0000, /* R244 */ + 0x0052, /* R245 */ + 0x0110, /* R246 */ + 0x0040, /* R247 */ + 0x0000, /* R248 */ + 0x0030, /* R249 */ + 0x0000, /* R250 */ + 0x0000, /* R251 */ + 0x0001, /* R252 - General test 1 */ +}; + +struct wm8961_priv { + struct snd_soc_codec codec; + int sysclk; + u16 reg_cache[WM8961_MAX_REGISTER]; +}; + +static int wm8961_reg_is_volatile(int reg) +{ + switch (reg) { + case WM8961_WRITE_SEQUENCER_7: + case WM8961_DC_SERVO_1: + return 1; + + default: + return 0; + } +} + +static unsigned int wm8961_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg > WM8961_MAX_REGISTER); + return cache[reg]; +} + +static unsigned int wm8961_read_hw(struct snd_soc_codec *codec, u8 reg) +{ + struct i2c_msg xfer[2]; + u16 data; + int ret; + struct i2c_client *client = codec->control_data; + + BUG_ON(reg > WM8961_MAX_REGISTER); + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = ® + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (u8 *)&data; + + ret = i2c_transfer(client->adapter, xfer, 2); + if (ret != 2) { + dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + return 0; + } + + return (data >> 8) | ((data & 0xff) << 8); +} + +static unsigned int wm8961_read(struct snd_soc_codec *codec, unsigned int reg) +{ + if (wm8961_reg_is_volatile(reg)) + return wm8961_read_hw(codec, reg); + else + return wm8961_read_reg_cache(codec, reg); +} + +static int wm8961_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 *cache = codec->reg_cache; + u8 data[3]; + + BUG_ON(reg > WM8961_MAX_REGISTER); + + if (!wm8961_reg_is_volatile(reg)) + cache[reg] = value; + + data[0] = reg; + data[1] = value >> 8; + data[2] = value & 0x00ff; + + if (codec->hw_write(codec->control_data, data, 3) == 3) + return 0; + else + return -EIO; +} + +static int wm8961_reset(struct snd_soc_codec *codec) +{ + return wm8961_write(codec, WM8961_SOFTWARE_RESET, 0); +} + +/* + * The headphone output supports special anti-pop sequences giving + * silent power up and power down. + */ +static int wm8961_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + u16 hp_reg = wm8961_read(codec, WM8961_ANALOGUE_HP_0); + u16 cp_reg = wm8961_read(codec, WM8961_CHARGE_PUMP_1); + u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2); + u16 dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1); + int timeout = 500; + + if (event & SND_SOC_DAPM_POST_PMU) { + /* Make sure the output is shorted */ + hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + + /* Enable the charge pump */ + cp_reg |= WM8961_CP_ENA; + wm8961_write(codec, WM8961_CHARGE_PUMP_1, cp_reg); + mdelay(5); + + /* Enable the PGA */ + pwr_reg |= WM8961_LOUT1_PGA | WM8961_ROUT1_PGA; + wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + + /* Enable the amplifier */ + hp_reg |= WM8961_HPR_ENA | WM8961_HPL_ENA; + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + + /* Second stage enable */ + hp_reg |= WM8961_HPR_ENA_DLY | WM8961_HPL_ENA_DLY; + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + + /* Enable the DC servo & trigger startup */ + dcs_reg |= + WM8961_DCS_ENA_CHAN_HPR | WM8961_DCS_TRIG_STARTUP_HPR | + WM8961_DCS_ENA_CHAN_HPL | WM8961_DCS_TRIG_STARTUP_HPL; + dev_dbg(codec->dev, "Enabling DC servo\n"); + + wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg); + do { + msleep(1); + dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1); + } while (--timeout && + dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR | + WM8961_DCS_TRIG_STARTUP_HPL)); + if (dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR | + WM8961_DCS_TRIG_STARTUP_HPL)) + dev_err(codec->dev, "DC servo timed out\n"); + else + dev_dbg(codec->dev, "DC servo startup complete\n"); + + /* Enable the output stage */ + hp_reg |= WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP; + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + + /* Remove the short on the output stage */ + hp_reg |= WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT; + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + } + + if (event & SND_SOC_DAPM_PRE_PMD) { + /* Short the output */ + hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + + /* Disable the output stage */ + hp_reg &= ~(WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + + /* Disable DC offset cancellation */ + dcs_reg &= ~(WM8961_DCS_ENA_CHAN_HPR | + WM8961_DCS_ENA_CHAN_HPL); + wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg); + + /* Finish up */ + hp_reg &= ~(WM8961_HPR_ENA_DLY | WM8961_HPR_ENA | + WM8961_HPL_ENA_DLY | WM8961_HPL_ENA); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + + /* Disable the PGA */ + pwr_reg &= ~(WM8961_LOUT1_PGA | WM8961_ROUT1_PGA); + wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + + /* Disable the charge pump */ + dev_dbg(codec->dev, "Disabling charge pump\n"); + wm8961_write(codec, WM8961_CHARGE_PUMP_1, + cp_reg & ~WM8961_CP_ENA); + } + + return 0; +} + +static int wm8961_spk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2); + u16 spk_reg = wm8961_read(codec, WM8961_CLASS_D_CONTROL_1); + + if (event & SND_SOC_DAPM_POST_PMU) { + /* Enable the PGA */ + pwr_reg |= WM8961_SPKL_PGA | WM8961_SPKR_PGA; + wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + + /* Enable the amplifier */ + spk_reg |= WM8961_SPKL_ENA | WM8961_SPKR_ENA; + wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); + } + + if (event & SND_SOC_DAPM_PRE_PMD) { + /* Enable the amplifier */ + spk_reg &= ~(WM8961_SPKL_ENA | WM8961_SPKR_ENA); + wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); + + /* Enable the PGA */ + pwr_reg &= ~(WM8961_SPKL_PGA | WM8961_SPKR_PGA); + wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + } + + return 0; +} + +static const char *adc_hpf_text[] = { + "Hi-fi", "Voice 1", "Voice 2", "Voice 3", +}; + +static const struct soc_enum adc_hpf = + SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_2, 7, 4, adc_hpf_text); + +static const char *dac_deemph_text[] = { + "None", "32kHz", "44.1kHz", "48kHz", +}; + +static const struct soc_enum dac_deemph = + SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_1, 1, 4, dac_deemph_text); + +static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); +static const DECLARE_TLV_DB_SCALE(hp_sec_tlv, -700, 100, 0); +static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1); +static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0); +static unsigned int boost_tlv[] = { + TLV_DB_RANGE_HEAD(4), + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(13, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(20, 0, 0), + 3, 3, TLV_DB_SCALE_ITEM(29, 0, 0), +}; +static const DECLARE_TLV_DB_SCALE(pga_tlv, -2325, 75, 0); + +static const struct snd_kcontrol_new wm8961_snd_controls[] = { +SOC_DOUBLE_R_TLV("Headphone Volume", WM8961_LOUT1_VOLUME, WM8961_ROUT1_VOLUME, + 0, 127, 0, out_tlv), +SOC_DOUBLE_TLV("Headphone Secondary Volume", WM8961_ANALOGUE_HP_2, + 6, 3, 7, 0, hp_sec_tlv), +SOC_DOUBLE_R("Headphone ZC Switch", WM8961_LOUT1_VOLUME, WM8961_ROUT1_VOLUME, + 7, 1, 0), + +SOC_DOUBLE_R_TLV("Speaker Volume", WM8961_LOUT2_VOLUME, WM8961_ROUT2_VOLUME, + 0, 127, 0, out_tlv), +SOC_DOUBLE_R("Speaker ZC Switch", WM8961_LOUT2_VOLUME, WM8961_ROUT2_VOLUME, + 7, 1, 0), +SOC_SINGLE("Speaker AC Gain", WM8961_CLASS_D_CONTROL_2, 0, 7, 0), + +SOC_SINGLE("DAC x128 OSR Switch", WM8961_ADC_DAC_CONTROL_2, 0, 1, 0), +SOC_ENUM("DAC Deemphasis", dac_deemph), +SOC_SINGLE("DAC Soft Mute Switch", WM8961_ADC_DAC_CONTROL_2, 3, 1, 0), + +SOC_DOUBLE_R_TLV("Sidetone Volume", WM8961_DSP_SIDETONE_0, + WM8961_DSP_SIDETONE_1, 4, 12, 0, sidetone_tlv), + +SOC_SINGLE("ADC High Pass Filter Switch", WM8961_ADC_DAC_CONTROL_1, 0, 1, 0), +SOC_ENUM("ADC High Pass Filter Mode", adc_hpf), + +SOC_DOUBLE_R_TLV("Capture Volume", + WM8961_LEFT_ADC_VOLUME, WM8961_RIGHT_ADC_VOLUME, + 1, 119, 0, adc_tlv), +SOC_DOUBLE_R_TLV("Capture Boost Volume", + WM8961_ADCL_SIGNAL_PATH, WM8961_ADCR_SIGNAL_PATH, + 4, 3, 0, boost_tlv), +SOC_DOUBLE_R_TLV("Capture PGA Volume", + WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME, + 0, 62, 0, pga_tlv), +SOC_DOUBLE_R("Capture PGA ZC Switch", + WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME, + 6, 1, 1), +SOC_DOUBLE_R("Capture PGA Switch", + WM8961_LEFT_INPUT_VOLUME, WM8961_RIGHT_INPUT_VOLUME, + 7, 1, 1), +}; + +static const char *sidetone_text[] = { + "None", "Left", "Right" +}; + +static const struct soc_enum dacl_sidetone = + SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_0, 2, 3, sidetone_text); + +static const struct soc_enum dacr_sidetone = + SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_1, 2, 3, sidetone_text); + +static const struct snd_kcontrol_new dacl_mux = + SOC_DAPM_ENUM("DACL Sidetone", dacl_sidetone); + +static const struct snd_kcontrol_new dacr_mux = + SOC_DAPM_ENUM("DACR Sidetone", dacr_sidetone); + +static const struct snd_soc_dapm_widget wm8961_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("LINPUT"), +SND_SOC_DAPM_INPUT("RINPUT"), + +SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8961_CLOCKING2, 4, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Left Input", WM8961_PWR_MGMT_1, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Input", WM8961_PWR_MGMT_1, 4, 0, NULL, 0), + +SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", WM8961_PWR_MGMT_1, 3, 0), +SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", WM8961_PWR_MGMT_1, 2, 0), + +SND_SOC_DAPM_MICBIAS("MICBIAS", WM8961_PWR_MGMT_1, 1, 0), + +SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &dacl_mux), +SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &dacr_mux), + +SND_SOC_DAPM_DAC("DACL", "HiFi Playback", WM8961_PWR_MGMT_2, 8, 0), +SND_SOC_DAPM_DAC("DACR", "HiFi Playback", WM8961_PWR_MGMT_2, 7, 0), + +/* Handle as a mono path for DCS */ +SND_SOC_DAPM_PGA_E("Headphone Output", SND_SOC_NOPM, + 4, 0, NULL, 0, wm8961_hp_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_PGA_E("Speaker Output", SND_SOC_NOPM, + 4, 0, NULL, 0, wm8961_spk_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_OUTPUT("HP_L"), +SND_SOC_DAPM_OUTPUT("HP_R"), +SND_SOC_DAPM_OUTPUT("SPK_LN"), +SND_SOC_DAPM_OUTPUT("SPK_LP"), +SND_SOC_DAPM_OUTPUT("SPK_RN"), +SND_SOC_DAPM_OUTPUT("SPK_RP"), +}; + + +static const struct snd_soc_dapm_route audio_paths[] = { + { "DACL", NULL, "CLK_DSP" }, + { "DACL", NULL, "DACL Sidetone" }, + { "DACR", NULL, "CLK_DSP" }, + { "DACR", NULL, "DACR Sidetone" }, + + { "DACL Sidetone", "Left", "ADCL" }, + { "DACL Sidetone", "Right", "ADCR" }, + + { "DACR Sidetone", "Left", "ADCL" }, + { "DACR Sidetone", "Right", "ADCR" }, + + { "HP_L", NULL, "Headphone Output" }, + { "HP_R", NULL, "Headphone Output" }, + { "Headphone Output", NULL, "DACL" }, + { "Headphone Output", NULL, "DACR" }, + + { "SPK_LN", NULL, "Speaker Output" }, + { "SPK_LP", NULL, "Speaker Output" }, + { "SPK_RN", NULL, "Speaker Output" }, + { "SPK_RP", NULL, "Speaker Output" }, + + { "Speaker Output", NULL, "DACL" }, + { "Speaker Output", NULL, "DACR" }, + + { "ADCL", NULL, "Left Input" }, + { "ADCL", NULL, "CLK_DSP" }, + { "ADCR", NULL, "Right Input" }, + { "ADCR", NULL, "CLK_DSP" }, + + { "Left Input", NULL, "LINPUT" }, + { "Right Input", NULL, "RINPUT" }, + +}; + +/* Values for CLK_SYS_RATE */ +static struct { + int ratio; + u16 val; +} wm8961_clk_sys_ratio[] = { + { 64, 0 }, + { 128, 1 }, + { 192, 2 }, + { 256, 3 }, + { 384, 4 }, + { 512, 5 }, + { 768, 6 }, + { 1024, 7 }, + { 1408, 8 }, + { 1536, 9 }, +}; + +/* Values for SAMPLE_RATE */ +static struct { + int rate; + u16 val; +} wm8961_srate[] = { + { 48000, 0 }, + { 44100, 0 }, + { 32000, 1 }, + { 22050, 2 }, + { 24000, 2 }, + { 16000, 3 }, + { 11250, 4 }, + { 12000, 4 }, + { 8000, 5 }, +}; + +static int wm8961_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8961_priv *wm8961 = codec->private_data; + int i, best, target, fs; + u16 reg; + + fs = params_rate(params); + + if (!wm8961->sysclk) { + dev_err(codec->dev, "MCLK has not been specified\n"); + return -EINVAL; + } + + /* Find the closest sample rate for the filters */ + best = 0; + for (i = 0; i < ARRAY_SIZE(wm8961_srate); i++) { + if (abs(wm8961_srate[i].rate - fs) < + abs(wm8961_srate[best].rate - fs)) + best = i; + } + reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_3); + reg &= ~WM8961_SAMPLE_RATE_MASK; + reg |= wm8961_srate[best].val; + wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg); + dev_dbg(codec->dev, "Selected SRATE %dHz for %dHz\n", + wm8961_srate[best].rate, fs); + + /* Select a CLK_SYS/fs ratio equal to or higher than required */ + target = wm8961->sysclk / fs; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && target < 64) { + dev_err(codec->dev, + "SYSCLK must be at least 64*fs for DAC\n"); + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && target < 256) { + dev_err(codec->dev, + "SYSCLK must be at least 256*fs for ADC\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(wm8961_clk_sys_ratio); i++) { + if (wm8961_clk_sys_ratio[i].ratio >= target) + break; + } + if (i == ARRAY_SIZE(wm8961_clk_sys_ratio)) { + dev_err(codec->dev, "Unable to generate CLK_SYS_RATE\n"); + return -EINVAL; + } + dev_dbg(codec->dev, "Selected CLK_SYS_RATE of %d for %d/%d=%d\n", + wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs, + wm8961->sysclk / fs); + + reg = wm8961_read(codec, WM8961_CLOCKING_4); + reg &= ~WM8961_CLK_SYS_RATE_MASK; + reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT; + wm8961_write(codec, WM8961_CLOCKING_4, reg); + + reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0); + reg &= ~WM8961_WL_MASK; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + reg |= 1 << WM8961_WL_SHIFT; + break; + case SNDRV_PCM_FORMAT_S24_LE: + reg |= 2 << WM8961_WL_SHIFT; + break; + case SNDRV_PCM_FORMAT_S32_LE: + reg |= 3 << WM8961_WL_SHIFT; + break; + default: + return -EINVAL; + } + wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, reg); + + /* Sloping stop-band filter is recommended for <= 24kHz */ + reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2); + if (fs <= 24000) + reg |= WM8961_DACSLOPE; + else + reg &= WM8961_DACSLOPE; + wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); + + return 0; +} + +static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, + int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8961_priv *wm8961 = codec->private_data; + u16 reg = wm8961_read(codec, WM8961_CLOCKING1); + + if (freq > 33000000) { + dev_err(codec->dev, "MCLK must be <33MHz\n"); + return -EINVAL; + } + + if (freq > 16500000) { + dev_dbg(codec->dev, "Using MCLK/2 for %dHz MCLK\n", freq); + reg |= WM8961_MCLKDIV; + freq /= 2; + } else { + dev_dbg(codec->dev, "Using MCLK/1 for %dHz MCLK\n", freq); + reg &= WM8961_MCLKDIV; + } + + wm8961_write(codec, WM8961_CLOCKING1, reg); + + wm8961->sysclk = freq; + + return 0; +} + +static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + u16 aif = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0); + + aif &= ~(WM8961_BCLKINV | WM8961_LRP | + WM8961_MS | WM8961_FORMAT_MASK); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + aif |= WM8961_MS; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + break; + + case SND_SOC_DAIFMT_LEFT_J: + aif |= 1; + break; + + case SND_SOC_DAIFMT_I2S: + aif |= 2; + break; + + case SND_SOC_DAIFMT_DSP_B: + aif |= WM8961_LRP; + case SND_SOC_DAIFMT_DSP_A: + aif |= 3; + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + case SND_SOC_DAIFMT_IB_NF: + break; + default: + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + aif |= WM8961_LRP; + break; + case SND_SOC_DAIFMT_IB_NF: + aif |= WM8961_BCLKINV; + break; + case SND_SOC_DAIFMT_IB_IF: + aif |= WM8961_BCLKINV | WM8961_LRP; + break; + default: + return -EINVAL; + } + + return wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, aif); +} + +static int wm8961_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + struct snd_soc_codec *codec = dai->codec; + u16 reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_2); + + if (tristate) + reg |= WM8961_TRIS; + else + reg &= ~WM8961_TRIS; + + return wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg); +} + +static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u16 reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_1); + + if (mute) + reg |= WM8961_DACMU; + else + reg &= ~WM8961_DACMU; + + msleep(17); + + return wm8961_write(codec, WM8961_ADC_DAC_CONTROL_1, reg); +} + +static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) +{ + struct snd_soc_codec *codec = dai->codec; + u16 reg; + + switch (div_id) { + case WM8961_BCLK: + reg = wm8961_read(codec, WM8961_CLOCKING2); + reg &= ~WM8961_BCLKDIV_MASK; + reg |= div; + wm8961_write(codec, WM8961_CLOCKING2, reg); + break; + + case WM8961_LRCLK: + reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_2); + reg &= ~WM8961_LRCLK_RATE_MASK; + reg |= div; + wm8961_write(codec, WM8961_AUDIO_INTERFACE_2, reg); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int wm8961_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u16 reg; + + /* This is all slightly unusual since we have no bypass paths + * and the output amplifier structure means we can just slam + * the biases straight up rather than having to ramp them + * slowly. + */ + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + if (codec->bias_level == SND_SOC_BIAS_STANDBY) { + /* Enable bias generation */ + reg = wm8961_read(codec, WM8961_ANTI_POP); + reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN; + wm8961_write(codec, WM8961_ANTI_POP, reg); + + /* VMID=2*50k, VREF */ + reg = wm8961_read(codec, WM8961_PWR_MGMT_1); + reg &= ~WM8961_VMIDSEL_MASK; + reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF; + wm8961_write(codec, WM8961_PWR_MGMT_1, reg); + } + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_PREPARE) { + /* VREF off */ + reg = wm8961_read(codec, WM8961_PWR_MGMT_1); + reg &= ~WM8961_VREF; + wm8961_write(codec, WM8961_PWR_MGMT_1, reg); + + /* Bias generation off */ + reg = wm8961_read(codec, WM8961_ANTI_POP); + reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN); + wm8961_write(codec, WM8961_ANTI_POP, reg); + + /* VMID off */ + reg = wm8961_read(codec, WM8961_PWR_MGMT_1); + reg &= ~WM8961_VMIDSEL_MASK; + wm8961_write(codec, WM8961_PWR_MGMT_1, reg); + } + break; + + case SND_SOC_BIAS_OFF: + break; + } + + codec->bias_level = level; + + return 0; +} + + +#define WM8961_RATES SNDRV_PCM_RATE_8000_48000 + +#define WM8961_FORMATS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops wm8961_dai_ops = { + .hw_params = wm8961_hw_params, + .set_sysclk = wm8961_set_sysclk, + .set_fmt = wm8961_set_fmt, + .digital_mute = wm8961_digital_mute, + .set_tristate = wm8961_set_tristate, + .set_clkdiv = wm8961_set_clkdiv, +}; + +struct snd_soc_dai wm8961_dai = { + .name = "WM8961", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8961_RATES, + .formats = WM8961_FORMATS,}, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8961_RATES, + .formats = WM8961_FORMATS,}, + .ops = &wm8961_dai_ops, +}; +EXPORT_SYMBOL_GPL(wm8961_dai); + + +static struct snd_soc_codec *wm8961_codec; + +static int wm8961_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (wm8961_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = wm8961_codec; + codec = wm8961_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, wm8961_snd_controls, + ARRAY_SIZE(wm8961_snd_controls)); + snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets, + ARRAY_SIZE(wm8961_dapm_widgets)); + snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); + snd_soc_dapm_new_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +static int wm8961_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +#ifdef CONFIG_PM +static int wm8961_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int wm8961_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + u16 *reg_cache = codec->reg_cache; + int i; + + for (i = 0; i < codec->reg_cache_size; i++) { + if (i == WM8961_SOFTWARE_RESET) + continue; + + wm8961_write(codec, i, reg_cache[i]); + } + + wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} +#else +#define wm8961_suspend NULL +#define wm8961_resume NULL +#endif + +struct snd_soc_codec_device soc_codec_dev_wm8961 = { + .probe = wm8961_probe, + .remove = wm8961_remove, + .suspend = wm8961_suspend, + .resume = wm8961_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8961); + +static int wm8961_register(struct wm8961_priv *wm8961) +{ + struct snd_soc_codec *codec = &wm8961->codec; + int ret; + u16 reg; + + if (wm8961_codec) { + dev_err(codec->dev, "Another WM8961 is registered\n"); + ret = -EINVAL; + goto err; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = wm8961; + codec->name = "WM8961"; + codec->owner = THIS_MODULE; + codec->read = wm8961_read; + codec->write = wm8961_write; + codec->dai = &wm8961_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache); + codec->reg_cache = &wm8961->reg_cache; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8961_set_bias_level; + + memcpy(codec->reg_cache, wm8961_reg_defaults, + sizeof(wm8961_reg_defaults)); + + reg = wm8961_read_hw(codec, WM8961_SOFTWARE_RESET); + if (reg != 0x1801) { + dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg); + ret = -EINVAL; + goto err; + } + + reg = wm8961_read_hw(codec, WM8961_RIGHT_INPUT_VOLUME); + dev_info(codec->dev, "WM8961 family %d revision %c\n", + (reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT, + ((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT) + + 'A'); + + ret = wm8961_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + return ret; + } + + /* Enable class W */ + reg = wm8961_read(codec, WM8961_CHARGE_PUMP_B); + reg |= WM8961_CP_DYN_PWR_MASK; + wm8961_write(codec, WM8961_CHARGE_PUMP_B, reg); + + /* Latch volume update bits (right channel only, we always + * write both out) and default ZC on. */ + reg = wm8961_read(codec, WM8961_ROUT1_VOLUME); + wm8961_write(codec, WM8961_ROUT1_VOLUME, + reg | WM8961_LO1ZC | WM8961_OUT1VU); + wm8961_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC); + reg = wm8961_read(codec, WM8961_ROUT2_VOLUME); + wm8961_write(codec, WM8961_ROUT2_VOLUME, + reg | WM8961_SPKRZC | WM8961_SPKVU); + wm8961_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC); + + reg = wm8961_read(codec, WM8961_RIGHT_ADC_VOLUME); + wm8961_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU); + reg = wm8961_read(codec, WM8961_RIGHT_INPUT_VOLUME); + wm8961_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU); + + /* Use soft mute by default */ + reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2); + reg |= WM8961_DACSMM; + wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); + + /* Use automatic clocking mode by default; for now this is all + * we support. + */ + reg = wm8961_read(codec, WM8961_CLOCKING_3); + reg &= ~WM8961_MANUAL_MODE; + wm8961_write(codec, WM8961_CLOCKING_3, reg); + + wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + wm8961_dai.dev = codec->dev; + + wm8961_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; + } + + ret = snd_soc_register_dai(&wm8961_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } + + return 0; + +err: + kfree(wm8961); + return ret; +} + +static void wm8961_unregister(struct wm8961_priv *wm8961) +{ + wm8961_set_bias_level(&wm8961->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&wm8961_dai); + snd_soc_unregister_codec(&wm8961->codec); + kfree(wm8961); + wm8961_codec = NULL; +} + +static __devinit int wm8961_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8961_priv *wm8961; + struct snd_soc_codec *codec; + + wm8961 = kzalloc(sizeof(struct wm8961_priv), GFP_KERNEL); + if (wm8961 == NULL) + return -ENOMEM; + + codec = &wm8961->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + + i2c_set_clientdata(i2c, wm8961); + codec->control_data = i2c; + + codec->dev = &i2c->dev; + + return wm8961_register(wm8961); +} + +static __devexit int wm8961_i2c_remove(struct i2c_client *client) +{ + struct wm8961_priv *wm8961 = i2c_get_clientdata(client); + wm8961_unregister(wm8961); + return 0; +} + +static const struct i2c_device_id wm8961_i2c_id[] = { + { "wm8961", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id); + +static struct i2c_driver wm8961_i2c_driver = { + .driver = { + .name = "wm8961", + .owner = THIS_MODULE, + }, + .probe = wm8961_i2c_probe, + .remove = __devexit_p(wm8961_i2c_remove), + .id_table = wm8961_i2c_id, +}; + +static int __init wm8961_modinit(void) +{ + int ret; + + ret = i2c_add_driver(&wm8961_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register WM8961 I2C driver: %d\n", + ret); + } + + return ret; +} +module_init(wm8961_modinit); + +static void __exit wm8961_exit(void) +{ + i2c_del_driver(&wm8961_i2c_driver); +} +module_exit(wm8961_exit); + + +MODULE_DESCRIPTION("ASoC WM8961 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8961.h b/sound/soc/codecs/wm8961.h new file mode 100644 index 0000000..5513bfd --- /dev/null +++ b/sound/soc/codecs/wm8961.h @@ -0,0 +1,866 @@ +/* + * wm8961.h -- WM8961 Soc Audio driver + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef _WM8961_H +#define _WM8961_H + +#include + +extern struct snd_soc_codec_device soc_codec_dev_wm8961; +extern struct snd_soc_dai wm8961_dai; + +#define WM8961_BCLK 1 +#define WM8961_LRCLK 2 + +#define WM8961_BCLK_DIV_1 0 +#define WM8961_BCLK_DIV_1_5 1 +#define WM8961_BCLK_DIV_2 2 +#define WM8961_BCLK_DIV_3 3 +#define WM8961_BCLK_DIV_4 4 +#define WM8961_BCLK_DIV_5_5 5 +#define WM8961_BCLK_DIV_6 6 +#define WM8961_BCLK_DIV_8 7 +#define WM8961_BCLK_DIV_11 8 +#define WM8961_BCLK_DIV_12 9 +#define WM8961_BCLK_DIV_16 10 +#define WM8961_BCLK_DIV_24 11 +#define WM8961_BCLK_DIV_32 13 + + +/* + * Register values. + */ +#define WM8961_LEFT_INPUT_VOLUME 0x00 +#define WM8961_RIGHT_INPUT_VOLUME 0x01 +#define WM8961_LOUT1_VOLUME 0x02 +#define WM8961_ROUT1_VOLUME 0x03 +#define WM8961_CLOCKING1 0x04 +#define WM8961_ADC_DAC_CONTROL_1 0x05 +#define WM8961_ADC_DAC_CONTROL_2 0x06 +#define WM8961_AUDIO_INTERFACE_0 0x07 +#define WM8961_CLOCKING2 0x08 +#define WM8961_AUDIO_INTERFACE_1 0x09 +#define WM8961_LEFT_DAC_VOLUME 0x0A +#define WM8961_RIGHT_DAC_VOLUME 0x0B +#define WM8961_AUDIO_INTERFACE_2 0x0E +#define WM8961_SOFTWARE_RESET 0x0F +#define WM8961_ALC1 0x11 +#define WM8961_ALC2 0x12 +#define WM8961_ALC3 0x13 +#define WM8961_NOISE_GATE 0x14 +#define WM8961_LEFT_ADC_VOLUME 0x15 +#define WM8961_RIGHT_ADC_VOLUME 0x16 +#define WM8961_ADDITIONAL_CONTROL_1 0x17 +#define WM8961_ADDITIONAL_CONTROL_2 0x18 +#define WM8961_PWR_MGMT_1 0x19 +#define WM8961_PWR_MGMT_2 0x1A +#define WM8961_ADDITIONAL_CONTROL_3 0x1B +#define WM8961_ANTI_POP 0x1C +#define WM8961_CLOCKING_3 0x1E +#define WM8961_ADCL_SIGNAL_PATH 0x20 +#define WM8961_ADCR_SIGNAL_PATH 0x21 +#define WM8961_LOUT2_VOLUME 0x28 +#define WM8961_ROUT2_VOLUME 0x29 +#define WM8961_PWR_MGMT_3 0x2F +#define WM8961_ADDITIONAL_CONTROL_4 0x30 +#define WM8961_CLASS_D_CONTROL_1 0x31 +#define WM8961_CLASS_D_CONTROL_2 0x33 +#define WM8961_CLOCKING_4 0x38 +#define WM8961_DSP_SIDETONE_0 0x39 +#define WM8961_DSP_SIDETONE_1 0x3A +#define WM8961_DC_SERVO_0 0x3C +#define WM8961_DC_SERVO_1 0x3D +#define WM8961_DC_SERVO_3 0x3F +#define WM8961_DC_SERVO_5 0x41 +#define WM8961_ANALOGUE_PGA_BIAS 0x44 +#define WM8961_ANALOGUE_HP_0 0x45 +#define WM8961_ANALOGUE_HP_2 0x47 +#define WM8961_CHARGE_PUMP_1 0x48 +#define WM8961_CHARGE_PUMP_B 0x52 +#define WM8961_WRITE_SEQUENCER_1 0x57 +#define WM8961_WRITE_SEQUENCER_2 0x58 +#define WM8961_WRITE_SEQUENCER_3 0x59 +#define WM8961_WRITE_SEQUENCER_4 0x5A +#define WM8961_WRITE_SEQUENCER_5 0x5B +#define WM8961_WRITE_SEQUENCER_6 0x5C +#define WM8961_WRITE_SEQUENCER_7 0x5D +#define WM8961_GENERAL_TEST_1 0xFC + + +/* + * Field Definitions. + */ + +/* + * R0 (0x00) - Left Input volume + */ +#define WM8961_IPVU 0x0100 /* IPVU */ +#define WM8961_IPVU_MASK 0x0100 /* IPVU */ +#define WM8961_IPVU_SHIFT 8 /* IPVU */ +#define WM8961_IPVU_WIDTH 1 /* IPVU */ +#define WM8961_LINMUTE 0x0080 /* LINMUTE */ +#define WM8961_LINMUTE_MASK 0x0080 /* LINMUTE */ +#define WM8961_LINMUTE_SHIFT 7 /* LINMUTE */ +#define WM8961_LINMUTE_WIDTH 1 /* LINMUTE */ +#define WM8961_LIZC 0x0040 /* LIZC */ +#define WM8961_LIZC_MASK 0x0040 /* LIZC */ +#define WM8961_LIZC_SHIFT 6 /* LIZC */ +#define WM8961_LIZC_WIDTH 1 /* LIZC */ +#define WM8961_LINVOL_MASK 0x003F /* LINVOL - [5:0] */ +#define WM8961_LINVOL_SHIFT 0 /* LINVOL - [5:0] */ +#define WM8961_LINVOL_WIDTH 6 /* LINVOL - [5:0] */ + +/* + * R1 (0x01) - Right Input volume + */ +#define WM8961_DEVICE_ID_MASK 0xF000 /* DEVICE_ID - [15:12] */ +#define WM8961_DEVICE_ID_SHIFT 12 /* DEVICE_ID - [15:12] */ +#define WM8961_DEVICE_ID_WIDTH 4 /* DEVICE_ID - [15:12] */ +#define WM8961_CHIP_REV_MASK 0x0E00 /* CHIP_REV - [11:9] */ +#define WM8961_CHIP_REV_SHIFT 9 /* CHIP_REV - [11:9] */ +#define WM8961_CHIP_REV_WIDTH 3 /* CHIP_REV - [11:9] */ +#define WM8961_IPVU 0x0100 /* IPVU */ +#define WM8961_IPVU_MASK 0x0100 /* IPVU */ +#define WM8961_IPVU_SHIFT 8 /* IPVU */ +#define WM8961_IPVU_WIDTH 1 /* IPVU */ +#define WM8961_RINMUTE 0x0080 /* RINMUTE */ +#define WM8961_RINMUTE_MASK 0x0080 /* RINMUTE */ +#define WM8961_RINMUTE_SHIFT 7 /* RINMUTE */ +#define WM8961_RINMUTE_WIDTH 1 /* RINMUTE */ +#define WM8961_RIZC 0x0040 /* RIZC */ +#define WM8961_RIZC_MASK 0x0040 /* RIZC */ +#define WM8961_RIZC_SHIFT 6 /* RIZC */ +#define WM8961_RIZC_WIDTH 1 /* RIZC */ +#define WM8961_RINVOL_MASK 0x003F /* RINVOL - [5:0] */ +#define WM8961_RINVOL_SHIFT 0 /* RINVOL - [5:0] */ +#define WM8961_RINVOL_WIDTH 6 /* RINVOL - [5:0] */ + +/* + * R2 (0x02) - LOUT1 volume + */ +#define WM8961_OUT1VU 0x0100 /* OUT1VU */ +#define WM8961_OUT1VU_MASK 0x0100 /* OUT1VU */ +#define WM8961_OUT1VU_SHIFT 8 /* OUT1VU */ +#define WM8961_OUT1VU_WIDTH 1 /* OUT1VU */ +#define WM8961_LO1ZC 0x0080 /* LO1ZC */ +#define WM8961_LO1ZC_MASK 0x0080 /* LO1ZC */ +#define WM8961_LO1ZC_SHIFT 7 /* LO1ZC */ +#define WM8961_LO1ZC_WIDTH 1 /* LO1ZC */ +#define WM8961_LOUT1VOL_MASK 0x007F /* LOUT1VOL - [6:0] */ +#define WM8961_LOUT1VOL_SHIFT 0 /* LOUT1VOL - [6:0] */ +#define WM8961_LOUT1VOL_WIDTH 7 /* LOUT1VOL - [6:0] */ + +/* + * R3 (0x03) - ROUT1 volume + */ +#define WM8961_OUT1VU 0x0100 /* OUT1VU */ +#define WM8961_OUT1VU_MASK 0x0100 /* OUT1VU */ +#define WM8961_OUT1VU_SHIFT 8 /* OUT1VU */ +#define WM8961_OUT1VU_WIDTH 1 /* OUT1VU */ +#define WM8961_RO1ZC 0x0080 /* RO1ZC */ +#define WM8961_RO1ZC_MASK 0x0080 /* RO1ZC */ +#define WM8961_RO1ZC_SHIFT 7 /* RO1ZC */ +#define WM8961_RO1ZC_WIDTH 1 /* RO1ZC */ +#define WM8961_ROUT1VOL_MASK 0x007F /* ROUT1VOL - [6:0] */ +#define WM8961_ROUT1VOL_SHIFT 0 /* ROUT1VOL - [6:0] */ +#define WM8961_ROUT1VOL_WIDTH 7 /* ROUT1VOL - [6:0] */ + +/* + * R4 (0x04) - Clocking1 + */ +#define WM8961_ADCDIV_MASK 0x01C0 /* ADCDIV - [8:6] */ +#define WM8961_ADCDIV_SHIFT 6 /* ADCDIV - [8:6] */ +#define WM8961_ADCDIV_WIDTH 3 /* ADCDIV - [8:6] */ +#define WM8961_DACDIV_MASK 0x0038 /* DACDIV - [5:3] */ +#define WM8961_DACDIV_SHIFT 3 /* DACDIV - [5:3] */ +#define WM8961_DACDIV_WIDTH 3 /* DACDIV - [5:3] */ +#define WM8961_MCLKDIV 0x0004 /* MCLKDIV */ +#define WM8961_MCLKDIV_MASK 0x0004 /* MCLKDIV */ +#define WM8961_MCLKDIV_SHIFT 2 /* MCLKDIV */ +#define WM8961_MCLKDIV_WIDTH 1 /* MCLKDIV */ + +/* + * R5 (0x05) - ADC & DAC Control 1 + */ +#define WM8961_ADCPOL_MASK 0x0060 /* ADCPOL - [6:5] */ +#define WM8961_ADCPOL_SHIFT 5 /* ADCPOL - [6:5] */ +#define WM8961_ADCPOL_WIDTH 2 /* ADCPOL - [6:5] */ +#define WM8961_DACMU 0x0008 /* DACMU */ +#define WM8961_DACMU_MASK 0x0008 /* DACMU */ +#define WM8961_DACMU_SHIFT 3 /* DACMU */ +#define WM8961_DACMU_WIDTH 1 /* DACMU */ +#define WM8961_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */ +#define WM8961_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */ +#define WM8961_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */ +#define WM8961_ADCHPD 0x0001 /* ADCHPD */ +#define WM8961_ADCHPD_MASK 0x0001 /* ADCHPD */ +#define WM8961_ADCHPD_SHIFT 0 /* ADCHPD */ +#define WM8961_ADCHPD_WIDTH 1 /* ADCHPD */ + +/* + * R6 (0x06) - ADC & DAC Control 2 + */ +#define WM8961_ADC_HPF_CUT_MASK 0x0180 /* ADC_HPF_CUT - [8:7] */ +#define WM8961_ADC_HPF_CUT_SHIFT 7 /* ADC_HPF_CUT - [8:7] */ +#define WM8961_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [8:7] */ +#define WM8961_DACPOL_MASK 0x0060 /* DACPOL - [6:5] */ +#define WM8961_DACPOL_SHIFT 5 /* DACPOL - [6:5] */ +#define WM8961_DACPOL_WIDTH 2 /* DACPOL - [6:5] */ +#define WM8961_DACSMM 0x0008 /* DACSMM */ +#define WM8961_DACSMM_MASK 0x0008 /* DACSMM */ +#define WM8961_DACSMM_SHIFT 3 /* DACSMM */ +#define WM8961_DACSMM_WIDTH 1 /* DACSMM */ +#define WM8961_DACMR 0x0004 /* DACMR */ +#define WM8961_DACMR_MASK 0x0004 /* DACMR */ +#define WM8961_DACMR_SHIFT 2 /* DACMR */ +#define WM8961_DACMR_WIDTH 1 /* DACMR */ +#define WM8961_DACSLOPE 0x0002 /* DACSLOPE */ +#define WM8961_DACSLOPE_MASK 0x0002 /* DACSLOPE */ +#define WM8961_DACSLOPE_SHIFT 1 /* DACSLOPE */ +#define WM8961_DACSLOPE_WIDTH 1 /* DACSLOPE */ +#define WM8961_DAC_OSR128 0x0001 /* DAC_OSR128 */ +#define WM8961_DAC_OSR128_MASK 0x0001 /* DAC_OSR128 */ +#define WM8961_DAC_OSR128_SHIFT 0 /* DAC_OSR128 */ +#define WM8961_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */ + +/* + * R7 (0x07) - Audio Interface 0 + */ +#define WM8961_ALRSWAP 0x0100 /* ALRSWAP */ +#define WM8961_ALRSWAP_MASK 0x0100 /* ALRSWAP */ +#define WM8961_ALRSWAP_SHIFT 8 /* ALRSWAP */ +#define WM8961_ALRSWAP_WIDTH 1 /* ALRSWAP */ +#define WM8961_BCLKINV 0x0080 /* BCLKINV */ +#define WM8961_BCLKINV_MASK 0x0080 /* BCLKINV */ +#define WM8961_BCLKINV_SHIFT 7 /* BCLKINV */ +#define WM8961_BCLKINV_WIDTH 1 /* BCLKINV */ +#define WM8961_MS 0x0040 /* MS */ +#define WM8961_MS_MASK 0x0040 /* MS */ +#define WM8961_MS_SHIFT 6 /* MS */ +#define WM8961_MS_WIDTH 1 /* MS */ +#define WM8961_DLRSWAP 0x0020 /* DLRSWAP */ +#define WM8961_DLRSWAP_MASK 0x0020 /* DLRSWAP */ +#define WM8961_DLRSWAP_SHIFT 5 /* DLRSWAP */ +#define WM8961_DLRSWAP_WIDTH 1 /* DLRSWAP */ +#define WM8961_LRP 0x0010 /* LRP */ +#define WM8961_LRP_MASK 0x0010 /* LRP */ +#define WM8961_LRP_SHIFT 4 /* LRP */ +#define WM8961_LRP_WIDTH 1 /* LRP */ +#define WM8961_WL_MASK 0x000C /* WL - [3:2] */ +#define WM8961_WL_SHIFT 2 /* WL - [3:2] */ +#define WM8961_WL_WIDTH 2 /* WL - [3:2] */ +#define WM8961_FORMAT_MASK 0x0003 /* FORMAT - [1:0] */ +#define WM8961_FORMAT_SHIFT 0 /* FORMAT - [1:0] */ +#define WM8961_FORMAT_WIDTH 2 /* FORMAT - [1:0] */ + +/* + * R8 (0x08) - Clocking2 + */ +#define WM8961_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */ +#define WM8961_DCLKDIV_SHIFT 6 /* DCLKDIV - [8:6] */ +#define WM8961_DCLKDIV_WIDTH 3 /* DCLKDIV - [8:6] */ +#define WM8961_CLK_SYS_ENA 0x0020 /* CLK_SYS_ENA */ +#define WM8961_CLK_SYS_ENA_MASK 0x0020 /* CLK_SYS_ENA */ +#define WM8961_CLK_SYS_ENA_SHIFT 5 /* CLK_SYS_ENA */ +#define WM8961_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */ +#define WM8961_CLK_DSP_ENA 0x0010 /* CLK_DSP_ENA */ +#define WM8961_CLK_DSP_ENA_MASK 0x0010 /* CLK_DSP_ENA */ +#define WM8961_CLK_DSP_ENA_SHIFT 4 /* CLK_DSP_ENA */ +#define WM8961_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */ +#define WM8961_BCLKDIV_MASK 0x000F /* BCLKDIV - [3:0] */ +#define WM8961_BCLKDIV_SHIFT 0 /* BCLKDIV - [3:0] */ +#define WM8961_BCLKDIV_WIDTH 4 /* BCLKDIV - [3:0] */ + +/* + * R9 (0x09) - Audio Interface 1 + */ +#define WM8961_DACCOMP_MASK 0x0018 /* DACCOMP - [4:3] */ +#define WM8961_DACCOMP_SHIFT 3 /* DACCOMP - [4:3] */ +#define WM8961_DACCOMP_WIDTH 2 /* DACCOMP - [4:3] */ +#define WM8961_ADCCOMP_MASK 0x0006 /* ADCCOMP - [2:1] */ +#define WM8961_ADCCOMP_SHIFT 1 /* ADCCOMP - [2:1] */ +#define WM8961_ADCCOMP_WIDTH 2 /* ADCCOMP - [2:1] */ +#define WM8961_LOOPBACK 0x0001 /* LOOPBACK */ +#define WM8961_LOOPBACK_MASK 0x0001 /* LOOPBACK */ +#define WM8961_LOOPBACK_SHIFT 0 /* LOOPBACK */ +#define WM8961_LOOPBACK_WIDTH 1 /* LOOPBACK */ + +/* + * R10 (0x0A) - Left DAC volume + */ +#define WM8961_DACVU 0x0100 /* DACVU */ +#define WM8961_DACVU_MASK 0x0100 /* DACVU */ +#define WM8961_DACVU_SHIFT 8 /* DACVU */ +#define WM8961_DACVU_WIDTH 1 /* DACVU */ +#define WM8961_LDACVOL_MASK 0x00FF /* LDACVOL - [7:0] */ +#define WM8961_LDACVOL_SHIFT 0 /* LDACVOL - [7:0] */ +#define WM8961_LDACVOL_WIDTH 8 /* LDACVOL - [7:0] */ + +/* + * R11 (0x0B) - Right DAC volume + */ +#define WM8961_DACVU 0x0100 /* DACVU */ +#define WM8961_DACVU_MASK 0x0100 /* DACVU */ +#define WM8961_DACVU_SHIFT 8 /* DACVU */ +#define WM8961_DACVU_WIDTH 1 /* DACVU */ +#define WM8961_RDACVOL_MASK 0x00FF /* RDACVOL - [7:0] */ +#define WM8961_RDACVOL_SHIFT 0 /* RDACVOL - [7:0] */ +#define WM8961_RDACVOL_WIDTH 8 /* RDACVOL - [7:0] */ + +/* + * R14 (0x0E) - Audio Interface 2 + */ +#define WM8961_LRCLK_RATE_MASK 0x01FF /* LRCLK_RATE - [8:0] */ +#define WM8961_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [8:0] */ +#define WM8961_LRCLK_RATE_WIDTH 9 /* LRCLK_RATE - [8:0] */ + +/* + * R15 (0x0F) - Software Reset + */ +#define WM8961_SW_RST_DEV_ID1_MASK 0xFFFF /* SW_RST_DEV_ID1 - [15:0] */ +#define WM8961_SW_RST_DEV_ID1_SHIFT 0 /* SW_RST_DEV_ID1 - [15:0] */ +#define WM8961_SW_RST_DEV_ID1_WIDTH 16 /* SW_RST_DEV_ID1 - [15:0] */ + +/* + * R17 (0x11) - ALC1 + */ +#define WM8961_ALCSEL_MASK 0x0180 /* ALCSEL - [8:7] */ +#define WM8961_ALCSEL_SHIFT 7 /* ALCSEL - [8:7] */ +#define WM8961_ALCSEL_WIDTH 2 /* ALCSEL - [8:7] */ +#define WM8961_MAXGAIN_MASK 0x0070 /* MAXGAIN - [6:4] */ +#define WM8961_MAXGAIN_SHIFT 4 /* MAXGAIN - [6:4] */ +#define WM8961_MAXGAIN_WIDTH 3 /* MAXGAIN - [6:4] */ +#define WM8961_ALCL_MASK 0x000F /* ALCL - [3:0] */ +#define WM8961_ALCL_SHIFT 0 /* ALCL - [3:0] */ +#define WM8961_ALCL_WIDTH 4 /* ALCL - [3:0] */ + +/* + * R18 (0x12) - ALC2 + */ +#define WM8961_ALCZC 0x0080 /* ALCZC */ +#define WM8961_ALCZC_MASK 0x0080 /* ALCZC */ +#define WM8961_ALCZC_SHIFT 7 /* ALCZC */ +#define WM8961_ALCZC_WIDTH 1 /* ALCZC */ +#define WM8961_MINGAIN_MASK 0x0070 /* MINGAIN - [6:4] */ +#define WM8961_MINGAIN_SHIFT 4 /* MINGAIN - [6:4] */ +#define WM8961_MINGAIN_WIDTH 3 /* MINGAIN - [6:4] */ +#define WM8961_HLD_MASK 0x000F /* HLD - [3:0] */ +#define WM8961_HLD_SHIFT 0 /* HLD - [3:0] */ +#define WM8961_HLD_WIDTH 4 /* HLD - [3:0] */ + +/* + * R19 (0x13) - ALC3 + */ +#define WM8961_ALCMODE 0x0100 /* ALCMODE */ +#define WM8961_ALCMODE_MASK 0x0100 /* ALCMODE */ +#define WM8961_ALCMODE_SHIFT 8 /* ALCMODE */ +#define WM8961_ALCMODE_WIDTH 1 /* ALCMODE */ +#define WM8961_DCY_MASK 0x00F0 /* DCY - [7:4] */ +#define WM8961_DCY_SHIFT 4 /* DCY - [7:4] */ +#define WM8961_DCY_WIDTH 4 /* DCY - [7:4] */ +#define WM8961_ATK_MASK 0x000F /* ATK - [3:0] */ +#define WM8961_ATK_SHIFT 0 /* ATK - [3:0] */ +#define WM8961_ATK_WIDTH 4 /* ATK - [3:0] */ + +/* + * R20 (0x14) - Noise Gate + */ +#define WM8961_NGTH_MASK 0x00F8 /* NGTH - [7:3] */ +#define WM8961_NGTH_SHIFT 3 /* NGTH - [7:3] */ +#define WM8961_NGTH_WIDTH 5 /* NGTH - [7:3] */ +#define WM8961_NGG 0x0002 /* NGG */ +#define WM8961_NGG_MASK 0x0002 /* NGG */ +#define WM8961_NGG_SHIFT 1 /* NGG */ +#define WM8961_NGG_WIDTH 1 /* NGG */ +#define WM8961_NGAT 0x0001 /* NGAT */ +#define WM8961_NGAT_MASK 0x0001 /* NGAT */ +#define WM8961_NGAT_SHIFT 0 /* NGAT */ +#define WM8961_NGAT_WIDTH 1 /* NGAT */ + +/* + * R21 (0x15) - Left ADC volume + */ +#define WM8961_ADCVU 0x0100 /* ADCVU */ +#define WM8961_ADCVU_MASK 0x0100 /* ADCVU */ +#define WM8961_ADCVU_SHIFT 8 /* ADCVU */ +#define WM8961_ADCVU_WIDTH 1 /* ADCVU */ +#define WM8961_LADCVOL_MASK 0x00FF /* LADCVOL - [7:0] */ +#define WM8961_LADCVOL_SHIFT 0 /* LADCVOL - [7:0] */ +#define WM8961_LADCVOL_WIDTH 8 /* LADCVOL - [7:0] */ + +/* + * R22 (0x16) - Right ADC volume + */ +#define WM8961_ADCVU 0x0100 /* ADCVU */ +#define WM8961_ADCVU_MASK 0x0100 /* ADCVU */ +#define WM8961_ADCVU_SHIFT 8 /* ADCVU */ +#define WM8961_ADCVU_WIDTH 1 /* ADCVU */ +#define WM8961_RADCVOL_MASK 0x00FF /* RADCVOL - [7:0] */ +#define WM8961_RADCVOL_SHIFT 0 /* RADCVOL - [7:0] */ +#define WM8961_RADCVOL_WIDTH 8 /* RADCVOL - [7:0] */ + +/* + * R23 (0x17) - Additional control(1) + */ +#define WM8961_TSDEN 0x0100 /* TSDEN */ +#define WM8961_TSDEN_MASK 0x0100 /* TSDEN */ +#define WM8961_TSDEN_SHIFT 8 /* TSDEN */ +#define WM8961_TSDEN_WIDTH 1 /* TSDEN */ +#define WM8961_DMONOMIX 0x0010 /* DMONOMIX */ +#define WM8961_DMONOMIX_MASK 0x0010 /* DMONOMIX */ +#define WM8961_DMONOMIX_SHIFT 4 /* DMONOMIX */ +#define WM8961_DMONOMIX_WIDTH 1 /* DMONOMIX */ +#define WM8961_TOEN 0x0001 /* TOEN */ +#define WM8961_TOEN_MASK 0x0001 /* TOEN */ +#define WM8961_TOEN_SHIFT 0 /* TOEN */ +#define WM8961_TOEN_WIDTH 1 /* TOEN */ + +/* + * R24 (0x18) - Additional control(2) + */ +#define WM8961_TRIS 0x0008 /* TRIS */ +#define WM8961_TRIS_MASK 0x0008 /* TRIS */ +#define WM8961_TRIS_SHIFT 3 /* TRIS */ +#define WM8961_TRIS_WIDTH 1 /* TRIS */ + +/* + * R25 (0x19) - Pwr Mgmt (1) + */ +#define WM8961_VMIDSEL_MASK 0x0180 /* VMIDSEL - [8:7] */ +#define WM8961_VMIDSEL_SHIFT 7 /* VMIDSEL - [8:7] */ +#define WM8961_VMIDSEL_WIDTH 2 /* VMIDSEL - [8:7] */ +#define WM8961_VREF 0x0040 /* VREF */ +#define WM8961_VREF_MASK 0x0040 /* VREF */ +#define WM8961_VREF_SHIFT 6 /* VREF */ +#define WM8961_VREF_WIDTH 1 /* VREF */ +#define WM8961_AINL 0x0020 /* AINL */ +#define WM8961_AINL_MASK 0x0020 /* AINL */ +#define WM8961_AINL_SHIFT 5 /* AINL */ +#define WM8961_AINL_WIDTH 1 /* AINL */ +#define WM8961_AINR 0x0010 /* AINR */ +#define WM8961_AINR_MASK 0x0010 /* AINR */ +#define WM8961_AINR_SHIFT 4 /* AINR */ +#define WM8961_AINR_WIDTH 1 /* AINR */ +#define WM8961_ADCL 0x0008 /* ADCL */ +#define WM8961_ADCL_MASK 0x0008 /* ADCL */ +#define WM8961_ADCL_SHIFT 3 /* ADCL */ +#define WM8961_ADCL_WIDTH 1 /* ADCL */ +#define WM8961_ADCR 0x0004 /* ADCR */ +#define WM8961_ADCR_MASK 0x0004 /* ADCR */ +#define WM8961_ADCR_SHIFT 2 /* ADCR */ +#define WM8961_ADCR_WIDTH 1 /* ADCR */ +#define WM8961_MICB 0x0002 /* MICB */ +#define WM8961_MICB_MASK 0x0002 /* MICB */ +#define WM8961_MICB_SHIFT 1 /* MICB */ +#define WM8961_MICB_WIDTH 1 /* MICB */ + +/* + * R26 (0x1A) - Pwr Mgmt (2) + */ +#define WM8961_DACL 0x0100 /* DACL */ +#define WM8961_DACL_MASK 0x0100 /* DACL */ +#define WM8961_DACL_SHIFT 8 /* DACL */ +#define WM8961_DACL_WIDTH 1 /* DACL */ +#define WM8961_DACR 0x0080 /* DACR */ +#define WM8961_DACR_MASK 0x0080 /* DACR */ +#define WM8961_DACR_SHIFT 7 /* DACR */ +#define WM8961_DACR_WIDTH 1 /* DACR */ +#define WM8961_LOUT1_PGA 0x0040 /* LOUT1_PGA */ +#define WM8961_LOUT1_PGA_MASK 0x0040 /* LOUT1_PGA */ +#define WM8961_LOUT1_PGA_SHIFT 6 /* LOUT1_PGA */ +#define WM8961_LOUT1_PGA_WIDTH 1 /* LOUT1_PGA */ +#define WM8961_ROUT1_PGA 0x0020 /* ROUT1_PGA */ +#define WM8961_ROUT1_PGA_MASK 0x0020 /* ROUT1_PGA */ +#define WM8961_ROUT1_PGA_SHIFT 5 /* ROUT1_PGA */ +#define WM8961_ROUT1_PGA_WIDTH 1 /* ROUT1_PGA */ +#define WM8961_SPKL_PGA 0x0010 /* SPKL_PGA */ +#define WM8961_SPKL_PGA_MASK 0x0010 /* SPKL_PGA */ +#define WM8961_SPKL_PGA_SHIFT 4 /* SPKL_PGA */ +#define WM8961_SPKL_PGA_WIDTH 1 /* SPKL_PGA */ +#define WM8961_SPKR_PGA 0x0008 /* SPKR_PGA */ +#define WM8961_SPKR_PGA_MASK 0x0008 /* SPKR_PGA */ +#define WM8961_SPKR_PGA_SHIFT 3 /* SPKR_PGA */ +#define WM8961_SPKR_PGA_WIDTH 1 /* SPKR_PGA */ + +/* + * R27 (0x1B) - Additional Control (3) + */ +#define WM8961_SAMPLE_RATE_MASK 0x0007 /* SAMPLE_RATE - [2:0] */ +#define WM8961_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [2:0] */ +#define WM8961_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [2:0] */ + +/* + * R28 (0x1C) - Anti-pop + */ +#define WM8961_BUFDCOPEN 0x0010 /* BUFDCOPEN */ +#define WM8961_BUFDCOPEN_MASK 0x0010 /* BUFDCOPEN */ +#define WM8961_BUFDCOPEN_SHIFT 4 /* BUFDCOPEN */ +#define WM8961_BUFDCOPEN_WIDTH 1 /* BUFDCOPEN */ +#define WM8961_BUFIOEN 0x0008 /* BUFIOEN */ +#define WM8961_BUFIOEN_MASK 0x0008 /* BUFIOEN */ +#define WM8961_BUFIOEN_SHIFT 3 /* BUFIOEN */ +#define WM8961_BUFIOEN_WIDTH 1 /* BUFIOEN */ +#define WM8961_SOFT_ST 0x0004 /* SOFT_ST */ +#define WM8961_SOFT_ST_MASK 0x0004 /* SOFT_ST */ +#define WM8961_SOFT_ST_SHIFT 2 /* SOFT_ST */ +#define WM8961_SOFT_ST_WIDTH 1 /* SOFT_ST */ + +/* + * R30 (0x1E) - Clocking 3 + */ +#define WM8961_CLK_TO_DIV_MASK 0x0180 /* CLK_TO_DIV - [8:7] */ +#define WM8961_CLK_TO_DIV_SHIFT 7 /* CLK_TO_DIV - [8:7] */ +#define WM8961_CLK_TO_DIV_WIDTH 2 /* CLK_TO_DIV - [8:7] */ +#define WM8961_CLK_256K_DIV_MASK 0x007E /* CLK_256K_DIV - [6:1] */ +#define WM8961_CLK_256K_DIV_SHIFT 1 /* CLK_256K_DIV - [6:1] */ +#define WM8961_CLK_256K_DIV_WIDTH 6 /* CLK_256K_DIV - [6:1] */ +#define WM8961_MANUAL_MODE 0x0001 /* MANUAL_MODE */ +#define WM8961_MANUAL_MODE_MASK 0x0001 /* MANUAL_MODE */ +#define WM8961_MANUAL_MODE_SHIFT 0 /* MANUAL_MODE */ +#define WM8961_MANUAL_MODE_WIDTH 1 /* MANUAL_MODE */ + +/* + * R32 (0x20) - ADCL signal path + */ +#define WM8961_LMICBOOST_MASK 0x0030 /* LMICBOOST - [5:4] */ +#define WM8961_LMICBOOST_SHIFT 4 /* LMICBOOST - [5:4] */ +#define WM8961_LMICBOOST_WIDTH 2 /* LMICBOOST - [5:4] */ + +/* + * R33 (0x21) - ADCR signal path + */ +#define WM8961_RMICBOOST_MASK 0x0030 /* RMICBOOST - [5:4] */ +#define WM8961_RMICBOOST_SHIFT 4 /* RMICBOOST - [5:4] */ +#define WM8961_RMICBOOST_WIDTH 2 /* RMICBOOST - [5:4] */ + +/* + * R40 (0x28) - LOUT2 volume + */ +#define WM8961_SPKVU 0x0100 /* SPKVU */ +#define WM8961_SPKVU_MASK 0x0100 /* SPKVU */ +#define WM8961_SPKVU_SHIFT 8 /* SPKVU */ +#define WM8961_SPKVU_WIDTH 1 /* SPKVU */ +#define WM8961_SPKLZC 0x0080 /* SPKLZC */ +#define WM8961_SPKLZC_MASK 0x0080 /* SPKLZC */ +#define WM8961_SPKLZC_SHIFT 7 /* SPKLZC */ +#define WM8961_SPKLZC_WIDTH 1 /* SPKLZC */ +#define WM8961_SPKLVOL_MASK 0x007F /* SPKLVOL - [6:0] */ +#define WM8961_SPKLVOL_SHIFT 0 /* SPKLVOL - [6:0] */ +#define WM8961_SPKLVOL_WIDTH 7 /* SPKLVOL - [6:0] */ + +/* + * R41 (0x29) - ROUT2 volume + */ +#define WM8961_SPKVU 0x0100 /* SPKVU */ +#define WM8961_SPKVU_MASK 0x0100 /* SPKVU */ +#define WM8961_SPKVU_SHIFT 8 /* SPKVU */ +#define WM8961_SPKVU_WIDTH 1 /* SPKVU */ +#define WM8961_SPKRZC 0x0080 /* SPKRZC */ +#define WM8961_SPKRZC_MASK 0x0080 /* SPKRZC */ +#define WM8961_SPKRZC_SHIFT 7 /* SPKRZC */ +#define WM8961_SPKRZC_WIDTH 1 /* SPKRZC */ +#define WM8961_SPKRVOL_MASK 0x007F /* SPKRVOL - [6:0] */ +#define WM8961_SPKRVOL_SHIFT 0 /* SPKRVOL - [6:0] */ +#define WM8961_SPKRVOL_WIDTH 7 /* SPKRVOL - [6:0] */ + +/* + * R47 (0x2F) - Pwr Mgmt (3) + */ +#define WM8961_TEMP_SHUT 0x0002 /* TEMP_SHUT */ +#define WM8961_TEMP_SHUT_MASK 0x0002 /* TEMP_SHUT */ +#define WM8961_TEMP_SHUT_SHIFT 1 /* TEMP_SHUT */ +#define WM8961_TEMP_SHUT_WIDTH 1 /* TEMP_SHUT */ +#define WM8961_TEMP_WARN 0x0001 /* TEMP_WARN */ +#define WM8961_TEMP_WARN_MASK 0x0001 /* TEMP_WARN */ +#define WM8961_TEMP_WARN_SHIFT 0 /* TEMP_WARN */ +#define WM8961_TEMP_WARN_WIDTH 1 /* TEMP_WARN */ + +/* + * R48 (0x30) - Additional Control (4) + */ +#define WM8961_TSENSEN 0x0002 /* TSENSEN */ +#define WM8961_TSENSEN_MASK 0x0002 /* TSENSEN */ +#define WM8961_TSENSEN_SHIFT 1 /* TSENSEN */ +#define WM8961_TSENSEN_WIDTH 1 /* TSENSEN */ +#define WM8961_MBSEL 0x0001 /* MBSEL */ +#define WM8961_MBSEL_MASK 0x0001 /* MBSEL */ +#define WM8961_MBSEL_SHIFT 0 /* MBSEL */ +#define WM8961_MBSEL_WIDTH 1 /* MBSEL */ + +/* + * R49 (0x31) - Class D Control 1 + */ +#define WM8961_SPKR_ENA 0x0080 /* SPKR_ENA */ +#define WM8961_SPKR_ENA_MASK 0x0080 /* SPKR_ENA */ +#define WM8961_SPKR_ENA_SHIFT 7 /* SPKR_ENA */ +#define WM8961_SPKR_ENA_WIDTH 1 /* SPKR_ENA */ +#define WM8961_SPKL_ENA 0x0040 /* SPKL_ENA */ +#define WM8961_SPKL_ENA_MASK 0x0040 /* SPKL_ENA */ +#define WM8961_SPKL_ENA_SHIFT 6 /* SPKL_ENA */ +#define WM8961_SPKL_ENA_WIDTH 1 /* SPKL_ENA */ + +/* + * R51 (0x33) - Class D Control 2 + */ +#define WM8961_CLASSD_ACGAIN_MASK 0x0007 /* CLASSD_ACGAIN - [2:0] */ +#define WM8961_CLASSD_ACGAIN_SHIFT 0 /* CLASSD_ACGAIN - [2:0] */ +#define WM8961_CLASSD_ACGAIN_WIDTH 3 /* CLASSD_ACGAIN - [2:0] */ + +/* + * R56 (0x38) - Clocking 4 + */ +#define WM8961_CLK_DCS_DIV_MASK 0x01E0 /* CLK_DCS_DIV - [8:5] */ +#define WM8961_CLK_DCS_DIV_SHIFT 5 /* CLK_DCS_DIV - [8:5] */ +#define WM8961_CLK_DCS_DIV_WIDTH 4 /* CLK_DCS_DIV - [8:5] */ +#define WM8961_CLK_SYS_RATE_MASK 0x001E /* CLK_SYS_RATE - [4:1] */ +#define WM8961_CLK_SYS_RATE_SHIFT 1 /* CLK_SYS_RATE - [4:1] */ +#define WM8961_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [4:1] */ + +/* + * R57 (0x39) - DSP Sidetone 0 + */ +#define WM8961_ADCR_DAC_SVOL_MASK 0x00F0 /* ADCR_DAC_SVOL - [7:4] */ +#define WM8961_ADCR_DAC_SVOL_SHIFT 4 /* ADCR_DAC_SVOL - [7:4] */ +#define WM8961_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [7:4] */ +#define WM8961_ADC_TO_DACR_MASK 0x000C /* ADC_TO_DACR - [3:2] */ +#define WM8961_ADC_TO_DACR_SHIFT 2 /* ADC_TO_DACR - [3:2] */ +#define WM8961_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [3:2] */ + +/* + * R58 (0x3A) - DSP Sidetone 1 + */ +#define WM8961_ADCL_DAC_SVOL_MASK 0x00F0 /* ADCL_DAC_SVOL - [7:4] */ +#define WM8961_ADCL_DAC_SVOL_SHIFT 4 /* ADCL_DAC_SVOL - [7:4] */ +#define WM8961_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [7:4] */ +#define WM8961_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */ +#define WM8961_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */ +#define WM8961_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */ + +/* + * R60 (0x3C) - DC Servo 0 + */ +#define WM8961_DCS_ENA_CHAN_INL 0x0080 /* DCS_ENA_CHAN_INL */ +#define WM8961_DCS_ENA_CHAN_INL_MASK 0x0080 /* DCS_ENA_CHAN_INL */ +#define WM8961_DCS_ENA_CHAN_INL_SHIFT 7 /* DCS_ENA_CHAN_INL */ +#define WM8961_DCS_ENA_CHAN_INL_WIDTH 1 /* DCS_ENA_CHAN_INL */ +#define WM8961_DCS_TRIG_STARTUP_INL 0x0040 /* DCS_TRIG_STARTUP_INL */ +#define WM8961_DCS_TRIG_STARTUP_INL_MASK 0x0040 /* DCS_TRIG_STARTUP_INL */ +#define WM8961_DCS_TRIG_STARTUP_INL_SHIFT 6 /* DCS_TRIG_STARTUP_INL */ +#define WM8961_DCS_TRIG_STARTUP_INL_WIDTH 1 /* DCS_TRIG_STARTUP_INL */ +#define WM8961_DCS_TRIG_SERIES_INL 0x0010 /* DCS_TRIG_SERIES_INL */ +#define WM8961_DCS_TRIG_SERIES_INL_MASK 0x0010 /* DCS_TRIG_SERIES_INL */ +#define WM8961_DCS_TRIG_SERIES_INL_SHIFT 4 /* DCS_TRIG_SERIES_INL */ +#define WM8961_DCS_TRIG_SERIES_INL_WIDTH 1 /* DCS_TRIG_SERIES_INL */ +#define WM8961_DCS_ENA_CHAN_INR 0x0008 /* DCS_ENA_CHAN_INR */ +#define WM8961_DCS_ENA_CHAN_INR_MASK 0x0008 /* DCS_ENA_CHAN_INR */ +#define WM8961_DCS_ENA_CHAN_INR_SHIFT 3 /* DCS_ENA_CHAN_INR */ +#define WM8961_DCS_ENA_CHAN_INR_WIDTH 1 /* DCS_ENA_CHAN_INR */ +#define WM8961_DCS_TRIG_STARTUP_INR 0x0004 /* DCS_TRIG_STARTUP_INR */ +#define WM8961_DCS_TRIG_STARTUP_INR_MASK 0x0004 /* DCS_TRIG_STARTUP_INR */ +#define WM8961_DCS_TRIG_STARTUP_INR_SHIFT 2 /* DCS_TRIG_STARTUP_INR */ +#define WM8961_DCS_TRIG_STARTUP_INR_WIDTH 1 /* DCS_TRIG_STARTUP_INR */ +#define WM8961_DCS_TRIG_SERIES_INR 0x0001 /* DCS_TRIG_SERIES_INR */ +#define WM8961_DCS_TRIG_SERIES_INR_MASK 0x0001 /* DCS_TRIG_SERIES_INR */ +#define WM8961_DCS_TRIG_SERIES_INR_SHIFT 0 /* DCS_TRIG_SERIES_INR */ +#define WM8961_DCS_TRIG_SERIES_INR_WIDTH 1 /* DCS_TRIG_SERIES_INR */ + +/* + * R61 (0x3D) - DC Servo 1 + */ +#define WM8961_DCS_ENA_CHAN_HPL 0x0080 /* DCS_ENA_CHAN_HPL */ +#define WM8961_DCS_ENA_CHAN_HPL_MASK 0x0080 /* DCS_ENA_CHAN_HPL */ +#define WM8961_DCS_ENA_CHAN_HPL_SHIFT 7 /* DCS_ENA_CHAN_HPL */ +#define WM8961_DCS_ENA_CHAN_HPL_WIDTH 1 /* DCS_ENA_CHAN_HPL */ +#define WM8961_DCS_TRIG_STARTUP_HPL 0x0040 /* DCS_TRIG_STARTUP_HPL */ +#define WM8961_DCS_TRIG_STARTUP_HPL_MASK 0x0040 /* DCS_TRIG_STARTUP_HPL */ +#define WM8961_DCS_TRIG_STARTUP_HPL_SHIFT 6 /* DCS_TRIG_STARTUP_HPL */ +#define WM8961_DCS_TRIG_STARTUP_HPL_WIDTH 1 /* DCS_TRIG_STARTUP_HPL */ +#define WM8961_DCS_TRIG_SERIES_HPL 0x0010 /* DCS_TRIG_SERIES_HPL */ +#define WM8961_DCS_TRIG_SERIES_HPL_MASK 0x0010 /* DCS_TRIG_SERIES_HPL */ +#define WM8961_DCS_TRIG_SERIES_HPL_SHIFT 4 /* DCS_TRIG_SERIES_HPL */ +#define WM8961_DCS_TRIG_SERIES_HPL_WIDTH 1 /* DCS_TRIG_SERIES_HPL */ +#define WM8961_DCS_ENA_CHAN_HPR 0x0008 /* DCS_ENA_CHAN_HPR */ +#define WM8961_DCS_ENA_CHAN_HPR_MASK 0x0008 /* DCS_ENA_CHAN_HPR */ +#define WM8961_DCS_ENA_CHAN_HPR_SHIFT 3 /* DCS_ENA_CHAN_HPR */ +#define WM8961_DCS_ENA_CHAN_HPR_WIDTH 1 /* DCS_ENA_CHAN_HPR */ +#define WM8961_DCS_TRIG_STARTUP_HPR 0x0004 /* DCS_TRIG_STARTUP_HPR */ +#define WM8961_DCS_TRIG_STARTUP_HPR_MASK 0x0004 /* DCS_TRIG_STARTUP_HPR */ +#define WM8961_DCS_TRIG_STARTUP_HPR_SHIFT 2 /* DCS_TRIG_STARTUP_HPR */ +#define WM8961_DCS_TRIG_STARTUP_HPR_WIDTH 1 /* DCS_TRIG_STARTUP_HPR */ +#define WM8961_DCS_TRIG_SERIES_HPR 0x0001 /* DCS_TRIG_SERIES_HPR */ +#define WM8961_DCS_TRIG_SERIES_HPR_MASK 0x0001 /* DCS_TRIG_SERIES_HPR */ +#define WM8961_DCS_TRIG_SERIES_HPR_SHIFT 0 /* DCS_TRIG_SERIES_HPR */ +#define WM8961_DCS_TRIG_SERIES_HPR_WIDTH 1 /* DCS_TRIG_SERIES_HPR */ + +/* + * R63 (0x3F) - DC Servo 3 + */ +#define WM8961_DCS_FILT_BW_SERIES_MASK 0x0030 /* DCS_FILT_BW_SERIES - [5:4] */ +#define WM8961_DCS_FILT_BW_SERIES_SHIFT 4 /* DCS_FILT_BW_SERIES - [5:4] */ +#define WM8961_DCS_FILT_BW_SERIES_WIDTH 2 /* DCS_FILT_BW_SERIES - [5:4] */ + +/* + * R65 (0x41) - DC Servo 5 + */ +#define WM8961_DCS_SERIES_NO_HP_MASK 0x007F /* DCS_SERIES_NO_HP - [6:0] */ +#define WM8961_DCS_SERIES_NO_HP_SHIFT 0 /* DCS_SERIES_NO_HP - [6:0] */ +#define WM8961_DCS_SERIES_NO_HP_WIDTH 7 /* DCS_SERIES_NO_HP - [6:0] */ + +/* + * R68 (0x44) - Analogue PGA Bias + */ +#define WM8961_HP_PGAS_BIAS_MASK 0x0007 /* HP_PGAS_BIAS - [2:0] */ +#define WM8961_HP_PGAS_BIAS_SHIFT 0 /* HP_PGAS_BIAS - [2:0] */ +#define WM8961_HP_PGAS_BIAS_WIDTH 3 /* HP_PGAS_BIAS - [2:0] */ + +/* + * R69 (0x45) - Analogue HP 0 + */ +#define WM8961_HPL_RMV_SHORT 0x0080 /* HPL_RMV_SHORT */ +#define WM8961_HPL_RMV_SHORT_MASK 0x0080 /* HPL_RMV_SHORT */ +#define WM8961_HPL_RMV_SHORT_SHIFT 7 /* HPL_RMV_SHORT */ +#define WM8961_HPL_RMV_SHORT_WIDTH 1 /* HPL_RMV_SHORT */ +#define WM8961_HPL_ENA_OUTP 0x0040 /* HPL_ENA_OUTP */ +#define WM8961_HPL_ENA_OUTP_MASK 0x0040 /* HPL_ENA_OUTP */ +#define WM8961_HPL_ENA_OUTP_SHIFT 6 /* HPL_ENA_OUTP */ +#define WM8961_HPL_ENA_OUTP_WIDTH 1 /* HPL_ENA_OUTP */ +#define WM8961_HPL_ENA_DLY 0x0020 /* HPL_ENA_DLY */ +#define WM8961_HPL_ENA_DLY_MASK 0x0020 /* HPL_ENA_DLY */ +#define WM8961_HPL_ENA_DLY_SHIFT 5 /* HPL_ENA_DLY */ +#define WM8961_HPL_ENA_DLY_WIDTH 1 /* HPL_ENA_DLY */ +#define WM8961_HPL_ENA 0x0010 /* HPL_ENA */ +#define WM8961_HPL_ENA_MASK 0x0010 /* HPL_ENA */ +#define WM8961_HPL_ENA_SHIFT 4 /* HPL_ENA */ +#define WM8961_HPL_ENA_WIDTH 1 /* HPL_ENA */ +#define WM8961_HPR_RMV_SHORT 0x0008 /* HPR_RMV_SHORT */ +#define WM8961_HPR_RMV_SHORT_MASK 0x0008 /* HPR_RMV_SHORT */ +#define WM8961_HPR_RMV_SHORT_SHIFT 3 /* HPR_RMV_SHORT */ +#define WM8961_HPR_RMV_SHORT_WIDTH 1 /* HPR_RMV_SHORT */ +#define WM8961_HPR_ENA_OUTP 0x0004 /* HPR_ENA_OUTP */ +#define WM8961_HPR_ENA_OUTP_MASK 0x0004 /* HPR_ENA_OUTP */ +#define WM8961_HPR_ENA_OUTP_SHIFT 2 /* HPR_ENA_OUTP */ +#define WM8961_HPR_ENA_OUTP_WIDTH 1 /* HPR_ENA_OUTP */ +#define WM8961_HPR_ENA_DLY 0x0002 /* HPR_ENA_DLY */ +#define WM8961_HPR_ENA_DLY_MASK 0x0002 /* HPR_ENA_DLY */ +#define WM8961_HPR_ENA_DLY_SHIFT 1 /* HPR_ENA_DLY */ +#define WM8961_HPR_ENA_DLY_WIDTH 1 /* HPR_ENA_DLY */ +#define WM8961_HPR_ENA 0x0001 /* HPR_ENA */ +#define WM8961_HPR_ENA_MASK 0x0001 /* HPR_ENA */ +#define WM8961_HPR_ENA_SHIFT 0 /* HPR_ENA */ +#define WM8961_HPR_ENA_WIDTH 1 /* HPR_ENA */ + +/* + * R71 (0x47) - Analogue HP 2 + */ +#define WM8961_HPL_VOL_MASK 0x01C0 /* HPL_VOL - [8:6] */ +#define WM8961_HPL_VOL_SHIFT 6 /* HPL_VOL - [8:6] */ +#define WM8961_HPL_VOL_WIDTH 3 /* HPL_VOL - [8:6] */ +#define WM8961_HPR_VOL_MASK 0x0038 /* HPR_VOL - [5:3] */ +#define WM8961_HPR_VOL_SHIFT 3 /* HPR_VOL - [5:3] */ +#define WM8961_HPR_VOL_WIDTH 3 /* HPR_VOL - [5:3] */ +#define WM8961_HP_BIAS_BOOST_MASK 0x0007 /* HP_BIAS_BOOST - [2:0] */ +#define WM8961_HP_BIAS_BOOST_SHIFT 0 /* HP_BIAS_BOOST - [2:0] */ +#define WM8961_HP_BIAS_BOOST_WIDTH 3 /* HP_BIAS_BOOST - [2:0] */ + +/* + * R72 (0x48) - Charge Pump 1 + */ +#define WM8961_CP_ENA 0x0001 /* CP_ENA */ +#define WM8961_CP_ENA_MASK 0x0001 /* CP_ENA */ +#define WM8961_CP_ENA_SHIFT 0 /* CP_ENA */ +#define WM8961_CP_ENA_WIDTH 1 /* CP_ENA */ + +/* + * R82 (0x52) - Charge Pump B + */ +#define WM8961_CP_DYN_PWR_MASK 0x0003 /* CP_DYN_PWR - [1:0] */ +#define WM8961_CP_DYN_PWR_SHIFT 0 /* CP_DYN_PWR - [1:0] */ +#define WM8961_CP_DYN_PWR_WIDTH 2 /* CP_DYN_PWR - [1:0] */ + +/* + * R87 (0x57) - Write Sequencer 1 + */ +#define WM8961_WSEQ_ENA 0x0020 /* WSEQ_ENA */ +#define WM8961_WSEQ_ENA_MASK 0x0020 /* WSEQ_ENA */ +#define WM8961_WSEQ_ENA_SHIFT 5 /* WSEQ_ENA */ +#define WM8961_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */ +#define WM8961_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */ +#define WM8961_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */ +#define WM8961_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */ + +/* + * R88 (0x58) - Write Sequencer 2 + */ +#define WM8961_WSEQ_EOS 0x0100 /* WSEQ_EOS */ +#define WM8961_WSEQ_EOS_MASK 0x0100 /* WSEQ_EOS */ +#define WM8961_WSEQ_EOS_SHIFT 8 /* WSEQ_EOS */ +#define WM8961_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */ +#define WM8961_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */ +#define WM8961_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */ +#define WM8961_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */ + +/* + * R89 (0x59) - Write Sequencer 3 + */ +#define WM8961_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */ +#define WM8961_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */ +#define WM8961_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */ + +/* + * R90 (0x5A) - Write Sequencer 4 + */ +#define WM8961_WSEQ_ABORT 0x0100 /* WSEQ_ABORT */ +#define WM8961_WSEQ_ABORT_MASK 0x0100 /* WSEQ_ABORT */ +#define WM8961_WSEQ_ABORT_SHIFT 8 /* WSEQ_ABORT */ +#define WM8961_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */ +#define WM8961_WSEQ_START 0x0080 /* WSEQ_START */ +#define WM8961_WSEQ_START_MASK 0x0080 /* WSEQ_START */ +#define WM8961_WSEQ_START_SHIFT 7 /* WSEQ_START */ +#define WM8961_WSEQ_START_WIDTH 1 /* WSEQ_START */ +#define WM8961_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */ +#define WM8961_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */ +#define WM8961_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */ + +/* + * R91 (0x5B) - Write Sequencer 5 + */ +#define WM8961_WSEQ_DATA_WIDTH_MASK 0x0070 /* WSEQ_DATA_WIDTH - [6:4] */ +#define WM8961_WSEQ_DATA_WIDTH_SHIFT 4 /* WSEQ_DATA_WIDTH - [6:4] */ +#define WM8961_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [6:4] */ +#define WM8961_WSEQ_DATA_START_MASK 0x000F /* WSEQ_DATA_START - [3:0] */ +#define WM8961_WSEQ_DATA_START_SHIFT 0 /* WSEQ_DATA_START - [3:0] */ +#define WM8961_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [3:0] */ + +/* + * R92 (0x5C) - Write Sequencer 6 + */ +#define WM8961_WSEQ_DELAY_MASK 0x000F /* WSEQ_DELAY - [3:0] */ +#define WM8961_WSEQ_DELAY_SHIFT 0 /* WSEQ_DELAY - [3:0] */ +#define WM8961_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [3:0] */ + +/* + * R93 (0x5D) - Write Sequencer 7 + */ +#define WM8961_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */ +#define WM8961_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */ +#define WM8961_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */ +#define WM8961_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */ + +/* + * R252 (0xFC) - General test 1 + */ +#define WM8961_ARA_ENA 0x0002 /* ARA_ENA */ +#define WM8961_ARA_ENA_MASK 0x0002 /* ARA_ENA */ +#define WM8961_ARA_ENA_SHIFT 1 /* ARA_ENA */ +#define WM8961_ARA_ENA_WIDTH 1 /* ARA_ENA */ +#define WM8961_AUTO_INC 0x0001 /* AUTO_INC */ +#define WM8961_AUTO_INC_MASK 0x0001 /* AUTO_INC */ +#define WM8961_AUTO_INC_SHIFT 0 /* AUTO_INC */ +#define WM8961_AUTO_INC_WIDTH 1 /* AUTO_INC */ + +#endif -- cgit v0.10.2 From 802070f5474af1a49435a9528aede47bb18abd47 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 12 Jun 2009 18:32:07 +0200 Subject: x86/oprofile: fix initialization of arch_perfmon for core_i7 Commit: e419294 x86/oprofile: moving arch_perfmon counter setup to op_x86_model_spec.init introduced a bug in the initialization of core_i7 leading to the incorrect model setup to &op_ppro_spec. This patch fixes this. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 7826dfc..28ee490 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -406,6 +406,7 @@ module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0); static int __init ppro_init(char **cpu_type) { __u8 cpu_model = boot_cpu_data.x86_model; + struct op_x86_model_spec const *spec = &op_ppro_spec; /* default */ if (force_arch_perfmon && cpu_has_arch_perfmon) return 0; @@ -432,7 +433,7 @@ static int __init ppro_init(char **cpu_type) *cpu_type = "i386/core_2"; break; case 26: - model = &op_arch_perfmon_spec; + spec = &op_arch_perfmon_spec; *cpu_type = "i386/core_i7"; break; case 28: @@ -443,7 +444,7 @@ static int __init ppro_init(char **cpu_type) return 0; } - model = &op_ppro_spec; + model = spec; return 1; } -- cgit v0.10.2 From df205936d5d1dfec9a52c90af77bb54a2c9c9728 Mon Sep 17 00:00:00 2001 From: "Lopez Cruz, Misael" Date: Thu, 11 Jun 2009 17:35:27 -0500 Subject: ASoC: Zoom2: Add machine driver for Zoom2 board Add support for Zoom2 board. Zoom2 machine driver connects both codec DAIs (audio and voice) to omap3 McBSP ports in the following way: HiFi <-> McBSP2 Voice <-> McBSP3 The zoom2 driver has the following DAPM widgets: * Ext Mic: MAINMIC, SUBMIC (with bias) * Ext Spk: HFL, HFR * Headset Stereophone: HSOL, HSOR * Headset Mic: HSMIC (with bias) * Aux In: AUXL, AUXR Signed-off-by: Misael Lopez Cruz Signed-off-by: Mark Brown diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index b771238..a5a90e5 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -72,4 +72,11 @@ config SND_OMAP_SOC_OMAP3_BEAGLE help Say Y if you want to add support for SoC audio on the Beagleboard. +config SND_OMAP_SOC_ZOOM2 + tristate "SoC Audio support for Zoom2" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_ZOOM2 + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for Soc audio on Zoom2 board. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index a37f498..fefc48f 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -14,6 +14,7 @@ snd-soc-omap3evm-objs := omap3evm.o snd-soc-sdp3430-objs := sdp3430.o snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o +snd-soc-zoom2-objs := zoom2.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o @@ -23,3 +24,4 @@ obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o +obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c new file mode 100644 index 0000000..be2e307 --- /dev/null +++ b/sound/soc/omap/zoom2.c @@ -0,0 +1,301 @@ +/* + * zoom2.c -- SoC audio for Zoom2 + * + * Author: Misael Lopez Cruz + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15) + +static int zoom2_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops zoom2_ops = { + .hw_params = zoom2_hw_params, +}; + +static int zoom2_hw_voice_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBS_CFM); + if (ret) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops zoom2_voice_ops = { + .hw_params = zoom2_hw_voice_params, +}; + +/* Zoom2 machine DAPM */ +static const struct snd_soc_dapm_widget zoom2_twl4030_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Ext Mic", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_HP("Headset Stereophone", NULL), + SND_SOC_DAPM_LINE("Aux In", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* External Mics: MAINMIC, SUBMIC with bias*/ + {"MAINMIC", NULL, "Mic Bias 1"}, + {"SUBMIC", NULL, "Mic Bias 2"}, + {"Mic Bias 1", NULL, "Ext Mic"}, + {"Mic Bias 2", NULL, "Ext Mic"}, + + /* External Speakers: HFL, HFR */ + {"Ext Spk", NULL, "HFL"}, + {"Ext Spk", NULL, "HFR"}, + + /* Headset Stereophone: HSOL, HSOR */ + {"Headset Stereophone", NULL, "HSOL"}, + {"Headset Stereophone", NULL, "HSOR"}, + + /* Headset Mic: HSMIC with bias */ + {"HSMIC", NULL, "Headset Mic Bias"}, + {"Headset Mic Bias", NULL, "Headset Mic"}, + + /* Aux In: AUXL, AUXR */ + {"Aux In", NULL, "AUXL"}, + {"Aux In", NULL, "AUXR"}, +}; + +static int zoom2_twl4030_init(struct snd_soc_codec *codec) +{ + int ret; + + /* Add Zoom2 specific widgets */ + ret = snd_soc_dapm_new_controls(codec, zoom2_twl4030_dapm_widgets, + ARRAY_SIZE(zoom2_twl4030_dapm_widgets)); + if (ret) + return ret; + + /* Set up Zoom2 specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + /* Zoom2 connected pins */ + snd_soc_dapm_enable_pin(codec, "Ext Mic"); + snd_soc_dapm_enable_pin(codec, "Ext Spk"); + snd_soc_dapm_enable_pin(codec, "Headset Mic"); + snd_soc_dapm_enable_pin(codec, "Headset Stereophone"); + snd_soc_dapm_enable_pin(codec, "Aux In"); + + /* TWL4030 not connected pins */ + snd_soc_dapm_nc_pin(codec, "CARKITMIC"); + snd_soc_dapm_nc_pin(codec, "DIGIMIC0"); + snd_soc_dapm_nc_pin(codec, "DIGIMIC1"); + + snd_soc_dapm_nc_pin(codec, "OUTL"); + snd_soc_dapm_nc_pin(codec, "OUTR"); + snd_soc_dapm_nc_pin(codec, "EARPIECE"); + snd_soc_dapm_nc_pin(codec, "PREDRIVEL"); + snd_soc_dapm_nc_pin(codec, "PREDRIVER"); + snd_soc_dapm_nc_pin(codec, "CARKITL"); + snd_soc_dapm_nc_pin(codec, "CARKITR"); + + ret = snd_soc_dapm_sync(codec); + + return ret; +} + +static int zoom2_twl4030_voice_init(struct snd_soc_codec *codec) +{ + unsigned short reg; + + /* Enable voice interface */ + reg = codec->read(codec, TWL4030_REG_VOICE_IF); + reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN; + codec->write(codec, TWL4030_REG_VOICE_IF, reg); + + return 0; +} + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link zoom2_dai[] = { + { + .name = "TWL4030 I2S", + .stream_name = "TWL4030 Audio", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], + .init = zoom2_twl4030_init, + .ops = &zoom2_ops, + }, + { + .name = "TWL4030 PCM", + .stream_name = "TWL4030 Voice", + .cpu_dai = &omap_mcbsp_dai[1], + .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE], + .init = zoom2_twl4030_voice_init, + .ops = &zoom2_voice_ops, + }, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_zoom2 = { + .name = "Zoom2", + .platform = &omap_soc_platform, + .dai_link = zoom2_dai, + .num_links = ARRAY_SIZE(zoom2_dai), +}; + +/* twl4030 setup */ +static struct twl4030_setup_data twl4030_setup = { + .ramp_delay_value = 2, /* 81 ms */ + .sysclk = 26000, +}; + +/* Audio subsystem */ +static struct snd_soc_device zoom2_snd_devdata = { + .card = &snd_soc_zoom2, + .codec_dev = &soc_codec_dev_twl4030, + .codec_data = &twl4030_setup, +}; + +static struct platform_device *zoom2_snd_device; + +static int __init zoom2_soc_init(void) +{ + int ret; + + if (!machine_is_omap_zoom2()) { + pr_debug("Not Zoom2!\n"); + return -ENODEV; + } + printk(KERN_INFO "Zoom2 SoC init\n"); + + zoom2_snd_device = platform_device_alloc("soc-audio", -1); + if (!zoom2_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(zoom2_snd_device, &zoom2_snd_devdata); + zoom2_snd_devdata.dev = &zoom2_snd_device->dev; + *(unsigned int *)zoom2_dai[0].cpu_dai->private_data = 1; /* McBSP2 */ + *(unsigned int *)zoom2_dai[1].cpu_dai->private_data = 2; /* McBSP3 */ + + ret = platform_device_add(zoom2_snd_device); + if (ret) + goto err1; + + BUG_ON(gpio_request(ZOOM2_HEADSET_MUX_GPIO, "hs_mux") < 0); + gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0); + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(zoom2_snd_device); + + return ret; +} +module_init(zoom2_soc_init); + +static void __exit zoom2_soc_exit(void) +{ + gpio_free(ZOOM2_HEADSET_MUX_GPIO); + + platform_device_unregister(zoom2_snd_device); +} +module_exit(zoom2_soc_exit); + +MODULE_AUTHOR("Misael Lopez Cruz "); +MODULE_DESCRIPTION("ALSA SoC Zoom2"); +MODULE_LICENSE("GPL"); + -- cgit v0.10.2 From 9e79261f302083cbc6aa95e0f778e3583b1ab36e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 12 Jun 2009 17:27:07 +0100 Subject: ASoC: Automatically control WM8903 sloping stopband filter For best performance the DAC sloping stopband filter should be enabled below 24kHz and not enabled above that so remove the user visible control for this and do it autonomously in the driver. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index d8a9222..3ebd770 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -715,8 +715,6 @@ SOC_ENUM("DAC Soft Mute Rate", soft_mute), SOC_ENUM("DAC Mute Mode", mute_mode), SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0), SOC_ENUM("DAC De-emphasis", dac_deemphasis), -SOC_SINGLE("DAC Sloping Stopband Filter Switch", - WM8903_DAC_DIGITAL_1, 11, 1, 0), SOC_ENUM("DAC Companding Mode", dac_companding), SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0), @@ -1377,12 +1375,19 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream, u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3); u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0); u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1); + u16 dac_digital1 = wm8903_read(codec, WM8903_DAC_DIGITAL_1); if (substream == wm8903->slave_substream) { dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); return 0; } + /* Enable sloping stopband filter for low sample rates */ + if (fs <= 24000) + dac_digital1 |= WM8903_DAC_SB_FILT; + else + dac_digital1 &= ~WM8903_DAC_SB_FILT; + /* Configure sample rate logic for DSP - choose nearest rate */ dsp_config = 0; best_val = abs(sample_rates[dsp_config].rate - fs); @@ -1507,6 +1512,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream, wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2); wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3); + wm8903_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1); return 0; } -- cgit v0.10.2 From 21002e20767292d85701154cdf12a591b45f0979 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 12 Jun 2009 17:27:52 +0100 Subject: ASoC: Automatically manage WM8900 sloping stopband filter For best performance the DAC sloping stopband filter should be enabled below 24kHz and not enabled above that so remove the user visible control for this and do it autonomously in the driver. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 3c78945..de99206 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -116,6 +116,7 @@ #define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c #define WM8900_REG_DACCTRL_MUTE 0x004 +#define WM8900_REG_DACCTRL_DAC_SB_FILT 0x100 #define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400 #define WM8900_REG_AUDIO3_ADCLRC_DIR 0x0800 @@ -439,7 +440,6 @@ SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1), SOC_ENUM("DAC Mute Rate", dac_mute_rate), SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0), SOC_ENUM("DAC Deemphasis", dac_deemphasis), -SOC_SINGLE("DAC Sloping Stopband Filter Switch", WM8900_REG_DACCTRL, 8, 1, 0), SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL, 12, 1, 0), @@ -743,6 +743,17 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream, wm8900_write(codec, WM8900_REG_AUDIO1, reg); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + reg = wm8900_read(codec, WM8900_REG_DACCTRL); + + if (params_rate(params) <= 24000) + reg |= WM8900_REG_DACCTRL_DAC_SB_FILT; + else + reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT; + + wm8900_write(codec, WM8900_REG_DACCTRL, reg); + } + return 0; } -- cgit v0.10.2 From 619439998ac32953d737fbe2dc82eb67024547d0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 12 Jun 2009 22:56:59 +0100 Subject: ASoC: Automatically manage WM8350 sloping stopband filter For best performance the DAC sloping stopband filter should be enabled below 24kHz and not enabled above that so remove the user visible control for this and do it autonomously in the driver. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index e7348d3..f6bb599 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -406,7 +406,6 @@ static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" }; static const char *wm8350_dacmutem[] = { "Normal", "Soft" }; static const char *wm8350_dacmutes[] = { "Fast", "Slow" }; -static const char *wm8350_dacfilter[] = { "Normal", "Sloping" }; static const char *wm8350_adcfilter[] = { "None", "High Pass" }; static const char *wm8350_adchp[] = { "44.1kHz", "8kHz", "16kHz", "32kHz" }; static const char *wm8350_lr[] = { "Left", "Right" }; @@ -416,7 +415,6 @@ static const struct soc_enum wm8350_enum[] = { SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 0, 4, wm8350_pol), SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 14, 2, wm8350_dacmutem), SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 13, 2, wm8350_dacmutes), - SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 12, 2, wm8350_dacfilter), SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 15, 2, wm8350_adcfilter), SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 8, 4, wm8350_adchp), SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 0, 4, wm8350_pol), @@ -444,10 +442,9 @@ static const struct snd_kcontrol_new wm8350_snd_controls[] = { 0, 255, 0, dac_pcm_tlv), SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]), SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]), - SOC_ENUM("Playback PCM Filter", wm8350_enum[4]), - SOC_ENUM("Capture PCM Filter", wm8350_enum[5]), - SOC_ENUM("Capture PCM HP Filter", wm8350_enum[6]), - SOC_ENUM("Capture ADC Inversion", wm8350_enum[7]), + SOC_ENUM("Capture PCM Filter", wm8350_enum[4]), + SOC_ENUM("Capture PCM HP Filter", wm8350_enum[5]), + SOC_ENUM("Capture ADC Inversion", wm8350_enum[6]), SOC_WM8350_DOUBLE_R_TLV("Capture PCM Volume", WM8350_ADC_DIGITAL_VOLUME_L, WM8350_ADC_DIGITAL_VOLUME_R, @@ -993,6 +990,7 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai) { struct snd_soc_codec *codec = codec_dai->codec; + struct wm8350 *wm8350 = codec->control_data; u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) & ~WM8350_AIF_WL_MASK; @@ -1012,6 +1010,19 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream, } wm8350_codec_write(codec, WM8350_AI_FORMATING, iface); + + /* The sloping stopband filter is recommended for use with + * lower sample rates to improve performance. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (params_rate(params) < 24000) + wm8350_set_bits(wm8350, WM8350_DAC_MUTE_VOLUME, + WM8350_DAC_SB_FILT); + else + wm8350_clear_bits(wm8350, WM8350_DAC_MUTE_VOLUME, + WM8350_DAC_SB_FILT); + } + return 0; } -- cgit v0.10.2 From 831dc0f10f7b2a4856094ff160c018bf19f77527 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 13 Jun 2009 19:55:02 +0100 Subject: ASoC: Add stub suspend and resume calls for ASoC subdevices Now that ASoC subdevices can be regular devices they can have normal suspend and resume calls from their buses. However, suspending them individually is not desirable since this can lead to problems such as pops and clicks from devices being suspended with their signals being amplified or clocks being stopped suddenly. This will be resolved by having the normal device model suspend and resume calls call into ASoC which will suspend the entire card while any of its components are suspended. At present this is not yet implemented but in order to aid the transition of drivers to the standard device model this patch adds API calls for the notifications. Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 5297ba7..e6704c0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -192,6 +192,11 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform); int snd_soc_register_codec(struct snd_soc_codec *codec); void snd_soc_unregister_codec(struct snd_soc_codec *codec); +#ifdef CONFIG_PM +int snd_soc_suspend_device(struct device *dev); +int snd_soc_resume_device(struct device *dev); +#endif + /* pcm <-> DAI connect */ void snd_soc_free_pcms(struct snd_soc_device *socdev); int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e1a920c..4414117 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -788,6 +788,45 @@ static int soc_resume(struct platform_device *pdev) return 0; } +/** + * snd_soc_suspend_device: Notify core of device suspend + * + * @dev: Device being suspended. + * + * In order to ensure that the entire audio subsystem is suspended in a + * coordinated fashion ASoC devices should suspend themselves when + * called by ASoC. When the standard kernel suspend process asks the + * device to suspend it should call this function to initiate a suspend + * of the entire ASoC card. + * + * \note Currently this function is stubbed out. + */ +int snd_soc_suspend_device(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_suspend_device); + +/** + * snd_soc_resume_device: Notify core of device resume + * + * @dev: Device being resumed. + * + * In order to ensure that the entire audio subsystem is resumed in a + * coordinated fashion ASoC devices should resume themselves when called + * by ASoC. When the standard kernel resume process asks the device + * to resume it should call this function. Once all the components of + * the card have notified that they are ready to be resumed the card + * will be resumed. + * + * \note Currently this function is stubbed out. + */ +int snd_soc_resume_device(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_resume_device); + #else #define soc_suspend NULL #define soc_resume NULL -- cgit v0.10.2 From c64b04fe6e0cb7c78e01751a44ef56cf20344e87 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sun, 14 Jun 2009 00:59:50 +0530 Subject: x86, cpu: cpu/proc.c display cache alignment and address sizes for 32 bit 32 bits can also access x86_cache_alignment, x86_phys_bits and x86_virt_bits, make them available to user space just as on 64 bits. Signed-off-by: Jaswinder Singh Rajput LKML-Reference: <1244921390.11733.30.camel@ht.satnam> Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c index d5e3039..f82706a 100644 --- a/arch/x86/kernel/cpu/proc.c +++ b/arch/x86/kernel/cpu/proc.c @@ -116,11 +116,9 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize); #endif seq_printf(m, "clflush size\t: %u\n", c->x86_clflush_size); -#ifdef CONFIG_X86_64 seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment); seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n", c->x86_phys_bits, c->x86_virt_bits); -#endif seq_printf(m, "power management:"); for (i = 0; i < 32; i++) { -- cgit v0.10.2 From b3b50b3f31775be5d2e441618bbc1c5cbee4d9f1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 13 Jun 2009 22:30:18 +0100 Subject: ASoC: Add suspend and resume callbacks to Wolfson CODEC drivers Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index f6bb599..4ded0e3 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1671,6 +1671,21 @@ static int __devexit wm8350_codec_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int wm8350_codec_suspend(struct platform_device *pdev, pm_message_t m) +{ + return snd_soc_suspend_device(&pdev->dev); +} + +static int wm8350_codec_resume(struct platform_device *pdev) +{ + return snd_soc_resume_device(&pdev->dev); +} +#else +#define wm8350_codec_suspend NULL +#define wm8350_codec_resume NULL +#endif + static struct platform_driver wm8350_codec_driver = { .driver = { .name = "wm8350-codec", @@ -1678,6 +1693,8 @@ static struct platform_driver wm8350_codec_driver = { }, .probe = wm8350_codec_probe, .remove = __devexit_p(wm8350_codec_remove), + .suspend = wm8350_codec_suspend, + .resume = wm8350_codec_resume, }; static __init int wm8350_init(void) diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 502eefa..0bf903f 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1553,6 +1553,21 @@ static int __exit wm8400_codec_remove(struct platform_device *dev) return 0; } +#ifdef CONFIG_PM +static int wm8400_pdev_suspend(struct platform_device *pdev, pm_message_t msg) +{ + return snd_soc_suspend_device(&pdev->dev); +} + +static int wm8400_pdev_resume(struct platform_device *pdev) +{ + return snd_soc_resume_device(&pdev->dev); +} +#else +#define wm8400_pdev_suspend NULL +#define wm8400_pdev_resume NULL +#endif + static struct platform_driver wm8400_codec_driver = { .driver = { .name = "wm8400-codec", @@ -1560,6 +1575,8 @@ static struct platform_driver wm8400_codec_driver = { }, .probe = wm8400_codec_probe, .remove = __exit_p(wm8400_codec_remove), + .suspend = wm8400_pdev_suspend, + .resume = wm8400_pdev_resume, }; static int __init wm8400_codec_init(void) diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 86c4b24d..261ef10 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -995,6 +995,21 @@ static int wm8580_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM +static int wm8580_i2c_suspend(struct i2c_client *client, pm_message_t msg) +{ + return snd_soc_suspend_device(&client->dev); +} + +static int wm8580_i2c_resume(struct i2c_client *client) +{ + return snd_soc_resume_device(&client->dev); +} +#else +#define wm8580_i2c_suspend NULL +#define wm8580_i2c_resume NULL +#endif + static const struct i2c_device_id wm8580_i2c_id[] = { { "wm8580", 0 }, { } @@ -1008,6 +1023,8 @@ static struct i2c_driver wm8580_i2c_driver = { }, .probe = wm8580_i2c_probe, .remove = wm8580_i2c_remove, + .suspend = wm8580_i2c_suspend, + .resume = wm8580_i2c_resume, .id_table = wm8580_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 7a20587..d7f4788 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -460,6 +460,7 @@ struct snd_soc_dai wm8731_dai = { }; EXPORT_SYMBOL_GPL(wm8731_dai); +#ifdef CONFIG_PM static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); @@ -488,6 +489,10 @@ static int wm8731_resume(struct platform_device *pdev) wm8731_set_bias_level(codec, codec->suspend_bias_level); return 0; } +#else +#define wm8731_suspend NULL +#define wm8731_resume NULL +#endif static int wm8731_probe(struct platform_device *pdev) { @@ -680,6 +685,21 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi) return 0; } +#ifdef CONFIG_PM +static int wm8731_spi_suspend(struct spi_device *spi, pm_message_t msg) +{ + return snd_soc_suspend_device(&spi->dev); +} + +static int wm8731_spi_resume(struct spi_device *spi) +{ + return snd_soc_resume_device(&spi->dev); +} +#else +#define wm8731_spi_suspend NULL +#define wm8731_spi_resume NULL +#endif + static struct spi_driver wm8731_spi_driver = { .driver = { .name = "wm8731", @@ -687,6 +707,8 @@ static struct spi_driver wm8731_spi_driver = { .owner = THIS_MODULE, }, .probe = wm8731_spi_probe, + .suspend = wm8731_spi_suspend, + .resume = wm8731_spi_resume, .remove = __devexit_p(wm8731_spi_remove), }; #endif /* CONFIG_SPI_MASTER */ @@ -720,6 +742,21 @@ static __devexit int wm8731_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM +static int wm8731_i2c_suspend(struct i2c_client *i2c, pm_message_t msg) +{ + return snd_soc_suspend_device(&i2c->dev); +} + +static int wm8731_i2c_resume(struct i2c_client *i2c) +{ + return snd_soc_resume_device(&i2c->dev); +} +#else +#define wm8731_i2c_suspend NULL +#define wm8731_i2c_resume NULL +#endif + static const struct i2c_device_id wm8731_i2c_id[] = { { "wm8731", 0 }, { } @@ -733,6 +770,8 @@ static struct i2c_driver wm8731_i2c_driver = { }, .probe = wm8731_i2c_probe, .remove = __devexit_p(wm8731_i2c_remove), + .suspend = wm8731_i2c_suspend, + .resume = wm8731_i2c_resume, .id_table = wm8731_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index d28eeac..370f7df 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1766,6 +1766,21 @@ static int wm8753_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM +static int wm8753_i2c_suspend(struct i2c_client *client, pm_message_t msg) +{ + return snd_soc_suspend_device(&client->dev); +} + +static int wm8753_i2c_resume(struct i2c_client *client) +{ + return snd_soc_resume_device(&client->dev); +} +#else +#define wm8753_i2c_suspend NULL +#define wm8753_i2c_resume NULL +#endif + static const struct i2c_device_id wm8753_i2c_id[] = { { "wm8753", 0 }, { } @@ -1779,6 +1794,8 @@ static struct i2c_driver wm8753_i2c_driver = { }, .probe = wm8753_i2c_probe, .remove = wm8753_i2c_remove, + .suspend = wm8753_i2c_suspend, + .resume = wm8753_i2c_resume, .id_table = wm8753_i2c_id, }; #endif @@ -1834,6 +1851,22 @@ static int __devexit wm8753_spi_remove(struct spi_device *spi) return 0; } +#ifdef CONFIG_PM +static int wm8753_spi_suspend(struct spi_device *spi, pm_message_t msg) +{ + return snd_soc_suspend_device(&spi->dev); +} + +static int wm8753_spi_resume(struct spi_device *spi) +{ + return snd_soc_resume_device(&spi->dev); +} + +#else +#define wm8753_spi_suspend NULL +#define wm8753_spi_resume NULL +#endif + static struct spi_driver wm8753_spi_driver = { .driver = { .name = "wm8753", @@ -1842,6 +1875,8 @@ static struct spi_driver wm8753_spi_driver = { }, .probe = wm8753_spi_probe, .remove = __devexit_p(wm8753_spi_remove), + .suspend = wm8753_spi_suspend, + .resume = wm8753_spi_resume, }; #endif diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index de99206..ac30899 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1399,6 +1399,21 @@ static __devexit int wm8900_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM +static int wm8900_i2c_suspend(struct i2c_client *client, pm_message_t msg) +{ + return snd_soc_suspend_device(&client->dev); +} + +static int wm8900_i2c_resume(struct i2c_client *client) +{ + return snd_soc_resume_device(&client->dev); +} +#else +#define wm8900_i2c_suspend NULL +#define wm8900_i2c_resume NULL +#endif + static const struct i2c_device_id wm8900_i2c_id[] = { { "wm8900", 0 }, { } @@ -1412,6 +1427,8 @@ static struct i2c_driver wm8900_i2c_driver = { }, .probe = wm8900_i2c_probe, .remove = __devexit_p(wm8900_i2c_remove), + .suspend = wm8900_i2c_suspend, + .resume = wm8900_i2c_resume, .id_table = wm8900_i2c_id, }; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 3ebd770..6239af8 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1731,6 +1731,21 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM +static int wm8903_i2c_suspend(struct i2c_client *client, pm_message_t msg) +{ + return snd_soc_suspend_device(&client->dev); +} + +static int wm8903_i2c_resume(struct i2c_client *client) +{ + return snd_soc_resume_device(&client->dev); +} +#else +#define wm8903_i2c_suspend NULL +#define wm8903_i2c_resume NULL +#endif + /* i2c codec control layer */ static const struct i2c_device_id wm8903_i2c_id[] = { { "wm8903", 0 }, @@ -1745,6 +1760,8 @@ static struct i2c_driver wm8903_i2c_driver = { }, .probe = wm8903_i2c_probe, .remove = __devexit_p(wm8903_i2c_remove), + .suspend = wm8903_i2c_suspend, + .resume = wm8903_i2c_resume, .id_table = wm8903_i2c_id, }; diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index b8e17d6..b69210a 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -916,6 +916,21 @@ static int __devexit wm8940_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM +static int wm8940_i2c_suspend(struct i2c_client *client, pm_message_t msg) +{ + return snd_soc_suspend_device(&client->dev); +} + +static int wm8940_i2c_resume(struct i2c_client *client) +{ + return snd_soc_resume_device(&client->dev); +} +#else +#define wm8940_i2c_suspend NULL +#define wm8940_i2c_resume NULL +#endif + static const struct i2c_device_id wm8940_i2c_id[] = { { "wm8940", 0 }, { } @@ -929,6 +944,8 @@ static struct i2c_driver wm8940_i2c_driver = { }, .probe = wm8940_i2c_probe, .remove = __devexit_p(wm8940_i2c_remove), + .suspend = wm8940_i2c_suspend, + .resume = wm8940_i2c_resume, .id_table = wm8940_i2c_id, }; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index e224d8a..b7894d6 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -927,6 +927,21 @@ static __devexit int wm8960_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM +static int wm8960_i2c_suspend(struct i2c_client *client, pm_message_t msg) +{ + return snd_soc_suspend_device(&client->dev); +} + +static int wm8960_i2c_resume(struct i2c_client *client) +{ + return snd_soc_resume_device(&client->dev); +} +#else +#define wm8960_i2c_suspend NULL +#define wm8960_i2c_resume NULL +#endif + static const struct i2c_device_id wm8960_i2c_id[] = { { "wm8960", 0 }, { } @@ -940,6 +955,8 @@ static struct i2c_driver wm8960_i2c_driver = { }, .probe = wm8960_i2c_probe, .remove = __devexit_p(wm8960_i2c_remove), + .suspend = wm8960_i2c_suspend, + .resume = wm8960_i2c_resume, .id_table = wm8960_i2c_id, }; diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index c05f718..03fac6a 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -981,6 +981,21 @@ static int wm8988_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM +static int wm8988_i2c_suspend(struct i2c_client *client, pm_message_t msg) +{ + return snd_soc_suspend_device(&client->dev); +} + +static int wm8988_i2c_resume(struct i2c_client *client) +{ + return snd_soc_resume_device(&client->dev); +} +#else +#define wm8988_i2c_suspend NULL +#define wm8988_i2c_resume NULL +#endif + static const struct i2c_device_id wm8988_i2c_id[] = { { "wm8988", 0 }, { } @@ -994,6 +1009,8 @@ static struct i2c_driver wm8988_i2c_driver = { }, .probe = wm8988_i2c_probe, .remove = wm8988_i2c_remove, + .suspend = wm8988_i2c_suspend, + .resume = wm8988_i2c_resume, .id_table = wm8988_i2c_id, }; #endif @@ -1051,6 +1068,21 @@ static int __devexit wm8988_spi_remove(struct spi_device *spi) return 0; } +#ifdef CONFIG_PM +static int wm8988_spi_suspend(struct spi_device *spi, pm_message_t msg) +{ + return snd_soc_suspend_device(&spi->dev); +} + +static int wm8988_spi_resume(struct spi_device *spi) +{ + return snd_soc_resume_device(&spi->dev); +} +#else +#define wm8988_spi_suspend NULL +#define wm8988_spi_resume NULL +#endif + static struct spi_driver wm8988_spi_driver = { .driver = { .name = "wm8988", @@ -1059,6 +1091,8 @@ static struct spi_driver wm8988_spi_driver = { }, .probe = wm8988_spi_probe, .remove = __devexit_p(wm8988_spi_remove), + .suspend = wm8988_spi_suspend, + .resume = wm8988_spi_resume, }; #endif diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 86fc57e..dbe2059 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1492,6 +1492,21 @@ static __devexit int wm9081_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM +static int wm9081_i2c_suspend(struct i2c_client *client, pm_message_t msg) +{ + return snd_soc_suspend_device(&client->dev); +} + +static int wm9081_i2c_resume(struct i2c_client *client) +{ + return snd_soc_resume_device(&client->dev); +} +#else +#define wm9081_i2c_suspend NULL +#define wm9081_i2c_resume NULL +#endif + static const struct i2c_device_id wm9081_i2c_id[] = { { "wm9081", 0 }, { } @@ -1505,6 +1520,8 @@ static struct i2c_driver wm9081_i2c_driver = { }, .probe = wm9081_i2c_probe, .remove = __devexit_p(wm9081_i2c_remove), + .suspend = wm9081_i2c_suspend, + .resume = wm9081_i2c_resume, .id_table = wm9081_i2c_id, }; -- cgit v0.10.2 From ca94c442535a44d508c99a77e54f21a59f4fc462 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Jun 2009 17:17:47 +0200 Subject: sched: Introduce SCHED_RESET_ON_FORK scheduling policy flag This patch introduces a new flag SCHED_RESET_ON_FORK which can be passed to the kernel via sched_setscheduler(), ORed in the policy parameter. If set this will make sure that when the process forks a) the scheduling priority is reset to DEFAULT_PRIO if it was higher and b) the scheduling policy is reset to SCHED_NORMAL if it was either SCHED_FIFO or SCHED_RR. Why have this? Currently, if a process is real-time scheduled this will 'leak' to all its child processes. For security reasons it is often (always?) a good idea to make sure that if a process acquires RT scheduling this is confined to this process and only this process. More specifically this makes the per-process resource limit RLIMIT_RTTIME useful for security purposes, because it makes it impossible to use a fork bomb to circumvent the per-process RLIMIT_RTTIME accounting. This feature is also useful for tools like 'renice' which can then change the nice level of a process without having this spill to all its child processes. Why expose this via sched_setscheduler() and not other syscalls such as prctl() or sched_setparam()? prctl() does not take a pid parameter. Due to that it would be impossible to modify this flag for other processes than the current one. The struct passed to sched_setparam() can unfortunately not be extended without breaking compatibility, since sched_setparam() lacks a size parameter. How to use this from userspace? In your RT program simply replace this: sched_setscheduler(pid, SCHED_FIFO, ¶m); by this: sched_setscheduler(pid, SCHED_FIFO|SCHED_RESET_ON_FORK, ¶m); Signed-off-by: Lennart Poettering Acked-by: Peter Zijlstra LKML-Reference: <20090615152714.GA29092@tango.0pointer.de> Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 4896fdf..d4a2c66 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -38,6 +38,8 @@ #define SCHED_BATCH 3 /* SCHED_ISO: reserved but not implemented yet */ #define SCHED_IDLE 5 +/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */ +#define SCHED_RESET_ON_FORK 0x40000000 #ifdef __KERNEL__ @@ -1209,6 +1211,10 @@ struct task_struct { unsigned did_exec:1; unsigned in_execve:1; /* Tell the LSMs that the process is doing an * execve */ + + /* Revert to default priority/policy when forking */ + unsigned sched_reset_on_fork:1; + pid_t pid; pid_t tgid; diff --git a/kernel/sched.c b/kernel/sched.c index 8ec9d13..32e6ede 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2613,12 +2613,28 @@ void sched_fork(struct task_struct *p, int clone_flags) set_task_cpu(p, cpu); /* - * Make sure we do not leak PI boosting priority to the child: + * Revert to default priority/policy on fork if requested. Make sure we + * do not leak PI boosting priority to the child. */ - p->prio = current->normal_prio; + if (current->sched_reset_on_fork && + (p->policy == SCHED_FIFO || p->policy == SCHED_RR)) + p->policy = SCHED_NORMAL; + + if (current->sched_reset_on_fork && + (current->normal_prio < DEFAULT_PRIO)) + p->prio = DEFAULT_PRIO; + else + p->prio = current->normal_prio; + if (!rt_prio(p->prio)) p->sched_class = &fair_sched_class; + /* + * We don't need the reset flag anymore after the fork. It has + * fulfilled its duty: + */ + p->sched_reset_on_fork = 0; + #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) if (likely(sched_info_on())) memset(&p->sched_info, 0, sizeof(p->sched_info)); @@ -6094,17 +6110,25 @@ static int __sched_setscheduler(struct task_struct *p, int policy, unsigned long flags; const struct sched_class *prev_class = p->sched_class; struct rq *rq; + int reset_on_fork; /* may grab non-irq protected spin_locks */ BUG_ON(in_interrupt()); recheck: /* double check policy once rq lock held */ - if (policy < 0) + if (policy < 0) { + reset_on_fork = p->sched_reset_on_fork; policy = oldpolicy = p->policy; - else if (policy != SCHED_FIFO && policy != SCHED_RR && - policy != SCHED_NORMAL && policy != SCHED_BATCH && - policy != SCHED_IDLE) - return -EINVAL; + } else { + reset_on_fork = !!(policy & SCHED_RESET_ON_FORK); + policy &= ~SCHED_RESET_ON_FORK; + + if (policy != SCHED_FIFO && policy != SCHED_RR && + policy != SCHED_NORMAL && policy != SCHED_BATCH && + policy != SCHED_IDLE) + return -EINVAL; + } + /* * Valid priorities for SCHED_FIFO and SCHED_RR are * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL, @@ -6148,6 +6172,10 @@ recheck: /* can't change other user's priorities */ if (!check_same_owner(p)) return -EPERM; + + /* Normal users shall not reset the sched_reset_on_fork flag */ + if (p->sched_reset_on_fork && !reset_on_fork) + return -EPERM; } if (user) { @@ -6191,6 +6219,8 @@ recheck: if (running) p->sched_class->put_prev_task(rq, p); + p->sched_reset_on_fork = reset_on_fork; + oldprio = p->prio; __setscheduler(rq, p, policy, param->sched_priority); @@ -6307,14 +6337,15 @@ SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid) if (p) { retval = security_task_getscheduler(p); if (!retval) - retval = p->policy; + retval = p->policy + | (p->sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0); } read_unlock(&tasklist_lock); return retval; } /** - * sys_sched_getscheduler - get the RT priority of a thread + * sys_sched_getparam - get the RT priority of a thread * @pid: the pid in question. * @param: structure containing the RT priority. */ -- cgit v0.10.2 From 1abd91849990ed61d6468ffa8b7fc1ae61db4b1a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 15 Jun 2009 22:18:23 +0200 Subject: ASoC: UDA1380: refactor device registration This patch mostly follows commit 5998102b9095fdb7c67755812038612afea315c5 "ASoC: Refactor WM8731 device registration" to make UDA1380 use standard device instantiation. Similarly, the I2C device registration temporarily moves into the magician machine driver before it will find its final resting place in the board file. At the same time, platform specific configuration is moved to platform data and common power/reset GPIO handling moves into the codec driver. Signed-off-by: Philipp Zabel Signed-off-by: Mark Brown diff --git a/include/sound/uda1380.h b/include/sound/uda1380.h new file mode 100644 index 0000000..381319c --- /dev/null +++ b/include/sound/uda1380.h @@ -0,0 +1,22 @@ +/* + * UDA1380 ALSA SoC Codec driver + * + * Copyright 2009 Philipp Zabel + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef __UDA1380_H +#define __UDA1380_H + +struct uda1380_platform_data { + int gpio_power; + int gpio_reset; + int dac_clk; +#define UDA1380_DAC_CLK_SYSCLK 0 +#define UDA1380_DAC_CLK_WSPLL 1 +}; + +#endif /* __UDA1380_H */ diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 5b21594..92ec034 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -5,9 +5,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Copyright (c) 2007 Philipp Zabel - * Improved support for DAPM and audio routing/mixing capabilities, - * added TLV support. + * Copyright (c) 2007-2009 Philipp Zabel * * Modified by Richard Purdie to fit into SoC * codec model. @@ -19,26 +17,32 @@ #include #include #include -#include #include #include -#include +#include #include #include #include #include #include #include -#include #include #include #include +#include #include "uda1380.h" -static struct work_struct uda1380_work; static struct snd_soc_codec *uda1380_codec; +/* codec private data */ +struct uda1380_priv { + struct snd_soc_codec codec; + u16 reg_cache[UDA1380_CACHEREGNUM]; + unsigned int dac_clk; + struct work_struct work; +}; + /* * uda1380 register cache */ @@ -473,6 +477,7 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; + struct uda1380_priv *uda1380 = codec->private_data; int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER); switch (cmd) { @@ -480,13 +485,13 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: uda1380_write_reg_cache(codec, UDA1380_MIXER, mixer & ~R14_SILENCE); - schedule_work(&uda1380_work); + schedule_work(&uda1380->work); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: uda1380_write_reg_cache(codec, UDA1380_MIXER, mixer | R14_SILENCE); - schedule_work(&uda1380_work); + schedule_work(&uda1380->work); break; } return 0; @@ -670,44 +675,33 @@ static int uda1380_resume(struct platform_device *pdev) return 0; } -/* - * initialise the UDA1380 driver - * register mixer and dsp interfaces with the kernel - */ -static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) +static int uda1380_probe(struct platform_device *pdev) { - struct snd_soc_codec *codec = socdev->card->codec; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct uda1380_platform_data *pdata; int ret = 0; - codec->name = "UDA1380"; - codec->owner = THIS_MODULE; - codec->read = uda1380_read_reg_cache; - codec->write = uda1380_write; - codec->set_bias_level = uda1380_set_bias_level; - codec->dai = uda1380_dai; - codec->num_dai = ARRAY_SIZE(uda1380_dai); - codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg), - GFP_KERNEL); - if (codec->reg_cache == NULL) - return -ENOMEM; - codec->reg_cache_size = ARRAY_SIZE(uda1380_reg); - codec->reg_cache_step = 1; - uda1380_reset(codec); + if (uda1380_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } - uda1380_codec = codec; - INIT_WORK(&uda1380_work, uda1380_flush_work); + socdev->card->codec = uda1380_codec; + codec = uda1380_codec; + pdata = codec->dev->platform_data; /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { - pr_err("uda1380: failed to create pcms\n"); + dev_err(codec->dev, "failed to create pcms: %d\n", ret); goto pcm_err; } /* power on device */ uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* set clock input */ - switch (dac_clk) { + switch (pdata->dac_clk) { case UDA1380_DAC_CLK_SYSCLK: uda1380_write(codec, UDA1380_CLK, 0); break; @@ -716,13 +710,12 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) break; } - /* uda1380 init */ snd_soc_add_controls(codec, uda1380_snd_controls, ARRAY_SIZE(uda1380_snd_controls)); uda1380_add_widgets(codec); ret = snd_soc_init_card(socdev); if (ret < 0) { - pr_err("uda1380: failed to register card\n"); + dev_err(codec->dev, "failed to register card: %d\n", ret); goto card_err; } @@ -732,165 +725,201 @@ card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); pcm_err: - kfree(codec->reg_cache); return ret; } -static struct snd_soc_device *uda1380_socdev; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -static int uda1380_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +/* power down chip */ +static int uda1380_remove(struct platform_device *pdev) { - struct snd_soc_device *socdev = uda1380_socdev; - struct uda1380_setup_data *setup = socdev->codec_data; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; - int ret; - - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - ret = uda1380_init(socdev, setup->dac_clk); - if (ret < 0) - pr_err("uda1380: failed to initialise UDA1380\n"); + if (codec->control_data) + uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); - return ret; -} + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); -static int uda1380_i2c_remove(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); return 0; } -static const struct i2c_device_id uda1380_i2c_id[] = { - { "uda1380", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id); - -static struct i2c_driver uda1380_i2c_driver = { - .driver = { - .name = "UDA1380 I2C Codec", - .owner = THIS_MODULE, - }, - .probe = uda1380_i2c_probe, - .remove = uda1380_i2c_remove, - .id_table = uda1380_i2c_id, +struct snd_soc_codec_device soc_codec_dev_uda1380 = { + .probe = uda1380_probe, + .remove = uda1380_remove, + .suspend = uda1380_suspend, + .resume = uda1380_resume, }; +EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); -static int uda1380_add_i2c_device(struct platform_device *pdev, - const struct uda1380_setup_data *setup) +static int uda1380_register(struct uda1380_priv *uda1380) { - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; - int ret; + int ret, i; + struct snd_soc_codec *codec = &uda1380->codec; + struct uda1380_platform_data *pdata = codec->dev->platform_data; - ret = i2c_add_driver(&uda1380_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; + if (uda1380_codec) { + dev_err(codec->dev, "Another UDA1380 is registered\n"); + return -EINVAL; + } + + if (!pdata || !pdata->gpio_power || !pdata->gpio_reset) + return -EINVAL; + + ret = gpio_request(pdata->gpio_power, "uda1380 power"); + if (ret) + goto err_out; + ret = gpio_request(pdata->gpio_reset, "uda1380 reset"); + if (ret) + goto err_gpio; + + gpio_direction_output(pdata->gpio_power, 1); + + /* we may need to have the clock running here - pH5 */ + gpio_direction_output(pdata->gpio_reset, 1); + udelay(5); + gpio_set_value(pdata->gpio_reset, 0); + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = uda1380; + codec->name = "UDA1380"; + codec->owner = THIS_MODULE; + codec->read = uda1380_read_reg_cache; + codec->write = uda1380_write; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = uda1380_set_bias_level; + codec->dai = uda1380_dai; + codec->num_dai = ARRAY_SIZE(uda1380_dai); + codec->reg_cache_size = ARRAY_SIZE(uda1380_reg); + codec->reg_cache = &uda1380->reg_cache; + codec->reg_cache_step = 1; + + memcpy(codec->reg_cache, uda1380_reg, sizeof(uda1380_reg)); + + ret = uda1380_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + goto err_reset; } - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = setup->i2c_address; - strlcpy(info.type, "uda1380", I2C_NAME_SIZE); + INIT_WORK(&uda1380->work, uda1380_flush_work); + + for (i = 0; i < ARRAY_SIZE(uda1380_dai); i++) + uda1380_dai[i].dev = codec->dev; - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "can't get i2c adapter %d\n", - setup->i2c_bus); - goto err_driver; + uda1380_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + goto err_reset; } - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - goto err_driver; + ret = snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); + goto err_dai; } return 0; -err_driver: - i2c_del_driver(&uda1380_i2c_driver); - return -ENODEV; +err_dai: + snd_soc_unregister_codec(codec); +err_reset: + gpio_set_value(pdata->gpio_power, 0); + gpio_free(pdata->gpio_reset); +err_gpio: + gpio_free(pdata->gpio_power); +err_out: + return ret; } -#endif -static int uda1380_probe(struct platform_device *pdev) +static void uda1380_unregister(struct uda1380_priv *uda1380) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct uda1380_setup_data *setup; + struct snd_soc_codec *codec = &uda1380->codec; + struct uda1380_platform_data *pdata = codec->dev->platform_data; + + snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); + snd_soc_unregister_codec(&uda1380->codec); + + gpio_set_value(pdata->gpio_power, 0); + gpio_free(pdata->gpio_reset); + gpio_free(pdata->gpio_power); + + kfree(uda1380); + uda1380_codec = NULL; +} + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static __devinit int uda1380_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct uda1380_priv *uda1380; struct snd_soc_codec *codec; int ret; - setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) + uda1380 = kzalloc(sizeof(struct uda1380_priv), GFP_KERNEL); + if (uda1380 == NULL) return -ENOMEM; - socdev->card->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); + codec = &uda1380->codec; + codec->hw_write = (hw_write_t)i2c_master_send; - uda1380_socdev = socdev; - ret = -ENODEV; + i2c_set_clientdata(i2c, uda1380); + codec->control_data = i2c; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - codec->hw_write = (hw_write_t)i2c_master_send; - ret = uda1380_add_i2c_device(pdev, setup); - } -#endif + codec->dev = &i2c->dev; + ret = uda1380_register(uda1380); if (ret != 0) - kfree(codec); + kfree(uda1380); + return ret; } -/* power down chip */ -static int uda1380_remove(struct platform_device *pdev) +static int __devexit uda1380_i2c_remove(struct i2c_client *i2c) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - if (codec->control_data) - uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_unregister_device(codec->control_data); - i2c_del_driver(&uda1380_i2c_driver); -#endif - kfree(codec); - + struct uda1380_priv *uda1380 = i2c_get_clientdata(i2c); + uda1380_unregister(uda1380); return 0; } -struct snd_soc_codec_device soc_codec_dev_uda1380 = { - .probe = uda1380_probe, - .remove = uda1380_remove, - .suspend = uda1380_suspend, - .resume = uda1380_resume, +static const struct i2c_device_id uda1380_i2c_id[] = { + { "uda1380", 0 }, + { } }; -EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); +MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id); + +static struct i2c_driver uda1380_i2c_driver = { + .driver = { + .name = "UDA1380 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = uda1380_i2c_probe, + .remove = __devexit_p(uda1380_i2c_remove), + .id_table = uda1380_i2c_id, +}; +#endif static int __init uda1380_modinit(void) { - return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); + int ret; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&uda1380_i2c_driver); + if (ret != 0) + pr_err("Failed to register UDA1380 I2C driver: %d\n", ret); +#endif + return 0; } module_init(uda1380_modinit); static void __exit uda1380_exit(void) { - snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&uda1380_i2c_driver); +#endif } module_exit(uda1380_exit); diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h index c55c17a..9cefa8a 100644 --- a/sound/soc/codecs/uda1380.h +++ b/sound/soc/codecs/uda1380.h @@ -72,14 +72,6 @@ #define R22_SKIP_DCFIL 0x0002 #define R23_AGC_EN 0x0001 -struct uda1380_setup_data { - int i2c_bus; - unsigned short i2c_address; - int dac_clk; -#define UDA1380_DAC_CLK_SYSCLK 0 -#define UDA1380_DAC_CLK_WSPLL 1 -}; - #define UDA1380_DAI_DUPLEX 0 /* playback and capture on single DAI */ #define UDA1380_DAI_PLAYBACK 1 /* playback DAI */ #define UDA1380_DAI_CAPTURE 2 /* capture DAI */ diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index c89a3cd..9fe4ad2 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -20,12 +20,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -447,34 +449,47 @@ static struct snd_soc_card snd_soc_card_magician = { .platform = &pxa2xx_soc_platform, }; -/* magician audio private data */ -static struct uda1380_setup_data magician_uda1380_setup = { - .i2c_address = 0x18, - .dac_clk = UDA1380_DAC_CLK_WSPLL, -}; - /* magician audio subsystem */ static struct snd_soc_device magician_snd_devdata = { .card = &snd_soc_card_magician, .codec_dev = &soc_codec_dev_uda1380, - .codec_data = &magician_uda1380_setup, }; static struct platform_device *magician_snd_device; +/* + * FIXME: move into magician board file once merged into the pxa tree + */ +static struct uda1380_platform_data uda1380_info = { + .gpio_power = EGPIO_MAGICIAN_CODEC_POWER, + .gpio_reset = EGPIO_MAGICIAN_CODEC_RESET, + .dac_clk = UDA1380_DAC_CLK_WSPLL, +}; + +static struct i2c_board_info i2c_board_info[] = { + { + I2C_BOARD_INFO("uda1380", 0x18), + .platform_data = &uda1380_info, + }, +}; + static int __init magician_init(void) { int ret; + struct i2c_adapter *adapter; + struct i2c_client *client; if (!machine_is_magician()) return -ENODEV; - ret = gpio_request(EGPIO_MAGICIAN_CODEC_POWER, "CODEC_POWER"); - if (ret) - goto err_request_power; - ret = gpio_request(EGPIO_MAGICIAN_CODEC_RESET, "CODEC_RESET"); - if (ret) - goto err_request_reset; + adapter = i2c_get_adapter(0); + if (!adapter) + return -ENODEV; + client = i2c_new_device(adapter, i2c_board_info); + i2c_put_adapter(adapter); + if (!client) + return -ENODEV; + ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER"); if (ret) goto err_request_spk; @@ -491,14 +506,8 @@ static int __init magician_init(void) if (ret) goto err_request_in_sel1; - gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 1); gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0); - /* we may need to have the clock running here - pH5 */ - gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 1); - udelay(5); - gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 0); - magician_snd_device = platform_device_alloc("soc-audio", -1); if (!magician_snd_device) { ret = -ENOMEM; @@ -526,10 +535,6 @@ err_request_mic: err_request_ep: gpio_free(EGPIO_MAGICIAN_SPK_POWER); err_request_spk: - gpio_free(EGPIO_MAGICIAN_CODEC_RESET); -err_request_reset: - gpio_free(EGPIO_MAGICIAN_CODEC_POWER); -err_request_power: return ret; } @@ -540,15 +545,12 @@ static void __exit magician_exit(void) gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0); gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0); gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0); - gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 0); gpio_free(EGPIO_MAGICIAN_IN_SEL1); gpio_free(EGPIO_MAGICIAN_IN_SEL0); gpio_free(EGPIO_MAGICIAN_MIC_POWER); gpio_free(EGPIO_MAGICIAN_EP_POWER); gpio_free(EGPIO_MAGICIAN_SPK_POWER); - gpio_free(EGPIO_MAGICIAN_CODEC_RESET); - gpio_free(EGPIO_MAGICIAN_CODEC_POWER); } module_init(magician_init); -- cgit v0.10.2 From 085f30654175a91c28d2b66b9ea6cceab627fed0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Jun 2009 13:57:07 +0200 Subject: ALSA: Add new TLV types for dBwith min/max Add new types for TLV dB scale specified with min/max values instead of min/step since the resolution can't match always with the one a device provides. For example, usb audio devices give 1/256 dB resolution while ALSA TLV is based on 1/100 dB resolution. The new min/max types have less problems because the possible rounding error happens only at min/max. Signed-off-by: Takashi Iwai diff --git a/include/sound/tlv.h b/include/sound/tlv.h index d136ea2..9fd5b19 100644 --- a/include/sound/tlv.h +++ b/include/sound/tlv.h @@ -35,6 +35,8 @@ #define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */ #define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */ #define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */ +#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */ +#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */ #define TLV_DB_SCALE_ITEM(min, step, mute) \ SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \ @@ -42,6 +44,18 @@ #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \ unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) } +/* dB scale specified with min/max values instead of step */ +#define TLV_DB_MINMAX_ITEM(min_dB, max_dB) \ + SNDRV_CTL_TLVT_DB_MINMAX, 2 * sizeof(unsigned int), \ + (min_dB), (max_dB) +#define TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \ + SNDRV_CTL_TLVT_DB_MINMAX_MUTE, 2 * sizeof(unsigned int), \ + (min_dB), (max_dB) +#define DECLARE_TLV_DB_MINMAX(name, min_dB, max_dB) \ + unsigned int name[] = { TLV_DB_MINMAX_ITEM(min_dB, max_dB) } +#define DECLARE_TLV_DB_MINMAX_MUTE(name, min_dB, max_dB) \ + unsigned int name[] = { TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) } + /* linear volume between min_dB and max_dB (.01dB unit) */ #define TLV_DB_LINEAR_ITEM(min_dB, max_dB) \ SNDRV_CTL_TLVT_DB_LINEAR, 2 * sizeof(unsigned int), \ diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 257624b..3b9b550 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -353,7 +353,8 @@ static void master_free(struct snd_kcontrol *kcontrol) * * The optional argument @tlv can be used to specify the TLV information * for dB scale of the master control. It should be a single element - * with #SNDRV_CTL_TLVT_DB_SCALE type, and should be the max 0dB. + * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or + * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB. */ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, const unsigned int *tlv) @@ -384,7 +385,10 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, kctl->private_free = master_free; /* additional (constant) TLV read */ - if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) { + if (tlv && + (tlv[0] == SNDRV_CTL_TLVT_DB_SCALE || + tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX || + tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX_MUTE)) { kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; memcpy(master->tlv, tlv, sizeof(master->tlv)); kctl->tlv.p = master->tlv; -- cgit v0.10.2 From b8e1c73f4608b8b9ca1e8f1a09f9fd8684e78071 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Jun 2009 14:04:37 +0200 Subject: ALSA: usb-audio - Use the new TLV_DB_MINMAX type Use the new TLV_DB_MINMAX type instead of TLV_DB_SCALE. Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index ecb58e7..f127bfd 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -461,7 +461,7 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) { struct usb_mixer_elem_info *cval = kcontrol->private_data; - DECLARE_TLV_DB_SCALE(scale, 0, 0, 0); + DECLARE_TLV_DB_MINMAX(scale, 0, 0); if (size < sizeof(scale)) return -ENOMEM; @@ -469,7 +469,7 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, * while ALSA TLV contains in 1/100 dB unit */ scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; - scale[3] = (convert_signed_value(cval, cval->res) * 100) / 256; + scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256; if (copy_to_user(_tlv, scale, sizeof(scale))) return -EFAULT; return 0; -- cgit v0.10.2 From eedbdf03a25ab3b2c332ad7fa205aa8ffbe477ba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Jun 2009 14:27:35 +0200 Subject: ALSA: usb-audio - Correct bogus volume dB information Some USB devices give bogus dB information and it screws up PA. It's better to detect a broken value and correct it in the driver before exposing the value to the outside. Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index f127bfd..539b427 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -470,6 +470,15 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, */ scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256; + if (scale[3] <= scale[2]) { + /* something is wrong; assume it's either from/to 0dB */ + if (scale[2] < 0) + scale[3] = 0; + else if (scale[2] > 0) + scale[2] = 0; + else /* totally crap, return an error */ + return -EINVAL; + } if (copy_to_user(_tlv, scale, sizeof(scale))) return -EFAULT; return 0; -- cgit v0.10.2 From a583cd53478f0c55b92f084bdbe3b66d2b4496df Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 17 Jun 2009 17:30:14 +0100 Subject: ASoC: Regulator support for WM8580 Add basic support for integration with the regulator API to WM8580. Since the core cannot yet disable biases when the CODEC is idle we simply request and enable the regulators for the entire time the driver is active. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 261ef10..97b9ed9 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -24,6 +24,8 @@ #include #include #include +#include + #include #include #include @@ -187,15 +189,22 @@ struct pll_state { unsigned int out; }; +#define WM8580_NUM_SUPPLIES 3 +static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = { + "AVDD", + "DVDD", + "PVDD", +}; + /* codec private data */ struct wm8580_priv { struct snd_soc_codec codec; + struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES]; u16 reg_cache[WM8580_MAX_REGISTER + 1]; struct pll_state a; struct pll_state b; }; - /* * read wm8580 register cache */ @@ -922,11 +931,28 @@ static int wm8580_register(struct wm8580_priv *wm8580) memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg)); + for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++) + wm8580->supplies[i].supply = wm8580_supply_names[i]; + + ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8580->supplies), + wm8580->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + goto err; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies), + wm8580->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + goto err_regulator_get; + } + /* Get the codec into a known state */ ret = wm8580_write(codec, WM8580_RESET, 0); if (ret != 0) { dev_err(codec->dev, "Failed to reset codec: %d\n", ret); - goto err; + goto err_regulator_enable; } for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++) @@ -939,7 +965,7 @@ static int wm8580_register(struct wm8580_priv *wm8580) ret = snd_soc_register_codec(codec); if (ret != 0) { dev_err(codec->dev, "Failed to register codec: %d\n", ret); - goto err; + goto err_regulator_enable; } ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); @@ -952,6 +978,10 @@ static int wm8580_register(struct wm8580_priv *wm8580) err_codec: snd_soc_unregister_codec(codec); +err_regulator_enable: + regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); +err_regulator_get: + regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); err: kfree(wm8580); return ret; @@ -962,6 +992,8 @@ static void wm8580_unregister(struct wm8580_priv *wm8580) wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF); snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); snd_soc_unregister_codec(&wm8580->codec); + regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); + regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); kfree(wm8580); wm8580_codec = NULL; } -- cgit v0.10.2 From b9dc29e72fd3dc2a739ce8eafd958220d0745734 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Wed, 17 Jun 2009 10:46:01 +0200 Subject: sched: Clean up SCHED_RESET_ON_FORK Make SCHED_RESET_ON_FORK sched_fork() bits a self-contained unlikely code path. Signed-off-by: Mike Galbraith Acked-by: Lennart Poettering Cc: Peter Zijlstra LKML-Reference: <1245228361.18329.6.camel@marge.simson.net> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 32e6ede..50e4e3d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2613,28 +2613,30 @@ void sched_fork(struct task_struct *p, int clone_flags) set_task_cpu(p, cpu); /* - * Revert to default priority/policy on fork if requested. Make sure we - * do not leak PI boosting priority to the child. + * Make sure we do not leak PI boosting priority to the child. */ - if (current->sched_reset_on_fork && - (p->policy == SCHED_FIFO || p->policy == SCHED_RR)) - p->policy = SCHED_NORMAL; + p->prio = current->normal_prio; - if (current->sched_reset_on_fork && - (current->normal_prio < DEFAULT_PRIO)) - p->prio = DEFAULT_PRIO; - else - p->prio = current->normal_prio; + /* + * Revert to default priority/policy on fork if requested. + */ + if (unlikely(p->sched_reset_on_fork)) { + if (p->policy == SCHED_FIFO || p->policy == SCHED_RR) + p->policy = SCHED_NORMAL; + + if (p->normal_prio < DEFAULT_PRIO) + p->prio = DEFAULT_PRIO; + + /* + * We don't need the reset flag anymore after the fork. It has + * fulfilled its duty: + */ + p->sched_reset_on_fork = 0; + } if (!rt_prio(p->prio)) p->sched_class = &fair_sched_class; - /* - * We don't need the reset flag anymore after the fork. It has - * fulfilled its duty: - */ - p->sched_reset_on_fork = 0; - #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) if (likely(sched_info_on())) memset(&p->sched_info, 0, sizeof(p->sched_info)); -- cgit v0.10.2 From 6c697bdf08a09ce461e305a22362973036e95db3 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Wed, 17 Jun 2009 10:48:02 +0200 Subject: sched: Add SCHED_RESET_ON_FORK functionality for nice < 0 tasks Signed-off-by: Mike Galbraith Acked-by: Lennart Poettering Cc: Peter Zijlstra LKML-Reference: <1245228482.27326.1.camel@marge.simson.net> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 50e4e3d..34f9424 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2627,6 +2627,11 @@ void sched_fork(struct task_struct *p, int clone_flags) if (p->normal_prio < DEFAULT_PRIO) p->prio = DEFAULT_PRIO; + if (PRIO_TO_NICE(p->static_prio) < 0) { + p->static_prio = NICE_TO_PRIO(0); + set_load_weight(p); + } + /* * We don't need the reset flag anymore after the fork. It has * fulfilled its duty: -- cgit v0.10.2 From ac5672f82c39ff2f8dce81bf3e68b1dfc41f366f Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 14 Apr 2009 14:29:44 -0700 Subject: x86/paravirt: split paravirt definitions into paravirt_types.h Split the monolithic asm/paravirt.h into separate paravirt.h (inlines and other "active" definitions), and paravirt_types.h (types, constants and other "passive" definitions). This makes it easier to use the type/constant definitions without pulling in everything else and causing circular dependency problems. [ Impact: cleanup ] Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 4fb37c8..6a07af4 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -7,689 +7,11 @@ #include #include -/* Bitmask of what can be clobbered: usually at least eax. */ -#define CLBR_NONE 0 -#define CLBR_EAX (1 << 0) -#define CLBR_ECX (1 << 1) -#define CLBR_EDX (1 << 2) -#define CLBR_EDI (1 << 3) - -#ifdef CONFIG_X86_32 -/* CLBR_ANY should match all regs platform has. For i386, that's just it */ -#define CLBR_ANY ((1 << 4) - 1) - -#define CLBR_ARG_REGS (CLBR_EAX | CLBR_EDX | CLBR_ECX) -#define CLBR_RET_REG (CLBR_EAX | CLBR_EDX) -#define CLBR_SCRATCH (0) -#else -#define CLBR_RAX CLBR_EAX -#define CLBR_RCX CLBR_ECX -#define CLBR_RDX CLBR_EDX -#define CLBR_RDI CLBR_EDI -#define CLBR_RSI (1 << 4) -#define CLBR_R8 (1 << 5) -#define CLBR_R9 (1 << 6) -#define CLBR_R10 (1 << 7) -#define CLBR_R11 (1 << 8) - -#define CLBR_ANY ((1 << 9) - 1) - -#define CLBR_ARG_REGS (CLBR_RDI | CLBR_RSI | CLBR_RDX | \ - CLBR_RCX | CLBR_R8 | CLBR_R9) -#define CLBR_RET_REG (CLBR_RAX) -#define CLBR_SCRATCH (CLBR_R10 | CLBR_R11) - -#include -#endif /* X86_64 */ - -#define CLBR_CALLEE_SAVE ((CLBR_ARG_REGS | CLBR_SCRATCH) & ~CLBR_RET_REG) +#include #ifndef __ASSEMBLY__ #include #include -#include -#include - -struct page; -struct thread_struct; -struct desc_ptr; -struct tss_struct; -struct mm_struct; -struct desc_struct; -struct task_struct; - -/* - * Wrapper type for pointers to code which uses the non-standard - * calling convention. See PV_CALL_SAVE_REGS_THUNK below. - */ -struct paravirt_callee_save { - void *func; -}; - -/* general info */ -struct pv_info { - unsigned int kernel_rpl; - int shared_kernel_pmd; - int paravirt_enabled; - const char *name; -}; - -struct pv_init_ops { - /* - * Patch may replace one of the defined code sequences with - * arbitrary code, subject to the same register constraints. - * This generally means the code is not free to clobber any - * registers other than EAX. The patch function should return - * the number of bytes of code generated, as we nop pad the - * rest in generic code. - */ - unsigned (*patch)(u8 type, u16 clobber, void *insnbuf, - unsigned long addr, unsigned len); - - /* Basic arch-specific setup */ - void (*arch_setup)(void); - char *(*memory_setup)(void); - void (*post_allocator_init)(void); - - /* Print a banner to identify the environment */ - void (*banner)(void); -}; - - -struct pv_lazy_ops { - /* Set deferred update mode, used for batching operations. */ - void (*enter)(void); - void (*leave)(void); -}; - -struct pv_time_ops { - void (*time_init)(void); - - /* Set and set time of day */ - unsigned long (*get_wallclock)(void); - int (*set_wallclock)(unsigned long); - - unsigned long long (*sched_clock)(void); - unsigned long (*get_tsc_khz)(void); -}; - -struct pv_cpu_ops { - /* hooks for various privileged instructions */ - unsigned long (*get_debugreg)(int regno); - void (*set_debugreg)(int regno, unsigned long value); - - void (*clts)(void); - - unsigned long (*read_cr0)(void); - void (*write_cr0)(unsigned long); - - unsigned long (*read_cr4_safe)(void); - unsigned long (*read_cr4)(void); - void (*write_cr4)(unsigned long); - -#ifdef CONFIG_X86_64 - unsigned long (*read_cr8)(void); - void (*write_cr8)(unsigned long); -#endif - - /* Segment descriptor handling */ - void (*load_tr_desc)(void); - void (*load_gdt)(const struct desc_ptr *); - void (*load_idt)(const struct desc_ptr *); - void (*store_gdt)(struct desc_ptr *); - void (*store_idt)(struct desc_ptr *); - void (*set_ldt)(const void *desc, unsigned entries); - unsigned long (*store_tr)(void); - void (*load_tls)(struct thread_struct *t, unsigned int cpu); -#ifdef CONFIG_X86_64 - void (*load_gs_index)(unsigned int idx); -#endif - void (*write_ldt_entry)(struct desc_struct *ldt, int entrynum, - const void *desc); - void (*write_gdt_entry)(struct desc_struct *, - int entrynum, const void *desc, int size); - void (*write_idt_entry)(gate_desc *, - int entrynum, const gate_desc *gate); - void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries); - void (*free_ldt)(struct desc_struct *ldt, unsigned entries); - - void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t); - - void (*set_iopl_mask)(unsigned mask); - - void (*wbinvd)(void); - void (*io_delay)(void); - - /* cpuid emulation, mostly so that caps bits can be disabled */ - void (*cpuid)(unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx); - - /* MSR, PMC and TSR operations. - err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */ - u64 (*read_msr_amd)(unsigned int msr, int *err); - u64 (*read_msr)(unsigned int msr, int *err); - int (*write_msr)(unsigned int msr, unsigned low, unsigned high); - - u64 (*read_tsc)(void); - u64 (*read_pmc)(int counter); - unsigned long long (*read_tscp)(unsigned int *aux); - - /* - * Atomically enable interrupts and return to userspace. This - * is only ever used to return to 32-bit processes; in a - * 64-bit kernel, it's used for 32-on-64 compat processes, but - * never native 64-bit processes. (Jump, not call.) - */ - void (*irq_enable_sysexit)(void); - - /* - * Switch to usermode gs and return to 64-bit usermode using - * sysret. Only used in 64-bit kernels to return to 64-bit - * processes. Usermode register state, including %rsp, must - * already be restored. - */ - void (*usergs_sysret64)(void); - - /* - * Switch to usermode gs and return to 32-bit usermode using - * sysret. Used to return to 32-on-64 compat processes. - * Other usermode register state, including %esp, must already - * be restored. - */ - void (*usergs_sysret32)(void); - - /* Normal iret. Jump to this with the standard iret stack - frame set up. */ - void (*iret)(void); - - void (*swapgs)(void); - - void (*start_context_switch)(struct task_struct *prev); - void (*end_context_switch)(struct task_struct *next); -}; - -struct pv_irq_ops { - void (*init_IRQ)(void); - - /* - * Get/set interrupt state. save_fl and restore_fl are only - * expected to use X86_EFLAGS_IF; all other bits - * returned from save_fl are undefined, and may be ignored by - * restore_fl. - * - * NOTE: These functions callers expect the callee to preserve - * more registers than the standard C calling convention. - */ - struct paravirt_callee_save save_fl; - struct paravirt_callee_save restore_fl; - struct paravirt_callee_save irq_disable; - struct paravirt_callee_save irq_enable; - - void (*safe_halt)(void); - void (*halt)(void); - -#ifdef CONFIG_X86_64 - void (*adjust_exception_frame)(void); -#endif -}; - -struct pv_apic_ops { -#ifdef CONFIG_X86_LOCAL_APIC - void (*setup_boot_clock)(void); - void (*setup_secondary_clock)(void); - - void (*startup_ipi_hook)(int phys_apicid, - unsigned long start_eip, - unsigned long start_esp); -#endif -}; - -struct pv_mmu_ops { - /* - * Called before/after init_mm pagetable setup. setup_start - * may reset %cr3, and may pre-install parts of the pagetable; - * pagetable setup is expected to preserve any existing - * mapping. - */ - void (*pagetable_setup_start)(pgd_t *pgd_base); - void (*pagetable_setup_done)(pgd_t *pgd_base); - - unsigned long (*read_cr2)(void); - void (*write_cr2)(unsigned long); - - unsigned long (*read_cr3)(void); - void (*write_cr3)(unsigned long); - - /* - * Hooks for intercepting the creation/use/destruction of an - * mm_struct. - */ - void (*activate_mm)(struct mm_struct *prev, - struct mm_struct *next); - void (*dup_mmap)(struct mm_struct *oldmm, - struct mm_struct *mm); - void (*exit_mmap)(struct mm_struct *mm); - - - /* TLB operations */ - void (*flush_tlb_user)(void); - void (*flush_tlb_kernel)(void); - void (*flush_tlb_single)(unsigned long addr); - void (*flush_tlb_others)(const struct cpumask *cpus, - struct mm_struct *mm, - unsigned long va); - - /* Hooks for allocating and freeing a pagetable top-level */ - int (*pgd_alloc)(struct mm_struct *mm); - void (*pgd_free)(struct mm_struct *mm, pgd_t *pgd); - - /* - * Hooks for allocating/releasing pagetable pages when they're - * attached to a pagetable - */ - void (*alloc_pte)(struct mm_struct *mm, unsigned long pfn); - void (*alloc_pmd)(struct mm_struct *mm, unsigned long pfn); - void (*alloc_pmd_clone)(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count); - void (*alloc_pud)(struct mm_struct *mm, unsigned long pfn); - void (*release_pte)(unsigned long pfn); - void (*release_pmd)(unsigned long pfn); - void (*release_pud)(unsigned long pfn); - - /* Pagetable manipulation functions */ - void (*set_pte)(pte_t *ptep, pte_t pteval); - void (*set_pte_at)(struct mm_struct *mm, unsigned long addr, - pte_t *ptep, pte_t pteval); - void (*set_pmd)(pmd_t *pmdp, pmd_t pmdval); - void (*pte_update)(struct mm_struct *mm, unsigned long addr, - pte_t *ptep); - void (*pte_update_defer)(struct mm_struct *mm, - unsigned long addr, pte_t *ptep); - - pte_t (*ptep_modify_prot_start)(struct mm_struct *mm, unsigned long addr, - pte_t *ptep); - void (*ptep_modify_prot_commit)(struct mm_struct *mm, unsigned long addr, - pte_t *ptep, pte_t pte); - - struct paravirt_callee_save pte_val; - struct paravirt_callee_save make_pte; - - struct paravirt_callee_save pgd_val; - struct paravirt_callee_save make_pgd; - -#if PAGETABLE_LEVELS >= 3 -#ifdef CONFIG_X86_PAE - void (*set_pte_atomic)(pte_t *ptep, pte_t pteval); - void (*pte_clear)(struct mm_struct *mm, unsigned long addr, - pte_t *ptep); - void (*pmd_clear)(pmd_t *pmdp); - -#endif /* CONFIG_X86_PAE */ - - void (*set_pud)(pud_t *pudp, pud_t pudval); - - struct paravirt_callee_save pmd_val; - struct paravirt_callee_save make_pmd; - -#if PAGETABLE_LEVELS == 4 - struct paravirt_callee_save pud_val; - struct paravirt_callee_save make_pud; - - void (*set_pgd)(pgd_t *pudp, pgd_t pgdval); -#endif /* PAGETABLE_LEVELS == 4 */ -#endif /* PAGETABLE_LEVELS >= 3 */ - -#ifdef CONFIG_HIGHPTE - void *(*kmap_atomic_pte)(struct page *page, enum km_type type); -#endif - - struct pv_lazy_ops lazy_mode; - - /* dom0 ops */ - - /* Sometimes the physical address is a pfn, and sometimes its - an mfn. We can tell which is which from the index. */ - void (*set_fixmap)(unsigned /* enum fixed_addresses */ idx, - phys_addr_t phys, pgprot_t flags); -}; - -struct raw_spinlock; -struct pv_lock_ops { - int (*spin_is_locked)(struct raw_spinlock *lock); - int (*spin_is_contended)(struct raw_spinlock *lock); - void (*spin_lock)(struct raw_spinlock *lock); - void (*spin_lock_flags)(struct raw_spinlock *lock, unsigned long flags); - int (*spin_trylock)(struct raw_spinlock *lock); - void (*spin_unlock)(struct raw_spinlock *lock); -}; - -/* This contains all the paravirt structures: we get a convenient - * number for each function using the offset which we use to indicate - * what to patch. */ -struct paravirt_patch_template { - struct pv_init_ops pv_init_ops; - struct pv_time_ops pv_time_ops; - struct pv_cpu_ops pv_cpu_ops; - struct pv_irq_ops pv_irq_ops; - struct pv_apic_ops pv_apic_ops; - struct pv_mmu_ops pv_mmu_ops; - struct pv_lock_ops pv_lock_ops; -}; - -extern struct pv_info pv_info; -extern struct pv_init_ops pv_init_ops; -extern struct pv_time_ops pv_time_ops; -extern struct pv_cpu_ops pv_cpu_ops; -extern struct pv_irq_ops pv_irq_ops; -extern struct pv_apic_ops pv_apic_ops; -extern struct pv_mmu_ops pv_mmu_ops; -extern struct pv_lock_ops pv_lock_ops; - -#define PARAVIRT_PATCH(x) \ - (offsetof(struct paravirt_patch_template, x) / sizeof(void *)) - -#define paravirt_type(op) \ - [paravirt_typenum] "i" (PARAVIRT_PATCH(op)), \ - [paravirt_opptr] "i" (&(op)) -#define paravirt_clobber(clobber) \ - [paravirt_clobber] "i" (clobber) - -/* - * Generate some code, and mark it as patchable by the - * apply_paravirt() alternate instruction patcher. - */ -#define _paravirt_alt(insn_string, type, clobber) \ - "771:\n\t" insn_string "\n" "772:\n" \ - ".pushsection .parainstructions,\"a\"\n" \ - _ASM_ALIGN "\n" \ - _ASM_PTR " 771b\n" \ - " .byte " type "\n" \ - " .byte 772b-771b\n" \ - " .short " clobber "\n" \ - ".popsection\n" - -/* Generate patchable code, with the default asm parameters. */ -#define paravirt_alt(insn_string) \ - _paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]") - -/* Simple instruction patching code. */ -#define DEF_NATIVE(ops, name, code) \ - extern const char start_##ops##_##name[], end_##ops##_##name[]; \ - asm("start_" #ops "_" #name ": " code "; end_" #ops "_" #name ":") - -unsigned paravirt_patch_nop(void); -unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len); -unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len); -unsigned paravirt_patch_ignore(unsigned len); -unsigned paravirt_patch_call(void *insnbuf, - const void *target, u16 tgt_clobbers, - unsigned long addr, u16 site_clobbers, - unsigned len); -unsigned paravirt_patch_jmp(void *insnbuf, const void *target, - unsigned long addr, unsigned len); -unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf, - unsigned long addr, unsigned len); - -unsigned paravirt_patch_insns(void *insnbuf, unsigned len, - const char *start, const char *end); - -unsigned native_patch(u8 type, u16 clobbers, void *ibuf, - unsigned long addr, unsigned len); - -int paravirt_disable_iospace(void); - -/* - * This generates an indirect call based on the operation type number. - * The type number, computed in PARAVIRT_PATCH, is derived from the - * offset into the paravirt_patch_template structure, and can therefore be - * freely converted back into a structure offset. - */ -#define PARAVIRT_CALL "call *%c[paravirt_opptr];" - -/* - * These macros are intended to wrap calls through one of the paravirt - * ops structs, so that they can be later identified and patched at - * runtime. - * - * Normally, a call to a pv_op function is a simple indirect call: - * (pv_op_struct.operations)(args...). - * - * Unfortunately, this is a relatively slow operation for modern CPUs, - * because it cannot necessarily determine what the destination - * address is. In this case, the address is a runtime constant, so at - * the very least we can patch the call to e a simple direct call, or - * ideally, patch an inline implementation into the callsite. (Direct - * calls are essentially free, because the call and return addresses - * are completely predictable.) - * - * For i386, these macros rely on the standard gcc "regparm(3)" calling - * convention, in which the first three arguments are placed in %eax, - * %edx, %ecx (in that order), and the remaining arguments are placed - * on the stack. All caller-save registers (eax,edx,ecx) are expected - * to be modified (either clobbered or used for return values). - * X86_64, on the other hand, already specifies a register-based calling - * conventions, returning at %rax, with parameteres going on %rdi, %rsi, - * %rdx, and %rcx. Note that for this reason, x86_64 does not need any - * special handling for dealing with 4 arguments, unlike i386. - * However, x86_64 also have to clobber all caller saved registers, which - * unfortunately, are quite a bit (r8 - r11) - * - * The call instruction itself is marked by placing its start address - * and size into the .parainstructions section, so that - * apply_paravirt() in arch/i386/kernel/alternative.c can do the - * appropriate patching under the control of the backend pv_init_ops - * implementation. - * - * Unfortunately there's no way to get gcc to generate the args setup - * for the call, and then allow the call itself to be generated by an - * inline asm. Because of this, we must do the complete arg setup and - * return value handling from within these macros. This is fairly - * cumbersome. - * - * There are 5 sets of PVOP_* macros for dealing with 0-4 arguments. - * It could be extended to more arguments, but there would be little - * to be gained from that. For each number of arguments, there are - * the two VCALL and CALL variants for void and non-void functions. - * - * When there is a return value, the invoker of the macro must specify - * the return type. The macro then uses sizeof() on that type to - * determine whether its a 32 or 64 bit value, and places the return - * in the right register(s) (just %eax for 32-bit, and %edx:%eax for - * 64-bit). For x86_64 machines, it just returns at %rax regardless of - * the return value size. - * - * 64-bit arguments are passed as a pair of adjacent 32-bit arguments - * i386 also passes 64-bit arguments as a pair of adjacent 32-bit arguments - * in low,high order - * - * Small structures are passed and returned in registers. The macro - * calling convention can't directly deal with this, so the wrapper - * functions must do this. - * - * These PVOP_* macros are only defined within this header. This - * means that all uses must be wrapped in inline functions. This also - * makes sure the incoming and outgoing types are always correct. - */ -#ifdef CONFIG_X86_32 -#define PVOP_VCALL_ARGS \ - unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx -#define PVOP_CALL_ARGS PVOP_VCALL_ARGS - -#define PVOP_CALL_ARG1(x) "a" ((unsigned long)(x)) -#define PVOP_CALL_ARG2(x) "d" ((unsigned long)(x)) -#define PVOP_CALL_ARG3(x) "c" ((unsigned long)(x)) - -#define PVOP_VCALL_CLOBBERS "=a" (__eax), "=d" (__edx), \ - "=c" (__ecx) -#define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS - -#define PVOP_VCALLEE_CLOBBERS "=a" (__eax), "=d" (__edx) -#define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS - -#define EXTRA_CLOBBERS -#define VEXTRA_CLOBBERS -#else /* CONFIG_X86_64 */ -#define PVOP_VCALL_ARGS \ - unsigned long __edi = __edi, __esi = __esi, \ - __edx = __edx, __ecx = __ecx -#define PVOP_CALL_ARGS PVOP_VCALL_ARGS, __eax - -#define PVOP_CALL_ARG1(x) "D" ((unsigned long)(x)) -#define PVOP_CALL_ARG2(x) "S" ((unsigned long)(x)) -#define PVOP_CALL_ARG3(x) "d" ((unsigned long)(x)) -#define PVOP_CALL_ARG4(x) "c" ((unsigned long)(x)) - -#define PVOP_VCALL_CLOBBERS "=D" (__edi), \ - "=S" (__esi), "=d" (__edx), \ - "=c" (__ecx) -#define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS, "=a" (__eax) - -#define PVOP_VCALLEE_CLOBBERS "=a" (__eax) -#define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS - -#define EXTRA_CLOBBERS , "r8", "r9", "r10", "r11" -#define VEXTRA_CLOBBERS , "rax", "r8", "r9", "r10", "r11" -#endif /* CONFIG_X86_32 */ - -#ifdef CONFIG_PARAVIRT_DEBUG -#define PVOP_TEST_NULL(op) BUG_ON(op == NULL) -#else -#define PVOP_TEST_NULL(op) ((void)op) -#endif - -#define ____PVOP_CALL(rettype, op, clbr, call_clbr, extra_clbr, \ - pre, post, ...) \ - ({ \ - rettype __ret; \ - PVOP_CALL_ARGS; \ - PVOP_TEST_NULL(op); \ - /* This is 32-bit specific, but is okay in 64-bit */ \ - /* since this condition will never hold */ \ - if (sizeof(rettype) > sizeof(unsigned long)) { \ - asm volatile(pre \ - paravirt_alt(PARAVIRT_CALL) \ - post \ - : call_clbr \ - : paravirt_type(op), \ - paravirt_clobber(clbr), \ - ##__VA_ARGS__ \ - : "memory", "cc" extra_clbr); \ - __ret = (rettype)((((u64)__edx) << 32) | __eax); \ - } else { \ - asm volatile(pre \ - paravirt_alt(PARAVIRT_CALL) \ - post \ - : call_clbr \ - : paravirt_type(op), \ - paravirt_clobber(clbr), \ - ##__VA_ARGS__ \ - : "memory", "cc" extra_clbr); \ - __ret = (rettype)__eax; \ - } \ - __ret; \ - }) - -#define __PVOP_CALL(rettype, op, pre, post, ...) \ - ____PVOP_CALL(rettype, op, CLBR_ANY, PVOP_CALL_CLOBBERS, \ - EXTRA_CLOBBERS, pre, post, ##__VA_ARGS__) - -#define __PVOP_CALLEESAVE(rettype, op, pre, post, ...) \ - ____PVOP_CALL(rettype, op.func, CLBR_RET_REG, \ - PVOP_CALLEE_CLOBBERS, , \ - pre, post, ##__VA_ARGS__) - - -#define ____PVOP_VCALL(op, clbr, call_clbr, extra_clbr, pre, post, ...) \ - ({ \ - PVOP_VCALL_ARGS; \ - PVOP_TEST_NULL(op); \ - asm volatile(pre \ - paravirt_alt(PARAVIRT_CALL) \ - post \ - : call_clbr \ - : paravirt_type(op), \ - paravirt_clobber(clbr), \ - ##__VA_ARGS__ \ - : "memory", "cc" extra_clbr); \ - }) - -#define __PVOP_VCALL(op, pre, post, ...) \ - ____PVOP_VCALL(op, CLBR_ANY, PVOP_VCALL_CLOBBERS, \ - VEXTRA_CLOBBERS, \ - pre, post, ##__VA_ARGS__) - -#define __PVOP_VCALLEESAVE(rettype, op, pre, post, ...) \ - ____PVOP_CALL(rettype, op.func, CLBR_RET_REG, \ - PVOP_VCALLEE_CLOBBERS, , \ - pre, post, ##__VA_ARGS__) - - - -#define PVOP_CALL0(rettype, op) \ - __PVOP_CALL(rettype, op, "", "") -#define PVOP_VCALL0(op) \ - __PVOP_VCALL(op, "", "") - -#define PVOP_CALLEE0(rettype, op) \ - __PVOP_CALLEESAVE(rettype, op, "", "") -#define PVOP_VCALLEE0(op) \ - __PVOP_VCALLEESAVE(op, "", "") - - -#define PVOP_CALL1(rettype, op, arg1) \ - __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1)) -#define PVOP_VCALL1(op, arg1) \ - __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1)) - -#define PVOP_CALLEE1(rettype, op, arg1) \ - __PVOP_CALLEESAVE(rettype, op, "", "", PVOP_CALL_ARG1(arg1)) -#define PVOP_VCALLEE1(op, arg1) \ - __PVOP_VCALLEESAVE(op, "", "", PVOP_CALL_ARG1(arg1)) - - -#define PVOP_CALL2(rettype, op, arg1, arg2) \ - __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \ - PVOP_CALL_ARG2(arg2)) -#define PVOP_VCALL2(op, arg1, arg2) \ - __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1), \ - PVOP_CALL_ARG2(arg2)) - -#define PVOP_CALLEE2(rettype, op, arg1, arg2) \ - __PVOP_CALLEESAVE(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \ - PVOP_CALL_ARG2(arg2)) -#define PVOP_VCALLEE2(op, arg1, arg2) \ - __PVOP_VCALLEESAVE(op, "", "", PVOP_CALL_ARG1(arg1), \ - PVOP_CALL_ARG2(arg2)) - - -#define PVOP_CALL3(rettype, op, arg1, arg2, arg3) \ - __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \ - PVOP_CALL_ARG2(arg2), PVOP_CALL_ARG3(arg3)) -#define PVOP_VCALL3(op, arg1, arg2, arg3) \ - __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1), \ - PVOP_CALL_ARG2(arg2), PVOP_CALL_ARG3(arg3)) - -/* This is the only difference in x86_64. We can make it much simpler */ -#ifdef CONFIG_X86_32 -#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4) \ - __PVOP_CALL(rettype, op, \ - "push %[_arg4];", "lea 4(%%esp),%%esp;", \ - PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \ - PVOP_CALL_ARG3(arg3), [_arg4] "mr" ((u32)(arg4))) -#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4) \ - __PVOP_VCALL(op, \ - "push %[_arg4];", "lea 4(%%esp),%%esp;", \ - "0" ((u32)(arg1)), "1" ((u32)(arg2)), \ - "2" ((u32)(arg3)), [_arg4] "mr" ((u32)(arg4))) -#else -#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4) \ - __PVOP_CALL(rettype, op, "", "", \ - PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \ - PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4)) -#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4) \ - __PVOP_VCALL(op, "", "", \ - PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \ - PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4)) -#endif static inline int paravirt_enabled(void) { @@ -1393,20 +715,6 @@ static inline void pmd_clear(pmd_t *pmdp) } #endif /* CONFIG_X86_PAE */ -/* Lazy mode for batching updates / context switch */ -enum paravirt_lazy_mode { - PARAVIRT_LAZY_NONE, - PARAVIRT_LAZY_MMU, - PARAVIRT_LAZY_CPU, -}; - -enum paravirt_lazy_mode paravirt_get_lazy_mode(void); -void paravirt_start_context_switch(struct task_struct *prev); -void paravirt_end_context_switch(struct task_struct *next); - -void paravirt_enter_lazy_mmu(void); -void paravirt_leave_lazy_mmu(void); - #define __HAVE_ARCH_START_CONTEXT_SWITCH static inline void arch_start_context_switch(struct task_struct *prev) { @@ -1437,12 +745,6 @@ static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx, pv_mmu_ops.set_fixmap(idx, phys, flags); } -void _paravirt_nop(void); -u32 _paravirt_ident_32(u32); -u64 _paravirt_ident_64(u64); - -#define paravirt_nop ((void *)_paravirt_nop) - #if defined(CONFIG_SMP) && defined(CONFIG_PARAVIRT_SPINLOCKS) static inline int __raw_spin_is_locked(struct raw_spinlock *lock) @@ -1479,17 +781,6 @@ static __always_inline void __raw_spin_unlock(struct raw_spinlock *lock) #endif -/* These all sit in the .parainstructions section to tell us what to patch. */ -struct paravirt_patch_site { - u8 *instr; /* original instructions */ - u8 instrtype; /* type of this instruction */ - u8 len; /* length of original instruction */ - u16 clobbers; /* what registers you may clobber */ -}; - -extern struct paravirt_patch_site __parainstructions[], - __parainstructions_end[]; - #ifdef CONFIG_X86_32 #define PV_SAVE_REGS "pushl %ecx; pushl %edx;" #define PV_RESTORE_REGS "popl %edx; popl %ecx;" diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h new file mode 100644 index 0000000..2b3371b --- /dev/null +++ b/arch/x86/include/asm/paravirt_types.h @@ -0,0 +1,720 @@ +#ifndef _ASM_X86_PARAVIRT_TYPES_H +#define _ASM_X86_PARAVIRT_TYPES_H + +/* Bitmask of what can be clobbered: usually at least eax. */ +#define CLBR_NONE 0 +#define CLBR_EAX (1 << 0) +#define CLBR_ECX (1 << 1) +#define CLBR_EDX (1 << 2) +#define CLBR_EDI (1 << 3) + +#ifdef CONFIG_X86_32 +/* CLBR_ANY should match all regs platform has. For i386, that's just it */ +#define CLBR_ANY ((1 << 4) - 1) + +#define CLBR_ARG_REGS (CLBR_EAX | CLBR_EDX | CLBR_ECX) +#define CLBR_RET_REG (CLBR_EAX | CLBR_EDX) +#define CLBR_SCRATCH (0) +#else +#define CLBR_RAX CLBR_EAX +#define CLBR_RCX CLBR_ECX +#define CLBR_RDX CLBR_EDX +#define CLBR_RDI CLBR_EDI +#define CLBR_RSI (1 << 4) +#define CLBR_R8 (1 << 5) +#define CLBR_R9 (1 << 6) +#define CLBR_R10 (1 << 7) +#define CLBR_R11 (1 << 8) + +#define CLBR_ANY ((1 << 9) - 1) + +#define CLBR_ARG_REGS (CLBR_RDI | CLBR_RSI | CLBR_RDX | \ + CLBR_RCX | CLBR_R8 | CLBR_R9) +#define CLBR_RET_REG (CLBR_RAX) +#define CLBR_SCRATCH (CLBR_R10 | CLBR_R11) + +#endif /* X86_64 */ + +#define CLBR_CALLEE_SAVE ((CLBR_ARG_REGS | CLBR_SCRATCH) & ~CLBR_RET_REG) + +#ifndef __ASSEMBLY__ + +#include +#include + +struct page; +struct thread_struct; +struct desc_ptr; +struct tss_struct; +struct mm_struct; +struct desc_struct; +struct task_struct; +struct cpumask; + +/* + * Wrapper type for pointers to code which uses the non-standard + * calling convention. See PV_CALL_SAVE_REGS_THUNK below. + */ +struct paravirt_callee_save { + void *func; +}; + +/* general info */ +struct pv_info { + unsigned int kernel_rpl; + int shared_kernel_pmd; + int paravirt_enabled; + const char *name; +}; + +struct pv_init_ops { + /* + * Patch may replace one of the defined code sequences with + * arbitrary code, subject to the same register constraints. + * This generally means the code is not free to clobber any + * registers other than EAX. The patch function should return + * the number of bytes of code generated, as we nop pad the + * rest in generic code. + */ + unsigned (*patch)(u8 type, u16 clobber, void *insnbuf, + unsigned long addr, unsigned len); + + /* Basic arch-specific setup */ + void (*arch_setup)(void); + char *(*memory_setup)(void); + void (*post_allocator_init)(void); + + /* Print a banner to identify the environment */ + void (*banner)(void); +}; + + +struct pv_lazy_ops { + /* Set deferred update mode, used for batching operations. */ + void (*enter)(void); + void (*leave)(void); +}; + +struct pv_time_ops { + void (*time_init)(void); + + /* Set and set time of day */ + unsigned long (*get_wallclock)(void); + int (*set_wallclock)(unsigned long); + + unsigned long long (*sched_clock)(void); + unsigned long (*get_tsc_khz)(void); +}; + +struct pv_cpu_ops { + /* hooks for various privileged instructions */ + unsigned long (*get_debugreg)(int regno); + void (*set_debugreg)(int regno, unsigned long value); + + void (*clts)(void); + + unsigned long (*read_cr0)(void); + void (*write_cr0)(unsigned long); + + unsigned long (*read_cr4_safe)(void); + unsigned long (*read_cr4)(void); + void (*write_cr4)(unsigned long); + +#ifdef CONFIG_X86_64 + unsigned long (*read_cr8)(void); + void (*write_cr8)(unsigned long); +#endif + + /* Segment descriptor handling */ + void (*load_tr_desc)(void); + void (*load_gdt)(const struct desc_ptr *); + void (*load_idt)(const struct desc_ptr *); + void (*store_gdt)(struct desc_ptr *); + void (*store_idt)(struct desc_ptr *); + void (*set_ldt)(const void *desc, unsigned entries); + unsigned long (*store_tr)(void); + void (*load_tls)(struct thread_struct *t, unsigned int cpu); +#ifdef CONFIG_X86_64 + void (*load_gs_index)(unsigned int idx); +#endif + void (*write_ldt_entry)(struct desc_struct *ldt, int entrynum, + const void *desc); + void (*write_gdt_entry)(struct desc_struct *, + int entrynum, const void *desc, int size); + void (*write_idt_entry)(gate_desc *, + int entrynum, const gate_desc *gate); + void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries); + void (*free_ldt)(struct desc_struct *ldt, unsigned entries); + + void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t); + + void (*set_iopl_mask)(unsigned mask); + + void (*wbinvd)(void); + void (*io_delay)(void); + + /* cpuid emulation, mostly so that caps bits can be disabled */ + void (*cpuid)(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx); + + /* MSR, PMC and TSR operations. + err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */ + u64 (*read_msr_amd)(unsigned int msr, int *err); + u64 (*read_msr)(unsigned int msr, int *err); + int (*write_msr)(unsigned int msr, unsigned low, unsigned high); + + u64 (*read_tsc)(void); + u64 (*read_pmc)(int counter); + unsigned long long (*read_tscp)(unsigned int *aux); + + /* + * Atomically enable interrupts and return to userspace. This + * is only ever used to return to 32-bit processes; in a + * 64-bit kernel, it's used for 32-on-64 compat processes, but + * never native 64-bit processes. (Jump, not call.) + */ + void (*irq_enable_sysexit)(void); + + /* + * Switch to usermode gs and return to 64-bit usermode using + * sysret. Only used in 64-bit kernels to return to 64-bit + * processes. Usermode register state, including %rsp, must + * already be restored. + */ + void (*usergs_sysret64)(void); + + /* + * Switch to usermode gs and return to 32-bit usermode using + * sysret. Used to return to 32-on-64 compat processes. + * Other usermode register state, including %esp, must already + * be restored. + */ + void (*usergs_sysret32)(void); + + /* Normal iret. Jump to this with the standard iret stack + frame set up. */ + void (*iret)(void); + + void (*swapgs)(void); + + void (*start_context_switch)(struct task_struct *prev); + void (*end_context_switch)(struct task_struct *next); +}; + +struct pv_irq_ops { + void (*init_IRQ)(void); + + /* + * Get/set interrupt state. save_fl and restore_fl are only + * expected to use X86_EFLAGS_IF; all other bits + * returned from save_fl are undefined, and may be ignored by + * restore_fl. + * + * NOTE: These functions callers expect the callee to preserve + * more registers than the standard C calling convention. + */ + struct paravirt_callee_save save_fl; + struct paravirt_callee_save restore_fl; + struct paravirt_callee_save irq_disable; + struct paravirt_callee_save irq_enable; + + void (*safe_halt)(void); + void (*halt)(void); + +#ifdef CONFIG_X86_64 + void (*adjust_exception_frame)(void); +#endif +}; + +struct pv_apic_ops { +#ifdef CONFIG_X86_LOCAL_APIC + void (*setup_boot_clock)(void); + void (*setup_secondary_clock)(void); + + void (*startup_ipi_hook)(int phys_apicid, + unsigned long start_eip, + unsigned long start_esp); +#endif +}; + +struct pv_mmu_ops { + /* + * Called before/after init_mm pagetable setup. setup_start + * may reset %cr3, and may pre-install parts of the pagetable; + * pagetable setup is expected to preserve any existing + * mapping. + */ + void (*pagetable_setup_start)(pgd_t *pgd_base); + void (*pagetable_setup_done)(pgd_t *pgd_base); + + unsigned long (*read_cr2)(void); + void (*write_cr2)(unsigned long); + + unsigned long (*read_cr3)(void); + void (*write_cr3)(unsigned long); + + /* + * Hooks for intercepting the creation/use/destruction of an + * mm_struct. + */ + void (*activate_mm)(struct mm_struct *prev, + struct mm_struct *next); + void (*dup_mmap)(struct mm_struct *oldmm, + struct mm_struct *mm); + void (*exit_mmap)(struct mm_struct *mm); + + + /* TLB operations */ + void (*flush_tlb_user)(void); + void (*flush_tlb_kernel)(void); + void (*flush_tlb_single)(unsigned long addr); + void (*flush_tlb_others)(const struct cpumask *cpus, + struct mm_struct *mm, + unsigned long va); + + /* Hooks for allocating and freeing a pagetable top-level */ + int (*pgd_alloc)(struct mm_struct *mm); + void (*pgd_free)(struct mm_struct *mm, pgd_t *pgd); + + /* + * Hooks for allocating/releasing pagetable pages when they're + * attached to a pagetable + */ + void (*alloc_pte)(struct mm_struct *mm, unsigned long pfn); + void (*alloc_pmd)(struct mm_struct *mm, unsigned long pfn); + void (*alloc_pmd_clone)(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count); + void (*alloc_pud)(struct mm_struct *mm, unsigned long pfn); + void (*release_pte)(unsigned long pfn); + void (*release_pmd)(unsigned long pfn); + void (*release_pud)(unsigned long pfn); + + /* Pagetable manipulation functions */ + void (*set_pte)(pte_t *ptep, pte_t pteval); + void (*set_pte_at)(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval); + void (*set_pmd)(pmd_t *pmdp, pmd_t pmdval); + void (*pte_update)(struct mm_struct *mm, unsigned long addr, + pte_t *ptep); + void (*pte_update_defer)(struct mm_struct *mm, + unsigned long addr, pte_t *ptep); + + pte_t (*ptep_modify_prot_start)(struct mm_struct *mm, unsigned long addr, + pte_t *ptep); + void (*ptep_modify_prot_commit)(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte); + + struct paravirt_callee_save pte_val; + struct paravirt_callee_save make_pte; + + struct paravirt_callee_save pgd_val; + struct paravirt_callee_save make_pgd; + +#if PAGETABLE_LEVELS >= 3 +#ifdef CONFIG_X86_PAE + void (*set_pte_atomic)(pte_t *ptep, pte_t pteval); + void (*pte_clear)(struct mm_struct *mm, unsigned long addr, + pte_t *ptep); + void (*pmd_clear)(pmd_t *pmdp); + +#endif /* CONFIG_X86_PAE */ + + void (*set_pud)(pud_t *pudp, pud_t pudval); + + struct paravirt_callee_save pmd_val; + struct paravirt_callee_save make_pmd; + +#if PAGETABLE_LEVELS == 4 + struct paravirt_callee_save pud_val; + struct paravirt_callee_save make_pud; + + void (*set_pgd)(pgd_t *pudp, pgd_t pgdval); +#endif /* PAGETABLE_LEVELS == 4 */ +#endif /* PAGETABLE_LEVELS >= 3 */ + +#ifdef CONFIG_HIGHPTE + void *(*kmap_atomic_pte)(struct page *page, enum km_type type); +#endif + + struct pv_lazy_ops lazy_mode; + + /* dom0 ops */ + + /* Sometimes the physical address is a pfn, and sometimes its + an mfn. We can tell which is which from the index. */ + void (*set_fixmap)(unsigned /* enum fixed_addresses */ idx, + phys_addr_t phys, pgprot_t flags); +}; + +struct raw_spinlock; +struct pv_lock_ops { + int (*spin_is_locked)(struct raw_spinlock *lock); + int (*spin_is_contended)(struct raw_spinlock *lock); + void (*spin_lock)(struct raw_spinlock *lock); + void (*spin_lock_flags)(struct raw_spinlock *lock, unsigned long flags); + int (*spin_trylock)(struct raw_spinlock *lock); + void (*spin_unlock)(struct raw_spinlock *lock); +}; + +/* This contains all the paravirt structures: we get a convenient + * number for each function using the offset which we use to indicate + * what to patch. */ +struct paravirt_patch_template { + struct pv_init_ops pv_init_ops; + struct pv_time_ops pv_time_ops; + struct pv_cpu_ops pv_cpu_ops; + struct pv_irq_ops pv_irq_ops; + struct pv_apic_ops pv_apic_ops; + struct pv_mmu_ops pv_mmu_ops; + struct pv_lock_ops pv_lock_ops; +}; + +extern struct pv_info pv_info; +extern struct pv_init_ops pv_init_ops; +extern struct pv_time_ops pv_time_ops; +extern struct pv_cpu_ops pv_cpu_ops; +extern struct pv_irq_ops pv_irq_ops; +extern struct pv_apic_ops pv_apic_ops; +extern struct pv_mmu_ops pv_mmu_ops; +extern struct pv_lock_ops pv_lock_ops; + +#define PARAVIRT_PATCH(x) \ + (offsetof(struct paravirt_patch_template, x) / sizeof(void *)) + +#define paravirt_type(op) \ + [paravirt_typenum] "i" (PARAVIRT_PATCH(op)), \ + [paravirt_opptr] "i" (&(op)) +#define paravirt_clobber(clobber) \ + [paravirt_clobber] "i" (clobber) + +/* + * Generate some code, and mark it as patchable by the + * apply_paravirt() alternate instruction patcher. + */ +#define _paravirt_alt(insn_string, type, clobber) \ + "771:\n\t" insn_string "\n" "772:\n" \ + ".pushsection .parainstructions,\"a\"\n" \ + _ASM_ALIGN "\n" \ + _ASM_PTR " 771b\n" \ + " .byte " type "\n" \ + " .byte 772b-771b\n" \ + " .short " clobber "\n" \ + ".popsection\n" + +/* Generate patchable code, with the default asm parameters. */ +#define paravirt_alt(insn_string) \ + _paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]") + +/* Simple instruction patching code. */ +#define DEF_NATIVE(ops, name, code) \ + extern const char start_##ops##_##name[], end_##ops##_##name[]; \ + asm("start_" #ops "_" #name ": " code "; end_" #ops "_" #name ":") + +unsigned paravirt_patch_nop(void); +unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len); +unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len); +unsigned paravirt_patch_ignore(unsigned len); +unsigned paravirt_patch_call(void *insnbuf, + const void *target, u16 tgt_clobbers, + unsigned long addr, u16 site_clobbers, + unsigned len); +unsigned paravirt_patch_jmp(void *insnbuf, const void *target, + unsigned long addr, unsigned len); +unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf, + unsigned long addr, unsigned len); + +unsigned paravirt_patch_insns(void *insnbuf, unsigned len, + const char *start, const char *end); + +unsigned native_patch(u8 type, u16 clobbers, void *ibuf, + unsigned long addr, unsigned len); + +int paravirt_disable_iospace(void); + +/* + * This generates an indirect call based on the operation type number. + * The type number, computed in PARAVIRT_PATCH, is derived from the + * offset into the paravirt_patch_template structure, and can therefore be + * freely converted back into a structure offset. + */ +#define PARAVIRT_CALL "call *%c[paravirt_opptr];" + +/* + * These macros are intended to wrap calls through one of the paravirt + * ops structs, so that they can be later identified and patched at + * runtime. + * + * Normally, a call to a pv_op function is a simple indirect call: + * (pv_op_struct.operations)(args...). + * + * Unfortunately, this is a relatively slow operation for modern CPUs, + * because it cannot necessarily determine what the destination + * address is. In this case, the address is a runtime constant, so at + * the very least we can patch the call to e a simple direct call, or + * ideally, patch an inline implementation into the callsite. (Direct + * calls are essentially free, because the call and return addresses + * are completely predictable.) + * + * For i386, these macros rely on the standard gcc "regparm(3)" calling + * convention, in which the first three arguments are placed in %eax, + * %edx, %ecx (in that order), and the remaining arguments are placed + * on the stack. All caller-save registers (eax,edx,ecx) are expected + * to be modified (either clobbered or used for return values). + * X86_64, on the other hand, already specifies a register-based calling + * conventions, returning at %rax, with parameteres going on %rdi, %rsi, + * %rdx, and %rcx. Note that for this reason, x86_64 does not need any + * special handling for dealing with 4 arguments, unlike i386. + * However, x86_64 also have to clobber all caller saved registers, which + * unfortunately, are quite a bit (r8 - r11) + * + * The call instruction itself is marked by placing its start address + * and size into the .parainstructions section, so that + * apply_paravirt() in arch/i386/kernel/alternative.c can do the + * appropriate patching under the control of the backend pv_init_ops + * implementation. + * + * Unfortunately there's no way to get gcc to generate the args setup + * for the call, and then allow the call itself to be generated by an + * inline asm. Because of this, we must do the complete arg setup and + * return value handling from within these macros. This is fairly + * cumbersome. + * + * There are 5 sets of PVOP_* macros for dealing with 0-4 arguments. + * It could be extended to more arguments, but there would be little + * to be gained from that. For each number of arguments, there are + * the two VCALL and CALL variants for void and non-void functions. + * + * When there is a return value, the invoker of the macro must specify + * the return type. The macro then uses sizeof() on that type to + * determine whether its a 32 or 64 bit value, and places the return + * in the right register(s) (just %eax for 32-bit, and %edx:%eax for + * 64-bit). For x86_64 machines, it just returns at %rax regardless of + * the return value size. + * + * 64-bit arguments are passed as a pair of adjacent 32-bit arguments + * i386 also passes 64-bit arguments as a pair of adjacent 32-bit arguments + * in low,high order + * + * Small structures are passed and returned in registers. The macro + * calling convention can't directly deal with this, so the wrapper + * functions must do this. + * + * These PVOP_* macros are only defined within this header. This + * means that all uses must be wrapped in inline functions. This also + * makes sure the incoming and outgoing types are always correct. + */ +#ifdef CONFIG_X86_32 +#define PVOP_VCALL_ARGS \ + unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx +#define PVOP_CALL_ARGS PVOP_VCALL_ARGS + +#define PVOP_CALL_ARG1(x) "a" ((unsigned long)(x)) +#define PVOP_CALL_ARG2(x) "d" ((unsigned long)(x)) +#define PVOP_CALL_ARG3(x) "c" ((unsigned long)(x)) + +#define PVOP_VCALL_CLOBBERS "=a" (__eax), "=d" (__edx), \ + "=c" (__ecx) +#define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS + +#define PVOP_VCALLEE_CLOBBERS "=a" (__eax), "=d" (__edx) +#define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS + +#define EXTRA_CLOBBERS +#define VEXTRA_CLOBBERS +#else /* CONFIG_X86_64 */ +#define PVOP_VCALL_ARGS \ + unsigned long __edi = __edi, __esi = __esi, \ + __edx = __edx, __ecx = __ecx +#define PVOP_CALL_ARGS PVOP_VCALL_ARGS, __eax + +#define PVOP_CALL_ARG1(x) "D" ((unsigned long)(x)) +#define PVOP_CALL_ARG2(x) "S" ((unsigned long)(x)) +#define PVOP_CALL_ARG3(x) "d" ((unsigned long)(x)) +#define PVOP_CALL_ARG4(x) "c" ((unsigned long)(x)) + +#define PVOP_VCALL_CLOBBERS "=D" (__edi), \ + "=S" (__esi), "=d" (__edx), \ + "=c" (__ecx) +#define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS, "=a" (__eax) + +#define PVOP_VCALLEE_CLOBBERS "=a" (__eax) +#define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS + +#define EXTRA_CLOBBERS , "r8", "r9", "r10", "r11" +#define VEXTRA_CLOBBERS , "rax", "r8", "r9", "r10", "r11" +#endif /* CONFIG_X86_32 */ + +#ifdef CONFIG_PARAVIRT_DEBUG +#define PVOP_TEST_NULL(op) BUG_ON(op == NULL) +#else +#define PVOP_TEST_NULL(op) ((void)op) +#endif + +#define ____PVOP_CALL(rettype, op, clbr, call_clbr, extra_clbr, \ + pre, post, ...) \ + ({ \ + rettype __ret; \ + PVOP_CALL_ARGS; \ + PVOP_TEST_NULL(op); \ + /* This is 32-bit specific, but is okay in 64-bit */ \ + /* since this condition will never hold */ \ + if (sizeof(rettype) > sizeof(unsigned long)) { \ + asm volatile(pre \ + paravirt_alt(PARAVIRT_CALL) \ + post \ + : call_clbr \ + : paravirt_type(op), \ + paravirt_clobber(clbr), \ + ##__VA_ARGS__ \ + : "memory", "cc" extra_clbr); \ + __ret = (rettype)((((u64)__edx) << 32) | __eax); \ + } else { \ + asm volatile(pre \ + paravirt_alt(PARAVIRT_CALL) \ + post \ + : call_clbr \ + : paravirt_type(op), \ + paravirt_clobber(clbr), \ + ##__VA_ARGS__ \ + : "memory", "cc" extra_clbr); \ + __ret = (rettype)__eax; \ + } \ + __ret; \ + }) + +#define __PVOP_CALL(rettype, op, pre, post, ...) \ + ____PVOP_CALL(rettype, op, CLBR_ANY, PVOP_CALL_CLOBBERS, \ + EXTRA_CLOBBERS, pre, post, ##__VA_ARGS__) + +#define __PVOP_CALLEESAVE(rettype, op, pre, post, ...) \ + ____PVOP_CALL(rettype, op.func, CLBR_RET_REG, \ + PVOP_CALLEE_CLOBBERS, , \ + pre, post, ##__VA_ARGS__) + + +#define ____PVOP_VCALL(op, clbr, call_clbr, extra_clbr, pre, post, ...) \ + ({ \ + PVOP_VCALL_ARGS; \ + PVOP_TEST_NULL(op); \ + asm volatile(pre \ + paravirt_alt(PARAVIRT_CALL) \ + post \ + : call_clbr \ + : paravirt_type(op), \ + paravirt_clobber(clbr), \ + ##__VA_ARGS__ \ + : "memory", "cc" extra_clbr); \ + }) + +#define __PVOP_VCALL(op, pre, post, ...) \ + ____PVOP_VCALL(op, CLBR_ANY, PVOP_VCALL_CLOBBERS, \ + VEXTRA_CLOBBERS, \ + pre, post, ##__VA_ARGS__) + +#define __PVOP_VCALLEESAVE(rettype, op, pre, post, ...) \ + ____PVOP_CALL(rettype, op.func, CLBR_RET_REG, \ + PVOP_VCALLEE_CLOBBERS, , \ + pre, post, ##__VA_ARGS__) + + + +#define PVOP_CALL0(rettype, op) \ + __PVOP_CALL(rettype, op, "", "") +#define PVOP_VCALL0(op) \ + __PVOP_VCALL(op, "", "") + +#define PVOP_CALLEE0(rettype, op) \ + __PVOP_CALLEESAVE(rettype, op, "", "") +#define PVOP_VCALLEE0(op) \ + __PVOP_VCALLEESAVE(op, "", "") + + +#define PVOP_CALL1(rettype, op, arg1) \ + __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1)) +#define PVOP_VCALL1(op, arg1) \ + __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1)) + +#define PVOP_CALLEE1(rettype, op, arg1) \ + __PVOP_CALLEESAVE(rettype, op, "", "", PVOP_CALL_ARG1(arg1)) +#define PVOP_VCALLEE1(op, arg1) \ + __PVOP_VCALLEESAVE(op, "", "", PVOP_CALL_ARG1(arg1)) + + +#define PVOP_CALL2(rettype, op, arg1, arg2) \ + __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \ + PVOP_CALL_ARG2(arg2)) +#define PVOP_VCALL2(op, arg1, arg2) \ + __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1), \ + PVOP_CALL_ARG2(arg2)) + +#define PVOP_CALLEE2(rettype, op, arg1, arg2) \ + __PVOP_CALLEESAVE(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \ + PVOP_CALL_ARG2(arg2)) +#define PVOP_VCALLEE2(op, arg1, arg2) \ + __PVOP_VCALLEESAVE(op, "", "", PVOP_CALL_ARG1(arg1), \ + PVOP_CALL_ARG2(arg2)) + + +#define PVOP_CALL3(rettype, op, arg1, arg2, arg3) \ + __PVOP_CALL(rettype, op, "", "", PVOP_CALL_ARG1(arg1), \ + PVOP_CALL_ARG2(arg2), PVOP_CALL_ARG3(arg3)) +#define PVOP_VCALL3(op, arg1, arg2, arg3) \ + __PVOP_VCALL(op, "", "", PVOP_CALL_ARG1(arg1), \ + PVOP_CALL_ARG2(arg2), PVOP_CALL_ARG3(arg3)) + +/* This is the only difference in x86_64. We can make it much simpler */ +#ifdef CONFIG_X86_32 +#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4) \ + __PVOP_CALL(rettype, op, \ + "push %[_arg4];", "lea 4(%%esp),%%esp;", \ + PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \ + PVOP_CALL_ARG3(arg3), [_arg4] "mr" ((u32)(arg4))) +#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4) \ + __PVOP_VCALL(op, \ + "push %[_arg4];", "lea 4(%%esp),%%esp;", \ + "0" ((u32)(arg1)), "1" ((u32)(arg2)), \ + "2" ((u32)(arg3)), [_arg4] "mr" ((u32)(arg4))) +#else +#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4) \ + __PVOP_CALL(rettype, op, "", "", \ + PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \ + PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4)) +#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4) \ + __PVOP_VCALL(op, "", "", \ + PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \ + PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4)) +#endif + +/* Lazy mode for batching updates / context switch */ +enum paravirt_lazy_mode { + PARAVIRT_LAZY_NONE, + PARAVIRT_LAZY_MMU, + PARAVIRT_LAZY_CPU, +}; + +enum paravirt_lazy_mode paravirt_get_lazy_mode(void); +void paravirt_start_context_switch(struct task_struct *prev); +void paravirt_end_context_switch(struct task_struct *next); + +void paravirt_enter_lazy_mmu(void); +void paravirt_leave_lazy_mmu(void); + +void _paravirt_nop(void); +u32 _paravirt_ident_32(u32); +u64 _paravirt_ident_64(u64); + +#define paravirt_nop ((void *)_paravirt_nop) + +/* These all sit in the .parainstructions section to tell us what to patch. */ +struct paravirt_patch_site { + u8 *instr; /* original instructions */ + u8 instrtype; /* type of this instruction */ + u8 len; /* length of original instruction */ + u16 clobbers; /* what registers you may clobber */ +}; + +extern struct paravirt_patch_site __parainstructions[], + __parainstructions_end[]; + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_X86_PARAVIRT_TYPES_H */ -- cgit v0.10.2 From e6e9cac8c3417b43498b243c1f8f11780e157168 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 24 Apr 2009 00:40:59 -0700 Subject: x86: split out core __math_state_restore Split the core fpu state restoration out into __math_state_restore, which assumes that cr0.TS is clear and that the fpu context has been initialized. This will be used during context switch. There are two reasons this is desireable: - There's a small clarification. When __switch_to() calls math_state_restore, it relies on the fact that tsk_used_math() returns true, and so will never do a blocking init_fpu(). __math_state_restore() does not have (or need) that logic, so the question never arises. - It allows the clts() to be moved earler in __switch_to() so it can be performed while cpu context updates are batched (will be done in a later patch). [ Impact: refactor code to make reuse cleaner; no functional change ] Signed-off-by: Jeremy Fitzhardinge Cc: Alok Kataria Cc: Rusty Russell diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 175adf5..2e75292 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -26,6 +26,7 @@ extern void fpu_init(void); extern void mxcsr_feature_mask_init(void); extern int init_fpu(struct task_struct *child); extern asmlinkage void math_state_restore(void); +extern void __math_state_restore(void); extern void init_thread_xstate(void); extern int dump_fpu(struct pt_regs *, struct user_i387_struct *); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 5f935f0..71b9166 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -814,6 +814,28 @@ asmlinkage void __attribute__((weak)) smp_threshold_interrupt(void) } /* + * __math_state_restore assumes that cr0.TS is already clear and the + * fpu state is all ready for use. Used during context switch. + */ +void __math_state_restore(void) +{ + struct thread_info *thread = current_thread_info(); + struct task_struct *tsk = thread->task; + + /* + * Paranoid restore. send a SIGSEGV if we fail to restore the state. + */ + if (unlikely(restore_fpu_checking(tsk))) { + stts(); + force_sig(SIGSEGV, tsk); + return; + } + + thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ + tsk->fpu_counter++; +} + +/* * 'math_state_restore()' saves the current math information in the * old math state array, and gets the new ones from the current task * @@ -844,17 +866,8 @@ asmlinkage void math_state_restore(void) } clts(); /* Allow maths ops (or we recurse) */ - /* - * Paranoid restore. send a SIGSEGV if we fail to restore the state. - */ - if (unlikely(restore_fpu_checking(tsk))) { - stts(); - force_sig(SIGSEGV, tsk); - return; - } - thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ - tsk->fpu_counter++; + __math_state_restore(); } EXPORT_SYMBOL_GPL(math_state_restore); -- cgit v0.10.2 From 2fcddce10f6771cfa0c56fd1e826d50d67d100b7 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 24 Apr 2009 00:45:26 -0700 Subject: x86-32: make sure clts is batched during context switch If we're preloading the fpu state during context switch, make sure the clts happens while we're batching the cpu context update, then do the actual __math_state_restore once the updates are flushed. This allows more efficient context switches when running paravirtualized, as all the hypercalls can be folded together into one. [ Impact: optimise paravirtual FPU context switch ] Signed-off-by: Jeremy Fitzhardinge Cc: Alok Kataria Cc: Rusty Russell diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 59f4524..a80eddd 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -350,14 +350,21 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) *next = &next_p->thread; int cpu = smp_processor_id(); struct tss_struct *tss = &per_cpu(init_tss, cpu); + bool preload_fpu; /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ - __unlazy_fpu(prev_p); + /* + * If the task has used fpu the last 5 timeslices, just do a full + * restore of the math state immediately to avoid the trap; the + * chances of needing FPU soon are obviously high now + */ + preload_fpu = tsk_used_math(next_p) && next_p->fpu_counter > 5; + __unlazy_fpu(prev_p); /* we're going to use this soon, after a few expensive things */ - if (next_p->fpu_counter > 5) + if (preload_fpu) prefetch(next->xstate); /* @@ -398,6 +405,11 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT)) __switch_to_xtra(prev_p, next_p, tss); + /* If we're going to preload the fpu context, make sure clts + is run while we're batching the cpu state updates. */ + if (preload_fpu) + clts(); + /* * Leave lazy mode, flushing any hypercalls made here. * This must be done before restoring TLS segments so @@ -407,15 +419,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) */ arch_end_context_switch(next_p); - /* If the task has used fpu the last 5 timeslices, just do a full - * restore of the math state immediately to avoid the trap; the - * chances of needing FPU soon are obviously high now - * - * tsk_used_math() checks prevent calling math_state_restore(), - * which can sleep in the case of !tsk_used_math() - */ - if (tsk_used_math(next_p) && next_p->fpu_counter > 5) - math_state_restore(); + if (preload_fpu) + __math_state_restore(); /* * Restore %gs if needed (which is common) -- cgit v0.10.2 From 16d9dbf0c2bd167fdd942b83592d59696c7b73bd Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 24 Apr 2009 00:50:27 -0700 Subject: x86-64: move unlazy_fpu() into lazy cpu state part of context switch Make sure that unlazy_fpu()'s stts gets batched along with the other cpu state changes during context switch. (32-bit already does this.) This makes sure it gets batched when running paravirtualized. [ Impact: optimise paravirtual FPU context switch ] Signed-off-by: Jeremy Fitzhardinge Cc: Alok Kataria Cc: Rusty Russell diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index ebefb54..c9b8904 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -419,6 +419,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) load_TLS(next, cpu); + /* Must be after DS reload */ + unlazy_fpu(prev_p); + /* * Leave lazy mode, flushing any hypercalls made here. * This must be done before restoring TLS segments so @@ -459,9 +462,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) wrmsrl(MSR_KERNEL_GS_BASE, next->gs); prev->gsindex = gsindex; - /* Must be after DS reload */ - unlazy_fpu(prev_p); - /* * Switch the PDA and FPU contexts. */ -- cgit v0.10.2 From 17950c5b243f99cbabef173415ee988c52104d7e Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 24 Apr 2009 01:01:01 -0700 Subject: x86-64: move clts into batch cpu state updates when preloading fpu When a task is likely to be using the fpu, we preload its state during the context switch, rather than waiting for it to run an fpu instruction. Make sure the clts() happens while we're doing batched fpu state updates to optimise paravirtualized context switches. [ Impact: optimise paravirtual FPU context switch ] Signed-off-by: Jeremy Fitzhardinge Cc: Alok Kataria Cc: Rusty Russell diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index c9b8904..a28279d 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -386,9 +386,17 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) int cpu = smp_processor_id(); struct tss_struct *tss = &per_cpu(init_tss, cpu); unsigned fsindex, gsindex; + bool preload_fpu; + + /* + * If the task has used fpu the last 5 timeslices, just do a full + * restore of the math state immediately to avoid the trap; the + * chances of needing FPU soon are obviously high now + */ + preload_fpu = tsk_used_math(next_p) && next_p->fpu_counter > 5; /* we're going to use this soon, after a few expensive things */ - if (next_p->fpu_counter > 5) + if (preload_fpu) prefetch(next->xstate); /* @@ -422,6 +430,10 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) /* Must be after DS reload */ unlazy_fpu(prev_p); + /* Make sure cpu is ready for new context */ + if (preload_fpu) + clts(); + /* * Leave lazy mode, flushing any hypercalls made here. * This must be done before restoring TLS segments so @@ -480,15 +492,12 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV)) __switch_to_xtra(prev_p, next_p, tss); - /* If the task has used fpu the last 5 timeslices, just do a full - * restore of the math state immediately to avoid the trap; the - * chances of needing FPU soon are obviously high now - * - * tsk_used_math() checks prevent calling math_state_restore(), - * which can sleep in the case of !tsk_used_math() + /* + * Preload the FPU context, now that we've determined that the + * task is likely to be using it. */ - if (tsk_used_math(next_p) && next_p->fpu_counter > 5) - math_state_restore(); + if (preload_fpu) + __math_state_restore(); return prev_p; } -- cgit v0.10.2 From 5b739ef8a4e8cf5201d21abff897e292c232477b Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 18 Jun 2009 19:50:21 +0800 Subject: random: Add optional continuous repetition test to entropy store based rngs FIPS-140 requires that all random number generators implement continuous self tests in which each extracted block of data is compared against the last block for repetition. The ansi_cprng implements such a test, but it would be nice if the hw rng's did the same thing. Obviously its not something thats always needed, but it seems like it would be a nice feature to have on occasion. I've written the below patch which allows individual entropy stores to be flagged as desiring a continuous test to be run on them as is extracted. By default this option is off, but is enabled in the event that fips mode is selected during bootup. Signed-off-by: Neil Horman Acked-by: Matt Mackall Signed-off-by: Herbert Xu diff --git a/crypto/internal.h b/crypto/internal.h index 113579a..95baaea 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -25,12 +25,7 @@ #include #include #include - -#ifdef CONFIG_CRYPTO_FIPS -extern int fips_enabled; -#else -#define fips_enabled 0 -#endif +#include /* Crypto notification events. */ enum { diff --git a/drivers/char/random.c b/drivers/char/random.c index 8c74448..d8a9255 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -240,6 +240,7 @@ #include #include #include +#include #ifdef CONFIG_GENERIC_HARDIRQS # include @@ -413,6 +414,7 @@ struct entropy_store { unsigned add_ptr; int entropy_count; int input_rotate; + __u8 *last_data; }; static __u32 input_pool_data[INPUT_POOL_WORDS]; @@ -852,12 +854,21 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, { ssize_t ret = 0, i; __u8 tmp[EXTRACT_SIZE]; + unsigned long flags; xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, min, reserved); while (nbytes) { extract_buf(r, tmp); + + if (r->last_data) { + spin_lock_irqsave(&r->lock, flags); + if (!memcmp(tmp, r->last_data, EXTRACT_SIZE)) + panic("Hardware RNG duplicated output!\n"); + memcpy(r->last_data, tmp, EXTRACT_SIZE); + spin_unlock_irqrestore(&r->lock, flags); + } i = min_t(int, nbytes, EXTRACT_SIZE); memcpy(buf, tmp, i); nbytes -= i; @@ -940,6 +951,9 @@ static void init_std_data(struct entropy_store *r) now = ktime_get_real(); mix_pool_bytes(r, &now, sizeof(now)); mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); + /* Enable continuous test in fips mode */ + if (fips_enabled) + r->last_data = kmalloc(EXTRACT_SIZE, GFP_KERNEL); } static int rand_initialize(void) diff --git a/include/linux/fips.h b/include/linux/fips.h new file mode 100644 index 0000000..f8fb07b --- /dev/null +++ b/include/linux/fips.h @@ -0,0 +1,10 @@ +#ifndef _FIPS_H +#define _FIPS_H + +#ifdef CONFIG_CRYPTO_FIPS +extern int fips_enabled; +#else +#define fips_enabled 0 +#endif + +#endif -- cgit v0.10.2 From 03b56ce54143a3a69d4fea6ff8130b1c903a47ce Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 18 Jun 2009 19:52:59 +0800 Subject: crypto: des_s390 - Permit weak keys unless REQ_WEAK_KEY set Just started running fips cavs test vectors through an s390x system for giggles, and discovered that I missed patching s390's arch-specific des3 implementation w/an earlier des3 patch to permit weak keys. This change adds the same flag tweaks as ad79cdd77fc1466e45cf923890f66bcfe7c43f12 (crypto: des3_ede - permit weak keys unless REQ_WEAK_KEY set) for s390's des3 implementation, yields expected test results now. Signed-off-by: Jarod Wilson Signed-off-by: Herbert Xu diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index 4aba83b..2bc479a 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -250,8 +250,9 @@ static int des3_128_setkey(struct crypto_tfm *tfm, const u8 *key, const u8 *temp_key = key; u32 *flags = &tfm->crt_flags; - if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE))) { - *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED; + if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE)) && + (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) { + *flags |= CRYPTO_TFM_RES_WEAK_KEY; return -EINVAL; } for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) { @@ -411,9 +412,9 @@ static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key, if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) && memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2], - DES_KEY_SIZE))) { - - *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED; + DES_KEY_SIZE)) && + (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) { + *flags |= CRYPTO_TFM_RES_WEAK_KEY; return -EINVAL; } for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) { -- cgit v0.10.2 From caabbdc07df4249f2ed516b2c3e2d6b0973bcbb3 Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Thu, 18 Jun 2009 17:30:07 +0900 Subject: cleanup in ss/services.c It is a cleanup patch to cut down a line within 80 columns. Signed-off-by: KaiGai Kohei -- security/selinux/ss/services.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) Signed-off-by: James Morris diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index deeec6c..cad5765 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -479,7 +479,7 @@ static int context_struct_compute_av(struct context *scontext, if ((constraint->permissions & (avd->allowed)) && !constraint_expr_eval(scontext, tcontext, NULL, constraint->expr)) { - avd->allowed = (avd->allowed) & ~(constraint->permissions); + avd->allowed &= ~(constraint->permissions); } constraint = constraint->next; } @@ -498,8 +498,8 @@ static int context_struct_compute_av(struct context *scontext, break; } if (!ra) - avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION | - PROCESS__DYNTRANSITION); + avd->allowed &= ~(PROCESS__TRANSITION | + PROCESS__DYNTRANSITION); } /* -- cgit v0.10.2 From 44c2d9bdd7022ca7d240d5adc009296fc1c6ce08 Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Thu, 18 Jun 2009 17:26:13 +0900 Subject: Add audit messages on type boundary violations The attached patch adds support to generate audit messages on two cases. The first one is a case when a multi-thread process tries to switch its performing security context using setcon(3), but new security context is not bounded by the old one. type=SELINUX_ERR msg=audit(1245311998.599:17): \ op=security_bounded_transition result=denied \ oldcontext=system_u:system_r:httpd_t:s0 \ newcontext=system_u:system_r:guest_webapp_t:s0 The other one is a case when security_compute_av() masked any permissions due to the type boundary violation. type=SELINUX_ERR msg=audit(1245312836.035:32): \ op=security_compute_av reason=bounds \ scontext=system_u:object_r:user_webapp_t:s0 \ tcontext=system_u:object_r:shadow_t:s0:c0 \ tclass=file perms=getattr,open Signed-off-by: KaiGai Kohei Acked-by: Stephen Smalley Signed-off-by: James Morris diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 7f9b5fa..4bf5d08 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -137,7 +137,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) * @tclass: target security class * @av: access vector */ -void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) +static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) { const char **common_pts = NULL; u32 common_base = 0; diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index d12ff1a..46a940d 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -127,9 +127,6 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, u32 events, u32 ssid, u32 tsid, u16 tclass, u32 perms); -/* Shows permission in human readable form */ -void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av); - /* Exported to selinuxfs */ int avc_get_hash_stats(char *page); extern unsigned int avc_cache_threshold; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index cad5765..a90cab2 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -22,6 +22,11 @@ * * Added validation of kernel classes and permissions * + * Updated: KaiGai Kohei + * + * Added support for bounds domain and audit messaged on masked permissions + * + * Copyright (C) 2008, 2009 NEC Corporation * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC @@ -279,6 +284,95 @@ mls_ops: } /* + * security_dump_masked_av - dumps masked permissions during + * security_compute_av due to RBAC, MLS/Constraint and Type bounds. + */ +static int dump_masked_av_helper(void *k, void *d, void *args) +{ + struct perm_datum *pdatum = d; + char **permission_names = args; + + BUG_ON(pdatum->value < 1 || pdatum->value > 32); + + permission_names[pdatum->value - 1] = (char *)k; + + return 0; +} + +static void security_dump_masked_av(struct context *scontext, + struct context *tcontext, + u16 tclass, + u32 permissions, + const char *reason) +{ + struct common_datum *common_dat; + struct class_datum *tclass_dat; + struct audit_buffer *ab; + char *tclass_name; + char *scontext_name = NULL; + char *tcontext_name = NULL; + char *permission_names[32]; + int index, length; + bool need_comma = false; + + if (!permissions) + return; + + tclass_name = policydb.p_class_val_to_name[tclass - 1]; + tclass_dat = policydb.class_val_to_struct[tclass - 1]; + common_dat = tclass_dat->comdatum; + + /* init permission_names */ + if (common_dat && + hashtab_map(common_dat->permissions.table, + dump_masked_av_helper, permission_names) < 0) + goto out; + + if (hashtab_map(tclass_dat->permissions.table, + dump_masked_av_helper, permission_names) < 0) + goto out; + + /* get scontext/tcontext in text form */ + if (context_struct_to_string(scontext, + &scontext_name, &length) < 0) + goto out; + + if (context_struct_to_string(tcontext, + &tcontext_name, &length) < 0) + goto out; + + /* audit a message */ + ab = audit_log_start(current->audit_context, + GFP_ATOMIC, AUDIT_SELINUX_ERR); + if (!ab) + goto out; + + audit_log_format(ab, "op=security_compute_av reason=%s " + "scontext=%s tcontext=%s tclass=%s perms=", + reason, scontext_name, tcontext_name, tclass_name); + + for (index = 0; index < 32; index++) { + u32 mask = (1 << index); + + if ((mask & permissions) == 0) + continue; + + audit_log_format(ab, "%s%s", + need_comma ? "," : "", + permission_names[index] + ? permission_names[index] : "????"); + need_comma = true; + } + audit_log_end(ab); +out: + /* release scontext/tcontext */ + kfree(tcontext_name); + kfree(scontext_name); + + return; +} + +/* * security_boundary_permission - drops violated permissions * on boundary constraint. */ @@ -347,28 +441,12 @@ static void type_attribute_bounds_av(struct context *scontext, } if (masked) { - struct audit_buffer *ab; - char *stype_name - = policydb.p_type_val_to_name[source->value - 1]; - char *ttype_name - = policydb.p_type_val_to_name[target->value - 1]; - char *tclass_name - = policydb.p_class_val_to_name[tclass - 1]; - /* mask violated permissions */ avd->allowed &= ~masked; - /* notice to userspace via audit message */ - ab = audit_log_start(current->audit_context, - GFP_ATOMIC, AUDIT_SELINUX_ERR); - if (!ab) - return; - - audit_log_format(ab, "av boundary violation: " - "source=%s target=%s tclass=%s", - stype_name, ttype_name, tclass_name); - avc_dump_av(ab, tclass, masked); - audit_log_end(ab); + /* audit masked permissions */ + security_dump_masked_av(scontext, tcontext, + tclass, masked, "bounds"); } } @@ -711,6 +789,26 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) } index = type->bounds; } + + if (rc) { + char *old_name = NULL; + char *new_name = NULL; + int length; + + if (!context_struct_to_string(old_context, + &old_name, &length) && + !context_struct_to_string(new_context, + &new_name, &length)) { + audit_log(current->audit_context, + GFP_ATOMIC, AUDIT_SELINUX_ERR, + "op=security_bounded_transition " + "result=denied " + "oldcontext=%s newcontext=%s", + old_name, new_name); + } + kfree(new_name); + kfree(old_name); + } out: read_unlock(&policy_rwlock); -- cgit v0.10.2 From 21e70878215f620fe99ea7d7c74bc641aeec932f Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Thu, 18 Jun 2009 17:09:27 +0530 Subject: x86: oprofile/op_model_amd.c set return values for op_amd_handle_ibs() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit op_amd_handle_ibs() should return 0 when IBS is not present or not defined. Fix compilation warning: CC [M] arch/x86/oprofile/op_model_amd.o arch/x86/oprofile/op_model_amd.c: In function ‘op_amd_handle_ibs’: arch/x86/oprofile/op_model_amd.c:217: warning: no return statement in function returning non-void Signed-off-by: Jaswinder Singh Rajput Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index cc93046..e95268e 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -132,7 +132,7 @@ op_amd_handle_ibs(struct pt_regs * const regs, struct op_entry entry; if (!has_ibs) - return 1; + return 0; if (ibs_config.fetch_enabled) { rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl); @@ -214,7 +214,10 @@ static void op_amd_stop_ibs(void) #else static inline int op_amd_handle_ibs(struct pt_regs * const regs, - struct op_msrs const * const msrs) { } + struct op_msrs const * const msrs) +{ + return 0; +} static inline void op_amd_start_ibs(void) { } static inline void op_amd_stop_ibs(void) { } -- cgit v0.10.2 From 4adc667593f83a18a8e54ce94f250fd166a272ac Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Jun 2009 21:48:16 +0200 Subject: x86: add copies of some headers to convert to asm-generic Just an intermediate step to make reviewing easier. These files are identical copies of the existing headers. Signed-off-by: Arnd Bergmann LKML-Reference: Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/generic-mman.h b/arch/x86/include/asm/generic-mman.h new file mode 100644 index 0000000..751af25 --- /dev/null +++ b/arch/x86/include/asm/generic-mman.h @@ -0,0 +1,20 @@ +#ifndef _ASM_X86_MMAN_H +#define _ASM_X86_MMAN_H + +#include + +#define MAP_32BIT 0x40 /* only give out 32bit addresses */ + +#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ +#define MAP_LOCKED 0x2000 /* pages are locked */ +#define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ +#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */ + +#define MCL_CURRENT 1 /* lock all current mappings */ +#define MCL_FUTURE 2 /* lock all future mappings */ + +#endif /* _ASM_X86_MMAN_H */ diff --git a/arch/x86/include/asm/generic-module.h b/arch/x86/include/asm/generic-module.h new file mode 100644 index 0000000..47d6274 --- /dev/null +++ b/arch/x86/include/asm/generic-module.h @@ -0,0 +1,80 @@ +#ifndef _ASM_X86_MODULE_H +#define _ASM_X86_MODULE_H + +/* x86_32/64 are simple */ +struct mod_arch_specific {}; + +#ifdef CONFIG_X86_32 +# define Elf_Shdr Elf32_Shdr +# define Elf_Sym Elf32_Sym +# define Elf_Ehdr Elf32_Ehdr +#else +# define Elf_Shdr Elf64_Shdr +# define Elf_Sym Elf64_Sym +# define Elf_Ehdr Elf64_Ehdr +#endif + +#ifdef CONFIG_X86_64 +/* X86_64 does not define MODULE_PROC_FAMILY */ +#elif defined CONFIG_M386 +#define MODULE_PROC_FAMILY "386 " +#elif defined CONFIG_M486 +#define MODULE_PROC_FAMILY "486 " +#elif defined CONFIG_M586 +#define MODULE_PROC_FAMILY "586 " +#elif defined CONFIG_M586TSC +#define MODULE_PROC_FAMILY "586TSC " +#elif defined CONFIG_M586MMX +#define MODULE_PROC_FAMILY "586MMX " +#elif defined CONFIG_MCORE2 +#define MODULE_PROC_FAMILY "CORE2 " +#elif defined CONFIG_M686 +#define MODULE_PROC_FAMILY "686 " +#elif defined CONFIG_MPENTIUMII +#define MODULE_PROC_FAMILY "PENTIUMII " +#elif defined CONFIG_MPENTIUMIII +#define MODULE_PROC_FAMILY "PENTIUMIII " +#elif defined CONFIG_MPENTIUMM +#define MODULE_PROC_FAMILY "PENTIUMM " +#elif defined CONFIG_MPENTIUM4 +#define MODULE_PROC_FAMILY "PENTIUM4 " +#elif defined CONFIG_MK6 +#define MODULE_PROC_FAMILY "K6 " +#elif defined CONFIG_MK7 +#define MODULE_PROC_FAMILY "K7 " +#elif defined CONFIG_MK8 +#define MODULE_PROC_FAMILY "K8 " +#elif defined CONFIG_X86_ELAN +#define MODULE_PROC_FAMILY "ELAN " +#elif defined CONFIG_MCRUSOE +#define MODULE_PROC_FAMILY "CRUSOE " +#elif defined CONFIG_MEFFICEON +#define MODULE_PROC_FAMILY "EFFICEON " +#elif defined CONFIG_MWINCHIPC6 +#define MODULE_PROC_FAMILY "WINCHIPC6 " +#elif defined CONFIG_MWINCHIP3D +#define MODULE_PROC_FAMILY "WINCHIP3D " +#elif defined CONFIG_MCYRIXIII +#define MODULE_PROC_FAMILY "CYRIXIII " +#elif defined CONFIG_MVIAC3_2 +#define MODULE_PROC_FAMILY "VIAC3-2 " +#elif defined CONFIG_MVIAC7 +#define MODULE_PROC_FAMILY "VIAC7 " +#elif defined CONFIG_MGEODEGX1 +#define MODULE_PROC_FAMILY "GEODEGX1 " +#elif defined CONFIG_MGEODE_LX +#define MODULE_PROC_FAMILY "GEODE " +#else +#error unknown processor family +#endif + +#ifdef CONFIG_X86_32 +# ifdef CONFIG_4KSTACKS +# define MODULE_STACKSIZE "4KSTACKS " +# else +# define MODULE_STACKSIZE "" +# endif +# define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_STACKSIZE +#endif + +#endif /* _ASM_X86_MODULE_H */ diff --git a/arch/x86/include/asm/generic-scatterlist.h b/arch/x86/include/asm/generic-scatterlist.h new file mode 100644 index 0000000..263d397 --- /dev/null +++ b/arch/x86/include/asm/generic-scatterlist.h @@ -0,0 +1,33 @@ +#ifndef _ASM_X86_SCATTERLIST_H +#define _ASM_X86_SCATTERLIST_H + +#include + +struct scatterlist { +#ifdef CONFIG_DEBUG_SG + unsigned long sg_magic; +#endif + unsigned long page_link; + unsigned int offset; + unsigned int length; + dma_addr_t dma_address; + unsigned int dma_length; +}; + +#define ARCH_HAS_SG_CHAIN +#define ISA_DMA_THRESHOLD (0x00ffffff) + +/* + * These macros should be used after a pci_map_sg call has been done + * to get bus addresses of each of the SG entries and their lengths. + * You should only work with the number of sg entries pci_map_sg + * returns. + */ +#define sg_dma_address(sg) ((sg)->dma_address) +#ifdef CONFIG_X86_32 +# define sg_dma_len(sg) ((sg)->length) +#else +# define sg_dma_len(sg) ((sg)->dma_length) +#endif + +#endif /* _ASM_X86_SCATTERLIST_H */ diff --git a/arch/x86/include/asm/generic-types.h b/arch/x86/include/asm/generic-types.h new file mode 100644 index 0000000..09b9774 --- /dev/null +++ b/arch/x86/include/asm/generic-types.h @@ -0,0 +1,30 @@ +#ifndef _ASM_X86_TYPES_H +#define _ASM_X86_TYPES_H + +#include + +#ifndef __ASSEMBLY__ + +typedef unsigned short umode_t; + +#endif /* __ASSEMBLY__ */ + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +typedef u64 dma64_addr_t; +#if defined(CONFIG_X86_64) || defined(CONFIG_HIGHMEM64G) +/* DMA addresses come in 32-bit and 64-bit flavours. */ +typedef u64 dma_addr_t; +#else +typedef u32 dma_addr_t; +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ + +#endif /* _ASM_X86_TYPES_H */ diff --git a/arch/x86/include/asm/generic-ucontext.h b/arch/x86/include/asm/generic-ucontext.h new file mode 100644 index 0000000..87324cf --- /dev/null +++ b/arch/x86/include/asm/generic-ucontext.h @@ -0,0 +1,18 @@ +#ifndef _ASM_X86_UCONTEXT_H +#define _ASM_X86_UCONTEXT_H + +#define UC_FP_XSTATE 0x1 /* indicates the presence of extended state + * information in the memory layout pointed + * by the fpstate pointer in the ucontext's + * sigcontext struct (uc_mcontext). + */ + +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +#endif /* _ASM_X86_UCONTEXT_H */ -- cgit v0.10.2 From 7bfd124d6dae7d394e73753300594a81a022fe7d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Jun 2009 21:48:17 +0200 Subject: x86: convert trivial headers to asm-generic version For these nine header files, the asm-generic version should be semantically identical to what is in x86. Change the contents to be binary identical, for better review. Signed-off-by: Arnd Bergmann LKML-Reference: Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/ioctls.h b/arch/x86/include/asm/ioctls.h index 0d5b23b..a799e20 100644 --- a/arch/x86/include/asm/ioctls.h +++ b/arch/x86/include/asm/ioctls.h @@ -1,12 +1,23 @@ -#ifndef _ASM_X86_IOCTLS_H -#define _ASM_X86_IOCTLS_H +#ifndef __ASM_GENERIC_IOCTLS_H +#define __ASM_GENERIC_IOCTLS_H -#include +#include + +/* + * These are the most common definitions for tty ioctl numbers. + * Most of them do not use the recommended _IOC(), but there is + * probably some source code out there hardcoding the number, + * so we might as well use them for all new platforms. + * + * The architectures that use different values here typically + * try to be compatible with some Unix variants for the same + * architecture. + */ /* 0x54 is just a magic number to make these relatively unique ('T') */ #define TCGETS 0x5401 -#define TCSETS 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */ +#define TCSETS 0x5402 #define TCSETSW 0x5403 #define TCSETSF 0x5404 #define TCGETA 0x5405 @@ -43,7 +54,6 @@ #define TIOCSETD 0x5423 #define TIOCGETD 0x5424 #define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -/* #define TIOCTTYGSTRUCT 0x5426 - Former debugging-only ioctl */ #define TIOCSBRK 0x5427 /* BSD compatibility */ #define TIOCCBRK 0x5428 /* BSD compatibility */ #define TIOCGSID 0x5429 /* Return the session ID of FD */ @@ -53,8 +63,7 @@ #define TCSETSF2 _IOW('T', 0x2D, struct termios2) #define TIOCGRS485 0x542E #define TIOCSRS485 0x542F -#define TIOCGPTN _IOR('T', 0x30, unsigned int) - /* Get Pty Number (of pty-mux device) */ +#define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ #define TCGETX 0x5432 /* SYS5 TCGETX compatibility */ #define TCSETX 0x5433 @@ -76,9 +85,16 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ -#define FIOQSIZE 0x5460 + +/* + * some architectures define FIOQSIZE as 0x545E, which is used for + * TIOCGHAYESESP on others + */ +#ifndef FIOQSIZE +# define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +# define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +# define FIOQSIZE 0x5460 +#endif /* Used for packet mode */ #define TIOCPKT_DATA 0 @@ -89,6 +105,6 @@ #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 -#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ -#endif /* _ASM_X86_IOCTLS_H */ +#endif /* __ASM_GENERIC_IOCTLS_H */ diff --git a/arch/x86/include/asm/ipcbuf.h b/arch/x86/include/asm/ipcbuf.h index ee678fd..888ca1c 100644 --- a/arch/x86/include/asm/ipcbuf.h +++ b/arch/x86/include/asm/ipcbuf.h @@ -1,13 +1,18 @@ -#ifndef _ASM_X86_IPCBUF_H -#define _ASM_X86_IPCBUF_H +#ifndef __ASM_GENERIC_IPCBUF_H +#define __ASM_GENERIC_IPCBUF_H /* - * The ipc64_perm structure for x86 architecture. + * The generic ipc64_perm structure: * Note extra padding because this structure is passed back and forth * between kernel and user space. * + * ipc64_perm was originally meant to be architecture specific, but + * everyone just ended up making identical copies without specific + * optimizations, so we may just as well all use the same one. + * * Pad space is left for: - * - 32-bit mode_t and seq + * - 32-bit mode_t on architectures that only had 16 bit + * - 32-bit seq * - 2 miscellaneous 32-bit values */ @@ -25,4 +30,4 @@ struct ipc64_perm { unsigned long __unused2; }; -#endif /* _ASM_X86_IPCBUF_H */ +#endif /* __ASM_GENERIC_IPCBUF_H */ diff --git a/arch/x86/include/asm/msgbuf.h b/arch/x86/include/asm/msgbuf.h index 7e4e948..aec850d 100644 --- a/arch/x86/include/asm/msgbuf.h +++ b/arch/x86/include/asm/msgbuf.h @@ -1,30 +1,38 @@ -#ifndef _ASM_X86_MSGBUF_H -#define _ASM_X86_MSGBUF_H +#ifndef __ASM_GENERIC_MSGBUF_H +#define __ASM_GENERIC_MSGBUF_H +#include /* - * The msqid64_ds structure for i386 architecture. + * generic msqid64_ds structure. + * * Note extra padding because this structure is passed back and forth * between kernel and user space. * - * Pad space on i386 is left for: + * msqid64_ds was originally meant to be architecture specific, but + * everyone just ended up making identical copies without specific + * optimizations, so we may just as well all use the same one. + * + * 64 bit architectures typically define a 64 bit __kernel_time_t, + * so they do not need the first three padding words. + * On big-endian systems, the padding is in the wrong place. + * + * Pad space is left for: * - 64-bit time_t to solve y2038 problem * - 2 miscellaneous 32-bit values - * - * Pad space on x8664 is left for: - * - 2 miscellaneous 64-bit values */ + struct msqid64_ds { struct ipc64_perm msg_perm; __kernel_time_t msg_stime; /* last msgsnd time */ -#ifdef __i386__ +#if __BITS_PER_LONG != 64 unsigned long __unused1; #endif __kernel_time_t msg_rtime; /* last msgrcv time */ -#ifdef __i386__ +#if __BITS_PER_LONG != 64 unsigned long __unused2; #endif __kernel_time_t msg_ctime; /* last change time */ -#ifdef __i386__ +#if __BITS_PER_LONG != 64 unsigned long __unused3; #endif unsigned long msg_cbytes; /* current number of bytes on queue */ @@ -36,4 +44,4 @@ struct msqid64_ds { unsigned long __unused5; }; -#endif /* _ASM_X86_MSGBUF_H */ +#endif /* __ASM_GENERIC_MSGBUF_H */ diff --git a/arch/x86/include/asm/param.h b/arch/x86/include/asm/param.h index 6f0d042..cdf8251 100644 --- a/arch/x86/include/asm/param.h +++ b/arch/x86/include/asm/param.h @@ -1,5 +1,5 @@ -#ifndef _ASM_X86_PARAM_H -#define _ASM_X86_PARAM_H +#ifndef __ASM_GENERIC_PARAM_H +#define __ASM_GENERIC_PARAM_H #ifdef __KERNEL__ # define HZ CONFIG_HZ /* Internal kernel timer frequency */ @@ -11,7 +11,9 @@ #define HZ 100 #endif +#ifndef EXEC_PAGESIZE #define EXEC_PAGESIZE 4096 +#endif #ifndef NOGROUP #define NOGROUP (-1) @@ -19,4 +21,4 @@ #define MAXHOSTNAMELEN 64 /* max length of hostname */ -#endif /* _ASM_X86_PARAM_H */ +#endif /* __ASM_GENERIC_PARAM_H */ diff --git a/arch/x86/include/asm/shmbuf.h b/arch/x86/include/asm/shmbuf.h index b51413b..5768fa6 100644 --- a/arch/x86/include/asm/shmbuf.h +++ b/arch/x86/include/asm/shmbuf.h @@ -1,32 +1,40 @@ -#ifndef _ASM_X86_SHMBUF_H -#define _ASM_X86_SHMBUF_H +#ifndef __ASM_GENERIC_SHMBUF_H +#define __ASM_GENERIC_SHMBUF_H + +#include /* * The shmid64_ds structure for x86 architecture. * Note extra padding because this structure is passed back and forth * between kernel and user space. * - * Pad space on 32 bit is left for: + * shmid64_ds was originally meant to be architecture specific, but + * everyone just ended up making identical copies without specific + * optimizations, so we may just as well all use the same one. + * + * 64 bit architectures typically define a 64 bit __kernel_time_t, + * so they do not need the first two padding words. + * On big-endian systems, the padding is in the wrong place. + * + * + * Pad space is left for: * - 64-bit time_t to solve y2038 problem * - 2 miscellaneous 32-bit values - * - * Pad space on 64 bit is left for: - * - 2 miscellaneous 64-bit values */ struct shmid64_ds { struct ipc64_perm shm_perm; /* operation perms */ size_t shm_segsz; /* size of segment (bytes) */ __kernel_time_t shm_atime; /* last attach time */ -#ifdef __i386__ +#if __BITS_PER_LONG != 64 unsigned long __unused1; #endif __kernel_time_t shm_dtime; /* last detach time */ -#ifdef __i386__ +#if __BITS_PER_LONG != 64 unsigned long __unused2; #endif __kernel_time_t shm_ctime; /* last change time */ -#ifdef __i386__ +#if __BITS_PER_LONG != 64 unsigned long __unused3; #endif __kernel_pid_t shm_cpid; /* pid of creator */ @@ -48,4 +56,4 @@ struct shminfo64 { unsigned long __unused4; }; -#endif /* _ASM_X86_SHMBUF_H */ +#endif /* __ASM_GENERIC_SHMBUF_H */ diff --git a/arch/x86/include/asm/socket.h b/arch/x86/include/asm/socket.h index ca8bf2c..d4ae42a 100644 --- a/arch/x86/include/asm/socket.h +++ b/arch/x86/include/asm/socket.h @@ -1,5 +1,5 @@ -#ifndef _ASM_X86_SOCKET_H -#define _ASM_X86_SOCKET_H +#ifndef __ASM_GENERIC_SOCKET_H +#define __ASM_GENERIC_SOCKET_H #include @@ -38,8 +38,8 @@ #define SO_BINDTODEVICE 25 /* Socket filtering */ -#define SO_ATTACH_FILTER 26 -#define SO_DETACH_FILTER 27 +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 #define SO_PEERNAME 28 #define SO_TIMESTAMP 29 @@ -57,4 +57,4 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING -#endif /* _ASM_X86_SOCKET_H */ +#endif /* __ASM_GENERIC_SOCKET_H */ diff --git a/arch/x86/include/asm/sockios.h b/arch/x86/include/asm/sockios.h index 49cc72b..9a61a36 100644 --- a/arch/x86/include/asm/sockios.h +++ b/arch/x86/include/asm/sockios.h @@ -1,5 +1,5 @@ -#ifndef _ASM_X86_SOCKIOS_H -#define _ASM_X86_SOCKIOS_H +#ifndef __ASM_GENERIC_SOCKIOS_H +#define __ASM_GENERIC_SOCKIOS_H /* Socket-level I/O control calls. */ #define FIOSETOWN 0x8901 @@ -10,4 +10,4 @@ #define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ #define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ -#endif /* _ASM_X86_SOCKIOS_H */ +#endif /* __ASM_GENERIC_SOCKIOS_H */ diff --git a/arch/x86/include/asm/termbits.h b/arch/x86/include/asm/termbits.h index af1b70e..1c9773d 100644 --- a/arch/x86/include/asm/termbits.h +++ b/arch/x86/include/asm/termbits.h @@ -1,5 +1,5 @@ -#ifndef _ASM_X86_TERMBITS_H -#define _ASM_X86_TERMBITS_H +#ifndef __ASM_GENERIC_TERMBITS_H +#define __ASM_GENERIC_TERMBITS_H #include @@ -140,7 +140,7 @@ struct ktermios { #define HUPCL 0002000 #define CLOCAL 0004000 #define CBAUDEX 0010000 -#define BOTHER 0010000 /* non standard rate */ +#define BOTHER 0010000 #define B57600 0010001 #define B115200 0010002 #define B230400 0010003 @@ -195,4 +195,4 @@ struct ktermios { #define TCSADRAIN 1 #define TCSAFLUSH 2 -#endif /* _ASM_X86_TERMBITS_H */ +#endif /* __ASM_GENERIC_TERMBITS_H */ -- cgit v0.10.2 From 06f5013aa8eb5895ced2c71d13f5114103605555 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Jun 2009 21:48:18 +0200 Subject: x86: convert almost generic headers to asm-generic version In x86, mman.h, module.h, scatterlist.h, types.h and ucontext.h can use the asm-generic version by just defining the x86 specific parts locally and falling back on the generic code for the common bits. This patch illustrates the differences between the x86 and asm-generic versions by changing a file that is initially identical to the x86 version to one that is identical to the asm-generic version. Signed-off-by: Arnd Bergmann LKML-Reference: Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/generic-mman.h b/arch/x86/include/asm/generic-mman.h index 751af25..7cab4de 100644 --- a/arch/x86/include/asm/generic-mman.h +++ b/arch/x86/include/asm/generic-mman.h @@ -1,10 +1,8 @@ -#ifndef _ASM_X86_MMAN_H -#define _ASM_X86_MMAN_H +#ifndef __ASM_GENERIC_MMAN_H +#define __ASM_GENERIC_MMAN_H #include -#define MAP_32BIT 0x40 /* only give out 32bit addresses */ - #define MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define MAP_DENYWRITE 0x0800 /* ETXTBSY */ #define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ @@ -17,4 +15,4 @@ #define MCL_CURRENT 1 /* lock all current mappings */ #define MCL_FUTURE 2 /* lock all future mappings */ -#endif /* _ASM_X86_MMAN_H */ +#endif /* __ASM_GENERIC_MMAN_H */ diff --git a/arch/x86/include/asm/generic-module.h b/arch/x86/include/asm/generic-module.h index 47d6274..ed5b44d 100644 --- a/arch/x86/include/asm/generic-module.h +++ b/arch/x86/include/asm/generic-module.h @@ -1,80 +1,22 @@ -#ifndef _ASM_X86_MODULE_H -#define _ASM_X86_MODULE_H +#ifndef __ASM_GENERIC_MODULE_H +#define __ASM_GENERIC_MODULE_H -/* x86_32/64 are simple */ -struct mod_arch_specific {}; +/* + * Many architectures just need a simple module + * loader without arch specific data. + */ +struct mod_arch_specific +{ +}; -#ifdef CONFIG_X86_32 -# define Elf_Shdr Elf32_Shdr -# define Elf_Sym Elf32_Sym -# define Elf_Ehdr Elf32_Ehdr +#ifdef CONFIG_64BIT +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Ehdr Elf64_Ehdr #else -# define Elf_Shdr Elf64_Shdr -# define Elf_Sym Elf64_Sym -# define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr #endif -#ifdef CONFIG_X86_64 -/* X86_64 does not define MODULE_PROC_FAMILY */ -#elif defined CONFIG_M386 -#define MODULE_PROC_FAMILY "386 " -#elif defined CONFIG_M486 -#define MODULE_PROC_FAMILY "486 " -#elif defined CONFIG_M586 -#define MODULE_PROC_FAMILY "586 " -#elif defined CONFIG_M586TSC -#define MODULE_PROC_FAMILY "586TSC " -#elif defined CONFIG_M586MMX -#define MODULE_PROC_FAMILY "586MMX " -#elif defined CONFIG_MCORE2 -#define MODULE_PROC_FAMILY "CORE2 " -#elif defined CONFIG_M686 -#define MODULE_PROC_FAMILY "686 " -#elif defined CONFIG_MPENTIUMII -#define MODULE_PROC_FAMILY "PENTIUMII " -#elif defined CONFIG_MPENTIUMIII -#define MODULE_PROC_FAMILY "PENTIUMIII " -#elif defined CONFIG_MPENTIUMM -#define MODULE_PROC_FAMILY "PENTIUMM " -#elif defined CONFIG_MPENTIUM4 -#define MODULE_PROC_FAMILY "PENTIUM4 " -#elif defined CONFIG_MK6 -#define MODULE_PROC_FAMILY "K6 " -#elif defined CONFIG_MK7 -#define MODULE_PROC_FAMILY "K7 " -#elif defined CONFIG_MK8 -#define MODULE_PROC_FAMILY "K8 " -#elif defined CONFIG_X86_ELAN -#define MODULE_PROC_FAMILY "ELAN " -#elif defined CONFIG_MCRUSOE -#define MODULE_PROC_FAMILY "CRUSOE " -#elif defined CONFIG_MEFFICEON -#define MODULE_PROC_FAMILY "EFFICEON " -#elif defined CONFIG_MWINCHIPC6 -#define MODULE_PROC_FAMILY "WINCHIPC6 " -#elif defined CONFIG_MWINCHIP3D -#define MODULE_PROC_FAMILY "WINCHIP3D " -#elif defined CONFIG_MCYRIXIII -#define MODULE_PROC_FAMILY "CYRIXIII " -#elif defined CONFIG_MVIAC3_2 -#define MODULE_PROC_FAMILY "VIAC3-2 " -#elif defined CONFIG_MVIAC7 -#define MODULE_PROC_FAMILY "VIAC7 " -#elif defined CONFIG_MGEODEGX1 -#define MODULE_PROC_FAMILY "GEODEGX1 " -#elif defined CONFIG_MGEODE_LX -#define MODULE_PROC_FAMILY "GEODE " -#else -#error unknown processor family -#endif - -#ifdef CONFIG_X86_32 -# ifdef CONFIG_4KSTACKS -# define MODULE_STACKSIZE "4KSTACKS " -# else -# define MODULE_STACKSIZE "" -# endif -# define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_STACKSIZE -#endif - -#endif /* _ASM_X86_MODULE_H */ +#endif /* __ASM_GENERIC_MODULE_H */ diff --git a/arch/x86/include/asm/generic-scatterlist.h b/arch/x86/include/asm/generic-scatterlist.h index 263d397..8b94544 100644 --- a/arch/x86/include/asm/generic-scatterlist.h +++ b/arch/x86/include/asm/generic-scatterlist.h @@ -1,7 +1,7 @@ -#ifndef _ASM_X86_SCATTERLIST_H -#define _ASM_X86_SCATTERLIST_H +#ifndef __ASM_GENERIC_SCATTERLIST_H +#define __ASM_GENERIC_SCATTERLIST_H -#include +#include struct scatterlist { #ifdef CONFIG_DEBUG_SG @@ -14,20 +14,30 @@ struct scatterlist { unsigned int dma_length; }; -#define ARCH_HAS_SG_CHAIN -#define ISA_DMA_THRESHOLD (0x00ffffff) - /* - * These macros should be used after a pci_map_sg call has been done + * These macros should be used after a dma_map_sg call has been done * to get bus addresses of each of the SG entries and their lengths. * You should only work with the number of sg entries pci_map_sg - * returns. + * returns, or alternatively stop on the first sg_dma_len(sg) which + * is 0. */ #define sg_dma_address(sg) ((sg)->dma_address) -#ifdef CONFIG_X86_32 -# define sg_dma_len(sg) ((sg)->length) +#ifndef sg_dma_len +/* + * Normally, you have an iommu on 64 bit machines, but not on 32 bit + * machines. Architectures that are differnt should override this. + */ +#if __BITS_PER_LONG == 64 +#define sg_dma_len(sg) ((sg)->dma_length) #else -# define sg_dma_len(sg) ((sg)->dma_length) +#define sg_dma_len(sg) ((sg)->length) +#endif /* 64 bit */ +#endif /* sg_dma_len */ + +#ifndef ISA_DMA_THRESHOLD +#define ISA_DMA_THRESHOLD (~0UL) #endif -#endif /* _ASM_X86_SCATTERLIST_H */ +#define ARCH_HAS_SG_CHAIN + +#endif /* __ASM_GENERIC_SCATTERLIST_H */ diff --git a/arch/x86/include/asm/generic-types.h b/arch/x86/include/asm/generic-types.h index 09b9774..fba7d33 100644 --- a/arch/x86/include/asm/generic-types.h +++ b/arch/x86/include/asm/generic-types.h @@ -1,6 +1,9 @@ -#ifndef _ASM_X86_TYPES_H -#define _ASM_X86_TYPES_H - +#ifndef _ASM_GENERIC_TYPES_H +#define _ASM_GENERIC_TYPES_H +/* + * int-ll64 is used practically everywhere now, + * so use it as a reasonable default. + */ #include #ifndef __ASSEMBLY__ @@ -13,18 +16,27 @@ typedef unsigned short umode_t; * These aren't exported outside the kernel to avoid name space clashes */ #ifdef __KERNEL__ - #ifndef __ASSEMBLY__ - -typedef u64 dma64_addr_t; -#if defined(CONFIG_X86_64) || defined(CONFIG_HIGHMEM64G) -/* DMA addresses come in 32-bit and 64-bit flavours. */ +/* + * DMA addresses may be very different from physical addresses + * and pointers. i386 and powerpc may have 64 bit DMA on 32 bit + * systems, while sparc64 uses 32 bit DMA addresses for 64 bit + * physical addresses. + * This default defines dma_addr_t to have the same size as + * phys_addr_t, which is the most common way. + * Do not define the dma64_addr_t type, which never really + * worked. + */ +#ifndef dma_addr_t +#ifdef CONFIG_PHYS_ADDR_T_64BIT typedef u64 dma_addr_t; #else typedef u32 dma_addr_t; -#endif +#endif /* CONFIG_PHYS_ADDR_T_64BIT */ +#endif /* dma_addr_t */ #endif /* __ASSEMBLY__ */ + #endif /* __KERNEL__ */ -#endif /* _ASM_X86_TYPES_H */ +#endif /* _ASM_GENERIC_TYPES_H */ diff --git a/arch/x86/include/asm/generic-ucontext.h b/arch/x86/include/asm/generic-ucontext.h index 87324cf..ad77343 100644 --- a/arch/x86/include/asm/generic-ucontext.h +++ b/arch/x86/include/asm/generic-ucontext.h @@ -1,11 +1,5 @@ -#ifndef _ASM_X86_UCONTEXT_H -#define _ASM_X86_UCONTEXT_H - -#define UC_FP_XSTATE 0x1 /* indicates the presence of extended state - * information in the memory layout pointed - * by the fpstate pointer in the ucontext's - * sigcontext struct (uc_mcontext). - */ +#ifndef __ASM_GENERIC_UCONTEXT_H +#define __ASM_GENERIC_UCONTEXT_H struct ucontext { unsigned long uc_flags; @@ -15,4 +9,4 @@ struct ucontext { sigset_t uc_sigmask; /* mask last for extensibility */ }; -#endif /* _ASM_X86_UCONTEXT_H */ +#endif /* __ASM_GENERIC_UCONTEXT_H */ diff --git a/arch/x86/include/asm/mman.h b/arch/x86/include/asm/mman.h index 751af25..063d8c9 100644 --- a/arch/x86/include/asm/mman.h +++ b/arch/x86/include/asm/mman.h @@ -1,20 +1,8 @@ #ifndef _ASM_X86_MMAN_H #define _ASM_X86_MMAN_H -#include - #define MAP_32BIT 0x40 /* only give out 32bit addresses */ -#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ -#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ -#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ -#define MAP_LOCKED 0x2000 /* pages are locked */ -#define MAP_NORESERVE 0x4000 /* don't check for reservations */ -#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ -#define MAP_NONBLOCK 0x10000 /* do not block on IO */ -#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */ - -#define MCL_CURRENT 1 /* lock all current mappings */ -#define MCL_FUTURE 2 /* lock all future mappings */ +#include #endif /* _ASM_X86_MMAN_H */ diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h index 47d6274..4a7a192 100644 --- a/arch/x86/include/asm/module.h +++ b/arch/x86/include/asm/module.h @@ -1,18 +1,7 @@ #ifndef _ASM_X86_MODULE_H #define _ASM_X86_MODULE_H -/* x86_32/64 are simple */ -struct mod_arch_specific {}; - -#ifdef CONFIG_X86_32 -# define Elf_Shdr Elf32_Shdr -# define Elf_Sym Elf32_Sym -# define Elf_Ehdr Elf32_Ehdr -#else -# define Elf_Shdr Elf64_Shdr -# define Elf_Sym Elf64_Sym -# define Elf_Ehdr Elf64_Ehdr -#endif +#include #ifdef CONFIG_X86_64 /* X86_64 does not define MODULE_PROC_FAMILY */ diff --git a/arch/x86/include/asm/scatterlist.h b/arch/x86/include/asm/scatterlist.h index 263d397..2097d68 100644 --- a/arch/x86/include/asm/scatterlist.h +++ b/arch/x86/include/asm/scatterlist.h @@ -1,33 +1,8 @@ #ifndef _ASM_X86_SCATTERLIST_H #define _ASM_X86_SCATTERLIST_H -#include - -struct scatterlist { -#ifdef CONFIG_DEBUG_SG - unsigned long sg_magic; -#endif - unsigned long page_link; - unsigned int offset; - unsigned int length; - dma_addr_t dma_address; - unsigned int dma_length; -}; - -#define ARCH_HAS_SG_CHAIN #define ISA_DMA_THRESHOLD (0x00ffffff) -/* - * These macros should be used after a pci_map_sg call has been done - * to get bus addresses of each of the SG entries and their lengths. - * You should only work with the number of sg entries pci_map_sg - * returns. - */ -#define sg_dma_address(sg) ((sg)->dma_address) -#ifdef CONFIG_X86_32 -# define sg_dma_len(sg) ((sg)->length) -#else -# define sg_dma_len(sg) ((sg)->dma_length) -#endif +#include #endif /* _ASM_X86_SCATTERLIST_H */ diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h index 09b9774..f2fe528 100644 --- a/arch/x86/include/asm/types.h +++ b/arch/x86/include/asm/types.h @@ -1,19 +1,11 @@ #ifndef _ASM_X86_TYPES_H #define _ASM_X86_TYPES_H -#include +#define dma_addr_t dma_addr_t -#ifndef __ASSEMBLY__ - -typedef unsigned short umode_t; +#include -#endif /* __ASSEMBLY__ */ - -/* - * These aren't exported outside the kernel to avoid name space clashes - */ #ifdef __KERNEL__ - #ifndef __ASSEMBLY__ typedef u64 dma64_addr_t; diff --git a/arch/x86/include/asm/ucontext.h b/arch/x86/include/asm/ucontext.h index 87324cf..7cfc436 100644 --- a/arch/x86/include/asm/ucontext.h +++ b/arch/x86/include/asm/ucontext.h @@ -7,12 +7,6 @@ * sigcontext struct (uc_mcontext). */ -struct ucontext { - unsigned long uc_flags; - struct ucontext *uc_link; - stack_t uc_stack; - struct sigcontext uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ -}; +#include #endif /* _ASM_X86_UCONTEXT_H */ -- cgit v0.10.2 From 69d5ffdaad7b77b97229b55c36afb20e5bebd29e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Jun 2009 21:48:19 +0200 Subject: x86: convert termios.h to the asm-generic version This patch turned out more controversial than expected and may get dropped in the future. I'm including it for reference anyway. The user_termio_to_kernel_termios and kernel_termios_to_user_termio functions on x86 are lacking error checking from get_user and are not portable to big-endian systems, so the asm-generic header has to differ in this regard. Signed-off-by: Arnd Bergmann LKML-Reference: Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/termios.h b/arch/x86/include/asm/termios.h index c4ee805..d0922ad 100644 --- a/arch/x86/include/asm/termios.h +++ b/arch/x86/include/asm/termios.h @@ -1,5 +1,12 @@ -#ifndef _ASM_X86_TERMIOS_H -#define _ASM_X86_TERMIOS_H +#ifndef _ASM_GENERIC_TERMIOS_H +#define _ASM_GENERIC_TERMIOS_H +/* + * Most architectures have straight copies of the x86 code, with + * varying levels of bug fixes on top. Usually it's a good idea + * to use this generic version instead, but be careful to avoid + * ABI changes. + * New architectures should not provide their own version. + */ #include #include @@ -54,37 +61,57 @@ struct termio { /* * Translate a "termio" structure into a "termios". Ugh. */ -#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \ - unsigned short __tmp; \ - get_user(__tmp,&(termio)->x); \ - *(unsigned short *) &(termios)->x = __tmp; \ -} - static inline int user_termio_to_kernel_termios(struct ktermios *termios, - struct termio __user *termio) + const struct termio __user *termio) { - SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); - SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); - SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); - SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); - get_user(termios->c_line, &termio->c_line); - return copy_from_user(termios->c_cc, termio->c_cc, NCC); + unsigned short tmp; + + if (get_user(tmp, &termio->c_iflag) < 0) + goto fault; + termios->c_iflag = (0xffff0000 & termios->c_iflag) | tmp; + + if (get_user(tmp, &termio->c_oflag) < 0) + goto fault; + termios->c_oflag = (0xffff0000 & termios->c_oflag) | tmp; + + if (get_user(tmp, &termio->c_cflag) < 0) + goto fault; + termios->c_cflag = (0xffff0000 & termios->c_cflag) | tmp; + + if (get_user(tmp, &termio->c_lflag) < 0) + goto fault; + termios->c_lflag = (0xffff0000 & termios->c_lflag) | tmp; + + if (get_user(termios->c_line, &termio->c_line) < 0) + goto fault; + + if (copy_from_user(termios->c_cc, termio->c_cc, NCC) != 0) + goto fault; + + return 0; + + fault: + return -EFAULT; } /* * Translate a "termios" structure into a "termio". Ugh. */ static inline int kernel_termios_to_user_termio(struct termio __user *termio, - struct ktermios *termios) + struct ktermios *termios) { - put_user((termios)->c_iflag, &(termio)->c_iflag); - put_user((termios)->c_oflag, &(termio)->c_oflag); - put_user((termios)->c_cflag, &(termio)->c_cflag); - put_user((termios)->c_lflag, &(termio)->c_lflag); - put_user((termios)->c_line, &(termio)->c_line); - return copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); + if (put_user(termios->c_iflag, &termio->c_iflag) < 0 || + put_user(termios->c_oflag, &termio->c_oflag) < 0 || + put_user(termios->c_cflag, &termio->c_cflag) < 0 || + put_user(termios->c_lflag, &termio->c_lflag) < 0 || + put_user(termios->c_line, &termio->c_line) < 0 || + copy_to_user(termio->c_cc, termios->c_cc, NCC) != 0) + return -EFAULT; + + return 0; } +#ifdef TCGETS2 static inline int user_termios_to_kernel_termios(struct ktermios *k, struct termios2 __user *u) { @@ -108,7 +135,20 @@ static inline int kernel_termios_to_user_termios_1(struct termios __user *u, { return copy_to_user(u, k, sizeof(struct termios)); } +#else /* TCGETS2 */ +static inline int user_termios_to_kernel_termios(struct ktermios *k, + struct termios __user *u) +{ + return copy_from_user(k, u, sizeof(struct termios)); +} + +static inline int kernel_termios_to_user_termios(struct termios __user *u, + struct ktermios *k) +{ + return copy_to_user(u, k, sizeof(struct termios)); +} +#endif /* TCGETS2 */ #endif /* __KERNEL__ */ -#endif /* _ASM_X86_TERMIOS_H */ +#endif /* _ASM_GENERIC_TERMIOS_H */ -- cgit v0.10.2 From 73a2d096fdf23aa841f7595d114a11ec85a85e4d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Jun 2009 21:48:20 +0200 Subject: x86: remove all now-duplicate header files All files that have been made identical to the asm-generic version in the previous patches can now be removed, guaranteeing that this does not introduce semantic changes. Signed-off-by: Arnd Bergmann LKML-Reference: Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/generic-mman.h b/arch/x86/include/asm/generic-mman.h deleted file mode 100644 index 7cab4de..0000000 --- a/arch/x86/include/asm/generic-mman.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __ASM_GENERIC_MMAN_H -#define __ASM_GENERIC_MMAN_H - -#include - -#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ -#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ -#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ -#define MAP_LOCKED 0x2000 /* pages are locked */ -#define MAP_NORESERVE 0x4000 /* don't check for reservations */ -#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ -#define MAP_NONBLOCK 0x10000 /* do not block on IO */ -#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */ - -#define MCL_CURRENT 1 /* lock all current mappings */ -#define MCL_FUTURE 2 /* lock all future mappings */ - -#endif /* __ASM_GENERIC_MMAN_H */ diff --git a/arch/x86/include/asm/generic-module.h b/arch/x86/include/asm/generic-module.h deleted file mode 100644 index ed5b44d..0000000 --- a/arch/x86/include/asm/generic-module.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __ASM_GENERIC_MODULE_H -#define __ASM_GENERIC_MODULE_H - -/* - * Many architectures just need a simple module - * loader without arch specific data. - */ -struct mod_arch_specific -{ -}; - -#ifdef CONFIG_64BIT -#define Elf_Shdr Elf64_Shdr -#define Elf_Sym Elf64_Sym -#define Elf_Ehdr Elf64_Ehdr -#else -#define Elf_Shdr Elf32_Shdr -#define Elf_Sym Elf32_Sym -#define Elf_Ehdr Elf32_Ehdr -#endif - -#endif /* __ASM_GENERIC_MODULE_H */ diff --git a/arch/x86/include/asm/generic-scatterlist.h b/arch/x86/include/asm/generic-scatterlist.h deleted file mode 100644 index 8b94544..0000000 --- a/arch/x86/include/asm/generic-scatterlist.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef __ASM_GENERIC_SCATTERLIST_H -#define __ASM_GENERIC_SCATTERLIST_H - -#include - -struct scatterlist { -#ifdef CONFIG_DEBUG_SG - unsigned long sg_magic; -#endif - unsigned long page_link; - unsigned int offset; - unsigned int length; - dma_addr_t dma_address; - unsigned int dma_length; -}; - -/* - * These macros should be used after a dma_map_sg call has been done - * to get bus addresses of each of the SG entries and their lengths. - * You should only work with the number of sg entries pci_map_sg - * returns, or alternatively stop on the first sg_dma_len(sg) which - * is 0. - */ -#define sg_dma_address(sg) ((sg)->dma_address) -#ifndef sg_dma_len -/* - * Normally, you have an iommu on 64 bit machines, but not on 32 bit - * machines. Architectures that are differnt should override this. - */ -#if __BITS_PER_LONG == 64 -#define sg_dma_len(sg) ((sg)->dma_length) -#else -#define sg_dma_len(sg) ((sg)->length) -#endif /* 64 bit */ -#endif /* sg_dma_len */ - -#ifndef ISA_DMA_THRESHOLD -#define ISA_DMA_THRESHOLD (~0UL) -#endif - -#define ARCH_HAS_SG_CHAIN - -#endif /* __ASM_GENERIC_SCATTERLIST_H */ diff --git a/arch/x86/include/asm/generic-types.h b/arch/x86/include/asm/generic-types.h deleted file mode 100644 index fba7d33..0000000 --- a/arch/x86/include/asm/generic-types.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _ASM_GENERIC_TYPES_H -#define _ASM_GENERIC_TYPES_H -/* - * int-ll64 is used practically everywhere now, - * so use it as a reasonable default. - */ -#include - -#ifndef __ASSEMBLY__ - -typedef unsigned short umode_t; - -#endif /* __ASSEMBLY__ */ - -/* - * These aren't exported outside the kernel to avoid name space clashes - */ -#ifdef __KERNEL__ -#ifndef __ASSEMBLY__ -/* - * DMA addresses may be very different from physical addresses - * and pointers. i386 and powerpc may have 64 bit DMA on 32 bit - * systems, while sparc64 uses 32 bit DMA addresses for 64 bit - * physical addresses. - * This default defines dma_addr_t to have the same size as - * phys_addr_t, which is the most common way. - * Do not define the dma64_addr_t type, which never really - * worked. - */ -#ifndef dma_addr_t -#ifdef CONFIG_PHYS_ADDR_T_64BIT -typedef u64 dma_addr_t; -#else -typedef u32 dma_addr_t; -#endif /* CONFIG_PHYS_ADDR_T_64BIT */ -#endif /* dma_addr_t */ - -#endif /* __ASSEMBLY__ */ - -#endif /* __KERNEL__ */ - -#endif /* _ASM_GENERIC_TYPES_H */ diff --git a/arch/x86/include/asm/generic-ucontext.h b/arch/x86/include/asm/generic-ucontext.h deleted file mode 100644 index ad77343..0000000 --- a/arch/x86/include/asm/generic-ucontext.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __ASM_GENERIC_UCONTEXT_H -#define __ASM_GENERIC_UCONTEXT_H - -struct ucontext { - unsigned long uc_flags; - struct ucontext *uc_link; - stack_t uc_stack; - struct sigcontext uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ -}; - -#endif /* __ASM_GENERIC_UCONTEXT_H */ diff --git a/arch/x86/include/asm/ioctls.h b/arch/x86/include/asm/ioctls.h index a799e20..ec34c76 100644 --- a/arch/x86/include/asm/ioctls.h +++ b/arch/x86/include/asm/ioctls.h @@ -1,110 +1 @@ -#ifndef __ASM_GENERIC_IOCTLS_H -#define __ASM_GENERIC_IOCTLS_H - -#include - -/* - * These are the most common definitions for tty ioctl numbers. - * Most of them do not use the recommended _IOC(), but there is - * probably some source code out there hardcoding the number, - * so we might as well use them for all new platforms. - * - * The architectures that use different values here typically - * try to be compatible with some Unix variants for the same - * architecture. - */ - -/* 0x54 is just a magic number to make these relatively unique ('T') */ - -#define TCGETS 0x5401 -#define TCSETS 0x5402 -#define TCSETSW 0x5403 -#define TCSETSF 0x5404 -#define TCGETA 0x5405 -#define TCSETA 0x5406 -#define TCSETAW 0x5407 -#define TCSETAF 0x5408 -#define TCSBRK 0x5409 -#define TCXONC 0x540A -#define TCFLSH 0x540B -#define TIOCEXCL 0x540C -#define TIOCNXCL 0x540D -#define TIOCSCTTY 0x540E -#define TIOCGPGRP 0x540F -#define TIOCSPGRP 0x5410 -#define TIOCOUTQ 0x5411 -#define TIOCSTI 0x5412 -#define TIOCGWINSZ 0x5413 -#define TIOCSWINSZ 0x5414 -#define TIOCMGET 0x5415 -#define TIOCMBIS 0x5416 -#define TIOCMBIC 0x5417 -#define TIOCMSET 0x5418 -#define TIOCGSOFTCAR 0x5419 -#define TIOCSSOFTCAR 0x541A -#define FIONREAD 0x541B -#define TIOCINQ FIONREAD -#define TIOCLINUX 0x541C -#define TIOCCONS 0x541D -#define TIOCGSERIAL 0x541E -#define TIOCSSERIAL 0x541F -#define TIOCPKT 0x5420 -#define FIONBIO 0x5421 -#define TIOCNOTTY 0x5422 -#define TIOCSETD 0x5423 -#define TIOCGETD 0x5424 -#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -#define TIOCSBRK 0x5427 /* BSD compatibility */ -#define TIOCCBRK 0x5428 /* BSD compatibility */ -#define TIOCGSID 0x5429 /* Return the session ID of FD */ -#define TCGETS2 _IOR('T', 0x2A, struct termios2) -#define TCSETS2 _IOW('T', 0x2B, struct termios2) -#define TCSETSW2 _IOW('T', 0x2C, struct termios2) -#define TCSETSF2 _IOW('T', 0x2D, struct termios2) -#define TIOCGRS485 0x542E -#define TIOCSRS485 0x542F -#define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ -#define TCGETX 0x5432 /* SYS5 TCGETX compatibility */ -#define TCSETX 0x5433 -#define TCSETXF 0x5434 -#define TCSETXW 0x5435 - -#define FIONCLEX 0x5450 -#define FIOCLEX 0x5451 -#define FIOASYNC 0x5452 -#define TIOCSERCONFIG 0x5453 -#define TIOCSERGWILD 0x5454 -#define TIOCSERSWILD 0x5455 -#define TIOCGLCKTRMIOS 0x5456 -#define TIOCSLCKTRMIOS 0x5457 -#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ -#define TIOCSERGETLSR 0x5459 /* Get line status register */ -#define TIOCSERGETMULTI 0x545A /* Get multiport config */ -#define TIOCSERSETMULTI 0x545B /* Set multiport config */ - -#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ -#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ - -/* - * some architectures define FIOQSIZE as 0x545E, which is used for - * TIOCGHAYESESP on others - */ -#ifndef FIOQSIZE -# define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -# define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ -# define FIOQSIZE 0x5460 -#endif - -/* Used for packet mode */ -#define TIOCPKT_DATA 0 -#define TIOCPKT_FLUSHREAD 1 -#define TIOCPKT_FLUSHWRITE 2 -#define TIOCPKT_STOP 4 -#define TIOCPKT_START 8 -#define TIOCPKT_NOSTOP 16 -#define TIOCPKT_DOSTOP 32 - -#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ - -#endif /* __ASM_GENERIC_IOCTLS_H */ +#include diff --git a/arch/x86/include/asm/ipcbuf.h b/arch/x86/include/asm/ipcbuf.h index 888ca1c..84c7e51 100644 --- a/arch/x86/include/asm/ipcbuf.h +++ b/arch/x86/include/asm/ipcbuf.h @@ -1,33 +1 @@ -#ifndef __ASM_GENERIC_IPCBUF_H -#define __ASM_GENERIC_IPCBUF_H - -/* - * The generic ipc64_perm structure: - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * ipc64_perm was originally meant to be architecture specific, but - * everyone just ended up making identical copies without specific - * optimizations, so we may just as well all use the same one. - * - * Pad space is left for: - * - 32-bit mode_t on architectures that only had 16 bit - * - 32-bit seq - * - 2 miscellaneous 32-bit values - */ - -struct ipc64_perm { - __kernel_key_t key; - __kernel_uid32_t uid; - __kernel_gid32_t gid; - __kernel_uid32_t cuid; - __kernel_gid32_t cgid; - __kernel_mode_t mode; - unsigned short __pad1; - unsigned short seq; - unsigned short __pad2; - unsigned long __unused1; - unsigned long __unused2; -}; - -#endif /* __ASM_GENERIC_IPCBUF_H */ +#include diff --git a/arch/x86/include/asm/mman.h b/arch/x86/include/asm/mman.h index 063d8c9..593e51d 100644 --- a/arch/x86/include/asm/mman.h +++ b/arch/x86/include/asm/mman.h @@ -3,6 +3,6 @@ #define MAP_32BIT 0x40 /* only give out 32bit addresses */ -#include +#include #endif /* _ASM_X86_MMAN_H */ diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h index 4a7a192..555bc12 100644 --- a/arch/x86/include/asm/module.h +++ b/arch/x86/include/asm/module.h @@ -1,7 +1,7 @@ #ifndef _ASM_X86_MODULE_H #define _ASM_X86_MODULE_H -#include +#include #ifdef CONFIG_X86_64 /* X86_64 does not define MODULE_PROC_FAMILY */ diff --git a/arch/x86/include/asm/msgbuf.h b/arch/x86/include/asm/msgbuf.h index aec850d..809134c 100644 --- a/arch/x86/include/asm/msgbuf.h +++ b/arch/x86/include/asm/msgbuf.h @@ -1,47 +1 @@ -#ifndef __ASM_GENERIC_MSGBUF_H -#define __ASM_GENERIC_MSGBUF_H - -#include -/* - * generic msqid64_ds structure. - * - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * msqid64_ds was originally meant to be architecture specific, but - * everyone just ended up making identical copies without specific - * optimizations, so we may just as well all use the same one. - * - * 64 bit architectures typically define a 64 bit __kernel_time_t, - * so they do not need the first three padding words. - * On big-endian systems, the padding is in the wrong place. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct msqid64_ds { - struct ipc64_perm msg_perm; - __kernel_time_t msg_stime; /* last msgsnd time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused1; -#endif - __kernel_time_t msg_rtime; /* last msgrcv time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused2; -#endif - __kernel_time_t msg_ctime; /* last change time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused3; -#endif - unsigned long msg_cbytes; /* current number of bytes on queue */ - unsigned long msg_qnum; /* number of messages in queue */ - unsigned long msg_qbytes; /* max number of bytes on queue */ - __kernel_pid_t msg_lspid; /* pid of last msgsnd */ - __kernel_pid_t msg_lrpid; /* last receive pid */ - unsigned long __unused4; - unsigned long __unused5; -}; - -#endif /* __ASM_GENERIC_MSGBUF_H */ +#include diff --git a/arch/x86/include/asm/param.h b/arch/x86/include/asm/param.h index cdf8251..965d454 100644 --- a/arch/x86/include/asm/param.h +++ b/arch/x86/include/asm/param.h @@ -1,24 +1 @@ -#ifndef __ASM_GENERIC_PARAM_H -#define __ASM_GENERIC_PARAM_H - -#ifdef __KERNEL__ -# define HZ CONFIG_HZ /* Internal kernel timer frequency */ -# define USER_HZ 100 /* some user interfaces are */ -# define CLOCKS_PER_SEC (USER_HZ) /* in "ticks" like times() */ -#endif - -#ifndef HZ -#define HZ 100 -#endif - -#ifndef EXEC_PAGESIZE -#define EXEC_PAGESIZE 4096 -#endif - -#ifndef NOGROUP -#define NOGROUP (-1) -#endif - -#define MAXHOSTNAMELEN 64 /* max length of hostname */ - -#endif /* __ASM_GENERIC_PARAM_H */ +#include diff --git a/arch/x86/include/asm/scatterlist.h b/arch/x86/include/asm/scatterlist.h index 2097d68..75af592 100644 --- a/arch/x86/include/asm/scatterlist.h +++ b/arch/x86/include/asm/scatterlist.h @@ -3,6 +3,6 @@ #define ISA_DMA_THRESHOLD (0x00ffffff) -#include +#include #endif /* _ASM_X86_SCATTERLIST_H */ diff --git a/arch/x86/include/asm/shmbuf.h b/arch/x86/include/asm/shmbuf.h index 5768fa6..83c05fc 100644 --- a/arch/x86/include/asm/shmbuf.h +++ b/arch/x86/include/asm/shmbuf.h @@ -1,59 +1 @@ -#ifndef __ASM_GENERIC_SHMBUF_H -#define __ASM_GENERIC_SHMBUF_H - -#include - -/* - * The shmid64_ds structure for x86 architecture. - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * shmid64_ds was originally meant to be architecture specific, but - * everyone just ended up making identical copies without specific - * optimizations, so we may just as well all use the same one. - * - * 64 bit architectures typically define a 64 bit __kernel_time_t, - * so they do not need the first two padding words. - * On big-endian systems, the padding is in the wrong place. - * - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct shmid64_ds { - struct ipc64_perm shm_perm; /* operation perms */ - size_t shm_segsz; /* size of segment (bytes) */ - __kernel_time_t shm_atime; /* last attach time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused1; -#endif - __kernel_time_t shm_dtime; /* last detach time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused2; -#endif - __kernel_time_t shm_ctime; /* last change time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused3; -#endif - __kernel_pid_t shm_cpid; /* pid of creator */ - __kernel_pid_t shm_lpid; /* pid of last operator */ - unsigned long shm_nattch; /* no. of current attaches */ - unsigned long __unused4; - unsigned long __unused5; -}; - -struct shminfo64 { - unsigned long shmmax; - unsigned long shmmin; - unsigned long shmmni; - unsigned long shmseg; - unsigned long shmall; - unsigned long __unused1; - unsigned long __unused2; - unsigned long __unused3; - unsigned long __unused4; -}; - -#endif /* __ASM_GENERIC_SHMBUF_H */ +#include diff --git a/arch/x86/include/asm/socket.h b/arch/x86/include/asm/socket.h index d4ae42a..6b71384 100644 --- a/arch/x86/include/asm/socket.h +++ b/arch/x86/include/asm/socket.h @@ -1,60 +1 @@ -#ifndef __ASM_GENERIC_SOCKET_H -#define __ASM_GENERIC_SOCKET_H - -#include - -/* For setsockopt(2) */ -#define SOL_SOCKET 1 - -#define SO_DEBUG 1 -#define SO_REUSEADDR 2 -#define SO_TYPE 3 -#define SO_ERROR 4 -#define SO_DONTROUTE 5 -#define SO_BROADCAST 6 -#define SO_SNDBUF 7 -#define SO_RCVBUF 8 -#define SO_SNDBUFFORCE 32 -#define SO_RCVBUFFORCE 33 -#define SO_KEEPALIVE 9 -#define SO_OOBINLINE 10 -#define SO_NO_CHECK 11 -#define SO_PRIORITY 12 -#define SO_LINGER 13 -#define SO_BSDCOMPAT 14 -/* To add :#define SO_REUSEPORT 15 */ -#define SO_PASSCRED 16 -#define SO_PEERCRED 17 -#define SO_RCVLOWAT 18 -#define SO_SNDLOWAT 19 -#define SO_RCVTIMEO 20 -#define SO_SNDTIMEO 21 - -/* Security levels - as per NRL IPv6 - don't actually do anything */ -#define SO_SECURITY_AUTHENTICATION 22 -#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 -#define SO_SECURITY_ENCRYPTION_NETWORK 24 - -#define SO_BINDTODEVICE 25 - -/* Socket filtering */ -#define SO_ATTACH_FILTER 26 -#define SO_DETACH_FILTER 27 - -#define SO_PEERNAME 28 -#define SO_TIMESTAMP 29 -#define SCM_TIMESTAMP SO_TIMESTAMP - -#define SO_ACCEPTCONN 30 - -#define SO_PEERSEC 31 -#define SO_PASSSEC 34 -#define SO_TIMESTAMPNS 35 -#define SCM_TIMESTAMPNS SO_TIMESTAMPNS - -#define SO_MARK 36 - -#define SO_TIMESTAMPING 37 -#define SCM_TIMESTAMPING SO_TIMESTAMPING - -#endif /* __ASM_GENERIC_SOCKET_H */ +#include diff --git a/arch/x86/include/asm/sockios.h b/arch/x86/include/asm/sockios.h index 9a61a36..def6d47 100644 --- a/arch/x86/include/asm/sockios.h +++ b/arch/x86/include/asm/sockios.h @@ -1,13 +1 @@ -#ifndef __ASM_GENERIC_SOCKIOS_H -#define __ASM_GENERIC_SOCKIOS_H - -/* Socket-level I/O control calls. */ -#define FIOSETOWN 0x8901 -#define SIOCSPGRP 0x8902 -#define FIOGETOWN 0x8903 -#define SIOCGPGRP 0x8904 -#define SIOCATMARK 0x8905 -#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ -#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ - -#endif /* __ASM_GENERIC_SOCKIOS_H */ +#include diff --git a/arch/x86/include/asm/termbits.h b/arch/x86/include/asm/termbits.h index 1c9773d..3935b10 100644 --- a/arch/x86/include/asm/termbits.h +++ b/arch/x86/include/asm/termbits.h @@ -1,198 +1 @@ -#ifndef __ASM_GENERIC_TERMBITS_H -#define __ASM_GENERIC_TERMBITS_H - -#include - -typedef unsigned char cc_t; -typedef unsigned int speed_t; -typedef unsigned int tcflag_t; - -#define NCCS 19 -struct termios { - tcflag_t c_iflag; /* input mode flags */ - tcflag_t c_oflag; /* output mode flags */ - tcflag_t c_cflag; /* control mode flags */ - tcflag_t c_lflag; /* local mode flags */ - cc_t c_line; /* line discipline */ - cc_t c_cc[NCCS]; /* control characters */ -}; - -struct termios2 { - tcflag_t c_iflag; /* input mode flags */ - tcflag_t c_oflag; /* output mode flags */ - tcflag_t c_cflag; /* control mode flags */ - tcflag_t c_lflag; /* local mode flags */ - cc_t c_line; /* line discipline */ - cc_t c_cc[NCCS]; /* control characters */ - speed_t c_ispeed; /* input speed */ - speed_t c_ospeed; /* output speed */ -}; - -struct ktermios { - tcflag_t c_iflag; /* input mode flags */ - tcflag_t c_oflag; /* output mode flags */ - tcflag_t c_cflag; /* control mode flags */ - tcflag_t c_lflag; /* local mode flags */ - cc_t c_line; /* line discipline */ - cc_t c_cc[NCCS]; /* control characters */ - speed_t c_ispeed; /* input speed */ - speed_t c_ospeed; /* output speed */ -}; - -/* c_cc characters */ -#define VINTR 0 -#define VQUIT 1 -#define VERASE 2 -#define VKILL 3 -#define VEOF 4 -#define VTIME 5 -#define VMIN 6 -#define VSWTC 7 -#define VSTART 8 -#define VSTOP 9 -#define VSUSP 10 -#define VEOL 11 -#define VREPRINT 12 -#define VDISCARD 13 -#define VWERASE 14 -#define VLNEXT 15 -#define VEOL2 16 - -/* c_iflag bits */ -#define IGNBRK 0000001 -#define BRKINT 0000002 -#define IGNPAR 0000004 -#define PARMRK 0000010 -#define INPCK 0000020 -#define ISTRIP 0000040 -#define INLCR 0000100 -#define IGNCR 0000200 -#define ICRNL 0000400 -#define IUCLC 0001000 -#define IXON 0002000 -#define IXANY 0004000 -#define IXOFF 0010000 -#define IMAXBEL 0020000 -#define IUTF8 0040000 - -/* c_oflag bits */ -#define OPOST 0000001 -#define OLCUC 0000002 -#define ONLCR 0000004 -#define OCRNL 0000010 -#define ONOCR 0000020 -#define ONLRET 0000040 -#define OFILL 0000100 -#define OFDEL 0000200 -#define NLDLY 0000400 -#define NL0 0000000 -#define NL1 0000400 -#define CRDLY 0003000 -#define CR0 0000000 -#define CR1 0001000 -#define CR2 0002000 -#define CR3 0003000 -#define TABDLY 0014000 -#define TAB0 0000000 -#define TAB1 0004000 -#define TAB2 0010000 -#define TAB3 0014000 -#define XTABS 0014000 -#define BSDLY 0020000 -#define BS0 0000000 -#define BS1 0020000 -#define VTDLY 0040000 -#define VT0 0000000 -#define VT1 0040000 -#define FFDLY 0100000 -#define FF0 0000000 -#define FF1 0100000 - -/* c_cflag bit meaning */ -#define CBAUD 0010017 -#define B0 0000000 /* hang up */ -#define B50 0000001 -#define B75 0000002 -#define B110 0000003 -#define B134 0000004 -#define B150 0000005 -#define B200 0000006 -#define B300 0000007 -#define B600 0000010 -#define B1200 0000011 -#define B1800 0000012 -#define B2400 0000013 -#define B4800 0000014 -#define B9600 0000015 -#define B19200 0000016 -#define B38400 0000017 -#define EXTA B19200 -#define EXTB B38400 -#define CSIZE 0000060 -#define CS5 0000000 -#define CS6 0000020 -#define CS7 0000040 -#define CS8 0000060 -#define CSTOPB 0000100 -#define CREAD 0000200 -#define PARENB 0000400 -#define PARODD 0001000 -#define HUPCL 0002000 -#define CLOCAL 0004000 -#define CBAUDEX 0010000 -#define BOTHER 0010000 -#define B57600 0010001 -#define B115200 0010002 -#define B230400 0010003 -#define B460800 0010004 -#define B500000 0010005 -#define B576000 0010006 -#define B921600 0010007 -#define B1000000 0010010 -#define B1152000 0010011 -#define B1500000 0010012 -#define B2000000 0010013 -#define B2500000 0010014 -#define B3000000 0010015 -#define B3500000 0010016 -#define B4000000 0010017 -#define CIBAUD 002003600000 /* input baud rate */ -#define CMSPAR 010000000000 /* mark or space (stick) parity */ -#define CRTSCTS 020000000000 /* flow control */ - -#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ - -/* c_lflag bits */ -#define ISIG 0000001 -#define ICANON 0000002 -#define XCASE 0000004 -#define ECHO 0000010 -#define ECHOE 0000020 -#define ECHOK 0000040 -#define ECHONL 0000100 -#define NOFLSH 0000200 -#define TOSTOP 0000400 -#define ECHOCTL 0001000 -#define ECHOPRT 0002000 -#define ECHOKE 0004000 -#define FLUSHO 0010000 -#define PENDIN 0040000 -#define IEXTEN 0100000 - -/* tcflow() and TCXONC use these */ -#define TCOOFF 0 -#define TCOON 1 -#define TCIOFF 2 -#define TCION 3 - -/* tcflush() and TCFLSH use these */ -#define TCIFLUSH 0 -#define TCOFLUSH 1 -#define TCIOFLUSH 2 - -/* tcsetattr uses these */ -#define TCSANOW 0 -#define TCSADRAIN 1 -#define TCSAFLUSH 2 - -#endif /* __ASM_GENERIC_TERMBITS_H */ +#include diff --git a/arch/x86/include/asm/termios.h b/arch/x86/include/asm/termios.h index d0922ad..280d78a 100644 --- a/arch/x86/include/asm/termios.h +++ b/arch/x86/include/asm/termios.h @@ -1,154 +1 @@ -#ifndef _ASM_GENERIC_TERMIOS_H -#define _ASM_GENERIC_TERMIOS_H -/* - * Most architectures have straight copies of the x86 code, with - * varying levels of bug fixes on top. Usually it's a good idea - * to use this generic version instead, but be careful to avoid - * ABI changes. - * New architectures should not provide their own version. - */ - -#include -#include - -struct winsize { - unsigned short ws_row; - unsigned short ws_col; - unsigned short ws_xpixel; - unsigned short ws_ypixel; -}; - -#define NCC 8 -struct termio { - unsigned short c_iflag; /* input mode flags */ - unsigned short c_oflag; /* output mode flags */ - unsigned short c_cflag; /* control mode flags */ - unsigned short c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[NCC]; /* control characters */ -}; - -/* modem lines */ -#define TIOCM_LE 0x001 -#define TIOCM_DTR 0x002 -#define TIOCM_RTS 0x004 -#define TIOCM_ST 0x008 -#define TIOCM_SR 0x010 -#define TIOCM_CTS 0x020 -#define TIOCM_CAR 0x040 -#define TIOCM_RNG 0x080 -#define TIOCM_DSR 0x100 -#define TIOCM_CD TIOCM_CAR -#define TIOCM_RI TIOCM_RNG -#define TIOCM_OUT1 0x2000 -#define TIOCM_OUT2 0x4000 -#define TIOCM_LOOP 0x8000 - -/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ - -#ifdef __KERNEL__ - -#include - -/* intr=^C quit=^\ erase=del kill=^U - eof=^D vtime=\0 vmin=\1 sxtc=\0 - start=^Q stop=^S susp=^Z eol=\0 - reprint=^R discard=^U werase=^W lnext=^V - eol2=\0 -*/ -#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" - -/* - * Translate a "termio" structure into a "termios". Ugh. - */ -static inline int user_termio_to_kernel_termios(struct ktermios *termios, - const struct termio __user *termio) -{ - unsigned short tmp; - - if (get_user(tmp, &termio->c_iflag) < 0) - goto fault; - termios->c_iflag = (0xffff0000 & termios->c_iflag) | tmp; - - if (get_user(tmp, &termio->c_oflag) < 0) - goto fault; - termios->c_oflag = (0xffff0000 & termios->c_oflag) | tmp; - - if (get_user(tmp, &termio->c_cflag) < 0) - goto fault; - termios->c_cflag = (0xffff0000 & termios->c_cflag) | tmp; - - if (get_user(tmp, &termio->c_lflag) < 0) - goto fault; - termios->c_lflag = (0xffff0000 & termios->c_lflag) | tmp; - - if (get_user(termios->c_line, &termio->c_line) < 0) - goto fault; - - if (copy_from_user(termios->c_cc, termio->c_cc, NCC) != 0) - goto fault; - - return 0; - - fault: - return -EFAULT; -} - -/* - * Translate a "termios" structure into a "termio". Ugh. - */ -static inline int kernel_termios_to_user_termio(struct termio __user *termio, - struct ktermios *termios) -{ - if (put_user(termios->c_iflag, &termio->c_iflag) < 0 || - put_user(termios->c_oflag, &termio->c_oflag) < 0 || - put_user(termios->c_cflag, &termio->c_cflag) < 0 || - put_user(termios->c_lflag, &termio->c_lflag) < 0 || - put_user(termios->c_line, &termio->c_line) < 0 || - copy_to_user(termio->c_cc, termios->c_cc, NCC) != 0) - return -EFAULT; - - return 0; -} - -#ifdef TCGETS2 -static inline int user_termios_to_kernel_termios(struct ktermios *k, - struct termios2 __user *u) -{ - return copy_from_user(k, u, sizeof(struct termios2)); -} - -static inline int kernel_termios_to_user_termios(struct termios2 __user *u, - struct ktermios *k) -{ - return copy_to_user(u, k, sizeof(struct termios2)); -} - -static inline int user_termios_to_kernel_termios_1(struct ktermios *k, - struct termios __user *u) -{ - return copy_from_user(k, u, sizeof(struct termios)); -} - -static inline int kernel_termios_to_user_termios_1(struct termios __user *u, - struct ktermios *k) -{ - return copy_to_user(u, k, sizeof(struct termios)); -} -#else /* TCGETS2 */ -static inline int user_termios_to_kernel_termios(struct ktermios *k, - struct termios __user *u) -{ - return copy_from_user(k, u, sizeof(struct termios)); -} - -static inline int kernel_termios_to_user_termios(struct termios __user *u, - struct ktermios *k) -{ - return copy_to_user(u, k, sizeof(struct termios)); -} -#endif /* TCGETS2 */ - -#endif /* __KERNEL__ */ - -#endif /* _ASM_GENERIC_TERMIOS_H */ +#include diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h index f2fe528..df1da20 100644 --- a/arch/x86/include/asm/types.h +++ b/arch/x86/include/asm/types.h @@ -3,7 +3,7 @@ #define dma_addr_t dma_addr_t -#include +#include #ifdef __KERNEL__ #ifndef __ASSEMBLY__ diff --git a/arch/x86/include/asm/ucontext.h b/arch/x86/include/asm/ucontext.h index 7cfc436..b7c29c8 100644 --- a/arch/x86/include/asm/ucontext.h +++ b/arch/x86/include/asm/ucontext.h @@ -7,6 +7,6 @@ * sigcontext struct (uc_mcontext). */ -#include +#include #endif /* _ASM_X86_UCONTEXT_H */ -- cgit v0.10.2 From ccf135f509abdbf607e9a68f08ddeee2c66dc36e Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 19 Jun 2009 10:29:34 +0900 Subject: TOMOYO: Move tomoyo_delete_domain(). We can mark tomoyo_delete_domain() as a "static" function by moving it from domain.c to common.c . Signed-off-by: Tetsuo Handa Signed-off-by: James Morris diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index fdd1f4b..3c8bd8e 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -1285,6 +1285,36 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, } /** + * tomoyo_delete_domain - Delete a domain. + * + * @domainname: The name of domain. + * + * Returns 0. + */ +static int tomoyo_delete_domain(char *domainname) +{ + struct tomoyo_domain_info *domain; + struct tomoyo_path_info name; + + name.name = domainname; + tomoyo_fill_path_info(&name); + down_write(&tomoyo_domain_list_lock); + /* Is there an active domain? */ + list_for_each_entry(domain, &tomoyo_domain_list, list) { + /* Never delete tomoyo_kernel_domain */ + if (domain == &tomoyo_kernel_domain) + continue; + if (domain->is_deleted || + tomoyo_pathcmp(domain->domainname, &name)) + continue; + domain->is_deleted = true; + break; + } + up_write(&tomoyo_domain_list_lock); + return 0; +} + +/** * tomoyo_write_domain_policy - Write domain policy. * * @head: Pointer to "struct tomoyo_io_buffer". diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 6d6ba09..31df541 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -339,8 +339,6 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); const char *tomoyo_get_msg(const bool is_enforce); /* Convert single path operation to operation name. */ const char *tomoyo_sp2keyword(const u8 operation); -/* Delete a domain. */ -int tomoyo_delete_domain(char *data); /* Create "alias" entry in exception policy. */ int tomoyo_write_alias_policy(char *data, const bool is_delete); /* diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 1d8b169..e68b105 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -717,38 +717,6 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete) return tomoyo_update_alias_entry(data, cp, is_delete); } -/* Domain create/delete handler. */ - -/** - * tomoyo_delete_domain - Delete a domain. - * - * @domainname: The name of domain. - * - * Returns 0. - */ -int tomoyo_delete_domain(char *domainname) -{ - struct tomoyo_domain_info *domain; - struct tomoyo_path_info name; - - name.name = domainname; - tomoyo_fill_path_info(&name); - down_write(&tomoyo_domain_list_lock); - /* Is there an active domain? */ - list_for_each_entry(domain, &tomoyo_domain_list, list) { - /* Never delete tomoyo_kernel_domain */ - if (domain == &tomoyo_kernel_domain) - continue; - if (domain->is_deleted || - tomoyo_pathcmp(domain->domainname, &name)) - continue; - domain->is_deleted = true; - break; - } - up_write(&tomoyo_domain_list_lock); - return 0; -} - /** * tomoyo_find_or_assign_new_domain - Create a domain. * -- cgit v0.10.2 From 56f8c9bc410deb55f21698e6a0d59f559ae1d794 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 19 Jun 2009 14:13:27 +0900 Subject: TOMOYO: Remove next_domain from tomoyo_find_next_domain(). We can update bprm->cred->security inside tomoyo_find_next_domain(). Signed-off-by: Tetsuo Handa Signed-off-by: James Morris diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index e68b105..fcf52ac 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -786,13 +786,11 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * /** * tomoyo_find_next_domain - Find a domain. * - * @bprm: Pointer to "struct linux_binprm". - * @next_domain: Pointer to pointer to "struct tomoyo_domain_info". + * @bprm: Pointer to "struct linux_binprm". * * Returns 0 on success, negative value otherwise. */ -int tomoyo_find_next_domain(struct linux_binprm *bprm, - struct tomoyo_domain_info **next_domain) +int tomoyo_find_next_domain(struct linux_binprm *bprm) { /* * This function assumes that the size of buffer returned by @@ -914,9 +912,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm, tomoyo_set_domain_flag(old_domain, false, TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); out: + if (!domain) + domain = old_domain; + bprm->cred->security = domain; tomoyo_free(real_program_name); tomoyo_free(symlink_program_name); - *next_domain = domain ? domain : old_domain; tomoyo_free(tmp); return retval; } diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 3194d09..35a13e7 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -61,14 +61,8 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) * Execute permission is checked against pathname passed to do_execve() * using current domain. */ - if (!domain) { - struct tomoyo_domain_info *next_domain = NULL; - int retval = tomoyo_find_next_domain(bprm, &next_domain); - - if (!retval) - bprm->cred->security = next_domain; - return retval; - } + if (!domain) + return tomoyo_find_next_domain(bprm); /* * Read permission is checked against interpreters using next domain. * '1' is the result of open_to_namei_flags(O_RDONLY). diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h index 0fd588a..cd6ba0b 100644 --- a/security/tomoyo/tomoyo.h +++ b/security/tomoyo/tomoyo.h @@ -31,8 +31,7 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain, struct path *path2); int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, struct file *filp); -int tomoyo_find_next_domain(struct linux_binprm *bprm, - struct tomoyo_domain_info **next_domain); +int tomoyo_find_next_domain(struct linux_binprm *bprm); /* Index numbers for Access Controls. */ -- cgit v0.10.2 From a873a5f1c4eda125f506c059a4f8ea48b9f42eff Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 19 Jun 2009 19:46:53 +0800 Subject: crypto: tcrypt - Test algorithms by name This adds the 'alg' module parameter to be able to test an algorithm by name. If the algorithm type is not ad-hoc clear for a algorithm (e.g. pcrypt, cryptd) it is possilbe to set the algorithm type with the 'type' module parameter. Signed-off-by: Steffen Klassert Signed-off-by: Herbert Xu diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index d59ba50..dfeec0c 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -45,6 +45,8 @@ */ static unsigned int sec; +static char *alg = NULL; +static u32 type; static int mode; static char *tvmem[TVMEMSIZE]; @@ -885,6 +887,11 @@ static int do_test(int m) return ret; } +static int do_alg_test(const char *alg, u32 type) +{ + return crypto_has_alg(alg, type, CRYPTO_ALG_TYPE_MASK); +} + static int __init tcrypt_mod_init(void) { int err = -ENOMEM; @@ -896,7 +903,11 @@ static int __init tcrypt_mod_init(void) goto err_free_tv; } - err = do_test(mode); + if (alg) + err = do_alg_test(alg, type); + else + err = do_test(mode); + if (err) { printk(KERN_ERR "tcrypt: one or more tests failed!\n"); goto err_free_tv; @@ -928,6 +939,8 @@ static void __exit tcrypt_mod_fini(void) { } module_init(tcrypt_mod_init); module_exit(tcrypt_mod_fini); +module_param(alg, charp, 0); +module_param(type, uint, 0); module_param(mode, int, 0); module_param(sec, uint, 0); MODULE_PARM_DESC(sec, "Length in seconds of speed tests " -- cgit v0.10.2 From 27300176d75e4723e2125e745a98a77bf0133f72 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 19 Jun 2009 20:32:58 +0800 Subject: crypto: ansi_cprng - Do not select FIPS The RNG should work with FIPS disabled. Signed-off-by: Herbert Xu diff --git a/crypto/Kconfig b/crypto/Kconfig index 4dfdd03..03ef1a9 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -782,7 +782,6 @@ config CRYPTO_ANSI_CPRNG tristate "Pseudo Random Number Generation for Cryptographic modules" select CRYPTO_AES select CRYPTO_RNG - select CRYPTO_FIPS help This option enables the generic pseudo random number generator for cryptographic modules. Uses the Algorithm specified in -- cgit v0.10.2 From ea4006576945195ed35824acfb4007ca7cb78b70 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 19 Jun 2009 20:37:00 +0800 Subject: crypto: tcrypt - Fix module return code when testing by name We should return 0/-ENOENT instead of 1/0 when testing by name. Signed-off-by: Herbert Xu diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index dfeec0c..a890a6792 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -889,7 +889,7 @@ static int do_test(int m) static int do_alg_test(const char *alg, u32 type) { - return crypto_has_alg(alg, type, CRYPTO_ALG_TYPE_MASK); + return crypto_has_alg(alg, type, CRYPTO_ALG_TYPE_MASK) ? 0 : -ENOENT; } static int __init tcrypt_mod_init(void) -- cgit v0.10.2 From b53109db5e016425b767e8e33669a5f41257e6e5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 20 Jun 2009 13:53:20 +0100 Subject: ASoC: Fix shadowed variables in twl4030 No need to define second copies of mode and format, they're declared with exactly the same type at the head of the function and there's no conflict in their use. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 4dbb853..a5062cc 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1609,8 +1609,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, /* If the substream has 4 channel, do the necessary setup */ if (params_channels(params) == 4) { - u8 format, mode; - format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); -- cgit v0.10.2 From 423c238d7185a0a8f1b28ddb0be44e0286927909 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 20 Jun 2009 13:54:02 +0100 Subject: ASoC: Staticise put_twl4030_opmode_enum_double() It's an operation for a control and doesn't need to be exported. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index a5062cc..4275eea 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -924,7 +924,7 @@ static const struct soc_enum twl4030_op_modes_enum = ARRAY_SIZE(twl4030_op_modes_texts), twl4030_op_modes_texts); -int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, +static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); -- cgit v0.10.2 From feaa0457ec8351cae855edc9a3052ac49322538e Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sat, 20 Jun 2009 16:15:40 +0530 Subject: x86: ds.c fix invalid assignment Fixes the type mixups that cause the following sparse warnings: CHECK arch/x86/kernel/ds.c arch/x86/kernel/ds.c:549:19: warning: incorrect type in argument 2 (invalid types) arch/x86/kernel/ds.c:549:19: expected bad type enum bts_field field arch/x86/kernel/ds.c:549:19: got int arch/x86/kernel/ds.c:514:35: error: incompatible types for operation (*) arch/x86/kernel/ds.c:514:35: left side has type unsigned char static [unsigned] [toplevel] sizeof_ptr_field arch/x86/kernel/ds.c:514:35: right side has type bad type enum bts_field field arch/x86/kernel/ds.c:514:7: error: invalid assignment arch/x86/kernel/ds.c:514:35: error: incompatible types for operation (*) arch/x86/kernel/ds.c:514:35: left side has type unsigned char static [unsigned] [toplevel] sizeof_ptr_field arch/x86/kernel/ds.c:514:35: right side has type bad type enum bts_field field arch/x86/kernel/ds.c:514:7: error: invalid assignment arch/x86/kernel/ds.c:514:35: error: incompatible types for operation (*) arch/x86/kernel/ds.c:514:35: left side has type unsigned char static [unsigned] [toplevel] sizeof_ptr_field arch/x86/kernel/ds.c:514:35: right side has type bad type enum bts_field field arch/x86/kernel/ds.c:514:7: error: invalid assignment arch/x86/kernel/ds.c:514:35: error: incompatible types for operation (*) arch/x86/kernel/ds.c:514:35: left side has type unsigned char static [unsigned] [toplevel] sizeof_ptr_field arch/x86/kernel/ds.c:514:35: right side has type bad type enum bts_field field arch/x86/kernel/ds.c:514:7: error: invalid assignment arch/x86/kernel/ds.c:514:35: error: incompatible types for operation (*) arch/x86/kernel/ds.c:514:35: left side has type unsigned char static [unsigned] [toplevel] sizeof_ptr_field arch/x86/kernel/ds.c:514:35: right side has type bad type enum bts_field field arch/x86/kernel/ds.c:514:7: error: invalid assignment arch/x86/kernel/ds.c:514:35: error: incompatible types for operation (*) arch/x86/kernel/ds.c:514:35: left side has type unsigned char static [unsigned] [toplevel] sizeof_ptr_field arch/x86/kernel/ds.c:514:35: right side has type bad type enum bts_field field arch/x86/kernel/ds.c:514:7: error: invalid assignment arch/x86/kernel/ds.c:520:35: error: incompatible types for operation (*) arch/x86/kernel/ds.c:520:35: left side has type unsigned char static [unsigned] [toplevel] sizeof_ptr_field arch/x86/kernel/ds.c:520:35: right side has type bad type enum bts_field field arch/x86/kernel/ds.c:520:7: error: invalid assignment arch/x86/kernel/ds.c:520:35: error: incompatible types for operation (*) Signed-off-by: Jaswinder Singh Rajput Cc: Markus Metzger LKML-Reference: <1245494740.8613.12.camel@localhost.localdomain> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c index 48bfe13..ef42a03 100644 --- a/arch/x86/kernel/ds.c +++ b/arch/x86/kernel/ds.c @@ -509,15 +509,15 @@ enum bts_field { bts_escape = ((unsigned long)-1 & ~bts_qual_mask) }; -static inline unsigned long bts_get(const char *base, enum bts_field field) +static inline unsigned long bts_get(const char *base, unsigned long field) { base += (ds_cfg.sizeof_ptr_field * field); return *(unsigned long *)base; } -static inline void bts_set(char *base, enum bts_field field, unsigned long val) +static inline void bts_set(char *base, unsigned long field, unsigned long val) { - base += (ds_cfg.sizeof_ptr_field * field);; + base += (ds_cfg.sizeof_ptr_field * field); (*(unsigned long *)base) = val; } -- cgit v0.10.2 From f274143f127dd9420e6def7dc47340b55f29c885 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Sat, 20 Jun 2009 11:29:56 -0400 Subject: ASoC: Blackfin: convert internal names from bf52x to bf5xx These drivers aren't BF52x specific, so don't use bf52x in the names. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger Signed-off-by: Mark Brown diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index edfbdc0..9825b71 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -203,23 +203,23 @@ static struct snd_soc_device bf5xx_ad73311_snd_devdata = { .codec_dev = &soc_codec_dev_ad73311, }; -static struct platform_device *bf52x_ad73311_snd_device; +static struct platform_device *bf5xx_ad73311_snd_device; static int __init bf5xx_ad73311_init(void) { int ret; pr_debug("%s enter\n", __func__); - bf52x_ad73311_snd_device = platform_device_alloc("soc-audio", -1); - if (!bf52x_ad73311_snd_device) + bf5xx_ad73311_snd_device = platform_device_alloc("soc-audio", -1); + if (!bf5xx_ad73311_snd_device) return -ENOMEM; - platform_set_drvdata(bf52x_ad73311_snd_device, &bf5xx_ad73311_snd_devdata); - bf5xx_ad73311_snd_devdata.dev = &bf52x_ad73311_snd_device->dev; - ret = platform_device_add(bf52x_ad73311_snd_device); + platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311_snd_devdata); + bf5xx_ad73311_snd_devdata.dev = &bf5xx_ad73311_snd_device->dev; + ret = platform_device_add(bf5xx_ad73311_snd_device); if (ret) - platform_device_put(bf52x_ad73311_snd_device); + platform_device_put(bf5xx_ad73311_snd_device); return ret; } @@ -227,7 +227,7 @@ static int __init bf5xx_ad73311_init(void) static void __exit bf5xx_ad73311_exit(void) { pr_debug("%s enter\n", __func__); - platform_device_unregister(bf52x_ad73311_snd_device); + platform_device_unregister(bf5xx_ad73311_snd_device); } module_init(bf5xx_ad73311_init); diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index bc0cdde..3a00fa4 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c @@ -148,24 +148,24 @@ static struct snd_soc_device bf5xx_ssm2602_snd_devdata = { .codec_data = &bf5xx_ssm2602_setup, }; -static struct platform_device *bf52x_ssm2602_snd_device; +static struct platform_device *bf5xx_ssm2602_snd_device; static int __init bf5xx_ssm2602_init(void) { int ret; pr_debug("%s enter\n", __func__); - bf52x_ssm2602_snd_device = platform_device_alloc("soc-audio", -1); - if (!bf52x_ssm2602_snd_device) + bf5xx_ssm2602_snd_device = platform_device_alloc("soc-audio", -1); + if (!bf5xx_ssm2602_snd_device) return -ENOMEM; - platform_set_drvdata(bf52x_ssm2602_snd_device, + platform_set_drvdata(bf5xx_ssm2602_snd_device, &bf5xx_ssm2602_snd_devdata); - bf5xx_ssm2602_snd_devdata.dev = &bf52x_ssm2602_snd_device->dev; - ret = platform_device_add(bf52x_ssm2602_snd_device); + bf5xx_ssm2602_snd_devdata.dev = &bf5xx_ssm2602_snd_device->dev; + ret = platform_device_add(bf5xx_ssm2602_snd_device); if (ret) - platform_device_put(bf52x_ssm2602_snd_device); + platform_device_put(bf5xx_ssm2602_snd_device); return ret; } @@ -173,7 +173,7 @@ static int __init bf5xx_ssm2602_init(void) static void __exit bf5xx_ssm2602_exit(void) { pr_debug("%s enter\n", __func__); - platform_device_unregister(bf52x_ssm2602_snd_device); + platform_device_unregister(bf5xx_ssm2602_snd_device); } module_init(bf5xx_ssm2602_init); -- cgit v0.10.2 From 215ccd6f55a2144bd553e0a3d12e1386f02309fd Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Sun, 21 Jun 2009 21:38:03 +0800 Subject: crypto: fips - Select CPRNG The ANSI CPRNG has no dependence on FIPS support. FIPS support however, requires the use of the CPRNG. Adjust that depedency relationship in Kconfig. Signed-off-by: Neil Horman Signed-off-by: Herbert Xu diff --git a/crypto/Kconfig b/crypto/Kconfig index 03ef1a9..f2002d8 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -23,6 +23,7 @@ comment "Crypto core or helper" config CRYPTO_FIPS bool "FIPS 200 compliance" + select CRYPTO_ANSI_CPRNG help This options enables the fips boot option which is required if you want to system to operate in a FIPS 200 -- cgit v0.10.2 From c264301c777840b2df130e042b7f5a0c1041646f Mon Sep 17 00:00:00 2001 From: "Lopez Cruz, Misael" Date: Fri, 19 Jun 2009 03:23:42 -0500 Subject: ASoC: TWL4030: Fix voice interface clock masters Voice interface of twl4030 codec supports: CBM_CFM and CBS_CFS. It doesn't support CBS_CFM. Signed-off-by: Misael Lopez Cruz Acked-By: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 4275eea..091125c 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1946,7 +1946,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBM_CFM: format &= ~(TWL4030_VIF_SLAVE_EN); break; case SND_SOC_DAIFMT_CBS_CFS: diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index b719e5d..c51594d 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -96,7 +96,7 @@ static int sdp3430_hw_voice_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBS_CFM); + SND_SOC_DAIFMT_CBM_CFM); if (ret) { printk(KERN_ERR "can't set codec DAI configuration\n"); return ret; diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index be2e307..3de6d2b 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c @@ -92,7 +92,7 @@ static int zoom2_hw_voice_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBS_CFM); + SND_SOC_DAIFMT_CBM_CFM); if (ret) { printk(KERN_ERR "can't set codec DAI configuration\n"); return ret; -- cgit v0.10.2 From 20dda18be9035c487c2e9534e4d18d2a1e1deade Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 22 Jun 2009 14:54:53 -0400 Subject: selinux: restore optimization to selinux_file_permission Restore the optimization to skip revalidation in selinux_file_permission if nothing has changed since the dentry_open checks, accidentally removed by 389fb800. Also remove redundant test from selinux_revalidate_file_permission. Signed-off-by: Stephen Smalley Reviewed-by: Paul Moore Acked-by: Eric Paris Signed-off-by: James Morris diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 15c2a08..d6f6478 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2938,11 +2938,6 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) const struct cred *cred = current_cred(); struct inode *inode = file->f_path.dentry->d_inode; - if (!mask) { - /* No permission to check. Existence test. */ - return 0; - } - /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */ if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) mask |= MAY_APPEND; @@ -2953,10 +2948,20 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) static int selinux_file_permission(struct file *file, int mask) { + struct inode *inode = file->f_path.dentry->d_inode; + struct file_security_struct *fsec = file->f_security; + struct inode_security_struct *isec = inode->i_security; + u32 sid = current_sid(); + if (!mask) /* No permission to check. Existence test. */ return 0; + if (sid == fsec->sid && fsec->isid == isec->sid && + fsec->pseqno == avc_policy_seqno()) + /* No change since dentry_open check. */ + return 0; + return selinux_revalidate_file_permission(file, mask); } -- cgit v0.10.2 From 328d0a138e3d7761f4db53fabf82279b90ea66dd Mon Sep 17 00:00:00 2001 From: "Lopez Cruz, Misael" Date: Mon, 22 Jun 2009 10:51:52 -0500 Subject: ASoC: TWL4030: Add AVADC Clock Priority AVDAC clk priority allows to determine the path ADC must be connected when the codec is in option2 and both HiFi and Voice paths are enabled. Signed-off-by: Misael Lopez Cruz Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 091125c..f916a9a 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1005,6 +1005,16 @@ static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); */ static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); +/* AVADC clock priority */ +static const char *twl4030_avadc_clk_priority_texts[] = { + "Voice high priority", "HiFi high priority" +}; + +static const struct soc_enum twl4030_avadc_clk_priority_enum = + SOC_ENUM_SINGLE(TWL4030_REG_AVADC_CTL, 2, + ARRAY_SIZE(twl4030_avadc_clk_priority_texts), + twl4030_avadc_clk_priority_texts); + static const char *twl4030_rampdelay_texts[] = { "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms", "437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms", @@ -1106,6 +1116,8 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN, 0, 3, 5, 0, input_gain_tlv), + SOC_ENUM("AVADC Clock Priority", twl4030_avadc_clk_priority_enum), + SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum), SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum), -- cgit v0.10.2 From 30808ca751c3b8d81e948efb8fed7451a8321010 Mon Sep 17 00:00:00 2001 From: "Lopez Cruz, Misael" Date: Mon, 22 Jun 2009 19:34:07 -0500 Subject: ASoC: TWL4030: Correct bypass event for voice sidetone Event for voice sidetone was being interpreted as an analog HiFi bypass event because VSTPGA register offset is less than ARXR2_APGA_CTL offset. Reordering the register checks allows to handle voice digital bypass event properly. Signed-off-by: Misael Lopez Cruz Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index f916a9a..df42fa2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -712,7 +712,19 @@ static int bypass_event(struct snd_soc_dapm_widget *w, reg = twl4030_read_reg_cache(w->codec, m->reg); - if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) { + /* + * bypass_state[0:3] - analog HiFi bypass + * bypass_state[4] - analog voice bypass + * bypass_state[5] - digital voice bypass + * bypass_state[6:7] - digital HiFi bypass + */ + if (m->reg == TWL4030_REG_VSTPGA) { + /* Voice digital bypass */ + if (reg) + twl4030->bypass_state |= (1 << 5); + else + twl4030->bypass_state &= ~(1 << 5); + } else if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) { /* Analog bypass */ if (reg & (1 << m->shift)) twl4030->bypass_state |= @@ -726,12 +738,6 @@ static int bypass_event(struct snd_soc_dapm_widget *w, twl4030->bypass_state |= (1 << 4); else twl4030->bypass_state &= ~(1 << 4); - } else if (m->reg == TWL4030_REG_VSTPGA) { - /* Voice digital bypass */ - if (reg) - twl4030->bypass_state |= (1 << 5); - else - twl4030->bypass_state &= ~(1 << 5); } else { /* Digital bypass */ if (reg & (0x7 << m->shift)) -- cgit v0.10.2 From 517374704da44c1ba77c1600714fe214524af286 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 22 Jun 2009 13:16:51 +0100 Subject: ASoC: Add a shutdown callback Ensure that the audio subsystem is powered down cleanly when the system shuts down by providing a shutdown operation. This ensures that all the components have been returned to an off state cleanly which should avoid audio issues from partially charged capacitors or noise on digital inputs if the system is restarted quickly. Signed-off-by: Mark Brown Tested-by: Ben Dooks diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index ec8a45f..35814ce 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -279,6 +279,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, /* dapm events */ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, int event); +void snd_soc_dapm_shutdown(struct snd_soc_device *socdev); /* dapm sys fs - used by the core */ int snd_soc_dapm_sys_add(struct device *dev); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4414117..55d45c4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1020,6 +1020,21 @@ static int soc_remove(struct platform_device *pdev) return 0; } +static void soc_shutdown(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_card *card = socdev->card; + + if (!card->instantiated) + return; + + /* Flush out pmdown_time work - we actually do want to run it + * now, we're shutting down so no imminent restart. */ + run_delayed_work(&card->delayed_work); + + snd_soc_dapm_shutdown(socdev); +} + /* ASoC platform driver */ static struct platform_driver soc_driver = { .driver = { @@ -1030,6 +1045,7 @@ static struct platform_driver soc_driver = { .remove = soc_remove, .suspend = soc_suspend, .resume = soc_resume, + .shutdown = soc_shutdown, }; /* create a new pcm */ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6534359..b9129ef 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2032,6 +2032,35 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev) } EXPORT_SYMBOL_GPL(snd_soc_dapm_free); +/* + * snd_soc_dapm_shutdown - callback for system shutdown + */ +void snd_soc_dapm_shutdown(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->card->codec; + struct snd_soc_dapm_widget *w; + LIST_HEAD(down_list); + int powerdown = 0; + + list_for_each_entry(w, &codec->dapm_widgets, list) { + if (w->power) { + dapm_seq_insert(w, &down_list, dapm_down_seq); + powerdown = 1; + } + } + + /* If there were no widgets to power down we're already in + * standby. + */ + if (powerdown) { + snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE); + dapm_seq_run(codec, &down_list, 0, dapm_down_seq); + snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY); + } + + snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF); +} + /* Module information */ MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC"); -- cgit v0.10.2 From c9944881acf02b6f25fa62a0441a98b7dc0d7ae6 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 24 Jun 2009 13:42:40 +0800 Subject: crypto: aes-ni - Don't print message with KERN_ERR on old system When the aes-intel module is loaded on a system that does not have the AES instructions, it prints Intel AES-NI instructions are not detected. at level KERN_ERR. Since aes-intel is aliased to "aes" it will be tried whenever anything uses AES and spam the console. This doesn't match existing practice for how to handle "no hardware" when initializing a module, so downgrade the message to KERN_INFO. Signed-off-by: Roland Dreier Signed-off-by: Herbert Xu diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index c580c5e..d3ec8d5 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -636,7 +636,7 @@ static int __init aesni_init(void) int err; if (!cpu_has_aes) { - printk(KERN_ERR "Intel AES-NI instructions are not detected.\n"); + printk(KERN_INFO "Intel AES-NI instructions are not detected.\n"); return -ENODEV; } if ((err = crypto_register_alg(&aesni_alg))) -- cgit v0.10.2 From 259c5e05c13daaaea039b5bf29a2674701cfd68e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 24 Jun 2009 13:48:13 +0800 Subject: crypto: testmgr - Remove hash size check Until hash test vectors grow longer than 256 bytes, the only purpose of the check is to generate a gcc warning. Signed-off-by: Herbert Xu diff --git a/crypto/testmgr.c b/crypto/testmgr.c index e9e9d84..f9bea9d 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -190,10 +190,6 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, hash_buff = xbuf[0]; - ret = -EINVAL; - if (WARN_ON(template[i].psize > PAGE_SIZE)) - goto out; - memcpy(hash_buff, template[i].plaintext, template[i].psize); sg_init_one(&sg[0], hash_buff, template[i].psize); -- cgit v0.10.2 From a1e21c9078fb8005e5accb921696ec9e2f38176e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 17 Jun 2009 09:33:52 +0200 Subject: ALSA: hda - Don't call snd_hda_codec_configure in snd_hda_codec_new() The codec setup call via snd_hda_codec_configure() isn't necessarily called in snd_hda_codec_new(). For the later added feature, it's better to change the code flow like: - create all codec instances - configure each codec Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 462e2ce..506f46e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -885,7 +885,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, * Returns 0 if successful, or a negative error code. */ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, - int do_init, struct hda_codec **codecp) + struct hda_codec **codecp) { struct hda_codec *codec; char component[31]; @@ -978,11 +978,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); - if (do_init) { - err = snd_hda_codec_configure(codec); - if (err < 0) - goto error; - } snd_hda_codec_proc_new(codec); snd_hda_create_hwdep(codec); @@ -1036,6 +1031,7 @@ int snd_hda_codec_configure(struct hda_codec *codec) err = init_unsol_queue(codec->bus); return err; } +EXPORT_SYMBOL_HDA(snd_hda_codec_configure); /** * snd_hda_codec_setup_stream - set up the codec for streaming diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index cad79ef..b7ca7d5 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -830,7 +830,8 @@ enum { int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, struct hda_bus **busp); int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, - int do_init, struct hda_codec **codecp); + struct hda_codec **codecp); +int snd_hda_codec_configure(struct hda_codec *codec); /* * low level functions diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4e9ea70..da58f2c 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1286,8 +1286,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { [AZX_DRIVER_TERA] = 1, }; -static int __devinit azx_codec_create(struct azx *chip, const char *model, - int no_init) +static int __devinit azx_codec_create(struct azx *chip, const char *model) { struct hda_bus_template bus_temp; int c, codecs, err; @@ -1346,7 +1345,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { struct hda_codec *codec; - err = snd_hda_codec_new(chip->bus, c, !no_init, &codec); + err = snd_hda_codec_new(chip->bus, c, &codec); if (err < 0) continue; codecs++; @@ -1356,7 +1355,16 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, snd_printk(KERN_ERR SFX "no codecs initialized\n"); return -ENXIO; } + return 0; +} +/* configure each codec instance */ +static int __devinit azx_codec_configure(struct azx *chip) +{ + struct hda_codec *codec; + list_for_each_entry(codec, &chip->bus->codec_list, list) { + snd_hda_codec_configure(codec); + } return 0; } @@ -2466,9 +2474,14 @@ static int __devinit azx_probe(struct pci_dev *pci, card->private_data = chip; /* create codec instances */ - err = azx_codec_create(chip, model[dev], probe_only[dev]); + err = azx_codec_create(chip, model[dev]); if (err < 0) goto out_free; + if (!probe_only[dev]) { + err = azx_codec_configure(chip); + if (err < 0) + goto out_free; + } /* create PCM streams */ err = snd_hda_build_pcms(chip->bus); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 8334901..75aa378 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -99,7 +99,6 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves); int snd_hda_codec_reset(struct hda_codec *codec); -int snd_hda_codec_configure(struct hda_codec *codec); /* amp value bits */ #define HDA_AMP_MUTE 0x80 -- cgit v0.10.2 From 4ea6fbc8eb23c3ae5fd2fb55a340ab85c8649bce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 17 Jun 2009 09:52:54 +0200 Subject: ALSA: hda - Add patch module option Added the patch module option to apply a "patch" as a firmware to modify pin configurations or give additional hints to the driver before actually initializing and configuring the codec. This can be used as a workaround when the BIOS doesn't give sufficient information or give wrong information that doesn't match with the real hardware setup, until it's fixed statically in the driver via a quirk. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 04438f1..b8a77f9 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -46,6 +46,20 @@ config SND_HDA_INPUT_JACK Say Y here to enable the jack plugging notification via input layer. +config SND_HDA_PATCH_LOADER + bool "Support initialization patch loading for HD-audio" + depends on EXPERIMENTAL + select FW_LOADER + select SND_HDA_HWDEP + select SND_HDA_RECONFIG + help + Say Y here to allow the HD-audio driver to load a pseudo + firmware file ("patch") for overriding the BIOS setup at + start up. The "patch" file can be specified via patch module + option, such as patch=hda-init. + + This option turns on hwdep and reconfig features automatically. + config SND_HDA_CODEC_REALTEK bool "Build Realtek HD-audio codec support" default y diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index b7ca7d5..72c9975 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -939,6 +939,13 @@ static inline void snd_hda_power_down(struct hda_codec *codec) {} #define snd_hda_codec_needs_resume(codec) 1 #endif +#ifdef CONFIG_SND_HDA_PATCH_LOADER +/* + * patch firmware + */ +int snd_hda_load_patch(struct hda_bus *bus, const char *patch); +#endif + /* * Codec modularization */ diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 6812fbe..cc24e67 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "hda_codec.h" #include "hda_local.h" @@ -312,12 +313,8 @@ static ssize_t init_verbs_show(struct device *dev, return len; } -static ssize_t init_verbs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int parse_init_verbs(struct hda_codec *codec, const char *buf) { - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; struct hda_verb *v; int nid, verb, param; @@ -331,6 +328,18 @@ static ssize_t init_verbs_store(struct device *dev, v->nid = nid; v->verb = verb; v->param = param; + return 0; +} + +static ssize_t init_verbs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + int err = parse_init_verbs(codec, buf); + if (err < 0) + return err; return count; } @@ -376,19 +385,15 @@ static void remove_trail_spaces(char *str) #define MAX_HINTS 1024 -static ssize_t hints_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int parse_hints(struct hda_codec *codec, const char *buf) { - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; char *key, *val; struct hda_hint *hint; while (isspace(*buf)) buf++; if (!*buf || *buf == '#' || *buf == '\n') - return count; + return 0; if (*buf == '=') return -EINVAL; key = kstrndup_noeol(buf, 1024); @@ -411,7 +416,7 @@ static ssize_t hints_store(struct device *dev, kfree(hint->key); hint->key = key; hint->val = val; - return count; + return 0; } /* allocate a new hint entry */ if (codec->hints.used >= MAX_HINTS) @@ -424,6 +429,18 @@ static ssize_t hints_store(struct device *dev, } hint->key = key; hint->val = val; + return 0; +} + +static ssize_t hints_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + int err = parse_hints(codec, buf); + if (err < 0) + return err; return count; } @@ -469,20 +486,24 @@ static ssize_t driver_pin_configs_show(struct device *dev, #define MAX_PIN_CONFIGS 32 -static ssize_t user_pin_configs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int parse_user_pin_configs(struct hda_codec *codec, const char *buf) { - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; int nid, cfg; - int err; if (sscanf(buf, "%i %i", &nid, &cfg) != 2) return -EINVAL; if (!nid) return -EINVAL; - err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); + return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); +} + +static ssize_t user_pin_configs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + int err = parse_user_pin_configs(codec, buf); if (err < 0) return err; return count; @@ -553,3 +574,180 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint); #endif /* CONFIG_SND_HDA_RECONFIG */ + +#ifdef CONFIG_SND_HDA_PATCH_LOADER + +/* parser mode */ +enum { + LINE_MODE_NONE, + LINE_MODE_CODEC, + LINE_MODE_MODEL, + LINE_MODE_PINCFG, + LINE_MODE_VERB, + LINE_MODE_HINT, + NUM_LINE_MODES, +}; + +static inline int strmatch(const char *a, const char *b) +{ + return strnicmp(a, b, strlen(b)) == 0; +} + +/* parse the contents after the line "[codec]" + * accept only the line with three numbers, and assign the current codec + */ +static void parse_codec_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + unsigned int vendorid, subid, caddr; + struct hda_codec *codec; + + *codecp = NULL; + if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) { + list_for_each_entry(codec, &bus->codec_list, list) { + if (codec->addr == caddr) { + *codecp = codec; + break; + } + } + } +} + +/* parse the contents after the other command tags, [pincfg], [verb], + * [hint] and [model] + * just pass to the sysfs helper (only when any codec was specified) + */ +static void parse_pincfg_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + if (!*codecp) + return; + parse_user_pin_configs(*codecp, buf); +} + +static void parse_verb_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + if (!*codecp) + return; + parse_init_verbs(*codecp, buf); +} + +static void parse_hint_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + if (!*codecp) + return; + parse_hints(*codecp, buf); +} + +static void parse_model_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + if (!*codecp) + return; + kfree((*codecp)->modelname); + (*codecp)->modelname = kstrdup(buf, GFP_KERNEL); +} + +struct hda_patch_item { + const char *tag; + void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc); +}; + +static struct hda_patch_item patch_items[NUM_LINE_MODES] = { + [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode }, + [LINE_MODE_MODEL] = { "[model]", parse_model_mode }, + [LINE_MODE_VERB] = { "[verb]", parse_verb_mode }, + [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode }, + [LINE_MODE_HINT] = { "[hint]", parse_hint_mode }, +}; + +/* check the line starting with '[' -- change the parser mode accodingly */ +static int parse_line_mode(char *buf, struct hda_bus *bus) +{ + int i; + for (i = 0; i < ARRAY_SIZE(patch_items); i++) { + if (!patch_items[i].tag) + continue; + if (strmatch(buf, patch_items[i].tag)) + return i; + } + return LINE_MODE_NONE; +} + +/* copy one line from the buffer in fw, and update the fields in fw + * return zero if it reaches to the end of the buffer, or non-zero + * if successfully copied a line + * + * the spaces at the beginning and the end of the line are stripped + */ +static int get_line_from_fw(char *buf, int size, struct firmware *fw) +{ + int len; + const char *p = fw->data; + while (isspace(*p) && fw->size) { + p++; + fw->size--; + } + if (!fw->size) + return 0; + if (size < fw->size) + size = fw->size; + + for (len = 0; len < fw->size; len++) { + if (!*p) + break; + if (*p == '\n') { + p++; + len++; + break; + } + if (len < size) + *buf++ = *p++; + } + *buf = 0; + fw->size -= len; + fw->data = p; + remove_trail_spaces(buf); + return 1; +} + +/* + * load a "patch" firmware file and parse it + */ +int snd_hda_load_patch(struct hda_bus *bus, const char *patch) +{ + int err; + const struct firmware *fw; + struct firmware tmp; + char buf[128]; + struct hda_codec *codec; + int line_mode; + struct device *dev = bus->card->dev; + + if (snd_BUG_ON(!dev)) + return -ENODEV; + err = request_firmware(&fw, patch, dev); + if (err < 0) { + printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n", + patch); + return err; + } + + tmp = *fw; + line_mode = LINE_MODE_NONE; + codec = NULL; + while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) { + if (!*buf || *buf == '#' || *buf == '\n') + continue; + if (*buf == '[') + line_mode = parse_line_mode(buf, bus); + else if (patch_items[line_mode].parser) + patch_items[line_mode].parser(buf, bus, &codec); + } + release_firmware(fw); + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_load_patch); +#endif /* CONFIG_SND_HDA_PATCH_LOADER */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index da58f2c..a2f4a11 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -61,6 +61,9 @@ static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_only[SNDRV_CARDS]; static int single_cmd; static int enable_msi; +#ifdef CONFIG_SND_HDA_PATCH_LOADER +static char *patch[SNDRV_CARDS]; +#endif module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); @@ -84,6 +87,10 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " "(for debugging only)."); module_param(enable_msi, int, 0444); MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); +#ifdef CONFIG_SND_HDA_PATCH_LOADER +module_param_array(patch, charp, NULL, 0444); +MODULE_PARM_DESC(patch, "Patch file for Intel HD audio interface."); +#endif #ifdef CONFIG_SND_HDA_POWER_SAVE static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; @@ -2468,6 +2475,9 @@ static int __devinit azx_probe(struct pci_dev *pci, return err; } + /* set this here since it's referred in snd_hda_load_patch() */ + snd_card_set_dev(card, &pci->dev); + err = azx_create(card, pci, dev, pci_id->driver_data, &chip); if (err < 0) goto out_free; @@ -2477,6 +2487,15 @@ static int __devinit azx_probe(struct pci_dev *pci, err = azx_codec_create(chip, model[dev]); if (err < 0) goto out_free; +#ifdef CONFIG_SND_HDA_PATCH_LOADER + if (patch[dev]) { + snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n", + patch[dev]); + err = snd_hda_load_patch(chip->bus, patch[dev]); + if (err < 0) + goto out_free; + } +#endif if (!probe_only[dev]) { err = azx_codec_configure(chip); if (err < 0) @@ -2493,8 +2512,6 @@ static int __devinit azx_probe(struct pci_dev *pci, if (err < 0) goto out_free; - snd_card_set_dev(card, &pci->dev); - err = snd_card_register(card); if (err < 0) goto out_free; -- cgit v0.10.2 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 diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 88b7433..8bc9867 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 v0.10.2 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 diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 012858d..414700b 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 8bc9867..55aab11 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 v0.10.2 From c17ef45342cc033fdf7bdd5b28615e0090f8d2e7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 23 Jun 2009 17:12:47 -0700 Subject: rcu: Remove Classic RCU Remove Classic RCU, given that the combination of Tree RCU and the proposed Bloatwatch RCU do everything that Classic RCU can with fewer bugs. Tree RCU has been default in x86 builds for almost six months, and seems to be quite reliable, so there does not seem to be much justification for keeping the Classic RCU code and config complexity around anymore. Signed-off-by: Paul E. McKenney Cc: akpm@linux-foundation.org Cc: niv@us.ibm.com Cc: dvhltc@us.ibm.com Cc: dipankar@in.ibm.com Cc: dhowells@redhat.com Cc: lethal@linux-sh.org Cc: kernel@wantstofly.org Signed-off-by: Ingo Molnar diff --git a/include/linux/rcuclassic.h b/include/linux/rcuclassic.h deleted file mode 100644 index bfd92e1..0000000 --- a/include/linux/rcuclassic.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion (classic version) - * - * 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, 2001 - * - * Author: Dipankar Sarma - * - * 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_RCUCLASSIC_H -#define __LINUX_RCUCLASSIC_H - -#include -#include -#include -#include -#include - -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR -#define RCU_SECONDS_TILL_STALL_CHECK (10 * HZ) /* for rcp->jiffies_stall */ -#define RCU_SECONDS_TILL_STALL_RECHECK (30 * HZ) /* for rcp->jiffies_stall */ -#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ - -/* Global control variables for rcupdate callback mechanism. */ -struct rcu_ctrlblk { - long cur; /* Current batch number. */ - long completed; /* Number of the last completed batch */ - long pending; /* Number of the last pending batch */ -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR - unsigned long gp_start; /* Time at which GP started in jiffies. */ - unsigned long jiffies_stall; - /* Time at which to check for CPU stalls. */ -#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ - - int signaled; - - spinlock_t lock ____cacheline_internodealigned_in_smp; - DECLARE_BITMAP(cpumask, NR_CPUS); /* CPUs that need to switch for */ - /* current batch to proceed. */ -} ____cacheline_internodealigned_in_smp; - -/* Is batch a before batch b ? */ -static inline int rcu_batch_before(long a, long b) -{ - return (a - b) < 0; -} - -/* Is batch a after batch b ? */ -static inline int rcu_batch_after(long a, long b) -{ - return (a - b) > 0; -} - -/* Per-CPU data for Read-Copy UPdate. */ -struct rcu_data { - /* 1) quiescent state handling : */ - long quiescbatch; /* Batch # for grace period */ - int passed_quiesc; /* User-mode/idle loop etc. */ - int qs_pending; /* core waits for quiesc state */ - - /* 2) batch handling */ - /* - * if nxtlist is not NULL, then: - * batch: - * The batch # for the last entry of nxtlist - * [*nxttail[1], NULL = *nxttail[2]): - * Entries that batch # <= batch - * [*nxttail[0], *nxttail[1]): - * Entries that batch # <= batch - 1 - * [nxtlist, *nxttail[0]): - * Entries that batch # <= batch - 2 - * The grace period for these entries has completed, and - * the other grace-period-completed entries may be moved - * here temporarily in rcu_process_callbacks(). - */ - long batch; - struct rcu_head *nxtlist; - struct rcu_head **nxttail[3]; - long qlen; /* # of queued callbacks */ - struct rcu_head *donelist; - struct rcu_head **donetail; - long blimit; /* Upper limit on a processed batch */ - int cpu; - struct rcu_head barrier; -}; - -/* - * Increment the quiescent state counter. - * The counter is a bit degenerated: 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. - */ -extern void rcu_qsctr_inc(int cpu); -extern void rcu_bh_qsctr_inc(int cpu); - -extern int rcu_pending(int cpu); -extern int rcu_needs_cpu(int cpu); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -extern struct lockdep_map rcu_lock_map; -# define rcu_read_acquire() \ - lock_acquire(&rcu_lock_map, 0, 0, 2, 1, NULL, _THIS_IP_) -# define rcu_read_release() lock_release(&rcu_lock_map, 1, _THIS_IP_) -#else -# define rcu_read_acquire() do { } while (0) -# define rcu_read_release() do { } while (0) -#endif - -#define __rcu_read_lock() \ - do { \ - preempt_disable(); \ - __acquire(RCU); \ - rcu_read_acquire(); \ - } while (0) -#define __rcu_read_unlock() \ - do { \ - rcu_read_release(); \ - __release(RCU); \ - preempt_enable(); \ - } while (0) -#define __rcu_read_lock_bh() \ - do { \ - local_bh_disable(); \ - __acquire(RCU_BH); \ - rcu_read_acquire(); \ - } while (0) -#define __rcu_read_unlock_bh() \ - do { \ - rcu_read_release(); \ - __release(RCU_BH); \ - local_bh_enable(); \ - } while (0) - -#define __synchronize_sched() synchronize_rcu() - -#define call_rcu_sched(head, func) call_rcu(head, func) - -extern void __rcu_init(void); -#define rcu_init_sched() do { } while (0) -extern void rcu_check_callbacks(int cpu, int user); -extern void rcu_restart_cpu(int cpu); - -extern long rcu_batches_completed(void); -extern long rcu_batches_completed_bh(void); - -#define rcu_enter_nohz() do { } while (0) -#define rcu_exit_nohz() do { } while (0) - -/* A context switch is a grace period for rcuclassic. */ -static inline int rcu_blocking_is_gp(void) -{ - return num_online_cpus() == 1; -} - -#endif /* __LINUX_RCUCLASSIC_H */ diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 15fbb3c..0cdfdb6 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -54,9 +54,7 @@ struct rcu_head { /* Internal to kernel, but needed by rcupreempt.h. */ extern int rcu_scheduler_active; -#if defined(CONFIG_CLASSIC_RCU) -#include -#elif defined(CONFIG_TREE_RCU) +#if defined(CONFIG_TREE_RCU) #include #elif defined(CONFIG_PREEMPT_RCU) #include diff --git a/init/Kconfig b/init/Kconfig index 1ce05a4..d10f31d 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -316,21 +316,13 @@ choice prompt "RCU Implementation" default TREE_RCU -config CLASSIC_RCU - bool "Classic RCU" - help - This option selects the classic RCU implementation that is - designed for best read-side performance on non-realtime - systems. - - Select this option if you are unsure. - config TREE_RCU bool "Tree-based hierarchical RCU" help This option selects the RCU implementation that is designed for very large SMP system with hundreds or - thousands of CPUs. + thousands of CPUs. It also scales down nicely to + smaller systems. config PREEMPT_RCU bool "Preemptible RCU" diff --git a/kernel/Makefile b/kernel/Makefile index 0a32cb2..d6042bc 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -80,7 +80,6 @@ obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o -obj-$(CONFIG_CLASSIC_RCU) += rcuclassic.o obj-$(CONFIG_TREE_RCU) += rcutree.o obj-$(CONFIG_PREEMPT_RCU) += rcupreempt.o obj-$(CONFIG_TREE_RCU_TRACE) += rcutree_trace.o diff --git a/kernel/rcuclassic.c b/kernel/rcuclassic.c deleted file mode 100644 index 0f2b0b3..0000000 --- a/kernel/rcuclassic.c +++ /dev/null @@ -1,807 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion - * - * 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, 2001 - * - * Authors: Dipankar Sarma - * Manfred Spraul - * - * 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 - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -static struct lock_class_key rcu_lock_key; -struct lockdep_map rcu_lock_map = - STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key); -EXPORT_SYMBOL_GPL(rcu_lock_map); -#endif - - -/* Definition for rcupdate control block. */ -static struct rcu_ctrlblk rcu_ctrlblk = { - .cur = -300, - .completed = -300, - .pending = -300, - .lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock), - .cpumask = CPU_BITS_NONE, -}; - -static struct rcu_ctrlblk rcu_bh_ctrlblk = { - .cur = -300, - .completed = -300, - .pending = -300, - .lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock), - .cpumask = CPU_BITS_NONE, -}; - -static DEFINE_PER_CPU(struct rcu_data, rcu_data); -static 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 - * how many quiescent states passed, just if there was at least - * one since the start of the grace period. Thus just a flag. - */ -void rcu_qsctr_inc(int cpu) -{ - struct rcu_data *rdp = &per_cpu(rcu_data, cpu); - rdp->passed_quiesc = 1; -} - -void rcu_bh_qsctr_inc(int cpu) -{ - struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu); - rdp->passed_quiesc = 1; -} - -static int blimit = 10; -static int qhimark = 10000; -static int qlowmark = 100; - -#ifdef CONFIG_SMP -static void force_quiescent_state(struct rcu_data *rdp, - struct rcu_ctrlblk *rcp) -{ - int cpu; - unsigned long flags; - - set_need_resched(); - spin_lock_irqsave(&rcp->lock, flags); - if (unlikely(!rcp->signaled)) { - rcp->signaled = 1; - /* - * Don't send IPI to itself. With irqs disabled, - * rdp->cpu is the current cpu. - * - * cpu_online_mask is updated by the _cpu_down() - * using __stop_machine(). Since we're in irqs disabled - * section, __stop_machine() is not exectuting, hence - * the cpu_online_mask is stable. - * - * However, a cpu might have been offlined _just_ before - * we disabled irqs while entering here. - * And rcu subsystem might not yet have handled the CPU_DEAD - * notification, leading to the offlined cpu's bit - * being set in the rcp->cpumask. - * - * Hence cpumask = (rcp->cpumask & cpu_online_mask) to prevent - * sending smp_reschedule() to an offlined CPU. - */ - for_each_cpu_and(cpu, - to_cpumask(rcp->cpumask), cpu_online_mask) { - if (cpu != rdp->cpu) - smp_send_reschedule(cpu); - } - } - spin_unlock_irqrestore(&rcp->lock, flags); -} -#else -static inline void force_quiescent_state(struct rcu_data *rdp, - struct rcu_ctrlblk *rcp) -{ - set_need_resched(); -} -#endif - -static void __call_rcu(struct rcu_head *head, struct rcu_ctrlblk *rcp, - struct rcu_data *rdp) -{ - long batch; - - head->next = NULL; - smp_mb(); /* Read of rcu->cur must happen after any change by caller. */ - - /* - * Determine the batch number of this callback. - * - * Using ACCESS_ONCE to avoid the following error when gcc eliminates - * local variable "batch" and emits codes like this: - * 1) rdp->batch = rcp->cur + 1 # gets old value - * ...... - * 2)rcu_batch_after(rcp->cur + 1, rdp->batch) # gets new value - * then [*nxttail[0], *nxttail[1]) may contain callbacks - * that batch# = rdp->batch, see the comment of struct rcu_data. - */ - batch = ACCESS_ONCE(rcp->cur) + 1; - - if (rdp->nxtlist && rcu_batch_after(batch, rdp->batch)) { - /* process callbacks */ - rdp->nxttail[0] = rdp->nxttail[1]; - rdp->nxttail[1] = rdp->nxttail[2]; - if (rcu_batch_after(batch - 1, rdp->batch)) - rdp->nxttail[0] = rdp->nxttail[2]; - } - - rdp->batch = batch; - *rdp->nxttail[2] = head; - rdp->nxttail[2] = &head->next; - - if (unlikely(++rdp->qlen > qhimark)) { - rdp->blimit = INT_MAX; - force_quiescent_state(rdp, &rcu_ctrlblk); - } -} - -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR - -static void record_gp_stall_check_time(struct rcu_ctrlblk *rcp) -{ - rcp->gp_start = jiffies; - rcp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_CHECK; -} - -static void print_other_cpu_stall(struct rcu_ctrlblk *rcp) -{ - int cpu; - long delta; - unsigned long flags; - - /* Only let one CPU complain about others per time interval. */ - - spin_lock_irqsave(&rcp->lock, flags); - delta = jiffies - rcp->jiffies_stall; - if (delta < 2 || rcp->cur != rcp->completed) { - spin_unlock_irqrestore(&rcp->lock, flags); - return; - } - rcp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_RECHECK; - spin_unlock_irqrestore(&rcp->lock, flags); - - /* OK, time to rat on our buddy... */ - - printk(KERN_ERR "INFO: RCU detected CPU stalls:"); - for_each_possible_cpu(cpu) { - if (cpumask_test_cpu(cpu, to_cpumask(rcp->cpumask))) - printk(" %d", cpu); - } - printk(" (detected by %d, t=%ld jiffies)\n", - smp_processor_id(), (long)(jiffies - rcp->gp_start)); -} - -static void print_cpu_stall(struct rcu_ctrlblk *rcp) -{ - unsigned long flags; - - printk(KERN_ERR "INFO: RCU detected CPU %d stall (t=%lu/%lu jiffies)\n", - smp_processor_id(), jiffies, - jiffies - rcp->gp_start); - dump_stack(); - spin_lock_irqsave(&rcp->lock, flags); - if ((long)(jiffies - rcp->jiffies_stall) >= 0) - rcp->jiffies_stall = - jiffies + RCU_SECONDS_TILL_STALL_RECHECK; - spin_unlock_irqrestore(&rcp->lock, flags); - set_need_resched(); /* kick ourselves to get things going. */ -} - -static void check_cpu_stall(struct rcu_ctrlblk *rcp) -{ - long delta; - - delta = jiffies - rcp->jiffies_stall; - if (cpumask_test_cpu(smp_processor_id(), to_cpumask(rcp->cpumask)) && - delta >= 0) { - - /* We haven't checked in, so go dump stack. */ - print_cpu_stall(rcp); - - } else if (rcp->cur != rcp->completed && delta >= 2) { - - /* They had two seconds to dump stack, so complain. */ - print_other_cpu_stall(rcp); - } -} - -#else /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ - -static void record_gp_stall_check_time(struct rcu_ctrlblk *rcp) -{ -} - -static inline void check_cpu_stall(struct rcu_ctrlblk *rcp) -{ -} - -#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ - -/** - * call_rcu - Queue an RCU callback for invocation after a 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 grace - * period elapses, in other words after all currently executing RCU - * read-side critical sections have completed. RCU read-side critical - * sections are delimited by rcu_read_lock() and rcu_read_unlock(), - * and may be nested. - */ -void call_rcu(struct rcu_head *head, - void (*func)(struct rcu_head *rcu)) -{ - unsigned long flags; - - head->func = func; - local_irq_save(flags); - __call_rcu(head, &rcu_ctrlblk, &__get_cpu_var(rcu_data)); - local_irq_restore(flags); -} -EXPORT_SYMBOL_GPL(call_rcu); - -/** - * call_rcu_bh - Queue an RCU for invocation after a quicker 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 grace - * period elapses, in other words after all currently executing RCU - * read-side critical sections have completed. call_rcu_bh() assumes - * that the read-side critical sections end on completion of a softirq - * handler. This means that read-side critical sections in process - * context must not be interrupted by softirqs. This interface is to be - * used when most of the read-side critical sections are in softirq context. - * RCU read-side critical sections are delimited by rcu_read_lock() and - * rcu_read_unlock(), * if in interrupt context or rcu_read_lock_bh() - * and rcu_read_unlock_bh(), if in process context. These may be nested. - */ -void call_rcu_bh(struct rcu_head *head, - void (*func)(struct rcu_head *rcu)) -{ - unsigned long flags; - - head->func = func; - local_irq_save(flags); - __call_rcu(head, &rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data)); - local_irq_restore(flags); -} -EXPORT_SYMBOL_GPL(call_rcu_bh); - -/* - * 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); - -/* - * Return the number of RCU batches processed thus far. Useful - * for debug and statistics. - */ -long rcu_batches_completed_bh(void) -{ - return rcu_bh_ctrlblk.completed; -} -EXPORT_SYMBOL_GPL(rcu_batches_completed_bh); - -/* Raises the softirq for processing rcu_callbacks. */ -static inline void raise_rcu_softirq(void) -{ - raise_softirq(RCU_SOFTIRQ); -} - -/* - * Invoke the completed RCU callbacks. They are expected to be in - * a per-cpu list. - */ -static void rcu_do_batch(struct rcu_data *rdp) -{ - unsigned long flags; - struct rcu_head *next, *list; - int count = 0; - - list = rdp->donelist; - while (list) { - next = list->next; - prefetch(next); - list->func(list); - list = next; - if (++count >= rdp->blimit) - break; - } - rdp->donelist = list; - - local_irq_save(flags); - rdp->qlen -= count; - local_irq_restore(flags); - if (rdp->blimit == INT_MAX && rdp->qlen <= qlowmark) - rdp->blimit = blimit; - - if (!rdp->donelist) - rdp->donetail = &rdp->donelist; - else - raise_rcu_softirq(); -} - -/* - * Grace period handling: - * The grace period handling consists out of two steps: - * - A new grace period is started. - * This is done by rcu_start_batch. The start is not broadcasted to - * all cpus, they must pick this up by comparing rcp->cur with - * rdp->quiescbatch. All cpus are recorded in the - * rcu_ctrlblk.cpumask bitmap. - * - All cpus must go through a quiescent state. - * Since the start of the grace period is not broadcasted, at least two - * calls to rcu_check_quiescent_state are required: - * The first call just notices that a new grace period is running. The - * following calls check if there was a quiescent state since the beginning - * of the grace period. If so, it updates rcu_ctrlblk.cpumask. If - * the bitmap is empty, then the grace period is completed. - * rcu_check_quiescent_state calls rcu_start_batch(0) to start the next grace - * period (if necessary). - */ - -/* - * Register a new batch of callbacks, and start it up if there is currently no - * active batch and the batch to be registered has not already occurred. - * Caller must hold rcu_ctrlblk.lock. - */ -static void rcu_start_batch(struct rcu_ctrlblk *rcp) -{ - if (rcp->cur != rcp->pending && - rcp->completed == rcp->cur) { - rcp->cur++; - record_gp_stall_check_time(rcp); - - /* - * Accessing nohz_cpu_mask before incrementing rcp->cur needs a - * Barrier Otherwise it can cause tickless idle CPUs to be - * included in rcp->cpumask, which will extend graceperiods - * unnecessarily. - */ - smp_mb(); - cpumask_andnot(to_cpumask(rcp->cpumask), - cpu_online_mask, nohz_cpu_mask); - - rcp->signaled = 0; - } -} - -/* - * cpu went through a quiescent state since the beginning of the grace period. - * Clear it from the cpu mask and complete the grace period if it was the last - * cpu. Start another grace period if someone has further entries pending - */ -static void cpu_quiet(int cpu, struct rcu_ctrlblk *rcp) -{ - cpumask_clear_cpu(cpu, to_cpumask(rcp->cpumask)); - if (cpumask_empty(to_cpumask(rcp->cpumask))) { - /* batch completed ! */ - rcp->completed = rcp->cur; - rcu_start_batch(rcp); - } -} - -/* - * Check if the cpu has gone through a quiescent state (say context - * switch). If so and if it already hasn't done so in this RCU - * quiescent cycle, then indicate that it has done so. - */ -static void rcu_check_quiescent_state(struct rcu_ctrlblk *rcp, - struct rcu_data *rdp) -{ - unsigned long flags; - - if (rdp->quiescbatch != rcp->cur) { - /* start new grace period: */ - rdp->qs_pending = 1; - rdp->passed_quiesc = 0; - rdp->quiescbatch = rcp->cur; - return; - } - - /* Grace period already completed for this cpu? - * qs_pending is checked instead of the actual bitmap to avoid - * cacheline trashing. - */ - if (!rdp->qs_pending) - return; - - /* - * Was there a quiescent state since the beginning of the grace - * period? If no, then exit and wait for the next call. - */ - if (!rdp->passed_quiesc) - return; - rdp->qs_pending = 0; - - spin_lock_irqsave(&rcp->lock, flags); - /* - * rdp->quiescbatch/rcp->cur and the cpu bitmap can come out of sync - * during cpu startup. Ignore the quiescent state. - */ - if (likely(rdp->quiescbatch == rcp->cur)) - cpu_quiet(rdp->cpu, rcp); - - spin_unlock_irqrestore(&rcp->lock, flags); -} - - -#ifdef CONFIG_HOTPLUG_CPU - -/* warning! helper for rcu_offline_cpu. do not use elsewhere without reviewing - * locking requirements, the list it's pulling from has to belong to a cpu - * which is dead and hence not processing interrupts. - */ -static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list, - struct rcu_head **tail, long batch) -{ - unsigned long flags; - - if (list) { - local_irq_save(flags); - this_rdp->batch = batch; - *this_rdp->nxttail[2] = list; - this_rdp->nxttail[2] = tail; - local_irq_restore(flags); - } -} - -static void __rcu_offline_cpu(struct rcu_data *this_rdp, - struct rcu_ctrlblk *rcp, struct rcu_data *rdp) -{ - unsigned long flags; - - /* - * if the cpu going offline owns the grace period - * we can block indefinitely waiting for it, so flush - * it here - */ - spin_lock_irqsave(&rcp->lock, flags); - if (rcp->cur != rcp->completed) - cpu_quiet(rdp->cpu, rcp); - rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail, rcp->cur + 1); - rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail[2], rcp->cur + 1); - spin_unlock(&rcp->lock); - - this_rdp->qlen += rdp->qlen; - local_irq_restore(flags); -} - -static void rcu_offline_cpu(int cpu) -{ - struct rcu_data *this_rdp = &get_cpu_var(rcu_data); - struct rcu_data *this_bh_rdp = &get_cpu_var(rcu_bh_data); - - __rcu_offline_cpu(this_rdp, &rcu_ctrlblk, - &per_cpu(rcu_data, cpu)); - __rcu_offline_cpu(this_bh_rdp, &rcu_bh_ctrlblk, - &per_cpu(rcu_bh_data, cpu)); - put_cpu_var(rcu_data); - put_cpu_var(rcu_bh_data); -} - -#else - -static void rcu_offline_cpu(int cpu) -{ -} - -#endif - -/* - * This does the RCU processing work from softirq context. - */ -static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp, - struct rcu_data *rdp) -{ - unsigned long flags; - long completed_snap; - - if (rdp->nxtlist) { - local_irq_save(flags); - completed_snap = ACCESS_ONCE(rcp->completed); - - /* - * move the other grace-period-completed entries to - * [rdp->nxtlist, *rdp->nxttail[0]) temporarily - */ - if (!rcu_batch_before(completed_snap, rdp->batch)) - rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2]; - else if (!rcu_batch_before(completed_snap, rdp->batch - 1)) - rdp->nxttail[0] = rdp->nxttail[1]; - - /* - * the grace period for entries in - * [rdp->nxtlist, *rdp->nxttail[0]) has completed and - * move these entries to donelist - */ - if (rdp->nxttail[0] != &rdp->nxtlist) { - *rdp->donetail = rdp->nxtlist; - rdp->donetail = rdp->nxttail[0]; - rdp->nxtlist = *rdp->nxttail[0]; - *rdp->donetail = NULL; - - if (rdp->nxttail[1] == rdp->nxttail[0]) - rdp->nxttail[1] = &rdp->nxtlist; - if (rdp->nxttail[2] == rdp->nxttail[0]) - rdp->nxttail[2] = &rdp->nxtlist; - rdp->nxttail[0] = &rdp->nxtlist; - } - - local_irq_restore(flags); - - if (rcu_batch_after(rdp->batch, rcp->pending)) { - unsigned long flags2; - - /* and start it/schedule start if it's a new batch */ - spin_lock_irqsave(&rcp->lock, flags2); - if (rcu_batch_after(rdp->batch, rcp->pending)) { - rcp->pending = rdp->batch; - rcu_start_batch(rcp); - } - spin_unlock_irqrestore(&rcp->lock, flags2); - } - } - - rcu_check_quiescent_state(rcp, rdp); - if (rdp->donelist) - rcu_do_batch(rdp); -} - -static void rcu_process_callbacks(struct softirq_action *unused) -{ - /* - * Memory references from any prior RCU read-side critical sections - * executed by the interrupted code must be see before any RCU - * grace-period manupulations below. - */ - - smp_mb(); /* See above block comment. */ - - __rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data)); - __rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data)); - - /* - * Memory references from any later RCU read-side critical sections - * executed by the interrupted code must be see after any RCU - * grace-period manupulations above. - */ - - smp_mb(); /* See above block comment. */ -} - -static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) -{ - /* Check for CPU stalls, if enabled. */ - check_cpu_stall(rcp); - - if (rdp->nxtlist) { - long completed_snap = ACCESS_ONCE(rcp->completed); - - /* - * This cpu has pending rcu entries and the grace period - * for them has completed. - */ - if (!rcu_batch_before(completed_snap, rdp->batch)) - return 1; - if (!rcu_batch_before(completed_snap, rdp->batch - 1) && - rdp->nxttail[0] != rdp->nxttail[1]) - return 1; - if (rdp->nxttail[0] != &rdp->nxtlist) - return 1; - - /* - * This cpu has pending rcu entries and the new batch - * for then hasn't been started nor scheduled start - */ - if (rcu_batch_after(rdp->batch, rcp->pending)) - return 1; - } - - /* This cpu has finished callbacks to invoke */ - if (rdp->donelist) - return 1; - - /* The rcu core waits for a quiescent state from the cpu */ - if (rdp->quiescbatch != rcp->cur || rdp->qs_pending) - return 1; - - /* nothing to do */ - return 0; -} - -/* - * Check to see if there is any immediate RCU-related work to be done - * by the current CPU, returning 1 if so. This function is part of the - * RCU implementation; it is -not- an exported member of the RCU API. - */ -int rcu_pending(int cpu) -{ - return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) || - __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu)); -} - -/* - * 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. 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 = &per_cpu(rcu_data, cpu); - struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu); - - return !!rdp->nxtlist || !!rdp_bh->nxtlist || rcu_pending(cpu); -} - -/* - * Top-level function driving RCU grace-period detection, normally - * invoked from the scheduler-clock interrupt. This function simply - * increments counters that are read only from softirq by this same - * CPU, so there are no memory barriers required. - */ -void rcu_check_callbacks(int cpu, int user) -{ - if (user || - (idle_cpu(cpu) && rcu_scheduler_active && - !in_softirq() && hardirq_count() <= (1 << HARDIRQ_SHIFT))) { - - /* - * 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. - * - * Also do a memory barrier. This 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. The memory barrier makes sure that - * the rcu_qsctr_inc() and rcu_bh_qsctr_inc() are see - * by other CPUs to happen after any such write. - */ - - smp_mb(); /* See above block comment. */ - rcu_qsctr_inc(cpu); - rcu_bh_qsctr_inc(cpu); - - } else if (!in_softirq()) { - - /* - * 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. The memory barrier - * is needed for the same reason as is the above one. - */ - - smp_mb(); /* See above block comment. */ - rcu_bh_qsctr_inc(cpu); - } - raise_rcu_softirq(); -} - -static void __cpuinit rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp, - struct rcu_data *rdp) -{ - unsigned long flags; - - spin_lock_irqsave(&rcp->lock, flags); - memset(rdp, 0, sizeof(*rdp)); - rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2] = &rdp->nxtlist; - rdp->donetail = &rdp->donelist; - rdp->quiescbatch = rcp->completed; - rdp->qs_pending = 0; - rdp->cpu = cpu; - rdp->blimit = blimit; - spin_unlock_irqrestore(&rcp->lock, flags); -} - -static void __cpuinit rcu_online_cpu(int cpu) -{ - struct rcu_data *rdp = &per_cpu(rcu_data, cpu); - struct rcu_data *bh_rdp = &per_cpu(rcu_bh_data, cpu); - - rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp); - rcu_init_percpu_data(cpu, &rcu_bh_ctrlblk, bh_rdp); - open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); -} - -static 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_DEAD: - case CPU_DEAD_FROZEN: - rcu_offline_cpu(cpu); - break; - default: - break; - } - return NOTIFY_OK; -} - -static struct notifier_block __cpuinitdata rcu_nb = { - .notifier_call = rcu_cpu_notify, -}; - -/* - * Initializes rcu mechanism. Assumed to be called early. - * That is before local timer(SMP) or jiffie timer (uniproc) is setup. - * Note that rcu_qsctr and friends are implicitly - * initialized due to the choice of ``0'' for RCU_CTR_INVALID. - */ -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_cpu_notify(&rcu_nb, CPU_UP_PREPARE, - (void *)(long)smp_processor_id()); - /* Register notifier for non-boot CPUs */ - register_cpu_notifier(&rcu_nb); -} - -module_param(blimit, int, 0); -module_param(qhimark, int, 0); -module_param(qlowmark, int, 0); -- cgit v0.10.2 From 86abcf9cebf7b5ceb33facde297face5ec4d2260 Mon Sep 17 00:00:00 2001 From: James Morris Date: Thu, 18 Jun 2009 22:00:05 +1000 Subject: keys: annotate seqfile ops with __releases and __acquires Annotate seqfile ops with __releases and __acquires to stop sparse complaining about unbalanced locking. Signed-off-by: James Morris Reviewed-by: Serge Hallyn diff --git a/security/keys/proc.c b/security/keys/proc.c index 769f9bd..39793c7 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -120,6 +120,7 @@ static int proc_keys_open(struct inode *inode, struct file *file) } static void *proc_keys_start(struct seq_file *p, loff_t *_pos) + __acquires(key_serial_lock) { struct rb_node *_p; loff_t pos = *_pos; @@ -144,6 +145,7 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) } static void proc_keys_stop(struct seq_file *p, void *v) + __releases(key_serial_lock) { spin_unlock(&key_serial_lock); } @@ -257,6 +259,7 @@ static int proc_key_users_open(struct inode *inode, struct file *file) } static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) + __acquires(key_user_lock) { struct rb_node *_p; loff_t pos = *_pos; @@ -281,6 +284,7 @@ static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) } static void proc_key_users_stop(struct seq_file *p, void *v) + __releases(key_user_lock) { spin_unlock(&key_user_lock); } -- cgit v0.10.2 From 9e48858f7d36a6a3849f1d1b40c3bf5624b4ee7c Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 7 May 2009 19:26:19 +1000 Subject: security: rename ptrace_may_access => ptrace_access_check The ->ptrace_may_access() methods are named confusingly - the real ptrace_may_access() returns a bool, while these security checks have a retval convention. Rename it to ptrace_access_check, to reduce the confusion factor. [ Impact: cleanup, no code changed ] Signed-off-by: Ingo Molnar Signed-off-by: James Morris diff --git a/include/linux/security.h b/include/linux/security.h index 5eff459..1459091 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -52,7 +52,7 @@ struct audit_krule; extern int cap_capable(struct task_struct *tsk, const struct cred *cred, int cap, int audit); extern int cap_settime(struct timespec *ts, struct timezone *tz); -extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode); +extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode); extern int cap_ptrace_traceme(struct task_struct *parent); extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); extern int cap_capset(struct cred *new, const struct cred *old, @@ -1209,7 +1209,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @alter contains the flag indicating whether changes are to be made. * Return 0 if permission is granted. * - * @ptrace_may_access: + * @ptrace_access_check: * Check permission before allowing the current process to trace the * @child process. * Security modules may also want to perform a process tracing check @@ -1224,7 +1224,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Check that the @parent process has sufficient permission to trace the * current process before allowing the current process to present itself * to the @parent process for tracing. - * The parent process will still have to undergo the ptrace_may_access + * The parent process will still have to undergo the ptrace_access_check * checks before it is allowed to trace this one. * @parent contains the task_struct structure for debugger process. * Return 0 if permission is granted. @@ -1336,7 +1336,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) struct security_operations { char name[SECURITY_NAME_MAX + 1]; - int (*ptrace_may_access) (struct task_struct *child, unsigned int mode); + int (*ptrace_access_check) (struct task_struct *child, unsigned int mode); int (*ptrace_traceme) (struct task_struct *parent); int (*capget) (struct task_struct *target, kernel_cap_t *effective, @@ -1617,7 +1617,7 @@ extern int security_module_enable(struct security_operations *ops); extern int register_security(struct security_operations *ops); /* Security operations */ -int security_ptrace_may_access(struct task_struct *child, unsigned int mode); +int security_ptrace_access_check(struct task_struct *child, unsigned int mode); int security_ptrace_traceme(struct task_struct *parent); int security_capget(struct task_struct *target, kernel_cap_t *effective, @@ -1798,10 +1798,10 @@ static inline int security_init(void) return 0; } -static inline int security_ptrace_may_access(struct task_struct *child, +static inline int security_ptrace_access_check(struct task_struct *child, unsigned int mode) { - return cap_ptrace_may_access(child, mode); + return cap_ptrace_access_check(child, mode); } static inline int security_ptrace_traceme(struct task_struct *parent) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 61c78b2..9a4184e 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -152,7 +152,7 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) if (!dumpable && !capable(CAP_SYS_PTRACE)) return -EPERM; - return security_ptrace_may_access(task, mode); + return security_ptrace_access_check(task, mode); } bool ptrace_may_access(struct task_struct *task, unsigned int mode) diff --git a/security/capability.c b/security/capability.c index 21b6cea..f218dd3 100644 --- a/security/capability.c +++ b/security/capability.c @@ -863,7 +863,7 @@ struct security_operations default_security_ops = { void security_fixup_ops(struct security_operations *ops) { - set_to_cap_if_null(ops, ptrace_may_access); + set_to_cap_if_null(ops, ptrace_access_check); set_to_cap_if_null(ops, ptrace_traceme); set_to_cap_if_null(ops, capget); set_to_cap_if_null(ops, capset); diff --git a/security/commoncap.c b/security/commoncap.c index 48b7e02..aa97704 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -101,7 +101,7 @@ int cap_settime(struct timespec *ts, struct timezone *tz) } /** - * cap_ptrace_may_access - Determine whether the current process may access + * cap_ptrace_access_check - Determine whether the current process may access * another * @child: The process to be accessed * @mode: The mode of attachment. @@ -109,7 +109,7 @@ int cap_settime(struct timespec *ts, struct timezone *tz) * Determine whether a process may access another, returning 0 if permission * granted, -ve if denied. */ -int cap_ptrace_may_access(struct task_struct *child, unsigned int mode) +int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) { int ret = 0; diff --git a/security/security.c b/security/security.c index dc7674f..4501c5e 100644 --- a/security/security.c +++ b/security/security.c @@ -124,9 +124,9 @@ int register_security(struct security_operations *ops) /* Security operations */ -int security_ptrace_may_access(struct task_struct *child, unsigned int mode) +int security_ptrace_access_check(struct task_struct *child, unsigned int mode) { - return security_ops->ptrace_may_access(child, mode); + return security_ops->ptrace_access_check(child, mode); } int security_ptrace_traceme(struct task_struct *parent) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d6f6478..e3b4f30 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1854,12 +1854,12 @@ static inline u32 open_file_to_av(struct file *file) /* Hook functions begin here. */ -static int selinux_ptrace_may_access(struct task_struct *child, +static int selinux_ptrace_access_check(struct task_struct *child, unsigned int mode) { int rc; - rc = cap_ptrace_may_access(child, mode); + rc = cap_ptrace_access_check(child, mode); if (rc) return rc; @@ -5315,7 +5315,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) static struct security_operations selinux_ops = { .name = "selinux", - .ptrace_may_access = selinux_ptrace_may_access, + .ptrace_access_check = selinux_ptrace_access_check, .ptrace_traceme = selinux_ptrace_traceme, .capget = selinux_capget, .capset = selinux_capset, diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 0023182..1c9bdbc 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -91,7 +91,7 @@ struct inode_smack *new_inode_smack(char *smack) */ /** - * smack_ptrace_may_access - Smack approval on PTRACE_ATTACH + * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH * @ctp: child task pointer * @mode: ptrace attachment mode * @@ -99,13 +99,13 @@ struct inode_smack *new_inode_smack(char *smack) * * Do the capability checks, and require read and write. */ -static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode) +static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) { int rc; struct smk_audit_info ad; char *sp, *tsp; - rc = cap_ptrace_may_access(ctp, mode); + rc = cap_ptrace_access_check(ctp, mode); if (rc != 0) return rc; @@ -3032,7 +3032,7 @@ static void smack_release_secctx(char *secdata, u32 seclen) struct security_operations smack_ops = { .name = "smack", - .ptrace_may_access = smack_ptrace_may_access, + .ptrace_access_check = smack_ptrace_access_check, .ptrace_traceme = smack_ptrace_traceme, .syslog = smack_syslog, -- cgit v0.10.2 From a893a84e8799270fbec5c3708d001650aab47138 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 23 Jun 2009 21:25:32 +0200 Subject: mm_for_maps: simplify, use ptrace_may_access() It would be nice to kill __ptrace_may_access(). It requires task_lock(), but this lock is only needed to read mm->flags in the middle. Convert mm_for_maps() to use ptrace_may_access(), this also simplifies the code a little bit. Also, we do not need to take ->mmap_sem in advance. In fact I think mm_for_maps() should not play with ->mmap_sem at all, the caller should take this lock. With or without this patch, without ->cred_guard_mutex held we can race with exec() and get the new ->mm but check old creds. Signed-off-by: Oleg Nesterov Reviewed-by: Serge Hallyn Signed-off-by: James Morris diff --git a/fs/proc/base.c b/fs/proc/base.c index 3ce5ae9..917f338 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -237,20 +237,19 @@ struct mm_struct *mm_for_maps(struct task_struct *task) struct mm_struct *mm = get_task_mm(task); if (!mm) return NULL; + if (mm != current->mm) { + /* + * task->mm can be changed before security check, + * in that case we must notice the change after. + */ + if (!ptrace_may_access(task, PTRACE_MODE_READ) || + mm != task->mm) { + mmput(mm); + return NULL; + } + } down_read(&mm->mmap_sem); - task_lock(task); - if (task->mm != mm) - goto out; - if (task->mm != current->mm && - __ptrace_may_access(task, PTRACE_MODE_READ) < 0) - goto out; - task_unlock(task); return mm; -out: - task_unlock(task); - up_read(&mm->mmap_sem); - mmput(mm); - return NULL; } static int proc_pid_cmdline(struct task_struct *task, char * buffer) -- cgit v0.10.2 From 89c86576ecde504da1eeb4f4882b2189ac2f9c4a Mon Sep 17 00:00:00 2001 From: Thomas Liu Date: Wed, 24 Jun 2009 17:58:05 -0400 Subject: selinux: clean up avc node cache when disabling selinux Added a call to free the avc_node_cache when inside selinux_disable because it should not waste resources allocated during avc_init if SELinux is disabled and the cache will never be used. Signed-off-by: Thomas Liu Acked-by: Eric Paris Signed-off-by: James Morris diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 7823e84..236aaa2 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -970,3 +970,9 @@ u32 avc_policy_seqno(void) { return avc_cache.latest_notif; } + +void avc_disable(void) +{ + if (avc_node_cachep) + kmem_cache_destroy(avc_node_cachep); +} diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e3b4f30..2081055 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5683,6 +5683,9 @@ int selinux_disable(void) selinux_disabled = 1; selinux_enabled = 0; + /* Try to destroy the avc node cache */ + avc_disable(); + /* Reset security_ops to the secondary module, dummy or capability. */ security_ops = secondary_ops; diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 46a940d..ae4c3a0 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -131,6 +131,9 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, int avc_get_hash_stats(char *page); extern unsigned int avc_cache_threshold; +/* Attempt to free avc node cache */ +void avc_disable(void); + #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats); #endif -- cgit v0.10.2 From 409a736336b560798f84d71ad6477c8fad20b523 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 25 Jun 2009 13:50:53 +0800 Subject: hwrng: Use PCI_VDEVICE Signed-off-by: Joe Perches Acked-by: Matt Mackall Signed-off-by: Herbert Xu diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index cd0ba51..0d8c578 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c @@ -44,8 +44,8 @@ * want to register another driver on the same PCI id. */ static const struct pci_device_id pci_tbl[] = { - { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, - { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, + { PCI_VDEVICE(AMD, 0x7443), 0, }, + { PCI_VDEVICE(AMD, 0x746b), 0, }, { 0, }, /* terminate list */ }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c index 64d513f..4c4d4e1 100644 --- a/drivers/char/hw_random/geode-rng.c +++ b/drivers/char/hw_random/geode-rng.c @@ -46,8 +46,7 @@ * want to register another driver on the same PCI id. */ static const struct pci_device_id pci_tbl[] = { - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_LX_AES), 0, }, { 0, }, /* terminate list */ }; MODULE_DEVICE_TABLE(pci, pci_tbl); -- cgit v0.10.2 From 435578aeaad5859dda8657e3ed2c1a5bc1e524ec Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 25 Jun 2009 14:46:31 +0800 Subject: crypto: skcipher - Fix request for sync algorithms When a sync givcipher algorithm is requested, if an async version of the same algorithm already exists, then we will loop forever without ever constructing the sync version based on a blkcipher. This is because we did not include the requested type/mask when getting a larval for the geniv algorithm that is to be constructed. Signed-off-by: Herbert Xu diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index e11ce37..43fc8fb 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -201,8 +201,9 @@ static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask) int err; larval = crypto_larval_lookup(alg->cra_driver_name, + (type & ~CRYPTO_ALG_TYPE_MASK) | CRYPTO_ALG_TYPE_GIVCIPHER, - CRYPTO_ALG_TYPE_MASK); + mask | CRYPTO_ALG_TYPE_MASK); err = PTR_ERR(larval); if (IS_ERR(larval)) goto out; -- cgit v0.10.2 From b40e9538124fc9b9333e3eea0fc514da4a185dae Mon Sep 17 00:00:00 2001 From: Igor Chernyshev Date: Thu, 25 Jun 2009 09:31:07 +0200 Subject: ALSA: ice1724 - Patch for suspend/resume for Audiotrak Prodigy HD2 I've built a small HTPC and had to add suspend/resume support in ice1724 driver. There seem to be 3 existing bugs related to that: https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4413 https://bugtrack.alsa-project.org/alsa-bug/view.php?id=3748 https://bugtrack.alsa-project.org/alsa-bug/view.php?id=2314 Due to hardware (un)availability, I only enabled the fix for Audiotrak Prodigy HD2 card, which is installed in my HTPC. However, most of my code should be reusable in the future on other ice1724-based cards as well (as long as people add card-specific peices of code). The fix is currently based on ALSA 1.0.20 and works on my MythBuntu 9.04 HTPC (using 2.6.28-11 kernel). Signed-off-by: Igor Chernyshev Signed-off-by: Takashi Iwai diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index adc909e..9da2dae 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -379,6 +379,15 @@ struct snd_ice1712 { unsigned char (*set_mclk)(struct snd_ice1712 *ice, unsigned int rate); void (*set_spdif_clock)(struct snd_ice1712 *ice); +#ifdef CONFIG_PM + int (*pm_suspend)(struct snd_ice1712 *); + int (*pm_resume)(struct snd_ice1712 *); + int pm_suspend_enabled:1; + int pm_saved_is_spdif_master:1; + unsigned int pm_saved_spdif_ctrl; + unsigned char pm_saved_spdif_cfg; + unsigned int pm_saved_route; +#endif }; diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 36ade77..6a56002 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -560,6 +560,7 @@ static int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: spin_lock(&ice->reg_lock); old = inb(ICEMT1724(ice, DMA_CONTROL)); if (cmd == SNDRV_PCM_TRIGGER_START) @@ -570,6 +571,10 @@ static int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_unlock(&ice->reg_lock); break; + case SNDRV_PCM_TRIGGER_RESUME: + /* apps will have to restart stream */ + break; + default: return -EINVAL; } @@ -2272,7 +2277,7 @@ static void __devinit snd_vt1724_chip_reset(struct snd_ice1712 *ice) msleep(10); } -static int __devinit snd_vt1724_chip_init(struct snd_ice1712 *ice) +static int snd_vt1724_chip_init(struct snd_ice1712 *ice) { outb(ice->eeprom.data[ICE_EEP2_SYSCONF], ICEREG1724(ice, SYS_CFG)); outb(ice->eeprom.data[ICE_EEP2_ACLINK], ICEREG1724(ice, AC97_CFG)); @@ -2287,6 +2292,14 @@ static int __devinit snd_vt1724_chip_init(struct snd_ice1712 *ice) outb(0, ICEREG1724(ice, POWERDOWN)); + /* MPU_RX and TX irq masks are cleared later dynamically */ + outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK)); + + /* don't handle FIFO overrun/underruns (just yet), + * since they cause machine lockups + */ + outb(VT1724_MULTI_FIFO_ERR, ICEMT1724(ice, DMA_INT_MASK)); + return 0; } @@ -2431,6 +2444,8 @@ static int __devinit snd_vt1724_create(struct snd_card *card, snd_vt1724_proc_init(ice); synchronize_irq(pci->irq); + card->private_data = ice; + err = pci_request_regions(pci, "ICE1724"); if (err < 0) { kfree(ice); @@ -2459,14 +2474,6 @@ static int __devinit snd_vt1724_create(struct snd_card *card, return -EIO; } - /* MPU_RX and TX irq masks are cleared later dynamically */ - outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK)); - - /* don't handle FIFO overrun/underruns (just yet), - * since they cause machine lockups - */ - outb(VT1724_MULTI_FIFO_ERR, ICEMT1724(ice, DMA_INT_MASK)); - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops); if (err < 0) { snd_vt1724_free(ice); @@ -2650,11 +2657,96 @@ static void __devexit snd_vt1724_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } +#ifdef CONFIG_PM +static int snd_vt1724_suspend(struct pci_dev *pci, pm_message_t state) +{ + struct snd_card *card = pci_get_drvdata(pci); + struct snd_ice1712 *ice = card->private_data; + + if (!ice->pm_suspend_enabled) + return 0; + + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + + snd_pcm_suspend_all(ice->pcm); + snd_pcm_suspend_all(ice->pcm_pro); + snd_pcm_suspend_all(ice->pcm_ds); + snd_ac97_suspend(ice->ac97); + + spin_lock_irq(&ice->reg_lock); + ice->pm_saved_is_spdif_master = ice->is_spdif_master(ice); + ice->pm_saved_spdif_ctrl = inw(ICEMT1724(ice, SPDIF_CTRL)); + ice->pm_saved_spdif_cfg = inb(ICEREG1724(ice, SPDIF_CFG)); + ice->pm_saved_route = inl(ICEMT1724(ice, ROUTE_PLAYBACK)); + spin_unlock_irq(&ice->reg_lock); + + if (ice->pm_suspend) + ice->pm_suspend(ice); + + pci_disable_device(pci); + pci_save_state(pci); + pci_set_power_state(pci, pci_choose_state(pci, state)); + return 0; +} + +static int snd_vt1724_resume(struct pci_dev *pci) +{ + struct snd_card *card = pci_get_drvdata(pci); + struct snd_ice1712 *ice = card->private_data; + + if (!ice->pm_suspend_enabled) + return 0; + + pci_set_power_state(pci, PCI_D0); + pci_restore_state(pci); + + if (pci_enable_device(pci) < 0) { + snd_card_disconnect(card); + return -EIO; + } + + pci_set_master(pci); + + snd_vt1724_chip_reset(ice); + + if (snd_vt1724_chip_init(ice) < 0) { + snd_card_disconnect(card); + return -EIO; + } + + if (ice->pm_resume) + ice->pm_resume(ice); + + if (ice->pm_saved_is_spdif_master) { + /* switching to external clock via SPDIF */ + ice->set_spdif_clock(ice); + } else { + /* internal on-card clock */ + snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1); + } + + update_spdif_bits(ice, ice->pm_saved_spdif_ctrl); + + outb(ice->pm_saved_spdif_cfg, ICEREG1724(ice, SPDIF_CFG)); + outl(ice->pm_saved_route, ICEMT1724(ice, ROUTE_PLAYBACK)); + + if (ice->ac97) + snd_ac97_resume(ice->ac97); + + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + return 0; +} +#endif + static struct pci_driver driver = { .name = "ICE1724", .id_table = snd_vt1724_ids, .probe = snd_vt1724_probe, .remove = __devexit_p(snd_vt1724_remove), +#ifdef CONFIG_PM + .suspend = snd_vt1724_suspend, + .resume = snd_vt1724_resume, +#endif }; static int __init alsa_card_ice1724_init(void) diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index 043a938..c75515f 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -1077,7 +1077,7 @@ static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice) /* * initialize the chip */ -static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) +static void ak4396_init(struct snd_ice1712 *ice) { static unsigned short ak4396_inits[] = { AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */ @@ -1087,9 +1087,37 @@ static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) AK4396_RCH_ATT, 0x00, }; - struct prodigy_hifi_spec *spec; unsigned int i; + /* initialize ak4396 codec */ + /* reset codec */ + ak4396_write(ice, AK4396_CTRL1, 0x86); + msleep(100); + ak4396_write(ice, AK4396_CTRL1, 0x87); + + for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2) + ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]); +} + +#ifdef CONFIG_PM +static int __devinit prodigy_hd2_resume(struct snd_ice1712 *ice) +{ + /* initialize ak4396 codec and restore previous mixer volumes */ + struct prodigy_hifi_spec *spec = ice->spec; + int i; + mutex_lock(&ice->gpio_mutex); + ak4396_init(ice); + for (i = 0; i < 2; i++) + ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff); + mutex_unlock(&ice->gpio_mutex); + return 0; +} +#endif + +static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) +{ + struct prodigy_hifi_spec *spec; + ice->vt1720 = 0; ice->vt1724 = 1; @@ -1112,14 +1140,12 @@ static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) return -ENOMEM; ice->spec = spec; - /* initialize ak4396 codec */ - /* reset codec */ - ak4396_write(ice, AK4396_CTRL1, 0x86); - msleep(100); - ak4396_write(ice, AK4396_CTRL1, 0x87); - - for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2) - ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]); +#ifdef CONFIG_PM + ice->pm_resume = &prodigy_hd2_resume; + ice->pm_suspend_enabled = 1; +#endif + + ak4396_init(ice); return 0; } -- cgit v0.10.2 From 0b67fb65d1b2ba1396de69112b8b9bc95d8d5feb Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 25 Jun 2009 18:43:48 +0800 Subject: crypto: skcipher - Change default sync geniv on SMP to eseqiv As it stands we use chainiv for sync algorithms and eseqiv for async algorithms. However, when there is more than one CPU chainiv forces all processing to be serialised which is usually not what you want. Also, the added overhead of eseqiv isn't that great. Therefore this patch changes the default sync geniv on SMP machines to eseqiv. For the odd situation where the overhead is unacceptable then chainiv is still available as an option. Note that on UP machines chainiv is still preferred over eseqiv for sync algorithms. Signed-off-by: Herbert Xu diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 43fc8fb..03fb5fa 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -14,6 +14,7 @@ */ #include +#include #include #include #include @@ -25,6 +26,8 @@ #include "internal.h" +static const char *skcipher_default_geniv __read_mostly; + static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen) { @@ -180,7 +183,8 @@ EXPORT_SYMBOL_GPL(crypto_givcipher_type); const char *crypto_default_geniv(const struct crypto_alg *alg) { - return alg->cra_flags & CRYPTO_ALG_ASYNC ? "eseqiv" : "chainiv"; + return alg->cra_flags & CRYPTO_ALG_ASYNC ? + "eseqiv" : skcipher_default_geniv; } static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask) @@ -361,3 +365,17 @@ err: return ERR_PTR(err); } EXPORT_SYMBOL_GPL(crypto_alloc_ablkcipher); + +static int __init skcipher_module_init(void) +{ + skcipher_default_geniv = num_possible_cpus() > 1 ? + "eseqiv" : "chainiv"; + return 0; +} + +static void skcipher_module_exit(void) +{ +} + +module_init(skcipher_module_init); +module_exit(skcipher_module_exit); -- cgit v0.10.2 From e2f551dacbdff8e40365a989ab66104b03316f4d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 25 Jun 2009 13:57:59 +0100 Subject: ASoC: Add core suspend and resume callbacks to WM8961 Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 8e78959..1af2d10 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -1267,6 +1267,21 @@ static __devexit int wm8961_i2c_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM +static int wm8961_i2c_suspend(struct i2c_client *client) +{ + return snd_soc_suspend_device(&client->dev); +} + +static int wm8961_i2c_resume(struct i2c_client *client) +{ + return snd_soc_resume_device(&client->dev); +} +#else +#define wm8961_i2c_suspend NULL +#define wm8961_i2c_resume NULL +#endif + static const struct i2c_device_id wm8961_i2c_id[] = { { "wm8961", 0 }, { } @@ -1280,6 +1295,8 @@ static struct i2c_driver wm8961_i2c_driver = { }, .probe = wm8961_i2c_probe, .remove = __devexit_p(wm8961_i2c_remove), + .suspend = wm8961_i2c_suspend, + .resume = wm8961_i2c_resume, .id_table = wm8961_i2c_id, }; -- cgit v0.10.2 From 647613e97fa46f6c25cf38b0f2fa81eba5f278d4 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 25 Jun 2009 22:36:58 +0900 Subject: ASoC: txx9aclc: dynamically allocate dmaengine devname Use kasprintf to allocate temporary devname string instead of a fixed size string. This fixes "FIXME" introduced on removal of BUS_ID_SIZE. Signed-off-by: Atsushi Nemoto Signed-off-by: Mark Brown diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index 938a58a..efed64b 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -297,15 +297,17 @@ static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, static bool filter(struct dma_chan *chan, void *param) { struct txx9aclc_dmadata *dmadata = param; - char devname[20 + 2]; /* FIXME: old BUS_ID_SIZE + 2 */ + char *devname; + bool found = false; - snprintf(devname, sizeof(devname), "%s.%d", dmadata->dma_res->name, + devname = kasprintf(GFP_KERNEL, "%s.%d", dmadata->dma_res->name, (int)dmadata->dma_res->start); if (strcmp(dev_name(chan->device->dev), devname) == 0) { chan->private = &dmadata->dma_slave; - return true; + found = true; } - return false; + kfree(devname); + return found; } static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev, -- cgit v0.10.2 From e3c7dbb07cde886ba97f183c4cc98a2a99b46eaa Mon Sep 17 00:00:00 2001 From: "Lopez Cruz, Misael" Date: Thu, 25 Jun 2009 12:36:14 -0500 Subject: ASoC: Remove word "Switch" from Handsfree switch name SoC dapm adds the suffix "Switch" to SND_SOC_DAPM_SWITCH controls, removing word "Switch" from HandsfreeL/HandsfreeR widget name for avoiding to duplicate it. Signed-off-by: Misael Lopez Cruz Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index df42fa2..49ceb62 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1258,14 +1258,14 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { /* HandsfreeL/R */ SND_SOC_DAPM_MUX("HandsfreeL Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_handsfreel_control), - SND_SOC_DAPM_SWITCH("HandsfreeL Switch", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SWITCH("HandsfreeL", SND_SOC_NOPM, 0, 0, &twl4030_dapm_handsfreelmute_control), SND_SOC_DAPM_PGA_E("HandsfreeL PGA", SND_SOC_NOPM, 0, 0, NULL, 0, handsfreelpga_event, SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("HandsfreeR Mux", SND_SOC_NOPM, 5, 0, &twl4030_dapm_handsfreer_control), - SND_SOC_DAPM_SWITCH("HandsfreeR Switch", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SWITCH("HandsfreeR", SND_SOC_NOPM, 0, 0, &twl4030_dapm_handsfreermute_control), SND_SOC_DAPM_PGA_E("HandsfreeR PGA", SND_SOC_NOPM, 0, 0, NULL, 0, handsfreerpga_event, @@ -1377,15 +1377,15 @@ static const struct snd_soc_dapm_route intercon[] = { {"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"}, {"HandsfreeL Mux", "AudioL2", "Analog L2 Playback Mixer"}, {"HandsfreeL Mux", "AudioR2", "Analog R2 Playback Mixer"}, - {"HandsfreeL Switch", "Switch", "HandsfreeL Mux"}, - {"HandsfreeL PGA", NULL, "HandsfreeL Switch"}, + {"HandsfreeL", "Switch", "HandsfreeL Mux"}, + {"HandsfreeL PGA", NULL, "HandsfreeL"}, /* HandsfreeR */ {"HandsfreeR Mux", "Voice", "Analog Voice Playback Mixer"}, {"HandsfreeR Mux", "AudioR1", "Analog R1 Playback Mixer"}, {"HandsfreeR Mux", "AudioR2", "Analog R2 Playback Mixer"}, {"HandsfreeR Mux", "AudioL2", "Analog L2 Playback Mixer"}, - {"HandsfreeR Switch", "Switch", "HandsfreeR Mux"}, - {"HandsfreeR PGA", NULL, "HandsfreeR Switch"}, + {"HandsfreeR", "Switch", "HandsfreeR Mux"}, + {"HandsfreeR PGA", NULL, "HandsfreeR"}, /* Vibra */ {"Vibra Mux", "AudioL1", "DAC Left1"}, {"Vibra Mux", "AudioR1", "DAC Right1"}, -- cgit v0.10.2 From c2caa4da46a41899b29f90ec30ef3ba86665b334 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 26 Jun 2009 15:36:56 +0100 Subject: ASoC: Fix widget powerdown on shutdown We need to set the widget power state we want to implement. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b9129ef..5157ec1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2045,6 +2045,7 @@ void snd_soc_dapm_shutdown(struct snd_soc_device *socdev) list_for_each_entry(w, &codec->dapm_widgets, list) { if (w->power) { dapm_seq_insert(w, &down_list, dapm_down_seq); + w->power = 0; powerdown = 1; } } -- cgit v0.10.2 From 2495fbf7effa6868f5d74124ae9b22a57980755b Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 26 Jun 2009 10:53:57 -0700 Subject: x86, setup: remove obsolete pre-Kconfig CONFIG_VIDEO_ variables There were a set of pre-Kconfig configuration variables defined in the video code. There is absolutely no evidence that they have been tweaked by anybody in modern history, so just get rid of them and hope nobody notices. If someone does complain, these should be made real Kconfig variables. Reported-by: Robert P. J. Day Signed-off-by: H. Peter Anvin diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c index c700147..d7ef26b 100644 --- a/arch/x86/boot/video-vesa.c +++ b/arch/x86/boot/video-vesa.c @@ -31,7 +31,6 @@ static inline void vesa_store_mode_params_graphics(void) {} static int vesa_probe(void) { -#if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID) struct biosregs ireg, oreg; u16 mode; addr_t mode_ptr; @@ -49,8 +48,7 @@ static int vesa_probe(void) vginfo.signature != VESA_MAGIC || vginfo.version < 0x0102) return 0; /* Not present */ -#endif /* CONFIG_VIDEO_VESA || CONFIG_FIRMWARE_EDID */ -#ifdef CONFIG_VIDEO_VESA + set_fs(vginfo.video_mode_ptr.seg); mode_ptr = vginfo.video_mode_ptr.off; @@ -102,9 +100,6 @@ static int vesa_probe(void) } return nmodes; -#else - return 0; -#endif /* CONFIG_VIDEO_VESA */ } static int vesa_set_mode(struct mode_info *mode) diff --git a/arch/x86/boot/video-vga.c b/arch/x86/boot/video-vga.c index 8f8d827..819caa1 100644 --- a/arch/x86/boot/video-vga.c +++ b/arch/x86/boot/video-vga.c @@ -47,14 +47,6 @@ static u8 vga_set_basic_mode(void) initregs(&ireg); -#ifdef CONFIG_VIDEO_400_HACK - if (adapter >= ADAPTER_VGA) { - ireg.ax = 0x1202; - ireg.bx = 0x0030; - intcall(0x10, &ireg, NULL); - } -#endif - ax = 0x0f00; intcall(0x10, &ireg, &oreg); mode = oreg.al; @@ -62,11 +54,9 @@ static u8 vga_set_basic_mode(void) set_fs(0); rows = rdfs8(0x484); /* rows minus one */ -#ifndef CONFIG_VIDEO_400_HACK if ((oreg.ax == 0x5003 || oreg.ax == 0x5007) && (rows == 0 || rows == 24)) return mode; -#endif if (mode != 3 && mode != 7) mode = 3; diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c index bad728b..d42da38 100644 --- a/arch/x86/boot/video.c +++ b/arch/x86/boot/video.c @@ -221,7 +221,6 @@ static unsigned int mode_menu(void) } } -#ifdef CONFIG_VIDEO_RETAIN /* Save screen content to the heap */ static struct saved_screen { int x, y; @@ -299,10 +298,6 @@ static void restore_screen(void) ireg.dl = saved.curx; intcall(0x10, &ireg, NULL); } -#else -#define save_screen() ((void)0) -#define restore_screen() ((void)0) -#endif void set_video(void) { diff --git a/arch/x86/boot/video.h b/arch/x86/boot/video.h index 5bb174a..ff339c5 100644 --- a/arch/x86/boot/video.h +++ b/arch/x86/boot/video.h @@ -17,19 +17,8 @@ #include -/* Enable autodetection of SVGA adapters and modes. */ -#undef CONFIG_VIDEO_SVGA - -/* Enable autodetection of VESA modes */ -#define CONFIG_VIDEO_VESA - -/* Retain screen contents when switching modes */ -#define CONFIG_VIDEO_RETAIN - -/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */ -#undef CONFIG_VIDEO_400_HACK - -/* This code uses an extended set of video mode numbers. These include: +/* + * This code uses an extended set of video mode numbers. These include: * Aliases for standard modes * NORMAL_VGA (-1) * EXTENDED_VGA (-2) @@ -67,13 +56,8 @@ /* The "recalculate timings" flag */ #define VIDEO_RECALC 0x8000 -/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ -#ifdef CONFIG_VIDEO_RETAIN void store_screen(void); #define DO_STORE() store_screen() -#else -#define DO_STORE() ((void)0) -#endif /* CONFIG_VIDEO_RETAIN */ /* * Mode table structures -- cgit v0.10.2 From 087975b06b00af9bf888fab6f94ae113c5cd80bd Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 27 Jun 2009 15:35:15 +0900 Subject: x86: Clean up dump_pagetable() Use pgtable access helpers for 32-bit version dump_pagetable() and get rid of __typeof__() operators. This needs to make pmd_pfn() available for 2-level pgtable. Also, remove some casts for 64-bit version dump_pagetable(). Signed-off-by: Akinobu Mita LKML-Reference: <20090627063514.GA2834@localhost.localdomain> Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 3cc06e3..af5481e 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -134,6 +134,11 @@ static inline unsigned long pte_pfn(pte_t pte) return (pte_val(pte) & PTE_PFN_MASK) >> PAGE_SHIFT; } +static inline unsigned long pmd_pfn(pmd_t pmd) +{ + return (pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT; +} + #define pte_page(pte) pfn_to_page(pte_pfn(pte)) static inline int pmd_large(pmd_t pte) @@ -422,11 +427,6 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(address); } -static inline unsigned long pmd_pfn(pmd_t pmd) -{ - return (pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT; -} - static inline int pud_large(pud_t pud) { return (pud_val(pud) & (_PAGE_PSE | _PAGE_PRESENT)) == diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 78a5fff..9bf7e52 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -285,26 +285,25 @@ check_v8086_mode(struct pt_regs *regs, unsigned long address, tsk->thread.screen_bitmap |= 1 << bit; } -static void dump_pagetable(unsigned long address) +static bool low_pfn(unsigned long pfn) { - __typeof__(pte_val(__pte(0))) page; + return pfn < max_low_pfn; +} - page = read_cr3(); - page = ((__typeof__(page) *) __va(page))[address >> PGDIR_SHIFT]; +static void dump_pagetable(unsigned long address) +{ + pgd_t *base = __va(read_cr3()); + pgd_t *pgd = &base[pgd_index(address)]; + pmd_t *pmd; + pte_t *pte; #ifdef CONFIG_X86_PAE - printk("*pdpt = %016Lx ", page); - if ((page >> PAGE_SHIFT) < max_low_pfn - && page & _PAGE_PRESENT) { - page &= PAGE_MASK; - page = ((__typeof__(page) *) __va(page))[(address >> PMD_SHIFT) - & (PTRS_PER_PMD - 1)]; - printk(KERN_CONT "*pde = %016Lx ", page); - page &= ~_PAGE_NX; - } -#else - printk("*pde = %08lx ", page); + printk("*pdpt = %016Lx ", pgd_val(*pgd)); + if (!low_pfn(pgd_val(*pgd) >> PAGE_SHIFT) || !pgd_present(*pgd)) + goto out; #endif + pmd = pmd_offset(pud_offset(pgd, address), address); + printk(KERN_CONT "*pde = %0*Lx ", sizeof(*pmd) * 2, (u64)pmd_val(*pmd)); /* * We must not directly access the pte in the highpte @@ -312,16 +311,12 @@ static void dump_pagetable(unsigned long address) * And let's rather not kmap-atomic the pte, just in case * it's allocated already: */ - if ((page >> PAGE_SHIFT) < max_low_pfn - && (page & _PAGE_PRESENT) - && !(page & _PAGE_PSE)) { - - page &= PAGE_MASK; - page = ((__typeof__(page) *) __va(page))[(address >> PAGE_SHIFT) - & (PTRS_PER_PTE - 1)]; - printk("*pte = %0*Lx ", sizeof(page)*2, (u64)page); - } + if (!low_pfn(pmd_pfn(*pmd)) || !pmd_present(*pmd) || pmd_large(*pmd)) + goto out; + pte = pte_offset_kernel(pmd, address); + printk("*pte = %0*Lx ", sizeof(*pte) * 2, (u64)pte_val(*pte)); +out: printk("\n"); } @@ -449,16 +444,12 @@ static int bad_address(void *p) static void dump_pagetable(unsigned long address) { - pgd_t *pgd; + pgd_t *base = __va(read_cr3() & PHYSICAL_PAGE_MASK); + pgd_t *pgd = base + pgd_index(address); pud_t *pud; pmd_t *pmd; pte_t *pte; - pgd = (pgd_t *)read_cr3(); - - pgd = __va((unsigned long)pgd & PHYSICAL_PAGE_MASK); - - pgd += pgd_index(address); if (bad_address(pgd)) goto bad; -- cgit v0.10.2 From ce0c0f9eec2f377055e8b23c6fa192202381e022 Mon Sep 17 00:00:00 2001 From: "Figo.zhang" Date: Sun, 28 Jun 2009 18:07:39 +0800 Subject: x86, pgtable.h: Clean up types Use "unsigned long" consistently, not "unsigned". Signed-off-by: Figo.zhang LKML-Reference: <1246183659.2530.4.camel@myhost> Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index af5481e..9de8729 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -356,7 +356,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) * this macro returns the index of the entry in the pmd page which would * control the given virtual address */ -static inline unsigned pmd_index(unsigned long address) +static inline unsigned long pmd_index(unsigned long address) { return (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); } @@ -376,7 +376,7 @@ static inline unsigned pmd_index(unsigned long address) * this function returns the index of the entry in the pte page which would * control the given virtual address */ -static inline unsigned pte_index(unsigned long address) +static inline unsigned long pte_index(unsigned long address) { return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); } @@ -462,7 +462,7 @@ static inline unsigned long pgd_page_vaddr(pgd_t pgd) #define pgd_page(pgd) pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT) /* to find an entry in a page-table-directory. */ -static inline unsigned pud_index(unsigned long address) +static inline unsigned long pud_index(unsigned long address) { return (address >> PUD_SHIFT) & (PTRS_PER_PUD - 1); } -- cgit v0.10.2 From 565b0c1f100408ccbcb04ba458a14da454cb271d Mon Sep 17 00:00:00 2001 From: "Figo.zhang" Date: Mon, 29 Jun 2009 12:02:55 +0800 Subject: x86, highmem_32.c: Clean up comment Signed-off-by: Figo.zhang Cc: Andrew Morton LKML-Reference: <1246248175.5759.12.camel@myhost> Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index 58f621e..0c6f43c 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -24,7 +24,7 @@ void kunmap(struct page *page) * no global lock is needed and because the kmap code must perform a global TLB * invalidation when the kmap pool wraps. * - * However when holding an atomic kmap is is not legal to sleep, so atomic + * However when holding an atomic kmap it is not legal to sleep, so atomic * kmaps are appropriate for short, tight code paths only. */ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot) -- cgit v0.10.2 From 74a0094cd9d030d7a684e6ce1cbd1658eb63bd7d Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 27 Jun 2009 16:26:35 +0200 Subject: ALSA: cmi8330: revert comments about AD1848 back In ALSA 1.0.20, the comments were changed to say CMI8330 instead of AD1848. The CMI8330 chip includes two codecs - AD1848 and SB16, so the comments were correct and are misleading now. Revert them back. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 3ee0269..d510c76 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -35,7 +35,7 @@ * * This card has two mixers and two PCM devices. I've cheesed it such * that recording and playback can be done through the same device. - * The driver "magically" routes the capturing to the CMI8330 codec, + * The driver "magically" routes the capturing to the AD1848 codec, * and playback to the SB16 codec. This allows for full-duplex mode * to some extent. * The utilities in alsa-utils are aware of both devices, so passing @@ -345,7 +345,7 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, err = pnp_activate_dev(pdev); if (err < 0) { - snd_printk(KERN_ERR "CMI8330/C3D PnP configure failure\n"); + snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n"); return -EBUSY; } wssport[dev] = pnp_port_start(pdev, 0); @@ -527,11 +527,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) wssdma[dev], -1, WSS_HW_DETECT, 0, &acard->wss); if (err < 0) { - snd_printk(KERN_ERR PFX "(CMI8330) device busy??\n"); + snd_printk(KERN_ERR PFX "(AD1848) device busy??\n"); return err; } if (acard->wss->hardware != WSS_HW_CMI8330) { - snd_printk(KERN_ERR PFX "(CMI8330) not found during probe\n"); + snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n"); return -ENODEV; } -- cgit v0.10.2 From b7b51141b4fb6f9059a20c03dd2a5bf77c466c7e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 29 Jun 2009 08:34:06 +0200 Subject: ALSA: hda - Check "beep" hint Check the hint "beep" in snd_hda_attach_beep_device() to avoid the beep device creation if user doesn't want. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 29272f2..08fe659 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -24,6 +24,7 @@ #include #include #include "hda_beep.h" +#include "hda_local.h" enum { DIGBEEP_HZ_STEP = 46875, /* 46.875 Hz */ @@ -115,6 +116,9 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) struct hda_beep *beep; int err; + if (!snd_hda_get_bool_hint(codec, "beep")) + return 0; /* disabled explicitly */ + beep = kzalloc(sizeof(*beep), GFP_KERNEL); if (beep == NULL) return -ENOMEM; -- cgit v0.10.2 From 54d35f29f49224d86b994acb6e5969b9ba09022d Mon Sep 17 00:00:00 2001 From: Hitoshi Mitake Date: Mon, 29 Jun 2009 14:44:57 +0900 Subject: sched: Hide runqueues from direct reference at source code level for __raw_get_cpu_var() Hide __raw_get_cpu_var() as well - thus all the direct references to runqueues will abstracted out. Signed-off-by: Hitoshi Mitake LKML-Reference: <20090629.144457.886429910353660979.mitake@dcl.info.waseda.ac.jp> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 168b268..ebc5151 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -692,6 +692,7 @@ static inline int cpu_of(struct rq *rq) #define this_rq() (&__get_cpu_var(runqueues)) #define task_rq(p) cpu_rq(task_cpu(p)) #define cpu_curr(cpu) (cpu_rq(cpu)->curr) +#define raw_rq() (&__raw_get_cpu_var(runqueues)) inline void update_rq_clock(struct rq *rq) { @@ -6669,7 +6670,7 @@ EXPORT_SYMBOL(yield); */ void __sched io_schedule(void) { - struct rq *rq = &__raw_get_cpu_var(runqueues); + struct rq *rq = raw_rq(); delayacct_blkio_start(); atomic_inc(&rq->nr_iowait); @@ -6681,7 +6682,7 @@ EXPORT_SYMBOL(io_schedule); long __sched io_schedule_timeout(long timeout) { - struct rq *rq = &__raw_get_cpu_var(runqueues); + struct rq *rq = raw_rq(); long ret; delayacct_blkio_start(); -- cgit v0.10.2 From 372a14a4a4db18751cd092aa3fe2a58216a8fc2f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 29 Jun 2009 14:56:01 +0100 Subject: ASoC: Remove unreferenced wm8974_add_controls() Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 397432a..d2a36ad 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -205,22 +205,6 @@ SOC_SINGLE("Capture Boost(+20dB)", WM8974_ADCBOOST, 8, 1, 0), SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 0), }; -/* add non dapm controls */ -static int wm8974_add_controls(struct snd_soc_codec *codec) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(wm8974_snd_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&wm8974_snd_controls[i], - codec, NULL)); - if (err < 0) - return err; - } - - return 0; -} - /* Speaker Output Mixer */ static const struct snd_kcontrol_new wm8974_speaker_mixer_controls[] = { SOC_DAPM_SINGLE("Line Bypass Switch", WM8974_SPKMIX, 1, 1, 0), -- cgit v0.10.2 From 9ea21ebca1a1c4caf3bdaecb0879034107cac1e9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 29 Jun 2009 16:29:06 +0100 Subject: ASoC: Fix WM8961 suspend function type Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 1af2d10..bd1af92 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -1268,7 +1268,7 @@ static __devexit int wm8961_i2c_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int wm8961_i2c_suspend(struct i2c_client *client) +static int wm8961_i2c_suspend(struct i2c_client *client, pm_message_t state) { return snd_soc_suspend_device(&client->dev); } -- cgit v0.10.2 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 diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 939a3dd..a1895d7 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 3a8e58c..6a899e8 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 */ @@ -6358,6 +6440,18 @@ static struct hda_verb alc882_3ST_ch2_init[] = { }; /* + * 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 */ static struct hda_verb alc882_3ST_ch6_init[] = { @@ -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 }, @@ -9613,9 +9055,32 @@ 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 v0.10.2 From 0d971c9fcf06d22663040570c3cfe08b137c4b2f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 30 Jun 2009 16:11:11 +0200 Subject: ALSA: hda - Fix input pinctl for ALC882 auto mode alc882_auto_init_analog_input() sets the input pins to VREF-80 regardless of the input pin types although it shouldn't be for line-in pins. This patch fixes the behavior to follow other codecs. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6a899e8..0f6b6a6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9125,9 +9125,6 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec) 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; @@ -9137,7 +9134,7 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec) hda_nid_t nid = spec->autocfg.input_pins[i]; if (!nid) continue; - alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/); + alc_set_input_pin(codec, nid, i); if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, -- cgit v0.10.2 From 416356fcfad46bdebcf8e2afdb94919401ff99d3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 30 Jun 2009 19:05:15 +0100 Subject: ASoC: Convert to dev_pm_ops Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2355032..dfc03c0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -619,8 +619,9 @@ static struct snd_pcm_ops soc_pcm_ops = { #ifdef CONFIG_PM /* powers down audio subsystem for suspend */ -static int soc_suspend(struct platform_device *pdev, pm_message_t state) +static int soc_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_card *card = socdev->card; struct snd_soc_platform *platform = card->platform; @@ -656,7 +657,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) snd_pcm_suspend_all(card->dai_link[i].pcm); if (card->suspend_pre) - card->suspend_pre(pdev, state); + card->suspend_pre(pdev, PMSG_SUSPEND); for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; @@ -682,7 +683,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) } if (codec_dev->suspend) - codec_dev->suspend(pdev, state); + codec_dev->suspend(pdev, PMSG_SUSPEND); for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; @@ -691,7 +692,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) } if (card->suspend_post) - card->suspend_post(pdev, state); + card->suspend_post(pdev, PMSG_SUSPEND); return 0; } @@ -765,8 +766,9 @@ static void soc_resume_deferred(struct work_struct *work) } /* powers up audio subsystem after a suspend */ -static int soc_resume(struct platform_device *pdev) +static int soc_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_card *card = socdev->card; struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai; @@ -826,7 +828,6 @@ int snd_soc_resume_device(struct device *dev) return 0; } EXPORT_SYMBOL_GPL(snd_soc_resume_device); - #else #define soc_suspend NULL #define soc_resume NULL @@ -1020,32 +1021,39 @@ static int soc_remove(struct platform_device *pdev) return 0; } -static void soc_shutdown(struct platform_device *pdev) +static int soc_poweroff(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_card *card = socdev->card; if (!card->instantiated) - return; + return 0; /* Flush out pmdown_time work - we actually do want to run it * now, we're shutting down so no imminent restart. */ run_delayed_work(&card->delayed_work); snd_soc_dapm_shutdown(socdev); + + return 0; } +static struct dev_pm_ops soc_pm_ops = { + .suspend = soc_suspend, + .resume = soc_resume, + .poweroff = soc_poweroff, +}; + /* ASoC platform driver */ static struct platform_driver soc_driver = { .driver = { .name = "soc-audio", .owner = THIS_MODULE, + .pm = &soc_pm_ops, }, .probe = soc_probe, .remove = soc_remove, - .suspend = soc_suspend, - .resume = soc_resume, - .shutdown = soc_shutdown, }; /* create a new pcm */ -- cgit v0.10.2 From df1ef7a38db21a92239c775a28f0c69124c9b454 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 30 Jun 2009 19:01:09 +0100 Subject: ASoC: Refresh WM8974 bias configuration Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index d2a36ad..c5d47bc 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -46,6 +46,9 @@ static const u16 wm8974_reg[WM8974_CACHEREGNUM] = { 0x0000, }; +#define WM8974_POWER1_BIASEN 0x08 +#define WM8974_POWER1_BUFIOEN 0x10 + struct wm8974_priv { struct snd_soc_codec codec; u16 reg_cache[WM8974_CACHEREGNUM]; @@ -528,22 +531,35 @@ static int wm8974_mute(struct snd_soc_dai *dai, int mute) static int wm8974_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + u16 power1 = wm8974_read_reg_cache(codec, WM8974_POWER1) & ~0x3; + switch (level) { case SND_SOC_BIAS_ON: - wm8974_write(codec, WM8974_POWER1, 0x1ff); - wm8974_write(codec, WM8974_POWER2, 0x1ff); - wm8974_write(codec, WM8974_POWER3, 0x1ff); - break; case SND_SOC_BIAS_PREPARE: + power1 |= 0x1; /* VMID 50k */ + wm8974_write(codec, WM8974_POWER1, power1); break; + case SND_SOC_BIAS_STANDBY: + power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN; + + if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* Initial cap charge at VMID 5k */ + wm8974_write(codec, WM8974_POWER1, power1 | 0x3); + mdelay(100); + } + + power1 |= 0x2; /* VMID 500k */ + wm8974_write(codec, WM8974_POWER1, power1); break; + case SND_SOC_BIAS_OFF: - wm8974_write(codec, WM8974_POWER1, 0x0); - wm8974_write(codec, WM8974_POWER2, 0x0); - wm8974_write(codec, WM8974_POWER3, 0x0); + wm8974_write(codec, WM8974_POWER1, 0); + wm8974_write(codec, WM8974_POWER2, 0); + wm8974_write(codec, WM8974_POWER3, 0); break; } + codec->bias_level = level; return 0; } -- cgit v0.10.2 From 33d81af4d12fc8863247abba1c1d706b462e89d0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 30 Jun 2009 19:01:52 +0100 Subject: ASoC: Declare 2 channels for WM8974 The device is a mono device but it can read two channel data and many I2S controllers only understand 2 channels. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index c5d47bc..207fe3f 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -582,13 +582,13 @@ struct snd_soc_dai wm8974_dai = { .playback = { .stream_name = "Playback", .channels_min = 1, - .channels_max = 1, + .channels_max = 2, /* Only 1 channel of data */ .rates = WM8974_RATES, .formats = WM8974_FORMATS,}, .capture = { .stream_name = "Capture", .channels_min = 1, - .channels_max = 1, + .channels_max = 2, /* Only 1 channel of data */ .rates = WM8974_RATES, .formats = WM8974_FORMATS,}, .ops = &wm8974_ops, -- cgit v0.10.2 From 91d0c3ecbaf6616c0723d7aad9b6dadad2dea43f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 30 Jun 2009 19:02:32 +0100 Subject: ASoC: Refresh WM8974 PLL configuration Move away from a fixed table to runtime calculation. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 207fe3f..d07bd0d 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -325,51 +325,84 @@ static int wm8974_add_widgets(struct snd_soc_codec *codec) } struct pll_ { - unsigned int in_hz, out_hz; - unsigned int pre:4; /* prescale - 1 */ + unsigned int pre_div:4; /* prescale - 1 */ unsigned int n:4; unsigned int k; }; -static struct pll_ pll[] = { - { 12000000, 11289600, 0, 7, 0x86c220 }, - { 12000000, 12288000, 0, 8, 0x3126e8 }, - { 13000000, 11289600, 0, 6, 0xf28bd4 }, - { 13000000, 12288000, 0, 7, 0x8fd525 }, - { 12288000, 11289600, 0, 7, 0x59999a }, - { 11289600, 12288000, 0, 8, 0x80dee9 }, - { 25000000, 11289600, 1, 7, 0x39B024 }, - { 25000000, 24576000, 1, 7, 0xdd4413 } -}; +static struct pll_ pll_div; + +/* The size in bits of the pll divide multiplied by 10 + * to allow rounding later */ +#define FIXED_PLL_SIZE ((1 << 24) * 10) + +static void pll_factors(unsigned int target, unsigned int source) +{ + unsigned long long Kpart; + unsigned int K, Ndiv, Nmod; + + Ndiv = target / source; + if (Ndiv < 6) { + source >>= 1; + pll_div.pre_div = 1; + Ndiv = target / source; + } else + pll_div.pre_div = 0; + + if ((Ndiv < 6) || (Ndiv > 12)) + printk(KERN_WARNING + "WM8974 N value %u outwith recommended range!d\n", + Ndiv); + + pll_div.n = Ndiv; + Nmod = target % source; + Kpart = FIXED_PLL_SIZE * (long long)Nmod; + + do_div(Kpart, source); + + K = Kpart & 0xFFFFFFFF; + + /* Check if we need to round */ + if ((K % 10) >= 5) + K += 5; + + /* Move down to proper range now rounding is done */ + K /= 10; + + pll_div.k = K; +} static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; - int i; u16 reg; if (freq_in == 0 || freq_out == 0) { + /* Clock CODEC directly from MCLK */ + reg = wm8974_read_reg_cache(codec, WM8974_CLOCK); + wm8974_write(codec, WM8974_CLOCK, reg & 0x0ff); + + /* Turn off PLL */ reg = wm8974_read_reg_cache(codec, WM8974_POWER1); wm8974_write(codec, WM8974_POWER1, reg & 0x1df); return 0; } - for (i = 0; i < ARRAY_SIZE(pll); i++) { - if (freq_in == pll[i].in_hz && freq_out == pll[i].out_hz) { - wm8974_write(codec, WM8974_PLLN, - (pll[i].pre << 4) | pll[i].n); - wm8974_write(codec, WM8974_PLLK1, pll[i].k >> 18); - wm8974_write(codec, WM8974_PLLK2, - (pll[i].k >> 9) & 0x1ff); - wm8974_write(codec, WM8974_PLLK3, pll[i].k & 0x1ff); - reg = wm8974_read_reg_cache(codec, WM8974_POWER1); - wm8974_write(codec, WM8974_POWER1, reg | 0x020); - return 0; - } - } + pll_factors(freq_out*4, freq_in); + + wm8974_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n); + wm8974_write(codec, WM8974_PLLK1, pll_div.k >> 18); + wm8974_write(codec, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff); + wm8974_write(codec, WM8974_PLLK3, pll_div.k & 0x1ff); + reg = wm8974_read_reg_cache(codec, WM8974_POWER1); + wm8974_write(codec, WM8974_POWER1, reg | 0x020); - return -EINVAL; + /* Run CODEC from PLL instead of MCLK */ + reg = wm8974_read_reg_cache(codec, WM8974_CLOCK); + wm8974_write(codec, WM8974_CLOCK, reg | 0x100); + + return 0; } /* -- cgit v0.10.2 From a5f8d2f1b83d47b09ff7b587b9402c449e1e18d5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 30 Jun 2009 19:30:33 +0100 Subject: ASoC: Add WM8974 TLV information Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index d07bd0d..cb2c412 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "wm8974.h" @@ -137,6 +138,11 @@ static const struct soc_enum wm8974_enum[] = { SOC_ENUM_SINGLE(WM8974_ALC3, 8, 2, wm8974_alc), }; +static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); +static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); +static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); + static const struct snd_kcontrol_new wm8974_snd_controls[] = { SOC_SINGLE("Digital Loopback Switch", WM8974_COMP, 0, 1, 0), @@ -147,33 +153,33 @@ SOC_ENUM("ADC Companding", wm8974_enum[0]), SOC_ENUM("Playback De-emphasis", wm8974_enum[2]), SOC_SINGLE("DAC Inversion Switch", WM8974_DAC, 0, 1, 0), -SOC_SINGLE("PCM Volume", WM8974_DACVOL, 0, 127, 0), +SOC_SINGLE_TLV("PCM Volume", WM8974_DACVOL, 0, 255, 0, digital_tlv), SOC_SINGLE("High Pass Filter Switch", WM8974_ADC, 8, 1, 0), SOC_SINGLE("High Pass Cut Off", WM8974_ADC, 4, 7, 0), SOC_SINGLE("ADC Inversion Switch", WM8974_COMP, 0, 1, 0), -SOC_SINGLE("Capture Volume", WM8974_ADCVOL, 0, 127, 0), +SOC_SINGLE_TLV("Capture Volume", WM8974_ADCVOL, 0, 255, 0, digital_tlv), SOC_ENUM("Equaliser Function", wm8974_enum[3]), SOC_ENUM("EQ1 Cut Off", wm8974_enum[4]), -SOC_SINGLE("EQ1 Volume", WM8974_EQ1, 0, 31, 1), +SOC_SINGLE_TLV("EQ1 Volume", WM8974_EQ1, 0, 24, 1, eq_tlv), SOC_ENUM("Equaliser EQ2 Bandwith", wm8974_enum[5]), SOC_ENUM("EQ2 Cut Off", wm8974_enum[6]), -SOC_SINGLE("EQ2 Volume", WM8974_EQ2, 0, 31, 1), +SOC_SINGLE_TLV("EQ2 Volume", WM8974_EQ2, 0, 24, 1, eq_tlv), SOC_ENUM("Equaliser EQ3 Bandwith", wm8974_enum[7]), SOC_ENUM("EQ3 Cut Off", wm8974_enum[8]), -SOC_SINGLE("EQ3 Volume", WM8974_EQ3, 0, 31, 1), +SOC_SINGLE_TLV("EQ3 Volume", WM8974_EQ3, 0, 24, 1, eq_tlv), SOC_ENUM("Equaliser EQ4 Bandwith", wm8974_enum[9]), SOC_ENUM("EQ4 Cut Off", wm8974_enum[10]), -SOC_SINGLE("EQ4 Volume", WM8974_EQ4, 0, 31, 1), +SOC_SINGLE_TLV("EQ4 Volume", WM8974_EQ4, 0, 24, 1, eq_tlv), SOC_ENUM("Equaliser EQ5 Bandwith", wm8974_enum[11]), SOC_ENUM("EQ5 Cut Off", wm8974_enum[12]), -SOC_SINGLE("EQ5 Volume", WM8974_EQ5, 0, 31, 1), +SOC_SINGLE_TLV("EQ5 Volume", WM8974_EQ5, 0, 24, 1, eq_tlv), SOC_SINGLE("DAC Playback Limiter Switch", WM8974_DACLIM1, 8, 1, 0), SOC_SINGLE("DAC Playback Limiter Decay", WM8974_DACLIM1, 4, 15, 0), @@ -198,11 +204,11 @@ SOC_SINGLE("ALC Capture Noise Gate Switch", WM8974_NGATE, 3, 1, 0), SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8974_NGATE, 0, 7, 0), SOC_SINGLE("Capture PGA ZC Switch", WM8974_INPPGA, 7, 1, 0), -SOC_SINGLE("Capture PGA Volume", WM8974_INPPGA, 0, 63, 0), +SOC_SINGLE_TLV("Capture PGA Volume", WM8974_INPPGA, 0, 63, 0, inpga_tlv), SOC_SINGLE("Speaker Playback ZC Switch", WM8974_SPKVOL, 7, 1, 0), SOC_SINGLE("Speaker Playback Switch", WM8974_SPKVOL, 6, 1, 1), -SOC_SINGLE("Speaker Playback Volume", WM8974_SPKVOL, 0, 63, 0), +SOC_SINGLE_TLV("Speaker Playback Volume", WM8974_SPKVOL, 0, 63, 1, spk_tlv), SOC_SINGLE("Capture Boost(+20dB)", WM8974_ADCBOOST, 8, 1, 0), SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 0), -- cgit v0.10.2 From cb11d39ead79e5bc8ca42de86b9df8dec8b88681 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 30 Jun 2009 19:36:39 +0100 Subject: ASoC: Use symmetric rates for WM8974 The chip has a single LRCLK. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index cb2c412..8c8fc60 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -631,6 +631,7 @@ struct snd_soc_dai wm8974_dai = { .rates = WM8974_RATES, .formats = WM8974_FORMATS,}, .ops = &wm8974_ops, + .symmetric_rates = 1, }; EXPORT_SYMBOL_GPL(wm8974_dai); -- cgit v0.10.2 From 8b83a19367dc3bdfef07634646bbad90f6cba898 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 30 Jun 2009 19:37:02 +0100 Subject: ASoC: WM8974 cosmetic cleanups Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 8c8fc60..6f0455c 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -1,7 +1,7 @@ /* * wm8974.c -- WM8974 ALSA Soc Audio driver * - * Copyright 2006 Wolfson Microelectronics PLC. + * Copyright 2006-2009 Wolfson Microelectronics PLC. * * Author: Liam Girdwood * @@ -357,7 +357,7 @@ static void pll_factors(unsigned int target, unsigned int source) if ((Ndiv < 6) || (Ndiv > 12)) printk(KERN_WARNING - "WM8974 N value %u outwith recommended range!d\n", + "WM8974 N value %u outwith recommended range!\n", Ndiv); pll_div.n = Ndiv; @@ -546,6 +546,7 @@ static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream, adn |= 0x1 << 1; break; case SNDRV_PCM_RATE_44100: + case SNDRV_PCM_RATE_48000: break; } @@ -822,7 +823,7 @@ MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id); static struct i2c_driver wm8974_i2c_driver = { .driver = { - .name = "WM8974 I2C Codec", + .name = "WM8974", .owner = THIS_MODULE, }, .probe = wm8974_i2c_probe, -- cgit v0.10.2 From 8a123ee2a46daa5c1b6f24eb3b004a5156244889 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 30 Jun 2009 21:10:34 +0100 Subject: ASoC: WM8974 DAPM cleanups Also implement AUX mode control. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 6f0455c..c400e5d 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -138,6 +138,11 @@ static const struct soc_enum wm8974_enum[] = { SOC_ENUM_SINGLE(WM8974_ALC3, 8, 2, wm8974_alc), }; +static const char *wm8974_auxmode_text[] = { "Buffer", "Mixer" }; + +static const struct soc_enum wm8974_auxmode = + SOC_ENUM_SINGLE(WM8974_INPUT, 3, 2, wm8974_auxmode_text); + static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); @@ -208,10 +213,12 @@ SOC_SINGLE_TLV("Capture PGA Volume", WM8974_INPPGA, 0, 63, 0, inpga_tlv), SOC_SINGLE("Speaker Playback ZC Switch", WM8974_SPKVOL, 7, 1, 0), SOC_SINGLE("Speaker Playback Switch", WM8974_SPKVOL, 6, 1, 1), -SOC_SINGLE_TLV("Speaker Playback Volume", WM8974_SPKVOL, 0, 63, 1, spk_tlv), +SOC_SINGLE_TLV("Speaker Playback Volume", WM8974_SPKVOL, 0, 63, 0, spk_tlv), + +SOC_ENUM("Aux Mode", wm8974_auxmode), SOC_SINGLE("Capture Boost(+20dB)", WM8974_ADCBOOST, 8, 1, 0), -SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 0), +SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 1), }; /* Speaker Output Mixer */ @@ -225,7 +232,19 @@ SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_SPKMIX, 0, 1, 1), static const struct snd_kcontrol_new wm8974_mono_mixer_controls[] = { SOC_DAPM_SINGLE("Line Bypass Switch", WM8974_MONOMIX, 1, 1, 0), SOC_DAPM_SINGLE("Aux Playback Switch", WM8974_MONOMIX, 2, 1, 0), -SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_MONOMIX, 0, 1, 1), +SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_MONOMIX, 0, 1, 0), +}; + +/* Boost mixer */ +static const struct snd_kcontrol_new wm8974_boost_mixer[] = { +SOC_DAPM_SINGLE("Aux Switch", WM8974_INPPGA, 6, 1, 0), +}; + +/* Input PGA */ +static const struct snd_kcontrol_new wm8974_inpga[] = { +SOC_DAPM_SINGLE("Aux Switch", WM8974_INPUT, 2, 1, 0), +SOC_DAPM_SINGLE("MicN Switch", WM8974_INPUT, 1, 1, 0), +SOC_DAPM_SINGLE("MicP Switch", WM8974_INPUT, 0, 1, 0), }; /* AUX Input boost vol */ @@ -236,22 +255,6 @@ SOC_DAPM_SINGLE("Aux Volume", WM8974_ADCBOOST, 0, 7, 0); static const struct snd_kcontrol_new wm8974_mic_boost_controls = SOC_DAPM_SINGLE("Mic Volume", WM8974_ADCBOOST, 4, 7, 0); -/* Capture boost switch */ -static const struct snd_kcontrol_new wm8974_capture_boost_controls = -SOC_DAPM_SINGLE("Capture Boost Switch", WM8974_INPPGA, 6, 1, 0); - -/* Aux In to PGA */ -static const struct snd_kcontrol_new wm8974_aux_capture_boost_controls = -SOC_DAPM_SINGLE("Aux Capture Boost Switch", WM8974_INPPGA, 2, 1, 0); - -/* Mic P In to PGA */ -static const struct snd_kcontrol_new wm8974_micp_capture_boost_controls = -SOC_DAPM_SINGLE("Mic P Capture Boost Switch", WM8974_INPPGA, 0, 1, 0); - -/* Mic N In to PGA */ -static const struct snd_kcontrol_new wm8974_micn_capture_boost_controls = -SOC_DAPM_SINGLE("Mic N Capture Boost Switch", WM8974_INPPGA, 1, 1, 0); - static const struct snd_soc_dapm_widget wm8974_dapm_widgets[] = { SND_SOC_DAPM_MIXER("Speaker Mixer", WM8974_POWER3, 2, 0, &wm8974_speaker_mixer_controls[0], @@ -260,21 +263,16 @@ SND_SOC_DAPM_MIXER("Mono Mixer", WM8974_POWER3, 3, 0, &wm8974_mono_mixer_controls[0], ARRAY_SIZE(wm8974_mono_mixer_controls)), SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8974_POWER3, 0, 0), -SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8974_POWER3, 0, 0), +SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8974_POWER2, 0, 0), SND_SOC_DAPM_PGA("Aux Input", WM8974_POWER1, 6, 0, NULL, 0), SND_SOC_DAPM_PGA("SpkN Out", WM8974_POWER3, 5, 0, NULL, 0), SND_SOC_DAPM_PGA("SpkP Out", WM8974_POWER3, 6, 0, NULL, 0), SND_SOC_DAPM_PGA("Mono Out", WM8974_POWER3, 7, 0, NULL, 0), -SND_SOC_DAPM_PGA("Mic PGA", WM8974_POWER2, 2, 0, NULL, 0), - -SND_SOC_DAPM_PGA("Aux Boost", SND_SOC_NOPM, 0, 0, - &wm8974_aux_boost_controls, 1), -SND_SOC_DAPM_PGA("Mic Boost", SND_SOC_NOPM, 0, 0, - &wm8974_mic_boost_controls, 1), -SND_SOC_DAPM_SWITCH("Capture Boost", SND_SOC_NOPM, 0, 0, - &wm8974_capture_boost_controls), -SND_SOC_DAPM_MIXER("Boost Mixer", WM8974_POWER2, 4, 0, NULL, 0), +SND_SOC_DAPM_MIXER("Input PGA", WM8974_POWER2, 2, 0, wm8974_inpga, + ARRAY_SIZE(wm8974_inpga)), +SND_SOC_DAPM_MIXER("Boost Mixer", WM8974_POWER2, 4, 0, + wm8974_boost_mixer, ARRAY_SIZE(wm8974_boost_mixer)), SND_SOC_DAPM_MICBIAS("Mic Bias", WM8974_POWER1, 4, 0), @@ -306,17 +304,18 @@ static const struct snd_soc_dapm_route audio_map[] = { {"SPKOUTP", NULL, "SpkP Out"}, /* Boost Mixer */ - {"Boost Mixer", NULL, "ADC"}, - {"Capture Boost Switch", "Aux Capture Boost Switch", "AUX"}, - {"Aux Boost", "Aux Volume", "Boost Mixer"}, - {"Capture Boost", "Capture Switch", "Boost Mixer"}, - {"Mic Boost", "Mic Volume", "Boost Mixer"}, + {"ADC", NULL, "Boost Mixer"}, + {"Boost Mixer", "Aux Switch", "Aux Input"}, + {"Boost Mixer", NULL, "Input PGA"}, + {"Boost Mixer", NULL, "MICP"}, + + /* Input PGA */ + {"Input PGA", "Aux Switch", "Aux Input"}, + {"Input PGA", "MicN Switch", "MICN"}, + {"Input PGA", "MicP Switch", "MICP"}, /* Inputs */ - {"MICP", NULL, "Mic Boost"}, - {"MICN", NULL, "Mic PGA"}, - {"Mic PGA", NULL, "Capture Boost"}, - {"AUX", NULL, "Aux Input"}, + {"Aux Input", NULL, "AUX"}, }; static int wm8974_add_widgets(struct snd_soc_codec *codec) -- cgit v0.10.2 From c5cb5a2d8d7dc872cf1504091ad0e59fe5ff7cb5 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 30 Jun 2009 17:08:14 -0400 Subject: kprobes: Clean up insn_pages by using list instead of hlist Use struct list instead of struct hlist for managing insn_pages, because insn_pages doesn't use hash table. Signed-off-by: Masami Hiramatsu Acked-by: Ananth N Mavinakayanahalli Cc: Ananth N Mavinakayanahalli Cc: Jim Keniston Cc: Ananth N Mavinakayanahalli LKML-Reference: <20090630210814.17851.64651.stgit@localhost.localdomain> Signed-off-by: Ingo Molnar diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 16b5739..6fe9dc6 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -103,7 +103,7 @@ static struct kprobe_blackpoint kprobe_blacklist[] = { #define INSNS_PER_PAGE (PAGE_SIZE/(MAX_INSN_SIZE * sizeof(kprobe_opcode_t))) struct kprobe_insn_page { - struct hlist_node hlist; + struct list_head list; kprobe_opcode_t *insns; /* Page of instruction slots */ char slot_used[INSNS_PER_PAGE]; int nused; @@ -117,7 +117,7 @@ enum kprobe_slot_state { }; static DEFINE_MUTEX(kprobe_insn_mutex); /* Protects kprobe_insn_pages */ -static struct hlist_head kprobe_insn_pages; +static LIST_HEAD(kprobe_insn_pages); static int kprobe_garbage_slots; static int collect_garbage_slots(void); @@ -152,10 +152,9 @@ loop_end: static kprobe_opcode_t __kprobes *__get_insn_slot(void) { struct kprobe_insn_page *kip; - struct hlist_node *pos; retry: - hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) { + list_for_each_entry(kip, &kprobe_insn_pages, list) { if (kip->nused < INSNS_PER_PAGE) { int i; for (i = 0; i < INSNS_PER_PAGE; i++) { @@ -189,8 +188,8 @@ static kprobe_opcode_t __kprobes *__get_insn_slot(void) kfree(kip); return NULL; } - INIT_HLIST_NODE(&kip->hlist); - hlist_add_head(&kip->hlist, &kprobe_insn_pages); + INIT_LIST_HEAD(&kip->list); + list_add(&kip->list, &kprobe_insn_pages); memset(kip->slot_used, SLOT_CLEAN, INSNS_PER_PAGE); kip->slot_used[0] = SLOT_USED; kip->nused = 1; @@ -219,12 +218,8 @@ static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx) * so as not to have to set it up again the * next time somebody inserts a probe. */ - hlist_del(&kip->hlist); - if (hlist_empty(&kprobe_insn_pages)) { - INIT_HLIST_NODE(&kip->hlist); - hlist_add_head(&kip->hlist, - &kprobe_insn_pages); - } else { + if (!list_is_singular(&kprobe_insn_pages)) { + list_del(&kip->list); module_free(NULL, kip->insns); kfree(kip); } @@ -235,14 +230,13 @@ static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx) static int __kprobes collect_garbage_slots(void) { - struct kprobe_insn_page *kip; - struct hlist_node *pos, *next; + struct kprobe_insn_page *kip, *next; /* Ensure no-one is preepmted on the garbages */ if (check_safety()) return -EAGAIN; - hlist_for_each_entry_safe(kip, pos, next, &kprobe_insn_pages, hlist) { + list_for_each_entry_safe(kip, next, &kprobe_insn_pages, list) { int i; if (kip->ngarbage == 0) continue; @@ -260,19 +254,17 @@ static int __kprobes collect_garbage_slots(void) void __kprobes free_insn_slot(kprobe_opcode_t * slot, int dirty) { struct kprobe_insn_page *kip; - struct hlist_node *pos; mutex_lock(&kprobe_insn_mutex); - hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) { + list_for_each_entry(kip, &kprobe_insn_pages, list) { if (kip->insns <= slot && slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) { int i = (slot - kip->insns) / MAX_INSN_SIZE; if (dirty) { kip->slot_used[i] = SLOT_DIRTY; kip->ngarbage++; - } else { + } else collect_one_slot(kip, i); - } break; } } -- cgit v0.10.2 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 diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d3f41db..2582e7a 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 f157d75..2bcc8d4 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 3aa0a0d..bdb3afc 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 3548ae5..52eb0d8 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 53c8fd3..fecac13 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 v0.10.2 From b5025c50b5e817b3e509ad7e569f131b80d7c223 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Jul 2009 18:05:27 +0200 Subject: ALSA: hda - Allow FLOAT PCM format So far, the FLOAT PCM format is used only exclusivley set. But this can be a combination with other formats. This patch changes the parser to allow the FLOAT format in addition to other PCM formats. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 506f46e..263d124 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2690,11 +2690,11 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, bps = 20; } } - else if (streams == AC_SUPFMT_FLOAT32) { - /* should be exclusive */ + if (streams & AC_SUPFMT_FLOAT32) { formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; bps = 32; - } else if (streams == AC_SUPFMT_AC3) { + } + if (streams == AC_SUPFMT_AC3) { /* should be exclusive */ /* temporary hack: we have still no proper support * for the direct AC3 stream... -- cgit v0.10.2 From e5f1424807f4fa7aeddc376575e3b413c71c6fe1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Jul 2009 18:11:44 +0200 Subject: ALSA: hda - Add Cirrus Logic CS420x support Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index b8a77f9..55545e0 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -148,6 +148,19 @@ config SND_HDA_ELD def_bool y depends on SND_HDA_CODEC_INTELHDMI +config SND_HDA_CODEC_CIRRUS + bool "Build Cirrus Logic codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Cirrus Logic codec support in + snd-hda-intel driver, such as CS4206. + + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-cirrus. + This module is automatically loaded at probing. + config SND_HDA_CODEC_CONEXANT bool "Build Conexant HD-audio codec support" default y diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index e3081d4..315a1c4 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -13,6 +13,7 @@ snd-hda-codec-analog-objs := patch_analog.o snd-hda-codec-idt-objs := patch_sigmatel.o snd-hda-codec-si3054-objs := patch_si3054.o snd-hda-codec-atihdmi-objs := patch_atihdmi.o +snd-hda-codec-cirrus-objs := patch_cirrus.o snd-hda-codec-ca0110-objs := patch_ca0110.o snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-via-objs := patch_via.o @@ -41,6 +42,9 @@ endif ifdef CONFIG_SND_HDA_CODEC_ATIHDMI obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o endif +ifdef CONFIG_SND_HDA_CODEC_CIRRUS +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o +endif ifdef CONFIG_SND_HDA_CODEC_CA0110 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o endif diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 263d124..eea91c3 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -44,6 +44,7 @@ struct hda_vendor_id { /* codec vendor labels */ static struct hda_vendor_id hda_vendor_ids[] = { { 0x1002, "ATI" }, + { 0x1013, "Cirrus Logic" }, { 0x1057, "Motorola" }, { 0x1095, "Silicon Image" }, { 0x10de, "Nvidia" }, diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c new file mode 100644 index 0000000..c4dc12e --- /dev/null +++ b/sound/pci/hda/patch_cirrus.c @@ -0,0 +1,937 @@ +/* + * HD audio interface patch for Cirrus Logic CS420x chip + * + * Copyright (c) 2009 Takashi Iwai + * + * This driver 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 driver 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 + */ + +#include +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" + +/* + */ + +struct cs_spec { + struct auto_pin_cfg autocfg; + struct hda_multi_out multiout; + struct snd_kcontrol *vmaster_sw; + struct snd_kcontrol *vmaster_vol; + + hda_nid_t dac_nid[AUTO_CFG_MAX_OUTS]; + hda_nid_t slave_dig_outs[2]; + + unsigned int input_idx[AUTO_PIN_LAST]; + unsigned int capsrc_idx[AUTO_PIN_LAST]; + hda_nid_t adc_nid[AUTO_PIN_LAST]; + unsigned int adc_idx[AUTO_PIN_LAST]; + unsigned int num_inputs; + unsigned int cur_input; + unsigned int automic_idx; + hda_nid_t cur_adc; + unsigned int cur_adc_stream_tag; + unsigned int cur_adc_format; + hda_nid_t dig_in; + + struct hda_bind_ctls *capture_bind[2]; + + struct hda_pcm pcm_rec[2]; /* PCM information */ + + unsigned int hp_detect:1; + unsigned int mic_detect:1; + unsigned int built_up:1; +}; + +#define HP_EVENT 1 +#define MIC_EVENT 2 + +/* + * PCM callbacks + */ +static int cs_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct cs_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + hinfo); +} + +static int cs_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct cs_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int cs_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct cs_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + +/* + * Digital out + */ +static int cs_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct cs_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int cs_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct cs_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +static int cs_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct cs_spec *spec = codec->spec; + return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, + format, substream); +} + +static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct cs_spec *spec = codec->spec; + return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); +} + +/* + * Analog capture + */ +static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct cs_spec *spec = codec->spec; + spec->cur_adc = spec->adc_nid[spec->cur_input]; + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); + return 0; +} + +static int cs_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct cs_spec *spec = codec->spec; + snd_hda_codec_cleanup_stream(codec, spec->cur_adc); + spec->cur_adc = 0; + return 0; +} + +/* + */ +static struct hda_pcm_stream cs_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .ops = { + .open = cs_playback_pcm_open, + .prepare = cs_playback_pcm_prepare, + .cleanup = cs_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream cs_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .ops = { + .prepare = cs_capture_pcm_prepare, + .cleanup = cs_capture_pcm_cleanup + }, +}; + +static struct hda_pcm_stream cs_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .ops = { + .open = cs_dig_playback_pcm_open, + .close = cs_dig_playback_pcm_close, + .prepare = cs_dig_playback_pcm_prepare, + .cleanup = cs_dig_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream cs_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +static int cs_build_pcms(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + + codec->pcm_info = info; + codec->num_pcms = 0; + + info->name = "Cirrus Analog"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cs_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dac_nid[0]; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = + spec->multiout.max_channels; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = cs_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = + spec->adc_nid[spec->cur_input]; + codec->num_pcms++; + + if (!spec->multiout.dig_out_nid && !spec->dig_in) + return 0; + + info++; + info->name = "Cirrus Digital"; + info->pcm_type = spec->autocfg.dig_out_type[0]; + if (!info->pcm_type) + info->pcm_type = HDA_PCM_TYPE_SPDIF; + if (spec->multiout.dig_out_nid) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + cs_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->multiout.dig_out_nid; + } + if (spec->dig_in) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + cs_pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; + } + codec->num_pcms++; + + return 0; +} + +static hda_nid_t get_dac(struct hda_codec *codec, hda_nid_t pin) +{ + hda_nid_t dac; + if (!pin) + return 0; + if (snd_hda_get_connections(codec, pin, &dac, 1) != 1) + return 0; + return dac; +} + +static const char *dir_sfx[2] = { "Playback", "Capture" }; + +static int add_mute(struct hda_codec *codec, const char *name, int index, + unsigned int pval, int dir, struct snd_kcontrol **kctlp) +{ + char tmp[32]; + struct snd_kcontrol_new knew = + HDA_CODEC_MUTE_IDX(tmp, index, 0, 0, HDA_OUTPUT); + knew.private_value = pval; + snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); + *kctlp = snd_ctl_new1(&knew, codec); + return snd_hda_ctl_add(codec, *kctlp); +} + +static int add_volume(struct hda_codec *codec, const char *name, + int index, unsigned int pval, int dir, + struct snd_kcontrol **kctlp) +{ + char tmp[32]; + struct snd_kcontrol_new knew = + HDA_CODEC_VOLUME_IDX(tmp, index, 0, 0, HDA_OUTPUT); + knew.private_value = pval; + snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); + *kctlp = snd_ctl_new1(&knew, codec); + return snd_hda_ctl_add(codec, *kctlp); +} + +static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) +{ + unsigned int caps; + + /* set the upper-limit for mixer amp to 0dB */ + caps = query_amp_caps(codec, dac, HDA_OUTPUT); + caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT); + caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f) + << AC_AMPCAP_NUM_STEPS_SHIFT; + snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps); +} + +static int add_vmaster(struct hda_codec *codec, hda_nid_t dac) +{ + struct cs_spec *spec = codec->spec; + unsigned int tlv[4]; + int err; + + spec->vmaster_sw = + snd_ctl_make_virtual_master("Master Playback Switch", NULL); + err = snd_hda_ctl_add(codec, spec->vmaster_sw); + if (err < 0) + return err; + + snd_hda_set_vmaster_tlv(codec, dac, HDA_OUTPUT, tlv); + spec->vmaster_vol = + snd_ctl_make_virtual_master("Master Playback Volume", tlv); + err = snd_hda_ctl_add(codec, spec->vmaster_vol); + if (err < 0) + return err; + return 0; +} + +static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx, + int num_ctls, int type) +{ + struct cs_spec *spec = codec->spec; + const char *name; + int err, index; + struct snd_kcontrol *kctl; + static char *speakers[] = { + "Front Speaker", "Surround Speaker", "Bass Speaker" + }; + static char *line_outs[] = { + "Front Line-Out", "Surround Line-Out", "Bass Line-Out" + }; + + fix_volume_caps(codec, dac); + if (!spec->vmaster_sw) { + err = add_vmaster(codec, dac); + if (err < 0) + return err; + } + + index = 0; + switch (type) { + case AUTO_PIN_HP_OUT: + name = "Headphone"; + index = idx; + break; + case AUTO_PIN_SPEAKER_OUT: + if (num_ctls > 1) + name = speakers[idx]; + else + name = "Speaker"; + break; + default: + if (num_ctls > 1) + name = line_outs[idx]; + else + name = "Line-Out"; + break; + } + + err = add_mute(codec, name, index, + HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); + if (err < 0) + return err; + err = snd_ctl_add_slave(spec->vmaster_sw, kctl); + if (err < 0) + return err; + + err = add_volume(codec, name, index, + HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); + if (err < 0) + return err; + err = snd_ctl_add_slave(spec->vmaster_vol, kctl); + if (err < 0) + return err; + + return 0; +} + +static int build_output(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, err, extra_nids; + hda_nid_t dac; + + for (i = 0; i < cfg->line_outs; i++) { + dac = get_dac(codec, cfg->line_out_pins[i]); + if (!dac) + break; + spec->dac_nid[i] = dac; + err = add_output(codec, dac, i, cfg->line_outs, + cfg->line_out_type); + if (err < 0) + return err; + } + spec->multiout.num_dacs = i; + spec->multiout.dac_nids = spec->dac_nid; + spec->multiout.max_channels = i * 2; + + /* add HP and speakers */ + extra_nids = 0; + for (i = 0; i < cfg->hp_outs; i++) { + dac = get_dac(codec, cfg->hp_pins[i]); + if (!dac) + break; + if (!i) + spec->multiout.hp_nid = dac; + else + spec->multiout.extra_out_nid[extra_nids++] = dac; + err = add_output(codec, dac, i, cfg->hp_outs, AUTO_PIN_HP_OUT); + if (err < 0) + return err; + } + for (i = 0; i < cfg->speaker_outs; i++) { + dac = get_dac(codec, cfg->speaker_pins[i]); + if (!dac) + break; + spec->multiout.extra_out_nid[extra_nids++] = dac; + err = add_output(codec, dac, i, cfg->speaker_outs, + AUTO_PIN_SPEAKER_OUT); + if (err < 0) + return err; + } + + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { + cfg->speaker_outs = cfg->line_outs; + memcpy(cfg->speaker_pins, cfg->line_out_pins, + sizeof(cfg->speaker_pins)); + cfg->line_outs = 0; + } + + return 0; +} + +/* + */ + +static struct snd_kcontrol_new cs_capture_ctls[] = { + HDA_BIND_SW("Capture Switch", 0), + HDA_BIND_VOL("Capture Volume", 0), +}; + +static int change_cur_input(struct hda_codec *codec, unsigned int idx) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (spec->cur_input == idx) + return 0; + if (spec->cur_adc && spec->cur_adc != spec->adc_nid[idx]) { + /* stream is running, let's swap the current ADC */ + snd_hda_codec_cleanup_stream(codec, spec->cur_adc); + spec->cur_adc = spec->adc_nid[idx]; + snd_hda_codec_setup_stream(codec, spec->cur_adc, + spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); + } + snd_hda_codec_write(codec, spec->cur_adc, 0, + AC_VERB_SET_CONNECT_SEL, + spec->adc_idx[idx]); + spec->cur_input = idx; + return 1; +} + +static int cs_capture_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cs_spec *spec = codec->spec; + unsigned int idx; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = spec->num_inputs; + if (uinfo->value.enumerated.item >= spec->num_inputs) + uinfo->value.enumerated.item = spec->num_inputs - 1; + idx = spec->input_idx[uinfo->value.enumerated.item]; + strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]); + return 0; +} + +static int cs_capture_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cs_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = spec->capsrc_idx[spec->cur_input]; + return 0; +} + +static int cs_capture_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cs_spec *spec = codec->spec; + unsigned int idx = ucontrol->value.enumerated.item[0]; + + if (idx >= spec->num_inputs) + return -EINVAL; + idx = spec->input_idx[idx]; + return change_cur_input(codec, idx); +} + +static struct snd_kcontrol_new cs_capture_source = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = cs_capture_source_info, + .get = cs_capture_source_get, + .put = cs_capture_source_put, +}; + + +static int is_ext_mic(struct hda_codec *codec, unsigned int idx) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t pin = cfg->input_pins[idx]; + unsigned int val = snd_hda_query_pin_caps(codec, pin); + if (!(val & AC_PINCAP_PRES_DETECT)) + return 0; + val = snd_hda_codec_get_pincfg(codec, pin); + return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX); +} + +static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, + unsigned int *idxp) +{ + int i; + hda_nid_t nid; + + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { + hda_nid_t pins[2]; + unsigned int type; + int j, nums; + type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) + >> AC_WCAP_TYPE_SHIFT; + if (type != AC_WID_AUD_IN) + continue; + nums = snd_hda_get_connections(codec, nid, pins, + ARRAY_SIZE(pins)); + if (nums <= 0) + continue; + for (j = 0; j < nums; j++) { + if (pins[j] == pin) { + *idxp = j; + return nid; + } + } + } + return 0; +} + +static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, + struct hda_ctl_ops *ops) +{ + struct cs_spec *spec = codec->spec; + struct hda_bind_ctls *bind; + int i, n; + + bind = kzalloc(sizeof(*bind) + sizeof(long) * (spec->num_inputs + 1), + GFP_KERNEL); + if (!bind) + return NULL; + bind->ops = ops; + n = 0; + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (!spec->adc_nid[i]) + continue; + bind->values[n++] = + HDA_COMPOSE_AMP_VAL(spec->adc_nid[i], 3, + spec->adc_idx[i], HDA_INPUT); + } + return bind; +} + +static int build_input(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, n, err; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + hda_nid_t pin = cfg->input_pins[i]; + struct snd_kcontrol *kctl; + if (!pin) + continue; + spec->input_idx[spec->num_inputs] = i; + spec->capsrc_idx[i] = spec->num_inputs++; + spec->cur_input = i; + spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); + } + if (!spec->num_inputs) + return 0; + + /* check whether the automatic mic switch is available */ + if (spec->num_inputs == 2 && + spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) { + if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) { + if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { + spec->mic_detect = 1; + spec->automic_idx = AUTO_PIN_FRONT_MIC; + } + } else { + if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { + spec->mic_detect = 1; + spec->automic_idx = AUTO_PIN_MIC; + } + } + } + + /* make bind-capture */ + spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw); + spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); + for (i = 0; i < 2; i++) { + struct snd_kcontrol *kctl; + if (!spec->capture_bind[i]) + return -ENOMEM; + kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = (long)spec->capture_bind[i]; + err = snd_hda_ctl_add(codec, kctl); + if (err < 0) + return err; + } + + if (spec->num_inputs > 1 && !spec->mic_detect) { + err = snd_hda_ctl_add(codec, + snd_ctl_new1(&cs_capture_source, codec)); + if (err < 0) + return err; + } + + return 0; +} + +static int build_digital_output(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid; + int err; + + if (!cfg->dig_outs) + return 0; + if (snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) < 1) + return 0; + spec->multiout.dig_out_nid = nid; + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + if (err < 0) + return err; + err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); + if (err < 0) + return err; + spec->multiout.share_spdif = 1; + if (cfg->dig_outs > 1 && + snd_hda_get_connections(codec, cfg->dig_out_pins[1], &nid, 1) > 0) { + spec->slave_dig_outs[0] = nid; + codec->slave_dig_outs = spec->slave_dig_outs; + } + return 0; +} + +static int build_digital_input(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int idx; + + if (!cfg->dig_in_pin) + return 0; + spec->dig_in = get_adc(codec, cfg->dig_in_pin, &idx); + if (!spec->dig_in) + return 0; + return snd_hda_create_spdif_in_ctls(codec, spec->dig_in); +} + +static void cs_automute(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int caps, present, hp_present; + hda_nid_t nid; + int i; + + hp_present = 0; + for (i = 0; i < cfg->hp_outs; i++) { + nid = cfg->hp_pins[i]; + caps = snd_hda_query_pin_caps(codec, nid); + if (!(caps & AC_PINCAP_PRES_DETECT)) + continue; + if (caps & AC_PINCAP_TRIG_REQ) + snd_hda_codec_read(codec, nid, 0, + AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_SENSE, 0); + hp_present |= (present & AC_PINSENSE_PRESENCE) != 0; + if (hp_present) + break; + } + for (i = 0; i < cfg->speaker_outs; i++) { + nid = cfg->speaker_pins[i]; + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + hp_present ? 0 : PIN_OUT); + } +} + +static void cs_automic(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid; + unsigned int caps, present; + + nid = cfg->input_pins[spec->automic_idx]; + caps = snd_hda_query_pin_caps(codec, nid); + if (caps & AC_PINCAP_TRIG_REQ) + snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_SENSE, 0); + if (present & AC_PINSENSE_PRESENCE) + change_cur_input(codec, spec->automic_idx); + else { + unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ? + AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC; + change_cur_input(codec, imic); + } +} + +/* + */ + +static void init_output(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + /* mute first */ + for (i = 0; i < spec->multiout.num_dacs; i++) + snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + if (spec->multiout.hp_nid) + snd_hda_codec_write(codec, spec->multiout.hp_nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) { + if (!spec->multiout.extra_out_nid[i]) + break; + snd_hda_codec_write(codec, spec->multiout.extra_out_nid[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + } + + /* set appropriate pin controls */ + for (i = 0; i < cfg->line_outs; i++) + snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + for (i = 0; i < cfg->hp_outs; i++) { + hda_nid_t nid = cfg->hp_pins[i]; + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); + if (!cfg->speaker_outs) + continue; + if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | HP_EVENT); + spec->hp_detect = 1; + } + } + for (i = 0; i < cfg->speaker_outs; i++) + snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + if (spec->hp_detect) + cs_automute(codec); +} + +static void init_input(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + unsigned int ctl; + hda_nid_t pin = cfg->input_pins[i]; + if (!pin || !spec->adc_nid[i]) + continue; + /* set appropriate pin control and mute first */ + ctl = PIN_IN; + if (i <= AUTO_PIN_FRONT_MIC) { + unsigned int caps = snd_hda_query_pin_caps(codec, pin); + caps >>= AC_PINCAP_VREF_SHIFT; + if (caps & AC_PINCAP_VREF_80) + ctl = PIN_VREF80; + } + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, ctl); + snd_hda_codec_write(codec, spec->adc_nid[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(spec->adc_idx[i])); + if (spec->mic_detect && spec->automic_idx == i) + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | MIC_EVENT); + } + if (spec->mic_detect) + cs_automic(codec); +} + +static int cs_init(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + + if (!spec->built_up) + return 0; + init_output(codec); + init_input(codec); + return 0; +} + +static int cs_build_controls(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + int err; + + err = build_output(codec); + if (err < 0) + return err; + err = build_input(codec); + if (err < 0) + return err; + err = build_digital_output(codec); + if (err < 0) + return err; + err = build_digital_input(codec); + if (err < 0) + return err; + spec->built_up = 1; + return cs_init(codec); +} + +static void cs_free(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + kfree(spec->capture_bind[0]); + kfree(spec->capture_bind[1]); + kfree(codec->spec); +} + +static void cs_unsol_event(struct hda_codec *codec, unsigned int res) +{ + switch ((res >> 26) & 0x7f) { + case HP_EVENT: + cs_automute(codec); + break; + case MIC_EVENT: + cs_automic(codec); + break; + } +} + +static struct hda_codec_ops cs_patch_ops = { + .build_controls = cs_build_controls, + .build_pcms = cs_build_pcms, + .init = cs_init, + .free = cs_free, + .unsol_event = cs_unsol_event, +}; + +static int cs_parse_auto_config(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + return 0; +} + + +static int patch_cs420x(struct hda_codec *codec) +{ + struct cs_spec *spec; + int err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + codec->spec = spec; + + err = cs_parse_auto_config(codec); + if (err < 0) + goto error; + + codec->patch_ops = cs_patch_ops; + + return 0; + + error: + kfree(codec->spec); + codec->spec = NULL; + return err; +} + + +/* + * patch entries + */ +static struct hda_codec_preset snd_hda_preset_cirrus[] = { + { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, + { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, + {} /* terminator */ +}; + +MODULE_ALIAS("snd-hda-codec-id:10134206"); +MODULE_ALIAS("snd-hda-codec-id:10134207"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); + +static struct hda_codec_preset_list cirrus_list = { + .preset = snd_hda_preset_cirrus, + .owner = THIS_MODULE, +}; + +static int __init patch_cirrus_init(void) +{ + return snd_hda_add_codec_preset(&cirrus_list); +} + +static void __exit patch_cirrus_exit(void) +{ + snd_hda_delete_codec_preset(&cirrus_list); +} + +module_init(patch_cirrus_init) +module_exit(patch_cirrus_exit) -- cgit v0.10.2 From 1dcf98ff8e2a4571a2accb852686023b47ca629a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 1 Jul 2009 18:28:54 +0100 Subject: ASoC: Add WM8523 CODEC driver The WM8523 is a high performance stereo DAC with integral charge pump providing 2Vrms line driver outputs using a single 3.3V power supply rail. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 021dbdf..68ea5b6 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -30,6 +30,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8350 if MFD_WM8350 select SND_SOC_WM8400 if MFD_WM8400 select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8523 if I2C select SND_SOC_WM8580 if I2C select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI @@ -130,6 +131,9 @@ config SND_SOC_WM8400 config SND_SOC_WM8510 tristate +config SND_SOC_WM8523 + tristate + config SND_SOC_WM8580 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index e520c2b..8ce28a3 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -18,6 +18,7 @@ snd-soc-uda1380-objs := uda1380.o snd-soc-wm8350-objs := wm8350.o snd-soc-wm8400-objs := wm8400.o snd-soc-wm8510-objs := wm8510.o +snd-soc-wm8523-objs := wm8523.o snd-soc-wm8580-objs := wm8580.o snd-soc-wm8728-objs := wm8728.o snd-soc-wm8731-objs := wm8731.o @@ -56,6 +57,7 @@ obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o +obj-$(CONFIG_SND_SOC_WM8523) += snd-soc-wm8523.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c new file mode 100644 index 0000000..3b499ae --- /dev/null +++ b/sound/soc/codecs/wm8523.c @@ -0,0 +1,755 @@ +/* + * wm8523.c -- WM8523 ALSA SoC Audio driver + * + * Copyright 2009 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8523.h" + +static struct snd_soc_codec *wm8523_codec; +struct snd_soc_codec_device soc_codec_dev_wm8523; + +#define WM8523_NUM_SUPPLIES 2 +static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = { + "AVDD", + "LINEVDD", +}; + +#define WM8523_NUM_RATES 7 + +/* codec private data */ +struct wm8523_priv { + struct snd_soc_codec codec; + u16 reg_cache[WM8523_REGISTER_COUNT]; + struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES]; + unsigned int sysclk; + unsigned int rate_constraint_list[WM8523_NUM_RATES]; + struct snd_pcm_hw_constraint_list rate_constraint; +}; + +static const u16 wm8523_reg[WM8523_REGISTER_COUNT] = { + 0x8523, /* R0 - DEVICE_ID */ + 0x0001, /* R1 - REVISION */ + 0x0000, /* R2 - PSCTRL1 */ + 0x1812, /* R3 - AIF_CTRL1 */ + 0x0000, /* R4 - AIF_CTRL2 */ + 0x0001, /* R5 - DAC_CTRL3 */ + 0x0190, /* R6 - DAC_GAINL */ + 0x0190, /* R7 - DAC_GAINR */ + 0x0000, /* R8 - ZERO_DETECT */ +}; + +static int wm8523_volatile(unsigned int reg) +{ + switch (reg) { + case WM8523_DEVICE_ID: + case WM8523_REVISION: + return 1; + default: + return 0; + } +} + +static int wm8523_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct wm8523_priv *wm8523 = codec->private_data; + u8 data[3]; + + BUG_ON(reg > WM8523_MAX_REGISTER); + + data[0] = reg; + data[1] = (value >> 8) & 0x00ff; + data[2] = value & 0x00ff; + + if (!wm8523_volatile(reg)) + wm8523->reg_cache[reg] = value; + if (codec->hw_write(codec->control_data, data, 3) == 3) + return 0; + else + return -EIO; +} + +static int wm8523_reset(struct snd_soc_codec *codec) +{ + return wm8523_write(codec, WM8523_DEVICE_ID, 0); +} + +static unsigned int wm8523_read_hw(struct snd_soc_codec *codec, u8 reg) +{ + struct i2c_msg xfer[2]; + u16 data; + int ret; + struct i2c_client *i2c = codec->control_data; + + /* Write register */ + xfer[0].addr = i2c->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = ® + + /* Read data */ + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (u8 *)&data; + + ret = i2c_transfer(i2c->adapter, xfer, 2); + if (ret != 2) { + dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret); + return 0; + } + + return (data >> 8) | ((data & 0xff) << 8); +} + + +static unsigned int wm8523_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *reg_cache = codec->reg_cache; + + BUG_ON(reg > WM8523_MAX_REGISTER); + + if (wm8523_volatile(reg)) + return wm8523_read_hw(codec, reg); + else + return reg_cache[reg]; +} + +static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0); + +static const char *wm8523_zd_count_text[] = { + "1024", + "2048", +}; + +static const struct soc_enum wm8523_zc_count = + SOC_ENUM_SINGLE(WM8523_ZERO_DETECT, 0, 2, wm8523_zd_count_text); + +static const struct snd_kcontrol_new wm8523_snd_controls[] = { +SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR, + 0, 448, 0, dac_tlv), +SOC_SINGLE("ZC Switch", WM8523_DAC_CTRL3, 4, 1, 0), +SOC_SINGLE("Playback Deemphasis Switch", WM8523_AIF_CTRL1, 8, 1, 0), +SOC_DOUBLE("Playback Switch", WM8523_DAC_CTRL3, 2, 3, 1, 1), +SOC_SINGLE("Volume Ramp Up Switch", WM8523_DAC_CTRL3, 1, 1, 0), +SOC_SINGLE("Volume Ramp Down Switch", WM8523_DAC_CTRL3, 0, 1, 0), +SOC_ENUM("Zero Detect Count", wm8523_zc_count), +}; + +static const struct snd_soc_dapm_widget wm8523_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_OUTPUT("LINEVOUTL"), +SND_SOC_DAPM_OUTPUT("LINEVOUTR"), +}; + +static const struct snd_soc_dapm_route intercon[] = { + { "LINEVOUTL", NULL, "DAC" }, + { "LINEVOUTR", NULL, "DAC" }, +}; + +static int wm8523_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, wm8523_dapm_widgets, + ARRAY_SIZE(wm8523_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +static struct { + int value; + int ratio; +} lrclk_ratios[WM8523_NUM_RATES] = { + { 1, 128 }, + { 2, 192 }, + { 3, 256 }, + { 4, 384 }, + { 5, 512 }, + { 6, 768 }, + { 7, 1152 }, +}; + +static int wm8523_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8523_priv *wm8523 = codec->private_data; + + /* The set of sample rates that can be supported depends on the + * MCLK supplied to the CODEC - enforce this. + */ + if (!wm8523->sysclk) { + dev_err(codec->dev, + "No MCLK configured, call set_sysclk() on init\n"); + return -EINVAL; + } + + return 0; + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &wm8523->rate_constraint); + + return 0; +} + +static int wm8523_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + struct wm8523_priv *wm8523 = codec->private_data; + int i; + u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1); + u16 aifctrl2 = wm8523_read(codec, WM8523_AIF_CTRL2); + + /* Find a supported LRCLK ratio */ + for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { + if (wm8523->sysclk / params_rate(params) == + lrclk_ratios[i].ratio) + break; + } + + /* Should never happen, should be handled by constraints */ + if (i == ARRAY_SIZE(lrclk_ratios)) { + dev_err(codec->dev, "MCLK/fs ratio %d unsupported\n", + wm8523->sysclk / params_rate(params)); + return -EINVAL; + } + + aifctrl2 &= ~WM8523_SR_MASK; + aifctrl2 |= lrclk_ratios[i].value; + + aifctrl1 &= ~WM8523_WL_MASK; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + aifctrl1 |= 0x8; + break; + case SNDRV_PCM_FORMAT_S24_LE: + aifctrl1 |= 0x10; + break; + case SNDRV_PCM_FORMAT_S32_LE: + aifctrl1 |= 0x18; + break; + } + + wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1); + wm8523_write(codec, WM8523_AIF_CTRL2, aifctrl2); + + return 0; +} + +static int wm8523_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8523_priv *wm8523 = codec->private_data; + unsigned int val; + int i; + + wm8523->sysclk = freq; + + wm8523->rate_constraint.count = 0; + for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { + val = freq / lrclk_ratios[i].ratio; + /* Check that it's a standard rate since core can't + * cope with others and having the odd rates confuses + * constraint matching. + */ + switch (val) { + case 8000: + case 11025: + case 16000: + case 22050: + case 32000: + case 44100: + case 48000: + case 64000: + case 88200: + case 96000: + case 176400: + case 192000: + dev_dbg(codec->dev, "Supported sample rate: %dHz\n", + val); + wm8523->rate_constraint_list[i] = val; + wm8523->rate_constraint.count++; + break; + default: + dev_dbg(codec->dev, "Skipping sample rate: %dHz\n", + val); + } + } + + /* Need at least one supported rate... */ + if (wm8523->rate_constraint.count == 0) + return -EINVAL; + + return 0; +} + + +static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1); + + aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK | + WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + aifctrl1 |= WM8523_AIF_MSTR; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + aifctrl1 |= 0x0002; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + aifctrl1 |= 0x0001; + break; + case SND_SOC_DAIFMT_DSP_A: + aifctrl1 |= 0x0003; + break; + case SND_SOC_DAIFMT_DSP_B: + aifctrl1 |= 0x0023; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + aifctrl1 |= WM8523_BCLK_INV | WM8523_LRCLK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + aifctrl1 |= WM8523_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + aifctrl1 |= WM8523_LRCLK_INV; + break; + default: + return -EINVAL; + } + + wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1); + + return 0; +} + +static int wm8523_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct wm8523_priv *wm8523 = codec->private_data; + int ret, i; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* Full power on */ + snd_soc_update_bits(codec, WM8523_PSCTRL1, + WM8523_SYS_ENA_MASK, 3); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), + wm8523->supplies); + if (ret != 0) { + dev_err(codec->dev, + "Failed to enable supplies: %d\n", + ret); + return ret; + } + + /* Initial power up */ + snd_soc_update_bits(codec, WM8523_PSCTRL1, + WM8523_SYS_ENA_MASK, 1); + + /* Sync back default/cached values */ + for (i = WM8523_AIF_CTRL1; + i < WM8523_MAX_REGISTER; i++) + wm8523_write(codec, i, wm8523->reg_cache[i]); + + + msleep(100); + } + + /* Power up to mute */ + snd_soc_update_bits(codec, WM8523_PSCTRL1, + WM8523_SYS_ENA_MASK, 2); + + break; + + case SND_SOC_BIAS_OFF: + /* The chip runs through the power down sequence for us. */ + snd_soc_update_bits(codec, WM8523_PSCTRL1, + WM8523_SYS_ENA_MASK, 0); + msleep(100); + + regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), + wm8523->supplies); + break; + } + codec->bias_level = level; + return 0; +} + +#define WM8523_RATES SNDRV_PCM_RATE_8000_192000 + +#define WM8523_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops wm8523_dai_ops = { + .startup = wm8523_startup, + .hw_params = wm8523_hw_params, + .set_sysclk = wm8523_set_dai_sysclk, + .set_fmt = wm8523_set_dai_fmt, +}; + +struct snd_soc_dai wm8523_dai = { + .name = "WM8523", + .playback = { + .stream_name = "Playback", + .channels_min = 2, /* Mono modes not yet supported */ + .channels_max = 2, + .rates = WM8523_RATES, + .formats = WM8523_FORMATS, + }, + .ops = &wm8523_dai_ops, +}; +EXPORT_SYMBOL_GPL(wm8523_dai); + +#ifdef CONFIG_PM +static int wm8523_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int wm8523_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} +#else +#define wm8523_suspend NULL +#define wm8523_resume NULL +#endif + +static int wm8523_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (wm8523_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = wm8523_codec; + codec = wm8523_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, wm8523_snd_controls, + ARRAY_SIZE(wm8523_snd_controls)); + wm8523_add_widgets(codec); + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +static int wm8523_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8523 = { + .probe = wm8523_probe, + .remove = wm8523_remove, + .suspend = wm8523_suspend, + .resume = wm8523_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523); + +static int wm8523_register(struct wm8523_priv *wm8523) +{ + int ret; + struct snd_soc_codec *codec = &wm8523->codec; + int i; + + if (wm8523_codec) { + dev_err(codec->dev, "Another WM8523 is registered\n"); + return -EINVAL; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = wm8523; + codec->name = "WM8523"; + codec->owner = THIS_MODULE; + codec->read = wm8523_read; + codec->write = wm8523_write; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8523_set_bias_level; + codec->dai = &wm8523_dai; + codec->num_dai = 1; + codec->reg_cache_size = WM8523_REGISTER_COUNT; + codec->reg_cache = &wm8523->reg_cache; + + wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0]; + wm8523->rate_constraint.count = + ARRAY_SIZE(wm8523->rate_constraint_list); + + memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg)); + + for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++) + wm8523->supplies[i].supply = wm8523_supply_names[i]; + + ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8523->supplies), + wm8523->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + goto err; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), + wm8523->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + goto err_get; + } + + ret = wm8523_read(codec, WM8523_DEVICE_ID); + if (ret < 0) { + dev_err(codec->dev, "Failed to read ID register\n"); + goto err_enable; + } + if (ret != wm8523_reg[WM8523_DEVICE_ID]) { + dev_err(codec->dev, "Device is not a WM8523, ID is %x\n", ret); + ret = -EINVAL; + goto err_enable; + } + + ret = wm8523_read(codec, WM8523_REVISION); + if (ret < 0) { + dev_err(codec->dev, "Failed to read revision register\n"); + goto err_enable; + } + dev_info(codec->dev, "revision %c\n", + (ret & WM8523_CHIP_REV_MASK) + 'A'); + + ret = wm8523_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + goto err_enable; + } + + wm8523_dai.dev = codec->dev; + + /* Change some default settings - latch VU and enable ZC */ + wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU; + wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC; + + wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* Bias level configuration will have done an extra enable */ + regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); + + wm8523_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; + } + + ret = snd_soc_register_dai(&wm8523_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } + + return 0; + +err_enable: + regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); +err_get: + regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); +err: + kfree(wm8523); + return ret; +} + +static void wm8523_unregister(struct wm8523_priv *wm8523) +{ + wm8523_set_bias_level(&wm8523->codec, SND_SOC_BIAS_OFF); + regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); + snd_soc_unregister_dai(&wm8523_dai); + snd_soc_unregister_codec(&wm8523->codec); + kfree(wm8523); + wm8523_codec = NULL; +} + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static __devinit int wm8523_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8523_priv *wm8523; + struct snd_soc_codec *codec; + + wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL); + if (wm8523 == NULL) + return -ENOMEM; + + codec = &wm8523->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + + i2c_set_clientdata(i2c, wm8523); + codec->control_data = i2c; + + codec->dev = &i2c->dev; + + return wm8523_register(wm8523); +} + +static __devexit int wm8523_i2c_remove(struct i2c_client *client) +{ + struct wm8523_priv *wm8523 = i2c_get_clientdata(client); + wm8523_unregister(wm8523); + return 0; +} + +#ifdef CONFIG_PM +static int wm8523_i2c_suspend(struct i2c_client *i2c, pm_message_t msg) +{ + return snd_soc_suspend_device(&i2c->dev); +} + +static int wm8523_i2c_resume(struct i2c_client *i2c) +{ + return snd_soc_resume_device(&i2c->dev); +} +#else +#define wm8523_i2c_suspend NULL +#define wm8523_i2c_resume NULL +#endif + +static const struct i2c_device_id wm8523_i2c_id[] = { + { "wm8523", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id); + +static struct i2c_driver wm8523_i2c_driver = { + .driver = { + .name = "WM8523", + .owner = THIS_MODULE, + }, + .probe = wm8523_i2c_probe, + .remove = __devexit_p(wm8523_i2c_remove), + .suspend = wm8523_i2c_suspend, + .resume = wm8523_i2c_resume, + .id_table = wm8523_i2c_id, +}; +#endif + +static int __init wm8523_modinit(void) +{ + int ret; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&wm8523_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register WM8523 I2C driver: %d\n", + ret); + } +#endif + return 0; +} +module_init(wm8523_modinit); + +static void __exit wm8523_exit(void) +{ +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&wm8523_i2c_driver); +#endif +} +module_exit(wm8523_exit); + +MODULE_DESCRIPTION("ASoC WM8523 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8523.h b/sound/soc/codecs/wm8523.h new file mode 100644 index 0000000..1aa9ce3 --- /dev/null +++ b/sound/soc/codecs/wm8523.h @@ -0,0 +1,160 @@ +/* + * wm8523.h -- WM8423 ASoC driver + * + * Copyright 2009 Wolfson Microelectronics, plc + * + * Author: Mark Brown + * + * Based on wm8753.h + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef _WM8523_H +#define _WM8523_H + +/* + * Register values. + */ +#define WM8523_DEVICE_ID 0x00 +#define WM8523_REVISION 0x01 +#define WM8523_PSCTRL1 0x02 +#define WM8523_AIF_CTRL1 0x03 +#define WM8523_AIF_CTRL2 0x04 +#define WM8523_DAC_CTRL3 0x05 +#define WM8523_DAC_GAINL 0x06 +#define WM8523_DAC_GAINR 0x07 +#define WM8523_ZERO_DETECT 0x08 + +#define WM8523_REGISTER_COUNT 9 +#define WM8523_MAX_REGISTER 0x08 + +/* + * Field Definitions. + */ + +/* + * R0 (0x00) - DEVICE_ID + */ +#define WM8523_CHIP_ID_MASK 0xFFFF /* CHIP_ID - [15:0] */ +#define WM8523_CHIP_ID_SHIFT 0 /* CHIP_ID - [15:0] */ +#define WM8523_CHIP_ID_WIDTH 16 /* CHIP_ID - [15:0] */ + +/* + * R1 (0x01) - REVISION + */ +#define WM8523_CHIP_REV_MASK 0x0007 /* CHIP_REV - [2:0] */ +#define WM8523_CHIP_REV_SHIFT 0 /* CHIP_REV - [2:0] */ +#define WM8523_CHIP_REV_WIDTH 3 /* CHIP_REV - [2:0] */ + +/* + * R2 (0x02) - PSCTRL1 + */ +#define WM8523_SYS_ENA_MASK 0x0003 /* SYS_ENA - [1:0] */ +#define WM8523_SYS_ENA_SHIFT 0 /* SYS_ENA - [1:0] */ +#define WM8523_SYS_ENA_WIDTH 2 /* SYS_ENA - [1:0] */ + +/* + * R3 (0x03) - AIF_CTRL1 + */ +#define WM8523_TDM_MODE_MASK 0x1800 /* TDM_MODE - [12:11] */ +#define WM8523_TDM_MODE_SHIFT 11 /* TDM_MODE - [12:11] */ +#define WM8523_TDM_MODE_WIDTH 2 /* TDM_MODE - [12:11] */ +#define WM8523_TDM_SLOT_MASK 0x0600 /* TDM_SLOT - [10:9] */ +#define WM8523_TDM_SLOT_SHIFT 9 /* TDM_SLOT - [10:9] */ +#define WM8523_TDM_SLOT_WIDTH 2 /* TDM_SLOT - [10:9] */ +#define WM8523_DEEMPH 0x0100 /* DEEMPH */ +#define WM8523_DEEMPH_MASK 0x0100 /* DEEMPH */ +#define WM8523_DEEMPH_SHIFT 8 /* DEEMPH */ +#define WM8523_DEEMPH_WIDTH 1 /* DEEMPH */ +#define WM8523_AIF_MSTR 0x0080 /* AIF_MSTR */ +#define WM8523_AIF_MSTR_MASK 0x0080 /* AIF_MSTR */ +#define WM8523_AIF_MSTR_SHIFT 7 /* AIF_MSTR */ +#define WM8523_AIF_MSTR_WIDTH 1 /* AIF_MSTR */ +#define WM8523_LRCLK_INV 0x0040 /* LRCLK_INV */ +#define WM8523_LRCLK_INV_MASK 0x0040 /* LRCLK_INV */ +#define WM8523_LRCLK_INV_SHIFT 6 /* LRCLK_INV */ +#define WM8523_LRCLK_INV_WIDTH 1 /* LRCLK_INV */ +#define WM8523_BCLK_INV 0x0020 /* BCLK_INV */ +#define WM8523_BCLK_INV_MASK 0x0020 /* BCLK_INV */ +#define WM8523_BCLK_INV_SHIFT 5 /* BCLK_INV */ +#define WM8523_BCLK_INV_WIDTH 1 /* BCLK_INV */ +#define WM8523_WL_MASK 0x0018 /* WL - [4:3] */ +#define WM8523_WL_SHIFT 3 /* WL - [4:3] */ +#define WM8523_WL_WIDTH 2 /* WL - [4:3] */ +#define WM8523_FMT_MASK 0x0007 /* FMT - [2:0] */ +#define WM8523_FMT_SHIFT 0 /* FMT - [2:0] */ +#define WM8523_FMT_WIDTH 3 /* FMT - [2:0] */ + +/* + * R4 (0x04) - AIF_CTRL2 + */ +#define WM8523_DAC_OP_MUX_MASK 0x00C0 /* DAC_OP_MUX - [7:6] */ +#define WM8523_DAC_OP_MUX_SHIFT 6 /* DAC_OP_MUX - [7:6] */ +#define WM8523_DAC_OP_MUX_WIDTH 2 /* DAC_OP_MUX - [7:6] */ +#define WM8523_BCLKDIV_MASK 0x0038 /* BCLKDIV - [5:3] */ +#define WM8523_BCLKDIV_SHIFT 3 /* BCLKDIV - [5:3] */ +#define WM8523_BCLKDIV_WIDTH 3 /* BCLKDIV - [5:3] */ +#define WM8523_SR_MASK 0x0007 /* SR - [2:0] */ +#define WM8523_SR_SHIFT 0 /* SR - [2:0] */ +#define WM8523_SR_WIDTH 3 /* SR - [2:0] */ + +/* + * R5 (0x05) - DAC_CTRL3 + */ +#define WM8523_ZC 0x0010 /* ZC */ +#define WM8523_ZC_MASK 0x0010 /* ZC */ +#define WM8523_ZC_SHIFT 4 /* ZC */ +#define WM8523_ZC_WIDTH 1 /* ZC */ +#define WM8523_DACR 0x0008 /* DACR */ +#define WM8523_DACR_MASK 0x0008 /* DACR */ +#define WM8523_DACR_SHIFT 3 /* DACR */ +#define WM8523_DACR_WIDTH 1 /* DACR */ +#define WM8523_DACL 0x0004 /* DACL */ +#define WM8523_DACL_MASK 0x0004 /* DACL */ +#define WM8523_DACL_SHIFT 2 /* DACL */ +#define WM8523_DACL_WIDTH 1 /* DACL */ +#define WM8523_VOL_UP_RAMP 0x0002 /* VOL_UP_RAMP */ +#define WM8523_VOL_UP_RAMP_MASK 0x0002 /* VOL_UP_RAMP */ +#define WM8523_VOL_UP_RAMP_SHIFT 1 /* VOL_UP_RAMP */ +#define WM8523_VOL_UP_RAMP_WIDTH 1 /* VOL_UP_RAMP */ +#define WM8523_VOL_DOWN_RAMP 0x0001 /* VOL_DOWN_RAMP */ +#define WM8523_VOL_DOWN_RAMP_MASK 0x0001 /* VOL_DOWN_RAMP */ +#define WM8523_VOL_DOWN_RAMP_SHIFT 0 /* VOL_DOWN_RAMP */ +#define WM8523_VOL_DOWN_RAMP_WIDTH 1 /* VOL_DOWN_RAMP */ + +/* + * R6 (0x06) - DAC_GAINL + */ +#define WM8523_DACL_VU 0x0200 /* DACL_VU */ +#define WM8523_DACL_VU_MASK 0x0200 /* DACL_VU */ +#define WM8523_DACL_VU_SHIFT 9 /* DACL_VU */ +#define WM8523_DACL_VU_WIDTH 1 /* DACL_VU */ +#define WM8523_DACL_VOL_MASK 0x01FF /* DACL_VOL - [8:0] */ +#define WM8523_DACL_VOL_SHIFT 0 /* DACL_VOL - [8:0] */ +#define WM8523_DACL_VOL_WIDTH 9 /* DACL_VOL - [8:0] */ + +/* + * R7 (0x07) - DAC_GAINR + */ +#define WM8523_DACR_VU 0x0200 /* DACR_VU */ +#define WM8523_DACR_VU_MASK 0x0200 /* DACR_VU */ +#define WM8523_DACR_VU_SHIFT 9 /* DACR_VU */ +#define WM8523_DACR_VU_WIDTH 1 /* DACR_VU */ +#define WM8523_DACR_VOL_MASK 0x01FF /* DACR_VOL - [8:0] */ +#define WM8523_DACR_VOL_SHIFT 0 /* DACR_VOL - [8:0] */ +#define WM8523_DACR_VOL_WIDTH 9 /* DACR_VOL - [8:0] */ + +/* + * R8 (0x08) - ZERO_DETECT + */ +#define WM8523_ZD_COUNT_MASK 0x0003 /* ZD_COUNT - [1:0] */ +#define WM8523_ZD_COUNT_SHIFT 0 /* ZD_COUNT - [1:0] */ +#define WM8523_ZD_COUNT_WIDTH 2 /* ZD_COUNT - [1:0] */ + +extern struct snd_soc_dai wm8523_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8523; + +#endif -- cgit v0.10.2 From cd775387244e379ef9b284f9b6aff6ee069f4d12 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Jul 2009 10:28:56 +0200 Subject: ALSA: ice1724 - Fix section mismatch Now snd_vt1724_chip_reset() is used in the resume callback, thus it cannot be __devinit. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 6a56002..fdd6c6d 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2267,7 +2267,7 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, -static void __devinit snd_vt1724_chip_reset(struct snd_ice1712 *ice) +static void snd_vt1724_chip_reset(struct snd_ice1712 *ice) { outb(VT1724_RESET , ICEREG1724(ice, CONTROL)); inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */ -- cgit v0.10.2 From a68f6610d4f1ebe61818f5926fa8fa9e75d06a95 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 2 Jul 2009 16:32:12 +0800 Subject: crypto: testmgr - Allow implementation-specific tests This patch adds the support for testing specific implementations. This should only be used in very specific situations. Right now this means specific implementations of random number generators. Signed-off-by: Herbert Xu diff --git a/crypto/testmgr.c b/crypto/testmgr.c index f9bea9d..29b228d 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -2344,6 +2344,7 @@ static int alg_find_test(const char *alg) int alg_test(const char *driver, const char *alg, u32 type, u32 mask) { int i; + int j; int rc; if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) { @@ -2365,14 +2366,22 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask) } i = alg_find_test(alg); - if (i < 0) + j = alg_find_test(driver); + if (i < 0 && j < 0) goto notest; - if (fips_enabled && !alg_test_descs[i].fips_allowed) + if (fips_enabled && ((i >= 0 && !alg_test_descs[i].fips_allowed) || + (j >= 0 && !alg_test_descs[j].fips_allowed))) goto non_fips_alg; - rc = alg_test_descs[i].test(alg_test_descs + i, driver, - type, mask); + rc = 0; + if (i >= 0) + rc |= alg_test_descs[i].test(alg_test_descs + i, driver, + type, mask); + if (j >= 0) + rc |= alg_test_descs[j].test(alg_test_descs + j, driver, + type, mask); + test_done: if (fips_enabled && rc) panic("%s: %s alg self test failed in fips mode!\n", driver, alg); -- cgit v0.10.2 From 4e49ffd10f01950bd81e8ef368a1ffb484a7d759 Mon Sep 17 00:00:00 2001 From: "Candelaria Villareal, Jorge" Date: Wed, 1 Jul 2009 19:17:43 -0500 Subject: ASoC: TWL4030: Add EXTMUTE to reduce pop-noise effect According to TRM, an external FET controlled by a 1.8V output signal can be used to reduce the pop-noise heard when the audio amplifier is switched on. It is suggested that GPIO6 of TWL4030 be used, but any other gpio can be used instead. This is indicated in machine driver with the following twl4030_setup_data members: -hs_extmute. Set to 1 if board has support for EXTMUTE. -set_hs_extmute. Set to a callback funcion to control an external gpio line. Set to NULL if MUTE[GPIO6] pin is used. Codec driver takes care of enabling and disabling this output during the headset pop attenuation sequence. Also add a delay to let VMID settle in ramp up sequence. Signed-off-by: Jorge Eduardo Candelaria Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 49ceb62..6da94ca 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -620,6 +620,9 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w, static void headset_ramp(struct snd_soc_codec *codec, int ramp) { + struct snd_soc_device *socdev = codec->socdev; + struct twl4030_setup_data *setup = socdev->codec_data; + unsigned char hs_gain, hs_pop; struct twl4030_priv *twl4030 = codec->private_data; /* Base values for ramp delay calculation: 2^19 - 2^26 */ @@ -629,6 +632,17 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET); hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); + /* Enable external mute control, this dramatically reduces + * the pop-noise */ + if (setup && setup->hs_extmute) { + if (setup->set_hs_extmute) { + setup->set_hs_extmute(1); + } else { + hs_pop |= TWL4030_EXTMUTE; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); + } + } + if (ramp) { /* Headset ramp-up according to the TRM */ hs_pop |= TWL4030_VMID_EN; @@ -636,6 +650,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain); hs_pop |= TWL4030_RAMP_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); + /* Wait ramp delay time + 1, so the VMID can settle */ + mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] / + twl4030->sysclk) + 1); } else { /* Headset ramp-down _not_ according to * the TRM, but in a way that it is working */ @@ -652,6 +669,16 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) hs_pop &= ~TWL4030_VMID_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); } + + /* Disable external mute */ + if (setup && setup->hs_extmute) { + if (setup->set_hs_extmute) { + setup->set_hs_extmute(0); + } else { + hs_pop &= ~TWL4030_EXTMUTE; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); + } + } } static int headsetlpga_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index fe5f395..2b4bfa2 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h @@ -274,6 +274,8 @@ extern struct snd_soc_codec_device soc_codec_dev_twl4030; struct twl4030_setup_data { unsigned int ramp_delay_value; unsigned int sysclk; + unsigned int hs_extmute:1; + void (*set_hs_extmute)(int mute); }; #endif /* End of __TWL4030_AUDIO_H__ */ -- cgit v0.10.2 From ed94070058033a3c99fe62c90d00c39dc443c679 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 3 Jul 2009 12:09:41 +0800 Subject: crypto: ansi_prng - Use just a BH lock The current code uses a mix of sping_lock() & spin_lock_irqsave(). This can lead to deadlock with the correct timming & cprng_get_random() + cprng_reset() sequence. I've converted them to bottom half locks since all three user grab just a BH lock so this runs probably in softirq :) Signed-off-by: Sebastian Andrzej Siewior Acked-by: Neil Horman Signed-off-by: Herbert Xu diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index d80ed4c..ff00b58 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -187,7 +187,6 @@ static int _get_more_prng_bytes(struct prng_context *ctx) /* Our exported functions */ static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx) { - unsigned long flags; unsigned char *ptr = buf; unsigned int byte_count = (unsigned int)nbytes; int err; @@ -196,7 +195,7 @@ static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx) if (nbytes < 0) return -EINVAL; - spin_lock_irqsave(&ctx->prng_lock, flags); + spin_lock_bh(&ctx->prng_lock); err = -EINVAL; if (ctx->flags & PRNG_NEED_RESET) @@ -268,7 +267,7 @@ empty_rbuf: goto remainder; done: - spin_unlock_irqrestore(&ctx->prng_lock, flags); + spin_unlock_bh(&ctx->prng_lock); dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n", err, ctx); return err; @@ -287,7 +286,7 @@ static int reset_prng_context(struct prng_context *ctx, int rc = -EINVAL; unsigned char *prng_key; - spin_lock(&ctx->prng_lock); + spin_lock_bh(&ctx->prng_lock); ctx->flags |= PRNG_NEED_RESET; prng_key = (key != NULL) ? key : (unsigned char *)DEFAULT_PRNG_KEY; @@ -332,7 +331,7 @@ static int reset_prng_context(struct prng_context *ctx, rc = 0; ctx->flags &= ~PRNG_NEED_RESET; out: - spin_unlock(&ctx->prng_lock); + spin_unlock_bh(&ctx->prng_lock); return rc; -- cgit v0.10.2 From fd09d7facb7cf3a884979eb5f843338ce1ce9b43 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 3 Jul 2009 12:10:47 +0800 Subject: crypto: ansi_prng - alloc cipher just in init As reported by Eric Sesterhenn the re-allocation of the cipher in reset leads to: |BUG: sleeping function called from invalid context at kernel/rwsem.c:21 |in_atomic(): 1, irqs_disabled(): 0, pid: 4926, name: modprobe |INFO: lockdep is turned off. |Pid: 4926, comm: modprobe Tainted: G M 2.6.31-rc1-22297-g5298976 #24 |Call Trace: | [] __might_sleep+0xf9/0x101 | [] down_read+0x16/0x68 | [] crypto_alg_lookup+0x16/0x34 | [] crypto_larval_lookup+0x30/0xf9 | [] crypto_alg_mod_lookup+0x1d/0x62 | [] crypto_alloc_base+0x1e/0x64 | [] reset_prng_context+0xab/0x13f | [] ? __spin_lock_init+0x27/0x51 | [] cprng_init+0x2a/0x42 | [] __crypto_alloc_tfm+0xfa/0x128 | [] crypto_alloc_base+0x33/0x64 | [] alg_test_cprng+0x30/0x1f4 | [] alg_test+0x12f/0x19f | [] ? __alloc_pages_nodemask+0x14d/0x481 | [] do_test+0xf9d/0x163f [tcrypt] | [] do_test+0x3a1/0x163f [tcrypt] | [] tcrypt_mod_init+0x35/0x7c [tcrypt] | [] _stext+0x54/0x12c | [] ? tcrypt_mod_init+0x0/0x7c [tcrypt] | [] ? up_read+0x16/0x2b | [] ? __blocking_notifier_call_chain+0x40/0x4c | [] sys_init_module+0xa9/0x1bf | [] sysenter_do_call+0x12/0x32 because a spin lock is held and crypto_alloc_base() may sleep. There is no reason to re-allocate the cipher, the state is resetted in ->setkey(). This patches makes the cipher allocation a one time thing and moves it to init. Reported-by: Eric Sesterhenn Signed-off-by: Sebastian Andrzej Siewior Acked-by: Neil Horman Signed-off-by: Herbert Xu diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index ff00b58..5357ba7 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -283,7 +283,6 @@ static int reset_prng_context(struct prng_context *ctx, unsigned char *V, unsigned char *DT) { int ret; - int rc = -EINVAL; unsigned char *prng_key; spin_lock_bh(&ctx->prng_lock); @@ -307,34 +306,20 @@ static int reset_prng_context(struct prng_context *ctx, memset(ctx->rand_data, 0, DEFAULT_BLK_SZ); memset(ctx->last_rand_data, 0, DEFAULT_BLK_SZ); - if (ctx->tfm) - crypto_free_cipher(ctx->tfm); - - ctx->tfm = crypto_alloc_cipher("aes", 0, 0); - if (IS_ERR(ctx->tfm)) { - dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n", - ctx); - ctx->tfm = NULL; - goto out; - } - ctx->rand_data_valid = DEFAULT_BLK_SZ; ret = crypto_cipher_setkey(ctx->tfm, prng_key, klen); if (ret) { dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n", crypto_cipher_get_flags(ctx->tfm)); - crypto_free_cipher(ctx->tfm); goto out; } - rc = 0; + ret = 0; ctx->flags &= ~PRNG_NEED_RESET; out: spin_unlock_bh(&ctx->prng_lock); - - return rc; - + return ret; } static int cprng_init(struct crypto_tfm *tfm) @@ -342,6 +327,12 @@ static int cprng_init(struct crypto_tfm *tfm) struct prng_context *ctx = crypto_tfm_ctx(tfm); spin_lock_init(&ctx->prng_lock); + ctx->tfm = crypto_alloc_cipher("aes", 0, 0); + if (IS_ERR(ctx->tfm)) { + dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n", + ctx); + return PTR_ERR(ctx->tfm); + } if (reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL) < 0) return -EINVAL; -- cgit v0.10.2 From 03b042bf1dc14a268a3d65d38b4ec2a4261e8477 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 25 Jun 2009 09:08:16 -0700 Subject: rcu: Add synchronize_sched_expedited() primitive This adds the synchronize_sched_expedited() primitive that implements the "big hammer" expedited RCU grace periods. This primitive is placed in kernel/sched.c rather than kernel/rcupdate.c due to its need to interact closely with the migration_thread() kthread. The idea is to wake up this kthread with req->task set to NULL, in response to which the kthread reports the quiescent state resulting from the kthread having been scheduled. Because this patch needs to fallback to the slow versions of the primitives in response to some races with CPU onlining and offlining, a new synchronize_rcu_bh() primitive is added as well. 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: <12459460982947-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 0cdfdb6..3c89d6a 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -51,7 +51,19 @@ struct rcu_head { void (*func)(struct rcu_head *head); }; -/* Internal to kernel, but needed by rcupreempt.h. */ +/* Exported common interfaces */ +extern void synchronize_rcu(void); +extern void synchronize_rcu_bh(void); +extern void rcu_barrier(void); +extern void rcu_barrier_bh(void); +extern void rcu_barrier_sched(void); +extern void synchronize_sched_expedited(void); +extern int sched_expedited_torture_stats(char *page); + +/* Internal to kernel */ +extern void rcu_init(void); +extern void rcu_scheduler_starting(void); +extern int rcu_needs_cpu(int cpu); extern int rcu_scheduler_active; #if defined(CONFIG_TREE_RCU) @@ -257,15 +269,4 @@ extern void call_rcu(struct rcu_head *head, extern void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *head)); -/* Exported common interfaces */ -extern void synchronize_rcu(void); -extern void rcu_barrier(void); -extern void rcu_barrier_bh(void); -extern void rcu_barrier_sched(void); - -/* Internal to kernel */ -extern void rcu_init(void); -extern void rcu_scheduler_starting(void); -extern int rcu_needs_cpu(int cpu); - #endif /* __LINUX_RCUPDATE_H */ diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h index fce5227..f164ac9 100644 --- a/include/linux/rcupreempt.h +++ b/include/linux/rcupreempt.h @@ -74,6 +74,16 @@ extern int rcu_needs_cpu(int cpu); 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); diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 5a51538..d4dfd24 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -286,8 +286,14 @@ static inline void __rcu_read_unlock_bh(void) #define call_rcu_sched(head, func) call_rcu(head, func) -static inline void rcu_init_sched(void) +static inline void synchronize_rcu_expedited(void) +{ + synchronize_sched_expedited(); +} + +static inline void synchronize_rcu_bh_expedited(void) { + synchronize_sched_expedited(); } extern void __rcu_init(void); @@ -297,6 +303,10 @@ extern void rcu_restart_cpu(int cpu); extern long rcu_batches_completed(void); extern long rcu_batches_completed_bh(void); +static inline void rcu_init_sched(void) +{ +} + #ifdef CONFIG_NO_HZ void rcu_enter_nohz(void); void rcu_exit_nohz(void); diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index a967c9f..eae29c2 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -98,6 +98,30 @@ void synchronize_rcu(void) } EXPORT_SYMBOL_GPL(synchronize_rcu); +/** + * synchronize_rcu_bh - wait until an rcu_bh grace period has elapsed. + * + * Control will return to the caller some time after a full rcu_bh grace + * period has elapsed, in other words after all currently executing rcu_bh + * read-side critical sections have completed. RCU read-side critical + * sections are delimited by rcu_read_lock_bh() and rcu_read_unlock_bh(), + * and may be nested. + */ +void synchronize_rcu_bh(void) +{ + struct rcu_synchronize rcu; + + if (rcu_blocking_is_gp()) + return; + + init_completion(&rcu.completion); + /* Will wake me after RCU finished. */ + call_rcu_bh(&rcu.head, wakeme_after_rcu); + /* Wait for it. */ + wait_for_completion(&rcu.completion); +} +EXPORT_SYMBOL_GPL(synchronize_rcu_bh); + static void rcu_barrier_callback(struct rcu_head *notused) { if (atomic_dec_and_test(&rcu_barrier_cpu_count)) @@ -129,6 +153,7 @@ static void rcu_barrier_func(void *type) static inline void wait_migrated_callbacks(void) { wait_event(rcu_migrate_wq, !atomic_read(&rcu_migrate_type_count)); + smp_mb(); /* In case we didn't sleep. */ } /* diff --git a/kernel/sched.c b/kernel/sched.c index 7c9098d..9ae80be 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -7024,6 +7024,11 @@ fail: return ret; } +#define RCU_MIGRATION_IDLE 0 +#define RCU_MIGRATION_NEED_QS 1 +#define RCU_MIGRATION_GOT_QS 2 +#define RCU_MIGRATION_MUST_SYNC 3 + /* * migration_thread - this is a highprio system thread that performs * thread migration by bumping thread off CPU then 'pushing' onto @@ -7031,6 +7036,7 @@ fail: */ static int migration_thread(void *data) { + int badcpu; int cpu = (long)data; struct rq *rq; @@ -7065,8 +7071,17 @@ static int migration_thread(void *data) req = list_entry(head->next, struct migration_req, list); list_del_init(head->next); - spin_unlock(&rq->lock); - __migrate_task(req->task, cpu, req->dest_cpu); + if (req->task != NULL) { + spin_unlock(&rq->lock); + __migrate_task(req->task, cpu, req->dest_cpu); + } else if (likely(cpu == (badcpu = smp_processor_id()))) { + req->dest_cpu = RCU_MIGRATION_GOT_QS; + spin_unlock(&rq->lock); + } else { + req->dest_cpu = RCU_MIGRATION_MUST_SYNC; + spin_unlock(&rq->lock); + WARN_ONCE(1, "migration_thread() on CPU %d, expected %d\n", badcpu, cpu); + } local_irq_enable(); complete(&req->done); @@ -10554,3 +10569,113 @@ struct cgroup_subsys cpuacct_subsys = { .subsys_id = cpuacct_subsys_id, }; #endif /* CONFIG_CGROUP_CPUACCT */ + +#ifndef CONFIG_SMP + +int rcu_expedited_torture_stats(char *page) +{ + return 0; +} +EXPORT_SYMBOL_GPL(rcu_expedited_torture_stats); + +void synchronize_sched_expedited(void) +{ +} +EXPORT_SYMBOL_GPL(synchronize_sched_expedited); + +#else /* #ifndef CONFIG_SMP */ + +static DEFINE_PER_CPU(struct migration_req, rcu_migration_req); +static DEFINE_MUTEX(rcu_sched_expedited_mutex); + +#define RCU_EXPEDITED_STATE_POST -2 +#define RCU_EXPEDITED_STATE_IDLE -1 + +static int rcu_expedited_state = RCU_EXPEDITED_STATE_IDLE; + +int rcu_expedited_torture_stats(char *page) +{ + int cnt = 0; + int cpu; + + cnt += sprintf(&page[cnt], "state: %d /", rcu_expedited_state); + for_each_online_cpu(cpu) { + cnt += sprintf(&page[cnt], " %d:%d", + cpu, per_cpu(rcu_migration_req, cpu).dest_cpu); + } + cnt += sprintf(&page[cnt], "\n"); + return cnt; +} +EXPORT_SYMBOL_GPL(rcu_expedited_torture_stats); + +static long synchronize_sched_expedited_count; + +/* + * Wait for an rcu-sched grace period to elapse, but use "big hammer" + * approach to force grace period to end quickly. This consumes + * significant time on all CPUs, and is thus not recommended for + * any sort of common-case code. + * + * Note that it is illegal to call this function while holding any + * lock that is acquired by a CPU-hotplug notifier. Failing to + * observe this restriction will result in deadlock. + */ +void synchronize_sched_expedited(void) +{ + int cpu; + unsigned long flags; + bool need_full_sync = 0; + struct rq *rq; + struct migration_req *req; + long snap; + int trycount = 0; + + smp_mb(); /* ensure prior mod happens before capturing snap. */ + snap = ACCESS_ONCE(synchronize_sched_expedited_count) + 1; + get_online_cpus(); + while (!mutex_trylock(&rcu_sched_expedited_mutex)) { + put_online_cpus(); + if (trycount++ < 10) + udelay(trycount * num_online_cpus()); + else { + synchronize_sched(); + return; + } + if (ACCESS_ONCE(synchronize_sched_expedited_count) - snap > 0) { + smp_mb(); /* ensure test happens before caller kfree */ + return; + } + get_online_cpus(); + } + rcu_expedited_state = RCU_EXPEDITED_STATE_POST; + for_each_online_cpu(cpu) { + rq = cpu_rq(cpu); + req = &per_cpu(rcu_migration_req, cpu); + init_completion(&req->done); + req->task = NULL; + req->dest_cpu = RCU_MIGRATION_NEED_QS; + spin_lock_irqsave(&rq->lock, flags); + list_add(&req->list, &rq->migration_queue); + spin_unlock_irqrestore(&rq->lock, flags); + wake_up_process(rq->migration_thread); + } + for_each_online_cpu(cpu) { + rcu_expedited_state = cpu; + req = &per_cpu(rcu_migration_req, cpu); + rq = cpu_rq(cpu); + wait_for_completion(&req->done); + spin_lock_irqsave(&rq->lock, flags); + if (unlikely(req->dest_cpu == RCU_MIGRATION_MUST_SYNC)) + need_full_sync = 1; + req->dest_cpu = RCU_MIGRATION_IDLE; + spin_unlock_irqrestore(&rq->lock, flags); + } + rcu_expedited_state = RCU_EXPEDITED_STATE_IDLE; + mutex_unlock(&rcu_sched_expedited_mutex); + put_online_cpus(); + if (need_full_sync) + synchronize_sched(); +} +EXPORT_SYMBOL_GPL(synchronize_sched_expedited); + +#endif /* #else #ifndef CONFIG_SMP */ -- cgit v0.10.2 From 0acc512cb1a29636df5e982c7d845edafe77c2d0 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 25 Jun 2009 09:08:17 -0700 Subject: rcu: Add synchronize_sched_expedited() torture tests This patch adds rcutorture tests for the new synchronize_sched_expedited() primitive, and also does some whitespace cleanups in kernel/rcutorture.c as well. 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: <12459460981342-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 9b4a975..b33db53 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -257,14 +257,14 @@ struct rcu_torture_ops { void (*init)(void); void (*cleanup)(void); int (*readlock)(void); - void (*readdelay)(struct rcu_random_state *rrsp); + void (*read_delay)(struct rcu_random_state *rrsp); void (*readunlock)(int idx); int (*completed)(void); - void (*deferredfree)(struct rcu_torture *p); + void (*deferred_free)(struct rcu_torture *p); void (*sync)(void); void (*cb_barrier)(void); int (*stats)(char *page); - int irqcapable; + int irq_capable; char *name; }; static struct rcu_torture_ops *cur_ops = NULL; @@ -320,7 +320,7 @@ rcu_torture_cb(struct rcu_head *p) rp->rtort_mbtest = 0; rcu_torture_free(rp); } else - cur_ops->deferredfree(rp); + cur_ops->deferred_free(rp); } static void rcu_torture_deferred_free(struct rcu_torture *p) @@ -329,18 +329,18 @@ static void rcu_torture_deferred_free(struct rcu_torture *p) } static struct rcu_torture_ops rcu_ops = { - .init = NULL, - .cleanup = NULL, - .readlock = rcu_torture_read_lock, - .readdelay = rcu_read_delay, - .readunlock = rcu_torture_read_unlock, - .completed = rcu_torture_completed, - .deferredfree = rcu_torture_deferred_free, - .sync = synchronize_rcu, - .cb_barrier = rcu_barrier, - .stats = NULL, - .irqcapable = 1, - .name = "rcu" + .init = NULL, + .cleanup = NULL, + .readlock = rcu_torture_read_lock, + .read_delay = rcu_read_delay, + .readunlock = rcu_torture_read_unlock, + .completed = rcu_torture_completed, + .deferred_free = rcu_torture_deferred_free, + .sync = synchronize_rcu, + .cb_barrier = rcu_barrier, + .stats = NULL, + .irq_capable = 1, + .name = "rcu" }; static void rcu_sync_torture_deferred_free(struct rcu_torture *p) @@ -370,18 +370,18 @@ static void rcu_sync_torture_init(void) } static struct rcu_torture_ops rcu_sync_ops = { - .init = rcu_sync_torture_init, - .cleanup = NULL, - .readlock = rcu_torture_read_lock, - .readdelay = rcu_read_delay, - .readunlock = rcu_torture_read_unlock, - .completed = rcu_torture_completed, - .deferredfree = rcu_sync_torture_deferred_free, - .sync = synchronize_rcu, - .cb_barrier = NULL, - .stats = NULL, - .irqcapable = 1, - .name = "rcu_sync" + .init = rcu_sync_torture_init, + .cleanup = NULL, + .readlock = rcu_torture_read_lock, + .read_delay = rcu_read_delay, + .readunlock = rcu_torture_read_unlock, + .completed = rcu_torture_completed, + .deferred_free = rcu_sync_torture_deferred_free, + .sync = synchronize_rcu, + .cb_barrier = NULL, + .stats = NULL, + .irq_capable = 1, + .name = "rcu_sync" }; /* @@ -432,33 +432,33 @@ static void rcu_bh_torture_synchronize(void) } static struct rcu_torture_ops rcu_bh_ops = { - .init = NULL, - .cleanup = NULL, - .readlock = rcu_bh_torture_read_lock, - .readdelay = rcu_read_delay, /* just reuse rcu's version. */ - .readunlock = rcu_bh_torture_read_unlock, - .completed = rcu_bh_torture_completed, - .deferredfree = rcu_bh_torture_deferred_free, - .sync = rcu_bh_torture_synchronize, - .cb_barrier = rcu_barrier_bh, - .stats = NULL, - .irqcapable = 1, - .name = "rcu_bh" + .init = NULL, + .cleanup = NULL, + .readlock = rcu_bh_torture_read_lock, + .read_delay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = rcu_bh_torture_read_unlock, + .completed = rcu_bh_torture_completed, + .deferred_free = rcu_bh_torture_deferred_free, + .sync = rcu_bh_torture_synchronize, + .cb_barrier = rcu_barrier_bh, + .stats = NULL, + .irq_capable = 1, + .name = "rcu_bh" }; static struct rcu_torture_ops rcu_bh_sync_ops = { - .init = rcu_sync_torture_init, - .cleanup = NULL, - .readlock = rcu_bh_torture_read_lock, - .readdelay = rcu_read_delay, /* just reuse rcu's version. */ - .readunlock = rcu_bh_torture_read_unlock, - .completed = rcu_bh_torture_completed, - .deferredfree = rcu_sync_torture_deferred_free, - .sync = rcu_bh_torture_synchronize, - .cb_barrier = NULL, - .stats = NULL, - .irqcapable = 1, - .name = "rcu_bh_sync" + .init = rcu_sync_torture_init, + .cleanup = NULL, + .readlock = rcu_bh_torture_read_lock, + .read_delay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = rcu_bh_torture_read_unlock, + .completed = rcu_bh_torture_completed, + .deferred_free = rcu_sync_torture_deferred_free, + .sync = rcu_bh_torture_synchronize, + .cb_barrier = NULL, + .stats = NULL, + .irq_capable = 1, + .name = "rcu_bh_sync" }; /* @@ -530,17 +530,17 @@ static int srcu_torture_stats(char *page) } static struct rcu_torture_ops srcu_ops = { - .init = srcu_torture_init, - .cleanup = srcu_torture_cleanup, - .readlock = srcu_torture_read_lock, - .readdelay = srcu_read_delay, - .readunlock = srcu_torture_read_unlock, - .completed = srcu_torture_completed, - .deferredfree = rcu_sync_torture_deferred_free, - .sync = srcu_torture_synchronize, - .cb_barrier = NULL, - .stats = srcu_torture_stats, - .name = "srcu" + .init = srcu_torture_init, + .cleanup = srcu_torture_cleanup, + .readlock = srcu_torture_read_lock, + .read_delay = srcu_read_delay, + .readunlock = srcu_torture_read_unlock, + .completed = srcu_torture_completed, + .deferred_free = rcu_sync_torture_deferred_free, + .sync = srcu_torture_synchronize, + .cb_barrier = NULL, + .stats = srcu_torture_stats, + .name = "srcu" }; /* @@ -574,32 +574,49 @@ static void sched_torture_synchronize(void) } static struct rcu_torture_ops sched_ops = { - .init = rcu_sync_torture_init, - .cleanup = NULL, - .readlock = sched_torture_read_lock, - .readdelay = rcu_read_delay, /* just reuse rcu's version. */ - .readunlock = sched_torture_read_unlock, - .completed = sched_torture_completed, - .deferredfree = rcu_sched_torture_deferred_free, - .sync = sched_torture_synchronize, - .cb_barrier = rcu_barrier_sched, - .stats = NULL, - .irqcapable = 1, - .name = "sched" + .init = rcu_sync_torture_init, + .cleanup = NULL, + .readlock = sched_torture_read_lock, + .read_delay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = sched_torture_read_unlock, + .completed = sched_torture_completed, + .deferred_free = rcu_sched_torture_deferred_free, + .sync = sched_torture_synchronize, + .cb_barrier = rcu_barrier_sched, + .stats = NULL, + .irq_capable = 1, + .name = "sched" }; static struct rcu_torture_ops sched_ops_sync = { - .init = rcu_sync_torture_init, - .cleanup = NULL, - .readlock = sched_torture_read_lock, - .readdelay = rcu_read_delay, /* just reuse rcu's version. */ - .readunlock = sched_torture_read_unlock, - .completed = sched_torture_completed, - .deferredfree = rcu_sync_torture_deferred_free, - .sync = sched_torture_synchronize, - .cb_barrier = NULL, - .stats = NULL, - .name = "sched_sync" + .init = rcu_sync_torture_init, + .cleanup = NULL, + .readlock = sched_torture_read_lock, + .read_delay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = sched_torture_read_unlock, + .completed = sched_torture_completed, + .deferred_free = rcu_sync_torture_deferred_free, + .sync = sched_torture_synchronize, + .cb_barrier = NULL, + .stats = NULL, + .name = "sched_sync" +}; + +extern int rcu_expedited_torture_stats(char *page); + +static struct rcu_torture_ops sched_expedited_ops = { + .init = rcu_sync_torture_init, + .cleanup = NULL, + .readlock = sched_torture_read_lock, + .read_delay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = sched_torture_read_unlock, + .completed = sched_torture_completed, + .deferred_free = rcu_sync_torture_deferred_free, + .sync = synchronize_sched_expedited, + .cb_barrier = NULL, + .stats = rcu_expedited_torture_stats, + .irq_capable = 1, + .name = "sched_expedited" }; /* @@ -635,7 +652,7 @@ rcu_torture_writer(void *arg) i = RCU_TORTURE_PIPE_LEN; atomic_inc(&rcu_torture_wcount[i]); old_rp->rtort_pipe_count++; - cur_ops->deferredfree(old_rp); + cur_ops->deferred_free(old_rp); } rcu_torture_current_version++; oldbatch = cur_ops->completed(); @@ -700,7 +717,7 @@ static void rcu_torture_timer(unsigned long unused) if (p->rtort_mbtest == 0) atomic_inc(&n_rcu_torture_mberror); spin_lock(&rand_lock); - cur_ops->readdelay(&rand); + cur_ops->read_delay(&rand); n_rcu_torture_timers++; spin_unlock(&rand_lock); preempt_disable(); @@ -738,11 +755,11 @@ rcu_torture_reader(void *arg) VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); set_user_nice(current, 19); - if (irqreader && cur_ops->irqcapable) + if (irqreader && cur_ops->irq_capable) setup_timer_on_stack(&t, rcu_torture_timer, 0); do { - if (irqreader && cur_ops->irqcapable) { + if (irqreader && cur_ops->irq_capable) { if (!timer_pending(&t)) mod_timer(&t, 1); } @@ -757,7 +774,7 @@ rcu_torture_reader(void *arg) } if (p->rtort_mbtest == 0) atomic_inc(&n_rcu_torture_mberror); - cur_ops->readdelay(&rand); + cur_ops->read_delay(&rand); preempt_disable(); pipe_count = p->rtort_pipe_count; if (pipe_count > RCU_TORTURE_PIPE_LEN) { @@ -778,7 +795,7 @@ rcu_torture_reader(void *arg) } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); rcutorture_shutdown_absorb("rcu_torture_reader"); - if (irqreader && cur_ops->irqcapable) + if (irqreader && cur_ops->irq_capable) del_timer_sync(&t); while (!kthread_should_stop()) schedule_timeout_uninterruptible(1); @@ -1078,6 +1095,7 @@ rcu_torture_init(void) int firsterr = 0; static struct rcu_torture_ops *torture_ops[] = { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, + &sched_expedited_ops, &srcu_ops, &sched_ops, &sched_ops_sync, }; mutex_lock(&fullstop_mutex); -- cgit v0.10.2 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 diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt index 9f711d2..d2b8523 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 aab4a9e..90ec534 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 accfe2f..51525a3 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 909602d..e439a0e 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 a342b6e..9dba3bb 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 9617082..97ded24 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 v0.10.2 From 4d09161196c9a836eacea4b36e2f217bc34894cf Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Wed, 1 Jul 2009 21:08:37 -0400 Subject: printk: Enable the use of more than one CON_BOOT (early console) Today, register_console() assumes the following usage: - The first console to register with a flag set to CON_BOOT is the one and only bootconsole. - If another register_console() is called with an additional CON_BOOT, it is silently rejected. - As soon as a console without the CON_BOOT set calls registers the bootconsole is automatically unregistered. - Once there is a "real" console - register_console() will silently reject any consoles with it's CON_BOOT flag set. In many systems (alpha, blackfin, microblaze, mips, powerpc, sh, & x86), there are early_printk implementations, which use the CON_BOOT which come out serial ports, vga, usb, & memory buffers. In many embedded systems, it would be nice to have two bootconsoles - in case the primary fails, you always have access to a backup memory buffer - but this requires at least two CON_BOOT consoles... This patch enables that functionality. With the change applied, on boot you get (if you try to re-enable a boot console after the "real" console has been registered): root:/> dmesg | grep console bootconsole [early_shadow0] enabled bootconsole [early_BFuart0] enabled Kernel command line: root=/dev/mtdblock0 rw earlyprintk=serial,uart0,57600 console=ttyBF0,57600 nmi_debug=regs console handover:boot [early_BFuart0] boot [early_shadow0] -> real [ttyBF0] Too late to register bootconsole early_shadow0 or: root:/> dmesg | grep console Kernel command line: root=/dev/mtdblock0 rw console=ttyBF0,57600 console [ttyBF0] enabled Signed-off-by: Robin Getz Cc: "Linus Torvalds" Cc: "Andrew Morton" Cc: "Mike Frysinger" Cc: "Paul Mundt" LKML-Reference: <200907012108.38030.rgetz@blackfin.uclinux.org> Signed-off-by: Ingo Molnar diff --git a/kernel/printk.c b/kernel/printk.c index b4d97b5..41fe609 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -37,6 +37,12 @@ #include /* + * for_each_console() allows you to iterate on each console + */ +#define for_each_console(con) \ + for (con = console_drivers; con != NULL; con = con->next) + +/* * Architectures can override it: */ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) @@ -412,7 +418,7 @@ static void __call_console_drivers(unsigned start, unsigned end) { struct console *con; - for (con = console_drivers; con; con = con->next) { + for_each_console(con) { if ((con->flags & CON_ENABLED) && con->write && (cpu_online(smp_processor_id()) || (con->flags & CON_ANYTIME))) @@ -544,7 +550,7 @@ static int have_callable_console(void) { struct console *con; - for (con = console_drivers; con; con = con->next) + for_each_console(con) if (con->flags & CON_ANYTIME) return 1; @@ -1082,7 +1088,7 @@ void console_unblank(void) console_locked = 1; console_may_schedule = 0; - for (c = console_drivers; c != NULL; c = c->next) + for_each_console(c) if ((c->flags & CON_ENABLED) && c->unblank) c->unblank(); release_console_sem(); @@ -1097,7 +1103,7 @@ struct tty_driver *console_device(int *index) struct tty_driver *driver = NULL; acquire_console_sem(); - for (c = console_drivers; c != NULL; c = c->next) { + for_each_console(c) { if (!c->device) continue; driver = c->device(c, index); @@ -1134,25 +1140,49 @@ EXPORT_SYMBOL(console_start); * to register the console printing procedure with printk() and to * print any messages that were printed by the kernel before the * console driver was initialized. + * + * This can happen pretty early during the boot process (because of + * early_printk) - sometimes before setup_arch() completes - be careful + * of what kernel features are used - they may not be initialised yet. + * + * There are two types of consoles - bootconsoles (early_printk) and + * "real" consoles (everything which is not a bootconsole) which are + * handled differently. + * - Any number of bootconsoles can be registered at any time. + * - As soon as a "real" console is registered, all bootconsoles + * will be unregistered automatically. + * - Once a "real" console is registered, any attempt to register a + * bootconsoles will be rejected */ -void register_console(struct console *console) +void register_console(struct console *newcon) { int i; unsigned long flags; - struct console *bootconsole = NULL; + struct console *bcon = NULL; - if (console_drivers) { - if (console->flags & CON_BOOT) - return; - if (console_drivers->flags & CON_BOOT) - bootconsole = console_drivers; + /* + * before we register a new CON_BOOT console, make sure we don't + * already have a valid console + */ + if (console_drivers && newcon->flags & CON_BOOT) { + /* find the last or real console */ + for_each_console(bcon) { + if (!(bcon->flags & CON_BOOT)) { + printk(KERN_INFO "Too late to register bootconsole %s%d\n", + newcon->name, newcon->index); + return; + } + } } - if (preferred_console < 0 || bootconsole || !console_drivers) + if (console_drivers && console_drivers->flags & CON_BOOT) + bcon = console_drivers; + + if (preferred_console < 0 || bcon || !console_drivers) preferred_console = selected_console; - if (console->early_setup) - console->early_setup(); + if (newcon->early_setup) + newcon->early_setup(); /* * See if we want to use this console driver. If we @@ -1160,13 +1190,13 @@ void register_console(struct console *console) * that registers here. */ if (preferred_console < 0) { - if (console->index < 0) - console->index = 0; - if (console->setup == NULL || - console->setup(console, NULL) == 0) { - console->flags |= CON_ENABLED; - if (console->device) { - console->flags |= CON_CONSDEV; + if (newcon->index < 0) + newcon->index = 0; + if (newcon->setup == NULL || + newcon->setup(newcon, NULL) == 0) { + newcon->flags |= CON_ENABLED; + if (newcon->device) { + newcon->flags |= CON_CONSDEV; preferred_console = 0; } } @@ -1178,47 +1208,53 @@ void register_console(struct console *console) */ for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) { - if (strcmp(console_cmdline[i].name, console->name) != 0) + if (strcmp(console_cmdline[i].name, newcon->name) != 0) continue; - if (console->index >= 0 && - console->index != console_cmdline[i].index) + if (newcon->index >= 0 && + newcon->index != console_cmdline[i].index) continue; - if (console->index < 0) - console->index = console_cmdline[i].index; + if (newcon->index < 0) + newcon->index = console_cmdline[i].index; #ifdef CONFIG_A11Y_BRAILLE_CONSOLE if (console_cmdline[i].brl_options) { - console->flags |= CON_BRL; - braille_register_console(console, + newcon->flags |= CON_BRL; + braille_register_console(newcon, console_cmdline[i].index, console_cmdline[i].options, console_cmdline[i].brl_options); return; } #endif - if (console->setup && - console->setup(console, console_cmdline[i].options) != 0) + if (newcon->setup && + newcon->setup(newcon, console_cmdline[i].options) != 0) break; - console->flags |= CON_ENABLED; - console->index = console_cmdline[i].index; + newcon->flags |= CON_ENABLED; + newcon->index = console_cmdline[i].index; if (i == selected_console) { - console->flags |= CON_CONSDEV; + newcon->flags |= CON_CONSDEV; preferred_console = selected_console; } break; } - if (!(console->flags & CON_ENABLED)) + if (!(newcon->flags & CON_ENABLED)) return; - if (bootconsole && (console->flags & CON_CONSDEV)) { - printk(KERN_INFO "console handover: boot [%s%d] -> real [%s%d]\n", - bootconsole->name, bootconsole->index, - console->name, console->index); - unregister_console(bootconsole); - console->flags &= ~CON_PRINTBUFFER; + if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) { + /* we need to iterate through twice, to make sure we print + * everything out, before we unregister the console(s) + */ + printk(KERN_INFO "console handover:"); + for_each_console(bcon) + printk("boot [%s%d] ", bcon->name, bcon->index); + printk(" -> real [%s%d]\n", newcon->name, newcon->index); + for_each_console(bcon) + unregister_console(bcon); + newcon->flags &= ~CON_PRINTBUFFER; } else { - printk(KERN_INFO "console [%s%d] enabled\n", - console->name, console->index); + printk(KERN_INFO "%sconsole [%s%d] enabled\n", + (newcon->flags & CON_BOOT) ? "boot" : "" , + newcon->name, newcon->index); } /* @@ -1226,16 +1262,16 @@ void register_console(struct console *console) * preferred driver at the head of the list. */ acquire_console_sem(); - if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { - console->next = console_drivers; - console_drivers = console; - if (console->next) - console->next->flags &= ~CON_CONSDEV; + if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { + newcon->next = console_drivers; + console_drivers = newcon; + if (newcon->next) + newcon->next->flags &= ~CON_CONSDEV; } else { - console->next = console_drivers->next; - console_drivers->next = console; + newcon->next = console_drivers->next; + console_drivers->next = newcon; } - if (console->flags & CON_PRINTBUFFER) { + if (newcon->flags & CON_PRINTBUFFER) { /* * release_console_sem() will print out the buffered messages * for us. @@ -1287,11 +1323,13 @@ EXPORT_SYMBOL(unregister_console); static int __init disable_boot_consoles(void) { - if (console_drivers != NULL) { - if (console_drivers->flags & CON_BOOT) { + struct console *con; + + for_each_console(con) { + if (con->flags & CON_BOOT) { printk(KERN_INFO "turn off boot console %s%d\n", - console_drivers->name, console_drivers->index); - return unregister_console(console_drivers); + con->name, con->index); + return unregister_console(con); } } return 0; -- cgit v0.10.2 From cb6381225a8064b0911dced3eb10f00bd5520c85 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 3 Jul 2009 10:56:10 +0200 Subject: ALSA: hda - Add missing mixer amp initialization for ALC882 After merting patch_alc882() and patch_alc883(), the initialization of mixer amp 0x0b was missing in alc882_base_init_verbs[]. This is usually no critical problem, but it can disable the power-saving as the default state, so better to put to mute these channels. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0f6b6a6..d15d83e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6849,6 +6849,13 @@ static struct hda_verb alc882_base_init_verbs[] = { {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)}, + /* Front Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, -- cgit v0.10.2 From 8ab9e0af6d7709a781b60a51711ddf1d43bd22bb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 3 Jul 2009 10:58:12 +0200 Subject: ALSA: hda - Manually expand alc882_init_verbs Instead of expanding alc882_init_verbs to two elements via a macro, manually expand to each entry. This makes clear that some have already the full slot for init_verbs array (currently 5). Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d15d83e..07e260a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6922,9 +6922,6 @@ static struct hda_verb alc882_adc1_init_verbs[] = { { } }; -/* 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}, @@ -8492,7 +8489,8 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { static struct alc_config_preset alc882_presets[] = { [ALC882_3ST_DIG] = { .mixers = { alc882_base_mixer }, - .init_verbs = { alc882_init_verbs }, + .init_verbs = { alc882_base_init_verbs, + alc882_adc1_init_verbs }, .num_dacs = ARRAY_SIZE(alc882_dac_nids), .dac_nids = alc882_dac_nids, .dig_out_nid = ALC882_DIGOUT_NID, @@ -8504,7 +8502,8 @@ static struct alc_config_preset alc882_presets[] = { }, [ALC882_6ST_DIG] = { .mixers = { alc882_base_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs }, + .init_verbs = { alc882_base_init_verbs, + alc882_adc1_init_verbs }, .num_dacs = ARRAY_SIZE(alc882_dac_nids), .dac_nids = alc882_dac_nids, .dig_out_nid = ALC882_DIGOUT_NID, @@ -8515,7 +8514,8 @@ static struct alc_config_preset alc882_presets[] = { }, [ALC882_ARIMA] = { .mixers = { alc882_base_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs, alc882_eapd_verbs }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_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), @@ -8524,8 +8524,8 @@ static struct alc_config_preset alc882_presets[] = { }, [ALC882_W2JC] = { .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, - alc880_gpio1_init_verbs }, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_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), @@ -8587,7 +8587,8 @@ static struct alc_config_preset alc882_presets[] = { }, [ALC882_TARGA] = { .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs, alc882_targa_verbs}, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc882_targa_verbs}, .num_dacs = ARRAY_SIZE(alc882_dac_nids), .dac_nids = alc882_dac_nids, .dig_out_nid = ALC882_DIGOUT_NID, @@ -8603,7 +8604,8 @@ static struct alc_config_preset alc882_presets[] = { }, [ALC882_ASUS_A7J] = { .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs}, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, + alc882_asus_a7j_verbs}, .num_dacs = ARRAY_SIZE(alc882_dac_nids), .dac_nids = alc882_dac_nids, .dig_out_nid = ALC882_DIGOUT_NID, @@ -8617,8 +8619,8 @@ static struct alc_config_preset alc882_presets[] = { }, [ALC882_ASUS_A7M] = { .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, - alc880_gpio1_init_verbs, + .init_verbs = { alc882_base_init_verbs, alc882_adc1_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, -- cgit v0.10.2 From ddc1637af217dbd8bc51f30e6d24e84476a869a6 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Fri, 3 Jul 2009 17:34:24 +0800 Subject: kmemtrace: Print binary output only if 'bin' option is set Currently by default the output of kmemtrace is binary format instead of human-readable output. This patch makes the following changes: - We'll see human-readable output by default - We'll see binary output if 'bin' option is set Note: you may probably need to explicitly disable context-info binary output: # echo 0 > options/context-info # echo 1 > options/bin # cat trace_pipe v2: - use %pF to print call_site Signed-off-by: Li Zefan Acked-by: Pekka Enberg Acked-by: Eduard - Gabriel Munteanu Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4A4DD0A0.5060500@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/kmemtrace.c b/kernel/trace/kmemtrace.c index 1edaa95..74903b6 100644 --- a/kernel/trace/kmemtrace.c +++ b/kernel/trace/kmemtrace.c @@ -239,12 +239,52 @@ struct kmemtrace_user_event_alloc { }; static enum print_line_t -kmemtrace_print_alloc_user(struct trace_iterator *iter, - struct kmemtrace_alloc_entry *entry) +kmemtrace_print_alloc_user(struct trace_iterator *iter, int flags) +{ + struct trace_seq *s = &iter->seq; + struct kmemtrace_alloc_entry *entry; + int ret; + + trace_assign_type(entry, iter->ent); + + ret = trace_seq_printf(s, "type_id %d call_site %pF ptr %lu " + "bytes_req %lu bytes_alloc %lu gfp_flags %lu node %d\n", + entry->type_id, (void *)entry->call_site, (unsigned long)entry->ptr, + (unsigned long)entry->bytes_req, (unsigned long)entry->bytes_alloc, + (unsigned long)entry->gfp_flags, entry->node); + + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t +kmemtrace_print_free_user(struct trace_iterator *iter, int flags) { - struct kmemtrace_user_event_alloc *ev_alloc; struct trace_seq *s = &iter->seq; + struct kmemtrace_free_entry *entry; + int ret; + + trace_assign_type(entry, iter->ent); + + ret = trace_seq_printf(s, "type_id %d call_site %pF ptr %lu\n", + entry->type_id, (void *)entry->call_site, + (unsigned long)entry->ptr); + + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t +kmemtrace_print_alloc_user_bin(struct trace_iterator *iter, int flags) +{ + struct trace_seq *s = &iter->seq; + struct kmemtrace_alloc_entry *entry; struct kmemtrace_user_event *ev; + struct kmemtrace_user_event_alloc *ev_alloc; + + trace_assign_type(entry, iter->ent); ev = trace_seq_reserve(s, sizeof(*ev)); if (!ev) @@ -271,12 +311,14 @@ kmemtrace_print_alloc_user(struct trace_iterator *iter, } static enum print_line_t -kmemtrace_print_free_user(struct trace_iterator *iter, - struct kmemtrace_free_entry *entry) +kmemtrace_print_free_user_bin(struct trace_iterator *iter, int flags) { struct trace_seq *s = &iter->seq; + struct kmemtrace_free_entry *entry; struct kmemtrace_user_event *ev; + trace_assign_type(entry, iter->ent); + ev = trace_seq_reserve(s, sizeof(*ev)); if (!ev) return TRACE_TYPE_PARTIAL_LINE; @@ -294,12 +336,14 @@ kmemtrace_print_free_user(struct trace_iterator *iter, /* The two other following provide a more minimalistic output */ static enum print_line_t -kmemtrace_print_alloc_compress(struct trace_iterator *iter, - struct kmemtrace_alloc_entry *entry) +kmemtrace_print_alloc_compress(struct trace_iterator *iter) { + struct kmemtrace_alloc_entry *entry; struct trace_seq *s = &iter->seq; int ret; + trace_assign_type(entry, iter->ent); + /* Alloc entry */ ret = trace_seq_printf(s, " + "); if (!ret) @@ -362,12 +406,14 @@ kmemtrace_print_alloc_compress(struct trace_iterator *iter, } static enum print_line_t -kmemtrace_print_free_compress(struct trace_iterator *iter, - struct kmemtrace_free_entry *entry) +kmemtrace_print_free_compress(struct trace_iterator *iter) { + struct kmemtrace_free_entry *entry; struct trace_seq *s = &iter->seq; int ret; + trace_assign_type(entry, iter->ent); + /* Free entry */ ret = trace_seq_printf(s, " - "); if (!ret) @@ -421,32 +467,31 @@ static enum print_line_t kmemtrace_print_line(struct trace_iterator *iter) { struct trace_entry *entry = iter->ent; - switch (entry->type) { - case TRACE_KMEM_ALLOC: { - struct kmemtrace_alloc_entry *field; - - trace_assign_type(field, entry); - if (kmem_tracer_flags.val & TRACE_KMEM_OPT_MINIMAL) - return kmemtrace_print_alloc_compress(iter, field); - else - return kmemtrace_print_alloc_user(iter, field); - } - - case TRACE_KMEM_FREE: { - struct kmemtrace_free_entry *field; - - trace_assign_type(field, entry); - if (kmem_tracer_flags.val & TRACE_KMEM_OPT_MINIMAL) - return kmemtrace_print_free_compress(iter, field); - else - return kmemtrace_print_free_user(iter, field); - } + if (!(kmem_tracer_flags.val & TRACE_KMEM_OPT_MINIMAL)) + return TRACE_TYPE_UNHANDLED; + switch (entry->type) { + case TRACE_KMEM_ALLOC: + return kmemtrace_print_alloc_compress(iter); + case TRACE_KMEM_FREE: + return kmemtrace_print_free_compress(iter); default: return TRACE_TYPE_UNHANDLED; } } +static struct trace_event kmem_trace_alloc = { + .type = TRACE_KMEM_ALLOC, + .trace = kmemtrace_print_alloc_user, + .binary = kmemtrace_print_alloc_user_bin, +}; + +static struct trace_event kmem_trace_free = { + .type = TRACE_KMEM_FREE, + .trace = kmemtrace_print_free_user, + .binary = kmemtrace_print_free_user_bin, +}; + static struct tracer kmem_tracer __read_mostly = { .name = "kmemtrace", .init = kmem_trace_init, @@ -463,6 +508,21 @@ void kmemtrace_init(void) static int __init init_kmem_tracer(void) { - return register_tracer(&kmem_tracer); + if (!register_ftrace_event(&kmem_trace_alloc)) { + pr_warning("Warning: could not register kmem events\n"); + return 1; + } + + if (!register_ftrace_event(&kmem_trace_free)) { + pr_warning("Warning: could not register kmem events\n"); + return 1; + } + + if (!register_tracer(&kmem_tracer)) { + pr_warning("Warning: could not register the kmem tracer\n"); + return 1; + } + + return 0; } device_initcall(init_kmem_tracer); -- cgit v0.10.2 From 1b6ebdd7bbdb3fdcab82c8056dbae0c23dbaaf4d Mon Sep 17 00:00:00 2001 From: "Candelaria Villareal, Jorge" Date: Thu, 2 Jul 2009 19:04:07 -0500 Subject: ASoC: Zoom2: Update twl4030_setup_data parameters Add support for EXTMUTE in Zoom2 machine driver. This is necessary to further reduce pop noise problem. Signal EXTMUTE is connected to signal GPIO 153 in Zoom2 board. In addition, change ramp delay value to 3 (218/161/109 ms). With previous ramp delay value, pop noise was louder. With a longer value the beep tone can be observed. Signed-off-by: Jorge Eduardo Candelaria Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index 3de6d2b..f90b45f 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c @@ -35,7 +35,8 @@ #include "omap-pcm.h" #include "../codecs/twl4030.h" -#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15) +#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15) +#define ZOOM2_HEADSET_EXTMUTE_GPIO 153 static int zoom2_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -234,10 +235,18 @@ static struct snd_soc_card snd_soc_zoom2 = { .num_links = ARRAY_SIZE(zoom2_dai), }; +/* EXTMUTE callback function */ +void zoom2_set_hs_extmute(int mute) +{ + gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute); +} + /* twl4030 setup */ static struct twl4030_setup_data twl4030_setup = { - .ramp_delay_value = 2, /* 81 ms */ + .ramp_delay_value = 3, /* 161 ms */ .sysclk = 26000, + .hs_extmute = 1, + .set_hs_extmute = zoom2_set_hs_extmute, }; /* Audio subsystem */ @@ -277,6 +286,9 @@ static int __init zoom2_soc_init(void) BUG_ON(gpio_request(ZOOM2_HEADSET_MUX_GPIO, "hs_mux") < 0); gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0); + BUG_ON(gpio_request(ZOOM2_HEADSET_EXTMUTE_GPIO, "ext_mute") < 0); + gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 0); + return 0; err1: @@ -290,6 +302,7 @@ module_init(zoom2_soc_init); static void __exit zoom2_soc_exit(void) { gpio_free(ZOOM2_HEADSET_MUX_GPIO); + gpio_free(ZOOM2_HEADSET_EXTMUTE_GPIO); platform_device_unregister(zoom2_snd_device); } -- cgit v0.10.2 From 6814044324e745e7c55aaf4bd47bdfd9a51d842a Mon Sep 17 00:00:00 2001 From: "Lopez Cruz, Misael" Date: Fri, 3 Jul 2009 02:21:39 -0500 Subject: ASoC: TWL4030: Add tristate callbacks for HiFi and Voice Add "set_tristate" callbacks for HiFi and Voice DAIs. Machine drivers can enable and disable tristate for each DAI with "snd_soc_dai_set_tristate" function. Signed-off-by: Misael Lopez Cruz Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 6da94ca..818fb37 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1849,6 +1849,19 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } +static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + struct snd_soc_codec *codec = dai->codec; + u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); + + if (tristate) + reg |= TWL4030_AIF_TRI_EN; + else + reg &= ~TWL4030_AIF_TRI_EN; + + return twl4030_write(codec, TWL4030_REG_AUDIO_IF, reg); +} + /* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R * (VTXL, VTXR) for uplink has to be enabled/disabled. */ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction, @@ -2023,6 +2036,19 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } +static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + struct snd_soc_codec *codec = dai->codec; + u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF); + + if (tristate) + reg |= TWL4030_VIF_TRI_EN; + else + reg &= ~TWL4030_VIF_TRI_EN; + + return twl4030_write(codec, TWL4030_REG_VOICE_IF, reg); +} + #define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) @@ -2032,6 +2058,7 @@ static struct snd_soc_dai_ops twl4030_dai_ops = { .hw_params = twl4030_hw_params, .set_sysclk = twl4030_set_dai_sysclk, .set_fmt = twl4030_set_dai_fmt, + .set_tristate = twl4030_set_tristate, }; static struct snd_soc_dai_ops twl4030_dai_voice_ops = { @@ -2040,6 +2067,7 @@ static struct snd_soc_dai_ops twl4030_dai_voice_ops = { .hw_params = twl4030_voice_hw_params, .set_sysclk = twl4030_voice_set_dai_sysclk, .set_fmt = twl4030_voice_set_dai_fmt, + .set_tristate = twl4030_voice_set_tristate, }; struct snd_soc_dai twl4030_dai[] = { -- cgit v0.10.2 From b0bb3aa6233dccfccd040793d0d9ce838e4890e1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 3 Jul 2009 23:25:37 +0200 Subject: ALSA: hda - Don't override maxbps for FLOAT sharing with linear formats When FLOAT PCM format is available but together with other linear PCM formats, don't override maxbps value. For FLOAT format, it's always 32, thus it can be better checked in snd_hda_calc_stream_format(). Otherwise the maxbps 32 might be used wrongly even if the linear PCM doesn't support it. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 263d124..fb5760c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2563,7 +2563,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, case 20: case 24: case 32: - if (maxbps >= 32) + if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE) val |= 0x40; else if (maxbps >= 24) val |= 0x30; @@ -2692,7 +2692,8 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, } if (streams & AC_SUPFMT_FLOAT32) { formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; - bps = 32; + if (!bps) + bps = 32; } if (streams == AC_SUPFMT_AC3) { /* should be exclusive */ -- cgit v0.10.2 From 42204455f160dab0c47f19e1be23f5c927af2d17 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sat, 4 Jul 2009 07:50:00 +0530 Subject: x86: Clean up mtrr/amd.c: Fix trivial style problems : ERROR: trailing whitespace WARNING: line over 80 characters ERROR: do not use C99 // comments arch/x86/kernel/cpu/mtrr/amd.o: text data bss dec hex filename 501 32 0 533 215 amd.o.before 501 32 0 533 215 amd.o.after md5: 62f795eb840ee2d17b03df89e789e76c amd.o.before.asm 62f795eb840ee2d17b03df89e789e76c amd.o.after.asm Suggested-by: Alan Cox Signed-off-by: Jaswinder Singh Rajput Cc: Andrew Morton Cc: Yinghai Lu LKML-Reference: <20090703164225.GA21447@elte.hu> [ Also restructured comments to be standard, removed stray return, converted function description to DocBook style, etc. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mtrr/amd.c b/arch/x86/kernel/cpu/mtrr/amd.c index ee2331b..33af141 100644 --- a/arch/x86/kernel/cpu/mtrr/amd.c +++ b/arch/x86/kernel/cpu/mtrr/amd.c @@ -7,15 +7,15 @@ static void amd_get_mtrr(unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type * type) + unsigned long *size, mtrr_type *type) { unsigned long low, high; rdmsr(MSR_K6_UWCCR, low, high); - /* Upper dword is region 1, lower is region 0 */ + /* Upper dword is region 1, lower is region 0 */ if (reg == 1) low = high; - /* The base masks off on the right alignment */ + /* The base masks off on the right alignment */ *base = (low & 0xFFFE0000) >> PAGE_SHIFT; *type = 0; if (low & 1) @@ -27,74 +27,81 @@ amd_get_mtrr(unsigned int reg, unsigned long *base, return; } /* - * This needs a little explaining. The size is stored as an - * inverted mask of bits of 128K granularity 15 bits long offset - * 2 bits + * This needs a little explaining. The size is stored as an + * inverted mask of bits of 128K granularity 15 bits long offset + * 2 bits. * - * So to get a size we do invert the mask and add 1 to the lowest - * mask bit (4 as its 2 bits in). This gives us a size we then shift - * to turn into 128K blocks + * So to get a size we do invert the mask and add 1 to the lowest + * mask bit (4 as its 2 bits in). This gives us a size we then shift + * to turn into 128K blocks. * - * eg 111 1111 1111 1100 is 512K + * eg 111 1111 1111 1100 is 512K * - * invert 000 0000 0000 0011 - * +1 000 0000 0000 0100 - * *128K ... + * invert 000 0000 0000 0011 + * +1 000 0000 0000 0100 + * *128K ... */ low = (~low) & 0x1FFFC; *size = (low + 4) << (15 - PAGE_SHIFT); - return; } -static void amd_set_mtrr(unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type) -/* [SUMMARY] Set variable MTRR register on the local CPU. - The register to set. - The base address of the region. - The size of the region. If this is 0 the region is disabled. - The type of the region. - [RETURNS] Nothing. -*/ +/** + * amd_set_mtrr - Set variable MTRR register on the local CPU. + * + * @reg The register to set. + * @base The base address of the region. + * @size The size of the region. If this is 0 the region is disabled. + * @type The type of the region. + * + * Returns nothing. + */ +static void +amd_set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type) { u32 regs[2]; /* - * Low is MTRR0 , High MTRR 1 + * Low is MTRR0, High MTRR 1 */ rdmsr(MSR_K6_UWCCR, regs[0], regs[1]); /* - * Blank to disable + * Blank to disable */ - if (size == 0) + if (size == 0) { regs[reg] = 0; - else - /* Set the register to the base, the type (off by one) and an - inverted bitmask of the size The size is the only odd - bit. We are fed say 512K We invert this and we get 111 1111 - 1111 1011 but if you subtract one and invert you get the - desired 111 1111 1111 1100 mask - - But ~(x - 1) == ~x + 1 == -x. Two's complement rocks! */ + } else { + /* + * Set the register to the base, the type (off by one) and an + * inverted bitmask of the size The size is the only odd + * bit. We are fed say 512K We invert this and we get 111 1111 + * 1111 1011 but if you subtract one and invert you get the + * desired 111 1111 1111 1100 mask + * + * But ~(x - 1) == ~x + 1 == -x. Two's complement rocks! + */ regs[reg] = (-size >> (15 - PAGE_SHIFT) & 0x0001FFFC) | (base << PAGE_SHIFT) | (type + 1); + } /* - * The writeback rule is quite specific. See the manual. Its - * disable local interrupts, write back the cache, set the mtrr + * The writeback rule is quite specific. See the manual. Its + * disable local interrupts, write back the cache, set the mtrr */ wbinvd(); wrmsr(MSR_K6_UWCCR, regs[0], regs[1]); } -static int amd_validate_add_page(unsigned long base, unsigned long size, unsigned int type) +static int +amd_validate_add_page(unsigned long base, unsigned long size, unsigned int type) { - /* Apply the K6 block alignment and size rules - In order - o Uncached or gathering only - o 128K or bigger block - o Power of 2 block - o base suitably aligned to the power - */ + /* + * Apply the K6 block alignment and size rules + * In order + * o Uncached or gathering only + * o 128K or bigger block + * o Power of 2 block + * o base suitably aligned to the power + */ if (type > MTRR_TYPE_WRCOMB || size < (1 << (17 - PAGE_SHIFT)) || (size & ~(size - 1)) - size || (base & (size - 1))) return -EINVAL; @@ -115,5 +122,3 @@ int __init amd_init_mtrr(void) set_mtrr_ops(&amd_mtrr_ops); return 0; } - -//arch_initcall(amd_mtrr_init); -- cgit v0.10.2 From 6c4caa1ab737502190e416b76e6c10d2bf24276a Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sat, 4 Jul 2009 07:50:44 +0530 Subject: x86: Clean up mtrr/centaur.c Remove dead code and fix trivial style problems: ERROR: trailing whitespace X 2 WARNING: line over 80 characters X 3 ROR: trailing whitespace ERROR: do not use C99 // comments X 2 arch/x86/kernel/cpu/mtrr/centaur.o: text data bss dec hex filename 605 32 68 705 2c1 centaur.o.before 605 32 68 705 2c1 centaur.o.after md5: a4865ea98ce3c163bb1d376a3949b3e3 centaur.o.before.asm a4865ea98ce3c163bb1d376a3949b3e3 centaur.o.after.asm Suggested-by: Alan Cox Signed-off-by: Jaswinder Singh Rajput Cc: Andrew Morton Cc: Yinghai Lu LKML-Reference: <20090703164225.GA21447@elte.hu> [ Standardized comments, DocBook, curly braces, newlines. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mtrr/centaur.c b/arch/x86/kernel/cpu/mtrr/centaur.c index cb9aa3a..de89f14 100644 --- a/arch/x86/kernel/cpu/mtrr/centaur.c +++ b/arch/x86/kernel/cpu/mtrr/centaur.c @@ -1,7 +1,9 @@ #include #include + #include #include + #include "mtrr.h" static struct { @@ -12,25 +14,25 @@ static struct { static u8 centaur_mcr_reserved; static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */ -/* - * Report boot time MCR setups +/** + * centaur_get_free_region - Get a free MTRR. + * + * @base: The starting (base) address of the region. + * @size: The size (in bytes) of the region. + * + * Returns: the index of the region on success, else -1 on error. */ - static int centaur_get_free_region(unsigned long base, unsigned long size, int replace_reg) -/* [SUMMARY] Get a free MTRR. - The starting (base) address of the region. - The size (in bytes) of the region. - [RETURNS] The index of the region on success, else -1 on error. -*/ { - int i, max; - mtrr_type ltype; unsigned long lbase, lsize; + mtrr_type ltype; + int i, max; max = num_var_ranges; if (replace_reg >= 0 && replace_reg < max) return replace_reg; + for (i = 0; i < max; ++i) { if (centaur_mcr_reserved & (1 << i)) continue; @@ -38,11 +40,14 @@ centaur_get_free_region(unsigned long base, unsigned long size, int replace_reg) if (lsize == 0) return i; } + return -ENOSPC; } -void -mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) +/* + * Report boot time MCR setups + */ +void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) { centaur_mcr[mcr].low = lo; centaur_mcr[mcr].high = hi; @@ -54,33 +59,35 @@ centaur_get_mcr(unsigned int reg, unsigned long *base, { *base = centaur_mcr[reg].high >> PAGE_SHIFT; *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT; - *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ + *type = MTRR_TYPE_WRCOMB; /* write-combining */ + if (centaur_mcr_type == 1 && ((centaur_mcr[reg].low & 31) & 2)) *type = MTRR_TYPE_UNCACHABLE; if (centaur_mcr_type == 1 && (centaur_mcr[reg].low & 31) == 25) *type = MTRR_TYPE_WRBACK; if (centaur_mcr_type == 0 && (centaur_mcr[reg].low & 31) == 31) *type = MTRR_TYPE_WRBACK; - } -static void centaur_set_mcr(unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type) +static void +centaur_set_mcr(unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type) { unsigned long low, high; if (size == 0) { - /* Disable */ + /* Disable */ high = low = 0; } else { high = base << PAGE_SHIFT; - if (centaur_mcr_type == 0) - low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ - else { + if (centaur_mcr_type == 0) { + /* Only support write-combining... */ + low = -size << PAGE_SHIFT | 0x1f; + } else { if (type == MTRR_TYPE_UNCACHABLE) - low = -size << PAGE_SHIFT | 0x02; /* NC */ + low = -size << PAGE_SHIFT | 0x02; /* NC */ else - low = -size << PAGE_SHIFT | 0x09; /* WWO,WC */ + low = -size << PAGE_SHIFT | 0x09; /* WWO, WC */ } } centaur_mcr[reg].high = high; @@ -88,118 +95,16 @@ static void centaur_set_mcr(unsigned int reg, unsigned long base, wrmsr(MSR_IDT_MCR0 + reg, low, high); } -#if 0 -/* - * Initialise the later (saner) Winchip MCR variant. In this version - * the BIOS can pass us the registers it has used (but not their values) - * and the control register is read/write - */ - -static void __init -centaur_mcr1_init(void) -{ - unsigned i; - u32 lo, hi; - - /* Unfortunately, MCR's are read-only, so there is no way to - * find out what the bios might have done. - */ - - rdmsr(MSR_IDT_MCR_CTRL, lo, hi); - if (((lo >> 17) & 7) == 1) { /* Type 1 Winchip2 MCR */ - lo &= ~0x1C0; /* clear key */ - lo |= 0x040; /* set key to 1 */ - wrmsr(MSR_IDT_MCR_CTRL, lo, hi); /* unlock MCR */ - } - - centaur_mcr_type = 1; - - /* - * Clear any unconfigured MCR's. - */ - - for (i = 0; i < 8; ++i) { - if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0) { - if (!(lo & (1 << (9 + i)))) - wrmsr(MSR_IDT_MCR0 + i, 0, 0); - else - /* - * If the BIOS set up an MCR we cannot see it - * but we don't wish to obliterate it - */ - centaur_mcr_reserved |= (1 << i); - } - } - /* - * Throw the main write-combining switch... - * However if OOSTORE is enabled then people have already done far - * cleverer things and we should behave. - */ - - lo |= 15; /* Write combine enables */ - wrmsr(MSR_IDT_MCR_CTRL, lo, hi); -} - -/* - * Initialise the original winchip with read only MCR registers - * no used bitmask for the BIOS to pass on and write only control - */ - -static void __init -centaur_mcr0_init(void) -{ - unsigned i; - - /* Unfortunately, MCR's are read-only, so there is no way to - * find out what the bios might have done. - */ - - /* Clear any unconfigured MCR's. - * This way we are sure that the centaur_mcr array contains the actual - * values. The disadvantage is that any BIOS tweaks are thus undone. - * - */ - for (i = 0; i < 8; ++i) { - if (centaur_mcr[i].high == 0 && centaur_mcr[i].low == 0) - wrmsr(MSR_IDT_MCR0 + i, 0, 0); - } - - wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0); /* Write only */ -} - -/* - * Initialise Winchip series MCR registers - */ - -static void __init -centaur_mcr_init(void) -{ - struct set_mtrr_context ctxt; - - set_mtrr_prepare_save(&ctxt); - set_mtrr_cache_disable(&ctxt); - - if (boot_cpu_data.x86_model == 4) - centaur_mcr0_init(); - else if (boot_cpu_data.x86_model == 8 || boot_cpu_data.x86_model == 9) - centaur_mcr1_init(); - - set_mtrr_done(&ctxt); -} -#endif - -static int centaur_validate_add_page(unsigned long base, - unsigned long size, unsigned int type) +static int +centaur_validate_add_page(unsigned long base, unsigned long size, unsigned int type) { /* - * FIXME: Winchip2 supports uncached + * FIXME: Winchip2 supports uncached */ - if (type != MTRR_TYPE_WRCOMB && + if (type != MTRR_TYPE_WRCOMB && (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) { - printk(KERN_WARNING - "mtrr: only write-combining%s supported\n", - centaur_mcr_type ? " and uncacheable are" - : " is"); + pr_warning("mtrr: only write-combining%s supported\n", + centaur_mcr_type ? " and uncacheable are" : " is"); return -EINVAL; } return 0; @@ -207,7 +112,6 @@ static int centaur_validate_add_page(unsigned long base, static struct mtrr_ops centaur_mtrr_ops = { .vendor = X86_VENDOR_CENTAUR, -// .init = centaur_mcr_init, .set = centaur_set_mcr, .get = centaur_get_mcr, .get_free_region = centaur_get_free_region, @@ -220,5 +124,3 @@ int __init centaur_init_mtrr(void) set_mtrr_ops(¢aur_mtrr_ops); return 0; } - -//arch_initcall(centaur_init_mtrr); -- cgit v0.10.2 From 63f9600fadb10ea739108ae93e3e842d9843c58b Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sat, 4 Jul 2009 07:51:32 +0530 Subject: x86: Clean up mtrr/cleanup.c Fix trivial style problems: WARNING: Use #include instead of WARNING: Use #include instead of Also, nr_mtrr_spare_reg should be unsigned long. arch/x86/kernel/cpu/mtrr/cleanup.o: text data bss dec hex filename 6241 8992 2056 17289 4389 cleanup.o.before 6241 8992 2056 17289 4389 cleanup.o.after The md5 has changed: 1a7a27513aef1825236daf29110fe657 cleanup.o.before.asm bcea358efa2532b6020e338e158447af cleanup.o.after.asm Because a WARN_ON()'s __LINE__ value changed by 3 lines. Suggested-by: Alan Cox Signed-off-by: Jaswinder Singh Rajput Cc: Andrew Morton Cc: Yinghai Lu LKML-Reference: <20090703164225.GA21447@elte.hu> [ Did lots of other cleanups to make the code look more consistent. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c index 1d584a1..b8aba81 100644 --- a/arch/x86/kernel/cpu/mtrr/cleanup.c +++ b/arch/x86/kernel/cpu/mtrr/cleanup.c @@ -1,51 +1,52 @@ -/* MTRR (Memory Type Range Register) cleanup - - Copyright (C) 2009 Yinghai Lu - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - +/* + * MTRR (Memory Type Range Register) cleanup + * + * Copyright (C) 2009 Yinghai Lu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include #include #include #include #include -#include #include +#include +#include +#include +#include #include #include -#include -#include #include -#include + #include "mtrr.h" -/* should be related to MTRR_VAR_RANGES nums */ +/* Should be related to MTRR_VAR_RANGES nums */ #define RANGE_NUM 256 struct res_range { - unsigned long start; - unsigned long end; + unsigned long start; + unsigned long end; }; static int __init -add_range(struct res_range *range, int nr_range, unsigned long start, - unsigned long end) +add_range(struct res_range *range, int nr_range, + unsigned long start, unsigned long end) { - /* out of slots */ + /* Out of slots: */ if (nr_range >= RANGE_NUM) return nr_range; @@ -58,12 +59,12 @@ add_range(struct res_range *range, int nr_range, unsigned long start, } static int __init -add_range_with_merge(struct res_range *range, int nr_range, unsigned long start, - unsigned long end) +add_range_with_merge(struct res_range *range, int nr_range, + unsigned long start, unsigned long end) { int i; - /* try to merge it with old one */ + /* Try to merge it with old one: */ for (i = 0; i < nr_range; i++) { unsigned long final_start, final_end; unsigned long common_start, common_end; @@ -84,7 +85,7 @@ add_range_with_merge(struct res_range *range, int nr_range, unsigned long start, return nr_range; } - /* need to add that */ + /* Need to add it: */ return add_range(range, nr_range, start, end); } @@ -117,7 +118,7 @@ subtract_range(struct res_range *range, unsigned long start, unsigned long end) } if (start > range[j].start && end < range[j].end) { - /* find the new spare */ + /* Find the new spare: */ for (i = 0; i < RANGE_NUM; i++) { if (range[i].end == 0) break; @@ -147,13 +148,19 @@ static int __init cmp_range(const void *x1, const void *x2) } struct var_mtrr_range_state { - unsigned long base_pfn; - unsigned long size_pfn; - mtrr_type type; + unsigned long base_pfn; + unsigned long size_pfn; + mtrr_type type; }; static struct var_mtrr_range_state __initdata range_state[RANGE_NUM]; + static int __initdata debug_print; +#define Dprintk(x...) do { if (debug_print) printk(KERN_DEBUG x); } while (0) + + +#define BIOS_BUG_MSG KERN_WARNING \ + "WARNING: BIOS bug: VAR MTRR %d contains strange UC entry under 1M, check with your system vendor!\n" static int __init x86_get_mtrr_mem_range(struct res_range *range, int nr_range, @@ -180,7 +187,7 @@ x86_get_mtrr_mem_range(struct res_range *range, int nr_range, range[i].start, range[i].end + 1); } - /* take out UC ranges */ + /* Take out UC ranges: */ for (i = 0; i < num_var_ranges; i++) { type = range_state[i].type; if (type != MTRR_TYPE_UNCACHABLE && @@ -244,10 +251,9 @@ static int __initdata nr_range; static unsigned long __init sum_ranges(struct res_range *range, int nr_range) { - unsigned long sum; + unsigned long sum = 0; int i; - sum = 0; for (i = 0; i < nr_range; i++) sum += range[i].end + 1 - range[i].start; @@ -288,7 +294,7 @@ struct var_mtrr_state { static void __init set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, - unsigned char type, unsigned int address_bits) + unsigned char type, unsigned int address_bits) { u32 base_lo, base_hi, mask_lo, mask_hi; u64 base, mask; @@ -301,7 +307,7 @@ set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, mask = (1ULL << address_bits) - 1; mask &= ~((((u64)sizek) << 10) - 1); - base = ((u64)basek) << 10; + base = ((u64)basek) << 10; base |= type; mask |= 0x800; @@ -317,15 +323,14 @@ set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, static void __init save_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, - unsigned char type) + unsigned char type) { range_state[reg].base_pfn = basek >> (PAGE_SHIFT - 10); range_state[reg].size_pfn = sizek >> (PAGE_SHIFT - 10); range_state[reg].type = type; } -static void __init -set_var_mtrr_all(unsigned int address_bits) +static void __init set_var_mtrr_all(unsigned int address_bits) { unsigned long basek, sizek; unsigned char type; @@ -342,11 +347,11 @@ set_var_mtrr_all(unsigned int address_bits) static unsigned long to_size_factor(unsigned long sizek, char *factorp) { - char factor; unsigned long base = sizek; + char factor; if (base & ((1<<10) - 1)) { - /* not MB alignment */ + /* Not MB-aligned: */ factor = 'K'; } else if (base & ((1<<20) - 1)) { factor = 'M'; @@ -372,11 +377,12 @@ range_to_mtrr(unsigned int reg, unsigned long range_startk, unsigned long max_align, align; unsigned long sizek; - /* Compute the maximum size I can make a range */ + /* Compute the maximum size with which we can make a range: */ if (range_startk) max_align = ffs(range_startk) - 1; else max_align = 32; + align = fls(range_sizek) - 1; if (align > max_align) align = max_align; @@ -386,11 +392,10 @@ range_to_mtrr(unsigned int reg, unsigned long range_startk, char start_factor = 'K', size_factor = 'K'; unsigned long start_base, size_base; - start_base = to_size_factor(range_startk, - &start_factor), - size_base = to_size_factor(sizek, &size_factor), + start_base = to_size_factor(range_startk, &start_factor); + size_base = to_size_factor(sizek, &size_factor); - printk(KERN_DEBUG "Setting variable MTRR %d, " + Dprintk("Setting variable MTRR %d, " "base: %ld%cB, range: %ld%cB, type %s\n", reg, start_base, start_factor, size_base, size_factor, @@ -425,10 +430,11 @@ range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek, chunk_sizek = state->chunk_sizek; gran_sizek = state->gran_sizek; - /* align with gran size, prevent small block used up MTRRs */ + /* Align with gran size, prevent small block used up MTRRs: */ range_basek = ALIGN(state->range_startk, gran_sizek); if ((range_basek > basek) && basek) return second_sizek; + state->range_sizek -= (range_basek - state->range_startk); range_sizek = ALIGN(state->range_sizek, gran_sizek); @@ -439,22 +445,21 @@ range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek, } state->range_sizek = range_sizek; - /* try to append some small hole */ + /* Try to append some small hole: */ range0_basek = state->range_startk; range0_sizek = ALIGN(state->range_sizek, chunk_sizek); - /* no increase */ + /* No increase: */ if (range0_sizek == state->range_sizek) { - if (debug_print) - printk(KERN_DEBUG "rangeX: %016lx - %016lx\n", - range0_basek<<10, - (range0_basek + state->range_sizek)<<10); + Dprintk("rangeX: %016lx - %016lx\n", + range0_basek<<10, + (range0_basek + state->range_sizek)<<10); state->reg = range_to_mtrr(state->reg, range0_basek, state->range_sizek, MTRR_TYPE_WRBACK); return 0; } - /* only cut back, when it is not the last */ + /* Only cut back when it is not the last: */ if (sizek) { while (range0_basek + range0_sizek > (basek + sizek)) { if (range0_sizek >= chunk_sizek) @@ -470,16 +475,16 @@ range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek, second_try: range_basek = range0_basek + range0_sizek; - /* one hole in the middle */ + /* One hole in the middle: */ if (range_basek > basek && range_basek <= (basek + sizek)) second_sizek = range_basek - basek; if (range0_sizek > state->range_sizek) { - /* one hole in middle or at end */ + /* One hole in middle or at the end: */ hole_sizek = range0_sizek - state->range_sizek - second_sizek; - /* hole size should be less than half of range0 size */ + /* Hole size should be less than half of range0 size: */ if (hole_sizek >= (range0_sizek >> 1) && range0_sizek >= chunk_sizek) { range0_sizek -= chunk_sizek; @@ -491,32 +496,30 @@ second_try: } if (range0_sizek) { - if (debug_print) - printk(KERN_DEBUG "range0: %016lx - %016lx\n", - range0_basek<<10, - (range0_basek + range0_sizek)<<10); + Dprintk("range0: %016lx - %016lx\n", + range0_basek<<10, + (range0_basek + range0_sizek)<<10); state->reg = range_to_mtrr(state->reg, range0_basek, range0_sizek, MTRR_TYPE_WRBACK); } if (range0_sizek < state->range_sizek) { - /* need to handle left over */ + /* Need to handle left over range: */ range_sizek = state->range_sizek - range0_sizek; - if (debug_print) - printk(KERN_DEBUG "range: %016lx - %016lx\n", - range_basek<<10, - (range_basek + range_sizek)<<10); + Dprintk("range: %016lx - %016lx\n", + range_basek<<10, + (range_basek + range_sizek)<<10); + state->reg = range_to_mtrr(state->reg, range_basek, range_sizek, MTRR_TYPE_WRBACK); } if (hole_sizek) { hole_basek = range_basek - hole_sizek - second_sizek; - if (debug_print) - printk(KERN_DEBUG "hole: %016lx - %016lx\n", - hole_basek<<10, - (hole_basek + hole_sizek)<<10); + Dprintk("hole: %016lx - %016lx\n", + hole_basek<<10, + (hole_basek + hole_sizek)<<10); state->reg = range_to_mtrr(state->reg, hole_basek, hole_sizek, MTRR_TYPE_UNCACHABLE); } @@ -537,23 +540,23 @@ set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn, basek = base_pfn << (PAGE_SHIFT - 10); sizek = size_pfn << (PAGE_SHIFT - 10); - /* See if I can merge with the last range */ + /* See if I can merge with the last range: */ if ((basek <= 1024) || (state->range_startk + state->range_sizek == basek)) { unsigned long endk = basek + sizek; state->range_sizek = endk - state->range_startk; return; } - /* Write the range mtrrs */ + /* Write the range mtrrs: */ if (state->range_sizek != 0) second_sizek = range_to_mtrr_with_hole(state, basek, sizek); - /* Allocate an msr */ + /* Allocate an msr: */ state->range_startk = basek + second_sizek; state->range_sizek = sizek - second_sizek; } -/* mininum size of mtrr block that can take hole */ +/* Mininum size of mtrr block that can take hole: */ static u64 mtrr_chunk_size __initdata = (256ULL<<20); static int __init parse_mtrr_chunk_size_opt(char *p) @@ -565,7 +568,7 @@ static int __init parse_mtrr_chunk_size_opt(char *p) } early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt); -/* granity of mtrr of block */ +/* Granularity of mtrr of block: */ static u64 mtrr_gran_size __initdata; static int __init parse_mtrr_gran_size_opt(char *p) @@ -577,7 +580,7 @@ static int __init parse_mtrr_gran_size_opt(char *p) } early_param("mtrr_gran_size", parse_mtrr_gran_size_opt); -static int nr_mtrr_spare_reg __initdata = +static unsigned long nr_mtrr_spare_reg __initdata = CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT; static int __init parse_mtrr_spare_reg(char *arg) @@ -586,7 +589,6 @@ static int __init parse_mtrr_spare_reg(char *arg) nr_mtrr_spare_reg = simple_strtoul(arg, NULL, 0); return 0; } - early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg); static int __init @@ -594,8 +596,8 @@ x86_setup_var_mtrrs(struct res_range *range, int nr_range, u64 chunk_size, u64 gran_size) { struct var_mtrr_state var_state; - int i; int num_reg; + int i; var_state.range_startk = 0; var_state.range_sizek = 0; @@ -605,17 +607,18 @@ x86_setup_var_mtrrs(struct res_range *range, int nr_range, memset(range_state, 0, sizeof(range_state)); - /* Write the range etc */ - for (i = 0; i < nr_range; i++) + /* Write the range: */ + for (i = 0; i < nr_range; i++) { set_var_mtrr_range(&var_state, range[i].start, range[i].end - range[i].start + 1); + } - /* Write the last range */ + /* Write the last range: */ if (var_state.range_sizek != 0) range_to_mtrr_with_hole(&var_state, 0, 0); num_reg = var_state.reg; - /* Clear out the extra MTRR's */ + /* Clear out the extra MTRR's: */ while (var_state.reg < num_var_ranges) { save_var_mtrr(var_state.reg, 0, 0, 0); var_state.reg++; @@ -625,11 +628,11 @@ x86_setup_var_mtrrs(struct res_range *range, int nr_range, } struct mtrr_cleanup_result { - unsigned long gran_sizek; - unsigned long chunk_sizek; - unsigned long lose_cover_sizek; - unsigned int num_reg; - int bad; + unsigned long gran_sizek; + unsigned long chunk_sizek; + unsigned long lose_cover_sizek; + unsigned int num_reg; + int bad; }; /* @@ -645,10 +648,10 @@ static unsigned long __initdata min_loss_pfn[RANGE_NUM]; static void __init print_out_mtrr_range_state(void) { - int i; char start_factor = 'K', size_factor = 'K'; unsigned long start_base, size_base; mtrr_type type; + int i; for (i = 0; i < num_var_ranges; i++) { @@ -676,10 +679,10 @@ static int __init mtrr_need_cleanup(void) int i; mtrr_type type; unsigned long size; - /* extra one for all 0 */ + /* Extra one for all 0: */ int num[MTRR_NUM_TYPES + 1]; - /* check entries number */ + /* Check entries number: */ memset(num, 0, sizeof(num)); for (i = 0; i < num_var_ranges; i++) { type = range_state[i].type; @@ -693,88 +696,86 @@ static int __init mtrr_need_cleanup(void) num[type]++; } - /* check if we got UC entries */ + /* Check if we got UC entries: */ if (!num[MTRR_TYPE_UNCACHABLE]) return 0; - /* check if we only had WB and UC */ + /* Check if we only had WB and UC */ if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] != - num_var_ranges - num[MTRR_NUM_TYPES]) + num_var_ranges - num[MTRR_NUM_TYPES]) return 0; return 1; } static unsigned long __initdata range_sums; -static void __init mtrr_calc_range_state(u64 chunk_size, u64 gran_size, - unsigned long extra_remove_base, - unsigned long extra_remove_size, - int i) + +static void __init +mtrr_calc_range_state(u64 chunk_size, u64 gran_size, + unsigned long x_remove_base, + unsigned long x_remove_size, int i) { - int num_reg; static struct res_range range_new[RANGE_NUM]; - static int nr_range_new; unsigned long range_sums_new; + static int nr_range_new; + int num_reg; - /* convert ranges to var ranges state */ - num_reg = x86_setup_var_mtrrs(range, nr_range, - chunk_size, gran_size); + /* Convert ranges to var ranges state: */ + num_reg = x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size); - /* we got new setting in range_state, check it */ + /* We got new setting in range_state, check it: */ memset(range_new, 0, sizeof(range_new)); nr_range_new = x86_get_mtrr_mem_range(range_new, 0, - extra_remove_base, extra_remove_size); + x_remove_base, x_remove_size); range_sums_new = sum_ranges(range_new, nr_range_new); result[i].chunk_sizek = chunk_size >> 10; result[i].gran_sizek = gran_size >> 10; result[i].num_reg = num_reg; + if (range_sums < range_sums_new) { - result[i].lose_cover_sizek = - (range_sums_new - range_sums) << PSHIFT; + result[i].lose_cover_sizek = (range_sums_new - range_sums) << PSHIFT; result[i].bad = 1; - } else - result[i].lose_cover_sizek = - (range_sums - range_sums_new) << PSHIFT; + } else { + result[i].lose_cover_sizek = (range_sums - range_sums_new) << PSHIFT; + } - /* double check it */ + /* Double check it: */ if (!result[i].bad && !result[i].lose_cover_sizek) { - if (nr_range_new != nr_range || - memcmp(range, range_new, sizeof(range))) - result[i].bad = 1; + if (nr_range_new != nr_range || memcmp(range, range_new, sizeof(range))) + result[i].bad = 1; } - if (!result[i].bad && (range_sums - range_sums_new < - min_loss_pfn[num_reg])) { - min_loss_pfn[num_reg] = - range_sums - range_sums_new; - } + if (!result[i].bad && (range_sums - range_sums_new < min_loss_pfn[num_reg])) + min_loss_pfn[num_reg] = range_sums - range_sums_new; } static void __init mtrr_print_out_one_result(int i) { - char gran_factor, chunk_factor, lose_factor; unsigned long gran_base, chunk_base, lose_base; + char gran_factor, chunk_factor, lose_factor; gran_base = to_size_factor(result[i].gran_sizek, &gran_factor), chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor), lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor), - printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t", - result[i].bad ? "*BAD*" : " ", - gran_base, gran_factor, chunk_base, chunk_factor); - printk(KERN_CONT "num_reg: %d \tlose cover RAM: %s%ld%c\n", - result[i].num_reg, result[i].bad ? "-" : "", - lose_base, lose_factor); + + pr_info("%sgran_size: %ld%c \tchunk_size: %ld%c \t", + result[i].bad ? "*BAD*" : " ", + gran_base, gran_factor, chunk_base, chunk_factor); + pr_cont("num_reg: %d \tlose cover RAM: %s%ld%c\n", + result[i].num_reg, result[i].bad ? "-" : "", + lose_base, lose_factor); } static int __init mtrr_search_optimal_index(void) { - int i; int num_reg_good; int index_good; + int i; if (nr_mtrr_spare_reg >= num_var_ranges) nr_mtrr_spare_reg = num_var_ranges - 1; + num_reg_good = -1; for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) { if (!min_loss_pfn[i]) @@ -796,24 +797,24 @@ static int __init mtrr_search_optimal_index(void) return index_good; } - int __init mtrr_cleanup(unsigned address_bits) { - unsigned long extra_remove_base, extra_remove_size; + unsigned long x_remove_base, x_remove_size; unsigned long base, size, def, dummy; - mtrr_type type; u64 chunk_size, gran_size; + mtrr_type type; int index_good; int i; if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1) return 0; + rdmsr(MSR_MTRRdefType, def, dummy); def &= 0xff; if (def != MTRR_TYPE_UNCACHABLE) return 0; - /* get it and store it aside */ + /* Get it and store it aside: */ memset(range_state, 0, sizeof(range_state)); for (i = 0; i < num_var_ranges; i++) { mtrr_if->get(i, &base, &size, &type); @@ -822,29 +823,28 @@ int __init mtrr_cleanup(unsigned address_bits) range_state[i].type = type; } - /* check if we need handle it and can handle it */ + /* Check if we need handle it and can handle it: */ if (!mtrr_need_cleanup()) return 0; - /* print original var MTRRs at first, for debugging: */ + /* Print original var MTRRs at first, for debugging: */ printk(KERN_DEBUG "original variable MTRRs\n"); print_out_mtrr_range_state(); memset(range, 0, sizeof(range)); - extra_remove_size = 0; - extra_remove_base = 1 << (32 - PAGE_SHIFT); + x_remove_size = 0; + x_remove_base = 1 << (32 - PAGE_SHIFT); if (mtrr_tom2) - extra_remove_size = - (mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base; - nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base, - extra_remove_size); + x_remove_size = (mtrr_tom2 >> PAGE_SHIFT) - x_remove_base; + + nr_range = x86_get_mtrr_mem_range(range, 0, x_remove_base, x_remove_size); /* - * [0, 1M) should always be coverred by var mtrr with WB - * and fixed mtrrs should take effective before var mtrr for it + * [0, 1M) should always be covered by var mtrr with WB + * and fixed mtrrs should take effect before var mtrr for it: */ nr_range = add_range_with_merge(range, nr_range, 0, (1ULL<<(20 - PAGE_SHIFT)) - 1); - /* sort the ranges */ + /* Sort the ranges: */ sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL); range_sums = sum_ranges(range, nr_range); @@ -854,7 +854,7 @@ int __init mtrr_cleanup(unsigned address_bits) if (mtrr_chunk_size && mtrr_gran_size) { i = 0; mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size, - extra_remove_base, extra_remove_size, i); + x_remove_base, x_remove_size, i); mtrr_print_out_one_result(i); @@ -880,7 +880,7 @@ int __init mtrr_cleanup(unsigned address_bits) continue; mtrr_calc_range_state(chunk_size, gran_size, - extra_remove_base, extra_remove_size, i); + x_remove_base, x_remove_size, i); if (debug_print) { mtrr_print_out_one_result(i); printk(KERN_INFO "\n"); @@ -890,7 +890,7 @@ int __init mtrr_cleanup(unsigned address_bits) } } - /* try to find the optimal index */ + /* Try to find the optimal index: */ index_good = mtrr_search_optimal_index(); if (index_good != -1) { @@ -898,7 +898,7 @@ int __init mtrr_cleanup(unsigned address_bits) i = index_good; mtrr_print_out_one_result(i); - /* convert ranges to var ranges state */ + /* Convert ranges to var ranges state: */ chunk_size = result[i].chunk_sizek; chunk_size <<= 10; gran_size = result[i].gran_sizek; @@ -941,8 +941,8 @@ early_param("disable_mtrr_trim", disable_mtrr_trim_setup); * Note this won't check if the MTRRs < 4GB where the magic bit doesn't * apply to are wrong, but so far we don't know of any such case in the wild. */ -#define Tom2Enabled (1U << 21) -#define Tom2ForceMemTypeWB (1U << 22) +#define Tom2Enabled (1U << 21) +#define Tom2ForceMemTypeWB (1U << 22) int __init amd_special_default_mtrr(void) { @@ -952,7 +952,7 @@ int __init amd_special_default_mtrr(void) return 0; if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11) return 0; - /* In case some hypervisor doesn't pass SYSCFG through */ + /* In case some hypervisor doesn't pass SYSCFG through: */ if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0) return 0; /* @@ -965,19 +965,21 @@ int __init amd_special_default_mtrr(void) return 0; } -static u64 __init real_trim_memory(unsigned long start_pfn, - unsigned long limit_pfn) +static u64 __init +real_trim_memory(unsigned long start_pfn, unsigned long limit_pfn) { u64 trim_start, trim_size; + trim_start = start_pfn; trim_start <<= PAGE_SHIFT; + trim_size = limit_pfn; trim_size <<= PAGE_SHIFT; trim_size -= trim_start; - return e820_update_range(trim_start, trim_size, E820_RAM, - E820_RESERVED); + return e820_update_range(trim_start, trim_size, E820_RAM, E820_RESERVED); } + /** * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs * @end_pfn: ending page frame number @@ -985,7 +987,7 @@ static u64 __init real_trim_memory(unsigned long start_pfn, * Some buggy BIOSes don't setup the MTRRs properly for systems with certain * memory configurations. This routine checks that the highest MTRR matches * the end of memory, to make sure the MTRRs having a write back type cover - * all of the memory the kernel is intending to use. If not, it'll trim any + * all of the memory the kernel is intending to use. If not, it'll trim any * memory off the end by adjusting end_pfn, removing it from the kernel's * allocation pools, warning the user with an obnoxious message. */ @@ -994,21 +996,22 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) unsigned long i, base, size, highest_pfn = 0, def, dummy; mtrr_type type; u64 total_trim_size; - /* extra one for all 0 */ int num[MTRR_NUM_TYPES + 1]; + /* * Make sure we only trim uncachable memory on machines that * support the Intel MTRR architecture: */ if (!is_cpu(INTEL) || disable_mtrr_trim) return 0; + rdmsr(MSR_MTRRdefType, def, dummy); def &= 0xff; if (def != MTRR_TYPE_UNCACHABLE) return 0; - /* get it and store it aside */ + /* Get it and store it aside: */ memset(range_state, 0, sizeof(range_state)); for (i = 0; i < num_var_ranges; i++) { mtrr_if->get(i, &base, &size, &type); @@ -1017,7 +1020,7 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) range_state[i].type = type; } - /* Find highest cached pfn */ + /* Find highest cached pfn: */ for (i = 0; i < num_var_ranges; i++) { type = range_state[i].type; if (type != MTRR_TYPE_WRBACK) @@ -1028,13 +1031,13 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) highest_pfn = base + size; } - /* kvm/qemu doesn't have mtrr set right, don't trim them all */ + /* kvm/qemu doesn't have mtrr set right, don't trim them all: */ if (!highest_pfn) { printk(KERN_INFO "CPU MTRRs all blank - virtualized system.\n"); return 0; } - /* check entries number */ + /* Check entries number: */ memset(num, 0, sizeof(num)); for (i = 0; i < num_var_ranges; i++) { type = range_state[i].type; @@ -1046,11 +1049,11 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) num[type]++; } - /* no entry for WB? */ + /* No entry for WB? */ if (!num[MTRR_TYPE_WRBACK]) return 0; - /* check if we only had WB and UC */ + /* Check if we only had WB and UC: */ if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] != num_var_ranges - num[MTRR_NUM_TYPES]) return 0; @@ -1066,31 +1069,31 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) } nr_range = x86_get_mtrr_mem_range(range, nr_range, 0, 0); + /* Check the head: */ total_trim_size = 0; - /* check the head */ if (range[0].start) total_trim_size += real_trim_memory(0, range[0].start); - /* check the holes */ + + /* Check the holes: */ for (i = 0; i < nr_range - 1; i++) { if (range[i].end + 1 < range[i+1].start) total_trim_size += real_trim_memory(range[i].end + 1, range[i+1].start); } - /* check the top */ + + /* Check the top: */ i = nr_range - 1; if (range[i].end + 1 < end_pfn) total_trim_size += real_trim_memory(range[i].end + 1, end_pfn); if (total_trim_size) { - printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover" - " all of memory, losing %lluMB of RAM.\n", - total_trim_size >> 20); + pr_warning("WARNING: BIOS bug: CPU MTRRs don't cover all of memory, losing %lluMB of RAM.\n", total_trim_size >> 20); if (!changed_by_mtrr_cleanup) WARN_ON(1); - printk(KERN_INFO "update e820 for mtrr\n"); + pr_info("update e820 for mtrr\n"); update_e820(); return 1; @@ -1098,4 +1101,3 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) return 0; } - -- cgit v0.10.2 From 2311037708c170977506fbcbe0a2ba0c6d221940 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sat, 4 Jul 2009 07:52:08 +0530 Subject: x86: Clean up mtrr/cyrix.c Fix trivial style problems: WARNING: Use #include instead of WARNING: line over 80 characters ERROR: do not initialise statics to 0 or NULL ERROR: space prohibited after that open parenthesis '(' X 2 ERROR: space prohibited before that close parenthesis ')' X 2 ERROR: trailing whitespace X 2 ERROR: trailing statements should be on next line ERROR: do not use C99 // comments X 2 arch/x86/kernel/cpu/mtrr/cyrix.o: text data bss dec hex filename 1637 32 8 1677 68d cyrix.o.before 1637 32 8 1677 68d cyrix.o.after md5: 6f52abd06905be3f4cabb5239f9b0ff0 cyrix.o.before.asm 6f52abd06905be3f4cabb5239f9b0ff0 cyrix.o.after.asm Suggested-by: Alan Cox Signed-off-by: Jaswinder Singh Rajput Cc: Andrew Morton Cc: Yinghai Lu LKML-Reference: <20090703164225.GA21447@elte.hu> [ Made the code more consistent ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mtrr/cyrix.c b/arch/x86/kernel/cpu/mtrr/cyrix.c index ff14c32..228d982 100644 --- a/arch/x86/kernel/cpu/mtrr/cyrix.c +++ b/arch/x86/kernel/cpu/mtrr/cyrix.c @@ -1,38 +1,40 @@ #include +#include #include -#include -#include -#include + #include #include +#include +#include + #include "mtrr.h" static void cyrix_get_arr(unsigned int reg, unsigned long *base, unsigned long *size, mtrr_type * type) { - unsigned long flags; unsigned char arr, ccr3, rcr, shift; + unsigned long flags; arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ - /* Save flags and disable interrupts */ local_irq_save(flags); ccr3 = getCx86(CX86_CCR3); setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ - ((unsigned char *) base)[3] = getCx86(arr); - ((unsigned char *) base)[2] = getCx86(arr + 1); - ((unsigned char *) base)[1] = getCx86(arr + 2); + ((unsigned char *)base)[3] = getCx86(arr); + ((unsigned char *)base)[2] = getCx86(arr + 1); + ((unsigned char *)base)[1] = getCx86(arr + 2); rcr = getCx86(CX86_RCR_BASE + reg); - setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ + setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ - /* Enable interrupts if it was enabled previously */ local_irq_restore(flags); + shift = ((unsigned char *) base)[1] & 0x0f; *base >>= PAGE_SHIFT; - /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7 + /* + * Power of two, at least 4K on ARR0-ARR6, 256K on ARR7 * Note: shift==0xf means 4G, this is unsupported. */ if (shift) @@ -76,17 +78,20 @@ cyrix_get_arr(unsigned int reg, unsigned long *base, } } +/* + * cyrix_get_free_region - get a free ARR. + * + * @base: the starting (base) address of the region. + * @size: the size (in bytes) of the region. + * + * Returns: the index of the region on success, else -1 on error. +*/ static int cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg) -/* [SUMMARY] Get a free ARR. - The starting (base) address of the region. - The size (in bytes) of the region. - [RETURNS] The index of the region on success, else -1 on error. -*/ { - int i; - mtrr_type ltype; unsigned long lbase, lsize; + mtrr_type ltype; + int i; switch (replace_reg) { case 7: @@ -107,14 +112,17 @@ cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg) cyrix_get_arr(7, &lbase, &lsize, <ype); if (lsize == 0) return 7; - /* Else try ARR0-ARR6 first */ + /* Else try ARR0-ARR6 first */ } else { for (i = 0; i < 7; i++) { cyrix_get_arr(i, &lbase, &lsize, <ype); if (lsize == 0) return i; } - /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */ + /* + * ARR0-ARR6 isn't free + * try ARR7 but its size must be at least 256K + */ cyrix_get_arr(i, &lbase, &lsize, <ype); if ((lsize == 0) && (size >= 0x40)) return i; @@ -122,21 +130,22 @@ cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg) return -ENOSPC; } -static u32 cr4 = 0; -static u32 ccr3; +static u32 cr4, ccr3; static void prepare_set(void) { u32 cr0; /* Save value of CR4 and clear Page Global Enable (bit 7) */ - if ( cpu_has_pge ) { + if (cpu_has_pge) { cr4 = read_cr4(); write_cr4(cr4 & ~X86_CR4_PGE); } - /* Disable and flush caches. Note that wbinvd flushes the TLBs as - a side-effect */ + /* + * Disable and flush caches. + * Note that wbinvd flushes the TLBs as a side-effect + */ cr0 = read_cr0() | X86_CR0_CD; wbinvd(); write_cr0(cr0); @@ -147,22 +156,21 @@ static void prepare_set(void) /* Cyrix ARRs - everything else was excluded at the top */ setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); - } static void post_set(void) { - /* Flush caches and TLBs */ + /* Flush caches and TLBs */ wbinvd(); /* Cyrix ARRs - everything else was excluded at the top */ setCx86(CX86_CCR3, ccr3); - - /* Enable caches */ + + /* Enable caches */ write_cr0(read_cr0() & 0xbfffffff); - /* Restore value of CR4 */ - if ( cpu_has_pge ) + /* Restore value of CR4 */ + if (cpu_has_pge) write_cr4(cr4); } @@ -178,7 +186,8 @@ static void cyrix_set_arr(unsigned int reg, unsigned long base, size >>= 6; size &= 0x7fff; /* make sure arr_size <= 14 */ - for (arr_size = 0; size; arr_size++, size >>= 1) ; + for (arr_size = 0; size; arr_size++, size >>= 1) + ; if (reg < 7) { switch (type) { @@ -215,18 +224,18 @@ static void cyrix_set_arr(unsigned int reg, unsigned long base, prepare_set(); base <<= PAGE_SHIFT; - setCx86(arr, ((unsigned char *) &base)[3]); - setCx86(arr + 1, ((unsigned char *) &base)[2]); - setCx86(arr + 2, (((unsigned char *) &base)[1]) | arr_size); + setCx86(arr + 0, ((unsigned char *)&base)[3]); + setCx86(arr + 1, ((unsigned char *)&base)[2]); + setCx86(arr + 2, (((unsigned char *)&base)[1]) | arr_size); setCx86(CX86_RCR_BASE + reg, arr_type); post_set(); } typedef struct { - unsigned long base; - unsigned long size; - mtrr_type type; + unsigned long base; + unsigned long size; + mtrr_type type; } arr_state_t; static arr_state_t arr_state[8] = { @@ -247,16 +256,17 @@ static void cyrix_set_all(void) setCx86(CX86_CCR0 + i, ccr_state[i]); for (; i < 7; i++) setCx86(CX86_CCR4 + i, ccr_state[i]); - for (i = 0; i < 8; i++) - cyrix_set_arr(i, arr_state[i].base, + + for (i = 0; i < 8; i++) { + cyrix_set_arr(i, arr_state[i].base, arr_state[i].size, arr_state[i].type); + } post_set(); } static struct mtrr_ops cyrix_mtrr_ops = { .vendor = X86_VENDOR_CYRIX, -// .init = cyrix_arr_init, .set_all = cyrix_set_all, .set = cyrix_set_arr, .get = cyrix_get_arr, @@ -270,5 +280,3 @@ int __init cyrix_init_mtrr(void) set_mtrr_ops(&cyrix_mtrr_ops); return 0; } - -//arch_initcall(cyrix_init_mtrr); -- cgit v0.10.2 From a1a499a39911fcfecbebaba1f38588088909f918 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sat, 4 Jul 2009 07:53:00 +0530 Subject: x86: Clean up mtrr/generic.c Fix following trivial style problems: ERROR: trailing whitespace X 4 WARNING: Use #include instead of WARNING: braces {} are not necessary for single statement blocks X 3 ERROR: "foo * bar" should be "foo *bar" WARNING: line over 80 characters X 6 ERROR: "foo * bar" should be "foo *bar" ERROR: spaces required around that '=' (ctx:VxO) ERROR: space required before that '-' (ctx:OxV) WARNING: suspect code indent for conditional statements (8, 12) ERROR: spaces required around that '=' (ctx:VxV) ERROR: do not initialise statics to 0 or NULL ERROR: space prohibited after that open parenthesis '(' X 2 ERROR: space prohibited before that close parenthesis ')' X 2 ERROR: trailing statements should be on next line ERROR: return is not a function, parentheses are not required Also use pr_debug and pr_warning where possible. arch/x86/kernel/cpu/mtrr/generic.o: text data bss dec hex filename 5652 77 4224 9953 26e1 generic.o.before 5652 77 4220 9949 26dd generic.o.after The md5 changed: b34d6c045f06daa4ed092b90cc760e8f generic.o.before.asm a490c6251cfd8442fbffecc0e09a573d generic.o.after.asm Because mtrr_state moved from data to bss, changing its offsets - and also because __LINE__ numbers changed. Suggested-by: Alan Cox Signed-off-by: Jaswinder Singh Rajput Cc: Andrew Morton Cc: Yinghai Lu LKML-Reference: <20090703164225.GA21447@elte.hu> [ Further cleanups to make the code more consistent ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index 0543f69..55da0c5 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c @@ -1,28 +1,34 @@ -/* This only handles 32bit MTRR on 32bit hosts. This is strictly wrong - because MTRRs can span upto 40 bits (36bits on most modern x86) */ +/* + * This only handles 32bit MTRR on 32bit hosts. This is strictly wrong + * because MTRRs can span upto 40 bits (36bits on most modern x86) + */ +#define DEBUG + +#include #include #include +#include #include -#include -#include -#include -#include -#include -#include + #include +#include #include +#include +#include +#include #include + #include "mtrr.h" struct fixed_range_block { - int base_msr; /* start address of an MTRR block */ - int ranges; /* number of MTRRs in this block */ + int base_msr; /* start address of an MTRR block */ + int ranges; /* number of MTRRs in this block */ }; static struct fixed_range_block fixed_range_blocks[] = { - { MSR_MTRRfix64K_00000, 1 }, /* one 64k MTRR */ - { MSR_MTRRfix16K_80000, 2 }, /* two 16k MTRRs */ - { MSR_MTRRfix4K_C0000, 8 }, /* eight 4k MTRRs */ + { MSR_MTRRfix64K_00000, 1 }, /* one 64k MTRR */ + { MSR_MTRRfix16K_80000, 2 }, /* two 16k MTRRs */ + { MSR_MTRRfix4K_C0000, 8 }, /* eight 4k MTRRs */ {} }; @@ -30,10 +36,10 @@ static unsigned long smp_changes_mask; static int mtrr_state_set; u64 mtrr_tom2; -struct mtrr_state_type mtrr_state = {}; +struct mtrr_state_type mtrr_state; EXPORT_SYMBOL_GPL(mtrr_state); -/** +/* * BIOS is expected to clear MtrrFixDramModEn bit, see for example * "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD * Opteron Processors" (26094 Rev. 3.30 February 2006), section @@ -104,9 +110,8 @@ u8 mtrr_type_lookup(u64 start, u64 end) * Look of multiple ranges matching this address and pick type * as per MTRR precedence */ - if (!(mtrr_state.enabled & 2)) { + if (!(mtrr_state.enabled & 2)) return mtrr_state.def_type; - } prev_match = 0xFF; for (i = 0; i < num_var_ranges; ++i) { @@ -125,9 +130,8 @@ u8 mtrr_type_lookup(u64 start, u64 end) if (start_state != end_state) return 0xFE; - if ((start & mask) != (base & mask)) { + if ((start & mask) != (base & mask)) continue; - } curr_match = mtrr_state.var_ranges[i].base_lo & 0xff; if (prev_match == 0xFF) { @@ -148,9 +152,8 @@ u8 mtrr_type_lookup(u64 start, u64 end) curr_match = MTRR_TYPE_WRTHROUGH; } - if (prev_match != curr_match) { + if (prev_match != curr_match) return MTRR_TYPE_UNCACHABLE; - } } if (mtrr_tom2) { @@ -164,7 +167,7 @@ u8 mtrr_type_lookup(u64 start, u64 end) return mtrr_state.def_type; } -/* Get the MSR pair relating to a var range */ +/* Get the MSR pair relating to a var range */ static void get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr) { @@ -172,7 +175,7 @@ get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr) rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); } -/* fill the MSR pair relating to a var range */ +/* Fill the MSR pair relating to a var range */ void fill_mtrr_var_range(unsigned int index, u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi) { @@ -186,10 +189,9 @@ void fill_mtrr_var_range(unsigned int index, vr[index].mask_hi = mask_hi; } -static void -get_fixed_ranges(mtrr_type * frs) +static void get_fixed_ranges(mtrr_type *frs) { - unsigned int *p = (unsigned int *) frs; + unsigned int *p = (unsigned int *)frs; int i; k8_check_syscfg_dram_mod_en(); @@ -217,22 +219,22 @@ static void __init print_fixed_last(void) if (!last_fixed_end) return; - printk(KERN_DEBUG " %05X-%05X %s\n", last_fixed_start, - last_fixed_end - 1, mtrr_attrib_to_str(last_fixed_type)); + pr_debug(" %05X-%05X %s\n", last_fixed_start, + last_fixed_end - 1, mtrr_attrib_to_str(last_fixed_type)); last_fixed_end = 0; } static void __init update_fixed_last(unsigned base, unsigned end, - mtrr_type type) + mtrr_type type) { last_fixed_start = base; last_fixed_end = end; last_fixed_type = type; } -static void __init print_fixed(unsigned base, unsigned step, - const mtrr_type *types) +static void __init +print_fixed(unsigned base, unsigned step, const mtrr_type *types) { unsigned i; @@ -259,54 +261,55 @@ static void __init print_mtrr_state(void) unsigned int i; int high_width; - printk(KERN_DEBUG "MTRR default type: %s\n", - mtrr_attrib_to_str(mtrr_state.def_type)); + pr_debug("MTRR default type: %s\n", + mtrr_attrib_to_str(mtrr_state.def_type)); if (mtrr_state.have_fixed) { - printk(KERN_DEBUG "MTRR fixed ranges %sabled:\n", - mtrr_state.enabled & 1 ? "en" : "dis"); + pr_debug("MTRR fixed ranges %sabled:\n", + mtrr_state.enabled & 1 ? "en" : "dis"); print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0); for (i = 0; i < 2; ++i) - print_fixed(0x80000 + i * 0x20000, 0x04000, mtrr_state.fixed_ranges + (i + 1) * 8); + print_fixed(0x80000 + i * 0x20000, 0x04000, + mtrr_state.fixed_ranges + (i + 1) * 8); for (i = 0; i < 8; ++i) - print_fixed(0xC0000 + i * 0x08000, 0x01000, mtrr_state.fixed_ranges + (i + 3) * 8); + print_fixed(0xC0000 + i * 0x08000, 0x01000, + mtrr_state.fixed_ranges + (i + 3) * 8); /* tail */ print_fixed_last(); } - printk(KERN_DEBUG "MTRR variable ranges %sabled:\n", - mtrr_state.enabled & 2 ? "en" : "dis"); + pr_debug("MTRR variable ranges %sabled:\n", + mtrr_state.enabled & 2 ? "en" : "dis"); if (size_or_mask & 0xffffffffUL) high_width = ffs(size_or_mask & 0xffffffffUL) - 1; else high_width = ffs(size_or_mask>>32) + 32 - 1; high_width = (high_width - (32 - PAGE_SHIFT) + 3) / 4; + for (i = 0; i < num_var_ranges; ++i) { if (mtrr_state.var_ranges[i].mask_lo & (1 << 11)) - printk(KERN_DEBUG " %u base %0*X%05X000 mask %0*X%05X000 %s\n", - i, - high_width, - mtrr_state.var_ranges[i].base_hi, - mtrr_state.var_ranges[i].base_lo >> 12, - high_width, - mtrr_state.var_ranges[i].mask_hi, - mtrr_state.var_ranges[i].mask_lo >> 12, - mtrr_attrib_to_str(mtrr_state.var_ranges[i].base_lo & 0xff)); + pr_debug(" %u base %0*X%05X000 mask %0*X%05X000 %s\n", + i, + high_width, + mtrr_state.var_ranges[i].base_hi, + mtrr_state.var_ranges[i].base_lo >> 12, + high_width, + mtrr_state.var_ranges[i].mask_hi, + mtrr_state.var_ranges[i].mask_lo >> 12, + mtrr_attrib_to_str(mtrr_state.var_ranges[i].base_lo & 0xff)); else - printk(KERN_DEBUG " %u disabled\n", i); - } - if (mtrr_tom2) { - printk(KERN_DEBUG "TOM2: %016llx aka %lldM\n", - mtrr_tom2, mtrr_tom2>>20); + pr_debug(" %u disabled\n", i); } + if (mtrr_tom2) + pr_debug("TOM2: %016llx aka %lldM\n", mtrr_tom2, mtrr_tom2>>20); } -/* Grab all of the MTRR state for this CPU into *state */ +/* Grab all of the MTRR state for this CPU into *state */ void __init get_mtrr_state(void) { - unsigned int i; struct mtrr_var_range *vrs; - unsigned lo, dummy; unsigned long flags; + unsigned lo, dummy; + unsigned int i; vrs = mtrr_state.var_ranges; @@ -324,6 +327,7 @@ void __init get_mtrr_state(void) if (amd_special_default_mtrr()) { unsigned low, high; + /* TOP_MEM2 */ rdmsr(MSR_K8_TOP_MEM2, low, high); mtrr_tom2 = high; @@ -344,10 +348,9 @@ void __init get_mtrr_state(void) post_set(); local_irq_restore(flags); - } -/* Some BIOS's are fucked and don't set all MTRRs the same! */ +/* Some BIOS's are messed up and don't set all MTRRs the same! */ void __init mtrr_state_warn(void) { unsigned long mask = smp_changes_mask; @@ -355,28 +358,33 @@ void __init mtrr_state_warn(void) if (!mask) return; if (mask & MTRR_CHANGE_MASK_FIXED) - printk(KERN_WARNING "mtrr: your CPUs had inconsistent fixed MTRR settings\n"); + pr_warning("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); if (mask & MTRR_CHANGE_MASK_VARIABLE) - printk(KERN_WARNING "mtrr: your CPUs had inconsistent variable MTRR settings\n"); + pr_warning("mtrr: your CPUs had inconsistent variable MTRR settings\n"); if (mask & MTRR_CHANGE_MASK_DEFTYPE) - printk(KERN_WARNING "mtrr: your CPUs had inconsistent MTRRdefType settings\n"); + pr_warning("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); + printk(KERN_INFO "mtrr: probably your BIOS does not setup all CPUs.\n"); printk(KERN_INFO "mtrr: corrected configuration.\n"); } -/* Doesn't attempt to pass an error out to MTRR users - because it's quite complicated in some cases and probably not - worth it because the best error handling is to ignore it. */ +/* + * Doesn't attempt to pass an error out to MTRR users + * because it's quite complicated in some cases and probably not + * worth it because the best error handling is to ignore it. + */ void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b) { - if (wrmsr_safe(msr, a, b) < 0) + if (wrmsr_safe(msr, a, b) < 0) { printk(KERN_ERR "MTRR: CPU %u: Writing MSR %x to %x:%x failed\n", smp_processor_id(), msr, a, b); + } } /** - * set_fixed_range - checks & updates a fixed-range MTRR if it differs from the value it should have + * set_fixed_range - checks & updates a fixed-range MTRR if it + * differs from the value it should have * @msr: MSR address of the MTTR which should be checked and updated * @changed: pointer which indicates whether the MTRR needed to be changed * @msrwords: pointer to the MSR values which the MSR should have @@ -401,20 +409,23 @@ static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords) * * Returns: The index of the region on success, else negative on error. */ -int generic_get_free_region(unsigned long base, unsigned long size, int replace_reg) +int +generic_get_free_region(unsigned long base, unsigned long size, int replace_reg) { - int i, max; - mtrr_type ltype; unsigned long lbase, lsize; + mtrr_type ltype; + int i, max; max = num_var_ranges; if (replace_reg >= 0 && replace_reg < max) return replace_reg; + for (i = 0; i < max; ++i) { mtrr_if->get(i, &lbase, &lsize, <ype); if (lsize == 0) return i; } + return -ENOSPC; } @@ -434,7 +445,7 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base, rdmsr(MTRRphysMask_MSR(reg), mask_lo, mask_hi); if ((mask_lo & 0x800) == 0) { - /* Invalid (i.e. free) range */ + /* Invalid (i.e. free) range */ *base = 0; *size = 0; *type = 0; @@ -471,27 +482,31 @@ out_put_cpu: } /** - * set_fixed_ranges - checks & updates the fixed-range MTRRs if they differ from the saved set + * set_fixed_ranges - checks & updates the fixed-range MTRRs if they + * differ from the saved set * @frs: pointer to fixed-range MTRR values, saved by get_fixed_ranges() */ -static int set_fixed_ranges(mtrr_type * frs) +static int set_fixed_ranges(mtrr_type *frs) { - unsigned long long *saved = (unsigned long long *) frs; + unsigned long long *saved = (unsigned long long *)frs; bool changed = false; - int block=-1, range; + int block = -1, range; k8_check_syscfg_dram_mod_en(); - while (fixed_range_blocks[++block].ranges) - for (range=0; range < fixed_range_blocks[block].ranges; range++) - set_fixed_range(fixed_range_blocks[block].base_msr + range, - &changed, (unsigned int *) saved++); + while (fixed_range_blocks[++block].ranges) { + for (range = 0; range < fixed_range_blocks[block].ranges; range++) + set_fixed_range(fixed_range_blocks[block].base_msr + range, + &changed, (unsigned int *)saved++); + } return changed; } -/* Set the MSR pair relating to a var range. Returns TRUE if - changes are made */ +/* + * Set the MSR pair relating to a var range. + * Returns true if changes are made. + */ static bool set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) { unsigned int lo, hi; @@ -501,6 +516,7 @@ static bool set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) || (vr->base_hi & (size_and_mask >> (32 - PAGE_SHIFT))) != (hi & (size_and_mask >> (32 - PAGE_SHIFT)))) { + mtrr_wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); changed = true; } @@ -526,21 +542,26 @@ static u32 deftype_lo, deftype_hi; */ static unsigned long set_mtrr_state(void) { - unsigned int i; unsigned long change_mask = 0; + unsigned int i; - for (i = 0; i < num_var_ranges; i++) + for (i = 0; i < num_var_ranges; i++) { if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i])) change_mask |= MTRR_CHANGE_MASK_VARIABLE; + } if (mtrr_state.have_fixed && set_fixed_ranges(mtrr_state.fixed_ranges)) change_mask |= MTRR_CHANGE_MASK_FIXED; - /* Set_mtrr_restore restores the old value of MTRRdefType, - so to set it we fiddle with the saved value */ + /* + * Set_mtrr_restore restores the old value of MTRRdefType, + * so to set it we fiddle with the saved value: + */ if ((deftype_lo & 0xff) != mtrr_state.def_type || ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) { - deftype_lo = (deftype_lo & ~0xcff) | mtrr_state.def_type | (mtrr_state.enabled << 10); + + deftype_lo = (deftype_lo & ~0xcff) | mtrr_state.def_type | + (mtrr_state.enabled << 10); change_mask |= MTRR_CHANGE_MASK_DEFTYPE; } @@ -548,33 +569,36 @@ static unsigned long set_mtrr_state(void) } -static unsigned long cr4 = 0; +static unsigned long cr4; static DEFINE_SPINLOCK(set_atomicity_lock); /* - * Since we are disabling the cache don't allow any interrupts - they - * would run extremely slow and would only increase the pain. The caller must - * ensure that local interrupts are disabled and are reenabled after post_set() - * has been called. + * Since we are disabling the cache don't allow any interrupts, + * they would run extremely slow and would only increase the pain. + * + * The caller must ensure that local interrupts are disabled and + * are reenabled after post_set() has been called. */ - static void prepare_set(void) __acquires(set_atomicity_lock) { unsigned long cr0; - /* Note that this is not ideal, since the cache is only flushed/disabled - for this CPU while the MTRRs are changed, but changing this requires - more invasive changes to the way the kernel boots */ + /* + * Note that this is not ideal + * since the cache is only flushed/disabled for this CPU while the + * MTRRs are changed, but changing this requires more invasive + * changes to the way the kernel boots + */ spin_lock(&set_atomicity_lock); - /* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */ + /* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */ cr0 = read_cr0() | X86_CR0_CD; write_cr0(cr0); wbinvd(); - /* Save value of CR4 and clear Page Global Enable (bit 7) */ - if ( cpu_has_pge ) { + /* Save value of CR4 and clear Page Global Enable (bit 7) */ + if (cpu_has_pge) { cr4 = read_cr4(); write_cr4(cr4 & ~X86_CR4_PGE); } @@ -582,26 +606,26 @@ static void prepare_set(void) __acquires(set_atomicity_lock) /* Flush all TLBs via a mov %cr3, %reg; mov %reg, %cr3 */ __flush_tlb(); - /* Save MTRR state */ + /* Save MTRR state */ rdmsr(MSR_MTRRdefType, deftype_lo, deftype_hi); - /* Disable MTRRs, and set the default type to uncached */ + /* Disable MTRRs, and set the default type to uncached */ mtrr_wrmsr(MSR_MTRRdefType, deftype_lo & ~0xcff, deftype_hi); } static void post_set(void) __releases(set_atomicity_lock) { - /* Flush TLBs (no need to flush caches - they are disabled) */ + /* Flush TLBs (no need to flush caches - they are disabled) */ __flush_tlb(); /* Intel (P6) standard MTRRs */ mtrr_wrmsr(MSR_MTRRdefType, deftype_lo, deftype_hi); - - /* Enable caches */ + + /* Enable caches */ write_cr0(read_cr0() & 0xbfffffff); - /* Restore value of CR4 */ - if ( cpu_has_pge ) + /* Restore value of CR4 */ + if (cpu_has_pge) write_cr4(cr4); spin_unlock(&set_atomicity_lock); } @@ -623,24 +647,27 @@ static void generic_set_all(void) post_set(); local_irq_restore(flags); - /* Use the atomic bitops to update the global mask */ + /* Use the atomic bitops to update the global mask */ for (count = 0; count < sizeof mask * 8; ++count) { if (mask & 0x01) set_bit(count, &smp_changes_mask); mask >>= 1; } - + } +/** + * generic_set_mtrr - set variable MTRR register on the local CPU. + * + * @reg: The register to set. + * @base: The base address of the region. + * @size: The size of the region. If this is 0 the region is disabled. + * @type: The type of the region. + * + * Returns nothing. + */ static void generic_set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type) -/* [SUMMARY] Set variable MTRR register on the local CPU. - The register to set. - The base address of the region. - The size of the region. If this is 0 the region is disabled. - The type of the region. - [RETURNS] Nothing. -*/ { unsigned long flags; struct mtrr_var_range *vr; @@ -651,8 +678,10 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base, prepare_set(); if (size == 0) { - /* The invalid bit is kept in the mask, so we simply clear the - relevant mask register to disable a range. */ + /* + * The invalid bit is kept in the mask, so we simply + * clear the relevant mask register to disable a range. + */ mtrr_wrmsr(MTRRphysMask_MSR(reg), 0, 0); memset(vr, 0, sizeof(struct mtrr_var_range)); } else { @@ -669,46 +698,50 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base, local_irq_restore(flags); } -int generic_validate_add_page(unsigned long base, unsigned long size, unsigned int type) +int generic_validate_add_page(unsigned long base, unsigned long size, + unsigned int type) { unsigned long lbase, last; - /* For Intel PPro stepping <= 7, must be 4 MiB aligned - and not touch 0x70000000->0x7003FFFF */ + /* + * For Intel PPro stepping <= 7 + * must be 4 MiB aligned and not touch 0x70000000 -> 0x7003FFFF + */ if (is_cpu(INTEL) && boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 1 && boot_cpu_data.x86_mask <= 7) { if (base & ((1 << (22 - PAGE_SHIFT)) - 1)) { - printk(KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base); + pr_warning("mtrr: base(0x%lx000) is not 4 MiB aligned\n", base); return -EINVAL; } if (!(base + size < 0x70000 || base > 0x7003F) && (type == MTRR_TYPE_WRCOMB || type == MTRR_TYPE_WRBACK)) { - printk(KERN_WARNING "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n"); + pr_warning("mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n"); return -EINVAL; } } - /* Check upper bits of base and last are equal and lower bits are 0 - for base and 1 for last */ + /* + * Check upper bits of base and last are equal and lower bits are 0 + * for base and 1 for last + */ last = base + size - 1; for (lbase = base; !(lbase & 1) && (last & 1); - lbase = lbase >> 1, last = last >> 1) ; + lbase = lbase >> 1, last = last >> 1) + ; if (lbase != last) { - printk(KERN_WARNING "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n", - base, size); + pr_warning("mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n", base, size); return -EINVAL; } return 0; } - static int generic_have_wrcomb(void) { unsigned long config, dummy; rdmsr(MSR_MTRRcap, config, dummy); - return (config & (1 << 10)); + return config & (1 << 10); } int positive_have_wrcomb(void) @@ -716,14 +749,15 @@ int positive_have_wrcomb(void) return 1; } -/* generic structure... +/* + * Generic structure... */ struct mtrr_ops generic_mtrr_ops = { - .use_intel_if = 1, - .set_all = generic_set_all, - .get = generic_get_mtrr, - .get_free_region = generic_get_free_region, - .set = generic_set_mtrr, - .validate_add_page = generic_validate_add_page, - .have_wrcomb = generic_have_wrcomb, + .use_intel_if = 1, + .set_all = generic_set_all, + .get = generic_get_mtrr, + .get_free_region = generic_get_free_region, + .set = generic_set_mtrr, + .validate_add_page = generic_validate_add_page, + .have_wrcomb = generic_have_wrcomb, }; -- cgit v0.10.2 From 26dc67eda19beafb7e5ef2770cec5b3ee5995a8e Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sat, 4 Jul 2009 07:53:40 +0530 Subject: x86: Clean up mtrr/if.c Fix: WARNING: Use #include instead of ERROR: trailing whitespace X 7 ERROR: trailing statements should be on next line X 3 WARNING: line over 80 characters X 5 ERROR: space required before the open parenthesis '(' arch/x86/kernel/cpu/mtrr/if.o: text data bss dec hex filename 2239 4 0 2243 8c3 if.o.before 2239 4 0 2243 8c3 if.o.after md5: 78d1f2aa4843ec6509c18e2dee54bc7f if.o.before.asm 78d1f2aa4843ec6509c18e2dee54bc7f if.o.after.asm Suggested-by: Alan Cox Signed-off-by: Jaswinder Singh Rajput Cc: Andrew Morton Cc: Yinghai Lu LKML-Reference: <20090703164225.GA21447@elte.hu> [ More cleanups to make the code more consistent. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c index fb73a52..08b6ea4 100644 --- a/arch/x86/kernel/cpu/mtrr/if.c +++ b/arch/x86/kernel/cpu/mtrr/if.c @@ -1,27 +1,28 @@ -#include -#include #include -#include -#include #include -#include +#include +#include +#include +#include +#include #define LINE_SIZE 80 #include + #include "mtrr.h" #define FILE_FCOUNT(f) (((struct seq_file *)((f)->private_data))->private) static const char *const mtrr_strings[MTRR_NUM_TYPES] = { - "uncachable", /* 0 */ - "write-combining", /* 1 */ - "?", /* 2 */ - "?", /* 3 */ - "write-through", /* 4 */ - "write-protect", /* 5 */ - "write-back", /* 6 */ + "uncachable", /* 0 */ + "write-combining", /* 1 */ + "?", /* 2 */ + "?", /* 3 */ + "write-through", /* 4 */ + "write-protect", /* 5 */ + "write-back", /* 6 */ }; const char *mtrr_attrib_to_str(int x) @@ -35,8 +36,8 @@ static int mtrr_file_add(unsigned long base, unsigned long size, unsigned int type, bool increment, struct file *file, int page) { + unsigned int *fcount = FILE_FCOUNT(file); int reg, max; - unsigned int *fcount = FILE_FCOUNT(file); max = num_var_ranges; if (fcount == NULL) { @@ -61,8 +62,8 @@ static int mtrr_file_del(unsigned long base, unsigned long size, struct file *file, int page) { - int reg; unsigned int *fcount = FILE_FCOUNT(file); + int reg; if (!page) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) @@ -81,13 +82,14 @@ mtrr_file_del(unsigned long base, unsigned long size, return reg; } -/* RED-PEN: seq_file can seek now. this is ignored. */ +/* + * seq_file can seek but we ignore it. + * + * Format of control line: + * "base=%Lx size=%Lx type=%s" or "disable=%d" + */ static ssize_t mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos) -/* Format of control line: - "base=%Lx size=%Lx type=%s" OR: - "disable=%d" -*/ { int i, err; unsigned long reg; @@ -100,15 +102,18 @@ mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos) return -EPERM; if (!len) return -EINVAL; + memset(line, 0, LINE_SIZE); if (len > LINE_SIZE) len = LINE_SIZE; if (copy_from_user(line, buf, len - 1)) return -EFAULT; + linelen = strlen(line); ptr = line + linelen - 1; if (linelen && *ptr == '\n') *ptr = '\0'; + if (!strncmp(line, "disable=", 8)) { reg = simple_strtoul(line + 8, &ptr, 0); err = mtrr_del_page(reg, 0, 0); @@ -116,28 +121,35 @@ mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos) return err; return len; } + if (strncmp(line, "base=", 5)) return -EINVAL; + base = simple_strtoull(line + 5, &ptr, 0); - for (; isspace(*ptr); ++ptr) ; + for (; isspace(*ptr); ++ptr) + ; + if (strncmp(ptr, "size=", 5)) return -EINVAL; + size = simple_strtoull(ptr + 5, &ptr, 0); if ((base & 0xfff) || (size & 0xfff)) return -EINVAL; - for (; isspace(*ptr); ++ptr) ; + for (; isspace(*ptr); ++ptr) + ; + if (strncmp(ptr, "type=", 5)) return -EINVAL; ptr += 5; - for (; isspace(*ptr); ++ptr) ; + for (; isspace(*ptr); ++ptr) + ; + for (i = 0; i < MTRR_NUM_TYPES; ++i) { if (strcmp(ptr, mtrr_strings[i])) continue; base >>= PAGE_SHIFT; size >>= PAGE_SHIFT; - err = - mtrr_add_page((unsigned long) base, (unsigned long) size, i, - true); + err = mtrr_add_page((unsigned long)base, (unsigned long)size, i, true); if (err < 0) return err; return len; @@ -181,7 +193,9 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) case MTRRIOC32_SET_PAGE_ENTRY: case MTRRIOC32_DEL_PAGE_ENTRY: case MTRRIOC32_KILL_PAGE_ENTRY: { - struct mtrr_sentry32 __user *s32 = (struct mtrr_sentry32 __user *)__arg; + struct mtrr_sentry32 __user *s32; + + s32 = (struct mtrr_sentry32 __user *)__arg; err = get_user(sentry.base, &s32->base); err |= get_user(sentry.size, &s32->size); err |= get_user(sentry.type, &s32->type); @@ -191,7 +205,9 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) } case MTRRIOC32_GET_ENTRY: case MTRRIOC32_GET_PAGE_ENTRY: { - struct mtrr_gentry32 __user *g32 = (struct mtrr_gentry32 __user *)__arg; + struct mtrr_gentry32 __user *g32; + + g32 = (struct mtrr_gentry32 __user *)__arg; err = get_user(gentry.regnum, &g32->regnum); err |= get_user(gentry.base, &g32->base); err |= get_user(gentry.size, &g32->size); @@ -314,7 +330,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) if (err) return err; - switch(cmd) { + switch (cmd) { case MTRRIOC_GET_ENTRY: case MTRRIOC_GET_PAGE_ENTRY: if (copy_to_user(arg, &gentry, sizeof gentry)) @@ -323,7 +339,9 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) #ifdef CONFIG_COMPAT case MTRRIOC32_GET_ENTRY: case MTRRIOC32_GET_PAGE_ENTRY: { - struct mtrr_gentry32 __user *g32 = (struct mtrr_gentry32 __user *)__arg; + struct mtrr_gentry32 __user *g32; + + g32 = (struct mtrr_gentry32 __user *)__arg; err = put_user(gentry.base, &g32->base); err |= put_user(gentry.size, &g32->size); err |= put_user(gentry.regnum, &g32->regnum); @@ -335,11 +353,10 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) return err; } -static int -mtrr_close(struct inode *ino, struct file *file) +static int mtrr_close(struct inode *ino, struct file *file) { - int i, max; unsigned int *fcount = FILE_FCOUNT(file); + int i, max; if (fcount != NULL) { max = num_var_ranges; @@ -359,22 +376,22 @@ static int mtrr_seq_show(struct seq_file *seq, void *offset); static int mtrr_open(struct inode *inode, struct file *file) { - if (!mtrr_if) + if (!mtrr_if) return -EIO; - if (!mtrr_if->get) - return -ENXIO; + if (!mtrr_if->get) + return -ENXIO; return single_open(file, mtrr_seq_show, NULL); } static const struct file_operations mtrr_fops = { - .owner = THIS_MODULE, - .open = mtrr_open, - .read = seq_read, - .llseek = seq_lseek, - .write = mtrr_write, - .unlocked_ioctl = mtrr_ioctl, - .compat_ioctl = mtrr_ioctl, - .release = mtrr_close, + .owner = THIS_MODULE, + .open = mtrr_open, + .read = seq_read, + .llseek = seq_lseek, + .write = mtrr_write, + .unlocked_ioctl = mtrr_ioctl, + .compat_ioctl = mtrr_ioctl, + .release = mtrr_close, }; static int mtrr_seq_show(struct seq_file *seq, void *offset) @@ -388,23 +405,24 @@ static int mtrr_seq_show(struct seq_file *seq, void *offset) max = num_var_ranges; for (i = 0; i < max; i++) { mtrr_if->get(i, &base, &size, &type); - if (size == 0) + if (size == 0) { mtrr_usage_table[i] = 0; - else { - if (size < (0x100000 >> PAGE_SHIFT)) { - /* less than 1MB */ - factor = 'K'; - size <<= PAGE_SHIFT - 10; - } else { - factor = 'M'; - size >>= 20 - PAGE_SHIFT; - } - /* RED-PEN: base can be > 32bit */ - len += seq_printf(seq, - "reg%02i: base=0x%06lx000 (%5luMB), size=%5lu%cB, count=%d: %s\n", - i, base, base >> (20 - PAGE_SHIFT), size, factor, - mtrr_usage_table[i], mtrr_attrib_to_str(type)); + continue; } + if (size < (0x100000 >> PAGE_SHIFT)) { + /* less than 1MB */ + factor = 'K'; + size <<= PAGE_SHIFT - 10; + } else { + factor = 'M'; + size >>= 20 - PAGE_SHIFT; + } + /* Base can be > 32bit */ + len += seq_printf(seq, "reg%02i: base=0x%06lx000 " + "(%5luMB), size=%5lu%cB, count=%d: %s\n", + i, base, base >> (20 - PAGE_SHIFT), size, + factor, mtrr_usage_table[i], + mtrr_attrib_to_str(type)); } return 0; } @@ -422,6 +440,5 @@ static int __init mtrr_if_init(void) proc_create("mtrr", S_IWUSR | S_IRUGO, NULL, &mtrr_fops); return 0; } - arch_initcall(mtrr_if_init); #endif /* CONFIG_PROC_FS */ -- cgit v0.10.2 From 3ec8dbcb09bb6df83993ca03e88cb85e3aaa8edb Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sat, 4 Jul 2009 07:54:16 +0530 Subject: x86: Clean up mtrr/mtrr.h Fix: ERROR: do not use C99 // comments ERROR: "foo * bar" should be "foo *bar" X 2 Suggested-by: Alan Cox Signed-off-by: Jaswinder Singh Rajput Cc: Andrew Morton Cc: Yinghai Lu LKML-Reference: <20090703164225.GA21447@elte.hu> [ More tidyups ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h index 7538b76..a501dee 100644 --- a/arch/x86/kernel/cpu/mtrr/mtrr.h +++ b/arch/x86/kernel/cpu/mtrr/mtrr.h @@ -1,5 +1,5 @@ /* - * local mtrr defines. + * local MTRR defines. */ #include @@ -14,13 +14,12 @@ extern unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES]; struct mtrr_ops { u32 vendor; u32 use_intel_if; -// void (*init)(void); void (*set)(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type); void (*set_all)(void); void (*get)(unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type * type); + unsigned long *size, mtrr_type *type); int (*get_free_region)(unsigned long base, unsigned long size, int replace_reg); int (*validate_add_page)(unsigned long base, unsigned long size, @@ -39,11 +38,11 @@ extern int positive_have_wrcomb(void); /* library functions for processor-specific routines */ struct set_mtrr_context { - unsigned long flags; - unsigned long cr4val; - u32 deftype_lo; - u32 deftype_hi; - u32 ccr3; + unsigned long flags; + unsigned long cr4val; + u32 deftype_lo; + u32 deftype_hi; + u32 ccr3; }; void set_mtrr_done(struct set_mtrr_context *ctxt); @@ -54,10 +53,10 @@ void fill_mtrr_var_range(unsigned int index, u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi); void get_mtrr_state(void); -extern void set_mtrr_ops(struct mtrr_ops * ops); +extern void set_mtrr_ops(struct mtrr_ops *ops); extern u64 size_or_mask, size_and_mask; -extern struct mtrr_ops * mtrr_if; +extern struct mtrr_ops *mtrr_if; #define is_cpu(vnd) (mtrr_if && mtrr_if->vendor == X86_VENDOR_##vnd) #define use_intel() (mtrr_if && mtrr_if->use_intel_if == 1) -- cgit v0.10.2 From 09b22c85d59dd935fdfa71655a443785e3f99c18 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sat, 4 Jul 2009 07:54:53 +0530 Subject: x86: Clean up mtrr/state.c Fix: WARNING: Use #include instead of WARNING: line over 80 characters X 4 arch/x86/kernel/cpu/mtrr/state.o: text data bss dec hex filename 864 0 0 864 360 state.o.before 864 0 0 864 360 state.o.after md5: c5c4364b9aeac74d70111e1e49667a2c state.o.before.asm c5c4364b9aeac74d70111e1e49667a2c state.o.after.asm Suggested-by: Alan Cox Signed-off-by: Jaswinder Singh Rajput Cc: Andrew Morton Cc: Yinghai Lu LKML-Reference: <20090703164225.GA21447@elte.hu> [ More cleanups ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mtrr/state.c b/arch/x86/kernel/cpu/mtrr/state.c index 1f5fb15..dfc80b4 100644 --- a/arch/x86/kernel/cpu/mtrr/state.c +++ b/arch/x86/kernel/cpu/mtrr/state.c @@ -1,24 +1,25 @@ -#include #include -#include -#include -#include +#include +#include + #include #include -#include "mtrr.h" +#include +#include +#include "mtrr.h" -/* Put the processor into a state where MTRRs can be safely set */ +/* Put the processor into a state where MTRRs can be safely set */ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt) { unsigned int cr0; - /* Disable interrupts locally */ + /* Disable interrupts locally */ local_irq_save(ctxt->flags); if (use_intel() || is_cpu(CYRIX)) { - /* Save value of CR4 and clear Page Global Enable (bit 7) */ + /* Save value of CR4 and clear Page Global Enable (bit 7) */ if (cpu_has_pge) { ctxt->cr4val = read_cr4(); write_cr4(ctxt->cr4val & ~X86_CR4_PGE); @@ -33,50 +34,61 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt) write_cr0(cr0); wbinvd(); - if (use_intel()) - /* Save MTRR state */ + if (use_intel()) { + /* Save MTRR state */ rdmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi); - else - /* Cyrix ARRs - everything else were excluded at the top */ + } else { + /* + * Cyrix ARRs - + * everything else were excluded at the top + */ ctxt->ccr3 = getCx86(CX86_CCR3); + } } } void set_mtrr_cache_disable(struct set_mtrr_context *ctxt) { - if (use_intel()) - /* Disable MTRRs, and set the default type to uncached */ + if (use_intel()) { + /* Disable MTRRs, and set the default type to uncached */ mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); - else if (is_cpu(CYRIX)) - /* Cyrix ARRs - everything else were excluded at the top */ - setCx86(CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10); + } else { + if (is_cpu(CYRIX)) { + /* Cyrix ARRs - everything else were excluded at the top */ + setCx86(CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10); + } + } } -/* Restore the processor after a set_mtrr_prepare */ +/* Restore the processor after a set_mtrr_prepare */ void set_mtrr_done(struct set_mtrr_context *ctxt) { if (use_intel() || is_cpu(CYRIX)) { - /* Flush caches and TLBs */ + /* Flush caches and TLBs */ wbinvd(); - /* Restore MTRRdefType */ - if (use_intel()) + /* Restore MTRRdefType */ + if (use_intel()) { /* Intel (P6) standard MTRRs */ - mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi); - else - /* Cyrix ARRs - everything else was excluded at the top */ + mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo, + ctxt->deftype_hi); + } else { + /* + * Cyrix ARRs - + * everything else was excluded at the top + */ setCx86(CX86_CCR3, ctxt->ccr3); + } - /* Enable caches */ + /* Enable caches */ write_cr0(read_cr0() & 0xbfffffff); - /* Restore value of CR4 */ + /* Restore value of CR4 */ if (cpu_has_pge) write_cr4(ctxt->cr4val); } - /* Re-enable interrupts locally (if enabled previously) */ + /* Re-enable interrupts locally (if enabled previously) */ local_irq_restore(ctxt->flags); } - -- cgit v0.10.2 From dbd51be026eaf84088fdee7fab9f38fa92eef26d Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sat, 4 Jul 2009 07:56:28 +0530 Subject: x86: Clean up mtrr/main.c Fix following trivial style problems: ERROR: trailing whitespace X 25 WARNING: Use #include instead of WARNING: Use #include instead of ERROR: do not initialise externals to 0 or NULL X 2 ERROR: "foo * bar" should be "foo *bar" X 5 ERROR: do not use assignment in if condition X 2 WARNING: line over 80 characters X 8 ERROR: return is not a function, parentheses are not required WARNING: braces {} are not necessary for any arm of this statement ERROR: space required before the open parenthesis '(' X 2 ERROR: open brace '{' following function declarations go on the next line ERROR: space required after that ',' (ctx:VxV) X 8 ERROR: space required before the open parenthesis '(' X 3 ERROR: else should follow close brace '}' WARNING: space prohibited between function name and open parenthesis '(' WARNING: EXPORT_SYMBOL(foo); should immediately follow its function/variable X 2 Also use pr_debug and pr_warning where possible. total: 50 errors, 14 warnings arch/x86/kernel/cpu/mtrr/main.o: text data bss dec hex filename 3668 116 4156 7940 1f04 main.o.before 3668 116 4156 7940 1f04 main.o.after md5: e01af2fd28deef77c8d01e71acfbd365 main.o.before.asm e01af2fd28deef77c8d01e71acfbd365 main.o.after.asm Suggested-by: Alan Cox Signed-off-by: Jaswinder Singh Rajput Cc: Andrew Morton Cc: Yinghai Lu LKML-Reference: <20090703164225.GA21447@elte.hu> Cc: Avi Kivity # Avi, please have a look at the kvm_para.h bit [ More cleanups ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index 8fc248b..7af0f88 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c @@ -25,43 +25,48 @@ Operating System Writer's Guide" (Intel document number 242692), section 11.11.7 - This was cleaned and made readable by Patrick Mochel - on 6-7 March 2002. - Source: Intel Architecture Software Developers Manual, Volume 3: + This was cleaned and made readable by Patrick Mochel + on 6-7 March 2002. + Source: Intel Architecture Software Developers Manual, Volume 3: System Programming Guide; Section 9.11. (1997 edition - PPro). */ +#define DEBUG + +#include /* FIXME: kvm_para.h needs this */ + +#include +#include #include +#include #include +#include +#include #include #include -#include -#include -#include +#include #include #include -#include -#include #include -#include + #include "mtrr.h" -u32 num_var_ranges = 0; +u32 num_var_ranges; unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES]; static DEFINE_MUTEX(mtrr_mutex); u64 size_or_mask, size_and_mask; -static struct mtrr_ops * mtrr_ops[X86_VENDOR_NUM] = {}; +static struct mtrr_ops *mtrr_ops[X86_VENDOR_NUM]; -struct mtrr_ops * mtrr_if = NULL; +struct mtrr_ops *mtrr_if; static void set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type); -void set_mtrr_ops(struct mtrr_ops * ops) +void set_mtrr_ops(struct mtrr_ops *ops) { if (ops->vendor && ops->vendor < X86_VENDOR_NUM) mtrr_ops[ops->vendor] = ops; @@ -72,30 +77,36 @@ static int have_wrcomb(void) { struct pci_dev *dev; u8 rev; - - if ((dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) { - /* ServerWorks LE chipsets < rev 6 have problems with write-combining - Don't allow it and leave room for other chipsets to be tagged */ + + dev = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, NULL); + if (dev != NULL) { + /* + * ServerWorks LE chipsets < rev 6 have problems with + * write-combining. Don't allow it and leave room for other + * chipsets to be tagged + */ if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS && dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) { pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); if (rev <= 5) { - printk(KERN_INFO "mtrr: Serverworks LE rev < 6 detected. Write-combining disabled.\n"); + pr_info("mtrr: Serverworks LE rev < 6 detected. Write-combining disabled.\n"); pci_dev_put(dev); return 0; } } - /* Intel 450NX errata # 23. Non ascending cacheline evictions to - write combining memory may resulting in data corruption */ + /* + * Intel 450NX errata # 23. Non ascending cacheline evictions to + * write combining memory may resulting in data corruption + */ if (dev->vendor == PCI_VENDOR_ID_INTEL && dev->device == PCI_DEVICE_ID_INTEL_82451NX) { - printk(KERN_INFO "mtrr: Intel 450NX MMC detected. Write-combining disabled.\n"); + pr_info("mtrr: Intel 450NX MMC detected. Write-combining disabled.\n"); pci_dev_put(dev); return 0; } pci_dev_put(dev); - } - return (mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0); + } + return mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0; } /* This function returns the number of variable MTRRs */ @@ -103,12 +114,13 @@ static void __init set_num_var_ranges(void) { unsigned long config = 0, dummy; - if (use_intel()) { + if (use_intel()) rdmsr(MSR_MTRRcap, config, dummy); - } else if (is_cpu(AMD)) + else if (is_cpu(AMD)) config = 2; else if (is_cpu(CYRIX) || is_cpu(CENTAUR)) config = 8; + num_var_ranges = config & 0xff; } @@ -130,10 +142,12 @@ struct set_mtrr_data { mtrr_type smp_type; }; +/** + * ipi_handler - Synchronisation handler. Executed by "other" CPUs. + * + * Returns nothing. + */ static void ipi_handler(void *info) -/* [SUMMARY] Synchronisation handler. Executed by "other" CPUs. - [RETURNS] Nothing. -*/ { #ifdef CONFIG_SMP struct set_mtrr_data *data = info; @@ -142,18 +156,19 @@ static void ipi_handler(void *info) local_irq_save(flags); atomic_dec(&data->count); - while(!atomic_read(&data->gate)) + while (!atomic_read(&data->gate)) cpu_relax(); /* The master has cleared me to execute */ - if (data->smp_reg != ~0U) - mtrr_if->set(data->smp_reg, data->smp_base, + if (data->smp_reg != ~0U) { + mtrr_if->set(data->smp_reg, data->smp_base, data->smp_size, data->smp_type); - else + } else { mtrr_if->set_all(); + } atomic_dec(&data->count); - while(atomic_read(&data->gate)) + while (atomic_read(&data->gate)) cpu_relax(); atomic_dec(&data->count); @@ -161,7 +176,8 @@ static void ipi_handler(void *info) #endif } -static inline int types_compatible(mtrr_type type1, mtrr_type type2) { +static inline int types_compatible(mtrr_type type1, mtrr_type type2) +{ return type1 == MTRR_TYPE_UNCACHABLE || type2 == MTRR_TYPE_UNCACHABLE || (type1 == MTRR_TYPE_WRTHROUGH && type2 == MTRR_TYPE_WRBACK) || @@ -176,10 +192,10 @@ static inline int types_compatible(mtrr_type type1, mtrr_type type2) { * @type: mtrr type * * This is kinda tricky, but fortunately, Intel spelled it out for us cleanly: - * + * * 1. Send IPI to do the following: * 2. Disable Interrupts - * 3. Wait for all procs to do so + * 3. Wait for all procs to do so * 4. Enter no-fill cache mode * 5. Flush caches * 6. Clear PGE bit @@ -189,26 +205,27 @@ static inline int types_compatible(mtrr_type type1, mtrr_type type2) { * 10. Enable all range registers * 11. Flush all TLBs and caches again * 12. Enter normal cache mode and reenable caching - * 13. Set PGE + * 13. Set PGE * 14. Wait for buddies to catch up * 15. Enable interrupts. - * + * * What does that mean for us? Well, first we set data.count to the number * of CPUs. As each CPU disables interrupts, it'll decrement it once. We wait * until it hits 0 and proceed. We set the data.gate flag and reset data.count. - * Meanwhile, they are waiting for that flag to be set. Once it's set, each - * CPU goes through the transition of updating MTRRs. The CPU vendors may each do it - * differently, so we call mtrr_if->set() callback and let them take care of it. - * When they're done, they again decrement data->count and wait for data.gate to - * be reset. - * When we finish, we wait for data.count to hit 0 and toggle the data.gate flag. + * Meanwhile, they are waiting for that flag to be set. Once it's set, each + * CPU goes through the transition of updating MTRRs. + * The CPU vendors may each do it differently, + * so we call mtrr_if->set() callback and let them take care of it. + * When they're done, they again decrement data->count and wait for data.gate + * to be reset. + * When we finish, we wait for data.count to hit 0 and toggle the data.gate flag * Everyone then enables interrupts and we all continue on. * * Note that the mechanism is the same for UP systems, too; all the SMP stuff * becomes nops. */ -static void set_mtrr(unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type) +static void +set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type) { struct set_mtrr_data data; unsigned long flags; @@ -218,121 +235,122 @@ static void set_mtrr(unsigned int reg, unsigned long base, data.smp_size = size; data.smp_type = type; atomic_set(&data.count, num_booting_cpus() - 1); - /* make sure data.count is visible before unleashing other CPUs */ + + /* Make sure data.count is visible before unleashing other CPUs */ smp_wmb(); - atomic_set(&data.gate,0); + atomic_set(&data.gate, 0); - /* Start the ball rolling on other CPUs */ + /* Start the ball rolling on other CPUs */ if (smp_call_function(ipi_handler, &data, 0) != 0) panic("mtrr: timed out waiting for other CPUs\n"); local_irq_save(flags); - while(atomic_read(&data.count)) + while (atomic_read(&data.count)) cpu_relax(); - /* ok, reset count and toggle gate */ + /* Ok, reset count and toggle gate */ atomic_set(&data.count, num_booting_cpus() - 1); smp_wmb(); - atomic_set(&data.gate,1); + atomic_set(&data.gate, 1); - /* do our MTRR business */ + /* Do our MTRR business */ - /* HACK! + /* + * HACK! * We use this same function to initialize the mtrrs on boot. * The state of the boot cpu's mtrrs has been saved, and we want - * to replicate across all the APs. + * to replicate across all the APs. * If we're doing that @reg is set to something special... */ - if (reg != ~0U) - mtrr_if->set(reg,base,size,type); + if (reg != ~0U) + mtrr_if->set(reg, base, size, type); - /* wait for the others */ - while(atomic_read(&data.count)) + /* Wait for the others */ + while (atomic_read(&data.count)) cpu_relax(); atomic_set(&data.count, num_booting_cpus() - 1); smp_wmb(); - atomic_set(&data.gate,0); + atomic_set(&data.gate, 0); /* * Wait here for everyone to have seen the gate change * So we're the last ones to touch 'data' */ - while(atomic_read(&data.count)) + while (atomic_read(&data.count)) cpu_relax(); local_irq_restore(flags); } /** - * mtrr_add_page - Add a memory type region - * @base: Physical base address of region in pages (in units of 4 kB!) - * @size: Physical size of region in pages (4 kB) - * @type: Type of MTRR desired - * @increment: If this is true do usage counting on the region + * mtrr_add_page - Add a memory type region + * @base: Physical base address of region in pages (in units of 4 kB!) + * @size: Physical size of region in pages (4 kB) + * @type: Type of MTRR desired + * @increment: If this is true do usage counting on the region * - * Memory type region registers control the caching on newer Intel and - * non Intel processors. This function allows drivers to request an - * MTRR is added. The details and hardware specifics of each processor's - * implementation are hidden from the caller, but nevertheless the - * caller should expect to need to provide a power of two size on an - * equivalent power of two boundary. + * Memory type region registers control the caching on newer Intel and + * non Intel processors. This function allows drivers to request an + * MTRR is added. The details and hardware specifics of each processor's + * implementation are hidden from the caller, but nevertheless the + * caller should expect to need to provide a power of two size on an + * equivalent power of two boundary. * - * If the region cannot be added either because all regions are in use - * or the CPU cannot support it a negative value is returned. On success - * the register number for this entry is returned, but should be treated - * as a cookie only. + * If the region cannot be added either because all regions are in use + * or the CPU cannot support it a negative value is returned. On success + * the register number for this entry is returned, but should be treated + * as a cookie only. * - * On a multiprocessor machine the changes are made to all processors. - * This is required on x86 by the Intel processors. + * On a multiprocessor machine the changes are made to all processors. + * This is required on x86 by the Intel processors. * - * The available types are + * The available types are * - * %MTRR_TYPE_UNCACHABLE - No caching + * %MTRR_TYPE_UNCACHABLE - No caching * - * %MTRR_TYPE_WRBACK - Write data back in bursts whenever + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever * - * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts + * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * - * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes + * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes * - * BUGS: Needs a quiet flag for the cases where drivers do not mind - * failures and do not wish system log messages to be sent. + * BUGS: Needs a quiet flag for the cases where drivers do not mind + * failures and do not wish system log messages to be sent. */ - -int mtrr_add_page(unsigned long base, unsigned long size, +int mtrr_add_page(unsigned long base, unsigned long size, unsigned int type, bool increment) { + unsigned long lbase, lsize; int i, replace, error; mtrr_type ltype; - unsigned long lbase, lsize; if (!mtrr_if) return -ENXIO; - - if ((error = mtrr_if->validate_add_page(base,size,type))) + + error = mtrr_if->validate_add_page(base, size, type); + if (error) return error; if (type >= MTRR_NUM_TYPES) { - printk(KERN_WARNING "mtrr: type: %u invalid\n", type); + pr_warning("mtrr: type: %u invalid\n", type); return -EINVAL; } - /* If the type is WC, check that this processor supports it */ + /* If the type is WC, check that this processor supports it */ if ((type == MTRR_TYPE_WRCOMB) && !have_wrcomb()) { - printk(KERN_WARNING - "mtrr: your processor doesn't support write-combining\n"); + pr_warning("mtrr: your processor doesn't support write-combining\n"); return -ENOSYS; } if (!size) { - printk(KERN_WARNING "mtrr: zero sized request\n"); + pr_warning("mtrr: zero sized request\n"); return -EINVAL; } if (base & size_or_mask || size & size_or_mask) { - printk(KERN_WARNING "mtrr: base or size exceeds the MTRR width\n"); + pr_warning("mtrr: base or size exceeds the MTRR width\n"); return -EINVAL; } @@ -341,36 +359,40 @@ int mtrr_add_page(unsigned long base, unsigned long size, /* No CPU hotplug when we change MTRR entries */ get_online_cpus(); - /* Search for existing MTRR */ + + /* Search for existing MTRR */ mutex_lock(&mtrr_mutex); for (i = 0; i < num_var_ranges; ++i) { mtrr_if->get(i, &lbase, &lsize, <ype); - if (!lsize || base > lbase + lsize - 1 || base + size - 1 < lbase) + if (!lsize || base > lbase + lsize - 1 || + base + size - 1 < lbase) continue; - /* At this point we know there is some kind of overlap/enclosure */ + /* + * At this point we know there is some kind of + * overlap/enclosure + */ if (base < lbase || base + size - 1 > lbase + lsize - 1) { - if (base <= lbase && base + size - 1 >= lbase + lsize - 1) { + if (base <= lbase && + base + size - 1 >= lbase + lsize - 1) { /* New region encloses an existing region */ if (type == ltype) { replace = replace == -1 ? i : -2; continue; - } - else if (types_compatible(type, ltype)) + } else if (types_compatible(type, ltype)) continue; } - printk(KERN_WARNING - "mtrr: 0x%lx000,0x%lx000 overlaps existing" - " 0x%lx000,0x%lx000\n", base, size, lbase, - lsize); + pr_warning("mtrr: 0x%lx000,0x%lx000 overlaps existing" + " 0x%lx000,0x%lx000\n", base, size, lbase, + lsize); goto out; } - /* New region is enclosed by an existing region */ + /* New region is enclosed by an existing region */ if (ltype != type) { if (types_compatible(type, ltype)) continue; - printk (KERN_WARNING "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", - base, size, mtrr_attrib_to_str(ltype), - mtrr_attrib_to_str(type)); + pr_warning("mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", + base, size, mtrr_attrib_to_str(ltype), + mtrr_attrib_to_str(type)); goto out; } if (increment) @@ -378,7 +400,7 @@ int mtrr_add_page(unsigned long base, unsigned long size, error = i; goto out; } - /* Search for an empty MTRR */ + /* Search for an empty MTRR */ i = mtrr_if->get_free_region(base, size, replace); if (i >= 0) { set_mtrr(i, base, size, type); @@ -393,8 +415,9 @@ int mtrr_add_page(unsigned long base, unsigned long size, mtrr_usage_table[replace] = 0; } } - } else - printk(KERN_INFO "mtrr: no more MTRRs available\n"); + } else { + pr_info("mtrr: no more MTRRs available\n"); + } error = i; out: mutex_unlock(&mtrr_mutex); @@ -405,10 +428,8 @@ int mtrr_add_page(unsigned long base, unsigned long size, static int mtrr_check(unsigned long base, unsigned long size) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { - printk(KERN_WARNING - "mtrr: size and base must be multiples of 4 kiB\n"); - printk(KERN_DEBUG - "mtrr: size: 0x%lx base: 0x%lx\n", size, base); + pr_warning("mtrr: size and base must be multiples of 4 kiB\n"); + pr_debug("mtrr: size: 0x%lx base: 0x%lx\n", size, base); dump_stack(); return -1; } @@ -416,66 +437,64 @@ static int mtrr_check(unsigned long base, unsigned long size) } /** - * mtrr_add - Add a memory type region - * @base: Physical base address of region - * @size: Physical size of region - * @type: Type of MTRR desired - * @increment: If this is true do usage counting on the region + * mtrr_add - Add a memory type region + * @base: Physical base address of region + * @size: Physical size of region + * @type: Type of MTRR desired + * @increment: If this is true do usage counting on the region * - * Memory type region registers control the caching on newer Intel and - * non Intel processors. This function allows drivers to request an - * MTRR is added. The details and hardware specifics of each processor's - * implementation are hidden from the caller, but nevertheless the - * caller should expect to need to provide a power of two size on an - * equivalent power of two boundary. + * Memory type region registers control the caching on newer Intel and + * non Intel processors. This function allows drivers to request an + * MTRR is added. The details and hardware specifics of each processor's + * implementation are hidden from the caller, but nevertheless the + * caller should expect to need to provide a power of two size on an + * equivalent power of two boundary. * - * If the region cannot be added either because all regions are in use - * or the CPU cannot support it a negative value is returned. On success - * the register number for this entry is returned, but should be treated - * as a cookie only. + * If the region cannot be added either because all regions are in use + * or the CPU cannot support it a negative value is returned. On success + * the register number for this entry is returned, but should be treated + * as a cookie only. * - * On a multiprocessor machine the changes are made to all processors. - * This is required on x86 by the Intel processors. + * On a multiprocessor machine the changes are made to all processors. + * This is required on x86 by the Intel processors. * - * The available types are + * The available types are * - * %MTRR_TYPE_UNCACHABLE - No caching + * %MTRR_TYPE_UNCACHABLE - No caching * - * %MTRR_TYPE_WRBACK - Write data back in bursts whenever + * %MTRR_TYPE_WRBACK - Write data back in bursts whenever * - * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts + * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * - * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes + * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes * - * BUGS: Needs a quiet flag for the cases where drivers do not mind - * failures and do not wish system log messages to be sent. + * BUGS: Needs a quiet flag for the cases where drivers do not mind + * failures and do not wish system log messages to be sent. */ - -int -mtrr_add(unsigned long base, unsigned long size, unsigned int type, - bool increment) +int mtrr_add(unsigned long base, unsigned long size, unsigned int type, + bool increment) { if (mtrr_check(base, size)) return -EINVAL; return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment); } +EXPORT_SYMBOL(mtrr_add); /** - * mtrr_del_page - delete a memory type region - * @reg: Register returned by mtrr_add - * @base: Physical base address - * @size: Size of region + * mtrr_del_page - delete a memory type region + * @reg: Register returned by mtrr_add + * @base: Physical base address + * @size: Size of region * - * If register is supplied then base and size are ignored. This is - * how drivers should call it. + * If register is supplied then base and size are ignored. This is + * how drivers should call it. * - * Releases an MTRR region. If the usage count drops to zero the - * register is freed and the region returns to default state. - * On success the register is returned, on failure a negative error - * code. + * Releases an MTRR region. If the usage count drops to zero the + * register is freed and the region returns to default state. + * On success the register is returned, on failure a negative error + * code. */ - int mtrr_del_page(int reg, unsigned long base, unsigned long size) { int i, max; @@ -500,22 +519,22 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) } } if (reg < 0) { - printk(KERN_DEBUG "mtrr: no MTRR for %lx000,%lx000 found\n", base, - size); + pr_debug("mtrr: no MTRR for %lx000,%lx000 found\n", + base, size); goto out; } } if (reg >= max) { - printk(KERN_WARNING "mtrr: register: %d too big\n", reg); + pr_warning("mtrr: register: %d too big\n", reg); goto out; } mtrr_if->get(reg, &lbase, &lsize, <ype); if (lsize < 1) { - printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg); + pr_warning("mtrr: MTRR %d not used\n", reg); goto out; } if (mtrr_usage_table[reg] < 1) { - printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg); + pr_warning("mtrr: reg: %d has count=0\n", reg); goto out; } if (--mtrr_usage_table[reg] < 1) @@ -526,33 +545,31 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) put_online_cpus(); return error; } + /** - * mtrr_del - delete a memory type region - * @reg: Register returned by mtrr_add - * @base: Physical base address - * @size: Size of region + * mtrr_del - delete a memory type region + * @reg: Register returned by mtrr_add + * @base: Physical base address + * @size: Size of region * - * If register is supplied then base and size are ignored. This is - * how drivers should call it. + * If register is supplied then base and size are ignored. This is + * how drivers should call it. * - * Releases an MTRR region. If the usage count drops to zero the - * register is freed and the region returns to default state. - * On success the register is returned, on failure a negative error - * code. + * Releases an MTRR region. If the usage count drops to zero the + * register is freed and the region returns to default state. + * On success the register is returned, on failure a negative error + * code. */ - -int -mtrr_del(int reg, unsigned long base, unsigned long size) +int mtrr_del(int reg, unsigned long base, unsigned long size) { if (mtrr_check(base, size)) return -EINVAL; return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); } - -EXPORT_SYMBOL(mtrr_add); EXPORT_SYMBOL(mtrr_del); -/* HACK ALERT! +/* + * HACK ALERT! * These should be called implicitly, but we can't yet until all the initcall * stuff is done... */ @@ -576,29 +593,28 @@ struct mtrr_value { static struct mtrr_value mtrr_value[MTRR_MAX_VAR_RANGES]; -static int mtrr_save(struct sys_device * sysdev, pm_message_t state) +static int mtrr_save(struct sys_device *sysdev, pm_message_t state) { int i; for (i = 0; i < num_var_ranges; i++) { - mtrr_if->get(i, - &mtrr_value[i].lbase, - &mtrr_value[i].lsize, - &mtrr_value[i].ltype); + mtrr_if->get(i, &mtrr_value[i].lbase, + &mtrr_value[i].lsize, + &mtrr_value[i].ltype); } return 0; } -static int mtrr_restore(struct sys_device * sysdev) +static int mtrr_restore(struct sys_device *sysdev) { int i; for (i = 0; i < num_var_ranges; i++) { - if (mtrr_value[i].lsize) - set_mtrr(i, - mtrr_value[i].lbase, - mtrr_value[i].lsize, - mtrr_value[i].ltype); + if (mtrr_value[i].lsize) { + set_mtrr(i, mtrr_value[i].lbase, + mtrr_value[i].lsize, + mtrr_value[i].ltype); + } } return 0; } @@ -615,26 +631,29 @@ int __initdata changed_by_mtrr_cleanup; /** * mtrr_bp_init - initialize mtrrs on the boot CPU * - * This needs to be called early; before any of the other CPUs are + * This needs to be called early; before any of the other CPUs are * initialized (i.e. before smp_init()). - * + * */ void __init mtrr_bp_init(void) { u32 phys_addr; + init_ifs(); phys_addr = 32; if (cpu_has_mtrr) { mtrr_if = &generic_mtrr_ops; - size_or_mask = 0xff000000; /* 36 bits */ + size_or_mask = 0xff000000; /* 36 bits */ size_and_mask = 0x00f00000; phys_addr = 36; - /* This is an AMD specific MSR, but we assume(hope?) that - Intel will implement it to when they extend the address - bus of the Xeon. */ + /* + * This is an AMD specific MSR, but we assume(hope?) that + * Intel will implement it to when they extend the address + * bus of the Xeon. + */ if (cpuid_eax(0x80000000) >= 0x80000008) { phys_addr = cpuid_eax(0x80000008) & 0xff; /* CPUID workaround for Intel 0F33/0F34 CPU */ @@ -649,9 +668,11 @@ void __init mtrr_bp_init(void) size_and_mask = ~size_or_mask & 0xfffff00000ULL; } else if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR && boot_cpu_data.x86 == 6) { - /* VIA C* family have Intel style MTRRs, but - don't support PAE */ - size_or_mask = 0xfff00000; /* 32 bits */ + /* + * VIA C* family have Intel style MTRRs, + * but don't support PAE + */ + size_or_mask = 0xfff00000; /* 32 bits */ size_and_mask = 0; phys_addr = 32; } @@ -694,7 +715,6 @@ void __init mtrr_bp_init(void) changed_by_mtrr_cleanup = 1; mtrr_if->set_all(); } - } } } @@ -706,12 +726,17 @@ void mtrr_ap_init(void) if (!mtrr_if || !use_intel()) return; /* - * Ideally we should hold mtrr_mutex here to avoid mtrr entries changed, - * but this routine will be called in cpu boot time, holding the lock - * breaks it. This routine is called in two cases: 1.very earily time - * of software resume, when there absolutely isn't mtrr entry changes; - * 2.cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug lock to - * prevent mtrr entry changes + * Ideally we should hold mtrr_mutex here to avoid mtrr entries + * changed, but this routine will be called in cpu boot time, + * holding the lock breaks it. + * + * This routine is called in two cases: + * + * 1. very earily time of software resume, when there absolutely + * isn't mtrr entry changes; + * + * 2. cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug + * lock to prevent mtrr entry changes */ local_irq_save(flags); @@ -732,19 +757,23 @@ static int __init mtrr_init_finialize(void) { if (!mtrr_if) return 0; + if (use_intel()) { if (!changed_by_mtrr_cleanup) mtrr_state_warn(); - } else { - /* The CPUs haven't MTRR and seem to not support SMP. They have - * specific drivers, we use a tricky method to support - * suspend/resume for them. - * TBD: is there any system with such CPU which supports - * suspend/resume? if no, we should remove the code. - */ - sysdev_driver_register(&cpu_sysdev_class, - &mtrr_sysdev_driver); + return 0; } + + /* + * The CPU has no MTRR and seems to not support SMP. They have + * specific drivers, we use a tricky method to support + * suspend/resume for them. + * + * TBD: is there any system with such CPU which supports + * suspend/resume? If no, we should remove the code. + */ + sysdev_driver_register(&cpu_sysdev_class, &mtrr_sysdev_driver); + return 0; } subsys_initcall(mtrr_init_finialize); -- cgit v0.10.2 From e3d0e69268dffb9676bf0800a60fb3573a723480 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 5 Jul 2009 09:44:11 +0200 Subject: x86: Further clean up of mtrr/generic.c Yinghai noticed that i defined BIOS_BUG_MSG but added no usage for it. The usage is to clean up this turd in generic.c: printk(KERN_WARNING "WARNING: BIOS bug: VAR MTRR %d " "contains strange UC entry under 1M, check " "with your system vendor!\n", i); Breaking printk lines in the middle looks ugly, is hard to read and breaks 'git grep'. Use the BIOS_BUG_MSG instead. Also complete the moving of structure definitions and variables to the top of the file. Reported-by: Yinghai Lu LKML-Reference: <20090703164225.GA21447@elte.hu> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c index b8aba81..315738c 100644 --- a/arch/x86/kernel/cpu/mtrr/cleanup.c +++ b/arch/x86/kernel/cpu/mtrr/cleanup.c @@ -34,14 +34,37 @@ #include "mtrr.h" -/* Should be related to MTRR_VAR_RANGES nums */ -#define RANGE_NUM 256 - struct res_range { unsigned long start; unsigned long end; }; +struct var_mtrr_range_state { + unsigned long base_pfn; + unsigned long size_pfn; + mtrr_type type; +}; + +struct var_mtrr_state { + unsigned long range_startk; + unsigned long range_sizek; + unsigned long chunk_sizek; + unsigned long gran_sizek; + unsigned int reg; +}; + +/* Should be related to MTRR_VAR_RANGES nums */ +#define RANGE_NUM 256 + +static struct res_range __initdata range[RANGE_NUM]; +static int __initdata nr_range; + +static struct var_mtrr_range_state __initdata range_state[RANGE_NUM]; + +static int __initdata debug_print; +#define Dprintk(x...) do { if (debug_print) printk(KERN_DEBUG x); } while (0) + + static int __init add_range(struct res_range *range, int nr_range, unsigned long start, unsigned long end) @@ -147,18 +170,6 @@ static int __init cmp_range(const void *x1, const void *x2) return start1 - start2; } -struct var_mtrr_range_state { - unsigned long base_pfn; - unsigned long size_pfn; - mtrr_type type; -}; - -static struct var_mtrr_range_state __initdata range_state[RANGE_NUM]; - -static int __initdata debug_print; -#define Dprintk(x...) do { if (debug_print) printk(KERN_DEBUG x); } while (0) - - #define BIOS_BUG_MSG KERN_WARNING \ "WARNING: BIOS bug: VAR MTRR %d contains strange UC entry under 1M, check with your system vendor!\n" @@ -200,9 +211,7 @@ x86_get_mtrr_mem_range(struct res_range *range, int nr_range, if (base < (1<<(20-PAGE_SHIFT)) && mtrr_state.have_fixed && (mtrr_state.enabled & 1)) { /* Var MTRR contains UC entry below 1M? Skip it: */ - printk(KERN_WARNING "WARNING: BIOS bug: VAR MTRR %d " - "contains strange UC entry under 1M, check " - "with your system vendor!\n", i); + printk(BIOS_BUG_MSG, i); if (base + size <= (1<<(20-PAGE_SHIFT))) continue; size -= (1<<(20-PAGE_SHIFT)) - base; @@ -244,9 +253,6 @@ x86_get_mtrr_mem_range(struct res_range *range, int nr_range, return nr_range; } -static struct res_range __initdata range[RANGE_NUM]; -static int __initdata nr_range; - #ifdef CONFIG_MTRR_SANITIZER static unsigned long __init sum_ranges(struct res_range *range, int nr_range) @@ -284,14 +290,6 @@ static int __init mtrr_cleanup_debug_setup(char *str) } early_param("mtrr_cleanup_debug", mtrr_cleanup_debug_setup); -struct var_mtrr_state { - unsigned long range_startk; - unsigned long range_sizek; - unsigned long chunk_sizek; - unsigned long gran_sizek; - unsigned int reg; -}; - static void __init set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, unsigned char type, unsigned int address_bits) -- cgit v0.10.2 From 69eb88825a7a562ee3564bdae20c35b0238307b0 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 4 Jul 2009 22:25:44 +0200 Subject: cmi8330: Add basic CMI8329 support Add basic support for CMI8329 cards. Makes PCM and OPL3 work. Does not break CMI8330 (tested). Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index d510c76..33e63fa 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -1,5 +1,5 @@ /* - * Driver for C-Media's CMI8330 soundcards. + * Driver for C-Media's CMI8330 and CMI8329 soundcards. * Copyright (c) by George Talusan * http://www.undergrad.math.uwaterloo.ca/~gstalusa * @@ -64,7 +64,7 @@ /* */ MODULE_AUTHOR("George Talusan "); -MODULE_DESCRIPTION("C-Media CMI8330"); +MODULE_DESCRIPTION("C-Media CMI8330/CMI8329"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}"); @@ -86,38 +86,38 @@ static long mpuport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard."); +MODULE_PARM_DESC(index, "Index value for CMI8330/CMI8329 soundcard."); module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for CMI8330 soundcard."); +MODULE_PARM_DESC(id, "ID string for CMI8330/CMI8329 soundcard."); module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable CMI8330 soundcard."); +MODULE_PARM_DESC(enable, "Enable CMI8330/CMI8329 soundcard."); #ifdef CONFIG_PNP module_param_array(isapnp, bool, NULL, 0444); MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard."); #endif module_param_array(sbport, long, NULL, 0444); -MODULE_PARM_DESC(sbport, "Port # for CMI8330 SB driver."); +MODULE_PARM_DESC(sbport, "Port # for CMI8330/CMI8329 SB driver."); module_param_array(sbirq, int, NULL, 0444); -MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330 SB driver."); +MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330/CMI8329 SB driver."); module_param_array(sbdma8, int, NULL, 0444); -MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330 SB driver."); +MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330/CMI8329 SB driver."); module_param_array(sbdma16, int, NULL, 0444); -MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330 SB driver."); +MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330/CMI8329 SB driver."); module_param_array(wssport, long, NULL, 0444); -MODULE_PARM_DESC(wssport, "Port # for CMI8330 WSS driver."); +MODULE_PARM_DESC(wssport, "Port # for CMI8330/CMI8329 WSS driver."); module_param_array(wssirq, int, NULL, 0444); -MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330 WSS driver."); +MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330/CMI8329 WSS driver."); module_param_array(wssdma, int, NULL, 0444); -MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver."); +MODULE_PARM_DESC(wssdma, "DMA for CMI8330/CMI8329 WSS driver."); module_param_array(fmport, long, NULL, 0444); -MODULE_PARM_DESC(fmport, "FM port # for CMI8330 driver."); +MODULE_PARM_DESC(fmport, "FM port # for CMI8330/CMI8329 driver."); module_param_array(mpuport, long, NULL, 0444); -MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330 driver."); +MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330/CMI8329 driver."); module_param_array(mpuirq, int, NULL, 0444); -MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330 MPU-401 port."); +MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330/CMI8329 MPU-401 port."); #ifdef CONFIG_PNP static int isa_registered; static int pnp_registered; @@ -156,6 +156,11 @@ static unsigned char snd_cmi8330_image[((CMI8330_CDINGAIN)-16) + 1] = typedef int (*snd_pcm_open_callback_t)(struct snd_pcm_substream *); +enum card_type { + CMI8330, + CMI8329 +}; + struct snd_cmi8330 { #ifdef CONFIG_PNP struct pnp_dev *cap; @@ -172,11 +177,14 @@ struct snd_cmi8330 { snd_pcm_open_callback_t open; void *private_data; /* sb or wss */ } streams[2]; + + enum card_type type; }; #ifdef CONFIG_PNP static struct pnp_card_device_id snd_cmi8330_pnpids[] = { + { .id = "CMI0001", .devs = { { "@X@0001" }, { "@@@0001" }, { "@H@0001" }, { "A@@0001" } } }, { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } }, { .id = "" } }; @@ -304,7 +312,7 @@ static int __devinit snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330 unsigned int idx; int err; - strcpy(card->mixername, "CMI8330/C3D"); + strcpy(card->mixername, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D"); for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) { err = snd_ctl_add(card, @@ -329,6 +337,9 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, struct pnp_dev *pdev; int err; + /* CMI8329 has a device with ID A@@0001, CMI8330 does not */ + acard->type = (id->devs[3].id[0]) ? CMI8329 : CMI8330; + acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL); if (acard->cap == NULL) return -EBUSY; @@ -345,34 +356,36 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, err = pnp_activate_dev(pdev); if (err < 0) { - snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n"); + snd_printk(KERN_ERR "AD1848 PnP configure failure\n"); return -EBUSY; } wssport[dev] = pnp_port_start(pdev, 0); wssdma[dev] = pnp_dma(pdev, 0); wssirq[dev] = pnp_irq(pdev, 0); - fmport[dev] = pnp_port_start(pdev, 1); + if (acard->type == CMI8330) + fmport[dev] = pnp_port_start(pdev, 1); /* allocate SB16 resources */ pdev = acard->play; err = pnp_activate_dev(pdev); if (err < 0) { - snd_printk(KERN_ERR "CMI8330/C3D (SB16) PnP configure failure\n"); + snd_printk(KERN_ERR "SB16 PnP configure failure\n"); return -EBUSY; } sbport[dev] = pnp_port_start(pdev, 0); sbdma8[dev] = pnp_dma(pdev, 0); sbdma16[dev] = pnp_dma(pdev, 1); sbirq[dev] = pnp_irq(pdev, 0); + if (acard->type == CMI8329) + fmport[dev] = pnp_port_start(pdev, 1); /* allocate MPU-401 resources */ pdev = acard->mpu; err = pnp_activate_dev(pdev); if (err < 0) { - snd_printk(KERN_ERR - "CMI8330/C3D (MPU-401) PnP configure failure\n"); + snd_printk(KERN_ERR "MPU-401 PnP configure failure\n"); return -EBUSY; } mpuport[dev] = pnp_port_start(pdev, 0); @@ -430,9 +443,9 @@ static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 * snd_cmi8330_capture_open }; - if ((err = snd_pcm_new(card, "CMI8330", 0, 1, 1, &pcm)) < 0) + if ((err = snd_pcm_new(card, (chip->type == CMI8329) ? "CMI8329" : "CMI8330", 0, 1, 1, &pcm)) < 0) return err; - strcpy(pcm->name, "CMI8330"); + strcpy(pcm->name, (chip->type == CMI8329) ? "CMI8329" : "CMI8330"); pcm->private_data = chip; /* SB16 */ @@ -527,11 +540,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) wssdma[dev], -1, WSS_HW_DETECT, 0, &acard->wss); if (err < 0) { - snd_printk(KERN_ERR PFX "(AD1848) device busy??\n"); + snd_printk(KERN_ERR PFX "AD1848 device busy??\n"); return err; } if (acard->wss->hardware != WSS_HW_CMI8330) { - snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n"); + snd_printk(KERN_ERR PFX "AD1848 not found during probe\n"); return -ENODEV; } @@ -541,11 +554,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) sbdma8[dev], sbdma16[dev], SB_HW_AUTO, &acard->sb)) < 0) { - snd_printk(KERN_ERR PFX "(SB16) device busy??\n"); + snd_printk(KERN_ERR PFX "SB16 device busy??\n"); return err; } if (acard->sb->hardware != SB_HW_16) { - snd_printk(KERN_ERR PFX "(SB16) not found during probe\n"); + snd_printk(KERN_ERR PFX "SB16 not found during probe\n"); return err; } @@ -585,8 +598,8 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) mpuport[dev]); } - strcpy(card->driver, "CMI8330/C3D"); - strcpy(card->shortname, "C-Media CMI8330/C3D"); + strcpy(card->driver, (acard->type == CMI8329) ? "CMI8329" : "CMI8330/C3D"); + strcpy(card->shortname, (acard->type == CMI8329) ? "C-Media CMI8329" : "C-Media CMI8330/C3D"); sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", card->shortname, acard->wss->port, -- cgit v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index f8cd450..2af7812 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 cb2e77a..6956df9 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -220,13 +220,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: */ #include -- cgit v0.10.2 From c71320d0c445e01555a86fa6523609db47eeaef6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 5 Jul 2009 00:22:34 +0200 Subject: genirq: Fix comment describing suspend_device_irqs() The kerneldoc comment describing suspend_device_irqs() is currently misleading, because generally the function doesn't really disable interrupt lines at the chip level. Replace it with a more accurate one. Signed-off-by: Rafael J. Wysocki LKML-Reference: <200907050022.35117.rjw@sisk.pl> Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index 638d8be..a0bb09e 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -15,10 +15,10 @@ /** * suspend_device_irqs - disable all currently enabled interrupt lines * - * During system-wide suspend or hibernation device interrupts need to be - * disabled at the chip level and this function is provided for this purpose. - * It disables all interrupt lines that are enabled at the moment and sets the - * IRQ_SUSPENDED flag for them. + * During system-wide suspend or hibernation device drivers need to be prevented + * from receiving interrupts and this function is provided for this purpose. + * It marks all interrupt lines in use, except for the timer ones, as disabled + * and sets the IRQ_SUSPENDED flag for each of them. */ void suspend_device_irqs(void) { -- cgit v0.10.2 From 35cf63583d8d81d8ac261e944db9eeb44a60692d Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Sat, 4 Jul 2009 19:29:51 -0700 Subject: ASoC: DaVinci: i2s, remove MOD_REG_BIT macro No functional changes. Rename variable w to something more meaningful. Remove code obfuscating macro MOD_REG_BIT. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index b1ea52f..bf5ec4b 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -85,14 +85,6 @@ #define DAVINCI_MCBSP_PCR_FSRM (1 << 10) #define DAVINCI_MCBSP_PCR_FSXM (1 << 11) -#define MOD_REG_BIT(val, mask, set) do { \ - if (set) { \ - val |= mask; \ - } else { \ - val &= ~mask; \ - } \ -} while (0) - enum { DAVINCI_MCBSP_WORD_8 = 0, DAVINCI_MCBSP_WORD_12, @@ -133,13 +125,13 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_platform *platform = socdev->card->platform; - u32 w; + u32 spcr; int ret; /* Start the sample generator and enable transmitter/receiver */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + spcr |= DAVINCI_MCBSP_SPCR_GRST; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* Stop the DMA to avoid data loss */ @@ -152,17 +144,17 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) } /* Enable the transmitter */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + spcr |= DAVINCI_MCBSP_SPCR_XRST; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); /* wait for any unexpected frame sync error to occur */ udelay(100); /* Disable the transmitter to clear any outstanding XSYNCERR */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + spcr &= ~DAVINCI_MCBSP_SPCR_XRST; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); /* Restart the DMA */ if (platform->pcm_ops->trigger) { @@ -172,40 +164,39 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) printk(KERN_DEBUG "Playback DMA start failed\n"); } /* Enable the transmitter */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + spcr |= DAVINCI_MCBSP_SPCR_XRST; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } else { /* Enable the reciever */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + spcr |= DAVINCI_MCBSP_SPCR_RRST; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } /* Start frame sync */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_FRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + spcr |= DAVINCI_MCBSP_SPCR_FRST; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; - u32 w; + u32 spcr; /* Reset transmitter/receiver and sample rate/frame sync generators */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST | - DAVINCI_MCBSP_SPCR_FRST, 0); + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + spcr &= ~(DAVINCI_MCBSP_SPCR_GRST | DAVINCI_MCBSP_SPCR_FRST); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0); + spcr &= ~DAVINCI_MCBSP_SPCR_XRST; else - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 0); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + spcr &= ~DAVINCI_MCBSP_SPCR_RRST; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } static int davinci_i2s_startup(struct snd_pcm_substream *substream, @@ -358,25 +349,26 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; struct snd_interval *i = NULL; int mcbsp_word_length; - u32 w; + unsigned int rcr, xcr, srgr; + u32 spcr; /* general line settings */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - w |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + spcr |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } else { - w |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + spcr |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); - w = DAVINCI_MCBSP_SRGR_FSGM; - MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1), 1); + srgr = DAVINCI_MCBSP_SRGR_FSGM; + srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); - MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w); + srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); /* Determine xfer data type */ switch (params_format(params)) { @@ -398,16 +390,16 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, } if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); + rcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); + rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); } else { - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); + xcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); + xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); } return 0; -- cgit v0.10.2 From c392bec716431d77e503345117a3e7ad3face677 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Sat, 4 Jul 2009 19:29:52 -0700 Subject: ASoC: DaVinci: i2s toggle clock to complete reset Add toggle_clock function to complete i2s reset earlier. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index bf5ec4b..dd44167 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -104,6 +104,7 @@ static struct davinci_pcm_dma_params davinci_i2s_pcm_in = { struct davinci_mcbsp_dev { void __iomem *base; + u32 pcr; struct clk *clk; struct davinci_pcm_dma_params *dma_params[2]; }; @@ -119,17 +120,34 @@ static inline u32 davinci_mcbsp_read_reg(struct davinci_mcbsp_dev *dev, int reg) return __raw_readl(dev->base + reg); } +static void toggle_clock(struct davinci_mcbsp_dev *dev, int playback) +{ + u32 m = playback ? DAVINCI_MCBSP_PCR_CLKXP : DAVINCI_MCBSP_PCR_CLKRP; + /* The clock needs to toggle to complete reset. + * So, fake it by toggling the clk polarity. + */ + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr ^ m); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr); +} + static void davinci_mcbsp_start(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_platform *platform = socdev->card->platform; + int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); u32 spcr; int ret; - - /* Start the sample generator and enable transmitter/receiver */ + u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST; spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + if (spcr & mask) { + /* start off disabled */ + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, + spcr & ~mask); + toggle_clock(dev, playback); + } + /* Start the sample generator and enable transmitter/receiver */ spcr |= DAVINCI_MCBSP_SPCR_GRST; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); @@ -155,6 +173,7 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); spcr &= ~DAVINCI_MCBSP_SPCR_XRST; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); + toggle_clock(dev, playback); /* Restart the DMA */ if (platform->pcm_ops->trigger) { @@ -188,15 +207,14 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; u32 spcr; + int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); /* Reset transmitter/receiver and sample rate/frame sync generators */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); spcr &= ~(DAVINCI_MCBSP_SPCR_GRST | DAVINCI_MCBSP_SPCR_FRST); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - spcr &= ~DAVINCI_MCBSP_SPCR_XRST; - else - spcr &= ~DAVINCI_MCBSP_SPCR_RRST; + spcr &= playback ? ~DAVINCI_MCBSP_SPCR_XRST : ~DAVINCI_MCBSP_SPCR_RRST; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); + toggle_clock(dev, playback); } static int davinci_i2s_startup(struct snd_pcm_substream *substream, @@ -334,6 +352,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); + dev->pcr = pcr; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); -- cgit v0.10.2 From f9af37cc632b59c39768329797443308ad6b4137 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Sat, 4 Jul 2009 19:29:53 -0700 Subject: ASoc: DaVinci: i2s, minor cleanup Add davinci_mcbsp_dev as argument to davinci_mcbsp_start and davinci_mcbsp_stop. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index dd44167..f7d7e4c 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -130,10 +130,10 @@ static void toggle_clock(struct davinci_mcbsp_dev *dev, int playback) davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr); } -static void davinci_mcbsp_start(struct snd_pcm_substream *substream) +static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev, + struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_platform *platform = socdev->card->platform; int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); @@ -202,12 +202,9 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } -static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) +static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; u32 spcr; - int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); /* Reset transmitter/receiver and sample rate/frame sync generators */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); @@ -427,18 +424,21 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; int ret = 0; + int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - davinci_mcbsp_start(substream); + davinci_mcbsp_start(dev, substream); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - davinci_mcbsp_stop(substream); + davinci_mcbsp_stop(dev, playback); break; default: ret = -EINVAL; -- cgit v0.10.2 From eba575c30b93755dc0ee5e9adbb5b06d3289b62a Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Sat, 4 Jul 2009 19:29:54 -0700 Subject: ASoC: DaVinci: i2s cleanup Move variable declaration closer to use. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index f7d7e4c..73a0fd8 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -138,7 +138,6 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev, struct snd_soc_platform *platform = socdev->card->platform; int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); u32 spcr; - int ret; u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST; spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); if (spcr & mask) { @@ -155,7 +154,7 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev, /* Stop the DMA to avoid data loss */ /* while the transmitter is out of reset to handle XSYNCERR */ if (platform->pcm_ops->trigger) { - ret = platform->pcm_ops->trigger(substream, + int ret = platform->pcm_ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); if (ret < 0) printk(KERN_DEBUG "Playback DMA stop failed\n"); @@ -177,7 +176,7 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev, /* Restart the DMA */ if (platform->pcm_ops->trigger) { - ret = platform->pcm_ops->trigger(substream, + int ret = platform->pcm_ops->trigger(substream, SNDRV_PCM_TRIGGER_START); if (ret < 0) printk(KERN_DEBUG "Playback DMA start failed\n"); -- cgit v0.10.2 From 1bef449989d0866a7db366a8153135cfa3d5cad9 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Sat, 4 Jul 2009 19:29:55 -0700 Subject: ASoC: DaVinci: i2s, only start sample generator if needed Only start sample generator if needed, and more cleanup on davinci_mcbsp_start. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 73a0fd8..4260965 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -146,11 +146,14 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev, spcr & ~mask); toggle_clock(dev, playback); } - /* Start the sample generator and enable transmitter/receiver */ - spcr |= DAVINCI_MCBSP_SPCR_GRST; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); + if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM | + DAVINCI_MCBSP_PCR_CLKXM | DAVINCI_MCBSP_PCR_CLKRM)) { + /* Start the sample generator */ + spcr |= DAVINCI_MCBSP_SPCR_GRST; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); + } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (playback) { /* Stop the DMA to avoid data loss */ /* while the transmitter is out of reset to handle XSYNCERR */ if (platform->pcm_ops->trigger) { @@ -181,23 +184,16 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev, if (ret < 0) printk(KERN_DEBUG "Playback DMA start failed\n"); } - /* Enable the transmitter */ - spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - spcr |= DAVINCI_MCBSP_SPCR_XRST; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); - - } else { - - /* Enable the reciever */ - spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - spcr |= DAVINCI_MCBSP_SPCR_RRST; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } - - /* Start frame sync */ + /* Enable transmitter or receiver */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - spcr |= DAVINCI_MCBSP_SPCR_FRST; + spcr |= mask; + + if (dev->pcr & (DAVINCI_MCBSP_PCR_FSXM | DAVINCI_MCBSP_PCR_FSRM)) { + /* Start frame sync */ + spcr |= DAVINCI_MCBSP_SPCR_FRST; + } davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } -- cgit v0.10.2 From 9333b594a08f2b2d8b7d96260164817acdbc5cab Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Sat, 4 Jul 2009 19:29:56 -0700 Subject: ASoC: DaVinci: i2s, minor cleanup of davinci_i2s_startup Save a few lines of code. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 4260965..5b31b56 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -210,14 +210,10 @@ static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback) } static int davinci_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *cpu_dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; - + struct davinci_mcbsp_dev *dev = cpu_dai->private_data; cpu_dai->dma_data = dev->dma_params[substream->stream]; - return 0; } -- cgit v0.10.2 From f5cfa954e6812c09e3a4b89e8009b22285b860a3 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Sat, 4 Jul 2009 19:29:57 -0700 Subject: ASoC: DaVinci: i2s, fix mcbsp_word_length update Code previously just "ors" in this field without clearing first. Fix, by never reading this register. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 5b31b56..6fa1b6a 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -63,6 +63,7 @@ #define DAVINCI_MCBSP_RCR_RWDLEN1(v) ((v) << 5) #define DAVINCI_MCBSP_RCR_RFRLEN1(v) ((v) << 8) #define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16) +#define DAVINCI_MCBSP_RCR_RFIG (1 << 18) #define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21) #define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5) @@ -104,6 +105,9 @@ static struct davinci_pcm_dma_params davinci_i2s_pcm_in = { struct davinci_mcbsp_dev { void __iomem *base; +#define MOD_DSP_A 0 +#define MOD_DSP_B 1 + int mode; u32 pcr; struct clk *clk; struct davinci_pcm_dma_params *dma_params[2]; @@ -225,12 +229,11 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, struct davinci_mcbsp_dev *dev = cpu_dai->private_data; unsigned int pcr; unsigned int srgr; - unsigned int rcr; - unsigned int xcr; srgr = DAVINCI_MCBSP_SRGR_FSGM | DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); + /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* cpu is master */ @@ -255,11 +258,8 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } - rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1); - xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1); + /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_DSP_B: - break; case SND_SOC_DAIFMT_I2S: /* Davinci doesn't support TRUE I2S, but some codecs will have * the left and right channels contiguous. This allows @@ -279,8 +279,10 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, */ fmt ^= SND_SOC_DAIFMT_NB_IF; case SND_SOC_DAIFMT_DSP_A: - rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); - xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); + dev->mode = MOD_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + dev->mode = MOD_DSP_B; break; default: printk(KERN_ERR "%s:bad format\n", __func__); @@ -342,8 +344,6 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); dev->pcr = pcr; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); return 0; } @@ -377,6 +377,15 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); + rcr = DAVINCI_MCBSP_RCR_RFIG; + xcr = DAVINCI_MCBSP_XCR_XFIG; + if (dev->mode == MOD_DSP_B) { + rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0); + xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0); + } else { + rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); + xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); + } /* Determine xfer data type */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: @@ -396,19 +405,18 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - rcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); - rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); + rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1); + xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1); - } else { - xcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); - xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); + rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); + xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length); - } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); + else + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); return 0; } -- cgit v0.10.2 From af0adf3e81dbcf782388b8a7d0d7094ef5e70f50 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Sat, 4 Jul 2009 19:29:59 -0700 Subject: ASoC: DaVinci: i2s, add davinci_i2s_prepare and shutdown If the codec is master then prepare should call mcbsp_start, not trigger. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 6fa1b6a..88ccef7 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -420,6 +420,20 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } +static int davinci_i2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; + int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + davinci_mcbsp_stop(dev, playback); + if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) { + /* codec is master */ + davinci_mcbsp_start(dev, substream); + } + return 0; +} + static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -427,6 +441,8 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; int ret = 0; int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) + return 0; /* return if codec is master */ switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -442,10 +458,18 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, default: ret = -EINVAL; } - return ret; } +static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; + int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + davinci_mcbsp_stop(dev, playback); +} + static int davinci_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { @@ -531,6 +555,8 @@ static void davinci_i2s_remove(struct platform_device *pdev, static struct snd_soc_dai_ops davinci_i2s_dai_ops = { .startup = davinci_i2s_startup, + .shutdown = davinci_i2s_shutdown, + .prepare = davinci_i2s_prepare, .trigger = davinci_i2s_trigger, .hw_params = davinci_i2s_hw_params, .set_fmt = davinci_i2s_set_dai_fmt, -- cgit v0.10.2 From 096e49d5e6f7bd93395e7ddf7e0239e1644d0505 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 5 Jul 2009 15:12:22 +0100 Subject: ASoC: Add CODEC volatile register operation Add a volatile_register() operation to the CODEC structure providing a standard operation to query if a register is volatile. This will be used to factor out the register cache I/O operations for the CODECs. Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index e6704c0..94fcc65 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -191,6 +191,7 @@ int snd_soc_register_platform(struct snd_soc_platform *platform); void snd_soc_unregister_platform(struct snd_soc_platform *platform); int snd_soc_register_codec(struct snd_soc_codec *codec); void snd_soc_unregister_codec(struct snd_soc_codec *codec); +int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg); #ifdef CONFIG_PM int snd_soc_suspend_device(struct device *dev); @@ -361,6 +362,7 @@ struct snd_soc_codec { int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); int (*display_register)(struct snd_soc_codec *, char *, size_t, unsigned int); + int (*volatile_register)(unsigned int); hw_write_t hw_write; hw_read_t hw_read; void *reg_cache; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index dfc03c0..8bf49a4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1125,6 +1125,23 @@ static int soc_new_pcm(struct snd_soc_device *socdev, return ret; } +/** + * snd_soc_codec_volatile_register: Report if a register is volatile. + * + * @codec: CODEC to query. + * @reg: Register to query. + * + * Boolean function indiciating if a CODEC register is volatile. + */ +int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg) +{ + if (codec->volatile_register) + return codec->volatile_register(reg); + else + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register); + /* codec register dump */ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) { -- cgit v0.10.2 From fe5422fc4ac221910083e603eb2a873280a9bd37 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 5 Jul 2009 15:18:01 +0100 Subject: ASoC: Fix leaks in WM8731 probe error handling Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index d7f4788..dfbc1bb 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -560,7 +560,8 @@ static int wm8731_register(struct wm8731_priv *wm8731) if (wm8731_codec) { dev_err(codec->dev, "Another WM8731 is registered\n"); - return -EINVAL; + ret = -EINVAL; + goto err; } mutex_init(&codec->mutex); @@ -583,8 +584,8 @@ static int wm8731_register(struct wm8731_priv *wm8731) ret = wm8731_reset(codec); if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset\n"); - return ret; + dev_err(codec->dev, "Failed to issue reset: %d\n", ret); + goto err; } wm8731_dai.dev = codec->dev; @@ -610,17 +611,23 @@ static int wm8731_register(struct wm8731_priv *wm8731) ret = snd_soc_register_codec(codec); if (ret != 0) { dev_err(codec->dev, "Failed to register codec: %d\n", ret); - return ret; + goto err; } ret = snd_soc_register_dai(&wm8731_dai); if (ret != 0) { dev_err(codec->dev, "Failed to register DAI: %d\n", ret); snd_soc_unregister_codec(codec); - return ret; + goto err_codec; } return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(wm8731); + return ret; } static void wm8731_unregister(struct wm8731_priv *wm8731) -- cgit v0.10.2 From 1a01417e85846e42e939a345a294e8ae2287cc1f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 5 Jul 2009 15:47:03 +0100 Subject: ASoC: Fix WM8960 leaks on probe failure Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index b7894d6..d1769e6 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -810,7 +810,8 @@ static int wm8960_register(struct wm8960_priv *wm8960) if (wm8960_codec) { dev_err(codec->dev, "Another WM8960 is registered\n"); - return -EINVAL; + ret = -EINVAL; + goto err; } if (!pdata) { @@ -843,7 +844,7 @@ static int wm8960_register(struct wm8960_priv *wm8960) ret = wm8960_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset\n"); - return ret; + goto err; } wm8960_dai.dev = codec->dev; @@ -877,17 +878,22 @@ static int wm8960_register(struct wm8960_priv *wm8960) ret = snd_soc_register_codec(codec); if (ret != 0) { dev_err(codec->dev, "Failed to register codec: %d\n", ret); - return ret; + goto err; } ret = snd_soc_register_dai(&wm8960_dai); if (ret != 0) { dev_err(codec->dev, "Failed to register DAI: %d\n", ret); - snd_soc_unregister_codec(codec); - return ret; + goto err_codec; } return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(wm8960); + return ret; } static void wm8960_unregister(struct wm8960_priv *wm8960) -- cgit v0.10.2 From 5420f30723122012c7bb868a55ff21c7d383b68e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 5 Jul 2009 16:29:39 +0100 Subject: ASoC: Fix leaks in WM8988 registration error handling Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 03fac6a..6f15acd 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -902,7 +902,7 @@ static int wm8988_register(struct wm8988_priv *wm8988) ret = wm8988_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset\n"); - return ret; + goto err; } /* set the update bits (we always update left then right) */ @@ -926,18 +926,20 @@ static int wm8988_register(struct wm8988_priv *wm8988) ret = snd_soc_register_codec(codec); if (ret != 0) { dev_err(codec->dev, "Failed to register codec: %d\n", ret); - return ret; + goto err; } ret = snd_soc_register_dai(&wm8988_dai); if (ret != 0) { dev_err(codec->dev, "Failed to register DAI: %d\n", ret); snd_soc_unregister_codec(codec); - return ret; + goto err_codec; } return 0; +err_codec: + snd_soc_unregister_codec(codec); err: kfree(wm8988); return ret; -- cgit v0.10.2 From 17a52fd60a0a0e617ed94aadb1b19751a8fa219e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 5 Jul 2009 17:24:50 +0100 Subject: ASoC: Begin to factor out register cache I/O functions A lot of CODECs share the same register data formats and therefore replicate the code to manage access to and caching of the register map. In order to reduce code duplication centralised versions of this code will be introduced with drivers able to configure the use of the common code by calling the new snd_soc_codec_set_cache_io() API call during startup. As an initial user the 7 bit address/9 bit data format used by many Wolfson devices is supported for write only CODECs and the drivers with straightforward register cache implementations are converted to use it. Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 94fcc65..27409dd 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -192,6 +192,8 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform); int snd_soc_register_codec(struct snd_soc_codec *codec); void snd_soc_unregister_codec(struct snd_soc_codec *codec); int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg); +int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, + int addr_bits, int data_bits); #ifdef CONFIG_PM int snd_soc_suspend_device(struct device *dev); diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 6f1e28d..4eaf48a 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,4 +1,4 @@ -snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o +snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index c8b8dba..7a169bf 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -58,55 +58,7 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { #define WM8510_POWER1_BIASEN 0x08 #define WM8510_POWER1_BUFIOEN 0x10 -/* - * read wm8510 register cache - */ -static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg == WM8510_RESET) - return 0; - if (reg >= WM8510_CACHEREGNUM) - return -1; - return cache[reg]; -} - -/* - * write wm8510 register cache - */ -static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg >= WM8510_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * write to the WM8510 register space - */ -static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8510 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8510_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define wm8510_reset(c) wm8510_write(c, WM8510_RESET, 0) +#define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0) static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; @@ -327,27 +279,27 @@ static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, if (freq_in == 0 || freq_out == 0) { /* Clock CODEC directly from MCLK */ - reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); - wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff); + reg = snd_soc_read(codec, WM8510_CLOCK); + snd_soc_write(codec, WM8510_CLOCK, reg & 0x0ff); /* Turn off PLL */ - reg = wm8510_read_reg_cache(codec, WM8510_POWER1); - wm8510_write(codec, WM8510_POWER1, reg & 0x1df); + reg = snd_soc_read(codec, WM8510_POWER1); + snd_soc_write(codec, WM8510_POWER1, reg & 0x1df); return 0; } pll_factors(freq_out*4, freq_in); - wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); - wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); - wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); - wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); - reg = wm8510_read_reg_cache(codec, WM8510_POWER1); - wm8510_write(codec, WM8510_POWER1, reg | 0x020); + snd_soc_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); + snd_soc_write(codec, WM8510_PLLK1, pll_div.k >> 18); + snd_soc_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); + snd_soc_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); + reg = snd_soc_read(codec, WM8510_POWER1); + snd_soc_write(codec, WM8510_POWER1, reg | 0x020); /* Run CODEC from PLL instead of MCLK */ - reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); - wm8510_write(codec, WM8510_CLOCK, reg | 0x100); + reg = snd_soc_read(codec, WM8510_CLOCK); + snd_soc_write(codec, WM8510_CLOCK, reg | 0x100); return 0; } @@ -363,24 +315,24 @@ static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8510_OPCLKDIV: - reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf; - wm8510_write(codec, WM8510_GPIO, reg | div); + reg = snd_soc_read(codec, WM8510_GPIO) & 0x1cf; + snd_soc_write(codec, WM8510_GPIO, reg | div); break; case WM8510_MCLKDIV: - reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x11f; - wm8510_write(codec, WM8510_CLOCK, reg | div); + reg = snd_soc_read(codec, WM8510_CLOCK) & 0x11f; + snd_soc_write(codec, WM8510_CLOCK, reg | div); break; case WM8510_ADCCLK: - reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7; - wm8510_write(codec, WM8510_ADC, reg | div); + reg = snd_soc_read(codec, WM8510_ADC) & 0x1f7; + snd_soc_write(codec, WM8510_ADC, reg | div); break; case WM8510_DACCLK: - reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7; - wm8510_write(codec, WM8510_DAC, reg | div); + reg = snd_soc_read(codec, WM8510_DAC) & 0x1f7; + snd_soc_write(codec, WM8510_DAC, reg | div); break; case WM8510_BCLKDIV: - reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3; - wm8510_write(codec, WM8510_CLOCK, reg | div); + reg = snd_soc_read(codec, WM8510_CLOCK) & 0x1e3; + snd_soc_write(codec, WM8510_CLOCK, reg | div); break; default: return -EINVAL; @@ -394,7 +346,7 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; u16 iface = 0; - u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe; + u16 clk = snd_soc_read(codec, WM8510_CLOCK) & 0x1fe; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -441,8 +393,8 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8510_write(codec, WM8510_IFACE, iface); - wm8510_write(codec, WM8510_CLOCK, clk); + snd_soc_write(codec, WM8510_IFACE, iface); + snd_soc_write(codec, WM8510_CLOCK, clk); return 0; } @@ -453,8 +405,8 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; - u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; + u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f; + u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1; /* bit size */ switch (params_format(params)) { @@ -493,20 +445,20 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, break; } - wm8510_write(codec, WM8510_IFACE, iface); - wm8510_write(codec, WM8510_ADD, adn); + snd_soc_write(codec, WM8510_IFACE, iface); + snd_soc_write(codec, WM8510_ADD, adn); return 0; } static int wm8510_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf; + u16 mute_reg = snd_soc_read(codec, WM8510_DAC) & 0xffbf; if (mute) - wm8510_write(codec, WM8510_DAC, mute_reg | 0x40); + snd_soc_write(codec, WM8510_DAC, mute_reg | 0x40); else - wm8510_write(codec, WM8510_DAC, mute_reg); + snd_soc_write(codec, WM8510_DAC, mute_reg); return 0; } @@ -514,13 +466,13 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute) static int wm8510_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3; + u16 power1 = snd_soc_read(codec, WM8510_POWER1) & ~0x3; switch (level) { case SND_SOC_BIAS_ON: case SND_SOC_BIAS_PREPARE: power1 |= 0x1; /* VMID 50k */ - wm8510_write(codec, WM8510_POWER1, power1); + snd_soc_write(codec, WM8510_POWER1, power1); break; case SND_SOC_BIAS_STANDBY: @@ -528,18 +480,18 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec, if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Initial cap charge at VMID 5k */ - wm8510_write(codec, WM8510_POWER1, power1 | 0x3); + snd_soc_write(codec, WM8510_POWER1, power1 | 0x3); mdelay(100); } power1 |= 0x2; /* VMID 500k */ - wm8510_write(codec, WM8510_POWER1, power1); + snd_soc_write(codec, WM8510_POWER1, power1); break; case SND_SOC_BIAS_OFF: - wm8510_write(codec, WM8510_POWER1, 0); - wm8510_write(codec, WM8510_POWER2, 0); - wm8510_write(codec, WM8510_POWER3, 0); + snd_soc_write(codec, WM8510_POWER1, 0); + snd_soc_write(codec, WM8510_POWER2, 0); + snd_soc_write(codec, WM8510_POWER3, 0); break; } @@ -619,8 +571,6 @@ static int wm8510_init(struct snd_soc_device *socdev) codec->name = "WM8510"; codec->owner = THIS_MODULE; - codec->read = wm8510_read_reg_cache; - codec->write = wm8510_write; codec->set_bias_level = wm8510_set_bias_level; codec->dai = &wm8510_dai; codec->num_dai = 1; @@ -630,13 +580,20 @@ static int wm8510_init(struct snd_soc_device *socdev) if (codec->reg_cache == NULL) return -ENOMEM; + ret = snd_soc_codec_set_cache_io(codec, 7, 9); + if (ret < 0) { + printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", + ret); + goto err; + } + wm8510_reset(codec); /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { printk(KERN_ERR "wm8510: failed to create pcms\n"); - goto pcm_err; + goto err; } /* power on device */ @@ -655,7 +612,7 @@ static int wm8510_init(struct snd_soc_device *socdev) card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -pcm_err: +err: kfree(codec->reg_cache); return ret; } diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index e7ff212..66da44b 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -43,45 +43,6 @@ static const u16 wm8728_reg_defaults[] = { 0x100, }; -static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults)); - return cache[reg]; -} - -static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults)); - cache[reg] = value; -} - -/* - * write to the WM8728 register space - */ -static int wm8728_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8728 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8728_write_reg_cache(codec, reg, value); - - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); static const struct snd_kcontrol_new wm8728_snd_controls[] = { @@ -121,12 +82,12 @@ static int wm8728_add_widgets(struct snd_soc_codec *codec) static int wm8728_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); + u16 mute_reg = snd_soc_read(codec, WM8728_DACCTL); if (mute) - wm8728_write(codec, WM8728_DACCTL, mute_reg | 1); + snd_soc_write(codec, WM8728_DACCTL, mute_reg | 1); else - wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1); + snd_soc_write(codec, WM8728_DACCTL, mute_reg & ~1); return 0; } @@ -138,7 +99,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL); + u16 dac = snd_soc_read(codec, WM8728_DACCTL); dac &= ~0x18; @@ -155,7 +116,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - wm8728_write(codec, WM8728_DACCTL, dac); + snd_soc_write(codec, WM8728_DACCTL, dac); return 0; } @@ -164,7 +125,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = wm8728_read_reg_cache(codec, WM8728_IFCTL); + u16 iface = snd_soc_read(codec, WM8728_IFCTL); /* Currently only I2S is supported by the driver, though the * hardware is more flexible. @@ -204,7 +165,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8728_write(codec, WM8728_IFCTL, iface); + snd_soc_write(codec, WM8728_IFCTL, iface); return 0; } @@ -220,19 +181,19 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Power everything up... */ - reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); - wm8728_write(codec, WM8728_DACCTL, reg & ~0x4); + reg = snd_soc_read(codec, WM8728_DACCTL); + snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4); /* ..then sync in the register cache. */ for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++) - wm8728_write(codec, i, - wm8728_read_reg_cache(codec, i)); + snd_soc_write(codec, i, + snd_soc_read(codec, i)); } break; case SND_SOC_BIAS_OFF: - reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); - wm8728_write(codec, WM8728_DACCTL, reg | 0x4); + reg = snd_soc_read(codec, WM8728_DACCTL); + snd_soc_write(codec, WM8728_DACCTL, reg | 0x4); break; } codec->bias_level = level; @@ -294,8 +255,6 @@ static int wm8728_init(struct snd_soc_device *socdev) codec->name = "WM8728"; codec->owner = THIS_MODULE; - codec->read = wm8728_read_reg_cache; - codec->write = wm8728_write; codec->set_bias_level = wm8728_set_bias_level; codec->dai = &wm8728_dai; codec->num_dai = 1; @@ -307,11 +266,18 @@ static int wm8728_init(struct snd_soc_device *socdev) if (codec->reg_cache == NULL) return -ENOMEM; + ret = snd_soc_codec_set_cache_io(codec, 7, 9); + if (ret < 0) { + printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n", + ret); + goto err; + } + /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { printk(KERN_ERR "wm8728: failed to create pcms\n"); - goto pcm_err; + goto err; } /* power on device */ @@ -331,7 +297,7 @@ static int wm8728_init(struct snd_soc_device *socdev) card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -pcm_err: +err: kfree(codec->reg_cache); return ret; } diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index dfbc1bb..4eb84ff 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -50,60 +50,12 @@ static int wm8731_spi_write(struct spi_device *spi, const char *data, int len); * There is no point in caching the reset register */ static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { - 0x0097, 0x0097, 0x0079, 0x0079, - 0x000a, 0x0008, 0x009f, 0x000a, - 0x0000, 0x0000 + 0x0097, 0x0097, 0x0079, 0x0079, + 0x000a, 0x0008, 0x009f, 0x000a, + 0x0000, 0x0000 }; -/* - * read wm8731 register cache - */ -static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg == WM8731_RESET) - return 0; - if (reg >= WM8731_CACHEREGNUM) - return -1; - return cache[reg]; -} - -/* - * write wm8731 register cache - */ -static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg >= WM8731_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * write to the WM8731 register space - */ -static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8731 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8731_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define wm8731_reset(c) wm8731_write(c, WM8731_RESET, 0) +#define wm8731_reset(c) snd_soc_write(c, WM8731_RESET, 0) static const char *wm8731_input_select[] = {"Line In", "Mic"}; static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; @@ -260,12 +212,12 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct wm8731_priv *wm8731 = codec->private_data; - u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3; + u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3; int i = get_coeff(wm8731->sysclk, params_rate(params)); u16 srate = (coeff_div[i].sr << 2) | (coeff_div[i].bosr << 1) | coeff_div[i].usb; - wm8731_write(codec, WM8731_SRATE, srate); + snd_soc_write(codec, WM8731_SRATE, srate); /* bit size */ switch (params_format(params)) { @@ -279,7 +231,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, break; } - wm8731_write(codec, WM8731_IFACE, iface); + snd_soc_write(codec, WM8731_IFACE, iface); return 0; } @@ -291,7 +243,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = socdev->card->codec; /* set active */ - wm8731_write(codec, WM8731_ACTIVE, 0x0001); + snd_soc_write(codec, WM8731_ACTIVE, 0x0001); return 0; } @@ -306,19 +258,19 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream, /* deactivate */ if (!codec->active) { udelay(50); - wm8731_write(codec, WM8731_ACTIVE, 0x0); + snd_soc_write(codec, WM8731_ACTIVE, 0x0); } } static int wm8731_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; + u16 mute_reg = snd_soc_read(codec, WM8731_APDIGI) & 0xfff7; if (mute) - wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8); + snd_soc_write(codec, WM8731_APDIGI, mute_reg | 0x8); else - wm8731_write(codec, WM8731_APDIGI, mute_reg); + snd_soc_write(codec, WM8731_APDIGI, mute_reg); return 0; } @@ -396,7 +348,7 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, } /* set iface */ - wm8731_write(codec, WM8731_IFACE, iface); + snd_soc_write(codec, WM8731_IFACE, iface); return 0; } @@ -412,12 +364,12 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, break; case SND_SOC_BIAS_STANDBY: /* Clear PWROFF, gate CLKOUT, everything else as-is */ - reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; - wm8731_write(codec, WM8731_PWR, reg | 0x0040); + reg = snd_soc_read(codec, WM8731_PWR) & 0xff7f; + snd_soc_write(codec, WM8731_PWR, reg | 0x0040); break; case SND_SOC_BIAS_OFF: - wm8731_write(codec, WM8731_ACTIVE, 0x0); - wm8731_write(codec, WM8731_PWR, 0xffff); + snd_soc_write(codec, WM8731_ACTIVE, 0x0); + snd_soc_write(codec, WM8731_PWR, 0xffff); break; } codec->bias_level = level; @@ -466,7 +418,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; - wm8731_write(codec, WM8731_ACTIVE, 0x0); + snd_soc_write(codec, WM8731_ACTIVE, 0x0); wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } @@ -556,7 +508,6 @@ static int wm8731_register(struct wm8731_priv *wm8731) { int ret; struct snd_soc_codec *codec = &wm8731->codec; - u16 reg; if (wm8731_codec) { dev_err(codec->dev, "Another WM8731 is registered\n"); @@ -571,8 +522,6 @@ static int wm8731_register(struct wm8731_priv *wm8731) codec->private_data = wm8731; codec->name = "WM8731"; codec->owner = THIS_MODULE; - codec->read = wm8731_read_reg_cache; - codec->write = wm8731_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8731_set_bias_level; codec->dai = &wm8731_dai; @@ -582,6 +531,12 @@ static int wm8731_register(struct wm8731_priv *wm8731) memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg)); + ret = snd_soc_codec_set_cache_io(codec, 7, 9); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + ret = wm8731_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset: %d\n", ret); @@ -593,18 +548,13 @@ static int wm8731_register(struct wm8731_priv *wm8731) wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Latch the update bits */ - reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); - wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100); - reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); - wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100); - reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); - wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100); - reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); - wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); + snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0); + snd_soc_update_bits(codec, WM8731_ROUT1V, 0x100, 0); + snd_soc_update_bits(codec, WM8731_LINVOL, 0x100, 0); + snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0); /* Disable bypass path by default */ - reg = wm8731_read_reg_cache(codec, WM8731_APANA); - wm8731_write(codec, WM8731_APANA, reg & ~0x4); + snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0); wm8731_codec = codec; diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index b64509b..ed09043 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -55,50 +55,7 @@ static const u16 wm8750_reg[] = { 0x0079, 0x0079, 0x0079, /* 40 */ }; -/* - * read wm8750 register cache - */ -static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg > WM8750_CACHE_REGNUM) - return -1; - return cache[reg]; -} - -/* - * write wm8750 register cache - */ -static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg > WM8750_CACHE_REGNUM) - return; - cache[reg] = value; -} - -static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8753 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8750_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define wm8750_reset(c) wm8750_write(c, WM8750_RESET, 0) +#define wm8750_reset(c) snd_soc_write(c, WM8750_RESET, 0) /* * WM8750 Controls @@ -594,7 +551,7 @@ static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8750_write(codec, WM8750_IFACE, iface); + snd_soc_write(codec, WM8750_IFACE, iface); return 0; } @@ -606,8 +563,8 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct wm8750_priv *wm8750 = codec->private_data; - u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3; - u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0; + u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3; + u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0; int coeff = get_coeff(wm8750->sysclk, params_rate(params)); /* bit size */ @@ -626,9 +583,9 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, } /* set iface & srate */ - wm8750_write(codec, WM8750_IFACE, iface); + snd_soc_write(codec, WM8750_IFACE, iface); if (coeff >= 0) - wm8750_write(codec, WM8750_SRATE, srate | + snd_soc_write(codec, WM8750_SRATE, srate | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); return 0; @@ -637,35 +594,35 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, static int wm8750_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; + u16 mute_reg = snd_soc_read(codec, WM8750_ADCDAC) & 0xfff7; if (mute) - wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); + snd_soc_write(codec, WM8750_ADCDAC, mute_reg | 0x8); else - wm8750_write(codec, WM8750_ADCDAC, mute_reg); + snd_soc_write(codec, WM8750_ADCDAC, mute_reg); return 0; } static int wm8750_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; + u16 pwr_reg = snd_soc_read(codec, WM8750_PWR1) & 0xfe3e; switch (level) { case SND_SOC_BIAS_ON: /* set vmid to 50k and unmute dac */ - wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); + snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); break; case SND_SOC_BIAS_PREPARE: /* set vmid to 5k for quick power up */ - wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); + snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); break; case SND_SOC_BIAS_STANDBY: /* mute dac and set vmid to 500k, enable VREF */ - wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); + snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x0141); break; case SND_SOC_BIAS_OFF: - wm8750_write(codec, WM8750_PWR1, 0x0001); + snd_soc_write(codec, WM8750_PWR1, 0x0001); break; } codec->bias_level = level; @@ -761,8 +718,6 @@ static int wm8750_init(struct snd_soc_device *socdev) codec->name = "WM8750"; codec->owner = THIS_MODULE; - codec->read = wm8750_read_reg_cache; - codec->write = wm8750_write; codec->set_bias_level = wm8750_set_bias_level; codec->dai = &wm8750_dai; codec->num_dai = 1; @@ -771,13 +726,23 @@ static int wm8750_init(struct snd_soc_device *socdev) if (codec->reg_cache == NULL) return -ENOMEM; - wm8750_reset(codec); + ret = snd_soc_codec_set_cache_io(codec, 7, 9); + if (ret < 0) { + printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret); + goto err; + } + + ret = wm8750_reset(codec); + if (ret < 0) { + printk(KERN_ERR "wm8750: failed to reset: %d\n", ret); + goto err; + } /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { printk(KERN_ERR "wm8750: failed to create pcms\n"); - goto pcm_err; + goto err; } /* charge output caps */ @@ -786,22 +751,22 @@ static int wm8750_init(struct snd_soc_device *socdev) schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); /* set the update bits */ - reg = wm8750_read_reg_cache(codec, WM8750_LDAC); - wm8750_write(codec, WM8750_LDAC, reg | 0x0100); - reg = wm8750_read_reg_cache(codec, WM8750_RDAC); - wm8750_write(codec, WM8750_RDAC, reg | 0x0100); - reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V); - wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100); - reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V); - wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100); - reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V); - wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100); - reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V); - wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100); - reg = wm8750_read_reg_cache(codec, WM8750_LINVOL); - wm8750_write(codec, WM8750_LINVOL, reg | 0x0100); - reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); - wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); + reg = snd_soc_read(codec, WM8750_LDAC); + snd_soc_write(codec, WM8750_LDAC, reg | 0x0100); + reg = snd_soc_read(codec, WM8750_RDAC); + snd_soc_write(codec, WM8750_RDAC, reg | 0x0100); + reg = snd_soc_read(codec, WM8750_LOUT1V); + snd_soc_write(codec, WM8750_LOUT1V, reg | 0x0100); + reg = snd_soc_read(codec, WM8750_ROUT1V); + snd_soc_write(codec, WM8750_ROUT1V, reg | 0x0100); + reg = snd_soc_read(codec, WM8750_LOUT2V); + snd_soc_write(codec, WM8750_LOUT2V, reg | 0x0100); + reg = snd_soc_read(codec, WM8750_ROUT2V); + snd_soc_write(codec, WM8750_ROUT2V, reg | 0x0100); + reg = snd_soc_read(codec, WM8750_LINVOL); + snd_soc_write(codec, WM8750_LINVOL, reg | 0x0100); + reg = snd_soc_read(codec, WM8750_RINVOL); + snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100); snd_soc_add_controls(codec, wm8750_snd_controls, ARRAY_SIZE(wm8750_snd_controls)); @@ -816,7 +781,7 @@ static int wm8750_init(struct snd_soc_device *socdev) card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -pcm_err: +err: kfree(codec->reg_cache); return ret; } diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index d1769e6..c529ffc 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -69,61 +69,7 @@ struct wm8960_priv { struct snd_soc_codec codec; }; -/* - * read wm8960 register cache - */ -static inline unsigned int wm8960_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg == WM8960_RESET) - return 0; - if (reg >= WM8960_CACHEREGNUM) - return -1; - return cache[reg]; -} - -/* - * write wm8960 register cache - */ -static inline void wm8960_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg >= WM8960_CACHEREGNUM) - return; - cache[reg] = value; -} - -static inline unsigned int wm8960_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return wm8960_read_reg_cache(codec, reg); -} - -/* - * write to the WM8960 register space - */ -static int wm8960_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8960 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8960_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define wm8960_reset(c) wm8960_write(c, WM8960_RESET, 0) +#define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) /* enumerated controls */ static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; @@ -420,7 +366,7 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai, } /* set iface */ - wm8960_write(codec, WM8960_IFACE1, iface); + snd_soc_write(codec, WM8960_IFACE1, iface); return 0; } @@ -431,7 +377,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 iface = wm8960_read(codec, WM8960_IFACE1) & 0xfff3; + u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; /* bit size */ switch (params_format(params)) { @@ -446,19 +392,19 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, } /* set iface */ - wm8960_write(codec, WM8960_IFACE1, iface); + snd_soc_write(codec, WM8960_IFACE1, iface); return 0; } static int wm8960_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8960_read(codec, WM8960_DACCTL1) & 0xfff7; + u16 mute_reg = snd_soc_read(codec, WM8960_DACCTL1) & 0xfff7; if (mute) - wm8960_write(codec, WM8960_DACCTL1, mute_reg | 0x8); + snd_soc_write(codec, WM8960_DACCTL1, mute_reg | 0x8); else - wm8960_write(codec, WM8960_DACCTL1, mute_reg); + snd_soc_write(codec, WM8960_DACCTL1, mute_reg); return 0; } @@ -474,16 +420,16 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: /* Set VMID to 2x50k */ - reg = wm8960_read(codec, WM8960_POWER1); + reg = snd_soc_read(codec, WM8960_POWER1); reg &= ~0x180; reg |= 0x80; - wm8960_write(codec, WM8960_POWER1, reg); + snd_soc_write(codec, WM8960_POWER1, reg); break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Enable anti-pop features */ - wm8960_write(codec, WM8960_APOP1, + snd_soc_write(codec, WM8960_APOP1, WM8960_POBCTRL | WM8960_SOFT_ST | WM8960_BUFDCOPEN | WM8960_BUFIOEN); @@ -491,43 +437,43 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec, reg = WM8960_DISOP; if (pdata) reg |= pdata->dres << 4; - wm8960_write(codec, WM8960_APOP2, reg); + snd_soc_write(codec, WM8960_APOP2, reg); msleep(400); - wm8960_write(codec, WM8960_APOP2, 0); + snd_soc_write(codec, WM8960_APOP2, 0); /* Enable & ramp VMID at 2x50k */ - reg = wm8960_read(codec, WM8960_POWER1); + reg = snd_soc_read(codec, WM8960_POWER1); reg |= 0x80; - wm8960_write(codec, WM8960_POWER1, reg); + snd_soc_write(codec, WM8960_POWER1, reg); msleep(100); /* Enable VREF */ - wm8960_write(codec, WM8960_POWER1, reg | WM8960_VREF); + snd_soc_write(codec, WM8960_POWER1, reg | WM8960_VREF); /* Disable anti-pop features */ - wm8960_write(codec, WM8960_APOP1, WM8960_BUFIOEN); + snd_soc_write(codec, WM8960_APOP1, WM8960_BUFIOEN); } /* Set VMID to 2x250k */ - reg = wm8960_read(codec, WM8960_POWER1); + reg = snd_soc_read(codec, WM8960_POWER1); reg &= ~0x180; reg |= 0x100; - wm8960_write(codec, WM8960_POWER1, reg); + snd_soc_write(codec, WM8960_POWER1, reg); break; case SND_SOC_BIAS_OFF: /* Enable anti-pop features */ - wm8960_write(codec, WM8960_APOP1, + snd_soc_write(codec, WM8960_APOP1, WM8960_POBCTRL | WM8960_SOFT_ST | WM8960_BUFDCOPEN | WM8960_BUFIOEN); /* Disable VMID and VREF, let them discharge */ - wm8960_write(codec, WM8960_POWER1, 0); + snd_soc_write(codec, WM8960_POWER1, 0); msleep(600); - wm8960_write(codec, WM8960_APOP1, 0); + snd_soc_write(codec, WM8960_APOP1, 0); break; } @@ -610,33 +556,33 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, /* Disable the PLL: even if we are changing the frequency the * PLL needs to be disabled while we do so. */ - wm8960_write(codec, WM8960_CLOCK1, - wm8960_read(codec, WM8960_CLOCK1) & ~1); - wm8960_write(codec, WM8960_POWER2, - wm8960_read(codec, WM8960_POWER2) & ~1); + snd_soc_write(codec, WM8960_CLOCK1, + snd_soc_read(codec, WM8960_CLOCK1) & ~1); + snd_soc_write(codec, WM8960_POWER2, + snd_soc_read(codec, WM8960_POWER2) & ~1); if (!freq_in || !freq_out) return 0; - reg = wm8960_read(codec, WM8960_PLL1) & ~0x3f; + reg = snd_soc_read(codec, WM8960_PLL1) & ~0x3f; reg |= pll_div.pre_div << 4; reg |= pll_div.n; if (pll_div.k) { reg |= 0x20; - wm8960_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f); - wm8960_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff); - wm8960_write(codec, WM8960_PLL4, pll_div.k & 0x1ff); + snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f); + snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff); + snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0x1ff); } - wm8960_write(codec, WM8960_PLL1, reg); + snd_soc_write(codec, WM8960_PLL1, reg); /* Turn it on */ - wm8960_write(codec, WM8960_POWER2, - wm8960_read(codec, WM8960_POWER2) | 1); + snd_soc_write(codec, WM8960_POWER2, + snd_soc_read(codec, WM8960_POWER2) | 1); msleep(250); - wm8960_write(codec, WM8960_CLOCK1, - wm8960_read(codec, WM8960_CLOCK1) | 1); + snd_soc_write(codec, WM8960_CLOCK1, + snd_soc_read(codec, WM8960_CLOCK1) | 1); return 0; } @@ -649,28 +595,28 @@ static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8960_SYSCLKSEL: - reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1fe; - wm8960_write(codec, WM8960_CLOCK1, reg | div); + reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1fe; + snd_soc_write(codec, WM8960_CLOCK1, reg | div); break; case WM8960_SYSCLKDIV: - reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1f9; - wm8960_write(codec, WM8960_CLOCK1, reg | div); + reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1f9; + snd_soc_write(codec, WM8960_CLOCK1, reg | div); break; case WM8960_DACDIV: - reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1c7; - wm8960_write(codec, WM8960_CLOCK1, reg | div); + reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1c7; + snd_soc_write(codec, WM8960_CLOCK1, reg | div); break; case WM8960_OPCLKDIV: - reg = wm8960_read(codec, WM8960_PLL1) & 0x03f; - wm8960_write(codec, WM8960_PLL1, reg | div); + reg = snd_soc_read(codec, WM8960_PLL1) & 0x03f; + snd_soc_write(codec, WM8960_PLL1, reg | div); break; case WM8960_DCLKDIV: - reg = wm8960_read(codec, WM8960_CLOCK2) & 0x03f; - wm8960_write(codec, WM8960_CLOCK2, reg | div); + reg = snd_soc_read(codec, WM8960_CLOCK2) & 0x03f; + snd_soc_write(codec, WM8960_CLOCK2, reg | div); break; case WM8960_TOCLKSEL: - reg = wm8960_read(codec, WM8960_ADDCTL1) & 0x1fd; - wm8960_write(codec, WM8960_ADDCTL1, reg | div); + reg = snd_soc_read(codec, WM8960_ADDCTL1) & 0x1fd; + snd_soc_write(codec, WM8960_ADDCTL1, reg | div); break; default: return -EINVAL; @@ -830,8 +776,6 @@ static int wm8960_register(struct wm8960_priv *wm8960) codec->private_data = wm8960; codec->name = "WM8960"; codec->owner = THIS_MODULE; - codec->read = wm8960_read_reg_cache; - codec->write = wm8960_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8960_set_bias_level; codec->dai = &wm8960_dai; @@ -841,6 +785,12 @@ static int wm8960_register(struct wm8960_priv *wm8960) memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg)); + ret = snd_soc_codec_set_cache_io(codec, 7, 9); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + ret = wm8960_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset\n"); @@ -852,26 +802,26 @@ static int wm8960_register(struct wm8960_priv *wm8960) wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Latch the update bits */ - reg = wm8960_read(codec, WM8960_LINVOL); - wm8960_write(codec, WM8960_LINVOL, reg | 0x100); - reg = wm8960_read(codec, WM8960_RINVOL); - wm8960_write(codec, WM8960_RINVOL, reg | 0x100); - reg = wm8960_read(codec, WM8960_LADC); - wm8960_write(codec, WM8960_LADC, reg | 0x100); - reg = wm8960_read(codec, WM8960_RADC); - wm8960_write(codec, WM8960_RADC, reg | 0x100); - reg = wm8960_read(codec, WM8960_LDAC); - wm8960_write(codec, WM8960_LDAC, reg | 0x100); - reg = wm8960_read(codec, WM8960_RDAC); - wm8960_write(codec, WM8960_RDAC, reg | 0x100); - reg = wm8960_read(codec, WM8960_LOUT1); - wm8960_write(codec, WM8960_LOUT1, reg | 0x100); - reg = wm8960_read(codec, WM8960_ROUT1); - wm8960_write(codec, WM8960_ROUT1, reg | 0x100); - reg = wm8960_read(codec, WM8960_LOUT2); - wm8960_write(codec, WM8960_LOUT2, reg | 0x100); - reg = wm8960_read(codec, WM8960_ROUT2); - wm8960_write(codec, WM8960_ROUT2, reg | 0x100); + reg = snd_soc_read(codec, WM8960_LINVOL); + snd_soc_write(codec, WM8960_LINVOL, reg | 0x100); + reg = snd_soc_read(codec, WM8960_RINVOL); + snd_soc_write(codec, WM8960_RINVOL, reg | 0x100); + reg = snd_soc_read(codec, WM8960_LADC); + snd_soc_write(codec, WM8960_LADC, reg | 0x100); + reg = snd_soc_read(codec, WM8960_RADC); + snd_soc_write(codec, WM8960_RADC, reg | 0x100); + reg = snd_soc_read(codec, WM8960_LDAC); + snd_soc_write(codec, WM8960_LDAC, reg | 0x100); + reg = snd_soc_read(codec, WM8960_RDAC); + snd_soc_write(codec, WM8960_RDAC, reg | 0x100); + reg = snd_soc_read(codec, WM8960_LOUT1); + snd_soc_write(codec, WM8960_LOUT1, reg | 0x100); + reg = snd_soc_read(codec, WM8960_ROUT1); + snd_soc_write(codec, WM8960_ROUT1, reg | 0x100); + reg = snd_soc_read(codec, WM8960_LOUT2); + snd_soc_write(codec, WM8960_LOUT2, reg | 0x100); + reg = snd_soc_read(codec, WM8960_ROUT2); + snd_soc_write(codec, WM8960_ROUT2, reg | 0x100); wm8960_codec = codec; diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 032dca2..53f3bc9 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -59,44 +59,7 @@ static const u16 wm8971_reg[] = { 0x0079, 0x0079, 0x0079, /* 40 */ }; -static inline unsigned int wm8971_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg < WM8971_REG_COUNT) - return cache[reg]; - - return -1; -} - -static inline void wm8971_write_reg_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg < WM8971_REG_COUNT) - cache[reg] = value; -} - -static int wm8971_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8753 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8971_write_reg_cache (codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define wm8971_reset(c) wm8971_write(c, WM8971_RESET, 0) +#define wm8971_reset(c) snd_soc_write(c, WM8971_RESET, 0) /* WM8971 Controls */ static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" }; @@ -521,7 +484,7 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8971_write(codec, WM8971_IFACE, iface); + snd_soc_write(codec, WM8971_IFACE, iface); return 0; } @@ -533,8 +496,8 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct wm8971_priv *wm8971 = codec->private_data; - u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3; - u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0; + u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3; + u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0; int coeff = get_coeff(wm8971->sysclk, params_rate(params)); /* bit size */ @@ -553,9 +516,9 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, } /* set iface & srate */ - wm8971_write(codec, WM8971_IFACE, iface); + snd_soc_write(codec, WM8971_IFACE, iface); if (coeff >= 0) - wm8971_write(codec, WM8971_SRATE, srate | + snd_soc_write(codec, WM8971_SRATE, srate | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); return 0; @@ -564,33 +527,33 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, static int wm8971_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8971_read_reg_cache(codec, WM8971_ADCDAC) & 0xfff7; + u16 mute_reg = snd_soc_read(codec, WM8971_ADCDAC) & 0xfff7; if (mute) - wm8971_write(codec, WM8971_ADCDAC, mute_reg | 0x8); + snd_soc_write(codec, WM8971_ADCDAC, mute_reg | 0x8); else - wm8971_write(codec, WM8971_ADCDAC, mute_reg); + snd_soc_write(codec, WM8971_ADCDAC, mute_reg); return 0; } static int wm8971_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 pwr_reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; + u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; switch (level) { case SND_SOC_BIAS_ON: /* set vmid to 50k and unmute dac */ - wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x00c1); + snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x00c1); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: /* mute dac and set vmid to 500k, enable VREF */ - wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x0140); + snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140); break; case SND_SOC_BIAS_OFF: - wm8971_write(codec, WM8971_PWR1, 0x0001); + snd_soc_write(codec, WM8971_PWR1, 0x0001); break; } codec->bias_level = level; @@ -667,8 +630,8 @@ static int wm8971_resume(struct platform_device *pdev) /* charge wm8971 caps */ if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { - reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; - wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); + reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; + snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); codec->bias_level = SND_SOC_BIAS_ON; queue_delayed_work(wm8971_workq, &codec->delayed_work, msecs_to_jiffies(1000)); @@ -684,8 +647,6 @@ static int wm8971_init(struct snd_soc_device *socdev) codec->name = "WM8971"; codec->owner = THIS_MODULE; - codec->read = wm8971_read_reg_cache; - codec->write = wm8971_write; codec->set_bias_level = wm8971_set_bias_level; codec->dai = &wm8971_dai; codec->reg_cache_size = ARRAY_SIZE(wm8971_reg); @@ -695,42 +656,48 @@ static int wm8971_init(struct snd_soc_device *socdev) if (codec->reg_cache == NULL) return -ENOMEM; + ret = snd_soc_codec_set_cache_io(codec, 7, 9); + if (ret < 0) { + printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret); + goto err; + } + wm8971_reset(codec); /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { printk(KERN_ERR "wm8971: failed to create pcms\n"); - goto pcm_err; + goto err; } /* charge output caps - set vmid to 5k for quick power up */ - reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; - wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); + reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; + snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); codec->bias_level = SND_SOC_BIAS_STANDBY; queue_delayed_work(wm8971_workq, &codec->delayed_work, msecs_to_jiffies(1000)); /* set the update bits */ - reg = wm8971_read_reg_cache(codec, WM8971_LDAC); - wm8971_write(codec, WM8971_LDAC, reg | 0x0100); - reg = wm8971_read_reg_cache(codec, WM8971_RDAC); - wm8971_write(codec, WM8971_RDAC, reg | 0x0100); - - reg = wm8971_read_reg_cache(codec, WM8971_LOUT1V); - wm8971_write(codec, WM8971_LOUT1V, reg | 0x0100); - reg = wm8971_read_reg_cache(codec, WM8971_ROUT1V); - wm8971_write(codec, WM8971_ROUT1V, reg | 0x0100); - - reg = wm8971_read_reg_cache(codec, WM8971_LOUT2V); - wm8971_write(codec, WM8971_LOUT2V, reg | 0x0100); - reg = wm8971_read_reg_cache(codec, WM8971_ROUT2V); - wm8971_write(codec, WM8971_ROUT2V, reg | 0x0100); - - reg = wm8971_read_reg_cache(codec, WM8971_LINVOL); - wm8971_write(codec, WM8971_LINVOL, reg | 0x0100); - reg = wm8971_read_reg_cache(codec, WM8971_RINVOL); - wm8971_write(codec, WM8971_RINVOL, reg | 0x0100); + reg = snd_soc_read(codec, WM8971_LDAC); + snd_soc_write(codec, WM8971_LDAC, reg | 0x0100); + reg = snd_soc_read(codec, WM8971_RDAC); + snd_soc_write(codec, WM8971_RDAC, reg | 0x0100); + + reg = snd_soc_read(codec, WM8971_LOUT1V); + snd_soc_write(codec, WM8971_LOUT1V, reg | 0x0100); + reg = snd_soc_read(codec, WM8971_ROUT1V); + snd_soc_write(codec, WM8971_ROUT1V, reg | 0x0100); + + reg = snd_soc_read(codec, WM8971_LOUT2V); + snd_soc_write(codec, WM8971_LOUT2V, reg | 0x0100); + reg = snd_soc_read(codec, WM8971_ROUT2V); + snd_soc_write(codec, WM8971_ROUT2V, reg | 0x0100); + + reg = snd_soc_read(codec, WM8971_LINVOL); + snd_soc_write(codec, WM8971_LINVOL, reg | 0x0100); + reg = snd_soc_read(codec, WM8971_RINVOL); + snd_soc_write(codec, WM8971_RINVOL, reg | 0x0100); snd_soc_add_controls(codec, wm8971_snd_controls, ARRAY_SIZE(wm8971_snd_controls)); @@ -745,7 +712,7 @@ static int wm8971_init(struct snd_soc_device *socdev) card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -pcm_err: +err: kfree(codec->reg_cache); return ret; } diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 6f15acd..7d5b807 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -57,50 +57,7 @@ struct wm8988_priv { }; -/* - * read wm8988 register cache - */ -static inline unsigned int wm8988_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg > WM8988_NUM_REG) - return -1; - return cache[reg]; -} - -/* - * write wm8988 register cache - */ -static inline void wm8988_write_reg_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg > WM8988_NUM_REG) - return; - cache[reg] = value; -} - -static int wm8988_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8753 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8988_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define wm8988_reset(c) wm8988_write(c, WM8988_RESET, 0) +#define wm8988_reset(c) snd_soc_write(c, WM8988_RESET, 0) /* * WM8988 Controls @@ -226,15 +183,15 @@ static int wm8988_lrc_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - u16 adctl2 = wm8988_read_reg_cache(codec, WM8988_ADCTL2); + u16 adctl2 = snd_soc_read(codec, WM8988_ADCTL2); /* Use the DAC to gate LRC if active, otherwise use ADC */ - if (wm8988_read_reg_cache(codec, WM8988_PWR2) & 0x180) + if (snd_soc_read(codec, WM8988_PWR2) & 0x180) adctl2 &= ~0x4; else adctl2 |= 0x4; - return wm8988_write(codec, WM8988_ADCTL2, adctl2); + return snd_soc_write(codec, WM8988_ADCTL2, adctl2); } static const char *wm8988_line_texts[] = { @@ -619,7 +576,7 @@ static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8988_write(codec, WM8988_IFACE, iface); + snd_soc_write(codec, WM8988_IFACE, iface); return 0; } @@ -653,8 +610,8 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct wm8988_priv *wm8988 = codec->private_data; - u16 iface = wm8988_read_reg_cache(codec, WM8988_IFACE) & 0x1f3; - u16 srate = wm8988_read_reg_cache(codec, WM8988_SRATE) & 0x180; + u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3; + u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180; int coeff; coeff = get_coeff(wm8988->sysclk, params_rate(params)); @@ -685,9 +642,9 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream, } /* set iface & srate */ - wm8988_write(codec, WM8988_IFACE, iface); + snd_soc_write(codec, WM8988_IFACE, iface); if (coeff >= 0) - wm8988_write(codec, WM8988_SRATE, srate | + snd_soc_write(codec, WM8988_SRATE, srate | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); return 0; @@ -696,19 +653,19 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream, static int wm8988_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8988_read_reg_cache(codec, WM8988_ADCDAC) & 0xfff7; + u16 mute_reg = snd_soc_read(codec, WM8988_ADCDAC) & 0xfff7; if (mute) - wm8988_write(codec, WM8988_ADCDAC, mute_reg | 0x8); + snd_soc_write(codec, WM8988_ADCDAC, mute_reg | 0x8); else - wm8988_write(codec, WM8988_ADCDAC, mute_reg); + snd_soc_write(codec, WM8988_ADCDAC, mute_reg); return 0; } static int wm8988_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 pwr_reg = wm8988_read_reg_cache(codec, WM8988_PWR1) & ~0x1c1; + u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1; switch (level) { case SND_SOC_BIAS_ON: @@ -716,24 +673,24 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: /* VREF, VMID=2x50k, digital enabled */ - wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x00c0); + snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x00c0); break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* VREF, VMID=2x5k */ - wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); + snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); /* Charge caps */ msleep(100); } /* VREF, VMID=2*500k, digital stopped */ - wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x0141); + snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x0141); break; case SND_SOC_BIAS_OFF: - wm8988_write(codec, WM8988_PWR1, 0x0000); + snd_soc_write(codec, WM8988_PWR1, 0x0000); break; } codec->bias_level = level; @@ -887,8 +844,6 @@ static int wm8988_register(struct wm8988_priv *wm8988) codec->private_data = wm8988; codec->name = "WM8988"; codec->owner = THIS_MODULE; - codec->read = wm8988_read_reg_cache; - codec->write = wm8988_write; codec->dai = &wm8988_dai; codec->num_dai = 1; codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache); @@ -899,6 +854,12 @@ static int wm8988_register(struct wm8988_priv *wm8988) memcpy(codec->reg_cache, wm8988_reg, sizeof(wm8988_reg)); + ret = snd_soc_codec_set_cache_io(codec, 7, 9); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + ret = wm8988_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset\n"); @@ -906,16 +867,16 @@ static int wm8988_register(struct wm8988_priv *wm8988) } /* set the update bits (we always update left then right) */ - reg = wm8988_read_reg_cache(codec, WM8988_RADC); - wm8988_write(codec, WM8988_RADC, reg | 0x100); - reg = wm8988_read_reg_cache(codec, WM8988_RDAC); - wm8988_write(codec, WM8988_RDAC, reg | 0x0100); - reg = wm8988_read_reg_cache(codec, WM8988_ROUT1V); - wm8988_write(codec, WM8988_ROUT1V, reg | 0x0100); - reg = wm8988_read_reg_cache(codec, WM8988_ROUT2V); - wm8988_write(codec, WM8988_ROUT2V, reg | 0x0100); - reg = wm8988_read_reg_cache(codec, WM8988_RINVOL); - wm8988_write(codec, WM8988_RINVOL, reg | 0x0100); + reg = snd_soc_read(codec, WM8988_RADC); + snd_soc_write(codec, WM8988_RADC, reg | 0x100); + reg = snd_soc_read(codec, WM8988_RDAC); + snd_soc_write(codec, WM8988_RDAC, reg | 0x0100); + reg = snd_soc_read(codec, WM8988_ROUT1V); + snd_soc_write(codec, WM8988_ROUT1V, reg | 0x0100); + reg = snd_soc_read(codec, WM8988_ROUT2V); + snd_soc_write(codec, WM8988_ROUT2V, reg | 0x0100); + reg = snd_soc_read(codec, WM8988_RINVOL); + snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100); wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY); diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c new file mode 100644 index 0000000..4eb4333 --- /dev/null +++ b/sound/soc/soc-cache.c @@ -0,0 +1,105 @@ +/* + * soc-cache.c -- ASoC register cache helpers + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * 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 + +static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg >= codec->reg_cache_size) + return -1; + return cache[reg]; +} + +static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 *cache = codec->reg_cache; + u8 data[2]; + int ret; + + BUG_ON(codec->volatile_register); + + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + if (reg < codec->reg_cache_size) + cache[reg] = value; + ret = codec->hw_write(codec->control_data, data, 2); + if (ret == 2) + return 0; + if (ret < 0) + return ret; + else + return -EIO; +} + + +static struct { + int addr_bits; + int data_bits; + int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); + unsigned int (*read)(struct snd_soc_codec *, unsigned int); +} io_types[] = { + { 7, 9, snd_soc_7_9_write, snd_soc_7_9_read }, +}; + +/** + * snd_soc_codec_set_cache_io: Set up standard I/O functions. + * + * @codec: CODEC to configure. + * @type: Type of cache. + * @addr_bits: Number of bits of register address data. + * @data_bits: Number of bits of data per register. + * + * Register formats are frequently shared between many I2C and SPI + * devices. In order to promote code reuse the ASoC core provides + * some standard implementations of CODEC read and write operations + * which can be set up using this function. + * + * The caller is responsible for allocating and initialising the + * actual cache. + * + * Note that at present this code cannot be used by CODECs with + * volatile registers. + */ +int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, + int addr_bits, int data_bits) +{ + int i; + + /* We don't support volatile registers yet - refactoring of + * the hw_read operation will be required to do so. */ + if (codec->volatile_register) { + printk(KERN_ERR "Volatile registers not yet supported\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(io_types); i++) + if (io_types[i].addr_bits == addr_bits && + io_types[i].data_bits == data_bits) + break; + if (i == ARRAY_SIZE(io_types)) { + printk(KERN_ERR + "No I/O functions for %d bit address %d bit data\n", + addr_bits, data_bits); + return -EINVAL; + } + + codec->write = io_types[i].write; + codec->read = io_types[i].read; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); -- cgit v0.10.2 From 1e30a5828e4e9e49fcc6e471bf0d99d4fd273ba4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 5 Jul 2009 17:28:41 +0100 Subject: ASoC: Remove unused AK4535 hardware read functionality Nothing uses it and the existing hw_read operation needs to be refectored so it's easier to remove it rather than work with it. Support can be re-added if the code requires volatile registers. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index dd33802..0abec0d 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -59,21 +59,6 @@ static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec, return cache[reg]; } -static inline unsigned int ak4535_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - u8 data; - data = reg; - - if (codec->hw_write(codec->control_data, &data, 1) != 1) - return -EIO; - - if (codec->hw_read(codec->control_data, &data, 1) != 1) - return -EIO; - - return data; -}; - /* * write ak4535 register cache */ @@ -635,7 +620,6 @@ static int ak4535_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { codec->hw_write = (hw_write_t)i2c_master_send; - codec->hw_read = (hw_read_t)i2c_master_recv; ret = ak4535_add_i2c_device(pdev, setup); } #endif -- cgit v0.10.2 From 5f345346dd715d53fb2ed168a4fd432e1bdcb14d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 5 Jul 2009 17:35:28 +0100 Subject: ASoC: Remove use of hw_read from TLV320AIC3x driver The TLV320AIC3x driver is currently the only user of the CODEC hw_read operation and is jumping through some hoops in order to do so. In order to support future refactoring to make the hw_read operation more usable unwrap the usage in this driver to avoid its use. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index ab099f4..0cf401f 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -145,8 +145,8 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, u8 *value) { *value = reg & 0xff; - if (codec->hw_read(codec->control_data, value, 1) != 1) - return -EIO; + + value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]); aic3x_write_reg_cache(codec, reg, *value); return 0; @@ -1316,12 +1316,6 @@ static struct i2c_driver aic3x_i2c_driver = { .id_table = aic3x_i2c_id, }; -static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) -{ - value[0] = i2c_smbus_read_byte_data(client, value[0]); - return (len == 1); -} - static int aic3x_add_i2c_device(struct platform_device *pdev, const struct aic3x_setup_data *setup) { @@ -1394,7 +1388,6 @@ static int aic3x_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { codec->hw_write = (hw_write_t) i2c_master_send; - codec->hw_read = (hw_read_t) aic3x_i2c_read; ret = aic3x_add_i2c_device(pdev, setup); } #else -- cgit v0.10.2 From f6f1eb1033959f3633eafbe06dcac92b9c503c41 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 5 Jul 2009 17:57:57 +0100 Subject: ASoC: Factor out WM8580 register cache code Note the slightly tricky cache usage in the volume update function due to the requirement for a separate write for the VU bit. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 97b9ed9..2250ade 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -205,73 +205,6 @@ struct wm8580_priv { struct pll_state b; }; -/* - * read wm8580 register cache - */ -static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg >= ARRAY_SIZE(wm8580_reg)); - return cache[reg]; -} - -/* - * write wm8580 register cache - */ -static inline void wm8580_write_reg_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - - cache[reg] = value; -} - -/* - * write to the WM8580 register space - */ -static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - BUG_ON(reg >= ARRAY_SIZE(wm8580_reg)); - - /* Registers are 9 bits wide */ - value &= 0x1ff; - - switch (reg) { - case WM8580_RESET: - /* Uncached */ - break; - default: - if (value == wm8580_read_reg_cache(codec, reg)) - return 0; - } - - /* data is - * D15..D9 WM8580 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8580_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -static inline unsigned int wm8580_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - switch (reg) { - default: - return wm8580_read_reg_cache(codec, reg); - } -} - static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); static int wm8580_out_vu(struct snd_kcontrol *kcontrol, @@ -280,25 +213,22 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + u16 *reg_cache = codec->reg_cache; unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; int ret; - u16 val; /* Clear the register cache so we write without VU set */ - wm8580_write_reg_cache(codec, reg, 0); - wm8580_write_reg_cache(codec, reg2, 0); + reg_cache[reg] = 0; + reg_cache[reg2] = 0; ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); if (ret < 0) return ret; /* Now write again with the volume update bit set */ - val = wm8580_read_reg_cache(codec, reg); - wm8580_write(codec, reg, val | 0x0100); - - val = wm8580_read_reg_cache(codec, reg2); - wm8580_write(codec, reg2, val | 0x0100); + snd_soc_update_bits(codec, reg, 0x100, 0x100); + snd_soc_update_bits(codec, reg2, 0x100, 0x100); return 0; } @@ -521,27 +451,27 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, /* Always disable the PLL - it is not safe to leave it running * while reprogramming it. */ - reg = wm8580_read(codec, WM8580_PWRDN2); - wm8580_write(codec, WM8580_PWRDN2, reg | pwr_mask); + reg = snd_soc_read(codec, WM8580_PWRDN2); + snd_soc_write(codec, WM8580_PWRDN2, reg | pwr_mask); if (!freq_in || !freq_out) return 0; - wm8580_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); - wm8580_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff); - wm8580_write(codec, WM8580_PLLA3 + offset, + snd_soc_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); + snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff); + snd_soc_write(codec, WM8580_PLLA3 + offset, (pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); - reg = wm8580_read(codec, WM8580_PLLA4 + offset); + reg = snd_soc_read(codec, WM8580_PLLA4 + offset); reg &= ~0x3f; reg |= pll_div.prescale | pll_div.postscale << 1 | pll_div.freqmode << 3; - wm8580_write(codec, WM8580_PLLA4 + offset, reg); + snd_soc_write(codec, WM8580_PLLA4 + offset, reg); /* All done, turn it on */ - reg = wm8580_read(codec, WM8580_PWRDN2); - wm8580_write(codec, WM8580_PWRDN2, reg & ~pwr_mask); + reg = snd_soc_read(codec, WM8580_PWRDN2); + snd_soc_write(codec, WM8580_PWRDN2, reg & ~pwr_mask); return 0; } @@ -556,7 +486,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id); + u16 paifb = snd_soc_read(codec, WM8580_PAIF3 + dai->id); paifb &= ~WM8580_AIF_LENGTH_MASK; /* bit size */ @@ -576,7 +506,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - wm8580_write(codec, WM8580_PAIF3 + dai->id, paifb); + snd_soc_write(codec, WM8580_PAIF3 + dai->id, paifb); return 0; } @@ -588,8 +518,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int aifb; int can_invert_lrclk; - aifa = wm8580_read(codec, WM8580_PAIF1 + codec_dai->id); - aifb = wm8580_read(codec, WM8580_PAIF3 + codec_dai->id); + aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->id); + aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->id); aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP); @@ -655,8 +585,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8580_write(codec, WM8580_PAIF1 + codec_dai->id, aifa); - wm8580_write(codec, WM8580_PAIF3 + codec_dai->id, aifb); + snd_soc_write(codec, WM8580_PAIF1 + codec_dai->id, aifa); + snd_soc_write(codec, WM8580_PAIF3 + codec_dai->id, aifb); return 0; } @@ -669,7 +599,7 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8580_MCLK: - reg = wm8580_read(codec, WM8580_PLLB4); + reg = snd_soc_read(codec, WM8580_PLLB4); reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK; switch (div) { @@ -691,11 +621,11 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - wm8580_write(codec, WM8580_PLLB4, reg); + snd_soc_write(codec, WM8580_PLLB4, reg); break; case WM8580_DAC_CLKSEL: - reg = wm8580_read(codec, WM8580_CLKSEL); + reg = snd_soc_read(codec, WM8580_CLKSEL); reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK; switch (div) { @@ -713,11 +643,11 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - wm8580_write(codec, WM8580_CLKSEL, reg); + snd_soc_write(codec, WM8580_CLKSEL, reg); break; case WM8580_CLKOUTSRC: - reg = wm8580_read(codec, WM8580_PLLB4); + reg = snd_soc_read(codec, WM8580_PLLB4); reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK; switch (div) { @@ -739,7 +669,7 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - wm8580_write(codec, WM8580_PLLB4, reg); + snd_soc_write(codec, WM8580_PLLB4, reg); break; default: @@ -754,14 +684,14 @@ static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute) struct snd_soc_codec *codec = codec_dai->codec; unsigned int reg; - reg = wm8580_read(codec, WM8580_DAC_CONTROL5); + reg = snd_soc_read(codec, WM8580_DAC_CONTROL5); if (mute) reg |= WM8580_DAC_CONTROL5_MUTEALL; else reg &= ~WM8580_DAC_CONTROL5_MUTEALL; - wm8580_write(codec, WM8580_DAC_CONTROL5, reg); + snd_soc_write(codec, WM8580_DAC_CONTROL5, reg); return 0; } @@ -778,20 +708,20 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Power up and get individual control of the DACs */ - reg = wm8580_read(codec, WM8580_PWRDN1); + reg = snd_soc_read(codec, WM8580_PWRDN1); reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); - wm8580_write(codec, WM8580_PWRDN1, reg); + snd_soc_write(codec, WM8580_PWRDN1, reg); /* Make VMID high impedence */ - reg = wm8580_read(codec, WM8580_ADC_CONTROL1); + reg = snd_soc_read(codec, WM8580_ADC_CONTROL1); reg &= ~0x100; - wm8580_write(codec, WM8580_ADC_CONTROL1, reg); + snd_soc_write(codec, WM8580_ADC_CONTROL1, reg); } break; case SND_SOC_BIAS_OFF: - reg = wm8580_read(codec, WM8580_PWRDN1); - wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); + reg = snd_soc_read(codec, WM8580_PWRDN1); + snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); break; } codec->bias_level = level; @@ -920,8 +850,6 @@ static int wm8580_register(struct wm8580_priv *wm8580) codec->private_data = wm8580; codec->name = "WM8580"; codec->owner = THIS_MODULE; - codec->read = wm8580_read_reg_cache; - codec->write = wm8580_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8580_set_bias_level; codec->dai = wm8580_dai; @@ -931,6 +859,12 @@ static int wm8580_register(struct wm8580_priv *wm8580) memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg)); + ret = snd_soc_codec_set_cache_io(codec, 7, 9); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++) wm8580->supplies[i].supply = wm8580_supply_names[i]; @@ -949,7 +883,7 @@ static int wm8580_register(struct wm8580_priv *wm8580) } /* Get the codec into a known state */ - ret = wm8580_write(codec, WM8580_RESET, 0); + ret = snd_soc_write(codec, WM8580_RESET, 0); if (ret != 0) { dev_err(codec->dev, "Failed to reset codec: %d\n", ret); goto err_regulator_enable; -- cgit v0.10.2 From 0e8635a8e1f2d4a9e1bfc6c3b21419a5921e674f Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 20 Jun 2009 00:53:25 +0000 Subject: net: remove NET_RX_BAD and NET_RX_CN* defines almost no users in the tree; and the few that use them treat them like NET_RX_DROP. Signed-off-by: Florian Westphal Signed-off-by: David S. Miller diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 8702e7a..74cdb6f 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -114,11 +114,6 @@ static int rionet_rx_clean(struct net_device *ndev) if (error == NET_RX_DROP) { ndev->stats.rx_dropped++; - } else if (error == NET_RX_BAD) { - if (netif_msg_rx_err(rnet)) - printk(KERN_WARNING "%s: bad rx packet\n", - DRV_NAME); - ndev->stats.rx_errors++; } else { ndev->stats.rx_packets++; ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 25c9ef6..90c0a31 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -792,25 +792,6 @@ fst_process_rx_status(int rx_status, char *name) */ break; } - - case NET_RX_CN_LOW: - { - dbg(DBG_ASS, "%s: Receive Low Congestion\n", name); - break; - } - - case NET_RX_CN_MOD: - { - dbg(DBG_ASS, "%s: Receive Moderate Congestion\n", name); - break; - } - - case NET_RX_CN_HIGH: - { - dbg(DBG_ASS, "%s: Receive High Congestion\n", name); - break; - } - case NET_RX_DROP: { dbg(DBG_ASS, "%s: Received packet dropped\n", name); diff --git a/drivers/staging/otus/wrap_pkt.c b/drivers/staging/otus/wrap_pkt.c index 5db0004..89a6b92 100644 --- a/drivers/staging/otus/wrap_pkt.c +++ b/drivers/staging/otus/wrap_pkt.c @@ -156,10 +156,7 @@ void zfLnxRecvEth(zdev_t* dev, zbuf_t* buf, u16_t port) switch(netif_rx(buf)) #endif { - case NET_RX_BAD: case NET_RX_DROP: - case NET_RX_CN_MOD: - case NET_RX_CN_HIGH: break; default: macp->drv_stats.net_stats.rx_packets++; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d4a4d98..9f25ab2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -72,10 +72,6 @@ struct wireless_dev; /* Backlog congestion levels */ #define NET_RX_SUCCESS 0 /* keep 'em coming, baby */ #define NET_RX_DROP 1 /* packet dropped */ -#define NET_RX_CN_LOW 2 /* storm alert, just in case */ -#define NET_RX_CN_MOD 3 /* Storm on its way! */ -#define NET_RX_CN_HIGH 4 /* The storm is here */ -#define NET_RX_BAD 5 /* packet dropped due to kernel error */ /* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It * indicates that the device will soon be dropping packets, or already drops diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 1d6ca8a..9383d3e 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -774,7 +774,7 @@ static int dn_rt_bug(struct sk_buff *skb) kfree_skb(skb); - return NET_RX_BAD; + return NET_RX_DROP; } static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) diff --git a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c index 2ba1bc4..bda96d1 100644 --- a/net/lapb/lapb_iface.c +++ b/net/lapb/lapb_iface.c @@ -407,7 +407,7 @@ int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb) return lapb->callbacks.data_indication(lapb->dev, skb); kfree_skb(skb); - return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */ + return NET_RX_SUCCESS; /* For now; must be != NET_RX_DROP */ } int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb) -- cgit v0.10.2 From 6ed106549d17474ca17a16057f4c0ed4eba5a7ca Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 23 Jun 2009 06:03:08 +0000 Subject: net: use NETDEV_TX_OK instead of 0 in ndo_start_xmit() functions This patch is the result of an automatic spatch transformation to convert all ndo_start_xmit() return values of 0 to NETDEV_TX_OK. Some occurences are missed by the automatic conversion, those will be handled in a seperate patch. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index e4d8fde..7e81966 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -412,7 +412,7 @@ simeth_tx(struct sk_buff *skb, struct net_device *dev) */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static inline struct sk_buff * diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 3b44b47..4c75409 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -245,7 +245,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void uml_net_set_multicast_list(struct net_device *dev) diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 0384144..14045a7 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -132,7 +132,7 @@ static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev) /* FIXME: do hardware work here ... */ - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index de4aad0..8209ed6 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1202,7 +1202,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) { isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (lp->phone[1]) { ulong flags; @@ -1215,7 +1215,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) if(time_before(jiffies, lp->dialwait_timer)) { isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else lp->dialwait_timer = 0; } @@ -1243,7 +1243,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_unreachable(ndev, skb, "No channel"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* Log packet, which triggered dialing */ if (dev->net_verbose) @@ -1258,7 +1258,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) dev_kfree_skb(skb); isdn_net_unbind_channel(lp); spin_unlock_irqrestore(&dev->lock, flags); - return 0; /* STN (skb to nirvana) ;) */ + return NETDEV_TX_OK; /* STN (skb to nirvana) ;) */ } #ifdef CONFIG_IPPP_FILTER if (isdn_ppp_autodial_filter(skb, lp)) { @@ -1267,7 +1267,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&dev->lock, flags); isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } #endif spin_unlock_irqrestore(&dev->lock, flags); @@ -1285,7 +1285,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_unreachable(ndev, skb, "No phone number"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } } else { /* Device is connected to an ISDN channel */ diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 8280f8d..8c9ae0a 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -904,7 +904,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index a9e48e2..bc2ec21 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -795,7 +795,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) IOC_AND_NETDEV_NAMES_s_s(dev), le32_to_cpu(pSimple->FlagsLength))); - return 0; + return NETDEV_TX_OK; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 8d1c60a..b681bf8 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -436,7 +436,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->data[0] == 0x33) { dev_kfree_skb(skb); - return 0; /* nothing needed to be done */ + return NETDEV_TX_OK; /* nothing needed to be done */ } /* @@ -503,7 +503,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index f71b354..7bba480 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1101,7 +1101,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) prime_rx(dev); spin_unlock_irqrestore(&adapter->lock, flags); netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } /****************************************************** diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 96b8665..9e93a0b 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -537,7 +537,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev) /* You might need to clean up and record Tx statistics here. */ - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index d2137ef..d2515d8 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -892,7 +892,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev) outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ } } - return 0; + return NETDEV_TX_OK; } /* The EL3 interrupt handler. */ diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 3e00fa8..85ffd13 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -1054,7 +1054,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, netif_wake_queue(dev); } dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* Put out the doubleword header... */ outl(skb->len, ioaddr + TX_FIFO); @@ -1117,7 +1117,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index cdd955c..70c701b 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -1198,7 +1198,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) netif_wake_queue(dev); dev_kfree_skb(skb); #endif - return 0; + return NETDEV_TX_OK; } /******************************************* diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index aaa8a9f..72b9ed7 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1035,7 +1035,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb_padto(skb, ETH_ZLEN)) { netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } atomic_dec(&lp->tx_count); @@ -1066,7 +1066,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) p->control &= ~CONTROL_EOL; netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index c34aee9..2020484 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2083,7 +2083,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } } - return 0; + return NETDEV_TX_OK; } static int @@ -2173,7 +2173,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) iowrite16(DownUnstall, ioaddr + EL3_CMD); spin_unlock_irqrestore(&vp->lock, flags); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 50efde1..07919d0 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -891,7 +891,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) cpw8(TxPoll, NormalTxPoll); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* Set or clear the multicast filter for this adaptor. diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 8ae72ec..1a223cd 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1706,7 +1706,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) } else { dev_kfree_skb(skb); dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&tp->lock, flags); @@ -1731,7 +1731,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) pr_debug("%s: Queued Tx packet size %u to slot %d.\n", dev->name, len, entry); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 7754754..996cc91 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1068,7 +1068,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } netif_stop_queue(dev); @@ -1110,7 +1110,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } static void print_eth(unsigned char *add, char *str) diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 19831bd..61ac671 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1346,7 +1346,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) netif_stop_queue(dev); } spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* This function returns all the memory mapped registers of the device. diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 7f83254..29b279f 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -920,7 +920,7 @@ static int cops_send_packet(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 78cea5e..6cfd961 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -132,7 +132,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) } if(rt == NULL) { spin_unlock(&ipddp_route_lock); - return 0; + return NETDEV_TX_OK; } our_addr = atalk_find_dev_addr(rt->dev); @@ -181,7 +181,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&ipddp_route_lock); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index b642647..c80fb9c 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -932,7 +932,7 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* initialization stuff */ diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 58e8d52..47d976c 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -610,7 +610,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; len = ETH_ZLEN; } @@ -685,7 +685,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) } local_irq_restore(flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 627bc75..164b37e 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -482,7 +482,7 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 2e7419a..d46a06e 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -834,7 +834,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) we free and return(0) or don't free and return 1 */ } - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index edf770f..e47c0d9 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -748,7 +748,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); out: - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 4550371..1f7a69c 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -511,7 +511,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); priv(dev)->stats.tx_dropped ++; netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } length = (length + 1) & ~1; @@ -562,7 +562,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); out: - return 0; + return NETDEV_TX_OK; } static irqreturn_t diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 18b566a..c2227d7 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -643,7 +643,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev) netif_start_queue (dev); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 5425ab0..0c0dece 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -796,7 +796,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) if (len > skb->len) { if (skb_padto(skb, len)) - return 0; + return NETDEV_TX_OK; } netif_stop_queue (dev); @@ -846,7 +846,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) lp->tx_full = 1; spin_unlock_irqrestore (&lp->devlock, flags); - return 0; + return NETDEV_TX_OK; } /* The LANCE interrupt handler. */ diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 4317b3e..4beacc9 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -587,7 +587,7 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index d3c734f..2aab1eb 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -988,7 +988,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index c15fc28..f580b21 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -656,7 +656,7 @@ out: dev->trans_start = jiffies; dev->stats.tx_packets++; dev->stats.tx_bytes += (skb->len); - return 0; + return NETDEV_TX_OK; } static void bfin_mac_rx(struct net_device *dev) diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 9578a3d..4160001 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1488,7 +1488,7 @@ bmac_output(struct sk_buff *skb, struct net_device *dev) struct bmac_data *bp = netdev_priv(dev); skb_queue_tail(bp->queue, skb); bmac_start(dev); - return 0; + return NETDEV_TX_OK; } static void bmac_tx_timeout(unsigned long data) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 571f133..1c30dbe 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -283,7 +283,7 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) priv->write_reg(priv, REG_CMR, CMD_TR); - return 0; + return NETDEV_TX_OK; } static void sja1000_rx(struct net_device *dev) diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index eb06667..299a33b 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2928,7 +2928,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) static int ring; if (skb_padto(skb, cp->min_frame_size)) - return 0; + return NETDEV_TX_OK; /* XXX: we need some higher-level QoS hooks to steer packets to * individual queues. @@ -2936,7 +2936,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb)) return NETDEV_TX_BUSY; dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void cas_init_tx_dma(struct cas *cp) diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 7a18dc7..15c0195 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -1108,7 +1108,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&np->lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 3eee666..b5f553a 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1571,7 +1571,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) * to restart the netdevice layer */ - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/de600.c b/drivers/net/de600.c index e1af089..6b13f4f 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -226,7 +226,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev) } spin_unlock_irqrestore(&de600_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/de620.c b/drivers/net/de620.c index 55d2bb6..45794f6 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -542,7 +542,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; spin_unlock_irqrestore(&de620_lock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /***************************************************** diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 2b22e58..a31696a 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -902,7 +902,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) if (len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; len = ETH_ZLEN; } @@ -933,7 +933,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void lance_load_multicast(struct net_device *dev) diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index dd771de..ffd9edc 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -788,7 +788,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) /* free this SKB */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c index 33fa9ee..2818d5d 100644 --- a/drivers/net/dnet.c +++ b/drivers/net/dnet.c @@ -596,7 +596,7 @@ static int dnet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void dnet_reset_hw(struct dnet *bp) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 8ebd7d7..713ce6c 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -85,7 +85,7 @@ static int dummy_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index efa680f..a150d58 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1720,7 +1720,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } netdev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static int e100_tx_clean(struct nic *nic) diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index cc2ab64..71605d6 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1145,7 +1145,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } netif_stop_queue (dev); @@ -1178,7 +1178,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) eepro_en_int(ioaddr); spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 1686dca..8c44ef4 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -664,7 +664,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) if (buf->len < ETH_ZLEN) { if (skb_padto(buf, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -691,7 +691,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); #endif enable_irq(dev->irq); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index fc6cc03..372d6c6 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1299,7 +1299,7 @@ static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev) priv->tx_skb = skb; schedule_work(&priv->tx_work); - return 0; + return NETDEV_TX_OK; } static void enc28j60_tx_work_handler(struct work_struct *work) diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index b60e27d..d6a7aa3 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -970,7 +970,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; /* Caution: the write order is important here, set the field with the "ownership" bit last. */ @@ -1014,7 +1014,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, (int)skb->len, entry, ctrl_word, (int)inl(dev->base_addr + TxSTAT)); - return 0; + return NETDEV_TX_OK; } static void epic_tx_error(struct net_device *dev, struct epic_private *ep, diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 19b7dd9..c0e69c5 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -348,7 +348,7 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&eql->queue.lock); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 0d8b6da..97d5205 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1064,7 +1064,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } buf = skb->data; @@ -1126,7 +1126,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */ status = 0; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void eth16i_rx(struct net_device *dev) diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 1e97232..9c51bc8 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -868,7 +868,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev) if (inb (EWRK3_FMQC) == 0) netif_stop_queue (dev); - return 0; + return NETDEV_TX_OK; err_out: ENABLE_IRQs; diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 891be28..75e5fe5 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1374,7 +1374,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&np->lock, flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 0f19b74..08f1edb 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -366,7 +366,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&fep->hw_lock, flags); - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 9d5b62c..4e8d372 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1369,7 +1369,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n", dev->name, hmp->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 1551600..e88209f 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -255,7 +255,7 @@ static int sp_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int sp_open_dev(struct net_device *dev) diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 5e4b7af..e229edf 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -774,18 +774,18 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb->data[0] != 0) { do_kiss_params(bc, skb->data, skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (bc->skb) return NETDEV_TX_LOCKED; /* strip KISS byte */ if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); bc->skb = skb; - return 0; + return NETDEV_TX_OK; } /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index abcd19a..4c5f4df 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -305,7 +305,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) dev_queue_xmit(skb); netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 7459b3a..950f3bb 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -959,7 +959,7 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->ring_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index d034f8c..16b060b 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -406,13 +406,13 @@ static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb->data[0] != 0) { do_kiss_params(sm, skb->data, skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (sm->skb) return NETDEV_TX_LOCKED; netif_stop_queue(dev); sm->skb = skb; - return 0; + return NETDEV_TX_OK; } /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index fda2fc8..ac191ef 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -560,7 +560,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) kfree_skb(skb); } - return 0; + return NETDEV_TX_OK; } static int ax_open_dev(struct net_device *dev) diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index d712e7a..c540652 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1643,7 +1643,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) if (skb->len > scc->stat.bufsize || skb->len < 2) { scc->dev_stat.tx_dropped++; /* bogus frame */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } scc->dev_stat.tx_packets++; @@ -1656,7 +1656,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) if (kisscmd) { scc_set_param(scc, kisscmd, *skb->data); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&scc->lock, flags); @@ -1684,7 +1684,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) __scc_start_tx_timer(scc, t_dwait, 0); } spin_unlock_irqrestore(&scc->lock, flags); - return 0; + return NETDEV_TX_OK; } /* ----> ioctl functions <---- */ diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index b066919..b85aa16 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -600,7 +600,7 @@ static int yam_send_packet(struct sk_buff *skb, struct net_device *dev) skb_queue_tail(&yp->send_queue, skb); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void yam_start_tx(struct net_device *dev, struct yam_port *yp) diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 1d3429a..d1b6338 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1499,7 +1499,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) goto drop; if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; /* Get Tx ring tail pointer */ if (lp->txrtail->next == lp->txrhead) { @@ -1585,7 +1585,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; drop: dev_kfree_skb(skb); @@ -1752,7 +1752,7 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev) printk("hp100: %s: start_xmit: end\n", dev->name); #endif - return 0; + return NETDEV_TX_OK; drop: dev_kfree_skb(skb); diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 0995c43..76b295a 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -971,7 +971,7 @@ out: spin_lock_irqsave(&adapter->stats_lock, flags); spin_unlock_irqrestore(&adapter->stats_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int ibmveth_poll(struct napi_struct *napi, int budget) diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index e3cfefa..8ec15ab 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1515,7 +1515,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&ip->ioc3_lock); - return 0; + return NETDEV_TX_OK; } static void ioc3_timeout(struct net_device *dev) diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index ad17955..7098357 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -1466,7 +1466,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -1577,7 +1577,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); - return 0; + return NETDEV_TX_OK; } @@ -1991,7 +1991,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -2015,7 +2015,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index c4361d4..22baf65 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -502,7 +502,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) aup->newspeed = 0; } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } ptxd = aup->tx_ring[aup->tx_head]; @@ -555,7 +555,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 9a0346e..1484c76 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -1021,7 +1021,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) { spin_unlock_irqrestore(&self->spinlock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* True packet, go on, but */ /* do not accept anything before change speed execution */ @@ -1036,7 +1036,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) toshoboe_setbaud (self); spin_unlock_irqrestore(&self->spinlock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } } @@ -1143,7 +1143,7 @@ dumpbufs(skb->data,skb->len,'>'); spin_unlock_irqrestore(&self->spinlock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /*interrupt handler */ diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 0c0831c..6a1aa7a 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -534,7 +534,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) } spin_unlock_irqrestore(&self->lock, flags); - return 0; + return NETDEV_TX_OK; drop: /* Drop silently the skb and exit */ diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 45fd9c1..05bfc98 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -1397,7 +1397,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -1424,7 +1424,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) @@ -1467,7 +1467,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else { /* Change speed after current frame */ self->new_speed = speed; @@ -1554,7 +1554,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index 3376a4f..e76a083 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -504,7 +504,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) pxa_irda_set_speed(si, speed); } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -539,7 +539,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 2aeb2e6..70e6acc 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -667,7 +667,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) sa1100_irda_set_speed(si, speed); } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (!IS_FIR(si)) { @@ -715,7 +715,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static int diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index fd0796c..bde004f 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -621,7 +621,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) */ dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } else dev->new_speed = speed; } @@ -668,7 +668,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) } spin_unlock_irqrestore(&dev->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } /* called from network layer with rtnl hold */ diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 8e5e45c..c475b23 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -578,7 +578,7 @@ static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); } - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 8647985..62ba94b 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -844,7 +844,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, via_ircc_change_speed(self, speed); dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -892,7 +892,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int via_ircc_hard_xmit_fir(struct sk_buff *skb, @@ -907,7 +907,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, iobase = self->io.fir_base; if (self->st_fifo.len) - return 0; + return NETDEV_TX_OK; if (self->chip_id == 0x3076) iodelay(1500); else @@ -919,7 +919,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, via_ircc_change_speed(self, speed); dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -940,7 +940,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, dev->trans_start = jiffies; dev_kfree_skb(skb); spin_unlock_irqrestore(&self->lock, flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index ac0e4b6..08e26f1 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -915,7 +915,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) */ spin_unlock_irqrestore(&idev->lock, flags); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } /* sanity checks - simply drop the packet */ @@ -1044,7 +1044,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) } spin_unlock_irqrestore(&idev->lock, flags); - return 0; + return NETDEV_TX_OK; drop_unlock: spin_unlock_irqrestore(&idev->lock, flags); @@ -1058,7 +1058,7 @@ drop: * packet for later retry of transmission - which isn't exactly * what we want after we've just called dev_kfree_skb_any ;-) */ - return 0; + return NETDEV_TX_OK; } static void vlsi_tx_interrupt(struct net_device *ndev) diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index d088383..49ef763 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -516,7 +516,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) w83977af_change_speed(self, speed); dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -576,7 +576,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Restore set register */ outb(set, iobase+SSR); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 73585fd..86d2300 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -467,7 +467,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); #endif - return 0; + return NETDEV_TX_OK; } #if TX_RING diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index e44215c..e36e951 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1205,7 +1205,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev) if ( ! ((1 << rlp) & port->lpar_map) ) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } lpmask = 1 << rlp; @@ -1217,7 +1217,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* You must hold the connection's lock when you call this function. */ diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 9c897cf..eb917f1 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1459,7 +1459,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (skb->len <= 0) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (unlikely(ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 2a0174b..588b44d 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -45,7 +45,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len > PAGE_SIZE)) { /* @@@ Count drops. */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } entry = tx_pointer; @@ -69,7 +69,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); local_irq_enable(); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 633808d..30fd4f5 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -1016,7 +1016,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) out: spin_unlock_irqrestore(&lp->devlock, flags); - return 0; + return NETDEV_TX_OK; } /* The LANCE interrupt handler. */ diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index 070fa45..51e11c3 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -983,7 +983,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -1028,7 +1028,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } static void print_eth(unsigned char *add, char *str) diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 96e7248..da8d0a0 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -591,7 +591,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* Kick off the transfer */ temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */ - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index da472c6..51bbce7 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -89,7 +89,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) } else lb_stats->drops++; - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *loopback_get_stats(struct net_device *dev) diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index d44bddb..c292bad 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -871,7 +871,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -906,7 +906,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { dev->stats.tx_packets++; } - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index dab4533..149e0ed 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -411,7 +411,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 5b5c253..d22952c 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -678,7 +678,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void macb_free_consistent(struct macb *bp) diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 1427755..7d7577b 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -581,7 +581,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&mp->lock, flags); - return 0; + return NETDEV_TX_OK; } static void mace_set_multicast(struct net_device *dev) diff --git a/drivers/net/meth.c b/drivers/net/meth.c index 5d04d94..abea35d 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -715,7 +715,7 @@ static int meth_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->meth_lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index b3b9a14..8ea98bd 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -141,7 +141,7 @@ static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); mipsnet_put_todevice(dev, skb); - return 0; + return NETDEV_TX_OK; } static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t len) diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1f6e36e..05cd24d 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2748,7 +2748,7 @@ again: /* The packet is gone, so we must * return 0 */ ss->stats.tx_dropped += 1; - return 0; + return NETDEV_TX_OK; } /* adjust the len to account for the zero pad * so that the nic can know how long it is */ @@ -2892,7 +2892,7 @@ again: tx->stop_queue++; netif_tx_stop_queue(netdev_queue); } - return 0; + return NETDEV_TX_OK; abort_linearize: /* Free any DMA resources we've alloced and clear out the skb @@ -2936,7 +2936,7 @@ abort_linearize: drop: dev_kfree_skb_any(skb); ss->stats.tx_dropped += 1; - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 5f0758b..29ebebc 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -692,7 +692,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) DTX(("tbusy=0, returning 0\n")); netif_start_queue(dev); spin_unlock_irqrestore(&mp->irq_lock, flags); - return 0; + return NETDEV_TX_OK; } /* Create the MyriNet MAC header for an arbitrary protocol layer diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index c9bfe4e..481aa2d 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -2125,7 +2125,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } static void netdev_tx_done(struct net_device *dev) diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 946366d..9f42354 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -134,7 +134,7 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irq(&priv->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void netx_eth_receive(struct net_device *ndev) diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 2a8da47..462d20f 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -463,7 +463,7 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev) hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len); dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 1f10ed6..81a0617 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -1216,7 +1216,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&p->ring_lock, flags); } - return 0; + return NETDEV_TX_OK; } static void set_multicast_list(struct net_device *dev) diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 8c1f698..e4a93b8 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1356,7 +1356,7 @@ static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev) DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index f35c609..a23aa87 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -806,7 +806,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) pop_tx_status(dev); spin_unlock_irqrestore(&lp->window_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* The EL3 interrupt handler. */ diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index ec7cf5a..a77417c 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -635,7 +635,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* The EL3 interrupt handler. */ diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 0e38d80..b5cfac7 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1179,7 +1179,7 @@ static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); dev->stats.tx_bytes += send_length; - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 479d5b4..434d940 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -865,7 +865,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -924,7 +924,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) } dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* fjn_start_xmit */ /*====================================================================*/ diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 02ef63e..0f8118a 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -990,7 +990,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* mace_start_xmit */ /* ---------------------------------------------------------------------------- diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 37e05d3..2f39244 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1399,7 +1399,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); smc->saved_skb = NULL; dev->stats.tx_dropped++; - return 0; /* Do not re-queue this packet. */ + return NETDEV_TX_OK; /* Do not re-queue this packet. */ } /* A packet is now waiting. */ smc->packets_waiting++; @@ -1422,7 +1422,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT); smc_hardware_send_packet(dev); /* Send the packet now.. */ spin_unlock_irqrestore(&smc->lock, flags); - return 0; + return NETDEV_TX_OK; } } @@ -1431,7 +1431,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT); spin_unlock_irqrestore(&smc->lock, flags); - return 0; + return NETDEV_TX_OK; } /*====================================================================== diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index ef37d22..eda7bf6 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1384,7 +1384,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) if (pktlen < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; pktlen = ETH_ZLEN; } @@ -1414,7 +1414,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev->stats.tx_bytes += pktlen; netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } /**************** diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 1c35e1d..955a87a 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -2536,7 +2536,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* The PCNET32 interrupt handler. */ diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 7a62f78..ef2e229 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -987,7 +987,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) schedule_work(&nl->immediate); spin_unlock_irq(&nl->lock); - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 639d11b..d0b9655 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -988,12 +988,12 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); skb_queue_tail(&ppp->file.xq, skb); ppp_xmit_process(ppp); - return 0; + return NETDEV_TX_OK; outf: kfree_skb(skb); ++dev->stats.tx_dropped; - return 0; + return NETDEV_TX_OK; } static int diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 74cdb6f..bc98e7f 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -203,7 +203,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&rnet->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid, diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 81dbcbb..d955346 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1466,7 +1466,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&rrpriv->lock, flags); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 458daa0..d4df933 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -4111,14 +4111,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len <= 0)) { DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } if (!is_s2io_card_up(sp)) { DBG_PRINT(TX_DBG, "%s: Card going down for reset\n", dev->name); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } queue = 0; @@ -4192,7 +4192,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) s2io_stop_tx_queue(sp, fifo->fifo_no); dev_kfree_skb(skb); spin_unlock_irqrestore(&fifo->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } offload_type = s2io_offload_type(skb); @@ -4304,14 +4304,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) if (sp->config.intr_type == MSI_X) tx_intr_handler(fifo); - return 0; + return NETDEV_TX_OK; pci_map_failed: stats->pci_map_fail_cnt++; s2io_stop_tx_queue(sp, fifo->fifo_no); stats->mem_freed += skb->truesize; dev_kfree_skb(skb); spin_unlock_irqrestore(&fifo->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index fc0e38b..6a81aec 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -1086,7 +1086,7 @@ sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name); /* sb1000 can't xmit datagrams */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* SB1000 interrupt handler. */ diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index d8c9cf1..4c2450b 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2091,7 +2091,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sc->sbm_lock, flags); - return 0; + return NETDEV_TX_OK; } /********************************************************************** diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index ebbbe09..7cc8bb8 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -401,7 +401,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } buf = skb->data; @@ -415,7 +415,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 5fb88ca..78f6008 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -594,7 +594,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) len = skb->len; if (len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; len = ETH_ZLEN; } @@ -642,7 +642,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&sp->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } static void timeout(struct net_device *dev) diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index a2d82dd..4c4dcbf 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1133,7 +1133,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) ndev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* device close function */ diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index a9a897b..61ceeaa 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1628,7 +1628,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) "to slot %d.\n", net_dev->name, skb->data, (int)skb->len, entry); - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 088fe26..0c31272 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -1091,7 +1091,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } // skfp_send_pkt diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 5c61d5f..899c4a2 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -484,12 +484,12 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&sl->lock); printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (sl->tty == NULL) { spin_unlock(&sl->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } sl_lock(sl); @@ -498,7 +498,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&sl->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index bc4976a..2a6b6de 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -553,7 +553,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_dropped++; spin_unlock_irqrestore(&lp->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } #ifdef SMC_USE_DMA @@ -566,7 +566,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->pending_tx_skb = skb; netif_stop_queue(dev); spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } else { DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name); lp->txdma_active = 1; @@ -577,7 +577,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) smc911x_hardware_send_pkt(dev); spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index e02471b..0a1b6f4 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -512,7 +512,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) { netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } length = ETH_ZLEN; } @@ -534,7 +534,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de lp->saved_skb = NULL; /* this IS an error, but, i don't want the skb saved */ netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } /* either way, a packet is waiting now */ lp->packets_waiting++; @@ -571,12 +571,12 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de SMC_ENABLE_INT( IM_ALLOC_INT ); PRINTK2((CARDNAME": memory allocation deferred. \n")); /* it's deferred, but I'll handle it later */ - return 0; + return NETDEV_TX_OK; } /* or YES! I can send the packet now.. */ smc_hardware_send_packet(dev); netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index fdcbaf8..2968c75 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -655,7 +655,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_errors++; dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } smc_special_lock(&lp->lock); @@ -692,7 +692,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) smc_hardware_send_pkt((unsigned long)dev); } - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 838cce8..1018349 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1311,7 +1311,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index 7bb2742..2f1eaaf 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -1015,7 +1015,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) if(skb->len > XMIT_BUFF_SIZE) { printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -1110,7 +1110,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); #endif } - return 0; + return NETDEV_TX_OK; } /******************************************* diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 534dfe3..0ca4241 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -562,7 +562,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) netif_start_queue(dev); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } @@ -648,7 +648,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) local_irq_restore(flags); - return 0; + return NETDEV_TX_OK; } /* The LANCE interrupt handler. */ diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 5017d7f..536cf7e 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -984,7 +984,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *bigmac_get_stats(struct net_device *dev) diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 545f81b..0df6332 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1091,7 +1091,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev) "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } /* Reset hardware tx and free all of tx buffers */ diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 4ef72919..008bd59 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2338,7 +2338,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; tx_add_log(hp, TXLOG_ACTION_TXMIT, 0); - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *happy_meal_get_stats(struct net_device *dev) diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index afc7b35..9d6fd47 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1163,7 +1163,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* taken from the depca driver */ diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index c6ec61e..dcefb60 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -621,7 +621,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void qe_set_multicast(struct net_device *dev) diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index d737f6b..1ce2da1 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -1509,7 +1509,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) */ spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } #define FATAL_ERROR_INT \ diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 384cb5e..70c9ec4 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1095,11 +1095,11 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", dev->name ); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } if (skb_padto(skb, TLAN_MIN_FRAME_SIZE)) - return 0; + return NETDEV_TX_OK; txlen = max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE); tail_list = priv->txList + priv->txTail; @@ -1150,7 +1150,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS ); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* TLan_StartTx */ diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index b40b6de..1787d52 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -1240,7 +1240,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; - return 0; + return NETDEV_TX_OK; } else { spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; return NETDEV_TX_BUSY; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 9d89611..6472ba5 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -1041,7 +1041,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev) writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); spin_unlock_irqrestore(&(ti->lock), flags); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /*****************************************************************************/ diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index b3715ef..d07e61a 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -1183,7 +1183,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); - return 0; + return NETDEV_TX_OK; } else { netif_stop_queue(dev); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 451b541..f73f4e6 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1052,7 +1052,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1); netif_wake_queue(dev); spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - return 0; + return NETDEV_TX_OK; } else { spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); return NETDEV_TX_BUSY; diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 81f054d..769af55 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -651,7 +651,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) dw32(TxPoll, NormalTxPoll); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* Set or clear the multicast filter for this adaptor. diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 2abb5d3..9d46638 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -690,7 +690,7 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void tulip_clean_tx_ring(struct tulip_private *tp) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 9277ce8..9074a34 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -582,7 +582,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len > MAX_PACKET_SIZE) { printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&db->lock, flags); @@ -624,7 +624,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* free this SKB */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 842b1a2..6bc7540 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1058,7 +1058,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } static void netdev_tx_done(struct net_device *dev) diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index c2ca9f4..22b6a23 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -434,7 +434,7 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev) card->transmit_used = nextdescriptor; leave("xircom-start_xmit - sent"); spin_unlock_irqrestore(&card->lock,flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b393536..c3927b4 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -398,12 +398,12 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) if (tun->flags & TUN_FASYNC) kill_fasync(&tun->fasync, SIGIO, POLL_IN); wake_up_interruptible(&tun->socket.wait); - return 0; + return NETDEV_TX_OK; drop: dev->stats.tx_dropped++; kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void tun_net_mclist(struct net_device *dev) diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index cf25eb4..2c26b45 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -909,7 +909,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) netif_wake_queue(dev); } - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 40c6eba..5ba9586 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3173,7 +3173,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) #endif spin_unlock_irq(&ugeth->lock); - return 0; + return NETDEV_TX_OK; } static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit) diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index b9dd425..7abdc4a 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -448,7 +448,7 @@ static int catc_start_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void catc_tx_timeout(struct net_device *netdev) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index f8c6d7e..ffe4106 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -780,7 +780,7 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net) netif_stop_queue(net); if (hso_get_activity(odev->parent) == -EAGAIN) { odev->skb_tx_buf = skb; - return 0; + return NETDEV_TX_OK; } /* log if asked */ diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index e013147..09a5bd3 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -829,7 +829,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) kaweth->stats.tx_errors++; netif_start_queue(net); spin_unlock_irq(&kaweth->device_lock); - return 0; + return NETDEV_TX_OK; } } @@ -864,7 +864,7 @@ skip: spin_unlock_irq(&kaweth->device_lock); - return 0; + return NETDEV_TX_OK; } /**************************************************************** diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 73acbd2..632d1ae 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -914,7 +914,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index fcc6fa0..bac8b77 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -753,7 +753,7 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) netdev->trans_start = jiffies; } - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 1097c72..f1d753d 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -189,17 +189,17 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev) rcv_stats->rx_packets++; netif_rx(skb); - return 0; + return NETDEV_TX_OK; tx_drop: kfree_skb(skb); stats->tx_dropped++; - return 0; + return NETDEV_TX_OK; rx_drop: kfree_skb(skb); rcv_stats->rx_dropped++; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index d3489a3..7152201 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1225,7 +1225,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) entry = rp->cur_tx % TX_RING_SIZE; if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; rp->tx_skbuff[entry] = skb; @@ -1237,7 +1237,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); rp->tx_skbuff[entry] = NULL; dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } /* Padding is not copied and so must be redone. */ @@ -1285,7 +1285,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, rp->cur_tx-1, entry); } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 3ba3595..42365e5 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2098,7 +2098,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef VELOCITY_ZERO_COPY_SUPPORT if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) { kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } #endif diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 6034497..fd0ebf7 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -1000,7 +1000,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) VXGE_COMPLETE_VPATH_TX(fifo); vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", dev->name, __func__, __LINE__); - return 0; + return NETDEV_TX_OK; _exit0: vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name); @@ -1024,7 +1024,7 @@ _exit2: spin_unlock_irqrestore(&fifo->tx_lock, flags); VXGE_COMPLETE_VPATH_TX(fifo); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index f525f9f..4ae9bd2 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -663,7 +663,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, free_packet: dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* Get Ethernet-style interface statistics. diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index bfa0161..52438c7 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -421,7 +421,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) GFP_ATOMIC)) { dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } skb_put(skb, pad); memset(skb->data + len, 0, pad); @@ -435,13 +435,13 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_compressed++; skb->dev = pvc->frad; dev_queue_xmit(skb); - return 0; + return NETDEV_TX_OK; } } dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static inline void fr_log_dlci_active(pvc_device *pvc) diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 3fb9dbc..545178e 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -465,7 +465,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) prepare_to_send( skb, p ); spin_unlock( &nl->lock ); netif_start_queue( dev ); - return 0; + return NETDEV_TX_OK; } } @@ -485,7 +485,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) prepare_to_send( skb, dev ); spin_unlock( &nl->lock ); - return 0; + return NETDEV_TX_OK; } #endif /* CONFIG_SBNI_MULTILINE */ diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index d67e208..1047920 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -308,7 +308,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } switch (skb->data[0]) { @@ -319,14 +319,14 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) if (err != LAPB_OK) printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; case 0x02: /* Disconnect request .. do nothing - hang up ?? */ err = lapb_disconnect_request(dev); if (err != LAPB_OK) printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err); default: kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } skb_pull(skb, 1); /* Remove control byte */ /* @@ -344,9 +344,9 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) if (err != LAPB_OK) { printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index c70604f..49f3139 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1927,7 +1927,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { if (!skb) { airo_print_err(dev->name, "%s: skb == NULL!",__func__); - return 0; + return NETDEV_TX_OK; } npacks = skb_queue_len (&ai->txq); @@ -1938,7 +1938,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { return NETDEV_TX_BUSY; } skb_queue_tail (&ai->txq, skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&ai->aux_lock, flags); @@ -1951,7 +1951,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { set_bit(FLAG_PENDING_XMIT, &ai->flags); mpi_send_packet (dev); } - return 0; + return NETDEV_TX_OK; } /* @@ -2127,7 +2127,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { if ( skb == NULL ) { airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return 0; + return NETDEV_TX_OK; } /* Find a vacant FID */ @@ -2155,7 +2155,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { wake_up_interruptible(&priv->thr_wait); } else airo_end_xmit(dev); - return 0; + return NETDEV_TX_OK; } static void airo_end_xmit11(struct net_device *dev) { @@ -2199,7 +2199,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { if ( skb == NULL ) { airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return 0; + return NETDEV_TX_OK; } /* Find a vacant FID */ @@ -2227,7 +2227,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { wake_up_interruptible(&priv->thr_wait); } else airo_end_xmit11(dev); - return 0; + return NETDEV_TX_OK; } static void airo_read_stats(struct net_device *dev) diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index d84caf1..d479f47 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1193,7 +1193,7 @@ static int arlan_tx(struct sk_buff *skb, struct net_device *dev) arlan_process_interrupt(dev); ARLAN_DEBUG_EXIT("arlan_tx"); - return 0; + return NETDEV_TX_OK; bad_end: arlan_process_interrupt(dev); diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 291a94b..05813bc 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -793,13 +793,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) !(*priv->present_callback)(priv->card)) { dev->stats.tx_errors++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (priv->station_state != STATION_STATE_READY) { dev->stats.tx_errors++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* first ensure the timer func cannot run */ @@ -856,7 +856,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_bh(&priv->timerlock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void atmel_transmit_management_frame(struct atmel_private *priv, diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index e789c6e..55f77ad 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -314,7 +314,7 @@ static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev) { /* TODO: allow packet injection */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index d63c899..712f26e 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -1047,7 +1047,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) { } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* netwave_start_xmit */ /* diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index b10b038..64e574c 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -937,7 +937,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) { @@ -951,9 +951,9 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) default: dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } - return 0; + return NETDEV_TX_OK; } /* ray_dev_start_xmit */ /*===========================================================================*/ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 38366a5..73300c2 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1582,7 +1582,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev) if (skb) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 4430b8d9..dae1bfb 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -789,7 +789,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!zd->mac_enabled || zd->monitor) { dev->stats.tx_dropped++; kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -826,7 +826,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void zd1201_tx_timeout(struct net_device *dev) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 8d88dae..3700c49 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -558,12 +558,12 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&np->tx_lock); - return 0; + return NETDEV_TX_OK; drop: dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int xennet_close(struct net_device *dev) diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 3c7a505..c3722b4 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -827,7 +827,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb_padto(skb, len)) { yp->tx_skbuff[entry] = NULL; netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } } } @@ -881,7 +881,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n", dev->name, yp->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 0a6992d..7f9e141 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -546,7 +546,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -600,7 +600,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length); } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* The ZNET interrupt handler. */ diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 222e473..38b5079 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -880,7 +880,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) "%s(%s): NULL sk_buff passed", CTCM_FUNTAIL, dev->name); priv->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } if (skb_headroom(skb) < (LL_HEADER_LENGTH + 2)) { CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR, @@ -888,7 +888,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) CTCM_FUNTAIL, dev->name, LL_HEADER_LENGTH + 2); dev_kfree_skb(skb); priv->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } /* @@ -901,7 +901,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) priv->stats.tx_dropped++; priv->stats.tx_errors++; priv->stats.tx_carrier_errors++; - return 0; + return NETDEV_TX_OK; } if (ctcm_test_and_set_busy(dev)) @@ -910,7 +910,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; if (ctcm_transmit_skb(priv->channel[WRITE], skb) != 0) return NETDEV_TX_BUSY; - return 0; + return NETDEV_TX_OK; } /* unmerged MPC variant of ctcm_tx */ @@ -1008,7 +1008,7 @@ done: if (do_debug) MPC_DBF_DEV_NAME(TRACE, dev, "exit"); - return 0; /* handle freeing of skb here */ + return NETDEV_TX_OK; /* handle freeing of skb here */ } diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c index 3f303ae..7b8aa5e 100644 --- a/drivers/staging/at76_usb/at76_usb.c +++ b/drivers/staging/at76_usb/at76_usb.c @@ -3134,7 +3134,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) netdev->name, __func__); /* skip this packet */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (priv->tx_urb->status == -EINPROGRESS) { @@ -3142,14 +3142,14 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) netdev->name, __func__); /* skip this packet */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (skb->len < ETH_HLEN) { printk(KERN_ERR "%s: %s: skb too short (%d)\n", netdev->name, __func__, skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */ @@ -3173,7 +3173,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) skb->data[ETH_HLEN + 1], skb->data[ETH_HLEN + 2]); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } } else { /* add RFC 1042 header in front */ diff --git a/drivers/staging/epl/VirtualEthernetLinux.c b/drivers/staging/epl/VirtualEthernetLinux.c index 077724a..7b7cce1 100644 --- a/drivers/staging/epl/VirtualEthernetLinux.c +++ b/drivers/staging/epl/VirtualEthernetLinux.c @@ -223,7 +223,7 @@ static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p) } Exit: - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/staging/otus/usbdrv.c b/drivers/staging/otus/usbdrv.c index 540cbbb..7cd87ca 100644 --- a/drivers/staging/otus/usbdrv.c +++ b/drivers/staging/otus/usbdrv.c @@ -659,7 +659,7 @@ int usbdrv_xmit_frame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - return 0; + return NETDEV_TX_OK; } @@ -796,13 +796,13 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev) if (vapId >= ZM_VAP_PORT_NUMBER) { dev_kfree_skb_irq(skb); - return 0; + return NETDEV_TX_OK; } #if 1 if (vap[vapId].openFlag == 0) { dev_kfree_skb_irq(skb); - return 0; + return NETDEV_TX_OK; } #endif @@ -819,7 +819,7 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - return 0; + return NETDEV_TX_OK; } static const struct net_device_ops vap_netdev_ops = { diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index ed47db5..b01a282 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -845,7 +845,7 @@ static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev) hcmd->paddrh, DONT_FLUSH); } xmit_done: - return 0; + return NETDEV_TX_OK; xmit_fail: slic_xmit_fail(adapter, skb, offloadcmd, skbtype, status); goto xmit_done; diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 96fb118..d17f108 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -256,7 +256,7 @@ out: dev_kfree_skb(skb); dev->stats.tx_dropped++; } - return 0; + return NETDEV_TX_OK; } static int pn_net_mtu(struct net_device *dev, int new_mtu) diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 016f63b..aac69b5 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -487,7 +487,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net) if (!in) { dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } /* apply outgoing CDC or RNDIS filters */ @@ -506,7 +506,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net) type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; if (!(cdc_filter & type)) { dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } } /* ignores USB_CDC_PACKET_TYPE_DIRECTED */ @@ -586,7 +586,7 @@ drop: list_add(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } - return 0; + return NETDEV_TX_OK; } /*-------------------------------------------------------------------------*/ diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 2912665f..848af11 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -238,7 +238,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) /* netif_stop_queue(dev); */ dev_kfree_skb(skb); read_unlock(&devs_lock); - return 0; + return NETDEV_TX_OK; } if (!br2684_xmit_vcc(skb, dev, brvcc)) { /* @@ -252,7 +252,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_fifo_errors++; } read_unlock(&devs_lock); - return 0; + return NETDEV_TX_OK; } /* diff --git a/net/atm/clip.c b/net/atm/clip.c index e65a3b1..64910bb 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -373,7 +373,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_ERR "clip_start_xmit: skb_dst(skb) == NULL\n"); dev_kfree_skb(skb); dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } if (!skb_dst(skb)->neighbour) { #if 0 @@ -387,7 +387,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n"); dev_kfree_skb(skb); dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } entry = NEIGH2ENTRY(skb_dst(skb)->neighbour); if (!entry->vccs) { @@ -402,7 +402,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); dev->stats.tx_dropped++; } - return 0; + return NETDEV_TX_OK; } pr_debug("neigh %p, vccs %p\n", entry, entry->vccs); ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc; @@ -421,14 +421,14 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */ if (old) { printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n"); - return 0; + return NETDEV_TX_OK; } dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; vcc->send(vcc, skb); if (atm_may_send(vcc, 0)) { entry->vccs->xoff = 0; - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&clip_priv->xoff_lock, flags); netif_stop_queue(dev); /* XOFF -> throttle immediately */ @@ -440,7 +440,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) of the brief netif_stop_queue. If this isn't true or if it changes, use netif_wake_queue instead. */ spin_unlock_irqrestore(&clip_priv->xoff_lock, flags); - return 0; + return NETDEV_TX_OK; } static int clip_mkip(struct atm_vcc *vcc, int timeout) diff --git a/net/atm/lec.c b/net/atm/lec.c index ff2e594..c463868 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -289,7 +289,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN); kfree_skb(skb); if (skb2 == NULL) - return 0; + return NETDEV_TX_OK; skb = skb2; } skb_push(skb, 2); @@ -307,7 +307,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN); kfree_skb(skb); if (skb2 == NULL) - return 0; + return NETDEV_TX_OK; skb = skb2; } #endif @@ -345,7 +345,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); if (skb2 == NULL) { dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } skb = skb2; } @@ -416,7 +416,7 @@ out: if (entry) lec_arp_put(entry); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* The inverse routine to net_open(). */ diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index d7a0e97..9c42990 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -175,14 +175,14 @@ static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef CONFIG_BT_BNEP_MC_FILTER if (bnep_net_mc_filter(skb, s)) { kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } #endif #ifdef CONFIG_BT_BNEP_PROTO_FILTER if (bnep_net_proto_filter(skb, s)) { kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } #endif @@ -203,7 +203,7 @@ static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - return 0; + return NETDEV_TX_OK; } static const struct net_device_ops bnep_netdev_ops = { diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 18538d7..15d43ba 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -39,7 +39,7 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) else br_flood_deliver(br, skb); - return 0; + return NETDEV_TX_OK; } static int br_dev_open(struct net_device *dev) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 44e2a3d..cd85ebc 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -821,7 +821,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_dropped++; dev_kfree_skb(skb); tunnel->recursion--; - return 0; + return NETDEV_TX_OK; } if (skb->sk) skb_set_owner_w(new_skb, skb->sk); @@ -889,7 +889,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) IPTUNNEL_XMIT(); tunnel->recursion--; - return 0; + return NETDEV_TX_OK; tx_error_icmp: dst_link_failure(skb); @@ -898,7 +898,7 @@ tx_error: stats->tx_errors++; dev_kfree_skb(skb); tunnel->recursion--; - return 0; + return NETDEV_TX_OK; } static int ipgre_tunnel_bind_dev(struct net_device *dev) diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 93e2b78..98075b6 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -486,7 +486,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_dropped++; dev_kfree_skb(skb); tunnel->recursion--; - return 0; + return NETDEV_TX_OK; } if (skb->sk) skb_set_owner_w(new_skb, skb->sk); @@ -524,7 +524,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) IPTUNNEL_XMIT(); tunnel->recursion--; - return 0; + return NETDEV_TX_OK; tx_error_icmp: dst_link_failure(skb); @@ -532,7 +532,7 @@ tx_error: stats->tx_errors++; dev_kfree_skb(skb); tunnel->recursion--; - return 0; + return NETDEV_TX_OK; } static void ipip_tunnel_bind_dev(struct net_device *dev) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 9a8da5e..06c33fb 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -212,7 +212,7 @@ static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) IGMPMSG_WHOLEPKT); read_unlock(&mrt_lock); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static const struct net_device_ops reg_vif_netdev_ops = { diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 51f410e..a1d6045 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1063,14 +1063,14 @@ ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_err; t->recursion--; - return 0; + return NETDEV_TX_OK; tx_err: stats->tx_errors++; stats->tx_dropped++; kfree_skb(skb); t->recursion--; - return 0; + return NETDEV_TX_OK; } static void ip6_tnl_set_cap(struct ip6_tnl *t) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index c769f15..07ded50 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -427,7 +427,7 @@ static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) MRT6MSG_WHOLEPKT); read_unlock(&mrt_lock); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static const struct net_device_ops reg_vif_netdev_ops = { diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 68e5230..d0b8505 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -753,7 +753,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_dropped++; dev_kfree_skb(skb); tunnel->recursion--; - return 0; + return NETDEV_TX_OK; } if (skb->sk) skb_set_owner_w(new_skb, skb->sk); @@ -794,7 +794,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) IPTUNNEL_XMIT(); tunnel->recursion--; - return 0; + return NETDEV_TX_OK; tx_error_icmp: dst_link_failure(skb); @@ -802,7 +802,7 @@ tx_error: stats->tx_errors++; dev_kfree_skb(skb); tunnel->recursion--; - return 0; + return NETDEV_TX_OK; } static void ipip6_tunnel_bind_dev(struct net_device *dev) diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 724bcf9..64230cf 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -177,7 +177,7 @@ static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev) /* Did the realloc succeed? */ if (new_skb == NULL) - return 0; + return NETDEV_TX_OK; /* Use the new skb instead */ skb = new_skb; @@ -209,7 +209,7 @@ static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev) self->stats.tx_bytes += skb->len; } - return 0; + return NETDEV_TX_OK; } /* diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c index 3513724..c7b7838 100644 --- a/net/netrom/nr_dev.c +++ b/net/netrom/nr_dev.c @@ -177,13 +177,13 @@ static int nr_xmit(struct sk_buff *skb, struct net_device *dev) if (!nr_route_frame(skb, NULL)) { kfree_skb(skb); stats->tx_errors++; - return 0; + return NETDEV_TX_OK; } stats->tx_packets++; stats->tx_bytes += len; - return 0; + return NETDEV_TX_OK; } static const struct header_ops nr_header_ops = { diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c index 480839d..4667af5 100644 --- a/net/phonet/pep-gprs.c +++ b/net/phonet/pep-gprs.c @@ -195,7 +195,7 @@ static int gprs_xmit(struct sk_buff *skb, struct net_device *dev) break; default: dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } skb_orphan(skb); @@ -215,7 +215,7 @@ static int gprs_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); if (pep_writeable(sk)) netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } static int gprs_set_mtu(struct net_device *dev, int new_mtu) diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c index 389d6e0..c711e2e 100644 --- a/net/rose/rose_dev.c +++ b/net/rose/rose_dev.c @@ -141,7 +141,7 @@ static int rose_xmit(struct sk_buff *skb, struct net_device *dev) } dev_kfree_skb(skb); stats->tx_errors++; - return 0; + return NETDEV_TX_OK; } static const struct header_ops rose_header_ops = { diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 9c002b6..12434b6 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -314,7 +314,7 @@ restart: netif_wake_queue(dev); txq->tx_packets++; txq->tx_bytes += length; - return 0; + return NETDEV_TX_OK; } __netif_tx_unlock(slave_txq); } @@ -323,7 +323,7 @@ restart: break; case 1: master->slaves = NEXT_SLAVE(q); - return 0; + return NETDEV_TX_OK; default: nores = 1; break; @@ -345,7 +345,7 @@ restart: drop: txq->tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int teql_master_open(struct net_device *dev) -- cgit v0.10.2 From 6f5bec195839dba3ca0ab8a7a53861e679109c0b Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Wed, 24 Jun 2009 21:05:09 +0000 Subject: Minor code cleanup in drivers/net/r6040.c Replaced '0' by 'bar' in the probe function. The 'bar' variable was already set to '0' and is already used in pci_iomap(). This is cleaner and improves code consistency. Signed-off-by: Michael Opdenacker Acked-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index ed63d23..b3197e9 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -1112,13 +1112,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, } /* IO Size check */ - if (pci_resource_len(pdev, 0) < io_size) { + if (pci_resource_len(pdev, bar) < io_size) { printk(KERN_ERR DRV_NAME ": Insufficient PCI resources, aborting\n"); err = -EIO; goto err_out; } - pioaddr = pci_resource_start(pdev, 0); /* IO map base address */ + pioaddr = pci_resource_start(pdev, bar); /* IO map base address */ pci_set_master(pdev); dev = alloc_etherdev(sizeof(struct r6040_private)); -- cgit v0.10.2 From af794c74240d8d788058bdfee339512e7ac029b2 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Thu, 25 Jun 2009 04:42:19 +0000 Subject: cleanup: remove unused member in scm_cookie. This patch removes an unused member (seq) scm_cookie; besides initialized to 0 in the header file, it is not used. Signed-off-by: Rami Rosen Signed-off-by: David S. Miller diff --git a/include/net/scm.h b/include/net/scm.h index f45bb6e..cf48c80 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -26,7 +26,6 @@ struct scm_cookie #ifdef CONFIG_SECURITY_NETWORK u32 secid; /* Passed security ID */ #endif - unsigned long seq; /* Connection seqno */ }; extern void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm); @@ -59,7 +58,6 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, scm->creds.gid = current_gid(); scm->creds.pid = task_tgid_vnr(p); scm->fp = NULL; - scm->seq = 0; unix_get_peersec_dgram(sock, scm); if (msg->msg_controllen <= 0) return 0; -- cgit v0.10.2 From 6650613d3387dcc30685e2781818ea7d0f840027 Mon Sep 17 00:00:00 2001 From: "oscar.medina@motorola.com" Date: Tue, 30 Jun 2009 03:25:39 +0000 Subject: tipc: Add socket options to get number of queued messages This patch allows a TIPC application to determine the number of messages currently waiting in a socket's receive queue (TIPC_SOCK_RECVQ_DEPTH) or in all TIPC socket receive queues (TIPC_NODE_RECVQ_DEPTH). Signed-off-by: Oscar Medina Signed-off-by: Allan Stephens Signed-off-by: David S. Miller diff --git a/include/linux/tipc.h b/include/linux/tipc.h index bea4694..3d92396 100644 --- a/include/linux/tipc.h +++ b/include/linux/tipc.h @@ -209,5 +209,7 @@ struct sockaddr_tipc { #define TIPC_SRC_DROPPABLE 128 /* Default: 0 (resend congested msg) */ #define TIPC_DEST_DROPPABLE 129 /* Default: based on socket type */ #define TIPC_CONN_TIMEOUT 130 /* Default: 8000 (ms) */ +#define TIPC_NODE_RECVQ_DEPTH 131 /* Default: none (read only) */ +#define TIPC_SOCK_RECVQ_DEPTH 132 /* Default: none (read only) */ #endif diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 1848693..e8254e8 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1748,6 +1748,12 @@ static int getsockopt(struct socket *sock, value = jiffies_to_msecs(sk->sk_rcvtimeo); /* no need to set "res", since already 0 at this point */ break; + case TIPC_NODE_RECVQ_DEPTH: + value = (u32)atomic_read(&tipc_queue_size); + break; + case TIPC_SOCK_RECVQ_DEPTH: + value = skb_queue_len(&sk->sk_receive_queue); + break; default: res = -EINVAL; } -- cgit v0.10.2 From 1490fd89474dab9c560d3cca1a4aefbdb89be247 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 3 Jul 2009 20:11:57 +0000 Subject: net, bridge: align br_nf_ops assignment No functional change -- just for easier reading. Signed-off-by: Cyrill Gorcunov Signed-off-by: David S. Miller diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index d22f611..4fde742 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -905,46 +905,62 @@ static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff *skb, * For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because * ip_refrag() can return NF_STOLEN. */ static struct nf_hook_ops br_nf_ops[] __read_mostly = { - { .hook = br_nf_pre_routing, - .owner = THIS_MODULE, - .pf = PF_BRIDGE, - .hooknum = NF_BR_PRE_ROUTING, - .priority = NF_BR_PRI_BRNF, }, - { .hook = br_nf_local_in, - .owner = THIS_MODULE, - .pf = PF_BRIDGE, - .hooknum = NF_BR_LOCAL_IN, - .priority = NF_BR_PRI_BRNF, }, - { .hook = br_nf_forward_ip, - .owner = THIS_MODULE, - .pf = PF_BRIDGE, - .hooknum = NF_BR_FORWARD, - .priority = NF_BR_PRI_BRNF - 1, }, - { .hook = br_nf_forward_arp, - .owner = THIS_MODULE, - .pf = PF_BRIDGE, - .hooknum = NF_BR_FORWARD, - .priority = NF_BR_PRI_BRNF, }, - { .hook = br_nf_local_out, - .owner = THIS_MODULE, - .pf = PF_BRIDGE, - .hooknum = NF_BR_LOCAL_OUT, - .priority = NF_BR_PRI_FIRST, }, - { .hook = br_nf_post_routing, - .owner = THIS_MODULE, - .pf = PF_BRIDGE, - .hooknum = NF_BR_POST_ROUTING, - .priority = NF_BR_PRI_LAST, }, - { .hook = ip_sabotage_in, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_INET_PRE_ROUTING, - .priority = NF_IP_PRI_FIRST, }, - { .hook = ip_sabotage_in, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_INET_PRE_ROUTING, - .priority = NF_IP6_PRI_FIRST, }, + { + .hook = br_nf_pre_routing, + .owner = THIS_MODULE, + .pf = PF_BRIDGE, + .hooknum = NF_BR_PRE_ROUTING, + .priority = NF_BR_PRI_BRNF, + }, + { + .hook = br_nf_local_in, + .owner = THIS_MODULE, + .pf = PF_BRIDGE, + .hooknum = NF_BR_LOCAL_IN, + .priority = NF_BR_PRI_BRNF, + }, + { + .hook = br_nf_forward_ip, + .owner = THIS_MODULE, + .pf = PF_BRIDGE, + .hooknum = NF_BR_FORWARD, + .priority = NF_BR_PRI_BRNF - 1, + }, + { + .hook = br_nf_forward_arp, + .owner = THIS_MODULE, + .pf = PF_BRIDGE, + .hooknum = NF_BR_FORWARD, + .priority = NF_BR_PRI_BRNF, + }, + { + .hook = br_nf_local_out, + .owner = THIS_MODULE, + .pf = PF_BRIDGE, + .hooknum = NF_BR_LOCAL_OUT, + .priority = NF_BR_PRI_FIRST, + }, + { + .hook = br_nf_post_routing, + .owner = THIS_MODULE, + .pf = PF_BRIDGE, + .hooknum = NF_BR_POST_ROUTING, + .priority = NF_BR_PRI_LAST, + }, + { + .hook = ip_sabotage_in, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_INET_PRE_ROUTING, + .priority = NF_IP_PRI_FIRST, + }, + { + .hook = ip_sabotage_in, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_INET_PRE_ROUTING, + .priority = NF_IP6_PRI_FIRST, + }, }; #ifdef CONFIG_SYSCTL -- cgit v0.10.2 From e04af024b2e74249990587e76ec98220028c01c3 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 3 Jul 2009 20:11:58 +0000 Subject: net, netns_xt: shrink netns_xt members In case if kernel was compiled without ebtables support there is no need to keep ebt_table pointers in netns_xt structure. Make it config dependent. Signed-off-by: Cyrill Gorcunov Signed-off-by: David S. Miller diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h index 9554a64..591db7d 100644 --- a/include/net/netns/x_tables.h +++ b/include/net/netns/x_tables.h @@ -8,8 +8,11 @@ struct ebt_table; struct netns_xt { struct list_head tables[NFPROTO_NUMPROTO]; +#if defined(CONFIG_BRIDGE_NF_EBTABLES) || \ + defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE) struct ebt_table *broute_table; struct ebt_table *frame_filter; struct ebt_table *frame_nat; +#endif }; #endif -- cgit v0.10.2 From 7975d1eed732c9d50b41f5847453e324f544bd30 Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:12:23 +0000 Subject: vxge: Removed ioremap of unused bar addresses and their references - Removed ioremap of bar1 address Driver needs only bar0 address for register access - Removed references to bar1 and bar2 addresses Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 58d2551..9e94c4b 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -313,14 +313,6 @@ __vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev) hldev->kdfc = (u8 __iomem *)(hldev->bar0 + VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); break; - case 2: - hldev->kdfc = (u8 __iomem *)(hldev->bar1 + - VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); - break; - case 4: - hldev->kdfc = (u8 __iomem *)(hldev->bar2 + - VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); - break; default: break; } @@ -831,8 +823,6 @@ vxge_hw_device_initialize( sizeof(struct vxge_hw_device_config)); hldev->bar0 = attr->bar0; - hldev->bar1 = attr->bar1; - hldev->bar2 = attr->bar2; hldev->pdev = attr->pdev; hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up; diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index afbdf6f..224acea 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -682,8 +682,6 @@ struct __vxge_hw_vpath_handle{ * @major_revision: PCI Device major revision * @minor_revision: PCI Device minor revision * @bar0: BAR0 virtual address. - * @bar1: BAR1 virtual address. - * @bar2: BAR2 virtual address. * @pdev: Physical device handle * @config: Confguration passed by the LL driver at initialization * @link_state: Link state @@ -698,8 +696,6 @@ struct __vxge_hw_device { u8 major_revision; u8 minor_revision; void __iomem *bar0; - void __iomem *bar1; - void __iomem *bar2; struct pci_dev *pdev; struct net_device *ndev; struct vxge_hw_device_config config; @@ -788,17 +784,13 @@ struct vxge_hw_device_hw_info { /** * struct vxge_hw_device_attr - Device memory spaces. * @bar0: BAR0 virtual address. - * @bar1: BAR1 virtual address. - * @bar2: BAR2 virtual address. * @pdev: PCI device object. * - * Device memory spaces. Includes configuration, BAR0, BAR1, etc. per device + * Device memory spaces. Includes configuration, BAR0 etc. per device * mapped memories. Also, includes a pointer to OS-specific PCI device object. */ struct vxge_hw_device_attr { void __iomem *bar0; - void __iomem *bar1; - void __iomem *bar2; struct pci_dev *pdev; struct vxge_hw_uld_cbs uld_callbacks; }; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index fd0ebf7..8a3c7b3 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -4152,18 +4152,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) attr.bar0, (unsigned long long)pci_resource_start(pdev, 0)); - attr.bar1 = pci_ioremap_bar(pdev, 2); - if (!attr.bar1) { - vxge_debug_init(VXGE_ERR, - "%s : cannot remap io memory bar2", __func__); - ret = -ENODEV; - goto _exit3; - } - vxge_debug_ll_config(VXGE_TRACE, - "pci ioremap bar1: %p:0x%llx", - attr.bar1, - (unsigned long long)pci_resource_start(pdev, 2)); - status = vxge_hw_device_hw_info_get(attr.bar0, &ll_config.device_hw_info); if (status != VXGE_HW_OK) { @@ -4171,7 +4159,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) "%s: Reading of hardware info failed." "Please try upgrading the firmware.", VXGE_DRIVER_NAME); ret = -EINVAL; - goto _exit4; + goto _exit3; } if (ll_config.device_hw_info.fw_version.major != @@ -4181,7 +4169,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) ll_config.device_hw_info.fw_version.major, VXGE_DRIVER_VERSION_MAJOR); ret = -EINVAL; - goto _exit4; + goto _exit3; } vpath_mask = ll_config.device_hw_info.vpath_mask; @@ -4189,7 +4177,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vxge_debug_ll_config(VXGE_TRACE, "%s: No vpaths available in device", VXGE_DRIVER_NAME); ret = -EINVAL; - goto _exit4; + goto _exit3; } vxge_debug_ll_config(VXGE_TRACE, @@ -4222,7 +4210,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vxge_debug_ll_config(VXGE_ERR, "%s: No more vpaths to configure", VXGE_DRIVER_NAME); ret = 0; - goto _exit4; + goto _exit3; } /* Setting driver callbacks */ @@ -4235,7 +4223,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vxge_debug_init(VXGE_ERR, "Failed to initialize device (%d)", status); ret = -EINVAL; - goto _exit4; + goto _exit3; } vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL); @@ -4260,7 +4248,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath, &vdev)) { ret = -EINVAL; - goto _exit5; + goto _exit4; } vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL); @@ -4271,7 +4259,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) hldev->ndev = vdev->ndev; vdev->mtu = VXGE_HW_DEFAULT_MTU; vdev->bar0 = attr.bar0; - vdev->bar1 = attr.bar1; vdev->max_vpath_supported = max_vpath_supported; vdev->no_of_vpath = no_of_vpath; @@ -4353,7 +4340,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) "%s: mac_addr_list : memory allocation failed", vdev->ndev->name); ret = -EPERM; - goto _exit6; + goto _exit5; } macaddr = (u8 *)&entry->macaddr; memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN); @@ -4370,16 +4357,14 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) return 0; -_exit6: +_exit5: for (i = 0; i < vdev->no_of_vpath; i++) vxge_free_mac_add_list(&vdev->vpaths[i]); vxge_device_unregister(hldev); -_exit5: +_exit4: pci_disable_sriov(pdev); vxge_hw_device_terminate(hldev); -_exit4: - iounmap(attr.bar1); _exit3: iounmap(attr.bar0); _exit2: @@ -4438,7 +4423,6 @@ vxge_remove(struct pci_dev *pdev) kfree(vdev->vpaths); iounmap(vdev->bar0); - iounmap(vdev->bar1); pci_disable_sriov(pdev); diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 9704b2b..3386970 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -363,7 +363,6 @@ struct vxgedev { struct __vxge_hw_vpath_handle *vp_handles[VXGE_HW_MAX_VIRTUAL_PATHS]; void __iomem *bar0; - void __iomem *bar1; struct vxge_sw_stats stats; int mtu; /* Below variables are used for vpath selection to transmit a packet */ -- cgit v0.10.2 From 914d0d714fa472d7f99ef899a8180628ecdcd23c Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:13:12 +0000 Subject: vxge: Fixed memory leak by freeing memory allocated for device_config - Fixed memory leak by freeing memory allocated for device_config. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 8a3c7b3..fa4dbc8 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -4348,6 +4348,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vdev->vpaths[i].mac_addr_cnt = 1; } + kfree(device_config); vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__); -- cgit v0.10.2 From bd9ee6808b6c9106fd8046693c544d081746184b Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:14:03 +0000 Subject: vxge: check for card status before continuing in device close - Fixed the crash in rmmod after vpath open failed when trying to change mtu. We should check for card status before continuing in device close. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index fa4dbc8..dd2add1 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -2890,6 +2890,9 @@ int do_vxge_close(struct net_device *dev, int do_io) vdev = (struct vxgedev *)netdev_priv(dev); hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); + if (unlikely(!is_vxge_card_up(vdev))) + return 0; + /* If vxge_handle_crit_err task is executing, * wait till it completes. */ while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) -- cgit v0.10.2 From 3255da416de6da8b3bac6d30b8eed61b54953480 Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:14:57 +0000 Subject: vxge: Corrected Register map entry for xmac_link registers - Corrected Register map entry for xmac_link registers. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h index 10f4da3..9a3b823 100644 --- a/drivers/net/vxge/vxge-reg.h +++ b/drivers/net/vxge/vxge-reg.h @@ -1784,7 +1784,7 @@ struct vxge_hw_mrpcim_reg { #define VXGE_HW_XMAC_GEN_ERR_REG_XMACJ_XMAC_FSM_ERR vxge_mBIT(63) /*0x01e18*/ u64 xmac_gen_err_mask; /*0x01e20*/ u64 xmac_gen_err_alarm; -/*0x01e28*/ u64 xmac_link_err_port_reg[2]; +/*0x01e28*/ u64 xmac_link_err_port0_reg; #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_DOWN vxge_mBIT(3) #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_UP vxge_mBIT(7) #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_DOWN vxge_mBIT(11) @@ -1798,8 +1798,11 @@ struct vxge_hw_mrpcim_reg { #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_LASI_INV vxge_mBIT(39) #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMDIO_MDIO_MGR_ACCESS_COMPLETE \ vxge_mBIT(47) -/*0x01e30*/ u64 xmac_link_err_port_mask[2]; -/*0x01e38*/ u64 xmac_link_err_port_alarm[2]; +/*0x01e30*/ u64 xmac_link_err_port0_mask; +/*0x01e38*/ u64 xmac_link_err_port0_alarm; +/*0x01e40*/ u64 xmac_link_err_port1_reg; +/*0x01e48*/ u64 xmac_link_err_port1_mask; +/*0x01e50*/ u64 xmac_link_err_port1_alarm; /*0x01e58*/ u64 xgxs_gen_err_reg; #define VXGE_HW_XGXS_GEN_ERR_REG_XGXS_XGXS_FSM_ERR vxge_mBIT(63) /*0x01e60*/ u64 xgxs_gen_err_mask; -- cgit v0.10.2 From 6052ae1676b705c67133542e663ec3380f032e2c Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:15:41 +0000 Subject: vxge: Removed the code to bounds check the mss value - Removed the code to bounds check the mss value. The hardware does bounds checking and will not allow an oversized mss to lockup the transmit path. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index dd2add1..cda18f8 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -817,7 +817,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) u64 dma_pointer; struct vxge_tx_priv *txdl_priv = NULL; struct __vxge_hw_fifo *fifo_hw; - u32 max_mss = 0x0; int offload_type; unsigned long flags = 0; int vpath_no = 0; @@ -969,10 +968,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) int mss = vxge_tcp_mss(skb); if (mss) { - max_mss = dev->mtu + ETH_HLEN - - VXGE_HW_TCPIP_HEADER_MAX_SIZE; - if (mss > max_mss) - mss = max_mss; vxge_debug_tx(VXGE_TRACE, "%s: %s:%d mss = %d", dev->name, __func__, __LINE__, mss); diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 7567a11..8260b91 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -35,8 +35,6 @@ VXGE_HW_HEADER_VLAN_SIZE + \ VXGE_HW_HEADER_SNAP_SIZE) -#define VXGE_HW_TCPIP_HEADER_MAX_SIZE (64 + 64) - /* 32bit alignments */ #define VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN 2 #define VXGE_HW_HEADER_802_2_SNAP_ALIGN 2 -- cgit v0.10.2 From a5d165b571fcf347e82af6292074d2f0c07de3a6 Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:16:37 +0000 Subject: vxge: Fixes in isr routine - Fixes in isr routine Fixed crash with INTA mode during driver unload. Pass hldev to request_irq instead of vdev. Fixed Traffic failure with GRO in INTA mode. Pass the correct napi context to gro functions. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index cda18f8..060549a 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -374,10 +374,10 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan, if (ring->vlgrp && ext_info->vlan && (ring->vlan_tag_strip == VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) - vlan_gro_receive(&ring->napi, ring->vlgrp, + vlan_gro_receive(ring->napi_p, ring->vlgrp, ext_info->vlan, skb); else - napi_gro_receive(&ring->napi, skb); + napi_gro_receive(ring->napi_p, skb); } else { if (ring->vlgrp && vlan && (ring->vlan_tag_strip == @@ -2132,16 +2132,16 @@ int vxge_open_vpaths(struct vxgedev *vdev) */ static irqreturn_t vxge_isr_napi(int irq, void *dev_id) { - struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)dev_id; - struct vxgedev *vdev; struct net_device *dev; + struct __vxge_hw_device *hldev; u64 reason; enum vxge_hw_status status; + struct vxgedev *vdev = (struct vxgedev *) dev_id;; vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__); - dev = hldev->ndev; - vdev = netdev_priv(dev); + dev = vdev->ndev; + hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); if (pci_channel_offline(vdev->pdev)) return IRQ_NONE; @@ -2412,15 +2412,13 @@ static void vxge_rem_isr(struct vxgedev *vdev) #endif if (vdev->config.intr_type == INTA) { synchronize_irq(vdev->pdev->irq); - free_irq(vdev->pdev->irq, hldev); + free_irq(vdev->pdev->irq, vdev); } } static int vxge_add_isr(struct vxgedev *vdev) { int ret = 0; - struct __vxge_hw_device *hldev = - (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); #ifdef CONFIG_PCI_MSI int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0; u64 function_mode = vdev->config.device_hw_info.function_mode; @@ -2574,7 +2572,7 @@ INTA_MODE: if (vdev->config.intr_type == INTA) { ret = request_irq((int) vdev->pdev->irq, vxge_isr_napi, - IRQF_SHARED, vdev->desc[0], hldev); + IRQF_SHARED, vdev->desc[0], vdev); if (ret) { vxge_debug_init(VXGE_ERR, "%s %s-%d: ISR registration failed", @@ -2707,11 +2705,15 @@ vxge_open(struct net_device *dev) netif_napi_add(dev, &vdev->napi, vxge_poll_inta, vdev->config.napi_weight); napi_enable(&vdev->napi); + for (i = 0; i < vdev->no_of_vpath; i++) + vdev->vpaths[i].ring.napi_p = &vdev->napi; } else { for (i = 0; i < vdev->no_of_vpath; i++) { netif_napi_add(dev, &vdev->vpaths[i].ring.napi, vxge_poll_msix, vdev->config.napi_weight); napi_enable(&vdev->vpaths[i].ring.napi); + vdev->vpaths[i].ring.napi_p = + &vdev->vpaths[i].ring.napi; } } diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 3386970..a46f7fe 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -260,6 +260,7 @@ struct vxge_ring { int gro_enable; struct napi_struct napi; + struct napi_struct *napi_p; #define VXGE_MAX_MAC_ADDR_COUNT 30 -- cgit v0.10.2 From 22fa125ee24f8db497fa447c145a4a1293fab098 Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:17:24 +0000 Subject: vxge: Disable fcs stripping. - Disable fcs stripping. The minimum frame size that can be received by the hardware is 57 Bytes. A 64 Byte Ethernet frame with the vlan tag and fcs stripped will result in a 56 Byte frame which will lock up the receive engine. The work around is to disable fcs stripping in the hardware which is done with a firmware upgrade. The fixes are - 1. Ensure that the correct firmware version is used. 2. Decrement the indicated packet length of the receive packet by 4 bytes (FCS length). Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 060549a..eaf916b 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -454,6 +454,8 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, vxge_hw_ring_rxd_1b_get(ringh, dtr, &dma_sizes); pkt_length = dma_sizes; + pkt_length -= ETH_FCS_LEN; + vxge_debug_rx(VXGE_TRACE, "%s: %s:%d Packet Length = %d", ring->ndev->name, __func__, __LINE__, pkt_length); @@ -4163,11 +4165,11 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) } if (ll_config.device_hw_info.fw_version.major != - VXGE_DRIVER_VERSION_MAJOR) { + VXGE_DRIVER_FW_VERSION_MAJOR) { vxge_debug_init(VXGE_ERR, - "FW Ver.(maj): %d not driver's expected version: %d", - ll_config.device_hw_info.fw_version.major, - VXGE_DRIVER_VERSION_MAJOR); + "%s: Incorrect firmware version." + "Please upgrade the firmware to version 1.x.x", + VXGE_DRIVER_NAME); ret = -EINVAL; goto _exit3; } diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index a46f7fe..18d824c 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -21,7 +21,7 @@ #define VXGE_DRIVER_NAME "vxge" #define VXGE_DRIVER_VENDOR "Neterion, Inc" -#define VXGE_DRIVER_VERSION_MAJOR 0 +#define VXGE_DRIVER_FW_VERSION_MAJOR 1 #define DRV_VERSION VXGE_VERSION_MAJOR"."VXGE_VERSION_MINOR"."\ VXGE_VERSION_FIX"."VXGE_VERSION_BUILD"-"\ -- cgit v0.10.2 From 0a25bdc69634fb343c4b23e3422a37e5819448f1 Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:18:06 +0000 Subject: vxge: Printing the function's configured mode of operation - Printing the function's configured mode of operation. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index eaf916b..7b5402b 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -4325,6 +4325,27 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) ll_config.device_hw_info.fw_version.version, ll_config.device_hw_info.fw_date.date); + if (new_device) { + switch (ll_config.device_hw_info.function_mode) { + case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION: + vxge_debug_init(VXGE_TRACE, + "%s: Single Function Mode Enabled", vdev->ndev->name); + break; + case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION: + vxge_debug_init(VXGE_TRACE, + "%s: Multi Function Mode Enabled", vdev->ndev->name); + break; + case VXGE_HW_FUNCTION_MODE_SRIOV: + vxge_debug_init(VXGE_TRACE, + "%s: Single Root IOV Mode Enabled", vdev->ndev->name); + break; + case VXGE_HW_FUNCTION_MODE_MRIOV: + vxge_debug_init(VXGE_TRACE, + "%s: Multi Root IOV Mode Enabled", vdev->ndev->name); + break; + } + } + vxge_print_parm(vdev, vpath_mask); /* Store the fw version for ethttool option */ -- cgit v0.10.2 From a73e76e23c20c05cb8c0b7ba8bc9daa04b05c80f Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:18:43 +0000 Subject: vxge: Version update - Version update Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index 82786ff..580c6eb 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -18,6 +18,6 @@ #define VXGE_VERSION_MAJOR "2" #define VXGE_VERSION_MINOR "0" #define VXGE_VERSION_FIX "4" -#define VXGE_VERSION_BUILD "17795" +#define VXGE_VERSION_BUILD "17899" #define VXGE_VERSION_FOR "k" #endif -- cgit v0.10.2 From ec634fe328182a1a098585bfc7b69e5042bdb08d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sun, 5 Jul 2009 19:23:38 -0700 Subject: net: convert remaining non-symbolic return values in ndo_start_xmit() functions This patch converts the remaining occurences of raw return values to their symbolic counterparts in ndo_start_xmit() functions that were missed by the previous automatic conversion. Additionally code that assumed the symbolic value of NETDEV_TX_OK to be zero is changed to explicitly use NETDEV_TX_OK. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index edad415..2f0b86b 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -545,7 +545,7 @@ static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index 579974c..c73004b 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -148,7 +148,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) if (lp->sk_count <= 3) { schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue); } - return (0); /* success */ + return NETDEV_TX_OK; /* success */ } /* net_send_packet */ diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 8209ed6..57bf4bf 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1051,12 +1051,12 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) isdn_net_dev *nd; isdn_net_local *slp; isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); - int retv = 0; + int retv = NETDEV_TX_OK; if (((isdn_net_local *) netdev_priv(ndev))->master) { printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* For the other encaps the header has already been built */ diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index aa30b5c..2d14b64 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -1223,7 +1223,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) isdn_net_dev *nd; unsigned int proto = PPP_IP; /* 0x21 */ struct ippp_struct *ipt,*ipts; - int slot, retval = 0; + int slot, retval = NETDEV_TX_OK; mlp = (isdn_net_local *) netdev_priv(netdev); nd = mlp->netdev; /* get master lp */ @@ -1240,7 +1240,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ if (ipts->debug & 0x1) printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name); - retval = 1; + retval = NETDEV_TX_BUSY; goto out; } @@ -1261,7 +1261,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) lp = isdn_net_get_locked_lp(nd); if (!lp) { printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name); - retval = 1; + retval = NETDEV_TX_BUSY; goto out; } /* we have our lp locked from now on */ diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 367bec6..e29fb1a 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -485,7 +485,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) if (el_debug > 2) pr_debug(" queued xmit.\n"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* A receive upset our load, despite our best efforts */ if (el_debug > 2) diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 69f5b7d..b1e5764 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -585,7 +585,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) lp->tx_full = 1; spin_unlock_irqrestore (&lp->devlock, flags); - return 0; + return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(lance_start_xmit); diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 85a1817..7302e43 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -553,11 +553,11 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) volatile struct lance_regs *ll = lp->ll; volatile struct lance_init_block *ib = lp->init_block; int entry, skblen; - int status = 0; + int status = NETDEV_TX_OK; unsigned long flags; if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; skblen = max_t(unsigned, skb->len, ETH_ZLEN); local_irq_save(flags); diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index d4b5708..0e7dfe0 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2431,7 +2431,7 @@ out: dev_kfree_skb(skb); } read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 46d312b..bf45d20 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1413,7 +1413,7 @@ out: } read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } void bond_alb_monitor(struct work_struct *work) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d927f71..66596d8 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4277,7 +4277,7 @@ out: dev_kfree_skb(skb); } read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } @@ -4308,7 +4308,7 @@ out: read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } /* @@ -4354,7 +4354,7 @@ out: dev_kfree_skb(skb); } read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } /* @@ -4414,7 +4414,7 @@ out: /* frame sent to all suitable interfaces */ read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } /*------------------------- Device initialization ---------------------------*/ diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 102b8d4..b2e0a8f 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -3218,7 +3218,7 @@ static int dfx_xmt_queue_pkt( bp->xmt_length_errors++; /* bump error counter */ netif_wake_queue(dev); dev_kfree_skb(skb); - return(0); /* return "success" */ + return NETDEV_TX_OK; /* return "success" */ } /* * See if adapter link is available, if not, free buffer @@ -3241,7 +3241,7 @@ static int dfx_xmt_queue_pkt( bp->xmt_discards++; /* bump error counter */ dev_kfree_skb(skb); /* free sk_buff now */ netif_wake_queue(dev); - return(0); /* return "success" */ + return NETDEV_TX_OK; /* return "success" */ } } @@ -3345,7 +3345,7 @@ static int dfx_xmt_queue_pkt( dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); spin_unlock_irqrestore(&bp->lock, flags); netif_wake_queue(dev); - return(0); /* packet queued to adapter */ + return NETDEV_TX_OK; /* packet queued to adapter */ } diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 97ea2d6..adb997c 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -1793,7 +1793,7 @@ static int __init get_hw_addr(struct net_device *dev) static int load_packet(struct net_device *dev, struct sk_buff *skb) { struct depca_private *lp = netdev_priv(dev); - int i, entry, end, len, status = 0; + int i, entry, end, len, status = NETDEV_TX_OK; entry = lp->tx_new; /* Ring around buffer number. */ end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask; diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index beb8421..5443558 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -1342,7 +1342,7 @@ static inline int emac_xmit_finish(struct emac_instance *dev, int len) ++dev->stats.tx_packets; dev->stats.tx_bytes += len; - return 0; + return NETDEV_TX_OK; } /* Tx lock BH */ diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 96713ef..0a79b45 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -164,7 +164,7 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) { struct ifb_private *dp = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; - int ret = 0; + int ret = NETDEV_TX_OK; u32 from = G_TC_FROM(skb->tc_verd); stats->rx_packets++; diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 7098357..f0d0cea 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -1966,10 +1966,10 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); iobase = self->io.sir_base; diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 1484c76..e4e9056 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -981,7 +981,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) self = netdev_priv(dev); - IRDA_ASSERT (self != NULL, return 0; ); + IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; ); IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __func__ ,skb->len,self->txpending,INB (OBOE_ENABLEH)); diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 05bfc98..51ca89c 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -1365,7 +1365,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); iobase = self->io.fir_base; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index bde004f..71dce20 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -590,7 +590,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) int err; s32 speed; - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); netif_stop_queue(ndev); diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index d0797ad..15f8a7f 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -886,10 +886,10 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) IRDA_DEBUG(1, "%s\n", __func__); - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); netif_stop_queue(dev); @@ -914,7 +914,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) smsc_ircc_change_speed(self, speed); spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } self->new_speed = speed; } @@ -935,7 +935,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* @@ -1190,9 +1190,9 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) s32 speed; int mtt; - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); netif_stop_queue(dev); @@ -1210,7 +1210,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) smsc_ircc_change_speed(self, speed); spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } self->new_speed = speed; @@ -1242,7 +1242,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 62ba94b..36a6074 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -832,7 +832,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, __u32 speed; self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); iobase = self->io.fir_base; netif_stop_queue(dev); diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index f28c233..d6be360 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -414,7 +414,7 @@ static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); dev->stats.tx_bytes += send_length; - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 08c43f2..d5c18c6 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -764,7 +764,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Poll CQ here */ mlx4_en_xmit_poll(priv, tx_ind); - return 0; + return NETDEV_TX_OK; tx_drop: dev_kfree_skb_any(skb); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 05cd24d..1a34f7e 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2968,13 +2968,13 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) } } dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; drop: ss = &mgp->ss[skb_get_queue_mapping(skb)]; dev_kfree_skb_any(skb); ss->stats.tx_dropped += 1; - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 77d44a0..a0ac5d4 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -1183,7 +1183,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb->len > XMIT_BUFF_SIZE) { printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -1267,7 +1267,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) } dev_kfree_skb(skb); #endif - return 0; + return NETDEV_TX_OK; } /******************************************* diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 0c31272..888a14a 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -1077,7 +1077,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) // dequeue packets from xmt queue and send them netif_start_queue(dev); dev_kfree_skb(skb); - return (0); /* return "success" */ + return NETDEV_TX_OK; /* return "success" */ } if (bp->QueueSkb == 0) { // return with tbusy set: queue full diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 753a1fb..9599ce7 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -211,7 +211,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) length = skb->len; if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -265,7 +265,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 54ad4ed..6515894 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -4609,7 +4609,7 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev) if(tp->QueueSkb > 0) netif_wake_queue(dev); - return (0); + return NETDEV_TX_OK; } static int smctr_send_lobe_media_test(struct net_device *dev) diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index a2eab72..07f6dfd 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -682,7 +682,7 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device tms380tr_exec_sifcmd(dev, CMD_TX_VALID); spin_unlock_irqrestore(&tp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 8e78f00..5e15fab 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -676,7 +676,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) if (skb->len > MAX_PACKET_SIZE) { printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&db->lock, flags); @@ -722,7 +722,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) /* free this SKB */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 2fa275a..8526b6d 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -194,7 +194,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) ret = 0; if (!skb || !dev) - return(0); + return NETDEV_TX_OK; dlp = netdev_priv(dev); @@ -219,7 +219,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) /* Alan Cox recommends always returning 0, and always freeing the packet */ /* experience suggest a slightly more conservative approach */ - if (!ret) + if (ret == NETDEV_TX_OK) { dev_kfree_skb(skb); netif_wake_queue(dev); diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 8face5d..e81946d 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -1182,7 +1182,7 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) if (dscc4_tx_quiescent(dpriv, dev)) dscc4_do_tx(dpriv, dev); - return 0; + return NETDEV_TX_OK; } static int dscc4_close(struct net_device *dev) diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 90c0a31..20a1237 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -2294,7 +2294,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) dbg(DBG_ASS, "Tried to transmit but no carrier on card %d port %d\n", card->card_no, port->index); - return 0; + return NETDEV_TX_OK; } /* Drop it if it's too big! MTU failure ? */ @@ -2303,7 +2303,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) LEN_TX_BUFFER); dev_kfree_skb(skb); dev->stats.tx_errors++; - return 0; + return NETDEV_TX_OK; } /* @@ -2337,7 +2337,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_errors++; dbg(DBG_ASS, "Tx queue overflow card %d port %d\n", card->card_no, port->index); - return 0; + return NETDEV_TX_OK; } /* @@ -2354,7 +2354,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) fst_q_work_item(&fst_work_txq, card->card_no); tasklet_schedule(&fst_tx_task); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 45b1822..d1492ae 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1428,7 +1428,7 @@ static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev) lmc_softc_t *sc = dev_to_sc(dev); u32 flag; int entry; - int ret = 0; + int ret = NETDEV_TX_OK; unsigned long flags; lmc_trace(dev, "lmc_start_xmit in"); diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index e4ad7b6..03b76ad 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -310,7 +310,7 @@ static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev) } spin_unlock(&port->lock); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index d313b00..1fe1bba 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -75,7 +75,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb " "(len=%d)\n", dev->name, skb->len); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (local->ddev != dev) { @@ -89,14 +89,14 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: prism2_tx: trying to use " "AP device with Ethernet net dev\n", dev->name); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } } else { if (local->iw_mode == IW_MODE_REPEAT) { printk(KERN_DEBUG "%s: prism2_tx: trying to use " "non-WDS link in Repeater mode\n", dev->name); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else if (local->iw_mode == IW_MODE_INFRA && (local->wds_type & HOSTAP_WDS_AP_CLIENT) && memcmp(skb->data + ETH_ALEN, dev->dev_addr, @@ -210,13 +210,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) skb = skb_unshare(skb, GFP_ATOMIC); if (skb == NULL) { iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } if (pskb_expand_head(skb, need_headroom, need_tailroom, GFP_ATOMIC)) { kfree_skb(skb); iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } } else if (skb_headroom(skb) < need_headroom) { struct sk_buff *tmp = skb; @@ -224,13 +224,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) kfree_skb(tmp); if (skb == NULL) { iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } } else { skb = skb_unshare(skb, GFP_ATOMIC); if (skb == NULL) { iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } } @@ -256,7 +256,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Send IEEE 802.11 encapsulated frame using the master radio device */ skb->dev = local->dev; dev_queue_xmit(skb); - return 0; + return NETDEV_TX_OK; } @@ -276,7 +276,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb " "(len=%d)\n", dev->name, skb->len); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } iface->stats.tx_packets++; @@ -301,7 +301,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Send IEEE 802.11 encapsulated frame using the master radio device */ skb->dev = local->dev; dev_queue_xmit(skb); - return 0; + return NETDEV_TX_OK; } @@ -396,7 +396,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " "expected 0x%08x)\n", dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; goto fail; } @@ -414,7 +414,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < 24) { printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb " "(len=%d)\n", dev->name, skb->len); - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; goto fail; } @@ -441,13 +441,13 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, meta->ethertype); hostap_dump_tx_80211(dev->name, skb); - ret = 0; /* drop packet */ + ret = NETDEV_TX_OK; /* drop packet */ iface->stats.tx_dropped++; goto fail; } break; case AP_TX_DROP: - ret = 0; /* drop packet */ + ret = NETDEV_TX_OK; /* drop packet */ iface->stats.tx_dropped++; goto fail; case AP_TX_RETRY: @@ -455,7 +455,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) case AP_TX_BUFFERED: /* do not free skb here, it will be freed when the * buffered frame is sent/timed out */ - ret = 0; + ret = NETDEV_TX_OK; goto tx_exit; } @@ -501,7 +501,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) "frame (drop_unencrypted=1)\n", dev->name); } iface->stats.tx_dropped++; - ret = 0; + ret = NETDEV_TX_OK; goto fail; } @@ -510,7 +510,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb == NULL) { printk(KERN_DEBUG "%s: TX - encryption failed\n", dev->name); - ret = 0; + ret = NETDEV_TX_OK; goto fail; } meta = (struct hostap_skb_tx_data *) skb->cb; @@ -519,23 +519,23 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) "expected 0x%08x) after hostap_tx_encrypt\n", dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; goto fail; } } if (local->func->tx == NULL || local->func->tx(skb, dev)) { - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; } else { - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_packets++; iface->stats.tx_bytes += skb->len; } fail: - if (!ret && skb) + if (ret == NETDEV_TX_OK && skb) dev_kfree_skb(skb); tx_exit: if (tx.sta_ptr) diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index da2ad54..2e8f84f 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -527,13 +527,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (ret == 0) { dev->stats.tx_packets++; dev->stats.tx_bytes += txb->payload_size; - return 0; + return NETDEV_TX_OK; } ieee80211_txb_free(txb); } - return 0; + return NETDEV_TX_OK; failed: spin_unlock_irqrestore(&ieee->lock, flags); diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 8f62109..c255d9c 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -234,7 +234,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) /* unlock the driver code */ spin_unlock_irqrestore(&priv->slock, flags); - return 0; + return NETDEV_TX_OK; drop_free: ndev->stats.tx_dropped++; diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index ab7fc5c..5cb5329 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2891,7 +2891,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); #endif - return 0; + return NETDEV_TX_OK; } /*********************** HARDWARE CONFIGURATION ***********************/ diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 6af7064..9dd241a 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3113,7 +3113,7 @@ wavelan_packet_xmit(struct sk_buff * skb, * able to detect collisions, therefore in theory we don't really * need to pad. Jean II */ if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; wv_packet_write(dev, skb->data, skb->len); @@ -3122,7 +3122,7 @@ wavelan_packet_xmit(struct sk_buff * skb, #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); #endif - return(0); + return NETDEV_TX_OK; } /********************** HARDWARE CONFIGURATION **********************/ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index e3e96bb..a83a562 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1348,7 +1348,6 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (rc) { ++dev->stats.tx_dropped; netif_stop_queue(dev); - rc = NETDEV_TX_OK; } else { ++dev->stats.tx_packets; dev->stats.tx_bytes += skb->len; @@ -1358,7 +1357,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } spin_unlock_irqrestore(&this->lock, flags); - return rc; + return NETDEV_TX_OK; } static int wl3501_open(struct net_device *dev) diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index f370f8d..c63babe 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -350,6 +350,8 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) CLAW_DBF_TEXT_(4, trace, "clawtx%d", rc); if (rc) rc = NETDEV_TX_BUSY; + else + rc = NETDEV_TX_OK; return rc; } /* end of claw_tx */ diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 8c67590..a70de9b 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1553,24 +1553,24 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb, struct net_device *dev) { struct lcs_header *header; - int rc = 0; + int rc = NETDEV_TX_OK; LCS_DBF_TEXT(5, trace, "hardxmit"); if (skb == NULL) { card->stats.tx_dropped++; card->stats.tx_errors++; - return 0; + return NETDEV_TX_OK; } if (card->state != DEV_STATE_UP) { dev_kfree_skb(skb); card->stats.tx_dropped++; card->stats.tx_errors++; card->stats.tx_carrier_errors++; - return 0; + return NETDEV_TX_OK; } if (skb->protocol == htons(ETH_P_IPV6)) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(card->dev); spin_lock(&card->lock); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 8c36eaf..bb1183a 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1376,14 +1376,14 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) if (skb == NULL) { IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb is NULL\n"); privptr->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } if (skb_headroom(skb) < NETIUCV_HDRLEN) { IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb_headroom < NETIUCV_HDRLEN\n"); dev_kfree_skb(skb); privptr->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } /** @@ -1395,7 +1395,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) privptr->stats.tx_dropped++; privptr->stats.tx_errors++; privptr->stats.tx_carrier_errors++; - return 0; + return NETDEV_TX_OK; } if (netiucv_test_and_set_busy(dev)) { diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 691cecd..2cfc338 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -744,6 +744,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) card->stats.tx_bytes += tx_bytes; if (new_skb != skb) dev_kfree_skb_any(skb); + rc = NETDEV_TX_OK; } else { if (data_offset >= 0) kmem_cache_free(qeth_core_header_cache, hdr); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 5487240..048defa 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2793,6 +2793,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) card->perf_stats.sg_frags_sent += nr_frags + 1; } } + rc = NETDEV_TX_OK; } else { if (data_offset >= 0) kmem_cache_free(qeth_core_header_cache, hdr); diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c index f298b9b..35c59d5 100644 --- a/drivers/staging/rt2860/rt_main_dev.c +++ b/drivers/staging/rt2860/rt_main_dev.c @@ -862,7 +862,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb) { struct net_device *net_dev = skb->dev; PRTMP_ADAPTER pAd = net_dev->ml_priv; - int status = 0; + int status = NETDEV_TX_OK; PNDIS_PACKET pPacket = (PNDIS_PACKET) skb; { @@ -892,7 +892,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb) STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1); - status = 0; + status = NETDEV_TX_OK; done: return status; @@ -923,7 +923,7 @@ INT rt28xx_send_packets( if (!(net_dev->flags & IFF_UP)) { RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE); - return 0; + return NETDEV_TX_OK; } NdisZeroMemory((PUCHAR)&skb_p->cb[CB_OFF], 15); diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c index 1294e05..1b77460 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c @@ -802,13 +802,13 @@ int ieee80211_xmit(struct sk_buff *skb, if ((*ieee->hard_start_xmit)(txb, dev) == 0) { stats->tx_packets++; stats->tx_bytes += txb->payload_size; - return 0; + return NETDEV_TX_OK; } ieee80211_txb_free(txb); } } - return 0; + return NETDEV_TX_OK; failed: spin_unlock_irqrestore(&ieee->lock, flags); diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index 7e2feca..26a5911 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -3040,7 +3040,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) spin_unlock_irqrestore(&priv->tx_lock,flags); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } rtl8180_tx(dev, skb->data, skb->len, priority, @@ -3051,7 +3051,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) spin_unlock_irqrestore(&priv->tx_lock,flags); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } // longpre 144+48 shortpre 72+24 diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 90f499e..c273c03 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -354,7 +354,7 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb, p80211_metawep_t p80211_wep; if (skb == NULL) - return 0; + return NETDEV_TX_OK; if (wlandev->state != WLAN_DEVICE_OPEN) { result = 1; diff --git a/net/atm/mpc.c b/net/atm/mpc.c index e5bf114..1ac4b94 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -554,7 +554,7 @@ static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev) while (i < mpc->number_of_mps_macs) { if (!compare_ether_addr(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN))) if ( send_via_shortcut(skb, mpc) == 0 ) /* try shortcut */ - return 0; /* success! */ + return NETDEV_TX_OK; /* success! */ i++; } diff --git a/net/core/dev.c b/net/core/dev.c index 70c27e0..dca8b50 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1704,7 +1704,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, skb_dst_drop(skb); rc = ops->ndo_start_xmit(skb, dev); - if (rc == 0) + if (rc == NETDEV_TX_OK) txq_trans_update(txq); /* * TODO: if skb_orphan() was called by @@ -1730,7 +1730,7 @@ gso: skb->next = nskb->next; nskb->next = NULL; rc = ops->ndo_start_xmit(nskb, dev); - if (unlikely(rc)) { + if (unlikely(rc != NETDEV_TX_OK)) { nskb->next = skb->next; skb->next = nskb; return rc; @@ -1744,7 +1744,7 @@ gso: out_kfree_skb: kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static u32 skb_tx_hashrnd; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d238a89..2ffb35d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1627,7 +1627,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, u32 sta_flags = 0; if (unlikely(skb->len < ETH_HLEN)) { - ret = 0; + ret = NETDEV_TX_OK; goto fail; } @@ -1664,7 +1664,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { /* Do not send frames with mesh_ttl == 0 */ sdata->u.mesh.mshstats.dropped_frames_ttl++; - ret = 0; + ret = NETDEV_TX_OK; goto fail; } memset(&mesh_hdr, 0, sizeof(mesh_hdr)); @@ -1724,7 +1724,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, hdrlen = 24; break; default: - ret = 0; + ret = NETDEV_TX_OK; goto fail; } @@ -1766,7 +1766,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); - ret = 0; + ret = NETDEV_TX_OK; goto fail; } @@ -1858,10 +1858,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, dev->trans_start = jiffies; dev_queue_xmit(skb); - return 0; + return NETDEV_TX_OK; fail: - if (!ret) + if (ret == NETDEV_TX_OK) dev_kfree_skb(skb); return ret; -- cgit v0.10.2 From 3eff8958308ed875a4e845d59a498288f8bbad77 Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Sun, 5 Jul 2009 13:28:48 +0200 Subject: ALSA: azt3328: fix Kconfig entry This driver is about as far from being experimental as it can ever get for an undocumented card, thus create this patch (interestingly it was the only EXPERIMENTAL remaining in the entire Kconfig file). Signed-off-by: Andreas Mohr Signed-off-by: Takashi Iwai diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 748f6b7..fb5ee3c 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -135,11 +135,11 @@ config SND_AW2 config SND_AZT3328 - tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)" - depends on EXPERIMENTAL + tristate "Aztech AZF3328 / PCI168" select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM + select SND_RAWMIDI help Say Y here to include support for Aztech AZF3328 (PCI168) soundcards. -- cgit v0.10.2 From dfbf9511155d3584b8747c935216077f46eb9a4f Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Sun, 5 Jul 2009 13:55:46 +0200 Subject: ALSA: azt3328: large codec cleanup, add I2S port etc. - fully separate codec I/O port handling, enabling the use of a single function each for all codecs (playback, capture, I2S out) - add a new separate pcm for I2S out port (UNTESTED, no I2S DAC available yet) - switch gameport to low frequency while idle, to try to reduce noise/power - improve snd_azf3328_codec_setdmaa() calculation - minor variable type cleanup (u16, bool etc.) - add some doc updates (help those lost Windows users, debug help, ...) Note that due to the large cleanup aspect of the codec I/O change, I was able to fit everything including all improvements into the same binary size!! (a measly 10 bytes more or so) This should now be the almost last patch to this driver (minus some possible kernel clocksource patch and x86_64 fixes or so). I just felt like taking a break from the usual stuff and wanted to get this driver's structure finished, and it's rather clean now... Tested, working and checkpatch.pl:ed on 2.6.30-rc5, applies cleanly to 2.6.30 proper. Signed-off-by: Andreas Mohr Signed-off-by: Takashi Iwai diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index f290bc5..39dfdaa 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1,6 +1,6 @@ /* * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). - * Copyright (C) 2002, 2005 - 2008 by Andreas Mohr + * Copyright (C) 2002, 2005 - 2009 by Andreas Mohr * * Framework borrowed from Bart Hartgers's als4000.c. * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), @@ -10,6 +10,13 @@ * PCI168 A/AP, sub ID 8000 * Please give me feedback in case you try my driver with one of these!! * + * Keywords: Windows XP Vista 168nt4-125.zip 168win95-125.zip PCI 168 download + * (XP/Vista do not support this card at all but every Linux distribution + * has very good support out of the box; + * just to make sure that the right people hit this and get to know that, + * despite the high level of Internet ignorance - as usual :-P - + * about Linux support for this card) + * * GPL LICENSE * 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 @@ -71,10 +78,11 @@ * - built-in General DirectX timer having a 20 bits counter * with 1us resolution (see below!) * - I2S serial output port for external DAC + * [FIXME: 3.3V or 5V level? maximum rate is 66.2kHz right?] * - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI * - supports hardware volume control * - single chip low cost solution (128 pin QFP) - * - supports programmable Sub-vendor and Sub-system ID + * - supports programmable Sub-vendor and Sub-system ID [24C02 SEEPROM chip] * required for Microsoft's logo compliance (FIXME: where?) * At least the Trident 4D Wave DX has one bit somewhere * to enable writes to PCI subsystem VID registers, that should be it. @@ -82,6 +90,7 @@ * some custom data starting at 0x80. What kind of config settings * are located in our extended PCI space anyway?? * - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms + * [TDA1517P chip] * * Note that this driver now is actually *better* than the Windows driver, * since it additionally supports the card's 1MHz DirectX timer - just try @@ -146,10 +155,15 @@ * to read the Digital Enhanced Game Port. Not sure whether it is fixable. * * TODO + * - use PCI_VDEVICE + * - verify driver status on x86_64 + * - test multi-card driver operation + * - (ab)use 1MHz DirectX timer as kernel clocksource * - test MPU401 MIDI playback etc. * - add more power micro-management (disable various units of the card - * as long as they're unused). However this requires more I/O ports which I - * haven't figured out yet and which thus might not even exist... + * as long as they're unused, to improve audio quality and save power). + * However this requires more I/O ports which I haven't figured out yet + * and which thus might not even exist... * The standard suspend/resume functionality could probably make use of * some improvement, too... * - figure out what all unknown port bits are responsible for @@ -185,6 +199,26 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); #define SUPPORT_GAMEPORT 1 #endif +/* === Debug settings === + Further diagnostic functionality than the settings below + does not need to be provided, since one can easily write a bash script + to dump the card's I/O ports (those listed in lspci -v -v): + function dump() + { + local descr=$1; local addr=$2; local count=$3 + + echo "${descr}: ${count} @ ${addr}:" + dd if=/dev/port skip=$[${addr}] count=${count} bs=1 2>/dev/null| hexdump -C + } + and then use something like + "dump joy200 0x200 8", "dump mpu388 0x388 4", "dump joy 0xb400 8", + "dump codec00 0xa800 32", "dump mixer 0xb800 64", "dump synth 0xbc00 8", + possibly within a "while true; do ... sleep 1; done" loop. + Tweaking ports could be done using + VALSTRING="`printf "%02x" $value`" + printf "\x""$VALSTRING"|dd of=/dev/port seek=$[${addr}] bs=1 2>/dev/null +*/ + #define DEBUG_MISC 0 #define DEBUG_CALLS 0 #define DEBUG_MIXER 0 @@ -250,22 +284,23 @@ static int seqtimer_scaling = 128; module_param(seqtimer_scaling, int, 0444); MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); -struct snd_azf3328_audio_stream { +struct snd_azf3328_codec_data { + unsigned long io_base; struct snd_pcm_substream *substream; - int enabled; - int running; - unsigned long portbase; + bool running; + const char *name; }; -enum snd_azf3328_stream_index { - AZF_PLAYBACK = 0, - AZF_CAPTURE = 1, +enum snd_azf3328_codec_type { + AZF_CODEC_PLAYBACK = 0, + AZF_CODEC_CAPTURE = 1, + AZF_CODEC_I2S_OUT = 2, }; struct snd_azf3328 { /* often-used fields towards beginning, then grouped */ - unsigned long codec_io; /* usually 0xb000, size 128 */ + unsigned long ctrl_io; /* usually 0xb000, size 128 */ unsigned long game_io; /* usually 0xb400, size 8 */ unsigned long mpu_io; /* usually 0xb800, size 4 */ unsigned long opl3_io; /* usually 0xbc00, size 8 */ @@ -275,15 +310,17 @@ struct snd_azf3328 { struct snd_timer *timer; - struct snd_pcm *pcm; - struct snd_azf3328_audio_stream audio_stream[2]; + struct snd_pcm *pcm[3]; + + /* playback, recording and I2S out codecs */ + struct snd_azf3328_codec_data codecs[3]; struct snd_card *card; struct snd_rawmidi *rmidi; #ifdef SUPPORT_GAMEPORT struct gameport *gameport; - int axes[4]; + u16 axes[4]; #endif struct pci_dev *pci; @@ -293,12 +330,12 @@ struct snd_azf3328 { * If we need to add more registers here, then we might try to fold this * into some transparent combined shadow register handling with * CONFIG_PM register storage below, but that's slightly difficult. */ - u16 shadow_reg_codec_6AH; + u16 shadow_reg_ctrl_6AH; #ifdef CONFIG_PM /* register value containers for power management * Note: not always full I/O range preserved (just like Win driver!) */ - u16 saved_regs_codec[AZF_IO_SIZE_CODEC_PM / 2]; + u16 saved_regs_ctrl[AZF_IO_SIZE_CTRL_PM / 2]; u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2]; u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2]; @@ -316,7 +353,7 @@ MODULE_DEVICE_TABLE(pci, snd_azf3328_ids); static int -snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set) +snd_azf3328_io_reg_setb(unsigned reg, u8 mask, bool do_set) { u8 prev = inb(reg), new; @@ -331,39 +368,72 @@ snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set) } static inline void -snd_azf3328_codec_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) +snd_azf3328_codec_outb(const struct snd_azf3328_codec_data *codec, + unsigned reg, + u8 value +) { - outb(value, chip->codec_io + reg); + outb(value, codec->io_base + reg); } static inline u8 -snd_azf3328_codec_inb(const struct snd_azf3328 *chip, unsigned reg) +snd_azf3328_codec_inb(const struct snd_azf3328_codec_data *codec, unsigned reg) { - return inb(chip->codec_io + reg); + return inb(codec->io_base + reg); } static inline void -snd_azf3328_codec_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) +snd_azf3328_codec_outw(const struct snd_azf3328_codec_data *codec, + unsigned reg, + u16 value +) { - outw(value, chip->codec_io + reg); + outw(value, codec->io_base + reg); } static inline u16 -snd_azf3328_codec_inw(const struct snd_azf3328 *chip, unsigned reg) +snd_azf3328_codec_inw(const struct snd_azf3328_codec_data *codec, unsigned reg) { - return inw(chip->codec_io + reg); + return inw(codec->io_base + reg); } static inline void -snd_azf3328_codec_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value) +snd_azf3328_codec_outl(const struct snd_azf3328_codec_data *codec, + unsigned reg, + u32 value +) { - outl(value, chip->codec_io + reg); + outl(value, codec->io_base + reg); } static inline u32 -snd_azf3328_codec_inl(const struct snd_azf3328 *chip, unsigned reg) +snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg) +{ + return inl(codec->io_base + reg); +} + +static inline void +snd_azf3328_ctrl_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) { - return inl(chip->codec_io + reg); + outb(value, chip->ctrl_io + reg); +} + +static inline u8 +snd_azf3328_ctrl_inb(const struct snd_azf3328 *chip, unsigned reg) +{ + return inb(chip->ctrl_io + reg); +} + +static inline void +snd_azf3328_ctrl_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) +{ + outw(value, chip->ctrl_io + reg); +} + +static inline void +snd_azf3328_ctrl_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value) +{ + outl(value, chip->ctrl_io + reg); } static inline void @@ -404,13 +474,13 @@ snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, unsigned reg) #define AZF_MUTE_BIT 0x80 -static int +static bool snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, - unsigned reg, int do_mute + unsigned reg, bool do_mute ) { unsigned long portbase = chip->mixer_io + reg + 1; - int updated; + bool updated; /* the mute bit is on the *second* (i.e. right) register of a * left/right channel setting */ @@ -569,7 +639,7 @@ snd_azf3328_get_mixer(struct snd_kcontrol *kcontrol, { struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); struct azf3328_mixer_reg reg; - unsigned int oreg, val; + u16 oreg, val; snd_azf3328_dbgcallenter(); snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); @@ -600,7 +670,7 @@ snd_azf3328_put_mixer(struct snd_kcontrol *kcontrol, { struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); struct azf3328_mixer_reg reg; - unsigned int oreg, nreg, val; + u16 oreg, nreg, val; snd_azf3328_dbgcallenter(); snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); @@ -709,7 +779,7 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, { struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); struct azf3328_mixer_reg reg; - unsigned int oreg, nreg, val; + u16 oreg, nreg, val; snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); oreg = snd_azf3328_mixer_inw(chip, reg.reg); @@ -867,14 +937,15 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream) static void snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, - unsigned reg, + enum snd_azf3328_codec_type codec_type, enum azf_freq_t bitrate, unsigned int format_width, unsigned int channels ) { - u16 val = 0xff00; unsigned long flags; + const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; + u16 val = 0xff00; snd_azf3328_dbgcallenter(); switch (bitrate) { @@ -917,7 +988,7 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, spin_lock_irqsave(&chip->reg_lock, flags); /* set bitrate/format */ - snd_azf3328_codec_outw(chip, reg, val); + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val); /* changing the bitrate/format settings switches off the * audio output with an annoying click in case of 8/16bit format change @@ -926,11 +997,11 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, * (FIXME: yes, it works, but what exactly am I doing here?? :) * FIXME: does this have some side effects for full-duplex * or other dramatic side effects? */ - if (reg == IDX_IO_PLAY_SOUNDFORMAT) /* only do it for playback */ - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, - snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | - DMA_PLAY_SOMETHING1 | - DMA_PLAY_SOMETHING2 | + if (codec_type == AZF_CODEC_PLAYBACK) /* only do it for playback */ + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, + snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS) | + DMA_RUN_SOMETHING1 | + DMA_RUN_SOMETHING2 | SOMETHING_ALMOST_ALWAYS_SET | DMA_EPILOGUE_SOMETHING | DMA_SOMETHING_ELSE @@ -942,134 +1013,132 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, static inline void snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip, - unsigned reg + enum snd_azf3328_codec_type codec_type ) { /* choose lowest frequency for low power consumption. * While this will cause louder noise due to rather coarse frequency, * it should never matter since output should always * get disabled properly when idle anyway. */ - snd_azf3328_codec_setfmt(chip, reg, AZF_FREQ_4000, 8, 1); + snd_azf3328_codec_setfmt(chip, codec_type, AZF_FREQ_4000, 8, 1); } static void -snd_azf3328_codec_reg_6AH_update(struct snd_azf3328 *chip, +snd_azf3328_ctrl_reg_6AH_update(struct snd_azf3328 *chip, unsigned bitmask, - int enable + bool enable ) { if (enable) - chip->shadow_reg_codec_6AH &= ~bitmask; + chip->shadow_reg_ctrl_6AH &= ~bitmask; else - chip->shadow_reg_codec_6AH |= bitmask; + chip->shadow_reg_ctrl_6AH |= bitmask; snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n", - bitmask, enable, chip->shadow_reg_codec_6AH); - snd_azf3328_codec_outw(chip, IDX_IO_6AH, chip->shadow_reg_codec_6AH); + bitmask, enable, chip->shadow_reg_ctrl_6AH); + snd_azf3328_ctrl_outw(chip, IDX_IO_6AH, chip->shadow_reg_ctrl_6AH); } static inline void -snd_azf3328_codec_enable(struct snd_azf3328 *chip, int enable) +snd_azf3328_ctrl_enable_codecs(struct snd_azf3328 *chip, bool enable) { snd_azf3328_dbgplay("codec_enable %d\n", enable); /* no idea what exactly is being done here, but I strongly assume it's * PM related */ - snd_azf3328_codec_reg_6AH_update( + snd_azf3328_ctrl_reg_6AH_update( chip, IO_6A_PAUSE_PLAYBACK_BIT8, enable ); } static void -snd_azf3328_codec_activity(struct snd_azf3328 *chip, - enum snd_azf3328_stream_index stream_type, - int enable +snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, + enum snd_azf3328_codec_type codec_type, + bool enable ) { - int need_change = (chip->audio_stream[stream_type].running != enable); + struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; + bool need_change = (codec->running != enable); snd_azf3328_dbgplay( - "codec_activity: type %d, enable %d, need_change %d\n", - stream_type, enable, need_change + "codec_activity: %s codec, enable %d, need_change %d\n", + codec->name, enable, need_change ); if (need_change) { - enum snd_azf3328_stream_index other = - (stream_type == AZF_PLAYBACK) ? - AZF_CAPTURE : AZF_PLAYBACK; - /* small check to prevent shutting down the other party - * in case it's active */ - if ((enable) || !(chip->audio_stream[other].running)) - snd_azf3328_codec_enable(chip, enable); + static const struct { + enum snd_azf3328_codec_type other1; + enum snd_azf3328_codec_type other2; + } peer_codecs[3] = + { { AZF_CODEC_CAPTURE, AZF_CODEC_I2S_OUT }, + { AZF_CODEC_PLAYBACK, AZF_CODEC_I2S_OUT }, + { AZF_CODEC_PLAYBACK, AZF_CODEC_CAPTURE } }; + bool call_function; + + if (enable) + /* if enable codec, call enable_codecs func + to enable codec supply... */ + call_function = 1; + else { + /* ...otherwise call enable_codecs func + (which globally shuts down operation of codecs) + only in case the other codecs are currently + not active either! */ + if ((!chip->codecs[peer_codecs[codec_type].other1] + .running) + && (!chip->codecs[peer_codecs[codec_type].other2] + .running)) + call_function = 1; + } + if (call_function) + snd_azf3328_ctrl_enable_codecs(chip, enable); /* ...and adjust clock, too * (reduce noise and power consumption) */ if (!enable) snd_azf3328_codec_setfmt_lowpower( chip, - chip->audio_stream[stream_type].portbase - + IDX_IO_PLAY_SOUNDFORMAT + codec_type ); } - chip->audio_stream[stream_type].running = enable; + codec->running = enable; } static void -snd_azf3328_setdmaa(struct snd_azf3328 *chip, - long unsigned int addr, - unsigned int count, - unsigned int size, - enum snd_azf3328_stream_index stream_type +snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, + enum snd_azf3328_codec_type codec_type, + unsigned long addr, + unsigned int count, + unsigned int size ) { + const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; snd_azf3328_dbgcallenter(); - if (!chip->audio_stream[stream_type].running) { - /* AZF3328 uses a two buffer pointer DMA playback approach */ + if (!codec->running) { + /* AZF3328 uses a two buffer pointer DMA transfer approach */ - unsigned long flags, portbase, addr_area2; + unsigned long flags; /* width 32bit (prevent overflow): */ - unsigned long count_areas, count_tmp; + u32 addr_area2, count_areas, lengths; - portbase = chip->audio_stream[stream_type].portbase; count_areas = size/2; addr_area2 = addr+count_areas; count_areas--; /* max. index */ snd_azf3328_dbgplay("set DMA: buf1 %08lx[%lu], buf2 %08lx[%lu]\n", addr, count_areas, addr_area2, count_areas); /* build combined I/O buffer length word */ - count_tmp = count_areas; - count_areas |= (count_tmp << 16); + lengths = (count_areas << 16) | (count_areas); spin_lock_irqsave(&chip->reg_lock, flags); - outl(addr, portbase + IDX_IO_PLAY_DMA_START_1); - outl(addr_area2, portbase + IDX_IO_PLAY_DMA_START_2); - outl(count_areas, portbase + IDX_IO_PLAY_DMA_LEN_1); + snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr); + snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2, + addr_area2); + snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS, + lengths); spin_unlock_irqrestore(&chip->reg_lock, flags); } snd_azf3328_dbgcallleave(); } static int -snd_azf3328_playback_prepare(struct snd_pcm_substream *substream) -{ -#if 0 - struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int size = snd_pcm_lib_buffer_bytes(substream); - unsigned int count = snd_pcm_lib_period_bytes(substream); -#endif - - snd_azf3328_dbgcallenter(); -#if 0 - snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, - runtime->rate, - snd_pcm_format_width(runtime->format), - runtime->channels); - snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_PLAYBACK); -#endif - snd_azf3328_dbgcallleave(); - return 0; -} - -static int -snd_azf3328_capture_prepare(struct snd_pcm_substream *substream) +snd_azf3328_codec_prepare(struct snd_pcm_substream *substream) { #if 0 struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); @@ -1080,135 +1149,161 @@ snd_azf3328_capture_prepare(struct snd_pcm_substream *substream) snd_azf3328_dbgcallenter(); #if 0 - snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, + snd_azf3328_codec_setfmt(chip, AZF_CODEC_..., runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); - snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_CAPTURE); + snd_azf3328_codec_setdmaa(chip, AZF_CODEC_..., + runtime->dma_addr, count, size); #endif snd_azf3328_dbgcallleave(); return 0; } static int -snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) +snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, + struct snd_pcm_substream *substream, int cmd) { struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); + const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; struct snd_pcm_runtime *runtime = substream->runtime; int result = 0; - unsigned int status1; - int previously_muted; + u16 flags1; + bool previously_muted = 0; + bool is_playback_codec = (AZF_CODEC_PLAYBACK == codec_type); - snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd); + snd_azf3328_dbgcalls("snd_azf3328_codec_trigger cmd %d\n", cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - snd_azf3328_dbgplay("START PLAYBACK\n"); - - /* mute WaveOut (avoid clicking during setup) */ - previously_muted = - snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); + snd_azf3328_dbgplay("START %s\n", codec->name); + + if (is_playback_codec) { + /* mute WaveOut (avoid clicking during setup) */ + previously_muted = + snd_azf3328_mixer_set_mute( + chip, IDX_MIXER_WAVEOUT, 1 + ); + } - snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, + snd_azf3328_codec_setfmt(chip, codec_type, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); spin_lock(&chip->reg_lock); /* first, remember current value: */ - status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); + flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); - /* stop playback */ - status1 &= ~DMA_RESUME; - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); + /* stop transfer */ + flags1 &= ~DMA_RESUME; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); /* FIXME: clear interrupts or what??? */ - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff); + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff); spin_unlock(&chip->reg_lock); - snd_azf3328_setdmaa(chip, runtime->dma_addr, + snd_azf3328_codec_setdmaa(chip, codec_type, runtime->dma_addr, snd_pcm_lib_period_bytes(substream), - snd_pcm_lib_buffer_bytes(substream), - AZF_PLAYBACK); + snd_pcm_lib_buffer_bytes(substream) + ); spin_lock(&chip->reg_lock); #ifdef WIN9X /* FIXME: enable playback/recording??? */ - status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2; - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); + flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); - /* start playback again */ + /* start transfer again */ /* FIXME: what is this value (0x0010)??? */ - status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); + flags1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); #else /* NT4 */ - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, 0x0000); - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, - DMA_PLAY_SOMETHING1); - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, - DMA_PLAY_SOMETHING1 | - DMA_PLAY_SOMETHING2); - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, + DMA_RUN_SOMETHING1); + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, + DMA_RUN_SOMETHING1 | + DMA_RUN_SOMETHING2); + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, DMA_RESUME | SOMETHING_ALMOST_ALWAYS_SET | DMA_EPILOGUE_SOMETHING | DMA_SOMETHING_ELSE); #endif spin_unlock(&chip->reg_lock); - snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 1); - - /* now unmute WaveOut */ - if (!previously_muted) - snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); + snd_azf3328_ctrl_codec_activity(chip, codec_type, 1); + + if (is_playback_codec) { + /* now unmute WaveOut */ + if (!previously_muted) + snd_azf3328_mixer_set_mute( + chip, IDX_MIXER_WAVEOUT, 0 + ); + } - snd_azf3328_dbgplay("STARTED PLAYBACK\n"); + snd_azf3328_dbgplay("STARTED %s\n", codec->name); break; case SNDRV_PCM_TRIGGER_RESUME: - snd_azf3328_dbgplay("RESUME PLAYBACK\n"); - /* resume playback if we were active */ + snd_azf3328_dbgplay("RESUME %s\n", codec->name); + /* resume codec if we were active */ spin_lock(&chip->reg_lock); - if (chip->audio_stream[AZF_PLAYBACK].running) - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, - snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME); + if (codec->running) + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, + snd_azf3328_codec_inw( + codec, IDX_IO_CODEC_DMA_FLAGS + ) | DMA_RESUME + ); spin_unlock(&chip->reg_lock); break; case SNDRV_PCM_TRIGGER_STOP: - snd_azf3328_dbgplay("STOP PLAYBACK\n"); - - /* mute WaveOut (avoid clicking during setup) */ - previously_muted = - snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); + snd_azf3328_dbgplay("STOP %s\n", codec->name); + + if (is_playback_codec) { + /* mute WaveOut (avoid clicking during setup) */ + previously_muted = + snd_azf3328_mixer_set_mute( + chip, IDX_MIXER_WAVEOUT, 1 + ); + } spin_lock(&chip->reg_lock); /* first, remember current value: */ - status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); + flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); - /* stop playback */ - status1 &= ~DMA_RESUME; - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); + /* stop transfer */ + flags1 &= ~DMA_RESUME; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); /* hmm, is this really required? we're resetting the same bit * immediately thereafter... */ - status1 |= DMA_PLAY_SOMETHING1; - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); + flags1 |= DMA_RUN_SOMETHING1; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); - status1 &= ~DMA_PLAY_SOMETHING1; - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); + flags1 &= ~DMA_RUN_SOMETHING1; + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); spin_unlock(&chip->reg_lock); - snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); - - /* now unmute WaveOut */ - if (!previously_muted) - snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); + snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); + + if (is_playback_codec) { + /* now unmute WaveOut */ + if (!previously_muted) + snd_azf3328_mixer_set_mute( + chip, IDX_MIXER_WAVEOUT, 0 + ); + } - snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); + snd_azf3328_dbgplay("STOPPED %s\n", codec->name); break; case SNDRV_PCM_TRIGGER_SUSPEND: - snd_azf3328_dbgplay("SUSPEND PLAYBACK\n"); - /* make sure playback is stopped */ - snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, - snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) & ~DMA_RESUME); + snd_azf3328_dbgplay("SUSPEND %s\n", codec->name); + /* make sure codec is stopped */ + snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, + snd_azf3328_codec_inw( + codec, IDX_IO_CODEC_DMA_FLAGS + ) & ~DMA_RESUME + ); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); @@ -1225,172 +1320,74 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) return result; } -/* this is just analogous to playback; I'm not quite sure whether recording - * should actually be triggered like that */ static int -snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) +snd_azf3328_codec_playback_trigger(struct snd_pcm_substream *substream, int cmd) { - struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int result = 0; - unsigned int status1; - - snd_azf3328_dbgcalls("snd_azf3328_capture_trigger cmd %d\n", cmd); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - - snd_azf3328_dbgplay("START CAPTURE\n"); - - snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, - runtime->rate, - snd_pcm_format_width(runtime->format), - runtime->channels); - - spin_lock(&chip->reg_lock); - /* first, remember current value: */ - status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); - - /* stop recording */ - status1 &= ~DMA_RESUME; - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); - - /* FIXME: clear interrupts or what??? */ - snd_azf3328_codec_outw(chip, IDX_IO_REC_IRQTYPE, 0xffff); - spin_unlock(&chip->reg_lock); - - snd_azf3328_setdmaa(chip, runtime->dma_addr, - snd_pcm_lib_period_bytes(substream), - snd_pcm_lib_buffer_bytes(substream), - AZF_CAPTURE); - - spin_lock(&chip->reg_lock); -#ifdef WIN9X - /* FIXME: enable playback/recording??? */ - status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2; - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); - - /* start capture again */ - /* FIXME: what is this value (0x0010)??? */ - status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); -#else - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, - 0x0000); - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, - DMA_PLAY_SOMETHING1); - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, - DMA_PLAY_SOMETHING1 | - DMA_PLAY_SOMETHING2); - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, - DMA_RESUME | - SOMETHING_ALMOST_ALWAYS_SET | - DMA_EPILOGUE_SOMETHING | - DMA_SOMETHING_ELSE); -#endif - spin_unlock(&chip->reg_lock); - snd_azf3328_codec_activity(chip, AZF_CAPTURE, 1); - - snd_azf3328_dbgplay("STARTED CAPTURE\n"); - break; - case SNDRV_PCM_TRIGGER_RESUME: - snd_azf3328_dbgplay("RESUME CAPTURE\n"); - /* resume recording if we were active */ - spin_lock(&chip->reg_lock); - if (chip->audio_stream[AZF_CAPTURE].running) - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, - snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME); - spin_unlock(&chip->reg_lock); - break; - case SNDRV_PCM_TRIGGER_STOP: - snd_azf3328_dbgplay("STOP CAPTURE\n"); - - spin_lock(&chip->reg_lock); - /* first, remember current value: */ - status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); - - /* stop recording */ - status1 &= ~DMA_RESUME; - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); - - status1 |= DMA_PLAY_SOMETHING1; - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); - - status1 &= ~DMA_PLAY_SOMETHING1; - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); - spin_unlock(&chip->reg_lock); - snd_azf3328_codec_activity(chip, AZF_CAPTURE, 0); + return snd_azf3328_codec_trigger(AZF_CODEC_PLAYBACK, substream, cmd); +} - snd_azf3328_dbgplay("STOPPED CAPTURE\n"); - break; - case SNDRV_PCM_TRIGGER_SUSPEND: - snd_azf3328_dbgplay("SUSPEND CAPTURE\n"); - /* make sure recording is stopped */ - snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, - snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) & ~DMA_RESUME); - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); - break; - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); - break; - default: - printk(KERN_ERR "FIXME: unknown trigger mode!\n"); - return -EINVAL; - } +static int +snd_azf3328_codec_capture_trigger(struct snd_pcm_substream *substream, int cmd) +{ + return snd_azf3328_codec_trigger(AZF_CODEC_CAPTURE, substream, cmd); +} - snd_azf3328_dbgcallleave(); - return result; +static int +snd_azf3328_codec_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd) +{ + return snd_azf3328_codec_trigger(AZF_CODEC_I2S_OUT, substream, cmd); } static snd_pcm_uframes_t -snd_azf3328_playback_pointer(struct snd_pcm_substream *substream) +snd_azf3328_codec_pointer(struct snd_pcm_substream *substream, + enum snd_azf3328_codec_type codec_type +) { - struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); + const struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); + const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; unsigned long bufptr, result; snd_pcm_uframes_t frmres; #ifdef QUERY_HARDWARE - bufptr = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_START_1); + bufptr = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1); #else bufptr = substream->runtime->dma_addr; #endif - result = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_CURRPOS); + result = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_CURRPOS); /* calculate offset */ result -= bufptr; frmres = bytes_to_frames( substream->runtime, result); - snd_azf3328_dbgplay("PLAY @ 0x%8lx, frames %8ld\n", result, frmres); + snd_azf3328_dbgplay("%s @ 0x%8lx, frames %8ld\n", + codec->name, result, frmres); return frmres; } static snd_pcm_uframes_t -snd_azf3328_capture_pointer(struct snd_pcm_substream *substream) +snd_azf3328_codec_playback_pointer(struct snd_pcm_substream *substream) { - struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); - unsigned long bufptr, result; - snd_pcm_uframes_t frmres; + return snd_azf3328_codec_pointer(substream, AZF_CODEC_PLAYBACK); +} -#ifdef QUERY_HARDWARE - bufptr = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_START_1); -#else - bufptr = substream->runtime->dma_addr; -#endif - result = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_CURRPOS); +static snd_pcm_uframes_t +snd_azf3328_codec_capture_pointer(struct snd_pcm_substream *substream) +{ + return snd_azf3328_codec_pointer(substream, AZF_CODEC_CAPTURE); +} - /* calculate offset */ - result -= bufptr; - frmres = bytes_to_frames( substream->runtime, result); - snd_azf3328_dbgplay("REC @ 0x%8lx, frames %8ld\n", result, frmres); - return frmres; +static snd_pcm_uframes_t +snd_azf3328_codec_i2s_out_pointer(struct snd_pcm_substream *substream) +{ + return snd_azf3328_codec_pointer(substream, AZF_CODEC_I2S_OUT); } /******************************************************************/ #ifdef SUPPORT_GAMEPORT static inline void -snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable) +snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, + bool enable +) { snd_azf3328_io_reg_setb( chip->game_io+IDX_GAME_HWCONFIG, @@ -1400,7 +1397,9 @@ snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable) } static inline void -snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable) +snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, + bool enable +) { snd_azf3328_io_reg_setb( chip->game_io+IDX_GAME_HWCONFIG, @@ -1409,10 +1408,27 @@ snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable) ); } +static void +snd_azf3328_gameport_set_counter_frequency(struct snd_azf3328 *chip, + unsigned int freq_cfg +) +{ + snd_azf3328_io_reg_setb( + chip->game_io+IDX_GAME_HWCONFIG, + 0x02, + (freq_cfg & 1) != 0 + ); + snd_azf3328_io_reg_setb( + chip->game_io+IDX_GAME_HWCONFIG, + 0x04, + (freq_cfg & 2) != 0 + ); +} + static inline void -snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, int enable) +snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, bool enable) { - snd_azf3328_codec_reg_6AH_update( + snd_azf3328_ctrl_reg_6AH_update( chip, IO_6A_SOMETHING2_GAMEPORT, enable ); } @@ -1447,6 +1463,8 @@ snd_azf3328_gameport_open(struct gameport *gameport, int mode) break; } + snd_azf3328_gameport_set_counter_frequency(chip, + GAME_HWCFG_ADC_COUNTER_FREQ_STD); snd_azf3328_gameport_axis_circuit_enable(chip, (res == 0)); return res; @@ -1458,6 +1476,8 @@ snd_azf3328_gameport_close(struct gameport *gameport) struct snd_azf3328 *chip = gameport_get_port_data(gameport); snd_azf3328_dbggame("gameport_close\n"); + snd_azf3328_gameport_set_counter_frequency(chip, + GAME_HWCFG_ADC_COUNTER_FREQ_1_200); snd_azf3328_gameport_axis_circuit_enable(chip, 0); } @@ -1491,7 +1511,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport, val = snd_azf3328_game_inb(chip, IDX_GAME_AXES_CONFIG); if (val & GAME_AXES_SAMPLING_READY) { - for (i = 0; i < 4; ++i) { + for (i = 0; i < ARRAY_SIZE(chip->axes); ++i) { /* configure the axis to read */ val = (i << 4) | 0x0f; snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); @@ -1514,7 +1534,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport, snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff); spin_unlock_irqrestore(&chip->reg_lock, flags); - for (i = 0; i < 4; i++) { + for (i = 0; i < ARRAY_SIZE(chip->axes); i++) { axes[i] = chip->axes[i]; if (axes[i] == 0xffff) axes[i] = -1; @@ -1552,6 +1572,8 @@ snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) /* DISABLE legacy address: we don't need it! */ snd_azf3328_gameport_legacy_address_enable(chip, 0); + snd_azf3328_gameport_set_counter_frequency(chip, + GAME_HWCFG_ADC_COUNTER_FREQ_1_200); snd_azf3328_gameport_axis_circuit_enable(chip, 0); gameport_register_port(chip->gameport); @@ -1591,29 +1613,69 @@ snd_azf3328_irq_log_unknown_type(u8 which) ); } +static inline void +snd_azf3328_codec_interrupt(struct snd_azf3328 *chip, u8 status) +{ + u8 which; + enum snd_azf3328_codec_type codec_type; + const struct snd_azf3328_codec_data *codec; + + for (codec_type = AZF_CODEC_PLAYBACK; + codec_type <= AZF_CODEC_I2S_OUT; + ++codec_type) { + + /* skip codec if there's no interrupt for it */ + if (!(status & (1 << codec_type))) + continue; + + codec = &chip->codecs[codec_type]; + + spin_lock(&chip->reg_lock); + which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE); + /* ack all IRQ types immediately */ + snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); + spin_unlock(&chip->reg_lock); + + if ((chip->pcm[codec_type]) + && (chip->codecs[codec_type].substream)) { + snd_pcm_period_elapsed( + chip->codecs[codec_type].substream + ); + snd_azf3328_dbgplay("%s period done (#%x), @ %x\n", + codec->name, + which, + snd_azf3328_codec_inl( + codec, IDX_IO_CODEC_DMA_CURRPOS + ) + ); + } else + printk(KERN_WARNING "azt3328: irq handler problem!\n"); + if (which & IRQ_SOMETHING) + snd_azf3328_irq_log_unknown_type(which); + } +} + static irqreturn_t snd_azf3328_interrupt(int irq, void *dev_id) { struct snd_azf3328 *chip = dev_id; - u8 status, which; + u8 status; #if DEBUG_PLAY_REC static unsigned long irq_count; #endif - status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS); + status = snd_azf3328_ctrl_inb(chip, IDX_IO_IRQSTATUS); /* fast path out, to ease interrupt sharing */ if (!(status & - (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER) + (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT + |IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER) )) return IRQ_NONE; /* must be interrupt for another device */ snd_azf3328_dbgplay( - "irq_count %ld! IDX_IO_PLAY_FLAGS %04x, " - "IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n", + "irq_count %ld! IDX_IO_IRQSTATUS %04x\n", irq_count++ /* debug-only */, - snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS), - snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), status ); @@ -1626,63 +1688,24 @@ snd_azf3328_interrupt(int irq, void *dev_id) snd_timer_interrupt(chip->timer, chip->timer->sticks); /* ACK timer */ spin_lock(&chip->reg_lock); - snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); + snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); spin_unlock(&chip->reg_lock); snd_azf3328_dbgplay("azt3328: timer IRQ\n"); } - if (status & IRQ_PLAYBACK) { - spin_lock(&chip->reg_lock); - which = snd_azf3328_codec_inb(chip, IDX_IO_PLAY_IRQTYPE); - /* ack all IRQ types immediately */ - snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); - spin_unlock(&chip->reg_lock); - if (chip->pcm && chip->audio_stream[AZF_PLAYBACK].substream) { - snd_pcm_period_elapsed( - chip->audio_stream[AZF_PLAYBACK].substream - ); - snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", - which, - snd_azf3328_codec_inl( - chip, IDX_IO_PLAY_DMA_CURRPOS - ) - ); - } else - printk(KERN_WARNING "azt3328: irq handler problem!\n"); - if (which & IRQ_PLAY_SOMETHING) - snd_azf3328_irq_log_unknown_type(which); - } - if (status & IRQ_RECORDING) { - spin_lock(&chip->reg_lock); - which = snd_azf3328_codec_inb(chip, IDX_IO_REC_IRQTYPE); - /* ack all IRQ types immediately */ - snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); - spin_unlock(&chip->reg_lock); + if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) + snd_azf3328_codec_interrupt(chip, status); - if (chip->pcm && chip->audio_stream[AZF_CAPTURE].substream) { - snd_pcm_period_elapsed( - chip->audio_stream[AZF_CAPTURE].substream - ); - snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", - which, - snd_azf3328_codec_inl( - chip, IDX_IO_REC_DMA_CURRPOS - ) - ); - } else - printk(KERN_WARNING "azt3328: irq handler problem!\n"); - if (which & IRQ_REC_SOMETHING) - snd_azf3328_irq_log_unknown_type(which); - } if (status & IRQ_GAMEPORT) snd_azf3328_gameport_interrupt(chip); + /* MPU401 has less critical IRQ requirements * than timer and playback/recording, right? */ if (status & IRQ_MPU401) { snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); /* hmm, do we have to ack the IRQ here somehow? - * If so, then I don't know how... */ + * If so, then I don't know how yet... */ snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); } return IRQ_HANDLED; @@ -1690,7 +1713,11 @@ snd_azf3328_interrupt(int irq, void *dev_id) /*****************************************************************/ -static const struct snd_pcm_hardware snd_azf3328_playback = +/* as long as we think we have identical snd_pcm_hardware parameters + for playback, capture and i2s out, we can use the same physical struct + since the struct is simply being copied into a member. +*/ +static const struct snd_pcm_hardware snd_azf3328_hardware = { /* FIXME!! Correct? */ .info = SNDRV_PCM_INFO_MMAP | @@ -1718,31 +1745,6 @@ static const struct snd_pcm_hardware snd_azf3328_playback = .fifo_size = 0, }; -static const struct snd_pcm_hardware snd_azf3328_capture = -{ - /* FIXME */ - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID, - .formats = SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_U16_LE, - .rates = SNDRV_PCM_RATE_5512 | - SNDRV_PCM_RATE_8000_48000 | - SNDRV_PCM_RATE_KNOT, - .rate_min = AZF_FREQ_4000, - .rate_max = AZF_FREQ_66200, - .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = 65536, - .period_bytes_min = 64, - .period_bytes_max = 65536, - .periods_min = 1, - .periods_max = 1024, - .fifo_size = 0, -}; - static unsigned int snd_azf3328_fixed_rates[] = { AZF_FREQ_4000, @@ -1770,14 +1772,19 @@ static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = { /*****************************************************************/ static int -snd_azf3328_playback_open(struct snd_pcm_substream *substream) +snd_azf3328_pcm_open(struct snd_pcm_substream *substream, + enum snd_azf3328_codec_type codec_type +) { struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; snd_azf3328_dbgcallenter(); - chip->audio_stream[AZF_PLAYBACK].substream = substream; - runtime->hw = snd_azf3328_playback; + chip->codecs[codec_type].substream = substream; + + /* same parameters for all our codecs - at least we think so... */ + runtime->hw = snd_azf3328_hardware; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &snd_azf3328_hw_constraints_rates); snd_azf3328_dbgcallleave(); @@ -1785,40 +1792,52 @@ snd_azf3328_playback_open(struct snd_pcm_substream *substream) } static int +snd_azf3328_playback_open(struct snd_pcm_substream *substream) +{ + return snd_azf3328_pcm_open(substream, AZF_CODEC_PLAYBACK); +} + +static int snd_azf3328_capture_open(struct snd_pcm_substream *substream) { - struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; + return snd_azf3328_pcm_open(substream, AZF_CODEC_CAPTURE); +} - snd_azf3328_dbgcallenter(); - chip->audio_stream[AZF_CAPTURE].substream = substream; - runtime->hw = snd_azf3328_capture; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - &snd_azf3328_hw_constraints_rates); - snd_azf3328_dbgcallleave(); - return 0; +static int +snd_azf3328_i2s_out_open(struct snd_pcm_substream *substream) +{ + return snd_azf3328_pcm_open(substream, AZF_CODEC_I2S_OUT); } static int -snd_azf3328_playback_close(struct snd_pcm_substream *substream) +snd_azf3328_pcm_close(struct snd_pcm_substream *substream, + enum snd_azf3328_codec_type codec_type +) { struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); snd_azf3328_dbgcallenter(); - chip->audio_stream[AZF_PLAYBACK].substream = NULL; + chip->codecs[codec_type].substream = NULL; snd_azf3328_dbgcallleave(); return 0; } static int +snd_azf3328_playback_close(struct snd_pcm_substream *substream) +{ + return snd_azf3328_pcm_close(substream, AZF_CODEC_PLAYBACK); +} + +static int snd_azf3328_capture_close(struct snd_pcm_substream *substream) { - struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); + return snd_azf3328_pcm_close(substream, AZF_CODEC_CAPTURE); +} - snd_azf3328_dbgcallenter(); - chip->audio_stream[AZF_CAPTURE].substream = NULL; - snd_azf3328_dbgcallleave(); - return 0; +static int +snd_azf3328_i2s_out_close(struct snd_pcm_substream *substream) +{ + return snd_azf3328_pcm_close(substream, AZF_CODEC_I2S_OUT); } /******************************************************************/ @@ -1829,9 +1848,9 @@ static struct snd_pcm_ops snd_azf3328_playback_ops = { .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_azf3328_hw_params, .hw_free = snd_azf3328_hw_free, - .prepare = snd_azf3328_playback_prepare, - .trigger = snd_azf3328_playback_trigger, - .pointer = snd_azf3328_playback_pointer + .prepare = snd_azf3328_codec_prepare, + .trigger = snd_azf3328_codec_playback_trigger, + .pointer = snd_azf3328_codec_playback_pointer }; static struct snd_pcm_ops snd_azf3328_capture_ops = { @@ -1840,30 +1859,67 @@ static struct snd_pcm_ops snd_azf3328_capture_ops = { .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_azf3328_hw_params, .hw_free = snd_azf3328_hw_free, - .prepare = snd_azf3328_capture_prepare, - .trigger = snd_azf3328_capture_trigger, - .pointer = snd_azf3328_capture_pointer + .prepare = snd_azf3328_codec_prepare, + .trigger = snd_azf3328_codec_capture_trigger, + .pointer = snd_azf3328_codec_capture_pointer +}; + +static struct snd_pcm_ops snd_azf3328_i2s_out_ops = { + .open = snd_azf3328_i2s_out_open, + .close = snd_azf3328_i2s_out_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_azf3328_hw_params, + .hw_free = snd_azf3328_hw_free, + .prepare = snd_azf3328_codec_prepare, + .trigger = snd_azf3328_codec_i2s_out_trigger, + .pointer = snd_azf3328_codec_i2s_out_pointer }; static int __devinit -snd_azf3328_pcm(struct snd_azf3328 *chip, int device) +snd_azf3328_pcm(struct snd_azf3328 *chip) { +enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */ + struct snd_pcm *pcm; int err; snd_azf3328_dbgcallenter(); - if ((err = snd_pcm_new(chip->card, "AZF3328 DSP", device, 1, 1, &pcm)) < 0) + + err = snd_pcm_new(chip->card, "AZF3328 DSP", AZF_PCMDEV_STD, + 1, 1, &pcm); + if (err < 0) return err; - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_azf3328_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_azf3328_capture_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_azf3328_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_azf3328_capture_ops); pcm->private_data = chip; pcm->info_flags = 0; strcpy(pcm->name, chip->card->shortname); - chip->pcm = pcm; + /* same pcm object for playback/capture (see snd_pcm_new() above) */ + chip->pcm[AZF_CODEC_PLAYBACK] = pcm; + chip->pcm[AZF_CODEC_CAPTURE] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), 64*1024, 64*1024); + snd_dma_pci_data(chip->pci), + 64*1024, 64*1024); + + err = snd_pcm_new(chip->card, "AZF3328 I2S OUT", AZF_PCMDEV_I2S_OUT, + 1, 0, &pcm); + if (err < 0) + return err; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_azf3328_i2s_out_ops); + + pcm->private_data = chip; + pcm->info_flags = 0; + strcpy(pcm->name, chip->card->shortname); + chip->pcm[AZF_CODEC_I2S_OUT] = pcm; + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + 64*1024, 64*1024); snd_azf3328_dbgcallleave(); return 0; @@ -1902,7 +1958,7 @@ snd_azf3328_timer_start(struct snd_timer *timer) snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; spin_lock_irqsave(&chip->reg_lock, flags); - snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay); + snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_azf3328_dbgcallleave(); return 0; @@ -1919,7 +1975,7 @@ snd_azf3328_timer_stop(struct snd_timer *timer) spin_lock_irqsave(&chip->reg_lock, flags); /* disable timer countdown and interrupt */ /* FIXME: should we write TIMER_IRQ_ACK here? */ - snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); + snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_azf3328_dbgcallleave(); return 0; @@ -2048,9 +2104,9 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) u16 tmp; snd_azf3328_dbgmisc( - "codec_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, " + "ctrl_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, " "opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n", - chip->codec_io, chip->game_io, chip->mpu_io, + chip->ctrl_io, chip->game_io, chip->mpu_io, chip->opl3_io, chip->mixer_io, chip->irq ); @@ -2083,9 +2139,9 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) inb(0x38c + tmp) ); - for (tmp = 0; tmp < AZF_IO_SIZE_CODEC; tmp += 2) - snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n", - tmp, snd_azf3328_codec_inw(chip, tmp) + for (tmp = 0; tmp < AZF_IO_SIZE_CTRL; tmp += 2) + snd_azf3328_dbgmisc("ctrl 0x%02x: 0x%04x\n", + tmp, snd_azf3328_ctrl_inw(chip, tmp) ); for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) @@ -2106,7 +2162,8 @@ snd_azf3328_create(struct snd_card *card, static struct snd_device_ops ops = { .dev_free = snd_azf3328_dev_free, }; - u16 tmp; + u8 dma_init; + enum snd_azf3328_codec_type codec_type; *rchip = NULL; @@ -2138,14 +2195,21 @@ snd_azf3328_create(struct snd_card *card, if (err < 0) goto out_err; - chip->codec_io = pci_resource_start(pci, 0); + chip->ctrl_io = pci_resource_start(pci, 0); chip->game_io = pci_resource_start(pci, 1); chip->mpu_io = pci_resource_start(pci, 2); - chip->opl3_io = pci_resource_start(pci, 3); + chip->opl3_io = pci_resource_start(pci, 3); chip->mixer_io = pci_resource_start(pci, 4); - chip->audio_stream[AZF_PLAYBACK].portbase = chip->codec_io + 0x00; - chip->audio_stream[AZF_CAPTURE].portbase = chip->codec_io + 0x20; + chip->codecs[AZF_CODEC_PLAYBACK].io_base = + chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK; + chip->codecs[AZF_CODEC_PLAYBACK].name = "PLAYBACK"; + chip->codecs[AZF_CODEC_CAPTURE].io_base = + chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE; + chip->codecs[AZF_CODEC_CAPTURE].name = "CAPTURE"; + chip->codecs[AZF_CODEC_I2S_OUT].io_base = + chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT; + chip->codecs[AZF_CODEC_I2S_OUT].name = "I2S_OUT"; if (request_irq(pci->irq, snd_azf3328_interrupt, IRQF_SHARED, card->shortname, chip)) { @@ -2168,20 +2232,25 @@ snd_azf3328_create(struct snd_card *card, if (err < 0) goto out_err; - /* shutdown codecs to save power */ - /* have snd_azf3328_codec_activity() act properly */ - chip->audio_stream[AZF_PLAYBACK].running = 1; - snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); + /* standard codec init stuff */ + /* default DMA init value */ + dma_init = DMA_RUN_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; + + for (codec_type = AZF_CODEC_PLAYBACK; + codec_type <= AZF_CODEC_I2S_OUT; ++codec_type) { + struct snd_azf3328_codec_data *codec = + &chip->codecs[codec_type]; - /* standard chip init stuff */ - /* default IRQ init value */ - tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; + /* shutdown codecs to save power */ + /* have ...ctrl_codec_activity() act properly */ + codec->running = 1; + snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); - spin_lock_irq(&chip->reg_lock); - snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp); - snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp); - snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp); - spin_unlock_irq(&chip->reg_lock); + spin_lock_irq(&chip->reg_lock); + snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS, + dma_init); + spin_unlock_irq(&chip->reg_lock); + } snd_card_set_dev(card, &pci->dev); @@ -2244,7 +2313,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (err < 0) goto out_err; - err = snd_azf3328_pcm(chip, 0); + err = snd_azf3328_pcm(chip); if (err < 0) goto out_err; @@ -2266,7 +2335,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) opl3->private_data = chip; sprintf(card->longname, "%s at 0x%lx, irq %i", - card->shortname, chip->codec_io, chip->irq); + card->shortname, chip->ctrl_io, chip->irq); err = snd_card_register(card); if (err < 0) @@ -2317,7 +2386,8 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); + snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]); + snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]); for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2); @@ -2326,11 +2396,11 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); - for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) - chip->saved_regs_codec[reg] = inw(chip->codec_io + reg * 2); + for (reg = 0; reg < AZF_IO_SIZE_CTRL_PM / 2; ++reg) + chip->saved_regs_ctrl[reg] = inw(chip->ctrl_io + reg * 2); /* manually store the one currently relevant write-only reg, too */ - chip->saved_regs_codec[IDX_IO_6AH / 2] = chip->shadow_reg_codec_6AH; + chip->saved_regs_ctrl[IDX_IO_6AH / 2] = chip->shadow_reg_ctrl_6AH; for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2); @@ -2349,7 +2419,7 @@ static int snd_azf3328_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); - struct snd_azf3328 *chip = card->private_data; + const struct snd_azf3328 *chip = card->private_data; unsigned reg; pci_set_power_state(pci, PCI_D0); @@ -2370,8 +2440,8 @@ snd_azf3328_resume(struct pci_dev *pci) outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2); for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) - outw(chip->saved_regs_codec[reg], chip->codec_io + reg * 2); + for (reg = 0; reg < AZF_IO_SIZE_CTRL_PM / 2; ++reg) + outw(chip->saved_regs_ctrl[reg], chip->ctrl_io + reg * 2); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h index 974e051..11d4b10 100644 --- a/sound/pci/azt3328.h +++ b/sound/pci/azt3328.h @@ -6,50 +6,59 @@ /*** main I/O area port indices ***/ /* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ -#define AZF_IO_SIZE_CODEC 0x80 -#define AZF_IO_SIZE_CODEC_PM 0x70 +#define AZF_IO_SIZE_CTRL 0x80 +#define AZF_IO_SIZE_CTRL_PM 0x70 -/* the driver initialisation suggests a layout of 4 main areas: - * from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe MPU401??). +/* the driver initialisation suggests a layout of 4 areas + * within the main card control I/O: + * from 0x00 (playback codec), from 0x20 (recording codec) + * and from 0x40 (most certainly I2S out codec). * And another area from 0x60 to 0x6f (DirectX timer, IRQ management, * power management etc.???). */ -/** playback area **/ -#define IDX_IO_PLAY_FLAGS 0x00 /* PU:0x0000 */ +#define AZF_IO_OFFS_CODEC_PLAYBACK 0x00 +#define AZF_IO_OFFS_CODEC_CAPTURE 0x20 +#define AZF_IO_OFFS_CODEC_I2S_OUT 0x40 + +#define IDX_IO_CODEC_DMA_FLAGS 0x00 /* PU:0x0000 */ /* able to reactivate output after output muting due to 8/16bit * output change, just like 0x0002. * 0x0001 is the only bit that's able to start the DMA counter */ - #define DMA_RESUME 0x0001 /* paused if cleared ? */ + #define DMA_RESUME 0x0001 /* paused if cleared? */ /* 0x0002 *temporarily* set during DMA stopping. hmm * both 0x0002 and 0x0004 set in playback setup. */ /* able to reactivate output after output muting due to 8/16bit * output change, just like 0x0001. */ - #define DMA_PLAY_SOMETHING1 0x0002 /* \ alternated (toggled) */ + #define DMA_RUN_SOMETHING1 0x0002 /* \ alternated (toggled) */ /* 0x0004: NOT able to reactivate output */ - #define DMA_PLAY_SOMETHING2 0x0004 /* / bits */ + #define DMA_RUN_SOMETHING2 0x0004 /* / bits */ #define SOMETHING_ALMOST_ALWAYS_SET 0x0008 /* ???; can be modified */ #define DMA_EPILOGUE_SOMETHING 0x0010 #define DMA_SOMETHING_ELSE 0x0020 /* ??? */ - #define SOMETHING_UNMODIFIABLE 0xffc0 /* unused ? not modifiable */ -#define IDX_IO_PLAY_IRQTYPE 0x02 /* PU:0x0001 */ + #define SOMETHING_UNMODIFIABLE 0xffc0 /* unused? not modifiable */ +#define IDX_IO_CODEC_IRQTYPE 0x02 /* PU:0x0001 */ /* write back to flags in case flags are set, in order to ACK IRQ in handler * (bit 1 of port 0x64 indicates interrupt for one of these three types) * sometimes in this case it just writes 0xffff to globally ACK all IRQs * settings written are not reflected when reading back, though. - * seems to be IRQ, too (frequently used: port |= 0x07 !), but who knows ? */ - #define IRQ_PLAY_SOMETHING 0x0001 /* something & ACK */ - #define IRQ_FINISHED_PLAYBUF_1 0x0002 /* 1st dmabuf finished & ACK */ - #define IRQ_FINISHED_PLAYBUF_2 0x0004 /* 2nd dmabuf finished & ACK */ + * seems to be IRQ, too (frequently used: port |= 0x07 !), but who knows? */ + #define IRQ_SOMETHING 0x0001 /* something & ACK */ + #define IRQ_FINISHED_DMABUF_1 0x0002 /* 1st dmabuf finished & ACK */ + #define IRQ_FINISHED_DMABUF_2 0x0004 /* 2nd dmabuf finished & ACK */ #define IRQMASK_SOME_STATUS_1 0x0008 /* \ related bits */ #define IRQMASK_SOME_STATUS_2 0x0010 /* / (checked together in loop) */ - #define IRQMASK_UNMODIFIABLE 0xffe0 /* unused ? not modifiable */ -#define IDX_IO_PLAY_DMA_START_1 0x04 /* start address of 1st DMA play area, PU:0x00000000 */ -#define IDX_IO_PLAY_DMA_START_2 0x08 /* start address of 2nd DMA play area, PU:0x00000000 */ -#define IDX_IO_PLAY_DMA_LEN_1 0x0c /* length of 1st DMA play area, PU:0x0000 */ -#define IDX_IO_PLAY_DMA_LEN_2 0x0e /* length of 2nd DMA play area, PU:0x0000 */ -#define IDX_IO_PLAY_DMA_CURRPOS 0x10 /* current DMA position, PU:0x00000000 */ -#define IDX_IO_PLAY_DMA_CURROFS 0x14 /* offset within current DMA play area, PU:0x0000 */ -#define IDX_IO_PLAY_SOUNDFORMAT 0x16 /* PU:0x0010 */ + #define IRQMASK_UNMODIFIABLE 0xffe0 /* unused? not modifiable */ + /* start address of 1st DMA transfer area, PU:0x00000000 */ +#define IDX_IO_CODEC_DMA_START_1 0x04 + /* start address of 2nd DMA transfer area, PU:0x00000000 */ +#define IDX_IO_CODEC_DMA_START_2 0x08 + /* both lengths of DMA transfer areas, PU:0x00000000 + length1: offset 0x0c, length2: offset 0x0e */ +#define IDX_IO_CODEC_DMA_LENGTHS 0x0c +#define IDX_IO_CODEC_DMA_CURRPOS 0x10 /* current DMA position, PU:0x00000000 */ + /* offset within current DMA transfer area, PU:0x0000 */ +#define IDX_IO_CODEC_DMA_CURROFS 0x14 +#define IDX_IO_CODEC_SOUNDFORMAT 0x16 /* PU:0x0010 */ /* all unspecified bits can't be modified */ #define SOUNDFORMAT_FREQUENCY_MASK 0x000f #define SOUNDFORMAT_XTAL1 0x00 @@ -76,6 +85,7 @@ #define SOUNDFORMAT_FLAG_16BIT 0x0010 #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020 + /* define frequency helpers, for maximum value safety */ enum azf_freq_t { #define AZF_FREQ(rate) AZF_FREQ_##rate = rate @@ -96,29 +106,6 @@ enum azf_freq_t { #undef AZF_FREQ }; -/** recording area (see also: playback bit flag definitions) **/ -#define IDX_IO_REC_FLAGS 0x20 /* ??, PU:0x0000 */ -#define IDX_IO_REC_IRQTYPE 0x22 /* ??, PU:0x0000 */ - #define IRQ_REC_SOMETHING 0x0001 /* something & ACK */ - #define IRQ_FINISHED_RECBUF_1 0x0002 /* 1st dmabuf finished & ACK */ - #define IRQ_FINISHED_RECBUF_2 0x0004 /* 2nd dmabuf finished & ACK */ - /* hmm, maybe these are just the corresponding *recording* flags ? - * but OTOH they are most likely at port 0x22 instead */ - #define IRQMASK_SOME_STATUS_1 0x0008 /* \ related bits */ - #define IRQMASK_SOME_STATUS_2 0x0010 /* / (checked together in loop) */ -#define IDX_IO_REC_DMA_START_1 0x24 /* PU:0x00000000 */ -#define IDX_IO_REC_DMA_START_2 0x28 /* PU:0x00000000 */ -#define IDX_IO_REC_DMA_LEN_1 0x2c /* PU:0x0000 */ -#define IDX_IO_REC_DMA_LEN_2 0x2e /* PU:0x0000 */ -#define IDX_IO_REC_DMA_CURRPOS 0x30 /* PU:0x00000000 */ -#define IDX_IO_REC_DMA_CURROFS 0x34 /* PU:0x00000000 */ -#define IDX_IO_REC_SOUNDFORMAT 0x36 /* PU:0x0000 */ - -/** hmm, what is this I/O area for? MPU401?? or external DAC via I2S?? (after playback, recording, ???, timer) **/ -#define IDX_IO_SOMETHING_FLAGS 0x40 /* gets set to 0x34 just like port 0x0 and 0x20 on card init, PU:0x0000 */ -/* general */ -#define IDX_IO_42H 0x42 /* PU:0x0001 */ - /** DirectX timer, main interrupt area (FIXME: and something else?) **/ #define IDX_IO_TIMER_VALUE 0x60 /* found this timer area by pure luck :-) */ /* timer countdown value; triggers IRQ when timer is finished */ @@ -138,7 +125,7 @@ enum azf_freq_t { #define IRQ_PLAYBACK 0x0001 #define IRQ_RECORDING 0x0002 - #define IRQ_UNKNOWN1 0x0004 /* most probably I2S port */ + #define IRQ_I2S_OUT 0x0004 /* this IS I2S, right!? (untested) */ #define IRQ_GAMEPORT 0x0008 /* Interrupt of Digital(ly) Enhanced Game Port */ #define IRQ_MPU401 0x0010 #define IRQ_TIMER 0x0020 /* DirectX timer */ @@ -272,6 +259,12 @@ enum { * 11 --> 1/200: */ #define GAME_HWCFG_ADC_COUNTER_FREQ_MASK 0x06 + /* FIXME: these values might be reversed... */ + #define GAME_HWCFG_ADC_COUNTER_FREQ_STD 0 + #define GAME_HWCFG_ADC_COUNTER_FREQ_1_2 1 + #define GAME_HWCFG_ADC_COUNTER_FREQ_1_20 2 + #define GAME_HWCFG_ADC_COUNTER_FREQ_1_200 3 + /* enable gameport legacy I/O address (0x200) * I was unable to locate any configurability for a different address: */ #define GAME_HWCFG_LEGACY_ADDRESS_ENABLE 0x08 -- cgit v0.10.2 From 21a4dc43acdd547335f59ad52efeef5160247736 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 6 Jul 2009 12:55:46 +0200 Subject: ALSA: hda - Fix cirrus codec parsing The parser wasn't called in the proper order. Split now the parser to be called in patch_cirrus(), and the rest are just for building PCMs and controls. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index c4dc12e..051302e 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -56,7 +56,6 @@ struct cs_spec { unsigned int hp_detect:1; unsigned int mic_detect:1; - unsigned int built_up:1; }; #define HP_EVENT 1 @@ -213,7 +212,6 @@ static int cs_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; info->stream[SNDRV_PCM_STREAM_CAPTURE] = cs_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nid[spec->cur_input]; codec->num_pcms++; @@ -242,6 +240,10 @@ static int cs_build_pcms(struct hda_codec *codec) return 0; } +/* + * parse codec topology + */ + static hda_nid_t get_dac(struct hda_codec *codec, hda_nid_t pin) { hda_nid_t dac; @@ -252,6 +254,169 @@ static hda_nid_t get_dac(struct hda_codec *codec, hda_nid_t pin) return dac; } +static int is_ext_mic(struct hda_codec *codec, unsigned int idx) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t pin = cfg->input_pins[idx]; + unsigned int val = snd_hda_query_pin_caps(codec, pin); + if (!(val & AC_PINCAP_PRES_DETECT)) + return 0; + val = snd_hda_codec_get_pincfg(codec, pin); + return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX); +} + +static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, + unsigned int *idxp) +{ + int i; + hda_nid_t nid; + + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { + hda_nid_t pins[2]; + unsigned int type; + int j, nums; + type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) + >> AC_WCAP_TYPE_SHIFT; + if (type != AC_WID_AUD_IN) + continue; + nums = snd_hda_get_connections(codec, nid, pins, + ARRAY_SIZE(pins)); + if (nums <= 0) + continue; + for (j = 0; j < nums; j++) { + if (pins[j] == pin) { + *idxp = j; + return nid; + } + } + } + return 0; +} + +static int parse_output(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, err, extra_nids; + hda_nid_t dac; + + for (i = 0; i < cfg->line_outs; i++) { + dac = get_dac(codec, cfg->line_out_pins[i]); + if (!dac) + break; + spec->dac_nid[i] = dac; + } + spec->multiout.num_dacs = i; + spec->multiout.dac_nids = spec->dac_nid; + spec->multiout.max_channels = i * 2; + + /* add HP and speakers */ + extra_nids = 0; + for (i = 0; i < cfg->hp_outs; i++) { + dac = get_dac(codec, cfg->hp_pins[i]); + if (!dac) + break; + if (!i) + spec->multiout.hp_nid = dac; + else + spec->multiout.extra_out_nid[extra_nids++] = dac; + } + for (i = 0; i < cfg->speaker_outs; i++) { + dac = get_dac(codec, cfg->speaker_pins[i]); + if (!dac) + break; + spec->multiout.extra_out_nid[extra_nids++] = dac; + } + + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { + cfg->speaker_outs = cfg->line_outs; + memcpy(cfg->speaker_pins, cfg->line_out_pins, + sizeof(cfg->speaker_pins)); + cfg->line_outs = 0; + } + + return 0; +} + +static int parse_input(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, n, err; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + hda_nid_t pin = cfg->input_pins[i]; + struct snd_kcontrol *kctl; + if (!pin) + continue; + spec->input_idx[spec->num_inputs] = i; + spec->capsrc_idx[i] = spec->num_inputs++; + spec->cur_input = i; + spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); + } + if (!spec->num_inputs) + return 0; + + /* check whether the automatic mic switch is available */ + if (spec->num_inputs == 2 && + spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) { + if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) { + if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { + spec->mic_detect = 1; + spec->automic_idx = AUTO_PIN_FRONT_MIC; + } + } else { + if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { + spec->mic_detect = 1; + spec->automic_idx = AUTO_PIN_MIC; + } + } + } + return 0; +} + + +static int parse_digital_output(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid; + int err; + + if (!cfg->dig_outs) + return 0; + if (snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) < 1) + return 0; + spec->multiout.dig_out_nid = nid; + spec->multiout.share_spdif = 1; + if (cfg->dig_outs > 1 && + snd_hda_get_connections(codec, cfg->dig_out_pins[1], &nid, 1) > 0) { + spec->slave_dig_outs[0] = nid; + codec->slave_dig_outs = spec->slave_dig_outs; + } + return 0; +} + +static int parse_digital_input(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int idx; + + if (!cfg->dig_in_pin) + return 0; + spec->dig_in = get_adc(codec, cfg->dig_in_pin, &idx); + if (!spec->dig_in) + return 0; + return snd_hda_create_spdif_in_ctls(codec, spec->dig_in); +} + +/* + * create mixer controls + */ + static const char *dir_sfx[2] = { "Playback", "Capture" }; static int add_mute(struct hda_codec *codec, const char *name, int index, @@ -376,55 +541,26 @@ static int build_output(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err, extra_nids; - hda_nid_t dac; + int i, err; for (i = 0; i < cfg->line_outs; i++) { - dac = get_dac(codec, cfg->line_out_pins[i]); - if (!dac) - break; - spec->dac_nid[i] = dac; - err = add_output(codec, dac, i, cfg->line_outs, - cfg->line_out_type); + err = add_output(codec, get_dac(codec, cfg->line_out_pins[i]), + i, cfg->line_outs, cfg->line_out_type); if (err < 0) return err; } - spec->multiout.num_dacs = i; - spec->multiout.dac_nids = spec->dac_nid; - spec->multiout.max_channels = i * 2; - - /* add HP and speakers */ - extra_nids = 0; for (i = 0; i < cfg->hp_outs; i++) { - dac = get_dac(codec, cfg->hp_pins[i]); - if (!dac) - break; - if (!i) - spec->multiout.hp_nid = dac; - else - spec->multiout.extra_out_nid[extra_nids++] = dac; - err = add_output(codec, dac, i, cfg->hp_outs, AUTO_PIN_HP_OUT); + err = add_output(codec, get_dac(codec, cfg->hp_pins[i]), + i, cfg->hp_outs, AUTO_PIN_HP_OUT); if (err < 0) return err; } for (i = 0; i < cfg->speaker_outs; i++) { - dac = get_dac(codec, cfg->speaker_pins[i]); - if (!dac) - break; - spec->multiout.extra_out_nid[extra_nids++] = dac; - err = add_output(codec, dac, i, cfg->speaker_outs, - AUTO_PIN_SPEAKER_OUT); + err = add_output(codec, get_dac(codec, cfg->speaker_pins[i]), + i, cfg->speaker_outs, AUTO_PIN_SPEAKER_OUT); if (err < 0) return err; } - - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = 0; - } - return 0; } @@ -506,48 +642,6 @@ static struct snd_kcontrol_new cs_capture_source = { .put = cs_capture_source_put, }; - -static int is_ext_mic(struct hda_codec *codec, unsigned int idx) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t pin = cfg->input_pins[idx]; - unsigned int val = snd_hda_query_pin_caps(codec, pin); - if (!(val & AC_PINCAP_PRES_DETECT)) - return 0; - val = snd_hda_codec_get_pincfg(codec, pin); - return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX); -} - -static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, - unsigned int *idxp) -{ - int i; - hda_nid_t nid; - - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - hda_nid_t pins[2]; - unsigned int type; - int j, nums; - type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) - >> AC_WCAP_TYPE_SHIFT; - if (type != AC_WID_AUD_IN) - continue; - nums = snd_hda_get_connections(codec, nid, pins, - ARRAY_SIZE(pins)); - if (nums <= 0) - continue; - for (j = 0; j < nums; j++) { - if (pins[j] == pin) { - *idxp = j; - return nid; - } - } - } - return 0; -} - static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, struct hda_ctl_ops *ops) { @@ -574,38 +668,11 @@ static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, static int build_input(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, n, err; + int i, err; - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t pin = cfg->input_pins[i]; - struct snd_kcontrol *kctl; - if (!pin) - continue; - spec->input_idx[spec->num_inputs] = i; - spec->capsrc_idx[i] = spec->num_inputs++; - spec->cur_input = i; - spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); - } if (!spec->num_inputs) return 0; - /* check whether the automatic mic switch is available */ - if (spec->num_inputs == 2 && - spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) { - if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) { - if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { - spec->mic_detect = 1; - spec->automic_idx = AUTO_PIN_FRONT_MIC; - } - } else { - if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { - spec->mic_detect = 1; - spec->automic_idx = AUTO_PIN_MIC; - } - } - } - /* make bind-capture */ spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw); spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); @@ -632,47 +699,35 @@ static int build_input(struct hda_codec *codec) return 0; } +/* + */ + static int build_digital_output(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; int err; - if (!cfg->dig_outs) - return 0; - if (snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) < 1) - return 0; - spec->multiout.dig_out_nid = nid; err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); if (err < 0) return err; - spec->multiout.share_spdif = 1; - if (cfg->dig_outs > 1 && - snd_hda_get_connections(codec, cfg->dig_out_pins[1], &nid, 1) > 0) { - spec->slave_dig_outs[0] = nid; - codec->slave_dig_outs = spec->slave_dig_outs; - } return 0; } static int build_digital_input(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int idx; - - if (!cfg->dig_in_pin) - return 0; - spec->dig_in = get_adc(codec, cfg->dig_in_pin, &idx); - if (!spec->dig_in) - return 0; - return snd_hda_create_spdif_in_ctls(codec, spec->dig_in); + if (spec->dig_in) + return snd_hda_create_spdif_in_ctls(codec, spec->dig_in); + return 0; } +/* + * auto-mute and auto-mic switching + */ + static void cs_automute(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; @@ -810,8 +865,6 @@ static int cs_init(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; - if (!spec->built_up) - return 0; init_output(codec); init_input(codec); return 0; @@ -834,7 +887,6 @@ static int cs_build_controls(struct hda_codec *codec) err = build_digital_input(codec); if (err < 0) return err; - spec->built_up = 1; return cs_init(codec); } @@ -892,6 +944,19 @@ static int patch_cs420x(struct hda_codec *codec) if (err < 0) goto error; + err = parse_output(codec); + if (err < 0) + goto error; + err = parse_input(codec); + if (err < 0) + goto error; + err = parse_digital_output(codec); + if (err < 0) + goto error; + err = parse_digital_input(codec); + if (err < 0) + goto error; + codec->patch_ops = cs_patch_ops; return 0; -- cgit v0.10.2 From ea35929b886975a240660b3ba6c61826761731ad Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 6 Jul 2009 12:58:59 +0200 Subject: ALSA: hda - Force to initialize input mixer setup for CS420x Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 051302e..8e33214 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -572,12 +572,13 @@ static struct snd_kcontrol_new cs_capture_ctls[] = { HDA_BIND_VOL("Capture Volume", 0), }; -static int change_cur_input(struct hda_codec *codec, unsigned int idx) +static int change_cur_input(struct hda_codec *codec, unsigned int idx, + int force) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - if (spec->cur_input == idx) + if (spec->cur_input == idx && !force) return 0; if (spec->cur_adc && spec->cur_adc != spec->adc_nid[idx]) { /* stream is running, let's swap the current ADC */ @@ -630,7 +631,7 @@ static int cs_capture_source_put(struct snd_kcontrol *kcontrol, if (idx >= spec->num_inputs) return -EINVAL; idx = spec->input_idx[idx]; - return change_cur_input(codec, idx); + return change_cur_input(codec, idx, 0); } static struct snd_kcontrol_new cs_capture_source = { @@ -773,11 +774,11 @@ static void cs_automic(struct hda_codec *codec) present = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); if (present & AC_PINSENSE_PRESENCE) - change_cur_input(codec, spec->automic_idx); + change_cur_input(codec, spec->automic_idx, 0); else { unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ? AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC; - change_cur_input(codec, imic); + change_cur_input(codec, imic, 0); } } @@ -857,6 +858,7 @@ static void init_input(struct hda_codec *codec) AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | MIC_EVENT); } + change_cur_input(codec, spec->cur_input, 1); if (spec->mic_detect) cs_automic(codec); } -- cgit v0.10.2 From 40c20fa05a29766565f56ede17d0ffa539e1c9a9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 6 Jul 2009 13:00:57 +0200 Subject: ALSA: hda - Add CS420x-specific coef setup Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 8e33214..2187383 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -58,6 +58,64 @@ struct cs_spec { unsigned int mic_detect:1; }; +/* Vendor-specific processing widget */ +#define CS420X_VENDOR_NID 0x11 +#define CS_DIG_OUT1_PIN_NID 0x10 +#define CS_DIG_OUT2_PIN_NID 0x15 +#define CS_DMIC1_PIN_NID 0x12 +#define CS_DMIC2_PIN_NID 0x0e + +/* coef indices */ +#define IDX_SPDIF_STAT 0x0000 +#define IDX_SPDIF_CTL 0x0001 +#define IDX_ADC_CFG 0x0002 +/* SZC bitmask, 4 modes below: + * 0 = immediate, + * 1 = digital immediate, analog zero-cross + * 2 = digtail & analog soft-ramp + * 3 = digital soft-ramp, analog zero-cross + */ +#define CS_COEF_ADC_SZC_MASK (3 << 0) +#define CS_COEF_ADC_MIC_SZC_MODE (3 << 0) /* SZC setup for mic */ +#define CS_COEF_ADC_LI_SZC_MODE (3 << 0) /* SZC setup for line-in */ +/* PGA mode: 0 = differential, 1 = signle-ended */ +#define CS_COEF_ADC_MIC_PGA_MODE (1 << 5) /* PGA setup for mic */ +#define CS_COEF_ADC_LI_PGA_MODE (1 << 6) /* PGA setup for line-in */ +#define IDX_DAC_CFG 0x0003 +/* SZC bitmask, 4 modes below: + * 0 = Immediate + * 1 = zero-cross + * 2 = soft-ramp + * 3 = soft-ramp on zero-cross + */ +#define CS_COEF_DAC_HP_SZC_MODE (3 << 0) /* nid 0x02 */ +#define CS_COEF_DAC_LO_SZC_MODE (3 << 2) /* nid 0x03 */ +#define CS_COEF_DAC_SPK_SZC_MODE (3 << 4) /* nid 0x04 */ + +#define IDX_BEEP_CFG 0x0004 +/* 0x0008 - test reg key */ +/* 0x0009 - 0x0014 -> 12 test regs */ +/* 0x0015 - visibility reg */ + + +static int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) +{ + snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, + AC_VERB_SET_COEF_INDEX, idx); + return snd_hda_codec_read(codec, CS420X_VENDOR_NID, 0, + AC_VERB_GET_PROC_COEF, 0); +} + +static void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, + unsigned int coef) +{ + snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, + AC_VERB_SET_COEF_INDEX, idx); + snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, + AC_VERB_SET_PROC_COEF, coef); +} + + #define HP_EVENT 1 #define MIC_EVENT 2 @@ -295,6 +353,14 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, return 0; } +static int is_active_pin(struct hda_codec *codec, hda_nid_t nid) +{ + struct cs_spec *spec = codec->spec; + unsigned int val; + val = snd_hda_codec_get_pincfg(codec, nid); + return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); +} + static int parse_output(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; @@ -833,6 +899,7 @@ static void init_input(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int coef; int i; for (i = 0; i < AUTO_PIN_LAST; i++) { @@ -861,14 +928,57 @@ static void init_input(struct hda_codec *codec) change_cur_input(codec, spec->cur_input, 1); if (spec->mic_detect) cs_automic(codec); + + coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ + if (is_active_pin(codec, CS_DMIC2_PIN_NID)) + coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */ + if (is_active_pin(codec, CS_DMIC1_PIN_NID)) + coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0 + * No effect if SPDIF_OUT2 is slected in + * IDX_SPDIF_CTL. + */ + cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); +} + +static struct hda_verb cs_coef_init_verbs[] = { + {0x11, AC_VERB_SET_PROC_STATE, 1}, + {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG}, + {0x11, AC_VERB_SET_PROC_COEF, + (0x002a /* DAC1/2/3 SZCMode Soft Ramp */ + | 0x0040 /* Mute DACs on FIFO error */ + | 0x1000 /* Enable DACs High Pass Filter */ + | 0x0400 /* Disable Coefficient Auto increment */ + )}, + /* Beep */ + {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG}, + {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */ + + {} /* terminator */ +}; + +/* SPDIF setup */ +static void init_digital(struct hda_codec *codec) +{ + unsigned int coef; + + coef = 0x0002; /* SRC_MUTE soft-mute on SPDIF (if no lock) */ + coef |= 0x0008; /* Replace with mute on error */ + if (is_active_pin(codec, CS_DIG_OUT2_PIN_NID)) + coef |= 0x4000; /* RX to TX1 or TX2 Loopthru / SPDIF2 + * SPDIF_OUT2 is shared with GPIO1 and + * DMIC_SDA2. + */ + cs_vendor_coef_set(codec, IDX_SPDIF_CTL, coef); } static int cs_init(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; + snd_hda_sequence_write(codec, cs_coef_init_verbs); init_output(codec); init_input(codec); + init_digital(codec); return 0; } -- cgit v0.10.2 From 9983aa62c321a22774e47cf701b6d8b16d92a822 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 6 Jul 2009 14:31:59 +0200 Subject: ALSA: info - Use krealloc() Use krealloc() to resize the buffer in sound/core/info.c. Signed-off-by: Takashi Iwai diff --git a/sound/core/info.c b/sound/core/info.c index 35df614..3d1f513 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -88,12 +88,10 @@ static int resize_info_buffer(struct snd_info_buffer *buffer, char *nbuf; nsize = PAGE_ALIGN(nsize); - nbuf = kmalloc(nsize, GFP_KERNEL); + nbuf = krealloc(buffer->buffer, nsize, GFP_KERNEL); if (! nbuf) return -ENOMEM; - memcpy(nbuf, buffer->buffer, buffer->len); - kfree(buffer->buffer); buffer->buffer = nbuf; buffer->len = nsize; return 0; -- cgit v0.10.2 From 60e53882ace216cf58fc847a94d839f32b8eb7bf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 6 Jul 2009 15:01:09 +0200 Subject: ALSA: hda - Fix double creation of SPDIF input controls Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 2187383..404c120 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -471,12 +471,9 @@ static int parse_digital_input(struct hda_codec *codec) struct auto_pin_cfg *cfg = &spec->autocfg; int idx; - if (!cfg->dig_in_pin) - return 0; - spec->dig_in = get_adc(codec, cfg->dig_in_pin, &idx); - if (!spec->dig_in) - return 0; - return snd_hda_create_spdif_in_ctls(codec, spec->dig_in); + if (cfg->dig_in_pin) + spec->dig_in = get_adc(codec, cfg->dig_in_pin, &idx); + return 0; } /* -- cgit v0.10.2 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 diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index a1895d7..4d120a6 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 404c120..b1fd183 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 v0.10.2 From eacf69a156dd068b3dfaa0aeb4874cda8633de87 Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:36:30 +0000 Subject: jme: Some minor coding style consistency modifications Making coding style more consistent. Signed-off-by: Guo-Fu Tseng Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 1e3c63d..abf82cd 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -554,7 +554,7 @@ jme_free_tx_resources(struct jme_adapter *jme) { int i; struct jme_ring *txring = &(jme->txring[0]); - struct jme_buffer_info *txbi = txring->bufinf; + struct jme_buffer_info *txbi; if (txring->alloc) { for (i = 0 ; i < jme->tx_ring_size ; ++i) { @@ -653,7 +653,7 @@ jme_disable_tx_engine(struct jme_adapter *jme) static void jme_set_clean_rxdesc(struct jme_adapter *jme, int i) { - struct jme_ring *rxring = jme->rxring; + struct jme_ring *rxring = &(jme->rxring[0]); register struct rxdesc *rxdesc = rxring->desc; struct jme_buffer_info *rxbi = rxring->bufinf; rxdesc += i; @@ -790,9 +790,9 @@ jme_enable_rx_engine(struct jme_adapter *jme) /* * Setup RX DMA Bass Address */ - jwrite32(jme, JME_RXDBA_LO, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL); + jwrite32(jme, JME_RXDBA_LO, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL); jwrite32(jme, JME_RXDBA_HI, (__u64)(jme->rxring[0].dma) >> 32); - jwrite32(jme, JME_RXNDA, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL); + jwrite32(jme, JME_RXNDA, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL); /* * Setup RX Descriptor Count @@ -1296,7 +1296,7 @@ jme_rx_empty_tasklet(unsigned long arg) static void jme_wake_queue_if_stopped(struct jme_adapter *jme) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); smp_wmb(); if (unlikely(netif_queue_stopped(jme->dev) && @@ -1668,7 +1668,7 @@ static int jme_alloc_txdesc(struct jme_adapter *jme, struct sk_buff *skb) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); int idx, nr_alloc, mask = jme->tx_ring_mask; idx = txring->next_to_use; @@ -1722,7 +1722,7 @@ jme_fill_tx_map(struct pci_dev *pdev, static void jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); struct txdesc *txdesc = txring->desc, *ctxdesc; struct jme_buffer_info *txbi = txring->bufinf, *ctxbi; u8 hidma = jme->dev->features & NETIF_F_HIGHDMA; @@ -1835,7 +1835,7 @@ jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags) static int jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); struct txdesc *txdesc; struct jme_buffer_info *txbi; u8 flags; @@ -1883,7 +1883,7 @@ jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) static void jme_stop_queue_if_full(struct jme_adapter *jme) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); struct jme_buffer_info *txbi = txring->bufinf; int idx = atomic_read(&txring->next_to_clean); -- cgit v0.10.2 From 38ed0c2107dea55347504042ed4e1d0cbc3e9100 Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:37:52 +0000 Subject: jme: Fix unmatched tasklet_{enable|disable} pair Fix faulty tasklet function usage. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller diff --git a/drivers/net/jme.c b/drivers/net/jme.c index abf82cd..8de3940 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -1566,6 +1566,7 @@ jme_open(struct net_device *netdev) jme_clear_pm(jme); JME_NAPI_ENABLE(jme); + tasklet_enable(&jme->linkch_task); tasklet_enable(&jme->txclean_task); tasklet_hi_enable(&jme->rxclean_task); tasklet_hi_enable(&jme->rxempty_task); @@ -1647,10 +1648,10 @@ jme_close(struct net_device *netdev) JME_NAPI_DISABLE(jme); - tasklet_kill(&jme->linkch_task); - tasklet_kill(&jme->txclean_task); - tasklet_kill(&jme->rxclean_task); - tasklet_kill(&jme->rxempty_task); + tasklet_disable(&jme->linkch_task); + tasklet_disable(&jme->txclean_task); + tasklet_disable(&jme->rxclean_task); + tasklet_disable(&jme->rxempty_task); jme_reset_ghc_speed(jme); jme_disable_rx_engine(jme); @@ -2768,6 +2769,7 @@ jme_init_one(struct pci_dev *pdev, tasklet_init(&jme->rxempty_task, &jme_rx_empty_tasklet, (unsigned long) jme); + tasklet_disable_nosync(&jme->linkch_task); tasklet_disable_nosync(&jme->txclean_task); tasklet_disable_nosync(&jme->rxclean_task); tasklet_disable_nosync(&jme->rxempty_task); -- cgit v0.10.2 From 44d8d2e9f0dfa52bb1aebdbaa510669bff61c9dc Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:38:35 +0000 Subject: jme: Fix typo Fix enum typo in jme.h Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 0996a06..0025e68 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -247,7 +247,7 @@ enum jme_txdesc_flags_bits { }; #define TXDESC_MSS_SHIFT 2 -enum jme_rxdescwb_flags_bits { +enum jme_txwbdesc_flags_bits { TXWBFLAG_OWN = 0x80, TXWBFLAG_INT = 0x40, TXWBFLAG_TMOUT = 0x20, -- cgit v0.10.2 From 47bd10d14b3341004266395014007c120a359c9d Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:39:46 +0000 Subject: jme: Change bufinf memory location Instead of using a large chunk of memory space preserved for for modules, using kmalloc to obtain the needed memory. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 8de3940..4a55b05 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -522,12 +522,8 @@ jme_setup_tx_resources(struct jme_adapter *jme) &(txring->dmaalloc), GFP_ATOMIC); - if (!txring->alloc) { - txring->desc = NULL; - txring->dmaalloc = 0; - txring->dma = 0; - return -ENOMEM; - } + if (!txring->alloc) + goto err_set_null; /* * 16 Bytes align @@ -539,6 +535,11 @@ jme_setup_tx_resources(struct jme_adapter *jme) atomic_set(&txring->next_to_clean, 0); atomic_set(&txring->nr_free, jme->tx_ring_size); + txring->bufinf = kmalloc(sizeof(struct jme_buffer_info) * + jme->tx_ring_size, GFP_ATOMIC); + if (unlikely(!(txring->bufinf))) + goto err_free_txring; + /* * Initialize Transmit Descriptors */ @@ -547,6 +548,20 @@ jme_setup_tx_resources(struct jme_adapter *jme) sizeof(struct jme_buffer_info) * jme->tx_ring_size); return 0; + +err_free_txring: + dma_free_coherent(&(jme->pdev->dev), + TX_RING_ALLOC_SIZE(jme->tx_ring_size), + txring->alloc, + txring->dmaalloc); + +err_set_null: + txring->desc = NULL; + txring->dmaalloc = 0; + txring->dma = 0; + txring->bufinf = NULL; + + return -ENOMEM; } static void @@ -557,16 +572,19 @@ jme_free_tx_resources(struct jme_adapter *jme) struct jme_buffer_info *txbi; if (txring->alloc) { - for (i = 0 ; i < jme->tx_ring_size ; ++i) { - txbi = txring->bufinf + i; - if (txbi->skb) { - dev_kfree_skb(txbi->skb); - txbi->skb = NULL; + if (txring->bufinf) { + for (i = 0 ; i < jme->tx_ring_size ; ++i) { + txbi = txring->bufinf + i; + if (txbi->skb) { + dev_kfree_skb(txbi->skb); + txbi->skb = NULL; + } + txbi->mapping = 0; + txbi->len = 0; + txbi->nr_desc = 0; + txbi->start_xmit = 0; } - txbi->mapping = 0; - txbi->len = 0; - txbi->nr_desc = 0; - txbi->start_xmit = 0; + kfree(txring->bufinf); } dma_free_coherent(&(jme->pdev->dev), @@ -578,11 +596,11 @@ jme_free_tx_resources(struct jme_adapter *jme) txring->desc = NULL; txring->dmaalloc = 0; txring->dma = 0; + txring->bufinf = NULL; } txring->next_to_use = 0; atomic_set(&txring->next_to_clean, 0); atomic_set(&txring->nr_free, 0); - } static inline void @@ -720,8 +738,11 @@ jme_free_rx_resources(struct jme_adapter *jme) struct jme_ring *rxring = &(jme->rxring[0]); if (rxring->alloc) { - for (i = 0 ; i < jme->rx_ring_size ; ++i) - jme_free_rx_buf(jme, i); + if (rxring->bufinf) { + for (i = 0 ; i < jme->rx_ring_size ; ++i) + jme_free_rx_buf(jme, i); + kfree(rxring->bufinf); + } dma_free_coherent(&(jme->pdev->dev), RX_RING_ALLOC_SIZE(jme->rx_ring_size), @@ -731,6 +752,7 @@ jme_free_rx_resources(struct jme_adapter *jme) rxring->desc = NULL; rxring->dmaalloc = 0; rxring->dma = 0; + rxring->bufinf = NULL; } rxring->next_to_use = 0; atomic_set(&rxring->next_to_clean, 0); @@ -746,12 +768,8 @@ jme_setup_rx_resources(struct jme_adapter *jme) RX_RING_ALLOC_SIZE(jme->rx_ring_size), &(rxring->dmaalloc), GFP_ATOMIC); - if (!rxring->alloc) { - rxring->desc = NULL; - rxring->dmaalloc = 0; - rxring->dma = 0; - return -ENOMEM; - } + if (!rxring->alloc) + goto err_set_null; /* * 16 Bytes align @@ -762,9 +780,16 @@ jme_setup_rx_resources(struct jme_adapter *jme) rxring->next_to_use = 0; atomic_set(&rxring->next_to_clean, 0); + rxring->bufinf = kmalloc(sizeof(struct jme_buffer_info) * + jme->rx_ring_size, GFP_ATOMIC); + if (unlikely(!(rxring->bufinf))) + goto err_free_rxring; + /* * Initiallize Receive Descriptors */ + memset(rxring->bufinf, 0, + sizeof(struct jme_buffer_info) * jme->rx_ring_size); for (i = 0 ; i < jme->rx_ring_size ; ++i) { if (unlikely(jme_make_new_rx_buf(jme, i))) { jme_free_rx_resources(jme); @@ -775,6 +800,19 @@ jme_setup_rx_resources(struct jme_adapter *jme) } return 0; + +err_free_rxring: + dma_free_coherent(&(jme->pdev->dev), + RX_RING_ALLOC_SIZE(jme->rx_ring_size), + rxring->alloc, + rxring->dmaalloc); +err_set_null: + rxring->desc = NULL; + rxring->dmaalloc = 0; + rxring->dma = 0; + rxring->bufinf = NULL; + + return -ENOMEM; } static inline void diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 0025e68..9d3cedd 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -372,7 +372,6 @@ struct jme_buffer_info { /* * The structure holding buffer information and ring descriptors all together. */ -#define MAX_RING_DESC_NR 1024 struct jme_ring { void *alloc; /* pointer to allocated memory */ void *desc; /* pointer to ring memory */ @@ -380,7 +379,7 @@ struct jme_ring { dma_addr_t dma; /* phys address for ring dma */ /* Buffer information corresponding to each descriptor */ - struct jme_buffer_info bufinf[MAX_RING_DESC_NR]; + struct jme_buffer_info *bufinf; int next_to_use; atomic_t next_to_clean; -- cgit v0.10.2 From d1dfa1d1de855e8db58ec4e403af5939d273f8fe Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:40:38 +0000 Subject: jme: Remove shadow register support The hardware failed to update the shadow register in several cases. It's known to be failed at 64bit box with more than 4G RAM. In order to make the device working stable, give up using the shadow register feature. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 4a55b05..29cd5f4 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -322,20 +322,6 @@ jme_stop_irq(struct jme_adapter *jme) jwrite32f(jme, JME_IENC, INTR_ENABLE); } -static inline void -jme_enable_shadow(struct jme_adapter *jme) -{ - jwrite32(jme, - JME_SHBA_LO, - ((u32)jme->shadow_dma & ~((u32)0x1F)) | SHBA_POSTEN); -} - -static inline void -jme_disable_shadow(struct jme_adapter *jme) -{ - jwrite32(jme, JME_SHBA_LO, 0x0); -} - static u32 jme_linkstat_from_phy(struct jme_adapter *jme) { @@ -1521,12 +1507,7 @@ jme_msi(int irq, void *dev_id) struct jme_adapter *jme = netdev_priv(netdev); u32 intrstat; - pci_dma_sync_single_for_cpu(jme->pdev, - jme->shadow_dma, - sizeof(u32) * SHADOW_REG_NR, - PCI_DMA_FROMDEVICE); - intrstat = jme->shadow_regs[SHADOW_IEVE]; - jme->shadow_regs[SHADOW_IEVE] = 0; + intrstat = jread32(jme, JME_IEVE); jme_intr_msi(jme, intrstat); @@ -1613,7 +1594,6 @@ jme_open(struct net_device *netdev) if (rc) goto err_out; - jme_enable_shadow(jme); jme_start_irq(jme); if (test_bit(JME_FLAG_SSET, &jme->flags)) @@ -1681,7 +1661,6 @@ jme_close(struct net_device *netdev) netif_carrier_off(netdev); jme_stop_irq(jme); - jme_disable_shadow(jme); jme_free_irq(jme); JME_NAPI_DISABLE(jme); @@ -2764,14 +2743,6 @@ jme_init_one(struct pci_dev *pdev, rc = -ENOMEM; goto err_out_free_netdev; } - jme->shadow_regs = pci_alloc_consistent(pdev, - sizeof(u32) * SHADOW_REG_NR, - &(jme->shadow_dma)); - if (!(jme->shadow_regs)) { - jeprintk(pdev, "Allocating shadow register mapping error.\n"); - rc = -ENOMEM; - goto err_out_unmap; - } if (no_pseudohp) { apmc = jread32(jme, JME_APMC) & ~JME_APMC_PSEUDO_HP_EN; @@ -2857,7 +2828,7 @@ jme_init_one(struct pci_dev *pdev, if (!jme->mii_if.phy_id) { rc = -EIO; jeprintk(pdev, "Can not find phy_id.\n"); - goto err_out_free_shadow; + goto err_out_unmap; } jme->reg_ghc |= GHC_LINK_POLL; @@ -2886,7 +2857,7 @@ jme_init_one(struct pci_dev *pdev, if (rc) { jeprintk(pdev, "Reload eeprom for reading MAC Address error.\n"); - goto err_out_free_shadow; + goto err_out_unmap; } jme_load_macaddr(netdev); @@ -2902,7 +2873,7 @@ jme_init_one(struct pci_dev *pdev, rc = register_netdev(netdev); if (rc) { jeprintk(pdev, "Cannot register net device.\n"); - goto err_out_free_shadow; + goto err_out_unmap; } msg_probe(jme, "%s%s ver:%x rev:%x macaddr:%pM\n", @@ -2916,11 +2887,6 @@ jme_init_one(struct pci_dev *pdev, return 0; -err_out_free_shadow: - pci_free_consistent(pdev, - sizeof(u32) * SHADOW_REG_NR, - jme->shadow_regs, - jme->shadow_dma); err_out_unmap: iounmap(jme->regs); err_out_free_netdev: @@ -2941,10 +2907,6 @@ jme_remove_one(struct pci_dev *pdev) struct jme_adapter *jme = netdev_priv(netdev); unregister_netdev(netdev); - pci_free_consistent(pdev, - sizeof(u32) * SHADOW_REG_NR, - jme->shadow_regs, - jme->shadow_dma); iounmap(jme->regs); pci_set_drvdata(pdev, NULL); free_netdev(netdev); @@ -2970,8 +2932,6 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state) tasklet_disable(&jme->rxclean_task); tasklet_disable(&jme->rxempty_task); - jme_disable_shadow(jme); - if (netif_carrier_ok(netdev)) { if (test_bit(JME_FLAG_POLL, &jme->flags)) jme_polling_mode(jme); @@ -3023,7 +2983,6 @@ jme_resume(struct pci_dev *pdev) else jme_reset_phy_processor(jme); - jme_enable_shadow(jme); jme_start_irq(jme); netif_device_attach(netdev); diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 9d3cedd..db912f6 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -410,13 +410,10 @@ struct jme_ring { /* * Jmac Adapter Private data */ -#define SHADOW_REG_NR 8 struct jme_adapter { struct pci_dev *pdev; struct net_device *dev; void __iomem *regs; - dma_addr_t shadow_dma; - u32 *shadow_regs; struct mii_if_info mii_if; struct jme_ring rxring[RX_RING_NR]; struct jme_ring txring[TX_RING_NR]; @@ -463,10 +460,6 @@ struct jme_adapter { DECLARE_NET_DEVICE_STATS }; -enum shadow_reg_val { - SHADOW_IEVE = 0, -}; - enum jme_flags_bits { JME_FLAG_MSI = 1, JME_FLAG_SSET = 2, @@ -1103,13 +1096,6 @@ enum jme_chipmode_shifts { }; /* - * Shadow base address register bits - */ -enum jme_shadow_base_address_bits { - SHBA_POSTEN = 0x1, -}; - -/* * Aggressive Power Mode Control */ enum jme_apmc_bits { -- cgit v0.10.2 From ce7d70af2c8b9c74e8afb2c0d69e304d141ce4aa Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:41:22 +0000 Subject: jme: Tuning rxsum function 1. Use more efficient way to determine flag status. 2. Hardware dose not mark fragment bit against IPv6 packets, print TCP/UDP checksum warning message for IPv4 packets only. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 29cd5f4..e7068c7 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -880,27 +880,27 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags) if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4))) return false; - if (unlikely(!(flags & RXWBFLAG_MF) && - (flags & RXWBFLAG_TCPON) && !(flags & RXWBFLAG_TCPCS))) { - msg_rx_err(jme, "TCP Checksum error.\n"); - goto out_sumerr; + if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_TCPON | RXWBFLAG_TCPCS)) + == RXWBFLAG_TCPON)) { + if (flags & RXWBFLAG_IPV4) + msg_rx_err(jme, "TCP Checksum error\n"); + return false; } - if (unlikely(!(flags & RXWBFLAG_MF) && - (flags & RXWBFLAG_UDPON) && !(flags & RXWBFLAG_UDPCS))) { - msg_rx_err(jme, "UDP Checksum error.\n"); - goto out_sumerr; + if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS)) + == RXWBFLAG_UDPON)) { + if (flags & RXWBFLAG_IPV4) + msg_rx_err(jme, "UDP Checksum error.\n"); + return false; } - if (unlikely((flags & RXWBFLAG_IPV4) && !(flags & RXWBFLAG_IPCS))) { + if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS)) + == RXWBFLAG_IPV4)) { msg_rx_err(jme, "IPv4 Checksum error.\n"); - goto out_sumerr; + return false; } return true; - -out_sumerr: - return false; } static void -- cgit v0.10.2 From f77139c07a0e1dd164e039320ada50111f899223 Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:45:58 +0000 Subject: jme: Advance driver version number Advance driver version number after modifications. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller diff --git a/drivers/net/jme.h b/drivers/net/jme.h index db912f6..251abed 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -25,7 +25,7 @@ #define __JME_H_INCLUDED__ #define DRV_NAME "jme" -#define DRV_VERSION "1.0.4" +#define DRV_VERSION "1.0.5" #define PFX DRV_NAME ": " #define PCI_DEVICE_ID_JMICRON_JMC250 0x0250 -- cgit v0.10.2 From 94c9e5a89349a1f1ebabe0876c059dc387b8b2a0 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 6 Jul 2009 10:44:20 +0000 Subject: e1000: allow ethtool coalesece to adjust interrupts per second This patch allows on-the-fly adjustment of the interrupts per second generated by e1000 devices 82545/82546 (hardware support of ITR register is a requirement) adjust using this command: ethtool -C eth0 rx-usecs 10 where 10 is 10 microseconds per interrupt interval, so 10 = 100,000 interrupts per second, and 125 = 8000 interrupts per second. changes should be immediate. 1,3 are special values and indicate the automatic tuning mode to the driver, where 1 is 4000-90000 interrupts per second and 3 is 4000-20000 interrupts per second and is the driver default. Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index e9a416f..c87f2cb 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -111,6 +111,9 @@ do { \ #define E1000_MIN_RXD 80 #define E1000_MAX_82544_RXD 4096 +#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */ +#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */ + /* this is the size past which hardware will drop packets when setting LPE=0 */ #define MAXIMUM_ETHERNET_VLAN_SIZE 1522 diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index c854c96..27f996a 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1904,6 +1904,53 @@ static int e1000_phys_id(struct net_device *netdev, u32 data) return 0; } +static int e1000_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (adapter->hw.mac_type < e1000_82545) + return -EOPNOTSUPP; + + if (adapter->itr_setting <= 3) + ec->rx_coalesce_usecs = adapter->itr_setting; + else + ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting; + + return 0; +} + +static int e1000_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (hw->mac_type < e1000_82545) + return -EOPNOTSUPP; + + if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) || + ((ec->rx_coalesce_usecs > 3) && + (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) || + (ec->rx_coalesce_usecs == 2)) + return -EINVAL; + + if (ec->rx_coalesce_usecs <= 3) { + adapter->itr = 20000; + adapter->itr_setting = ec->rx_coalesce_usecs; + } else { + adapter->itr = (1000000 / ec->rx_coalesce_usecs); + adapter->itr_setting = adapter->itr & ~3; + } + + if (adapter->itr_setting != 0) + ew32(ITR, 1000000000 / (adapter->itr * 256)); + else + ew32(ITR, 0); + + return 0; +} + static int e1000_nway_reset(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); @@ -1978,7 +2025,9 @@ static const struct ethtool_ops e1000_ethtool_ops = { .get_strings = e1000_get_strings, .phys_id = e1000_phys_id, .get_ethtool_stats = e1000_get_ethtool_stats, - .get_sset_count = e1000_get_sset_count, + .get_sset_count = e1000_get_sset_count, + .get_coalesce = e1000_get_coalesce, + .set_coalesce = e1000_set_coalesce, }; void e1000_set_ethtool_ops(struct net_device *netdev) -- cgit v0.10.2 From edbbb3ca107715067b27a71e6ea7f58750912aa2 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 6 Jul 2009 10:44:39 +0000 Subject: e1000: implement jumbo receive with partial descriptors This is code extremely similar to what is committed in e1000e already. e1000 will no longer request 32kB slab buffers to support jumbo frames on PCI/PCI-X adapters. This will significantly reduce the likelyhood of order:3 allocation failures. This new code adds support for using pages as receive buffers, and the driver will chain multiple pages together to build a jumbo frame for OS consumption. The hardware takes a power of two buffer size and will dump as much data as it can receive into 1 or more buffers. The benefits of applying this are 1) stop akpm's dissing :-) of this lame e1000 behavior [1] 2) more efficient memory allocation (half) when using jumbo frames, which will also allow for much better socket utilization with jumbos since the socket is charged for the full allocation of each receive buffer, regardless of how much is used. 3) this was a feature request by a customer 4) copybreak for small packets < 256 bytes still applies [1] http://lkml.org/lkml/2008/7/10/68 http://article.gmane.org/gmane.linux.network/130986 Signed-off-by: Jesse Brandeburg CC: Andrew Morton Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index c87f2cb..1a4f89c 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -140,7 +140,7 @@ do { \ #define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */ #define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */ -#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ +#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */ /* How many Tx Descriptors do we need to call netif_wake_queue ? */ #define E1000_TX_QUEUE_WAKE 16 @@ -164,6 +164,7 @@ do { \ struct e1000_buffer { struct sk_buff *skb; dma_addr_t dma; + struct page *page; unsigned long time_stamp; u16 length; u16 next_to_watch; @@ -205,6 +206,7 @@ struct e1000_rx_ring { unsigned int next_to_clean; /* array of buffer information structs */ struct e1000_buffer *buffer_info; + struct sk_buff *rx_skb_top; /* cpu for rx queue */ int cpu; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 5b8cbdb..f2db9e2 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -137,9 +137,15 @@ static int e1000_clean(struct napi_struct *napi, int budget); static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); +static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do); static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring, + struct e1000_rx_ring *rx_ring, int cleaned_count); +static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int cleaned_count); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); @@ -761,10 +767,7 @@ void e1000_reset(struct e1000_adapter *adapter) hw->fc_high_water = fc_high_water_mark; hw->fc_low_water = fc_high_water_mark - 8; - if (hw->mac_type == e1000_80003es2lan) - hw->fc_pause_time = 0xFFFF; - else - hw->fc_pause_time = E1000_FC_PAUSE_TIME; + hw->fc_pause_time = E1000_FC_PAUSE_TIME; hw->fc_send_xon = 1; hw->fc = hw->original_fc; @@ -1862,6 +1865,7 @@ setup_rx_desc_die: rxdr->next_to_clean = 0; rxdr->next_to_use = 0; + rxdr->rx_skb_top = NULL; return 0; } @@ -1968,10 +1972,17 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 rdlen, rctl, rxcsum, ctrl_ext; - rdlen = adapter->rx_ring[0].count * - sizeof(struct e1000_rx_desc); - adapter->clean_rx = e1000_clean_rx_irq; - adapter->alloc_rx_buf = e1000_alloc_rx_buffers; + if (adapter->netdev->mtu > ETH_DATA_LEN) { + rdlen = adapter->rx_ring[0].count * + sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_jumbo_rx_irq; + adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers; + } else { + rdlen = adapter->rx_ring[0].count * + sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_rx_irq; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers; + } /* disable receives while setting up the descriptors */ rctl = er32(RCTL); @@ -2185,26 +2196,39 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter, /* Free all the Rx ring sk_buffs */ for (i = 0; i < rx_ring->count; i++) { buffer_info = &rx_ring->buffer_info[i]; - if (buffer_info->dma) { - pci_unmap_single(pdev, - buffer_info->dma, - buffer_info->length, - PCI_DMA_FROMDEVICE); + if (buffer_info->dma && + adapter->clean_rx == e1000_clean_rx_irq) { + pci_unmap_single(pdev, buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); + } else if (buffer_info->dma && + adapter->clean_rx == e1000_clean_jumbo_rx_irq) { + pci_unmap_page(pdev, buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); } buffer_info->dma = 0; - + if (buffer_info->page) { + put_page(buffer_info->page); + buffer_info->page = NULL; + } if (buffer_info->skb) { dev_kfree_skb(buffer_info->skb); buffer_info->skb = NULL; } } + /* there also may be some cached data from a chained receive */ + if (rx_ring->rx_skb_top) { + dev_kfree_skb(rx_ring->rx_skb_top); + rx_ring->rx_skb_top = NULL; + } + size = sizeof(struct e1000_buffer) * rx_ring->count; memset(rx_ring->buffer_info, 0, size); /* Zero out the descriptor ring */ - memset(rx_ring->desc, 0, rx_ring->size); rx_ring->next_to_clean = 0; @@ -3489,8 +3513,10 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN * means we reserve 2 more, this pushes us to allocate from the next - * larger slab size - * i.e. RXBUFFER_2048 --> size-4096 slab */ + * larger slab size. + * i.e. RXBUFFER_2048 --> size-4096 slab + * however with the new *_jumbo_rx* routines, jumbo receives will use + * fragmented skbs */ if (max_frame <= E1000_RXBUFFER_256) adapter->rx_buffer_len = E1000_RXBUFFER_256; @@ -3500,12 +3526,12 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) adapter->rx_buffer_len = E1000_RXBUFFER_1024; else if (max_frame <= E1000_RXBUFFER_2048) adapter->rx_buffer_len = E1000_RXBUFFER_2048; - else if (max_frame <= E1000_RXBUFFER_4096) - adapter->rx_buffer_len = E1000_RXBUFFER_4096; - else if (max_frame <= E1000_RXBUFFER_8192) - adapter->rx_buffer_len = E1000_RXBUFFER_8192; - else if (max_frame <= E1000_RXBUFFER_16384) + else +#if (PAGE_SIZE >= E1000_RXBUFFER_16384) adapter->rx_buffer_len = E1000_RXBUFFER_16384; +#elif (PAGE_SIZE >= E1000_RXBUFFER_4096) + adapter->rx_buffer_len = PAGE_SIZE; +#endif /* adjust allocation if LPE protects us, and we aren't using SBP */ if (!hw->tbi_compatibility_on && @@ -3987,9 +4013,227 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, } /** + * e1000_consume_page - helper function + **/ +static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb, + u16 length) +{ + bi->page = NULL; + skb->len += length; + skb->data_len += length; + skb->truesize += length; +} + +/** + * e1000_receive_skb - helper function to handle rx indications + * @adapter: board private structure + * @status: descriptor status field as written by hardware + * @vlan: descriptor vlan field as written by hardware (no le/be conversion) + * @skb: pointer to sk_buff to be indicated to stack + */ +static void e1000_receive_skb(struct e1000_adapter *adapter, u8 status, + __le16 vlan, struct sk_buff *skb) +{ + if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) { + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, + le16_to_cpu(vlan) & + E1000_RXD_SPC_VLAN_MASK); + } else { + netif_receive_skb(skb); + } +} + +/** + * e1000_clean_jumbo_rx_irq - Send received data up the network stack; legacy + * @adapter: board private structure + * @rx_ring: ring to clean + * @work_done: amount of napi work completed this call + * @work_to_do: max amount of work allowed for this call to do + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + */ +static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc, *next_rxd; + struct e1000_buffer *buffer_info, *next_buffer; + unsigned long irq_flags; + u32 length; + unsigned int i; + int cleaned_count = 0; + bool cleaned = false; + unsigned int total_rx_bytes=0, total_rx_packets=0; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC(*rx_ring, i); + buffer_info = &rx_ring->buffer_info[i]; + + while (rx_desc->status & E1000_RXD_STAT_DD) { + struct sk_buff *skb; + u8 status; + + if (*work_done >= work_to_do) + break; + (*work_done)++; + + status = rx_desc->status; + skb = buffer_info->skb; + buffer_info->skb = NULL; + + if (++i == rx_ring->count) i = 0; + next_rxd = E1000_RX_DESC(*rx_ring, i); + prefetch(next_rxd); + + next_buffer = &rx_ring->buffer_info[i]; + + cleaned = true; + cleaned_count++; + pci_unmap_page(pdev, buffer_info->dma, buffer_info->length, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + length = le16_to_cpu(rx_desc->length); + + /* errors is only valid for DD + EOP descriptors */ + if (unlikely((status & E1000_RXD_STAT_EOP) && + (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) { + u8 last_byte = *(skb->data + length - 1); + if (TBI_ACCEPT(hw, status, rx_desc->errors, length, + last_byte)) { + spin_lock_irqsave(&adapter->stats_lock, + irq_flags); + e1000_tbi_adjust_stats(hw, &adapter->stats, + length, skb->data); + spin_unlock_irqrestore(&adapter->stats_lock, + irq_flags); + length--; + } else { + /* recycle both page and skb */ + buffer_info->skb = skb; + /* an error means any chain goes out the window + * too */ + if (rx_ring->rx_skb_top) + dev_kfree_skb(rx_ring->rx_skb_top); + rx_ring->rx_skb_top = NULL; + goto next_desc; + } + } + +#define rxtop rx_ring->rx_skb_top + if (!(status & E1000_RXD_STAT_EOP)) { + /* this descriptor is only the beginning (or middle) */ + if (!rxtop) { + /* this is the beginning of a chain */ + rxtop = skb; + skb_fill_page_desc(rxtop, 0, buffer_info->page, + 0, length); + } else { + /* this is the middle of a chain */ + skb_fill_page_desc(rxtop, + skb_shinfo(rxtop)->nr_frags, + buffer_info->page, 0, length); + /* re-use the skb, only consumed the page */ + buffer_info->skb = skb; + } + e1000_consume_page(buffer_info, rxtop, length); + goto next_desc; + } else { + if (rxtop) { + /* end of the chain */ + skb_fill_page_desc(rxtop, + skb_shinfo(rxtop)->nr_frags, + buffer_info->page, 0, length); + /* re-use the current skb, we only consumed the + * page */ + buffer_info->skb = skb; + skb = rxtop; + rxtop = NULL; + e1000_consume_page(buffer_info, skb, length); + } else { + /* no chain, got EOP, this buf is the packet + * copybreak to save the put_page/alloc_page */ + if (length <= copybreak && + skb_tailroom(skb) >= length) { + u8 *vaddr; + vaddr = kmap_atomic(buffer_info->page, + KM_SKB_DATA_SOFTIRQ); + memcpy(skb_tail_pointer(skb), vaddr, length); + kunmap_atomic(vaddr, + KM_SKB_DATA_SOFTIRQ); + /* re-use the page, so don't erase + * buffer_info->page */ + skb_put(skb, length); + } else { + skb_fill_page_desc(skb, 0, + buffer_info->page, 0, + length); + e1000_consume_page(buffer_info, skb, + length); + } + } + } + + /* Receive Checksum Offload XXX recompute due to CRC strip? */ + e1000_rx_checksum(adapter, + (u32)(status) | + ((u32)(rx_desc->errors) << 24), + le16_to_cpu(rx_desc->csum), skb); + + pskb_trim(skb, skb->len - 4); + + /* probably a little skewed due to removing CRC */ + total_rx_bytes += skb->len; + total_rx_packets++; + + /* eth type trans needs skb->data to point to something */ + if (!pskb_may_pull(skb, ETH_HLEN)) { + DPRINTK(DRV, ERR, "pskb_may_pull failed.\n"); + dev_kfree_skb(skb); + goto next_desc; + } + + skb->protocol = eth_type_trans(skb, netdev); + + e1000_receive_skb(adapter, status, rx_desc->special, skb); + +next_desc: + rx_desc->status = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) { + adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + buffer_info = next_buffer; + } + rx_ring->next_to_clean = i; + + cleaned_count = E1000_DESC_UNUSED(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + adapter->net_stats.rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; + return cleaned; +} + +/** * e1000_clean_rx_irq - Send received data up the network stack; legacy * @adapter: board private structure - **/ + * @rx_ring: ring to clean + * @work_done: amount of napi work completed this call + * @work_to_do: max amount of work allowed for this call to do + */ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do) @@ -4001,7 +4245,6 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info, *next_buffer; unsigned long flags; u32 length; - u8 last_byte; unsigned int i; int cleaned_count = 0; bool cleaned = false; @@ -4033,9 +4276,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, cleaned = true; cleaned_count++; - pci_unmap_single(pdev, - buffer_info->dma, - buffer_info->length, + pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE); buffer_info->dma = 0; @@ -4052,7 +4293,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, } if (unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { - last_byte = *(skb->data + length - 1); + u8 last_byte = *(skb->data + length - 1); if (TBI_ACCEPT(hw, status, rx_desc->errors, length, last_byte)) { spin_lock_irqsave(&adapter->stats_lock, flags); @@ -4107,13 +4348,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, skb->protocol = eth_type_trans(skb, netdev); - if (unlikely(adapter->vlgrp && - (status & E1000_RXD_STAT_VP))) { - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special)); - } else { - netif_receive_skb(skb); - } + e1000_receive_skb(adapter, status, rx_desc->special, skb); next_desc: rx_desc->status = 0; @@ -4142,6 +4377,114 @@ next_desc: } /** + * e1000_alloc_jumbo_rx_buffers - Replace used jumbo receive buffers + * @adapter: address of board private structure + * @rx_ring: pointer to receive ring structure + * @cleaned_count: number of buffers to allocate this pass + **/ + +static void +e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + struct e1000_buffer *buffer_info; + struct sk_buff *skb; + unsigned int i; + unsigned int bufsz = 256 - + 16 /*for skb_reserve */ - + NET_IP_ALIGN; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + + while (cleaned_count--) { + skb = buffer_info->skb; + if (skb) { + skb_trim(skb, 0); + goto check_page; + } + + skb = netdev_alloc_skb(netdev, bufsz); + if (unlikely(!skb)) { + /* Better luck next round */ + adapter->alloc_rx_buff_failed++; + break; + } + + /* Fix for errata 23, can't cross 64kB boundary */ + if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) { + struct sk_buff *oldskb = skb; + DPRINTK(PROBE, ERR, "skb align check failed: %u bytes " + "at %p\n", bufsz, skb->data); + /* Try again, without freeing the previous */ + skb = netdev_alloc_skb(netdev, bufsz); + /* Failed allocation, critical failure */ + if (!skb) { + dev_kfree_skb(oldskb); + adapter->alloc_rx_buff_failed++; + break; + } + + if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) { + /* give up */ + dev_kfree_skb(skb); + dev_kfree_skb(oldskb); + break; /* while (cleaned_count--) */ + } + + /* Use new allocation */ + dev_kfree_skb(oldskb); + } + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + buffer_info->skb = skb; + buffer_info->length = adapter->rx_buffer_len; +check_page: + /* allocate a new page if necessary */ + if (!buffer_info->page) { + buffer_info->page = alloc_page(GFP_ATOMIC); + if (unlikely(!buffer_info->page)) { + adapter->alloc_rx_buff_failed++; + break; + } + } + + if (!buffer_info->dma) + buffer_info->dma = pci_map_page(pdev, + buffer_info->page, 0, + buffer_info->length, + PCI_DMA_FROMDEVICE); + + rx_desc = E1000_RX_DESC(*rx_ring, i); + rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + + if (unlikely(++i == rx_ring->count)) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + + if (likely(rx_ring->next_to_use != i)) { + rx_ring->next_to_use = i; + if (unlikely(i-- == 0)) + i = (rx_ring->count - 1); + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + writel(i, adapter->hw.hw_addr + rx_ring->rdt); + } +} + +/** * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended * @adapter: address of board private structure **/ @@ -4186,6 +4529,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, /* Failed allocation, critical failure */ if (!skb) { dev_kfree_skb(oldskb); + adapter->alloc_rx_buff_failed++; break; } @@ -4193,6 +4537,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, /* give up */ dev_kfree_skb(skb); dev_kfree_skb(oldskb); + adapter->alloc_rx_buff_failed++; break; /* while !buffer_info->skb */ } @@ -4210,9 +4555,14 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, map_skb: buffer_info->dma = pci_map_single(pdev, skb->data, - adapter->rx_buffer_len, + buffer_info->length, PCI_DMA_FROMDEVICE); + /* + * XXX if it was allocated cleanly it will never map to a + * boundary crossing + */ + /* Fix for errata 23, can't cross 64kB boundary */ if (!e1000_check_64k_bound(adapter, (void *)(unsigned long)buffer_info->dma, @@ -4229,6 +4579,7 @@ map_skb: PCI_DMA_FROMDEVICE); buffer_info->dma = 0; + adapter->alloc_rx_buff_failed++; break; /* while !buffer_info->skb */ } rx_desc = E1000_RX_DESC(*rx_ring, i); -- cgit v0.10.2 From b7cb8c2c8275ab081b97610b13a83c80904571a6 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 6 Jul 2009 10:45:01 +0000 Subject: e1000: fix flow control thresholds when testing the jumbo frames with pages patch, the stats would show rx_missed errors (dropped packets) even when connected to a link partner with flow control enabled. this indicates that for this MTU (9000) the flow control thresholds are not adjusting correctly. In fact, before this change, the FCRTH (xoff threshold) is 36864 when the fifo size is only 40000, with 9000 byte MTU. fix it so that we at least have room for one frame after we send the xoff. Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index e1a3fc1..1e5ae11 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -1955,7 +1955,7 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw) s32 ret_val; u16 i; u16 phy_data; - u16 reg_data; + u16 reg_data = 0; DEBUGFUNC("e1000_setup_copper_link"); diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 99fce2c..a8866bd 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -523,11 +523,8 @@ s32 e1000_check_phy_reset_block(struct e1000_hw *hw); /* The sizes (in bytes) of a ethernet packet */ #define ENET_HEADER_SIZE 14 -#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */ #define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */ #define ETHERNET_FCS_SIZE 4 -#define MAXIMUM_ETHERNET_PACKET_SIZE \ - (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE) #define MINIMUM_ETHERNET_PACKET_SIZE \ (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE) #define CRC_LENGTH ETHERNET_FCS_SIZE diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index f2db9e2..d7df00c 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -641,8 +641,8 @@ void e1000_reset(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; u32 pba = 0, tx_space, min_tx_space, min_rx_space; - u16 fc_high_water_mark = E1000_FC_HIGH_DIFF; bool legacy_pba_adjust = false; + u16 hwm; /* Repartition Pba for greater than 9k mtu * To take effect CTRL.RST is required. @@ -686,7 +686,7 @@ void e1000_reset(struct e1000_adapter *adapter) } if (legacy_pba_adjust) { - if (adapter->netdev->mtu > E1000_RXBUFFER_8192) + if (hw->max_frame_size > E1000_RXBUFFER_8192) pba -= 8; /* allocate more FIFO for Tx */ if (hw->mac_type == e1000_82547) { @@ -696,14 +696,14 @@ void e1000_reset(struct e1000_adapter *adapter) (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT; atomic_set(&adapter->tx_fifo_stall, 0); } - } else if (hw->max_frame_size > MAXIMUM_ETHERNET_FRAME_SIZE) { + } else if (hw->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) { /* adjust PBA for jumbo frames */ ew32(PBA, pba); /* To maintain wire speed transmits, the Tx FIFO should be - * large enough to accomodate two full transmit packets, + * large enough to accommodate two full transmit packets, * rounded up to the next 1KB and expressed in KB. Likewise, - * the Rx FIFO should be large enough to accomodate at least + * the Rx FIFO should be large enough to accommodate at least * one full receive packet and is similarly rounded up and * expressed in KB. */ pba = er32(PBA); @@ -711,13 +711,17 @@ void e1000_reset(struct e1000_adapter *adapter) tx_space = pba >> 16; /* lower 16 bits has Rx packet buffer allocation size in KB */ pba &= 0xffff; - /* don't include ethernet FCS because hardware appends/strips */ - min_rx_space = adapter->netdev->mtu + ENET_HEADER_SIZE + - VLAN_TAG_SIZE; - min_tx_space = min_rx_space; - min_tx_space *= 2; + /* + * the tx fifo also stores 16 bytes of information about the tx + * but don't include ethernet FCS because hardware appends it + */ + min_tx_space = (hw->max_frame_size + + sizeof(struct e1000_tx_desc) - + ETH_FCS_LEN) * 2; min_tx_space = ALIGN(min_tx_space, 1024); min_tx_space >>= 10; + /* software strips receive CRC, so leave room for it */ + min_rx_space = hw->max_frame_size; min_rx_space = ALIGN(min_rx_space, 1024); min_rx_space >>= 10; @@ -754,19 +758,21 @@ void e1000_reset(struct e1000_adapter *adapter) ew32(PBA, pba); - /* flow control settings */ - /* Set the FC high water mark to 90% of the FIFO size. - * Required to clear last 3 LSB */ - fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8; - /* We can't use 90% on small FIFOs because the remainder - * would be less than 1 full frame. In this case, we size - * it to allow at least a full frame above the high water - * mark. */ - if (pba < E1000_PBA_16K) - fc_high_water_mark = (pba * 1024) - 1600; - - hw->fc_high_water = fc_high_water_mark; - hw->fc_low_water = fc_high_water_mark - 8; + /* + * flow control settings: + * The high water mark must be low enough to fit one full frame + * (or the size used for early receive) above it in the Rx FIFO. + * Set it to the lower of: + * - 90% of the Rx FIFO size, and + * - the full Rx FIFO size minus the early receive size (for parts + * with ERT support assuming ERT set to E1000_ERT_2048), or + * - the full Rx FIFO size minus one full frame + */ + hwm = min(((pba << 10) * 9 / 10), + ((pba << 10) - hw->max_frame_size)); + + hw->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */ + hw->fc_low_water = hw->fc_high_water - 8; hw->fc_pause_time = E1000_FC_PAUSE_TIME; hw->fc_send_xon = 1; hw->fc = hw->original_fc; @@ -3474,7 +3480,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) switch (hw->mac_type) { case e1000_undefined ... e1000_82542_rev2_1: case e1000_ich8lan: - if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { + if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) { DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n"); return -EINVAL; } @@ -3487,7 +3493,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) &eeprom_data); if ((hw->device_id != E1000_DEV_ID_82573L) || (eeprom_data & EEPROM_WORD1A_ASPM_MASK)) { - if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { + if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) { DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n"); return -EINVAL; @@ -3535,7 +3541,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) /* adjust allocation if LPE protects us, and we aren't using SBP */ if (!hw->tbi_compatibility_on && - ((max_frame == MAXIMUM_ETHERNET_FRAME_SIZE) || + ((max_frame == (ETH_FRAME_LEN + ETH_FCS_LEN)) || (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE))) adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; -- cgit v0.10.2 From 5c91face51d29f553a444d16db4ac2c6162a3cd0 Mon Sep 17 00:00:00 2001 From: Mark Smith Date: Mon, 6 Jul 2009 11:26:24 +0000 Subject: ipv6: correct return on ipv6_rcv() packet drop The routine ipv6_rcv() uses magic number 0 for a return when it drops a packet. This corresponds to NET_RX_SUCCESS, which is obviously incorrect. Correct this by using NET_RX_DROP instead. ps. It isn't exactly clear who the IPv6 maintainers are, apologies if I've missed any. Signed-off-by: Mark Smith Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 6d6a427..2d9cbaa 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -63,7 +63,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt if (skb->pkt_type == PACKET_OTHERHOST) { kfree_skb(skb); - return 0; + return NET_RX_DROP; } rcu_read_lock(); @@ -133,7 +133,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt if (ipv6_parse_hopopts(skb) < 0) { IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS); rcu_read_unlock(); - return 0; + return NET_RX_DROP; } } @@ -149,7 +149,7 @@ err: drop: rcu_read_unlock(); kfree_skb(skb); - return 0; + return NET_RX_DROP; } /* -- cgit v0.10.2 From 482d804cb4b520b6e3134c959c968712ebcdea02 Mon Sep 17 00:00:00 2001 From: Mark Smith Date: Mon, 6 Jul 2009 11:05:58 +0000 Subject: econet: use NET_RX_SUCCESS instead of magic number 0 for econet_rcv successful return Signed-off-by: Mark Smith Signed-off-by: David S. Miller diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 2e1f836..e114da7 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -1072,7 +1072,7 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet skb->protocol = htons(ETH_P_IP); skb_pull(skb, sizeof(struct ec_framehdr)); netif_rx(skb); - return 0; + return NET_RX_SUCCESS; } sk = ec_listening_socket(hdr->port, hdr->src_stn, hdr->src_net); @@ -1083,7 +1083,7 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet hdr->port)) goto drop; - return 0; + return NET_RX_SUCCESS; drop: kfree_skb(skb); -- cgit v0.10.2 From 5dcc60b71886795965fd5029b5d9a9ba7b5a2c17 Mon Sep 17 00:00:00 2001 From: Yeasah Pell Date: Mon, 6 Jul 2009 18:12:33 -0700 Subject: dm9000: add checksum offload support Add checksum offload support for DM9000A and DM9000B chips. v2 changes: added a local copy of ip_summed to save IO cycles in dm9000_send_packet v3 changes: trans_start updating is removed. Signed-off-by: Yeasah Pell Signed-off-by: Mike Rapoport Signed-off-by: David S. Miller diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index ffd9edc..8603806 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -92,6 +92,7 @@ typedef struct board_info { u16 tx_pkt_cnt; u16 queue_pkt_len; u16 queue_start_addr; + u16 queue_ip_summed; u16 dbug_cnt; u8 io_mode; /* 0:word, 2:byte */ u8 phy_addr; @@ -124,6 +125,10 @@ typedef struct board_info { struct mii_if_info mii; u32 msg_enable; + + int rx_csum; + int can_csum; + int ip_summed; } board_info_t; /* debug code */ @@ -460,6 +465,40 @@ static int dm9000_nway_reset(struct net_device *dev) return mii_nway_restart(&dm->mii); } +static uint32_t dm9000_get_rx_csum(struct net_device *dev) +{ + board_info_t *dm = to_dm9000_board(dev); + return dm->rx_csum; +} + +static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) +{ + board_info_t *dm = to_dm9000_board(dev); + unsigned long flags; + + if (dm->can_csum) { + dm->rx_csum = data; + + spin_lock_irqsave(&dm->lock, flags); + iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); + spin_unlock_irqrestore(&dm->lock, flags); + + return 0; + } + + return -EOPNOTSUPP; +} + +static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data) +{ + board_info_t *dm = to_dm9000_board(dev); + int ret = -EOPNOTSUPP; + + if (dm->can_csum) + ret = ethtool_op_set_tx_csum(dev, data); + return ret; +} + static u32 dm9000_get_link(struct net_device *dev) { board_info_t *dm = to_dm9000_board(dev); @@ -540,6 +579,10 @@ static const struct ethtool_ops dm9000_ethtool_ops = { .get_eeprom_len = dm9000_get_eeprom_len, .get_eeprom = dm9000_get_eeprom, .set_eeprom = dm9000_set_eeprom, + .get_rx_csum = dm9000_get_rx_csum, + .set_rx_csum = dm9000_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = dm9000_set_tx_csum, }; static void dm9000_show_carrier(board_info_t *db, @@ -685,6 +728,9 @@ dm9000_init_dm9000(struct net_device *dev) /* I/O mode */ db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ + /* Checksum mode */ + dm9000_set_rx_csum(dev, db->rx_csum); + /* GPIO0 on pre-activate PHY */ iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ @@ -743,6 +789,29 @@ static void dm9000_timeout(struct net_device *dev) spin_unlock_irqrestore(&db->lock, flags); } +static void dm9000_send_packet(struct net_device *dev, + int ip_summed, + u16 pkt_len) +{ + board_info_t *dm = to_dm9000_board(dev); + + /* The DM9000 is not smart enough to leave fragmented packets alone. */ + if (dm->ip_summed != ip_summed) { + if (ip_summed == CHECKSUM_NONE) + iow(dm, DM9000_TCCR, 0); + else + iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP); + dm->ip_summed = ip_summed; + } + + /* Set TX length to DM9000 */ + iow(dm, DM9000_TXPLL, pkt_len); + iow(dm, DM9000_TXPLH, pkt_len >> 8); + + /* Issue TX polling command */ + iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ +} + /* * Hardware start transmission. * Send a packet to media from the upper layer. @@ -769,17 +838,11 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) db->tx_pkt_cnt++; /* TX control: First packet immediately send, second packet queue */ if (db->tx_pkt_cnt == 1) { - /* Set TX length to DM9000 */ - iow(db, DM9000_TXPLL, skb->len); - iow(db, DM9000_TXPLH, skb->len >> 8); - - /* Issue TX polling command */ - iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ - - dev->trans_start = jiffies; /* save the time stamp */ + dm9000_send_packet(dev, skb->ip_summed, skb->len); } else { /* Second packet */ db->queue_pkt_len = skb->len; + db->queue_ip_summed = skb->ip_summed; netif_stop_queue(dev); } @@ -809,12 +872,9 @@ static void dm9000_tx_done(struct net_device *dev, board_info_t *db) dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status); /* Queue packet check & send */ - if (db->tx_pkt_cnt > 0) { - iow(db, DM9000_TXPLL, db->queue_pkt_len); - iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8); - iow(db, DM9000_TCR, TCR_TXREQ); - dev->trans_start = jiffies; - } + if (db->tx_pkt_cnt > 0) + dm9000_send_packet(dev, db->queue_ip_summed, + db->queue_pkt_len); netif_wake_queue(dev); } } @@ -846,14 +906,14 @@ dm9000_rx(struct net_device *dev) rxbyte = readb(db->io_data); /* Status check: this byte must be 0 or 1 */ - if (rxbyte > DM9000_PKT_RDY) { + if (rxbyte & DM9000_PKT_ERR) { dev_warn(db->dev, "status check fail: %d\n", rxbyte); iow(db, DM9000_RCR, 0x00); /* Stop Device */ iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */ return; } - if (rxbyte != DM9000_PKT_RDY) + if (!(rxbyte & DM9000_PKT_RDY)) return; /* A packet ready now & Get status/length */ @@ -914,6 +974,12 @@ dm9000_rx(struct net_device *dev) /* Pass to upper layer */ skb->protocol = eth_type_trans(skb, dev); + if (db->rx_csum) { + if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + } netif_rx(skb); dev->stats.rx_packets++; @@ -922,7 +988,7 @@ dm9000_rx(struct net_device *dev) (db->dumpblk)(db->io_data, RxLen); } - } while (rxbyte == DM9000_PKT_RDY); + } while (rxbyte & DM9000_PKT_RDY); } static irqreturn_t dm9000_interrupt(int irq, void *dev_id) @@ -1349,6 +1415,13 @@ dm9000_probe(struct platform_device *pdev) db->type = TYPE_DM9000E; } + /* dm9000a/b are capable of hardware checksum offload */ + if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) { + db->can_csum = 1; + db->rx_csum = 1; + ndev->features |= NETIF_F_IP_CSUM; + } + /* from this point we assume that we have found a DM9000 */ /* driver system function */ diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h index ba25cf5..80817c2 100644 --- a/drivers/net/dm9000.h +++ b/drivers/net/dm9000.h @@ -45,6 +45,10 @@ #define DM9000_CHIPR 0x2C #define DM9000_SMCR 0x2F +#define DM9000_ETXCSR 0x30 +#define DM9000_TCCR 0x31 +#define DM9000_RCSR 0x32 + #define CHIPR_DM9000A 0x19 #define CHIPR_DM9000B 0x1B @@ -131,7 +135,21 @@ #define GPCR_GEP_CNTL (1<<0) +#define TCCR_IP (1<<0) +#define TCCR_TCP (1<<1) +#define TCCR_UDP (1<<2) + +#define RCSR_UDP_BAD (1<<7) +#define RCSR_TCP_BAD (1<<6) +#define RCSR_IP_BAD (1<<5) +#define RCSR_UDP (1<<4) +#define RCSR_TCP (1<<3) +#define RCSR_IP (1<<2) +#define RCSR_CSUM (1<<1) +#define RCSR_DISCARD (1<<0) + #define DM9000_PKT_RDY 0x01 /* Packet ready to receive */ +#define DM9000_PKT_ERR 0x02 #define DM9000_PKT_MAX 1536 /* Received packet max size */ /* DM9000A / DM9000B definitions */ -- cgit v0.10.2 From ef0657c49e0f93dcebc9b4719e4fe0b478411f60 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 6 Jul 2009 19:09:50 -0700 Subject: drivers/net/cs89x0.c: Avoid using magic number in set_dma_mode The constant DMA_RX_MODE is defined to be 0x14 in the local include file cs89x0.h. Since a constant with the same name is used elsewhere with set_dma_mode, it seems likely that this constant could be used here. The semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ expression E1; identifier I; constant int C; @@ ( set_dma_mode(E1,I,...) | *set_dma_mode(E1,C,...) ) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index b5f553a..e594897 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1367,7 +1367,7 @@ net_open(struct net_device *dev) spin_lock_irqsave(&lp->lock, flags); disable_dma(dev->dma); clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, 0x14); /* auto_init as well */ + set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */ set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff)); set_dma_count(dev->dma, lp->dmasize*1024); enable_dma(dev->dma); -- cgit v0.10.2 From f2ac72e8268d9559c3114d5a22679f91f80a2238 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 7 Jul 2009 12:30:33 +0800 Subject: crypto: api - Add new template create function This patch introduces the template->create function intended to replace the existing alloc function. The intention is for create to handle the registration directly, whereas currently the caller of alloc has to handle the registration. This allows type-specific code to be run prior to registration. Signed-off-by: Herbert Xu diff --git a/crypto/algboss.c b/crypto/algboss.c index 9908dd8..412241c 100644 --- a/crypto/algboss.c +++ b/crypto/algboss.c @@ -68,6 +68,11 @@ static int cryptomgr_probe(void *data) goto err; do { + if (tmpl->create) { + err = tmpl->create(tmpl, param->tb); + continue; + } + inst = tmpl->alloc(param->tb); if (IS_ERR(inst)) err = PTR_ERR(inst); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 0105454..ce010a3 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -52,6 +52,7 @@ struct crypto_template { struct crypto_instance *(*alloc)(struct rtattr **tb); void (*free)(struct crypto_instance *inst); + int (*create)(struct crypto_template *tmpl, struct rtattr **tb); char name[CRYPTO_MAX_ALG_NAME]; }; -- cgit v0.10.2 From 0b959167237208bc1a811e30bf866cd29bff1652 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 6 Jul 2009 22:08:04 +0200 Subject: ALSA: cmi8330: find OPL3 port automatically My CMI8329 had OPL3 port specified in SB16 resources. But now I found out that it was my modification of the card's PnP EEPROM a couple of years ago (can be done using C9SETROM.EXE utility). I did it because the OPL3 port was completely missing from PnP data. It seems to be hardwired to 0x388 on CMI8329. Find OPL3 port automatically by searching in WSS and SB16 resources. If not found, assume that it's hardwired to 0x388. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 33e63fa..f7acb8d 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -362,7 +362,7 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, wssport[dev] = pnp_port_start(pdev, 0); wssdma[dev] = pnp_dma(pdev, 0); wssirq[dev] = pnp_irq(pdev, 0); - if (acard->type == CMI8330) + if (pnp_port_start(pdev, 1)) fmport[dev] = pnp_port_start(pdev, 1); /* allocate SB16 resources */ @@ -377,8 +377,13 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, sbdma8[dev] = pnp_dma(pdev, 0); sbdma16[dev] = pnp_dma(pdev, 1); sbirq[dev] = pnp_irq(pdev, 0); - if (acard->type == CMI8329) - fmport[dev] = pnp_port_start(pdev, 1); + /* On CMI8239, the OPL3 port might be present in SB16 PnP resources */ + if (fmport[dev] == SNDRV_AUTO_PORT) { + if (pnp_port_start(pdev, 1)) + fmport[dev] = pnp_port_start(pdev, 1); + else + fmport[dev] = 0x388; /* Or hardwired */ + } /* allocate MPU-401 resources */ pdev = acard->mpu; -- cgit v0.10.2 From ed208255e700073c34b0ef8d2045ac030ac28971 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Jul 2009 09:04:26 +0200 Subject: ALSA: hda - Add GPIO setup for MacBook pro 5,5 with CS420x GPIO3 seems corresponding to EAPD that is required for the speaker output. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index b1fd183..1217344 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -53,6 +53,10 @@ struct cs_spec { struct hda_bind_ctls *capture_bind[2]; + unsigned int gpio_mask; + unsigned int gpio_dir; + unsigned int gpio_data; + struct hda_pcm pcm_rec[2]; /* PCM information */ unsigned int hp_detect:1; @@ -981,6 +985,16 @@ static int cs_init(struct hda_codec *codec) struct cs_spec *spec = codec->spec; snd_hda_sequence_write(codec, cs_coef_init_verbs); + + if (spec->gpio_mask) { + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, + spec->gpio_mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, + spec->gpio_dir); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_data); + } + init_output(codec); init_input(codec); init_digital(codec); @@ -1043,6 +1057,19 @@ static int cs_parse_auto_config(struct hda_codec *codec) err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); if (err < 0) return err; + + err = parse_output(codec); + if (err < 0) + return err; + err = parse_input(codec); + if (err < 0) + return err; + err = parse_digital_output(codec); + if (err < 0) + return err; + err = parse_digital_input(codec); + if (err < 0) + return err; return 0; } @@ -1106,20 +1133,16 @@ static int patch_cs420x(struct hda_codec *codec) if (spec->board_config >= 0) fix_pincfg(codec, spec->board_config); - err = cs_parse_auto_config(codec); - if (err < 0) - goto error; + switch (spec->board_config) { + case CS420X_MBP55: + /* GPIO3 = EAPD? */ + spec->gpio_mask = 0x08; + spec->gpio_dir = 0x08; + spec->gpio_data = 0x08; + break; + } - err = parse_output(codec); - if (err < 0) - goto error; - err = parse_input(codec); - if (err < 0) - goto error; - err = parse_digital_output(codec); - if (err < 0) - goto error; - err = parse_digital_input(codec); + err = cs_parse_auto_config(codec); if (err < 0) goto error; -- cgit v0.10.2 From b4dabfc452a1011882983db9e464f8ee1e3c01e6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Jul 2009 09:05:07 +0200 Subject: ALSA: hda - Fix the speaker volume control name Increase the name string buffer size so that "Surround Speaker Playback Volume" won't be truncated. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 1217344..54a7dc8 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -497,7 +497,7 @@ static const char *dir_sfx[2] = { "Playback", "Capture" }; static int add_mute(struct hda_codec *codec, const char *name, int index, unsigned int pval, int dir, struct snd_kcontrol **kctlp) { - char tmp[32]; + char tmp[44]; struct snd_kcontrol_new knew = HDA_CODEC_MUTE_IDX(tmp, index, 0, 0, HDA_OUTPUT); knew.private_value = pval; -- cgit v0.10.2 From 70ec7bb91ad0d6cce84c8e17f8cbb608dda7b18c Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 7 Jul 2009 14:07:37 +0800 Subject: crypto: api - Add crypto_alloc_instance2 This patch adds a new argument to crypto_alloc_instance which sets aside some space before the instance for use by algorithms such as shash that place type-specific data before crypto_alg. For compatibility the function has been renamed so that existing users aren't affected. Signed-off-by: Herbert Xu diff --git a/crypto/algapi.c b/crypto/algapi.c index 56c62e2..429f1a0 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -627,17 +627,20 @@ int crypto_attr_u32(struct rtattr *rta, u32 *num) } EXPORT_SYMBOL_GPL(crypto_attr_u32); -struct crypto_instance *crypto_alloc_instance(const char *name, - struct crypto_alg *alg) +void *crypto_alloc_instance2(const char *name, struct crypto_alg *alg, + unsigned int head) { struct crypto_instance *inst; - struct crypto_spawn *spawn; + char *p; int err; - inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); - if (!inst) + p = kzalloc(head + sizeof(*inst) + sizeof(struct crypto_spawn), + GFP_KERNEL); + if (!p) return ERR_PTR(-ENOMEM); + inst = (void *)(p + head); + err = -ENAMETOOLONG; if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name, alg->cra_name) >= CRYPTO_MAX_ALG_NAME) @@ -647,6 +650,25 @@ struct crypto_instance *crypto_alloc_instance(const char *name, name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) goto err_free_inst; + return p; + +err_free_inst: + kfree(p); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(crypto_alloc_instance2); + +struct crypto_instance *crypto_alloc_instance(const char *name, + struct crypto_alg *alg) +{ + struct crypto_instance *inst; + struct crypto_spawn *spawn; + int err; + + inst = crypto_alloc_instance2(name, alg, 0); + if (IS_ERR(inst)) + goto out; + spawn = crypto_instance_ctx(inst); err = crypto_init_spawn(spawn, alg, inst, CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); @@ -658,7 +680,10 @@ struct crypto_instance *crypto_alloc_instance(const char *name, err_free_inst: kfree(inst); - return ERR_PTR(err); + inst = ERR_PTR(err); + +out: + return inst; } EXPORT_SYMBOL_GPL(crypto_alloc_instance); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index ce010a3..99bb297 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -132,6 +132,8 @@ int crypto_check_attr_type(struct rtattr **tb, u32 type); const char *crypto_attr_alg_name(struct rtattr *rta); struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask); int crypto_attr_u32(struct rtattr *rta, u32 *num); +void *crypto_alloc_instance2(const char *name, struct crypto_alg *alg, + unsigned int head); struct crypto_instance *crypto_alloc_instance(const char *name, struct crypto_alg *alg); -- cgit v0.10.2 From 72b43cf1402169e8bc088838a6db91d613c35627 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 7 Jul 2009 18:09:48 +0200 Subject: ALSA: cmi8330: Allow MPU-401-less operation Adding MPU-401 support to cmi8330 driver could cause a regression (non-working sound) on a system where there is no free IRQ for the MPU-401 device (which is not very uncommon as this card requires two separate IRQs plus a third one for MPU-401). When MPU-401 PnP configuration fails (mostly because of unavailable IRQ), just ignore MPU-401 and continue without it. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index f7acb8d..02f79d2 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -389,12 +389,12 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, pdev = acard->mpu; err = pnp_activate_dev(pdev); - if (err < 0) { - snd_printk(KERN_ERR "MPU-401 PnP configure failure\n"); - return -EBUSY; + if (err < 0) + snd_printk(KERN_ERR "MPU-401 PnP configure failure: will be disabled\n"); + else { + mpuport[dev] = pnp_port_start(pdev, 0); + mpuirq[dev] = pnp_irq(pdev, 0); } - mpuport[dev] = pnp_port_start(pdev, 0); - mpuirq[dev] = pnp_irq(pdev, 0); return 0; } #endif -- cgit v0.10.2 From 3adc54fa82a68be1cd1ac82ad786ee362796e50a Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 30 Mar 2009 15:32:01 -0400 Subject: ring-buffer: make the buffer a true circular link list This patch changes the ring buffer data pages from using a link list head pointer, to making each buffer page point to another buffer page and never back to a "head". This makes the handling of the ring buffer less complex, since the traversing of the ring buffer pages no longer needs to account for the head pointer. This change also is needed to make the ring buffer lockless. [ Changes in version 2: - Added change that Lai Jiangshan mentioned. From: Lai Jiangshan Date: Thu, 11 Jun 2009 11:25:48 +0800 LKML-Reference: <4A30793C.6090208@cn.fujitsu.com> I'm not sure whether these 4 lines: bpage = list_entry(pages.next, struct buffer_page, list); list_del_init(&bpage->list); cpu_buffer->pages = &bpage->list; list_splice(&pages, cpu_buffer->pages); equal to these 2 lines: cpu_buffer->pages = pages.next; list_del(&pages); If there are equivalent, I think the second one are simpler. It may be not a really necessarily cleanup. What I asked is: if there are equivalent, could you use these two line: cpu_buffer->pages = pages.next; list_del(&pages); ] [ Impact: simplify the ring buffer to help make it lockless ] Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index bf27bb7..7c0168a 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -406,7 +406,7 @@ struct ring_buffer_per_cpu { spinlock_t reader_lock; /* serialize readers */ raw_spinlock_t lock; struct lock_class_key lock_key; - struct list_head pages; + struct list_head *pages; struct buffer_page *head_page; /* read from head */ struct buffer_page *tail_page; /* write to tail */ struct buffer_page *commit_page; /* committed pages */ @@ -498,7 +498,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_normalize_time_stamp); */ static int rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer) { - struct list_head *head = &cpu_buffer->pages; + struct list_head *head = cpu_buffer->pages; struct buffer_page *bpage, *tmp; if (RB_WARN_ON(cpu_buffer, head->next->prev != head)) @@ -521,12 +521,13 @@ static int rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer) static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned nr_pages) { - struct list_head *head = &cpu_buffer->pages; struct buffer_page *bpage, *tmp; unsigned long addr; LIST_HEAD(pages); unsigned i; + WARN_ON(!nr_pages); + for (i = 0; i < nr_pages; i++) { bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()), GFP_KERNEL, cpu_to_node(cpu_buffer->cpu)); @@ -541,7 +542,13 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer, rb_init_page(bpage->page); } - list_splice(&pages, head); + /* + * The ring buffer page list is a circular list that does not + * start and end with a list head. All page list items point to + * other pages. + */ + cpu_buffer->pages = pages.next; + list_del(&pages); rb_check_pages(cpu_buffer); @@ -573,7 +580,6 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) spin_lock_init(&cpu_buffer->reader_lock); lockdep_set_class(&cpu_buffer->reader_lock, buffer->reader_lock_key); cpu_buffer->lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; - INIT_LIST_HEAD(&cpu_buffer->pages); bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()), GFP_KERNEL, cpu_to_node(cpu)); @@ -594,7 +600,7 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) goto fail_free_reader; cpu_buffer->head_page - = list_entry(cpu_buffer->pages.next, struct buffer_page, list); + = list_entry(cpu_buffer->pages, struct buffer_page, list); cpu_buffer->tail_page = cpu_buffer->commit_page = cpu_buffer->head_page; return cpu_buffer; @@ -609,15 +615,20 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer) { - struct list_head *head = &cpu_buffer->pages; + struct list_head *head = cpu_buffer->pages; struct buffer_page *bpage, *tmp; free_buffer_page(cpu_buffer->reader_page); - list_for_each_entry_safe(bpage, tmp, head, list) { - list_del_init(&bpage->list); + if (head) { + list_for_each_entry_safe(bpage, tmp, head, list) { + list_del_init(&bpage->list); + free_buffer_page(bpage); + } + bpage = list_entry(head, struct buffer_page, list); free_buffer_page(bpage); } + kfree(cpu_buffer); } @@ -760,14 +771,14 @@ rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned nr_pages) synchronize_sched(); for (i = 0; i < nr_pages; i++) { - if (RB_WARN_ON(cpu_buffer, list_empty(&cpu_buffer->pages))) + if (RB_WARN_ON(cpu_buffer, list_empty(cpu_buffer->pages))) return; - p = cpu_buffer->pages.next; + p = cpu_buffer->pages->next; bpage = list_entry(p, struct buffer_page, list); list_del_init(&bpage->list); free_buffer_page(bpage); } - if (RB_WARN_ON(cpu_buffer, list_empty(&cpu_buffer->pages))) + if (RB_WARN_ON(cpu_buffer, list_empty(cpu_buffer->pages))) return; rb_reset_cpu(cpu_buffer); @@ -795,7 +806,7 @@ rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer, p = pages->next; bpage = list_entry(p, struct buffer_page, list); list_del_init(&bpage->list); - list_add_tail(&bpage->list, &cpu_buffer->pages); + list_add_tail(&bpage->list, cpu_buffer->pages); } rb_reset_cpu(cpu_buffer); @@ -992,9 +1003,6 @@ static inline void rb_inc_page(struct ring_buffer_per_cpu *cpu_buffer, { struct list_head *p = (*bpage)->list.next; - if (p == &cpu_buffer->pages) - p = p->next; - *bpage = list_entry(p, struct buffer_page, list); } @@ -2247,6 +2255,13 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) cpu_buffer->reader_page->list.next = reader->list.next; cpu_buffer->reader_page->list.prev = reader->list.prev; + /* + * cpu_buffer->pages just needs to point to the buffer, it + * has no specific buffer page to point to. Lets move it out + * of our way so we don't accidently swap it. + */ + cpu_buffer->pages = reader->list.prev; + local_set(&cpu_buffer->reader_page->write, 0); local_set(&cpu_buffer->reader_page->entries, 0); local_set(&cpu_buffer->reader_page->page->commit, 0); @@ -2719,7 +2734,7 @@ static void rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer) { cpu_buffer->head_page - = list_entry(cpu_buffer->pages.next, struct buffer_page, list); + = list_entry(cpu_buffer->pages, struct buffer_page, list); local_set(&cpu_buffer->head_page->write, 0); local_set(&cpu_buffer->head_page->entries, 0); local_set(&cpu_buffer->head_page->page->commit, 0); -- cgit v0.10.2 From 77ae365eca895061c8bf2b2e3ae1d9ea62869739 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 27 Mar 2009 11:00:29 -0400 Subject: ring-buffer: make lockless This patch converts the ring buffers into a completely lockless buffer recording system. The read side still takes locks since we still serialize readers. But the writers are the ones that must be lockless (those can happen in NMIs). The main change is to the "head_page" pointer. We write to the tail, and read from the head. The "head_page" pointer in the cpu buffer is now just a reference to where to look. The real head page is now kept in the head_page->list->prev->next pointer. That is, in the list head of the previous page we set flags. The list pages are allocated to be aligned such that the lowest significant bits are always zero pointing to the list. This gives us play to put in flags to their pointers. bit 0: set when the page is a head page bit 1: set when the writer is moving the page (for overwrite mode) cmpxchg is used to update the pointer. When the writer wraps the buffer and the tail meets the head, in overwrite mode, the writer must move the head page forward. It first uses cmpxchg to change the pointer flag from 1 to 2. Once this is done, the reader on another CPU will not take the page from the buffer. The writers need to protect against interrupts (we don't bother with disabling interrupts because NMIs are allowed to write too). After the writer sets the pointer flag to 2, it takes care to manage interrupts coming in. This is discribed in detail within the comments of the code. Changes in version 2: - Let reader reset entries value of header page. - Fix tail page passing commit page on reader page test. - Always increment entries and write counter in rb_tail_page_update - Add safety check in rb_set_commit_to_write to break out of infinite loop - add mask in rb_is_reader_page [ Impact: lock free writing to the ring buffer ] Signed-off-by: Steven Rostedt diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index 29f8599..7fca716 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h @@ -170,7 +170,6 @@ unsigned long ring_buffer_overruns(struct ring_buffer *buffer); unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu); unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu); unsigned long ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu); -unsigned long ring_buffer_nmi_dropped_cpu(struct ring_buffer *buffer, int cpu); u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu); void ring_buffer_normalize_time_stamp(struct ring_buffer *buffer, diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 7c0168a..e648ba4 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -322,6 +322,14 @@ struct buffer_data_page { unsigned char data[]; /* data of buffer page */ }; +/* + * Note, the buffer_page list must be first. The buffer pages + * are allocated in cache lines, which means that each buffer + * page will be at the beginning of a cache line, and thus + * the least significant bits will be zero. We use this to + * add flags in the list struct pointers, to make the ring buffer + * lockless. + */ struct buffer_page { struct list_head list; /* list of buffer pages */ local_t write; /* index for next write */ @@ -330,6 +338,21 @@ struct buffer_page { struct buffer_data_page *page; /* Actual data page */ }; +/* + * The buffer page counters, write and entries, must be reset + * atomically when crossing page boundaries. To synchronize this + * update, two counters are inserted into the number. One is + * the actual counter for the write position or count on the page. + * + * The other is a counter of updaters. Before an update happens + * the update partition of the counter is incremented. This will + * allow the updater to update the counter atomically. + * + * The counter is 20 bits, and the state data is 12. + */ +#define RB_WRITE_MASK 0xfffff +#define RB_WRITE_INTCNT (1 << 20) + static void rb_init_page(struct buffer_data_page *bpage) { local_set(&bpage->commit, 0); @@ -403,7 +426,7 @@ int ring_buffer_print_page_header(struct trace_seq *s) struct ring_buffer_per_cpu { int cpu; struct ring_buffer *buffer; - spinlock_t reader_lock; /* serialize readers */ + spinlock_t reader_lock; /* serialize readers */ raw_spinlock_t lock; struct lock_class_key lock_key; struct list_head *pages; @@ -411,13 +434,12 @@ struct ring_buffer_per_cpu { struct buffer_page *tail_page; /* write to tail */ struct buffer_page *commit_page; /* committed pages */ struct buffer_page *reader_page; - unsigned long nmi_dropped; - unsigned long commit_overrun; - unsigned long overrun; - unsigned long read; + local_t commit_overrun; + local_t overrun; local_t entries; local_t committing; local_t commits; + unsigned long read; u64 write_stamp; u64 read_stamp; atomic_t record_disabled; @@ -489,6 +511,385 @@ void ring_buffer_normalize_time_stamp(struct ring_buffer *buffer, } EXPORT_SYMBOL_GPL(ring_buffer_normalize_time_stamp); +/* + * Making the ring buffer lockless makes things tricky. + * Although writes only happen on the CPU that they are on, + * and they only need to worry about interrupts. Reads can + * happen on any CPU. + * + * The reader page is always off the ring buffer, but when the + * reader finishes with a page, it needs to swap its page with + * a new one from the buffer. The reader needs to take from + * the head (writes go to the tail). But if a writer is in overwrite + * mode and wraps, it must push the head page forward. + * + * Here lies the problem. + * + * The reader must be careful to replace only the head page, and + * not another one. As described at the top of the file in the + * ASCII art, the reader sets its old page to point to the next + * page after head. It then sets the page after head to point to + * the old reader page. But if the writer moves the head page + * during this operation, the reader could end up with the tail. + * + * We use cmpxchg to help prevent this race. We also do something + * special with the page before head. We set the LSB to 1. + * + * When the writer must push the page forward, it will clear the + * bit that points to the head page, move the head, and then set + * the bit that points to the new head page. + * + * We also don't want an interrupt coming in and moving the head + * page on another writer. Thus we use the second LSB to catch + * that too. Thus: + * + * head->list->prev->next bit 1 bit 0 + * ------- ------- + * Normal page 0 0 + * Points to head page 0 1 + * New head page 1 0 + * + * Note we can not trust the prev pointer of the head page, because: + * + * +----+ +-----+ +-----+ + * | |------>| T |---X--->| N | + * | |<------| | | | + * +----+ +-----+ +-----+ + * ^ ^ | + * | +-----+ | | + * +----------| R |----------+ | + * | |<-----------+ + * +-----+ + * + * Key: ---X--> HEAD flag set in pointer + * T Tail page + * R Reader page + * N Next page + * + * (see __rb_reserve_next() to see where this happens) + * + * What the above shows is that the reader just swapped out + * the reader page with a page in the buffer, but before it + * could make the new header point back to the new page added + * it was preempted by a writer. The writer moved forward onto + * the new page added by the reader and is about to move forward + * again. + * + * You can see, it is legitimate for the previous pointer of + * the head (or any page) not to point back to itself. But only + * temporarially. + */ + +#define RB_PAGE_NORMAL 0UL +#define RB_PAGE_HEAD 1UL +#define RB_PAGE_UPDATE 2UL + + +#define RB_FLAG_MASK 3UL + +/* PAGE_MOVED is not part of the mask */ +#define RB_PAGE_MOVED 4UL + +/* + * rb_list_head - remove any bit + */ +static struct list_head *rb_list_head(struct list_head *list) +{ + unsigned long val = (unsigned long)list; + + return (struct list_head *)(val & ~RB_FLAG_MASK); +} + +/* + * rb_is_head_page - test if the give page is the head page + * + * Because the reader may move the head_page pointer, we can + * not trust what the head page is (it may be pointing to + * the reader page). But if the next page is a header page, + * its flags will be non zero. + */ +static int inline +rb_is_head_page(struct ring_buffer_per_cpu *cpu_buffer, + struct buffer_page *page, struct list_head *list) +{ + unsigned long val; + + val = (unsigned long)list->next; + + if ((val & ~RB_FLAG_MASK) != (unsigned long)&page->list) + return RB_PAGE_MOVED; + + return val & RB_FLAG_MASK; +} + +/* + * rb_is_reader_page + * + * The unique thing about the reader page, is that, if the + * writer is ever on it, the previous pointer never points + * back to the reader page. + */ +static int rb_is_reader_page(struct buffer_page *page) +{ + struct list_head *list = page->list.prev; + + return rb_list_head(list->next) != &page->list; +} + +/* + * rb_set_list_to_head - set a list_head to be pointing to head. + */ +static void rb_set_list_to_head(struct ring_buffer_per_cpu *cpu_buffer, + struct list_head *list) +{ + unsigned long *ptr; + + ptr = (unsigned long *)&list->next; + *ptr |= RB_PAGE_HEAD; + *ptr &= ~RB_PAGE_UPDATE; +} + +/* + * rb_head_page_activate - sets up head page + */ +static void rb_head_page_activate(struct ring_buffer_per_cpu *cpu_buffer) +{ + struct buffer_page *head; + + head = cpu_buffer->head_page; + if (!head) + return; + + /* + * Set the previous list pointer to have the HEAD flag. + */ + rb_set_list_to_head(cpu_buffer, head->list.prev); +} + +static void rb_list_head_clear(struct list_head *list) +{ + unsigned long *ptr = (unsigned long *)&list->next; + + *ptr &= ~RB_FLAG_MASK; +} + +/* + * rb_head_page_dactivate - clears head page ptr (for free list) + */ +static void +rb_head_page_deactivate(struct ring_buffer_per_cpu *cpu_buffer) +{ + struct list_head *hd; + + /* Go through the whole list and clear any pointers found. */ + rb_list_head_clear(cpu_buffer->pages); + + list_for_each(hd, cpu_buffer->pages) + rb_list_head_clear(hd); +} + +static int rb_head_page_set(struct ring_buffer_per_cpu *cpu_buffer, + struct buffer_page *head, + struct buffer_page *prev, + int old_flag, int new_flag) +{ + struct list_head *list; + unsigned long val = (unsigned long)&head->list; + unsigned long ret; + + list = &prev->list; + + val &= ~RB_FLAG_MASK; + + ret = (unsigned long)cmpxchg(&list->next, + val | old_flag, val | new_flag); + + /* check if the reader took the page */ + if ((ret & ~RB_FLAG_MASK) != val) + return RB_PAGE_MOVED; + + return ret & RB_FLAG_MASK; +} + +static int rb_head_page_set_update(struct ring_buffer_per_cpu *cpu_buffer, + struct buffer_page *head, + struct buffer_page *prev, + int old_flag) +{ + return rb_head_page_set(cpu_buffer, head, prev, + old_flag, RB_PAGE_UPDATE); +} + +static int rb_head_page_set_head(struct ring_buffer_per_cpu *cpu_buffer, + struct buffer_page *head, + struct buffer_page *prev, + int old_flag) +{ + return rb_head_page_set(cpu_buffer, head, prev, + old_flag, RB_PAGE_HEAD); +} + +static int rb_head_page_set_normal(struct ring_buffer_per_cpu *cpu_buffer, + struct buffer_page *head, + struct buffer_page *prev, + int old_flag) +{ + return rb_head_page_set(cpu_buffer, head, prev, + old_flag, RB_PAGE_NORMAL); +} + +static inline void rb_inc_page(struct ring_buffer_per_cpu *cpu_buffer, + struct buffer_page **bpage) +{ + struct list_head *p = rb_list_head((*bpage)->list.next); + + *bpage = list_entry(p, struct buffer_page, list); +} + +static struct buffer_page * +rb_set_head_page(struct ring_buffer_per_cpu *cpu_buffer) +{ + struct buffer_page *head; + struct buffer_page *page; + struct list_head *list; + int i; + + if (RB_WARN_ON(cpu_buffer, !cpu_buffer->head_page)) + return NULL; + + /* sanity check */ + list = cpu_buffer->pages; + if (RB_WARN_ON(cpu_buffer, rb_list_head(list->prev->next) != list)) + return NULL; + + page = head = cpu_buffer->head_page; + /* + * It is possible that the writer moves the header behind + * where we started, and we miss in one loop. + * A second loop should grab the header, but we'll do + * three loops just because I'm paranoid. + */ + for (i = 0; i < 3; i++) { + do { + if (rb_is_head_page(cpu_buffer, page, page->list.prev)) { + cpu_buffer->head_page = page; + return page; + } + rb_inc_page(cpu_buffer, &page); + } while (page != head); + } + + RB_WARN_ON(cpu_buffer, 1); + + return NULL; +} + +static int rb_head_page_replace(struct buffer_page *old, + struct buffer_page *new) +{ + unsigned long *ptr = (unsigned long *)&old->list.prev->next; + unsigned long val; + unsigned long ret; + + val = *ptr & ~RB_FLAG_MASK; + val |= RB_PAGE_HEAD; + + ret = cmpxchg(ptr, val, &new->list); + + return ret == val; +} + +/* + * rb_tail_page_update - move the tail page forward + * + * Returns 1 if moved tail page, 0 if someone else did. + */ +static int rb_tail_page_update(struct ring_buffer_per_cpu *cpu_buffer, + struct buffer_page *tail_page, + struct buffer_page *next_page) +{ + struct buffer_page *old_tail; + unsigned long old_entries; + unsigned long old_write; + int ret = 0; + + /* + * The tail page now needs to be moved forward. + * + * We need to reset the tail page, but without messing + * with possible erasing of data brought in by interrupts + * that have moved the tail page and are currently on it. + * + * We add a counter to the write field to denote this. + */ + old_write = local_add_return(RB_WRITE_INTCNT, &next_page->write); + old_entries = local_add_return(RB_WRITE_INTCNT, &next_page->entries); + + /* + * Just make sure we have seen our old_write and synchronize + * with any interrupts that come in. + */ + barrier(); + + /* + * If the tail page is still the same as what we think + * it is, then it is up to us to update the tail + * pointer. + */ + if (tail_page == cpu_buffer->tail_page) { + /* Zero the write counter */ + unsigned long val = old_write & ~RB_WRITE_MASK; + unsigned long eval = old_entries & ~RB_WRITE_MASK; + + /* + * This will only succeed if an interrupt did + * not come in and change it. In which case, we + * do not want to modify it. + */ + local_cmpxchg(&next_page->write, old_write, val); + local_cmpxchg(&next_page->entries, old_entries, eval); + + /* + * No need to worry about races with clearing out the commit. + * it only can increment when a commit takes place. But that + * only happens in the outer most nested commit. + */ + local_set(&next_page->page->commit, 0); + + old_tail = cmpxchg(&cpu_buffer->tail_page, + tail_page, next_page); + + if (old_tail == tail_page) + ret = 1; + } + + return ret; +} + +static int rb_check_bpage(struct ring_buffer_per_cpu *cpu_buffer, + struct buffer_page *bpage) +{ + unsigned long val = (unsigned long)bpage; + + if (RB_WARN_ON(cpu_buffer, val & RB_FLAG_MASK)) + return 1; + + return 0; +} + +/** + * rb_check_list - make sure a pointer to a list has the last bits zero + */ +static int rb_check_list(struct ring_buffer_per_cpu *cpu_buffer, + struct list_head *list) +{ + if (RB_WARN_ON(cpu_buffer, rb_list_head(list->prev) != list->prev)) + return 1; + if (RB_WARN_ON(cpu_buffer, rb_list_head(list->next) != list->next)) + return 1; + return 0; +} + /** * check_pages - integrity check of buffer pages * @cpu_buffer: CPU buffer with pages to test @@ -501,11 +902,16 @@ static int rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer) struct list_head *head = cpu_buffer->pages; struct buffer_page *bpage, *tmp; + rb_head_page_deactivate(cpu_buffer); + if (RB_WARN_ON(cpu_buffer, head->next->prev != head)) return -1; if (RB_WARN_ON(cpu_buffer, head->prev->next != head)) return -1; + if (rb_check_list(cpu_buffer, head)) + return -1; + list_for_each_entry_safe(bpage, tmp, head, list) { if (RB_WARN_ON(cpu_buffer, bpage->list.next->prev != &bpage->list)) @@ -513,8 +919,12 @@ static int rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer) if (RB_WARN_ON(cpu_buffer, bpage->list.prev->next != &bpage->list)) return -1; + if (rb_check_list(cpu_buffer, &bpage->list)) + return -1; } + rb_head_page_activate(cpu_buffer); + return 0; } @@ -533,6 +943,9 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer, GFP_KERNEL, cpu_to_node(cpu_buffer->cpu)); if (!bpage) goto free_pages; + + rb_check_bpage(cpu_buffer, bpage); + list_add(&bpage->list, &pages); addr = __get_free_page(GFP_KERNEL); @@ -586,6 +999,8 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) if (!bpage) goto fail_free_buffer; + rb_check_bpage(cpu_buffer, bpage); + cpu_buffer->reader_page = bpage; addr = __get_free_page(GFP_KERNEL); if (!addr) @@ -603,6 +1018,8 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) = list_entry(cpu_buffer->pages, struct buffer_page, list); cpu_buffer->tail_page = cpu_buffer->commit_page = cpu_buffer->head_page; + rb_head_page_activate(cpu_buffer); + return cpu_buffer; fail_free_reader: @@ -620,6 +1037,8 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer) free_buffer_page(cpu_buffer->reader_page); + rb_head_page_deactivate(cpu_buffer); + if (head) { list_for_each_entry_safe(bpage, tmp, head, list) { list_del_init(&bpage->list); @@ -770,6 +1189,8 @@ rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned nr_pages) atomic_inc(&cpu_buffer->record_disabled); synchronize_sched(); + rb_head_page_deactivate(cpu_buffer); + for (i = 0; i < nr_pages; i++) { if (RB_WARN_ON(cpu_buffer, list_empty(cpu_buffer->pages))) return; @@ -800,6 +1221,9 @@ rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer, atomic_inc(&cpu_buffer->record_disabled); synchronize_sched(); + spin_lock_irq(&cpu_buffer->reader_lock); + rb_head_page_deactivate(cpu_buffer); + for (i = 0; i < nr_pages; i++) { if (RB_WARN_ON(cpu_buffer, list_empty(pages))) return; @@ -809,6 +1233,7 @@ rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer, list_add_tail(&bpage->list, cpu_buffer->pages); } rb_reset_cpu(cpu_buffer); + spin_unlock_irq(&cpu_buffer->reader_lock); rb_check_pages(cpu_buffer); @@ -959,21 +1384,14 @@ rb_reader_event(struct ring_buffer_per_cpu *cpu_buffer) } static inline struct ring_buffer_event * -rb_head_event(struct ring_buffer_per_cpu *cpu_buffer) -{ - return __rb_page_index(cpu_buffer->head_page, - cpu_buffer->head_page->read); -} - -static inline struct ring_buffer_event * rb_iter_head_event(struct ring_buffer_iter *iter) { return __rb_page_index(iter->head_page, iter->head); } -static inline unsigned rb_page_write(struct buffer_page *bpage) +static inline unsigned long rb_page_write(struct buffer_page *bpage) { - return local_read(&bpage->write); + return local_read(&bpage->write) & RB_WRITE_MASK; } static inline unsigned rb_page_commit(struct buffer_page *bpage) @@ -981,6 +1399,11 @@ static inline unsigned rb_page_commit(struct buffer_page *bpage) return local_read(&bpage->page->commit); } +static inline unsigned long rb_page_entries(struct buffer_page *bpage) +{ + return local_read(&bpage->entries) & RB_WRITE_MASK; +} + /* Size is determined by what has been commited */ static inline unsigned rb_page_size(struct buffer_page *bpage) { @@ -993,19 +1416,6 @@ rb_commit_index(struct ring_buffer_per_cpu *cpu_buffer) return rb_page_commit(cpu_buffer->commit_page); } -static inline unsigned rb_head_size(struct ring_buffer_per_cpu *cpu_buffer) -{ - return rb_page_commit(cpu_buffer->head_page); -} - -static inline void rb_inc_page(struct ring_buffer_per_cpu *cpu_buffer, - struct buffer_page **bpage) -{ - struct list_head *p = (*bpage)->list.next; - - *bpage = list_entry(p, struct buffer_page, list); -} - static inline unsigned rb_event_index(struct ring_buffer_event *event) { @@ -1031,6 +1441,8 @@ rb_event_is_commit(struct ring_buffer_per_cpu *cpu_buffer, static void rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer) { + unsigned long max_count; + /* * We only race with interrupts and NMIs on this CPU. * If we own the commit event, then we can commit @@ -1040,9 +1452,16 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer) * assign the commit to the tail. */ again: + max_count = cpu_buffer->buffer->pages * 100; + while (cpu_buffer->commit_page != cpu_buffer->tail_page) { - cpu_buffer->commit_page->page->commit = - cpu_buffer->commit_page->write; + if (RB_WARN_ON(cpu_buffer, !(--max_count))) + return; + if (RB_WARN_ON(cpu_buffer, + rb_is_reader_page(cpu_buffer->tail_page))) + return; + local_set(&cpu_buffer->commit_page->page->commit, + rb_page_write(cpu_buffer->commit_page)); rb_inc_page(cpu_buffer, &cpu_buffer->commit_page); cpu_buffer->write_stamp = cpu_buffer->commit_page->page->time_stamp; @@ -1051,8 +1470,12 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer) } while (rb_commit_index(cpu_buffer) != rb_page_write(cpu_buffer->commit_page)) { - cpu_buffer->commit_page->page->commit = - cpu_buffer->commit_page->write; + + local_set(&cpu_buffer->commit_page->page->commit, + rb_page_write(cpu_buffer->commit_page)); + RB_WARN_ON(cpu_buffer, + local_read(&cpu_buffer->commit_page->page->commit) & + ~RB_WRITE_MASK); barrier(); } @@ -1085,7 +1508,7 @@ static void rb_inc_iter(struct ring_buffer_iter *iter) * to the head page instead of next. */ if (iter->head_page == cpu_buffer->reader_page) - iter->head_page = cpu_buffer->head_page; + iter->head_page = rb_set_head_page(cpu_buffer); else rb_inc_page(cpu_buffer, &iter->head_page); @@ -1129,6 +1552,163 @@ rb_update_event(struct ring_buffer_event *event, } } +/* + * rb_handle_head_page - writer hit the head page + * + * Returns: +1 to retry page + * 0 to continue + * -1 on error + */ +static int +rb_handle_head_page(struct ring_buffer_per_cpu *cpu_buffer, + struct buffer_page *tail_page, + struct buffer_page *next_page) +{ + struct buffer_page *new_head; + int entries; + int type; + int ret; + + entries = rb_page_entries(next_page); + + /* + * The hard part is here. We need to move the head + * forward, and protect against both readers on + * other CPUs and writers coming in via interrupts. + */ + type = rb_head_page_set_update(cpu_buffer, next_page, tail_page, + RB_PAGE_HEAD); + + /* + * type can be one of four: + * NORMAL - an interrupt already moved it for us + * HEAD - we are the first to get here. + * UPDATE - we are the interrupt interrupting + * a current move. + * MOVED - a reader on another CPU moved the next + * pointer to its reader page. Give up + * and try again. + */ + + switch (type) { + case RB_PAGE_HEAD: + /* + * We changed the head to UPDATE, thus + * it is our responsibility to update + * the counters. + */ + local_add(entries, &cpu_buffer->overrun); + + /* + * The entries will be zeroed out when we move the + * tail page. + */ + + /* still more to do */ + break; + + case RB_PAGE_UPDATE: + /* + * This is an interrupt that interrupt the + * previous update. Still more to do. + */ + break; + case RB_PAGE_NORMAL: + /* + * An interrupt came in before the update + * and processed this for us. + * Nothing left to do. + */ + return 1; + case RB_PAGE_MOVED: + /* + * The reader is on another CPU and just did + * a swap with our next_page. + * Try again. + */ + return 1; + default: + RB_WARN_ON(cpu_buffer, 1); /* WTF??? */ + return -1; + } + + /* + * Now that we are here, the old head pointer is + * set to UPDATE. This will keep the reader from + * swapping the head page with the reader page. + * The reader (on another CPU) will spin till + * we are finished. + * + * We just need to protect against interrupts + * doing the job. We will set the next pointer + * to HEAD. After that, we set the old pointer + * to NORMAL, but only if it was HEAD before. + * otherwise we are an interrupt, and only + * want the outer most commit to reset it. + */ + new_head = next_page; + rb_inc_page(cpu_buffer, &new_head); + + ret = rb_head_page_set_head(cpu_buffer, new_head, next_page, + RB_PAGE_NORMAL); + + /* + * Valid returns are: + * HEAD - an interrupt came in and already set it. + * NORMAL - One of two things: + * 1) We really set it. + * 2) A bunch of interrupts came in and moved + * the page forward again. + */ + switch (ret) { + case RB_PAGE_HEAD: + case RB_PAGE_NORMAL: + /* OK */ + break; + default: + RB_WARN_ON(cpu_buffer, 1); + return -1; + } + + /* + * It is possible that an interrupt came in, + * set the head up, then more interrupts came in + * and moved it again. When we get back here, + * the page would have been set to NORMAL but we + * just set it back to HEAD. + * + * How do you detect this? Well, if that happened + * the tail page would have moved. + */ + if (ret == RB_PAGE_NORMAL) { + /* + * If the tail had moved passed next, then we need + * to reset the pointer. + */ + if (cpu_buffer->tail_page != tail_page && + cpu_buffer->tail_page != next_page) + rb_head_page_set_normal(cpu_buffer, new_head, + next_page, + RB_PAGE_HEAD); + } + + /* + * If this was the outer most commit (the one that + * changed the original pointer from HEAD to UPDATE), + * then it is up to us to reset it to NORMAL. + */ + if (type == RB_PAGE_HEAD) { + ret = rb_head_page_set_normal(cpu_buffer, next_page, + tail_page, + RB_PAGE_UPDATE); + if (RB_WARN_ON(cpu_buffer, + ret != RB_PAGE_UPDATE)) + return -1; + } + + return 0; +} + static unsigned rb_calculate_event_length(unsigned length) { struct ring_buffer_event event; /* Used only for sizeof array */ @@ -1207,96 +1787,93 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, struct buffer_page *commit_page, struct buffer_page *tail_page, u64 *ts) { - struct buffer_page *next_page, *head_page, *reader_page; struct ring_buffer *buffer = cpu_buffer->buffer; - bool lock_taken = false; - unsigned long flags; + struct buffer_page *next_page; + int ret; next_page = tail_page; - local_irq_save(flags); - /* - * Since the write to the buffer is still not - * fully lockless, we must be careful with NMIs. - * The locks in the writers are taken when a write - * crosses to a new page. The locks protect against - * races with the readers (this will soon be fixed - * with a lockless solution). - * - * Because we can not protect against NMIs, and we - * want to keep traces reentrant, we need to manage - * what happens when we are in an NMI. - * - * NMIs can happen after we take the lock. - * If we are in an NMI, only take the lock - * if it is not already taken. Otherwise - * simply fail. - */ - if (unlikely(in_nmi())) { - if (!__raw_spin_trylock(&cpu_buffer->lock)) { - cpu_buffer->nmi_dropped++; - goto out_reset; - } - } else - __raw_spin_lock(&cpu_buffer->lock); - - lock_taken = true; - rb_inc_page(cpu_buffer, &next_page); - head_page = cpu_buffer->head_page; - reader_page = cpu_buffer->reader_page; - - /* we grabbed the lock before incrementing */ - if (RB_WARN_ON(cpu_buffer, next_page == reader_page)) - goto out_reset; - /* * If for some reason, we had an interrupt storm that made * it all the way around the buffer, bail, and warn * about it. */ if (unlikely(next_page == commit_page)) { - cpu_buffer->commit_overrun++; + local_inc(&cpu_buffer->commit_overrun); goto out_reset; } - if (next_page == head_page) { - if (!(buffer->flags & RB_FL_OVERWRITE)) - goto out_reset; - - /* tail_page has not moved yet? */ - if (tail_page == cpu_buffer->tail_page) { - /* count overflows */ - cpu_buffer->overrun += - local_read(&head_page->entries); + /* + * This is where the fun begins! + * + * We are fighting against races between a reader that + * could be on another CPU trying to swap its reader + * page with the buffer head. + * + * We are also fighting against interrupts coming in and + * moving the head or tail on us as well. + * + * If the next page is the head page then we have filled + * the buffer, unless the commit page is still on the + * reader page. + */ + if (rb_is_head_page(cpu_buffer, next_page, &tail_page->list)) { - rb_inc_page(cpu_buffer, &head_page); - cpu_buffer->head_page = head_page; - cpu_buffer->head_page->read = 0; + /* + * If the commit is not on the reader page, then + * move the header page. + */ + if (!rb_is_reader_page(cpu_buffer->commit_page)) { + /* + * If we are not in overwrite mode, + * this is easy, just stop here. + */ + if (!(buffer->flags & RB_FL_OVERWRITE)) + goto out_reset; + + ret = rb_handle_head_page(cpu_buffer, + tail_page, + next_page); + if (ret < 0) + goto out_reset; + if (ret) + goto out_again; + } else { + /* + * We need to be careful here too. The + * commit page could still be on the reader + * page. We could have a small buffer, and + * have filled up the buffer with events + * from interrupts and such, and wrapped. + * + * Note, if the tail page is also the on the + * reader_page, we let it move out. + */ + if (unlikely((cpu_buffer->commit_page != + cpu_buffer->tail_page) && + (cpu_buffer->commit_page == + cpu_buffer->reader_page))) { + local_inc(&cpu_buffer->commit_overrun); + goto out_reset; + } } } - /* - * If the tail page is still the same as what we think - * it is, then it is up to us to update the tail - * pointer. - */ - if (tail_page == cpu_buffer->tail_page) { - local_set(&next_page->write, 0); - local_set(&next_page->entries, 0); - local_set(&next_page->page->commit, 0); - cpu_buffer->tail_page = next_page; - - /* reread the time stamp */ + ret = rb_tail_page_update(cpu_buffer, tail_page, next_page); + if (ret) { + /* + * Nested commits always have zero deltas, so + * just reread the time stamp + */ *ts = rb_time_stamp(buffer, cpu_buffer->cpu); - cpu_buffer->tail_page->page->time_stamp = *ts; + next_page->page->time_stamp = *ts; } - rb_reset_tail(cpu_buffer, tail_page, tail, length); + out_again: - __raw_spin_unlock(&cpu_buffer->lock); - local_irq_restore(flags); + rb_reset_tail(cpu_buffer, tail_page, tail, length); /* fail and let the caller try again */ return ERR_PTR(-EAGAIN); @@ -1305,9 +1882,6 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, /* reset write */ rb_reset_tail(cpu_buffer, tail_page, tail, length); - if (likely(lock_taken)) - __raw_spin_unlock(&cpu_buffer->lock); - local_irq_restore(flags); return NULL; } @@ -1324,6 +1898,9 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, barrier(); tail_page = cpu_buffer->tail_page; write = local_add_return(length, &tail_page->write); + + /* set write to only the index of the write */ + write &= RB_WRITE_MASK; tail = write - length; /* See if we shot pass the end of this buffer page */ @@ -1368,12 +1945,16 @@ rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer, bpage = cpu_buffer->tail_page; if (bpage->page == (void *)addr && rb_page_write(bpage) == old_index) { + unsigned long write_mask = + local_read(&bpage->write) & ~RB_WRITE_MASK; /* * This is on the tail page. It is possible that * a write could come in and move the tail page * and write to the next page. That is fine * because we just shorten what is on this page. */ + old_index += write_mask; + new_index += write_mask; index = local_cmpxchg(&bpage->write, old_index, new_index); if (index == old_index) return 1; @@ -1882,9 +2463,13 @@ EXPORT_SYMBOL_GPL(ring_buffer_write); static int rb_per_cpu_empty(struct ring_buffer_per_cpu *cpu_buffer) { struct buffer_page *reader = cpu_buffer->reader_page; - struct buffer_page *head = cpu_buffer->head_page; + struct buffer_page *head = rb_set_head_page(cpu_buffer); struct buffer_page *commit = cpu_buffer->commit_page; + /* In case of error, head will be NULL */ + if (unlikely(!head)) + return 1; + return reader->read == rb_page_commit(reader) && (commit == reader || (commit == head && @@ -1975,7 +2560,7 @@ unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu) return 0; cpu_buffer = buffer->buffers[cpu]; - ret = (local_read(&cpu_buffer->entries) - cpu_buffer->overrun) + ret = (local_read(&cpu_buffer->entries) - local_read(&cpu_buffer->overrun)) - cpu_buffer->read; return ret; @@ -1996,33 +2581,13 @@ unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu) return 0; cpu_buffer = buffer->buffers[cpu]; - ret = cpu_buffer->overrun; + ret = local_read(&cpu_buffer->overrun); return ret; } EXPORT_SYMBOL_GPL(ring_buffer_overrun_cpu); /** - * ring_buffer_nmi_dropped_cpu - get the number of nmis that were dropped - * @buffer: The ring buffer - * @cpu: The per CPU buffer to get the number of overruns from - */ -unsigned long ring_buffer_nmi_dropped_cpu(struct ring_buffer *buffer, int cpu) -{ - struct ring_buffer_per_cpu *cpu_buffer; - unsigned long ret; - - if (!cpumask_test_cpu(cpu, buffer->cpumask)) - return 0; - - cpu_buffer = buffer->buffers[cpu]; - ret = cpu_buffer->nmi_dropped; - - return ret; -} -EXPORT_SYMBOL_GPL(ring_buffer_nmi_dropped_cpu); - -/** * ring_buffer_commit_overrun_cpu - get the number of overruns caused by commits * @buffer: The ring buffer * @cpu: The per CPU buffer to get the number of overruns from @@ -2037,7 +2602,7 @@ ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu) return 0; cpu_buffer = buffer->buffers[cpu]; - ret = cpu_buffer->commit_overrun; + ret = local_read(&cpu_buffer->commit_overrun); return ret; } @@ -2060,7 +2625,7 @@ unsigned long ring_buffer_entries(struct ring_buffer *buffer) for_each_buffer_cpu(buffer, cpu) { cpu_buffer = buffer->buffers[cpu]; entries += (local_read(&cpu_buffer->entries) - - cpu_buffer->overrun) - cpu_buffer->read; + local_read(&cpu_buffer->overrun)) - cpu_buffer->read; } return entries; @@ -2083,7 +2648,7 @@ unsigned long ring_buffer_overruns(struct ring_buffer *buffer) /* if you care about this being correct, lock the buffer */ for_each_buffer_cpu(buffer, cpu) { cpu_buffer = buffer->buffers[cpu]; - overruns += cpu_buffer->overrun; + overruns += local_read(&cpu_buffer->overrun); } return overruns; @@ -2096,8 +2661,10 @@ static void rb_iter_reset(struct ring_buffer_iter *iter) /* Iterator usage is expected to have record disabled */ if (list_empty(&cpu_buffer->reader_page->list)) { - iter->head_page = cpu_buffer->head_page; - iter->head = cpu_buffer->head_page->read; + iter->head_page = rb_set_head_page(cpu_buffer); + if (unlikely(!iter->head_page)) + return; + iter->head = iter->head_page->read; } else { iter->head_page = cpu_buffer->reader_page; iter->head = cpu_buffer->reader_page->read; @@ -2214,6 +2781,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) struct buffer_page *reader = NULL; unsigned long flags; int nr_loops = 0; + int ret; local_irq_save(flags); __raw_spin_lock(&cpu_buffer->lock); @@ -2247,11 +2815,17 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) goto out; /* - * Splice the empty reader page into the list around the head. * Reset the reader page to size zero. */ + local_set(&cpu_buffer->reader_page->write, 0); + local_set(&cpu_buffer->reader_page->entries, 0); + local_set(&cpu_buffer->reader_page->page->commit, 0); - reader = cpu_buffer->head_page; + spin: + /* + * Splice the empty reader page into the list around the head. + */ + reader = rb_set_head_page(cpu_buffer); cpu_buffer->reader_page->list.next = reader->list.next; cpu_buffer->reader_page->list.prev = reader->list.prev; @@ -2262,22 +2836,35 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) */ cpu_buffer->pages = reader->list.prev; - local_set(&cpu_buffer->reader_page->write, 0); - local_set(&cpu_buffer->reader_page->entries, 0); - local_set(&cpu_buffer->reader_page->page->commit, 0); + /* The reader page will be pointing to the new head */ + rb_set_list_to_head(cpu_buffer, &cpu_buffer->reader_page->list); - /* Make the reader page now replace the head */ - reader->list.prev->next = &cpu_buffer->reader_page->list; - reader->list.next->prev = &cpu_buffer->reader_page->list; + /* + * Here's the tricky part. + * + * We need to move the pointer past the header page. + * But we can only do that if a writer is not currently + * moving it. The page before the header page has the + * flag bit '1' set if it is pointing to the page we want. + * but if the writer is in the process of moving it + * than it will be '2' or already moved '0'. + */ + + ret = rb_head_page_replace(reader, cpu_buffer->reader_page); /* - * If the tail is on the reader, then we must set the head - * to the inserted page, otherwise we set it one before. + * If we did not convert it, then we must try again. */ - cpu_buffer->head_page = cpu_buffer->reader_page; + if (!ret) + goto spin; - if (cpu_buffer->commit_page != reader) - rb_inc_page(cpu_buffer, &cpu_buffer->head_page); + /* + * Yeah! We succeeded in replacing the page. + * + * Now make the new head point back to the reader page. + */ + reader->list.next->prev = &cpu_buffer->reader_page->list; + rb_inc_page(cpu_buffer, &cpu_buffer->head_page); /* Finally update the reader page to the new head */ cpu_buffer->reader_page = reader; @@ -2733,6 +3320,8 @@ EXPORT_SYMBOL_GPL(ring_buffer_size); static void rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer) { + rb_head_page_deactivate(cpu_buffer); + cpu_buffer->head_page = list_entry(cpu_buffer->pages, struct buffer_page, list); local_set(&cpu_buffer->head_page->write, 0); @@ -2750,16 +3339,17 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer) local_set(&cpu_buffer->reader_page->page->commit, 0); cpu_buffer->reader_page->read = 0; - cpu_buffer->nmi_dropped = 0; - cpu_buffer->commit_overrun = 0; - cpu_buffer->overrun = 0; - cpu_buffer->read = 0; + local_set(&cpu_buffer->commit_overrun, 0); + local_set(&cpu_buffer->overrun, 0); local_set(&cpu_buffer->entries, 0); local_set(&cpu_buffer->committing, 0); local_set(&cpu_buffer->commits, 0); + cpu_buffer->read = 0; cpu_buffer->write_stamp = 0; cpu_buffer->read_stamp = 0; + + rb_head_page_activate(cpu_buffer); } /** @@ -3107,7 +3697,7 @@ int ring_buffer_read_page(struct ring_buffer *buffer, read = 0; } else { /* update the entry counter */ - cpu_buffer->read += local_read(&reader->entries); + cpu_buffer->read += rb_page_entries(reader); /* swap the pages */ rb_init_page(bpage); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index bdb3afc..b591f7a 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3630,9 +3630,6 @@ tracing_stats_read(struct file *filp, char __user *ubuf, cnt = ring_buffer_commit_overrun_cpu(tr->buffer, cpu); trace_seq_printf(s, "commit overrun: %ld\n", cnt); - cnt = ring_buffer_nmi_dropped_cpu(tr->buffer, cpu); - trace_seq_printf(s, "nmi dropped: %ld\n", cnt); - count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len); kfree(s); -- cgit v0.10.2 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 diff --git a/Documentation/trace/ring-buffer-design.txt b/Documentation/trace/ring-buffer-design.txt new file mode 100644 index 0000000..5b1d23d --- /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 v0.10.2 From 50f238fdf38e37f0350be17c36e3ec0fd298cc40 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 7 Jul 2009 08:38:42 +0000 Subject: ucc_geth: Add support for skb recycling We can reclaim transmitted skbs to use in the receive path, so-called skb recycling support. Also reorder ucc_geth_poll() steps, so that we'll clean tx ring firstly, thus maybe reclaim some skbs for rx. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 5ba9586..ca476a5 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -209,9 +209,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, { struct sk_buff *skb = NULL; - skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length + - UCC_GETH_RX_DATA_BUF_ALIGNMENT); - + skb = __skb_dequeue(&ugeth->rx_recycle); + if (!skb) + skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT); if (skb == NULL) return NULL; @@ -1986,6 +1987,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) iounmap(ugeth->ug_regs); ugeth->ug_regs = NULL; } + + skb_queue_purge(&ugeth->rx_recycle); } static void ucc_geth_set_multi(struct net_device *dev) @@ -2202,6 +2205,8 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) return -ENOMEM; } + skb_queue_head_init(&ugeth->rx_recycle); + return 0; } @@ -3208,8 +3213,10 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit if (netif_msg_rx_err(ugeth)) ugeth_err("%s, %d: ERROR!!! skb - 0x%08x", __func__, __LINE__, (u32) skb); - if (skb) - dev_kfree_skb_any(skb); + if (skb) { + skb->data = skb->head + NET_SKB_PAD; + __skb_queue_head(&ugeth->rx_recycle, skb); + } ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL; dev->stats.rx_dropped++; @@ -3267,6 +3274,8 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) /* Normal processing. */ while ((bd_status & T_R) == 0) { + struct sk_buff *skb; + /* BD contains already transmitted buffer. */ /* Handle the transmitted buffer and release */ /* the BD to be used with the current frame */ @@ -3276,9 +3285,16 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) dev->stats.tx_packets++; - /* Free the sk buffer associated with this TxBD */ - dev_kfree_skb(ugeth-> - tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]); + skb = ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]; + + if (skb_queue_len(&ugeth->rx_recycle) < RX_BD_RING_LEN && + skb_recycle_check(skb, + ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT)) + __skb_queue_head(&ugeth->rx_recycle, skb); + else + dev_kfree_skb(skb); + ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL; ugeth->skb_dirtytx[txQ] = (ugeth->skb_dirtytx[txQ] + @@ -3307,16 +3323,16 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget) ug_info = ugeth->ug_info; - howmany = 0; - for (i = 0; i < ug_info->numQueuesRx; i++) - howmany += ucc_geth_rx(ugeth, i, budget - howmany); - /* Tx event processing */ spin_lock(&ugeth->lock); for (i = 0; i < ug_info->numQueuesTx; i++) ucc_geth_tx(ugeth->ndev, i); spin_unlock(&ugeth->lock); + howmany = 0; + for (i = 0; i < ug_info->numQueuesRx; i++) + howmany += ucc_geth_rx(ugeth, i, budget - howmany); + if (howmany < budget) { napi_complete(napi); setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS); diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 195ab26..cfb31af 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1212,6 +1212,8 @@ struct ucc_geth_private { /* index of the first skb which hasn't been transmitted yet. */ u16 skb_dirtytx[NUM_TX_QUEUES]; + struct sk_buff_head rx_recycle; + struct ugeth_mii_info *mii_info; struct phy_device *phydev; phy_interface_t phy_interface; -- cgit v0.10.2 From 460deefae62db4472e8bd16b21c7d70f3c7fd785 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Tue, 7 Jul 2009 08:11:33 +0000 Subject: tun: Remove a dead line of code Remove an unnecessary assignment. Signed-off-by: Paul Moore Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index c3927b4..92ffd11 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -995,7 +995,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) goto err_free_sk; } - err = -EINVAL; err = register_netdevice(tun->dev); if (err < 0) goto err_free_sk; -- cgit v0.10.2 From 09bb9aa0ed22bea814b0f137390f911af33ddd1b Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Wed, 1 Jul 2009 01:29:36 +0000 Subject: MIPS: BCM63XX: Add integrated ethernet PHY support for phylib. Signed-off-by: Maxime Bizon Signed-off-by: Ralf Baechle drivers/net/phy/Kconfig | 6 ++ drivers/net/phy/Makefile | 1 drivers/net/phy/bcm63xx.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 drivers/net/phy/bcm63xx.c Signed-off-by: David S. Miller diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index de9cf51..d5d8e1c 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -56,6 +56,12 @@ config BROADCOM_PHY Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481 and BCM5482 PHYs. +config BCM63XX_PHY + tristate "Drivers for Broadcom 63xx SOCs internal PHY" + depends on BCM63XX + ---help--- + Currently supports the 6348 and 6358 PHYs. + config ICPLUS_PHY tristate "Drivers for ICPlus PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 3a1bfef..edfaac4 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_SMSC_PHY) += smsc.o obj-$(CONFIG_VITESSE_PHY) += vitesse.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o +obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c new file mode 100644 index 0000000..4fed95e --- /dev/null +++ b/drivers/net/phy/bcm63xx.c @@ -0,0 +1,132 @@ +/* + * Driver for Broadcom 63xx SOCs integrated PHYs + * + * 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 +#include + +#define MII_BCM63XX_IR 0x1a /* interrupt register */ +#define MII_BCM63XX_IR_EN 0x4000 /* global interrupt enable */ +#define MII_BCM63XX_IR_DUPLEX 0x0800 /* duplex changed */ +#define MII_BCM63XX_IR_SPEED 0x0400 /* speed changed */ +#define MII_BCM63XX_IR_LINK 0x0200 /* link changed */ +#define MII_BCM63XX_IR_GMASK 0x0100 /* global interrupt mask */ + +MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver"); +MODULE_AUTHOR("Maxime Bizon "); +MODULE_LICENSE("GPL"); + +static int bcm63xx_config_init(struct phy_device *phydev) +{ + int reg, err; + + reg = phy_read(phydev, MII_BCM63XX_IR); + if (reg < 0) + return reg; + + /* Mask interrupts globally. */ + reg |= MII_BCM63XX_IR_GMASK; + err = phy_write(phydev, MII_BCM63XX_IR, reg); + if (err < 0) + return err; + + /* Unmask events we are interested in */ + reg = ~(MII_BCM63XX_IR_DUPLEX | + MII_BCM63XX_IR_SPEED | + MII_BCM63XX_IR_LINK) | + MII_BCM63XX_IR_EN; + err = phy_write(phydev, MII_BCM63XX_IR, reg); + if (err < 0) + return err; + return 0; +} + +static int bcm63xx_ack_interrupt(struct phy_device *phydev) +{ + int reg; + + /* Clear pending interrupts. */ + reg = phy_read(phydev, MII_BCM63XX_IR); + if (reg < 0) + return reg; + + return 0; +} + +static int bcm63xx_config_intr(struct phy_device *phydev) +{ + int reg, err; + + reg = phy_read(phydev, MII_BCM63XX_IR); + if (reg < 0) + return reg; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + reg &= ~MII_BCM63XX_IR_GMASK; + else + reg |= MII_BCM63XX_IR_GMASK; + + err = phy_write(phydev, MII_BCM63XX_IR, reg); + return err; +} + +static struct phy_driver bcm63xx_1_driver = { + .phy_id = 0x00406000, + .phy_id_mask = 0xfffffc00, + .name = "Broadcom BCM63XX (1)", + /* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */ + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), + .flags = PHY_HAS_INTERRUPT, + .config_init = bcm63xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm63xx_ack_interrupt, + .config_intr = bcm63xx_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + +/* same phy as above, with just a different OUI */ +static struct phy_driver bcm63xx_2_driver = { + .phy_id = 0x002bdc00, + .phy_id_mask = 0xfffffc00, + .name = "Broadcom BCM63XX (2)", + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), + .flags = PHY_HAS_INTERRUPT, + .config_init = bcm63xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm63xx_ack_interrupt, + .config_intr = bcm63xx_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + +static int __init bcm63xx_phy_init(void) +{ + int ret; + + ret = phy_driver_register(&bcm63xx_1_driver); + if (ret) + goto out_63xx_1; + ret = phy_driver_register(&bcm63xx_2_driver); + if (ret) + goto out_63xx_2; + return ret; + +out_63xx_2: + phy_driver_unregister(&bcm63xx_1_driver); +out_63xx_1: + return ret; +} + +static void __exit bcm63xx_phy_exit(void) +{ + phy_driver_unregister(&bcm63xx_1_driver); + phy_driver_unregister(&bcm63xx_2_driver); +} + +module_init(bcm63xx_phy_init); +module_exit(bcm63xx_phy_exit); -- cgit v0.10.2 From 277a57c710ff73af1213f5d4b42bf6458c1ebca3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Jul 2009 12:42:08 +0200 Subject: ALSA: hda - Fix compile warnings in patch_cirrus.c Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 54a7dc8..57251d7 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -110,7 +110,7 @@ enum { /* 0x0015 - visibility reg */ -static int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) +static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) { snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, AC_VERB_SET_COEF_INDEX, idx); @@ -118,8 +118,8 @@ static int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) AC_VERB_GET_PROC_COEF, 0); } -static void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, - unsigned int coef) +static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, + unsigned int coef) { snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, AC_VERB_SET_COEF_INDEX, idx); @@ -367,7 +367,6 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, static int is_active_pin(struct hda_codec *codec, hda_nid_t nid) { - struct cs_spec *spec = codec->spec; unsigned int val; val = snd_hda_codec_get_pincfg(codec, nid); return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); @@ -377,7 +376,7 @@ static int parse_output(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err, extra_nids; + int i, extra_nids; hda_nid_t dac; for (i = 0; i < cfg->line_outs; i++) { @@ -422,11 +421,10 @@ static int parse_input(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i, n, err; + int i; for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t pin = cfg->input_pins[i]; - struct snd_kcontrol *kctl; if (!pin) continue; spec->input_idx[spec->num_inputs] = i; @@ -461,7 +459,6 @@ static int parse_digital_output(struct hda_codec *codec) struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t nid; - int err; if (!cfg->dig_outs) return 0; @@ -651,7 +648,6 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx, int force) { struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; if (spec->cur_input == idx && !force) return 0; @@ -1003,7 +999,6 @@ static int cs_init(struct hda_codec *codec) static int cs_build_controls(struct hda_codec *codec) { - struct cs_spec *spec = codec->spec; int err; err = build_output(codec); -- cgit v0.10.2 From 2e4fddd8e420e8f531a34e7a97f9cdb851a6ad13 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 7 Jul 2009 15:17:12 +0800 Subject: crypto: shash - Add shash_instance This patch adds shash_instance and the associated alloc/free functions. This is meant to be an instance that with a shash algorithm under it. Note that the instance itself doesn't have to be shash. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 2ccc8b0..8f9d883 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -502,5 +502,12 @@ int crypto_unregister_shash(struct shash_alg *alg) } EXPORT_SYMBOL_GPL(crypto_unregister_shash); +void shash_free_instance(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(shash_instance(inst)); +} +EXPORT_SYMBOL_GPL(shash_free_instance); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Synchronous cryptographic hash type"); diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 82b7056..44d3bcd 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -34,6 +34,10 @@ struct crypto_hash_walk { unsigned int flags; }; +struct shash_instance { + struct shash_alg alg; +}; + extern const struct crypto_type crypto_ahash_type; int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err); @@ -46,6 +50,8 @@ int crypto_hash_walk_first_compat(struct hash_desc *hdesc, int crypto_register_shash(struct shash_alg *alg); int crypto_unregister_shash(struct shash_alg *alg); +void shash_free_instance(struct crypto_instance *inst); + static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm) { return crypto_tfm_ctx(&tfm->base); @@ -80,5 +86,25 @@ static inline void *crypto_shash_ctx(struct crypto_shash *tfm) return crypto_tfm_ctx(&tfm->base); } +static inline struct crypto_instance *shash_crypto_instance( + struct shash_instance *inst) +{ + return container_of(&inst->alg.base, struct crypto_instance, alg); +} + +static inline struct shash_instance *shash_instance( + struct crypto_instance *inst) +{ + return container_of(__crypto_shash_alg(&inst->alg), + struct shash_instance, alg); +} + +static inline struct shash_instance *shash_alloc_instance( + const char *name, struct crypto_alg *alg) +{ + return crypto_alloc_instance2(name, alg, + sizeof(struct shash_alg) - sizeof(*alg)); +} + #endif /* _CRYPTO_INTERNAL_HASH_H */ -- cgit v0.10.2 From 97eedce1a64a57648ac5e39f03825528c47ba72e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 8 Jul 2009 15:55:52 +0800 Subject: crypto: api - Add new style spawn support This patch modifies the spawn infrastructure to support new style algorithms like shash. In particular, this means storing the frontend type in the spawn and using crypto_create_tfm to allocate the tfm. Signed-off-by: Herbert Xu diff --git a/crypto/algapi.c b/crypto/algapi.c index 429f1a0..17a5fff 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -488,6 +488,23 @@ int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg, } EXPORT_SYMBOL_GPL(crypto_init_spawn); +int crypto_init_spawn2(struct crypto_spawn *spawn, struct crypto_alg *alg, + struct crypto_instance *inst, + const struct crypto_type *frontend) +{ + int err = -EINVAL; + + if (frontend && (alg->cra_flags ^ frontend->type) & frontend->maskset) + goto out; + + spawn->frontend = frontend; + err = crypto_init_spawn(spawn, alg, inst, frontend->maskset); + +out: + return err; +} +EXPORT_SYMBOL_GPL(crypto_init_spawn2); + void crypto_drop_spawn(struct crypto_spawn *spawn) { down_write(&crypto_alg_sem); @@ -496,12 +513,10 @@ void crypto_drop_spawn(struct crypto_spawn *spawn) } EXPORT_SYMBOL_GPL(crypto_drop_spawn); -struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, - u32 mask) +static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn) { struct crypto_alg *alg; struct crypto_alg *alg2; - struct crypto_tfm *tfm; down_read(&crypto_alg_sem); alg = spawn->alg; @@ -516,6 +531,19 @@ struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, return ERR_PTR(-EAGAIN); } + return alg; +} + +struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, + u32 mask) +{ + struct crypto_alg *alg; + struct crypto_tfm *tfm; + + alg = crypto_spawn_alg(spawn); + if (IS_ERR(alg)) + return ERR_CAST(alg); + tfm = ERR_PTR(-EINVAL); if (unlikely((alg->cra_flags ^ type) & mask)) goto out_put_alg; @@ -532,6 +560,27 @@ out_put_alg: } EXPORT_SYMBOL_GPL(crypto_spawn_tfm); +void *crypto_spawn_tfm2(struct crypto_spawn *spawn) +{ + struct crypto_alg *alg; + struct crypto_tfm *tfm; + + alg = crypto_spawn_alg(spawn); + if (IS_ERR(alg)) + return ERR_CAST(alg); + + tfm = crypto_create_tfm(alg, spawn->frontend); + if (IS_ERR(tfm)) + goto out_put_alg; + + return tfm; + +out_put_alg: + crypto_mod_put(alg); + return tfm; +} +EXPORT_SYMBOL_GPL(crypto_spawn_tfm2); + int crypto_register_notifier(struct notifier_block *nb) { return blocking_notifier_chain_register(&crypto_chain, nb); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 99bb297..c9bff92 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -61,6 +61,7 @@ struct crypto_spawn { struct list_head list; struct crypto_alg *alg; struct crypto_instance *inst; + const struct crypto_type *frontend; u32 mask; }; @@ -117,9 +118,14 @@ struct crypto_template *crypto_lookup_template(const char *name); int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg, struct crypto_instance *inst, u32 mask); +int crypto_init_spawn2(struct crypto_spawn *spawn, struct crypto_alg *alg, + struct crypto_instance *inst, + const struct crypto_type *frontend); + void crypto_drop_spawn(struct crypto_spawn *spawn); struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, u32 mask); +void *crypto_spawn_tfm2(struct crypto_spawn *spawn); static inline void crypto_set_spawn(struct crypto_spawn *spawn, struct crypto_instance *inst) -- cgit v0.10.2 From 942969992d86330c9700e2cd9afe8a6bea42df78 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 8 Jul 2009 17:21:37 +0800 Subject: crypto: shash - Add spawn support This patch adds the functions needed to create and use shash spawns, i.e., to use shash algorithms in a template. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 8f9d883..97f6c8b 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -509,5 +509,14 @@ void shash_free_instance(struct crypto_instance *inst) } EXPORT_SYMBOL_GPL(shash_free_instance); +int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn, + struct shash_alg *alg, + struct crypto_instance *inst) +{ + return crypto_init_spawn2(&spawn->base, &alg->base, inst, + &crypto_shash_type); +} +EXPORT_SYMBOL_GPL(crypto_init_shash_spawn); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Synchronous cryptographic hash type"); diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 44d3bcd..6cc824b 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -38,6 +38,10 @@ struct shash_instance { struct shash_alg alg; }; +struct crypto_shash_spawn { + struct crypto_spawn base; +}; + extern const struct crypto_type crypto_ahash_type; int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err); @@ -52,6 +56,10 @@ int crypto_unregister_shash(struct shash_alg *alg); void shash_free_instance(struct crypto_instance *inst); +int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn, + struct shash_alg *alg, + struct crypto_instance *inst); + static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm) { return crypto_tfm_ctx(&tfm->base); @@ -106,5 +114,11 @@ static inline struct shash_instance *shash_alloc_instance( sizeof(struct shash_alg) - sizeof(*alg)); } +static inline struct crypto_shash *crypto_spawn_shash( + struct crypto_shash_spawn *spawn) +{ + return crypto_spawn_tfm2(&spawn->base); +} + #endif /* _CRYPTO_INTERNAL_HASH_H */ -- cgit v0.10.2 From d06854f0243d91badabaab14503f7f3bb770061d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 8 Jul 2009 17:53:16 +0800 Subject: crypto: api - Add crypto_attr_alg2 helper This patch adds the helper crypto_attr_alg2 which is similar to crypto_attr_alg but takes an extra frontend argument. This is intended to be used by new style algorithm types such as shash. Signed-off-by: Herbert Xu diff --git a/crypto/algapi.c b/crypto/algapi.c index 17a5fff..2154815 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -644,7 +644,9 @@ const char *crypto_attr_alg_name(struct rtattr *rta) } EXPORT_SYMBOL_GPL(crypto_attr_alg_name); -struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask) +struct crypto_alg *crypto_attr_alg2(struct rtattr *rta, + const struct crypto_type *frontend, + u32 type, u32 mask) { const char *name; int err; @@ -654,9 +656,9 @@ struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask) if (IS_ERR(name)) return ERR_PTR(err); - return crypto_alg_mod_lookup(name, type, mask); + return crypto_find_alg(name, frontend, type, mask); } -EXPORT_SYMBOL_GPL(crypto_attr_alg); +EXPORT_SYMBOL_GPL(crypto_attr_alg2); int crypto_attr_u32(struct rtattr *rta, u32 *num) { diff --git a/crypto/api.c b/crypto/api.c index d5944f9..ba81221 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -503,6 +503,27 @@ out: } EXPORT_SYMBOL_GPL(crypto_create_tfm); +struct crypto_alg *crypto_find_alg(const char *alg_name, + const struct crypto_type *frontend, + u32 type, u32 mask) +{ + struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask) = + crypto_alg_mod_lookup; + + if (frontend) { + type &= frontend->maskclear; + mask &= frontend->maskclear; + type |= frontend->type; + mask |= frontend->maskset; + + if (frontend->lookup) + lookup = frontend->lookup; + } + + return lookup(alg_name, type, mask); +} +EXPORT_SYMBOL_GPL(crypto_find_alg); + /* * crypto_alloc_tfm - Locate algorithm and allocate transform * @alg_name: Name of algorithm @@ -526,21 +547,13 @@ EXPORT_SYMBOL_GPL(crypto_create_tfm); void *crypto_alloc_tfm(const char *alg_name, const struct crypto_type *frontend, u32 type, u32 mask) { - struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask); void *tfm; int err; - type &= frontend->maskclear; - mask &= frontend->maskclear; - type |= frontend->type; - mask |= frontend->maskset; - - lookup = frontend->lookup ?: crypto_alg_mod_lookup; - for (;;) { struct crypto_alg *alg; - alg = lookup(alg_name, type, mask); + alg = crypto_find_alg(alg_name, frontend, type, mask); if (IS_ERR(alg)) { err = PTR_ERR(alg); goto err; diff --git a/crypto/internal.h b/crypto/internal.h index 95baaea..7efa4d0 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -106,6 +106,9 @@ struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, u32 mask); void *crypto_create_tfm(struct crypto_alg *alg, const struct crypto_type *frontend); +struct crypto_alg *crypto_find_alg(const char *alg_name, + const struct crypto_type *frontend, + u32 type, u32 mask); void *crypto_alloc_tfm(const char *alg_name, const struct crypto_type *frontend, u32 type, u32 mask); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index c9bff92..1d15a92 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -136,7 +136,16 @@ static inline void crypto_set_spawn(struct crypto_spawn *spawn, struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb); int crypto_check_attr_type(struct rtattr **tb, u32 type); const char *crypto_attr_alg_name(struct rtattr *rta); -struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask); +struct crypto_alg *crypto_attr_alg2(struct rtattr *rta, + const struct crypto_type *frontend, + u32 type, u32 mask); + +static inline struct crypto_alg *crypto_attr_alg(struct rtattr *rta, + u32 type, u32 mask) +{ + return crypto_attr_alg2(rta, NULL, type, mask); +} + int crypto_attr_u32(struct rtattr *rta, u32 *num); void *crypto_alloc_instance2(const char *name, struct crypto_alg *alg, unsigned int head); -- cgit v0.10.2 From 7d6f56400a695af497a8b7c23ea0ff9c3d9d99f4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 8 Jul 2009 17:56:28 +0800 Subject: crypto: shash - Add shash_attr_alg2 helper This patch adds the helper shash_attr_alg2 which locates a shash algorithm based on the information in the given attribute. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 97f6c8b..21bcff6 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -518,5 +518,15 @@ int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn, } EXPORT_SYMBOL_GPL(crypto_init_shash_spawn); +struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask) +{ + struct crypto_alg *alg; + + alg = crypto_attr_alg2(rta, &crypto_shash_type, type, mask); + return IS_ERR(alg) ? ERR_CAST(alg) : + container_of(alg, struct shash_alg, base); +} +EXPORT_SYMBOL_GPL(shash_attr_alg); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Synchronous cryptographic hash type"); diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 6cc824b..e2ab35a 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -60,6 +60,8 @@ int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn, struct shash_alg *alg, struct crypto_instance *inst); +struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask); + static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm) { return crypto_tfm_ctx(&tfm->base); -- cgit v0.10.2 From 619a6ebd2547f3a8ec2fbc5245daaa1f2056eb32 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 8 Jul 2009 18:46:23 +0800 Subject: crypto: shash - Add shash_register_instance This patch adds shash_register_instance so that shash instances can be registered without bypassing the shash checks applied to normal algorithms. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 21bcff6..3d24242 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -480,7 +480,7 @@ struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type, } EXPORT_SYMBOL_GPL(crypto_alloc_shash); -int crypto_register_shash(struct shash_alg *alg) +static int shash_prepare_alg(struct shash_alg *alg) { struct crypto_alg *base = &alg->base; @@ -491,6 +491,17 @@ int crypto_register_shash(struct shash_alg *alg) base->cra_type = &crypto_shash_type; base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_SHASH; + return 0; +} + +int crypto_register_shash(struct shash_alg *alg) +{ + struct crypto_alg *base = &alg->base; + int err; + + err = shash_prepare_alg(alg); + if (err) + return err; return crypto_register_alg(base); } @@ -502,6 +513,19 @@ int crypto_unregister_shash(struct shash_alg *alg) } EXPORT_SYMBOL_GPL(crypto_unregister_shash); +int shash_register_instance(struct crypto_template *tmpl, + struct shash_instance *inst) +{ + int err; + + err = shash_prepare_alg(&inst->alg); + if (err) + return err; + + return crypto_register_instance(tmpl, shash_crypto_instance(inst)); +} +EXPORT_SYMBOL_GPL(shash_register_instance); + void shash_free_instance(struct crypto_instance *inst) { crypto_drop_spawn(crypto_instance_ctx(inst)); diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index e2ab35a..fa5c9fb 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -53,7 +53,8 @@ int crypto_hash_walk_first_compat(struct hash_desc *hdesc, int crypto_register_shash(struct shash_alg *alg); int crypto_unregister_shash(struct shash_alg *alg); - +int shash_register_instance(struct crypto_template *tmpl, + struct shash_instance *inst); void shash_free_instance(struct crypto_instance *inst); int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn, -- cgit v0.10.2 From b1e4422f96a9b4830ffd8119b05211abb830ef4a Mon Sep 17 00:00:00 2001 From: William Weston Date: Wed, 8 Jul 2009 01:10:05 -0700 Subject: ALSA: hda - Add quirks for RTL888 & RV630/M76 based MSI GX710 Signed-off-by: William Weston Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index de72b72..0227b0c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8422,6 +8422,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), @@ -8435,6 +8436,7 @@ static struct snd_pci_quirk alc882_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(0x1462, 0xaa08, "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), -- cgit v0.10.2 From cc6a8acdeee932f6911d8b236d2c7d6bcc4616f6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 Jun 2008 16:39:06 +0200 Subject: ALSA: Fix SG-buffer DMA with non-coherent architectures Using SG-buffers with dma_alloc_coherent() is often very inefficient on non-coherent architectures because a tracking record could be allocated in addition for each dma_alloc_coherent() call. Instead, simply disable SG-buffers but just allocate normal continuous buffers on non-supported (currently all but x86) architectures. Signed-off-by: Takashi Iwai diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index 7ccce94..c425062 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -47,7 +47,11 @@ struct snd_dma_device { #define SNDRV_DMA_TYPE_UNKNOWN 0 /* not defined */ #define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */ #define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */ +#ifdef CONFIG_SND_DMA_SGBUF #define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */ +#else +#define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */ +#endif /* * info for buffer allocation @@ -60,6 +64,7 @@ struct snd_dma_buffer { void *private_data; /* private for allocator; don't touch */ }; +#ifdef CONFIG_SND_DMA_SGBUF /* * Scatter-Gather generic device pages */ @@ -107,6 +112,7 @@ static inline void *snd_sgbuf_get_ptr(struct snd_sg_buf *sgbuf, size_t offset) { return sgbuf->table[offset >> PAGE_SHIFT].buf + offset % PAGE_SIZE; } +#endif /* CONFIG_SND_DMA_SGBUF */ /* allocate/release a buffer */ int snd_dma_alloc_pages(int type, struct device *dev, size_t size, diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 2389352..1691c7f 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -902,6 +902,7 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size); int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream); +#ifdef CONFIG_SND_DMA_SGBUF /* * SG-buffer handling */ @@ -927,6 +928,28 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream, unsigned int ofs, unsigned int size); +#else /* !SND_DMA_SGBUF */ +/* + * fake using a continuous buffer + */ +static inline dma_addr_t +snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs) +{ + return substream->runtime->dma_addr + ofs; +} + +static inline void * +snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs) +{ + return substream->runtime->dma_area + ofs; +} + +#define snd_pcm_sgbuf_ops_page NULL + +#define snd_pcm_sgbuf_get_chunk_size(subs, ofs, size) (size) + +#endif /* SND_DMA_SGBUF */ + /* handle mmap counter - PCM mmap callback should handle this counter properly */ static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area) { diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 6061fb5..c15682a 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -206,4 +206,8 @@ config SND_PCM_XRUN_DEBUG config SND_VMASTER bool +config SND_DMA_SGBUF + def_bool y + depends on X86 + source "sound/core/seq/Kconfig" diff --git a/sound/core/Makefile b/sound/core/Makefile index 4229052..350a08d 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -13,7 +13,7 @@ snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o snd-page-alloc-y := memalloc.o -snd-page-alloc-$(CONFIG_HAS_DMA) += sgbuf.o +snd-page-alloc-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o snd-rawmidi-objs := rawmidi.o snd-timer-objs := timer.o diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 1b3534d..9e92441 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -199,6 +199,8 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, case SNDRV_DMA_TYPE_DEV: dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); break; +#endif +#ifdef CONFIG_SND_DMA_SGBUF case SNDRV_DMA_TYPE_DEV_SG: snd_malloc_sgbuf_pages(device, size, dmab, NULL); break; @@ -269,6 +271,8 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) case SNDRV_DMA_TYPE_DEV: snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); break; +#endif +#ifdef CONFIG_SND_DMA_SGBUF case SNDRV_DMA_TYPE_DEV_SG: snd_free_sgbuf_pages(dmab); break; diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index a6d4280..caa7796 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -304,6 +304,7 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); +#ifdef CONFIG_SND_DMA_SGBUF /** * snd_pcm_sgbuf_ops_page - get the page struct at the given offset * @substream: the pcm substream instance @@ -349,6 +350,7 @@ unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream, return size; } EXPORT_SYMBOL(snd_pcm_sgbuf_get_chunk_size); +#endif /* CONFIG_SND_DMA_SGBUF */ /** * snd_pcm_lib_malloc_pages - allocate the DMA buffer -- cgit v0.10.2 From cde6263fa954dfc03ebe169aa3f7f71176d7901b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 8 Jul 2009 22:32:07 +0800 Subject: crypto: shash - Add crypto_shash_ctx_aligned This patch adds crypto_shash_ctx_aligned which will be needed by hmac after its conversion to shash. Signed-off-by: Herbert Xu diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index fa5c9fb..f104114 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -123,5 +123,10 @@ static inline struct crypto_shash *crypto_spawn_shash( return crypto_spawn_tfm2(&spawn->base); } +static inline void *crypto_shash_ctx_aligned(struct crypto_shash *tfm) +{ + return crypto_tfm_ctx_aligned(&tfm->base); +} + #endif /* _CRYPTO_INTERNAL_HASH_H */ -- cgit v0.10.2 From 0390e6aecf571ddac934e6c0644bb4038167b698 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 8 Jul 2009 22:36:36 +0800 Subject: crypto: shash - Add __crypto_shash_cast This patch adds __crypto_shash_cast which turns a crypto_tfm into crypto_shash. It's analogous to the other __crypto_*_cast functions. It hasn't been needed until now since no existing shash algorithms have had an init function. Signed-off-by: Herbert Xu diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index f104114..3af34ca 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -128,5 +128,10 @@ static inline void *crypto_shash_ctx_aligned(struct crypto_shash *tfm) return crypto_tfm_ctx_aligned(&tfm->base); } +static inline struct crypto_shash *__crypto_shash_cast(struct crypto_tfm *tfm) +{ + return (struct crypto_shash *)tfm; +} + #endif /* _CRYPTO_INTERNAL_HASH_H */ -- cgit v0.10.2 From 6e5414750af8a521c3ba7805d6ad460ba21df1a1 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Tue, 7 Jul 2009 17:36:06 -0700 Subject: ASoC: DaVinci: pcm, don't play 1st sound period twice Update the dma link with correct data as soon as the master channel has copied it. Otherwise, the 1st period will play twice. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index a059965..8fd0c3c 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -206,6 +206,7 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream) /* Copy self-linked parameter RAM entry into master channel */ edma_read_slot(prtd->slave_lch, &temp); edma_write_slot(prtd->master_lch, &temp); + davinci_pcm_enqueue_dma(substream); return 0; } -- cgit v0.10.2 From f88ad8de282a9c4afd79fb0b4b536025f24a2005 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 8 Jul 2009 23:32:08 +0800 Subject: crypto: shash - Use finup in default digest This patch simplifies the default digest function by using finup. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 3d24242..7832310 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -154,8 +154,7 @@ static int shash_digest_unaligned(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { return crypto_shash_init(desc) ?: - crypto_shash_update(desc, data, len) ?: - crypto_shash_final(desc, out); + crypto_shash_finup(desc, data, len, out); } int crypto_shash_digest(struct shash_desc *desc, const u8 *data, -- cgit v0.10.2 From deee2289b932d512035f579b8f8e178796564ba1 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 8 Jul 2009 23:39:01 +0800 Subject: crypto: shash - Propagate reinit return value This patch fixes crypto_shash_import to propagate the value returned by reinit. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 7832310..23e05a1 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -180,7 +180,7 @@ int crypto_shash_import(struct shash_desc *desc, const u8 *in) memcpy(shash_desc_ctx(desc), in, crypto_shash_descsize(tfm)); if (alg->reinit) - alg->reinit(desc); + return alg->reinit(desc); return 0; } -- cgit v0.10.2 From d00efa648d3c78ba212f08facf0defdff385dc28 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 8 Jul 2009 16:53:12 +0100 Subject: ASoC: Add TLV information for WM8731 Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index dfbc1bb..33e89a1 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "wm8731.h" @@ -113,20 +114,26 @@ static const struct soc_enum wm8731_enum[] = { SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph), }; +static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -1500, 300, 0); +static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); + static const struct snd_kcontrol_new wm8731_snd_controls[] = { -SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V, - 0, 127, 0), +SOC_DOUBLE_R_TLV("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V, + 0, 127, 0, out_tlv), SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V, 7, 1, 0), -SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0), +SOC_DOUBLE_R_TLV("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0, + in_tlv), SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1), SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0), SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1), -SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1), +SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1, + sidetone_tlv), SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1), SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0), -- cgit v0.10.2 From ef38ed888eee33af93a006db6e337d71320dfa2b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 8 Jul 2009 17:05:43 +0100 Subject: ASoC: Correct WM8731 Mic Capture Switch control name Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 33e89a1..de43263 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -130,7 +130,7 @@ SOC_DOUBLE_R_TLV("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0, SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1), SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0), -SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1), +SOC_SINGLE("Mic Capture Switch", WM8731_APANA, 1, 1, 1), SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1, sidetone_tlv), -- cgit v0.10.2 From ff7d04b130d76ab3a7b79120070346ccf3a72b3f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 8 Jul 2009 16:54:51 +0100 Subject: ASoC: DaVinci I2S needs mach/asp.h Reported-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 7c48399..f7330e1 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -22,6 +22,8 @@ #include #include +#include + #include "davinci-pcm.h" -- cgit v0.10.2 From 942c435ba79fd263a922bb114d56eccab6250662 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Jun 2009 16:32:59 +0100 Subject: ASoC: Add WM8993 CODEC driver The WM8993 is a highly integrated ultra-low power hi-fi CODEC designed for portable devices such as multimedia phones. Signed-off-by: Mark Brown diff --git a/include/sound/wm8993.h b/include/sound/wm8993.h new file mode 100644 index 0000000..9c661f2 --- /dev/null +++ b/include/sound/wm8993.h @@ -0,0 +1,44 @@ +/* + * linux/sound/wm8993.h -- Platform data for WM8993 + * + * Copyright 2009 Wolfson Microelectronics. PLC. + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_WM8993_H +#define __LINUX_SND_WM8993_H + +/* Note that EQ1 only contains the enable/disable bit so will be + ignored but is included for simplicity. + */ +struct wm8993_retune_mobile_setting { + const char *name; + unsigned int rate; + u16 config[24]; +}; + +struct wm8993_platform_data { + struct wm8993_retune_mobile_setting *retune_configs; + int num_retune_configs; + + /* LINEOUT can be differential or single ended */ + unsigned int lineout1_diff:1; + unsigned int lineout2_diff:1; + + /* Common mode feedback */ + unsigned int lineout1fb:1; + unsigned int lineout2fb:1; + + /* Microphone biases: 0=0.9*AVDD1 1=0.65*AVVD1 */ + unsigned int micbias1_lvl:1; + unsigned int micbias2_lvl:1; + + /* Jack detect threashold levels, see datasheet for values */ + unsigned int jd_scthr:2; + unsigned int jd_thr:2; +}; + +#endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 68ea5b6..b674d3a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -44,6 +44,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8971 if I2C select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8990 if I2C + select SND_SOC_WM8993 if I2C select SND_SOC_WM9081 if I2C select SND_SOC_WM9705 if SND_SOC_AC97_BUS select SND_SOC_WM9712 if SND_SOC_AC97_BUS @@ -173,6 +174,9 @@ config SND_SOC_WM8988 config SND_SOC_WM8990 tristate +config SND_SOC_WM8993 + tristate + config SND_SOC_WM9081 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 8ce28a3..301eb08 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -32,6 +32,7 @@ snd-soc-wm8961-objs := wm8961.o snd-soc-wm8971-objs := wm8971.o snd-soc-wm8988-objs := wm8988.o snd-soc-wm8990-objs := wm8990.o +snd-soc-wm8993-objs := wm8993.o snd-soc-wm9081-objs := wm9081.o snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o @@ -71,6 +72,7 @@ obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o +obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c new file mode 100644 index 0000000..3e5c65a --- /dev/null +++ b/sound/soc/codecs/wm8993.c @@ -0,0 +1,2203 @@ +/* + * wm8993.c -- WM8993 ALSA SoC audio driver + * + * Copyright 2009 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8993.h" + +static u16 wm8993_reg_defaults[WM8993_REGISTER_COUNT] = { + 0x8993, /* R0 - Software Reset */ + 0x0000, /* R1 - Power Management (1) */ + 0x6000, /* R2 - Power Management (2) */ + 0x0000, /* R3 - Power Management (3) */ + 0x4050, /* R4 - Audio Interface (1) */ + 0x4000, /* R5 - Audio Interface (2) */ + 0x01C8, /* R6 - Clocking 1 */ + 0x0000, /* R7 - Clocking 2 */ + 0x0000, /* R8 - Audio Interface (3) */ + 0x0040, /* R9 - Audio Interface (4) */ + 0x0004, /* R10 - DAC CTRL */ + 0x00C0, /* R11 - Left DAC Digital Volume */ + 0x00C0, /* R12 - Right DAC Digital Volume */ + 0x0000, /* R13 - Digital Side Tone */ + 0x0300, /* R14 - ADC CTRL */ + 0x00C0, /* R15 - Left ADC Digital Volume */ + 0x00C0, /* R16 - Right ADC Digital Volume */ + 0x0000, /* R17 */ + 0x0000, /* R18 - GPIO CTRL 1 */ + 0x0010, /* R19 - GPIO1 */ + 0x0000, /* R20 - IRQ_DEBOUNCE */ + 0x0000, /* R21 */ + 0x8000, /* R22 - GPIOCTRL 2 */ + 0x0800, /* R23 - GPIO_POL */ + 0x008B, /* R24 - Left Line Input 1&2 Volume */ + 0x008B, /* R25 - Left Line Input 3&4 Volume */ + 0x008B, /* R26 - Right Line Input 1&2 Volume */ + 0x008B, /* R27 - Right Line Input 3&4 Volume */ + 0x006D, /* R28 - Left Output Volume */ + 0x006D, /* R29 - Right Output Volume */ + 0x0066, /* R30 - Line Outputs Volume */ + 0x0020, /* R31 - HPOUT2 Volume */ + 0x0079, /* R32 - Left OPGA Volume */ + 0x0079, /* R33 - Right OPGA Volume */ + 0x0003, /* R34 - SPKMIXL Attenuation */ + 0x0003, /* R35 - SPKMIXR Attenuation */ + 0x0011, /* R36 - SPKOUT Mixers */ + 0x0100, /* R37 - SPKOUT Boost */ + 0x0079, /* R38 - Speaker Volume Left */ + 0x0079, /* R39 - Speaker Volume Right */ + 0x0000, /* R40 - Input Mixer2 */ + 0x0000, /* R41 - Input Mixer3 */ + 0x0000, /* R42 - Input Mixer4 */ + 0x0000, /* R43 - Input Mixer5 */ + 0x0000, /* R44 - Input Mixer6 */ + 0x0000, /* R45 - Output Mixer1 */ + 0x0000, /* R46 - Output Mixer2 */ + 0x0000, /* R47 - Output Mixer3 */ + 0x0000, /* R48 - Output Mixer4 */ + 0x0000, /* R49 - Output Mixer5 */ + 0x0000, /* R50 - Output Mixer6 */ + 0x0000, /* R51 - HPOUT2 Mixer */ + 0x0000, /* R52 - Line Mixer1 */ + 0x0000, /* R53 - Line Mixer2 */ + 0x0000, /* R54 - Speaker Mixer */ + 0x0000, /* R55 - Additional Control */ + 0x0000, /* R56 - AntiPOP1 */ + 0x0000, /* R57 - AntiPOP2 */ + 0x0000, /* R58 - MICBIAS */ + 0x0000, /* R59 */ + 0x0000, /* R60 - FLL Control 1 */ + 0x0000, /* R61 - FLL Control 2 */ + 0x0000, /* R62 - FLL Control 3 */ + 0x2EE0, /* R63 - FLL Control 4 */ + 0x0002, /* R64 - FLL Control 5 */ + 0x2287, /* R65 - Clocking 3 */ + 0x025F, /* R66 - Clocking 4 */ + 0x0000, /* R67 - MW Slave Control */ + 0x0000, /* R68 */ + 0x0002, /* R69 - Bus Control 1 */ + 0x0000, /* R70 - Write Sequencer 0 */ + 0x0000, /* R71 - Write Sequencer 1 */ + 0x0000, /* R72 - Write Sequencer 2 */ + 0x0000, /* R73 - Write Sequencer 3 */ + 0x0000, /* R74 - Write Sequencer 4 */ + 0x0000, /* R75 - Write Sequencer 5 */ + 0x1F25, /* R76 - Charge Pump 1 */ + 0x0000, /* R77 */ + 0x0000, /* R78 */ + 0x0000, /* R79 */ + 0x0000, /* R80 */ + 0x0000, /* R81 - Class W 0 */ + 0x0000, /* R82 */ + 0x0000, /* R83 */ + 0x0000, /* R84 - DC Servo 0 */ + 0x054A, /* R85 - DC Servo 1 */ + 0x0000, /* R86 */ + 0x0000, /* R87 - DC Servo 3 */ + 0x0000, /* R88 - DC Servo Readback 0 */ + 0x0000, /* R89 - DC Servo Readback 1 */ + 0x0000, /* R90 - DC Servo Readback 2 */ + 0x0000, /* R91 */ + 0x0000, /* R92 */ + 0x0000, /* R93 */ + 0x0000, /* R94 */ + 0x0000, /* R95 */ + 0x0100, /* R96 - Analogue HP 0 */ + 0x0000, /* R97 */ + 0x0000, /* R98 - EQ1 */ + 0x000C, /* R99 - EQ2 */ + 0x000C, /* R100 - EQ3 */ + 0x000C, /* R101 - EQ4 */ + 0x000C, /* R102 - EQ5 */ + 0x000C, /* R103 - EQ6 */ + 0x0FCA, /* R104 - EQ7 */ + 0x0400, /* R105 - EQ8 */ + 0x00D8, /* R106 - EQ9 */ + 0x1EB5, /* R107 - EQ10 */ + 0xF145, /* R108 - EQ11 */ + 0x0B75, /* R109 - EQ12 */ + 0x01C5, /* R110 - EQ13 */ + 0x1C58, /* R111 - EQ14 */ + 0xF373, /* R112 - EQ15 */ + 0x0A54, /* R113 - EQ16 */ + 0x0558, /* R114 - EQ17 */ + 0x168E, /* R115 - EQ18 */ + 0xF829, /* R116 - EQ19 */ + 0x07AD, /* R117 - EQ20 */ + 0x1103, /* R118 - EQ21 */ + 0x0564, /* R119 - EQ22 */ + 0x0559, /* R120 - EQ23 */ + 0x4000, /* R121 - EQ24 */ + 0x0000, /* R122 - Digital Pulls */ + 0x0F08, /* R123 - DRC Control 1 */ + 0x0000, /* R124 - DRC Control 2 */ + 0x0080, /* R125 - DRC Control 3 */ + 0x0000, /* R126 - DRC Control 4 */ +}; + +static struct { + int ratio; + int clk_sys_rate; +} clk_sys_rates[] = { + { 64, 0 }, + { 128, 1 }, + { 192, 2 }, + { 256, 3 }, + { 384, 4 }, + { 512, 5 }, + { 768, 6 }, + { 1024, 7 }, + { 1408, 8 }, + { 1536, 9 }, +}; + +static struct { + int rate; + int sample_rate; +} sample_rates[] = { + { 8000, 0 }, + { 11025, 1 }, + { 12000, 1 }, + { 16000, 2 }, + { 22050, 3 }, + { 24000, 3 }, + { 32000, 4 }, + { 44100, 5 }, + { 48000, 5 }, +}; + +static struct { + int div; /* *10 due to .5s */ + int bclk_div; +} bclk_divs[] = { + { 10, 0 }, + { 15, 1 }, + { 20, 2 }, + { 30, 3 }, + { 40, 4 }, + { 55, 5 }, + { 60, 6 }, + { 80, 7 }, + { 110, 8 }, + { 120, 9 }, + { 160, 10 }, + { 220, 11 }, + { 240, 12 }, + { 320, 13 }, + { 440, 14 }, + { 480, 15 }, +}; + +struct wm8993_priv { + u16 reg_cache[WM8993_REGISTER_COUNT]; + struct wm8993_platform_data pdata; + struct snd_soc_codec codec; + int master; + int sysclk_source; + unsigned int mclk_rate; + unsigned int sysclk_rate; + unsigned int fs; + unsigned int bclk; + int class_w_users; + unsigned int fll_fref; + unsigned int fll_fout; +}; + +static unsigned int wm8993_read_hw(struct snd_soc_codec *codec, u8 reg) +{ + struct i2c_msg xfer[2]; + u16 data; + int ret; + struct i2c_client *i2c = codec->control_data; + + /* Write register */ + xfer[0].addr = i2c->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = ® + + /* Read data */ + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (u8 *)&data; + + ret = i2c_transfer(i2c->adapter, xfer, 2); + if (ret != 2) { + dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret); + return 0; + } + + return (data >> 8) | ((data & 0xff) << 8); +} + +static int wm8993_volatile(unsigned int reg) +{ + switch (reg) { + case WM8993_SOFTWARE_RESET: + case WM8993_DC_SERVO_0: + case WM8993_DC_SERVO_READBACK_0: + case WM8993_DC_SERVO_READBACK_1: + case WM8993_DC_SERVO_READBACK_2: + return 1; + default: + return 0; + } +} + +static unsigned int wm8993_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *reg_cache = codec->reg_cache; + + BUG_ON(reg > WM8993_MAX_REGISTER); + + if (wm8993_volatile(reg)) + return wm8993_read_hw(codec, reg); + else + return reg_cache[reg]; +} + +static int wm8993_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 *reg_cache = codec->reg_cache; + u8 data[3]; + int ret; + + BUG_ON(reg > WM8993_MAX_REGISTER); + + /* data is + * D15..D9 WM8993 register offset + * D8...D0 register data + */ + data[0] = reg; + data[1] = value >> 8; + data[2] = value & 0x00ff; + + if (!wm8993_volatile(reg)) + reg_cache[reg] = value; + + ret = codec->hw_write(codec->control_data, data, 3); + + if (ret == 3) + return 0; + if (ret < 0) + return ret; + return -EIO; +} + +struct _fll_div { + u16 fll_fratio; + u16 fll_outdiv; + u16 fll_clk_ref_div; + u16 n; + u16 k; +}; + +/* The size in bits of the FLL divide multiplied by 10 + * to allow rounding later */ +#define FIXED_FLL_SIZE ((1 << 16) * 10) + +static struct { + unsigned int min; + unsigned int max; + u16 fll_fratio; + int ratio; +} fll_fratios[] = { + { 0, 64000, 4, 16 }, + { 64000, 128000, 3, 8 }, + { 128000, 256000, 2, 4 }, + { 256000, 1000000, 1, 2 }, + { 1000000, 13500000, 0, 1 }, +}; + +static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, + unsigned int Fout) +{ + u64 Kpart; + unsigned int K, Ndiv, Nmod, target; + unsigned int div; + int i; + + /* Fref must be <=13.5MHz */ + div = 1; + while ((Fref / div) > 13500000) { + div *= 2; + + if (div > 8) { + pr_err("Can't scale %dMHz input down to <=13.5MHz\n", + Fref); + return -EINVAL; + } + } + + pr_debug("Fref=%u Fout=%u\n", Fref, Fout); + + /* Apply the division for our remaining calculations */ + Fref /= div; + + /* Fvco should be 90-100MHz; don't check the upper bound */ + div = 0; + target = Fout * 2; + while (target < 90000000) { + div++; + target *= 2; + if (div > 7) { + pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n", + Fout); + return -EINVAL; + } + } + fll_div->fll_outdiv = div; + + pr_debug("Fvco=%dHz\n", target); + + /* Find an appropraite FLL_FRATIO and factor it out of the target */ + for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { + if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { + fll_div->fll_fratio = fll_fratios[i].fll_fratio; + target /= fll_fratios[i].ratio; + break; + } + } + if (i == ARRAY_SIZE(fll_fratios)) { + pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref); + return -EINVAL; + } + + /* Now, calculate N.K */ + Ndiv = target / Fref; + + fll_div->n = Ndiv; + Nmod = target % Fref; + pr_debug("Nmod=%d\n", Nmod); + + /* Calculate fractional part - scale up so we can round. */ + Kpart = FIXED_FLL_SIZE * (long long)Nmod; + + do_div(Kpart, Fref); + + K = Kpart & 0xFFFFFFFF; + + if ((K % 10) >= 5) + K += 5; + + /* Move down to proper range now rounding is done */ + fll_div->k = K / 10; + + pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n", + fll_div->n, fll_div->k, + fll_div->fll_fratio, fll_div->fll_outdiv, + fll_div->fll_clk_ref_div); + + return 0; +} + +static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, + unsigned int Fref, unsigned int Fout) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8993_priv *wm8993 = codec->private_data; + u16 reg1, reg4, reg5; + struct _fll_div fll_div; + int ret; + + /* Any change? */ + if (Fref == wm8993->fll_fref && Fout == wm8993->fll_fout) + return 0; + + /* Disable the FLL */ + if (Fout == 0) { + dev_dbg(codec->dev, "FLL disabled\n"); + wm8993->fll_fref = 0; + wm8993->fll_fout = 0; + + reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1); + reg1 &= ~WM8993_FLL_ENA; + wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1); + + return 0; + } + + ret = fll_factors(&fll_div, Fref, Fout); + if (ret != 0) + return ret; + + reg5 = wm8993_read(codec, WM8993_FLL_CONTROL_5); + reg5 &= ~WM8993_FLL_CLK_SRC_MASK; + + switch (fll_id) { + case WM8993_FLL_MCLK: + break; + + case WM8993_FLL_LRCLK: + reg5 |= 1; + break; + + case WM8993_FLL_BCLK: + reg5 |= 2; + break; + + default: + dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id); + return -EINVAL; + } + + /* Any FLL configuration change requires that the FLL be + * disabled first. */ + reg1 = wm8993_read(codec, WM8993_FLL_CONTROL_1); + reg1 &= ~WM8993_FLL_ENA; + wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1); + + /* Apply the configuration */ + if (fll_div.k) + reg1 |= WM8993_FLL_FRAC_MASK; + else + reg1 &= ~WM8993_FLL_FRAC_MASK; + wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1); + + wm8993_write(codec, WM8993_FLL_CONTROL_2, + (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) | + (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT)); + wm8993_write(codec, WM8993_FLL_CONTROL_3, fll_div.k); + + reg4 = wm8993_read(codec, WM8993_FLL_CONTROL_4); + reg4 &= ~WM8993_FLL_N_MASK; + reg4 |= fll_div.n << WM8993_FLL_N_SHIFT; + wm8993_write(codec, WM8993_FLL_CONTROL_4, reg4); + + reg5 &= ~WM8993_FLL_CLK_REF_DIV_MASK; + reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT; + wm8993_write(codec, WM8993_FLL_CONTROL_5, reg5); + + /* Enable the FLL */ + wm8993_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA); + + dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); + + wm8993->fll_fref = Fref; + wm8993->fll_fout = Fout; + + return 0; +} + +static int configure_clock(struct snd_soc_codec *codec) +{ + struct wm8993_priv *wm8993 = codec->private_data; + unsigned int reg; + + /* This should be done on init() for bypass paths */ + switch (wm8993->sysclk_source) { + case WM8993_SYSCLK_MCLK: + dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8993->mclk_rate); + + reg = wm8993_read(codec, WM8993_CLOCKING_2); + reg &= ~WM8993_SYSCLK_SRC; + if (wm8993->mclk_rate > 13500000) { + reg |= WM8993_MCLK_DIV; + wm8993->sysclk_rate = wm8993->mclk_rate / 2; + } else { + reg &= ~WM8993_MCLK_DIV; + wm8993->sysclk_rate = wm8993->mclk_rate; + } + reg &= ~WM8993_MCLK_DIV; + reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC); + wm8993_write(codec, WM8993_CLOCKING_2, reg); + break; + + case WM8993_SYSCLK_FLL: + dev_dbg(codec->dev, "Using %dHz FLL clock\n", + wm8993->fll_fout); + + reg = wm8993_read(codec, WM8993_CLOCKING_2); + reg |= WM8993_SYSCLK_SRC; + if (wm8993->fll_fout > 13500000) { + reg |= WM8993_MCLK_DIV; + wm8993->sysclk_rate = wm8993->fll_fout / 2; + } else { + reg &= ~WM8993_MCLK_DIV; + wm8993->sysclk_rate = wm8993->fll_fout; + } + wm8993_write(codec, WM8993_CLOCKING_2, reg); + break; + + default: + dev_err(codec->dev, "System clock not configured\n"); + return -EINVAL; + } + + dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8993->sysclk_rate); + + return 0; +} + +static void wait_for_dc_servo(struct snd_soc_codec *codec, int mask) +{ + unsigned int reg; + int count = 0; + + dev_dbg(codec->dev, "Waiting for DC servo...\n"); + do { + count++; + msleep(1); + reg = wm8993_read(codec, WM8993_DC_SERVO_READBACK_0); + dev_dbg(codec->dev, "DC servo status: %x\n", reg); + } while ((reg & WM8993_DCS_CAL_COMPLETE_MASK) + != WM8993_DCS_CAL_COMPLETE_MASK && count < 1000); + + if ((reg & WM8993_DCS_CAL_COMPLETE_MASK) + != WM8993_DCS_CAL_COMPLETE_MASK) + dev_err(codec->dev, "Timed out waiting for DC Servo\n"); +} + +static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1650, 150, 0); +static const DECLARE_TLV_DB_SCALE(inmix_sw_tlv, 0, 3000, 0); +static const DECLARE_TLV_DB_SCALE(inmix_tlv, -1500, 300, 1); +static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0); +static const DECLARE_TLV_DB_SCALE(drc_comp_threash, -4500, 75, 0); +static const DECLARE_TLV_DB_SCALE(drc_comp_amp, -2250, 75, 0); +static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0); +static const unsigned int drc_max_tlv[] = { + TLV_DB_RANGE_HEAD(4), + 0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0), + 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0), +}; +static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0); +static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -1800, 300, 0); +static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); +static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); +static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); +static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0); +static const DECLARE_TLV_DB_SCALE(spkmix_tlv, -300, 300, 0); +static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1); +static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0); +static const unsigned int spkboost_tlv[] = { + TLV_DB_RANGE_HEAD(7), + 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0), + 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0), +}; +static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0); + +static const char *speaker_ref_text[] = { + "SPKVDD/2", + "VMID", +}; + +static const struct soc_enum speaker_ref = + SOC_ENUM_SINGLE(WM8993_SPEAKER_MIXER, 8, 2, speaker_ref_text); + +static const char *speaker_mode_text[] = { + "Class D", + "Class AB", +}; + +static const struct soc_enum speaker_mode = + SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text); + +static const char *dac_deemph_text[] = { + "None", + "32kHz", + "44.1kHz", + "48kHz", +}; + +static const struct soc_enum dac_deemph = + SOC_ENUM_SINGLE(WM8993_DAC_CTRL, 4, 4, dac_deemph_text); + +static const char *adc_hpf_text[] = { + "Hi-Fi", + "Voice 1", + "Voice 2", + "Voice 3", +}; + +static const struct soc_enum adc_hpf = + SOC_ENUM_SINGLE(WM8993_ADC_CTRL, 5, 4, adc_hpf_text); + +static const char *drc_path_text[] = { + "ADC", + "DAC" +}; + +static const struct soc_enum drc_path = + SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 14, 2, drc_path_text); + +static const char *drc_r0_text[] = { + "1", + "1/2", + "1/4", + "1/8", + "1/16", + "0", +}; + +static const struct soc_enum drc_r0 = + SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 8, 6, drc_r0_text); + +static const char *drc_r1_text[] = { + "1", + "1/2", + "1/4", + "1/8", + "0", +}; + +static const struct soc_enum drc_r1 = + SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_4, 13, 5, drc_r1_text); + +static const char *drc_attack_text[] = { + "Reserved", + "181us", + "363us", + "726us", + "1.45ms", + "2.9ms", + "5.8ms", + "11.6ms", + "23.2ms", + "46.4ms", + "92.8ms", + "185.6ms", +}; + +static const struct soc_enum drc_attack = + SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 12, 12, drc_attack_text); + +static const char *drc_decay_text[] = { + "186ms", + "372ms", + "743ms", + "1.49s", + "2.97ms", + "5.94ms", + "11.89ms", + "23.78ms", + "47.56ms", +}; + +static const struct soc_enum drc_decay = + SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 8, 9, drc_decay_text); + +static const char *drc_ff_text[] = { + "5 samples", + "9 samples", +}; + +static const struct soc_enum drc_ff = + SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 7, 2, drc_ff_text); + +static const char *drc_qr_rate_text[] = { + "0.725ms", + "1.45ms", + "5.8ms", +}; + +static const struct soc_enum drc_qr_rate = + SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 0, 3, drc_qr_rate_text); + +static const char *drc_smooth_text[] = { + "Low", + "Medium", + "High", +}; + +static const struct soc_enum drc_smooth = + SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 4, 3, drc_smooth_text); + + +/* + * Update the DC servo calibration on gain changes + */ +static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int ret; + + ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); + + /* Only need to do this if the outputs are active */ + if (wm8993_read(codec, WM8993_POWER_MANAGEMENT_1) + & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA)) + snd_soc_update_bits(codec, + WM8993_DC_SERVO_0, + WM8993_DCS_TRIG_SINGLE_0 | + WM8993_DCS_TRIG_SINGLE_1, + WM8993_DCS_TRIG_SINGLE_0 | + WM8993_DCS_TRIG_SINGLE_1); + + return ret; +} + +static const struct snd_kcontrol_new wm8993_snd_controls[] = { +SOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0, + inpga_tlv), +SOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1), +SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 0), + +SOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0, + inpga_tlv), +SOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1), +SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 0), + + +SOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0, + inpga_tlv), +SOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1), +SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 0), + +SOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0, + inpga_tlv), +SOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1), +SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 0), + +SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0, + inmix_sw_tlv), +SOC_SINGLE_TLV("MIXINL IN1L Volume", WM8993_INPUT_MIXER3, 4, 1, 0, + inmix_sw_tlv), +SOC_SINGLE_TLV("MIXINL Output Record Volume", WM8993_INPUT_MIXER3, 0, 7, 0, + inmix_tlv), +SOC_SINGLE_TLV("MIXINL IN1LP Volume", WM8993_INPUT_MIXER5, 6, 7, 0, inmix_tlv), +SOC_SINGLE_TLV("MIXINL Direct Voice Volume", WM8993_INPUT_MIXER5, 0, 6, 0, + inmix_tlv), + +SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8993_INPUT_MIXER4, 7, 1, 0, + inmix_sw_tlv), +SOC_SINGLE_TLV("MIXINR IN1R Volume", WM8993_INPUT_MIXER4, 4, 1, 0, + inmix_sw_tlv), +SOC_SINGLE_TLV("MIXINR Output Record Volume", WM8993_INPUT_MIXER4, 0, 7, 0, + inmix_tlv), +SOC_SINGLE_TLV("MIXINR IN1RP Volume", WM8993_INPUT_MIXER6, 6, 7, 0, inmix_tlv), +SOC_SINGLE_TLV("MIXINR Direct Voice Volume", WM8993_INPUT_MIXER6, 0, 6, 0, + inmix_tlv), + +SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE, + 5, 9, 12, 0, sidetone_tlv), + +SOC_SINGLE("DRC Switch", WM8993_DRC_CONTROL_1, 15, 1, 0), +SOC_ENUM("DRC Path", drc_path), +SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8993_DRC_CONTROL_2, + 2, 60, 1, drc_comp_threash), +SOC_SINGLE_TLV("DRC Compressor Amplitude Volume", WM8993_DRC_CONTROL_3, + 11, 30, 1, drc_comp_amp), +SOC_ENUM("DRC R0", drc_r0), +SOC_ENUM("DRC R1", drc_r1), +SOC_SINGLE_TLV("DRC Minimum Volume", WM8993_DRC_CONTROL_1, 2, 3, 1, + drc_min_tlv), +SOC_SINGLE_TLV("DRC Maximum Volume", WM8993_DRC_CONTROL_1, 0, 3, 0, + drc_max_tlv), +SOC_ENUM("DRC Attack Rate", drc_attack), +SOC_ENUM("DRC Decay Rate", drc_decay), +SOC_ENUM("DRC FF Delay", drc_ff), +SOC_SINGLE("DRC Anti-clip Switch", WM8993_DRC_CONTROL_1, 9, 1, 0), +SOC_SINGLE("DRC Quick Release Switch", WM8993_DRC_CONTROL_1, 10, 1, 0), +SOC_SINGLE_TLV("DRC Quick Release Volume", WM8993_DRC_CONTROL_3, 2, 3, 0, + drc_qr_tlv), +SOC_ENUM("DRC Quick Release Rate", drc_qr_rate), +SOC_SINGLE("DRC Smoothing Switch", WM8993_DRC_CONTROL_1, 11, 1, 0), +SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8993_DRC_CONTROL_1, 8, 1, 0), +SOC_ENUM("DRC Smoothing Hysteresis Threashold", drc_smooth), +SOC_SINGLE_TLV("DRC Startup Volume", WM8993_DRC_CONTROL_4, 8, 18, 0, + drc_startup_tlv), + +SOC_SINGLE("EQ Switch", WM8993_EQ1, 0, 1, 0), + +SOC_DOUBLE_R_TLV("Capture Volume", WM8993_LEFT_ADC_DIGITAL_VOLUME, + WM8993_RIGHT_ADC_DIGITAL_VOLUME, 1, 96, 0, digital_tlv), +SOC_SINGLE("ADC High Pass Filter Switch", WM8993_ADC_CTRL, 8, 1, 0), +SOC_ENUM("ADC High Pass Filter Mode", adc_hpf), + +SOC_DOUBLE_R_TLV("Playback Volume", WM8993_LEFT_DAC_DIGITAL_VOLUME, + WM8993_RIGHT_DAC_DIGITAL_VOLUME, 1, 96, 0, digital_tlv), +SOC_SINGLE_TLV("Playback Boost Volume", WM8993_AUDIO_INTERFACE_2, 10, 3, 0, + dac_boost_tlv), +SOC_ENUM("DAC Deemphasis", dac_deemph), + +SOC_SINGLE_TLV("Left Output Mixer IN2RN Volume", WM8993_OUTPUT_MIXER5, 6, 7, 1, + outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer IN2LN Volume", WM8993_OUTPUT_MIXER3, 6, 7, 1, + outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer IN2LP Volume", WM8993_OUTPUT_MIXER3, 9, 7, 1, + outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer IN1L Volume", WM8993_OUTPUT_MIXER3, 0, 7, 1, + outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer IN1R Volume", WM8993_OUTPUT_MIXER3, 3, 7, 1, + outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer Right Input Volume", + WM8993_OUTPUT_MIXER5, 3, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer Left Input Volume", + WM8993_OUTPUT_MIXER5, 0, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer DAC Volume", WM8993_OUTPUT_MIXER5, 9, 7, 1, + outmix_tlv), + +SOC_SINGLE_TLV("Right Output Mixer IN2LN Volume", + WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer IN2RN Volume", + WM8993_OUTPUT_MIXER4, 6, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer IN1L Volume", + WM8993_OUTPUT_MIXER4, 3, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer IN1R Volume", + WM8993_OUTPUT_MIXER4, 0, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer IN2RP Volume", + WM8993_OUTPUT_MIXER4, 9, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer Left Input Volume", + WM8993_OUTPUT_MIXER6, 3, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer Right Input Volume", + WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer DAC Volume", + WM8993_OUTPUT_MIXER6, 9, 7, 1, outmix_tlv), + +SOC_DOUBLE_R_TLV("Output Volume", WM8993_LEFT_OPGA_VOLUME, + WM8993_RIGHT_OPGA_VOLUME, 0, 63, 0, outpga_tlv), +SOC_DOUBLE_R("Output Switch", WM8993_LEFT_OPGA_VOLUME, + WM8993_RIGHT_OPGA_VOLUME, 6, 1, 0), +SOC_DOUBLE_R("Output ZC Switch", WM8993_LEFT_OPGA_VOLUME, + WM8993_RIGHT_OPGA_VOLUME, 7, 1, 0), + +SOC_SINGLE("Earpiece Switch", WM8993_HPOUT2_VOLUME, 5, 1, 1), +SOC_SINGLE_TLV("Earpiece Volume", WM8993_HPOUT2_VOLUME, 4, 1, 1, earpiece_tlv), + +SOC_SINGLE_TLV("SPKL Input Volume", WM8993_SPKMIXL_ATTENUATION, + 5, 1, 1, spkmix_tlv), +SOC_SINGLE_TLV("SPKL IN1LP Volume", WM8993_SPKMIXL_ATTENUATION, + 4, 1, 1, spkmix_tlv), +SOC_SINGLE_TLV("SPKL Output Volume", WM8993_SPKMIXL_ATTENUATION, + 3, 1, 1, spkmix_tlv), +SOC_SINGLE_TLV("SPKL DAC Volume", WM8993_SPKMIXL_ATTENUATION, + 2, 1, 1, spkmix_tlv), + +SOC_SINGLE_TLV("SPKR Input Volume", WM8993_SPKMIXR_ATTENUATION, + 5, 1, 1, spkmix_tlv), +SOC_SINGLE_TLV("SPKR IN1RP Volume", WM8993_SPKMIXR_ATTENUATION, + 4, 1, 1, spkmix_tlv), +SOC_SINGLE_TLV("SPKR Output Volume", WM8993_SPKMIXR_ATTENUATION, + 3, 1, 1, spkmix_tlv), +SOC_SINGLE_TLV("SPKR DAC Volume", WM8993_SPKMIXR_ATTENUATION, + 2, 1, 1, spkmix_tlv), + +SOC_DOUBLE_R_TLV("Speaker Mixer Volume", + WM8993_SPKMIXL_ATTENUATION, WM8993_SPKMIXR_ATTENUATION, + 0, 3, 1, spkmixout_tlv), +SOC_DOUBLE_R_TLV("Speaker Volume", + WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT, + 0, 63, 0, outpga_tlv), +SOC_DOUBLE_R("Speaker Switch", + WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT, + 6, 1, 0), +SOC_DOUBLE_R("Speaker ZC Switch", + WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT, + 7, 1, 0), +SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 0, 3, 7, 0, + spkboost_tlv), +SOC_ENUM("Speaker Reference", speaker_ref), +SOC_ENUM("Speaker Mode", speaker_mode), + +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Volume", + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_READWRITE, + .tlv.p = outpga_tlv, + .info = snd_soc_info_volsw_2r, + .get = snd_soc_get_volsw_2r, .put = wm8993_put_dc_servo, + .private_value = (unsigned long)&(struct soc_mixer_control) { + .reg = WM8993_LEFT_OUTPUT_VOLUME, + .rreg = WM8993_RIGHT_OUTPUT_VOLUME, + .shift = 0, .max = 63 + }, +}, +SOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME, + WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0), +SOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME, + WM8993_RIGHT_OUTPUT_VOLUME, 7, 1, 0), + +SOC_SINGLE("LINEOUT1N Switch", WM8993_LINE_OUTPUTS_VOLUME, 6, 1, 1), +SOC_SINGLE("LINEOUT1P Switch", WM8993_LINE_OUTPUTS_VOLUME, 5, 1, 1), +SOC_SINGLE_TLV("LINEOUT1 Volume", WM8993_LINE_OUTPUTS_VOLUME, 4, 1, 1, + line_tlv), + +SOC_SINGLE("LINEOUT2N Switch", WM8993_LINE_OUTPUTS_VOLUME, 2, 1, 1), +SOC_SINGLE("LINEOUT2P Switch", WM8993_LINE_OUTPUTS_VOLUME, 1, 1, 1), +SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1, + line_tlv), +}; + +static const struct snd_kcontrol_new wm8993_eq_controls[] = { +SOC_SINGLE_TLV("EQ1 Volume", WM8993_EQ2, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 Volume", WM8993_EQ3, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ3 Volume", WM8993_EQ4, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ4 Volume", WM8993_EQ5, 0, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ5 Volume", WM8993_EQ6, 0, 24, 0, eq_tlv), +}; + +static int wm8993_earpiece_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *control, int event) +{ + struct snd_soc_codec *codec = w->codec; + u16 reg = wm8993_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + reg |= WM8993_HPOUT2_IN_ENA; + wm8993_write(codec, WM8993_ANTIPOP1, reg); + udelay(50); + break; + + case SND_SOC_DAPM_POST_PMD: + wm8993_write(codec, WM8993_ANTIPOP1, reg); + break; + + default: + BUG(); + break; + } + + return 0; +} + +static int clk_sys_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return configure_clock(codec); + + case SND_SOC_DAPM_POST_PMD: + break; + } + + return 0; +} + +/* + * When used with DAC outputs only the WM8993 charge pump supports + * operation in class W mode, providing very low power consumption + * when used with digital sources. Enable and disable this mode + * automatically depending on the mixer configuration. + * + * Currently the only supported paths are the direct DAC->headphone + * paths (which provide minimum power consumption anyway). + */ +static int wm8993_class_w_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct snd_soc_codec *codec = widget->codec; + struct wm8993_priv *wm8993 = codec->private_data; + int ret; + + /* Turn it off if we're using the main output mixer */ + if (ucontrol->value.integer.value[0] == 0) { + if (wm8993->class_w_users == 0) { + dev_dbg(codec->dev, "Disabling Class W\n"); + snd_soc_update_bits(codec, WM8993_CLASS_W_0, + WM8993_CP_DYN_FREQ | + WM8993_CP_DYN_V, + 0); + } + wm8993->class_w_users++; + } + + /* Implement the change */ + ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + /* Enable it if we're using the direct DAC path */ + if (ucontrol->value.integer.value[0] == 1) { + if (wm8993->class_w_users == 1) { + dev_dbg(codec->dev, "Enabling Class W\n"); + snd_soc_update_bits(codec, WM8993_CLASS_W_0, + WM8993_CP_DYN_FREQ | + WM8993_CP_DYN_V, + WM8993_CP_DYN_FREQ | + WM8993_CP_DYN_V); + } + wm8993->class_w_users--; + } + + dev_dbg(codec->dev, "Indirect DAC use count now %d\n", + wm8993->class_w_users); + + return ret; +} + +#define SOC_DAPM_ENUM_W(xname, xenum) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_enum_double, \ + .get = snd_soc_dapm_get_enum_double, \ + .put = wm8993_class_w_put, \ + .private_value = (unsigned long)&xenum } + +static int hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + unsigned int reg = wm8993_read(codec, WM8993_ANALOGUE_HP_0); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, + WM8993_CP_ENA, WM8993_CP_ENA); + + msleep(5); + + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, + WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, + WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA); + + reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY; + wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg); + + /* Start the DC servo */ + snd_soc_update_bits(codec, WM8993_DC_SERVO_0, + WM8993_DCS_ENA_CHAN_0 | + WM8993_DCS_ENA_CHAN_1 | + WM8993_DCS_TRIG_STARTUP_1 | + WM8993_DCS_TRIG_STARTUP_0, + WM8993_DCS_ENA_CHAN_0 | + WM8993_DCS_ENA_CHAN_1 | + WM8993_DCS_TRIG_STARTUP_1 | + WM8993_DCS_TRIG_STARTUP_0); + wait_for_dc_servo(codec, WM8993_DCS_TRIG_STARTUP_0 | + WM8993_DCS_TRIG_STARTUP_1); + snd_soc_update_bits(codec, WM8993_DC_SERVO_1, + WM8993_DCS_TIMER_PERIOD_01_MASK, 0xa); + + reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | + WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; + wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg); + break; + + case SND_SOC_DAPM_PRE_PMD: + reg &= ~(WM8993_HPOUT1L_RMV_SHORT | + WM8993_HPOUT1L_DLY | + WM8993_HPOUT1L_OUTP | + WM8993_HPOUT1R_RMV_SHORT | + WM8993_HPOUT1R_DLY | + WM8993_HPOUT1R_OUTP); + + snd_soc_update_bits(codec, WM8993_DC_SERVO_1, + WM8993_DCS_TIMER_PERIOD_01_MASK, 0); + snd_soc_update_bits(codec, WM8993_DC_SERVO_0, + WM8993_DCS_ENA_CHAN_0 | + WM8993_DCS_ENA_CHAN_1, 0); + + wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg); + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, + WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, + 0); + + snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, + WM8993_CP_ENA, 0); + break; + } + + return 0; +} + +static const struct snd_kcontrol_new in1l_pga[] = { +SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0), +SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0), +}; + +static const struct snd_kcontrol_new in1r_pga[] = { +SOC_DAPM_SINGLE("IN1RP Switch", WM8993_INPUT_MIXER2, 1, 1, 0), +SOC_DAPM_SINGLE("IN1RN Switch", WM8993_INPUT_MIXER2, 0, 1, 0), +}; + +static const struct snd_kcontrol_new in2l_pga[] = { +SOC_DAPM_SINGLE("IN2LP Switch", WM8993_INPUT_MIXER2, 7, 1, 0), +SOC_DAPM_SINGLE("IN2LN Switch", WM8993_INPUT_MIXER2, 6, 1, 0), +}; + +static const struct snd_kcontrol_new in2r_pga[] = { +SOC_DAPM_SINGLE("IN2RP Switch", WM8993_INPUT_MIXER2, 3, 1, 0), +SOC_DAPM_SINGLE("IN2RN Switch", WM8993_INPUT_MIXER2, 2, 1, 0), +}; + +static const struct snd_kcontrol_new mixinl[] = { +SOC_DAPM_SINGLE("IN2L Switch", WM8993_INPUT_MIXER3, 8, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_INPUT_MIXER3, 5, 1, 0), +}; + +static const struct snd_kcontrol_new mixinr[] = { +SOC_DAPM_SINGLE("IN2R Switch", WM8993_INPUT_MIXER4, 8, 1, 0), +SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0), +}; + +static const struct snd_kcontrol_new left_output_mixer[] = { +SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0), +SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0), +SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0), +SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0), +SOC_DAPM_SINGLE("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0), +SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0), +}; + +static const struct snd_kcontrol_new right_output_mixer[] = { +SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0), +SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0), +SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0), +SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0), +SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0), +SOC_DAPM_SINGLE("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0), +}; + +static const struct snd_kcontrol_new earpiece_mixer[] = { +SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_HPOUT2_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("Left Output Switch", WM8993_HPOUT2_MIXER, 4, 1, 0), +SOC_DAPM_SINGLE("Right Output Switch", WM8993_HPOUT2_MIXER, 3, 1, 0), +}; + +static const struct snd_kcontrol_new left_speaker_mixer[] = { +SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 7, 1, 0), +SOC_DAPM_SINGLE("IN1LP Switch", WM8993_SPEAKER_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 3, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 6, 1, 0), +}; + +static const struct snd_kcontrol_new right_speaker_mixer[] = { +SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 6, 1, 0), +SOC_DAPM_SINGLE("IN1RP Switch", WM8993_SPEAKER_MIXER, 4, 1, 0), +SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 2, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 0, 1, 0), +}; + +static const struct snd_kcontrol_new left_speaker_boost[] = { +SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 5, 1, 0), +SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 4, 1, 0), +SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 3, 1, 0), +}; + +static const struct snd_kcontrol_new right_speaker_boost[] = { +SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 2, 1, 0), +SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 1, 1, 0), +SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 0, 1, 0), +}; + +static const char *hp_mux_text[] = { + "Mixer", + "DAC", +}; + +static const struct soc_enum hpl_enum = + SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text); + +static const struct snd_kcontrol_new hpl_mux = + SOC_DAPM_ENUM_W("Left Headphone Mux", hpl_enum); + +static const struct soc_enum hpr_enum = + SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text); + +static const struct snd_kcontrol_new hpr_mux = + SOC_DAPM_ENUM_W("Right Headphone Mux", hpr_enum); + +static const struct snd_kcontrol_new line1_mix[] = { +SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER1, 2, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER1, 1, 1, 0), +SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER1, 0, 1, 0), +}; + +static const struct snd_kcontrol_new line1n_mix[] = { +SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 6, 1, 0), +SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER1, 5, 1, 0), +}; + +static const struct snd_kcontrol_new line1p_mix[] = { +SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0), +}; + +static const struct snd_kcontrol_new line2_mix[] = { +SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0), +SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0), +SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), +}; + +static const struct snd_kcontrol_new line2n_mix[] = { +SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0), +SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0), +}; + +static const struct snd_kcontrol_new line2p_mix[] = { +SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), +}; + +static const struct snd_soc_dapm_widget wm8993_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("IN1LN"), +SND_SOC_DAPM_INPUT("IN1LP"), +SND_SOC_DAPM_INPUT("IN2LN"), +SND_SOC_DAPM_INPUT("IN2LP/VXRN"), +SND_SOC_DAPM_INPUT("IN1RN"), +SND_SOC_DAPM_INPUT("IN1RP"), +SND_SOC_DAPM_INPUT("IN2RN"), +SND_SOC_DAPM_INPUT("IN2RP/VXRP"), + +SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8993_BUS_CONTROL_1, 1, 0, clk_sys_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("TOCLK", WM8993_CLOCKING_1, 14, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8993_CLOCKING_3, 0, 0, NULL, 0), + +SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0), +SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0), + +SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0, + in1l_pga, ARRAY_SIZE(in1l_pga)), +SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0, + in1r_pga, ARRAY_SIZE(in1r_pga)), + +SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0, + in2l_pga, ARRAY_SIZE(in2l_pga)), +SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0, + in2r_pga, ARRAY_SIZE(in2r_pga)), + +/* Dummy widgets to represent differential paths */ +SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), + +SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0, + mixinl, ARRAY_SIZE(mixinl)), +SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0, + mixinr, ARRAY_SIZE(mixinr)), + +SND_SOC_DAPM_ADC("ADCL", "Capture", WM8993_POWER_MANAGEMENT_2, 1, 0), +SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0), + +SND_SOC_DAPM_DAC("DACL", "Playback", WM8993_POWER_MANAGEMENT_3, 1, 0), +SND_SOC_DAPM_DAC("DACR", "Playback", WM8993_POWER_MANAGEMENT_3, 0, 0), + +SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0, + left_output_mixer, ARRAY_SIZE(left_output_mixer)), +SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0, + right_output_mixer, ARRAY_SIZE(right_output_mixer)), + +SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0), + +SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, + earpiece_mixer, ARRAY_SIZE(earpiece_mixer)), +SND_SOC_DAPM_PGA_E("Earpiece Driver", WM8993_POWER_MANAGEMENT_1, 11, 0, + NULL, 0, wm8993_earpiece_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + +SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0, + left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), +SND_SOC_DAPM_MIXER("SPKR", WM8993_POWER_MANAGEMENT_3, 9, 0, + right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), + +SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0, + left_speaker_boost, ARRAY_SIZE(left_speaker_boost)), +SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0, + right_speaker_boost, ARRAY_SIZE(right_speaker_boost)), + +SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0, + NULL, 0), +SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0, + NULL, 0), + +SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), +SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), +SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, + NULL, 0, + hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0, + line1_mix, ARRAY_SIZE(line1_mix)), +SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0, + line2_mix, ARRAY_SIZE(line2_mix)), + +SND_SOC_DAPM_MIXER("LINEOUT1N Mixer", SND_SOC_NOPM, 0, 0, + line1n_mix, ARRAY_SIZE(line1n_mix)), +SND_SOC_DAPM_MIXER("LINEOUT1P Mixer", SND_SOC_NOPM, 0, 0, + line1p_mix, ARRAY_SIZE(line1p_mix)), +SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0, + line2n_mix, ARRAY_SIZE(line2n_mix)), +SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0, + line2p_mix, ARRAY_SIZE(line2p_mix)), + +SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, + NULL, 0), + +SND_SOC_DAPM_OUTPUT("SPKOUTLP"), +SND_SOC_DAPM_OUTPUT("SPKOUTLN"), +SND_SOC_DAPM_OUTPUT("SPKOUTRP"), +SND_SOC_DAPM_OUTPUT("SPKOUTRN"), +SND_SOC_DAPM_OUTPUT("HPOUT1L"), +SND_SOC_DAPM_OUTPUT("HPOUT1R"), +SND_SOC_DAPM_OUTPUT("HPOUT2P"), +SND_SOC_DAPM_OUTPUT("HPOUT2N"), +SND_SOC_DAPM_OUTPUT("LINEOUT1P"), +SND_SOC_DAPM_OUTPUT("LINEOUT1N"), +SND_SOC_DAPM_OUTPUT("LINEOUT2P"), +SND_SOC_DAPM_OUTPUT("LINEOUT2N"), +}; + +static const struct snd_soc_dapm_route routes[] = { + { "IN1L PGA", "IN1LP Switch", "IN1LP" }, + { "IN1L PGA", "IN1LN Switch", "IN1LN" }, + + { "IN1R PGA", "IN1RP Switch", "IN1RP" }, + { "IN1R PGA", "IN1RN Switch", "IN1RN" }, + + { "IN2L PGA", "IN2LP Switch", "IN2LP/VXRN" }, + { "IN2L PGA", "IN2LN Switch", "IN2LN" }, + + { "IN2R PGA", "IN2RP Switch", "IN2RP/VXRP" }, + { "IN2R PGA", "IN2RN Switch", "IN2RN" }, + + { "Direct Voice", NULL, "IN2LP/VXRN" }, + { "Direct Voice", NULL, "IN2RP/VXRP" }, + + { "MIXINL", "IN1L Switch", "IN1L PGA" }, + { "MIXINL", "IN2L Switch", "IN2L PGA" }, + { "MIXINL", NULL, "Direct Voice" }, + { "MIXINL", NULL, "IN1LP" }, + { "MIXINL", NULL, "Left Output Mixer" }, + + { "MIXINR", "IN1R Switch", "IN1R PGA" }, + { "MIXINR", "IN2R Switch", "IN2R PGA" }, + { "MIXINR", NULL, "Direct Voice" }, + { "MIXINR", NULL, "IN1RP" }, + { "MIXINR", NULL, "Right Output Mixer" }, + + { "ADCL", NULL, "MIXINL" }, + { "ADCL", NULL, "CLK_SYS" }, + { "ADCL", NULL, "CLK_DSP" }, + { "ADCR", NULL, "MIXINR" }, + { "ADCR", NULL, "CLK_SYS" }, + { "ADCR", NULL, "CLK_DSP" }, + + { "DACL", NULL, "CLK_SYS" }, + { "DACL", NULL, "CLK_DSP" }, + { "DACR", NULL, "CLK_SYS" }, + { "DACR", NULL, "CLK_DSP" }, + + { "Left Output Mixer", "Left Input Switch", "MIXINL" }, + { "Left Output Mixer", "Right Input Switch", "MIXINR" }, + { "Left Output Mixer", "IN2RN Switch", "IN2RN" }, + { "Left Output Mixer", "IN2LN Switch", "IN2LN" }, + { "Left Output Mixer", "IN2LP Switch", "IN2LP/VXRN" }, + { "Left Output Mixer", "IN1L Switch", "IN1L PGA" }, + { "Left Output Mixer", "IN1R Switch", "IN1R PGA" }, + { "Left Output Mixer", "DAC Switch", "DACL" }, + + { "Right Output Mixer", "Left Input Switch", "MIXINL" }, + { "Right Output Mixer", "Right Input Switch", "MIXINR" }, + { "Right Output Mixer", "IN2LN Switch", "IN2LN" }, + { "Right Output Mixer", "IN2RN Switch", "IN2RN" }, + { "Right Output Mixer", "IN2RP Switch", "IN2RP/VXRP" }, + { "Right Output Mixer", "IN1L Switch", "IN1L PGA" }, + { "Right Output Mixer", "IN1R Switch", "IN1R PGA" }, + { "Right Output Mixer", "DAC Switch", "DACR" }, + + { "Left Output PGA", NULL, "Left Output Mixer" }, + { "Left Output PGA", NULL, "CLK_SYS" }, + { "Left Output PGA", NULL, "TOCLK" }, + + { "Right Output PGA", NULL, "Right Output Mixer" }, + { "Right Output PGA", NULL, "CLK_SYS" }, + { "Right Output PGA", NULL, "TOCLK" }, + + { "Earpiece Mixer", "Direct Voice Switch", "Direct Voice" }, + { "Earpiece Mixer", "Left Output Switch", "Left Output PGA" }, + { "Earpiece Mixer", "Right Output Switch", "Right Output PGA" }, + + { "Earpiece Driver", NULL, "Earpiece Mixer" }, + { "HPOUT2N", NULL, "Earpiece Driver" }, + { "HPOUT2P", NULL, "Earpiece Driver" }, + + { "SPKL", "Input Switch", "MIXINL" }, + { "SPKL", "IN1LP Switch", "IN1LP" }, + { "SPKL", "Output Switch", "Left Output Mixer" }, + { "SPKL", "DAC Switch", "DACL" }, + { "SPKL", NULL, "CLK_SYS" }, + { "SPKL", NULL, "TOCLK" }, + + { "SPKR", "Input Switch", "MIXINR" }, + { "SPKR", "IN1RP Switch", "IN1RP" }, + { "SPKR", "Output Switch", "Right Output Mixer" }, + { "SPKR", "DAC Switch", "DACR" }, + { "SPKR", NULL, "CLK_SYS" }, + { "SPKR", NULL, "TOCLK" }, + + { "SPKL Boost", "Direct Voice Switch", "Direct Voice" }, + { "SPKL Boost", "SPKL Switch", "SPKL" }, + { "SPKL Boost", "SPKR Switch", "SPKR" }, + + { "SPKR Boost", "Direct Voice Switch", "Direct Voice" }, + { "SPKR Boost", "SPKR Switch", "SPKR" }, + { "SPKR Boost", "SPKL Switch", "SPKL" }, + + { "SPKL Driver", NULL, "SPKL Boost" }, + { "SPKL Driver", NULL, "CLK_SYS" }, + + { "SPKR Driver", NULL, "SPKR Boost" }, + { "SPKR Driver", NULL, "CLK_SYS" }, + + { "SPKOUTLP", NULL, "SPKL Driver" }, + { "SPKOUTLN", NULL, "SPKL Driver" }, + { "SPKOUTRP", NULL, "SPKR Driver" }, + { "SPKOUTRN", NULL, "SPKR Driver" }, + + { "Left Headphone Mux", "DAC", "DACL" }, + { "Left Headphone Mux", "Mixer", "Left Output Mixer" }, + { "Right Headphone Mux", "DAC", "DACR" }, + { "Right Headphone Mux", "Mixer", "Right Output Mixer" }, + + { "Headphone PGA", NULL, "Left Headphone Mux" }, + { "Headphone PGA", NULL, "Right Headphone Mux" }, + { "Headphone PGA", NULL, "CLK_SYS" }, + { "Headphone PGA", NULL, "TOCLK" }, + + { "HPOUT1L", NULL, "Headphone PGA" }, + { "HPOUT1R", NULL, "Headphone PGA" }, + + { "LINEOUT1N", NULL, "LINEOUT1N Driver" }, + { "LINEOUT1P", NULL, "LINEOUT1P Driver" }, + { "LINEOUT2N", NULL, "LINEOUT2N Driver" }, + { "LINEOUT2P", NULL, "LINEOUT2P Driver" }, +}; + +static const struct snd_soc_dapm_route lineout1_diff_routes[] = { + { "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" }, + { "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" }, + { "LINEOUT1 Mixer", "Output Switch", "Left Output Mixer" }, + + { "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" }, + { "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" }, +}; + +static const struct snd_soc_dapm_route lineout1_se_routes[] = { + { "LINEOUT1N Mixer", "Left Output Switch", "Left Output Mixer" }, + { "LINEOUT1N Mixer", "Right Output Switch", "Left Output Mixer" }, + + { "LINEOUT1P Mixer", "Left Output Switch", "Left Output Mixer" }, + + { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, + { "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" }, +}; + +static const struct snd_soc_dapm_route lineout2_diff_routes[] = { + { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" }, + { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" }, + { "LINEOUT2 Mixer", "Output Switch", "Right Output Mixer" }, + + { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" }, + { "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" }, +}; + +static const struct snd_soc_dapm_route lineout2_se_routes[] = { + { "LINEOUT2N Mixer", "Left Output Switch", "Left Output Mixer" }, + { "LINEOUT2N Mixer", "Right Output Switch", "Left Output Mixer" }, + + { "LINEOUT2P Mixer", "Right Output Switch", "Right Output Mixer" }, + + { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, + { "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" }, +}; + +static int wm8993_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct wm8993_priv *wm8993 = codec->private_data; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + /* VMID=2*40k */ + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, + WM8993_VMID_SEL_MASK, 0x2); + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_2, + WM8993_TSHUT_ENA, WM8993_TSHUT_ENA); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* Bring up VMID with fast soft start */ + snd_soc_update_bits(codec, WM8993_ANTIPOP2, + WM8993_STARTUP_BIAS_ENA | + WM8993_VMID_BUF_ENA | + WM8993_VMID_RAMP_MASK | + WM8993_BIAS_SRC, + WM8993_STARTUP_BIAS_ENA | + WM8993_VMID_BUF_ENA | + WM8993_VMID_RAMP_MASK | + WM8993_BIAS_SRC); + + /* If either line output is single ended we + * need the VMID buffer */ + if (!wm8993->pdata.lineout1_diff || + !wm8993->pdata.lineout2_diff) + snd_soc_update_bits(codec, WM8993_ANTIPOP1, + WM8993_LINEOUT_VMID_BUF_ENA, + WM8993_LINEOUT_VMID_BUF_ENA); + + /* VMID=2*40k */ + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, + WM8993_VMID_SEL_MASK | + WM8993_BIAS_ENA, + WM8993_BIAS_ENA | 0x2); + msleep(32); + + /* Switch to normal bias */ + snd_soc_update_bits(codec, WM8993_ANTIPOP2, + WM8993_BIAS_SRC | + WM8993_STARTUP_BIAS_ENA, 0); + } + + /* VMID=2*240k */ + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, + WM8993_VMID_SEL_MASK, 0x4); + + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_2, + WM8993_TSHUT_ENA, 0); + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, WM8993_ANTIPOP1, + WM8993_LINEOUT_VMID_BUF_ENA, 0); + + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, + WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA, + 0); + break; + } + + codec->bias_level = level; + + return 0; +} + +static int wm8993_set_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8993_priv *wm8993 = codec->private_data; + + switch (clk_id) { + case WM8993_SYSCLK_MCLK: + wm8993->mclk_rate = freq; + case WM8993_SYSCLK_FLL: + wm8993->sysclk_source = clk_id; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int wm8993_set_dai_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8993_priv *wm8993 = codec->private_data; + unsigned int aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1); + unsigned int aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4); + + aif1 &= ~(WM8993_BCLK_DIR | WM8993_AIF_BCLK_INV | + WM8993_AIF_LRCLK_INV | WM8993_AIF_FMT_MASK); + aif4 &= ~WM8993_LRCLK_DIR; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + wm8993->master = 0; + break; + case SND_SOC_DAIFMT_CBS_CFM: + aif4 |= WM8993_LRCLK_DIR; + wm8993->master = 1; + break; + case SND_SOC_DAIFMT_CBM_CFS: + aif1 |= WM8993_BCLK_DIR; + wm8993->master = 1; + break; + case SND_SOC_DAIFMT_CBM_CFM: + aif1 |= WM8993_BCLK_DIR; + aif4 |= WM8993_LRCLK_DIR; + wm8993->master = 1; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_B: + aif1 |= WM8993_AIF_LRCLK_INV; + case SND_SOC_DAIFMT_DSP_A: + aif1 |= 0x18; + break; + case SND_SOC_DAIFMT_I2S: + aif1 |= 0x10; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + aif1 |= 0x8; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* frame inversion not valid for DSP modes */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + aif1 |= WM8993_AIF_BCLK_INV; + break; + default: + return -EINVAL; + } + break; + + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + aif1 |= WM8993_AIF_BCLK_INV | WM8993_AIF_LRCLK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + aif1 |= WM8993_AIF_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + aif1 |= WM8993_AIF_LRCLK_INV; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1); + wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4); + + return 0; +} + +static int wm8993_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8993_priv *wm8993 = codec->private_data; + int ret, i, best, best_val, cur_val; + unsigned int clocking1, clocking3, aif1, aif4; + + clocking1 = wm8993_read(codec, WM8993_CLOCKING_1); + clocking1 &= ~WM8993_BCLK_DIV_MASK; + + clocking3 = wm8993_read(codec, WM8993_CLOCKING_3); + clocking3 &= ~(WM8993_CLK_SYS_RATE_MASK | WM8993_SAMPLE_RATE_MASK); + + aif1 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_1); + aif1 &= ~WM8993_AIF_WL_MASK; + + aif4 = wm8993_read(codec, WM8993_AUDIO_INTERFACE_4); + aif4 &= ~WM8993_LRCLK_RATE_MASK; + + /* What BCLK do we need? */ + wm8993->fs = params_rate(params); + wm8993->bclk = 2 * wm8993->fs; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + wm8993->bclk *= 16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + wm8993->bclk *= 20; + aif1 |= 0x8; + break; + case SNDRV_PCM_FORMAT_S24_LE: + wm8993->bclk *= 24; + aif1 |= 0x10; + break; + case SNDRV_PCM_FORMAT_S32_LE: + wm8993->bclk *= 32; + aif1 |= 0x18; + break; + default: + return -EINVAL; + } + + dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8993->bclk); + + ret = configure_clock(codec); + if (ret != 0) + return ret; + + /* Select nearest CLK_SYS_RATE */ + best = 0; + best_val = abs((wm8993->sysclk_rate / clk_sys_rates[0].ratio) + - wm8993->fs); + for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) { + cur_val = abs((wm8993->sysclk_rate / + clk_sys_rates[i].ratio) - wm8993->fs);; + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n", + clk_sys_rates[best].ratio); + clocking3 |= (clk_sys_rates[best].clk_sys_rate + << WM8993_CLK_SYS_RATE_SHIFT); + + /* SAMPLE_RATE */ + best = 0; + best_val = abs(wm8993->fs - sample_rates[0].rate); + for (i = 1; i < ARRAY_SIZE(sample_rates); i++) { + /* Closest match */ + cur_val = abs(wm8993->fs - sample_rates[i].rate); + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n", + sample_rates[best].rate); + clocking3 |= (sample_rates[i].sample_rate << WM8993_SAMPLE_RATE_SHIFT); + + /* BCLK_DIV */ + best = 0; + best_val = INT_MAX; + for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { + cur_val = ((wm8993->sysclk_rate * 10) / bclk_divs[i].div) + - wm8993->bclk; + if (cur_val < 0) /* Table is sorted */ + break; + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + wm8993->bclk = (wm8993->sysclk_rate * 10) / bclk_divs[best].div; + dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n", + bclk_divs[best].div, wm8993->bclk); + clocking1 |= bclk_divs[best].bclk_div << WM8993_BCLK_DIV_SHIFT; + + /* LRCLK is a simple fraction of BCLK */ + dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8993->bclk / wm8993->fs); + aif4 |= wm8993->bclk / wm8993->fs; + + wm8993_write(codec, WM8993_CLOCKING_1, clocking1); + wm8993_write(codec, WM8993_CLOCKING_3, clocking3); + wm8993_write(codec, WM8993_AUDIO_INTERFACE_1, aif1); + wm8993_write(codec, WM8993_AUDIO_INTERFACE_4, aif4); + + /* ReTune Mobile? */ + if (wm8993->pdata.num_retune_configs) { + u16 eq1 = wm8993_read(codec, WM8993_EQ1); + struct wm8993_retune_mobile_setting *s; + + best = 0; + best_val = abs(wm8993->pdata.retune_configs[0].rate + - wm8993->fs); + for (i = 0; i < wm8993->pdata.num_retune_configs; i++) { + cur_val = abs(wm8993->pdata.retune_configs[i].rate + - wm8993->fs); + if (cur_val < best_val) { + best_val = cur_val; + best = i; + } + } + s = &wm8993->pdata.retune_configs[best]; + + dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n", + s->name, s->rate); + + /* Disable EQ while we reconfigure */ + snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, 0); + + for (i = 1; i < ARRAY_SIZE(s->config); i++) + wm8993_write(codec, WM8993_EQ1 + i, s->config[i]); + + snd_soc_update_bits(codec, WM8993_EQ1, WM8993_EQ_ENA, eq1); + } + + return 0; +} + +static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute) +{ + struct snd_soc_codec *codec = codec_dai->codec; + unsigned int reg; + + reg = wm8993_read(codec, WM8993_DAC_CTRL); + + if (mute) + reg |= WM8993_DAC_MUTE; + else + reg &= ~WM8993_DAC_MUTE; + + wm8993_write(codec, WM8993_DAC_CTRL, reg); + + return 0; +} + +static struct snd_soc_dai_ops wm8993_ops = { + .set_sysclk = wm8993_set_sysclk, + .set_fmt = wm8993_set_dai_fmt, + .hw_params = wm8993_hw_params, + .digital_mute = wm8993_digital_mute, + .set_pll = wm8993_set_fll, +}; + +#define WM8993_RATES SNDRV_PCM_RATE_8000_48000 + +#define WM8993_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +struct snd_soc_dai wm8993_dai = { + .name = "WM8993", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8993_RATES, + .formats = WM8993_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8993_RATES, + .formats = WM8993_FORMATS, + }, + .ops = &wm8993_ops, + .symmetric_rates = 1, +}; +EXPORT_SYMBOL_GPL(wm8993_dai); + +static struct snd_soc_codec *wm8993_codec; + +static int wm8993_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct wm8993_priv *wm8993; + int ret = 0; + + if (!wm8993_codec) { + dev_err(&pdev->dev, "I2C device not yet probed\n"); + goto err; + } + + socdev->card->codec = wm8993_codec; + codec = wm8993_codec; + wm8993 = codec->private_data; + + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms\n"); + goto err; + } + + snd_soc_add_controls(codec, wm8993_snd_controls, + ARRAY_SIZE(wm8993_snd_controls)); + if (wm8993->pdata.num_retune_configs != 0) { + dev_dbg(codec->dev, "Using ReTune Mobile\n"); + } else { + dev_dbg(codec->dev, "No ReTune Mobile, using normal EQ\n"); + snd_soc_add_controls(codec, wm8993_eq_controls, + ARRAY_SIZE(wm8993_eq_controls)); + } + + snd_soc_dapm_new_controls(codec, wm8993_dapm_widgets, + ARRAY_SIZE(wm8993_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes)); + + if (wm8993->pdata.lineout1_diff) + snd_soc_dapm_add_routes(codec, + lineout1_diff_routes, + ARRAY_SIZE(lineout1_diff_routes)); + else + snd_soc_dapm_add_routes(codec, + lineout1_se_routes, + ARRAY_SIZE(lineout1_se_routes)); + + if (wm8993->pdata.lineout2_diff) + snd_soc_dapm_add_routes(codec, + lineout2_diff_routes, + ARRAY_SIZE(lineout2_diff_routes)); + else + snd_soc_dapm_add_routes(codec, + lineout2_se_routes, + ARRAY_SIZE(lineout2_se_routes)); + + snd_soc_dapm_new_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card\n"); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +err: + return ret; +} + +static int wm8993_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8993 = { + .probe = wm8993_probe, + .remove = wm8993_remove, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993); + +static int wm8993_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8993_priv *wm8993; + struct snd_soc_codec *codec; + unsigned int val; + int ret; + + if (wm8993_codec) { + dev_err(&i2c->dev, "A WM8993 is already registered\n"); + return -EINVAL; + } + + wm8993 = kzalloc(sizeof(struct wm8993_priv), GFP_KERNEL); + if (wm8993 == NULL) + return -ENOMEM; + + codec = &wm8993->codec; + if (i2c->dev.platform_data) + memcpy(&wm8993->pdata, i2c->dev.platform_data, + sizeof(wm8993->pdata)); + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->name = "WM8993"; + codec->read = wm8993_read; + codec->write = wm8993_write; + codec->hw_write = (hw_write_t)i2c_master_send; + codec->reg_cache = wm8993->reg_cache; + codec->reg_cache_size = ARRAY_SIZE(wm8993->reg_cache); + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8993_set_bias_level; + codec->dai = &wm8993_dai; + codec->num_dai = 1; + codec->private_data = wm8993; + + memcpy(wm8993->reg_cache, wm8993_reg_defaults, + sizeof(wm8993->reg_cache)); + + i2c_set_clientdata(i2c, wm8993); + codec->control_data = i2c; + wm8993_codec = codec; + + codec->dev = &i2c->dev; + + val = wm8993_read_hw(codec, WM8993_SOFTWARE_RESET); + if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) { + dev_err(codec->dev, "Invalid ID register value %x\n", val); + ret = -EINVAL; + goto err; + } + + ret = wm8993_write(codec, WM8993_SOFTWARE_RESET, 0xffff); + if (ret != 0) + goto err; + + /* By default we're using the output mixers */ + wm8993->class_w_users = 2; + + /* Latch volume update bits and default ZC on */ + snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME, + WM8993_IN1_VU, WM8993_IN1_VU); + snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, + WM8993_IN1_VU, WM8993_IN1_VU); + snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_3_4_VOLUME, + WM8993_IN2_VU, WM8993_IN2_VU); + snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, + WM8993_IN2_VU, WM8993_IN2_VU); + + snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT, + WM8993_SPKOUT_VU, WM8993_SPKOUT_VU); + + snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME, + WM8993_HPOUT1L_ZC, WM8993_HPOUT1L_ZC); + snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME, + WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC, + WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC); + + snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME, + WM8993_MIXOUTL_ZC, WM8993_MIXOUTL_ZC); + snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME, + WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU, + WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU); + + snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME, + WM8993_DAC_VU, WM8993_DAC_VU); + snd_soc_update_bits(codec, WM8993_RIGHT_ADC_DIGITAL_VOLUME, + WM8993_ADC_VU, WM8993_ADC_VU); + + /* Manualy manage the HPOUT sequencing for independent stereo + * control. */ + snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0, + WM8993_HPOUT1_AUTO_PU, 0); + + /* Use automatic clock configuration */ + snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0); + + if (!wm8993->pdata.lineout1_diff) + snd_soc_update_bits(codec, WM8993_LINE_MIXER1, + WM8993_LINEOUT1_MODE, + WM8993_LINEOUT1_MODE); + if (!wm8993->pdata.lineout2_diff) + snd_soc_update_bits(codec, WM8993_LINE_MIXER2, + WM8993_LINEOUT2_MODE, + WM8993_LINEOUT2_MODE); + + if (wm8993->pdata.lineout1fb) + snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, + WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB); + + if (wm8993->pdata.lineout2fb) + snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, + WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB); + + /* Apply the microphone bias/detection configuration - the + * platform data is directly applicable to the register. */ + snd_soc_update_bits(codec, WM8993_MICBIAS, + WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK | + WM8993_MICB1_LVL | WM8993_MICB2_LVL, + wm8993->pdata.jd_scthr << WM8993_JD_SCTHR_SHIFT | + wm8993->pdata.jd_thr << WM8993_JD_THR_SHIFT | + wm8993->pdata.micbias1_lvl | + wm8993->pdata.micbias1_lvl << 1); + + ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + if (ret != 0) + goto err; + + wm8993_dai.dev = codec->dev; + + ret = snd_soc_register_dai(&wm8993_dai); + if (ret != 0) + goto err_bias; + + ret = snd_soc_register_codec(codec); + + return 0; + +err_bias: + wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); +err: + wm8993_codec = NULL; + kfree(wm8993); + return ret; +} + +static int wm8993_i2c_remove(struct i2c_client *client) +{ + struct wm8993_priv *wm8993 = i2c_get_clientdata(client); + + snd_soc_unregister_codec(&wm8993->codec); + snd_soc_unregister_dai(&wm8993_dai); + + wm8993_set_bias_level(&wm8993->codec, SND_SOC_BIAS_OFF); + kfree(wm8993); + + return 0; +} + +static const struct i2c_device_id wm8993_i2c_id[] = { + { "wm8993", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id); + +static struct i2c_driver wm8993_i2c_driver = { + .driver = { + .name = "WM8993", + .owner = THIS_MODULE, + }, + .probe = wm8993_i2c_probe, + .remove = wm8993_i2c_remove, + .id_table = wm8993_i2c_id, +}; + + +static int __init wm8993_modinit(void) +{ + int ret; + + ret = i2c_add_driver(&wm8993_i2c_driver); + if (ret != 0) + pr_err("WM8993: Unable to register I2C driver: %d\n", ret); + + return ret; +} +module_init(wm8993_modinit); + +static void __exit wm8993_exit(void) +{ + i2c_del_driver(&wm8993_i2c_driver); +} +module_exit(wm8993_exit); + + +MODULE_DESCRIPTION("ASoC WM8993 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8993.h b/sound/soc/codecs/wm8993.h new file mode 100644 index 0000000..30e71ca --- /dev/null +++ b/sound/soc/codecs/wm8993.h @@ -0,0 +1,2132 @@ +#ifndef WM8993_H +#define WM8993_H + +extern struct snd_soc_dai wm8993_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8993; + +#define WM8993_SYSCLK_MCLK 1 +#define WM8993_SYSCLK_FLL 2 + +#define WM8993_FLL_MCLK 1 +#define WM8993_FLL_BCLK 2 +#define WM8993_FLL_LRCLK 3 + +/* + * Register values. + */ +#define WM8993_SOFTWARE_RESET 0x00 +#define WM8993_POWER_MANAGEMENT_1 0x01 +#define WM8993_POWER_MANAGEMENT_2 0x02 +#define WM8993_POWER_MANAGEMENT_3 0x03 +#define WM8993_AUDIO_INTERFACE_1 0x04 +#define WM8993_AUDIO_INTERFACE_2 0x05 +#define WM8993_CLOCKING_1 0x06 +#define WM8993_CLOCKING_2 0x07 +#define WM8993_AUDIO_INTERFACE_3 0x08 +#define WM8993_AUDIO_INTERFACE_4 0x09 +#define WM8993_DAC_CTRL 0x0A +#define WM8993_LEFT_DAC_DIGITAL_VOLUME 0x0B +#define WM8993_RIGHT_DAC_DIGITAL_VOLUME 0x0C +#define WM8993_DIGITAL_SIDE_TONE 0x0D +#define WM8993_ADC_CTRL 0x0E +#define WM8993_LEFT_ADC_DIGITAL_VOLUME 0x0F +#define WM8993_RIGHT_ADC_DIGITAL_VOLUME 0x10 +#define WM8993_GPIO_CTRL_1 0x12 +#define WM8993_GPIO1 0x13 +#define WM8993_IRQ_DEBOUNCE 0x14 +#define WM8993_GPIOCTRL_2 0x16 +#define WM8993_GPIO_POL 0x17 +#define WM8993_LEFT_LINE_INPUT_1_2_VOLUME 0x18 +#define WM8993_LEFT_LINE_INPUT_3_4_VOLUME 0x19 +#define WM8993_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A +#define WM8993_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B +#define WM8993_LEFT_OUTPUT_VOLUME 0x1C +#define WM8993_RIGHT_OUTPUT_VOLUME 0x1D +#define WM8993_LINE_OUTPUTS_VOLUME 0x1E +#define WM8993_HPOUT2_VOLUME 0x1F +#define WM8993_LEFT_OPGA_VOLUME 0x20 +#define WM8993_RIGHT_OPGA_VOLUME 0x21 +#define WM8993_SPKMIXL_ATTENUATION 0x22 +#define WM8993_SPKMIXR_ATTENUATION 0x23 +#define WM8993_SPKOUT_MIXERS 0x24 +#define WM8993_SPKOUT_BOOST 0x25 +#define WM8993_SPEAKER_VOLUME_LEFT 0x26 +#define WM8993_SPEAKER_VOLUME_RIGHT 0x27 +#define WM8993_INPUT_MIXER2 0x28 +#define WM8993_INPUT_MIXER3 0x29 +#define WM8993_INPUT_MIXER4 0x2A +#define WM8993_INPUT_MIXER5 0x2B +#define WM8993_INPUT_MIXER6 0x2C +#define WM8993_OUTPUT_MIXER1 0x2D +#define WM8993_OUTPUT_MIXER2 0x2E +#define WM8993_OUTPUT_MIXER3 0x2F +#define WM8993_OUTPUT_MIXER4 0x30 +#define WM8993_OUTPUT_MIXER5 0x31 +#define WM8993_OUTPUT_MIXER6 0x32 +#define WM8993_HPOUT2_MIXER 0x33 +#define WM8993_LINE_MIXER1 0x34 +#define WM8993_LINE_MIXER2 0x35 +#define WM8993_SPEAKER_MIXER 0x36 +#define WM8993_ADDITIONAL_CONTROL 0x37 +#define WM8993_ANTIPOP1 0x38 +#define WM8993_ANTIPOP2 0x39 +#define WM8993_MICBIAS 0x3A +#define WM8993_FLL_CONTROL_1 0x3C +#define WM8993_FLL_CONTROL_2 0x3D +#define WM8993_FLL_CONTROL_3 0x3E +#define WM8993_FLL_CONTROL_4 0x3F +#define WM8993_FLL_CONTROL_5 0x40 +#define WM8993_CLOCKING_3 0x41 +#define WM8993_CLOCKING_4 0x42 +#define WM8993_MW_SLAVE_CONTROL 0x43 +#define WM8993_BUS_CONTROL_1 0x45 +#define WM8993_WRITE_SEQUENCER_0 0x46 +#define WM8993_WRITE_SEQUENCER_1 0x47 +#define WM8993_WRITE_SEQUENCER_2 0x48 +#define WM8993_WRITE_SEQUENCER_3 0x49 +#define WM8993_WRITE_SEQUENCER_4 0x4A +#define WM8993_WRITE_SEQUENCER_5 0x4B +#define WM8993_CHARGE_PUMP_1 0x4C +#define WM8993_CLASS_W_0 0x51 +#define WM8993_DC_SERVO_0 0x54 +#define WM8993_DC_SERVO_1 0x55 +#define WM8993_DC_SERVO_3 0x57 +#define WM8993_DC_SERVO_READBACK_0 0x58 +#define WM8993_DC_SERVO_READBACK_1 0x59 +#define WM8993_DC_SERVO_READBACK_2 0x5A +#define WM8993_ANALOGUE_HP_0 0x60 +#define WM8993_EQ1 0x62 +#define WM8993_EQ2 0x63 +#define WM8993_EQ3 0x64 +#define WM8993_EQ4 0x65 +#define WM8993_EQ5 0x66 +#define WM8993_EQ6 0x67 +#define WM8993_EQ7 0x68 +#define WM8993_EQ8 0x69 +#define WM8993_EQ9 0x6A +#define WM8993_EQ10 0x6B +#define WM8993_EQ11 0x6C +#define WM8993_EQ12 0x6D +#define WM8993_EQ13 0x6E +#define WM8993_EQ14 0x6F +#define WM8993_EQ15 0x70 +#define WM8993_EQ16 0x71 +#define WM8993_EQ17 0x72 +#define WM8993_EQ18 0x73 +#define WM8993_EQ19 0x74 +#define WM8993_EQ20 0x75 +#define WM8993_EQ21 0x76 +#define WM8993_EQ22 0x77 +#define WM8993_EQ23 0x78 +#define WM8993_EQ24 0x79 +#define WM8993_DIGITAL_PULLS 0x7A +#define WM8993_DRC_CONTROL_1 0x7B +#define WM8993_DRC_CONTROL_2 0x7C +#define WM8993_DRC_CONTROL_3 0x7D +#define WM8993_DRC_CONTROL_4 0x7E + +#define WM8993_REGISTER_COUNT 0x7F +#define WM8993_MAX_REGISTER 0x7E + +/* + * Field Definitions. + */ + +/* + * R0 (0x00) - Software Reset + */ +#define WM8993_SW_RESET_MASK 0xFFFF /* SW_RESET - [15:0] */ +#define WM8993_SW_RESET_SHIFT 0 /* SW_RESET - [15:0] */ +#define WM8993_SW_RESET_WIDTH 16 /* SW_RESET - [15:0] */ + +/* + * R1 (0x01) - Power Management (1) + */ +#define WM8993_SPKOUTR_ENA 0x2000 /* SPKOUTR_ENA */ +#define WM8993_SPKOUTR_ENA_MASK 0x2000 /* SPKOUTR_ENA */ +#define WM8993_SPKOUTR_ENA_SHIFT 13 /* SPKOUTR_ENA */ +#define WM8993_SPKOUTR_ENA_WIDTH 1 /* SPKOUTR_ENA */ +#define WM8993_SPKOUTL_ENA 0x1000 /* SPKOUTL_ENA */ +#define WM8993_SPKOUTL_ENA_MASK 0x1000 /* SPKOUTL_ENA */ +#define WM8993_SPKOUTL_ENA_SHIFT 12 /* SPKOUTL_ENA */ +#define WM8993_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */ +#define WM8993_HPOUT2_ENA 0x0800 /* HPOUT2_ENA */ +#define WM8993_HPOUT2_ENA_MASK 0x0800 /* HPOUT2_ENA */ +#define WM8993_HPOUT2_ENA_SHIFT 11 /* HPOUT2_ENA */ +#define WM8993_HPOUT2_ENA_WIDTH 1 /* HPOUT2_ENA */ +#define WM8993_HPOUT1L_ENA 0x0200 /* HPOUT1L_ENA */ +#define WM8993_HPOUT1L_ENA_MASK 0x0200 /* HPOUT1L_ENA */ +#define WM8993_HPOUT1L_ENA_SHIFT 9 /* HPOUT1L_ENA */ +#define WM8993_HPOUT1L_ENA_WIDTH 1 /* HPOUT1L_ENA */ +#define WM8993_HPOUT1R_ENA 0x0100 /* HPOUT1R_ENA */ +#define WM8993_HPOUT1R_ENA_MASK 0x0100 /* HPOUT1R_ENA */ +#define WM8993_HPOUT1R_ENA_SHIFT 8 /* HPOUT1R_ENA */ +#define WM8993_HPOUT1R_ENA_WIDTH 1 /* HPOUT1R_ENA */ +#define WM8993_MICB2_ENA 0x0020 /* MICB2_ENA */ +#define WM8993_MICB2_ENA_MASK 0x0020 /* MICB2_ENA */ +#define WM8993_MICB2_ENA_SHIFT 5 /* MICB2_ENA */ +#define WM8993_MICB2_ENA_WIDTH 1 /* MICB2_ENA */ +#define WM8993_MICB1_ENA 0x0010 /* MICB1_ENA */ +#define WM8993_MICB1_ENA_MASK 0x0010 /* MICB1_ENA */ +#define WM8993_MICB1_ENA_SHIFT 4 /* MICB1_ENA */ +#define WM8993_MICB1_ENA_WIDTH 1 /* MICB1_ENA */ +#define WM8993_VMID_SEL_MASK 0x0006 /* VMID_SEL - [2:1] */ +#define WM8993_VMID_SEL_SHIFT 1 /* VMID_SEL - [2:1] */ +#define WM8993_VMID_SEL_WIDTH 2 /* VMID_SEL - [2:1] */ +#define WM8993_BIAS_ENA 0x0001 /* BIAS_ENA */ +#define WM8993_BIAS_ENA_MASK 0x0001 /* BIAS_ENA */ +#define WM8993_BIAS_ENA_SHIFT 0 /* BIAS_ENA */ +#define WM8993_BIAS_ENA_WIDTH 1 /* BIAS_ENA */ + +/* + * R2 (0x02) - Power Management (2) + */ +#define WM8993_TSHUT_ENA 0x4000 /* TSHUT_ENA */ +#define WM8993_TSHUT_ENA_MASK 0x4000 /* TSHUT_ENA */ +#define WM8993_TSHUT_ENA_SHIFT 14 /* TSHUT_ENA */ +#define WM8993_TSHUT_ENA_WIDTH 1 /* TSHUT_ENA */ +#define WM8993_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */ +#define WM8993_TSHUT_OPDIS_MASK 0x2000 /* TSHUT_OPDIS */ +#define WM8993_TSHUT_OPDIS_SHIFT 13 /* TSHUT_OPDIS */ +#define WM8993_TSHUT_OPDIS_WIDTH 1 /* TSHUT_OPDIS */ +#define WM8993_OPCLK_ENA 0x0800 /* OPCLK_ENA */ +#define WM8993_OPCLK_ENA_MASK 0x0800 /* OPCLK_ENA */ +#define WM8993_OPCLK_ENA_SHIFT 11 /* OPCLK_ENA */ +#define WM8993_OPCLK_ENA_WIDTH 1 /* OPCLK_ENA */ +#define WM8993_MIXINL_ENA 0x0200 /* MIXINL_ENA */ +#define WM8993_MIXINL_ENA_MASK 0x0200 /* MIXINL_ENA */ +#define WM8993_MIXINL_ENA_SHIFT 9 /* MIXINL_ENA */ +#define WM8993_MIXINL_ENA_WIDTH 1 /* MIXINL_ENA */ +#define WM8993_MIXINR_ENA 0x0100 /* MIXINR_ENA */ +#define WM8993_MIXINR_ENA_MASK 0x0100 /* MIXINR_ENA */ +#define WM8993_MIXINR_ENA_SHIFT 8 /* MIXINR_ENA */ +#define WM8993_MIXINR_ENA_WIDTH 1 /* MIXINR_ENA */ +#define WM8993_IN2L_ENA 0x0080 /* IN2L_ENA */ +#define WM8993_IN2L_ENA_MASK 0x0080 /* IN2L_ENA */ +#define WM8993_IN2L_ENA_SHIFT 7 /* IN2L_ENA */ +#define WM8993_IN2L_ENA_WIDTH 1 /* IN2L_ENA */ +#define WM8993_IN1L_ENA 0x0040 /* IN1L_ENA */ +#define WM8993_IN1L_ENA_MASK 0x0040 /* IN1L_ENA */ +#define WM8993_IN1L_ENA_SHIFT 6 /* IN1L_ENA */ +#define WM8993_IN1L_ENA_WIDTH 1 /* IN1L_ENA */ +#define WM8993_IN2R_ENA 0x0020 /* IN2R_ENA */ +#define WM8993_IN2R_ENA_MASK 0x0020 /* IN2R_ENA */ +#define WM8993_IN2R_ENA_SHIFT 5 /* IN2R_ENA */ +#define WM8993_IN2R_ENA_WIDTH 1 /* IN2R_ENA */ +#define WM8993_IN1R_ENA 0x0010 /* IN1R_ENA */ +#define WM8993_IN1R_ENA_MASK 0x0010 /* IN1R_ENA */ +#define WM8993_IN1R_ENA_SHIFT 4 /* IN1R_ENA */ +#define WM8993_IN1R_ENA_WIDTH 1 /* IN1R_ENA */ +#define WM8993_ADCL_ENA 0x0002 /* ADCL_ENA */ +#define WM8993_ADCL_ENA_MASK 0x0002 /* ADCL_ENA */ +#define WM8993_ADCL_ENA_SHIFT 1 /* ADCL_ENA */ +#define WM8993_ADCL_ENA_WIDTH 1 /* ADCL_ENA */ +#define WM8993_ADCR_ENA 0x0001 /* ADCR_ENA */ +#define WM8993_ADCR_ENA_MASK 0x0001 /* ADCR_ENA */ +#define WM8993_ADCR_ENA_SHIFT 0 /* ADCR_ENA */ +#define WM8993_ADCR_ENA_WIDTH 1 /* ADCR_ENA */ + +/* + * R3 (0x03) - Power Management (3) + */ +#define WM8993_LINEOUT1N_ENA 0x2000 /* LINEOUT1N_ENA */ +#define WM8993_LINEOUT1N_ENA_MASK 0x2000 /* LINEOUT1N_ENA */ +#define WM8993_LINEOUT1N_ENA_SHIFT 13 /* LINEOUT1N_ENA */ +#define WM8993_LINEOUT1N_ENA_WIDTH 1 /* LINEOUT1N_ENA */ +#define WM8993_LINEOUT1P_ENA 0x1000 /* LINEOUT1P_ENA */ +#define WM8993_LINEOUT1P_ENA_MASK 0x1000 /* LINEOUT1P_ENA */ +#define WM8993_LINEOUT1P_ENA_SHIFT 12 /* LINEOUT1P_ENA */ +#define WM8993_LINEOUT1P_ENA_WIDTH 1 /* LINEOUT1P_ENA */ +#define WM8993_LINEOUT2N_ENA 0x0800 /* LINEOUT2N_ENA */ +#define WM8993_LINEOUT2N_ENA_MASK 0x0800 /* LINEOUT2N_ENA */ +#define WM8993_LINEOUT2N_ENA_SHIFT 11 /* LINEOUT2N_ENA */ +#define WM8993_LINEOUT2N_ENA_WIDTH 1 /* LINEOUT2N_ENA */ +#define WM8993_LINEOUT2P_ENA 0x0400 /* LINEOUT2P_ENA */ +#define WM8993_LINEOUT2P_ENA_MASK 0x0400 /* LINEOUT2P_ENA */ +#define WM8993_LINEOUT2P_ENA_SHIFT 10 /* LINEOUT2P_ENA */ +#define WM8993_LINEOUT2P_ENA_WIDTH 1 /* LINEOUT2P_ENA */ +#define WM8993_SPKRVOL_ENA 0x0200 /* SPKRVOL_ENA */ +#define WM8993_SPKRVOL_ENA_MASK 0x0200 /* SPKRVOL_ENA */ +#define WM8993_SPKRVOL_ENA_SHIFT 9 /* SPKRVOL_ENA */ +#define WM8993_SPKRVOL_ENA_WIDTH 1 /* SPKRVOL_ENA */ +#define WM8993_SPKLVOL_ENA 0x0100 /* SPKLVOL_ENA */ +#define WM8993_SPKLVOL_ENA_MASK 0x0100 /* SPKLVOL_ENA */ +#define WM8993_SPKLVOL_ENA_SHIFT 8 /* SPKLVOL_ENA */ +#define WM8993_SPKLVOL_ENA_WIDTH 1 /* SPKLVOL_ENA */ +#define WM8993_MIXOUTLVOL_ENA 0x0080 /* MIXOUTLVOL_ENA */ +#define WM8993_MIXOUTLVOL_ENA_MASK 0x0080 /* MIXOUTLVOL_ENA */ +#define WM8993_MIXOUTLVOL_ENA_SHIFT 7 /* MIXOUTLVOL_ENA */ +#define WM8993_MIXOUTLVOL_ENA_WIDTH 1 /* MIXOUTLVOL_ENA */ +#define WM8993_MIXOUTRVOL_ENA 0x0040 /* MIXOUTRVOL_ENA */ +#define WM8993_MIXOUTRVOL_ENA_MASK 0x0040 /* MIXOUTRVOL_ENA */ +#define WM8993_MIXOUTRVOL_ENA_SHIFT 6 /* MIXOUTRVOL_ENA */ +#define WM8993_MIXOUTRVOL_ENA_WIDTH 1 /* MIXOUTRVOL_ENA */ +#define WM8993_MIXOUTL_ENA 0x0020 /* MIXOUTL_ENA */ +#define WM8993_MIXOUTL_ENA_MASK 0x0020 /* MIXOUTL_ENA */ +#define WM8993_MIXOUTL_ENA_SHIFT 5 /* MIXOUTL_ENA */ +#define WM8993_MIXOUTL_ENA_WIDTH 1 /* MIXOUTL_ENA */ +#define WM8993_MIXOUTR_ENA 0x0010 /* MIXOUTR_ENA */ +#define WM8993_MIXOUTR_ENA_MASK 0x0010 /* MIXOUTR_ENA */ +#define WM8993_MIXOUTR_ENA_SHIFT 4 /* MIXOUTR_ENA */ +#define WM8993_MIXOUTR_ENA_WIDTH 1 /* MIXOUTR_ENA */ +#define WM8993_DACL_ENA 0x0002 /* DACL_ENA */ +#define WM8993_DACL_ENA_MASK 0x0002 /* DACL_ENA */ +#define WM8993_DACL_ENA_SHIFT 1 /* DACL_ENA */ +#define WM8993_DACL_ENA_WIDTH 1 /* DACL_ENA */ +#define WM8993_DACR_ENA 0x0001 /* DACR_ENA */ +#define WM8993_DACR_ENA_MASK 0x0001 /* DACR_ENA */ +#define WM8993_DACR_ENA_SHIFT 0 /* DACR_ENA */ +#define WM8993_DACR_ENA_WIDTH 1 /* DACR_ENA */ + +/* + * R4 (0x04) - Audio Interface (1) + */ +#define WM8993_AIFADCL_SRC 0x8000 /* AIFADCL_SRC */ +#define WM8993_AIFADCL_SRC_MASK 0x8000 /* AIFADCL_SRC */ +#define WM8993_AIFADCL_SRC_SHIFT 15 /* AIFADCL_SRC */ +#define WM8993_AIFADCL_SRC_WIDTH 1 /* AIFADCL_SRC */ +#define WM8993_AIFADCR_SRC 0x4000 /* AIFADCR_SRC */ +#define WM8993_AIFADCR_SRC_MASK 0x4000 /* AIFADCR_SRC */ +#define WM8993_AIFADCR_SRC_SHIFT 14 /* AIFADCR_SRC */ +#define WM8993_AIFADCR_SRC_WIDTH 1 /* AIFADCR_SRC */ +#define WM8993_AIFADC_TDM 0x2000 /* AIFADC_TDM */ +#define WM8993_AIFADC_TDM_MASK 0x2000 /* AIFADC_TDM */ +#define WM8993_AIFADC_TDM_SHIFT 13 /* AIFADC_TDM */ +#define WM8993_AIFADC_TDM_WIDTH 1 /* AIFADC_TDM */ +#define WM8993_AIFADC_TDM_CHAN 0x1000 /* AIFADC_TDM_CHAN */ +#define WM8993_AIFADC_TDM_CHAN_MASK 0x1000 /* AIFADC_TDM_CHAN */ +#define WM8993_AIFADC_TDM_CHAN_SHIFT 12 /* AIFADC_TDM_CHAN */ +#define WM8993_AIFADC_TDM_CHAN_WIDTH 1 /* AIFADC_TDM_CHAN */ +#define WM8993_BCLK_DIR 0x0200 /* BCLK_DIR */ +#define WM8993_BCLK_DIR_MASK 0x0200 /* BCLK_DIR */ +#define WM8993_BCLK_DIR_SHIFT 9 /* BCLK_DIR */ +#define WM8993_BCLK_DIR_WIDTH 1 /* BCLK_DIR */ +#define WM8993_AIF_BCLK_INV 0x0100 /* AIF_BCLK_INV */ +#define WM8993_AIF_BCLK_INV_MASK 0x0100 /* AIF_BCLK_INV */ +#define WM8993_AIF_BCLK_INV_SHIFT 8 /* AIF_BCLK_INV */ +#define WM8993_AIF_BCLK_INV_WIDTH 1 /* AIF_BCLK_INV */ +#define WM8993_AIF_LRCLK_INV 0x0080 /* AIF_LRCLK_INV */ +#define WM8993_AIF_LRCLK_INV_MASK 0x0080 /* AIF_LRCLK_INV */ +#define WM8993_AIF_LRCLK_INV_SHIFT 7 /* AIF_LRCLK_INV */ +#define WM8993_AIF_LRCLK_INV_WIDTH 1 /* AIF_LRCLK_INV */ +#define WM8993_AIF_WL_MASK 0x0060 /* AIF_WL - [6:5] */ +#define WM8993_AIF_WL_SHIFT 5 /* AIF_WL - [6:5] */ +#define WM8993_AIF_WL_WIDTH 2 /* AIF_WL - [6:5] */ +#define WM8993_AIF_FMT_MASK 0x0018 /* AIF_FMT - [4:3] */ +#define WM8993_AIF_FMT_SHIFT 3 /* AIF_FMT - [4:3] */ +#define WM8993_AIF_FMT_WIDTH 2 /* AIF_FMT - [4:3] */ + +/* + * R5 (0x05) - Audio Interface (2) + */ +#define WM8993_AIFDACL_SRC 0x8000 /* AIFDACL_SRC */ +#define WM8993_AIFDACL_SRC_MASK 0x8000 /* AIFDACL_SRC */ +#define WM8993_AIFDACL_SRC_SHIFT 15 /* AIFDACL_SRC */ +#define WM8993_AIFDACL_SRC_WIDTH 1 /* AIFDACL_SRC */ +#define WM8993_AIFDACR_SRC 0x4000 /* AIFDACR_SRC */ +#define WM8993_AIFDACR_SRC_MASK 0x4000 /* AIFDACR_SRC */ +#define WM8993_AIFDACR_SRC_SHIFT 14 /* AIFDACR_SRC */ +#define WM8993_AIFDACR_SRC_WIDTH 1 /* AIFDACR_SRC */ +#define WM8993_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */ +#define WM8993_AIFDAC_TDM_MASK 0x2000 /* AIFDAC_TDM */ +#define WM8993_AIFDAC_TDM_SHIFT 13 /* AIFDAC_TDM */ +#define WM8993_AIFDAC_TDM_WIDTH 1 /* AIFDAC_TDM */ +#define WM8993_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */ +#define WM8993_AIFDAC_TDM_CHAN_MASK 0x1000 /* AIFDAC_TDM_CHAN */ +#define WM8993_AIFDAC_TDM_CHAN_SHIFT 12 /* AIFDAC_TDM_CHAN */ +#define WM8993_AIFDAC_TDM_CHAN_WIDTH 1 /* AIFDAC_TDM_CHAN */ +#define WM8993_DAC_BOOST_MASK 0x0C00 /* DAC_BOOST - [11:10] */ +#define WM8993_DAC_BOOST_SHIFT 10 /* DAC_BOOST - [11:10] */ +#define WM8993_DAC_BOOST_WIDTH 2 /* DAC_BOOST - [11:10] */ +#define WM8993_DAC_COMP 0x0010 /* DAC_COMP */ +#define WM8993_DAC_COMP_MASK 0x0010 /* DAC_COMP */ +#define WM8993_DAC_COMP_SHIFT 4 /* DAC_COMP */ +#define WM8993_DAC_COMP_WIDTH 1 /* DAC_COMP */ +#define WM8993_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */ +#define WM8993_DAC_COMPMODE_MASK 0x0008 /* DAC_COMPMODE */ +#define WM8993_DAC_COMPMODE_SHIFT 3 /* DAC_COMPMODE */ +#define WM8993_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */ +#define WM8993_ADC_COMP 0x0004 /* ADC_COMP */ +#define WM8993_ADC_COMP_MASK 0x0004 /* ADC_COMP */ +#define WM8993_ADC_COMP_SHIFT 2 /* ADC_COMP */ +#define WM8993_ADC_COMP_WIDTH 1 /* ADC_COMP */ +#define WM8993_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */ +#define WM8993_ADC_COMPMODE_MASK 0x0002 /* ADC_COMPMODE */ +#define WM8993_ADC_COMPMODE_SHIFT 1 /* ADC_COMPMODE */ +#define WM8993_ADC_COMPMODE_WIDTH 1 /* ADC_COMPMODE */ +#define WM8993_LOOPBACK 0x0001 /* LOOPBACK */ +#define WM8993_LOOPBACK_MASK 0x0001 /* LOOPBACK */ +#define WM8993_LOOPBACK_SHIFT 0 /* LOOPBACK */ +#define WM8993_LOOPBACK_WIDTH 1 /* LOOPBACK */ + +/* + * R6 (0x06) - Clocking 1 + */ +#define WM8993_TOCLK_RATE 0x8000 /* TOCLK_RATE */ +#define WM8993_TOCLK_RATE_MASK 0x8000 /* TOCLK_RATE */ +#define WM8993_TOCLK_RATE_SHIFT 15 /* TOCLK_RATE */ +#define WM8993_TOCLK_RATE_WIDTH 1 /* TOCLK_RATE */ +#define WM8993_TOCLK_ENA 0x4000 /* TOCLK_ENA */ +#define WM8993_TOCLK_ENA_MASK 0x4000 /* TOCLK_ENA */ +#define WM8993_TOCLK_ENA_SHIFT 14 /* TOCLK_ENA */ +#define WM8993_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */ +#define WM8993_OPCLK_DIV_MASK 0x1E00 /* OPCLK_DIV - [12:9] */ +#define WM8993_OPCLK_DIV_SHIFT 9 /* OPCLK_DIV - [12:9] */ +#define WM8993_OPCLK_DIV_WIDTH 4 /* OPCLK_DIV - [12:9] */ +#define WM8993_DCLK_DIV_MASK 0x01C0 /* DCLK_DIV - [8:6] */ +#define WM8993_DCLK_DIV_SHIFT 6 /* DCLK_DIV - [8:6] */ +#define WM8993_DCLK_DIV_WIDTH 3 /* DCLK_DIV - [8:6] */ +#define WM8993_BCLK_DIV_MASK 0x001E /* BCLK_DIV - [4:1] */ +#define WM8993_BCLK_DIV_SHIFT 1 /* BCLK_DIV - [4:1] */ +#define WM8993_BCLK_DIV_WIDTH 4 /* BCLK_DIV - [4:1] */ + +/* + * R7 (0x07) - Clocking 2 + */ +#define WM8993_MCLK_SRC 0x8000 /* MCLK_SRC */ +#define WM8993_MCLK_SRC_MASK 0x8000 /* MCLK_SRC */ +#define WM8993_MCLK_SRC_SHIFT 15 /* MCLK_SRC */ +#define WM8993_MCLK_SRC_WIDTH 1 /* MCLK_SRC */ +#define WM8993_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */ +#define WM8993_SYSCLK_SRC_MASK 0x4000 /* SYSCLK_SRC */ +#define WM8993_SYSCLK_SRC_SHIFT 14 /* SYSCLK_SRC */ +#define WM8993_SYSCLK_SRC_WIDTH 1 /* SYSCLK_SRC */ +#define WM8993_MCLK_DIV 0x1000 /* MCLK_DIV */ +#define WM8993_MCLK_DIV_MASK 0x1000 /* MCLK_DIV */ +#define WM8993_MCLK_DIV_SHIFT 12 /* MCLK_DIV */ +#define WM8993_MCLK_DIV_WIDTH 1 /* MCLK_DIV */ +#define WM8993_MCLK_INV 0x0400 /* MCLK_INV */ +#define WM8993_MCLK_INV_MASK 0x0400 /* MCLK_INV */ +#define WM8993_MCLK_INV_SHIFT 10 /* MCLK_INV */ +#define WM8993_MCLK_INV_WIDTH 1 /* MCLK_INV */ +#define WM8993_ADC_DIV_MASK 0x00E0 /* ADC_DIV - [7:5] */ +#define WM8993_ADC_DIV_SHIFT 5 /* ADC_DIV - [7:5] */ +#define WM8993_ADC_DIV_WIDTH 3 /* ADC_DIV - [7:5] */ +#define WM8993_DAC_DIV_MASK 0x001C /* DAC_DIV - [4:2] */ +#define WM8993_DAC_DIV_SHIFT 2 /* DAC_DIV - [4:2] */ +#define WM8993_DAC_DIV_WIDTH 3 /* DAC_DIV - [4:2] */ + +/* + * R8 (0x08) - Audio Interface (3) + */ +#define WM8993_AIF_MSTR1 0x8000 /* AIF_MSTR1 */ +#define WM8993_AIF_MSTR1_MASK 0x8000 /* AIF_MSTR1 */ +#define WM8993_AIF_MSTR1_SHIFT 15 /* AIF_MSTR1 */ +#define WM8993_AIF_MSTR1_WIDTH 1 /* AIF_MSTR1 */ + +/* + * R9 (0x09) - Audio Interface (4) + */ +#define WM8993_AIF_TRIS 0x2000 /* AIF_TRIS */ +#define WM8993_AIF_TRIS_MASK 0x2000 /* AIF_TRIS */ +#define WM8993_AIF_TRIS_SHIFT 13 /* AIF_TRIS */ +#define WM8993_AIF_TRIS_WIDTH 1 /* AIF_TRIS */ +#define WM8993_LRCLK_DIR 0x0800 /* LRCLK_DIR */ +#define WM8993_LRCLK_DIR_MASK 0x0800 /* LRCLK_DIR */ +#define WM8993_LRCLK_DIR_SHIFT 11 /* LRCLK_DIR */ +#define WM8993_LRCLK_DIR_WIDTH 1 /* LRCLK_DIR */ +#define WM8993_LRCLK_RATE_MASK 0x07FF /* LRCLK_RATE - [10:0] */ +#define WM8993_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [10:0] */ +#define WM8993_LRCLK_RATE_WIDTH 11 /* LRCLK_RATE - [10:0] */ + +/* + * R10 (0x0A) - DAC CTRL + */ +#define WM8993_DAC_OSR128 0x2000 /* DAC_OSR128 */ +#define WM8993_DAC_OSR128_MASK 0x2000 /* DAC_OSR128 */ +#define WM8993_DAC_OSR128_SHIFT 13 /* DAC_OSR128 */ +#define WM8993_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */ +#define WM8993_DAC_MONO 0x0200 /* DAC_MONO */ +#define WM8993_DAC_MONO_MASK 0x0200 /* DAC_MONO */ +#define WM8993_DAC_MONO_SHIFT 9 /* DAC_MONO */ +#define WM8993_DAC_MONO_WIDTH 1 /* DAC_MONO */ +#define WM8993_DAC_SB_FILT 0x0100 /* DAC_SB_FILT */ +#define WM8993_DAC_SB_FILT_MASK 0x0100 /* DAC_SB_FILT */ +#define WM8993_DAC_SB_FILT_SHIFT 8 /* DAC_SB_FILT */ +#define WM8993_DAC_SB_FILT_WIDTH 1 /* DAC_SB_FILT */ +#define WM8993_DAC_MUTERATE 0x0080 /* DAC_MUTERATE */ +#define WM8993_DAC_MUTERATE_MASK 0x0080 /* DAC_MUTERATE */ +#define WM8993_DAC_MUTERATE_SHIFT 7 /* DAC_MUTERATE */ +#define WM8993_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */ +#define WM8993_DAC_UNMUTE_RAMP 0x0040 /* DAC_UNMUTE_RAMP */ +#define WM8993_DAC_UNMUTE_RAMP_MASK 0x0040 /* DAC_UNMUTE_RAMP */ +#define WM8993_DAC_UNMUTE_RAMP_SHIFT 6 /* DAC_UNMUTE_RAMP */ +#define WM8993_DAC_UNMUTE_RAMP_WIDTH 1 /* DAC_UNMUTE_RAMP */ +#define WM8993_DEEMPH_MASK 0x0030 /* DEEMPH - [5:4] */ +#define WM8993_DEEMPH_SHIFT 4 /* DEEMPH - [5:4] */ +#define WM8993_DEEMPH_WIDTH 2 /* DEEMPH - [5:4] */ +#define WM8993_DAC_MUTE 0x0004 /* DAC_MUTE */ +#define WM8993_DAC_MUTE_MASK 0x0004 /* DAC_MUTE */ +#define WM8993_DAC_MUTE_SHIFT 2 /* DAC_MUTE */ +#define WM8993_DAC_MUTE_WIDTH 1 /* DAC_MUTE */ +#define WM8993_DACL_DATINV 0x0002 /* DACL_DATINV */ +#define WM8993_DACL_DATINV_MASK 0x0002 /* DACL_DATINV */ +#define WM8993_DACL_DATINV_SHIFT 1 /* DACL_DATINV */ +#define WM8993_DACL_DATINV_WIDTH 1 /* DACL_DATINV */ +#define WM8993_DACR_DATINV 0x0001 /* DACR_DATINV */ +#define WM8993_DACR_DATINV_MASK 0x0001 /* DACR_DATINV */ +#define WM8993_DACR_DATINV_SHIFT 0 /* DACR_DATINV */ +#define WM8993_DACR_DATINV_WIDTH 1 /* DACR_DATINV */ + +/* + * R11 (0x0B) - Left DAC Digital Volume + */ +#define WM8993_DAC_VU 0x0100 /* DAC_VU */ +#define WM8993_DAC_VU_MASK 0x0100 /* DAC_VU */ +#define WM8993_DAC_VU_SHIFT 8 /* DAC_VU */ +#define WM8993_DAC_VU_WIDTH 1 /* DAC_VU */ +#define WM8993_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */ +#define WM8993_DACL_VOL_SHIFT 0 /* DACL_VOL - [7:0] */ +#define WM8993_DACL_VOL_WIDTH 8 /* DACL_VOL - [7:0] */ + +/* + * R12 (0x0C) - Right DAC Digital Volume + */ +#define WM8993_DAC_VU 0x0100 /* DAC_VU */ +#define WM8993_DAC_VU_MASK 0x0100 /* DAC_VU */ +#define WM8993_DAC_VU_SHIFT 8 /* DAC_VU */ +#define WM8993_DAC_VU_WIDTH 1 /* DAC_VU */ +#define WM8993_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */ +#define WM8993_DACR_VOL_SHIFT 0 /* DACR_VOL - [7:0] */ +#define WM8993_DACR_VOL_WIDTH 8 /* DACR_VOL - [7:0] */ + +/* + * R13 (0x0D) - Digital Side Tone + */ +#define WM8993_ADCL_DAC_SVOL_MASK 0x1E00 /* ADCL_DAC_SVOL - [12:9] */ +#define WM8993_ADCL_DAC_SVOL_SHIFT 9 /* ADCL_DAC_SVOL - [12:9] */ +#define WM8993_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [12:9] */ +#define WM8993_ADCR_DAC_SVOL_MASK 0x01E0 /* ADCR_DAC_SVOL - [8:5] */ +#define WM8993_ADCR_DAC_SVOL_SHIFT 5 /* ADCR_DAC_SVOL - [8:5] */ +#define WM8993_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [8:5] */ +#define WM8993_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */ +#define WM8993_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */ +#define WM8993_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */ +#define WM8993_ADC_TO_DACR_MASK 0x0003 /* ADC_TO_DACR - [1:0] */ +#define WM8993_ADC_TO_DACR_SHIFT 0 /* ADC_TO_DACR - [1:0] */ +#define WM8993_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [1:0] */ + +/* + * R14 (0x0E) - ADC CTRL + */ +#define WM8993_ADC_OSR128 0x0200 /* ADC_OSR128 */ +#define WM8993_ADC_OSR128_MASK 0x0200 /* ADC_OSR128 */ +#define WM8993_ADC_OSR128_SHIFT 9 /* ADC_OSR128 */ +#define WM8993_ADC_OSR128_WIDTH 1 /* ADC_OSR128 */ +#define WM8993_ADC_HPF 0x0100 /* ADC_HPF */ +#define WM8993_ADC_HPF_MASK 0x0100 /* ADC_HPF */ +#define WM8993_ADC_HPF_SHIFT 8 /* ADC_HPF */ +#define WM8993_ADC_HPF_WIDTH 1 /* ADC_HPF */ +#define WM8993_ADC_HPF_CUT_MASK 0x0060 /* ADC_HPF_CUT - [6:5] */ +#define WM8993_ADC_HPF_CUT_SHIFT 5 /* ADC_HPF_CUT - [6:5] */ +#define WM8993_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [6:5] */ +#define WM8993_ADCL_DATINV 0x0002 /* ADCL_DATINV */ +#define WM8993_ADCL_DATINV_MASK 0x0002 /* ADCL_DATINV */ +#define WM8993_ADCL_DATINV_SHIFT 1 /* ADCL_DATINV */ +#define WM8993_ADCL_DATINV_WIDTH 1 /* ADCL_DATINV */ +#define WM8993_ADCR_DATINV 0x0001 /* ADCR_DATINV */ +#define WM8993_ADCR_DATINV_MASK 0x0001 /* ADCR_DATINV */ +#define WM8993_ADCR_DATINV_SHIFT 0 /* ADCR_DATINV */ +#define WM8993_ADCR_DATINV_WIDTH 1 /* ADCR_DATINV */ + +/* + * R15 (0x0F) - Left ADC Digital Volume + */ +#define WM8993_ADC_VU 0x0100 /* ADC_VU */ +#define WM8993_ADC_VU_MASK 0x0100 /* ADC_VU */ +#define WM8993_ADC_VU_SHIFT 8 /* ADC_VU */ +#define WM8993_ADC_VU_WIDTH 1 /* ADC_VU */ +#define WM8993_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */ +#define WM8993_ADCL_VOL_SHIFT 0 /* ADCL_VOL - [7:0] */ +#define WM8993_ADCL_VOL_WIDTH 8 /* ADCL_VOL - [7:0] */ + +/* + * R16 (0x10) - Right ADC Digital Volume + */ +#define WM8993_ADC_VU 0x0100 /* ADC_VU */ +#define WM8993_ADC_VU_MASK 0x0100 /* ADC_VU */ +#define WM8993_ADC_VU_SHIFT 8 /* ADC_VU */ +#define WM8993_ADC_VU_WIDTH 1 /* ADC_VU */ +#define WM8993_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */ +#define WM8993_ADCR_VOL_SHIFT 0 /* ADCR_VOL - [7:0] */ +#define WM8993_ADCR_VOL_WIDTH 8 /* ADCR_VOL - [7:0] */ + +/* + * R18 (0x12) - GPIO CTRL 1 + */ +#define WM8993_JD2_SC_EINT 0x8000 /* JD2_SC_EINT */ +#define WM8993_JD2_SC_EINT_MASK 0x8000 /* JD2_SC_EINT */ +#define WM8993_JD2_SC_EINT_SHIFT 15 /* JD2_SC_EINT */ +#define WM8993_JD2_SC_EINT_WIDTH 1 /* JD2_SC_EINT */ +#define WM8993_JD2_EINT 0x4000 /* JD2_EINT */ +#define WM8993_JD2_EINT_MASK 0x4000 /* JD2_EINT */ +#define WM8993_JD2_EINT_SHIFT 14 /* JD2_EINT */ +#define WM8993_JD2_EINT_WIDTH 1 /* JD2_EINT */ +#define WM8993_WSEQ_EINT 0x2000 /* WSEQ_EINT */ +#define WM8993_WSEQ_EINT_MASK 0x2000 /* WSEQ_EINT */ +#define WM8993_WSEQ_EINT_SHIFT 13 /* WSEQ_EINT */ +#define WM8993_WSEQ_EINT_WIDTH 1 /* WSEQ_EINT */ +#define WM8993_IRQ 0x1000 /* IRQ */ +#define WM8993_IRQ_MASK 0x1000 /* IRQ */ +#define WM8993_IRQ_SHIFT 12 /* IRQ */ +#define WM8993_IRQ_WIDTH 1 /* IRQ */ +#define WM8993_TEMPOK_EINT 0x0800 /* TEMPOK_EINT */ +#define WM8993_TEMPOK_EINT_MASK 0x0800 /* TEMPOK_EINT */ +#define WM8993_TEMPOK_EINT_SHIFT 11 /* TEMPOK_EINT */ +#define WM8993_TEMPOK_EINT_WIDTH 1 /* TEMPOK_EINT */ +#define WM8993_JD1_SC_EINT 0x0400 /* JD1_SC_EINT */ +#define WM8993_JD1_SC_EINT_MASK 0x0400 /* JD1_SC_EINT */ +#define WM8993_JD1_SC_EINT_SHIFT 10 /* JD1_SC_EINT */ +#define WM8993_JD1_SC_EINT_WIDTH 1 /* JD1_SC_EINT */ +#define WM8993_JD1_EINT 0x0200 /* JD1_EINT */ +#define WM8993_JD1_EINT_MASK 0x0200 /* JD1_EINT */ +#define WM8993_JD1_EINT_SHIFT 9 /* JD1_EINT */ +#define WM8993_JD1_EINT_WIDTH 1 /* JD1_EINT */ +#define WM8993_FLL_LOCK_EINT 0x0100 /* FLL_LOCK_EINT */ +#define WM8993_FLL_LOCK_EINT_MASK 0x0100 /* FLL_LOCK_EINT */ +#define WM8993_FLL_LOCK_EINT_SHIFT 8 /* FLL_LOCK_EINT */ +#define WM8993_FLL_LOCK_EINT_WIDTH 1 /* FLL_LOCK_EINT */ +#define WM8993_GPI8_EINT 0x0080 /* GPI8_EINT */ +#define WM8993_GPI8_EINT_MASK 0x0080 /* GPI8_EINT */ +#define WM8993_GPI8_EINT_SHIFT 7 /* GPI8_EINT */ +#define WM8993_GPI8_EINT_WIDTH 1 /* GPI8_EINT */ +#define WM8993_GPI7_EINT 0x0040 /* GPI7_EINT */ +#define WM8993_GPI7_EINT_MASK 0x0040 /* GPI7_EINT */ +#define WM8993_GPI7_EINT_SHIFT 6 /* GPI7_EINT */ +#define WM8993_GPI7_EINT_WIDTH 1 /* GPI7_EINT */ +#define WM8993_GPIO1_EINT 0x0001 /* GPIO1_EINT */ +#define WM8993_GPIO1_EINT_MASK 0x0001 /* GPIO1_EINT */ +#define WM8993_GPIO1_EINT_SHIFT 0 /* GPIO1_EINT */ +#define WM8993_GPIO1_EINT_WIDTH 1 /* GPIO1_EINT */ + +/* + * R19 (0x13) - GPIO1 + */ +#define WM8993_GPIO1_PU 0x0020 /* GPIO1_PU */ +#define WM8993_GPIO1_PU_MASK 0x0020 /* GPIO1_PU */ +#define WM8993_GPIO1_PU_SHIFT 5 /* GPIO1_PU */ +#define WM8993_GPIO1_PU_WIDTH 1 /* GPIO1_PU */ +#define WM8993_GPIO1_PD 0x0010 /* GPIO1_PD */ +#define WM8993_GPIO1_PD_MASK 0x0010 /* GPIO1_PD */ +#define WM8993_GPIO1_PD_SHIFT 4 /* GPIO1_PD */ +#define WM8993_GPIO1_PD_WIDTH 1 /* GPIO1_PD */ +#define WM8993_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */ +#define WM8993_GPIO1_SEL_SHIFT 0 /* GPIO1_SEL - [3:0] */ +#define WM8993_GPIO1_SEL_WIDTH 4 /* GPIO1_SEL - [3:0] */ + +/* + * R20 (0x14) - IRQ_DEBOUNCE + */ +#define WM8993_JD2_SC_DB 0x8000 /* JD2_SC_DB */ +#define WM8993_JD2_SC_DB_MASK 0x8000 /* JD2_SC_DB */ +#define WM8993_JD2_SC_DB_SHIFT 15 /* JD2_SC_DB */ +#define WM8993_JD2_SC_DB_WIDTH 1 /* JD2_SC_DB */ +#define WM8993_JD2_DB 0x4000 /* JD2_DB */ +#define WM8993_JD2_DB_MASK 0x4000 /* JD2_DB */ +#define WM8993_JD2_DB_SHIFT 14 /* JD2_DB */ +#define WM8993_JD2_DB_WIDTH 1 /* JD2_DB */ +#define WM8993_WSEQ_DB 0x2000 /* WSEQ_DB */ +#define WM8993_WSEQ_DB_MASK 0x2000 /* WSEQ_DB */ +#define WM8993_WSEQ_DB_SHIFT 13 /* WSEQ_DB */ +#define WM8993_WSEQ_DB_WIDTH 1 /* WSEQ_DB */ +#define WM8993_TEMPOK_DB 0x0800 /* TEMPOK_DB */ +#define WM8993_TEMPOK_DB_MASK 0x0800 /* TEMPOK_DB */ +#define WM8993_TEMPOK_DB_SHIFT 11 /* TEMPOK_DB */ +#define WM8993_TEMPOK_DB_WIDTH 1 /* TEMPOK_DB */ +#define WM8993_JD1_SC_DB 0x0400 /* JD1_SC_DB */ +#define WM8993_JD1_SC_DB_MASK 0x0400 /* JD1_SC_DB */ +#define WM8993_JD1_SC_DB_SHIFT 10 /* JD1_SC_DB */ +#define WM8993_JD1_SC_DB_WIDTH 1 /* JD1_SC_DB */ +#define WM8993_JD1_DB 0x0200 /* JD1_DB */ +#define WM8993_JD1_DB_MASK 0x0200 /* JD1_DB */ +#define WM8993_JD1_DB_SHIFT 9 /* JD1_DB */ +#define WM8993_JD1_DB_WIDTH 1 /* JD1_DB */ +#define WM8993_FLL_LOCK_DB 0x0100 /* FLL_LOCK_DB */ +#define WM8993_FLL_LOCK_DB_MASK 0x0100 /* FLL_LOCK_DB */ +#define WM8993_FLL_LOCK_DB_SHIFT 8 /* FLL_LOCK_DB */ +#define WM8993_FLL_LOCK_DB_WIDTH 1 /* FLL_LOCK_DB */ +#define WM8993_GPI8_DB 0x0080 /* GPI8_DB */ +#define WM8993_GPI8_DB_MASK 0x0080 /* GPI8_DB */ +#define WM8993_GPI8_DB_SHIFT 7 /* GPI8_DB */ +#define WM8993_GPI8_DB_WIDTH 1 /* GPI8_DB */ +#define WM8993_GPI7_DB 0x0008 /* GPI7_DB */ +#define WM8993_GPI7_DB_MASK 0x0008 /* GPI7_DB */ +#define WM8993_GPI7_DB_SHIFT 3 /* GPI7_DB */ +#define WM8993_GPI7_DB_WIDTH 1 /* GPI7_DB */ +#define WM8993_GPIO1_DB 0x0001 /* GPIO1_DB */ +#define WM8993_GPIO1_DB_MASK 0x0001 /* GPIO1_DB */ +#define WM8993_GPIO1_DB_SHIFT 0 /* GPIO1_DB */ +#define WM8993_GPIO1_DB_WIDTH 1 /* GPIO1_DB */ + +/* + * R22 (0x16) - GPIOCTRL 2 + */ +#define WM8993_IM_JD2_EINT 0x2000 /* IM_JD2_EINT */ +#define WM8993_IM_JD2_EINT_MASK 0x2000 /* IM_JD2_EINT */ +#define WM8993_IM_JD2_EINT_SHIFT 13 /* IM_JD2_EINT */ +#define WM8993_IM_JD2_EINT_WIDTH 1 /* IM_JD2_EINT */ +#define WM8993_IM_JD2_SC_EINT 0x1000 /* IM_JD2_SC_EINT */ +#define WM8993_IM_JD2_SC_EINT_MASK 0x1000 /* IM_JD2_SC_EINT */ +#define WM8993_IM_JD2_SC_EINT_SHIFT 12 /* IM_JD2_SC_EINT */ +#define WM8993_IM_JD2_SC_EINT_WIDTH 1 /* IM_JD2_SC_EINT */ +#define WM8993_IM_TEMPOK_EINT 0x0800 /* IM_TEMPOK_EINT */ +#define WM8993_IM_TEMPOK_EINT_MASK 0x0800 /* IM_TEMPOK_EINT */ +#define WM8993_IM_TEMPOK_EINT_SHIFT 11 /* IM_TEMPOK_EINT */ +#define WM8993_IM_TEMPOK_EINT_WIDTH 1 /* IM_TEMPOK_EINT */ +#define WM8993_IM_JD1_SC_EINT 0x0400 /* IM_JD1_SC_EINT */ +#define WM8993_IM_JD1_SC_EINT_MASK 0x0400 /* IM_JD1_SC_EINT */ +#define WM8993_IM_JD1_SC_EINT_SHIFT 10 /* IM_JD1_SC_EINT */ +#define WM8993_IM_JD1_SC_EINT_WIDTH 1 /* IM_JD1_SC_EINT */ +#define WM8993_IM_JD1_EINT 0x0200 /* IM_JD1_EINT */ +#define WM8993_IM_JD1_EINT_MASK 0x0200 /* IM_JD1_EINT */ +#define WM8993_IM_JD1_EINT_SHIFT 9 /* IM_JD1_EINT */ +#define WM8993_IM_JD1_EINT_WIDTH 1 /* IM_JD1_EINT */ +#define WM8993_IM_FLL_LOCK_EINT 0x0100 /* IM_FLL_LOCK_EINT */ +#define WM8993_IM_FLL_LOCK_EINT_MASK 0x0100 /* IM_FLL_LOCK_EINT */ +#define WM8993_IM_FLL_LOCK_EINT_SHIFT 8 /* IM_FLL_LOCK_EINT */ +#define WM8993_IM_FLL_LOCK_EINT_WIDTH 1 /* IM_FLL_LOCK_EINT */ +#define WM8993_IM_GPI8_EINT 0x0040 /* IM_GPI8_EINT */ +#define WM8993_IM_GPI8_EINT_MASK 0x0040 /* IM_GPI8_EINT */ +#define WM8993_IM_GPI8_EINT_SHIFT 6 /* IM_GPI8_EINT */ +#define WM8993_IM_GPI8_EINT_WIDTH 1 /* IM_GPI8_EINT */ +#define WM8993_IM_GPIO1_EINT 0x0020 /* IM_GPIO1_EINT */ +#define WM8993_IM_GPIO1_EINT_MASK 0x0020 /* IM_GPIO1_EINT */ +#define WM8993_IM_GPIO1_EINT_SHIFT 5 /* IM_GPIO1_EINT */ +#define WM8993_IM_GPIO1_EINT_WIDTH 1 /* IM_GPIO1_EINT */ +#define WM8993_GPI8_ENA 0x0010 /* GPI8_ENA */ +#define WM8993_GPI8_ENA_MASK 0x0010 /* GPI8_ENA */ +#define WM8993_GPI8_ENA_SHIFT 4 /* GPI8_ENA */ +#define WM8993_GPI8_ENA_WIDTH 1 /* GPI8_ENA */ +#define WM8993_IM_GPI7_EINT 0x0004 /* IM_GPI7_EINT */ +#define WM8993_IM_GPI7_EINT_MASK 0x0004 /* IM_GPI7_EINT */ +#define WM8993_IM_GPI7_EINT_SHIFT 2 /* IM_GPI7_EINT */ +#define WM8993_IM_GPI7_EINT_WIDTH 1 /* IM_GPI7_EINT */ +#define WM8993_IM_WSEQ_EINT 0x0002 /* IM_WSEQ_EINT */ +#define WM8993_IM_WSEQ_EINT_MASK 0x0002 /* IM_WSEQ_EINT */ +#define WM8993_IM_WSEQ_EINT_SHIFT 1 /* IM_WSEQ_EINT */ +#define WM8993_IM_WSEQ_EINT_WIDTH 1 /* IM_WSEQ_EINT */ +#define WM8993_GPI7_ENA 0x0001 /* GPI7_ENA */ +#define WM8993_GPI7_ENA_MASK 0x0001 /* GPI7_ENA */ +#define WM8993_GPI7_ENA_SHIFT 0 /* GPI7_ENA */ +#define WM8993_GPI7_ENA_WIDTH 1 /* GPI7_ENA */ + +/* + * R23 (0x17) - GPIO_POL + */ +#define WM8993_JD2_SC_POL 0x8000 /* JD2_SC_POL */ +#define WM8993_JD2_SC_POL_MASK 0x8000 /* JD2_SC_POL */ +#define WM8993_JD2_SC_POL_SHIFT 15 /* JD2_SC_POL */ +#define WM8993_JD2_SC_POL_WIDTH 1 /* JD2_SC_POL */ +#define WM8993_JD2_POL 0x4000 /* JD2_POL */ +#define WM8993_JD2_POL_MASK 0x4000 /* JD2_POL */ +#define WM8993_JD2_POL_SHIFT 14 /* JD2_POL */ +#define WM8993_JD2_POL_WIDTH 1 /* JD2_POL */ +#define WM8993_WSEQ_POL 0x2000 /* WSEQ_POL */ +#define WM8993_WSEQ_POL_MASK 0x2000 /* WSEQ_POL */ +#define WM8993_WSEQ_POL_SHIFT 13 /* WSEQ_POL */ +#define WM8993_WSEQ_POL_WIDTH 1 /* WSEQ_POL */ +#define WM8993_IRQ_POL 0x1000 /* IRQ_POL */ +#define WM8993_IRQ_POL_MASK 0x1000 /* IRQ_POL */ +#define WM8993_IRQ_POL_SHIFT 12 /* IRQ_POL */ +#define WM8993_IRQ_POL_WIDTH 1 /* IRQ_POL */ +#define WM8993_TEMPOK_POL 0x0800 /* TEMPOK_POL */ +#define WM8993_TEMPOK_POL_MASK 0x0800 /* TEMPOK_POL */ +#define WM8993_TEMPOK_POL_SHIFT 11 /* TEMPOK_POL */ +#define WM8993_TEMPOK_POL_WIDTH 1 /* TEMPOK_POL */ +#define WM8993_JD1_SC_POL 0x0400 /* JD1_SC_POL */ +#define WM8993_JD1_SC_POL_MASK 0x0400 /* JD1_SC_POL */ +#define WM8993_JD1_SC_POL_SHIFT 10 /* JD1_SC_POL */ +#define WM8993_JD1_SC_POL_WIDTH 1 /* JD1_SC_POL */ +#define WM8993_JD1_POL 0x0200 /* JD1_POL */ +#define WM8993_JD1_POL_MASK 0x0200 /* JD1_POL */ +#define WM8993_JD1_POL_SHIFT 9 /* JD1_POL */ +#define WM8993_JD1_POL_WIDTH 1 /* JD1_POL */ +#define WM8993_FLL_LOCK_POL 0x0100 /* FLL_LOCK_POL */ +#define WM8993_FLL_LOCK_POL_MASK 0x0100 /* FLL_LOCK_POL */ +#define WM8993_FLL_LOCK_POL_SHIFT 8 /* FLL_LOCK_POL */ +#define WM8993_FLL_LOCK_POL_WIDTH 1 /* FLL_LOCK_POL */ +#define WM8993_GPI8_POL 0x0080 /* GPI8_POL */ +#define WM8993_GPI8_POL_MASK 0x0080 /* GPI8_POL */ +#define WM8993_GPI8_POL_SHIFT 7 /* GPI8_POL */ +#define WM8993_GPI8_POL_WIDTH 1 /* GPI8_POL */ +#define WM8993_GPI7_POL 0x0040 /* GPI7_POL */ +#define WM8993_GPI7_POL_MASK 0x0040 /* GPI7_POL */ +#define WM8993_GPI7_POL_SHIFT 6 /* GPI7_POL */ +#define WM8993_GPI7_POL_WIDTH 1 /* GPI7_POL */ +#define WM8993_GPIO1_POL 0x0001 /* GPIO1_POL */ +#define WM8993_GPIO1_POL_MASK 0x0001 /* GPIO1_POL */ +#define WM8993_GPIO1_POL_SHIFT 0 /* GPIO1_POL */ +#define WM8993_GPIO1_POL_WIDTH 1 /* GPIO1_POL */ + +/* + * R24 (0x18) - Left Line Input 1&2 Volume + */ +#define WM8993_IN1_VU 0x0100 /* IN1_VU */ +#define WM8993_IN1_VU_MASK 0x0100 /* IN1_VU */ +#define WM8993_IN1_VU_SHIFT 8 /* IN1_VU */ +#define WM8993_IN1_VU_WIDTH 1 /* IN1_VU */ +#define WM8993_IN1L_MUTE 0x0080 /* IN1L_MUTE */ +#define WM8993_IN1L_MUTE_MASK 0x0080 /* IN1L_MUTE */ +#define WM8993_IN1L_MUTE_SHIFT 7 /* IN1L_MUTE */ +#define WM8993_IN1L_MUTE_WIDTH 1 /* IN1L_MUTE */ +#define WM8993_IN1L_ZC 0x0040 /* IN1L_ZC */ +#define WM8993_IN1L_ZC_MASK 0x0040 /* IN1L_ZC */ +#define WM8993_IN1L_ZC_SHIFT 6 /* IN1L_ZC */ +#define WM8993_IN1L_ZC_WIDTH 1 /* IN1L_ZC */ +#define WM8993_IN1L_VOL_MASK 0x001F /* IN1L_VOL - [4:0] */ +#define WM8993_IN1L_VOL_SHIFT 0 /* IN1L_VOL - [4:0] */ +#define WM8993_IN1L_VOL_WIDTH 5 /* IN1L_VOL - [4:0] */ + +/* + * R25 (0x19) - Left Line Input 3&4 Volume + */ +#define WM8993_IN2_VU 0x0100 /* IN2_VU */ +#define WM8993_IN2_VU_MASK 0x0100 /* IN2_VU */ +#define WM8993_IN2_VU_SHIFT 8 /* IN2_VU */ +#define WM8993_IN2_VU_WIDTH 1 /* IN2_VU */ +#define WM8993_IN2L_MUTE 0x0080 /* IN2L_MUTE */ +#define WM8993_IN2L_MUTE_MASK 0x0080 /* IN2L_MUTE */ +#define WM8993_IN2L_MUTE_SHIFT 7 /* IN2L_MUTE */ +#define WM8993_IN2L_MUTE_WIDTH 1 /* IN2L_MUTE */ +#define WM8993_IN2L_ZC 0x0040 /* IN2L_ZC */ +#define WM8993_IN2L_ZC_MASK 0x0040 /* IN2L_ZC */ +#define WM8993_IN2L_ZC_SHIFT 6 /* IN2L_ZC */ +#define WM8993_IN2L_ZC_WIDTH 1 /* IN2L_ZC */ +#define WM8993_IN2L_VOL_MASK 0x001F /* IN2L_VOL - [4:0] */ +#define WM8993_IN2L_VOL_SHIFT 0 /* IN2L_VOL - [4:0] */ +#define WM8993_IN2L_VOL_WIDTH 5 /* IN2L_VOL - [4:0] */ + +/* + * R26 (0x1A) - Right Line Input 1&2 Volume + */ +#define WM8993_IN1_VU 0x0100 /* IN1_VU */ +#define WM8993_IN1_VU_MASK 0x0100 /* IN1_VU */ +#define WM8993_IN1_VU_SHIFT 8 /* IN1_VU */ +#define WM8993_IN1_VU_WIDTH 1 /* IN1_VU */ +#define WM8993_IN1R_MUTE 0x0080 /* IN1R_MUTE */ +#define WM8993_IN1R_MUTE_MASK 0x0080 /* IN1R_MUTE */ +#define WM8993_IN1R_MUTE_SHIFT 7 /* IN1R_MUTE */ +#define WM8993_IN1R_MUTE_WIDTH 1 /* IN1R_MUTE */ +#define WM8993_IN1R_ZC 0x0040 /* IN1R_ZC */ +#define WM8993_IN1R_ZC_MASK 0x0040 /* IN1R_ZC */ +#define WM8993_IN1R_ZC_SHIFT 6 /* IN1R_ZC */ +#define WM8993_IN1R_ZC_WIDTH 1 /* IN1R_ZC */ +#define WM8993_IN1R_VOL_MASK 0x001F /* IN1R_VOL - [4:0] */ +#define WM8993_IN1R_VOL_SHIFT 0 /* IN1R_VOL - [4:0] */ +#define WM8993_IN1R_VOL_WIDTH 5 /* IN1R_VOL - [4:0] */ + +/* + * R27 (0x1B) - Right Line Input 3&4 Volume + */ +#define WM8993_IN2_VU 0x0100 /* IN2_VU */ +#define WM8993_IN2_VU_MASK 0x0100 /* IN2_VU */ +#define WM8993_IN2_VU_SHIFT 8 /* IN2_VU */ +#define WM8993_IN2_VU_WIDTH 1 /* IN2_VU */ +#define WM8993_IN2R_MUTE 0x0080 /* IN2R_MUTE */ +#define WM8993_IN2R_MUTE_MASK 0x0080 /* IN2R_MUTE */ +#define WM8993_IN2R_MUTE_SHIFT 7 /* IN2R_MUTE */ +#define WM8993_IN2R_MUTE_WIDTH 1 /* IN2R_MUTE */ +#define WM8993_IN2R_ZC 0x0040 /* IN2R_ZC */ +#define WM8993_IN2R_ZC_MASK 0x0040 /* IN2R_ZC */ +#define WM8993_IN2R_ZC_SHIFT 6 /* IN2R_ZC */ +#define WM8993_IN2R_ZC_WIDTH 1 /* IN2R_ZC */ +#define WM8993_IN2R_VOL_MASK 0x001F /* IN2R_VOL - [4:0] */ +#define WM8993_IN2R_VOL_SHIFT 0 /* IN2R_VOL - [4:0] */ +#define WM8993_IN2R_VOL_WIDTH 5 /* IN2R_VOL - [4:0] */ + +/* + * R28 (0x1C) - Left Output Volume + */ +#define WM8993_HPOUT1_VU 0x0100 /* HPOUT1_VU */ +#define WM8993_HPOUT1_VU_MASK 0x0100 /* HPOUT1_VU */ +#define WM8993_HPOUT1_VU_SHIFT 8 /* HPOUT1_VU */ +#define WM8993_HPOUT1_VU_WIDTH 1 /* HPOUT1_VU */ +#define WM8993_HPOUT1L_ZC 0x0080 /* HPOUT1L_ZC */ +#define WM8993_HPOUT1L_ZC_MASK 0x0080 /* HPOUT1L_ZC */ +#define WM8993_HPOUT1L_ZC_SHIFT 7 /* HPOUT1L_ZC */ +#define WM8993_HPOUT1L_ZC_WIDTH 1 /* HPOUT1L_ZC */ +#define WM8993_HPOUT1L_MUTE_N 0x0040 /* HPOUT1L_MUTE_N */ +#define WM8993_HPOUT1L_MUTE_N_MASK 0x0040 /* HPOUT1L_MUTE_N */ +#define WM8993_HPOUT1L_MUTE_N_SHIFT 6 /* HPOUT1L_MUTE_N */ +#define WM8993_HPOUT1L_MUTE_N_WIDTH 1 /* HPOUT1L_MUTE_N */ +#define WM8993_HPOUT1L_VOL_MASK 0x003F /* HPOUT1L_VOL - [5:0] */ +#define WM8993_HPOUT1L_VOL_SHIFT 0 /* HPOUT1L_VOL - [5:0] */ +#define WM8993_HPOUT1L_VOL_WIDTH 6 /* HPOUT1L_VOL - [5:0] */ + +/* + * R29 (0x1D) - Right Output Volume + */ +#define WM8993_HPOUT1_VU 0x0100 /* HPOUT1_VU */ +#define WM8993_HPOUT1_VU_MASK 0x0100 /* HPOUT1_VU */ +#define WM8993_HPOUT1_VU_SHIFT 8 /* HPOUT1_VU */ +#define WM8993_HPOUT1_VU_WIDTH 1 /* HPOUT1_VU */ +#define WM8993_HPOUT1R_ZC 0x0080 /* HPOUT1R_ZC */ +#define WM8993_HPOUT1R_ZC_MASK 0x0080 /* HPOUT1R_ZC */ +#define WM8993_HPOUT1R_ZC_SHIFT 7 /* HPOUT1R_ZC */ +#define WM8993_HPOUT1R_ZC_WIDTH 1 /* HPOUT1R_ZC */ +#define WM8993_HPOUT1R_MUTE_N 0x0040 /* HPOUT1R_MUTE_N */ +#define WM8993_HPOUT1R_MUTE_N_MASK 0x0040 /* HPOUT1R_MUTE_N */ +#define WM8993_HPOUT1R_MUTE_N_SHIFT 6 /* HPOUT1R_MUTE_N */ +#define WM8993_HPOUT1R_MUTE_N_WIDTH 1 /* HPOUT1R_MUTE_N */ +#define WM8993_HPOUT1R_VOL_MASK 0x003F /* HPOUT1R_VOL - [5:0] */ +#define WM8993_HPOUT1R_VOL_SHIFT 0 /* HPOUT1R_VOL - [5:0] */ +#define WM8993_HPOUT1R_VOL_WIDTH 6 /* HPOUT1R_VOL - [5:0] */ + +/* + * R30 (0x1E) - Line Outputs Volume + */ +#define WM8993_LINEOUT1N_MUTE 0x0040 /* LINEOUT1N_MUTE */ +#define WM8993_LINEOUT1N_MUTE_MASK 0x0040 /* LINEOUT1N_MUTE */ +#define WM8993_LINEOUT1N_MUTE_SHIFT 6 /* LINEOUT1N_MUTE */ +#define WM8993_LINEOUT1N_MUTE_WIDTH 1 /* LINEOUT1N_MUTE */ +#define WM8993_LINEOUT1P_MUTE 0x0020 /* LINEOUT1P_MUTE */ +#define WM8993_LINEOUT1P_MUTE_MASK 0x0020 /* LINEOUT1P_MUTE */ +#define WM8993_LINEOUT1P_MUTE_SHIFT 5 /* LINEOUT1P_MUTE */ +#define WM8993_LINEOUT1P_MUTE_WIDTH 1 /* LINEOUT1P_MUTE */ +#define WM8993_LINEOUT1_VOL 0x0010 /* LINEOUT1_VOL */ +#define WM8993_LINEOUT1_VOL_MASK 0x0010 /* LINEOUT1_VOL */ +#define WM8993_LINEOUT1_VOL_SHIFT 4 /* LINEOUT1_VOL */ +#define WM8993_LINEOUT1_VOL_WIDTH 1 /* LINEOUT1_VOL */ +#define WM8993_LINEOUT2N_MUTE 0x0004 /* LINEOUT2N_MUTE */ +#define WM8993_LINEOUT2N_MUTE_MASK 0x0004 /* LINEOUT2N_MUTE */ +#define WM8993_LINEOUT2N_MUTE_SHIFT 2 /* LINEOUT2N_MUTE */ +#define WM8993_LINEOUT2N_MUTE_WIDTH 1 /* LINEOUT2N_MUTE */ +#define WM8993_LINEOUT2P_MUTE 0x0002 /* LINEOUT2P_MUTE */ +#define WM8993_LINEOUT2P_MUTE_MASK 0x0002 /* LINEOUT2P_MUTE */ +#define WM8993_LINEOUT2P_MUTE_SHIFT 1 /* LINEOUT2P_MUTE */ +#define WM8993_LINEOUT2P_MUTE_WIDTH 1 /* LINEOUT2P_MUTE */ +#define WM8993_LINEOUT2_VOL 0x0001 /* LINEOUT2_VOL */ +#define WM8993_LINEOUT2_VOL_MASK 0x0001 /* LINEOUT2_VOL */ +#define WM8993_LINEOUT2_VOL_SHIFT 0 /* LINEOUT2_VOL */ +#define WM8993_LINEOUT2_VOL_WIDTH 1 /* LINEOUT2_VOL */ + +/* + * R31 (0x1F) - HPOUT2 Volume + */ +#define WM8993_HPOUT2_MUTE 0x0020 /* HPOUT2_MUTE */ +#define WM8993_HPOUT2_MUTE_MASK 0x0020 /* HPOUT2_MUTE */ +#define WM8993_HPOUT2_MUTE_SHIFT 5 /* HPOUT2_MUTE */ +#define WM8993_HPOUT2_MUTE_WIDTH 1 /* HPOUT2_MUTE */ +#define WM8993_HPOUT2_VOL 0x0010 /* HPOUT2_VOL */ +#define WM8993_HPOUT2_VOL_MASK 0x0010 /* HPOUT2_VOL */ +#define WM8993_HPOUT2_VOL_SHIFT 4 /* HPOUT2_VOL */ +#define WM8993_HPOUT2_VOL_WIDTH 1 /* HPOUT2_VOL */ + +/* + * R32 (0x20) - Left OPGA Volume + */ +#define WM8993_MIXOUT_VU 0x0100 /* MIXOUT_VU */ +#define WM8993_MIXOUT_VU_MASK 0x0100 /* MIXOUT_VU */ +#define WM8993_MIXOUT_VU_SHIFT 8 /* MIXOUT_VU */ +#define WM8993_MIXOUT_VU_WIDTH 1 /* MIXOUT_VU */ +#define WM8993_MIXOUTL_ZC 0x0080 /* MIXOUTL_ZC */ +#define WM8993_MIXOUTL_ZC_MASK 0x0080 /* MIXOUTL_ZC */ +#define WM8993_MIXOUTL_ZC_SHIFT 7 /* MIXOUTL_ZC */ +#define WM8993_MIXOUTL_ZC_WIDTH 1 /* MIXOUTL_ZC */ +#define WM8993_MIXOUTL_MUTE_N 0x0040 /* MIXOUTL_MUTE_N */ +#define WM8993_MIXOUTL_MUTE_N_MASK 0x0040 /* MIXOUTL_MUTE_N */ +#define WM8993_MIXOUTL_MUTE_N_SHIFT 6 /* MIXOUTL_MUTE_N */ +#define WM8993_MIXOUTL_MUTE_N_WIDTH 1 /* MIXOUTL_MUTE_N */ +#define WM8993_MIXOUTL_VOL_MASK 0x003F /* MIXOUTL_VOL - [5:0] */ +#define WM8993_MIXOUTL_VOL_SHIFT 0 /* MIXOUTL_VOL - [5:0] */ +#define WM8993_MIXOUTL_VOL_WIDTH 6 /* MIXOUTL_VOL - [5:0] */ + +/* + * R33 (0x21) - Right OPGA Volume + */ +#define WM8993_MIXOUT_VU 0x0100 /* MIXOUT_VU */ +#define WM8993_MIXOUT_VU_MASK 0x0100 /* MIXOUT_VU */ +#define WM8993_MIXOUT_VU_SHIFT 8 /* MIXOUT_VU */ +#define WM8993_MIXOUT_VU_WIDTH 1 /* MIXOUT_VU */ +#define WM8993_MIXOUTR_ZC 0x0080 /* MIXOUTR_ZC */ +#define WM8993_MIXOUTR_ZC_MASK 0x0080 /* MIXOUTR_ZC */ +#define WM8993_MIXOUTR_ZC_SHIFT 7 /* MIXOUTR_ZC */ +#define WM8993_MIXOUTR_ZC_WIDTH 1 /* MIXOUTR_ZC */ +#define WM8993_MIXOUTR_MUTE_N 0x0040 /* MIXOUTR_MUTE_N */ +#define WM8993_MIXOUTR_MUTE_N_MASK 0x0040 /* MIXOUTR_MUTE_N */ +#define WM8993_MIXOUTR_MUTE_N_SHIFT 6 /* MIXOUTR_MUTE_N */ +#define WM8993_MIXOUTR_MUTE_N_WIDTH 1 /* MIXOUTR_MUTE_N */ +#define WM8993_MIXOUTR_VOL_MASK 0x003F /* MIXOUTR_VOL - [5:0] */ +#define WM8993_MIXOUTR_VOL_SHIFT 0 /* MIXOUTR_VOL - [5:0] */ +#define WM8993_MIXOUTR_VOL_WIDTH 6 /* MIXOUTR_VOL - [5:0] */ + +/* + * R34 (0x22) - SPKMIXL Attenuation + */ +#define WM8993_MIXINL_SPKMIXL_VOL 0x0020 /* MIXINL_SPKMIXL_VOL */ +#define WM8993_MIXINL_SPKMIXL_VOL_MASK 0x0020 /* MIXINL_SPKMIXL_VOL */ +#define WM8993_MIXINL_SPKMIXL_VOL_SHIFT 5 /* MIXINL_SPKMIXL_VOL */ +#define WM8993_MIXINL_SPKMIXL_VOL_WIDTH 1 /* MIXINL_SPKMIXL_VOL */ +#define WM8993_IN1LP_SPKMIXL_VOL 0x0010 /* IN1LP_SPKMIXL_VOL */ +#define WM8993_IN1LP_SPKMIXL_VOL_MASK 0x0010 /* IN1LP_SPKMIXL_VOL */ +#define WM8993_IN1LP_SPKMIXL_VOL_SHIFT 4 /* IN1LP_SPKMIXL_VOL */ +#define WM8993_IN1LP_SPKMIXL_VOL_WIDTH 1 /* IN1LP_SPKMIXL_VOL */ +#define WM8993_MIXOUTL_SPKMIXL_VOL 0x0008 /* MIXOUTL_SPKMIXL_VOL */ +#define WM8993_MIXOUTL_SPKMIXL_VOL_MASK 0x0008 /* MIXOUTL_SPKMIXL_VOL */ +#define WM8993_MIXOUTL_SPKMIXL_VOL_SHIFT 3 /* MIXOUTL_SPKMIXL_VOL */ +#define WM8993_MIXOUTL_SPKMIXL_VOL_WIDTH 1 /* MIXOUTL_SPKMIXL_VOL */ +#define WM8993_DACL_SPKMIXL_VOL 0x0004 /* DACL_SPKMIXL_VOL */ +#define WM8993_DACL_SPKMIXL_VOL_MASK 0x0004 /* DACL_SPKMIXL_VOL */ +#define WM8993_DACL_SPKMIXL_VOL_SHIFT 2 /* DACL_SPKMIXL_VOL */ +#define WM8993_DACL_SPKMIXL_VOL_WIDTH 1 /* DACL_SPKMIXL_VOL */ +#define WM8993_SPKMIXL_VOL_MASK 0x0003 /* SPKMIXL_VOL - [1:0] */ +#define WM8993_SPKMIXL_VOL_SHIFT 0 /* SPKMIXL_VOL - [1:0] */ +#define WM8993_SPKMIXL_VOL_WIDTH 2 /* SPKMIXL_VOL - [1:0] */ + +/* + * R35 (0x23) - SPKMIXR Attenuation + */ +#define WM8993_SPKOUT_CLASSAB_MODE 0x0100 /* SPKOUT_CLASSAB_MODE */ +#define WM8993_SPKOUT_CLASSAB_MODE_MASK 0x0100 /* SPKOUT_CLASSAB_MODE */ +#define WM8993_SPKOUT_CLASSAB_MODE_SHIFT 8 /* SPKOUT_CLASSAB_MODE */ +#define WM8993_SPKOUT_CLASSAB_MODE_WIDTH 1 /* SPKOUT_CLASSAB_MODE */ +#define WM8993_MIXINR_SPKMIXR_VOL 0x0020 /* MIXINR_SPKMIXR_VOL */ +#define WM8993_MIXINR_SPKMIXR_VOL_MASK 0x0020 /* MIXINR_SPKMIXR_VOL */ +#define WM8993_MIXINR_SPKMIXR_VOL_SHIFT 5 /* MIXINR_SPKMIXR_VOL */ +#define WM8993_MIXINR_SPKMIXR_VOL_WIDTH 1 /* MIXINR_SPKMIXR_VOL */ +#define WM8993_IN1RP_SPKMIXR_VOL 0x0010 /* IN1RP_SPKMIXR_VOL */ +#define WM8993_IN1RP_SPKMIXR_VOL_MASK 0x0010 /* IN1RP_SPKMIXR_VOL */ +#define WM8993_IN1RP_SPKMIXR_VOL_SHIFT 4 /* IN1RP_SPKMIXR_VOL */ +#define WM8993_IN1RP_SPKMIXR_VOL_WIDTH 1 /* IN1RP_SPKMIXR_VOL */ +#define WM8993_MIXOUTR_SPKMIXR_VOL 0x0008 /* MIXOUTR_SPKMIXR_VOL */ +#define WM8993_MIXOUTR_SPKMIXR_VOL_MASK 0x0008 /* MIXOUTR_SPKMIXR_VOL */ +#define WM8993_MIXOUTR_SPKMIXR_VOL_SHIFT 3 /* MIXOUTR_SPKMIXR_VOL */ +#define WM8993_MIXOUTR_SPKMIXR_VOL_WIDTH 1 /* MIXOUTR_SPKMIXR_VOL */ +#define WM8993_DACR_SPKMIXR_VOL 0x0004 /* DACR_SPKMIXR_VOL */ +#define WM8993_DACR_SPKMIXR_VOL_MASK 0x0004 /* DACR_SPKMIXR_VOL */ +#define WM8993_DACR_SPKMIXR_VOL_SHIFT 2 /* DACR_SPKMIXR_VOL */ +#define WM8993_DACR_SPKMIXR_VOL_WIDTH 1 /* DACR_SPKMIXR_VOL */ +#define WM8993_SPKMIXR_VOL_MASK 0x0003 /* SPKMIXR_VOL - [1:0] */ +#define WM8993_SPKMIXR_VOL_SHIFT 0 /* SPKMIXR_VOL - [1:0] */ +#define WM8993_SPKMIXR_VOL_WIDTH 2 /* SPKMIXR_VOL - [1:0] */ + +/* + * R36 (0x24) - SPKOUT Mixers + */ +#define WM8993_VRX_TO_SPKOUTL 0x0020 /* VRX_TO_SPKOUTL */ +#define WM8993_VRX_TO_SPKOUTL_MASK 0x0020 /* VRX_TO_SPKOUTL */ +#define WM8993_VRX_TO_SPKOUTL_SHIFT 5 /* VRX_TO_SPKOUTL */ +#define WM8993_VRX_TO_SPKOUTL_WIDTH 1 /* VRX_TO_SPKOUTL */ +#define WM8993_SPKMIXL_TO_SPKOUTL 0x0010 /* SPKMIXL_TO_SPKOUTL */ +#define WM8993_SPKMIXL_TO_SPKOUTL_MASK 0x0010 /* SPKMIXL_TO_SPKOUTL */ +#define WM8993_SPKMIXL_TO_SPKOUTL_SHIFT 4 /* SPKMIXL_TO_SPKOUTL */ +#define WM8993_SPKMIXL_TO_SPKOUTL_WIDTH 1 /* SPKMIXL_TO_SPKOUTL */ +#define WM8993_SPKMIXR_TO_SPKOUTL 0x0008 /* SPKMIXR_TO_SPKOUTL */ +#define WM8993_SPKMIXR_TO_SPKOUTL_MASK 0x0008 /* SPKMIXR_TO_SPKOUTL */ +#define WM8993_SPKMIXR_TO_SPKOUTL_SHIFT 3 /* SPKMIXR_TO_SPKOUTL */ +#define WM8993_SPKMIXR_TO_SPKOUTL_WIDTH 1 /* SPKMIXR_TO_SPKOUTL */ +#define WM8993_VRX_TO_SPKOUTR 0x0004 /* VRX_TO_SPKOUTR */ +#define WM8993_VRX_TO_SPKOUTR_MASK 0x0004 /* VRX_TO_SPKOUTR */ +#define WM8993_VRX_TO_SPKOUTR_SHIFT 2 /* VRX_TO_SPKOUTR */ +#define WM8993_VRX_TO_SPKOUTR_WIDTH 1 /* VRX_TO_SPKOUTR */ +#define WM8993_SPKMIXL_TO_SPKOUTR 0x0002 /* SPKMIXL_TO_SPKOUTR */ +#define WM8993_SPKMIXL_TO_SPKOUTR_MASK 0x0002 /* SPKMIXL_TO_SPKOUTR */ +#define WM8993_SPKMIXL_TO_SPKOUTR_SHIFT 1 /* SPKMIXL_TO_SPKOUTR */ +#define WM8993_SPKMIXL_TO_SPKOUTR_WIDTH 1 /* SPKMIXL_TO_SPKOUTR */ +#define WM8993_SPKMIXR_TO_SPKOUTR 0x0001 /* SPKMIXR_TO_SPKOUTR */ +#define WM8993_SPKMIXR_TO_SPKOUTR_MASK 0x0001 /* SPKMIXR_TO_SPKOUTR */ +#define WM8993_SPKMIXR_TO_SPKOUTR_SHIFT 0 /* SPKMIXR_TO_SPKOUTR */ +#define WM8993_SPKMIXR_TO_SPKOUTR_WIDTH 1 /* SPKMIXR_TO_SPKOUTR */ + +/* + * R37 (0x25) - SPKOUT Boost + */ +#define WM8993_SPKOUTL_BOOST_MASK 0x0038 /* SPKOUTL_BOOST - [5:3] */ +#define WM8993_SPKOUTL_BOOST_SHIFT 3 /* SPKOUTL_BOOST - [5:3] */ +#define WM8993_SPKOUTL_BOOST_WIDTH 3 /* SPKOUTL_BOOST - [5:3] */ +#define WM8993_SPKOUTR_BOOST_MASK 0x0007 /* SPKOUTR_BOOST - [2:0] */ +#define WM8993_SPKOUTR_BOOST_SHIFT 0 /* SPKOUTR_BOOST - [2:0] */ +#define WM8993_SPKOUTR_BOOST_WIDTH 3 /* SPKOUTR_BOOST - [2:0] */ + +/* + * R38 (0x26) - Speaker Volume Left + */ +#define WM8993_SPKOUT_VU 0x0100 /* SPKOUT_VU */ +#define WM8993_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */ +#define WM8993_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */ +#define WM8993_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */ +#define WM8993_SPKOUTL_ZC 0x0080 /* SPKOUTL_ZC */ +#define WM8993_SPKOUTL_ZC_MASK 0x0080 /* SPKOUTL_ZC */ +#define WM8993_SPKOUTL_ZC_SHIFT 7 /* SPKOUTL_ZC */ +#define WM8993_SPKOUTL_ZC_WIDTH 1 /* SPKOUTL_ZC */ +#define WM8993_SPKOUTL_MUTE_N 0x0040 /* SPKOUTL_MUTE_N */ +#define WM8993_SPKOUTL_MUTE_N_MASK 0x0040 /* SPKOUTL_MUTE_N */ +#define WM8993_SPKOUTL_MUTE_N_SHIFT 6 /* SPKOUTL_MUTE_N */ +#define WM8993_SPKOUTL_MUTE_N_WIDTH 1 /* SPKOUTL_MUTE_N */ +#define WM8993_SPKOUTL_VOL_MASK 0x003F /* SPKOUTL_VOL - [5:0] */ +#define WM8993_SPKOUTL_VOL_SHIFT 0 /* SPKOUTL_VOL - [5:0] */ +#define WM8993_SPKOUTL_VOL_WIDTH 6 /* SPKOUTL_VOL - [5:0] */ + +/* + * R39 (0x27) - Speaker Volume Right + */ +#define WM8993_SPKOUT_VU 0x0100 /* SPKOUT_VU */ +#define WM8993_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */ +#define WM8993_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */ +#define WM8993_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */ +#define WM8993_SPKOUTR_ZC 0x0080 /* SPKOUTR_ZC */ +#define WM8993_SPKOUTR_ZC_MASK 0x0080 /* SPKOUTR_ZC */ +#define WM8993_SPKOUTR_ZC_SHIFT 7 /* SPKOUTR_ZC */ +#define WM8993_SPKOUTR_ZC_WIDTH 1 /* SPKOUTR_ZC */ +#define WM8993_SPKOUTR_MUTE_N 0x0040 /* SPKOUTR_MUTE_N */ +#define WM8993_SPKOUTR_MUTE_N_MASK 0x0040 /* SPKOUTR_MUTE_N */ +#define WM8993_SPKOUTR_MUTE_N_SHIFT 6 /* SPKOUTR_MUTE_N */ +#define WM8993_SPKOUTR_MUTE_N_WIDTH 1 /* SPKOUTR_MUTE_N */ +#define WM8993_SPKOUTR_VOL_MASK 0x003F /* SPKOUTR_VOL - [5:0] */ +#define WM8993_SPKOUTR_VOL_SHIFT 0 /* SPKOUTR_VOL - [5:0] */ +#define WM8993_SPKOUTR_VOL_WIDTH 6 /* SPKOUTR_VOL - [5:0] */ + +/* + * R40 (0x28) - Input Mixer2 + */ +#define WM8993_IN2LP_TO_IN2L 0x0080 /* IN2LP_TO_IN2L */ +#define WM8993_IN2LP_TO_IN2L_MASK 0x0080 /* IN2LP_TO_IN2L */ +#define WM8993_IN2LP_TO_IN2L_SHIFT 7 /* IN2LP_TO_IN2L */ +#define WM8993_IN2LP_TO_IN2L_WIDTH 1 /* IN2LP_TO_IN2L */ +#define WM8993_IN2LN_TO_IN2L 0x0040 /* IN2LN_TO_IN2L */ +#define WM8993_IN2LN_TO_IN2L_MASK 0x0040 /* IN2LN_TO_IN2L */ +#define WM8993_IN2LN_TO_IN2L_SHIFT 6 /* IN2LN_TO_IN2L */ +#define WM8993_IN2LN_TO_IN2L_WIDTH 1 /* IN2LN_TO_IN2L */ +#define WM8993_IN1LP_TO_IN1L 0x0020 /* IN1LP_TO_IN1L */ +#define WM8993_IN1LP_TO_IN1L_MASK 0x0020 /* IN1LP_TO_IN1L */ +#define WM8993_IN1LP_TO_IN1L_SHIFT 5 /* IN1LP_TO_IN1L */ +#define WM8993_IN1LP_TO_IN1L_WIDTH 1 /* IN1LP_TO_IN1L */ +#define WM8993_IN1LN_TO_IN1L 0x0010 /* IN1LN_TO_IN1L */ +#define WM8993_IN1LN_TO_IN1L_MASK 0x0010 /* IN1LN_TO_IN1L */ +#define WM8993_IN1LN_TO_IN1L_SHIFT 4 /* IN1LN_TO_IN1L */ +#define WM8993_IN1LN_TO_IN1L_WIDTH 1 /* IN1LN_TO_IN1L */ +#define WM8993_IN2RP_TO_IN2R 0x0008 /* IN2RP_TO_IN2R */ +#define WM8993_IN2RP_TO_IN2R_MASK 0x0008 /* IN2RP_TO_IN2R */ +#define WM8993_IN2RP_TO_IN2R_SHIFT 3 /* IN2RP_TO_IN2R */ +#define WM8993_IN2RP_TO_IN2R_WIDTH 1 /* IN2RP_TO_IN2R */ +#define WM8993_IN2RN_TO_IN2R 0x0004 /* IN2RN_TO_IN2R */ +#define WM8993_IN2RN_TO_IN2R_MASK 0x0004 /* IN2RN_TO_IN2R */ +#define WM8993_IN2RN_TO_IN2R_SHIFT 2 /* IN2RN_TO_IN2R */ +#define WM8993_IN2RN_TO_IN2R_WIDTH 1 /* IN2RN_TO_IN2R */ +#define WM8993_IN1RP_TO_IN1R 0x0002 /* IN1RP_TO_IN1R */ +#define WM8993_IN1RP_TO_IN1R_MASK 0x0002 /* IN1RP_TO_IN1R */ +#define WM8993_IN1RP_TO_IN1R_SHIFT 1 /* IN1RP_TO_IN1R */ +#define WM8993_IN1RP_TO_IN1R_WIDTH 1 /* IN1RP_TO_IN1R */ +#define WM8993_IN1RN_TO_IN1R 0x0001 /* IN1RN_TO_IN1R */ +#define WM8993_IN1RN_TO_IN1R_MASK 0x0001 /* IN1RN_TO_IN1R */ +#define WM8993_IN1RN_TO_IN1R_SHIFT 0 /* IN1RN_TO_IN1R */ +#define WM8993_IN1RN_TO_IN1R_WIDTH 1 /* IN1RN_TO_IN1R */ + +/* + * R41 (0x29) - Input Mixer3 + */ +#define WM8993_IN2L_TO_MIXINL 0x0100 /* IN2L_TO_MIXINL */ +#define WM8993_IN2L_TO_MIXINL_MASK 0x0100 /* IN2L_TO_MIXINL */ +#define WM8993_IN2L_TO_MIXINL_SHIFT 8 /* IN2L_TO_MIXINL */ +#define WM8993_IN2L_TO_MIXINL_WIDTH 1 /* IN2L_TO_MIXINL */ +#define WM8993_IN2L_MIXINL_VOL 0x0080 /* IN2L_MIXINL_VOL */ +#define WM8993_IN2L_MIXINL_VOL_MASK 0x0080 /* IN2L_MIXINL_VOL */ +#define WM8993_IN2L_MIXINL_VOL_SHIFT 7 /* IN2L_MIXINL_VOL */ +#define WM8993_IN2L_MIXINL_VOL_WIDTH 1 /* IN2L_MIXINL_VOL */ +#define WM8993_IN1L_TO_MIXINL 0x0020 /* IN1L_TO_MIXINL */ +#define WM8993_IN1L_TO_MIXINL_MASK 0x0020 /* IN1L_TO_MIXINL */ +#define WM8993_IN1L_TO_MIXINL_SHIFT 5 /* IN1L_TO_MIXINL */ +#define WM8993_IN1L_TO_MIXINL_WIDTH 1 /* IN1L_TO_MIXINL */ +#define WM8993_IN1L_MIXINL_VOL 0x0010 /* IN1L_MIXINL_VOL */ +#define WM8993_IN1L_MIXINL_VOL_MASK 0x0010 /* IN1L_MIXINL_VOL */ +#define WM8993_IN1L_MIXINL_VOL_SHIFT 4 /* IN1L_MIXINL_VOL */ +#define WM8993_IN1L_MIXINL_VOL_WIDTH 1 /* IN1L_MIXINL_VOL */ +#define WM8993_MIXOUTL_MIXINL_VOL_MASK 0x0007 /* MIXOUTL_MIXINL_VOL - [2:0] */ +#define WM8993_MIXOUTL_MIXINL_VOL_SHIFT 0 /* MIXOUTL_MIXINL_VOL - [2:0] */ +#define WM8993_MIXOUTL_MIXINL_VOL_WIDTH 3 /* MIXOUTL_MIXINL_VOL - [2:0] */ + +/* + * R42 (0x2A) - Input Mixer4 + */ +#define WM8993_IN2R_TO_MIXINR 0x0100 /* IN2R_TO_MIXINR */ +#define WM8993_IN2R_TO_MIXINR_MASK 0x0100 /* IN2R_TO_MIXINR */ +#define WM8993_IN2R_TO_MIXINR_SHIFT 8 /* IN2R_TO_MIXINR */ +#define WM8993_IN2R_TO_MIXINR_WIDTH 1 /* IN2R_TO_MIXINR */ +#define WM8993_IN2R_MIXINR_VOL 0x0080 /* IN2R_MIXINR_VOL */ +#define WM8993_IN2R_MIXINR_VOL_MASK 0x0080 /* IN2R_MIXINR_VOL */ +#define WM8993_IN2R_MIXINR_VOL_SHIFT 7 /* IN2R_MIXINR_VOL */ +#define WM8993_IN2R_MIXINR_VOL_WIDTH 1 /* IN2R_MIXINR_VOL */ +#define WM8993_IN1R_TO_MIXINR 0x0020 /* IN1R_TO_MIXINR */ +#define WM8993_IN1R_TO_MIXINR_MASK 0x0020 /* IN1R_TO_MIXINR */ +#define WM8993_IN1R_TO_MIXINR_SHIFT 5 /* IN1R_TO_MIXINR */ +#define WM8993_IN1R_TO_MIXINR_WIDTH 1 /* IN1R_TO_MIXINR */ +#define WM8993_IN1R_MIXINR_VOL 0x0010 /* IN1R_MIXINR_VOL */ +#define WM8993_IN1R_MIXINR_VOL_MASK 0x0010 /* IN1R_MIXINR_VOL */ +#define WM8993_IN1R_MIXINR_VOL_SHIFT 4 /* IN1R_MIXINR_VOL */ +#define WM8993_IN1R_MIXINR_VOL_WIDTH 1 /* IN1R_MIXINR_VOL */ +#define WM8993_MIXOUTR_MIXINR_VOL_MASK 0x0007 /* MIXOUTR_MIXINR_VOL - [2:0] */ +#define WM8993_MIXOUTR_MIXINR_VOL_SHIFT 0 /* MIXOUTR_MIXINR_VOL - [2:0] */ +#define WM8993_MIXOUTR_MIXINR_VOL_WIDTH 3 /* MIXOUTR_MIXINR_VOL - [2:0] */ + +/* + * R43 (0x2B) - Input Mixer5 + */ +#define WM8993_IN1LP_MIXINL_VOL_MASK 0x01C0 /* IN1LP_MIXINL_VOL - [8:6] */ +#define WM8993_IN1LP_MIXINL_VOL_SHIFT 6 /* IN1LP_MIXINL_VOL - [8:6] */ +#define WM8993_IN1LP_MIXINL_VOL_WIDTH 3 /* IN1LP_MIXINL_VOL - [8:6] */ +#define WM8993_VRX_MIXINL_VOL_MASK 0x0007 /* VRX_MIXINL_VOL - [2:0] */ +#define WM8993_VRX_MIXINL_VOL_SHIFT 0 /* VRX_MIXINL_VOL - [2:0] */ +#define WM8993_VRX_MIXINL_VOL_WIDTH 3 /* VRX_MIXINL_VOL - [2:0] */ + +/* + * R44 (0x2C) - Input Mixer6 + */ +#define WM8993_IN1RP_MIXINR_VOL_MASK 0x01C0 /* IN1RP_MIXINR_VOL - [8:6] */ +#define WM8993_IN1RP_MIXINR_VOL_SHIFT 6 /* IN1RP_MIXINR_VOL - [8:6] */ +#define WM8993_IN1RP_MIXINR_VOL_WIDTH 3 /* IN1RP_MIXINR_VOL - [8:6] */ +#define WM8993_VRX_MIXINR_VOL_MASK 0x0007 /* VRX_MIXINR_VOL - [2:0] */ +#define WM8993_VRX_MIXINR_VOL_SHIFT 0 /* VRX_MIXINR_VOL - [2:0] */ +#define WM8993_VRX_MIXINR_VOL_WIDTH 3 /* VRX_MIXINR_VOL - [2:0] */ + +/* + * R45 (0x2D) - Output Mixer1 + */ +#define WM8993_DACL_TO_HPOUT1L 0x0100 /* DACL_TO_HPOUT1L */ +#define WM8993_DACL_TO_HPOUT1L_MASK 0x0100 /* DACL_TO_HPOUT1L */ +#define WM8993_DACL_TO_HPOUT1L_SHIFT 8 /* DACL_TO_HPOUT1L */ +#define WM8993_DACL_TO_HPOUT1L_WIDTH 1 /* DACL_TO_HPOUT1L */ +#define WM8993_MIXINR_TO_MIXOUTL 0x0080 /* MIXINR_TO_MIXOUTL */ +#define WM8993_MIXINR_TO_MIXOUTL_MASK 0x0080 /* MIXINR_TO_MIXOUTL */ +#define WM8993_MIXINR_TO_MIXOUTL_SHIFT 7 /* MIXINR_TO_MIXOUTL */ +#define WM8993_MIXINR_TO_MIXOUTL_WIDTH 1 /* MIXINR_TO_MIXOUTL */ +#define WM8993_MIXINL_TO_MIXOUTL 0x0040 /* MIXINL_TO_MIXOUTL */ +#define WM8993_MIXINL_TO_MIXOUTL_MASK 0x0040 /* MIXINL_TO_MIXOUTL */ +#define WM8993_MIXINL_TO_MIXOUTL_SHIFT 6 /* MIXINL_TO_MIXOUTL */ +#define WM8993_MIXINL_TO_MIXOUTL_WIDTH 1 /* MIXINL_TO_MIXOUTL */ +#define WM8993_IN2RN_TO_MIXOUTL 0x0020 /* IN2RN_TO_MIXOUTL */ +#define WM8993_IN2RN_TO_MIXOUTL_MASK 0x0020 /* IN2RN_TO_MIXOUTL */ +#define WM8993_IN2RN_TO_MIXOUTL_SHIFT 5 /* IN2RN_TO_MIXOUTL */ +#define WM8993_IN2RN_TO_MIXOUTL_WIDTH 1 /* IN2RN_TO_MIXOUTL */ +#define WM8993_IN2LN_TO_MIXOUTL 0x0010 /* IN2LN_TO_MIXOUTL */ +#define WM8993_IN2LN_TO_MIXOUTL_MASK 0x0010 /* IN2LN_TO_MIXOUTL */ +#define WM8993_IN2LN_TO_MIXOUTL_SHIFT 4 /* IN2LN_TO_MIXOUTL */ +#define WM8993_IN2LN_TO_MIXOUTL_WIDTH 1 /* IN2LN_TO_MIXOUTL */ +#define WM8993_IN1R_TO_MIXOUTL 0x0008 /* IN1R_TO_MIXOUTL */ +#define WM8993_IN1R_TO_MIXOUTL_MASK 0x0008 /* IN1R_TO_MIXOUTL */ +#define WM8993_IN1R_TO_MIXOUTL_SHIFT 3 /* IN1R_TO_MIXOUTL */ +#define WM8993_IN1R_TO_MIXOUTL_WIDTH 1 /* IN1R_TO_MIXOUTL */ +#define WM8993_IN1L_TO_MIXOUTL 0x0004 /* IN1L_TO_MIXOUTL */ +#define WM8993_IN1L_TO_MIXOUTL_MASK 0x0004 /* IN1L_TO_MIXOUTL */ +#define WM8993_IN1L_TO_MIXOUTL_SHIFT 2 /* IN1L_TO_MIXOUTL */ +#define WM8993_IN1L_TO_MIXOUTL_WIDTH 1 /* IN1L_TO_MIXOUTL */ +#define WM8993_IN2LP_TO_MIXOUTL 0x0002 /* IN2LP_TO_MIXOUTL */ +#define WM8993_IN2LP_TO_MIXOUTL_MASK 0x0002 /* IN2LP_TO_MIXOUTL */ +#define WM8993_IN2LP_TO_MIXOUTL_SHIFT 1 /* IN2LP_TO_MIXOUTL */ +#define WM8993_IN2LP_TO_MIXOUTL_WIDTH 1 /* IN2LP_TO_MIXOUTL */ +#define WM8993_DACL_TO_MIXOUTL 0x0001 /* DACL_TO_MIXOUTL */ +#define WM8993_DACL_TO_MIXOUTL_MASK 0x0001 /* DACL_TO_MIXOUTL */ +#define WM8993_DACL_TO_MIXOUTL_SHIFT 0 /* DACL_TO_MIXOUTL */ +#define WM8993_DACL_TO_MIXOUTL_WIDTH 1 /* DACL_TO_MIXOUTL */ + +/* + * R46 (0x2E) - Output Mixer2 + */ +#define WM8993_DACR_TO_HPOUT1R 0x0100 /* DACR_TO_HPOUT1R */ +#define WM8993_DACR_TO_HPOUT1R_MASK 0x0100 /* DACR_TO_HPOUT1R */ +#define WM8993_DACR_TO_HPOUT1R_SHIFT 8 /* DACR_TO_HPOUT1R */ +#define WM8993_DACR_TO_HPOUT1R_WIDTH 1 /* DACR_TO_HPOUT1R */ +#define WM8993_MIXINL_TO_MIXOUTR 0x0080 /* MIXINL_TO_MIXOUTR */ +#define WM8993_MIXINL_TO_MIXOUTR_MASK 0x0080 /* MIXINL_TO_MIXOUTR */ +#define WM8993_MIXINL_TO_MIXOUTR_SHIFT 7 /* MIXINL_TO_MIXOUTR */ +#define WM8993_MIXINL_TO_MIXOUTR_WIDTH 1 /* MIXINL_TO_MIXOUTR */ +#define WM8993_MIXINR_TO_MIXOUTR 0x0040 /* MIXINR_TO_MIXOUTR */ +#define WM8993_MIXINR_TO_MIXOUTR_MASK 0x0040 /* MIXINR_TO_MIXOUTR */ +#define WM8993_MIXINR_TO_MIXOUTR_SHIFT 6 /* MIXINR_TO_MIXOUTR */ +#define WM8993_MIXINR_TO_MIXOUTR_WIDTH 1 /* MIXINR_TO_MIXOUTR */ +#define WM8993_IN2LN_TO_MIXOUTR 0x0020 /* IN2LN_TO_MIXOUTR */ +#define WM8993_IN2LN_TO_MIXOUTR_MASK 0x0020 /* IN2LN_TO_MIXOUTR */ +#define WM8993_IN2LN_TO_MIXOUTR_SHIFT 5 /* IN2LN_TO_MIXOUTR */ +#define WM8993_IN2LN_TO_MIXOUTR_WIDTH 1 /* IN2LN_TO_MIXOUTR */ +#define WM8993_IN2RN_TO_MIXOUTR 0x0010 /* IN2RN_TO_MIXOUTR */ +#define WM8993_IN2RN_TO_MIXOUTR_MASK 0x0010 /* IN2RN_TO_MIXOUTR */ +#define WM8993_IN2RN_TO_MIXOUTR_SHIFT 4 /* IN2RN_TO_MIXOUTR */ +#define WM8993_IN2RN_TO_MIXOUTR_WIDTH 1 /* IN2RN_TO_MIXOUTR */ +#define WM8993_IN1L_TO_MIXOUTR 0x0008 /* IN1L_TO_MIXOUTR */ +#define WM8993_IN1L_TO_MIXOUTR_MASK 0x0008 /* IN1L_TO_MIXOUTR */ +#define WM8993_IN1L_TO_MIXOUTR_SHIFT 3 /* IN1L_TO_MIXOUTR */ +#define WM8993_IN1L_TO_MIXOUTR_WIDTH 1 /* IN1L_TO_MIXOUTR */ +#define WM8993_IN1R_TO_MIXOUTR 0x0004 /* IN1R_TO_MIXOUTR */ +#define WM8993_IN1R_TO_MIXOUTR_MASK 0x0004 /* IN1R_TO_MIXOUTR */ +#define WM8993_IN1R_TO_MIXOUTR_SHIFT 2 /* IN1R_TO_MIXOUTR */ +#define WM8993_IN1R_TO_MIXOUTR_WIDTH 1 /* IN1R_TO_MIXOUTR */ +#define WM8993_IN2RP_TO_MIXOUTR 0x0002 /* IN2RP_TO_MIXOUTR */ +#define WM8993_IN2RP_TO_MIXOUTR_MASK 0x0002 /* IN2RP_TO_MIXOUTR */ +#define WM8993_IN2RP_TO_MIXOUTR_SHIFT 1 /* IN2RP_TO_MIXOUTR */ +#define WM8993_IN2RP_TO_MIXOUTR_WIDTH 1 /* IN2RP_TO_MIXOUTR */ +#define WM8993_DACR_TO_MIXOUTR 0x0001 /* DACR_TO_MIXOUTR */ +#define WM8993_DACR_TO_MIXOUTR_MASK 0x0001 /* DACR_TO_MIXOUTR */ +#define WM8993_DACR_TO_MIXOUTR_SHIFT 0 /* DACR_TO_MIXOUTR */ +#define WM8993_DACR_TO_MIXOUTR_WIDTH 1 /* DACR_TO_MIXOUTR */ + +/* + * R47 (0x2F) - Output Mixer3 + */ +#define WM8993_IN2LP_MIXOUTL_VOL_MASK 0x0E00 /* IN2LP_MIXOUTL_VOL - [11:9] */ +#define WM8993_IN2LP_MIXOUTL_VOL_SHIFT 9 /* IN2LP_MIXOUTL_VOL - [11:9] */ +#define WM8993_IN2LP_MIXOUTL_VOL_WIDTH 3 /* IN2LP_MIXOUTL_VOL - [11:9] */ +#define WM8993_IN2LN_MIXOUTL_VOL_MASK 0x01C0 /* IN2LN_MIXOUTL_VOL - [8:6] */ +#define WM8993_IN2LN_MIXOUTL_VOL_SHIFT 6 /* IN2LN_MIXOUTL_VOL - [8:6] */ +#define WM8993_IN2LN_MIXOUTL_VOL_WIDTH 3 /* IN2LN_MIXOUTL_VOL - [8:6] */ +#define WM8993_IN1R_MIXOUTL_VOL_MASK 0x0038 /* IN1R_MIXOUTL_VOL - [5:3] */ +#define WM8993_IN1R_MIXOUTL_VOL_SHIFT 3 /* IN1R_MIXOUTL_VOL - [5:3] */ +#define WM8993_IN1R_MIXOUTL_VOL_WIDTH 3 /* IN1R_MIXOUTL_VOL - [5:3] */ +#define WM8993_IN1L_MIXOUTL_VOL_MASK 0x0007 /* IN1L_MIXOUTL_VOL - [2:0] */ +#define WM8993_IN1L_MIXOUTL_VOL_SHIFT 0 /* IN1L_MIXOUTL_VOL - [2:0] */ +#define WM8993_IN1L_MIXOUTL_VOL_WIDTH 3 /* IN1L_MIXOUTL_VOL - [2:0] */ + +/* + * R48 (0x30) - Output Mixer4 + */ +#define WM8993_IN2RP_MIXOUTR_VOL_MASK 0x0E00 /* IN2RP_MIXOUTR_VOL - [11:9] */ +#define WM8993_IN2RP_MIXOUTR_VOL_SHIFT 9 /* IN2RP_MIXOUTR_VOL - [11:9] */ +#define WM8993_IN2RP_MIXOUTR_VOL_WIDTH 3 /* IN2RP_MIXOUTR_VOL - [11:9] */ +#define WM8993_IN2RN_MIXOUTR_VOL_MASK 0x01C0 /* IN2RN_MIXOUTR_VOL - [8:6] */ +#define WM8993_IN2RN_MIXOUTR_VOL_SHIFT 6 /* IN2RN_MIXOUTR_VOL - [8:6] */ +#define WM8993_IN2RN_MIXOUTR_VOL_WIDTH 3 /* IN2RN_MIXOUTR_VOL - [8:6] */ +#define WM8993_IN1L_MIXOUTR_VOL_MASK 0x0038 /* IN1L_MIXOUTR_VOL - [5:3] */ +#define WM8993_IN1L_MIXOUTR_VOL_SHIFT 3 /* IN1L_MIXOUTR_VOL - [5:3] */ +#define WM8993_IN1L_MIXOUTR_VOL_WIDTH 3 /* IN1L_MIXOUTR_VOL - [5:3] */ +#define WM8993_IN1R_MIXOUTR_VOL_MASK 0x0007 /* IN1R_MIXOUTR_VOL - [2:0] */ +#define WM8993_IN1R_MIXOUTR_VOL_SHIFT 0 /* IN1R_MIXOUTR_VOL - [2:0] */ +#define WM8993_IN1R_MIXOUTR_VOL_WIDTH 3 /* IN1R_MIXOUTR_VOL - [2:0] */ + +/* + * R49 (0x31) - Output Mixer5 + */ +#define WM8993_DACL_MIXOUTL_VOL_MASK 0x0E00 /* DACL_MIXOUTL_VOL - [11:9] */ +#define WM8993_DACL_MIXOUTL_VOL_SHIFT 9 /* DACL_MIXOUTL_VOL - [11:9] */ +#define WM8993_DACL_MIXOUTL_VOL_WIDTH 3 /* DACL_MIXOUTL_VOL - [11:9] */ +#define WM8993_IN2RN_MIXOUTL_VOL_MASK 0x01C0 /* IN2RN_MIXOUTL_VOL - [8:6] */ +#define WM8993_IN2RN_MIXOUTL_VOL_SHIFT 6 /* IN2RN_MIXOUTL_VOL - [8:6] */ +#define WM8993_IN2RN_MIXOUTL_VOL_WIDTH 3 /* IN2RN_MIXOUTL_VOL - [8:6] */ +#define WM8993_MIXINR_MIXOUTL_VOL_MASK 0x0038 /* MIXINR_MIXOUTL_VOL - [5:3] */ +#define WM8993_MIXINR_MIXOUTL_VOL_SHIFT 3 /* MIXINR_MIXOUTL_VOL - [5:3] */ +#define WM8993_MIXINR_MIXOUTL_VOL_WIDTH 3 /* MIXINR_MIXOUTL_VOL - [5:3] */ +#define WM8993_MIXINL_MIXOUTL_VOL_MASK 0x0007 /* MIXINL_MIXOUTL_VOL - [2:0] */ +#define WM8993_MIXINL_MIXOUTL_VOL_SHIFT 0 /* MIXINL_MIXOUTL_VOL - [2:0] */ +#define WM8993_MIXINL_MIXOUTL_VOL_WIDTH 3 /* MIXINL_MIXOUTL_VOL - [2:0] */ + +/* + * R50 (0x32) - Output Mixer6 + */ +#define WM8993_DACR_MIXOUTR_VOL_MASK 0x0E00 /* DACR_MIXOUTR_VOL - [11:9] */ +#define WM8993_DACR_MIXOUTR_VOL_SHIFT 9 /* DACR_MIXOUTR_VOL - [11:9] */ +#define WM8993_DACR_MIXOUTR_VOL_WIDTH 3 /* DACR_MIXOUTR_VOL - [11:9] */ +#define WM8993_IN2LN_MIXOUTR_VOL_MASK 0x01C0 /* IN2LN_MIXOUTR_VOL - [8:6] */ +#define WM8993_IN2LN_MIXOUTR_VOL_SHIFT 6 /* IN2LN_MIXOUTR_VOL - [8:6] */ +#define WM8993_IN2LN_MIXOUTR_VOL_WIDTH 3 /* IN2LN_MIXOUTR_VOL - [8:6] */ +#define WM8993_MIXINL_MIXOUTR_VOL_MASK 0x0038 /* MIXINL_MIXOUTR_VOL - [5:3] */ +#define WM8993_MIXINL_MIXOUTR_VOL_SHIFT 3 /* MIXINL_MIXOUTR_VOL - [5:3] */ +#define WM8993_MIXINL_MIXOUTR_VOL_WIDTH 3 /* MIXINL_MIXOUTR_VOL - [5:3] */ +#define WM8993_MIXINR_MIXOUTR_VOL_MASK 0x0007 /* MIXINR_MIXOUTR_VOL - [2:0] */ +#define WM8993_MIXINR_MIXOUTR_VOL_SHIFT 0 /* MIXINR_MIXOUTR_VOL - [2:0] */ +#define WM8993_MIXINR_MIXOUTR_VOL_WIDTH 3 /* MIXINR_MIXOUTR_VOL - [2:0] */ + +/* + * R51 (0x33) - HPOUT2 Mixer + */ +#define WM8993_VRX_TO_HPOUT2 0x0020 /* VRX_TO_HPOUT2 */ +#define WM8993_VRX_TO_HPOUT2_MASK 0x0020 /* VRX_TO_HPOUT2 */ +#define WM8993_VRX_TO_HPOUT2_SHIFT 5 /* VRX_TO_HPOUT2 */ +#define WM8993_VRX_TO_HPOUT2_WIDTH 1 /* VRX_TO_HPOUT2 */ +#define WM8993_MIXOUTLVOL_TO_HPOUT2 0x0010 /* MIXOUTLVOL_TO_HPOUT2 */ +#define WM8993_MIXOUTLVOL_TO_HPOUT2_MASK 0x0010 /* MIXOUTLVOL_TO_HPOUT2 */ +#define WM8993_MIXOUTLVOL_TO_HPOUT2_SHIFT 4 /* MIXOUTLVOL_TO_HPOUT2 */ +#define WM8993_MIXOUTLVOL_TO_HPOUT2_WIDTH 1 /* MIXOUTLVOL_TO_HPOUT2 */ +#define WM8993_MIXOUTRVOL_TO_HPOUT2 0x0008 /* MIXOUTRVOL_TO_HPOUT2 */ +#define WM8993_MIXOUTRVOL_TO_HPOUT2_MASK 0x0008 /* MIXOUTRVOL_TO_HPOUT2 */ +#define WM8993_MIXOUTRVOL_TO_HPOUT2_SHIFT 3 /* MIXOUTRVOL_TO_HPOUT2 */ +#define WM8993_MIXOUTRVOL_TO_HPOUT2_WIDTH 1 /* MIXOUTRVOL_TO_HPOUT2 */ + +/* + * R52 (0x34) - Line Mixer1 + */ +#define WM8993_MIXOUTL_TO_LINEOUT1N 0x0040 /* MIXOUTL_TO_LINEOUT1N */ +#define WM8993_MIXOUTL_TO_LINEOUT1N_MASK 0x0040 /* MIXOUTL_TO_LINEOUT1N */ +#define WM8993_MIXOUTL_TO_LINEOUT1N_SHIFT 6 /* MIXOUTL_TO_LINEOUT1N */ +#define WM8993_MIXOUTL_TO_LINEOUT1N_WIDTH 1 /* MIXOUTL_TO_LINEOUT1N */ +#define WM8993_MIXOUTR_TO_LINEOUT1N 0x0020 /* MIXOUTR_TO_LINEOUT1N */ +#define WM8993_MIXOUTR_TO_LINEOUT1N_MASK 0x0020 /* MIXOUTR_TO_LINEOUT1N */ +#define WM8993_MIXOUTR_TO_LINEOUT1N_SHIFT 5 /* MIXOUTR_TO_LINEOUT1N */ +#define WM8993_MIXOUTR_TO_LINEOUT1N_WIDTH 1 /* MIXOUTR_TO_LINEOUT1N */ +#define WM8993_LINEOUT1_MODE 0x0010 /* LINEOUT1_MODE */ +#define WM8993_LINEOUT1_MODE_MASK 0x0010 /* LINEOUT1_MODE */ +#define WM8993_LINEOUT1_MODE_SHIFT 4 /* LINEOUT1_MODE */ +#define WM8993_LINEOUT1_MODE_WIDTH 1 /* LINEOUT1_MODE */ +#define WM8993_IN1R_TO_LINEOUT1P 0x0004 /* IN1R_TO_LINEOUT1P */ +#define WM8993_IN1R_TO_LINEOUT1P_MASK 0x0004 /* IN1R_TO_LINEOUT1P */ +#define WM8993_IN1R_TO_LINEOUT1P_SHIFT 2 /* IN1R_TO_LINEOUT1P */ +#define WM8993_IN1R_TO_LINEOUT1P_WIDTH 1 /* IN1R_TO_LINEOUT1P */ +#define WM8993_IN1L_TO_LINEOUT1P 0x0002 /* IN1L_TO_LINEOUT1P */ +#define WM8993_IN1L_TO_LINEOUT1P_MASK 0x0002 /* IN1L_TO_LINEOUT1P */ +#define WM8993_IN1L_TO_LINEOUT1P_SHIFT 1 /* IN1L_TO_LINEOUT1P */ +#define WM8993_IN1L_TO_LINEOUT1P_WIDTH 1 /* IN1L_TO_LINEOUT1P */ +#define WM8993_MIXOUTL_TO_LINEOUT1P 0x0001 /* MIXOUTL_TO_LINEOUT1P */ +#define WM8993_MIXOUTL_TO_LINEOUT1P_MASK 0x0001 /* MIXOUTL_TO_LINEOUT1P */ +#define WM8993_MIXOUTL_TO_LINEOUT1P_SHIFT 0 /* MIXOUTL_TO_LINEOUT1P */ +#define WM8993_MIXOUTL_TO_LINEOUT1P_WIDTH 1 /* MIXOUTL_TO_LINEOUT1P */ + +/* + * R53 (0x35) - Line Mixer2 + */ +#define WM8993_MIXOUTR_TO_LINEOUT2N 0x0040 /* MIXOUTR_TO_LINEOUT2N */ +#define WM8993_MIXOUTR_TO_LINEOUT2N_MASK 0x0040 /* MIXOUTR_TO_LINEOUT2N */ +#define WM8993_MIXOUTR_TO_LINEOUT2N_SHIFT 6 /* MIXOUTR_TO_LINEOUT2N */ +#define WM8993_MIXOUTR_TO_LINEOUT2N_WIDTH 1 /* MIXOUTR_TO_LINEOUT2N */ +#define WM8993_MIXOUTL_TO_LINEOUT2N 0x0020 /* MIXOUTL_TO_LINEOUT2N */ +#define WM8993_MIXOUTL_TO_LINEOUT2N_MASK 0x0020 /* MIXOUTL_TO_LINEOUT2N */ +#define WM8993_MIXOUTL_TO_LINEOUT2N_SHIFT 5 /* MIXOUTL_TO_LINEOUT2N */ +#define WM8993_MIXOUTL_TO_LINEOUT2N_WIDTH 1 /* MIXOUTL_TO_LINEOUT2N */ +#define WM8993_LINEOUT2_MODE 0x0010 /* LINEOUT2_MODE */ +#define WM8993_LINEOUT2_MODE_MASK 0x0010 /* LINEOUT2_MODE */ +#define WM8993_LINEOUT2_MODE_SHIFT 4 /* LINEOUT2_MODE */ +#define WM8993_LINEOUT2_MODE_WIDTH 1 /* LINEOUT2_MODE */ +#define WM8993_IN1L_TO_LINEOUT2P 0x0004 /* IN1L_TO_LINEOUT2P */ +#define WM8993_IN1L_TO_LINEOUT2P_MASK 0x0004 /* IN1L_TO_LINEOUT2P */ +#define WM8993_IN1L_TO_LINEOUT2P_SHIFT 2 /* IN1L_TO_LINEOUT2P */ +#define WM8993_IN1L_TO_LINEOUT2P_WIDTH 1 /* IN1L_TO_LINEOUT2P */ +#define WM8993_IN1R_TO_LINEOUT2P 0x0002 /* IN1R_TO_LINEOUT2P */ +#define WM8993_IN1R_TO_LINEOUT2P_MASK 0x0002 /* IN1R_TO_LINEOUT2P */ +#define WM8993_IN1R_TO_LINEOUT2P_SHIFT 1 /* IN1R_TO_LINEOUT2P */ +#define WM8993_IN1R_TO_LINEOUT2P_WIDTH 1 /* IN1R_TO_LINEOUT2P */ +#define WM8993_MIXOUTR_TO_LINEOUT2P 0x0001 /* MIXOUTR_TO_LINEOUT2P */ +#define WM8993_MIXOUTR_TO_LINEOUT2P_MASK 0x0001 /* MIXOUTR_TO_LINEOUT2P */ +#define WM8993_MIXOUTR_TO_LINEOUT2P_SHIFT 0 /* MIXOUTR_TO_LINEOUT2P */ +#define WM8993_MIXOUTR_TO_LINEOUT2P_WIDTH 1 /* MIXOUTR_TO_LINEOUT2P */ + +/* + * R54 (0x36) - Speaker Mixer + */ +#define WM8993_SPKAB_REF_SEL 0x0100 /* SPKAB_REF_SEL */ +#define WM8993_SPKAB_REF_SEL_MASK 0x0100 /* SPKAB_REF_SEL */ +#define WM8993_SPKAB_REF_SEL_SHIFT 8 /* SPKAB_REF_SEL */ +#define WM8993_SPKAB_REF_SEL_WIDTH 1 /* SPKAB_REF_SEL */ +#define WM8993_MIXINL_TO_SPKMIXL 0x0080 /* MIXINL_TO_SPKMIXL */ +#define WM8993_MIXINL_TO_SPKMIXL_MASK 0x0080 /* MIXINL_TO_SPKMIXL */ +#define WM8993_MIXINL_TO_SPKMIXL_SHIFT 7 /* MIXINL_TO_SPKMIXL */ +#define WM8993_MIXINL_TO_SPKMIXL_WIDTH 1 /* MIXINL_TO_SPKMIXL */ +#define WM8993_MIXINR_TO_SPKMIXR 0x0040 /* MIXINR_TO_SPKMIXR */ +#define WM8993_MIXINR_TO_SPKMIXR_MASK 0x0040 /* MIXINR_TO_SPKMIXR */ +#define WM8993_MIXINR_TO_SPKMIXR_SHIFT 6 /* MIXINR_TO_SPKMIXR */ +#define WM8993_MIXINR_TO_SPKMIXR_WIDTH 1 /* MIXINR_TO_SPKMIXR */ +#define WM8993_IN1LP_TO_SPKMIXL 0x0020 /* IN1LP_TO_SPKMIXL */ +#define WM8993_IN1LP_TO_SPKMIXL_MASK 0x0020 /* IN1LP_TO_SPKMIXL */ +#define WM8993_IN1LP_TO_SPKMIXL_SHIFT 5 /* IN1LP_TO_SPKMIXL */ +#define WM8993_IN1LP_TO_SPKMIXL_WIDTH 1 /* IN1LP_TO_SPKMIXL */ +#define WM8993_IN1RP_TO_SPKMIXR 0x0010 /* IN1RP_TO_SPKMIXR */ +#define WM8993_IN1RP_TO_SPKMIXR_MASK 0x0010 /* IN1RP_TO_SPKMIXR */ +#define WM8993_IN1RP_TO_SPKMIXR_SHIFT 4 /* IN1RP_TO_SPKMIXR */ +#define WM8993_IN1RP_TO_SPKMIXR_WIDTH 1 /* IN1RP_TO_SPKMIXR */ +#define WM8993_MIXOUTL_TO_SPKMIXL 0x0008 /* MIXOUTL_TO_SPKMIXL */ +#define WM8993_MIXOUTL_TO_SPKMIXL_MASK 0x0008 /* MIXOUTL_TO_SPKMIXL */ +#define WM8993_MIXOUTL_TO_SPKMIXL_SHIFT 3 /* MIXOUTL_TO_SPKMIXL */ +#define WM8993_MIXOUTL_TO_SPKMIXL_WIDTH 1 /* MIXOUTL_TO_SPKMIXL */ +#define WM8993_MIXOUTR_TO_SPKMIXR 0x0004 /* MIXOUTR_TO_SPKMIXR */ +#define WM8993_MIXOUTR_TO_SPKMIXR_MASK 0x0004 /* MIXOUTR_TO_SPKMIXR */ +#define WM8993_MIXOUTR_TO_SPKMIXR_SHIFT 2 /* MIXOUTR_TO_SPKMIXR */ +#define WM8993_MIXOUTR_TO_SPKMIXR_WIDTH 1 /* MIXOUTR_TO_SPKMIXR */ +#define WM8993_DACL_TO_SPKMIXL 0x0002 /* DACL_TO_SPKMIXL */ +#define WM8993_DACL_TO_SPKMIXL_MASK 0x0002 /* DACL_TO_SPKMIXL */ +#define WM8993_DACL_TO_SPKMIXL_SHIFT 1 /* DACL_TO_SPKMIXL */ +#define WM8993_DACL_TO_SPKMIXL_WIDTH 1 /* DACL_TO_SPKMIXL */ +#define WM8993_DACR_TO_SPKMIXR 0x0001 /* DACR_TO_SPKMIXR */ +#define WM8993_DACR_TO_SPKMIXR_MASK 0x0001 /* DACR_TO_SPKMIXR */ +#define WM8993_DACR_TO_SPKMIXR_SHIFT 0 /* DACR_TO_SPKMIXR */ +#define WM8993_DACR_TO_SPKMIXR_WIDTH 1 /* DACR_TO_SPKMIXR */ + +/* + * R55 (0x37) - Additional Control + */ +#define WM8993_LINEOUT1_FB 0x0080 /* LINEOUT1_FB */ +#define WM8993_LINEOUT1_FB_MASK 0x0080 /* LINEOUT1_FB */ +#define WM8993_LINEOUT1_FB_SHIFT 7 /* LINEOUT1_FB */ +#define WM8993_LINEOUT1_FB_WIDTH 1 /* LINEOUT1_FB */ +#define WM8993_LINEOUT2_FB 0x0040 /* LINEOUT2_FB */ +#define WM8993_LINEOUT2_FB_MASK 0x0040 /* LINEOUT2_FB */ +#define WM8993_LINEOUT2_FB_SHIFT 6 /* LINEOUT2_FB */ +#define WM8993_LINEOUT2_FB_WIDTH 1 /* LINEOUT2_FB */ +#define WM8993_VROI 0x0001 /* VROI */ +#define WM8993_VROI_MASK 0x0001 /* VROI */ +#define WM8993_VROI_SHIFT 0 /* VROI */ +#define WM8993_VROI_WIDTH 1 /* VROI */ + +/* + * R56 (0x38) - AntiPOP1 + */ +#define WM8993_LINEOUT_VMID_BUF_ENA 0x0080 /* LINEOUT_VMID_BUF_ENA */ +#define WM8993_LINEOUT_VMID_BUF_ENA_MASK 0x0080 /* LINEOUT_VMID_BUF_ENA */ +#define WM8993_LINEOUT_VMID_BUF_ENA_SHIFT 7 /* LINEOUT_VMID_BUF_ENA */ +#define WM8993_LINEOUT_VMID_BUF_ENA_WIDTH 1 /* LINEOUT_VMID_BUF_ENA */ +#define WM8993_HPOUT2_IN_ENA 0x0040 /* HPOUT2_IN_ENA */ +#define WM8993_HPOUT2_IN_ENA_MASK 0x0040 /* HPOUT2_IN_ENA */ +#define WM8993_HPOUT2_IN_ENA_SHIFT 6 /* HPOUT2_IN_ENA */ +#define WM8993_HPOUT2_IN_ENA_WIDTH 1 /* HPOUT2_IN_ENA */ +#define WM8993_LINEOUT1_DISCH 0x0020 /* LINEOUT1_DISCH */ +#define WM8993_LINEOUT1_DISCH_MASK 0x0020 /* LINEOUT1_DISCH */ +#define WM8993_LINEOUT1_DISCH_SHIFT 5 /* LINEOUT1_DISCH */ +#define WM8993_LINEOUT1_DISCH_WIDTH 1 /* LINEOUT1_DISCH */ +#define WM8993_LINEOUT2_DISCH 0x0010 /* LINEOUT2_DISCH */ +#define WM8993_LINEOUT2_DISCH_MASK 0x0010 /* LINEOUT2_DISCH */ +#define WM8993_LINEOUT2_DISCH_SHIFT 4 /* LINEOUT2_DISCH */ +#define WM8993_LINEOUT2_DISCH_WIDTH 1 /* LINEOUT2_DISCH */ + +/* + * R57 (0x39) - AntiPOP2 + */ +#define WM8993_VMID_RAMP_MASK 0x0060 /* VMID_RAMP - [6:5] */ +#define WM8993_VMID_RAMP_SHIFT 5 /* VMID_RAMP - [6:5] */ +#define WM8993_VMID_RAMP_WIDTH 2 /* VMID_RAMP - [6:5] */ +#define WM8993_VMID_BUF_ENA 0x0008 /* VMID_BUF_ENA */ +#define WM8993_VMID_BUF_ENA_MASK 0x0008 /* VMID_BUF_ENA */ +#define WM8993_VMID_BUF_ENA_SHIFT 3 /* VMID_BUF_ENA */ +#define WM8993_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */ +#define WM8993_STARTUP_BIAS_ENA 0x0004 /* STARTUP_BIAS_ENA */ +#define WM8993_STARTUP_BIAS_ENA_MASK 0x0004 /* STARTUP_BIAS_ENA */ +#define WM8993_STARTUP_BIAS_ENA_SHIFT 2 /* STARTUP_BIAS_ENA */ +#define WM8993_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */ +#define WM8993_BIAS_SRC 0x0002 /* BIAS_SRC */ +#define WM8993_BIAS_SRC_MASK 0x0002 /* BIAS_SRC */ +#define WM8993_BIAS_SRC_SHIFT 1 /* BIAS_SRC */ +#define WM8993_BIAS_SRC_WIDTH 1 /* BIAS_SRC */ +#define WM8993_VMID_DISCH 0x0001 /* VMID_DISCH */ +#define WM8993_VMID_DISCH_MASK 0x0001 /* VMID_DISCH */ +#define WM8993_VMID_DISCH_SHIFT 0 /* VMID_DISCH */ +#define WM8993_VMID_DISCH_WIDTH 1 /* VMID_DISCH */ + +/* + * R58 (0x3A) - MICBIAS + */ +#define WM8993_JD_SCTHR_MASK 0x00C0 /* JD_SCTHR - [7:6] */ +#define WM8993_JD_SCTHR_SHIFT 6 /* JD_SCTHR - [7:6] */ +#define WM8993_JD_SCTHR_WIDTH 2 /* JD_SCTHR - [7:6] */ +#define WM8993_JD_THR_MASK 0x0030 /* JD_THR - [5:4] */ +#define WM8993_JD_THR_SHIFT 4 /* JD_THR - [5:4] */ +#define WM8993_JD_THR_WIDTH 2 /* JD_THR - [5:4] */ +#define WM8993_JD_ENA 0x0004 /* JD_ENA */ +#define WM8993_JD_ENA_MASK 0x0004 /* JD_ENA */ +#define WM8993_JD_ENA_SHIFT 2 /* JD_ENA */ +#define WM8993_JD_ENA_WIDTH 1 /* JD_ENA */ +#define WM8993_MICB2_LVL 0x0002 /* MICB2_LVL */ +#define WM8993_MICB2_LVL_MASK 0x0002 /* MICB2_LVL */ +#define WM8993_MICB2_LVL_SHIFT 1 /* MICB2_LVL */ +#define WM8993_MICB2_LVL_WIDTH 1 /* MICB2_LVL */ +#define WM8993_MICB1_LVL 0x0001 /* MICB1_LVL */ +#define WM8993_MICB1_LVL_MASK 0x0001 /* MICB1_LVL */ +#define WM8993_MICB1_LVL_SHIFT 0 /* MICB1_LVL */ +#define WM8993_MICB1_LVL_WIDTH 1 /* MICB1_LVL */ + +/* + * R60 (0x3C) - FLL Control 1 + */ +#define WM8993_FLL_FRAC 0x0004 /* FLL_FRAC */ +#define WM8993_FLL_FRAC_MASK 0x0004 /* FLL_FRAC */ +#define WM8993_FLL_FRAC_SHIFT 2 /* FLL_FRAC */ +#define WM8993_FLL_FRAC_WIDTH 1 /* FLL_FRAC */ +#define WM8993_FLL_OSC_ENA 0x0002 /* FLL_OSC_ENA */ +#define WM8993_FLL_OSC_ENA_MASK 0x0002 /* FLL_OSC_ENA */ +#define WM8993_FLL_OSC_ENA_SHIFT 1 /* FLL_OSC_ENA */ +#define WM8993_FLL_OSC_ENA_WIDTH 1 /* FLL_OSC_ENA */ +#define WM8993_FLL_ENA 0x0001 /* FLL_ENA */ +#define WM8993_FLL_ENA_MASK 0x0001 /* FLL_ENA */ +#define WM8993_FLL_ENA_SHIFT 0 /* FLL_ENA */ +#define WM8993_FLL_ENA_WIDTH 1 /* FLL_ENA */ + +/* + * R61 (0x3D) - FLL Control 2 + */ +#define WM8993_FLL_OUTDIV_MASK 0x0700 /* FLL_OUTDIV - [10:8] */ +#define WM8993_FLL_OUTDIV_SHIFT 8 /* FLL_OUTDIV - [10:8] */ +#define WM8993_FLL_OUTDIV_WIDTH 3 /* FLL_OUTDIV - [10:8] */ +#define WM8993_FLL_CTRL_RATE_MASK 0x0070 /* FLL_CTRL_RATE - [6:4] */ +#define WM8993_FLL_CTRL_RATE_SHIFT 4 /* FLL_CTRL_RATE - [6:4] */ +#define WM8993_FLL_CTRL_RATE_WIDTH 3 /* FLL_CTRL_RATE - [6:4] */ +#define WM8993_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */ +#define WM8993_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */ +#define WM8993_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */ + +/* + * R62 (0x3E) - FLL Control 3 + */ +#define WM8993_FLL_K_MASK 0xFFFF /* FLL_K - [15:0] */ +#define WM8993_FLL_K_SHIFT 0 /* FLL_K - [15:0] */ +#define WM8993_FLL_K_WIDTH 16 /* FLL_K - [15:0] */ + +/* + * R63 (0x3F) - FLL Control 4 + */ +#define WM8993_FLL_N_MASK 0x7FE0 /* FLL_N - [14:5] */ +#define WM8993_FLL_N_SHIFT 5 /* FLL_N - [14:5] */ +#define WM8993_FLL_N_WIDTH 10 /* FLL_N - [14:5] */ +#define WM8993_FLL_GAIN_MASK 0x000F /* FLL_GAIN - [3:0] */ +#define WM8993_FLL_GAIN_SHIFT 0 /* FLL_GAIN - [3:0] */ +#define WM8993_FLL_GAIN_WIDTH 4 /* FLL_GAIN - [3:0] */ + +/* + * R64 (0x40) - FLL Control 5 + */ +#define WM8993_FLL_FRC_NCO_VAL_MASK 0x1F80 /* FLL_FRC_NCO_VAL - [12:7] */ +#define WM8993_FLL_FRC_NCO_VAL_SHIFT 7 /* FLL_FRC_NCO_VAL - [12:7] */ +#define WM8993_FLL_FRC_NCO_VAL_WIDTH 6 /* FLL_FRC_NCO_VAL - [12:7] */ +#define WM8993_FLL_FRC_NCO 0x0040 /* FLL_FRC_NCO */ +#define WM8993_FLL_FRC_NCO_MASK 0x0040 /* FLL_FRC_NCO */ +#define WM8993_FLL_FRC_NCO_SHIFT 6 /* FLL_FRC_NCO */ +#define WM8993_FLL_FRC_NCO_WIDTH 1 /* FLL_FRC_NCO */ +#define WM8993_FLL_CLK_REF_DIV_MASK 0x0018 /* FLL_CLK_REF_DIV - [4:3] */ +#define WM8993_FLL_CLK_REF_DIV_SHIFT 3 /* FLL_CLK_REF_DIV - [4:3] */ +#define WM8993_FLL_CLK_REF_DIV_WIDTH 2 /* FLL_CLK_REF_DIV - [4:3] */ +#define WM8993_FLL_CLK_SRC_MASK 0x0003 /* FLL_CLK_SRC - [1:0] */ +#define WM8993_FLL_CLK_SRC_SHIFT 0 /* FLL_CLK_SRC - [1:0] */ +#define WM8993_FLL_CLK_SRC_WIDTH 2 /* FLL_CLK_SRC - [1:0] */ + +/* + * R65 (0x41) - Clocking 3 + */ +#define WM8993_CLK_DCS_DIV_MASK 0x3C00 /* CLK_DCS_DIV - [13:10] */ +#define WM8993_CLK_DCS_DIV_SHIFT 10 /* CLK_DCS_DIV - [13:10] */ +#define WM8993_CLK_DCS_DIV_WIDTH 4 /* CLK_DCS_DIV - [13:10] */ +#define WM8993_SAMPLE_RATE_MASK 0x0380 /* SAMPLE_RATE - [9:7] */ +#define WM8993_SAMPLE_RATE_SHIFT 7 /* SAMPLE_RATE - [9:7] */ +#define WM8993_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [9:7] */ +#define WM8993_CLK_SYS_RATE_MASK 0x001E /* CLK_SYS_RATE - [4:1] */ +#define WM8993_CLK_SYS_RATE_SHIFT 1 /* CLK_SYS_RATE - [4:1] */ +#define WM8993_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [4:1] */ +#define WM8993_CLK_DSP_ENA 0x0001 /* CLK_DSP_ENA */ +#define WM8993_CLK_DSP_ENA_MASK 0x0001 /* CLK_DSP_ENA */ +#define WM8993_CLK_DSP_ENA_SHIFT 0 /* CLK_DSP_ENA */ +#define WM8993_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */ + +/* + * R66 (0x42) - Clocking 4 + */ +#define WM8993_DAC_DIV4 0x0200 /* DAC_DIV4 */ +#define WM8993_DAC_DIV4_MASK 0x0200 /* DAC_DIV4 */ +#define WM8993_DAC_DIV4_SHIFT 9 /* DAC_DIV4 */ +#define WM8993_DAC_DIV4_WIDTH 1 /* DAC_DIV4 */ +#define WM8993_CLK_256K_DIV_MASK 0x007E /* CLK_256K_DIV - [6:1] */ +#define WM8993_CLK_256K_DIV_SHIFT 1 /* CLK_256K_DIV - [6:1] */ +#define WM8993_CLK_256K_DIV_WIDTH 6 /* CLK_256K_DIV - [6:1] */ +#define WM8993_SR_MODE 0x0001 /* SR_MODE */ +#define WM8993_SR_MODE_MASK 0x0001 /* SR_MODE */ +#define WM8993_SR_MODE_SHIFT 0 /* SR_MODE */ +#define WM8993_SR_MODE_WIDTH 1 /* SR_MODE */ + +/* + * R67 (0x43) - MW Slave Control + */ +#define WM8993_MASK_WRITE_ENA 0x0001 /* MASK_WRITE_ENA */ +#define WM8993_MASK_WRITE_ENA_MASK 0x0001 /* MASK_WRITE_ENA */ +#define WM8993_MASK_WRITE_ENA_SHIFT 0 /* MASK_WRITE_ENA */ +#define WM8993_MASK_WRITE_ENA_WIDTH 1 /* MASK_WRITE_ENA */ + +/* + * R69 (0x45) - Bus Control 1 + */ +#define WM8993_CLK_SYS_ENA 0x0002 /* CLK_SYS_ENA */ +#define WM8993_CLK_SYS_ENA_MASK 0x0002 /* CLK_SYS_ENA */ +#define WM8993_CLK_SYS_ENA_SHIFT 1 /* CLK_SYS_ENA */ +#define WM8993_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */ + +/* + * R70 (0x46) - Write Sequencer 0 + */ +#define WM8993_WSEQ_ENA 0x0100 /* WSEQ_ENA */ +#define WM8993_WSEQ_ENA_MASK 0x0100 /* WSEQ_ENA */ +#define WM8993_WSEQ_ENA_SHIFT 8 /* WSEQ_ENA */ +#define WM8993_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */ +#define WM8993_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */ +#define WM8993_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */ +#define WM8993_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */ + +/* + * R71 (0x47) - Write Sequencer 1 + */ +#define WM8993_WSEQ_DATA_WIDTH_MASK 0x7000 /* WSEQ_DATA_WIDTH - [14:12] */ +#define WM8993_WSEQ_DATA_WIDTH_SHIFT 12 /* WSEQ_DATA_WIDTH - [14:12] */ +#define WM8993_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [14:12] */ +#define WM8993_WSEQ_DATA_START_MASK 0x0F00 /* WSEQ_DATA_START - [11:8] */ +#define WM8993_WSEQ_DATA_START_SHIFT 8 /* WSEQ_DATA_START - [11:8] */ +#define WM8993_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [11:8] */ +#define WM8993_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */ +#define WM8993_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */ +#define WM8993_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */ + +/* + * R72 (0x48) - Write Sequencer 2 + */ +#define WM8993_WSEQ_EOS 0x4000 /* WSEQ_EOS */ +#define WM8993_WSEQ_EOS_MASK 0x4000 /* WSEQ_EOS */ +#define WM8993_WSEQ_EOS_SHIFT 14 /* WSEQ_EOS */ +#define WM8993_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */ +#define WM8993_WSEQ_DELAY_MASK 0x0F00 /* WSEQ_DELAY - [11:8] */ +#define WM8993_WSEQ_DELAY_SHIFT 8 /* WSEQ_DELAY - [11:8] */ +#define WM8993_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [11:8] */ +#define WM8993_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */ +#define WM8993_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */ +#define WM8993_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */ + +/* + * R73 (0x49) - Write Sequencer 3 + */ +#define WM8993_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */ +#define WM8993_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */ +#define WM8993_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */ +#define WM8993_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */ +#define WM8993_WSEQ_START 0x0100 /* WSEQ_START */ +#define WM8993_WSEQ_START_MASK 0x0100 /* WSEQ_START */ +#define WM8993_WSEQ_START_SHIFT 8 /* WSEQ_START */ +#define WM8993_WSEQ_START_WIDTH 1 /* WSEQ_START */ +#define WM8993_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */ +#define WM8993_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */ +#define WM8993_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */ + +/* + * R74 (0x4A) - Write Sequencer 4 + */ +#define WM8993_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */ +#define WM8993_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */ +#define WM8993_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */ +#define WM8993_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */ + +/* + * R75 (0x4B) - Write Sequencer 5 + */ +#define WM8993_WSEQ_CURRENT_INDEX_MASK 0x003F /* WSEQ_CURRENT_INDEX - [5:0] */ +#define WM8993_WSEQ_CURRENT_INDEX_SHIFT 0 /* WSEQ_CURRENT_INDEX - [5:0] */ +#define WM8993_WSEQ_CURRENT_INDEX_WIDTH 6 /* WSEQ_CURRENT_INDEX - [5:0] */ + +/* + * R76 (0x4C) - Charge Pump 1 + */ +#define WM8993_CP_ENA 0x8000 /* CP_ENA */ +#define WM8993_CP_ENA_MASK 0x8000 /* CP_ENA */ +#define WM8993_CP_ENA_SHIFT 15 /* CP_ENA */ +#define WM8993_CP_ENA_WIDTH 1 /* CP_ENA */ + +/* + * R81 (0x51) - Class W 0 + */ +#define WM8993_CP_DYN_FREQ 0x0002 /* CP_DYN_FREQ */ +#define WM8993_CP_DYN_FREQ_MASK 0x0002 /* CP_DYN_FREQ */ +#define WM8993_CP_DYN_FREQ_SHIFT 1 /* CP_DYN_FREQ */ +#define WM8993_CP_DYN_FREQ_WIDTH 1 /* CP_DYN_FREQ */ +#define WM8993_CP_DYN_V 0x0001 /* CP_DYN_V */ +#define WM8993_CP_DYN_V_MASK 0x0001 /* CP_DYN_V */ +#define WM8993_CP_DYN_V_SHIFT 0 /* CP_DYN_V */ +#define WM8993_CP_DYN_V_WIDTH 1 /* CP_DYN_V */ + +/* + * R84 (0x54) - DC Servo 0 + */ +#define WM8993_DCS_TRIG_SINGLE_1 0x2000 /* DCS_TRIG_SINGLE_1 */ +#define WM8993_DCS_TRIG_SINGLE_1_MASK 0x2000 /* DCS_TRIG_SINGLE_1 */ +#define WM8993_DCS_TRIG_SINGLE_1_SHIFT 13 /* DCS_TRIG_SINGLE_1 */ +#define WM8993_DCS_TRIG_SINGLE_1_WIDTH 1 /* DCS_TRIG_SINGLE_1 */ +#define WM8993_DCS_TRIG_SINGLE_0 0x1000 /* DCS_TRIG_SINGLE_0 */ +#define WM8993_DCS_TRIG_SINGLE_0_MASK 0x1000 /* DCS_TRIG_SINGLE_0 */ +#define WM8993_DCS_TRIG_SINGLE_0_SHIFT 12 /* DCS_TRIG_SINGLE_0 */ +#define WM8993_DCS_TRIG_SINGLE_0_WIDTH 1 /* DCS_TRIG_SINGLE_0 */ +#define WM8993_DCS_TRIG_SERIES_1 0x0200 /* DCS_TRIG_SERIES_1 */ +#define WM8993_DCS_TRIG_SERIES_1_MASK 0x0200 /* DCS_TRIG_SERIES_1 */ +#define WM8993_DCS_TRIG_SERIES_1_SHIFT 9 /* DCS_TRIG_SERIES_1 */ +#define WM8993_DCS_TRIG_SERIES_1_WIDTH 1 /* DCS_TRIG_SERIES_1 */ +#define WM8993_DCS_TRIG_SERIES_0 0x0100 /* DCS_TRIG_SERIES_0 */ +#define WM8993_DCS_TRIG_SERIES_0_MASK 0x0100 /* DCS_TRIG_SERIES_0 */ +#define WM8993_DCS_TRIG_SERIES_0_SHIFT 8 /* DCS_TRIG_SERIES_0 */ +#define WM8993_DCS_TRIG_SERIES_0_WIDTH 1 /* DCS_TRIG_SERIES_0 */ +#define WM8993_DCS_TRIG_STARTUP_1 0x0020 /* DCS_TRIG_STARTUP_1 */ +#define WM8993_DCS_TRIG_STARTUP_1_MASK 0x0020 /* DCS_TRIG_STARTUP_1 */ +#define WM8993_DCS_TRIG_STARTUP_1_SHIFT 5 /* DCS_TRIG_STARTUP_1 */ +#define WM8993_DCS_TRIG_STARTUP_1_WIDTH 1 /* DCS_TRIG_STARTUP_1 */ +#define WM8993_DCS_TRIG_STARTUP_0 0x0010 /* DCS_TRIG_STARTUP_0 */ +#define WM8993_DCS_TRIG_STARTUP_0_MASK 0x0010 /* DCS_TRIG_STARTUP_0 */ +#define WM8993_DCS_TRIG_STARTUP_0_SHIFT 4 /* DCS_TRIG_STARTUP_0 */ +#define WM8993_DCS_TRIG_STARTUP_0_WIDTH 1 /* DCS_TRIG_STARTUP_0 */ +#define WM8993_DCS_TRIG_DAC_WR_1 0x0008 /* DCS_TRIG_DAC_WR_1 */ +#define WM8993_DCS_TRIG_DAC_WR_1_MASK 0x0008 /* DCS_TRIG_DAC_WR_1 */ +#define WM8993_DCS_TRIG_DAC_WR_1_SHIFT 3 /* DCS_TRIG_DAC_WR_1 */ +#define WM8993_DCS_TRIG_DAC_WR_1_WIDTH 1 /* DCS_TRIG_DAC_WR_1 */ +#define WM8993_DCS_TRIG_DAC_WR_0 0x0004 /* DCS_TRIG_DAC_WR_0 */ +#define WM8993_DCS_TRIG_DAC_WR_0_MASK 0x0004 /* DCS_TRIG_DAC_WR_0 */ +#define WM8993_DCS_TRIG_DAC_WR_0_SHIFT 2 /* DCS_TRIG_DAC_WR_0 */ +#define WM8993_DCS_TRIG_DAC_WR_0_WIDTH 1 /* DCS_TRIG_DAC_WR_0 */ +#define WM8993_DCS_ENA_CHAN_1 0x0002 /* DCS_ENA_CHAN_1 */ +#define WM8993_DCS_ENA_CHAN_1_MASK 0x0002 /* DCS_ENA_CHAN_1 */ +#define WM8993_DCS_ENA_CHAN_1_SHIFT 1 /* DCS_ENA_CHAN_1 */ +#define WM8993_DCS_ENA_CHAN_1_WIDTH 1 /* DCS_ENA_CHAN_1 */ +#define WM8993_DCS_ENA_CHAN_0 0x0001 /* DCS_ENA_CHAN_0 */ +#define WM8993_DCS_ENA_CHAN_0_MASK 0x0001 /* DCS_ENA_CHAN_0 */ +#define WM8993_DCS_ENA_CHAN_0_SHIFT 0 /* DCS_ENA_CHAN_0 */ +#define WM8993_DCS_ENA_CHAN_0_WIDTH 1 /* DCS_ENA_CHAN_0 */ + +/* + * R85 (0x55) - DC Servo 1 + */ +#define WM8993_DCS_SERIES_NO_01_MASK 0x0FE0 /* DCS_SERIES_NO_01 - [11:5] */ +#define WM8993_DCS_SERIES_NO_01_SHIFT 5 /* DCS_SERIES_NO_01 - [11:5] */ +#define WM8993_DCS_SERIES_NO_01_WIDTH 7 /* DCS_SERIES_NO_01 - [11:5] */ +#define WM8993_DCS_TIMER_PERIOD_01_MASK 0x000F /* DCS_TIMER_PERIOD_01 - [3:0] */ +#define WM8993_DCS_TIMER_PERIOD_01_SHIFT 0 /* DCS_TIMER_PERIOD_01 - [3:0] */ +#define WM8993_DCS_TIMER_PERIOD_01_WIDTH 4 /* DCS_TIMER_PERIOD_01 - [3:0] */ + +/* + * R87 (0x57) - DC Servo 3 + */ +#define WM8993_DCS_DAC_WR_VAL_1_MASK 0xFF00 /* DCS_DAC_WR_VAL_1 - [15:8] */ +#define WM8993_DCS_DAC_WR_VAL_1_SHIFT 8 /* DCS_DAC_WR_VAL_1 - [15:8] */ +#define WM8993_DCS_DAC_WR_VAL_1_WIDTH 8 /* DCS_DAC_WR_VAL_1 - [15:8] */ +#define WM8993_DCS_DAC_WR_VAL_0_MASK 0x00FF /* DCS_DAC_WR_VAL_0 - [7:0] */ +#define WM8993_DCS_DAC_WR_VAL_0_SHIFT 0 /* DCS_DAC_WR_VAL_0 - [7:0] */ +#define WM8993_DCS_DAC_WR_VAL_0_WIDTH 8 /* DCS_DAC_WR_VAL_0 - [7:0] */ + +/* + * R88 (0x58) - DC Servo Readback 0 + */ +#define WM8993_DCS_DATAPATH_BUSY 0x4000 /* DCS_DATAPATH_BUSY */ +#define WM8993_DCS_DATAPATH_BUSY_MASK 0x4000 /* DCS_DATAPATH_BUSY */ +#define WM8993_DCS_DATAPATH_BUSY_SHIFT 14 /* DCS_DATAPATH_BUSY */ +#define WM8993_DCS_DATAPATH_BUSY_WIDTH 1 /* DCS_DATAPATH_BUSY */ +#define WM8993_DCS_CHANNEL_MASK 0x3000 /* DCS_CHANNEL - [13:12] */ +#define WM8993_DCS_CHANNEL_SHIFT 12 /* DCS_CHANNEL - [13:12] */ +#define WM8993_DCS_CHANNEL_WIDTH 2 /* DCS_CHANNEL - [13:12] */ +#define WM8993_DCS_CAL_COMPLETE_MASK 0x0300 /* DCS_CAL_COMPLETE - [9:8] */ +#define WM8993_DCS_CAL_COMPLETE_SHIFT 8 /* DCS_CAL_COMPLETE - [9:8] */ +#define WM8993_DCS_CAL_COMPLETE_WIDTH 2 /* DCS_CAL_COMPLETE - [9:8] */ +#define WM8993_DCS_DAC_WR_COMPLETE_MASK 0x0030 /* DCS_DAC_WR_COMPLETE - [5:4] */ +#define WM8993_DCS_DAC_WR_COMPLETE_SHIFT 4 /* DCS_DAC_WR_COMPLETE - [5:4] */ +#define WM8993_DCS_DAC_WR_COMPLETE_WIDTH 2 /* DCS_DAC_WR_COMPLETE - [5:4] */ +#define WM8993_DCS_STARTUP_COMPLETE_MASK 0x0003 /* DCS_STARTUP_COMPLETE - [1:0] */ +#define WM8993_DCS_STARTUP_COMPLETE_SHIFT 0 /* DCS_STARTUP_COMPLETE - [1:0] */ +#define WM8993_DCS_STARTUP_COMPLETE_WIDTH 2 /* DCS_STARTUP_COMPLETE - [1:0] */ + +/* + * R89 (0x59) - DC Servo Readback 1 + */ +#define WM8993_DCS_INTEG_CHAN_1_MASK 0x00FF /* DCS_INTEG_CHAN_1 - [7:0] */ +#define WM8993_DCS_INTEG_CHAN_1_SHIFT 0 /* DCS_INTEG_CHAN_1 - [7:0] */ +#define WM8993_DCS_INTEG_CHAN_1_WIDTH 8 /* DCS_INTEG_CHAN_1 - [7:0] */ + +/* + * R90 (0x5A) - DC Servo Readback 2 + */ +#define WM8993_DCS_INTEG_CHAN_0_MASK 0x00FF /* DCS_INTEG_CHAN_0 - [7:0] */ +#define WM8993_DCS_INTEG_CHAN_0_SHIFT 0 /* DCS_INTEG_CHAN_0 - [7:0] */ +#define WM8993_DCS_INTEG_CHAN_0_WIDTH 8 /* DCS_INTEG_CHAN_0 - [7:0] */ + +/* + * R96 (0x60) - Analogue HP 0 + */ +#define WM8993_HPOUT1_AUTO_PU 0x0100 /* HPOUT1_AUTO_PU */ +#define WM8993_HPOUT1_AUTO_PU_MASK 0x0100 /* HPOUT1_AUTO_PU */ +#define WM8993_HPOUT1_AUTO_PU_SHIFT 8 /* HPOUT1_AUTO_PU */ +#define WM8993_HPOUT1_AUTO_PU_WIDTH 1 /* HPOUT1_AUTO_PU */ +#define WM8993_HPOUT1L_RMV_SHORT 0x0080 /* HPOUT1L_RMV_SHORT */ +#define WM8993_HPOUT1L_RMV_SHORT_MASK 0x0080 /* HPOUT1L_RMV_SHORT */ +#define WM8993_HPOUT1L_RMV_SHORT_SHIFT 7 /* HPOUT1L_RMV_SHORT */ +#define WM8993_HPOUT1L_RMV_SHORT_WIDTH 1 /* HPOUT1L_RMV_SHORT */ +#define WM8993_HPOUT1L_OUTP 0x0040 /* HPOUT1L_OUTP */ +#define WM8993_HPOUT1L_OUTP_MASK 0x0040 /* HPOUT1L_OUTP */ +#define WM8993_HPOUT1L_OUTP_SHIFT 6 /* HPOUT1L_OUTP */ +#define WM8993_HPOUT1L_OUTP_WIDTH 1 /* HPOUT1L_OUTP */ +#define WM8993_HPOUT1L_DLY 0x0020 /* HPOUT1L_DLY */ +#define WM8993_HPOUT1L_DLY_MASK 0x0020 /* HPOUT1L_DLY */ +#define WM8993_HPOUT1L_DLY_SHIFT 5 /* HPOUT1L_DLY */ +#define WM8993_HPOUT1L_DLY_WIDTH 1 /* HPOUT1L_DLY */ +#define WM8993_HPOUT1R_RMV_SHORT 0x0008 /* HPOUT1R_RMV_SHORT */ +#define WM8993_HPOUT1R_RMV_SHORT_MASK 0x0008 /* HPOUT1R_RMV_SHORT */ +#define WM8993_HPOUT1R_RMV_SHORT_SHIFT 3 /* HPOUT1R_RMV_SHORT */ +#define WM8993_HPOUT1R_RMV_SHORT_WIDTH 1 /* HPOUT1R_RMV_SHORT */ +#define WM8993_HPOUT1R_OUTP 0x0004 /* HPOUT1R_OUTP */ +#define WM8993_HPOUT1R_OUTP_MASK 0x0004 /* HPOUT1R_OUTP */ +#define WM8993_HPOUT1R_OUTP_SHIFT 2 /* HPOUT1R_OUTP */ +#define WM8993_HPOUT1R_OUTP_WIDTH 1 /* HPOUT1R_OUTP */ +#define WM8993_HPOUT1R_DLY 0x0002 /* HPOUT1R_DLY */ +#define WM8993_HPOUT1R_DLY_MASK 0x0002 /* HPOUT1R_DLY */ +#define WM8993_HPOUT1R_DLY_SHIFT 1 /* HPOUT1R_DLY */ +#define WM8993_HPOUT1R_DLY_WIDTH 1 /* HPOUT1R_DLY */ + +/* + * R98 (0x62) - EQ1 + */ +#define WM8993_EQ_ENA 0x0001 /* EQ_ENA */ +#define WM8993_EQ_ENA_MASK 0x0001 /* EQ_ENA */ +#define WM8993_EQ_ENA_SHIFT 0 /* EQ_ENA */ +#define WM8993_EQ_ENA_WIDTH 1 /* EQ_ENA */ + +/* + * R99 (0x63) - EQ2 + */ +#define WM8993_EQ_B1_GAIN_MASK 0x001F /* EQ_B1_GAIN - [4:0] */ +#define WM8993_EQ_B1_GAIN_SHIFT 0 /* EQ_B1_GAIN - [4:0] */ +#define WM8993_EQ_B1_GAIN_WIDTH 5 /* EQ_B1_GAIN - [4:0] */ + +/* + * R100 (0x64) - EQ3 + */ +#define WM8993_EQ_B2_GAIN_MASK 0x001F /* EQ_B2_GAIN - [4:0] */ +#define WM8993_EQ_B2_GAIN_SHIFT 0 /* EQ_B2_GAIN - [4:0] */ +#define WM8993_EQ_B2_GAIN_WIDTH 5 /* EQ_B2_GAIN - [4:0] */ + +/* + * R101 (0x65) - EQ4 + */ +#define WM8993_EQ_B3_GAIN_MASK 0x001F /* EQ_B3_GAIN - [4:0] */ +#define WM8993_EQ_B3_GAIN_SHIFT 0 /* EQ_B3_GAIN - [4:0] */ +#define WM8993_EQ_B3_GAIN_WIDTH 5 /* EQ_B3_GAIN - [4:0] */ + +/* + * R102 (0x66) - EQ5 + */ +#define WM8993_EQ_B4_GAIN_MASK 0x001F /* EQ_B4_GAIN - [4:0] */ +#define WM8993_EQ_B4_GAIN_SHIFT 0 /* EQ_B4_GAIN - [4:0] */ +#define WM8993_EQ_B4_GAIN_WIDTH 5 /* EQ_B4_GAIN - [4:0] */ + +/* + * R103 (0x67) - EQ6 + */ +#define WM8993_EQ_B5_GAIN_MASK 0x001F /* EQ_B5_GAIN - [4:0] */ +#define WM8993_EQ_B5_GAIN_SHIFT 0 /* EQ_B5_GAIN - [4:0] */ +#define WM8993_EQ_B5_GAIN_WIDTH 5 /* EQ_B5_GAIN - [4:0] */ + +/* + * R104 (0x68) - EQ7 + */ +#define WM8993_EQ_B1_A_MASK 0xFFFF /* EQ_B1_A - [15:0] */ +#define WM8993_EQ_B1_A_SHIFT 0 /* EQ_B1_A - [15:0] */ +#define WM8993_EQ_B1_A_WIDTH 16 /* EQ_B1_A - [15:0] */ + +/* + * R105 (0x69) - EQ8 + */ +#define WM8993_EQ_B1_B_MASK 0xFFFF /* EQ_B1_B - [15:0] */ +#define WM8993_EQ_B1_B_SHIFT 0 /* EQ_B1_B - [15:0] */ +#define WM8993_EQ_B1_B_WIDTH 16 /* EQ_B1_B - [15:0] */ + +/* + * R106 (0x6A) - EQ9 + */ +#define WM8993_EQ_B1_PG_MASK 0xFFFF /* EQ_B1_PG - [15:0] */ +#define WM8993_EQ_B1_PG_SHIFT 0 /* EQ_B1_PG - [15:0] */ +#define WM8993_EQ_B1_PG_WIDTH 16 /* EQ_B1_PG - [15:0] */ + +/* + * R107 (0x6B) - EQ10 + */ +#define WM8993_EQ_B2_A_MASK 0xFFFF /* EQ_B2_A - [15:0] */ +#define WM8993_EQ_B2_A_SHIFT 0 /* EQ_B2_A - [15:0] */ +#define WM8993_EQ_B2_A_WIDTH 16 /* EQ_B2_A - [15:0] */ + +/* + * R108 (0x6C) - EQ11 + */ +#define WM8993_EQ_B2_B_MASK 0xFFFF /* EQ_B2_B - [15:0] */ +#define WM8993_EQ_B2_B_SHIFT 0 /* EQ_B2_B - [15:0] */ +#define WM8993_EQ_B2_B_WIDTH 16 /* EQ_B2_B - [15:0] */ + +/* + * R109 (0x6D) - EQ12 + */ +#define WM8993_EQ_B2_C_MASK 0xFFFF /* EQ_B2_C - [15:0] */ +#define WM8993_EQ_B2_C_SHIFT 0 /* EQ_B2_C - [15:0] */ +#define WM8993_EQ_B2_C_WIDTH 16 /* EQ_B2_C - [15:0] */ + +/* + * R110 (0x6E) - EQ13 + */ +#define WM8993_EQ_B2_PG_MASK 0xFFFF /* EQ_B2_PG - [15:0] */ +#define WM8993_EQ_B2_PG_SHIFT 0 /* EQ_B2_PG - [15:0] */ +#define WM8993_EQ_B2_PG_WIDTH 16 /* EQ_B2_PG - [15:0] */ + +/* + * R111 (0x6F) - EQ14 + */ +#define WM8993_EQ_B3_A_MASK 0xFFFF /* EQ_B3_A - [15:0] */ +#define WM8993_EQ_B3_A_SHIFT 0 /* EQ_B3_A - [15:0] */ +#define WM8993_EQ_B3_A_WIDTH 16 /* EQ_B3_A - [15:0] */ + +/* + * R112 (0x70) - EQ15 + */ +#define WM8993_EQ_B3_B_MASK 0xFFFF /* EQ_B3_B - [15:0] */ +#define WM8993_EQ_B3_B_SHIFT 0 /* EQ_B3_B - [15:0] */ +#define WM8993_EQ_B3_B_WIDTH 16 /* EQ_B3_B - [15:0] */ + +/* + * R113 (0x71) - EQ16 + */ +#define WM8993_EQ_B3_C_MASK 0xFFFF /* EQ_B3_C - [15:0] */ +#define WM8993_EQ_B3_C_SHIFT 0 /* EQ_B3_C - [15:0] */ +#define WM8993_EQ_B3_C_WIDTH 16 /* EQ_B3_C - [15:0] */ + +/* + * R114 (0x72) - EQ17 + */ +#define WM8993_EQ_B3_PG_MASK 0xFFFF /* EQ_B3_PG - [15:0] */ +#define WM8993_EQ_B3_PG_SHIFT 0 /* EQ_B3_PG - [15:0] */ +#define WM8993_EQ_B3_PG_WIDTH 16 /* EQ_B3_PG - [15:0] */ + +/* + * R115 (0x73) - EQ18 + */ +#define WM8993_EQ_B4_A_MASK 0xFFFF /* EQ_B4_A - [15:0] */ +#define WM8993_EQ_B4_A_SHIFT 0 /* EQ_B4_A - [15:0] */ +#define WM8993_EQ_B4_A_WIDTH 16 /* EQ_B4_A - [15:0] */ + +/* + * R116 (0x74) - EQ19 + */ +#define WM8993_EQ_B4_B_MASK 0xFFFF /* EQ_B4_B - [15:0] */ +#define WM8993_EQ_B4_B_SHIFT 0 /* EQ_B4_B - [15:0] */ +#define WM8993_EQ_B4_B_WIDTH 16 /* EQ_B4_B - [15:0] */ + +/* + * R117 (0x75) - EQ20 + */ +#define WM8993_EQ_B4_C_MASK 0xFFFF /* EQ_B4_C - [15:0] */ +#define WM8993_EQ_B4_C_SHIFT 0 /* EQ_B4_C - [15:0] */ +#define WM8993_EQ_B4_C_WIDTH 16 /* EQ_B4_C - [15:0] */ + +/* + * R118 (0x76) - EQ21 + */ +#define WM8993_EQ_B4_PG_MASK 0xFFFF /* EQ_B4_PG - [15:0] */ +#define WM8993_EQ_B4_PG_SHIFT 0 /* EQ_B4_PG - [15:0] */ +#define WM8993_EQ_B4_PG_WIDTH 16 /* EQ_B4_PG - [15:0] */ + +/* + * R119 (0x77) - EQ22 + */ +#define WM8993_EQ_B5_A_MASK 0xFFFF /* EQ_B5_A - [15:0] */ +#define WM8993_EQ_B5_A_SHIFT 0 /* EQ_B5_A - [15:0] */ +#define WM8993_EQ_B5_A_WIDTH 16 /* EQ_B5_A - [15:0] */ + +/* + * R120 (0x78) - EQ23 + */ +#define WM8993_EQ_B5_B_MASK 0xFFFF /* EQ_B5_B - [15:0] */ +#define WM8993_EQ_B5_B_SHIFT 0 /* EQ_B5_B - [15:0] */ +#define WM8993_EQ_B5_B_WIDTH 16 /* EQ_B5_B - [15:0] */ + +/* + * R121 (0x79) - EQ24 + */ +#define WM8993_EQ_B5_PG_MASK 0xFFFF /* EQ_B5_PG - [15:0] */ +#define WM8993_EQ_B5_PG_SHIFT 0 /* EQ_B5_PG - [15:0] */ +#define WM8993_EQ_B5_PG_WIDTH 16 /* EQ_B5_PG - [15:0] */ + +/* + * R122 (0x7A) - Digital Pulls + */ +#define WM8993_MCLK_PU 0x0080 /* MCLK_PU */ +#define WM8993_MCLK_PU_MASK 0x0080 /* MCLK_PU */ +#define WM8993_MCLK_PU_SHIFT 7 /* MCLK_PU */ +#define WM8993_MCLK_PU_WIDTH 1 /* MCLK_PU */ +#define WM8993_MCLK_PD 0x0040 /* MCLK_PD */ +#define WM8993_MCLK_PD_MASK 0x0040 /* MCLK_PD */ +#define WM8993_MCLK_PD_SHIFT 6 /* MCLK_PD */ +#define WM8993_MCLK_PD_WIDTH 1 /* MCLK_PD */ +#define WM8993_DACDAT_PU 0x0020 /* DACDAT_PU */ +#define WM8993_DACDAT_PU_MASK 0x0020 /* DACDAT_PU */ +#define WM8993_DACDAT_PU_SHIFT 5 /* DACDAT_PU */ +#define WM8993_DACDAT_PU_WIDTH 1 /* DACDAT_PU */ +#define WM8993_DACDAT_PD 0x0010 /* DACDAT_PD */ +#define WM8993_DACDAT_PD_MASK 0x0010 /* DACDAT_PD */ +#define WM8993_DACDAT_PD_SHIFT 4 /* DACDAT_PD */ +#define WM8993_DACDAT_PD_WIDTH 1 /* DACDAT_PD */ +#define WM8993_LRCLK_PU 0x0008 /* LRCLK_PU */ +#define WM8993_LRCLK_PU_MASK 0x0008 /* LRCLK_PU */ +#define WM8993_LRCLK_PU_SHIFT 3 /* LRCLK_PU */ +#define WM8993_LRCLK_PU_WIDTH 1 /* LRCLK_PU */ +#define WM8993_LRCLK_PD 0x0004 /* LRCLK_PD */ +#define WM8993_LRCLK_PD_MASK 0x0004 /* LRCLK_PD */ +#define WM8993_LRCLK_PD_SHIFT 2 /* LRCLK_PD */ +#define WM8993_LRCLK_PD_WIDTH 1 /* LRCLK_PD */ +#define WM8993_BCLK_PU 0x0002 /* BCLK_PU */ +#define WM8993_BCLK_PU_MASK 0x0002 /* BCLK_PU */ +#define WM8993_BCLK_PU_SHIFT 1 /* BCLK_PU */ +#define WM8993_BCLK_PU_WIDTH 1 /* BCLK_PU */ +#define WM8993_BCLK_PD 0x0001 /* BCLK_PD */ +#define WM8993_BCLK_PD_MASK 0x0001 /* BCLK_PD */ +#define WM8993_BCLK_PD_SHIFT 0 /* BCLK_PD */ +#define WM8993_BCLK_PD_WIDTH 1 /* BCLK_PD */ + +/* + * R123 (0x7B) - DRC Control 1 + */ +#define WM8993_DRC_ENA 0x8000 /* DRC_ENA */ +#define WM8993_DRC_ENA_MASK 0x8000 /* DRC_ENA */ +#define WM8993_DRC_ENA_SHIFT 15 /* DRC_ENA */ +#define WM8993_DRC_ENA_WIDTH 1 /* DRC_ENA */ +#define WM8993_DRC_DAC_PATH 0x4000 /* DRC_DAC_PATH */ +#define WM8993_DRC_DAC_PATH_MASK 0x4000 /* DRC_DAC_PATH */ +#define WM8993_DRC_DAC_PATH_SHIFT 14 /* DRC_DAC_PATH */ +#define WM8993_DRC_DAC_PATH_WIDTH 1 /* DRC_DAC_PATH */ +#define WM8993_DRC_SMOOTH_ENA 0x0800 /* DRC_SMOOTH_ENA */ +#define WM8993_DRC_SMOOTH_ENA_MASK 0x0800 /* DRC_SMOOTH_ENA */ +#define WM8993_DRC_SMOOTH_ENA_SHIFT 11 /* DRC_SMOOTH_ENA */ +#define WM8993_DRC_SMOOTH_ENA_WIDTH 1 /* DRC_SMOOTH_ENA */ +#define WM8993_DRC_QR_ENA 0x0400 /* DRC_QR_ENA */ +#define WM8993_DRC_QR_ENA_MASK 0x0400 /* DRC_QR_ENA */ +#define WM8993_DRC_QR_ENA_SHIFT 10 /* DRC_QR_ENA */ +#define WM8993_DRC_QR_ENA_WIDTH 1 /* DRC_QR_ENA */ +#define WM8993_DRC_ANTICLIP_ENA 0x0200 /* DRC_ANTICLIP_ENA */ +#define WM8993_DRC_ANTICLIP_ENA_MASK 0x0200 /* DRC_ANTICLIP_ENA */ +#define WM8993_DRC_ANTICLIP_ENA_SHIFT 9 /* DRC_ANTICLIP_ENA */ +#define WM8993_DRC_ANTICLIP_ENA_WIDTH 1 /* DRC_ANTICLIP_ENA */ +#define WM8993_DRC_HYST_ENA 0x0100 /* DRC_HYST_ENA */ +#define WM8993_DRC_HYST_ENA_MASK 0x0100 /* DRC_HYST_ENA */ +#define WM8993_DRC_HYST_ENA_SHIFT 8 /* DRC_HYST_ENA */ +#define WM8993_DRC_HYST_ENA_WIDTH 1 /* DRC_HYST_ENA */ +#define WM8993_DRC_THRESH_HYST_MASK 0x0030 /* DRC_THRESH_HYST - [5:4] */ +#define WM8993_DRC_THRESH_HYST_SHIFT 4 /* DRC_THRESH_HYST - [5:4] */ +#define WM8993_DRC_THRESH_HYST_WIDTH 2 /* DRC_THRESH_HYST - [5:4] */ +#define WM8993_DRC_MINGAIN_MASK 0x000C /* DRC_MINGAIN - [3:2] */ +#define WM8993_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [3:2] */ +#define WM8993_DRC_MINGAIN_WIDTH 2 /* DRC_MINGAIN - [3:2] */ +#define WM8993_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */ +#define WM8993_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */ +#define WM8993_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */ + +/* + * R124 (0x7C) - DRC Control 2 + */ +#define WM8993_DRC_ATTACK_RATE_MASK 0xF000 /* DRC_ATTACK_RATE - [15:12] */ +#define WM8993_DRC_ATTACK_RATE_SHIFT 12 /* DRC_ATTACK_RATE - [15:12] */ +#define WM8993_DRC_ATTACK_RATE_WIDTH 4 /* DRC_ATTACK_RATE - [15:12] */ +#define WM8993_DRC_DECAY_RATE_MASK 0x0F00 /* DRC_DECAY_RATE - [11:8] */ +#define WM8993_DRC_DECAY_RATE_SHIFT 8 /* DRC_DECAY_RATE - [11:8] */ +#define WM8993_DRC_DECAY_RATE_WIDTH 4 /* DRC_DECAY_RATE - [11:8] */ +#define WM8993_DRC_THRESH_COMP_MASK 0x00FC /* DRC_THRESH_COMP - [7:2] */ +#define WM8993_DRC_THRESH_COMP_SHIFT 2 /* DRC_THRESH_COMP - [7:2] */ +#define WM8993_DRC_THRESH_COMP_WIDTH 6 /* DRC_THRESH_COMP - [7:2] */ + +/* + * R125 (0x7D) - DRC Control 3 + */ +#define WM8993_DRC_AMP_COMP_MASK 0xF800 /* DRC_AMP_COMP - [15:11] */ +#define WM8993_DRC_AMP_COMP_SHIFT 11 /* DRC_AMP_COMP - [15:11] */ +#define WM8993_DRC_AMP_COMP_WIDTH 5 /* DRC_AMP_COMP - [15:11] */ +#define WM8993_DRC_R0_SLOPE_COMP_MASK 0x0700 /* DRC_R0_SLOPE_COMP - [10:8] */ +#define WM8993_DRC_R0_SLOPE_COMP_SHIFT 8 /* DRC_R0_SLOPE_COMP - [10:8] */ +#define WM8993_DRC_R0_SLOPE_COMP_WIDTH 3 /* DRC_R0_SLOPE_COMP - [10:8] */ +#define WM8993_DRC_FF_DELAY 0x0080 /* DRC_FF_DELAY */ +#define WM8993_DRC_FF_DELAY_MASK 0x0080 /* DRC_FF_DELAY */ +#define WM8993_DRC_FF_DELAY_SHIFT 7 /* DRC_FF_DELAY */ +#define WM8993_DRC_FF_DELAY_WIDTH 1 /* DRC_FF_DELAY */ +#define WM8993_DRC_THRESH_QR_MASK 0x000C /* DRC_THRESH_QR - [3:2] */ +#define WM8993_DRC_THRESH_QR_SHIFT 2 /* DRC_THRESH_QR - [3:2] */ +#define WM8993_DRC_THRESH_QR_WIDTH 2 /* DRC_THRESH_QR - [3:2] */ +#define WM8993_DRC_RATE_QR_MASK 0x0003 /* DRC_RATE_QR - [1:0] */ +#define WM8993_DRC_RATE_QR_SHIFT 0 /* DRC_RATE_QR - [1:0] */ +#define WM8993_DRC_RATE_QR_WIDTH 2 /* DRC_RATE_QR - [1:0] */ + +/* + * R126 (0x7E) - DRC Control 4 + */ +#define WM8993_DRC_R1_SLOPE_COMP_MASK 0xE000 /* DRC_R1_SLOPE_COMP - [15:13] */ +#define WM8993_DRC_R1_SLOPE_COMP_SHIFT 13 /* DRC_R1_SLOPE_COMP - [15:13] */ +#define WM8993_DRC_R1_SLOPE_COMP_WIDTH 3 /* DRC_R1_SLOPE_COMP - [15:13] */ +#define WM8993_DRC_STARTUP_GAIN_MASK 0x1F00 /* DRC_STARTUP_GAIN - [12:8] */ +#define WM8993_DRC_STARTUP_GAIN_SHIFT 8 /* DRC_STARTUP_GAIN - [12:8] */ +#define WM8993_DRC_STARTUP_GAIN_WIDTH 5 /* DRC_STARTUP_GAIN - [12:8] */ + +#endif -- cgit v0.10.2 From 4934482d93ca42d57180e08bf3ee6b77124f5f8e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 8 Jul 2009 17:48:12 +0100 Subject: ASoC: Limit WM8731 to symmetric rates While the hardware is capable of some limited asynmmetric modes the driver does not currently support those modes so tell applications that only symmetric rates are available. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index de43263..1560028 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -464,6 +464,7 @@ struct snd_soc_dai wm8731_dai = { .rates = WM8731_RATES, .formats = WM8731_FORMATS,}, .ops = &wm8731_dai_ops, + .symmetric_rates = 1, }; EXPORT_SYMBOL_GPL(wm8731_dai); -- cgit v0.10.2 From 2a01e5f3587be459c934d711bffddc14d66386f3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 8 Jul 2009 18:05:51 +0100 Subject: ASoC: Use CODEC as clock master on AT91SAM9G20-EK This simplifies the driver by removing the need to manually configure dividers within the CPU and improve audio performance by ensuring that the optimal phase relationships between the clocks in the system are maintained. Note that currently this means that for playback to work the Output Mixer HiFi switch must be enabled since otherwise CODEC will not generate the DAC clock. Signed-off-by: Mark Brown diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 173a239..9abab94 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -87,102 +87,17 @@ static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct atmel_ssc_info *ssc_p = cpu_dai->private_data; - struct ssc_device *ssc = ssc_p->ssc; int ret; - unsigned int rate; - int cmr_div, period; - - if (ssc == NULL) { - printk(KERN_INFO "at91sam9g20ek_hw_params: ssc is NULL!\n"); - return -EINVAL; - } - /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* - * The SSC clock dividers depend on the sample rate. The CMR.DIV - * field divides the system master clock MCK to drive the SSC TK - * signal which provides the codec BCLK. The TCMR.PERIOD and - * RCMR.PERIOD fields further divide the BCLK signal to drive - * the SSC TF and RF signals which provide the codec DACLRC and - * ADCLRC clocks. - * - * The dividers were determined through trial and error, where a - * CMR.DIV value is chosen such that the resulting BCLK value is - * divisible, or almost divisible, by (2 * sample rate), and then - * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1. - */ - rate = params_rate(params); - - switch (rate) { - case 8000: - cmr_div = 55; /* BCLK = 133MHz/(2*55) = 1.209MHz */ - period = 74; /* LRC = BCLK/(2*(74+1)) ~= 8060,6Hz */ - break; - case 11025: - cmr_div = 67; /* BCLK = 133MHz/(2*60) = 1.108MHz */ - period = 45; /* LRC = BCLK/(2*(49+1)) = 11083,3Hz */ - break; - case 16000: - cmr_div = 63; /* BCLK = 133MHz/(2*63) = 1.055MHz */ - period = 32; /* LRC = BCLK/(2*(32+1)) = 15993,2Hz */ - break; - case 22050: - cmr_div = 52; /* BCLK = 133MHz/(2*52) = 1.278MHz */ - period = 28; /* LRC = BCLK/(2*(28+1)) = 22049Hz */ - break; - case 32000: - cmr_div = 66; /* BCLK = 133MHz/(2*66) = 1.007MHz */ - period = 15; /* LRC = BCLK/(2*(15+1)) = 31486,742Hz */ - break; - case 44100: - cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */ - period = 25; /* LRC = BCLK/(2*(25+1)) = 44098Hz */ - break; - case 48000: - cmr_div = 33; /* BCLK = 133MHz/(2*33) = 2.015MHz */ - period = 20; /* LRC = BCLK/(2*(20+1)) = 47979,79Hz */ - break; - case 88200: - cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */ - period = 12; /* LRC = BCLK/(2*(12+1)) = 88196Hz */ - break; - case 96000: - cmr_div = 23; /* BCLK = 133MHz/(2*23) = 2.891MHz */ - period = 14; /* LRC = BCLK/(2*(14+1)) = 96376Hz */ - break; - default: - printk(KERN_WARNING "unsupported rate %d" - " on at91sam9g20ek board\n", rate); - return -EINVAL; - } - - /* set the MCK divider for BCLK */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cmr_div); - if (ret < 0) - return ret; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* set the BCLK divider for DACLRC */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, - ATMEL_SSC_TCMR_PERIOD, period); - } else { - /* set the BCLK divider for ADCLRC */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, - ATMEL_SSC_RCMR_PERIOD, period); - } + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; -- cgit v0.10.2 From 22df8eb4fe293d67c98732e02a2dbef0d9c6cd96 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 8 Jul 2009 18:18:19 +0100 Subject: ASoC: Disable microphone input for AT91SAM9G20-EK by default As shipped the board does not have inputs but it is relatively straightforward to modify the board to hook them up so support is provided in the driver. When these modifications have not been made enabling the microphone stage can cause problems. Add an ifdef to disable this by default. Don't put it into Kconfig since users will have to get their soldering irons out to change things. Signed-off-by: Mark Brown diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 9abab94..ba93df7 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -56,6 +56,13 @@ #define MCLK_RATE 12000000 +/* + * As shipped the board does not have inputs. However, it is relatively + * straightforward to modify the board to hook them up so support is left + * in the driver. + */ +#undef ENABLE_MIC_INPUT + static struct clk *mclk; static int at91sam9g20ek_startup(struct snd_pcm_substream *substream) @@ -170,8 +177,13 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec) snd_soc_dapm_nc_pin(codec, "RLINEIN"); snd_soc_dapm_nc_pin(codec, "LLINEIN"); - /* always connected */ +#ifdef ENABLE_MIC_INPUT snd_soc_dapm_enable_pin(codec, "Int Mic"); +#else + snd_soc_dapm_nc_pin(codec, "Int Mic"); +#endif + + /* always connected */ snd_soc_dapm_enable_pin(codec, "Ext Spk"); snd_soc_dapm_sync(codec); -- cgit v0.10.2 From 96fd6d471b2c953df5379a356be04f8c8f8b4bdf Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 8 Jul 2009 18:26:16 +0100 Subject: ASoC: Configure WM8731 SYSCLK at startup on AT91SAM9G20-EK The system clock is currently fixed by the driver and this avoids the need for us to handle errors with enabling and disabling MCLK (which was incorrect previously so this fixes bugs in error handling). Signed-off-by: Mark Brown diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index ba93df7..130b121 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -65,29 +65,6 @@ static struct clk *mclk; -static int at91sam9g20ek_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, - MCLK_RATE, SND_SOC_CLOCK_IN); - if (ret < 0) { - clk_disable(mclk); - return ret; - } - - return 0; -} - -static void at91sam9g20ek_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - - dev_dbg(rtd->socdev->dev, "shutdown"); -} - static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -112,9 +89,7 @@ static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream, } static struct snd_soc_ops at91sam9g20ek_ops = { - .startup = at91sam9g20ek_startup, .hw_params = at91sam9g20ek_hw_params, - .shutdown = at91sam9g20ek_shutdown, }; static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card, @@ -163,10 +138,20 @@ static const struct snd_soc_dapm_route intercon[] = { */ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec) { + struct snd_soc_dai *codec_dai = &codec->dai[0]; + int ret; + printk(KERN_DEBUG "at91sam9g20ek_wm8731 " ": at91sam9g20ek_wm8731_init() called\n"); + ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, + MCLK_RATE, SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret); + return ret; + } + /* Add specific widgets */ snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets, ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); -- cgit v0.10.2 From 2c3d50f7db6c4aa85b099613aba8660da6de75d4 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:48 +0000 Subject: cxgb3: AQ100X phy support update Add missing SUPPORTED_TP flag. Update FW version checking. Do the full initialization even if the FW version is unknown, it might help catching further issues. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c index b1fd5bf..341b7ef 100644 --- a/drivers/net/cxgb3/aq100x.c +++ b/drivers/net/cxgb3/aq100x.c @@ -271,7 +271,8 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops, SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_AUI, "1000/10GBASE-T"); + SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI, + "1000/10GBASE-T"); /* * The PHY has been out of reset ever since the system powered up. So @@ -316,11 +317,9 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, /* Firmware version check. */ t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v); - if (v != 30) { + if (v != 101) CH_WARN(adapter, "PHY%d: unsupported firmware %d\n", phy_addr, v); - return 0; /* allow t3_prep_adapter to succeed */ - } /* * The PHY should start in really-low-power mode. Prepare it for normal -- cgit v0.10.2 From 619f05cf690149bef1f15cd0cec6a31b40d96951 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:53 +0000 Subject: cxgb3: fix phy power down 2 phys are were not getting the Global Tx disable bit set when powered down, leading to an inconsistent link state on peer. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index 9fe008e..949d248 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -224,12 +224,6 @@ static int ael1006_reset(struct cphy *phy, int wait) return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait); } -static int ael1006_power_down(struct cphy *phy, int enable) -{ - return mdio_set_flag(&phy->mdio, phy->mdio.prtad, MDIO_MMD_PMAPMD, - MDIO_CTRL1, MDIO_CTRL1_LPOWER, enable); -} - static struct cphy_ops ael1006_ops = { .reset = ael1006_reset, .intr_enable = t3_phy_lasi_intr_enable, @@ -237,7 +231,7 @@ static struct cphy_ops ael1006_ops = { .intr_clear = t3_phy_lasi_intr_clear, .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_r, - .power_down = ael1006_power_down, + .power_down = ael1002_power_down, .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; @@ -1840,7 +1834,7 @@ static struct cphy_ops qt2045_ops = { .intr_clear = t3_phy_lasi_intr_clear, .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_x, - .power_down = ael1006_power_down, + .power_down = ael1002_power_down, .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; -- cgit v0.10.2 From cfe2462c6af309ee70e4aeefa55cae976071b9e2 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:38 +0000 Subject: cxgb3: Fix T3C MAC max packet size access Max packet size is not the only field in T3C's High Water Mark register. Mask the register to access this field. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index f87f943..0109ee4 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -447,11 +447,12 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); - if (fc & PAUSE_TX) - val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm( - t3_read_reg(adap, - A_XGM_RX_MAX_PKT_SIZE - + oft)) / 8); + if (fc & PAUSE_TX) { + u32 rx_max_pkt_size = + G_RXMAXPKTSIZE(t3_read_reg(adap, + A_XGM_RX_MAX_PKT_SIZE + oft)); + val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); + } t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, -- cgit v0.10.2 From 5e659515569220701bfe3c8936dcab67554cc286 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:43 +0000 Subject: cxgb3: AEL2020 phy support update We don't always see the link status update interrupt when we come out of reset and the peer is up. Check and report the link status right before enabling interrupts. Also fix LED settings, to get a consistent link status. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 1694fad..bfa312d 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -276,6 +276,14 @@ static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) return netdev_priv(adap->port[idx]); } +static inline int phy2portid(struct cphy *phy) +{ + struct adapter *adap = phy->adapter; + struct port_info *port0 = adap2pinfo(adap, 0); + + return &port0->phy == phy ? 0 : 1; +} + #define OFFLOAD_DEVMAP_BIT 15 #define tdev2adap(d) container_of(d, struct adapter, tdev) diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index 949d248..66e47f7 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -1643,9 +1643,39 @@ static int ael2020_get_module_type(struct cphy *phy, int delay_ms) */ static int ael2020_intr_enable(struct cphy *phy) { - int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0x2 << (AEL2020_GPIO_MODDET*4)); - return err ? err : t3_phy_lasi_intr_enable(phy); + struct reg_val regs[] = { + /* output Module's Loss Of Signal (LOS) to LED */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, + 0xffff, 0x4 }, + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, + + /* enable module detect status change interrupts */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err, link_ok = 0; + + /* set up "link status" LED and enable module change interrupts */ + err = set_phy_regs(phy, regs); + if (err) + return err; + + err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL); + if (err) + return err; + if (link_ok) + t3_link_changed(phy->adapter, + phy2portid(phy)); + + err = t3_phy_lasi_intr_enable(phy); + if (err) + return err; + + return 0; } /* @@ -1653,9 +1683,26 @@ static int ael2020_intr_enable(struct cphy *phy) */ static int ael2020_intr_disable(struct cphy *phy) { - int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0x1 << (AEL2020_GPIO_MODDET*4)); - return err ? err : t3_phy_lasi_intr_disable(phy); + struct reg_val regs[] = { + /* reset "link status" LED to "off" */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) }, + + /* disable module detect status change interrupts */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + + /* turn off "link status" LED and disable module change interrupts */ + err = set_phy_regs(phy, regs); + if (err) + return err; + + return t3_phy_lasi_intr_disable(phy); } /* @@ -1673,31 +1720,26 @@ static int ael2020_intr_clear(struct cphy *phy) return err ? err : t3_phy_lasi_intr_clear(phy); } +static struct reg_val ael2020_reset_regs[] = { + /* Erratum #2: CDRLOL asserted, causing PMA link down status */ + { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 }, + + /* force XAUI to send LF when RX_LOS is asserted */ + { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 }, + + /* allow writes to transceiver module EEPROM on i2c bus */ + { MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 }, + { MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 }, + { MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 }, + + /* end */ + { 0, 0, 0, 0 } +}; /* * Reset the PHY and put it into a canonical operating state. */ static int ael2020_reset(struct cphy *phy, int wait) { - static struct reg_val regs0[] = { - /* Erratum #2: CDRLOL asserted, causing PMA link down status */ - { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 }, - - /* force XAUI to send LF when RX_LOS is asserted */ - { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 }, - - /* RX_LOS pin is active high */ - { MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, - 0x0020, 0x0020 }, - - /* output Module's Loss Of Signal (LOS) to LED */ - { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, - 0xffff, 0x0004 }, - { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, - - /* end */ - { 0, 0, 0, 0 } - }; int err; unsigned int lasi_ctrl; @@ -1714,7 +1756,7 @@ static int ael2020_reset(struct cphy *phy, int wait) /* basic initialization for all module types */ phy->priv = edc_none; - err = set_phy_regs(phy, regs0); + err = set_phy_regs(phy, ael2020_reset_regs); if (err) return err; @@ -1792,10 +1834,16 @@ static struct cphy_ops ael2020_ops = { int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops) { + int err; + cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | SUPPORTED_IRQ, "10GBASE-R"); msleep(125); + + err = set_phy_regs(phy, ael2020_reset_regs); + if (err) + return err; return 0; } -- cgit v0.10.2 From 2e8c07c35b3ffee7689406be61fd1448ee45d3cd Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:49:09 +0000 Subject: cxgb3: use request_firmware() for the EDC registers setup use request_firmware() to load the phy's EDC programmation Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index bfa312d..74723f2 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -320,4 +320,6 @@ int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, unsigned char *data); irqreturn_t t3_sge_intr_msix(int irq, void *cookie); +int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size); + #endif /* __T3_ADAPTER_H__ */ diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index 66e47f7..5248f9e 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -298,279 +298,7 @@ static int ael2005_setup_sr_edc(struct cphy *phy) { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 }, { 0, 0, 0, 0 } }; - static u16 sr_edc[] = { - 0xcc00, 0x2ff4, - 0xcc01, 0x3cd4, - 0xcc02, 0x2015, - 0xcc03, 0x3105, - 0xcc04, 0x6524, - 0xcc05, 0x27ff, - 0xcc06, 0x300f, - 0xcc07, 0x2c8b, - 0xcc08, 0x300b, - 0xcc09, 0x4009, - 0xcc0a, 0x400e, - 0xcc0b, 0x2f72, - 0xcc0c, 0x3002, - 0xcc0d, 0x1002, - 0xcc0e, 0x2172, - 0xcc0f, 0x3012, - 0xcc10, 0x1002, - 0xcc11, 0x25d2, - 0xcc12, 0x3012, - 0xcc13, 0x1002, - 0xcc14, 0xd01e, - 0xcc15, 0x27d2, - 0xcc16, 0x3012, - 0xcc17, 0x1002, - 0xcc18, 0x2004, - 0xcc19, 0x3c84, - 0xcc1a, 0x6436, - 0xcc1b, 0x2007, - 0xcc1c, 0x3f87, - 0xcc1d, 0x8676, - 0xcc1e, 0x40b7, - 0xcc1f, 0xa746, - 0xcc20, 0x4047, - 0xcc21, 0x5673, - 0xcc22, 0x2982, - 0xcc23, 0x3002, - 0xcc24, 0x13d2, - 0xcc25, 0x8bbd, - 0xcc26, 0x2862, - 0xcc27, 0x3012, - 0xcc28, 0x1002, - 0xcc29, 0x2092, - 0xcc2a, 0x3012, - 0xcc2b, 0x1002, - 0xcc2c, 0x5cc3, - 0xcc2d, 0x314, - 0xcc2e, 0x2942, - 0xcc2f, 0x3002, - 0xcc30, 0x1002, - 0xcc31, 0xd019, - 0xcc32, 0x2032, - 0xcc33, 0x3012, - 0xcc34, 0x1002, - 0xcc35, 0x2a04, - 0xcc36, 0x3c74, - 0xcc37, 0x6435, - 0xcc38, 0x2fa4, - 0xcc39, 0x3cd4, - 0xcc3a, 0x6624, - 0xcc3b, 0x5563, - 0xcc3c, 0x2d42, - 0xcc3d, 0x3002, - 0xcc3e, 0x13d2, - 0xcc3f, 0x464d, - 0xcc40, 0x2862, - 0xcc41, 0x3012, - 0xcc42, 0x1002, - 0xcc43, 0x2032, - 0xcc44, 0x3012, - 0xcc45, 0x1002, - 0xcc46, 0x2fb4, - 0xcc47, 0x3cd4, - 0xcc48, 0x6624, - 0xcc49, 0x5563, - 0xcc4a, 0x2d42, - 0xcc4b, 0x3002, - 0xcc4c, 0x13d2, - 0xcc4d, 0x2ed2, - 0xcc4e, 0x3002, - 0xcc4f, 0x1002, - 0xcc50, 0x2fd2, - 0xcc51, 0x3002, - 0xcc52, 0x1002, - 0xcc53, 0x004, - 0xcc54, 0x2942, - 0xcc55, 0x3002, - 0xcc56, 0x1002, - 0xcc57, 0x2092, - 0xcc58, 0x3012, - 0xcc59, 0x1002, - 0xcc5a, 0x5cc3, - 0xcc5b, 0x317, - 0xcc5c, 0x2f72, - 0xcc5d, 0x3002, - 0xcc5e, 0x1002, - 0xcc5f, 0x2942, - 0xcc60, 0x3002, - 0xcc61, 0x1002, - 0xcc62, 0x22cd, - 0xcc63, 0x301d, - 0xcc64, 0x2862, - 0xcc65, 0x3012, - 0xcc66, 0x1002, - 0xcc67, 0x2ed2, - 0xcc68, 0x3002, - 0xcc69, 0x1002, - 0xcc6a, 0x2d72, - 0xcc6b, 0x3002, - 0xcc6c, 0x1002, - 0xcc6d, 0x628f, - 0xcc6e, 0x2112, - 0xcc6f, 0x3012, - 0xcc70, 0x1002, - 0xcc71, 0x5aa3, - 0xcc72, 0x2dc2, - 0xcc73, 0x3002, - 0xcc74, 0x1312, - 0xcc75, 0x6f72, - 0xcc76, 0x1002, - 0xcc77, 0x2807, - 0xcc78, 0x31a7, - 0xcc79, 0x20c4, - 0xcc7a, 0x3c24, - 0xcc7b, 0x6724, - 0xcc7c, 0x1002, - 0xcc7d, 0x2807, - 0xcc7e, 0x3187, - 0xcc7f, 0x20c4, - 0xcc80, 0x3c24, - 0xcc81, 0x6724, - 0xcc82, 0x1002, - 0xcc83, 0x2514, - 0xcc84, 0x3c64, - 0xcc85, 0x6436, - 0xcc86, 0xdff4, - 0xcc87, 0x6436, - 0xcc88, 0x1002, - 0xcc89, 0x40a4, - 0xcc8a, 0x643c, - 0xcc8b, 0x4016, - 0xcc8c, 0x8c6c, - 0xcc8d, 0x2b24, - 0xcc8e, 0x3c24, - 0xcc8f, 0x6435, - 0xcc90, 0x1002, - 0xcc91, 0x2b24, - 0xcc92, 0x3c24, - 0xcc93, 0x643a, - 0xcc94, 0x4025, - 0xcc95, 0x8a5a, - 0xcc96, 0x1002, - 0xcc97, 0x2731, - 0xcc98, 0x3011, - 0xcc99, 0x1001, - 0xcc9a, 0xc7a0, - 0xcc9b, 0x100, - 0xcc9c, 0xc502, - 0xcc9d, 0x53ac, - 0xcc9e, 0xc503, - 0xcc9f, 0xd5d5, - 0xcca0, 0xc600, - 0xcca1, 0x2a6d, - 0xcca2, 0xc601, - 0xcca3, 0x2a4c, - 0xcca4, 0xc602, - 0xcca5, 0x111, - 0xcca6, 0xc60c, - 0xcca7, 0x5900, - 0xcca8, 0xc710, - 0xcca9, 0x700, - 0xccaa, 0xc718, - 0xccab, 0x700, - 0xccac, 0xc720, - 0xccad, 0x4700, - 0xccae, 0xc801, - 0xccaf, 0x7f50, - 0xccb0, 0xc802, - 0xccb1, 0x7760, - 0xccb2, 0xc803, - 0xccb3, 0x7fce, - 0xccb4, 0xc804, - 0xccb5, 0x5700, - 0xccb6, 0xc805, - 0xccb7, 0x5f11, - 0xccb8, 0xc806, - 0xccb9, 0x4751, - 0xccba, 0xc807, - 0xccbb, 0x57e1, - 0xccbc, 0xc808, - 0xccbd, 0x2700, - 0xccbe, 0xc809, - 0xccbf, 0x000, - 0xccc0, 0xc821, - 0xccc1, 0x002, - 0xccc2, 0xc822, - 0xccc3, 0x014, - 0xccc4, 0xc832, - 0xccc5, 0x1186, - 0xccc6, 0xc847, - 0xccc7, 0x1e02, - 0xccc8, 0xc013, - 0xccc9, 0xf341, - 0xccca, 0xc01a, - 0xcccb, 0x446, - 0xcccc, 0xc024, - 0xcccd, 0x1000, - 0xccce, 0xc025, - 0xcccf, 0xa00, - 0xccd0, 0xc026, - 0xccd1, 0xc0c, - 0xccd2, 0xc027, - 0xccd3, 0xc0c, - 0xccd4, 0xc029, - 0xccd5, 0x0a0, - 0xccd6, 0xc030, - 0xccd7, 0xa00, - 0xccd8, 0xc03c, - 0xccd9, 0x01c, - 0xccda, 0xc005, - 0xccdb, 0x7a06, - 0xccdc, 0x000, - 0xccdd, 0x2731, - 0xccde, 0x3011, - 0xccdf, 0x1001, - 0xcce0, 0xc620, - 0xcce1, 0x000, - 0xcce2, 0xc621, - 0xcce3, 0x03f, - 0xcce4, 0xc622, - 0xcce5, 0x000, - 0xcce6, 0xc623, - 0xcce7, 0x000, - 0xcce8, 0xc624, - 0xcce9, 0x000, - 0xccea, 0xc625, - 0xcceb, 0x000, - 0xccec, 0xc627, - 0xcced, 0x000, - 0xccee, 0xc628, - 0xccef, 0x000, - 0xccf0, 0xc62c, - 0xccf1, 0x000, - 0xccf2, 0x000, - 0xccf3, 0x2806, - 0xccf4, 0x3cb6, - 0xccf5, 0xc161, - 0xccf6, 0x6134, - 0xccf7, 0x6135, - 0xccf8, 0x5443, - 0xccf9, 0x303, - 0xccfa, 0x6524, - 0xccfb, 0x00b, - 0xccfc, 0x1002, - 0xccfd, 0x2104, - 0xccfe, 0x3c24, - 0xccff, 0x2105, - 0xcd00, 0x3805, - 0xcd01, 0x6524, - 0xcd02, 0xdff4, - 0xcd03, 0x4005, - 0xcd04, 0x6524, - 0xcd05, 0x1002, - 0xcd06, 0x5dd3, - 0xcd07, 0x306, - 0xcd08, 0x2ff7, - 0xcd09, 0x38f7, - 0xcd0a, 0x60b7, - 0xcd0b, 0xdffd, - 0xcd0c, 0x00a, - 0xcd0d, 0x1002, - 0xcd0e, 0 - }; + int i, err; err = set_phy_regs(phy, regs); @@ -579,9 +307,16 @@ static int ael2005_setup_sr_edc(struct cphy *phy) msleep(50); - for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, sr_edc[i], - sr_edc[i + 1]); + if (phy->priv != edc_sr) + err = t3_get_edc_fw(phy, EDC_OPT_AEL2005, + EDC_OPT_AEL2005_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); if (!err) phy->priv = edc_sr; return err; @@ -598,374 +333,6 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) { MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 }, { 0, 0, 0, 0 } }; - static u16 twinax_edc[] = { - 0xcc00, 0x4009, - 0xcc01, 0x27ff, - 0xcc02, 0x300f, - 0xcc03, 0x40aa, - 0xcc04, 0x401c, - 0xcc05, 0x401e, - 0xcc06, 0x2ff4, - 0xcc07, 0x3cd4, - 0xcc08, 0x2035, - 0xcc09, 0x3145, - 0xcc0a, 0x6524, - 0xcc0b, 0x26a2, - 0xcc0c, 0x3012, - 0xcc0d, 0x1002, - 0xcc0e, 0x29c2, - 0xcc0f, 0x3002, - 0xcc10, 0x1002, - 0xcc11, 0x2072, - 0xcc12, 0x3012, - 0xcc13, 0x1002, - 0xcc14, 0x22cd, - 0xcc15, 0x301d, - 0xcc16, 0x2e52, - 0xcc17, 0x3012, - 0xcc18, 0x1002, - 0xcc19, 0x28e2, - 0xcc1a, 0x3002, - 0xcc1b, 0x1002, - 0xcc1c, 0x628f, - 0xcc1d, 0x2ac2, - 0xcc1e, 0x3012, - 0xcc1f, 0x1002, - 0xcc20, 0x5553, - 0xcc21, 0x2ae2, - 0xcc22, 0x3002, - 0xcc23, 0x1302, - 0xcc24, 0x401e, - 0xcc25, 0x2be2, - 0xcc26, 0x3012, - 0xcc27, 0x1002, - 0xcc28, 0x2da2, - 0xcc29, 0x3012, - 0xcc2a, 0x1002, - 0xcc2b, 0x2ba2, - 0xcc2c, 0x3002, - 0xcc2d, 0x1002, - 0xcc2e, 0x5ee3, - 0xcc2f, 0x305, - 0xcc30, 0x400e, - 0xcc31, 0x2bc2, - 0xcc32, 0x3002, - 0xcc33, 0x1002, - 0xcc34, 0x2b82, - 0xcc35, 0x3012, - 0xcc36, 0x1002, - 0xcc37, 0x5663, - 0xcc38, 0x302, - 0xcc39, 0x401e, - 0xcc3a, 0x6f72, - 0xcc3b, 0x1002, - 0xcc3c, 0x628f, - 0xcc3d, 0x2be2, - 0xcc3e, 0x3012, - 0xcc3f, 0x1002, - 0xcc40, 0x22cd, - 0xcc41, 0x301d, - 0xcc42, 0x2e52, - 0xcc43, 0x3012, - 0xcc44, 0x1002, - 0xcc45, 0x2522, - 0xcc46, 0x3012, - 0xcc47, 0x1002, - 0xcc48, 0x2da2, - 0xcc49, 0x3012, - 0xcc4a, 0x1002, - 0xcc4b, 0x2ca2, - 0xcc4c, 0x3012, - 0xcc4d, 0x1002, - 0xcc4e, 0x2fa4, - 0xcc4f, 0x3cd4, - 0xcc50, 0x6624, - 0xcc51, 0x410b, - 0xcc52, 0x56b3, - 0xcc53, 0x3c4, - 0xcc54, 0x2fb2, - 0xcc55, 0x3002, - 0xcc56, 0x1002, - 0xcc57, 0x220b, - 0xcc58, 0x303b, - 0xcc59, 0x56b3, - 0xcc5a, 0x3c3, - 0xcc5b, 0x866b, - 0xcc5c, 0x400c, - 0xcc5d, 0x23a2, - 0xcc5e, 0x3012, - 0xcc5f, 0x1002, - 0xcc60, 0x2da2, - 0xcc61, 0x3012, - 0xcc62, 0x1002, - 0xcc63, 0x2ca2, - 0xcc64, 0x3012, - 0xcc65, 0x1002, - 0xcc66, 0x2fb4, - 0xcc67, 0x3cd4, - 0xcc68, 0x6624, - 0xcc69, 0x56b3, - 0xcc6a, 0x3c3, - 0xcc6b, 0x866b, - 0xcc6c, 0x401c, - 0xcc6d, 0x2205, - 0xcc6e, 0x3035, - 0xcc6f, 0x5b53, - 0xcc70, 0x2c52, - 0xcc71, 0x3002, - 0xcc72, 0x13c2, - 0xcc73, 0x5cc3, - 0xcc74, 0x317, - 0xcc75, 0x2522, - 0xcc76, 0x3012, - 0xcc77, 0x1002, - 0xcc78, 0x2da2, - 0xcc79, 0x3012, - 0xcc7a, 0x1002, - 0xcc7b, 0x2b82, - 0xcc7c, 0x3012, - 0xcc7d, 0x1002, - 0xcc7e, 0x5663, - 0xcc7f, 0x303, - 0xcc80, 0x401e, - 0xcc81, 0x004, - 0xcc82, 0x2c42, - 0xcc83, 0x3012, - 0xcc84, 0x1002, - 0xcc85, 0x6f72, - 0xcc86, 0x1002, - 0xcc87, 0x628f, - 0xcc88, 0x2304, - 0xcc89, 0x3c84, - 0xcc8a, 0x6436, - 0xcc8b, 0xdff4, - 0xcc8c, 0x6436, - 0xcc8d, 0x2ff5, - 0xcc8e, 0x3005, - 0xcc8f, 0x8656, - 0xcc90, 0xdfba, - 0xcc91, 0x56a3, - 0xcc92, 0xd05a, - 0xcc93, 0x21c2, - 0xcc94, 0x3012, - 0xcc95, 0x1392, - 0xcc96, 0xd05a, - 0xcc97, 0x56a3, - 0xcc98, 0xdfba, - 0xcc99, 0x383, - 0xcc9a, 0x6f72, - 0xcc9b, 0x1002, - 0xcc9c, 0x28c5, - 0xcc9d, 0x3005, - 0xcc9e, 0x4178, - 0xcc9f, 0x5653, - 0xcca0, 0x384, - 0xcca1, 0x22b2, - 0xcca2, 0x3012, - 0xcca3, 0x1002, - 0xcca4, 0x2be5, - 0xcca5, 0x3005, - 0xcca6, 0x41e8, - 0xcca7, 0x5653, - 0xcca8, 0x382, - 0xcca9, 0x002, - 0xccaa, 0x4258, - 0xccab, 0x2474, - 0xccac, 0x3c84, - 0xccad, 0x6437, - 0xccae, 0xdff4, - 0xccaf, 0x6437, - 0xccb0, 0x2ff5, - 0xccb1, 0x3c05, - 0xccb2, 0x8757, - 0xccb3, 0xb888, - 0xccb4, 0x9787, - 0xccb5, 0xdff4, - 0xccb6, 0x6724, - 0xccb7, 0x866a, - 0xccb8, 0x6f72, - 0xccb9, 0x1002, - 0xccba, 0x2d01, - 0xccbb, 0x3011, - 0xccbc, 0x1001, - 0xccbd, 0xc620, - 0xccbe, 0x14e5, - 0xccbf, 0xc621, - 0xccc0, 0xc53d, - 0xccc1, 0xc622, - 0xccc2, 0x3cbe, - 0xccc3, 0xc623, - 0xccc4, 0x4452, - 0xccc5, 0xc624, - 0xccc6, 0xc5c5, - 0xccc7, 0xc625, - 0xccc8, 0xe01e, - 0xccc9, 0xc627, - 0xccca, 0x000, - 0xcccb, 0xc628, - 0xcccc, 0x000, - 0xcccd, 0xc62b, - 0xccce, 0x000, - 0xcccf, 0xc62c, - 0xccd0, 0x000, - 0xccd1, 0x000, - 0xccd2, 0x2d01, - 0xccd3, 0x3011, - 0xccd4, 0x1001, - 0xccd5, 0xc620, - 0xccd6, 0x000, - 0xccd7, 0xc621, - 0xccd8, 0x000, - 0xccd9, 0xc622, - 0xccda, 0x0ce, - 0xccdb, 0xc623, - 0xccdc, 0x07f, - 0xccdd, 0xc624, - 0xccde, 0x032, - 0xccdf, 0xc625, - 0xcce0, 0x000, - 0xcce1, 0xc627, - 0xcce2, 0x000, - 0xcce3, 0xc628, - 0xcce4, 0x000, - 0xcce5, 0xc62b, - 0xcce6, 0x000, - 0xcce7, 0xc62c, - 0xcce8, 0x000, - 0xcce9, 0x000, - 0xccea, 0x2d01, - 0xcceb, 0x3011, - 0xccec, 0x1001, - 0xcced, 0xc502, - 0xccee, 0x609f, - 0xccef, 0xc600, - 0xccf0, 0x2a6e, - 0xccf1, 0xc601, - 0xccf2, 0x2a2c, - 0xccf3, 0xc60c, - 0xccf4, 0x5400, - 0xccf5, 0xc710, - 0xccf6, 0x700, - 0xccf7, 0xc718, - 0xccf8, 0x700, - 0xccf9, 0xc720, - 0xccfa, 0x4700, - 0xccfb, 0xc728, - 0xccfc, 0x700, - 0xccfd, 0xc729, - 0xccfe, 0x1207, - 0xccff, 0xc801, - 0xcd00, 0x7f50, - 0xcd01, 0xc802, - 0xcd02, 0x7760, - 0xcd03, 0xc803, - 0xcd04, 0x7fce, - 0xcd05, 0xc804, - 0xcd06, 0x520e, - 0xcd07, 0xc805, - 0xcd08, 0x5c11, - 0xcd09, 0xc806, - 0xcd0a, 0x3c51, - 0xcd0b, 0xc807, - 0xcd0c, 0x4061, - 0xcd0d, 0xc808, - 0xcd0e, 0x49c1, - 0xcd0f, 0xc809, - 0xcd10, 0x3840, - 0xcd11, 0xc80a, - 0xcd12, 0x000, - 0xcd13, 0xc821, - 0xcd14, 0x002, - 0xcd15, 0xc822, - 0xcd16, 0x046, - 0xcd17, 0xc844, - 0xcd18, 0x182f, - 0xcd19, 0xc013, - 0xcd1a, 0xf341, - 0xcd1b, 0xc01a, - 0xcd1c, 0x446, - 0xcd1d, 0xc024, - 0xcd1e, 0x1000, - 0xcd1f, 0xc025, - 0xcd20, 0xa00, - 0xcd21, 0xc026, - 0xcd22, 0xc0c, - 0xcd23, 0xc027, - 0xcd24, 0xc0c, - 0xcd25, 0xc029, - 0xcd26, 0x0a0, - 0xcd27, 0xc030, - 0xcd28, 0xa00, - 0xcd29, 0xc03c, - 0xcd2a, 0x01c, - 0xcd2b, 0x000, - 0xcd2c, 0x2b84, - 0xcd2d, 0x3c74, - 0xcd2e, 0x6435, - 0xcd2f, 0xdff4, - 0xcd30, 0x6435, - 0xcd31, 0x2806, - 0xcd32, 0x3006, - 0xcd33, 0x8565, - 0xcd34, 0x2b24, - 0xcd35, 0x3c24, - 0xcd36, 0x6436, - 0xcd37, 0x1002, - 0xcd38, 0x2b24, - 0xcd39, 0x3c24, - 0xcd3a, 0x6436, - 0xcd3b, 0x4045, - 0xcd3c, 0x8656, - 0xcd3d, 0x1002, - 0xcd3e, 0x2807, - 0xcd3f, 0x31a7, - 0xcd40, 0x20c4, - 0xcd41, 0x3c24, - 0xcd42, 0x6724, - 0xcd43, 0x1002, - 0xcd44, 0x2807, - 0xcd45, 0x3187, - 0xcd46, 0x20c4, - 0xcd47, 0x3c24, - 0xcd48, 0x6724, - 0xcd49, 0x1002, - 0xcd4a, 0x2514, - 0xcd4b, 0x3c64, - 0xcd4c, 0x6436, - 0xcd4d, 0xdff4, - 0xcd4e, 0x6436, - 0xcd4f, 0x1002, - 0xcd50, 0x2806, - 0xcd51, 0x3cb6, - 0xcd52, 0xc161, - 0xcd53, 0x6134, - 0xcd54, 0x6135, - 0xcd55, 0x5443, - 0xcd56, 0x303, - 0xcd57, 0x6524, - 0xcd58, 0x00b, - 0xcd59, 0x1002, - 0xcd5a, 0xd019, - 0xcd5b, 0x2104, - 0xcd5c, 0x3c24, - 0xcd5d, 0x2105, - 0xcd5e, 0x3805, - 0xcd5f, 0x6524, - 0xcd60, 0xdff4, - 0xcd61, 0x4005, - 0xcd62, 0x6524, - 0xcd63, 0x2e8d, - 0xcd64, 0x303d, - 0xcd65, 0x5dd3, - 0xcd66, 0x306, - 0xcd67, 0x2ff7, - 0xcd68, 0x38f7, - 0xcd69, 0x60b7, - 0xcd6a, 0xdffd, - 0xcd6b, 0x00a, - 0xcd6c, 0x1002, - 0xcd6d, 0 - }; int i, err; err = set_phy_regs(phy, regs); @@ -976,9 +343,16 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) msleep(50); - for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i], - twinax_edc[i + 1]); + if (phy->priv != edc_twinax) + err = t3_get_edc_fw(phy, EDC_TWX_AEL2005, + EDC_TWX_AEL2005_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); if (!err) phy->priv = edc_twinax; return err; @@ -1195,405 +569,6 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) { MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 }, { 0, 0, 0, 0 } }; - - /* TWINAX EDC firmware */ - static u16 twinax_edc[] = { - 0xd800, 0x4009, - 0xd801, 0x2fff, - 0xd802, 0x300f, - 0xd803, 0x40aa, - 0xd804, 0x401c, - 0xd805, 0x401e, - 0xd806, 0x2ff4, - 0xd807, 0x3dc4, - 0xd808, 0x2035, - 0xd809, 0x3035, - 0xd80a, 0x6524, - 0xd80b, 0x2cb2, - 0xd80c, 0x3012, - 0xd80d, 0x1002, - 0xd80e, 0x26e2, - 0xd80f, 0x3022, - 0xd810, 0x1002, - 0xd811, 0x27d2, - 0xd812, 0x3022, - 0xd813, 0x1002, - 0xd814, 0x2822, - 0xd815, 0x3012, - 0xd816, 0x1002, - 0xd817, 0x2492, - 0xd818, 0x3022, - 0xd819, 0x1002, - 0xd81a, 0x2772, - 0xd81b, 0x3012, - 0xd81c, 0x1002, - 0xd81d, 0x23d2, - 0xd81e, 0x3022, - 0xd81f, 0x1002, - 0xd820, 0x22cd, - 0xd821, 0x301d, - 0xd822, 0x27f2, - 0xd823, 0x3022, - 0xd824, 0x1002, - 0xd825, 0x5553, - 0xd826, 0x0307, - 0xd827, 0x2522, - 0xd828, 0x3022, - 0xd829, 0x1002, - 0xd82a, 0x2142, - 0xd82b, 0x3012, - 0xd82c, 0x1002, - 0xd82d, 0x4016, - 0xd82e, 0x5e63, - 0xd82f, 0x0344, - 0xd830, 0x2142, - 0xd831, 0x3012, - 0xd832, 0x1002, - 0xd833, 0x400e, - 0xd834, 0x2522, - 0xd835, 0x3022, - 0xd836, 0x1002, - 0xd837, 0x2b52, - 0xd838, 0x3012, - 0xd839, 0x1002, - 0xd83a, 0x2742, - 0xd83b, 0x3022, - 0xd83c, 0x1002, - 0xd83d, 0x25e2, - 0xd83e, 0x3022, - 0xd83f, 0x1002, - 0xd840, 0x2fa4, - 0xd841, 0x3dc4, - 0xd842, 0x6624, - 0xd843, 0x414b, - 0xd844, 0x56b3, - 0xd845, 0x03c6, - 0xd846, 0x866b, - 0xd847, 0x400c, - 0xd848, 0x2712, - 0xd849, 0x3012, - 0xd84a, 0x1002, - 0xd84b, 0x2c4b, - 0xd84c, 0x309b, - 0xd84d, 0x56b3, - 0xd84e, 0x03c3, - 0xd84f, 0x866b, - 0xd850, 0x400c, - 0xd851, 0x2272, - 0xd852, 0x3022, - 0xd853, 0x1002, - 0xd854, 0x2742, - 0xd855, 0x3022, - 0xd856, 0x1002, - 0xd857, 0x25e2, - 0xd858, 0x3022, - 0xd859, 0x1002, - 0xd85a, 0x2fb4, - 0xd85b, 0x3dc4, - 0xd85c, 0x6624, - 0xd85d, 0x56b3, - 0xd85e, 0x03c3, - 0xd85f, 0x866b, - 0xd860, 0x401c, - 0xd861, 0x2c45, - 0xd862, 0x3095, - 0xd863, 0x5b53, - 0xd864, 0x2372, - 0xd865, 0x3012, - 0xd866, 0x13c2, - 0xd867, 0x5cc3, - 0xd868, 0x2712, - 0xd869, 0x3012, - 0xd86a, 0x1312, - 0xd86b, 0x2b52, - 0xd86c, 0x3012, - 0xd86d, 0x1002, - 0xd86e, 0x2742, - 0xd86f, 0x3022, - 0xd870, 0x1002, - 0xd871, 0x2582, - 0xd872, 0x3022, - 0xd873, 0x1002, - 0xd874, 0x2142, - 0xd875, 0x3012, - 0xd876, 0x1002, - 0xd877, 0x628f, - 0xd878, 0x2985, - 0xd879, 0x33a5, - 0xd87a, 0x25e2, - 0xd87b, 0x3022, - 0xd87c, 0x1002, - 0xd87d, 0x5653, - 0xd87e, 0x03d2, - 0xd87f, 0x401e, - 0xd880, 0x6f72, - 0xd881, 0x1002, - 0xd882, 0x628f, - 0xd883, 0x2304, - 0xd884, 0x3c84, - 0xd885, 0x6436, - 0xd886, 0xdff4, - 0xd887, 0x6436, - 0xd888, 0x2ff5, - 0xd889, 0x3005, - 0xd88a, 0x8656, - 0xd88b, 0xdfba, - 0xd88c, 0x56a3, - 0xd88d, 0xd05a, - 0xd88e, 0x2972, - 0xd88f, 0x3012, - 0xd890, 0x1392, - 0xd891, 0xd05a, - 0xd892, 0x56a3, - 0xd893, 0xdfba, - 0xd894, 0x0383, - 0xd895, 0x6f72, - 0xd896, 0x1002, - 0xd897, 0x2b45, - 0xd898, 0x3005, - 0xd899, 0x4178, - 0xd89a, 0x5653, - 0xd89b, 0x0384, - 0xd89c, 0x2a62, - 0xd89d, 0x3012, - 0xd89e, 0x1002, - 0xd89f, 0x2f05, - 0xd8a0, 0x3005, - 0xd8a1, 0x41c8, - 0xd8a2, 0x5653, - 0xd8a3, 0x0382, - 0xd8a4, 0x0002, - 0xd8a5, 0x4218, - 0xd8a6, 0x2474, - 0xd8a7, 0x3c84, - 0xd8a8, 0x6437, - 0xd8a9, 0xdff4, - 0xd8aa, 0x6437, - 0xd8ab, 0x2ff5, - 0xd8ac, 0x3c05, - 0xd8ad, 0x8757, - 0xd8ae, 0xb888, - 0xd8af, 0x9787, - 0xd8b0, 0xdff4, - 0xd8b1, 0x6724, - 0xd8b2, 0x866a, - 0xd8b3, 0x6f72, - 0xd8b4, 0x1002, - 0xd8b5, 0x2641, - 0xd8b6, 0x3021, - 0xd8b7, 0x1001, - 0xd8b8, 0xc620, - 0xd8b9, 0x0000, - 0xd8ba, 0xc621, - 0xd8bb, 0x0000, - 0xd8bc, 0xc622, - 0xd8bd, 0x00ce, - 0xd8be, 0xc623, - 0xd8bf, 0x007f, - 0xd8c0, 0xc624, - 0xd8c1, 0x0032, - 0xd8c2, 0xc625, - 0xd8c3, 0x0000, - 0xd8c4, 0xc627, - 0xd8c5, 0x0000, - 0xd8c6, 0xc628, - 0xd8c7, 0x0000, - 0xd8c8, 0xc62c, - 0xd8c9, 0x0000, - 0xd8ca, 0x0000, - 0xd8cb, 0x2641, - 0xd8cc, 0x3021, - 0xd8cd, 0x1001, - 0xd8ce, 0xc502, - 0xd8cf, 0x53ac, - 0xd8d0, 0xc503, - 0xd8d1, 0x2cd3, - 0xd8d2, 0xc600, - 0xd8d3, 0x2a6e, - 0xd8d4, 0xc601, - 0xd8d5, 0x2a2c, - 0xd8d6, 0xc605, - 0xd8d7, 0x5557, - 0xd8d8, 0xc60c, - 0xd8d9, 0x5400, - 0xd8da, 0xc710, - 0xd8db, 0x0700, - 0xd8dc, 0xc711, - 0xd8dd, 0x0f06, - 0xd8de, 0xc718, - 0xd8df, 0x0700, - 0xd8e0, 0xc719, - 0xd8e1, 0x0f06, - 0xd8e2, 0xc720, - 0xd8e3, 0x4700, - 0xd8e4, 0xc721, - 0xd8e5, 0x0f06, - 0xd8e6, 0xc728, - 0xd8e7, 0x0700, - 0xd8e8, 0xc729, - 0xd8e9, 0x1207, - 0xd8ea, 0xc801, - 0xd8eb, 0x7f50, - 0xd8ec, 0xc802, - 0xd8ed, 0x7760, - 0xd8ee, 0xc803, - 0xd8ef, 0x7fce, - 0xd8f0, 0xc804, - 0xd8f1, 0x520e, - 0xd8f2, 0xc805, - 0xd8f3, 0x5c11, - 0xd8f4, 0xc806, - 0xd8f5, 0x3c51, - 0xd8f6, 0xc807, - 0xd8f7, 0x4061, - 0xd8f8, 0xc808, - 0xd8f9, 0x49c1, - 0xd8fa, 0xc809, - 0xd8fb, 0x3840, - 0xd8fc, 0xc80a, - 0xd8fd, 0x0000, - 0xd8fe, 0xc821, - 0xd8ff, 0x0002, - 0xd900, 0xc822, - 0xd901, 0x0046, - 0xd902, 0xc844, - 0xd903, 0x182f, - 0xd904, 0xc013, - 0xd905, 0xf341, - 0xd906, 0xc084, - 0xd907, 0x0030, - 0xd908, 0xc904, - 0xd909, 0x1401, - 0xd90a, 0xcb0c, - 0xd90b, 0x0004, - 0xd90c, 0xcb0e, - 0xd90d, 0xa00a, - 0xd90e, 0xcb0f, - 0xd90f, 0xc0c0, - 0xd910, 0xcb10, - 0xd911, 0xc0c0, - 0xd912, 0xcb11, - 0xd913, 0x00a0, - 0xd914, 0xcb12, - 0xd915, 0x0007, - 0xd916, 0xc241, - 0xd917, 0xa000, - 0xd918, 0xc243, - 0xd919, 0x7fe0, - 0xd91a, 0xc604, - 0xd91b, 0x000e, - 0xd91c, 0xc609, - 0xd91d, 0x00f5, - 0xd91e, 0xc611, - 0xd91f, 0x000e, - 0xd920, 0xc660, - 0xd921, 0x9600, - 0xd922, 0xc687, - 0xd923, 0x0004, - 0xd924, 0xc60a, - 0xd925, 0x04f5, - 0xd926, 0x0000, - 0xd927, 0x2641, - 0xd928, 0x3021, - 0xd929, 0x1001, - 0xd92a, 0xc620, - 0xd92b, 0x14e5, - 0xd92c, 0xc621, - 0xd92d, 0xc53d, - 0xd92e, 0xc622, - 0xd92f, 0x3cbe, - 0xd930, 0xc623, - 0xd931, 0x4452, - 0xd932, 0xc624, - 0xd933, 0xc5c5, - 0xd934, 0xc625, - 0xd935, 0xe01e, - 0xd936, 0xc627, - 0xd937, 0x0000, - 0xd938, 0xc628, - 0xd939, 0x0000, - 0xd93a, 0xc62c, - 0xd93b, 0x0000, - 0xd93c, 0x0000, - 0xd93d, 0x2b84, - 0xd93e, 0x3c74, - 0xd93f, 0x6435, - 0xd940, 0xdff4, - 0xd941, 0x6435, - 0xd942, 0x2806, - 0xd943, 0x3006, - 0xd944, 0x8565, - 0xd945, 0x2b24, - 0xd946, 0x3c24, - 0xd947, 0x6436, - 0xd948, 0x1002, - 0xd949, 0x2b24, - 0xd94a, 0x3c24, - 0xd94b, 0x6436, - 0xd94c, 0x4045, - 0xd94d, 0x8656, - 0xd94e, 0x5663, - 0xd94f, 0x0302, - 0xd950, 0x401e, - 0xd951, 0x1002, - 0xd952, 0x2807, - 0xd953, 0x31a7, - 0xd954, 0x20c4, - 0xd955, 0x3c24, - 0xd956, 0x6724, - 0xd957, 0x1002, - 0xd958, 0x2807, - 0xd959, 0x3187, - 0xd95a, 0x20c4, - 0xd95b, 0x3c24, - 0xd95c, 0x6724, - 0xd95d, 0x1002, - 0xd95e, 0x24f4, - 0xd95f, 0x3c64, - 0xd960, 0x6436, - 0xd961, 0xdff4, - 0xd962, 0x6436, - 0xd963, 0x1002, - 0xd964, 0x2006, - 0xd965, 0x3d76, - 0xd966, 0xc161, - 0xd967, 0x6134, - 0xd968, 0x6135, - 0xd969, 0x5443, - 0xd96a, 0x0303, - 0xd96b, 0x6524, - 0xd96c, 0x00fb, - 0xd96d, 0x1002, - 0xd96e, 0x20d4, - 0xd96f, 0x3c24, - 0xd970, 0x2025, - 0xd971, 0x3005, - 0xd972, 0x6524, - 0xd973, 0x1002, - 0xd974, 0xd019, - 0xd975, 0x2104, - 0xd976, 0x3c24, - 0xd977, 0x2105, - 0xd978, 0x3805, - 0xd979, 0x6524, - 0xd97a, 0xdff4, - 0xd97b, 0x4005, - 0xd97c, 0x6524, - 0xd97d, 0x2e8d, - 0xd97e, 0x303d, - 0xd97f, 0x2408, - 0xd980, 0x35d8, - 0xd981, 0x5dd3, - 0xd982, 0x0307, - 0xd983, 0x8887, - 0xd984, 0x63a7, - 0xd985, 0x8887, - 0xd986, 0x63a7, - 0xd987, 0xdffd, - 0xd988, 0x00f9, - 0xd989, 0x1002, - 0xd98a, 0x0000, - }; int i, err; /* set uC clock and activate it */ @@ -1606,10 +581,16 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) if (err) return err; - /* write TWINAX EDC firmware into PHY */ - for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i], - twinax_edc[i + 1]); + if (phy->priv != edc_twinax) + err = t3_get_edc_fw(phy, EDC_TWX_AEL2020, + EDC_TWX_AEL2020_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); /* activate uC */ err = set_phy_regs(phy, uCactivate); if (!err) diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index d21b705..1b2c305 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -566,6 +566,15 @@ struct cphy_ops { u32 mmds; }; +enum { + EDC_OPT_AEL2005 = 0, + EDC_OPT_AEL2005_SIZE = 1084, + EDC_TWX_AEL2005 = 1, + EDC_TWX_AEL2005_SIZE = 1464, + EDC_TWX_AEL2020 = 2, + EDC_TWX_AEL2020_SIZE = 1628, + EDC_MAX_SIZE = EDC_TWX_AEL2020_SIZE, /* Max cache size */ +}; /* A PHY instance */ struct cphy { @@ -577,6 +586,7 @@ struct cphy { unsigned long fifo_errors; /* FIFO over/under-flows */ const struct cphy_ops *ops; /* PHY operations */ struct mdio_if_info mdio; + u16 phy_cache[EDC_MAX_SIZE]; /* EDC cache */ }; /* Convenience MDIO read/write wrappers */ diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 538dda4..27e7ef5 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -964,6 +964,75 @@ static int bind_qsets(struct adapter *adap) #define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin" #define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin" +#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin" +#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" +#define AEL2020_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" + +static inline const char *get_edc_fw_name(int edc_idx) +{ + const char *fw_name = NULL; + + switch (edc_idx) { + case EDC_OPT_AEL2005: + fw_name = AEL2005_OPT_EDC_NAME; + break; + case EDC_TWX_AEL2005: + fw_name = AEL2005_TWX_EDC_NAME; + break; + case EDC_TWX_AEL2020: + fw_name = AEL2020_TWX_EDC_NAME; + break; + } + return fw_name; +} + +int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size) +{ + struct adapter *adapter = phy->adapter; + const struct firmware *fw; + char buf[64]; + u32 csum; + const __be32 *p; + u16 *cache = phy->phy_cache; + int i, ret; + + snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx)); + + ret = request_firmware(&fw, buf, &adapter->pdev->dev); + if (ret < 0) { + dev_err(&adapter->pdev->dev, + "could not upgrade firmware: unable to load %s\n", + buf); + return ret; + } + + /* check size, take checksum in account */ + if (fw->size > size + 4) { + CH_ERR(adapter, "firmware image too large %u, expected %d\n", + (unsigned int)fw->size, size + 4); + ret = -EINVAL; + } + + /* compute checksum */ + p = (const __be32 *)fw->data; + for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++) + csum += ntohl(p[i]); + + if (csum != 0xffffffff) { + CH_ERR(adapter, "corrupted firmware image, checksum %u\n", + csum); + ret = -EINVAL; + } + + for (i = 0; i < size / 4 ; i++) { + *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16; + *cache++ = be32_to_cpu(p[i]) & 0xffff; + } + + release_firmware(fw); + + return ret; +} static int upgrade_fw(struct adapter *adap) { diff --git a/firmware/Makefile b/firmware/Makefile index 621de8e..44313b2 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -41,7 +41,10 @@ fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \ cxgb3/t3c_psram-1.1.0.bin \ - cxgb3/t3fw-7.4.0.bin + cxgb3/t3fw-7.4.0.bin \ + cxgb3/ael2005_opt_edc.bin \ + cxgb3/ael2005_twx_edc.bin \ + cxgb3/ael2020_twx_edc.bin fw-shipped-$(CONFIG_DVB_AV7110) += av7110/bootcode.bin fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \ diff --git a/firmware/WHENCE b/firmware/WHENCE index 0f5649a..d9e3a94 100644 --- a/firmware/WHENCE +++ b/firmware/WHENCE @@ -418,6 +418,23 @@ License: GPLv2 or OpenIB.org BSD license, no source visible -------------------------------------------------------------------------- +Driver: cxgb3 - Chelsio Terminator 3 1G/10G Ethernet adapter + +File: cxgb3/ael2005_opt_edc.bin.ihex +File: cxgb3/ael2005_twx_edc.bin.ihex +File: cxgb3/ael2020_twx_edc.bin.ihex + +Licence: + * Copyright (c) 2007-2009 NetLogic Microsystems, Inc. + * + * Permission is hereby granted for the distribution of this firmware + * data in hexadecimal or equivalent format, provided this copyright + * notice is accompanying it. + +Found in hex form in kernel source. + +-------------------------------------------------------------------------- + Driver: e100 -- Intel PRO/100 Ethernet NIC File: e100/d101m_ucode.bin diff --git a/firmware/cxgb3/ael2005_opt_edc.bin.ihex b/firmware/cxgb3/ael2005_opt_edc.bin.ihex new file mode 100644 index 0000000..c1d6e5d --- /dev/null +++ b/firmware/cxgb3/ael2005_opt_edc.bin.ihex @@ -0,0 +1,69 @@ +:10000000CC002FF4CC013CD4CC022015CC0331051C +:10001000CC046524CC0527FFCC06300FCC072C8BF5 +:10002000CC08300BCC094009CC0A400ECC0B2F7207 +:10003000CC0C3002CC0D1002CC0E2172CC0F301241 +:10004000CC101002CC1125D2CC123012CC131002DD +:10005000CC14D01ECC1527D2CC163012CC171002DF +:10006000CC182004CC193C84CC1A6436CC1B200755 +:10007000CC1C3F87CC1D8676CC1E40B7CC1FA74634 +:10008000CC204047CC215673CC222982CC2330028D +:10009000CC2413D2CC258BBDCC262862CC273012A1 +:1000A000CC281002CC292092CC2A3012CC2B100262 +:1000B000CC2C5CC3CC2D0314CC2E2942CC2F300287 +:1000C000CC301002CC31D019CC322032CC333012AB +:1000D000CC341002CC352A04CC363C74CC37643591 +:1000E000CC382FA4CC393CD4CC3A6624CC3B5563D5 +:1000F000CC3C2D42CC3D3002CC3E13D2CC3F464DC1 +:10010000CC402862CC413012CC421002CC43203289 +:10011000CC443012CC451002CC462FB4CC473CD452 +:10012000CC486624CC495563CC4A2D42CC4B300296 +:10013000CC4C13D2CC4D2ED2CC4E3002CC4F100230 +:10014000CC502FD2CC513002CC521002CC530004F0 +:10015000CC542942CC553002CC561002CC572092B8 +:10016000CC583012CC591002CC5A5CC3CC5B03176C +:10017000CC5C2F72CC5D3002CC5E1002CC5F294289 +:10018000CC603002CC611002CC6222CDCC63301D39 +:10019000CC642862CC653012CC661002CC672ED2BB +:1001A000CC683002CC691002CC6A2D72CC6B300264 +:1001B000CC6C1002CC6D628FCC6E2112CC6F3012E1 +:1001C000CC701002CC715AA3CC722DC2CC73300209 +:1001D000CC741312CC756F72CC761002CC772807D2 +:1001E000CC7831A7CC7920C4CC7A3C24CC7B672452 +:1001F000CC7C1002CC7D2807CC7E3187CC7F20C4FC +:10020000CC803C24CC816724CC821002CC83251482 +:10021000CC843C64CC856436CC86DFF4CC876436F1 +:10022000CC881002CC8940A4CC8A643CCC8B40168C +:10023000CC8C8C6CCC8D2B24CC8E3C24CC8F643518 +:10024000CC901002CC912B24CC923C24CC93643AD9 +:10025000CC944025CC958A5ACC961002CC97273165 +:10026000CC983011CC991001CC9AC7A0CC9B01003E +:10027000CC9CC502CC9D53ACCC9EC503CC9FD5D5A0 +:10028000CCA0C600CCA12A6DCCA2C601CCA32A4C1E +:10029000CCA4C602CCA50111CCA6C60CCCA7590093 +:1002A000CCA8C710CCA90700CCAAC718CCAB0700B4 +:1002B000CCACC720CCAD4700CCAEC801CCAF7F5092 +:1002C000CCB0C802CCB17760CCB2C803CCB37FCE7F +:1002D000CCB4C804CCB55700CCB6C805CCB75F11B8 +:1002E000CCB8C806CCB94751CCBAC807CCBB57E18B +:1002F000CCBCC808CCBD2700CCBEC809CCBF000010 +:10030000CCC0C821CCC10002CCC2C822CCC30014CE +:10031000CCC4C832CCC51186CCC6C847CCC71E02D7 +:10032000CCC8C013CCC9F341CCCAC01ACCCB04464C +:10033000CCCCC024CCCD1000CCCEC025CCCF0A0074 +:10034000CCD0C026CCD10C0CCCD2C027CCD30C0C3A +:10035000CCD4C029CCD500A0CCD6C030CCD70A0094 +:10036000CCD8C03CCCD9001CCCDAC005CCDB7A069A +:10037000CCDC0000CCDD2731CCDE3011CCDF10012D +:10038000CCE0C620CCE10000CCE2C621CCE3003FAB +:10039000CCE4C622CCE50000CCE6C623CCE70000C6 +:1003A000CCE8C624CCE90000CCEAC625CCEB0000A2 +:1003B000CCECC627CCED0000CCEEC628CCEF00007C +:1003C000CCF0C62CCCF10000CCF20000CCF3280617 +:1003D000CCF43CB6CCF5C161CCF66134CCF76135D8 +:1003E000CCF85443CCF90303CCFA6524CCFB000BC6 +:1003F000CCFC1002CCFD2104CCFE3C24CCFF21051A +:10040000CD003805CD016524CD02DFF4CD034005D4 +:10041000CD046524CD051002CD065DD3CD070306BE +:10042000CD082FF7CD0938F7CD0A60B7CD0BDFFD2A +:10043000CD0C000ACD0D1002CD0E00007CC7AE59C8 +:00000001FF diff --git a/firmware/cxgb3/ael2005_twx_edc.bin.ihex b/firmware/cxgb3/ael2005_twx_edc.bin.ihex new file mode 100644 index 0000000..9b5e9e5 --- /dev/null +++ b/firmware/cxgb3/ael2005_twx_edc.bin.ihex @@ -0,0 +1,93 @@ +:10000000CC004009CC0127FFCC02300FCC0340AA22 +:10001000CC04401CCC05401ECC062FF4CC073CD4AD +:10002000CC082035CC093145CC0A6524CC0B26A25E +:10003000CC0C3012CC0D1002CC0E29C2CC0F3002E9 +:10004000CC101002CC112072CC123012CC13100242 +:10005000CC1422CDCC15301DCC162E52CC1730121C +:10006000CC181002CC1928E2CC1A3002CC1B10029A +:10007000CC1C628FCC1D2AC2CC1E3012CC1F1002A9 +:10008000CC205553CC212AE2CC223002CC231302BF +:10009000CC24401ECC252BE2CC263012CC271002DB +:1000A000CC282DA2CC293012CC2A1002CC2B2BA28A +:1000B000CC2C3002CC2D1002CC2E5EE3CC2F0305CD +:1000C000CC30400ECC312BC2CC323002CC331002BB +:1000D000CC342B82CC353012CC361002CC37566360 +:1000E000CC380302CC39401ECC3A6F72CC3B1002A4 +:1000F000CC3C628FCC3D2BE2CC3E3012CC3F100288 +:10010000CC4022CDCC41301DCC422E52CC433012BB +:10011000CC441002CC452522CC463012CC471002EC +:10012000CC482DA2CC493012CC4A1002CC4B2CA288 +:10013000CC4C3012CC4D1002CC4E2FA4CC4F3CD422 +:10014000CC506624CC51410BCC5256B3CC5303C493 +:10015000CC542FB2CC553002CC561002CC57220BC7 +:10016000CC58303BCC5956B3CC5A03C3CC5B866BCE +:10017000CC5C400CCC5D23A2CC5E3012CC5F100274 +:10018000CC602DA2CC613012CC621002CC632CA2C8 +:10019000CC643012CC651002CC662FB4CC673CD452 +:1001A000CC686624CC6956B3CC6A03C3CC6B866B2F +:1001B000CC6C401CCC6D2205CC6E3035CC6F5B53C3 +:1001C000CC702C52CC713002CC7213C2CC735CC395 +:1001D000CC740317CC752522CC763012CC77100264 +:1001E000CC782DA2CC793012CC7A1002CC7B2B8229 +:1001F000CC7C3012CC7D1002CC7E5663CC7F0303C6 +:10020000CC80401ECC810004CC822C42CC833012A6 +:10021000CC841002CC856F72CC861002CC87628FA2 +:10022000CC882304CC893C84CC8A6436CC8BDFF424 +:10023000CC8C6436CC8D2FF5CC8E3005CC8F865689 +:10024000CC90DFBACC9156A3CC92D05ACC9321C299 +:10025000CC943012CC951392CC96D05ACC9756A30E +:10026000CC98DFBACC990383CC9A6F72CC9B1002E6 +:10027000CC9C28C5CC9D3005CC9E4178CC9F565354 +:10028000CCA00384CCA122B2CCA23012CCA3100209 +:10029000CCA42BE5CCA53005CCA641E8CCA7565381 +:1002A000CCA80382CCA90002CCAA4258CCAB2474BF +:1002B000CCAC3C84CCAD6437CCAEDFF4CCAF64378F +:1002C000CCB02FF5CCB13C05CCB28757CCB3B888B5 +:1002D000CCB49787CCB5DFF4CCB66724CCB7866AAC +:1002E000CCB86F72CCB91002CCBA2D01CCBB301196 +:1002F000CCBC1001CCBDC620CCBE14E5CCBFC62101 +:10030000CCC0C53DCCC1C622CCC23CBECCC3C623EA +:10031000CCC44452CCC5C624CCC6C5C5CCC7C625A2 +:10032000CCC8E01ECCC9C627CCCA0000CCCBC6289E +:10033000CCCC0000CCCDC62BCCCE0000CCCFC62C74 +:10034000CCD00000CCD10000CCD22D01CCD33011C8 +:10035000CCD41001CCD5C620CCD60000CCD7C62139 +:10036000CCD80000CCD9C622CCDA00CECCDBC62358 +:10037000CCDC007FCCDDC624CCDE0032CCDFC62551 +:10038000CCE00000CCE1C627CCE20000CCE3C628DC +:10039000CCE40000CCE5C62BCCE60000CCE7C62CB4 +:1003A000CCE80000CCE90000CCEA2D01CCEB301108 +:1003B000CCEC1001CCEDC502CCEE609FCCEFC600BA +:1003C000CCF02A6ECCF1C601CCF22A2CCCF3C60CB0 +:1003D000CCF45400CCF5C710CCF60700CCF7C71806 +:1003E000CCF80700CCF9C720CCFA4700CCFBC728D3 +:1003F000CCFC0700CCFDC729CCFE1207CCFFC801FE +:10040000CD007F50CD01C802CD027760CD03C80377 +:10041000CD047FCECD05C804CD06520ECD07C8054C +:10042000CD085C11CD09C806CD0A3C51CD0BC807DB +:10043000CD0C4061CD0DC808CD0E49C1CD0FC80906 +:10044000CD103840CD11C80ACD120000CD13C821FF +:10045000CD140002CD15C822CD160046CD17C844D4 +:10046000CD18182FCD19C013CD1AF341CD1BC01ACA +:10047000CD1C0446CD1DC024CD1E1000CD1FC025AF +:10048000CD200A00CD21C026CD220C0CCD23C027C3 +:10049000CD240C0CCD25C029CD2600A0CD27C03001 +:1004A000CD280A00CD29C03CCD2A001CCD2B000050 +:1004B000CD2C2B84CD2D3C74CD2E6435CD2FDFF487 +:1004C000CD306435CD312806CD323006CD3385654B +:1004D000CD342B24CD353C24CD366436CD371002B7 +:1004E000CD382B24CD393C24CD3A6436CD3B404524 +:1004F000CD3C8656CD3D1002CD3E2807CD3F31A7DD +:10050000CD4020C4CD413C24CD426724CD431002D0 +:10051000CD442807CD453187CD4620C4CD473C2466 +:10052000CD486724CD491002CD4A2514CD4B3C64FB +:10053000CD4C6436CD4DDFF4CD4E6436CD4F100238 +:10054000CD502806CD513CB6CD52C161CD5361345A +:10055000CD546135CD555443CD560303CD57652455 +:10056000CD58000BCD591002CD5AD019CD5B2104C6 +:10057000CD5C3C24CD5D2105CD5E3805CD5F652485 +:10058000CD60DFF4CD614005CD626524CD632E8D55 +:10059000CD64303DCD655DD3CD660306CD672FF7C5 +:1005A000CD6838F7CD6960B7CD6ADFFDCD6B000A45 +:0C05B000CD6C1002CD6D000052A76B0E48 +:00000001FF diff --git a/firmware/cxgb3/ael2020_twx_edc.bin.ihex b/firmware/cxgb3/ael2020_twx_edc.bin.ihex new file mode 100644 index 0000000..8b1337f --- /dev/null +++ b/firmware/cxgb3/ael2020_twx_edc.bin.ihex @@ -0,0 +1,100 @@ +:10000000D8004009D8012FFFD802300FD80340AAEA +:10001000D804401CD805401ED8062FF4D8073DC48C +:10002000D8082035D8093035D80A6524D80B2CB229 +:10003000D80C3012D80D1002D80E26E2D80F30227C +:10004000D8101002D81127D2D8123022D81310029B +:10005000D8142822D8153012D8161002D817249296 +:10006000D8183022D8191002D81A2772D81B30128B +:10007000D81C1002D81D23D2D81E3022D81F10023F +:10008000D82022CDD821301DD82227F2D8233022E3 +:10009000D8241002D8255553D8260307D82725225F +:1000A000D8283022D8291002D82A2142D82B301241 +:1000B000D82C1002D82D4016D82E5E63D82F0344BA +:1000C000D8302142D8313012D8321002D833400E05 +:1000D000D8342522D8353022D8361002D8372B52C2 +:1000E000D8383012D8391002D83A2742D83B3022BB +:1000F000D83C1002D83D25E2D83E3022D83F10022D +:10010000D8402FA4D8413DC4D8426624D843414B9F +:10011000D84456B3D84503C6D846866BD847400C5A +:10012000D8482712D8493012D84A1002D84B2C4B45 +:10013000D84C309BD84D56B3D84E03C3D84F866B9E +:10014000D850400CD8512272D8523022D8531002C5 +:10015000D8542742D8553022D8561002D85725E215 +:10016000D8583022D8591002D85A2FB4D85B3DC481 +:10017000D85C6624D85D56B3D85E03C3D85F866B5F +:10018000D860401CD8612C45D8623095D8635B5349 +:10019000D8642372D8653012D86613C2D8675CC39E +:1001A000D8682712D8693012D86A1312D86B2B522C +:1001B000D86C3012D86D1002D86E2742D86F30221A +:1001C000D8701002D8712582D8723022D8731002EC +:1001D000D8742142D8753012D8761002D877628F41 +:1001E000D8782985D87933A5D87A25E2D87B3022EA +:1001F000D87C1002D87D5653D87E03D2D87F401EBB +:10020000D8806F72D8811002D882628FD88323047D +:10021000D8843C84D8856436D886DFF4D8876436A1 +:10022000D8882FF5D8893005D88A8656D88BDFBA7A +:10023000D88C56A3D88DD05AD88E2972D88F301228 +:10024000D8901392D891D05AD89256A3D893DFBAA7 +:10025000D8940383D8956F72D8961002D8972B45FF +:10026000D8983005D8994178D89A5653D89B0384AA +:10027000D89C2A62D89D3012D89E1002D89F2F0594 +:10028000D8A03005D8A141C8D8A25653D8A303821C +:10029000D8A40002D8A54218D8A62474D8A73C84B4 +:1002A000D8A86437D8A9DFF4D8AA6437D8AB2FF51B +:1002B000D8AC3C05D8AD8757D8AEB888D8AF9787AB +:1002C000D8B0DFF4D8B16724D8B2866AD8B36F72D9 +:1002D000D8B41002D8B52641D8B63021D8B710010D +:1002E000D8B8C620D8B90000D8BAC621D8BB0000FB +:1002F000D8BCC622D8BD00CED8BEC623D8BF007F8A +:10030000D8C0C624D8C10032D8C2C625D8C3000080 +:10031000D8C4C627D8C50000D8C6C628D8C700008C +:10032000D8C8C62CD8C90000D8CA0000D8CB2641EE +:10033000D8CC3021D8CD1001D8CEC502D8CF53ACFF +:10034000D8D0C503D8D12CD3D8D2C600D8D32A6EE2 +:10035000D8D4C601D8D52A2CD8D6C605D8D7555753 +:10036000D8D8C60CD8D95400D8DAC710D8DB0700C3 +:10037000D8DCC711D8DD0F06D8DEC718D8DF0700D4 +:10038000D8E0C719D8E10F06D8E2C720D8E3470064 +:10039000D8E4C721D8E50F06D8E6C728D8E7070074 +:1003A000D8E8C729D8E91207D8EAC801D8EB7F50A6 +:1003B000D8ECC802D8ED7760D8EEC803D8EF7FCE6E +:1003C000D8F0C804D8F1520ED8F2C805D8F35C11A1 +:1003D000D8F4C806D8F53C51D8F6C807D8F740611C +:1003E000D8F8C808D8F949C1D8FAC809D8FB3840A4 +:1003F000D8FCC80AD8FD0000D8FEC821D8FF0002EA +:10040000D900C822D9010046D902C844D903182FFF +:10041000D904C013D905F341D906C084D9070030E7 +:10042000D908C904D9091401D90ACB0CD90B000485 +:10043000D90CCB0ED90DA00AD90ECB0FD90FC0C045 +:10044000D910CB10D911C0C0D912CB11D91300A02B +:10045000D914CB12D9150007D916C241D917A0005B +:10046000D918C243D9197FE0D91AC604D91B000E86 +:10047000D91CC609D91D00F5D91EC611D91F000EF9 +:10048000D920C660D9219600D922C687D923000475 +:10049000D924C60AD92504F5D9260000D927264132 +:1004A000D9283021D9291001D92AC620D92B14E501 +:1004B000D92CC621D92DC53DD92EC622D92F3CBE57 +:1004C000D930C623D9314452D932C624D933C5C50F +:1004D000D934C625D935E01ED936C627D93700000C +:1004E000D938C628D9390000D93AC62CD93B0000E2 +:1004F000D93C0000D93D2B84D93E3C74D93F6435AA +:10050000D940DFF4D9416435D9422806D9433006B1 +:10051000D9448565D9452B24D9463C24D94764362E +:10052000D9481002D9492B24D94A3C24D94B6436E6 +:10053000D94C4045D94D8656D94E5663D94F030202 +:10054000D950401ED9511002D9522807D95331A78A +:10055000D95420C4D9553C24D9566724D957100200 +:10056000D9582807D9593187D95A20C4D95B3C2496 +:10057000D95C6724D95D1002D95E24F4D95F3C644C +:10058000D9606436D961DFF4D9626436D963100268 +:10059000D9642006D9653D76D966C161D9676134D1 +:1005A000D9686135D9695443D96A0303D96B652485 +:1005B000D96C00FBD96D1002D96E20D4D96F3C24C0 +:1005C000D9702025D9713005D9726524D9731002EC +:1005D000D974D019D9752104D9763C24D97721054D +:1005E000D9783805D9796524D97ADFF4D97B4005E3 +:1005F000D97C6524D97D2E8DD97E303DD97F2408C4 +:10060000D98035D8D9815DD3D9820307D98388872A +:10061000D98463A7D9858887D98663A7D987DFFD61 +:10062000D98800F9D9891002D98A0000878C30D97D +:00000001FF -- cgit v0.10.2 From dce7d1d031aeaa8c65bd37ff2480dc450a68185e Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:59 +0000 Subject: cxgb3: Fix mss table initialization Fix the HW SMT table initialization to avoid random mss miscomputations for offload connections. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 27e7ef5..d4c4076 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -443,6 +443,7 @@ static int init_tp_parity(struct adapter *adap) memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); + req->mtu_idx = NMTUS - 1; req->iff = i; t3_mgmt_tx(adap, skb); if (skb == adap->nofail_skb) { -- cgit v0.10.2 From 88045b3cf0f8981129cb489c7b6bc36c21dd33a7 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:49:04 +0000 Subject: cxgb3: fix mac index mapping Override the mac index computation for the gen2 adapter, as each port is expected to use index 0. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 870d449..e78d341 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -3682,6 +3682,8 @@ static void mc7_prep(struct adapter *adapter, struct mc7 *mc7, void mac_prep(struct cmac *mac, struct adapter *adapter, int index) { mac->adapter = adapter; + if (!adapter->params.vpd.xauicfg[1]) + index = 0; mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; mac->nucast = 1; -- cgit v0.10.2 From 34701fde8f4bf207ca96d10b8700a8667157854c Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:32 +0000 Subject: cxgb3: Drain Mac Tx fifo when the port goes down. Drain the MAC TX fifos when a port goes down. Back pressure might otherwise occur, leading to both ports of the same adapter to hang. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index d4c4076..8c381c6 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -172,6 +172,23 @@ static void link_report(struct net_device *dev) } } +static void enable_tx_fifo_drain(struct adapter *adapter, + struct port_info *pi) +{ + t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0, + F_ENDROPPKT); + t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0); + t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN); + t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN); +} + +static void disable_tx_fifo_drain(struct adapter *adapter, + struct port_info *pi) +{ + t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, + F_ENDROPPKT, 0); +} + void t3_os_link_fault(struct adapter *adap, int port_id, int state) { struct net_device *dev = adap->port[port_id]; @@ -185,6 +202,8 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state) netif_carrier_on(dev); + disable_tx_fifo_drain(adap, pi); + /* Clear local faults */ t3_xgm_intr_disable(adap, pi->port_id); t3_read_reg(adap, A_XGM_INT_STATUS + @@ -200,9 +219,12 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state) t3_xgm_intr_enable(adap, pi->port_id); t3_mac_enable(mac, MAC_DIRECTION_TX); - } else + } else { netif_carrier_off(dev); + /* Flush TX FIFO */ + enable_tx_fifo_drain(adap, pi); + } link_report(dev); } @@ -232,6 +254,8 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat, if (link_stat != netif_carrier_ok(dev)) { if (link_stat) { + disable_tx_fifo_drain(adapter, pi); + t3_mac_enable(mac, MAC_DIRECTION_RX); /* Clear local faults */ @@ -263,6 +287,9 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat, t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); t3_mac_disable(mac, MAC_DIRECTION_RX); t3_link_start(&pi->phy, mac, &pi->link_config); + + /* Flush TX FIFO */ + enable_tx_fifo_drain(adapter, pi); } link_report(dev); -- cgit v0.10.2 From cb507e7e79f3c0e45ecaefad9220c34fcfbe74e8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 8 Jul 2009 18:54:57 +0100 Subject: ASoC: Add pop delay debug at end of DAPM sequencing Provide an interval after the end of DAPM sequencing so that we can distinguish between a pop in the final step of the sequence and a pop generated from some other source outside DAPM. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 5157ec1..a40594f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -997,6 +997,9 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) pr_err("Failed to apply active bias: %d\n", ret); } + pop_dbg(codec->pop_time, "DAPM sequencing finished, waiting %dms\n", + codec->pop_time); + return 0; } -- cgit v0.10.2 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 diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d77fbd8..9347f4a 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 9675f31..3afe381 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 v0.10.2 From ef5d590c9b9a00b017683006fe4cf959b9532336 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 9 Jul 2009 11:32:55 +0800 Subject: crypto: shash - Add shash_instance_ctx This patch adds the helper shash_instance_ctx which is the shash analogue of crypto_instance_ctx. Signed-off-by: Herbert Xu diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 3af34ca..069b93e 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -110,6 +110,11 @@ static inline struct shash_instance *shash_instance( struct shash_instance, alg); } +static inline void *shash_instance_ctx(struct shash_instance *inst) +{ + return crypto_instance_ctx(shash_crypto_instance(inst)); +} + static inline struct shash_instance *shash_alloc_instance( const char *name, struct crypto_alg *alg) { -- cgit v0.10.2 From 7ede5a5ba55a696a6e1d8456526e44635e966a81 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 9 Jul 2009 11:34:06 +0800 Subject: crypto: api - Fix crypto_drop_spawn crash on blank spawns This patch allows crypto_drop_spawn to be called on spawns that have not been initialised or have failed initialisation. This fixes potential crashes during initialisation without adding special case code. Signed-off-by: Herbert Xu diff --git a/crypto/algapi.c b/crypto/algapi.c index 2154815..6a98076 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -507,6 +507,9 @@ EXPORT_SYMBOL_GPL(crypto_init_spawn2); void crypto_drop_spawn(struct crypto_spawn *spawn) { + if (!spawn->alg) + return; + down_write(&crypto_alg_sem); list_del(&spawn->list); up_write(&crypto_alg_sem); -- cgit v0.10.2 From 63b2413b2ff446e30286c2bd775fd10b12d188c6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Jul 2009 11:45:59 +0200 Subject: ALSA: hda - don't build digital output controls if not exist Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 57251d7..f552738 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -779,6 +779,9 @@ static int build_digital_output(struct hda_codec *codec) struct cs_spec *spec = codec->spec; int err; + if (!spec->multiout.dig_out_nid) + return 0; + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); if (err < 0) return err; -- cgit v0.10.2 From cc369cf504c51d36765e18b0c28a09a92d28ed79 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 9 Jul 2009 11:28:07 +0100 Subject: ASoC: WM8510 has a single frame clock so needs symmetric rates Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index c8b8dba..261d4cb 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -577,6 +577,7 @@ struct snd_soc_dai wm8510_dai = { .rates = WM8510_RATES, .formats = WM8510_FORMATS,}, .ops = &wm8510_dai_ops, + .symmetric_rates = 1, }; EXPORT_SYMBOL_GPL(wm8510_dai); -- cgit v0.10.2 From ed5215a21460f63d6bdc118cb55a9e6d1b433f35 Mon Sep 17 00:00:00 2001 From: Thomas Liu Date: Thu, 9 Jul 2009 10:00:29 -0400 Subject: Move variable function in lsm_audit.h into SMACK private space Moved variable function in include/linux/lsm_audit.h into the smack_audit_data struct since it is never used outside of it. Also removed setting of function in the COMMON_AUDIT_DATA_INIT macro because that variable is now private to SMACK. Signed-off-by: Thomas Liu Acked-by: Eric Paris I-dont-see-any-problems-with-it: Casey Schaufler Signed-off-by: James Morris diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index e461b2c..68f7bce 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -66,11 +66,11 @@ struct common_audit_data { } key_struct; #endif } u; - const char *function; /* this union contains LSM specific data */ union { /* SMACK data */ struct smack_audit_data { + const char *function; char *subject; char *object; char *request; @@ -104,7 +104,7 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb, /* Initialize an LSM audit data structure. */ #define COMMON_AUDIT_DATA_INIT(_d, _t) \ { memset((_d), 0, sizeof(struct common_audit_data)); \ - (_d)->type = LSM_AUDIT_DATA_##_t; (_d)->function = __func__; } + (_d)->type = LSM_AUDIT_DATA_##_t; } void common_lsm_audit(struct common_audit_data *a); diff --git a/security/smack/smack.h b/security/smack/smack.h index 243bec1..ff180ed 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -275,7 +275,7 @@ static inline void smk_ad_init(struct smk_audit_info *a, const char *func, { memset(a, 0, sizeof(*a)); a->a.type = type; - a->a.function = func; + a->a.lsm_priv.smack_audit_data.function = func; } static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 513dc1a..dd84877 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -241,7 +241,8 @@ static void smack_log_callback(struct audit_buffer *ab, void *a) { struct common_audit_data *ad = a; struct smack_audit_data *sad = &ad->lsm_priv.smack_audit_data; - audit_log_format(ab, "lsm=SMACK fn=%s action=%s", ad->function, + audit_log_format(ab, "lsm=SMACK fn=%s action=%s", + ad->lsm_priv.smack_audit_data.function, sad->result ? "denied" : "granted"); audit_log_format(ab, " subject="); audit_log_untrustedstring(ab, sad->subject); @@ -274,8 +275,8 @@ void smack_log(char *subject_label, char *object_label, int request, if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) return; - if (a->function == NULL) - a->function = "unknown"; + if (a->lsm_priv.smack_audit_data.function == NULL) + a->lsm_priv.smack_audit_data.function = "unknown"; /* end preparing the audit data */ sad = &a->lsm_priv.smack_audit_data; -- cgit v0.10.2 From d4131ded4d4c1a5c1363ddd93ca104ed97dd0458 Mon Sep 17 00:00:00 2001 From: Thomas Liu Date: Thu, 9 Jul 2009 10:00:30 -0400 Subject: security: Make lsm_priv union in lsm_audit.h anonymous Made the lsm_priv union in include/linux/lsm_audit.h anonymous. Signed-off-by: Thomas Liu Acked-by: Eric Paris Signed-off-by: James Morris diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index 68f7bce..40d1b84f 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -86,7 +86,7 @@ struct common_audit_data { struct av_decision *avd; int result; } selinux_audit_data; - } lsm_priv; + }; /* these callback will be implemented by a specific LSM */ void (*lsm_pre_audit)(struct audit_buffer *, void *); void (*lsm_post_audit)(struct audit_buffer *, void *); diff --git a/security/smack/smack.h b/security/smack/smack.h index ff180ed..c6e9aca 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -275,7 +275,7 @@ static inline void smk_ad_init(struct smk_audit_info *a, const char *func, { memset(a, 0, sizeof(*a)); a->a.type = type; - a->a.lsm_priv.smack_audit_data.function = func; + a->a.smack_audit_data.function = func; } static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index dd84877..0f9ac81 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -240,9 +240,9 @@ static inline void smack_str_from_perm(char *string, int access) static void smack_log_callback(struct audit_buffer *ab, void *a) { struct common_audit_data *ad = a; - struct smack_audit_data *sad = &ad->lsm_priv.smack_audit_data; + struct smack_audit_data *sad = &ad->smack_audit_data; audit_log_format(ab, "lsm=SMACK fn=%s action=%s", - ad->lsm_priv.smack_audit_data.function, + ad->smack_audit_data.function, sad->result ? "denied" : "granted"); audit_log_format(ab, " subject="); audit_log_untrustedstring(ab, sad->subject); @@ -275,11 +275,11 @@ void smack_log(char *subject_label, char *object_label, int request, if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) return; - if (a->lsm_priv.smack_audit_data.function == NULL) - a->lsm_priv.smack_audit_data.function = "unknown"; + if (a->smack_audit_data.function == NULL) + a->smack_audit_data.function = "unknown"; /* end preparing the audit data */ - sad = &a->lsm_priv.smack_audit_data; + sad = &a->smack_audit_data; smack_str_from_perm(request_buffer, request); sad->subject = subject_label; sad->object = object_label; -- cgit v0.10.2 From 65c3f0a2d0f72d210c879e4974c2d222b7951321 Mon Sep 17 00:00:00 2001 From: Thomas Liu Date: Thu, 9 Jul 2009 10:00:31 -0400 Subject: security: Wrap SMACK and SELINUX audit data structs in ifdefs Wrapped the smack_audit_data and selinux_audit_data structs in include/linux/lsm_audit.h in ifdefs so that the union will always be the correct size. Signed-off-by: Thomas Liu Acked-by: Eric Paris Signed-off-by: James Morris diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index 40d1b84f..a5514a3 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -68,6 +68,7 @@ struct common_audit_data { } u; /* this union contains LSM specific data */ union { +#ifdef CONFIG_SECURITY_SMACK /* SMACK data */ struct smack_audit_data { const char *function; @@ -76,6 +77,8 @@ struct common_audit_data { char *request; int result; } smack_audit_data; +#endif +#ifdef CONFIG_SECURITY_SELINUX /* SELinux data */ struct { u32 ssid; @@ -86,6 +89,7 @@ struct common_audit_data { struct av_decision *avd; int result; } selinux_audit_data; +#endif }; /* these callback will be implemented by a specific LSM */ void (*lsm_pre_audit)(struct audit_buffer *, void *); -- cgit v0.10.2 From c5cb183608167c744cb28bbd85884be5a4ce875d Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 9 Jul 2009 16:20:12 +0800 Subject: tracing/filter: Remove preds from struct event_subsystem No need to save preds to event_subsystem, because it's not used. Signed-off-by: Xiao Guangrong Acked-by: Tom Zanussi Reviewed-by: Li Zefan Cc: Frederic Weisbecker Cc: Steven Rostedt LKML-Reference: <4A55A83C.1030005@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 936c621..b9aae72 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -420,17 +420,7 @@ EXPORT_SYMBOL_GPL(init_preds); static void filter_free_subsystem_preds(struct event_subsystem *system) { - struct event_filter *filter = system->filter; struct ftrace_event_call *call; - int i; - - if (filter->n_preds) { - for (i = 0; i < filter->n_preds; i++) - filter_free_pred(filter->preds[i]); - kfree(filter->preds); - filter->preds = NULL; - filter->n_preds = 0; - } list_for_each_entry(call, &ftrace_events, list) { if (!call->define_fields) @@ -607,26 +597,9 @@ static int filter_add_subsystem_pred(struct filter_parse_state *ps, struct filter_pred *pred, char *filter_string) { - struct event_filter *filter = system->filter; struct ftrace_event_call *call; int err = 0; - if (!filter->preds) { - filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), - GFP_KERNEL); - - if (!filter->preds) - return -ENOMEM; - } - - if (filter->n_preds == MAX_FILTER_PRED) { - parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); - return -ENOSPC; - } - - filter->preds[filter->n_preds] = pred; - filter->n_preds++; - list_for_each_entry(call, &ftrace_events, list) { if (!call->define_fields) @@ -1029,12 +1002,12 @@ static int replace_preds(struct event_subsystem *system, if (elt->op == OP_AND || elt->op == OP_OR) { pred = create_logical_pred(elt->op); - if (call) { + if (call) err = filter_add_pred(ps, call, pred); - filter_free_pred(pred); - } else + else err = filter_add_subsystem_pred(ps, system, pred, filter_string); + filter_free_pred(pred); if (err) return err; @@ -1048,12 +1021,12 @@ static int replace_preds(struct event_subsystem *system, } pred = create_pred(elt->op, operand1, operand2); - if (call) { + if (call) err = filter_add_pred(ps, call, pred); - filter_free_pred(pred); - } else + else err = filter_add_subsystem_pred(ps, system, pred, filter_string); + filter_free_pred(pred); if (err) return err; -- cgit v0.10.2 From dc82ec98a4727fd51b77e92d05fe7d2db3dcc11c Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 9 Jul 2009 16:22:22 +0800 Subject: tracing/filter: Remove empty subsystem and its directory Remove empty subsystem and its directory when module unload. Before patch: # rmmod trace-events-sample.ko # ls sample enable filter After patch: # rmmod trace-events-sample.ko # ls sample ls: cannot access sample: No such file or directory Signed-off-by: Xiao Guangrong Acked-by: Tom Zanussi Reviewed-by: Li Zefan Cc: Frederic Weisbecker Cc: Steven Rostedt LKML-Reference: <4A55A8BE.9010707@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 52eb0d8..94305c7 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -757,6 +757,7 @@ struct event_subsystem { const char *name; struct dentry *entry; void *filter; + int nr_events; }; struct filter_pred; diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index fecac13..90cf936 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -851,8 +851,10 @@ event_subsystem_dir(const char *name, struct dentry *d_events) /* First see if we did not already create this dir */ list_for_each_entry(system, &event_subsystems, list) { - if (strcmp(system->name, name) == 0) + if (strcmp(system->name, name) == 0) { + system->nr_events++; return system->entry; + } } /* need to create new entry */ @@ -871,6 +873,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events) return d_events; } + system->nr_events = 1; system->name = kstrdup(name, GFP_KERNEL); if (!system->name) { debugfs_remove(system->entry); @@ -905,6 +908,32 @@ event_subsystem_dir(const char *name, struct dentry *d_events) return system->entry; } +static void remove_subsystem_dir(const char *name) +{ + struct event_subsystem *system; + + if (strcmp(name, TRACE_SYSTEM) == 0) + return; + + list_for_each_entry(system, &event_subsystems, list) { + if (strcmp(system->name, name) == 0) { + if (!--system->nr_events) { + struct event_filter *filter = system->filter; + + debugfs_remove_recursive(system->entry); + list_del(&system->list); + if (filter) { + kfree(filter->filter_string); + kfree(filter); + } + kfree(system->name); + kfree(system); + } + break; + } + } +} + static int event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, const struct file_operations *id, @@ -1079,6 +1108,7 @@ static void trace_module_remove_events(struct module *mod) list_del(&call->list); trace_destroy_fields(call); destroy_preds(call); + remove_subsystem_dir(call->system); } } -- cgit v0.10.2 From 68baafcfc46074c4bb4e4c3115c2c76a8a85f37d Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 9 Jul 2009 04:46:29 +0200 Subject: tracing/function-graph-tracer: Use the %pf format Remove the obsolete seq_print_ip_sym() usage and replace it by the %pf format in order to print function symbols. Signed-off-by: Frederic Weisbecker Reviewed-by: Li Zefan Cc: Steven Rostedt Cc: Lai Jiangshan LKML-Reference: <1247107590-6428-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index d2249ab..abf7c4a 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -565,11 +565,7 @@ print_graph_entry_leaf(struct trace_iterator *iter, return TRACE_TYPE_PARTIAL_LINE; } - ret = seq_print_ip_sym(s, call->func, 0); - if (!ret) - return TRACE_TYPE_PARTIAL_LINE; - - ret = trace_seq_printf(s, "();\n"); + ret = trace_seq_printf(s, "%pf();\n", (void *)call->func); if (!ret) return TRACE_TYPE_PARTIAL_LINE; @@ -612,11 +608,7 @@ print_graph_entry_nested(struct trace_iterator *iter, return TRACE_TYPE_PARTIAL_LINE; } - ret = seq_print_ip_sym(s, call->func, 0); - if (!ret) - return TRACE_TYPE_PARTIAL_LINE; - - ret = trace_seq_printf(s, "() {\n"); + ret = trace_seq_printf(s, "%pf() {\n", (void *)call->func); if (!ret) return TRACE_TYPE_PARTIAL_LINE; -- cgit v0.10.2 From 6a167c655858cbec4175532fd00417661c87f149 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 9 Jul 2009 04:46:30 +0200 Subject: tracing/kmemtrace: Use the %pf format Remove the obsolete seq_print_ip_sym() usage and replace it by the %pf format in order to print function symbols. Signed-off-by: Frederic Weisbecker Reviewed-by: Li Zefan Cc: Steven Rostedt Cc: Lai Jiangshan Cc: Pekka Enberg Cc: Eduard - Gabriel Munteanu LKML-Reference: <1247107590-6428-3-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/kmemtrace.c b/kernel/trace/kmemtrace.c index 74903b6..2f6fa47 100644 --- a/kernel/trace/kmemtrace.c +++ b/kernel/trace/kmemtrace.c @@ -389,19 +389,12 @@ kmemtrace_print_alloc_compress(struct trace_iterator *iter) if (!ret) return TRACE_TYPE_PARTIAL_LINE; - /* Node */ - ret = trace_seq_printf(s, "%4d ", entry->node); + /* Node and call site*/ + ret = trace_seq_printf(s, "%4d %pf\n", entry->node, + (void *)entry->call_site); if (!ret) return TRACE_TYPE_PARTIAL_LINE; - /* Call site */ - ret = seq_print_ip_sym(s, entry->call_site, 0); - if (!ret) - return TRACE_TYPE_PARTIAL_LINE; - - if (!trace_seq_printf(s, "\n")) - return TRACE_TYPE_PARTIAL_LINE; - return TRACE_TYPE_HANDLED; } @@ -447,19 +440,11 @@ kmemtrace_print_free_compress(struct trace_iterator *iter) if (!ret) return TRACE_TYPE_PARTIAL_LINE; - /* Skip node */ - ret = trace_seq_printf(s, " "); + /* Skip node and print call site*/ + ret = trace_seq_printf(s, " %pf\n", (void *)entry->call_site); if (!ret) return TRACE_TYPE_PARTIAL_LINE; - /* Call site */ - ret = seq_print_ip_sym(s, entry->call_site, 0); - if (!ret) - return TRACE_TYPE_PARTIAL_LINE; - - if (!trace_seq_printf(s, "\n")) - return TRACE_TYPE_PARTIAL_LINE; - return TRACE_TYPE_HANDLED; } -- cgit v0.10.2 From 80098c200e2ee3b4c86a9d1e156dbcd05380e08f Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 6 Jul 2009 16:15:04 +0800 Subject: kmemtrace: Rename some functions So we have: - kmemtrace_print_alloc/free() for kmemtrace default output - kmemtrace_print_alloc/free_user() for binary output used by kmemtrace-user. Suggested-by: Eduard - Gabriel Munteanu Signed-off-by: Li Zefan Acked-by: Pekka Enberg Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4A51B288.70505@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/kmemtrace.c b/kernel/trace/kmemtrace.c index 2f6fa47..dda53cc 100644 --- a/kernel/trace/kmemtrace.c +++ b/kernel/trace/kmemtrace.c @@ -239,7 +239,7 @@ struct kmemtrace_user_event_alloc { }; static enum print_line_t -kmemtrace_print_alloc_user(struct trace_iterator *iter, int flags) +kmemtrace_print_alloc(struct trace_iterator *iter, int flags) { struct trace_seq *s = &iter->seq; struct kmemtrace_alloc_entry *entry; @@ -259,7 +259,7 @@ kmemtrace_print_alloc_user(struct trace_iterator *iter, int flags) } static enum print_line_t -kmemtrace_print_free_user(struct trace_iterator *iter, int flags) +kmemtrace_print_free(struct trace_iterator *iter, int flags) { struct trace_seq *s = &iter->seq; struct kmemtrace_free_entry *entry; @@ -277,7 +277,7 @@ kmemtrace_print_free_user(struct trace_iterator *iter, int flags) } static enum print_line_t -kmemtrace_print_alloc_user_bin(struct trace_iterator *iter, int flags) +kmemtrace_print_alloc_user(struct trace_iterator *iter, int flags) { struct trace_seq *s = &iter->seq; struct kmemtrace_alloc_entry *entry; @@ -311,7 +311,7 @@ kmemtrace_print_alloc_user_bin(struct trace_iterator *iter, int flags) } static enum print_line_t -kmemtrace_print_free_user_bin(struct trace_iterator *iter, int flags) +kmemtrace_print_free_user(struct trace_iterator *iter, int flags) { struct trace_seq *s = &iter->seq; struct kmemtrace_free_entry *entry; @@ -467,14 +467,14 @@ static enum print_line_t kmemtrace_print_line(struct trace_iterator *iter) static struct trace_event kmem_trace_alloc = { .type = TRACE_KMEM_ALLOC, - .trace = kmemtrace_print_alloc_user, - .binary = kmemtrace_print_alloc_user_bin, + .trace = kmemtrace_print_alloc, + .binary = kmemtrace_print_alloc_user, }; static struct trace_event kmem_trace_free = { .type = TRACE_KMEM_FREE, - .trace = kmemtrace_print_free_user, - .binary = kmemtrace_print_free_user_bin, + .trace = kmemtrace_print_free, + .binary = kmemtrace_print_free_user, }; static struct tracer kmem_tracer __read_mostly = { -- cgit v0.10.2 From d8ea37d5de58d35a39d0b4e7d209751aaa1b8174 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Mon, 6 Jul 2009 16:10:18 +0800 Subject: tracing/stat: Add stat_release() callback Add stat_release() callback to struct tracer_stat, so a stat tracer can release it's entries after the stat file has been read out. Signed-off-by: Lai Jiangshan Signed-off-by: Li Zefan Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4A51B16A.6020708@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c index e66f5e4..f069461 100644 --- a/kernel/trace/trace_stat.c +++ b/kernel/trace/trace_stat.c @@ -49,7 +49,8 @@ static struct dentry *stat_dir; * but it will at least advance closer to the next one * to be released. */ -static struct rb_node *release_next(struct rb_node *node) +static struct rb_node *release_next(struct tracer_stat *ts, + struct rb_node *node) { struct stat_node *snode; struct rb_node *parent = rb_parent(node); @@ -67,6 +68,8 @@ static struct rb_node *release_next(struct rb_node *node) parent->rb_right = NULL; snode = container_of(node, struct stat_node, node); + if (ts->stat_release) + ts->stat_release(snode->stat); kfree(snode); return parent; @@ -78,7 +81,7 @@ static void reset_stat_session(struct stat_session *session) struct rb_node *node = session->stat_root.rb_node; while (node) - node = release_next(node); + node = release_next(session->ts, node); session->stat_root = RB_ROOT; } diff --git a/kernel/trace/trace_stat.h b/kernel/trace/trace_stat.h index f3546a2..8f03914 100644 --- a/kernel/trace/trace_stat.h +++ b/kernel/trace/trace_stat.h @@ -18,6 +18,8 @@ struct tracer_stat { int (*stat_cmp)(void *p1, void *p2); /* Print a stat entry */ int (*stat_show)(struct seq_file *s, void *p); + /* Release an entry */ + void (*stat_release)(void *stat); /* Print the headers of your stat entries */ int (*stat_headers)(struct seq_file *s); }; -- cgit v0.10.2 From a35780005eb256eb5ec83ffcc802967295887a45 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Mon, 6 Jul 2009 16:10:23 +0800 Subject: tracing/workqueues: Add refcnt to struct cpu_workqueue_stats The stat entries can be freed when the stat file is being read. The worse is, the ptr can be freed immediately after it's returned from workqueue_stat_start/next(). Add a refcnt to struct cpu_workqueue_stats to avoid use-after-free. Signed-off-by: Lai Jiangshan Signed-off-by: Li Zefan Acked-by: Frederic Weisbecker Cc: Steven Rostedt LKML-Reference: <4A51B16F.6010608@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace_workqueue.c b/kernel/trace/trace_workqueue.c index 97fcea4..40cafb0 100644 --- a/kernel/trace/trace_workqueue.c +++ b/kernel/trace/trace_workqueue.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "trace_stat.h" #include "trace.h" @@ -16,6 +17,7 @@ /* A cpu workqueue thread */ struct cpu_workqueue_stats { struct list_head list; + struct kref kref; int cpu; pid_t pid; /* Can be inserted from interrupt or user context, need to be atomic */ @@ -39,6 +41,11 @@ struct workqueue_global_stats { static DEFINE_PER_CPU(struct workqueue_global_stats, all_workqueue_stat); #define workqueue_cpu_stat(cpu) (&per_cpu(all_workqueue_stat, cpu)) +static void cpu_workqueue_stat_free(struct kref *kref) +{ + kfree(container_of(kref, struct cpu_workqueue_stats, kref)); +} + /* Insertion of a work */ static void probe_workqueue_insertion(struct task_struct *wq_thread, @@ -96,8 +103,8 @@ static void probe_workqueue_creation(struct task_struct *wq_thread, int cpu) return; } INIT_LIST_HEAD(&cws->list); + kref_init(&cws->kref); cws->cpu = cpu; - cws->pid = wq_thread->pid; spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags); @@ -118,7 +125,7 @@ static void probe_workqueue_destruction(struct task_struct *wq_thread) list) { if (node->pid == wq_thread->pid) { list_del(&node->list); - kfree(node); + kref_put(&node->kref, cpu_workqueue_stat_free); goto found; } } @@ -137,9 +144,11 @@ static struct cpu_workqueue_stats *workqueue_stat_start_cpu(int cpu) spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags); - if (!list_empty(&workqueue_cpu_stat(cpu)->list)) + if (!list_empty(&workqueue_cpu_stat(cpu)->list)) { ret = list_entry(workqueue_cpu_stat(cpu)->list.next, struct cpu_workqueue_stats, list); + kref_get(&ret->kref); + } spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags); @@ -162,9 +171,9 @@ static void *workqueue_stat_start(struct tracer_stat *trace) static void *workqueue_stat_next(void *prev, int idx) { struct cpu_workqueue_stats *prev_cws = prev; + struct cpu_workqueue_stats *ret; int cpu = prev_cws->cpu; unsigned long flags; - void *ret = NULL; spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags); if (list_is_last(&prev_cws->list, &workqueue_cpu_stat(cpu)->list)) { @@ -175,11 +184,14 @@ static void *workqueue_stat_next(void *prev, int idx) return NULL; } while (!(ret = workqueue_stat_start_cpu(cpu))); return ret; + } else { + ret = list_entry(prev_cws->list.next, + struct cpu_workqueue_stats, list); + kref_get(&ret->kref); } spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags); - return list_entry(prev_cws->list.next, struct cpu_workqueue_stats, - list); + return ret; } static int workqueue_stat_show(struct seq_file *s, void *p) @@ -203,6 +215,13 @@ static int workqueue_stat_show(struct seq_file *s, void *p) return 0; } +static void workqueue_stat_release(void *stat) +{ + struct cpu_workqueue_stats *node = stat; + + kref_put(&node->kref, cpu_workqueue_stat_free); +} + static int workqueue_stat_headers(struct seq_file *s) { seq_printf(s, "# CPU INSERTED EXECUTED NAME\n"); @@ -215,6 +234,7 @@ struct tracer_stat workqueue_stats __read_mostly = { .stat_start = workqueue_stat_start, .stat_next = workqueue_stat_next, .stat_show = workqueue_stat_show, + .stat_release = workqueue_stat_release, .stat_headers = workqueue_stat_headers }; -- cgit v0.10.2 From 8259cf4342029aad37660e524178c8858f48b0ab Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Thu, 9 Jul 2009 13:08:37 -0400 Subject: printk: Ensure that "console enabled" messages are printed on the console Today, when a console is registered without CON_PRINTBUFFER, end users never see the announcement of it being added, and never know if they missed something, if the console is really at the start or not, and just leads to general confusion. This re-orders existing code, to make sure the console is added, before the "console [%s%d] enabled" is printed out - ensuring that this message is _always_ seen. This has the desired/intended side effect of making sure that "console enabled:" messages are printed on the bootconsole, and the real console. This does cause the same line is printed twice if the bootconsole and real console are the same device, but if they are on different devices, the message is printed to both consoles. Signed-off-by : Robin Getz Cc: "Andrew Morton" Cc: "Linus Torvalds" LKML-Reference: <200907091308.37370.rgetz@blackfin.uclinux.org> Signed-off-by: Ingo Molnar diff --git a/kernel/printk.c b/kernel/printk.c index 41fe609..668df35 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -1240,22 +1240,14 @@ void register_console(struct console *newcon) if (!(newcon->flags & CON_ENABLED)) return; - if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) { - /* we need to iterate through twice, to make sure we print - * everything out, before we unregister the console(s) - */ - printk(KERN_INFO "console handover:"); - for_each_console(bcon) - printk("boot [%s%d] ", bcon->name, bcon->index); - printk(" -> real [%s%d]\n", newcon->name, newcon->index); - for_each_console(bcon) - unregister_console(bcon); + /* + * If we have a bootconsole, and are switching to a real console, + * don't print everything out again, since when the boot console, and + * the real console are the same physical device, it's annoying to + * see the beginning boot messages twice + */ + if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) newcon->flags &= ~CON_PRINTBUFFER; - } else { - printk(KERN_INFO "%sconsole [%s%d] enabled\n", - (newcon->flags & CON_BOOT) ? "boot" : "" , - newcon->name, newcon->index); - } /* * Put this console in the list - keep the @@ -1281,6 +1273,28 @@ void register_console(struct console *newcon) spin_unlock_irqrestore(&logbuf_lock, flags); } release_console_sem(); + + /* + * By unregistering the bootconsoles after we enable the real console + * we get the "console xxx enabled" message on all the consoles - + * boot consoles, real consoles, etc - this is to ensure that end + * users know there might be something in the kernel's log buffer that + * went to the bootconsole (that they do not see on the real console) + */ + if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) { + /* we need to iterate through twice, to make sure we print + * everything out, before we unregister the console(s) + */ + printk(KERN_INFO "console [%s%d] enabled, bootconsole disabled\n", + newcon->name, newcon->index); + for_each_console(bcon) + if (bcon->flags & CON_BOOT) + unregister_console(bcon); + } else { + printk(KERN_INFO "%sconsole [%s%d] enabled\n", + (newcon->flags & CON_BOOT) ? "boot" : "" , + newcon->name, newcon->index); + } } EXPORT_SYMBOL(register_console); -- cgit v0.10.2 From 31909b83ea5b4035ce129bb0df622ec2d2fb3e96 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jul 2009 12:33:48 +0200 Subject: ALSA: hda - Fix the merge error Fix the merge error at the commit 305355aad89f1b7eb27cb210fad2f9d3c67b2572, an addition of the missing alc880_gpio3_init_verbs to ALC882_TARGA model. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 88a9da4..7967f8f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8587,7 +8587,7 @@ static struct alc_config_preset alc882_presets[] = { [ALC882_TARGA] = { .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, - alc882_targa_verbs}, + alc880_gpio3_init_verbs, alc882_targa_verbs}, .num_dacs = ARRAY_SIZE(alc882_dac_nids), .dac_nids = alc882_dac_nids, .dig_out_nid = ALC882_DIGOUT_NID, -- cgit v0.10.2 From 3c6aae4489e7c05f3685e9eaa538249be7c79ebe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jul 2009 12:52:27 +0200 Subject: ALSA: hda - Check codec errors in snd_hda_get_connections() The codec read errors in snd_hda_get_connections() are ignored so far, and it causes a problem like the bug in the commit 9d30937accf2c01e8b0bd59787409a7348cbbcb7 ALSA: hda_intel: more strict alc880_parse_auto_config dig_nid checking Better to check errors in the function and returns a proper error code rather than passing bogus NID values. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 94d848e..ec352c6 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -316,6 +316,8 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, /* single connection */ parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, 0); + if (parm == -1 && codec->bus->rirb_error) + return -EIO; conn_list[0] = parm & mask; return 1; } @@ -327,9 +329,12 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, int range_val; hda_nid_t val, n; - if (i % num_elems == 0) + if (i % num_elems == 0) { parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, i); + if (parm == -1 && codec->bus->rirb_error) + return -EIO; + } range_val = !!(parm & (1 << (shift-1))); /* ranges */ val = parm & mask; parm >>= shift; -- cgit v0.10.2 From 9ff80942992cd5abd0779c815f310f65b7b83860 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 8 Jul 2009 22:03:53 +0400 Subject: x86: Clean up idt_descr and idt_tableby using NR_VECTORS instead of hardcoded number Signed-off-by: Cyrill Gorcunov Cc: Yinghai Lu LKML-Reference: <20090708180353.GH5301@lenovo> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index f1961c0..d6f27c9 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -982,7 +982,7 @@ static __init int setup_disablecpuid(char *arg) __setup("clearcpuid=", setup_disablecpuid); #ifdef CONFIG_X86_64 -struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; +struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table }; DEFINE_PER_CPU_FIRST(union irq_stack_union, irq_stack_union) __aligned(PAGE_SIZE); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 5204332..7e4b1f5 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -76,7 +76,7 @@ char ignore_fpu_irq; * F0 0F bug workaround.. We have a special link segment * for this. */ -gate_desc idt_table[256] +gate_desc idt_table[NR_VECTORS] __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; #endif -- cgit v0.10.2 From a1b4f1a5b7f57be2593a9f1fca465a529c95fc07 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sun, 5 Jul 2009 20:01:54 +0400 Subject: x86, ipi: Clean up safe_smp_processor_id() by using the cpu_has_apic() macro helper We already use a lot of cpu_has_ helpers. Lets do here the same for consistency. Signed-off-by: Cyrill Gorcunov Cc: Yinghai Lu LKML-Reference: <20090705160154.GB4791@lenovo> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/ipi.c b/arch/x86/kernel/apic/ipi.c index dbf5445..e6b4f51 100644 --- a/arch/x86/kernel/apic/ipi.c +++ b/arch/x86/kernel/apic/ipi.c @@ -150,7 +150,7 @@ int safe_smp_processor_id(void) { int apicid, cpuid; - if (!boot_cpu_has(X86_FEATURE_APIC)) + if (!cpu_has_apic) return 0; apicid = hard_smp_processor_id(); -- cgit v0.10.2 From 1aaad49e856ce41adc07d8ae0c8ef35fc4483245 Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Mon, 6 Jul 2009 13:31:48 +0200 Subject: printk: Restore previous console_loglevel when re-enabling logging When logging to console is disabled from userspace using klogctl() and later re-enabled, console_loglevel gets set to the default log level instead to the previous value. This means that if the kernel was booted with 'quiet', the boot is suddenly no longer quiet after logging to console gets re-enabled. Save the current console_loglevel when logging is disabled and restore to that value. If the log level is set to a specific value while disabled, this is interpreted as an implicit re-enabling of the logging. The problem that prompted this patch is described in: http://lkml.org/lkml/2009/6/28/234 There are two variations possible on the patch below: 1) If klogctl(7) is called while logging is not disabled, then set level to default (partially preserving current functionality): case 7: /* Enable logging to console */ - console_loglevel = default_console_loglevel; + if (saved_console_loglevel == -1) + console_loglevel = default_console_loglevel; + else { + console_loglevel = saved_console_loglevel; + saved_console_loglevel = -1; + } 2) If klogctl(8) is called while logging is disabled, then don't enable logging, but remember the requested value for when logging does get enabled again: case 8: /* Set level of messages printed to console */ [...] - console_loglevel = len; + if (saved_console_loglevel == -1) + console_loglevel = len; + else + saved_console_loglevel = len; Yet another option would be to ignore the request. Signed-off-by: Frans Pop Cc: cryptsetup@packages.debian.org Cc: Andrew Morton Cc: Linus Torvalds LKML-Reference: <200907061331.49930.elendil@planet.nl> Signed-off-by: Ingo Molnar diff --git a/kernel/printk.c b/kernel/printk.c index 668df35..e0daaf5 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -67,6 +67,8 @@ int console_printk[4] = { DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ }; +static int saved_console_loglevel = -1; + /* * Low level drivers may need that to know if they can schedule in * their unblank() callback or not. So let's export it. @@ -378,10 +380,15 @@ int do_syslog(int type, char __user *buf, int len) logged_chars = 0; break; case 6: /* Disable logging to console */ + if (saved_console_loglevel == -1) + saved_console_loglevel = console_loglevel; console_loglevel = minimum_console_loglevel; break; case 7: /* Enable logging to console */ - console_loglevel = default_console_loglevel; + if (saved_console_loglevel != -1) { + console_loglevel = saved_console_loglevel; + saved_console_loglevel = -1; + } break; case 8: /* Set level of messages printed to console */ error = -EINVAL; @@ -390,6 +397,8 @@ int do_syslog(int type, char __user *buf, int len) if (len < minimum_console_loglevel) len = minimum_console_loglevel; console_loglevel = len; + /* Implicitly re-enable logging to console */ + saved_console_loglevel = -1; error = 0; break; case 9: /* Number of chars in the log buffer */ -- cgit v0.10.2 From e36d56b64808aec54b68b4e9976180c1da0933b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Jun 2009 21:04:43 +0200 Subject: cfg80211: pass netdev to change_virtual_intf If there was a reason I'm passing the ifidx I cannot remember it any more and don't see one now, so let's just pass the pointer itself. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 96f714e..bc89b1e 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -167,20 +167,15 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) return 0; } -static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex, +static int iwm_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct net_device *ndev; struct wireless_dev *wdev; struct iwm_priv *iwm; u32 old_mode; - /* we're under RTNL */ - ndev = __dev_get_by_index(&init_net, ifindex); - if (!ndev) - return -ENODEV; - wdev = ndev->ieee80211_ptr; iwm = ndev_to_iwm(ndev); old_mode = iwm->conf.mode; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 3bec3db..e8b0793 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -420,7 +420,8 @@ struct rndis_wlan_private { /* * cfg80211 ops */ -static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, +static int rndis_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, enum nl80211_iftype type, u32 *flags, struct vif_params *params); @@ -1222,20 +1223,14 @@ static void set_multicast_list(struct usbnet *usbdev) /* * cfg80211 ops */ -static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, +static int rndis_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct net_device *dev; - struct usbnet *usbdev; + struct usbnet *usbdev = netdev_priv(dev); int mode; - /* we're under RTNL */ - dev = __dev_get_by_index(&init_net, ifindex); - if (!dev) - return -ENODEV; - usbdev = netdev_priv(dev); - switch (type) { case NL80211_IFTYPE_ADHOC: mode = NDIS_80211_INFRA_ADHOC; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1a21895..90f9bfa 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -866,7 +866,8 @@ struct cfg80211_ops { enum nl80211_iftype type, u32 *flags, struct vif_params *params); int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); - int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex, + int (*change_virtual_intf)(struct wiphy *wiphy, + struct net_device *dev, enum nl80211_iftype type, u32 *flags, struct vif_params *params); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3f47276..eb93eb6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -74,19 +74,14 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) return 0; } -static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, +static int ieee80211_change_iface(struct wiphy *wiphy, + struct net_device *dev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct net_device *dev; struct ieee80211_sub_if_data *sdata; int ret; - /* we're under RTNL */ - dev = __dev_get_by_index(&init_net, ifindex); - if (!dev) - return -ENODEV; - if (!nl80211_type_check(type)) return -EINVAL; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 43bdb13..f91e5d4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -767,7 +767,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; struct vif_params params; - int err, ifindex; + int err; enum nl80211_iftype otype, ntype; struct net_device *dev; u32 _flags, *flags = NULL; @@ -781,9 +781,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) if (err) goto unlock_rtnl; - ifindex = dev->ifindex; otype = ntype = dev->ieee80211_ptr->iftype; - dev_put(dev); if (info->attrs[NL80211_ATTR_IFTYPE]) { ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); @@ -826,20 +824,20 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } if (change) - err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, + err = drv->ops->change_virtual_intf(&drv->wiphy, dev, ntype, flags, ¶ms); else err = 0; - dev = __dev_get_by_index(&init_net, ifindex); - WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != ntype)); + WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); - if (dev && !err && (ntype != otype)) { + if (!err && (ntype != otype)) { if (otype == NL80211_IFTYPE_ADHOC) cfg80211_clear_ibss(dev, false); } unlock: + dev_put(dev); cfg80211_put_dev(drv); unlock_rtnl: rtnl_unlock(); diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index d030c53..9e56f35 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -103,7 +103,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, memset(&vifparams, 0, sizeof(vifparams)); - ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type, + ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev, type, NULL, &vifparams); WARN_ON(!ret && wdev->iftype != type); -- cgit v0.10.2 From 089e698d235162324142063c96780aeacd546d36 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Jun 2009 17:50:07 +0530 Subject: ath9k: Nuke unneccesary helper function to see if aggr is active IEEE80211_TX_CTL_AMPDU in tx control flags should be enough to confirm BA is negotiated for that tid. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 4ccf48e..aca3526 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -73,18 +73,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, /* Aggregation logic */ /*********************/ -static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) -{ - struct ath_atx_tid *tid; - tid = ATH_AN_2_TID(an, tidno); - - if (tid->state & AGGR_ADDBA_COMPLETE || - tid->state & AGGR_ADDBA_PROGRESS) - return 1; - else - return 0; -} - static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) { struct ath_atx_ac *ac = tid->ac; @@ -1636,7 +1624,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, goto tx_done; } - if (ath_aggr_query(sc, an, bf->bf_tidno)) { + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { /* * Try aggregation if it's a unicast data frame * and the destination is HT capable. -- cgit v0.10.2 From c3d8f02ed9699252d69a9a14276980d9df7c5fe1 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Jun 2009 17:50:08 +0530 Subject: ath9k: Remove unnecessary count for addba attempt mac80211 already has one to keep track of number of failure addba attempts. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 5efc934..747e046 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -272,7 +272,6 @@ struct ath_atx_tid { int sched; int paused; u8 state; - int addba_exchangeattempts; }; struct ath_atx_ac { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index aca3526..e08c817 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -402,7 +402,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (tid->state & AGGR_CLEANUP) { if (tid->baw_head == tid->baw_tail) { tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->addba_exchangeattempts = 0; tid->state &= ~AGGR_CLEANUP; /* send buffered frames as singles */ @@ -707,7 +706,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { txtid->state &= ~AGGR_ADDBA_PROGRESS; - txtid->addba_exchangeattempts = 0; return 0; } @@ -735,7 +733,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) txtid->state |= AGGR_CLEANUP; } else { txtid->state &= ~AGGR_ADDBA_COMPLETE; - txtid->addba_exchangeattempts = 0; ath_tx_flush_tid(sc, txtid); } @@ -768,14 +765,8 @@ bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) txtid = ATH_AN_2_TID(an, tidno); - if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { - if (!(txtid->state & AGGR_ADDBA_PROGRESS) && - (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) { - txtid->addba_exchangeattempts++; + if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS))) return true; - } - } - return false; } @@ -2110,7 +2101,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->ac = &an->ac[acno]; tid->state &= ~AGGR_ADDBA_COMPLETE; tid->state &= ~AGGR_ADDBA_PROGRESS; - tid->addba_exchangeattempts = 0; } for (acno = 0, ac = &an->ac[acno]; @@ -2167,7 +2157,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) tid->sched = false; ath_tid_drain(sc, txq, tid); tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->addba_exchangeattempts = 0; tid->state &= ~AGGR_CLEANUP; } } -- cgit v0.10.2 From 8a46097a6c60dc9d2f09bf01734f3308142614b3 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Jun 2009 17:50:09 +0530 Subject: ath9k: downgrade ASSERT() in ath_clone_txbuf() We can easily run out of tx buf if there is any stuck in transmission, so downgrade it to WARN_ON(). Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index e08c817..5de9878 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -238,6 +238,10 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) struct ath_buf *tbf; spin_lock_bh(&sc->tx.txbuflock); + if (WARN_ON(list_empty(&sc->tx.txbuf))) { + spin_unlock_bh(&sc->tx.txbuflock); + return NULL; + } ASSERT(!list_empty((&sc->tx.txbuf))); tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); list_del(&tbf->list); @@ -379,6 +383,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *tbf; tbf = ath_clone_txbuf(sc, bf_last); + if (!tbf) + break; ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc); list_add_tail(&tbf->list, &bf_head); } else { -- cgit v0.10.2 From 46026e8f487c075f9ec4d671348e351eb5e46d3e Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 10 Jun 2009 22:22:20 -0400 Subject: ath5k: cleanup ath5k_hw struct ah_gpios array isn't used, and ah_current_channel can be a pointer instead of an embedded struct. Removing these and some other write-only variables, and moving some things around for better packing and cache utilization saves 116 bytes. text data bss dec hex filename 121762 472 64 122298 1ddba ath5k_before.ko 121646 472 64 122182 1dd46 ath5k.ko Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 6358233..9137511 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -713,8 +713,8 @@ struct ath5k_gain { * Used internaly for reset_tx_queue). * Also see struct struct ieee80211_channel. */ -#define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0) -#define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0) +#define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0) +#define IS_CHAN_B(_c) ((_c->hw_value & CHANNEL_B) != 0) /* * The following structure is used to map 2GHz channels to @@ -1029,14 +1029,15 @@ struct ath5k_hw { enum ath5k_int ah_imr; enum nl80211_iftype ah_op_mode; - enum ath5k_power_mode ah_power_mode; - struct ieee80211_channel ah_current_channel; + struct ieee80211_channel *ah_current_channel; bool ah_turbo; bool ah_calibration; - bool ah_running; bool ah_single_chip; bool ah_combined_mic; + enum ath5k_version ah_version; + enum ath5k_radio ah_radio; + u32 ah_phy; u32 ah_mac_srev; u16 ah_mac_version; u16 ah_mac_revision; @@ -1044,13 +1045,6 @@ struct ath5k_hw { u16 ah_radio_5ghz_revision; u16 ah_radio_2ghz_revision; - enum ath5k_version ah_version; - enum ath5k_radio ah_radio; - u32 ah_phy; - - bool ah_5ghz; - bool ah_2ghz; - #define ah_modes ah_capabilities.cap_mode #define ah_ee_version ah_capabilities.cap_eeprom.ee_version @@ -1058,7 +1052,6 @@ struct ath5k_hw { u32 ah_aifs; u32 ah_cw_min; u32 ah_cw_max; - bool ah_software_retry; u32 ah_limit_tx_retries; /* Antenna Control */ @@ -1066,6 +1059,7 @@ struct ath5k_hw { u8 ah_ant_mode; u8 ah_tx_ant; u8 ah_def_ant; + bool ah_software_retry; u8 ah_sta_id[ETH_ALEN]; @@ -1075,7 +1069,6 @@ struct ath5k_hw { u8 ah_bssid[ETH_ALEN]; u8 ah_bssid_mask[ETH_ALEN]; - u32 ah_gpio[AR5K_MAX_GPIO]; int ah_gpio_npins; struct ath_regulatory ah_regulatory; diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index a876ca8..2075ba9 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1085,8 +1085,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) AR5K_PHY_CCKTXCTL_WORLD); } - ah->ah_current_channel.center_freq = channel->center_freq; - ah->ah_current_channel.hw_value = channel->hw_value; + ah->ah_current_channel = channel; ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false; return 0; @@ -1731,7 +1730,7 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable) void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) { - struct ieee80211_channel *channel = &ah->ah_current_channel; + struct ieee80211_channel *channel = ah->ah_current_channel; bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div; bool use_def_for_sg; u8 def_ant, tx_ant, ee_mode; @@ -3011,7 +3010,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) { /*Just a try M.F.*/ - struct ieee80211_channel *channel = &ah->ah_current_channel; + struct ieee80211_channel *channel = ah->ah_current_channel; u8 ee_mode; ATH5K_TRACE(ah->ah_sc); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index bd0a97a..86733fd 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -290,7 +290,6 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, } commit: - ah->ah_power_mode = mode; ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1); return 0; -- cgit v0.10.2 From f0f3d388baabdbc613548d6ad8e5da7616b1cbd1 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 10 Jun 2009 22:22:21 -0400 Subject: ath5k: enable hardware LEDs Cardbus and some PCI cards use hardware LEDs rather than software GPIOs. Program them with the proper blink patterns when idle, scanning or associated. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=13288. Tested-by: Frans Pop Tested-by: Mark Hindley Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index c41ef58..9a84d94 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -319,6 +319,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) ath5k_hw_rfgain_opt_init(ah); + /* turn on HW LEDs */ + ath5k_hw_set_ledstate(ah, AR5K_LED_INIT); + return ah; err_free: kfree(ah); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index ea04515..f26a689 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -248,6 +248,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); +static void ath5k_sw_scan_start(struct ieee80211_hw *hw); +static void ath5k_sw_scan_complete(struct ieee80211_hw *hw); static const struct ieee80211_ops ath5k_hw_ops = { .tx = ath5k_tx, @@ -265,6 +267,8 @@ static const struct ieee80211_ops ath5k_hw_ops = { .set_tsf = ath5k_set_tsf, .reset_tsf = ath5k_reset_tsf, .bss_info_changed = ath5k_bss_info_changed, + .sw_scan_start = ath5k_sw_scan_start, + .sw_scan_complete = ath5k_sw_scan_complete, }; /* @@ -3167,6 +3171,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, sc->assoc = bss_conf->assoc; if (sc->opmode == NL80211_IFTYPE_STATION) set_beacon_filter(hw, sc->assoc); + ath5k_hw_set_ledstate(sc->ah, sc->assoc ? + AR5K_LED_ASSOC : AR5K_LED_INIT); } if (changes & BSS_CHANGED_BEACON && @@ -3179,3 +3185,17 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, unlock: mutex_unlock(&sc->lock); } + +static void ath5k_sw_scan_start(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + if (!sc->assoc) + ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN); +} + +static void ath5k_sw_scan_complete(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + ath5k_hw_set_ledstate(sc->ah, sc->assoc ? + AR5K_LED_ASSOC : AR5K_LED_INIT); +} -- cgit v0.10.2 From e0d6133cba88759bc760b254c27975330fff6519 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Tue, 16 Jun 2009 13:20:01 -0700 Subject: libertas: remove ps_supported flag, use fwcapinfo Power save support depends on the firmware capabilities rather than the card's hardware interface. Use the FW_CAPINFO_PS bit in the firmware capabilities mask throughout the driver in place of the redundant ps_supported flag and don't make decisions about PS support in the interface drivers (with the exception of a special case in the USB driver). V2: put the USB special case in the right place. Signed-off-by: Andrey Yurovsky Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f9ec69e..578c697 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -260,7 +260,6 @@ struct lbs_private { u16 psmode; /* Wlan802_11PowermodeCAM=disable Wlan802_11PowermodeMAX_PSP=enable */ u32 psstate; - char ps_supported; u8 needtowakeup; struct assoc_request * pending_assoc_req; diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 2a5b083..f658fd6 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -933,9 +933,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out3; } - /* The firmware for the CF card supports powersave */ - priv->ps_supported = 1; - ret = 0; goto out; diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 8cdb88c..89396a7 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -1039,9 +1039,6 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) goto err_activate_card; - if (priv->fwcapinfo & FW_CAPINFO_PS) - priv->ps_supported = 1; - out: lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 6564282..b213de4 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -1118,7 +1118,6 @@ static int __devinit if_spi_probe(struct spi_device *spi) priv->card = card; priv->hw_host_to_card = if_spi_host_to_card; priv->fw_ready = 1; - priv->ps_supported = 1; /* Initialize interrupt handling stuff. */ card->run_thread = 1; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 1844c5a..92bc8c5 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -181,13 +181,14 @@ static void if_usb_setup_firmware(struct lbs_private *priv) wake_method.action = cpu_to_le16(CMD_ACT_GET); if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) { lbs_pr_info("Firmware does not seem to support PS mode\n"); + priv->fwcapinfo &= ~FW_CAPINFO_PS; } else { if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) { lbs_deb_usb("Firmware seems to support PS with wake-via-command\n"); - priv->ps_supported = 1; } else { /* The versions which boot up this way don't seem to work even if we set it to the command interrupt */ + priv->fwcapinfo &= ~FW_CAPINFO_PS; lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n"); } } diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 8bc19074..e96451c 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -712,7 +712,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!priv->ps_supported) { + if (!(priv->fwcapinfo & FW_CAPINFO_PS)) { if (vwrq->disabled) return 0; else -- cgit v0.10.2 From c4f9f16b309b65f9f578ec4ba78b3efa106cf65d Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 12 Jun 2009 10:55:55 +0530 Subject: ath9k: Make sure we configure a non-zero beacon interval This patch moves the sanity check on beacon interval which was done only for mesh mode to all operating modes just to be safe. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 3639a2e..45c4ea5 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -674,13 +674,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; - /* - * It looks like mac80211 may end up using beacon interval of zero in - * some cases (at least for mesh point). Avoid getting into an - * infinite loop by using a bit safer value instead.. - */ - if (intval == 0) - intval = 100; /* Pull nexttbtt forward to reflect the current TSF */ @@ -745,6 +738,14 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) iftype = sc->sc_ah->opmode; } + /* + * It looks like mac80211 may end up using beacon interval of zero in + * some cases (at least for mesh point). Avoid getting into an + * infinite loop by using a bit safer value instead. To be safe, + * do sanity check on beacon interval for all operating modes. + */ + if (cur_conf->beacon_interval == 0) + cur_conf->beacon_interval = 100; switch (iftype) { case NL80211_IFTYPE_AP: -- cgit v0.10.2 From ff25839bf0c99e828c26864a24417a36a6b6a31e Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:19 +0300 Subject: wl12xx: cmd and acx interface rework Rework cmd and acx interfaces, it was just too confusing earlier. Now all commands need to contain all the needed headers, either just cmd headers or both cmd and acx headers. This accomplish to remove the extra copy done for each command. The interfaces are now properly documented as well. Also try to make all commands safe for DMA transfers. I might have missed some, but most of them should be fixed now. And this is not all! As a free bonus you will also get some cosmetic cleanups and code reorganisation. Order today! Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 1cfd458..d0daf69 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -13,126 +13,160 @@ int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, u8 mgt_rate, u8 mgt_mod) { + struct acx_fw_gen_frame_rates *rates; int ret; - struct acx_fw_gen_frame_rates rates; wl12xx_debug(DEBUG_ACX, "acx frame rates"); - rates.header.id = ACX_FW_GEN_FRAME_RATES; - rates.header.len = sizeof(struct acx_fw_gen_frame_rates) - - sizeof(struct acx_header); + rates = kzalloc(sizeof(*rates), GFP_KERNEL); + if (!rates) { + ret = -ENOMEM; + goto out; + } - rates.tx_ctrl_frame_rate = ctrl_rate; - rates.tx_ctrl_frame_mod = ctrl_mod; - rates.tx_mgt_frame_rate = mgt_rate; - rates.tx_mgt_frame_mod = mgt_mod; + rates->tx_ctrl_frame_rate = ctrl_rate; + rates->tx_ctrl_frame_mod = ctrl_mod; + rates->tx_mgt_frame_rate = mgt_rate; + rates->tx_mgt_frame_mod = mgt_mod; - ret = wl12xx_cmd_configure(wl, &rates, sizeof(rates)); + ret = wl12xx_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, + rates, sizeof(*rates)); if (ret < 0) { wl12xx_error("Failed to set FW rates and modulation"); - return ret; + goto out; } - return 0; +out: + kfree(rates); + return ret; } int wl12xx_acx_station_id(struct wl12xx *wl) { + struct acx_dot11_station_id *mac; int ret, i; - struct dot11_station_id mac; wl12xx_debug(DEBUG_ACX, "acx dot11_station_id"); - mac.header.id = DOT11_STATION_ID; - mac.header.len = sizeof(mac) - sizeof(struct acx_header); + mac = kzalloc(sizeof(*mac), GFP_KERNEL); + if (!mac) { + ret = -ENOMEM; + goto out; + } for (i = 0; i < ETH_ALEN; i++) - mac.mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; + mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; - ret = wl12xx_cmd_configure(wl, &mac, sizeof(mac)); + ret = wl12xx_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); if (ret < 0) - return ret; + goto out; - return 0; +out: + kfree(mac); + return ret; } int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) { - struct acx_dot11_default_key default_key; + struct acx_dot11_default_key *default_key; int ret; wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); - default_key.header.id = DOT11_DEFAULT_KEY; - default_key.header.len = sizeof(default_key) - - sizeof(struct acx_header); + default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); + if (!default_key) { + ret = -ENOMEM; + goto out; + } - default_key.id = key_id; + default_key->id = key_id; - ret = wl12xx_cmd_configure(wl, &default_key, sizeof(default_key)); + ret = wl12xx_cmd_configure(wl, DOT11_DEFAULT_KEY, + default_key, sizeof(*default_key)); if (ret < 0) { wl12xx_error("Couldnt set default key"); - return ret; + goto out; } wl->default_key = key_id; - return 0; +out: + kfree(default_key); + return ret; } int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval) { - struct acx_wake_up_condition wake_up; + struct acx_wake_up_condition *wake_up; + int ret; wl12xx_debug(DEBUG_ACX, "acx wake up conditions"); - wake_up.header.id = ACX_WAKE_UP_CONDITIONS; - wake_up.header.len = sizeof(wake_up) - sizeof(struct acx_header); + wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); + if (!wake_up) { + ret = -ENOMEM; + goto out; + } - wake_up.wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP; - wake_up.listen_interval = listen_interval; + wake_up->wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP; + wake_up->listen_interval = listen_interval; - return wl12xx_cmd_configure(wl, &wake_up, sizeof(wake_up)); + ret = wl12xx_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, + wake_up, sizeof(*wake_up)); + if (ret < 0) { + wl12xx_warning("could not set wake up conditions: %d", ret); + goto out; + } + +out: + kfree(wake_up); + return ret; } int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) { + struct acx_sleep_auth *auth; int ret; - struct acx_sleep_auth auth; wl12xx_debug(DEBUG_ACX, "acx sleep auth"); - auth.header.id = ACX_SLEEP_AUTH; - auth.header.len = sizeof(auth) - sizeof(struct acx_header); + auth = kzalloc(sizeof(*auth), GFP_KERNEL); + if (!auth) { + ret = -ENOMEM; + goto out; + } - auth.sleep_auth = sleep_auth; + auth->sleep_auth = sleep_auth; - ret = wl12xx_cmd_configure(wl, &auth, sizeof(auth)); + ret = wl12xx_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); if (ret < 0) return ret; - return 0; +out: + kfree(auth); + return ret; } int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) { - struct wl12xx_command cmd; struct acx_revision *rev; int ret; wl12xx_debug(DEBUG_ACX, "acx fw rev"); - memset(&cmd, 0, sizeof(cmd)); + rev = kzalloc(sizeof(*rev), GFP_KERNEL); + if (!rev) { + ret = -ENOMEM; + goto out; + } - ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, sizeof(*rev), &cmd); + ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); if (ret < 0) { wl12xx_warning("ACX_FW_REV interrogate failed"); - return ret; + goto out; } - rev = (struct acx_revision *) &cmd.parameters; - /* be careful with the buffer sizes */ strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); @@ -143,12 +177,14 @@ int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) */ buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; - return 0; +out: + kfree(rev); + return ret; } int wl12xx_acx_tx_power(struct wl12xx *wl, int power) { - struct acx_current_tx_power ie; + struct acx_current_tx_power *acx; int ret; wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); @@ -156,534 +192,648 @@ int wl12xx_acx_tx_power(struct wl12xx *wl, int power) if (power < 0 || power > 25) return -EINVAL; - memset(&ie, 0, sizeof(ie)); + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } - ie.header.id = DOT11_CUR_TX_PWR; - ie.header.len = sizeof(ie) - sizeof(struct acx_header); - ie.current_tx_power = power * 10; + acx->current_tx_power = power * 10; - ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + ret = wl12xx_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); if (ret < 0) { wl12xx_warning("configure of tx power failed: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(acx); + return ret; } int wl12xx_acx_feature_cfg(struct wl12xx *wl) { - struct acx_feature_config feature; + struct acx_feature_config *feature; int ret; wl12xx_debug(DEBUG_ACX, "acx feature cfg"); - memset(&feature, 0, sizeof(feature)); - - feature.header.id = ACX_FEATURE_CFG; - feature.header.len = sizeof(feature) - sizeof(struct acx_header); + feature = kzalloc(sizeof(*feature), GFP_KERNEL); + if (!feature) { + ret = -ENOMEM; + goto out; + } /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ - feature.data_flow_options = 0; - feature.options = 0; + feature->data_flow_options = 0; + feature->options = 0; - ret = wl12xx_cmd_configure(wl, &feature, sizeof(feature)); - if (ret < 0) + ret = wl12xx_cmd_configure(wl, ACX_FEATURE_CFG, + feature, sizeof(*feature)); + if (ret < 0) { wl12xx_error("Couldnt set HW encryption"); + goto out; + } +out: + kfree(feature); return ret; } -int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len) +int wl12xx_acx_mem_map(struct wl12xx *wl, struct acx_header *mem_map, + size_t len) { - struct wl12xx_command cmd; int ret; wl12xx_debug(DEBUG_ACX, "acx mem map"); - ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, len, &cmd); + ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); if (ret < 0) return ret; - else if (cmd.status != CMD_STATUS_SUCCESS) - return -EIO; - - memcpy(mem_map, &cmd.parameters, len); return 0; } int wl12xx_acx_data_path_params(struct wl12xx *wl, - struct acx_data_path_params_resp *data_path) + struct acx_data_path_params_resp *resp) { - struct acx_data_path_params params; - struct wl12xx_command cmd; + struct acx_data_path_params *params; int ret; wl12xx_debug(DEBUG_ACX, "acx data path params"); - params.rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; - params.tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + ret = -ENOMEM; + goto out; + } - params.rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; - params.tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; + params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; + params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; - params.tx_complete_threshold = 1; + params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; + params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; - params.tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; + params->tx_complete_threshold = 1; - params.tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; + params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; - params.header.id = ACX_DATA_PATH_PARAMS; - params.header.len = sizeof(params) - sizeof(struct acx_header); + params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; - ret = wl12xx_cmd_configure(wl, ¶ms, sizeof(params)); + ret = wl12xx_cmd_configure(wl, ACX_DATA_PATH_PARAMS, + params, sizeof(*params)); if (ret < 0) - return ret; - + goto out; + /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, - sizeof(struct acx_data_path_params_resp), - &cmd); + resp, sizeof(*resp)); if (ret < 0) { wl12xx_warning("failed to read data path parameters: %d", ret); - return ret; - } else if (cmd.status != CMD_STATUS_SUCCESS) { + goto out; + } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { wl12xx_warning("data path parameter acx status failed"); - return -EIO; + ret = -EIO; + goto out; } - memcpy(data_path, &cmd.parameters, sizeof(*data_path)); - - return 0; +out: + kfree(params); + return ret; } int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) { - struct rx_msdu_lifetime msdu_lifetime; + struct acx_rx_msdu_lifetime *acx; int ret; wl12xx_debug(DEBUG_ACX, "acx rx msdu life time"); - msdu_lifetime.header.id = DOT11_RX_MSDU_LIFE_TIME; - msdu_lifetime.header.len = sizeof(msdu_lifetime) - - sizeof(struct acx_header); - msdu_lifetime.lifetime = life_time; + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } - ret = wl12xx_cmd_configure(wl, &msdu_lifetime, sizeof(msdu_lifetime)); + ret = wl12xx_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, + acx, sizeof(*acx)); if (ret < 0) { wl12xx_warning("failed to set rx msdu life time: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(acx); + return ret; } int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) { - struct acx_rx_config rx_config; + struct acx_rx_config *rx_config; int ret; wl12xx_debug(DEBUG_ACX, "acx rx config"); - rx_config.header.id = ACX_RX_CFG; - rx_config.header.len = sizeof(rx_config) - sizeof(struct acx_header); - rx_config.config_options = config; - rx_config.filter_options = filter; + rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); + if (!rx_config) { + ret = -ENOMEM; + goto out; + } + + rx_config->config_options = config; + rx_config->filter_options = filter; - ret = wl12xx_cmd_configure(wl, &rx_config, sizeof(rx_config)); + ret = wl12xx_cmd_configure(wl, ACX_RX_CFG, + rx_config, sizeof(*rx_config)); if (ret < 0) { wl12xx_warning("failed to set rx config: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(rx_config); + return ret; } int wl12xx_acx_pd_threshold(struct wl12xx *wl) { - struct acx_packet_detection packet_detection; + struct acx_packet_detection *pd; int ret; wl12xx_debug(DEBUG_ACX, "acx data pd threshold"); + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + ret = -ENOMEM; + goto out; + } + /* FIXME: threshold value not set */ - packet_detection.header.id = ACX_PD_THRESHOLD; - packet_detection.header.len = sizeof(packet_detection) - - sizeof(struct acx_header); - ret = wl12xx_cmd_configure(wl, &packet_detection, - sizeof(packet_detection)); + ret = wl12xx_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); if (ret < 0) { wl12xx_warning("failed to set pd threshold: %d", ret); - return ret; + goto out; } +out: + kfree(pd); return 0; } int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) { - struct acx_slot slot; + struct acx_slot *slot; int ret; wl12xx_debug(DEBUG_ACX, "acx slot"); - slot.header.id = ACX_SLOT; - slot.header.len = sizeof(slot) - sizeof(struct acx_header); + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + ret = -ENOMEM; + goto out; + } - slot.wone_index = STATION_WONE_INDEX; - slot.slot_time = slot_time; + slot->wone_index = STATION_WONE_INDEX; + slot->slot_time = slot_time; - ret = wl12xx_cmd_configure(wl, &slot, sizeof(slot)); + ret = wl12xx_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); if (ret < 0) { wl12xx_warning("failed to set slot time: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(slot); + return ret; } int wl12xx_acx_group_address_tbl(struct wl12xx *wl) { - struct multicast_grp_addr_start multicast; + struct acx_dot11_grp_addr_tbl *acx; int ret; wl12xx_debug(DEBUG_ACX, "acx group address tbl"); - /* MAC filtering */ - multicast.header.id = DOT11_GROUP_ADDRESS_TBL; - multicast.header.len = sizeof(multicast) - sizeof(struct acx_header); + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } - multicast.enabled = 0; - multicast.num_groups = 0; - memset(multicast.mac_table, 0, ADDRESS_GROUP_MAX_LEN); + /* MAC filtering */ + acx->enabled = 0; + acx->num_groups = 0; + memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); - ret = wl12xx_cmd_configure(wl, &multicast, sizeof(multicast)); + ret = wl12xx_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + acx, sizeof(*acx)); if (ret < 0) { wl12xx_warning("failed to set group addr table: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(acx); + return ret; } int wl12xx_acx_service_period_timeout(struct wl12xx *wl) { - struct acx_rx_timeout rx_timeout; + struct acx_rx_timeout *rx_timeout; int ret; - wl12xx_debug(DEBUG_ACX, "acx service period timeout"); + rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); + if (!rx_timeout) { + ret = -ENOMEM; + goto out; + } - /* RX timeout */ - rx_timeout.header.id = ACX_SERVICE_PERIOD_TIMEOUT; - rx_timeout.header.len = sizeof(rx_timeout) - sizeof(struct acx_header); + wl12xx_debug(DEBUG_ACX, "acx service period timeout"); - rx_timeout.ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; - rx_timeout.upsd_timeout = RX_TIMEOUT_UPSD_DEF; + rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; + rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; - ret = wl12xx_cmd_configure(wl, &rx_timeout, sizeof(rx_timeout)); + ret = wl12xx_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, + rx_timeout, sizeof(*rx_timeout)); if (ret < 0) { wl12xx_warning("failed to set service period timeout: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(rx_timeout); + return ret; } int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) { - struct acx_rts_threshold rts; + struct acx_rts_threshold *rts; int ret; wl12xx_debug(DEBUG_ACX, "acx rts threshold"); - rts.header.id = DOT11_RTS_THRESHOLD; - rts.header.len = sizeof(rts) - sizeof(struct acx_header); + rts = kzalloc(sizeof(*rts), GFP_KERNEL); + if (!rts) { + ret = -ENOMEM; + goto out; + } - rts.threshold = rts_threshold; + rts->threshold = rts_threshold; - ret = wl12xx_cmd_configure(wl, &rts, sizeof(rts)); + ret = wl12xx_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); if (ret < 0) { wl12xx_warning("failed to set rts threshold: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(rts); + return ret; } int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) { - struct acx_beacon_filter_option beacon_filter; + struct acx_beacon_filter_option *beacon_filter; int ret; wl12xx_debug(DEBUG_ACX, "acx beacon filter opt"); - beacon_filter.header.id = ACX_BEACON_FILTER_OPT; - beacon_filter.header.len = sizeof(beacon_filter) - - sizeof(struct acx_header); + beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); + if (!beacon_filter) { + ret = -ENOMEM; + goto out; + } - beacon_filter.enable = 0; - beacon_filter.max_num_beacons = 0; + beacon_filter->enable = 0; + beacon_filter->max_num_beacons = 0; - ret = wl12xx_cmd_configure(wl, &beacon_filter, sizeof(beacon_filter)); + ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_OPT, + beacon_filter, sizeof(*beacon_filter)); if (ret < 0) { wl12xx_warning("failed to set beacon filter opt: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(beacon_filter); + return ret; } int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) { - struct acx_beacon_filter_ie_table ie_table; + struct acx_beacon_filter_ie_table *ie_table; int ret; wl12xx_debug(DEBUG_ACX, "acx beacon filter table"); - ie_table.header.id = ACX_BEACON_FILTER_TABLE; - ie_table.header.len = sizeof(ie_table) - sizeof(struct acx_header); + ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); + if (!ie_table) { + ret = -ENOMEM; + goto out; + } - ie_table.num_ie = 0; - memset(ie_table.table, 0, BEACON_FILTER_TABLE_MAX_SIZE); + ie_table->num_ie = 0; + memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); - ret = wl12xx_cmd_configure(wl, &ie_table, sizeof(ie_table)); + ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, + ie_table, sizeof(*ie_table)); if (ret < 0) { wl12xx_warning("failed to set beacon filter table: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(ie_table); + return ret; } int wl12xx_acx_sg_enable(struct wl12xx *wl) { - struct acx_bt_wlan_coex pta; + struct acx_bt_wlan_coex *pta; int ret; wl12xx_debug(DEBUG_ACX, "acx sg enable"); - pta.header.id = ACX_SG_ENABLE; - pta.header.len = sizeof(pta) - sizeof(struct acx_header); + pta = kzalloc(sizeof(*pta), GFP_KERNEL); + if (!pta) { + ret = -ENOMEM; + goto out; + } - pta.enable = SG_ENABLE; + pta->enable = SG_ENABLE; - ret = wl12xx_cmd_configure(wl, &pta, sizeof(pta)); + ret = wl12xx_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); if (ret < 0) { wl12xx_warning("failed to set softgemini enable: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(pta); + return ret; } int wl12xx_acx_sg_cfg(struct wl12xx *wl) { - struct acx_bt_wlan_coex_param param; + struct acx_bt_wlan_coex_param *param; int ret; wl12xx_debug(DEBUG_ACX, "acx sg cfg"); + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + /* BT-WLAN coext parameters */ - param.header.id = ACX_SG_CFG; - param.header.len = sizeof(param) - sizeof(struct acx_header); - - param.min_rate = RATE_INDEX_24MBPS; - param.bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; - param.wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; - param.sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; - param.rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; - param.tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; - param.rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; - param.tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; - param.wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; - param.bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; - param.next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; - param.wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; - param.hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; - param.next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; - param.antenna_type = PTA_ANTENNA_TYPE_DEF; - param.signal_type = PTA_SIGNALING_TYPE_DEF; - param.afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; - param.quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; - param.max_cts = PTA_MAX_NUM_CTS_DEF; - param.wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; - param.bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; - param.missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; - param.wlan_elp_hp = PTA_ELP_HP_DEF; - param.bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; - param.ack_mode_dual_ant = PTA_ACK_MODE_DEF; - param.pa_sd_enable = PTA_ALLOW_PA_SD_DEF; - param.pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; - param.bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; - - ret = wl12xx_cmd_configure(wl, ¶m, sizeof(param)); + param->min_rate = RATE_INDEX_24MBPS; + param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; + param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; + param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; + param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; + param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; + param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; + param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; + param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; + param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; + param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; + param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; + param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; + param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; + param->antenna_type = PTA_ANTENNA_TYPE_DEF; + param->signal_type = PTA_SIGNALING_TYPE_DEF; + param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; + param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; + param->max_cts = PTA_MAX_NUM_CTS_DEF; + param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; + param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; + param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; + param->wlan_elp_hp = PTA_ELP_HP_DEF; + param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; + param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; + param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; + param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; + param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; + + ret = wl12xx_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); if (ret < 0) { wl12xx_warning("failed to set sg config: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(param); + return ret; } int wl12xx_acx_cca_threshold(struct wl12xx *wl) { - struct acx_energy_detection detection; + struct acx_energy_detection *detection; int ret; wl12xx_debug(DEBUG_ACX, "acx cca threshold"); - detection.header.id = ACX_CCA_THRESHOLD; - detection.header.len = sizeof(detection) - sizeof(struct acx_header); + detection = kzalloc(sizeof(*detection), GFP_KERNEL); + if (!detection) { + ret = -ENOMEM; + goto out; + } - detection.rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; - detection.tx_energy_detection = 0; + detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; + detection->tx_energy_detection = 0; - ret = wl12xx_cmd_configure(wl, &detection, sizeof(detection)); + ret = wl12xx_cmd_configure(wl, ACX_CCA_THRESHOLD, + detection, sizeof(*detection)); if (ret < 0) { wl12xx_warning("failed to set cca threshold: %d", ret); return ret; } - return 0; +out: + kfree(detection); + return ret; } int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) { - struct acx_beacon_broadcast bb; + struct acx_beacon_broadcast *bb; int ret; wl12xx_debug(DEBUG_ACX, "acx bcn dtim options"); - bb.header.id = ACX_BCN_DTIM_OPTIONS; - bb.header.len = sizeof(bb) - sizeof(struct acx_header); + bb = kzalloc(sizeof(*bb), GFP_KERNEL); + if (!bb) { + ret = -ENOMEM; + goto out; + } - bb.beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; - bb.broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; - bb.rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; - bb.ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; + bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; + bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; + bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; + bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; - ret = wl12xx_cmd_configure(wl, &bb, sizeof(bb)); + ret = wl12xx_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); if (ret < 0) { wl12xx_warning("failed to set rx config: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(bb); + return ret; } int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) { - struct acx_aid acx_aid; + struct acx_aid *acx_aid; int ret; wl12xx_debug(DEBUG_ACX, "acx aid"); - acx_aid.header.id = ACX_AID; - acx_aid.header.len = sizeof(acx_aid) - sizeof(struct acx_header); + acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); + if (!acx_aid) { + ret = -ENOMEM; + goto out; + } - acx_aid.aid = aid; + acx_aid->aid = aid; - ret = wl12xx_cmd_configure(wl, &acx_aid, sizeof(acx_aid)); + ret = wl12xx_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); if (ret < 0) { wl12xx_warning("failed to set aid: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(acx_aid); + return ret; } int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) { - struct acx_event_mask mask; + struct acx_event_mask *mask; int ret; wl12xx_debug(DEBUG_ACX, "acx event mbox mask"); - mask.header.id = ACX_EVENT_MBOX_MASK; - mask.header.len = sizeof(mask) - sizeof(struct acx_header); + mask = kzalloc(sizeof(*mask), GFP_KERNEL); + if (!mask) { + ret = -ENOMEM; + goto out; + } /* high event mask is unused */ - mask.high_event_mask = 0xffffffff; + mask->high_event_mask = 0xffffffff; - mask.event_mask = event_mask; + mask->event_mask = event_mask; - ret = wl12xx_cmd_configure(wl, &mask, sizeof(mask)); + ret = wl12xx_cmd_configure(wl, ACX_EVENT_MBOX_MASK, + mask, sizeof(*mask)); if (ret < 0) { wl12xx_warning("failed to set aid: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(mask); + return ret; } int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) { - struct acx_preamble ie; + struct acx_preamble *acx; int ret; wl12xx_debug(DEBUG_ACX, "acx_set_preamble"); - memset(&ie, 0, sizeof(ie)); + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } - ie.header.id = ACX_PREAMBLE_TYPE; - ie.header.len = sizeof(ie) - sizeof(struct acx_header); - ie.preamble = preamble; - ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + acx->preamble = preamble; + + ret = wl12xx_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); if (ret < 0) { wl12xx_warning("Setting of preamble failed: %d", ret); - return ret; + goto out; } - return 0; + +out: + kfree(acx); + return ret; } int wl12xx_acx_cts_protect(struct wl12xx *wl, enum acx_ctsprotect_type ctsprotect) { - struct acx_ctsprotect ie; + struct acx_ctsprotect *acx; int ret; wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); - memset(&ie, 0, sizeof(ie)); + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ctsprotect = ctsprotect; - ie.header.id = ACX_CTS_PROTECTION; - ie.header.len = sizeof(ie) - sizeof(struct acx_header); - ie.ctsprotect = ctsprotect; - ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + ret = wl12xx_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); if (ret < 0) { wl12xx_warning("Setting of ctsprotect failed: %d", ret); - return ret; + goto out; } - return 0; + +out: + kfree(acx); + return ret; } -int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) +int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime) { - struct wl12xx_command *answer; + struct acx_tsf_info *tsf_info; int ret; - wl12xx_debug(DEBUG_ACX, "acx statistics"); - - answer = kmalloc(sizeof(*answer), GFP_KERNEL); - if (!answer) { - wl12xx_warning("could not allocate memory for acx statistics"); + tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); + if (!tsf_info) { ret = -ENOMEM; goto out; } - ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, sizeof(*answer), - answer); + ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, + tsf_info, sizeof(*tsf_info)); if (ret < 0) { - wl12xx_warning("acx statistics failed: %d", ret); + wl12xx_warning("ACX_FW_REV interrogate failed"); goto out; } - memcpy(stats, answer->parameters, sizeof(*stats)); + *mactime = tsf_info->current_tsf_lsb | + (tsf_info->current_tsf_msb << 31); out: - kfree(answer); + kfree(tsf_info); return ret; } + +int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) +{ + int ret; + + wl12xx_debug(DEBUG_ACX, "acx statistics"); + + ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, stats, + sizeof(*stats)); + if (ret < 0) { + wl12xx_warning("acx statistics failed: %d", ret); + return -ENOMEM; + } + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index fb2d234..549e537 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -26,10 +26,16 @@ #define __WL12XX_ACX_H__ #include "wl12xx.h" +#include "cmd.h" /* Target's information element */ struct acx_header { + struct wl12xx_cmd_header cmd; + + /* acx (or information element) header */ u16 id; + + /* payload length (not including headers */ u16 len; }; @@ -107,25 +113,6 @@ struct acx_sleep_auth { u8 padding[3]; } __attribute__ ((packed)); -#define TIM_ELE_ID 5 -#define PARTIAL_VBM_MAX 251 - -struct tim { - u8 identity; - u8 length; - u8 dtim_count; - u8 dtim_period; - u8 bitmap_ctrl; - u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ -} __attribute__ ((packed)); - -/* Virtual Bit Map update */ -struct vbm_update_request { - __le16 len; - u8 padding[2]; - struct tim tim; -} __attribute__ ((packed)); - enum { HOSTIF_PCI_MASTER_HOST_INDIRECT, HOSTIF_PCI_MASTER_HOST_DIRECT, @@ -202,7 +189,7 @@ struct acx_data_path_params_resp { #define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF #define RX_MSDU_LIFETIME_DEF 512000 -struct rx_msdu_lifetime { +struct acx_rx_msdu_lifetime { struct acx_header header; /* @@ -368,7 +355,7 @@ struct acx_slot { #define ADDRESS_GROUP_MAX (8) #define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) -struct multicast_grp_addr_start { +struct acx_dot11_grp_addr_tbl { struct acx_header header; u8 enabled; @@ -730,22 +717,13 @@ struct acx_fw_gen_frame_rates { } __attribute__ ((packed)); /* STA MAC */ -struct dot11_station_id { +struct acx_dot11_station_id { struct acx_header header; u8 mac[ETH_ALEN]; u8 pad[2]; } __attribute__ ((packed)); -/* HW encryption keys */ -#define NUM_ACCESS_CATEGORIES_COPY 4 -#define MAX_KEY_SIZE 32 - -/* When set, disable HW encryption */ -#define DF_ENCRYPTION_DISABLE 0x01 -/* When set, disable HW decryption */ -#define DF_SNIFF_MODE_ENABLE 0x80 - struct acx_feature_config { struct acx_header header; @@ -753,67 +731,6 @@ struct acx_feature_config { u32 data_flow_options; } __attribute__ ((packed)); -enum acx_key_action { - KEY_ADD_OR_REPLACE = 1, - KEY_REMOVE = 2, - KEY_SET_ID = 3, - MAX_KEY_ACTION = 0xffff, -}; - -enum acx_key_type { - KEY_WEP_DEFAULT = 0, - KEY_WEP_ADDR = 1, - KEY_AES_GROUP = 4, - KEY_AES_PAIRWISE = 5, - KEY_WEP_GROUP = 6, - KEY_TKIP_MIC_GROUP = 10, - KEY_TKIP_MIC_PAIRWISE = 11, -}; - -/* - * - * key_type_e key size key format - * ---------- --------- ---------- - * 0x00 5, 13, 29 Key data - * 0x01 5, 13, 29 Key data - * 0x04 16 16 bytes of key data - * 0x05 16 16 bytes of key data - * 0x0a 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * 0x0b 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * - */ - -struct acx_set_key { - /* Ignored for default WEP key */ - u8 addr[ETH_ALEN]; - - /* key_action_e */ - u16 key_action; - - u16 reserved_1; - - /* key size in bytes */ - u8 key_size; - - /* key_type_e */ - u8 key_type; - u8 ssid_profile; - - /* - * TKIP, AES: frame's key id field. - * For WEP default key: key id; - */ - u8 id; - u8 reserved_2[6]; - u8 key[MAX_KEY_SIZE]; - u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; - u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; -} __attribute__ ((packed)); - struct acx_current_tx_power { struct acx_header header; @@ -839,26 +756,6 @@ struct acx_tsf_info { u8 pad[3]; } __attribute__ ((packed)); -/* 802.11 PS */ -enum acx_ps_mode { - STATION_ACTIVE_MODE, - STATION_POWER_SAVE_MODE -}; - -struct acx_ps_params { - u8 ps_mode; /* STATION_* */ - u8 send_null_data; /* Do we have to send NULL data packet ? */ - u8 retries; /* Number of retires for the initial NULL data packet */ - - /* - * TUs during which the target stays awake after switching - * to power save mode. - */ - u8 hang_over_period; - u16 null_data_rate; - u8 pad[2]; -} __attribute__ ((packed)); - enum acx_wake_up_event { WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ @@ -892,6 +789,7 @@ enum acx_preamble_type { struct acx_preamble { struct acx_header header; + /* * When set, the WiLink transmits the frames with a short preamble and * when cleared, the WiLink transmits the frames with a long preamble. @@ -1219,7 +1117,8 @@ int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); int wl12xx_acx_tx_power(struct wl12xx *wl, int power); int wl12xx_acx_feature_cfg(struct wl12xx *wl); -int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len); +int wl12xx_acx_mem_map(struct wl12xx *wl, + struct acx_header *mem_map, size_t len); int wl12xx_acx_data_path_params(struct wl12xx *wl, struct acx_data_path_params_resp *data_path); int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time); @@ -1241,5 +1140,6 @@ int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble); int wl12xx_acx_cts_protect(struct wl12xx *wl, enum acx_ctsprotect_type ctsprotect); int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats); +int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime); #endif /* __WL12XX_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index f73ab60..0a02cdd 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -9,24 +9,32 @@ #include "reg.h" #include "spi.h" #include "ps.h" - -int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len) +#include "acx.h" + +/** + * send command to firmware + * + * @wl: wl struct + * @id: command id + * @buf: buffer containing the command, must work with dma + * @len: length of the buffer + */ +int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) { - struct wl12xx_command cmd; + struct wl12xx_cmd_header *cmd; unsigned long timeout; - size_t cmd_len; u32 intr; int ret = 0; - memset(&cmd, 0, sizeof(cmd)); - cmd.id = type; - cmd.status = 0; - memcpy(cmd.parameters, buf, buf_len); - cmd_len = ALIGN(buf_len, 4) + CMDMBOX_HEADER_LEN; + cmd = buf; + cmd->id = id; + cmd->status = 0; + + WARN_ON(len % 4 != 0); wl12xx_ps_elp_wakeup(wl); - wl12xx_spi_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len); + wl12xx_spi_mem_write(wl, wl->cmd_box_addr, buf, len); wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); @@ -54,21 +62,42 @@ out: return ret; } +/** + * send test command to firmware + * + * @wl: wl struct + * @buf: buffer containing the command, without headers, no dma requirements + * @len: length of the buffer + * @answer: is answer needed + * + * FIXME: cmd_test users need to be converted to the new interface + */ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) { + struct wl12xx_command *cmd; + size_t cmd_len; int ret; wl12xx_debug(DEBUG_CMD, "cmd test"); - ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + memcpy(cmd->parameters, buf, buf_len); + + /* FIXME: ugly */ + cmd_len = sizeof(struct wl12xx_cmd_header) + buf_len; + + ret = wl12xx_cmd_send(wl, CMD_TEST, cmd, cmd_len); if (ret < 0) { wl12xx_warning("TEST command failed"); - return ret; + goto out; } if (answer) { - struct wl12xx_command *cmd_answer; - /* * The test command got in, we can read the answer. * The answer would be a wl12xx_command, where the @@ -77,109 +106,146 @@ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) wl12xx_ps_elp_wakeup(wl); - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, cmd_len); wl12xx_ps_elp_sleep(wl); - cmd_answer = buf; - if (cmd_answer->status != CMD_STATUS_SUCCESS) + if (cmd->header.status != CMD_STATUS_SUCCESS) wl12xx_error("TEST command answer error: %d", - cmd_answer->status); + cmd->header.status); + memcpy(buf, cmd->parameters, buf_len); } - return 0; +out: + kfree(cmd); + return ret; } - -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len, - void *answer) +/** + * read acx from firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer for the response, including all headers, must work with dma + * @len: lenght of buf + */ +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len) { - struct wl12xx_command *cmd; - struct acx_header header; + struct acx_header *acx = buf; int ret; wl12xx_debug(DEBUG_CMD, "cmd interrogate"); - header.id = ie_id; - header.len = ie_len - sizeof(header); + acx->id = id; - ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, &header, sizeof(header)); + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); if (ret < 0) { wl12xx_error("INTERROGATE command failed"); - return ret; + goto out; } wl12xx_ps_elp_wakeup(wl); /* the interrogate command got in, we can read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, answer, - CMDMBOX_HEADER_LEN + ie_len); + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, len); wl12xx_ps_elp_sleep(wl); - cmd = answer; - if (cmd->status != CMD_STATUS_SUCCESS) + acx = buf; + if (acx->cmd.status != CMD_STATUS_SUCCESS) wl12xx_error("INTERROGATE command error: %d", - cmd->status); - - return 0; + acx->cmd.status); +out: + return ret; } -int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len) +/** + * write acx value to firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer containing acx, including all headers, must work with dma + * @len: length of buf + */ +int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len) { + struct acx_header *acx = buf; int ret; wl12xx_debug(DEBUG_CMD, "cmd configure"); - ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, ie, - ie_len); + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, acx, len); if (ret < 0) { wl12xx_warning("CONFIGURE command NOK"); return ret; } return 0; - } int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control) { - struct vbm_update_request vbm; + struct wl12xx_cmd_vbm_update *vbm; int ret; wl12xx_debug(DEBUG_CMD, "cmd vbm"); + vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); + if (!vbm) { + ret = -ENOMEM; + goto out; + } + /* Count and period will be filled by the target */ - vbm.tim.bitmap_ctrl = bitmap_control; + vbm->tim.bitmap_ctrl = bitmap_control; if (bitmap_len > PARTIAL_VBM_MAX) { wl12xx_warning("cmd vbm len is %d B, truncating to %d", bitmap_len, PARTIAL_VBM_MAX); bitmap_len = PARTIAL_VBM_MAX; } - memcpy(vbm.tim.pvb_field, bitmap, bitmap_len); - vbm.tim.identity = identity; - vbm.tim.length = bitmap_len + 3; + memcpy(vbm->tim.pvb_field, bitmap, bitmap_len); + vbm->tim.identity = identity; + vbm->tim.length = bitmap_len + 3; - vbm.len = cpu_to_le16(bitmap_len + 5); + vbm->len = cpu_to_le16(bitmap_len + 5); - ret = wl12xx_cmd_send(wl, CMD_VBM, &vbm, sizeof(vbm)); + ret = wl12xx_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); if (ret < 0) { wl12xx_error("VBM command failed"); - return ret; + goto out; } +out: + kfree(vbm); return 0; } -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable) +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable) { + struct cmd_enabledisable_path *cmd; int ret; u16 cmd_rx, cmd_tx; wl12xx_debug(DEBUG_CMD, "cmd data path"); + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->channel = channel; + if (enable) { cmd_rx = CMD_ENABLE_RX; cmd_tx = CMD_ENABLE_TX; @@ -188,17 +254,17 @@ int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable) cmd_tx = CMD_DISABLE_TX; } - ret = wl12xx_cmd_send(wl, cmd_rx, &channel, sizeof(channel)); + ret = wl12xx_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); if (ret < 0) { wl12xx_error("rx %s cmd for channel %d failed", enable ? "start" : "stop", channel); - return ret; + goto out; } wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d", enable ? "start" : "stop", channel); - ret = wl12xx_cmd_send(wl, cmd_tx, &channel, sizeof(channel)); + ret = wl12xx_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); if (ret < 0) { wl12xx_error("tx %s cmd for channel %d failed", enable ? "start" : "stop", channel); @@ -208,48 +274,56 @@ int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable) wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d", enable ? "start" : "stop", channel); - return 0; +out: + kfree(cmd); + return ret; } int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait) { unsigned long timeout; - struct cmd_join join = {}; + struct cmd_join *join; int ret, i; u8 *bssid; + join = kzalloc(sizeof(*join), GFP_KERNEL); + if (!join) { + ret = -ENOMEM; + goto out; + } + /* FIXME: this should be in main.c */ ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, DEFAULT_HW_GEN_MODULATION_TYPE, wl->tx_mgmt_frm_rate, wl->tx_mgmt_frm_mod); if (ret < 0) - return ret; + goto out; wl12xx_debug(DEBUG_CMD, "cmd join"); /* Reverse order BSSID */ - bssid = (u8 *)&join.bssid_lsb; + bssid = (u8 *) &join->bssid_lsb; for (i = 0; i < ETH_ALEN; i++) bssid[i] = wl->bssid[ETH_ALEN - i - 1]; - join.rx_config_options = wl->rx_config; - join.rx_filter_options = wl->rx_filter; + join->rx_config_options = wl->rx_config; + join->rx_filter_options = wl->rx_filter; - join.basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | + join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; - join.beacon_interval = beacon_interval; - join.dtim_interval = dtim_interval; - join.bss_type = bss_type; - join.channel = wl->channel; - join.ctrl = JOIN_CMD_CTRL_TX_FLUSH; + join->beacon_interval = beacon_interval; + join->dtim_interval = dtim_interval; + join->bss_type = bss_type; + join->channel = wl->channel; + join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; - ret = wl12xx_cmd_send(wl, CMD_START_JOIN, &join, sizeof(join)); + ret = wl12xx_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); if (ret < 0) { wl12xx_error("failed to initiate cmd join"); - return ret; + goto out; } timeout = msecs_to_jiffies(JOIN_TIMEOUT); @@ -261,93 +335,120 @@ int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, if (wait) msleep(10); - return 0; +out: + kfree(join); + return ret; } int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) { - int ret; - struct acx_ps_params ps_params; + struct wl12xx_cmd_ps_params *ps_params = NULL; + int ret = 0; /* FIXME: this should be in ps.c */ ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int); if (ret < 0) { - wl12xx_error("Couldnt set wake up conditions"); - return ret; + wl12xx_error("couldn't set wake up conditions"); + goto out; } wl12xx_debug(DEBUG_CMD, "cmd set ps mode"); - ps_params.ps_mode = ps_mode; - ps_params.send_null_data = 1; - ps_params.retries = 5; - ps_params.hang_over_period = 128; - ps_params.null_data_rate = 1; /* 1 Mbps */ + ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); + if (!ps_params) { + ret = -ENOMEM; + goto out; + } + + ps_params->ps_mode = ps_mode; + ps_params->send_null_data = 1; + ps_params->retries = 5; + ps_params->hang_over_period = 128; + ps_params->null_data_rate = 1; /* 1 Mbps */ - ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, &ps_params, - sizeof(ps_params)); + ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, ps_params, + sizeof(*ps_params)); if (ret < 0) { wl12xx_error("cmd set_ps_mode failed"); - return ret; + goto out; } - return 0; +out: + kfree(ps_params); + return ret; } -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer) +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, + size_t len) { - struct cmd_read_write_memory mem_cmd, *mem_answer; - struct wl12xx_command cmd; - int ret; + struct cmd_read_write_memory *cmd; + int ret = 0; wl12xx_debug(DEBUG_CMD, "cmd read memory"); - memset(&mem_cmd, 0, sizeof(mem_cmd)); - mem_cmd.addr = addr; - mem_cmd.size = len; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + WARN_ON(len > MAX_READ_SIZE); + len = min_t(size_t, len, MAX_READ_SIZE); + + cmd->addr = addr; + cmd->size = len; - ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, &mem_cmd, sizeof(mem_cmd)); + ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); if (ret < 0) { wl12xx_error("read memory command failed: %d", ret); - return ret; + goto out; } /* the read command got in, we can now read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, &cmd, - CMDMBOX_HEADER_LEN + sizeof(mem_cmd)); + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); - if (cmd.status != CMD_STATUS_SUCCESS) - wl12xx_error("error in read command result: %d", cmd.status); + if (cmd->header.status != CMD_STATUS_SUCCESS) + wl12xx_error("error in read command result: %d", + cmd->header.status); - mem_answer = (struct cmd_read_write_memory *) cmd.parameters; - memcpy(answer, mem_answer->value, len); + memcpy(answer, cmd->value, len); - return 0; +out: + kfree(cmd); + return ret; } int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, void *buf, size_t buf_len) { - struct wl12xx_cmd_packet_template template; - int ret; + struct wl12xx_cmd_packet_template *cmd; + size_t cmd_len; + int ret = 0; wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id); - memset(&template, 0, sizeof(template)); - WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE); buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE); - template.size = cpu_to_le16(buf_len); + cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); + + cmd = kzalloc(cmd_len, GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->size = cpu_to_le16(buf_len); if (buf) - memcpy(template.template, buf, buf_len); + memcpy(cmd->data, buf, buf_len); - ret = wl12xx_cmd_send(wl, cmd_id, &template, - sizeof(template.size) + buf_len); + ret = wl12xx_cmd_send(wl, cmd_id, cmd, cmd_len); if (ret < 0) { wl12xx_warning("cmd set_template failed: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(cmd); + return ret; } diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index aa307dc..7aef1f2 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -27,31 +27,26 @@ #include "wl12xx.h" +struct acx_header; + int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len); int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer); -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len, - void *answer); -int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len); +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len); +int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len); int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable); +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable); int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait); int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer); +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, + size_t len); int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, void *buf, size_t buf_len); /* unit ms */ #define WL12XX_COMMAND_TIMEOUT 2000 -#define WL12XX_MAX_TEMPLATE_SIZE 300 - -struct wl12xx_cmd_packet_template { - __le16 size; - u8 template[WL12XX_MAX_TEMPLATE_SIZE]; -} __attribute__ ((packed)); - enum wl12xx_commands { CMD_RESET = 0, CMD_INTERROGATE = 1, /*use this to read information elements*/ @@ -100,9 +95,15 @@ enum wl12xx_commands { #define MAX_CMD_PARAMS 572 -struct wl12xx_command { +struct wl12xx_cmd_header { u16 id; u16 status; + /* payload */ + u8 data[0]; +} __attribute__ ((packed)); + +struct wl12xx_command { + struct wl12xx_cmd_header header; u8 parameters[MAX_CMD_PARAMS]; }; @@ -144,6 +145,8 @@ enum { #define MAX_READ_SIZE 256 struct cmd_read_write_memory { + struct wl12xx_cmd_header header; + /* The address of the memory to read from or write to.*/ u32 addr; @@ -211,6 +214,8 @@ struct basic_scan_channel_parameters { #define SCAN_MAX_NUM_OF_CHANNELS 16 struct cmd_scan { + struct wl12xx_cmd_header header; + struct basic_scan_parameters params; struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; } __attribute__ ((packed)); @@ -227,6 +232,8 @@ enum { struct cmd_join { + struct wl12xx_cmd_header header; + u32 bssid_lsb; u16 bssid_msb; u16 beacon_interval; /* in TBTTs */ @@ -261,5 +268,140 @@ struct cmd_join { u8 reserved; } __attribute__ ((packed)); +struct cmd_enabledisable_path { + struct wl12xx_cmd_header header; + + u8 channel; + u8 padding[3]; +} __attribute__ ((packed)); + +#define WL12XX_MAX_TEMPLATE_SIZE 300 + +struct wl12xx_cmd_packet_template { + struct wl12xx_cmd_header header; + + __le16 size; + u8 data[0]; +} __attribute__ ((packed)); + +#define TIM_ELE_ID 5 +#define PARTIAL_VBM_MAX 251 + +struct wl12xx_tim { + u8 identity; + u8 length; + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ +} __attribute__ ((packed)); + +/* Virtual Bit Map update */ +struct wl12xx_cmd_vbm_update { + struct wl12xx_cmd_header header; + __le16 len; + u8 padding[2]; + struct wl12xx_tim tim; +} __attribute__ ((packed)); + +enum wl12xx_cmd_ps_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct wl12xx_cmd_ps_params { + struct wl12xx_cmd_header header; + + u8 ps_mode; /* STATION_* */ + u8 send_null_data; /* Do we have to send NULL data packet ? */ + u8 retries; /* Number of retires for the initial NULL data packet */ + + /* + * TUs during which the target stays awake after switching + * to power save mode. + */ + u8 hang_over_period; + u16 null_data_rate; + u8 pad[2]; +} __attribute__ ((packed)); + +struct wl12xx_cmd_trigger_scan_to { + struct wl12xx_cmd_header header; + + u32 timeout; +}; + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 +#define MAX_KEY_SIZE 32 + +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +/* When set, disable HW decryption */ +#define DF_SNIFF_MODE_ENABLE 0x80 + +enum wl12xx_cmd_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum wl12xx_cmd_key_type { + KEY_WEP_DEFAULT = 0, + KEY_WEP_ADDR = 1, + KEY_AES_GROUP = 4, + KEY_AES_PAIRWISE = 5, + KEY_WEP_GROUP = 6, + KEY_TKIP_MIC_GROUP = 10, + KEY_TKIP_MIC_PAIRWISE = 11, +}; + +/* + * + * key_type_e key size key format + * ---------- --------- ---------- + * 0x00 5, 13, 29 Key data + * 0x01 5, 13, 29 Key data + * 0x04 16 16 bytes of key data + * 0x05 16 16 bytes of key data + * 0x0a 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * 0x0b 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * + */ + +struct wl12xx_cmd_set_keys { + struct wl12xx_cmd_header header; + + /* Ignored for default WEP key */ + u8 addr[ETH_ALEN]; + + /* key_action_e */ + u16 key_action; + + u16 reserved_1; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + u8 ssid_profile; + + /* + * TKIP, AES: frame's key id field. + * For WEP default key: key id; + */ + u8 id; + u8 reserved_2[6]; + u8 key[MAX_KEY_SIZE]; + u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __attribute__ ((packed)); + #endif /* __WL12XX_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 603d611..c6a4544 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -618,7 +618,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, } /* HW encryption */ -static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key, +static int wl12xx_set_key_type(struct wl12xx *wl, + struct wl12xx_cmd_set_keys *key, enum set_key_cmd cmd, struct ieee80211_key_conf *mac80211_key, const u8 *addr) @@ -661,7 +662,7 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct wl12xx *wl = hw->priv; - struct acx_set_key wl_key; + struct wl12xx_cmd_set_keys *wl_cmd; const u8 *addr; int ret; @@ -670,7 +671,11 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); - memset(&wl_key, 0, sizeof(wl_key)); + wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); + if (!wl_cmd) { + ret = -ENOMEM; + goto out; + } addr = sta ? sta->addr : bcast_addr; @@ -680,59 +685,69 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key->alg, key->keyidx, key->keylen, key->flags); wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); + if (is_zero_ether_addr(addr)) { + /* We dont support TX only encryption */ + ret = -EOPNOTSUPP; + goto out; + } + mutex_lock(&wl->mutex); switch (cmd) { case SET_KEY: - wl_key.key_action = KEY_ADD_OR_REPLACE; + wl_cmd->key_action = KEY_ADD_OR_REPLACE; break; case DISABLE_KEY: - wl_key.key_action = KEY_REMOVE; + wl_cmd->key_action = KEY_REMOVE; break; default: wl12xx_error("Unsupported key cmd 0x%x", cmd); break; } - ret = wl12xx_set_key_type(wl, &wl_key, cmd, key, addr); + ret = wl12xx_set_key_type(wl, wl_cmd, cmd, key, addr); if (ret < 0) { wl12xx_error("Set KEY type failed"); - goto out; + goto out_unlock; } - if (wl_key.key_type != KEY_WEP_DEFAULT) - memcpy(wl_key.addr, addr, ETH_ALEN); + if (wl_cmd->key_type != KEY_WEP_DEFAULT) + memcpy(wl_cmd->addr, addr, ETH_ALEN); - if ((wl_key.key_type == KEY_TKIP_MIC_GROUP) || - (wl_key.key_type == KEY_TKIP_MIC_PAIRWISE)) { + if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || + (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { /* * We get the key in the following form: * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) * but the target is expecting: * TKIP - RX MIC - TX MIC */ - memcpy(wl_key.key, key->key, 16); - memcpy(wl_key.key + 16, key->key + 24, 8); - memcpy(wl_key.key + 24, key->key + 16, 8); + memcpy(wl_cmd->key, key->key, 16); + memcpy(wl_cmd->key + 16, key->key + 24, 8); + memcpy(wl_cmd->key + 24, key->key + 16, 8); } else { - memcpy(wl_key.key, key->key, key->keylen); + memcpy(wl_cmd->key, key->key, key->keylen); } - wl_key.key_size = key->keylen; + wl_cmd->key_size = key->keylen; - wl_key.id = key->keyidx; - wl_key.ssid_profile = 0; + wl_cmd->id = key->keyidx; + wl_cmd->ssid_profile = 0; - wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", &wl_key, sizeof(wl_key)); + wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); - if (wl12xx_cmd_send(wl, CMD_SET_KEYS, &wl_key, sizeof(wl_key)) < 0) { - wl12xx_error("Set KEY failed"); - ret = -EOPNOTSUPP; - goto out; + ret = wl12xx_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); + if (ret < 0) { + wl12xx_warning("could not set keys"); + goto out_unlock; } -out: +out_unlock: mutex_unlock(&wl->mutex); + +out: + kfree(wl_cmd); + return ret; } @@ -812,11 +827,10 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, u8 active_scan, u8 high_prio, u8 num_channels, u8 probe_requests) { + struct wl12xx_cmd_trigger_scan_to *trigger = NULL; + struct cmd_scan *params = NULL; int i, ret; - u32 split_scan = 0; u16 scan_options = 0; - struct cmd_scan *params; - struct wl12xx_command *cmd_answer; if (wl->scanning) return -EINVAL; @@ -870,10 +884,16 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, goto out; } - ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, &split_scan, - sizeof(u32)); + trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); + if (!trigger) + goto out; + + trigger->timeout = 0; + + ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + sizeof(*trigger)); if (ret < 0) { - wl12xx_error("Split SCAN failed"); + wl12xx_error("trigger scan to failed for hw scan"); goto out; } @@ -887,10 +907,9 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); - cmd_answer = (struct wl12xx_command *) params; - if (cmd_answer->status != CMD_STATUS_SUCCESS) { + if (params->header.status != CMD_STATUS_SUCCESS) { wl12xx_error("TEST command answer error: %d", - cmd_answer->status); + params->header.status); wl->scanning = false; ret = -EIO; goto out; @@ -942,7 +961,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changed) { - enum acx_ps_mode mode; + enum wl12xx_cmd_ps_mode mode; struct wl12xx *wl = hw->priv; struct sk_buff *beacon; int ret; diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 83a1011..fe5e2d1 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -114,7 +114,7 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) return 0; } -int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode) +int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode) { int ret; diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h index 5d7c525..ad61b4a 100644 --- a/drivers/net/wireless/wl12xx/ps.h +++ b/drivers/net/wireless/wl12xx/ps.h @@ -28,7 +28,7 @@ #include "wl12xx.h" #include "acx.h" -int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode); +int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode); void wl12xx_ps_elp_sleep(struct wl12xx *wl); int wl12xx_ps_elp_wakeup(struct wl12xx *wl); diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 981ea25..5fd916a 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -48,6 +48,9 @@ static void wl12xx_rx_status(struct wl12xx *wl, struct ieee80211_rx_status *status, u8 beacon) { + u64 mactime; + int ret; + memset(status, 0, sizeof(struct ieee80211_rx_status)); status->band = IEEE80211_BAND_2GHZ; @@ -62,27 +65,9 @@ static void wl12xx_rx_status(struct wl12xx *wl, * this one must be atomic, while our SPI routines can sleep. */ if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { - u64 mactime; - int ret; - struct wl12xx_command cmd; - struct acx_tsf_info *tsf_info; - - memset(&cmd, 0, sizeof(cmd)); - - ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, - sizeof(struct acx_tsf_info), - &cmd); - if (ret < 0) { - wl12xx_warning("ACX_FW_REV interrogate failed"); - return; - } - - tsf_info = (struct acx_tsf_info *)&(cmd.parameters); - - mactime = tsf_info->current_tsf_lsb | - (tsf_info->current_tsf_msb << 31); - - status->mactime = mactime; + ret = wl12xx_acx_tsf_info(wl, &mactime); + if (ret == 0) + status->mactime = mactime; } status->signal = desc->rssi; diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index ce1561a..1a352cf 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -297,45 +297,48 @@ out: static int wl1251_mem_cfg(struct wl12xx *wl) { - struct wl1251_acx_config_memory mem_conf; + struct wl1251_acx_config_memory *mem_conf; int ret, i; wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg"); + mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); + if (!mem_conf) { + ret = -ENOMEM; + goto out; + } + /* memory config */ - mem_conf.mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); - mem_conf.mem_config.rx_mem_block_num = 35; - mem_conf.mem_config.tx_min_mem_block_num = 64; - mem_conf.mem_config.num_tx_queues = MAX_TX_QUEUES; - mem_conf.mem_config.host_if_options = HOSTIF_PKT_RING; - mem_conf.mem_config.num_ssid_profiles = 1; - mem_conf.mem_config.debug_buffer_size = + mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf->mem_config.rx_mem_block_num = 35; + mem_conf->mem_config.tx_min_mem_block_num = 64; + mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; + mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; + mem_conf->mem_config.num_ssid_profiles = 1; + mem_conf->mem_config.debug_buffer_size = cpu_to_le16(TRACE_BUFFER_MAX_SIZE); /* RX queue config */ - mem_conf.rx_queue_config.dma_address = 0; - mem_conf.rx_queue_config.num_descs = ACX_RX_DESC_DEF; - mem_conf.rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; - mem_conf.rx_queue_config.type = DEFAULT_RXQ_TYPE; + mem_conf->rx_queue_config.dma_address = 0; + mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; + mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; + mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; /* TX queue config */ for (i = 0; i < MAX_TX_QUEUES; i++) { - mem_conf.tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; - mem_conf.tx_queue_config[i].attributes = i; + mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; + mem_conf->tx_queue_config[i].attributes = i; } - mem_conf.header.id = ACX_MEM_CFG; - mem_conf.header.len = sizeof(struct wl1251_acx_config_memory) - - sizeof(struct acx_header); - mem_conf.header.len -= - (MAX_TX_QUEUE_CONFIGS - mem_conf.mem_config.num_tx_queues) * - sizeof(struct wl1251_acx_tx_queue_config); - - ret = wl12xx_cmd_configure(wl, &mem_conf, - sizeof(struct wl1251_acx_config_memory)); - if (ret < 0) + ret = wl12xx_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); + if (ret < 0) { wl12xx_warning("wl1251 mem config failed: %d", ret); + goto out; + } +out: + kfree(mem_conf); return ret; } @@ -529,28 +532,33 @@ static int wl1251_hw_init_txq_fill(u8 qid, static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) { - struct acx_tx_queue_qos_config config; + struct acx_tx_queue_qos_config *config; struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; int ret, i; wl12xx_debug(DEBUG_ACX, "acx tx queue config"); - config.header.id = ACX_TX_QUEUE_CFG; - config.header.len = sizeof(struct acx_tx_queue_qos_config) - - sizeof(struct acx_header); + config = kzalloc(sizeof(*config), GFP_KERNEL); + if (!config) { + ret = -ENOMEM; + goto out; + } for (i = 0; i < MAX_NUM_OF_AC; i++) { - ret = wl1251_hw_init_txq_fill(i, &config, + ret = wl1251_hw_init_txq_fill(i, config, wl_mem_map->num_tx_mem_blocks); if (ret < 0) - return ret; + goto out; - ret = wl12xx_cmd_configure(wl, &config, sizeof(config)); + ret = wl12xx_cmd_configure(wl, ACX_TX_QUEUE_CFG, + config, sizeof(*config)); if (ret < 0) - return ret; + goto out; } - return 0; +out: + kfree(config); + return ret; } static int wl1251_hw_init_data_path_config(struct wl12xx *wl) -- cgit v0.10.2 From 1d3b8130611bbe50168ad0a12841735c9c235410 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:28 +0300 Subject: wl12xx: reserver buffer for read32()/write32() in struct wl12xx The buffer is needed for DMA safe transfers. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index fd3227e..f3f1895 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -94,16 +94,15 @@ void wl12xx_set_partition(struct wl12xx *wl, static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) { - u32 response; + wl12xx_spi_read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); - wl12xx_spi_read(wl, addr, &response, sizeof(u32)); - - return response; + return wl->buffer_32; } static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) { - wl12xx_spi_write(wl, addr, &val, sizeof(u32)); + wl->buffer_32 = val; + wl12xx_spi_write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); } #endif /* __WL12XX_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 4864143..f252a11 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -382,6 +382,8 @@ struct wl12xx { struct wl12xx_stats stats; struct wl12xx_debugfs debugfs; + + u32 buffer_32; }; int wl12xx_plt_start(struct wl12xx *wl); -- cgit v0.10.2 From c4f5c8521868789caaf704c9c2d523b40ccfcb02 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:34 +0300 Subject: wl12xx: fix error handling in wl12xx_probe() Resources were not freed properly in some cases. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index c6a4544..6d27cd6 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1274,13 +1274,15 @@ static int __devinit wl12xx_probe(struct spi_device *spi) wl->set_power = pdata->set_power; if (!wl->set_power) { wl12xx_error("set power function missing in platform data"); - return -ENODEV; + ret = -ENODEV; + goto out_free; } wl->irq = spi->irq; if (wl->irq < 0) { wl12xx_error("irq missing in platform data"); - return -ENODEV; + ret = -ENODEV; + goto out_free; } ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); -- cgit v0.10.2 From 8d47cdb617e0e76e05ea0f92fc164e53bf874b30 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:41 +0300 Subject: wl12xx: reserve buffer for partition command in struct wl12xx This is now DMA safe. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index abdf171..fb7c52c 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -167,24 +167,26 @@ void wl12xx_spi_init(struct wl12xx *wl) * | | * */ -void wl12xx_set_partition(struct wl12xx *wl, +int wl12xx_set_partition(struct wl12xx *wl, u32 mem_start, u32 mem_size, u32 reg_start, u32 reg_size) { - u8 tx_buf[sizeof(u32) + 2 * sizeof(struct wl12xx_partition)]; struct wl12xx_partition *partition; struct spi_transfer t; struct spi_message m; + size_t len, cmd_len; u32 *cmd; - size_t len; int addr; + cmd_len = sizeof(u32) + 2 * sizeof(struct wl12xx_partition); + cmd = kzalloc(cmd_len, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + spi_message_init(&m); memset(&t, 0, sizeof(t)); - memset(tx_buf, 0, sizeof(tx_buf)); - cmd = (u32 *) tx_buf; - partition = (struct wl12xx_partition *) (tx_buf + sizeof(u32)); + partition = (struct wl12xx_partition *) (cmd + 1); addr = HW_ACCESS_PART0_SIZE_ADDR; len = 2 * sizeof(struct wl12xx_partition); @@ -244,11 +246,15 @@ void wl12xx_set_partition(struct wl12xx *wl, wl->virtual_mem_addr = 0; wl->virtual_reg_addr = mem_size; - t.tx_buf = tx_buf; - t.len = sizeof(tx_buf); + t.tx_buf = cmd; + t.len = cmd_len; spi_message_add_tail(&t, &m); spi_sync(wl->spi, &m); + + kfree(cmd); + + return 0; } void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index f3f1895..7edb218 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -88,9 +88,9 @@ void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); /* INIT and RESET words */ void wl12xx_spi_reset(struct wl12xx *wl); void wl12xx_spi_init(struct wl12xx *wl); -void wl12xx_set_partition(struct wl12xx *wl, - u32 part_start, u32 part_size, - u32 reg_start, u32 reg_size); +int wl12xx_set_partition(struct wl12xx *wl, + u32 part_start, u32 part_size, + u32 reg_start, u32 reg_size); static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) { -- cgit v0.10.2 From 56343a3cfdea4d341c7c13d26013024037eae602 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:47 +0300 Subject: wl12xx: allocate buffer spi read/write command buffer kzalloc() Needed for DMA safe transfers. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index fb7c52c..9392742 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -263,17 +263,19 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, struct spi_transfer t[3]; struct spi_message m; char busy_buf[TNETWIF_READ_OFFSET_BYTES]; - u32 cmd; + u32 *cmd; - cmd = 0; - cmd |= WSPI_CMD_READ; - cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - cmd |= addr & WSPI_CMD_BYTE_ADDR; + cmd = &wl->buffer_cmd; + + *cmd = 0; + *cmd |= WSPI_CMD_READ; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; spi_message_init(&m); memset(t, 0, sizeof(t)); - t[0].tx_buf = &cmd; + t[0].tx_buf = cmd; t[0].len = 4; spi_message_add_tail(&t[0], &m); @@ -290,7 +292,7 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, /* FIXME: check busy words */ - wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", &cmd, sizeof(cmd)); + wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); } @@ -299,18 +301,20 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, { struct spi_transfer t[2]; struct spi_message m; - u32 cmd; + u32 *cmd; - cmd = 0; - cmd |= WSPI_CMD_WRITE; - cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - cmd |= addr & WSPI_CMD_BYTE_ADDR; + cmd = &wl->buffer_cmd; + + *cmd = 0; + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; spi_message_init(&m); memset(t, 0, sizeof(t)); - t[0].tx_buf = &cmd; - t[0].len = sizeof(cmd); + t[0].tx_buf = cmd; + t[0].len = sizeof(*cmd); spi_message_add_tail(&t[0], &m); t[1].tx_buf = buf; @@ -319,7 +323,7 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, spi_sync(wl->spi, &m); - wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd)); + wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index f252a11..5865935 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -384,6 +384,7 @@ struct wl12xx { struct wl12xx_debugfs debugfs; u32 buffer_32; + u32 buffer_cmd; }; int wl12xx_plt_start(struct wl12xx *wl); -- cgit v0.10.2 From 5262c12d16334a37354c93d606bdb96499f7e5fc Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:55 +0300 Subject: wl12xx: allocate buffer the spi busy word from struct wl12xx Needed for DMA transfers. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 9392742..bcdcfbc 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -262,10 +262,11 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, { struct spi_transfer t[3]; struct spi_message m; - char busy_buf[TNETWIF_READ_OFFSET_BYTES]; + u8 *busy_buf; u32 *cmd; cmd = &wl->buffer_cmd; + busy_buf = wl->buffer_busyword; *cmd = 0; *cmd |= WSPI_CMD_READ; @@ -281,7 +282,7 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, /* Busy and non busy words read */ t[1].rx_buf = busy_buf; - t[1].len = TNETWIF_READ_OFFSET_BYTES; + t[1].len = WL12XX_BUSY_WORD_LEN; spi_message_add_tail(&t[1], &m); t[2].rx_buf = buf; diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index 7edb218..1a19557 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -65,9 +65,8 @@ #define WSPI_INIT_CMD_LEN 8 -#define TNETWIF_READ_OFFSET_BYTES 8 #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ - ((TNETWIF_READ_OFFSET_BYTES - 4) / sizeof(u32)) + ((WL12XX_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 5865935..b811020 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -105,6 +105,7 @@ enum { CFG_RX_AUTH_EN | \ CFG_RX_ASSOC_EN) +#define WL12XX_BUSY_WORD_LEN 8 struct boot_attr { u32 radio_type; @@ -385,6 +386,7 @@ struct wl12xx { u32 buffer_32; u32 buffer_cmd; + u8 buffer_busyword[WL12XX_BUSY_WORD_LEN]; }; int wl12xx_plt_start(struct wl12xx *wl); -- cgit v0.10.2 From 53d65423ba1bc3c38d53b27656395c632b073590 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:15:00 +0300 Subject: wl12xx: use wl12xx_mem_read32() to read the rx counter As a side effect the transfer is now DMA safe. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index 1a352cf..e484a23 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -415,8 +415,8 @@ static void wl1251_irq_work(struct work_struct *work) wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr); if (wl->data_path) { - wl12xx_spi_mem_read(wl, wl->data_path->rx_control_addr, - &wl->rx_counter, sizeof(u32)); + wl->rx_counter = + wl12xx_mem_read32(wl, wl->data_path->rx_control_addr); /* We handle a frmware bug here */ switch ((wl->rx_counter - wl->rx_handled) & 0xf) { -- cgit v0.10.2 From 4721213fdde4456a36a5e63f02e5c2556a4df398 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:15:08 +0300 Subject: wl12xx: fix rx descriptor use Rx descriptor was incorrectly allocated from stack, use struct wl12xx instead. Needed for DMA transfers. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 6d27cd6..3c6cd77 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1261,6 +1261,13 @@ static int __devinit wl12xx_probe(struct spi_device *spi) wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; + wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); + if (!wl->rx_descriptor) { + wl12xx_error("could not allocate memory for rx descriptor"); + ret = -ENOMEM; + goto out_free; + } + /* This is the only SPI value that we need to set here, the rest * comes from the board-peripherals file */ spi->bits_per_word = 32; @@ -1313,6 +1320,9 @@ static int __devinit wl12xx_probe(struct spi_device *spi) free_irq(wl->irq, wl); out_free: + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + ieee80211_free_hw(hw); return ret; @@ -1333,6 +1343,10 @@ static int __devexit wl12xx_remove(struct spi_device *spi) wl->fw = NULL; kfree(wl->nvs); wl->nvs = NULL; + + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + ieee80211_free_hw(wl->hw); return 0; diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 5fd916a..7ac26ef 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -39,8 +39,7 @@ static void wl12xx_rx_header(struct wl12xx *wl, if (wl->rx_current_buffer) rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, - sizeof(struct wl12xx_rx_descriptor)); + wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); } static void wl12xx_rx_status(struct wl12xx *wl, @@ -175,16 +174,18 @@ static void wl12xx_rx_ack(struct wl12xx *wl) void wl12xx_rx(struct wl12xx *wl) { - struct wl12xx_rx_descriptor rx_desc; + struct wl12xx_rx_descriptor *rx_desc; if (wl->state != WL12XX_STATE_ON) return; + rx_desc = wl->rx_descriptor; + /* We first read the frame's header */ - wl12xx_rx_header(wl, &rx_desc); + wl12xx_rx_header(wl, rx_desc); /* Now we can read the body */ - wl12xx_rx_body(wl, &rx_desc); + wl12xx_rx_body(wl, rx_desc); /* Finally, we need to ACK the RX */ wl12xx_rx_ack(wl); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index b811020..b874214 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -387,6 +387,7 @@ struct wl12xx { u32 buffer_32; u32 buffer_cmd; u8 buffer_busyword[WL12XX_BUSY_WORD_LEN]; + struct wl12xx_rx_descriptor *rx_descriptor; }; int wl12xx_plt_start(struct wl12xx *wl); -- cgit v0.10.2 From 0628817accc305201fc0e1b7f020dec618c868cc Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 12 Jun 2009 14:15:13 +0300 Subject: wl12xx: removed chipset interrupt source configuration from fw wakeup The chipset source interrupt source configuration during fw wakeup was blocking interrupts on the wl1271. The configuration is effectively unused here as it is used to trigger an interrupt for the chipset wake-up event, which is not handled, or waited for, in the fw wakeup anyway on either wl1251 or wl1271. Signed-off-by: Juuso Oikarinen Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3c6cd77..950c425 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -157,8 +157,6 @@ static void wl12xx_fw_wakeup(struct wl12xx *wl) if (!(elp_reg & ELPCTRL_WLAN_READY)) { wl12xx_warning("WLAN not ready"); - elp_reg = ELPCTRL_WAKE_UP_WLAN_READY; - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); } } -- cgit v0.10.2 From a336e266640cd9f7be96b14ff09bbb37dfa646de Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:15:22 +0300 Subject: wl12xx: add wl12xx_spi_reg_read() and wl12xx_spi_reg_write() functions In some cases we need to read more than 32 bits from the register area. These functions were added to support that, like the existing wl12xx_spi_mem_read() and wl12xx_spi_mem_write() already do for large blocks in the memory area. Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index bcdcfbc..0d2b13a 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -348,6 +348,24 @@ void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, wl12xx_spi_write(wl, physical, buf, len); } +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len) +{ + int physical; + + physical = wl12xx_translate_reg_addr(wl, addr); + + wl12xx_spi_read(wl, physical, buf, len); +} + +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len) +{ + int physical; + + physical = wl12xx_translate_reg_addr(wl, addr); + + wl12xx_spi_write(wl, physical, buf, len); +} + u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) { return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr)); diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index 1a19557..0996e48 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -81,6 +81,8 @@ u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); /* Registers IO */ +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf,size_t len); u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); -- cgit v0.10.2 From 0d1c38398fa8cd478a229b4428fb511f813376e8 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:15:27 +0300 Subject: wl12xx: moved firmware version reading routine to chip-specific functions With WL1271, the firmware version can only be read right after booting the chip. To keep WL1251 aligned with this procedure, the code that reads the firmware version initially has been moved to a common place where it can be read from both chipsets. Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 48ac08c..a6a2649 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -269,6 +269,8 @@ int wl12xx_boot_run_firmware(struct wl12xx *wl) wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", wl->cmd_box_addr, wl->event_box_addr); + wl->chip.op_fw_version(wl); + /* * in case of full asynchronous mode the firmware event must be * ready to receive event from the command mailbox diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index e484a23..b793325 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -288,9 +288,6 @@ static int wl1251_boot(struct wl12xx *wl) if (ret < 0) goto out; - /* Get and save the firmware version */ - wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); - out: return ret; } @@ -394,6 +391,11 @@ static void wl1251_target_enable_interrupts(struct wl12xx *wl) wl12xx_boot_target_enable_interrupts(wl); } +static void wl1251_fw_version(struct wl12xx *wl) +{ + wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); +} + static void wl1251_irq_work(struct work_struct *work) { u32 intr; @@ -709,6 +711,7 @@ void wl1251_setup(struct wl12xx *wl) wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; wl->chip.op_hw_init = wl1251_hw_init; wl->chip.op_plt_init = wl1251_plt_init; + wl->chip.op_fw_version = wl1251_fw_version; wl->chip.p_table = wl1251_part_table; wl->chip.acx_reg_table = wl1251_acx_reg_table; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index b874214..32f62a6 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -163,6 +163,7 @@ struct wl12xx_chip { void (*op_target_enable_interrupts)(struct wl12xx *wl); int (*op_hw_init)(struct wl12xx *wl); int (*op_plt_init)(struct wl12xx *wl); + void (*op_fw_version)(struct wl12xx *wl); struct wl12xx_partition_set *p_table; enum wl12xx_acx_int_reg *acx_reg_table; -- cgit v0.10.2 From 27797d68f70b28e77e6d183910dc7b3d7505105d Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:15:33 +0300 Subject: wl12xx: add support for new WL1271 chip revision This patch adds the code that recognizes the new WL1271 chip revision (PG 2.0). Full support for this chip is not yet implemented and support for WL1271 PG 1.0 is not guaranteed anymore. Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 950c425..73232db 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -196,6 +196,13 @@ static int wl12xx_chip_wakeup(struct wl12xx *wl) break; case CHIP_ID_1271_PG10: + wl12xx_warning("chip id 0x%x (1271 PG10) support is obsolete", + wl->chip.id); + break; + case CHIP_ID_1271_PG20: + wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", + wl->chip.id); + break; case CHIP_ID_1251_PG10: case CHIP_ID_1251_PG11: default: diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 32f62a6..c1d00c01 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -412,5 +412,6 @@ int wl12xx_plt_stop(struct wl12xx *wl); #define CHIP_ID_1251_PG11 (0x7020101) #define CHIP_ID_1251_PG12 (0x7030101) #define CHIP_ID_1271_PG10 (0x4030101) +#define CHIP_ID_1271_PG20 (0x4030111) #endif -- cgit v0.10.2 From 052a625a859ceba68022862eeee70511f56483a5 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:15:41 +0300 Subject: wl12xx: add support for fixed address in wl12xx_spi_read In the wl1271 implementation, we need to read memory from the register partition using fixed addresses. This change adds the possibility to request fixed address when calling wl12xx_spi_read() or wl12xx_spi_reg_read(). Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 0d2b13a..c3d5b73 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -258,7 +258,7 @@ int wl12xx_set_partition(struct wl12xx *wl, } void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, - size_t len) + size_t len, bool fixed) { struct spi_transfer t[3]; struct spi_message m; @@ -273,6 +273,9 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; + if (fixed) + *cmd |= WSPI_CMD_FIXED; + spi_message_init(&m); memset(t, 0, sizeof(t)); @@ -335,7 +338,7 @@ void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, physical = wl12xx_translate_mem_addr(wl, addr); - wl12xx_spi_read(wl, physical, buf, len); + wl12xx_spi_read(wl, physical, buf, len, false); } void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, @@ -348,13 +351,14 @@ void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, wl12xx_spi_write(wl, physical, buf, len); } -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len) +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed) { int physical; physical = wl12xx_translate_reg_addr(wl, addr); - wl12xx_spi_read(wl, physical, buf, len); + wl12xx_spi_read(wl, physical, buf, len, fixed); } void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len) diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index 0996e48..30f9098 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -71,8 +71,9 @@ /* Raw target IO, address is not translated */ -void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len); void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed); /* Memory target IO, address is tranlated to partition 0 */ void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len); @@ -81,7 +82,8 @@ u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); /* Registers IO */ -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed); void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf,size_t len); u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); @@ -95,7 +97,8 @@ int wl12xx_set_partition(struct wl12xx *wl, static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) { - wl12xx_spi_read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); + wl12xx_spi_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); return wl->buffer_32; } -- cgit v0.10.2 From 9f483dc3d1b0b1695c8177c1dea2e721954b10fb Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:15:46 +0300 Subject: wl12xx: pass the wake up condition when configuring the wake up event Changed the function wl12xx_acx_wake_up_conditions() so that it receives an argument with the actual wake up condition, instead of having WAKE_UP_EVENT_DTIM_BITMAP hardcoded. This is needed because we have to use different conditions in 1271. Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index d0daf69..a6b8945 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -96,7 +96,8 @@ out: return ret; } -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval) +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, + u8 listen_interval) { struct acx_wake_up_condition *wake_up; int ret; @@ -109,7 +110,7 @@ int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval) goto out; } - wake_up->wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP; + wake_up->wake_up_event = wake_up_event; wake_up->listen_interval = listen_interval; ret = wl12xx_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 549e537..92e7248 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1112,7 +1112,8 @@ int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, u8 mgt_rate, u8 mgt_mod); int wl12xx_acx_station_id(struct wl12xx *wl); int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id); -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval); +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, + u8 listen_interval); int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); int wl12xx_acx_tx_power(struct wl12xx *wl, int power); diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 0a02cdd..d98941a 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -346,7 +346,8 @@ int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) int ret = 0; /* FIXME: this should be in ps.c */ - ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int); + ret = wl12xx_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); if (ret < 0) { wl12xx_error("couldn't set wake up conditions"); goto out; -- cgit v0.10.2 From 9f2ad4fb52916e58a1b75e9a30f42638655932d3 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 12 Jun 2009 14:15:54 +0300 Subject: wl12xx: Moved wl1251 TX path implementation into chip specific files Moved wl1251 TX path implementation into chip specific files to enable parallel implementation for the wl1271 TX path. Signed-off-by: Juuso Oikarinen Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index d43de27..7e05ea3 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,4 +1,4 @@ -wl12xx-objs = main.o spi.o event.o tx.o rx.o \ - ps.o cmd.o acx.o boot.o init.o wl1251.o \ +wl12xx-objs = main.o spi.o event.o wl1251_tx.o rx.o \ + ps.o cmd.o acx.o boot.o init.o wl1251.o \ debugfs.o obj-$(CONFIG_WL12XX) += wl12xx.o diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 73232db..8feba36 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -37,7 +37,7 @@ #include "wl1251.h" #include "spi.h" #include "event.h" -#include "tx.h" +#include "wl1251_tx.h" #include "rx.h" #include "ps.h" #include "init.h" @@ -303,6 +303,11 @@ static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) skb_queue_tail(&wl->tx_queue, skb); + /* + * The chip specific setup must run before the first TX packet - + * before that, the tx_work will not be initialized! + */ + schedule_work(&wl->tx_work); /* @@ -400,8 +405,7 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw) mutex_lock(&wl->mutex); /* let's notify MAC80211 about the remaining pending TX frames */ - wl12xx_tx_flush(wl); - + wl->chip.op_tx_flush(wl); wl12xx_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); @@ -1176,7 +1180,7 @@ static int wl12xx_init_ieee80211(struct wl12xx *wl) { /* The tx descriptor buffer and the TKIP space */ wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) - + WL12XX_TKIP_IV_SPACE; + + WL1251_TKIP_IV_SPACE; /* unit us */ /* FIXME: find a proper value */ @@ -1226,7 +1230,6 @@ static int __devinit wl12xx_probe(struct spi_device *spi) skb_queue_head_init(&wl->tx_queue); - INIT_WORK(&wl->tx_work, wl12xx_tx_work); INIT_WORK(&wl->filter_work, wl12xx_filter_work); wl->channel = WL12XX_DEFAULT_CHANNEL; wl->scanning = false; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c deleted file mode 100644 index 62145e2..0000000 --- a/drivers/net/wireless/wl12xx/tx.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "wl12xx.h" -#include "reg.h" -#include "spi.h" -#include "tx.h" -#include "ps.h" - -static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) -{ - int used, data_in_count; - - data_in_count = wl->data_in_count; - - if (data_in_count < data_out_count) - /* data_in_count has wrapped */ - data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; - - used = data_in_count - data_out_count; - - WARN_ON(used < 0); - WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); - - if (used >= DP_TX_PACKET_RING_CHUNK_NUM) - return true; - else - return false; -} - -static int wl12xx_tx_path_status(struct wl12xx *wl) -{ - u32 status, addr, data_out_count; - bool busy; - - addr = wl->data_path->tx_control_addr; - status = wl12xx_mem_read32(wl, addr); - data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; - busy = wl12xx_tx_double_buffer_busy(wl, data_out_count); - - if (busy) - return -EBUSY; - - return 0; -} - -static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb) -{ - int i; - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - if (wl->tx_frames[i] == NULL) { - wl->tx_frames[i] = skb; - return i; - } - - return -EBUSY; -} - -static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr, - struct ieee80211_tx_info *control, u16 fc) -{ - *(u16 *)&tx_hdr->control = 0; - - tx_hdr->control.rate_policy = 0; - - /* 802.11 packets */ - tx_hdr->control.packet_type = 0; - - if (control->flags & IEEE80211_TX_CTL_NO_ACK) - tx_hdr->control.ack_policy = 1; - - tx_hdr->control.tx_complete = 1; - - if ((fc & IEEE80211_FTYPE_DATA) && - ((fc & IEEE80211_STYPE_QOS_DATA) || - (fc & IEEE80211_STYPE_QOS_NULLFUNC))) - tx_hdr->control.qos = 1; -} - -/* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ -#define MAX_MSDU_SECURITY_LENGTH 16 -#define MAX_MPDU_SECURITY_LENGTH 16 -#define WLAN_QOS_HDR_LEN 26 -#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ - WLAN_QOS_HDR_LEN) -#define HW_BLOCK_SIZE 252 -static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) -{ - u16 payload_len, frag_threshold, mem_blocks; - u16 num_mpdus, mem_blocks_per_frag; - - frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); - - payload_len = tx_hdr->length + MAX_MSDU_SECURITY_LENGTH; - - if (payload_len > frag_threshold) { - mem_blocks_per_frag = - ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / - HW_BLOCK_SIZE) + 1; - num_mpdus = payload_len / frag_threshold; - mem_blocks = num_mpdus * mem_blocks_per_frag; - payload_len -= num_mpdus * frag_threshold; - num_mpdus++; - - } else { - mem_blocks_per_frag = 0; - mem_blocks = 0; - num_mpdus = 1; - } - - mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; - - if (num_mpdus > 1) - mem_blocks += min(num_mpdus, mem_blocks_per_frag); - - tx_hdr->num_mem_blocks = mem_blocks; -} - -static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb, - struct ieee80211_tx_info *control) -{ - struct tx_double_buffer_desc *tx_hdr; - struct ieee80211_rate *rate; - int id; - u16 fc; - - if (!skb) - return -EINVAL; - - id = wl12xx_tx_id(wl, skb); - if (id < 0) - return id; - - fc = *(u16 *)skb->data; - tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, - sizeof(*tx_hdr)); - - tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); - rate = ieee80211_get_tx_rate(wl->hw, control); - tx_hdr->rate = cpu_to_le16(rate->hw_value); - tx_hdr->expiry_time = cpu_to_le32(1 << 16); - tx_hdr->id = id; - - /* FIXME: how to get the correct queue id? */ - tx_hdr->xmit_queue = 0; - - wl12xx_tx_control(tx_hdr, control, fc); - wl12xx_tx_frag_block_num(tx_hdr); - - return 0; -} - -/* We copy the packet to the target */ -static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, - struct ieee80211_tx_info *control) -{ - struct tx_double_buffer_desc *tx_hdr; - int len; - u32 addr; - - if (!skb) - return -EINVAL; - - tx_hdr = (struct tx_double_buffer_desc *) skb->data; - - if (control->control.hw_key && - control->control.hw_key->alg == ALG_TKIP) { - int hdrlen; - u16 fc; - u8 *pos; - - fc = *(u16 *)(skb->data + sizeof(*tx_hdr)); - tx_hdr->length += WL12XX_TKIP_IV_SPACE; - - hdrlen = ieee80211_hdrlen(fc); - - pos = skb_push(skb, WL12XX_TKIP_IV_SPACE); - memmove(pos, pos + WL12XX_TKIP_IV_SPACE, - sizeof(*tx_hdr) + hdrlen); - } - - /* Revisit. This is a workaround for getting non-aligned packets. - This happens at least with EAPOL packets from the user space. - Our DMA requires packets to be aligned on a 4-byte boundary. - */ - if (unlikely((long)skb->data & 0x03)) { - int offset = (4 - (long)skb->data) & 0x03; - wl12xx_debug(DEBUG_TX, "skb offset %d", offset); - - /* check whether the current skb can be used */ - if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { - unsigned char *src = skb->data; - - /* align the buffer on a 4-byte boundary */ - skb_reserve(skb, offset); - memmove(skb->data, src, skb->len); - } else { - wl12xx_info("No handler, fixme!"); - return -EINVAL; - } - } - - /* Our skb->data at this point includes the HW header */ - len = WL12XX_TX_ALIGN(skb->len); - - if (wl->data_in_count & 0x1) - addr = wl->data_path->tx_packet_ring_addr + - wl->data_path->tx_packet_ring_chunk_size; - else - addr = wl->data_path->tx_packet_ring_addr; - - wl12xx_spi_mem_write(wl, addr, skb->data, len); - - wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", - tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); - - return 0; -} - -static void wl12xx_tx_trigger(struct wl12xx *wl) -{ - u32 data, addr; - - if (wl->data_in_count & 0x1) { - addr = ACX_REG_INTERRUPT_TRIG_H; - data = INTR_TRIG_TX_PROC1; - } else { - addr = ACX_REG_INTERRUPT_TRIG; - data = INTR_TRIG_TX_PROC0; - } - - wl12xx_reg_write32(wl, addr, data); - - /* Bumping data in */ - wl->data_in_count = (wl->data_in_count + 1) & - TX_STATUS_DATA_OUT_COUNT_MASK; -} - -/* caller must hold wl->mutex */ -static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info; - int ret = 0; - u8 idx; - - info = IEEE80211_SKB_CB(skb); - - if (info->control.hw_key) { - idx = info->control.hw_key->hw_key_idx; - if (unlikely(wl->default_key != idx)) { - ret = wl12xx_acx_default_key(wl, idx); - if (ret < 0) - return ret; - } - } - - ret = wl12xx_tx_path_status(wl); - if (ret < 0) - return ret; - - ret = wl12xx_tx_fill_hdr(wl, skb, info); - if (ret < 0) - return ret; - - ret = wl12xx_tx_send_packet(wl, skb, info); - if (ret < 0) - return ret; - - wl12xx_tx_trigger(wl); - - return ret; -} - -void wl12xx_tx_work(struct work_struct *work) -{ - struct wl12xx *wl = container_of(work, struct wl12xx, tx_work); - struct sk_buff *skb; - bool woken_up = false; - int ret; - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL12XX_STATE_OFF)) - goto out; - - while ((skb = skb_dequeue(&wl->tx_queue))) { - if (!woken_up) { - wl12xx_ps_elp_wakeup(wl); - woken_up = true; - } - - ret = wl12xx_tx_frame(wl, skb); - if (ret == -EBUSY) { - /* firmware buffer is full, stop queues */ - wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, " - "stop queues"); - ieee80211_stop_queues(wl->hw); - wl->tx_queue_stopped = true; - skb_queue_head(&wl->tx_queue, skb); - goto out; - } else if (ret < 0) { - dev_kfree_skb(skb); - goto out; - } - } - -out: - if (woken_up) - wl12xx_ps_elp_sleep(wl); - - mutex_unlock(&wl->mutex); -} - -static const char *wl12xx_tx_parse_status(u8 status) -{ - /* 8 bit status field, one character per bit plus null */ - static char buf[9]; - int i = 0; - - memset(buf, 0, sizeof(buf)); - - if (status & TX_DMA_ERROR) - buf[i++] = 'm'; - if (status & TX_DISABLED) - buf[i++] = 'd'; - if (status & TX_RETRY_EXCEEDED) - buf[i++] = 'r'; - if (status & TX_TIMEOUT) - buf[i++] = 't'; - if (status & TX_KEY_NOT_FOUND) - buf[i++] = 'k'; - if (status & TX_ENCRYPT_FAIL) - buf[i++] = 'e'; - if (status & TX_UNAVAILABLE_PRIORITY) - buf[i++] = 'p'; - - /* bit 0 is unused apparently */ - - return buf; -} - -static void wl12xx_tx_packet_cb(struct wl12xx *wl, - struct tx_result *result) -{ - struct ieee80211_tx_info *info; - struct sk_buff *skb; - int hdrlen, ret; - u8 *frame; - - skb = wl->tx_frames[result->id]; - if (skb == NULL) { - wl12xx_error("SKB for packet %d is NULL", result->id); - return; - } - - info = IEEE80211_SKB_CB(skb); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (result->status == TX_SUCCESS)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.rates[0].count = result->ack_failures + 1; - wl->stats.retry_count += result->ack_failures; - - /* - * We have to remove our private TX header before pushing - * the skb back to mac80211. - */ - frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); - if (info->control.hw_key && - info->control.hw_key->alg == ALG_TKIP) { - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - memmove(frame + WL12XX_TKIP_IV_SPACE, frame, hdrlen); - skb_pull(skb, WL12XX_TKIP_IV_SPACE); - } - - wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" - " status 0x%x (%s)", - result->id, skb, result->ack_failures, result->rate, - result->status, wl12xx_tx_parse_status(result->status)); - - - ieee80211_tx_status(wl->hw, skb); - - wl->tx_frames[result->id] = NULL; - - if (wl->tx_queue_stopped) { - wl12xx_debug(DEBUG_TX, "cb: queue was stopped"); - - skb = skb_dequeue(&wl->tx_queue); - - /* The skb can be NULL because tx_work might have been - scheduled before the queue was stopped making the - queue empty */ - - if (skb) { - ret = wl12xx_tx_frame(wl, skb); - if (ret == -EBUSY) { - /* firmware buffer is still full */ - wl12xx_debug(DEBUG_TX, "cb: fw buffer " - "still full"); - skb_queue_head(&wl->tx_queue, skb); - return; - } else if (ret < 0) { - dev_kfree_skb(skb); - return; - } - } - - wl12xx_debug(DEBUG_TX, "cb: waking queues"); - ieee80211_wake_queues(wl->hw); - wl->tx_queue_stopped = false; - } -} - -/* Called upon reception of a TX complete interrupt */ -void wl12xx_tx_complete(struct wl12xx *wl) -{ - int i, result_index, num_complete = 0; - struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; - - if (unlikely(wl->state != WL12XX_STATE_ON)) - return; - - /* First we read the result */ - wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr, - result, sizeof(result)); - - result_index = wl->next_tx_complete; - - for (i = 0; i < ARRAY_SIZE(result); i++) { - result_ptr = &result[result_index]; - - if (result_ptr->done_1 == 1 && - result_ptr->done_2 == 1) { - wl12xx_tx_packet_cb(wl, result_ptr); - - result_ptr->done_1 = 0; - result_ptr->done_2 = 0; - - result_index = (result_index + 1) & - (FW_TX_CMPLT_BLOCK_SIZE - 1); - num_complete++; - } else { - break; - } - } - - /* Every completed frame needs to be acknowledged */ - if (num_complete) { - /* - * If we've wrapped, we have to clear - * the results in 2 steps. - */ - if (result_index > wl->next_tx_complete) { - /* Only 1 write is needed */ - wl12xx_spi_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - num_complete * - sizeof(struct tx_result)); - - - } else if (result_index < wl->next_tx_complete) { - /* 2 writes are needed */ - wl12xx_spi_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - (FW_TX_CMPLT_BLOCK_SIZE - - wl->next_tx_complete) * - sizeof(struct tx_result)); - - wl12xx_spi_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - (num_complete - - FW_TX_CMPLT_BLOCK_SIZE + - wl->next_tx_complete) * - sizeof(struct tx_result)); - - } else { - /* We have to write the whole array */ - wl12xx_spi_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - FW_TX_CMPLT_BLOCK_SIZE * - sizeof(struct tx_result)); - } - - } - - wl->next_tx_complete = result_index; -} - -/* caller must hold wl->mutex */ -void wl12xx_tx_flush(struct wl12xx *wl) -{ - int i; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - - /* TX failure */ -/* control->flags = 0; FIXME */ - - while ((skb = skb_dequeue(&wl->tx_queue))) { - info = IEEE80211_SKB_CB(skb); - - wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb); - - if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) - continue; - - ieee80211_tx_status(wl->hw, skb); - } - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - if (wl->tx_frames[i] != NULL) { - skb = wl->tx_frames[i]; - info = IEEE80211_SKB_CB(skb); - - if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) - continue; - - ieee80211_tx_status(wl->hw, skb); - wl->tx_frames[i] = NULL; - } -} diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h deleted file mode 100644 index dc82691..0000000 --- a/drivers/net/wireless/wl12xx/tx.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_TX_H__ -#define __WL12XX_TX_H__ - -#include - -/* - * - * TX PATH - * - * The Tx path uses a double buffer and a tx_control structure, each located - * at a fixed address in the device's memory. On startup, the host retrieves - * the pointers to these addresses. A double buffer allows for continuous data - * flow towards the device. The host keeps track of which buffer is available - * and alternates between these two buffers on a per packet basis. - * - * The size of each of the two buffers is large enough to hold the longest - * 802.3 packet - maximum size Ethernet packet + header + descriptor. - * TX complete indication will be received a-synchronously in a TX done cyclic - * buffer which is composed of 16 tx_result descriptors structures and is used - * in a cyclic manner. - * - * The TX (HOST) procedure is as follows: - * 1. Read the Tx path status, that will give the data_out_count. - * 2. goto 1, if not possible. - * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double - * buffer). - * 3. Copy the packet (preceded by double_buffer_desc), if possible. - * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double - * buffer). - * 4. increment data_in_count. - * 5. Inform the firmware by generating a firmware internal interrupt. - * 6. FW will increment data_out_count after it reads the buffer. - * - * The TX Complete procedure: - * 1. To get a TX complete indication the host enables the tx_complete flag in - * the TX descriptor Structure. - * 2. For each packet with a Tx Complete field set, the firmware adds the - * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 - * and done_2 to 1 to indicate driver ownership. - * 3. The firmware sends a Tx Complete interrupt to the host to trigger the - * host to process the new data. Note: interrupt will be send per packet if - * TX complete indication was requested in tx_control or per crossing - * aggregation threshold. - * 4. After receiving the Tx Complete interrupt, the host reads the - * TxDescriptorDone information in a cyclic manner and clears both done_1 - * and done_2 fields. - * - */ - -#define TX_COMPLETE_REQUIRED_BIT 0x80 -#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf -#define WL12XX_TX_ALIGN_TO 4 -#define WL12XX_TX_ALIGN(len) (((len) + WL12XX_TX_ALIGN_TO - 1) & \ - ~(WL12XX_TX_ALIGN_TO - 1)) -#define WL12XX_TKIP_IV_SPACE 4 - -struct tx_control { - /* Rate Policy (class) index */ - unsigned rate_policy:3; - - /* When set, no ack policy is expected */ - unsigned ack_policy:1; - - /* - * Packet type: - * 0 -> 802.11 - * 1 -> 802.3 - * 2 -> IP - * 3 -> raw codec - */ - unsigned packet_type:2; - - /* If set, this is a QoS-Null or QoS-Data frame */ - unsigned qos:1; - - /* - * If set, the target triggers the tx complete INT - * upon frame sending completion. - */ - unsigned tx_complete:1; - - /* 2 bytes padding before packet header */ - unsigned xfer_pad:1; - - unsigned reserved:7; -} __attribute__ ((packed)); - - -struct tx_double_buffer_desc { - /* Length of payload, including headers. */ - u16 length; - - /* - * A bit mask that specifies the initial rate to be used - * Possible values are: - * 0x0001 - 1Mbits - * 0x0002 - 2Mbits - * 0x0004 - 5.5Mbits - * 0x0008 - 6Mbits - * 0x0010 - 9Mbits - * 0x0020 - 11Mbits - * 0x0040 - 12Mbits - * 0x0080 - 18Mbits - * 0x0100 - 22Mbits - * 0x0200 - 24Mbits - * 0x0400 - 36Mbits - * 0x0800 - 48Mbits - * 0x1000 - 54Mbits - */ - u16 rate; - - /* Time in us that a packet can spend in the target */ - u32 expiry_time; - - /* index of the TX queue used for this packet */ - u8 xmit_queue; - - /* Used to identify a packet */ - u8 id; - - struct tx_control control; - - /* - * The FW should cut the packet into fragments - * of this size. - */ - u16 frag_threshold; - - /* Numbers of HW queue blocks to be allocated */ - u8 num_mem_blocks; - - u8 reserved; -} __attribute__ ((packed)); - -enum { - TX_SUCCESS = 0, - TX_DMA_ERROR = BIT(7), - TX_DISABLED = BIT(6), - TX_RETRY_EXCEEDED = BIT(5), - TX_TIMEOUT = BIT(4), - TX_KEY_NOT_FOUND = BIT(3), - TX_ENCRYPT_FAIL = BIT(2), - TX_UNAVAILABLE_PRIORITY = BIT(1), -}; - -struct tx_result { - /* - * Ownership synchronization between the host and - * the firmware. If done_1 and done_2 are cleared, - * owned by the FW (no info ready). - */ - u8 done_1; - - /* same as double_buffer_desc->id */ - u8 id; - - /* - * Total air access duration consumed by this - * packet, including all retries and overheads. - */ - u16 medium_usage; - - /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ - u32 medium_delay; - - /* Time between host xfer and tx complete */ - u32 fw_hnadling_time; - - /* The LS-byte of the last TKIP sequence number. */ - u8 lsb_seq_num; - - /* Retry count */ - u8 ack_failures; - - /* At which rate we got a ACK */ - u16 rate; - - u16 reserved; - - /* TX_* */ - u8 status; - - /* See done_1 */ - u8 done_2; -} __attribute__ ((packed)); - -void wl12xx_tx_work(struct work_struct *work); -void wl12xx_tx_complete(struct wl12xx *wl); -void wl12xx_tx_flush(struct wl12xx *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index b793325..903624a 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -30,7 +30,7 @@ #include "boot.h" #include "event.h" #include "acx.h" -#include "tx.h" +#include "wl1251_tx.h" #include "rx.h" #include "ps.h" #include "init.h" @@ -471,7 +471,7 @@ static void wl1251_irq_work(struct work_struct *work) if (intr & WL1251_ACX_INTR_TX_RESULT) { wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); - wl12xx_tx_complete(wl); + wl1251_tx_complete(wl); } if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { @@ -712,9 +712,12 @@ void wl1251_setup(struct wl12xx *wl) wl->chip.op_hw_init = wl1251_hw_init; wl->chip.op_plt_init = wl1251_plt_init; wl->chip.op_fw_version = wl1251_fw_version; + wl->chip.op_tx_flush = wl1251_tx_flush; wl->chip.p_table = wl1251_part_table; wl->chip.acx_reg_table = wl1251_acx_reg_table; INIT_WORK(&wl->irq_work, wl1251_irq_work); + INIT_WORK(&wl->tx_work, wl1251_tx_work); + } diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c new file mode 100644 index 0000000..c42c43d --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -0,0 +1,557 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl12xx.h" +#include "reg.h" +#include "spi.h" +#include "wl1251_tx.h" +#include "ps.h" + +static bool wl1251_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) +{ + int used, data_in_count; + + data_in_count = wl->data_in_count; + + if (data_in_count < data_out_count) + /* data_in_count has wrapped */ + data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; + + used = data_in_count - data_out_count; + + WARN_ON(used < 0); + WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); + + if (used >= DP_TX_PACKET_RING_CHUNK_NUM) + return true; + else + return false; +} + +static int wl1251_tx_path_status(struct wl12xx *wl) +{ + u32 status, addr, data_out_count; + bool busy; + + addr = wl->data_path->tx_control_addr; + status = wl12xx_mem_read32(wl, addr); + data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; + busy = wl1251_tx_double_buffer_busy(wl, data_out_count); + + if (busy) + return -EBUSY; + + return 0; +} + +static int wl1251_tx_id(struct wl12xx *wl, struct sk_buff *skb) +{ + int i; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] == NULL) { + wl->tx_frames[i] = skb; + return i; + } + + return -EBUSY; +} + +static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr, + struct ieee80211_tx_info *control, u16 fc) +{ + *(u16 *)&tx_hdr->control = 0; + + tx_hdr->control.rate_policy = 0; + + /* 802.11 packets */ + tx_hdr->control.packet_type = 0; + + if (control->flags & IEEE80211_TX_CTL_NO_ACK) + tx_hdr->control.ack_policy = 1; + + tx_hdr->control.tx_complete = 1; + + if ((fc & IEEE80211_FTYPE_DATA) && + ((fc & IEEE80211_STYPE_QOS_DATA) || + (fc & IEEE80211_STYPE_QOS_NULLFUNC))) + tx_hdr->control.qos = 1; +} + +/* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ +#define MAX_MSDU_SECURITY_LENGTH 16 +#define MAX_MPDU_SECURITY_LENGTH 16 +#define WLAN_QOS_HDR_LEN 26 +#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ + WLAN_QOS_HDR_LEN) +#define HW_BLOCK_SIZE 252 +static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) +{ + u16 payload_len, frag_threshold, mem_blocks; + u16 num_mpdus, mem_blocks_per_frag; + + frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; + tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); + + payload_len = tx_hdr->length + MAX_MSDU_SECURITY_LENGTH; + + if (payload_len > frag_threshold) { + mem_blocks_per_frag = + ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / + HW_BLOCK_SIZE) + 1; + num_mpdus = payload_len / frag_threshold; + mem_blocks = num_mpdus * mem_blocks_per_frag; + payload_len -= num_mpdus * frag_threshold; + num_mpdus++; + + } else { + mem_blocks_per_frag = 0; + mem_blocks = 0; + num_mpdus = 1; + } + + mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; + + if (num_mpdus > 1) + mem_blocks += min(num_mpdus, mem_blocks_per_frag); + + tx_hdr->num_mem_blocks = mem_blocks; +} + +static int wl1251_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + struct tx_double_buffer_desc *tx_hdr; + struct ieee80211_rate *rate; + int id; + u16 fc; + + if (!skb) + return -EINVAL; + + id = wl1251_tx_id(wl, skb); + if (id < 0) + return id; + + fc = *(u16 *)skb->data; + tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, + sizeof(*tx_hdr)); + + tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); + rate = ieee80211_get_tx_rate(wl->hw, control); + tx_hdr->rate = cpu_to_le16(rate->hw_value); + tx_hdr->expiry_time = cpu_to_le32(1 << 16); + tx_hdr->id = id; + + /* FIXME: how to get the correct queue id? */ + tx_hdr->xmit_queue = 0; + + wl1251_tx_control(tx_hdr, control, fc); + wl1251_tx_frag_block_num(tx_hdr); + + return 0; +} + +/* We copy the packet to the target */ +static int wl1251_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + struct tx_double_buffer_desc *tx_hdr; + int len; + u32 addr; + + if (!skb) + return -EINVAL; + + tx_hdr = (struct tx_double_buffer_desc *) skb->data; + + if (control->control.hw_key && + control->control.hw_key->alg == ALG_TKIP) { + int hdrlen; + u16 fc; + u8 *pos; + + fc = *(u16 *)(skb->data + sizeof(*tx_hdr)); + tx_hdr->length += WL1251_TKIP_IV_SPACE; + + hdrlen = ieee80211_hdrlen(fc); + + pos = skb_push(skb, WL1251_TKIP_IV_SPACE); + memmove(pos, pos + WL1251_TKIP_IV_SPACE, + sizeof(*tx_hdr) + hdrlen); + } + + /* Revisit. This is a workaround for getting non-aligned packets. + This happens at least with EAPOL packets from the user space. + Our DMA requires packets to be aligned on a 4-byte boundary. + */ + if (unlikely((long)skb->data & 0x03)) { + int offset = (4 - (long)skb->data) & 0x03; + wl12xx_debug(DEBUG_TX, "skb offset %d", offset); + + /* check whether the current skb can be used */ + if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { + unsigned char *src = skb->data; + + /* align the buffer on a 4-byte boundary */ + skb_reserve(skb, offset); + memmove(skb->data, src, skb->len); + } else { + wl12xx_info("No handler, fixme!"); + return -EINVAL; + } + } + + /* Our skb->data at this point includes the HW header */ + len = WL1251_TX_ALIGN(skb->len); + + if (wl->data_in_count & 0x1) + addr = wl->data_path->tx_packet_ring_addr + + wl->data_path->tx_packet_ring_chunk_size; + else + addr = wl->data_path->tx_packet_ring_addr; + + wl12xx_spi_mem_write(wl, addr, skb->data, len); + + wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", + tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); + + return 0; +} + +static void wl1251_tx_trigger(struct wl12xx *wl) +{ + u32 data, addr; + + if (wl->data_in_count & 0x1) { + addr = ACX_REG_INTERRUPT_TRIG_H; + data = INTR_TRIG_TX_PROC1; + } else { + addr = ACX_REG_INTERRUPT_TRIG; + data = INTR_TRIG_TX_PROC0; + } + + wl12xx_reg_write32(wl, addr, data); + + /* Bumping data in */ + wl->data_in_count = (wl->data_in_count + 1) & + TX_STATUS_DATA_OUT_COUNT_MASK; +} + +/* caller must hold wl->mutex */ +static int wl1251_tx_frame(struct wl12xx *wl, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info; + int ret = 0; + u8 idx; + + info = IEEE80211_SKB_CB(skb); + + if (info->control.hw_key) { + idx = info->control.hw_key->hw_key_idx; + if (unlikely(wl->default_key != idx)) { + ret = wl12xx_acx_default_key(wl, idx); + if (ret < 0) + return ret; + } + } + + ret = wl1251_tx_path_status(wl); + if (ret < 0) + return ret; + + ret = wl1251_tx_fill_hdr(wl, skb, info); + if (ret < 0) + return ret; + + ret = wl1251_tx_send_packet(wl, skb, info); + if (ret < 0) + return ret; + + wl1251_tx_trigger(wl); + + return ret; +} + +void wl1251_tx_work(struct work_struct *work) +{ + struct wl12xx *wl = container_of(work, struct wl12xx, tx_work); + struct sk_buff *skb; + bool woken_up = false; + int ret; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL12XX_STATE_OFF)) + goto out; + + while ((skb = skb_dequeue(&wl->tx_queue))) { + if (!woken_up) { + wl12xx_ps_elp_wakeup(wl); + woken_up = true; + } + + ret = wl1251_tx_frame(wl, skb); + if (ret == -EBUSY) { + /* firmware buffer is full, stop queues */ + wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, " + "stop queues"); + ieee80211_stop_queues(wl->hw); + wl->tx_queue_stopped = true; + skb_queue_head(&wl->tx_queue, skb); + goto out; + } else if (ret < 0) { + dev_kfree_skb(skb); + goto out; + } + } + +out: + if (woken_up) + wl12xx_ps_elp_sleep(wl); + + mutex_unlock(&wl->mutex); +} + +static const char *wl1251_tx_parse_status(u8 status) +{ + /* 8 bit status field, one character per bit plus null */ + static char buf[9]; + int i = 0; + + memset(buf, 0, sizeof(buf)); + + if (status & TX_DMA_ERROR) + buf[i++] = 'm'; + if (status & TX_DISABLED) + buf[i++] = 'd'; + if (status & TX_RETRY_EXCEEDED) + buf[i++] = 'r'; + if (status & TX_TIMEOUT) + buf[i++] = 't'; + if (status & TX_KEY_NOT_FOUND) + buf[i++] = 'k'; + if (status & TX_ENCRYPT_FAIL) + buf[i++] = 'e'; + if (status & TX_UNAVAILABLE_PRIORITY) + buf[i++] = 'p'; + + /* bit 0 is unused apparently */ + + return buf; +} + +static void wl1251_tx_packet_cb(struct wl12xx *wl, + struct tx_result *result) +{ + struct ieee80211_tx_info *info; + struct sk_buff *skb; + int hdrlen, ret; + u8 *frame; + + skb = wl->tx_frames[result->id]; + if (skb == NULL) { + wl12xx_error("SKB for packet %d is NULL", result->id); + return; + } + + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (result->status == TX_SUCCESS)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = result->ack_failures + 1; + wl->stats.retry_count += result->ack_failures; + + /* + * We have to remove our private TX header before pushing + * the skb back to mac80211. + */ + frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); + if (info->control.hw_key && + info->control.hw_key->alg == ALG_TKIP) { + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen); + skb_pull(skb, WL1251_TKIP_IV_SPACE); + } + + wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" + " status 0x%x (%s)", + result->id, skb, result->ack_failures, result->rate, + result->status, wl1251_tx_parse_status(result->status)); + + + ieee80211_tx_status(wl->hw, skb); + + wl->tx_frames[result->id] = NULL; + + if (wl->tx_queue_stopped) { + wl12xx_debug(DEBUG_TX, "cb: queue was stopped"); + + skb = skb_dequeue(&wl->tx_queue); + + /* The skb can be NULL because tx_work might have been + scheduled before the queue was stopped making the + queue empty */ + + if (skb) { + ret = wl1251_tx_frame(wl, skb); + if (ret == -EBUSY) { + /* firmware buffer is still full */ + wl12xx_debug(DEBUG_TX, "cb: fw buffer " + "still full"); + skb_queue_head(&wl->tx_queue, skb); + return; + } else if (ret < 0) { + dev_kfree_skb(skb); + return; + } + } + + wl12xx_debug(DEBUG_TX, "cb: waking queues"); + ieee80211_wake_queues(wl->hw); + wl->tx_queue_stopped = false; + } +} + +/* Called upon reception of a TX complete interrupt */ +void wl1251_tx_complete(struct wl12xx *wl) +{ + int i, result_index, num_complete = 0; + struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; + + if (unlikely(wl->state != WL12XX_STATE_ON)) + return; + + /* First we read the result */ + wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr, + result, sizeof(result)); + + result_index = wl->next_tx_complete; + + for (i = 0; i < ARRAY_SIZE(result); i++) { + result_ptr = &result[result_index]; + + if (result_ptr->done_1 == 1 && + result_ptr->done_2 == 1) { + wl1251_tx_packet_cb(wl, result_ptr); + + result_ptr->done_1 = 0; + result_ptr->done_2 = 0; + + result_index = (result_index + 1) & + (FW_TX_CMPLT_BLOCK_SIZE - 1); + num_complete++; + } else { + break; + } + } + + /* Every completed frame needs to be acknowledged */ + if (num_complete) { + /* + * If we've wrapped, we have to clear + * the results in 2 steps. + */ + if (result_index > wl->next_tx_complete) { + /* Only 1 write is needed */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + num_complete * + sizeof(struct tx_result)); + + + } else if (result_index < wl->next_tx_complete) { + /* 2 writes are needed */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + (FW_TX_CMPLT_BLOCK_SIZE - + wl->next_tx_complete) * + sizeof(struct tx_result)); + + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + (num_complete - + FW_TX_CMPLT_BLOCK_SIZE + + wl->next_tx_complete) * + sizeof(struct tx_result)); + + } else { + /* We have to write the whole array */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + FW_TX_CMPLT_BLOCK_SIZE * + sizeof(struct tx_result)); + } + + } + + wl->next_tx_complete = result_index; +} + +/* caller must hold wl->mutex */ +void wl1251_tx_flush(struct wl12xx *wl) +{ + int i; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + + /* TX failure */ +/* control->flags = 0; FIXME */ + + while ((skb = skb_dequeue(&wl->tx_queue))) { + info = IEEE80211_SKB_CB(skb); + + wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + } + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] != NULL) { + skb = wl->tx_frames[i]; + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + wl->tx_frames[i] = NULL; + } +} diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h new file mode 100644 index 0000000..a5d4c82 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_tx.h @@ -0,0 +1,216 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_TX_H__ +#define __WL1251_TX_H__ + +#include + +/* + * + * TX PATH + * + * The Tx path uses a double buffer and a tx_control structure, each located + * at a fixed address in the device's memory. On startup, the host retrieves + * the pointers to these addresses. A double buffer allows for continuous data + * flow towards the device. The host keeps track of which buffer is available + * and alternates between these two buffers on a per packet basis. + * + * The size of each of the two buffers is large enough to hold the longest + * 802.3 packet - maximum size Ethernet packet + header + descriptor. + * TX complete indication will be received a-synchronously in a TX done cyclic + * buffer which is composed of 16 tx_result descriptors structures and is used + * in a cyclic manner. + * + * The TX (HOST) procedure is as follows: + * 1. Read the Tx path status, that will give the data_out_count. + * 2. goto 1, if not possible. + * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double + * buffer). + * 3. Copy the packet (preceded by double_buffer_desc), if possible. + * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double + * buffer). + * 4. increment data_in_count. + * 5. Inform the firmware by generating a firmware internal interrupt. + * 6. FW will increment data_out_count after it reads the buffer. + * + * The TX Complete procedure: + * 1. To get a TX complete indication the host enables the tx_complete flag in + * the TX descriptor Structure. + * 2. For each packet with a Tx Complete field set, the firmware adds the + * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 + * and done_2 to 1 to indicate driver ownership. + * 3. The firmware sends a Tx Complete interrupt to the host to trigger the + * host to process the new data. Note: interrupt will be send per packet if + * TX complete indication was requested in tx_control or per crossing + * aggregation threshold. + * 4. After receiving the Tx Complete interrupt, the host reads the + * TxDescriptorDone information in a cyclic manner and clears both done_1 + * and done_2 fields. + * + */ + +#define TX_COMPLETE_REQUIRED_BIT 0x80 +#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf + +#define WL1251_TX_ALIGN_TO 4 +#define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \ + ~(WL1251_TX_ALIGN_TO - 1)) +#define WL1251_TKIP_IV_SPACE 4 + +struct tx_control { + /* Rate Policy (class) index */ + unsigned rate_policy:3; + + /* When set, no ack policy is expected */ + unsigned ack_policy:1; + + /* + * Packet type: + * 0 -> 802.11 + * 1 -> 802.3 + * 2 -> IP + * 3 -> raw codec + */ + unsigned packet_type:2; + + /* If set, this is a QoS-Null or QoS-Data frame */ + unsigned qos:1; + + /* + * If set, the target triggers the tx complete INT + * upon frame sending completion. + */ + unsigned tx_complete:1; + + /* 2 bytes padding before packet header */ + unsigned xfer_pad:1; + + unsigned reserved:7; +} __attribute__ ((packed)); + + +struct tx_double_buffer_desc { + /* Length of payload, including headers. */ + u16 length; + + /* + * A bit mask that specifies the initial rate to be used + * Possible values are: + * 0x0001 - 1Mbits + * 0x0002 - 2Mbits + * 0x0004 - 5.5Mbits + * 0x0008 - 6Mbits + * 0x0010 - 9Mbits + * 0x0020 - 11Mbits + * 0x0040 - 12Mbits + * 0x0080 - 18Mbits + * 0x0100 - 22Mbits + * 0x0200 - 24Mbits + * 0x0400 - 36Mbits + * 0x0800 - 48Mbits + * 0x1000 - 54Mbits + */ + u16 rate; + + /* Time in us that a packet can spend in the target */ + u32 expiry_time; + + /* index of the TX queue used for this packet */ + u8 xmit_queue; + + /* Used to identify a packet */ + u8 id; + + struct tx_control control; + + /* + * The FW should cut the packet into fragments + * of this size. + */ + u16 frag_threshold; + + /* Numbers of HW queue blocks to be allocated */ + u8 num_mem_blocks; + + u8 reserved; +} __attribute__ ((packed)); + +enum { + TX_SUCCESS = 0, + TX_DMA_ERROR = BIT(7), + TX_DISABLED = BIT(6), + TX_RETRY_EXCEEDED = BIT(5), + TX_TIMEOUT = BIT(4), + TX_KEY_NOT_FOUND = BIT(3), + TX_ENCRYPT_FAIL = BIT(2), + TX_UNAVAILABLE_PRIORITY = BIT(1), +}; + +struct tx_result { + /* + * Ownership synchronization between the host and + * the firmware. If done_1 and done_2 are cleared, + * owned by the FW (no info ready). + */ + u8 done_1; + + /* same as double_buffer_desc->id */ + u8 id; + + /* + * Total air access duration consumed by this + * packet, including all retries and overheads. + */ + u16 medium_usage; + + /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ + u32 medium_delay; + + /* Time between host xfer and tx complete */ + u32 fw_hnadling_time; + + /* The LS-byte of the last TKIP sequence number. */ + u8 lsb_seq_num; + + /* Retry count */ + u8 ack_failures; + + /* At which rate we got a ACK */ + u16 rate; + + u16 reserved; + + /* TX_* */ + u8 status; + + /* See done_1 */ + u8 done_2; +} __attribute__ ((packed)); + +void wl1251_tx_work(struct work_struct *work); +void wl1251_tx_complete(struct wl12xx *wl); +void wl1251_tx_flush(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index c1d00c01..c38aa54 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -163,6 +163,7 @@ struct wl12xx_chip { void (*op_target_enable_interrupts)(struct wl12xx *wl); int (*op_hw_init)(struct wl12xx *wl); int (*op_plt_init)(struct wl12xx *wl); + void (*op_tx_flush)(struct wl12xx *wl); void (*op_fw_version)(struct wl12xx *wl); struct wl12xx_partition_set *p_table; -- cgit v0.10.2 From 8ec8beb28361864c82153fec5ddb82c9d636430f Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 12 Jun 2009 14:16:00 +0300 Subject: wl12xx: Add support for block reading from a fixed register address Add support for block reading (multiple bytes) from a fixed chipset register address. This is required for the wl1271 TX data path. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index c3d5b73..9c9943f 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -301,7 +301,7 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, } void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, - size_t len) + size_t len, bool fixed) { struct spi_transfer t[2]; struct spi_message m; @@ -314,6 +314,9 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; + if (fixed) + *cmd |= WSPI_CMD_FIXED; + spi_message_init(&m); memset(t, 0, sizeof(t)); @@ -348,7 +351,7 @@ void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, physical = wl12xx_translate_mem_addr(wl, addr); - wl12xx_spi_write(wl, physical, buf, len); + wl12xx_spi_write(wl, physical, buf, len, false); } void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, @@ -361,13 +364,14 @@ void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, wl12xx_spi_read(wl, physical, buf, len, fixed); } -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len) +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed) { int physical; physical = wl12xx_translate_reg_addr(wl, addr); - wl12xx_spi_write(wl, physical, buf, len); + wl12xx_spi_write(wl, physical, buf, len, fixed); } u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index 30f9098..e48a552 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -71,7 +71,8 @@ /* Raw target IO, address is not translated */ -void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed); void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len, bool fixed); @@ -84,7 +85,8 @@ void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); /* Registers IO */ void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, bool fixed); -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf,size_t len); +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed); u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); @@ -106,7 +108,8 @@ static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) { wl->buffer_32 = val; - wl12xx_spi_write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); + wl12xx_spi_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); } #endif /* __WL12XX_SPI_H__ */ -- cgit v0.10.2 From c518a73e537a2c7b83e490335ddedb6465fa5f73 Mon Sep 17 00:00:00 2001 From: Ari Kauppi Date: Fri, 12 Jun 2009 14:16:07 +0300 Subject: wl12xx: Fix incorrect warning message. A warning message in wl12xx_acx_event_mbox_mask has a copy/paste error. Fix it to print the correct acx command. Signed-off-by: Ari Kauppi Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index a6b8945..8227d6d 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -735,7 +735,7 @@ int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) ret = wl12xx_cmd_configure(wl, ACX_EVENT_MBOX_MASK, mask, sizeof(*mask)); if (ret < 0) { - wl12xx_warning("failed to set aid: %d", ret); + wl12xx_warning("failed to set acx_event_mbox_mask: %d", ret); goto out; } -- cgit v0.10.2 From 6021b2895891b161f73ede9938c101234c63218e Mon Sep 17 00:00:00 2001 From: Ari Kauppi Date: Fri, 12 Jun 2009 14:16:13 +0300 Subject: wl12xx: Fix CMD_TEST regression via netlink. CMD_TEST via netlink API has been broken since e29c3f59cfbc38c3b481a2694b08962da19c4664: cmd and acx interface rework. The user of the interface sends the request in a buffer without the wl12xx_command header but expects the response to have the wl12xx_command header (with id and status). This patch reverts the e29c3f5 commit for cmd.c:wl12xx_cmd_test and implements the needed wrapper functionality in netlink.c. Now the API of wl12xx_cmd_test and rest of wl12xx_cmd_* commands in cmd.c are similar. Signed-off-by: Ari Kauppi Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index d98941a..04e8401 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -66,38 +66,26 @@ out: * send test command to firmware * * @wl: wl struct - * @buf: buffer containing the command, without headers, no dma requirements + * @buf: buffer containing the command, with all headers, must work with dma * @len: length of the buffer * @answer: is answer needed - * - * FIXME: cmd_test users need to be converted to the new interface */ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) { - struct wl12xx_command *cmd; - size_t cmd_len; int ret; wl12xx_debug(DEBUG_CMD, "cmd test"); - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - memcpy(cmd->parameters, buf, buf_len); - - /* FIXME: ugly */ - cmd_len = sizeof(struct wl12xx_cmd_header) + buf_len; + ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); - ret = wl12xx_cmd_send(wl, CMD_TEST, cmd, cmd_len); if (ret < 0) { wl12xx_warning("TEST command failed"); - goto out; + return ret; } if (answer) { + struct wl12xx_command *cmd_answer; + /* * The test command got in, we can read the answer. * The answer would be a wl12xx_command, where the @@ -106,19 +94,18 @@ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) wl12xx_ps_elp_wakeup(wl); - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, cmd_len); + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); wl12xx_ps_elp_sleep(wl); - if (cmd->header.status != CMD_STATUS_SUCCESS) + cmd_answer = buf; + + if (cmd_answer->header.status != CMD_STATUS_SUCCESS) wl12xx_error("TEST command answer error: %d", - cmd->header.status); - memcpy(buf, cmd->parameters, buf_len); + cmd_answer->header.status); } -out: - kfree(cmd); - return ret; + return 0; } /** -- cgit v0.10.2 From cee4fd2712a3db21f432bdff14e59aed160453b2 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:16:20 +0300 Subject: wl12xx: protect wl12xx_op_set_rts_threshold() The function doesn't lock the mutex before sending the acx. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 8feba36..7ec1749 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -957,11 +957,15 @@ static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) struct wl12xx *wl = hw->priv; int ret; + mutex_lock(&wl->mutex); + ret = wl12xx_acx_rts_threshold(wl, (u16) value); if (ret < 0) wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); + mutex_unlock(&wl->mutex); + return ret; } -- cgit v0.10.2 From 01d9cfbdaadc64a46b57437c989bbad241074135 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:16:26 +0300 Subject: wl12xx: optimise elp wakeup and sleep calls The wakeup call was done too deep in code path, it's better to wakeup chip from higher levels. This will also reduce wakeup calls significantly. Signed-off-by: Kalle Valo Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 04e8401..fb4e996 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -32,8 +32,6 @@ int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) WARN_ON(len % 4 != 0); - wl12xx_ps_elp_wakeup(wl); - wl12xx_spi_mem_write(wl, wl->cmd_box_addr, buf, len); wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); @@ -57,8 +55,6 @@ int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) wl->chip.intr_cmd_complete); out: - wl12xx_ps_elp_sleep(wl); - return ret; } @@ -91,13 +87,8 @@ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) * The answer would be a wl12xx_command, where the * parameter array contains the actual answer. */ - - wl12xx_ps_elp_wakeup(wl); - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); - wl12xx_ps_elp_sleep(wl); - cmd_answer = buf; if (cmd_answer->header.status != CMD_STATUS_SUCCESS) @@ -134,13 +125,9 @@ int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len) goto out; } - wl12xx_ps_elp_wakeup(wl); - /* the interrogate command got in, we can read the answer */ wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, len); - wl12xx_ps_elp_sleep(wl); - acx = buf; if (acx->cmd.status != CMD_STATUS_SUCCESS) wl12xx_error("INTERROGATE command error: %d", diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index cdb368c..3cc5460 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -27,6 +27,7 @@ #include "wl12xx.h" #include "acx.h" +#include "ps.h" /* ms */ #define WL12XX_DEBUGFS_STATS_LIFETIME 1000 @@ -96,6 +97,8 @@ static void wl12xx_debugfs_update_stats(struct wl12xx *wl) { mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + if (wl->state == WL12XX_STATE_ON && time_after(jiffies, wl->stats.fw_stats_update + msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) { @@ -103,6 +106,8 @@ static void wl12xx_debugfs_update_stats(struct wl12xx *wl) wl->stats.fw_stats_update = jiffies; } + wl12xx_ps_elp_sleep(wl); + mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7ec1749..894d5cc 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -239,11 +239,14 @@ static void wl12xx_filter_work(struct work_struct *work) if (wl->state == WL12XX_STATE_OFF) goto out; + wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out; out: + wl12xx_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); } @@ -521,6 +524,8 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + if (channel != wl->channel) { /* FIXME: use beacon interval provided by mac80211 */ ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); @@ -564,6 +569,7 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) } out: + wl12xx_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); return ret; } @@ -702,6 +708,8 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + switch (cmd) { case SET_KEY: wl_cmd->key_action = KEY_ADD_OR_REPLACE; @@ -752,6 +760,7 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } out_unlock: + wl12xx_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); out: @@ -946,7 +955,11 @@ static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, } mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + + wl12xx_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); return ret; @@ -959,11 +972,15 @@ static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_acx_rts_threshold(wl, (u16) value); if (ret < 0) wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); + wl12xx_ps_elp_sleep(wl); + mutex_unlock(&wl->mutex); return ret; @@ -983,6 +1000,8 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { wl->aid = bss_conf->aid; @@ -1072,6 +1091,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, } out: + wl12xx_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); } -- cgit v0.10.2 From c5483b71936333ba9474f57d0f3a7a7abf9b87a0 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:16:32 +0300 Subject: wl12xx: check if elp wakeup failed Check the return call from wl12xx_ps_elp_wakeup() and bail out if it fails. This shouldn't happen, but if does there's a fundamental low level issue. Signed-off-by: Kalle Valo Reviewed-by: Luciano Coelho Reviewed-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 3cc5460..94ad994 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -95,9 +95,13 @@ static const struct file_operations sub## _ ##name## _ops = { \ static void wl12xx_debugfs_update_stats(struct wl12xx *wl) { + int ret; + mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; if (wl->state == WL12XX_STATE_ON && time_after(jiffies, wl->stats.fw_stats_update + @@ -108,6 +112,7 @@ static void wl12xx_debugfs_update_stats(struct wl12xx *wl) wl12xx_ps_elp_sleep(wl); +out: mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 894d5cc..245544e 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -239,14 +239,18 @@ static void wl12xx_filter_work(struct work_struct *work) if (wl->state == WL12XX_STATE_OFF) goto out; - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) - goto out; + goto out_sleep; -out: +out_sleep: wl12xx_ps_elp_sleep(wl); + +out: mutex_unlock(&wl->mutex); } @@ -524,20 +528,22 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; if (channel != wl->channel) { /* FIXME: use beacon interval provided by mac80211 */ ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) - goto out; + goto out_sleep; wl->channel = channel; } ret = wl12xx_build_null_data(wl); if (ret < 0) - goto out; + goto out_sleep; if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { wl12xx_info("psm enabled"); @@ -568,9 +574,12 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) wl->power_level = conf->power_level; } -out: +out_sleep: wl12xx_ps_elp_sleep(wl); + +out: mutex_unlock(&wl->mutex); + return ret; } @@ -708,7 +717,9 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; switch (cmd) { case SET_KEY: @@ -725,7 +736,7 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = wl12xx_set_key_type(wl, wl_cmd, cmd, key, addr); if (ret < 0) { wl12xx_error("Set KEY type failed"); - goto out_unlock; + goto out_sleep; } if (wl_cmd->key_type != KEY_WEP_DEFAULT) @@ -756,11 +767,13 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = wl12xx_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); if (ret < 0) { wl12xx_warning("could not set keys"); - goto out_unlock; + goto out_sleep; } -out_unlock: +out_sleep: wl12xx_ps_elp_sleep(wl); + +out_unlock: mutex_unlock(&wl->mutex); out: @@ -955,11 +968,16 @@ static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, } mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); wl12xx_ps_elp_sleep(wl); + +out: mutex_unlock(&wl->mutex); return ret; @@ -972,15 +990,17 @@ static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; ret = wl12xx_acx_rts_threshold(wl, (u16) value); - if (ret < 0) wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); wl12xx_ps_elp_sleep(wl); +out: mutex_unlock(&wl->mutex); return ret; @@ -1000,7 +1020,9 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { @@ -1008,18 +1030,18 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, ret = wl12xx_build_ps_poll(wl, wl->aid); if (ret < 0) - goto out; + goto out_sleep; ret = wl12xx_acx_aid(wl, wl->aid); if (ret < 0) - goto out; + goto out_sleep; /* If we want to go in PSM but we're not there yet */ if (wl->psm_requested && !wl->psm) { mode = STATION_POWER_SAVE_MODE; ret = wl12xx_ps_set_mode(wl, mode); if (ret < 0) - goto out; + goto out_sleep; } } } @@ -1030,7 +1052,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); if (ret < 0) { wl12xx_warning("Set slot time failed %d", ret); - goto out; + goto out_sleep; } } @@ -1048,7 +1070,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); if (ret < 0) { wl12xx_warning("Set ctsprotect failed %d", ret); - goto out; + goto out_sleep; } } @@ -1090,8 +1112,10 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, goto out; } -out: +out_sleep: wl12xx_ps_elp_sleep(wl); + +out: mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index 903624a..5f6e75c 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -401,6 +401,7 @@ static void wl1251_irq_work(struct work_struct *work) u32 intr; struct wl12xx *wl = container_of(work, struct wl12xx, irq_work); + int ret; mutex_lock(&wl->mutex); @@ -409,7 +410,9 @@ static void wl1251_irq_work(struct work_struct *work) if (wl->state == WL12XX_STATE_OFF) goto out; - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); @@ -489,6 +492,7 @@ static void wl1251_irq_work(struct work_struct *work) out_sleep: wl12xx_ps_elp_sleep(wl); + out: mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index c42c43d..10023fc 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -311,7 +311,9 @@ void wl1251_tx_work(struct work_struct *work) while ((skb = skb_dequeue(&wl->tx_queue))) { if (!woken_up) { - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; woken_up = true; } -- cgit v0.10.2 From 0182f8d56c1836629f8331a19bd71e3833b81769 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:16:39 +0300 Subject: wl12xx: enable ELP mode ELP mode is working now, let's enable it so that the firmware can sleep and reduce power consumption. Signed-off-by: Kalle Valo Reviewed-by: Luciano Coelho Reviewed-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index fe5e2d1..f28f194 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -85,11 +85,7 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) if (enable) { wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp"); - /* - * FIXME: we should PSM_ELP, but because of firmware wakeup - * problems let's use only PSM_PS - */ - ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_PS); + ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_ELP); if (ret < 0) return ret; -- cgit v0.10.2 From ce650b5cde686a282aed860bb5cd7368e00eac07 Mon Sep 17 00:00:00 2001 From: Vidhya Govindan Date: Fri, 12 Jun 2009 14:16:45 +0300 Subject: wl12xx: Assign value to rx msdu lifetime variable The patch "wl12xx: cmd and acx interface rework" failed to assign MSDU lifetime value in wl12xx_acx_rx_msdu_life_time() and breaks the functionality. This patch fixes the regression by assigning the correct value. Signed-off-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 8227d6d..328f88a 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -317,6 +317,7 @@ int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) goto out; } + acx->lifetime = life_time; ret = wl12xx_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, acx, sizeof(*acx)); if (ret < 0) { -- cgit v0.10.2 From 77cc9e43cee58303893f3a4fb8eaa2a3288c9c17 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 12 Jun 2009 14:16:52 +0300 Subject: wl12xx: Use chipset specific join commands Add implementation to use chipset specific join commands. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index fb4e996..cad258d 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -253,7 +253,7 @@ out: return ret; } -int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, +int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait) { unsigned long timeout; diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 7aef1f2..a2eae54 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -36,7 +36,7 @@ int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len); int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable); -int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, +int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait); int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 245544e..a2aebac 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -243,7 +243,8 @@ static void wl12xx_filter_work(struct work_struct *work) if (ret < 0) goto out; - ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + /* FIXME: replace the magic numbers with proper definitions */ + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out_sleep; @@ -534,7 +535,7 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) if (channel != wl->channel) { /* FIXME: use beacon interval provided by mac80211 */ - ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out_sleep; @@ -1082,7 +1083,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl12xx_cmd_join(wl, wl->bss_type, 5, 100, 1); + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 5, 100, 1); if (ret < 0) goto out; } @@ -1106,7 +1107,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out; diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index 5f6e75c..77494a9 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -717,6 +717,7 @@ void wl1251_setup(struct wl12xx *wl) wl->chip.op_plt_init = wl1251_plt_init; wl->chip.op_fw_version = wl1251_fw_version; wl->chip.op_tx_flush = wl1251_tx_flush; + wl->chip.op_cmd_join = wl1251_cmd_join; wl->chip.p_table = wl1251_part_table; wl->chip.acx_reg_table = wl1251_acx_reg_table; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index c38aa54..c673cdb 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -165,6 +165,8 @@ struct wl12xx_chip { int (*op_plt_init)(struct wl12xx *wl); void (*op_tx_flush)(struct wl12xx *wl); void (*op_fw_version)(struct wl12xx *wl); + int (*op_cmd_join)(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait); struct wl12xx_partition_set *p_table; enum wl12xx_acx_int_reg *acx_reg_table; -- cgit v0.10.2 From e6f0b5c2993609c576a0c45e86f7e5b6dd0ae421 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:16:58 +0300 Subject: wl12xx: rename wl1251.c wl1251_ops.c In preparation to split wl12xx to wl1251 and wl1271. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 7e05ea3..bb2f252 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,4 +1,4 @@ wl12xx-objs = main.o spi.o event.o wl1251_tx.o rx.o \ - ps.o cmd.o acx.o boot.o init.o wl1251.o \ + ps.o cmd.o acx.o boot.o init.o wl1251_ops.o \ debugfs.o obj-$(CONFIG_WL12XX) += wl12xx.o diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a2aebac..3fc48c7 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -34,7 +34,7 @@ #include "wl12xx.h" #include "wl12xx_80211.h" #include "reg.h" -#include "wl1251.h" +#include "wl1251_ops.h" #include "spi.h" #include "event.h" #include "wl1251_tx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c deleted file mode 100644 index 77494a9..0000000 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ /dev/null @@ -1,728 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "wl1251.h" -#include "reg.h" -#include "spi.h" -#include "boot.h" -#include "event.h" -#include "acx.h" -#include "wl1251_tx.h" -#include "rx.h" -#include "ps.h" -#include "init.h" - -static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = { - [PART_DOWN] = { - .mem = { - .start = 0x00000000, - .size = 0x00016800 - }, - .reg = { - .start = REGISTERS_BASE, - .size = REGISTERS_DOWN_SIZE - }, - }, - - [PART_WORK] = { - .mem = { - .start = 0x00028000, - .size = 0x00014000 - }, - .reg = { - .start = REGISTERS_BASE, - .size = REGISTERS_WORK_SIZE - }, - }, - - /* WL1251 doesn't use the DRPW partition, so we don't set it here */ -}; - -static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { - [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), - [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), - [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), - [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), - [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), - [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), - [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), - [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), - [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), - [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), - [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) -}; - -static int wl1251_upload_firmware(struct wl12xx *wl) -{ - struct wl12xx_partition_set *p_table = wl->chip.p_table; - int addr, chunk_num, partition_limit; - size_t fw_data_len; - u8 *p; - - /* whal_FwCtrl_LoadFwImageSm() */ - - wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", - wl12xx_reg_read32(wl, CHIP_ID_B)); - - /* 10.0 check firmware length and set partition */ - fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | - (wl->fw[6] << 8) | (wl->fw[7]); - - wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, - CHUNK_SIZE); - - if ((fw_data_len % 4) != 0) { - wl12xx_error("firmware length not multiple of four"); - return -EIO; - } - - wl12xx_set_partition(wl, - p_table[PART_DOWN].mem.start, - p_table[PART_DOWN].mem.size, - p_table[PART_DOWN].reg.start, - p_table[PART_DOWN].reg.size); - - /* 10.1 set partition limit and chunk num */ - chunk_num = 0; - partition_limit = p_table[PART_DOWN].mem.size; - - while (chunk_num < fw_data_len / CHUNK_SIZE) { - /* 10.2 update partition, if needed */ - addr = p_table[PART_DOWN].mem.start + - (chunk_num + 2) * CHUNK_SIZE; - if (addr > partition_limit) { - addr = p_table[PART_DOWN].mem.start + - chunk_num * CHUNK_SIZE; - partition_limit = chunk_num * CHUNK_SIZE + - p_table[PART_DOWN].mem.size; - wl12xx_set_partition(wl, - addr, - p_table[PART_DOWN].mem.size, - p_table[PART_DOWN].reg.start, - p_table[PART_DOWN].reg.size); - } - - /* 10.3 upload the chunk */ - addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", - p, addr); - wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE); - - chunk_num++; - } - - /* 10.4 upload the last chunk */ - addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", - fw_data_len % CHUNK_SIZE, p, addr); - wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); - - return 0; -} - -static int wl1251_upload_nvs(struct wl12xx *wl) -{ - size_t nvs_len, nvs_bytes_written, burst_len; - int nvs_start, i; - u32 dest_addr, val; - u8 *nvs_ptr, *nvs; - - nvs = wl->nvs; - if (nvs == NULL) - return -ENODEV; - - nvs_ptr = nvs; - - nvs_len = wl->nvs_len; - nvs_start = wl->fw_len; - - /* - * Layout before the actual NVS tables: - * 1 byte : burst length. - * 2 bytes: destination address. - * n bytes: data to burst copy. - * - * This is ended by a 0 length, then the NVS tables. - */ - - while (nvs_ptr[0]) { - burst_len = nvs_ptr[0]; - dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); - - /* We move our pointer to the data */ - nvs_ptr += 3; - - for (i = 0; i < burst_len; i++) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - wl12xx_debug(DEBUG_BOOT, - "nvs burst write 0x%x: 0x%x", - dest_addr, val); - wl12xx_mem_write32(wl, dest_addr, val); - - nvs_ptr += 4; - dest_addr += 4; - } - } - - /* - * We've reached the first zero length, the first NVS table - * is 7 bytes further. - */ - nvs_ptr += 7; - nvs_len -= nvs_ptr - nvs; - nvs_len = ALIGN(nvs_len, 4); - - /* Now we must set the partition correctly */ - wl12xx_set_partition(wl, nvs_start, - wl->chip.p_table[PART_DOWN].mem.size, - wl->chip.p_table[PART_DOWN].reg.start, - wl->chip.p_table[PART_DOWN].reg.size); - - /* And finally we upload the NVS tables */ - nvs_bytes_written = 0; - while (nvs_bytes_written < nvs_len) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - val = cpu_to_le32(val); - - wl12xx_debug(DEBUG_BOOT, - "nvs write table 0x%x: 0x%x", - nvs_start, val); - wl12xx_mem_write32(wl, nvs_start, val); - - nvs_ptr += 4; - nvs_bytes_written += 4; - nvs_start += 4; - } - - return 0; -} - -static int wl1251_boot(struct wl12xx *wl) -{ - int ret = 0, minor_minor_e2_ver; - u32 tmp, boot_data; - - ret = wl12xx_boot_soft_reset(wl); - if (ret < 0) - goto out; - - /* 2. start processing NVS file */ - ret = wl->chip.op_upload_nvs(wl); - if (ret < 0) - goto out; - - /* write firmware's last address (ie. it's length) to - * ACX_EEPROMLESS_IND_REG */ - wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); - - /* 6. read the EEPROM parameters */ - tmp = wl12xx_reg_read32(wl, SCR_PAD2); - - /* 7. read bootdata */ - wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; - wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; - tmp = wl12xx_reg_read32(wl, SCR_PAD3); - - /* 8. check bootdata and call restart sequence */ - wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; - minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; - - wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " - "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", - wl->boot_attr.radio_type, wl->boot_attr.major, - wl->boot_attr.minor, minor_minor_e2_ver); - - ret = wl12xx_boot_init_seq(wl); - if (ret < 0) - goto out; - - /* 9. NVS processing done */ - boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); - - /* 10. check that ECPU_CONTROL_HALT bits are set in - * pWhalBus->uBootData and start uploading firmware - */ - if ((boot_data & ECPU_CONTROL_HALT) == 0) { - wl12xx_error("boot failed, ECPU_CONTROL_HALT not set"); - ret = -EIO; - goto out; - } - - ret = wl->chip.op_upload_fw(wl); - if (ret < 0) - goto out; - - /* 10.5 start firmware */ - ret = wl12xx_boot_run_firmware(wl); - if (ret < 0) - goto out; - -out: - return ret; -} - -static int wl1251_mem_cfg(struct wl12xx *wl) -{ - struct wl1251_acx_config_memory *mem_conf; - int ret, i; - - wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg"); - - mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); - if (!mem_conf) { - ret = -ENOMEM; - goto out; - } - - /* memory config */ - mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); - mem_conf->mem_config.rx_mem_block_num = 35; - mem_conf->mem_config.tx_min_mem_block_num = 64; - mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; - mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; - mem_conf->mem_config.num_ssid_profiles = 1; - mem_conf->mem_config.debug_buffer_size = - cpu_to_le16(TRACE_BUFFER_MAX_SIZE); - - /* RX queue config */ - mem_conf->rx_queue_config.dma_address = 0; - mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; - mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; - mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; - - /* TX queue config */ - for (i = 0; i < MAX_TX_QUEUES; i++) { - mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; - mem_conf->tx_queue_config[i].attributes = i; - } - - ret = wl12xx_cmd_configure(wl, ACX_MEM_CFG, mem_conf, - sizeof(*mem_conf)); - if (ret < 0) { - wl12xx_warning("wl1251 mem config failed: %d", ret); - goto out; - } - -out: - kfree(mem_conf); - return ret; -} - -static int wl1251_hw_init_mem_config(struct wl12xx *wl) -{ - int ret; - - ret = wl1251_mem_cfg(wl); - if (ret < 0) - return ret; - - wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), - GFP_KERNEL); - if (!wl->target_mem_map) { - wl12xx_error("couldn't allocate target memory map"); - return -ENOMEM; - } - - /* we now ask for the firmware built memory map */ - ret = wl12xx_acx_mem_map(wl, wl->target_mem_map, - sizeof(struct wl1251_acx_mem_map)); - if (ret < 0) { - wl12xx_error("couldn't retrieve firmware memory map"); - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - return ret; - } - - return 0; -} - -static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag) -{ - u32 cpu_ctrl; - - /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - /* 10.5.1 run the firmware (II) */ - cpu_ctrl &= ~flag; - wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); -} - -static void wl1251_target_enable_interrupts(struct wl12xx *wl) -{ - /* Enable target's interrupts */ - wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | - WL1251_ACX_INTR_RX1_DATA | - WL1251_ACX_INTR_TX_RESULT | - WL1251_ACX_INTR_EVENT_A | - WL1251_ACX_INTR_EVENT_B | - WL1251_ACX_INTR_INIT_COMPLETE; - wl12xx_boot_target_enable_interrupts(wl); -} - -static void wl1251_fw_version(struct wl12xx *wl) -{ - wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); -} - -static void wl1251_irq_work(struct work_struct *work) -{ - u32 intr; - struct wl12xx *wl = - container_of(work, struct wl12xx, irq_work); - int ret; - - mutex_lock(&wl->mutex); - - wl12xx_debug(DEBUG_IRQ, "IRQ work"); - - if (wl->state == WL12XX_STATE_OFF) - goto out; - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); - - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr); - - if (wl->data_path) { - wl->rx_counter = - wl12xx_mem_read32(wl, wl->data_path->rx_control_addr); - - /* We handle a frmware bug here */ - switch ((wl->rx_counter - wl->rx_handled) & 0xf) { - case 0: - wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync"); - intr &= ~WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 1: - wl12xx_debug(DEBUG_IRQ, "RX: FW +1"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 2: - wl12xx_debug(DEBUG_IRQ, "RX: FW +2"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr |= WL1251_ACX_INTR_RX1_DATA; - break; - default: - wl12xx_warning("RX: FW and host out of sync: %d", - wl->rx_counter - wl->rx_handled); - break; - } - - wl->rx_handled = wl->rx_counter; - - - wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); - } - - intr &= wl->intr_mask; - - if (intr == 0) { - wl12xx_debug(DEBUG_IRQ, "INTR is 0"); - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, - ~(wl->intr_mask)); - - goto out_sleep; - } - - if (intr & WL1251_ACX_INTR_RX0_DATA) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); - wl12xx_rx(wl); - } - - if (intr & WL1251_ACX_INTR_RX1_DATA) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); - wl12xx_rx(wl); - } - - if (intr & WL1251_ACX_INTR_TX_RESULT) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); - wl1251_tx_complete(wl); - } - - if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); - if (intr & WL1251_ACX_INTR_EVENT_A) - wl12xx_event_handle(wl, 0); - else - wl12xx_event_handle(wl, 1); - } - - if (intr & WL1251_ACX_INTR_INIT_COMPLETE) - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); - - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - -out_sleep: - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1251_hw_init_txq_fill(u8 qid, - struct acx_tx_queue_qos_config *config, - u32 num_blocks) -{ - config->qid = qid; - - switch (qid) { - case QOS_AC_BE: - config->high_threshold = - (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BE_DEF * num_blocks) / 100; - break; - case QOS_AC_BK: - config->high_threshold = - (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BK_DEF * num_blocks) / 100; - break; - case QOS_AC_VI: - config->high_threshold = - (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VI_DEF * num_blocks) / 100; - break; - case QOS_AC_VO: - config->high_threshold = - (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VO_DEF * num_blocks) / 100; - break; - default: - wl12xx_error("Invalid TX queue id: %d", qid); - return -EINVAL; - } - - return 0; -} - -static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) -{ - struct acx_tx_queue_qos_config *config; - struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; - int ret, i; - - wl12xx_debug(DEBUG_ACX, "acx tx queue config"); - - config = kzalloc(sizeof(*config), GFP_KERNEL); - if (!config) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < MAX_NUM_OF_AC; i++) { - ret = wl1251_hw_init_txq_fill(i, config, - wl_mem_map->num_tx_mem_blocks); - if (ret < 0) - goto out; - - ret = wl12xx_cmd_configure(wl, ACX_TX_QUEUE_CFG, - config, sizeof(*config)); - if (ret < 0) - goto out; - } - -out: - kfree(config); - return ret; -} - -static int wl1251_hw_init_data_path_config(struct wl12xx *wl) -{ - int ret; - - /* asking for the data path parameters */ - wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), - GFP_KERNEL); - if (!wl->data_path) { - wl12xx_error("Couldnt allocate data path parameters"); - return -ENOMEM; - } - - ret = wl12xx_acx_data_path_params(wl, wl->data_path); - if (ret < 0) { - kfree(wl->data_path); - wl->data_path = NULL; - return ret; - } - - return 0; -} - -static int wl1251_hw_init(struct wl12xx *wl) -{ - struct wl1251_acx_mem_map *wl_mem_map; - int ret; - - ret = wl12xx_hw_init_hwenc_config(wl); - if (ret < 0) - return ret; - - /* Template settings */ - ret = wl12xx_hw_init_templates_config(wl); - if (ret < 0) - return ret; - - /* Default memory configuration */ - ret = wl1251_hw_init_mem_config(wl); - if (ret < 0) - return ret; - - /* Default data path configuration */ - ret = wl1251_hw_init_data_path_config(wl); - if (ret < 0) - goto out_free_memmap; - - /* RX config */ - ret = wl12xx_hw_init_rx_config(wl, - RX_CFG_PROMISCUOUS | RX_CFG_TSF, - RX_FILTER_OPTION_DEF); - /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, - RX_FILTER_OPTION_FILTER_ALL); */ - if (ret < 0) - goto out_free_data_path; - - /* TX queues config */ - ret = wl1251_hw_init_tx_queue_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* PHY layer config */ - ret = wl12xx_hw_init_phy_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacon filtering */ - ret = wl12xx_hw_init_beacon_filter(wl); - if (ret < 0) - goto out_free_data_path; - - /* Bluetooth WLAN coexistence */ - ret = wl12xx_hw_init_pta(wl); - if (ret < 0) - goto out_free_data_path; - - /* Energy detection */ - ret = wl12xx_hw_init_energy_detection(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacons and boradcast settings */ - ret = wl12xx_hw_init_beacon_broadcast(wl); - if (ret < 0) - goto out_free_data_path; - - /* Enable data path */ - ret = wl12xx_cmd_data_path(wl, wl->channel, 1); - if (ret < 0) - goto out_free_data_path; - - /* Default power state */ - ret = wl12xx_hw_init_power_auth(wl); - if (ret < 0) - goto out_free_data_path; - - wl_mem_map = wl->target_mem_map; - wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", - wl_mem_map->num_tx_mem_blocks, - wl->data_path->tx_control_addr, - wl_mem_map->num_rx_mem_blocks, - wl->data_path->rx_control_addr); - - return 0; - - out_free_data_path: - kfree(wl->data_path); - - out_free_memmap: - kfree(wl->target_mem_map); - - return ret; -} - -static int wl1251_plt_init(struct wl12xx *wl) -{ - int ret; - - ret = wl1251_hw_init_mem_config(wl); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_data_path(wl, wl->channel, 1); - if (ret < 0) - return ret; - - return 0; -} - -void wl1251_setup(struct wl12xx *wl) -{ - /* FIXME: Is it better to use strncpy here or is this ok? */ - wl->chip.fw_filename = WL1251_FW_NAME; - wl->chip.nvs_filename = WL1251_NVS_NAME; - - /* Now we know what chip we're using, so adjust the power on sleep - * time accordingly */ - wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; - - wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; - wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; - - wl->chip.op_upload_nvs = wl1251_upload_nvs; - wl->chip.op_upload_fw = wl1251_upload_firmware; - wl->chip.op_boot = wl1251_boot; - wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; - wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; - wl->chip.op_hw_init = wl1251_hw_init; - wl->chip.op_plt_init = wl1251_plt_init; - wl->chip.op_fw_version = wl1251_fw_version; - wl->chip.op_tx_flush = wl1251_tx_flush; - wl->chip.op_cmd_join = wl1251_cmd_join; - - wl->chip.p_table = wl1251_part_table; - wl->chip.acx_reg_table = wl1251_acx_reg_table; - - INIT_WORK(&wl->irq_work, wl1251_irq_work); - INIT_WORK(&wl->tx_work, wl1251_tx_work); - -} diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h deleted file mode 100644 index 1f4a443..0000000 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_H__ -#define __WL1251_H__ - -#include - -#include "wl12xx.h" -#include "acx.h" - -#define WL1251_FW_NAME "wl1251-fw.bin" -#define WL1251_NVS_NAME "wl1251-nvs.bin" - -#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ - -void wl1251_setup(struct wl12xx *wl); - - -struct wl1251_acx_memory { - __le16 num_stations; /* number of STAs to be supported. */ - u16 reserved_1; - - /* - * Nmber of memory buffers for the RX mem pool. - * The actual number may be less if there are - * not enough blocks left for the minimum num - * of TX ones. - */ - u8 rx_mem_block_num; - u8 reserved_2; - u8 num_tx_queues; /* From 1 to 16 */ - u8 host_if_options; /* HOST_IF* */ - u8 tx_min_mem_block_num; - u8 num_ssid_profiles; - __le16 debug_buffer_size; -} __attribute__ ((packed)); - - -#define ACX_RX_DESC_MIN 1 -#define ACX_RX_DESC_MAX 127 -#define ACX_RX_DESC_DEF 32 -struct wl1251_acx_rx_queue_config { - u8 num_descs; - u8 pad; - u8 type; - u8 priority; - __le32 dma_address; -} __attribute__ ((packed)); - -#define ACX_TX_DESC_MIN 1 -#define ACX_TX_DESC_MAX 127 -#define ACX_TX_DESC_DEF 16 -struct wl1251_acx_tx_queue_config { - u8 num_descs; - u8 pad[2]; - u8 attributes; -} __attribute__ ((packed)); - -#define MAX_TX_QUEUE_CONFIGS 5 -#define MAX_TX_QUEUES 4 -struct wl1251_acx_config_memory { - struct acx_header header; - - struct wl1251_acx_memory mem_config; - struct wl1251_acx_rx_queue_config rx_queue_config; - struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; -} __attribute__ ((packed)); - -struct wl1251_acx_mem_map { - struct acx_header header; - - void *code_start; - void *code_end; - - void *wep_defkey_start; - void *wep_defkey_end; - - void *sta_table_start; - void *sta_table_end; - - void *packet_template_start; - void *packet_template_end; - - void *queue_memory_start; - void *queue_memory_end; - - void *packet_memory_pool_start; - void *packet_memory_pool_end; - - void *debug_buffer1_start; - void *debug_buffer1_end; - - void *debug_buffer2_start; - void *debug_buffer2_end; - - /* Number of blocks FW allocated for TX packets */ - u32 num_tx_mem_blocks; - - /* Number of blocks FW allocated for RX packets */ - u32 num_rx_mem_blocks; -} __attribute__ ((packed)); - -/************************************************************************* - - Host Interrupt Register (WiLink -> Host) - -**************************************************************************/ - -/* RX packet is ready in Xfer buffer #0 */ -#define WL1251_ACX_INTR_RX0_DATA BIT(0) - -/* TX result(s) are in the TX complete buffer */ -#define WL1251_ACX_INTR_TX_RESULT BIT(1) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_TX_XFR BIT(2) - -/* RX packet is ready in Xfer buffer #1 */ -#define WL1251_ACX_INTR_RX1_DATA BIT(3) - -/* Event was entered to Event MBOX #A */ -#define WL1251_ACX_INTR_EVENT_A BIT(4) - -/* Event was entered to Event MBOX #B */ -#define WL1251_ACX_INTR_EVENT_B BIT(5) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) - -/* Trace meassge on MBOX #A */ -#define WL1251_ACX_INTR_TRACE_A BIT(7) - -/* Trace meassge on MBOX #B */ -#define WL1251_ACX_INTR_TRACE_B BIT(8) - -/* Command processing completion */ -#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) - -/* Init sequence is done */ -#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) - -#define WL1251_ACX_INTR_ALL 0xFFFFFFFF - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c new file mode 100644 index 0000000..126537f --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -0,0 +1,728 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl1251_ops.h" +#include "reg.h" +#include "spi.h" +#include "boot.h" +#include "event.h" +#include "acx.h" +#include "wl1251_tx.h" +#include "rx.h" +#include "ps.h" +#include "init.h" + +static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = { + [PART_DOWN] = { + .mem = { + .start = 0x00000000, + .size = 0x00016800 + }, + .reg = { + .start = REGISTERS_BASE, + .size = REGISTERS_DOWN_SIZE + }, + }, + + [PART_WORK] = { + .mem = { + .start = 0x00028000, + .size = 0x00014000 + }, + .reg = { + .start = REGISTERS_BASE, + .size = REGISTERS_WORK_SIZE + }, + }, + + /* WL1251 doesn't use the DRPW partition, so we don't set it here */ +}; + +static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { + [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), + [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), + [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), + [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), + [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), + [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), + [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), + [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), + [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), + [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), + [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) +}; + +static int wl1251_upload_firmware(struct wl12xx *wl) +{ + struct wl12xx_partition_set *p_table = wl->chip.p_table; + int addr, chunk_num, partition_limit; + size_t fw_data_len; + u8 *p; + + /* whal_FwCtrl_LoadFwImageSm() */ + + wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", + wl12xx_reg_read32(wl, CHIP_ID_B)); + + /* 10.0 check firmware length and set partition */ + fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | + (wl->fw[6] << 8) | (wl->fw[7]); + + wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, + CHUNK_SIZE); + + if ((fw_data_len % 4) != 0) { + wl12xx_error("firmware length not multiple of four"); + return -EIO; + } + + wl12xx_set_partition(wl, + p_table[PART_DOWN].mem.start, + p_table[PART_DOWN].mem.size, + p_table[PART_DOWN].reg.start, + p_table[PART_DOWN].reg.size); + + /* 10.1 set partition limit and chunk num */ + chunk_num = 0; + partition_limit = p_table[PART_DOWN].mem.size; + + while (chunk_num < fw_data_len / CHUNK_SIZE) { + /* 10.2 update partition, if needed */ + addr = p_table[PART_DOWN].mem.start + + (chunk_num + 2) * CHUNK_SIZE; + if (addr > partition_limit) { + addr = p_table[PART_DOWN].mem.start + + chunk_num * CHUNK_SIZE; + partition_limit = chunk_num * CHUNK_SIZE + + p_table[PART_DOWN].mem.size; + wl12xx_set_partition(wl, + addr, + p_table[PART_DOWN].mem.size, + p_table[PART_DOWN].reg.start, + p_table[PART_DOWN].reg.size); + } + + /* 10.3 upload the chunk */ + addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + p, addr); + wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE); + + chunk_num++; + } + + /* 10.4 upload the last chunk */ + addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", + fw_data_len % CHUNK_SIZE, p, addr); + wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + + return 0; +} + +static int wl1251_upload_nvs(struct wl12xx *wl) +{ + size_t nvs_len, nvs_bytes_written, burst_len; + int nvs_start, i; + u32 dest_addr, val; + u8 *nvs_ptr, *nvs; + + nvs = wl->nvs; + if (nvs == NULL) + return -ENODEV; + + nvs_ptr = nvs; + + nvs_len = wl->nvs_len; + nvs_start = wl->fw_len; + + /* + * Layout before the actual NVS tables: + * 1 byte : burst length. + * 2 bytes: destination address. + * n bytes: data to burst copy. + * + * This is ended by a 0 length, then the NVS tables. + */ + + while (nvs_ptr[0]) { + burst_len = nvs_ptr[0]; + dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); + + /* We move our pointer to the data */ + nvs_ptr += 3; + + for (i = 0; i < burst_len; i++) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + wl12xx_debug(DEBUG_BOOT, + "nvs burst write 0x%x: 0x%x", + dest_addr, val); + wl12xx_mem_write32(wl, dest_addr, val); + + nvs_ptr += 4; + dest_addr += 4; + } + } + + /* + * We've reached the first zero length, the first NVS table + * is 7 bytes further. + */ + nvs_ptr += 7; + nvs_len -= nvs_ptr - nvs; + nvs_len = ALIGN(nvs_len, 4); + + /* Now we must set the partition correctly */ + wl12xx_set_partition(wl, nvs_start, + wl->chip.p_table[PART_DOWN].mem.size, + wl->chip.p_table[PART_DOWN].reg.start, + wl->chip.p_table[PART_DOWN].reg.size); + + /* And finally we upload the NVS tables */ + nvs_bytes_written = 0; + while (nvs_bytes_written < nvs_len) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + val = cpu_to_le32(val); + + wl12xx_debug(DEBUG_BOOT, + "nvs write table 0x%x: 0x%x", + nvs_start, val); + wl12xx_mem_write32(wl, nvs_start, val); + + nvs_ptr += 4; + nvs_bytes_written += 4; + nvs_start += 4; + } + + return 0; +} + +static int wl1251_boot(struct wl12xx *wl) +{ + int ret = 0, minor_minor_e2_ver; + u32 tmp, boot_data; + + ret = wl12xx_boot_soft_reset(wl); + if (ret < 0) + goto out; + + /* 2. start processing NVS file */ + ret = wl->chip.op_upload_nvs(wl); + if (ret < 0) + goto out; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); + + /* 6. read the EEPROM parameters */ + tmp = wl12xx_reg_read32(wl, SCR_PAD2); + + /* 7. read bootdata */ + wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; + wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; + tmp = wl12xx_reg_read32(wl, SCR_PAD3); + + /* 8. check bootdata and call restart sequence */ + wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; + minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; + + wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " + "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", + wl->boot_attr.radio_type, wl->boot_attr.major, + wl->boot_attr.minor, minor_minor_e2_ver); + + ret = wl12xx_boot_init_seq(wl); + if (ret < 0) + goto out; + + /* 9. NVS processing done */ + boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); + + /* 10. check that ECPU_CONTROL_HALT bits are set in + * pWhalBus->uBootData and start uploading firmware + */ + if ((boot_data & ECPU_CONTROL_HALT) == 0) { + wl12xx_error("boot failed, ECPU_CONTROL_HALT not set"); + ret = -EIO; + goto out; + } + + ret = wl->chip.op_upload_fw(wl); + if (ret < 0) + goto out; + + /* 10.5 start firmware */ + ret = wl12xx_boot_run_firmware(wl); + if (ret < 0) + goto out; + +out: + return ret; +} + +static int wl1251_mem_cfg(struct wl12xx *wl) +{ + struct wl1251_acx_config_memory *mem_conf; + int ret, i; + + wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg"); + + mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); + if (!mem_conf) { + ret = -ENOMEM; + goto out; + } + + /* memory config */ + mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf->mem_config.rx_mem_block_num = 35; + mem_conf->mem_config.tx_min_mem_block_num = 64; + mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; + mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; + mem_conf->mem_config.num_ssid_profiles = 1; + mem_conf->mem_config.debug_buffer_size = + cpu_to_le16(TRACE_BUFFER_MAX_SIZE); + + /* RX queue config */ + mem_conf->rx_queue_config.dma_address = 0; + mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; + mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; + mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; + + /* TX queue config */ + for (i = 0; i < MAX_TX_QUEUES; i++) { + mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; + mem_conf->tx_queue_config[i].attributes = i; + } + + ret = wl12xx_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); + if (ret < 0) { + wl12xx_warning("wl1251 mem config failed: %d", ret); + goto out; + } + +out: + kfree(mem_conf); + return ret; +} + +static int wl1251_hw_init_mem_config(struct wl12xx *wl) +{ + int ret; + + ret = wl1251_mem_cfg(wl); + if (ret < 0) + return ret; + + wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), + GFP_KERNEL); + if (!wl->target_mem_map) { + wl12xx_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = wl12xx_acx_mem_map(wl, wl->target_mem_map, + sizeof(struct wl1251_acx_mem_map)); + if (ret < 0) { + wl12xx_error("couldn't retrieve firmware memory map"); + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + return ret; + } + + return 0; +} + +static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag) +{ + u32 cpu_ctrl; + + /* 10.5.0 run the firmware (I) */ + cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + /* 10.5.1 run the firmware (II) */ + cpu_ctrl &= ~flag; + wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); +} + +static void wl1251_target_enable_interrupts(struct wl12xx *wl) +{ + /* Enable target's interrupts */ + wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | + WL1251_ACX_INTR_RX1_DATA | + WL1251_ACX_INTR_TX_RESULT | + WL1251_ACX_INTR_EVENT_A | + WL1251_ACX_INTR_EVENT_B | + WL1251_ACX_INTR_INIT_COMPLETE; + wl12xx_boot_target_enable_interrupts(wl); +} + +static void wl1251_fw_version(struct wl12xx *wl) +{ + wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); +} + +static void wl1251_irq_work(struct work_struct *work) +{ + u32 intr; + struct wl12xx *wl = + container_of(work, struct wl12xx, irq_work); + int ret; + + mutex_lock(&wl->mutex); + + wl12xx_debug(DEBUG_IRQ, "IRQ work"); + + if (wl->state == WL12XX_STATE_OFF) + goto out; + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr); + + if (wl->data_path) { + wl->rx_counter = + wl12xx_mem_read32(wl, wl->data_path->rx_control_addr); + + /* We handle a frmware bug here */ + switch ((wl->rx_counter - wl->rx_handled) & 0xf) { + case 0: + wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync"); + intr &= ~WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 1: + wl12xx_debug(DEBUG_IRQ, "RX: FW +1"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 2: + wl12xx_debug(DEBUG_IRQ, "RX: FW +2"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr |= WL1251_ACX_INTR_RX1_DATA; + break; + default: + wl12xx_warning("RX: FW and host out of sync: %d", + wl->rx_counter - wl->rx_handled); + break; + } + + wl->rx_handled = wl->rx_counter; + + + wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); + } + + intr &= wl->intr_mask; + + if (intr == 0) { + wl12xx_debug(DEBUG_IRQ, "INTR is 0"); + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + ~(wl->intr_mask)); + + goto out_sleep; + } + + if (intr & WL1251_ACX_INTR_RX0_DATA) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); + wl12xx_rx(wl); + } + + if (intr & WL1251_ACX_INTR_RX1_DATA) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); + wl12xx_rx(wl); + } + + if (intr & WL1251_ACX_INTR_TX_RESULT) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); + wl1251_tx_complete(wl); + } + + if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); + if (intr & WL1251_ACX_INTR_EVENT_A) + wl12xx_event_handle(wl, 0); + else + wl12xx_event_handle(wl, 1); + } + + if (intr & WL1251_ACX_INTR_INIT_COMPLETE) + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + +out_sleep: + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1251_hw_init_txq_fill(u8 qid, + struct acx_tx_queue_qos_config *config, + u32 num_blocks) +{ + config->qid = qid; + + switch (qid) { + case QOS_AC_BE: + config->high_threshold = + (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BE_DEF * num_blocks) / 100; + break; + case QOS_AC_BK: + config->high_threshold = + (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BK_DEF * num_blocks) / 100; + break; + case QOS_AC_VI: + config->high_threshold = + (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VI_DEF * num_blocks) / 100; + break; + case QOS_AC_VO: + config->high_threshold = + (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VO_DEF * num_blocks) / 100; + break; + default: + wl12xx_error("Invalid TX queue id: %d", qid); + return -EINVAL; + } + + return 0; +} + +static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) +{ + struct acx_tx_queue_qos_config *config; + struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; + int ret, i; + + wl12xx_debug(DEBUG_ACX, "acx tx queue config"); + + config = kzalloc(sizeof(*config), GFP_KERNEL); + if (!config) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < MAX_NUM_OF_AC; i++) { + ret = wl1251_hw_init_txq_fill(i, config, + wl_mem_map->num_tx_mem_blocks); + if (ret < 0) + goto out; + + ret = wl12xx_cmd_configure(wl, ACX_TX_QUEUE_CFG, + config, sizeof(*config)); + if (ret < 0) + goto out; + } + +out: + kfree(config); + return ret; +} + +static int wl1251_hw_init_data_path_config(struct wl12xx *wl) +{ + int ret; + + /* asking for the data path parameters */ + wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), + GFP_KERNEL); + if (!wl->data_path) { + wl12xx_error("Couldnt allocate data path parameters"); + return -ENOMEM; + } + + ret = wl12xx_acx_data_path_params(wl, wl->data_path); + if (ret < 0) { + kfree(wl->data_path); + wl->data_path = NULL; + return ret; + } + + return 0; +} + +static int wl1251_hw_init(struct wl12xx *wl) +{ + struct wl1251_acx_mem_map *wl_mem_map; + int ret; + + ret = wl12xx_hw_init_hwenc_config(wl); + if (ret < 0) + return ret; + + /* Template settings */ + ret = wl12xx_hw_init_templates_config(wl); + if (ret < 0) + return ret; + + /* Default memory configuration */ + ret = wl1251_hw_init_mem_config(wl); + if (ret < 0) + return ret; + + /* Default data path configuration */ + ret = wl1251_hw_init_data_path_config(wl); + if (ret < 0) + goto out_free_memmap; + + /* RX config */ + ret = wl12xx_hw_init_rx_config(wl, + RX_CFG_PROMISCUOUS | RX_CFG_TSF, + RX_FILTER_OPTION_DEF); + /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, + RX_FILTER_OPTION_FILTER_ALL); */ + if (ret < 0) + goto out_free_data_path; + + /* TX queues config */ + ret = wl1251_hw_init_tx_queue_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* PHY layer config */ + ret = wl12xx_hw_init_phy_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacon filtering */ + ret = wl12xx_hw_init_beacon_filter(wl); + if (ret < 0) + goto out_free_data_path; + + /* Bluetooth WLAN coexistence */ + ret = wl12xx_hw_init_pta(wl); + if (ret < 0) + goto out_free_data_path; + + /* Energy detection */ + ret = wl12xx_hw_init_energy_detection(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacons and boradcast settings */ + ret = wl12xx_hw_init_beacon_broadcast(wl); + if (ret < 0) + goto out_free_data_path; + + /* Enable data path */ + ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + goto out_free_data_path; + + /* Default power state */ + ret = wl12xx_hw_init_power_auth(wl); + if (ret < 0) + goto out_free_data_path; + + wl_mem_map = wl->target_mem_map; + wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", + wl_mem_map->num_tx_mem_blocks, + wl->data_path->tx_control_addr, + wl_mem_map->num_rx_mem_blocks, + wl->data_path->rx_control_addr); + + return 0; + + out_free_data_path: + kfree(wl->data_path); + + out_free_memmap: + kfree(wl->target_mem_map); + + return ret; +} + +static int wl1251_plt_init(struct wl12xx *wl) +{ + int ret; + + ret = wl1251_hw_init_mem_config(wl); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + return ret; + + return 0; +} + +void wl1251_setup(struct wl12xx *wl) +{ + /* FIXME: Is it better to use strncpy here or is this ok? */ + wl->chip.fw_filename = WL1251_FW_NAME; + wl->chip.nvs_filename = WL1251_NVS_NAME; + + /* Now we know what chip we're using, so adjust the power on sleep + * time accordingly */ + wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; + + wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; + wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; + + wl->chip.op_upload_nvs = wl1251_upload_nvs; + wl->chip.op_upload_fw = wl1251_upload_firmware; + wl->chip.op_boot = wl1251_boot; + wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; + wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; + wl->chip.op_hw_init = wl1251_hw_init; + wl->chip.op_plt_init = wl1251_plt_init; + wl->chip.op_fw_version = wl1251_fw_version; + wl->chip.op_tx_flush = wl1251_tx_flush; + wl->chip.op_cmd_join = wl1251_cmd_join; + + wl->chip.p_table = wl1251_part_table; + wl->chip.acx_reg_table = wl1251_acx_reg_table; + + INIT_WORK(&wl->irq_work, wl1251_irq_work); + INIT_WORK(&wl->tx_work, wl1251_tx_work); + +} diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h new file mode 100644 index 0000000..74acf8e --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_ops.h @@ -0,0 +1,165 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_OPS_H__ +#define __WL1251_OPS_H__ + +#include + +#include "wl12xx.h" +#include "acx.h" + +#define WL1251_FW_NAME "wl1251-fw.bin" +#define WL1251_NVS_NAME "wl1251-nvs.bin" + +#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ + +void wl1251_setup(struct wl12xx *wl); + + +struct wl1251_acx_memory { + __le16 num_stations; /* number of STAs to be supported. */ + u16 reserved_1; + + /* + * Nmber of memory buffers for the RX mem pool. + * The actual number may be less if there are + * not enough blocks left for the minimum num + * of TX ones. + */ + u8 rx_mem_block_num; + u8 reserved_2; + u8 num_tx_queues; /* From 1 to 16 */ + u8 host_if_options; /* HOST_IF* */ + u8 tx_min_mem_block_num; + u8 num_ssid_profiles; + __le16 debug_buffer_size; +} __attribute__ ((packed)); + + +#define ACX_RX_DESC_MIN 1 +#define ACX_RX_DESC_MAX 127 +#define ACX_RX_DESC_DEF 32 +struct wl1251_acx_rx_queue_config { + u8 num_descs; + u8 pad; + u8 type; + u8 priority; + __le32 dma_address; +} __attribute__ ((packed)); + +#define ACX_TX_DESC_MIN 1 +#define ACX_TX_DESC_MAX 127 +#define ACX_TX_DESC_DEF 16 +struct wl1251_acx_tx_queue_config { + u8 num_descs; + u8 pad[2]; + u8 attributes; +} __attribute__ ((packed)); + +#define MAX_TX_QUEUE_CONFIGS 5 +#define MAX_TX_QUEUES 4 +struct wl1251_acx_config_memory { + struct acx_header header; + + struct wl1251_acx_memory mem_config; + struct wl1251_acx_rx_queue_config rx_queue_config; + struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; +} __attribute__ ((packed)); + +struct wl1251_acx_mem_map { + struct acx_header header; + + void *code_start; + void *code_end; + + void *wep_defkey_start; + void *wep_defkey_end; + + void *sta_table_start; + void *sta_table_end; + + void *packet_template_start; + void *packet_template_end; + + void *queue_memory_start; + void *queue_memory_end; + + void *packet_memory_pool_start; + void *packet_memory_pool_end; + + void *debug_buffer1_start; + void *debug_buffer1_end; + + void *debug_buffer2_start; + void *debug_buffer2_end; + + /* Number of blocks FW allocated for TX packets */ + u32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + u32 num_rx_mem_blocks; +} __attribute__ ((packed)); + +/************************************************************************* + + Host Interrupt Register (WiLink -> Host) + +**************************************************************************/ + +/* RX packet is ready in Xfer buffer #0 */ +#define WL1251_ACX_INTR_RX0_DATA BIT(0) + +/* TX result(s) are in the TX complete buffer */ +#define WL1251_ACX_INTR_TX_RESULT BIT(1) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_TX_XFR BIT(2) + +/* RX packet is ready in Xfer buffer #1 */ +#define WL1251_ACX_INTR_RX1_DATA BIT(3) + +/* Event was entered to Event MBOX #A */ +#define WL1251_ACX_INTR_EVENT_A BIT(4) + +/* Event was entered to Event MBOX #B */ +#define WL1251_ACX_INTR_EVENT_B BIT(5) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) + +/* Trace meassge on MBOX #A */ +#define WL1251_ACX_INTR_TRACE_A BIT(7) + +/* Trace meassge on MBOX #B */ +#define WL1251_ACX_INTR_TRACE_B BIT(8) + +/* Command processing completion */ +#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) + +/* Init sequence is done */ +#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) + +#define WL1251_ACX_INTR_ALL 0xFFFFFFFF + +#endif -- cgit v0.10.2 From c5ce901b3fdb2312f896f138ac864a7ef363c02d Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:06 +0300 Subject: wl12xx: rename driver to wl1251 Rename driver to wl1251.ko in preparation for wl1271 driver. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index a82c4cd..82a0f97 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -1,11 +1,18 @@ -config WL12XX - tristate "TI wl1251/wl1271 support" - depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS && EXPERIMENTAL +menuconfig WL12XX + boolean "TI wl12xx driver support" + depends on MAC80211 && WLAN_80211 && EXPERIMENTAL + ---help--- + This will enable TI wl12xx driver support. The drivers make + use of the mac80211 stack. + +config WL1251 + tristate "TI wl1251 support" + depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS select FW_LOADER select CRC7 ---help--- This module adds support for wireless adapters based on - TI wl1251/wl1271 chipsets. + TI wl1251 chipset. - If you choose to build a module, it'll be called wl12xx. Say N if + If you choose to build a module, it'll be called wl1251. Say N if unsure. diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index bb2f252..f94970c 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,4 +1,4 @@ -wl12xx-objs = main.o spi.o event.o wl1251_tx.o rx.o \ +wl1251-objs = main.o spi.o event.o wl1251_tx.o rx.o \ ps.o cmd.o acx.o boot.o init.o wl1251_ops.o \ debugfs.o -obj-$(CONFIG_WL12XX) += wl12xx.o +obj-$(CONFIG_WL1251) += wl1251.o -- cgit v0.10.2 From c731837855a9dcc2ec0c5367b0e16ad975aaed16 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:12 +0300 Subject: wl1251: remove wl1271_setup() We don't want to have any 1271 code in wl1251. Signed-off-by: Kalle Valo Reviewed-by: Luciano Coelho Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3fc48c7..dd75d3d 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -195,14 +195,6 @@ static int wl12xx_chip_wakeup(struct wl12xx *wl) wl1251_setup(wl); break; - case CHIP_ID_1271_PG10: - wl12xx_warning("chip id 0x%x (1271 PG10) support is obsolete", - wl->chip.id); - break; - case CHIP_ID_1271_PG20: - wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", - wl->chip.id); - break; case CHIP_ID_1251_PG10: case CHIP_ID_1251_PG11: default: -- cgit v0.10.2 From ef2f8d45771490de5b8373c25e983ee1e3aee9ea Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:19 +0300 Subject: wl1251: add wl1251 prefix to all 1251 files Now that all 1271 files are split, we can add wl1251_ prefix to the files. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index f94970c..d5595a8 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,4 +1,5 @@ -wl1251-objs = main.o spi.o event.o wl1251_tx.o rx.o \ - ps.o cmd.o acx.o boot.o init.o wl1251_ops.o \ - debugfs.o +wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \ + wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ + wl1251_acx.o wl1251_boot.o wl1251_init.o \ + wl1251_ops.o wl1251_debugfs.o obj-$(CONFIG_WL1251) += wl1251.o diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c deleted file mode 100644 index 328f88a..0000000 --- a/drivers/net/wireless/wl12xx/acx.c +++ /dev/null @@ -1,841 +0,0 @@ -#include "acx.h" - -#include -#include -#include - -#include "wl12xx.h" -#include "wl12xx_80211.h" -#include "reg.h" -#include "spi.h" -#include "ps.h" - -int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, - u8 mgt_rate, u8 mgt_mod) -{ - struct acx_fw_gen_frame_rates *rates; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx frame rates"); - - rates = kzalloc(sizeof(*rates), GFP_KERNEL); - if (!rates) { - ret = -ENOMEM; - goto out; - } - - rates->tx_ctrl_frame_rate = ctrl_rate; - rates->tx_ctrl_frame_mod = ctrl_mod; - rates->tx_mgt_frame_rate = mgt_rate; - rates->tx_mgt_frame_mod = mgt_mod; - - ret = wl12xx_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, - rates, sizeof(*rates)); - if (ret < 0) { - wl12xx_error("Failed to set FW rates and modulation"); - goto out; - } - -out: - kfree(rates); - return ret; -} - - -int wl12xx_acx_station_id(struct wl12xx *wl) -{ - struct acx_dot11_station_id *mac; - int ret, i; - - wl12xx_debug(DEBUG_ACX, "acx dot11_station_id"); - - mac = kzalloc(sizeof(*mac), GFP_KERNEL); - if (!mac) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < ETH_ALEN; i++) - mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; - - ret = wl12xx_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); - if (ret < 0) - goto out; - -out: - kfree(mac); - return ret; -} - -int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) -{ - struct acx_dot11_default_key *default_key; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); - - default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); - if (!default_key) { - ret = -ENOMEM; - goto out; - } - - default_key->id = key_id; - - ret = wl12xx_cmd_configure(wl, DOT11_DEFAULT_KEY, - default_key, sizeof(*default_key)); - if (ret < 0) { - wl12xx_error("Couldnt set default key"); - goto out; - } - - wl->default_key = key_id; - -out: - kfree(default_key); - return ret; -} - -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, - u8 listen_interval) -{ - struct acx_wake_up_condition *wake_up; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx wake up conditions"); - - wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); - if (!wake_up) { - ret = -ENOMEM; - goto out; - } - - wake_up->wake_up_event = wake_up_event; - wake_up->listen_interval = listen_interval; - - ret = wl12xx_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, - wake_up, sizeof(*wake_up)); - if (ret < 0) { - wl12xx_warning("could not set wake up conditions: %d", ret); - goto out; - } - -out: - kfree(wake_up); - return ret; -} - -int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) -{ - struct acx_sleep_auth *auth; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx sleep auth"); - - auth = kzalloc(sizeof(*auth), GFP_KERNEL); - if (!auth) { - ret = -ENOMEM; - goto out; - } - - auth->sleep_auth = sleep_auth; - - ret = wl12xx_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); - if (ret < 0) - return ret; - -out: - kfree(auth); - return ret; -} - -int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) -{ - struct acx_revision *rev; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx fw rev"); - - rev = kzalloc(sizeof(*rev), GFP_KERNEL); - if (!rev) { - ret = -ENOMEM; - goto out; - } - - ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); - if (ret < 0) { - wl12xx_warning("ACX_FW_REV interrogate failed"); - goto out; - } - - /* be careful with the buffer sizes */ - strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); - - /* - * if the firmware version string is exactly - * sizeof(rev->fw_version) long or fw_len is less than - * sizeof(rev->fw_version) it won't be null terminated - */ - buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; - -out: - kfree(rev); - return ret; -} - -int wl12xx_acx_tx_power(struct wl12xx *wl, int power) -{ - struct acx_current_tx_power *acx; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); - - if (power < 0 || power > 25) - return -EINVAL; - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->current_tx_power = power * 10; - - ret = wl12xx_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_warning("configure of tx power failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_feature_cfg(struct wl12xx *wl) -{ - struct acx_feature_config *feature; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx feature cfg"); - - feature = kzalloc(sizeof(*feature), GFP_KERNEL); - if (!feature) { - ret = -ENOMEM; - goto out; - } - - /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ - feature->data_flow_options = 0; - feature->options = 0; - - ret = wl12xx_cmd_configure(wl, ACX_FEATURE_CFG, - feature, sizeof(*feature)); - if (ret < 0) { - wl12xx_error("Couldnt set HW encryption"); - goto out; - } - -out: - kfree(feature); - return ret; -} - -int wl12xx_acx_mem_map(struct wl12xx *wl, struct acx_header *mem_map, - size_t len) -{ - int ret; - - wl12xx_debug(DEBUG_ACX, "acx mem map"); - - ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_acx_data_path_params(struct wl12xx *wl, - struct acx_data_path_params_resp *resp) -{ - struct acx_data_path_params *params; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx data path params"); - - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - ret = -ENOMEM; - goto out; - } - - params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; - params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; - - params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; - params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; - - params->tx_complete_threshold = 1; - - params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; - - params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; - - ret = wl12xx_cmd_configure(wl, ACX_DATA_PATH_PARAMS, - params, sizeof(*params)); - if (ret < 0) - goto out; - - /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ - ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, - resp, sizeof(*resp)); - - if (ret < 0) { - wl12xx_warning("failed to read data path parameters: %d", ret); - goto out; - } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { - wl12xx_warning("data path parameter acx status failed"); - ret = -EIO; - goto out; - } - -out: - kfree(params); - return ret; -} - -int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) -{ - struct acx_rx_msdu_lifetime *acx; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx rx msdu life time"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->lifetime = life_time; - ret = wl12xx_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, - acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_warning("failed to set rx msdu life time: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) -{ - struct acx_rx_config *rx_config; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx rx config"); - - rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); - if (!rx_config) { - ret = -ENOMEM; - goto out; - } - - rx_config->config_options = config; - rx_config->filter_options = filter; - - ret = wl12xx_cmd_configure(wl, ACX_RX_CFG, - rx_config, sizeof(*rx_config)); - if (ret < 0) { - wl12xx_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(rx_config); - return ret; -} - -int wl12xx_acx_pd_threshold(struct wl12xx *wl) -{ - struct acx_packet_detection *pd; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx data pd threshold"); - - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { - ret = -ENOMEM; - goto out; - } - - /* FIXME: threshold value not set */ - - ret = wl12xx_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); - if (ret < 0) { - wl12xx_warning("failed to set pd threshold: %d", ret); - goto out; - } - -out: - kfree(pd); - return 0; -} - -int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) -{ - struct acx_slot *slot; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx slot"); - - slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) { - ret = -ENOMEM; - goto out; - } - - slot->wone_index = STATION_WONE_INDEX; - slot->slot_time = slot_time; - - ret = wl12xx_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); - if (ret < 0) { - wl12xx_warning("failed to set slot time: %d", ret); - goto out; - } - -out: - kfree(slot); - return ret; -} - -int wl12xx_acx_group_address_tbl(struct wl12xx *wl) -{ - struct acx_dot11_grp_addr_tbl *acx; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx group address tbl"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - /* MAC filtering */ - acx->enabled = 0; - acx->num_groups = 0; - memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); - - ret = wl12xx_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, - acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_warning("failed to set group addr table: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_service_period_timeout(struct wl12xx *wl) -{ - struct acx_rx_timeout *rx_timeout; - int ret; - - rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); - if (!rx_timeout) { - ret = -ENOMEM; - goto out; - } - - wl12xx_debug(DEBUG_ACX, "acx service period timeout"); - - rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; - rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; - - ret = wl12xx_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, - rx_timeout, sizeof(*rx_timeout)); - if (ret < 0) { - wl12xx_warning("failed to set service period timeout: %d", - ret); - goto out; - } - -out: - kfree(rx_timeout); - return ret; -} - -int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) -{ - struct acx_rts_threshold *rts; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx rts threshold"); - - rts = kzalloc(sizeof(*rts), GFP_KERNEL); - if (!rts) { - ret = -ENOMEM; - goto out; - } - - rts->threshold = rts_threshold; - - ret = wl12xx_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); - if (ret < 0) { - wl12xx_warning("failed to set rts threshold: %d", ret); - goto out; - } - -out: - kfree(rts); - return ret; -} - -int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) -{ - struct acx_beacon_filter_option *beacon_filter; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx beacon filter opt"); - - beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); - if (!beacon_filter) { - ret = -ENOMEM; - goto out; - } - - beacon_filter->enable = 0; - beacon_filter->max_num_beacons = 0; - - ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_OPT, - beacon_filter, sizeof(*beacon_filter)); - if (ret < 0) { - wl12xx_warning("failed to set beacon filter opt: %d", ret); - goto out; - } - -out: - kfree(beacon_filter); - return ret; -} - -int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) -{ - struct acx_beacon_filter_ie_table *ie_table; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx beacon filter table"); - - ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); - if (!ie_table) { - ret = -ENOMEM; - goto out; - } - - ie_table->num_ie = 0; - memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); - - ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, - ie_table, sizeof(*ie_table)); - if (ret < 0) { - wl12xx_warning("failed to set beacon filter table: %d", ret); - goto out; - } - -out: - kfree(ie_table); - return ret; -} - -int wl12xx_acx_sg_enable(struct wl12xx *wl) -{ - struct acx_bt_wlan_coex *pta; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx sg enable"); - - pta = kzalloc(sizeof(*pta), GFP_KERNEL); - if (!pta) { - ret = -ENOMEM; - goto out; - } - - pta->enable = SG_ENABLE; - - ret = wl12xx_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); - if (ret < 0) { - wl12xx_warning("failed to set softgemini enable: %d", ret); - goto out; - } - -out: - kfree(pta); - return ret; -} - -int wl12xx_acx_sg_cfg(struct wl12xx *wl) -{ - struct acx_bt_wlan_coex_param *param; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx sg cfg"); - - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) { - ret = -ENOMEM; - goto out; - } - - /* BT-WLAN coext parameters */ - param->min_rate = RATE_INDEX_24MBPS; - param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; - param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; - param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; - param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; - param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; - param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; - param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; - param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; - param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; - param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; - param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; - param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; - param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; - param->antenna_type = PTA_ANTENNA_TYPE_DEF; - param->signal_type = PTA_SIGNALING_TYPE_DEF; - param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; - param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; - param->max_cts = PTA_MAX_NUM_CTS_DEF; - param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; - param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; - param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; - param->wlan_elp_hp = PTA_ELP_HP_DEF; - param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; - param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; - param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; - param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; - param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; - - ret = wl12xx_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); - if (ret < 0) { - wl12xx_warning("failed to set sg config: %d", ret); - goto out; - } - -out: - kfree(param); - return ret; -} - -int wl12xx_acx_cca_threshold(struct wl12xx *wl) -{ - struct acx_energy_detection *detection; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx cca threshold"); - - detection = kzalloc(sizeof(*detection), GFP_KERNEL); - if (!detection) { - ret = -ENOMEM; - goto out; - } - - detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; - detection->tx_energy_detection = 0; - - ret = wl12xx_cmd_configure(wl, ACX_CCA_THRESHOLD, - detection, sizeof(*detection)); - if (ret < 0) { - wl12xx_warning("failed to set cca threshold: %d", ret); - return ret; - } - -out: - kfree(detection); - return ret; -} - -int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) -{ - struct acx_beacon_broadcast *bb; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx bcn dtim options"); - - bb = kzalloc(sizeof(*bb), GFP_KERNEL); - if (!bb) { - ret = -ENOMEM; - goto out; - } - - bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; - bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; - bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; - bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; - - ret = wl12xx_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); - if (ret < 0) { - wl12xx_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(bb); - return ret; -} - -int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) -{ - struct acx_aid *acx_aid; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx aid"); - - acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); - if (!acx_aid) { - ret = -ENOMEM; - goto out; - } - - acx_aid->aid = aid; - - ret = wl12xx_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); - if (ret < 0) { - wl12xx_warning("failed to set aid: %d", ret); - goto out; - } - -out: - kfree(acx_aid); - return ret; -} - -int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) -{ - struct acx_event_mask *mask; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx event mbox mask"); - - mask = kzalloc(sizeof(*mask), GFP_KERNEL); - if (!mask) { - ret = -ENOMEM; - goto out; - } - - /* high event mask is unused */ - mask->high_event_mask = 0xffffffff; - - mask->event_mask = event_mask; - - ret = wl12xx_cmd_configure(wl, ACX_EVENT_MBOX_MASK, - mask, sizeof(*mask)); - if (ret < 0) { - wl12xx_warning("failed to set acx_event_mbox_mask: %d", ret); - goto out; - } - -out: - kfree(mask); - return ret; -} - -int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) -{ - struct acx_preamble *acx; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx_set_preamble"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->preamble = preamble; - - ret = wl12xx_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_warning("Setting of preamble failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_cts_protect(struct wl12xx *wl, - enum acx_ctsprotect_type ctsprotect) -{ - struct acx_ctsprotect *acx; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->ctsprotect = ctsprotect; - - ret = wl12xx_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_warning("Setting of ctsprotect failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime) -{ - struct acx_tsf_info *tsf_info; - int ret; - - tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); - if (!tsf_info) { - ret = -ENOMEM; - goto out; - } - - ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, - tsf_info, sizeof(*tsf_info)); - if (ret < 0) { - wl12xx_warning("ACX_FW_REV interrogate failed"); - goto out; - } - - *mactime = tsf_info->current_tsf_lsb | - (tsf_info->current_tsf_msb << 31); - -out: - kfree(tsf_info); - return ret; -} - -int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) -{ - int ret; - - wl12xx_debug(DEBUG_ACX, "acx statistics"); - - ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, stats, - sizeof(*stats)); - if (ret < 0) { - wl12xx_warning("acx statistics failed: %d", ret); - return -ENOMEM; - } - - return 0; -} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h deleted file mode 100644 index 92e7248..0000000 --- a/drivers/net/wireless/wl12xx/acx.h +++ /dev/null @@ -1,1146 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_ACX_H__ -#define __WL12XX_ACX_H__ - -#include "wl12xx.h" -#include "cmd.h" - -/* Target's information element */ -struct acx_header { - struct wl12xx_cmd_header cmd; - - /* acx (or information element) header */ - u16 id; - - /* payload length (not including headers */ - u16 len; -}; - -struct acx_error_counter { - struct acx_header header; - - /* The number of PLCP errors since the last time this */ - /* information element was interrogated. This field is */ - /* automatically cleared when it is interrogated.*/ - u32 PLCP_error; - - /* The number of FCS errors since the last time this */ - /* information element was interrogated. This field is */ - /* automatically cleared when it is interrogated.*/ - u32 FCS_error; - - /* The number of MPDUs without PLCP header errors received*/ - /* since the last time this information element was interrogated. */ - /* This field is automatically cleared when it is interrogated.*/ - u32 valid_frame; - - /* the number of missed sequence numbers in the squentially */ - /* values of frames seq numbers */ - u32 seq_num_miss; -} __attribute__ ((packed)); - -struct acx_revision { - struct acx_header header; - - /* - * The WiLink firmware version, an ASCII string x.x.x.x, - * that uniquely identifies the current firmware. - * The left most digit is incremented each time a - * significant change is made to the firmware, such as - * code redesign or new platform support. - * The second digit is incremented when major enhancements - * are added or major fixes are made. - * The third digit is incremented for each GA release. - * The fourth digit is incremented for each build. - * The first two digits identify a firmware release version, - * in other words, a unique set of features. - * The first three digits identify a GA release. - */ - char fw_version[20]; - - /* - * This 4 byte field specifies the WiLink hardware version. - * bits 0 - 15: Reserved. - * bits 16 - 23: Version ID - The WiLink version ID - * (1 = first spin, 2 = second spin, and so on). - * bits 24 - 31: Chip ID - The WiLink chip ID. - */ - u32 hw_version; -} __attribute__ ((packed)); - -enum wl12xx_psm_mode { - /* Active mode */ - WL12XX_PSM_CAM = 0, - - /* Power save mode */ - WL12XX_PSM_PS = 1, - - /* Extreme low power */ - WL12XX_PSM_ELP = 2, -}; - -struct acx_sleep_auth { - struct acx_header header; - - /* The sleep level authorization of the device. */ - /* 0 - Always active*/ - /* 1 - Power down mode: light / fast sleep*/ - /* 2 - ELP mode: Deep / Max sleep*/ - u8 sleep_auth; - u8 padding[3]; -} __attribute__ ((packed)); - -enum { - HOSTIF_PCI_MASTER_HOST_INDIRECT, - HOSTIF_PCI_MASTER_HOST_DIRECT, - HOSTIF_SLAVE, - HOSTIF_PKT_RING, - HOSTIF_DONTCARE = 0xFF -}; - -#define DEFAULT_UCAST_PRIORITY 0 -#define DEFAULT_RX_Q_PRIORITY 0 -#define DEFAULT_NUM_STATIONS 1 -#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ -#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ -#define TRACE_BUFFER_MAX_SIZE 256 - -#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 -#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 -#define DP_RX_PACKET_RING_CHUNK_NUM 2 -#define DP_TX_PACKET_RING_CHUNK_NUM 2 -#define DP_TX_COMPLETE_TIME_OUT 20 -#define FW_TX_CMPLT_BLOCK_SIZE 16 - -struct acx_data_path_params { - struct acx_header header; - - u16 rx_packet_ring_chunk_size; - u16 tx_packet_ring_chunk_size; - - u8 rx_packet_ring_chunk_num; - u8 tx_packet_ring_chunk_num; - - /* - * Maximum number of packets that can be gathered - * in the TX complete ring before an interrupt - * is generated. - */ - u8 tx_complete_threshold; - - /* Number of pending TX complete entries in cyclic ring.*/ - u8 tx_complete_ring_depth; - - /* - * Max num microseconds since a packet enters the TX - * complete ring until an interrupt is generated. - */ - u32 tx_complete_timeout; -} __attribute__ ((packed)); - - -struct acx_data_path_params_resp { - struct acx_header header; - - u16 rx_packet_ring_chunk_size; - u16 tx_packet_ring_chunk_size; - - u8 rx_packet_ring_chunk_num; - u8 tx_packet_ring_chunk_num; - - u8 pad[2]; - - u32 rx_packet_ring_addr; - u32 tx_packet_ring_addr; - - u32 rx_control_addr; - u32 tx_control_addr; - - u32 tx_complete_addr; -} __attribute__ ((packed)); - -#define TX_MSDU_LIFETIME_MIN 0 -#define TX_MSDU_LIFETIME_MAX 3000 -#define TX_MSDU_LIFETIME_DEF 512 -#define RX_MSDU_LIFETIME_MIN 0 -#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF -#define RX_MSDU_LIFETIME_DEF 512000 - -struct acx_rx_msdu_lifetime { - struct acx_header header; - - /* - * The maximum amount of time, in TU, before the - * firmware discards the MSDU. - */ - u32 lifetime; -} __attribute__ ((packed)); - -/* - * RX Config Options Table - * Bit Definition - * === ========== - * 31:14 Reserved - * 13 Copy RX Status - when set, write three receive status words - * to top of rx'd MPDUs. - * When cleared, do not write three status words (added rev 1.5) - * 12 Reserved - * 11 RX Complete upon FCS error - when set, give rx complete - * interrupt for FCS errors, after the rx filtering, e.g. unicast - * frames not to us with FCS error will not generate an interrupt. - * 10 SSID Filter Enable - When set, the WiLink discards all beacon, - * probe request, and probe response frames with an SSID that does - * not match the SSID specified by the host in the START/JOIN - * command. - * When clear, the WiLink receives frames with any SSID. - * 9 Broadcast Filter Enable - When set, the WiLink discards all - * broadcast frames. When clear, the WiLink receives all received - * broadcast frames. - * 8:6 Reserved - * 5 BSSID Filter Enable - When set, the WiLink discards any frames - * with a BSSID that does not match the BSSID specified by the - * host. - * When clear, the WiLink receives frames from any BSSID. - * 4 MAC Addr Filter - When set, the WiLink discards any frames - * with a destination address that does not match the MAC address - * of the adaptor. - * When clear, the WiLink receives frames destined to any MAC - * address. - * 3 Promiscuous - When set, the WiLink receives all valid frames - * (i.e., all frames that pass the FCS check). - * When clear, only frames that pass the other filters specified - * are received. - * 2 FCS - When set, the WiLink includes the FCS with the received - * frame. - * When cleared, the FCS is discarded. - * 1 PLCP header - When set, write all data from baseband to frame - * buffer including PHY header. - * 0 Reserved - Always equal to 0. - * - * RX Filter Options Table - * Bit Definition - * === ========== - * 31:12 Reserved - Always equal to 0. - * 11 Association - When set, the WiLink receives all association - * related frames (association request/response, reassocation - * request/response, and disassociation). When clear, these frames - * are discarded. - * 10 Auth/De auth - When set, the WiLink receives all authentication - * and de-authentication frames. When clear, these frames are - * discarded. - * 9 Beacon - When set, the WiLink receives all beacon frames. - * When clear, these frames are discarded. - * 8 Contention Free - When set, the WiLink receives all contention - * free frames. - * When clear, these frames are discarded. - * 7 Control - When set, the WiLink receives all control frames. - * When clear, these frames are discarded. - * 6 Data - When set, the WiLink receives all data frames. - * When clear, these frames are discarded. - * 5 FCS Error - When set, the WiLink receives frames that have FCS - * errors. - * When clear, these frames are discarded. - * 4 Management - When set, the WiLink receives all management - * frames. - * When clear, these frames are discarded. - * 3 Probe Request - When set, the WiLink receives all probe request - * frames. - * When clear, these frames are discarded. - * 2 Probe Response - When set, the WiLink receives all probe - * response frames. - * When clear, these frames are discarded. - * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK - * frames. - * When clear, these frames are discarded. - * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames - * that have reserved frame types and sub types as defined by the - * 802.11 specification. - * When clear, these frames are discarded. - */ -struct acx_rx_config { - struct acx_header header; - - u32 config_options; - u32 filter_options; -} __attribute__ ((packed)); - -enum { - QOS_AC_BE = 0, - QOS_AC_BK, - QOS_AC_VI, - QOS_AC_VO, - QOS_HIGHEST_AC_INDEX = QOS_AC_VO, -}; - -#define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) -#define FIRST_AC_INDEX QOS_AC_BE -#define MAX_NUM_OF_802_1d_TAGS 8 -#define AC_PARAMS_MAX_TSID 15 -#define MAX_APSD_CONF 0xffff - -#define QOS_TX_HIGH_MIN (0) -#define QOS_TX_HIGH_MAX (100) - -#define QOS_TX_HIGH_BK_DEF (25) -#define QOS_TX_HIGH_BE_DEF (35) -#define QOS_TX_HIGH_VI_DEF (35) -#define QOS_TX_HIGH_VO_DEF (35) - -#define QOS_TX_LOW_BK_DEF (15) -#define QOS_TX_LOW_BE_DEF (25) -#define QOS_TX_LOW_VI_DEF (25) -#define QOS_TX_LOW_VO_DEF (25) - -struct acx_tx_queue_qos_config { - struct acx_header header; - - u8 qid; - u8 pad[3]; - - /* Max number of blocks allowd in the queue */ - u16 high_threshold; - - /* Lowest memory blocks guaranteed for this queue */ - u16 low_threshold; -} __attribute__ ((packed)); - -struct acx_packet_detection { - struct acx_header header; - - u32 threshold; -} __attribute__ ((packed)); - - -enum acx_slot_type { - SLOT_TIME_LONG = 0, - SLOT_TIME_SHORT = 1, - DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, - MAX_SLOT_TIMES = 0xFF -}; - -#define STATION_WONE_INDEX 0 - -struct acx_slot { - struct acx_header header; - - u8 wone_index; /* Reserved */ - u8 slot_time; - u8 reserved[6]; -} __attribute__ ((packed)); - - -#define ADDRESS_GROUP_MAX (8) -#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) - -struct acx_dot11_grp_addr_tbl { - struct acx_header header; - - u8 enabled; - u8 num_groups; - u8 pad[2]; - u8 mac_table[ADDRESS_GROUP_MAX_LEN]; -} __attribute__ ((packed)); - - -#define RX_TIMEOUT_PS_POLL_MIN 0 -#define RX_TIMEOUT_PS_POLL_MAX (200000) -#define RX_TIMEOUT_PS_POLL_DEF (15) -#define RX_TIMEOUT_UPSD_MIN 0 -#define RX_TIMEOUT_UPSD_MAX (200000) -#define RX_TIMEOUT_UPSD_DEF (15) - -struct acx_rx_timeout { - struct acx_header header; - - /* - * The longest time the STA will wait to receive - * traffic from the AP after a PS-poll has been - * transmitted. - */ - u16 ps_poll_timeout; - - /* - * The longest time the STA will wait to receive - * traffic from the AP after a frame has been sent - * from an UPSD enabled queue. - */ - u16 upsd_timeout; -} __attribute__ ((packed)); - -#define RTS_THRESHOLD_MIN 0 -#define RTS_THRESHOLD_MAX 4096 -#define RTS_THRESHOLD_DEF 2347 - -struct acx_rts_threshold { - struct acx_header header; - - u16 threshold; - u8 pad[2]; -} __attribute__ ((packed)); - -struct acx_beacon_filter_option { - struct acx_header header; - - u8 enable; - - /* - * The number of beacons without the unicast TIM - * bit set that the firmware buffers before - * signaling the host about ready frames. - * When set to 0 and the filter is enabled, beacons - * without the unicast TIM bit set are dropped. - */ - u8 max_num_beacons; - u8 pad[2]; -} __attribute__ ((packed)); - -/* - * ACXBeaconFilterEntry (not 221) - * Byte Offset Size (Bytes) Definition - * =========== ============ ========== - * 0 1 IE identifier - * 1 1 Treatment bit mask - * - * ACXBeaconFilterEntry (221) - * Byte Offset Size (Bytes) Definition - * =========== ============ ========== - * 0 1 IE identifier - * 1 1 Treatment bit mask - * 2 3 OUI - * 5 1 Type - * 6 2 Version - * - * - * Treatment bit mask - The information element handling: - * bit 0 - The information element is compared and transferred - * in case of change. - * bit 1 - The information element is transferred to the host - * with each appearance or disappearance. - * Note that both bits can be set at the same time. - */ -#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) -#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) -#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) -#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) -#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ - BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ - (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ - BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) - -struct acx_beacon_filter_ie_table { - struct acx_header header; - - u8 num_ie; - u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; - u8 pad[3]; -} __attribute__ ((packed)); - -enum { - SG_ENABLE = 0, - SG_DISABLE, - SG_SENSE_NO_ACTIVITY, - SG_SENSE_ACTIVE -}; - -struct acx_bt_wlan_coex { - struct acx_header header; - - /* - * 0 -> PTA enabled - * 1 -> PTA disabled - * 2 -> sense no active mode, i.e. - * an interrupt is sent upon - * BT activity. - * 3 -> PTA is switched on in response - * to the interrupt sending. - */ - u8 enable; - u8 pad[3]; -} __attribute__ ((packed)); - -#define PTA_ANTENNA_TYPE_DEF (0) -#define PTA_BT_HP_MAXTIME_DEF (2000) -#define PTA_WLAN_HP_MAX_TIME_DEF (5000) -#define PTA_SENSE_DISABLE_TIMER_DEF (1350) -#define PTA_PROTECTIVE_RX_TIME_DEF (1500) -#define PTA_PROTECTIVE_TX_TIME_DEF (1500) -#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) -#define PTA_SIGNALING_TYPE_DEF (1) -#define PTA_AFH_LEVERAGE_ON_DEF (0) -#define PTA_NUMBER_QUIET_CYCLE_DEF (0) -#define PTA_MAX_NUM_CTS_DEF (3) -#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) -#define PTA_NUMBER_OF_BT_PACKETS_DEF (2) -#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) -#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) -#define PTA_CYCLE_TIME_FAST_DEF (8700) -#define PTA_RX_FOR_AVALANCHE_DEF (5) -#define PTA_ELP_HP_DEF (0) -#define PTA_ANTI_STARVE_PERIOD_DEF (500) -#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) -#define PTA_ALLOW_PA_SD_DEF (1) -#define PTA_TIME_BEFORE_BEACON_DEF (6300) -#define PTA_HPDM_MAX_TIME_DEF (1600) -#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) -#define PTA_AUTO_MODE_NO_CTS_DEF (0) -#define PTA_BT_HP_RESPECTED_DEF (3) -#define PTA_WLAN_RX_MIN_RATE_DEF (24) -#define PTA_ACK_MODE_DEF (1) - -struct acx_bt_wlan_coex_param { - struct acx_header header; - - /* - * The minimum rate of a received WLAN packet in the STA, - * during protective mode, of which a new BT-HP request - * during this Rx will always be respected and gain the antenna. - */ - u32 min_rate; - - /* Max time the BT HP will be respected. */ - u16 bt_hp_max_time; - - /* Max time the WLAN HP will be respected. */ - u16 wlan_hp_max_time; - - /* - * The time between the last BT activity - * and the moment when the sense mode returns - * to SENSE_INACTIVE. - */ - u16 sense_disable_timer; - - /* Time before the next BT HP instance */ - u16 rx_time_bt_hp; - u16 tx_time_bt_hp; - - /* range: 10-20000 default: 1500 */ - u16 rx_time_bt_hp_fast; - u16 tx_time_bt_hp_fast; - - /* range: 2000-65535 default: 8700 */ - u16 wlan_cycle_fast; - - /* range: 0 - 15000 (Msec) default: 1000 */ - u16 bt_anti_starvation_period; - - /* range 400-10000(Usec) default: 3000 */ - u16 next_bt_lp_packet; - - /* Deafult: worst case for BT DH5 traffic */ - u16 wake_up_beacon; - - /* range: 0-50000(Usec) default: 1050 */ - u16 hp_dm_max_guard_time; - - /* - * This is to prevent both BT & WLAN antenna - * starvation. - * Range: 100-50000(Usec) default:2550 - */ - u16 next_wlan_packet; - - /* 0 -> shared antenna */ - u8 antenna_type; - - /* - * 0 -> TI legacy - * 1 -> Palau - */ - u8 signal_type; - - /* - * BT AFH status - * 0 -> no AFH - * 1 -> from dedicated GPIO - * 2 -> AFH on (from host) - */ - u8 afh_leverage_on; - - /* - * The number of cycles during which no - * TX will be sent after 1 cycle of RX - * transaction in protective mode - */ - u8 quiet_cycle_num; - - /* - * The maximum number of CTSs that will - * be sent for receiving RX packet in - * protective mode - */ - u8 max_cts; - - /* - * The number of WLAN packets - * transferred in common mode before - * switching to BT. - */ - u8 wlan_packets_num; - - /* - * The number of BT packets - * transferred in common mode before - * switching to WLAN. - */ - u8 bt_packets_num; - - /* range: 1-255 default: 5 */ - u8 missed_rx_avalanche; - - /* range: 0-1 default: 1 */ - u8 wlan_elp_hp; - - /* range: 0 - 15 default: 4 */ - u8 bt_anti_starvation_cycles; - - u8 ack_mode_dual_ant; - - /* - * Allow PA_SD assertion/de-assertion - * during enabled BT activity. - */ - u8 pa_sd_enable; - - /* - * Enable/Disable PTA in auto mode: - * Support Both Active & P.S modes - */ - u8 pta_auto_mode_enable; - - /* range: 0 - 20 default: 1 */ - u8 bt_hp_respected_num; -} __attribute__ ((packed)); - -#define CCA_THRSH_ENABLE_ENERGY_D 0x140A -#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF - -struct acx_energy_detection { - struct acx_header header; - - /* The RX Clear Channel Assessment threshold in the PHY */ - u16 rx_cca_threshold; - u8 tx_energy_detection; - u8 pad; -} __attribute__ ((packed)); - -#define BCN_RX_TIMEOUT_DEF_VALUE 10000 -#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 -#define RX_BROADCAST_IN_PS_DEF_VALUE 1 -#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 - -struct acx_beacon_broadcast { - struct acx_header header; - - u16 beacon_rx_timeout; - u16 broadcast_timeout; - - /* Enables receiving of broadcast packets in PS mode */ - u8 rx_broadcast_in_ps; - - /* Consecutive PS Poll failures before updating the host */ - u8 ps_poll_threshold; - u8 pad[2]; -} __attribute__ ((packed)); - -struct acx_event_mask { - struct acx_header header; - - u32 event_mask; - u32 high_event_mask; /* Unused */ -} __attribute__ ((packed)); - -#define CFG_RX_FCS BIT(2) -#define CFG_RX_ALL_GOOD BIT(3) -#define CFG_UNI_FILTER_EN BIT(4) -#define CFG_BSSID_FILTER_EN BIT(5) -#define CFG_MC_FILTER_EN BIT(6) -#define CFG_MC_ADDR0_EN BIT(7) -#define CFG_MC_ADDR1_EN BIT(8) -#define CFG_BC_REJECT_EN BIT(9) -#define CFG_SSID_FILTER_EN BIT(10) -#define CFG_RX_INT_FCS_ERROR BIT(11) -#define CFG_RX_INT_ENCRYPTED BIT(12) -#define CFG_RX_WR_RX_STATUS BIT(13) -#define CFG_RX_FILTER_NULTI BIT(14) -#define CFG_RX_RESERVE BIT(15) -#define CFG_RX_TIMESTAMP_TSF BIT(16) - -#define CFG_RX_RSV_EN BIT(0) -#define CFG_RX_RCTS_ACK BIT(1) -#define CFG_RX_PRSP_EN BIT(2) -#define CFG_RX_PREQ_EN BIT(3) -#define CFG_RX_MGMT_EN BIT(4) -#define CFG_RX_FCS_ERROR BIT(5) -#define CFG_RX_DATA_EN BIT(6) -#define CFG_RX_CTL_EN BIT(7) -#define CFG_RX_CF_EN BIT(8) -#define CFG_RX_BCN_EN BIT(9) -#define CFG_RX_AUTH_EN BIT(10) -#define CFG_RX_ASSOC_EN BIT(11) - -#define SCAN_PASSIVE BIT(0) -#define SCAN_5GHZ_BAND BIT(1) -#define SCAN_TRIGGERED BIT(2) -#define SCAN_PRIORITY_HIGH BIT(3) - -struct acx_fw_gen_frame_rates { - struct acx_header header; - - u8 tx_ctrl_frame_rate; /* RATE_* */ - u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ - u8 tx_mgt_frame_rate; - u8 tx_mgt_frame_mod; -} __attribute__ ((packed)); - -/* STA MAC */ -struct acx_dot11_station_id { - struct acx_header header; - - u8 mac[ETH_ALEN]; - u8 pad[2]; -} __attribute__ ((packed)); - -struct acx_feature_config { - struct acx_header header; - - u32 options; - u32 data_flow_options; -} __attribute__ ((packed)); - -struct acx_current_tx_power { - struct acx_header header; - - u8 current_tx_power; - u8 padding[3]; -} __attribute__ ((packed)); - -struct acx_dot11_default_key { - struct acx_header header; - - u8 id; - u8 pad[3]; -} __attribute__ ((packed)); - -struct acx_tsf_info { - struct acx_header header; - - u32 current_tsf_msb; - u32 current_tsf_lsb; - u32 last_TBTT_msb; - u32 last_TBTT_lsb; - u8 last_dtim_count; - u8 pad[3]; -} __attribute__ ((packed)); - -enum acx_wake_up_event { - WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ - WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ - WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ - WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ - WAKE_UP_EVENT_BITS_MASK = 0x0F -}; - -struct acx_wake_up_condition { - struct acx_header header; - - u8 wake_up_event; /* Only one bit can be set */ - u8 listen_interval; - u8 pad[2]; -} __attribute__ ((packed)); - -struct acx_aid { - struct acx_header header; - - /* - * To be set when associated with an AP. - */ - u16 aid; - u8 pad[2]; -} __attribute__ ((packed)); - -enum acx_preamble_type { - ACX_PREAMBLE_LONG = 0, - ACX_PREAMBLE_SHORT = 1 -}; - -struct acx_preamble { - struct acx_header header; - - /* - * When set, the WiLink transmits the frames with a short preamble and - * when cleared, the WiLink transmits the frames with a long preamble. - */ - u8 preamble; - u8 padding[3]; -} __attribute__ ((packed)); - -enum acx_ctsprotect_type { - CTSPROTECT_DISABLE = 0, - CTSPROTECT_ENABLE = 1 -}; - -struct acx_ctsprotect { - struct acx_header header; - u8 ctsprotect; - u8 padding[3]; -} __attribute__ ((packed)); - -struct acx_tx_statistics { - u32 internal_desc_overflow; -} __attribute__ ((packed)); - -struct acx_rx_statistics { - u32 out_of_mem; - u32 hdr_overflow; - u32 hw_stuck; - u32 dropped; - u32 fcs_err; - u32 xfr_hint_trig; - u32 path_reset; - u32 reset_counter; -} __attribute__ ((packed)); - -struct acx_dma_statistics { - u32 rx_requested; - u32 rx_errors; - u32 tx_requested; - u32 tx_errors; -} __attribute__ ((packed)); - -struct acx_isr_statistics { - /* host command complete */ - u32 cmd_cmplt; - - /* fiqisr() */ - u32 fiqs; - - /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ - u32 rx_headers; - - /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ - u32 rx_completes; - - /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ - u32 rx_mem_overflow; - - /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ - u32 rx_rdys; - - /* irqisr() */ - u32 irqs; - - /* (INT_STS_ND & INT_TRIG_TX_PROC) */ - u32 tx_procs; - - /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ - u32 decrypt_done; - - /* (INT_STS_ND & INT_TRIG_DMA0) */ - u32 dma0_done; - - /* (INT_STS_ND & INT_TRIG_DMA1) */ - u32 dma1_done; - - /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ - u32 tx_exch_complete; - - /* (INT_STS_ND & INT_TRIG_COMMAND) */ - u32 commands; - - /* (INT_STS_ND & INT_TRIG_RX_PROC) */ - u32 rx_procs; - - /* (INT_STS_ND & INT_TRIG_PM_802) */ - u32 hw_pm_mode_changes; - - /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ - u32 host_acknowledges; - - /* (INT_STS_ND & INT_TRIG_PM_PCI) */ - u32 pci_pm; - - /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ - u32 wakeups; - - /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ - u32 low_rssi; -} __attribute__ ((packed)); - -struct acx_wep_statistics { - /* WEP address keys configured */ - u32 addr_key_count; - - /* default keys configured */ - u32 default_key_count; - - u32 reserved; - - /* number of times that WEP key not found on lookup */ - u32 key_not_found; - - /* number of times that WEP key decryption failed */ - u32 decrypt_fail; - - /* WEP packets decrypted */ - u32 packets; - - /* WEP decrypt interrupts */ - u32 interrupt; -} __attribute__ ((packed)); - -#define ACX_MISSED_BEACONS_SPREAD 10 - -struct acx_pwr_statistics { - /* the amount of enters into power save mode (both PD & ELP) */ - u32 ps_enter; - - /* the amount of enters into ELP mode */ - u32 elp_enter; - - /* the amount of missing beacon interrupts to the host */ - u32 missing_bcns; - - /* the amount of wake on host-access times */ - u32 wake_on_host; - - /* the amount of wake on timer-expire */ - u32 wake_on_timer_exp; - - /* the number of packets that were transmitted with PS bit set */ - u32 tx_with_ps; - - /* the number of packets that were transmitted with PS bit clear */ - u32 tx_without_ps; - - /* the number of received beacons */ - u32 rcvd_beacons; - - /* the number of entering into PowerOn (power save off) */ - u32 power_save_off; - - /* the number of entries into power save mode */ - u16 enable_ps; - - /* - * the number of exits from power save, not including failed PS - * transitions - */ - u16 disable_ps; - - /* - * the number of times the TSF counter was adjusted because - * of drift - */ - u32 fix_tsf_ps; - - /* Gives statistics about the spread continuous missed beacons. - * The 16 LSB are dedicated for the PS mode. - * The 16 MSB are dedicated for the PS mode. - * cont_miss_bcns_spread[0] - single missed beacon. - * cont_miss_bcns_spread[1] - two continuous missed beacons. - * cont_miss_bcns_spread[2] - three continuous missed beacons. - * ... - * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. - */ - u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; - - /* the number of beacons in awake mode */ - u32 rcvd_awake_beacons; -} __attribute__ ((packed)); - -struct acx_mic_statistics { - u32 rx_pkts; - u32 calc_failure; -} __attribute__ ((packed)); - -struct acx_aes_statistics { - u32 encrypt_fail; - u32 decrypt_fail; - u32 encrypt_packets; - u32 decrypt_packets; - u32 encrypt_interrupt; - u32 decrypt_interrupt; -} __attribute__ ((packed)); - -struct acx_event_statistics { - u32 heart_beat; - u32 calibration; - u32 rx_mismatch; - u32 rx_mem_empty; - u32 rx_pool; - u32 oom_late; - u32 phy_transmit_error; - u32 tx_stuck; -} __attribute__ ((packed)); - -struct acx_ps_statistics { - u32 pspoll_timeouts; - u32 upsd_timeouts; - u32 upsd_max_sptime; - u32 upsd_max_apturn; - u32 pspoll_max_apturn; - u32 pspoll_utilization; - u32 upsd_utilization; -} __attribute__ ((packed)); - -struct acx_rxpipe_statistics { - u32 rx_prep_beacon_drop; - u32 descr_host_int_trig_rx_data; - u32 beacon_buffer_thres_host_int_trig_rx_data; - u32 missed_beacon_host_int_trig_rx_data; - u32 tx_xfr_host_int_trig_rx_data; -} __attribute__ ((packed)); - -struct acx_statistics { - struct acx_header header; - - struct acx_tx_statistics tx; - struct acx_rx_statistics rx; - struct acx_dma_statistics dma; - struct acx_isr_statistics isr; - struct acx_wep_statistics wep; - struct acx_pwr_statistics pwr; - struct acx_aes_statistics aes; - struct acx_mic_statistics mic; - struct acx_event_statistics event; - struct acx_ps_statistics ps; - struct acx_rxpipe_statistics rxpipe; -} __attribute__ ((packed)); - -enum { - ACX_WAKE_UP_CONDITIONS = 0x0002, - ACX_MEM_CFG = 0x0003, - ACX_SLOT = 0x0004, - ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ - ACX_AC_CFG = 0x0007, - ACX_MEM_MAP = 0x0008, - ACX_AID = 0x000A, - ACX_RADIO_PARAM = 0x000B, /* Not used */ - ACX_CFG = 0x000C, /* Not used */ - ACX_FW_REV = 0x000D, - ACX_MEDIUM_USAGE = 0x000F, - ACX_RX_CFG = 0x0010, - ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ - ACX_BSS_IN_PS = 0x0012, /* for AP only */ - ACX_STATISTICS = 0x0013, /* Debug API */ - ACX_FEATURE_CFG = 0x0015, - ACX_MISC_CFG = 0x0017, /* Not used */ - ACX_TID_CFG = 0x001A, - ACX_BEACON_FILTER_OPT = 0x001F, - ACX_LOW_RSSI = 0x0020, - ACX_NOISE_HIST = 0x0021, - ACX_HDK_VERSION = 0x0022, /* ??? */ - ACX_PD_THRESHOLD = 0x0023, - ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ - ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ - ACX_CCA_THRESHOLD = 0x0025, - ACX_EVENT_MBOX_MASK = 0x0026, -#ifdef FW_RUNNING_AS_AP - ACX_DTIM_PERIOD = 0x0027, /* for AP only */ -#else - ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ -#endif - ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ - ACX_GPIO_CFG = 0x002A, /* Not used */ - ACX_GPIO_SET = 0x002B, /* Not used */ - ACX_PM_CFG = 0x002C, /* To Be Documented */ - ACX_CONN_MONIT_PARAMS = 0x002D, - ACX_AVERAGE_RSSI = 0x002E, /* Not used */ - ACX_CONS_TX_FAILURE = 0x002F, - ACX_BCN_DTIM_OPTIONS = 0x0031, - ACX_SG_ENABLE = 0x0032, - ACX_SG_CFG = 0x0033, - ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ - ACX_LOW_SNR = 0x0037, /* To Be Documented */ - ACX_BEACON_FILTER_TABLE = 0x0038, - ACX_ARP_IP_FILTER = 0x0039, - ACX_ROAMING_STATISTICS_TBL = 0x003B, - ACX_RATE_POLICY = 0x003D, - ACX_CTS_PROTECTION = 0x003E, - ACX_SLEEP_AUTH = 0x003F, - ACX_PREAMBLE_TYPE = 0x0040, - ACX_ERROR_CNT = 0x0041, - ACX_FW_GEN_FRAME_RATES = 0x0042, - ACX_IBSS_FILTER = 0x0044, - ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, - ACX_TSF_INFO = 0x0046, - ACX_CONFIG_PS_WMM = 0x0049, - ACX_ENABLE_RX_DATA_FILTER = 0x004A, - ACX_SET_RX_DATA_FILTER = 0x004B, - ACX_GET_DATA_FILTER_STATISTICS = 0x004C, - ACX_POWER_LEVEL_TABLE = 0x004D, - ACX_BET_ENABLE = 0x0050, - DOT11_STATION_ID = 0x1001, - DOT11_RX_MSDU_LIFE_TIME = 0x1004, - DOT11_CUR_TX_PWR = 0x100D, - DOT11_DEFAULT_KEY = 0x1010, - DOT11_RX_DOT11_MODE = 0x1012, - DOT11_RTS_THRESHOLD = 0x1013, - DOT11_GROUP_ADDRESS_TBL = 0x1014, - - MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, - - MAX_IE = 0xFFFF -}; - - -int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, - u8 mgt_rate, u8 mgt_mod); -int wl12xx_acx_station_id(struct wl12xx *wl); -int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id); -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, - u8 listen_interval); -int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); -int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); -int wl12xx_acx_tx_power(struct wl12xx *wl, int power); -int wl12xx_acx_feature_cfg(struct wl12xx *wl); -int wl12xx_acx_mem_map(struct wl12xx *wl, - struct acx_header *mem_map, size_t len); -int wl12xx_acx_data_path_params(struct wl12xx *wl, - struct acx_data_path_params_resp *data_path); -int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time); -int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter); -int wl12xx_acx_pd_threshold(struct wl12xx *wl); -int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time); -int wl12xx_acx_group_address_tbl(struct wl12xx *wl); -int wl12xx_acx_service_period_timeout(struct wl12xx *wl); -int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold); -int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl); -int wl12xx_acx_beacon_filter_table(struct wl12xx *wl); -int wl12xx_acx_sg_enable(struct wl12xx *wl); -int wl12xx_acx_sg_cfg(struct wl12xx *wl); -int wl12xx_acx_cca_threshold(struct wl12xx *wl); -int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl); -int wl12xx_acx_aid(struct wl12xx *wl, u16 aid); -int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask); -int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble); -int wl12xx_acx_cts_protect(struct wl12xx *wl, - enum acx_ctsprotect_type ctsprotect); -int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats); -int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime); - -#endif /* __WL12XX_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c deleted file mode 100644 index a6a2649..0000000 --- a/drivers/net/wireless/wl12xx/boot.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include - -#include "reg.h" -#include "boot.h" -#include "spi.h" -#include "event.h" - -static void wl12xx_boot_enable_interrupts(struct wl12xx *wl) -{ - enable_irq(wl->irq); -} - -void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl) -{ - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); -} - -int wl12xx_boot_soft_reset(struct wl12xx *wl) -{ - unsigned long timeout; - u32 boot_data; - - /* perform soft reset */ - wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); - - /* SOFT_RESET is self clearing */ - timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); - while (1) { - boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); - wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); - if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) - break; - - if (time_after(jiffies, timeout)) { - /* 1.2 check pWhalBus->uSelfClearTime if the - * timeout was reached */ - wl12xx_error("soft reset timeout"); - return -1; - } - - udelay(SOFT_RESET_STALL_TIME); - } - - /* disable Rx/Tx */ - wl12xx_reg_write32(wl, ENABLE, 0x0); - - /* disable auto calibration on start*/ - wl12xx_reg_write32(wl, SPARE_A2, 0xffff); - - return 0; -} - -int wl12xx_boot_init_seq(struct wl12xx *wl) -{ - u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; - - /* - * col #1: INTEGER_DIVIDER - * col #2: FRACTIONAL_DIVIDER - * col #3: ATTN_BB - * col #4: ALPHA_BB - * col #5: STOP_TIME_BB - * col #6: BB_PLL_LOOP_FILTER - */ - static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { - - { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ - { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ - { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ - { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ - { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ - }; - - /* read NVS params */ - scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6); - wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); - - /* read ELP_CMD */ - elp_cmd = wl12xx_reg_read32(wl, ELP_CMD); - wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); - - /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ - ref_freq = scr_pad6 & 0x000000FF; - wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); - - wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9); - - /* - * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) - */ - wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6); - - /* - * set the clock detect feature to work in the restart wu procedure - * (ELP_CFG_MODE[14]) and Select the clock source type - * (ELP_CFG_MODE[13:12]) - */ - tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; - wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp); - - /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ - elp_cmd |= 0x00000040; - wl12xx_reg_write32(wl, ELP_CMD, elp_cmd); - - /* PG 1.2: Set the BB PLL stable time to be 1000usec - * (PLL_STABLE_TIME) */ - wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); - - /* PG 1.2: read clock request time */ - init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME); - - /* - * PG 1.2: set the clock request time to be ref_clk_settling_time - - * 1ms = 4ms - */ - if (init_data > 0x21) - tmp = init_data - 0x21; - else - tmp = 0; - wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp); - - /* set BB PLL configurations in RF AFE */ - wl12xx_reg_write32(wl, 0x003058cc, 0x4B5); - - /* set RF_AFE_REG_5 */ - wl12xx_reg_write32(wl, 0x003058d4, 0x50); - - /* set RF_AFE_CTRL_REG_2 */ - wl12xx_reg_write32(wl, 0x00305948, 0x11c001); - - /* - * change RF PLL and BB PLL divider for VCO clock and adjust VCO - * bais current(RF_AFE_REG_13) - */ - wl12xx_reg_write32(wl, 0x003058f4, 0x1e); - - /* set BB PLL configurations */ - tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; - wl12xx_reg_write32(wl, 0x00305840, tmp); - - /* set fractional divider according to Appendix C-BB PLL - * Calculations - */ - tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; - wl12xx_reg_write32(wl, 0x00305844, tmp); - - /* set the initial data for the sigma delta */ - wl12xx_reg_write32(wl, 0x00305848, 0x3039); - - /* - * set the accumulator attenuation value, calibration loop1 - * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and - * the VCO gain - */ - tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | - (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; - wl12xx_reg_write32(wl, 0x00305854, tmp); - - /* - * set the calibration stop time after holdoff time expires and set - * settling time HOLD_OFF_TIME_BB - */ - tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; - wl12xx_reg_write32(wl, 0x00305858, tmp); - - /* - * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL - * constant leakage current to linearize PFD to 0uA - - * BB_ILOOPF[7:3] - */ - tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; - wl12xx_reg_write32(wl, 0x003058f8, tmp); - - /* - * set regulator output voltage for n divider to - * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], - * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB - * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] - */ - wl12xx_reg_write32(wl, 0x003058f0, 0x29); - - /* enable restart wakeup sequence (ELP_CMD[0]) */ - wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); - - /* restart sequence completed */ - udelay(2000); - - return 0; -} - -int wl12xx_boot_run_firmware(struct wl12xx *wl) -{ - int loop, ret; - u32 chip_id, interrupt; - - wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); - - chip_id = wl12xx_reg_read32(wl, CHIP_ID_B); - - wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); - - if (chip_id != wl->chip.id) { - wl12xx_error("chip id doesn't match after firmware boot"); - return -EIO; - } - - /* wait for init to complete */ - loop = 0; - while (loop++ < INIT_LOOP) { - udelay(INIT_LOOP_DELAY); - interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - - if (interrupt == 0xffffffff) { - wl12xx_error("error reading hardware complete " - "init indication"); - return -EIO; - } - /* check that ACX_INTR_INIT_COMPLETE is enabled */ - else if (interrupt & wl->chip.intr_init_complete) { - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - wl->chip.intr_init_complete); - break; - } - } - - if (loop >= INIT_LOOP) { - wl12xx_error("timeout waiting for the hardware to " - "complete initialization"); - return -EIO; - } - - /* get hardware config command mail box */ - wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); - - /* get hardware config event mail box */ - wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); - - /* set the working partition to its "running" mode offset */ - wl12xx_set_partition(wl, - wl->chip.p_table[PART_WORK].mem.start, - wl->chip.p_table[PART_WORK].mem.size, - wl->chip.p_table[PART_WORK].reg.start, - wl->chip.p_table[PART_WORK].reg.size); - - wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", - wl->cmd_box_addr, wl->event_box_addr); - - wl->chip.op_fw_version(wl); - - /* - * in case of full asynchronous mode the firmware event must be - * ready to receive event from the command mailbox - */ - - /* enable gpio interrupts */ - wl12xx_boot_enable_interrupts(wl); - - wl->chip.op_target_enable_interrupts(wl); - - /* unmask all mbox events */ - wl->event_mask = 0xffffffff; - - ret = wl12xx_event_unmask(wl); - if (ret < 0) { - wl12xx_error("EVENT mask setting failed"); - return ret; - } - - wl12xx_event_mbox_config(wl); - - /* firmware startup completed */ - return 0; -} diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h deleted file mode 100644 index 4fa7313..0000000 --- a/drivers/net/wireless/wl12xx/boot.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __BOOT_H__ -#define __BOOT_H__ - -#include "wl12xx.h" - -int wl12xx_boot_soft_reset(struct wl12xx *wl); -int wl12xx_boot_init_seq(struct wl12xx *wl); -int wl12xx_boot_run_firmware(struct wl12xx *wl); -void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl); - -/* number of times we try to read the INIT interrupt */ -#define INIT_LOOP 20000 - -/* delay between retries */ -#define INIT_LOOP_DELAY 50 - -#endif diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c deleted file mode 100644 index cad258d..0000000 --- a/drivers/net/wireless/wl12xx/cmd.c +++ /dev/null @@ -1,429 +0,0 @@ -#include "cmd.h" - -#include -#include -#include - -#include "wl12xx.h" -#include "wl12xx_80211.h" -#include "reg.h" -#include "spi.h" -#include "ps.h" -#include "acx.h" - -/** - * send command to firmware - * - * @wl: wl struct - * @id: command id - * @buf: buffer containing the command, must work with dma - * @len: length of the buffer - */ -int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) -{ - struct wl12xx_cmd_header *cmd; - unsigned long timeout; - u32 intr; - int ret = 0; - - cmd = buf; - cmd->id = id; - cmd->status = 0; - - WARN_ON(len % 4 != 0); - - wl12xx_spi_mem_write(wl, wl->cmd_box_addr, buf, len); - - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); - - timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT); - - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - while (!(intr & wl->chip.intr_cmd_complete)) { - if (time_after(jiffies, timeout)) { - wl12xx_error("command complete timeout"); - ret = -ETIMEDOUT; - goto out; - } - - msleep(1); - - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - } - - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - wl->chip.intr_cmd_complete); - -out: - return ret; -} - -/** - * send test command to firmware - * - * @wl: wl struct - * @buf: buffer containing the command, with all headers, must work with dma - * @len: length of the buffer - * @answer: is answer needed - */ -int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) -{ - int ret; - - wl12xx_debug(DEBUG_CMD, "cmd test"); - - ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); - - if (ret < 0) { - wl12xx_warning("TEST command failed"); - return ret; - } - - if (answer) { - struct wl12xx_command *cmd_answer; - - /* - * The test command got in, we can read the answer. - * The answer would be a wl12xx_command, where the - * parameter array contains the actual answer. - */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); - - cmd_answer = buf; - - if (cmd_answer->header.status != CMD_STATUS_SUCCESS) - wl12xx_error("TEST command answer error: %d", - cmd_answer->header.status); - } - - return 0; -} - -/** - * read acx from firmware - * - * @wl: wl struct - * @id: acx id - * @buf: buffer for the response, including all headers, must work with dma - * @len: lenght of buf - */ -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl12xx_debug(DEBUG_CMD, "cmd interrogate"); - - acx->id = id; - - /* payload length, does not include any headers */ - acx->len = len - sizeof(*acx); - - ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_error("INTERROGATE command failed"); - goto out; - } - - /* the interrogate command got in, we can read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, len); - - acx = buf; - if (acx->cmd.status != CMD_STATUS_SUCCESS) - wl12xx_error("INTERROGATE command error: %d", - acx->cmd.status); - -out: - return ret; -} - -/** - * write acx value to firmware - * - * @wl: wl struct - * @id: acx id - * @buf: buffer containing acx, including all headers, must work with dma - * @len: length of buf - */ -int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl12xx_debug(DEBUG_CMD, "cmd configure"); - - acx->id = id; - - /* payload length, does not include any headers */ - acx->len = len - sizeof(*acx); - - ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, acx, len); - if (ret < 0) { - wl12xx_warning("CONFIGURE command NOK"); - return ret; - } - - return 0; -} - -int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, - void *bitmap, u16 bitmap_len, u8 bitmap_control) -{ - struct wl12xx_cmd_vbm_update *vbm; - int ret; - - wl12xx_debug(DEBUG_CMD, "cmd vbm"); - - vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); - if (!vbm) { - ret = -ENOMEM; - goto out; - } - - /* Count and period will be filled by the target */ - vbm->tim.bitmap_ctrl = bitmap_control; - if (bitmap_len > PARTIAL_VBM_MAX) { - wl12xx_warning("cmd vbm len is %d B, truncating to %d", - bitmap_len, PARTIAL_VBM_MAX); - bitmap_len = PARTIAL_VBM_MAX; - } - memcpy(vbm->tim.pvb_field, bitmap, bitmap_len); - vbm->tim.identity = identity; - vbm->tim.length = bitmap_len + 3; - - vbm->len = cpu_to_le16(bitmap_len + 5); - - ret = wl12xx_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); - if (ret < 0) { - wl12xx_error("VBM command failed"); - goto out; - } - -out: - kfree(vbm); - return 0; -} - -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable) -{ - struct cmd_enabledisable_path *cmd; - int ret; - u16 cmd_rx, cmd_tx; - - wl12xx_debug(DEBUG_CMD, "cmd data path"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->channel = channel; - - if (enable) { - cmd_rx = CMD_ENABLE_RX; - cmd_tx = CMD_ENABLE_TX; - } else { - cmd_rx = CMD_DISABLE_RX; - cmd_tx = CMD_DISABLE_TX; - } - - ret = wl12xx_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); - if (ret < 0) { - wl12xx_error("rx %s cmd for channel %d failed", - enable ? "start" : "stop", channel); - goto out; - } - - wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d", - enable ? "start" : "stop", channel); - - ret = wl12xx_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); - if (ret < 0) { - wl12xx_error("tx %s cmd for channel %d failed", - enable ? "start" : "stop", channel); - return ret; - } - - wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d", - enable ? "start" : "stop", channel); - -out: - kfree(cmd); - return ret; -} - -int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait) -{ - unsigned long timeout; - struct cmd_join *join; - int ret, i; - u8 *bssid; - - join = kzalloc(sizeof(*join), GFP_KERNEL); - if (!join) { - ret = -ENOMEM; - goto out; - } - - /* FIXME: this should be in main.c */ - ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, - DEFAULT_HW_GEN_MODULATION_TYPE, - wl->tx_mgmt_frm_rate, - wl->tx_mgmt_frm_mod); - if (ret < 0) - goto out; - - wl12xx_debug(DEBUG_CMD, "cmd join"); - - /* Reverse order BSSID */ - bssid = (u8 *) &join->bssid_lsb; - for (i = 0; i < ETH_ALEN; i++) - bssid[i] = wl->bssid[ETH_ALEN - i - 1]; - - join->rx_config_options = wl->rx_config; - join->rx_filter_options = wl->rx_filter; - - join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | - RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; - - join->beacon_interval = beacon_interval; - join->dtim_interval = dtim_interval; - join->bss_type = bss_type; - join->channel = wl->channel; - join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; - - ret = wl12xx_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); - if (ret < 0) { - wl12xx_error("failed to initiate cmd join"); - goto out; - } - - timeout = msecs_to_jiffies(JOIN_TIMEOUT); - - /* - * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to - * simplify locking we just sleep instead, for now - */ - if (wait) - msleep(10); - -out: - kfree(join); - return ret; -} - -int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) -{ - struct wl12xx_cmd_ps_params *ps_params = NULL; - int ret = 0; - - /* FIXME: this should be in ps.c */ - ret = wl12xx_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, - wl->listen_int); - if (ret < 0) { - wl12xx_error("couldn't set wake up conditions"); - goto out; - } - - wl12xx_debug(DEBUG_CMD, "cmd set ps mode"); - - ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); - if (!ps_params) { - ret = -ENOMEM; - goto out; - } - - ps_params->ps_mode = ps_mode; - ps_params->send_null_data = 1; - ps_params->retries = 5; - ps_params->hang_over_period = 128; - ps_params->null_data_rate = 1; /* 1 Mbps */ - - ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, ps_params, - sizeof(*ps_params)); - if (ret < 0) { - wl12xx_error("cmd set_ps_mode failed"); - goto out; - } - -out: - kfree(ps_params); - return ret; -} - -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, - size_t len) -{ - struct cmd_read_write_memory *cmd; - int ret = 0; - - wl12xx_debug(DEBUG_CMD, "cmd read memory"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - WARN_ON(len > MAX_READ_SIZE); - len = min_t(size_t, len, MAX_READ_SIZE); - - cmd->addr = addr; - cmd->size = len; - - ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); - if (ret < 0) { - wl12xx_error("read memory command failed: %d", ret); - goto out; - } - - /* the read command got in, we can now read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); - - if (cmd->header.status != CMD_STATUS_SUCCESS) - wl12xx_error("error in read command result: %d", - cmd->header.status); - - memcpy(answer, cmd->value, len); - -out: - kfree(cmd); - return ret; -} - -int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, - void *buf, size_t buf_len) -{ - struct wl12xx_cmd_packet_template *cmd; - size_t cmd_len; - int ret = 0; - - wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id); - - WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE); - buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE); - cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); - - cmd = kzalloc(cmd_len, GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->size = cpu_to_le16(buf_len); - - if (buf) - memcpy(cmd->data, buf, buf_len); - - ret = wl12xx_cmd_send(wl, cmd_id, cmd, cmd_len); - if (ret < 0) { - wl12xx_warning("cmd set_template failed: %d", ret); - goto out; - } - -out: - kfree(cmd); - return ret; -} diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h deleted file mode 100644 index a2eae54..0000000 --- a/drivers/net/wireless/wl12xx/cmd.h +++ /dev/null @@ -1,407 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_CMD_H__ -#define __WL12XX_CMD_H__ - -#include "wl12xx.h" - -struct acx_header; - -int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len); -int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer); -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len); -int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len); -int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, - void *bitmap, u16 bitmap_len, u8 bitmap_control); -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable); -int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait); -int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, - size_t len); -int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, - void *buf, size_t buf_len); - -/* unit ms */ -#define WL12XX_COMMAND_TIMEOUT 2000 - -enum wl12xx_commands { - CMD_RESET = 0, - CMD_INTERROGATE = 1, /*use this to read information elements*/ - CMD_CONFIGURE = 2, /*use this to write information elements*/ - CMD_ENABLE_RX = 3, - CMD_ENABLE_TX = 4, - CMD_DISABLE_RX = 5, - CMD_DISABLE_TX = 6, - CMD_SCAN = 8, - CMD_STOP_SCAN = 9, - CMD_VBM = 10, - CMD_START_JOIN = 11, - CMD_SET_KEYS = 12, - CMD_READ_MEMORY = 13, - CMD_WRITE_MEMORY = 14, - CMD_BEACON = 19, - CMD_PROBE_RESP = 20, - CMD_NULL_DATA = 21, - CMD_PROBE_REQ = 22, - CMD_TEST = 23, - CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ - CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ - CMD_NOISE_HIST = 28, - CMD_RX_RESET = 29, - CMD_PS_POLL = 30, - CMD_QOS_NULL_DATA = 31, - CMD_LNA_CONTROL = 32, - CMD_SET_BCN_MODE = 33, - CMD_MEASUREMENT = 34, - CMD_STOP_MEASUREMENT = 35, - CMD_DISCONNECT = 36, - CMD_SET_PS_MODE = 37, - CMD_CHANNEL_SWITCH = 38, - CMD_STOP_CHANNEL_SWICTH = 39, - CMD_AP_DISCOVERY = 40, - CMD_STOP_AP_DISCOVERY = 41, - CMD_SPS_SCAN = 42, - CMD_STOP_SPS_SCAN = 43, - CMD_HEALTH_CHECK = 45, - CMD_DEBUG = 46, - CMD_TRIGGER_SCAN_TO = 47, - - NUM_COMMANDS, - MAX_COMMAND_ID = 0xFFFF, -}; - -#define MAX_CMD_PARAMS 572 - -struct wl12xx_cmd_header { - u16 id; - u16 status; - /* payload */ - u8 data[0]; -} __attribute__ ((packed)); - -struct wl12xx_command { - struct wl12xx_cmd_header header; - u8 parameters[MAX_CMD_PARAMS]; -}; - -enum { - CMD_MAILBOX_IDLE = 0, - CMD_STATUS_SUCCESS = 1, - CMD_STATUS_UNKNOWN_CMD = 2, - CMD_STATUS_UNKNOWN_IE = 3, - CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, - CMD_STATUS_RX_BUSY = 13, - CMD_STATUS_INVALID_PARAM = 14, - CMD_STATUS_TEMPLATE_TOO_LARGE = 15, - CMD_STATUS_OUT_OF_MEMORY = 16, - CMD_STATUS_STA_TABLE_FULL = 17, - CMD_STATUS_RADIO_ERROR = 18, - CMD_STATUS_WRONG_NESTING = 19, - CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ - CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ - MAX_COMMAND_STATUS = 0xff -}; - - -/* - * CMD_READ_MEMORY - * - * The host issues this command to read the WiLink device memory/registers. - * - * Note: The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -/* - * CMD_WRITE_MEMORY - * - * The host issues this command to write the WiLink device memory/registers. - * - * The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -#define MAX_READ_SIZE 256 - -struct cmd_read_write_memory { - struct wl12xx_cmd_header header; - - /* The address of the memory to read from or write to.*/ - u32 addr; - - /* The amount of data in bytes to read from or write to the WiLink - * device.*/ - u32 size; - - /* The actual value read from or written to the Wilink. The source - of this field is the Host in WRITE command or the Wilink in READ - command. */ - u8 value[MAX_READ_SIZE]; -}; - -#define CMDMBOX_HEADER_LEN 4 -#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 - - -struct basic_scan_parameters { - u32 rx_config_options; - u32 rx_filter_options; - - /* - * Scan options: - * bit 0: When this bit is set, passive scan. - * bit 1: Band, when this bit is set we scan - * in the 5Ghz band. - * bit 2: voice mode, 0 for normal scan. - * bit 3: scan priority, 1 for high priority. - */ - u16 scan_options; - - /* Number of channels to scan */ - u8 num_channels; - - /* Number opf probe requests to send, per channel */ - u8 num_probe_requests; - - /* Rate and modulation for probe requests */ - u16 tx_rate; - - u8 tid_trigger; - u8 ssid_len; - u32 ssid[8]; - -} __attribute__ ((packed)); - -struct basic_scan_channel_parameters { - u32 min_duration; /* in TU */ - u32 max_duration; /* in TU */ - u32 bssid_lsb; - u16 bssid_msb; - - /* - * bits 0-3: Early termination count. - * bits 4-5: Early termination condition. - */ - u8 early_termination; - - u8 tx_power_att; - u8 channel; - u8 pad[3]; -} __attribute__ ((packed)); - -/* SCAN parameters */ -#define SCAN_MAX_NUM_OF_CHANNELS 16 - -struct cmd_scan { - struct wl12xx_cmd_header header; - - struct basic_scan_parameters params; - struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; -} __attribute__ ((packed)); - -enum { - BSS_TYPE_IBSS = 0, - BSS_TYPE_STA_BSS = 2, - BSS_TYPE_AP_BSS = 3, - MAX_BSS_TYPE = 0xFF -}; - -#define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ -#define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ - - -struct cmd_join { - struct wl12xx_cmd_header header; - - u32 bssid_lsb; - u16 bssid_msb; - u16 beacon_interval; /* in TBTTs */ - u32 rx_config_options; - u32 rx_filter_options; - - /* - * The target uses this field to determine the rate at - * which to transmit control frame responses (such as - * ACK or CTS frames). - */ - u16 basic_rate_set; - u8 dtim_interval; - u8 tx_ctrl_frame_rate; /* OBSOLETE */ - u8 tx_ctrl_frame_mod; /* OBSOLETE */ - /* - * bits 0-2: This bitwise field specifies the type - * of BSS to start or join (BSS_TYPE_*). - * bit 4: Band - The radio band in which to join - * or start. - * 0 - 2.4GHz band - * 1 - 5GHz band - * bits 3, 5-7: Reserved - */ - u8 bss_type; - u8 channel; - u8 ssid_len; - u8 ssid[IW_ESSID_MAX_SIZE]; - u8 ctrl; /* JOIN_CMD_CTRL_* */ - u8 tx_mgt_frame_rate; /* OBSOLETE */ - u8 tx_mgt_frame_mod; /* OBSOLETE */ - u8 reserved; -} __attribute__ ((packed)); - -struct cmd_enabledisable_path { - struct wl12xx_cmd_header header; - - u8 channel; - u8 padding[3]; -} __attribute__ ((packed)); - -#define WL12XX_MAX_TEMPLATE_SIZE 300 - -struct wl12xx_cmd_packet_template { - struct wl12xx_cmd_header header; - - __le16 size; - u8 data[0]; -} __attribute__ ((packed)); - -#define TIM_ELE_ID 5 -#define PARTIAL_VBM_MAX 251 - -struct wl12xx_tim { - u8 identity; - u8 length; - u8 dtim_count; - u8 dtim_period; - u8 bitmap_ctrl; - u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ -} __attribute__ ((packed)); - -/* Virtual Bit Map update */ -struct wl12xx_cmd_vbm_update { - struct wl12xx_cmd_header header; - __le16 len; - u8 padding[2]; - struct wl12xx_tim tim; -} __attribute__ ((packed)); - -enum wl12xx_cmd_ps_mode { - STATION_ACTIVE_MODE, - STATION_POWER_SAVE_MODE -}; - -struct wl12xx_cmd_ps_params { - struct wl12xx_cmd_header header; - - u8 ps_mode; /* STATION_* */ - u8 send_null_data; /* Do we have to send NULL data packet ? */ - u8 retries; /* Number of retires for the initial NULL data packet */ - - /* - * TUs during which the target stays awake after switching - * to power save mode. - */ - u8 hang_over_period; - u16 null_data_rate; - u8 pad[2]; -} __attribute__ ((packed)); - -struct wl12xx_cmd_trigger_scan_to { - struct wl12xx_cmd_header header; - - u32 timeout; -}; - -/* HW encryption keys */ -#define NUM_ACCESS_CATEGORIES_COPY 4 -#define MAX_KEY_SIZE 32 - -/* When set, disable HW encryption */ -#define DF_ENCRYPTION_DISABLE 0x01 -/* When set, disable HW decryption */ -#define DF_SNIFF_MODE_ENABLE 0x80 - -enum wl12xx_cmd_key_action { - KEY_ADD_OR_REPLACE = 1, - KEY_REMOVE = 2, - KEY_SET_ID = 3, - MAX_KEY_ACTION = 0xffff, -}; - -enum wl12xx_cmd_key_type { - KEY_WEP_DEFAULT = 0, - KEY_WEP_ADDR = 1, - KEY_AES_GROUP = 4, - KEY_AES_PAIRWISE = 5, - KEY_WEP_GROUP = 6, - KEY_TKIP_MIC_GROUP = 10, - KEY_TKIP_MIC_PAIRWISE = 11, -}; - -/* - * - * key_type_e key size key format - * ---------- --------- ---------- - * 0x00 5, 13, 29 Key data - * 0x01 5, 13, 29 Key data - * 0x04 16 16 bytes of key data - * 0x05 16 16 bytes of key data - * 0x0a 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * 0x0b 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * - */ - -struct wl12xx_cmd_set_keys { - struct wl12xx_cmd_header header; - - /* Ignored for default WEP key */ - u8 addr[ETH_ALEN]; - - /* key_action_e */ - u16 key_action; - - u16 reserved_1; - - /* key size in bytes */ - u8 key_size; - - /* key_type_e */ - u8 key_type; - u8 ssid_profile; - - /* - * TKIP, AES: frame's key id field. - * For WEP default key: key id; - */ - u8 id; - u8 reserved_2[6]; - u8 key[MAX_KEY_SIZE]; - u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; - u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; -} __attribute__ ((packed)); - - -#endif /* __WL12XX_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c deleted file mode 100644 index 94ad994..0000000 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ /dev/null @@ -1,518 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "debugfs.h" - -#include - -#include "wl12xx.h" -#include "acx.h" -#include "ps.h" - -/* ms */ -#define WL12XX_DEBUGFS_STATS_LIFETIME 1000 - -/* debugfs macros idea from mac80211 */ - -#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ -static ssize_t name## _read(struct file *file, char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct wl12xx *wl = file->private_data; \ - char buf[buflen]; \ - int res; \ - \ - res = scnprintf(buf, buflen, fmt "\n", ##value); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ -} \ - \ -static const struct file_operations name## _ops = { \ - .read = name## _read, \ - .open = wl12xx_open_file_generic, \ -}; - -#define DEBUGFS_ADD(name, parent) \ - wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ - wl, &name## _ops); \ - if (IS_ERR(wl->debugfs.name)) { \ - ret = PTR_ERR(wl->debugfs.name); \ - wl->debugfs.name = NULL; \ - goto out; \ - } - -#define DEBUGFS_DEL(name) \ - do { \ - debugfs_remove(wl->debugfs.name); \ - wl->debugfs.name = NULL; \ - } while (0) - -#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ -static ssize_t sub## _ ##name## _read(struct file *file, \ - char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct wl12xx *wl = file->private_data; \ - char buf[buflen]; \ - int res; \ - \ - wl12xx_debugfs_update_stats(wl); \ - \ - res = scnprintf(buf, buflen, fmt "\n", \ - wl->stats.fw_stats->sub.name); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ -} \ - \ -static const struct file_operations sub## _ ##name## _ops = { \ - .read = sub## _ ##name## _read, \ - .open = wl12xx_open_file_generic, \ -}; - -#define DEBUGFS_FWSTATS_ADD(sub, name) \ - DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) - -#define DEBUGFS_FWSTATS_DEL(sub, name) \ - DEBUGFS_DEL(sub## _ ##name) - -static void wl12xx_debugfs_update_stats(struct wl12xx *wl) -{ - int ret; - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (wl->state == WL12XX_STATE_ON && - time_after(jiffies, wl->stats.fw_stats_update + - msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) { - wl12xx_acx_statistics(wl, wl->stats.fw_stats); - wl->stats.fw_stats_update = jiffies; - } - - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl12xx_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); -/* skipping wep.reserved */ -DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); -/* skipping cont_miss_bcns_spread for now */ -DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, - 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); - -DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); -DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", - wl->stats.excessive_retries); - -static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct wl12xx *wl = file->private_data; - u32 queue_len; - char buf[20]; - int res; - - queue_len = skb_queue_len(&wl->tx_queue); - - res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); - return simple_read_from_buffer(userbuf, count, ppos, buf, res); -} - -static const struct file_operations tx_queue_len_ops = { - .read = tx_queue_len_read, - .open = wl12xx_open_file_generic, -}; - -static void wl12xx_debugfs_delete_files(struct wl12xx *wl) -{ - DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); - - DEBUGFS_FWSTATS_DEL(rx, out_of_mem); - DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); - DEBUGFS_FWSTATS_DEL(rx, hw_stuck); - DEBUGFS_FWSTATS_DEL(rx, dropped); - DEBUGFS_FWSTATS_DEL(rx, fcs_err); - DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); - DEBUGFS_FWSTATS_DEL(rx, path_reset); - DEBUGFS_FWSTATS_DEL(rx, reset_counter); - - DEBUGFS_FWSTATS_DEL(dma, rx_requested); - DEBUGFS_FWSTATS_DEL(dma, rx_errors); - DEBUGFS_FWSTATS_DEL(dma, tx_requested); - DEBUGFS_FWSTATS_DEL(dma, tx_errors); - - DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); - DEBUGFS_FWSTATS_DEL(isr, fiqs); - DEBUGFS_FWSTATS_DEL(isr, rx_headers); - DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); - DEBUGFS_FWSTATS_DEL(isr, rx_rdys); - DEBUGFS_FWSTATS_DEL(isr, irqs); - DEBUGFS_FWSTATS_DEL(isr, tx_procs); - DEBUGFS_FWSTATS_DEL(isr, decrypt_done); - DEBUGFS_FWSTATS_DEL(isr, dma0_done); - DEBUGFS_FWSTATS_DEL(isr, dma1_done); - DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); - DEBUGFS_FWSTATS_DEL(isr, commands); - DEBUGFS_FWSTATS_DEL(isr, rx_procs); - DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); - DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); - DEBUGFS_FWSTATS_DEL(isr, pci_pm); - DEBUGFS_FWSTATS_DEL(isr, wakeups); - DEBUGFS_FWSTATS_DEL(isr, low_rssi); - - DEBUGFS_FWSTATS_DEL(wep, addr_key_count); - DEBUGFS_FWSTATS_DEL(wep, default_key_count); - /* skipping wep.reserved */ - DEBUGFS_FWSTATS_DEL(wep, key_not_found); - DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); - DEBUGFS_FWSTATS_DEL(wep, packets); - DEBUGFS_FWSTATS_DEL(wep, interrupt); - - DEBUGFS_FWSTATS_DEL(pwr, ps_enter); - DEBUGFS_FWSTATS_DEL(pwr, elp_enter); - DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); - DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); - DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); - DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); - DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); - DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); - DEBUGFS_FWSTATS_DEL(pwr, power_save_off); - DEBUGFS_FWSTATS_DEL(pwr, enable_ps); - DEBUGFS_FWSTATS_DEL(pwr, disable_ps); - DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); - /* skipping cont_miss_bcns_spread for now */ - DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); - - DEBUGFS_FWSTATS_DEL(mic, rx_pkts); - DEBUGFS_FWSTATS_DEL(mic, calc_failure); - - DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); - DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); - DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); - DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); - DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); - DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); - - DEBUGFS_FWSTATS_DEL(event, heart_beat); - DEBUGFS_FWSTATS_DEL(event, calibration); - DEBUGFS_FWSTATS_DEL(event, rx_mismatch); - DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); - DEBUGFS_FWSTATS_DEL(event, rx_pool); - DEBUGFS_FWSTATS_DEL(event, oom_late); - DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); - DEBUGFS_FWSTATS_DEL(event, tx_stuck); - - DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); - DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); - DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); - DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); - DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); - DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); - DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); - - DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); - DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); - - DEBUGFS_DEL(tx_queue_len); - DEBUGFS_DEL(retry_count); - DEBUGFS_DEL(excessive_retries); -} - -static int wl12xx_debugfs_add_files(struct wl12xx *wl) -{ - int ret = 0; - - DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); - - DEBUGFS_FWSTATS_ADD(rx, out_of_mem); - DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); - DEBUGFS_FWSTATS_ADD(rx, hw_stuck); - DEBUGFS_FWSTATS_ADD(rx, dropped); - DEBUGFS_FWSTATS_ADD(rx, fcs_err); - DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); - DEBUGFS_FWSTATS_ADD(rx, path_reset); - DEBUGFS_FWSTATS_ADD(rx, reset_counter); - - DEBUGFS_FWSTATS_ADD(dma, rx_requested); - DEBUGFS_FWSTATS_ADD(dma, rx_errors); - DEBUGFS_FWSTATS_ADD(dma, tx_requested); - DEBUGFS_FWSTATS_ADD(dma, tx_errors); - - DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); - DEBUGFS_FWSTATS_ADD(isr, fiqs); - DEBUGFS_FWSTATS_ADD(isr, rx_headers); - DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); - DEBUGFS_FWSTATS_ADD(isr, rx_rdys); - DEBUGFS_FWSTATS_ADD(isr, irqs); - DEBUGFS_FWSTATS_ADD(isr, tx_procs); - DEBUGFS_FWSTATS_ADD(isr, decrypt_done); - DEBUGFS_FWSTATS_ADD(isr, dma0_done); - DEBUGFS_FWSTATS_ADD(isr, dma1_done); - DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); - DEBUGFS_FWSTATS_ADD(isr, commands); - DEBUGFS_FWSTATS_ADD(isr, rx_procs); - DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); - DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); - DEBUGFS_FWSTATS_ADD(isr, pci_pm); - DEBUGFS_FWSTATS_ADD(isr, wakeups); - DEBUGFS_FWSTATS_ADD(isr, low_rssi); - - DEBUGFS_FWSTATS_ADD(wep, addr_key_count); - DEBUGFS_FWSTATS_ADD(wep, default_key_count); - /* skipping wep.reserved */ - DEBUGFS_FWSTATS_ADD(wep, key_not_found); - DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); - DEBUGFS_FWSTATS_ADD(wep, packets); - DEBUGFS_FWSTATS_ADD(wep, interrupt); - - DEBUGFS_FWSTATS_ADD(pwr, ps_enter); - DEBUGFS_FWSTATS_ADD(pwr, elp_enter); - DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); - DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); - DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); - DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); - DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); - DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); - DEBUGFS_FWSTATS_ADD(pwr, power_save_off); - DEBUGFS_FWSTATS_ADD(pwr, enable_ps); - DEBUGFS_FWSTATS_ADD(pwr, disable_ps); - DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); - /* skipping cont_miss_bcns_spread for now */ - DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); - - DEBUGFS_FWSTATS_ADD(mic, rx_pkts); - DEBUGFS_FWSTATS_ADD(mic, calc_failure); - - DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); - DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); - DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); - DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); - DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); - DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); - - DEBUGFS_FWSTATS_ADD(event, heart_beat); - DEBUGFS_FWSTATS_ADD(event, calibration); - DEBUGFS_FWSTATS_ADD(event, rx_mismatch); - DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); - DEBUGFS_FWSTATS_ADD(event, rx_pool); - DEBUGFS_FWSTATS_ADD(event, oom_late); - DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); - DEBUGFS_FWSTATS_ADD(event, tx_stuck); - - DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); - DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); - DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); - DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); - DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); - DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); - DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); - - DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); - DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); - - DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); - DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); - DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); - -out: - if (ret < 0) - wl12xx_debugfs_delete_files(wl); - - return ret; -} - -void wl12xx_debugfs_reset(struct wl12xx *wl) -{ - memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); - wl->stats.retry_count = 0; - wl->stats.excessive_retries = 0; -} - -int wl12xx_debugfs_init(struct wl12xx *wl) -{ - int ret; - - wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); - - if (IS_ERR(wl->debugfs.rootdir)) { - ret = PTR_ERR(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - goto err; - } - - wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", - wl->debugfs.rootdir); - - if (IS_ERR(wl->debugfs.fw_statistics)) { - ret = PTR_ERR(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - goto err_root; - } - - wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), - GFP_KERNEL); - - if (!wl->stats.fw_stats) { - ret = -ENOMEM; - goto err_fw; - } - - wl->stats.fw_stats_update = jiffies; - - ret = wl12xx_debugfs_add_files(wl); - - if (ret < 0) - goto err_file; - - return 0; - -err_file: - kfree(wl->stats.fw_stats); - wl->stats.fw_stats = NULL; - -err_fw: - debugfs_remove(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - -err_root: - debugfs_remove(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - -err: - return ret; -} - -void wl12xx_debugfs_exit(struct wl12xx *wl) -{ - wl12xx_debugfs_delete_files(wl); - - kfree(wl->stats.fw_stats); - wl->stats.fw_stats = NULL; - - debugfs_remove(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - - debugfs_remove(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - -} diff --git a/drivers/net/wireless/wl12xx/debugfs.h b/drivers/net/wireless/wl12xx/debugfs.h deleted file mode 100644 index 562cdcb..0000000 --- a/drivers/net/wireless/wl12xx/debugfs.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef WL12XX_DEBUGFS_H -#define WL12XX_DEBUGFS_H - -#include "wl12xx.h" - -int wl12xx_debugfs_init(struct wl12xx *wl); -void wl12xx_debugfs_exit(struct wl12xx *wl); -void wl12xx_debugfs_reset(struct wl12xx *wl); - -#endif /* WL12XX_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c deleted file mode 100644 index 99529ca..0000000 --- a/drivers/net/wireless/wl12xx/event.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl12xx.h" -#include "reg.h" -#include "spi.h" -#include "event.h" -#include "ps.h" - -static int wl12xx_event_scan_complete(struct wl12xx *wl, - struct event_mailbox *mbox) -{ - wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", - mbox->scheduled_scan_status, - mbox->scheduled_scan_channels); - - if (wl->scanning) { - mutex_unlock(&wl->mutex); - ieee80211_scan_completed(wl->hw, false); - mutex_lock(&wl->mutex); - wl->scanning = false; - } - - return 0; -} - -static void wl12xx_event_mbox_dump(struct event_mailbox *mbox) -{ - wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:"); - wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); - wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); -} - -static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox) -{ - int ret; - u32 vector; - - wl12xx_event_mbox_dump(mbox); - - vector = mbox->events_vector & ~(mbox->events_mask); - wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector); - - if (vector & SCAN_COMPLETE_EVENT_ID) { - ret = wl12xx_event_scan_complete(wl, mbox); - if (ret < 0) - return ret; - } - - if (vector & BSS_LOSE_EVENT_ID) { - wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); - - if (wl->psm_requested && wl->psm) { - ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - return ret; - } - } - - return 0; -} - -int wl12xx_event_unmask(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask)); - if (ret < 0) - return ret; - - return 0; -} - -void wl12xx_event_mbox_config(struct wl12xx *wl) -{ - wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); - wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); - - wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", - wl->mbox_ptr[0], wl->mbox_ptr[1]); -} - -int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num) -{ - struct event_mailbox mbox; - int ret; - - wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); - - if (mbox_num > 1) - return -EINVAL; - - /* first we read the mbox descriptor */ - wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, - sizeof(struct event_mailbox)); - - /* process the descriptor */ - ret = wl12xx_event_process(wl, &mbox); - if (ret < 0) - return ret; - - /* then we let the firmware know it can go on...*/ - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); - - return 0; -} diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h deleted file mode 100644 index 1f4c2f7..0000000 --- a/drivers/net/wireless/wl12xx/event.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_EVENT_H__ -#define __WL12XX_EVENT_H__ - -/* - * Mbox events - * - * The event mechanism is based on a pair of event buffers (buffers A and - * B) at fixed locations in the target's memory. The host processes one - * buffer while the other buffer continues to collect events. If the host - * is not processing events, an interrupt is issued to signal that a buffer - * is ready. Once the host is done with processing events from one buffer, - * it signals the target (with an ACK interrupt) that the event buffer is - * free. - */ - -enum { - RESERVED1_EVENT_ID = BIT(0), - RESERVED2_EVENT_ID = BIT(1), - MEASUREMENT_START_EVENT_ID = BIT(2), - SCAN_COMPLETE_EVENT_ID = BIT(3), - CALIBRATION_COMPLETE_EVENT_ID = BIT(4), - ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), - PS_REPORT_EVENT_ID = BIT(6), - SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), - HEALTH_REPORT_EVENT_ID = BIT(8), - ACI_DETECTION_EVENT_ID = BIT(9), - DEBUG_REPORT_EVENT_ID = BIT(10), - MAC_STATUS_EVENT_ID = BIT(11), - DISCONNECT_EVENT_COMPLETE_ID = BIT(12), - JOIN_EVENT_COMPLETE_ID = BIT(13), - CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), - BSS_LOSE_EVENT_ID = BIT(15), - ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), - MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), - AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), - SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), - PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), - RESET_BSS_EVENT_ID = BIT(21), - REGAINED_BSS_EVENT_ID = BIT(22), - ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), - ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), - ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), - - DBG_EVENT_ID = BIT(26), - BT_PTA_SENSE_EVENT_ID = BIT(27), - BT_PTA_PREDICTION_EVENT_ID = BIT(28), - BT_PTA_AVALANCHE_EVENT_ID = BIT(29), - - PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), - - EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, -}; - -struct event_debug_report { - u8 debug_event_id; - u8 num_params; - u16 pad; - u32 report_1; - u32 report_2; - u32 report_3; -} __attribute__ ((packed)); - -struct event_mailbox { - u32 events_vector; - u32 events_mask; - u32 reserved_1; - u32 reserved_2; - - char average_rssi_level; - u8 ps_status; - u8 channel_switch_status; - u8 scheduled_scan_status; - - /* Channels scanned by the scheduled scan */ - u16 scheduled_scan_channels; - - /* If bit 0 is set -> target's fatal error */ - u16 health_report; - u16 bad_fft_counter; - u8 bt_pta_sense_info; - u8 bt_pta_protective_info; - u32 reserved; - u32 debug_report[2]; - - /* Number of FCS errors since last event */ - u32 fcs_err_counter; - - struct event_debug_report report; - u8 average_snr_level; - u8 padding[19]; -} __attribute__ ((packed)); - -int wl12xx_event_unmask(struct wl12xx *wl); -void wl12xx_event_mbox_config(struct wl12xx *wl); -int wl12xx_event_handle(struct wl12xx *wl, u8 mbox); - -#endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c deleted file mode 100644 index 2a573a6..0000000 --- a/drivers/net/wireless/wl12xx/init.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "init.h" -#include "wl12xx_80211.h" -#include "acx.h" -#include "cmd.h" - -int wl12xx_hw_init_hwenc_config(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_feature_cfg(wl); - if (ret < 0) { - wl12xx_warning("couldn't set feature config"); - return ret; - } - - ret = wl12xx_acx_default_key(wl, wl->default_key); - if (ret < 0) { - wl12xx_warning("couldn't set default key"); - return ret; - } - - return 0; -} - -int wl12xx_hw_init_templates_config(struct wl12xx *wl) -{ - int ret; - u8 partial_vbm[PARTIAL_VBM_MAX]; - - /* send empty templates for fw memory reservation */ - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL, - sizeof(struct wl12xx_probe_req_template)); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL, - sizeof(struct wl12xx_null_data_template)); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL, - sizeof(struct wl12xx_ps_poll_template)); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, - sizeof - (struct wl12xx_qos_null_data_template)); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL, - sizeof - (struct wl12xx_probe_resp_template)); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL, - sizeof - (struct wl12xx_beacon_template)); - if (ret < 0) - return ret; - - /* tim templates, first reserve space then allocate an empty one */ - memset(partial_vbm, 0, PARTIAL_VBM_MAX); - ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter) -{ - int ret; - - ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); - if (ret < 0) - return ret; - - ret = wl12xx_acx_rx_config(wl, config, filter); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_phy_config(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_pd_threshold(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME); - if (ret < 0) - return ret; - - ret = wl12xx_acx_group_address_tbl(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_service_period_timeout(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_beacon_filter(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_beacon_filter_opt(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_beacon_filter_table(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_pta(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_sg_enable(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_sg_cfg(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_energy_detection(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_cca_threshold(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_bcn_dtim_options(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_power_auth(struct wl12xx *wl) -{ - return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); -} diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h deleted file mode 100644 index c8b6cd0..0000000 --- a/drivers/net/wireless/wl12xx/init.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_INIT_H__ -#define __WL12XX_INIT_H__ - -#include "wl12xx.h" - -int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); -int wl12xx_hw_init_templates_config(struct wl12xx *wl); -int wl12xx_hw_init_mem_config(struct wl12xx *wl); -int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter); -int wl12xx_hw_init_phy_config(struct wl12xx *wl); -int wl12xx_hw_init_beacon_filter(struct wl12xx *wl); -int wl12xx_hw_init_pta(struct wl12xx *wl); -int wl12xx_hw_init_energy_detection(struct wl12xx *wl); -int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl); -int wl12xx_hw_init_power_auth(struct wl12xx *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c deleted file mode 100644 index dd75d3d..0000000 --- a/drivers/net/wireless/wl12xx/main.c +++ /dev/null @@ -1,1442 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wl12xx.h" -#include "wl12xx_80211.h" -#include "reg.h" -#include "wl1251_ops.h" -#include "spi.h" -#include "event.h" -#include "wl1251_tx.h" -#include "rx.h" -#include "ps.h" -#include "init.h" -#include "debugfs.h" - -static void wl12xx_disable_interrupts(struct wl12xx *wl) -{ - disable_irq(wl->irq); -} - -static void wl12xx_power_off(struct wl12xx *wl) -{ - wl->set_power(false); -} - -static void wl12xx_power_on(struct wl12xx *wl) -{ - wl->set_power(true); -} - -static irqreturn_t wl12xx_irq(int irq, void *cookie) -{ - struct wl12xx *wl; - - wl12xx_debug(DEBUG_IRQ, "IRQ"); - - wl = cookie; - - schedule_work(&wl->irq_work); - - return IRQ_HANDLED; -} - -static int wl12xx_fetch_firmware(struct wl12xx *wl) -{ - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); - - if (ret < 0) { - wl12xx_error("could not get firmware: %d", ret); - return ret; - } - - if (fw->size % 4) { - wl12xx_error("firmware size is not multiple of 32 bits: %zu", - fw->size); - ret = -EILSEQ; - goto out; - } - - wl->fw_len = fw->size; - wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); - - if (!wl->fw) { - wl12xx_error("could not allocate memory for the firmware"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->fw, fw->data, wl->fw_len); - - ret = 0; - -out: - release_firmware(fw); - - return ret; -} - -static int wl12xx_fetch_nvs(struct wl12xx *wl) -{ - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); - - if (ret < 0) { - wl12xx_error("could not get nvs file: %d", ret); - return ret; - } - - if (fw->size % 4) { - wl12xx_error("nvs size is not multiple of 32 bits: %zu", - fw->size); - ret = -EILSEQ; - goto out; - } - - wl->nvs_len = fw->size; - wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); - - if (!wl->nvs) { - wl12xx_error("could not allocate memory for the nvs file"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->nvs, fw->data, wl->nvs_len); - - ret = 0; - -out: - release_firmware(fw); - - return ret; -} - -static void wl12xx_fw_wakeup(struct wl12xx *wl) -{ - u32 elp_reg; - - elp_reg = ELPCTRL_WAKE_UP; - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - - if (!(elp_reg & ELPCTRL_WLAN_READY)) { - wl12xx_warning("WLAN not ready"); - } -} - -static int wl12xx_chip_wakeup(struct wl12xx *wl) -{ - int ret = 0; - - wl12xx_power_on(wl); - msleep(wl->chip.power_on_sleep); - wl12xx_spi_reset(wl); - wl12xx_spi_init(wl); - - /* We don't need a real memory partition here, because we only want - * to use the registers at this point. */ - wl12xx_set_partition(wl, - 0x00000000, - 0x00000000, - REGISTERS_BASE, - REGISTERS_DOWN_SIZE); - - /* ELP module wake up */ - wl12xx_fw_wakeup(wl); - - /* whal_FwCtrl_BootSm() */ - - /* 0. read chip id from CHIP_ID */ - wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B); - - /* 1. check if chip id is valid */ - - switch (wl->chip.id) { - case CHIP_ID_1251_PG12: - wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", - wl->chip.id); - - wl1251_setup(wl); - - break; - case CHIP_ID_1251_PG10: - case CHIP_ID_1251_PG11: - default: - wl12xx_error("unsupported chip id: 0x%x", wl->chip.id); - ret = -ENODEV; - goto out; - } - - if (wl->fw == NULL) { - ret = wl12xx_fetch_firmware(wl); - if (ret < 0) - goto out; - } - - /* No NVS from netlink, try to get it from the filesystem */ - if (wl->nvs == NULL) { - ret = wl12xx_fetch_nvs(wl); - if (ret < 0) - goto out; - } - -out: - return ret; -} - -static void wl12xx_filter_work(struct work_struct *work) -{ - struct wl12xx *wl = - container_of(work, struct wl12xx, filter_work); - int ret; - - mutex_lock(&wl->mutex); - - if (wl->state == WL12XX_STATE_OFF) - goto out; - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - /* FIXME: replace the magic numbers with proper definitions */ - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -int wl12xx_plt_start(struct wl12xx *wl) -{ - int ret; - - wl12xx_notice("power up"); - - if (wl->state != WL12XX_STATE_OFF) { - wl12xx_error("cannot go into PLT state because not " - "in off state: %d", wl->state); - return -EBUSY; - } - - wl->state = WL12XX_STATE_PLT; - - ret = wl12xx_chip_wakeup(wl); - if (ret < 0) - return ret; - - ret = wl->chip.op_boot(wl); - if (ret < 0) - return ret; - - wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); - - ret = wl->chip.op_plt_init(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_plt_stop(struct wl12xx *wl) -{ - wl12xx_notice("power down"); - - if (wl->state != WL12XX_STATE_PLT) { - wl12xx_error("cannot power down because not in PLT " - "state: %d", wl->state); - return -EBUSY; - } - - wl12xx_disable_interrupts(wl); - wl12xx_power_off(wl); - - wl->state = WL12XX_STATE_OFF; - - return 0; -} - - -static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct wl12xx *wl = hw->priv; - - skb_queue_tail(&wl->tx_queue, skb); - - /* - * The chip specific setup must run before the first TX packet - - * before that, the tx_work will not be initialized! - */ - - schedule_work(&wl->tx_work); - - /* - * The workqueue is slow to process the tx_queue and we need stop - * the queue here, otherwise the queue will get too long. - */ - if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) { - ieee80211_stop_queues(wl->hw); - - /* - * FIXME: this is racy, the variable is not properly - * protected. Maybe fix this by removing the stupid - * variable altogether and checking the real queue state? - */ - wl->tx_queue_stopped = true; - } - - return NETDEV_TX_OK; -} - -static int wl12xx_op_start(struct ieee80211_hw *hw) -{ - struct wl12xx *wl = hw->priv; - int ret = 0; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 start"); - - mutex_lock(&wl->mutex); - - if (wl->state != WL12XX_STATE_OFF) { - wl12xx_error("cannot start because not in off state: %d", - wl->state); - ret = -EBUSY; - goto out; - } - - ret = wl12xx_chip_wakeup(wl); - if (ret < 0) - return ret; - - ret = wl->chip.op_boot(wl); - if (ret < 0) - goto out; - - ret = wl->chip.op_hw_init(wl); - if (ret < 0) - goto out; - - ret = wl12xx_acx_station_id(wl); - if (ret < 0) - goto out; - - wl->state = WL12XX_STATE_ON; - - wl12xx_info("firmware booted (%s)", wl->chip.fw_ver); - -out: - if (ret < 0) - wl12xx_power_off(wl); - - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wl12xx_op_stop(struct ieee80211_hw *hw) -{ - struct wl12xx *wl = hw->priv; - - wl12xx_info("down"); - - wl12xx_debug(DEBUG_MAC80211, "mac80211 stop"); - - mutex_lock(&wl->mutex); - - WARN_ON(wl->state != WL12XX_STATE_ON); - - if (wl->scanning) { - mutex_unlock(&wl->mutex); - ieee80211_scan_completed(wl->hw, true); - mutex_lock(&wl->mutex); - wl->scanning = false; - } - - wl->state = WL12XX_STATE_OFF; - - wl12xx_disable_interrupts(wl); - - mutex_unlock(&wl->mutex); - - cancel_work_sync(&wl->irq_work); - cancel_work_sync(&wl->tx_work); - cancel_work_sync(&wl->filter_work); - - mutex_lock(&wl->mutex); - - /* let's notify MAC80211 about the remaining pending TX frames */ - wl->chip.op_tx_flush(wl); - wl12xx_power_off(wl); - - memset(wl->bssid, 0, ETH_ALEN); - wl->listen_int = 1; - wl->bss_type = MAX_BSS_TYPE; - - wl->data_in_count = 0; - wl->rx_counter = 0; - wl->rx_handled = 0; - wl->rx_current_buffer = 0; - wl->rx_last_id = 0; - wl->next_tx_complete = 0; - wl->elp = false; - wl->psm = 0; - wl->tx_queue_stopped = false; - wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; - - wl12xx_debugfs_reset(wl); - - mutex_unlock(&wl->mutex); -} - -static int wl12xx_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct wl12xx *wl = hw->priv; - DECLARE_MAC_BUF(mac); - int ret = 0; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", - conf->type, print_mac(mac, conf->mac_addr)); - - mutex_lock(&wl->mutex); - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - wl->bss_type = BSS_TYPE_STA_BSS; - break; - case NL80211_IFTYPE_ADHOC: - wl->bss_type = BSS_TYPE_IBSS; - break; - default: - ret = -EOPNOTSUPP; - goto out; - } - - if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { - memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); - SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); - ret = wl12xx_acx_station_id(wl); - if (ret < 0) - goto out; - } - -out: - mutex_unlock(&wl->mutex); - return ret; -} - -static void wl12xx_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface"); -} - -static int wl12xx_build_null_data(struct wl12xx *wl) -{ - struct wl12xx_null_data_template template; - - if (!is_zero_ether_addr(wl->bssid)) { - memcpy(template.header.da, wl->bssid, ETH_ALEN); - memcpy(template.header.bssid, wl->bssid, ETH_ALEN); - } else { - memset(template.header.da, 0xff, ETH_ALEN); - memset(template.header.bssid, 0xff, ETH_ALEN); - } - - memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); - template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_NULLFUNC); - - return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template, - sizeof(template)); - -} - -static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) -{ - struct wl12xx_ps_poll_template template; - - memcpy(template.bssid, wl->bssid, ETH_ALEN); - memcpy(template.ta, wl->mac_addr, ETH_ALEN); - template.aid = aid; - template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); - - return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template, - sizeof(template)); - -} - -static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) -{ - struct wl12xx *wl = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - int channel, ret = 0; - - channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - - wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", - channel, - conf->flags & IEEE80211_CONF_PS ? "on" : "off", - conf->power_level); - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (channel != wl->channel) { - /* FIXME: use beacon interval provided by mac80211 */ - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); - if (ret < 0) - goto out_sleep; - - wl->channel = channel; - } - - ret = wl12xx_build_null_data(wl); - if (ret < 0) - goto out_sleep; - - if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl12xx_info("psm enabled"); - - wl->psm_requested = true; - - /* - * We enter PSM only if we're already associated. - * If we're not, we'll enter it when joining an SSID, - * through the bss_info_changed() hook. - */ - ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE); - } else if (!(conf->flags & IEEE80211_CONF_PS) && - wl->psm_requested) { - wl12xx_info("psm disabled"); - - wl->psm_requested = false; - - if (wl->psm) - ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); - } - - if (conf->power_level != wl->power_level) { - ret = wl12xx_acx_tx_power(wl, conf->power_level); - if (ret < 0) - goto out; - - wl->power_level = conf->power_level; - } - -out_sleep: - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ - FIF_FCSFAIL | \ - FIF_BCN_PRBRESP_PROMISC | \ - FIF_CONTROL | \ - FIF_OTHER_BSS) - -static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed, - unsigned int *total, - int mc_count, - struct dev_addr_list *mc_list) -{ - struct wl12xx *wl = hw->priv; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter"); - - *total &= WL12XX_SUPPORTED_FILTERS; - changed &= WL12XX_SUPPORTED_FILTERS; - - if (changed == 0) - /* no filters which we support changed */ - return; - - /* FIXME: wl->rx_config and wl->rx_filter are not protected */ - - wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; - wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; - - if (*total & FIF_PROMISC_IN_BSS) { - wl->rx_config |= CFG_BSSID_FILTER_EN; - wl->rx_config |= CFG_RX_ALL_GOOD; - } - if (*total & FIF_ALLMULTI) - /* - * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive - * all multicast frames - */ - wl->rx_config &= ~CFG_MC_FILTER_EN; - if (*total & FIF_FCSFAIL) - wl->rx_filter |= CFG_RX_FCS_ERROR; - if (*total & FIF_BCN_PRBRESP_PROMISC) { - wl->rx_config &= ~CFG_BSSID_FILTER_EN; - wl->rx_config &= ~CFG_SSID_FILTER_EN; - } - if (*total & FIF_CONTROL) - wl->rx_filter |= CFG_RX_CTL_EN; - if (*total & FIF_OTHER_BSS) - wl->rx_filter &= ~CFG_BSSID_FILTER_EN; - - /* - * FIXME: workqueues need to be properly cancelled on stop(), for - * now let's just disable changing the filter settings. They will - * be updated any on config(). - */ - /* schedule_work(&wl->filter_work); */ -} - -/* HW encryption */ -static int wl12xx_set_key_type(struct wl12xx *wl, - struct wl12xx_cmd_set_keys *key, - enum set_key_cmd cmd, - struct ieee80211_key_conf *mac80211_key, - const u8 *addr) -{ - switch (mac80211_key->alg) { - case ALG_WEP: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_WEP_DEFAULT; - else - key->key_type = KEY_WEP_ADDR; - - mac80211_key->hw_key_idx = mac80211_key->keyidx; - break; - case ALG_TKIP: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_TKIP_MIC_GROUP; - else - key->key_type = KEY_TKIP_MIC_PAIRWISE; - - mac80211_key->hw_key_idx = mac80211_key->keyidx; - break; - case ALG_CCMP: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_AES_GROUP; - else - key->key_type = KEY_AES_PAIRWISE; - mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - break; - default: - wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg); - return -EOPNOTSUPP; - } - - return 0; -} - -static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct wl12xx *wl = hw->priv; - struct wl12xx_cmd_set_keys *wl_cmd; - const u8 *addr; - int ret; - - static const u8 bcast_addr[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); - - wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); - if (!wl_cmd) { - ret = -ENOMEM; - goto out; - } - - addr = sta ? sta->addr : bcast_addr; - - wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); - wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); - wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", - key->alg, key->keyidx, key->keylen, key->flags); - wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); - - if (is_zero_ether_addr(addr)) { - /* We dont support TX only encryption */ - ret = -EOPNOTSUPP; - goto out; - } - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out_unlock; - - switch (cmd) { - case SET_KEY: - wl_cmd->key_action = KEY_ADD_OR_REPLACE; - break; - case DISABLE_KEY: - wl_cmd->key_action = KEY_REMOVE; - break; - default: - wl12xx_error("Unsupported key cmd 0x%x", cmd); - break; - } - - ret = wl12xx_set_key_type(wl, wl_cmd, cmd, key, addr); - if (ret < 0) { - wl12xx_error("Set KEY type failed"); - goto out_sleep; - } - - if (wl_cmd->key_type != KEY_WEP_DEFAULT) - memcpy(wl_cmd->addr, addr, ETH_ALEN); - - if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || - (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { - /* - * We get the key in the following form: - * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) - * but the target is expecting: - * TKIP - RX MIC - TX MIC - */ - memcpy(wl_cmd->key, key->key, 16); - memcpy(wl_cmd->key + 16, key->key + 24, 8); - memcpy(wl_cmd->key + 24, key->key + 16, 8); - - } else { - memcpy(wl_cmd->key, key->key, key->keylen); - } - wl_cmd->key_size = key->keylen; - - wl_cmd->id = key->keyidx; - wl_cmd->ssid_profile = 0; - - wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); - - ret = wl12xx_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); - if (ret < 0) { - wl12xx_warning("could not set keys"); - goto out_sleep; - } - -out_sleep: - wl12xx_ps_elp_sleep(wl); - -out_unlock: - mutex_unlock(&wl->mutex); - -out: - kfree(wl_cmd); - - return ret; -} - -static int wl12xx_build_basic_rates(char *rates) -{ - u8 index = 0; - - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; - - return index; -} - -static int wl12xx_build_extended_rates(char *rates) -{ - u8 index = 0; - - rates[index++] = IEEE80211_OFDM_RATE_6MB; - rates[index++] = IEEE80211_OFDM_RATE_9MB; - rates[index++] = IEEE80211_OFDM_RATE_12MB; - rates[index++] = IEEE80211_OFDM_RATE_18MB; - rates[index++] = IEEE80211_OFDM_RATE_24MB; - rates[index++] = IEEE80211_OFDM_RATE_36MB; - rates[index++] = IEEE80211_OFDM_RATE_48MB; - rates[index++] = IEEE80211_OFDM_RATE_54MB; - - return index; -} - - -static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) -{ - struct wl12xx_probe_req_template template; - struct wl12xx_ie_rates *rates; - char *ptr; - u16 size; - - ptr = (char *)&template; - size = sizeof(struct ieee80211_header); - - memset(template.header.da, 0xff, ETH_ALEN); - memset(template.header.bssid, 0xff, ETH_ALEN); - memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); - template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - - /* IEs */ - /* SSID */ - template.ssid.header.id = WLAN_EID_SSID; - template.ssid.header.len = ssid_len; - if (ssid_len && ssid) - memcpy(template.ssid.ssid, ssid, ssid_len); - size += sizeof(struct wl12xx_ie_header) + ssid_len; - ptr += size; - - /* Basic Rates */ - rates = (struct wl12xx_ie_rates *)ptr; - rates->header.id = WLAN_EID_SUPP_RATES; - rates->header.len = wl12xx_build_basic_rates(rates->rates); - size += sizeof(struct wl12xx_ie_header) + rates->header.len; - ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; - - /* Extended rates */ - rates = (struct wl12xx_ie_rates *)ptr; - rates->header.id = WLAN_EID_EXT_SUPP_RATES; - rates->header.len = wl12xx_build_extended_rates(rates->rates); - size += sizeof(struct wl12xx_ie_header) + rates->header.len; - - wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); - - return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template, - size); -} - -static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, - u8 active_scan, u8 high_prio, u8 num_channels, - u8 probe_requests) -{ - struct wl12xx_cmd_trigger_scan_to *trigger = NULL; - struct cmd_scan *params = NULL; - int i, ret; - u16 scan_options = 0; - - if (wl->scanning) - return -EINVAL; - - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) - return -ENOMEM; - - params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); - params->params.rx_filter_options = - cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); - - /* High priority scan */ - if (!active_scan) - scan_options |= SCAN_PASSIVE; - if (high_prio) - scan_options |= SCAN_PRIORITY_HIGH; - params->params.scan_options = scan_options; - - params->params.num_channels = num_channels; - params->params.num_probe_requests = probe_requests; - params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ - params->params.tid_trigger = 0; - - for (i = 0; i < num_channels; i++) { - params->channels[i].min_duration = cpu_to_le32(30000); - params->channels[i].max_duration = cpu_to_le32(60000); - memset(¶ms->channels[i].bssid_lsb, 0xff, 4); - memset(¶ms->channels[i].bssid_msb, 0xff, 2); - params->channels[i].early_termination = 0; - params->channels[i].tx_power_att = 0; - params->channels[i].channel = i + 1; - memset(params->channels[i].pad, 0, 3); - } - - for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) - memset(¶ms->channels[i], 0, - sizeof(struct basic_scan_channel_parameters)); - - if (len && ssid) { - params->params.ssid_len = len; - memcpy(params->params.ssid, ssid, len); - } else { - params->params.ssid_len = 0; - memset(params->params.ssid, 0, 32); - } - - ret = wl12xx_build_probe_req(wl, ssid, len); - if (ret < 0) { - wl12xx_error("PROBE request template failed"); - goto out; - } - - trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); - if (!trigger) - goto out; - - trigger->timeout = 0; - - ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, - sizeof(*trigger)); - if (ret < 0) { - wl12xx_error("trigger scan to failed for hw scan"); - goto out; - } - - wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); - - wl->scanning = true; - - ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); - if (ret < 0) - wl12xx_error("SCAN failed"); - - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); - - if (params->header.status != CMD_STATUS_SUCCESS) { - wl12xx_error("TEST command answer error: %d", - params->header.status); - wl->scanning = false; - ret = -EIO; - goto out; - } - -out: - kfree(params); - return ret; - -} - -static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, - struct cfg80211_scan_request *req) -{ - struct wl12xx *wl = hw->priv; - int ret; - u8 *ssid = NULL; - size_t ssid_len = 0; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan"); - - if (req->n_ssids) { - ssid = req->ssids[0].ssid; - ssid_len = req->ssids[0].ssid_len; - } - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); - - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct wl12xx *wl = hw->priv; - int ret; - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl12xx_acx_rts_threshold(wl, (u16) value); - if (ret < 0) - wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); - - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - enum wl12xx_cmd_ps_mode mode; - struct wl12xx *wl = hw->priv; - struct sk_buff *beacon; - int ret; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed"); - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (changed & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { - wl->aid = bss_conf->aid; - - ret = wl12xx_build_ps_poll(wl, wl->aid); - if (ret < 0) - goto out_sleep; - - ret = wl12xx_acx_aid(wl, wl->aid); - if (ret < 0) - goto out_sleep; - - /* If we want to go in PSM but we're not there yet */ - if (wl->psm_requested && !wl->psm) { - mode = STATION_POWER_SAVE_MODE; - ret = wl12xx_ps_set_mode(wl, mode); - if (ret < 0) - goto out_sleep; - } - } - } - if (changed & BSS_CHANGED_ERP_SLOT) { - if (bss_conf->use_short_slot) - ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT); - else - ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); - if (ret < 0) { - wl12xx_warning("Set slot time failed %d", ret); - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - if (bss_conf->use_short_preamble) - wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); - else - wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG); - } - - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - if (bss_conf->use_cts_prot) - ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE); - else - ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); - if (ret < 0) { - wl12xx_warning("Set ctsprotect failed %d", ret); - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_BSSID) { - memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - - ret = wl12xx_build_null_data(wl); - if (ret < 0) - goto out; - - if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 5, 100, 1); - if (ret < 0) - goto out; - } - } - - if (changed & BSS_CHANGED_BEACON) { - beacon = ieee80211_beacon_get(hw, vif); - ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data, - beacon->len); - - if (ret < 0) { - dev_kfree_skb(beacon); - goto out; - } - - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, - beacon->len); - - dev_kfree_skb(beacon); - - if (ret < 0) - goto out; - - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); - - if (ret < 0) - goto out; - } - -out_sleep: - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_rate wl12xx_rates[] = { - { .bitrate = 10, - .hw_value = 0x1, - .hw_value_short = 0x1, }, - { .bitrate = 20, - .hw_value = 0x2, - .hw_value_short = 0x2, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 55, - .hw_value = 0x4, - .hw_value_short = 0x4, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 110, - .hw_value = 0x20, - .hw_value_short = 0x20, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 60, - .hw_value = 0x8, - .hw_value_short = 0x8, }, - { .bitrate = 90, - .hw_value = 0x10, - .hw_value_short = 0x10, }, - { .bitrate = 120, - .hw_value = 0x40, - .hw_value_short = 0x40, }, - { .bitrate = 180, - .hw_value = 0x80, - .hw_value_short = 0x80, }, - { .bitrate = 240, - .hw_value = 0x200, - .hw_value_short = 0x200, }, - { .bitrate = 360, - .hw_value = 0x400, - .hw_value_short = 0x400, }, - { .bitrate = 480, - .hw_value = 0x800, - .hw_value_short = 0x800, }, - { .bitrate = 540, - .hw_value = 0x1000, - .hw_value_short = 0x1000, }, -}; - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_channel wl12xx_channels[] = { - { .hw_value = 1, .center_freq = 2412}, - { .hw_value = 2, .center_freq = 2417}, - { .hw_value = 3, .center_freq = 2422}, - { .hw_value = 4, .center_freq = 2427}, - { .hw_value = 5, .center_freq = 2432}, - { .hw_value = 6, .center_freq = 2437}, - { .hw_value = 7, .center_freq = 2442}, - { .hw_value = 8, .center_freq = 2447}, - { .hw_value = 9, .center_freq = 2452}, - { .hw_value = 10, .center_freq = 2457}, - { .hw_value = 11, .center_freq = 2462}, - { .hw_value = 12, .center_freq = 2467}, - { .hw_value = 13, .center_freq = 2472}, -}; - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_supported_band wl12xx_band_2ghz = { - .channels = wl12xx_channels, - .n_channels = ARRAY_SIZE(wl12xx_channels), - .bitrates = wl12xx_rates, - .n_bitrates = ARRAY_SIZE(wl12xx_rates), -}; - -static const struct ieee80211_ops wl12xx_ops = { - .start = wl12xx_op_start, - .stop = wl12xx_op_stop, - .add_interface = wl12xx_op_add_interface, - .remove_interface = wl12xx_op_remove_interface, - .config = wl12xx_op_config, - .configure_filter = wl12xx_op_configure_filter, - .tx = wl12xx_op_tx, - .set_key = wl12xx_op_set_key, - .hw_scan = wl12xx_op_hw_scan, - .bss_info_changed = wl12xx_op_bss_info_changed, - .set_rts_threshold = wl12xx_op_set_rts_threshold, -}; - -static int wl12xx_register_hw(struct wl12xx *wl) -{ - int ret; - - if (wl->mac80211_registered) - return 0; - - SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); - - ret = ieee80211_register_hw(wl->hw); - if (ret < 0) { - wl12xx_error("unable to register mac80211 hw: %d", ret); - return ret; - } - - wl->mac80211_registered = true; - - wl12xx_notice("loaded"); - - return 0; -} - -static int wl12xx_init_ieee80211(struct wl12xx *wl) -{ - /* The tx descriptor buffer and the TKIP space */ - wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) - + WL1251_TKIP_IV_SPACE; - - /* unit us */ - /* FIXME: find a proper value */ - wl->hw->channel_change_time = 10000; - - wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; - - wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - wl->hw->wiphy->max_scan_ssids = 1; - wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz; - - SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); - - return 0; -} - -#define WL12XX_DEFAULT_CHANNEL 1 -static int __devinit wl12xx_probe(struct spi_device *spi) -{ - struct wl12xx_platform_data *pdata; - struct ieee80211_hw *hw; - struct wl12xx *wl; - int ret, i; - static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; - - pdata = spi->dev.platform_data; - if (!pdata) { - wl12xx_error("no platform data"); - return -ENODEV; - } - - hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops); - if (!hw) { - wl12xx_error("could not alloc ieee80211_hw"); - return -ENOMEM; - } - - wl = hw->priv; - memset(wl, 0, sizeof(*wl)); - - wl->hw = hw; - dev_set_drvdata(&spi->dev, wl); - wl->spi = spi; - - wl->data_in_count = 0; - - skb_queue_head_init(&wl->tx_queue); - - INIT_WORK(&wl->filter_work, wl12xx_filter_work); - wl->channel = WL12XX_DEFAULT_CHANNEL; - wl->scanning = false; - wl->default_key = 0; - wl->listen_int = 1; - wl->rx_counter = 0; - wl->rx_handled = 0; - wl->rx_current_buffer = 0; - wl->rx_last_id = 0; - wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; - wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; - wl->elp = false; - wl->psm = 0; - wl->psm_requested = false; - wl->tx_queue_stopped = false; - wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; - - /* We use the default power on sleep time until we know which chip - * we're using */ - wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP; - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - wl->tx_frames[i] = NULL; - - wl->next_tx_complete = 0; - - /* - * In case our MAC address is not correctly set, - * we use a random but Nokia MAC. - */ - memcpy(wl->mac_addr, nokia_oui, 3); - get_random_bytes(wl->mac_addr + 3, 3); - - wl->state = WL12XX_STATE_OFF; - mutex_init(&wl->mutex); - - wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; - wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; - - wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); - if (!wl->rx_descriptor) { - wl12xx_error("could not allocate memory for rx descriptor"); - ret = -ENOMEM; - goto out_free; - } - - /* This is the only SPI value that we need to set here, the rest - * comes from the board-peripherals file */ - spi->bits_per_word = 32; - - ret = spi_setup(spi); - if (ret < 0) { - wl12xx_error("spi_setup failed"); - goto out_free; - } - - wl->set_power = pdata->set_power; - if (!wl->set_power) { - wl12xx_error("set power function missing in platform data"); - ret = -ENODEV; - goto out_free; - } - - wl->irq = spi->irq; - if (wl->irq < 0) { - wl12xx_error("irq missing in platform data"); - ret = -ENODEV; - goto out_free; - } - - ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); - if (ret < 0) { - wl12xx_error("request_irq() failed: %d", ret); - goto out_free; - } - - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - - disable_irq(wl->irq); - - ret = wl12xx_init_ieee80211(wl); - if (ret) - goto out_irq; - - ret = wl12xx_register_hw(wl); - if (ret) - goto out_irq; - - wl12xx_debugfs_init(wl); - - wl12xx_notice("initialized"); - - return 0; - - out_irq: - free_irq(wl->irq, wl); - - out_free: - kfree(wl->rx_descriptor); - wl->rx_descriptor = NULL; - - ieee80211_free_hw(hw); - - return ret; -} - -static int __devexit wl12xx_remove(struct spi_device *spi) -{ - struct wl12xx *wl = dev_get_drvdata(&spi->dev); - - ieee80211_unregister_hw(wl->hw); - - wl12xx_debugfs_exit(wl); - - free_irq(wl->irq, wl); - kfree(wl->target_mem_map); - kfree(wl->data_path); - kfree(wl->fw); - wl->fw = NULL; - kfree(wl->nvs); - wl->nvs = NULL; - - kfree(wl->rx_descriptor); - wl->rx_descriptor = NULL; - - ieee80211_free_hw(wl->hw); - - return 0; -} - - -static struct spi_driver wl12xx_spi_driver = { - .driver = { - .name = "wl12xx", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - - .probe = wl12xx_probe, - .remove = __devexit_p(wl12xx_remove), -}; - -static int __init wl12xx_init(void) -{ - int ret; - - ret = spi_register_driver(&wl12xx_spi_driver); - if (ret < 0) { - wl12xx_error("failed to register spi driver: %d", ret); - goto out; - } - -out: - return ret; -} - -static void __exit wl12xx_exit(void) -{ - spi_unregister_driver(&wl12xx_spi_driver); - - wl12xx_notice("unloaded"); -} - -module_init(wl12xx_init); -module_exit(wl12xx_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo , " - "Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c deleted file mode 100644 index f28f194..0000000 --- a/drivers/net/wireless/wl12xx/ps.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "reg.h" -#include "ps.h" -#include "spi.h" - -#define WL12XX_WAKEUP_TIMEOUT 2000 - -/* Routines to toggle sleep mode while in ELP */ -void wl12xx_ps_elp_sleep(struct wl12xx *wl) -{ - if (wl->elp || !wl->psm) - return; - - wl12xx_debug(DEBUG_PSM, "chip to elp"); - - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); - - wl->elp = true; -} - -int wl12xx_ps_elp_wakeup(struct wl12xx *wl) -{ - unsigned long timeout; - u32 elp_reg; - - if (!wl->elp) - return 0; - - wl12xx_debug(DEBUG_PSM, "waking up chip from elp"); - - timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT); - - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); - - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - - /* - * FIXME: we should wait for irq from chip but, as a temporary - * solution to simplify locking, let's poll instead - */ - while (!(elp_reg & ELPCTRL_WLAN_READY)) { - if (time_after(jiffies, timeout)) { - wl12xx_error("elp wakeup timeout"); - return -ETIMEDOUT; - } - msleep(1); - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - } - - wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms", - jiffies_to_msecs(jiffies) - - (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT)); - - wl->elp = false; - - return 0; -} - -static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) -{ - int ret; - - if (enable) { - wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp"); - - ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_ELP); - if (ret < 0) - return ret; - - wl12xx_ps_elp_sleep(wl); - } else { - wl12xx_debug(DEBUG_PSM, "sleep auth cam"); - - /* - * When the target is in ELP, we can only - * access the ELP control register. Thus, - * we have to wake the target up before - * changing the power authorization. - */ - - wl12xx_ps_elp_wakeup(wl); - - ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); - if (ret < 0) - return ret; - } - - return 0; -} - -int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode) -{ - int ret; - - switch (mode) { - case STATION_POWER_SAVE_MODE: - wl12xx_debug(DEBUG_PSM, "entering psm"); - ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); - if (ret < 0) - return ret; - - ret = wl12xx_ps_set_elp(wl, true); - if (ret < 0) - return ret; - - wl->psm = 1; - break; - case STATION_ACTIVE_MODE: - default: - wl12xx_debug(DEBUG_PSM, "leaving psm"); - ret = wl12xx_ps_set_elp(wl, false); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - return ret; - - wl->psm = 0; - break; - } - - return ret; -} - diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h deleted file mode 100644 index ad61b4a..0000000 --- a/drivers/net/wireless/wl12xx/ps.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __WL12XX_PS_H__ -#define __WL12XX_PS_H__ - -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl12xx.h" -#include "acx.h" - -int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode); -void wl12xx_ps_elp_sleep(struct wl12xx *wl); -int wl12xx_ps_elp_wakeup(struct wl12xx *wl); - - -#endif /* __WL12XX_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c deleted file mode 100644 index 7ac26ef..0000000 --- a/drivers/net/wireless/wl12xx/rx.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "wl12xx.h" -#include "reg.h" -#include "spi.h" -#include "rx.h" - -static void wl12xx_rx_header(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc) -{ - u32 rx_packet_ring_addr; - - rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; - if (wl->rx_current_buffer) - rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - - wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); -} - -static void wl12xx_rx_status(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc, - struct ieee80211_rx_status *status, - u8 beacon) -{ - u64 mactime; - int ret; - - memset(status, 0, sizeof(struct ieee80211_rx_status)); - - status->band = IEEE80211_BAND_2GHZ; - status->mactime = desc->timestamp; - - /* - * The rx status timestamp is a 32 bits value while the TSF is a - * 64 bits one. - * For IBSS merging, TSF is mandatory, so we have to get it - * somehow, so we ask for ACX_TSF_INFO. - * That could be moved to the get_tsf() hook, but unfortunately, - * this one must be atomic, while our SPI routines can sleep. - */ - if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { - ret = wl12xx_acx_tsf_info(wl, &mactime); - if (ret == 0) - status->mactime = mactime; - } - - status->signal = desc->rssi; - status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 / - (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI); - status->qual = min(status->qual, 100); - status->qual = max(status->qual, 0); - - /* - * FIXME: guessing that snr needs to be divided by two, otherwise - * the values don't make any sense - */ - status->noise = desc->rssi - desc->snr / 2; - - status->freq = ieee80211_channel_to_frequency(desc->channel); - - status->flag |= RX_FLAG_TSFT; - - if (desc->flags & RX_DESC_ENCRYPTION_MASK) { - status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; - - if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) - status->flag |= RX_FLAG_DECRYPTED; - - if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) - status->flag |= RX_FLAG_MMIC_ERROR; - } - - if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) - status->flag |= RX_FLAG_FAILED_FCS_CRC; - - - /* FIXME: set status->rate_idx */ -} - -static void wl12xx_rx_body(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc) -{ - struct sk_buff *skb; - struct ieee80211_rx_status status; - u8 *rx_buffer, beacon = 0; - u16 length, *fc; - u32 curr_id, last_id_inc, rx_packet_ring_addr; - - length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); - curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; - last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); - - if (last_id_inc != curr_id) { - wl12xx_warning("curr ID:%d, last ID inc:%d", - curr_id, last_id_inc); - wl->rx_last_id = curr_id; - } else { - wl->rx_last_id = last_id_inc; - } - - rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + - sizeof(struct wl12xx_rx_descriptor) + 20; - if (wl->rx_current_buffer) - rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - - skb = dev_alloc_skb(length); - if (!skb) { - wl12xx_error("Couldn't allocate RX frame"); - return; - } - - rx_buffer = skb_put(skb, length); - wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); - - /* The actual lenght doesn't include the target's alignment */ - skb->len = desc->length - PLCP_HEADER_LENGTH; - - fc = (u16 *)skb->data; - - if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) - beacon = 1; - - wl12xx_rx_status(wl, desc, &status, beacon); - - wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, - beacon ? "beacon" : ""); - - ieee80211_rx(wl->hw, skb, &status); -} - -static void wl12xx_rx_ack(struct wl12xx *wl) -{ - u32 data, addr; - - if (wl->rx_current_buffer) { - addr = ACX_REG_INTERRUPT_TRIG_H; - data = INTR_TRIG_RX_PROC1; - } else { - addr = ACX_REG_INTERRUPT_TRIG; - data = INTR_TRIG_RX_PROC0; - } - - wl12xx_reg_write32(wl, addr, data); - - /* Toggle buffer ring */ - wl->rx_current_buffer = !wl->rx_current_buffer; -} - - -void wl12xx_rx(struct wl12xx *wl) -{ - struct wl12xx_rx_descriptor *rx_desc; - - if (wl->state != WL12XX_STATE_ON) - return; - - rx_desc = wl->rx_descriptor; - - /* We first read the frame's header */ - wl12xx_rx_header(wl, rx_desc); - - /* Now we can read the body */ - wl12xx_rx_body(wl, rx_desc); - - /* Finally, we need to ACK the RX */ - wl12xx_rx_ack(wl); - - return; -} diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h deleted file mode 100644 index 8a23fde..0000000 --- a/drivers/net/wireless/wl12xx/rx.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_RX_H__ -#define __WL12XX_RX_H__ - -#include - -/* - * RX PATH - * - * The Rx path uses a double buffer and an rx_contro structure, each located - * at a fixed address in the device memory. The host keeps track of which - * buffer is available and alternates between them on a per packet basis. - * The size of each of the two buffers is large enough to hold the longest - * 802.3 packet. - * The RX path goes like that: - * 1) The target generates an interrupt each time a new packet is received. - * There are 2 RX interrupts, one for each buffer. - * 2) The host reads the received packet from one of the double buffers. - * 3) The host triggers a target interrupt. - * 4) The target prepares the next RX packet. - */ - -#define WL12XX_RX_MAX_RSSI -30 -#define WL12XX_RX_MIN_RSSI -95 - -#define WL12XX_RX_ALIGN_TO 4 -#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \ - ~(WL12XX_RX_ALIGN_TO - 1)) - -#define SHORT_PREAMBLE_BIT BIT(0) -#define OFDM_RATE_BIT BIT(6) -#define PBCC_RATE_BIT BIT(7) - -#define PLCP_HEADER_LENGTH 8 -#define RX_DESC_PACKETID_SHIFT 11 -#define RX_MAX_PACKET_ID 3 - -#define RX_DESC_VALID_FCS 0x0001 -#define RX_DESC_MATCH_RXADDR1 0x0002 -#define RX_DESC_MCAST 0x0004 -#define RX_DESC_STAINTIM 0x0008 -#define RX_DESC_VIRTUAL_BM 0x0010 -#define RX_DESC_BCAST 0x0020 -#define RX_DESC_MATCH_SSID 0x0040 -#define RX_DESC_MATCH_BSSID 0x0080 -#define RX_DESC_ENCRYPTION_MASK 0x0300 -#define RX_DESC_MEASURMENT 0x0400 -#define RX_DESC_SEQNUM_MASK 0x1800 -#define RX_DESC_MIC_FAIL 0x2000 -#define RX_DESC_DECRYPT_FAIL 0x4000 - -struct wl12xx_rx_descriptor { - u32 timestamp; /* In microseconds */ - u16 length; /* Paylod length, including headers */ - u16 flags; - - /* - * 0 - 802.11 - * 1 - 802.3 - * 2 - IP - * 3 - Raw Codec - */ - u8 type; - - /* - * Recevied Rate: - * 0x0A - 1MBPS - * 0x14 - 2MBPS - * 0x37 - 5_5MBPS - * 0x0B - 6MBPS - * 0x0F - 9MBPS - * 0x6E - 11MBPS - * 0x0A - 12MBPS - * 0x0E - 18MBPS - * 0xDC - 22MBPS - * 0x09 - 24MBPS - * 0x0D - 36MBPS - * 0x08 - 48MBPS - * 0x0C - 54MBPS - */ - u8 rate; - - u8 mod_pre; /* Modulation and preamble */ - u8 channel; - - /* - * 0 - 2.4 Ghz - * 1 - 5 Ghz - */ - u8 band; - - s8 rssi; /* in dB */ - u8 rcpi; /* in dB */ - u8 snr; /* in dB */ -} __attribute__ ((packed)); - -void wl12xx_rx(struct wl12xx *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c deleted file mode 100644 index 9c9943f..0000000 --- a/drivers/net/wireless/wl12xx/spi.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include - -#include "wl12xx.h" -#include "wl12xx_80211.h" -#include "reg.h" -#include "spi.h" -#include "ps.h" - -static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) -{ - /* If the address is lower than REGISTERS_BASE, it means that this is - * a chip-specific register address, so look it up in the registers - * table */ - if (addr < REGISTERS_BASE) { - /* Make sure we don't go over the table */ - if (addr >= ACX_REG_TABLE_LEN) { - wl12xx_error("address out of range (%d)", addr); - return -EINVAL; - } - addr = wl->chip.acx_reg_table[addr]; - } - - return addr - wl->physical_reg_addr + wl->virtual_reg_addr; -} - -static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr) -{ - return addr - wl->physical_mem_addr + wl->virtual_mem_addr; -} - - -void wl12xx_spi_reset(struct wl12xx *wl) -{ - u8 *cmd; - struct spi_transfer t; - struct spi_message m; - - cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); - if (!cmd) { - wl12xx_error("could not allocate cmd for spi reset"); - return; - } - - memset(&t, 0, sizeof(t)); - spi_message_init(&m); - - memset(cmd, 0xff, WSPI_INIT_CMD_LEN); - - t.tx_buf = cmd; - t.len = WSPI_INIT_CMD_LEN; - spi_message_add_tail(&t, &m); - - spi_sync(wl->spi, &m); - - wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); -} - -void wl12xx_spi_init(struct wl12xx *wl) -{ - u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; - struct spi_transfer t; - struct spi_message m; - - cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); - if (!cmd) { - wl12xx_error("could not allocate cmd for spi init"); - return; - } - - memset(crc, 0, sizeof(crc)); - memset(&t, 0, sizeof(t)); - spi_message_init(&m); - - /* - * Set WSPI_INIT_COMMAND - * the data is being send from the MSB to LSB - */ - cmd[2] = 0xff; - cmd[3] = 0xff; - cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; - cmd[0] = 0; - cmd[7] = 0; - cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; - cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; - - if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) - cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; - else - cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; - - cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS - | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; - - crc[0] = cmd[1]; - crc[1] = cmd[0]; - crc[2] = cmd[7]; - crc[3] = cmd[6]; - crc[4] = cmd[5]; - - cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; - cmd[4] |= WSPI_INIT_CMD_END; - - t.tx_buf = cmd; - t.len = WSPI_INIT_CMD_LEN; - spi_message_add_tail(&t, &m); - - spi_sync(wl->spi, &m); - - wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); -} - -/* Set the SPI partitions to access the chip addresses - * - * There are two VIRTUAL (SPI) partitions (the memory partition and the - * registers partition), which are mapped to two different areas of the - * PHYSICAL (hardware) memory. This function also makes other checks to - * ensure that the partitions are not overlapping. In the diagram below, the - * memory partition comes before the register partition, but the opposite is - * also supported. - * - * PHYSICAL address - * space - * - * | | - * ...+----+--> mem_start - * VIRTUAL address ... | | - * space ... | | [PART_0] - * ... | | - * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size - * | | ... | | - * |MEM | ... | | - * | | ... | | - * part_size <--+----+... | | {unused area) - * | | ... | | - * |REG | ... | | - * part_size | | ... | | - * + <--+----+... ...+----+--> reg_start - * reg_size ... | | - * ... | | [PART_1] - * ... | | - * ...+----+--> reg_start + reg_size - * | | - * - */ -int wl12xx_set_partition(struct wl12xx *wl, - u32 mem_start, u32 mem_size, - u32 reg_start, u32 reg_size) -{ - struct wl12xx_partition *partition; - struct spi_transfer t; - struct spi_message m; - size_t len, cmd_len; - u32 *cmd; - int addr; - - cmd_len = sizeof(u32) + 2 * sizeof(struct wl12xx_partition); - cmd = kzalloc(cmd_len, GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - spi_message_init(&m); - memset(&t, 0, sizeof(t)); - - partition = (struct wl12xx_partition *) (cmd + 1); - addr = HW_ACCESS_PART0_SIZE_ADDR; - len = 2 * sizeof(struct wl12xx_partition); - - *cmd |= WSPI_CMD_WRITE; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - - /* Make sure that the two partitions together don't exceed the - * address range */ - if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { - wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual" - " address range. Truncating partition[0]."); - mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - if ((mem_start < reg_start) && - ((mem_start + mem_size) > reg_start)) { - /* Guarantee that the memory partition doesn't overlap the - * registers partition */ - wl12xx_debug(DEBUG_SPI, "End of partition[0] is " - "overlapping partition[1]. Adjusted."); - mem_size = reg_start - mem_start; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } else if ((reg_start < mem_start) && - ((reg_start + reg_size) > mem_start)) { - /* Guarantee that the register partition doesn't overlap the - * memory partition */ - wl12xx_debug(DEBUG_SPI, "End of partition[1] is" - " overlapping partition[0]. Adjusted."); - reg_size = mem_start - reg_start; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - partition[0].start = mem_start; - partition[0].size = mem_size; - partition[1].start = reg_start; - partition[1].size = reg_size; - - wl->physical_mem_addr = mem_start; - wl->physical_reg_addr = reg_start; - - wl->virtual_mem_addr = 0; - wl->virtual_reg_addr = mem_size; - - t.tx_buf = cmd; - t.len = cmd_len; - spi_message_add_tail(&t, &m); - - spi_sync(wl->spi, &m); - - kfree(cmd); - - return 0; -} - -void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, - size_t len, bool fixed) -{ - struct spi_transfer t[3]; - struct spi_message m; - u8 *busy_buf; - u32 *cmd; - - cmd = &wl->buffer_cmd; - busy_buf = wl->buffer_busyword; - - *cmd = 0; - *cmd |= WSPI_CMD_READ; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - if (fixed) - *cmd |= WSPI_CMD_FIXED; - - spi_message_init(&m); - memset(t, 0, sizeof(t)); - - t[0].tx_buf = cmd; - t[0].len = 4; - spi_message_add_tail(&t[0], &m); - - /* Busy and non busy words read */ - t[1].rx_buf = busy_buf; - t[1].len = WL12XX_BUSY_WORD_LEN; - spi_message_add_tail(&t[1], &m); - - t[2].rx_buf = buf; - t[2].len = len; - spi_message_add_tail(&t[2], &m); - - spi_sync(wl->spi, &m); - - /* FIXME: check busy words */ - - wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); - wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); -} - -void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, - size_t len, bool fixed) -{ - struct spi_transfer t[2]; - struct spi_message m; - u32 *cmd; - - cmd = &wl->buffer_cmd; - - *cmd = 0; - *cmd |= WSPI_CMD_WRITE; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - if (fixed) - *cmd |= WSPI_CMD_FIXED; - - spi_message_init(&m); - memset(t, 0, sizeof(t)); - - t[0].tx_buf = cmd; - t[0].len = sizeof(*cmd); - spi_message_add_tail(&t[0], &m); - - t[1].tx_buf = buf; - t[1].len = len; - spi_message_add_tail(&t[1], &m); - - spi_sync(wl->spi, &m); - - wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); - wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); -} - -void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, - size_t len) -{ - int physical; - - physical = wl12xx_translate_mem_addr(wl, addr); - - wl12xx_spi_read(wl, physical, buf, len, false); -} - -void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, - size_t len) -{ - int physical; - - physical = wl12xx_translate_mem_addr(wl, addr); - - wl12xx_spi_write(wl, physical, buf, len, false); -} - -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, - bool fixed) -{ - int physical; - - physical = wl12xx_translate_reg_addr(wl, addr); - - wl12xx_spi_read(wl, physical, buf, len, fixed); -} - -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, - bool fixed) -{ - int physical; - - physical = wl12xx_translate_reg_addr(wl, addr); - - wl12xx_spi_write(wl, physical, buf, len, fixed); -} - -u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) -{ - return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr)); -} - -void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val) -{ - wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val); -} - -u32 wl12xx_reg_read32(struct wl12xx *wl, int addr) -{ - return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr)); -} - -void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val) -{ - wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val); -} diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h deleted file mode 100644 index e48a552..0000000 --- a/drivers/net/wireless/wl12xx/spi.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_SPI_H__ -#define __WL12XX_SPI_H__ - -#include "cmd.h" -#include "acx.h" -#include "reg.h" - -#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 - -#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 -#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 -#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 -#define HW_ACCESS_PART1_START_ADDR 0x1FFCC - -#define HW_ACCESS_REGISTER_SIZE 4 - -#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 - -#define WSPI_CMD_READ 0x40000000 -#define WSPI_CMD_WRITE 0x00000000 -#define WSPI_CMD_FIXED 0x20000000 -#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 -#define WSPI_CMD_BYTE_LENGTH_OFFSET 17 -#define WSPI_CMD_BYTE_ADDR 0x0001FFFF - -#define WSPI_INIT_CMD_CRC_LEN 5 - -#define WSPI_INIT_CMD_START 0x00 -#define WSPI_INIT_CMD_TX 0x40 -/* the extra bypass bit is sampled by the TNET as '1' */ -#define WSPI_INIT_CMD_BYPASS_BIT 0x80 -#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 -#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 -#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 -#define WSPI_INIT_CMD_IOD 0x40 -#define WSPI_INIT_CMD_IP 0x20 -#define WSPI_INIT_CMD_CS 0x10 -#define WSPI_INIT_CMD_WS 0x08 -#define WSPI_INIT_CMD_WSPI 0x01 -#define WSPI_INIT_CMD_END 0x01 - -#define WSPI_INIT_CMD_LEN 8 - -#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ - ((WL12XX_BUSY_WORD_LEN - 4) / sizeof(u32)) -#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 - - -/* Raw target IO, address is not translated */ -void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, - size_t len, bool fixed); -void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, - size_t len, bool fixed); - -/* Memory target IO, address is tranlated to partition 0 */ -void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len); -void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len); -u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); -void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); - -/* Registers IO */ -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, - bool fixed); -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, - bool fixed); -u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); -void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); - -/* INIT and RESET words */ -void wl12xx_spi_reset(struct wl12xx *wl); -void wl12xx_spi_init(struct wl12xx *wl); -int wl12xx_set_partition(struct wl12xx *wl, - u32 part_start, u32 part_size, - u32 reg_start, u32 reg_size); - -static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) -{ - wl12xx_spi_read(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); - - return wl->buffer_32; -} - -static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) -{ - wl->buffer_32 = val; - wl12xx_spi_write(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); -} - -#endif /* __WL12XX_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c new file mode 100644 index 0000000..cecc1fa --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -0,0 +1,841 @@ +#include "wl1251_acx.h" + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251_spi.h" +#include "wl1251_ps.h" + +int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, + u8 mgt_rate, u8 mgt_mod) +{ + struct acx_fw_gen_frame_rates *rates; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx frame rates"); + + rates = kzalloc(sizeof(*rates), GFP_KERNEL); + if (!rates) { + ret = -ENOMEM; + goto out; + } + + rates->tx_ctrl_frame_rate = ctrl_rate; + rates->tx_ctrl_frame_mod = ctrl_mod; + rates->tx_mgt_frame_rate = mgt_rate; + rates->tx_mgt_frame_mod = mgt_mod; + + ret = wl12xx_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, + rates, sizeof(*rates)); + if (ret < 0) { + wl12xx_error("Failed to set FW rates and modulation"); + goto out; + } + +out: + kfree(rates); + return ret; +} + + +int wl12xx_acx_station_id(struct wl12xx *wl) +{ + struct acx_dot11_station_id *mac; + int ret, i; + + wl12xx_debug(DEBUG_ACX, "acx dot11_station_id"); + + mac = kzalloc(sizeof(*mac), GFP_KERNEL); + if (!mac) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < ETH_ALEN; i++) + mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; + + ret = wl12xx_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); + if (ret < 0) + goto out; + +out: + kfree(mac); + return ret; +} + +int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) +{ + struct acx_dot11_default_key *default_key; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); + + default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); + if (!default_key) { + ret = -ENOMEM; + goto out; + } + + default_key->id = key_id; + + ret = wl12xx_cmd_configure(wl, DOT11_DEFAULT_KEY, + default_key, sizeof(*default_key)); + if (ret < 0) { + wl12xx_error("Couldnt set default key"); + goto out; + } + + wl->default_key = key_id; + +out: + kfree(default_key); + return ret; +} + +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, + u8 listen_interval) +{ + struct acx_wake_up_condition *wake_up; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx wake up conditions"); + + wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); + if (!wake_up) { + ret = -ENOMEM; + goto out; + } + + wake_up->wake_up_event = wake_up_event; + wake_up->listen_interval = listen_interval; + + ret = wl12xx_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, + wake_up, sizeof(*wake_up)); + if (ret < 0) { + wl12xx_warning("could not set wake up conditions: %d", ret); + goto out; + } + +out: + kfree(wake_up); + return ret; +} + +int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) +{ + struct acx_sleep_auth *auth; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx sleep auth"); + + auth = kzalloc(sizeof(*auth), GFP_KERNEL); + if (!auth) { + ret = -ENOMEM; + goto out; + } + + auth->sleep_auth = sleep_auth; + + ret = wl12xx_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); + if (ret < 0) + return ret; + +out: + kfree(auth); + return ret; +} + +int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) +{ + struct acx_revision *rev; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx fw rev"); + + rev = kzalloc(sizeof(*rev), GFP_KERNEL); + if (!rev) { + ret = -ENOMEM; + goto out; + } + + ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); + if (ret < 0) { + wl12xx_warning("ACX_FW_REV interrogate failed"); + goto out; + } + + /* be careful with the buffer sizes */ + strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); + + /* + * if the firmware version string is exactly + * sizeof(rev->fw_version) long or fw_len is less than + * sizeof(rev->fw_version) it won't be null terminated + */ + buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; + +out: + kfree(rev); + return ret; +} + +int wl12xx_acx_tx_power(struct wl12xx *wl, int power) +{ + struct acx_current_tx_power *acx; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); + + if (power < 0 || power > 25) + return -EINVAL; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->current_tx_power = power * 10; + + ret = wl12xx_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_warning("configure of tx power failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_feature_cfg(struct wl12xx *wl) +{ + struct acx_feature_config *feature; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx feature cfg"); + + feature = kzalloc(sizeof(*feature), GFP_KERNEL); + if (!feature) { + ret = -ENOMEM; + goto out; + } + + /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ + feature->data_flow_options = 0; + feature->options = 0; + + ret = wl12xx_cmd_configure(wl, ACX_FEATURE_CFG, + feature, sizeof(*feature)); + if (ret < 0) { + wl12xx_error("Couldnt set HW encryption"); + goto out; + } + +out: + kfree(feature); + return ret; +} + +int wl12xx_acx_mem_map(struct wl12xx *wl, struct acx_header *mem_map, + size_t len) +{ + int ret; + + wl12xx_debug(DEBUG_ACX, "acx mem map"); + + ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_acx_data_path_params(struct wl12xx *wl, + struct acx_data_path_params_resp *resp) +{ + struct acx_data_path_params *params; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx data path params"); + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + ret = -ENOMEM; + goto out; + } + + params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; + params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; + + params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; + params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; + + params->tx_complete_threshold = 1; + + params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; + + params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; + + ret = wl12xx_cmd_configure(wl, ACX_DATA_PATH_PARAMS, + params, sizeof(*params)); + if (ret < 0) + goto out; + + /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ + ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, + resp, sizeof(*resp)); + + if (ret < 0) { + wl12xx_warning("failed to read data path parameters: %d", ret); + goto out; + } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { + wl12xx_warning("data path parameter acx status failed"); + ret = -EIO; + goto out; + } + +out: + kfree(params); + return ret; +} + +int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) +{ + struct acx_rx_msdu_lifetime *acx; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rx msdu life time"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->lifetime = life_time; + ret = wl12xx_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, + acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_warning("failed to set rx msdu life time: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) +{ + struct acx_rx_config *rx_config; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rx config"); + + rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); + if (!rx_config) { + ret = -ENOMEM; + goto out; + } + + rx_config->config_options = config; + rx_config->filter_options = filter; + + ret = wl12xx_cmd_configure(wl, ACX_RX_CFG, + rx_config, sizeof(*rx_config)); + if (ret < 0) { + wl12xx_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(rx_config); + return ret; +} + +int wl12xx_acx_pd_threshold(struct wl12xx *wl) +{ + struct acx_packet_detection *pd; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx data pd threshold"); + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + ret = -ENOMEM; + goto out; + } + + /* FIXME: threshold value not set */ + + ret = wl12xx_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); + if (ret < 0) { + wl12xx_warning("failed to set pd threshold: %d", ret); + goto out; + } + +out: + kfree(pd); + return 0; +} + +int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) +{ + struct acx_slot *slot; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx slot"); + + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + ret = -ENOMEM; + goto out; + } + + slot->wone_index = STATION_WONE_INDEX; + slot->slot_time = slot_time; + + ret = wl12xx_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); + if (ret < 0) { + wl12xx_warning("failed to set slot time: %d", ret); + goto out; + } + +out: + kfree(slot); + return ret; +} + +int wl12xx_acx_group_address_tbl(struct wl12xx *wl) +{ + struct acx_dot11_grp_addr_tbl *acx; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx group address tbl"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* MAC filtering */ + acx->enabled = 0; + acx->num_groups = 0; + memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); + + ret = wl12xx_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_warning("failed to set group addr table: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_service_period_timeout(struct wl12xx *wl) +{ + struct acx_rx_timeout *rx_timeout; + int ret; + + rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); + if (!rx_timeout) { + ret = -ENOMEM; + goto out; + } + + wl12xx_debug(DEBUG_ACX, "acx service period timeout"); + + rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; + rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; + + ret = wl12xx_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, + rx_timeout, sizeof(*rx_timeout)); + if (ret < 0) { + wl12xx_warning("failed to set service period timeout: %d", + ret); + goto out; + } + +out: + kfree(rx_timeout); + return ret; +} + +int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) +{ + struct acx_rts_threshold *rts; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rts threshold"); + + rts = kzalloc(sizeof(*rts), GFP_KERNEL); + if (!rts) { + ret = -ENOMEM; + goto out; + } + + rts->threshold = rts_threshold; + + ret = wl12xx_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); + if (ret < 0) { + wl12xx_warning("failed to set rts threshold: %d", ret); + goto out; + } + +out: + kfree(rts); + return ret; +} + +int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) +{ + struct acx_beacon_filter_option *beacon_filter; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx beacon filter opt"); + + beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); + if (!beacon_filter) { + ret = -ENOMEM; + goto out; + } + + beacon_filter->enable = 0; + beacon_filter->max_num_beacons = 0; + + ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_OPT, + beacon_filter, sizeof(*beacon_filter)); + if (ret < 0) { + wl12xx_warning("failed to set beacon filter opt: %d", ret); + goto out; + } + +out: + kfree(beacon_filter); + return ret; +} + +int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) +{ + struct acx_beacon_filter_ie_table *ie_table; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx beacon filter table"); + + ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); + if (!ie_table) { + ret = -ENOMEM; + goto out; + } + + ie_table->num_ie = 0; + memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); + + ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, + ie_table, sizeof(*ie_table)); + if (ret < 0) { + wl12xx_warning("failed to set beacon filter table: %d", ret); + goto out; + } + +out: + kfree(ie_table); + return ret; +} + +int wl12xx_acx_sg_enable(struct wl12xx *wl) +{ + struct acx_bt_wlan_coex *pta; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx sg enable"); + + pta = kzalloc(sizeof(*pta), GFP_KERNEL); + if (!pta) { + ret = -ENOMEM; + goto out; + } + + pta->enable = SG_ENABLE; + + ret = wl12xx_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); + if (ret < 0) { + wl12xx_warning("failed to set softgemini enable: %d", ret); + goto out; + } + +out: + kfree(pta); + return ret; +} + +int wl12xx_acx_sg_cfg(struct wl12xx *wl) +{ + struct acx_bt_wlan_coex_param *param; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx sg cfg"); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + + /* BT-WLAN coext parameters */ + param->min_rate = RATE_INDEX_24MBPS; + param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; + param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; + param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; + param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; + param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; + param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; + param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; + param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; + param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; + param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; + param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; + param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; + param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; + param->antenna_type = PTA_ANTENNA_TYPE_DEF; + param->signal_type = PTA_SIGNALING_TYPE_DEF; + param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; + param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; + param->max_cts = PTA_MAX_NUM_CTS_DEF; + param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; + param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; + param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; + param->wlan_elp_hp = PTA_ELP_HP_DEF; + param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; + param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; + param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; + param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; + param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; + + ret = wl12xx_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); + if (ret < 0) { + wl12xx_warning("failed to set sg config: %d", ret); + goto out; + } + +out: + kfree(param); + return ret; +} + +int wl12xx_acx_cca_threshold(struct wl12xx *wl) +{ + struct acx_energy_detection *detection; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx cca threshold"); + + detection = kzalloc(sizeof(*detection), GFP_KERNEL); + if (!detection) { + ret = -ENOMEM; + goto out; + } + + detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; + detection->tx_energy_detection = 0; + + ret = wl12xx_cmd_configure(wl, ACX_CCA_THRESHOLD, + detection, sizeof(*detection)); + if (ret < 0) { + wl12xx_warning("failed to set cca threshold: %d", ret); + return ret; + } + +out: + kfree(detection); + return ret; +} + +int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) +{ + struct acx_beacon_broadcast *bb; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx bcn dtim options"); + + bb = kzalloc(sizeof(*bb), GFP_KERNEL); + if (!bb) { + ret = -ENOMEM; + goto out; + } + + bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; + bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; + bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; + bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; + + ret = wl12xx_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); + if (ret < 0) { + wl12xx_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(bb); + return ret; +} + +int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) +{ + struct acx_aid *acx_aid; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx aid"); + + acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); + if (!acx_aid) { + ret = -ENOMEM; + goto out; + } + + acx_aid->aid = aid; + + ret = wl12xx_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); + if (ret < 0) { + wl12xx_warning("failed to set aid: %d", ret); + goto out; + } + +out: + kfree(acx_aid); + return ret; +} + +int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) +{ + struct acx_event_mask *mask; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx event mbox mask"); + + mask = kzalloc(sizeof(*mask), GFP_KERNEL); + if (!mask) { + ret = -ENOMEM; + goto out; + } + + /* high event mask is unused */ + mask->high_event_mask = 0xffffffff; + + mask->event_mask = event_mask; + + ret = wl12xx_cmd_configure(wl, ACX_EVENT_MBOX_MASK, + mask, sizeof(*mask)); + if (ret < 0) { + wl12xx_warning("failed to set acx_event_mbox_mask: %d", ret); + goto out; + } + +out: + kfree(mask); + return ret; +} + +int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) +{ + struct acx_preamble *acx; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx_set_preamble"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->preamble = preamble; + + ret = wl12xx_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_warning("Setting of preamble failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_cts_protect(struct wl12xx *wl, + enum acx_ctsprotect_type ctsprotect) +{ + struct acx_ctsprotect *acx; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ctsprotect = ctsprotect; + + ret = wl12xx_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_warning("Setting of ctsprotect failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime) +{ + struct acx_tsf_info *tsf_info; + int ret; + + tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); + if (!tsf_info) { + ret = -ENOMEM; + goto out; + } + + ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, + tsf_info, sizeof(*tsf_info)); + if (ret < 0) { + wl12xx_warning("ACX_FW_REV interrogate failed"); + goto out; + } + + *mactime = tsf_info->current_tsf_lsb | + (tsf_info->current_tsf_msb << 31); + +out: + kfree(tsf_info); + return ret; +} + +int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) +{ + int ret; + + wl12xx_debug(DEBUG_ACX, "acx statistics"); + + ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, stats, + sizeof(*stats)); + if (ret < 0) { + wl12xx_warning("acx statistics failed: %d", ret); + return -ENOMEM; + } + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h new file mode 100644 index 0000000..203f11f --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -0,0 +1,1146 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_ACX_H__ +#define __WL12XX_ACX_H__ + +#include "wl12xx.h" +#include "wl1251_cmd.h" + +/* Target's information element */ +struct acx_header { + struct wl12xx_cmd_header cmd; + + /* acx (or information element) header */ + u16 id; + + /* payload length (not including headers */ + u16 len; +}; + +struct acx_error_counter { + struct acx_header header; + + /* The number of PLCP errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 PLCP_error; + + /* The number of FCS errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 FCS_error; + + /* The number of MPDUs without PLCP header errors received*/ + /* since the last time this information element was interrogated. */ + /* This field is automatically cleared when it is interrogated.*/ + u32 valid_frame; + + /* the number of missed sequence numbers in the squentially */ + /* values of frames seq numbers */ + u32 seq_num_miss; +} __attribute__ ((packed)); + +struct acx_revision { + struct acx_header header; + + /* + * The WiLink firmware version, an ASCII string x.x.x.x, + * that uniquely identifies the current firmware. + * The left most digit is incremented each time a + * significant change is made to the firmware, such as + * code redesign or new platform support. + * The second digit is incremented when major enhancements + * are added or major fixes are made. + * The third digit is incremented for each GA release. + * The fourth digit is incremented for each build. + * The first two digits identify a firmware release version, + * in other words, a unique set of features. + * The first three digits identify a GA release. + */ + char fw_version[20]; + + /* + * This 4 byte field specifies the WiLink hardware version. + * bits 0 - 15: Reserved. + * bits 16 - 23: Version ID - The WiLink version ID + * (1 = first spin, 2 = second spin, and so on). + * bits 24 - 31: Chip ID - The WiLink chip ID. + */ + u32 hw_version; +} __attribute__ ((packed)); + +enum wl12xx_psm_mode { + /* Active mode */ + WL12XX_PSM_CAM = 0, + + /* Power save mode */ + WL12XX_PSM_PS = 1, + + /* Extreme low power */ + WL12XX_PSM_ELP = 2, +}; + +struct acx_sleep_auth { + struct acx_header header; + + /* The sleep level authorization of the device. */ + /* 0 - Always active*/ + /* 1 - Power down mode: light / fast sleep*/ + /* 2 - ELP mode: Deep / Max sleep*/ + u8 sleep_auth; + u8 padding[3]; +} __attribute__ ((packed)); + +enum { + HOSTIF_PCI_MASTER_HOST_INDIRECT, + HOSTIF_PCI_MASTER_HOST_DIRECT, + HOSTIF_SLAVE, + HOSTIF_PKT_RING, + HOSTIF_DONTCARE = 0xFF +}; + +#define DEFAULT_UCAST_PRIORITY 0 +#define DEFAULT_RX_Q_PRIORITY 0 +#define DEFAULT_NUM_STATIONS 1 +#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ +#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ +#define TRACE_BUFFER_MAX_SIZE 256 + +#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_RX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_COMPLETE_TIME_OUT 20 +#define FW_TX_CMPLT_BLOCK_SIZE 16 + +struct acx_data_path_params { + struct acx_header header; + + u16 rx_packet_ring_chunk_size; + u16 tx_packet_ring_chunk_size; + + u8 rx_packet_ring_chunk_num; + u8 tx_packet_ring_chunk_num; + + /* + * Maximum number of packets that can be gathered + * in the TX complete ring before an interrupt + * is generated. + */ + u8 tx_complete_threshold; + + /* Number of pending TX complete entries in cyclic ring.*/ + u8 tx_complete_ring_depth; + + /* + * Max num microseconds since a packet enters the TX + * complete ring until an interrupt is generated. + */ + u32 tx_complete_timeout; +} __attribute__ ((packed)); + + +struct acx_data_path_params_resp { + struct acx_header header; + + u16 rx_packet_ring_chunk_size; + u16 tx_packet_ring_chunk_size; + + u8 rx_packet_ring_chunk_num; + u8 tx_packet_ring_chunk_num; + + u8 pad[2]; + + u32 rx_packet_ring_addr; + u32 tx_packet_ring_addr; + + u32 rx_control_addr; + u32 tx_control_addr; + + u32 tx_complete_addr; +} __attribute__ ((packed)); + +#define TX_MSDU_LIFETIME_MIN 0 +#define TX_MSDU_LIFETIME_MAX 3000 +#define TX_MSDU_LIFETIME_DEF 512 +#define RX_MSDU_LIFETIME_MIN 0 +#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF +#define RX_MSDU_LIFETIME_DEF 512000 + +struct acx_rx_msdu_lifetime { + struct acx_header header; + + /* + * The maximum amount of time, in TU, before the + * firmware discards the MSDU. + */ + u32 lifetime; +} __attribute__ ((packed)); + +/* + * RX Config Options Table + * Bit Definition + * === ========== + * 31:14 Reserved + * 13 Copy RX Status - when set, write three receive status words + * to top of rx'd MPDUs. + * When cleared, do not write three status words (added rev 1.5) + * 12 Reserved + * 11 RX Complete upon FCS error - when set, give rx complete + * interrupt for FCS errors, after the rx filtering, e.g. unicast + * frames not to us with FCS error will not generate an interrupt. + * 10 SSID Filter Enable - When set, the WiLink discards all beacon, + * probe request, and probe response frames with an SSID that does + * not match the SSID specified by the host in the START/JOIN + * command. + * When clear, the WiLink receives frames with any SSID. + * 9 Broadcast Filter Enable - When set, the WiLink discards all + * broadcast frames. When clear, the WiLink receives all received + * broadcast frames. + * 8:6 Reserved + * 5 BSSID Filter Enable - When set, the WiLink discards any frames + * with a BSSID that does not match the BSSID specified by the + * host. + * When clear, the WiLink receives frames from any BSSID. + * 4 MAC Addr Filter - When set, the WiLink discards any frames + * with a destination address that does not match the MAC address + * of the adaptor. + * When clear, the WiLink receives frames destined to any MAC + * address. + * 3 Promiscuous - When set, the WiLink receives all valid frames + * (i.e., all frames that pass the FCS check). + * When clear, only frames that pass the other filters specified + * are received. + * 2 FCS - When set, the WiLink includes the FCS with the received + * frame. + * When cleared, the FCS is discarded. + * 1 PLCP header - When set, write all data from baseband to frame + * buffer including PHY header. + * 0 Reserved - Always equal to 0. + * + * RX Filter Options Table + * Bit Definition + * === ========== + * 31:12 Reserved - Always equal to 0. + * 11 Association - When set, the WiLink receives all association + * related frames (association request/response, reassocation + * request/response, and disassociation). When clear, these frames + * are discarded. + * 10 Auth/De auth - When set, the WiLink receives all authentication + * and de-authentication frames. When clear, these frames are + * discarded. + * 9 Beacon - When set, the WiLink receives all beacon frames. + * When clear, these frames are discarded. + * 8 Contention Free - When set, the WiLink receives all contention + * free frames. + * When clear, these frames are discarded. + * 7 Control - When set, the WiLink receives all control frames. + * When clear, these frames are discarded. + * 6 Data - When set, the WiLink receives all data frames. + * When clear, these frames are discarded. + * 5 FCS Error - When set, the WiLink receives frames that have FCS + * errors. + * When clear, these frames are discarded. + * 4 Management - When set, the WiLink receives all management + * frames. + * When clear, these frames are discarded. + * 3 Probe Request - When set, the WiLink receives all probe request + * frames. + * When clear, these frames are discarded. + * 2 Probe Response - When set, the WiLink receives all probe + * response frames. + * When clear, these frames are discarded. + * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK + * frames. + * When clear, these frames are discarded. + * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames + * that have reserved frame types and sub types as defined by the + * 802.11 specification. + * When clear, these frames are discarded. + */ +struct acx_rx_config { + struct acx_header header; + + u32 config_options; + u32 filter_options; +} __attribute__ ((packed)); + +enum { + QOS_AC_BE = 0, + QOS_AC_BK, + QOS_AC_VI, + QOS_AC_VO, + QOS_HIGHEST_AC_INDEX = QOS_AC_VO, +}; + +#define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) +#define FIRST_AC_INDEX QOS_AC_BE +#define MAX_NUM_OF_802_1d_TAGS 8 +#define AC_PARAMS_MAX_TSID 15 +#define MAX_APSD_CONF 0xffff + +#define QOS_TX_HIGH_MIN (0) +#define QOS_TX_HIGH_MAX (100) + +#define QOS_TX_HIGH_BK_DEF (25) +#define QOS_TX_HIGH_BE_DEF (35) +#define QOS_TX_HIGH_VI_DEF (35) +#define QOS_TX_HIGH_VO_DEF (35) + +#define QOS_TX_LOW_BK_DEF (15) +#define QOS_TX_LOW_BE_DEF (25) +#define QOS_TX_LOW_VI_DEF (25) +#define QOS_TX_LOW_VO_DEF (25) + +struct acx_tx_queue_qos_config { + struct acx_header header; + + u8 qid; + u8 pad[3]; + + /* Max number of blocks allowd in the queue */ + u16 high_threshold; + + /* Lowest memory blocks guaranteed for this queue */ + u16 low_threshold; +} __attribute__ ((packed)); + +struct acx_packet_detection { + struct acx_header header; + + u32 threshold; +} __attribute__ ((packed)); + + +enum acx_slot_type { + SLOT_TIME_LONG = 0, + SLOT_TIME_SHORT = 1, + DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, + MAX_SLOT_TIMES = 0xFF +}; + +#define STATION_WONE_INDEX 0 + +struct acx_slot { + struct acx_header header; + + u8 wone_index; /* Reserved */ + u8 slot_time; + u8 reserved[6]; +} __attribute__ ((packed)); + + +#define ADDRESS_GROUP_MAX (8) +#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) + +struct acx_dot11_grp_addr_tbl { + struct acx_header header; + + u8 enabled; + u8 num_groups; + u8 pad[2]; + u8 mac_table[ADDRESS_GROUP_MAX_LEN]; +} __attribute__ ((packed)); + + +#define RX_TIMEOUT_PS_POLL_MIN 0 +#define RX_TIMEOUT_PS_POLL_MAX (200000) +#define RX_TIMEOUT_PS_POLL_DEF (15) +#define RX_TIMEOUT_UPSD_MIN 0 +#define RX_TIMEOUT_UPSD_MAX (200000) +#define RX_TIMEOUT_UPSD_DEF (15) + +struct acx_rx_timeout { + struct acx_header header; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a PS-poll has been + * transmitted. + */ + u16 ps_poll_timeout; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a frame has been sent + * from an UPSD enabled queue. + */ + u16 upsd_timeout; +} __attribute__ ((packed)); + +#define RTS_THRESHOLD_MIN 0 +#define RTS_THRESHOLD_MAX 4096 +#define RTS_THRESHOLD_DEF 2347 + +struct acx_rts_threshold { + struct acx_header header; + + u16 threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_beacon_filter_option { + struct acx_header header; + + u8 enable; + + /* + * The number of beacons without the unicast TIM + * bit set that the firmware buffers before + * signaling the host about ready frames. + * When set to 0 and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + u8 max_num_beacons; + u8 pad[2]; +} __attribute__ ((packed)); + +/* + * ACXBeaconFilterEntry (not 221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * + * ACXBeaconFilterEntry (221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * 2 3 OUI + * 5 1 Type + * 6 2 Version + * + * + * Treatment bit mask - The information element handling: + * bit 0 - The information element is compared and transferred + * in case of change. + * bit 1 - The information element is transferred to the host + * with each appearance or disappearance. + * Note that both bits can be set at the same time. + */ +#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) +#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) +#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) +#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) +#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ + BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ + (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ + BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) + +struct acx_beacon_filter_ie_table { + struct acx_header header; + + u8 num_ie; + u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; + u8 pad[3]; +} __attribute__ ((packed)); + +enum { + SG_ENABLE = 0, + SG_DISABLE, + SG_SENSE_NO_ACTIVITY, + SG_SENSE_ACTIVE +}; + +struct acx_bt_wlan_coex { + struct acx_header header; + + /* + * 0 -> PTA enabled + * 1 -> PTA disabled + * 2 -> sense no active mode, i.e. + * an interrupt is sent upon + * BT activity. + * 3 -> PTA is switched on in response + * to the interrupt sending. + */ + u8 enable; + u8 pad[3]; +} __attribute__ ((packed)); + +#define PTA_ANTENNA_TYPE_DEF (0) +#define PTA_BT_HP_MAXTIME_DEF (2000) +#define PTA_WLAN_HP_MAX_TIME_DEF (5000) +#define PTA_SENSE_DISABLE_TIMER_DEF (1350) +#define PTA_PROTECTIVE_RX_TIME_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_DEF (1500) +#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) +#define PTA_SIGNALING_TYPE_DEF (1) +#define PTA_AFH_LEVERAGE_ON_DEF (0) +#define PTA_NUMBER_QUIET_CYCLE_DEF (0) +#define PTA_MAX_NUM_CTS_DEF (3) +#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) +#define PTA_NUMBER_OF_BT_PACKETS_DEF (2) +#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) +#define PTA_CYCLE_TIME_FAST_DEF (8700) +#define PTA_RX_FOR_AVALANCHE_DEF (5) +#define PTA_ELP_HP_DEF (0) +#define PTA_ANTI_STARVE_PERIOD_DEF (500) +#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) +#define PTA_ALLOW_PA_SD_DEF (1) +#define PTA_TIME_BEFORE_BEACON_DEF (6300) +#define PTA_HPDM_MAX_TIME_DEF (1600) +#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) +#define PTA_AUTO_MODE_NO_CTS_DEF (0) +#define PTA_BT_HP_RESPECTED_DEF (3) +#define PTA_WLAN_RX_MIN_RATE_DEF (24) +#define PTA_ACK_MODE_DEF (1) + +struct acx_bt_wlan_coex_param { + struct acx_header header; + + /* + * The minimum rate of a received WLAN packet in the STA, + * during protective mode, of which a new BT-HP request + * during this Rx will always be respected and gain the antenna. + */ + u32 min_rate; + + /* Max time the BT HP will be respected. */ + u16 bt_hp_max_time; + + /* Max time the WLAN HP will be respected. */ + u16 wlan_hp_max_time; + + /* + * The time between the last BT activity + * and the moment when the sense mode returns + * to SENSE_INACTIVE. + */ + u16 sense_disable_timer; + + /* Time before the next BT HP instance */ + u16 rx_time_bt_hp; + u16 tx_time_bt_hp; + + /* range: 10-20000 default: 1500 */ + u16 rx_time_bt_hp_fast; + u16 tx_time_bt_hp_fast; + + /* range: 2000-65535 default: 8700 */ + u16 wlan_cycle_fast; + + /* range: 0 - 15000 (Msec) default: 1000 */ + u16 bt_anti_starvation_period; + + /* range 400-10000(Usec) default: 3000 */ + u16 next_bt_lp_packet; + + /* Deafult: worst case for BT DH5 traffic */ + u16 wake_up_beacon; + + /* range: 0-50000(Usec) default: 1050 */ + u16 hp_dm_max_guard_time; + + /* + * This is to prevent both BT & WLAN antenna + * starvation. + * Range: 100-50000(Usec) default:2550 + */ + u16 next_wlan_packet; + + /* 0 -> shared antenna */ + u8 antenna_type; + + /* + * 0 -> TI legacy + * 1 -> Palau + */ + u8 signal_type; + + /* + * BT AFH status + * 0 -> no AFH + * 1 -> from dedicated GPIO + * 2 -> AFH on (from host) + */ + u8 afh_leverage_on; + + /* + * The number of cycles during which no + * TX will be sent after 1 cycle of RX + * transaction in protective mode + */ + u8 quiet_cycle_num; + + /* + * The maximum number of CTSs that will + * be sent for receiving RX packet in + * protective mode + */ + u8 max_cts; + + /* + * The number of WLAN packets + * transferred in common mode before + * switching to BT. + */ + u8 wlan_packets_num; + + /* + * The number of BT packets + * transferred in common mode before + * switching to WLAN. + */ + u8 bt_packets_num; + + /* range: 1-255 default: 5 */ + u8 missed_rx_avalanche; + + /* range: 0-1 default: 1 */ + u8 wlan_elp_hp; + + /* range: 0 - 15 default: 4 */ + u8 bt_anti_starvation_cycles; + + u8 ack_mode_dual_ant; + + /* + * Allow PA_SD assertion/de-assertion + * during enabled BT activity. + */ + u8 pa_sd_enable; + + /* + * Enable/Disable PTA in auto mode: + * Support Both Active & P.S modes + */ + u8 pta_auto_mode_enable; + + /* range: 0 - 20 default: 1 */ + u8 bt_hp_respected_num; +} __attribute__ ((packed)); + +#define CCA_THRSH_ENABLE_ENERGY_D 0x140A +#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF + +struct acx_energy_detection { + struct acx_header header; + + /* The RX Clear Channel Assessment threshold in the PHY */ + u16 rx_cca_threshold; + u8 tx_energy_detection; + u8 pad; +} __attribute__ ((packed)); + +#define BCN_RX_TIMEOUT_DEF_VALUE 10000 +#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 +#define RX_BROADCAST_IN_PS_DEF_VALUE 1 +#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 + +struct acx_beacon_broadcast { + struct acx_header header; + + u16 beacon_rx_timeout; + u16 broadcast_timeout; + + /* Enables receiving of broadcast packets in PS mode */ + u8 rx_broadcast_in_ps; + + /* Consecutive PS Poll failures before updating the host */ + u8 ps_poll_threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_event_mask { + struct acx_header header; + + u32 event_mask; + u32 high_event_mask; /* Unused */ +} __attribute__ ((packed)); + +#define CFG_RX_FCS BIT(2) +#define CFG_RX_ALL_GOOD BIT(3) +#define CFG_UNI_FILTER_EN BIT(4) +#define CFG_BSSID_FILTER_EN BIT(5) +#define CFG_MC_FILTER_EN BIT(6) +#define CFG_MC_ADDR0_EN BIT(7) +#define CFG_MC_ADDR1_EN BIT(8) +#define CFG_BC_REJECT_EN BIT(9) +#define CFG_SSID_FILTER_EN BIT(10) +#define CFG_RX_INT_FCS_ERROR BIT(11) +#define CFG_RX_INT_ENCRYPTED BIT(12) +#define CFG_RX_WR_RX_STATUS BIT(13) +#define CFG_RX_FILTER_NULTI BIT(14) +#define CFG_RX_RESERVE BIT(15) +#define CFG_RX_TIMESTAMP_TSF BIT(16) + +#define CFG_RX_RSV_EN BIT(0) +#define CFG_RX_RCTS_ACK BIT(1) +#define CFG_RX_PRSP_EN BIT(2) +#define CFG_RX_PREQ_EN BIT(3) +#define CFG_RX_MGMT_EN BIT(4) +#define CFG_RX_FCS_ERROR BIT(5) +#define CFG_RX_DATA_EN BIT(6) +#define CFG_RX_CTL_EN BIT(7) +#define CFG_RX_CF_EN BIT(8) +#define CFG_RX_BCN_EN BIT(9) +#define CFG_RX_AUTH_EN BIT(10) +#define CFG_RX_ASSOC_EN BIT(11) + +#define SCAN_PASSIVE BIT(0) +#define SCAN_5GHZ_BAND BIT(1) +#define SCAN_TRIGGERED BIT(2) +#define SCAN_PRIORITY_HIGH BIT(3) + +struct acx_fw_gen_frame_rates { + struct acx_header header; + + u8 tx_ctrl_frame_rate; /* RATE_* */ + u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ + u8 tx_mgt_frame_rate; + u8 tx_mgt_frame_mod; +} __attribute__ ((packed)); + +/* STA MAC */ +struct acx_dot11_station_id { + struct acx_header header; + + u8 mac[ETH_ALEN]; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_feature_config { + struct acx_header header; + + u32 options; + u32 data_flow_options; +} __attribute__ ((packed)); + +struct acx_current_tx_power { + struct acx_header header; + + u8 current_tx_power; + u8 padding[3]; +} __attribute__ ((packed)); + +struct acx_dot11_default_key { + struct acx_header header; + + u8 id; + u8 pad[3]; +} __attribute__ ((packed)); + +struct acx_tsf_info { + struct acx_header header; + + u32 current_tsf_msb; + u32 current_tsf_lsb; + u32 last_TBTT_msb; + u32 last_TBTT_lsb; + u8 last_dtim_count; + u8 pad[3]; +} __attribute__ ((packed)); + +enum acx_wake_up_event { + WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ + WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ + WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ + WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ + WAKE_UP_EVENT_BITS_MASK = 0x0F +}; + +struct acx_wake_up_condition { + struct acx_header header; + + u8 wake_up_event; /* Only one bit can be set */ + u8 listen_interval; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_aid { + struct acx_header header; + + /* + * To be set when associated with an AP. + */ + u16 aid; + u8 pad[2]; +} __attribute__ ((packed)); + +enum acx_preamble_type { + ACX_PREAMBLE_LONG = 0, + ACX_PREAMBLE_SHORT = 1 +}; + +struct acx_preamble { + struct acx_header header; + + /* + * When set, the WiLink transmits the frames with a short preamble and + * when cleared, the WiLink transmits the frames with a long preamble. + */ + u8 preamble; + u8 padding[3]; +} __attribute__ ((packed)); + +enum acx_ctsprotect_type { + CTSPROTECT_DISABLE = 0, + CTSPROTECT_ENABLE = 1 +}; + +struct acx_ctsprotect { + struct acx_header header; + u8 ctsprotect; + u8 padding[3]; +} __attribute__ ((packed)); + +struct acx_tx_statistics { + u32 internal_desc_overflow; +} __attribute__ ((packed)); + +struct acx_rx_statistics { + u32 out_of_mem; + u32 hdr_overflow; + u32 hw_stuck; + u32 dropped; + u32 fcs_err; + u32 xfr_hint_trig; + u32 path_reset; + u32 reset_counter; +} __attribute__ ((packed)); + +struct acx_dma_statistics { + u32 rx_requested; + u32 rx_errors; + u32 tx_requested; + u32 tx_errors; +} __attribute__ ((packed)); + +struct acx_isr_statistics { + /* host command complete */ + u32 cmd_cmplt; + + /* fiqisr() */ + u32 fiqs; + + /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ + u32 rx_headers; + + /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ + u32 rx_completes; + + /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ + u32 rx_mem_overflow; + + /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ + u32 rx_rdys; + + /* irqisr() */ + u32 irqs; + + /* (INT_STS_ND & INT_TRIG_TX_PROC) */ + u32 tx_procs; + + /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ + u32 decrypt_done; + + /* (INT_STS_ND & INT_TRIG_DMA0) */ + u32 dma0_done; + + /* (INT_STS_ND & INT_TRIG_DMA1) */ + u32 dma1_done; + + /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ + u32 tx_exch_complete; + + /* (INT_STS_ND & INT_TRIG_COMMAND) */ + u32 commands; + + /* (INT_STS_ND & INT_TRIG_RX_PROC) */ + u32 rx_procs; + + /* (INT_STS_ND & INT_TRIG_PM_802) */ + u32 hw_pm_mode_changes; + + /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ + u32 host_acknowledges; + + /* (INT_STS_ND & INT_TRIG_PM_PCI) */ + u32 pci_pm; + + /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ + u32 wakeups; + + /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ + u32 low_rssi; +} __attribute__ ((packed)); + +struct acx_wep_statistics { + /* WEP address keys configured */ + u32 addr_key_count; + + /* default keys configured */ + u32 default_key_count; + + u32 reserved; + + /* number of times that WEP key not found on lookup */ + u32 key_not_found; + + /* number of times that WEP key decryption failed */ + u32 decrypt_fail; + + /* WEP packets decrypted */ + u32 packets; + + /* WEP decrypt interrupts */ + u32 interrupt; +} __attribute__ ((packed)); + +#define ACX_MISSED_BEACONS_SPREAD 10 + +struct acx_pwr_statistics { + /* the amount of enters into power save mode (both PD & ELP) */ + u32 ps_enter; + + /* the amount of enters into ELP mode */ + u32 elp_enter; + + /* the amount of missing beacon interrupts to the host */ + u32 missing_bcns; + + /* the amount of wake on host-access times */ + u32 wake_on_host; + + /* the amount of wake on timer-expire */ + u32 wake_on_timer_exp; + + /* the number of packets that were transmitted with PS bit set */ + u32 tx_with_ps; + + /* the number of packets that were transmitted with PS bit clear */ + u32 tx_without_ps; + + /* the number of received beacons */ + u32 rcvd_beacons; + + /* the number of entering into PowerOn (power save off) */ + u32 power_save_off; + + /* the number of entries into power save mode */ + u16 enable_ps; + + /* + * the number of exits from power save, not including failed PS + * transitions + */ + u16 disable_ps; + + /* + * the number of times the TSF counter was adjusted because + * of drift + */ + u32 fix_tsf_ps; + + /* Gives statistics about the spread continuous missed beacons. + * The 16 LSB are dedicated for the PS mode. + * The 16 MSB are dedicated for the PS mode. + * cont_miss_bcns_spread[0] - single missed beacon. + * cont_miss_bcns_spread[1] - two continuous missed beacons. + * cont_miss_bcns_spread[2] - three continuous missed beacons. + * ... + * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. + */ + u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; + + /* the number of beacons in awake mode */ + u32 rcvd_awake_beacons; +} __attribute__ ((packed)); + +struct acx_mic_statistics { + u32 rx_pkts; + u32 calc_failure; +} __attribute__ ((packed)); + +struct acx_aes_statistics { + u32 encrypt_fail; + u32 decrypt_fail; + u32 encrypt_packets; + u32 decrypt_packets; + u32 encrypt_interrupt; + u32 decrypt_interrupt; +} __attribute__ ((packed)); + +struct acx_event_statistics { + u32 heart_beat; + u32 calibration; + u32 rx_mismatch; + u32 rx_mem_empty; + u32 rx_pool; + u32 oom_late; + u32 phy_transmit_error; + u32 tx_stuck; +} __attribute__ ((packed)); + +struct acx_ps_statistics { + u32 pspoll_timeouts; + u32 upsd_timeouts; + u32 upsd_max_sptime; + u32 upsd_max_apturn; + u32 pspoll_max_apturn; + u32 pspoll_utilization; + u32 upsd_utilization; +} __attribute__ ((packed)); + +struct acx_rxpipe_statistics { + u32 rx_prep_beacon_drop; + u32 descr_host_int_trig_rx_data; + u32 beacon_buffer_thres_host_int_trig_rx_data; + u32 missed_beacon_host_int_trig_rx_data; + u32 tx_xfr_host_int_trig_rx_data; +} __attribute__ ((packed)); + +struct acx_statistics { + struct acx_header header; + + struct acx_tx_statistics tx; + struct acx_rx_statistics rx; + struct acx_dma_statistics dma; + struct acx_isr_statistics isr; + struct acx_wep_statistics wep; + struct acx_pwr_statistics pwr; + struct acx_aes_statistics aes; + struct acx_mic_statistics mic; + struct acx_event_statistics event; + struct acx_ps_statistics ps; + struct acx_rxpipe_statistics rxpipe; +} __attribute__ ((packed)); + +enum { + ACX_WAKE_UP_CONDITIONS = 0x0002, + ACX_MEM_CFG = 0x0003, + ACX_SLOT = 0x0004, + ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ + ACX_AC_CFG = 0x0007, + ACX_MEM_MAP = 0x0008, + ACX_AID = 0x000A, + ACX_RADIO_PARAM = 0x000B, /* Not used */ + ACX_CFG = 0x000C, /* Not used */ + ACX_FW_REV = 0x000D, + ACX_MEDIUM_USAGE = 0x000F, + ACX_RX_CFG = 0x0010, + ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ + ACX_BSS_IN_PS = 0x0012, /* for AP only */ + ACX_STATISTICS = 0x0013, /* Debug API */ + ACX_FEATURE_CFG = 0x0015, + ACX_MISC_CFG = 0x0017, /* Not used */ + ACX_TID_CFG = 0x001A, + ACX_BEACON_FILTER_OPT = 0x001F, + ACX_LOW_RSSI = 0x0020, + ACX_NOISE_HIST = 0x0021, + ACX_HDK_VERSION = 0x0022, /* ??? */ + ACX_PD_THRESHOLD = 0x0023, + ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ + ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ + ACX_CCA_THRESHOLD = 0x0025, + ACX_EVENT_MBOX_MASK = 0x0026, +#ifdef FW_RUNNING_AS_AP + ACX_DTIM_PERIOD = 0x0027, /* for AP only */ +#else + ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ +#endif + ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ + ACX_GPIO_CFG = 0x002A, /* Not used */ + ACX_GPIO_SET = 0x002B, /* Not used */ + ACX_PM_CFG = 0x002C, /* To Be Documented */ + ACX_CONN_MONIT_PARAMS = 0x002D, + ACX_AVERAGE_RSSI = 0x002E, /* Not used */ + ACX_CONS_TX_FAILURE = 0x002F, + ACX_BCN_DTIM_OPTIONS = 0x0031, + ACX_SG_ENABLE = 0x0032, + ACX_SG_CFG = 0x0033, + ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ + ACX_LOW_SNR = 0x0037, /* To Be Documented */ + ACX_BEACON_FILTER_TABLE = 0x0038, + ACX_ARP_IP_FILTER = 0x0039, + ACX_ROAMING_STATISTICS_TBL = 0x003B, + ACX_RATE_POLICY = 0x003D, + ACX_CTS_PROTECTION = 0x003E, + ACX_SLEEP_AUTH = 0x003F, + ACX_PREAMBLE_TYPE = 0x0040, + ACX_ERROR_CNT = 0x0041, + ACX_FW_GEN_FRAME_RATES = 0x0042, + ACX_IBSS_FILTER = 0x0044, + ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, + ACX_TSF_INFO = 0x0046, + ACX_CONFIG_PS_WMM = 0x0049, + ACX_ENABLE_RX_DATA_FILTER = 0x004A, + ACX_SET_RX_DATA_FILTER = 0x004B, + ACX_GET_DATA_FILTER_STATISTICS = 0x004C, + ACX_POWER_LEVEL_TABLE = 0x004D, + ACX_BET_ENABLE = 0x0050, + DOT11_STATION_ID = 0x1001, + DOT11_RX_MSDU_LIFE_TIME = 0x1004, + DOT11_CUR_TX_PWR = 0x100D, + DOT11_DEFAULT_KEY = 0x1010, + DOT11_RX_DOT11_MODE = 0x1012, + DOT11_RTS_THRESHOLD = 0x1013, + DOT11_GROUP_ADDRESS_TBL = 0x1014, + + MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, + + MAX_IE = 0xFFFF +}; + + +int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, + u8 mgt_rate, u8 mgt_mod); +int wl12xx_acx_station_id(struct wl12xx *wl); +int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id); +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, + u8 listen_interval); +int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); +int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); +int wl12xx_acx_tx_power(struct wl12xx *wl, int power); +int wl12xx_acx_feature_cfg(struct wl12xx *wl); +int wl12xx_acx_mem_map(struct wl12xx *wl, + struct acx_header *mem_map, size_t len); +int wl12xx_acx_data_path_params(struct wl12xx *wl, + struct acx_data_path_params_resp *data_path); +int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time); +int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter); +int wl12xx_acx_pd_threshold(struct wl12xx *wl); +int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time); +int wl12xx_acx_group_address_tbl(struct wl12xx *wl); +int wl12xx_acx_service_period_timeout(struct wl12xx *wl); +int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold); +int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl); +int wl12xx_acx_beacon_filter_table(struct wl12xx *wl); +int wl12xx_acx_sg_enable(struct wl12xx *wl); +int wl12xx_acx_sg_cfg(struct wl12xx *wl); +int wl12xx_acx_cca_threshold(struct wl12xx *wl); +int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl); +int wl12xx_acx_aid(struct wl12xx *wl, u16 aid); +int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask); +int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble); +int wl12xx_acx_cts_protect(struct wl12xx *wl, + enum acx_ctsprotect_type ctsprotect); +int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats); +int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime); + +#endif /* __WL12XX_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c new file mode 100644 index 0000000..c52a208 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -0,0 +1,297 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include + +#include "reg.h" +#include "wl1251_boot.h" +#include "wl1251_spi.h" +#include "wl1251_event.h" + +static void wl12xx_boot_enable_interrupts(struct wl12xx *wl) +{ + enable_irq(wl->irq); +} + +void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl) +{ + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); +} + +int wl12xx_boot_soft_reset(struct wl12xx *wl) +{ + unsigned long timeout; + u32 boot_data; + + /* perform soft reset */ + wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + + /* SOFT_RESET is self clearing */ + timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); + while (1) { + boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); + wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); + if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) + break; + + if (time_after(jiffies, timeout)) { + /* 1.2 check pWhalBus->uSelfClearTime if the + * timeout was reached */ + wl12xx_error("soft reset timeout"); + return -1; + } + + udelay(SOFT_RESET_STALL_TIME); + } + + /* disable Rx/Tx */ + wl12xx_reg_write32(wl, ENABLE, 0x0); + + /* disable auto calibration on start*/ + wl12xx_reg_write32(wl, SPARE_A2, 0xffff); + + return 0; +} + +int wl12xx_boot_init_seq(struct wl12xx *wl) +{ + u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; + + /* + * col #1: INTEGER_DIVIDER + * col #2: FRACTIONAL_DIVIDER + * col #3: ATTN_BB + * col #4: ALPHA_BB + * col #5: STOP_TIME_BB + * col #6: BB_PLL_LOOP_FILTER + */ + static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { + + { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ + { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ + { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ + { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ + { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ + }; + + /* read NVS params */ + scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6); + wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); + + /* read ELP_CMD */ + elp_cmd = wl12xx_reg_read32(wl, ELP_CMD); + wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); + + /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ + ref_freq = scr_pad6 & 0x000000FF; + wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); + + wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9); + + /* + * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) + */ + wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6); + + /* + * set the clock detect feature to work in the restart wu procedure + * (ELP_CFG_MODE[14]) and Select the clock source type + * (ELP_CFG_MODE[13:12]) + */ + tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; + wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp); + + /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ + elp_cmd |= 0x00000040; + wl12xx_reg_write32(wl, ELP_CMD, elp_cmd); + + /* PG 1.2: Set the BB PLL stable time to be 1000usec + * (PLL_STABLE_TIME) */ + wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); + + /* PG 1.2: read clock request time */ + init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME); + + /* + * PG 1.2: set the clock request time to be ref_clk_settling_time - + * 1ms = 4ms + */ + if (init_data > 0x21) + tmp = init_data - 0x21; + else + tmp = 0; + wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp); + + /* set BB PLL configurations in RF AFE */ + wl12xx_reg_write32(wl, 0x003058cc, 0x4B5); + + /* set RF_AFE_REG_5 */ + wl12xx_reg_write32(wl, 0x003058d4, 0x50); + + /* set RF_AFE_CTRL_REG_2 */ + wl12xx_reg_write32(wl, 0x00305948, 0x11c001); + + /* + * change RF PLL and BB PLL divider for VCO clock and adjust VCO + * bais current(RF_AFE_REG_13) + */ + wl12xx_reg_write32(wl, 0x003058f4, 0x1e); + + /* set BB PLL configurations */ + tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; + wl12xx_reg_write32(wl, 0x00305840, tmp); + + /* set fractional divider according to Appendix C-BB PLL + * Calculations + */ + tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; + wl12xx_reg_write32(wl, 0x00305844, tmp); + + /* set the initial data for the sigma delta */ + wl12xx_reg_write32(wl, 0x00305848, 0x3039); + + /* + * set the accumulator attenuation value, calibration loop1 + * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and + * the VCO gain + */ + tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | + (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; + wl12xx_reg_write32(wl, 0x00305854, tmp); + + /* + * set the calibration stop time after holdoff time expires and set + * settling time HOLD_OFF_TIME_BB + */ + tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; + wl12xx_reg_write32(wl, 0x00305858, tmp); + + /* + * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL + * constant leakage current to linearize PFD to 0uA - + * BB_ILOOPF[7:3] + */ + tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; + wl12xx_reg_write32(wl, 0x003058f8, tmp); + + /* + * set regulator output voltage for n divider to + * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], + * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB + * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] + */ + wl12xx_reg_write32(wl, 0x003058f0, 0x29); + + /* enable restart wakeup sequence (ELP_CMD[0]) */ + wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); + + /* restart sequence completed */ + udelay(2000); + + return 0; +} + +int wl12xx_boot_run_firmware(struct wl12xx *wl) +{ + int loop, ret; + u32 chip_id, interrupt; + + wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + + chip_id = wl12xx_reg_read32(wl, CHIP_ID_B); + + wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); + + if (chip_id != wl->chip.id) { + wl12xx_error("chip id doesn't match after firmware boot"); + return -EIO; + } + + /* wait for init to complete */ + loop = 0; + while (loop++ < INIT_LOOP) { + udelay(INIT_LOOP_DELAY); + interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + + if (interrupt == 0xffffffff) { + wl12xx_error("error reading hardware complete " + "init indication"); + return -EIO; + } + /* check that ACX_INTR_INIT_COMPLETE is enabled */ + else if (interrupt & wl->chip.intr_init_complete) { + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl->chip.intr_init_complete); + break; + } + } + + if (loop >= INIT_LOOP) { + wl12xx_error("timeout waiting for the hardware to " + "complete initialization"); + return -EIO; + } + + /* get hardware config command mail box */ + wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); + + /* get hardware config event mail box */ + wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + + /* set the working partition to its "running" mode offset */ + wl12xx_set_partition(wl, + wl->chip.p_table[PART_WORK].mem.start, + wl->chip.p_table[PART_WORK].mem.size, + wl->chip.p_table[PART_WORK].reg.start, + wl->chip.p_table[PART_WORK].reg.size); + + wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", + wl->cmd_box_addr, wl->event_box_addr); + + wl->chip.op_fw_version(wl); + + /* + * in case of full asynchronous mode the firmware event must be + * ready to receive event from the command mailbox + */ + + /* enable gpio interrupts */ + wl12xx_boot_enable_interrupts(wl); + + wl->chip.op_target_enable_interrupts(wl); + + /* unmask all mbox events */ + wl->event_mask = 0xffffffff; + + ret = wl12xx_event_unmask(wl); + if (ret < 0) { + wl12xx_error("EVENT mask setting failed"); + return ret; + } + + wl12xx_event_mbox_config(wl); + + /* firmware startup completed */ + return 0; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h new file mode 100644 index 0000000..4fa7313 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_boot.h @@ -0,0 +1,40 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __BOOT_H__ +#define __BOOT_H__ + +#include "wl12xx.h" + +int wl12xx_boot_soft_reset(struct wl12xx *wl); +int wl12xx_boot_init_seq(struct wl12xx *wl); +int wl12xx_boot_run_firmware(struct wl12xx *wl); +void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl); + +/* number of times we try to read the INIT interrupt */ +#define INIT_LOOP 20000 + +/* delay between retries */ +#define INIT_LOOP_DELAY 50 + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c new file mode 100644 index 0000000..d0c2df6 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -0,0 +1,429 @@ +#include "wl1251_cmd.h" + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251_spi.h" +#include "wl1251_ps.h" +#include "wl1251_acx.h" + +/** + * send command to firmware + * + * @wl: wl struct + * @id: command id + * @buf: buffer containing the command, must work with dma + * @len: length of the buffer + */ +int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) +{ + struct wl12xx_cmd_header *cmd; + unsigned long timeout; + u32 intr; + int ret = 0; + + cmd = buf; + cmd->id = id; + cmd->status = 0; + + WARN_ON(len % 4 != 0); + + wl12xx_spi_mem_write(wl, wl->cmd_box_addr, buf, len); + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + + timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + while (!(intr & wl->chip.intr_cmd_complete)) { + if (time_after(jiffies, timeout)) { + wl12xx_error("command complete timeout"); + ret = -ETIMEDOUT; + goto out; + } + + msleep(1); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + } + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl->chip.intr_cmd_complete); + +out: + return ret; +} + +/** + * send test command to firmware + * + * @wl: wl struct + * @buf: buffer containing the command, with all headers, must work with dma + * @len: length of the buffer + * @answer: is answer needed + */ +int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) +{ + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd test"); + + ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); + + if (ret < 0) { + wl12xx_warning("TEST command failed"); + return ret; + } + + if (answer) { + struct wl12xx_command *cmd_answer; + + /* + * The test command got in, we can read the answer. + * The answer would be a wl12xx_command, where the + * parameter array contains the actual answer. + */ + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + + cmd_answer = buf; + + if (cmd_answer->header.status != CMD_STATUS_SUCCESS) + wl12xx_error("TEST command answer error: %d", + cmd_answer->header.status); + } + + return 0; +} + +/** + * read acx from firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer for the response, including all headers, must work with dma + * @len: lenght of buf + */ +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd interrogate"); + + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_error("INTERROGATE command failed"); + goto out; + } + + /* the interrogate command got in, we can read the answer */ + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, len); + + acx = buf; + if (acx->cmd.status != CMD_STATUS_SUCCESS) + wl12xx_error("INTERROGATE command error: %d", + acx->cmd.status); + +out: + return ret; +} + +/** + * write acx value to firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer containing acx, including all headers, must work with dma + * @len: length of buf + */ +int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd configure"); + + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, acx, len); + if (ret < 0) { + wl12xx_warning("CONFIGURE command NOK"); + return ret; + } + + return 0; +} + +int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, + void *bitmap, u16 bitmap_len, u8 bitmap_control) +{ + struct wl12xx_cmd_vbm_update *vbm; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd vbm"); + + vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); + if (!vbm) { + ret = -ENOMEM; + goto out; + } + + /* Count and period will be filled by the target */ + vbm->tim.bitmap_ctrl = bitmap_control; + if (bitmap_len > PARTIAL_VBM_MAX) { + wl12xx_warning("cmd vbm len is %d B, truncating to %d", + bitmap_len, PARTIAL_VBM_MAX); + bitmap_len = PARTIAL_VBM_MAX; + } + memcpy(vbm->tim.pvb_field, bitmap, bitmap_len); + vbm->tim.identity = identity; + vbm->tim.length = bitmap_len + 3; + + vbm->len = cpu_to_le16(bitmap_len + 5); + + ret = wl12xx_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); + if (ret < 0) { + wl12xx_error("VBM command failed"); + goto out; + } + +out: + kfree(vbm); + return 0; +} + +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable) +{ + struct cmd_enabledisable_path *cmd; + int ret; + u16 cmd_rx, cmd_tx; + + wl12xx_debug(DEBUG_CMD, "cmd data path"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->channel = channel; + + if (enable) { + cmd_rx = CMD_ENABLE_RX; + cmd_tx = CMD_ENABLE_TX; + } else { + cmd_rx = CMD_DISABLE_RX; + cmd_tx = CMD_DISABLE_TX; + } + + ret = wl12xx_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); + if (ret < 0) { + wl12xx_error("rx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + goto out; + } + + wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d", + enable ? "start" : "stop", channel); + + ret = wl12xx_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); + if (ret < 0) { + wl12xx_error("tx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + return ret; + } + + wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d", + enable ? "start" : "stop", channel); + +out: + kfree(cmd); + return ret; +} + +int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait) +{ + unsigned long timeout; + struct cmd_join *join; + int ret, i; + u8 *bssid; + + join = kzalloc(sizeof(*join), GFP_KERNEL); + if (!join) { + ret = -ENOMEM; + goto out; + } + + /* FIXME: this should be in main.c */ + ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, + DEFAULT_HW_GEN_MODULATION_TYPE, + wl->tx_mgmt_frm_rate, + wl->tx_mgmt_frm_mod); + if (ret < 0) + goto out; + + wl12xx_debug(DEBUG_CMD, "cmd join"); + + /* Reverse order BSSID */ + bssid = (u8 *) &join->bssid_lsb; + for (i = 0; i < ETH_ALEN; i++) + bssid[i] = wl->bssid[ETH_ALEN - i - 1]; + + join->rx_config_options = wl->rx_config; + join->rx_filter_options = wl->rx_filter; + + join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | + RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; + + join->beacon_interval = beacon_interval; + join->dtim_interval = dtim_interval; + join->bss_type = bss_type; + join->channel = wl->channel; + join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; + + ret = wl12xx_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); + if (ret < 0) { + wl12xx_error("failed to initiate cmd join"); + goto out; + } + + timeout = msecs_to_jiffies(JOIN_TIMEOUT); + + /* + * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to + * simplify locking we just sleep instead, for now + */ + if (wait) + msleep(10); + +out: + kfree(join); + return ret; +} + +int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) +{ + struct wl12xx_cmd_ps_params *ps_params = NULL; + int ret = 0; + + /* FIXME: this should be in ps.c */ + ret = wl12xx_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); + if (ret < 0) { + wl12xx_error("couldn't set wake up conditions"); + goto out; + } + + wl12xx_debug(DEBUG_CMD, "cmd set ps mode"); + + ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); + if (!ps_params) { + ret = -ENOMEM; + goto out; + } + + ps_params->ps_mode = ps_mode; + ps_params->send_null_data = 1; + ps_params->retries = 5; + ps_params->hang_over_period = 128; + ps_params->null_data_rate = 1; /* 1 Mbps */ + + ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, ps_params, + sizeof(*ps_params)); + if (ret < 0) { + wl12xx_error("cmd set_ps_mode failed"); + goto out; + } + +out: + kfree(ps_params); + return ret; +} + +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, + size_t len) +{ + struct cmd_read_write_memory *cmd; + int ret = 0; + + wl12xx_debug(DEBUG_CMD, "cmd read memory"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + WARN_ON(len > MAX_READ_SIZE); + len = min_t(size_t, len, MAX_READ_SIZE); + + cmd->addr = addr; + cmd->size = len; + + ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); + if (ret < 0) { + wl12xx_error("read memory command failed: %d", ret); + goto out; + } + + /* the read command got in, we can now read the answer */ + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + + if (cmd->header.status != CMD_STATUS_SUCCESS) + wl12xx_error("error in read command result: %d", + cmd->header.status); + + memcpy(answer, cmd->value, len); + +out: + kfree(cmd); + return ret; +} + +int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, + void *buf, size_t buf_len) +{ + struct wl12xx_cmd_packet_template *cmd; + size_t cmd_len; + int ret = 0; + + wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id); + + WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE); + buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE); + cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); + + cmd = kzalloc(cmd_len, GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->size = cpu_to_le16(buf_len); + + if (buf) + memcpy(cmd->data, buf, buf_len); + + ret = wl12xx_cmd_send(wl, cmd_id, cmd, cmd_len); + if (ret < 0) { + wl12xx_warning("cmd set_template failed: %d", ret); + goto out; + } + +out: + kfree(cmd); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h new file mode 100644 index 0000000..a2eae54 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -0,0 +1,407 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_CMD_H__ +#define __WL12XX_CMD_H__ + +#include "wl12xx.h" + +struct acx_header; + +int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len); +int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer); +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len); +int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len); +int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, + void *bitmap, u16 bitmap_len, u8 bitmap_control); +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable); +int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait); +int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, + size_t len); +int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, + void *buf, size_t buf_len); + +/* unit ms */ +#define WL12XX_COMMAND_TIMEOUT 2000 + +enum wl12xx_commands { + CMD_RESET = 0, + CMD_INTERROGATE = 1, /*use this to read information elements*/ + CMD_CONFIGURE = 2, /*use this to write information elements*/ + CMD_ENABLE_RX = 3, + CMD_ENABLE_TX = 4, + CMD_DISABLE_RX = 5, + CMD_DISABLE_TX = 6, + CMD_SCAN = 8, + CMD_STOP_SCAN = 9, + CMD_VBM = 10, + CMD_START_JOIN = 11, + CMD_SET_KEYS = 12, + CMD_READ_MEMORY = 13, + CMD_WRITE_MEMORY = 14, + CMD_BEACON = 19, + CMD_PROBE_RESP = 20, + CMD_NULL_DATA = 21, + CMD_PROBE_REQ = 22, + CMD_TEST = 23, + CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ + CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ + CMD_NOISE_HIST = 28, + CMD_RX_RESET = 29, + CMD_PS_POLL = 30, + CMD_QOS_NULL_DATA = 31, + CMD_LNA_CONTROL = 32, + CMD_SET_BCN_MODE = 33, + CMD_MEASUREMENT = 34, + CMD_STOP_MEASUREMENT = 35, + CMD_DISCONNECT = 36, + CMD_SET_PS_MODE = 37, + CMD_CHANNEL_SWITCH = 38, + CMD_STOP_CHANNEL_SWICTH = 39, + CMD_AP_DISCOVERY = 40, + CMD_STOP_AP_DISCOVERY = 41, + CMD_SPS_SCAN = 42, + CMD_STOP_SPS_SCAN = 43, + CMD_HEALTH_CHECK = 45, + CMD_DEBUG = 46, + CMD_TRIGGER_SCAN_TO = 47, + + NUM_COMMANDS, + MAX_COMMAND_ID = 0xFFFF, +}; + +#define MAX_CMD_PARAMS 572 + +struct wl12xx_cmd_header { + u16 id; + u16 status; + /* payload */ + u8 data[0]; +} __attribute__ ((packed)); + +struct wl12xx_command { + struct wl12xx_cmd_header header; + u8 parameters[MAX_CMD_PARAMS]; +}; + +enum { + CMD_MAILBOX_IDLE = 0, + CMD_STATUS_SUCCESS = 1, + CMD_STATUS_UNKNOWN_CMD = 2, + CMD_STATUS_UNKNOWN_IE = 3, + CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, + CMD_STATUS_RX_BUSY = 13, + CMD_STATUS_INVALID_PARAM = 14, + CMD_STATUS_TEMPLATE_TOO_LARGE = 15, + CMD_STATUS_OUT_OF_MEMORY = 16, + CMD_STATUS_STA_TABLE_FULL = 17, + CMD_STATUS_RADIO_ERROR = 18, + CMD_STATUS_WRONG_NESTING = 19, + CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ + CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ + MAX_COMMAND_STATUS = 0xff +}; + + +/* + * CMD_READ_MEMORY + * + * The host issues this command to read the WiLink device memory/registers. + * + * Note: The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +/* + * CMD_WRITE_MEMORY + * + * The host issues this command to write the WiLink device memory/registers. + * + * The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +#define MAX_READ_SIZE 256 + +struct cmd_read_write_memory { + struct wl12xx_cmd_header header; + + /* The address of the memory to read from or write to.*/ + u32 addr; + + /* The amount of data in bytes to read from or write to the WiLink + * device.*/ + u32 size; + + /* The actual value read from or written to the Wilink. The source + of this field is the Host in WRITE command or the Wilink in READ + command. */ + u8 value[MAX_READ_SIZE]; +}; + +#define CMDMBOX_HEADER_LEN 4 +#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 + + +struct basic_scan_parameters { + u32 rx_config_options; + u32 rx_filter_options; + + /* + * Scan options: + * bit 0: When this bit is set, passive scan. + * bit 1: Band, when this bit is set we scan + * in the 5Ghz band. + * bit 2: voice mode, 0 for normal scan. + * bit 3: scan priority, 1 for high priority. + */ + u16 scan_options; + + /* Number of channels to scan */ + u8 num_channels; + + /* Number opf probe requests to send, per channel */ + u8 num_probe_requests; + + /* Rate and modulation for probe requests */ + u16 tx_rate; + + u8 tid_trigger; + u8 ssid_len; + u32 ssid[8]; + +} __attribute__ ((packed)); + +struct basic_scan_channel_parameters { + u32 min_duration; /* in TU */ + u32 max_duration; /* in TU */ + u32 bssid_lsb; + u16 bssid_msb; + + /* + * bits 0-3: Early termination count. + * bits 4-5: Early termination condition. + */ + u8 early_termination; + + u8 tx_power_att; + u8 channel; + u8 pad[3]; +} __attribute__ ((packed)); + +/* SCAN parameters */ +#define SCAN_MAX_NUM_OF_CHANNELS 16 + +struct cmd_scan { + struct wl12xx_cmd_header header; + + struct basic_scan_parameters params; + struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; +} __attribute__ ((packed)); + +enum { + BSS_TYPE_IBSS = 0, + BSS_TYPE_STA_BSS = 2, + BSS_TYPE_AP_BSS = 3, + MAX_BSS_TYPE = 0xFF +}; + +#define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ +#define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ + + +struct cmd_join { + struct wl12xx_cmd_header header; + + u32 bssid_lsb; + u16 bssid_msb; + u16 beacon_interval; /* in TBTTs */ + u32 rx_config_options; + u32 rx_filter_options; + + /* + * The target uses this field to determine the rate at + * which to transmit control frame responses (such as + * ACK or CTS frames). + */ + u16 basic_rate_set; + u8 dtim_interval; + u8 tx_ctrl_frame_rate; /* OBSOLETE */ + u8 tx_ctrl_frame_mod; /* OBSOLETE */ + /* + * bits 0-2: This bitwise field specifies the type + * of BSS to start or join (BSS_TYPE_*). + * bit 4: Band - The radio band in which to join + * or start. + * 0 - 2.4GHz band + * 1 - 5GHz band + * bits 3, 5-7: Reserved + */ + u8 bss_type; + u8 channel; + u8 ssid_len; + u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ctrl; /* JOIN_CMD_CTRL_* */ + u8 tx_mgt_frame_rate; /* OBSOLETE */ + u8 tx_mgt_frame_mod; /* OBSOLETE */ + u8 reserved; +} __attribute__ ((packed)); + +struct cmd_enabledisable_path { + struct wl12xx_cmd_header header; + + u8 channel; + u8 padding[3]; +} __attribute__ ((packed)); + +#define WL12XX_MAX_TEMPLATE_SIZE 300 + +struct wl12xx_cmd_packet_template { + struct wl12xx_cmd_header header; + + __le16 size; + u8 data[0]; +} __attribute__ ((packed)); + +#define TIM_ELE_ID 5 +#define PARTIAL_VBM_MAX 251 + +struct wl12xx_tim { + u8 identity; + u8 length; + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ +} __attribute__ ((packed)); + +/* Virtual Bit Map update */ +struct wl12xx_cmd_vbm_update { + struct wl12xx_cmd_header header; + __le16 len; + u8 padding[2]; + struct wl12xx_tim tim; +} __attribute__ ((packed)); + +enum wl12xx_cmd_ps_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct wl12xx_cmd_ps_params { + struct wl12xx_cmd_header header; + + u8 ps_mode; /* STATION_* */ + u8 send_null_data; /* Do we have to send NULL data packet ? */ + u8 retries; /* Number of retires for the initial NULL data packet */ + + /* + * TUs during which the target stays awake after switching + * to power save mode. + */ + u8 hang_over_period; + u16 null_data_rate; + u8 pad[2]; +} __attribute__ ((packed)); + +struct wl12xx_cmd_trigger_scan_to { + struct wl12xx_cmd_header header; + + u32 timeout; +}; + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 +#define MAX_KEY_SIZE 32 + +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +/* When set, disable HW decryption */ +#define DF_SNIFF_MODE_ENABLE 0x80 + +enum wl12xx_cmd_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum wl12xx_cmd_key_type { + KEY_WEP_DEFAULT = 0, + KEY_WEP_ADDR = 1, + KEY_AES_GROUP = 4, + KEY_AES_PAIRWISE = 5, + KEY_WEP_GROUP = 6, + KEY_TKIP_MIC_GROUP = 10, + KEY_TKIP_MIC_PAIRWISE = 11, +}; + +/* + * + * key_type_e key size key format + * ---------- --------- ---------- + * 0x00 5, 13, 29 Key data + * 0x01 5, 13, 29 Key data + * 0x04 16 16 bytes of key data + * 0x05 16 16 bytes of key data + * 0x0a 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * 0x0b 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * + */ + +struct wl12xx_cmd_set_keys { + struct wl12xx_cmd_header header; + + /* Ignored for default WEP key */ + u8 addr[ETH_ALEN]; + + /* key_action_e */ + u16 key_action; + + u16 reserved_1; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + u8 ssid_profile; + + /* + * TKIP, AES: frame's key id field. + * For WEP default key: key id; + */ + u8 id; + u8 reserved_2[6]; + u8 key[MAX_KEY_SIZE]; + u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __attribute__ ((packed)); + + +#endif /* __WL12XX_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c new file mode 100644 index 0000000..a63bc78 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -0,0 +1,518 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1251_debugfs.h" + +#include + +#include "wl12xx.h" +#include "wl1251_acx.h" +#include "wl1251_ps.h" + +/* ms */ +#define WL12XX_DEBUGFS_STATS_LIFETIME 1000 + +/* debugfs macros idea from mac80211 */ + +#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ +static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl12xx *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + res = scnprintf(buf, buflen, fmt "\n", ##value); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = wl12xx_open_file_generic, \ +}; + +#define DEBUGFS_ADD(name, parent) \ + wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ + wl, &name## _ops); \ + if (IS_ERR(wl->debugfs.name)) { \ + ret = PTR_ERR(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + goto out; \ + } + +#define DEBUGFS_DEL(name) \ + do { \ + debugfs_remove(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + } while (0) + +#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ +static ssize_t sub## _ ##name## _read(struct file *file, \ + char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl12xx *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + wl12xx_debugfs_update_stats(wl); \ + \ + res = scnprintf(buf, buflen, fmt "\n", \ + wl->stats.fw_stats->sub.name); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations sub## _ ##name## _ops = { \ + .read = sub## _ ##name## _read, \ + .open = wl12xx_open_file_generic, \ +}; + +#define DEBUGFS_FWSTATS_ADD(sub, name) \ + DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) + +#define DEBUGFS_FWSTATS_DEL(sub, name) \ + DEBUGFS_DEL(sub## _ ##name) + +static void wl12xx_debugfs_update_stats(struct wl12xx *wl) +{ + int ret; + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (wl->state == WL12XX_STATE_ON && + time_after(jiffies, wl->stats.fw_stats_update + + msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) { + wl12xx_acx_statistics(wl, wl->stats.fw_stats); + wl->stats.fw_stats_update = jiffies; + } + + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl12xx_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); +/* skipping wep.reserved */ +DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); +/* skipping cont_miss_bcns_spread for now */ +DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, + 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); + +DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); +DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", + wl->stats.excessive_retries); + +static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl12xx *wl = file->private_data; + u32 queue_len; + char buf[20]; + int res; + + queue_len = skb_queue_len(&wl->tx_queue); + + res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +static const struct file_operations tx_queue_len_ops = { + .read = tx_queue_len_read, + .open = wl12xx_open_file_generic, +}; + +static void wl12xx_debugfs_delete_files(struct wl12xx *wl) +{ + DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_DEL(rx, out_of_mem); + DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); + DEBUGFS_FWSTATS_DEL(rx, hw_stuck); + DEBUGFS_FWSTATS_DEL(rx, dropped); + DEBUGFS_FWSTATS_DEL(rx, fcs_err); + DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_DEL(rx, path_reset); + DEBUGFS_FWSTATS_DEL(rx, reset_counter); + + DEBUGFS_FWSTATS_DEL(dma, rx_requested); + DEBUGFS_FWSTATS_DEL(dma, rx_errors); + DEBUGFS_FWSTATS_DEL(dma, tx_requested); + DEBUGFS_FWSTATS_DEL(dma, tx_errors); + + DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); + DEBUGFS_FWSTATS_DEL(isr, fiqs); + DEBUGFS_FWSTATS_DEL(isr, rx_headers); + DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_DEL(isr, rx_rdys); + DEBUGFS_FWSTATS_DEL(isr, irqs); + DEBUGFS_FWSTATS_DEL(isr, tx_procs); + DEBUGFS_FWSTATS_DEL(isr, decrypt_done); + DEBUGFS_FWSTATS_DEL(isr, dma0_done); + DEBUGFS_FWSTATS_DEL(isr, dma1_done); + DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); + DEBUGFS_FWSTATS_DEL(isr, commands); + DEBUGFS_FWSTATS_DEL(isr, rx_procs); + DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); + DEBUGFS_FWSTATS_DEL(isr, pci_pm); + DEBUGFS_FWSTATS_DEL(isr, wakeups); + DEBUGFS_FWSTATS_DEL(isr, low_rssi); + + DEBUGFS_FWSTATS_DEL(wep, addr_key_count); + DEBUGFS_FWSTATS_DEL(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_DEL(wep, key_not_found); + DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); + DEBUGFS_FWSTATS_DEL(wep, packets); + DEBUGFS_FWSTATS_DEL(wep, interrupt); + + DEBUGFS_FWSTATS_DEL(pwr, ps_enter); + DEBUGFS_FWSTATS_DEL(pwr, elp_enter); + DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); + DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); + DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_DEL(pwr, power_save_off); + DEBUGFS_FWSTATS_DEL(pwr, enable_ps); + DEBUGFS_FWSTATS_DEL(pwr, disable_ps); + DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_DEL(mic, rx_pkts); + DEBUGFS_FWSTATS_DEL(mic, calc_failure); + + DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_DEL(event, heart_beat); + DEBUGFS_FWSTATS_DEL(event, calibration); + DEBUGFS_FWSTATS_DEL(event, rx_mismatch); + DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); + DEBUGFS_FWSTATS_DEL(event, rx_pool); + DEBUGFS_FWSTATS_DEL(event, oom_late); + DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); + DEBUGFS_FWSTATS_DEL(event, tx_stuck); + + DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); + DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); + + DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_DEL(tx_queue_len); + DEBUGFS_DEL(retry_count); + DEBUGFS_DEL(excessive_retries); +} + +static int wl12xx_debugfs_add_files(struct wl12xx *wl) +{ + int ret = 0; + + DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_ADD(rx, out_of_mem); + DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); + DEBUGFS_FWSTATS_ADD(rx, hw_stuck); + DEBUGFS_FWSTATS_ADD(rx, dropped); + DEBUGFS_FWSTATS_ADD(rx, fcs_err); + DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_ADD(rx, path_reset); + DEBUGFS_FWSTATS_ADD(rx, reset_counter); + + DEBUGFS_FWSTATS_ADD(dma, rx_requested); + DEBUGFS_FWSTATS_ADD(dma, rx_errors); + DEBUGFS_FWSTATS_ADD(dma, tx_requested); + DEBUGFS_FWSTATS_ADD(dma, tx_errors); + + DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); + DEBUGFS_FWSTATS_ADD(isr, fiqs); + DEBUGFS_FWSTATS_ADD(isr, rx_headers); + DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_ADD(isr, rx_rdys); + DEBUGFS_FWSTATS_ADD(isr, irqs); + DEBUGFS_FWSTATS_ADD(isr, tx_procs); + DEBUGFS_FWSTATS_ADD(isr, decrypt_done); + DEBUGFS_FWSTATS_ADD(isr, dma0_done); + DEBUGFS_FWSTATS_ADD(isr, dma1_done); + DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); + DEBUGFS_FWSTATS_ADD(isr, commands); + DEBUGFS_FWSTATS_ADD(isr, rx_procs); + DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); + DEBUGFS_FWSTATS_ADD(isr, pci_pm); + DEBUGFS_FWSTATS_ADD(isr, wakeups); + DEBUGFS_FWSTATS_ADD(isr, low_rssi); + + DEBUGFS_FWSTATS_ADD(wep, addr_key_count); + DEBUGFS_FWSTATS_ADD(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_ADD(wep, key_not_found); + DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); + DEBUGFS_FWSTATS_ADD(wep, packets); + DEBUGFS_FWSTATS_ADD(wep, interrupt); + + DEBUGFS_FWSTATS_ADD(pwr, ps_enter); + DEBUGFS_FWSTATS_ADD(pwr, elp_enter); + DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); + DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); + DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_ADD(pwr, power_save_off); + DEBUGFS_FWSTATS_ADD(pwr, enable_ps); + DEBUGFS_FWSTATS_ADD(pwr, disable_ps); + DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_ADD(mic, rx_pkts); + DEBUGFS_FWSTATS_ADD(mic, calc_failure); + + DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_ADD(event, heart_beat); + DEBUGFS_FWSTATS_ADD(event, calibration); + DEBUGFS_FWSTATS_ADD(event, rx_mismatch); + DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); + DEBUGFS_FWSTATS_ADD(event, rx_pool); + DEBUGFS_FWSTATS_ADD(event, oom_late); + DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); + DEBUGFS_FWSTATS_ADD(event, tx_stuck); + + DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); + DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); + + DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); + DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); + DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); + +out: + if (ret < 0) + wl12xx_debugfs_delete_files(wl); + + return ret; +} + +void wl12xx_debugfs_reset(struct wl12xx *wl) +{ + memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); + wl->stats.retry_count = 0; + wl->stats.excessive_retries = 0; +} + +int wl12xx_debugfs_init(struct wl12xx *wl) +{ + int ret; + + wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + if (IS_ERR(wl->debugfs.rootdir)) { + ret = PTR_ERR(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + goto err; + } + + wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", + wl->debugfs.rootdir); + + if (IS_ERR(wl->debugfs.fw_statistics)) { + ret = PTR_ERR(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + goto err_root; + } + + wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), + GFP_KERNEL); + + if (!wl->stats.fw_stats) { + ret = -ENOMEM; + goto err_fw; + } + + wl->stats.fw_stats_update = jiffies; + + ret = wl12xx_debugfs_add_files(wl); + + if (ret < 0) + goto err_file; + + return 0; + +err_file: + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + +err_fw: + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + +err_root: + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +err: + return ret; +} + +void wl12xx_debugfs_exit(struct wl12xx *wl) +{ + wl12xx_debugfs_delete_files(wl); + + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +} diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h new file mode 100644 index 0000000..562cdcb --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.h @@ -0,0 +1,33 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef WL12XX_DEBUGFS_H +#define WL12XX_DEBUGFS_H + +#include "wl12xx.h" + +int wl12xx_debugfs_init(struct wl12xx *wl); +void wl12xx_debugfs_exit(struct wl12xx *wl); +void wl12xx_debugfs_reset(struct wl12xx *wl); + +#endif /* WL12XX_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c new file mode 100644 index 0000000..50b5e43 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -0,0 +1,127 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl12xx.h" +#include "reg.h" +#include "wl1251_spi.h" +#include "wl1251_event.h" +#include "wl1251_ps.h" + +static int wl12xx_event_scan_complete(struct wl12xx *wl, + struct event_mailbox *mbox) +{ + wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", + mbox->scheduled_scan_status, + mbox->scheduled_scan_channels); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, false); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + return 0; +} + +static void wl12xx_event_mbox_dump(struct event_mailbox *mbox) +{ + wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:"); + wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); + wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); +} + +static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox) +{ + int ret; + u32 vector; + + wl12xx_event_mbox_dump(mbox); + + vector = mbox->events_vector & ~(mbox->events_mask); + wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector); + + if (vector & SCAN_COMPLETE_EVENT_ID) { + ret = wl12xx_event_scan_complete(wl, mbox); + if (ret < 0) + return ret; + } + + if (vector & BSS_LOSE_EVENT_ID) { + wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); + + if (wl->psm_requested && wl->psm) { + ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + } + } + + return 0; +} + +int wl12xx_event_unmask(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask)); + if (ret < 0) + return ret; + + return 0; +} + +void wl12xx_event_mbox_config(struct wl12xx *wl) +{ + wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); + + wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", + wl->mbox_ptr[0], wl->mbox_ptr[1]); +} + +int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num) +{ + struct event_mailbox mbox; + int ret; + + wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); + + if (mbox_num > 1) + return -EINVAL; + + /* first we read the mbox descriptor */ + wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, + sizeof(struct event_mailbox)); + + /* process the descriptor */ + ret = wl12xx_event_process(wl, &mbox); + if (ret < 0) + return ret; + + /* then we let the firmware know it can go on...*/ + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl12xx/wl1251_event.h new file mode 100644 index 0000000..1f4c2f7 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_event.h @@ -0,0 +1,121 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_EVENT_H__ +#define __WL12XX_EVENT_H__ + +/* + * Mbox events + * + * The event mechanism is based on a pair of event buffers (buffers A and + * B) at fixed locations in the target's memory. The host processes one + * buffer while the other buffer continues to collect events. If the host + * is not processing events, an interrupt is issued to signal that a buffer + * is ready. Once the host is done with processing events from one buffer, + * it signals the target (with an ACK interrupt) that the event buffer is + * free. + */ + +enum { + RESERVED1_EVENT_ID = BIT(0), + RESERVED2_EVENT_ID = BIT(1), + MEASUREMENT_START_EVENT_ID = BIT(2), + SCAN_COMPLETE_EVENT_ID = BIT(3), + CALIBRATION_COMPLETE_EVENT_ID = BIT(4), + ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), + PS_REPORT_EVENT_ID = BIT(6), + SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), + HEALTH_REPORT_EVENT_ID = BIT(8), + ACI_DETECTION_EVENT_ID = BIT(9), + DEBUG_REPORT_EVENT_ID = BIT(10), + MAC_STATUS_EVENT_ID = BIT(11), + DISCONNECT_EVENT_COMPLETE_ID = BIT(12), + JOIN_EVENT_COMPLETE_ID = BIT(13), + CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), + BSS_LOSE_EVENT_ID = BIT(15), + ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), + MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), + AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), + SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), + PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), + RESET_BSS_EVENT_ID = BIT(21), + REGAINED_BSS_EVENT_ID = BIT(22), + ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), + ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), + ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), + + DBG_EVENT_ID = BIT(26), + BT_PTA_SENSE_EVENT_ID = BIT(27), + BT_PTA_PREDICTION_EVENT_ID = BIT(28), + BT_PTA_AVALANCHE_EVENT_ID = BIT(29), + + PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), + + EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, +}; + +struct event_debug_report { + u8 debug_event_id; + u8 num_params; + u16 pad; + u32 report_1; + u32 report_2; + u32 report_3; +} __attribute__ ((packed)); + +struct event_mailbox { + u32 events_vector; + u32 events_mask; + u32 reserved_1; + u32 reserved_2; + + char average_rssi_level; + u8 ps_status; + u8 channel_switch_status; + u8 scheduled_scan_status; + + /* Channels scanned by the scheduled scan */ + u16 scheduled_scan_channels; + + /* If bit 0 is set -> target's fatal error */ + u16 health_report; + u16 bad_fft_counter; + u8 bt_pta_sense_info; + u8 bt_pta_protective_info; + u32 reserved; + u32 debug_report[2]; + + /* Number of FCS errors since last event */ + u32 fcs_err_counter; + + struct event_debug_report report; + u8 average_snr_level; + u8 padding[19]; +} __attribute__ ((packed)); + +int wl12xx_event_unmask(struct wl12xx *wl); +void wl12xx_event_mbox_config(struct wl12xx *wl); +int wl12xx_event_handle(struct wl12xx *wl, u8 mbox); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c new file mode 100644 index 0000000..0929461 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -0,0 +1,200 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl1251_init.h" +#include "wl12xx_80211.h" +#include "wl1251_acx.h" +#include "wl1251_cmd.h" + +int wl12xx_hw_init_hwenc_config(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_feature_cfg(wl); + if (ret < 0) { + wl12xx_warning("couldn't set feature config"); + return ret; + } + + ret = wl12xx_acx_default_key(wl, wl->default_key); + if (ret < 0) { + wl12xx_warning("couldn't set default key"); + return ret; + } + + return 0; +} + +int wl12xx_hw_init_templates_config(struct wl12xx *wl) +{ + int ret; + u8 partial_vbm[PARTIAL_VBM_MAX]; + + /* send empty templates for fw memory reservation */ + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL, + sizeof(struct wl12xx_probe_req_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL, + sizeof(struct wl12xx_null_data_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL, + sizeof(struct wl12xx_ps_poll_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, + sizeof + (struct wl12xx_qos_null_data_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL, + sizeof + (struct wl12xx_probe_resp_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL, + sizeof + (struct wl12xx_beacon_template)); + if (ret < 0) + return ret; + + /* tim templates, first reserve space then allocate an empty one */ + memset(partial_vbm, 0, PARTIAL_VBM_MAX); + ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter) +{ + int ret; + + ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); + if (ret < 0) + return ret; + + ret = wl12xx_acx_rx_config(wl, config, filter); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_phy_config(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_pd_threshold(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME); + if (ret < 0) + return ret; + + ret = wl12xx_acx_group_address_tbl(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_service_period_timeout(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_beacon_filter(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_beacon_filter_opt(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_beacon_filter_table(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_pta(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_sg_enable(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_sg_cfg(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_energy_detection(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_cca_threshold(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_bcn_dtim_options(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_power_auth(struct wl12xx *wl) +{ + return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); +} diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h new file mode 100644 index 0000000..c8b6cd0 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -0,0 +1,40 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_INIT_H__ +#define __WL12XX_INIT_H__ + +#include "wl12xx.h" + +int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); +int wl12xx_hw_init_templates_config(struct wl12xx *wl); +int wl12xx_hw_init_mem_config(struct wl12xx *wl); +int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter); +int wl12xx_hw_init_phy_config(struct wl12xx *wl); +int wl12xx_hw_init_beacon_filter(struct wl12xx *wl); +int wl12xx_hw_init_pta(struct wl12xx *wl); +int wl12xx_hw_init_energy_detection(struct wl12xx *wl); +int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl); +int wl12xx_hw_init_power_auth(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c new file mode 100644 index 0000000..16cd46c --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -0,0 +1,1442 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251_ops.h" +#include "wl1251_spi.h" +#include "wl1251_event.h" +#include "wl1251_tx.h" +#include "wl1251_rx.h" +#include "wl1251_ps.h" +#include "wl1251_init.h" +#include "wl1251_debugfs.h" + +static void wl12xx_disable_interrupts(struct wl12xx *wl) +{ + disable_irq(wl->irq); +} + +static void wl12xx_power_off(struct wl12xx *wl) +{ + wl->set_power(false); +} + +static void wl12xx_power_on(struct wl12xx *wl) +{ + wl->set_power(true); +} + +static irqreturn_t wl12xx_irq(int irq, void *cookie) +{ + struct wl12xx *wl; + + wl12xx_debug(DEBUG_IRQ, "IRQ"); + + wl = cookie; + + schedule_work(&wl->irq_work); + + return IRQ_HANDLED; +} + +static int wl12xx_fetch_firmware(struct wl12xx *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); + + if (ret < 0) { + wl12xx_error("could not get firmware: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl12xx_error("firmware size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->fw_len = fw->size; + wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); + + if (!wl->fw) { + wl12xx_error("could not allocate memory for the firmware"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->fw, fw->data, wl->fw_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static int wl12xx_fetch_nvs(struct wl12xx *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); + + if (ret < 0) { + wl12xx_error("could not get nvs file: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl12xx_error("nvs size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->nvs_len = fw->size; + wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); + + if (!wl->nvs) { + wl12xx_error("could not allocate memory for the nvs file"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->nvs, fw->data, wl->nvs_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static void wl12xx_fw_wakeup(struct wl12xx *wl) +{ + u32 elp_reg; + + elp_reg = ELPCTRL_WAKE_UP; + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + + if (!(elp_reg & ELPCTRL_WLAN_READY)) { + wl12xx_warning("WLAN not ready"); + } +} + +static int wl12xx_chip_wakeup(struct wl12xx *wl) +{ + int ret = 0; + + wl12xx_power_on(wl); + msleep(wl->chip.power_on_sleep); + wl12xx_spi_reset(wl); + wl12xx_spi_init(wl); + + /* We don't need a real memory partition here, because we only want + * to use the registers at this point. */ + wl12xx_set_partition(wl, + 0x00000000, + 0x00000000, + REGISTERS_BASE, + REGISTERS_DOWN_SIZE); + + /* ELP module wake up */ + wl12xx_fw_wakeup(wl); + + /* whal_FwCtrl_BootSm() */ + + /* 0. read chip id from CHIP_ID */ + wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B); + + /* 1. check if chip id is valid */ + + switch (wl->chip.id) { + case CHIP_ID_1251_PG12: + wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", + wl->chip.id); + + wl1251_setup(wl); + + break; + case CHIP_ID_1251_PG10: + case CHIP_ID_1251_PG11: + default: + wl12xx_error("unsupported chip id: 0x%x", wl->chip.id); + ret = -ENODEV; + goto out; + } + + if (wl->fw == NULL) { + ret = wl12xx_fetch_firmware(wl); + if (ret < 0) + goto out; + } + + /* No NVS from netlink, try to get it from the filesystem */ + if (wl->nvs == NULL) { + ret = wl12xx_fetch_nvs(wl); + if (ret < 0) + goto out; + } + +out: + return ret; +} + +static void wl12xx_filter_work(struct work_struct *work) +{ + struct wl12xx *wl = + container_of(work, struct wl12xx, filter_work); + int ret; + + mutex_lock(&wl->mutex); + + if (wl->state == WL12XX_STATE_OFF) + goto out; + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* FIXME: replace the magic numbers with proper definitions */ + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +int wl12xx_plt_start(struct wl12xx *wl) +{ + int ret; + + wl12xx_notice("power up"); + + if (wl->state != WL12XX_STATE_OFF) { + wl12xx_error("cannot go into PLT state because not " + "in off state: %d", wl->state); + return -EBUSY; + } + + wl->state = WL12XX_STATE_PLT; + + ret = wl12xx_chip_wakeup(wl); + if (ret < 0) + return ret; + + ret = wl->chip.op_boot(wl); + if (ret < 0) + return ret; + + wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); + + ret = wl->chip.op_plt_init(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_plt_stop(struct wl12xx *wl) +{ + wl12xx_notice("power down"); + + if (wl->state != WL12XX_STATE_PLT) { + wl12xx_error("cannot power down because not in PLT " + "state: %d", wl->state); + return -EBUSY; + } + + wl12xx_disable_interrupts(wl); + wl12xx_power_off(wl); + + wl->state = WL12XX_STATE_OFF; + + return 0; +} + + +static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct wl12xx *wl = hw->priv; + + skb_queue_tail(&wl->tx_queue, skb); + + /* + * The chip specific setup must run before the first TX packet - + * before that, the tx_work will not be initialized! + */ + + schedule_work(&wl->tx_work); + + /* + * The workqueue is slow to process the tx_queue and we need stop + * the queue here, otherwise the queue will get too long. + */ + if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) { + ieee80211_stop_queues(wl->hw); + + /* + * FIXME: this is racy, the variable is not properly + * protected. Maybe fix this by removing the stupid + * variable altogether and checking the real queue state? + */ + wl->tx_queue_stopped = true; + } + + return NETDEV_TX_OK; +} + +static int wl12xx_op_start(struct ieee80211_hw *hw) +{ + struct wl12xx *wl = hw->priv; + int ret = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 start"); + + mutex_lock(&wl->mutex); + + if (wl->state != WL12XX_STATE_OFF) { + wl12xx_error("cannot start because not in off state: %d", + wl->state); + ret = -EBUSY; + goto out; + } + + ret = wl12xx_chip_wakeup(wl); + if (ret < 0) + return ret; + + ret = wl->chip.op_boot(wl); + if (ret < 0) + goto out; + + ret = wl->chip.op_hw_init(wl); + if (ret < 0) + goto out; + + ret = wl12xx_acx_station_id(wl); + if (ret < 0) + goto out; + + wl->state = WL12XX_STATE_ON; + + wl12xx_info("firmware booted (%s)", wl->chip.fw_ver); + +out: + if (ret < 0) + wl12xx_power_off(wl); + + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl12xx_op_stop(struct ieee80211_hw *hw) +{ + struct wl12xx *wl = hw->priv; + + wl12xx_info("down"); + + wl12xx_debug(DEBUG_MAC80211, "mac80211 stop"); + + mutex_lock(&wl->mutex); + + WARN_ON(wl->state != WL12XX_STATE_ON); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, true); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + wl->state = WL12XX_STATE_OFF; + + wl12xx_disable_interrupts(wl); + + mutex_unlock(&wl->mutex); + + cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->tx_work); + cancel_work_sync(&wl->filter_work); + + mutex_lock(&wl->mutex); + + /* let's notify MAC80211 about the remaining pending TX frames */ + wl->chip.op_tx_flush(wl); + wl12xx_power_off(wl); + + memset(wl->bssid, 0, ETH_ALEN); + wl->listen_int = 1; + wl->bss_type = MAX_BSS_TYPE; + + wl->data_in_count = 0; + wl->rx_counter = 0; + wl->rx_handled = 0; + wl->rx_current_buffer = 0; + wl->rx_last_id = 0; + wl->next_tx_complete = 0; + wl->elp = false; + wl->psm = 0; + wl->tx_queue_stopped = false; + wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + + wl12xx_debugfs_reset(wl); + + mutex_unlock(&wl->mutex); +} + +static int wl12xx_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct wl12xx *wl = hw->priv; + DECLARE_MAC_BUF(mac); + int ret = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", + conf->type, print_mac(mac, conf->mac_addr)); + + mutex_lock(&wl->mutex); + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + wl->bss_type = BSS_TYPE_STA_BSS; + break; + case NL80211_IFTYPE_ADHOC: + wl->bss_type = BSS_TYPE_IBSS; + break; + default: + ret = -EOPNOTSUPP; + goto out; + } + + if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + ret = wl12xx_acx_station_id(wl); + if (ret < 0) + goto out; + } + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static void wl12xx_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface"); +} + +static int wl12xx_build_null_data(struct wl12xx *wl) +{ + struct wl12xx_null_data_template template; + + if (!is_zero_ether_addr(wl->bssid)) { + memcpy(template.header.da, wl->bssid, ETH_ALEN); + memcpy(template.header.bssid, wl->bssid, ETH_ALEN); + } else { + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + } + + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC); + + return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template, + sizeof(template)); + +} + +static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) +{ + struct wl12xx_ps_poll_template template; + + memcpy(template.bssid, wl->bssid, ETH_ALEN); + memcpy(template.ta, wl->mac_addr, ETH_ALEN); + template.aid = aid; + template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); + + return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template, + sizeof(template)); + +} + +static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct wl12xx *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + int channel, ret = 0; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", + channel, + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level); + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (channel != wl->channel) { + /* FIXME: use beacon interval provided by mac80211 */ + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) + goto out_sleep; + + wl->channel = channel; + } + + ret = wl12xx_build_null_data(wl); + if (ret < 0) + goto out_sleep; + + if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { + wl12xx_info("psm enabled"); + + wl->psm_requested = true; + + /* + * We enter PSM only if we're already associated. + * If we're not, we'll enter it when joining an SSID, + * through the bss_info_changed() hook. + */ + ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + } else if (!(conf->flags & IEEE80211_CONF_PS) && + wl->psm_requested) { + wl12xx_info("psm disabled"); + + wl->psm_requested = false; + + if (wl->psm) + ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + } + + if (conf->power_level != wl->power_level) { + ret = wl12xx_acx_tx_power(wl, conf->power_level); + if (ret < 0) + goto out; + + wl->power_level = conf->power_level; + } + +out_sleep: + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | \ + FIF_OTHER_BSS) + +static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *total, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct wl12xx *wl = hw->priv; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter"); + + *total &= WL12XX_SUPPORTED_FILTERS; + changed &= WL12XX_SUPPORTED_FILTERS; + + if (changed == 0) + /* no filters which we support changed */ + return; + + /* FIXME: wl->rx_config and wl->rx_filter are not protected */ + + wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; + wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + + if (*total & FIF_PROMISC_IN_BSS) { + wl->rx_config |= CFG_BSSID_FILTER_EN; + wl->rx_config |= CFG_RX_ALL_GOOD; + } + if (*total & FIF_ALLMULTI) + /* + * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive + * all multicast frames + */ + wl->rx_config &= ~CFG_MC_FILTER_EN; + if (*total & FIF_FCSFAIL) + wl->rx_filter |= CFG_RX_FCS_ERROR; + if (*total & FIF_BCN_PRBRESP_PROMISC) { + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + wl->rx_config &= ~CFG_SSID_FILTER_EN; + } + if (*total & FIF_CONTROL) + wl->rx_filter |= CFG_RX_CTL_EN; + if (*total & FIF_OTHER_BSS) + wl->rx_filter &= ~CFG_BSSID_FILTER_EN; + + /* + * FIXME: workqueues need to be properly cancelled on stop(), for + * now let's just disable changing the filter settings. They will + * be updated any on config(). + */ + /* schedule_work(&wl->filter_work); */ +} + +/* HW encryption */ +static int wl12xx_set_key_type(struct wl12xx *wl, + struct wl12xx_cmd_set_keys *key, + enum set_key_cmd cmd, + struct ieee80211_key_conf *mac80211_key, + const u8 *addr) +{ + switch (mac80211_key->alg) { + case ALG_WEP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_WEP_DEFAULT; + else + key->key_type = KEY_WEP_ADDR; + + mac80211_key->hw_key_idx = mac80211_key->keyidx; + break; + case ALG_TKIP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_TKIP_MIC_GROUP; + else + key->key_type = KEY_TKIP_MIC_PAIRWISE; + + mac80211_key->hw_key_idx = mac80211_key->keyidx; + break; + case ALG_CCMP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_AES_GROUP; + else + key->key_type = KEY_AES_PAIRWISE; + mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + default: + wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg); + return -EOPNOTSUPP; + } + + return 0; +} + +static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct wl12xx *wl = hw->priv; + struct wl12xx_cmd_set_keys *wl_cmd; + const u8 *addr; + int ret; + + static const u8 bcast_addr[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); + + wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); + if (!wl_cmd) { + ret = -ENOMEM; + goto out; + } + + addr = sta ? sta->addr : bcast_addr; + + wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); + wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); + wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + key->alg, key->keyidx, key->keylen, key->flags); + wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); + + if (is_zero_ether_addr(addr)) { + /* We dont support TX only encryption */ + ret = -EOPNOTSUPP; + goto out; + } + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + + switch (cmd) { + case SET_KEY: + wl_cmd->key_action = KEY_ADD_OR_REPLACE; + break; + case DISABLE_KEY: + wl_cmd->key_action = KEY_REMOVE; + break; + default: + wl12xx_error("Unsupported key cmd 0x%x", cmd); + break; + } + + ret = wl12xx_set_key_type(wl, wl_cmd, cmd, key, addr); + if (ret < 0) { + wl12xx_error("Set KEY type failed"); + goto out_sleep; + } + + if (wl_cmd->key_type != KEY_WEP_DEFAULT) + memcpy(wl_cmd->addr, addr, ETH_ALEN); + + if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || + (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { + /* + * We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(wl_cmd->key, key->key, 16); + memcpy(wl_cmd->key + 16, key->key + 24, 8); + memcpy(wl_cmd->key + 24, key->key + 16, 8); + + } else { + memcpy(wl_cmd->key, key->key, key->keylen); + } + wl_cmd->key_size = key->keylen; + + wl_cmd->id = key->keyidx; + wl_cmd->ssid_profile = 0; + + wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); + + ret = wl12xx_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); + if (ret < 0) { + wl12xx_warning("could not set keys"); + goto out_sleep; + } + +out_sleep: + wl12xx_ps_elp_sleep(wl); + +out_unlock: + mutex_unlock(&wl->mutex); + +out: + kfree(wl_cmd); + + return ret; +} + +static int wl12xx_build_basic_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + + return index; +} + +static int wl12xx_build_extended_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_OFDM_RATE_6MB; + rates[index++] = IEEE80211_OFDM_RATE_9MB; + rates[index++] = IEEE80211_OFDM_RATE_12MB; + rates[index++] = IEEE80211_OFDM_RATE_18MB; + rates[index++] = IEEE80211_OFDM_RATE_24MB; + rates[index++] = IEEE80211_OFDM_RATE_36MB; + rates[index++] = IEEE80211_OFDM_RATE_48MB; + rates[index++] = IEEE80211_OFDM_RATE_54MB; + + return index; +} + + +static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) +{ + struct wl12xx_probe_req_template template; + struct wl12xx_ie_rates *rates; + char *ptr; + u16 size; + + ptr = (char *)&template; + size = sizeof(struct ieee80211_header); + + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + + /* IEs */ + /* SSID */ + template.ssid.header.id = WLAN_EID_SSID; + template.ssid.header.len = ssid_len; + if (ssid_len && ssid) + memcpy(template.ssid.ssid, ssid, ssid_len); + size += sizeof(struct wl12xx_ie_header) + ssid_len; + ptr += size; + + /* Basic Rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_SUPP_RATES; + rates->header.len = wl12xx_build_basic_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; + + /* Extended rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_EXT_SUPP_RATES; + rates->header.len = wl12xx_build_extended_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + + wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); + + return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template, + size); +} + +static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, + u8 active_scan, u8 high_prio, u8 num_channels, + u8 probe_requests) +{ + struct wl12xx_cmd_trigger_scan_to *trigger = NULL; + struct cmd_scan *params = NULL; + int i, ret; + u16 scan_options = 0; + + if (wl->scanning) + return -EINVAL; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + + params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); + params->params.rx_filter_options = + cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); + + /* High priority scan */ + if (!active_scan) + scan_options |= SCAN_PASSIVE; + if (high_prio) + scan_options |= SCAN_PRIORITY_HIGH; + params->params.scan_options = scan_options; + + params->params.num_channels = num_channels; + params->params.num_probe_requests = probe_requests; + params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ + params->params.tid_trigger = 0; + + for (i = 0; i < num_channels; i++) { + params->channels[i].min_duration = cpu_to_le32(30000); + params->channels[i].max_duration = cpu_to_le32(60000); + memset(¶ms->channels[i].bssid_lsb, 0xff, 4); + memset(¶ms->channels[i].bssid_msb, 0xff, 2); + params->channels[i].early_termination = 0; + params->channels[i].tx_power_att = 0; + params->channels[i].channel = i + 1; + memset(params->channels[i].pad, 0, 3); + } + + for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) + memset(¶ms->channels[i], 0, + sizeof(struct basic_scan_channel_parameters)); + + if (len && ssid) { + params->params.ssid_len = len; + memcpy(params->params.ssid, ssid, len); + } else { + params->params.ssid_len = 0; + memset(params->params.ssid, 0, 32); + } + + ret = wl12xx_build_probe_req(wl, ssid, len); + if (ret < 0) { + wl12xx_error("PROBE request template failed"); + goto out; + } + + trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); + if (!trigger) + goto out; + + trigger->timeout = 0; + + ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + sizeof(*trigger)); + if (ret < 0) { + wl12xx_error("trigger scan to failed for hw scan"); + goto out; + } + + wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); + + wl->scanning = true; + + ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); + if (ret < 0) + wl12xx_error("SCAN failed"); + + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); + + if (params->header.status != CMD_STATUS_SUCCESS) { + wl12xx_error("TEST command answer error: %d", + params->header.status); + wl->scanning = false; + ret = -EIO; + goto out; + } + +out: + kfree(params); + return ret; + +} + +static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, + struct cfg80211_scan_request *req) +{ + struct wl12xx *wl = hw->priv; + int ret; + u8 *ssid = NULL; + size_t ssid_len = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan"); + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + ssid_len = req->ssids[0].ssid_len; + } + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wl12xx *wl = hw->priv; + int ret; + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl12xx_acx_rts_threshold(wl, (u16) value); + if (ret < 0) + wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); + + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + enum wl12xx_cmd_ps_mode mode; + struct wl12xx *wl = hw->priv; + struct sk_buff *beacon; + int ret; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed"); + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + wl->aid = bss_conf->aid; + + ret = wl12xx_build_ps_poll(wl, wl->aid); + if (ret < 0) + goto out_sleep; + + ret = wl12xx_acx_aid(wl, wl->aid); + if (ret < 0) + goto out_sleep; + + /* If we want to go in PSM but we're not there yet */ + if (wl->psm_requested && !wl->psm) { + mode = STATION_POWER_SAVE_MODE; + ret = wl12xx_ps_set_mode(wl, mode); + if (ret < 0) + goto out_sleep; + } + } + } + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT); + else + ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); + if (ret < 0) { + wl12xx_warning("Set slot time failed %d", ret); + goto out_sleep; + } + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + else + wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (bss_conf->use_cts_prot) + ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE); + else + ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); + if (ret < 0) { + wl12xx_warning("Set ctsprotect failed %d", ret); + goto out_sleep; + } + } + + if (changed & BSS_CHANGED_BSSID) { + memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); + + ret = wl12xx_build_null_data(wl); + if (ret < 0) + goto out; + + if (wl->bss_type != BSS_TYPE_IBSS) { + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 5, 100, 1); + if (ret < 0) + goto out; + } + } + + if (changed & BSS_CHANGED_BEACON) { + beacon = ieee80211_beacon_get(hw, vif); + ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data, + beacon->len); + + if (ret < 0) { + dev_kfree_skb(beacon); + goto out; + } + + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, + beacon->len); + + dev_kfree_skb(beacon); + + if (ret < 0) + goto out; + + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + + if (ret < 0) + goto out; + } + +out_sleep: + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_rate wl12xx_rates[] = { + { .bitrate = 10, + .hw_value = 0x1, + .hw_value_short = 0x1, }, + { .bitrate = 20, + .hw_value = 0x2, + .hw_value_short = 0x2, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = 0x4, + .hw_value_short = 0x4, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = 0x20, + .hw_value_short = 0x20, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = 0x8, + .hw_value_short = 0x8, }, + { .bitrate = 90, + .hw_value = 0x10, + .hw_value_short = 0x10, }, + { .bitrate = 120, + .hw_value = 0x40, + .hw_value_short = 0x40, }, + { .bitrate = 180, + .hw_value = 0x80, + .hw_value_short = 0x80, }, + { .bitrate = 240, + .hw_value = 0x200, + .hw_value_short = 0x200, }, + { .bitrate = 360, + .hw_value = 0x400, + .hw_value_short = 0x400, }, + { .bitrate = 480, + .hw_value = 0x800, + .hw_value_short = 0x800, }, + { .bitrate = 540, + .hw_value = 0x1000, + .hw_value_short = 0x1000, }, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_channel wl12xx_channels[] = { + { .hw_value = 1, .center_freq = 2412}, + { .hw_value = 2, .center_freq = 2417}, + { .hw_value = 3, .center_freq = 2422}, + { .hw_value = 4, .center_freq = 2427}, + { .hw_value = 5, .center_freq = 2432}, + { .hw_value = 6, .center_freq = 2437}, + { .hw_value = 7, .center_freq = 2442}, + { .hw_value = 8, .center_freq = 2447}, + { .hw_value = 9, .center_freq = 2452}, + { .hw_value = 10, .center_freq = 2457}, + { .hw_value = 11, .center_freq = 2462}, + { .hw_value = 12, .center_freq = 2467}, + { .hw_value = 13, .center_freq = 2472}, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_supported_band wl12xx_band_2ghz = { + .channels = wl12xx_channels, + .n_channels = ARRAY_SIZE(wl12xx_channels), + .bitrates = wl12xx_rates, + .n_bitrates = ARRAY_SIZE(wl12xx_rates), +}; + +static const struct ieee80211_ops wl12xx_ops = { + .start = wl12xx_op_start, + .stop = wl12xx_op_stop, + .add_interface = wl12xx_op_add_interface, + .remove_interface = wl12xx_op_remove_interface, + .config = wl12xx_op_config, + .configure_filter = wl12xx_op_configure_filter, + .tx = wl12xx_op_tx, + .set_key = wl12xx_op_set_key, + .hw_scan = wl12xx_op_hw_scan, + .bss_info_changed = wl12xx_op_bss_info_changed, + .set_rts_threshold = wl12xx_op_set_rts_threshold, +}; + +static int wl12xx_register_hw(struct wl12xx *wl) +{ + int ret; + + if (wl->mac80211_registered) + return 0; + + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + + ret = ieee80211_register_hw(wl->hw); + if (ret < 0) { + wl12xx_error("unable to register mac80211 hw: %d", ret); + return ret; + } + + wl->mac80211_registered = true; + + wl12xx_notice("loaded"); + + return 0; +} + +static int wl12xx_init_ieee80211(struct wl12xx *wl) +{ + /* The tx descriptor buffer and the TKIP space */ + wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) + + WL1251_TKIP_IV_SPACE; + + /* unit us */ + /* FIXME: find a proper value */ + wl->hw->channel_change_time = 10000; + + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz; + + SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); + + return 0; +} + +#define WL12XX_DEFAULT_CHANNEL 1 +static int __devinit wl12xx_probe(struct spi_device *spi) +{ + struct wl12xx_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl12xx *wl; + int ret, i; + static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; + + pdata = spi->dev.platform_data; + if (!pdata) { + wl12xx_error("no platform data"); + return -ENODEV; + } + + hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops); + if (!hw) { + wl12xx_error("could not alloc ieee80211_hw"); + return -ENOMEM; + } + + wl = hw->priv; + memset(wl, 0, sizeof(*wl)); + + wl->hw = hw; + dev_set_drvdata(&spi->dev, wl); + wl->spi = spi; + + wl->data_in_count = 0; + + skb_queue_head_init(&wl->tx_queue); + + INIT_WORK(&wl->filter_work, wl12xx_filter_work); + wl->channel = WL12XX_DEFAULT_CHANNEL; + wl->scanning = false; + wl->default_key = 0; + wl->listen_int = 1; + wl->rx_counter = 0; + wl->rx_handled = 0; + wl->rx_current_buffer = 0; + wl->rx_last_id = 0; + wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; + wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + wl->elp = false; + wl->psm = 0; + wl->psm_requested = false; + wl->tx_queue_stopped = false; + wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + + /* We use the default power on sleep time until we know which chip + * we're using */ + wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + wl->tx_frames[i] = NULL; + + wl->next_tx_complete = 0; + + /* + * In case our MAC address is not correctly set, + * we use a random but Nokia MAC. + */ + memcpy(wl->mac_addr, nokia_oui, 3); + get_random_bytes(wl->mac_addr + 3, 3); + + wl->state = WL12XX_STATE_OFF; + mutex_init(&wl->mutex); + + wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; + wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; + + wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); + if (!wl->rx_descriptor) { + wl12xx_error("could not allocate memory for rx descriptor"); + ret = -ENOMEM; + goto out_free; + } + + /* This is the only SPI value that we need to set here, the rest + * comes from the board-peripherals file */ + spi->bits_per_word = 32; + + ret = spi_setup(spi); + if (ret < 0) { + wl12xx_error("spi_setup failed"); + goto out_free; + } + + wl->set_power = pdata->set_power; + if (!wl->set_power) { + wl12xx_error("set power function missing in platform data"); + ret = -ENODEV; + goto out_free; + } + + wl->irq = spi->irq; + if (wl->irq < 0) { + wl12xx_error("irq missing in platform data"); + ret = -ENODEV; + goto out_free; + } + + ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); + if (ret < 0) { + wl12xx_error("request_irq() failed: %d", ret); + goto out_free; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + + disable_irq(wl->irq); + + ret = wl12xx_init_ieee80211(wl); + if (ret) + goto out_irq; + + ret = wl12xx_register_hw(wl); + if (ret) + goto out_irq; + + wl12xx_debugfs_init(wl); + + wl12xx_notice("initialized"); + + return 0; + + out_irq: + free_irq(wl->irq, wl); + + out_free: + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + + ieee80211_free_hw(hw); + + return ret; +} + +static int __devexit wl12xx_remove(struct spi_device *spi) +{ + struct wl12xx *wl = dev_get_drvdata(&spi->dev); + + ieee80211_unregister_hw(wl->hw); + + wl12xx_debugfs_exit(wl); + + free_irq(wl->irq, wl); + kfree(wl->target_mem_map); + kfree(wl->data_path); + kfree(wl->fw); + wl->fw = NULL; + kfree(wl->nvs); + wl->nvs = NULL; + + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + + ieee80211_free_hw(wl->hw); + + return 0; +} + + +static struct spi_driver wl12xx_spi_driver = { + .driver = { + .name = "wl12xx", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = wl12xx_probe, + .remove = __devexit_p(wl12xx_remove), +}; + +static int __init wl12xx_init(void) +{ + int ret; + + ret = spi_register_driver(&wl12xx_spi_driver); + if (ret < 0) { + wl12xx_error("failed to register spi driver: %d", ret); + goto out; + } + +out: + return ret; +} + +static void __exit wl12xx_exit(void) +{ + spi_unregister_driver(&wl12xx_spi_driver); + + wl12xx_notice("unloaded"); +} + +module_init(wl12xx_init); +module_exit(wl12xx_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo , " + "Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c new file mode 100644 index 0000000..1bc049f --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_netlink.c @@ -0,0 +1,679 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include "wl1251_netlink.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "wl12xx.h" +#include "wl1251_spi.h" +#include "wl1251_acx.h" + +/* FIXME: this should be changed as soon as user space catches up */ +#define WL12XX_NL_NAME "wl1251" +#define WL12XX_NL_VERSION 1 + +#define WL12XX_MAX_TEST_LENGTH 1024 +#define WL12XX_MAX_NVS_LENGTH 1024 + +enum wl12xx_nl_commands { + WL12XX_NL_CMD_UNSPEC, + WL12XX_NL_CMD_TEST, + WL12XX_NL_CMD_INTERROGATE, + WL12XX_NL_CMD_CONFIGURE, + WL12XX_NL_CMD_PHY_REG_READ, + WL12XX_NL_CMD_NVS_PUSH, + WL12XX_NL_CMD_REG_WRITE, + WL12XX_NL_CMD_REG_READ, + WL12XX_NL_CMD_SET_PLT_MODE, + + __WL12XX_NL_CMD_AFTER_LAST +}; +#define WL12XX_NL_CMD_MAX (__WL12XX_NL_CMD_AFTER_LAST - 1) + +enum wl12xx_nl_attrs { + WL12XX_NL_ATTR_UNSPEC, + WL12XX_NL_ATTR_IFNAME, + WL12XX_NL_ATTR_CMD_TEST_PARAM, + WL12XX_NL_ATTR_CMD_TEST_ANSWER, + WL12XX_NL_ATTR_CMD_IE, + WL12XX_NL_ATTR_CMD_IE_LEN, + WL12XX_NL_ATTR_CMD_IE_BUFFER, + WL12XX_NL_ATTR_CMD_IE_ANSWER, + WL12XX_NL_ATTR_REG_ADDR, + WL12XX_NL_ATTR_REG_VAL, + WL12XX_NL_ATTR_NVS_BUFFER, + WL12XX_NL_ATTR_NVS_LEN, + WL12XX_NL_ATTR_PLT_MODE, + + __WL12XX_NL_ATTR_AFTER_LAST +}; +#define WL12XX_NL_ATTR_MAX (__WL12XX_NL_ATTR_AFTER_LAST - 1) + +static struct genl_family wl12xx_nl_family = { + .id = GENL_ID_GENERATE, + .name = WL12XX_NL_NAME, + .hdrsize = 0, + .version = WL12XX_NL_VERSION, + .maxattr = WL12XX_NL_ATTR_MAX, +}; + +static struct net_device *ifname_to_netdev(struct net *net, + struct genl_info *info) +{ + char *ifname; + + if (!info->attrs[WL12XX_NL_ATTR_IFNAME]) + return NULL; + + ifname = nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]); + + wl12xx_debug(DEBUG_NETLINK, "Looking for %s", ifname); + + return dev_get_by_name(net, ifname); +} + +static struct wl12xx *ifname_to_wl12xx(struct net *net, struct genl_info *info) +{ + struct net_device *netdev; + struct wireless_dev *wdev; + struct wiphy *wiphy; + struct ieee80211_hw *hw; + + netdev = ifname_to_netdev(net, info); + if (netdev == NULL) { + wl12xx_error("Wrong interface"); + return NULL; + } + + wdev = netdev->ieee80211_ptr; + if (wdev == NULL) { + wl12xx_error("ieee80211_ptr is NULL"); + return NULL; + } + + wiphy = wdev->wiphy; + if (wiphy == NULL) { + wl12xx_error("wiphy is NULL"); + return NULL; + } + + hw = wiphy_priv(wiphy); + if (hw == NULL) { + wl12xx_error("hw is NULL"); + return NULL; + } + + dev_put(netdev); + + return hw->priv; +} + +static int wl12xx_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + struct wl12xx_command *cmd; + char *buf; + int buf_len, ret, cmd_len; + u8 answer; + + if (!info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]) + return -EINVAL; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + return -EINVAL; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + buf = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]); + buf_len = nla_len(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]); + answer = nla_get_u8(info->attrs[WL12XX_NL_ATTR_CMD_TEST_ANSWER]); + + cmd->header.id = CMD_TEST; + memcpy(cmd->parameters, buf, buf_len); + cmd_len = sizeof(struct wl12xx_cmd_header) + buf_len; + + mutex_lock(&wl->mutex); + ret = wl12xx_cmd_test(wl, cmd, cmd_len, answer); + mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto out; + } + + if (answer) { + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; + goto out; + } + + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + &wl12xx_nl_family, 0, WL12XX_NL_CMD_TEST); + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto nla_put_failure; + } + + NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, + nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + NLA_PUT(msg, WL12XX_NL_ATTR_CMD_TEST_ANSWER, + sizeof(*cmd), cmd); + + ret = genlmsg_end(msg, hdr); + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent, answer"); + ret = genlmsg_reply(msg, info); + goto out; + + nla_put_failure: + nlmsg_free(msg); + } else + wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent"); + +out: + kfree(cmd); + return ret; +} + +static int wl12xx_nl_interrogate(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + struct sk_buff *msg; + int ret = -ENOBUFS, cmd_ie, cmd_ie_len; + struct wl12xx_command *cmd; + void *hdr; + + if (!info->attrs[WL12XX_NL_ATTR_CMD_IE]) + return -EINVAL; + + if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + ret = -EINVAL; + goto nla_put_failure; + } + + /* acx id */ + cmd_ie = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE]); + + /* maximum length of acx, including all headers */ + cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]); + + wl12xx_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)", + cmd_ie, cmd_ie_len); + + mutex_lock(&wl->mutex); + ret = wl12xx_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len); + mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + &wl12xx_nl_family, 0, WL12XX_NL_CMD_INTERROGATE); + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto nla_put_failure; + } + + NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, + nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + NLA_PUT(msg, WL12XX_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd); + + ret = genlmsg_end(msg, hdr); + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + kfree(cmd); + return genlmsg_reply(msg, info); + + nla_put_failure: + kfree(cmd); + nlmsg_free(msg); + + return ret; +} + +static int wl12xx_nl_configure(struct sk_buff *skb, struct genl_info *info) +{ + int ret = 0, cmd_ie_len, acx_len; + struct acx_header *acx = NULL; + struct sk_buff *msg; + struct wl12xx *wl; + void *cmd_ie; + u16 *id; + + if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER]) + return -EINVAL; + + if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]) + return -EINVAL; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + ret = -EINVAL; + goto nla_put_failure; + } + + /* contains the acx header but not the cmd header */ + cmd_ie = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER]); + + cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]); + + /* acx id is in the first two bytes */ + id = cmd_ie; + + /* need to add acx_header before cmd_ie, so create a new command */ + acx_len = sizeof(struct acx_header) + cmd_ie_len; + acx = kzalloc(acx_len, GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto nla_put_failure; + } + + /* copy the acx header and the payload */ + memcpy(&acx->id, cmd_ie, cmd_ie_len); + + mutex_lock(&wl->mutex); + ret = wl12xx_cmd_configure(wl, *id, acx, acx_len); + mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + wl12xx_debug(DEBUG_NETLINK, "CONFIGURE cmd sent"); + + nla_put_failure: + kfree(acx); + nlmsg_free(msg); + + return ret; +} + +static int wl12xx_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + struct sk_buff *msg; + u32 reg_addr, *reg_value = NULL; + int ret = 0; + void *hdr; + + if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + return -EINVAL; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + ret = -EINVAL; + goto nla_put_failure; + } + + reg_value = kmalloc(sizeof(*reg_value), GFP_KERNEL); + if (!reg_value) { + ret = -ENOMEM; + goto nla_put_failure; + } + + reg_addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); + + wl12xx_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr); + + mutex_lock(&wl->mutex); + ret = wl12xx_cmd_read_memory(wl, reg_addr, reg_value, + sizeof(*reg_value)); + mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ); + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto nla_put_failure; + } + + NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, + nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + + NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, *reg_value); + + ret = genlmsg_end(msg, hdr); + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + kfree(reg_value); + + return genlmsg_reply(msg, info); + + nla_put_failure: + nlmsg_free(msg); + kfree(reg_value); + + return ret; +} + +static int wl12xx_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + int ret = 0; + + if (!info->attrs[WL12XX_NL_ATTR_NVS_BUFFER]) + return -EINVAL; + + if (!info->attrs[WL12XX_NL_ATTR_NVS_LEN]) + return -EINVAL; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + return -EINVAL; + } + + mutex_lock(&wl->mutex); + wl->nvs_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_NVS_LEN]); + if (wl->nvs_len % 4) { + wl12xx_error("NVS size is not multiple of 32: %d", wl->nvs_len); + ret = -EILSEQ; + goto out; + } + + /* If we already have an NVS, we should free it */ + kfree(wl->nvs); + + wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL); + if (wl->nvs == NULL) { + wl12xx_error("Can't allocate NVS"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->nvs, + nla_data(info->attrs[WL12XX_NL_ATTR_NVS_BUFFER]), + wl->nvs_len); + + wl12xx_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes", + wl->nvs_len); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl12xx_nl_reg_read(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + u32 addr, val; + int ret = 0; + struct sk_buff *msg; + void *hdr; + + if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + return -EINVAL; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + return -EINVAL; + } + + addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); + + mutex_lock(&wl->mutex); + val = wl12xx_reg_read32(wl, addr); + mutex_unlock(&wl->mutex); + + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ); + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto nla_put_failure; + } + + NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, + nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + + NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, val); + + ret = genlmsg_end(msg, hdr); + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + return genlmsg_reply(msg, info); + + nla_put_failure: + nlmsg_free(msg); + + return ret; +} + +static int wl12xx_nl_reg_write(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + u32 addr, val; + + if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + return -EINVAL; + + if (!info->attrs[WL12XX_NL_ATTR_REG_VAL]) + return -EINVAL; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + return -EINVAL; + } + + addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); + val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_VAL]); + + mutex_lock(&wl->mutex); + wl12xx_reg_write32(wl, addr, val); + mutex_unlock(&wl->mutex); + + return 0; +} + +static int wl12xx_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + u32 val; + int ret; + + if (!info->attrs[WL12XX_NL_ATTR_PLT_MODE]) + return -EINVAL; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + return -EINVAL; + } + + val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_PLT_MODE]); + + switch (val) { + case 0: + ret = wl12xx_plt_stop(wl); + break; + case 1: + ret = wl12xx_plt_start(wl); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static struct nla_policy wl12xx_nl_policy[WL12XX_NL_ATTR_MAX + 1] = { + [WL12XX_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, + .len = IFNAMSIZ-1 }, + [WL12XX_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY, + .len = WL12XX_MAX_TEST_LENGTH }, + [WL12XX_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 }, + [WL12XX_NL_ATTR_CMD_IE] = { .type = NLA_U32 }, + [WL12XX_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 }, + [WL12XX_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY, + .len = WL12XX_MAX_TEST_LENGTH }, + [WL12XX_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY, + .len = WL12XX_MAX_TEST_LENGTH }, + [WL12XX_NL_ATTR_REG_ADDR] = { .type = NLA_U32 }, + [WL12XX_NL_ATTR_REG_VAL] = { .type = NLA_U32 }, + [WL12XX_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY, + .len = WL12XX_MAX_NVS_LENGTH }, + [WL12XX_NL_ATTR_NVS_LEN] = { .type = NLA_U32 }, + [WL12XX_NL_ATTR_PLT_MODE] = { .type = NLA_U32 }, +}; + +static struct genl_ops wl12xx_nl_ops[] = { + { + .cmd = WL12XX_NL_CMD_TEST, + .doit = wl12xx_nl_test_cmd, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_INTERROGATE, + .doit = wl12xx_nl_interrogate, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_CONFIGURE, + .doit = wl12xx_nl_configure, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_PHY_REG_READ, + .doit = wl12xx_nl_phy_reg_read, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_NVS_PUSH, + .doit = wl12xx_nl_nvs_push, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_REG_WRITE, + .doit = wl12xx_nl_reg_write, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_REG_READ, + .doit = wl12xx_nl_reg_read, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_SET_PLT_MODE, + .doit = wl12xx_nl_set_plt_mode, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, +}; + +int wl12xx_nl_register(void) +{ + int err, i; + + err = genl_register_family(&wl12xx_nl_family); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(wl12xx_nl_ops); i++) { + err = genl_register_ops(&wl12xx_nl_family, &wl12xx_nl_ops[i]); + if (err) + goto err_out; + } + return 0; + err_out: + genl_unregister_family(&wl12xx_nl_family); + return err; +} + +void wl12xx_nl_unregister(void) +{ + genl_unregister_family(&wl12xx_nl_family); +} diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h new file mode 100644 index 0000000..acfbd02 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_netlink.h @@ -0,0 +1,30 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_NETLINK_H__ +#define __WL12XX_NETLINK_H__ + +int wl12xx_nl_register(void); +void wl12xx_nl_unregister(void); + +#endif /* __WL12XX_NETLINK_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c index 126537f..cdfd2c2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -26,14 +26,14 @@ #include "wl1251_ops.h" #include "reg.h" -#include "spi.h" -#include "boot.h" -#include "event.h" -#include "acx.h" +#include "wl1251_spi.h" +#include "wl1251_boot.h" +#include "wl1251_event.h" +#include "wl1251_acx.h" #include "wl1251_tx.h" -#include "rx.h" -#include "ps.h" -#include "init.h" +#include "wl1251_rx.h" +#include "wl1251_ps.h" +#include "wl1251_init.h" static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = { [PART_DOWN] = { diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h index 74acf8e..7a78cc9 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.h +++ b/drivers/net/wireless/wl12xx/wl1251_ops.h @@ -27,7 +27,7 @@ #include #include "wl12xx.h" -#include "acx.h" +#include "wl1251_acx.h" #define WL1251_FW_NAME "wl1251-fw.bin" #define WL1251_NVS_NAME "wl1251-nvs.bin" diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c new file mode 100644 index 0000000..83baaa2 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -0,0 +1,147 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "reg.h" +#include "wl1251_ps.h" +#include "wl1251_spi.h" + +#define WL12XX_WAKEUP_TIMEOUT 2000 + +/* Routines to toggle sleep mode while in ELP */ +void wl12xx_ps_elp_sleep(struct wl12xx *wl) +{ + if (wl->elp || !wl->psm) + return; + + wl12xx_debug(DEBUG_PSM, "chip to elp"); + + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + + wl->elp = true; +} + +int wl12xx_ps_elp_wakeup(struct wl12xx *wl) +{ + unsigned long timeout; + u32 elp_reg; + + if (!wl->elp) + return 0; + + wl12xx_debug(DEBUG_PSM, "waking up chip from elp"); + + timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT); + + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + + /* + * FIXME: we should wait for irq from chip but, as a temporary + * solution to simplify locking, let's poll instead + */ + while (!(elp_reg & ELPCTRL_WLAN_READY)) { + if (time_after(jiffies, timeout)) { + wl12xx_error("elp wakeup timeout"); + return -ETIMEDOUT; + } + msleep(1); + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + } + + wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms", + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT)); + + wl->elp = false; + + return 0; +} + +static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) +{ + int ret; + + if (enable) { + wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp"); + + ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_ELP); + if (ret < 0) + return ret; + + wl12xx_ps_elp_sleep(wl); + } else { + wl12xx_debug(DEBUG_PSM, "sleep auth cam"); + + /* + * When the target is in ELP, we can only + * access the ELP control register. Thus, + * we have to wake the target up before + * changing the power authorization. + */ + + wl12xx_ps_elp_wakeup(wl); + + ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); + if (ret < 0) + return ret; + } + + return 0; +} + +int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode) +{ + int ret; + + switch (mode) { + case STATION_POWER_SAVE_MODE: + wl12xx_debug(DEBUG_PSM, "entering psm"); + ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + return ret; + + ret = wl12xx_ps_set_elp(wl, true); + if (ret < 0) + return ret; + + wl->psm = 1; + break; + case STATION_ACTIVE_MODE: + default: + wl12xx_debug(DEBUG_PSM, "leaving psm"); + ret = wl12xx_ps_set_elp(wl, false); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + + wl->psm = 0; + break; + } + + return ret; +} + diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h new file mode 100644 index 0000000..db9f7ed --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_ps.h @@ -0,0 +1,36 @@ +#ifndef __WL12XX_PS_H__ +#define __WL12XX_PS_H__ + +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl12xx.h" +#include "wl1251_acx.h" + +int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode); +void wl12xx_ps_elp_sleep(struct wl12xx *wl); +int wl12xx_ps_elp_wakeup(struct wl12xx *wl); + + +#endif /* __WL12XX_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c new file mode 100644 index 0000000..d73e014 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -0,0 +1,195 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl12xx.h" +#include "reg.h" +#include "wl1251_spi.h" +#include "wl1251_rx.h" +#include "wl1251_acx.h" + +static void wl12xx_rx_header(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc) +{ + u32 rx_packet_ring_addr; + + rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; + if (wl->rx_current_buffer) + rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; + + wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); +} + +static void wl12xx_rx_status(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc, + struct ieee80211_rx_status *status, + u8 beacon) +{ + u64 mactime; + int ret; + + memset(status, 0, sizeof(struct ieee80211_rx_status)); + + status->band = IEEE80211_BAND_2GHZ; + status->mactime = desc->timestamp; + + /* + * The rx status timestamp is a 32 bits value while the TSF is a + * 64 bits one. + * For IBSS merging, TSF is mandatory, so we have to get it + * somehow, so we ask for ACX_TSF_INFO. + * That could be moved to the get_tsf() hook, but unfortunately, + * this one must be atomic, while our SPI routines can sleep. + */ + if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { + ret = wl12xx_acx_tsf_info(wl, &mactime); + if (ret == 0) + status->mactime = mactime; + } + + status->signal = desc->rssi; + status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 / + (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI); + status->qual = min(status->qual, 100); + status->qual = max(status->qual, 0); + + /* + * FIXME: guessing that snr needs to be divided by two, otherwise + * the values don't make any sense + */ + status->noise = desc->rssi - desc->snr / 2; + + status->freq = ieee80211_channel_to_frequency(desc->channel); + + status->flag |= RX_FLAG_TSFT; + + if (desc->flags & RX_DESC_ENCRYPTION_MASK) { + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + + if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) + status->flag |= RX_FLAG_DECRYPTED; + + if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) + status->flag |= RX_FLAG_MMIC_ERROR; + } + + if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + + /* FIXME: set status->rate_idx */ +} + +static void wl12xx_rx_body(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc) +{ + struct sk_buff *skb; + struct ieee80211_rx_status status; + u8 *rx_buffer, beacon = 0; + u16 length, *fc; + u32 curr_id, last_id_inc, rx_packet_ring_addr; + + length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); + curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; + last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); + + if (last_id_inc != curr_id) { + wl12xx_warning("curr ID:%d, last ID inc:%d", + curr_id, last_id_inc); + wl->rx_last_id = curr_id; + } else { + wl->rx_last_id = last_id_inc; + } + + rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + + sizeof(struct wl12xx_rx_descriptor) + 20; + if (wl->rx_current_buffer) + rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; + + skb = dev_alloc_skb(length); + if (!skb) { + wl12xx_error("Couldn't allocate RX frame"); + return; + } + + rx_buffer = skb_put(skb, length); + wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); + + /* The actual lenght doesn't include the target's alignment */ + skb->len = desc->length - PLCP_HEADER_LENGTH; + + fc = (u16 *)skb->data; + + if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + beacon = 1; + + wl12xx_rx_status(wl, desc, &status, beacon); + + wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + beacon ? "beacon" : ""); + + ieee80211_rx(wl->hw, skb, &status); +} + +static void wl12xx_rx_ack(struct wl12xx *wl) +{ + u32 data, addr; + + if (wl->rx_current_buffer) { + addr = ACX_REG_INTERRUPT_TRIG_H; + data = INTR_TRIG_RX_PROC1; + } else { + addr = ACX_REG_INTERRUPT_TRIG; + data = INTR_TRIG_RX_PROC0; + } + + wl12xx_reg_write32(wl, addr, data); + + /* Toggle buffer ring */ + wl->rx_current_buffer = !wl->rx_current_buffer; +} + + +void wl12xx_rx(struct wl12xx *wl) +{ + struct wl12xx_rx_descriptor *rx_desc; + + if (wl->state != WL12XX_STATE_ON) + return; + + rx_desc = wl->rx_descriptor; + + /* We first read the frame's header */ + wl12xx_rx_header(wl, rx_desc); + + /* Now we can read the body */ + wl12xx_rx_body(wl, rx_desc); + + /* Finally, we need to ACK the RX */ + wl12xx_rx_ack(wl); + + return; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h new file mode 100644 index 0000000..8a23fde --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_rx.h @@ -0,0 +1,122 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_RX_H__ +#define __WL12XX_RX_H__ + +#include + +/* + * RX PATH + * + * The Rx path uses a double buffer and an rx_contro structure, each located + * at a fixed address in the device memory. The host keeps track of which + * buffer is available and alternates between them on a per packet basis. + * The size of each of the two buffers is large enough to hold the longest + * 802.3 packet. + * The RX path goes like that: + * 1) The target generates an interrupt each time a new packet is received. + * There are 2 RX interrupts, one for each buffer. + * 2) The host reads the received packet from one of the double buffers. + * 3) The host triggers a target interrupt. + * 4) The target prepares the next RX packet. + */ + +#define WL12XX_RX_MAX_RSSI -30 +#define WL12XX_RX_MIN_RSSI -95 + +#define WL12XX_RX_ALIGN_TO 4 +#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \ + ~(WL12XX_RX_ALIGN_TO - 1)) + +#define SHORT_PREAMBLE_BIT BIT(0) +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +#define PLCP_HEADER_LENGTH 8 +#define RX_DESC_PACKETID_SHIFT 11 +#define RX_MAX_PACKET_ID 3 + +#define RX_DESC_VALID_FCS 0x0001 +#define RX_DESC_MATCH_RXADDR1 0x0002 +#define RX_DESC_MCAST 0x0004 +#define RX_DESC_STAINTIM 0x0008 +#define RX_DESC_VIRTUAL_BM 0x0010 +#define RX_DESC_BCAST 0x0020 +#define RX_DESC_MATCH_SSID 0x0040 +#define RX_DESC_MATCH_BSSID 0x0080 +#define RX_DESC_ENCRYPTION_MASK 0x0300 +#define RX_DESC_MEASURMENT 0x0400 +#define RX_DESC_SEQNUM_MASK 0x1800 +#define RX_DESC_MIC_FAIL 0x2000 +#define RX_DESC_DECRYPT_FAIL 0x4000 + +struct wl12xx_rx_descriptor { + u32 timestamp; /* In microseconds */ + u16 length; /* Paylod length, including headers */ + u16 flags; + + /* + * 0 - 802.11 + * 1 - 802.3 + * 2 - IP + * 3 - Raw Codec + */ + u8 type; + + /* + * Recevied Rate: + * 0x0A - 1MBPS + * 0x14 - 2MBPS + * 0x37 - 5_5MBPS + * 0x0B - 6MBPS + * 0x0F - 9MBPS + * 0x6E - 11MBPS + * 0x0A - 12MBPS + * 0x0E - 18MBPS + * 0xDC - 22MBPS + * 0x09 - 24MBPS + * 0x0D - 36MBPS + * 0x08 - 48MBPS + * 0x0C - 54MBPS + */ + u8 rate; + + u8 mod_pre; /* Modulation and preamble */ + u8 channel; + + /* + * 0 - 2.4 Ghz + * 1 - 5 Ghz + */ + u8 band; + + s8 rssi; /* in dB */ + u8 rcpi; /* in dB */ + u8 snr; /* in dB */ +} __attribute__ ((packed)); + +void wl12xx_rx(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c new file mode 100644 index 0000000..d7eee8c --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -0,0 +1,394 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251_spi.h" + +static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) +{ + /* If the address is lower than REGISTERS_BASE, it means that this is + * a chip-specific register address, so look it up in the registers + * table */ + if (addr < REGISTERS_BASE) { + /* Make sure we don't go over the table */ + if (addr >= ACX_REG_TABLE_LEN) { + wl12xx_error("address out of range (%d)", addr); + return -EINVAL; + } + addr = wl->chip.acx_reg_table[addr]; + } + + return addr - wl->physical_reg_addr + wl->virtual_reg_addr; +} + +static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr) +{ + return addr - wl->physical_mem_addr + wl->virtual_mem_addr; +} + + +void wl12xx_spi_reset(struct wl12xx *wl) +{ + u8 *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl12xx_error("could not allocate cmd for spi reset"); + return; + } + + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + memset(cmd, 0xff, WSPI_INIT_CMD_LEN); + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); +} + +void wl12xx_spi_init(struct wl12xx *wl) +{ + u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl12xx_error("could not allocate cmd for spi init"); + return; + } + + memset(crc, 0, sizeof(crc)); + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + /* + * Set WSPI_INIT_COMMAND + * the data is being send from the MSB to LSB + */ + cmd[2] = 0xff; + cmd[3] = 0xff; + cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; + cmd[0] = 0; + cmd[7] = 0; + cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; + cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; + + if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) + cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; + else + cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; + + cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS + | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; + + crc[0] = cmd[1]; + crc[1] = cmd[0]; + crc[2] = cmd[7]; + crc[3] = cmd[6]; + crc[4] = cmd[5]; + + cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; + cmd[4] |= WSPI_INIT_CMD_END; + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); +} + +/* Set the SPI partitions to access the chip addresses + * + * There are two VIRTUAL (SPI) partitions (the memory partition and the + * registers partition), which are mapped to two different areas of the + * PHYSICAL (hardware) memory. This function also makes other checks to + * ensure that the partitions are not overlapping. In the diagram below, the + * memory partition comes before the register partition, but the opposite is + * also supported. + * + * PHYSICAL address + * space + * + * | | + * ...+----+--> mem_start + * VIRTUAL address ... | | + * space ... | | [PART_0] + * ... | | + * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * part_size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * part_size | | ... | | + * + <--+----+... ...+----+--> reg_start + * reg_size ... | | + * ... | | [PART_1] + * ... | | + * ...+----+--> reg_start + reg_size + * | | + * + */ +int wl12xx_set_partition(struct wl12xx *wl, + u32 mem_start, u32 mem_size, + u32 reg_start, u32 reg_size) +{ + struct wl12xx_partition *partition; + struct spi_transfer t; + struct spi_message m; + size_t len, cmd_len; + u32 *cmd; + int addr; + + cmd_len = sizeof(u32) + 2 * sizeof(struct wl12xx_partition); + cmd = kzalloc(cmd_len, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + spi_message_init(&m); + memset(&t, 0, sizeof(t)); + + partition = (struct wl12xx_partition *) (cmd + 1); + addr = HW_ACCESS_PART0_SIZE_ADDR; + len = 2 * sizeof(struct wl12xx_partition); + + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + + /* Make sure that the two partitions together don't exceed the + * address range */ + if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { + wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual" + " address range. Truncating partition[0]."); + mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + if ((mem_start < reg_start) && + ((mem_start + mem_size) > reg_start)) { + /* Guarantee that the memory partition doesn't overlap the + * registers partition */ + wl12xx_debug(DEBUG_SPI, "End of partition[0] is " + "overlapping partition[1]. Adjusted."); + mem_size = reg_start - mem_start; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } else if ((reg_start < mem_start) && + ((reg_start + reg_size) > mem_start)) { + /* Guarantee that the register partition doesn't overlap the + * memory partition */ + wl12xx_debug(DEBUG_SPI, "End of partition[1] is" + " overlapping partition[0]. Adjusted."); + reg_size = mem_start - reg_start; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + partition[0].start = mem_start; + partition[0].size = mem_size; + partition[1].start = reg_start; + partition[1].size = reg_size; + + wl->physical_mem_addr = mem_start; + wl->physical_reg_addr = reg_start; + + wl->virtual_mem_addr = 0; + wl->virtual_reg_addr = mem_size; + + t.tx_buf = cmd; + t.len = cmd_len; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + kfree(cmd); + + return 0; +} + +void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed) +{ + struct spi_transfer t[3]; + struct spi_message m; + u8 *busy_buf; + u32 *cmd; + + cmd = &wl->buffer_cmd; + busy_buf = wl->buffer_busyword; + + *cmd = 0; + *cmd |= WSPI_CMD_READ; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = 4; + spi_message_add_tail(&t[0], &m); + + /* Busy and non busy words read */ + t[1].rx_buf = busy_buf; + t[1].len = WL12XX_BUSY_WORD_LEN; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = buf; + t[2].len = len; + spi_message_add_tail(&t[2], &m); + + spi_sync(wl->spi, &m); + + /* FIXME: check busy words */ + + wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); + wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); +} + +void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed) +{ + struct spi_transfer t[2]; + struct spi_message m; + u32 *cmd; + + cmd = &wl->buffer_cmd; + + *cmd = 0; + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = sizeof(*cmd); + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = buf; + t[1].len = len; + spi_message_add_tail(&t[1], &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); + wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); +} + +void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl12xx_translate_mem_addr(wl, addr); + + wl12xx_spi_read(wl, physical, buf, len, false); +} + +void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl12xx_translate_mem_addr(wl, addr); + + wl12xx_spi_write(wl, physical, buf, len, false); +} + +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed) +{ + int physical; + + physical = wl12xx_translate_reg_addr(wl, addr); + + wl12xx_spi_read(wl, physical, buf, len, fixed); +} + +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed) +{ + int physical; + + physical = wl12xx_translate_reg_addr(wl, addr); + + wl12xx_spi_write(wl, physical, buf, len, fixed); +} + +u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) +{ + return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr)); +} + +void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val); +} + +u32 wl12xx_reg_read32(struct wl12xx *wl, int addr) +{ + return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr)); +} + +void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val); +} diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h new file mode 100644 index 0000000..82b009c --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -0,0 +1,115 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_SPI_H__ +#define __WL12XX_SPI_H__ + +#include "wl1251_cmd.h" +#include "wl1251_acx.h" +#include "reg.h" + +#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 + +#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 +#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 +#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 +#define HW_ACCESS_PART1_START_ADDR 0x1FFCC + +#define HW_ACCESS_REGISTER_SIZE 4 + +#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 + +#define WSPI_CMD_READ 0x40000000 +#define WSPI_CMD_WRITE 0x00000000 +#define WSPI_CMD_FIXED 0x20000000 +#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 +#define WSPI_CMD_BYTE_LENGTH_OFFSET 17 +#define WSPI_CMD_BYTE_ADDR 0x0001FFFF + +#define WSPI_INIT_CMD_CRC_LEN 5 + +#define WSPI_INIT_CMD_START 0x00 +#define WSPI_INIT_CMD_TX 0x40 +/* the extra bypass bit is sampled by the TNET as '1' */ +#define WSPI_INIT_CMD_BYPASS_BIT 0x80 +#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 +#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 +#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 +#define WSPI_INIT_CMD_IOD 0x40 +#define WSPI_INIT_CMD_IP 0x20 +#define WSPI_INIT_CMD_CS 0x10 +#define WSPI_INIT_CMD_WS 0x08 +#define WSPI_INIT_CMD_WSPI 0x01 +#define WSPI_INIT_CMD_END 0x01 + +#define WSPI_INIT_CMD_LEN 8 + +#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ + ((WL12XX_BUSY_WORD_LEN - 4) / sizeof(u32)) +#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 + + +/* Raw target IO, address is not translated */ +void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed); +void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed); + +/* Memory target IO, address is tranlated to partition 0 */ +void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len); +u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); +void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); + +/* Registers IO */ +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed); +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed); +u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); +void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); + +/* INIT and RESET words */ +void wl12xx_spi_reset(struct wl12xx *wl); +void wl12xx_spi_init(struct wl12xx *wl); +int wl12xx_set_partition(struct wl12xx *wl, + u32 part_start, u32 part_size, + u32 reg_start, u32 reg_size); + +static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) +{ + wl12xx_spi_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); + + return wl->buffer_32; +} + +static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl->buffer_32 = val; + wl12xx_spi_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); +} + +#endif /* __WL12XX_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index 10023fc..c57330e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -27,9 +27,9 @@ #include "wl12xx.h" #include "reg.h" -#include "spi.h" +#include "wl1251_spi.h" #include "wl1251_tx.h" -#include "ps.h" +#include "wl1251_ps.h" static bool wl1251_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) { -- cgit v0.10.2 From 1367411858d5fc60b632a3f488f2b4adc73d12d7 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:25 +0300 Subject: wl1251: rename wl12xx.h to wl1251.h wl12xx.h is now only used by 1251 code, so we can rename it. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h index e421643..2de47cc 100644 --- a/drivers/net/wireless/wl12xx/reg.h +++ b/drivers/net/wireless/wl12xx/reg.h @@ -26,7 +26,6 @@ #define __REG_H__ #include -#include "wl12xx.h" #define REGISTERS_BASE 0x00300000 #define DRPW_BASE 0x00310000 diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h new file mode 100644 index 0000000..c673cdb --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -0,0 +1,420 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_H__ +#define __WL12XX_H__ + +#include +#include +#include +#include + +#define DRIVER_NAME "wl12xx" +#define DRIVER_PREFIX DRIVER_NAME ": " + +enum { + DEBUG_NONE = 0, + DEBUG_IRQ = BIT(0), + DEBUG_SPI = BIT(1), + DEBUG_BOOT = BIT(2), + DEBUG_MAILBOX = BIT(3), + DEBUG_NETLINK = BIT(4), + DEBUG_EVENT = BIT(5), + DEBUG_TX = BIT(6), + DEBUG_RX = BIT(7), + DEBUG_SCAN = BIT(8), + DEBUG_CRYPT = BIT(9), + DEBUG_PSM = BIT(10), + DEBUG_MAC80211 = BIT(11), + DEBUG_CMD = BIT(12), + DEBUG_ACX = BIT(13), + DEBUG_ALL = ~0, +}; + +#define DEBUG_LEVEL (DEBUG_NONE) + +#define DEBUG_DUMP_LIMIT 1024 + +#define wl12xx_error(fmt, arg...) \ + printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) + +#define wl12xx_warning(fmt, arg...) \ + printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) + +#define wl12xx_notice(fmt, arg...) \ + printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) + +#define wl12xx_info(fmt, arg...) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) + +#define wl12xx_debug(level, fmt, arg...) \ + do { \ + if (level & DEBUG_LEVEL) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) + +#define wl12xx_dump(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + 0); \ + } while (0) + +#define wl12xx_dump_ascii(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + true); \ + } while (0) + +#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ + CFG_BSSID_FILTER_EN) + +#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ + CFG_RX_MGMT_EN | \ + CFG_RX_DATA_EN | \ + CFG_RX_CTL_EN | \ + CFG_RX_BCN_EN | \ + CFG_RX_AUTH_EN | \ + CFG_RX_ASSOC_EN) + +#define WL12XX_BUSY_WORD_LEN 8 + +struct boot_attr { + u32 radio_type; + u8 mac_clock; + u8 arm_clock; + int firmware_debug; + u32 minor; + u32 major; + u32 bugfix; +}; + +enum wl12xx_state { + WL12XX_STATE_OFF, + WL12XX_STATE_ON, + WL12XX_STATE_PLT, +}; + +enum wl12xx_partition_type { + PART_DOWN, + PART_WORK, + PART_DRPW, + + PART_TABLE_LEN +}; + +struct wl12xx_partition { + u32 size; + u32 start; +}; + +struct wl12xx_partition_set { + struct wl12xx_partition mem; + struct wl12xx_partition reg; +}; + +struct wl12xx; + +/* FIXME: I'm not sure about this structure name */ +struct wl12xx_chip { + u32 id; + + const char *fw_filename; + const char *nvs_filename; + + char fw_ver[21]; + + unsigned int power_on_sleep; + int intr_cmd_complete; + int intr_init_complete; + + int (*op_upload_fw)(struct wl12xx *wl); + int (*op_upload_nvs)(struct wl12xx *wl); + int (*op_boot)(struct wl12xx *wl); + void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag); + void (*op_target_enable_interrupts)(struct wl12xx *wl); + int (*op_hw_init)(struct wl12xx *wl); + int (*op_plt_init)(struct wl12xx *wl); + void (*op_tx_flush)(struct wl12xx *wl); + void (*op_fw_version)(struct wl12xx *wl); + int (*op_cmd_join)(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait); + + struct wl12xx_partition_set *p_table; + enum wl12xx_acx_int_reg *acx_reg_table; +}; + +struct wl12xx_stats { + struct acx_statistics *fw_stats; + unsigned long fw_stats_update; + + unsigned int retry_count; + unsigned int excessive_retries; +}; + +struct wl12xx_debugfs { + struct dentry *rootdir; + struct dentry *fw_statistics; + + struct dentry *tx_internal_desc_overflow; + + struct dentry *rx_out_of_mem; + struct dentry *rx_hdr_overflow; + struct dentry *rx_hw_stuck; + struct dentry *rx_dropped; + struct dentry *rx_fcs_err; + struct dentry *rx_xfr_hint_trig; + struct dentry *rx_path_reset; + struct dentry *rx_reset_counter; + + struct dentry *dma_rx_requested; + struct dentry *dma_rx_errors; + struct dentry *dma_tx_requested; + struct dentry *dma_tx_errors; + + struct dentry *isr_cmd_cmplt; + struct dentry *isr_fiqs; + struct dentry *isr_rx_headers; + struct dentry *isr_rx_mem_overflow; + struct dentry *isr_rx_rdys; + struct dentry *isr_irqs; + struct dentry *isr_tx_procs; + struct dentry *isr_decrypt_done; + struct dentry *isr_dma0_done; + struct dentry *isr_dma1_done; + struct dentry *isr_tx_exch_complete; + struct dentry *isr_commands; + struct dentry *isr_rx_procs; + struct dentry *isr_hw_pm_mode_changes; + struct dentry *isr_host_acknowledges; + struct dentry *isr_pci_pm; + struct dentry *isr_wakeups; + struct dentry *isr_low_rssi; + + struct dentry *wep_addr_key_count; + struct dentry *wep_default_key_count; + /* skipping wep.reserved */ + struct dentry *wep_key_not_found; + struct dentry *wep_decrypt_fail; + struct dentry *wep_packets; + struct dentry *wep_interrupt; + + struct dentry *pwr_ps_enter; + struct dentry *pwr_elp_enter; + struct dentry *pwr_missing_bcns; + struct dentry *pwr_wake_on_host; + struct dentry *pwr_wake_on_timer_exp; + struct dentry *pwr_tx_with_ps; + struct dentry *pwr_tx_without_ps; + struct dentry *pwr_rcvd_beacons; + struct dentry *pwr_power_save_off; + struct dentry *pwr_enable_ps; + struct dentry *pwr_disable_ps; + struct dentry *pwr_fix_tsf_ps; + /* skipping cont_miss_bcns_spread for now */ + struct dentry *pwr_rcvd_awake_beacons; + + struct dentry *mic_rx_pkts; + struct dentry *mic_calc_failure; + + struct dentry *aes_encrypt_fail; + struct dentry *aes_decrypt_fail; + struct dentry *aes_encrypt_packets; + struct dentry *aes_decrypt_packets; + struct dentry *aes_encrypt_interrupt; + struct dentry *aes_decrypt_interrupt; + + struct dentry *event_heart_beat; + struct dentry *event_calibration; + struct dentry *event_rx_mismatch; + struct dentry *event_rx_mem_empty; + struct dentry *event_rx_pool; + struct dentry *event_oom_late; + struct dentry *event_phy_transmit_error; + struct dentry *event_tx_stuck; + + struct dentry *ps_pspoll_timeouts; + struct dentry *ps_upsd_timeouts; + struct dentry *ps_upsd_max_sptime; + struct dentry *ps_upsd_max_apturn; + struct dentry *ps_pspoll_max_apturn; + struct dentry *ps_pspoll_utilization; + struct dentry *ps_upsd_utilization; + + struct dentry *rxpipe_rx_prep_beacon_drop; + struct dentry *rxpipe_descr_host_int_trig_rx_data; + struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; + struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; + struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; + + struct dentry *tx_queue_len; + + struct dentry *retry_count; + struct dentry *excessive_retries; +}; + +struct wl12xx { + struct ieee80211_hw *hw; + bool mac80211_registered; + + struct spi_device *spi; + + void (*set_power)(bool enable); + int irq; + + enum wl12xx_state state; + struct mutex mutex; + + int physical_mem_addr; + int physical_reg_addr; + int virtual_mem_addr; + int virtual_reg_addr; + + struct wl12xx_chip chip; + + int cmd_box_addr; + int event_box_addr; + struct boot_attr boot_attr; + + u8 *fw; + size_t fw_len; + u8 *nvs; + size_t nvs_len; + + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; + u8 bss_type; + u8 listen_int; + int channel; + + void *target_mem_map; + struct acx_data_path_params_resp *data_path; + + /* Number of TX packets transferred to the FW, modulo 16 */ + u32 data_in_count; + + /* Frames scheduled for transmission, not handled yet */ + struct sk_buff_head tx_queue; + bool tx_queue_stopped; + + struct work_struct tx_work; + struct work_struct filter_work; + + /* Pending TX frames */ + struct sk_buff *tx_frames[16]; + + /* + * Index pointing to the next TX complete entry + * in the cyclic XT complete array we get from + * the FW. + */ + u32 next_tx_complete; + + /* FW Rx counter */ + u32 rx_counter; + + /* Rx frames handled */ + u32 rx_handled; + + /* Current double buffer */ + u32 rx_current_buffer; + u32 rx_last_id; + + /* The target interrupt mask */ + u32 intr_mask; + struct work_struct irq_work; + + /* The mbox event mask */ + u32 event_mask; + + /* Mailbox pointers */ + u32 mbox_ptr[2]; + + /* Are we currently scanning */ + bool scanning; + + /* Our association ID */ + u16 aid; + + /* Default key (for WEP) */ + u32 default_key; + + unsigned int tx_mgmt_frm_rate; + unsigned int tx_mgmt_frm_mod; + + unsigned int rx_config; + unsigned int rx_filter; + + /* is firmware in elp mode */ + bool elp; + + /* we can be in psm, but not in elp, we have to differentiate */ + bool psm; + + /* PSM mode requested */ + bool psm_requested; + + /* in dBm */ + int power_level; + + struct wl12xx_stats stats; + struct wl12xx_debugfs debugfs; + + u32 buffer_32; + u32 buffer_cmd; + u8 buffer_busyword[WL12XX_BUSY_WORD_LEN]; + struct wl12xx_rx_descriptor *rx_descriptor; +}; + +int wl12xx_plt_start(struct wl12xx *wl); +int wl12xx_plt_stop(struct wl12xx *wl); + +#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ +#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS +#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ + +#define WL12XX_DEFAULT_POWER_LEVEL 20 + +#define WL12XX_TX_QUEUE_MAX_LENGTH 20 + +/* Different chips need different sleep times after power on. WL1271 needs + * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we + * know the chip ID, we change the sleep value in the wl12xx chip structure, + * so in subsequent power ons, we don't waste more time then needed. */ +#define WL12XX_DEFAULT_POWER_ON_SLEEP 200 + +#define CHIP_ID_1251_PG10 (0x7010101) +#define CHIP_ID_1251_PG11 (0x7020101) +#define CHIP_ID_1251_PG12 (0x7030101) +#define CHIP_ID_1271_PG10 (0x4030101) +#define CHIP_ID_1271_PG20 (0x4030111) + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index cecc1fa..1a840fa 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -4,7 +4,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 203f11f..a239120 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -25,7 +25,7 @@ #ifndef __WL12XX_ACX_H__ #define __WL12XX_ACX_H__ -#include "wl12xx.h" +#include "wl1251.h" #include "wl1251_cmd.h" /* Target's information element */ diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h index 4fa7313..3e2b766 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.h +++ b/drivers/net/wireless/wl12xx/wl1251_boot.h @@ -24,7 +24,7 @@ #ifndef __BOOT_H__ #define __BOOT_H__ -#include "wl12xx.h" +#include "wl1251.h" int wl12xx_boot_soft_reset(struct wl12xx *wl); int wl12xx_boot_init_seq(struct wl12xx *wl); diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index d0c2df6..92c7fb6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -4,7 +4,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index a2eae54..b252ad2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -25,7 +25,7 @@ #ifndef __WL12XX_CMD_H__ #define __WL12XX_CMD_H__ -#include "wl12xx.h" +#include "wl1251.h" struct acx_header; diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c index a63bc78..866303d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -25,7 +25,7 @@ #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl1251_acx.h" #include "wl1251_ps.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h index 562cdcb..37653eb 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.h +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.h @@ -24,7 +24,7 @@ #ifndef WL12XX_DEBUGFS_H #define WL12XX_DEBUGFS_H -#include "wl12xx.h" +#include "wl1251.h" int wl12xx_debugfs_init(struct wl12xx *wl); void wl12xx_debugfs_exit(struct wl12xx *wl); diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 50b5e43..a6d9234 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -22,7 +22,7 @@ * */ -#include "wl12xx.h" +#include "wl1251.h" #include "reg.h" #include "wl1251_spi.h" #include "wl1251_event.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index c8b6cd0..5b3301a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -24,7 +24,7 @@ #ifndef __WL12XX_INIT_H__ #define __WL12XX_INIT_H__ -#include "wl12xx.h" +#include "wl1251.h" int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); int wl12xx_hw_init_templates_config(struct wl12xx *wl); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 16cd46c..41b9c616 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -31,7 +31,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_ops.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c index 1bc049f..ca9a856 100644 --- a/drivers/net/wireless/wl12xx/wl1251_netlink.c +++ b/drivers/net/wireless/wl12xx/wl1251_netlink.c @@ -30,7 +30,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl1251_spi.h" #include "wl1251_acx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h index 7a78cc9..c5c997b 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.h +++ b/drivers/net/wireless/wl12xx/wl1251_ops.h @@ -26,7 +26,7 @@ #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl1251_acx.h" #define WL1251_FW_NAME "wl1251-fw.bin" diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h index db9f7ed..8877842 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.h +++ b/drivers/net/wireless/wl12xx/wl1251_ps.h @@ -25,7 +25,7 @@ * */ -#include "wl12xx.h" +#include "wl1251.h" #include "wl1251_acx.h" int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode); diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index d73e014..280fc18 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -25,7 +25,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "reg.h" #include "wl1251_spi.h" #include "wl1251_rx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h index 8a23fde..4379c53 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.h +++ b/drivers/net/wireless/wl12xx/wl1251_rx.h @@ -27,6 +27,8 @@ #include +#include "wl1251.h" + /* * RX PATH * diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index d7eee8c..5b4889e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -25,7 +25,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index c57330e..00c5649 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -25,7 +25,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "reg.h" #include "wl1251_spi.h" #include "wl1251_tx.h" diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h deleted file mode 100644 index c673cdb..0000000 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ /dev/null @@ -1,420 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_H__ -#define __WL12XX_H__ - -#include -#include -#include -#include - -#define DRIVER_NAME "wl12xx" -#define DRIVER_PREFIX DRIVER_NAME ": " - -enum { - DEBUG_NONE = 0, - DEBUG_IRQ = BIT(0), - DEBUG_SPI = BIT(1), - DEBUG_BOOT = BIT(2), - DEBUG_MAILBOX = BIT(3), - DEBUG_NETLINK = BIT(4), - DEBUG_EVENT = BIT(5), - DEBUG_TX = BIT(6), - DEBUG_RX = BIT(7), - DEBUG_SCAN = BIT(8), - DEBUG_CRYPT = BIT(9), - DEBUG_PSM = BIT(10), - DEBUG_MAC80211 = BIT(11), - DEBUG_CMD = BIT(12), - DEBUG_ACX = BIT(13), - DEBUG_ALL = ~0, -}; - -#define DEBUG_LEVEL (DEBUG_NONE) - -#define DEBUG_DUMP_LIMIT 1024 - -#define wl12xx_error(fmt, arg...) \ - printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) - -#define wl12xx_warning(fmt, arg...) \ - printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) - -#define wl12xx_notice(fmt, arg...) \ - printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) - -#define wl12xx_info(fmt, arg...) \ - printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) - -#define wl12xx_debug(level, fmt, arg...) \ - do { \ - if (level & DEBUG_LEVEL) \ - printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ - } while (0) - -#define wl12xx_dump(level, prefix, buf, len) \ - do { \ - if (level & DEBUG_LEVEL) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - 0); \ - } while (0) - -#define wl12xx_dump_ascii(level, prefix, buf, len) \ - do { \ - if (level & DEBUG_LEVEL) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - true); \ - } while (0) - -#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ - CFG_BSSID_FILTER_EN) - -#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ - CFG_RX_MGMT_EN | \ - CFG_RX_DATA_EN | \ - CFG_RX_CTL_EN | \ - CFG_RX_BCN_EN | \ - CFG_RX_AUTH_EN | \ - CFG_RX_ASSOC_EN) - -#define WL12XX_BUSY_WORD_LEN 8 - -struct boot_attr { - u32 radio_type; - u8 mac_clock; - u8 arm_clock; - int firmware_debug; - u32 minor; - u32 major; - u32 bugfix; -}; - -enum wl12xx_state { - WL12XX_STATE_OFF, - WL12XX_STATE_ON, - WL12XX_STATE_PLT, -}; - -enum wl12xx_partition_type { - PART_DOWN, - PART_WORK, - PART_DRPW, - - PART_TABLE_LEN -}; - -struct wl12xx_partition { - u32 size; - u32 start; -}; - -struct wl12xx_partition_set { - struct wl12xx_partition mem; - struct wl12xx_partition reg; -}; - -struct wl12xx; - -/* FIXME: I'm not sure about this structure name */ -struct wl12xx_chip { - u32 id; - - const char *fw_filename; - const char *nvs_filename; - - char fw_ver[21]; - - unsigned int power_on_sleep; - int intr_cmd_complete; - int intr_init_complete; - - int (*op_upload_fw)(struct wl12xx *wl); - int (*op_upload_nvs)(struct wl12xx *wl); - int (*op_boot)(struct wl12xx *wl); - void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag); - void (*op_target_enable_interrupts)(struct wl12xx *wl); - int (*op_hw_init)(struct wl12xx *wl); - int (*op_plt_init)(struct wl12xx *wl); - void (*op_tx_flush)(struct wl12xx *wl); - void (*op_fw_version)(struct wl12xx *wl); - int (*op_cmd_join)(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait); - - struct wl12xx_partition_set *p_table; - enum wl12xx_acx_int_reg *acx_reg_table; -}; - -struct wl12xx_stats { - struct acx_statistics *fw_stats; - unsigned long fw_stats_update; - - unsigned int retry_count; - unsigned int excessive_retries; -}; - -struct wl12xx_debugfs { - struct dentry *rootdir; - struct dentry *fw_statistics; - - struct dentry *tx_internal_desc_overflow; - - struct dentry *rx_out_of_mem; - struct dentry *rx_hdr_overflow; - struct dentry *rx_hw_stuck; - struct dentry *rx_dropped; - struct dentry *rx_fcs_err; - struct dentry *rx_xfr_hint_trig; - struct dentry *rx_path_reset; - struct dentry *rx_reset_counter; - - struct dentry *dma_rx_requested; - struct dentry *dma_rx_errors; - struct dentry *dma_tx_requested; - struct dentry *dma_tx_errors; - - struct dentry *isr_cmd_cmplt; - struct dentry *isr_fiqs; - struct dentry *isr_rx_headers; - struct dentry *isr_rx_mem_overflow; - struct dentry *isr_rx_rdys; - struct dentry *isr_irqs; - struct dentry *isr_tx_procs; - struct dentry *isr_decrypt_done; - struct dentry *isr_dma0_done; - struct dentry *isr_dma1_done; - struct dentry *isr_tx_exch_complete; - struct dentry *isr_commands; - struct dentry *isr_rx_procs; - struct dentry *isr_hw_pm_mode_changes; - struct dentry *isr_host_acknowledges; - struct dentry *isr_pci_pm; - struct dentry *isr_wakeups; - struct dentry *isr_low_rssi; - - struct dentry *wep_addr_key_count; - struct dentry *wep_default_key_count; - /* skipping wep.reserved */ - struct dentry *wep_key_not_found; - struct dentry *wep_decrypt_fail; - struct dentry *wep_packets; - struct dentry *wep_interrupt; - - struct dentry *pwr_ps_enter; - struct dentry *pwr_elp_enter; - struct dentry *pwr_missing_bcns; - struct dentry *pwr_wake_on_host; - struct dentry *pwr_wake_on_timer_exp; - struct dentry *pwr_tx_with_ps; - struct dentry *pwr_tx_without_ps; - struct dentry *pwr_rcvd_beacons; - struct dentry *pwr_power_save_off; - struct dentry *pwr_enable_ps; - struct dentry *pwr_disable_ps; - struct dentry *pwr_fix_tsf_ps; - /* skipping cont_miss_bcns_spread for now */ - struct dentry *pwr_rcvd_awake_beacons; - - struct dentry *mic_rx_pkts; - struct dentry *mic_calc_failure; - - struct dentry *aes_encrypt_fail; - struct dentry *aes_decrypt_fail; - struct dentry *aes_encrypt_packets; - struct dentry *aes_decrypt_packets; - struct dentry *aes_encrypt_interrupt; - struct dentry *aes_decrypt_interrupt; - - struct dentry *event_heart_beat; - struct dentry *event_calibration; - struct dentry *event_rx_mismatch; - struct dentry *event_rx_mem_empty; - struct dentry *event_rx_pool; - struct dentry *event_oom_late; - struct dentry *event_phy_transmit_error; - struct dentry *event_tx_stuck; - - struct dentry *ps_pspoll_timeouts; - struct dentry *ps_upsd_timeouts; - struct dentry *ps_upsd_max_sptime; - struct dentry *ps_upsd_max_apturn; - struct dentry *ps_pspoll_max_apturn; - struct dentry *ps_pspoll_utilization; - struct dentry *ps_upsd_utilization; - - struct dentry *rxpipe_rx_prep_beacon_drop; - struct dentry *rxpipe_descr_host_int_trig_rx_data; - struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; - struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; - struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; - - struct dentry *tx_queue_len; - - struct dentry *retry_count; - struct dentry *excessive_retries; -}; - -struct wl12xx { - struct ieee80211_hw *hw; - bool mac80211_registered; - - struct spi_device *spi; - - void (*set_power)(bool enable); - int irq; - - enum wl12xx_state state; - struct mutex mutex; - - int physical_mem_addr; - int physical_reg_addr; - int virtual_mem_addr; - int virtual_reg_addr; - - struct wl12xx_chip chip; - - int cmd_box_addr; - int event_box_addr; - struct boot_attr boot_attr; - - u8 *fw; - size_t fw_len; - u8 *nvs; - size_t nvs_len; - - u8 bssid[ETH_ALEN]; - u8 mac_addr[ETH_ALEN]; - u8 bss_type; - u8 listen_int; - int channel; - - void *target_mem_map; - struct acx_data_path_params_resp *data_path; - - /* Number of TX packets transferred to the FW, modulo 16 */ - u32 data_in_count; - - /* Frames scheduled for transmission, not handled yet */ - struct sk_buff_head tx_queue; - bool tx_queue_stopped; - - struct work_struct tx_work; - struct work_struct filter_work; - - /* Pending TX frames */ - struct sk_buff *tx_frames[16]; - - /* - * Index pointing to the next TX complete entry - * in the cyclic XT complete array we get from - * the FW. - */ - u32 next_tx_complete; - - /* FW Rx counter */ - u32 rx_counter; - - /* Rx frames handled */ - u32 rx_handled; - - /* Current double buffer */ - u32 rx_current_buffer; - u32 rx_last_id; - - /* The target interrupt mask */ - u32 intr_mask; - struct work_struct irq_work; - - /* The mbox event mask */ - u32 event_mask; - - /* Mailbox pointers */ - u32 mbox_ptr[2]; - - /* Are we currently scanning */ - bool scanning; - - /* Our association ID */ - u16 aid; - - /* Default key (for WEP) */ - u32 default_key; - - unsigned int tx_mgmt_frm_rate; - unsigned int tx_mgmt_frm_mod; - - unsigned int rx_config; - unsigned int rx_filter; - - /* is firmware in elp mode */ - bool elp; - - /* we can be in psm, but not in elp, we have to differentiate */ - bool psm; - - /* PSM mode requested */ - bool psm_requested; - - /* in dBm */ - int power_level; - - struct wl12xx_stats stats; - struct wl12xx_debugfs debugfs; - - u32 buffer_32; - u32 buffer_cmd; - u8 buffer_busyword[WL12XX_BUSY_WORD_LEN]; - struct wl12xx_rx_descriptor *rx_descriptor; -}; - -int wl12xx_plt_start(struct wl12xx *wl); -int wl12xx_plt_stop(struct wl12xx *wl); - -#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ -#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS -#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ - -#define WL12XX_DEFAULT_POWER_LEVEL 20 - -#define WL12XX_TX_QUEUE_MAX_LENGTH 20 - -/* Different chips need different sleep times after power on. WL1271 needs - * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we - * know the chip ID, we change the sleep value in the wl12xx chip structure, - * so in subsequent power ons, we don't waste more time then needed. */ -#define WL12XX_DEFAULT_POWER_ON_SLEEP 200 - -#define CHIP_ID_1251_PG10 (0x7010101) -#define CHIP_ID_1251_PG11 (0x7020101) -#define CHIP_ID_1251_PG12 (0x7030101) -#define CHIP_ID_1271_PG10 (0x4030101) -#define CHIP_ID_1271_PG20 (0x4030111) - -#endif -- cgit v0.10.2 From 1e6f172fccbf1194bad4b2aeae437ec3189a3f08 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:33 +0300 Subject: wl12xx: remove unused wl12xx_hw_init_mem_config() The function declaration is a leftover from some earlier, already removed, code. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index 5b3301a..2b6268e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -28,7 +28,6 @@ int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); int wl12xx_hw_init_templates_config(struct wl12xx *wl); -int wl12xx_hw_init_mem_config(struct wl12xx *wl); int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter); int wl12xx_hw_init_phy_config(struct wl12xx *wl); int wl12xx_hw_init_beacon_filter(struct wl12xx *wl); -- cgit v0.10.2 From 80301cdcfe44e3533175be23d7d52a9fc8c3fdb0 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:39 +0300 Subject: wl1251: use wl1251 prefix everywhere Last we can change all code prefixes from wl12xx/WL12XX to wl1251/WL1251. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index c673cdb..665aca0 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008-2009 Nokia Corporation @@ -22,15 +22,15 @@ * */ -#ifndef __WL12XX_H__ -#define __WL12XX_H__ +#ifndef __WL1251_H__ +#define __WL1251_H__ #include #include #include #include -#define DRIVER_NAME "wl12xx" +#define DRIVER_NAME "wl1251" #define DRIVER_PREFIX DRIVER_NAME ": " enum { @@ -56,25 +56,25 @@ enum { #define DEBUG_DUMP_LIMIT 1024 -#define wl12xx_error(fmt, arg...) \ +#define wl1251_error(fmt, arg...) \ printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) -#define wl12xx_warning(fmt, arg...) \ +#define wl1251_warning(fmt, arg...) \ printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) -#define wl12xx_notice(fmt, arg...) \ +#define wl1251_notice(fmt, arg...) \ printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) -#define wl12xx_info(fmt, arg...) \ +#define wl1251_info(fmt, arg...) \ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) -#define wl12xx_debug(level, fmt, arg...) \ +#define wl1251_debug(level, fmt, arg...) \ do { \ if (level & DEBUG_LEVEL) \ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ } while (0) -#define wl12xx_dump(level, prefix, buf, len) \ +#define wl1251_dump(level, prefix, buf, len) \ do { \ if (level & DEBUG_LEVEL) \ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ @@ -84,7 +84,7 @@ enum { 0); \ } while (0) -#define wl12xx_dump_ascii(level, prefix, buf, len) \ +#define wl1251_dump_ascii(level, prefix, buf, len) \ do { \ if (level & DEBUG_LEVEL) \ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ @@ -94,10 +94,10 @@ enum { true); \ } while (0) -#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ +#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ CFG_BSSID_FILTER_EN) -#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ +#define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ CFG_RX_MGMT_EN | \ CFG_RX_DATA_EN | \ CFG_RX_CTL_EN | \ @@ -105,7 +105,7 @@ enum { CFG_RX_AUTH_EN | \ CFG_RX_ASSOC_EN) -#define WL12XX_BUSY_WORD_LEN 8 +#define WL1251_BUSY_WORD_LEN 8 struct boot_attr { u32 radio_type; @@ -117,13 +117,13 @@ struct boot_attr { u32 bugfix; }; -enum wl12xx_state { - WL12XX_STATE_OFF, - WL12XX_STATE_ON, - WL12XX_STATE_PLT, +enum wl1251_state { + WL1251_STATE_OFF, + WL1251_STATE_ON, + WL1251_STATE_PLT, }; -enum wl12xx_partition_type { +enum wl1251_partition_type { PART_DOWN, PART_WORK, PART_DRPW, @@ -131,20 +131,20 @@ enum wl12xx_partition_type { PART_TABLE_LEN }; -struct wl12xx_partition { +struct wl1251_partition { u32 size; u32 start; }; -struct wl12xx_partition_set { - struct wl12xx_partition mem; - struct wl12xx_partition reg; +struct wl1251_partition_set { + struct wl1251_partition mem; + struct wl1251_partition reg; }; -struct wl12xx; +struct wl1251; /* FIXME: I'm not sure about this structure name */ -struct wl12xx_chip { +struct wl1251_chip { u32 id; const char *fw_filename; @@ -156,23 +156,23 @@ struct wl12xx_chip { int intr_cmd_complete; int intr_init_complete; - int (*op_upload_fw)(struct wl12xx *wl); - int (*op_upload_nvs)(struct wl12xx *wl); - int (*op_boot)(struct wl12xx *wl); - void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag); - void (*op_target_enable_interrupts)(struct wl12xx *wl); - int (*op_hw_init)(struct wl12xx *wl); - int (*op_plt_init)(struct wl12xx *wl); - void (*op_tx_flush)(struct wl12xx *wl); - void (*op_fw_version)(struct wl12xx *wl); - int (*op_cmd_join)(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + int (*op_upload_fw)(struct wl1251 *wl); + int (*op_upload_nvs)(struct wl1251 *wl); + int (*op_boot)(struct wl1251 *wl); + void (*op_set_ecpu_ctrl)(struct wl1251 *wl, u32 flag); + void (*op_target_enable_interrupts)(struct wl1251 *wl); + int (*op_hw_init)(struct wl1251 *wl); + int (*op_plt_init)(struct wl1251 *wl); + void (*op_tx_flush)(struct wl1251 *wl); + void (*op_fw_version)(struct wl1251 *wl); + int (*op_cmd_join)(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait); - struct wl12xx_partition_set *p_table; + struct wl1251_partition_set *p_table; enum wl12xx_acx_int_reg *acx_reg_table; }; -struct wl12xx_stats { +struct wl1251_stats { struct acx_statistics *fw_stats; unsigned long fw_stats_update; @@ -180,7 +180,7 @@ struct wl12xx_stats { unsigned int excessive_retries; }; -struct wl12xx_debugfs { +struct wl1251_debugfs { struct dentry *rootdir; struct dentry *fw_statistics; @@ -281,7 +281,7 @@ struct wl12xx_debugfs { struct dentry *excessive_retries; }; -struct wl12xx { +struct wl1251 { struct ieee80211_hw *hw; bool mac80211_registered; @@ -290,7 +290,7 @@ struct wl12xx { void (*set_power)(bool enable); int irq; - enum wl12xx_state state; + enum wl1251_state state; struct mutex mutex; int physical_mem_addr; @@ -298,7 +298,7 @@ struct wl12xx { int virtual_mem_addr; int virtual_reg_addr; - struct wl12xx_chip chip; + struct wl1251_chip chip; int cmd_box_addr; int event_box_addr; @@ -385,31 +385,31 @@ struct wl12xx { /* in dBm */ int power_level; - struct wl12xx_stats stats; - struct wl12xx_debugfs debugfs; + struct wl1251_stats stats; + struct wl1251_debugfs debugfs; u32 buffer_32; u32 buffer_cmd; - u8 buffer_busyword[WL12XX_BUSY_WORD_LEN]; - struct wl12xx_rx_descriptor *rx_descriptor; + u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; + struct wl1251_rx_descriptor *rx_descriptor; }; -int wl12xx_plt_start(struct wl12xx *wl); -int wl12xx_plt_stop(struct wl12xx *wl); +int wl1251_plt_start(struct wl1251 *wl); +int wl1251_plt_stop(struct wl1251 *wl); #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ -#define WL12XX_DEFAULT_POWER_LEVEL 20 +#define WL1251_DEFAULT_POWER_LEVEL 20 -#define WL12XX_TX_QUEUE_MAX_LENGTH 20 +#define WL1251_TX_QUEUE_MAX_LENGTH 20 /* Different chips need different sleep times after power on. WL1271 needs * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we - * know the chip ID, we change the sleep value in the wl12xx chip structure, + * know the chip ID, we change the sleep value in the wl1251 chip structure, * so in subsequent power ons, we don't waste more time then needed. */ -#define WL12XX_DEFAULT_POWER_ON_SLEEP 200 +#define WL1251_DEFAULT_POWER_ON_SLEEP 200 #define CHIP_ID_1251_PG10 (0x7010101) #define CHIP_ID_1251_PG11 (0x7020101) diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 1a840fa..5a8d21c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -5,18 +5,17 @@ #include #include "wl1251.h" -#include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" #include "wl1251_ps.h" -int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, +int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, u8 mgt_rate, u8 mgt_mod) { struct acx_fw_gen_frame_rates *rates; int ret; - wl12xx_debug(DEBUG_ACX, "acx frame rates"); + wl1251_debug(DEBUG_ACX, "acx frame rates"); rates = kzalloc(sizeof(*rates), GFP_KERNEL); if (!rates) { @@ -29,10 +28,10 @@ int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, rates->tx_mgt_frame_rate = mgt_rate; rates->tx_mgt_frame_mod = mgt_mod; - ret = wl12xx_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, + ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, rates, sizeof(*rates)); if (ret < 0) { - wl12xx_error("Failed to set FW rates and modulation"); + wl1251_error("Failed to set FW rates and modulation"); goto out; } @@ -42,12 +41,12 @@ out: } -int wl12xx_acx_station_id(struct wl12xx *wl) +int wl1251_acx_station_id(struct wl1251 *wl) { struct acx_dot11_station_id *mac; int ret, i; - wl12xx_debug(DEBUG_ACX, "acx dot11_station_id"); + wl1251_debug(DEBUG_ACX, "acx dot11_station_id"); mac = kzalloc(sizeof(*mac), GFP_KERNEL); if (!mac) { @@ -58,7 +57,7 @@ int wl12xx_acx_station_id(struct wl12xx *wl) for (i = 0; i < ETH_ALEN; i++) mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; - ret = wl12xx_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); + ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); if (ret < 0) goto out; @@ -67,12 +66,12 @@ out: return ret; } -int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) +int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id) { struct acx_dot11_default_key *default_key; int ret; - wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); + wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); if (!default_key) { @@ -82,10 +81,10 @@ int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) default_key->id = key_id; - ret = wl12xx_cmd_configure(wl, DOT11_DEFAULT_KEY, + ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY, default_key, sizeof(*default_key)); if (ret < 0) { - wl12xx_error("Couldnt set default key"); + wl1251_error("Couldnt set default key"); goto out; } @@ -96,13 +95,13 @@ out: return ret; } -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, +int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, u8 listen_interval) { struct acx_wake_up_condition *wake_up; int ret; - wl12xx_debug(DEBUG_ACX, "acx wake up conditions"); + wl1251_debug(DEBUG_ACX, "acx wake up conditions"); wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); if (!wake_up) { @@ -113,10 +112,10 @@ int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, wake_up->wake_up_event = wake_up_event; wake_up->listen_interval = listen_interval; - ret = wl12xx_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, + ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, wake_up, sizeof(*wake_up)); if (ret < 0) { - wl12xx_warning("could not set wake up conditions: %d", ret); + wl1251_warning("could not set wake up conditions: %d", ret); goto out; } @@ -125,12 +124,12 @@ out: return ret; } -int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) +int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth) { struct acx_sleep_auth *auth; int ret; - wl12xx_debug(DEBUG_ACX, "acx sleep auth"); + wl1251_debug(DEBUG_ACX, "acx sleep auth"); auth = kzalloc(sizeof(*auth), GFP_KERNEL); if (!auth) { @@ -140,7 +139,7 @@ int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) auth->sleep_auth = sleep_auth; - ret = wl12xx_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); + ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); if (ret < 0) return ret; @@ -149,12 +148,12 @@ out: return ret; } -int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) +int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len) { struct acx_revision *rev; int ret; - wl12xx_debug(DEBUG_ACX, "acx fw rev"); + wl1251_debug(DEBUG_ACX, "acx fw rev"); rev = kzalloc(sizeof(*rev), GFP_KERNEL); if (!rev) { @@ -162,9 +161,9 @@ int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) goto out; } - ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); + ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); if (ret < 0) { - wl12xx_warning("ACX_FW_REV interrogate failed"); + wl1251_warning("ACX_FW_REV interrogate failed"); goto out; } @@ -183,12 +182,12 @@ out: return ret; } -int wl12xx_acx_tx_power(struct wl12xx *wl, int power) +int wl1251_acx_tx_power(struct wl1251 *wl, int power) { struct acx_current_tx_power *acx; int ret; - wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); + wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); if (power < 0 || power > 25) return -EINVAL; @@ -201,9 +200,9 @@ int wl12xx_acx_tx_power(struct wl12xx *wl, int power) acx->current_tx_power = power * 10; - ret = wl12xx_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); + ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_warning("configure of tx power failed: %d", ret); + wl1251_warning("configure of tx power failed: %d", ret); goto out; } @@ -212,12 +211,12 @@ out: return ret; } -int wl12xx_acx_feature_cfg(struct wl12xx *wl) +int wl1251_acx_feature_cfg(struct wl1251 *wl) { struct acx_feature_config *feature; int ret; - wl12xx_debug(DEBUG_ACX, "acx feature cfg"); + wl1251_debug(DEBUG_ACX, "acx feature cfg"); feature = kzalloc(sizeof(*feature), GFP_KERNEL); if (!feature) { @@ -229,10 +228,10 @@ int wl12xx_acx_feature_cfg(struct wl12xx *wl) feature->data_flow_options = 0; feature->options = 0; - ret = wl12xx_cmd_configure(wl, ACX_FEATURE_CFG, + ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, feature, sizeof(*feature)); if (ret < 0) { - wl12xx_error("Couldnt set HW encryption"); + wl1251_error("Couldnt set HW encryption"); goto out; } @@ -241,27 +240,27 @@ out: return ret; } -int wl12xx_acx_mem_map(struct wl12xx *wl, struct acx_header *mem_map, +int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, size_t len) { int ret; - wl12xx_debug(DEBUG_ACX, "acx mem map"); + wl1251_debug(DEBUG_ACX, "acx mem map"); - ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); + ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); if (ret < 0) return ret; return 0; } -int wl12xx_acx_data_path_params(struct wl12xx *wl, +int wl1251_acx_data_path_params(struct wl1251 *wl, struct acx_data_path_params_resp *resp) { struct acx_data_path_params *params; int ret; - wl12xx_debug(DEBUG_ACX, "acx data path params"); + wl1251_debug(DEBUG_ACX, "acx data path params"); params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) { @@ -281,20 +280,20 @@ int wl12xx_acx_data_path_params(struct wl12xx *wl, params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; - ret = wl12xx_cmd_configure(wl, ACX_DATA_PATH_PARAMS, + ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS, params, sizeof(*params)); if (ret < 0) goto out; /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ - ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, + ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, resp, sizeof(*resp)); if (ret < 0) { - wl12xx_warning("failed to read data path parameters: %d", ret); + wl1251_warning("failed to read data path parameters: %d", ret); goto out; } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { - wl12xx_warning("data path parameter acx status failed"); + wl1251_warning("data path parameter acx status failed"); ret = -EIO; goto out; } @@ -304,12 +303,12 @@ out: return ret; } -int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) +int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time) { struct acx_rx_msdu_lifetime *acx; int ret; - wl12xx_debug(DEBUG_ACX, "acx rx msdu life time"); + wl1251_debug(DEBUG_ACX, "acx rx msdu life time"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -318,10 +317,10 @@ int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) } acx->lifetime = life_time; - ret = wl12xx_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, + ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_warning("failed to set rx msdu life time: %d", ret); + wl1251_warning("failed to set rx msdu life time: %d", ret); goto out; } @@ -330,12 +329,12 @@ out: return ret; } -int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) +int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter) { struct acx_rx_config *rx_config; int ret; - wl12xx_debug(DEBUG_ACX, "acx rx config"); + wl1251_debug(DEBUG_ACX, "acx rx config"); rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); if (!rx_config) { @@ -346,10 +345,10 @@ int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) rx_config->config_options = config; rx_config->filter_options = filter; - ret = wl12xx_cmd_configure(wl, ACX_RX_CFG, + ret = wl1251_cmd_configure(wl, ACX_RX_CFG, rx_config, sizeof(*rx_config)); if (ret < 0) { - wl12xx_warning("failed to set rx config: %d", ret); + wl1251_warning("failed to set rx config: %d", ret); goto out; } @@ -358,12 +357,12 @@ out: return ret; } -int wl12xx_acx_pd_threshold(struct wl12xx *wl) +int wl1251_acx_pd_threshold(struct wl1251 *wl) { struct acx_packet_detection *pd; int ret; - wl12xx_debug(DEBUG_ACX, "acx data pd threshold"); + wl1251_debug(DEBUG_ACX, "acx data pd threshold"); pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) { @@ -373,9 +372,9 @@ int wl12xx_acx_pd_threshold(struct wl12xx *wl) /* FIXME: threshold value not set */ - ret = wl12xx_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); + ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); if (ret < 0) { - wl12xx_warning("failed to set pd threshold: %d", ret); + wl1251_warning("failed to set pd threshold: %d", ret); goto out; } @@ -384,12 +383,12 @@ out: return 0; } -int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) +int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time) { struct acx_slot *slot; int ret; - wl12xx_debug(DEBUG_ACX, "acx slot"); + wl1251_debug(DEBUG_ACX, "acx slot"); slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) { @@ -400,9 +399,9 @@ int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) slot->wone_index = STATION_WONE_INDEX; slot->slot_time = slot_time; - ret = wl12xx_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); + ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); if (ret < 0) { - wl12xx_warning("failed to set slot time: %d", ret); + wl1251_warning("failed to set slot time: %d", ret); goto out; } @@ -411,12 +410,12 @@ out: return ret; } -int wl12xx_acx_group_address_tbl(struct wl12xx *wl) +int wl1251_acx_group_address_tbl(struct wl1251 *wl) { struct acx_dot11_grp_addr_tbl *acx; int ret; - wl12xx_debug(DEBUG_ACX, "acx group address tbl"); + wl1251_debug(DEBUG_ACX, "acx group address tbl"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -429,10 +428,10 @@ int wl12xx_acx_group_address_tbl(struct wl12xx *wl) acx->num_groups = 0; memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); - ret = wl12xx_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_warning("failed to set group addr table: %d", ret); + wl1251_warning("failed to set group addr table: %d", ret); goto out; } @@ -441,7 +440,7 @@ out: return ret; } -int wl12xx_acx_service_period_timeout(struct wl12xx *wl) +int wl1251_acx_service_period_timeout(struct wl1251 *wl) { struct acx_rx_timeout *rx_timeout; int ret; @@ -452,15 +451,15 @@ int wl12xx_acx_service_period_timeout(struct wl12xx *wl) goto out; } - wl12xx_debug(DEBUG_ACX, "acx service period timeout"); + wl1251_debug(DEBUG_ACX, "acx service period timeout"); rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; - ret = wl12xx_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, + ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, rx_timeout, sizeof(*rx_timeout)); if (ret < 0) { - wl12xx_warning("failed to set service period timeout: %d", + wl1251_warning("failed to set service period timeout: %d", ret); goto out; } @@ -470,12 +469,12 @@ out: return ret; } -int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) +int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold) { struct acx_rts_threshold *rts; int ret; - wl12xx_debug(DEBUG_ACX, "acx rts threshold"); + wl1251_debug(DEBUG_ACX, "acx rts threshold"); rts = kzalloc(sizeof(*rts), GFP_KERNEL); if (!rts) { @@ -485,9 +484,9 @@ int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) rts->threshold = rts_threshold; - ret = wl12xx_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); + ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); if (ret < 0) { - wl12xx_warning("failed to set rts threshold: %d", ret); + wl1251_warning("failed to set rts threshold: %d", ret); goto out; } @@ -496,12 +495,12 @@ out: return ret; } -int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) +int wl1251_acx_beacon_filter_opt(struct wl1251 *wl) { struct acx_beacon_filter_option *beacon_filter; int ret; - wl12xx_debug(DEBUG_ACX, "acx beacon filter opt"); + wl1251_debug(DEBUG_ACX, "acx beacon filter opt"); beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); if (!beacon_filter) { @@ -512,10 +511,10 @@ int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) beacon_filter->enable = 0; beacon_filter->max_num_beacons = 0; - ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_OPT, + ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT, beacon_filter, sizeof(*beacon_filter)); if (ret < 0) { - wl12xx_warning("failed to set beacon filter opt: %d", ret); + wl1251_warning("failed to set beacon filter opt: %d", ret); goto out; } @@ -524,12 +523,12 @@ out: return ret; } -int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) +int wl1251_acx_beacon_filter_table(struct wl1251 *wl) { struct acx_beacon_filter_ie_table *ie_table; int ret; - wl12xx_debug(DEBUG_ACX, "acx beacon filter table"); + wl1251_debug(DEBUG_ACX, "acx beacon filter table"); ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); if (!ie_table) { @@ -540,10 +539,10 @@ int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) ie_table->num_ie = 0; memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); - ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, + ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, ie_table, sizeof(*ie_table)); if (ret < 0) { - wl12xx_warning("failed to set beacon filter table: %d", ret); + wl1251_warning("failed to set beacon filter table: %d", ret); goto out; } @@ -552,12 +551,12 @@ out: return ret; } -int wl12xx_acx_sg_enable(struct wl12xx *wl) +int wl1251_acx_sg_enable(struct wl1251 *wl) { struct acx_bt_wlan_coex *pta; int ret; - wl12xx_debug(DEBUG_ACX, "acx sg enable"); + wl1251_debug(DEBUG_ACX, "acx sg enable"); pta = kzalloc(sizeof(*pta), GFP_KERNEL); if (!pta) { @@ -567,9 +566,9 @@ int wl12xx_acx_sg_enable(struct wl12xx *wl) pta->enable = SG_ENABLE; - ret = wl12xx_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); + ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); if (ret < 0) { - wl12xx_warning("failed to set softgemini enable: %d", ret); + wl1251_warning("failed to set softgemini enable: %d", ret); goto out; } @@ -578,12 +577,12 @@ out: return ret; } -int wl12xx_acx_sg_cfg(struct wl12xx *wl) +int wl1251_acx_sg_cfg(struct wl1251 *wl) { struct acx_bt_wlan_coex_param *param; int ret; - wl12xx_debug(DEBUG_ACX, "acx sg cfg"); + wl1251_debug(DEBUG_ACX, "acx sg cfg"); param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) { @@ -621,9 +620,9 @@ int wl12xx_acx_sg_cfg(struct wl12xx *wl) param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; - ret = wl12xx_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); + ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); if (ret < 0) { - wl12xx_warning("failed to set sg config: %d", ret); + wl1251_warning("failed to set sg config: %d", ret); goto out; } @@ -632,12 +631,12 @@ out: return ret; } -int wl12xx_acx_cca_threshold(struct wl12xx *wl) +int wl1251_acx_cca_threshold(struct wl1251 *wl) { struct acx_energy_detection *detection; int ret; - wl12xx_debug(DEBUG_ACX, "acx cca threshold"); + wl1251_debug(DEBUG_ACX, "acx cca threshold"); detection = kzalloc(sizeof(*detection), GFP_KERNEL); if (!detection) { @@ -648,10 +647,10 @@ int wl12xx_acx_cca_threshold(struct wl12xx *wl) detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; detection->tx_energy_detection = 0; - ret = wl12xx_cmd_configure(wl, ACX_CCA_THRESHOLD, + ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD, detection, sizeof(*detection)); if (ret < 0) { - wl12xx_warning("failed to set cca threshold: %d", ret); + wl1251_warning("failed to set cca threshold: %d", ret); return ret; } @@ -660,12 +659,12 @@ out: return ret; } -int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) +int wl1251_acx_bcn_dtim_options(struct wl1251 *wl) { struct acx_beacon_broadcast *bb; int ret; - wl12xx_debug(DEBUG_ACX, "acx bcn dtim options"); + wl1251_debug(DEBUG_ACX, "acx bcn dtim options"); bb = kzalloc(sizeof(*bb), GFP_KERNEL); if (!bb) { @@ -678,9 +677,9 @@ int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; - ret = wl12xx_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); + ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); if (ret < 0) { - wl12xx_warning("failed to set rx config: %d", ret); + wl1251_warning("failed to set rx config: %d", ret); goto out; } @@ -689,12 +688,12 @@ out: return ret; } -int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) +int wl1251_acx_aid(struct wl1251 *wl, u16 aid) { struct acx_aid *acx_aid; int ret; - wl12xx_debug(DEBUG_ACX, "acx aid"); + wl1251_debug(DEBUG_ACX, "acx aid"); acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); if (!acx_aid) { @@ -704,9 +703,9 @@ int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) acx_aid->aid = aid; - ret = wl12xx_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); + ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); if (ret < 0) { - wl12xx_warning("failed to set aid: %d", ret); + wl1251_warning("failed to set aid: %d", ret); goto out; } @@ -715,12 +714,12 @@ out: return ret; } -int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) +int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask) { struct acx_event_mask *mask; int ret; - wl12xx_debug(DEBUG_ACX, "acx event mbox mask"); + wl1251_debug(DEBUG_ACX, "acx event mbox mask"); mask = kzalloc(sizeof(*mask), GFP_KERNEL); if (!mask) { @@ -733,10 +732,10 @@ int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) mask->event_mask = event_mask; - ret = wl12xx_cmd_configure(wl, ACX_EVENT_MBOX_MASK, + ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK, mask, sizeof(*mask)); if (ret < 0) { - wl12xx_warning("failed to set acx_event_mbox_mask: %d", ret); + wl1251_warning("failed to set acx_event_mbox_mask: %d", ret); goto out; } @@ -745,12 +744,12 @@ out: return ret; } -int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) +int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) { struct acx_preamble *acx; int ret; - wl12xx_debug(DEBUG_ACX, "acx_set_preamble"); + wl1251_debug(DEBUG_ACX, "acx_set_preamble"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -760,9 +759,9 @@ int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) acx->preamble = preamble; - ret = wl12xx_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); + ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_warning("Setting of preamble failed: %d", ret); + wl1251_warning("Setting of preamble failed: %d", ret); goto out; } @@ -771,13 +770,13 @@ out: return ret; } -int wl12xx_acx_cts_protect(struct wl12xx *wl, +int wl1251_acx_cts_protect(struct wl1251 *wl, enum acx_ctsprotect_type ctsprotect) { struct acx_ctsprotect *acx; int ret; - wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); + wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -787,9 +786,9 @@ int wl12xx_acx_cts_protect(struct wl12xx *wl, acx->ctsprotect = ctsprotect; - ret = wl12xx_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); + ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_warning("Setting of ctsprotect failed: %d", ret); + wl1251_warning("Setting of ctsprotect failed: %d", ret); goto out; } @@ -798,7 +797,7 @@ out: return ret; } -int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime) +int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime) { struct acx_tsf_info *tsf_info; int ret; @@ -809,10 +808,10 @@ int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime) goto out; } - ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, + ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO, tsf_info, sizeof(*tsf_info)); if (ret < 0) { - wl12xx_warning("ACX_FW_REV interrogate failed"); + wl1251_warning("ACX_FW_REV interrogate failed"); goto out; } @@ -824,16 +823,16 @@ out: return ret; } -int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) +int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) { int ret; - wl12xx_debug(DEBUG_ACX, "acx statistics"); + wl1251_debug(DEBUG_ACX, "acx statistics"); - ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, stats, + ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats, sizeof(*stats)); if (ret < 0) { - wl12xx_warning("acx statistics failed: %d", ret); + wl1251_warning("acx statistics failed: %d", ret); return -ENOMEM; } diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index a239120..2e7b193 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -22,15 +22,15 @@ * */ -#ifndef __WL12XX_ACX_H__ -#define __WL12XX_ACX_H__ +#ifndef __WL1251_ACX_H__ +#define __WL1251_ACX_H__ #include "wl1251.h" #include "wl1251_cmd.h" /* Target's information element */ struct acx_header { - struct wl12xx_cmd_header cmd; + struct wl1251_cmd_header cmd; /* acx (or information element) header */ u16 id; @@ -91,15 +91,15 @@ struct acx_revision { u32 hw_version; } __attribute__ ((packed)); -enum wl12xx_psm_mode { +enum wl1251_psm_mode { /* Active mode */ - WL12XX_PSM_CAM = 0, + WL1251_PSM_CAM = 0, /* Power save mode */ - WL12XX_PSM_PS = 1, + WL1251_PSM_PS = 1, /* Extreme low power */ - WL12XX_PSM_ELP = 2, + WL1251_PSM_ELP = 2, }; struct acx_sleep_auth { @@ -1108,39 +1108,39 @@ enum { }; -int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, +int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, u8 mgt_rate, u8 mgt_mod); -int wl12xx_acx_station_id(struct wl12xx *wl); -int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id); -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, +int wl1251_acx_station_id(struct wl1251 *wl); +int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id); +int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, u8 listen_interval); -int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); -int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); -int wl12xx_acx_tx_power(struct wl12xx *wl, int power); -int wl12xx_acx_feature_cfg(struct wl12xx *wl); -int wl12xx_acx_mem_map(struct wl12xx *wl, +int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth); +int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len); +int wl1251_acx_tx_power(struct wl1251 *wl, int power); +int wl1251_acx_feature_cfg(struct wl1251 *wl); +int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, size_t len); -int wl12xx_acx_data_path_params(struct wl12xx *wl, +int wl1251_acx_data_path_params(struct wl1251 *wl, struct acx_data_path_params_resp *data_path); -int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time); -int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter); -int wl12xx_acx_pd_threshold(struct wl12xx *wl); -int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time); -int wl12xx_acx_group_address_tbl(struct wl12xx *wl); -int wl12xx_acx_service_period_timeout(struct wl12xx *wl); -int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold); -int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl); -int wl12xx_acx_beacon_filter_table(struct wl12xx *wl); -int wl12xx_acx_sg_enable(struct wl12xx *wl); -int wl12xx_acx_sg_cfg(struct wl12xx *wl); -int wl12xx_acx_cca_threshold(struct wl12xx *wl); -int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl); -int wl12xx_acx_aid(struct wl12xx *wl, u16 aid); -int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask); -int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble); -int wl12xx_acx_cts_protect(struct wl12xx *wl, +int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time); +int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); +int wl1251_acx_pd_threshold(struct wl1251 *wl); +int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); +int wl1251_acx_group_address_tbl(struct wl1251 *wl); +int wl1251_acx_service_period_timeout(struct wl1251 *wl); +int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); +int wl1251_acx_beacon_filter_opt(struct wl1251 *wl); +int wl1251_acx_beacon_filter_table(struct wl1251 *wl); +int wl1251_acx_sg_enable(struct wl1251 *wl); +int wl1251_acx_sg_cfg(struct wl1251 *wl); +int wl1251_acx_cca_threshold(struct wl1251 *wl); +int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); +int wl1251_acx_aid(struct wl1251 *wl, u16 aid); +int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); +int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); +int wl1251_acx_cts_protect(struct wl1251 *wl, enum acx_ctsprotect_type ctsprotect); -int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats); -int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime); +int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); +int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); -#endif /* __WL12XX_ACX_H__ */ +#endif /* __WL1251_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index c52a208..d8a155d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -28,37 +28,37 @@ #include "wl1251_spi.h" #include "wl1251_event.h" -static void wl12xx_boot_enable_interrupts(struct wl12xx *wl) +static void wl1251_boot_enable_interrupts(struct wl1251 *wl) { enable_irq(wl->irq); } -void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl) +void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) { - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); } -int wl12xx_boot_soft_reset(struct wl12xx *wl) +int wl1251_boot_soft_reset(struct wl1251 *wl) { unsigned long timeout; u32 boot_data; /* perform soft reset */ - wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); /* SOFT_RESET is self clearing */ timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); while (1) { - boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); - wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); + boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); + wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) break; if (time_after(jiffies, timeout)) { /* 1.2 check pWhalBus->uSelfClearTime if the * timeout was reached */ - wl12xx_error("soft reset timeout"); + wl1251_error("soft reset timeout"); return -1; } @@ -66,15 +66,15 @@ int wl12xx_boot_soft_reset(struct wl12xx *wl) } /* disable Rx/Tx */ - wl12xx_reg_write32(wl, ENABLE, 0x0); + wl1251_reg_write32(wl, ENABLE, 0x0); /* disable auto calibration on start*/ - wl12xx_reg_write32(wl, SPARE_A2, 0xffff); + wl1251_reg_write32(wl, SPARE_A2, 0xffff); return 0; } -int wl12xx_boot_init_seq(struct wl12xx *wl) +int wl1251_boot_init_seq(struct wl1251 *wl) { u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; @@ -96,23 +96,23 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) }; /* read NVS params */ - scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6); - wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); + scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6); + wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); /* read ELP_CMD */ - elp_cmd = wl12xx_reg_read32(wl, ELP_CMD); - wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); + elp_cmd = wl1251_reg_read32(wl, ELP_CMD); + wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ ref_freq = scr_pad6 & 0x000000FF; - wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); + wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); - wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9); + wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9); /* * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) */ - wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6); + wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6); /* * set the clock detect feature to work in the restart wu procedure @@ -120,18 +120,18 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) * (ELP_CFG_MODE[13:12]) */ tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; - wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp); + wl1251_reg_write32(wl, ELP_CFG_MODE, tmp); /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ elp_cmd |= 0x00000040; - wl12xx_reg_write32(wl, ELP_CMD, elp_cmd); + wl1251_reg_write32(wl, ELP_CMD, elp_cmd); /* PG 1.2: Set the BB PLL stable time to be 1000usec * (PLL_STABLE_TIME) */ - wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); + wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); /* PG 1.2: read clock request time */ - init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME); + init_data = wl1251_reg_read32(wl, CLK_REQ_TIME); /* * PG 1.2: set the clock request time to be ref_clk_settling_time - @@ -141,35 +141,35 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) tmp = init_data - 0x21; else tmp = 0; - wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp); + wl1251_reg_write32(wl, CLK_REQ_TIME, tmp); /* set BB PLL configurations in RF AFE */ - wl12xx_reg_write32(wl, 0x003058cc, 0x4B5); + wl1251_reg_write32(wl, 0x003058cc, 0x4B5); /* set RF_AFE_REG_5 */ - wl12xx_reg_write32(wl, 0x003058d4, 0x50); + wl1251_reg_write32(wl, 0x003058d4, 0x50); /* set RF_AFE_CTRL_REG_2 */ - wl12xx_reg_write32(wl, 0x00305948, 0x11c001); + wl1251_reg_write32(wl, 0x00305948, 0x11c001); /* * change RF PLL and BB PLL divider for VCO clock and adjust VCO * bais current(RF_AFE_REG_13) */ - wl12xx_reg_write32(wl, 0x003058f4, 0x1e); + wl1251_reg_write32(wl, 0x003058f4, 0x1e); /* set BB PLL configurations */ tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; - wl12xx_reg_write32(wl, 0x00305840, tmp); + wl1251_reg_write32(wl, 0x00305840, tmp); /* set fractional divider according to Appendix C-BB PLL * Calculations */ tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; - wl12xx_reg_write32(wl, 0x00305844, tmp); + wl1251_reg_write32(wl, 0x00305844, tmp); /* set the initial data for the sigma delta */ - wl12xx_reg_write32(wl, 0x00305848, 0x3039); + wl1251_reg_write32(wl, 0x00305848, 0x3039); /* * set the accumulator attenuation value, calibration loop1 @@ -178,14 +178,14 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) */ tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; - wl12xx_reg_write32(wl, 0x00305854, tmp); + wl1251_reg_write32(wl, 0x00305854, tmp); /* * set the calibration stop time after holdoff time expires and set * settling time HOLD_OFF_TIME_BB */ tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; - wl12xx_reg_write32(wl, 0x00305858, tmp); + wl1251_reg_write32(wl, 0x00305858, tmp); /* * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL @@ -193,7 +193,7 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) * BB_ILOOPF[7:3] */ tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; - wl12xx_reg_write32(wl, 0x003058f8, tmp); + wl1251_reg_write32(wl, 0x003058f8, tmp); /* * set regulator output voltage for n divider to @@ -201,10 +201,10 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] */ - wl12xx_reg_write32(wl, 0x003058f0, 0x29); + wl1251_reg_write32(wl, 0x003058f0, 0x29); /* enable restart wakeup sequence (ELP_CMD[0]) */ - wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); + wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); /* restart sequence completed */ udelay(2000); @@ -212,19 +212,19 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) return 0; } -int wl12xx_boot_run_firmware(struct wl12xx *wl) +int wl1251_boot_run_firmware(struct wl1251 *wl) { int loop, ret; u32 chip_id, interrupt; wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); - chip_id = wl12xx_reg_read32(wl, CHIP_ID_B); + chip_id = wl1251_reg_read32(wl, CHIP_ID_B); - wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); + wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); if (chip_id != wl->chip.id) { - wl12xx_error("chip id doesn't match after firmware boot"); + wl1251_error("chip id doesn't match after firmware boot"); return -EIO; } @@ -232,41 +232,41 @@ int wl12xx_boot_run_firmware(struct wl12xx *wl) loop = 0; while (loop++ < INIT_LOOP) { udelay(INIT_LOOP_DELAY); - interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + interrupt = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); if (interrupt == 0xffffffff) { - wl12xx_error("error reading hardware complete " + wl1251_error("error reading hardware complete " "init indication"); return -EIO; } /* check that ACX_INTR_INIT_COMPLETE is enabled */ else if (interrupt & wl->chip.intr_init_complete) { - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, wl->chip.intr_init_complete); break; } } if (loop >= INIT_LOOP) { - wl12xx_error("timeout waiting for the hardware to " + wl1251_error("timeout waiting for the hardware to " "complete initialization"); return -EIO; } /* get hardware config command mail box */ - wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); + wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); /* get hardware config event mail box */ - wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); /* set the working partition to its "running" mode offset */ - wl12xx_set_partition(wl, + wl1251_set_partition(wl, wl->chip.p_table[PART_WORK].mem.start, wl->chip.p_table[PART_WORK].mem.size, wl->chip.p_table[PART_WORK].reg.start, wl->chip.p_table[PART_WORK].reg.size); - wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", + wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", wl->cmd_box_addr, wl->event_box_addr); wl->chip.op_fw_version(wl); @@ -277,20 +277,20 @@ int wl12xx_boot_run_firmware(struct wl12xx *wl) */ /* enable gpio interrupts */ - wl12xx_boot_enable_interrupts(wl); + wl1251_boot_enable_interrupts(wl); wl->chip.op_target_enable_interrupts(wl); /* unmask all mbox events */ wl->event_mask = 0xffffffff; - ret = wl12xx_event_unmask(wl); + ret = wl1251_event_unmask(wl); if (ret < 0) { - wl12xx_error("EVENT mask setting failed"); + wl1251_error("EVENT mask setting failed"); return ret; } - wl12xx_event_mbox_config(wl); + wl1251_event_mbox_config(wl); /* firmware startup completed */ return 0; diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h index 3e2b766..798362d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.h +++ b/drivers/net/wireless/wl12xx/wl1251_boot.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -26,10 +26,10 @@ #include "wl1251.h" -int wl12xx_boot_soft_reset(struct wl12xx *wl); -int wl12xx_boot_init_seq(struct wl12xx *wl); -int wl12xx_boot_run_firmware(struct wl12xx *wl); -void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl); +int wl1251_boot_soft_reset(struct wl1251 *wl); +int wl1251_boot_init_seq(struct wl1251 *wl); +int wl1251_boot_run_firmware(struct wl1251 *wl); +void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); /* number of times we try to read the INIT interrupt */ #define INIT_LOOP 20000 diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 92c7fb6..dc04d1f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -5,7 +5,6 @@ #include #include "wl1251.h" -#include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" #include "wl1251_ps.h" @@ -19,9 +18,9 @@ * @buf: buffer containing the command, must work with dma * @len: length of the buffer */ -int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) +int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) { - struct wl12xx_cmd_header *cmd; + struct wl1251_cmd_header *cmd; unsigned long timeout; u32 intr; int ret = 0; @@ -32,26 +31,26 @@ int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) WARN_ON(len % 4 != 0); - wl12xx_spi_mem_write(wl, wl->cmd_box_addr, buf, len); + wl1251_spi_mem_write(wl, wl->cmd_box_addr, buf, len); - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); - timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT); + timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); while (!(intr & wl->chip.intr_cmd_complete)) { if (time_after(jiffies, timeout)) { - wl12xx_error("command complete timeout"); + wl1251_error("command complete timeout"); ret = -ETIMEDOUT; goto out; } msleep(1); - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); } - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, wl->chip.intr_cmd_complete); out: @@ -66,33 +65,33 @@ out: * @len: length of the buffer * @answer: is answer needed */ -int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) +int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) { int ret; - wl12xx_debug(DEBUG_CMD, "cmd test"); + wl1251_debug(DEBUG_CMD, "cmd test"); - ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); + ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len); if (ret < 0) { - wl12xx_warning("TEST command failed"); + wl1251_warning("TEST command failed"); return ret; } if (answer) { - struct wl12xx_command *cmd_answer; + struct wl1251_command *cmd_answer; /* * The test command got in, we can read the answer. - * The answer would be a wl12xx_command, where the + * The answer would be a wl1251_command, where the * parameter array contains the actual answer. */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); cmd_answer = buf; if (cmd_answer->header.status != CMD_STATUS_SUCCESS) - wl12xx_error("TEST command answer error: %d", + wl1251_error("TEST command answer error: %d", cmd_answer->header.status); } @@ -107,30 +106,30 @@ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) * @buf: buffer for the response, including all headers, must work with dma * @len: lenght of buf */ -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len) +int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) { struct acx_header *acx = buf; int ret; - wl12xx_debug(DEBUG_CMD, "cmd interrogate"); + wl1251_debug(DEBUG_CMD, "cmd interrogate"); acx->id = id; /* payload length, does not include any headers */ acx->len = len - sizeof(*acx); - ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); + ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_error("INTERROGATE command failed"); + wl1251_error("INTERROGATE command failed"); goto out; } /* the interrogate command got in, we can read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, len); + wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, len); acx = buf; if (acx->cmd.status != CMD_STATUS_SUCCESS) - wl12xx_error("INTERROGATE command error: %d", + wl1251_error("INTERROGATE command error: %d", acx->cmd.status); out: @@ -145,34 +144,34 @@ out: * @buf: buffer containing acx, including all headers, must work with dma * @len: length of buf */ -int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len) +int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len) { struct acx_header *acx = buf; int ret; - wl12xx_debug(DEBUG_CMD, "cmd configure"); + wl1251_debug(DEBUG_CMD, "cmd configure"); acx->id = id; /* payload length, does not include any headers */ acx->len = len - sizeof(*acx); - ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, acx, len); + ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len); if (ret < 0) { - wl12xx_warning("CONFIGURE command NOK"); + wl1251_warning("CONFIGURE command NOK"); return ret; } return 0; } -int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, +int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control) { - struct wl12xx_cmd_vbm_update *vbm; + struct wl1251_cmd_vbm_update *vbm; int ret; - wl12xx_debug(DEBUG_CMD, "cmd vbm"); + wl1251_debug(DEBUG_CMD, "cmd vbm"); vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); if (!vbm) { @@ -183,7 +182,7 @@ int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, /* Count and period will be filled by the target */ vbm->tim.bitmap_ctrl = bitmap_control; if (bitmap_len > PARTIAL_VBM_MAX) { - wl12xx_warning("cmd vbm len is %d B, truncating to %d", + wl1251_warning("cmd vbm len is %d B, truncating to %d", bitmap_len, PARTIAL_VBM_MAX); bitmap_len = PARTIAL_VBM_MAX; } @@ -193,9 +192,9 @@ int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, vbm->len = cpu_to_le16(bitmap_len + 5); - ret = wl12xx_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); + ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); if (ret < 0) { - wl12xx_error("VBM command failed"); + wl1251_error("VBM command failed"); goto out; } @@ -204,13 +203,13 @@ out: return 0; } -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable) +int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) { struct cmd_enabledisable_path *cmd; int ret; u16 cmd_rx, cmd_tx; - wl12xx_debug(DEBUG_CMD, "cmd data path"); + wl1251_debug(DEBUG_CMD, "cmd data path"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -228,24 +227,24 @@ int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable) cmd_tx = CMD_DISABLE_TX; } - ret = wl12xx_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); + ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); if (ret < 0) { - wl12xx_error("rx %s cmd for channel %d failed", + wl1251_error("rx %s cmd for channel %d failed", enable ? "start" : "stop", channel); goto out; } - wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d", + wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d", enable ? "start" : "stop", channel); - ret = wl12xx_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); + ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); if (ret < 0) { - wl12xx_error("tx %s cmd for channel %d failed", + wl1251_error("tx %s cmd for channel %d failed", enable ? "start" : "stop", channel); return ret; } - wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d", + wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d", enable ? "start" : "stop", channel); out: @@ -253,7 +252,7 @@ out: return ret; } -int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait) { unsigned long timeout; @@ -268,14 +267,14 @@ int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, } /* FIXME: this should be in main.c */ - ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, + ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, DEFAULT_HW_GEN_MODULATION_TYPE, wl->tx_mgmt_frm_rate, wl->tx_mgmt_frm_mod); if (ret < 0) goto out; - wl12xx_debug(DEBUG_CMD, "cmd join"); + wl1251_debug(DEBUG_CMD, "cmd join"); /* Reverse order BSSID */ bssid = (u8 *) &join->bssid_lsb; @@ -294,9 +293,9 @@ int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, join->channel = wl->channel; join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; - ret = wl12xx_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); + ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); if (ret < 0) { - wl12xx_error("failed to initiate cmd join"); + wl1251_error("failed to initiate cmd join"); goto out; } @@ -314,20 +313,20 @@ out: return ret; } -int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) +int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode) { - struct wl12xx_cmd_ps_params *ps_params = NULL; + struct wl1251_cmd_ps_params *ps_params = NULL; int ret = 0; /* FIXME: this should be in ps.c */ - ret = wl12xx_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, + ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, wl->listen_int); if (ret < 0) { - wl12xx_error("couldn't set wake up conditions"); + wl1251_error("couldn't set wake up conditions"); goto out; } - wl12xx_debug(DEBUG_CMD, "cmd set ps mode"); + wl1251_debug(DEBUG_CMD, "cmd set ps mode"); ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); if (!ps_params) { @@ -341,10 +340,10 @@ int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) ps_params->hang_over_period = 128; ps_params->null_data_rate = 1; /* 1 Mbps */ - ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, ps_params, + ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params, sizeof(*ps_params)); if (ret < 0) { - wl12xx_error("cmd set_ps_mode failed"); + wl1251_error("cmd set_ps_mode failed"); goto out; } @@ -353,13 +352,13 @@ out: return ret; } -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, +int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len) { struct cmd_read_write_memory *cmd; int ret = 0; - wl12xx_debug(DEBUG_CMD, "cmd read memory"); + wl1251_debug(DEBUG_CMD, "cmd read memory"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -373,17 +372,17 @@ int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, cmd->addr = addr; cmd->size = len; - ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); + ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); if (ret < 0) { - wl12xx_error("read memory command failed: %d", ret); + wl1251_error("read memory command failed: %d", ret); goto out; } /* the read command got in, we can now read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + wl1251_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); if (cmd->header.status != CMD_STATUS_SUCCESS) - wl12xx_error("error in read command result: %d", + wl1251_error("error in read command result: %d", cmd->header.status); memcpy(answer, cmd->value, len); @@ -393,17 +392,17 @@ out: return ret; } -int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, +int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, void *buf, size_t buf_len) { - struct wl12xx_cmd_packet_template *cmd; + struct wl1251_cmd_packet_template *cmd; size_t cmd_len; int ret = 0; - wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id); + wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id); - WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE); - buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE); + WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE); + buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE); cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); cmd = kzalloc(cmd_len, GFP_KERNEL); @@ -417,9 +416,9 @@ int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, if (buf) memcpy(cmd->data, buf, buf_len); - ret = wl12xx_cmd_send(wl, cmd_id, cmd, cmd_len); + ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len); if (ret < 0) { - wl12xx_warning("cmd set_template failed: %d", ret); + wl1251_warning("cmd set_template failed: %d", ret); goto out; } diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index b252ad2..64f228d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -22,32 +22,32 @@ * */ -#ifndef __WL12XX_CMD_H__ -#define __WL12XX_CMD_H__ +#ifndef __WL1251_CMD_H__ +#define __WL1251_CMD_H__ #include "wl1251.h" struct acx_header; -int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len); -int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer); -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len); -int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len); -int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, +int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); +int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer); +int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len); +int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); +int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable); -int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, +int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait); -int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, +int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); +int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len); -int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, +int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, void *buf, size_t buf_len); /* unit ms */ -#define WL12XX_COMMAND_TIMEOUT 2000 +#define WL1251_COMMAND_TIMEOUT 2000 -enum wl12xx_commands { +enum wl1251_commands { CMD_RESET = 0, CMD_INTERROGATE = 1, /*use this to read information elements*/ CMD_CONFIGURE = 2, /*use this to write information elements*/ @@ -95,15 +95,15 @@ enum wl12xx_commands { #define MAX_CMD_PARAMS 572 -struct wl12xx_cmd_header { +struct wl1251_cmd_header { u16 id; u16 status; /* payload */ u8 data[0]; } __attribute__ ((packed)); -struct wl12xx_command { - struct wl12xx_cmd_header header; +struct wl1251_command { + struct wl1251_cmd_header header; u8 parameters[MAX_CMD_PARAMS]; }; @@ -145,7 +145,7 @@ enum { #define MAX_READ_SIZE 256 struct cmd_read_write_memory { - struct wl12xx_cmd_header header; + struct wl1251_cmd_header header; /* The address of the memory to read from or write to.*/ u32 addr; @@ -214,7 +214,7 @@ struct basic_scan_channel_parameters { #define SCAN_MAX_NUM_OF_CHANNELS 16 struct cmd_scan { - struct wl12xx_cmd_header header; + struct wl1251_cmd_header header; struct basic_scan_parameters params; struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; @@ -232,7 +232,7 @@ enum { struct cmd_join { - struct wl12xx_cmd_header header; + struct wl1251_cmd_header header; u32 bssid_lsb; u16 bssid_msb; @@ -269,16 +269,16 @@ struct cmd_join { } __attribute__ ((packed)); struct cmd_enabledisable_path { - struct wl12xx_cmd_header header; + struct wl1251_cmd_header header; u8 channel; u8 padding[3]; } __attribute__ ((packed)); -#define WL12XX_MAX_TEMPLATE_SIZE 300 +#define WL1251_MAX_TEMPLATE_SIZE 300 -struct wl12xx_cmd_packet_template { - struct wl12xx_cmd_header header; +struct wl1251_cmd_packet_template { + struct wl1251_cmd_header header; __le16 size; u8 data[0]; @@ -287,7 +287,7 @@ struct wl12xx_cmd_packet_template { #define TIM_ELE_ID 5 #define PARTIAL_VBM_MAX 251 -struct wl12xx_tim { +struct wl1251_tim { u8 identity; u8 length; u8 dtim_count; @@ -297,20 +297,20 @@ struct wl12xx_tim { } __attribute__ ((packed)); /* Virtual Bit Map update */ -struct wl12xx_cmd_vbm_update { - struct wl12xx_cmd_header header; +struct wl1251_cmd_vbm_update { + struct wl1251_cmd_header header; __le16 len; u8 padding[2]; - struct wl12xx_tim tim; + struct wl1251_tim tim; } __attribute__ ((packed)); -enum wl12xx_cmd_ps_mode { +enum wl1251_cmd_ps_mode { STATION_ACTIVE_MODE, STATION_POWER_SAVE_MODE }; -struct wl12xx_cmd_ps_params { - struct wl12xx_cmd_header header; +struct wl1251_cmd_ps_params { + struct wl1251_cmd_header header; u8 ps_mode; /* STATION_* */ u8 send_null_data; /* Do we have to send NULL data packet ? */ @@ -325,8 +325,8 @@ struct wl12xx_cmd_ps_params { u8 pad[2]; } __attribute__ ((packed)); -struct wl12xx_cmd_trigger_scan_to { - struct wl12xx_cmd_header header; +struct wl1251_cmd_trigger_scan_to { + struct wl1251_cmd_header header; u32 timeout; }; @@ -340,14 +340,14 @@ struct wl12xx_cmd_trigger_scan_to { /* When set, disable HW decryption */ #define DF_SNIFF_MODE_ENABLE 0x80 -enum wl12xx_cmd_key_action { +enum wl1251_cmd_key_action { KEY_ADD_OR_REPLACE = 1, KEY_REMOVE = 2, KEY_SET_ID = 3, MAX_KEY_ACTION = 0xffff, }; -enum wl12xx_cmd_key_type { +enum wl1251_cmd_key_type { KEY_WEP_DEFAULT = 0, KEY_WEP_ADDR = 1, KEY_AES_GROUP = 4, @@ -374,8 +374,8 @@ enum wl12xx_cmd_key_type { * */ -struct wl12xx_cmd_set_keys { - struct wl12xx_cmd_header header; +struct wl1251_cmd_set_keys { + struct wl1251_cmd_header header; /* Ignored for default WEP key */ u8 addr[ETH_ALEN]; @@ -404,4 +404,4 @@ struct wl12xx_cmd_set_keys { } __attribute__ ((packed)); -#endif /* __WL12XX_CMD_H__ */ +#endif /* __WL1251_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c index 866303d..a007230 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2009 Nokia Corporation * @@ -30,7 +30,7 @@ #include "wl1251_ps.h" /* ms */ -#define WL12XX_DEBUGFS_STATS_LIFETIME 1000 +#define WL1251_DEBUGFS_STATS_LIFETIME 1000 /* debugfs macros idea from mac80211 */ @@ -38,7 +38,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ size_t count, loff_t *ppos) \ { \ - struct wl12xx *wl = file->private_data; \ + struct wl1251 *wl = file->private_data; \ char buf[buflen]; \ int res; \ \ @@ -48,7 +48,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ \ static const struct file_operations name## _ops = { \ .read = name## _read, \ - .open = wl12xx_open_file_generic, \ + .open = wl1251_open_file_generic, \ }; #define DEBUGFS_ADD(name, parent) \ @@ -71,11 +71,11 @@ static ssize_t sub## _ ##name## _read(struct file *file, \ char __user *userbuf, \ size_t count, loff_t *ppos) \ { \ - struct wl12xx *wl = file->private_data; \ + struct wl1251 *wl = file->private_data; \ char buf[buflen]; \ int res; \ \ - wl12xx_debugfs_update_stats(wl); \ + wl1251_debugfs_update_stats(wl); \ \ res = scnprintf(buf, buflen, fmt "\n", \ wl->stats.fw_stats->sub.name); \ @@ -84,7 +84,7 @@ static ssize_t sub## _ ##name## _read(struct file *file, \ \ static const struct file_operations sub## _ ##name## _ops = { \ .read = sub## _ ##name## _read, \ - .open = wl12xx_open_file_generic, \ + .open = wl1251_open_file_generic, \ }; #define DEBUGFS_FWSTATS_ADD(sub, name) \ @@ -93,30 +93,30 @@ static const struct file_operations sub## _ ##name## _ops = { \ #define DEBUGFS_FWSTATS_DEL(sub, name) \ DEBUGFS_DEL(sub## _ ##name) -static void wl12xx_debugfs_update_stats(struct wl12xx *wl) +static void wl1251_debugfs_update_stats(struct wl1251 *wl) { int ret; mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; - if (wl->state == WL12XX_STATE_ON && + if (wl->state == WL1251_STATE_ON && time_after(jiffies, wl->stats.fw_stats_update + - msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) { - wl12xx_acx_statistics(wl, wl->stats.fw_stats); + msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) { + wl1251_acx_statistics(wl, wl->stats.fw_stats); wl->stats.fw_stats_update = jiffies; } - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); } -static int wl12xx_open_file_generic(struct inode *inode, struct file *file) +static int wl1251_open_file_generic(struct inode *inode, struct file *file) { file->private_data = inode->i_private; return 0; @@ -221,7 +221,7 @@ DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - struct wl12xx *wl = file->private_data; + struct wl1251 *wl = file->private_data; u32 queue_len; char buf[20]; int res; @@ -234,10 +234,10 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, static const struct file_operations tx_queue_len_ops = { .read = tx_queue_len_read, - .open = wl12xx_open_file_generic, + .open = wl1251_open_file_generic, }; -static void wl12xx_debugfs_delete_files(struct wl12xx *wl) +static void wl1251_debugfs_delete_files(struct wl1251 *wl) { DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); @@ -335,7 +335,7 @@ static void wl12xx_debugfs_delete_files(struct wl12xx *wl) DEBUGFS_DEL(excessive_retries); } -static int wl12xx_debugfs_add_files(struct wl12xx *wl) +static int wl1251_debugfs_add_files(struct wl1251 *wl) { int ret = 0; @@ -436,19 +436,19 @@ static int wl12xx_debugfs_add_files(struct wl12xx *wl) out: if (ret < 0) - wl12xx_debugfs_delete_files(wl); + wl1251_debugfs_delete_files(wl); return ret; } -void wl12xx_debugfs_reset(struct wl12xx *wl) +void wl1251_debugfs_reset(struct wl1251 *wl) { memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); wl->stats.retry_count = 0; wl->stats.excessive_retries = 0; } -int wl12xx_debugfs_init(struct wl12xx *wl) +int wl1251_debugfs_init(struct wl1251 *wl) { int ret; @@ -479,7 +479,7 @@ int wl12xx_debugfs_init(struct wl12xx *wl) wl->stats.fw_stats_update = jiffies; - ret = wl12xx_debugfs_add_files(wl); + ret = wl1251_debugfs_add_files(wl); if (ret < 0) goto err_file; @@ -502,9 +502,9 @@ err: return ret; } -void wl12xx_debugfs_exit(struct wl12xx *wl) +void wl1251_debugfs_exit(struct wl1251 *wl) { - wl12xx_debugfs_delete_files(wl); + wl1251_debugfs_delete_files(wl); kfree(wl->stats.fw_stats); wl->stats.fw_stats = NULL; diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h index 37653eb..6dc3d08 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.h +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2009 Nokia Corporation * @@ -21,13 +21,13 @@ * */ -#ifndef WL12XX_DEBUGFS_H -#define WL12XX_DEBUGFS_H +#ifndef WL1251_DEBUGFS_H +#define WL1251_DEBUGFS_H #include "wl1251.h" -int wl12xx_debugfs_init(struct wl12xx *wl); -void wl12xx_debugfs_exit(struct wl12xx *wl); -void wl12xx_debugfs_reset(struct wl12xx *wl); +int wl1251_debugfs_init(struct wl1251 *wl); +void wl1251_debugfs_exit(struct wl1251 *wl); +void wl1251_debugfs_reset(struct wl1251 *wl); -#endif /* WL12XX_DEBUGFS_H */ +#endif /* WL1251_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index a6d9234..1a0a0bc 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -28,10 +28,10 @@ #include "wl1251_event.h" #include "wl1251_ps.h" -static int wl12xx_event_scan_complete(struct wl12xx *wl, +static int wl1251_event_scan_complete(struct wl1251 *wl, struct event_mailbox *mbox) { - wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", + wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", mbox->scheduled_scan_status, mbox->scheduled_scan_channels); @@ -45,34 +45,34 @@ static int wl12xx_event_scan_complete(struct wl12xx *wl, return 0; } -static void wl12xx_event_mbox_dump(struct event_mailbox *mbox) +static void wl1251_event_mbox_dump(struct event_mailbox *mbox) { - wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:"); - wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); - wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); + wl1251_debug(DEBUG_EVENT, "MBOX DUMP:"); + wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); + wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); } -static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox) +static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) { int ret; u32 vector; - wl12xx_event_mbox_dump(mbox); + wl1251_event_mbox_dump(mbox); vector = mbox->events_vector & ~(mbox->events_mask); - wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector); + wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector); if (vector & SCAN_COMPLETE_EVENT_ID) { - ret = wl12xx_event_scan_complete(wl, mbox); + ret = wl1251_event_scan_complete(wl, mbox); if (ret < 0) return ret; } if (vector & BSS_LOSE_EVENT_ID) { - wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); + wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); if (wl->psm_requested && wl->psm) { - ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; } @@ -81,47 +81,47 @@ static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox) return 0; } -int wl12xx_event_unmask(struct wl12xx *wl) +int wl1251_event_unmask(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask)); + ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask)); if (ret < 0) return ret; return 0; } -void wl12xx_event_mbox_config(struct wl12xx *wl) +void wl1251_event_mbox_config(struct wl1251 *wl) { - wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); - wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", + wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", wl->mbox_ptr[0], wl->mbox_ptr[1]); } -int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num) +int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) { struct event_mailbox mbox; int ret; - wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); + wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); if (mbox_num > 1) return -EINVAL; /* first we read the mbox descriptor */ - wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, + wl1251_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, sizeof(struct event_mailbox)); /* process the descriptor */ - ret = wl12xx_event_process(wl, &mbox); + ret = wl1251_event_process(wl, &mbox); if (ret < 0) return ret; /* then we let the firmware know it can go on...*/ - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl12xx/wl1251_event.h index 1f4c2f7..be0ac54 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.h +++ b/drivers/net/wireless/wl12xx/wl1251_event.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -22,8 +22,8 @@ * */ -#ifndef __WL12XX_EVENT_H__ -#define __WL12XX_EVENT_H__ +#ifndef __WL1251_EVENT_H__ +#define __WL1251_EVENT_H__ /* * Mbox events @@ -114,8 +114,8 @@ struct event_mailbox { u8 padding[19]; } __attribute__ ((packed)); -int wl12xx_event_unmask(struct wl12xx *wl); -void wl12xx_event_mbox_config(struct wl12xx *wl); -int wl12xx_event_handle(struct wl12xx *wl, u8 mbox); +int wl1251_event_unmask(struct wl1251 *wl); +void wl1251_event_mbox_config(struct wl1251 *wl); +int wl1251_event_handle(struct wl1251 *wl, u8 mbox); #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index 0929461..df6c60f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2009 Nokia Corporation * @@ -29,59 +29,59 @@ #include "wl1251_acx.h" #include "wl1251_cmd.h" -int wl12xx_hw_init_hwenc_config(struct wl12xx *wl) +int wl1251_hw_init_hwenc_config(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_feature_cfg(wl); + ret = wl1251_acx_feature_cfg(wl); if (ret < 0) { - wl12xx_warning("couldn't set feature config"); + wl1251_warning("couldn't set feature config"); return ret; } - ret = wl12xx_acx_default_key(wl, wl->default_key); + ret = wl1251_acx_default_key(wl, wl->default_key); if (ret < 0) { - wl12xx_warning("couldn't set default key"); + wl1251_warning("couldn't set default key"); return ret; } return 0; } -int wl12xx_hw_init_templates_config(struct wl12xx *wl) +int wl1251_hw_init_templates_config(struct wl1251 *wl) { int ret; u8 partial_vbm[PARTIAL_VBM_MAX]; /* send empty templates for fw memory reservation */ - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL, + ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL, sizeof(struct wl12xx_probe_req_template)); if (ret < 0) return ret; - ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL, + ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL, sizeof(struct wl12xx_null_data_template)); if (ret < 0) return ret; - ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL, + ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL, sizeof(struct wl12xx_ps_poll_template)); if (ret < 0) return ret; - ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, + ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, sizeof (struct wl12xx_qos_null_data_template)); if (ret < 0) return ret; - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL, + ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL, sizeof (struct wl12xx_probe_resp_template)); if (ret < 0) return ret; - ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL, + ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL, sizeof (struct wl12xx_beacon_template)); if (ret < 0) @@ -89,112 +89,112 @@ int wl12xx_hw_init_templates_config(struct wl12xx *wl) /* tim templates, first reserve space then allocate an empty one */ memset(partial_vbm, 0, PARTIAL_VBM_MAX); - ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); + ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); if (ret < 0) return ret; - ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); + ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter) +int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter) { int ret; - ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); + ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); if (ret < 0) return ret; - ret = wl12xx_acx_rx_config(wl, config, filter); + ret = wl1251_acx_rx_config(wl, config, filter); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_phy_config(struct wl12xx *wl) +int wl1251_hw_init_phy_config(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_pd_threshold(wl); + ret = wl1251_acx_pd_threshold(wl); if (ret < 0) return ret; - ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME); + ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME); if (ret < 0) return ret; - ret = wl12xx_acx_group_address_tbl(wl); + ret = wl1251_acx_group_address_tbl(wl); if (ret < 0) return ret; - ret = wl12xx_acx_service_period_timeout(wl); + ret = wl1251_acx_service_period_timeout(wl); if (ret < 0) return ret; - ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); + ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_beacon_filter(struct wl12xx *wl) +int wl1251_hw_init_beacon_filter(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_beacon_filter_opt(wl); + ret = wl1251_acx_beacon_filter_opt(wl); if (ret < 0) return ret; - ret = wl12xx_acx_beacon_filter_table(wl); + ret = wl1251_acx_beacon_filter_table(wl); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_pta(struct wl12xx *wl) +int wl1251_hw_init_pta(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_sg_enable(wl); + ret = wl1251_acx_sg_enable(wl); if (ret < 0) return ret; - ret = wl12xx_acx_sg_cfg(wl); + ret = wl1251_acx_sg_cfg(wl); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_energy_detection(struct wl12xx *wl) +int wl1251_hw_init_energy_detection(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_cca_threshold(wl); + ret = wl1251_acx_cca_threshold(wl); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl) +int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_bcn_dtim_options(wl); + ret = wl1251_acx_bcn_dtim_options(wl); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_power_auth(struct wl12xx *wl) +int wl1251_hw_init_power_auth(struct wl1251 *wl) { - return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); + return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); } diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index 2b6268e..8596188 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2009 Nokia Corporation * @@ -21,19 +21,19 @@ * */ -#ifndef __WL12XX_INIT_H__ -#define __WL12XX_INIT_H__ +#ifndef __WL1251_INIT_H__ +#define __WL1251_INIT_H__ #include "wl1251.h" -int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); -int wl12xx_hw_init_templates_config(struct wl12xx *wl); -int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter); -int wl12xx_hw_init_phy_config(struct wl12xx *wl); -int wl12xx_hw_init_beacon_filter(struct wl12xx *wl); -int wl12xx_hw_init_pta(struct wl12xx *wl); -int wl12xx_hw_init_energy_detection(struct wl12xx *wl); -int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl); -int wl12xx_hw_init_power_auth(struct wl12xx *wl); +int wl1251_hw_init_hwenc_config(struct wl1251 *wl); +int wl1251_hw_init_templates_config(struct wl1251 *wl); +int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); +int wl1251_hw_init_phy_config(struct wl1251 *wl); +int wl1251_hw_init_beacon_filter(struct wl1251 *wl); +int wl1251_hw_init_pta(struct wl1251 *wl); +int wl1251_hw_init_energy_detection(struct wl1251 *wl); +int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); +int wl1251_hw_init_power_auth(struct wl1251 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 41b9c616..f4bc579 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008-2009 Nokia Corporation * @@ -43,26 +43,26 @@ #include "wl1251_init.h" #include "wl1251_debugfs.h" -static void wl12xx_disable_interrupts(struct wl12xx *wl) +static void wl1251_disable_interrupts(struct wl1251 *wl) { disable_irq(wl->irq); } -static void wl12xx_power_off(struct wl12xx *wl) +static void wl1251_power_off(struct wl1251 *wl) { wl->set_power(false); } -static void wl12xx_power_on(struct wl12xx *wl) +static void wl1251_power_on(struct wl1251 *wl) { wl->set_power(true); } -static irqreturn_t wl12xx_irq(int irq, void *cookie) +static irqreturn_t wl1251_irq(int irq, void *cookie) { - struct wl12xx *wl; + struct wl1251 *wl; - wl12xx_debug(DEBUG_IRQ, "IRQ"); + wl1251_debug(DEBUG_IRQ, "IRQ"); wl = cookie; @@ -71,7 +71,7 @@ static irqreturn_t wl12xx_irq(int irq, void *cookie) return IRQ_HANDLED; } -static int wl12xx_fetch_firmware(struct wl12xx *wl) +static int wl1251_fetch_firmware(struct wl1251 *wl) { const struct firmware *fw; int ret; @@ -79,12 +79,12 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl) ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); if (ret < 0) { - wl12xx_error("could not get firmware: %d", ret); + wl1251_error("could not get firmware: %d", ret); return ret; } if (fw->size % 4) { - wl12xx_error("firmware size is not multiple of 32 bits: %zu", + wl1251_error("firmware size is not multiple of 32 bits: %zu", fw->size); ret = -EILSEQ; goto out; @@ -94,7 +94,7 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl) wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); if (!wl->fw) { - wl12xx_error("could not allocate memory for the firmware"); + wl1251_error("could not allocate memory for the firmware"); ret = -ENOMEM; goto out; } @@ -109,7 +109,7 @@ out: return ret; } -static int wl12xx_fetch_nvs(struct wl12xx *wl) +static int wl1251_fetch_nvs(struct wl1251 *wl) { const struct firmware *fw; int ret; @@ -117,12 +117,12 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl) ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); if (ret < 0) { - wl12xx_error("could not get nvs file: %d", ret); + wl1251_error("could not get nvs file: %d", ret); return ret; } if (fw->size % 4) { - wl12xx_error("nvs size is not multiple of 32 bits: %zu", + wl1251_error("nvs size is not multiple of 32 bits: %zu", fw->size); ret = -EILSEQ; goto out; @@ -132,7 +132,7 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl) wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); if (!wl->nvs) { - wl12xx_error("could not allocate memory for the nvs file"); + wl1251_error("could not allocate memory for the nvs file"); ret = -ENOMEM; goto out; } @@ -147,49 +147,49 @@ out: return ret; } -static void wl12xx_fw_wakeup(struct wl12xx *wl) +static void wl1251_fw_wakeup(struct wl1251 *wl) { u32 elp_reg; elp_reg = ELPCTRL_WAKE_UP; - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); + elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); if (!(elp_reg & ELPCTRL_WLAN_READY)) { - wl12xx_warning("WLAN not ready"); + wl1251_warning("WLAN not ready"); } } -static int wl12xx_chip_wakeup(struct wl12xx *wl) +static int wl1251_chip_wakeup(struct wl1251 *wl) { int ret = 0; - wl12xx_power_on(wl); + wl1251_power_on(wl); msleep(wl->chip.power_on_sleep); - wl12xx_spi_reset(wl); - wl12xx_spi_init(wl); + wl1251_spi_reset(wl); + wl1251_spi_init(wl); /* We don't need a real memory partition here, because we only want * to use the registers at this point. */ - wl12xx_set_partition(wl, + wl1251_set_partition(wl, 0x00000000, 0x00000000, REGISTERS_BASE, REGISTERS_DOWN_SIZE); /* ELP module wake up */ - wl12xx_fw_wakeup(wl); + wl1251_fw_wakeup(wl); /* whal_FwCtrl_BootSm() */ /* 0. read chip id from CHIP_ID */ - wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B); + wl->chip.id = wl1251_reg_read32(wl, CHIP_ID_B); /* 1. check if chip id is valid */ switch (wl->chip.id) { case CHIP_ID_1251_PG12: - wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", + wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", wl->chip.id); wl1251_setup(wl); @@ -198,20 +198,20 @@ static int wl12xx_chip_wakeup(struct wl12xx *wl) case CHIP_ID_1251_PG10: case CHIP_ID_1251_PG11: default: - wl12xx_error("unsupported chip id: 0x%x", wl->chip.id); + wl1251_error("unsupported chip id: 0x%x", wl->chip.id); ret = -ENODEV; goto out; } if (wl->fw == NULL) { - ret = wl12xx_fetch_firmware(wl); + ret = wl1251_fetch_firmware(wl); if (ret < 0) goto out; } /* No NVS from netlink, try to get it from the filesystem */ if (wl->nvs == NULL) { - ret = wl12xx_fetch_nvs(wl); + ret = wl1251_fetch_nvs(wl); if (ret < 0) goto out; } @@ -220,18 +220,18 @@ out: return ret; } -static void wl12xx_filter_work(struct work_struct *work) +static void wl1251_filter_work(struct work_struct *work) { - struct wl12xx *wl = - container_of(work, struct wl12xx, filter_work); + struct wl1251 *wl = + container_of(work, struct wl1251, filter_work); int ret; mutex_lock(&wl->mutex); - if (wl->state == WL12XX_STATE_OFF) + if (wl->state == WL1251_STATE_OFF) goto out; - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -241,27 +241,29 @@ static void wl12xx_filter_work(struct work_struct *work) goto out_sleep; out_sleep: - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); } -int wl12xx_plt_start(struct wl12xx *wl) +int wl1251_plt_start(struct wl1251 *wl) { int ret; - wl12xx_notice("power up"); + mutex_lock(&wl->mutex); + + wl1251_notice("power up"); - if (wl->state != WL12XX_STATE_OFF) { - wl12xx_error("cannot go into PLT state because not " + if (wl->state != WL1251_STATE_OFF) { + wl1251_error("cannot go into PLT state because not " "in off state: %d", wl->state); return -EBUSY; } - wl->state = WL12XX_STATE_PLT; + wl->state = WL1251_STATE_PLT; - ret = wl12xx_chip_wakeup(wl); + ret = wl1251_chip_wakeup(wl); if (ret < 0) return ret; @@ -269,7 +271,7 @@ int wl12xx_plt_start(struct wl12xx *wl) if (ret < 0) return ret; - wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); + wl1251_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); ret = wl->chip.op_plt_init(wl); if (ret < 0) @@ -278,28 +280,30 @@ int wl12xx_plt_start(struct wl12xx *wl) return 0; } -int wl12xx_plt_stop(struct wl12xx *wl) +int wl1251_plt_stop(struct wl1251 *wl) { - wl12xx_notice("power down"); + mutex_lock(&wl->mutex); + + wl1251_notice("power down"); - if (wl->state != WL12XX_STATE_PLT) { - wl12xx_error("cannot power down because not in PLT " + if (wl->state != WL1251_STATE_PLT) { + wl1251_error("cannot power down because not in PLT " "state: %d", wl->state); return -EBUSY; } - wl12xx_disable_interrupts(wl); - wl12xx_power_off(wl); + wl1251_disable_interrupts(wl); + wl1251_power_off(wl); - wl->state = WL12XX_STATE_OFF; + wl->state = WL1251_STATE_OFF; return 0; } -static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; skb_queue_tail(&wl->tx_queue, skb); @@ -314,7 +318,7 @@ static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * The workqueue is slow to process the tx_queue and we need stop * the queue here, otherwise the queue will get too long. */ - if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) { + if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) { ieee80211_stop_queues(wl->hw); /* @@ -328,23 +332,23 @@ static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -static int wl12xx_op_start(struct ieee80211_hw *hw) +static int wl1251_op_start(struct ieee80211_hw *hw) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; int ret = 0; - wl12xx_debug(DEBUG_MAC80211, "mac80211 start"); + wl1251_debug(DEBUG_MAC80211, "mac80211 start"); mutex_lock(&wl->mutex); - if (wl->state != WL12XX_STATE_OFF) { - wl12xx_error("cannot start because not in off state: %d", + if (wl->state != WL1251_STATE_OFF) { + wl1251_error("cannot start because not in off state: %d", wl->state); ret = -EBUSY; goto out; } - ret = wl12xx_chip_wakeup(wl); + ret = wl1251_chip_wakeup(wl); if (ret < 0) return ret; @@ -356,34 +360,34 @@ static int wl12xx_op_start(struct ieee80211_hw *hw) if (ret < 0) goto out; - ret = wl12xx_acx_station_id(wl); + ret = wl1251_acx_station_id(wl); if (ret < 0) goto out; - wl->state = WL12XX_STATE_ON; + wl->state = WL1251_STATE_ON; - wl12xx_info("firmware booted (%s)", wl->chip.fw_ver); + wl1251_info("firmware booted (%s)", wl->chip.fw_ver); out: if (ret < 0) - wl12xx_power_off(wl); + wl1251_power_off(wl); mutex_unlock(&wl->mutex); return ret; } -static void wl12xx_op_stop(struct ieee80211_hw *hw) +static void wl1251_op_stop(struct ieee80211_hw *hw) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; - wl12xx_info("down"); + wl1251_info("down"); - wl12xx_debug(DEBUG_MAC80211, "mac80211 stop"); + wl1251_debug(DEBUG_MAC80211, "mac80211 stop"); mutex_lock(&wl->mutex); - WARN_ON(wl->state != WL12XX_STATE_ON); + WARN_ON(wl->state != WL1251_STATE_ON); if (wl->scanning) { mutex_unlock(&wl->mutex); @@ -392,9 +396,9 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw) wl->scanning = false; } - wl->state = WL12XX_STATE_OFF; + wl->state = WL1251_STATE_OFF; - wl12xx_disable_interrupts(wl); + wl1251_disable_interrupts(wl); mutex_unlock(&wl->mutex); @@ -406,7 +410,7 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw) /* let's notify MAC80211 about the remaining pending TX frames */ wl->chip.op_tx_flush(wl); - wl12xx_power_off(wl); + wl1251_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); wl->listen_int = 1; @@ -421,21 +425,21 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw) wl->elp = false; wl->psm = 0; wl->tx_queue_stopped = false; - wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + wl->power_level = WL1251_DEFAULT_POWER_LEVEL; - wl12xx_debugfs_reset(wl); + wl1251_debugfs_reset(wl); mutex_unlock(&wl->mutex); } -static int wl12xx_op_add_interface(struct ieee80211_hw *hw, +static int wl1251_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; DECLARE_MAC_BUF(mac); int ret = 0; - wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", + wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", conf->type, print_mac(mac, conf->mac_addr)); mutex_lock(&wl->mutex); @@ -455,7 +459,7 @@ static int wl12xx_op_add_interface(struct ieee80211_hw *hw, if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); - ret = wl12xx_acx_station_id(wl); + ret = wl1251_acx_station_id(wl); if (ret < 0) goto out; } @@ -465,13 +469,13 @@ out: return ret; } -static void wl12xx_op_remove_interface(struct ieee80211_hw *hw, +static void wl1251_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface"); + wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface"); } -static int wl12xx_build_null_data(struct wl12xx *wl) +static int wl1251_build_null_data(struct wl1251 *wl) { struct wl12xx_null_data_template template; @@ -487,12 +491,12 @@ static int wl12xx_build_null_data(struct wl12xx *wl) template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC); - return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template, + return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template, sizeof(template)); } -static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) +static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid) { struct wl12xx_ps_poll_template template; @@ -501,27 +505,27 @@ static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) template.aid = aid; template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); - return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template, + return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template, sizeof(template)); } -static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) +static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; struct ieee80211_conf *conf = &hw->conf; int channel, ret = 0; channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", + wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", channel, conf->flags & IEEE80211_CONF_PS ? "on" : "off", conf->power_level); mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -534,12 +538,12 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) wl->channel = channel; } - ret = wl12xx_build_null_data(wl); + ret = wl1251_build_null_data(wl); if (ret < 0) goto out_sleep; if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl12xx_info("psm enabled"); + wl1251_info("psm enabled"); wl->psm_requested = true; @@ -548,19 +552,19 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) * If we're not, we'll enter it when joining an SSID, * through the bss_info_changed() hook. */ - ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); } else if (!(conf->flags & IEEE80211_CONF_PS) && wl->psm_requested) { - wl12xx_info("psm disabled"); + wl1251_info("psm disabled"); wl->psm_requested = false; if (wl->psm) - ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); } if (conf->power_level != wl->power_level) { - ret = wl12xx_acx_tx_power(wl, conf->power_level); + ret = wl1251_acx_tx_power(wl, conf->power_level); if (ret < 0) goto out; @@ -568,7 +572,7 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) } out_sleep: - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -576,25 +580,25 @@ out: return ret; } -#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ +#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ FIF_ALLMULTI | \ FIF_FCSFAIL | \ FIF_BCN_PRBRESP_PROMISC | \ FIF_CONTROL | \ FIF_OTHER_BSS) -static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, +static void wl1251_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, unsigned int *total, int mc_count, struct dev_addr_list *mc_list) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; - wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter"); + wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter"); - *total &= WL12XX_SUPPORTED_FILTERS; - changed &= WL12XX_SUPPORTED_FILTERS; + *total &= WL1251_SUPPORTED_FILTERS; + changed &= WL1251_SUPPORTED_FILTERS; if (changed == 0) /* no filters which we support changed */ @@ -602,8 +606,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, /* FIXME: wl->rx_config and wl->rx_filter are not protected */ - wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; - wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + wl->rx_config = WL1251_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1251_DEFAULT_RX_FILTER; if (*total & FIF_PROMISC_IN_BSS) { wl->rx_config |= CFG_BSSID_FILTER_EN; @@ -635,8 +639,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, } /* HW encryption */ -static int wl12xx_set_key_type(struct wl12xx *wl, - struct wl12xx_cmd_set_keys *key, +static int wl1251_set_key_type(struct wl1251 *wl, + struct wl1251_cmd_set_keys *key, enum set_key_cmd cmd, struct ieee80211_key_conf *mac80211_key, const u8 *addr) @@ -666,27 +670,27 @@ static int wl12xx_set_key_type(struct wl12xx *wl, mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; break; default: - wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg); + wl1251_error("Unknown key algo 0x%x", mac80211_key->alg); return -EOPNOTSUPP; } return 0; } -static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - struct wl12xx *wl = hw->priv; - struct wl12xx_cmd_set_keys *wl_cmd; + struct wl1251 *wl = hw->priv; + struct wl1251_cmd_set_keys *wl_cmd; const u8 *addr; int ret; static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); + wl1251_debug(DEBUG_MAC80211, "mac80211 set key"); wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); if (!wl_cmd) { @@ -696,11 +700,11 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, addr = sta ? sta->addr : bcast_addr; - wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); - wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); - wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); + wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); + wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", key->alg, key->keyidx, key->keylen, key->flags); - wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); + wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); if (is_zero_ether_addr(addr)) { /* We dont support TX only encryption */ @@ -710,7 +714,7 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out_unlock; @@ -722,13 +726,13 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, wl_cmd->key_action = KEY_REMOVE; break; default: - wl12xx_error("Unsupported key cmd 0x%x", cmd); + wl1251_error("Unsupported key cmd 0x%x", cmd); break; } - ret = wl12xx_set_key_type(wl, wl_cmd, cmd, key, addr); + ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr); if (ret < 0) { - wl12xx_error("Set KEY type failed"); + wl1251_error("Set KEY type failed"); goto out_sleep; } @@ -755,16 +759,16 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, wl_cmd->id = key->keyidx; wl_cmd->ssid_profile = 0; - wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); + wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); - ret = wl12xx_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); + ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); if (ret < 0) { - wl12xx_warning("could not set keys"); + wl1251_warning("could not set keys"); goto out_sleep; } out_sleep: - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out_unlock: mutex_unlock(&wl->mutex); @@ -775,7 +779,7 @@ out: return ret; } -static int wl12xx_build_basic_rates(char *rates) +static int wl1251_build_basic_rates(char *rates) { u8 index = 0; @@ -787,7 +791,7 @@ static int wl12xx_build_basic_rates(char *rates) return index; } -static int wl12xx_build_extended_rates(char *rates) +static int wl1251_build_extended_rates(char *rates) { u8 index = 0; @@ -804,7 +808,7 @@ static int wl12xx_build_extended_rates(char *rates) } -static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) +static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len) { struct wl12xx_probe_req_template template; struct wl12xx_ie_rates *rates; @@ -831,27 +835,27 @@ static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) /* Basic Rates */ rates = (struct wl12xx_ie_rates *)ptr; rates->header.id = WLAN_EID_SUPP_RATES; - rates->header.len = wl12xx_build_basic_rates(rates->rates); + rates->header.len = wl1251_build_basic_rates(rates->rates); size += sizeof(struct wl12xx_ie_header) + rates->header.len; ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; /* Extended rates */ rates = (struct wl12xx_ie_rates *)ptr; rates->header.id = WLAN_EID_EXT_SUPP_RATES; - rates->header.len = wl12xx_build_extended_rates(rates->rates); + rates->header.len = wl1251_build_extended_rates(rates->rates); size += sizeof(struct wl12xx_ie_header) + rates->header.len; - wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); + wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); - return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template, + return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template, size); } -static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, +static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len, u8 active_scan, u8 high_prio, u8 num_channels, u8 probe_requests) { - struct wl12xx_cmd_trigger_scan_to *trigger = NULL; + struct wl1251_cmd_trigger_scan_to *trigger = NULL; struct cmd_scan *params = NULL; int i, ret; u16 scan_options = 0; @@ -902,9 +906,9 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, memset(params->params.ssid, 0, 32); } - ret = wl12xx_build_probe_req(wl, ssid, len); + ret = wl1251_build_probe_req(wl, ssid, len); if (ret < 0) { - wl12xx_error("PROBE request template failed"); + wl1251_error("PROBE request template failed"); goto out; } @@ -914,25 +918,25 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, trigger->timeout = 0; - ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, sizeof(*trigger)); if (ret < 0) { - wl12xx_error("trigger scan to failed for hw scan"); + wl1251_error("trigger scan to failed for hw scan"); goto out; } - wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); + wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); wl->scanning = true; - ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); + ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); if (ret < 0) - wl12xx_error("SCAN failed"); + wl1251_error("SCAN failed"); - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); + wl1251_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); if (params->header.status != CMD_STATUS_SUCCESS) { - wl12xx_error("TEST command answer error: %d", + wl1251_error("TEST command answer error: %d", params->header.status); wl->scanning = false; ret = -EIO; @@ -945,15 +949,15 @@ out: } -static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, +static int wl1251_op_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; int ret; u8 *ssid = NULL; size_t ssid_len = 0; - wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan"); + wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); if (req->n_ssids) { ssid = req->ssids[0].ssid; @@ -962,13 +966,13 @@ static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; - ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -976,22 +980,22 @@ out: return ret; } -static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; int ret; mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; - ret = wl12xx_acx_rts_threshold(wl, (u16) value); + ret = wl1251_acx_rts_threshold(wl, (u16) value); if (ret < 0) - wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); + wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret); - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -999,21 +1003,21 @@ out: return ret; } -static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, +static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changed) { - enum wl12xx_cmd_ps_mode mode; - struct wl12xx *wl = hw->priv; + enum wl1251_cmd_ps_mode mode; + struct wl1251 *wl = hw->priv; struct sk_buff *beacon; int ret; - wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed"); + wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -1021,18 +1025,18 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, if (bss_conf->assoc) { wl->aid = bss_conf->aid; - ret = wl12xx_build_ps_poll(wl, wl->aid); + ret = wl1251_build_ps_poll(wl, wl->aid); if (ret < 0) goto out_sleep; - ret = wl12xx_acx_aid(wl, wl->aid); + ret = wl1251_acx_aid(wl, wl->aid); if (ret < 0) goto out_sleep; /* If we want to go in PSM but we're not there yet */ if (wl->psm_requested && !wl->psm) { mode = STATION_POWER_SAVE_MODE; - ret = wl12xx_ps_set_mode(wl, mode); + ret = wl1251_ps_set_mode(wl, mode); if (ret < 0) goto out_sleep; } @@ -1040,50 +1044,52 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ERP_SLOT) { if (bss_conf->use_short_slot) - ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT); + ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT); else - ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); + ret = wl1251_acx_slot(wl, SLOT_TIME_LONG); if (ret < 0) { - wl12xx_warning("Set slot time failed %d", ret); + wl1251_warning("Set slot time failed %d", ret); goto out_sleep; } } if (changed & BSS_CHANGED_ERP_PREAMBLE) { if (bss_conf->use_short_preamble) - wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); else - wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG); } if (changed & BSS_CHANGED_ERP_CTS_PROT) { if (bss_conf->use_cts_prot) - ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE); + ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE); else - ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); + ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); if (ret < 0) { - wl12xx_warning("Set ctsprotect failed %d", ret); - goto out_sleep; + wl1251_warning("Set ctsprotect failed %d", ret); + goto out; } } if (changed & BSS_CHANGED_BSSID) { memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - ret = wl12xx_build_null_data(wl); + ret = wl1251_build_null_data(wl); if (ret < 0) goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 5, 100, 1); + ret = wl1251_cmd_join(wl, wl->bss_type, 5, 100, 1); if (ret < 0) - goto out; + goto out_sleep; + wl1251_warning("Set ctsprotect failed %d", ret); + goto out_sleep; } } if (changed & BSS_CHANGED_BEACON) { beacon = ieee80211_beacon_get(hw, vif); - ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data, + ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data, beacon->len); if (ret < 0) { @@ -1091,7 +1097,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, goto out; } - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, + ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, beacon->len); dev_kfree_skb(beacon); @@ -1106,7 +1112,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, } out_sleep: - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -1114,7 +1120,7 @@ out: /* can't be const, mac80211 writes to this */ -static struct ieee80211_rate wl12xx_rates[] = { +static struct ieee80211_rate wl1251_rates[] = { { .bitrate = 10, .hw_value = 0x1, .hw_value_short = 0x1, }, @@ -1157,7 +1163,7 @@ static struct ieee80211_rate wl12xx_rates[] = { }; /* can't be const, mac80211 writes to this */ -static struct ieee80211_channel wl12xx_channels[] = { +static struct ieee80211_channel wl1251_channels[] = { { .hw_value = 1, .center_freq = 2412}, { .hw_value = 2, .center_freq = 2417}, { .hw_value = 3, .center_freq = 2422}, @@ -1174,28 +1180,28 @@ static struct ieee80211_channel wl12xx_channels[] = { }; /* can't be const, mac80211 writes to this */ -static struct ieee80211_supported_band wl12xx_band_2ghz = { - .channels = wl12xx_channels, - .n_channels = ARRAY_SIZE(wl12xx_channels), - .bitrates = wl12xx_rates, - .n_bitrates = ARRAY_SIZE(wl12xx_rates), +static struct ieee80211_supported_band wl1251_band_2ghz = { + .channels = wl1251_channels, + .n_channels = ARRAY_SIZE(wl1251_channels), + .bitrates = wl1251_rates, + .n_bitrates = ARRAY_SIZE(wl1251_rates), }; -static const struct ieee80211_ops wl12xx_ops = { - .start = wl12xx_op_start, - .stop = wl12xx_op_stop, - .add_interface = wl12xx_op_add_interface, - .remove_interface = wl12xx_op_remove_interface, - .config = wl12xx_op_config, - .configure_filter = wl12xx_op_configure_filter, - .tx = wl12xx_op_tx, - .set_key = wl12xx_op_set_key, - .hw_scan = wl12xx_op_hw_scan, - .bss_info_changed = wl12xx_op_bss_info_changed, - .set_rts_threshold = wl12xx_op_set_rts_threshold, +static const struct ieee80211_ops wl1251_ops = { + .start = wl1251_op_start, + .stop = wl1251_op_stop, + .add_interface = wl1251_op_add_interface, + .remove_interface = wl1251_op_remove_interface, + .config = wl1251_op_config, + .configure_filter = wl1251_op_configure_filter, + .tx = wl1251_op_tx, + .set_key = wl1251_op_set_key, + .hw_scan = wl1251_op_hw_scan, + .bss_info_changed = wl1251_op_bss_info_changed, + .set_rts_threshold = wl1251_op_set_rts_threshold, }; -static int wl12xx_register_hw(struct wl12xx *wl) +static int wl1251_register_hw(struct wl1251 *wl) { int ret; @@ -1206,18 +1212,18 @@ static int wl12xx_register_hw(struct wl12xx *wl) ret = ieee80211_register_hw(wl->hw); if (ret < 0) { - wl12xx_error("unable to register mac80211 hw: %d", ret); + wl1251_error("unable to register mac80211 hw: %d", ret); return ret; } wl->mac80211_registered = true; - wl12xx_notice("loaded"); + wl1251_notice("loaded"); return 0; } -static int wl12xx_init_ieee80211(struct wl12xx *wl) +static int wl1251_init_ieee80211(struct wl1251 *wl) { /* The tx descriptor buffer and the TKIP space */ wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) @@ -1232,31 +1238,31 @@ static int wl12xx_init_ieee80211(struct wl12xx *wl) wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wl->hw->wiphy->max_scan_ssids = 1; - wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz; + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); return 0; } -#define WL12XX_DEFAULT_CHANNEL 1 -static int __devinit wl12xx_probe(struct spi_device *spi) +#define WL1251_DEFAULT_CHANNEL 1 +static int __devinit wl1251_probe(struct spi_device *spi) { struct wl12xx_platform_data *pdata; struct ieee80211_hw *hw; - struct wl12xx *wl; + struct wl1251 *wl; int ret, i; static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; pdata = spi->dev.platform_data; if (!pdata) { - wl12xx_error("no platform data"); + wl1251_error("no platform data"); return -ENODEV; } - hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops); + hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); if (!hw) { - wl12xx_error("could not alloc ieee80211_hw"); + wl1251_error("could not alloc ieee80211_hw"); return -ENOMEM; } @@ -1271,8 +1277,8 @@ static int __devinit wl12xx_probe(struct spi_device *spi) skb_queue_head_init(&wl->tx_queue); - INIT_WORK(&wl->filter_work, wl12xx_filter_work); - wl->channel = WL12XX_DEFAULT_CHANNEL; + INIT_WORK(&wl->filter_work, wl1251_filter_work); + wl->channel = WL1251_DEFAULT_CHANNEL; wl->scanning = false; wl->default_key = 0; wl->listen_int = 1; @@ -1280,17 +1286,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi) wl->rx_handled = 0; wl->rx_current_buffer = 0; wl->rx_last_id = 0; - wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; - wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + wl->rx_config = WL1251_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1251_DEFAULT_RX_FILTER; wl->elp = false; wl->psm = 0; wl->psm_requested = false; wl->tx_queue_stopped = false; - wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + wl->power_level = WL1251_DEFAULT_POWER_LEVEL; /* We use the default power on sleep time until we know which chip * we're using */ - wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP; + wl->chip.power_on_sleep = WL1251_DEFAULT_POWER_ON_SLEEP; for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) wl->tx_frames[i] = NULL; @@ -1304,7 +1310,7 @@ static int __devinit wl12xx_probe(struct spi_device *spi) memcpy(wl->mac_addr, nokia_oui, 3); get_random_bytes(wl->mac_addr + 3, 3); - wl->state = WL12XX_STATE_OFF; + wl->state = WL1251_STATE_OFF; mutex_init(&wl->mutex); wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; @@ -1312,7 +1318,7 @@ static int __devinit wl12xx_probe(struct spi_device *spi) wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); if (!wl->rx_descriptor) { - wl12xx_error("could not allocate memory for rx descriptor"); + wl1251_error("could not allocate memory for rx descriptor"); ret = -ENOMEM; goto out_free; } @@ -1323,27 +1329,27 @@ static int __devinit wl12xx_probe(struct spi_device *spi) ret = spi_setup(spi); if (ret < 0) { - wl12xx_error("spi_setup failed"); + wl1251_error("spi_setup failed"); goto out_free; } wl->set_power = pdata->set_power; if (!wl->set_power) { - wl12xx_error("set power function missing in platform data"); + wl1251_error("set power function missing in platform data"); ret = -ENODEV; goto out_free; } wl->irq = spi->irq; if (wl->irq < 0) { - wl12xx_error("irq missing in platform data"); + wl1251_error("irq missing in platform data"); ret = -ENODEV; goto out_free; } - ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); + ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); if (ret < 0) { - wl12xx_error("request_irq() failed: %d", ret); + wl1251_error("request_irq() failed: %d", ret); goto out_free; } @@ -1351,17 +1357,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi) disable_irq(wl->irq); - ret = wl12xx_init_ieee80211(wl); + ret = wl1251_init_ieee80211(wl); if (ret) goto out_irq; - ret = wl12xx_register_hw(wl); + ret = wl1251_register_hw(wl); if (ret) goto out_irq; - wl12xx_debugfs_init(wl); + wl1251_debugfs_init(wl); - wl12xx_notice("initialized"); + wl1251_notice("initialized"); return 0; @@ -1377,13 +1383,13 @@ static int __devinit wl12xx_probe(struct spi_device *spi) return ret; } -static int __devexit wl12xx_remove(struct spi_device *spi) +static int __devexit wl1251_remove(struct spi_device *spi) { - struct wl12xx *wl = dev_get_drvdata(&spi->dev); + struct wl1251 *wl = dev_get_drvdata(&spi->dev); ieee80211_unregister_hw(wl->hw); - wl12xx_debugfs_exit(wl); + wl1251_debugfs_exit(wl); free_irq(wl->irq, wl); kfree(wl->target_mem_map); @@ -1402,24 +1408,25 @@ static int __devexit wl12xx_remove(struct spi_device *spi) } -static struct spi_driver wl12xx_spi_driver = { +static struct spi_driver wl1251_spi_driver = { .driver = { + /* FIXME: use wl12xx name to not break the user space */ .name = "wl12xx", .bus = &spi_bus_type, .owner = THIS_MODULE, }, - .probe = wl12xx_probe, - .remove = __devexit_p(wl12xx_remove), + .probe = wl1251_probe, + .remove = __devexit_p(wl1251_remove), }; -static int __init wl12xx_init(void) +static int __init wl1251_init(void) { int ret; - ret = spi_register_driver(&wl12xx_spi_driver); + ret = spi_register_driver(&wl1251_spi_driver); if (ret < 0) { - wl12xx_error("failed to register spi driver: %d", ret); + wl1251_error("failed to register spi driver: %d", ret); goto out; } @@ -1427,15 +1434,15 @@ out: return ret; } -static void __exit wl12xx_exit(void) +static void __exit wl1251_exit(void) { - spi_unregister_driver(&wl12xx_spi_driver); + spi_unregister_driver(&wl1251_spi_driver); - wl12xx_notice("unloaded"); + wl1251_notice("unloaded"); } -module_init(wl12xx_init); -module_exit(wl12xx_exit); +module_init(wl1251_init); +module_exit(wl1251_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kalle Valo , " diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c index ca9a856..67d3d5a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_netlink.c +++ b/drivers/net/wireless/wl12xx/wl1251_netlink.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -35,52 +35,52 @@ #include "wl1251_acx.h" /* FIXME: this should be changed as soon as user space catches up */ -#define WL12XX_NL_NAME "wl1251" -#define WL12XX_NL_VERSION 1 - -#define WL12XX_MAX_TEST_LENGTH 1024 -#define WL12XX_MAX_NVS_LENGTH 1024 - -enum wl12xx_nl_commands { - WL12XX_NL_CMD_UNSPEC, - WL12XX_NL_CMD_TEST, - WL12XX_NL_CMD_INTERROGATE, - WL12XX_NL_CMD_CONFIGURE, - WL12XX_NL_CMD_PHY_REG_READ, - WL12XX_NL_CMD_NVS_PUSH, - WL12XX_NL_CMD_REG_WRITE, - WL12XX_NL_CMD_REG_READ, - WL12XX_NL_CMD_SET_PLT_MODE, - - __WL12XX_NL_CMD_AFTER_LAST +#define WL1251_NL_NAME "wl1251" +#define WL1251_NL_VERSION 1 + +#define WL1251_MAX_TEST_LENGTH 1024 +#define WL1251_MAX_NVS_LENGTH 1024 + +enum wl1251_nl_commands { + WL1251_NL_CMD_UNSPEC, + WL1251_NL_CMD_TEST, + WL1251_NL_CMD_INTERROGATE, + WL1251_NL_CMD_CONFIGURE, + WL1251_NL_CMD_PHY_REG_READ, + WL1251_NL_CMD_NVS_PUSH, + WL1251_NL_CMD_REG_WRITE, + WL1251_NL_CMD_REG_READ, + WL1251_NL_CMD_SET_PLT_MODE, + + __WL1251_NL_CMD_AFTER_LAST }; -#define WL12XX_NL_CMD_MAX (__WL12XX_NL_CMD_AFTER_LAST - 1) - -enum wl12xx_nl_attrs { - WL12XX_NL_ATTR_UNSPEC, - WL12XX_NL_ATTR_IFNAME, - WL12XX_NL_ATTR_CMD_TEST_PARAM, - WL12XX_NL_ATTR_CMD_TEST_ANSWER, - WL12XX_NL_ATTR_CMD_IE, - WL12XX_NL_ATTR_CMD_IE_LEN, - WL12XX_NL_ATTR_CMD_IE_BUFFER, - WL12XX_NL_ATTR_CMD_IE_ANSWER, - WL12XX_NL_ATTR_REG_ADDR, - WL12XX_NL_ATTR_REG_VAL, - WL12XX_NL_ATTR_NVS_BUFFER, - WL12XX_NL_ATTR_NVS_LEN, - WL12XX_NL_ATTR_PLT_MODE, - - __WL12XX_NL_ATTR_AFTER_LAST +#define WL1251_NL_CMD_MAX (__WL1251_NL_CMD_AFTER_LAST - 1) + +enum wl1251_nl_attrs { + WL1251_NL_ATTR_UNSPEC, + WL1251_NL_ATTR_IFNAME, + WL1251_NL_ATTR_CMD_TEST_PARAM, + WL1251_NL_ATTR_CMD_TEST_ANSWER, + WL1251_NL_ATTR_CMD_IE, + WL1251_NL_ATTR_CMD_IE_LEN, + WL1251_NL_ATTR_CMD_IE_BUFFER, + WL1251_NL_ATTR_CMD_IE_ANSWER, + WL1251_NL_ATTR_REG_ADDR, + WL1251_NL_ATTR_REG_VAL, + WL1251_NL_ATTR_NVS_BUFFER, + WL1251_NL_ATTR_NVS_LEN, + WL1251_NL_ATTR_PLT_MODE, + + __WL1251_NL_ATTR_AFTER_LAST }; -#define WL12XX_NL_ATTR_MAX (__WL12XX_NL_ATTR_AFTER_LAST - 1) +#define WL1251_NL_ATTR_MAX (__WL1251_NL_ATTR_AFTER_LAST - 1) -static struct genl_family wl12xx_nl_family = { +static struct genl_family wl1251_nl_family = { .id = GENL_ID_GENERATE, - .name = WL12XX_NL_NAME, + .name = WL1251_NL_NAME, .hdrsize = 0, - .version = WL12XX_NL_VERSION, - .maxattr = WL12XX_NL_ATTR_MAX, + .version = WL1251_NL_VERSION, + .maxattr = WL1251_NL_ATTR_MAX, }; static struct net_device *ifname_to_netdev(struct net *net, @@ -88,17 +88,17 @@ static struct net_device *ifname_to_netdev(struct net *net, { char *ifname; - if (!info->attrs[WL12XX_NL_ATTR_IFNAME]) + if (!info->attrs[WL1251_NL_ATTR_IFNAME]) return NULL; - ifname = nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]); + ifname = nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]); - wl12xx_debug(DEBUG_NETLINK, "Looking for %s", ifname); + wl1251_debug(DEBUG_NETLINK, "Looking for %s", ifname); return dev_get_by_name(net, ifname); } -static struct wl12xx *ifname_to_wl12xx(struct net *net, struct genl_info *info) +static struct wl1251 *ifname_to_wl1251(struct net *net, struct genl_info *info) { struct net_device *netdev; struct wireless_dev *wdev; @@ -107,25 +107,25 @@ static struct wl12xx *ifname_to_wl12xx(struct net *net, struct genl_info *info) netdev = ifname_to_netdev(net, info); if (netdev == NULL) { - wl12xx_error("Wrong interface"); + wl1251_error("Wrong interface"); return NULL; } wdev = netdev->ieee80211_ptr; if (wdev == NULL) { - wl12xx_error("ieee80211_ptr is NULL"); + wl1251_error("ieee80211_ptr is NULL"); return NULL; } wiphy = wdev->wiphy; if (wiphy == NULL) { - wl12xx_error("wiphy is NULL"); + wl1251_error("wiphy is NULL"); return NULL; } hw = wiphy_priv(wiphy); if (hw == NULL) { - wl12xx_error("hw is NULL"); + wl1251_error("hw is NULL"); return NULL; } @@ -134,20 +134,20 @@ static struct wl12xx *ifname_to_wl12xx(struct net *net, struct genl_info *info) return hw->priv; } -static int wl12xx_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; - struct wl12xx_command *cmd; + struct wl1251 *wl; + struct wl1251_command *cmd; char *buf; int buf_len, ret, cmd_len; u8 answer; - if (!info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]) + if (!info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]) return -EINVAL; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); return -EINVAL; } @@ -155,20 +155,20 @@ static int wl12xx_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) if (!cmd) return -ENOMEM; - buf = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]); - buf_len = nla_len(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]); - answer = nla_get_u8(info->attrs[WL12XX_NL_ATTR_CMD_TEST_ANSWER]); + buf = nla_data(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]); + buf_len = nla_len(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]); + answer = nla_get_u8(info->attrs[WL1251_NL_ATTR_CMD_TEST_ANSWER]); cmd->header.id = CMD_TEST; memcpy(cmd->parameters, buf, buf_len); - cmd_len = sizeof(struct wl12xx_cmd_header) + buf_len; + cmd_len = sizeof(struct wl1251_cmd_header) + buf_len; mutex_lock(&wl->mutex); - ret = wl12xx_cmd_test(wl, cmd, cmd_len, answer); + ret = wl1251_cmd_test(wl, cmd, cmd_len, answer); mutex_unlock(&wl->mutex); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto out; } @@ -183,49 +183,49 @@ static int wl12xx_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) } hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl12xx_nl_family, 0, WL12XX_NL_CMD_TEST); + &wl1251_nl_family, 0, WL1251_NL_CMD_TEST); if (IS_ERR(hdr)) { ret = PTR_ERR(hdr); goto nla_put_failure; } - NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, - nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); - NLA_PUT(msg, WL12XX_NL_ATTR_CMD_TEST_ANSWER, + NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, + nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); + NLA_PUT(msg, WL1251_NL_ATTR_CMD_TEST_ANSWER, sizeof(*cmd), cmd); ret = genlmsg_end(msg, hdr); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } - wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent, answer"); + wl1251_debug(DEBUG_NETLINK, "TEST cmd sent, answer"); ret = genlmsg_reply(msg, info); goto out; nla_put_failure: nlmsg_free(msg); } else - wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent"); + wl1251_debug(DEBUG_NETLINK, "TEST cmd sent"); out: kfree(cmd); return ret; } -static int wl12xx_nl_interrogate(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_interrogate(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; struct sk_buff *msg; int ret = -ENOBUFS, cmd_ie, cmd_ie_len; - struct wl12xx_command *cmd; + struct wl1251_command *cmd; void *hdr; - if (!info->attrs[WL12XX_NL_ATTR_CMD_IE]) + if (!info->attrs[WL1251_NL_ATTR_CMD_IE]) return -EINVAL; - if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]) + if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]) return -EINVAL; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -236,45 +236,45 @@ static int wl12xx_nl_interrogate(struct sk_buff *skb, struct genl_info *info) if (!msg) return -ENOMEM; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); ret = -EINVAL; goto nla_put_failure; } /* acx id */ - cmd_ie = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE]); + cmd_ie = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE]); /* maximum length of acx, including all headers */ - cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]); + cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]); - wl12xx_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)", + wl1251_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)", cmd_ie, cmd_ie_len); mutex_lock(&wl->mutex); - ret = wl12xx_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len); + ret = wl1251_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len); mutex_unlock(&wl->mutex); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl12xx_nl_family, 0, WL12XX_NL_CMD_INTERROGATE); + &wl1251_nl_family, 0, WL1251_NL_CMD_INTERROGATE); if (IS_ERR(hdr)) { ret = PTR_ERR(hdr); goto nla_put_failure; } - NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, - nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); - NLA_PUT(msg, WL12XX_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd); + NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, + nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); + NLA_PUT(msg, WL1251_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd); ret = genlmsg_end(msg, hdr); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } @@ -288,36 +288,36 @@ static int wl12xx_nl_interrogate(struct sk_buff *skb, struct genl_info *info) return ret; } -static int wl12xx_nl_configure(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_configure(struct sk_buff *skb, struct genl_info *info) { int ret = 0, cmd_ie_len, acx_len; struct acx_header *acx = NULL; struct sk_buff *msg; - struct wl12xx *wl; + struct wl1251 *wl; void *cmd_ie; u16 *id; - if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER]) + if (!info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]) return -EINVAL; - if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]) + if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]) return -EINVAL; msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) return -ENOMEM; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); ret = -EINVAL; goto nla_put_failure; } /* contains the acx header but not the cmd header */ - cmd_ie = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER]); + cmd_ie = nla_data(info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]); - cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]); + cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]); /* acx id is in the first two bytes */ id = cmd_ie; @@ -334,15 +334,15 @@ static int wl12xx_nl_configure(struct sk_buff *skb, struct genl_info *info) memcpy(&acx->id, cmd_ie, cmd_ie_len); mutex_lock(&wl->mutex); - ret = wl12xx_cmd_configure(wl, *id, acx, acx_len); + ret = wl1251_cmd_configure(wl, *id, acx, acx_len); mutex_unlock(&wl->mutex); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } - wl12xx_debug(DEBUG_NETLINK, "CONFIGURE cmd sent"); + wl1251_debug(DEBUG_NETLINK, "CONFIGURE cmd sent"); nla_put_failure: kfree(acx); @@ -351,24 +351,24 @@ static int wl12xx_nl_configure(struct sk_buff *skb, struct genl_info *info) return ret; } -static int wl12xx_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; struct sk_buff *msg; u32 reg_addr, *reg_value = NULL; int ret = 0; void *hdr; - if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) return -EINVAL; msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) return -ENOMEM; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); ret = -EINVAL; goto nla_put_failure; } @@ -379,36 +379,36 @@ static int wl12xx_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) goto nla_put_failure; } - reg_addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); + reg_addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); - wl12xx_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr); + wl1251_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr); mutex_lock(&wl->mutex); - ret = wl12xx_cmd_read_memory(wl, reg_addr, reg_value, + ret = wl1251_cmd_read_memory(wl, reg_addr, reg_value, sizeof(*reg_value)); mutex_unlock(&wl->mutex); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ); + &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ); if (IS_ERR(hdr)) { ret = PTR_ERR(hdr); goto nla_put_failure; } - NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, - nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, + nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, *reg_value); + NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, *reg_value); ret = genlmsg_end(msg, hdr); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } @@ -423,27 +423,27 @@ static int wl12xx_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) return ret; } -static int wl12xx_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; int ret = 0; - if (!info->attrs[WL12XX_NL_ATTR_NVS_BUFFER]) + if (!info->attrs[WL1251_NL_ATTR_NVS_BUFFER]) return -EINVAL; - if (!info->attrs[WL12XX_NL_ATTR_NVS_LEN]) + if (!info->attrs[WL1251_NL_ATTR_NVS_LEN]) return -EINVAL; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); return -EINVAL; } mutex_lock(&wl->mutex); - wl->nvs_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_NVS_LEN]); + wl->nvs_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_NVS_LEN]); if (wl->nvs_len % 4) { - wl12xx_error("NVS size is not multiple of 32: %d", wl->nvs_len); + wl1251_error("NVS size is not multiple of 32: %d", wl->nvs_len); ret = -EILSEQ; goto out; } @@ -453,16 +453,16 @@ static int wl12xx_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL); if (wl->nvs == NULL) { - wl12xx_error("Can't allocate NVS"); + wl1251_error("Can't allocate NVS"); ret = -ENOMEM; goto out; } memcpy(wl->nvs, - nla_data(info->attrs[WL12XX_NL_ATTR_NVS_BUFFER]), + nla_data(info->attrs[WL1251_NL_ATTR_NVS_BUFFER]), wl->nvs_len); - wl12xx_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes", + wl1251_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes", wl->nvs_len); out: @@ -471,48 +471,48 @@ out: return ret; } -static int wl12xx_nl_reg_read(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_reg_read(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; u32 addr, val; int ret = 0; struct sk_buff *msg; void *hdr; - if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) return -EINVAL; msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) return -ENOMEM; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); return -EINVAL; } - addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); + addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); mutex_lock(&wl->mutex); - val = wl12xx_reg_read32(wl, addr); + val = wl1251_reg_read32(wl, addr); mutex_unlock(&wl->mutex); hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ); + &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ); if (IS_ERR(hdr)) { ret = PTR_ERR(hdr); goto nla_put_failure; } - NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, - nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, + nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, val); + NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, val); ret = genlmsg_end(msg, hdr); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } @@ -524,56 +524,56 @@ static int wl12xx_nl_reg_read(struct sk_buff *skb, struct genl_info *info) return ret; } -static int wl12xx_nl_reg_write(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_reg_write(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; u32 addr, val; - if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) return -EINVAL; - if (!info->attrs[WL12XX_NL_ATTR_REG_VAL]) + if (!info->attrs[WL1251_NL_ATTR_REG_VAL]) return -EINVAL; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); return -EINVAL; } - addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); - val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_VAL]); + addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); + val = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_VAL]); mutex_lock(&wl->mutex); - wl12xx_reg_write32(wl, addr, val); + wl1251_reg_write32(wl, addr, val); mutex_unlock(&wl->mutex); return 0; } -static int wl12xx_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; u32 val; int ret; - if (!info->attrs[WL12XX_NL_ATTR_PLT_MODE]) + if (!info->attrs[WL1251_NL_ATTR_PLT_MODE]) return -EINVAL; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); return -EINVAL; } - val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_PLT_MODE]); + val = nla_get_u32(info->attrs[WL1251_NL_ATTR_PLT_MODE]); switch (val) { case 0: - ret = wl12xx_plt_stop(wl); + ret = wl1251_plt_stop(wl); break; case 1: - ret = wl12xx_plt_start(wl); + ret = wl1251_plt_start(wl); break; default: ret = -EINVAL; @@ -583,97 +583,97 @@ static int wl12xx_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info) return ret; } -static struct nla_policy wl12xx_nl_policy[WL12XX_NL_ATTR_MAX + 1] = { - [WL12XX_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, +static struct nla_policy wl1251_nl_policy[WL1251_NL_ATTR_MAX + 1] = { + [WL1251_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, - [WL12XX_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY, - .len = WL12XX_MAX_TEST_LENGTH }, - [WL12XX_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 }, - [WL12XX_NL_ATTR_CMD_IE] = { .type = NLA_U32 }, - [WL12XX_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 }, - [WL12XX_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY, - .len = WL12XX_MAX_TEST_LENGTH }, - [WL12XX_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY, - .len = WL12XX_MAX_TEST_LENGTH }, - [WL12XX_NL_ATTR_REG_ADDR] = { .type = NLA_U32 }, - [WL12XX_NL_ATTR_REG_VAL] = { .type = NLA_U32 }, - [WL12XX_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY, - .len = WL12XX_MAX_NVS_LENGTH }, - [WL12XX_NL_ATTR_NVS_LEN] = { .type = NLA_U32 }, - [WL12XX_NL_ATTR_PLT_MODE] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY, + .len = WL1251_MAX_TEST_LENGTH }, + [WL1251_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 }, + [WL1251_NL_ATTR_CMD_IE] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY, + .len = WL1251_MAX_TEST_LENGTH }, + [WL1251_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY, + .len = WL1251_MAX_TEST_LENGTH }, + [WL1251_NL_ATTR_REG_ADDR] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_REG_VAL] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY, + .len = WL1251_MAX_NVS_LENGTH }, + [WL1251_NL_ATTR_NVS_LEN] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_PLT_MODE] = { .type = NLA_U32 }, }; -static struct genl_ops wl12xx_nl_ops[] = { +static struct genl_ops wl1251_nl_ops[] = { { - .cmd = WL12XX_NL_CMD_TEST, - .doit = wl12xx_nl_test_cmd, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_TEST, + .doit = wl1251_nl_test_cmd, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_INTERROGATE, - .doit = wl12xx_nl_interrogate, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_INTERROGATE, + .doit = wl1251_nl_interrogate, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_CONFIGURE, - .doit = wl12xx_nl_configure, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_CONFIGURE, + .doit = wl1251_nl_configure, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_PHY_REG_READ, - .doit = wl12xx_nl_phy_reg_read, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_PHY_REG_READ, + .doit = wl1251_nl_phy_reg_read, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_NVS_PUSH, - .doit = wl12xx_nl_nvs_push, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_NVS_PUSH, + .doit = wl1251_nl_nvs_push, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_REG_WRITE, - .doit = wl12xx_nl_reg_write, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_REG_WRITE, + .doit = wl1251_nl_reg_write, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_REG_READ, - .doit = wl12xx_nl_reg_read, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_REG_READ, + .doit = wl1251_nl_reg_read, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_SET_PLT_MODE, - .doit = wl12xx_nl_set_plt_mode, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_SET_PLT_MODE, + .doit = wl1251_nl_set_plt_mode, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, }; -int wl12xx_nl_register(void) +int wl1251_nl_register(void) { int err, i; - err = genl_register_family(&wl12xx_nl_family); + err = genl_register_family(&wl1251_nl_family); if (err) return err; - for (i = 0; i < ARRAY_SIZE(wl12xx_nl_ops); i++) { - err = genl_register_ops(&wl12xx_nl_family, &wl12xx_nl_ops[i]); + for (i = 0; i < ARRAY_SIZE(wl1251_nl_ops); i++) { + err = genl_register_ops(&wl1251_nl_family, &wl1251_nl_ops[i]); if (err) goto err_out; } return 0; err_out: - genl_unregister_family(&wl12xx_nl_family); + genl_unregister_family(&wl1251_nl_family); return err; } -void wl12xx_nl_unregister(void) +void wl1251_nl_unregister(void) { - genl_unregister_family(&wl12xx_nl_family); + genl_unregister_family(&wl1251_nl_family); } diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h index acfbd02..ee36695 100644 --- a/drivers/net/wireless/wl12xx/wl1251_netlink.h +++ b/drivers/net/wireless/wl12xx/wl1251_netlink.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2009 Nokia Corporation * @@ -21,10 +21,10 @@ * */ -#ifndef __WL12XX_NETLINK_H__ -#define __WL12XX_NETLINK_H__ +#ifndef __WL1251_NETLINK_H__ +#define __WL1251_NETLINK_H__ -int wl12xx_nl_register(void); -void wl12xx_nl_unregister(void); +int wl1251_nl_register(void); +void wl1251_nl_unregister(void); -#endif /* __WL12XX_NETLINK_H__ */ +#endif /* __WL1251_NETLINK_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c index cdfd2c2..96a45f5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008-2009 Nokia Corporation * @@ -35,7 +35,7 @@ #include "wl1251_ps.h" #include "wl1251_init.h" -static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = { +static struct wl1251_partition_set wl1251_part_table[PART_TABLE_LEN] = { [PART_DOWN] = { .mem = { .start = 0x00000000, @@ -75,31 +75,31 @@ static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) }; -static int wl1251_upload_firmware(struct wl12xx *wl) +static int wl1251_upload_firmware(struct wl1251 *wl) { - struct wl12xx_partition_set *p_table = wl->chip.p_table; + struct wl1251_partition_set *p_table = wl->chip.p_table; int addr, chunk_num, partition_limit; size_t fw_data_len; u8 *p; /* whal_FwCtrl_LoadFwImageSm() */ - wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", - wl12xx_reg_read32(wl, CHIP_ID_B)); + wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", + wl1251_reg_read32(wl, CHIP_ID_B)); /* 10.0 check firmware length and set partition */ fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | (wl->fw[6] << 8) | (wl->fw[7]); - wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, + wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, CHUNK_SIZE); if ((fw_data_len % 4) != 0) { - wl12xx_error("firmware length not multiple of four"); + wl1251_error("firmware length not multiple of four"); return -EIO; } - wl12xx_set_partition(wl, + wl1251_set_partition(wl, p_table[PART_DOWN].mem.start, p_table[PART_DOWN].mem.size, p_table[PART_DOWN].reg.start, @@ -118,7 +118,7 @@ static int wl1251_upload_firmware(struct wl12xx *wl) chunk_num * CHUNK_SIZE; partition_limit = chunk_num * CHUNK_SIZE + p_table[PART_DOWN].mem.size; - wl12xx_set_partition(wl, + wl1251_set_partition(wl, addr, p_table[PART_DOWN].mem.size, p_table[PART_DOWN].reg.start, @@ -128,9 +128,9 @@ static int wl1251_upload_firmware(struct wl12xx *wl) /* 10.3 upload the chunk */ addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", p, addr); - wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE); + wl1251_spi_mem_write(wl, addr, p, CHUNK_SIZE); chunk_num++; } @@ -138,14 +138,14 @@ static int wl1251_upload_firmware(struct wl12xx *wl) /* 10.4 upload the last chunk */ addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", + wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); - wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + wl1251_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); return 0; } -static int wl1251_upload_nvs(struct wl12xx *wl) +static int wl1251_upload_nvs(struct wl1251 *wl) { size_t nvs_len, nvs_bytes_written, burst_len; int nvs_start, i; @@ -181,10 +181,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl) val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - wl12xx_debug(DEBUG_BOOT, + wl1251_debug(DEBUG_BOOT, "nvs burst write 0x%x: 0x%x", dest_addr, val); - wl12xx_mem_write32(wl, dest_addr, val); + wl1251_mem_write32(wl, dest_addr, val); nvs_ptr += 4; dest_addr += 4; @@ -200,7 +200,7 @@ static int wl1251_upload_nvs(struct wl12xx *wl) nvs_len = ALIGN(nvs_len, 4); /* Now we must set the partition correctly */ - wl12xx_set_partition(wl, nvs_start, + wl1251_set_partition(wl, nvs_start, wl->chip.p_table[PART_DOWN].mem.size, wl->chip.p_table[PART_DOWN].reg.start, wl->chip.p_table[PART_DOWN].reg.size); @@ -213,10 +213,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl) val = cpu_to_le32(val); - wl12xx_debug(DEBUG_BOOT, + wl1251_debug(DEBUG_BOOT, "nvs write table 0x%x: 0x%x", nvs_start, val); - wl12xx_mem_write32(wl, nvs_start, val); + wl1251_mem_write32(wl, nvs_start, val); nvs_ptr += 4; nvs_bytes_written += 4; @@ -226,12 +226,12 @@ static int wl1251_upload_nvs(struct wl12xx *wl) return 0; } -static int wl1251_boot(struct wl12xx *wl) +static int wl1251_boot(struct wl1251 *wl) { int ret = 0, minor_minor_e2_ver; u32 tmp, boot_data; - ret = wl12xx_boot_soft_reset(wl); + ret = wl1251_boot_soft_reset(wl); if (ret < 0) goto out; @@ -242,39 +242,39 @@ static int wl1251_boot(struct wl12xx *wl) /* write firmware's last address (ie. it's length) to * ACX_EEPROMLESS_IND_REG */ - wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); + wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); /* 6. read the EEPROM parameters */ - tmp = wl12xx_reg_read32(wl, SCR_PAD2); + tmp = wl1251_reg_read32(wl, SCR_PAD2); /* 7. read bootdata */ wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; - tmp = wl12xx_reg_read32(wl, SCR_PAD3); + tmp = wl1251_reg_read32(wl, SCR_PAD3); /* 8. check bootdata and call restart sequence */ wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; - wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " + wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", wl->boot_attr.radio_type, wl->boot_attr.major, wl->boot_attr.minor, minor_minor_e2_ver); - ret = wl12xx_boot_init_seq(wl); + ret = wl1251_boot_init_seq(wl); if (ret < 0) goto out; /* 9. NVS processing done */ - boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); - wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); + wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); /* 10. check that ECPU_CONTROL_HALT bits are set in * pWhalBus->uBootData and start uploading firmware */ if ((boot_data & ECPU_CONTROL_HALT) == 0) { - wl12xx_error("boot failed, ECPU_CONTROL_HALT not set"); + wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); ret = -EIO; goto out; } @@ -284,7 +284,7 @@ static int wl1251_boot(struct wl12xx *wl) goto out; /* 10.5 start firmware */ - ret = wl12xx_boot_run_firmware(wl); + ret = wl1251_boot_run_firmware(wl); if (ret < 0) goto out; @@ -292,12 +292,12 @@ out: return ret; } -static int wl1251_mem_cfg(struct wl12xx *wl) +static int wl1251_mem_cfg(struct wl1251 *wl) { struct wl1251_acx_config_memory *mem_conf; int ret, i; - wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg"); + wl1251_debug(DEBUG_ACX, "wl1251 mem cfg"); mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); if (!mem_conf) { @@ -327,10 +327,10 @@ static int wl1251_mem_cfg(struct wl12xx *wl) mem_conf->tx_queue_config[i].attributes = i; } - ret = wl12xx_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, sizeof(*mem_conf)); if (ret < 0) { - wl12xx_warning("wl1251 mem config failed: %d", ret); + wl1251_warning("wl1251 mem config failed: %d", ret); goto out; } @@ -339,7 +339,7 @@ out: return ret; } -static int wl1251_hw_init_mem_config(struct wl12xx *wl) +static int wl1251_hw_init_mem_config(struct wl1251 *wl) { int ret; @@ -350,15 +350,15 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl) wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), GFP_KERNEL); if (!wl->target_mem_map) { - wl12xx_error("couldn't allocate target memory map"); + wl1251_error("couldn't allocate target memory map"); return -ENOMEM; } /* we now ask for the firmware built memory map */ - ret = wl12xx_acx_mem_map(wl, wl->target_mem_map, + ret = wl1251_acx_mem_map(wl, wl->target_mem_map, sizeof(struct wl1251_acx_mem_map)); if (ret < 0) { - wl12xx_error("couldn't retrieve firmware memory map"); + wl1251_error("couldn't retrieve firmware memory map"); kfree(wl->target_mem_map); wl->target_mem_map = NULL; return ret; @@ -367,19 +367,19 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl) return 0; } -static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag) +static void wl1251_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) { u32 cpu_ctrl; /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); /* 10.5.1 run the firmware (II) */ cpu_ctrl &= ~flag; - wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); + wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); } -static void wl1251_target_enable_interrupts(struct wl12xx *wl) +static void wl1251_target_enable_interrupts(struct wl1251 *wl) { /* Enable target's interrupts */ wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | @@ -388,60 +388,60 @@ static void wl1251_target_enable_interrupts(struct wl12xx *wl) WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B | WL1251_ACX_INTR_INIT_COMPLETE; - wl12xx_boot_target_enable_interrupts(wl); + wl1251_boot_target_enable_interrupts(wl); } -static void wl1251_fw_version(struct wl12xx *wl) +static void wl1251_fw_version(struct wl1251 *wl) { - wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); + wl1251_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); } static void wl1251_irq_work(struct work_struct *work) { u32 intr; - struct wl12xx *wl = - container_of(work, struct wl12xx, irq_work); + struct wl1251 *wl = + container_of(work, struct wl1251, irq_work); int ret; mutex_lock(&wl->mutex); - wl12xx_debug(DEBUG_IRQ, "IRQ work"); + wl1251_debug(DEBUG_IRQ, "IRQ work"); - if (wl->state == WL12XX_STATE_OFF) + if (wl->state == WL1251_STATE_OFF) goto out; - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr); + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); if (wl->data_path) { wl->rx_counter = - wl12xx_mem_read32(wl, wl->data_path->rx_control_addr); + wl1251_mem_read32(wl, wl->data_path->rx_control_addr); /* We handle a frmware bug here */ switch ((wl->rx_counter - wl->rx_handled) & 0xf) { case 0: - wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync"); + wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); intr &= ~WL1251_ACX_INTR_RX0_DATA; intr &= ~WL1251_ACX_INTR_RX1_DATA; break; case 1: - wl12xx_debug(DEBUG_IRQ, "RX: FW +1"); + wl1251_debug(DEBUG_IRQ, "RX: FW +1"); intr |= WL1251_ACX_INTR_RX0_DATA; intr &= ~WL1251_ACX_INTR_RX1_DATA; break; case 2: - wl12xx_debug(DEBUG_IRQ, "RX: FW +2"); + wl1251_debug(DEBUG_IRQ, "RX: FW +2"); intr |= WL1251_ACX_INTR_RX0_DATA; intr |= WL1251_ACX_INTR_RX1_DATA; break; default: - wl12xx_warning("RX: FW and host out of sync: %d", + wl1251_warning("RX: FW and host out of sync: %d", wl->rx_counter - wl->rx_handled); break; } @@ -449,49 +449,49 @@ static void wl1251_irq_work(struct work_struct *work) wl->rx_handled = wl->rx_counter; - wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); + wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); } intr &= wl->intr_mask; if (intr == 0) { - wl12xx_debug(DEBUG_IRQ, "INTR is 0"); - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + wl1251_debug(DEBUG_IRQ, "INTR is 0"); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); goto out_sleep; } if (intr & WL1251_ACX_INTR_RX0_DATA) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); - wl12xx_rx(wl); + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); + wl1251_rx(wl); } if (intr & WL1251_ACX_INTR_RX1_DATA) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); - wl12xx_rx(wl); + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); + wl1251_rx(wl); } if (intr & WL1251_ACX_INTR_TX_RESULT) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); wl1251_tx_complete(wl); } if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); if (intr & WL1251_ACX_INTR_EVENT_A) - wl12xx_event_handle(wl, 0); + wl1251_event_handle(wl, 0); else - wl12xx_event_handle(wl, 1); + wl1251_event_handle(wl, 1); } if (intr & WL1251_ACX_INTR_INIT_COMPLETE) - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); out_sleep: - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -529,20 +529,20 @@ static int wl1251_hw_init_txq_fill(u8 qid, (QOS_TX_LOW_VO_DEF * num_blocks) / 100; break; default: - wl12xx_error("Invalid TX queue id: %d", qid); + wl1251_error("Invalid TX queue id: %d", qid); return -EINVAL; } return 0; } -static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) +static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) { struct acx_tx_queue_qos_config *config; struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; int ret, i; - wl12xx_debug(DEBUG_ACX, "acx tx queue config"); + wl1251_debug(DEBUG_ACX, "acx tx queue config"); config = kzalloc(sizeof(*config), GFP_KERNEL); if (!config) { @@ -556,7 +556,7 @@ static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) if (ret < 0) goto out; - ret = wl12xx_cmd_configure(wl, ACX_TX_QUEUE_CFG, + ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, config, sizeof(*config)); if (ret < 0) goto out; @@ -567,7 +567,7 @@ out: return ret; } -static int wl1251_hw_init_data_path_config(struct wl12xx *wl) +static int wl1251_hw_init_data_path_config(struct wl1251 *wl) { int ret; @@ -575,11 +575,11 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl) wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), GFP_KERNEL); if (!wl->data_path) { - wl12xx_error("Couldnt allocate data path parameters"); + wl1251_error("Couldnt allocate data path parameters"); return -ENOMEM; } - ret = wl12xx_acx_data_path_params(wl, wl->data_path); + ret = wl1251_acx_data_path_params(wl, wl->data_path); if (ret < 0) { kfree(wl->data_path); wl->data_path = NULL; @@ -589,17 +589,17 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl) return 0; } -static int wl1251_hw_init(struct wl12xx *wl) +static int wl1251_hw_init(struct wl1251 *wl) { struct wl1251_acx_mem_map *wl_mem_map; int ret; - ret = wl12xx_hw_init_hwenc_config(wl); + ret = wl1251_hw_init_hwenc_config(wl); if (ret < 0) return ret; /* Template settings */ - ret = wl12xx_hw_init_templates_config(wl); + ret = wl1251_hw_init_templates_config(wl); if (ret < 0) return ret; @@ -614,7 +614,7 @@ static int wl1251_hw_init(struct wl12xx *wl) goto out_free_memmap; /* RX config */ - ret = wl12xx_hw_init_rx_config(wl, + ret = wl1251_hw_init_rx_config(wl, RX_CFG_PROMISCUOUS | RX_CFG_TSF, RX_FILTER_OPTION_DEF); /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, @@ -628,42 +628,42 @@ static int wl1251_hw_init(struct wl12xx *wl) goto out_free_data_path; /* PHY layer config */ - ret = wl12xx_hw_init_phy_config(wl); + ret = wl1251_hw_init_phy_config(wl); if (ret < 0) goto out_free_data_path; /* Beacon filtering */ - ret = wl12xx_hw_init_beacon_filter(wl); + ret = wl1251_hw_init_beacon_filter(wl); if (ret < 0) goto out_free_data_path; /* Bluetooth WLAN coexistence */ - ret = wl12xx_hw_init_pta(wl); + ret = wl1251_hw_init_pta(wl); if (ret < 0) goto out_free_data_path; /* Energy detection */ - ret = wl12xx_hw_init_energy_detection(wl); + ret = wl1251_hw_init_energy_detection(wl); if (ret < 0) goto out_free_data_path; /* Beacons and boradcast settings */ - ret = wl12xx_hw_init_beacon_broadcast(wl); + ret = wl1251_hw_init_beacon_broadcast(wl); if (ret < 0) goto out_free_data_path; /* Enable data path */ - ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + ret = wl1251_cmd_data_path(wl, wl->channel, 1); if (ret < 0) goto out_free_data_path; /* Default power state */ - ret = wl12xx_hw_init_power_auth(wl); + ret = wl1251_hw_init_power_auth(wl); if (ret < 0) goto out_free_data_path; wl_mem_map = wl->target_mem_map; - wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", + wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", wl_mem_map->num_tx_mem_blocks, wl->data_path->tx_control_addr, wl_mem_map->num_rx_mem_blocks, @@ -680,7 +680,7 @@ static int wl1251_hw_init(struct wl12xx *wl) return ret; } -static int wl1251_plt_init(struct wl12xx *wl) +static int wl1251_plt_init(struct wl1251 *wl) { int ret; @@ -688,14 +688,14 @@ static int wl1251_plt_init(struct wl12xx *wl) if (ret < 0) return ret; - ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + ret = wl1251_cmd_data_path(wl, wl->channel, 1); if (ret < 0) return ret; return 0; } -void wl1251_setup(struct wl12xx *wl) +void wl1251_setup(struct wl1251 *wl) { /* FIXME: Is it better to use strncpy here or is this ok? */ wl->chip.fw_filename = WL1251_FW_NAME; diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h index c5c997b..68183c4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.h +++ b/drivers/net/wireless/wl12xx/wl1251_ops.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -34,7 +34,7 @@ #define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ -void wl1251_setup(struct wl12xx *wl); +void wl1251_setup(struct wl1251 *wl); struct wl1251_acx_memory { diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 83baaa2..68ff7f1 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -25,22 +25,22 @@ #include "wl1251_ps.h" #include "wl1251_spi.h" -#define WL12XX_WAKEUP_TIMEOUT 2000 +#define WL1251_WAKEUP_TIMEOUT 2000 /* Routines to toggle sleep mode while in ELP */ -void wl12xx_ps_elp_sleep(struct wl12xx *wl) +void wl1251_ps_elp_sleep(struct wl1251 *wl) { if (wl->elp || !wl->psm) return; - wl12xx_debug(DEBUG_PSM, "chip to elp"); + wl1251_debug(DEBUG_PSM, "chip to elp"); - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); wl->elp = true; } -int wl12xx_ps_elp_wakeup(struct wl12xx *wl) +int wl1251_ps_elp_wakeup(struct wl1251 *wl) { unsigned long timeout; u32 elp_reg; @@ -48,13 +48,13 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl) if (!wl->elp) return 0; - wl12xx_debug(DEBUG_PSM, "waking up chip from elp"); + wl1251_debug(DEBUG_PSM, "waking up chip from elp"); - timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT); + timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); /* * FIXME: we should wait for irq from chip but, as a temporary @@ -62,36 +62,36 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl) */ while (!(elp_reg & ELPCTRL_WLAN_READY)) { if (time_after(jiffies, timeout)) { - wl12xx_error("elp wakeup timeout"); + wl1251_error("elp wakeup timeout"); return -ETIMEDOUT; } msleep(1); - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); } - wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms", + wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", jiffies_to_msecs(jiffies) - - (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT)); + (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT)); wl->elp = false; return 0; } -static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) +static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable) { int ret; if (enable) { - wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp"); + wl1251_debug(DEBUG_PSM, "sleep auth psm/elp"); - ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_ELP); + ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); if (ret < 0) return ret; - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); } else { - wl12xx_debug(DEBUG_PSM, "sleep auth cam"); + wl1251_debug(DEBUG_PSM, "sleep auth cam"); /* * When the target is in ELP, we can only @@ -100,9 +100,9 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) * changing the power authorization. */ - wl12xx_ps_elp_wakeup(wl); + wl1251_ps_elp_wakeup(wl); - ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); + ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); if (ret < 0) return ret; } @@ -110,18 +110,18 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) return 0; } -int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode) +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) { int ret; switch (mode) { case STATION_POWER_SAVE_MODE: - wl12xx_debug(DEBUG_PSM, "entering psm"); - ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + wl1251_debug(DEBUG_PSM, "entering psm"); + ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); if (ret < 0) return ret; - ret = wl12xx_ps_set_elp(wl, true); + ret = wl1251_ps_set_elp(wl, true); if (ret < 0) return ret; @@ -129,12 +129,12 @@ int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode) break; case STATION_ACTIVE_MODE: default: - wl12xx_debug(DEBUG_PSM, "leaving psm"); - ret = wl12xx_ps_set_elp(wl, false); + wl1251_debug(DEBUG_PSM, "leaving psm"); + ret = wl1251_ps_set_elp(wl, false); if (ret < 0) return ret; - ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h index 8877842..db036fe 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.h +++ b/drivers/net/wireless/wl12xx/wl1251_ps.h @@ -1,8 +1,8 @@ -#ifndef __WL12XX_PS_H__ -#define __WL12XX_PS_H__ +#ifndef __WL1251_PS_H__ +#define __WL1251_PS_H__ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -28,9 +28,9 @@ #include "wl1251.h" #include "wl1251_acx.h" -int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode); -void wl12xx_ps_elp_sleep(struct wl12xx *wl); -int wl12xx_ps_elp_wakeup(struct wl12xx *wl); +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); +void wl1251_ps_elp_sleep(struct wl1251 *wl); +int wl1251_ps_elp_wakeup(struct wl1251 *wl); -#endif /* __WL12XX_PS_H__ */ +#endif /* __WL1251_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index 280fc18..48fa39e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -31,8 +31,8 @@ #include "wl1251_rx.h" #include "wl1251_acx.h" -static void wl12xx_rx_header(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc) +static void wl1251_rx_header(struct wl1251 *wl, + struct wl1251_rx_descriptor *desc) { u32 rx_packet_ring_addr; @@ -40,11 +40,11 @@ static void wl12xx_rx_header(struct wl12xx *wl, if (wl->rx_current_buffer) rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); + wl1251_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); } -static void wl12xx_rx_status(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc, +static void wl1251_rx_status(struct wl1251 *wl, + struct wl1251_rx_descriptor *desc, struct ieee80211_rx_status *status, u8 beacon) { @@ -65,14 +65,14 @@ static void wl12xx_rx_status(struct wl12xx *wl, * this one must be atomic, while our SPI routines can sleep. */ if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { - ret = wl12xx_acx_tsf_info(wl, &mactime); + ret = wl1251_acx_tsf_info(wl, &mactime); if (ret == 0) status->mactime = mactime; } status->signal = desc->rssi; - status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 / - (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI); + status->qual = (desc->rssi - WL1251_RX_MIN_RSSI) * 100 / + (WL1251_RX_MAX_RSSI - WL1251_RX_MIN_RSSI); status->qual = min(status->qual, 100); status->qual = max(status->qual, 0); @@ -103,8 +103,8 @@ static void wl12xx_rx_status(struct wl12xx *wl, /* FIXME: set status->rate_idx */ } -static void wl12xx_rx_body(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc) +static void wl1251_rx_body(struct wl1251 *wl, + struct wl1251_rx_descriptor *desc) { struct sk_buff *skb; struct ieee80211_rx_status status; @@ -112,12 +112,12 @@ static void wl12xx_rx_body(struct wl12xx *wl, u16 length, *fc; u32 curr_id, last_id_inc, rx_packet_ring_addr; - length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); + length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); if (last_id_inc != curr_id) { - wl12xx_warning("curr ID:%d, last ID inc:%d", + wl1251_warning("curr ID:%d, last ID inc:%d", curr_id, last_id_inc); wl->rx_last_id = curr_id; } else { @@ -125,18 +125,18 @@ static void wl12xx_rx_body(struct wl12xx *wl, } rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + - sizeof(struct wl12xx_rx_descriptor) + 20; + sizeof(struct wl1251_rx_descriptor) + 20; if (wl->rx_current_buffer) rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; skb = dev_alloc_skb(length); if (!skb) { - wl12xx_error("Couldn't allocate RX frame"); + wl1251_error("Couldn't allocate RX frame"); return; } rx_buffer = skb_put(skb, length); - wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); + wl1251_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); /* The actual lenght doesn't include the target's alignment */ skb->len = desc->length - PLCP_HEADER_LENGTH; @@ -146,15 +146,15 @@ static void wl12xx_rx_body(struct wl12xx *wl, if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) beacon = 1; - wl12xx_rx_status(wl, desc, &status, beacon); + wl1251_rx_status(wl, desc, &status, beacon); - wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, beacon ? "beacon" : ""); ieee80211_rx(wl->hw, skb, &status); } -static void wl12xx_rx_ack(struct wl12xx *wl) +static void wl1251_rx_ack(struct wl1251 *wl) { u32 data, addr; @@ -166,30 +166,30 @@ static void wl12xx_rx_ack(struct wl12xx *wl) data = INTR_TRIG_RX_PROC0; } - wl12xx_reg_write32(wl, addr, data); + wl1251_reg_write32(wl, addr, data); /* Toggle buffer ring */ wl->rx_current_buffer = !wl->rx_current_buffer; } -void wl12xx_rx(struct wl12xx *wl) +void wl1251_rx(struct wl1251 *wl) { - struct wl12xx_rx_descriptor *rx_desc; + struct wl1251_rx_descriptor *rx_desc; - if (wl->state != WL12XX_STATE_ON) + if (wl->state != WL1251_STATE_ON) return; rx_desc = wl->rx_descriptor; /* We first read the frame's header */ - wl12xx_rx_header(wl, rx_desc); + wl1251_rx_header(wl, rx_desc); /* Now we can read the body */ - wl12xx_rx_body(wl, rx_desc); + wl1251_rx_body(wl, rx_desc); /* Finally, we need to ACK the RX */ - wl12xx_rx_ack(wl); + wl1251_rx_ack(wl); return; } diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h index 4379c53..81156b9 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.h +++ b/drivers/net/wireless/wl12xx/wl1251_rx.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -22,8 +22,8 @@ * */ -#ifndef __WL12XX_RX_H__ -#define __WL12XX_RX_H__ +#ifndef __WL1251_RX_H__ +#define __WL1251_RX_H__ #include @@ -45,12 +45,12 @@ * 4) The target prepares the next RX packet. */ -#define WL12XX_RX_MAX_RSSI -30 -#define WL12XX_RX_MIN_RSSI -95 +#define WL1251_RX_MAX_RSSI -30 +#define WL1251_RX_MIN_RSSI -95 -#define WL12XX_RX_ALIGN_TO 4 -#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \ - ~(WL12XX_RX_ALIGN_TO - 1)) +#define WL1251_RX_ALIGN_TO 4 +#define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \ + ~(WL1251_RX_ALIGN_TO - 1)) #define SHORT_PREAMBLE_BIT BIT(0) #define OFDM_RATE_BIT BIT(6) @@ -74,7 +74,7 @@ #define RX_DESC_MIC_FAIL 0x2000 #define RX_DESC_DECRYPT_FAIL 0x4000 -struct wl12xx_rx_descriptor { +struct wl1251_rx_descriptor { u32 timestamp; /* In microseconds */ u16 length; /* Paylod length, including headers */ u16 flags; @@ -119,6 +119,6 @@ struct wl12xx_rx_descriptor { u8 snr; /* in dB */ } __attribute__ ((packed)); -void wl12xx_rx(struct wl12xx *wl); +void wl1251_rx(struct wl1251 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 5b4889e..c5da79d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -26,11 +26,10 @@ #include #include "wl1251.h" -#include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" -static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) +static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) { /* If the address is lower than REGISTERS_BASE, it means that this is * a chip-specific register address, so look it up in the registers @@ -38,7 +37,7 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) if (addr < REGISTERS_BASE) { /* Make sure we don't go over the table */ if (addr >= ACX_REG_TABLE_LEN) { - wl12xx_error("address out of range (%d)", addr); + wl1251_error("address out of range (%d)", addr); return -EINVAL; } addr = wl->chip.acx_reg_table[addr]; @@ -47,13 +46,13 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) return addr - wl->physical_reg_addr + wl->virtual_reg_addr; } -static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr) +static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) { return addr - wl->physical_mem_addr + wl->virtual_mem_addr; } -void wl12xx_spi_reset(struct wl12xx *wl) +void wl1251_spi_reset(struct wl1251 *wl) { u8 *cmd; struct spi_transfer t; @@ -61,7 +60,7 @@ void wl12xx_spi_reset(struct wl12xx *wl) cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); if (!cmd) { - wl12xx_error("could not allocate cmd for spi reset"); + wl1251_error("could not allocate cmd for spi reset"); return; } @@ -76,10 +75,10 @@ void wl12xx_spi_reset(struct wl12xx *wl) spi_sync(wl->spi, &m); - wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); + wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); } -void wl12xx_spi_init(struct wl12xx *wl) +void wl1251_spi_init(struct wl1251 *wl) { u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; struct spi_transfer t; @@ -87,7 +86,7 @@ void wl12xx_spi_init(struct wl12xx *wl) cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); if (!cmd) { - wl12xx_error("could not allocate cmd for spi init"); + wl1251_error("could not allocate cmd for spi init"); return; } @@ -130,7 +129,7 @@ void wl12xx_spi_init(struct wl12xx *wl) spi_sync(wl->spi, &m); - wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); + wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); } /* Set the SPI partitions to access the chip addresses @@ -166,18 +165,18 @@ void wl12xx_spi_init(struct wl12xx *wl) * | | * */ -int wl12xx_set_partition(struct wl12xx *wl, +int wl1251_set_partition(struct wl1251 *wl, u32 mem_start, u32 mem_size, u32 reg_start, u32 reg_size) { - struct wl12xx_partition *partition; + struct wl1251_partition *partition; struct spi_transfer t; struct spi_message m; size_t len, cmd_len; u32 *cmd; int addr; - cmd_len = sizeof(u32) + 2 * sizeof(struct wl12xx_partition); + cmd_len = sizeof(u32) + 2 * sizeof(struct wl1251_partition); cmd = kzalloc(cmd_len, GFP_KERNEL); if (!cmd) return -ENOMEM; @@ -185,28 +184,28 @@ int wl12xx_set_partition(struct wl12xx *wl, spi_message_init(&m); memset(&t, 0, sizeof(t)); - partition = (struct wl12xx_partition *) (cmd + 1); + partition = (struct wl1251_partition *) (cmd + 1); addr = HW_ACCESS_PART0_SIZE_ADDR; - len = 2 * sizeof(struct wl12xx_partition); + len = 2 * sizeof(struct wl1251_partition); *cmd |= WSPI_CMD_WRITE; *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); /* Make sure that the two partitions together don't exceed the * address range */ if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { - wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual" + wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" " address range. Truncating partition[0]."); mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); } @@ -214,23 +213,23 @@ int wl12xx_set_partition(struct wl12xx *wl, ((mem_start + mem_size) > reg_start)) { /* Guarantee that the memory partition doesn't overlap the * registers partition */ - wl12xx_debug(DEBUG_SPI, "End of partition[0] is " + wl1251_debug(DEBUG_SPI, "End of partition[0] is " "overlapping partition[1]. Adjusted."); mem_size = reg_start - mem_start; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); } else if ((reg_start < mem_start) && ((reg_start + reg_size) > mem_start)) { /* Guarantee that the register partition doesn't overlap the * memory partition */ - wl12xx_debug(DEBUG_SPI, "End of partition[1] is" + wl1251_debug(DEBUG_SPI, "End of partition[1] is" " overlapping partition[0]. Adjusted."); reg_size = mem_start - reg_start; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); } @@ -256,7 +255,7 @@ int wl12xx_set_partition(struct wl12xx *wl, return 0; } -void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed) { struct spi_transfer t[3]; @@ -284,7 +283,7 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, /* Busy and non busy words read */ t[1].rx_buf = busy_buf; - t[1].len = WL12XX_BUSY_WORD_LEN; + t[1].len = WL1251_BUSY_WORD_LEN; spi_message_add_tail(&t[1], &m); t[2].rx_buf = buf; @@ -295,11 +294,11 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, /* FIXME: check busy words */ - wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); - wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); + wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); + wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); } -void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed) { struct spi_transfer t[2]; @@ -329,66 +328,66 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, spi_sync(wl->spi, &m); - wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); - wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); + wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); + wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } -void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) { int physical; - physical = wl12xx_translate_mem_addr(wl, addr); + physical = wl1251_translate_mem_addr(wl, addr); - wl12xx_spi_read(wl, physical, buf, len, false); + wl1251_spi_read(wl, physical, buf, len, false); } -void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) { int physical; - physical = wl12xx_translate_mem_addr(wl, addr); + physical = wl1251_translate_mem_addr(wl, addr); - wl12xx_spi_write(wl, physical, buf, len, false); + wl1251_spi_write(wl, physical, buf, len, false); } -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, +void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed) { int physical; - physical = wl12xx_translate_reg_addr(wl, addr); + physical = wl1251_translate_reg_addr(wl, addr); - wl12xx_spi_read(wl, physical, buf, len, fixed); + wl1251_spi_read(wl, physical, buf, len, fixed); } -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, +void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed) { int physical; - physical = wl12xx_translate_reg_addr(wl, addr); + physical = wl1251_translate_reg_addr(wl, addr); - wl12xx_spi_write(wl, physical, buf, len, fixed); + wl1251_spi_write(wl, physical, buf, len, fixed); } -u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) +u32 wl1251_mem_read32(struct wl1251 *wl, int addr) { - return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr)); + return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); } -void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val) +void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) { - wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val); + wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); } -u32 wl12xx_reg_read32(struct wl12xx *wl, int addr) +u32 wl1251_reg_read32(struct wl1251 *wl, int addr) { - return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr)); + return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); } -void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val) +void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) { - wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val); + wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); } diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index 82b009c..6e8daf4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -22,8 +22,8 @@ * */ -#ifndef __WL12XX_SPI_H__ -#define __WL12XX_SPI_H__ +#ifndef __WL1251_SPI_H__ +#define __WL1251_SPI_H__ #include "wl1251_cmd.h" #include "wl1251_acx.h" @@ -66,50 +66,50 @@ #define WSPI_INIT_CMD_LEN 8 #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ - ((WL12XX_BUSY_WORD_LEN - 4) / sizeof(u32)) + ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 /* Raw target IO, address is not translated */ -void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed); -void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed); /* Memory target IO, address is tranlated to partition 0 */ -void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len); -void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len); -u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); -void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); +void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); +void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); +u32 wl1251_mem_read32(struct wl1251 *wl, int addr); +void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); /* Registers IO */ -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, +void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed); -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, +void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed); -u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); -void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); +u32 wl1251_reg_read32(struct wl1251 *wl, int addr); +void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); /* INIT and RESET words */ -void wl12xx_spi_reset(struct wl12xx *wl); -void wl12xx_spi_init(struct wl12xx *wl); -int wl12xx_set_partition(struct wl12xx *wl, +void wl1251_spi_reset(struct wl1251 *wl); +void wl1251_spi_init(struct wl1251 *wl); +int wl1251_set_partition(struct wl1251 *wl, u32 part_start, u32 part_size, u32 reg_start, u32 reg_size); -static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) +static inline u32 wl1251_read32(struct wl1251 *wl, int addr) { - wl12xx_spi_read(wl, addr, &wl->buffer_32, + wl1251_spi_read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32), false); return wl->buffer_32; } -static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) +static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) { wl->buffer_32 = val; - wl12xx_spi_write(wl, addr, &wl->buffer_32, + wl1251_spi_write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32), false); } -#endif /* __WL12XX_SPI_H__ */ +#endif /* __WL1251_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index 00c5649..2652a22 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -31,7 +31,7 @@ #include "wl1251_tx.h" #include "wl1251_ps.h" -static bool wl1251_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) +static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) { int used, data_in_count; @@ -52,13 +52,13 @@ static bool wl1251_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) return false; } -static int wl1251_tx_path_status(struct wl12xx *wl) +static int wl1251_tx_path_status(struct wl1251 *wl) { u32 status, addr, data_out_count; bool busy; addr = wl->data_path->tx_control_addr; - status = wl12xx_mem_read32(wl, addr); + status = wl1251_mem_read32(wl, addr); data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; busy = wl1251_tx_double_buffer_busy(wl, data_out_count); @@ -68,7 +68,7 @@ static int wl1251_tx_path_status(struct wl12xx *wl) return 0; } -static int wl1251_tx_id(struct wl12xx *wl, struct sk_buff *skb) +static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb) { int i; @@ -142,7 +142,7 @@ static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) tx_hdr->num_mem_blocks = mem_blocks; } -static int wl1251_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb, +static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb, struct ieee80211_tx_info *control) { struct tx_double_buffer_desc *tx_hdr; @@ -177,7 +177,7 @@ static int wl1251_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb, } /* We copy the packet to the target */ -static int wl1251_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, +static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, struct ieee80211_tx_info *control) { struct tx_double_buffer_desc *tx_hdr; @@ -211,7 +211,7 @@ static int wl1251_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, */ if (unlikely((long)skb->data & 0x03)) { int offset = (4 - (long)skb->data) & 0x03; - wl12xx_debug(DEBUG_TX, "skb offset %d", offset); + wl1251_debug(DEBUG_TX, "skb offset %d", offset); /* check whether the current skb can be used */ if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { @@ -221,7 +221,7 @@ static int wl1251_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, skb_reserve(skb, offset); memmove(skb->data, src, skb->len); } else { - wl12xx_info("No handler, fixme!"); + wl1251_info("No handler, fixme!"); return -EINVAL; } } @@ -235,15 +235,15 @@ static int wl1251_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, else addr = wl->data_path->tx_packet_ring_addr; - wl12xx_spi_mem_write(wl, addr, skb->data, len); + wl1251_spi_mem_write(wl, addr, skb->data, len); - wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", + wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); return 0; } -static void wl1251_tx_trigger(struct wl12xx *wl) +static void wl1251_tx_trigger(struct wl1251 *wl) { u32 data, addr; @@ -255,7 +255,7 @@ static void wl1251_tx_trigger(struct wl12xx *wl) data = INTR_TRIG_TX_PROC0; } - wl12xx_reg_write32(wl, addr, data); + wl1251_reg_write32(wl, addr, data); /* Bumping data in */ wl->data_in_count = (wl->data_in_count + 1) & @@ -263,7 +263,7 @@ static void wl1251_tx_trigger(struct wl12xx *wl) } /* caller must hold wl->mutex */ -static int wl1251_tx_frame(struct wl12xx *wl, struct sk_buff *skb) +static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb) { struct ieee80211_tx_info *info; int ret = 0; @@ -274,7 +274,7 @@ static int wl1251_tx_frame(struct wl12xx *wl, struct sk_buff *skb) if (info->control.hw_key) { idx = info->control.hw_key->hw_key_idx; if (unlikely(wl->default_key != idx)) { - ret = wl12xx_acx_default_key(wl, idx); + ret = wl1251_acx_default_key(wl, idx); if (ret < 0) return ret; } @@ -299,19 +299,19 @@ static int wl1251_tx_frame(struct wl12xx *wl, struct sk_buff *skb) void wl1251_tx_work(struct work_struct *work) { - struct wl12xx *wl = container_of(work, struct wl12xx, tx_work); + struct wl1251 *wl = container_of(work, struct wl1251, tx_work); struct sk_buff *skb; bool woken_up = false; int ret; mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL12XX_STATE_OFF)) + if (unlikely(wl->state == WL1251_STATE_OFF)) goto out; while ((skb = skb_dequeue(&wl->tx_queue))) { if (!woken_up) { - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; woken_up = true; @@ -320,7 +320,7 @@ void wl1251_tx_work(struct work_struct *work) ret = wl1251_tx_frame(wl, skb); if (ret == -EBUSY) { /* firmware buffer is full, stop queues */ - wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, " + wl1251_debug(DEBUG_TX, "tx_work: fw buffer full, " "stop queues"); ieee80211_stop_queues(wl->hw); wl->tx_queue_stopped = true; @@ -334,7 +334,7 @@ void wl1251_tx_work(struct work_struct *work) out: if (woken_up) - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); } @@ -367,7 +367,7 @@ static const char *wl1251_tx_parse_status(u8 status) return buf; } -static void wl1251_tx_packet_cb(struct wl12xx *wl, +static void wl1251_tx_packet_cb(struct wl1251 *wl, struct tx_result *result) { struct ieee80211_tx_info *info; @@ -377,7 +377,7 @@ static void wl1251_tx_packet_cb(struct wl12xx *wl, skb = wl->tx_frames[result->id]; if (skb == NULL) { - wl12xx_error("SKB for packet %d is NULL", result->id); + wl1251_error("SKB for packet %d is NULL", result->id); return; } @@ -402,7 +402,7 @@ static void wl1251_tx_packet_cb(struct wl12xx *wl, skb_pull(skb, WL1251_TKIP_IV_SPACE); } - wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" + wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" " status 0x%x (%s)", result->id, skb, result->ack_failures, result->rate, result->status, wl1251_tx_parse_status(result->status)); @@ -413,7 +413,7 @@ static void wl1251_tx_packet_cb(struct wl12xx *wl, wl->tx_frames[result->id] = NULL; if (wl->tx_queue_stopped) { - wl12xx_debug(DEBUG_TX, "cb: queue was stopped"); + wl1251_debug(DEBUG_TX, "cb: queue was stopped"); skb = skb_dequeue(&wl->tx_queue); @@ -425,7 +425,7 @@ static void wl1251_tx_packet_cb(struct wl12xx *wl, ret = wl1251_tx_frame(wl, skb); if (ret == -EBUSY) { /* firmware buffer is still full */ - wl12xx_debug(DEBUG_TX, "cb: fw buffer " + wl1251_debug(DEBUG_TX, "cb: fw buffer " "still full"); skb_queue_head(&wl->tx_queue, skb); return; @@ -435,23 +435,23 @@ static void wl1251_tx_packet_cb(struct wl12xx *wl, } } - wl12xx_debug(DEBUG_TX, "cb: waking queues"); + wl1251_debug(DEBUG_TX, "cb: waking queues"); ieee80211_wake_queues(wl->hw); wl->tx_queue_stopped = false; } } /* Called upon reception of a TX complete interrupt */ -void wl1251_tx_complete(struct wl12xx *wl) +void wl1251_tx_complete(struct wl1251 *wl) { int i, result_index, num_complete = 0; struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; - if (unlikely(wl->state != WL12XX_STATE_ON)) + if (unlikely(wl->state != WL1251_STATE_ON)) return; /* First we read the result */ - wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr, + wl1251_spi_mem_read(wl, wl->data_path->tx_complete_addr, result, sizeof(result)); result_index = wl->next_tx_complete; @@ -482,7 +482,7 @@ void wl1251_tx_complete(struct wl12xx *wl) */ if (result_index > wl->next_tx_complete) { /* Only 1 write is needed */ - wl12xx_spi_mem_write(wl, + wl1251_spi_mem_write(wl, wl->data_path->tx_complete_addr + (wl->next_tx_complete * sizeof(struct tx_result)), @@ -493,7 +493,7 @@ void wl1251_tx_complete(struct wl12xx *wl) } else if (result_index < wl->next_tx_complete) { /* 2 writes are needed */ - wl12xx_spi_mem_write(wl, + wl1251_spi_mem_write(wl, wl->data_path->tx_complete_addr + (wl->next_tx_complete * sizeof(struct tx_result)), @@ -502,7 +502,7 @@ void wl1251_tx_complete(struct wl12xx *wl) wl->next_tx_complete) * sizeof(struct tx_result)); - wl12xx_spi_mem_write(wl, + wl1251_spi_mem_write(wl, wl->data_path->tx_complete_addr, result, (num_complete - @@ -512,7 +512,7 @@ void wl1251_tx_complete(struct wl12xx *wl) } else { /* We have to write the whole array */ - wl12xx_spi_mem_write(wl, + wl1251_spi_mem_write(wl, wl->data_path->tx_complete_addr, result, FW_TX_CMPLT_BLOCK_SIZE * @@ -525,7 +525,7 @@ void wl1251_tx_complete(struct wl12xx *wl) } /* caller must hold wl->mutex */ -void wl1251_tx_flush(struct wl12xx *wl) +void wl1251_tx_flush(struct wl1251 *wl) { int i; struct sk_buff *skb; @@ -537,7 +537,7 @@ void wl1251_tx_flush(struct wl12xx *wl) while ((skb = skb_dequeue(&wl->tx_queue))) { info = IEEE80211_SKB_CB(skb); - wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb); + wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb); if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) continue; diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h index a5d4c82..7c1c166 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.h +++ b/drivers/net/wireless/wl12xx/wl1251_tx.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -210,7 +210,7 @@ struct tx_result { } __attribute__ ((packed)); void wl1251_tx_work(struct work_struct *work); -void wl1251_tx_complete(struct wl12xx *wl); -void wl1251_tx_flush(struct wl12xx *wl); +void wl1251_tx_complete(struct wl1251 *wl); +void wl1251_tx_flush(struct wl1251 *wl); #endif -- cgit v0.10.2 From 05fac682c2ca0c572d1bd8e6a38025838ddf0e68 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:47 +0300 Subject: wl1251: fix a checkpatch warning drivers/net/wireless/wl12xx/wl1251_main.c:158: WARNING: braces {} are not necessary for single statement blocks Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index f4bc579..11e1903 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -155,9 +155,8 @@ static void wl1251_fw_wakeup(struct wl1251 *wl) wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - if (!(elp_reg & ELPCTRL_WLAN_READY)) { + if (!(elp_reg & ELPCTRL_WLAN_READY)) wl1251_warning("WLAN not ready"); - } } static int wl1251_chip_wakeup(struct wl1251 *wl) -- cgit v0.10.2 From 47af3fe36dc478f7eddc8bec104ff1876d71f37c Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:17:53 +0300 Subject: wl1251: change psm enabled/disabled info to debug With shorter CAM timeouts, the logs get flooded with "psm enabled" and "psm disabled traces. This patch changes it from wl1251_info to wl1251_debug, so they are only shown if DEBUF_PSM is enabled. Signed-off-by: Luciano Coelho Reviewed-by: Janne Ylalehto Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 11e1903..cf5e054 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -542,7 +542,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) goto out_sleep; if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl1251_info("psm enabled"); + wl1251_debug(DEBUG_PSM, "psm enabled"); wl->psm_requested = true; @@ -554,7 +554,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); } else if (!(conf->flags & IEEE80211_CONF_PS) && wl->psm_requested) { - wl1251_info("psm disabled"); + wl1251_debug(DEBUG_PSM, "psm disabled"); wl->psm_requested = false; -- cgit v0.10.2 From 9d67187dbd93df98011f7229f76de25d142b57cc Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 12 Jun 2009 13:22:53 -0700 Subject: iwlwifi: modify sensitivity value for 5150 In 5150 there is a long delay between the AGC(Automatic Gain Control) command till the RF is stabilized causing us to miss detections when there was adjacent channel noise, so we need to adjusted the Sensitivity calibration for 5150 differently. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b3c648c..0e445a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -407,6 +407,28 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = { .nrg_th_ofdm = 95, }; +static struct iwl_sensitivity_ranges iwl5150_sensitivity = { + .min_nrg_cck = 95, + .max_nrg_cck = 0, /* not used, set to 0 */ + .auto_corr_min_ofdm = 90, + .auto_corr_min_ofdm_mrc = 170, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 220, + + .auto_corr_max_ofdm = 120, + .auto_corr_max_ofdm_mrc = 210, + /* max = min for performance bug in 5150 DSP */ + .auto_corr_max_ofdm_x1 = 105, + .auto_corr_max_ofdm_mrc_x1 = 220, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 200, + .auto_corr_min_cck_mrc = 170, + .auto_corr_max_cck_mrc = 400, + .nrg_th_cck = 95, + .nrg_th_ofdm = 95, +}; + static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) { @@ -826,8 +848,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; - priv->hw_params.sens = &iwl5000_sensitivity; - priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; @@ -836,9 +856,11 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) if (priv->cfg->ops->lib->temp_ops.set_ct_kill) priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); + /* Set initial sensitivity parameters */ /* Set initial calibration set */ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_5150: + priv->hw_params.sens = &iwl5150_sensitivity; priv->hw_params.calib_init_cfg = BIT(IWL_CALIB_DC) | BIT(IWL_CALIB_LO) | @@ -847,6 +869,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) break; default: + priv->hw_params.sens = &iwl5000_sensitivity; priv->hw_params.calib_init_cfg = BIT(IWL_CALIB_XTAL) | BIT(IWL_CALIB_LO) | -- cgit v0.10.2 From fe6efb4b423c923fb491a9ca4fa419e843548740 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 12 Jun 2009 13:22:54 -0700 Subject: iwlwifi: no need to refer to max_nrg_cck range value max_nrg_cck value inside the sensitivity range structure is not needed for sensitivity calibration. Keep the parameter in sensitivity structure but set the value to "0" in case needed in the future implementation. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 8f3d4bc..edbb0bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -728,7 +728,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) static struct iwl_sensitivity_ranges iwl4965_sensitivity = { .min_nrg_cck = 97, - .max_nrg_cck = 0, + .max_nrg_cck = 0, /* not used, set to 0 */ .auto_corr_min_ofdm = 85, .auto_corr_min_ofdm_mrc = 170, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 0e445a9..85e8bac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -388,7 +388,7 @@ void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, static struct iwl_sensitivity_ranges iwl5000_sensitivity = { .min_nrg_cck = 95, - .max_nrg_cck = 0, + .max_nrg_cck = 0, /* not used, set to 0 */ .auto_corr_min_ofdm = 90, .auto_corr_min_ofdm_mrc = 170, .auto_corr_min_ofdm_x1 = 120, diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index a5d6367..f8bf592 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -251,12 +251,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv, /* increase energy threshold (reduce nrg value) * to decrease sensitivity */ - if (data->nrg_th_cck > - (ranges->max_nrg_cck + NRG_STEP_CCK)) - data->nrg_th_cck = data->nrg_th_cck - - NRG_STEP_CCK; - else - data->nrg_th_cck = ranges->max_nrg_cck; + data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK; /* Else if we got fewer than desired, increase sensitivity */ } else if (false_alarms < min_false_alarms) { data->nrg_curr_state = IWL_FA_TOO_FEW; -- cgit v0.10.2 From 030b865520c3e26f4a316852aa022a22c4948907 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 12 Jun 2009 13:22:55 -0700 Subject: iwlwifi: remove disable_tx_power for device > 4965 After 4965, tx_power_calibration moved from driver to uCode. remove "disable_tx_power" from debugfs to minimize the confusion. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 11e08c0..f32ac74 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -615,7 +615,10 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); - DEBUGFS_ADD_BOOL(disable_tx_power, rf, &priv->disable_tx_power_cal); + if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || + ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945)) + DEBUGFS_ADD_BOOL(disable_tx_power, rf, + &priv->disable_tx_power_cal); return 0; err: @@ -646,7 +649,9 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power); + if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || + ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945)) + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power); DEBUGFS_REMOVE(priv->dbgfs->dir_rf); DEBUGFS_REMOVE(priv->dbgfs->dir_drv); kfree(priv->dbgfs); -- cgit v0.10.2 From 0c5553b1392dea5ba5ad678790367c1275ed1172 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 15 Jun 2009 21:59:50 +0200 Subject: iwmc3200wifi: invalidate keys when changing the BSSID While associated, we have to invalidate our key cache if we clear our BSSID through siwap. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 584c94d..8891949 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -82,6 +82,7 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { struct iwm_priv *iwm = ndev_to_iwm(dev); + int ret; if (iwm->conf.mode == UMAC_MODE_IBSS) return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); @@ -104,10 +105,26 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, } if (iwm->umac_profile_active) { + int i; + if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN)) return 0; - iwm_invalidate_mlme_profile(iwm); + /* + * If we're clearing the BSSID, and we're associated, + * we have to clear the keys as they're no longer valid. + */ + if (is_zero_ether_addr(ap_addr->sa_data)) { + for (i = 0; i < IWM_NUM_KEYS; i++) + iwm->keys[i].in_use = 0; + + } + + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } } if (iwm->umac_profile->ssid.ssid_len) -- cgit v0.10.2 From a70742f167424bab794ca74b9e99b598b358bb7d Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 15 Jun 2009 21:59:51 +0200 Subject: iwmc3200wifi: handling wifi_if_ntfy responses When we're calling iwm_send_wifi_if_cmd() with the resp flag set, we're currently waiting on the mlme queue, waiting for some flags here and there to show up. This patch adds a wifi_ntfy bitmap, and when we're sending a wifi_if command expecting an answers, we wait synchronously for it to show up, on a dedicated queue. The wifi_ntfy bit is set when we receive the corresponding answer. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 834a7f5..337a884 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -70,14 +70,28 @@ static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm, int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, bool resp) { + struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload; struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; struct iwm_umac_cmd umac_cmd; + int ret; + u8 oid = hdr->oid; umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; umac_cmd.resp = resp; - return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, - payload, payload_size); + ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, + payload, payload_size); + + if (resp) { + ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue, + test_and_clear_bit(oid, &iwm->wifi_ntfy[0]), + 3 * HZ); + + if (!ret) + ret = -EBUSY; + } + + return ret; } static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = @@ -746,14 +760,6 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) return ret; } - /* Wait for the profile to be active */ - ret = wait_event_interruptible_timeout(iwm->mlme_queue, - iwm->umac_profile_active == 1, - 3 * HZ); - if (!ret) - return -EBUSY; - - for (i = 0; i < IWM_NUM_KEYS; i++) if (iwm->keys[i].in_use) { int default_key = 0; @@ -778,8 +784,8 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) { - int ret; struct iwm_umac_invalidate_profile invalid; + int ret; invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE; invalid.hdr.buf_size = @@ -793,8 +799,7 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) return ret; ret = wait_event_interruptible_timeout(iwm->mlme_queue, - (iwm->umac_profile_active == 0), - 2 * HZ); + (iwm->umac_profile_active == 0), 2 * HZ); if (!ret) return -EBUSY; diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 77c339f..d8d4ae2 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -278,6 +278,9 @@ struct iwm_priv { struct iwm_key keys[IWM_NUM_KEYS]; struct iwm_key *default_key; + DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX); + wait_queue_head_t wifi_ntfy_queue; + wait_queue_head_t mlme_queue; struct iw_statistics wstats; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 8be206d..8448722 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -191,6 +191,7 @@ int iwm_priv_init(struct iwm_priv *iwm) INIT_LIST_HEAD(&iwm->pending_notif); init_waitqueue_head(&iwm->notif_queue); init_waitqueue_head(&iwm->nonwifi_queue); + init_waitqueue_head(&iwm->wifi_ntfy_queue); init_waitqueue_head(&iwm->mlme_queue); memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf)); spin_lock_init(&iwm->tx_credit.lock); diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index d73cf96..49a8be7 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -993,12 +993,17 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, (struct iwm_umac_wifi_if *)cmd->buf.payload; IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " - "oid is %d\n", hdr->oid); + "oid is 0x%x\n", hdr->oid); + + if (hdr->oid <= WIFI_IF_NTFY_MAX) { + set_bit(hdr->oid, &iwm->wifi_ntfy[0]); + wake_up_interruptible(&iwm->wifi_ntfy_queue); + } else + return -EINVAL; switch (hdr->oid) { case UMAC_WIFI_IF_CMD_SET_PROFILE: iwm->umac_profile_active = 1; - wake_up_interruptible(&iwm->mlme_queue); break; default: break; diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h index 4a95cce..0af2a3c 100644 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -495,6 +495,8 @@ struct iwm_fw_alive_hdr { #define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8 #define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9 +#define WIFI_IF_NTFY_MAX 0xff + /* Notification structures */ struct iwm_umac_notif_wifi_if { struct iwm_umac_wifi_in_hdr hdr; -- cgit v0.10.2 From 13e0fe70960e95cdea89b71aa3d046ec71efac8c Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 15 Jun 2009 21:59:52 +0200 Subject: iwmc3200wifi: cfg80211 key hooks implemetation This patch implements the new cfg80211 privacy related hooks: add/get/set_key and the set_default_key one. With this implementation we can now call the wext-compat *encode* routines and reduce our own wext code. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index bc89b1e..739bd9b 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -130,6 +131,173 @@ static struct ieee80211_supported_band iwm_band_5ghz = { .n_bitrates = iwm_a_rates_size, }; +static int iwm_key_init(struct iwm_key *key, u8 key_index, + const u8 *mac_addr, struct key_params *params) +{ + key->hdr.key_idx = key_index; + if (!mac_addr || is_broadcast_ether_addr(mac_addr)) { + key->hdr.multicast = 1; + memset(key->hdr.mac, 0xff, ETH_ALEN); + } else { + key->hdr.multicast = 0; + memcpy(key->hdr.mac, mac_addr, ETH_ALEN); + } + + if (params) { + if (params->key_len > WLAN_MAX_KEY_LEN || + params->seq_len > IW_ENCODE_SEQ_MAX_SIZE) + return -EINVAL; + + key->cipher = params->cipher; + key->key_len = params->key_len; + key->seq_len = params->seq_len; + memcpy(key->key, params->key, key->key_len); + memcpy(key->seq, params->seq, key->seq_len); + } + + return 0; +} + +static int iwm_reset_profile(struct iwm_priv *iwm) +{ + int ret; + + if (!iwm->umac_profile_active) + return 0; + + /* + * If there is a current active profile, but no + * default key, it's not worth trying to associate again. + */ + if (iwm->default_key < 0) + return 0; + + /* + * Here we have an active profile, but a key setting changed. + * We thus have to invalidate the current profile, and push the + * new one. Keys will be pushed when association takes place. + */ + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, const u8 *mac_addr, + struct key_params *params) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + struct iwm_key *key = &iwm->keys[key_index]; + int ret; + + IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr); + + memset(key, 0, sizeof(struct iwm_key)); + ret = iwm_key_init(key, key_index, mac_addr, params); + if (ret < 0) { + IWM_ERR(iwm, "Invalid key_params\n"); + return ret; + } + + /* + * The WEP keys can be set before or after setting the essid. + * We need to handle both cases by simply pushing the keys after + * we send the profile. + * If the profile is not set yet (i.e. we're pushing keys before + * the essid), we set the cipher appropriately. + * If the profile is set, we havent associated yet because our + * cipher was incorrectly set. So we invalidate and send the + * profile again. + */ + if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || + key->cipher == WLAN_CIPHER_SUITE_WEP104) { + u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher; + u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher; + + IWM_DBG_WEXT(iwm, DBG, "WEP key\n"); + + if (key->cipher == WLAN_CIPHER_SUITE_WEP40) + *ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40; + if (key->cipher == WLAN_CIPHER_SUITE_WEP104) + *ucast_cipher = *mcast_cipher = + UMAC_CIPHER_TYPE_WEP_104; + + return iwm_reset_profile(iwm); + } + + return iwm_set_key(iwm, 0, key); +} + +static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params*)) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + struct iwm_key *key = &iwm->keys[key_index]; + struct key_params params; + + IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index); + + memset(¶ms, 0, sizeof(params)); + + params.cipher = key->cipher; + params.key_len = key->key_len; + params.seq_len = key->seq_len; + params.seq = key->seq; + params.key = key->key; + + callback(cookie, ¶ms); + + return key->key_len ? 0 : -ENOENT; +} + + +static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, const u8 *mac_addr) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + struct iwm_key *key = &iwm->keys[key_index]; + + if (!iwm->keys[key_index].key_len) { + IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index); + return 0; + } + + if (key_index == iwm->default_key) + iwm->default_key = -1; + + return iwm_set_key(iwm, 1, key); +} + +static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + int ret; + + IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index); + + if (!iwm->keys[key_index].key_len) { + IWM_ERR(iwm, "Key %d not used\n", key_index); + return -EINVAL; + } + + ret = iwm_set_tx_key(iwm, key_index); + if (ret < 0) + return ret; + + iwm->default_key = key_index; + + return iwm_reset_profile(iwm); +} + + int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) { struct wiphy *wiphy = iwm_to_wiphy(iwm); @@ -326,6 +494,10 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) static struct cfg80211_ops iwm_cfg80211_ops = { .change_virtual_intf = iwm_cfg80211_change_iface, + .add_key = iwm_cfg80211_add_key, + .get_key = iwm_cfg80211_get_key, + .del_key = iwm_cfg80211_del_key, + .set_default_key = iwm_cfg80211_set_default_key, .scan = iwm_cfg80211_scan, .set_wiphy_params = iwm_cfg80211_set_wiphy_params, .join_ibss = iwm_cfg80211_join_ibss, diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 337a884..145f6f5 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -524,9 +524,6 @@ int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) { struct iwm_umac_tx_key_id tx_key_id; - if (!iwm->default_key || !iwm->default_key->in_use) - return -EINVAL; - tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - sizeof(struct iwm_umac_wifi_if)); @@ -569,10 +566,9 @@ static int iwm_check_profile(struct iwm_priv *iwm) return 0; } -int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, - struct iwm_key *key) +int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) { - int ret; + int ret = 0; u8 cmd[64], *sta_addr, *key_data, key_len; s8 key_idx; u16 cmd_size = 0; @@ -582,9 +578,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; - if (set_tx_key) - iwm->default_key = key; - /* * We check if our current profile is valid. * If not, we dont push the key, we just cache them, @@ -603,8 +596,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, key_idx = key->hdr.key_idx; if (!remove) { - IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n", - key_idx, set_tx_key); + IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx); IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); @@ -616,8 +608,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, iwm->umac_profile->sec.auth_type, iwm->umac_profile->sec.flags); - switch (key->alg) { - case UMAC_CIPHER_TYPE_WEP_40: + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; wep40->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - @@ -631,7 +623,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, cmd_size = sizeof(struct iwm_umac_key_wep40); break; - case UMAC_CIPHER_TYPE_WEP_104: + case WLAN_CIPHER_SUITE_WEP104: wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; wep104->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - @@ -645,7 +637,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, cmd_size = sizeof(struct iwm_umac_key_wep104); break; - case UMAC_CIPHER_TYPE_CCMP: + case WLAN_CIPHER_SUITE_CCMP: key_hdr->key_idx++; ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; ccmp->hdr.buf_size = @@ -657,13 +649,13 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, memcpy(ccmp->key, key_data, key_len); - if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) - memcpy(ccmp->iv_count, key->rx_seq, 6); + if (key->seq_len) + memcpy(ccmp->iv_count, key->seq, key->seq_len); cmd_size = sizeof(struct iwm_umac_key_ccmp); break; - case UMAC_CIPHER_TYPE_TKIP: + case WLAN_CIPHER_SUITE_TKIP: key_hdr->key_idx++; tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; tkip->hdr.buf_size = @@ -680,8 +672,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, IWM_TKIP_MIC_SIZE); - if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) - memcpy(ccmp->iv_count, key->rx_seq, 6); + if (key->seq_len) + memcpy(ccmp->iv_count, key->seq, key->seq_len); cmd_size = sizeof(struct iwm_umac_key_tkip); break; @@ -690,8 +682,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, return -ENOTSUPP; } - if ((key->alg == UMAC_CIPHER_TYPE_CCMP) || - (key->alg == UMAC_CIPHER_TYPE_TKIP)) + if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) || + (key->cipher == WLAN_CIPHER_SUITE_CCMP)) /* * UGLY_UGLY_UGLY * Copied HACK from the MWG driver. @@ -702,23 +694,11 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, schedule_timeout_interruptible(usecs_to_jiffies(300)); ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); - if (ret < 0) - goto err; - - /* - * We need a default key only if it is set and - * if we're doing WEP. - */ - if (iwm->default_key == key && - ((key->alg == UMAC_CIPHER_TYPE_WEP_40) || - (key->alg == UMAC_CIPHER_TYPE_WEP_104))) { - ret = iwm_set_tx_key(iwm, key_idx); - if (ret < 0) - goto err; - } } else { struct iwm_umac_key_remove key_remove; + IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx); + key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; key_remove.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_remove) - @@ -732,13 +712,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, if (ret < 0) return ret; - iwm->keys[key_idx].in_use = 0; + iwm->keys[key_idx].key_len = 0; } - return 0; - - err: - kfree(key); return ret; } @@ -761,22 +737,24 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) } for (i = 0; i < IWM_NUM_KEYS; i++) - if (iwm->keys[i].in_use) { - int default_key = 0; + if (iwm->keys[i].key_len) { struct iwm_key *key = &iwm->keys[i]; - if (key == iwm->default_key) - default_key = 1; - /* Wait for the profile before sending the keys */ wait_event_interruptible_timeout(iwm->mlme_queue, (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) || test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)), 3 * HZ); - ret = iwm_set_key(iwm, 0, default_key, key); + ret = iwm_set_key(iwm, 0, key); if (ret < 0) return ret; + + if (iwm->default_key == i) { + ret = iwm_set_tx_key(iwm, i); + if (ret < 0) + return ret; + } } return 0; diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index 36b13a1..3510df8 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -406,8 +406,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm); int iwm_invalidate_mlme_profile(struct iwm_priv *iwm); int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); -int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, - struct iwm_key *key); +int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key); int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); int iwm_send_umac_channel_list(struct iwm_priv *iwm); int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index d8d4ae2..90b05d9 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -162,13 +162,11 @@ struct iwm_umac_key_hdr { struct iwm_key { struct iwm_umac_key_hdr hdr; - u8 in_use; - u8 alg; - u32 flags; - u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; - u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; - u8 key_len; - u8 key[32]; + u32 cipher; + u8 key[WLAN_MAX_KEY_LEN]; + u8 seq[IW_ENCODE_SEQ_MAX_SIZE]; + int key_len; + int seq_len; }; #define IWM_RX_ID_HASH 0xff @@ -276,7 +274,7 @@ struct iwm_priv { struct iwm_tx_queue txq[IWM_TX_QUEUES]; struct iwm_key keys[IWM_NUM_KEYS]; - struct iwm_key *default_key; + s8 default_key; DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX); wait_queue_head_t wifi_ntfy_queue; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 8448722..7f56c06 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -230,7 +230,7 @@ int iwm_priv_init(struct iwm_priv *iwm) for (i = 0; i < IWM_NUM_KEYS; i++) memset(&iwm->keys[i], 0, sizeof(struct iwm_key)); - iwm->default_key = NULL; + iwm->default_key = -1; init_timer(&iwm->watchdog); iwm->watchdog.function = iwm_watchdog; @@ -709,7 +709,7 @@ int __iwm_down(struct iwm_priv *iwm) iwm->umac_profile = NULL; iwm_bss_list_clean(iwm); - iwm->default_key = NULL; + iwm->default_key = -1; iwm->core_enabled = 0; ret = iwm_bus_disable(iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 8891949..3062f37 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -84,6 +84,8 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, struct iwm_priv *iwm = ndev_to_iwm(dev); int ret; + IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data); + if (iwm->conf.mode == UMAC_MODE_IBSS) return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); @@ -116,8 +118,7 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, */ if (is_zero_ether_addr(ap_addr->sa_data)) { for (i = 0; i < IWM_NUM_KEYS; i++) - iwm->keys[i].in_use = 0; - + iwm->keys[i].key_len = 0; } ret = iwm_invalidate_mlme_profile(iwm); @@ -163,6 +164,8 @@ static int iwm_wext_siwessid(struct net_device *dev, size_t len = data->length; int ret; + IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid); + if (iwm->conf.mode == UMAC_MODE_IBSS) return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); @@ -212,27 +215,6 @@ static int iwm_wext_giwessid(struct net_device *dev, return 0; } -static struct iwm_key * -iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use, - struct iw_encode_ext *ext, u8 alg) -{ - struct iwm_key *key = &iwm->keys[key_idx]; - - memset(key, 0, sizeof(struct iwm_key)); - memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN); - key->hdr.key_idx = key_idx; - if (is_broadcast_ether_addr(ext->addr.sa_data)) - key->hdr.multicast = 1; - - key->in_use = in_use; - key->flags = ext->ext_flags; - key->alg = alg; - key->key_len = ext->key_len; - memcpy(key->key, ext->key, ext->key_len); - - return key; -} - static int iwm_wext_giwrate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rate, char *extra) @@ -244,184 +226,6 @@ static int iwm_wext_giwrate(struct net_device *dev, return 0; } -static int iwm_wext_siwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key_buf) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - struct iwm_key *uninitialized_var(key); - int idx, i, uninitialized_var(alg), remove = 0, ret; - - IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length); - IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); - - if (!iwm->umac_profile) { - IWM_ERR(iwm, "UMAC profile not allocated yet\n"); - return -ENODEV; - } - - if (erq->length == WLAN_KEY_LEN_WEP40) { - alg = UMAC_CIPHER_TYPE_WEP_40; - iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40; - iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40; - } else if (erq->length == WLAN_KEY_LEN_WEP104) { - alg = UMAC_CIPHER_TYPE_WEP_104; - iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104; - iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104; - } - - if (erq->flags & IW_ENCODE_RESTRICTED) - iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - else - iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx == 0) { - if (iwm->default_key) - for (i = 0; i < IWM_NUM_KEYS; i++) { - if (iwm->default_key == &iwm->keys[i]) { - idx = i; - break; - } - } - else - iwm->default_key = &iwm->keys[idx]; - } else if (idx < 1 || idx > 4) { - return -EINVAL; - } else - idx--; - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - else if (erq->length == 0) { - if (!iwm->keys[idx].in_use) - return -EINVAL; - iwm->default_key = &iwm->keys[idx]; - } - - if (erq->length) { - key = &iwm->keys[idx]; - memset(key, 0, sizeof(struct iwm_key)); - memset(key->hdr.mac, 0xff, ETH_ALEN); - key->hdr.key_idx = idx; - key->hdr.multicast = 1; - key->in_use = !remove; - key->alg = alg; - key->key_len = erq->length; - memcpy(key->key, key_buf, erq->length); - - IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n", - idx, !!iwm->default_key); - } - - if (remove) { - if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) { - int j; - for (j = 0; j < IWM_NUM_KEYS; j++) - if (iwm->keys[j].in_use) { - struct iwm_key *k = &iwm->keys[j]; - - k->in_use = 0; - ret = iwm_set_key(iwm, remove, 0, k); - if (ret < 0) - return ret; - } - - iwm->umac_profile->sec.ucast_cipher = - UMAC_CIPHER_TYPE_NONE; - iwm->umac_profile->sec.mcast_cipher = - UMAC_CIPHER_TYPE_NONE; - iwm->umac_profile->sec.auth_type = - UMAC_AUTH_TYPE_OPEN; - - return 0; - } else { - key->in_use = 0; - return iwm_set_key(iwm, remove, 0, key); - } - } - - /* - * If we havent set a profile yet, we cant set keys. - * Keys will be pushed after we're associated. - */ - if (!iwm->umac_profile_active) - return 0; - - /* - * If there is a current active profile, but no - * default key, it's not worth trying to associate again. - */ - if (!iwm->default_key) - return 0; - - /* - * Here we have an active profile, but a key setting changed. - * We thus have to invalidate the current profile, and push the - * new one. Keys will be pushed when association takes place. - */ - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } - - return iwm_send_mlme_profile(iwm); -} - -static int iwm_wext_giwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - int idx, i; - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx < 1 || idx > 4) { - idx = -1; - if (!iwm->default_key) { - erq->length = 0; - erq->flags |= IW_ENCODE_NOKEY; - return 0; - } else - for (i = 0; i < IWM_NUM_KEYS; i++) { - if (iwm->default_key == &iwm->keys[i]) { - idx = i; - break; - } - } - if (idx < 0) - return -EINVAL; - } else - idx--; - - erq->flags = idx + 1; - - if (!iwm->keys[idx].in_use) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - - memcpy(key, iwm->keys[idx].key, - min_t(int, erq->length, iwm->keys[idx].key_len)); - erq->length = iwm->keys[idx].key_len; - erq->flags |= IW_ENCODE_ENABLED; - - if (iwm->umac_profile->mode == UMAC_MODE_BSS) { - switch (iwm->umac_profile->sec.auth_type) { - case UMAC_AUTH_TYPE_OPEN: - erq->flags |= IW_ENCODE_OPEN; - break; - default: - erq->flags |= IW_ENCODE_RESTRICTED; - break; - } - } - - return 0; -} - static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) { if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) @@ -481,6 +285,8 @@ static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt) { u8 *auth_type = &iwm->umac_profile->sec.auth_type; + IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt); + if (key_mgt == IW_AUTH_KEY_MGMT_802_1X) *auth_type = UMAC_AUTH_TYPE_8021X; else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) { @@ -530,6 +336,8 @@ static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg) { u8 *auth_type = &iwm->umac_profile->sec.auth_type; + IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg); + switch (auth_alg) { case IW_AUTH_ALG_OPEN_SYSTEM: *auth_type = UMAC_AUTH_TYPE_OPEN; @@ -541,6 +349,7 @@ static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg) return -EINVAL; *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; } else { + IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n"); *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; } break; @@ -603,75 +412,6 @@ static int iwm_wext_giwauth(struct net_device *dev, return 0; } -static int iwm_wext_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - struct iwm_key *key; - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int uninitialized_var(alg), idx, i, remove = 0; - - IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg); - IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len); - IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags); - IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); - IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length); - - switch (ext->alg) { - case IW_ENCODE_ALG_NONE: - remove = 1; - break; - case IW_ENCODE_ALG_WEP: - if (ext->key_len == WLAN_KEY_LEN_WEP40) - alg = UMAC_CIPHER_TYPE_WEP_40; - else if (ext->key_len == WLAN_KEY_LEN_WEP104) - alg = UMAC_CIPHER_TYPE_WEP_104; - else { - IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len); - return -EINVAL; - } - - break; - case IW_ENCODE_ALG_TKIP: - alg = UMAC_CIPHER_TYPE_TKIP; - break; - case IW_ENCODE_ALG_CCMP: - alg = UMAC_CIPHER_TYPE_CCMP; - break; - default: - return -EOPNOTSUPP; - } - - idx = erq->flags & IW_ENCODE_INDEX; - - if (idx == 0) { - if (iwm->default_key) - for (i = 0; i < IWM_NUM_KEYS; i++) { - if (iwm->default_key == &iwm->keys[i]) { - idx = i; - break; - } - } - } else if (idx < 1 || idx > 4) { - return -EINVAL; - } else - idx--; - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - else if ((erq->length == 0) || - (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) { - iwm->default_key = &iwm->keys[idx]; - if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP) - return iwm_set_tx_key(iwm, idx); - } - - key = iwm_key_init(iwm, idx, !remove, ext, alg); - - return iwm_set_key(iwm, remove, !iwm->default_key, key); -} - static const iw_handler iwm_handlers[] = { (iw_handler) NULL, /* SIOCSIWCOMMIT */ @@ -716,8 +456,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* SIOCGIWTXPOW */ (iw_handler) NULL, /* SIOCSIWRETRY */ (iw_handler) NULL, /* SIOCGIWRETRY */ - (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */ - (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */ + (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ + (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */ (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ @@ -726,7 +466,7 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* SIOCGIWGENIE */ (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */ (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */ - (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ (iw_handler) NULL, /* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ (iw_handler) NULL, /* -- hole -- */ -- cgit v0.10.2 From 191506ecbce03f09f6afa76f1af069574bf99bec Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 15 Jun 2009 21:59:53 +0200 Subject: iwmc3200wifi: change coexist periodic calibration flag The patch changes coexist periodic calibration priority flag. It also set wireless mode to UMAC and set PM control flag to 0x1. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 145f6f5..0d35afe 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -120,7 +120,7 @@ static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, {5, 5, 0, COEX_CALIBRATION_FLAGS}, - {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, + {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS}, {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, @@ -345,8 +345,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, return ret; } -int iwm_send_umac_config(struct iwm_priv *iwm, - __le32 reset_flags) +int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags) { int ret; @@ -374,6 +373,12 @@ int iwm_send_umac_config(struct iwm_priv *iwm, return ret; ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_WIRELESS_MODE, + iwm->conf.wireless_mode); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, CFG_COEX_MODE, iwm->conf.coexist_mode); if (ret < 0) return ret; @@ -415,7 +420,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm, return ret; ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_PM_CTRL_FLAGS, 0x30001); + CFG_PM_CTRL_FLAGS, 0x1); if (ret < 0) return ret; diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index 3510df8..e24d5b6 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -106,8 +106,7 @@ enum { CFG_TLC_SPATIAL_STREAM_SUPPORTED, CFG_TLC_RETRY_PER_RATE, CFG_TLC_RETRY_PER_HT_RATE, - CFG_TLC_FIXED_RATE, - CFG_TLC_FIXED_RATE_FLAGS, + CFG_TLC_FIXED_MCS, CFG_TLC_CONTROL_FLAGS, CFG_TLC_SR_MIN_FAIL, CFG_TLC_SR_MIN_PASS, @@ -232,6 +231,7 @@ struct iwm_umac_cmd_get_channel_list { /* Wireless mode */ #define WIRELESS_MODE_11A 0x1 #define WIRELESS_MODE_11G 0x2 +#define WIRELESS_MODE_11N 0x4 #define UMAC_PROFILE_EX_IE_REQUIRED 0x1 #define UMAC_PROFILE_QOS_ALLOWED 0x2 -- cgit v0.10.2 From 3549716484a95fd16f7fcf8b68699bd4c803b382 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 15 Jun 2009 21:59:54 +0200 Subject: iwmc3200wifi: cache keys when interface is down When the interface is down and one sets a WEP key from userspace, we should be able to simply cache it. Since that implies setting part of the profile's security settings, we now alloc/free the umac_profile at probe/remove time, and no longer at interface bring up/down time. Simply resetting it during the latter is enough. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 739bd9b..0cdd7ef 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -271,6 +271,10 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, if (key_index == iwm->default_key) iwm->default_key = -1; + /* If the interface is down, we just cache this */ + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return 0; + return iwm_set_key(iwm, 1, key); } @@ -288,12 +292,16 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, return -EINVAL; } + iwm->default_key = key_index; + + /* If the interface is down, we just cache this */ + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return 0; + ret = iwm_set_tx_key(iwm, key_index); if (ret < 0) return ret; - iwm->default_key = key_index; - return iwm_reset_profile(iwm); } diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 7f56c06..930056b 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -643,19 +643,10 @@ int __iwm_up(struct iwm_priv *iwm) } } - iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), - GFP_KERNEL); - if (!iwm->umac_profile) { - IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); - goto err_fw; - } - - iwm_init_default_profile(iwm, iwm->umac_profile); - ret = iwm_channels_init(iwm); if (ret < 0) { IWM_ERR(iwm, "Couldn't init channels\n"); - goto err_profile; + goto err_fw; } /* Set the READY bit to indicate interface is brought up successfully */ @@ -663,10 +654,6 @@ int __iwm_up(struct iwm_priv *iwm) return 0; - err_profile: - kfree(iwm->umac_profile); - iwm->umac_profile = NULL; - err_fw: iwm_eeprom_exit(iwm); @@ -705,10 +692,9 @@ int __iwm_down(struct iwm_priv *iwm) clear_bit(IWM_STATUS_READY, &iwm->status); iwm_eeprom_exit(iwm); - kfree(iwm->umac_profile); - iwm->umac_profile = NULL; iwm_bss_list_clean(iwm); - + iwm_init_default_profile(iwm, iwm->umac_profile); + iwm->umac_profile_active = false; iwm->default_key = -1; iwm->core_enabled = 0; diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index aaa20c6..d4deb4b 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -48,6 +48,7 @@ #include #include "iwm.h" +#include "commands.h" #include "cfg80211.h" #include "debug.h" @@ -135,8 +136,20 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev, SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; + iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), + GFP_KERNEL); + if (!iwm->umac_profile) { + dev_err(dev, "Couldn't alloc memory for profile\n"); + goto out_profile; + } + + iwm_init_default_profile(iwm, iwm->umac_profile); + return iwm; + out_profile: + free_netdev(ndev); + out_priv: iwm_priv_deinit(iwm); @@ -153,6 +166,8 @@ void iwm_if_free(struct iwm_priv *iwm) free_netdev(iwm_to_ndev(iwm)); iwm_wdev_free(iwm); iwm_priv_deinit(iwm); + kfree(iwm->umac_profile); + iwm->umac_profile = NULL; } int iwm_if_add(struct iwm_priv *iwm) -- cgit v0.10.2 From 257862f3faef397f1a677ae6a5a1828fa00a97b1 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 15 Jun 2009 21:59:56 +0200 Subject: iwmc3200wifi: rfkill cleanup The patch cleans up the unused rfkill related structures and flags. It also adds wext and cfg80211 handlers for txpower auto and off so that software rfkill could be issued by user space. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 0cdd7ef..d0629d4 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -500,6 +500,28 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return 0; } +static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, + enum tx_power_setting type, int dbm) +{ + switch (type) { + case TX_POWER_AUTOMATIC: + return 0; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + *dbm = iwm->txpower; + + return 0; +} + static struct cfg80211_ops iwm_cfg80211_ops = { .change_virtual_intf = iwm_cfg80211_change_iface, .add_key = iwm_cfg80211_add_key, @@ -510,6 +532,8 @@ static struct cfg80211_ops iwm_cfg80211_ops = { .set_wiphy_params = iwm_cfg80211_set_wiphy_params, .join_ibss = iwm_cfg80211_join_ibss, .leave_ibss = iwm_cfg80211_leave_ibss, + .set_tx_power = iwm_cfg80211_set_txpower, + .get_tx_power = iwm_cfg80211_get_txpower, }; struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 90b05d9..4da57f7 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -184,10 +184,6 @@ struct iwm_key { #define IWM_STATUS_ASSOCIATING 3 #define IWM_STATUS_ASSOCIATED 4 -#define IWM_RADIO_RFKILL_OFF 0 -#define IWM_RADIO_RFKILL_HW 1 -#define IWM_RADIO_RFKILL_SW 2 - struct iwm_tx_queue { int id; struct sk_buff_head queue; @@ -221,7 +217,6 @@ struct iwm_priv { struct iwm_conf conf; unsigned long status; - unsigned long radio; struct list_head pending_notif; wait_queue_head_t notif_queue; @@ -240,6 +235,7 @@ struct iwm_priv { u8 bssid[ETH_ALEN]; u8 channel; u16 rate; + u32 txpower; struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM]; struct list_head bss_list; @@ -290,7 +286,6 @@ struct iwm_priv { struct timer_list watchdog; struct work_struct reset_worker; struct mutex mutex; - struct rfkill *rfkill; char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index d4deb4b..e94e969 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -55,23 +55,15 @@ static int iwm_open(struct net_device *ndev) { struct iwm_priv *iwm = ndev_to_iwm(ndev); - int ret = 0; - - if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) - ret = iwm_up(iwm); - return ret; + return iwm_up(iwm); } static int iwm_stop(struct net_device *ndev) { struct iwm_priv *iwm = ndev_to_iwm(ndev); - int ret = 0; - - if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) - ret = iwm_down(iwm); - return ret; + return iwm_down(iwm); } /* diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 49a8be7..55871da 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -143,17 +143,18 @@ static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) { + struct wiphy *wiphy = iwm_to_wiphy(iwm); struct iwm_umac_notif_init_complete *init_complete = (struct iwm_umac_notif_init_complete *)(buf); u16 status = le16_to_cpu(init_complete->status); + bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR); - if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) { + if (blocked) IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n"); - set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); - } else { + else IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n"); - clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); - } + + wiphy_rfkill_set_hw_state(wiphy, blocked); return 0; } @@ -875,6 +876,7 @@ static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf, /* UMAC passes rate info multiplies by 2 */ iwm->rate = max_rate >> 1; } + iwm->txpower = le32_to_cpu(stats->tx_power); wstats->status = 0; @@ -1015,6 +1017,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) { + struct wiphy *wiphy = iwm_to_wiphy(iwm); struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *) (buf + sizeof(struct iwm_umac_wifi_in_hdr)); u32 flags = le32_to_cpu(state->flags); @@ -1023,10 +1026,7 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); - if (flags & IWM_CARD_STATE_HW_DISABLED) - set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); - else - clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); + wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED); return 0; } diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index 9166818..b93f620 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -506,11 +506,7 @@ static struct sdio_driver iwm_sdio_driver = { static int __init iwm_sdio_init_module(void) { - int ret; - - ret = sdio_register_driver(&iwm_sdio_driver); - - return ret; + return sdio_register_driver(&iwm_sdio_driver); } static void __exit iwm_sdio_exit_module(void) diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 3062f37..9734573 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -452,8 +452,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) NULL, /* SIOCSIWTXPOW */ - (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ + (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ (iw_handler) NULL, /* SIOCSIWRETRY */ (iw_handler) NULL, /* SIOCGIWRETRY */ (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ -- cgit v0.10.2 From d75ec2b7ec27fd6cdba78492fbd63bee4d091a87 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 16 Jun 2009 17:17:21 +0300 Subject: rndis_wlan: convert get/set frag/rts to cfg80211 Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index e8b0793..edd4aad 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -428,9 +428,12 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request); +static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, + .set_wiphy_params = rndis_set_wiphy_params, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -969,6 +972,36 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) } +static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) +{ + __le32 tmp; + + devdbg(usbdev, "set_rts_threshold %i", rts_threshold); + + if (rts_threshold < 0 || rts_threshold > 2347) + rts_threshold = 2347; + + tmp = cpu_to_le32(rts_threshold); + return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, + sizeof(tmp)); +} + + +static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) +{ + __le32 tmp; + + devdbg(usbdev, "set_frag_threshold %i", frag_threshold); + + if (frag_threshold < 256 || frag_threshold > 2346) + frag_threshold = 2346; + + tmp = cpu_to_le32(frag_threshold); + return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp, + sizeof(tmp)); +} + + static void set_default_iw_params(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1246,6 +1279,28 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, } +static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + int err; + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + err = set_frag_threshold(usbdev, wiphy->frag_threshold); + if (err < 0) + return err; + } + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + err = set_rts_threshold(usbdev, wiphy->rts_threshold); + if (err < 0) + return err; + } + + return 0; +} + + #define SCAN_DELAY_JIFFIES (HZ) static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) @@ -1761,74 +1816,6 @@ static int rndis_iw_get_genie(struct net_device *dev, } -static int rndis_iw_set_rts(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - __le32 tmp; - devdbg(usbdev, "SIOCSIWRTS"); - - tmp = cpu_to_le32(wrqu->rts.value); - return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, - sizeof(tmp)); -} - - -static int rndis_iw_get_rts(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - __le32 tmp; - int len, ret; - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, &len); - if (ret == 0) { - wrqu->rts.value = le32_to_cpu(tmp); - wrqu->rts.flags = 1; - wrqu->rts.disabled = 0; - } - - devdbg(usbdev, "SIOCGIWRTS: %d", wrqu->rts.value); - - return ret; -} - - -static int rndis_iw_set_frag(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - __le32 tmp; - - devdbg(usbdev, "SIOCSIWFRAG"); - - tmp = cpu_to_le32(wrqu->frag.value); - return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp, - sizeof(tmp)); -} - - -static int rndis_iw_get_frag(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - __le32 tmp; - int len, ret; - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp, - &len); - if (ret == 0) { - wrqu->frag.value = le32_to_cpu(tmp); - wrqu->frag.flags = 1; - wrqu->frag.disabled = 0; - } - devdbg(usbdev, "SIOCGIWFRAG: %d", wrqu->frag.value); - return ret; -} - - static int rndis_iw_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2017,10 +2004,10 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid, IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid, IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate, - IW_IOCTL(SIOCSIWRTS) = rndis_iw_set_rts, - IW_IOCTL(SIOCGIWRTS) = rndis_iw_get_rts, - IW_IOCTL(SIOCSIWFRAG) = rndis_iw_set_frag, - IW_IOCTL(SIOCGIWFRAG) = rndis_iw_get_frag, + IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, + IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, + IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag, + IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag, IW_IOCTL(SIOCSIWTXPOW) = rndis_iw_set_txpower, IW_IOCTL(SIOCGIWTXPOW) = rndis_iw_get_txpower, IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode, @@ -2470,6 +2457,10 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) set_default_iw_params(usbdev); + /* set default rts/frag */ + rndis_set_wiphy_params(wiphy, + WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD); + /* turn radio on */ priv->radio_on = 1; disassociate(usbdev, 1); -- cgit v0.10.2 From a33e9e7f35ef6dcab528e0327f29188475f60691 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 16 Jun 2009 17:17:27 +0300 Subject: usbnet: Add stop function pointer to 'struct rndis_data'. Allow minidriver to know that netdev has stopped. This is to let wireless turn off radio when usbnet dev is stopped. Signed-off-by: Jussi Kivilinna Acked-by: David Brownell Acked-by: David S. Miller Signed-off-by: John W. Linville diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index edfd9e1..25e435c 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -575,7 +575,9 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); int usbnet_stop (struct net_device *net) { struct usbnet *dev = netdev_priv(net); + struct driver_info *info = dev->driver_info; int temp; + int retval; DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); DECLARE_WAITQUEUE (wait, current); @@ -587,6 +589,18 @@ int usbnet_stop (struct net_device *net) net->stats.rx_errors, net->stats.tx_errors ); + /* allow minidriver to stop correctly (wireless devices to turn off + * radio etc) */ + if (info->stop) { + retval = info->stop(dev); + if (retval < 0 && netif_msg_ifdown(dev)) + devinfo(dev, + "stop fail (%d) usbnet usb-%s-%s, %s", + retval, + dev->udev->bus->bus_name, dev->udev->devpath, + info->description); + } + // ensure there are no more active urbs add_wait_queue (&unlink_wakeup, &wait); dev->wait = &unlink_wakeup; diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 310e18a..7c17b2e 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -97,6 +97,9 @@ struct driver_info { /* reset device ... can sleep */ int (*reset)(struct usbnet *); + /* stop device ... can sleep */ + int (*stop)(struct usbnet *); + /* see if peer is connected ... can sleep */ int (*check_connect)(struct usbnet *); -- cgit v0.10.2 From 222ec50a0a5d20e75522aacf4c767df6585e8548 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 16 Jun 2009 17:17:32 +0300 Subject: rndis_wlan: convert set/get txpower to cfg80211 Convert set/get txpower to cfg80211 and add stop netdev handler to turn off radio for rfkill. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index edd4aad..09c0702 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -139,9 +139,15 @@ MODULE_PARM_DESC(workaround_interval, /* Assume that Broadcom 4320 (only chipset at time of writing known to be * based on wireless rndis) has default txpower of 13dBm. * This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications. - * 13dBm == 19.9mW + * 100% : 20 mW ~ 13dBm + * 75% : 15 mW ~ 12dBm + * 50% : 10 mW ~ 10dBm + * 25% : 5 mW ~ 7dBm */ -#define BCM4320_DEFAULT_TXPOWER 20 +#define BCM4320_DEFAULT_TXPOWER_DBM_100 13 +#define BCM4320_DEFAULT_TXPOWER_DBM_75 12 +#define BCM4320_DEFAULT_TXPOWER_DBM_50 10 +#define BCM4320_DEFAULT_TXPOWER_DBM_25 7 /* codes for "status" field of completion messages */ @@ -430,15 +436,20 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); +static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, + int dbm); +static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, .set_wiphy_params = rndis_set_wiphy_params, + .set_tx_power = rndis_set_tx_power, + .get_tx_power = rndis_get_tx_power, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; -static const int bcm4320_power_output[4] = { 25, 50, 75, 100 }; static const unsigned char zero_bssid[ETH_ALEN] = {0,}; static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, @@ -451,10 +462,19 @@ static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) } -static u32 get_bcm4320_power(struct rndis_wlan_private *priv) +static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) { - return BCM4320_DEFAULT_TXPOWER * - bcm4320_power_output[priv->param_power_output] / 100; + switch (priv->param_power_output) { + default: + case 3: + return BCM4320_DEFAULT_TXPOWER_DBM_100; + case 2: + return BCM4320_DEFAULT_TXPOWER_DBM_75; + case 1: + return BCM4320_DEFAULT_TXPOWER_DBM_50; + case 0: + return BCM4320_DEFAULT_TXPOWER_DBM_25; + } } @@ -1301,6 +1321,42 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) } +static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, + int dbm) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + devdbg(usbdev, "rndis_set_tx_power type:0x%x dbm:%i", type, dbm); + + /* Device doesn't support changing txpower after initialization, only + * turn off/on radio. Support 'auto' mode and setting same dBm that is + * currently used. + */ + if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) { + if (!priv->radio_on) + disassociate(usbdev, 1); /* turn on radio */ + + return 0; + } + + return -ENOTSUPP; +} + + +static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + *dbm = get_bcm4320_power_dbm(priv); + + devdbg(usbdev, "rndis_get_tx_power dbm:%i", *dbm); + + return 0; +} + + #define SCAN_DELAY_JIFFIES (HZ) static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) @@ -1864,71 +1920,6 @@ static int rndis_iw_get_freq(struct net_device *dev, } -static int rndis_iw_get_txpower(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tx_power; - - if (priv->radio_on) { - /* fake since changing tx_power (by userlevel) not supported */ - tx_power = cpu_to_le32(get_bcm4320_power(priv)); - - wrqu->txpower.flags = IW_TXPOW_MWATT; - wrqu->txpower.value = le32_to_cpu(tx_power); - wrqu->txpower.disabled = 0; - } else { - wrqu->txpower.flags = IW_TXPOW_MWATT; - wrqu->txpower.value = 0; - wrqu->txpower.disabled = 1; - } - - devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value); - - return 0; -} - - -static int rndis_iw_set_txpower(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tx_power = 0; - - if (!wrqu->txpower.disabled) { - if (wrqu->txpower.flags == IW_TXPOW_MWATT) - tx_power = cpu_to_le32(wrqu->txpower.value); - else { /* wrqu->txpower.flags == IW_TXPOW_DBM */ - if (wrqu->txpower.value > 20) - tx_power = cpu_to_le32(128); - else if (wrqu->txpower.value < -43) - tx_power = cpu_to_le32(127); - else { - signed char tmp; - tmp = wrqu->txpower.value; - tmp = -12 - tmp; - tmp <<= 2; - tx_power = cpu_to_le32((unsigned char)tmp); - } - } - } - - devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power)); - - if (le32_to_cpu(tx_power) != 0) { - /* txpower unsupported, just turn radio on */ - if (!priv->radio_on) - return disassociate(usbdev, 1); - return 0; /* all ready on */ - } - - /* tx_power == 0, turn off radio */ - return disassociate(usbdev, 0); -} - - static int rndis_iw_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2008,8 +1999,8 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag, IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag, - IW_IOCTL(SIOCSIWTXPOW) = rndis_iw_set_txpower, - IW_IOCTL(SIOCGIWTXPOW) = rndis_iw_get_txpower, + IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) cfg80211_wext_siwtxpower, + IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower, IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode, IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext, IW_IOCTL(SIOCSIWAUTH) = rndis_iw_set_auth, @@ -2508,10 +2499,18 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) static int rndis_wlan_reset(struct usbnet *usbdev) { + devdbg(usbdev, "rndis_wlan_reset"); return deauthenticate(usbdev); } +static int rndis_wlan_stop(struct usbnet *usbdev) +{ + devdbg(usbdev, "rndis_wlan_stop"); + return disassociate(usbdev, 0); +} + + static const struct driver_info bcm4320b_info = { .description = "Wireless RNDIS device, BCM4320b based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, @@ -2521,6 +2520,7 @@ static const struct driver_info bcm4320b_info = { .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, .reset = rndis_wlan_reset, + .stop = rndis_wlan_stop, .early_init = bcm4320b_early_init, .link_change = rndis_wlan_link_change, }; @@ -2534,6 +2534,7 @@ static const struct driver_info bcm4320a_info = { .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, .reset = rndis_wlan_reset, + .stop = rndis_wlan_stop, .early_init = bcm4320a_early_init, .link_change = rndis_wlan_link_change, }; @@ -2547,6 +2548,7 @@ static const struct driver_info rndis_wlan_info = { .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, .reset = rndis_wlan_reset, + .stop = rndis_wlan_stop, .early_init = bcm4320a_early_init, .link_change = rndis_wlan_link_change, }; -- cgit v0.10.2 From a538e2d5a30f577e9c8f6ccfe72b29a258e0fe86 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2009 19:56:42 +0200 Subject: cfg80211: issue netlink notification when scan starts To ease multiple apps working together smoothly, send a notification when a scan is started. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f91e5d4..5a6c4ca 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2839,6 +2839,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) drv->scan_req = request; err = drv->ops->scan(&drv->wiphy, dev, request); + if (!err) + nl80211_send_scan_start(drv, dev); + out_free: if (err) { drv->scan_req = NULL; @@ -3665,11 +3668,11 @@ static int nl80211_add_scan_req(struct sk_buff *msg, return -ENOBUFS; } -static int nl80211_send_scan_donemsg(struct sk_buff *msg, - struct cfg80211_registered_device *rdev, - struct net_device *netdev, - u32 pid, u32 seq, int flags, - u32 cmd) +static int nl80211_send_scan_msg(struct sk_buff *msg, + struct cfg80211_registered_device *rdev, + struct net_device *netdev, + u32 pid, u32 seq, int flags, + u32 cmd) { void *hdr; @@ -3690,6 +3693,24 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg, return -EMSGSIZE; } +void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, + struct net_device *netdev) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return; + + if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + NL80211_CMD_TRIGGER_SCAN) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); +} + void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, struct net_device *netdev) { @@ -3699,8 +3720,8 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, if (!msg) return; - if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0, - NL80211_CMD_NEW_SCAN_RESULTS) < 0) { + if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + NL80211_CMD_NEW_SCAN_RESULTS) < 0) { nlmsg_free(msg); return; } @@ -3717,8 +3738,8 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, if (!msg) return; - if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0, - NL80211_CMD_SCAN_ABORTED) < 0) { + if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + NL80211_CMD_SCAN_ABORTED) < 0) { nlmsg_free(msg); return; } diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 5c12ad1..a3872a4 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -6,6 +6,8 @@ extern int nl80211_init(void); extern void nl80211_exit(void); extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); +extern void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, + struct net_device *netdev); extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, struct net_device *netdev); extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/scan.c b/net/wireless/scan.c index f8e71b3..261a063 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -647,7 +647,8 @@ int cfg80211_wext_siwscan(struct net_device *dev, if (err) { rdev->scan_req = NULL; kfree(creq); - } + } else + nl80211_send_scan_start(rdev, dev); out: cfg80211_put_dev(rdev); return err; -- cgit v0.10.2 From 18ad01c43918751cc22f8ee28f6b38b8954a55b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2009 20:46:45 +0200 Subject: rt2x00: remove skb->do_not_encrypt usage Johannes is trying to get rid of the master netdev and in the process will remove skb->do_not_encrypt field. This removes the do_not_encrypt usage from rt2x00 to make the change easier. Signed-off-by: Johannes Berg Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index bc4e81e..c54eda3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -53,8 +53,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; - if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || - !hw_key || entry->skb->do_not_encrypt) + if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key) return; __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); @@ -82,8 +81,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev, struct ieee80211_key_conf *key = tx_info->control.hw_key; unsigned int overhead = 0; - if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || - !key || skb->do_not_encrypt) + if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key) return overhead; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c4c06b4..475a3ed 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -73,7 +73,8 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, else rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; - skb->do_not_encrypt = 1; + /* Disable hardware encryption */ + rts_info->control.hw_key = NULL; /* * RTS/CTS frame should use the length of the frame plus any -- cgit v0.10.2 From f1d58c2521eb160178b2151d6326d8dc5d7c8560 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2009 13:13:00 +0200 Subject: mac80211: push rx status into skb->cb Within mac80211, we often need to copy the rx status into skb->cb. This is wasteful, as drivers could be building it in there to start with. This patch changes the API so that drivers are expected to pass the RX status in skb->cb, now accessible as IEEE80211_SKB_RXCB(skb). It also updates all drivers to pass the rx status in there, but only by making them memcpy() it into place before the call to the receive function (ieee80211_rx(_irqsafe)). Each driver can now be optimised on its own schedule. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 2b9e379..ecc9383 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -452,7 +452,8 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) rx_status.freq = adm8211_channels[priv->channel - 1].center_freq; rx_status.band = IEEE80211_BAND_2GHZ; - ieee80211_rx_irqsafe(dev, skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(dev, skb); } entry = (++priv->cur_rx) % priv->rx_ring_size; diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 4efbdbe..13303fa 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1568,7 +1568,8 @@ static void at76_rx_tasklet(unsigned long param) at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d", priv->rx_skb->len, priv->rx_skb->data_len); - ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(priv->rx_skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(priv->hw, priv->rx_skb); /* Use a new skb for the next receive */ priv->rx_skb = NULL; diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 9d38cf6..51753ed 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -917,8 +917,10 @@ static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) ar9170_rx_phy_status(ar, phy, &status); skb = ar9170_rx_copy_data(buf, mpdu_len); - if (likely(skb)) - ieee80211_rx_irqsafe(ar->hw, skb, &status); + if (likely(skb)) { + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx_irqsafe(ar->hw, skb); + } } void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index f26a689..c6e7091 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1905,7 +1905,8 @@ accept: if (sc->opmode == NL80211_IFTYPE_ADHOC) ath5k_check_ibss_tsf(sc, skb, &rxs); - __ieee80211_rx(sc->hw, skb, &rxs); + memcpy(IEEE80211_SKB_RXCB(skb), &rxs, sizeof(rxs)); + ieee80211_rx(sc->hw, skb); bf->skb = next_skb; bf->skbaddr = next_skb_addr; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index cece1c4..c00b905 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -619,13 +619,18 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, if (aphy == NULL) continue; nskb = skb_copy(skb, GFP_ATOMIC); - if (nskb) - __ieee80211_rx(aphy->hw, nskb, rx_status); + if (nskb) { + memcpy(IEEE80211_SKB_RXCB(nskb), rx_status, + sizeof(*rx_status)); + ieee80211_rx(aphy->hw, nskb); + } } - __ieee80211_rx(sc->hw, skb, rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); + ieee80211_rx(sc->hw, skb); } else { /* Deliver unicast frames based on receiver address */ - __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); + ieee80211_rx(ath_get_virt_hw(sc, hdr), skb); } } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 55f36a7..5b85e7d 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -670,7 +670,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) goto drop; } - ieee80211_rx_irqsafe(dev->wl->hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx_irqsafe(dev->wl->hw, skb); return; drop: diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index b8e39dd..f79cee8 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -591,7 +591,8 @@ void b43legacy_rx(struct b43legacy_wldev *dev, } dev->stats.last_rx = jiffies; - ieee80211_rx_irqsafe(dev->wl->hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx_irqsafe(dev->wl->hw, skb); return; drop: diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 46288e7..777c095 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -577,7 +577,8 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, if (ieee80211_is_data(hdr->frame_control)) priv->rxtxpackets += len; #endif - ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); + ieee80211_rx_irqsafe(priv->hw, rxb->skb); rxb->skb = NULL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 2b8d40b..2160795 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -932,7 +932,8 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, return; iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); - ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); + ieee80211_rx_irqsafe(priv->hw, rxb->skb); priv->alloc_rxb_skb--; rxb->skb = NULL; } diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 10a99e2..4872345 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -503,7 +503,8 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) skb_reserve(skb, 2); } - ieee80211_rx_irqsafe(priv->hw, skb, &stats); + memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats)); + ieee80211_rx_irqsafe(priv->hw, skb); return 0; } EXPORT_SYMBOL_GPL(lbtf_rx); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index c47ef48..b1e4bae 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -430,7 +430,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr, ETH_ALEN) == 0) ack = true; - ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(data2->hw, nskb); } spin_unlock(&hwsim_radio_lock); diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a263d5c..b9eded8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1047,7 +1047,8 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) status.flag = 0; status.band = IEEE80211_BAND_2GHZ; status.freq = ieee80211_channel_to_frequency(rx_desc->channel); - ieee80211_rx_irqsafe(hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx_irqsafe(hw, skb); processed++; } diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 22ca122..1b15f9e 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -794,7 +794,8 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) skb_pull(skb, header_len); skb_trim(skb, le16_to_cpu(hdr->len)); - ieee80211_rx_irqsafe(dev, skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(dev, skb); queue_delayed_work(dev->workqueue, &priv->work, msecs_to_jiffies(P54_STATISTICS_UPDATE)); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 57813e7..41e3379 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -449,7 +449,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * mac80211 will clean up the skb structure. */ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); - ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status); + memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status)); + ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb); /* * Replace the skb with the freshly allocated one. diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 7e65d7c..47521c5 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -143,7 +143,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; - ieee80211_rx_irqsafe(dev, skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(dev, skb); skb = new_skb; priv->rx_buf[priv->rx_idx] = skb; diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 294250e..c9b9dbe 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -380,7 +380,8 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.flag |= RX_FLAG_TSFT; if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; - ieee80211_rx_irqsafe(dev, skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(dev, skb); skb = dev_alloc_skb(RTL8187_MAX_RX); if (unlikely(!skb)) { diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index 48fa39e..0dbb483 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -151,7 +151,8 @@ static void wl1251_rx_body(struct wl1251 *wl, wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, beacon ? "beacon" : ""); - ieee80211_rx(wl->hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx(wl->hw, skb); } static void wl1251_rx_ack(struct wl1251 *wl) diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 40b07b9..9600b72 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -711,7 +711,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) memcpy(skb_put(skb, length), buffer, length); - ieee80211_rx_irqsafe(hw, skb, &stats); + memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats)); + ieee80211_rx_irqsafe(hw, skb); return 0; } diff --git a/drivers/staging/agnx/xmit.c b/drivers/staging/agnx/xmit.c index 0e03408..42db410 100644 --- a/drivers/staging/agnx/xmit.c +++ b/drivers/staging/agnx/xmit.c @@ -384,7 +384,8 @@ void handle_rx_irq(struct agnx_priv *priv) /* dump_ieee80211_hdr((struct ieee80211_hdr *)skb->data, "RX G"); */ } else agnx_bug("Unknown packets type"); - ieee80211_rx_irqsafe(priv->hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx_irqsafe(priv->hw, skb); rx_desc_reinit(priv, i); } while (priv->rx.idx++); diff --git a/drivers/staging/stlc45xx/stlc45xx.c b/drivers/staging/stlc45xx/stlc45xx.c index cfdaac9..52744fa 100644 --- a/drivers/staging/stlc45xx/stlc45xx.c +++ b/drivers/staging/stlc45xx/stlc45xx.c @@ -1429,7 +1429,8 @@ static int stlc45xx_rx_data(struct stlc45xx *stlc, struct sk_buff *skb) stlc45xx_debug(DEBUG_RX, "rx data 0x%p %d B", skb->data, skb->len); stlc45xx_dump(DEBUG_RX_CONTENT, skb->data, skb->len); - ieee80211_rx(stlc->hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx(stlc->hw, skb); return 0; } diff --git a/drivers/staging/winbond/wb35rx.c b/drivers/staging/winbond/wb35rx.c index 3e8cf08..b905e7b 100644 --- a/drivers/staging/winbond/wb35rx.c +++ b/drivers/staging/winbond/wb35rx.c @@ -40,7 +40,8 @@ static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress, int Pac rx_status.phymode = MODE_IEEE80211B; */ - ieee80211_rx_irqsafe(hw, skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(hw, skb); } static void Wb35Rx_adjust(PDESCRIPTOR pRxDes) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c061044..fe80771 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -397,6 +397,11 @@ static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) return (struct ieee80211_tx_info *)skb->cb; } +static inline struct ieee80211_rx_status *IEEE80211_SKB_RXCB(struct sk_buff *skb) +{ + return (struct ieee80211_rx_status *)skb->cb; +} + /** * ieee80211_tx_info_clear_status - clear TX status * @@ -478,7 +483,7 @@ enum mac80211_rx_flags { * * The low-level driver should provide this information (the subset * supported by hardware) to the 802.11 code with each received - * frame. + * frame, in the skb's control buffer (cb). * * @mactime: value in microseconds of the 64-bit Time Synchronization Function * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. @@ -1606,9 +1611,11 @@ void ieee80211_free_hw(struct ieee80211_hw *hw); */ void ieee80211_restart_hw(struct ieee80211_hw *hw); -/* trick to avoid symbol clashes with the ieee80211 subsystem */ -void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_rx_status *status); +/* + * trick to avoid symbol clashes with the ieee80211 subsystem, + * use the inline below instead + */ +void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb); /** * ieee80211_rx - receive frame @@ -1624,13 +1631,10 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, * * @hw: the hardware this frame came in on * @skb: the buffer to receive, owned by mac80211 after this call - * @status: status of this frame; the status pointer need not be valid - * after this function returns */ -static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_rx_status *status) +static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) { - __ieee80211_rx(hw, skb, status); + __ieee80211_rx(hw, skb); } /** @@ -1644,13 +1648,8 @@ static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, * * @hw: the hardware this frame came in on * @skb: the buffer to receive, owned by mac80211 after this call - * @status: status of this frame; the status pointer need not be valid - * after this function returns and is not freed by mac80211, - * it is recommended that it points to a stack area */ -void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_rx_status *status); +void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb); /** * ieee80211_tx_status - transmit status callback diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 0b30277..15d5a53 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -705,7 +705,7 @@ static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt; u16 fc; - rx_status = (struct ieee80211_rx_status *) skb->cb; + rx_status = IEEE80211_SKB_RXCB(skb); mgmt = (struct ieee80211_mgmt *) skb->data; fc = le16_to_cpu(mgmt->frame_control); @@ -836,8 +836,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) } ieee80211_rx_result -ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) +ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { struct ieee80211_local *local = sdata->local; struct ieee80211_mgmt *mgmt; @@ -852,7 +851,6 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: - memcpy(skb->cb, rx_status, sizeof(*rx_status)); case IEEE80211_STYPE_PROBE_REQ: case IEEE80211_STYPE_AUTH: skb_queue_tail(&sdata->u.ibss.skb_queue, skb); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 68eb505..c65c65a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -943,8 +943,7 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; /* STA code */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); + struct sk_buff *skb); int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata); int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); @@ -967,8 +966,7 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result -ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); +ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, u8 *bssid, u8 *addr, u32 supp_rates); int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, @@ -988,9 +986,7 @@ int ieee80211_scan_results(struct ieee80211_local *local, char *buf, size_t len); void ieee80211_scan_cancel(struct ieee80211_local *local); ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); +ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, const char *ie, size_t len); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 092a017..5b69f5f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -330,19 +330,16 @@ static void ieee80211_tasklet_handler(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *) data; struct sk_buff *skb; - struct ieee80211_rx_status rx_status; struct ieee80211_ra_tid *ra_tid; while ((skb = skb_dequeue(&local->skb_queue)) || (skb = skb_dequeue(&local->skb_queue_unreliable))) { switch (skb->pkt_type) { case IEEE80211_RX_MSG: - /* status is in skb->cb */ - memcpy(&rx_status, skb->cb, sizeof(rx_status)); /* Clear skb->pkt_type in order to not confuse kernel * netstack. */ skb->pkt_type = 0; - __ieee80211_rx(local_to_hw(local), skb, &rx_status); + ieee80211_rx(local_to_hw(local), skb); break; case IEEE80211_TX_STATUS_MSG: skb->pkt_type = 0; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 11cf45b..542ea02 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -568,7 +568,7 @@ static void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, ifmsh = &sdata->u.mesh; - rx_status = (struct ieee80211_rx_status *) skb->cb; + rx_status = IEEE80211_SKB_RXCB(skb); mgmt = (struct ieee80211_mgmt *) skb->data; stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; @@ -671,8 +671,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) } ieee80211_rx_result -ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) +ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; @@ -689,7 +688,6 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: case IEEE80211_STYPE_ACTION: - memcpy(skb->cb, rx_status, sizeof(*rx_status)); skb_queue_tail(&ifmsh->skb_queue, skb); queue_work(local->hw.workqueue, &ifmsh->work); return RX_QUEUED; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index c7d7281..2a2ed18 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -208,8 +208,7 @@ void ieee80211s_init(void); void ieee80211s_stop(void); void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result -ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); +ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index aca22b0..5e25d32 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2063,8 +2063,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) + struct sk_buff *skb) { struct ieee80211_local *local = sdata->local; struct ieee80211_mgmt *mgmt; @@ -2080,7 +2079,6 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, case IEEE80211_STYPE_PROBE_REQ: case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: - memcpy(skb->cb, rx_status, sizeof(*rx_status)); case IEEE80211_STYPE_AUTH: case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_RESP: diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index de5bba7..0563b69 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -30,7 +30,6 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, struct tid_ampdu_rx *tid_agg_rx, struct sk_buff *skb, - struct ieee80211_rx_status *status, u16 mpdu_seq_num, int bar_req); /* @@ -59,11 +58,11 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, return skb; } -static inline int should_drop_frame(struct ieee80211_rx_status *status, - struct sk_buff *skb, +static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len, int radiotap_len) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) @@ -111,10 +110,10 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, static void ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_rx_status *status, struct ieee80211_rate *rate, int rtap_len) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_radiotap_header *rthdr; unsigned char *pos; @@ -220,9 +219,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, */ static struct sk_buff * ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, - struct ieee80211_rx_status *status, struct ieee80211_rate *rate) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); struct ieee80211_sub_if_data *sdata; int needed_headroom = 0; struct sk_buff *skb, *skb2; @@ -248,8 +247,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, present_fcs_len = FCS_LEN; if (!local->monitors) { - if (should_drop_frame(status, origskb, present_fcs_len, - rtap_len)) { + if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { dev_kfree_skb(origskb); return NULL; } @@ -257,7 +255,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, return remove_monitor_info(local, origskb, rtap_len); } - if (should_drop_frame(status, origskb, present_fcs_len, rtap_len)) { + if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { /* only need to expand headroom if necessary */ skb = origskb; origskb = NULL; @@ -289,7 +287,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, /* if necessary, prepend radiotap information */ if (!(status->flag & RX_FLAG_RADIOTAP)) - ieee80211_add_rx_radiotap_header(local, skb, status, rate, + ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom); skb_reset_mac_header(skb); @@ -421,12 +419,11 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) struct sk_buff *skb = rx->skb; if (unlikely(local->hw_scanning)) - return ieee80211_scan_rx(rx->sdata, skb, rx->status); + return ieee80211_scan_rx(rx->sdata, skb); if (unlikely(local->sw_scanning)) { /* drop all the other packets during a software scan anyway */ - if (ieee80211_scan_rx(rx->sdata, skb, rx->status) - != RX_QUEUED) + if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) dev_kfree_skb(skb); return RX_QUEUED; } @@ -1620,7 +1617,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) /* manage reordering buffer according to requested */ /* sequence number */ rcu_read_lock(); - ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, NULL, + ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, start_seq_num, 1); rcu_read_unlock(); return RX_DROP_UNUSABLE; @@ -1817,13 +1814,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; if (ieee80211_vif_is_mesh(&sdata->vif)) - return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status); + return ieee80211_mesh_rx_mgmt(sdata, rx->skb); if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status); + return ieee80211_ibss_rx_mgmt(sdata, rx->skb); if (sdata->vif.type == NL80211_IFTYPE_STATION) - return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status); + return ieee80211_sta_rx_mgmt(sdata, rx->skb); return RX_DROP_MONITOR; } @@ -2114,9 +2111,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, */ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_rx_status *status, struct ieee80211_rate *rate) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr; @@ -2227,20 +2224,21 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, { struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; - struct ieee80211_rx_status status; + struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; + struct ieee80211_rx_status *status; - if (!tid_agg_rx->reorder_buf[index]) + if (!skb) goto no_frame; + status = IEEE80211_SKB_RXCB(skb); + /* release the reordered frames to stack */ - memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status)); - sband = hw->wiphy->bands[status.band]; - if (status.flag & RX_FLAG_HT) + sband = hw->wiphy->bands[status->band]; + if (status->flag & RX_FLAG_HT) rate = sband->bitrates; /* TODO: HT rates */ else - rate = &sband->bitrates[status.rate_idx]; - __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, rate); + rate = &sband->bitrates[status->rate_idx]; + __ieee80211_rx_handle_packet(hw, skb, rate); tid_agg_rx->stored_mpdu_num--; tid_agg_rx->reorder_buf[index] = NULL; @@ -2265,7 +2263,6 @@ no_frame: static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, struct tid_ampdu_rx *tid_agg_rx, struct sk_buff *skb, - struct ieee80211_rx_status *rxstatus, u16 mpdu_seq_num, int bar_req) { @@ -2324,8 +2321,6 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, /* put the frame in the reordering buffer */ tid_agg_rx->reorder_buf[index] = skb; tid_agg_rx->reorder_time[index] = jiffies; - memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus, - sizeof(*rxstatus)); tid_agg_rx->stored_mpdu_num++; /* release the buffer until next missing frame */ index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) @@ -2374,8 +2369,7 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, } static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_rx_status *status) + struct sk_buff *skb) { struct ieee80211_hw *hw = &local->hw; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -2424,7 +2418,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, /* according to mpdu sequence number deal with reordering buffer */ mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; - ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, status, + ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, mpdu_seq_num, 0); end_reorder: return ret; @@ -2434,12 +2428,12 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, * This is the receive path handler. It is called by a low level driver when an * 802.11 MPDU is received from the hardware. */ -void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_rx_status *status) +void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate = NULL; struct ieee80211_supported_band *sband; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); if (status->band < 0 || status->band >= IEEE80211_NUM_BANDS) { @@ -2482,7 +2476,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, * if it was previously present. * Also, frames with less than 16 bytes are dropped. */ - skb = ieee80211_rx_monitor(local, skb, status, rate); + skb = ieee80211_rx_monitor(local, skb, rate); if (!skb) { rcu_read_unlock(); return; @@ -2500,8 +2494,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, * frames from other than operational channel), but that should not * happen in normal networks. */ - if (!ieee80211_rx_reorder_ampdu(local, skb, status)) - __ieee80211_rx_handle_packet(hw, skb, status, rate); + if (!ieee80211_rx_reorder_ampdu(local, skb)) + __ieee80211_rx_handle_packet(hw, skb, rate); rcu_read_unlock(); } @@ -2509,16 +2503,13 @@ EXPORT_SYMBOL(__ieee80211_rx); /* This is a version of the rx handler that can be called from hard irq * context. Post the skb on the queue and schedule the tasklet */ -void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_rx_status *status) +void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb)); skb->dev = local->mdev; - /* copy status into skb->cb for use by tasklet */ - memcpy(skb->cb, status, sizeof(*status)); skb->pkt_type = IEEE80211_RX_MSG; skb_queue_tail(&local->skb_queue, skb); tasklet_schedule(&local->tasklet); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 2a8d09a..8b2416c 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -135,9 +135,9 @@ void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, } ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) +ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct ieee80211_mgmt *mgmt; struct ieee80211_bss *bss; u8 *elements; -- cgit v0.10.2 From 386aa23dd5f94b810210b9f849807946a5100b57 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2009 17:28:45 +0200 Subject: mac80211: improve per-sta debugfs We had code for a number of files, that we didn't publish in debugfs, fix that. Also make the agg_status file layout more readable and add more information to it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 90230c7..33a2e89 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -120,45 +120,38 @@ STA_OPS(last_seq_ctrl); static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - char buf[768], *p = buf; + char buf[30 + STA_TID_NUM * 70], *p = buf; int i; struct sta_info *sta = file->private_data; - p += scnprintf(p, sizeof(buf)+buf-p, "Agg state for STA is:\n"); - p += scnprintf(p, sizeof(buf)+buf-p, " STA next dialog_token is %d \n " - "TIDs info is: \n TID :", - (sta->ampdu_mlme.dialog_token_allocator + 1)); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", i); - - p += scnprintf(p, sizeof(buf)+buf-p, "\n RX :"); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_state_rx[i]); - - p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_state_rx[i] ? - sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); - - p += scnprintf(p, sizeof(buf)+buf-p, "\n TX :"); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_state_tx[i]); - - p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_state_tx[i] ? - sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); - - p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :"); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_state_tx[i] ? - sta->ampdu_mlme.tid_tx[i]->ssn : 0); - p += scnprintf(p, sizeof(buf)+buf-p, "\n"); + spin_lock_bh(&sta->lock); + p += scnprintf(p, sizeof(buf)+buf-p, "next dialog_token is %#02x\n", + sta->ampdu_mlme.dialog_token_allocator + 1); + for (i = 0; i < STA_TID_NUM; i++) { + p += scnprintf(p, sizeof(buf)+buf-p, "TID %02d:", i); + p += scnprintf(p, sizeof(buf)+buf-p, " RX=%x", + sta->ampdu_mlme.tid_state_rx[i]); + p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", + sta->ampdu_mlme.tid_state_rx[i] ? + sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); + p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", + sta->ampdu_mlme.tid_state_rx[i] ? + sta->ampdu_mlme.tid_rx[i]->ssn : 0); + + p += scnprintf(p, sizeof(buf)+buf-p, " TX=%x", + sta->ampdu_mlme.tid_state_tx[i]); + p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", + sta->ampdu_mlme.tid_state_tx[i] ? + sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); + p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", + sta->ampdu_mlme.tid_state_tx[i] ? + sta->ampdu_mlme.tid_tx[i]->ssn : 0); + p += scnprintf(p, sizeof(buf)+buf-p, "/pending=%03d", + sta->ampdu_mlme.tid_state_tx[i] ? + skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); + p += scnprintf(p, sizeof(buf)+buf-p, "\n"); + } + spin_unlock_bh(&sta->lock); return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); } @@ -203,6 +196,22 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(inactive_ms); DEBUGFS_ADD(last_seq_ctrl); DEBUGFS_ADD(agg_status); + DEBUGFS_ADD(dev); + DEBUGFS_ADD(rx_packets); + DEBUGFS_ADD(tx_packets); + DEBUGFS_ADD(rx_bytes); + DEBUGFS_ADD(tx_bytes); + DEBUGFS_ADD(rx_duplicates); + DEBUGFS_ADD(rx_fragments); + DEBUGFS_ADD(rx_dropped); + DEBUGFS_ADD(tx_fragments); + DEBUGFS_ADD(tx_filtered); + DEBUGFS_ADD(tx_retry_failed); + DEBUGFS_ADD(tx_retry_count); + DEBUGFS_ADD(last_signal); + DEBUGFS_ADD(last_qual); + DEBUGFS_ADD(last_noise); + DEBUGFS_ADD(wep_weak_iv_count); } void ieee80211_sta_debugfs_remove(struct sta_info *sta) @@ -212,6 +221,23 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta) DEBUGFS_DEL(inactive_ms); DEBUGFS_DEL(last_seq_ctrl); DEBUGFS_DEL(agg_status); + DEBUGFS_DEL(aid); + DEBUGFS_DEL(dev); + DEBUGFS_DEL(rx_packets); + DEBUGFS_DEL(tx_packets); + DEBUGFS_DEL(rx_bytes); + DEBUGFS_DEL(tx_bytes); + DEBUGFS_DEL(rx_duplicates); + DEBUGFS_DEL(rx_fragments); + DEBUGFS_DEL(rx_dropped); + DEBUGFS_DEL(tx_fragments); + DEBUGFS_DEL(tx_filtered); + DEBUGFS_DEL(tx_retry_failed); + DEBUGFS_DEL(tx_retry_count); + DEBUGFS_DEL(last_signal); + DEBUGFS_DEL(last_qual); + DEBUGFS_DEL(last_noise); + DEBUGFS_DEL(wep_weak_iv_count); debugfs_remove(sta->debugfs.dir); sta->debugfs.dir = NULL; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 49a1a1f..4ecf10a 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -308,6 +308,23 @@ struct sta_info { struct dentry *inactive_ms; struct dentry *last_seq_ctrl; struct dentry *agg_status; + struct dentry *aid; + struct dentry *dev; + struct dentry *rx_packets; + struct dentry *tx_packets; + struct dentry *rx_bytes; + struct dentry *tx_bytes; + struct dentry *rx_duplicates; + struct dentry *rx_fragments; + struct dentry *rx_dropped; + struct dentry *tx_fragments; + struct dentry *tx_filtered; + struct dentry *tx_retry_failed; + struct dentry *tx_retry_count; + struct dentry *last_signal; + struct dentry *last_qual; + struct dentry *last_noise; + struct dentry *wep_weak_iv_count; bool add_has_run; } debugfs; #endif -- cgit v0.10.2 From 83f5e2cf79390f7ca909b7035dd415230257cc4d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2009 17:41:49 +0200 Subject: cfg80211: prohibit scanning the same channel more than once It isn't very useful to scan the same channel more than once during a given scan, and some hardware (notably iwlwifi) can only scan a limited number of channels at a time. To prevent any overflows, simply disallow scanning any channel multiple times in a given scan command. This is a small change in the userspace ABI, but the only user, wpa_supplicant, never asks for a scan with the same frequency listed twice. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5a6c4ca..7946b82 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2695,6 +2695,31 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) return r; } +static int validate_scan_freqs(struct nlattr *freqs) +{ + struct nlattr *attr1, *attr2; + int n_channels = 0, tmp1, tmp2; + + nla_for_each_nested(attr1, freqs, tmp1) { + n_channels++; + /* + * Some hardware has a limited channel list for + * scanning, and it is pretty much nonsensical + * to scan for a channel twice, so disallow that + * and don't require drivers to check that the + * channel list they get isn't longer than what + * they can scan, as long as they can scan all + * the channels they registered at once. + */ + nla_for_each_nested(attr2, freqs, tmp2) + if (attr1 != attr2 && + nla_get_u32(attr1) == nla_get_u32(attr2)) + return 0; + } + + return n_channels; +} + static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; @@ -2704,7 +2729,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) struct ieee80211_channel *channel; struct nlattr *attr; struct wiphy *wiphy; - int err, tmp, n_ssids = 0, n_channels = 0, i; + int err, tmp, n_ssids = 0, n_channels, i; enum ieee80211_band band; size_t ie_len; @@ -2735,13 +2760,15 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { - nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) - n_channels++; + n_channels = validate_scan_freqs( + info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); if (!n_channels) { err = -EINVAL; goto out; } } else { + n_channels = 0; + for (band = 0; band < IEEE80211_NUM_BANDS; band++) if (wiphy->bands[band]) n_channels += wiphy->bands[band]->n_channels; -- cgit v0.10.2 From 3bfbe80e4462c22e5dc42a00b2b394e347f4aa09 Mon Sep 17 00:00:00 2001 From: Hin-Tak Leung Date: Thu, 18 Jun 2009 03:53:26 +0100 Subject: zd1211rw: sort vid/pid pairs by numerical value In the past ids were inserted in no particular order and it has become hard to see what ids are already included or not. This patch sorts the ids by numerical value and has no functional effect. Signed-off-by: Hin-Tak Leung Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 0e6e446..07d7ab6 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -36,58 +36,59 @@ static struct usb_device_id usb_ids[] = { /* ZD1211 */ + { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ + { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, -- cgit v0.10.2 From 90e3012e94be0755a516f60f5339a2a08f4a7d0a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 18 Jun 2009 14:51:12 +0200 Subject: mac80211_hwsim: clean up the skb before passing it back We need to clean up the skb before we can copy it, this is required for proper operation since the socket it is still attached to could potentially live in a different network namespace or so. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index b1e4bae..1b59edc 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -15,6 +15,8 @@ #include #include +#include +#include #include #include #include @@ -409,6 +411,14 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (data->ps != PS_DISABLED) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + /* release the skb's source info */ + skb_orphan(skb); + dst_release(skb->dst); + skb->dst = NULL; + skb->mark = 0; + secpath_reset(skb); + nf_reset(skb); + /* Copy skb to all enabled radios that are on the current frequency */ spin_lock(&hwsim_radio_lock); list_for_each_entry(data2, &hwsim_radios, list) { -- cgit v0.10.2 From f1f74825fe01ac77204ca34e3240dec50a8207c2 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:13 +0100 Subject: cfg80211: add wrapper function to get wiphy from priv pointer Signed-off-by: David Kilroy Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 90f9bfa..dba7874 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1059,6 +1059,17 @@ static inline void *wiphy_priv(struct wiphy *wiphy) } /** + * priv_to_wiphy - return the wiphy containing the priv + * + * @priv: a pointer previously returned by wiphy_priv + */ +static inline struct wiphy *priv_to_wiphy(void *priv) +{ + BUG_ON(!priv); + return container_of(priv, struct wiphy, priv); +} + +/** * set_wiphy_dev - set device pointer for wiphy * * @wiphy: The wiphy whose device to bind -- cgit v0.10.2 From 3daf097594d398b2ddd2dca6caeaa92cb9148e23 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:14 +0100 Subject: cfg80211: Advertise ciphers via WE according to driver capability Signed-off-by: David Kilroy Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 9e56f35..7dbe6c6 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -204,8 +204,19 @@ int cfg80211_wext_giwrange(struct net_device *dev, range->avg_qual.noise = range->max_qual.noise / 2; range->avg_qual.updated = range->max_qual.updated; - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2; + + for (c = 0; c < wdev->wiphy->n_cipher_suites; c++) { + switch (wdev->wiphy->cipher_suites[c]) { + case WLAN_CIPHER_SUITE_TKIP: + range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; + break; + + case WLAN_CIPHER_SUITE_CCMP: + range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; + break; + } + } for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { int i; -- cgit v0.10.2 From 51cd4aabd082144881644c308647ca501690b68c Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:15 +0100 Subject: cfg80211: allow drivers that can't scan for specific ssids Signed-off-by: David Kilroy Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index d585029..a98670c 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -346,9 +346,6 @@ int wiphy_register(struct wiphy *wiphy) int i; u16 ifmodes = wiphy->interface_modes; - if (WARN_ON(wiphy->max_scan_ssids < 1)) - return -EINVAL; - /* sanity check ifmodes */ WARN_ON(!ifmodes); ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 7dbe6c6..bb97061 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -247,7 +247,8 @@ int cfg80211_wext_giwrange(struct net_device *dev, IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); - range->scan_capa |= IW_SCAN_CAPA_ESSID; + if (wdev->wiphy->max_scan_ssids > 0) + range->scan_capa |= IW_SCAN_CAPA_ESSID; return 0; } -- cgit v0.10.2 From 2ab658f9ce218ae93b3d2db2b3fe68bfefb81196 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:16 +0100 Subject: cfg80211: set WE encoding size based on available ciphers Only set the sizes for WEP40 and WEP104. Signed-off-by: David Kilroy Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index bb97061..2f7e776 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -173,9 +173,6 @@ int cfg80211_wext_giwrange(struct net_device *dev, range->min_frag = 256; range->max_frag = 2346; - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; range->max_encoding_tokens = 4; range->max_qual.updated = IW_QUAL_NOISE_INVALID; @@ -215,6 +212,16 @@ int cfg80211_wext_giwrange(struct net_device *dev, case WLAN_CIPHER_SUITE_CCMP: range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; break; + + case WLAN_CIPHER_SUITE_WEP40: + range->encoding_size[range->num_encoding_sizes++] = + WLAN_KEY_LEN_WEP40; + break; + + case WLAN_CIPHER_SUITE_WEP104: + range->encoding_size[range->num_encoding_sizes++] = + WLAN_KEY_LEN_WEP104; + break; } } -- cgit v0.10.2 From 27bea66c22582853ad2e1de93d26c3016493818b Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:17 +0100 Subject: cfg80211: infer WPA and WPA2 support from TKIP and CCMP Signed-off-by: David Kilroy Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 2f7e776..cae3b52 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -201,16 +201,16 @@ int cfg80211_wext_giwrange(struct net_device *dev, range->avg_qual.noise = range->max_qual.noise / 2; range->avg_qual.updated = range->max_qual.updated; - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2; - for (c = 0; c < wdev->wiphy->n_cipher_suites; c++) { switch (wdev->wiphy->cipher_suites[c]) { case WLAN_CIPHER_SUITE_TKIP: - range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; + range->enc_capa |= (IW_ENC_CAPA_CIPHER_TKIP | + IW_ENC_CAPA_WPA); break; case WLAN_CIPHER_SUITE_CCMP: - range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; + range->enc_capa |= (IW_ENC_CAPA_CIPHER_CCMP | + IW_ENC_CAPA_WPA2); break; case WLAN_CIPHER_SUITE_WEP40: -- cgit v0.10.2 From a2d1a42a4b44c97fb83c5bf53af8cd6ab4c6c110 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:18 +0100 Subject: orinoco: Move firmware capability determination into hw.c This is part of refactorring the initialisation code so that we can load the firmware before registerring with netdev. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 632fac8..209c6be 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -13,6 +13,8 @@ #include "hw.h" +#define SYMBOL_MAX_VER_LEN (14) + /********************************************************************/ /* Data tables */ /********************************************************************/ @@ -36,6 +38,220 @@ static const struct { }; #define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) +/* Firmware version encoding */ +struct comp_id { + u16 id, variant, major, minor; +} __attribute__ ((packed)); + +static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) +{ + if (nic_id->id < 0x8000) + return FIRMWARE_TYPE_AGERE; + else if (nic_id->id == 0x8000 && nic_id->major == 0) + return FIRMWARE_TYPE_SYMBOL; + else + return FIRMWARE_TYPE_INTERSIL; +} + +/* Set priv->firmware type, determine firmware properties */ +int determine_fw_capabilities(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + hermes_t *hw = &priv->hw; + int err; + struct comp_id nic_id, sta_id; + unsigned int firmver; + char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2))); + + /* Get the hardware version */ + err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); + if (err) { + printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n", + dev->name, err); + return err; + } + + le16_to_cpus(&nic_id.id); + le16_to_cpus(&nic_id.variant); + le16_to_cpus(&nic_id.major); + le16_to_cpus(&nic_id.minor); + printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n", + dev->name, nic_id.id, nic_id.variant, + nic_id.major, nic_id.minor); + + priv->firmware_type = determine_firmware_type(&nic_id); + + /* Get the firmware version */ + err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); + if (err) { + printk(KERN_ERR "%s: Cannot read station identity: error %d\n", + dev->name, err); + return err; + } + + le16_to_cpus(&sta_id.id); + le16_to_cpus(&sta_id.variant); + le16_to_cpus(&sta_id.major); + le16_to_cpus(&sta_id.minor); + printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", + dev->name, sta_id.id, sta_id.variant, + sta_id.major, sta_id.minor); + + switch (sta_id.id) { + case 0x15: + printk(KERN_ERR "%s: Primary firmware is active\n", + dev->name); + return -ENODEV; + case 0x14b: + printk(KERN_ERR "%s: Tertiary firmware is active\n", + dev->name); + return -ENODEV; + case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ + case 0x21: /* Symbol Spectrum24 Trilogy */ + break; + default: + printk(KERN_NOTICE "%s: Unknown station ID, please report\n", + dev->name); + break; + } + + /* Default capabilities */ + priv->has_sensitivity = 1; + priv->has_mwo = 0; + priv->has_preamble = 0; + priv->has_port3 = 1; + priv->has_ibss = 1; + priv->has_wep = 0; + priv->has_big_wep = 0; + priv->has_alt_txcntl = 0; + priv->has_ext_scan = 0; + priv->has_wpa = 0; + priv->do_fw_download = 0; + + /* Determine capabilities from the firmware version */ + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, + ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor); + + firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; + + priv->has_ibss = (firmver >= 0x60006); + priv->has_wep = (firmver >= 0x40020); + priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell + Gold cards from the others? */ + priv->has_mwo = (firmver >= 0x60000); + priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ + priv->ibss_port = 1; + priv->has_hostscan = (firmver >= 0x8000a); + priv->do_fw_download = 1; + priv->broken_monitor = (firmver >= 0x80000); + priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ + priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ + priv->has_wpa = (firmver >= 0x9002a); + /* Tested with Agere firmware : + * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II + * Tested CableTron firmware : 4.32 => Anton */ + break; + case FIRMWARE_TYPE_SYMBOL: + /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ + /* Intel MAC : 00:02:B3:* */ + /* 3Com MAC : 00:50:DA:* */ + memset(tmp, 0, sizeof(tmp)); + /* Get the Symbol firmware version */ + err = hermes_read_ltv(hw, USER_BAP, + HERMES_RID_SECONDARYVERSION_SYMBOL, + SYMBOL_MAX_VER_LEN, NULL, &tmp); + if (err) { + printk(KERN_WARNING + "%s: Error %d reading Symbol firmware info. " + "Wildly guessing capabilities...\n", + dev->name, err); + firmver = 0; + tmp[0] = '\0'; + } else { + /* The firmware revision is a string, the format is + * something like : "V2.20-01". + * Quick and dirty parsing... - Jean II + */ + firmver = ((tmp[1] - '0') << 16) + | ((tmp[3] - '0') << 12) + | ((tmp[4] - '0') << 8) + | ((tmp[6] - '0') << 4) + | (tmp[7] - '0'); + + tmp[SYMBOL_MAX_VER_LEN] = '\0'; + } + + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Symbol %s", tmp); + + priv->has_ibss = (firmver >= 0x20000); + priv->has_wep = (firmver >= 0x15012); + priv->has_big_wep = (firmver >= 0x20000); + priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || + (firmver >= 0x29000 && firmver < 0x30000) || + firmver >= 0x31000; + priv->has_preamble = (firmver >= 0x20000); + priv->ibss_port = 4; + + /* Symbol firmware is found on various cards, but + * there has been no attempt to check firmware + * download on non-spectrum_cs based cards. + * + * Given that the Agere firmware download works + * differently, we should avoid doing a firmware + * download with the Symbol algorithm on non-spectrum + * cards. + * + * For now we can identify a spectrum_cs based card + * because it has a firmware reset function. + */ + priv->do_fw_download = (priv->stop_fw != NULL); + + priv->broken_disableport = (firmver == 0x25013) || + (firmver >= 0x30000 && firmver <= 0x31000); + priv->has_hostscan = (firmver >= 0x31001) || + (firmver >= 0x29057 && firmver < 0x30000); + /* Tested with Intel firmware : 0x20015 => Jean II */ + /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ + break; + case FIRMWARE_TYPE_INTERSIL: + /* D-Link, Linksys, Adtron, ZoomAir, and many others... + * Samsung, Compaq 100/200 and Proxim are slightly + * different and less well tested */ + /* D-Link MAC : 00:40:05:* */ + /* Addtron MAC : 00:90:D1:* */ + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Intersil %d.%d.%d", sta_id.major, sta_id.minor, + sta_id.variant); + + firmver = ((unsigned long)sta_id.major << 16) | + ((unsigned long)sta_id.minor << 8) | sta_id.variant; + + priv->has_ibss = (firmver >= 0x000700); /* FIXME */ + priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); + priv->has_pm = (firmver >= 0x000700); + priv->has_hostscan = (firmver >= 0x010301); + + if (firmver >= 0x000800) + priv->ibss_port = 0; + else { + printk(KERN_NOTICE "%s: Intersil firmware earlier " + "than v0.8.x - several features not supported\n", + dev->name); + priv->ibss_port = 1; + } + break; + } + printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name, + priv->fw_name); + + return 0; +} + int orinoco_get_bitratemode(int bitrate, int automatic) { int ratemode = -1; diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index dc3f23a..f7845b8 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -23,6 +23,7 @@ struct orinoco_private; struct dev_addr_list; +int determine_fw_capabilities(struct orinoco_private *priv); int orinoco_get_bitratemode(int bitrate, int automatic); void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 345593c..33326d6 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -142,7 +142,6 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; #define ORINOCO_MIN_MTU 256 #define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) -#define SYMBOL_MAX_VER_LEN (14) #define MAX_IRQLOOPS_PER_IRQ 10 #define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of * how many events the @@ -2096,219 +2095,6 @@ static void orinoco_unregister_pm_notifier(struct orinoco_private *priv) /* Initialization */ /********************************************************************/ -struct comp_id { - u16 id, variant, major, minor; -} __attribute__ ((packed)); - -static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) -{ - if (nic_id->id < 0x8000) - return FIRMWARE_TYPE_AGERE; - else if (nic_id->id == 0x8000 && nic_id->major == 0) - return FIRMWARE_TYPE_SYMBOL; - else - return FIRMWARE_TYPE_INTERSIL; -} - -/* Set priv->firmware type, determine firmware properties */ -static int determine_firmware(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int err; - struct comp_id nic_id, sta_id; - unsigned int firmver; - char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2))); - - /* Get the hardware version */ - err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); - if (err) { - printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n", - dev->name, err); - return err; - } - - le16_to_cpus(&nic_id.id); - le16_to_cpus(&nic_id.variant); - le16_to_cpus(&nic_id.major); - le16_to_cpus(&nic_id.minor); - printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n", - dev->name, nic_id.id, nic_id.variant, - nic_id.major, nic_id.minor); - - priv->firmware_type = determine_firmware_type(&nic_id); - - /* Get the firmware version */ - err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); - if (err) { - printk(KERN_ERR "%s: Cannot read station identity: error %d\n", - dev->name, err); - return err; - } - - le16_to_cpus(&sta_id.id); - le16_to_cpus(&sta_id.variant); - le16_to_cpus(&sta_id.major); - le16_to_cpus(&sta_id.minor); - printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", - dev->name, sta_id.id, sta_id.variant, - sta_id.major, sta_id.minor); - - switch (sta_id.id) { - case 0x15: - printk(KERN_ERR "%s: Primary firmware is active\n", - dev->name); - return -ENODEV; - case 0x14b: - printk(KERN_ERR "%s: Tertiary firmware is active\n", - dev->name); - return -ENODEV; - case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ - case 0x21: /* Symbol Spectrum24 Trilogy */ - break; - default: - printk(KERN_NOTICE "%s: Unknown station ID, please report\n", - dev->name); - break; - } - - /* Default capabilities */ - priv->has_sensitivity = 1; - priv->has_mwo = 0; - priv->has_preamble = 0; - priv->has_port3 = 1; - priv->has_ibss = 1; - priv->has_wep = 0; - priv->has_big_wep = 0; - priv->has_alt_txcntl = 0; - priv->has_ext_scan = 0; - priv->has_wpa = 0; - priv->do_fw_download = 0; - - /* Determine capabilities from the firmware version */ - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, - ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor); - - firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; - - priv->has_ibss = (firmver >= 0x60006); - priv->has_wep = (firmver >= 0x40020); - priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell - Gold cards from the others? */ - priv->has_mwo = (firmver >= 0x60000); - priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ - priv->ibss_port = 1; - priv->has_hostscan = (firmver >= 0x8000a); - priv->do_fw_download = 1; - priv->broken_monitor = (firmver >= 0x80000); - priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_wpa = (firmver >= 0x9002a); - /* Tested with Agere firmware : - * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II - * Tested CableTron firmware : 4.32 => Anton */ - break; - case FIRMWARE_TYPE_SYMBOL: - /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ - /* Intel MAC : 00:02:B3:* */ - /* 3Com MAC : 00:50:DA:* */ - memset(tmp, 0, sizeof(tmp)); - /* Get the Symbol firmware version */ - err = hermes_read_ltv(hw, USER_BAP, - HERMES_RID_SECONDARYVERSION_SYMBOL, - SYMBOL_MAX_VER_LEN, NULL, &tmp); - if (err) { - printk(KERN_WARNING - "%s: Error %d reading Symbol firmware info. " - "Wildly guessing capabilities...\n", - dev->name, err); - firmver = 0; - tmp[0] = '\0'; - } else { - /* The firmware revision is a string, the format is - * something like : "V2.20-01". - * Quick and dirty parsing... - Jean II - */ - firmver = ((tmp[1] - '0') << 16) - | ((tmp[3] - '0') << 12) - | ((tmp[4] - '0') << 8) - | ((tmp[6] - '0') << 4) - | (tmp[7] - '0'); - - tmp[SYMBOL_MAX_VER_LEN] = '\0'; - } - - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Symbol %s", tmp); - - priv->has_ibss = (firmver >= 0x20000); - priv->has_wep = (firmver >= 0x15012); - priv->has_big_wep = (firmver >= 0x20000); - priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || - (firmver >= 0x29000 && firmver < 0x30000) || - firmver >= 0x31000; - priv->has_preamble = (firmver >= 0x20000); - priv->ibss_port = 4; - - /* Symbol firmware is found on various cards, but - * there has been no attempt to check firmware - * download on non-spectrum_cs based cards. - * - * Given that the Agere firmware download works - * differently, we should avoid doing a firmware - * download with the Symbol algorithm on non-spectrum - * cards. - * - * For now we can identify a spectrum_cs based card - * because it has a firmware reset function. - */ - priv->do_fw_download = (priv->stop_fw != NULL); - - priv->broken_disableport = (firmver == 0x25013) || - (firmver >= 0x30000 && firmver <= 0x31000); - priv->has_hostscan = (firmver >= 0x31001) || - (firmver >= 0x29057 && firmver < 0x30000); - /* Tested with Intel firmware : 0x20015 => Jean II */ - /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ - break; - case FIRMWARE_TYPE_INTERSIL: - /* D-Link, Linksys, Adtron, ZoomAir, and many others... - * Samsung, Compaq 100/200 and Proxim are slightly - * different and less well tested */ - /* D-Link MAC : 00:40:05:* */ - /* Addtron MAC : 00:90:D1:* */ - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Intersil %d.%d.%d", sta_id.major, sta_id.minor, - sta_id.variant); - - firmver = ((unsigned long)sta_id.major << 16) | - ((unsigned long)sta_id.minor << 8) | sta_id.variant; - - priv->has_ibss = (firmver >= 0x000700); /* FIXME */ - priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); - priv->has_pm = (firmver >= 0x000700); - priv->has_hostscan = (firmver >= 0x010301); - - if (firmver >= 0x000800) - priv->ibss_port = 0; - else { - printk(KERN_NOTICE "%s: Intersil firmware earlier " - "than v0.8.x - several features not supported\n", - dev->name); - priv->ibss_port = 1; - } - break; - } - printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name, - priv->fw_name); - - return 0; -} - static int orinoco_init(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); @@ -2330,7 +2116,7 @@ static int orinoco_init(struct net_device *dev) goto out; } - err = determine_firmware(dev); + err = determine_fw_capabilities(priv); if (err != 0) { printk(KERN_ERR "%s: Incompatible firmware, aborting\n", dev->name); @@ -2347,7 +2133,7 @@ static int orinoco_init(struct net_device *dev) priv->do_fw_download = 0; /* Check firmware version again */ - err = determine_firmware(dev); + err = determine_fw_capabilities(priv); if (err != 0) { printk(KERN_ERR "%s: Incompatible firmware, aborting\n", dev->name); -- cgit v0.10.2 From e9e3d0100eae5f254024bd59229ef1be2b719b84 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:19 +0100 Subject: orinoco: Move card reading code into hw.c This is part of refactorring the initialisation code so that we can load the firmware before registerring with netdev. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 209c6be..40dc25c 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -252,6 +252,118 @@ int determine_fw_capabilities(struct orinoco_private *priv) return 0; } +/* Read settings from EEPROM into our private structure. + * MAC address gets dropped into callers buffer */ +int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) +{ + struct net_device *dev = priv->ndev; + struct hermes_idstring nickbuf; + hermes_t *hw = &priv->hw; + int len; + int err; + u16 reclen; + + /* Get the MAC address */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, + ETH_ALEN, NULL, dev_addr); + if (err) { + printk(KERN_WARNING "%s: failed to read MAC address!\n", + dev->name); + goto out; + } + + printk(KERN_DEBUG "%s: MAC address %pM\n", + dev->name, dev_addr); + + /* Get the station name */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, + sizeof(nickbuf), &reclen, &nickbuf); + if (err) { + printk(KERN_ERR "%s: failed to read station name\n", + dev->name); + goto out; + } + if (nickbuf.len) + len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); + else + len = min(IW_ESSID_MAX_SIZE, 2 * reclen); + memcpy(priv->nick, &nickbuf.val, len); + priv->nick[len] = '\0'; + + printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); + + /* Get allowed channels */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, + &priv->channel_mask); + if (err) { + printk(KERN_ERR "%s: failed to read channel list!\n", + dev->name); + goto out; + } + + /* Get initial AP density */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, + &priv->ap_density); + if (err || priv->ap_density < 1 || priv->ap_density > 3) + priv->has_sensitivity = 0; + + /* Get initial RTS threshold */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, + &priv->rts_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read RTS threshold!\n", + dev->name); + goto out; + } + + /* Get initial fragmentation settings */ + if (priv->has_mwo) + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, + &priv->mwo_robust); + else + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + &priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read fragmentation settings!\n", + dev->name); + goto out; + } + + /* Power management setup */ + if (priv->has_pm) { + priv->pm_on = 0; + priv->pm_mcast = 1; + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, + &priv->pm_period); + if (err) { + printk(KERN_ERR "%s: failed to read power management " + "period!\n", dev->name); + goto out; + } + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMHOLDOVERDURATION, + &priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: failed to read power management " + "timeout!\n", dev->name); + goto out; + } + } + + /* Preamble setup */ + if (priv->has_preamble) { + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFPREAMBLE_SYMBOL, + &priv->preamble); + } + +out: + return err; +} + int orinoco_get_bitratemode(int bitrate, int automatic) { int ratemode = -1; diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index f7845b8..6186e44 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -24,6 +24,7 @@ struct orinoco_private; struct dev_addr_list; int determine_fw_capabilities(struct orinoco_private *priv); +int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr); int orinoco_get_bitratemode(int bitrate, int automatic); void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 33326d6..0fe9420 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -2100,9 +2100,6 @@ static int orinoco_init(struct net_device *dev) struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; - struct hermes_idstring nickbuf; - u16 reclen; - int len; /* No need to lock, the hw_unavailable flag is already set in * alloc_orinocodev() */ @@ -2166,34 +2163,9 @@ static int orinoco_init(struct net_device *dev) goto out; orinoco_bss_data_init(priv); - /* Get the MAC address */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - ETH_ALEN, NULL, dev->dev_addr); - if (err) { - printk(KERN_WARNING "%s: failed to read MAC address!\n", - dev->name); - goto out; - } - - printk(KERN_DEBUG "%s: MAC address %pM\n", - dev->name, dev->dev_addr); - - /* Get the station name */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - sizeof(nickbuf), &reclen, &nickbuf); - if (err) { - printk(KERN_ERR "%s: failed to read station name\n", - dev->name); + err = orinoco_hw_read_card_settings(priv, dev->dev_addr); + if (err) goto out; - } - if (nickbuf.len) - len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); - else - len = min(IW_ESSID_MAX_SIZE, 2 * reclen); - memcpy(priv->nick, &nickbuf.val, len); - priv->nick[len] = '\0'; - - printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); err = orinoco_allocate_fid(dev); if (err) { @@ -2202,76 +2174,6 @@ static int orinoco_init(struct net_device *dev) goto out; } - /* Get allowed channels */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, - &priv->channel_mask); - if (err) { - printk(KERN_ERR "%s: failed to read channel list!\n", - dev->name); - goto out; - } - - /* Get initial AP density */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, - &priv->ap_density); - if (err || priv->ap_density < 1 || priv->ap_density > 3) - priv->has_sensitivity = 0; - - /* Get initial RTS threshold */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - &priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: failed to read RTS threshold!\n", - dev->name); - goto out; - } - - /* Get initial fragmentation settings */ - if (priv->has_mwo) - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - &priv->mwo_robust); - else - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - &priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: failed to read fragmentation settings!\n", - dev->name); - goto out; - } - - /* Power management setup */ - if (priv->has_pm) { - priv->pm_on = 0; - priv->pm_mcast = 1; - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - &priv->pm_period); - if (err) { - printk(KERN_ERR "%s: failed to read power management period!\n", - dev->name); - goto out; - } - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - &priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: failed to read power management timeout!\n", - dev->name); - goto out; - } - } - - /* Preamble setup */ - if (priv->has_preamble) { - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - &priv->preamble); - if (err) - goto out; - } - /* Set up the default configuration */ priv->iw_mode = IW_MODE_INFRA; /* By default use IEEE/IBSS ad-hoc mode if we have it */ -- cgit v0.10.2 From 42a51b933034bbed93fa54009c96a482044e5b43 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:20 +0100 Subject: orinoco: Move FID allocation to hw.c This is part of refactorring the initialisation code so that we can load the firmware before registerring with netdev. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 40dc25c..0f6426d 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -15,6 +15,9 @@ #define SYMBOL_MAX_VER_LEN (14) +/* Symbol firmware has a bug allocating buffers larger than this */ +#define TX_NICBUF_SIZE_BUG 1585 + /********************************************************************/ /* Data tables */ /********************************************************************/ @@ -364,6 +367,26 @@ out: return err; } +int orinoco_hw_allocate_fid(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + struct hermes *hw = &priv->hw; + int err; + + err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); + if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) { + /* Try workaround for old Symbol firmware bug */ + priv->nicbuf_size = TX_NICBUF_SIZE_BUG; + err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); + + printk(KERN_WARNING "%s: firmware ALLOC bug detected " + "(old Symbol firmware?). Work around %s\n", + dev->name, err ? "failed!" : "ok."); + } + + return err; +} + int orinoco_get_bitratemode(int bitrate, int automatic) { int ratemode = -1; diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 6186e44..89277de 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -25,6 +25,7 @@ struct dev_addr_list; int determine_fw_capabilities(struct orinoco_private *priv); int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr); +int orinoco_hw_allocate_fid(struct orinoco_private *priv); int orinoco_get_bitratemode(int bitrate, int automatic); void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 0fe9420..58a48db 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -147,7 +147,6 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; * how many events the * device could * legitimately generate */ -#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ #define DUMMY_FID 0xFFFF @@ -1574,26 +1573,6 @@ int __orinoco_down(struct net_device *dev) } EXPORT_SYMBOL(__orinoco_down); -static int orinoco_allocate_fid(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - - err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); - if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) { - /* Try workaround for old Symbol firmware bug */ - priv->nicbuf_size = TX_NICBUF_SIZE_BUG; - err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); - - printk(KERN_WARNING "%s: firmware ALLOC bug detected " - "(old Symbol firmware?). Work around %s\n", - dev->name, err ? "failed!" : "ok."); - } - - return err; -} - int orinoco_reinit_firmware(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); @@ -1607,7 +1586,7 @@ int orinoco_reinit_firmware(struct net_device *dev) priv->do_fw_download = 0; } if (!err) - err = orinoco_allocate_fid(dev); + err = orinoco_hw_allocate_fid(priv); return err; } @@ -2167,7 +2146,7 @@ static int orinoco_init(struct net_device *dev) if (err) goto out; - err = orinoco_allocate_fid(dev); + err = orinoco_hw_allocate_fid(priv); if (err) { printk(KERN_ERR "%s: failed to allocate NIC buffer!\n", dev->name); -- cgit v0.10.2 From a3f47b9c2ada45ffacc8f2b54507221a1ba8eb10 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:21 +0100 Subject: orinoco: use dev_err in early initialisation routines This allows us to use determine_fw_capabilities, orinoco_hw_read_card_setting and orinoco_hw_allocate_fid prior to netdev registration. Since dev_dbg only prints if DEBUG is defined (or dynamic debug is enabled), move a couple of the more useful prints up to info. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 0f6426d..4a26d68 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -3,6 +3,7 @@ * See copyright notice in main.c */ #include +#include #include #include #include @@ -56,10 +57,13 @@ static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) return FIRMWARE_TYPE_INTERSIL; } -/* Set priv->firmware type, determine firmware properties */ +/* Set priv->firmware type, determine firmware properties + * This function can be called before we have registerred with netdev, + * so all errors go out with dev_* rather than printk + */ int determine_fw_capabilities(struct orinoco_private *priv) { - struct net_device *dev = priv->ndev; + struct device *dev = priv->dev; hermes_t *hw = &priv->hw; int err; struct comp_id nic_id, sta_id; @@ -69,8 +73,8 @@ int determine_fw_capabilities(struct orinoco_private *priv) /* Get the hardware version */ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); if (err) { - printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n", - dev->name, err); + dev_err(dev, "Cannot read hardware identity: error %d\n", + err); return err; } @@ -78,17 +82,16 @@ int determine_fw_capabilities(struct orinoco_private *priv) le16_to_cpus(&nic_id.variant); le16_to_cpus(&nic_id.major); le16_to_cpus(&nic_id.minor); - printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n", - dev->name, nic_id.id, nic_id.variant, - nic_id.major, nic_id.minor); + dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n", + nic_id.id, nic_id.variant, nic_id.major, nic_id.minor); priv->firmware_type = determine_firmware_type(&nic_id); /* Get the firmware version */ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); if (err) { - printk(KERN_ERR "%s: Cannot read station identity: error %d\n", - dev->name, err); + dev_err(dev, "Cannot read station identity: error %d\n", + err); return err; } @@ -96,25 +99,21 @@ int determine_fw_capabilities(struct orinoco_private *priv) le16_to_cpus(&sta_id.variant); le16_to_cpus(&sta_id.major); le16_to_cpus(&sta_id.minor); - printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", - dev->name, sta_id.id, sta_id.variant, - sta_id.major, sta_id.minor); + dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n", + sta_id.id, sta_id.variant, sta_id.major, sta_id.minor); switch (sta_id.id) { case 0x15: - printk(KERN_ERR "%s: Primary firmware is active\n", - dev->name); + dev_err(dev, "Primary firmware is active\n"); return -ENODEV; case 0x14b: - printk(KERN_ERR "%s: Tertiary firmware is active\n", - dev->name); + dev_err(dev, "Tertiary firmware is active\n"); return -ENODEV; case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ case 0x21: /* Symbol Spectrum24 Trilogy */ break; default: - printk(KERN_NOTICE "%s: Unknown station ID, please report\n", - dev->name); + dev_notice(dev, "Unknown station ID, please report\n"); break; } @@ -168,10 +167,8 @@ int determine_fw_capabilities(struct orinoco_private *priv) HERMES_RID_SECONDARYVERSION_SYMBOL, SYMBOL_MAX_VER_LEN, NULL, &tmp); if (err) { - printk(KERN_WARNING - "%s: Error %d reading Symbol firmware info. " - "Wildly guessing capabilities...\n", - dev->name, err); + dev_warn(dev, "Error %d reading Symbol firmware info. " + "Wildly guessing capabilities...\n", err); firmver = 0; tmp[0] = '\0'; } else { @@ -242,24 +239,24 @@ int determine_fw_capabilities(struct orinoco_private *priv) if (firmver >= 0x000800) priv->ibss_port = 0; else { - printk(KERN_NOTICE "%s: Intersil firmware earlier " - "than v0.8.x - several features not supported\n", - dev->name); + dev_notice(dev, "Intersil firmware earlier than v0.8.x" + " - several features not supported\n"); priv->ibss_port = 1; } break; } - printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name, - priv->fw_name); + dev_info(dev, "Firmware determined as %s\n", priv->fw_name); return 0; } /* Read settings from EEPROM into our private structure. - * MAC address gets dropped into callers buffer */ + * MAC address gets dropped into callers buffer + * Can be called before netdev registration. + */ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) { - struct net_device *dev = priv->ndev; + struct device *dev = priv->dev; struct hermes_idstring nickbuf; hermes_t *hw = &priv->hw; int len; @@ -270,20 +267,17 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, ETH_ALEN, NULL, dev_addr); if (err) { - printk(KERN_WARNING "%s: failed to read MAC address!\n", - dev->name); + dev_warn(dev, "Failed to read MAC address!\n"); goto out; } - printk(KERN_DEBUG "%s: MAC address %pM\n", - dev->name, dev_addr); + dev_dbg(dev, "MAC address %pM\n", dev_addr); /* Get the station name */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, sizeof(nickbuf), &reclen, &nickbuf); if (err) { - printk(KERN_ERR "%s: failed to read station name\n", - dev->name); + dev_err(dev, "failed to read station name\n"); goto out; } if (nickbuf.len) @@ -293,14 +287,13 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) memcpy(priv->nick, &nickbuf.val, len); priv->nick[len] = '\0'; - printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); + dev_dbg(dev, "Station name \"%s\"\n", priv->nick); /* Get allowed channels */ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, &priv->channel_mask); if (err) { - printk(KERN_ERR "%s: failed to read channel list!\n", - dev->name); + dev_err(dev, "Failed to read channel list!\n"); goto out; } @@ -314,8 +307,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, &priv->rts_thresh); if (err) { - printk(KERN_ERR "%s: failed to read RTS threshold!\n", - dev->name); + dev_err(dev, "Failed to read RTS threshold!\n"); goto out; } @@ -329,8 +321,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, &priv->frag_thresh); if (err) { - printk(KERN_ERR "%s: failed to read fragmentation settings!\n", - dev->name); + dev_err(dev, "Failed to read fragmentation settings!\n"); goto out; } @@ -342,16 +333,16 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) HERMES_RID_CNFMAXSLEEPDURATION, &priv->pm_period); if (err) { - printk(KERN_ERR "%s: failed to read power management " - "period!\n", dev->name); + dev_err(dev, "Failed to read power management " + "period!\n"); goto out; } err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &priv->pm_timeout); if (err) { - printk(KERN_ERR "%s: failed to read power management " - "timeout!\n", dev->name); + dev_err(dev, "Failed to read power management " + "timeout!\n"); goto out; } } @@ -367,9 +358,10 @@ out: return err; } +/* Can be called before netdev registration */ int orinoco_hw_allocate_fid(struct orinoco_private *priv) { - struct net_device *dev = priv->ndev; + struct device *dev = priv->dev; struct hermes *hw = &priv->hw; int err; @@ -379,9 +371,9 @@ int orinoco_hw_allocate_fid(struct orinoco_private *priv) priv->nicbuf_size = TX_NICBUF_SIZE_BUG; err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); - printk(KERN_WARNING "%s: firmware ALLOC bug detected " - "(old Symbol firmware?). Work around %s\n", - dev->name, err ? "failed!" : "ok."); + dev_warn(dev, "Firmware ALLOC bug detected " + "(old Symbol firmware?). Work around %s\n", + err ? "failed!" : "ok."); } return err; -- cgit v0.10.2 From 44d8dade8f12ffe5c9b7eddd0512c1548c027a4c Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:22 +0100 Subject: orinoco: firmware helpers should use dev_err and friends We should be able to call these routines before we register with netdev, so avoid printks using the netdev name. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c index 1084b43..1257250 100644 --- a/drivers/net/wireless/orinoco/fw.c +++ b/drivers/net/wireless/orinoco/fw.c @@ -4,6 +4,7 @@ */ #include #include +#include #include "hermes.h" #include "hermes_dld.h" @@ -99,7 +100,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, const void *end; const char *firmware; const char *fw_err; - struct net_device *dev = priv->ndev; + struct device *dev = priv->dev; int err = 0; pda = kzalloc(fw->pda_size, GFP_KERNEL); @@ -111,12 +112,11 @@ orinoco_dl_firmware(struct orinoco_private *priv, else firmware = fw->sta_fw; - printk(KERN_DEBUG "%s: Attempting to download firmware %s\n", - dev->name, firmware); + dev_dbg(dev, "Attempting to download firmware %s\n", firmware); /* Read current plug data */ err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0); - printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); + dev_dbg(dev, "Read PDA returned %d\n", err); if (err) goto free; @@ -124,8 +124,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, err = request_firmware(&fw_entry, firmware, priv->dev); if (err) { - printk(KERN_ERR "%s: Cannot find firmware %s\n", - dev->name, firmware); + dev_err(dev, "Cannot find firmware %s\n", firmware); err = -ENOENT; goto free; } @@ -136,16 +135,15 @@ orinoco_dl_firmware(struct orinoco_private *priv, fw_err = validate_fw(hdr, fw_entry->size); if (fw_err) { - printk(KERN_WARNING "%s: Invalid firmware image detected (%s). " - "Aborting download\n", - dev->name, fw_err); + dev_warn(dev, "Invalid firmware image detected (%s). " + "Aborting download\n", fw_err); err = -EINVAL; goto abort; } /* Enable aux port to allow programming */ err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); - printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err); + dev_dbg(dev, "Program init returned %d\n", err); if (err != 0) goto abort; @@ -156,7 +154,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, end = fw_entry->data + fw_entry->size; err = hermes_program(hw, first_block, end); - printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err); + dev_dbg(dev, "Program returned %d\n", err); if (err != 0) goto abort; @@ -167,19 +165,18 @@ orinoco_dl_firmware(struct orinoco_private *priv, err = hermes_apply_pda_with_defaults(hw, first_block, end, pda, &pda[fw->pda_size / sizeof(*pda)]); - printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); + dev_dbg(dev, "Apply PDA returned %d\n", err); if (err) goto abort; /* Tell card we've finished */ err = hermesi_program_end(hw); - printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err); + dev_dbg(dev, "Program end returned %d\n", err); if (err != 0) goto abort; /* Check if we're running */ - printk(KERN_DEBUG "%s: hermes_present returned %d\n", - dev->name, hermes_present(hw)); + dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw)); abort: /* If we requested the firmware, release it. */ @@ -282,14 +279,13 @@ static int symbol_dl_firmware(struct orinoco_private *priv, const struct fw_info *fw) { - struct net_device *dev = priv->ndev; + struct device *dev = priv->dev; int ret; const struct firmware *fw_entry; if (!orinoco_cached_fw_get(priv, true)) { if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->pri_fw); + dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw); return -ENOENT; } } else @@ -302,15 +298,13 @@ symbol_dl_firmware(struct orinoco_private *priv, if (!orinoco_cached_fw_get(priv, true)) release_firmware(fw_entry); if (ret) { - printk(KERN_ERR "%s: Primary firmware download failed\n", - dev->name); + dev_err(dev, "Primary firmware download failed\n"); return ret; } if (!orinoco_cached_fw_get(priv, false)) { if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->sta_fw); + dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw); return -ENOENT; } } else @@ -322,8 +316,7 @@ symbol_dl_firmware(struct orinoco_private *priv, if (!orinoco_cached_fw_get(priv, false)) release_firmware(fw_entry); if (ret) { - printk(KERN_ERR "%s: Secondary firmware download failed\n", - dev->name); + dev_err(dev, "Secondary firmware download failed\n"); } return ret; -- cgit v0.10.2 From a2608362b22ade22ef5472a8c9b82687d86f976f Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:23 +0100 Subject: orinoco: Replace net_device with orinoco_private in driver interfaces Move away from using net_device as the main structure in orinoco function calls. Use orinoco_private instead. This makes more sense when we move to cfg80211, and we get wiphys as well. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index 8c4065f..6559aee 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -34,8 +34,8 @@ struct airport { static int airport_suspend(struct macio_dev *mdev, pm_message_t state) { - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); + struct net_device *dev = priv->ndev; unsigned long flags; int err; @@ -48,7 +48,7 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state) return 0; } - err = __orinoco_down(dev); + err = __orinoco_down(priv); if (err) printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n", dev->name, err); @@ -69,8 +69,8 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state) static int airport_resume(struct macio_dev *mdev) { - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); + struct net_device *dev = priv->ndev; unsigned long flags; int err; @@ -82,7 +82,7 @@ airport_resume(struct macio_dev *mdev) enable_irq(dev->irq); - err = orinoco_reinit_firmware(dev); + err = orinoco_reinit_firmware(priv); if (err) { printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n", dev->name, err); @@ -96,7 +96,7 @@ airport_resume(struct macio_dev *mdev) priv->hw_unavailable--; if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (err) printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n", dev->name, err); @@ -111,8 +111,8 @@ airport_resume(struct macio_dev *mdev) static int airport_detach(struct macio_dev *mdev) { - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); + struct net_device *dev = priv->ndev; struct airport *card = priv->card; if (card->ndev_registered) @@ -120,7 +120,7 @@ airport_detach(struct macio_dev *mdev) card->ndev_registered = 0; if (card->irq_requested) - free_irq(dev->irq, dev); + free_irq(dev->irq, priv); card->irq_requested = 0; if (card->vaddr) @@ -134,7 +134,7 @@ airport_detach(struct macio_dev *mdev) ssleep(1); macio_set_drvdata(mdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); return 0; } @@ -185,13 +185,13 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) } /* Allocate space for private device-specific data */ - dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, - airport_hard_reset, NULL); - if (!dev) { + priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, + airport_hard_reset, NULL); + if (!priv) { printk(KERN_ERR PFX "Cannot allocate network device\n"); return -ENODEV; } - priv = netdev_priv(dev); + dev = priv->ndev; card = priv->card; hw = &priv->hw; @@ -199,13 +199,13 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) if (macio_request_resource(mdev, 0, "airport")) { printk(KERN_ERR PFX "can't request IO resource !\n"); - free_orinocodev(dev); + free_orinocodev(priv); return -EBUSY; } SET_NETDEV_DEV(dev, &mdev->ofdev.dev); - macio_set_drvdata(mdev, dev); + macio_set_drvdata(mdev, priv); /* Setup interrupts & base address */ dev->irq = macio_irq(mdev, 0); @@ -228,7 +228,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) /* Reset it before we get the interrupt */ hermes_init(hw); - if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) { + if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, priv)) { printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq); goto failed; } diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 58a48db..4fa8264 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -252,7 +252,7 @@ static int orinoco_open(struct net_device *dev) if (orinoco_lock(priv, &flags) != 0) return -EBUSY; - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (!err) priv->open = 1; @@ -274,7 +274,7 @@ static int orinoco_stop(struct net_device *dev) priv->open = 0; - err = __orinoco_down(dev); + err = __orinoco_down(priv); spin_unlock_irq(&priv->lock); @@ -1511,9 +1511,9 @@ static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) /* Internal hardware control routines */ /********************************************************************/ -int __orinoco_up(struct net_device *dev) +int __orinoco_up(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); + struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; int err; @@ -1541,9 +1541,9 @@ int __orinoco_up(struct net_device *dev) } EXPORT_SYMBOL(__orinoco_up); -int __orinoco_down(struct net_device *dev) +int __orinoco_down(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); + struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; int err; @@ -1573,9 +1573,8 @@ int __orinoco_down(struct net_device *dev) } EXPORT_SYMBOL(__orinoco_down); -int orinoco_reinit_firmware(struct net_device *dev) +int orinoco_reinit_firmware(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; int err; @@ -1887,7 +1886,7 @@ void orinoco_reset(struct work_struct *work) } } - err = orinoco_reinit_firmware(dev); + err = orinoco_reinit_firmware(priv); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", dev->name, err); @@ -1902,7 +1901,7 @@ void orinoco_reset(struct work_struct *work) /* priv->open or priv->hw_unavailable might have changed while * we dropped the lock */ if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", dev->name, err); @@ -1938,8 +1937,8 @@ static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) irqreturn_t orinoco_interrupt(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = dev_id; + struct net_device *dev = priv->ndev; hermes_t *hw = &priv->hw; int count = MAX_IRQLOOPS_PER_IRQ; u16 evstat, events; @@ -2192,7 +2191,7 @@ static const struct net_device_ops orinoco_netdev_ops = { .ndo_get_stats = orinoco_get_stats, }; -struct net_device +struct orinoco_private *alloc_orinocodev(int sizeof_card, struct device *device, int (*hard_reset)(struct orinoco_private *), @@ -2255,13 +2254,13 @@ struct net_device /* Register PM notifiers */ orinoco_register_pm_notifier(priv); - return dev; + return priv; } EXPORT_SYMBOL(alloc_orinocodev); -void free_orinocodev(struct net_device *dev) +void free_orinocodev(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); + struct net_device *dev = priv->ndev; struct orinoco_rx_data *rx_data, *temp; /* If the tasklet is scheduled when we call tasklet_kill it diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 8e5a72c..b93e86c 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -182,14 +182,14 @@ extern int orinoco_debug; /* Exported prototypes */ /********************************************************************/ -extern struct net_device *alloc_orinocodev( +extern struct orinoco_private *alloc_orinocodev( int sizeof_card, struct device *device, int (*hard_reset)(struct orinoco_private *), int (*stop_fw)(struct orinoco_private *, int)); -extern void free_orinocodev(struct net_device *dev); -extern int __orinoco_up(struct net_device *dev); -extern int __orinoco_down(struct net_device *dev); -extern int orinoco_reinit_firmware(struct net_device *dev); +extern void free_orinocodev(struct orinoco_private *priv); +extern int __orinoco_up(struct orinoco_private *priv); +extern int __orinoco_down(struct orinoco_private *priv); +extern int orinoco_reinit_firmware(struct orinoco_private *priv); extern irqreturn_t orinoco_interrupt(int irq, void *dev_id); /********************************************************************/ diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index b381aed..fa8fe5b 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -106,26 +106,24 @@ orinoco_cs_hard_reset(struct orinoco_private *priv) static int orinoco_cs_probe(struct pcmcia_device *link) { - struct net_device *dev; struct orinoco_private *priv; struct orinoco_pccard *card; - dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), - orinoco_cs_hard_reset, NULL); - if (!dev) + priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + orinoco_cs_hard_reset, NULL); + if (!priv) return -ENOMEM; - priv = netdev_priv(dev); card = priv->card; /* Link both structures together */ card->p_dev = link; - link->priv = dev; + link->priv = priv; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = orinoco_interrupt; - link->irq.Instance = dev; + link->irq.Instance = priv; /* General socket configuration defaults can go here. In this * client, we assume very little, and rely on the CIS for @@ -146,14 +144,14 @@ orinoco_cs_probe(struct pcmcia_device *link) */ static void orinoco_cs_detach(struct pcmcia_device *link) { - struct net_device *dev = link->priv; + struct orinoco_private *priv = link->priv; if (link->dev_node) - unregister_netdev(dev); + unregister_netdev(priv->ndev); orinoco_cs_release(link); - free_orinocodev(dev); + free_orinocodev(priv); } /* orinoco_cs_detach */ /* @@ -239,9 +237,9 @@ next_entry: static int orinoco_cs_config(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; + struct net_device *dev = priv->ndev; hermes_t *hw = &priv->hw; int last_fn, last_ret; void __iomem *mem; @@ -336,8 +334,7 @@ orinoco_cs_config(struct pcmcia_device *link) static void orinoco_cs_release(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; unsigned long flags; /* We're committed to taking the device away now, so mark the @@ -353,9 +350,9 @@ orinoco_cs_release(struct pcmcia_device *link) static int orinoco_cs_suspend(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; + struct net_device *dev = priv->ndev; int err = 0; unsigned long flags; @@ -365,7 +362,7 @@ static int orinoco_cs_suspend(struct pcmcia_device *link) if (!test_bit(0, &card->hard_reset_in_progress)) { spin_lock_irqsave(&priv->lock, flags); - err = __orinoco_down(dev); + err = __orinoco_down(priv); if (err) printk(KERN_WARNING "%s: Error %d downing interface\n", dev->name, err); @@ -381,14 +378,14 @@ static int orinoco_cs_suspend(struct pcmcia_device *link) static int orinoco_cs_resume(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; + struct net_device *dev = priv->ndev; int err = 0; unsigned long flags; if (!test_bit(0, &card->hard_reset_in_progress)) { - err = orinoco_reinit_firmware(dev); + err = orinoco_reinit_firmware(priv); if (err) { printk(KERN_ERR "%s: Error %d re-initializing firmware\n", dev->name, err); @@ -401,7 +398,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link) priv->hw_unavailable--; if (priv->open && !priv->hw_unavailable) { - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (err) printk(KERN_ERR "%s: Error %d restarting card\n", dev->name, err); diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c index b017262..4efd5a0 100644 --- a/drivers/net/wireless/orinoco/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c @@ -181,15 +181,15 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_nortel_cor_reset, NULL); - if (!dev) { + priv = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_nortel_cor_reset, NULL); + if (!priv) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; goto fail_alloc; } - priv = netdev_priv(dev); + dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; @@ -198,7 +198,7 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); + dev->name, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -223,18 +223,18 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, goto fail; } - pci_set_drvdata(pdev, dev); + pci_set_drvdata(pdev, priv); printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, pci_name(pdev)); return 0; fail: - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); fail_irq: pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); fail_alloc: pci_iounmap(pdev, hermes_io); @@ -256,17 +256,17 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; /* Clear LEDs */ iowrite16(0, card->bridge_io + 10); unregister_netdev(dev); - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); pci_iounmap(pdev, priv->hw.iobase); pci_iounmap(pdev, card->attr_io); pci_iounmap(pdev, card->bridge_io); diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index 78cafff..12b9c6a 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -139,22 +139,22 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_pci_cor_reset, NULL); - if (!dev) { + priv = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_pci_cor_reset, NULL); + if (!priv) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; goto fail_alloc; } - priv = netdev_priv(dev); + dev = priv->ndev; card = priv->card; SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); + dev->name, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -173,18 +173,18 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, goto fail; } - pci_set_drvdata(pdev, dev); + pci_set_drvdata(pdev, priv); printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, pci_name(pdev)); return 0; fail: - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); fail_irq: pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); fail_alloc: pci_iounmap(pdev, hermes_io); @@ -200,13 +200,13 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; unregister_netdev(dev); - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); pci_iounmap(pdev, priv->hw.iobase); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/wireless/orinoco/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h index c655b4a..22aa630 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.h +++ b/drivers/net/wireless/orinoco/orinoco_pci.h @@ -21,8 +21,8 @@ struct orinoco_pci_card { #ifdef CONFIG_PM static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; unsigned long flags; int err; @@ -33,7 +33,7 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) return err; } - err = __orinoco_down(dev); + err = __orinoco_down(priv); if (err) printk(KERN_WARNING "%s: error %d bringing interface down " "for suspend\n", dev->name, err); @@ -44,7 +44,7 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) orinoco_unlock(priv, &flags); - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); @@ -54,8 +54,8 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) static int orinoco_pci_resume(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; unsigned long flags; int err; @@ -69,7 +69,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev) pci_restore_state(pdev); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); + dev->name, priv); if (err) { printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", dev->name); @@ -77,7 +77,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev) return -EBUSY; } - err = orinoco_reinit_firmware(dev); + err = orinoco_reinit_firmware(priv); if (err) { printk(KERN_ERR "%s: error %d re-initializing firmware " "on resume\n", dev->name, err); @@ -91,7 +91,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev) priv->hw_unavailable--; if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (err) printk(KERN_ERR "%s: Error %d restarting card on resume\n", dev->name, err); diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index a2a4471..77d5668 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -220,15 +220,15 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_plx_cor_reset, NULL); - if (!dev) { + priv = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_plx_cor_reset, NULL); + if (!priv) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; goto fail_alloc; } - priv = netdev_priv(dev); + dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; @@ -237,7 +237,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); + dev->name, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -262,18 +262,18 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, goto fail; } - pci_set_drvdata(pdev, dev); + pci_set_drvdata(pdev, priv); printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, pci_name(pdev)); return 0; fail: - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); fail_irq: pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); fail_alloc: pci_iounmap(pdev, hermes_io); @@ -295,14 +295,14 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; unregister_netdev(dev); - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); pci_iounmap(pdev, priv->hw.iobase); pci_iounmap(pdev, card->attr_io); pci_iounmap(pdev, card->bridge_io); diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c index cda0e6e..5f24c033 100644 --- a/drivers/net/wireless/orinoco/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c @@ -124,15 +124,15 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_tmd_cor_reset, NULL); - if (!dev) { + priv = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_tmd_cor_reset, NULL); + if (!priv) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; goto fail_alloc; } - priv = netdev_priv(dev); + dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; SET_NETDEV_DEV(dev, &pdev->dev); @@ -140,7 +140,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); + dev->name, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -159,18 +159,18 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, goto fail; } - pci_set_drvdata(pdev, dev); + pci_set_drvdata(pdev, priv); printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, pci_name(pdev)); return 0; fail: - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); fail_irq: pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); fail_alloc: pci_iounmap(pdev, hermes_io); @@ -189,14 +189,14 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; unregister_netdev(dev); - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); pci_iounmap(pdev, priv->hw.iobase); pci_iounmap(pdev, card->bridge_io); pci_release_regions(pdev); diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 38e5198..ce909e4 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -178,27 +178,25 @@ spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle) static int spectrum_cs_probe(struct pcmcia_device *link) { - struct net_device *dev; struct orinoco_private *priv; struct orinoco_pccard *card; - dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), - spectrum_cs_hard_reset, - spectrum_cs_stop_firmware); - if (!dev) + priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + spectrum_cs_hard_reset, + spectrum_cs_stop_firmware); + if (!priv) return -ENOMEM; - priv = netdev_priv(dev); card = priv->card; /* Link both structures together */ card->p_dev = link; - link->priv = dev; + link->priv = priv; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = orinoco_interrupt; - link->irq.Instance = dev; + link->irq.Instance = priv; /* General socket configuration defaults can go here. In this * client, we assume very little, and rely on the CIS for @@ -219,14 +217,14 @@ spectrum_cs_probe(struct pcmcia_device *link) */ static void spectrum_cs_detach(struct pcmcia_device *link) { - struct net_device *dev = link->priv; + struct orinoco_private *priv = link->priv; if (link->dev_node) - unregister_netdev(dev); + unregister_netdev(priv->ndev); spectrum_cs_release(link); - free_orinocodev(dev); + free_orinocodev(priv); } /* spectrum_cs_detach */ /* @@ -306,9 +304,9 @@ next_entry: static int spectrum_cs_config(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; + struct net_device *dev = priv->ndev; hermes_t *hw = &priv->hw; int last_fn, last_ret; void __iomem *mem; @@ -408,8 +406,7 @@ spectrum_cs_config(struct pcmcia_device *link) static void spectrum_cs_release(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; unsigned long flags; /* We're committed to taking the device away now, so mark the @@ -427,15 +424,15 @@ spectrum_cs_release(struct pcmcia_device *link) static int spectrum_cs_suspend(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; + struct net_device *dev = priv->ndev; unsigned long flags; int err = 0; /* Mark the device as stopped, to block IO until later */ spin_lock_irqsave(&priv->lock, flags); - err = __orinoco_down(dev); + err = __orinoco_down(priv); if (err) printk(KERN_WARNING "%s: Error %d downing interface\n", dev->name, err); @@ -451,12 +448,12 @@ spectrum_cs_suspend(struct pcmcia_device *link) static int spectrum_cs_resume(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; + struct net_device *dev = priv->ndev; unsigned long flags; int err; - err = orinoco_reinit_firmware(dev); + err = orinoco_reinit_firmware(priv); if (err) { printk(KERN_ERR "%s: Error %d re-initializing firmware\n", dev->name, err); @@ -469,7 +466,7 @@ spectrum_cs_resume(struct pcmcia_device *link) priv->hw_unavailable--; if (priv->open && !priv->hw_unavailable) { - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (err) printk(KERN_ERR "%s: Error %d restarting card\n", dev->name, err); -- cgit v0.10.2 From 8e638267a896e171e49fb9013f5baf96a4ede754 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:24 +0100 Subject: orinoco: initialise independently of netdev Initialise the orinoco driver before registerring with netdev, which will help when we get to cfg80211... Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index 6559aee..9f90337 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -234,6 +234,12 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) } card->irq_requested = 1; + /* Initialise the main driver */ + if (orinoco_init(priv) != 0) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto failed; + } + /* Tell the stack we exist */ if (register_netdev(dev) != 0) { printk(KERN_ERR PFX "register_netdev() failed\n"); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 4fa8264..ff869a2 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include #include @@ -2073,9 +2074,9 @@ static void orinoco_unregister_pm_notifier(struct orinoco_private *priv) /* Initialization */ /********************************************************************/ -static int orinoco_init(struct net_device *dev) +int orinoco_init(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); + struct device *dev = priv->dev; hermes_t *hw = &priv->hw; int err = 0; @@ -2086,15 +2087,14 @@ static int orinoco_init(struct net_device *dev) /* Initialize the firmware */ err = hermes_init(hw); if (err != 0) { - printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n", - dev->name, err); + dev_err(dev, "Failed to initialize firmware (err = %d)\n", + err); goto out; } err = determine_fw_capabilities(priv); if (err != 0) { - printk(KERN_ERR "%s: Incompatible firmware, aborting\n", - dev->name); + dev_err(dev, "Incompatible firmware, aborting\n"); goto out; } @@ -2110,27 +2110,23 @@ static int orinoco_init(struct net_device *dev) /* Check firmware version again */ err = determine_fw_capabilities(priv); if (err != 0) { - printk(KERN_ERR "%s: Incompatible firmware, aborting\n", - dev->name); + dev_err(dev, "Incompatible firmware, aborting\n"); goto out; } } if (priv->has_port3) - printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", - dev->name); + dev_info(dev, "Ad-hoc demo mode supported\n"); if (priv->has_ibss) - printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n", - dev->name); - if (priv->has_wep) { - printk(KERN_DEBUG "%s: WEP supported, %s-bit key\n", dev->name, - priv->has_big_wep ? "104" : "40"); - } + dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n"); + if (priv->has_wep) + dev_info(dev, "WEP supported, %s-bit key\n", + priv->has_big_wep ? "104" : "40"); if (priv->has_wpa) { - printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name); + dev_info(dev, "WPA-PSK supported\n"); if (orinoco_mic_init(priv)) { - printk(KERN_ERR "%s: Failed to setup MIC crypto " - "algorithm. Disabling WPA support\n", dev->name); + dev_err(dev, "Failed to setup MIC crypto algorithm. " + "Disabling WPA support\n"); priv->has_wpa = 0; } } @@ -2141,14 +2137,14 @@ static int orinoco_init(struct net_device *dev) goto out; orinoco_bss_data_init(priv); - err = orinoco_hw_read_card_settings(priv, dev->dev_addr); + /* Netdev has not initialised, but we have allocated the buffer. */ + err = orinoco_hw_read_card_settings(priv, priv->ndev->dev_addr); if (err) goto out; err = orinoco_hw_allocate_fid(priv); if (err) { - printk(KERN_ERR "%s: failed to allocate NIC buffer!\n", - dev->name); + dev_err(dev, "Failed to allocate NIC buffer!\n"); goto out; } @@ -2174,14 +2170,14 @@ static int orinoco_init(struct net_device *dev) priv->hw_unavailable--; spin_unlock_irq(&priv->lock); - printk(KERN_DEBUG "%s: ready\n", dev->name); + dev_dbg(dev, "Ready\n"); out: return err; } +EXPORT_SYMBOL(orinoco_init); static const struct net_device_ops orinoco_netdev_ops = { - .ndo_init = orinoco_init, .ndo_open = orinoco_open, .ndo_stop = orinoco_stop, .ndo_start_xmit = orinoco_xmit, diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index b93e86c..2e9d33f 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -187,6 +187,7 @@ extern struct orinoco_private *alloc_orinocodev( int (*hard_reset)(struct orinoco_private *), int (*stop_fw)(struct orinoco_private *, int)); extern void free_orinocodev(struct orinoco_private *priv); +extern int orinoco_init(struct orinoco_private *priv); extern int __orinoco_up(struct orinoco_private *priv); extern int __orinoco_down(struct orinoco_private *priv); extern int orinoco_reinit_firmware(struct orinoco_private *priv); diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index fa8fe5b..20abf02 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -297,6 +297,12 @@ orinoco_cs_config(struct pcmcia_device *link) dev->irq = link->irq.AssignedIRQ; card->node.major = card->node.minor = 0; + /* Initialise the main driver */ + if (orinoco_init(priv) != 0) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto failed; + } + SET_NETDEV_DEV(dev, &handle_to_dev(link)); /* Tell the stack we exist */ if (register_netdev(dev) != 0) { diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c index 4efd5a0..45cef81 100644 --- a/drivers/net/wireless/orinoco/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c @@ -217,6 +217,12 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, goto fail; } + err = orinoco_init(priv); + if (err) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto fail; + } + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register network device\n"); diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index 12b9c6a..d0eb4ae 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -167,6 +167,12 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, goto fail; } + err = orinoco_init(priv); + if (err) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto fail; + } + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register network device\n"); diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index 77d5668..8f225d0 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -256,6 +256,12 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, goto fail; } + err = orinoco_init(priv); + if (err) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto fail; + } + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register network device\n"); diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c index 5f24c033..3c04fae 100644 --- a/drivers/net/wireless/orinoco/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c @@ -153,6 +153,12 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, goto fail; } + err = orinoco_init(priv); + if (err) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto fail; + } + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register network device\n"); diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index ce909e4..43e1aed 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -368,6 +368,12 @@ spectrum_cs_config(struct pcmcia_device *link) if (spectrum_cs_hard_reset(priv) != 0) goto failed; + /* Initialise the main driver */ + if (orinoco_init(priv) != 0) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto failed; + } + SET_NETDEV_DEV(dev, &handle_to_dev(link)); /* Tell the stack we exist */ if (register_netdev(dev) != 0) { -- cgit v0.10.2 From 98e5f404485d5d11b15e8351535a0e064a37647c Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:25 +0100 Subject: orinoco: Change set_tkip to use orinoco_private instead of hermes_t hw.h does not include hermes.h, and none of the other functions requires types from that file. Also hermes_t is a (discouraged) typedef so we can't add a forward declaration. Therefore change this function to use orinoco_private. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 4a26d68..eaa89d3 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -677,8 +677,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) * rsc must be 8 bytes * tsc must be 8 bytes or NULL */ -int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, - u8 *key, u8 *rsc, u8 *tsc) +int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, + int set_tx, u8 *key, u8 *rsc, u8 *tsc) { struct { __le16 idx; @@ -688,6 +688,7 @@ int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, u8 rx_mic[MIC_KEYLEN]; u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; } __attribute__ ((packed)) buf; + hermes_t *hw = &priv->hw; int ret; int err; int k; diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 89277de..84c108c 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -35,8 +35,8 @@ int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate); int __orinoco_hw_set_wap(struct orinoco_private *priv); int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); int __orinoco_hw_setup_enc(struct orinoco_private *priv); -int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, - u8 *key, u8 *rsc, u8 *tsc); +int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, + int set_tx, u8 *key, u8 *rsc, u8 *tsc); int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, struct dev_addr_list *mc_list, diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 3f08142..74fdfce 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -1079,7 +1079,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, case IW_ENCODE_ALG_TKIP: { - hermes_t *hw = &priv->hw; u8 *tkip_iv = NULL; if (!priv->has_wpa || @@ -1094,7 +1093,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) tkip_iv = &ext->rx_seq[0]; - err = __orinoco_hw_set_tkip_key(hw, idx, + err = __orinoco_hw_set_tkip_key(priv, idx, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, (u8 *) &priv->tkip_key[idx], tkip_iv, NULL); -- cgit v0.10.2 From ea60a6aaf55984a13a7150568cc103d006e86ab2 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:26 +0100 Subject: orinoco: initiate cfg80211 conversion Initialise and register a wiphy. Store the orinoco_private structure in the new wiphy, and use the net_device private area to store the wireless_dev. This results in a change to the way we navigate from a net_device to the driver private orinoco_private, which we encapsulate in the inline function ndev_priv. Most of the remaining calls to netdev_priv are thus replaced by ndev_priv. We can immediately rely on cfg80211 to handle SIOCGIWNAME, so orinoco_ioctl_getname is removed. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig index 44411eb..83b635f 100644 --- a/drivers/net/wireless/orinoco/Kconfig +++ b/drivers/net/wireless/orinoco/Kconfig @@ -1,6 +1,7 @@ config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 + depends on CFG80211 select WIRELESS_EXT select FW_LOADER select CRYPTO diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile index 1fc7409..9abd632 100644 --- a/drivers/net/wireless/orinoco/Makefile +++ b/drivers/net/wireless/orinoco/Makefile @@ -1,7 +1,7 @@ # # Makefile for the orinoco wireless device drivers. # -orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o +orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o obj-$(CONFIG_HERMES) += orinoco.o obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c new file mode 100644 index 0000000..9a616dd --- /dev/null +++ b/drivers/net/wireless/orinoco/cfg.c @@ -0,0 +1,98 @@ +/* cfg80211 support + * + * See copyright notice in main.c + */ +#include +#include +#include "hw.h" +#include "main.h" +#include "orinoco.h" + +#include "cfg.h" + +/* Supported bitrates. Must agree with hw.c */ +static struct ieee80211_rate orinoco_rates[] = { + { .bitrate = 10 }, + { .bitrate = 20 }, + { .bitrate = 55 }, + { .bitrate = 110 }, +}; + +static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid; + +/* Called after orinoco_private is allocated. */ +void orinoco_wiphy_init(struct wiphy *wiphy) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + + wiphy->privid = orinoco_wiphy_privid; + + set_wiphy_dev(wiphy, priv->dev); +} + +/* Called after firmware is initialised */ +int orinoco_wiphy_register(struct wiphy *wiphy) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + int i, channels = 0; + + if (priv->firmware_type == FIRMWARE_TYPE_AGERE) + wiphy->max_scan_ssids = 1; + else + wiphy->max_scan_ssids = 0; + + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + + /* TODO: should we set if we only have demo ad-hoc? + * (priv->has_port3) + */ + if (priv->has_ibss) + wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); + + if (!priv->broken_monitor || force_monitor) + wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); + + priv->band.bitrates = orinoco_rates; + priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates); + + /* Only support channels allowed by the card EEPROM */ + for (i = 0; i < NUM_CHANNELS; i++) { + if (priv->channel_mask & (1 << i)) { + priv->channels[i].center_freq = + ieee80211_dsss_chan_to_freq(i+1); + channels++; + } + } + priv->band.channels = priv->channels; + priv->band.n_channels = channels; + + wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + i = 0; + if (priv->has_wep) { + priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40; + i++; + + if (priv->has_big_wep) { + priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104; + i++; + } + } + if (priv->has_wpa) { + priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP; + i++; + } + wiphy->cipher_suites = priv->cipher_suites; + wiphy->n_cipher_suites = i; + + wiphy->rts_threshold = priv->rts_thresh; + if (!priv->has_mwo) + wiphy->frag_threshold = priv->frag_thresh; + + return wiphy_register(wiphy); +} + +const struct cfg80211_ops orinoco_cfg_ops = { + +}; diff --git a/drivers/net/wireless/orinoco/cfg.h b/drivers/net/wireless/orinoco/cfg.h new file mode 100644 index 0000000..3ddc96a --- /dev/null +++ b/drivers/net/wireless/orinoco/cfg.h @@ -0,0 +1,15 @@ +/* cfg80211 support. + * + * See copyright notice in main.c + */ +#ifndef ORINOCO_CFG_H +#define ORINOCO_CFG_H + +#include + +extern const struct cfg80211_ops orinoco_cfg_ops; + +void orinoco_wiphy_init(struct wiphy *wiphy); +int orinoco_wiphy_register(struct wiphy *wiphy); + +#endif /* ORINOCO_CFG_H */ diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index ff869a2..5c1cf64 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -89,6 +89,7 @@ #include #include #include +#include #include "hermes_rid.h" #include "hermes_dld.h" @@ -97,6 +98,7 @@ #include "mic.h" #include "fw.h" #include "wext.h" +#include "cfg.h" #include "main.h" #include "orinoco.h" @@ -246,7 +248,7 @@ void set_port_type(struct orinoco_private *priv) static int orinoco_open(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; int err; @@ -265,7 +267,7 @@ static int orinoco_open(struct net_device *dev) static int orinoco_stop(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = 0; /* We mustn't use orinoco_lock() here, because we need to be @@ -284,14 +286,14 @@ static int orinoco_stop(struct net_device *dev) static struct net_device_stats *orinoco_get_stats(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); return &priv->stats; } static void orinoco_set_multicast_list(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; if (orinoco_lock(priv, &flags) != 0) { @@ -306,7 +308,7 @@ static void orinoco_set_multicast_list(struct net_device *dev) static int orinoco_change_mtu(struct net_device *dev, int new_mtu) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); if ((new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU)) return -EINVAL; @@ -327,7 +329,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu) static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw; int err = 0; @@ -517,7 +519,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); u16 fid = hermes_read_regn(hw, ALLOCFID); if (fid != priv->txfid) { @@ -532,7 +534,7 @@ static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; stats->tx_packets++; @@ -544,7 +546,7 @@ static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); u16 status; @@ -600,7 +602,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) static void orinoco_tx_timeout(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; struct hermes *hw = &priv->hw; @@ -649,7 +651,7 @@ static void orinoco_stat_gather(struct net_device *dev, struct sk_buff *skb, struct hermes_rx_descriptor *desc) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); /* Using spy support with lots of Rx packets, like in an * infrastructure (AP), will really slow down everything, because @@ -686,7 +688,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, int err; int len; struct sk_buff *skb; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw; @@ -777,7 +779,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; struct iw_statistics *wstats = &priv->wstats; struct sk_buff *skb = NULL; @@ -901,7 +903,7 @@ static void orinoco_rx(struct net_device *dev, struct hermes_rx_descriptor *desc, struct sk_buff *skb) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; u16 status, fc; int length; @@ -1016,7 +1018,7 @@ static void orinoco_rx(struct net_device *dev, static void orinoco_rx_isr_tasklet(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct orinoco_rx_data *rx_data, *temp; struct hermes_rx_descriptor *desc; struct sk_buff *skb; @@ -1261,7 +1263,7 @@ static void orinoco_send_wevents(struct work_struct *work) static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); u16 infofid; struct { __le16 len; @@ -1594,7 +1596,7 @@ EXPORT_SYMBOL(orinoco_reinit_firmware); int __orinoco_program_rids(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int err; struct hermes_idstring idbuf; @@ -1825,7 +1827,7 @@ int __orinoco_program_rids(struct net_device *dev) static void __orinoco_set_multicast_list(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = 0; int promisc, mc_count; @@ -2077,6 +2079,7 @@ static void orinoco_unregister_pm_notifier(struct orinoco_private *priv) int orinoco_init(struct orinoco_private *priv) { struct device *dev = priv->dev; + struct wiphy *wiphy = priv_to_wiphy(priv); hermes_t *hw = &priv->hw; int err = 0; @@ -2137,10 +2140,10 @@ int orinoco_init(struct orinoco_private *priv) goto out; orinoco_bss_data_init(priv); - /* Netdev has not initialised, but we have allocated the buffer. */ - err = orinoco_hw_read_card_settings(priv, priv->ndev->dev_addr); + err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); if (err) goto out; + memcpy(priv->ndev->dev_addr, wiphy->perm_addr, ETH_ALEN); err = orinoco_hw_allocate_fid(priv); if (err) { @@ -2164,6 +2167,11 @@ int orinoco_init(struct orinoco_private *priv) priv->wpa_ie_len = 0; priv->wpa_ie = NULL; + if (orinoco_wiphy_register(wiphy)) { + err = -ENODEV; + goto out; + } + /* Make the hardware available, as long as it hasn't been * removed elsewhere (e.g. by PCMCIA hot unplug) */ spin_lock_irq(&priv->lock); @@ -2187,6 +2195,31 @@ static const struct net_device_ops orinoco_netdev_ops = { .ndo_get_stats = orinoco_get_stats, }; +/* Allocate private data. + * + * This driver has a number of structures associated with it + * netdev - Net device structure for each network interface + * wiphy - structure associated with wireless phy + * wireless_dev (wdev) - structure for each wireless interface + * hw - structure for hermes chip info + * card - card specific structure for use by the card driver + * (airport, orinoco_cs) + * priv - orinoco private data + * device - generic linux device structure + * + * +---------+ +---------+ + * | wiphy | | netdev | + * | +-------+ | +-------+ + * | | priv | | | wdev | + * | | +-----+ +-+-------+ + * | | | hw | + * | +-+-----+ + * | | card | + * +-+-------+ + * + * priv has a link to netdev and device + * wdev has a link to wiphy + */ struct orinoco_private *alloc_orinocodev(int sizeof_card, struct device *device, @@ -2195,12 +2228,27 @@ struct orinoco_private { struct net_device *dev; struct orinoco_private *priv; + struct wireless_dev *wdev; + struct wiphy *wiphy; + + /* allocate wiphy + * NOTE: We only support a single virtual interface + * but this may change when monitor mode is added + */ + wiphy = wiphy_new(&orinoco_cfg_ops, + sizeof(struct orinoco_private) + sizeof_card); + if (!wiphy) + return NULL; - dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); - if (!dev) + dev = alloc_etherdev(sizeof(struct wireless_dev)); + if (!dev) { + wiphy_free(wiphy); return NULL; - priv = netdev_priv(dev); + } + + priv = wiphy_priv(wiphy); priv->ndev = dev; + if (sizeof_card) priv->card = (void *)((unsigned long)priv + sizeof(struct orinoco_private)); @@ -2208,7 +2256,15 @@ struct orinoco_private priv->card = NULL; priv->dev = device; + orinoco_wiphy_init(wiphy); + + /* Initialise wireless_dev */ + wdev = netdev_priv(dev); + wdev->wiphy = wiphy; + wdev->iftype = NL80211_IFTYPE_STATION; + /* Setup / override net_device fields */ + dev->ieee80211_ptr = wdev; dev->netdev_ops = &orinoco_netdev_ops; dev->watchdog_timeo = HZ; /* 1 second timeout */ dev->ethtool_ops = &orinoco_ethtool_ops; @@ -2257,8 +2313,11 @@ EXPORT_SYMBOL(alloc_orinocodev); void free_orinocodev(struct orinoco_private *priv) { struct net_device *dev = priv->ndev; + struct wiphy *wiphy = priv_to_wiphy(priv); struct orinoco_rx_data *rx_data, *temp; + wiphy_unregister(wiphy); + /* If the tasklet is scheduled when we call tasklet_kill it * will run one final time. However the tasklet will only * drain priv->rx_list if the hw is still available. */ @@ -2281,13 +2340,14 @@ void free_orinocodev(struct orinoco_private *priv) orinoco_mic_free(priv); orinoco_bss_data_free(priv); free_netdev(dev); + wiphy_free(wiphy); } EXPORT_SYMBOL(free_orinocodev); static void orinoco_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1); strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 2e9d33f..608cc5e 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "hermes.h" @@ -67,6 +68,10 @@ struct orinoco_private { int (*hard_reset)(struct orinoco_private *); int (*stop_fw)(struct orinoco_private *, int); + struct ieee80211_supported_band band; + struct ieee80211_channel channels[14]; + u32 cipher_suites[3]; + /* Synchronisation stuff */ spinlock_t lock; int hw_unavailable; @@ -216,4 +221,10 @@ static inline void orinoco_unlock(struct orinoco_private *priv, spin_unlock_irqrestore(&priv->lock, *flags); } +/*** Navigate from net_device to orinoco_private ***/ +static inline struct orinoco_private *ndev_priv(struct net_device *dev) +{ + struct wireless_dev *wdev = netdev_priv(dev); + return wdev_priv(wdev); +} #endif /* _ORINOCO_H */ diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 74fdfce..74892e1 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "hermes.h" #include "hermes_rid.h" @@ -23,7 +24,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; struct iw_statistics *wstats = &priv->wstats; int err; @@ -87,31 +88,12 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) /* Wireless extensions */ /********************************************************************/ -static int orinoco_ioctl_getname(struct net_device *dev, - struct iw_request_info *info, - char *name, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int numrates; - int err; - - err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0); - - if (!err && (numrates > 2)) - strcpy(name, "IEEE 802.11b"); - else - strcpy(name, "IEEE 802.11-DS"); - - return 0; -} - static int orinoco_ioctl_setwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ unsigned long flags; static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -172,7 +154,7 @@ static int orinoco_ioctl_getwap(struct net_device *dev, struct sockaddr *ap_addr, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; @@ -195,7 +177,7 @@ static int orinoco_ioctl_setmode(struct net_device *dev, u32 *mode, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ unsigned long flags; @@ -243,7 +225,7 @@ static int orinoco_ioctl_getmode(struct net_device *dev, u32 *mode, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); *mode = priv->iw_mode; return 0; @@ -254,7 +236,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = 0; struct iw_range *range = (struct iw_range *) extra; int numrates; @@ -367,7 +349,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq, char *keybuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; int setindex = priv->tx_key; int encode_alg = priv->encode_alg; @@ -469,7 +451,7 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq, char *keybuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; u16 xlen = 0; unsigned long flags; @@ -508,7 +490,7 @@ static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq, char *essidbuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it @@ -539,7 +521,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq, char *essidbuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int active; int err = 0; unsigned long flags; @@ -567,7 +549,7 @@ static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq, char *nickbuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; if (nrq->length > IW_ESSID_MAX_SIZE) @@ -589,7 +571,7 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq, char *nickbuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; if (orinoco_lock(priv, &flags) != 0) @@ -608,7 +590,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int chan = -1; unsigned long flags; int err = -EINPROGRESS; /* Call commit handler */ @@ -657,7 +639,7 @@ static int orinoco_ioctl_getfreq(struct net_device *dev, struct iw_freq *frq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int tmp; /* Locking done in there */ @@ -676,7 +658,7 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; u16 val; int err; @@ -705,7 +687,7 @@ static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int val = srq->value; unsigned long flags; @@ -728,7 +710,7 @@ static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int val = rrq->value; unsigned long flags; @@ -752,7 +734,7 @@ static int orinoco_ioctl_getrts(struct net_device *dev, struct iw_param *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); rrq->value = priv->rts_thresh; rrq->disabled = (rrq->value == 2347); @@ -766,7 +748,7 @@ static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ unsigned long flags; @@ -806,7 +788,7 @@ static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int err; u16 val; @@ -847,7 +829,7 @@ static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int ratemode; int bitrate; /* 100s of kilobits */ unsigned long flags; @@ -881,7 +863,7 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = 0; int bitrate, automatic; unsigned long flags; @@ -910,7 +892,7 @@ static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ unsigned long flags; @@ -964,7 +946,7 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; u16 enable, period, timeout, mcast; @@ -1018,7 +1000,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int idx, alg = ext->alg, set_key = 1; @@ -1119,7 +1101,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int idx, max_key_len; @@ -1176,7 +1158,7 @@ static int orinoco_ioctl_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; struct iw_param *param = &wrqu->param; unsigned long flags; @@ -1254,7 +1236,7 @@ static int orinoco_ioctl_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct iw_param *param = &wrqu->param; unsigned long flags; int ret = 0; @@ -1294,7 +1276,7 @@ static int orinoco_ioctl_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); u8 *buf; unsigned long flags; @@ -1337,7 +1319,7 @@ static int orinoco_ioctl_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; int err = 0; @@ -1366,7 +1348,7 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; struct iw_mlme *mlme = (struct iw_mlme *)extra; unsigned long flags; @@ -1407,7 +1389,7 @@ static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; u16 short_limit, long_limit, lifetime; @@ -1461,7 +1443,7 @@ static int orinoco_ioctl_reset(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -1486,7 +1468,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int val = *((int *) extra); unsigned long flags; @@ -1507,7 +1489,7 @@ static int orinoco_ioctl_getibssport(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int *val = (int *) extra; *val = priv->ibss_port; @@ -1519,7 +1501,7 @@ static int orinoco_ioctl_setport3(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int val = *((int *) extra); int err = 0; unsigned long flags; @@ -1565,7 +1547,7 @@ static int orinoco_ioctl_getport3(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int *val = (int *) extra; *val = priv->prefer_port3; @@ -1577,7 +1559,7 @@ static int orinoco_ioctl_setpreamble(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; int val; @@ -1609,7 +1591,7 @@ static int orinoco_ioctl_getpreamble(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int *val = (int *) extra; if (!priv->has_preamble) @@ -1629,7 +1611,7 @@ static int orinoco_ioctl_getrid(struct net_device *dev, struct iw_point *data, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int rid = data->flags; u16 length; @@ -1666,7 +1648,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, struct iw_point *srq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; struct iw_scan_req *si = (struct iw_scan_req *) extra; int err = 0; @@ -1791,7 +1773,7 @@ static inline char *orinoco_translate_scan(struct net_device *dev, union hermes_scan_info *bss, unsigned long last_scanned) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); u16 capabilities; u16 channel; struct iw_event iwe; /* Temporary buffer */ @@ -2102,7 +2084,7 @@ static int orinoco_ioctl_getscan(struct net_device *dev, struct iw_point *srq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = 0; unsigned long flags; char *current_ev = extra; @@ -2180,7 +2162,7 @@ static int orinoco_ioctl_commit(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct hermes *hw = &priv->hw; unsigned long flags; int err = 0; @@ -2257,7 +2239,7 @@ static const struct iw_priv_args orinoco_privtab[] = { [IW_IOCTL_IDX(id)] = (iw_handler) func static const iw_handler orinoco_handler[] = { STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit), - STD_IW_HANDLER(SIOCGIWNAME, orinoco_ioctl_getname), + STD_IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname), STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode), -- cgit v0.10.2 From 35832c50d1d1552618f55aa5457a251df9e63b26 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:27 +0100 Subject: orinoco: make firmware download less verbose The firmware download code has been in a couple of releases, without any significant issues reported in this code. Convert to use pr_debug, so the messages can be recoverred by defining DEBUG. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c index a9ba195..a3eefe1 100644 --- a/drivers/net/wireless/orinoco/hermes_dld.c +++ b/drivers/net/wireless/orinoco/hermes_dld.c @@ -309,7 +309,7 @@ int hermes_read_pda(hermes_t *hw, /* Open auxiliary port */ ret = hermes_aux_control(hw, 1); - printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret); + pr_debug(PFX "AUX enable returned %d\n", ret); if (ret) return ret; @@ -319,12 +319,12 @@ int hermes_read_pda(hermes_t *hw, /* Close aux port */ ret = hermes_aux_control(hw, 0); - printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret); + pr_debug(PFX "AUX disable returned %d\n", ret); /* Check PDA length */ pda_size = le16_to_cpu(pda[0]); - printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n", - pda_size, pda_len); + pr_debug(PFX "Actual PDA length %d, Max allowed %d\n", + pda_size, pda_len); if (pda_size > pda_len) return -EINVAL; @@ -422,20 +422,19 @@ int hermesi_program_init(hermes_t *hw, u32 offset) return err; err = hermes_aux_control(hw, 1); - printk(KERN_DEBUG PFX "AUX enable returned %d\n", err); + pr_debug(PFX "AUX enable returned %d\n", err); if (err) return err; - printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset); + pr_debug(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset); err = hermes_doicmd_wait(hw, HERMES_PROGRAM_ENABLE_VOLATILE, offset & 0xFFFFu, offset >> 16, 0, NULL); - printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n", - err); + pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err); return err; } @@ -454,16 +453,16 @@ int hermesi_program_end(hermes_t *hw) rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp); - printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, " - "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", - rc, resp.resp0, resp.resp1, resp.resp2); + pr_debug(PFX "PROGRAM_DISABLE returned %d, " + "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", + rc, resp.resp0, resp.resp1, resp.resp2); if ((rc == 0) && ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD)) rc = -EIO; err = hermes_aux_control(hw, 0); - printk(KERN_DEBUG PFX "AUX disable returned %d\n", err); + pr_debug(PFX "AUX disable returned %d\n", err); /* Acknowledge any outstanding command */ hermes_write_regn(hw, EVACK, 0xFFFF); @@ -496,9 +495,8 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end) while ((blkaddr != BLOCK_END) && (((void *) blk + blklen) <= end)) { - printk(KERN_DEBUG PFX - "Programming block of length %d to address 0x%08x\n", - blklen, blkaddr); + pr_debug(PFX "Programming block of length %d " + "to address 0x%08x\n", blklen, blkaddr); #if !LIMIT_PROGRAM_SIZE /* wl_lkm driver splits this into writes of 2000 bytes */ @@ -510,10 +508,9 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end) addr = blkaddr; while (addr < (blkaddr + blklen)) { - printk(KERN_DEBUG PFX - "Programming subblock of length %d " - "to address 0x%08x. Data @ %p\n", - len, addr, &blk->data[addr - blkaddr]); + pr_debug(PFX "Programming subblock of length %d " + "to address 0x%08x. Data @ %p\n", + len, addr, &blk->data[addr - blkaddr]); hermes_aux_setaddr(hw, addr); hermes_write_bytes(hw, HERMES_AUXDATA, @@ -643,8 +640,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, pdi = hermes_find_pdi(first_pdi, record_id, pda_end); if (pdi) - printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n", - record_id, pdi); + pr_debug(PFX "Found record 0x%04x at %p\n", + record_id, pdi); switch (record_id) { case 0x110: /* Modem REFDAC values */ @@ -654,9 +651,9 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, default_pdi = NULL; if (outdoor_pdi) { pdi = outdoor_pdi; - printk(KERN_DEBUG PFX - "Using outdoor record 0x%04x at %p\n", - record_id + 1, pdi); + pr_debug(PFX + "Using outdoor record 0x%04x at %p\n", + record_id + 1, pdi); } break; case 0x5: /* HWIF Compatiblity */ @@ -684,9 +681,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, if (!pdi && default_pdi) { /* Use default */ pdi = default_pdi; - printk(KERN_DEBUG PFX - "Using default record 0x%04x at %p\n", - record_id, pdi); + pr_debug(PFX "Using default record 0x%04x at %p\n", + record_id, pdi); } if (pdi) { -- cgit v0.10.2 From 5381956b780e82805247c2ec8e32c4c665309394 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:28 +0100 Subject: orinoco: move netdev interface creation to main driver With the move to cfg80211 it's nice to keep the hardware operations distinct from the interface, even though we can only support a single interface. This also means the driver resembles other cfg80211 drivers. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index 9f90337..e46e0d7 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -116,7 +116,7 @@ airport_detach(struct macio_dev *mdev) struct airport *card = priv->card; if (card->ndev_registered) - unregister_netdev(dev); + orinoco_if_del(priv); card->ndev_registered = 0; if (card->irq_requested) @@ -174,9 +174,9 @@ static int airport_attach(struct macio_dev *mdev, const struct of_device_id *match) { struct orinoco_private *priv; - struct net_device *dev; struct airport *card; unsigned long phys_addr; + unsigned int irq; hermes_t *hw; if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { @@ -191,27 +191,23 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) printk(KERN_ERR PFX "Cannot allocate network device\n"); return -ENODEV; } - dev = priv->ndev; card = priv->card; hw = &priv->hw; card->mdev = mdev; - if (macio_request_resource(mdev, 0, "airport")) { + if (macio_request_resource(mdev, 0, DRIVER_NAME)) { printk(KERN_ERR PFX "can't request IO resource !\n"); free_orinocodev(priv); return -EBUSY; } - SET_NETDEV_DEV(dev, &mdev->ofdev.dev); - macio_set_drvdata(mdev, priv); /* Setup interrupts & base address */ - dev->irq = macio_irq(mdev, 0); + irq = macio_irq(mdev, 0); phys_addr = macio_resource_start(mdev, 0); /* Physical address */ printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr); - dev->base_addr = phys_addr; card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); if (!card->vaddr) { printk(KERN_ERR PFX "ioremap() failed\n"); @@ -228,8 +224,8 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) /* Reset it before we get the interrupt */ hermes_init(hw); - if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, priv)) { - printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq); + if (request_irq(irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) { + printk(KERN_ERR PFX "Couldn't get IRQ %d\n", irq); goto failed; } card->irq_requested = 1; @@ -240,12 +236,11 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) goto failed; } - /* Tell the stack we exist */ - if (register_netdev(dev) != 0) { - printk(KERN_ERR PFX "register_netdev() failed\n"); + /* Register an interface with the stack */ + if (orinoco_if_add(priv, phys_addr, irq) != 0) { + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto failed; } - printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name); card->ndev_registered = 1; return 0; failed: diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 5c1cf64..361cf09 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -1017,8 +1017,8 @@ static void orinoco_rx(struct net_device *dev, static void orinoco_rx_isr_tasklet(unsigned long data) { - struct net_device *dev = (struct net_device *) data; - struct orinoco_private *priv = ndev_priv(dev); + struct orinoco_private *priv = (struct orinoco_private *) data; + struct net_device *dev = priv->ndev; struct orinoco_rx_data *rx_data, *temp; struct hermes_rx_descriptor *desc; struct sk_buff *skb; @@ -2143,7 +2143,6 @@ int orinoco_init(struct orinoco_private *priv) err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); if (err) goto out; - memcpy(priv->ndev->dev_addr, wiphy->perm_addr, ETH_ALEN); err = orinoco_hw_allocate_fid(priv); if (err) { @@ -2226,9 +2225,7 @@ struct orinoco_private int (*hard_reset)(struct orinoco_private *), int (*stop_fw)(struct orinoco_private *, int)) { - struct net_device *dev; struct orinoco_private *priv; - struct wireless_dev *wdev; struct wiphy *wiphy; /* allocate wiphy @@ -2240,43 +2237,20 @@ struct orinoco_private if (!wiphy) return NULL; - dev = alloc_etherdev(sizeof(struct wireless_dev)); - if (!dev) { - wiphy_free(wiphy); - return NULL; - } - priv = wiphy_priv(wiphy); - priv->ndev = dev; + priv->dev = device; if (sizeof_card) priv->card = (void *)((unsigned long)priv + sizeof(struct orinoco_private)); else priv->card = NULL; - priv->dev = device; orinoco_wiphy_init(wiphy); - /* Initialise wireless_dev */ - wdev = netdev_priv(dev); - wdev->wiphy = wiphy; - wdev->iftype = NL80211_IFTYPE_STATION; - - /* Setup / override net_device fields */ - dev->ieee80211_ptr = wdev; - dev->netdev_ops = &orinoco_netdev_ops; - dev->watchdog_timeo = HZ; /* 1 second timeout */ - dev->ethtool_ops = &orinoco_ethtool_ops; - dev->wireless_handlers = &orinoco_handler_def; #ifdef WIRELESS_SPY priv->wireless_data.spy_data = &priv->spy_data; - dev->wireless_data = &priv->wireless_data; #endif - /* we use the default eth_mac_addr for setting the MAC addr */ - - /* Reserve space in skb for the SNAP header */ - dev->hard_header_len += ENCAPS_OVERHEAD; /* Set up default callbacks */ priv->hard_reset = hard_reset; @@ -2293,9 +2267,8 @@ struct orinoco_private INIT_LIST_HEAD(&priv->rx_list); tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, - (unsigned long) dev); + (unsigned long) priv); - netif_carrier_off(dev); priv->last_linkstatus = 0xffff; #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) @@ -2310,9 +2283,82 @@ struct orinoco_private } EXPORT_SYMBOL(alloc_orinocodev); -void free_orinocodev(struct orinoco_private *priv) +/* We can only support a single interface. We provide a separate + * function to set it up to distinguish between hardware + * initialisation and interface setup. + * + * The base_addr and irq parameters are passed on to netdev for use + * with SIOCGIFMAP. + */ +int orinoco_if_add(struct orinoco_private *priv, + unsigned long base_addr, + unsigned int irq) +{ + struct wiphy *wiphy = priv_to_wiphy(priv); + struct wireless_dev *wdev; + struct net_device *dev; + int ret; + + dev = alloc_etherdev(sizeof(struct wireless_dev)); + + if (!dev) + return -ENOMEM; + + /* Initialise wireless_dev */ + wdev = netdev_priv(dev); + wdev->wiphy = wiphy; + wdev->iftype = NL80211_IFTYPE_STATION; + + /* Setup / override net_device fields */ + dev->ieee80211_ptr = wdev; + dev->netdev_ops = &orinoco_netdev_ops; + dev->watchdog_timeo = HZ; /* 1 second timeout */ + dev->ethtool_ops = &orinoco_ethtool_ops; + dev->wireless_handlers = &orinoco_handler_def; +#ifdef WIRELESS_SPY + dev->wireless_data = &priv->wireless_data; +#endif + /* we use the default eth_mac_addr for setting the MAC addr */ + + /* Reserve space in skb for the SNAP header */ + dev->hard_header_len += ENCAPS_OVERHEAD; + + netif_carrier_off(dev); + + memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); + + dev->base_addr = base_addr; + dev->irq = irq; + + SET_NETDEV_DEV(dev, priv->dev); + ret = register_netdev(dev); + if (ret) + goto fail; + + priv->ndev = dev; + + /* Report what we've done */ + dev_dbg(priv->dev, "Registerred interface %s.\n", dev->name); + + return 0; + + fail: + free_netdev(dev); + return ret; +} +EXPORT_SYMBOL(orinoco_if_add); + +void orinoco_if_del(struct orinoco_private *priv) { struct net_device *dev = priv->ndev; + + unregister_netdev(dev); + free_netdev(dev); +} +EXPORT_SYMBOL(orinoco_if_del); + +void free_orinocodev(struct orinoco_private *priv) +{ struct wiphy *wiphy = priv_to_wiphy(priv); struct orinoco_rx_data *rx_data, *temp; @@ -2339,7 +2385,6 @@ void free_orinocodev(struct orinoco_private *priv) kfree(priv->wpa_ie); orinoco_mic_free(priv); orinoco_bss_data_free(priv); - free_netdev(dev); wiphy_free(wiphy); } EXPORT_SYMBOL(free_orinocodev); diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 608cc5e..45aa616 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -193,6 +193,10 @@ extern struct orinoco_private *alloc_orinocodev( int (*stop_fw)(struct orinoco_private *, int)); extern void free_orinocodev(struct orinoco_private *priv); extern int orinoco_init(struct orinoco_private *priv); +extern int orinoco_if_add(struct orinoco_private *priv, + unsigned long base_addr, + unsigned int irq); +extern void orinoco_if_del(struct orinoco_private *priv); extern int __orinoco_up(struct orinoco_private *priv); extern int __orinoco_down(struct orinoco_private *priv); extern int orinoco_reinit_firmware(struct orinoco_private *priv); diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index 20abf02..4c29d36 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -147,7 +147,7 @@ static void orinoco_cs_detach(struct pcmcia_device *link) struct orinoco_private *priv = link->priv; if (link->dev_node) - unregister_netdev(priv->ndev); + orinoco_if_del(priv); orinoco_cs_release(link); @@ -239,7 +239,6 @@ orinoco_cs_config(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; - struct net_device *dev = priv->ndev; hermes_t *hw = &priv->hw; int last_fn, last_ret; void __iomem *mem; @@ -293,8 +292,6 @@ orinoco_cs_config(struct pcmcia_device *link) pcmcia_request_configuration(link, &link->conf)); /* Ok, we have the configuration, prepare to register the netdev */ - dev->base_addr = link->io.BasePort1; - dev->irq = link->irq.AssignedIRQ; card->node.major = card->node.minor = 0; /* Initialise the main driver */ @@ -303,25 +300,19 @@ orinoco_cs_config(struct pcmcia_device *link) goto failed; } - SET_NETDEV_DEV(dev, &handle_to_dev(link)); - /* Tell the stack we exist */ - if (register_netdev(dev) != 0) { - printk(KERN_ERR PFX "register_netdev() failed\n"); + /* Register an interface with the stack */ + if (orinoco_if_add(priv, link->io.BasePort1, + link->irq.AssignedIRQ) != 0) { + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto failed; } /* At this point, the dev_node_t structure(s) needs to be * initialized and arranged in a linked list at link->dev_node. */ - strcpy(card->node.dev_name, dev->name); + strcpy(card->node.dev_name, priv->ndev->name); link->dev_node = &card->node; /* link->dev_node being non-NULL is also * used to indicate that the * net_device has been registered */ - - /* Finally, report what we've done */ - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent), - link->irq.AssignedIRQ, link->io.BasePort1, - link->io.BasePort1 + link->io.NumPorts1 - 1); return 0; cs_failed: diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c index 45cef81..c13a4c3 100644 --- a/drivers/net/wireless/orinoco/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c @@ -144,7 +144,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, int err; struct orinoco_private *priv; struct orinoco_pci_card *card; - struct net_device *dev; void __iomem *hermes_io, *bridge_io, *attr_io; err = pci_enable_device(pdev); @@ -189,16 +188,14 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, goto fail_alloc; } - dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; - SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, priv); + DRIVER_NAME, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -223,15 +220,13 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, goto fail; } - err = register_netdev(dev); + err = orinoco_if_add(priv, 0, 0); if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto fail; } pci_set_drvdata(pdev, priv); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); return 0; @@ -263,13 +258,12 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; /* Clear LEDs */ iowrite16(0, card->bridge_io + 10); - unregister_netdev(dev); + orinoco_if_del(priv); free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); free_orinocodev(priv); diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index d0eb4ae..fea7781 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -116,7 +116,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, int err; struct orinoco_private *priv; struct orinoco_pci_card *card; - struct net_device *dev; void __iomem *hermes_io; err = pci_enable_device(pdev); @@ -147,14 +146,12 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, goto fail_alloc; } - dev = priv->ndev; card = priv->card; - SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, priv); + DRIVER_NAME, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -173,15 +170,13 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, goto fail; } - err = register_netdev(dev); + err = orinoco_if_add(priv, 0, 0); if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto fail; } pci_set_drvdata(pdev, priv); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); return 0; @@ -207,9 +202,8 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; - unregister_netdev(dev); + orinoco_if_del(priv); free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); free_orinocodev(priv); diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index 8f225d0..3f2942a 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -183,7 +183,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, int err; struct orinoco_private *priv; struct orinoco_pci_card *card; - struct net_device *dev; void __iomem *hermes_io, *attr_io, *bridge_io; err = pci_enable_device(pdev); @@ -228,16 +227,14 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, goto fail_alloc; } - dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; - SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, priv); + DRIVER_NAME, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -262,15 +259,13 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, goto fail; } - err = register_netdev(dev); + err = orinoco_if_add(priv, 0, 0); if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto fail; } pci_set_drvdata(pdev, priv); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); return 0; @@ -302,10 +297,9 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; - unregister_netdev(dev); + orinoco_if_del(priv); free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); free_orinocodev(priv); diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c index 3c04fae..d345254 100644 --- a/drivers/net/wireless/orinoco/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c @@ -94,7 +94,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, int err; struct orinoco_private *priv; struct orinoco_pci_card *card; - struct net_device *dev; void __iomem *hermes_io, *bridge_io; err = pci_enable_device(pdev); @@ -132,15 +131,13 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, goto fail_alloc; } - dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; - SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, priv); + DRIVER_NAME, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -159,15 +156,13 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, goto fail; } - err = register_netdev(dev); + err = orinoco_if_add(priv, 0, 0); if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto fail; } pci_set_drvdata(pdev, priv); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); return 0; @@ -196,10 +191,9 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; - unregister_netdev(dev); + orinoco_if_del(priv); free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); free_orinocodev(priv); diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 43e1aed..7b4a7e4 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -220,7 +220,7 @@ static void spectrum_cs_detach(struct pcmcia_device *link) struct orinoco_private *priv = link->priv; if (link->dev_node) - unregister_netdev(priv->ndev); + orinoco_if_del(priv); spectrum_cs_release(link); @@ -306,7 +306,6 @@ spectrum_cs_config(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; - struct net_device *dev = priv->ndev; hermes_t *hw = &priv->hw; int last_fn, last_ret; void __iomem *mem; @@ -360,8 +359,6 @@ spectrum_cs_config(struct pcmcia_device *link) pcmcia_request_configuration(link, &link->conf)); /* Ok, we have the configuration, prepare to register the netdev */ - dev->base_addr = link->io.BasePort1; - dev->irq = link->irq.AssignedIRQ; card->node.major = card->node.minor = 0; /* Reset card */ @@ -374,26 +371,19 @@ spectrum_cs_config(struct pcmcia_device *link) goto failed; } - SET_NETDEV_DEV(dev, &handle_to_dev(link)); - /* Tell the stack we exist */ - if (register_netdev(dev) != 0) { - printk(KERN_ERR PFX "register_netdev() failed\n"); + /* Register an interface with the stack */ + if (orinoco_if_add(priv, link->io.BasePort1, + link->irq.AssignedIRQ) != 0) { + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto failed; } /* At this point, the dev_node_t structure(s) needs to be * initialized and arranged in a linked list at link->dev_node. */ - strcpy(card->node.dev_name, dev->name); + strcpy(card->node.dev_name, priv->ndev->name); link->dev_node = &card->node; /* link->dev_node being non-NULL is also * used to indicate that the * net_device has been registered */ - - /* Finally, report what we've done */ - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent), - link->irq.AssignedIRQ, link->io.BasePort1, - link->io.BasePort1 + link->io.NumPorts1 - 1); - return 0; cs_failed: -- cgit v0.10.2 From ef96b5c9ed6ba4b45fd4cf45810c34978bb8d8bb Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:29 +0100 Subject: airport: store irq in card private structure ... instead of relying on the net_device fields. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index e46e0d7..70f1331 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -27,6 +27,7 @@ struct airport { struct macio_dev *mdev; void __iomem *vaddr; + unsigned int irq; int irq_requested; int ndev_registered; }; @@ -36,6 +37,7 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state) { struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); struct net_device *dev = priv->ndev; + struct airport *card = priv->card; unsigned long flags; int err; @@ -59,7 +61,7 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state) orinoco_unlock(priv, &flags); - disable_irq(dev->irq); + disable_irq(card->irq); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); @@ -71,6 +73,7 @@ airport_resume(struct macio_dev *mdev) { struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); struct net_device *dev = priv->ndev; + struct airport *card = priv->card; unsigned long flags; int err; @@ -80,7 +83,7 @@ airport_resume(struct macio_dev *mdev) macio_get_of_node(mdev), 0, 1); msleep(200); - enable_irq(dev->irq); + enable_irq(card->irq); err = orinoco_reinit_firmware(priv); if (err) { @@ -112,7 +115,6 @@ static int airport_detach(struct macio_dev *mdev) { struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); - struct net_device *dev = priv->ndev; struct airport *card = priv->card; if (card->ndev_registered) @@ -120,7 +122,7 @@ airport_detach(struct macio_dev *mdev) card->ndev_registered = 0; if (card->irq_requested) - free_irq(dev->irq, priv); + free_irq(card->irq, priv); card->irq_requested = 0; if (card->vaddr) @@ -146,7 +148,6 @@ static int airport_hard_reset(struct orinoco_private *priv) * re-initialize properly, it falls in a screaming heap * shortly afterwards. */ #if 0 - struct net_device *dev = priv->ndev; struct airport *card = priv->card; /* Vitally important. If we don't do this it seems we get an @@ -154,7 +155,7 @@ static int airport_hard_reset(struct orinoco_private *priv) * hw_unavailable is already set it doesn't get ACKed, we get * into an interrupt loop and the PMU decides to turn us * off. */ - disable_irq(dev->irq); + disable_irq(card->irq); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0); @@ -163,7 +164,7 @@ static int airport_hard_reset(struct orinoco_private *priv) macio_get_of_node(card->mdev), 0, 1); ssleep(1); - enable_irq(dev->irq); + enable_irq(card->irq); ssleep(1); #endif @@ -176,7 +177,6 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) struct orinoco_private *priv; struct airport *card; unsigned long phys_addr; - unsigned int irq; hermes_t *hw; if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { @@ -205,7 +205,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) macio_set_drvdata(mdev, priv); /* Setup interrupts & base address */ - irq = macio_irq(mdev, 0); + card->irq = macio_irq(mdev, 0); phys_addr = macio_resource_start(mdev, 0); /* Physical address */ printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr); card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); @@ -224,8 +224,8 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) /* Reset it before we get the interrupt */ hermes_init(hw); - if (request_irq(irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) { - printk(KERN_ERR PFX "Couldn't get IRQ %d\n", irq); + if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) { + printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq); goto failed; } card->irq_requested = 1; @@ -237,7 +237,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) } /* Register an interface with the stack */ - if (orinoco_if_add(priv, phys_addr, irq) != 0) { + if (orinoco_if_add(priv, phys_addr, card->irq) != 0) { printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto failed; } -- cgit v0.10.2 From 6415f7df10573bf1ec42644f42bef565127114a1 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:30 +0100 Subject: orinoco: Handle suspend/restore in core driver Each device does almost exactly the same things on suspend and resume when upping and downing the interface. So move this logic into a common routine. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index 70f1331..c60df2c 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -50,15 +50,7 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state) return 0; } - err = __orinoco_down(priv); - if (err) - printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - - priv->hw_unavailable++; - + orinoco_down(priv); orinoco_unlock(priv, &flags); disable_irq(card->irq); @@ -85,30 +77,11 @@ airport_resume(struct macio_dev *mdev) enable_irq(card->irq); - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n", - dev->name, err); - return 0; - } - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - - priv->hw_unavailable--; - - if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(priv); - if (err) - printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n", - dev->name, err); - } - - + err = orinoco_up(priv); spin_unlock_irqrestore(&priv->lock, flags); - return 0; + return err; } static int diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 361cf09..0727b41 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -211,6 +211,8 @@ struct orinoco_rx_data { /********************************************************************/ static void __orinoco_set_multicast_list(struct net_device *dev); +static int __orinoco_up(struct orinoco_private *priv); +static int __orinoco_down(struct orinoco_private *priv); /********************************************************************/ /* Internal helper functions */ @@ -1514,7 +1516,7 @@ static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) /* Internal hardware control routines */ /********************************************************************/ -int __orinoco_up(struct orinoco_private *priv) +static int __orinoco_up(struct orinoco_private *priv) { struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; @@ -1542,9 +1544,8 @@ int __orinoco_up(struct orinoco_private *priv) return 0; } -EXPORT_SYMBOL(__orinoco_up); -int __orinoco_down(struct orinoco_private *priv) +static int __orinoco_down(struct orinoco_private *priv) { struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; @@ -1574,9 +1575,8 @@ int __orinoco_down(struct orinoco_private *priv) return 0; } -EXPORT_SYMBOL(__orinoco_down); -int orinoco_reinit_firmware(struct orinoco_private *priv) +static int orinoco_reinit_firmware(struct orinoco_private *priv) { struct hermes *hw = &priv->hw; int err; @@ -1592,7 +1592,6 @@ int orinoco_reinit_firmware(struct orinoco_private *priv) return err; } -EXPORT_SYMBOL(orinoco_reinit_firmware); int __orinoco_program_rids(struct net_device *dev) { @@ -2389,6 +2388,56 @@ void free_orinocodev(struct orinoco_private *priv) } EXPORT_SYMBOL(free_orinocodev); +int orinoco_up(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + unsigned long flags; + int err; + + spin_lock_irqsave(&priv->lock, flags); + + err = orinoco_reinit_firmware(priv); + if (err) { + printk(KERN_ERR "%s: Error %d re-initializing firmware\n", + dev->name, err); + goto exit; + } + + netif_device_attach(dev); + priv->hw_unavailable--; + + if (priv->open && !priv->hw_unavailable) { + err = __orinoco_up(priv); + if (err) + printk(KERN_ERR "%s: Error %d restarting card\n", + dev->name, err); + } + +exit: + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} +EXPORT_SYMBOL(orinoco_up); + +void orinoco_down(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + unsigned long flags; + int err; + + spin_lock_irqsave(&priv->lock, flags); + err = __orinoco_down(priv); + if (err) + printk(KERN_WARNING "%s: Error %d downing interface\n", + dev->name, err); + + netif_device_detach(dev); + priv->hw_unavailable++; + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL(orinoco_down); + static void orinoco_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 45aa616..4ee85f8 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -197,9 +197,8 @@ extern int orinoco_if_add(struct orinoco_private *priv, unsigned long base_addr, unsigned int irq); extern void orinoco_if_del(struct orinoco_private *priv); -extern int __orinoco_up(struct orinoco_private *priv); -extern int __orinoco_down(struct orinoco_private *priv); -extern int orinoco_reinit_firmware(struct orinoco_private *priv); +extern int orinoco_up(struct orinoco_private *priv); +extern void orinoco_down(struct orinoco_private *priv); extern irqreturn_t orinoco_interrupt(int irq, void *dev_id); /********************************************************************/ diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index 4c29d36..38c1c9d 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -349,26 +349,12 @@ static int orinoco_cs_suspend(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; - struct net_device *dev = priv->ndev; - int err = 0; - unsigned long flags; /* This is probably racy, but I can't think of a better way, short of rewriting the PCMCIA layer to not suck :-( */ - if (!test_bit(0, &card->hard_reset_in_progress)) { - spin_lock_irqsave(&priv->lock, flags); - - err = __orinoco_down(priv); - if (err) - printk(KERN_WARNING "%s: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - priv->hw_unavailable++; - - spin_unlock_irqrestore(&priv->lock, flags); - } + if (!test_bit(0, &card->hard_reset_in_progress)) + orinoco_down(priv); return 0; } @@ -377,32 +363,10 @@ static int orinoco_cs_resume(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; - struct net_device *dev = priv->ndev; int err = 0; - unsigned long flags; - if (!test_bit(0, &card->hard_reset_in_progress)) { - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware\n", - dev->name, err); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - priv->hw_unavailable--; - - if (priv->open && !priv->hw_unavailable) { - err = __orinoco_up(priv); - if (err) - printk(KERN_ERR "%s: Error %d restarting card\n", - dev->name, err); - } - - spin_unlock_irqrestore(&priv->lock, flags); - } + if (!test_bit(0, &card->hard_reset_in_progress)) + err = orinoco_up(priv); return err; } diff --git a/drivers/net/wireless/orinoco/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h index 22aa630..ea7231a 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.h +++ b/drivers/net/wireless/orinoco/orinoco_pci.h @@ -22,28 +22,8 @@ struct orinoco_pci_card { static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; - unsigned long flags; - int err; - - err = orinoco_lock(priv, &flags); - if (err) { - printk(KERN_ERR "%s: cannot lock hardware for suspend\n", - dev->name); - return err; - } - - err = __orinoco_down(priv); - if (err) - printk(KERN_WARNING "%s: error %d bringing interface down " - "for suspend\n", dev->name, err); - - netif_device_detach(dev); - - priv->hw_unavailable++; - - orinoco_unlock(priv, &flags); + orinoco_down(priv); free_irq(pdev->irq, priv); pci_save_state(pdev); pci_disable_device(pdev); @@ -56,7 +36,6 @@ static int orinoco_pci_resume(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); struct net_device *dev = priv->ndev; - unsigned long flags; int err; pci_set_power_state(pdev, 0); @@ -77,29 +56,9 @@ static int orinoco_pci_resume(struct pci_dev *pdev) return -EBUSY; } - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: error %d re-initializing firmware " - "on resume\n", dev->name, err); - return err; - } - - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); + err = orinoco_up(priv); - priv->hw_unavailable--; - - if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(priv); - if (err) - printk(KERN_ERR "%s: Error %d restarting card on resume\n", - dev->name, err); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; + return err; } #else #define orinoco_pci_suspend NULL diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 7b4a7e4..c361310 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -421,22 +421,10 @@ static int spectrum_cs_suspend(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; - struct net_device *dev = priv->ndev; - unsigned long flags; int err = 0; /* Mark the device as stopped, to block IO until later */ - spin_lock_irqsave(&priv->lock, flags); - - err = __orinoco_down(priv); - if (err) - printk(KERN_WARNING "%s: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - priv->hw_unavailable++; - - spin_unlock_irqrestore(&priv->lock, flags); + orinoco_down(priv); return err; } @@ -445,32 +433,9 @@ static int spectrum_cs_resume(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; - struct net_device *dev = priv->ndev; - unsigned long flags; - int err; - - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware\n", - dev->name, err); - return -EIO; - } + int err = orinoco_up(priv); - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - priv->hw_unavailable--; - - if (priv->open && !priv->hw_unavailable) { - err = __orinoco_up(priv); - if (err) - printk(KERN_ERR "%s: Error %d restarting card\n", - dev->name, err); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; + return err; } -- cgit v0.10.2 From 721aa2f75b00399074eb443fdf16d797b4504a36 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:31 +0100 Subject: orinoco: provide generic commit function This allows changes to be commited from cfg80211 functions. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index eaa89d3..56627d9 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -406,6 +406,233 @@ void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic) *automatic = bitrate_table[ratemode].automatic; } +int orinoco_hw_program_rids(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + hermes_t *hw = &priv->hw; + int err; + struct hermes_idstring idbuf; + + /* Set the MAC address */ + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, + HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); + if (err) { + printk(KERN_ERR "%s: Error %d setting MAC address\n", + dev->name, err); + return err; + } + + /* Set up the link mode */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, + priv->port_type); + if (err) { + printk(KERN_ERR "%s: Error %d setting port type\n", + dev->name, err); + return err; + } + /* Set the channel/frequency */ + if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFOWNCHANNEL, + priv->channel); + if (err) { + printk(KERN_ERR "%s: Error %d setting channel %d\n", + dev->name, err, priv->channel); + return err; + } + } + + if (priv->has_ibss) { + u16 createibss; + + if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { + printk(KERN_WARNING "%s: This firmware requires an " + "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); + /* With wvlan_cs, in this case, we would crash. + * hopefully, this driver will behave better... + * Jean II */ + createibss = 0; + } else { + createibss = priv->createibss; + } + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFCREATEIBSS, + createibss); + if (err) { + printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", + dev->name, err); + return err; + } + } + + /* Set the desired BSSID */ + err = __orinoco_hw_set_wap(priv); + if (err) { + printk(KERN_ERR "%s: Error %d setting AP address\n", + dev->name, err); + return err; + } + + /* Set the desired ESSID */ + idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); + memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); + /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting OWNSSID\n", + dev->name, err); + return err; + } + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", + dev->name, err); + return err; + } + + /* Set the station name */ + idbuf.len = cpu_to_le16(strlen(priv->nick)); + memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, + HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting nickname\n", + dev->name, err); + return err; + } + + /* Set AP density */ + if (priv->has_sensitivity) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSYSTEMSCALE, + priv->ap_density); + if (err) { + printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " + "Disabling sensitivity control\n", + dev->name, err); + + priv->has_sensitivity = 0; + } + } + + /* Set RTS threshold */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, + priv->rts_thresh); + if (err) { + printk(KERN_ERR "%s: Error %d setting RTS threshold\n", + dev->name, err); + return err; + } + + /* Set fragmentation threshold or MWO robustness */ + if (priv->has_mwo) + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, + priv->mwo_robust); + else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: Error %d setting fragmentation\n", + dev->name, err); + return err; + } + + /* Set bitrate */ + err = __orinoco_hw_set_bitrate(priv); + if (err) { + printk(KERN_ERR "%s: Error %d setting bitrate\n", + dev->name, err); + return err; + } + + /* Set power management */ + if (priv->has_pm) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMENABLED, + priv->pm_on); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMULTICASTRECEIVE, + priv->pm_mcast); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, + priv->pm_period); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMHOLDOVERDURATION, + priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + } + + /* Set preamble - only for Symbol so far... */ + if (priv->has_preamble) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPREAMBLE_SYMBOL, + priv->preamble); + if (err) { + printk(KERN_ERR "%s: Error %d setting preamble\n", + dev->name, err); + return err; + } + } + + /* Set up encryption */ + if (priv->has_wep || priv->has_wpa) { + err = __orinoco_hw_setup_enc(priv); + if (err) { + printk(KERN_ERR "%s: Error %d activating encryption\n", + dev->name, err); + return err; + } + } + + if (priv->iw_mode == IW_MODE_MONITOR) { + /* Enable monitor mode */ + dev->type = ARPHRD_IEEE80211; + err = hermes_docmd_wait(hw, HERMES_CMD_TEST | + HERMES_TEST_MONITOR, 0, NULL); + } else { + /* Disable monitor mode */ + dev->type = ARPHRD_ETHER; + err = hermes_docmd_wait(hw, HERMES_CMD_TEST | + HERMES_TEST_STOP, 0, NULL); + } + if (err) + return err; + + /* Reset promiscuity / multicast*/ + priv->promiscuous = 0; + priv->mc_count = 0; + + return 0; +} + /* Get tsc from the firmware */ int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc) { diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 84c108c..210c2b1 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -29,6 +29,7 @@ int orinoco_hw_allocate_fid(struct orinoco_private *priv); int orinoco_get_bitratemode(int bitrate, int automatic); void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); +int orinoco_hw_program_rids(struct orinoco_private *priv); int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc); int __orinoco_hw_set_bitrate(struct orinoco_private *priv); int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 0727b41..dab6649 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -210,9 +210,10 @@ struct orinoco_rx_data { /* Function prototypes */ /********************************************************************/ -static void __orinoco_set_multicast_list(struct net_device *dev); +static int __orinoco_set_multicast_list(struct net_device *dev); static int __orinoco_up(struct orinoco_private *priv); static int __orinoco_down(struct orinoco_private *priv); +static int __orinoco_commit(struct orinoco_private *priv); /********************************************************************/ /* Internal helper functions */ @@ -1524,7 +1525,7 @@ static int __orinoco_up(struct orinoco_private *priv) netif_carrier_off(dev); /* just to make sure */ - err = __orinoco_program_rids(dev); + err = __orinoco_commit(priv); if (err) { printk(KERN_ERR "%s: Error %d configuring card\n", dev->name, err); @@ -1593,237 +1594,7 @@ static int orinoco_reinit_firmware(struct orinoco_private *priv) return err; } -int __orinoco_program_rids(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - hermes_t *hw = &priv->hw; - int err; - struct hermes_idstring idbuf; - - /* Set the MAC address */ - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); - if (err) { - printk(KERN_ERR "%s: Error %d setting MAC address\n", - dev->name, err); - return err; - } - - /* Set up the link mode */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, - priv->port_type); - if (err) { - printk(KERN_ERR "%s: Error %d setting port type\n", - dev->name, err); - return err; - } - /* Set the channel/frequency */ - if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFOWNCHANNEL, - priv->channel); - if (err) { - printk(KERN_ERR "%s: Error %d setting channel %d\n", - dev->name, err, priv->channel); - return err; - } - } - - if (priv->has_ibss) { - u16 createibss; - - if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { - printk(KERN_WARNING "%s: This firmware requires an " - "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); - /* With wvlan_cs, in this case, we would crash. - * hopefully, this driver will behave better... - * Jean II */ - createibss = 0; - } else { - createibss = priv->createibss; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFCREATEIBSS, - createibss); - if (err) { - printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", - dev->name, err); - return err; - } - } - - /* Set the desired BSSID */ - err = __orinoco_hw_set_wap(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting AP address\n", - dev->name, err); - return err; - } - /* Set the desired ESSID */ - idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); - memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); - /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting OWNSSID\n", - dev->name, err); - return err; - } - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", - dev->name, err); - return err; - } - - /* Set the station name */ - idbuf.len = cpu_to_le16(strlen(priv->nick)); - memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting nickname\n", - dev->name, err); - return err; - } - - /* Set AP density */ - if (priv->has_sensitivity) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSYSTEMSCALE, - priv->ap_density); - if (err) { - printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " - "Disabling sensitivity control\n", - dev->name, err); - - priv->has_sensitivity = 0; - } - } - - /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting RTS threshold\n", - dev->name, err); - return err; - } - - /* Set fragmentation threshold or MWO robustness */ - if (priv->has_mwo) - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - priv->mwo_robust); - else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting fragmentation\n", - dev->name, err); - return err; - } - - /* Set bitrate */ - err = __orinoco_hw_set_bitrate(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting bitrate\n", - dev->name, err); - return err; - } - - /* Set power management */ - if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMENABLED, - priv->pm_on); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMULTICASTRECEIVE, - priv->pm_mcast); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - priv->pm_period); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - } - - /* Set preamble - only for Symbol so far... */ - if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - priv->preamble); - if (err) { - printk(KERN_ERR "%s: Error %d setting preamble\n", - dev->name, err); - return err; - } - } - - /* Set up encryption */ - if (priv->has_wep || priv->has_wpa) { - err = __orinoco_hw_setup_enc(priv); - if (err) { - printk(KERN_ERR "%s: Error %d activating encryption\n", - dev->name, err); - return err; - } - } - - if (priv->iw_mode == IW_MODE_MONITOR) { - /* Enable monitor mode */ - dev->type = ARPHRD_IEEE80211; - err = hermes_docmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_MONITOR, 0, NULL); - } else { - /* Disable monitor mode */ - dev->type = ARPHRD_ETHER; - err = hermes_docmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_STOP, 0, NULL); - } - if (err) - return err; - - /* Set promiscuity / multicast*/ - priv->promiscuous = 0; - priv->mc_count = 0; - - /* FIXME: what about netif_tx_lock */ - __orinoco_set_multicast_list(dev); - - return 0; -} - -/* FIXME: return int? */ -static void +static int __orinoco_set_multicast_list(struct net_device *dev) { struct orinoco_private *priv = ndev_priv(dev); @@ -1843,6 +1614,8 @@ __orinoco_set_multicast_list(struct net_device *dev) err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count, promisc); + + return err; } /* This must be called from user context, without locks held - use @@ -1920,6 +1693,64 @@ void orinoco_reset(struct work_struct *work) printk(KERN_ERR "%s: Device has been disabled!\n", dev->name); } +static int __orinoco_commit(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + int err = 0; + + err = orinoco_hw_program_rids(priv); + + /* FIXME: what about netif_tx_lock */ + (void) __orinoco_set_multicast_list(dev); + + return err; +} + +/* Ensures configuration changes are applied. May result in a reset. + * The caller should hold priv->lock + */ +int orinoco_commit(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + hermes_t *hw = &priv->hw; + int err; + + if (priv->broken_disableport) { + schedule_work(&priv->reset_work); + return 0; + } + + err = hermes_disable_port(hw, 0); + if (err) { + printk(KERN_WARNING "%s: Unable to disable port " + "while reconfiguring card\n", dev->name); + priv->broken_disableport = 1; + goto out; + } + + err = __orinoco_commit(priv); + if (err) { + printk(KERN_WARNING "%s: Unable to reconfigure card\n", + dev->name); + goto out; + } + + err = hermes_enable_port(hw, 0); + if (err) { + printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", + dev->name); + goto out; + } + + out: + if (err) { + printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); + schedule_work(&priv->reset_work); + err = 0; + } + return err; +} + /********************************************************************/ /* Interrupt handler */ /********************************************************************/ diff --git a/drivers/net/wireless/orinoco/main.h b/drivers/net/wireless/orinoco/main.h index af2bae4..21ab36c 100644 --- a/drivers/net/wireless/orinoco/main.h +++ b/drivers/net/wireless/orinoco/main.h @@ -29,10 +29,9 @@ struct net_device; struct work_struct; void set_port_type(struct orinoco_private *priv); -int __orinoco_program_rids(struct net_device *dev); +int orinoco_commit(struct orinoco_private *priv); void orinoco_reset(struct work_struct *work); - /* Information element helpers - find a home for these... */ static inline u8 *orinoco_get_ie(u8 *data, size_t len, enum ieee80211_eid eid) diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 74892e1..4c20b1d 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -2163,49 +2163,16 @@ static int orinoco_ioctl_commit(struct net_device *dev, char *extra) { struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; unsigned long flags; int err = 0; if (!priv->open) return 0; - if (priv->broken_disableport) { - orinoco_reset(&priv->reset_work); - return 0; - } - if (orinoco_lock(priv, &flags) != 0) return err; - err = hermes_disable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to disable port " - "while reconfiguring card\n", dev->name); - priv->broken_disableport = 1; - goto out; - } - - err = __orinoco_program_rids(dev); - if (err) { - printk(KERN_WARNING "%s: Unable to reconfigure card\n", - dev->name); - goto out; - } - - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", - dev->name); - goto out; - } - - out: - if (err) { - printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); - schedule_work(&priv->reset_work); - err = 0; - } + err = orinoco_commit(priv); orinoco_unlock(priv, &flags); return err; -- cgit v0.10.2 From 5217c571c898371c540e49671600d54346b2e123 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:32 +0100 Subject: orinoco: convert mode setting to cfg80211 Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 9a616dd..9e59d90 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -93,6 +93,50 @@ int orinoco_wiphy_register(struct wiphy *wiphy) return wiphy_register(wiphy); } -const struct cfg80211_ops orinoco_cfg_ops = { +static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + int err = 0; + unsigned long lock; + + if (orinoco_lock(priv, &lock) != 0) + return -EBUSY; + + switch (type) { + case NL80211_IFTYPE_ADHOC: + if (!priv->has_ibss && !priv->has_port3) + err = -EINVAL; + break; + + case NL80211_IFTYPE_STATION: + break; + + case NL80211_IFTYPE_MONITOR: + if (priv->broken_monitor && !force_monitor) { + printk(KERN_WARNING "%s: Monitor mode support is " + "buggy in this firmware, not enabling\n", + wiphy_name(wiphy)); + err = -EINVAL; + } + break; + + default: + err = -EINVAL; + } + if (!err) { + priv->iw_mode = type; + set_port_type(priv); + err = orinoco_commit(priv); + } + + orinoco_unlock(priv, &lock); + + return err; +} + +const struct cfg80211_ops orinoco_cfg_ops = { + .change_virtual_intf = orinoco_change_vif, }; diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 56627d9..4600fe4 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -7,7 +7,7 @@ #include #include #include - +#include #include "hermes.h" #include "hermes_rid.h" #include "orinoco.h" @@ -409,6 +409,7 @@ void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic) int orinoco_hw_program_rids(struct orinoco_private *priv) { struct net_device *dev = priv->ndev; + struct wireless_dev *wdev = netdev_priv(dev); hermes_t *hw = &priv->hw; int err; struct hermes_idstring idbuf; @@ -431,7 +432,7 @@ int orinoco_hw_program_rids(struct orinoco_private *priv) return err; } /* Set the channel/frequency */ - if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) { + if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) { err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel); @@ -612,7 +613,7 @@ int orinoco_hw_program_rids(struct orinoco_private *priv) } } - if (priv->iw_mode == IW_MODE_MONITOR) { + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { /* Enable monitor mode */ dev->type = ARPHRD_IEEE80211; err = hermes_docmd_wait(hw, HERMES_CMD_TEST | @@ -630,6 +631,9 @@ int orinoco_hw_program_rids(struct orinoco_private *priv) priv->promiscuous = 0; priv->mc_count = 0; + /* Record mode change */ + wdev->iftype = priv->iw_mode; + return 0; } @@ -884,7 +888,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) } else master_wep_flag = 0; - if (priv->iw_mode == IW_MODE_MONITOR) + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) master_wep_flag |= HERMES_WEP_HOST_DECRYPT; /* Master WEP setting : on/off */ diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index dab6649..ebf92ae 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -222,11 +222,11 @@ static int __orinoco_commit(struct orinoco_private *priv); void set_port_type(struct orinoco_private *priv) { switch (priv->iw_mode) { - case IW_MODE_INFRA: + case NL80211_IFTYPE_STATION: priv->port_type = 1; priv->createibss = 0; break; - case IW_MODE_ADHOC: + case NL80211_IFTYPE_ADHOC: if (priv->prefer_port3) { priv->port_type = 3; priv->createibss = 0; @@ -235,7 +235,7 @@ void set_port_type(struct orinoco_private *priv) priv->createibss = 1; } break; - case IW_MODE_MONITOR: + case NL80211_IFTYPE_MONITOR: priv->port_type = 3; priv->createibss = 0; break; @@ -359,7 +359,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } - if (!netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) { + if (!netif_carrier_ok(dev) || + (priv->iw_mode == NL80211_IFTYPE_MONITOR)) { /* Oops, the firmware hasn't established a connection, silently drop the packet (this seems to be the safest approach). */ @@ -820,7 +821,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) } /* Handle frames in monitor mode */ - if (priv->iw_mode == IW_MODE_MONITOR) { + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { orinoco_rx_monitor(dev, rxfid, desc); goto out; } @@ -1331,7 +1332,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) u16 newstatus; int connected; - if (priv->iw_mode == IW_MODE_MONITOR) + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) break; if (len != sizeof(linkstatus)) { @@ -1981,7 +1982,7 @@ int orinoco_init(struct orinoco_private *priv) } /* Set up the default configuration */ - priv->iw_mode = IW_MODE_INFRA; + priv->iw_mode = NL80211_IFTYPE_STATION; /* By default use IEEE/IBSS ad-hoc mode if we have it */ priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss); set_port_type(priv); diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 4ee85f8..0c89c28 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -121,7 +121,7 @@ struct orinoco_private { unsigned int broken_monitor:1; /* Configuration paramaters */ - u32 iw_mode; + enum nl80211_iftype iw_mode; int prefer_port3; u16 encode_alg, wep_restrict, tx_key; struct orinoco_key keys[ORINOCO_MAX_KEYS]; diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 4c20b1d..9cd991a 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -52,7 +52,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) * here so we're not safe to sleep here. */ hermes_inquire(hw, HERMES_INQ_TALLIES); - if (priv->iw_mode == IW_MODE_ADHOC) { + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { memset(&wstats->qual, 0, sizeof(wstats->qual)); /* If a spy address is defined, we report stats of the * first spy address - Jean II */ @@ -124,7 +124,7 @@ static int orinoco_ioctl_setwap(struct net_device *dev, goto out; } - if (priv->iw_mode != IW_MODE_INFRA) { + if (priv->iw_mode != NL80211_IFTYPE_STATION) { printk(KERN_WARNING "%s: Manual roaming supported only in " "managed mode\n", dev->name); err = -EOPNOTSUPP; @@ -172,65 +172,6 @@ static int orinoco_ioctl_getwap(struct net_device *dev, return err; } -static int orinoco_ioctl_setmode(struct net_device *dev, - struct iw_request_info *info, - u32 *mode, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (priv->iw_mode == *mode) - return 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (*mode) { - case IW_MODE_ADHOC: - if (!priv->has_ibss && !priv->has_port3) - err = -EOPNOTSUPP; - break; - - case IW_MODE_INFRA: - break; - - case IW_MODE_MONITOR: - if (priv->broken_monitor && !force_monitor) { - printk(KERN_WARNING "%s: Monitor mode support is " - "buggy in this firmware, not enabling\n", - dev->name); - err = -EOPNOTSUPP; - } - break; - - default: - err = -EOPNOTSUPP; - break; - } - - if (err == -EINPROGRESS) { - priv->iw_mode = *mode; - set_port_type(priv); - } - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getmode(struct net_device *dev, - struct iw_request_info *info, - u32 *mode, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - - *mode = priv->iw_mode; - return 0; -} - static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_request_info *info, struct iw_point *rrq, @@ -280,7 +221,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, if (priv->has_wpa) range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP; - if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))) { + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && (!SPY_NUMBER(priv))) { /* Quality stats meaningless in ad-hoc mode */ } else { range->max_qual.qual = 0x8b - 0x2f; @@ -596,7 +537,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, int err = -EINPROGRESS; /* Call commit handler */ /* In infrastructure mode the AP sets the channel */ - if (priv->iw_mode == IW_MODE_INFRA) + if (priv->iw_mode == NL80211_IFTYPE_STATION) return -EBUSY; if ((frq->e == 0) && (frq->m <= 1000)) { @@ -622,7 +563,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, return -EBUSY; priv->channel = chan; - if (priv->iw_mode == IW_MODE_MONITOR) { + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { /* Fast channel change - no commit if successful */ hermes_t *hw = &priv->hw; err = hermes_docmd_wait(hw, HERMES_CMD_TEST | @@ -1673,7 +1614,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, /* In monitor mode, the scan results are always empty. * Probe responses are passed to the driver as received * frames and could be processed in software. */ - if (priv->iw_mode == IW_MODE_MONITOR) { + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { err = -EOPNOTSUPP; goto out; } @@ -2209,8 +2150,8 @@ static const iw_handler orinoco_handler[] = { STD_IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname), STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), - STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode), - STD_IW_HANDLER(SIOCGIWMODE, orinoco_ioctl_getmode), + STD_IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode), + STD_IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode), STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange), -- cgit v0.10.2 From c63cdbe8f80487c372fe0dfe460ed30467029f01 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:33 +0100 Subject: orinoco: convert scanning to cfg80211 This removes the custom scan cache used by orinoco. We also have to avoid calling cfg80211_scan_done from the hard interrupt, so we offload the entirety of scan processing to a workqueue. This may behave strangely if you start scanning just prior to suspending... Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 9e59d90..1a87d3a 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -137,6 +137,26 @@ static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, return err; } +static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + int err; + + if (!request) + return -EINVAL; + + if (priv->scan_request && priv->scan_request != request) + return -EBUSY; + + priv->scan_request = request; + + err = orinoco_hw_trigger_scan(priv, request->ssids); + + return err; +} + const struct cfg80211_ops orinoco_cfg_ops = { .change_virtual_intf = orinoco_change_vif, + .scan = orinoco_scan, }; diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h index c78c442..2dddbb5 100644 --- a/drivers/net/wireless/orinoco/hermes.h +++ b/drivers/net/wireless/orinoco/hermes.h @@ -342,7 +342,7 @@ struct agere_ext_scan_info { __le64 timestamp; __le16 beacon_interval; __le16 capabilities; - u8 data[316]; + u8 data[0]; } __attribute__ ((packed)); #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 4600fe4..fa508af 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -1157,3 +1157,88 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv, return 0; } + +int orinoco_hw_trigger_scan(struct orinoco_private *priv, + const struct cfg80211_ssid *ssid) +{ + struct net_device *dev = priv->ndev; + hermes_t *hw = &priv->hw; + unsigned long flags; + int err = 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + /* Scanning with port 0 disabled would fail */ + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + /* In monitor mode, the scan results are always empty. + * Probe responses are passed to the driver as received + * frames and could be processed in software. */ + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { + err = -EOPNOTSUPP; + goto out; + } + + if (priv->has_hostscan) { + switch (priv->firmware_type) { + case FIRMWARE_TYPE_SYMBOL: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFHOSTSCAN_SYMBOL, + HERMES_HOSTSCAN_SYMBOL_ONCE | + HERMES_HOSTSCAN_SYMBOL_BCAST); + break; + case FIRMWARE_TYPE_INTERSIL: { + __le16 req[3]; + + req[0] = cpu_to_le16(0x3fff); /* All channels */ + req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ + req[2] = 0; /* Any ESSID */ + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFHOSTSCAN, &req); + break; + } + case FIRMWARE_TYPE_AGERE: + if (ssid->ssid_len > 0) { + struct hermes_idstring idbuf; + size_t len = ssid->ssid_len; + + idbuf.len = cpu_to_le16(len); + memcpy(idbuf.val, ssid->ssid, len); + + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNFSCANSSID_AGERE, + HERMES_BYTES_TO_RECLEN(len + 2), + &idbuf); + } else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSCANSSID_AGERE, + 0); /* Any ESSID */ + if (err) + break; + + if (priv->has_ext_scan) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSCANCHANNELS2GHZ, + 0x7FFF); + if (err) + goto out; + + err = hermes_inquire(hw, + HERMES_INQ_CHANNELINFO); + } else + err = hermes_inquire(hw, HERMES_INQ_SCAN); + + break; + } + } else + err = hermes_inquire(hw, HERMES_INQ_SCAN); + + out: + orinoco_unlock(priv, &flags); + + return err; +} diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 210c2b1..27b4276 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -7,6 +7,7 @@ #include #include +#include /* Hardware BAPs */ #define USER_BAP 0 @@ -47,5 +48,7 @@ int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, int orinoco_hw_get_freq(struct orinoco_private *priv); int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, s32 *rates, int max); +int orinoco_hw_trigger_scan(struct orinoco_private *priv, + const struct cfg80211_ssid *ssid); #endif /* _ORINOCO_HW_H_ */ diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index ebf92ae..cd1c04d 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -206,6 +206,13 @@ struct orinoco_rx_data { struct list_head list; }; +struct orinoco_scan_data { + void *buf; + size_t len; + int type; + struct list_head list; +}; + /********************************************************************/ /* Function prototypes */ /********************************************************************/ @@ -1265,6 +1272,78 @@ static void orinoco_send_wevents(struct work_struct *work) orinoco_unlock(priv, &flags); } +static void qbuf_scan(struct orinoco_private *priv, void *buf, + int len, int type) +{ + struct orinoco_scan_data *sd; + unsigned long flags; + + sd = kmalloc(sizeof(*sd), GFP_ATOMIC); + sd->buf = buf; + sd->len = len; + sd->type = type; + + spin_lock_irqsave(&priv->scan_lock, flags); + list_add_tail(&sd->list, &priv->scan_list); + spin_unlock_irqrestore(&priv->scan_lock, flags); + + schedule_work(&priv->process_scan); +} + +static void qabort_scan(struct orinoco_private *priv) +{ + struct orinoco_scan_data *sd; + unsigned long flags; + + sd = kmalloc(sizeof(*sd), GFP_ATOMIC); + sd->len = -1; /* Abort */ + + spin_lock_irqsave(&priv->scan_lock, flags); + list_add_tail(&sd->list, &priv->scan_list); + spin_unlock_irqrestore(&priv->scan_lock, flags); + + schedule_work(&priv->process_scan); +} + +static void orinoco_process_scan_results(struct work_struct *work) +{ + struct orinoco_private *priv = + container_of(work, struct orinoco_private, process_scan); + struct orinoco_scan_data *sd, *temp; + unsigned long flags; + void *buf; + int len; + int type; + + spin_lock_irqsave(&priv->scan_lock, flags); + list_for_each_entry_safe(sd, temp, &priv->scan_list, list) { + spin_unlock_irqrestore(&priv->scan_lock, flags); + + buf = sd->buf; + len = sd->len; + type = sd->type; + + list_del(&sd->list); + kfree(sd); + + if (len > 0) { + if (type == HERMES_INQ_CHANNELINFO) + orinoco_add_extscan_result(priv, buf, len); + else + orinoco_add_hostscan_results(priv, buf, len); + + kfree(buf); + } else if (priv->scan_request) { + /* Either abort or complete the scan */ + cfg80211_scan_done(priv->scan_request, (len < 0)); + priv->scan_request = NULL; + } + + spin_lock_irqsave(&priv->scan_lock, flags); + } + spin_unlock_irqrestore(&priv->scan_lock, flags); +} + static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { struct orinoco_private *priv = ndev_priv(dev); @@ -1351,7 +1430,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) * the hostscan frame can be requested. */ if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && priv->firmware_type == FIRMWARE_TYPE_SYMBOL && - priv->has_hostscan && priv->scan_inprogress) { + priv->has_hostscan && priv->scan_request) { hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); break; } @@ -1377,7 +1456,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) } break; case HERMES_INQ_SCAN: - if (!priv->scan_inprogress && priv->bssid_fixed && + if (!priv->scan_request && priv->bssid_fixed && priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { schedule_work(&priv->join_work); break; @@ -1387,30 +1466,30 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) case HERMES_INQ_HOSTSCAN_SYMBOL: { /* Result of a scanning. Contains information about * cells in the vicinity - Jean II */ - union iwreq_data wrqu; unsigned char *buf; - /* Scan is no longer in progress */ - priv->scan_inprogress = 0; - /* Sanity check */ if (len > 4096) { printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", dev->name, len); + qabort_scan(priv); break; } /* Allocate buffer for results */ buf = kmalloc(len, GFP_ATOMIC); - if (buf == NULL) + if (buf == NULL) { /* No memory, so can't printk()... */ + qabort_scan(priv); break; + } /* Read scan data */ err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len, infofid, sizeof(info)); if (err) { kfree(buf); + qabort_scan(priv); break; } @@ -1424,24 +1503,14 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) } #endif /* ORINOCO_DEBUG */ - if (orinoco_process_scan_results(priv, buf, len) == 0) { - /* Send an empty event to user space. - * We don't send the received data on the event because - * it would require us to do complex transcoding, and - * we want to minimise the work done in the irq handler - * Use a request to extract the data - Jean II */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); - } - kfree(buf); + qbuf_scan(priv, buf, len, type); } break; case HERMES_INQ_CHANNELINFO: { struct agere_ext_scan_info *bss; - if (!priv->scan_inprogress) { + if (!priv->scan_request) { printk(KERN_DEBUG "%s: Got chaninfo without scan, " "len=%d\n", dev->name, len); break; @@ -1449,25 +1518,12 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) /* An empty result indicates that the scan is complete */ if (len == 0) { - union iwreq_data wrqu; - - /* Scan is no longer in progress */ - priv->scan_inprogress = 0; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + qbuf_scan(priv, NULL, len, type); break; } /* Sanity check */ - else if (len > sizeof(*bss)) { - printk(KERN_WARNING - "%s: Ext scan results too large (%d bytes). " - "Truncating results to %zd bytes.\n", - dev->name, len, sizeof(*bss)); - len = sizeof(*bss); - } else if (len < (offsetof(struct agere_ext_scan_info, + else if (len < (offsetof(struct agere_ext_scan_info, data) + 2)) { /* Drop this result now so we don't have to * keep checking later */ @@ -1477,21 +1533,18 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) break; } - bss = kmalloc(sizeof(*bss), GFP_ATOMIC); + bss = kmalloc(len, GFP_ATOMIC); if (bss == NULL) break; /* Read scan data */ err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len, infofid, sizeof(info)); - if (err) { + if (err) kfree(bss); - break; - } - - orinoco_add_ext_scan_result(priv, bss); + else + qbuf_scan(priv, bss, len, type); - kfree(bss); break; } case HERMES_INQ_SEC_STAT_AGERE: @@ -1506,6 +1559,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) /* We don't actually do anything about it */ break; } + + return; } static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) @@ -1649,9 +1704,11 @@ void orinoco_reset(struct work_struct *work) orinoco_unlock(priv, &flags); - /* Scanning support: Cleanup of driver struct */ - orinoco_clear_scan_results(priv, 0); - priv->scan_inprogress = 0; + /* Scanning support: Notify scan cancellation */ + if (priv->scan_request) { + cfg80211_scan_done(priv->scan_request, 1); + priv->scan_request = NULL; + } if (priv->hard_reset) { err = (*priv->hard_reset)(priv); @@ -1965,12 +2022,6 @@ int orinoco_init(struct orinoco_private *priv) } } - /* Now we have the firmware capabilities, allocate appropiate - * sized scan buffers */ - if (orinoco_bss_data_allocate(priv)) - goto out; - orinoco_bss_data_init(priv); - err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); if (err) goto out; @@ -2100,6 +2151,10 @@ struct orinoco_private tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, (unsigned long) priv); + spin_lock_init(&priv->scan_lock); + INIT_LIST_HEAD(&priv->scan_list); + INIT_WORK(&priv->process_scan, orinoco_process_scan_results); + priv->last_linkstatus = 0xffff; #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) @@ -2192,6 +2247,7 @@ void free_orinocodev(struct orinoco_private *priv) { struct wiphy *wiphy = priv_to_wiphy(priv); struct orinoco_rx_data *rx_data, *temp; + struct orinoco_scan_data *sd, *sdtemp; wiphy_unregister(wiphy); @@ -2209,13 +2265,22 @@ void free_orinocodev(struct orinoco_private *priv) kfree(rx_data); } + cancel_work_sync(&priv->process_scan); + /* Explicitly drain priv->scan_list */ + list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) { + list_del(&sd->list); + + if ((sd->len > 0) && sd->buf) + kfree(sd->buf); + kfree(sd); + } + orinoco_unregister_pm_notifier(priv); orinoco_uncache_fw(priv); priv->wpa_ie_len = 0; kfree(priv->wpa_ie); orinoco_mic_free(priv); - orinoco_bss_data_free(priv); wiphy_free(wiphy); } EXPORT_SYMBOL(free_orinocodev); diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 0c89c28..5f4f5c9 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -48,18 +48,6 @@ typedef enum { FIRMWARE_TYPE_SYMBOL } fwtype_t; -struct bss_element { - union hermes_scan_info bss; - unsigned long last_scanned; - struct list_head list; -}; - -struct xbss_element { - struct agere_ext_scan_info bss; - unsigned long last_scanned; - struct list_head list; -}; - struct firmware; struct orinoco_private { @@ -145,12 +133,10 @@ struct orinoco_private { int promiscuous, mc_count; /* Scanning support */ - struct list_head bss_list; - struct list_head bss_free_list; - void *bss_xbss_data; - - int scan_inprogress; /* Scan pending... */ - u32 scan_mode; /* Type of scan done */ + struct cfg80211_scan_request *scan_request; + struct work_struct process_scan; + struct list_head scan_list; + spinlock_t scan_lock; /* protects the scan list */ /* WPA support */ u8 *wpa_ie; diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c index 89d699d..522eb98 100644 --- a/drivers/net/wireless/orinoco/scan.c +++ b/drivers/net/wireless/orinoco/scan.c @@ -5,147 +5,166 @@ #include #include -#include +#include +#include #include "hermes.h" #include "orinoco.h" +#include "main.h" #include "scan.h" -#define ORINOCO_MAX_BSS_COUNT 64 +#define ZERO_DBM_OFFSET 0x95 +#define MAX_SIGNAL_LEVEL 0x8A +#define MIN_SIGNAL_LEVEL 0x2F -#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data) -#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data) +#define SIGNAL_TO_DBM(x) \ + (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \ + - ZERO_DBM_OFFSET) +#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100) -int orinoco_bss_data_allocate(struct orinoco_private *priv) +static int symbol_build_supp_rates(u8 *buf, const __le16 *rates) { - if (priv->bss_xbss_data) - return 0; - - if (priv->has_ext_scan) - priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * - sizeof(struct xbss_element), - GFP_KERNEL); - else - priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * - sizeof(struct bss_element), - GFP_KERNEL); - - if (!priv->bss_xbss_data) { - printk(KERN_WARNING "Out of memory allocating beacons"); - return -ENOMEM; + int i; + u8 rate; + + buf[0] = WLAN_EID_SUPP_RATES; + for (i = 0; i < 5; i++) { + rate = le16_to_cpu(rates[i]); + /* NULL terminated */ + if (rate == 0x0) + break; + buf[i + 2] = rate; } - return 0; -} + buf[1] = i; -void orinoco_bss_data_free(struct orinoco_private *priv) -{ - kfree(priv->bss_xbss_data); - priv->bss_xbss_data = NULL; + return i + 2; } -void orinoco_bss_data_init(struct orinoco_private *priv) +static int prism_build_supp_rates(u8 *buf, const u8 *rates) { int i; - INIT_LIST_HEAD(&priv->bss_free_list); - INIT_LIST_HEAD(&priv->bss_list); - if (priv->has_ext_scan) - for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) - list_add_tail(&(PRIV_XBSS[i].list), - &priv->bss_free_list); - else - for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) - list_add_tail(&(PRIV_BSS[i].list), - &priv->bss_free_list); - -} - -void orinoco_clear_scan_results(struct orinoco_private *priv, - unsigned long scan_age) -{ - if (priv->has_ext_scan) { - struct xbss_element *bss; - struct xbss_element *tmp_bss; - - /* Blow away current list of scan results */ - list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { - if (!scan_age || - time_after(jiffies, bss->last_scanned + scan_age)) { - list_move_tail(&bss->list, - &priv->bss_free_list); - /* Don't blow away ->list, just BSS data */ - memset(&bss->bss, 0, sizeof(bss->bss)); - bss->last_scanned = 0; - } - } - } else { - struct bss_element *bss; - struct bss_element *tmp_bss; - - /* Blow away current list of scan results */ - list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { - if (!scan_age || - time_after(jiffies, bss->last_scanned + scan_age)) { - list_move_tail(&bss->list, - &priv->bss_free_list); - /* Don't blow away ->list, just BSS data */ - memset(&bss->bss, 0, sizeof(bss->bss)); - bss->last_scanned = 0; - } + buf[0] = WLAN_EID_SUPP_RATES; + for (i = 0; i < 8; i++) { + /* NULL terminated */ + if (rates[i] == 0x0) + break; + buf[i + 2] = rates[i]; + } + buf[1] = i; + + /* We might still have another 2 rates, which need to go in + * extended supported rates */ + if (i == 8 && rates[i] > 0) { + buf[10] = WLAN_EID_EXT_SUPP_RATES; + for (; i < 10; i++) { + /* NULL terminated */ + if (rates[i] == 0x0) + break; + buf[i + 2] = rates[i]; } + buf[11] = i - 8; } + + return (i < 8) ? i + 2 : i + 4; } -void orinoco_add_ext_scan_result(struct orinoco_private *priv, - struct agere_ext_scan_info *atom) +static void orinoco_add_hostscan_result(struct orinoco_private *priv, + const union hermes_scan_info *bss) { - struct xbss_element *bss = NULL; - int found = 0; - - /* Try to update an existing bss first */ - list_for_each_entry(bss, &priv->bss_list, list) { - if (compare_ether_addr(bss->bss.bssid, atom->bssid)) - continue; - /* ESSID lengths */ - if (bss->bss.data[1] != atom->data[1]) - continue; - if (memcmp(&bss->bss.data[2], &atom->data[2], - atom->data[1])) - continue; - found = 1; + struct wiphy *wiphy = priv_to_wiphy(priv); + struct ieee80211_channel *channel; + u8 *ie; + u8 ie_buf[46]; + u64 timestamp; + s32 signal; + u16 capability; + u16 beacon_interval; + int ie_len; + int freq; + int len; + + len = le16_to_cpu(bss->a.essid_len); + + /* Reconstruct SSID and bitrate IEs to pass up */ + ie_buf[0] = WLAN_EID_SSID; + ie_buf[1] = len; + memcpy(&ie_buf[2], bss->a.essid, len); + + ie = ie_buf + len + 2; + ie_len = ie_buf[1] + 2; + switch (priv->firmware_type) { + case FIRMWARE_TYPE_SYMBOL: + ie_len += symbol_build_supp_rates(ie, bss->s.rates); break; - } - /* Grab a bss off the free list */ - if (!found && !list_empty(&priv->bss_free_list)) { - bss = list_entry(priv->bss_free_list.next, - struct xbss_element, list); - list_del(priv->bss_free_list.next); + case FIRMWARE_TYPE_INTERSIL: + ie_len += prism_build_supp_rates(ie, bss->p.rates); + break; - list_add_tail(&bss->list, &priv->bss_list); + case FIRMWARE_TYPE_AGERE: + default: + break; } - if (bss) { - /* Always update the BSS to get latest beacon info */ - memcpy(&bss->bss, atom, sizeof(bss->bss)); - bss->last_scanned = jiffies; - } + freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel)); + channel = ieee80211_get_channel(wiphy, freq); + timestamp = 0; + capability = le16_to_cpu(bss->a.capabilities); + beacon_interval = le16_to_cpu(bss->a.beacon_interv); + signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level)); + + cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp, + capability, beacon_interval, ie_buf, ie_len, + signal, GFP_KERNEL); } -int orinoco_process_scan_results(struct orinoco_private *priv, - unsigned char *buf, - int len) +void orinoco_add_extscan_result(struct orinoco_private *priv, + struct agere_ext_scan_info *bss, + size_t len) { - int offset; /* In the scan data */ - union hermes_scan_info *atom; - int atom_len; + struct wiphy *wiphy = priv_to_wiphy(priv); + struct ieee80211_channel *channel; + u8 *ie; + u64 timestamp; + s32 signal; + u16 capability; + u16 beacon_interval; + size_t ie_len; + int chan, freq; + + ie_len = len - sizeof(*bss); + ie = orinoco_get_ie(bss->data, ie_len, WLAN_EID_DS_PARAMS); + chan = ie ? ie[2] : 0; + freq = ieee80211_dsss_chan_to_freq(chan); + channel = ieee80211_get_channel(wiphy, freq); + + timestamp = le64_to_cpu(bss->timestamp); + capability = le16_to_cpu(bss->capabilities); + beacon_interval = le16_to_cpu(bss->beacon_interval); + ie = bss->data; + signal = SIGNAL_TO_MBM(bss->level); + + cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp, + capability, beacon_interval, ie, ie_len, + signal, GFP_KERNEL); +} + +void orinoco_add_hostscan_results(struct orinoco_private *priv, + unsigned char *buf, + size_t len) +{ + int offset; /* In the scan data */ + size_t atom_len; + bool abort = false; switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: atom_len = sizeof(struct agere_scan_apinfo); offset = 0; break; + case FIRMWARE_TYPE_SYMBOL: /* Lack of documentation necessitates this hack. * Different firmwares have 68 or 76 byte long atoms. @@ -163,6 +182,7 @@ int orinoco_process_scan_results(struct orinoco_private *priv, atom_len = 68; offset = 0; break; + case FIRMWARE_TYPE_INTERSIL: offset = 4; if (priv->has_hostscan) { @@ -172,13 +192,16 @@ int orinoco_process_scan_results(struct orinoco_private *priv, printk(KERN_ERR "%s: Invalid atom_len in scan " "data: %d\n", priv->ndev->name, atom_len); - return -EIO; + abort = true; + goto scan_abort; } } else atom_len = offsetof(struct prism2_scan_apinfo, atim); break; + default: - return -EOPNOTSUPP; + abort = true; + goto scan_abort; } /* Check that we got an whole number of atoms */ @@ -186,48 +209,22 @@ int orinoco_process_scan_results(struct orinoco_private *priv, printk(KERN_ERR "%s: Unexpected scan data length %d, " "atom_len %d, offset %d\n", priv->ndev->name, len, atom_len, offset); - return -EIO; + abort = true; + goto scan_abort; } - orinoco_clear_scan_results(priv, msecs_to_jiffies(15000)); - - /* Read the entries one by one */ + /* Process the entries one by one */ for (; offset + atom_len <= len; offset += atom_len) { - int found = 0; - struct bss_element *bss = NULL; + union hermes_scan_info *atom; - /* Get next atom */ atom = (union hermes_scan_info *) (buf + offset); - /* Try to update an existing bss first */ - list_for_each_entry(bss, &priv->bss_list, list) { - if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid)) - continue; - if (le16_to_cpu(bss->bss.a.essid_len) != - le16_to_cpu(atom->a.essid_len)) - continue; - if (memcmp(bss->bss.a.essid, atom->a.essid, - le16_to_cpu(atom->a.essid_len))) - continue; - found = 1; - break; - } - - /* Grab a bss off the free list */ - if (!found && !list_empty(&priv->bss_free_list)) { - bss = list_entry(priv->bss_free_list.next, - struct bss_element, list); - list_del(priv->bss_free_list.next); - - list_add_tail(&bss->list, &priv->bss_list); - } - - if (bss) { - /* Always update the BSS to get latest beacon info */ - memcpy(&bss->bss, atom, sizeof(bss->bss)); - bss->last_scanned = jiffies; - } + orinoco_add_hostscan_result(priv, atom); } - return 0; + scan_abort: + if (priv->scan_request) { + cfg80211_scan_done(priv->scan_request, abort); + priv->scan_request = NULL; + } } diff --git a/drivers/net/wireless/orinoco/scan.h b/drivers/net/wireless/orinoco/scan.h index f319f74..2dc4e04 100644 --- a/drivers/net/wireless/orinoco/scan.h +++ b/drivers/net/wireless/orinoco/scan.h @@ -9,21 +9,12 @@ struct orinoco_private; struct agere_ext_scan_info; -/* Setup and free memory for scan results */ -int orinoco_bss_data_allocate(struct orinoco_private *priv); -void orinoco_bss_data_free(struct orinoco_private *priv); -void orinoco_bss_data_init(struct orinoco_private *priv); - /* Add scan results */ -void orinoco_add_ext_scan_result(struct orinoco_private *priv, - struct agere_ext_scan_info *atom); -int orinoco_process_scan_results(struct orinoco_private *dev, - unsigned char *buf, - int len); - -/* Clear scan results */ -void orinoco_clear_scan_results(struct orinoco_private *priv, - unsigned long scan_age); - +void orinoco_add_extscan_result(struct orinoco_private *priv, + struct agere_ext_scan_info *atom, + size_t len); +void orinoco_add_hostscan_results(struct orinoco_private *dev, + unsigned char *buf, + size_t len); #endif /* _ORINOCO_SCAN_H_ */ diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 9cd991a..082ea0a 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -1583,519 +1583,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev, return err; } -/* Trigger a scan (look for other cells in the vicinity) */ -static int orinoco_ioctl_setscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - hermes_t *hw = &priv->hw; - struct iw_scan_req *si = (struct iw_scan_req *) extra; - int err = 0; - unsigned long flags; - - /* Note : you may have realised that, as this is a SET operation, - * this is privileged and therefore a normal user can't - * perform scanning. - * This is not an error, while the device perform scanning, - * traffic doesn't flow, so it's a perfect DoS... - * Jean II */ - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Scanning with port 0 disabled would fail */ - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } - - /* In monitor mode, the scan results are always empty. - * Probe responses are passed to the driver as received - * frames and could be processed in software. */ - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - err = -EOPNOTSUPP; - goto out; - } - - /* Note : because we don't lock out the irq handler, the way - * we access scan variables in priv is critical. - * o scan_inprogress : not touched by irq handler - * o scan_mode : not touched by irq handler - * Before modifying anything on those variables, please think hard ! - * Jean II */ - - /* Save flags */ - priv->scan_mode = srq->flags; - - /* Always trigger scanning, even if it's in progress. - * This way, if the info frame get lost, we will recover somewhat - * gracefully - Jean II */ - - if (priv->has_hostscan) { - switch (priv->firmware_type) { - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN_SYMBOL, - HERMES_HOSTSCAN_SYMBOL_ONCE | - HERMES_HOSTSCAN_SYMBOL_BCAST); - break; - case FIRMWARE_TYPE_INTERSIL: { - __le16 req[3]; - - req[0] = cpu_to_le16(0x3fff); /* All channels */ - req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ - req[2] = 0; /* Any ESSID */ - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN, &req); - } - break; - case FIRMWARE_TYPE_AGERE: - if (priv->scan_mode & IW_SCAN_THIS_ESSID) { - struct hermes_idstring idbuf; - size_t len = min(sizeof(idbuf.val), - (size_t) si->essid_len); - idbuf.len = cpu_to_le16(len); - memcpy(idbuf.val, si->essid, len); - - err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - HERMES_BYTES_TO_RECLEN(len + 2), - &idbuf); - } else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - 0); /* Any ESSID */ - if (err) - break; - - if (priv->has_ext_scan) { - /* Clear scan results at the start of - * an extended scan */ - orinoco_clear_scan_results(priv, - msecs_to_jiffies(15000)); - - /* TODO: Is this available on older firmware? - * Can we use it to scan specific channels - * for IW_SCAN_THIS_FREQ? */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANCHANNELS2GHZ, - 0x7FFF); - if (err) - goto out; - - err = hermes_inquire(hw, - HERMES_INQ_CHANNELINFO); - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - break; - } - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - - /* One more client */ - if (!err) - priv->scan_inprogress = 1; - - out: - orinoco_unlock(priv, &flags); - return err; -} - -#define MAX_CUSTOM_LEN 64 - -/* Translate scan data returned from the card to a card independant - * format that the Wireless Tools will understand - Jean II */ -static inline char *orinoco_translate_scan(struct net_device *dev, - struct iw_request_info *info, - char *current_ev, - char *end_buf, - union hermes_scan_info *bss, - unsigned long last_scanned) -{ - struct orinoco_private *priv = ndev_priv(dev); - u16 capabilities; - u16 channel; - struct iw_event iwe; /* Temporary buffer */ - char custom[MAX_CUSTOM_LEN]; - - memset(&iwe, 0, sizeof(iwe)); - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - /* Add the ESSID */ - iwe.u.data.length = le16_to_cpu(bss->a.essid_len); - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->a.essid); - - /* Add mode */ - iwe.cmd = SIOCGIWMODE; - capabilities = le16_to_cpu(bss->a.capabilities); - if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { - if (capabilities & WLAN_CAPABILITY_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - channel = bss->s.channel; - if ((channel >= 1) && (channel <= NUM_CHANNELS)) { - /* Add channel and frequency */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = channel; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - } - - /* Add quality statistics. level and noise in dB. No link quality */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; - iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95; - iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95; - /* Wireless tools prior to 27.pre22 will show link quality - * anyway, so we provide a reasonable value. */ - if (iwe.u.qual.level > iwe.u.qual.noise) - iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; - else - iwe.u.qual.qual = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (capabilities & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, NULL); - - /* Bit rate is not available in Lucent/Agere firmwares */ - if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { - char *current_val = current_ev + iwe_stream_lcp_len(info); - int i; - int step; - - if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) - step = 2; - else - step = 1; - - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - /* Max 10 values */ - for (i = 0; i < 10; i += step) { - /* NULL terminated */ - if (bss->p.rates[i] == 0x0) - break; - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = - ((bss->p.rates[i] & 0x7f) * 500000); - current_val = iwe_stream_add_value(info, current_ev, - current_val, - end_buf, &iwe, - IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if ((current_val - current_ev) > iwe_stream_lcp_len(info)) - current_ev = current_val; - } - - /* Beacon interval */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "bcn_int=%d", - le16_to_cpu(bss->a.beacon_interv)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Capabilites */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "capab=0x%04x", - capabilities); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Add EXTRA: Age to display seconds since last beacon/probe response - * for given network. */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - " Last beacon: %dms ago", - jiffies_to_msecs(jiffies - last_scanned)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - return current_ev; -} - -static inline char *orinoco_translate_ext_scan(struct net_device *dev, - struct iw_request_info *info, - char *current_ev, - char *end_buf, - struct agere_ext_scan_info *bss, - unsigned long last_scanned) -{ - u16 capabilities; - u16 channel; - struct iw_event iwe; /* Temporary buffer */ - char custom[MAX_CUSTOM_LEN]; - u8 *ie; - - memset(&iwe, 0, sizeof(iwe)); - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - /* Add the ESSID */ - ie = bss->data; - iwe.u.data.length = ie[1]; - if (iwe.u.data.length) { - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, &ie[2]); - } - - /* Add mode */ - capabilities = le16_to_cpu(bss->capabilities); - if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { - iwe.cmd = SIOCGIWMODE; - if (capabilities & WLAN_CAPABILITY_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS); - channel = ie ? ie[2] : 0; - if ((channel >= 1) && (channel <= NUM_CHANNELS)) { - /* Add channel and frequency */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = channel; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - } - - /* Add quality statistics. level and noise in dB. No link quality */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; - iwe.u.qual.level = bss->level - 0x95; - iwe.u.qual.noise = bss->noise - 0x95; - /* Wireless tools prior to 27.pre22 will show link quality - * anyway, so we provide a reasonable value. */ - if (iwe.u.qual.level > iwe.u.qual.noise) - iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; - else - iwe.u.qual.qual = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (capabilities & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, NULL); - - /* WPA IE */ - ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data)); - if (ie) { - iwe.cmd = IWEVGENIE; - iwe.u.data.length = ie[1] + 2; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ie); - } - - /* RSN IE */ - ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN); - if (ie) { - iwe.cmd = IWEVGENIE; - iwe.u.data.length = ie[1] + 2; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ie); - } - - ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES); - if (ie) { - char *p = current_ev + iwe_stream_lcp_len(info); - int i; - - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - - for (i = 2; i < (ie[1] + 2); i++) { - iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000); - p = iwe_stream_add_value(info, current_ev, p, end_buf, - &iwe, IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if (p > (current_ev + iwe_stream_lcp_len(info))) - current_ev = p; - } - - /* Timestamp */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = - snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx", - (unsigned long long) le64_to_cpu(bss->timestamp)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Beacon interval */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "bcn_int=%d", - le16_to_cpu(bss->beacon_interval)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Capabilites */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "capab=0x%04x", - capabilities); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Add EXTRA: Age to display seconds since last beacon/probe response - * for given network. */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - " Last beacon: %dms ago", - jiffies_to_msecs(jiffies - last_scanned)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - return current_ev; -} - -/* Return results of a scan */ -static int orinoco_ioctl_getscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - unsigned long flags; - char *current_ev = extra; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (priv->scan_inprogress) { - /* Important note : we don't want to block the caller - * until results are ready for various reasons. - * First, managing wait queues is complex and racy. - * Second, we grab some rtnetlink lock before comming - * here (in dev_ioctl()). - * Third, we generate an Wireless Event, so the - * caller can wait itself on that - Jean II */ - err = -EAGAIN; - goto out; - } - - if (priv->has_ext_scan) { - struct xbss_element *bss; - - list_for_each_entry(bss, &priv->bss_list, list) { - /* Translate this entry to WE format */ - current_ev = - orinoco_translate_ext_scan(dev, info, - current_ev, - extra + srq->length, - &bss->bss, - bss->last_scanned); - - /* Check if there is space for one more entry */ - if ((extra + srq->length - current_ev) - <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a - * bigger buffer */ - err = -E2BIG; - goto out; - } - } - - } else { - struct bss_element *bss; - - list_for_each_entry(bss, &priv->bss_list, list) { - /* Translate this entry to WE format */ - current_ev = orinoco_translate_scan(dev, info, - current_ev, - extra + srq->length, - &bss->bss, - bss->last_scanned); - - /* Check if there is space for one more entry */ - if ((extra + srq->length - current_ev) - <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a - * bigger buffer */ - err = -E2BIG; - goto out; - } - } - } - - srq->length = (current_ev - extra); - srq->flags = (__u16) priv->scan_mode; - -out: - orinoco_unlock(priv, &flags); - return err; -} /* Commit handler, called after set operations */ static int orinoco_ioctl_commit(struct net_device *dev, @@ -2161,8 +1648,8 @@ static const iw_handler orinoco_handler[] = { STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), - STD_IW_HANDLER(SIOCSIWSCAN, orinoco_ioctl_setscan), - STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan), + STD_IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan), + STD_IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan), STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick), -- cgit v0.10.2 From 934fd51a94572bcdeea5150ba6a0148971ea9980 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:34 +0100 Subject: orinoco: convert giwrange to cfg80211 Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 082ea0a..21db578 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -172,119 +172,6 @@ static int orinoco_ioctl_getwap(struct net_device *dev, return err; } -static int orinoco_ioctl_getiwrange(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *rrq, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - struct iw_range *range = (struct iw_range *) extra; - int numrates; - int i, k; - - rrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 22; - - /* Set available channels/frequencies */ - range->num_channels = NUM_CHANNELS; - k = 0; - for (i = 0; i < NUM_CHANNELS; i++) { - if (priv->channel_mask & (1 << i)) { - range->freq[k].i = i + 1; - range->freq[k].m = (ieee80211_dsss_chan_to_freq(i + 1) * - 100000); - range->freq[k].e = 1; - k++; - } - - if (k >= IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = k; - range->sensitivity = 3; - - if (priv->has_wep) { - range->max_encoding_tokens = ORINOCO_MAX_KEYS; - range->encoding_size[0] = SMALL_KEY_SIZE; - range->num_encoding_sizes = 1; - - if (priv->has_big_wep) { - range->encoding_size[1] = LARGE_KEY_SIZE; - range->num_encoding_sizes = 2; - } - } - - if (priv->has_wpa) - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP; - - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && (!SPY_NUMBER(priv))) { - /* Quality stats meaningless in ad-hoc mode */ - } else { - range->max_qual.qual = 0x8b - 0x2f; - range->max_qual.level = 0x2f - 0x95 - 1; - range->max_qual.noise = 0x2f - 0x95 - 1; - /* Need to get better values */ - range->avg_qual.qual = 0x24; - range->avg_qual.level = 0xC2; - range->avg_qual.noise = 0x9E; - } - - err = orinoco_hw_get_bitratelist(priv, &numrates, - range->bitrate, IW_MAX_BITRATES); - if (err) - return err; - range->num_bitrates = numrates; - - /* Set an indication of the max TCP throughput in bit/s that we can - * expect using this interface. May be use for QoS stuff... - * Jean II */ - if (numrates > 2) - range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ - else - range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - range->min_pmp = 0; - range->max_pmp = 65535000; - range->min_pmt = 0; - range->max_pmt = 65535 * 1000; /* ??? */ - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = (IW_POWER_PERIOD | IW_POWER_TIMEOUT | - IW_POWER_UNICAST_R); - - range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; - range->retry_flags = IW_RETRY_LIMIT; - range->r_time_flags = IW_RETRY_LIFETIME; - range->min_retry = 0; - range->max_retry = 65535; /* ??? */ - range->min_r_time = 0; - range->max_r_time = 65535 * 1000; /* ??? */ - - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) - range->scan_capa = IW_SCAN_CAPA_ESSID; - else - range->scan_capa = IW_SCAN_CAPA_NONE; - - /* Event capability (kernel) */ - IW_EVENT_CAPA_SET_KERNEL(range->event_capa); - /* Event capability (driver) */ - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); - IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); - - return 0; -} - static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, @@ -1641,7 +1528,7 @@ static const iw_handler orinoco_handler[] = { STD_IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode), STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), - STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange), + STD_IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange), STD_IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), -- cgit v0.10.2 From b5c469108935bacfe6f45005867256801832fdce Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:35 +0100 Subject: orinoco: remove WE nickname support Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 21db578..b6ff3db 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -372,47 +372,6 @@ static int orinoco_ioctl_getessid(struct net_device *dev, return 0; } -static int orinoco_ioctl_setnick(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *nrq, - char *nickbuf) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - - if (nrq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - memset(priv->nick, 0, sizeof(priv->nick)); - memcpy(priv->nick, nickbuf, nrq->length); - - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getnick(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *nrq, - char *nickbuf) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE); - orinoco_unlock(priv, &flags); - - nrq->length = strlen(priv->nick); - - return 0; -} - static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *frq, @@ -1539,8 +1498,6 @@ static const iw_handler orinoco_handler[] = { STD_IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan), STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), - STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick), - STD_IW_HANDLER(SIOCGIWNICKN, orinoco_ioctl_getnick), STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate), STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate), STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts), -- cgit v0.10.2 From f58d4ed98bfe7b2febcd6f0d62744b623e4b8371 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 19 Jun 2009 02:45:21 +0200 Subject: cfg80211: send wext MLME-MICHAELMICFAILURE.indication Instead of having mac80211 do it itself. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/event.c b/net/mac80211/event.c index f288d01..3ac6362 100644 --- a/net/mac80211/event.c +++ b/net/mac80211/event.c @@ -7,8 +7,7 @@ * * mac80211 - events */ - -#include +#include #include "ieee80211_i.h" /* @@ -19,21 +18,6 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, struct ieee80211_hdr *hdr, const u8 *tsc) { - union iwreq_data wrqu; - char *buf = kmalloc(128, GFP_ATOMIC); - - if (buf) { - /* TODO: needed parameters: count, key type, TSC */ - sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=%pM)", - keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", - hdr->addr2); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = strlen(buf); - wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf); - kfree(buf); - } - cfg80211_michael_mic_failure(sdata->dev, hdr->addr2, (hdr->addr1[0] & 0x01) ? NL80211_KEYTYPE_GROUP : diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 4218436..e56bbea 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -77,6 +77,22 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); +#ifdef CONFIG_WIRELESS_EXT + union iwreq_data wrqu; + char *buf = kmalloc(128, GFP_ATOMIC); + + if (buf) { + sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" + "keyid=%d %scast addr=%pM)", key_id, + key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni", + addr); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlen(buf); + wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); + kfree(buf); + } +#endif + nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc); } EXPORT_SYMBOL(cfg80211_michael_mic_failure); -- cgit v0.10.2 From b7351a003ca29ac4372393040ffb06dc04309e2e Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 19 Jun 2009 12:17:47 +0200 Subject: ath9k: remove unnecessary clearing of SC_OP_WAIT_{BEACON,CAB} flags All SC_OP_WAIT_* flags will be cleared in 'ath9k_conf' when PS mode is disabled, so we don't have to clear it here. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c00b905..385bd4c 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -528,14 +528,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) ath_beacon_config(sc, NULL); } - if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) { - /* We are not in PS mode anymore; remain awake */ - DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain " - "awake\n"); - sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); - return; - } - if (ath_beacon_dtim_pending_cab(skb)) { /* * Remain awake waiting for buffered broadcast/multicast -- cgit v0.10.2 From 293dc5dfdbcc16cde06e40a688394cc8ab083e48 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 19 Jun 2009 12:17:48 +0200 Subject: ath9k: remove ath_rx_ps_back_to_sleep helper This helper only clears the SC_OP_WAIT_FOR_{BEACON,CAB} flags. Remove it and clear these flags directly in the approptiate places instead. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 385bd4c..2b2872b 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -505,11 +505,6 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) return false; } -static void ath_rx_ps_back_to_sleep(struct ath_softc *sc) -{ - sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); -} - static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) { struct ieee80211_mgmt *mgmt; @@ -521,6 +516,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0) return; /* not from our current AP */ + sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; + if (sc->sc_flags & SC_OP_BEACON_SYNC) { sc->sc_flags &= ~SC_OP_BEACON_SYNC; DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on " @@ -548,11 +545,9 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) * fails to send a frame indicating that all CAB frames have * been delivered. */ + sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); } - - /* No more broadcast/multicast frames to be received at this point. */ - ath_rx_ps_back_to_sleep(sc); } static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) @@ -570,13 +565,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) ieee80211_is_action(hdr->frame_control)) && is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_moredata(hdr->frame_control)) { - DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to " - "sleep\n"); /* * No more broadcast/multicast frames to be received at this * point. */ - ath_rx_ps_back_to_sleep(sc); + sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; + DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to " + "sleep\n"); } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && !is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_morefrags(hdr->frame_control)) { -- cgit v0.10.2 From c0acf38e0ba42f93d8d56a6db2e2116ea1b23961 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 30 Jun 2009 16:55:52 -0400 Subject: mac80211_hwsim: fix-up build damage from removal of skb->dst Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1b59edc..93c1c4a 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -413,8 +413,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, /* release the skb's source info */ skb_orphan(skb); - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); skb->mark = 0; secpath_reset(skb); nf_reset(skb); -- cgit v0.10.2 From df2b35b65b7142bac2c7add3a1dedde3a373aff3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:42 +0200 Subject: wext: allow returning NULL stats Currently, wext drivers cannot return NULL for stats even though that would make the ioctl return -EOPNOTSUPP because that would mean they are no longer listed in /proc/net/wireless. This patch changes the wext core's behaviour to list them if they have any wireless_handlers, but only show their stats when available, so that drivers can start returning NULL if stats are currently not available, reducing confusion for e.g. IBSS. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 252c201..5da07e0 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -610,6 +610,11 @@ static void wireless_seq_printf_stats(struct seq_file *seq, { /* Get stats from the driver */ struct iw_statistics *stats = get_wireless_stats(dev); + static struct iw_statistics nullstats = {}; + + /* show device if it's wireless regardless of current stats */ + if (!stats && dev->wireless_handlers) + stats = &nullstats; if (stats) { seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " @@ -628,7 +633,9 @@ static void wireless_seq_printf_stats(struct seq_file *seq, stats->discard.nwid, stats->discard.code, stats->discard.fragment, stats->discard.retries, stats->discard.misc, stats->miss.beacon); - stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; + + if (stats != &nullstats) + stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; } } -- cgit v0.10.2 From d3cebbdcedf8d1519913f6e9bf88dbac7fbaa760 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:43 +0200 Subject: mac80211: fix todo lock The key todo lock can be taken from different locks that require it to be _bh to avoid lock inversion due to (soft)irqs. This should fix the two problems reported by Bob and Gabor: http://mid.gmane.org/20090619113049.GB18956@hash.localnet http://mid.gmane.org/4A3FA376.8020307@openwrt.org Signed-off-by: Johannes Berg Cc: Bob Copeland Cc: Gabor Juhos Signed-off-by: John W. Linville diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ce26756..659a42d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -67,6 +67,8 @@ static DECLARE_WORK(todo_work, key_todo); * * @key: key to add to do item for * @flag: todo flag(s) + * + * Must be called with IRQs or softirqs disabled. */ static void add_todo(struct ieee80211_key *key, u32 flag) { @@ -140,9 +142,9 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf); if (!ret) { - spin_lock(&todo_lock); + spin_lock_bh(&todo_lock); key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); } if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) @@ -164,12 +166,12 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) if (!key || !key->local->ops->set_key) return; - spin_lock(&todo_lock); + spin_lock_bh(&todo_lock); if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); return; } - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); sta = get_sta_for_key(key); sdata = key->sdata; @@ -188,9 +190,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) wiphy_name(key->local->hw.wiphy), key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); - spin_lock(&todo_lock); + spin_lock_bh(&todo_lock); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); } static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, @@ -437,14 +439,14 @@ void ieee80211_key_link(struct ieee80211_key *key, __ieee80211_key_replace(sdata, sta, old_key, key); - spin_unlock_irqrestore(&sdata->local->key_lock, flags); - /* free old key later */ add_todo(old_key, KEY_FLAG_TODO_DELETE); add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); if (netif_running(sdata->dev)) add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD); + + spin_unlock_irqrestore(&sdata->local->key_lock, flags); } static void __ieee80211_key_free(struct ieee80211_key *key) @@ -547,7 +549,7 @@ static void __ieee80211_key_todo(void) */ synchronize_rcu(); - spin_lock(&todo_lock); + spin_lock_bh(&todo_lock); while (!list_empty(&todo_list)) { key = list_first_entry(&todo_list, struct ieee80211_key, todo); list_del_init(&key->todo); @@ -558,7 +560,7 @@ static void __ieee80211_key_todo(void) KEY_FLAG_TODO_HWACCEL_REMOVE | KEY_FLAG_TODO_DELETE); key->flags &= ~todoflags; - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); work_done = false; @@ -591,9 +593,9 @@ static void __ieee80211_key_todo(void) WARN_ON(!work_done); - spin_lock(&todo_lock); + spin_lock_bh(&todo_lock); } - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); } void ieee80211_key_todo(void) -- cgit v0.10.2 From 898324025fc12132d3ed98f8baf4fb3fa45327e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:44 +0200 Subject: wext: default to y The way I initially thought we could do wireless extensions is by making all the compat code in cfg80211 be independent of CONFIG_WIRELESS_EXT, but this is turning out to not be feasible. Therefore, fix the Kconfig help text and make the option default to yes, so people won't get a nasty surprise when mac80211 will get rid of its 'select WIRELESS_EXT' any time now. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 4428dd5..ec64571c 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -35,19 +35,13 @@ config WIRELESS_OLD_REGULATORY config WIRELESS_EXT bool "Wireless extensions" - default n + default y ---help--- This option enables the legacy wireless extensions (wireless network interface configuration via ioctls.) - Wireless extensions will be replaced by cfg80211 and - will be required only by legacy drivers that implement - wireless extension handlers. This option does not - affect the wireless-extension backward compatibility - code in cfg80211. - - Say N (if you can) unless you know you need wireless - extensions for external modules. + Say Y unless you've upgraded all your userspace to use + nl80211 instead of wireless extensions. config WIRELESS_EXT_SYSFS bool "Wireless extensions sysfs files" -- cgit v0.10.2 From 2a783c136b4f280d9863170bd6703d25bdb4746c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:45 +0200 Subject: cfg80211: move break statement to correct place Move a break statement to the correct place _after_ the #endif, otherwise w/o WIRELESS_EXT things break badly. Also, while touching this code, do a cleanup and assign dev->ieee80211_ptr to a new variable. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index a98670c..d41b741 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -526,52 +526,53 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, void *ndev) { struct net_device *dev = ndev; + struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev; - if (!dev->ieee80211_ptr) + if (!wdev) return NOTIFY_DONE; - rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); + rdev = wiphy_to_dev(wdev->wiphy); - WARN_ON(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_UNSPECIFIED); + WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED); switch (state) { case NETDEV_REGISTER: mutex_lock(&rdev->devlist_mtx); - list_add(&dev->ieee80211_ptr->list, &rdev->netdev_list); + list_add(&wdev->list, &rdev->netdev_list); if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, "phy80211")) { printk(KERN_ERR "wireless: failed to add phy80211 " "symlink to netdev!\n"); } - dev->ieee80211_ptr->netdev = dev; + wdev->netdev = dev; #ifdef CONFIG_WIRELESS_EXT - dev->ieee80211_ptr->wext.default_key = -1; - dev->ieee80211_ptr->wext.default_mgmt_key = -1; + wdev->wext.default_key = -1; + wdev->wext.default_mgmt_key = -1; #endif mutex_unlock(&rdev->devlist_mtx); break; case NETDEV_GOING_DOWN: - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + if (wdev->iftype != NL80211_IFTYPE_ADHOC) break; - if (!dev->ieee80211_ptr->ssid_len) + if (!wdev->ssid_len) break; cfg80211_leave_ibss(rdev, dev, true); break; case NETDEV_UP: #ifdef CONFIG_WIRELESS_EXT - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + if (wdev->iftype != NL80211_IFTYPE_ADHOC) break; - if (!dev->ieee80211_ptr->wext.ibss.ssid_len) + if (!wdev->wext.ibss.ssid_len) break; - cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext.ibss); - break; + cfg80211_join_ibss(rdev, dev, &wdev->wext.ibss); #endif + break; case NETDEV_UNREGISTER: mutex_lock(&rdev->devlist_mtx); - if (!list_empty(&dev->ieee80211_ptr->list)) { + if (!list_empty(&wdev->list)) { sysfs_remove_link(&dev->dev.kobj, "phy80211"); - list_del_init(&dev->ieee80211_ptr->list); + list_del_init(&wdev->list); } mutex_unlock(&rdev->devlist_mtx); break; -- cgit v0.10.2 From dad823302135a2d99efd40e35d94a6ff14961c93 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:46 +0200 Subject: nl80211: clean up function definitions I don't like the 'extern' keyword much when it's not necessary, it makes lines rather long. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index a3872a4..cf0d271 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -3,41 +3,41 @@ #include "core.h" -extern int nl80211_init(void); -extern void nl80211_exit(void); -extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); -extern void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, - struct net_device *netdev); -extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, - struct net_device *netdev); -extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, - struct net_device *netdev); -extern void nl80211_send_reg_change_event(struct regulatory_request *request); -extern void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - const u8 *buf, size_t len); -extern void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - const u8 *buf, size_t len); -extern void nl80211_send_deauth(struct cfg80211_registered_device *rdev, +int nl80211_init(void); +void nl80211_exit(void); +void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); +void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, + struct net_device *netdev); +void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, + struct net_device *netdev); +void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, + struct net_device *netdev); +void nl80211_send_reg_change_event(struct regulatory_request *request); +void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len); +void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len); +void nl80211_send_deauth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len); +void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len); +void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *addr); +void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, struct net_device *netdev, - const u8 *buf, size_t len); -extern void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - const u8 *buf, size_t len); -extern void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - const u8 *addr); -extern void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - const u8 *addr); -extern void + const u8 *addr); +void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *addr, enum nl80211_key_type key_type, int key_id, const u8 *tsc); -extern void +void nl80211_send_beacon_hint_event(struct wiphy *wiphy, struct ieee80211_channel *channel_before, struct ieee80211_channel *channel_after); -- cgit v0.10.2 From e6d6e3420d511cd7552a95d1f04bd4c80a9ddb34 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:47 +0200 Subject: cfg80211: use proper allocation flags Instead of hardcoding GFP_ATOMIC everywhere, add a new function parameter that gets the flags from the caller. Obviously then I need to update all callers (all of them in mac80211), and it turns out that now it's ok to use GFP_KERNEL in almost all places. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index dba7874..1696ff6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1572,64 +1572,70 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss); * @dev: network device * @buf: authentication frame (header + body) * @len: length of the frame data + * @gfp: allocation flags * * This function is called whenever an authentication has been processed in * station mode. The driver is required to call either this function or * cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth() * call. */ -void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); +void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); /** * cfg80211_send_auth_timeout - notification of timed out authentication * @dev: network device * @addr: The MAC address of the device with which the authentication timed out + * @gfp: allocation flags */ -void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr); +void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp); /** * cfg80211_send_rx_assoc - notification of processed association * @dev: network device * @buf: (re)association response frame (header + body) * @len: length of the frame data + * @gfp: allocation flags * * This function is called whenever a (re)association response has been * processed in station mode. The driver is required to call either this * function or cfg80211_send_assoc_timeout() to indicate the result of * cfg80211_ops::assoc() call. */ -void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len); +void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); /** * cfg80211_send_assoc_timeout - notification of timed out association * @dev: network device * @addr: The MAC address of the device with which the association timed out + * @gfp: allocation flags */ -void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr); +void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp); /** * cfg80211_send_deauth - notification of processed deauthentication * @dev: network device * @buf: deauthentication frame (header + body) * @len: length of the frame data + * @gfp: allocation flags * * This function is called whenever deauthentication has been processed in * station mode. This includes both received deauthentication frames and * locally generated ones. */ -void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); /** * cfg80211_send_disassoc - notification of processed disassociation * @dev: network device * @buf: disassociation response frame (header + body) * @len: length of the frame data + * @gfp: allocation flags * * This function is called whenever disassociation has been processed in * station mode. This includes both received disassociation frames and locally * generated ones. */ -void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len); +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); /** * cfg80211_hold_bss - exclude bss from expiration @@ -1655,6 +1661,7 @@ void cfg80211_unhold_bss(struct cfg80211_bss *bss); * @key_type: The key type that the received frame used * @key_id: Key identifier (0..3) * @tsc: The TSC value of the frame that generated the MIC failure (6 octets) + * @gfp: allocation flags * * This function is called whenever the local MAC detects a MIC failure in a * received frame. This matches with MLME-MICHAELMICFAILURE.indication() @@ -1662,7 +1669,7 @@ void cfg80211_unhold_bss(struct cfg80211_bss *bss); */ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, enum nl80211_key_type key_type, int key_id, - const u8 *tsc); + const u8 *tsc, gfp_t gfp); /** * cfg80211_ibss_joined - notify cfg80211 that device joined an IBSS diff --git a/net/mac80211/event.c b/net/mac80211/event.c index 3ac6362..01ae759 100644 --- a/net/mac80211/event.c +++ b/net/mac80211/event.c @@ -16,11 +16,12 @@ * driver or is still in the frame), it should provide that information. */ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, - struct ieee80211_hdr *hdr, const u8 *tsc) + struct ieee80211_hdr *hdr, const u8 *tsc, + gfp_t gfp) { cfg80211_michael_mic_failure(sdata->dev, hdr->addr2, (hdr->addr1[0] & 0x01) ? NL80211_KEYTYPE_GROUP : NL80211_KEYTYPE_PAIRWISE, - keyidx, tsc); + keyidx, tsc, gfp); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c65c65a..e0323e5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1088,7 +1088,8 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, int rate, int erp, int short_preamble); void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, - struct ieee80211_hdr *hdr, const u8 *tsc); + struct ieee80211_hdr *hdr, const u8 *tsc, + gfp_t gfp); void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, int encrypt); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5e25d32..383392b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -419,9 +419,11 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt->u.deauth.reason_code = cpu_to_le16(reason); if (stype == IEEE80211_STYPE_DEAUTH) - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len); + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len, + GFP_KERNEL); else - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len); + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len, + GFP_KERNEL); ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); } @@ -1006,7 +1008,8 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; ieee80211_recalc_idle(local); - cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); + cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, + GFP_KERNEL); /* * Most likely AP is not in the range so remove the @@ -1055,7 +1058,8 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; ieee80211_recalc_idle(local); - cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); + cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, + GFP_KERNEL); ieee80211_rx_bss_remove(sdata, ifmgd->bssid, sdata->local->hw.conf.channel->center_freq, ifmgd->ssid, ifmgd->ssid_len); @@ -1243,7 +1247,8 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; ieee80211_recalc_idle(local); - cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid); + cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid, + GFP_KERNEL); ieee80211_rx_bss_remove(sdata, ifmgd->bssid, sdata->local->hw.conf.channel->center_freq, ifmgd->ssid, ifmgd->ssid_len); @@ -1517,12 +1522,14 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, case WLAN_AUTH_LEAP: case WLAN_AUTH_FT: ieee80211_auth_completed(sdata); - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, + GFP_KERNEL); break; case WLAN_AUTH_SHARED_KEY: if (ifmgd->auth_transaction == 4) { ieee80211_auth_completed(sdata); - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, + GFP_KERNEL); } else ieee80211_auth_challenge(sdata, mgmt, len); break; @@ -1560,7 +1567,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, ieee80211_set_disassoc(sdata, true, false, 0); ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); } @@ -1591,7 +1598,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, } ieee80211_set_disassoc(sdata, false, false, reason_code); - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); } @@ -1660,7 +1667,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * association next time. This works around some broken APs * which do not correctly reject reassociation requests. */ ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; - cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, + GFP_KERNEL); if (ifmgd->flags & IEEE80211_STA_EXT_SME) { /* Wait for SME to decide what to do next */ ifmgd->state = IEEE80211_STA_MLME_DISABLED; @@ -1823,7 +1831,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ifmgd->last_beacon = jiffies; ieee80211_associated(sdata); - cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0563b69..ec5acc6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1863,7 +1863,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, !ieee80211_is_auth(hdr->frame_control)) goto ignore; - mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL); + mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL, + GFP_ATOMIC); ignore: dev_kfree_skb(rx->skb); rx->skb = NULL; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index dcfae88..7077869 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -122,7 +122,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, - (void *) skb->data, NULL); + (void *) skb->data, NULL, + GFP_ATOMIC); return RX_DROP_UNUSABLE; } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index e56bbea..c4e6d4b 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -12,35 +12,35 @@ #include "core.h" #include "nl80211.h" -void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) +void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_rx_auth(rdev, dev, buf, len); + nl80211_send_rx_auth(rdev, dev, buf, len, gfp); } EXPORT_SYMBOL(cfg80211_send_rx_auth); -void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) +void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_rx_assoc(rdev, dev, buf, len); + nl80211_send_rx_assoc(rdev, dev, buf, len, gfp); } EXPORT_SYMBOL(cfg80211_send_rx_assoc); -void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_deauth(rdev, dev, buf, len); + nl80211_send_deauth(rdev, dev, buf, len, gfp); } EXPORT_SYMBOL(cfg80211_send_deauth); -void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_disassoc(rdev, dev, buf, len); + nl80211_send_disassoc(rdev, dev, buf, len, gfp); } EXPORT_SYMBOL(cfg80211_send_disassoc); @@ -53,33 +53,33 @@ static void cfg80211_wext_disconnected(struct net_device *dev) #endif } -void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) +void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_auth_timeout(rdev, dev, addr); + nl80211_send_auth_timeout(rdev, dev, addr, gfp); cfg80211_wext_disconnected(dev); } EXPORT_SYMBOL(cfg80211_send_auth_timeout); -void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) +void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_assoc_timeout(rdev, dev, addr); + nl80211_send_assoc_timeout(rdev, dev, addr, gfp); cfg80211_wext_disconnected(dev); } EXPORT_SYMBOL(cfg80211_send_assoc_timeout); void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, enum nl80211_key_type key_type, int key_id, - const u8 *tsc) + const u8 *tsc, gfp_t gfp) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); #ifdef CONFIG_WIRELESS_EXT union iwreq_data wrqu; - char *buf = kmalloc(128, GFP_ATOMIC); + char *buf = kmalloc(128, gfp); if (buf) { sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" @@ -93,6 +93,6 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, } #endif - nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc); + nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp); } EXPORT_SYMBOL(cfg80211_michael_mic_failure); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7946b82..01523ba 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3832,12 +3832,12 @@ nla_put_failure: static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len, - enum nl80211_commands cmd) + enum nl80211_commands cmd, gfp_t gfp) { struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); if (!msg) return; @@ -3856,7 +3856,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -3865,42 +3865,45 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, } void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, - struct net_device *netdev, const u8 *buf, size_t len) + struct net_device *netdev, const u8 *buf, + size_t len, gfp_t gfp) { nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_AUTHENTICATE); + NL80211_CMD_AUTHENTICATE, gfp); } void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, - size_t len) + size_t len, gfp_t gfp) { - nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); + nl80211_send_mlme_event(rdev, netdev, buf, len, + NL80211_CMD_ASSOCIATE, gfp); } void nl80211_send_deauth(struct cfg80211_registered_device *rdev, - struct net_device *netdev, const u8 *buf, size_t len) + struct net_device *netdev, const u8 *buf, + size_t len, gfp_t gfp) { nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_DEAUTHENTICATE); + NL80211_CMD_DEAUTHENTICATE, gfp); } void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, - size_t len) + size_t len, gfp_t gfp) { nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_DISASSOCIATE); + NL80211_CMD_DISASSOCIATE, gfp); } static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, struct net_device *netdev, int cmd, - const u8 *addr) + const u8 *addr, gfp_t gfp) { struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); if (!msg) return; @@ -3920,7 +3923,7 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -3929,16 +3932,19 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, } void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, - struct net_device *netdev, const u8 *addr) + struct net_device *netdev, const u8 *addr, + gfp_t gfp) { nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE, - addr); + addr, gfp); } void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, - struct net_device *netdev, const u8 *addr) + struct net_device *netdev, const u8 *addr, + gfp_t gfp) { - nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, addr); + nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, + addr, gfp); } void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, @@ -3978,12 +3984,12 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *addr, enum nl80211_key_type key_type, int key_id, - const u8 *tsc) + const u8 *tsc, gfp_t gfp) { struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); if (!msg) return; @@ -4007,7 +4013,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index cf0d271..662c216 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -15,27 +15,27 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, void nl80211_send_reg_change_event(struct regulatory_request *request); void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, struct net_device *netdev, - const u8 *buf, size_t len); + const u8 *buf, size_t len, gfp_t gfp); void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, - const u8 *buf, size_t len); + const u8 *buf, size_t len, gfp_t gfp); void nl80211_send_deauth(struct cfg80211_registered_device *rdev, struct net_device *netdev, - const u8 *buf, size_t len); + const u8 *buf, size_t len, gfp_t gfp); void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, - const u8 *buf, size_t len); + const u8 *buf, size_t len, gfp_t gfp); void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, struct net_device *netdev, - const u8 *addr); + const u8 *addr, gfp_t gfp); void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, struct net_device *netdev, - const u8 *addr); + const u8 *addr, gfp_t gfp); void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *addr, enum nl80211_key_type key_type, - int key_id, const u8 *tsc); + int key_id, const u8 *tsc, gfp_t gfp); void nl80211_send_beacon_hint_event(struct wiphy *wiphy, -- cgit v0.10.2 From 7ebbe6bd51a259e16608b3fd7b578f5dd1292a45 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:48 +0200 Subject: cfg80211: remove wireless_dev->bssid This variable isn't necessary -- the wext code keeps track of the BSSID itself, and otherwise we have current_bss. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1696ff6..10eb53e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1170,7 +1170,6 @@ struct wireless_dev { /* currently used for IBSS - might be rearranged in the future */ struct cfg80211_bss *current_bss; - u8 bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index a4a1c34..34b11ea 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -24,9 +24,6 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) if (WARN_ON(!wdev->ssid_len)) return; - if (memcmp(bssid, wdev->bssid, ETH_ALEN) == 0) - return; - bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, wdev->ssid, wdev->ssid_len, WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); @@ -41,7 +38,6 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) cfg80211_hold_bss(bss); wdev->current_bss = bss; - memcpy(wdev->bssid, bssid, ETH_ALEN); nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); #ifdef CONFIG_WIRELESS_EXT @@ -87,7 +83,6 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext) wdev->current_bss = NULL; wdev->ssid_len = 0; - memset(wdev->bssid, 0, ETH_ALEN); #ifdef CONFIG_WIRELESS_EXT if (!nowext) wdev->wext.ibss.ssid_len = 0; @@ -356,12 +351,10 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, ap_addr->sa_family = ARPHRD_ETHER; - if (wdev->wext.ibss.bssid) { + if (wdev->current_bss) + memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN); + else memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); - return 0; - } - - memcpy(ap_addr->sa_data, wdev->bssid, ETH_ALEN); return 0; } /* temporary symbol - mark GPL - in the future the handler won't be */ -- cgit v0.10.2 From 0575606b086ad216b7b1976ca9b9a6e711db92f0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:49 +0200 Subject: mac80211: tell SME about real auth state When the auth algorithm is rejected, but we don't have another one to try, we will eventually retry but that isn't useful -- we'll then do it again and again until we eventually give up. Instead, we should let the SME know and go into disabled state. The same applies for situations where the AP rejects with any other status code. Additionally, when trying the next auth algorithm, we should reset the auth_tries so that just a single lost frame doesn't lead to us giving up on the third auth algorithm. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 383392b..58135a5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1511,9 +1511,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, !ieee80211_sta_wep_configured(sdata)) continue; ifmgd->auth_alg = algs[pos]; - break; + ifmgd->auth_tries = 0; + return; } } + /* nothing else to try -- give up */ + cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, + GFP_KERNEL); + ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(sdata->local); return; } -- cgit v0.10.2 From 5121ea0481f9cea1dfd958f18d7b4ac78778cd40 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:50 +0200 Subject: wext: constify extra argument to wireless_send_event This is never changed by the function, so can be marked const. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h index 51b9a37..2b3fbbb 100644 --- a/include/net/iw_handler.h +++ b/include/net/iw_handler.h @@ -443,7 +443,7 @@ extern int dev_get_wireless_info(char * buffer, char **start, off_t offset, extern void wireless_send_event(struct net_device * dev, unsigned int cmd, union iwreq_data * wrqu, - char * extra); + const char * extra); /* We may need a function to send a stream of events to user space. * More on that later... */ diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 5da07e0..425f7d5 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -1376,7 +1376,7 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) void wireless_send_event(struct net_device * dev, unsigned int cmd, union iwreq_data * wrqu, - char * extra) + const char * extra) { const struct iw_ioctl_description * descr = NULL; int extra_len = 0; -- cgit v0.10.2 From aff89a9b9084931e51b89d8f3ee3c547bea6c422 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:51 +0200 Subject: cfg80211: introduce nl80211 testmode command This introduces a new NL80211_CMD_TESTMODE for testing and calibration use with nl80211. There's no multiplexing like like iwpriv had, and the command is not available by default, it needs to be explicitly enabled in Kconfig and shouldn't be enabled in most kernels. The command requires a wiphy index or interface index to identify the device to operate on, and the new TESTDATA attribute. There also is API for sending replies to the command, and testmode multicast messages (on a testmode multicast group). I've also updated mac80211 to be able to pass through the command to the driver, since it itself doesn't implement the testmode command. Additionally, to give people an idea of how to use the command, I've added a little code to hwsim that makes use of the new command to set the powersave mode, this is currently done via debugfs and should remain there, and the testmode command only serves as an example of how to use this best -- with nested netlink attributes in the TESTDATA attribute. A hwsim testmode tool can be found at http://git.sipsolutions.net/hwsim.git/. This tool is BSD licensed so people can easily use it as a basis for their own internal fabrication and validation tools. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 93c1c4a..6ac8565 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -700,6 +700,73 @@ static int mac80211_hwsim_conf_tx( return 0; } +#ifdef CONFIG_NL80211_TESTMODE +/* + * This section contains example code for using netlink + * attributes with the testmode command in nl80211. + */ + +/* These enums need to be kept in sync with userspace */ +enum hwsim_testmode_attr { + __HWSIM_TM_ATTR_INVALID = 0, + HWSIM_TM_ATTR_CMD = 1, + HWSIM_TM_ATTR_PS = 2, + + /* keep last */ + __HWSIM_TM_ATTR_AFTER_LAST, + HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1 +}; + +enum hwsim_testmode_cmd { + HWSIM_TM_CMD_SET_PS = 0, + HWSIM_TM_CMD_GET_PS = 1, +}; + +static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { + [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 }, + [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 }, +}; + +static int hwsim_fops_ps_write(void *dat, u64 val); + +int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +{ + struct mac80211_hwsim_data *hwsim = hw->priv; + struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1]; + struct sk_buff *skb; + int err, ps; + + err = nla_parse(tb, HWSIM_TM_ATTR_MAX, data, len, + hwsim_testmode_policy); + if (err) + return err; + + if (!tb[HWSIM_TM_ATTR_CMD]) + return -EINVAL; + + switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) { + case HWSIM_TM_CMD_SET_PS: + if (!tb[HWSIM_TM_ATTR_PS]) + return -EINVAL; + ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]); + return hwsim_fops_ps_write(hwsim, ps); + case HWSIM_TM_CMD_GET_PS: + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, + nla_total_size(sizeof(u32))); + if (!skb) + return -ENOMEM; + NLA_PUT_U32(skb, HWSIM_TM_ATTR_PS, hwsim->ps); + return cfg80211_testmode_reply(skb); + default: + return -EOPNOTSUPP; + } + + nla_put_failure: + kfree_skb(skb); + return -ENOBUFS; +} +#endif + static const struct ieee80211_ops mac80211_hwsim_ops = { .tx = mac80211_hwsim_tx, @@ -713,6 +780,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = .sta_notify = mac80211_hwsim_sta_notify, .set_tim = mac80211_hwsim_set_tim, .conf_tx = mac80211_hwsim_conf_tx, + CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) }; diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index dbea93b..651b188 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -242,6 +242,10 @@ * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is * determined by the network interface. * + * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute + * to identify the device, and the TESTDATA blob attribute to pass through + * to the driver. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -310,6 +314,8 @@ enum nl80211_commands { NL80211_CMD_JOIN_IBSS, NL80211_CMD_LEAVE_IBSS, + NL80211_CMD_TESTMODE, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -511,6 +517,9 @@ enum nl80211_commands { * authorized by user space. Otherwise, port is marked authorized by * default in station mode. * + * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. + * We recommend using nested, driver-specific attributes within this. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -619,6 +628,8 @@ enum nl80211_attrs { NL80211_ATTR_CONTROL_PORT, + NL80211_ATTR_TESTDATA, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 10eb53e..885d4e5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -857,6 +857,8 @@ enum tx_power_setting { * * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting * functions to adjust rfkill hw state + * + * @testmode_cmd: run a test mode command */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy); @@ -955,6 +957,10 @@ struct cfg80211_ops { int (*get_tx_power)(struct wiphy *wiphy, int *dbm); void (*rfkill_poll)(struct wiphy *wiphy); + +#ifdef CONFIG_NL80211_TESTMODE + int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len); +#endif }; /* @@ -1705,4 +1711,81 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy); */ void wiphy_rfkill_stop_polling(struct wiphy *wiphy); +#ifdef CONFIG_NL80211_TESTMODE +/** + * cfg80211_testmode_alloc_reply_skb - allocate testmode reply + * @wiphy: the wiphy + * @approxlen: an upper bound of the length of the data that will + * be put into the skb + * + * This function allocates and pre-fills an skb for a reply to + * the testmode command. Since it is intended for a reply, calling + * it outside of the @testmode_cmd operation is invalid. + * + * The returned skb (or %NULL if any errors happen) is pre-filled + * with the wiphy index and set up in a way that any data that is + * put into the skb (with skb_put(), nla_put() or similar) will end + * up being within the %NL80211_ATTR_TESTDATA attribute, so all that + * needs to be done with the skb is adding data for the corresponding + * userspace tool which can then read that data out of the testdata + * attribute. You must not modify the skb in any other way. + * + * When done, call cfg80211_testmode_reply() with the skb and return + * its error code as the result of the @testmode_cmd operation. + */ +struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, + int approxlen); + +/** + * cfg80211_testmode_reply - send the reply skb + * @skb: The skb, must have been allocated with + * cfg80211_testmode_alloc_reply_skb() + * + * Returns an error code or 0 on success, since calling this + * function will usually be the last thing before returning + * from the @testmode_cmd you should return the error code. + * Note that this function consumes the skb regardless of the + * return value. + */ +int cfg80211_testmode_reply(struct sk_buff *skb); + +/** + * cfg80211_testmode_alloc_event_skb - allocate testmode event + * @wiphy: the wiphy + * @approxlen: an upper bound of the length of the data that will + * be put into the skb + * @gfp: allocation flags + * + * This function allocates and pre-fills an skb for an event on the + * testmode multicast group. + * + * The returned skb (or %NULL if any errors happen) is set up in the + * same way as with cfg80211_testmode_alloc_reply_skb() but prepared + * for an event. As there, you should simply add data to it that will + * then end up in the %NL80211_ATTR_TESTDATA attribute. Again, you must + * not modify the skb in any other way. + * + * When done filling the skb, call cfg80211_testmode_event() with the + * skb to send the event. + */ +struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, + int approxlen, gfp_t gfp); + +/** + * cfg80211_testmode_event - send the event + * @skb: The skb, must have been allocated with + * cfg80211_testmode_alloc_event_skb() + * @gfp: allocation flags + * + * This function sends the given @skb, which must have been allocated + * by cfg80211_testmode_alloc_event_skb(), as an event. It always + * consumes it. + */ +void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp); + +#define CFG80211_TESTMODE_CMD(cmd) .testmode_cmd = (cmd), +#else +#define CFG80211_TESTMODE_CMD(cmd) +#endif + #endif /* __NET_CFG80211_H */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fe80771..ce7cb1b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1416,6 +1416,8 @@ enum ieee80211_ampdu_mlme_action { * @rfkill_poll: Poll rfkill hardware state. If you need this, you also * need to set wiphy->rfkill_poll to %true before registration, * and need to call wiphy_rfkill_set_hw_state() in the callback. + * + * @testmode_cmd: Implement a cfg80211 test mode command. */ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); @@ -1466,6 +1468,9 @@ struct ieee80211_ops { struct ieee80211_sta *sta, u16 tid, u16 *ssn); void (*rfkill_poll)(struct ieee80211_hw *hw); +#ifdef CONFIG_NL80211_TESTMODE + int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); +#endif }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index eb93eb6..c34c1a4 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1376,6 +1376,18 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy) drv_rfkill_poll(local); } +#ifdef CONFIG_NL80211_TESTMODE +int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + if (!local->ops->testmode_cmd) + return -EOPNOTSUPP; + + return local->ops->testmode_cmd(&local->hw, data, len); +} +#endif + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1418,4 +1430,5 @@ struct cfg80211_ops mac80211_config_ops = { .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, .rfkill_poll = ieee80211_rfkill_poll, + CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) }; diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index ec64571c..0402631 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -2,6 +2,21 @@ config CFG80211 tristate "Improved wireless configuration API" depends on RFKILL || !RFKILL +config NL80211_TESTMODE + bool "nl80211 testmode command" + depends on CFG80211 + help + The nl80211 testmode command helps implementing things like + factory calibration or validation tools for wireless chips. + + Select this option ONLY for kernels that are specifically + built for such purposes. + + Debugging tools that are supposed to end up in the hands of + users should better be implemented with debugfs. + + Say N. + config CFG80211_REG_DEBUG bool "cfg80211 regulatory debugging" depends on CFG80211 diff --git a/net/wireless/core.h b/net/wireless/core.h index bfa340c..bc084b6 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -58,6 +58,10 @@ struct cfg80211_registered_device { struct cfg80211_scan_request *scan_req; /* protected by RTNL */ unsigned long suspend_at; +#ifdef CONFIG_NL80211_TESTMODE + struct genl_info *testmode_info; +#endif + #ifdef CONFIG_CFG80211_DEBUGFS /* Debugfs entries */ struct wiphy_debugfsdentries { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 01523ba..bb8de26 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3416,6 +3416,128 @@ unlock_rtnl: return err; } +#ifdef CONFIG_NL80211_TESTMODE +static struct genl_multicast_group nl80211_testmode_mcgrp = { + .name = "testmode", +}; + +static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + int err; + + if (!info->attrs[NL80211_ATTR_TESTDATA]) + return -EINVAL; + + rtnl_lock(); + + rdev = cfg80211_get_dev_from_info(info); + if (IS_ERR(rdev)) { + err = PTR_ERR(rdev); + goto unlock_rtnl; + } + + err = -EOPNOTSUPP; + if (rdev->ops->testmode_cmd) { + rdev->testmode_info = info; + err = rdev->ops->testmode_cmd(&rdev->wiphy, + nla_data(info->attrs[NL80211_ATTR_TESTDATA]), + nla_len(info->attrs[NL80211_ATTR_TESTDATA])); + rdev->testmode_info = NULL; + } + + cfg80211_put_dev(rdev); + + unlock_rtnl: + rtnl_unlock(); + return err; +} + +static struct sk_buff * +__cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, + int approxlen, u32 pid, u32 seq, gfp_t gfp) +{ + struct sk_buff *skb; + void *hdr; + struct nlattr *data; + + skb = nlmsg_new(approxlen + 100, gfp); + if (!skb) + return NULL; + + hdr = nl80211hdr_put(skb, pid, seq, 0, NL80211_CMD_TESTMODE); + if (!hdr) { + kfree_skb(skb); + return NULL; + } + + NLA_PUT_U32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + data = nla_nest_start(skb, NL80211_ATTR_TESTDATA); + + ((void **)skb->cb)[0] = rdev; + ((void **)skb->cb)[1] = hdr; + ((void **)skb->cb)[2] = data; + + return skb; + + nla_put_failure: + kfree_skb(skb); + return NULL; +} + +struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, + int approxlen) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + if (WARN_ON(!rdev->testmode_info)) + return NULL; + + return __cfg80211_testmode_alloc_skb(rdev, approxlen, + rdev->testmode_info->snd_pid, + rdev->testmode_info->snd_seq, + GFP_KERNEL); +} +EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb); + +int cfg80211_testmode_reply(struct sk_buff *skb) +{ + struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; + void *hdr = ((void **)skb->cb)[1]; + struct nlattr *data = ((void **)skb->cb)[2]; + + if (WARN_ON(!rdev->testmode_info)) { + kfree_skb(skb); + return -EINVAL; + } + + nla_nest_end(skb, data); + genlmsg_end(skb, hdr); + return genlmsg_reply(skb, rdev->testmode_info); +} +EXPORT_SYMBOL(cfg80211_testmode_reply); + +struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, + int approxlen, gfp_t gfp) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp); +} +EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb); + +void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) +{ + void *hdr = ((void **)skb->cb)[1]; + struct nlattr *data = ((void **)skb->cb)[2]; + + nla_nest_end(skb, data); + genlmsg_end(skb, hdr); + genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp); +} +EXPORT_SYMBOL(cfg80211_testmode_event); +#endif + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -3629,6 +3751,14 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, +#ifdef CONFIG_NL80211_TESTMODE + { + .cmd = NL80211_CMD_TESTMODE, + .doit = nl80211_testmode_do, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, +#endif }; static struct genl_multicast_group nl80211_mlme_mcgrp = { .name = "mlme", @@ -4102,6 +4232,12 @@ int nl80211_init(void) if (err) goto err_out; +#ifdef CONFIG_NL80211_TESTMODE + err = genl_register_mc_group(&nl80211_fam, &nl80211_testmode_mcgrp); + if (err) + goto err_out; +#endif + return 0; err_out: genl_unregister_family(&nl80211_fam); -- cgit v0.10.2 From 3f65b24536996ac493777ef11474c47e1d3f56a0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:52 +0200 Subject: mac80211: remove an unused function declaration The ieee80211_scan_results function hasn't existed for a long time now, so its declaration should be removed as well. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e0323e5..1950e2e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -981,9 +981,6 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, const u8 *ssid, u8 ssid_len); int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req); -int ieee80211_scan_results(struct ieee80211_local *local, - struct iw_request_info *info, - char *buf, size_t len); void ieee80211_scan_cancel(struct ieee80211_local *local); ieee80211_rx_result ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -- cgit v0.10.2 From 6a669e65c5ec393a650362874e13f7d3365a7827 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:53 +0200 Subject: wireless: define AKM suites We'll need these values for some drivers using connect API and for wext compat code, so let's define them. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index a9173d5..23343ab 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1196,6 +1196,10 @@ enum ieee80211_sa_query_action { #define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 #define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 +/* AKM suite selectors */ +#define WLAN_AKM_SUITE_8021X 0x000FAC01 +#define WLAN_AKM_SUITE_PSK 0x000FAC02 + #define WLAN_MAX_KEY_LEN 32 /** -- cgit v0.10.2 From b23aa676ab9d54469cda9f7151f51a2851c6f36e Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 1 Jul 2009 21:26:54 +0200 Subject: cfg80211: connect/disconnect API This patch introduces the cfg80211 connect/disconnect API. The goal here is to run the AUTH and ASSOC steps in one call. This is needed for some fullmac cards that run both steps directly from the target, after the host driver sends a connect command. Additionally, all the new crypto parameters for connect() are now also valid for associate() -- although associate requires the IEs to be used, the information can be useful for drivers and should be given. Signed-off-by: Samuel Ortiz Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 651b188..b34c17f 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -246,6 +246,22 @@ * to identify the device, and the TESTDATA blob attribute to pass through * to the driver. * + * @NL80211_CMD_CONNECT: connection request and notification; this command + * requests to connect to a specified network but without separating + * auth and assoc steps. For this, you need to specify the SSID in a + * %NL80211_ATTR_SSID attribute, and can optionally specify the association + * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC, + * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT. + * It is also sent as an event, with the BSSID and response IEs when the + * connection is established or failed to be established. This can be + * determined by the STATUS_CODE attribute. + * @NL80211_CMD_ROAM: request that the card roam (currently not implemented), + * sent as an event when the card/driver roamed by itself. + * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify + * userspace that a connection was dropped by the AP or due to other + * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and + * %NL80211_ATTR_REASON_CODE attributes are used. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -316,6 +332,10 @@ enum nl80211_commands { NL80211_CMD_TESTMODE, + NL80211_CMD_CONNECT, + NL80211_CMD_ROAM, + NL80211_CMD_DISCONNECT, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -520,6 +540,30 @@ enum nl80211_commands { * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. * We recommend using nested, driver-specific attributes within this. * + * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT + * event was due to the AP disconnecting the station, and not due to + * a local disconnect request. + * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT + * event (u16) + * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating + * that protected APs should be used. + * + * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to + * indicate which unicast key ciphers will be used with the connection + * (an array of u32). + * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate + * which group key cipher will be used with the connection (a u32). + * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate + * which WPA version(s) the AP we want to associate with is using + * (a u32 with flags from &enum nl80211_wpa_versions). + * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate + * which key management algorithm(s) to use (an array of u32). + * + * @NL80211_ATTR_REQ_IE: (Re)association request information elements as + * sent out by the card, for ROAM and successful CONNECT events. + * @NL80211_ATTR_RESP_IE: (Re)association response information elements as + * sent by peer, for ROAM and successful CONNECT events. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -630,6 +674,19 @@ enum nl80211_attrs { NL80211_ATTR_TESTDATA, + NL80211_ATTR_PRIVACY, + + NL80211_ATTR_DISCONNECTED_BY_AP, + NL80211_ATTR_STATUS_CODE, + + NL80211_ATTR_CIPHER_SUITES_PAIRWISE, + NL80211_ATTR_CIPHER_SUITE_GROUP, + NL80211_ATTR_WPA_VERSIONS, + NL80211_ATTR_AKM_SUITES, + + NL80211_ATTR_REQ_IE, + NL80211_ATTR_RESP_IE, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -640,6 +697,7 @@ enum nl80211_attrs { * Allow user space programs to use #ifdef on new attributes by defining them * here */ +#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY #define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES #define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS @@ -653,6 +711,10 @@ enum nl80211_attrs { #define NL80211_ATTR_SSID NL80211_ATTR_SSID #define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE #define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE +#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE +#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP +#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS +#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_REG_RULES 32 @@ -661,6 +723,9 @@ enum nl80211_attrs { #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 #define NL80211_HT_CAPABILITY_LEN 26 +#define NL80211_MAX_NR_CIPHER_SUITES 5 +#define NL80211_MAX_NR_AKM_SUITES 2 + /** * enum nl80211_iftype - (virtual) interface types * @@ -1205,12 +1270,22 @@ enum nl80211_bss { * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only) * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) + * @__NL80211_AUTHTYPE_NUM: internal + * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm + * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by + * trying multiple times); this is invalid in netlink -- leave out + * the attribute for this on CONNECT commands. */ enum nl80211_auth_type { NL80211_AUTHTYPE_OPEN_SYSTEM, NL80211_AUTHTYPE_SHARED_KEY, NL80211_AUTHTYPE_FT, NL80211_AUTHTYPE_NETWORK_EAP, + + /* keep last */ + __NL80211_AUTHTYPE_NUM, + NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1, + NL80211_AUTHTYPE_AUTOMATIC }; /** @@ -1235,4 +1310,9 @@ enum nl80211_mfp { NL80211_MFP_REQUIRED, }; +enum nl80211_wpa_versions { + NL80211_WPA_VERSION_1 = 1 << 0, + NL80211_WPA_VERSION_2 = 1 << 1, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 885d4e5..68e1132 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -605,6 +605,30 @@ struct cfg80211_bss { }; /** + * struct cfg80211_crypto_settings - Crypto settings + * @wpa_versions: indicates which, if any, WPA versions are enabled + * (from enum nl80211_wpa_versions) + * @cipher_group: group key cipher suite (or 0 if unset) + * @n_ciphers_pairwise: number of AP supported unicast ciphers + * @ciphers_pairwise: unicast key cipher suites + * @n_akm_suites: number of AKM suites + * @akm_suites: AKM suites + * @control_port: Whether user space controls IEEE 802.1X port, i.e., + * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is + * required to assume that the port is unauthorized until authorized by + * user space. Otherwise, port is marked authorized by default. + */ +struct cfg80211_crypto_settings { + u32 wpa_versions; + u32 cipher_group; + int n_ciphers_pairwise; + u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES]; + int n_akm_suites; + u32 akm_suites[NL80211_MAX_NR_AKM_SUITES]; + bool control_port; +}; + +/** * struct cfg80211_auth_request - Authentication request data * * This structure provides information needed to complete IEEE 802.11 @@ -658,10 +682,7 @@ struct cfg80211_auth_request { * @ie: Extra IEs to add to (Re)Association Request frame or %NULL * @ie_len: Length of ie buffer in octets * @use_mfp: Use management frame protection (IEEE 802.11w) in this association - * @control_port: Whether user space controls IEEE 802.1X port, i.e., - * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is - * required to assume that the port is unauthorized until authorized by - * user space. Otherwise, port is marked authorized by default. + * @crypto: crypto settings */ struct cfg80211_assoc_request { struct ieee80211_channel *chan; @@ -671,7 +692,7 @@ struct cfg80211_assoc_request { const u8 *ie; size_t ie_len; bool use_mfp; - bool control_port; + struct cfg80211_crypto_settings crypto; }; /** @@ -738,6 +759,36 @@ struct cfg80211_ibss_params { }; /** + * struct cfg80211_connect_params - Connection parameters + * + * This structure provides information needed to complete IEEE 802.11 + * authentication and association. + * + * @channel: The channel to use or %NULL if not specified (auto-select based + * on scan results) + * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan + * results) + * @ssid: SSID + * @ssid_len: Length of ssid in octets + * @auth_type: Authentication type (algorithm) + * @assoc_ie: IEs for association request + * @assoc_ie_len: Length of assoc_ie in octets + * @privacy: indicates whether privacy-enabled APs should be used + * @crypto: crypto settings + */ +struct cfg80211_connect_params { + struct ieee80211_channel *channel; + u8 *bssid; + u8 *ssid; + size_t ssid_len; + enum nl80211_auth_type auth_type; + u8 *ie; + size_t ie_len; + bool privacy; + struct cfg80211_crypto_settings crypto; +}; + +/** * enum wiphy_params_flags - set_wiphy_params bitfield values * WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed * WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed @@ -841,6 +892,12 @@ enum tx_power_setting { * @deauth: Request to deauthenticate from the specified peer * @disassoc: Request to disassociate from the specified peer * + * @connect: Connect to the ESS with the specified parameters. When connected, + * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. + * If the connection fails for some reason, call cfg80211_connect_result() + * with the status from the AP. + * @disconnect: Disconnect from the BSS/ESS. + * * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call * cfg80211_ibss_joined(), also call that function when changing BSSID due * to a merge. @@ -946,6 +1003,11 @@ struct cfg80211_ops { int (*disassoc)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req); + int (*connect)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme); + int (*disconnect)(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code); + int (*join_ibss)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params); int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); @@ -1174,10 +1236,15 @@ struct wireless_dev { struct list_head list; struct net_device *netdev; - /* currently used for IBSS - might be rearranged in the future */ + /* currently used for IBSS and SME - might be rearranged later */ struct cfg80211_bss *current_bss; u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; + enum { + CFG80211_SME_IDLE, + CFG80211_SME_CONNECTING, /* ->connect called */ + CFG80211_SME_CONNECTED, + } sme_state; #ifdef CONFIG_WIRELESS_EXT /* wext data */ @@ -1788,4 +1855,60 @@ void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp); #define CFG80211_TESTMODE_CMD(cmd) #endif +/** + * cfg80211_connect_result - notify cfg80211 of connection result + * + * @dev: network device + * @bssid: the BSSID of the AP + * @req_ie: association request IEs (maybe be %NULL) + * @req_ie_len: association request IEs length + * @resp_ie: association response IEs (may be %NULL) + * @resp_ie_len: assoc response IEs length + * @status: status code, 0 for successful connection, use + * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you + * the real status code for failures. + * @gfp: allocation flags + * + * It should be called by the underlying driver whenever connect() has + * succeeded. + */ +void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, gfp_t gfp); + +/** + * cfg80211_roamed - notify cfg80211 of roaming + * + * @dev: network device + * @bssid: the BSSID of the new AP + * @req_ie: association request IEs (maybe be %NULL) + * @req_ie_len: association request IEs length + * @resp_ie: association response IEs (may be %NULL) + * @resp_ie_len: assoc response IEs length + * @gfp: allocation flags + * + * It should be called by the underlying driver whenever it roamed + * from one AP to another while connected. + */ +void cfg80211_roamed(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp); + +/** + * cfg80211_disconnected - notify cfg80211 that connection was dropped + * + * @dev: network device + * @ie: information elements of the deauth/disassoc frame (may be %NULL) + * @ie_len: length of IEs + * @reason: reason code for the disconnection, set it to 0 if unknown + * @gfp: allocation flags + * + * After it calls this function, the driver should enter an idle state + * and not try to connect to any AP any more. + */ +void cfg80211_disconnected(struct net_device *dev, u16 reason, + u8 *ie, size_t ie_len, gfp_t gfp); + + #endif /* __NET_CFG80211_H */ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c34c1a4..03de402 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1262,7 +1262,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; } - if (req->control_port) + if (req->crypto.control_port) sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; else sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; diff --git a/net/wireless/Makefile b/net/wireless/Makefile index f78c483..750c08e 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o -cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o +cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o diff --git a/net/wireless/core.c b/net/wireless/core.c index d41b741..314e00f 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -546,6 +546,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, "symlink to netdev!\n"); } wdev->netdev = dev; + wdev->sme_state = CFG80211_SME_IDLE; #ifdef CONFIG_WIRELESS_EXT wdev->wext.default_key = -1; wdev->wext.default_mgmt_key = -1; @@ -553,11 +554,20 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, mutex_unlock(&rdev->devlist_mtx); break; case NETDEV_GOING_DOWN: - if (wdev->iftype != NL80211_IFTYPE_ADHOC) - break; if (!wdev->ssid_len) break; - cfg80211_leave_ibss(rdev, dev, true); + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + cfg80211_leave_ibss(rdev, dev, true); + break; + case NL80211_IFTYPE_STATION: + cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING); + break; + default: + break; + } break; case NETDEV_UP: #ifdef CONFIG_WIRELESS_EXT diff --git a/net/wireless/core.h b/net/wireless/core.h index bc084b6..f93f96f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -174,6 +174,13 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext); int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, bool nowext); +/* SME */ +int cfg80211_connect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_connect_params *connect); +int cfg80211_disconnect(struct cfg80211_registered_device *rdev, + struct net_device *dev, u16 reason); + /* internal helpers */ int cfg80211_validate_key_settings(struct key_params *params, int key_idx, const u8 *mac_addr); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bb8de26..89dd379 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -128,6 +128,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { .len = sizeof(struct nl80211_sta_flag_update), }, [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, + [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, + [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, + [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, }; /* IE validation */ @@ -347,6 +350,17 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(join_ibss, JOIN_IBSS); #undef CMD + + if (dev->ops->connect) { + i++; + NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT); + } + + if (dev->ops->disconnect) { + i++; + NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT); + } + nla_nest_end(msg, nl_cmds); return genlmsg_end(msg, hdr); @@ -3001,12 +3015,31 @@ static int nl80211_dump_scan(struct sk_buff *skb, static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) { - return auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM || - auth_type == NL80211_AUTHTYPE_SHARED_KEY || - auth_type == NL80211_AUTHTYPE_FT || - auth_type == NL80211_AUTHTYPE_NETWORK_EAP; + return auth_type <= NL80211_AUTHTYPE_MAX; +} + +static bool nl80211_valid_wpa_versions(u32 wpa_versions) +{ + return !(wpa_versions & ~(NL80211_WPA_VERSION_1 | + NL80211_WPA_VERSION_2)); +} + +static bool nl80211_valid_akm_suite(u32 akm) +{ + return akm == WLAN_AKM_SUITE_8021X || + akm == WLAN_AKM_SUITE_PSK; +} + +static bool nl80211_valid_cipher_suite(u32 cipher) +{ + return cipher == WLAN_CIPHER_SUITE_WEP40 || + cipher == WLAN_CIPHER_SUITE_WEP104 || + cipher == WLAN_CIPHER_SUITE_TKIP || + cipher == WLAN_CIPHER_SUITE_CCMP || + cipher == WLAN_CIPHER_SUITE_AES_CMAC; } + static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; @@ -3086,6 +3119,68 @@ unlock_rtnl: return err; } +static int nl80211_crypto_settings(struct genl_info *info, + struct cfg80211_crypto_settings *settings) +{ + settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; + + if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { + void *data; + int len, i; + + data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]); + len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]); + settings->n_ciphers_pairwise = len / sizeof(u32); + + if (len % sizeof(u32)) + return -EINVAL; + + if (settings->n_ciphers_pairwise > NL80211_MAX_NR_CIPHER_SUITES) + return -EINVAL; + + memcpy(settings->ciphers_pairwise, data, len); + + for (i = 0; i < settings->n_ciphers_pairwise; i++) + if (!nl80211_valid_cipher_suite( + settings->ciphers_pairwise[i])) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) { + settings->cipher_group = + nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]); + if (!nl80211_valid_cipher_suite(settings->cipher_group)) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) { + settings->wpa_versions = + nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]); + if (!nl80211_valid_wpa_versions(settings->wpa_versions)) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_AKM_SUITES]) { + void *data; + int len, i; + + data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]); + len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]); + settings->n_akm_suites = len / sizeof(u32); + + if (len % sizeof(u32)) + return -EINVAL; + + memcpy(settings->akm_suites, data, len); + + for (i = 0; i < settings->n_ciphers_pairwise; i++) + if (!nl80211_valid_akm_suite(settings->akm_suites[i])) + return -EINVAL; + } + + return 0; +} + static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; @@ -3156,9 +3251,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) } } - req.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; - - err = drv->ops->assoc(&drv->wiphy, dev, &req); + err = nl80211_crypto_settings(info, &req.crypto); + if (!err) + err = drv->ops->assoc(&drv->wiphy, dev, &req); out: cfg80211_put_dev(drv); @@ -3538,6 +3633,130 @@ void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) EXPORT_SYMBOL(cfg80211_testmode_event); #endif +static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + struct net_device *dev; + struct cfg80211_connect_params connect; + struct wiphy *wiphy; + int err; + + memset(&connect, 0, sizeof(connect)); + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_SSID] || + !nla_len(info->attrs[NL80211_ATTR_SSID])) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { + connect.auth_type = + nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); + if (!nl80211_valid_auth_type(connect.auth_type)) + return -EINVAL; + } else + connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; + + connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; + + err = nl80211_crypto_settings(info, &connect.crypto); + if (err) + return err; + rtnl_lock(); + + err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + if (err) + goto unlock_rtnl; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + err = -EOPNOTSUPP; + goto out; + } + + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + wiphy = &drv->wiphy; + + connect.bssid = NULL; + connect.channel = NULL; + connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; + + if (info->attrs[NL80211_ATTR_MAC]) + connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); + + if (info->attrs[NL80211_ATTR_IE]) { + connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]); + connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + + if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { + connect.channel = + ieee80211_get_channel(wiphy, + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); + if (!connect.channel || + connect.channel->flags & IEEE80211_CHAN_DISABLED) { + err = -EINVAL; + goto out; + } + } + + err = cfg80211_connect(drv, dev, &connect); + +out: + cfg80211_put_dev(drv); + dev_put(dev); +unlock_rtnl: + rtnl_unlock(); + return err; +} + +static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + struct net_device *dev; + int err; + u16 reason; + + if (!info->attrs[NL80211_ATTR_REASON_CODE]) + reason = WLAN_REASON_DEAUTH_LEAVING; + else + reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + + if (reason == 0) + return -EINVAL; + + rtnl_lock(); + + err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + if (err) + goto unlock_rtnl; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + err = -EOPNOTSUPP; + goto out; + } + + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + err = cfg80211_disconnect(drv, dev, reason); + +out: + cfg80211_put_dev(drv); + dev_put(dev); +unlock_rtnl: + rtnl_unlock(); + return err; +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -3759,6 +3978,18 @@ static struct genl_ops nl80211_ops[] = { .flags = GENL_ADMIN_PERM, }, #endif + { + .cmd = NL80211_CMD_CONNECT, + .doit = nl80211_connect, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_DISCONNECT, + .doit = nl80211_disconnect, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { .name = "mlme", @@ -4077,6 +4308,129 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, addr, gfp); } +void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + if (bssid) + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); + NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status); + if (req_ie) + NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie); + if (resp_ie) + NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); + +} + +void nl80211_send_roamed(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); + if (req_ie) + NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie); + if (resp_ie) + NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); + +} + +void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u16 reason, + u8 *ie, size_t ie_len, bool from_ap, gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + if (from_ap && reason) + NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason); + if (from_ap) + NLA_PUT_FLAG(msg, NL80211_ATTR_DISCONNECTED_BY_AP); + if (ie) + NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); + +} + void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *bssid, gfp_t gfp) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 662c216..cf3708b 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -31,6 +31,19 @@ void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *addr, gfp_t gfp); +void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, gfp_t gfp); +void nl80211_send_roamed(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp); +void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u16 reason, + u8 *ie, size_t ie_len, bool from_ap, gfp_t gfp); + void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *addr, diff --git a/net/wireless/sme.c b/net/wireless/sme.c new file mode 100644 index 0000000..fc11703 --- /dev/null +++ b/net/wireless/sme.c @@ -0,0 +1,224 @@ +/* + * SME code for cfg80211's connect emulation. + * + * Copyright 2009 Johannes Berg + * Copyright (C) 2009 Intel Corporation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include "nl80211.h" + + +void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_bss *bss; +#ifdef CONFIG_WIRELESS_EXT + union iwreq_data wrqu; +#endif + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return; + + if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING)) + return; + + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(wdev->current_bss); + wdev->current_bss = NULL; + } + + if (status == WLAN_STATUS_SUCCESS) { + bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, + wdev->ssid, wdev->ssid_len, + WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); + + if (WARN_ON(!bss)) + return; + + cfg80211_hold_bss(bss); + wdev->current_bss = bss; + + wdev->sme_state = CFG80211_SME_CONNECTED; + } else { + wdev->sme_state = CFG80211_SME_IDLE; + } + + nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, bssid, + req_ie, req_ie_len, resp_ie, resp_ie_len, + status, gfp); + +#ifdef CONFIG_WIRELESS_EXT + if (req_ie && status == WLAN_STATUS_SUCCESS) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = req_ie_len; + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); + } + + if (resp_ie && status == WLAN_STATUS_SUCCESS) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = resp_ie_len; + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); + } + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if (bssid) + memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +#endif +} +EXPORT_SYMBOL(cfg80211_connect_result); + +void cfg80211_roamed(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_bss *bss; +#ifdef CONFIG_WIRELESS_EXT + union iwreq_data wrqu; +#endif + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return; + + if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED)) + return; + + /* internal error -- how did we get to CONNECTED w/o BSS? */ + if (WARN_ON(!wdev->current_bss)) { + return; + } + + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(wdev->current_bss); + wdev->current_bss = NULL; + + bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, + wdev->ssid, wdev->ssid_len, + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + + if (WARN_ON(!bss)) + return; + + cfg80211_hold_bss(bss); + wdev->current_bss = bss; + + nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, + req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); + +#ifdef CONFIG_WIRELESS_EXT + if (req_ie) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = req_ie_len; + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); + } + + if (resp_ie) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = resp_ie_len; + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); + } + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +#endif +} +EXPORT_SYMBOL(cfg80211_roamed); + +static void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, + u8 *ie, size_t ie_len, u16 reason, + bool from_ap) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; +#ifdef CONFIG_WIRELESS_EXT + union iwreq_data wrqu; +#endif + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return; + + if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED)) + return; + + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(wdev->current_bss); + } + + wdev->current_bss = NULL; + wdev->sme_state = CFG80211_SME_IDLE; + + nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, + reason, ie, ie_len, from_ap, gfp); + +#ifdef CONFIG_WIRELESS_EXT + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +#endif +} + +void cfg80211_disconnected(struct net_device *dev, u16 reason, + u8 *ie, size_t ie_len, gfp_t gfp) +{ + __cfg80211_disconnected(dev, reason, ie, ie_len, true, gfp); +} +EXPORT_SYMBOL(cfg80211_disconnected); + +int cfg80211_connect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_connect_params *connect) +{ + int err; + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (wdev->sme_state != CFG80211_SME_IDLE) + return -EALREADY; + + if (!rdev->ops->connect) { + return -EOPNOTSUPP; + } else { + wdev->sme_state = CFG80211_SME_CONNECTING; + err = rdev->ops->connect(&rdev->wiphy, dev, connect); + if (err) { + wdev->sme_state = CFG80211_SME_IDLE; + return err; + } + } + + memcpy(wdev->ssid, connect->ssid, connect->ssid_len); + wdev->ssid_len = connect->ssid_len; + + return 0; +} + +int cfg80211_disconnect(struct cfg80211_registered_device *rdev, + struct net_device *dev, u16 reason) +{ + int err; + + if (!rdev->ops->disconnect) { + return -EOPNOTSUPP; + } else { + err = rdev->ops->disconnect(&rdev->wiphy, dev, reason); + if (err) + return err; + } + + __cfg80211_disconnected(dev, 0, NULL, 0, false, GFP_KERNEL); + + return 0; +} -- cgit v0.10.2 From 6829c878ecd24ff0ae41b4668c7e9d0f11b66942 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Jul 2009 09:13:27 +0200 Subject: cfg80211: emulate connect with auth/assoc This adds code to cfg80211 so that drivers (mac80211 right now) that don't implement connect but rather auth/assoc can still be used with the nl80211 connect command. This will also be necessary for the wext compat code. Signed-off-by: Samuel Ortiz Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 68e1132..24fab43 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1209,6 +1209,9 @@ extern void wiphy_unregister(struct wiphy *wiphy); */ extern void wiphy_free(struct wiphy *wiphy); +/* internal struct */ +struct cfg80211_conn; + /** * struct wireless_dev - wireless per-netdev state * @@ -1242,9 +1245,10 @@ struct wireless_dev { u8 ssid_len; enum { CFG80211_SME_IDLE, - CFG80211_SME_CONNECTING, /* ->connect called */ + CFG80211_SME_CONNECTING, CFG80211_SME_CONNECTED, } sme_state; + struct cfg80211_conn *conn; #ifdef CONFIG_WIRELESS_EXT /* wext data */ diff --git a/net/wireless/core.c b/net/wireless/core.c index 314e00f..a0a6797 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -321,6 +321,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) } INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work); + INIT_WORK(&drv->conn_work, cfg80211_conn_work); /* * Initialize wiphy parameters to IEEE 802.11 MIB default values. @@ -481,6 +482,8 @@ void wiphy_unregister(struct wiphy *wiphy) /* unlock again before freeing */ mutex_unlock(&drv->mtx); + cancel_work_sync(&drv->conn_work); + cfg80211_debugfs_drv_del(drv); /* If this device got a regulatory hint tell core its @@ -569,6 +572,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; } break; + case NETDEV_DOWN: + kfree(wdev->conn); + wdev->conn = NULL; + break; case NETDEV_UP: #ifdef CONFIG_WIRELESS_EXT if (wdev->iftype != NL80211_IFTYPE_ADHOC) diff --git a/net/wireless/core.h b/net/wireless/core.h index f93f96f..2c0f642 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -62,6 +62,8 @@ struct cfg80211_registered_device { struct genl_info *testmode_info; #endif + struct work_struct conn_work; + #ifdef CONFIG_CFG80211_DEBUGFS /* Debugfs entries */ struct wiphy_debugfsdentries { @@ -181,8 +183,14 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, int cfg80211_disconnect(struct cfg80211_registered_device *rdev, struct net_device *dev, u16 reason); +void cfg80211_conn_work(struct work_struct *work); + /* internal helpers */ int cfg80211_validate_key_settings(struct key_params *params, int key_idx, const u8 *mac_addr); +void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, + size_t ie_len, u16 reason, bool from_ap); +void cfg80211_sme_scan_done(struct net_device *dev); +void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index c4e6d4b..3427fe7 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -16,58 +16,105 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gf { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + nl80211_send_rx_auth(rdev, dev, buf, len, gfp); + cfg80211_sme_rx_auth(dev, buf, len); } EXPORT_SYMBOL(cfg80211_send_rx_auth); void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) { - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + u16 status_code; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + u8 *ie = mgmt->u.assoc_resp.variable; + int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); + + status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); + nl80211_send_rx_assoc(rdev, dev, buf, len, gfp); + + cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, + status_code, gfp); } EXPORT_SYMBOL(cfg80211_send_rx_assoc); void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) { - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + nl80211_send_deauth(rdev, dev, buf, len, gfp); + + if (wdev->sme_state == CFG80211_SME_CONNECTED) { + u16 reason_code; + bool from_ap; + + reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); + + from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; + __cfg80211_disconnected(dev, gfp, NULL, 0, + reason_code, from_ap); + + wdev->sme_state = CFG80211_SME_IDLE; + } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { + cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); + } } EXPORT_SYMBOL(cfg80211_send_deauth); void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) { - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + nl80211_send_disassoc(rdev, dev, buf, len, gfp); -} -EXPORT_SYMBOL(cfg80211_send_disassoc); -static void cfg80211_wext_disconnected(struct net_device *dev) -{ -#ifdef CONFIG_WIRELESS_EXT - union iwreq_data wrqu; - memset(&wrqu, 0, sizeof(wrqu)); - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); -#endif + if (wdev->sme_state == CFG80211_SME_CONNECTED) { + u16 reason_code; + bool from_ap; + + reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); + + from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; + __cfg80211_disconnected(dev, gfp, NULL, 0, + reason_code, from_ap); + + wdev->sme_state = CFG80211_SME_IDLE; + } } +EXPORT_SYMBOL(cfg80211_send_disassoc); void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) { - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); nl80211_send_auth_timeout(rdev, dev, addr, gfp); - cfg80211_wext_disconnected(dev); + if (wdev->sme_state == CFG80211_SME_CONNECTING) + cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); + wdev->sme_state = CFG80211_SME_IDLE; } EXPORT_SYMBOL(cfg80211_send_auth_timeout); void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) { - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); nl80211_send_assoc_timeout(rdev, dev, addr, gfp); - cfg80211_wext_disconnected(dev); + if (wdev->sme_state == CFG80211_SME_CONNECTING) + cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); + wdev->sme_state = CFG80211_SME_IDLE; } EXPORT_SYMBOL(cfg80211_send_assoc_timeout); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 89dd379..89aa9e7 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -351,12 +351,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, #undef CMD - if (dev->ops->connect) { + if (dev->ops->connect || dev->ops->auth) { i++; NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT); } - if (dev->ops->disconnect) { + if (dev->ops->disconnect || dev->ops->deauth) { i++; NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT); } diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 261a063..82b33e7 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -30,6 +30,13 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); + /* + * This must be before sending the other events! + * Otherwise, wpa_supplicant gets completely confused with + * wext events. + */ + cfg80211_sme_scan_done(dev); + if (aborted) nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); else diff --git a/net/wireless/sme.c b/net/wireless/sme.c index fc11703..3abb047 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -12,6 +12,266 @@ #include #include "nl80211.h" +struct cfg80211_conn { + struct cfg80211_connect_params params; + /* these are sub-states of the _CONNECTING sme_state */ + enum { + CFG80211_CONN_IDLE, + CFG80211_CONN_SCANNING, + CFG80211_CONN_SCAN_AGAIN, + CFG80211_CONN_AUTHENTICATE_NEXT, + CFG80211_CONN_AUTHENTICATING, + CFG80211_CONN_ASSOCIATE_NEXT, + CFG80211_CONN_ASSOCIATING, + } state; + u8 bssid[ETH_ALEN]; + u8 *ie; + size_t ie_len; + bool auto_auth; +}; + + +static int cfg80211_conn_scan(struct wireless_dev *wdev) +{ + struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); + struct cfg80211_scan_request *request; + int n_channels, err; + + ASSERT_RTNL(); + + if (drv->scan_req) + return -EBUSY; + + if (wdev->conn->params.channel) { + n_channels = 1; + } else { + enum ieee80211_band band; + n_channels = 0; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!wdev->wiphy->bands[band]) + continue; + n_channels += wdev->wiphy->bands[band]->n_channels; + } + } + request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) + + sizeof(request->channels[0]) * n_channels, + GFP_KERNEL); + if (!request) + return -ENOMEM; + + request->channels = (void *)((char *)request + sizeof(*request)); + if (wdev->conn->params.channel) + request->channels[0] = wdev->conn->params.channel; + else { + int i = 0, j; + enum ieee80211_band band; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!wdev->wiphy->bands[band]) + continue; + for (j = 0; j < wdev->wiphy->bands[band]->n_channels; + i++, j++) + request->channels[i] = + &wdev->wiphy->bands[band]->channels[j]; + } + } + request->n_channels = n_channels; + request->ssids = (void *)(request->channels + n_channels); + request->n_ssids = 1; + + memcpy(request->ssids[0].ssid, wdev->conn->params.ssid, + wdev->conn->params.ssid_len); + request->ssids[0].ssid_len = wdev->conn->params.ssid_len; + + request->ifidx = wdev->netdev->ifindex; + request->wiphy = &drv->wiphy; + + drv->scan_req = request; + + err = drv->ops->scan(wdev->wiphy, wdev->netdev, request); + if (!err) { + wdev->conn->state = CFG80211_CONN_SCANNING; + nl80211_send_scan_start(drv, wdev->netdev); + } else { + drv->scan_req = NULL; + kfree(request); + } + return err; +} + +static int cfg80211_conn_do_work(struct wireless_dev *wdev) +{ + struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); + union { + struct cfg80211_auth_request auth_req; + struct cfg80211_assoc_request assoc_req; + } u; + + memset(&u, 0, sizeof(u)); + + if (!wdev->conn) + return 0; + + switch (wdev->conn->state) { + case CFG80211_CONN_SCAN_AGAIN: + return cfg80211_conn_scan(wdev); + case CFG80211_CONN_AUTHENTICATE_NEXT: + u.auth_req.chan = wdev->conn->params.channel; + u.auth_req.peer_addr = wdev->conn->params.bssid; + u.auth_req.ssid = wdev->conn->params.ssid; + u.auth_req.ssid_len = wdev->conn->params.ssid_len; + u.auth_req.auth_type = wdev->conn->params.auth_type; + u.auth_req.ie = NULL; + u.auth_req.ie_len = 0; + wdev->conn->state = CFG80211_CONN_AUTHENTICATING; + BUG_ON(!drv->ops->auth); + return drv->ops->auth(wdev->wiphy, wdev->netdev, &u.auth_req); + case CFG80211_CONN_ASSOCIATE_NEXT: + u.assoc_req.chan = wdev->conn->params.channel; + u.assoc_req.peer_addr = wdev->conn->params.bssid; + u.assoc_req.ssid = wdev->conn->params.ssid; + u.assoc_req.ssid_len = wdev->conn->params.ssid_len; + u.assoc_req.ie = wdev->conn->params.ie; + u.assoc_req.ie_len = wdev->conn->params.ie_len; + u.assoc_req.use_mfp = false; + memcpy(&u.assoc_req.crypto, &wdev->conn->params.crypto, + sizeof(u.assoc_req.crypto)); + wdev->conn->state = CFG80211_CONN_ASSOCIATING; + BUG_ON(!drv->ops->assoc); + return drv->ops->assoc(wdev->wiphy, wdev->netdev, + &u.assoc_req); + default: + return 0; + } +} + +void cfg80211_conn_work(struct work_struct *work) +{ + struct cfg80211_registered_device *drv = + container_of(work, struct cfg80211_registered_device, conn_work); + struct wireless_dev *wdev; + + rtnl_lock(); + mutex_lock(&drv->devlist_mtx); + + list_for_each_entry(wdev, &drv->netdev_list, list) { + if (!netif_running(wdev->netdev)) + continue; + if (wdev->sme_state != CFG80211_SME_CONNECTING) + continue; + if (cfg80211_conn_do_work(wdev)) + cfg80211_connect_result(wdev->netdev, + wdev->conn->params.bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_ATOMIC); + } + + mutex_unlock(&drv->devlist_mtx); + rtnl_unlock(); +} + +static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) +{ + struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); + struct cfg80211_bss *bss; + u16 capa = WLAN_CAPABILITY_ESS; + + if (wdev->conn->params.privacy) + capa |= WLAN_CAPABILITY_PRIVACY; + + bss = cfg80211_get_bss(wdev->wiphy, NULL, wdev->conn->params.bssid, + wdev->conn->params.ssid, + wdev->conn->params.ssid_len, + WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, + capa); + + if (!bss) + return false; + + memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN); + wdev->conn->params.bssid = wdev->conn->bssid; + wdev->conn->params.channel = bss->channel; + wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; + schedule_work(&drv->conn_work); + + cfg80211_put_bss(bss); + return true; +} + +void cfg80211_sme_scan_done(struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); + + if (wdev->sme_state != CFG80211_SME_CONNECTING) + return; + + if (WARN_ON(!wdev->conn)) + return; + + if (wdev->conn->state != CFG80211_CONN_SCANNING && + wdev->conn->state != CFG80211_CONN_SCAN_AGAIN) + return; + + if (!cfg80211_get_conn_bss(wdev)) { + /* not found */ + if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) + schedule_work(&drv->conn_work); + else + cfg80211_connect_result(dev, wdev->conn->params.bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_ATOMIC); + return; + } +} + +void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + u16 status_code = le16_to_cpu(mgmt->u.auth.status_code); + + /* should only RX auth frames when connecting */ + if (wdev->sme_state != CFG80211_SME_CONNECTING) + return; + + if (WARN_ON(!wdev->conn)) + return; + + if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG && + wdev->conn->auto_auth && + wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) { + /* select automatically between only open, shared, leap */ + switch (wdev->conn->params.auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + wdev->conn->params.auth_type = + NL80211_AUTHTYPE_SHARED_KEY; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + wdev->conn->params.auth_type = + NL80211_AUTHTYPE_NETWORK_EAP; + break; + default: + /* huh? */ + wdev->conn->params.auth_type = + NL80211_AUTHTYPE_OPEN_SYSTEM; + break; + } + wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; + schedule_work(&rdev->conn_work); + } else if (status_code != WLAN_STATUS_SUCCESS) + wdev->sme_state = CFG80211_SME_IDLE; + else if (wdev->sme_state == CFG80211_SME_CONNECTING && + wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { + wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; + schedule_work(&rdev->conn_work); + } +} void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, const u8 *req_ie, size_t req_ie_len, @@ -27,7 +287,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; - if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING)) + if (wdev->sme_state != CFG80211_SME_CONNECTING) return; if (wdev->current_bss) { @@ -53,6 +313,9 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, wdev->sme_state = CFG80211_SME_IDLE; } + if (wdev->conn) + wdev->conn->state = CFG80211_CONN_IDLE; + nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, status, gfp); @@ -72,7 +335,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, memset(&wrqu, 0, sizeof(wrqu)); wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if (bssid) + if (bssid && status == WLAN_STATUS_SUCCESS) memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); #endif @@ -138,9 +401,8 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, } EXPORT_SYMBOL(cfg80211_roamed); -static void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, - u8 *ie, size_t ie_len, u16 reason, - bool from_ap) +void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, + size_t ie_len, u16 reason, bool from_ap) { struct wireless_dev *wdev = dev->ieee80211_ptr; #ifdef CONFIG_WIRELESS_EXT @@ -161,6 +423,11 @@ static void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, wdev->current_bss = NULL; wdev->sme_state = CFG80211_SME_IDLE; + if (wdev->conn) { + kfree(wdev->conn->ie); + wdev->conn->ie = NULL; + } + nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, reason, ie, ie_len, from_ap, gfp); @@ -174,7 +441,7 @@ static void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, void cfg80211_disconnected(struct net_device *dev, u16 reason, u8 *ie, size_t ie_len, gfp_t gfp) { - __cfg80211_disconnected(dev, reason, ie, ie_len, true, gfp); + __cfg80211_disconnected(dev, gfp, ie, ie_len, reason, true); } EXPORT_SYMBOL(cfg80211_disconnected); @@ -189,7 +456,74 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, return -EALREADY; if (!rdev->ops->connect) { - return -EOPNOTSUPP; + if (!rdev->ops->auth || !rdev->ops->assoc) + return -EOPNOTSUPP; + + if (!wdev->conn) { + wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); + if (!wdev->conn) + return -ENOMEM; + } else + memset(wdev->conn, 0, sizeof(*wdev->conn)); + + /* + * Copy all parameters, and treat explicitly IEs, BSSID, SSID. + */ + memcpy(&wdev->conn->params, connect, sizeof(*connect)); + if (connect->bssid) { + wdev->conn->params.bssid = wdev->conn->bssid; + memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN); + } + + if (connect->ie) { + wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, + GFP_KERNEL); + wdev->conn->params.ie = wdev->conn->ie; + if (!wdev->conn->ie) + return -ENOMEM; + } + + if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { + wdev->conn->auto_auth = true; + /* start with open system ... should mostly work */ + wdev->conn->params.auth_type = + NL80211_AUTHTYPE_OPEN_SYSTEM; + } else { + wdev->conn->auto_auth = false; + } + + memcpy(wdev->ssid, connect->ssid, connect->ssid_len); + wdev->ssid_len = connect->ssid_len; + wdev->conn->params.ssid = wdev->ssid; + wdev->conn->params.ssid_len = connect->ssid_len; + + /* don't care about result -- but fill bssid & channel */ + if (!wdev->conn->params.bssid || !wdev->conn->params.channel) + cfg80211_get_conn_bss(wdev); + + wdev->sme_state = CFG80211_SME_CONNECTING; + + /* we're good if we have both BSSID and channel */ + if (wdev->conn->params.bssid && wdev->conn->params.channel) { + wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; + err = cfg80211_conn_do_work(wdev); + } else { + /* otherwise we'll need to scan for the AP first */ + err = cfg80211_conn_scan(wdev); + /* + * If we can't scan right now, then we need to scan again + * after the current scan finished, since the parameters + * changed (unless we find a good AP anyway). + */ + if (err == -EBUSY) { + err = 0; + wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; + } + } + if (err) + wdev->sme_state = CFG80211_SME_IDLE; + + return err; } else { wdev->sme_state = CFG80211_SME_CONNECTING; err = rdev->ops->connect(&rdev->wiphy, dev, connect); @@ -197,28 +531,63 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, wdev->sme_state = CFG80211_SME_IDLE; return err; } - } - memcpy(wdev->ssid, connect->ssid, connect->ssid_len); - wdev->ssid_len = connect->ssid_len; + memcpy(wdev->ssid, connect->ssid, connect->ssid_len); + wdev->ssid_len = connect->ssid_len; - return 0; + return 0; + } } int cfg80211_disconnect(struct cfg80211_registered_device *rdev, struct net_device *dev, u16 reason) { + struct wireless_dev *wdev = dev->ieee80211_ptr; int err; + if (wdev->sme_state == CFG80211_SME_IDLE) + return -EINVAL; + if (!rdev->ops->disconnect) { - return -EOPNOTSUPP; + struct cfg80211_deauth_request deauth; + u8 bssid[ETH_ALEN]; + + /* internal bug. */ + if (WARN_ON(!wdev->conn)) + return -EINVAL; + + if (wdev->sme_state == CFG80211_SME_CONNECTING && + (wdev->conn->state == CFG80211_CONN_SCANNING || + wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { + wdev->sme_state = CFG80211_SME_IDLE; + return 0; + } + + if (!rdev->ops->deauth) + return -EOPNOTSUPP; + + memset(&deauth, 0, sizeof(deauth)); + + /* wdev->conn->params.bssid must be set if > SCANNING */ + memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN); + deauth.peer_addr = bssid; + deauth.reason_code = reason; + + err = rdev->ops->deauth(&rdev->wiphy, dev, &deauth); + if (err) + return err; } else { err = rdev->ops->disconnect(&rdev->wiphy, dev, reason); if (err) return err; } - __cfg80211_disconnected(dev, 0, NULL, 0, false, GFP_KERNEL); + if (wdev->sme_state == CFG80211_SME_CONNECTED) + __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, 0, false); + else if (wdev->sme_state == CFG80211_SME_CONNECTING) + cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); return 0; } -- cgit v0.10.2 From f21293549f60f88c74fcb9944737f11048896dc4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:56 +0200 Subject: cfg80211: managed mode wext compatibility This adds code to make it possible to use the cfg80211 connect() API with wireless extensions, and because the previous patch added emulation of that API with auth() and assoc(), by extension also supports wext on that. At the same time, removes code from mac80211 for wext, but doesn't yet clean up mac80211's mlme code more. Signed-off-by: Samuel Ortiz Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 24fab43..0708521 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1253,8 +1253,14 @@ struct wireless_dev { #ifdef CONFIG_WIRELESS_EXT /* wext data */ struct { - struct cfg80211_ibss_params ibss; + union { + struct cfg80211_ibss_params ibss; + struct cfg80211_connect_params connect; + }; + u8 *ie; + size_t ie_len; u8 bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; s8 default_key, default_mgmt_key; } wext; #endif @@ -1535,6 +1541,34 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra); +int cfg80211_mgd_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_mgd_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_mgd_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_mgd_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_mgd_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_mgd_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_wext_siwgenie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra); +int cfg80211_wext_siwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra); +int cfg80211_wext_giwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra); + struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 58135a5..fbb93a7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -870,70 +870,6 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, return changed; } -static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata) -{ - union iwreq_data wrqu; - - memset(&wrqu, 0, sizeof(wrqu)); - if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) - memcpy(wrqu.ap_addr.sa_data, sdata->u.mgd.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); -} - -static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - char *buf; - size_t len; - int i; - union iwreq_data wrqu; - - if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies) - return; - - buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len + - ifmgd->assocresp_ies_len), GFP_KERNEL); - if (!buf) - return; - - len = sprintf(buf, "ASSOCINFO("); - if (ifmgd->assocreq_ies) { - len += sprintf(buf + len, "ReqIEs="); - for (i = 0; i < ifmgd->assocreq_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifmgd->assocreq_ies[i]); - } - } - if (ifmgd->assocresp_ies) { - if (ifmgd->assocreq_ies) - len += sprintf(buf + len, " "); - len += sprintf(buf + len, "RespIEs="); - for (i = 0; i < ifmgd->assocresp_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifmgd->assocresp_ies[i]); - } - } - len += sprintf(buf + len, ")"); - - if (len > IW_CUSTOM_MAX) { - len = sprintf(buf, "ASSOCRESPIE="); - for (i = 0; i < ifmgd->assocresp_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifmgd->assocresp_ies[i]); - } - } - - if (len <= IW_CUSTOM_MAX) { - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = len; - wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf); - } - - kfree(buf); -} - - static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, u32 bss_info_changed) { @@ -966,7 +902,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET; memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN); - ieee80211_sta_send_associnfo(sdata); ifmgd->last_probe = jiffies; ieee80211_led_assoc(local, 1); @@ -993,8 +928,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, netif_tx_start_all_queues(sdata->dev); netif_carrier_on(sdata->dev); - - ieee80211_sta_send_apinfo(sdata); } static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) @@ -1147,8 +1080,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_ASSOC; sdata->vif.bss_conf.assoc = false; - ieee80211_sta_send_apinfo(sdata); - if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { ifmgd->state = IEEE80211_STA_MLME_DISABLED; ieee80211_rx_bss_remove(sdata, ifmgd->bssid, diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 1da81f4..d4e61dc 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -27,29 +27,6 @@ #include "aes_ccm.h" -static int ieee80211_ioctl_siwgenie(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); - if (ret && ret != -EALREADY) - return ret; - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; - sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; - sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - if (ret != -EALREADY) - ieee80211_sta_req_auth(sdata); - return 0; - } - - return -EOPNOTSUPP; -} - static int ieee80211_ioctl_siwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) @@ -61,16 +38,13 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); else if (sdata->vif.type == NL80211_IFTYPE_STATION) - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; + return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra); /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ if (freq->e == 0) { - if (freq->m < 0) { - if (sdata->vif.type == NL80211_IFTYPE_STATION) - sdata->u.mgd.flags |= - IEEE80211_STA_AUTO_CHANNEL_SEL; - return 0; - } else + if (freq->m < 0) + return -EINVAL; + else chan = ieee80211_get_channel(local->hw.wiphy, ieee80211_channel_to_frequency(freq->m)); } else { @@ -95,9 +69,6 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, if (local->oper_channel == chan) return 0; - if (sdata->vif.type == NL80211_IFTYPE_STATION) - ieee80211_sta_req_auth(sdata); - local->oper_channel = chan; local->oper_channel_type = NL80211_CHAN_NO_HT; ieee80211_hw_config(local, 0); @@ -115,6 +86,8 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); + else if (sdata->vif.type == NL80211_IFTYPE_STATION) + return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); freq->m = local->oper_channel->center_freq; freq->e = 6; @@ -128,31 +101,11 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, struct iw_point *data, char *ssid) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - size_t len = data->length; - int ret; if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); - - /* iwconfig uses nul termination in SSID.. */ - if (len > 0 && ssid[len - 1] == '\0') - len--; - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (data->flags) - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; - else - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; - - ret = ieee80211_sta_set_ssid(sdata, ssid, len); - if (ret) - return ret; - - sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; - sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - ieee80211_sta_req_auth(sdata); - return 0; - } + else if (sdata->vif.type == NL80211_IFTYPE_STATION) + return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); return -EOPNOTSUPP; } @@ -162,23 +115,14 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) { - size_t len; struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - int res = ieee80211_sta_get_ssid(sdata, ssid, &len); - if (res == 0) { - data->length = len; - data->flags = 1; - } else - data->flags = 0; - return res; - } + else if (sdata->vif.type == NL80211_IFTYPE_STATION) + return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); return -EOPNOTSUPP; } @@ -193,24 +137,10 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - int ret; + if (sdata->vif.type == NL80211_IFTYPE_STATION) + return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); - if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL | - IEEE80211_STA_AUTO_CHANNEL_SEL; - else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL; - else - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; - ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data); - if (ret) - return ret; - sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; - sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - ieee80211_sta_req_auth(sdata); - return 0; - } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { + if (sdata->vif.type == NL80211_IFTYPE_WDS) { /* * If it is necessary to update the WDS peer address * while the interface is running, then we need to do @@ -240,14 +170,10 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(&ap_addr->sa_data, sdata->u.mgd.bssid, ETH_ALEN); - } else - memset(&ap_addr->sa_data, 0, ETH_ALEN); - return 0; - } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { + if (sdata->vif.type == NL80211_IFTYPE_STATION) + return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); + + if (sdata->vif.type == NL80211_IFTYPE_WDS) { ap_addr->sa_family = ARPHRD_ETHER; memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); return 0; @@ -395,85 +321,6 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev, return 0; } -static int ieee80211_ioctl_siwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int ret = 0; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_WPA_ENABLED: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_KEY_MGMT: - case IW_AUTH_CIPHER_GROUP_MGMT: - break; - case IW_AUTH_CIPHER_PAIRWISE: - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (data->value & (IW_AUTH_CIPHER_WEP40 | - IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP)) - sdata->u.mgd.flags |= - IEEE80211_STA_TKIP_WEP_USED; - else - sdata->u.mgd.flags &= - ~IEEE80211_STA_TKIP_WEP_USED; - } - break; - case IW_AUTH_DROP_UNENCRYPTED: - sdata->drop_unencrypted = !!data->value; - break; - case IW_AUTH_PRIVACY_INVOKED: - if (sdata->vif.type != NL80211_IFTYPE_STATION) - ret = -EINVAL; - else { - sdata->u.mgd.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; - /* - * Privacy invoked by wpa_supplicant, store the - * value and allow associating to a protected - * network without having a key up front. - */ - if (data->value) - sdata->u.mgd.flags |= - IEEE80211_STA_PRIVACY_INVOKED; - } - break; - case IW_AUTH_80211_AUTH_ALG: - if (sdata->vif.type == NL80211_IFTYPE_STATION) - sdata->u.mgd.auth_algs = data->value; - else - ret = -EOPNOTSUPP; - break; - case IW_AUTH_MFP: - if (!(sdata->local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) { - ret = -EOPNOTSUPP; - break; - } - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - switch (data->value) { - case IW_AUTH_MFP_DISABLED: - sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; - break; - case IW_AUTH_MFP_OPTIONAL: - sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL; - break; - case IW_AUTH_MFP_REQUIRED: - sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; - break; - default: - ret = -EINVAL; - } - } else - ret = -EOPNOTSUPP; - break; - default: - ret = -EOPNOTSUPP; - break; - } - return ret; -} - /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) { @@ -541,28 +388,6 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev return wstats; } -static int ieee80211_ioctl_giwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int ret = 0; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_80211_AUTH_ALG: - if (sdata->vif.type == NL80211_IFTYPE_STATION) - data->value = sdata->u.mgd.auth_algs; - else - ret = -EOPNOTSUPP; - break; - default: - ret = -EOPNOTSUPP; - break; - } - return ret; -} - - /* Structures to export the Wireless Handlers */ static const iw_handler ieee80211_handler[] = @@ -615,10 +440,10 @@ static const iw_handler ieee80211_handler[] = (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ - (iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */ + (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */ (iw_handler) NULL, /* SIOCGIWGENIE */ - (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ - (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ + (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */ + (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */ (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ (iw_handler) NULL, /* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 750c08e..d74cc77 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -7,6 +7,6 @@ obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o -cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o +cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/wireless/core.c b/net/wireless/core.c index a0a6797..e2f80dd 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -553,6 +553,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, #ifdef CONFIG_WIRELESS_EXT wdev->wext.default_key = -1; wdev->wext.default_mgmt_key = -1; + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; #endif mutex_unlock(&rdev->devlist_mtx); break; @@ -565,8 +566,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, cfg80211_leave_ibss(rdev, dev, true); break; case NL80211_IFTYPE_STATION: +#ifdef CONFIG_WIRELESS_EXT + kfree(wdev->wext.ie); + wdev->wext.ie = NULL; + wdev->wext.ie_len = 0; +#endif cfg80211_disconnect(rdev, dev, - WLAN_REASON_DEAUTH_LEAVING); + WLAN_REASON_DEAUTH_LEAVING, true); break; default: break; @@ -578,11 +584,20 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; case NETDEV_UP: #ifdef CONFIG_WIRELESS_EXT - if (wdev->iftype != NL80211_IFTYPE_ADHOC) + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + if (wdev->wext.ibss.ssid_len) + cfg80211_join_ibss(rdev, dev, + &wdev->wext.ibss); break; - if (!wdev->wext.ibss.ssid_len) + case NL80211_IFTYPE_STATION: + if (wdev->wext.connect.ssid_len) + cfg80211_connect(rdev, dev, + &wdev->wext.connect); + break; + default: break; - cfg80211_join_ibss(rdev, dev, &wdev->wext.ibss); + } #endif break; case NETDEV_UNREGISTER: diff --git a/net/wireless/core.h b/net/wireless/core.h index 2c0f642..5209acb 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -181,7 +181,8 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_connect_params *connect); int cfg80211_disconnect(struct cfg80211_registered_device *rdev, - struct net_device *dev, u16 reason); + struct net_device *dev, u16 reason, + bool wextev); void cfg80211_conn_work(struct work_struct *work); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 89aa9e7..0008144 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3747,7 +3747,7 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) goto out; } - err = cfg80211_disconnect(drv, dev, reason); + err = cfg80211_disconnect(drv, dev, reason, true); out: cfg80211_put_dev(drv); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 3abb047..f272ebf 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -273,10 +273,10 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) } } -void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, - const u8 *req_ie, size_t req_ie_len, - const u8 *resp_ie, size_t resp_ie_len, - u16 status, gfp_t gfp) +static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, bool wextev, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_bss *bss; @@ -321,25 +321,36 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, status, gfp); #ifdef CONFIG_WIRELESS_EXT - if (req_ie && status == WLAN_STATUS_SUCCESS) { - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = req_ie_len; - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); - } + if (wextev) { + if (req_ie && status == WLAN_STATUS_SUCCESS) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = req_ie_len; + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); + } + + if (resp_ie && status == WLAN_STATUS_SUCCESS) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = resp_ie_len; + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); + } - if (resp_ie && status == WLAN_STATUS_SUCCESS) { memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = resp_ie_len; - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if (bssid && status == WLAN_STATUS_SUCCESS) + memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); } - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if (bssid && status == WLAN_STATUS_SUCCESS) - memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); #endif } + +void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, gfp_t gfp) +{ + bool wextev = status == WLAN_STATUS_SUCCESS; + __cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, status, wextev, gfp); +} EXPORT_SYMBOL(cfg80211_connect_result); void cfg80211_roamed(struct net_device *dev, const u8 *bssid, @@ -540,7 +551,7 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, } int cfg80211_disconnect(struct cfg80211_registered_device *rdev, - struct net_device *dev, u16 reason) + struct net_device *dev, u16 reason, bool wextev) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; @@ -585,9 +596,9 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, if (wdev->sme_state == CFG80211_SME_CONNECTED) __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, 0, false); else if (wdev->sme_state == CFG80211_SME_CONNECTING) - cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); + __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + wextev, GFP_KERNEL); return 0; } diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index cae3b52..02f052f 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -261,50 +261,6 @@ int cfg80211_wext_giwrange(struct net_device *dev, } EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); -int cfg80211_wext_siwmlme(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct iw_mlme *mlme = (struct iw_mlme *)extra; - struct cfg80211_registered_device *rdev; - union { - struct cfg80211_disassoc_request disassoc; - struct cfg80211_deauth_request deauth; - } cmd; - - if (!wdev) - return -EOPNOTSUPP; - - rdev = wiphy_to_dev(wdev->wiphy); - - if (wdev->iftype != NL80211_IFTYPE_STATION) - return -EINVAL; - - if (mlme->addr.sa_family != ARPHRD_ETHER) - return -EINVAL; - - memset(&cmd, 0, sizeof(cmd)); - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - if (!rdev->ops->deauth) - return -EOPNOTSUPP; - cmd.deauth.peer_addr = mlme->addr.sa_data; - cmd.deauth.reason_code = mlme->reason_code; - return rdev->ops->deauth(wdev->wiphy, dev, &cmd.deauth); - case IW_MLME_DISASSOC: - if (!rdev->ops->disassoc) - return -EOPNOTSUPP; - cmd.disassoc.peer_addr = mlme->addr.sa_data; - cmd.disassoc.reason_code = mlme->reason_code; - return rdev->ops->disassoc(wdev->wiphy, dev, &cmd.disassoc); - default: - return -EOPNOTSUPP; - } -} -EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme); - /** * cfg80211_wext_freq - get wext frequency for non-"auto" @@ -846,3 +802,188 @@ int cfg80211_wext_giwtxpower(struct net_device *dev, return 0; } EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower); + +static int cfg80211_set_auth_alg(struct wireless_dev *wdev, + s32 auth_alg) +{ + int nr_alg = 0; + + if (!auth_alg) + return -EINVAL; + + if (auth_alg & ~(IW_AUTH_ALG_OPEN_SYSTEM | + IW_AUTH_ALG_SHARED_KEY | + IW_AUTH_ALG_LEAP)) + return -EINVAL; + + if (auth_alg & IW_AUTH_ALG_OPEN_SYSTEM) { + nr_alg++; + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; + } + + if (auth_alg & IW_AUTH_ALG_SHARED_KEY) { + nr_alg++; + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_SHARED_KEY; + } + + if (auth_alg & IW_AUTH_ALG_LEAP) { + nr_alg++; + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_NETWORK_EAP; + } + + if (nr_alg > 1) + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; + + return 0; +} + +static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) +{ + wdev->wext.connect.crypto.wpa_versions = 0; + + if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA | + IW_AUTH_WPA_VERSION_WPA2)) + return -EINVAL; + + if (wpa_versions & IW_AUTH_WPA_VERSION_WPA) + wdev->wext.connect.crypto.wpa_versions |= + NL80211_WPA_VERSION_1; + + if (wpa_versions & IW_AUTH_WPA_VERSION_WPA2) + wdev->wext.connect.crypto.wpa_versions |= + NL80211_WPA_VERSION_2; + + return 0; +} + +int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) +{ + wdev->wext.connect.crypto.cipher_group = 0; + + if (cipher & IW_AUTH_CIPHER_WEP40) + wdev->wext.connect.crypto.cipher_group = + WLAN_CIPHER_SUITE_WEP40; + else if (cipher & IW_AUTH_CIPHER_WEP104) + wdev->wext.connect.crypto.cipher_group = + WLAN_CIPHER_SUITE_WEP104; + else if (cipher & IW_AUTH_CIPHER_TKIP) + wdev->wext.connect.crypto.cipher_group = + WLAN_CIPHER_SUITE_TKIP; + else if (cipher & IW_AUTH_CIPHER_CCMP) + wdev->wext.connect.crypto.cipher_group = + WLAN_CIPHER_SUITE_CCMP; + else if (cipher & IW_AUTH_CIPHER_AES_CMAC) + wdev->wext.connect.crypto.cipher_group = + WLAN_CIPHER_SUITE_AES_CMAC; + else + return -EINVAL; + + return 0; +} + +int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher) +{ + int nr_ciphers = 0; + u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise; + + if (cipher & IW_AUTH_CIPHER_WEP40) { + ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP40; + nr_ciphers++; + } + + if (cipher & IW_AUTH_CIPHER_WEP104) { + ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP104; + nr_ciphers++; + } + + if (cipher & IW_AUTH_CIPHER_TKIP) { + ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_TKIP; + nr_ciphers++; + } + + if (cipher & IW_AUTH_CIPHER_CCMP) { + ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_CCMP; + nr_ciphers++; + } + + if (cipher & IW_AUTH_CIPHER_AES_CMAC) { + ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_AES_CMAC; + nr_ciphers++; + } + + BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5); + + wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers; + + return 0; +} + + +int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt) +{ + int nr_akm_suites = 0; + + if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X | + IW_AUTH_KEY_MGMT_PSK)) + return -EINVAL; + + if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) { + wdev->wext.connect.crypto.akm_suites[nr_akm_suites] = + WLAN_AKM_SUITE_8021X; + nr_akm_suites++; + } + + if (key_mgt & IW_AUTH_KEY_MGMT_PSK) { + wdev->wext.connect.crypto.akm_suites[nr_akm_suites] = + WLAN_AKM_SUITE_PSK; + nr_akm_suites++; + } + + wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites; + + return 0; +} + +int cfg80211_wext_siwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + switch (data->flags & IW_AUTH_INDEX) { + case IW_AUTH_PRIVACY_INVOKED: + wdev->wext.connect.privacy = data->value; + return 0; + case IW_AUTH_WPA_VERSION: + return cfg80211_set_wpa_version(wdev, data->value); + case IW_AUTH_CIPHER_GROUP: + return cfg80211_set_cipher_group(wdev, data->value); + case IW_AUTH_KEY_MGMT: + return cfg80211_set_key_mgt(wdev, data->value); + case IW_AUTH_CIPHER_PAIRWISE: + return cfg80211_set_cipher_pairwise(wdev, data->value); + case IW_AUTH_80211_AUTH_ALG: + return cfg80211_set_auth_alg(wdev, data->value); + case IW_AUTH_WPA_ENABLED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_DROP_UNENCRYPTED: + case IW_AUTH_MFP: + return 0; + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwauth); + +int cfg80211_wext_giwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + /* XXX: what do we need? */ + + return -EOPNOTSUPP; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwauth); diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c new file mode 100644 index 0000000..3b531d5 --- /dev/null +++ b/net/wireless/wext-sme.c @@ -0,0 +1,329 @@ +/* + * cfg80211 wext compat for managed mode. + * + * Copyright 2009 Johannes Berg + * Copyright (C) 2009 Intel Corporation. All rights reserved. + */ + +#include +#include +#include +#include "nl80211.h" + +static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + int err; + + if (!netif_running(wdev->netdev)) + return 0; + + wdev->wext.connect.ie = wdev->wext.ie; + wdev->wext.connect.ie_len = wdev->wext.ie_len; + wdev->wext.connect.privacy = wdev->wext.default_key != -1; + + err = 0; + if (wdev->wext.connect.ssid_len != 0) + err = cfg80211_connect(rdev, wdev->netdev, + &wdev->wext.connect); + + return err; +} + +int cfg80211_mgd_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct ieee80211_channel *chan; + int err; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + chan = cfg80211_wext_freq(wdev->wiphy, freq); + if (chan && IS_ERR(chan)) + return PTR_ERR(chan); + + if (chan && (chan->flags & IEEE80211_CHAN_DISABLED)) + return -EINVAL; + + if (wdev->wext.connect.channel == chan) + return 0; + + if (wdev->sme_state != CFG80211_SME_IDLE) { + bool event = true; + /* if SSID set, we'll try right again, avoid event */ + if (wdev->wext.connect.ssid_len) + event = false; + err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), + dev, WLAN_REASON_DEAUTH_LEAVING, + event); + if (err) + return err; + } + + wdev->wext.connect.channel = chan; + + /* SSID is not set, we just want to switch channel */ + if (wdev->wext.connect.ssid_len && chan) { + if (!rdev->ops->set_channel) + return -EOPNOTSUPP; + + return rdev->ops->set_channel(wdev->wiphy, chan, + NL80211_CHAN_NO_HT); + } + + return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq); + +int cfg80211_mgd_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_channel *chan = NULL; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + if (wdev->current_bss) + chan = wdev->current_bss->channel; + else if (wdev->wext.connect.channel) + chan = wdev->wext.connect.channel; + + if (chan) { + freq->m = chan->center_freq; + freq->e = 6; + return 0; + } + + /* no channel if not joining */ + return -EINVAL; +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwfreq); + +int cfg80211_mgd_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + size_t len = data->length; + int err; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + if (!data->flags) + len = 0; + + /* iwconfig uses nul termination in SSID.. */ + if (len > 0 && ssid[len - 1] == '\0') + len--; + + if (wdev->wext.connect.ssid && len && + len == wdev->wext.connect.ssid_len && + memcmp(wdev->wext.connect.ssid, ssid, len)) + return 0; + + if (wdev->sme_state != CFG80211_SME_IDLE) { + bool event = true; + /* if SSID set now, we'll try to connect, avoid event */ + if (len) + event = false; + err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), + dev, WLAN_REASON_DEAUTH_LEAVING, + event); + if (err) + return err; + } + + wdev->wext.connect.ssid = wdev->wext.ssid; + memcpy(wdev->wext.ssid, ssid, len); + wdev->wext.connect.ssid_len = len; + + wdev->wext.connect.crypto.control_port = false; + + return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid); + +int cfg80211_mgd_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + data->flags = 0; + + if (wdev->ssid_len) { + data->flags = 1; + data->length = wdev->ssid_len; + memcpy(ssid, wdev->ssid, data->length); + } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { + data->flags = 1; + data->length = wdev->wext.connect.ssid_len; + memcpy(ssid, wdev->wext.connect.ssid, data->length); + } else + data->flags = 0; + + return 0; +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwessid); + +int cfg80211_mgd_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + u8 *bssid = ap_addr->sa_data; + int err; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + if (ap_addr->sa_family != ARPHRD_ETHER) + return -EINVAL; + + /* automatic mode */ + if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) + bssid = NULL; + + /* both automatic */ + if (!bssid && !wdev->wext.connect.bssid) + return 0; + + /* fixed already - and no change */ + if (wdev->wext.connect.bssid && bssid && + compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) + return 0; + + if (wdev->sme_state != CFG80211_SME_IDLE) { + err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), + dev, WLAN_REASON_DEAUTH_LEAVING, + false); + if (err) + return err; + } + + if (bssid) { + memcpy(wdev->wext.bssid, bssid, ETH_ALEN); + wdev->wext.connect.bssid = wdev->wext.bssid; + } else + wdev->wext.connect.bssid = NULL; + + return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap); + +int cfg80211_mgd_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* call only for station! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + return -EINVAL; + + ap_addr->sa_family = ARPHRD_ETHER; + + if (wdev->current_bss) + memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN); + else if (wdev->wext.connect.bssid) + memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN); + else + memset(ap_addr->sa_data, 0, ETH_ALEN); + + return 0; +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwap); + +int cfg80211_wext_siwgenie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u8 *ie = extra; + int ie_len = data->length, err; + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (!ie_len) + ie = NULL; + + /* no change */ + if (wdev->wext.ie_len == ie_len && + memcmp(wdev->wext.ie, ie, ie_len) == 0) + return 0; + + if (ie_len) { + ie = kmemdup(extra, ie_len, GFP_KERNEL); + if (!ie) + return -ENOMEM; + } else + ie = NULL; + + kfree(wdev->wext.ie); + wdev->wext.ie = ie; + wdev->wext.ie_len = ie_len; + + if (wdev->sme_state != CFG80211_SME_IDLE) { + err = cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, false); + if (err) + return err; + } + + /* userspace better not think we'll reconnect */ + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie); + +int cfg80211_wext_siwmlme(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct iw_mlme *mlme = (struct iw_mlme *)extra; + struct cfg80211_registered_device *rdev; + + if (!wdev) + return -EOPNOTSUPP; + + rdev = wiphy_to_dev(wdev->wiphy); + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EINVAL; + + if (mlme->addr.sa_family != ARPHRD_ETHER) + return -EINVAL; + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + case IW_MLME_DISASSOC: + return cfg80211_disconnect(rdev, dev, mlme->reason_code, + true); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme); -- cgit v0.10.2 From bc92afd92088ab41223383cc6863ab4792533c54 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:57 +0200 Subject: cfg80211: implement iwpower Just on/off and timeout, and with a hacky cfg80211 method until we figure out what we want, though this is probably sufficient as we want to use pm_qos for wifi everywhere. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index d0629d4..54bebba 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -522,6 +522,27 @@ static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) return 0; } +static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool enabled, int timeout) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + u32 power_index; + + if (enabled) + power_index = IWM_POWER_INDEX_DEFAULT; + else + power_index = IWM_POWER_INDEX_MIN; + + if (power_index == iwm->conf.power_index) + return 0; + + iwm->conf.power_index = power_index; + + return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_POWER_INDEX, iwm->conf.power_index); +} + static struct cfg80211_ops iwm_cfg80211_ops = { .change_virtual_intf = iwm_cfg80211_change_iface, .add_key = iwm_cfg80211_add_key, @@ -534,6 +555,7 @@ static struct cfg80211_ops iwm_cfg80211_ops = { .leave_ibss = iwm_cfg80211_leave_ibss, .set_tx_power = iwm_cfg80211_set_txpower, .get_tx_power = iwm_cfg80211_get_txpower, + .set_power_mgmt = iwm_cfg80211_set_power_mgmt, }; struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 9734573..2e7eaf9 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -238,49 +238,6 @@ static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) return 0; } -static int iwm_wext_siwpower(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *wrq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - u32 power_index; - - if (wrq->disabled) { - power_index = IWM_POWER_INDEX_MIN; - goto set; - } else - power_index = IWM_POWER_INDEX_DEFAULT; - - switch (wrq->flags & IW_POWER_MODE) { - case IW_POWER_ON: - case IW_POWER_MODE: - case IW_POWER_ALL_R: - break; - default: - return -EINVAL; - } - - set: - if (power_index == iwm->conf.power_index) - return 0; - - iwm->conf.power_index = power_index; - - return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_POWER_INDEX, iwm->conf.power_index); -} - -static int iwm_wext_giwpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN); - - return 0; -} - static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt) { u8 *auth_type = &iwm->umac_profile->sec.auth_type; @@ -458,8 +415,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* SIOCGIWRETRY */ (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ - (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */ - (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */ + (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */ + (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* SIOCSIWGENIE */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0708521..82b7d80 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1023,6 +1023,10 @@ struct cfg80211_ops { #ifdef CONFIG_NL80211_TESTMODE int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len); #endif + + /* some temporary stuff to finish wext */ + int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, + bool enabled, int timeout); }; /* @@ -1262,6 +1266,8 @@ struct wireless_dev { u8 bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; s8 default_key, default_mgmt_key; + bool ps; + int ps_timeout; } wext; #endif }; @@ -1606,6 +1612,13 @@ int cfg80211_wext_giwtxpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *data, char *keybuf); +int cfg80211_wext_siwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra); +int cfg80211_wext_giwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra); + /* * callbacks for asynchronous cfg80211 methods, notification * functions and BSS handling helpers diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index ba2643a..41a32cd 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -14,22 +14,6 @@ config MAC80211 comment "CFG80211 needs to be enabled for MAC80211" depends on CFG80211=n -config MAC80211_DEFAULT_PS - bool "enable powersave by default" - depends on MAC80211 - default y - help - This option enables powersave mode by default. - - If this causes your applications to misbehave you should fix your - applications instead -- they need to register their network - latency requirement, see Documentation/power/pm_qos_interface.txt. - -config MAC80211_DEFAULT_PS_VALUE - int - default 1 if MAC80211_DEFAULT_PS - default 0 - menu "Rate control algorithm selection" depends on MAC80211 != n diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 03de402..8c7b2cd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1388,6 +1388,31 @@ int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) } #endif +static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, int timeout) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_conf *conf = &local->hw.conf; + + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) + return -EOPNOTSUPP; + + if (enabled == sdata->u.mgd.powersave && + timeout == conf->dynamic_ps_timeout) + return 0; + + sdata->u.mgd.powersave = enabled; + conf->dynamic_ps_timeout = timeout; + + if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + + ieee80211_recalc_ps(local, -1); + + return 0; +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1431,4 +1456,5 @@ struct cfg80211_ops mac80211_config_ops = { .get_tx_power = ieee80211_get_tx_power, .rfkill_poll = ieee80211_rfkill_poll, CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) + .set_power_mgmt = ieee80211_set_power_mgmt, }; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fbb93a7..2a78600 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2360,11 +2360,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; hw_flags = sdata->local->hw.flags; - - if (hw_flags & IEEE80211_HW_SUPPORTS_PS) { - ifmgd->powersave = CONFIG_MAC80211_DEFAULT_PS_VALUE; - sdata->local->hw.conf.dynamic_ps_timeout = 500; - } } /* configuration hooks */ diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index d4e61dc..f779298 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -255,72 +255,6 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, return 0; } -static int ieee80211_ioctl_siwpower(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *wrq, - char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_conf *conf = &local->hw.conf; - int timeout = 0; - bool ps; - - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) - return -EOPNOTSUPP; - - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return -EINVAL; - - if (wrq->disabled) { - ps = false; - timeout = 0; - goto set; - } - - switch (wrq->flags & IW_POWER_MODE) { - case IW_POWER_ON: /* If not specified */ - case IW_POWER_MODE: /* If set all mask */ - case IW_POWER_ALL_R: /* If explicitely state all */ - ps = true; - break; - default: /* Otherwise we ignore */ - return -EINVAL; - } - - if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT)) - return -EINVAL; - - if (wrq->flags & IW_POWER_TIMEOUT) - timeout = wrq->value / 1000; - - set: - if (ps == sdata->u.mgd.powersave && timeout == conf->dynamic_ps_timeout) - return 0; - - sdata->u.mgd.powersave = ps; - conf->dynamic_ps_timeout = timeout; - - if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - - ieee80211_recalc_ps(local, -1); - - return 0; -} - -static int ieee80211_ioctl_giwpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - wrqu->power.disabled = !sdata->u.mgd.powersave; - - return 0; -} - /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) { @@ -436,8 +370,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ - (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ - (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ + (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */ + (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */ diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 0402631..c6031d5 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -26,6 +26,22 @@ config CFG80211_REG_DEBUG If unsure, say N. +config CFG80211_DEFAULT_PS + bool "enable powersave by default" + depends on CFG80211 + default y + help + This option enables powersave mode by default. + + If this causes your applications to misbehave you should fix your + applications instead -- they need to register their network + latency requirement, see Documentation/power/pm_qos_interface.txt. + +config CFG80211_DEFAULT_PS_VALUE + int + default 1 if CFG80211_DEFAULT_PS + default 0 + config CFG80211_DEBUGFS bool "cfg80211 DebugFS entries" depends on CFG80211 && DEBUG_FS diff --git a/net/wireless/core.c b/net/wireless/core.c index e2f80dd..413d291 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -550,12 +550,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, } wdev->netdev = dev; wdev->sme_state = CFG80211_SME_IDLE; + mutex_unlock(&rdev->devlist_mtx); #ifdef CONFIG_WIRELESS_EXT wdev->wext.default_key = -1; wdev->wext.default_mgmt_key = -1; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; + wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE; + wdev->wext.ps_timeout = 500; + if (rdev->ops->set_power_mgmt) + if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, + wdev->wext.ps, + wdev->wext.ps_timeout)) { + /* assume this means it's off */ + wdev->wext.ps = false; + } #endif - mutex_unlock(&rdev->devlist_mtx); break; case NETDEV_GOING_DOWN: if (!wdev->ssid_len) diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 02f052f..2e1ab78 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -987,3 +987,63 @@ int cfg80211_wext_giwauth(struct net_device *dev, return -EOPNOTSUPP; } EXPORT_SYMBOL_GPL(cfg80211_wext_giwauth); + +int cfg80211_wext_siwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + bool ps = wdev->wext.ps; + int timeout = wdev->wext.ps_timeout; + int err; + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EINVAL; + + if (!rdev->ops->set_power_mgmt) + return -EOPNOTSUPP; + + if (wrq->disabled) { + ps = false; + } else { + switch (wrq->flags & IW_POWER_MODE) { + case IW_POWER_ON: /* If not specified */ + case IW_POWER_MODE: /* If set all mask */ + case IW_POWER_ALL_R: /* If explicitely state all */ + ps = true; + break; + default: /* Otherwise we ignore */ + return -EINVAL; + } + + if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT)) + return -EINVAL; + + if (wrq->flags & IW_POWER_TIMEOUT) + timeout = wrq->value / 1000; + } + + err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, ps, timeout); + if (err) + return err; + + wdev->wext.ps = ps; + wdev->wext.ps_timeout = timeout; + + return 0; + +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwpower); + +int cfg80211_wext_giwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + wrq->disabled = !wdev->wext.ps; + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower); -- cgit v0.10.2 From ab737a4f7dbe57b12b73f482a7b973bf00b41942 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:58 +0200 Subject: cfg80211: implement IWAP for WDS This implements siocsiwap/giwap for WDS mode. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 82b7d80..b396d11 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1018,6 +1018,9 @@ struct cfg80211_ops { enum tx_power_setting type, int dbm); int (*get_tx_power)(struct wiphy *wiphy, int *dbm); + int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, + u8 *addr); + void (*rfkill_poll)(struct wiphy *wiphy); #ifdef CONFIG_NL80211_TESTMODE @@ -1619,6 +1622,13 @@ int cfg80211_wext_giwpower(struct net_device *dev, struct iw_request_info *info, struct iw_param *wrq, char *extra); +int cfg80211_wds_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *addr, char *extra); +int cfg80211_wds_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *addr, char *extra); + /* * callbacks for asynchronous cfg80211 methods, notification * functions and BSS handling helpers diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8c7b2cd..2cf5bf6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1369,6 +1369,16 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) return 0; } +static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, + u8 *addr) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + memcpy(&sdata->u.wds.remote_addr, addr, ETH_ALEN); + + return 0; +} + static void ieee80211_rfkill_poll(struct wiphy *wiphy) { struct ieee80211_local *local = wiphy_priv(wiphy); @@ -1454,6 +1464,7 @@ struct cfg80211_ops mac80211_config_ops = { .set_wiphy_params = ieee80211_set_wiphy_params, .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, + .set_wds_peer = ieee80211_set_wds_peer, .rfkill_poll = ieee80211_rfkill_poll, CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) .set_power_mgmt = ieee80211_set_power_mgmt, diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index f779298..4053d76 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -140,23 +140,8 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_STATION) return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); - if (sdata->vif.type == NL80211_IFTYPE_WDS) { - /* - * If it is necessary to update the WDS peer address - * while the interface is running, then we need to do - * more work here, namely if it is running we need to - * add a new and remove the old STA entry, this is - * normally handled by _open() and _stop(). - */ - if (netif_running(dev)) - return -EBUSY; - - memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, - ETH_ALEN); - - return 0; - } - + if (sdata->vif.type == NL80211_IFTYPE_WDS) + return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra); return -EOPNOTSUPP; } @@ -173,11 +158,8 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_STATION) return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); - if (sdata->vif.type == NL80211_IFTYPE_WDS) { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); - return 0; - } + if (sdata->vif.type == NL80211_IFTYPE_WDS) + return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra); return -EOPNOTSUPP; } diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 2e1ab78..2f72dae 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1047,3 +1047,49 @@ int cfg80211_wext_giwpower(struct net_device *dev, return 0; } EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower); + +int cfg80211_wds_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int err; + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS)) + return -EINVAL; + + if (addr->sa_family != ARPHRD_ETHER) + return -EINVAL; + + if (netif_running(dev)) + return -EBUSY; + + if (!rdev->ops->set_wds_peer) + return -EOPNOTSUPP; + + err = rdev->ops->set_wds_peer(wdev->wiphy, dev, (u8 *) &addr->sa_data); + if (err) + return err; + + memcpy(&wdev->wext.bssid, (u8 *) &addr->sa_data, ETH_ALEN); + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wds_wext_siwap); + +int cfg80211_wds_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS)) + return -EINVAL; + + addr->sa_family = ARPHRD_ETHER; + memcpy(&addr->sa_data, wdev->wext.bssid, ETH_ALEN); + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap); -- cgit v0.10.2 From 9930380f0bd8405fa6a51d644f3de88c30666519 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:59 +0200 Subject: cfg80211: implement IWRATE For now, let's implement that using a very hackish way: simply mirror the wext API in the cfg80211 API. This will have to be changed later when we implement proper bitrate API. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b396d11..5790855 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -815,6 +815,26 @@ enum tx_power_setting { TX_POWER_FIXED, }; +/* + * cfg80211_bitrate_mask - masks for bitrate control + */ +struct cfg80211_bitrate_mask { +/* + * As discussed in Berlin, this struct really + * should look like this: + + struct { + u32 legacy; + u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; + } control[IEEE80211_NUM_BANDS]; + + * Since we can always fix in-kernel users, let's keep + * it simpler for now: + */ + u32 fixed; /* fixed bitrate, 0 == not fixed */ + u32 maxrate; /* in kbps, 0 == no limit */ +}; + /** * struct cfg80211_ops - backend description for wireless configuration * @@ -1027,6 +1047,11 @@ struct cfg80211_ops { int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len); #endif + int (*set_bitrate_mask)(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, + const struct cfg80211_bitrate_mask *mask); + /* some temporary stuff to finish wext */ int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout); @@ -1581,6 +1606,13 @@ int cfg80211_wext_giwauth(struct net_device *dev, struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); +int cfg80211_wext_siwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra); +int cfg80211_wext_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra); + int cfg80211_wext_siwrts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2cf5bf6..028f643 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1423,6 +1423,48 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, return 0; } +static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, + const u8 *addr, + const struct cfg80211_bitrate_mask *mask) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + int i, err = -EINVAL; + u32 target_rate; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates + * target_rate = X, rate->fixed = 1 means only rate X + * target_rate = X, rate->fixed = 0 means all rates <= X */ + sdata->max_ratectrl_rateidx = -1; + sdata->force_unicast_rateidx = -1; + + if (mask->fixed) + target_rate = mask->fixed / 100; + else if (mask->maxrate) + target_rate = mask->maxrate / 100; + else + return 0; + + for (i=0; i< sband->n_bitrates; i++) { + struct ieee80211_rate *brate = &sband->bitrates[i]; + int this_rate = brate->bitrate; + + if (target_rate == this_rate) { + sdata->max_ratectrl_rateidx = i; + if (mask->fixed) + sdata->force_unicast_rateidx = i; + err = 0; + break; + } + } + + return err; +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1468,4 +1510,5 @@ struct cfg80211_ops mac80211_config_ops = { .rfkill_poll = ieee80211_rfkill_poll, CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) .set_power_mgmt = ieee80211_set_power_mgmt, + .set_bitrate_mask = ieee80211_set_bitrate_mask, }; diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 4053d76..244d830 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -165,78 +165,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, } -static int ieee80211_ioctl_siwrate(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rate, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int i, err = -EINVAL; - u32 target_rate = rate->value / 100000; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_supported_band *sband; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates - * target_rate = X, rate->fixed = 1 means only rate X - * target_rate = X, rate->fixed = 0 means all rates <= X */ - sdata->max_ratectrl_rateidx = -1; - sdata->force_unicast_rateidx = -1; - if (rate->value < 0) - return 0; - - for (i=0; i< sband->n_bitrates; i++) { - struct ieee80211_rate *brate = &sband->bitrates[i]; - int this_rate = brate->bitrate; - - if (target_rate == this_rate) { - sdata->max_ratectrl_rateidx = i; - if (rate->fixed) - sdata->force_unicast_rateidx = i; - err = 0; - break; - } - } - return err; -} - -static int ieee80211_ioctl_giwrate(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rate, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_supported_band *sband; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return -EOPNOTSUPP; - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - rcu_read_lock(); - - sta = sta_info_get(local, sdata->u.mgd.bssid); - - if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) - rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate; - else - rate->value = 0; - - rcu_read_unlock(); - - if (!sta) - return -ENODEV; - - rate->value *= 100000; - - return 0; -} - /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) { @@ -340,8 +268,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* SIOCGIWNICKN */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ - (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */ - (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ + (iw_handler) cfg80211_wext_siwrate, /* SIOCSIWRATE */ + (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */ (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 2f72dae..3a5f999 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1093,3 +1093,66 @@ int cfg80211_wds_wext_giwap(struct net_device *dev, return 0; } EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap); + +int cfg80211_wext_siwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_bitrate_mask mask; + + if (!rdev->ops->set_bitrate_mask) + return -EOPNOTSUPP; + + mask.fixed = 0; + mask.maxrate = 0; + + if (rate->value < 0) { + /* nothing */ + } else if (rate->fixed) { + mask.fixed = rate->value / 1000; /* kbps */ + } else { + mask.maxrate = rate->value / 1000; /* kbps */ + } + + return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); + +int cfg80211_wext_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + /* we are under RTNL - globally locked - so can use a static struct */ + static struct station_info sinfo; + u8 *addr; + int err; + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (!rdev->ops->get_station) + return -EOPNOTSUPP; + + addr = wdev->wext.connect.bssid; + if (!addr) + return -EOPNOTSUPP; + + err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo); + if (err) + return err; + + if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) + return -EOPNOTSUPP; + + rate->value = 0; + + if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS)) + rate->value = 100000 * sinfo.txrate.legacy; + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate); -- cgit v0.10.2 From 8990646d2fafeacfacba4a4b1073a4216662089a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:27:00 +0200 Subject: cfg80211: implement get_wireless_stats By dropping the noise reporting, we can implement wireless stats in cfg80211. We also make the handler return NULL if we have no information, which is possible thanks to the recent wext change. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5790855..fe87819 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1646,6 +1646,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, int cfg80211_wext_giwtxpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *data, char *keybuf); +struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev); int cfg80211_wext_siwpower(struct net_device *dev, struct iw_request_info *info, diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 244d830..5acb814 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -165,73 +165,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, } -/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ -static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct iw_statistics *wstats = &local->wstats; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sta_info *sta = NULL; - - rcu_read_lock(); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) - sta = sta_info_get(local, sdata->u.mgd.bssid); - - if (!sta) { - wstats->discard.fragment = 0; - wstats->discard.misc = 0; - wstats->qual.qual = 0; - wstats->qual.level = 0; - wstats->qual.noise = 0; - wstats->qual.updated = IW_QUAL_ALL_INVALID; - } else { - wstats->qual.updated = 0; - /* - * mirror what cfg80211 does for iwrange/scan results, - * otherwise userspace gets confused. - */ - if (local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | - IEEE80211_HW_SIGNAL_DBM)) { - wstats->qual.updated |= IW_QUAL_LEVEL_UPDATED; - wstats->qual.updated |= IW_QUAL_QUAL_UPDATED; - } else { - wstats->qual.updated |= IW_QUAL_LEVEL_INVALID; - wstats->qual.updated |= IW_QUAL_QUAL_INVALID; - } - - if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) { - wstats->qual.level = sta->last_signal; - wstats->qual.qual = sta->last_signal; - } else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { - int sig = sta->last_signal; - - wstats->qual.updated |= IW_QUAL_DBM; - wstats->qual.level = sig; - if (sig < -110) - sig = -110; - else if (sig > -40) - sig = -40; - wstats->qual.qual = sig + 110; - } - - if (local->hw.flags & IEEE80211_HW_NOISE_DBM) { - /* - * This assumes that if driver reports noise, it also - * reports signal in dBm. - */ - wstats->qual.noise = sta->last_noise; - wstats->qual.updated |= IW_QUAL_NOISE_UPDATED; - } else { - wstats->qual.updated |= IW_QUAL_NOISE_INVALID; - } - } - - rcu_read_unlock(); - - return wstats; -} - /* Structures to export the Wireless Handlers */ static const iw_handler ieee80211_handler[] = @@ -298,5 +231,5 @@ const struct iw_handler_def ieee80211_iw_handler_def = { .num_standard = ARRAY_SIZE(ieee80211_handler), .standard = (iw_handler *) ieee80211_handler, - .get_wireless_stats = ieee80211_get_wireless_stats, + .get_wireless_stats = cfg80211_wireless_stats, }; diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 3a5f999..226cf86 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1156,3 +1156,62 @@ int cfg80211_wext_giwrate(struct net_device *dev, return 0; } EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate); + +/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ +struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + /* we are under RTNL - globally locked - so can use static structs */ + static struct iw_statistics wstats; + static struct station_info sinfo; + u8 *addr; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) + return NULL; + + if (!rdev->ops->get_station) + return NULL; + + addr = wdev->wext.connect.bssid; + if (!addr) + return NULL; + + if (rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo)) + return NULL; + + memset(&wstats, 0, sizeof(wstats)); + + switch (rdev->wiphy.signal_type) { + case CFG80211_SIGNAL_TYPE_MBM: + if (sinfo.filled & STATION_INFO_SIGNAL) { + int sig = sinfo.signal; + wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; + wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; + wstats.qual.updated |= IW_QUAL_DBM; + wstats.qual.level = sig; + if (sig < -110) + sig = -110; + else if (sig > -40) + sig = -40; + wstats.qual.qual = sig + 110; + break; + } + case CFG80211_SIGNAL_TYPE_UNSPEC: + if (sinfo.filled & STATION_INFO_SIGNAL) { + wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; + wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; + wstats.qual.level = sinfo.signal; + wstats.qual.qual = sinfo.signal; + break; + } + default: + wstats.qual.updated |= IW_QUAL_LEVEL_INVALID; + wstats.qual.updated |= IW_QUAL_QUAL_INVALID; + } + + wstats.qual.updated |= IW_QUAL_NOISE_INVALID; + + return &wstats; +} +EXPORT_SYMBOL_GPL(cfg80211_wireless_stats); -- cgit v0.10.2 From ac00326e9d1d46bf48e9cf60cf892a96b885601a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:27:01 +0200 Subject: mac80211: re-add HT disabling The IEEE80211_STA_TKIP_WEP_USED flag is used internally to disable HT when WEP or TKIP are used. Now that cfg80211 is giving us the required information, we can set the flag appropriately again. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 028f643..af4733b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1228,7 +1228,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_assoc_request *req) { struct ieee80211_sub_if_data *sdata; - int ret; + int ret, i; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -1236,6 +1236,14 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) return -ENOLINK; /* not authenticated */ + sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED; + + for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) + if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || + req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || + req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) + sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED; + sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET; -- cgit v0.10.2 From 6dc1cb0319997648f59b0f46b9e093e779f0353d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:40:45 +0200 Subject: mac80211: remove auth algorithm retry The automatic auth algorithm issue is now solved in cfg80211, so mac80211 no longer needs code to try different algorithms -- just using whatever cfg80211 asked for is good. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index af4733b..3c9774e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1178,16 +1178,16 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, switch (req->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: - sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_OPEN; + sdata->u.mgd.auth_alg = WLAN_AUTH_OPEN; break; case NL80211_AUTHTYPE_SHARED_KEY: - sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_SHARED_KEY; + sdata->u.mgd.auth_alg = WLAN_AUTH_SHARED_KEY; break; case NL80211_AUTHTYPE_FT: - sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_FT; + sdata->u.mgd.auth_alg = WLAN_AUTH_FT; break; case NL80211_AUTHTYPE_NETWORK_EAP: - sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_LEAP; + sdata->u.mgd.auth_alg = WLAN_AUTH_LEAP; break; default: return -EOPNOTSUPP; diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index e342032..df8c804 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -105,7 +105,6 @@ IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE); IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC); IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC); -IEEE80211_IF_FILE(auth_algs, u.mgd.auth_algs, HEX); IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC); IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC); @@ -194,7 +193,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(extra_ie_len, sta); DEBUGFS_ADD(auth_tries, sta); DEBUGFS_ADD(assoc_tries, sta); - DEBUGFS_ADD(auth_algs, sta); DEBUGFS_ADD(auth_alg, sta); DEBUGFS_ADD(auth_transaction, sta); DEBUGFS_ADD(flags, sta); @@ -327,7 +325,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_DEL(extra_ie_len, sta); DEBUGFS_DEL(auth_tries, sta); DEBUGFS_DEL(assoc_tries, sta); - DEBUGFS_DEL(auth_algs, sta); DEBUGFS_DEL(auth_alg, sta); DEBUGFS_DEL(auth_transaction, sta); DEBUGFS_DEL(flags, sta); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1950e2e..f7024ee 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -251,12 +251,6 @@ struct mesh_preq_queue { #define IEEE80211_STA_REQ_AUTH 1 #define IEEE80211_STA_REQ_RUN 2 -/* bitfield of allowed auth algs */ -#define IEEE80211_AUTH_ALG_OPEN BIT(0) -#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) -#define IEEE80211_AUTH_ALG_LEAP BIT(2) -#define IEEE80211_AUTH_ALG_FT BIT(3) - struct ieee80211_if_managed { struct timer_list timer; struct timer_list chswitch_timer; @@ -303,7 +297,6 @@ struct ieee80211_if_managed { unsigned int flags; - unsigned int auth_algs; /* bitfield of allowed auth algs */ int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ int auth_transaction; @@ -488,7 +481,6 @@ struct ieee80211_sub_if_data { struct dentry *extra_ie_len; struct dentry *auth_tries; struct dentry *assoc_tries; - struct dentry *auth_algs; struct dentry *auth_alg; struct dentry *auth_transaction; struct dentry *flags; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2a78600..2b357c7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1414,39 +1414,6 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, return; if (status_code != WLAN_STATUS_SUCCESS) { - if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { - u8 algs[3]; - const int num_algs = ARRAY_SIZE(algs); - int i, pos; - algs[0] = algs[1] = algs[2] = 0xff; - if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN) - algs[0] = WLAN_AUTH_OPEN; - if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) - algs[1] = WLAN_AUTH_SHARED_KEY; - if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) - algs[2] = WLAN_AUTH_LEAP; - if (ifmgd->auth_alg == WLAN_AUTH_OPEN) - pos = 0; - else if (ifmgd->auth_alg == WLAN_AUTH_SHARED_KEY) - pos = 1; - else - pos = 2; - for (i = 0; i < num_algs; i++) { - pos++; - if (pos >= num_algs) - pos = 0; - if (algs[pos] == ifmgd->auth_alg || - algs[pos] == 0xff) - continue; - if (algs[pos] == WLAN_AUTH_SHARED_KEY && - !ieee80211_sta_wep_configured(sdata)) - continue; - ifmgd->auth_alg = algs[pos]; - ifmgd->auth_tries = 0; - return; - } - } - /* nothing else to try -- give up */ cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); ifmgd->state = IEEE80211_STA_MLME_DISABLED; @@ -2102,18 +2069,6 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) drv_reset_tsf(local); ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ - - - if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN) - ifmgd->auth_alg = WLAN_AUTH_OPEN; - else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) - ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY; - else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) - ifmgd->auth_alg = WLAN_AUTH_LEAP; - else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_FT) - ifmgd->auth_alg = WLAN_AUTH_FT; - else - ifmgd->auth_alg = WLAN_AUTH_OPEN; ifmgd->auth_transaction = -1; ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; ifmgd->assoc_scan_tries = 0; @@ -2351,8 +2306,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) skb_queue_head_init(&ifmgd->skb_queue); ifmgd->capab = WLAN_CAPABILITY_ESS; - ifmgd->auth_algs = IEEE80211_AUTH_ALG_OPEN | - IEEE80211_AUTH_ALG_SHARED_KEY; ifmgd->flags |= IEEE80211_STA_CREATE_IBSS | IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL; -- cgit v0.10.2 From ab1faead50d09165b58c2854997c7205ca9c0d22 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:41:17 +0200 Subject: mac80211: remove dead code, clean up With mac80211 now always controlled by an external SME, a lot of code is dead -- SSID, BSSID, channel selection is always done externally, etc. Additionally, rename IEEE80211_STA_TKIP_WEP_USED to IEEE80211_STA_DISABLE_11N and clean up the code a bit. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3c9774e..7606571 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1194,18 +1194,14 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, } memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN); - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; - sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET; - /* TODO: req->chan */ - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; + sdata->local->oper_channel = req->chan; + ieee80211_hw_config(sdata->local, 0); - if (req->ssid) { - sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET; - memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); - sdata->u.mgd.ssid_len = req->ssid_len; - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; - } + if (!req->ssid) + return -EINVAL; + memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); + sdata->u.mgd.ssid_len = req->ssid_len; kfree(sdata->u.mgd.sme_auth_ie); sdata->u.mgd.sme_auth_ie = NULL; @@ -1218,7 +1214,6 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, sdata->u.mgd.sme_auth_ie_len = req->ie_len; } - sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE; ieee80211_sta_req_auth(sdata); return 0; @@ -1236,27 +1231,22 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) return -ENOLINK; /* not authenticated */ - sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED; + sdata->u.mgd.flags &= ~IEEE80211_STA_DISABLE_11N; for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) - sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED; + sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N; - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; - sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET; + sdata->local->oper_channel = req->chan; + ieee80211_hw_config(sdata->local, 0); - /* TODO: req->chan */ - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; + if (!req->ssid) + return -EINVAL; - if (req->ssid) { - sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET; - memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); - sdata->u.mgd.ssid_len = req->ssid_len; - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; - } else - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; + memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); + sdata->u.mgd.ssid_len = req->ssid_len; ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); if (ret && ret != -EALREADY) @@ -1275,7 +1265,6 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, else sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; ieee80211_sta_req_auth(sdata); return 0; diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index df8c804..ffe9add 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -111,9 +111,7 @@ IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC); static ssize_t ieee80211_if_fmt_flags( const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) { - return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n", - sdata->u.mgd.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "", - sdata->u.mgd.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "", + return scnprintf(buf, buflen, "%s%s%s%s%s\n", sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f7024ee..a550aeb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -228,28 +228,24 @@ struct mesh_preq_queue { }; /* flags used in struct ieee80211_if_managed.flags */ -#define IEEE80211_STA_SSID_SET BIT(0) -#define IEEE80211_STA_BSSID_SET BIT(1) -#define IEEE80211_STA_PREV_BSSID_SET BIT(2) -#define IEEE80211_STA_AUTHENTICATED BIT(3) -#define IEEE80211_STA_ASSOCIATED BIT(4) -#define IEEE80211_STA_PROBEREQ_POLL BIT(5) -#define IEEE80211_STA_CREATE_IBSS BIT(6) -#define IEEE80211_STA_CONTROL_PORT BIT(7) -#define IEEE80211_STA_WMM_ENABLED BIT(8) -/* hole at 9, please re-use */ -#define IEEE80211_STA_AUTO_SSID_SEL BIT(10) -#define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) -#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) -#define IEEE80211_STA_PRIVACY_INVOKED BIT(13) -#define IEEE80211_STA_TKIP_WEP_USED BIT(14) -#define IEEE80211_STA_CSA_RECEIVED BIT(15) -#define IEEE80211_STA_MFP_ENABLED BIT(16) -#define IEEE80211_STA_EXT_SME BIT(17) +enum ieee80211_sta_flags { + IEEE80211_STA_PREV_BSSID_SET = BIT(0), + IEEE80211_STA_AUTHENTICATED = BIT(1), + IEEE80211_STA_ASSOCIATED = BIT(2), + IEEE80211_STA_PROBEREQ_POLL = BIT(3), + IEEE80211_STA_CONTROL_PORT = BIT(4), + IEEE80211_STA_WMM_ENABLED = BIT(5), + IEEE80211_STA_DISABLE_11N = BIT(6), + IEEE80211_STA_CSA_RECEIVED = BIT(7), + IEEE80211_STA_MFP_ENABLED = BIT(8), +}; + /* flags for MLME request */ -#define IEEE80211_STA_REQ_SCAN 0 -#define IEEE80211_STA_REQ_AUTH 1 -#define IEEE80211_STA_REQ_RUN 2 +enum ieee80211_sta_request { + IEEE80211_STA_REQ_SCAN, + IEEE80211_STA_REQ_AUTH, + IEEE80211_STA_REQ_RUN, +}; struct ieee80211_if_managed { struct timer_list timer; @@ -936,10 +932,6 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata); -int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); -int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); -int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata); int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b7c8a44..b87bf42 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -486,8 +486,6 @@ static int ieee80211_stop(struct net_device *dev) synchronize_rcu(); skb_queue_purge(&sdata->u.mgd.skb_queue); - sdata->u.mgd.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED | - IEEE80211_STA_TKIP_WEP_USED); kfree(sdata->u.mgd.extra_ie); sdata->u.mgd.extra_ie = NULL; sdata->u.mgd.extra_ie_len = 0; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2b357c7..2d9b666 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -347,7 +347,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) sband->ht_cap.ht_supported && (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && ht_ie[1] >= sizeof(struct ieee80211_ht_info) && - (!(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))) { + (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { struct ieee80211_ht_info *ht_info = (struct ieee80211_ht_info *)(ht_ie + 2); u16 cap = sband->ht_cap.cap; @@ -981,8 +981,6 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - u8 *ies; - size_t ies_len; ifmgd->auth_tries++; if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { @@ -1010,15 +1008,8 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: authenticate with AP %pM\n", sdata->dev->name, ifmgd->bssid); - if (ifmgd->flags & IEEE80211_STA_EXT_SME) { - ies = ifmgd->sme_auth_ie; - ies_len = ifmgd->sme_auth_ie_len; - } else { - ies = NULL; - ies_len = 0; - } - ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ies, ies_len, - ifmgd->bssid, 0); + ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ifmgd->sme_auth_ie, + ifmgd->sme_auth_ie_len, ifmgd->bssid, 0); ifmgd->auth_transaction = 2; mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); @@ -1128,44 +1119,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sta_info_destroy(sta); } -static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) -{ - if (!sdata || !sdata->default_key || - sdata->default_key->conf.alg != ALG_WEP) - return 0; - return 1; -} - -static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - struct ieee80211_bss *bss; - int bss_privacy; - int wep_privacy; - int privacy_invoked; - - if (!ifmgd || (ifmgd->flags & IEEE80211_STA_EXT_SME)) - return 0; - - bss = ieee80211_rx_bss_get(local, ifmgd->bssid, - local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (!bss) - return 0; - - bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY); - wep_privacy = !!ieee80211_sta_wep_configured(sdata); - privacy_invoked = !!(ifmgd->flags & IEEE80211_STA_PRIVACY_INVOKED); - - ieee80211_rx_bss_put(local, bss); - - if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked)) - return 0; - - return 1; -} - static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -1195,14 +1148,6 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; printk(KERN_DEBUG "%s: associate with AP %pM\n", sdata->dev->name, ifmgd->bssid); - if (ieee80211_privacy_mismatch(sdata)) { - printk(KERN_DEBUG "%s: mismatch in privacy configuration and " - "mixed-cell disabled - abort association\n", sdata->dev->name); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - return; - } - ieee80211_send_assoc(sdata); mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); @@ -1360,12 +1305,9 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; - if (ifmgd->flags & IEEE80211_STA_EXT_SME) { - /* Wait for SME to request association */ - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(sdata->local); - } else - ieee80211_associate(sdata); + /* Wait for SME to request association */ + ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(sdata->local); } @@ -1460,15 +1402,6 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", sdata->dev->name, reason_code); - if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && - (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || - ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE || - ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) { - ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; - mod_timer(&ifmgd->timer, jiffies + - IEEE80211_RETRY_AUTH_INTERVAL); - } - ieee80211_set_disassoc(sdata, true, false, 0); ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); @@ -1494,13 +1427,6 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", sdata->dev->name, reason_code); - if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && - ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { - ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; - mod_timer(&ifmgd->timer, jiffies + - IEEE80211_RETRY_AUTH_INTERVAL); - } - ieee80211_set_disassoc(sdata, false, false, reason_code); cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); } @@ -1573,11 +1499,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); - if (ifmgd->flags & IEEE80211_STA_EXT_SME) { - /* Wait for SME to decide what to do next */ - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - } + /* Wait for SME to decide what to do next */ + ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(local); return; } @@ -1683,8 +1607,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, else sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; - /* If TKIP/WEP is used, no need to parse AP's HT capabilities */ - if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) + if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) ieee80211_ht_cap_ie_to_sta_ht_cap(sband, elems.ht_cap_elem, &sta->sta.ht_cap); @@ -1718,7 +1641,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (elems.ht_info_elem && elems.wmm_param && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && - !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) + !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, ap_ht_cap_flags); @@ -1931,7 +1854,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && - !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) { + !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { struct sta_info *sta; struct ieee80211_supported_band *sband; u16 ap_ht_cap_flags; @@ -2090,26 +2013,6 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) u16 capa_val = WLAN_CAPABILITY_ESS; struct ieee80211_channel *chan = local->oper_channel; - if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && - ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL | - IEEE80211_STA_AUTO_BSSID_SEL | - IEEE80211_STA_AUTO_CHANNEL_SEL)) { - capa_mask |= WLAN_CAPABILITY_PRIVACY; - if (sdata->default_key) - capa_val |= WLAN_CAPABILITY_PRIVACY; - } - - if (ifmgd->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) - chan = NULL; - - if (ifmgd->flags & IEEE80211_STA_AUTO_BSSID_SEL) - bssid = NULL; - - if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) { - ssid = NULL; - ssid_len = 0; - } - bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, ssid, ssid_len, capa_mask, capa_val); @@ -2119,10 +2022,6 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) local->oper_channel_type = NL80211_CHAN_NO_HT; ieee80211_hw_config(local, 0); - if (!(ifmgd->flags & IEEE80211_STA_SSID_SET)) - ieee80211_sta_set_ssid(sdata, bss->ssid, - bss->ssid_len); - ieee80211_sta_set_bssid(sdata, bss->cbss.bssid); ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len, bss->supp_rates); if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED) @@ -2232,14 +2131,6 @@ static void ieee80211_sta_work(struct work_struct *work) WARN_ON(1); break; } - - if (ieee80211_privacy_mismatch(sdata)) { - printk(KERN_DEBUG "%s: privacy configuration mismatch and " - "mixed-cell disabled - disassociate\n", sdata->dev->name); - - ieee80211_set_disassoc(sdata, false, true, - WLAN_REASON_UNSPECIFIED); - } } static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) @@ -2306,9 +2197,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) skb_queue_head_init(&ifmgd->skb_queue); ifmgd->capab = WLAN_CAPABILITY_ESS; - ifmgd->flags |= IEEE80211_STA_CREATE_IBSS | - IEEE80211_STA_AUTO_BSSID_SEL | - IEEE80211_STA_AUTO_CHANNEL_SEL; + ifmgd->flags = 0; if (sdata->local->hw.queues >= 4) ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; @@ -2324,96 +2213,20 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata) if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) return; - if ((ifmgd->flags & (IEEE80211_STA_BSSID_SET | - IEEE80211_STA_AUTO_BSSID_SEL)) && - (ifmgd->flags & (IEEE80211_STA_SSID_SET | - IEEE80211_STA_AUTO_SSID_SEL))) { - - if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) - ieee80211_set_disassoc(sdata, true, true, - WLAN_REASON_DEAUTH_LEAVING); - - if (ifmgd->ssid_len == 0) { - /* - * Only allow association to be started if a valid SSID - * is configured. - */ - return; - } - - if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) || - ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) - set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); - else if (ifmgd->flags & IEEE80211_STA_EXT_SME) - set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); - queue_work(local->hw.workqueue, &ifmgd->work); - } -} - -int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - - if (ifmgd->ssid_len) - ifmgd->flags |= IEEE80211_STA_SSID_SET; - else - ifmgd->flags &= ~IEEE80211_STA_SSID_SET; - - return 0; -} - -int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) -{ - struct ieee80211_if_managed *ifmgd; - - if (len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; - - ifmgd = &sdata->u.mgd; - - if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) { - if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) - ieee80211_set_disassoc(sdata, true, true, - WLAN_REASON_DEAUTH_LEAVING); - - /* - * Do not use reassociation if SSID is changed (different ESS). - */ - ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; - memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid)); - memcpy(ifmgd->ssid, ssid, len); - ifmgd->ssid_len = len; - } - - return ieee80211_sta_commit(sdata); -} - -int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - memcpy(ssid, ifmgd->ssid, ifmgd->ssid_len); - *len = ifmgd->ssid_len; - return 0; -} - -int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - - if (compare_ether_addr(bssid, ifmgd->bssid) != 0 && - ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) + if (WARN_ON(ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) ieee80211_set_disassoc(sdata, true, true, WLAN_REASON_DEAUTH_LEAVING); - if (is_valid_ether_addr(bssid)) { - memcpy(ifmgd->bssid, bssid, ETH_ALEN); - ifmgd->flags |= IEEE80211_STA_BSSID_SET; - } else { - memset(ifmgd->bssid, 0, ETH_ALEN); - ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; + if (WARN_ON(ifmgd->ssid_len == 0)) { + /* + * Only allow association to be started if a valid SSID + * is configured. + */ + return; } - return ieee80211_sta_commit(sdata); + set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); + queue_work(local->hw.workqueue, &ifmgd->work); } int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, -- cgit v0.10.2 From e45cd82ace91b71bc690ba78a0ebea17edfaabef Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Jul 2009 09:58:04 +0200 Subject: cfg80211: send events for userspace SME When the userspace SME is in control, we are currently not sending events, but this means that any userspace applications using wext or nl80211 to receive events will not know what's going on unless they can also interpret the nl80211 assoc event. Since we have all the required code, let the SME follow events from the userspace SME, this even means that you will be refused to connect() while the userspace SME is in control and connected. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f272ebf..d4e0b40 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -287,6 +287,44 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; + if (wdev->sme_state == CFG80211_SME_CONNECTED) + nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, + bssid, req_ie, req_ie_len, + resp_ie, resp_ie_len, gfp); + else + nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, + bssid, req_ie, req_ie_len, + resp_ie, resp_ie_len, + status, gfp); + +#ifdef CONFIG_WIRELESS_EXT + if (wextev) { + if (req_ie && status == WLAN_STATUS_SUCCESS) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = req_ie_len; + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); + } + + if (resp_ie && status == WLAN_STATUS_SUCCESS) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = resp_ie_len; + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); + } + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if (bssid && status == WLAN_STATUS_SUCCESS) + memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); + } +#endif + + if (status == WLAN_STATUS_SUCCESS && + wdev->sme_state == CFG80211_SME_IDLE) { + wdev->sme_state = CFG80211_SME_CONNECTED; + return; + } + if (wdev->sme_state != CFG80211_SME_CONNECTING) return; @@ -315,32 +353,6 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (wdev->conn) wdev->conn->state = CFG80211_CONN_IDLE; - - nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, bssid, - req_ie, req_ie_len, resp_ie, resp_ie_len, - status, gfp); - -#ifdef CONFIG_WIRELESS_EXT - if (wextev) { - if (req_ie && status == WLAN_STATUS_SUCCESS) { - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = req_ie_len; - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); - } - - if (resp_ie && status == WLAN_STATUS_SUCCESS) { - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = resp_ie_len; - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); - } - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if (bssid && status == WLAN_STATUS_SUCCESS) - memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); - } -#endif } void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, -- cgit v0.10.2 From 0eb14647fc6b56f73efb28a72ca0c7cc03a653f9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Jul 2009 15:49:03 +0200 Subject: cfg80211: reset auth algorithm When the interface is brought down, we need to reset the auth algorithm because wpa_supplicant doesn't reset it, and then we fail to use shared key auth when required later. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 413d291..5f6a832 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -579,6 +579,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, kfree(wdev->wext.ie); wdev->wext.ie = NULL; wdev->wext.ie_len = 0; + wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; #endif cfg80211_disconnect(rdev, dev, WLAN_REASON_DEAUTH_LEAVING, true); -- cgit v0.10.2 From 517357c685ccc4b5783cc7dbdae8824ada19a97f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Jul 2009 17:18:40 +0200 Subject: cfg80211: assimilate and export ieee80211_bss_get_ie This function from mac80211 seems generally useful, and I will need it in cfg80211 soon. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index fe87819..eb02654 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -605,6 +605,15 @@ struct cfg80211_bss { }; /** + * ieee80211_bss_get_ie - find IE with given ID + * @bss: the bss to search + * @ie: the IE ID + * Returns %NULL if not found. + */ +const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); + + +/** * struct cfg80211_crypto_settings - Crypto settings * @wpa_versions: indicates which, if any, WPA versions are enabled * (from enum nl80211_wpa_versions) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2d9b666..5748cda 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -46,26 +46,6 @@ static int ecw2cw(int ecw) return (1 << ecw) - 1; } -static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie) -{ - u8 *end, *pos; - - pos = bss->cbss.information_elements; - if (pos == NULL) - return NULL; - end = pos + bss->cbss.len_information_elements; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == ie) - return pos; - pos += 2 + pos[1]; - } - - return NULL; -} - static int ieee80211_compatible_rates(struct ieee80211_bss *bss, struct ieee80211_supported_band *sband, u32 *rates) @@ -181,7 +161,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - u8 *pos, *ies, *ht_ie; + u8 *pos; + const u8 *ies, *ht_ie; int i, len, count, rates_len, supp_rates_len; u16 capab; struct ieee80211_bss *bss; @@ -345,7 +326,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) */ if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && sband->ht_cap.ht_supported && - (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && + (ht_ie = ieee80211_bss_get_ie(&bss->cbss, WLAN_EID_HT_INFORMATION)) && ht_ie[1] >= sizeof(struct ieee80211_ht_info) && (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { struct ieee80211_ht_info *ht_info = diff --git a/net/wireless/util.c b/net/wireless/util.c index 2555069..28f8f96 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -502,3 +502,24 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb) return dscp >> 5; } EXPORT_SYMBOL(cfg80211_classify8021d); + +const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie) +{ + u8 *end, *pos; + + pos = bss->information_elements; + if (pos == NULL) + return NULL; + end = pos + bss->len_information_elements; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + break; + if (pos[0] == ie) + return pos; + pos += 2 + pos[1]; + } + + return NULL; +} +EXPORT_SYMBOL(ieee80211_bss_get_ie); -- cgit v0.10.2 From 19957bb399e2722719c0e20c9ae91cf8b6aaff04 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Jul 2009 17:20:43 +0200 Subject: cfg80211: keep track of BSSes In order to avoid problems with BSS structs going away while they're in use, I've long wanted to make cfg80211 keep track of them. Without the SME, that wasn't doable but now that we have the SME we can do this too. It can keep track of up to four separate authentications and one association, regardless of whether it's controlled by the cfg80211 SME or the userspace SME. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index eb02654..ca986cc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -584,7 +584,6 @@ enum cfg80211_signal_type { * is no guarantee that these are well-formed!) * @len_information_elements: total length of the information elements * @signal: signal strength value (type depends on the wiphy's signal_type) - * @hold: BSS should not expire * @free_priv: function pointer to free private data * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes */ @@ -642,33 +641,17 @@ struct cfg80211_crypto_settings { * * This structure provides information needed to complete IEEE 802.11 * authentication. - * NOTE: This structure will likely change when more code from mac80211 is - * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too. - * Before using this in a driver that does not use mac80211, it would be better - * to check the status of that work and better yet, volunteer to work on it. - * - * @chan: The channel to use or %NULL if not specified (auto-select based on - * scan results) - * @peer_addr: The address of the peer STA (AP BSSID in infrastructure case); - * this field is required to be present; if the driver wants to help with - * BSS selection, it should use (yet to be added) MLME event to allow user - * space SME to be notified of roaming candidate, so that the SME can then - * use the authentication request with the recommended BSSID and whatever - * other data may be needed for authentication/association - * @ssid: SSID or %NULL if not yet available - * @ssid_len: Length of ssid in octets + * + * @bss: The BSS to authenticate with. * @auth_type: Authentication type (algorithm) * @ie: Extra IEs to add to Authentication frame or %NULL * @ie_len: Length of ie buffer in octets */ struct cfg80211_auth_request { - struct ieee80211_channel *chan; - u8 *peer_addr; - const u8 *ssid; - size_t ssid_len; - enum nl80211_auth_type auth_type; + struct cfg80211_bss *bss; const u8 *ie; size_t ie_len; + enum nl80211_auth_type auth_type; }; /** @@ -676,32 +659,18 @@ struct cfg80211_auth_request { * * This structure provides information needed to complete IEEE 802.11 * (re)association. - * NOTE: This structure will likely change when more code from mac80211 is - * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too. - * Before using this in a driver that does not use mac80211, it would be better - * to check the status of that work and better yet, volunteer to work on it. - * - * @chan: The channel to use or %NULL if not specified (auto-select based on - * scan results) - * @peer_addr: The address of the peer STA (AP BSSID); this field is required - * to be present and the STA must be in State 2 (authenticated) with the - * peer STA - * @ssid: SSID - * @ssid_len: Length of ssid in octets + * @bss: The BSS to associate with. * @ie: Extra IEs to add to (Re)Association Request frame or %NULL * @ie_len: Length of ie buffer in octets * @use_mfp: Use management frame protection (IEEE 802.11w) in this association * @crypto: crypto settings */ struct cfg80211_assoc_request { - struct ieee80211_channel *chan; - u8 *peer_addr; - const u8 *ssid; - size_t ssid_len; + struct cfg80211_bss *bss; const u8 *ie; size_t ie_len; - bool use_mfp; struct cfg80211_crypto_settings crypto; + bool use_mfp; }; /** @@ -710,16 +679,16 @@ struct cfg80211_assoc_request { * This structure provides information needed to complete IEEE 802.11 * deauthentication. * - * @peer_addr: The address of the peer STA (AP BSSID); this field is required - * to be present and the STA must be authenticated with the peer STA + * @bss: the BSS to deauthenticate from * @ie: Extra IEs to add to Deauthentication frame or %NULL * @ie_len: Length of ie buffer in octets + * @reason_code: The reason code for the deauthentication */ struct cfg80211_deauth_request { - u8 *peer_addr; - u16 reason_code; + struct cfg80211_bss *bss; const u8 *ie; size_t ie_len; + u16 reason_code; }; /** @@ -728,16 +697,16 @@ struct cfg80211_deauth_request { * This structure provides information needed to complete IEEE 802.11 * disassocation. * - * @peer_addr: The address of the peer STA (AP BSSID); this field is required - * to be present and the STA must be associated with the peer STA + * @bss: the BSS to disassociate from * @ie: Extra IEs to add to Disassociation frame or %NULL * @ie_len: Length of ie buffer in octets + * @reason_code: The reason code for the disassociation */ struct cfg80211_disassoc_request { - u8 *peer_addr; - u16 reason_code; + struct cfg80211_bss *bss; const u8 *ie; size_t ie_len; + u16 reason_code; }; /** @@ -1252,6 +1221,9 @@ extern void wiphy_free(struct wiphy *wiphy); /* internal struct */ struct cfg80211_conn; +struct cfg80211_internal_bss; + +#define MAX_AUTH_BSSES 4 /** * struct wireless_dev - wireless per-netdev state @@ -1281,7 +1253,6 @@ struct wireless_dev { struct net_device *netdev; /* currently used for IBSS and SME - might be rearranged later */ - struct cfg80211_bss *current_bss; u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; enum { @@ -1291,6 +1262,10 @@ struct wireless_dev { } sme_state; struct cfg80211_conn *conn; + struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES]; + struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; + struct cfg80211_internal_bss *current_bss; /* associated / joined */ + #ifdef CONFIG_WIRELESS_EXT /* wext data */ struct { @@ -1813,23 +1788,6 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); /** - * cfg80211_hold_bss - exclude bss from expiration - * @bss: bss which should not expire - * - * In a case when the BSS is not updated but it shouldn't expire this - * function can be used to mark the BSS to be excluded from expiration. - */ -void cfg80211_hold_bss(struct cfg80211_bss *bss); - -/** - * cfg80211_unhold_bss - remove expiration exception from the BSS - * @bss: bss which can expire again - * - * This function marks the BSS to be expirable again. - */ -void cfg80211_unhold_bss(struct cfg80211_bss *bss); - -/** * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP) * @dev: network device * @addr: The source MAC address of the frame diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7606571..0f29cd0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1173,6 +1173,7 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_auth_request *req) { struct ieee80211_sub_if_data *sdata; + const u8 *ssid; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -1193,15 +1194,16 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, return -EOPNOTSUPP; } - memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN); + memcpy(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN); - sdata->local->oper_channel = req->chan; + sdata->local->oper_channel = req->bss->channel; ieee80211_hw_config(sdata->local, 0); - if (!req->ssid) + ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); + if (!ssid) return -EINVAL; - memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); - sdata->u.mgd.ssid_len = req->ssid_len; + sdata->u.mgd.ssid_len = *(ssid + 1); + memcpy(sdata->u.mgd.ssid, ssid + 2, sdata->u.mgd.ssid_len); kfree(sdata->u.mgd.sme_auth_ie); sdata->u.mgd.sme_auth_ie = NULL; @@ -1227,7 +1229,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0 || + if (memcmp(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN) != 0 || !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) return -ENOLINK; /* not authenticated */ @@ -1239,15 +1241,9 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N; - sdata->local->oper_channel = req->chan; + sdata->local->oper_channel = req->bss->channel; ieee80211_hw_config(sdata->local, 0); - if (!req->ssid) - return -EINVAL; - - memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); - sdata->u.mgd.ssid_len = req->ssid_len; - ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); if (ret && ret != -EALREADY) return ret; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5748cda..aa1829a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -876,8 +876,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss_info_changed |= ieee80211_handle_bss_capability(sdata, bss->cbss.capability, bss->has_erp_value, bss->erp_value); - cfg80211_hold_bss(&bss->cbss); - ieee80211_rx_bss_put(local, bss); } @@ -1031,10 +1029,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, conf->channel->center_freq, ifmgd->ssid, ifmgd->ssid_len); - if (bss) { - cfg80211_unhold_bss(&bss->cbss); + if (bss) ieee80211_rx_bss_put(local, bss); - } if (self_disconnected) { if (deauth) diff --git a/net/wireless/core.c b/net/wireless/core.c index 5f6a832..7b66cf1 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -583,15 +583,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, #endif cfg80211_disconnect(rdev, dev, WLAN_REASON_DEAUTH_LEAVING, true); + cfg80211_mlme_down(rdev, dev); break; default: break; } break; - case NETDEV_DOWN: - kfree(wdev->conn); - wdev->conn = NULL; - break; case NETDEV_UP: #ifdef CONFIG_WIRELESS_EXT switch (wdev->iftype) { diff --git a/net/wireless/core.h b/net/wireless/core.h index 5209acb..82918f5 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -110,12 +110,30 @@ struct cfg80211_internal_bss { struct rb_node rbn; unsigned long ts; struct kref ref; - bool hold, ies_allocated; + atomic_t hold; + bool ies_allocated; /* must be last because of priv member */ struct cfg80211_bss pub; }; +static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pub) +{ + return container_of(pub, struct cfg80211_internal_bss, pub); +} + +static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) +{ + atomic_inc(&bss->hold); +} + +static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) +{ + int r = atomic_dec_return(&bss->hold); + WARN_ON(r < 0); +} + + struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); int get_wiphy_idx(struct wiphy *wiphy); @@ -176,6 +194,26 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext); int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, bool nowext); +/* MLME */ +int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, + struct net_device *dev, struct ieee80211_channel *chan, + enum nl80211_auth_type auth_type, const u8 *bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len); +int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, struct ieee80211_channel *chan, + const u8 *bssid, const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, bool use_mfp, + struct cfg80211_crypto_settings *crypt); +int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason); +int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason); +void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, + struct net_device *dev); + /* SME */ int cfg80211_connect(struct cfg80211_registered_device *rdev, struct net_device *dev, @@ -193,5 +231,6 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, size_t ie_len, u16 reason, bool from_ap); void cfg80211_sme_scan_done(struct net_device *dev); void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); +void cfg80211_sme_disassoc(struct net_device *dev, int idx); #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 34b11ea..c92b542 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -33,11 +33,11 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); } - cfg80211_hold_bss(bss); - wdev->current_bss = bss; + cfg80211_hold_bss(bss_from_pub(bss)); + wdev->current_bss = bss_from_pub(bss); nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); #ifdef CONFIG_WIRELESS_EXT @@ -78,7 +78,7 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext) if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); } wdev->current_bss = NULL; @@ -212,7 +212,7 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, return -EINVAL; if (wdev->current_bss) - chan = wdev->current_bss->channel; + chan = wdev->current_bss->pub.channel; else if (wdev->wext.ibss.channel) chan = wdev->wext.ibss.channel; @@ -352,7 +352,7 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, ap_addr->sa_family = ARPHRD_ETHER; if (wdev->current_bss) - memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN); + memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); else memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); return 0; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 3427fe7..1a92bf7 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -14,8 +14,32 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) { - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + u8 *bssid = mgmt->bssid; + int i; + u16 status = le16_to_cpu(mgmt->u.auth.status_code); + bool done = false; + + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->authtry_bsses[i] && + memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, + ETH_ALEN) == 0) { + if (status == WLAN_STATUS_SUCCESS) { + wdev->auth_bsses[i] = wdev->authtry_bsses[i]; + } else { + cfg80211_unhold_bss(wdev->authtry_bsses[i]); + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); + } + wdev->authtry_bsses[i] = NULL; + done = true; + break; + } + } + + WARN_ON(!done); nl80211_send_rx_auth(rdev, dev, buf, len, gfp); cfg80211_sme_rx_auth(dev, buf, len); @@ -30,7 +54,8 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, g struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; u8 *ie = mgmt->u.assoc_resp.variable; - int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); + int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); + bool done; status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); @@ -38,6 +63,20 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, g cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, status_code, gfp); + + if (status_code == WLAN_STATUS_SUCCESS) { + for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) { + if (wdev->auth_bsses[i] == wdev->current_bss) { + cfg80211_unhold_bss(wdev->auth_bsses[i]); + cfg80211_put_bss(&wdev->auth_bsses[i]->pub); + wdev->auth_bsses[i] = NULL; + done = true; + break; + } + } + + WARN_ON(!done); + } } EXPORT_SYMBOL(cfg80211_send_rx_assoc); @@ -47,9 +86,45 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + const u8 *bssid = mgmt->bssid; + int i; + bool done = false; nl80211_send_deauth(rdev, dev, buf, len, gfp); + if (wdev->current_bss && + memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { + done = true; + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + wdev->current_bss = NULL; + } else for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->auth_bsses[i] && + memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { + cfg80211_unhold_bss(wdev->auth_bsses[i]); + cfg80211_put_bss(&wdev->auth_bsses[i]->pub); + wdev->auth_bsses[i] = NULL; + done = true; + break; + } + if (wdev->authtry_bsses[i] && + memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { + cfg80211_unhold_bss(wdev->authtry_bsses[i]); + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); + wdev->authtry_bsses[i] = NULL; + done = true; + break; + } + } +/* + * mac80211 currently triggers this warning, + * so disable for now (it's harmless, just + * means that we got a spurious event) + + WARN_ON(!done); + + */ + if (wdev->sme_state == CFG80211_SME_CONNECTED) { u16 reason_code; bool from_ap; @@ -59,8 +134,6 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; __cfg80211_disconnected(dev, gfp, NULL, 0, reason_code, from_ap); - - wdev->sme_state = CFG80211_SME_IDLE; } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); @@ -74,21 +147,38 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, g struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; + const u8 *bssid = mgmt->bssid; + int i; + u16 reason_code; + bool from_ap; + bool done = false; nl80211_send_disassoc(rdev, dev, buf, len, gfp); - if (wdev->sme_state == CFG80211_SME_CONNECTED) { - u16 reason_code; - bool from_ap; + if (!wdev->sme_state == CFG80211_SME_CONNECTED) + return; - reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); + if (wdev->current_bss && + memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) { + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) + continue; + wdev->auth_bsses[i] = wdev->current_bss; + wdev->current_bss = NULL; + done = true; + cfg80211_sme_disassoc(dev, i); + break; + } + WARN_ON(!done); + } else + WARN_ON(1); - from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; - __cfg80211_disconnected(dev, gfp, NULL, 0, - reason_code, from_ap); - wdev->sme_state = CFG80211_SME_IDLE; - } + reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); + + from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; + __cfg80211_disconnected(dev, gfp, NULL, 0, + reason_code, from_ap); } EXPORT_SYMBOL(cfg80211_send_disassoc); @@ -97,11 +187,27 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gf struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + int i; + bool done = false; + nl80211_send_auth_timeout(rdev, dev, addr, gfp); if (wdev->sme_state == CFG80211_SME_CONNECTING) cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); - wdev->sme_state = CFG80211_SME_IDLE; + + for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { + if (wdev->authtry_bsses[i] && + memcmp(wdev->authtry_bsses[i]->pub.bssid, + addr, ETH_ALEN) == 0) { + cfg80211_unhold_bss(wdev->authtry_bsses[i]); + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); + wdev->authtry_bsses[i] = NULL; + done = true; + break; + } + } + + WARN_ON(!done); } EXPORT_SYMBOL(cfg80211_send_auth_timeout); @@ -110,11 +216,27 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t g struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + int i; + bool done = false; + nl80211_send_assoc_timeout(rdev, dev, addr, gfp); if (wdev->sme_state == CFG80211_SME_CONNECTING) cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); - wdev->sme_state = CFG80211_SME_IDLE; + + for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { + if (wdev->auth_bsses[i] && + memcmp(wdev->auth_bsses[i]->pub.bssid, + addr, ETH_ALEN) == 0) { + cfg80211_unhold_bss(wdev->auth_bsses[i]); + cfg80211_put_bss(&wdev->auth_bsses[i]->pub); + wdev->auth_bsses[i] = NULL; + done = true; + break; + } + } + + WARN_ON(!done); } EXPORT_SYMBOL(cfg80211_send_assoc_timeout); @@ -143,3 +265,208 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp); } EXPORT_SYMBOL(cfg80211_michael_mic_failure); + +/* some MLME handling for userspace SME */ +int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, + struct net_device *dev, struct ieee80211_channel *chan, + enum nl80211_auth_type auth_type, const u8 *bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_auth_request req; + struct cfg80211_internal_bss *bss; + int i, err, slot = -1, nfree = 0; + + memset(&req, 0, sizeof(req)); + + req.ie = ie; + req.ie_len = ie_len; + req.auth_type = auth_type; + req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + if (!req.bss) + return -ENOENT; + + bss = bss_from_pub(req.bss); + + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (bss == wdev->auth_bsses[i]) { + err = -EALREADY; + goto out; + } + } + + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) { + slot = i; + nfree++; + } + } + + /* we need one free slot for disassoc and one for this auth */ + if (nfree < 2) { + err = -ENOSPC; + goto out; + } + + wdev->authtry_bsses[slot] = bss; + cfg80211_hold_bss(bss); + + err = rdev->ops->auth(&rdev->wiphy, dev, &req); + if (err) { + wdev->authtry_bsses[slot] = NULL; + cfg80211_unhold_bss(bss); + } + + out: + if (err) + cfg80211_put_bss(req.bss); + return err; +} + +int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, struct ieee80211_channel *chan, + const u8 *bssid, const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, bool use_mfp, + struct cfg80211_crypto_settings *crypt) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_assoc_request req; + struct cfg80211_internal_bss *bss; + int i, err, slot = -1; + + memset(&req, 0, sizeof(req)); + + if (wdev->current_bss) + return -EALREADY; + + req.ie = ie; + req.ie_len = ie_len; + memcpy(&req.crypto, crypt, sizeof(req.crypto)); + req.use_mfp = use_mfp; + req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + if (!req.bss) + return -ENOENT; + + bss = bss_from_pub(req.bss); + + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (bss == wdev->auth_bsses[i]) { + slot = i; + break; + } + } + + if (slot < 0) { + err = -ENOTCONN; + goto out; + } + + err = rdev->ops->assoc(&rdev->wiphy, dev, &req); + out: + /* still a reference in wdev->auth_bsses[slot] */ + cfg80211_put_bss(req.bss); + return err; +} + +int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_deauth_request req; + int i; + + memset(&req, 0, sizeof(req)); + req.reason_code = reason; + req.ie = ie; + req.ie_len = ie_len; + if (wdev->current_bss && + memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { + req.bss = &wdev->current_bss->pub; + } else for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->auth_bsses[i] && + memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) { + req.bss = &wdev->auth_bsses[i]->pub; + break; + } + if (wdev->authtry_bsses[i] && + memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) { + req.bss = &wdev->authtry_bsses[i]->pub; + break; + } + } + + if (!req.bss) + return -ENOTCONN; + + return rdev->ops->deauth(&rdev->wiphy, dev, &req); +} + +int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_disassoc_request req; + + memset(&req, 0, sizeof(req)); + req.reason_code = reason; + req.ie = ie; + req.ie_len = ie_len; + if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) + req.bss = &wdev->current_bss->pub; + else + return -ENOTCONN; + + return rdev->ops->disassoc(&rdev->wiphy, dev, &req); +} + +void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_deauth_request req; + int i; + + if (!rdev->ops->deauth) + return; + + memset(&req, 0, sizeof(req)); + req.reason_code = WLAN_REASON_DEAUTH_LEAVING; + req.ie = NULL; + req.ie_len = 0; + + if (wdev->current_bss) { + req.bss = &wdev->current_bss->pub; + rdev->ops->deauth(&rdev->wiphy, dev, &req); + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + wdev->current_bss = NULL; + } + } + + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->auth_bsses[i]) { + req.bss = &wdev->auth_bsses[i]->pub; + rdev->ops->deauth(&rdev->wiphy, dev, &req); + if (wdev->auth_bsses[i]) { + cfg80211_unhold_bss(wdev->auth_bsses[i]); + cfg80211_put_bss(&wdev->auth_bsses[i]->pub); + wdev->auth_bsses[i] = NULL; + } + } + if (wdev->authtry_bsses[i]) { + req.bss = &wdev->authtry_bsses[i]->pub; + rdev->ops->deauth(&rdev->wiphy, dev, &req); + if (wdev->authtry_bsses[i]) { + cfg80211_unhold_bss(wdev->authtry_bsses[i]); + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); + wdev->authtry_bsses[i] = NULL; + } + } + } +} diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0008144..aa2b3f3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3044,9 +3044,10 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; struct net_device *dev; - struct cfg80211_auth_request req; - struct wiphy *wiphy; - int err; + struct ieee80211_channel *chan; + const u8 *bssid, *ssid, *ie = NULL; + int err, ssid_len, ie_len = 0; + enum nl80211_auth_type auth_type; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; @@ -3057,6 +3058,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) return -EINVAL; + if (!info->attrs[NL80211_ATTR_SSID]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -3078,38 +3085,30 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) goto out; } - wiphy = &drv->wiphy; - memset(&req, 0, sizeof(req)); - - req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - - if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { - req.chan = ieee80211_get_channel( - wiphy, - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); - if (!req.chan) { - err = -EINVAL; - goto out; - } + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + chan = ieee80211_get_channel(&drv->wiphy, + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); + if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { + err = -EINVAL; + goto out; } - if (info->attrs[NL80211_ATTR_SSID]) { - req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); - req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); - } + ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); if (info->attrs[NL80211_ATTR_IE]) { - req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); - req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + ie = nla_data(info->attrs[NL80211_ATTR_IE]); + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } - req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); - if (!nl80211_valid_auth_type(req.auth_type)) { + auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); + if (!nl80211_valid_auth_type(auth_type)) { err = -EINVAL; goto out; } - err = drv->ops->auth(&drv->wiphy, dev, &req); + err = cfg80211_mlme_auth(drv, dev, chan, auth_type, bssid, + ssid, ssid_len, ie, ie_len); out: cfg80211_put_dev(drv); @@ -3183,26 +3182,29 @@ static int nl80211_crypto_settings(struct genl_info *info, static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct net_device *dev; - struct cfg80211_assoc_request req; - struct wiphy *wiphy; - int err; + struct cfg80211_crypto_settings crypto; + struct ieee80211_channel *chan; + const u8 *bssid, *ssid, *ie = NULL; + int err, ssid_len, ie_len = 0; + bool use_mfp = false; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; if (!info->attrs[NL80211_ATTR_MAC] || - !info->attrs[NL80211_ATTR_SSID]) + !info->attrs[NL80211_ATTR_SSID] || + !info->attrs[NL80211_ATTR_WIPHY_FREQ]) return -EINVAL; rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_drv_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; - if (!drv->ops->assoc) { + if (!rdev->ops->assoc) { err = -EOPNOTSUPP; goto out; } @@ -3217,46 +3219,42 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) goto out; } - wiphy = &drv->wiphy; - memset(&req, 0, sizeof(req)); - - req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { - req.chan = ieee80211_get_channel( - wiphy, - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); - if (!req.chan) { - err = -EINVAL; - goto out; - } + chan = ieee80211_get_channel(&rdev->wiphy, + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); + if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { + err = -EINVAL; + goto out; } - req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); - req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); + ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); if (info->attrs[NL80211_ATTR_IE]) { - req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); - req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + ie = nla_data(info->attrs[NL80211_ATTR_IE]); + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } if (info->attrs[NL80211_ATTR_USE_MFP]) { enum nl80211_mfp use_mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); if (use_mfp == NL80211_MFP_REQUIRED) - req.use_mfp = true; + use_mfp = true; else if (use_mfp != NL80211_MFP_NO) { err = -EINVAL; goto out; } } - err = nl80211_crypto_settings(info, &req.crypto); + err = nl80211_crypto_settings(info, &crypto); if (!err) - err = drv->ops->assoc(&drv->wiphy, dev, &req); + err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, ssid, + ssid_len, ie, ie_len, use_mfp, + &crypto); out: - cfg80211_put_dev(drv); + cfg80211_put_dev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3267,9 +3265,9 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; struct net_device *dev; - struct cfg80211_deauth_request req; - struct wiphy *wiphy; - int err; + const u8 *ie = NULL, *bssid; + int err, ie_len = 0; + u16 reason_code; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; @@ -3301,24 +3299,21 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) goto out; } - wiphy = &drv->wiphy; - memset(&req, 0, sizeof(req)); - - req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); - req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); - if (req.reason_code == 0) { + reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + if (reason_code == 0) { /* Reason Code 0 is reserved */ err = -EINVAL; goto out; } if (info->attrs[NL80211_ATTR_IE]) { - req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); - req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + ie = nla_data(info->attrs[NL80211_ATTR_IE]); + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } - err = drv->ops->deauth(&drv->wiphy, dev, &req); + err = cfg80211_mlme_deauth(drv, dev, bssid, ie, ie_len, reason_code); out: cfg80211_put_dev(drv); @@ -3332,9 +3327,9 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; struct net_device *dev; - struct cfg80211_disassoc_request req; - struct wiphy *wiphy; - int err; + const u8 *ie = NULL, *bssid; + int err, ie_len = 0; + u16 reason_code; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; @@ -3366,24 +3361,21 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) goto out; } - wiphy = &drv->wiphy; - memset(&req, 0, sizeof(req)); - - req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); - req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); - if (req.reason_code == 0) { + reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + if (reason_code == 0) { /* Reason Code 0 is reserved */ err = -EINVAL; goto out; } if (info->attrs[NL80211_ATTR_IE]) { - req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); - req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + ie = nla_data(info->attrs[NL80211_ATTR_IE]); + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } - err = drv->ops->disassoc(&drv->wiphy, dev, &req); + err = cfg80211_mlme_disassoc(drv, dev, bssid, ie, ie_len, reason_code); out: cfg80211_put_dev(drv); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 82b33e7..9253994 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -70,6 +70,8 @@ static void bss_release(struct kref *ref) if (bss->ies_allocated) kfree(bss->pub.information_elements); + BUG_ON(atomic_read(&bss->hold)); + kfree(bss); } @@ -92,8 +94,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) bool expired = false; list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { - if (bss->hold || - !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) + if (atomic_read(&bss->hold)) + continue; + if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) continue; list_del(&bss->list); rb_erase(&bss->rbn, &dev->bss_tree); @@ -553,30 +556,6 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) } EXPORT_SYMBOL(cfg80211_unlink_bss); -void cfg80211_hold_bss(struct cfg80211_bss *pub) -{ - struct cfg80211_internal_bss *bss; - - if (!pub) - return; - - bss = container_of(pub, struct cfg80211_internal_bss, pub); - bss->hold = true; -} -EXPORT_SYMBOL(cfg80211_hold_bss); - -void cfg80211_unhold_bss(struct cfg80211_bss *pub) -{ - struct cfg80211_internal_bss *bss; - - if (!pub) - return; - - bss = container_of(pub, struct cfg80211_internal_bss, pub); - bss->hold = false; -} -EXPORT_SYMBOL(cfg80211_unhold_bss); - #ifdef CONFIG_WIRELESS_EXT int cfg80211_wext_siwscan(struct net_device *dev, struct iw_request_info *info, diff --git a/net/wireless/sme.c b/net/wireless/sme.c index d4e0b40..412161f 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -103,44 +103,37 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) static int cfg80211_conn_do_work(struct wireless_dev *wdev) { struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); - union { - struct cfg80211_auth_request auth_req; - struct cfg80211_assoc_request assoc_req; - } u; - - memset(&u, 0, sizeof(u)); + struct cfg80211_connect_params *params; + int err; if (!wdev->conn) return 0; + params = &wdev->conn->params; + switch (wdev->conn->state) { case CFG80211_CONN_SCAN_AGAIN: return cfg80211_conn_scan(wdev); case CFG80211_CONN_AUTHENTICATE_NEXT: - u.auth_req.chan = wdev->conn->params.channel; - u.auth_req.peer_addr = wdev->conn->params.bssid; - u.auth_req.ssid = wdev->conn->params.ssid; - u.auth_req.ssid_len = wdev->conn->params.ssid_len; - u.auth_req.auth_type = wdev->conn->params.auth_type; - u.auth_req.ie = NULL; - u.auth_req.ie_len = 0; - wdev->conn->state = CFG80211_CONN_AUTHENTICATING; BUG_ON(!drv->ops->auth); - return drv->ops->auth(wdev->wiphy, wdev->netdev, &u.auth_req); + wdev->conn->state = CFG80211_CONN_AUTHENTICATING; + return cfg80211_mlme_auth(drv, wdev->netdev, + params->channel, params->auth_type, + params->bssid, + params->ssid, params->ssid_len, + NULL, 0); case CFG80211_CONN_ASSOCIATE_NEXT: - u.assoc_req.chan = wdev->conn->params.channel; - u.assoc_req.peer_addr = wdev->conn->params.bssid; - u.assoc_req.ssid = wdev->conn->params.ssid; - u.assoc_req.ssid_len = wdev->conn->params.ssid_len; - u.assoc_req.ie = wdev->conn->params.ie; - u.assoc_req.ie_len = wdev->conn->params.ie_len; - u.assoc_req.use_mfp = false; - memcpy(&u.assoc_req.crypto, &wdev->conn->params.crypto, - sizeof(u.assoc_req.crypto)); - wdev->conn->state = CFG80211_CONN_ASSOCIATING; BUG_ON(!drv->ops->assoc); - return drv->ops->assoc(wdev->wiphy, wdev->netdev, - &u.assoc_req); + wdev->conn->state = CFG80211_CONN_ASSOCIATING; + err = cfg80211_mlme_assoc(drv, wdev->netdev, + params->channel, params->bssid, + params->ssid, params->ssid_len, + params->ie, params->ie_len, + false, ¶ms->crypto); + if (err) + cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid, + NULL, 0, WLAN_REASON_DEAUTH_LEAVING); + return err; default: return 0; } @@ -186,7 +179,6 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) wdev->conn->params.ssid_len, WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, capa); - if (!bss) return false; @@ -264,9 +256,11 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) } wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; schedule_work(&rdev->conn_work); - } else if (status_code != WLAN_STATUS_SUCCESS) + } else if (status_code != WLAN_STATUS_SUCCESS) { wdev->sme_state = CFG80211_SME_IDLE; - else if (wdev->sme_state == CFG80211_SME_CONNECTING && + kfree(wdev->conn); + wdev->conn = NULL; + } else if (wdev->sme_state == CFG80211_SME_CONNECTING && wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; schedule_work(&rdev->conn_work); @@ -330,10 +324,13 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); wdev->current_bss = NULL; } + if (wdev->conn) + wdev->conn->state = CFG80211_CONN_IDLE; + if (status == WLAN_STATUS_SUCCESS) { bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, wdev->ssid, wdev->ssid_len, @@ -343,16 +340,15 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (WARN_ON(!bss)) return; - cfg80211_hold_bss(bss); - wdev->current_bss = bss; + cfg80211_hold_bss(bss_from_pub(bss)); + wdev->current_bss = bss_from_pub(bss); wdev->sme_state = CFG80211_SME_CONNECTED; } else { wdev->sme_state = CFG80211_SME_IDLE; + kfree(wdev->conn); + wdev->conn = NULL; } - - if (wdev->conn) - wdev->conn->state = CFG80211_CONN_IDLE; } void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, @@ -387,7 +383,7 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, } cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); wdev->current_bss = NULL; bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, @@ -397,8 +393,8 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, if (WARN_ON(!bss)) return; - cfg80211_hold_bss(bss); - wdev->current_bss = bss; + cfg80211_hold_bss(bss_from_pub(bss)); + wdev->current_bss = bss_from_pub(bss); nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); @@ -440,7 +436,7 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); } wdev->current_bss = NULL; @@ -449,6 +445,8 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, if (wdev->conn) { kfree(wdev->conn->ie); wdev->conn->ie = NULL; + kfree(wdev->conn); + wdev->conn = NULL; } nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, @@ -482,12 +480,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, if (!rdev->ops->auth || !rdev->ops->assoc) return -EOPNOTSUPP; - if (!wdev->conn) { - wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); - if (!wdev->conn) - return -ENOMEM; - } else - memset(wdev->conn, 0, sizeof(*wdev->conn)); + if (WARN_ON(wdev->conn)) + return -EINPROGRESS; + + wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); + if (!wdev->conn) + return -ENOMEM; /* * Copy all parameters, and treat explicitly IEs, BSSID, SSID. @@ -502,8 +500,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, GFP_KERNEL); wdev->conn->params.ie = wdev->conn->ie; - if (!wdev->conn->ie) + if (!wdev->conn->ie) { + kfree(wdev->conn); + wdev->conn = NULL; return -ENOMEM; + } } if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { @@ -543,8 +544,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; } } - if (err) + if (err) { + kfree(wdev->conn); + wdev->conn = NULL; wdev->sme_state = CFG80211_SME_IDLE; + } return err; } else { @@ -572,31 +576,27 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, return -EINVAL; if (!rdev->ops->disconnect) { - struct cfg80211_deauth_request deauth; - u8 bssid[ETH_ALEN]; + if (!rdev->ops->deauth) + return -EOPNOTSUPP; - /* internal bug. */ - if (WARN_ON(!wdev->conn)) - return -EINVAL; + /* was it connected by userspace SME? */ + if (!wdev->conn) { + cfg80211_mlme_down(rdev, dev); + return 0; + } if (wdev->sme_state == CFG80211_SME_CONNECTING && (wdev->conn->state == CFG80211_CONN_SCANNING || wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { wdev->sme_state = CFG80211_SME_IDLE; + kfree(wdev->conn); + wdev->conn = NULL; return 0; } - if (!rdev->ops->deauth) - return -EOPNOTSUPP; - - memset(&deauth, 0, sizeof(deauth)); - /* wdev->conn->params.bssid must be set if > SCANNING */ - memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN); - deauth.peer_addr = bssid; - deauth.reason_code = reason; - - err = rdev->ops->deauth(&rdev->wiphy, dev, &deauth); + err = cfg80211_mlme_deauth(rdev, dev, wdev->conn->params.bssid, + NULL, 0, reason); if (err) return err; } else { @@ -614,3 +614,33 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, return 0; } + +void cfg80211_sme_disassoc(struct net_device *dev, int idx) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u8 bssid[ETH_ALEN]; + + if (!wdev->conn) + return; + + if (wdev->conn->state == CFG80211_CONN_IDLE) + return; + + /* + * Ok, so the association was made by this SME -- we don't + * want it any more so deauthenticate too. + */ + + if (!wdev->auth_bsses[idx]) + return; + + memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); + if (cfg80211_mlme_deauth(rdev, dev, bssid, + NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) { + /* whatever -- assume gone anyway */ + cfg80211_unhold_bss(wdev->auth_bsses[idx]); + cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); + wdev->auth_bsses[idx] = NULL; + } +} diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 3b531d5..fe1987a 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -93,7 +93,7 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev, return -EINVAL; if (wdev->current_bss) - chan = wdev->current_bss->channel; + chan = wdev->current_bss->pub.channel; else if (wdev->wext.connect.channel) chan = wdev->wext.connect.channel; @@ -244,7 +244,7 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev, ap_addr->sa_family = ARPHRD_ETHER; if (wdev->current_bss) - memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN); + memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); else if (wdev->wext.connect.bssid) memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN); else -- cgit v0.10.2 From 0a9b5e17952ec7ce938645a23ba29bcfdb66c8d9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Jul 2009 18:26:18 +0200 Subject: cfg80211: refuse authenticating to same BSSID twice It is possible that there are different BSS structs with the same BSSID, but we cannot authenticate with multiple of them them because we need the BSSID to be unique for deauthenticating/disassociating. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 1a92bf7..020f33b 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -278,6 +278,21 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *bss; int i, err, slot = -1, nfree = 0; + if (wdev->current_bss && + memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0) + return -EALREADY; + + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (wdev->authtry_bsses[i] && + memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, + ETH_ALEN) == 0) + return -EALREADY; + if (wdev->auth_bsses[i] && + memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, + ETH_ALEN) == 0) + return -EALREADY; + } + memset(&req, 0, sizeof(req)); req.ie = ie; @@ -291,13 +306,6 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, bss = bss_from_pub(req.bss); for (i = 0; i < MAX_AUTH_BSSES; i++) { - if (bss == wdev->auth_bsses[i]) { - err = -EALREADY; - goto out; - } - } - - for (i = 0; i < MAX_AUTH_BSSES; i++) { if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) { slot = i; nfree++; -- cgit v0.10.2 From 4244f41a040288e07d050ea64f60997c584cce9e Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 2 Jul 2009 20:26:45 +0100 Subject: orinoco: fix printk format specifier for size_t arguments This addresses the following compile warnings on 64-bit platforms. drivers/net/wireless/orinoco/scan.c: In function 'orinoco_add_hostscan_results': drivers/net/wireless/orinoco/scan.c:194: warning: format '%d' expects type 'int', but argument 3 has type 'size_t' drivers/net/wireless/orinoco/scan.c:211: warning: format '%d' expects type 'int', but argument 3 has type 'size_t' drivers/net/wireless/orinoco/scan.c:211: warning: format '%d' expects type 'int', but argument 4 has type 'size_t' Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c index 522eb98..d2f10e9 100644 --- a/drivers/net/wireless/orinoco/scan.c +++ b/drivers/net/wireless/orinoco/scan.c @@ -190,7 +190,7 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv, /* Sanity check for atom_len */ if (atom_len < sizeof(struct prism2_scan_apinfo)) { printk(KERN_ERR "%s: Invalid atom_len in scan " - "data: %d\n", priv->ndev->name, + "data: %zu\n", priv->ndev->name, atom_len); abort = true; goto scan_abort; @@ -206,8 +206,8 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv, /* Check that we got an whole number of atoms */ if ((len - offset) % atom_len) { - printk(KERN_ERR "%s: Unexpected scan data length %d, " - "atom_len %d, offset %d\n", priv->ndev->name, len, + printk(KERN_ERR "%s: Unexpected scan data length %zu, " + "atom_len %zu, offset %d\n", priv->ndev->name, len, atom_len, offset); abort = true; goto scan_abort; -- cgit v0.10.2 From 3dc27d25f288c923735e8f10fa8e578be896e96a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Jul 2009 21:36:37 +0200 Subject: nl80211: limit to one pairwise cipher for associate() In this case, only one cipher makes sense, unlike for connect() where it may be possible to have the card or driver select. No changes to mac80211 due to the way the structs are laid out -- but the loop in net/mac80211/cfg.c will degrade to just zero or one passes. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index aa2b3f3..723512b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3119,7 +3119,8 @@ unlock_rtnl: } static int nl80211_crypto_settings(struct genl_info *info, - struct cfg80211_crypto_settings *settings) + struct cfg80211_crypto_settings *settings, + int cipher_limit) { settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; @@ -3134,7 +3135,7 @@ static int nl80211_crypto_settings(struct genl_info *info, if (len % sizeof(u32)) return -EINVAL; - if (settings->n_ciphers_pairwise > NL80211_MAX_NR_CIPHER_SUITES) + if (settings->n_ciphers_pairwise > cipher_limit) return -EINVAL; memcpy(settings->ciphers_pairwise, data, len); @@ -3247,7 +3248,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) } } - err = nl80211_crypto_settings(info, &crypto); + err = nl80211_crypto_settings(info, &crypto, 1); if (!err) err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, ssid, ssid_len, ie, ie_len, use_mfp, @@ -3652,7 +3653,8 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; - err = nl80211_crypto_settings(info, &connect.crypto); + err = nl80211_crypto_settings(info, &connect.crypto, + NL80211_MAX_NR_CIPHER_SUITES); if (err) return err; rtnl_lock(); -- cgit v0.10.2 From 9834c079d130217c8c5ac8791428ebeb8c660538 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jul 2009 19:40:51 +0200 Subject: cfg80211: fix giwrange "cfg80211: Advertise ciphers via WE according to driver capability" unfortunately broke iwrange -- it used the variable c that needs to be 0 for the channel list. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 226cf86..d39688c 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -154,7 +154,7 @@ int cfg80211_wext_giwrange(struct net_device *dev, struct wireless_dev *wdev = dev->ieee80211_ptr; struct iw_range *range = (struct iw_range *) extra; enum ieee80211_band band; - int c = 0; + int i, c = 0; if (!wdev) return -EOPNOTSUPP; @@ -201,8 +201,8 @@ int cfg80211_wext_giwrange(struct net_device *dev, range->avg_qual.noise = range->max_qual.noise / 2; range->avg_qual.updated = range->max_qual.updated; - for (c = 0; c < wdev->wiphy->n_cipher_suites; c++) { - switch (wdev->wiphy->cipher_suites[c]) { + for (i = 0; i < wdev->wiphy->n_cipher_suites; i++) { + switch (wdev->wiphy->cipher_suites[i]) { case WLAN_CIPHER_SUITE_TKIP: range->enc_capa |= (IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_WPA); @@ -226,7 +226,6 @@ int cfg80211_wext_giwrange(struct net_device *dev, } for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { - int i; struct ieee80211_supported_band *sband; sband = wdev->wiphy->bands[band]; -- cgit v0.10.2 From ce8d096dac70e92a506d2f686ae4f724f42052cf Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Wed, 17 Jun 2009 18:45:34 -0700 Subject: libertas: copy WPA keys to priv when associating Libertas currently maintains a copy of the WPA unicast and group keys when using WPA or WPA2. This copy is checked when deciding whether or not to return to sleep in IEEE PS mode but the actual copying back to priv was omitted, which breaks IEEE PS mode with WPA/WPA2 when one issues commands that require temporarily keeping the device awake. This patch introduces the omitted copy-back of the keys so that IEEE PS functions correctly in WPA/WPA2 mode. Thanks to Dan Williams for clearing up the issue. V2: fix typo. Also, this has been tested on GSPI and SDIO with V9 firmware. Signed-off-by: Andrey Yurovsky Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index b9b3741..fbf2649 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1368,11 +1368,17 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv, if (ret) goto out; + memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key, + sizeof(struct enc_key)); + if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req); assoc_req->flags = flags; + + memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key, + sizeof(struct enc_key)); } out: -- cgit v0.10.2 From efcfd1f28f6a5c377a0e630ca2c96c54eb3f1e8f Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Thu, 18 Jun 2009 09:51:57 -0700 Subject: libertas: correct card cleanup order in SPI driver The SPI driver does a couple of card cleanup steps in the wrong order on module removal. If IEEE PS is enabled, this results in the card being left in IEEE PS mode and subsequent failures to reload the module. The problem is that the surpriseremoved flag is set before calling lbs_remove_card, but that function needs to issue a command to exit IEEE PS mode (the flag blocks the command path). In addition, lbs_stop_card should be called first because it clears out any pending commands. Tested on a GSPI device with V9 firmware by confirming that we can reload the module with or without IEEE PS enabled. Also fix a warning from the wrong uint format in a printk. V2: use z modifier, thanks Sebastian. Signed-off-by: Andrey Yurovsky Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index b213de4..963c201 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -737,7 +737,7 @@ static int if_spi_c2h_data(struct if_spi_card *card) goto out; } else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { lbs_pr_err("%s: error: card has %d bytes of data, but " - "our maximum skb size is %lu\n", + "our maximum skb size is %zu\n", __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); err = -EINVAL; goto out; @@ -1170,12 +1170,13 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) lbs_deb_spi("libertas_spi_remove\n"); lbs_deb_enter(LBS_DEB_SPI); - priv->surpriseremoved = 1; lbs_stop_card(priv); + lbs_remove_card(priv); /* will call free_netdev */ + + priv->surpriseremoved = 1; free_irq(spi->irq, card); if_spi_terminate_spi_thread(card); - lbs_remove_card(priv); /* will call free_netdev */ if (card->pdata->teardown) card->pdata->teardown(spi); free_if_spi_card(card); -- cgit v0.10.2 From 23b149c1890f9a55f065c6b7842e9383d22e0c04 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Wed, 17 Jun 2009 19:15:19 -0700 Subject: libertas: fix card cleanup order in SDIO driver The SDIO driver sets the surpriseremoved flag before calling lbs_remove_card. With IEEE PS enabled, lbs_remove_card must issue a command to exit IEEE PS mode, however with that flag set the command path is blocked and the card is never taken out of IEEE PS mode. This step is required to ensure that the driver can be reloaded. This patch moves the setting of surpriseremoved after lbs_remove_card is called. Tested with V9 firmware by ensuring that IEEE PS is disabled when the driver is removed. Reloading the driver is not fully tested due to a separate issue with module reload in the SDIO driver, however this patch at least leaves the card in a better state when we bring the driver down. Signed-off-by: Andrey Yurovsky Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 89396a7..485a8d4 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -1093,11 +1093,11 @@ static void if_sdio_remove(struct sdio_func *func) lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n"); } - card->priv->surpriseremoved = 1; lbs_deb_sdio("call remove card\n"); lbs_stop_card(card->priv); lbs_remove_card(card->priv); + card->priv->surpriseremoved = 1; flush_workqueue(card->workqueue); destroy_workqueue(card->workqueue); -- cgit v0.10.2 From 7d5ca3b8b2b38ab676d0adc268a3c6a82e7a7588 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 19 Jun 2009 11:57:59 -0700 Subject: ath9k: differentiate quality reporting between legacy and HT configurations We were not differentiating quality between legacy and HT configurations. We change this to consider the differences. New theory for reporting quality: At a hardware RSSI of 45 you will be able to use MCS 7 reliably. At a hardware RSSI of 45 you will be able to use MCS 15 reliably. At a hardware RSSI of 35 you should be able use 54 Mbps reliably. MCS 7 is the highets MCS index usable by a 1-stream device. MCS 15 is the highest MCS index usable by a 2-stream device. All ath9k devices are either 1-stream or 2-stream. How many bars you see is derived from the qual reporting. A more elaborate scheme can be used here but it requires tables of SNR/throughput for each possible mode used. For the MCS table you can refer to the wireless wiki: http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n This should fix this bug report: http://bugzilla.kernel.org/show_bug.cgi?id=13537 Cc: Janath.Peiris@atheros.com Cc: Matt.Smith@atheros.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 2b2872b..b3da81d 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -236,10 +236,31 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; rx_status->antenna = ds->ds_rxstat.rs_antenna; - /* at 45 you will be able to use MCS 15 reliably. A more elaborate - * scheme can be used here but it requires tables of SNR/throughput for - * each possible mode used. */ - rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; + /* + * Theory for reporting quality: + * + * At a hardware RSSI of 45 you will be able to use MCS 7 reliably. + * At a hardware RSSI of 45 you will be able to use MCS 15 reliably. + * At a hardware RSSI of 35 you should be able use 54 Mbps reliably. + * + * MCS 7 is the highets MCS index usable by a 1-stream device. + * MCS 15 is the highest MCS index usable by a 2-stream device. + * + * All ath9k devices are either 1-stream or 2-stream. + * + * How many bars you see is derived from the qual reporting. + * + * A more elaborate scheme can be used here but it requires tables + * of SNR/throughput for each possible mode used. For the MCS table + * you can refer to the wireless wiki: + * + * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n + * + */ + if (conf_is_ht(&hw->conf)) + rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; + else + rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 35; /* rssi can be more than 45 though, anything above that * should be considered at 100% */ -- cgit v0.10.2 From 3354a0f6a3ced6957dfb9f689ad075cfa8fd272f Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 19 Jun 2009 13:52:41 -0700 Subject: iwlwifi: Check HW ready before prepare card. Hardware may be ready for us to manage it without us trying to prepare it first. Check if this is the case. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6d1519e..63cba8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1812,6 +1812,11 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n"); + ret = iwl_set_hw_ready(priv); + if (priv->hw_ready) + return ret; + + /* If HW is not ready, prepare the conditions to check again */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PREPARE); @@ -1819,6 +1824,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv) ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); + /* HW should be ready by now, check again. */ if (ret != -ETIMEDOUT) iwl_set_hw_ready(priv); -- cgit v0.10.2 From 90e8e424d9c071f2db22100de81af6c8f7df34ee Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 19 Jun 2009 13:52:42 -0700 Subject: iwlwifi: drop sw_crypto from hw_params. Each HW supported by iwlwifi is capable of hardware crypto so drop this flag from hw_params structure. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 777c095..8cfc830 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1987,7 +1987,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) staging_rxon->reserved4 = 0; staging_rxon->reserved5 = 0; - iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); + iwl_set_rxon_hwcrypto(priv, !iwl3945_mod_params.sw_crypto); /* Apply the new configuration */ rc = iwl_send_cmd_pdu(priv, REPLY_RXON, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 63cba8c..d928561 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -171,7 +171,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) le16_to_cpu(priv->staging_rxon.channel), priv->staging_rxon.bssid_addr); - iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); + iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto); /* Apply the new configuration * RXON unassoc clears the station table in uCode, send it before @@ -2337,7 +2337,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, IWL_DEBUG_MAC80211(priv, "enter\n"); - if (priv->hw_params.sw_crypto) { + if (priv->cfg->mod_params->sw_crypto) { IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6ab0716..11a1969 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1361,7 +1361,6 @@ EXPORT_SYMBOL(iwl_setup_mac); int iwl_set_hw_params(struct iwl_priv *priv) { - priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; if (priv->cfg->mod_params->amsdu_size_8K) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e2d620f..5da60e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -608,7 +608,6 @@ struct iwl_hw_params { u8 max_stations; u8 bcast_sta_id; u8 fat_channel; - u8 sw_crypto; u32 max_inst_size; u32 max_data_size; u32 max_bsm_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 2160795..66fe365 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -927,7 +927,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, hdr = (struct ieee80211_hdr *)rxb->skb->data; /* in case of HW accelerated crypto and bad decryption, drop */ - if (!priv->hw_params.sw_crypto && + if (!priv->cfg->mod_params->sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; -- cgit v0.10.2 From 45af81956e990440fe78d6d41f847664cb620609 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 19 Jun 2009 13:52:43 -0700 Subject: iwlwifi: make software queue assignment more efficient There really is no reason to be assigning txq->swq_id all the time, once at aggregation setup is sufficient. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 85ae7a6..b35c1fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -348,6 +348,10 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, txq->need_update = 0; + /* aggregation TX queues will get their ID when aggregation begins */ + if (txq_id <= IWL_TX_FIFO_AC3) + txq->swq_id = txq_id; + /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); @@ -734,8 +738,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); - swq_id = skb_get_queue_mapping(skb); - txq_id = swq_id; + txq_id = skb_get_queue_mapping(skb); if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; @@ -746,16 +749,14 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr->seq_ctrl |= cpu_to_le16(seq_number); seq_number += 0x10; /* aggregation is on for this */ - if (info->flags & IEEE80211_TX_CTL_AMPDU) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; - swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id); - } priv->stations[sta_id].tid[tid].tfds_in_queue++; } txq = &priv->txq[txq_id]; + swq_id = txq->swq_id; q = &txq->q; - txq->swq_id = swq_id; spin_lock_irqsave(&priv->lock, flags); @@ -1186,6 +1187,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) tid_data = &priv->stations[sta_id].tid[tid]; *ssn = SEQ_TO_SN(tid_data->seq_number); tid_data->agg.txq_id = txq_id; + priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(tx_fifo, txq_id); spin_unlock_irqrestore(&priv->sta_lock, flags); ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, -- cgit v0.10.2 From 4e05c2347a50f1d0892ff3475d7609eec428f781 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 19 Jun 2009 13:52:44 -0700 Subject: iwlwifi: scan requested channels only When userspace requests only certain channels to be scanned, we currently ignore that request entirely. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index dabf663..356d4e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -384,7 +384,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) void iwl_init_scan_params(struct iwl_priv *priv); int iwl_scan_cancel(struct iwl_priv *priv); int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); -int iwl_scan_initiate(struct iwl_priv *priv); int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, const u8 *ie, int ie_len, int left); @@ -398,7 +397,6 @@ void iwl_bg_scan_check(struct work_struct *data); void iwl_bg_abort_scan(struct work_struct *work); void iwl_bg_scan_completed(struct work_struct *work); void iwl_setup_scan_deferred_work(struct iwl_priv *priv); -int iwl_send_scan_abort(struct iwl_priv *priv); /* For faster active scanning, scan will move to the next channel if fewer than * PLCP_QUIET_THRESH packets are heard on this channel within diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index e26875d..00398d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -109,7 +109,7 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) } EXPORT_SYMBOL(iwl_scan_cancel_timeout); -int iwl_send_scan_abort(struct iwl_priv *priv) +static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret = 0; struct iwl_rx_packet *res; @@ -150,7 +150,6 @@ int iwl_send_scan_abort(struct iwl_priv *priv) return ret; } -EXPORT_SYMBOL(iwl_send_scan_abort); /* Service response to REPLY_SCAN_CMD (0x80) */ static void iwl_rx_reply_scan(struct iwl_priv *priv, @@ -322,7 +321,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, u8 is_active, u8 n_probes, struct iwl_scan_channel *scan_ch) { - const struct ieee80211_channel *channels = NULL; + struct ieee80211_channel *chan; const struct ieee80211_supported_band *sband; const struct iwl_channel_info *ch_info; u16 passive_dwell = 0; @@ -334,20 +333,19 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, if (!sband) return 0; - channels = sband->channels; - active_dwell = iwl_get_active_dwell_time(priv, band, n_probes); passive_dwell = iwl_get_passive_dwell_time(priv, band); if (passive_dwell <= active_dwell) passive_dwell = active_dwell + 1; - for (i = 0, added = 0; i < sband->n_channels; i++) { - if (channels[i].flags & IEEE80211_CHAN_DISABLED) + for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) { + chan = priv->scan_request->channels[i]; + + if (chan->band != band) continue; - channel = - ieee80211_frequency_to_channel(channels[i].center_freq); + channel = ieee80211_frequency_to_channel(chan->center_freq); scan_ch->channel = cpu_to_le16(channel); ch_info = iwl_get_channel_info(priv, band, channel); @@ -358,7 +356,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, } if (!is_active || is_channel_passive(ch_info) || - (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) + (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; else scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; @@ -405,7 +403,7 @@ void iwl_init_scan_params(struct iwl_priv *priv) priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; } -int iwl_scan_initiate(struct iwl_priv *priv) +static int iwl_scan_initiate(struct iwl_priv *priv) { if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n"); @@ -423,10 +421,6 @@ int iwl_scan_initiate(struct iwl_priv *priv) } IWL_DEBUG_INFO(priv, "Starting scan...\n"); - if (priv->cfg->sku & IWL_SKU_G) - priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ); - if (priv->cfg->sku & IWL_SKU_A) - priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ); set_bit(STATUS_SCANNING, &priv->status); priv->scan_start = jiffies; priv->scan_pass_start = priv->scan_start; @@ -435,7 +429,6 @@ int iwl_scan_initiate(struct iwl_priv *priv) return 0; } -EXPORT_SYMBOL(iwl_scan_initiate); #define IWL_DELAY_NEXT_SCAN (HZ*2) @@ -444,7 +437,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, { unsigned long flags; struct iwl_priv *priv = hw->priv; - int ret; + int ret, i; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -478,6 +471,10 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, goto out_unlock; } + priv->scan_bands = 0; + for (i = 0; i < req->n_channels; i++) + priv->scan_bands |= BIT(req->channels[i]->band); + priv->scan_request = req; ret = iwl_scan_initiate(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index cb9bd4c..016567f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1844,7 +1844,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, u8 is_active, u8 n_probes, struct iwl3945_scan_channel *scan_ch) { - const struct ieee80211_channel *channels = NULL; + struct ieee80211_channel *chan; const struct ieee80211_supported_band *sband; const struct iwl_channel_info *ch_info; u16 passive_dwell = 0; @@ -1855,19 +1855,19 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, if (!sband) return 0; - channels = sband->channels; - active_dwell = iwl_get_active_dwell_time(priv, band, n_probes); passive_dwell = iwl_get_passive_dwell_time(priv, band); if (passive_dwell <= active_dwell) passive_dwell = active_dwell + 1; - for (i = 0, added = 0; i < sband->n_channels; i++) { - if (channels[i].flags & IEEE80211_CHAN_DISABLED) + for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) { + chan = priv->scan_request->channels[i]; + + if (chan->band != band) continue; - scan_ch->channel = channels[i].hw_value; + scan_ch->channel = chan->hw_value; ch_info = iwl_get_channel_info(priv, band, scan_ch->channel); if (!is_channel_valid(ch_info)) { @@ -1882,7 +1882,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, * and use long active_dwell time. */ if (!is_active || is_channel_passive(ch_info) || - (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) { + (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) { scan_ch->type = 0; /* passive */ if (IWL_UCODE_API(priv->ucode_ver) == 1) scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1); -- cgit v0.10.2 From 2c2f3b33888419fb9e7d015b9dc67b9db4437efa Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 19 Jun 2009 13:52:45 -0700 Subject: iwlwifi: unify iwl_setup_rxon_timing This patch unifies setup_rxon_timing funcions of AGN and 3945. HWs differ only in supported maximal beacon interval. This is reflected in hw_paras.max_beacon_itrvl Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8cfc830..b0246db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2563,6 +2563,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.bcast_sta_id = IWL3945_BROADCAST_ID; priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR; + priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL; return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index d928561..1d4e9ca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -512,70 +512,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv, return 0; } - -/****************************************************************************** - * - * Misc. internal state and helper functions - * - ******************************************************************************/ - -#define MAX_UCODE_BEACON_INTERVAL 4096 - -static u16 iwl_adjust_beacon_interval(u16 beacon_val) -{ - u16 new_val = 0; - u16 beacon_factor = 0; - - beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL) - / MAX_UCODE_BEACON_INTERVAL; - new_val = beacon_val / beacon_factor; - - if (!new_val) - new_val = MAX_UCODE_BEACON_INTERVAL; - - return new_val; -} - -static void iwl_setup_rxon_timing(struct iwl_priv *priv) -{ - u64 tsf; - s32 interval_tm, rem; - unsigned long flags; - struct ieee80211_conf *conf = NULL; - u16 beacon_int = 0; - - conf = ieee80211_get_hw_conf(priv->hw); - - spin_lock_irqsave(&priv->lock, flags); - priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp); - priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); - - if (priv->iw_mode == NL80211_IFTYPE_STATION) { - beacon_int = iwl_adjust_beacon_interval(priv->beacon_int); - priv->rxon_timing.atim_window = 0; - } else { - beacon_int = iwl_adjust_beacon_interval( - priv->vif->bss_conf.beacon_int); - - /* TODO: we need to get atim_window from upper stack - * for now we set to 0 */ - priv->rxon_timing.atim_window = 0; - } - - priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int); - - tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ - interval_tm = beacon_int * 1024; - rem = do_div(tsf, interval_tm); - priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem); - - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_ASSOC(priv, "beacon interval %d beacon timer %d beacon tim %d\n", - le16_to_cpu(priv->rxon_timing.beacon_interval), - le32_to_cpu(priv->rxon_timing.beacon_init_val), - le16_to_cpu(priv->rxon_timing.atim_window)); -} - /****************************************************************************** * * Generic RX handler implementations diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index c87033b..6e9b8a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -765,6 +765,8 @@ struct iwl5000_rxon_assoc_cmd { } __attribute__ ((packed)); #define IWL_CONN_MAX_LISTEN_INTERVAL 10 +#define IWL_MAX_UCODE_BEACON_INTERVAL 4 /* 4096 */ +#define IWL39_MAX_UCODE_BEACON_INTERVAL 1 /* 1024 */ /* * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 11a1969..7e528a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -635,6 +635,63 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_is_fat_tx_allowed); +static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) +{ + u16 new_val = 0; + u16 beacon_factor = 0; + + beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val; + new_val = beacon_val / beacon_factor; + + if (!new_val) + new_val = max_beacon_val; + + return new_val; +} + +void iwl_setup_rxon_timing(struct iwl_priv *priv) +{ + u64 tsf; + s32 interval_tm, rem; + unsigned long flags; + struct ieee80211_conf *conf = NULL; + u16 beacon_int; + + conf = ieee80211_get_hw_conf(priv->hw); + + spin_lock_irqsave(&priv->lock, flags); + priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp); + priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); + + if (priv->iw_mode == NL80211_IFTYPE_STATION) { + beacon_int = priv->beacon_int; + priv->rxon_timing.atim_window = 0; + } else { + beacon_int = priv->vif->bss_conf.beacon_int; + + /* TODO: we need to get atim_window from upper stack + * for now we set to 0 */ + priv->rxon_timing.atim_window = 0; + } + + beacon_int = iwl_adjust_beacon_interval(beacon_int, + priv->hw_params.max_beacon_itrvl * 1024); + priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int); + + tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ + interval_tm = beacon_int * 1024; + rem = do_div(tsf, interval_tm); + priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem); + + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_ASSOC(priv, + "beacon interval %d beacon timer %d beacon tim %d\n", + le16_to_cpu(priv->rxon_timing.beacon_interval), + le32_to_cpu(priv->rxon_timing.beacon_init_val), + le16_to_cpu(priv->rxon_timing.atim_window)); +} +EXPORT_SYMBOL(iwl_setup_rxon_timing); + void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -1369,6 +1426,8 @@ int iwl_set_hw_params(struct iwl_priv *priv) priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; + priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL; + if (priv->cfg->mod_params->disable_11n) priv->cfg->sku &= ~IWL_SKU_N; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 356d4e3..a658410 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -554,6 +554,7 @@ extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv, void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); +void iwl_setup_rxon_timing(struct iwl_priv *priv); static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) { return priv->cfg->ops->hcmd->rxon_assoc(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 5da60e4..1a2fe37 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -608,6 +608,7 @@ struct iwl_hw_params { u8 max_stations; u8 bcast_sta_id; u8 fat_channel; + u8 max_beacon_itrvl; /* in 1024 ms */ u32 max_inst_size; u32 max_data_size; u32 max_bsm_size; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 016567f..303c4b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -361,76 +361,6 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv) priv->shared_phys); } -#define MAX_UCODE_BEACON_INTERVAL 1024 -#define INTEL_CONN_LISTEN_INTERVAL cpu_to_le16(0xA) - -static __le16 iwl3945_adjust_beacon_interval(u16 beacon_val) -{ - u16 new_val = 0; - u16 beacon_factor = 0; - - beacon_factor = - (beacon_val + MAX_UCODE_BEACON_INTERVAL) - / MAX_UCODE_BEACON_INTERVAL; - new_val = beacon_val / beacon_factor; - - return cpu_to_le16(new_val); -} - -static void iwl3945_setup_rxon_timing(struct iwl_priv *priv) -{ - u64 interval_tm_unit; - u64 tsf, result; - unsigned long flags; - struct ieee80211_conf *conf = NULL; - u16 beacon_int = 0; - - conf = ieee80211_get_hw_conf(priv->hw); - - spin_lock_irqsave(&priv->lock, flags); - priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp); - priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL; - - tsf = priv->timestamp; - - beacon_int = priv->beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->iw_mode == NL80211_IFTYPE_STATION) { - if (beacon_int == 0) { - priv->rxon_timing.beacon_interval = cpu_to_le16(100); - priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); - } else { - priv->rxon_timing.beacon_interval = - cpu_to_le16(beacon_int); - priv->rxon_timing.beacon_interval = - iwl3945_adjust_beacon_interval( - le16_to_cpu(priv->rxon_timing.beacon_interval)); - } - - priv->rxon_timing.atim_window = 0; - } else { - priv->rxon_timing.beacon_interval = - iwl3945_adjust_beacon_interval( - priv->vif->bss_conf.beacon_int); - /* TODO: we need to get atim_window from upper stack - * for now we set to 0 */ - priv->rxon_timing.atim_window = 0; - } - - interval_tm_unit = - (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024); - result = do_div(tsf, interval_tm_unit); - priv->rxon_timing.beacon_init_val = - cpu_to_le32((u32) ((u64) interval_tm_unit - result)); - - IWL_DEBUG_ASSOC(priv, - "beacon interval %d beacon timer %d beacon tim %d\n", - le16_to_cpu(priv->rxon_timing.beacon_interval), - le32_to_cpu(priv->rxon_timing.beacon_init_val), - le16_to_cpu(priv->rxon_timing.atim_window)); -} - static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct ieee80211_tx_info *info, struct iwl_cmd *cmd, @@ -3066,7 +2996,7 @@ void iwl3945_post_associate(struct iwl_priv *priv) iwlcore_commit_rxon(priv); memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); - iwl3945_setup_rxon_timing(priv); + iwl_setup_rxon_timing(priv); rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (rc) @@ -3261,7 +3191,7 @@ void iwl3945_config_ap(struct iwl_priv *priv) /* RXON Timing */ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); - iwl3945_setup_rxon_timing(priv); + iwl_setup_rxon_timing(priv); rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); -- cgit v0.10.2 From 92179986ba5221a21e0f8a1e9b7b82a2883fef79 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 20 Jun 2009 05:10:24 +0200 Subject: ar9170usb: module link in sysfs Andrey Yurovsky reported that the driver forwarded erroneously the parent device structure instead of the real thing, which of course led to some dodgy sysfs links (at least?). Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 754b1f8..1aec7af 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -779,7 +779,7 @@ static int ar9170_usb_probe(struct usb_interface *intf, aru->req_one_stage_fw = ar9170_requires_one_stage(id); usb_set_intfdata(intf, aru); - SET_IEEE80211_DEV(ar->hw, &udev->dev); + SET_IEEE80211_DEV(ar->hw, &intf->dev); init_usb_anchor(&aru->rx_submitted); init_usb_anchor(&aru->tx_pending); -- cgit v0.10.2 From 1795378ee8d162084c6f98fc62ec309e418dfbe9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 20 Jun 2009 21:13:46 +0200 Subject: p54: redo rx_status into skb->cb This patch slightly optimizes p54_rx_data's stack and code size. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 1b15f9e..d1ea609 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -743,7 +743,7 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; - struct ieee80211_rx_status rx_status = {0}; + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); u16 freq = le16_to_cpu(hdr->freq); size_t header_len = sizeof(*hdr); u32 tsf32; @@ -762,39 +762,37 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) } if (hdr->decrypt_status == P54_DECRYPT_OK) - rx_status.flag |= RX_FLAG_DECRYPTED; + rx_status->flag |= RX_FLAG_DECRYPTED; if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) || (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP)) - rx_status.flag |= RX_FLAG_MMIC_ERROR; + rx_status->flag |= RX_FLAG_MMIC_ERROR; - rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); - rx_status.noise = priv->noise; + rx_status->signal = p54_rssi_to_dbm(dev, hdr->rssi); + rx_status->noise = priv->noise; if (hdr->rate & 0x10) - rx_status.flag |= RX_FLAG_SHORTPRE; + rx_status->flag |= RX_FLAG_SHORTPRE; if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) - rx_status.rate_idx = (rate < 4) ? 0 : rate - 4; + rx_status->rate_idx = (rate < 4) ? 0 : rate - 4; else - rx_status.rate_idx = rate; + rx_status->rate_idx = rate; - rx_status.freq = freq; - rx_status.band = dev->conf.channel->band; - rx_status.antenna = hdr->antenna; + rx_status->freq = freq; + rx_status->band = dev->conf.channel->band; + rx_status->antenna = hdr->antenna; tsf32 = le32_to_cpu(hdr->tsf32); if (tsf32 < priv->tsf_low32) priv->tsf_high32++; - rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32; + rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32; priv->tsf_low32 = tsf32; - rx_status.flag |= RX_FLAG_TSFT; + rx_status->flag |= RX_FLAG_TSFT; if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) header_len += hdr->align[0]; skb_pull(skb, header_len); skb_trim(skb, le16_to_cpu(hdr->len)); - - memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(dev, skb); queue_delayed_work(dev->workqueue, &priv->work, -- cgit v0.10.2 From 35a0ace7739b50331c919a3255639f123b78eaff Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 22 Jun 2009 17:42:21 +0200 Subject: wireless: remove redundant tests on unsigned bufsize and remainder are unsigned. When negative they are wrapped and caught by the other test. Signed-off-by: Roel Kluin Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c index f2c918c..1a2fca7 100644 --- a/drivers/net/wireless/orinoco/hermes.c +++ b/drivers/net/wireless/orinoco/hermes.c @@ -469,7 +469,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize, u16 rlength, rtype; unsigned nwords; - if ((bufsize < 0) || (bufsize % 2)) + if (bufsize % 2) return -EINVAL; err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL); diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 47521c5..09f46ab 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -281,7 +281,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); remainder = (16 * (skb->len + 4)) % ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); - if (remainder > 0 && remainder <= 6) + if (remainder <= 6) plcp_len |= 1 << 15; } -- cgit v0.10.2 From 4c8a32f57105a78c49e01f083717cdb531d3c2b9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:36:26 -0500 Subject: p54: Move eeprom code Copy the eeprom code from p54common.c into a new file eeprom.c Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c new file mode 100644 index 0000000..a2a044e --- /dev/null +++ b/drivers/net/wireless/p54/eeprom.c @@ -0,0 +1,564 @@ +/* + * EEPROM parser code for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * Copyright 2008, Johannes Berg + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include + +#include "p54.h" +#include "eeprom.h" +#include "lmac.h" + +static struct ieee80211_rate p54_bgrates[] = { + { .bitrate = 10, .hw_value = 0, }, + { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static struct ieee80211_channel p54_bgchannels[] = { + { .center_freq = 2412, .hw_value = 1, }, + { .center_freq = 2417, .hw_value = 2, }, + { .center_freq = 2422, .hw_value = 3, }, + { .center_freq = 2427, .hw_value = 4, }, + { .center_freq = 2432, .hw_value = 5, }, + { .center_freq = 2437, .hw_value = 6, }, + { .center_freq = 2442, .hw_value = 7, }, + { .center_freq = 2447, .hw_value = 8, }, + { .center_freq = 2452, .hw_value = 9, }, + { .center_freq = 2457, .hw_value = 10, }, + { .center_freq = 2462, .hw_value = 11, }, + { .center_freq = 2467, .hw_value = 12, }, + { .center_freq = 2472, .hw_value = 13, }, + { .center_freq = 2484, .hw_value = 14, }, +}; + +static struct ieee80211_supported_band band_2GHz = { + .channels = p54_bgchannels, + .n_channels = ARRAY_SIZE(p54_bgchannels), + .bitrates = p54_bgrates, + .n_bitrates = ARRAY_SIZE(p54_bgrates), +}; + +static struct ieee80211_rate p54_arates[] = { + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static struct ieee80211_channel p54_achannels[] = { + { .center_freq = 4920 }, + { .center_freq = 4940 }, + { .center_freq = 4960 }, + { .center_freq = 4980 }, + { .center_freq = 5040 }, + { .center_freq = 5060 }, + { .center_freq = 5080 }, + { .center_freq = 5170 }, + { .center_freq = 5180 }, + { .center_freq = 5190 }, + { .center_freq = 5200 }, + { .center_freq = 5210 }, + { .center_freq = 5220 }, + { .center_freq = 5230 }, + { .center_freq = 5240 }, + { .center_freq = 5260 }, + { .center_freq = 5280 }, + { .center_freq = 5300 }, + { .center_freq = 5320 }, + { .center_freq = 5500 }, + { .center_freq = 5520 }, + { .center_freq = 5540 }, + { .center_freq = 5560 }, + { .center_freq = 5580 }, + { .center_freq = 5600 }, + { .center_freq = 5620 }, + { .center_freq = 5640 }, + { .center_freq = 5660 }, + { .center_freq = 5680 }, + { .center_freq = 5700 }, + { .center_freq = 5745 }, + { .center_freq = 5765 }, + { .center_freq = 5785 }, + { .center_freq = 5805 }, + { .center_freq = 5825 }, +}; + +static struct ieee80211_supported_band band_5GHz = { + .channels = p54_achannels, + .n_channels = ARRAY_SIZE(p54_achannels), + .bitrates = p54_arates, + .n_bitrates = ARRAY_SIZE(p54_arates), +}; + +static int p54_convert_rev0(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) +{ + struct p54_common *priv = dev->priv; + struct p54_pa_curve_data_sample *dst; + struct pda_pa_curve_data_sample_rev0 *src; + size_t cd_len = sizeof(*curve_data) + + (curve_data->points_per_channel*sizeof(*dst) + 2) * + curve_data->channels; + unsigned int i, j; + void *source, *target; + + priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len, + GFP_KERNEL); + if (!priv->curve_data) + return -ENOMEM; + + priv->curve_data->entries = curve_data->channels; + priv->curve_data->entry_size = sizeof(__le16) + + sizeof(*dst) * curve_data->points_per_channel; + priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data); + priv->curve_data->len = cd_len; + memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data)); + source = curve_data->data; + target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data; + for (i = 0; i < curve_data->channels; i++) { + __le16 *freq = source; + source += sizeof(__le16); + *((__le16 *)target) = *freq; + target += sizeof(__le16); + for (j = 0; j < curve_data->points_per_channel; j++) { + dst = target; + src = source; + + dst->rf_power = src->rf_power; + dst->pa_detector = src->pa_detector; + dst->data_64qam = src->pcv; + /* "invent" the points for the other modulations */ +#define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y)) + dst->data_16qam = SUB(src->pcv, 12); + dst->data_qpsk = SUB(dst->data_16qam, 12); + dst->data_bpsk = SUB(dst->data_qpsk, 12); + dst->data_barker = SUB(dst->data_bpsk, 14); +#undef SUB + target += sizeof(*dst); + source += sizeof(*src); + } + } + + return 0; +} + +static int p54_convert_rev1(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) +{ + struct p54_common *priv = dev->priv; + struct p54_pa_curve_data_sample *dst; + struct pda_pa_curve_data_sample_rev1 *src; + size_t cd_len = sizeof(*curve_data) + + (curve_data->points_per_channel*sizeof(*dst) + 2) * + curve_data->channels; + unsigned int i, j; + void *source, *target; + + priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data), + GFP_KERNEL); + if (!priv->curve_data) + return -ENOMEM; + + priv->curve_data->entries = curve_data->channels; + priv->curve_data->entry_size = sizeof(__le16) + + sizeof(*dst) * curve_data->points_per_channel; + priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data); + priv->curve_data->len = cd_len; + memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data)); + source = curve_data->data; + target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data; + for (i = 0; i < curve_data->channels; i++) { + __le16 *freq = source; + source += sizeof(__le16); + *((__le16 *)target) = *freq; + target += sizeof(__le16); + for (j = 0; j < curve_data->points_per_channel; j++) { + memcpy(target, source, sizeof(*src)); + + target += sizeof(*dst); + source += sizeof(*src); + } + source++; + } + + return 0; +} + +static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2", + "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" }; + +static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len, + u16 type) +{ + struct p54_common *priv = dev->priv; + int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0; + int entry_size = sizeof(struct pda_rssi_cal_entry) + offset; + int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2; + int i; + + if (len != (entry_size * num_entries)) { + printk(KERN_ERR "%s: unknown rssi calibration data packing " + " type:(%x) len:%d.\n", + wiphy_name(dev->wiphy), type, len); + + print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, + data, len); + + printk(KERN_ERR "%s: please report this issue.\n", + wiphy_name(dev->wiphy)); + return; + } + + for (i = 0; i < num_entries; i++) { + struct pda_rssi_cal_entry *cal = data + + (offset + i * entry_size); + priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul); + priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add); + } +} + +static void p54_parse_default_country(struct ieee80211_hw *dev, + void *data, int len) +{ + struct pda_country *country; + + if (len != sizeof(*country)) { + printk(KERN_ERR "%s: found possible invalid default country " + "eeprom entry. (entry size: %d)\n", + wiphy_name(dev->wiphy), len); + + print_hex_dump_bytes("country:", DUMP_PREFIX_NONE, + data, len); + + printk(KERN_ERR "%s: please report this issue.\n", + wiphy_name(dev->wiphy)); + return; + } + + country = (struct pda_country *) data; + if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO) + regulatory_hint(dev->wiphy, country->alpha2); + else { + /* TODO: + * write a shared/common function that converts + * "Regulatory domain codes" (802.11-2007 14.8.2.2) + * into ISO/IEC 3166-1 alpha2 for regulatory_hint. + */ + } +} + +static int p54_convert_output_limits(struct ieee80211_hw *dev, + u8 *data, size_t len) +{ + struct p54_common *priv = dev->priv; + + if (len < 2) + return -EINVAL; + + if (data[0] != 0) { + printk(KERN_ERR "%s: unknown output power db revision:%x\n", + wiphy_name(dev->wiphy), data[0]); + return -EINVAL; + } + + if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len) + return -EINVAL; + + priv->output_limit = kmalloc(data[1] * + sizeof(struct pda_channel_output_limit) + + sizeof(*priv->output_limit), GFP_KERNEL); + + if (!priv->output_limit) + return -ENOMEM; + + priv->output_limit->offset = 0; + priv->output_limit->entries = data[1]; + priv->output_limit->entry_size = + sizeof(struct pda_channel_output_limit); + priv->output_limit->len = priv->output_limit->entry_size * + priv->output_limit->entries + + priv->output_limit->offset; + + memcpy(priv->output_limit->data, &data[2], + data[1] * sizeof(struct pda_channel_output_limit)); + + return 0; +} + +static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src, + size_t total_len) +{ + struct p54_cal_database *dst; + size_t payload_len, entries, entry_size, offset; + + payload_len = le16_to_cpu(src->len); + entries = le16_to_cpu(src->entries); + entry_size = le16_to_cpu(src->entry_size); + offset = le16_to_cpu(src->offset); + if (((entries * entry_size + offset) != payload_len) || + (payload_len + sizeof(*src) != total_len)) + return NULL; + + dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL); + if (!dst) + return NULL; + + dst->entries = entries; + dst->entry_size = entry_size; + dst->offset = offset; + dst->len = payload_len; + + memcpy(dst->data, src->data, payload_len); + return dst; +} + +int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) +{ + struct p54_common *priv = dev->priv; + struct eeprom_pda_wrap *wrap = NULL; + struct pda_entry *entry; + unsigned int data_len, entry_len; + void *tmp; + int err; + u8 *end = (u8 *)eeprom + len; + u16 synth = 0; + + wrap = (struct eeprom_pda_wrap *) eeprom; + entry = (void *)wrap->data + le16_to_cpu(wrap->len); + + /* verify that at least the entry length/code fits */ + while ((u8 *)entry <= end - sizeof(*entry)) { + entry_len = le16_to_cpu(entry->len); + data_len = ((entry_len - 1) << 1); + + /* abort if entry exceeds whole structure */ + if ((u8 *)entry + sizeof(*entry) + data_len > end) + break; + + switch (le16_to_cpu(entry->code)) { + case PDR_MAC_ADDRESS: + if (data_len != ETH_ALEN) + break; + SET_IEEE80211_PERM_ADDR(dev, entry->data); + break; + case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS: + if (priv->output_limit) + break; + err = p54_convert_output_limits(dev, entry->data, + data_len); + if (err) + goto err; + break; + case PDR_PRISM_PA_CAL_CURVE_DATA: { + struct pda_pa_curve_data *curve_data = + (struct pda_pa_curve_data *)entry->data; + if (data_len < sizeof(*curve_data)) { + err = -EINVAL; + goto err; + } + + switch (curve_data->cal_method_rev) { + case 0: + err = p54_convert_rev0(dev, curve_data); + break; + case 1: + err = p54_convert_rev1(dev, curve_data); + break; + default: + printk(KERN_ERR "%s: unknown curve data " + "revision %d\n", + wiphy_name(dev->wiphy), + curve_data->cal_method_rev); + err = -ENODEV; + break; + } + if (err) + goto err; + } + break; + case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: + priv->iq_autocal = kmalloc(data_len, GFP_KERNEL); + if (!priv->iq_autocal) { + err = -ENOMEM; + goto err; + } + + memcpy(priv->iq_autocal, entry->data, data_len); + priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry); + break; + case PDR_DEFAULT_COUNTRY: + p54_parse_default_country(dev, entry->data, data_len); + break; + case PDR_INTERFACE_LIST: + tmp = entry->data; + while ((u8 *)tmp < entry->data + data_len) { + struct exp_if *exp_if = tmp; + if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000)) + synth = le16_to_cpu(exp_if->variant); + tmp += sizeof(*exp_if); + } + break; + case PDR_HARDWARE_PLATFORM_COMPONENT_ID: + if (data_len < 2) + break; + priv->version = *(u8 *)(entry->data + 1); + break; + case PDR_RSSI_LINEAR_APPROXIMATION: + case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: + case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: + p54_parse_rssical(dev, entry->data, data_len, + le16_to_cpu(entry->code)); + break; + case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: { + __le16 *src = (void *) entry->data; + s16 *dst = (void *) &priv->rssical_db; + int i; + + if (data_len != sizeof(priv->rssical_db)) { + err = -EINVAL; + goto err; + } + for (i = 0; i < sizeof(priv->rssical_db) / + sizeof(*src); i++) + *(dst++) = (s16) le16_to_cpu(*(src++)); + } + break; + case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: { + struct pda_custom_wrapper *pda = (void *) entry->data; + if (priv->output_limit || data_len < sizeof(*pda)) + break; + priv->output_limit = p54_convert_db(pda, data_len); + } + break; + case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: { + struct pda_custom_wrapper *pda = (void *) entry->data; + if (priv->curve_data || data_len < sizeof(*pda)) + break; + priv->curve_data = p54_convert_db(pda, data_len); + } + break; + case PDR_END: + /* make it overrun */ + entry_len = len; + break; + default: + break; + } + + entry = (void *)entry + (entry_len + 1)*2; + } + + if (!synth || !priv->iq_autocal || !priv->output_limit || + !priv->curve_data) { + printk(KERN_ERR "%s: not all required entries found in eeprom!\n", + wiphy_name(dev->wiphy)); + err = -EINVAL; + goto err; + } + + priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; + if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) + p54_init_xbow_synth(priv); + if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; + if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) + dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; + if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED) + priv->rx_diversity_mask = 3; + if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED) + priv->tx_diversity_mask = 3; + + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + u8 perm_addr[ETH_ALEN]; + + printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n", + wiphy_name(dev->wiphy)); + random_ether_addr(perm_addr); + SET_IEEE80211_PERM_ADDR(dev, perm_addr); + } + + printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, priv->version, + p54_rf_chips[priv->rxhw]); + + return 0; + +err: + kfree(priv->iq_autocal); + kfree(priv->output_limit); + kfree(priv->curve_data); + priv->iq_autocal = NULL; + priv->output_limit = NULL; + priv->curve_data = NULL; + + printk(KERN_ERR "%s: eeprom parse failed!\n", + wiphy_name(dev->wiphy)); + return err; +} +EXPORT_SYMBOL_GPL(p54_parse_eeprom); + +int p54_read_eeprom(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; + int ret = -ENOMEM; + void *eeprom = NULL; + + maxblocksize = EEPROM_READBACK_LEN; + if (priv->fw_var >= 0x509) + maxblocksize -= 0xc; + else + maxblocksize -= 0x4; + + eeprom = kzalloc(eeprom_size, GFP_KERNEL); + if (unlikely(!eeprom)) + goto free; + + while (eeprom_size) { + blocksize = min(eeprom_size, maxblocksize); + ret = p54_download_eeprom(priv, (void *) (eeprom + offset), + offset, blocksize); + if (unlikely(ret)) + goto free; + + offset += blocksize; + eeprom_size -= blocksize; + } + + ret = p54_parse_eeprom(dev, eeprom, offset); +free: + kfree(eeprom); + return ret; +} +EXPORT_SYMBOL_GPL(p54_read_eeprom); -- cgit v0.10.2 From 289b098c2754d04f768b34ac5a9d08b59c38b725 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:37:13 -0500 Subject: p54: Move eeprom header Copy the eeprom code from p54common.h into a new file eeprom.h Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/eeprom.h b/drivers/net/wireless/p54/eeprom.h new file mode 100644 index 0000000..9051aef --- /dev/null +++ b/drivers/net/wireless/p54/eeprom.h @@ -0,0 +1,226 @@ +/* + * eeprom specific definitions for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * - LMAC API interface header file for STLC4560 (lmac_longbow.h) + * Copyright (C) 2007 Conexant Systems, Inc. + * + * - islmvc driver + * Copyright (C) 2001 Intersil Americas Inc. + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef EEPROM_H +#define EEPROM_H + +/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ + +struct pda_entry { + __le16 len; /* includes both code and data */ + __le16 code; + u8 data[0]; +} __packed; + +struct eeprom_pda_wrap { + __le32 magic; + __le16 pad; + __le16 len; + __le32 arm_opcode; + u8 data[0]; +} __packed; + +struct p54_iq_autocal_entry { + __le16 iq_param[4]; +} __packed; + +struct pda_iq_autocal_entry { + __le16 freq; + struct p54_iq_autocal_entry params; +} __packed; + +struct pda_channel_output_limit { + __le16 freq; + u8 val_bpsk; + u8 val_qpsk; + u8 val_16qam; + u8 val_64qam; + u8 rate_set_mask; + u8 rate_set_size; +} __packed; + +struct pda_pa_curve_data_sample_rev0 { + u8 rf_power; + u8 pa_detector; + u8 pcv; +} __packed; + +struct pda_pa_curve_data_sample_rev1 { + u8 rf_power; + u8 pa_detector; + u8 data_barker; + u8 data_bpsk; + u8 data_qpsk; + u8 data_16qam; + u8 data_64qam; +} __packed; + +struct pda_pa_curve_data { + u8 cal_method_rev; + u8 channels; + u8 points_per_channel; + u8 padding; + u8 data[0]; +} __packed; + +struct pda_rssi_cal_entry { + __le16 mul; + __le16 add; +} __packed; + +struct pda_country { + u8 regdomain; + u8 alpha2[2]; + u8 flags; +} __packed; + +struct pda_antenna_gain { + struct { + u8 gain_5GHz; /* 0.25 dBi units */ + u8 gain_2GHz; /* 0.25 dBi units */ + } __packed antenna[0]; +} __packed; + +struct pda_custom_wrapper { + __le16 entries; + __le16 entry_size; + __le16 offset; + __le16 len; + u8 data[0]; +} __packed; + +/* + * this defines the PDR codes used to build PDAs as defined in document + * number 553155. The current implementation mirrors version 1.1 of the + * document and lists only PDRs supported by the ARM platform. + */ + +/* common and choice range (0x0000 - 0x0fff) */ +#define PDR_END 0x0000 +#define PDR_MANUFACTURING_PART_NUMBER 0x0001 +#define PDR_PDA_VERSION 0x0002 +#define PDR_NIC_SERIAL_NUMBER 0x0003 +#define PDR_NIC_RAM_SIZE 0x0005 +#define PDR_RFMODEM_SUP_RANGE 0x0006 +#define PDR_PRISM_MAC_SUP_RANGE 0x0007 +#define PDR_NIC_ID 0x0008 + +#define PDR_MAC_ADDRESS 0x0101 +#define PDR_REGULATORY_DOMAIN_LIST 0x0103 /* obsolete */ +#define PDR_ALLOWED_CHAN_SET 0x0104 +#define PDR_DEFAULT_CHAN 0x0105 +#define PDR_TEMPERATURE_TYPE 0x0107 + +#define PDR_IFR_SETTING 0x0200 +#define PDR_RFR_SETTING 0x0201 +#define PDR_3861_BASELINE_REG_SETTINGS 0x0202 +#define PDR_3861_SHADOW_REG_SETTINGS 0x0203 +#define PDR_3861_IFRF_REG_SETTINGS 0x0204 + +#define PDR_3861_CHAN_CALIB_SET_POINTS 0x0300 +#define PDR_3861_CHAN_CALIB_INTEGRATOR 0x0301 + +#define PDR_3842_PRISM_II_NIC_CONFIG 0x0400 +#define PDR_PRISM_USB_ID 0x0401 +#define PDR_PRISM_PCI_ID 0x0402 +#define PDR_PRISM_PCI_IF_CONFIG 0x0403 +#define PDR_PRISM_PCI_PM_CONFIG 0x0404 + +#define PDR_3861_MF_TEST_CHAN_SET_POINTS 0x0900 +#define PDR_3861_MF_TEST_CHAN_INTEGRATORS 0x0901 + +/* ARM range (0x1000 - 0x1fff) */ +#define PDR_COUNTRY_INFORMATION 0x1000 /* obsolete */ +#define PDR_INTERFACE_LIST 0x1001 +#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002 +#define PDR_OEM_NAME 0x1003 +#define PDR_PRODUCT_NAME 0x1004 +#define PDR_UTF8_OEM_NAME 0x1005 +#define PDR_UTF8_PRODUCT_NAME 0x1006 +#define PDR_COUNTRY_LIST 0x1007 +#define PDR_DEFAULT_COUNTRY 0x1008 + +#define PDR_ANTENNA_GAIN 0x1100 + +#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901 +#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902 +#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903 +#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904 +#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905 +#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906 +#define PDR_REGULATORY_POWER_LIMITS 0x1907 +#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908 +#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909 +#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a + +/* reserved range (0x2000 - 0x7fff) */ + +/* customer range (0x8000 - 0xffff) */ +#define PDR_BASEBAND_REGISTERS 0x8000 +#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001 + +/* used by our modificated eeprom image */ +#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD +#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF +#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D + +/* Interface Definitions */ +#define PDR_INTERFACE_ROLE_SERVER 0x0000 +#define PDR_INTERFACE_ROLE_CLIENT 0x0001 + +/* PDR definitions for default country & country list */ +#define PDR_COUNTRY_CERT_CODE 0x80 +#define PDR_COUNTRY_CERT_CODE_REAL 0x00 +#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80 +#define PDR_COUNTRY_CERT_BAND 0x40 +#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00 +#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40 +#define PDR_COUNTRY_CERT_IODOOR 0x30 +#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00 +#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20 +#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30 +#define PDR_COUNTRY_CERT_INDEX 0x0f + +/* Specific LMAC FW/HW variant definitions */ +#define PDR_SYNTH_FRONTEND_MASK 0x0007 +#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001 +#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002 +#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003 +#define PDR_SYNTH_FRONTEND_XBOW 0x0004 +#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005 +#define PDR_SYNTH_IQ_CAL_MASK 0x0018 +#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000 +#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008 +#define PDR_SYNTH_IQ_CAL_ZIF 0x0010 +#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020 +#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020 +#define PDR_SYNTH_24_GHZ_MASK 0x0040 +#define PDR_SYNTH_24_GHZ_DISABLED 0x0040 +#define PDR_SYNTH_5_GHZ_MASK 0x0080 +#define PDR_SYNTH_5_GHZ_DISABLED 0x0080 +#define PDR_SYNTH_RX_DIV_MASK 0x0100 +#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100 +#define PDR_SYNTH_TX_DIV_MASK 0x0200 +#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200 +#define PDR_SYNTH_ASM_MASK 0x0400 +#define PDR_SYNTH_ASM_XSWON 0x0400 + +#endif /* EEPROM_H */ -- cgit v0.10.2 From 76074e1670b197385ce93242e3ba3ccc7a6be377 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:37:40 -0500 Subject: p54: Move firmware code Copy the firmware i/o code from p54common.c into a new file fwio.c Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c new file mode 100644 index 0000000..178efbc --- /dev/null +++ b/drivers/net/wireless/p54/fwio.c @@ -0,0 +1,697 @@ +/* + * Firmware I/O code for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * Copyright 2008, Johannes Berg + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include + +#include "p54.h" +#include "eeprom.h" +#include "lmac.h" + +int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) +{ + struct p54_common *priv = dev->priv; + struct exp_if *exp_if; + struct bootrec *bootrec; + u32 *data = (u32 *)fw->data; + u32 *end_data = (u32 *)fw->data + (fw->size >> 2); + u8 *fw_version = NULL; + size_t len; + int i; + int maxlen; + + if (priv->rx_start) + return 0; + + while (data < end_data && *data) + data++; + + while (data < end_data && !*data) + data++; + + bootrec = (struct bootrec *) data; + + while (bootrec->data <= end_data && (bootrec->data + + (len = le32_to_cpu(bootrec->len))) <= end_data) { + u32 code = le32_to_cpu(bootrec->code); + switch (code) { + case BR_CODE_COMPONENT_ID: + priv->fw_interface = be32_to_cpup((__be32 *) + bootrec->data); + switch (priv->fw_interface) { + case FW_LM86: + case FW_LM20: + case FW_LM87: { + char *iftype = (char *)bootrec->data; + printk(KERN_INFO "%s: p54 detected a LM%c%c " + "firmware\n", + wiphy_name(priv->hw->wiphy), + iftype[2], iftype[3]); + break; + } + case FW_FMAC: + default: + printk(KERN_ERR "%s: unsupported firmware\n", + wiphy_name(priv->hw->wiphy)); + return -ENODEV; + } + break; + case BR_CODE_COMPONENT_VERSION: + /* 24 bytes should be enough for all firmwares */ + if (strnlen((unsigned char *) bootrec->data, 24) < 24) + fw_version = (unsigned char *) bootrec->data; + break; + case BR_CODE_DESCR: { + struct bootrec_desc *desc = + (struct bootrec_desc *)bootrec->data; + priv->rx_start = le32_to_cpu(desc->rx_start); + /* FIXME add sanity checking */ + priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; + priv->headroom = desc->headroom; + priv->tailroom = desc->tailroom; + priv->privacy_caps = desc->privacy_caps; + priv->rx_keycache_size = desc->rx_keycache_size; + if (le32_to_cpu(bootrec->len) == 11) + priv->rx_mtu = le16_to_cpu(desc->rx_mtu); + else + priv->rx_mtu = (size_t) + 0x620 - priv->tx_hdr_len; + maxlen = priv->tx_hdr_len + /* USB devices */ + sizeof(struct p54_rx_data) + + 4 + /* rx alignment */ + IEEE80211_MAX_FRAG_THRESHOLD; + if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) { + printk(KERN_INFO "p54: rx_mtu reduced from %d " + "to %d\n", priv->rx_mtu, maxlen); + priv->rx_mtu = maxlen; + } + break; + } + case BR_CODE_EXPOSED_IF: + exp_if = (struct exp_if *) bootrec->data; + for (i = 0; i < (len * sizeof(*exp_if) / 4); i++) + if (exp_if[i].if_id == cpu_to_le16(IF_ID_LMAC)) + priv->fw_var = le16_to_cpu(exp_if[i].variant); + break; + case BR_CODE_DEPENDENT_IF: + break; + case BR_CODE_END_OF_BRA: + case LEGACY_BR_CODE_END_OF_BRA: + end_data = NULL; + break; + default: + break; + } + bootrec = (struct bootrec *)&bootrec->data[len]; + } + + if (fw_version) + printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n", + wiphy_name(priv->hw->wiphy), fw_version, + priv->fw_var >> 8, priv->fw_var & 0xff); + + if (priv->fw_var < 0x500) + printk(KERN_INFO "%s: you are using an obsolete firmware. " + "visit http://wireless.kernel.org/en/users/Drivers/p54 " + "and grab one for \"kernel >= 2.6.28\"!\n", + wiphy_name(priv->hw->wiphy)); + + if (priv->fw_var >= 0x300) { + /* Firmware supports QoS, use it! */ + + if (priv->fw_var >= 0x500) { + priv->tx_stats[P54_QUEUE_AC_VO].limit = 16; + priv->tx_stats[P54_QUEUE_AC_VI].limit = 16; + priv->tx_stats[P54_QUEUE_AC_BE].limit = 16; + priv->tx_stats[P54_QUEUE_AC_BK].limit = 16; + } else { + priv->tx_stats[P54_QUEUE_AC_VO].limit = 3; + priv->tx_stats[P54_QUEUE_AC_VI].limit = 4; + priv->tx_stats[P54_QUEUE_AC_BE].limit = 3; + priv->tx_stats[P54_QUEUE_AC_BK].limit = 2; + } + priv->hw->queues = P54_QUEUE_AC_NUM; + } + + printk(KERN_INFO "%s: cryptographic accelerator " + "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(priv->hw->wiphy), + (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : + "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP | + BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no", + (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? + "YES" : "no"); + + if (priv->rx_keycache_size) { + /* + * NOTE: + * + * The firmware provides at most 255 (0 - 254) slots + * for keys which are then used to offload decryption. + * As a result the 255 entry (aka 0xff) can be used + * safely by the driver to mark keys that didn't fit + * into the full cache. This trick saves us from + * keeping a extra list for uploaded keys. + */ + + priv->used_rxkeys = kzalloc(BITS_TO_LONGS( + priv->rx_keycache_size), GFP_KERNEL); + + if (!priv->used_rxkeys) + return -ENOMEM; + } + + return 0; +} +EXPORT_SYMBOL_GPL(p54_parse_firmware); + +static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags, + u16 payload_len, u16 type, gfp_t memflags) +{ + struct p54_hdr *hdr; + struct sk_buff *skb; + size_t frame_len = sizeof(*hdr) + payload_len; + + if (frame_len > P54_MAX_CTRL_FRAME_LEN) + return NULL; + + if (unlikely(skb_queue_len(&priv->tx_pending) > 64)) + return NULL; + + skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags); + if (!skb) + return NULL; + skb_reserve(skb, priv->tx_hdr_len); + + hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr)); + hdr->flags = cpu_to_le16(hdr_flags); + hdr->len = cpu_to_le16(payload_len); + hdr->type = cpu_to_le16(type); + hdr->tries = hdr->rts_tries = 0; + return skb; +} + +int p54_download_eeprom(struct p54_common *priv, void *buf, + u16 offset, u16 len) +{ + struct p54_eeprom_lm86 *eeprom_hdr; + struct sk_buff *skb; + size_t eeprom_hdr_size; + int ret = 0; + + if (priv->fw_var >= 0x509) + eeprom_hdr_size = sizeof(*eeprom_hdr); + else + eeprom_hdr_size = 0x4; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, eeprom_hdr_size + + len, P54_CONTROL_TYPE_EEPROM_READBACK, + GFP_KERNEL); + if (unlikely(!skb)) + return -ENOMEM; + + mutex_lock(&priv->eeprom_mutex); + priv->eeprom = buf; + eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, + eeprom_hdr_size + len); + + if (priv->fw_var < 0x509) { + eeprom_hdr->v1.offset = cpu_to_le16(offset); + eeprom_hdr->v1.len = cpu_to_le16(len); + } else { + eeprom_hdr->v2.offset = cpu_to_le32(offset); + eeprom_hdr->v2.len = cpu_to_le16(len); + eeprom_hdr->v2.magic2 = 0xf; + memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); + } + + p54_tx(priv, skb); + + if (!wait_for_completion_interruptible_timeout( + &priv->eeprom_comp, HZ)) { + printk(KERN_ERR "%s: device does not respond!\n", + wiphy_name(priv->hw->wiphy)); + ret = -EBUSY; + } + priv->eeprom = NULL; + mutex_unlock(&priv->eeprom_mutex); + return ret; +} + +int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set) +{ + struct sk_buff *skb; + struct p54_tim *tim; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim), + P54_CONTROL_TYPE_TIM, GFP_ATOMIC); + if (unlikely(!skb)) + return -ENOMEM; + + tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); + tim->count = 1; + tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid); + p54_tx(priv, skb); + return 0; +} + +int p54_sta_unlock(struct p54_common *priv, u8 *addr) +{ + struct sk_buff *skb; + struct p54_sta_unlock *sta; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta), + P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC); + if (unlikely(!skb)) + return -ENOMEM; + + sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); + memcpy(sta->addr, addr, ETH_ALEN); + p54_tx(priv, skb); + return 0; +} + +int p54_tx_cancel(struct p54_common *priv, __le32 req_id) +{ + struct sk_buff *skb; + struct p54_txcancel *cancel; + + if (unlikely(req_id < priv->rx_start || req_id > priv->rx_end)) + return -EINVAL; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel), + P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC); + if (unlikely(!skb)) + return -ENOMEM; + + cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); + cancel->req_id = req_id; + p54_tx(priv, skb); + return 0; +} + +int p54_setup_mac(struct p54_common *priv) +{ + struct sk_buff *skb; + struct p54_setup_mac *setup; + u16 mode; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup), + P54_CONTROL_TYPE_SETUP, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); + if (priv->hw->conf.radio_enabled) { + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + mode = P54_FILTER_TYPE_STATION; + break; + case NL80211_IFTYPE_AP: + mode = P54_FILTER_TYPE_AP; + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + mode = P54_FILTER_TYPE_IBSS; + break; + case NL80211_IFTYPE_MONITOR: + mode = P54_FILTER_TYPE_PROMISCUOUS; + break; + default: + mode = P54_FILTER_TYPE_HIBERNATE; + break; + } + + /* + * "TRANSPARENT and PROMISCUOUS are mutually exclusive" + * STSW45X0C LMAC API - page 12 + */ + if (((priv->filter_flags & FIF_PROMISC_IN_BSS) || + (priv->filter_flags & FIF_OTHER_BSS)) && + (mode != P54_FILTER_TYPE_PROMISCUOUS)) + mode |= P54_FILTER_TYPE_TRANSPARENT; + } else + mode = P54_FILTER_TYPE_HIBERNATE; + + setup->mac_mode = cpu_to_le16(mode); + memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); + memcpy(setup->bssid, priv->bssid, ETH_ALEN); + setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */ + setup->rx_align = 0; + if (priv->fw_var < 0x500) { + setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + memset(setup->v1.rts_rates, 0, 8); + setup->v1.rx_addr = cpu_to_le32(priv->rx_end); + setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v1.rxhw = cpu_to_le16(priv->rxhw); + setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer); + setup->v1.unalloc0 = cpu_to_le16(0); + } else { + setup->v2.rx_addr = cpu_to_le32(priv->rx_end); + setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v2.rxhw = cpu_to_le16(priv->rxhw); + setup->v2.timer = cpu_to_le16(priv->wakeup_timer); + setup->v2.truncate = cpu_to_le16(48896); + setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + setup->v2.sbss_offset = 0; + setup->v2.mcast_window = 0; + setup->v2.rx_rssi_threshold = 0; + setup->v2.rx_ed_threshold = 0; + setup->v2.ref_clock = cpu_to_le32(644245094); + setup->v2.lpf_bandwidth = cpu_to_le16(65535); + setup->v2.osc_start_delay = cpu_to_le16(65535); + } + p54_tx(priv, skb); + return 0; +} + +int p54_scan(struct p54_common *priv, u16 mode, u16 dwell) +{ + struct sk_buff *skb; + struct p54_hdr *hdr; + struct p54_scan_head *head; + struct p54_iq_autocal_entry *iq_autocal; + union p54_scan_body_union *body; + struct p54_scan_tail_rate *rate; + struct pda_rssi_cal_entry *rssi; + unsigned int i; + void *entry; + int band = priv->hw->conf.channel->band; + __le16 freq = cpu_to_le16(priv->hw->conf.channel->center_freq); + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) + + 2 + sizeof(*iq_autocal) + sizeof(*body) + + sizeof(*rate) + 2 * sizeof(*rssi), + P54_CONTROL_TYPE_SCAN, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + head = (struct p54_scan_head *) skb_put(skb, sizeof(*head)); + memset(head->scan_params, 0, sizeof(head->scan_params)); + head->mode = cpu_to_le16(mode); + head->dwell = cpu_to_le16(dwell); + head->freq = freq; + + if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { + __le16 *pa_power_points = (__le16 *) skb_put(skb, 2); + *pa_power_points = cpu_to_le16(0x0c); + } + + iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal)); + for (i = 0; i < priv->iq_autocal_len; i++) { + if (priv->iq_autocal[i].freq != freq) + continue; + + memcpy(iq_autocal, &priv->iq_autocal[i].params, + sizeof(struct p54_iq_autocal_entry)); + break; + } + if (i == priv->iq_autocal_len) + goto err; + + if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) + body = (void *) skb_put(skb, sizeof(body->longbow)); + else + body = (void *) skb_put(skb, sizeof(body->normal)); + + for (i = 0; i < priv->output_limit->entries; i++) { + __le16 *entry_freq = (void *) (priv->output_limit->data + + priv->output_limit->entry_size * i); + + if (*entry_freq != freq) + continue; + + if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { + memcpy(&body->longbow.power_limits, + (void *) entry_freq + sizeof(__le16), + priv->output_limit->entry_size); + } else { + struct pda_channel_output_limit *limits = + (void *) entry_freq; + + body->normal.val_barker = 0x38; + body->normal.val_bpsk = body->normal.dup_bpsk = + limits->val_bpsk; + body->normal.val_qpsk = body->normal.dup_qpsk = + limits->val_qpsk; + body->normal.val_16qam = body->normal.dup_16qam = + limits->val_16qam; + body->normal.val_64qam = body->normal.dup_64qam = + limits->val_64qam; + } + break; + } + if (i == priv->output_limit->entries) + goto err; + + entry = (void *)(priv->curve_data->data + priv->curve_data->offset); + for (i = 0; i < priv->curve_data->entries; i++) { + if (*((__le16 *)entry) != freq) { + entry += priv->curve_data->entry_size; + continue; + } + + if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { + memcpy(&body->longbow.curve_data, + (void *) entry + sizeof(__le16), + priv->curve_data->entry_size); + } else { + struct p54_scan_body *chan = &body->normal; + struct pda_pa_curve_data *curve_data = + (void *) priv->curve_data->data; + + entry += sizeof(__le16); + chan->pa_points_per_curve = 8; + memset(chan->curve_data, 0, sizeof(*chan->curve_data)); + memcpy(chan->curve_data, entry, + sizeof(struct p54_pa_curve_data_sample) * + min((u8)8, curve_data->points_per_channel)); + } + break; + } + if (i == priv->curve_data->entries) + goto err; + + if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) { + rate = (void *) skb_put(skb, sizeof(*rate)); + rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + for (i = 0; i < sizeof(rate->rts_rates); i++) + rate->rts_rates[i] = i; + } + + rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi)); + rssi->mul = cpu_to_le16(priv->rssical_db[band].mul); + rssi->add = cpu_to_le16(priv->rssical_db[band].add); + if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { + /* Longbow frontend needs ever more */ + rssi = (void *) skb_put(skb, sizeof(*rssi)); + rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn); + rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2); + } + + if (priv->fw_var >= 0x509) { + rate = (void *) skb_put(skb, sizeof(*rate)); + rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + for (i = 0; i < sizeof(rate->rts_rates); i++) + rate->rts_rates[i] = i; + } + + hdr = (struct p54_hdr *) skb->data; + hdr->len = cpu_to_le16(skb->len - sizeof(*hdr)); + + p54_tx(priv, skb); + return 0; + +err: + printk(KERN_ERR "%s: frequency change to channel %d failed.\n", + wiphy_name(priv->hw->wiphy), ieee80211_frequency_to_channel( + priv->hw->conf.channel->center_freq)); + + dev_kfree_skb_any(skb); + return -EINVAL; +} + +int p54_set_leds(struct p54_common *priv) +{ + struct sk_buff *skb; + struct p54_led *led; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led), + P54_CONTROL_TYPE_LED, GFP_ATOMIC); + if (unlikely(!skb)) + return -ENOMEM; + + led = (struct p54_led *) skb_put(skb, sizeof(*led)); + led->flags = cpu_to_le16(0x0003); + led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state); + led->delay[0] = cpu_to_le16(1); + led->delay[1] = cpu_to_le16(0); + p54_tx(priv, skb); + return 0; +} + +int p54_set_edcf(struct p54_common *priv) +{ + struct sk_buff *skb; + struct p54_edcf *edcf; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf), + P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC); + if (unlikely(!skb)) + return -ENOMEM; + + edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); + if (priv->use_short_slot) { + edcf->slottime = 9; + edcf->sifs = 0x10; + edcf->eofpad = 0x00; + } else { + edcf->slottime = 20; + edcf->sifs = 0x0a; + edcf->eofpad = 0x06; + } + /* (see prism54/isl_oid.h for further details) */ + edcf->frameburst = cpu_to_le16(0); + edcf->round_trip_delay = cpu_to_le16(0); + edcf->flags = 0; + memset(edcf->mapping, 0, sizeof(edcf->mapping)); + memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); + p54_tx(priv, skb); + return 0; +} + +int p54_set_ps(struct p54_common *priv) +{ + struct sk_buff *skb; + struct p54_psm *psm; + unsigned int i; + u16 mode; + + if (priv->hw->conf.flags & IEEE80211_CONF_PS) + mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM | + P54_PSM_CHECKSUM | P54_PSM_MCBC; + else + mode = P54_PSM_CAM; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm), + P54_CONTROL_TYPE_PSM, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + psm = (struct p54_psm *)skb_put(skb, sizeof(*psm)); + psm->mode = cpu_to_le16(mode); + psm->aid = cpu_to_le16(priv->aid); + for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) { + psm->intervals[i].interval = + cpu_to_le16(priv->hw->conf.listen_interval); + psm->intervals[i].periods = cpu_to_le16(1); + } + + psm->beacon_rssi_skip_max = 200; + psm->rssi_delta_threshold = 0; + psm->nr = 10; + psm->exclude[0] = 0; + + p54_tx(priv, skb); + return 0; +} + +int p54_init_xbow_synth(struct p54_common *priv) +{ + struct sk_buff *skb; + struct p54_xbow_synth *xbow; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow), + P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL); + if (unlikely(!skb)) + return -ENOMEM; + + xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow)); + xbow->magic1 = cpu_to_le16(0x1); + xbow->magic2 = cpu_to_le16(0x2); + xbow->freq = cpu_to_le16(5390); + memset(xbow->padding, 0, sizeof(xbow->padding)); + p54_tx(priv, skb); + return 0; +} + +int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len, + u8 *addr, u8* key) +{ + struct sk_buff *skb; + struct p54_keycache *rxkey; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey), + P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL); + if (unlikely(!skb)) + return -ENOMEM; + + rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); + rxkey->entry = slot; + rxkey->key_id = idx; + rxkey->key_type = algo; + if (addr) + memcpy(rxkey->mac, addr, ETH_ALEN); + else + memset(rxkey->mac, ~0, ETH_ALEN); + + switch (algo) { + case P54_CRYPTO_WEP: + case P54_CRYPTO_AESCCMP: + rxkey->key_len = min_t(u8, 16, len); + memcpy(rxkey->key, key, rxkey->key_len); + break; + + case P54_CRYPTO_TKIPMICHAEL: + rxkey->key_len = 24; + memcpy(rxkey->key, key, 16); + memcpy(&(rxkey->key[16]), &(key + [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); + break; + + case P54_CRYPTO_NONE: + rxkey->key_len = 0; + memset(rxkey->key, 0, sizeof(rxkey->key)); + break; + + default: + printk(KERN_ERR "%s: invalid cryptographic algorithm: %d\n", + wiphy_name(priv->hw->wiphy), algo); + dev_kfree_skb(skb); + return -EINVAL; + } + + p54_tx(priv, skb); + return 0; +} + +int p54_fetch_statistics(struct p54_common *priv) +{ + struct sk_buff *skb; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, + sizeof(struct p54_statistics), + P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + p54_tx(priv, skb); + return 0; +} -- cgit v0.10.2 From 0597c0141cf011ccf76419cb4f96f99b0d4b6171 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:37:59 -0500 Subject: p54: Move LED code Copy the LED code from p54common.c into a new file led.c Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c new file mode 100644 index 0000000..c00115b --- /dev/null +++ b/drivers/net/wireless/p54/led.c @@ -0,0 +1,163 @@ +/* + * Common code for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * Copyright 2008, Johannes Berg + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#ifdef CONFIG_P54_LEDS +#include +#endif /* CONFIG_P54_LEDS */ + +#include "p54.h" +#include "lmac.h" + +static void p54_update_leds(struct work_struct *work) +{ + struct p54_common *priv = container_of(work, struct p54_common, + led_work.work); + int err, i, tmp, blink_delay = 400; + bool rerun = false; + + /* Don't toggle the LED, when the device is down. */ + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + + for (i = 0; i < ARRAY_SIZE(priv->leds); i++) + if (priv->leds[i].toggled) { + priv->softled_state |= BIT(i); + + tmp = 70 + 200 / (priv->leds[i].toggled); + if (tmp < blink_delay) + blink_delay = tmp; + + if (priv->leds[i].led_dev.brightness == LED_OFF) + rerun = true; + + priv->leds[i].toggled = + !!priv->leds[i].led_dev.brightness; + } else + priv->softled_state &= ~BIT(i); + + err = p54_set_leds(priv); + if (err && net_ratelimit()) + printk(KERN_ERR "%s: failed to update LEDs (%d).\n", + wiphy_name(priv->hw->wiphy), err); + + if (rerun) + queue_delayed_work(priv->hw->workqueue, &priv->led_work, + msecs_to_jiffies(blink_delay)); +} + +static void p54_led_brightness_set(struct led_classdev *led_dev, + enum led_brightness brightness) +{ + struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev, + led_dev); + struct ieee80211_hw *dev = led->hw_dev; + struct p54_common *priv = dev->priv; + + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + + if ((brightness) && (led->registered)) { + led->toggled++; + queue_delayed_work(priv->hw->workqueue, &priv->led_work, + HZ/10); + } +} + +static int p54_register_led(struct p54_common *priv, + unsigned int led_index, + char *name, char *trigger) +{ + struct p54_led_dev *led = &priv->leds[led_index]; + int err; + + if (led->registered) + return -EEXIST; + + snprintf(led->name, sizeof(led->name), "p54-%s::%s", + wiphy_name(priv->hw->wiphy), name); + led->hw_dev = priv->hw; + led->index = led_index; + led->led_dev.name = led->name; + led->led_dev.default_trigger = trigger; + led->led_dev.brightness_set = p54_led_brightness_set; + + err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev); + if (err) + printk(KERN_ERR "%s: Failed to register %s LED.\n", + wiphy_name(priv->hw->wiphy), name); + else + led->registered = 1; + + return err; +} + +int p54_init_leds(struct p54_common *priv) +{ + int err; + + /* + * TODO: + * Figure out if the EEPROM contains some hints about the number + * of available/programmable LEDs of the device. + */ + + INIT_DELAYED_WORK(&priv->led_work, p54_update_leds); + + err = p54_register_led(priv, 0, "assoc", + ieee80211_get_assoc_led_name(priv->hw)); + if (err) + return err; + + err = p54_register_led(priv, 1, "tx", + ieee80211_get_tx_led_name(priv->hw)); + if (err) + return err; + + err = p54_register_led(priv, 2, "rx", + ieee80211_get_rx_led_name(priv->hw)); + if (err) + return err; + + err = p54_register_led(priv, 3, "radio", + ieee80211_get_radio_led_name(priv->hw)); + if (err) + return err; + + err = p54_set_leds(priv); + return err; +} + +void p54_unregister_leds(struct p54_common *priv) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(priv->leds); i++) { + if (priv->leds[i].registered) { + priv->leds[i].registered = false; + priv->leds[i].toggled = 0; + led_classdev_unregister(&priv->leds[i].led_dev); + } + } + + cancel_delayed_work_sync(&priv->led_work); +} -- cgit v0.10.2 From 0533f796993f7e8ccd682005bfbbe4135b24587e Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:38:24 -0500 Subject: p54: Move LMAC interface definitions Copy the LMAC Interface specific definitions from p54common.h into a new file lmac.h Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h new file mode 100644 index 0000000..0496cff --- /dev/null +++ b/drivers/net/wireless/p54/lmac.h @@ -0,0 +1,551 @@ +/* + * LMAC Interface specific definitions for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007 - 2009, Christian Lamparter + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * - LMAC API interface header file for STLC4560 (lmac_longbow.h) + * Copyright (C) 2007 Conexant Systems, Inc. + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef LMAC_H +#define LMAC_H + +enum p54_control_frame_types { + P54_CONTROL_TYPE_SETUP = 0, + P54_CONTROL_TYPE_SCAN, + P54_CONTROL_TYPE_TRAP, + P54_CONTROL_TYPE_DCFINIT, + P54_CONTROL_TYPE_RX_KEYCACHE, + P54_CONTROL_TYPE_TIM, + P54_CONTROL_TYPE_PSM, + P54_CONTROL_TYPE_TXCANCEL, + P54_CONTROL_TYPE_TXDONE, + P54_CONTROL_TYPE_BURST, + P54_CONTROL_TYPE_STAT_READBACK, + P54_CONTROL_TYPE_BBP, + P54_CONTROL_TYPE_EEPROM_READBACK, + P54_CONTROL_TYPE_LED, + P54_CONTROL_TYPE_GPIO, + P54_CONTROL_TYPE_TIMER, + P54_CONTROL_TYPE_MODULATION, + P54_CONTROL_TYPE_SYNTH_CONFIG, + P54_CONTROL_TYPE_DETECTOR_VALUE, + P54_CONTROL_TYPE_XBOW_SYNTH_CFG, + P54_CONTROL_TYPE_CCE_QUIET, + P54_CONTROL_TYPE_PSM_STA_UNLOCK, + P54_CONTROL_TYPE_PCS, + P54_CONTROL_TYPE_BT_BALANCER = 28, + P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30, + P54_CONTROL_TYPE_ARPTABLE = 31, + P54_CONTROL_TYPE_BT_OPTIONS = 35, +}; + +#define P54_HDR_FLAG_CONTROL BIT(15) +#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) +#define P54_HDR_FLAG_DATA_ALIGN BIT(14) + +#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0) +#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1) +#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2) +#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3) +#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4) +#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5) +#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6) +#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7) +#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8) +#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9) +#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10) +#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11) + +#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0) +#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1) +#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2) +#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3) +#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4) +#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5) +#define P54_HDR_FLAG_DATA_IN_DATA BIT(6) +#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7) +#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8) +#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9) + +struct p54_hdr { + __le16 flags; + __le16 len; + __le32 req_id; + __le16 type; /* enum p54_control_frame_types */ + u8 rts_tries; + u8 tries; + u8 data[0]; +} __packed; + +#define GET_REQ_ID(skb) \ + (((struct p54_hdr *) ((struct sk_buff *) skb)->data)->req_id) \ + +#define FREE_AFTER_TX(skb) \ + ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ + flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET)) + +#define IS_DATA_FRAME(skb) \ + (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ + flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL))) + +/* + * shared interface ID definitions + * The interface ID is a unique identification of a specific interface. + * The following values are reserved: 0x0000, 0x0002, 0x0012, 0x0014, 0x0015 + */ +#define IF_ID_ISL36356A 0x0001 /* ISL36356A <-> Firmware */ +#define IF_ID_MVC 0x0003 /* MAC Virtual Coprocessor */ +#define IF_ID_DEBUG 0x0008 /* PolDebug Interface */ +#define IF_ID_PRODUCT 0x0009 +#define IF_ID_OEM 0x000a +#define IF_ID_PCI3877 0x000b /* 3877 <-> Host PCI */ +#define IF_ID_ISL37704C 0x000c /* ISL37704C <-> Fw */ +#define IF_ID_ISL39000 0x000f /* ISL39000 <-> Fw */ +#define IF_ID_ISL39300A 0x0010 /* ISL39300A <-> Fw */ +#define IF_ID_ISL37700_UAP 0x0016 /* ISL37700 uAP Fw <-> Fw */ +#define IF_ID_ISL39000_UAP 0x0017 /* ISL39000 uAP Fw <-> Fw */ +#define IF_ID_LMAC 0x001a /* Interface exposed by LMAC */ + +struct exp_if { + __le16 role; + __le16 if_id; + __le16 variant; + __le16 btm_compat; + __le16 top_compat; +} __packed; + +struct dep_if { + __le16 role; + __le16 if_id; + __le16 variant; +} __packed; + +/* driver <-> lmac definitions */ +struct p54_eeprom_lm86 { + union { + struct { + __le16 offset; + __le16 len; + u8 data[0]; + } __packed v1; + struct { + __le32 offset; + __le16 len; + u8 magic2; + u8 pad; + u8 magic[4]; + u8 data[0]; + } __packed v2; + } __packed; +} __packed; + +enum p54_rx_decrypt_status { + P54_DECRYPT_NONE = 0, + P54_DECRYPT_OK, + P54_DECRYPT_NOKEY, + P54_DECRYPT_NOMICHAEL, + P54_DECRYPT_NOCKIPMIC, + P54_DECRYPT_FAIL_WEP, + P54_DECRYPT_FAIL_TKIP, + P54_DECRYPT_FAIL_MICHAEL, + P54_DECRYPT_FAIL_CKIPKP, + P54_DECRYPT_FAIL_CKIPMIC, + P54_DECRYPT_FAIL_AESCCMP +}; + +struct p54_rx_data { + __le16 flags; + __le16 len; + __le16 freq; + u8 antenna; + u8 rate; + u8 rssi; + u8 quality; + u8 decrypt_status; + u8 rssi_raw; + __le32 tsf32; + __le32 unalloc0; + u8 align[0]; +} __packed; + +enum p54_trap_type { + P54_TRAP_SCAN = 0, + P54_TRAP_TIMER, + P54_TRAP_BEACON_TX, + P54_TRAP_FAA_RADIO_ON, + P54_TRAP_FAA_RADIO_OFF, + P54_TRAP_RADAR, + P54_TRAP_NO_BEACON, + P54_TRAP_TBTT, + P54_TRAP_SCO_ENTER, + P54_TRAP_SCO_EXIT +}; + +struct p54_trap { + __le16 event; + __le16 frequency; +} __packed; + +enum p54_frame_sent_status { + P54_TX_OK = 0, + P54_TX_FAILED, + P54_TX_PSM, + P54_TX_PSM_CANCELLED = 4 +}; + +struct p54_frame_sent { + u8 status; + u8 tries; + u8 ack_rssi; + u8 quality; + __le16 seq; + u8 antenna; + u8 padding; +} __packed; + +enum p54_tx_data_crypt { + P54_CRYPTO_NONE = 0, + P54_CRYPTO_WEP, + P54_CRYPTO_TKIP, + P54_CRYPTO_TKIPMICHAEL, + P54_CRYPTO_CCX_WEPMIC, + P54_CRYPTO_CCX_KPMIC, + P54_CRYPTO_CCX_KP, + P54_CRYPTO_AESCCMP +}; + +enum p54_tx_data_queue { + P54_QUEUE_BEACON = 0, + P54_QUEUE_FWSCAN = 1, + P54_QUEUE_MGMT = 2, + P54_QUEUE_CAB = 3, + P54_QUEUE_DATA = 4, + + P54_QUEUE_AC_NUM = 4, + P54_QUEUE_AC_VO = 4, + P54_QUEUE_AC_VI = 5, + P54_QUEUE_AC_BE = 6, + P54_QUEUE_AC_BK = 7, + + /* keep last */ + P54_QUEUE_NUM = 8, +}; + +#define IS_QOS_QUEUE(n) (n >= P54_QUEUE_DATA) + +struct p54_tx_data { + u8 rateset[8]; + u8 rts_rate_idx; + u8 crypt_offset; + u8 key_type; + u8 key_len; + u8 key[16]; + u8 hw_queue; + u8 backlog; + __le16 durations[4]; + u8 tx_antenna; + union { + struct { + u8 cts_rate; + __le16 output_power; + } __packed longbow; + struct { + u8 output_power; + u8 cts_rate; + u8 unalloc; + } __packed normal; + } __packed; + u8 unalloc2[2]; + u8 align[0]; +} __packed; + +/* unit is ms */ +#define P54_TX_FRAME_LIFETIME 2000 +#define P54_TX_TIMEOUT 4000 +#define P54_STATISTICS_UPDATE 5000 + +#define P54_FILTER_TYPE_NONE 0 +#define P54_FILTER_TYPE_STATION BIT(0) +#define P54_FILTER_TYPE_IBSS BIT(1) +#define P54_FILTER_TYPE_AP BIT(2) +#define P54_FILTER_TYPE_TRANSPARENT BIT(3) +#define P54_FILTER_TYPE_PROMISCUOUS BIT(4) +#define P54_FILTER_TYPE_HIBERNATE BIT(5) +#define P54_FILTER_TYPE_NOACK BIT(6) +#define P54_FILTER_TYPE_RX_DISABLED BIT(7) + +struct p54_setup_mac { + __le16 mac_mode; + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u8 rx_antenna; + u8 rx_align; + union { + struct { + __le32 basic_rate_mask; + u8 rts_rates[8]; + __le32 rx_addr; + __le16 max_rx; + __le16 rxhw; + __le16 wakeup_timer; + __le16 unalloc0; + } __packed v1; + struct { + __le32 rx_addr; + __le16 max_rx; + __le16 rxhw; + __le16 timer; + __le16 truncate; + __le32 basic_rate_mask; + u8 sbss_offset; + u8 mcast_window; + u8 rx_rssi_threshold; + u8 rx_ed_threshold; + __le32 ref_clock; + __le16 lpf_bandwidth; + __le16 osc_start_delay; + } __packed v2; + } __packed; +} __packed; + +#define P54_SETUP_V1_LEN 40 +#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac)) + +#define P54_SCAN_EXIT BIT(0) +#define P54_SCAN_TRAP BIT(1) +#define P54_SCAN_ACTIVE BIT(2) +#define P54_SCAN_FILTER BIT(3) + +struct p54_scan_head { + __le16 mode; + __le16 dwell; + u8 scan_params[20]; + __le16 freq; +} __packed; + +struct p54_pa_curve_data_sample { + u8 rf_power; + u8 pa_detector; + u8 data_barker; + u8 data_bpsk; + u8 data_qpsk; + u8 data_16qam; + u8 data_64qam; + u8 padding; +} __packed; + +struct p54_scan_body { + u8 pa_points_per_curve; + u8 val_barker; + u8 val_bpsk; + u8 val_qpsk; + u8 val_16qam; + u8 val_64qam; + struct p54_pa_curve_data_sample curve_data[8]; + u8 dup_bpsk; + u8 dup_qpsk; + u8 dup_16qam; + u8 dup_64qam; +} __packed; + +/* + * Warning: Longbow's structures are bogus. + */ +struct p54_channel_output_limit_longbow { + __le16 rf_power_points[12]; +} __packed; + +struct p54_pa_curve_data_sample_longbow { + __le16 rf_power; + __le16 pa_detector; + struct { + __le16 data[4]; + } points[3] __packed; +} __packed; + +struct p54_scan_body_longbow { + struct p54_channel_output_limit_longbow power_limits; + struct p54_pa_curve_data_sample_longbow curve_data[8]; + __le16 unkn[6]; /* maybe more power_limits or rate_mask */ +} __packed; + +union p54_scan_body_union { + struct p54_scan_body normal; + struct p54_scan_body_longbow longbow; +} __packed; + +struct p54_scan_tail_rate { + __le32 basic_rate_mask; + u8 rts_rates[8]; +} __packed; + +struct p54_led { + __le16 flags; + __le16 mask[2]; + __le16 delay[2]; +} __packed; + +struct p54_edcf { + u8 flags; + u8 slottime; + u8 sifs; + u8 eofpad; + struct p54_edcf_queue_param queue[8]; + u8 mapping[4]; + __le16 frameburst; + __le16 round_trip_delay; +} __packed; + +struct p54_statistics { + __le32 rx_success; + __le32 rx_bad_fcs; + __le32 rx_abort; + __le32 rx_abort_phy; + __le32 rts_success; + __le32 rts_fail; + __le32 tsf32; + __le32 airtime; + __le32 noise; + __le32 sample_noise[8]; + __le32 sample_cca; + __le32 sample_tx; +} __packed; + +struct p54_xbow_synth { + __le16 magic1; + __le16 magic2; + __le16 freq; + u32 padding[5]; +} __packed; + +struct p54_timer { + __le32 interval; +} __packed; + +struct p54_keycache { + u8 entry; + u8 key_id; + u8 mac[ETH_ALEN]; + u8 padding[2]; + u8 key_type; + u8 key_len; + u8 key[24]; +} __packed; + +struct p54_burst { + u8 flags; + u8 queue; + u8 backlog; + u8 pad; + __le16 durations[32]; +} __packed; + +struct p54_psm_interval { + __le16 interval; + __le16 periods; +} __packed; + +#define P54_PSM_CAM 0 +#define P54_PSM BIT(0) +#define P54_PSM_DTIM BIT(1) +#define P54_PSM_MCBC BIT(2) +#define P54_PSM_CHECKSUM BIT(3) +#define P54_PSM_SKIP_MORE_DATA BIT(4) +#define P54_PSM_BEACON_TIMEOUT BIT(5) +#define P54_PSM_HFOSLEEP BIT(6) +#define P54_PSM_AUTOSWITCH_SLEEP BIT(7) +#define P54_PSM_LPIT BIT(8) +#define P54_PSM_BF_UCAST_SKIP BIT(9) +#define P54_PSM_BF_MCAST_SKIP BIT(10) + +struct p54_psm { + __le16 mode; + __le16 aid; + struct p54_psm_interval intervals[4]; + u8 beacon_rssi_skip_max; + u8 rssi_delta_threshold; + u8 nr; + u8 exclude[1]; +} __packed; + +#define MC_FILTER_ADDRESS_NUM 4 + +struct p54_group_address_table { + __le16 filter_enable; + __le16 num_address; + u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN]; +} __packed; + +struct p54_txcancel { + __le32 req_id; +} __packed; + +struct p54_sta_unlock { + u8 addr[ETH_ALEN]; + u16 padding; +} __packed; + +#define P54_TIM_CLEAR BIT(15) +struct p54_tim { + u8 count; + u8 padding[3]; + __le16 entry[8]; +} __packed; + +struct p54_cce_quiet { + __le32 period; +} __packed; + +struct p54_bt_balancer { + __le16 prio_thresh; + __le16 acl_thresh; +} __packed; + +struct p54_arp_table { + __le16 filter_enable; + u8 ipv4_addr[4]; +} __packed; + +/* LED control */ +int p54_set_leds(struct p54_common *priv); +int p54_init_leds(struct p54_common *priv); +void p54_unregister_leds(struct p54_common *priv); + +/* xmit functions */ +int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb); +int p54_tx_cancel(struct p54_common *priv, __le32 req_id); +void p54_tx(struct p54_common *priv, struct sk_buff *skb); + +/* synth/phy configuration */ +int p54_init_xbow_synth(struct p54_common *priv); +int p54_scan(struct p54_common *priv, u16 mode, u16 dwell); + +/* MAC */ +int p54_sta_unlock(struct p54_common *priv, u8 *addr); +int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set); +int p54_setup_mac(struct p54_common *priv); +int p54_set_ps(struct p54_common *priv); +int p54_fetch_statistics(struct p54_common *priv); + +/* e/v DCF setup */ +int p54_set_edcf(struct p54_common *priv); + +/* cryptographic engine */ +int p54_upload_key(struct p54_common *priv, u8 algo, int slot, + u8 idx, u8 len, u8 *addr, u8* key); + +/* eeprom */ +int p54_download_eeprom(struct p54_common *priv, void *buf, + u16 offset, u16 len); + +#endif /* LMAC_H */ -- cgit v0.10.2 From 0ac0d6cedf6110381501c236339a9fbe13c3441d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:38:49 -0500 Subject: p54: Move mac80211 glue code Copy the mac80211 glue code from p54common.c into a new file main.c Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c new file mode 100644 index 0000000..f9b4f6a --- /dev/null +++ b/drivers/net/wireless/p54/main.c @@ -0,0 +1,607 @@ +/* + * mac80211 glue code for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * Copyright 2008, Johannes Berg + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include + +#include "p54.h" +#include "lmac.h" + +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +MODULE_AUTHOR("Michael Wu "); +MODULE_DESCRIPTION("Softmac Prism54 common code"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("prism54common"); + +static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, + enum sta_notify_cmd notify_cmd, + struct ieee80211_sta *sta) +{ + struct p54_common *priv = dev->priv; + switch (notify_cmd) { + case STA_NOTIFY_ADD: + case STA_NOTIFY_REMOVE: + /* + * Notify the firmware that we don't want or we don't + * need to buffer frames for this station anymore. + */ + + p54_sta_unlock(priv, sta->addr); + break; + case STA_NOTIFY_AWAKE: + /* update the firmware's filter table */ + p54_sta_unlock(priv, sta->addr); + break; + default: + break; + } +} + +static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, + bool set) +{ + struct p54_common *priv = dev->priv; + + return p54_update_beacon_tim(priv, sta->aid, set); +} + +static int p54_beacon_format_ie_tim(struct sk_buff *skb) +{ + /* + * the good excuse for this mess is ... the firmware. + * The dummy TIM MUST be at the end of the beacon frame, + * because it'll be overwritten! + */ + + struct ieee80211_mgmt *mgmt = (void *)skb->data; + u8 *pos, *end; + + if (skb->len <= sizeof(mgmt)) + return -EINVAL; + + pos = (u8 *)mgmt->u.beacon.variable; + end = skb->data + skb->len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return -EINVAL; + + if (pos[0] == WLAN_EID_TIM) { + u8 dtim_len = pos[1]; + u8 dtim_period = pos[3]; + u8 *next = pos + 2 + dtim_len; + + if (dtim_len < 3) + return -EINVAL; + + memmove(pos, next, end - next); + + if (dtim_len > 3) + skb_trim(skb, skb->len - (dtim_len - 3)); + + pos = end - (dtim_len + 2); + + /* add the dummy at the end */ + pos[0] = WLAN_EID_TIM; + pos[1] = 3; + pos[2] = 0; + pos[3] = dtim_period; + pos[4] = 0; + return 0; + } + pos += 2 + pos[1]; + } + return 0; +} + +static int p54_beacon_update(struct p54_common *priv, + struct ieee80211_vif *vif) +{ + struct sk_buff *beacon; + __le32 old_beacon_req_id; + int ret; + + beacon = ieee80211_beacon_get(priv->hw, vif); + if (!beacon) + return -ENOMEM; + ret = p54_beacon_format_ie_tim(beacon); + if (ret) + return ret; + + old_beacon_req_id = priv->beacon_req_id; + priv->beacon_req_id = GET_REQ_ID(beacon); + + ret = p54_tx_80211(priv->hw, beacon); + if (ret) { + priv->beacon_req_id = old_beacon_req_id; + return -ENOSPC; + } + + priv->tsf_high32 = 0; + priv->tsf_low32 = 0; + + return 0; +} + +static int p54_start(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int err; + + mutex_lock(&priv->conf_mutex); + err = priv->open(dev); + if (err) + goto out; + P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47); + P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94); + P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); + P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); + err = p54_set_edcf(priv); + if (err) + goto out; + + memset(priv->bssid, ~0, ETH_ALEN); + priv->mode = NL80211_IFTYPE_MONITOR; + err = p54_setup_mac(priv); + if (err) { + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + goto out; + } + + queue_delayed_work(dev->workqueue, &priv->work, 0); + + priv->softled_state = 0; + err = p54_set_leds(priv); + +out: + mutex_unlock(&priv->conf_mutex); + return err; +} + +static void p54_stop(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int i; + + mutex_lock(&priv->conf_mutex); + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + priv->softled_state = 0; + p54_set_leds(priv); + + cancel_delayed_work_sync(&priv->work); + + priv->stop(dev); + skb_queue_purge(&priv->tx_pending); + skb_queue_purge(&priv->tx_queue); + for (i = 0; i < P54_QUEUE_NUM; i++) { + priv->tx_stats[i].count = 0; + priv->tx_stats[i].len = 0; + } + + priv->beacon_req_id = cpu_to_le32(0); + priv->tsf_high32 = priv->tsf_low32 = 0; + mutex_unlock(&priv->conf_mutex); +} + +static int p54_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct p54_common *priv = dev->priv; + + mutex_lock(&priv->conf_mutex); + if (priv->mode != NL80211_IFTYPE_MONITOR) { + mutex_unlock(&priv->conf_mutex); + return -EOPNOTSUPP; + } + + priv->vif = conf->vif; + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + priv->mode = conf->type; + break; + default: + mutex_unlock(&priv->conf_mutex); + return -EOPNOTSUPP; + } + + memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); + p54_setup_mac(priv); + mutex_unlock(&priv->conf_mutex); + return 0; +} + +static void p54_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct p54_common *priv = dev->priv; + + mutex_lock(&priv->conf_mutex); + priv->vif = NULL; + if (priv->beacon_req_id) { + p54_tx_cancel(priv, priv->beacon_req_id); + priv->beacon_req_id = cpu_to_le32(0); + } + priv->mode = NL80211_IFTYPE_MONITOR; + memset(priv->mac_addr, 0, ETH_ALEN); + memset(priv->bssid, 0, ETH_ALEN); + p54_setup_mac(priv); + mutex_unlock(&priv->conf_mutex); +} + +static int p54_config(struct ieee80211_hw *dev, u32 changed) +{ + int ret = 0; + struct p54_common *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; + + mutex_lock(&priv->conf_mutex); + if (changed & IEEE80211_CONF_CHANGE_POWER) + priv->output_power = conf->power_level << 2; + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ret = p54_scan(priv, P54_SCAN_EXIT, 0); + if (ret) + goto out; + } + if (changed & IEEE80211_CONF_CHANGE_PS) { + ret = p54_set_ps(priv); + if (ret) + goto out; + } + +out: + mutex_unlock(&priv->conf_mutex); + return ret; +} + +static void p54_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_mc_list *mclist) +{ + struct p54_common *priv = dev->priv; + + *total_flags &= FIF_PROMISC_IN_BSS | + FIF_OTHER_BSS; + + priv->filter_flags = *total_flags; + + if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) + p54_setup_mac(priv); +} + +static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct p54_common *priv = dev->priv; + int ret; + + mutex_lock(&priv->conf_mutex); + if ((params) && !(queue > 4)) { + P54_SET_QUEUE(priv->qos_params[queue], params->aifs, + params->cw_min, params->cw_max, params->txop); + ret = p54_set_edcf(priv); + } else + ret = -EINVAL; + mutex_unlock(&priv->conf_mutex); + return ret; +} + +static void p54_work(struct work_struct *work) +{ + struct p54_common *priv = container_of(work, struct p54_common, + work.work); + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + + /* + * TODO: walk through tx_queue and do the following tasks + * 1. initiate bursts. + * 2. cancel stuck frames / reset the device if necessary. + */ + + p54_fetch_statistics(priv); +} + +static int p54_get_stats(struct ieee80211_hw *dev, + struct ieee80211_low_level_stats *stats) +{ + struct p54_common *priv = dev->priv; + + memcpy(stats, &priv->stats, sizeof(*stats)); + return 0; +} + +static int p54_get_tx_stats(struct ieee80211_hw *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct p54_common *priv = dev->priv; + + memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA], + sizeof(stats[0]) * dev->queues); + return 0; +} + +static void p54_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct p54_common *priv = dev->priv; + + mutex_lock(&priv->conf_mutex); + if (changed & BSS_CHANGED_BSSID) { + memcpy(priv->bssid, info->bssid, ETH_ALEN); + p54_setup_mac(priv); + } + + if (changed & BSS_CHANGED_BEACON) { + p54_scan(priv, P54_SCAN_EXIT, 0); + p54_setup_mac(priv); + p54_beacon_update(priv, vif); + p54_set_edcf(priv); + } + + if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) { + priv->use_short_slot = info->use_short_slot; + p54_set_edcf(priv); + } + if (changed & BSS_CHANGED_BASIC_RATES) { + if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) + priv->basic_rate_mask = (info->basic_rates << 4); + else + priv->basic_rate_mask = info->basic_rates; + p54_setup_mac(priv); + if (priv->fw_var >= 0x500) + p54_scan(priv, P54_SCAN_EXIT, 0); + } + if (changed & BSS_CHANGED_ASSOC) { + if (info->assoc) { + priv->aid = info->aid; + priv->wakeup_timer = info->beacon_int * + info->dtim_period * 5; + p54_setup_mac(priv); + } + } + + mutex_unlock(&priv->conf_mutex); +} + +static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct p54_common *priv = dev->priv; + int slot, ret = 0; + u8 algo = 0; + u8 *addr = NULL; + + if (modparam_nohwcrypt) + return -EOPNOTSUPP; + + mutex_lock(&priv->conf_mutex); + if (cmd == SET_KEY) { + switch (key->alg) { + case ALG_TKIP: + if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | + BR_DESC_PRIV_CAP_TKIP))) { + ret = -EOPNOTSUPP; + goto out_unlock; + } + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_TKIPMICHAEL; + break; + case ALG_WEP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_WEP; + break; + case ALG_CCMP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_AESCCMP; + break; + default: + ret = -EOPNOTSUPP; + goto out_unlock; + } + slot = bitmap_find_free_region(priv->used_rxkeys, + priv->rx_keycache_size, 0); + + if (slot < 0) { + /* + * The device supports the choosen algorithm, but the + * firmware does not provide enough key slots to store + * all of them. + * But encryption offload for outgoing frames is always + * possible, so we just pretend that the upload was + * successful and do the decryption in software. + */ + + /* mark the key as invalid. */ + key->hw_key_idx = 0xff; + goto out_unlock; + } + } else { + slot = key->hw_key_idx; + + if (slot == 0xff) { + /* This key was not uploaded into the rx key cache. */ + + goto out_unlock; + } + + bitmap_release_region(priv->used_rxkeys, slot, 0); + algo = 0; + } + + if (sta) + addr = sta->addr; + + ret = p54_upload_key(priv, algo, slot, key->keyidx, + key->keylen, addr, key->key); + if (ret) { + bitmap_release_region(priv->used_rxkeys, slot, 0); + ret = -EOPNOTSUPP; + goto out_unlock; + } + + key->hw_key_idx = slot; + +out_unlock: + mutex_unlock(&priv->conf_mutex); + return ret; +} + +static const struct ieee80211_ops p54_ops = { + .tx = p54_tx_80211, + .start = p54_start, + .stop = p54_stop, + .add_interface = p54_add_interface, + .remove_interface = p54_remove_interface, + .set_tim = p54_set_tim, + .sta_notify = p54_sta_notify, + .set_key = p54_set_key, + .config = p54_config, + .bss_info_changed = p54_bss_info_changed, + .configure_filter = p54_configure_filter, + .conf_tx = p54_conf_tx, + .get_stats = p54_get_stats, + .get_tx_stats = p54_get_tx_stats +}; + +struct ieee80211_hw *p54_init_common(size_t priv_data_len) +{ + struct ieee80211_hw *dev; + struct p54_common *priv; + + dev = ieee80211_alloc_hw(priv_data_len, &p54_ops); + if (!dev) + return NULL; + + priv = dev->priv; + priv->hw = dev; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + priv->basic_rate_mask = 0x15f; + spin_lock_init(&priv->tx_stats_lock); + skb_queue_head_init(&priv->tx_queue); + skb_queue_head_init(&priv->tx_pending); + dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT); + + dev->channel_change_time = 1000; /* TODO: find actual value */ + priv->tx_stats[P54_QUEUE_BEACON].limit = 1; + priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1; + priv->tx_stats[P54_QUEUE_MGMT].limit = 3; + priv->tx_stats[P54_QUEUE_CAB].limit = 3; + priv->tx_stats[P54_QUEUE_DATA].limit = 5; + dev->queues = 1; + priv->noise = -94; + /* + * We support at most 8 tries no matter which rate they're at, + * we cannot support max_rates * max_rate_tries as we set it + * here, but setting it correctly to 4/2 or so would limit us + * artificially if the RC algorithm wants just two rates, so + * let's say 4/7, we'll redistribute it at TX time, see the + * comments there. + */ + dev->max_rates = 4; + dev->max_rate_tries = 7; + dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 + + sizeof(struct p54_tx_data); + + mutex_init(&priv->conf_mutex); + mutex_init(&priv->eeprom_mutex); + init_completion(&priv->eeprom_comp); + INIT_DELAYED_WORK(&priv->work, p54_work); + + return dev; +} +EXPORT_SYMBOL_GPL(p54_init_common); + +int p54_register_common(struct ieee80211_hw *dev, struct device *pdev) +{ + struct p54_common *priv = dev->priv; + int err; + + err = ieee80211_register_hw(dev); + if (err) { + dev_err(pdev, "Cannot register device (%d).\n", err); + return err; + } + +#ifdef CONFIG_P54_LEDS + err = p54_init_leds(priv); + if (err) + return err; +#endif /* CONFIG_P54_LEDS */ + + dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy)); + return 0; +} +EXPORT_SYMBOL_GPL(p54_register_common); + +void p54_free_common(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + + kfree(priv->iq_autocal); + kfree(priv->output_limit); + kfree(priv->curve_data); + kfree(priv->used_rxkeys); + priv->iq_autocal = NULL; + priv->output_limit = NULL; + priv->curve_data = NULL; + priv->used_rxkeys = NULL; + ieee80211_free_hw(dev); +} +EXPORT_SYMBOL_GPL(p54_free_common); + +void p54_unregister_common(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + +#ifdef CONFIG_P54_LEDS + p54_unregister_leds(priv); +#endif /* CONFIG_P54_LEDS */ + + ieee80211_unregister_hw(dev); + mutex_destroy(&priv->conf_mutex); + mutex_destroy(&priv->eeprom_mutex); +} +EXPORT_SYMBOL_GPL(p54_unregister_common); -- cgit v0.10.2 From 0a5fb84f6b62bca8352f0aad045118e47340b096 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:39:12 -0500 Subject: p54: Move TX/RX code Copy the TX/RX code from p54common.c into a new file txrx.c Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c new file mode 100644 index 0000000..31fda17 --- /dev/null +++ b/drivers/net/wireless/p54/txrx.c @@ -0,0 +1,825 @@ +/* + * Common code for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * Copyright 2008, Johannes Berg + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include + +#include "p54.h" +#include "lmac.h" + +#ifdef P54_MM_DEBUG +static void p54_dump_tx_queue(struct p54_common *priv) +{ + unsigned long flags; + struct ieee80211_tx_info *info; + struct p54_tx_info *range; + struct sk_buff *skb; + struct p54_hdr *hdr; + unsigned int i = 0; + u32 prev_addr; + u32 largest_hole = 0, free; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) --- \n", + wiphy_name(priv->hw->wiphy), skb_queue_len(&priv->tx_queue)); + + prev_addr = priv->rx_start; + skb_queue_walk(&priv->tx_queue, skb) { + info = IEEE80211_SKB_CB(skb); + range = (void *) info->rate_driver_data; + hdr = (void *) skb->data; + + free = range->start_addr - prev_addr; + printk(KERN_DEBUG "%s: | [%02d] => [skb:%p skb_len:0x%04x " + "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} " + "mem:{start:%04x end:%04x, free:%d}]\n", + wiphy_name(priv->hw->wiphy), i++, skb, skb->len, + le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len), + le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type), + range->start_addr, range->end_addr, free); + + prev_addr = range->end_addr; + largest_hole = max(largest_hole, free); + } + free = priv->rx_end - prev_addr; + largest_hole = max(largest_hole, free); + printk(KERN_DEBUG "%s: \\ --- [free: %d], largest free block: %d ---\n", + wiphy_name(priv->hw->wiphy), free, largest_hole); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); +} +#endif /* P54_MM_DEBUG */ + +/* + * So, the firmware is somewhat stupid and doesn't know what places in its + * memory incoming data should go to. By poking around in the firmware, we + * can find some unused memory to upload our packets to. However, data that we + * want the card to TX needs to stay intact until the card has told us that + * it is done with it. This function finds empty places we can upload to and + * marks allocated areas as reserved if necessary. p54_find_and_unlink_skb or + * p54_free_skb frees allocated areas. + */ +static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb) +{ + struct sk_buff *entry, *target_skb = NULL; + struct ieee80211_tx_info *info; + struct p54_tx_info *range; + struct p54_hdr *data = (void *) skb->data; + unsigned long flags; + u32 last_addr = priv->rx_start; + u32 target_addr = priv->rx_start; + u16 len = priv->headroom + skb->len + priv->tailroom + 3; + + if (unlikely(WARN_ON(!skb || !priv))) + return -EINVAL; + + info = IEEE80211_SKB_CB(skb); + range = (void *) info->rate_driver_data; + len = (range->extra_len + len) & ~0x3; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + if (unlikely(skb_queue_len(&priv->tx_queue) == 32)) { + /* + * The tx_queue is now really full. + * + * TODO: check if the device has crashed and reset it. + */ + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return -EBUSY; + } + + skb_queue_walk(&priv->tx_queue, entry) { + u32 hole_size; + info = IEEE80211_SKB_CB(entry); + range = (void *) info->rate_driver_data; + hole_size = range->start_addr - last_addr; + + if (!entry->next) { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return -ENOSPC; + } + + if (!target_skb && hole_size >= len) { + target_skb = entry->prev; + hole_size -= len; + target_addr = last_addr; + break; + } + last_addr = range->end_addr; + } + if (unlikely(!target_skb)) { + if (priv->rx_end - last_addr >= len) { + target_skb = priv->tx_queue.prev; + if (!skb_queue_empty(&priv->tx_queue)) { + info = IEEE80211_SKB_CB(target_skb); + range = (void *)info->rate_driver_data; + target_addr = range->end_addr; + } + } else { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return -ENOSPC; + } + } + + info = IEEE80211_SKB_CB(skb); + range = (void *) info->rate_driver_data; + range->start_addr = target_addr; + range->end_addr = target_addr + len; + __skb_queue_after(&priv->tx_queue, target_skb, skb); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + data->req_id = cpu_to_le32(target_addr + priv->headroom); + return 0; +} + +static void p54_tx_pending(struct p54_common *priv) +{ + struct sk_buff *skb; + int ret; + + if (unlikely(WARN_ON(!priv))) + return ; + + skb = skb_dequeue(&priv->tx_pending); + if (unlikely(!skb)) + return ; + + ret = p54_assign_address(priv, skb); + if (unlikely(ret)) + skb_queue_head(&priv->tx_pending, skb); + else + priv->tx(priv->hw, skb); +} + +static void p54_wake_queues(struct p54_common *priv) +{ + unsigned long flags; + unsigned int i; + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + + p54_tx_pending(priv); + + spin_lock_irqsave(&priv->tx_stats_lock, flags); + for (i = 0; i < priv->hw->queues; i++) { + if (priv->tx_stats[i + P54_QUEUE_DATA].len < + priv->tx_stats[i + P54_QUEUE_DATA].limit) + ieee80211_wake_queue(priv->hw, i); + } + spin_unlock_irqrestore(&priv->tx_stats_lock, flags); +} + +static int p54_tx_qos_accounting_alloc(struct p54_common *priv, + struct sk_buff *skb, + const u16 p54_queue) +{ + struct ieee80211_tx_queue_stats *queue; + unsigned long flags; + + if (WARN_ON(p54_queue > P54_QUEUE_NUM)) + return -EINVAL; + + queue = &priv->tx_stats[p54_queue]; + + spin_lock_irqsave(&priv->tx_stats_lock, flags); + if (unlikely(queue->len > queue->limit && IS_QOS_QUEUE(p54_queue))) { + spin_unlock_irqrestore(&priv->tx_stats_lock, flags); + return -ENOSPC; + } + + queue->len++; + queue->count++; + + if (unlikely(queue->len == queue->limit && IS_QOS_QUEUE(p54_queue))) { + u16 ac_queue = p54_queue - P54_QUEUE_DATA; + ieee80211_stop_queue(priv->hw, ac_queue); + } + + spin_unlock_irqrestore(&priv->tx_stats_lock, flags); + return 0; +} + +static void p54_tx_qos_accounting_free(struct p54_common *priv, + struct sk_buff *skb) +{ + if (skb && IS_DATA_FRAME(skb)) { + struct p54_hdr *hdr = (void *) skb->data; + struct p54_tx_data *data = (void *) hdr->data; + + priv->tx_stats[data->hw_queue].len--; + } + p54_wake_queues(priv); +} + +void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + if (unlikely(!skb)) + return ; + + skb_unlink(skb, &priv->tx_queue); + p54_tx_qos_accounting_free(priv, skb); + dev_kfree_skb_any(skb); +} +EXPORT_SYMBOL_GPL(p54_free_skb); + +static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv, + const __le32 req_id) +{ + struct sk_buff *entry; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + skb_queue_walk(&priv->tx_queue, entry) { + struct p54_hdr *hdr = (struct p54_hdr *) entry->data; + + if (hdr->req_id == req_id) { + __skb_unlink(entry, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + p54_tx_qos_accounting_free(priv, entry); + return entry; + } + } + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return NULL; +} + +void p54_tx(struct p54_common *priv, struct sk_buff *skb) +{ + if (unlikely(WARN_ON(!priv))) + return ; + + skb_queue_tail(&priv->tx_pending, skb); + p54_tx_pending(priv); +} + +static int p54_rssi_to_dbm(struct p54_common *priv, int rssi) +{ + int band = priv->hw->conf.channel->band; + + if (priv->rxhw != 5) + return ((rssi * priv->rssical_db[band].mul) / 64 + + priv->rssical_db[band].add) / 4; + else + /* + * TODO: find the correct formula + */ + return ((rssi * priv->rssical_db[band].mul) / 64 + + priv->rssical_db[band].add) / 4; +} + +static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb) +{ + struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + u16 freq = le16_to_cpu(hdr->freq); + size_t header_len = sizeof(*hdr); + u32 tsf32; + u8 rate = hdr->rate & 0xf; + + /* + * If the device is in a unspecified state we have to + * ignore all data frames. Else we could end up with a + * nasty crash. + */ + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return 0; + + if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) + return 0; + + if (hdr->decrypt_status == P54_DECRYPT_OK) + rx_status->flag |= RX_FLAG_DECRYPTED; + if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) || + (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP)) + rx_status->flag |= RX_FLAG_MMIC_ERROR; + + rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi); + rx_status->noise = priv->noise; + if (hdr->rate & 0x10) + rx_status->flag |= RX_FLAG_SHORTPRE; + if (priv->hw->conf.channel->band == IEEE80211_BAND_5GHZ) + rx_status->rate_idx = (rate < 4) ? 0 : rate - 4; + else + rx_status->rate_idx = rate; + + rx_status->freq = freq; + rx_status->band = priv->hw->conf.channel->band; + rx_status->antenna = hdr->antenna; + + tsf32 = le32_to_cpu(hdr->tsf32); + if (tsf32 < priv->tsf_low32) + priv->tsf_high32++; + rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32; + priv->tsf_low32 = tsf32; + + rx_status->flag |= RX_FLAG_TSFT; + + if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) + header_len += hdr->align[0]; + + skb_pull(skb, header_len); + skb_trim(skb, le16_to_cpu(hdr->len)); + ieee80211_rx_irqsafe(priv->hw, skb); + + queue_delayed_work(priv->hw->workqueue, &priv->work, + msecs_to_jiffies(P54_STATISTICS_UPDATE)); + + return -1; +} + +static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data; + struct ieee80211_tx_info *info; + struct p54_hdr *entry_hdr; + struct p54_tx_data *entry_data; + struct sk_buff *entry; + unsigned int pad = 0, frame_len; + int count, idx; + + entry = p54_find_and_unlink_skb(priv, hdr->req_id); + if (unlikely(!entry)) + return ; + + frame_len = entry->len; + info = IEEE80211_SKB_CB(entry); + entry_hdr = (struct p54_hdr *) entry->data; + entry_data = (struct p54_tx_data *) entry_hdr->data; + priv->stats.dot11ACKFailureCount += payload->tries - 1; + + /* + * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are + * generated by the driver. Therefore tx_status is bogus + * and we don't want to confuse the mac80211 stack. + */ + if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) { + if (entry_data->hw_queue == P54_QUEUE_BEACON && + hdr->req_id == priv->beacon_req_id) + priv->beacon_req_id = cpu_to_le32(0); + + dev_kfree_skb_any(entry); + return ; + } + + /* + * Clear manually, ieee80211_tx_info_clear_status would + * clear the counts too and we need them. + */ + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, + status.ampdu_ack_len) != 23); + + if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) + pad = entry_data->align[0]; + + /* walk through the rates array and adjust the counts */ + count = payload->tries; + for (idx = 0; idx < 4; idx++) { + if (count >= info->status.rates[idx].count) { + count -= info->status.rates[idx].count; + } else if (count > 0) { + info->status.rates[idx].count = count; + count = 0; + } else { + info->status.rates[idx].idx = -1; + info->status.rates[idx].count = 0; + } + } + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (!payload->status)) + info->flags |= IEEE80211_TX_STAT_ACK; + if (payload->status & P54_TX_PSM_CANCELLED) + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + info->status.ack_signal = p54_rssi_to_dbm(priv, + (int)payload->ack_rssi); + + /* Undo all changes to the frame. */ + switch (entry_data->key_type) { + case P54_CRYPTO_TKIPMICHAEL: { + u8 *iv = (u8 *)(entry_data->align + pad + + entry_data->crypt_offset); + + /* Restore the original TKIP IV. */ + iv[2] = iv[0]; + iv[0] = iv[1]; + iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */ + + frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */ + break; + } + case P54_CRYPTO_AESCCMP: + frame_len -= 8; /* remove CCMP_MIC */ + break; + case P54_CRYPTO_WEP: + frame_len -= 4; /* remove WEP_ICV */ + break; + } + + skb_trim(entry, frame_len); + skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); + ieee80211_tx_status_irqsafe(priv->hw, entry); +} + +static void p54_rx_eeprom_readback(struct p54_common *priv, + struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data; + struct sk_buff *tmp; + + if (!priv->eeprom) + return ; + + if (priv->fw_var >= 0x509) { + memcpy(priv->eeprom, eeprom->v2.data, + le16_to_cpu(eeprom->v2.len)); + } else { + memcpy(priv->eeprom, eeprom->v1.data, + le16_to_cpu(eeprom->v1.len)); + } + + priv->eeprom = NULL; + tmp = p54_find_and_unlink_skb(priv, hdr->req_id); + p54_tx_qos_accounting_free(priv, tmp); + dev_kfree_skb_any(tmp); + complete(&priv->eeprom_comp); +} + +static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_statistics *stats = (struct p54_statistics *) hdr->data; + struct sk_buff *tmp; + u32 tsf32; + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + + tsf32 = le32_to_cpu(stats->tsf32); + if (tsf32 < priv->tsf_low32) + priv->tsf_high32++; + priv->tsf_low32 = tsf32; + + priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail); + priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success); + priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); + + priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise)); + + tmp = p54_find_and_unlink_skb(priv, hdr->req_id); + p54_tx_qos_accounting_free(priv, tmp); + dev_kfree_skb_any(tmp); +} + +static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_trap *trap = (struct p54_trap *) hdr->data; + u16 event = le16_to_cpu(trap->event); + u16 freq = le16_to_cpu(trap->frequency); + + switch (event) { + case P54_TRAP_BEACON_TX: + break; + case P54_TRAP_RADAR: + printk(KERN_INFO "%s: radar (freq:%d MHz)\n", + wiphy_name(priv->hw->wiphy), freq); + break; + case P54_TRAP_NO_BEACON: + if (priv->vif) + ieee80211_beacon_loss(priv->vif); + break; + case P54_TRAP_SCAN: + break; + case P54_TRAP_TBTT: + break; + case P54_TRAP_TIMER: + break; + default: + printk(KERN_INFO "%s: received event:%x freq:%d\n", + wiphy_name(priv->hw->wiphy), event, freq); + break; + } +} + +static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + + switch (le16_to_cpu(hdr->type)) { + case P54_CONTROL_TYPE_TXDONE: + p54_rx_frame_sent(priv, skb); + break; + case P54_CONTROL_TYPE_TRAP: + p54_rx_trap(priv, skb); + break; + case P54_CONTROL_TYPE_BBP: + break; + case P54_CONTROL_TYPE_STAT_READBACK: + p54_rx_stats(priv, skb); + break; + case P54_CONTROL_TYPE_EEPROM_READBACK: + p54_rx_eeprom_readback(priv, skb); + break; + default: + printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n", + wiphy_name(priv->hw->wiphy), le16_to_cpu(hdr->type)); + break; + } + return 0; +} + +/* returns zero if skb can be reused */ +int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + u16 type = le16_to_cpu(*((__le16 *)skb->data)); + + if (type & P54_HDR_FLAG_CONTROL) + return p54_rx_control(priv, skb); + else + return p54_rx_data(priv, skb); +} +EXPORT_SYMBOL_GPL(p54_rx); + +static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, + struct ieee80211_tx_info *info, u8 *queue, + u32 *extra_len, u16 *flags, u16 *aid, + bool *burst_possible) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (ieee80211_is_data_qos(hdr->frame_control)) + *burst_possible = true; + else + *burst_possible = false; + + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; + + if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) + *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; + + *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA; + + switch (priv->mode) { + case NL80211_IFTYPE_MONITOR: + /* + * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for + * every frame in promiscuous/monitor mode. + * see STSW45x0C LMAC API - page 12. + */ + *aid = 0; + *flags |= P54_HDR_FLAG_DATA_OUT_PROMISC; + break; + case NL80211_IFTYPE_STATION: + *aid = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { + *aid = 0; + *queue = P54_QUEUE_CAB; + return; + } + + if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) { + if (ieee80211_is_probe_resp(hdr->frame_control)) { + *aid = 0; + *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP | + P54_HDR_FLAG_DATA_OUT_NOCANCEL; + return; + } else if (ieee80211_is_beacon(hdr->frame_control)) { + *aid = 0; + + if (info->flags & IEEE80211_TX_CTL_INJECTED) { + /* + * Injecting beacons on top of a AP is + * not a good idea... nevertheless, + * it should be doable. + */ + + return; + } + + *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP; + *queue = P54_QUEUE_BEACON; + *extra_len = IEEE80211_MAX_TIM_LEN; + return; + } + } + + if (info->control.sta) + *aid = info->control.sta->aid; + break; + } +} + +static u8 p54_convert_algo(enum ieee80211_key_alg alg) +{ + switch (alg) { + case ALG_WEP: + return P54_CRYPTO_WEP; + case ALG_TKIP: + return P54_CRYPTO_TKIPMICHAEL; + case ALG_CCMP: + return P54_CRYPTO_AESCCMP; + default: + return 0; + } +} + +int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct p54_tx_info *p54info; + struct p54_hdr *hdr; + struct p54_tx_data *txhdr; + unsigned int padding, len, extra_len; + int i, j, ridx; + u16 hdr_flags = 0, aid = 0; + u8 rate, queue = 0, crypt_offset = 0; + u8 cts_rate = 0x20; + u8 rc_flags; + u8 calculated_tries[4]; + u8 nrates = 0, nremaining = 8; + bool burst_allowed = false; + + p54_tx_80211_header(priv, skb, info, &queue, &extra_len, + &hdr_flags, &aid, &burst_allowed); + + if (p54_tx_qos_accounting_alloc(priv, skb, queue)) { + if (!IS_QOS_QUEUE(queue)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } else { + return NETDEV_TX_BUSY; + } + } + + padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; + len = skb->len; + + if (info->control.hw_key) { + crypt_offset = ieee80211_get_hdrlen_from_skb(skb); + if (info->control.hw_key->alg == ALG_TKIP) { + u8 *iv = (u8 *)(skb->data + crypt_offset); + /* + * The firmware excepts that the IV has to have + * this special format + */ + iv[1] = iv[0]; + iv[0] = iv[2]; + iv[2] = 0; + } + } + + txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); + hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); + + if (padding) + hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; + hdr->type = cpu_to_le16(aid); + hdr->rts_tries = info->control.rates[0].count; + + /* + * we register the rates in perfect order, and + * RTS/CTS won't happen on 5 GHz + */ + cts_rate = info->control.rts_cts_rate_idx; + + memset(&txhdr->rateset, 0, sizeof(txhdr->rateset)); + + /* see how many rates got used */ + for (i = 0; i < dev->max_rates; i++) { + if (info->control.rates[i].idx < 0) + break; + nrates++; + } + + /* limit tries to 8/nrates per rate */ + for (i = 0; i < nrates; i++) { + /* + * The magic expression here is equivalent to 8/nrates for + * all values that matter, but avoids division and jumps. + * Note that nrates can only take the values 1 through 4. + */ + calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1, + info->control.rates[i].count); + nremaining -= calculated_tries[i]; + } + + /* if there are tries left, distribute from back to front */ + for (i = nrates - 1; nremaining > 0 && i >= 0; i--) { + int tmp = info->control.rates[i].count - calculated_tries[i]; + + if (tmp <= 0) + continue; + /* RC requested more tries at this rate */ + + tmp = min_t(int, tmp, nremaining); + calculated_tries[i] += tmp; + nremaining -= tmp; + } + + ridx = 0; + for (i = 0; i < nrates && ridx < 8; i++) { + /* we register the rates in perfect order */ + rate = info->control.rates[i].idx; + if (info->band == IEEE80211_BAND_5GHZ) + rate += 4; + + /* store the count we actually calculated for TX status */ + info->control.rates[i].count = calculated_tries[i]; + + rc_flags = info->control.rates[i].flags; + if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { + rate |= 0x10; + cts_rate |= 0x10; + } + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { + burst_allowed = false; + rate |= 0x40; + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + rate |= 0x20; + burst_allowed = false; + } + for (j = 0; j < calculated_tries[i] && ridx < 8; j++) { + txhdr->rateset[ridx] = rate; + ridx++; + } + } + + if (burst_allowed) + hdr_flags |= P54_HDR_FLAG_DATA_OUT_BURST; + + /* TODO: enable bursting */ + hdr->flags = cpu_to_le16(hdr_flags); + hdr->tries = ridx; + txhdr->rts_rate_idx = 0; + if (info->control.hw_key) { + txhdr->key_type = p54_convert_algo(info->control.hw_key->alg); + txhdr->key_len = min((u8)16, info->control.hw_key->keylen); + memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len); + if (info->control.hw_key->alg == ALG_TKIP) { + /* reserve space for the MIC key */ + len += 8; + memcpy(skb_put(skb, 8), &(info->control.hw_key->key + [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8); + } + /* reserve some space for ICV */ + len += info->control.hw_key->icv_len; + memset(skb_put(skb, info->control.hw_key->icv_len), 0, + info->control.hw_key->icv_len); + } else { + txhdr->key_type = 0; + txhdr->key_len = 0; + } + txhdr->crypt_offset = crypt_offset; + txhdr->hw_queue = queue; + txhdr->backlog = priv->tx_stats[queue].len - 1; + memset(txhdr->durations, 0, sizeof(txhdr->durations)); + txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ? + 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask; + if (priv->rxhw == 5) { + txhdr->longbow.cts_rate = cts_rate; + txhdr->longbow.output_power = cpu_to_le16(priv->output_power); + } else { + txhdr->normal.output_power = priv->output_power; + txhdr->normal.cts_rate = cts_rate; + } + if (padding) + txhdr->align[0] = padding; + + hdr->len = cpu_to_le16(len); + /* modifies skb->cb and with it info, so must be last! */ + p54info = (void *) info->rate_driver_data; + p54info->extra_len = extra_len; + + p54_tx(priv, skb); + return NETDEV_TX_OK; +} -- cgit v0.10.2 From d8c9210757605c5191d2d9f4e09be5e59ceac824 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:39:45 -0500 Subject: p54: Modify p54 files for new organization Modify the remaining p54 files to account for the new file organization. Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/Makefile b/drivers/net/wireless/p54/Makefile index c2050de..b542e68 100644 --- a/drivers/net/wireless/p54/Makefile +++ b/drivers/net/wireless/p54/Makefile @@ -1,3 +1,6 @@ +p54common-objs := eeprom.o fwio.o txrx.o main.o +p54common-$(CONFIG_P54_LEDS) += led.o + obj-$(CONFIG_P54_COMMON) += p54common.o obj-$(CONFIG_P54_USB) += p54usb.o obj-$(CONFIG_P54_PCI) += p54pci.o diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index db3df94..19d085c 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -1,6 +1,3 @@ -#ifndef P54_H -#define P54_H - /* * Shared defines for all mac80211 Prism54 code * @@ -14,39 +11,78 @@ * published by the Free Software Foundation. */ +#ifndef P54_H +#define P54_H + #ifdef CONFIG_P54_LEDS #include #endif /* CONFIG_P54_LEDS */ -enum p54_control_frame_types { - P54_CONTROL_TYPE_SETUP = 0, - P54_CONTROL_TYPE_SCAN, - P54_CONTROL_TYPE_TRAP, - P54_CONTROL_TYPE_DCFINIT, - P54_CONTROL_TYPE_RX_KEYCACHE, - P54_CONTROL_TYPE_TIM, - P54_CONTROL_TYPE_PSM, - P54_CONTROL_TYPE_TXCANCEL, - P54_CONTROL_TYPE_TXDONE, - P54_CONTROL_TYPE_BURST, - P54_CONTROL_TYPE_STAT_READBACK, - P54_CONTROL_TYPE_BBP, - P54_CONTROL_TYPE_EEPROM_READBACK, - P54_CONTROL_TYPE_LED, - P54_CONTROL_TYPE_GPIO, - P54_CONTROL_TYPE_TIMER, - P54_CONTROL_TYPE_MODULATION, - P54_CONTROL_TYPE_SYNTH_CONFIG, - P54_CONTROL_TYPE_DETECTOR_VALUE, - P54_CONTROL_TYPE_XBOW_SYNTH_CFG, - P54_CONTROL_TYPE_CCE_QUIET, - P54_CONTROL_TYPE_PSM_STA_UNLOCK, - P54_CONTROL_TYPE_PCS, - P54_CONTROL_TYPE_BT_BALANCER = 28, - P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30, - P54_CONTROL_TYPE_ARPTABLE = 31, - P54_CONTROL_TYPE_BT_OPTIONS = 35 -}; +#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 + +#define BR_CODE_MIN 0x80000000 +#define BR_CODE_COMPONENT_ID 0x80000001 +#define BR_CODE_COMPONENT_VERSION 0x80000002 +#define BR_CODE_DEPENDENT_IF 0x80000003 +#define BR_CODE_EXPOSED_IF 0x80000004 +#define BR_CODE_DESCR 0x80000101 +#define BR_CODE_MAX 0x8FFFFFFF +#define BR_CODE_END_OF_BRA 0xFF0000FF +#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF + +struct bootrec { + __le32 code; + __le32 len; + u32 data[10]; +} __packed; + +/* Interface role definitions */ +#define BR_INTERFACE_ROLE_SERVER 0x0000 +#define BR_INTERFACE_ROLE_CLIENT 0x8000 + +#define BR_DESC_PRIV_CAP_WEP BIT(0) +#define BR_DESC_PRIV_CAP_TKIP BIT(1) +#define BR_DESC_PRIV_CAP_MICHAEL BIT(2) +#define BR_DESC_PRIV_CAP_CCX_CP BIT(3) +#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4) +#define BR_DESC_PRIV_CAP_AESCCMP BIT(5) + +struct bootrec_desc { + __le16 modes; + __le16 flags; + __le32 rx_start; + __le32 rx_end; + u8 headroom; + u8 tailroom; + u8 tx_queues; + u8 tx_depth; + u8 privacy_caps; + u8 rx_keycache_size; + u8 time_size; + u8 padding; + u8 rates[16]; + u8 padding2[4]; + __le16 rx_mtu; +} __packed; + +#define FW_FMAC 0x464d4143 +#define FW_LM86 0x4c4d3836 +#define FW_LM87 0x4c4d3837 +#define FW_LM20 0x4c4d3230 + +struct bootrec_comp_id { + __le32 fw_variant; +} __packed; + +struct bootrec_comp_ver { + char fw_version[24]; +} __packed; + +struct bootrec_end { + __le16 crc; + u8 padding[2]; + u8 md5[16]; +} __packed; /* provide 16 bytes for the transport back-end */ #define P54_TX_INFO_DATA_SIZE 16 @@ -55,34 +91,30 @@ enum p54_control_frame_types { struct p54_tx_info { u32 start_addr; u32 end_addr; - void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)]; + union { + void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)]; + struct { + u32 extra_len; + }; + }; }; #define P54_MAX_CTRL_FRAME_LEN 0x1000 -#define P54_HDR_FLAG_CONTROL BIT(15) -#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) - -struct p54_hdr { - __le16 flags; - __le16 len; - __le32 req_id; - __le16 type; /* enum p54_control_frame_types */ - u8 rts_tries; - u8 tries; - u8 data[0]; -} __attribute__ ((packed)); - -#define FREE_AFTER_TX(skb) \ - ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ - flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET)) +#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \ +do { \ + queue.aifs = cpu_to_le16(ai_fs); \ + queue.cwmin = cpu_to_le16(cw_min); \ + queue.cwmax = cpu_to_le16(cw_max); \ + queue.txop = cpu_to_le16(_txop); \ +} while (0) struct p54_edcf_queue_param { __le16 aifs; __le16 cwmin; __le16 cwmax; __le16 txop; -} __attribute__ ((packed)); +} __packed; struct p54_rssi_linear_approximation { s16 mul; @@ -101,13 +133,6 @@ struct p54_cal_database { #define EEPROM_READBACK_LEN 0x3fc -#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 - -#define FW_FMAC 0x464d4143 -#define FW_LM86 0x4c4d3836 -#define FW_LM87 0x4c4d3837 -#define FW_LM20 0x4c4d3230 - enum fw_state { FW_STATE_OFF, FW_STATE_BOOTING, @@ -138,6 +163,7 @@ struct p54_common { void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); + struct sk_buff_head tx_pending; struct sk_buff_head tx_queue; struct mutex conf_mutex; @@ -156,6 +182,7 @@ struct p54_common { /* (e)DCF / QOS state */ bool use_short_slot; + spinlock_t tx_stats_lock; struct ieee80211_tx_queue_stats tx_stats[8]; struct p54_edcf_queue_param qos_params[8]; @@ -181,7 +208,7 @@ struct p54_common { u32 tsf_low32, tsf_high32; u32 basic_rate_mask; u16 aid; - struct sk_buff *cached_beacon; + __le32 beacon_req_id; /* cryptographic engine information */ u8 privacy_caps; @@ -202,15 +229,20 @@ struct p54_common { /* eeprom handling */ void *eeprom; struct completion eeprom_comp; + struct mutex eeprom_mutex; }; +/* interfaces for the drivers */ int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb); int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len); int p54_read_eeprom(struct ieee80211_hw *dev); + struct ieee80211_hw *p54_init_common(size_t priv_data_len); int p54_register_common(struct ieee80211_hw *dev, struct device *pdev); void p54_free_common(struct ieee80211_hw *dev); +void p54_unregister_common(struct ieee80211_hw *dev); + #endif /* P54_H */ diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c deleted file mode 100644 index d1ea609..0000000 --- a/drivers/net/wireless/p54/p54common.c +++ /dev/null @@ -1,2687 +0,0 @@ -/* - * Common code for mac80211 Prism54 drivers - * - * Copyright (c) 2006, Michael Wu - * Copyright (c) 2007, Christian Lamparter - * Copyright 2008, Johannes Berg - * - * Based on: - * - the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. - * - stlc45xx driver - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). - * - * 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 - * published by the Free Software Foundation. - */ - -#include -#include -#include - -#include -#ifdef CONFIG_P54_LEDS -#include -#endif /* CONFIG_P54_LEDS */ - -#include "p54.h" -#include "p54common.h" - -static int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); -MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -MODULE_AUTHOR("Michael Wu "); -MODULE_DESCRIPTION("Softmac Prism54 common code"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("prism54common"); - -static struct ieee80211_rate p54_bgrates[] = { - { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 60, .hw_value = 4, }, - { .bitrate = 90, .hw_value = 5, }, - { .bitrate = 120, .hw_value = 6, }, - { .bitrate = 180, .hw_value = 7, }, - { .bitrate = 240, .hw_value = 8, }, - { .bitrate = 360, .hw_value = 9, }, - { .bitrate = 480, .hw_value = 10, }, - { .bitrate = 540, .hw_value = 11, }, -}; - -static struct ieee80211_channel p54_bgchannels[] = { - { .center_freq = 2412, .hw_value = 1, }, - { .center_freq = 2417, .hw_value = 2, }, - { .center_freq = 2422, .hw_value = 3, }, - { .center_freq = 2427, .hw_value = 4, }, - { .center_freq = 2432, .hw_value = 5, }, - { .center_freq = 2437, .hw_value = 6, }, - { .center_freq = 2442, .hw_value = 7, }, - { .center_freq = 2447, .hw_value = 8, }, - { .center_freq = 2452, .hw_value = 9, }, - { .center_freq = 2457, .hw_value = 10, }, - { .center_freq = 2462, .hw_value = 11, }, - { .center_freq = 2467, .hw_value = 12, }, - { .center_freq = 2472, .hw_value = 13, }, - { .center_freq = 2484, .hw_value = 14, }, -}; - -static struct ieee80211_supported_band band_2GHz = { - .channels = p54_bgchannels, - .n_channels = ARRAY_SIZE(p54_bgchannels), - .bitrates = p54_bgrates, - .n_bitrates = ARRAY_SIZE(p54_bgrates), -}; - -static struct ieee80211_rate p54_arates[] = { - { .bitrate = 60, .hw_value = 4, }, - { .bitrate = 90, .hw_value = 5, }, - { .bitrate = 120, .hw_value = 6, }, - { .bitrate = 180, .hw_value = 7, }, - { .bitrate = 240, .hw_value = 8, }, - { .bitrate = 360, .hw_value = 9, }, - { .bitrate = 480, .hw_value = 10, }, - { .bitrate = 540, .hw_value = 11, }, -}; - -static struct ieee80211_channel p54_achannels[] = { - { .center_freq = 4920 }, - { .center_freq = 4940 }, - { .center_freq = 4960 }, - { .center_freq = 4980 }, - { .center_freq = 5040 }, - { .center_freq = 5060 }, - { .center_freq = 5080 }, - { .center_freq = 5170 }, - { .center_freq = 5180 }, - { .center_freq = 5190 }, - { .center_freq = 5200 }, - { .center_freq = 5210 }, - { .center_freq = 5220 }, - { .center_freq = 5230 }, - { .center_freq = 5240 }, - { .center_freq = 5260 }, - { .center_freq = 5280 }, - { .center_freq = 5300 }, - { .center_freq = 5320 }, - { .center_freq = 5500 }, - { .center_freq = 5520 }, - { .center_freq = 5540 }, - { .center_freq = 5560 }, - { .center_freq = 5580 }, - { .center_freq = 5600 }, - { .center_freq = 5620 }, - { .center_freq = 5640 }, - { .center_freq = 5660 }, - { .center_freq = 5680 }, - { .center_freq = 5700 }, - { .center_freq = 5745 }, - { .center_freq = 5765 }, - { .center_freq = 5785 }, - { .center_freq = 5805 }, - { .center_freq = 5825 }, -}; - -static struct ieee80211_supported_band band_5GHz = { - .channels = p54_achannels, - .n_channels = ARRAY_SIZE(p54_achannels), - .bitrates = p54_arates, - .n_bitrates = ARRAY_SIZE(p54_arates), -}; - -int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) -{ - struct p54_common *priv = dev->priv; - struct bootrec_exp_if *exp_if; - struct bootrec *bootrec; - u32 *data = (u32 *)fw->data; - u32 *end_data = (u32 *)fw->data + (fw->size >> 2); - u8 *fw_version = NULL; - size_t len; - int i; - int maxlen; - - if (priv->rx_start) - return 0; - - while (data < end_data && *data) - data++; - - while (data < end_data && !*data) - data++; - - bootrec = (struct bootrec *) data; - - while (bootrec->data <= end_data && - (bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) { - u32 code = le32_to_cpu(bootrec->code); - switch (code) { - case BR_CODE_COMPONENT_ID: - priv->fw_interface = be32_to_cpup((__be32 *) - bootrec->data); - switch (priv->fw_interface) { - case FW_LM86: - case FW_LM20: - case FW_LM87: { - char *iftype = (char *)bootrec->data; - printk(KERN_INFO "%s: p54 detected a LM%c%c " - "firmware\n", - wiphy_name(dev->wiphy), - iftype[2], iftype[3]); - break; - } - case FW_FMAC: - default: - printk(KERN_ERR "%s: unsupported firmware\n", - wiphy_name(dev->wiphy)); - return -ENODEV; - } - break; - case BR_CODE_COMPONENT_VERSION: - /* 24 bytes should be enough for all firmwares */ - if (strnlen((unsigned char*)bootrec->data, 24) < 24) - fw_version = (unsigned char*)bootrec->data; - break; - case BR_CODE_DESCR: { - struct bootrec_desc *desc = - (struct bootrec_desc *)bootrec->data; - priv->rx_start = le32_to_cpu(desc->rx_start); - /* FIXME add sanity checking */ - priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; - priv->headroom = desc->headroom; - priv->tailroom = desc->tailroom; - priv->privacy_caps = desc->privacy_caps; - priv->rx_keycache_size = desc->rx_keycache_size; - if (le32_to_cpu(bootrec->len) == 11) - priv->rx_mtu = le16_to_cpu(desc->rx_mtu); - else - priv->rx_mtu = (size_t) - 0x620 - priv->tx_hdr_len; - maxlen = priv->tx_hdr_len + /* USB devices */ - sizeof(struct p54_rx_data) + - 4 + /* rx alignment */ - IEEE80211_MAX_FRAG_THRESHOLD; - if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) { - printk(KERN_INFO "p54: rx_mtu reduced from %d " - "to %d\n", priv->rx_mtu, - maxlen); - priv->rx_mtu = maxlen; - } - break; - } - case BR_CODE_EXPOSED_IF: - exp_if = (struct bootrec_exp_if *) bootrec->data; - for (i = 0; i < (len * sizeof(*exp_if) / 4); i++) - if (exp_if[i].if_id == cpu_to_le16(0x1a)) - priv->fw_var = le16_to_cpu(exp_if[i].variant); - break; - case BR_CODE_DEPENDENT_IF: - break; - case BR_CODE_END_OF_BRA: - case LEGACY_BR_CODE_END_OF_BRA: - end_data = NULL; - break; - default: - break; - } - bootrec = (struct bootrec *)&bootrec->data[len]; - } - - if (fw_version) - printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n", - wiphy_name(dev->wiphy), fw_version, - priv->fw_var >> 8, priv->fw_var & 0xff); - - if (priv->fw_var < 0x500) - printk(KERN_INFO "%s: you are using an obsolete firmware. " - "visit http://wireless.kernel.org/en/users/Drivers/p54 " - "and grab one for \"kernel >= 2.6.28\"!\n", - wiphy_name(dev->wiphy)); - - if (priv->fw_var >= 0x300) { - /* Firmware supports QoS, use it! */ - priv->tx_stats[P54_QUEUE_AC_VO].limit = 3; - priv->tx_stats[P54_QUEUE_AC_VI].limit = 4; - priv->tx_stats[P54_QUEUE_AC_BE].limit = 3; - priv->tx_stats[P54_QUEUE_AC_BK].limit = 2; - dev->queues = P54_QUEUE_AC_NUM; - } - - if (!modparam_nohwcrypt) { - printk(KERN_INFO "%s: cryptographic accelerator " - "WEP:%s, TKIP:%s, CCMP:%s\n", - wiphy_name(dev->wiphy), - (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : - "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP | - BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no", - (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? - "YES" : "no"); - - if (priv->rx_keycache_size) { - /* - * NOTE: - * - * The firmware provides at most 255 (0 - 254) slots - * for keys which are then used to offload decryption. - * As a result the 255 entry (aka 0xff) can be used - * safely by the driver to mark keys that didn't fit - * into the full cache. This trick saves us from - * keeping a extra list for uploaded keys. - */ - - priv->used_rxkeys = kzalloc(BITS_TO_LONGS( - priv->rx_keycache_size), GFP_KERNEL); - - if (!priv->used_rxkeys) - return -ENOMEM; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(p54_parse_firmware); - -static int p54_convert_rev0(struct ieee80211_hw *dev, - struct pda_pa_curve_data *curve_data) -{ - struct p54_common *priv = dev->priv; - struct p54_pa_curve_data_sample *dst; - struct pda_pa_curve_data_sample_rev0 *src; - size_t cd_len = sizeof(*curve_data) + - (curve_data->points_per_channel*sizeof(*dst) + 2) * - curve_data->channels; - unsigned int i, j; - void *source, *target; - - priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len, - GFP_KERNEL); - if (!priv->curve_data) - return -ENOMEM; - - priv->curve_data->entries = curve_data->channels; - priv->curve_data->entry_size = sizeof(__le16) + - sizeof(*dst) * curve_data->points_per_channel; - priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data); - priv->curve_data->len = cd_len; - memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data)); - source = curve_data->data; - target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data; - for (i = 0; i < curve_data->channels; i++) { - __le16 *freq = source; - source += sizeof(__le16); - *((__le16 *)target) = *freq; - target += sizeof(__le16); - for (j = 0; j < curve_data->points_per_channel; j++) { - dst = target; - src = source; - - dst->rf_power = src->rf_power; - dst->pa_detector = src->pa_detector; - dst->data_64qam = src->pcv; - /* "invent" the points for the other modulations */ -#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y) - dst->data_16qam = SUB(src->pcv, 12); - dst->data_qpsk = SUB(dst->data_16qam, 12); - dst->data_bpsk = SUB(dst->data_qpsk, 12); - dst->data_barker = SUB(dst->data_bpsk, 14); -#undef SUB - target += sizeof(*dst); - source += sizeof(*src); - } - } - - return 0; -} - -static int p54_convert_rev1(struct ieee80211_hw *dev, - struct pda_pa_curve_data *curve_data) -{ - struct p54_common *priv = dev->priv; - struct p54_pa_curve_data_sample *dst; - struct pda_pa_curve_data_sample_rev1 *src; - size_t cd_len = sizeof(*curve_data) + - (curve_data->points_per_channel*sizeof(*dst) + 2) * - curve_data->channels; - unsigned int i, j; - void *source, *target; - - priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data), - GFP_KERNEL); - if (!priv->curve_data) - return -ENOMEM; - - priv->curve_data->entries = curve_data->channels; - priv->curve_data->entry_size = sizeof(__le16) + - sizeof(*dst) * curve_data->points_per_channel; - priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data); - priv->curve_data->len = cd_len; - memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data)); - source = curve_data->data; - target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data; - for (i = 0; i < curve_data->channels; i++) { - __le16 *freq = source; - source += sizeof(__le16); - *((__le16 *)target) = *freq; - target += sizeof(__le16); - for (j = 0; j < curve_data->points_per_channel; j++) { - memcpy(target, source, sizeof(*src)); - - target += sizeof(*dst); - source += sizeof(*src); - } - source++; - } - - return 0; -} - -static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2", - "Frisbee", "Xbow", "Longbow", "NULL", "NULL" }; -static int p54_init_xbow_synth(struct ieee80211_hw *dev); - -static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len, - u16 type) -{ - struct p54_common *priv = dev->priv; - int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0; - int entry_size = sizeof(struct pda_rssi_cal_entry) + offset; - int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2; - int i; - - if (len != (entry_size * num_entries)) { - printk(KERN_ERR "%s: unknown rssi calibration data packing " - " type:(%x) len:%d.\n", - wiphy_name(dev->wiphy), type, len); - - print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, - data, len); - - printk(KERN_ERR "%s: please report this issue.\n", - wiphy_name(dev->wiphy)); - return; - } - - for (i = 0; i < num_entries; i++) { - struct pda_rssi_cal_entry *cal = data + - (offset + i * entry_size); - priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul); - priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add); - } -} - -static void p54_parse_default_country(struct ieee80211_hw *dev, - void *data, int len) -{ - struct pda_country *country; - - if (len != sizeof(*country)) { - printk(KERN_ERR "%s: found possible invalid default country " - "eeprom entry. (entry size: %d)\n", - wiphy_name(dev->wiphy), len); - - print_hex_dump_bytes("country:", DUMP_PREFIX_NONE, - data, len); - - printk(KERN_ERR "%s: please report this issue.\n", - wiphy_name(dev->wiphy)); - return; - } - - country = (struct pda_country *) data; - if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO) - regulatory_hint(dev->wiphy, country->alpha2); - else { - /* TODO: - * write a shared/common function that converts - * "Regulatory domain codes" (802.11-2007 14.8.2.2) - * into ISO/IEC 3166-1 alpha2 for regulatory_hint. - */ - } -} - -static int p54_convert_output_limits(struct ieee80211_hw *dev, - u8 *data, size_t len) -{ - struct p54_common *priv = dev->priv; - - if (len < 2) - return -EINVAL; - - if (data[0] != 0) { - printk(KERN_ERR "%s: unknown output power db revision:%x\n", - wiphy_name(dev->wiphy), data[0]); - return -EINVAL; - } - - if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len) - return -EINVAL; - - priv->output_limit = kmalloc(data[1] * - sizeof(struct pda_channel_output_limit) + - sizeof(*priv->output_limit), GFP_KERNEL); - - if (!priv->output_limit) - return -ENOMEM; - - priv->output_limit->offset = 0; - priv->output_limit->entries = data[1]; - priv->output_limit->entry_size = - sizeof(struct pda_channel_output_limit); - priv->output_limit->len = priv->output_limit->entry_size * - priv->output_limit->entries + - priv->output_limit->offset; - - memcpy(priv->output_limit->data, &data[2], - data[1] * sizeof(struct pda_channel_output_limit)); - - return 0; -} - -static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src, - size_t total_len) -{ - struct p54_cal_database *dst; - size_t payload_len, entries, entry_size, offset; - - payload_len = le16_to_cpu(src->len); - entries = le16_to_cpu(src->entries); - entry_size = le16_to_cpu(src->entry_size); - offset = le16_to_cpu(src->offset); - if (((entries * entry_size + offset) != payload_len) || - (payload_len + sizeof(*src) != total_len)) - return NULL; - - dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL); - if (!dst) - return NULL; - - dst->entries = entries; - dst->entry_size = entry_size; - dst->offset = offset; - dst->len = payload_len; - - memcpy(dst->data, src->data, payload_len); - return dst; -} - -int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) -{ - struct p54_common *priv = dev->priv; - struct eeprom_pda_wrap *wrap = NULL; - struct pda_entry *entry; - unsigned int data_len, entry_len; - void *tmp; - int err; - u8 *end = (u8 *)eeprom + len; - u16 synth = 0; - - wrap = (struct eeprom_pda_wrap *) eeprom; - entry = (void *)wrap->data + le16_to_cpu(wrap->len); - - /* verify that at least the entry length/code fits */ - while ((u8 *)entry <= end - sizeof(*entry)) { - entry_len = le16_to_cpu(entry->len); - data_len = ((entry_len - 1) << 1); - - /* abort if entry exceeds whole structure */ - if ((u8 *)entry + sizeof(*entry) + data_len > end) - break; - - switch (le16_to_cpu(entry->code)) { - case PDR_MAC_ADDRESS: - if (data_len != ETH_ALEN) - break; - SET_IEEE80211_PERM_ADDR(dev, entry->data); - break; - case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS: - if (priv->output_limit) - break; - err = p54_convert_output_limits(dev, entry->data, - data_len); - if (err) - goto err; - break; - case PDR_PRISM_PA_CAL_CURVE_DATA: { - struct pda_pa_curve_data *curve_data = - (struct pda_pa_curve_data *)entry->data; - if (data_len < sizeof(*curve_data)) { - err = -EINVAL; - goto err; - } - - switch (curve_data->cal_method_rev) { - case 0: - err = p54_convert_rev0(dev, curve_data); - break; - case 1: - err = p54_convert_rev1(dev, curve_data); - break; - default: - printk(KERN_ERR "%s: unknown curve data " - "revision %d\n", - wiphy_name(dev->wiphy), - curve_data->cal_method_rev); - err = -ENODEV; - break; - } - if (err) - goto err; - } - break; - case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: - priv->iq_autocal = kmalloc(data_len, GFP_KERNEL); - if (!priv->iq_autocal) { - err = -ENOMEM; - goto err; - } - - memcpy(priv->iq_autocal, entry->data, data_len); - priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry); - break; - case PDR_DEFAULT_COUNTRY: - p54_parse_default_country(dev, entry->data, data_len); - break; - case PDR_INTERFACE_LIST: - tmp = entry->data; - while ((u8 *)tmp < entry->data + data_len) { - struct bootrec_exp_if *exp_if = tmp; - if (le16_to_cpu(exp_if->if_id) == 0xf) - synth = le16_to_cpu(exp_if->variant); - tmp += sizeof(struct bootrec_exp_if); - } - break; - case PDR_HARDWARE_PLATFORM_COMPONENT_ID: - if (data_len < 2) - break; - priv->version = *(u8 *)(entry->data + 1); - break; - case PDR_RSSI_LINEAR_APPROXIMATION: - case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: - case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: - p54_parse_rssical(dev, entry->data, data_len, - le16_to_cpu(entry->code)); - break; - case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: { - __le16 *src = (void *) entry->data; - s16 *dst = (void *) &priv->rssical_db; - int i; - - if (data_len != sizeof(priv->rssical_db)) { - err = -EINVAL; - goto err; - } - for (i = 0; i < sizeof(priv->rssical_db) / - sizeof(*src); i++) - *(dst++) = (s16) le16_to_cpu(*(src++)); - } - break; - case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: { - struct pda_custom_wrapper *pda = (void *) entry->data; - if (priv->output_limit || data_len < sizeof(*pda)) - break; - priv->output_limit = p54_convert_db(pda, data_len); - } - break; - case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: { - struct pda_custom_wrapper *pda = (void *) entry->data; - if (priv->curve_data || data_len < sizeof(*pda)) - break; - priv->curve_data = p54_convert_db(pda, data_len); - } - break; - case PDR_END: - /* make it overrun */ - entry_len = len; - break; - case PDR_MANUFACTURING_PART_NUMBER: - case PDR_PDA_VERSION: - case PDR_NIC_SERIAL_NUMBER: - case PDR_REGULATORY_DOMAIN_LIST: - case PDR_TEMPERATURE_TYPE: - case PDR_PRISM_PCI_IDENTIFIER: - case PDR_COUNTRY_INFORMATION: - case PDR_OEM_NAME: - case PDR_PRODUCT_NAME: - case PDR_UTF8_OEM_NAME: - case PDR_UTF8_PRODUCT_NAME: - case PDR_COUNTRY_LIST: - case PDR_ANTENNA_GAIN: - case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA: - case PDR_REGULATORY_POWER_LIMITS: - case PDR_RADIATED_TRANSMISSION_CORRECTION: - case PDR_PRISM_TX_IQ_CALIBRATION: - case PDR_BASEBAND_REGISTERS: - case PDR_PER_CHANNEL_BASEBAND_REGISTERS: - break; - default: - printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n", - wiphy_name(dev->wiphy), - le16_to_cpu(entry->code)); - break; - } - - entry = (void *)entry + (entry_len + 1)*2; - } - - if (!synth || !priv->iq_autocal || !priv->output_limit || - !priv->curve_data) { - printk(KERN_ERR "%s: not all required entries found in eeprom!\n", - wiphy_name(dev->wiphy)); - err = -EINVAL; - goto err; - } - - priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; - if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) - p54_init_xbow_synth(dev); - if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) - dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; - if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) - dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; - if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED) - priv->rx_diversity_mask = 3; - if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED) - priv->tx_diversity_mask = 3; - - if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { - u8 perm_addr[ETH_ALEN]; - - printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n", - wiphy_name(dev->wiphy)); - random_ether_addr(perm_addr); - SET_IEEE80211_PERM_ADDR(dev, perm_addr); - } - - printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n", - wiphy_name(dev->wiphy), - dev->wiphy->perm_addr, - priv->version, p54_rf_chips[priv->rxhw]); - - return 0; - - err: - if (priv->iq_autocal) { - kfree(priv->iq_autocal); - priv->iq_autocal = NULL; - } - - if (priv->output_limit) { - kfree(priv->output_limit); - priv->output_limit = NULL; - } - - if (priv->curve_data) { - kfree(priv->curve_data); - priv->curve_data = NULL; - } - - printk(KERN_ERR "%s: eeprom parse failed!\n", - wiphy_name(dev->wiphy)); - return err; -} -EXPORT_SYMBOL_GPL(p54_parse_eeprom); - -static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) -{ - struct p54_common *priv = dev->priv; - int band = dev->conf.channel->band; - - if (priv->rxhw != PDR_SYNTH_FRONTEND_LONGBOW) - return ((rssi * priv->rssical_db[band].mul) / 64 + - priv->rssical_db[band].add) / 4; - else - /* - * TODO: find the correct formula - */ - return ((rssi * priv->rssical_db[band].mul) / 64 + - priv->rssical_db[band].add) / 4; -} - -static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_common *priv = dev->priv; - struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; - struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - u16 freq = le16_to_cpu(hdr->freq); - size_t header_len = sizeof(*hdr); - u32 tsf32; - u8 rate = hdr->rate & 0xf; - - /* - * If the device is in a unspecified state we have to - * ignore all data frames. Else we could end up with a - * nasty crash. - */ - if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) - return 0; - - if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) { - return 0; - } - - if (hdr->decrypt_status == P54_DECRYPT_OK) - rx_status->flag |= RX_FLAG_DECRYPTED; - if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) || - (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP)) - rx_status->flag |= RX_FLAG_MMIC_ERROR; - - rx_status->signal = p54_rssi_to_dbm(dev, hdr->rssi); - rx_status->noise = priv->noise; - if (hdr->rate & 0x10) - rx_status->flag |= RX_FLAG_SHORTPRE; - if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) - rx_status->rate_idx = (rate < 4) ? 0 : rate - 4; - else - rx_status->rate_idx = rate; - - rx_status->freq = freq; - rx_status->band = dev->conf.channel->band; - rx_status->antenna = hdr->antenna; - - tsf32 = le32_to_cpu(hdr->tsf32); - if (tsf32 < priv->tsf_low32) - priv->tsf_high32++; - rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32; - priv->tsf_low32 = tsf32; - - rx_status->flag |= RX_FLAG_TSFT; - - if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) - header_len += hdr->align[0]; - - skb_pull(skb, header_len); - skb_trim(skb, le16_to_cpu(hdr->len)); - ieee80211_rx_irqsafe(dev, skb); - - queue_delayed_work(dev->workqueue, &priv->work, - msecs_to_jiffies(P54_STATISTICS_UPDATE)); - - return -1; -} - -static void inline p54_wake_free_queues(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - int i; - - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) - return ; - - for (i = 0; i < dev->queues; i++) - if (priv->tx_stats[i + P54_QUEUE_DATA].len < - priv->tx_stats[i + P54_QUEUE_DATA].limit) - ieee80211_wake_queue(dev, i); -} - -void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_common *priv = dev->priv; - struct ieee80211_tx_info *info; - struct p54_tx_info *range; - unsigned long flags; - - if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) - return; - - /* - * don't try to free an already unlinked skb - */ - if (unlikely((!skb->next) || (!skb->prev))) - return; - - spin_lock_irqsave(&priv->tx_queue.lock, flags); - info = IEEE80211_SKB_CB(skb); - range = (void *)info->rate_driver_data; - if (skb->prev != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *ni; - struct p54_tx_info *mr; - - ni = IEEE80211_SKB_CB(skb->prev); - mr = (struct p54_tx_info *)ni->rate_driver_data; - } - if (skb->next != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *ni; - struct p54_tx_info *mr; - - ni = IEEE80211_SKB_CB(skb->next); - mr = (struct p54_tx_info *)ni->rate_driver_data; - } - __skb_unlink(skb, &priv->tx_queue); - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - dev_kfree_skb_any(skb); - p54_wake_free_queues(dev); -} -EXPORT_SYMBOL_GPL(p54_free_skb); - -static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev, - __le32 req_id) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *entry; - unsigned long flags; - - spin_lock_irqsave(&priv->tx_queue.lock, flags); - entry = priv->tx_queue.next; - while (entry != (struct sk_buff *)&priv->tx_queue) { - struct p54_hdr *hdr = (struct p54_hdr *) entry->data; - - if (hdr->req_id == req_id) { - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - return entry; - } - entry = entry->next; - } - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - return NULL; -} - -static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_common *priv = dev->priv; - struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data; - struct sk_buff *entry; - u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom; - struct p54_tx_info *range = NULL; - unsigned long flags; - int count, idx; - - spin_lock_irqsave(&priv->tx_queue.lock, flags); - entry = (struct sk_buff *) priv->tx_queue.next; - while (entry != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - struct p54_hdr *entry_hdr; - struct p54_tx_data *entry_data; - unsigned int pad = 0, frame_len; - - range = (void *)info->rate_driver_data; - if (range->start_addr != addr) { - entry = entry->next; - continue; - } - - if (entry->next != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *ni; - struct p54_tx_info *mr; - - ni = IEEE80211_SKB_CB(entry->next); - mr = (struct p54_tx_info *)ni->rate_driver_data; - } - - __skb_unlink(entry, &priv->tx_queue); - - frame_len = entry->len; - entry_hdr = (struct p54_hdr *) entry->data; - entry_data = (struct p54_tx_data *) entry_hdr->data; - if (priv->tx_stats[entry_data->hw_queue].len) - priv->tx_stats[entry_data->hw_queue].len--; - priv->stats.dot11ACKFailureCount += payload->tries - 1; - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - - /* - * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are - * generated by the driver. Therefore tx_status is bogus - * and we don't want to confuse the mac80211 stack. - */ - if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) { - if (entry_data->hw_queue == P54_QUEUE_BEACON) - priv->cached_beacon = NULL; - - kfree_skb(entry); - goto out; - } - - /* - * Clear manually, ieee80211_tx_info_clear_status would - * clear the counts too and we need them. - */ - memset(&info->status.ampdu_ack_len, 0, - sizeof(struct ieee80211_tx_info) - - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); - BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, - status.ampdu_ack_len) != 23); - - if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) - pad = entry_data->align[0]; - - /* walk through the rates array and adjust the counts */ - count = payload->tries; - for (idx = 0; idx < 4; idx++) { - if (count >= info->status.rates[idx].count) { - count -= info->status.rates[idx].count; - } else if (count > 0) { - info->status.rates[idx].count = count; - count = 0; - } else { - info->status.rates[idx].idx = -1; - info->status.rates[idx].count = 0; - } - } - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (!payload->status)) - info->flags |= IEEE80211_TX_STAT_ACK; - if (payload->status & P54_TX_PSM_CANCELLED) - info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - info->status.ack_signal = p54_rssi_to_dbm(dev, - (int)payload->ack_rssi); - - /* Undo all changes to the frame. */ - switch (entry_data->key_type) { - case P54_CRYPTO_TKIPMICHAEL: { - u8 *iv = (u8 *)(entry_data->align + pad + - entry_data->crypt_offset); - - /* Restore the original TKIP IV. */ - iv[2] = iv[0]; - iv[0] = iv[1]; - iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */ - - frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */ - break; - } - case P54_CRYPTO_AESCCMP: - frame_len -= 8; /* remove CCMP_MIC */ - break; - case P54_CRYPTO_WEP: - frame_len -= 4; /* remove WEP_ICV */ - break; - } - skb_trim(entry, frame_len); - skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); - ieee80211_tx_status_irqsafe(dev, entry); - goto out; - } - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - -out: - p54_wake_free_queues(dev); -} - -static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, - struct sk_buff *skb) -{ - struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data; - struct p54_common *priv = dev->priv; - - if (!priv->eeprom) - return ; - - if (priv->fw_var >= 0x509) { - memcpy(priv->eeprom, eeprom->v2.data, - le16_to_cpu(eeprom->v2.len)); - } else { - memcpy(priv->eeprom, eeprom->v1.data, - le16_to_cpu(eeprom->v1.len)); - } - - complete(&priv->eeprom_comp); -} - -static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_common *priv = dev->priv; - struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - struct p54_statistics *stats = (struct p54_statistics *) hdr->data; - u32 tsf32; - - if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) - return ; - - tsf32 = le32_to_cpu(stats->tsf32); - if (tsf32 < priv->tsf_low32) - priv->tsf_high32++; - priv->tsf_low32 = tsf32; - - priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail); - priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success); - priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); - - priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); - - p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id)); -} - -static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_common *priv = dev->priv; - struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - struct p54_trap *trap = (struct p54_trap *) hdr->data; - u16 event = le16_to_cpu(trap->event); - u16 freq = le16_to_cpu(trap->frequency); - - switch (event) { - case P54_TRAP_BEACON_TX: - break; - case P54_TRAP_RADAR: - printk(KERN_INFO "%s: radar (freq:%d MHz)\n", - wiphy_name(dev->wiphy), freq); - break; - case P54_TRAP_NO_BEACON: - if (priv->vif) - ieee80211_beacon_loss(priv->vif); - break; - case P54_TRAP_SCAN: - break; - case P54_TRAP_TBTT: - break; - case P54_TRAP_TIMER: - break; - default: - printk(KERN_INFO "%s: received event:%x freq:%d\n", - wiphy_name(dev->wiphy), event, freq); - break; - } -} - -static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - - switch (le16_to_cpu(hdr->type)) { - case P54_CONTROL_TYPE_TXDONE: - p54_rx_frame_sent(dev, skb); - break; - case P54_CONTROL_TYPE_TRAP: - p54_rx_trap(dev, skb); - break; - case P54_CONTROL_TYPE_BBP: - break; - case P54_CONTROL_TYPE_STAT_READBACK: - p54_rx_stats(dev, skb); - break; - case P54_CONTROL_TYPE_EEPROM_READBACK: - p54_rx_eeprom_readback(dev, skb); - break; - default: - printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n", - wiphy_name(dev->wiphy), le16_to_cpu(hdr->type)); - break; - } - - return 0; -} - -/* returns zero if skb can be reused */ -int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - u16 type = le16_to_cpu(*((__le16 *)skb->data)); - - if (type & P54_HDR_FLAG_CONTROL) - return p54_rx_control(dev, skb); - else - return p54_rx_data(dev, skb); -} -EXPORT_SYMBOL_GPL(p54_rx); - -/* - * So, the firmware is somewhat stupid and doesn't know what places in its - * memory incoming data should go to. By poking around in the firmware, we - * can find some unused memory to upload our packets to. However, data that we - * want the card to TX needs to stay intact until the card has told us that - * it is done with it. This function finds empty places we can upload to and - * marks allocated areas as reserved if necessary. p54_rx_frame_sent or - * p54_free_skb frees allocated areas. - */ -static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, - struct p54_hdr *data, u32 len) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *entry; - struct sk_buff *target_skb = NULL; - struct ieee80211_tx_info *info; - struct p54_tx_info *range; - u32 last_addr = priv->rx_start; - u32 largest_hole = 0; - u32 target_addr = priv->rx_start; - unsigned long flags; - unsigned int left; - len = (len + priv->headroom + priv->tailroom + 3) & ~0x3; - - if (!skb) - return -EINVAL; - - spin_lock_irqsave(&priv->tx_queue.lock, flags); - - left = skb_queue_len(&priv->tx_queue); - if (unlikely(left >= 28)) { - /* - * The tx_queue is nearly full! - * We have throttle normal data traffic, because we must - * have a few spare slots for control frames left. - */ - ieee80211_stop_queues(dev); - queue_delayed_work(dev->workqueue, &priv->work, - msecs_to_jiffies(P54_TX_TIMEOUT)); - - if (unlikely(left == 32)) { - /* - * The tx_queue is now really full. - * - * TODO: check if the device has crashed and reset it. - */ - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - return -ENOSPC; - } - } - - entry = priv->tx_queue.next; - while (left--) { - u32 hole_size; - info = IEEE80211_SKB_CB(entry); - range = (void *)info->rate_driver_data; - hole_size = range->start_addr - last_addr; - if (!target_skb && hole_size >= len) { - target_skb = entry->prev; - hole_size -= len; - target_addr = last_addr; - } - largest_hole = max(largest_hole, hole_size); - last_addr = range->end_addr; - entry = entry->next; - } - if (!target_skb && priv->rx_end - last_addr >= len) { - target_skb = priv->tx_queue.prev; - largest_hole = max(largest_hole, priv->rx_end - last_addr - len); - if (!skb_queue_empty(&priv->tx_queue)) { - info = IEEE80211_SKB_CB(target_skb); - range = (void *)info->rate_driver_data; - target_addr = range->end_addr; - } - } else - largest_hole = max(largest_hole, priv->rx_end - last_addr); - - if (!target_skb) { - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - ieee80211_stop_queues(dev); - return -ENOSPC; - } - - info = IEEE80211_SKB_CB(skb); - range = (void *)info->rate_driver_data; - range->start_addr = target_addr; - range->end_addr = target_addr + len; - __skb_queue_after(&priv->tx_queue, target_skb, skb); - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - - if (largest_hole < priv->headroom + sizeof(struct p54_hdr) + - 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) - ieee80211_stop_queues(dev); - - data->req_id = cpu_to_le32(target_addr + priv->headroom); - return 0; -} - -static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, u16 hdr_flags, - u16 payload_len, u16 type, gfp_t memflags) -{ - struct p54_common *priv = dev->priv; - struct p54_hdr *hdr; - struct sk_buff *skb; - size_t frame_len = sizeof(*hdr) + payload_len; - - if (frame_len > P54_MAX_CTRL_FRAME_LEN) - return NULL; - - skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags); - if (!skb) - return NULL; - skb_reserve(skb, priv->tx_hdr_len); - - hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr)); - hdr->flags = cpu_to_le16(hdr_flags); - hdr->len = cpu_to_le16(payload_len); - hdr->type = cpu_to_le16(type); - hdr->tries = hdr->rts_tries = 0; - - if (p54_assign_address(dev, skb, hdr, frame_len)) { - kfree_skb(skb); - return NULL; - } - return skb; -} - -int p54_read_eeprom(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct p54_eeprom_lm86 *eeprom_hdr; - struct sk_buff *skb; - size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; - int ret = -ENOMEM; - void *eeprom = NULL; - - maxblocksize = EEPROM_READBACK_LEN; - if (priv->fw_var >= 0x509) - maxblocksize -= 0xc; - else - maxblocksize -= 0x4; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*eeprom_hdr) + - maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK, - GFP_KERNEL); - if (!skb) - goto free; - priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL); - if (!priv->eeprom) - goto free; - eeprom = kzalloc(eeprom_size, GFP_KERNEL); - if (!eeprom) - goto free; - - eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, - sizeof(*eeprom_hdr) + maxblocksize); - - while (eeprom_size) { - blocksize = min(eeprom_size, maxblocksize); - if (priv->fw_var < 0x509) { - eeprom_hdr->v1.offset = cpu_to_le16(offset); - eeprom_hdr->v1.len = cpu_to_le16(blocksize); - } else { - eeprom_hdr->v2.offset = cpu_to_le32(offset); - eeprom_hdr->v2.len = cpu_to_le16(blocksize); - eeprom_hdr->v2.magic2 = 0xf; - memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); - } - priv->tx(dev, skb); - - if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { - printk(KERN_ERR "%s: device does not respond!\n", - wiphy_name(dev->wiphy)); - ret = -EBUSY; - goto free; - } - - memcpy(eeprom + offset, priv->eeprom, blocksize); - offset += blocksize; - eeprom_size -= blocksize; - } - - ret = p54_parse_eeprom(dev, eeprom, offset); -free: - kfree(priv->eeprom); - priv->eeprom = NULL; - p54_free_skb(dev, skb); - kfree(eeprom); - - return ret; -} -EXPORT_SYMBOL_GPL(p54_read_eeprom); - -static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, - bool set) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_tim *tim; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim), - P54_CONTROL_TYPE_TIM, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); - tim->count = 1; - tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid); - priv->tx(dev, skb); - return 0; -} - -static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_sta_unlock *sta; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta), - P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); - memcpy(sta->addr, addr, ETH_ALEN); - priv->tx(dev, skb); - return 0; -} - -static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, - enum sta_notify_cmd notify_cmd, - struct ieee80211_sta *sta) -{ - switch (notify_cmd) { - case STA_NOTIFY_ADD: - case STA_NOTIFY_REMOVE: - /* - * Notify the firmware that we don't want or we don't - * need to buffer frames for this station anymore. - */ - - p54_sta_unlock(dev, sta->addr); - break; - case STA_NOTIFY_AWAKE: - /* update the firmware's filter table */ - p54_sta_unlock(dev, sta->addr); - break; - default: - break; - } -} - -static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_hdr *hdr; - struct p54_txcancel *cancel; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel), - P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - hdr = (void *)entry->data; - cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); - cancel->req_id = hdr->req_id; - priv->tx(dev, skb); - return 0; -} - -static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len, - u16 *flags, u16 *aid) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct p54_common *priv = dev->priv; - int ret = 1; - - switch (priv->mode) { - case NL80211_IFTYPE_MONITOR: - /* - * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for - * every frame in promiscuous/monitor mode. - * see STSW45x0C LMAC API - page 12. - */ - *aid = 0; - *flags = P54_HDR_FLAG_DATA_OUT_PROMISC; - *queue += P54_QUEUE_DATA; - break; - case NL80211_IFTYPE_STATION: - *aid = 1; - if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) { - *queue = P54_QUEUE_MGMT; - ret = 0; - } else - *queue += P54_QUEUE_DATA; - break; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { - *aid = 0; - *queue = P54_QUEUE_CAB; - return 0; - } - - if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) { - if (ieee80211_is_probe_resp(hdr->frame_control)) { - *aid = 0; - *queue = P54_QUEUE_MGMT; - *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP | - P54_HDR_FLAG_DATA_OUT_NOCANCEL; - return 0; - } else if (ieee80211_is_beacon(hdr->frame_control)) { - *aid = 0; - - if (info->flags & IEEE80211_TX_CTL_INJECTED) { - /* - * Injecting beacons on top of a AP is - * not a good idea... nevertheless, - * it should be doable. - */ - - *queue += P54_QUEUE_DATA; - return 1; - } - - *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP; - *queue = P54_QUEUE_BEACON; - *extra_len = IEEE80211_MAX_TIM_LEN; - return 0; - } else { - *queue = P54_QUEUE_MGMT; - ret = 0; - } - } else - *queue += P54_QUEUE_DATA; - - if (info->control.sta) - *aid = info->control.sta->aid; - - if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) - *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; - break; - } - return ret; -} - -static u8 p54_convert_algo(enum ieee80211_key_alg alg) -{ - switch (alg) { - case ALG_WEP: - return P54_CRYPTO_WEP; - case ALG_TKIP: - return P54_CRYPTO_TKIPMICHAEL; - case ALG_CCMP: - return P54_CRYPTO_AESCCMP; - default: - return 0; - } -} - -static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_queue_stats *current_queue; - struct p54_common *priv = dev->priv; - struct p54_hdr *hdr; - struct p54_tx_data *txhdr; - size_t padding, len, tim_len = 0; - int i, j, ridx, ret; - u16 hdr_flags = 0, aid = 0; - u8 rate, queue, crypt_offset = 0; - u8 cts_rate = 0x20; - u8 rc_flags; - u8 calculated_tries[4]; - u8 nrates = 0, nremaining = 8; - - queue = skb_get_queue_mapping(skb); - - ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid); - current_queue = &priv->tx_stats[queue]; - if (unlikely((current_queue->len > current_queue->limit) && ret)) - return NETDEV_TX_BUSY; - current_queue->len++; - current_queue->count++; - if ((current_queue->len == current_queue->limit) && ret) - ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); - - padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; - len = skb->len; - - if (info->control.hw_key) { - crypt_offset = ieee80211_get_hdrlen_from_skb(skb); - if (info->control.hw_key->alg == ALG_TKIP) { - u8 *iv = (u8 *)(skb->data + crypt_offset); - /* - * The firmware excepts that the IV has to have - * this special format - */ - iv[1] = iv[0]; - iv[0] = iv[2]; - iv[2] = 0; - } - } - - txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); - hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); - - if (padding) - hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; - hdr->type = cpu_to_le16(aid); - hdr->rts_tries = info->control.rates[0].count; - - /* - * we register the rates in perfect order, and - * RTS/CTS won't happen on 5 GHz - */ - cts_rate = info->control.rts_cts_rate_idx; - - memset(&txhdr->rateset, 0, sizeof(txhdr->rateset)); - - /* see how many rates got used */ - for (i = 0; i < 4; i++) { - if (info->control.rates[i].idx < 0) - break; - nrates++; - } - - /* limit tries to 8/nrates per rate */ - for (i = 0; i < nrates; i++) { - /* - * The magic expression here is equivalent to 8/nrates for - * all values that matter, but avoids division and jumps. - * Note that nrates can only take the values 1 through 4. - */ - calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1, - info->control.rates[i].count); - nremaining -= calculated_tries[i]; - } - - /* if there are tries left, distribute from back to front */ - for (i = nrates - 1; nremaining > 0 && i >= 0; i--) { - int tmp = info->control.rates[i].count - calculated_tries[i]; - - if (tmp <= 0) - continue; - /* RC requested more tries at this rate */ - - tmp = min_t(int, tmp, nremaining); - calculated_tries[i] += tmp; - nremaining -= tmp; - } - - ridx = 0; - for (i = 0; i < nrates && ridx < 8; i++) { - /* we register the rates in perfect order */ - rate = info->control.rates[i].idx; - if (info->band == IEEE80211_BAND_5GHZ) - rate += 4; - - /* store the count we actually calculated for TX status */ - info->control.rates[i].count = calculated_tries[i]; - - rc_flags = info->control.rates[i].flags; - if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { - rate |= 0x10; - cts_rate |= 0x10; - } - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) - rate |= 0x40; - else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) - rate |= 0x20; - for (j = 0; j < calculated_tries[i] && ridx < 8; j++) { - txhdr->rateset[ridx] = rate; - ridx++; - } - } - - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) - hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; - - /* TODO: enable bursting */ - hdr->flags = cpu_to_le16(hdr_flags); - hdr->tries = ridx; - txhdr->rts_rate_idx = 0; - if (info->control.hw_key) { - txhdr->key_type = p54_convert_algo(info->control.hw_key->alg); - txhdr->key_len = min((u8)16, info->control.hw_key->keylen); - memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len); - if (info->control.hw_key->alg == ALG_TKIP) { - if (unlikely(skb_tailroom(skb) < 12)) - goto err; - /* reserve space for the MIC key */ - len += 8; - memcpy(skb_put(skb, 8), &(info->control.hw_key->key - [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8); - } - /* reserve some space for ICV */ - len += info->control.hw_key->icv_len; - memset(skb_put(skb, info->control.hw_key->icv_len), 0, - info->control.hw_key->icv_len); - } else { - txhdr->key_type = 0; - txhdr->key_len = 0; - } - txhdr->crypt_offset = crypt_offset; - txhdr->hw_queue = queue; - txhdr->backlog = current_queue->len; - memset(txhdr->durations, 0, sizeof(txhdr->durations)); - txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ? - 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask; - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - txhdr->longbow.cts_rate = cts_rate; - txhdr->longbow.output_power = cpu_to_le16(priv->output_power); - } else { - txhdr->normal.output_power = priv->output_power; - txhdr->normal.cts_rate = cts_rate; - } - if (padding) - txhdr->align[0] = padding; - - hdr->len = cpu_to_le16(len); - /* modifies skb->cb and with it info, so must be last! */ - if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) - goto err; - priv->tx(dev, skb); - - queue_delayed_work(dev->workqueue, &priv->work, - msecs_to_jiffies(P54_TX_FRAME_LIFETIME)); - - return NETDEV_TX_OK; - - err: - skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); - current_queue->len--; - current_queue->count--; - return NETDEV_TX_BUSY; -} - -static int p54_setup_mac(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_setup_mac *setup; - u16 mode; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup), - P54_CONTROL_TYPE_SETUP, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); - if (dev->conf.radio_enabled) { - switch (priv->mode) { - case NL80211_IFTYPE_STATION: - mode = P54_FILTER_TYPE_STATION; - break; - case NL80211_IFTYPE_AP: - mode = P54_FILTER_TYPE_AP; - break; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - mode = P54_FILTER_TYPE_IBSS; - break; - case NL80211_IFTYPE_MONITOR: - mode = P54_FILTER_TYPE_PROMISCUOUS; - break; - default: - mode = P54_FILTER_TYPE_HIBERNATE; - break; - } - - /* - * "TRANSPARENT and PROMISCUOUS are mutually exclusive" - * STSW45X0C LMAC API - page 12 - */ - if (((priv->filter_flags & FIF_PROMISC_IN_BSS) || - (priv->filter_flags & FIF_OTHER_BSS)) && - (mode != P54_FILTER_TYPE_PROMISCUOUS)) - mode |= P54_FILTER_TYPE_TRANSPARENT; - } else - mode = P54_FILTER_TYPE_HIBERNATE; - - setup->mac_mode = cpu_to_le16(mode); - memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); - memcpy(setup->bssid, priv->bssid, ETH_ALEN); - setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */ - setup->rx_align = 0; - if (priv->fw_var < 0x500) { - setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); - memset(setup->v1.rts_rates, 0, 8); - setup->v1.rx_addr = cpu_to_le32(priv->rx_end); - setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); - setup->v1.rxhw = cpu_to_le16(priv->rxhw); - setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer); - setup->v1.unalloc0 = cpu_to_le16(0); - } else { - setup->v2.rx_addr = cpu_to_le32(priv->rx_end); - setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); - setup->v2.rxhw = cpu_to_le16(priv->rxhw); - setup->v2.timer = cpu_to_le16(priv->wakeup_timer); - setup->v2.truncate = cpu_to_le16(48896); - setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); - setup->v2.sbss_offset = 0; - setup->v2.mcast_window = 0; - setup->v2.rx_rssi_threshold = 0; - setup->v2.rx_ed_threshold = 0; - setup->v2.ref_clock = cpu_to_le32(644245094); - setup->v2.lpf_bandwidth = cpu_to_le16(65535); - setup->v2.osc_start_delay = cpu_to_le16(65535); - } - priv->tx(dev, skb); - return 0; -} - -static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_hdr *hdr; - struct p54_scan_head *head; - struct p54_iq_autocal_entry *iq_autocal; - union p54_scan_body_union *body; - struct p54_scan_tail_rate *rate; - struct pda_rssi_cal_entry *rssi; - unsigned int i; - void *entry; - int band = dev->conf.channel->band; - __le16 freq = cpu_to_le16(dev->conf.channel->center_freq); - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) + - 2 + sizeof(*iq_autocal) + sizeof(*body) + - sizeof(*rate) + 2 * sizeof(*rssi), - P54_CONTROL_TYPE_SCAN, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - head = (struct p54_scan_head *) skb_put(skb, sizeof(*head)); - memset(head->scan_params, 0, sizeof(head->scan_params)); - head->mode = cpu_to_le16(mode); - head->dwell = cpu_to_le16(dwell); - head->freq = freq; - - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - __le16 *pa_power_points = (__le16 *) skb_put(skb, 2); - *pa_power_points = cpu_to_le16(0x0c); - } - - iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal)); - for (i = 0; i < priv->iq_autocal_len; i++) { - if (priv->iq_autocal[i].freq != freq) - continue; - - memcpy(iq_autocal, &priv->iq_autocal[i].params, - sizeof(struct p54_iq_autocal_entry)); - break; - } - if (i == priv->iq_autocal_len) - goto err; - - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) - body = (void *) skb_put(skb, sizeof(body->longbow)); - else - body = (void *) skb_put(skb, sizeof(body->normal)); - - for (i = 0; i < priv->output_limit->entries; i++) { - __le16 *entry_freq = (void *) (priv->output_limit->data + - priv->output_limit->entry_size * i); - - if (*entry_freq != freq) - continue; - - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - memcpy(&body->longbow.power_limits, - (void *) entry_freq + sizeof(__le16), - priv->output_limit->entry_size); - } else { - struct pda_channel_output_limit *limits = - (void *) entry_freq; - - body->normal.val_barker = 0x38; - body->normal.val_bpsk = body->normal.dup_bpsk = - limits->val_bpsk; - body->normal.val_qpsk = body->normal.dup_qpsk = - limits->val_qpsk; - body->normal.val_16qam = body->normal.dup_16qam = - limits->val_16qam; - body->normal.val_64qam = body->normal.dup_64qam = - limits->val_64qam; - } - break; - } - if (i == priv->output_limit->entries) - goto err; - - entry = (void *)(priv->curve_data->data + priv->curve_data->offset); - for (i = 0; i < priv->curve_data->entries; i++) { - if (*((__le16 *)entry) != freq) { - entry += priv->curve_data->entry_size; - continue; - } - - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - memcpy(&body->longbow.curve_data, - (void *) entry + sizeof(__le16), - priv->curve_data->entry_size); - } else { - struct p54_scan_body *chan = &body->normal; - struct pda_pa_curve_data *curve_data = - (void *) priv->curve_data->data; - - entry += sizeof(__le16); - chan->pa_points_per_curve = 8; - memset(chan->curve_data, 0, sizeof(*chan->curve_data)); - memcpy(chan->curve_data, entry, - sizeof(struct p54_pa_curve_data_sample) * - min((u8)8, curve_data->points_per_channel)); - } - break; - } - if (i == priv->curve_data->entries) - goto err; - - if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) { - rate = (void *) skb_put(skb, sizeof(*rate)); - rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); - for (i = 0; i < sizeof(rate->rts_rates); i++) - rate->rts_rates[i] = i; - } - - rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi)); - rssi->mul = cpu_to_le16(priv->rssical_db[band].mul); - rssi->add = cpu_to_le16(priv->rssical_db[band].add); - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - /* Longbow frontend needs ever more */ - rssi = (void *) skb_put(skb, sizeof(*rssi)); - rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn); - rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2); - } - - if (priv->fw_var >= 0x509) { - rate = (void *) skb_put(skb, sizeof(*rate)); - rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); - for (i = 0; i < sizeof(rate->rts_rates); i++) - rate->rts_rates[i] = i; - } - - hdr = (struct p54_hdr *) skb->data; - hdr->len = cpu_to_le16(skb->len - sizeof(*hdr)); - - priv->tx(dev, skb); - return 0; - - err: - printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy)); - p54_free_skb(dev, skb); - return -EINVAL; -} - -static int p54_set_leds(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_led *led; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led), - P54_CONTROL_TYPE_LED, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - led = (struct p54_led *) skb_put(skb, sizeof(*led)); - led->flags = cpu_to_le16(0x0003); - led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state); - led->delay[0] = cpu_to_le16(1); - led->delay[1] = cpu_to_le16(0); - priv->tx(dev, skb); - return 0; -} - -#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \ -do { \ - queue.aifs = cpu_to_le16(ai_fs); \ - queue.cwmin = cpu_to_le16(cw_min); \ - queue.cwmax = cpu_to_le16(cw_max); \ - queue.txop = cpu_to_le16(_txop); \ -} while(0) - -static int p54_set_edcf(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_edcf *edcf; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf), - P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); - if (priv->use_short_slot) { - edcf->slottime = 9; - edcf->sifs = 0x10; - edcf->eofpad = 0x00; - } else { - edcf->slottime = 20; - edcf->sifs = 0x0a; - edcf->eofpad = 0x06; - } - /* (see prism54/isl_oid.h for further details) */ - edcf->frameburst = cpu_to_le16(0); - edcf->round_trip_delay = cpu_to_le16(0); - edcf->flags = 0; - memset(edcf->mapping, 0, sizeof(edcf->mapping)); - memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); - priv->tx(dev, skb); - return 0; -} - -static int p54_set_ps(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_psm *psm; - u16 mode; - int i; - - if (dev->conf.flags & IEEE80211_CONF_PS) - mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM | - P54_PSM_CHECKSUM | P54_PSM_MCBC; - else - mode = P54_PSM_CAM; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm), - P54_CONTROL_TYPE_PSM, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - psm = (struct p54_psm *)skb_put(skb, sizeof(*psm)); - psm->mode = cpu_to_le16(mode); - psm->aid = cpu_to_le16(priv->aid); - for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) { - psm->intervals[i].interval = - cpu_to_le16(dev->conf.listen_interval); - psm->intervals[i].periods = cpu_to_le16(1); - } - - psm->beacon_rssi_skip_max = 200; - psm->rssi_delta_threshold = 0; - psm->nr = 10; - psm->exclude[0] = 0; - - priv->tx(dev, skb); - - return 0; -} - -static int p54_beacon_tim(struct sk_buff *skb) -{ - /* - * the good excuse for this mess is ... the firmware. - * The dummy TIM MUST be at the end of the beacon frame, - * because it'll be overwritten! - */ - - struct ieee80211_mgmt *mgmt = (void *)skb->data; - u8 *pos, *end; - - if (skb->len <= sizeof(mgmt)) - return -EINVAL; - - pos = (u8 *)mgmt->u.beacon.variable; - end = skb->data + skb->len; - while (pos < end) { - if (pos + 2 + pos[1] > end) - return -EINVAL; - - if (pos[0] == WLAN_EID_TIM) { - u8 dtim_len = pos[1]; - u8 dtim_period = pos[3]; - u8 *next = pos + 2 + dtim_len; - - if (dtim_len < 3) - return -EINVAL; - - memmove(pos, next, end - next); - - if (dtim_len > 3) - skb_trim(skb, skb->len - (dtim_len - 3)); - - pos = end - (dtim_len + 2); - - /* add the dummy at the end */ - pos[0] = WLAN_EID_TIM; - pos[1] = 3; - pos[2] = 0; - pos[3] = dtim_period; - pos[4] = 0; - return 0; - } - pos += 2 + pos[1]; - } - return 0; -} - -static int p54_beacon_update(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *beacon; - int ret; - - if (priv->cached_beacon) { - p54_tx_cancel(dev, priv->cached_beacon); - /* wait for the last beacon the be freed */ - msleep(10); - } - - beacon = ieee80211_beacon_get(dev, vif); - if (!beacon) - return -ENOMEM; - ret = p54_beacon_tim(beacon); - if (ret) - return ret; - ret = p54_tx(dev, beacon); - if (ret) - return ret; - priv->cached_beacon = beacon; - priv->tsf_high32 = 0; - priv->tsf_low32 = 0; - - return 0; -} - -static int p54_start(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - int err; - - mutex_lock(&priv->conf_mutex); - err = priv->open(dev); - if (err) - goto out; - P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47); - P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94); - P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); - P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); - err = p54_set_edcf(dev); - if (err) - goto out; - - memset(priv->bssid, ~0, ETH_ALEN); - priv->mode = NL80211_IFTYPE_MONITOR; - err = p54_setup_mac(dev); - if (err) { - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - goto out; - } - - queue_delayed_work(dev->workqueue, &priv->work, 0); - - priv->softled_state = 0; - err = p54_set_leds(dev); - -out: - mutex_unlock(&priv->conf_mutex); - return err; -} - -static void p54_stop(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - - mutex_lock(&priv->conf_mutex); - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - priv->softled_state = 0; - p54_set_leds(dev); - -#ifdef CONFIG_P54_LEDS - cancel_delayed_work_sync(&priv->led_work); -#endif /* CONFIG_P54_LEDS */ - cancel_delayed_work_sync(&priv->work); - if (priv->cached_beacon) - p54_tx_cancel(dev, priv->cached_beacon); - - priv->stop(dev); - while ((skb = skb_dequeue(&priv->tx_queue))) - kfree_skb(skb); - priv->cached_beacon = NULL; - priv->tsf_high32 = priv->tsf_low32 = 0; - mutex_unlock(&priv->conf_mutex); -} - -static int p54_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct p54_common *priv = dev->priv; - - mutex_lock(&priv->conf_mutex); - if (priv->mode != NL80211_IFTYPE_MONITOR) { - mutex_unlock(&priv->conf_mutex); - return -EOPNOTSUPP; - } - - priv->vif = conf->vif; - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_MESH_POINT: - priv->mode = conf->type; - break; - default: - mutex_unlock(&priv->conf_mutex); - return -EOPNOTSUPP; - } - - memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - p54_setup_mac(dev); - mutex_unlock(&priv->conf_mutex); - return 0; -} - -static void p54_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct p54_common *priv = dev->priv; - - mutex_lock(&priv->conf_mutex); - priv->vif = NULL; - if (priv->cached_beacon) - p54_tx_cancel(dev, priv->cached_beacon); - priv->mode = NL80211_IFTYPE_MONITOR; - memset(priv->mac_addr, 0, ETH_ALEN); - memset(priv->bssid, 0, ETH_ALEN); - p54_setup_mac(dev); - mutex_unlock(&priv->conf_mutex); -} - -static int p54_config(struct ieee80211_hw *dev, u32 changed) -{ - int ret = 0; - struct p54_common *priv = dev->priv; - struct ieee80211_conf *conf = &dev->conf; - - mutex_lock(&priv->conf_mutex); - if (changed & IEEE80211_CONF_CHANGE_POWER) - priv->output_power = conf->power_level << 2; - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - ret = p54_setup_mac(dev); - if (ret) - goto out; - } - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ret = p54_scan(dev, P54_SCAN_EXIT, 0); - if (ret) - goto out; - } - if (changed & IEEE80211_CONF_CHANGE_PS) { - ret = p54_set_ps(dev); - if (ret) - goto out; - } - -out: - mutex_unlock(&priv->conf_mutex); - return ret; -} - -static void p54_configure_filter(struct ieee80211_hw *dev, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_mc_list *mclist) -{ - struct p54_common *priv = dev->priv; - - *total_flags &= FIF_PROMISC_IN_BSS | - FIF_OTHER_BSS; - - priv->filter_flags = *total_flags; - - if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) - p54_setup_mac(dev); -} - -static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct p54_common *priv = dev->priv; - int ret; - - mutex_lock(&priv->conf_mutex); - if ((params) && !(queue > 4)) { - P54_SET_QUEUE(priv->qos_params[queue], params->aifs, - params->cw_min, params->cw_max, params->txop); - ret = p54_set_edcf(dev); - } else - ret = -EINVAL; - mutex_unlock(&priv->conf_mutex); - return ret; -} - -static int p54_init_xbow_synth(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_xbow_synth *xbow; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow), - P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL); - if (!skb) - return -ENOMEM; - - xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow)); - xbow->magic1 = cpu_to_le16(0x1); - xbow->magic2 = cpu_to_le16(0x2); - xbow->freq = cpu_to_le16(5390); - memset(xbow->padding, 0, sizeof(xbow->padding)); - priv->tx(dev, skb); - return 0; -} - -static void p54_work(struct work_struct *work) -{ - struct p54_common *priv = container_of(work, struct p54_common, - work.work); - struct ieee80211_hw *dev = priv->hw; - struct sk_buff *skb; - - if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) - return ; - - /* - * TODO: walk through tx_queue and do the following tasks - * 1. initiate bursts. - * 2. cancel stuck frames / reset the device if necessary. - */ - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, - sizeof(struct p54_statistics), - P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); - if (!skb) - return ; - - priv->tx(dev, skb); -} - -static int p54_get_stats(struct ieee80211_hw *dev, - struct ieee80211_low_level_stats *stats) -{ - struct p54_common *priv = dev->priv; - - memcpy(stats, &priv->stats, sizeof(*stats)); - return 0; -} - -static int p54_get_tx_stats(struct ieee80211_hw *dev, - struct ieee80211_tx_queue_stats *stats) -{ - struct p54_common *priv = dev->priv; - - memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA], - sizeof(stats[0]) * dev->queues); - return 0; -} - -static void p54_bss_info_changed(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u32 changed) -{ - struct p54_common *priv = dev->priv; - int ret; - - mutex_lock(&priv->conf_mutex); - if (changed & BSS_CHANGED_BSSID) { - memcpy(priv->bssid, info->bssid, ETH_ALEN); - ret = p54_setup_mac(dev); - if (ret) - goto out; - } - - if (changed & BSS_CHANGED_BEACON) { - ret = p54_scan(dev, P54_SCAN_EXIT, 0); - if (ret) - goto out; - ret = p54_setup_mac(dev); - if (ret) - goto out; - ret = p54_beacon_update(dev, vif); - if (ret) - goto out; - } - /* XXX: this mimics having two callbacks... clean up */ - out: - mutex_unlock(&priv->conf_mutex); - - if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) { - priv->use_short_slot = info->use_short_slot; - p54_set_edcf(dev); - } - if (changed & BSS_CHANGED_BASIC_RATES) { - if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) - priv->basic_rate_mask = (info->basic_rates << 4); - else - priv->basic_rate_mask = info->basic_rates; - p54_setup_mac(dev); - if (priv->fw_var >= 0x500) - p54_scan(dev, P54_SCAN_EXIT, 0); - } - if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc) { - priv->aid = info->aid; - priv->wakeup_timer = info->beacon_int * - info->dtim_period * 5; - p54_setup_mac(dev); - } - } -} - -static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_keycache *rxkey; - int slot, ret = 0; - u8 algo = 0; - - if (modparam_nohwcrypt) - return -EOPNOTSUPP; - - mutex_lock(&priv->conf_mutex); - if (cmd == SET_KEY) { - switch (key->alg) { - case ALG_TKIP: - if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | - BR_DESC_PRIV_CAP_TKIP))) { - ret = -EOPNOTSUPP; - goto out_unlock; - } - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - algo = P54_CRYPTO_TKIPMICHAEL; - break; - case ALG_WEP: - if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) { - ret = -EOPNOTSUPP; - goto out_unlock; - } - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - algo = P54_CRYPTO_WEP; - break; - case ALG_CCMP: - if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) { - ret = -EOPNOTSUPP; - goto out_unlock; - } - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - algo = P54_CRYPTO_AESCCMP; - break; - default: - ret = -EOPNOTSUPP; - goto out_unlock; - } - slot = bitmap_find_free_region(priv->used_rxkeys, - priv->rx_keycache_size, 0); - - if (slot < 0) { - /* - * The device supports the choosen algorithm, but the - * firmware does not provide enough key slots to store - * all of them. - * But encryption offload for outgoing frames is always - * possible, so we just pretend that the upload was - * successful and do the decryption in software. - */ - - /* mark the key as invalid. */ - key->hw_key_idx = 0xff; - goto out_unlock; - } - } else { - slot = key->hw_key_idx; - - if (slot == 0xff) { - /* This key was not uploaded into the rx key cache. */ - - goto out_unlock; - } - - bitmap_release_region(priv->used_rxkeys, slot, 0); - algo = 0; - } - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey), - P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL); - if (!skb) { - bitmap_release_region(priv->used_rxkeys, slot, 0); - ret = -ENOSPC; - goto out_unlock; - } - - rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); - rxkey->entry = slot; - rxkey->key_id = key->keyidx; - rxkey->key_type = algo; - if (sta) - memcpy(rxkey->mac, sta->addr, ETH_ALEN); - else - memset(rxkey->mac, ~0, ETH_ALEN); - if (key->alg != ALG_TKIP) { - rxkey->key_len = min((u8)16, key->keylen); - memcpy(rxkey->key, key->key, rxkey->key_len); - } else { - rxkey->key_len = 24; - memcpy(rxkey->key, key->key, 16); - memcpy(&(rxkey->key[16]), &(key->key - [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); - } - - priv->tx(dev, skb); - key->hw_key_idx = slot; - -out_unlock: - mutex_unlock(&priv->conf_mutex); - return ret; -} - -#ifdef CONFIG_P54_LEDS -static void p54_update_leds(struct work_struct *work) -{ - struct p54_common *priv = container_of(work, struct p54_common, - led_work.work); - int err, i, tmp, blink_delay = 400; - bool rerun = false; - - /* Don't toggle the LED, when the device is down. */ - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) - return ; - - for (i = 0; i < ARRAY_SIZE(priv->leds); i++) - if (priv->leds[i].toggled) { - priv->softled_state |= BIT(i); - - tmp = 70 + 200 / (priv->leds[i].toggled); - if (tmp < blink_delay) - blink_delay = tmp; - - if (priv->leds[i].led_dev.brightness == LED_OFF) - rerun = true; - - priv->leds[i].toggled = - !!priv->leds[i].led_dev.brightness; - } else - priv->softled_state &= ~BIT(i); - - err = p54_set_leds(priv->hw); - if (err && net_ratelimit()) - printk(KERN_ERR "%s: failed to update LEDs.\n", - wiphy_name(priv->hw->wiphy)); - - if (rerun) - queue_delayed_work(priv->hw->workqueue, &priv->led_work, - msecs_to_jiffies(blink_delay)); -} - -static void p54_led_brightness_set(struct led_classdev *led_dev, - enum led_brightness brightness) -{ - struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev, - led_dev); - struct ieee80211_hw *dev = led->hw_dev; - struct p54_common *priv = dev->priv; - - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) - return ; - - if (brightness) { - led->toggled++; - queue_delayed_work(priv->hw->workqueue, &priv->led_work, - HZ/10); - } -} - -static int p54_register_led(struct ieee80211_hw *dev, - unsigned int led_index, - char *name, char *trigger) -{ - struct p54_common *priv = dev->priv; - struct p54_led_dev *led = &priv->leds[led_index]; - int err; - - if (led->registered) - return -EEXIST; - - snprintf(led->name, sizeof(led->name), "p54-%s::%s", - wiphy_name(dev->wiphy), name); - led->hw_dev = dev; - led->index = led_index; - led->led_dev.name = led->name; - led->led_dev.default_trigger = trigger; - led->led_dev.brightness_set = p54_led_brightness_set; - - err = led_classdev_register(wiphy_dev(dev->wiphy), &led->led_dev); - if (err) - printk(KERN_ERR "%s: Failed to register %s LED.\n", - wiphy_name(dev->wiphy), name); - else - led->registered = 1; - - return err; -} - -static int p54_init_leds(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - int err; - - /* - * TODO: - * Figure out if the EEPROM contains some hints about the number - * of available/programmable LEDs of the device. - */ - - INIT_DELAYED_WORK(&priv->led_work, p54_update_leds); - - err = p54_register_led(dev, 0, "assoc", - ieee80211_get_assoc_led_name(dev)); - if (err) - return err; - - err = p54_register_led(dev, 1, "tx", - ieee80211_get_tx_led_name(dev)); - if (err) - return err; - - err = p54_register_led(dev, 2, "rx", - ieee80211_get_rx_led_name(dev)); - if (err) - return err; - - err = p54_register_led(dev, 3, "radio", - ieee80211_get_radio_led_name(dev)); - if (err) - return err; - - err = p54_set_leds(dev); - return err; -} - -static void p54_unregister_leds(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - int i; - - for (i = 0; i < ARRAY_SIZE(priv->leds); i++) - if (priv->leds[i].registered) - led_classdev_unregister(&priv->leds[i].led_dev); -} -#endif /* CONFIG_P54_LEDS */ - -static const struct ieee80211_ops p54_ops = { - .tx = p54_tx, - .start = p54_start, - .stop = p54_stop, - .add_interface = p54_add_interface, - .remove_interface = p54_remove_interface, - .set_tim = p54_set_tim, - .sta_notify = p54_sta_notify, - .set_key = p54_set_key, - .config = p54_config, - .bss_info_changed = p54_bss_info_changed, - .configure_filter = p54_configure_filter, - .conf_tx = p54_conf_tx, - .get_stats = p54_get_stats, - .get_tx_stats = p54_get_tx_stats -}; - -struct ieee80211_hw *p54_init_common(size_t priv_data_len) -{ - struct ieee80211_hw *dev; - struct p54_common *priv; - - dev = ieee80211_alloc_hw(priv_data_len, &p54_ops); - if (!dev) - return NULL; - - priv = dev->priv; - priv->hw = dev; - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - priv->basic_rate_mask = 0x15f; - skb_queue_head_init(&priv->tx_queue); - dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; - - dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_MESH_POINT); - - dev->channel_change_time = 1000; /* TODO: find actual value */ - priv->tx_stats[P54_QUEUE_BEACON].limit = 1; - priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1; - priv->tx_stats[P54_QUEUE_MGMT].limit = 3; - priv->tx_stats[P54_QUEUE_CAB].limit = 3; - priv->tx_stats[P54_QUEUE_DATA].limit = 5; - dev->queues = 1; - priv->noise = -94; - /* - * We support at most 8 tries no matter which rate they're at, - * we cannot support max_rates * max_rate_tries as we set it - * here, but setting it correctly to 4/2 or so would limit us - * artificially if the RC algorithm wants just two rates, so - * let's say 4/7, we'll redistribute it at TX time, see the - * comments there. - */ - dev->max_rates = 4; - dev->max_rate_tries = 7; - dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 + - sizeof(struct p54_tx_data); - - mutex_init(&priv->conf_mutex); - init_completion(&priv->eeprom_comp); - INIT_DELAYED_WORK(&priv->work, p54_work); - - return dev; -} -EXPORT_SYMBOL_GPL(p54_init_common); - -int p54_register_common(struct ieee80211_hw *dev, struct device *pdev) -{ - int err; - - err = ieee80211_register_hw(dev); - if (err) { - dev_err(pdev, "Cannot register device (%d).\n", err); - return err; - } - -#ifdef CONFIG_P54_LEDS - err = p54_init_leds(dev); - if (err) - return err; -#endif /* CONFIG_P54_LEDS */ - - dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy)); - return 0; -} -EXPORT_SYMBOL_GPL(p54_register_common); - -void p54_free_common(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - kfree(priv->iq_autocal); - kfree(priv->output_limit); - kfree(priv->curve_data); - kfree(priv->used_rxkeys); - -#ifdef CONFIG_P54_LEDS - p54_unregister_leds(dev); -#endif /* CONFIG_P54_LEDS */ -} -EXPORT_SYMBOL_GPL(p54_free_common); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h deleted file mode 100644 index 75ead7a..0000000 --- a/drivers/net/wireless/p54/p54common.h +++ /dev/null @@ -1,644 +0,0 @@ -#ifndef P54COMMON_H -#define P54COMMON_H - -/* - * Common code specific definitions for mac80211 Prism54 drivers - * - * Copyright (c) 2006, Michael Wu - * Copyright (c) 2007, Christian Lamparter - * - * Based on: - * - the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. - * - * - LMAC API interface header file for STLC4560 (lmac_longbow.h) - * Copyright (C) 2007 Conexant Systems, Inc. - * - * 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 - * published by the Free Software Foundation. - */ - -struct bootrec { - __le32 code; - __le32 len; - u32 data[10]; -} __attribute__((packed)); - -#define PDR_SYNTH_FRONTEND_MASK 0x0007 -#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001 -#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002 -#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003 -#define PDR_SYNTH_FRONTEND_XBOW 0x0004 -#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005 -#define PDR_SYNTH_IQ_CAL_MASK 0x0018 -#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000 -#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008 -#define PDR_SYNTH_IQ_CAL_ZIF 0x0010 -#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020 -#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020 -#define PDR_SYNTH_24_GHZ_MASK 0x0040 -#define PDR_SYNTH_24_GHZ_DISABLED 0x0040 -#define PDR_SYNTH_5_GHZ_MASK 0x0080 -#define PDR_SYNTH_5_GHZ_DISABLED 0x0080 -#define PDR_SYNTH_RX_DIV_MASK 0x0100 -#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100 -#define PDR_SYNTH_TX_DIV_MASK 0x0200 -#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200 - -struct bootrec_exp_if { - __le16 role; - __le16 if_id; - __le16 variant; - __le16 btm_compat; - __le16 top_compat; -} __attribute__((packed)); - -#define BR_DESC_PRIV_CAP_WEP BIT(0) -#define BR_DESC_PRIV_CAP_TKIP BIT(1) -#define BR_DESC_PRIV_CAP_MICHAEL BIT(2) -#define BR_DESC_PRIV_CAP_CCX_CP BIT(3) -#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4) -#define BR_DESC_PRIV_CAP_AESCCMP BIT(5) - -struct bootrec_desc { - __le16 modes; - __le16 flags; - __le32 rx_start; - __le32 rx_end; - u8 headroom; - u8 tailroom; - u8 tx_queues; - u8 tx_depth; - u8 privacy_caps; - u8 rx_keycache_size; - u8 time_size; - u8 padding; - u8 rates[16]; - u8 padding2[4]; - __le16 rx_mtu; -} __attribute__((packed)); - -#define BR_CODE_MIN 0x80000000 -#define BR_CODE_COMPONENT_ID 0x80000001 -#define BR_CODE_COMPONENT_VERSION 0x80000002 -#define BR_CODE_DEPENDENT_IF 0x80000003 -#define BR_CODE_EXPOSED_IF 0x80000004 -#define BR_CODE_DESCR 0x80000101 -#define BR_CODE_MAX 0x8FFFFFFF -#define BR_CODE_END_OF_BRA 0xFF0000FF -#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF - -#define P54_HDR_FLAG_DATA_ALIGN BIT(14) -#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0) -#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1) -#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2) -#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3) -#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4) -#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5) -#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6) -#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7) -#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8) -#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9) -#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10) -#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11) - -#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0) -#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1) -#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2) -#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3) -#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4) -#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5) -#define P54_HDR_FLAG_DATA_IN_DATA BIT(6) -#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7) -#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8) -#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9) - -/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ - -struct pda_entry { - __le16 len; /* includes both code and data */ - __le16 code; - u8 data[0]; -} __attribute__ ((packed)); - -struct eeprom_pda_wrap { - __le32 magic; - __le16 pad; - __le16 len; - __le32 arm_opcode; - u8 data[0]; -} __attribute__ ((packed)); - -struct p54_iq_autocal_entry { - __le16 iq_param[4]; -} __attribute__ ((packed)); - -struct pda_iq_autocal_entry { - __le16 freq; - struct p54_iq_autocal_entry params; -} __attribute__ ((packed)); - -struct pda_channel_output_limit { - __le16 freq; - u8 val_bpsk; - u8 val_qpsk; - u8 val_16qam; - u8 val_64qam; - u8 rate_set_mask; - u8 rate_set_size; -} __attribute__ ((packed)); - -struct pda_pa_curve_data_sample_rev0 { - u8 rf_power; - u8 pa_detector; - u8 pcv; -} __attribute__ ((packed)); - -struct pda_pa_curve_data_sample_rev1 { - u8 rf_power; - u8 pa_detector; - u8 data_barker; - u8 data_bpsk; - u8 data_qpsk; - u8 data_16qam; - u8 data_64qam; -} __attribute__ ((packed)); - -struct p54_pa_curve_data_sample { - u8 rf_power; - u8 pa_detector; - u8 data_barker; - u8 data_bpsk; - u8 data_qpsk; - u8 data_16qam; - u8 data_64qam; - u8 padding; -} __attribute__ ((packed)); - -struct pda_pa_curve_data { - u8 cal_method_rev; - u8 channels; - u8 points_per_channel; - u8 padding; - u8 data[0]; -} __attribute__ ((packed)); - -struct pda_rssi_cal_entry { - __le16 mul; - __le16 add; -} __attribute__ ((packed)); - -struct pda_country { - u8 regdomain; - u8 alpha2[2]; - u8 flags; -} __attribute__ ((packed)); - -/* - * Warning: Longbow's structures are bogus. - */ -struct p54_channel_output_limit_longbow { - __le16 rf_power_points[12]; -} __attribute__ ((packed)); - -struct p54_pa_curve_data_sample_longbow { - __le16 rf_power; - __le16 pa_detector; - struct { - __le16 data[4]; - } points[3] __attribute__ ((packed)); -} __attribute__ ((packed)); - -struct pda_custom_wrapper { - __le16 entries; - __le16 entry_size; - __le16 offset; - __le16 len; - u8 data[0]; -} __attribute__ ((packed)); - -/* - * this defines the PDR codes used to build PDAs as defined in document - * number 553155. The current implementation mirrors version 1.1 of the - * document and lists only PDRs supported by the ARM platform. - */ - -/* common and choice range (0x0000 - 0x0fff) */ -#define PDR_END 0x0000 -#define PDR_MANUFACTURING_PART_NUMBER 0x0001 -#define PDR_PDA_VERSION 0x0002 -#define PDR_NIC_SERIAL_NUMBER 0x0003 - -#define PDR_MAC_ADDRESS 0x0101 -#define PDR_REGULATORY_DOMAIN_LIST 0x0103 -#define PDR_TEMPERATURE_TYPE 0x0107 - -#define PDR_PRISM_PCI_IDENTIFIER 0x0402 - -/* ARM range (0x1000 - 0x1fff) */ -#define PDR_COUNTRY_INFORMATION 0x1000 -#define PDR_INTERFACE_LIST 0x1001 -#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002 -#define PDR_OEM_NAME 0x1003 -#define PDR_PRODUCT_NAME 0x1004 -#define PDR_UTF8_OEM_NAME 0x1005 -#define PDR_UTF8_PRODUCT_NAME 0x1006 -#define PDR_COUNTRY_LIST 0x1007 -#define PDR_DEFAULT_COUNTRY 0x1008 - -#define PDR_ANTENNA_GAIN 0x1100 - -#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901 -#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902 -#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903 -#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904 -#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905 -#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906 -#define PDR_REGULATORY_POWER_LIMITS 0x1907 -#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908 -#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909 -#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a - -/* reserved range (0x2000 - 0x7fff) */ - -/* customer range (0x8000 - 0xffff) */ -#define PDR_BASEBAND_REGISTERS 0x8000 -#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001 - -/* used by our modificated eeprom image */ -#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD -#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF -#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D - -/* PDR definitions for default country & country list */ -#define PDR_COUNTRY_CERT_CODE 0x80 -#define PDR_COUNTRY_CERT_CODE_REAL 0x00 -#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80 -#define PDR_COUNTRY_CERT_BAND 0x40 -#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00 -#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40 -#define PDR_COUNTRY_CERT_IODOOR 0x30 -#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00 -#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20 -#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30 -#define PDR_COUNTRY_CERT_INDEX 0x0F - -struct p54_eeprom_lm86 { - union { - struct { - __le16 offset; - __le16 len; - u8 data[0]; - } v1; - struct { - __le32 offset; - __le16 len; - u8 magic2; - u8 pad; - u8 magic[4]; - u8 data[0]; - } v2; - } __attribute__ ((packed)); -} __attribute__ ((packed)); - -enum p54_rx_decrypt_status { - P54_DECRYPT_NONE = 0, - P54_DECRYPT_OK, - P54_DECRYPT_NOKEY, - P54_DECRYPT_NOMICHAEL, - P54_DECRYPT_NOCKIPMIC, - P54_DECRYPT_FAIL_WEP, - P54_DECRYPT_FAIL_TKIP, - P54_DECRYPT_FAIL_MICHAEL, - P54_DECRYPT_FAIL_CKIPKP, - P54_DECRYPT_FAIL_CKIPMIC, - P54_DECRYPT_FAIL_AESCCMP -}; - -struct p54_rx_data { - __le16 flags; - __le16 len; - __le16 freq; - u8 antenna; - u8 rate; - u8 rssi; - u8 quality; - u8 decrypt_status; - u8 rssi_raw; - __le32 tsf32; - __le32 unalloc0; - u8 align[0]; -} __attribute__ ((packed)); - -enum p54_trap_type { - P54_TRAP_SCAN = 0, - P54_TRAP_TIMER, - P54_TRAP_BEACON_TX, - P54_TRAP_FAA_RADIO_ON, - P54_TRAP_FAA_RADIO_OFF, - P54_TRAP_RADAR, - P54_TRAP_NO_BEACON, - P54_TRAP_TBTT, - P54_TRAP_SCO_ENTER, - P54_TRAP_SCO_EXIT -}; - -struct p54_trap { - __le16 event; - __le16 frequency; -} __attribute__ ((packed)); - -enum p54_frame_sent_status { - P54_TX_OK = 0, - P54_TX_FAILED, - P54_TX_PSM, - P54_TX_PSM_CANCELLED = 4 -}; - -struct p54_frame_sent { - u8 status; - u8 tries; - u8 ack_rssi; - u8 quality; - __le16 seq; - u8 antenna; - u8 padding; -} __attribute__ ((packed)); - -enum p54_tx_data_crypt { - P54_CRYPTO_NONE = 0, - P54_CRYPTO_WEP, - P54_CRYPTO_TKIP, - P54_CRYPTO_TKIPMICHAEL, - P54_CRYPTO_CCX_WEPMIC, - P54_CRYPTO_CCX_KPMIC, - P54_CRYPTO_CCX_KP, - P54_CRYPTO_AESCCMP -}; - -enum p54_tx_data_queue { - P54_QUEUE_BEACON = 0, - P54_QUEUE_FWSCAN = 1, - P54_QUEUE_MGMT = 2, - P54_QUEUE_CAB = 3, - P54_QUEUE_DATA = 4, - - P54_QUEUE_AC_NUM = 4, - P54_QUEUE_AC_VO = 4, - P54_QUEUE_AC_VI = 5, - P54_QUEUE_AC_BE = 6, - P54_QUEUE_AC_BK = 7, - - /* keep last */ - P54_QUEUE_NUM = 8, -}; - -struct p54_tx_data { - u8 rateset[8]; - u8 rts_rate_idx; - u8 crypt_offset; - u8 key_type; - u8 key_len; - u8 key[16]; - u8 hw_queue; - u8 backlog; - __le16 durations[4]; - u8 tx_antenna; - union { - struct { - u8 cts_rate; - __le16 output_power; - } __attribute__((packed)) longbow; - struct { - u8 output_power; - u8 cts_rate; - u8 unalloc; - } __attribute__ ((packed)) normal; - } __attribute__ ((packed)); - u8 unalloc2[2]; - u8 align[0]; -} __attribute__ ((packed)); - -/* unit is ms */ -#define P54_TX_FRAME_LIFETIME 2000 -#define P54_TX_TIMEOUT 4000 -#define P54_STATISTICS_UPDATE 5000 - -#define P54_FILTER_TYPE_NONE 0 -#define P54_FILTER_TYPE_STATION BIT(0) -#define P54_FILTER_TYPE_IBSS BIT(1) -#define P54_FILTER_TYPE_AP BIT(2) -#define P54_FILTER_TYPE_TRANSPARENT BIT(3) -#define P54_FILTER_TYPE_PROMISCUOUS BIT(4) -#define P54_FILTER_TYPE_HIBERNATE BIT(5) -#define P54_FILTER_TYPE_NOACK BIT(6) -#define P54_FILTER_TYPE_RX_DISABLED BIT(7) - -struct p54_setup_mac { - __le16 mac_mode; - u8 mac_addr[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - u8 rx_antenna; - u8 rx_align; - union { - struct { - __le32 basic_rate_mask; - u8 rts_rates[8]; - __le32 rx_addr; - __le16 max_rx; - __le16 rxhw; - __le16 wakeup_timer; - __le16 unalloc0; - } v1 __attribute__ ((packed)); - struct { - __le32 rx_addr; - __le16 max_rx; - __le16 rxhw; - __le16 timer; - __le16 truncate; - __le32 basic_rate_mask; - u8 sbss_offset; - u8 mcast_window; - u8 rx_rssi_threshold; - u8 rx_ed_threshold; - __le32 ref_clock; - __le16 lpf_bandwidth; - __le16 osc_start_delay; - } v2 __attribute__ ((packed)); - } __attribute__ ((packed)); -} __attribute__ ((packed)); - -#define P54_SETUP_V1_LEN 40 -#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac)) - -#define P54_SCAN_EXIT BIT(0) -#define P54_SCAN_TRAP BIT(1) -#define P54_SCAN_ACTIVE BIT(2) -#define P54_SCAN_FILTER BIT(3) - -struct p54_scan_head { - __le16 mode; - __le16 dwell; - u8 scan_params[20]; - __le16 freq; -} __attribute__ ((packed)); - -struct p54_scan_body { - u8 pa_points_per_curve; - u8 val_barker; - u8 val_bpsk; - u8 val_qpsk; - u8 val_16qam; - u8 val_64qam; - struct p54_pa_curve_data_sample curve_data[8]; - u8 dup_bpsk; - u8 dup_qpsk; - u8 dup_16qam; - u8 dup_64qam; -} __attribute__ ((packed)); - -struct p54_scan_body_longbow { - struct p54_channel_output_limit_longbow power_limits; - struct p54_pa_curve_data_sample_longbow curve_data[8]; - __le16 unkn[6]; /* maybe more power_limits or rate_mask */ -} __attribute__ ((packed)); - -union p54_scan_body_union { - struct p54_scan_body normal; - struct p54_scan_body_longbow longbow; -} __attribute__ ((packed)); - -struct p54_scan_tail_rate { - __le32 basic_rate_mask; - u8 rts_rates[8]; -} __attribute__ ((packed)); - -struct p54_led { - __le16 flags; - __le16 mask[2]; - __le16 delay[2]; -} __attribute__ ((packed)); - -struct p54_edcf { - u8 flags; - u8 slottime; - u8 sifs; - u8 eofpad; - struct p54_edcf_queue_param queue[8]; - u8 mapping[4]; - __le16 frameburst; - __le16 round_trip_delay; -} __attribute__ ((packed)); - -struct p54_statistics { - __le32 rx_success; - __le32 rx_bad_fcs; - __le32 rx_abort; - __le32 rx_abort_phy; - __le32 rts_success; - __le32 rts_fail; - __le32 tsf32; - __le32 airtime; - __le32 noise; - __le32 sample_noise[8]; - __le32 sample_cca; - __le32 sample_tx; -} __attribute__ ((packed)); - -struct p54_xbow_synth { - __le16 magic1; - __le16 magic2; - __le16 freq; - u32 padding[5]; -} __attribute__ ((packed)); - -struct p54_timer { - __le32 interval; -} __attribute__ ((packed)); - -struct p54_keycache { - u8 entry; - u8 key_id; - u8 mac[ETH_ALEN]; - u8 padding[2]; - u8 key_type; - u8 key_len; - u8 key[24]; -} __attribute__ ((packed)); - -struct p54_burst { - u8 flags; - u8 queue; - u8 backlog; - u8 pad; - __le16 durations[32]; -} __attribute__ ((packed)); - -struct p54_psm_interval { - __le16 interval; - __le16 periods; -} __attribute__ ((packed)); - -#define P54_PSM_CAM 0 -#define P54_PSM BIT(0) -#define P54_PSM_DTIM BIT(1) -#define P54_PSM_MCBC BIT(2) -#define P54_PSM_CHECKSUM BIT(3) -#define P54_PSM_SKIP_MORE_DATA BIT(4) -#define P54_PSM_BEACON_TIMEOUT BIT(5) -#define P54_PSM_HFOSLEEP BIT(6) -#define P54_PSM_AUTOSWITCH_SLEEP BIT(7) -#define P54_PSM_LPIT BIT(8) -#define P54_PSM_BF_UCAST_SKIP BIT(9) -#define P54_PSM_BF_MCAST_SKIP BIT(10) - -struct p54_psm { - __le16 mode; - __le16 aid; - struct p54_psm_interval intervals[4]; - u8 beacon_rssi_skip_max; - u8 rssi_delta_threshold; - u8 nr; - u8 exclude[1]; -} __attribute__ ((packed)); - -#define MC_FILTER_ADDRESS_NUM 4 - -struct p54_group_address_table { - __le16 filter_enable; - __le16 num_address; - u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN]; -} __attribute__ ((packed)); - -struct p54_txcancel { - __le32 req_id; -} __attribute__ ((packed)); - -struct p54_sta_unlock { - u8 addr[ETH_ALEN]; - u16 padding; -} __attribute__ ((packed)); - -#define P54_TIM_CLEAR BIT(15) -struct p54_tim { - u8 count; - u8 padding[3]; - __le16 entry[8]; -} __attribute__ ((packed)); - -struct p54_cce_quiet { - __le32 period; -} __attribute__ ((packed)); - -struct p54_bt_balancer { - __le16 prio_thresh; - __le16 acl_thresh; -} __attribute__ ((packed)); - -struct p54_arp_table { - __le16 filter_enable; - u8 ipv4_addr[4]; -} __attribute__ ((packed)); - -#endif /* P54COMMON_H */ diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index b1610ea..d348c26 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -22,6 +22,7 @@ #include #include "p54.h" +#include "lmac.h" #include "p54pci.h" MODULE_AUTHOR("Michael Wu "); @@ -564,7 +565,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err_free_common: release_firmware(priv->firmware); - p54_free_common(dev); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); @@ -573,7 +573,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err_free_dev: pci_set_drvdata(pdev, NULL); - ieee80211_free_hw(dev); + p54_free_common(dev); err_free_reg: pci_release_regions(pdev); @@ -590,16 +590,15 @@ static void __devexit p54p_remove(struct pci_dev *pdev) if (!dev) return; - ieee80211_unregister_hw(dev); + p54_unregister_common(dev); priv = dev->priv; release_firmware(priv->firmware); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); - p54_free_common(dev); iounmap(priv->map); pci_release_regions(pdev); pci_disable_device(pdev); - ieee80211_free_hw(dev); + p54_free_common(dev); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 83116ba..7ef191a 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -34,7 +34,7 @@ #include "p54spi_eeprom.h" #include "p54.h" -#include "p54common.h" +#include "lmac.h" MODULE_FIRMWARE("3826.arm"); MODULE_ALIAS("stlc45xx"); @@ -713,7 +713,7 @@ static int __devexit p54spi_remove(struct spi_device *spi) { struct p54s_priv *priv = dev_get_drvdata(&spi->dev); - ieee80211_unregister_hw(priv->hw); + p54_unregister_common(priv->hw); free_irq(gpio_to_irq(p54spi_gpio_irq), spi); @@ -724,7 +724,6 @@ static int __devexit p54spi_remove(struct spi_device *spi) mutex_destroy(&priv->mutex); p54_free_common(priv->hw); - ieee80211_free_hw(priv->hw); return 0; } diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 0e877a1..461d88f 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -22,6 +22,7 @@ #include #include "p54.h" +#include "lmac.h" #include "p54usb.h" MODULE_AUTHOR("Michael Wu "); @@ -961,7 +962,7 @@ err_free_fw: release_firmware(priv->fw); err_free_dev: - ieee80211_free_hw(dev); + p54_free_common(dev); usb_set_intfdata(intf, NULL); usb_put_dev(udev); return err; @@ -975,13 +976,12 @@ static void __devexit p54u_disconnect(struct usb_interface *intf) if (!dev) return; - ieee80211_unregister_hw(dev); + p54_unregister_common(dev); priv = dev->priv; usb_put_dev(interface_to_usbdev(intf)); release_firmware(priv->fw); p54_free_common(dev); - ieee80211_free_hw(dev); } static int p54u_pre_reset(struct usb_interface *intf) -- cgit v0.10.2 From 2664f201ef162224c775ecf7e33aee9c4cac62b0 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 24 Jun 2009 18:56:39 +0530 Subject: ath9k: remove unnecessary STATION mode check. Remove unncessary STATION mode check in ath9k_bss_assoc_info() as it is called only for STATION mode. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 66a6c1f..48cb553 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -920,24 +920,21 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) { - struct ath_vif *avp = (void *)vif->drv_priv; if (bss_conf->assoc) { DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", bss_conf->aid, sc->curbssid); /* New association, store aid */ - if (avp->av_opmode == NL80211_IFTYPE_STATION) { - sc->curaid = bss_conf->aid; - ath9k_hw_write_associd(sc); + sc->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc); - /* - * Request a re-configuration of Beacon related timers - * on the receipt of the first Beacon frame (i.e., - * after time sync with the AP). - */ - sc->sc_flags |= SC_OP_BEACON_SYNC; - } + /* + * Request a re-configuration of Beacon related timers + * on the receipt of the first Beacon frame (i.e., + * after time sync with the AP). + */ + sc->sc_flags |= SC_OP_BEACON_SYNC; /* Configure the beacon */ ath_beacon_config(sc, vif); -- cgit v0.10.2 From f38faa31e0da07390d72fb67d3151e56c54871f4 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 24 Jun 2009 18:56:40 +0530 Subject: ath9k: stop ani when the STA gets disconnected. ANI is not required when the STA is disconnected. So stop it and enable ANI for adhoc and monitor mode. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 48cb553..6d63126 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -949,6 +949,8 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, } else { DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); sc->curaid = 0; + /* Stop ANI */ + del_timer_sync(&sc->ani.timer); } } @@ -2193,7 +2195,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - if (conf->type == NL80211_IFTYPE_AP) + if (conf->type == NL80211_IFTYPE_AP || + conf->type == NL80211_IFTYPE_ADHOC || + conf->type == NL80211_IFTYPE_MONITOR) ath_start_ani(sc); out: -- cgit v0.10.2 From e5f0921a9593365b506f69daa3cfd19c0ed1340b Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 24 Jun 2009 18:56:41 +0530 Subject: ath9k: race condition in SCANNING state check during ANI calibration ANI calibration shouldn't be done when we are not on our home channel. This is already verified. However, it is racy. Fix this by proper spin locks. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 747e046..eb9d522 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -540,6 +540,7 @@ struct ath_softc { int irq; spinlock_t sc_resetlock; spinlock_t sc_serial_rw; + spinlock_t ani_lock; struct mutex mutex; u8 curbssid[ETH_ALEN]; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6d63126..52dfa43 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -342,6 +342,7 @@ static void ath_ani_calibrate(unsigned long data) * don't calibrate when we're scanning. * we are most likely not on our home channel. */ + spin_lock(&sc->ani_lock); if (sc->sc_flags & SC_OP_SCANNING) goto set_timer; @@ -405,6 +406,7 @@ static void ath_ani_calibrate(unsigned long data) ath9k_ps_restore(sc); set_timer: + spin_unlock(&sc->ani_lock); /* * Set timer interval based on previous results. * The interval must be the shortest necessary to satisfy ANI, @@ -1310,6 +1312,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) spin_lock_init(&sc->wiphy_lock); spin_lock_init(&sc->sc_resetlock); spin_lock_init(&sc->sc_serial_rw); + spin_lock_init(&sc->ani_lock); mutex_init(&sc->mutex); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, @@ -2682,9 +2685,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) aphy->state = ATH_WIPHY_SCAN; ath9k_wiphy_pause_all_forced(sc, aphy); - mutex_lock(&sc->mutex); + spin_lock_bh(&sc->ani_lock); sc->sc_flags |= SC_OP_SCANNING; - mutex_unlock(&sc->mutex); + spin_unlock_bh(&sc->ani_lock); } static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) @@ -2692,11 +2695,11 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - mutex_lock(&sc->mutex); + spin_lock_bh(&sc->ani_lock); aphy->state = ATH_WIPHY_ACTIVE; sc->sc_flags &= ~SC_OP_SCANNING; sc->sc_flags |= SC_OP_FULL_RESET; - mutex_unlock(&sc->mutex); + spin_unlock_bh(&sc->ani_lock); } struct ieee80211_ops ath9k_ops = { -- cgit v0.10.2 From 140add21356528fc76ad276fd32b2e7abb945325 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 24 Jun 2009 18:56:42 +0530 Subject: ath9k: Handle different TX and RX streams properly. This patch fixes an issue when the TX and RX streams are different. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 52dfa43..961b0ce 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -889,6 +889,7 @@ static void setup_ht_cap(struct ath_softc *sc, { #define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ #define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ + u8 tx_streams, rx_streams; ht_info->ht_supported = true; ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | @@ -901,21 +902,22 @@ static void setup_ht_cap(struct ath_softc *sc, /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + tx_streams = !(sc->tx_chainmask & (sc->tx_chainmask - 1)) ? 1 : 2; + rx_streams = !(sc->rx_chainmask & (sc->rx_chainmask - 1)) ? 1 : 2; - switch(sc->rx_chainmask) { - case 1: - ht_info->mcs.rx_mask[0] = 0xff; - break; - case 3: - case 5: - case 7: - default: - ht_info->mcs.rx_mask[0] = 0xff; - ht_info->mcs.rx_mask[1] = 0xff; - break; + if (tx_streams != rx_streams) { + DPRINTF(sc, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", + tx_streams, rx_streams); + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_streams - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); } - ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + ht_info->mcs.rx_mask[0] = 0xff; + if (rx_streams >= 2) + ht_info->mcs.rx_mask[1] = 0xff; + + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; } static void ath9k_bss_assoc_info(struct ath_softc *sc, -- cgit v0.10.2 From 8ab0ea77273ecf97d26cf8ca026ef383098577fb Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 24 Jun 2009 22:13:27 -0700 Subject: drivers/net/wireless: Use PCI_VDEVICE Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 44c29b3..d726b3c 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11436,11 +11436,11 @@ static struct pci_device_id card_ids[] = { {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0}, {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0}, {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ - {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ - {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ - {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ + {PCI_VDEVICE(INTEL, 0x104f), 0}, + {PCI_VDEVICE(INTEL, 0x4220), 0}, /* BG */ + {PCI_VDEVICE(INTEL, 0x4221), 0}, /* BG */ + {PCI_VDEVICE(INTEL, 0x4223), 0}, /* ABG */ + {PCI_VDEVICE(INTEL, 0x4224), 0}, /* ABG */ /* required last entry */ {0,} diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index 3087672..83d3662 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -49,9 +49,7 @@ static const struct pci_device_id prism54_id_tbl[] = { /* 3COM 3CRWE154G72 Wireless LAN adapter */ { - 0x10b7, 0x6001, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 0 + PCI_VDEVICE(3COM, 0x6001), 0 }, /* Intersil PRISM Indigo Wireless LAN adapter */ -- cgit v0.10.2 From dd13fd649879b6230be5d855e00c286c5e60f354 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 25 Jun 2009 18:28:30 +0800 Subject: iwmc3200wifi: replace netif_rx with netif_rx_ni The patch uses netif_rx_ni() over netif_rx() to post buffers to upper network code because it is always scheduled in a workqueue. The problem was first observed from a dynamic ticks warning: "NOHZ: local_softirq_pending ..." Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 55871da..5d2239f 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1373,7 +1373,7 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm, ndev->stats.rx_packets++; ndev->stats.rx_bytes += skb->len; - if (netif_rx(skb) == NET_RX_DROP) { + if (netif_rx_ni(skb) == NET_RX_DROP) { IWM_ERR(iwm, "Packet dropped\n"); ndev->stats.rx_dropped++; } -- cgit v0.10.2 From fd2c7fe0b4dedc34ea0a2a72e00648bd2b8c7c3a Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 25 Jun 2009 18:28:31 +0800 Subject: iwmc3200wifi: simplify calibration map The patch simplifies calibration map by combining the init_calib_map and periodic_calib_map into one calib_map in struct iwm_conf. Now the initial calibration map is stored in the lower 16 bits of calib_map and the periodic calibration map is stored in the higher 16 bits. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index ec1a15a..c58f614 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -275,6 +275,7 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) */ int iwm_load_fw(struct iwm_priv *iwm) { + unsigned long init_calib_map, periodic_calib_map; int ret; /* We first start downloading the UMAC */ @@ -315,23 +316,25 @@ int iwm_load_fw(struct iwm_priv *iwm) return ret; } + init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK; + periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map); + #ifdef CONFIG_IWM_B0_HW_SUPPORT if (iwm->conf.hw_b0) { - clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map); - clear_bit(PHY_CALIBRATE_RX_IQ_CMD, - &iwm->conf.periodic_calib_map); + clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map); + clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &periodic_calib_map); } #endif /* Read RX IQ calibration result from EEPROM */ - if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) { + if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) { iwm_store_rxiq_calib_result(iwm); set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); } iwm_send_prio_table(iwm); - iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map); + iwm_send_init_calib_cfg(iwm, init_calib_map); - while (iwm->calib_done_map != iwm->conf.init_calib_map) { + while (iwm->calib_done_map != init_calib_map) { ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); if (ret) { @@ -340,7 +343,7 @@ int iwm_load_fw(struct iwm_priv *iwm) } IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " "0x%lx, requested calibrations: 0x%lx\n", - iwm->calib_done_map, iwm->conf.init_calib_map); + iwm->calib_done_map, init_calib_map); } /* Handle LMAC CALIBRATION_COMPLETE notification */ @@ -378,7 +381,7 @@ int iwm_load_fw(struct iwm_priv *iwm) iwm_send_prio_table(iwm); iwm_send_calib_results(iwm); - iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map); + iwm_send_periodic_calib_cfg(iwm, periodic_calib_map); return 0; diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 4da57f7..1bad78f 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -65,8 +65,7 @@ struct iwm_conf { u32 sdio_ior_timeout; - unsigned long init_calib_map; - unsigned long periodic_calib_map; + unsigned long calib_map; bool reset_on_fatal_err; bool auto_connect; bool wimax_not_present; diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h index db2e5ee..19213e1 100644 --- a/drivers/net/wireless/iwmc3200wifi/lmac.h +++ b/drivers/net/wireless/iwmc3200wifi/lmac.h @@ -396,6 +396,10 @@ enum { CALIBRATION_CMD_NUM, }; +#define IWM_CALIB_MAP_INIT_MSK 0xFFFF +#define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16) +#define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24) + struct iwm_lmac_calib_hdr { u8 opcode; u8 first_grp; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 930056b..4fedb45 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -53,11 +53,7 @@ static struct iwm_conf def_iwm_conf = { .sdio_ior_timeout = 5000, - .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | - BIT(PHY_CALIBRATE_LO_CMD) | - BIT(PHY_CALIBRATE_TX_IQ_CMD) | - BIT(PHY_CALIBRATE_RX_IQ_CMD), - .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | + .calib_map = BIT(PHY_CALIBRATE_DC_CMD) | BIT(PHY_CALIBRATE_LO_CMD) | BIT(PHY_CALIBRATE_TX_IQ_CMD) | BIT(PHY_CALIBRATE_RX_IQ_CMD) | -- cgit v0.10.2 From 19a42803f310ff60ce5a6c02992762068a01394a Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 25 Jun 2009 18:28:32 +0800 Subject: iwmc3200wifi: remove B0 hardware support The patch removes B0 hardware support. Nobody is using it anyway. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c index 0f34b84..365910f 100644 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.c +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c @@ -156,10 +156,6 @@ int iwm_eeprom_init(struct iwm_priv *iwm) return -ENOMEM; for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET)) - break; -#endif ret = iwm_eeprom_read(iwm, i); if (ret < 0) { IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n", diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index c58f614..0f32cab 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -319,12 +319,6 @@ int iwm_load_fw(struct iwm_priv *iwm) init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK; periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map); -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (iwm->conf.hw_b0) { - clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map); - clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &periodic_calib_map); - } -#endif /* Read RX IQ calibration result from EEPROM */ if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) { iwm_store_rxiq_calib_result(iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 1bad78f..79d9d89 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -52,8 +52,6 @@ #define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation" #define IWM_AUTHOR "" -#define CONFIG_IWM_B0_HW_SUPPORT 1 - #define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX #define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA #define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW @@ -86,9 +84,6 @@ struct iwm_conf { u8 ibss_channel; u8 mac_addr[ETH_ALEN]; -#ifdef CONFIG_IWM_B0_HW_SUPPORT - bool hw_b0; -#endif }; enum { diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 4fedb45..484f110 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -515,13 +515,6 @@ static int iwm_channels_init(struct iwm_priv *iwm) { int ret; -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (iwm->conf.hw_b0) { - IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n"); - return 0; - } -#endif - ret = iwm_send_umac_channel_list(iwm); if (ret) { IWM_ERR(iwm, "Send channel list failed\n"); diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 5d2239f..3909477 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -924,13 +924,6 @@ static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf, if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN) return -EINVAL; -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) { - if (eeprom_proxy->buf[0] == 0xff) - iwm->conf.hw_b0 = 1; - } -#endif - switch (hdr_type) { case IWM_UMAC_CMD_EEPROM_TYPE_READ: memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len); -- cgit v0.10.2 From f55e668f902e40a5299deb8cc5940d1d24b19ea0 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 26 Jun 2009 11:00:53 -0700 Subject: iwlagn: re-enable PS support for iwlagn The register locking rework addressed the problem where nic access was obtained incorrectly when PS is enabled. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7e528a0..d5cd9a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1382,7 +1382,8 @@ int iwl_setup_mac(struct iwl_priv *priv) hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_SPECTRUM_MGMT; + IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_SUPPORTS_PS; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); -- cgit v0.10.2 From 68021b966b3cb363596251bac0370c12e084e7da Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 26 Jun 2009 11:00:54 -0700 Subject: iwlwifi: add utility to print buffer when error occurs Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 2cf014f..65bbce0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -36,6 +36,12 @@ struct iwl_priv; #define IWL_INFO(p, f, a...) dev_info(&((p)->pci_dev->dev), f, ## a) #define IWL_CRIT(p, f, a...) dev_crit(&((p)->pci_dev->dev), f, ## a) +#define iwl_print_hex_error(priv, p, len) \ +do { \ + print_hex_dump(KERN_ERR, "iwl data: ", \ + DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ +} while (0) + #ifdef CONFIG_IWLWIFI_DEBUG #define IWL_DEBUG(__priv, level, fmt, args...) \ do { \ -- cgit v0.10.2 From 7ac487260e087f1660e856d4afae2dd49774f66b Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 26 Jun 2009 11:00:55 -0700 Subject: iwlwifi: always print buffer when error condition occurs We want to see the buffer contents when the error occurs without needing to set any debug flags. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index b35c1fd..753fca3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1109,7 +1109,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) txq_id, sequence, priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr, priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) { - iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32); + iwl_print_hex_error(priv, rxb, 32); return; } -- cgit v0.10.2 From 6badaaf7729e5d1c02934b1739303ce79014ab67 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 28 Jun 2009 09:26:32 -0700 Subject: drivers/net/wireless/ath/ath9k: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index a2fda70..d82a0f9 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -2516,10 +2516,8 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, targetPowerCck.tPow2x[1]; ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; - ; ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; - ; } if (IS_CHAN_HT40(chan)) { for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 34935a8..cffb078 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2345,7 +2345,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_init_bb(ah, chan); if (!ath9k_hw_init_cal(ah, chan)) - return -EIO;; + return -EIO; rx_chainmask = ah->rxchainmask; if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { -- cgit v0.10.2 From 31670070ffe18f8e8743109b19297a0efac0a72c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 28 Jun 2009 23:25:27 +0200 Subject: ath5k: remove permissions from debugfs files Don't allow users to open debugfs files, because it can cause oopses. When a user opens some file, driver unlinks it and frees the corresponding structure, we will dereference freed memory. Signed-off-by: Jiri Slaby Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 4904a07..747508c 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -380,13 +380,15 @@ ath5k_debug_init_device(struct ath5k_softc *sc) sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy), ath5k_global_debugfs); - sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUGO, + sc->debug.debugfs_debug = debugfs_create_file("debug", + S_IWUSR | S_IRUSR, sc->debug.debugfs_phydir, sc, &fops_debug); - sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO, + sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR, sc->debug.debugfs_phydir, sc, &fops_registers); - sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO, + sc->debug.debugfs_beacon = debugfs_create_file("beacon", + S_IWUSR | S_IRUSR, sc->debug.debugfs_phydir, sc, &fops_beacon); sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, -- cgit v0.10.2 From 9d49e861a5e31fb7f575f348743886189045e102 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 28 Jun 2009 23:25:28 +0200 Subject: ath9k: remove permissions from debugfs files Don't allow users to open debugfs files, because it can cause oopses. When a user opens some file, driver unlinks it and frees the corresponding structure, we will dereference freed memory. Signed-off-by: Jiri Slaby Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 6d20725..9f99f00 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -500,31 +500,31 @@ int ath9k_init_debug(struct ath_softc *sc) goto err; sc->debug.debugfs_debug = debugfs_create_file("debug", - S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); + S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); if (!sc->debug.debugfs_debug) goto err; - sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, + sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_dma); if (!sc->debug.debugfs_dma) goto err; sc->debug.debugfs_interrupt = debugfs_create_file("interrupt", - S_IRUGO, + S_IRUSR, sc->debug.debugfs_phy, sc, &fops_interrupt); if (!sc->debug.debugfs_interrupt) goto err; sc->debug.debugfs_rcstat = debugfs_create_file("rcstat", - S_IRUGO, + S_IRUSR, sc->debug.debugfs_phy, sc, &fops_rcstat); if (!sc->debug.debugfs_rcstat) goto err; sc->debug.debugfs_wiphy = debugfs_create_file( - "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, + "wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_wiphy); if (!sc->debug.debugfs_wiphy) goto err; -- cgit v0.10.2 From 96f7e73938da744e718ce4817dd3e7e424624654 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Tue, 30 Jun 2009 14:49:18 +0200 Subject: mac80211: shorten the passive dwell time for sw scans mac80211's software scan implementation uses a passive dwell time of (HZ / 5) which means we stay 200ms on each passive channel. Compared to iwlwifi's hw scan and the old ipw* drivers which use values around 120ms this is quite long. Reducing the passive dwell time from 200ms to 125ms should save us something around a second on cards capable of 11a and we should still be able to catch beacons from most access points (assuming a ~100ms beacon interval). Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 8b2416c..569a464 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -26,7 +26,7 @@ #define IEEE80211_PROBE_DELAY (HZ / 33) #define IEEE80211_CHANNEL_TIME (HZ / 33) -#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5) +#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8) struct ieee80211_bss * ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, -- cgit v0.10.2 From b623a9f7c488e51dbe4320d8b5cdd0ba242d0067 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 14:57:59 +0200 Subject: iwlwifi: fix aggregation limit According to the documentation, the limit is 0x3f == 63, not 64. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6e9b8a8..ebb2fbc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1924,7 +1924,7 @@ struct iwl_link_qual_general_params { #define LINK_QUAL_AGG_DISABLE_START_MIN (0) #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) -#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (64) +#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) /** -- cgit v0.10.2 From e47a5cddf893815e7da16e3226b959af785d8aaf Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 1 Jul 2009 15:17:35 +0200 Subject: rt2x00: use wiphy rfkill interface Remove the input_polldev from rt2x00 and replace it with the rfkill interface offered by the wiphy structure. This simplifies the entire rfkill handling in rt2x00 and allows us to remove the CONFIG_RT2X00_LIB_RFKILL option and always enables rfkill capabilities. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 8aab3e6..f970aa2 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -112,14 +112,6 @@ config RT2X00_LIB_FIRMWARE config RT2X00_LIB_CRYPTO boolean -config RT2X00_LIB_RFKILL - boolean - default y if (RT2X00_LIB=y && INPUT=y) || (RT2X00_LIB=m && INPUT!=n) - select INPUT_POLLDEV - -comment "rt2x00 rfkill support disabled due to modularized INPUT and built-in rt2x00" - depends on RT2X00_LIB=y && INPUT=m - config RT2X00_LIB_LEDS boolean default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n) diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index bfc7226..13043ea 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -5,7 +5,6 @@ rt2x00lib-y += rt2x00queue.o rt2x00lib-y += rt2x00link.o rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o -rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 435f945..d8035e3 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -199,7 +199,6 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -207,9 +206,6 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); return rt2x00_get_field32(reg, GPIOCSR_BIT0); } -#else -#define rt2400pci_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt2400pci_brightness_set(struct led_classdev *led_cdev, @@ -1391,10 +1387,8 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Check if the BBP tuning should be enabled. @@ -1573,6 +1567,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2400pci_get_tsf, .tx_last_beacon = rt2400pci_tx_last_beacon, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 08b30d0..c123e28 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -199,7 +199,6 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -207,9 +206,6 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); return rt2x00_get_field32(reg, GPIOCSR_BIT0); } -#else -#define rt2500pci_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt2500pci_brightness_set(struct led_classdev *led_cdev, @@ -1548,10 +1544,8 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Check if the BBP tuning should be enabled. @@ -1872,6 +1866,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2500pci_get_tsf, .tx_last_beacon = rt2500pci_tx_last_beacon, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 66daf68..795706d 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -277,7 +277,6 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u16 reg; @@ -285,9 +284,6 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®); return rt2x00_get_field32(reg, MAC_CSR19_BIT7); } -#else -#define rt2500usb_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt2500usb_brightness_set(struct led_classdev *led_cdev, @@ -1601,10 +1597,8 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Check if the BBP tuning should be disabled. @@ -1905,6 +1899,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3756166..a204e66 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -264,7 +264,6 @@ static const struct rt2x00debug rt2800usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -272,9 +271,6 @@ static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); } -#else -#define rt2800usb_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt2800usb_brightness_set(struct led_classdev *led_cdev, @@ -2385,10 +2381,8 @@ static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Store led settings, for correct led behaviour. @@ -2800,6 +2794,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { .conf_tx = rt2800usb_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2800usb_get_tsf, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index a498dde..71f37cb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -651,18 +651,6 @@ struct rt2x00_dev { enum ieee80211_band curr_band; /* - * rfkill structure for RF state switching support. - * This will only be compiled in when required. - */ -#ifdef CONFIG_RT2X00_LIB_RFKILL - unsigned long rfkill_state; -#define RFKILL_STATE_ALLOCATED 1 -#define RFKILL_STATE_REGISTERED 2 -#define RFKILL_STATE_BLOCKED 3 - struct input_polled_dev *rfkill_poll_dev; -#endif /* CONFIG_RT2X00_LIB_RFKILL */ - - /* * If enabled, the debugfs interface structures * required for deregistration of debugfs. */ @@ -992,6 +980,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, u32 changes); int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); +void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); /* * Driver allocation handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 41e3379..4fff3a8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -871,7 +871,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) */ rt2x00link_register(rt2x00dev); rt2x00leds_register(rt2x00dev); - rt2x00rfkill_allocate(rt2x00dev); rt2x00debug_register(rt2x00dev); set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); @@ -903,7 +902,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) * Free extra components */ rt2x00debug_deregister(rt2x00dev); - rt2x00rfkill_free(rt2x00dev); rt2x00leds_unregister(rt2x00dev); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 0bf2715..512fa2b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -30,10 +30,8 @@ /* * Interval defines - * Both the link tuner as the rfkill will be called once per second. */ #define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) -#define RFKILL_POLL_INTERVAL 1000 /* * rt2x00_rate: Per rate device information @@ -386,29 +384,18 @@ static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, /* * RFkill handlers. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL -void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev); -void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev); -void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev); -void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev); -#else static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { + if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy); } static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) { + if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy); } -static inline void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) -{ -} - -static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) -{ -} -#endif /* CONFIG_RT2X00_LIB_RFKILL */ - /* * LED handlers */ diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 475a3ed..b7e0ddd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -688,3 +688,12 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, return 0; } EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx); + +void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + bool blocked = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); + + wiphy_rfkill_set_hw_state(hw->wiphy, blocked); +} +EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll); diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c deleted file mode 100644 index b6d4c67..0000000 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project - - - 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. - */ - -/* - Module: rt2x00rfkill - Abstract: rt2x00 rfkill routines. - */ - -#include -#include - -#include "rt2x00.h" -#include "rt2x00lib.h" - -static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev) -{ - struct rt2x00_dev *rt2x00dev = poll_dev->private; - int state, old_state; - - if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) || - !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) - return; - - /* - * Poll latest state, if the state is different then the previous state, - * we should generate an input event. - */ - state = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); - old_state = !!test_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state); - - if (old_state != state) { - input_report_switch(poll_dev->input, SW_RFKILL_ALL, state); - change_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state); - } -} - -void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) -{ - if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || - test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) - return; - - if (input_register_polled_device(rt2x00dev->rfkill_poll_dev)) { - ERROR(rt2x00dev, "Failed to register polled device.\n"); - return; - } - - __set_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state); - - /* - * Force initial poll which will detect the initial device state, - * and correctly sends the signal to the input layer about this - * state. - */ - rt2x00rfkill_poll(rt2x00dev->rfkill_poll_dev); -} - -void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) -{ - if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || - !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) - return; - - input_unregister_polled_device(rt2x00dev->rfkill_poll_dev); - - __clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state); -} - -void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) -{ - struct input_polled_dev *poll_dev; - - if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || - !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) - return; - - poll_dev = input_allocate_polled_device(); - if (!poll_dev) { - ERROR(rt2x00dev, "Failed to allocate polled device.\n"); - return; - } - - poll_dev->private = rt2x00dev; - poll_dev->poll = rt2x00rfkill_poll; - poll_dev->poll_interval = RFKILL_POLL_INTERVAL; - - poll_dev->input->name = rt2x00dev->ops->name; - poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy); - poll_dev->input->id.bustype = BUS_HOST; - poll_dev->input->id.vendor = 0x1814; - poll_dev->input->id.product = rt2x00dev->chip.rt; - poll_dev->input->id.version = rt2x00dev->chip.rev; - poll_dev->input->dev.parent = wiphy_dev(rt2x00dev->hw->wiphy); - poll_dev->input->evbit[0] = BIT(EV_SW); - poll_dev->input->swbit[0] = BIT(SW_RFKILL_ALL); - - rt2x00dev->rfkill_poll_dev = poll_dev; - - __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state); -} - -void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) -{ - if (!__test_and_clear_bit(RFKILL_STATE_ALLOCATED, - &rt2x00dev->rfkill_state)) - return; - - input_free_polled_device(rt2x00dev->rfkill_poll_dev); - rt2x00dev->rfkill_poll_dev = NULL; -} diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 49b29ff..8a49d99 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -237,7 +237,6 @@ static const struct rt2x00debug rt61pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -245,9 +244,6 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); return rt2x00_get_field32(reg, MAC_CSR13_BIT5); } -#else -#define rt61pci_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt61pci_brightness_set(struct led_classdev *led_cdev, @@ -2338,10 +2334,8 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Read frequency offset and RF programming sequence. @@ -2728,6 +2722,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .conf_tx = rt61pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt61pci_get_tsf, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index c188488..ad2898c 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -183,7 +183,6 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -191,9 +190,6 @@ static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_read(rt2x00dev, MAC_CSR13, ®); return rt2x00_get_field32(reg, MAC_CSR13_BIT7); } -#else -#define rt73usb_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt73usb_brightness_set(struct led_classdev *led_cdev, @@ -1863,10 +1859,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Read frequency offset. @@ -2253,6 +2247,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .conf_tx = rt73usb_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt73usb_get_tsf, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { -- cgit v0.10.2 From 6c230c02700f9d2aebe6edf9f571835c06707940 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 3 Jul 2009 02:00:48 +0200 Subject: cfg80211: check for current_bss from giwrate When connecting to an ESSID manually, we may not set the BSSID, and thus wdev->wext.connect.bssid will be NULL. wdev->current_bss is always updated when a connection is established so we should check it first. Signed-off-by: Samuel Ortiz Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index d39688c..2c33cd8 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1136,8 +1136,11 @@ int cfg80211_wext_giwrate(struct net_device *dev, if (!rdev->ops->get_station) return -EOPNOTSUPP; - addr = wdev->wext.connect.bssid; - if (!addr) + if (wdev->current_bss) + addr = wdev->current_bss->pub.bssid; + else if (wdev->wext.connect.bssid) + addr = wdev->wext.connect.bssid; + else return -EOPNOTSUPP; err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo); -- cgit v0.10.2 From a7eee06b874a02e2de75727ab21a8747ca6309ff Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 3 Jul 2009 21:01:15 +0200 Subject: p54: two endian fixes This patch fixes all CHECK_ENDIAN complains: 1. p54/fwio.c:296:6: warning: restricted __le32 degrades to integer p54/fwio.c:296:6: warning: restricted __le32 degrades to integer 2. p54/p54spi.c:172:32: warning: incorrect type in initializer p54spi.c:172:32: expected restricted __le32 [usertype] buffer p54/p54spi.c:172:32: got unsigned int Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 178efbc..dc4f3f5 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -292,8 +292,9 @@ int p54_tx_cancel(struct p54_common *priv, __le32 req_id) { struct sk_buff *skb; struct p54_txcancel *cancel; + u32 _req_id = le32_to_cpu(req_id); - if (unlikely(req_id < priv->rx_start || req_id > priv->rx_end)) + if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end)) return -EINVAL; skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel), diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 7ef191a..9b347ce 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -164,12 +164,12 @@ static const struct p54spi_spi_reg p54spi_registers_array[] = { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_RD_BASE " } }; -static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) +static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits) { int i; for (i = 0; i < 2000; i++) { - __le32 buffer = p54spi_read32(priv, reg); + u32 buffer = p54spi_read32(priv, reg); if ((buffer & bits) == bits) return 1; } @@ -179,8 +179,7 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, const void *buf, size_t len) { - if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, - cpu_to_le32(HOST_ALLOWED))) { + if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, HOST_ALLOWED)) { dev_err(&priv->spi->dev, "spi_write_dma not allowed " "to DMA write.\n"); return -EAGAIN; @@ -333,7 +332,7 @@ static int p54spi_wakeup(struct p54s_priv *priv) /* And wait for the READY interrupt */ if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, - cpu_to_le32(SPI_HOST_INT_READY))) { + SPI_HOST_INT_READY)) { dev_err(&priv->spi->dev, "INT_READY timeout\n"); return -EBUSY; } @@ -444,7 +443,7 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) goto out; if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, - cpu_to_le32(SPI_HOST_INT_WR_READY))) { + SPI_HOST_INT_WR_READY)) { dev_err(&priv->spi->dev, "WR_READY timeout\n"); ret = -EAGAIN; goto out; -- cgit v0.10.2 From 0859339b5c2902a7a4ba1d4c9cf35d882f421e7f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 4 Jul 2009 17:49:59 +0200 Subject: p54spi: remove dead code and definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch removes some dead code: p54spi.c:115: warning: ‘p54spi_read16’ defined but not used and while we're at it, p54spi_registers_array is purged as well. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 9b347ce..d5f181a 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -111,15 +111,6 @@ static void p54spi_spi_write(struct p54s_priv *priv, u8 address, spi_sync(priv->spi, &m); } -static u16 p54spi_read16(struct p54s_priv *priv, u8 addr) -{ - __le16 val; - - p54spi_spi_read(priv, addr, &val, sizeof(val)); - - return le16_to_cpu(val); -} - static u32 p54spi_read32(struct p54s_priv *priv, u8 addr) { __le32 val; @@ -139,31 +130,6 @@ static inline void p54spi_write32(struct p54s_priv *priv, u8 addr, __le32 val) p54spi_spi_write(priv, addr, &val, sizeof(val)); } -struct p54spi_spi_reg { - u16 address; /* __le16 ? */ - u16 length; - char *name; -}; - -static const struct p54spi_spi_reg p54spi_registers_array[] = -{ - { SPI_ADRS_ARM_INTERRUPTS, 32, "ARM_INT " }, - { SPI_ADRS_ARM_INT_EN, 32, "ARM_INT_ENA " }, - { SPI_ADRS_HOST_INTERRUPTS, 32, "HOST_INT " }, - { SPI_ADRS_HOST_INT_EN, 32, "HOST_INT_ENA" }, - { SPI_ADRS_HOST_INT_ACK, 32, "HOST_INT_ACK" }, - { SPI_ADRS_GEN_PURP_1, 32, "GP1_COMM " }, - { SPI_ADRS_GEN_PURP_2, 32, "GP2_COMM " }, - { SPI_ADRS_DEV_CTRL_STAT, 32, "DEV_CTRL_STA" }, - { SPI_ADRS_DMA_DATA, 16, "DMA_DATA " }, - { SPI_ADRS_DMA_WRITE_CTRL, 16, "DMA_WR_CTRL " }, - { SPI_ADRS_DMA_WRITE_LEN, 16, "DMA_WR_LEN " }, - { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_WR_BASE " }, - { SPI_ADRS_DMA_READ_CTRL, 16, "DMA_RD_CTRL " }, - { SPI_ADRS_DMA_READ_LEN, 16, "DMA_RD_LEN " }, - { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_RD_BASE " } -}; - static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits) { int i; -- cgit v0.10.2 From cec8db23011d2a0a5ec101a0263d79678adf21ba Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 4 Jul 2009 12:59:51 -0400 Subject: ath5k: send buffered frames after the beacon Enable the "Content" After Beacon queue and utilize it to send any buffered frames for power-saving clients. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c6e7091..87ebc46 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -218,6 +218,8 @@ static struct pci_driver ath5k_pci_driver = { * Prototypes - MAC 802.11 stack related functions */ static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); +static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath5k_txq *txq); static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan); static int ath5k_reset_wake(struct ath5k_softc *sc); static int ath5k_start(struct ieee80211_hw *hw); @@ -301,7 +303,8 @@ static void ath5k_desc_free(struct ath5k_softc *sc, static int ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf); static int ath5k_txbuf_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf); + struct ath5k_buf *bf, + struct ath5k_txq *txq); static inline void ath5k_txbuf_free(struct ath5k_softc *sc, struct ath5k_buf *bf) { @@ -516,6 +519,7 @@ ath5k_pci_probe(struct pci_dev *pdev, /* Initialize driver private data */ SET_IEEE80211_DEV(hw, &pdev->dev); hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; @@ -789,12 +793,18 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) goto err_desc; } sc->bhalq = ret; + sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0); + if (IS_ERR(sc->cabq)) { + ATH5K_ERR(sc, "can't setup cab queue\n"); + ret = PTR_ERR(sc->cabq); + goto err_bhal; + } sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); if (IS_ERR(sc->txq)) { ATH5K_ERR(sc, "can't setup xmit queue\n"); ret = PTR_ERR(sc->txq); - goto err_bhal; + goto err_queues; } tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); @@ -1232,10 +1242,10 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) } static int -ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) +ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, + struct ath5k_txq *txq) { struct ath5k_hw *ah = sc->ah; - struct ath5k_txq *txq = sc->txq; struct ath5k_desc *ds = bf->desc; struct sk_buff *skb = bf->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -2103,6 +2113,7 @@ ath5k_beacon_send(struct ath5k_softc *sc) { struct ath5k_buf *bf = sc->bbuf; struct ath5k_hw *ah = sc->ah; + struct sk_buff *skb; ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n"); @@ -2156,6 +2167,12 @@ ath5k_beacon_send(struct ath5k_softc *sc) ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", sc->bhalq, (unsigned long long)bf->daddr, bf->desc); + skb = ieee80211_get_buffered_bc(sc->hw, sc->vif); + while (skb) { + ath5k_tx_queue(sc->hw, skb, sc->cabq); + skb = ieee80211_get_buffered_bc(sc->hw, sc->vif); + } + sc->bsent++; } @@ -2603,6 +2620,14 @@ static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath5k_softc *sc = hw->priv; + + return ath5k_tx_queue(hw, skb, sc->txq); +} + +static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath5k_txq *txq) +{ + struct ath5k_softc *sc = hw->priv; struct ath5k_buf *bf; unsigned long flags; int hdrlen; @@ -2646,7 +2671,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) bf->skb = skb; - if (ath5k_txbuf_setup(sc, bf)) { + if (ath5k_txbuf_setup(sc, bf, txq)) { bf->skb = NULL; spin_lock_irqsave(&sc->txbuflock, flags); list_add_tail(&bf->list, &sc->txbuf); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index f9b7f2f..65e75fb 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -114,8 +114,7 @@ struct ath5k_softc { struct pci_dev *pdev; /* for dma mapping */ void __iomem *iobase; /* address of the device */ struct mutex lock; /* dev-level lock */ - /* FIXME: how many does it really need? */ - struct ieee80211_tx_queue_stats tx_stats[16]; + struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES]; struct ieee80211_low_level_stats ll_stats; struct ieee80211_hw *hw; /* IEEE 802.11 common */ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; @@ -171,9 +170,8 @@ struct ath5k_softc { struct list_head txbuf; /* transmit buffer */ spinlock_t txbuflock; unsigned int txbuf_len; /* buf count in txbuf list */ - struct ath5k_txq txqs[2]; /* beacon and tx */ - - struct ath5k_txq *txq; /* beacon and tx*/ + struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */ + struct ath5k_txq *txq; /* main tx queue */ struct tasklet_struct txtq; /* tx intr tasklet */ struct ath5k_led tx_led; /* tx led */ @@ -187,6 +185,7 @@ struct ath5k_softc { bintval, /* beacon interval in TU */ bsent; unsigned int nexttbtt; /* next beacon time in TU */ + struct ath5k_txq *cabq; /* content after beacon */ struct timer_list calib_tim; /* calibration timer */ int power_level; /* Requested tx power in dbm */ diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 73407b3..6d5aaf0 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -411,7 +411,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), AR5K_QCU_MISC_FRSHED_BCN_SENT_GT | AR5K_QCU_MISC_CBREXP_DIS | - AR5K_QCU_MISC_RDY_VEOL_POLICY | AR5K_QCU_MISC_CBREXP_BCN_DIS); ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - -- cgit v0.10.2 From 21800491cc5c48e9f1084a6f524a0da7c2525cc6 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 4 Jul 2009 12:59:52 -0400 Subject: ath5k: rework beacon configuration Using the enable_beacon flag allows some simplifications and fixes some corner cases in beacon handling. This change adds a state variable for beaconing in ath5k_beacon_config and handles both enabling and disabling, thus eliminating the need for ath5k_beacon_disable. We also now configure the beacon when any of the beacon parameters change, so ath5k_beacon_reconfig is no longer needed (its mmiowb gets moved to ath5k_beacon_config). Finally, by locking around the whole config function, we don't need to worry about clearing the interrupt mask register before installing the new mask. The upshot is this correctly disables beaconing when the interfaces are taken down, it fixes a potential restarting of beaconing when ath5k_reset() is called, and ensures that updates to the beacon interval take effect immediately. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 87ebc46..4829329 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2093,13 +2093,6 @@ err_unmap: return ret; } -static void ath5k_beacon_disable(struct ath5k_softc *sc) -{ - sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); - ath5k_hw_set_imr(sc->ah, sc->imask); - ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq); -} - /* * Transmit a beacon frame at SWBA. Dynamic updates to the * frame contents are done as needed and the slot time is @@ -2293,13 +2286,11 @@ ath5k_beacon_config(struct ath5k_softc *sc) struct ath5k_hw *ah = sc->ah; unsigned long flags; - ath5k_hw_set_imr(ah, 0); + spin_lock_irqsave(&sc->block, flags); sc->bmisscount = 0; sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); - if (sc->opmode == NL80211_IFTYPE_ADHOC || - sc->opmode == NL80211_IFTYPE_MESH_POINT || - sc->opmode == NL80211_IFTYPE_AP) { + if (sc->enable_beacon) { /* * In IBSS mode we use a self-linked tx descriptor and let the * hardware send the beacons automatically. We have to load it @@ -2312,16 +2303,17 @@ ath5k_beacon_config(struct ath5k_softc *sc) sc->imask |= AR5K_INT_SWBA; if (sc->opmode == NL80211_IFTYPE_ADHOC) { - if (ath5k_hw_hasveol(ah)) { - spin_lock_irqsave(&sc->block, flags); + if (ath5k_hw_hasveol(ah)) ath5k_beacon_send(sc); - spin_unlock_irqrestore(&sc->block, flags); - } } else ath5k_beacon_update_timers(sc, -1); + } else { + ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq); } ath5k_hw_set_imr(ah, sc->imask); + mmiowb(); + spin_unlock_irqrestore(&sc->block, flags); } static void ath5k_tasklet_beacon(unsigned long data) @@ -2806,7 +2798,6 @@ ath5k_remove_interface(struct ieee80211_hw *hw, goto end; ath5k_hw_set_lladdr(sc->ah, mac); - ath5k_beacon_disable(sc); sc->vif = NULL; end: mutex_unlock(&sc->lock); @@ -3135,25 +3126,6 @@ out: return ret; } -/* - * Update the beacon and reconfigure the beacon queues. - */ -static void -ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - int ret; - unsigned long flags; - struct ath5k_softc *sc = hw->priv; - - spin_lock_irqsave(&sc->block, flags); - ret = ath5k_beacon_update(hw, vif); - spin_unlock_irqrestore(&sc->block, flags); - if (ret == 0) { - ath5k_beacon_config(sc); - mmiowb(); - } -} - static void set_beacon_filter(struct ieee80211_hw *hw, bool enable) { @@ -3176,6 +3148,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; + unsigned long flags; mutex_lock(&sc->lock); if (WARN_ON(sc->vif != vif)) @@ -3201,13 +3174,19 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, AR5K_LED_ASSOC : AR5K_LED_INIT); } - if (changes & BSS_CHANGED_BEACON && - (vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MESH_POINT || - vif->type == NL80211_IFTYPE_AP)) { - ath5k_beacon_reconfig(hw, vif); + if (changes & BSS_CHANGED_BEACON) { + spin_lock_irqsave(&sc->block, flags); + ath5k_beacon_update(hw, vif); + spin_unlock_irqrestore(&sc->block, flags); } + if (changes & BSS_CHANGED_BEACON_ENABLED) + sc->enable_beacon = bss_conf->enable_beacon; + + if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | + BSS_CHANGED_BEACON_INT)) + ath5k_beacon_config(sc); + unlock: mutex_unlock(&sc->lock); } diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 65e75fb..778e422 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -190,6 +190,7 @@ struct ath5k_softc { struct timer_list calib_tim; /* calibration timer */ int power_level; /* Requested tx power in dbm */ bool assoc; /* assocate state */ + bool enable_beacon; /* true if beacons are on */ }; #define ath5k_hw_hasbssidmask(_ah) \ -- cgit v0.10.2 From 88f6bfe1829d67bea37b060d53131b2b96ebc8ac Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 4 Jul 2009 12:59:53 -0400 Subject: ath: remove unnecessary return in ath_regd_get_band_ctl 'default' case already returns NO_CTL Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index eef370bd..f37c832 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -569,7 +569,5 @@ u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, default: return NO_CTL; } - - return NO_CTL; } EXPORT_SYMBOL(ath_regd_get_band_ctl); -- cgit v0.10.2 From 0d0cd72fa1e6bfd419c99478ec70b4877ed0ef86 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 4 Jul 2009 12:59:54 -0400 Subject: ath5k: do not release irq across suspend/resume Paraphrasing Rafael J. Wysocki: "drivers should not release PCI IRQs in suspend." Doing so causes a warning during suspend/resume on some platforms. Cc: Rafael J. Wysocki Reported-by: Alan Jenkins Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 4829329..3f55e90 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -674,7 +674,6 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath5k_led_off(sc); - free_irq(pdev->irq, sc); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); @@ -702,18 +701,8 @@ ath5k_pci_resume(struct pci_dev *pdev) */ pci_write_config_byte(pdev, 0x41, 0); - err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); - if (err) { - ATH5K_ERR(sc, "request_irq failed\n"); - goto err_no_irq; - } - ath5k_led_enable(sc); return 0; - -err_no_irq: - pci_disable_device(pdev); - return err; } #endif /* CONFIG_PM */ -- cgit v0.10.2 From 3355443ad7601991affa5992b0d53870335af765 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 4 Jul 2009 21:03:13 -0400 Subject: ath5k: write PCU registers on initial reset "Ath5k: unify resets" introduced a regression into 2.6.28 where the PCU registers are never initialized, due to ath5k_reset() always passing true for change_channel. We subsequently program a lot of these registers but several may start in an unknown state. Cc: stable@kernel.org Reported-by: Forrest Zhang Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 3f55e90..20ba6fa 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2687,7 +2687,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) sc->curchan = chan; sc->curband = &sc->sbands[chan->band]; } - ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true); + ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL); if (ret) { ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret); goto err; -- cgit v0.10.2 From 1be491fca12ff599c37ceaf7e9042ebee9f0068e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 5 Jul 2009 14:51:06 +0200 Subject: rfkill: prep for rfkill API changes We've designed the /dev/rfkill API in a way that we can increase the event struct by adding members at the end, should it become necessary. To validate the events, userspace and the kernel need to have the proper event size to check for -- when reading from the other end they need to verify that it's at least version 1 of the event API, with the current struct size, so define a constant for that and make the code a little more 'future proof'. Not that I expect that we'll have to change the event size any time soon, but it's better to write the code in a way that lends itself to extending. Due to the current size of the event struct, the code is currently equivalent, but should the event struct ever need to be increased the new code might not need changing. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 2ce2983..f3d5812 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -82,6 +82,20 @@ struct rfkill_event { __u8 soft, hard; } __packed; +/* + * We are planning to be backward and forward compatible with changes + * to the event struct, by adding new, optional, members at the end. + * When reading an event (whether the kernel from userspace or vice + * versa) we need to accept anything that's at least as large as the + * version 1 event size, but might be able to accept other sizes in + * the future. + * + * One exception is the kernel -- we already have two event sizes in + * that we've made the 'hard' member optional since our only option + * is to ignore it anyway. + */ +#define RFKILL_EVENT_SIZE_V1 8 + /* ioctl for turning off rfkill-input (if present) */ #define RFKILL_IOC_MAGIC 'R' #define RFKILL_IOC_NOINPUT 1 diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 79693fe..47497c9 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -1076,10 +1076,16 @@ static ssize_t rfkill_fop_write(struct file *file, const char __user *buf, struct rfkill_event ev; /* we don't need the 'hard' variable but accept it */ - if (count < sizeof(ev) - 1) + if (count < RFKILL_EVENT_SIZE_V1 - 1) return -EINVAL; - if (copy_from_user(&ev, buf, sizeof(ev) - 1)) + /* + * Copy as much data as we can accept into our 'ev' buffer, + * but tell userspace how much we've copied so it can determine + * our API version even in a write() call, if it cares. + */ + count = min(count, sizeof(ev)); + if (copy_from_user(&ev, buf, count)) return -EFAULT; if (ev.op != RFKILL_OP_CHANGE && ev.op != RFKILL_OP_CHANGE_ALL) -- cgit v0.10.2 From 6d541a684d7eb72c71eaba82b09a360c96609134 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 6 Jul 2009 15:17:56 +0200 Subject: p54usb: fix stalls caused by urb allocation failures This patch squashes a few old bugs, which have been around since the initial version of p54usb in one form or another. we never freed a orphaned frame, when were denied the resources, which are necessary to pass the data into the usb subsystem. As a result we could end up with a full queue that wasn't emptied, until the device was brought down. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 461d88f..e44460f 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -246,8 +246,10 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb) struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); data_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!data_urb) + if (!data_urb) { + p54_free_skb(dev, skb); return; + } hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len); hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id; @@ -269,27 +271,22 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb) static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; - struct urb *int_urb, *data_urb; + struct urb *int_urb = NULL, *data_urb = NULL; struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); - struct net2280_reg_write *reg; - int err = 0; + struct net2280_reg_write *reg = NULL; + int err = -ENOMEM; reg = kmalloc(sizeof(*reg), GFP_ATOMIC); if (!reg) - return; + goto out; int_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!int_urb) { - kfree(reg); - return; - } + if (!int_urb) + goto out; data_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!data_urb) { - kfree(reg); - usb_free_urb(int_urb); - return; - } + if (!data_urb) + goto out; reg->port = cpu_to_le16(NET2280_DEV_U32); reg->addr = cpu_to_le32(P54U_DEV_BASE); @@ -304,11 +301,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) p54u_tx_dummy_cb, dev); /* - * This flag triggers a code path in the USB subsystem that will - * free what's inside the transfer_buffer after the callback routine - * has completed. + * URB_FREE_BUFFER triggers a code path in the USB subsystem that will + * free what is inside the transfer_buffer after the last reference to + * the int_urb is dropped. */ int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET; + reg = NULL; usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), @@ -329,12 +327,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) usb_unanchor_urb(data_urb); goto out; } - out: +out: usb_free_urb(int_urb); usb_free_urb(data_urb); if (err) { - skb_pull(skb, sizeof(*hdr)); + kfree(reg); p54_free_skb(dev, skb); } } -- cgit v0.10.2 From 2ffa5fede379091bf62a732462b829e4b51af054 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 6 Jul 2009 15:18:13 +0200 Subject: p54: fix queue stall due to underrun Larry Finger discovered a weird behavior under load. In essence, the queue's length count under runs, which in turn renders the associated ac queue unusable. Reported-by: Larry Finger Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 31fda17..6426d2ca 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -199,7 +199,7 @@ static int p54_tx_qos_accounting_alloc(struct p54_common *priv, queue = &priv->tx_stats[p54_queue]; spin_lock_irqsave(&priv->tx_stats_lock, flags); - if (unlikely(queue->len > queue->limit && IS_QOS_QUEUE(p54_queue))) { + if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) { spin_unlock_irqrestore(&priv->tx_stats_lock, flags); return -ENOSPC; } @@ -222,8 +222,11 @@ static void p54_tx_qos_accounting_free(struct p54_common *priv, if (skb && IS_DATA_FRAME(skb)) { struct p54_hdr *hdr = (void *) skb->data; struct p54_tx_data *data = (void *) hdr->data; + unsigned long flags; + spin_lock_irqsave(&priv->tx_stats_lock, flags); priv->tx_stats[data->hw_queue].len--; + spin_unlock_irqrestore(&priv->tx_stats_lock, flags); } p54_wake_queues(priv); } @@ -462,7 +465,6 @@ static void p54_rx_eeprom_readback(struct p54_common *priv, priv->eeprom = NULL; tmp = p54_find_and_unlink_skb(priv, hdr->req_id); - p54_tx_qos_accounting_free(priv, tmp); dev_kfree_skb_any(tmp); complete(&priv->eeprom_comp); } @@ -489,7 +491,6 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb) priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise)); tmp = p54_find_and_unlink_skb(priv, hdr->req_id); - p54_tx_qos_accounting_free(priv, tmp); dev_kfree_skb_any(tmp); } -- cgit v0.10.2 From 3e5d7649a64e558e4146ddfad4dfcf13fc65dd47 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 14:37:26 +0200 Subject: cfg80211: let SME control reassociation vs. association Since we don't really know that well in the kernel, let's let the SME control whether it wants to use reassociation or not, by allowing it to give the previous BSSID in the associate() parameters. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index b34c17f..e496a2d 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -564,6 +564,9 @@ enum nl80211_commands { * @NL80211_ATTR_RESP_IE: (Re)association response information elements as * sent by peer, for ROAM and successful CONNECT events. * + * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE + * commands to specify using a reassociate frame + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -687,6 +690,8 @@ enum nl80211_attrs { NL80211_ATTR_REQ_IE, NL80211_ATTR_RESP_IE, + NL80211_ATTR_PREV_BSSID, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ca986cc..71847d3 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -664,10 +664,11 @@ struct cfg80211_auth_request { * @ie_len: Length of ie buffer in octets * @use_mfp: Use management frame protection (IEEE 802.11w) in this association * @crypto: crypto settings + * @prev_bssid: previous BSSID, if not %NULL use reassociate frame */ struct cfg80211_assoc_request { struct cfg80211_bss *bss; - const u8 *ie; + const u8 *ie, *prev_bssid; size_t ie_len; struct cfg80211_crypto_settings crypto; bool use_mfp; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 0f29cd0..e6d8860 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1256,6 +1256,12 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; } + if (req->prev_bssid) { + sdata->u.mgd.flags |= IEEE80211_STA_PREV_BSSID_SET; + memcpy(sdata->u.mgd.prev_bssid, req->prev_bssid, ETH_ALEN); + } else + sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; + if (req->crypto.control_port) sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; else diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index aa1829a..2448645 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -879,9 +879,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_put(local, bss); } - ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET; - memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN); - ifmgd->last_probe = jiffies; ieee80211_led_assoc(local, 1); @@ -1470,10 +1467,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (status_code != WLAN_STATUS_SUCCESS) { printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", sdata->dev->name, status_code); - /* if this was a reassociation, ensure we try a "full" - * association next time. This works around some broken APs - * which do not correctly reject reassociation requests. */ - ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); /* Wait for SME to decide what to do next */ diff --git a/net/wireless/core.h b/net/wireless/core.h index 82918f5..4554453 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -202,7 +202,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, const u8 *ie, int ie_len); int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, - const u8 *bssid, const u8 *ssid, int ssid_len, + const u8 *bssid, const u8 *prev_bssid, + const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, bool use_mfp, struct cfg80211_crypto_settings *crypt); int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 020f33b..087d337 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -335,7 +335,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, - const u8 *bssid, const u8 *ssid, int ssid_len, + const u8 *bssid, const u8 *prev_bssid, + const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, bool use_mfp, struct cfg80211_crypto_settings *crypt) { @@ -353,6 +354,7 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, req.ie_len = ie_len; memcpy(&req.crypto, crypt, sizeof(req.crypto)); req.use_mfp = use_mfp; + req.prev_bssid = prev_bssid; req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); if (!req.bss) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 723512b..44c520c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -71,6 +71,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, + [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, @@ -3187,7 +3188,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) struct net_device *dev; struct cfg80211_crypto_settings crypto; struct ieee80211_channel *chan; - const u8 *bssid, *ssid, *ie = NULL; + const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; int err, ssid_len, ie_len = 0; bool use_mfp = false; @@ -3248,10 +3249,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) } } + if (info->attrs[NL80211_ATTR_PREV_BSSID]) + prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); + err = nl80211_crypto_settings(info, &crypto, 1); if (!err) - err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, ssid, - ssid_len, ie, ie_len, use_mfp, + err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, + ssid, ssid_len, ie, ie_len, use_mfp, &crypto); out: diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 412161f..066a19e 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -125,8 +125,14 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) case CFG80211_CONN_ASSOCIATE_NEXT: BUG_ON(!drv->ops->assoc); wdev->conn->state = CFG80211_CONN_ASSOCIATING; + /* + * We could, later, implement roaming here and then actually + * set prev_bssid to non-NULL. But then we need to be aware + * that some APs don't like that -- so we'd need to retry + * the association. + */ err = cfg80211_mlme_assoc(drv, wdev->netdev, - params->channel, params->bssid, + params->channel, params->bssid, NULL, params->ssid, params->ssid_len, params->ie, params->ie_len, false, ¶ms->crypto); -- cgit v0.10.2 From a7c1cfc9616ee76213a6d4fd4c17f13fdc92ddce Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:45:16 +0200 Subject: mac80211: remove dead code from mlme The ap_capab and last_probe struct members are unused. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index ffe9add..4c541f0 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -100,7 +100,6 @@ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC); IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE); IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); -IEEE80211_IF_FILE(ap_capab, u.mgd.ap_capab, HEX); IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE); IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC); @@ -186,7 +185,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(prev_bssid, sta); DEBUGFS_ADD(ssid_len, sta); DEBUGFS_ADD(aid, sta); - DEBUGFS_ADD(ap_capab, sta); DEBUGFS_ADD(capab, sta); DEBUGFS_ADD(extra_ie_len, sta); DEBUGFS_ADD(auth_tries, sta); @@ -318,7 +316,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_DEL(prev_bssid, sta); DEBUGFS_DEL(ssid_len, sta); DEBUGFS_DEL(aid, sta); - DEBUGFS_DEL(ap_capab, sta); DEBUGFS_DEL(capab, sta); DEBUGFS_DEL(extra_ie_len, sta); DEBUGFS_DEL(auth_tries, sta); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a550aeb..d0354b1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -268,7 +268,7 @@ struct ieee80211_if_managed { } state; u16 aid; - u16 ap_capab, capab; + u16 capab; u8 *extra_ie; /* to be added to the end of AssocReq */ size_t extra_ie_len; @@ -288,7 +288,6 @@ struct ieee80211_if_managed { unsigned long request; - unsigned long last_probe; unsigned long last_beacon; unsigned int flags; @@ -472,7 +471,6 @@ struct ieee80211_sub_if_data { struct dentry *prev_bssid; struct dentry *ssid_len; struct dentry *aid; - struct dentry *ap_capab; struct dentry *capab; struct dentry *extra_ie_len; struct dentry *auth_tries; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2448645..29575ee 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -879,7 +879,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_put(local, bss); } - ifmgd->last_probe = jiffies; ieee80211_led_assoc(local, 1); sdata->vif.bss_conf.assoc = 1; @@ -1488,7 +1487,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); ifmgd->aid = aid; - ifmgd->ap_capab = capab_info; kfree(ifmgd->assocresp_ies); ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt); -- cgit v0.10.2 From 77fdaa12cea26c204cc12c312fe40bc0f3dcdfd8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:45:17 +0200 Subject: mac80211: rework MLME for multiple authentications Sit tight. This shakes up the world as you know it. Let go of your spaghetti tongs, they will no longer be required, the horrible statemachine in net/mac80211/mlme.c is no more... With the cfg80211 SME mac80211 now has much less to keep track of, but, on the other hand, for FT it needs to be able to keep track of at least one authentication being in progress while associated. So convert from a single state machine to having small ones for all the different things we need to do. For real FT it will still need work wrt. PS, but this should be a good step. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e6d8860..7cfc14e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1172,122 +1172,25 @@ static int ieee80211_scan(struct wiphy *wiphy, static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_auth_request *req) { - struct ieee80211_sub_if_data *sdata; - const u8 *ssid; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (req->auth_type) { - case NL80211_AUTHTYPE_OPEN_SYSTEM: - sdata->u.mgd.auth_alg = WLAN_AUTH_OPEN; - break; - case NL80211_AUTHTYPE_SHARED_KEY: - sdata->u.mgd.auth_alg = WLAN_AUTH_SHARED_KEY; - break; - case NL80211_AUTHTYPE_FT: - sdata->u.mgd.auth_alg = WLAN_AUTH_FT; - break; - case NL80211_AUTHTYPE_NETWORK_EAP: - sdata->u.mgd.auth_alg = WLAN_AUTH_LEAP; - break; - default: - return -EOPNOTSUPP; - } - - memcpy(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN); - - sdata->local->oper_channel = req->bss->channel; - ieee80211_hw_config(sdata->local, 0); - - ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - if (!ssid) - return -EINVAL; - sdata->u.mgd.ssid_len = *(ssid + 1); - memcpy(sdata->u.mgd.ssid, ssid + 2, sdata->u.mgd.ssid_len); - - kfree(sdata->u.mgd.sme_auth_ie); - sdata->u.mgd.sme_auth_ie = NULL; - sdata->u.mgd.sme_auth_ie_len = 0; - if (req->ie) { - sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL); - if (sdata->u.mgd.sme_auth_ie == NULL) - return -ENOMEM; - memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len); - sdata->u.mgd.sme_auth_ie_len = req->ie_len; - } - - sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE; - ieee80211_sta_req_auth(sdata); - return 0; + return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_assoc_request *req) { - struct ieee80211_sub_if_data *sdata; - int ret, i; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (memcmp(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN) != 0 || - !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) - return -ENOLINK; /* not authenticated */ - - sdata->u.mgd.flags &= ~IEEE80211_STA_DISABLE_11N; - - for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) - if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || - req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || - req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) - sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N; - - sdata->local->oper_channel = req->bss->channel; - ieee80211_hw_config(sdata->local, 0); - - ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); - if (ret && ret != -EALREADY) - return ret; - - if (req->use_mfp) { - sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; - sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; - } else { - sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; - sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; - } - - if (req->prev_bssid) { - sdata->u.mgd.flags |= IEEE80211_STA_PREV_BSSID_SET; - memcpy(sdata->u.mgd.prev_bssid, req->prev_bssid, ETH_ALEN); - } else - sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - - if (req->crypto.control_port) - sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; - else - sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - - sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; - ieee80211_sta_req_auth(sdata); - return 0; + return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - /* TODO: req->ie, req->peer_addr */ - return ieee80211_sta_deauthenticate(sdata, req->reason_code); + return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - /* TODO: req->ie, req->peer_addr */ - return ieee80211_sta_disassociate(sdata, req->reason_code); + return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 4c541f0..e9ec6ca 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -95,29 +95,9 @@ IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); /* STA attributes */ -IEEE80211_IF_FILE(state, u.mgd.state, DEC); IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); -IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC); -IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE); IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); -IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE); -IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC); -IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC); -IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC); -IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC); - -static ssize_t ieee80211_if_fmt_flags( - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) -{ - return scnprintf(buf, buflen, "%s%s%s%s%s\n", - sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", - sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", - sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", - sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", - sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : ""); -} -__IEEE80211_IF_FILE(flags); /* AP attributes */ IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); @@ -180,18 +160,9 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(force_unicast_rateidx, sta); DEBUGFS_ADD(max_ratectrl_rateidx, sta); - DEBUGFS_ADD(state, sta); DEBUGFS_ADD(bssid, sta); - DEBUGFS_ADD(prev_bssid, sta); - DEBUGFS_ADD(ssid_len, sta); DEBUGFS_ADD(aid, sta); DEBUGFS_ADD(capab, sta); - DEBUGFS_ADD(extra_ie_len, sta); - DEBUGFS_ADD(auth_tries, sta); - DEBUGFS_ADD(assoc_tries, sta); - DEBUGFS_ADD(auth_alg, sta); - DEBUGFS_ADD(auth_transaction, sta); - DEBUGFS_ADD(flags, sta); } static void add_ap_files(struct ieee80211_sub_if_data *sdata) @@ -311,18 +282,9 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_DEL(force_unicast_rateidx, sta); DEBUGFS_DEL(max_ratectrl_rateidx, sta); - DEBUGFS_DEL(state, sta); DEBUGFS_DEL(bssid, sta); - DEBUGFS_DEL(prev_bssid, sta); - DEBUGFS_DEL(ssid_len, sta); DEBUGFS_DEL(aid, sta); DEBUGFS_DEL(capab, sta); - DEBUGFS_DEL(extra_ie_len, sta); - DEBUGFS_DEL(auth_tries, sta); - DEBUGFS_DEL(assoc_tries, sta); - DEBUGFS_DEL(auth_alg, sta); - DEBUGFS_DEL(auth_transaction, sta); - DEBUGFS_DEL(flags, sta); } static void del_ap_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d0354b1..2e92bbd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -227,11 +227,32 @@ struct mesh_preq_queue { u8 flags; }; +enum ieee80211_mgd_state { + IEEE80211_MGD_STATE_IDLE, + IEEE80211_MGD_STATE_PROBE, + IEEE80211_MGD_STATE_AUTH, + IEEE80211_MGD_STATE_ASSOC, +}; + +struct ieee80211_mgd_work { + struct list_head list; + struct ieee80211_bss *bss; + int ie_len; + u8 prev_bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + unsigned long timeout; + enum ieee80211_mgd_state state; + u16 auth_alg, auth_transaction; + + int tries; + + /* must be last */ + u8 ie[0]; /* for auth or assoc frame, not probe */ +}; + /* flags used in struct ieee80211_if_managed.flags */ enum ieee80211_sta_flags { - IEEE80211_STA_PREV_BSSID_SET = BIT(0), - IEEE80211_STA_AUTHENTICATED = BIT(1), - IEEE80211_STA_ASSOCIATED = BIT(2), IEEE80211_STA_PROBEREQ_POLL = BIT(3), IEEE80211_STA_CONTROL_PORT = BIT(4), IEEE80211_STA_WMM_ENABLED = BIT(5), @@ -243,8 +264,6 @@ enum ieee80211_sta_flags { /* flags for MLME request */ enum ieee80211_sta_request { IEEE80211_STA_REQ_SCAN, - IEEE80211_STA_REQ_AUTH, - IEEE80211_STA_REQ_RUN, }; struct ieee80211_if_managed { @@ -254,35 +273,17 @@ struct ieee80211_if_managed { struct work_struct chswitch_work; struct work_struct beacon_loss_work; - u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; + struct mutex mtx; + struct ieee80211_bss *associated; + struct list_head work_list; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - size_t ssid_len; - - enum { - IEEE80211_STA_MLME_DISABLED, - IEEE80211_STA_MLME_DIRECT_PROBE, - IEEE80211_STA_MLME_AUTHENTICATE, - IEEE80211_STA_MLME_ASSOCIATE, - IEEE80211_STA_MLME_ASSOCIATED, - } state; + u8 bssid[ETH_ALEN]; u16 aid; u16 capab; - u8 *extra_ie; /* to be added to the end of AssocReq */ - size_t extra_ie_len; - - /* The last AssocReq/Resp IEs */ - u8 *assocreq_ies, *assocresp_ies; - size_t assocreq_ies_len, assocresp_ies_len; struct sk_buff_head skb_queue; - int assoc_scan_tries; /* number of scans done pre-association */ - int direct_probe_tries; /* retries for direct probes */ - int auth_tries; /* retries for auth req */ - int assoc_tries; /* retries for assoc req */ - unsigned long timers_running; /* used for quiesce/restart */ bool powersave; /* powersave requested for this iface */ @@ -292,9 +293,6 @@ struct ieee80211_if_managed { unsigned int flags; - int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ - int auth_transaction; - u32 beacon_crc; enum { @@ -304,10 +302,6 @@ struct ieee80211_if_managed { } mfp; /* management frame protection */ int wmm_last_param_set; - - /* Extra IE data for management frames */ - u8 *sme_auth_ie; - size_t sme_auth_ie_len; }; enum ieee80211_ibss_request { @@ -466,18 +460,9 @@ struct ieee80211_sub_if_data { union { struct { struct dentry *drop_unencrypted; - struct dentry *state; struct dentry *bssid; - struct dentry *prev_bssid; - struct dentry *ssid_len; struct dentry *aid; struct dentry *capab; - struct dentry *extra_ie_len; - struct dentry *auth_tries; - struct dentry *assoc_tries; - struct dentry *auth_alg; - struct dentry *auth_transaction; - struct dentry *flags; struct dentry *force_unicast_rateidx; struct dentry *max_ratectrl_rateidx; } sta; @@ -928,11 +913,16 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; /* STA code */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); +int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, + struct cfg80211_auth_request *req); +int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, + struct cfg80211_assoc_request *req); +int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, + struct cfg80211_deauth_request *req); +int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, + struct cfg80211_disassoc_request *req); ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata); -int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); -int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); @@ -966,8 +956,6 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, void ieee80211_scan_cancel(struct ieee80211_local *local); ieee80211_rx_result ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, - const char *ie, size_t len); void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); struct ieee80211_bss * @@ -983,8 +971,6 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, u8 *ssid, u8 ssid_len); void ieee80211_rx_bss_put(struct ieee80211_local *local, struct ieee80211_bss *bss); -void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, - int freq, u8 *ssid, u8 ssid_len); /* interface handling */ int ieee80211_if_add(struct ieee80211_local *local, const char *name, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b87bf42..4839a2d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -233,9 +233,6 @@ static int ieee80211_open(struct net_device *dev) ieee80211_configure_filter(local); netif_addr_unlock_bh(local->mdev); break; - case NL80211_IFTYPE_STATION: - sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - /* fall through */ default: conf.vif = &sdata->vif; conf.type = sdata->vif.type; @@ -366,18 +363,6 @@ static int ieee80211_stop(struct net_device *dev) rcu_read_unlock(); /* - * Announce that we are leaving the network, in case we are a - * station interface type. This must be done before removing - * all stations associated with sta_info_flush, otherwise STA - * information will be gone and no announce being done. - */ - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED) - ieee80211_sta_deauthenticate(sdata, - WLAN_REASON_DEAUTH_LEAVING); - } - - /* * Remove all stations associated with this interface. * * This must be done before calling ops->remove_interface() @@ -462,7 +447,6 @@ static int ieee80211_stop(struct net_device *dev) netif_addr_unlock_bh(local->mdev); break; case NL80211_IFTYPE_STATION: - memset(sdata->u.mgd.bssid, 0, ETH_ALEN); del_timer_sync(&sdata->u.mgd.chswitch_timer); del_timer_sync(&sdata->u.mgd.timer); /* @@ -485,10 +469,6 @@ static int ieee80211_stop(struct net_device *dev) */ synchronize_rcu(); skb_queue_purge(&sdata->u.mgd.skb_queue); - - kfree(sdata->u.mgd.extra_ie); - sdata->u.mgd.extra_ie = NULL; - sdata->u.mgd.extra_ie_len = 0; /* fall through */ case NL80211_IFTYPE_ADHOC: if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { @@ -650,11 +630,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev) kfree_skb(sdata->u.ibss.presp); break; case NL80211_IFTYPE_STATION: - kfree(sdata->u.mgd.extra_ie); - kfree(sdata->u.mgd.assocreq_ies); - kfree(sdata->u.mgd.assocresp_ies); - kfree(sdata->u.mgd.sme_auth_ie); - break; case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_MONITOR: @@ -937,7 +912,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) continue; /* do not count disabled managed interfaces */ if (sdata->vif.type == NL80211_IFTYPE_STATION && - sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED) + !sdata->u.mgd.associated && + list_empty(&sdata->u.mgd.work_list)) continue; /* do not count unused IBSS interfaces */ if (sdata->vif.type == NL80211_IFTYPE_ADHOC && diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 29575ee..108e8c9 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -27,20 +27,51 @@ #include "rate.h" #include "led.h" -#define IEEE80211_ASSOC_SCANS_MAX_TRIES 2 #define IEEE80211_AUTH_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_MAX_TRIES 3 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_ASSOC_MAX_TRIES 3 #define IEEE80211_MONITORING_INTERVAL (2 * HZ) #define IEEE80211_PROBE_WAIT (HZ / 5) -#define IEEE80211_PROBE_IDLE_TIME (60 * HZ) -#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) #define TMR_RUNNING_TIMER 0 #define TMR_RUNNING_CHANSW 1 +/* + * All cfg80211 functions have to be called outside a locked + * section so that they can acquire a lock themselves... This + * is much simpler than queuing up things in cfg80211, but we + * do need some indirection for that here. + */ +enum rx_mgmt_action { + /* no action required */ + RX_MGMT_NONE, + + /* caller must call cfg80211_send_rx_auth() */ + RX_MGMT_CFG80211_AUTH, + + /* caller must call cfg80211_send_rx_assoc() */ + RX_MGMT_CFG80211_ASSOC, + + /* caller must call cfg80211_send_deauth() */ + RX_MGMT_CFG80211_DEAUTH, + + /* caller must call cfg80211_send_disassoc() */ + RX_MGMT_CFG80211_DISASSOC, + + /* caller must call cfg80211_auth_timeout() & free work */ + RX_MGMT_CFG80211_AUTH_TO, + + /* caller must call cfg80211_assoc_timeout() & free work */ + RX_MGMT_CFG80211_ASSOC_TO, +}; + /* utils */ +static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) +{ + WARN_ON(!mutex_is_locked(&ifmgd->mtx)); +} + static int ecw2cw(int ecw) { return (1 << ecw) - 1; @@ -74,11 +105,10 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, */ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, struct ieee80211_ht_info *hti, - u16 ap_ht_cap_flags) + const u8 *bssid, u16 ap_ht_cap_flags) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct sta_info *sta; u32 changed = 0; u16 ht_opmode; @@ -127,12 +157,10 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, ieee80211_hw_config(local, 0); rcu_read_lock(); - - sta = sta_info_get(local, ifmgd->bssid); + sta = sta_info_get(local, bssid); if (sta) rate_control_rate_update(local, sband, sta, IEEE80211_RC_HT_CHANGED); - rcu_read_unlock(); } @@ -155,7 +183,8 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, /* frame sending functions */ -static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) +static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -165,14 +194,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) const u8 *ies, *ht_ie; int i, len, count, rates_len, supp_rates_len; u16 capab; - struct ieee80211_bss *bss; int wmm = 0; struct ieee80211_supported_band *sband; u32 rates = 0; skb = dev_alloc_skb(local->hw.extra_tx_headroom + - sizeof(*mgmt) + 200 + ifmgd->extra_ie_len + - ifmgd->ssid_len); + sizeof(*mgmt) + 200 + wk->ie_len + + wk->ssid_len); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " "frame\n", sdata->dev->name); @@ -191,45 +219,35 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; } - bss = ieee80211_rx_bss_get(local, ifmgd->bssid, - local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (bss) { - if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) - capab |= WLAN_CAPABILITY_PRIVACY; - if (bss->wmm_used) - wmm = 1; + if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) + capab |= WLAN_CAPABILITY_PRIVACY; + if (wk->bss->wmm_used) + wmm = 1; - /* get all rates supported by the device and the AP as - * some APs don't like getting a superset of their rates - * in the association request (e.g. D-Link DAP 1353 in - * b-only mode) */ - rates_len = ieee80211_compatible_rates(bss, sband, &rates); + /* get all rates supported by the device and the AP as + * some APs don't like getting a superset of their rates + * in the association request (e.g. D-Link DAP 1353 in + * b-only mode) */ + rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates); - if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && - (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) - capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; - - ieee80211_rx_bss_put(local, bss); - } else { - rates = ~0; - rates_len = sband->n_bitrates; - } + if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && + (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) + capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); - memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN); - if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) { + if (!is_zero_ether_addr(wk->prev_bssid)) { skb_put(skb, 10); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_REQ); mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); mgmt->u.reassoc_req.listen_interval = cpu_to_le16(local->hw.conf.listen_interval); - memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid, + memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid, ETH_ALEN); } else { skb_put(skb, 4); @@ -241,10 +259,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } /* SSID */ - ies = pos = skb_put(skb, 2 + ifmgd->ssid_len); + ies = pos = skb_put(skb, 2 + wk->ssid_len); *pos++ = WLAN_EID_SSID; - *pos++ = ifmgd->ssid_len; - memcpy(pos, ifmgd->ssid, ifmgd->ssid_len); + *pos++ = wk->ssid_len; + memcpy(pos, wk->ssid, wk->ssid_len); /* add all rates which were marked to be used above */ supp_rates_len = rates_len; @@ -299,9 +317,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } } - if (ifmgd->extra_ie) { - pos = skb_put(skb, ifmgd->extra_ie_len); - memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len); + if (wk->ie_len && wk->ie) { + pos = skb_put(skb, wk->ie_len); + memcpy(pos, wk->ie, wk->ie_len); } if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { @@ -326,7 +344,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) */ if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && sband->ht_cap.ht_supported && - (ht_ie = ieee80211_bss_get_ie(&bss->cbss, WLAN_EID_HT_INFORMATION)) && + (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) && ht_ie[1] >= sizeof(struct ieee80211_ht_info) && (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { struct ieee80211_ht_info *ht_info = @@ -363,18 +381,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); } - kfree(ifmgd->assocreq_ies); - ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies; - ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL); - if (ifmgd->assocreq_ies) - memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len); - ieee80211_tx_skb(sdata, skb, 0); } static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, - u16 stype, u16 reason) + const u8 *bssid, u16 stype, u16 reason) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -391,9 +403,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); - memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->da, bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->bssid, bssid, ETH_ALEN); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); skb_put(skb, 2); /* u.deauth.reason_code == u.disassoc.reason_code */ @@ -477,28 +489,26 @@ static void ieee80211_chswitch_work(struct work_struct *work) { struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); - struct ieee80211_bss *bss; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; if (!netif_running(sdata->dev)) return; - bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (!bss) - goto exit; + mutex_lock(&ifmgd->mtx); + if (!ifmgd->associated) + goto out; sdata->local->oper_channel = sdata->local->csa_channel; + ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); + /* XXX: shouldn't really modify cfg80211-owned data! */ - if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) - bss->cbss.channel = sdata->local->oper_channel; + ifmgd->associated->cbss.channel = sdata->local->oper_channel; - ieee80211_rx_bss_put(sdata->local, bss); -exit: - ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; ieee80211_wake_queues_by_reason(&sdata->local->hw, IEEE80211_QUEUE_STOP_REASON_CSA); + out: + ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; + mutex_unlock(&ifmgd->mtx); } static void ieee80211_chswitch_timer(unsigned long data) @@ -523,7 +533,9 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); - if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) + ASSERT_MGD_MTX(ifmgd); + + if (!ifmgd->associated) return; if (sdata->local->sw_scanning || sdata->local->hw_scanning) @@ -634,7 +646,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) } if (count == 1 && found->u.mgd.powersave && - (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) && + found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { s32 beaconint_us; @@ -789,9 +801,6 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, u16 capab, bool erp_valid, u8 erp) { struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; -#endif u32 changed = 0; bool use_protection; bool use_short_preamble; @@ -808,42 +817,16 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); if (use_protection != bss_conf->use_cts_prot) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", - sdata->dev->name, - use_protection ? "enabled" : "disabled", - ifmgd->bssid); - } -#endif bss_conf->use_cts_prot = use_protection; changed |= BSS_CHANGED_ERP_CTS_PROT; } if (use_short_preamble != bss_conf->use_short_preamble) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: switched to %s barker preamble" - " (BSSID=%pM)\n", - sdata->dev->name, - use_short_preamble ? "short" : "long", - ifmgd->bssid); - } -#endif bss_conf->use_short_preamble = use_short_preamble; changed |= BSS_CHANGED_ERP_PREAMBLE; } if (use_short_slot != bss_conf->use_short_slot) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: switched to %s slot time" - " (BSSID=%pM)\n", - sdata->dev->name, - use_short_slot ? "short" : "long", - ifmgd->bssid); - } -#endif bss_conf->use_short_slot = use_short_slot; changed |= BSS_CHANGED_ERP_SLOT; } @@ -852,32 +835,23 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, + struct ieee80211_bss *bss, u32 bss_info_changed) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - struct ieee80211_conf *conf = &local_to_hw(local)->conf; - - struct ieee80211_bss *bss; bss_info_changed |= BSS_CHANGED_ASSOC; - ifmgd->flags |= IEEE80211_STA_ASSOCIATED; + /* set timing information */ + sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; + sdata->vif.bss_conf.timestamp = bss->cbss.tsf; + sdata->vif.bss_conf.dtim_period = bss->dtim_period; - bss = ieee80211_rx_bss_get(local, ifmgd->bssid, - conf->channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (bss) { - /* set timing information */ - sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; - sdata->vif.bss_conf.timestamp = bss->cbss.tsf; - sdata->vif.bss_conf.dtim_period = bss->dtim_period; + bss_info_changed |= BSS_CHANGED_BEACON_INT; + bss_info_changed |= ieee80211_handle_bss_capability(sdata, + bss->cbss.capability, bss->has_erp_value, bss->erp_value); - bss_info_changed |= BSS_CHANGED_BEACON_INT; - bss_info_changed |= ieee80211_handle_bss_capability(sdata, - bss->cbss.capability, bss->has_erp_value, bss->erp_value); - - ieee80211_rx_bss_put(local, bss); - } + sdata->u.mgd.associated = bss; + memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); ieee80211_led_assoc(local, 1); @@ -905,152 +879,133 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, netif_carrier_on(sdata->dev); } -static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) +static enum rx_mgmt_action __must_check +ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - ifmgd->direct_probe_tries++; - if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { + wk->tries++; + if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", - sdata->dev->name, ifmgd->bssid); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, - GFP_KERNEL); + sdata->dev->name, wk->bss->cbss.bssid); /* * Most likely AP is not in the range so remove the - * bss information associated to the AP + * bss struct for that AP. */ - ieee80211_rx_bss_remove(sdata, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); + cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); /* * We might have a pending scan which had no chance to run yet - * due to state == IEEE80211_STA_MLME_DIRECT_PROBE. - * Hence, queue the STAs work again + * due to work needing to be done. Hence, queue the STAs work + * again for that. */ queue_work(local->hw.workqueue, &ifmgd->work); - return; + return RX_MGMT_CFG80211_AUTH_TO; } - printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", - sdata->dev->name, ifmgd->bssid, - ifmgd->direct_probe_tries); + printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", + sdata->dev->name, wk->bss->cbss.bssid, + wk->tries); - ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; - - /* Direct probe is sent to broadcast address as some APs + /* + * Direct probe is sent to broadcast address as some APs * will not answer to direct packet in unassociated state. */ - ieee80211_send_probe_req(sdata, NULL, - ifmgd->ssid, ifmgd->ssid_len, NULL, 0); + ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0); + + wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + mod_timer(&ifmgd->timer, wk->timeout); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); + return RX_MGMT_NONE; } -static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) +static enum rx_mgmt_action __must_check +ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - ifmgd->auth_tries++; - if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { + wk->tries++; + if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { printk(KERN_DEBUG "%s: authentication with AP %pM" " timed out\n", - sdata->dev->name, ifmgd->bssid); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, - GFP_KERNEL); - ieee80211_rx_bss_remove(sdata, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); + sdata->dev->name, wk->bss->cbss.bssid); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); /* * We might have a pending scan which had no chance to run yet - * due to state == IEEE80211_STA_MLME_AUTHENTICATE. - * Hence, queue the STAs work again + * due to work needing to be done. Hence, queue the STAs work + * again for that. */ queue_work(local->hw.workqueue, &ifmgd->work); - return; + return RX_MGMT_CFG80211_AUTH_TO; } - ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; - printk(KERN_DEBUG "%s: authenticate with AP %pM\n", - sdata->dev->name, ifmgd->bssid); + printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", + sdata->dev->name, wk->bss->cbss.bssid, wk->tries); + + ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, + wk->bss->cbss.bssid, 0); + wk->auth_transaction = 2; - ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ifmgd->sme_auth_ie, - ifmgd->sme_auth_ie_len, ifmgd->bssid, 0); - ifmgd->auth_transaction = 2; + wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + mod_timer(&ifmgd->timer, wk->timeout); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); + return RX_MGMT_NONE; } -/* - * The disassoc 'reason' argument can be either our own reason - * if self disconnected or a reason code from the AP. - */ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, - bool deauth, bool self_disconnected, - u16 reason) + const u8 *bssid, bool deauth) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - struct ieee80211_conf *conf = &local_to_hw(local)->conf; - struct ieee80211_bss *bss; struct sta_info *sta; u32 changed = 0, config_changed = 0; - if (deauth) { - ifmgd->direct_probe_tries = 0; - ifmgd->auth_tries = 0; - } - ifmgd->assoc_scan_tries = 0; - ifmgd->assoc_tries = 0; + ASSERT_MGD_MTX(ifmgd); + + ifmgd->associated = NULL; + memset(ifmgd->bssid, 0, ETH_ALEN); + + /* + * we need to commit the associated = NULL change because the + * scan code uses that to determine whether this iface should + * go to/wake up from powersave or not -- and could otherwise + * wake the queues erroneously. + */ + smp_mb(); + + /* + * Thus, we can only afterwards stop the queues -- to account + * for the case where another CPU is finishing a scan at this + * time -- we don't want the scan code to enable queues. + */ netif_tx_stop_all_queues(sdata->dev); netif_carrier_off(sdata->dev); rcu_read_lock(); - sta = sta_info_get(local, ifmgd->bssid); + sta = sta_info_get(local, bssid); if (sta) ieee80211_sta_tear_down_BA_sessions(sta); rcu_read_unlock(); - bss = ieee80211_rx_bss_get(local, ifmgd->bssid, - conf->channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - - if (bss) - ieee80211_rx_bss_put(local, bss); - - if (self_disconnected) { - if (deauth) - ieee80211_send_deauth_disassoc(sdata, - IEEE80211_STYPE_DEAUTH, reason); - else - ieee80211_send_deauth_disassoc(sdata, - IEEE80211_STYPE_DISASSOC, reason); - } - - ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; changed |= ieee80211_reset_erp_info(sdata); ieee80211_led_assoc(local, 0); changed |= BSS_CHANGED_ASSOC; sdata->vif.bss_conf.assoc = false; - if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_rx_bss_remove(sdata, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - } - ieee80211_set_wmm_default(sdata); ieee80211_recalc_idle(local); @@ -1079,7 +1034,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); - sta = sta_info_get(local, ifmgd->bssid); + sta = sta_info_get(local, bssid); if (!sta) { rcu_read_unlock(); return; @@ -1092,38 +1047,42 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sta_info_destroy(sta); } -static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) +static enum rx_mgmt_action __must_check +ieee80211_associate(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - ifmgd->assoc_tries++; - if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { + wk->tries++; + if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) { printk(KERN_DEBUG "%s: association with AP %pM" " timed out\n", - sdata->dev->name, ifmgd->bssid); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid, - GFP_KERNEL); - ieee80211_rx_bss_remove(sdata, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); + sdata->dev->name, wk->bss->cbss.bssid); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); + /* * We might have a pending scan which had no chance to run yet - * due to state == IEEE80211_STA_MLME_ASSOCIATE. - * Hence, queue the STAs work again + * due to work needing to be done. Hence, queue the STAs work + * again for that. */ queue_work(local->hw.workqueue, &ifmgd->work); - return; + return RX_MGMT_CFG80211_ASSOC_TO; } - ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; - printk(KERN_DEBUG "%s: associate with AP %pM\n", - sdata->dev->name, ifmgd->bssid); - ieee80211_send_assoc(sdata); + printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", + sdata->dev->name, wk->bss->cbss.bssid, wk->tries); + ieee80211_send_assoc(sdata, wk); + + wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; + mod_timer(&ifmgd->timer, wk->timeout); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); + return RX_MGMT_NONE; } void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, @@ -1148,6 +1107,7 @@ void ieee80211_beacon_loss_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.beacon_loss_work); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + const u8 *ssid; /* * The driver has already reported this event and we have @@ -1160,12 +1120,15 @@ void ieee80211_beacon_loss_work(struct work_struct *work) if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) return; + mutex_lock(&ifmgd->mtx); + + if (!ifmgd->associated) + goto out; + #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM " - "- sending probe request\n", sdata->dev->name, - sdata->u.mgd.bssid); - } + if (net_ratelimit()) + printk(KERN_DEBUG "%s: driver reports beacon loss from AP " + "- sending probe request\n", sdata->dev->name); #endif ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; @@ -1174,10 +1137,13 @@ void ieee80211_beacon_loss_work(struct work_struct *work) ieee80211_recalc_ps(sdata->local, -1); mutex_unlock(&sdata->local->iflist_mtx); - ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, - ifmgd->ssid_len, NULL, 0); + ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); + ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, + ssid + 2, ssid[1], NULL, 0); mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); + out: + mutex_unlock(&ifmgd->mtx); } void ieee80211_beacon_loss(struct ieee80211_vif *vif) @@ -1189,102 +1155,16 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) } EXPORT_SYMBOL(ieee80211_beacon_loss); -static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) +static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - struct sta_info *sta; - unsigned long last_rx; - bool disassoc = false; - - /* TODO: start monitoring current AP signal quality and number of - * missed beacons. Scan other channels every now and then and search - * for better APs. */ - /* TODO: remove expired BSSes */ - - ifmgd->state = IEEE80211_STA_MLME_ASSOCIATED; - - rcu_read_lock(); - - sta = sta_info_get(local, ifmgd->bssid); - if (!sta) { - printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", - sdata->dev->name, ifmgd->bssid); - disassoc = true; - rcu_read_unlock(); - goto out; - } - - last_rx = sta->last_rx; - rcu_read_unlock(); - - if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && - time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) { - printk(KERN_DEBUG "%s: no probe response from AP %pM " - "- disassociating\n", - sdata->dev->name, ifmgd->bssid); - disassoc = true; - ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; - goto out; - } - - /* - * Beacon filtering is only enabled with power save and then the - * stack should not check for beacon loss. - */ - if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) && - (local->hw.conf.flags & IEEE80211_CONF_PS)) && - time_after(jiffies, - ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: beacon loss from AP %pM " - "- sending probe request\n", - sdata->dev->name, ifmgd->bssid); - } -#endif - ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; - mutex_lock(&local->iflist_mtx); - ieee80211_recalc_ps(local, -1); - mutex_unlock(&local->iflist_mtx); - ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, - ifmgd->ssid_len, NULL, 0); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); - goto out; - } - - if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) { - ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; - mutex_lock(&local->iflist_mtx); - ieee80211_recalc_ps(local, -1); - mutex_unlock(&local->iflist_mtx); - ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, - ifmgd->ssid_len, NULL, 0); - } - - out: - if (!disassoc) - mod_timer(&ifmgd->timer, - jiffies + IEEE80211_MONITORING_INTERVAL); - else - ieee80211_set_disassoc(sdata, true, true, - WLAN_REASON_PREV_AUTH_NOT_VALID); -} - - -static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - + wk->state = IEEE80211_MGD_STATE_IDLE; printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); - ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; - /* Wait for SME to request association */ - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(sdata->local); } static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, struct ieee80211_mgmt *mgmt, size_t len) { @@ -1295,120 +1175,132 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); if (!elems.challenge) return; - ieee80211_send_auth(sdata, 3, sdata->u.mgd.auth_alg, + ieee80211_send_auth(sdata, 3, wk->auth_alg, elems.challenge - 2, elems.challenge_len + 2, - sdata->u.mgd.bssid, 1); - sdata->u.mgd.auth_transaction = 4; + wk->bss->cbss.bssid, 1); + wk->auth_transaction = 4; } -static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len) +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, size_t len) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u16 auth_alg, auth_transaction, status_code; - if (ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE) - return; + if (wk->state != IEEE80211_MGD_STATE_AUTH) + return RX_MGMT_NONE; if (len < 24 + 6) - return; + return RX_MGMT_NONE; - if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) - return; + if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) + return RX_MGMT_NONE; - if (memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) - return; + if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) + return RX_MGMT_NONE; auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); status_code = le16_to_cpu(mgmt->u.auth.status_code); - if (auth_alg != ifmgd->auth_alg || - auth_transaction != ifmgd->auth_transaction) - return; + if (auth_alg != wk->auth_alg || + auth_transaction != wk->auth_transaction) + return RX_MGMT_NONE; if (status_code != WLAN_STATUS_SUCCESS) { - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, - GFP_KERNEL); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(sdata->local); - return; + list_del(&wk->list); + kfree(wk); + return RX_MGMT_CFG80211_AUTH; } - switch (ifmgd->auth_alg) { + switch (wk->auth_alg) { case WLAN_AUTH_OPEN: case WLAN_AUTH_LEAP: case WLAN_AUTH_FT: - ieee80211_auth_completed(sdata); - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, - GFP_KERNEL); - break; + ieee80211_auth_completed(sdata, wk); + return RX_MGMT_CFG80211_AUTH; case WLAN_AUTH_SHARED_KEY: - if (ifmgd->auth_transaction == 4) { - ieee80211_auth_completed(sdata); - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, - GFP_KERNEL); + if (wk->auth_transaction == 4) { + ieee80211_auth_completed(sdata, wk); + return RX_MGMT_CFG80211_AUTH; } else - ieee80211_auth_challenge(sdata, mgmt, len); + ieee80211_auth_challenge(sdata, wk, mgmt, len); break; } + + return RX_MGMT_NONE; } -static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len) +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + const u8 *bssid = NULL; u16 reason_code; if (len < 24 + 2) - return; + return RX_MGMT_NONE; - if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) - return; + ASSERT_MGD_MTX(ifmgd); + + if (wk) + bssid = wk->bss->cbss.bssid; + else + bssid = ifmgd->associated->cbss.bssid; reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - if (ifmgd->flags & IEEE80211_STA_AUTHENTICATED) - printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", - sdata->dev->name, reason_code); + printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", + sdata->dev->name, bssid, reason_code); + + if (!wk) { + ieee80211_set_disassoc(sdata, bssid, true); + } else { + list_del(&wk->list); + kfree(wk); + } - ieee80211_set_disassoc(sdata, true, false, 0); - ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); + return RX_MGMT_CFG80211_DEAUTH; } -static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len) +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u16 reason_code; if (len < 24 + 2) - return; + return RX_MGMT_NONE; - if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) - return; + ASSERT_MGD_MTX(ifmgd); + + if (WARN_ON(!ifmgd->associated)) + return RX_MGMT_NONE; + + if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN))) + return RX_MGMT_NONE; reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - if (ifmgd->flags & IEEE80211_STA_ASSOCIATED) - printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", - sdata->dev->name, reason_code); + printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", + sdata->dev->name, reason_code); - ieee80211_set_disassoc(sdata, false, false, reason_code); - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); + ieee80211_set_disassoc(sdata, ifmgd->associated->cbss.bssid, false); + return RX_MGMT_CFG80211_DISASSOC; } -static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len, - int reassoc) +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, size_t len, + bool reassoc) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -1424,17 +1316,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, bool have_higher_than_11mbit = false, newsta = false; u16 ap_ht_cap_flags; - /* AssocResp and ReassocResp have identical structure, so process both - * of them in this function. */ - - if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) - return; + /* + * AssocResp and ReassocResp have identical structure, so process both + * of them in this function. + */ if (len < 24 + 6) - return; + return RX_MGMT_NONE; - if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) - return; + if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) + return RX_MGMT_NONE; capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); @@ -1457,21 +1348,19 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: AP rejected association temporarily; " "comeback duration %u TU (%u ms)\n", sdata->dev->name, tu, ms); + wk->timeout = jiffies + msecs_to_jiffies(ms); if (ms > IEEE80211_ASSOC_TIMEOUT) mod_timer(&ifmgd->timer, jiffies + msecs_to_jiffies(ms)); - return; + return RX_MGMT_NONE; } if (status_code != WLAN_STATUS_SUCCESS) { printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", sdata->dev->name, status_code); - cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, - GFP_KERNEL); - /* Wait for SME to decide what to do next */ - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - return; + list_del(&wk->list); + kfree(wk); + return RX_MGMT_CFG80211_ASSOC; } if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) @@ -1482,50 +1371,38 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (!elems.supp_rates) { printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", sdata->dev->name); - return; + return RX_MGMT_NONE; } printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); ifmgd->aid = aid; - kfree(ifmgd->assocresp_ies); - ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt); - ifmgd->assocresp_ies = kmalloc(ifmgd->assocresp_ies_len, GFP_KERNEL); - if (ifmgd->assocresp_ies) - memcpy(ifmgd->assocresp_ies, pos, ifmgd->assocresp_ies_len); - rcu_read_lock(); /* Add STA entry for the AP */ - sta = sta_info_get(local, ifmgd->bssid); + sta = sta_info_get(local, wk->bss->cbss.bssid); if (!sta) { newsta = true; - sta = sta_info_alloc(sdata, ifmgd->bssid, GFP_ATOMIC); + rcu_read_unlock(); + + sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL); if (!sta) { printk(KERN_DEBUG "%s: failed to alloc STA entry for" " the AP\n", sdata->dev->name); - rcu_read_unlock(); - return; + return RX_MGMT_NONE; } /* update new sta with its last rx activity */ sta->last_rx = jiffies; - } - /* - * FIXME: Do we really need to update the sta_info's information here? - * We already know about the AP (we found it in our list) so it - * should already be filled with the right info, no? - * As is stands, all this is racy because typically we assume - * the information that is filled in here (except flags) doesn't - * change while a STA structure is alive. As such, it should move - * to between the sta_info_alloc() and sta_info_insert() above. - */ + set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | + WLAN_STA_ASSOC_AP); + if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) + set_sta_flags(sta, WLAN_STA_AUTHORIZED); - set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP); - if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) - set_sta_flags(sta, WLAN_STA_AUTHORIZED); + rcu_read_lock(); + } rates = 0; basic_rates = 0; @@ -1595,7 +1472,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: failed to insert STA entry for" " the AP (error %d)\n", sdata->dev->name, err); rcu_read_unlock(); - return; + return RX_MGMT_NONE; } } @@ -1611,13 +1488,14 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, + wk->bss->cbss.bssid, ap_ht_cap_flags); /* set AID and assoc capability, * ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; bss_conf->assoc_capability = capab_info; - ieee80211_set_associated(sdata, changed); + ieee80211_set_associated(sdata, wk->bss, changed); /* * initialise the time of last beacon to be the association time, @@ -1625,8 +1503,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, */ ifmgd->last_beacon = jiffies; - ieee80211_associated(sdata); - cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); + list_del(&wk->list); + kfree(wk); + return RX_MGMT_CFG80211_ASSOC; } @@ -1654,23 +1533,25 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, channel, beacon); - if (!bss) + if (bss) + ieee80211_rx_bss_put(local, bss); + + if (!sdata->u.mgd.associated) return; if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && - (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { + (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid, + ETH_ALEN) == 0)) { struct ieee80211_channel_sw_ie *sw_elem = (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; ieee80211_sta_process_chanswitch(sdata, sw_elem, bss); } - - ieee80211_rx_bss_put(local, bss); } static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len, + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { struct ieee80211_if_managed *ifmgd; @@ -1679,6 +1560,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ifmgd = &sdata->u.mgd; + ASSERT_MGD_MTX(ifmgd); + if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */ @@ -1692,13 +1575,17 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); /* direct probe may be part of the association flow */ - if (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE) { + if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) { printk(KERN_DEBUG "%s direct probe responded\n", sdata->dev->name); - ieee80211_authenticate(sdata); + wk->tries = 0; + wk->state = IEEE80211_MGD_STATE_AUTH; + WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE); } - if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { + if (ifmgd->associated && + memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && + ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; mutex_lock(&sdata->local->iflist_mtx); ieee80211_recalc_ps(sdata->local, -1); @@ -1740,6 +1627,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, bool erp_valid, directed_tim = false; u8 erp_value = 0; u32 ncrc; + u8 *bssid; + + ASSERT_MGD_MTX(ifmgd); /* Process beacon from the current BSS */ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; @@ -1749,8 +1639,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (rx_status->freq != local->hw.conf.channel->center_freq) return; - if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) || - memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) + if (WARN_ON(!ifmgd->associated)) + return; + + bssid = ifmgd->associated->cbss.bssid; + + if (WARN_ON(memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)) return; if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { @@ -1829,8 +1723,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); - sta = sta_info_get(local, ifmgd->bssid); - if (!sta) { + sta = sta_info_get(local, bssid); + if (WARN_ON(!sta)) { rcu_read_unlock(); return; } @@ -1845,7 +1739,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, - ap_ht_cap_flags); + bssid, ap_ht_cap_flags); } if (elems.country_elem) { @@ -1887,6 +1781,7 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, case IEEE80211_STYPE_REASSOC_RESP: case IEEE80211_STYPE_DEAUTH: case IEEE80211_STYPE_DISASSOC: + case IEEE80211_STYPE_ACTION: skb_queue_tail(&sdata->u.mgd.skb_queue, skb); queue_work(local->hw.workqueue, &sdata->u.mgd.work); return RX_QUEUED; @@ -1898,40 +1793,118 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_rx_status *rx_status; struct ieee80211_mgmt *mgmt; + struct ieee80211_mgd_work *wk; + enum rx_mgmt_action rma = RX_MGMT_NONE; u16 fc; rx_status = (struct ieee80211_rx_status *) skb->cb; mgmt = (struct ieee80211_mgmt *) skb->data; fc = le16_to_cpu(mgmt->frame_control); - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PROBE_RESP: - ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, - rx_status); - break; - case IEEE80211_STYPE_BEACON: - ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, - rx_status); - break; - case IEEE80211_STYPE_AUTH: - ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); - break; - case IEEE80211_STYPE_ASSOC_RESP: - ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 0); + mutex_lock(&ifmgd->mtx); + + if (ifmgd->associated && + memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid, + ETH_ALEN) == 0) { + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_BEACON: + ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, + rx_status); + break; + case IEEE80211_STYPE_PROBE_RESP: + ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt, + skb->len, rx_status); + break; + case IEEE80211_STYPE_DEAUTH: + rma = ieee80211_rx_mgmt_deauth(sdata, NULL, + mgmt, skb->len); + break; + case IEEE80211_STYPE_DISASSOC: + rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); + break; + case IEEE80211_STYPE_ACTION: + /* XXX: differentiate, can only happen for CSA now! */ + ieee80211_sta_process_chanswitch(sdata, + &mgmt->u.action.u.chan_switch.sw_elem, + ifmgd->associated); + break; + } + mutex_unlock(&ifmgd->mtx); + + switch (rma) { + case RX_MGMT_NONE: + /* no action */ + break; + case RX_MGMT_CFG80211_DEAUTH: + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, + skb->len, GFP_KERNEL); + break; + case RX_MGMT_CFG80211_DISASSOC: + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, + skb->len, GFP_KERNEL); + break; + default: + WARN(1, "unexpected: %d", rma); + } + goto out; + } + + list_for_each_entry(wk, &ifmgd->work_list, list) { + if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) + continue; + + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_RESP: + ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len, + rx_status); + break; + case IEEE80211_STYPE_AUTH: + rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len); + break; + case IEEE80211_STYPE_ASSOC_RESP: + rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, + skb->len, false); + break; + case IEEE80211_STYPE_REASSOC_RESP: + rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, + skb->len, true); + break; + case IEEE80211_STYPE_DEAUTH: + rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt, + skb->len); + break; + } + /* + * We've processed this frame for that work, so it can't + * belong to another work struct. + * NB: this is also required for correctness because the + * called functions can free 'wk', and for 'rma'! + */ break; - case IEEE80211_STYPE_REASSOC_RESP: - ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 1); + } + + mutex_unlock(&ifmgd->mtx); + + switch (rma) { + case RX_MGMT_NONE: + /* no action */ break; - case IEEE80211_STYPE_DEAUTH: - ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); + case RX_MGMT_CFG80211_AUTH: + cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len, + GFP_KERNEL); break; - case IEEE80211_STYPE_DISASSOC: - ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); + case RX_MGMT_CFG80211_ASSOC: + cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len, + GFP_KERNEL); break; + default: + WARN(1, "unexpected: %d", rma); } + out: kfree_skb(skb); } @@ -1947,89 +1920,9 @@ static void ieee80211_sta_timer(unsigned long data) return; } - set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); queue_work(local->hw.workqueue, &ifmgd->work); } -static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - - /* Reset own TSF to allow time synchronization work. */ - drv_reset_tsf(local); - - ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ - ifmgd->auth_transaction = -1; - ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; - ifmgd->assoc_scan_tries = 0; - ifmgd->direct_probe_tries = 0; - ifmgd->auth_tries = 0; - ifmgd->assoc_tries = 0; - netif_tx_stop_all_queues(sdata->dev); - netif_carrier_off(sdata->dev); -} - -static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - struct ieee80211_bss *bss; - u8 *bssid = ifmgd->bssid, *ssid = ifmgd->ssid; - u8 ssid_len = ifmgd->ssid_len; - u16 capa_mask = WLAN_CAPABILITY_ESS; - u16 capa_val = WLAN_CAPABILITY_ESS; - struct ieee80211_channel *chan = local->oper_channel; - - bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, - bssid, ssid, ssid_len, - capa_mask, capa_val); - - if (bss) { - local->oper_channel = bss->cbss.channel; - local->oper_channel_type = NL80211_CHAN_NO_HT; - ieee80211_hw_config(local, 0); - - ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len, - bss->supp_rates); - if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED) - sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; - else - sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; - - /* Send out direct probe if no probe resp was received or - * the one we have is outdated - */ - if (!bss->last_probe_resp || - time_after(jiffies, bss->last_probe_resp - + IEEE80211_SCAN_RESULT_EXPIRE)) - ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; - else - ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; - - ieee80211_rx_bss_put(local, bss); - ieee80211_sta_reset_auth(sdata); - return 0; - } else { - if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { - - ifmgd->assoc_scan_tries++; - - ieee80211_request_internal_scan(sdata, ifmgd->ssid, - ssid_len); - - ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; - set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); - } else { - ifmgd->assoc_scan_tries = 0; - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - } - } - return -1; -} - - static void ieee80211_sta_work(struct work_struct *work) { struct ieee80211_sub_if_data *sdata = @@ -2037,6 +1930,10 @@ static void ieee80211_sta_work(struct work_struct *work) struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd; struct sk_buff *skb; + struct ieee80211_mgd_work *wk, *tmp; + LIST_HEAD(free_work); + enum rx_mgmt_action rma; + bool anybusy = false; if (!netif_running(sdata->dev)) return; @@ -2059,46 +1956,93 @@ static void ieee80211_sta_work(struct work_struct *work) ifmgd = &sdata->u.mgd; + /* first process frames to avoid timing out while a frame is pending */ while ((skb = skb_dequeue(&ifmgd->skb_queue))) ieee80211_sta_rx_queued_mgmt(sdata, skb); - if (ifmgd->state != IEEE80211_STA_MLME_DIRECT_PROBE && - ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && - ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && - test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { - queue_delayed_work(local->hw.workqueue, &local->scan_work, - round_jiffies_relative(0)); - return; + /* then process the rest of the work */ + mutex_lock(&ifmgd->mtx); + + list_for_each_entry(wk, &ifmgd->work_list, list) { + if (wk->state != IEEE80211_MGD_STATE_IDLE) { + anybusy = true; + break; + } } - if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request)) { - if (ieee80211_sta_config_auth(sdata)) - return; - clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); - } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request)) + ieee80211_recalc_idle(local); + + if (!anybusy) { + mutex_unlock(&ifmgd->mtx); + + if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) + queue_delayed_work(local->hw.workqueue, + &local->scan_work, + round_jiffies_relative(0)); return; + } - ieee80211_recalc_idle(local); + list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { + if (time_before(jiffies, wk->timeout)) + continue; - switch (ifmgd->state) { - case IEEE80211_STA_MLME_DISABLED: - break; - case IEEE80211_STA_MLME_DIRECT_PROBE: - ieee80211_direct_probe(sdata); - break; - case IEEE80211_STA_MLME_AUTHENTICATE: - ieee80211_authenticate(sdata); - break; - case IEEE80211_STA_MLME_ASSOCIATE: - ieee80211_associate(sdata); - break; - case IEEE80211_STA_MLME_ASSOCIATED: - ieee80211_associated(sdata); - break; - default: - WARN_ON(1); - break; + switch (wk->state) { + default: + WARN_ON(1); + /* fall through */ + case IEEE80211_MGD_STATE_IDLE: + /* nothing */ + rma = RX_MGMT_NONE; + break; + case IEEE80211_MGD_STATE_PROBE: + rma = ieee80211_direct_probe(sdata, wk); + break; + case IEEE80211_MGD_STATE_AUTH: + rma = ieee80211_authenticate(sdata, wk); + break; + case IEEE80211_MGD_STATE_ASSOC: + rma = ieee80211_associate(sdata, wk); + break; + } + + switch (rma) { + case RX_MGMT_NONE: + /* no action required */ + break; + case RX_MGMT_CFG80211_AUTH_TO: + case RX_MGMT_CFG80211_ASSOC_TO: + list_del(&wk->list); + list_add(&wk->list, &free_work); + wk->tries = rma; /* small abuse but only local */ + break; + default: + WARN(1, "unexpected: %d", rma); + } + } + + mutex_unlock(&ifmgd->mtx); + + list_for_each_entry_safe(wk, tmp, &free_work, list) { + switch (wk->tries) { + case RX_MGMT_CFG80211_AUTH_TO: + cfg80211_send_auth_timeout(sdata->dev, + wk->bss->cbss.bssid, + GFP_KERNEL); + break; + case RX_MGMT_CFG80211_ASSOC_TO: + cfg80211_send_auth_timeout(sdata->dev, + wk->bss->cbss.bssid, + GFP_KERNEL); + break; + default: + WARN(1, "unexpected: %d", wk->tries); + } + + list_del(&wk->list); + kfree(wk); } + + ieee80211_recalc_idle(local); } static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) @@ -2110,7 +2054,6 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) */ sdata->u.mgd.last_beacon = jiffies; - queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); } @@ -2152,7 +2095,6 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd; - u32 hw_flags; ifmgd = &sdata->u.mgd; INIT_WORK(&ifmgd->work, ieee80211_sta_work); @@ -2164,113 +2106,239 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) (unsigned long) sdata); skb_queue_head_init(&ifmgd->skb_queue); + INIT_LIST_HEAD(&ifmgd->work_list); + ifmgd->capab = WLAN_CAPABILITY_ESS; ifmgd->flags = 0; if (sdata->local->hw.queues >= 4) ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; - hw_flags = sdata->local->hw.flags; + mutex_init(&ifmgd->mtx); } -/* configuration hooks */ -void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata) +/* scan finished notification */ +void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; - if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) - return; + /* Restart STA timers */ + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) + ieee80211_restart_sta_timer(sdata); + rcu_read_unlock(); +} - if (WARN_ON(ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) - ieee80211_set_disassoc(sdata, true, true, - WLAN_REASON_DEAUTH_LEAVING); +int ieee80211_max_network_latency(struct notifier_block *nb, + unsigned long data, void *dummy) +{ + s32 latency_usec = (s32) data; + struct ieee80211_local *local = + container_of(nb, struct ieee80211_local, + network_latency_notifier); - if (WARN_ON(ifmgd->ssid_len == 0)) { - /* - * Only allow association to be started if a valid SSID - * is configured. - */ - return; - } + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, latency_usec); + mutex_unlock(&local->iflist_mtx); - set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); - queue_work(local->hw.workqueue, &ifmgd->work); + return 0; } -int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, - const char *ie, size_t len) +/* config hooks */ +int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, + struct cfg80211_auth_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + const u8 *ssid; + struct ieee80211_mgd_work *wk; + u16 auth_alg; - if (len == 0 && ifmgd->extra_ie_len == 0) - return -EALREADY; - - if (len == ifmgd->extra_ie_len && ifmgd->extra_ie && - memcmp(ifmgd->extra_ie, ie, len) == 0) - return -EALREADY; - - kfree(ifmgd->extra_ie); - if (len == 0) { - ifmgd->extra_ie = NULL; - ifmgd->extra_ie_len = 0; - return 0; + switch (req->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + auth_alg = WLAN_AUTH_OPEN; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + auth_alg = WLAN_AUTH_SHARED_KEY; + break; + case NL80211_AUTHTYPE_FT: + auth_alg = WLAN_AUTH_FT; + break; + case NL80211_AUTHTYPE_NETWORK_EAP: + auth_alg = WLAN_AUTH_LEAP; + break; + default: + return -EOPNOTSUPP; } - ifmgd->extra_ie = kmalloc(len, GFP_KERNEL); - if (!ifmgd->extra_ie) { - ifmgd->extra_ie_len = 0; + + wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); + if (!wk) return -ENOMEM; + + wk->bss = (void *)req->bss; + + if (req->ie && req->ie_len) { + memcpy(wk->ie, req->ie, req->ie_len); + wk->ie_len = req->ie_len; } - memcpy(ifmgd->extra_ie, ie, len); - ifmgd->extra_ie_len = len; + + ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); + memcpy(wk->ssid, ssid + 2, ssid[1]); + wk->ssid_len = ssid[1]; + + wk->state = IEEE80211_MGD_STATE_PROBE; + wk->auth_alg = auth_alg; + + /* + * XXX: if still associated need to tell AP that we're going + * to sleep and then change channel etc. + */ + sdata->local->oper_channel = req->bss->channel; + ieee80211_hw_config(sdata->local, 0); + + mutex_lock(&ifmgd->mtx); + list_add(&wk->list, &sdata->u.mgd.work_list); + mutex_unlock(&ifmgd->mtx); + + queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); return 0; } -int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) +int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, + struct cfg80211_assoc_request *req) { - printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", - sdata->dev->name, reason); + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_work *wk, *found = NULL; + int i, err; - ieee80211_set_disassoc(sdata, true, true, reason); - return 0; + mutex_lock(&ifmgd->mtx); + + list_for_each_entry(wk, &ifmgd->work_list, list) { + if (&wk->bss->cbss == req->bss && + wk->state == IEEE80211_MGD_STATE_IDLE) { + found = wk; + break; + } + } + + if (!found) { + err = -ENOLINK; + goto out; + } + + list_del(&found->list); + + wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL); + if (!wk) { + list_add(&found->list, &ifmgd->work_list); + err = -ENOMEM; + goto out; + } + + list_add(&wk->list, &ifmgd->work_list); + + ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; + + for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) + if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || + req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || + req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) + ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + + sdata->local->oper_channel = req->bss->channel; + ieee80211_hw_config(sdata->local, 0); + + if (req->ie && req->ie_len) { + memcpy(wk->ie, req->ie, req->ie_len); + wk->ie_len = req->ie_len; + } else + wk->ie_len = 0; + + if (req->prev_bssid) + memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN); + + wk->state = IEEE80211_MGD_STATE_ASSOC; + wk->tries = 0; + + if (req->use_mfp) { + ifmgd->mfp = IEEE80211_MFP_REQUIRED; + ifmgd->flags |= IEEE80211_STA_MFP_ENABLED; + } else { + ifmgd->mfp = IEEE80211_MFP_DISABLED; + ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED; + } + + if (req->crypto.control_port) + ifmgd->flags |= IEEE80211_STA_CONTROL_PORT; + else + ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; + + queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); + + err = 0; + + out: + mutex_unlock(&ifmgd->mtx); + return err; } -int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) +int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, + struct cfg80211_deauth_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_work *wk; + const u8 *bssid = NULL; - printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", - sdata->dev->name, reason); + printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", + sdata->dev->name, req->reason_code); + + mutex_lock(&ifmgd->mtx); + + if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { + bssid = req->bss->bssid; + ieee80211_set_disassoc(sdata, bssid, true); + } else list_for_each_entry(wk, &ifmgd->work_list, list) { + if (&wk->bss->cbss == req->bss) { + bssid = req->bss->bssid; + list_del(&wk->list); + kfree(wk); + break; + } + } - if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED)) + /* cfg80211 should catch this... */ + if (WARN_ON(!bssid)) { + mutex_unlock(&ifmgd->mtx); return -ENOLINK; + } + + mutex_unlock(&ifmgd->mtx); + + ieee80211_send_deauth_disassoc(sdata, bssid, + IEEE80211_STYPE_DEAUTH, req->reason_code); - ieee80211_set_disassoc(sdata, false, true, reason); return 0; } -/* scan finished notification */ -void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) +int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, + struct cfg80211_disassoc_request *req) { - struct ieee80211_sub_if_data *sdata = local->scan_sdata; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - /* Restart STA timers */ - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) - ieee80211_restart_sta_timer(sdata); - rcu_read_unlock(); -} + printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", + sdata->dev->name, req->reason_code); -int ieee80211_max_network_latency(struct notifier_block *nb, - unsigned long data, void *dummy) -{ - s32 latency_usec = (s32) data; - struct ieee80211_local *local = - container_of(nb, struct ieee80211_local, - network_latency_notifier); + mutex_lock(&ifmgd->mtx); - mutex_lock(&local->iflist_mtx); - ieee80211_recalc_ps(local, latency_usec); - mutex_unlock(&local->iflist_mtx); + /* cfg80211 should catch that */ + if (WARN_ON(&ifmgd->associated->cbss != req->bss)) { + mutex_unlock(&ifmgd->mtx); + return -ENOLINK; + } + + ieee80211_set_disassoc(sdata, req->bss->bssid, false); + + mutex_unlock(&ifmgd->mtx); + ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, + IEEE80211_STYPE_DISASSOC, req->reason_code); return 0; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ec5acc6..fe6b990 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1641,12 +1641,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 || compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) { - /* Not from the current AP. */ - return; - } - - if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) { - /* Association in progress; ignore SA Query */ + /* Not from the current AP or not associated yet. */ return; } @@ -1683,7 +1678,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) struct ieee80211_local *local = rx->local; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; - struct ieee80211_bss *bss; int len = rx->skb->len; if (!ieee80211_is_action(mgmt->frame_control)) @@ -1761,17 +1755,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) return RX_DROP_MONITOR; - bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid, - local->hw.conf.channel->center_freq, - sdata->u.mgd.ssid, - sdata->u.mgd.ssid_len); - if (!bss) - return RX_DROP_MONITOR; - - ieee80211_sta_process_chanswitch(sdata, - &mgmt->u.action.u.chan_switch.sw_elem, bss); - ieee80211_rx_bss_put(local, bss); - break; + return ieee80211_sta_rx_mgmt(sdata, rx->skb); } break; case WLAN_CATEGORY_SA_QUERY: @@ -2026,13 +2010,8 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, case NL80211_IFTYPE_STATION: if (!bssid) return 0; - if (!ieee80211_bssid_match(bssid, sdata->u.mgd.bssid)) { - if (!(rx->flags & IEEE80211_RX_IN_SCAN)) - return 0; - rx->flags &= ~IEEE80211_RX_RA_MATCH; - } else if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) { + if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; rx->flags &= ~IEEE80211_RX_RA_MATCH; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 569a464..5f4f786 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -121,19 +121,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, return bss; } -void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, - int freq, u8 *ssid, u8 ssid_len) -{ - struct ieee80211_bss *bss; - struct ieee80211_local *local = sdata->local; - - bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len); - if (bss) { - cfg80211_unlink_bss(local->hw.wiphy, (void *)bss); - ieee80211_rx_bss_put(local, bss); - } -} - ieee80211_rx_result ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { @@ -327,7 +314,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) /* Tell AP we're back */ if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { + if (sdata->u.mgd.associated) { ieee80211_scan_ps_disable(sdata); netif_tx_wake_all_queues(sdata->dev); } @@ -383,7 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) sdata, BSS_CHANGED_BEACON_ENABLED); if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { + if (sdata->u.mgd.associated) { netif_tx_stop_all_queues(sdata->dev); ieee80211_scan_ps_enable(sdata); } @@ -443,10 +430,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (req != &local->int_scan_req && sdata->vif.type == NL80211_IFTYPE_STATION && - (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE || - ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || - ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) { - /* actually wait for the assoc to finish/time out */ + !list_empty(&ifmgd->work_list)) { + /* actually wait for the work it's doing to finish/time out */ set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); return 0; } -- cgit v0.10.2 From c9cf01226e0bd1fa4f7f7024d8d53e982fad208f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:45:18 +0200 Subject: mac80211: refactor the WEP code to be directly usable The new key work for cfg80211 will only give us the WEP key for shared auth to do that authentication, and not via the regular key settings, so we need to be able to encrypt a single frame in software, and that without a key struct. Thus, refactor the WEP code to not require a key structure but use the key, len and idx directly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index ef73105..4fafb2d 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -67,10 +67,10 @@ static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen) static void ieee80211_wep_get_iv(struct ieee80211_local *local, - struct ieee80211_key *key, u8 *iv) + int keylen, int keyidx, u8 *iv) { local->wep_iv++; - if (ieee80211_wep_weak_iv(local->wep_iv, key->conf.keylen)) + if (ieee80211_wep_weak_iv(local->wep_iv, keylen)) local->wep_iv += 0x0100; if (!iv) @@ -79,13 +79,13 @@ static void ieee80211_wep_get_iv(struct ieee80211_local *local, *iv++ = (local->wep_iv >> 16) & 0xff; *iv++ = (local->wep_iv >> 8) & 0xff; *iv++ = local->wep_iv & 0xff; - *iv++ = key->conf.keyidx << 6; + *iv++ = keyidx << 6; } static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_key *key) + int keylen, int keyidx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; unsigned int hdrlen; @@ -100,7 +100,7 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, hdrlen = ieee80211_hdrlen(hdr->frame_control); newhdr = skb_push(skb, WEP_IV_LEN); memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen); - ieee80211_wep_get_iv(local, key, newhdr + hdrlen); + ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); return newhdr + hdrlen; } @@ -144,26 +144,17 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, * * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) */ -int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_key *key) +static int ieee80211_wep_encrypt(struct ieee80211_local *local, + struct sk_buff *skb, + const u8 *key, int keylen, int keyidx) { - u32 klen; - u8 *rc4key, *iv; + u8 *iv; size_t len; + u8 rc4key[3 + WLAN_KEY_LEN_WEP104]; - if (!key || key->conf.alg != ALG_WEP) - return -1; - - klen = 3 + key->conf.keylen; - rc4key = kmalloc(klen, GFP_ATOMIC); - if (!rc4key) - return -1; - - iv = ieee80211_wep_add_iv(local, skb, key); - if (!iv) { - kfree(rc4key); + iv = ieee80211_wep_add_iv(local, skb, keylen, keyidx); + if (!iv) return -1; - } len = skb->len - (iv + WEP_IV_LEN - skb->data); @@ -171,16 +162,14 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, memcpy(rc4key, iv, 3); /* Copy rest of the WEP key (the secret part) */ - memcpy(rc4key + 3, key->conf.key, key->conf.keylen); + memcpy(rc4key + 3, key, keylen); /* Add room for ICV */ skb_put(skb, WEP_ICV_LEN); - ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, klen, + ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3, iv + WEP_IV_LEN, len); - kfree(rc4key); - return 0; } @@ -216,8 +205,9 @@ int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, * failure. If frame is OK, IV and ICV will be removed, i.e., decrypted payload * is moved to the beginning of the skb and skb length will be reduced. */ -int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_key *key) +static int ieee80211_wep_decrypt(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_key *key) { u32 klen; u8 *rc4key; @@ -314,12 +304,16 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) + if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, + tx->key->conf.keylen, + tx->key->conf.keyidx)) return -1; } else { info->control.hw_key = &tx->key->conf; if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { - if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) + if (!ieee80211_wep_add_iv(tx->local, skb, + tx->key->conf.keylen, + tx->key->conf.keyidx)) return -1; } } diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index d3f0db4..85219de 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -22,10 +22,6 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); -int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_key *key); -int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_key *key); bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); ieee80211_rx_result -- cgit v0.10.2 From 78485475618cf9f1c70dc7f15e8deafa8b6074ab Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:56:05 +0200 Subject: cfg80211: fix netdev down problem We shouldn't be looking at the ssid_len for non-IBSS, and for IBSS we should also return an error on trying to leave an IBSS while not in or joining an IBSS. This fixes an issue where we wouldn't disconnect() on an interface being taken down since there's no SSID configured this way. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 7b66cf1..83ec719 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -567,9 +567,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, #endif break; case NETDEV_GOING_DOWN: - if (!wdev->ssid_len) - break; - switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: cfg80211_leave_ibss(rdev, dev, true); diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index c92b542..a5330c5 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -92,8 +92,12 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext) int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, bool nowext) { + struct wireless_dev *wdev = dev->ieee80211_ptr; int err; + if (!wdev->ssid_len) + return -ENOLINK; + err = rdev->ops->leave_ibss(&rdev->wiphy, dev); if (err) -- cgit v0.10.2 From c238c8ac63f2d33ea5e7c0b9e9e0ccd8ae9a34e4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:56:06 +0200 Subject: cfg80211: dont use union for wext Otherwise it becomes very hard to reset the structs correctly since wext can be configured while the interface is down. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 71847d3..fe49833 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1270,10 +1270,8 @@ struct wireless_dev { #ifdef CONFIG_WIRELESS_EXT /* wext data */ struct { - union { - struct cfg80211_ibss_params ibss; - struct cfg80211_connect_params connect; - }; + struct cfg80211_ibss_params ibss; + struct cfg80211_connect_params connect; u8 *ie; size_t ie_len; u8 bssid[ETH_ALEN]; -- cgit v0.10.2 From cb0b4beb93d14429bf0c50fc1ab8e26348dca880 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:56:07 +0200 Subject: cfg80211: mlme API must be able to sleep After the mac80211 mlme cleanup, we can require that the MLME functions in cfg80211 can sleep. This will simplify future work in cfg80211 a lot. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index fe49833..60c1f11 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1721,70 +1721,68 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss); * @dev: network device * @buf: authentication frame (header + body) * @len: length of the frame data - * @gfp: allocation flags * * This function is called whenever an authentication has been processed in * station mode. The driver is required to call either this function or * cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth() - * call. + * call. This function may sleep. */ -void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); +void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); /** * cfg80211_send_auth_timeout - notification of timed out authentication * @dev: network device * @addr: The MAC address of the device with which the authentication timed out - * @gfp: allocation flags + * + * This function may sleep. */ -void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp); +void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr); /** * cfg80211_send_rx_assoc - notification of processed association * @dev: network device * @buf: (re)association response frame (header + body) * @len: length of the frame data - * @gfp: allocation flags * * This function is called whenever a (re)association response has been * processed in station mode. The driver is required to call either this * function or cfg80211_send_assoc_timeout() to indicate the result of - * cfg80211_ops::assoc() call. + * cfg80211_ops::assoc() call. This function may sleep. */ -void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); +void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len); /** * cfg80211_send_assoc_timeout - notification of timed out association * @dev: network device * @addr: The MAC address of the device with which the association timed out - * @gfp: allocation flags + * + * This function may sleep. */ -void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp); +void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr); /** * cfg80211_send_deauth - notification of processed deauthentication * @dev: network device * @buf: deauthentication frame (header + body) * @len: length of the frame data - * @gfp: allocation flags * * This function is called whenever deauthentication has been processed in * station mode. This includes both received deauthentication frames and - * locally generated ones. + * locally generated ones. This function may sleep. */ -void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); /** * cfg80211_send_disassoc - notification of processed disassociation * @dev: network device * @buf: disassociation response frame (header + body) * @len: length of the frame data - * @gfp: allocation flags * * This function is called whenever disassociation has been processed in * station mode. This includes both received disassociation frames and locally - * generated ones. + * generated ones. This function may sleep. */ -void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len); /** * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 108e8c9..15dbb57 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -412,11 +412,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt->u.deauth.reason_code = cpu_to_le16(reason); if (stype == IEEE80211_STYPE_DEAUTH) - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len, - GFP_KERNEL); + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len); else - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len, - GFP_KERNEL); + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len); ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); } @@ -1839,12 +1837,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, /* no action */ break; case RX_MGMT_CFG80211_DEAUTH: - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, - skb->len, GFP_KERNEL); + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); break; case RX_MGMT_CFG80211_DISASSOC: - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, - skb->len, GFP_KERNEL); + cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); break; default: WARN(1, "unexpected: %d", rma); @@ -1893,12 +1889,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, /* no action */ break; case RX_MGMT_CFG80211_AUTH: - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len, - GFP_KERNEL); + cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len); break; case RX_MGMT_CFG80211_ASSOC: - cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len, - GFP_KERNEL); + cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); break; default: WARN(1, "unexpected: %d", rma); @@ -2026,13 +2020,11 @@ static void ieee80211_sta_work(struct work_struct *work) switch (wk->tries) { case RX_MGMT_CFG80211_AUTH_TO: cfg80211_send_auth_timeout(sdata->dev, - wk->bss->cbss.bssid, - GFP_KERNEL); + wk->bss->cbss.bssid); break; case RX_MGMT_CFG80211_ASSOC_TO: - cfg80211_send_auth_timeout(sdata->dev, - wk->bss->cbss.bssid, - GFP_KERNEL); + cfg80211_send_assoc_timeout(sdata->dev, + wk->bss->cbss.bssid); break; default: WARN(1, "unexpected: %d", wk->tries); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 087d337..f7dc752 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -12,7 +12,7 @@ #include "core.h" #include "nl80211.h" -void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) +void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -23,6 +23,8 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gf u16 status = le16_to_cpu(mgmt->u.auth.status_code); bool done = false; + might_sleep(); + for (i = 0; i < MAX_AUTH_BSSES; i++) { if (wdev->authtry_bsses[i] && memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, @@ -41,12 +43,12 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gf WARN_ON(!done); - nl80211_send_rx_auth(rdev, dev, buf, len, gfp); + nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); cfg80211_sme_rx_auth(dev, buf, len); } EXPORT_SYMBOL(cfg80211_send_rx_auth); -void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) +void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) { u16 status_code; struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -57,12 +59,14 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, g int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); bool done; + might_sleep(); + status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); - nl80211_send_rx_assoc(rdev, dev, buf, len, gfp); + nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, - status_code, gfp); + status_code, GFP_KERNEL); if (status_code == WLAN_STATUS_SUCCESS) { for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) { @@ -80,7 +84,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, g } EXPORT_SYMBOL(cfg80211_send_rx_assoc); -void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -90,7 +94,9 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp int i; bool done = false; - nl80211_send_deauth(rdev, dev, buf, len, gfp); + might_sleep(); + + nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); if (wdev->current_bss && memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { @@ -132,16 +138,17 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; - __cfg80211_disconnected(dev, gfp, NULL, 0, + __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, reason_code, from_ap); } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); } } EXPORT_SYMBOL(cfg80211_send_deauth); -void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -153,7 +160,9 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, g bool from_ap; bool done = false; - nl80211_send_disassoc(rdev, dev, buf, len, gfp); + might_sleep(); + + nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); if (!wdev->sme_state == CFG80211_SME_CONNECTED) return; @@ -177,12 +186,12 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, g reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; - __cfg80211_disconnected(dev, gfp, NULL, 0, + __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, reason_code, from_ap); } EXPORT_SYMBOL(cfg80211_send_disassoc); -void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) +void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -190,10 +199,13 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gf int i; bool done = false; - nl80211_send_auth_timeout(rdev, dev, addr, gfp); + might_sleep(); + + nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); if (wdev->sme_state == CFG80211_SME_CONNECTING) cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { if (wdev->authtry_bsses[i] && @@ -211,7 +223,7 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gf } EXPORT_SYMBOL(cfg80211_send_auth_timeout); -void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) +void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -219,10 +231,13 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t g int i; bool done = false; - nl80211_send_assoc_timeout(rdev, dev, addr, gfp); + might_sleep(); + + nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); if (wdev->sme_state == CFG80211_SME_CONNECTING) cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { if (wdev->auth_bsses[i] && -- cgit v0.10.2 From c1e6fb1aad0d4d4f032d46b6bab093a41c6c82bf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:56:08 +0200 Subject: cfg80211: warn again on spurious deauth The original code in mac80211 could send a deauth frame under certain circumstances even if nothing had ever requested an authentication. This has been fixed with the rework there, so cfg80211 can now warn again about spurious events to catch possible future drivers or mac80211 regressions. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index f7dc752..960bf60 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -122,15 +122,9 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) break; } } -/* - * mac80211 currently triggers this warning, - * so disable for now (it's harmless, just - * means that we got a spurious event) WARN_ON(!done); - */ - if (wdev->sme_state == CFG80211_SME_CONNECTED) { u16 reason_code; bool from_ap; -- cgit v0.10.2 From 4d0c8aead32ecdbe1310ad473b3637991f560865 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:56:09 +0200 Subject: cfg80211: properly name driver locking Currently we call that cfg80211_put_dev(), but that is misleading. With the new convention of using 'rdev' for registered_device variables, also call that function cfg80211_unlock_rdev(). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 83ec719..c6813be 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -171,12 +171,6 @@ cfg80211_get_dev_from_ifindex(int ifindex) return drv; } -void cfg80211_put_dev(struct cfg80211_registered_device *drv) -{ - BUG_ON(IS_ERR(drv)); - mutex_unlock(&drv->mtx); -} - /* requires cfg80211_mutex to be held */ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, char *newname) diff --git a/net/wireless/core.h b/net/wireless/core.h index 4554453..92da612 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -146,7 +146,7 @@ __cfg80211_drv_from_info(struct genl_info *info); * If successful, it returns non-NULL and also locks * the driver's mutex! * - * This means that you need to call cfg80211_put_dev() + * This means that you need to call cfg80211_unlock_rdev() * before being allowed to acquire &cfg80211_mutex! * * This is necessary because we need to lock the global @@ -170,7 +170,11 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); extern struct cfg80211_registered_device * cfg80211_get_dev_from_ifindex(int ifindex); -extern void cfg80211_put_dev(struct cfg80211_registered_device *drv); +static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *drv) +{ + BUG_ON(IS_ERR(drv) || !drv); + mutex_unlock(&drv->mtx); +} /* free object */ extern void cfg80211_dev_free(struct cfg80211_registered_device *drv); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 44c520c..df22048 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -411,14 +411,14 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) goto out_free; - cfg80211_put_dev(dev); + cfg80211_unlock_rdev(dev); return genlmsg_unicast(msg, info->snd_pid); out_free: nlmsg_free(msg); out_err: - cfg80211_put_dev(dev); + cfg80211_unlock_rdev(dev); return -ENOBUFS; } @@ -737,7 +737,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) goto out_free; dev_put(netdev); - cfg80211_put_dev(dev); + cfg80211_unlock_rdev(dev); return genlmsg_unicast(msg, info->snd_pid); @@ -745,7 +745,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) nlmsg_free(msg); out_err: dev_put(netdev); - cfg80211_put_dev(dev); + cfg80211_unlock_rdev(dev); return -ENOBUFS; } @@ -853,7 +853,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) unlock: dev_put(dev); - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); unlock_rtnl: rtnl_unlock(); return err; @@ -906,7 +906,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) type, err ? NULL : &flags, ¶ms); unlock: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); unlock_rtnl: rtnl_unlock(); return err; @@ -934,7 +934,7 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); unlock_rtnl: rtnl_unlock(); return err; @@ -1037,7 +1037,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) err = -ENOBUFS; nlmsg_free(msg); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -1097,7 +1097,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) #endif out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: @@ -1163,7 +1163,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -1211,7 +1211,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) #endif out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: @@ -1306,7 +1306,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) err = call(&drv->wiphy, dev, ¶ms); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -1338,7 +1338,7 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) err = drv->ops->del_beacon(&drv->wiphy, dev); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -1572,7 +1572,7 @@ static int nl80211_dump_station(struct sk_buff *skb, cb->args[1] = sta_idx; err = skb->len; out_err: - cfg80211_put_dev(dev); + cfg80211_unlock_rdev(dev); out_rtnl: rtnl_unlock(); @@ -1624,7 +1624,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) out_free: nlmsg_free(msg); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -1760,7 +1760,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) out: if (params.vlan) dev_put(params.vlan); - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -1865,7 +1865,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) out: if (params.vlan) dev_put(params.vlan); - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -1904,7 +1904,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2035,7 +2035,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, cb->args[1] = path_idx; err = skb->len; out_err: - cfg80211_put_dev(dev); + cfg80211_unlock_rdev(dev); out_rtnl: rtnl_unlock(); @@ -2093,7 +2093,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) out_free: nlmsg_free(msg); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2142,7 +2142,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2190,7 +2190,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2222,7 +2222,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) err = drv->ops->del_mpath(&drv->wiphy, dev, dst); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2278,7 +2278,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) err = drv->ops->change_bss(&drv->wiphy, dev, ¶ms); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2444,7 +2444,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, err = -EMSGSIZE; out: /* Cleanup */ - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2550,7 +2550,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) out: /* cleanup */ - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2890,7 +2890,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) kfree(request); } out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -3007,7 +3007,7 @@ static int nl80211_dump_scan(struct sk_buff *skb, cb->args[1] = idx; err = skb->len; - cfg80211_put_dev(dev); + cfg80211_unlock_rdev(dev); out_put_netdev: dev_put(netdev); @@ -3112,7 +3112,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) ssid, ssid_len, ie, ie_len); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3259,7 +3259,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) &crypto); out: - cfg80211_put_dev(rdev); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3321,7 +3321,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) err = cfg80211_mlme_deauth(drv, dev, bssid, ie, ie_len, reason_code); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3383,7 +3383,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) err = cfg80211_mlme_disassoc(drv, dev, bssid, ie, ie_len, reason_code); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3464,7 +3464,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) err = cfg80211_join_ibss(drv, dev, &ibss); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3501,7 +3501,7 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) err = cfg80211_leave_ibss(drv, dev, false); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3538,7 +3538,7 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) rdev->testmode_info = NULL; } - cfg80211_put_dev(rdev); + cfg80211_unlock_rdev(rdev); unlock_rtnl: rtnl_unlock(); @@ -3707,7 +3707,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) err = cfg80211_connect(drv, dev, &connect); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3748,7 +3748,7 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) err = cfg80211_disconnect(drv, dev, reason, true); out: - cfg80211_put_dev(drv); + cfg80211_unlock_rdev(drv); dev_put(dev); unlock_rtnl: rtnl_unlock(); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 9253994..1625faf 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -28,8 +28,6 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) if (!dev) goto out; - WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); - /* * This must be before sending the other events! * Otherwise, wpa_supplicant gets completely confused with @@ -636,7 +634,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, } else nl80211_send_scan_start(rdev, dev); out: - cfg80211_put_dev(rdev); + cfg80211_unlock_rdev(rdev); return err; } EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); @@ -945,7 +943,7 @@ int cfg80211_wext_giwscan(struct net_device *dev, } out: - cfg80211_put_dev(rdev); + cfg80211_unlock_rdev(rdev); return res; } EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); -- cgit v0.10.2 From 4f5dadcebb55fccef34722bbbf6401d39124c8a4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:56:10 +0200 Subject: cfg80211: fix MFP bug, sparse warnings sparse warns about a number of things, and one of them (use_mfp shadowed variable) actually is a bug, fix all of them. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index df22048..4976eac 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3239,11 +3239,11 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_USE_MFP]) { - enum nl80211_mfp use_mfp = + enum nl80211_mfp mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); - if (use_mfp == NL80211_MFP_REQUIRED) + if (mfp == NL80211_MFP_REQUIRED) use_mfp = true; - else if (use_mfp != NL80211_MFP_NO) { + else if (mfp != NL80211_MFP_NO) { err = -EINVAL; goto out; } diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 2c33cd8..9d101d5 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -855,7 +855,7 @@ static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) return 0; } -int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) +static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) { wdev->wext.connect.crypto.cipher_group = 0; @@ -880,7 +880,7 @@ int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) return 0; } -int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher) +static int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher) { int nr_ciphers = 0; u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise; @@ -918,7 +918,7 @@ int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher) } -int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt) +static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt) { int nr_akm_suites = 0; -- cgit v0.10.2 From 667503ddcb96f3b10211f997fe55907fa7509841 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:56:11 +0200 Subject: cfg80211: fix locking Over time, a lot of locking issues have crept into the smarts of cfg80211, so e.g. scan completion can race against a new scan, IBSS join can race against leaving an IBSS, etc. Introduce a new per-interface lock that protects most of the per-interface data that we need to keep track of, and sprinkle assertions about that lock everywhere. Some things now need to be offloaded to work structs so that we don't require being able to sleep in functions the drivers call. The exception to that are the MLME callbacks (rx_auth etc.) that currently only mac80211 calls because it was easier to do that there instead of in cfg80211, and future drivers implementing those calls will, if they ever exist, probably need to use a similar scheme like mac80211 anyway... In order to be able to handle _deauth and _disassoc properly, introduce a cookie passed to it that will determine locking requirements. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 60c1f11..83c2c72 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -555,6 +555,7 @@ struct cfg80211_scan_request { /* internal */ struct wiphy *wiphy; int ifidx; + bool aborted; }; /** @@ -998,9 +999,11 @@ struct cfg80211_ops { int (*assoc)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_assoc_request *req); int (*deauth)(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_deauth_request *req); + struct cfg80211_deauth_request *req, + void *cookie); int (*disassoc)(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_disassoc_request *req); + struct cfg80211_disassoc_request *req, + void *cookie); int (*connect)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme); @@ -1249,10 +1252,12 @@ struct wireless_dev { struct wiphy *wiphy; enum nl80211_iftype iftype; - /* private to the generic wireless code */ + /* the remainder of this struct should be private to cfg80211 */ struct list_head list; struct net_device *netdev; + struct mutex mtx; + /* currently used for IBSS and SME - might be rearranged later */ u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; @@ -1263,6 +1268,9 @@ struct wireless_dev { } sme_state; struct cfg80211_conn *conn; + struct list_head event_list; + spinlock_t event_lock; + struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES]; struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; struct cfg80211_internal_bss *current_bss; /* associated / joined */ @@ -1765,24 +1773,30 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr); * @dev: network device * @buf: deauthentication frame (header + body) * @len: length of the frame data + * @cookie: cookie from ->deauth if called within that callback, + * %NULL otherwise * * This function is called whenever deauthentication has been processed in * station mode. This includes both received deauthentication frames and * locally generated ones. This function may sleep. */ -void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, + void *cookie); /** * cfg80211_send_disassoc - notification of processed disassociation * @dev: network device * @buf: disassociation response frame (header + body) * @len: length of the frame data + * @cookie: cookie from ->disassoc if called within that callback, + * %NULL otherwise * * This function is called whenever disassociation has been processed in * station mode. This includes both received disassociation frames and locally * generated ones. This function may sleep. */ -void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len); +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, + void *cookie); /** * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7cfc14e..36f8f24 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1182,15 +1182,19 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_deauth_request *req) + struct cfg80211_deauth_request *req, + void *cookie) { - return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req); + return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), + req, cookie); } static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_disassoc_request *req) + struct cfg80211_disassoc_request *req, + void *cookie) { - return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req); + return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), + req, cookie); } static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2e92bbd..327aabc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -918,9 +918,11 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req); int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, - struct cfg80211_deauth_request *req); + struct cfg80211_deauth_request *req, + void *cookie); int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, - struct cfg80211_disassoc_request *req); + struct cfg80211_disassoc_request *req, + void *cookie); ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee80211_send_pspoll(struct ieee80211_local *local, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 15dbb57..c9db964 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -386,7 +386,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, - const u8 *bssid, u16 stype, u16 reason) + const u8 *bssid, u16 stype, u16 reason, + void *cookie) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -412,9 +413,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt->u.deauth.reason_code = cpu_to_le16(reason); if (stype == IEEE80211_STYPE_DEAUTH) - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len); + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, cookie); else - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len); + cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, cookie); ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); } @@ -1837,10 +1838,12 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, /* no action */ break; case RX_MGMT_CFG80211_DEAUTH: - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, + NULL); break; case RX_MGMT_CFG80211_DISASSOC: - cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); + cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, + NULL); break; default: WARN(1, "unexpected: %d", rma); @@ -2273,7 +2276,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, - struct cfg80211_deauth_request *req) + struct cfg80211_deauth_request *req, + void *cookie) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_mgd_work *wk; @@ -2305,13 +2309,15 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); ieee80211_send_deauth_disassoc(sdata, bssid, - IEEE80211_STYPE_DEAUTH, req->reason_code); + IEEE80211_STYPE_DEAUTH, req->reason_code, + cookie); return 0; } int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, - struct cfg80211_disassoc_request *req) + struct cfg80211_disassoc_request *req, + void *cookie) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -2331,6 +2337,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, - IEEE80211_STYPE_DISASSOC, req->reason_code); + IEEE80211_STYPE_DISASSOC, req->reason_code, + cookie); return 0; } diff --git a/net/wireless/core.c b/net/wireless/core.c index c6813be..9c73769 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -257,6 +257,71 @@ static void cfg80211_rfkill_sync_work(struct work_struct *work) cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill)); } +static void cfg80211_process_events(struct wireless_dev *wdev) +{ + struct cfg80211_event *ev; + unsigned long flags; + + spin_lock_irqsave(&wdev->event_lock, flags); + while (!list_empty(&wdev->event_list)) { + ev = list_first_entry(&wdev->event_list, + struct cfg80211_event, list); + list_del(&ev->list); + spin_unlock_irqrestore(&wdev->event_lock, flags); + + wdev_lock(wdev); + switch (ev->type) { + case EVENT_CONNECT_RESULT: + __cfg80211_connect_result( + wdev->netdev, ev->cr.bssid, + ev->cr.req_ie, ev->cr.req_ie_len, + ev->cr.resp_ie, ev->cr.resp_ie_len, + ev->cr.status, + ev->cr.status == WLAN_STATUS_SUCCESS); + break; + case EVENT_ROAMED: + __cfg80211_roamed(wdev, ev->rm.bssid, + ev->rm.req_ie, ev->rm.req_ie_len, + ev->rm.resp_ie, ev->rm.resp_ie_len); + break; + case EVENT_DISCONNECTED: + __cfg80211_disconnected(wdev->netdev, + ev->dc.ie, ev->dc.ie_len, + ev->dc.reason, true); + break; + case EVENT_IBSS_JOINED: + __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); + break; + } + wdev_unlock(wdev); + + kfree(ev); + + spin_lock_irqsave(&wdev->event_lock, flags); + } + spin_unlock_irqrestore(&wdev->event_lock, flags); +} + +static void cfg80211_event_work(struct work_struct *work) +{ + struct cfg80211_registered_device *rdev; + struct wireless_dev *wdev; + + rdev = container_of(work, struct cfg80211_registered_device, + event_work); + + rtnl_lock(); + cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->devlist_mtx); + + list_for_each_entry(wdev, &rdev->netdev_list, list) + cfg80211_process_events(wdev); + + mutex_unlock(&rdev->devlist_mtx); + cfg80211_unlock_rdev(rdev); + rtnl_unlock(); +} + /* exported functions */ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) @@ -299,6 +364,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) INIT_LIST_HEAD(&drv->netdev_list); spin_lock_init(&drv->bss_lock); INIT_LIST_HEAD(&drv->bss_list); + INIT_WORK(&drv->scan_done_wk, __cfg80211_scan_done); device_initialize(&drv->wiphy.dev); drv->wiphy.dev.class = &ieee80211_class; @@ -316,6 +382,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work); INIT_WORK(&drv->conn_work, cfg80211_conn_work); + INIT_WORK(&drv->event_work, cfg80211_event_work); /* * Initialize wiphy parameters to IEEE 802.11 MIB default values. @@ -477,6 +544,9 @@ void wiphy_unregister(struct wiphy *wiphy) mutex_unlock(&drv->mtx); cancel_work_sync(&drv->conn_work); + cancel_work_sync(&drv->scan_done_wk); + kfree(drv->scan_req); + flush_work(&drv->event_work); cfg80211_debugfs_drv_del(drv); @@ -535,6 +605,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, switch (state) { case NETDEV_REGISTER: + mutex_init(&wdev->mtx); + INIT_LIST_HEAD(&wdev->event_list); + spin_lock_init(&wdev->event_lock); mutex_lock(&rdev->devlist_mtx); list_add(&wdev->list, &rdev->netdev_list); if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, @@ -566,15 +639,17 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, cfg80211_leave_ibss(rdev, dev, true); break; case NL80211_IFTYPE_STATION: + wdev_lock(wdev); #ifdef CONFIG_WIRELESS_EXT kfree(wdev->wext.ie); wdev->wext.ie = NULL; wdev->wext.ie_len = 0; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; #endif - cfg80211_disconnect(rdev, dev, - WLAN_REASON_DEAUTH_LEAVING, true); + __cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, true); cfg80211_mlme_down(rdev, dev); + wdev_unlock(wdev); break; default: break; @@ -582,20 +657,24 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; case NETDEV_UP: #ifdef CONFIG_WIRELESS_EXT + cfg80211_lock_rdev(rdev); + wdev_lock(wdev); switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: if (wdev->wext.ibss.ssid_len) - cfg80211_join_ibss(rdev, dev, - &wdev->wext.ibss); + __cfg80211_join_ibss(rdev, dev, + &wdev->wext.ibss); break; case NL80211_IFTYPE_STATION: if (wdev->wext.connect.ssid_len) - cfg80211_connect(rdev, dev, - &wdev->wext.connect); + __cfg80211_connect(rdev, dev, + &wdev->wext.connect); break; default: break; } + wdev_unlock(wdev); + cfg80211_unlock_rdev(rdev); #endif break; case NETDEV_UNREGISTER: @@ -605,6 +684,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, list_del_init(&wdev->list); } mutex_unlock(&rdev->devlist_mtx); + mutex_destroy(&wdev->mtx); break; case NETDEV_PRE_UP: if (rfkill_blocked(rdev->rfkill)) diff --git a/net/wireless/core.h b/net/wireless/core.h index 92da612..5ccd642 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -57,12 +57,14 @@ struct cfg80211_registered_device { u32 bss_generation; struct cfg80211_scan_request *scan_req; /* protected by RTNL */ unsigned long suspend_at; + struct work_struct scan_done_wk; #ifdef CONFIG_NL80211_TESTMODE struct genl_info *testmode_info; #endif struct work_struct conn_work; + struct work_struct event_work; #ifdef CONFIG_CFG80211_DEBUGFS /* Debugfs entries */ @@ -170,12 +172,73 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); extern struct cfg80211_registered_device * cfg80211_get_dev_from_ifindex(int ifindex); +static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *drv) +{ + mutex_lock(&drv->mtx); +} + static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *drv) { BUG_ON(IS_ERR(drv) || !drv); mutex_unlock(&drv->mtx); } +static inline void wdev_lock(struct wireless_dev *wdev) + __acquires(wdev) +{ + mutex_lock(&wdev->mtx); + __acquire(wdev->mtx); +} + +static inline void wdev_unlock(struct wireless_dev *wdev) + __releases(wdev) +{ + __release(wdev->mtx); + mutex_unlock(&wdev->mtx); +} + +#define ASSERT_RDEV_LOCK(rdev) WARN_ON(!mutex_is_locked(&(rdev)->mtx)); +#define ASSERT_WDEV_LOCK(wdev) WARN_ON(!mutex_is_locked(&(wdev)->mtx)); + +enum cfg80211_event_type { + EVENT_CONNECT_RESULT, + EVENT_ROAMED, + EVENT_DISCONNECTED, + EVENT_IBSS_JOINED, +}; + +struct cfg80211_event { + struct list_head list; + enum cfg80211_event_type type; + + union { + struct { + u8 bssid[ETH_ALEN]; + const u8 *req_ie; + const u8 *resp_ie; + size_t req_ie_len; + size_t resp_ie_len; + u16 status; + } cr; + struct { + u8 bssid[ETH_ALEN]; + const u8 *req_ie; + const u8 *resp_ie; + size_t req_ie_len; + size_t resp_ie_len; + } rm; + struct { + const u8 *ie; + size_t ie_len; + u16 reason; + } dc; + struct { + u8 bssid[ETH_ALEN]; + } ij; + }; +}; + + /* free object */ extern void cfg80211_dev_free(struct cfg80211_registered_device *drv); @@ -191,25 +254,46 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev, unsigned long age_secs); /* IBSS */ +int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params); int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_ibss_params *params); void cfg80211_clear_ibss(struct net_device *dev, bool nowext); int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, bool nowext); +void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); /* MLME */ +int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_auth_type auth_type, + const u8 *bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len); int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len); +int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + const u8 *bssid, const u8 *prev_bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, bool use_mfp, + struct cfg80211_crypto_settings *crypt); int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, const u8 *bssid, const u8 *prev_bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, bool use_mfp, struct cfg80211_crypto_settings *crypt); +int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason); int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, const u8 *ie, int ie_len, u16 reason); @@ -218,24 +302,38 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, const u8 *ie, int ie_len, u16 reason); void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, struct net_device *dev); +void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, bool wextev); /* SME */ +int __cfg80211_connect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_connect_params *connect); int cfg80211_connect(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_connect_params *connect); +int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, + struct net_device *dev, u16 reason, + bool wextev); int cfg80211_disconnect(struct cfg80211_registered_device *rdev, struct net_device *dev, u16 reason, bool wextev); +void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len); void cfg80211_conn_work(struct work_struct *work); /* internal helpers */ int cfg80211_validate_key_settings(struct key_params *params, int key_idx, const u8 *mac_addr); -void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, +void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, size_t ie_len, u16 reason, bool from_ap); void cfg80211_sme_scan_done(struct net_device *dev); void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); void cfg80211_sme_disassoc(struct net_device *dev, int idx); +void __cfg80211_scan_done(struct work_struct *wk); #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index a5330c5..99ef936 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -10,7 +10,7 @@ #include "nl80211.h" -void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) +void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_bss *bss; @@ -39,22 +39,45 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) cfg80211_hold_bss(bss_from_pub(bss)); wdev->current_bss = bss_from_pub(bss); - nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); + nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, + GFP_KERNEL); #ifdef CONFIG_WIRELESS_EXT memset(&wrqu, 0, sizeof(wrqu)); memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); #endif } + +void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_event *ev; + unsigned long flags; + + ev = kzalloc(sizeof(*ev), gfp); + if (!ev) + return; + + ev->type = EVENT_IBSS_JOINED; + memcpy(ev->cr.bssid, bssid, ETH_ALEN); + + spin_lock_irqsave(&wdev->event_lock, flags); + list_add_tail(&ev->list, &wdev->event_list); + spin_unlock_irqrestore(&wdev->event_lock, flags); + schedule_work(&rdev->event_work); +} EXPORT_SYMBOL(cfg80211_ibss_joined); -int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, - struct net_device *dev, - struct cfg80211_ibss_params *params) +int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; + ASSERT_WDEV_LOCK(wdev); + if (wdev->ssid_len) return -EALREADY; @@ -72,10 +95,26 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, return 0; } -void cfg80211_clear_ibss(struct net_device *dev, bool nowext) +int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_join_ibss(rdev, dev, params); + wdev_unlock(wdev); + + return err; +} + +static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) { struct wireless_dev *wdev = dev->ieee80211_ptr; + ASSERT_WDEV_LOCK(wdev); + if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); cfg80211_put_bss(&wdev->current_bss->pub); @@ -89,12 +128,23 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext) #endif } -int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool nowext) +void cfg80211_clear_ibss(struct net_device *dev, bool nowext) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + wdev_lock(wdev); + __cfg80211_clear_ibss(dev, nowext); + wdev_unlock(wdev); +} + +static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool nowext) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; + ASSERT_WDEV_LOCK(wdev); + if (!wdev->ssid_len) return -ENOLINK; @@ -103,11 +153,24 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, if (err) return err; - cfg80211_clear_ibss(dev, nowext); + __cfg80211_clear_ibss(dev, nowext); return 0; } +int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool nowext) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_leave_ibss(rdev, dev, nowext); + wdev_unlock(wdev); + + return err; +} + #ifdef CONFIG_WIRELESS_EXT static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev) @@ -184,12 +247,15 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, if (wdev->wext.ibss.channel == chan) return 0; - if (wdev->ssid_len) { - err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), - dev, true); - if (err) - return err; - } + wdev_lock(wdev); + err = 0; + if (wdev->ssid_len) + err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), + dev, true); + wdev_unlock(wdev); + + if (err) + return err; if (chan) { wdev->wext.ibss.channel = chan; @@ -215,10 +281,12 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) return -EINVAL; + wdev_lock(wdev); if (wdev->current_bss) chan = wdev->current_bss->pub.channel; else if (wdev->wext.ibss.channel) chan = wdev->wext.ibss.channel; + wdev_unlock(wdev); if (chan) { freq->m = chan->center_freq; @@ -247,12 +315,15 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) return -EOPNOTSUPP; - if (wdev->ssid_len) { - err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), - dev, true); - if (err) - return err; - } + wdev_lock(wdev); + err = 0; + if (wdev->ssid_len) + err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), + dev, true); + wdev_unlock(wdev); + + if (err) + return err; /* iwconfig uses nul termination in SSID.. */ if (len > 0 && ssid[len - 1] == '\0') @@ -279,6 +350,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev, data->flags = 0; + wdev_lock(wdev); if (wdev->ssid_len) { data->flags = 1; data->length = wdev->ssid_len; @@ -288,6 +360,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev, data->length = wdev->wext.ibss.ssid_len; memcpy(ssid, wdev->wext.ibss.ssid, data->length); } + wdev_unlock(wdev); return 0; } @@ -325,12 +398,15 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0) return 0; - if (wdev->ssid_len) { - err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), - dev, true); - if (err) - return err; - } + wdev_lock(wdev); + err = 0; + if (wdev->ssid_len) + err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), + dev, true); + wdev_unlock(wdev); + + if (err) + return err; if (bssid) { memcpy(wdev->wext.bssid, bssid, ETH_ALEN); @@ -355,10 +431,13 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, ap_addr->sa_family = ARPHRD_ETHER; + wdev_lock(wdev); if (wdev->current_bss) memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); else memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); + wdev_unlock(wdev); + return 0; } /* temporary symbol - mark GPL - in the future the handler won't be */ diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 960bf60..1b2ca1f 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -23,7 +23,7 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) u16 status = le16_to_cpu(mgmt->u.auth.status_code); bool done = false; - might_sleep(); + wdev_lock(wdev); for (i = 0; i < MAX_AUTH_BSSES; i++) { if (wdev->authtry_bsses[i] && @@ -45,6 +45,8 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); cfg80211_sme_rx_auth(dev, buf, len); + + wdev_unlock(wdev); } EXPORT_SYMBOL(cfg80211_send_rx_auth); @@ -59,14 +61,15 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); bool done; - might_sleep(); + wdev_lock(wdev); status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); - cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, - status_code, GFP_KERNEL); + __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, + status_code, + status_code == WLAN_STATUS_SUCCESS); if (status_code == WLAN_STATUS_SUCCESS) { for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) { @@ -81,10 +84,13 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) WARN_ON(!done); } + + wdev_unlock(wdev); } EXPORT_SYMBOL(cfg80211_send_rx_assoc); -void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) +static void __cfg80211_send_deauth(struct net_device *dev, + const u8 *buf, size_t len) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -94,7 +100,7 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) int i; bool done = false; - might_sleep(); + ASSERT_WDEV_LOCK(wdev); nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); @@ -132,17 +138,35 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; - __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, - reason_code, from_ap); + __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { - cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); + __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + false); + } +} + + +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, + void *cookie) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + BUG_ON(cookie && wdev != cookie); + + if (cookie) { + /* called within callback */ + __cfg80211_send_deauth(dev, buf, len); + } else { + wdev_lock(wdev); + __cfg80211_send_deauth(dev, buf, len); + wdev_unlock(wdev); } } EXPORT_SYMBOL(cfg80211_send_deauth); -void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) +static void __cfg80211_send_disassoc(struct net_device *dev, + const u8 *buf, size_t len) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -154,12 +178,12 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) bool from_ap; bool done = false; - might_sleep(); + wdev_lock(wdev); nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); if (!wdev->sme_state == CFG80211_SME_CONNECTED) - return; + goto out; if (wdev->current_bss && memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) { @@ -180,8 +204,26 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; - __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, - reason_code, from_ap); + __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); + out: + wdev_unlock(wdev); +} + +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, + void *cookie) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + BUG_ON(cookie && wdev != cookie); + + if (cookie) { + /* called within callback */ + __cfg80211_send_disassoc(dev, buf, len); + } else { + wdev_lock(wdev); + __cfg80211_send_disassoc(dev, buf, len); + wdev_unlock(wdev); + } } EXPORT_SYMBOL(cfg80211_send_disassoc); @@ -193,13 +235,13 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) int i; bool done = false; - might_sleep(); + wdev_lock(wdev); nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); if (wdev->sme_state == CFG80211_SME_CONNECTING) - cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); + __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + false); for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { if (wdev->authtry_bsses[i] && @@ -214,6 +256,8 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) } WARN_ON(!done); + + wdev_unlock(wdev); } EXPORT_SYMBOL(cfg80211_send_auth_timeout); @@ -225,13 +269,13 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) int i; bool done = false; - might_sleep(); + wdev_lock(wdev); nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); if (wdev->sme_state == CFG80211_SME_CONNECTING) - cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); + __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + false); for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { if (wdev->auth_bsses[i] && @@ -246,6 +290,8 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) } WARN_ON(!done); + + wdev_unlock(wdev); } EXPORT_SYMBOL(cfg80211_send_assoc_timeout); @@ -276,17 +322,21 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, EXPORT_SYMBOL(cfg80211_michael_mic_failure); /* some MLME handling for userspace SME */ -int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, - struct net_device *dev, struct ieee80211_channel *chan, - enum nl80211_auth_type auth_type, const u8 *bssid, - const u8 *ssid, int ssid_len, - const u8 *ie, int ie_len) +int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_auth_type auth_type, + const u8 *bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_auth_request req; struct cfg80211_internal_bss *bss; int i, err, slot = -1, nfree = 0; + ASSERT_WDEV_LOCK(wdev); + if (wdev->current_bss && memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0) return -EALREADY; @@ -342,18 +392,37 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, return err; } -int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, - struct net_device *dev, struct ieee80211_channel *chan, - const u8 *bssid, const u8 *prev_bssid, - const u8 *ssid, int ssid_len, - const u8 *ie, int ie_len, bool use_mfp, - struct cfg80211_crypto_settings *crypt) +int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, + struct net_device *dev, struct ieee80211_channel *chan, + enum nl80211_auth_type auth_type, const u8 *bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len) +{ + int err; + + wdev_lock(dev->ieee80211_ptr); + err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, + ssid, ssid_len, ie, ie_len); + wdev_unlock(dev->ieee80211_ptr); + + return err; +} + +int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + const u8 *bssid, const u8 *prev_bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, bool use_mfp, + struct cfg80211_crypto_settings *crypt) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_assoc_request req; struct cfg80211_internal_bss *bss; int i, err, slot = -1; + ASSERT_WDEV_LOCK(wdev); + memset(&req, 0, sizeof(req)); if (wdev->current_bss) @@ -390,14 +459,35 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, return err; } -int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *bssid, - const u8 *ie, int ie_len, u16 reason) +int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + const u8 *bssid, const u8 *prev_bssid, + const u8 *ssid, int ssid_len, + const u8 *ie, int ie_len, bool use_mfp, + struct cfg80211_crypto_settings *crypt) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, + ssid, ssid_len, ie, ie_len, use_mfp, crypt); + wdev_unlock(wdev); + + return err; +} + +int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_deauth_request req; int i; + ASSERT_WDEV_LOCK(wdev); + memset(&req, 0, sizeof(req)); req.reason_code = reason; req.ie = ie; @@ -421,16 +511,32 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, if (!req.bss) return -ENOTCONN; - return rdev->ops->deauth(&rdev->wiphy, dev, &req); + return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); } -int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *bssid, - const u8 *ie, int ie_len, u16 reason) +int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason); + wdev_unlock(wdev); + + return err; +} + +static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_disassoc_request req; + ASSERT_WDEV_LOCK(wdev); + memset(&req, 0, sizeof(req)); req.reason_code = reason; req.ie = ie; @@ -440,7 +546,21 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, else return -ENOTCONN; - return rdev->ops->disassoc(&rdev->wiphy, dev, &req); + return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev); +} + +int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *bssid, + const u8 *ie, int ie_len, u16 reason) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason); + wdev_unlock(wdev); + + return err; } void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, @@ -450,6 +570,8 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, struct cfg80211_deauth_request req; int i; + ASSERT_WDEV_LOCK(wdev); + if (!rdev->ops->deauth) return; @@ -460,7 +582,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, if (wdev->current_bss) { req.bss = &wdev->current_bss->pub; - rdev->ops->deauth(&rdev->wiphy, dev, &req); + rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); cfg80211_put_bss(&wdev->current_bss->pub); @@ -471,7 +593,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, for (i = 0; i < MAX_AUTH_BSSES; i++) { if (wdev->auth_bsses[i]) { req.bss = &wdev->auth_bsses[i]->pub; - rdev->ops->deauth(&rdev->wiphy, dev, &req); + rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); if (wdev->auth_bsses[i]) { cfg80211_unhold_bss(wdev->auth_bsses[i]); cfg80211_put_bss(&wdev->auth_bsses[i]->pub); @@ -480,7 +602,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, } if (wdev->authtry_bsses[i]) { req.bss = &wdev->authtry_bsses[i]->pub; - rdev->ops->deauth(&rdev->wiphy, dev, &req); + rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); if (wdev->authtry_bsses[i]) { cfg80211_unhold_bss(wdev->authtry_bsses[i]); cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4976eac..cf4ac78 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4029,6 +4029,8 @@ static int nl80211_add_scan_req(struct sk_buff *msg, struct nlattr *nest; int i; + ASSERT_RDEV_LOCK(rdev); + if (WARN_ON(!req)) return 0; @@ -4391,12 +4393,12 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, struct net_device *netdev, u16 reason, - u8 *ie, size_t ie_len, bool from_ap, gfp_t gfp) + const u8 *ie, size_t ie_len, bool from_ap) { struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) return; @@ -4420,7 +4422,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); return; nla_put_failure: diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index cf3708b..44cc2a7 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -42,7 +42,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp); void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, struct net_device *netdev, u16 reason, - u8 *ie, size_t ie_len, bool from_ap, gfp_t gfp); + const u8 *ie, size_t ie_len, bool from_ap); void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 1625faf..4f552c3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -17,13 +17,21 @@ #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) -void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) +void __cfg80211_scan_done(struct work_struct *wk) { + struct cfg80211_registered_device *rdev; + struct cfg80211_scan_request *request; struct net_device *dev; #ifdef CONFIG_WIRELESS_EXT union iwreq_data wrqu; #endif + rdev = container_of(wk, struct cfg80211_registered_device, + scan_done_wk); + + mutex_lock(&rdev->mtx); + request = rdev->scan_req; + dev = dev_get_by_index(&init_net, request->ifidx); if (!dev) goto out; @@ -35,7 +43,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) */ cfg80211_sme_scan_done(dev); - if (aborted) + if (request->aborted) nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); else nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); @@ -43,7 +51,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) wiphy_to_dev(request->wiphy)->scan_req = NULL; #ifdef CONFIG_WIRELESS_EXT - if (!aborted) { + if (!request->aborted) { memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); @@ -53,8 +61,24 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) dev_put(dev); out: + cfg80211_unlock_rdev(rdev); kfree(request); } + +void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) +{ + struct net_device *dev = dev_get_by_index(&init_net, request->ifidx); + if (WARN_ON(!dev)) { + kfree(request); + return; + } + + WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); + + request->aborted = aborted; + schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk); + dev_put(dev); +} EXPORT_SYMBOL(cfg80211_scan_done); static void bss_release(struct kref *ref) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 066a19e..472e241 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -38,6 +38,8 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) int n_channels, err; ASSERT_RTNL(); + ASSERT_RDEV_LOCK(drv); + ASSERT_WDEV_LOCK(wdev); if (drv->scan_req) return -EBUSY; @@ -106,6 +108,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) struct cfg80211_connect_params *params; int err; + ASSERT_WDEV_LOCK(wdev); + if (!wdev->conn) return 0; @@ -117,11 +121,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) case CFG80211_CONN_AUTHENTICATE_NEXT: BUG_ON(!drv->ops->auth); wdev->conn->state = CFG80211_CONN_AUTHENTICATING; - return cfg80211_mlme_auth(drv, wdev->netdev, - params->channel, params->auth_type, - params->bssid, - params->ssid, params->ssid_len, - NULL, 0); + return __cfg80211_mlme_auth(drv, wdev->netdev, + params->channel, params->auth_type, + params->bssid, + params->ssid, params->ssid_len, + NULL, 0); case CFG80211_CONN_ASSOCIATE_NEXT: BUG_ON(!drv->ops->assoc); wdev->conn->state = CFG80211_CONN_ASSOCIATING; @@ -131,14 +135,16 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) * that some APs don't like that -- so we'd need to retry * the association. */ - err = cfg80211_mlme_assoc(drv, wdev->netdev, - params->channel, params->bssid, NULL, - params->ssid, params->ssid_len, - params->ie, params->ie_len, - false, ¶ms->crypto); + err = __cfg80211_mlme_assoc(drv, wdev->netdev, + params->channel, params->bssid, + NULL, + params->ssid, params->ssid_len, + params->ie, params->ie_len, + false, ¶ms->crypto); if (err) - cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid, - NULL, 0, WLAN_REASON_DEAUTH_LEAVING); + __cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid, + NULL, 0, + WLAN_REASON_DEAUTH_LEAVING); return err; default: return 0; @@ -152,22 +158,31 @@ void cfg80211_conn_work(struct work_struct *work) struct wireless_dev *wdev; rtnl_lock(); + cfg80211_lock_rdev(drv); mutex_lock(&drv->devlist_mtx); list_for_each_entry(wdev, &drv->netdev_list, list) { - if (!netif_running(wdev->netdev)) + wdev_lock(wdev); + if (!netif_running(wdev->netdev)) { + wdev_unlock(wdev); continue; - if (wdev->sme_state != CFG80211_SME_CONNECTING) + } + if (wdev->sme_state != CFG80211_SME_CONNECTING) { + wdev_unlock(wdev); continue; + } if (cfg80211_conn_do_work(wdev)) - cfg80211_connect_result(wdev->netdev, - wdev->conn->params.bssid, - NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_ATOMIC); + __cfg80211_connect_result( + wdev->netdev, + wdev->conn->params.bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + false); + wdev_unlock(wdev); } mutex_unlock(&drv->devlist_mtx); + cfg80211_unlock_rdev(drv); rtnl_unlock(); } @@ -177,6 +192,8 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) struct cfg80211_bss *bss; u16 capa = WLAN_CAPABILITY_ESS; + ASSERT_WDEV_LOCK(wdev); + if (wdev->conn->params.privacy) capa |= WLAN_CAPABILITY_PRIVACY; @@ -198,11 +215,13 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) return true; } -void cfg80211_sme_scan_done(struct net_device *dev) +static void __cfg80211_sme_scan_done(struct net_device *dev) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); + ASSERT_WDEV_LOCK(wdev); + if (wdev->sme_state != CFG80211_SME_CONNECTING) return; @@ -218,15 +237,26 @@ void cfg80211_sme_scan_done(struct net_device *dev) if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) schedule_work(&drv->conn_work); else - cfg80211_connect_result(dev, wdev->conn->params.bssid, - NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_ATOMIC); - return; + __cfg80211_connect_result( + wdev->netdev, + wdev->conn->params.bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + false); } } -void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) +void cfg80211_sme_scan_done(struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + wdev_lock(wdev); + __cfg80211_sme_scan_done(dev); + wdev_unlock(wdev); +} + +void cfg80211_sme_rx_auth(struct net_device *dev, + const u8 *buf, size_t len) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -234,6 +264,8 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; u16 status_code = le16_to_cpu(mgmt->u.auth.status_code); + ASSERT_WDEV_LOCK(wdev); + /* should only RX auth frames when connecting */ if (wdev->sme_state != CFG80211_SME_CONNECTING) return; @@ -273,10 +305,10 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) } } -static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, - const u8 *req_ie, size_t req_ie_len, - const u8 *resp_ie, size_t resp_ie_len, - u16 status, bool wextev, gfp_t gfp) +void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, + u16 status, bool wextev) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_bss *bss; @@ -284,18 +316,20 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, union iwreq_data wrqu; #endif + ASSERT_WDEV_LOCK(wdev); + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; if (wdev->sme_state == CFG80211_SME_CONNECTED) nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, req_ie, req_ie_len, - resp_ie, resp_ie_len, gfp); + resp_ie, resp_ie_len, GFP_KERNEL); else nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, - status, gfp); + status, GFP_KERNEL); #ifdef CONFIG_WIRELESS_EXT if (wextev) { @@ -362,21 +396,43 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, const u8 *resp_ie, size_t resp_ie_len, u16 status, gfp_t gfp) { - bool wextev = status == WLAN_STATUS_SUCCESS; - __cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, status, wextev, gfp); + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_event *ev; + unsigned long flags; + + ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); + if (!ev) + return; + + ev->type = EVENT_CONNECT_RESULT; + memcpy(ev->cr.bssid, bssid, ETH_ALEN); + ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev); + ev->cr.req_ie_len = req_ie_len; + memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len); + ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; + ev->cr.resp_ie_len = resp_ie_len; + memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len); + ev->cr.status = status; + + spin_lock_irqsave(&wdev->event_lock, flags); + list_add_tail(&ev->list, &wdev->event_list); + spin_unlock_irqrestore(&wdev->event_lock, flags); + schedule_work(&rdev->event_work); } EXPORT_SYMBOL(cfg80211_connect_result); -void cfg80211_roamed(struct net_device *dev, const u8 *bssid, - const u8 *req_ie, size_t req_ie_len, - const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) +void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len) { - struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_bss *bss; #ifdef CONFIG_WIRELESS_EXT union iwreq_data wrqu; #endif + ASSERT_WDEV_LOCK(wdev); + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; @@ -402,31 +458,62 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, cfg80211_hold_bss(bss_from_pub(bss)); wdev->current_bss = bss_from_pub(bss); - nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, - req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); + nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bssid, + req_ie, req_ie_len, resp_ie, resp_ie_len, + GFP_KERNEL); #ifdef CONFIG_WIRELESS_EXT if (req_ie) { memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = req_ie_len; - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); + wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, + &wrqu, req_ie); } if (resp_ie) { memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = resp_ie_len; - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); + wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, + &wrqu, resp_ie); } memset(&wrqu, 0, sizeof(wrqu)); wrqu.ap_addr.sa_family = ARPHRD_ETHER; memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); + wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); #endif } + +void cfg80211_roamed(struct net_device *dev, const u8 *bssid, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_event *ev; + unsigned long flags; + + ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); + if (!ev) + return; + + ev->type = EVENT_ROAMED; + memcpy(ev->rm.bssid, bssid, ETH_ALEN); + ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev); + ev->rm.req_ie_len = req_ie_len; + memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len); + ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; + ev->rm.resp_ie_len = resp_ie_len; + memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len); + + spin_lock_irqsave(&wdev->event_lock, flags); + list_add_tail(&ev->list, &wdev->event_list); + spin_unlock_irqrestore(&wdev->event_lock, flags); + schedule_work(&rdev->event_work); +} EXPORT_SYMBOL(cfg80211_roamed); -void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, +void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, size_t ie_len, u16 reason, bool from_ap) { struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -434,6 +521,8 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, union iwreq_data wrqu; #endif + ASSERT_WDEV_LOCK(wdev); + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; @@ -456,7 +545,7 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, } nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, - reason, ie, ie_len, from_ap, gfp); + reason, ie, ie_len, from_ap); #ifdef CONFIG_WIRELESS_EXT memset(&wrqu, 0, sizeof(wrqu)); @@ -468,16 +557,36 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, void cfg80211_disconnected(struct net_device *dev, u16 reason, u8 *ie, size_t ie_len, gfp_t gfp) { - __cfg80211_disconnected(dev, gfp, ie, ie_len, reason, true); + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_event *ev; + unsigned long flags; + + ev = kzalloc(sizeof(*ev) + ie_len, gfp); + if (!ev) + return; + + ev->type = EVENT_DISCONNECTED; + ev->dc.ie = ((u8 *)ev) + sizeof(*ev); + ev->dc.ie_len = ie_len; + memcpy((void *)ev->dc.ie, ie, ie_len); + ev->dc.reason = reason; + + spin_lock_irqsave(&wdev->event_lock, flags); + list_add_tail(&ev->list, &wdev->event_list); + spin_unlock_irqrestore(&wdev->event_lock, flags); + schedule_work(&rdev->event_work); } EXPORT_SYMBOL(cfg80211_disconnected); -int cfg80211_connect(struct cfg80211_registered_device *rdev, - struct net_device *dev, - struct cfg80211_connect_params *connect) +int __cfg80211_connect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_connect_params *connect) { - int err; struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + ASSERT_WDEV_LOCK(wdev); if (wdev->sme_state != CFG80211_SME_IDLE) return -EALREADY; @@ -572,12 +681,27 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, } } -int cfg80211_disconnect(struct cfg80211_registered_device *rdev, - struct net_device *dev, u16 reason, bool wextev) +int cfg80211_connect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_connect_params *connect) +{ + int err; + + wdev_lock(dev->ieee80211_ptr); + err = __cfg80211_connect(rdev, dev, connect); + wdev_unlock(dev->ieee80211_ptr); + + return err; +} + +int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, + struct net_device *dev, u16 reason, bool wextev) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; + ASSERT_WDEV_LOCK(wdev); + if (wdev->sme_state == CFG80211_SME_IDLE) return -EINVAL; @@ -601,8 +725,9 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, } /* wdev->conn->params.bssid must be set if > SCANNING */ - err = cfg80211_mlme_deauth(rdev, dev, wdev->conn->params.bssid, - NULL, 0, reason); + err = __cfg80211_mlme_deauth(rdev, dev, + wdev->conn->params.bssid, + NULL, 0, reason); if (err) return err; } else { @@ -612,21 +737,36 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, } if (wdev->sme_state == CFG80211_SME_CONNECTED) - __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, 0, false); + __cfg80211_disconnected(dev, NULL, 0, 0, false); else if (wdev->sme_state == CFG80211_SME_CONNECTING) __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, - wextev, GFP_KERNEL); + wextev); return 0; } +int cfg80211_disconnect(struct cfg80211_registered_device *rdev, + struct net_device *dev, + u16 reason, bool wextev) +{ + int err; + + wdev_lock(dev->ieee80211_ptr); + err = __cfg80211_disconnect(rdev, dev, reason, wextev); + wdev_unlock(dev->ieee80211_ptr); + + return err; +} + void cfg80211_sme_disassoc(struct net_device *dev, int idx) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); u8 bssid[ETH_ALEN]; + ASSERT_WDEV_LOCK(wdev); + if (!wdev->conn) return; diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index fe1987a..6f75aaa7f 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -15,6 +15,9 @@ static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, { int err; + ASSERT_RDEV_LOCK(rdev); + ASSERT_WDEV_LOCK(wdev); + if (!netif_running(wdev->netdev)) return 0; @@ -24,8 +27,8 @@ static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, err = 0; if (wdev->wext.connect.ssid_len != 0) - err = cfg80211_connect(rdev, wdev->netdev, - &wdev->wext.connect); + err = __cfg80211_connect(rdev, wdev->netdev, + &wdev->wext.connect); return err; } @@ -50,33 +53,43 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, if (chan && (chan->flags & IEEE80211_CHAN_DISABLED)) return -EINVAL; - if (wdev->wext.connect.channel == chan) - return 0; + cfg80211_lock_rdev(rdev); + wdev_lock(wdev); + + if (wdev->wext.connect.channel == chan) { + err = 0; + goto out; + } if (wdev->sme_state != CFG80211_SME_IDLE) { bool event = true; /* if SSID set, we'll try right again, avoid event */ if (wdev->wext.connect.ssid_len) event = false; - err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), - dev, WLAN_REASON_DEAUTH_LEAVING, - event); + err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), + dev, WLAN_REASON_DEAUTH_LEAVING, + event); if (err) - return err; + goto out; } + wdev->wext.connect.channel = chan; /* SSID is not set, we just want to switch channel */ if (wdev->wext.connect.ssid_len && chan) { - if (!rdev->ops->set_channel) - return -EOPNOTSUPP; - - return rdev->ops->set_channel(wdev->wiphy, chan, - NL80211_CHAN_NO_HT); + err = -EOPNOTSUPP; + if (rdev->ops->set_channel) + err = rdev->ops->set_channel(wdev->wiphy, chan, + NL80211_CHAN_NO_HT); + goto out; } - return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); + err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); + out: + wdev_unlock(wdev); + cfg80211_unlock_rdev(rdev); + return err; } /* temporary symbol - mark GPL - in the future the handler won't be */ EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq); @@ -92,10 +105,12 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; + wdev_lock(wdev); if (wdev->current_bss) chan = wdev->current_bss->pub.channel; else if (wdev->wext.connect.channel) chan = wdev->wext.connect.channel; + wdev_unlock(wdev); if (chan) { freq->m = chan->center_freq; @@ -128,21 +143,26 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, if (len > 0 && ssid[len - 1] == '\0') len--; + cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); + wdev_lock(wdev); + + err = 0; + if (wdev->wext.connect.ssid && len && len == wdev->wext.connect.ssid_len && memcmp(wdev->wext.connect.ssid, ssid, len)) - return 0; + goto out; if (wdev->sme_state != CFG80211_SME_IDLE) { bool event = true; /* if SSID set now, we'll try to connect, avoid event */ if (len) event = false; - err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), - dev, WLAN_REASON_DEAUTH_LEAVING, - event); + err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), + dev, WLAN_REASON_DEAUTH_LEAVING, + event); if (err) - return err; + goto out; } wdev->wext.connect.ssid = wdev->wext.ssid; @@ -151,7 +171,11 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, wdev->wext.connect.crypto.control_port = false; - return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); + err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); + out: + wdev_unlock(wdev); + cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); + return err; } /* temporary symbol - mark GPL - in the future the handler won't be */ EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid); @@ -168,6 +192,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, data->flags = 0; + wdev_lock(wdev); if (wdev->ssid_len) { data->flags = 1; data->length = wdev->ssid_len; @@ -178,6 +203,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, memcpy(ssid, wdev->wext.connect.ssid, data->length); } else data->flags = 0; + wdev_unlock(wdev); return 0; } @@ -203,21 +229,25 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) bssid = NULL; + cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); + wdev_lock(wdev); + + err = 0; /* both automatic */ if (!bssid && !wdev->wext.connect.bssid) - return 0; + goto out; /* fixed already - and no change */ if (wdev->wext.connect.bssid && bssid && compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) - return 0; + goto out; if (wdev->sme_state != CFG80211_SME_IDLE) { - err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), - dev, WLAN_REASON_DEAUTH_LEAVING, - false); + err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), + dev, WLAN_REASON_DEAUTH_LEAVING, + false); if (err) - return err; + goto out; } if (bssid) { @@ -226,7 +256,11 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, } else wdev->wext.connect.bssid = NULL; - return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); + err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); + out: + wdev_unlock(wdev); + cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); + return err; } /* temporary symbol - mark GPL - in the future the handler won't be */ EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap); @@ -243,12 +277,14 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev, ap_addr->sa_family = ARPHRD_ETHER; + wdev_lock(wdev); if (wdev->current_bss) memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); else if (wdev->wext.connect.bssid) memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN); else memset(ap_addr->sa_data, 0, ETH_ALEN); + wdev_unlock(wdev); return 0; } @@ -270,15 +306,20 @@ int cfg80211_wext_siwgenie(struct net_device *dev, if (!ie_len) ie = NULL; + wdev_lock(wdev); + /* no change */ + err = 0; if (wdev->wext.ie_len == ie_len && memcmp(wdev->wext.ie, ie, ie_len) == 0) - return 0; + goto out; if (ie_len) { ie = kmemdup(extra, ie_len, GFP_KERNEL); - if (!ie) - return -ENOMEM; + if (!ie) { + err = -ENOMEM; + goto out; + } } else ie = NULL; @@ -287,14 +328,17 @@ int cfg80211_wext_siwgenie(struct net_device *dev, wdev->wext.ie_len = ie_len; if (wdev->sme_state != CFG80211_SME_IDLE) { - err = cfg80211_disconnect(rdev, dev, - WLAN_REASON_DEAUTH_LEAVING, false); + err = __cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, false); if (err) - return err; + goto out; } /* userspace better not think we'll reconnect */ - return 0; + err = 0; + out: + wdev_unlock(wdev); + return err; } EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie); @@ -305,6 +349,7 @@ int cfg80211_wext_siwmlme(struct net_device *dev, struct wireless_dev *wdev = dev->ieee80211_ptr; struct iw_mlme *mlme = (struct iw_mlme *)extra; struct cfg80211_registered_device *rdev; + int err; if (!wdev) return -EOPNOTSUPP; @@ -317,13 +362,19 @@ int cfg80211_wext_siwmlme(struct net_device *dev, if (mlme->addr.sa_family != ARPHRD_ETHER) return -EINVAL; + wdev_lock(wdev); switch (mlme->cmd) { case IW_MLME_DEAUTH: case IW_MLME_DISASSOC: - return cfg80211_disconnect(rdev, dev, mlme->reason_code, - true); + err = __cfg80211_disconnect(rdev, dev, mlme->reason_code, + true); + break; default: - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + break; } + wdev_unlock(wdev); + + return err; } EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme); -- cgit v0.10.2 From 79c97e97aed7f760d2826c7daf2d42d8eefe9838 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:56:12 +0200 Subject: cfg80211: clean up naming once and for all We've named the registered devices 'drv' sometimes, thinking of "driver", which is not what it is, it's the internal representation of a wiphy, i.e. a device. Let's clean up the naming once and and use 'rdev' aka 'registered device' everywhere. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 9c73769..b5e2f6d 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -30,10 +30,10 @@ MODULE_DESCRIPTION("wireless configuration support"); /* RCU might be appropriate here since we usually * only read the list, and that can happen quite * often because we need to do it for each command */ -LIST_HEAD(cfg80211_drv_list); +LIST_HEAD(cfg80211_rdev_list); /* - * This is used to protect the cfg80211_drv_list, cfg80211_regdomain, + * This is used to protect the cfg80211_rdev_list, cfg80211_regdomain, * country_ie_regdomain, the reg_beacon_list and the the last regulatory * request receipt (last_request). */ @@ -43,18 +43,18 @@ DEFINE_MUTEX(cfg80211_mutex); static struct dentry *ieee80211_debugfs_dir; /* requires cfg80211_mutex to be held! */ -struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx) +struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) { - struct cfg80211_registered_device *result = NULL, *drv; + struct cfg80211_registered_device *result = NULL, *rdev; if (!wiphy_idx_valid(wiphy_idx)) return NULL; assert_cfg80211_lock(); - list_for_each_entry(drv, &cfg80211_drv_list, list) { - if (drv->wiphy_idx == wiphy_idx) { - result = drv; + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + if (rdev->wiphy_idx == wiphy_idx) { + result = rdev; break; } } @@ -64,32 +64,32 @@ struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx) int get_wiphy_idx(struct wiphy *wiphy) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; if (!wiphy) return WIPHY_IDX_STALE; - drv = wiphy_to_dev(wiphy); - return drv->wiphy_idx; + rdev = wiphy_to_dev(wiphy); + return rdev->wiphy_idx; } -/* requires cfg80211_drv_mutex to be held! */ +/* requires cfg80211_rdev_mutex to be held! */ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; if (!wiphy_idx_valid(wiphy_idx)) return NULL; assert_cfg80211_lock(); - drv = cfg80211_drv_by_wiphy_idx(wiphy_idx); - if (!drv) + rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx); + if (!rdev) return NULL; - return &drv->wiphy; + return &rdev->wiphy; } /* requires cfg80211_mutex to be held! */ struct cfg80211_registered_device * -__cfg80211_drv_from_info(struct genl_info *info) +__cfg80211_rdev_from_info(struct genl_info *info) { int ifindex; struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL; @@ -99,7 +99,7 @@ __cfg80211_drv_from_info(struct genl_info *info) assert_cfg80211_lock(); if (info->attrs[NL80211_ATTR_WIPHY]) { - bywiphyidx = cfg80211_drv_by_wiphy_idx( + bywiphyidx = cfg80211_rdev_by_wiphy_idx( nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); err = -ENODEV; } @@ -134,26 +134,26 @@ __cfg80211_drv_from_info(struct genl_info *info) struct cfg80211_registered_device * cfg80211_get_dev_from_info(struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; mutex_lock(&cfg80211_mutex); - drv = __cfg80211_drv_from_info(info); + rdev = __cfg80211_rdev_from_info(info); /* if it is not an error we grab the lock on * it to assure it won't be going away while * we operate on it */ - if (!IS_ERR(drv)) - mutex_lock(&drv->mtx); + if (!IS_ERR(rdev)) + mutex_lock(&rdev->mtx); mutex_unlock(&cfg80211_mutex); - return drv; + return rdev; } struct cfg80211_registered_device * cfg80211_get_dev_from_ifindex(int ifindex) { - struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV); + struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV); struct net_device *dev; mutex_lock(&cfg80211_mutex); @@ -161,21 +161,21 @@ cfg80211_get_dev_from_ifindex(int ifindex) if (!dev) goto out; if (dev->ieee80211_ptr) { - drv = wiphy_to_dev(dev->ieee80211_ptr->wiphy); - mutex_lock(&drv->mtx); + rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); + mutex_lock(&rdev->mtx); } else - drv = ERR_PTR(-ENODEV); + rdev = ERR_PTR(-ENODEV); dev_put(dev); out: mutex_unlock(&cfg80211_mutex); - return drv; + return rdev; } /* requires cfg80211_mutex to be held */ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, char *newname) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev2; int wiphy_idx, taken = -1, result, digits; assert_cfg80211_lock(); @@ -201,8 +201,8 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, return 0; /* Ensure another device does not already have this name. */ - list_for_each_entry(drv, &cfg80211_drv_list, list) - if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0) + list_for_each_entry(rdev2, &cfg80211_rdev_list, list) + if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) return -EINVAL; result = device_rename(&rdev->wiphy.dev, newname); @@ -224,26 +224,26 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) { - struct cfg80211_registered_device *drv = data; + struct cfg80211_registered_device *rdev = data; - drv->ops->rfkill_poll(&drv->wiphy); + rdev->ops->rfkill_poll(&rdev->wiphy); } static int cfg80211_rfkill_set_block(void *data, bool blocked) { - struct cfg80211_registered_device *drv = data; + struct cfg80211_registered_device *rdev = data; struct wireless_dev *wdev; if (!blocked) return 0; rtnl_lock(); - mutex_lock(&drv->devlist_mtx); + mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &drv->netdev_list, list) + list_for_each_entry(wdev, &rdev->netdev_list, list) dev_close(wdev->netdev); - mutex_unlock(&drv->devlist_mtx); + mutex_unlock(&rdev->devlist_mtx); rtnl_unlock(); return 0; @@ -251,10 +251,10 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) static void cfg80211_rfkill_sync_work(struct work_struct *work) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; - drv = container_of(work, struct cfg80211_registered_device, rfkill_sync); - cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill)); + rdev = container_of(work, struct cfg80211_registered_device, rfkill_sync); + cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill)); } static void cfg80211_process_events(struct wireless_dev *wdev) @@ -328,79 +328,79 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) { static int wiphy_counter; - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int alloc_size; WARN_ON(!ops->add_key && ops->del_key); WARN_ON(ops->add_key && !ops->del_key); - alloc_size = sizeof(*drv) + sizeof_priv; + alloc_size = sizeof(*rdev) + sizeof_priv; - drv = kzalloc(alloc_size, GFP_KERNEL); - if (!drv) + rdev = kzalloc(alloc_size, GFP_KERNEL); + if (!rdev) return NULL; - drv->ops = ops; + rdev->ops = ops; mutex_lock(&cfg80211_mutex); - drv->wiphy_idx = wiphy_counter++; + rdev->wiphy_idx = wiphy_counter++; - if (unlikely(!wiphy_idx_valid(drv->wiphy_idx))) { + if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { wiphy_counter--; mutex_unlock(&cfg80211_mutex); /* ugh, wrapped! */ - kfree(drv); + kfree(rdev); return NULL; } mutex_unlock(&cfg80211_mutex); /* give it a proper name */ - dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->wiphy_idx); - - mutex_init(&drv->mtx); - mutex_init(&drv->devlist_mtx); - INIT_LIST_HEAD(&drv->netdev_list); - spin_lock_init(&drv->bss_lock); - INIT_LIST_HEAD(&drv->bss_list); - INIT_WORK(&drv->scan_done_wk, __cfg80211_scan_done); - - device_initialize(&drv->wiphy.dev); - drv->wiphy.dev.class = &ieee80211_class; - drv->wiphy.dev.platform_data = drv; - - drv->rfkill_ops.set_block = cfg80211_rfkill_set_block; - drv->rfkill = rfkill_alloc(dev_name(&drv->wiphy.dev), - &drv->wiphy.dev, RFKILL_TYPE_WLAN, - &drv->rfkill_ops, drv); - - if (!drv->rfkill) { - kfree(drv); + dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); + + mutex_init(&rdev->mtx); + mutex_init(&rdev->devlist_mtx); + INIT_LIST_HEAD(&rdev->netdev_list); + spin_lock_init(&rdev->bss_lock); + INIT_LIST_HEAD(&rdev->bss_list); + INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); + + device_initialize(&rdev->wiphy.dev); + rdev->wiphy.dev.class = &ieee80211_class; + rdev->wiphy.dev.platform_data = rdev; + + rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; + rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev), + &rdev->wiphy.dev, RFKILL_TYPE_WLAN, + &rdev->rfkill_ops, rdev); + + if (!rdev->rfkill) { + kfree(rdev); return NULL; } - INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work); - INIT_WORK(&drv->conn_work, cfg80211_conn_work); - INIT_WORK(&drv->event_work, cfg80211_event_work); + INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work); + INIT_WORK(&rdev->conn_work, cfg80211_conn_work); + INIT_WORK(&rdev->event_work, cfg80211_event_work); /* * Initialize wiphy parameters to IEEE 802.11 MIB default values. * Fragmentation and RTS threshold are disabled by default with the * special -1 value. */ - drv->wiphy.retry_short = 7; - drv->wiphy.retry_long = 4; - drv->wiphy.frag_threshold = (u32) -1; - drv->wiphy.rts_threshold = (u32) -1; + rdev->wiphy.retry_short = 7; + rdev->wiphy.retry_long = 4; + rdev->wiphy.frag_threshold = (u32) -1; + rdev->wiphy.rts_threshold = (u32) -1; - return &drv->wiphy; + return &rdev->wiphy; } EXPORT_SYMBOL(wiphy_new); int wiphy_register(struct wiphy *wiphy) { - struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); int res; enum ieee80211_band band; struct ieee80211_supported_band *sband; @@ -454,11 +454,11 @@ int wiphy_register(struct wiphy *wiphy) /* check and set up bitrates */ ieee80211_set_bitrate_flags(wiphy); - res = device_add(&drv->wiphy.dev); + res = device_add(&rdev->wiphy.dev); if (res) return res; - res = rfkill_register(drv->rfkill); + res = rfkill_register(rdev->rfkill); if (res) goto out_rm_dev; @@ -467,16 +467,16 @@ int wiphy_register(struct wiphy *wiphy) /* set up regulatory info */ wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); - list_add(&drv->list, &cfg80211_drv_list); + list_add(&rdev->list, &cfg80211_rdev_list); mutex_unlock(&cfg80211_mutex); /* add to debugfs */ - drv->wiphy.debugfsdir = - debugfs_create_dir(wiphy_name(&drv->wiphy), + rdev->wiphy.debugfsdir = + debugfs_create_dir(wiphy_name(&rdev->wiphy), ieee80211_debugfs_dir); - if (IS_ERR(drv->wiphy.debugfsdir)) - drv->wiphy.debugfsdir = NULL; + if (IS_ERR(rdev->wiphy.debugfsdir)) + rdev->wiphy.debugfsdir = NULL; if (wiphy->custom_regulatory) { struct regulatory_request request; @@ -489,48 +489,48 @@ int wiphy_register(struct wiphy *wiphy) nl80211_send_reg_change_event(&request); } - cfg80211_debugfs_drv_add(drv); + cfg80211_debugfs_rdev_add(rdev); return 0; out_rm_dev: - device_del(&drv->wiphy.dev); + device_del(&rdev->wiphy.dev); return res; } EXPORT_SYMBOL(wiphy_register); void wiphy_rfkill_start_polling(struct wiphy *wiphy) { - struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - if (!drv->ops->rfkill_poll) + if (!rdev->ops->rfkill_poll) return; - drv->rfkill_ops.poll = cfg80211_rfkill_poll; - rfkill_resume_polling(drv->rfkill); + rdev->rfkill_ops.poll = cfg80211_rfkill_poll; + rfkill_resume_polling(rdev->rfkill); } EXPORT_SYMBOL(wiphy_rfkill_start_polling); void wiphy_rfkill_stop_polling(struct wiphy *wiphy) { - struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - rfkill_pause_polling(drv->rfkill); + rfkill_pause_polling(rdev->rfkill); } EXPORT_SYMBOL(wiphy_rfkill_stop_polling); void wiphy_unregister(struct wiphy *wiphy) { - struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - rfkill_unregister(drv->rfkill); + rfkill_unregister(rdev->rfkill); /* protect the device list */ mutex_lock(&cfg80211_mutex); - BUG_ON(!list_empty(&drv->netdev_list)); + BUG_ON(!list_empty(&rdev->netdev_list)); /* - * Try to grab drv->mtx. If a command is still in progress, + * Try to grab rdev->mtx. If a command is still in progress, * hopefully the driver will refuse it since it's tearing * down the device already. We wait for this command to complete * before unlinking the item from the list. @@ -539,38 +539,38 @@ void wiphy_unregister(struct wiphy *wiphy) * get to lock contention here if userspace issues a command * that identified the hardware by wiphy index. */ - mutex_lock(&drv->mtx); + mutex_lock(&rdev->mtx); /* unlock again before freeing */ - mutex_unlock(&drv->mtx); + mutex_unlock(&rdev->mtx); - cancel_work_sync(&drv->conn_work); - cancel_work_sync(&drv->scan_done_wk); - kfree(drv->scan_req); - flush_work(&drv->event_work); + cancel_work_sync(&rdev->conn_work); + cancel_work_sync(&rdev->scan_done_wk); + kfree(rdev->scan_req); + flush_work(&rdev->event_work); - cfg80211_debugfs_drv_del(drv); + cfg80211_debugfs_rdev_del(rdev); /* If this device got a regulatory hint tell core its * free to listen now to a new shiny device regulatory hint */ reg_device_remove(wiphy); - list_del(&drv->list); - device_del(&drv->wiphy.dev); - debugfs_remove(drv->wiphy.debugfsdir); + list_del(&rdev->list); + device_del(&rdev->wiphy.dev); + debugfs_remove(rdev->wiphy.debugfsdir); mutex_unlock(&cfg80211_mutex); } EXPORT_SYMBOL(wiphy_unregister); -void cfg80211_dev_free(struct cfg80211_registered_device *drv) +void cfg80211_dev_free(struct cfg80211_registered_device *rdev) { struct cfg80211_internal_bss *scan, *tmp; - rfkill_destroy(drv->rfkill); - mutex_destroy(&drv->mtx); - mutex_destroy(&drv->devlist_mtx); - list_for_each_entry_safe(scan, tmp, &drv->bss_list, list) + rfkill_destroy(rdev->rfkill); + mutex_destroy(&rdev->mtx); + mutex_destroy(&rdev->devlist_mtx); + list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) cfg80211_put_bss(&scan->pub); - kfree(drv); + kfree(rdev); } void wiphy_free(struct wiphy *wiphy) @@ -581,10 +581,10 @@ EXPORT_SYMBOL(wiphy_free); void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) { - struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - if (rfkill_set_hw_state(drv->rfkill, blocked)) - schedule_work(&drv->rfkill_sync); + if (rfkill_set_hw_state(rdev->rfkill, blocked)) + schedule_work(&rdev->rfkill_sync); } EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); diff --git a/net/wireless/core.h b/net/wireless/core.h index 5ccd642..e46cd6e 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -97,13 +97,13 @@ bool wiphy_idx_valid(int wiphy_idx) } extern struct mutex cfg80211_mutex; -extern struct list_head cfg80211_drv_list; +extern struct list_head cfg80211_rdev_list; #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) /* * You can use this to mark a wiphy_idx as not having an associated wiphy. - * It guarantees cfg80211_drv_by_wiphy_idx(wiphy_idx) will return NULL + * It guarantees cfg80211_rdev_by_wiphy_idx(wiphy_idx) will return NULL */ #define WIPHY_IDX_STALE -1 @@ -136,11 +136,11 @@ static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) } -struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); +struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx); int get_wiphy_idx(struct wiphy *wiphy); struct cfg80211_registered_device * -__cfg80211_drv_from_info(struct genl_info *info); +__cfg80211_rdev_from_info(struct genl_info *info); /* * This function returns a pointer to the driver @@ -153,7 +153,7 @@ __cfg80211_drv_from_info(struct genl_info *info); * * This is necessary because we need to lock the global * mutex to get an item off the list safely, and then - * we lock the drv mutex so it doesn't go away under us. + * we lock the rdev mutex so it doesn't go away under us. * * We don't want to keep cfg80211_mutex locked * for all the time in order to allow requests on @@ -165,22 +165,22 @@ __cfg80211_drv_from_info(struct genl_info *info); extern struct cfg80211_registered_device * cfg80211_get_dev_from_info(struct genl_info *info); -/* requires cfg80211_drv_mutex to be held! */ +/* requires cfg80211_rdev_mutex to be held! */ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ extern struct cfg80211_registered_device * cfg80211_get_dev_from_ifindex(int ifindex); -static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *drv) +static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev) { - mutex_lock(&drv->mtx); + mutex_lock(&rdev->mtx); } -static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *drv) +static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *rdev) { - BUG_ON(IS_ERR(drv) || !drv); - mutex_unlock(&drv->mtx); + BUG_ON(IS_ERR(rdev) || !rdev); + mutex_unlock(&rdev->mtx); } static inline void wdev_lock(struct wireless_dev *wdev) @@ -240,9 +240,9 @@ struct cfg80211_event { /* free object */ -extern void cfg80211_dev_free(struct cfg80211_registered_device *drv); +extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); -extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv, +extern int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, char *newname); void ieee80211_set_bitrate_flags(struct wiphy *wiphy); diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c index 679ddfc..13d93d8 100644 --- a/net/wireless/debugfs.c +++ b/net/wireless/debugfs.c @@ -104,15 +104,15 @@ static const struct file_operations ht40allow_map_ops = { }; #define DEBUGFS_ADD(name) \ - drv->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd, \ - &drv->wiphy, &name## _ops); + rdev->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd, \ + &rdev->wiphy, &name## _ops); #define DEBUGFS_DEL(name) \ - debugfs_remove(drv->debugfs.name); \ - drv->debugfs.name = NULL; + debugfs_remove(rdev->debugfs.name); \ + rdev->debugfs.name = NULL; -void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) +void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) { - struct dentry *phyd = drv->wiphy.debugfsdir; + struct dentry *phyd = rdev->wiphy.debugfsdir; DEBUGFS_ADD(rts_threshold); DEBUGFS_ADD(fragmentation_threshold); @@ -121,7 +121,7 @@ void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) DEBUGFS_ADD(ht40allow_map); } -void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) +void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev) { DEBUGFS_DEL(rts_threshold); DEBUGFS_DEL(fragmentation_threshold); diff --git a/net/wireless/debugfs.h b/net/wireless/debugfs.h index c226983..6419b6d 100644 --- a/net/wireless/debugfs.h +++ b/net/wireless/debugfs.h @@ -2,13 +2,13 @@ #define __CFG80211_DEBUGFS_H #ifdef CONFIG_CFG80211_DEBUGFS -void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv); -void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv); +void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev); +void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev); #else static inline -void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) {} +void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) {} static inline -void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) {} +void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev) {} #endif #endif /* __CFG80211_DEBUGFS_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cf4ac78..9deb12f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -29,9 +29,9 @@ static struct genl_family nl80211_fam = { .maxattr = NL80211_ATTR_MAX, }; -/* internal helper: get drv and dev */ -static int get_drv_dev_by_info_ifindex(struct nlattr **attrs, - struct cfg80211_registered_device **drv, +/* internal helper: get rdev and dev */ +static int get_rdev_dev_by_info_ifindex(struct nlattr **attrs, + struct cfg80211_registered_device **rdev, struct net_device **dev) { int ifindex; @@ -44,10 +44,10 @@ static int get_drv_dev_by_info_ifindex(struct nlattr **attrs, if (!*dev) return -ENODEV; - *drv = cfg80211_get_dev_from_ifindex(ifindex); - if (IS_ERR(*drv)) { + *rdev = cfg80211_get_dev_from_ifindex(ifindex); + if (IS_ERR(*rdev)) { dev_put(*dev); - return PTR_ERR(*drv); + return PTR_ERR(*rdev); } return 0; @@ -378,7 +378,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) struct cfg80211_registered_device *dev; mutex_lock(&cfg80211_mutex); - list_for_each_entry(dev, &cfg80211_drv_list, list) { + list_for_each_entry(dev, &cfg80211_rdev_list, list) { if (++idx <= start) continue; if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, @@ -460,7 +460,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) mutex_lock(&cfg80211_mutex); - rdev = __cfg80211_drv_from_info(info); + rdev = __cfg80211_rdev_from_info(info); if (IS_ERR(rdev)) { mutex_unlock(&cfg80211_mutex); result = PTR_ERR(rdev); @@ -683,7 +683,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * struct wireless_dev *wdev; mutex_lock(&cfg80211_mutex); - list_for_each_entry(dev, &cfg80211_drv_list, list) { + list_for_each_entry(dev, &cfg80211_rdev_list, list) { if (wp_idx < wp_start) { wp_idx++; continue; @@ -724,7 +724,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) struct net_device *netdev; int err; - err = get_drv_dev_by_info_ifindex(info->attrs, &dev, &netdev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &dev, &netdev); if (err) return err; @@ -780,7 +780,7 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct vif_params params; int err; enum nl80211_iftype otype, ntype; @@ -792,7 +792,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; @@ -808,8 +808,8 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } } - if (!drv->ops->change_virtual_intf || - !(drv->wiphy.interface_modes & (1 << ntype))) { + if (!rdev->ops->change_virtual_intf || + !(rdev->wiphy.interface_modes & (1 << ntype))) { err = -EOPNOTSUPP; goto unlock; } @@ -839,7 +839,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } if (change) - err = drv->ops->change_virtual_intf(&drv->wiphy, dev, + err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, ntype, flags, ¶ms); else err = 0; @@ -853,7 +853,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) unlock: dev_put(dev); - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); unlock_rtnl: rtnl_unlock(); return err; @@ -861,7 +861,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct vif_params params; int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; @@ -880,14 +880,14 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - drv = cfg80211_get_dev_from_info(info); - if (IS_ERR(drv)) { - err = PTR_ERR(drv); + rdev = cfg80211_get_dev_from_info(info); + if (IS_ERR(rdev)) { + err = PTR_ERR(rdev); goto unlock_rtnl; } - if (!drv->ops->add_virtual_intf || - !(drv->wiphy.interface_modes & (1 << type))) { + if (!rdev->ops->add_virtual_intf || + !(rdev->wiphy.interface_modes & (1 << type))) { err = -EOPNOTSUPP; goto unlock; } @@ -901,12 +901,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, &flags); - err = drv->ops->add_virtual_intf(&drv->wiphy, + err = rdev->ops->add_virtual_intf(&rdev->wiphy, nla_data(info->attrs[NL80211_ATTR_IFNAME]), type, err ? NULL : &flags, ¶ms); unlock: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); unlock_rtnl: rtnl_unlock(); return err; @@ -914,27 +914,27 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int ifindex, err; struct net_device *dev; rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; ifindex = dev->ifindex; dev_put(dev); - if (!drv->ops->del_virtual_intf) { + if (!rdev->ops->del_virtual_intf) { err = -EOPNOTSUPP; goto out; } - err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); + err = rdev->ops->del_virtual_intf(&rdev->wiphy, ifindex); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); unlock_rtnl: rtnl_unlock(); return err; @@ -968,7 +968,7 @@ static void get_key_callback(void *c, struct key_params *params) static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; u8 key_idx = 0; @@ -990,11 +990,11 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; - if (!drv->ops->get_key) { + if (!rdev->ops->get_key) { err = -EOPNOTSUPP; goto out; } @@ -1020,7 +1020,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) if (mac_addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); - err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, + err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr, &cookie, get_key_callback); if (err) @@ -1037,7 +1037,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) err = -ENOBUFS; nlmsg_free(msg); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -1047,7 +1047,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; u8 key_idx; @@ -1072,24 +1072,24 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) - func = drv->ops->set_default_key; + func = rdev->ops->set_default_key; else - func = drv->ops->set_default_mgmt_key; + func = rdev->ops->set_default_mgmt_key; if (!func) { err = -EOPNOTSUPP; goto out; } - err = func(&drv->wiphy, dev, key_idx); + err = func(&rdev->wiphy, dev, key_idx); #ifdef CONFIG_WIRELESS_EXT if (!err) { - if (func == drv->ops->set_default_key) + if (func == rdev->ops->set_default_key) dev->ieee80211_ptr->wext.default_key = key_idx; else dev->ieee80211_ptr->wext.default_mgmt_key = key_idx; @@ -1097,7 +1097,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) #endif out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: @@ -1108,7 +1108,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err, i; struct net_device *dev; struct key_params params; @@ -1143,27 +1143,27 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; - for (i = 0; i < drv->wiphy.n_cipher_suites; i++) - if (params.cipher == drv->wiphy.cipher_suites[i]) + for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) + if (params.cipher == rdev->wiphy.cipher_suites[i]) break; - if (i == drv->wiphy.n_cipher_suites) { + if (i == rdev->wiphy.n_cipher_suites) { err = -EINVAL; goto out; } - if (!drv->ops->add_key) { + if (!rdev->ops->add_key) { err = -EOPNOTSUPP; goto out; } - err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms); + err = rdev->ops->add_key(&rdev->wiphy, dev, key_idx, mac_addr, ¶ms); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -1173,7 +1173,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; u8 key_idx = 0; @@ -1190,16 +1190,16 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; - if (!drv->ops->del_key) { + if (!rdev->ops->del_key) { err = -EOPNOTSUPP; goto out; } - err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); + err = rdev->ops->del_key(&rdev->wiphy, dev, key_idx, mac_addr); #ifdef CONFIG_WIRELESS_EXT if (!err) { @@ -1211,7 +1211,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) #endif out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: @@ -1224,7 +1224,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) { int (*call)(struct wiphy *wiphy, struct net_device *dev, struct beacon_parameters *info); - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; struct beacon_parameters params; @@ -1235,7 +1235,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1254,10 +1254,10 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) goto out; } - call = drv->ops->add_beacon; + call = rdev->ops->add_beacon; break; case NL80211_CMD_SET_BEACON: - call = drv->ops->set_beacon; + call = rdev->ops->set_beacon; break; default: WARN_ON(1); @@ -1303,10 +1303,10 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) goto out; } - err = call(&drv->wiphy, dev, ¶ms); + err = call(&rdev->wiphy, dev, ¶ms); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -1316,17 +1316,17 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; - if (!drv->ops->del_beacon) { + if (!rdev->ops->del_beacon) { err = -EOPNOTSUPP; goto out; } @@ -1335,10 +1335,10 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) err = -EOPNOTSUPP; goto out; } - err = drv->ops->del_beacon(&drv->wiphy, dev); + err = rdev->ops->del_beacon(&rdev->wiphy, dev); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -1581,7 +1581,7 @@ static int nl80211_dump_station(struct sk_buff *skb, static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; struct station_info sinfo; @@ -1597,16 +1597,16 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; - if (!drv->ops->get_station) { + if (!rdev->ops->get_station) { err = -EOPNOTSUPP; goto out; } - err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); + err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); if (err) goto out; @@ -1624,7 +1624,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) out_free: nlmsg_free(msg); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -1655,7 +1655,7 @@ static int get_vlan(struct nlattr *vlanattr, static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; struct station_parameters params; @@ -1697,11 +1697,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; - err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); + err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan); if (err) goto out; @@ -1750,17 +1750,17 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) if (err) goto out; - if (!drv->ops->change_station) { + if (!rdev->ops->change_station) { err = -EOPNOTSUPP; goto out; } - err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms); + err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, ¶ms); out: if (params.vlan) dev_put(params.vlan); - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -1770,7 +1770,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; struct station_parameters params; @@ -1810,11 +1810,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; - err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); + err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan); if (err) goto out; @@ -1850,7 +1850,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (err) goto out; - if (!drv->ops->add_station) { + if (!rdev->ops->add_station) { err = -EOPNOTSUPP; goto out; } @@ -1860,12 +1860,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) goto out; } - err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms); + err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); out: if (params.vlan) dev_put(params.vlan); - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -1875,7 +1875,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; u8 *mac_addr = NULL; @@ -1885,7 +1885,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; @@ -1896,15 +1896,15 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!drv->ops->del_station) { + if (!rdev->ops->del_station) { err = -EOPNOTSUPP; goto out; } - err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); + err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2044,7 +2044,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; struct mpath_info pinfo; @@ -2061,11 +2061,11 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; - if (!drv->ops->get_mpath) { + if (!rdev->ops->get_mpath) { err = -EOPNOTSUPP; goto out; } @@ -2075,7 +2075,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) goto out; } - err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); + err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); if (err) goto out; @@ -2093,7 +2093,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) out_free: nlmsg_free(msg); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2103,7 +2103,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; u8 *dst = NULL; @@ -2120,11 +2120,11 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; - if (!drv->ops->change_mpath) { + if (!rdev->ops->change_mpath) { err = -EOPNOTSUPP; goto out; } @@ -2139,10 +2139,10 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) goto out; } - err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); + err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2151,7 +2151,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) } static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; u8 *dst = NULL; @@ -2168,11 +2168,11 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; - if (!drv->ops->add_mpath) { + if (!rdev->ops->add_mpath) { err = -EOPNOTSUPP; goto out; } @@ -2187,10 +2187,10 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) goto out; } - err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); + err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2200,7 +2200,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; u8 *dst = NULL; @@ -2210,19 +2210,19 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; - if (!drv->ops->del_mpath) { + if (!rdev->ops->del_mpath) { err = -EOPNOTSUPP; goto out; } - err = drv->ops->del_mpath(&drv->wiphy, dev, dst); + err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2232,7 +2232,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; int err; struct net_device *dev; struct bss_parameters params; @@ -2261,11 +2261,11 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; - if (!drv->ops->change_bss) { + if (!rdev->ops->change_bss) { err = -EOPNOTSUPP; goto out; } @@ -2275,10 +2275,10 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) goto out; } - err = drv->ops->change_bss(&drv->wiphy, dev, ¶ms); + err = rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2369,7 +2369,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) static int nl80211_get_mesh_params(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct mesh_config cur_params; int err; struct net_device *dev; @@ -2380,17 +2380,17 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, rtnl_lock(); /* Look up our device */ - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; - if (!drv->ops->get_mesh_params) { + if (!rdev->ops->get_mesh_params) { err = -EOPNOTSUPP; goto out; } /* Get the mesh params */ - err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params); + err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); if (err) goto out; @@ -2444,7 +2444,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, err = -EMSGSIZE; out: /* Cleanup */ - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2482,7 +2482,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) { int err; u32 mask; - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct net_device *dev; struct mesh_config cfg; struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; @@ -2497,11 +2497,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; - if (!drv->ops->set_mesh_params) { + if (!rdev->ops->set_mesh_params) { err = -EOPNOTSUPP; goto out; } @@ -2546,11 +2546,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) nla_get_u16); /* Apply changes */ - err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask); + err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); out: /* cleanup */ - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -2737,7 +2737,7 @@ static int validate_scan_freqs(struct nlattr *freqs) static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct net_device *dev; struct cfg80211_scan_request *request; struct cfg80211_ssid *ssid; @@ -2753,13 +2753,13 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto out_rtnl; - wiphy = &drv->wiphy; + wiphy = &rdev->wiphy; - if (!drv->ops->scan) { + if (!rdev->ops->scan) { err = -EOPNOTSUPP; goto out; } @@ -2769,7 +2769,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) goto out; } - if (drv->scan_req) { + if (rdev->scan_req) { err = -EBUSY; goto out; } @@ -2876,21 +2876,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) } request->ifidx = dev->ifindex; - request->wiphy = &drv->wiphy; + request->wiphy = &rdev->wiphy; - drv->scan_req = request; - err = drv->ops->scan(&drv->wiphy, dev, request); + rdev->scan_req = request; + err = rdev->ops->scan(&rdev->wiphy, dev, request); if (!err) - nl80211_send_scan_start(drv, dev); + nl80211_send_scan_start(rdev, dev); out_free: if (err) { - drv->scan_req = NULL; + rdev->scan_req = NULL; kfree(request); } out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); out_rtnl: rtnl_unlock(); @@ -3043,7 +3043,7 @@ static bool nl80211_valid_cipher_suite(u32 cipher) static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct net_device *dev; struct ieee80211_channel *chan; const u8 *bssid, *ssid, *ie = NULL; @@ -3067,11 +3067,11 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; - if (!drv->ops->auth) { + if (!rdev->ops->auth) { err = -EOPNOTSUPP; goto out; } @@ -3087,7 +3087,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) } bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); - chan = ieee80211_get_channel(&drv->wiphy, + chan = ieee80211_get_channel(&rdev->wiphy, nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { err = -EINVAL; @@ -3108,11 +3108,11 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) goto out; } - err = cfg80211_mlme_auth(drv, dev, chan, auth_type, bssid, + err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, ssid, ssid_len, ie, ie_len); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3202,7 +3202,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3268,7 +3268,7 @@ unlock_rtnl: static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct net_device *dev; const u8 *ie = NULL, *bssid; int err, ie_len = 0; @@ -3285,11 +3285,11 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; - if (!drv->ops->deauth) { + if (!rdev->ops->deauth) { err = -EOPNOTSUPP; goto out; } @@ -3318,10 +3318,10 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } - err = cfg80211_mlme_deauth(drv, dev, bssid, ie, ie_len, reason_code); + err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3330,7 +3330,7 @@ unlock_rtnl: static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct net_device *dev; const u8 *ie = NULL, *bssid; int err, ie_len = 0; @@ -3347,11 +3347,11 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; - if (!drv->ops->disassoc) { + if (!rdev->ops->disassoc) { err = -EOPNOTSUPP; goto out; } @@ -3380,10 +3380,10 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } - err = cfg80211_mlme_disassoc(drv, dev, bssid, ie, ie_len, reason_code); + err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3392,7 +3392,7 @@ unlock_rtnl: static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct net_device *dev; struct cfg80211_ibss_params ibss; struct wiphy *wiphy; @@ -3419,11 +3419,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; - if (!drv->ops->join_ibss) { + if (!rdev->ops->join_ibss) { err = -EOPNOTSUPP; goto out; } @@ -3438,7 +3438,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) goto out; } - wiphy = &drv->wiphy; + wiphy = &rdev->wiphy; if (info->attrs[NL80211_ATTR_MAC]) ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); @@ -3461,10 +3461,10 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; - err = cfg80211_join_ibss(drv, dev, &ibss); + err = cfg80211_join_ibss(rdev, dev, &ibss); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3473,17 +3473,17 @@ unlock_rtnl: static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct net_device *dev; int err; rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; - if (!drv->ops->leave_ibss) { + if (!rdev->ops->leave_ibss) { err = -EOPNOTSUPP; goto out; } @@ -3498,10 +3498,10 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) goto out; } - err = cfg80211_leave_ibss(drv, dev, false); + err = cfg80211_leave_ibss(rdev, dev, false); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3632,7 +3632,7 @@ EXPORT_SYMBOL(cfg80211_testmode_event); static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct net_device *dev; struct cfg80211_connect_params connect; struct wiphy *wiphy; @@ -3663,7 +3663,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) return err; rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3677,7 +3677,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) goto out; } - wiphy = &drv->wiphy; + wiphy = &rdev->wiphy; connect.bssid = NULL; connect.channel = NULL; @@ -3704,10 +3704,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) } } - err = cfg80211_connect(drv, dev, &connect); + err = cfg80211_connect(rdev, dev, &connect); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); @@ -3716,7 +3716,7 @@ unlock_rtnl: static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct net_device *dev; int err; u16 reason; @@ -3731,7 +3731,7 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3745,10 +3745,10 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) goto out; } - err = cfg80211_disconnect(drv, dev, reason, true); + err = cfg80211_disconnect(rdev, dev, reason, true); out: - cfg80211_unlock_rdev(drv); + cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: rtnl_unlock(); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5e14371..2b4a6c6 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1061,10 +1061,10 @@ static bool ignore_reg_update(struct wiphy *wiphy, static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; - list_for_each_entry(drv, &cfg80211_drv_list, list) - wiphy_update_regulatory(&drv->wiphy, initiator); + list_for_each_entry(rdev, &cfg80211_rdev_list, list) + wiphy_update_regulatory(&rdev->wiphy, initiator); } static void handle_reg_beacon(struct wiphy *wiphy, @@ -1614,7 +1614,7 @@ static void reg_process_pending_hints(void) /* Processes beacon hints -- this has nothing to do with country IEs */ static void reg_process_pending_beacon_hints(void) { - struct cfg80211_registered_device *drv; + struct cfg80211_registered_device *rdev; struct reg_beacon *pending_beacon, *tmp; mutex_lock(&cfg80211_mutex); @@ -1633,8 +1633,8 @@ static void reg_process_pending_beacon_hints(void) list_del_init(&pending_beacon->list); /* Applies the beacon hint to current wiphys */ - list_for_each_entry(drv, &cfg80211_drv_list, list) - wiphy_update_new_beacon(&drv->wiphy, pending_beacon); + list_for_each_entry(rdev, &cfg80211_rdev_list, list) + wiphy_update_new_beacon(&rdev->wiphy, pending_beacon); /* Remembers the beacon hint for new wiphys or reg changes */ list_add_tail(&pending_beacon->list, ®_beacon_list); @@ -1814,23 +1814,23 @@ void regulatory_hint_11d(struct wiphy *wiphy, if (likely(last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && wiphy_idx_valid(last_request->wiphy_idx))) { - struct cfg80211_registered_device *drv_last_ie; + struct cfg80211_registered_device *rdev_last_ie; - drv_last_ie = - cfg80211_drv_by_wiphy_idx(last_request->wiphy_idx); + rdev_last_ie = + cfg80211_rdev_by_wiphy_idx(last_request->wiphy_idx); /* * Lets keep this simple -- we trust the first AP * after we intersect with CRDA */ - if (likely(&drv_last_ie->wiphy == wiphy)) { + if (likely(&rdev_last_ie->wiphy == wiphy)) { /* * Ignore IEs coming in on this wiphy with * the same alpha2 and environment cap */ - if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, + if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2, alpha2) && - env == drv_last_ie->env)) { + env == rdev_last_ie->env)) { goto out; } /* @@ -1846,9 +1846,9 @@ void regulatory_hint_11d(struct wiphy *wiphy, * Ignore IEs coming in on two separate wiphys with * the same alpha2 and environment cap */ - if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, + if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2, alpha2) && - env == drv_last_ie->env)) { + env == rdev_last_ie->env)) { goto out; } /* We could potentially intersect though */ @@ -1995,14 +1995,14 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - struct cfg80211_registered_device *drv; - drv = cfg80211_drv_by_wiphy_idx( + struct cfg80211_registered_device *rdev; + rdev = cfg80211_rdev_by_wiphy_idx( last_request->wiphy_idx); - if (drv) { + if (rdev) { printk(KERN_INFO "cfg80211: Current regulatory " "domain updated by AP to: %c%c\n", - drv->country_ie_alpha2[0], - drv->country_ie_alpha2[1]); + rdev->country_ie_alpha2[0], + rdev->country_ie_alpha2[1]); } else printk(KERN_INFO "cfg80211: Current regulatory " "domain intersected: \n"); @@ -2063,7 +2063,7 @@ static inline void reg_country_ie_process_debug( static int __set_regdom(const struct ieee80211_regdomain *rd) { const struct ieee80211_regdomain *intersected_rd = NULL; - struct cfg80211_registered_device *drv = NULL; + struct cfg80211_registered_device *rdev = NULL; struct wiphy *request_wiphy; /* Some basic sanity checks first */ @@ -2202,11 +2202,11 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) if (!intersected_rd) return -EINVAL; - drv = wiphy_to_dev(request_wiphy); + rdev = wiphy_to_dev(request_wiphy); - drv->country_ie_alpha2[0] = rd->alpha2[0]; - drv->country_ie_alpha2[1] = rd->alpha2[1]; - drv->env = last_request->country_ie_env; + rdev->country_ie_alpha2[0] = rd->alpha2[0]; + rdev->country_ie_alpha2[1] = rd->alpha2[1]; + rdev->env = last_request->country_ie_env; BUG_ON(intersected_rd == rd); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 472e241..df9173f 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -33,15 +33,15 @@ struct cfg80211_conn { static int cfg80211_conn_scan(struct wireless_dev *wdev) { - struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); struct cfg80211_scan_request *request; int n_channels, err; ASSERT_RTNL(); - ASSERT_RDEV_LOCK(drv); + ASSERT_RDEV_LOCK(rdev); ASSERT_WDEV_LOCK(wdev); - if (drv->scan_req) + if (rdev->scan_req) return -EBUSY; if (wdev->conn->params.channel) { @@ -87,16 +87,16 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) request->ssids[0].ssid_len = wdev->conn->params.ssid_len; request->ifidx = wdev->netdev->ifindex; - request->wiphy = &drv->wiphy; + request->wiphy = &rdev->wiphy; - drv->scan_req = request; + rdev->scan_req = request; - err = drv->ops->scan(wdev->wiphy, wdev->netdev, request); + err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request); if (!err) { wdev->conn->state = CFG80211_CONN_SCANNING; - nl80211_send_scan_start(drv, wdev->netdev); + nl80211_send_scan_start(rdev, wdev->netdev); } else { - drv->scan_req = NULL; + rdev->scan_req = NULL; kfree(request); } return err; @@ -104,7 +104,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) static int cfg80211_conn_do_work(struct wireless_dev *wdev) { - struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); struct cfg80211_connect_params *params; int err; @@ -119,15 +119,15 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) case CFG80211_CONN_SCAN_AGAIN: return cfg80211_conn_scan(wdev); case CFG80211_CONN_AUTHENTICATE_NEXT: - BUG_ON(!drv->ops->auth); + BUG_ON(!rdev->ops->auth); wdev->conn->state = CFG80211_CONN_AUTHENTICATING; - return __cfg80211_mlme_auth(drv, wdev->netdev, + return __cfg80211_mlme_auth(rdev, wdev->netdev, params->channel, params->auth_type, params->bssid, params->ssid, params->ssid_len, NULL, 0); case CFG80211_CONN_ASSOCIATE_NEXT: - BUG_ON(!drv->ops->assoc); + BUG_ON(!rdev->ops->assoc); wdev->conn->state = CFG80211_CONN_ASSOCIATING; /* * We could, later, implement roaming here and then actually @@ -135,14 +135,14 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) * that some APs don't like that -- so we'd need to retry * the association. */ - err = __cfg80211_mlme_assoc(drv, wdev->netdev, + err = __cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel, params->bssid, NULL, params->ssid, params->ssid_len, params->ie, params->ie_len, false, ¶ms->crypto); if (err) - __cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid, + __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, NULL, 0, WLAN_REASON_DEAUTH_LEAVING); return err; @@ -153,15 +153,15 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) void cfg80211_conn_work(struct work_struct *work) { - struct cfg80211_registered_device *drv = + struct cfg80211_registered_device *rdev = container_of(work, struct cfg80211_registered_device, conn_work); struct wireless_dev *wdev; rtnl_lock(); - cfg80211_lock_rdev(drv); - mutex_lock(&drv->devlist_mtx); + cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &drv->netdev_list, list) { + list_for_each_entry(wdev, &rdev->netdev_list, list) { wdev_lock(wdev); if (!netif_running(wdev->netdev)) { wdev_unlock(wdev); @@ -181,14 +181,14 @@ void cfg80211_conn_work(struct work_struct *work) wdev_unlock(wdev); } - mutex_unlock(&drv->devlist_mtx); - cfg80211_unlock_rdev(drv); + mutex_unlock(&rdev->devlist_mtx); + cfg80211_unlock_rdev(rdev); rtnl_unlock(); } static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) { - struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); struct cfg80211_bss *bss; u16 capa = WLAN_CAPABILITY_ESS; @@ -209,7 +209,7 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) wdev->conn->params.bssid = wdev->conn->bssid; wdev->conn->params.channel = bss->channel; wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; - schedule_work(&drv->conn_work); + schedule_work(&rdev->conn_work); cfg80211_put_bss(bss); return true; @@ -218,7 +218,7 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) static void __cfg80211_sme_scan_done(struct net_device *dev) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); ASSERT_WDEV_LOCK(wdev); @@ -235,7 +235,7 @@ static void __cfg80211_sme_scan_done(struct net_device *dev) if (!cfg80211_get_conn_bss(wdev)) { /* not found */ if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) - schedule_work(&drv->conn_work); + schedule_work(&rdev->conn_work); else __cfg80211_connect_result( wdev->netdev, -- cgit v0.10.2 From 0b20633d966eb08506f8796544aef7a9ab5f3544 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:56:13 +0200 Subject: cfg80211: disallow configuring unsupported interfaces In order to force drivers to advertise their interface types, don't just disallow creating new interfaces with unadvertised types but also disallow setting them UP. Additionally, add some validation on the operations the drivers support. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index b5e2f6d..1a78b3c 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -331,8 +331,13 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) struct cfg80211_registered_device *rdev; int alloc_size; - WARN_ON(!ops->add_key && ops->del_key); - WARN_ON(ops->add_key && !ops->del_key); + WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); + WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); + WARN_ON(ops->connect && !ops->disconnect); + WARN_ON(ops->join_ibss && !ops->leave_ibss); + WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf); + WARN_ON(ops->add_station && !ops->del_station); + WARN_ON(ops->add_mpath && !ops->del_mpath); alloc_size = sizeof(*rdev) + sizeof_priv; @@ -687,6 +692,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, mutex_destroy(&wdev->mtx); break; case NETDEV_PRE_UP: + if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) + return notifier_from_errno(-EOPNOTSUPP); if (rfkill_blocked(rdev->rfkill)) return notifier_from_errno(-ERFKILL); break; -- cgit v0.10.2 From 5bc38193c1793e240a7e0b93f129606931e35fdb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 11:00:55 +0200 Subject: hwsim: make testmode_cmd static sparse correctly complains about this, no reason for it not to be static. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 6ac8565..4befa48 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -729,7 +729,8 @@ static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { static int hwsim_fops_ps_write(void *dat, u64 val); -int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, + void *data, int len) { struct mac80211_hwsim_data *hwsim = hw->priv; struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1]; -- cgit v0.10.2 From e90476d3bab4322070c0afb3e3b55671de8664ea Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Sat, 11 Jul 2009 09:32:46 +0800 Subject: x86: Remove duplicated #include Remove duplicated #include in: arch/x86/kernel/dumpstack.c Signed-off-by: Huang Weiyi Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index c840571..2d8a371 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -15,7 +15,6 @@ #include #include #include -#include #include -- cgit v0.10.2 From 8bdbd962ecfcbdd96f9dbb02d780b4553afd2543 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 4 Jul 2009 00:35:45 +0100 Subject: x86/cpu: Clean up various files a bit No code changes except printk levels (although some of the K6 mtrr code might be clearer if there were a few as would splitting out some of the intel cache code). Signed-off-by: Alan Cox LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 28e5f59..c6eb02e 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include @@ -45,8 +45,8 @@ static void __cpuinit init_amd_k5(struct cpuinfo_x86 *c) #define CBAR_ENB (0x80000000) #define CBAR_KEY (0X000000CB) if (c->x86_model == 9 || c->x86_model == 10) { - if (inl (CBAR) & CBAR_ENB) - outl (0 | CBAR_KEY, CBAR); + if (inl(CBAR) & CBAR_ENB) + outl(0 | CBAR_KEY, CBAR); } } @@ -87,9 +87,10 @@ static void __cpuinit init_amd_k6(struct cpuinfo_x86 *c) d = d2-d; if (d > 20*K6_BUG_LOOP) - printk("system stability may be impaired when more than 32 MB are used.\n"); + printk(KERN_CONT + "system stability may be impaired when more than 32 MB are used.\n"); else - printk("probably OK (after B9730xxxx).\n"); + printk(KERN_CONT "probably OK (after B9730xxxx).\n"); printk(KERN_INFO "Please see http://membres.lycos.fr/poulot/k6bug.html\n"); } @@ -219,8 +220,9 @@ static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c) if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) { rdmsr(MSR_K7_CLK_CTL, l, h); if ((l & 0xfff00000) != 0x20000000) { - printk ("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", l, - ((l & 0x000fffff)|0x20000000)); + printk(KERN_INFO + "CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", + l, ((l & 0x000fffff)|0x20000000)); wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h); } } @@ -398,7 +400,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) u32 level; level = cpuid_eax(1); - if((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58) + if ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58) set_cpu_cap(c, X86_FEATURE_REP_GOOD); } if (c->x86 == 0x10 || c->x86 == 0x11) @@ -487,27 +489,30 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) * benefit in doing so. */ if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg)) { - printk(KERN_DEBUG "tseg: %010llx\n", tseg); - if ((tseg>>PMD_SHIFT) < + printk(KERN_DEBUG "tseg: %010llx\n", tseg); + if ((tseg>>PMD_SHIFT) < (max_low_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) || - ((tseg>>PMD_SHIFT) < + ((tseg>>PMD_SHIFT) < (max_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) && - (tseg>>PMD_SHIFT) >= (1ULL<<(32 - PMD_SHIFT)))) - set_memory_4k((unsigned long)__va(tseg), 1); + (tseg>>PMD_SHIFT) >= (1ULL<<(32 - PMD_SHIFT)))) + set_memory_4k((unsigned long)__va(tseg), 1); } } #endif } #ifdef CONFIG_X86_32 -static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) +static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, + unsigned int size) { /* AMD errata T13 (order #21922) */ if ((c->x86 == 6)) { - if (c->x86_model == 3 && c->x86_mask == 0) /* Duron Rev A0 */ + /* Duron Rev A0 */ + if (c->x86_model == 3 && c->x86_mask == 0) size = 64; + /* Tbird rev A1/A2 */ if (c->x86_model == 4 && - (c->x86_mask == 0 || c->x86_mask == 1)) /* Tbird rev A1/A2 */ + (c->x86_mask == 0 || c->x86_mask == 1)) size = 256; } return size; diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index c8e315f..01a2652 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -81,7 +81,7 @@ static void __init check_fpu(void) boot_cpu_data.fdiv_bug = fdiv_bug; if (boot_cpu_data.fdiv_bug) - printk("Hmm, FPU with FDIV bug.\n"); + printk(KERN_WARNING "Hmm, FPU with FDIV bug.\n"); } static void __init check_hlt(void) @@ -98,7 +98,7 @@ static void __init check_hlt(void) halt(); halt(); halt(); - printk("OK.\n"); + printk(KERN_CONT "OK.\n"); } /* @@ -122,9 +122,9 @@ static void __init check_popad(void) * CPU hard. Too bad. */ if (res != 12345678) - printk("Buggy.\n"); + printk(KERN_CONT "Buggy.\n"); else - printk("OK.\n"); + printk(KERN_CONT "OK.\n"); #endif } @@ -156,7 +156,7 @@ void __init check_bugs(void) { identify_boot_cpu(); #ifndef CONFIG_SMP - printk("CPU: "); + printk(KERN_INFO "CPU: "); print_cpu_info(&boot_cpu_data); #endif check_config(); diff --git a/arch/x86/kernel/cpu/bugs_64.c b/arch/x86/kernel/cpu/bugs_64.c index 9a3ed06..04f0fe5 100644 --- a/arch/x86/kernel/cpu/bugs_64.c +++ b/arch/x86/kernel/cpu/bugs_64.c @@ -15,7 +15,7 @@ void __init check_bugs(void) { identify_boot_cpu(); #if !defined(CONFIG_SMP) - printk("CPU: "); + printk(KERN_INFO "CPU: "); print_cpu_info(&boot_cpu_data); #endif alternative_instructions(); diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index d6f27c9..c96ea44 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -18,8 +18,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -28,13 +28,13 @@ #include #include #include -#include +#include #include #include #include #include #include -#include +#include #ifdef CONFIG_X86_LOCAL_APIC #include diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c index 593171e..19807b8 100644 --- a/arch/x86/kernel/cpu/cyrix.c +++ b/arch/x86/kernel/cpu/cyrix.c @@ -3,10 +3,10 @@ #include #include #include -#include +#include #include #include -#include +#include #include #include @@ -282,7 +282,8 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c) * The 5510/5520 companion chips have a funky PIT. */ if (vendor == PCI_VENDOR_ID_CYRIX && - (device == PCI_DEVICE_ID_CYRIX_5510 || device == PCI_DEVICE_ID_CYRIX_5520)) + (device == PCI_DEVICE_ID_CYRIX_5510 || + device == PCI_DEVICE_ID_CYRIX_5520)) mark_tsc_unstable("cyrix 5510/5520 detected"); } #endif @@ -299,7 +300,8 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c) * ? : 0x7x * GX1 : 0x8x GX1 datasheet 56 */ - if ((0x30 <= dir1 && dir1 <= 0x6f) || (0x80 <= dir1 && dir1 <= 0x8f)) + if ((0x30 <= dir1 && dir1 <= 0x6f) || + (0x80 <= dir1 && dir1 <= 0x8f)) geode_configure(); return; } else { /* MediaGX */ @@ -427,9 +429,12 @@ static void __cpuinit cyrix_identify(struct cpuinfo_x86 *c) printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n"); local_irq_save(flags); ccr3 = getCx86(CX86_CCR3); - setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ - setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x80); /* enable cpuid */ - setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ + /* enable MAPEN */ + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); + /* enable cpuid */ + setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x80); + /* disable MAPEN */ + setCx86(CX86_CCR3, ccr3); local_irq_restore(flags); } } diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c index fb5b86a..93ba8ee 100644 --- a/arch/x86/kernel/cpu/hypervisor.c +++ b/arch/x86/kernel/cpu/hypervisor.c @@ -28,11 +28,10 @@ static inline void __cpuinit detect_hypervisor_vendor(struct cpuinfo_x86 *c) { - if (vmware_platform()) { + if (vmware_platform()) c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE; - } else { + else c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE; - } } unsigned long get_hypervisor_tsc_freq(void) diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 3260ab0..80a722a 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -7,17 +7,17 @@ #include #include #include +#include #include #include #include -#include #include #include #include #ifdef CONFIG_X86_64 -#include +#include #include #endif @@ -174,7 +174,8 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c) #ifdef CONFIG_X86_F00F_BUG /* * All current models of Pentium and Pentium with MMX technology CPUs - * have the F0 0F bug, which lets nonprivileged users lock up the system. + * have the F0 0F bug, which lets nonprivileged users lock up the + * system. * Note that the workaround only should be initialized once... */ c->f00f_bug = 0; @@ -207,7 +208,7 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c) printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n"); printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n"); lo |= MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE; - wrmsr (MSR_IA32_MISC_ENABLE, lo, hi); + wrmsr(MSR_IA32_MISC_ENABLE, lo, hi); } } @@ -283,7 +284,7 @@ static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c) /* Intel has a non-standard dependency on %ecx for this CPUID level. */ cpuid_count(4, 0, &eax, &ebx, &ecx, &edx); if (eax & 0x1f) - return ((eax >> 26) + 1); + return (eax >> 26) + 1; else return 1; } diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 789efe2..306bf0d 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -3,7 +3,7 @@ * * Changes: * Venkatesh Pallipadi : Adding cache identification through cpuid(4) - * Ashok Raj : Work with CPU hotplug infrastructure. + * Ashok Raj : Work with CPU hotplug infrastructure. * Andi Kleen / Andreas Herrmann : CPUID4 emulation on AMD. */ @@ -16,7 +16,7 @@ #include #include -#include +#include #include #define LVL_1_INST 1 @@ -25,14 +25,15 @@ #define LVL_3 4 #define LVL_TRACE 5 -struct _cache_table -{ +struct _cache_table { unsigned char descriptor; char cache_type; short size; }; -/* all the cache descriptor types we care about (no TLB or trace cache entries) */ +/* All the cache descriptor types we care about (no TLB or + trace cache entries) */ + static const struct _cache_table __cpuinitconst cache_table[] = { { 0x06, LVL_1_INST, 8 }, /* 4-way set assoc, 32 byte line size */ @@ -105,8 +106,7 @@ static const struct _cache_table __cpuinitconst cache_table[] = }; -enum _cache_type -{ +enum _cache_type { CACHE_TYPE_NULL = 0, CACHE_TYPE_DATA = 1, CACHE_TYPE_INST = 2, @@ -170,31 +170,31 @@ unsigned short num_cache_leaves; Maybe later */ union l1_cache { struct { - unsigned line_size : 8; - unsigned lines_per_tag : 8; - unsigned assoc : 8; - unsigned size_in_kb : 8; + unsigned line_size:8; + unsigned lines_per_tag:8; + unsigned assoc:8; + unsigned size_in_kb:8; }; unsigned val; }; union l2_cache { struct { - unsigned line_size : 8; - unsigned lines_per_tag : 4; - unsigned assoc : 4; - unsigned size_in_kb : 16; + unsigned line_size:8; + unsigned lines_per_tag:4; + unsigned assoc:4; + unsigned size_in_kb:16; }; unsigned val; }; union l3_cache { struct { - unsigned line_size : 8; - unsigned lines_per_tag : 4; - unsigned assoc : 4; - unsigned res : 2; - unsigned size_encoded : 14; + unsigned line_size:8; + unsigned lines_per_tag:4; + unsigned assoc:4; + unsigned res:2; + unsigned size_encoded:14; }; unsigned val; }; @@ -350,7 +350,8 @@ static int __cpuinit find_num_cache_leaves(void) unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) { - unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ + /* Cache sizes */ + unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */ unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */ unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb; @@ -377,8 +378,8 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) retval = cpuid4_cache_lookup_regs(i, &this_leaf); if (retval >= 0) { - switch(this_leaf.eax.split.level) { - case 1: + switch (this_leaf.eax.split.level) { + case 1: if (this_leaf.eax.split.type == CACHE_TYPE_DATA) new_l1d = this_leaf.size/1024; @@ -386,19 +387,20 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) CACHE_TYPE_INST) new_l1i = this_leaf.size/1024; break; - case 2: + case 2: new_l2 = this_leaf.size/1024; num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing; index_msb = get_count_order(num_threads_sharing); l2_id = c->apicid >> index_msb; break; - case 3: + case 3: new_l3 = this_leaf.size/1024; num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing; - index_msb = get_count_order(num_threads_sharing); + index_msb = get_count_order( + num_threads_sharing); l3_id = c->apicid >> index_msb; break; - default: + default: break; } } @@ -421,22 +423,21 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) /* Number of times to iterate */ n = cpuid_eax(2) & 0xFF; - for ( i = 0 ; i < n ; i++ ) { + for (i = 0 ; i < n ; i++) { cpuid(2, ®s[0], ®s[1], ®s[2], ®s[3]); /* If bit 31 is set, this is an unknown format */ - for ( j = 0 ; j < 3 ; j++ ) { - if (regs[j] & (1 << 31)) regs[j] = 0; - } + for (j = 0 ; j < 3 ; j++) + if (regs[j] & (1 << 31)) + regs[j] = 0; /* Byte 0 is level count, not a descriptor */ - for ( j = 1 ; j < 16 ; j++ ) { + for (j = 1 ; j < 16 ; j++) { unsigned char des = dp[j]; unsigned char k = 0; /* look up this descriptor in the table */ - while (cache_table[k].descriptor != 0) - { + while (cache_table[k].descriptor != 0) { if (cache_table[k].descriptor == des) { if (only_trace && cache_table[k].cache_type != LVL_TRACE) break; @@ -488,14 +489,14 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) } if (trace) - printk (KERN_INFO "CPU: Trace cache: %dK uops", trace); - else if ( l1i ) - printk (KERN_INFO "CPU: L1 I cache: %dK", l1i); + printk(KERN_INFO "CPU: Trace cache: %dK uops", trace); + else if (l1i) + printk(KERN_INFO "CPU: L1 I cache: %dK", l1i); if (l1d) - printk(", L1 D cache: %dK\n", l1d); + printk(KERN_CONT ", L1 D cache: %dK\n", l1d); else - printk("\n"); + printk(KERN_CONT "\n"); if (l2) printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); @@ -558,8 +559,13 @@ static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index) } } #else -static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index) {} -static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index) {} +static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index) +{ +} + +static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index) +{ +} #endif static void __cpuinit free_cache_attributes(unsigned int cpu) @@ -645,7 +651,7 @@ static DEFINE_PER_CPU(struct _index_kobject *, index_kobject); static ssize_t show_##file_name \ (struct _cpuid4_info *this_leaf, char *buf) \ { \ - return sprintf (buf, "%lu\n", (unsigned long)this_leaf->object + val); \ + return sprintf(buf, "%lu\n", (unsigned long)this_leaf->object + val); \ } show_one_plus(level, eax.split.level, 0); @@ -656,7 +662,7 @@ show_one_plus(number_of_sets, ecx.split.number_of_sets, 1); static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf) { - return sprintf (buf, "%luK\n", this_leaf->size / 1024); + return sprintf(buf, "%luK\n", this_leaf->size / 1024); } static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf, @@ -669,7 +675,7 @@ static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf, const struct cpumask *mask; mask = to_cpumask(this_leaf->shared_cpu_map); - n = type? + n = type ? cpulist_scnprintf(buf, len-2, mask) : cpumask_scnprintf(buf, len-2, mask); buf[n++] = '\n'; @@ -800,7 +806,7 @@ static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644, static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644, show_cache_disable_1, store_cache_disable_1); -static struct attribute * default_attrs[] = { +static struct attribute *default_attrs[] = { &type.attr, &level.attr, &coherency_line_size.attr, @@ -815,7 +821,7 @@ static struct attribute * default_attrs[] = { NULL }; -static ssize_t show(struct kobject * kobj, struct attribute * attr, char * buf) +static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) { struct _cache_attr *fattr = to_attr(attr); struct _index_kobject *this_leaf = to_object(kobj); @@ -828,8 +834,8 @@ static ssize_t show(struct kobject * kobj, struct attribute * attr, char * buf) return ret; } -static ssize_t store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { struct _cache_attr *fattr = to_attr(attr); struct _index_kobject *this_leaf = to_object(kobj); @@ -883,7 +889,7 @@ static int __cpuinit cpuid4_cache_sysfs_init(unsigned int cpu) goto err_out; per_cpu(index_kobject, cpu) = kzalloc( - sizeof(struct _index_kobject ) * num_cache_leaves, GFP_KERNEL); + sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL); if (unlikely(per_cpu(index_kobject, cpu) == NULL)) goto err_out; @@ -917,7 +923,7 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) } for (i = 0; i < num_cache_leaves; i++) { - this_object = INDEX_KOBJECT_PTR(cpu,i); + this_object = INDEX_KOBJECT_PTR(cpu, i); this_object->cpu = cpu; this_object->index = i; retval = kobject_init_and_add(&(this_object->kobj), @@ -925,9 +931,8 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) per_cpu(cache_kobject, cpu), "index%1lu", i); if (unlikely(retval)) { - for (j = 0; j < i; j++) { - kobject_put(&(INDEX_KOBJECT_PTR(cpu,j)->kobj)); - } + for (j = 0; j < i; j++) + kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj)); kobject_put(per_cpu(cache_kobject, cpu)); cpuid4_cache_sysfs_exit(cpu); return retval; @@ -952,7 +957,7 @@ static void __cpuinit cache_remove_dev(struct sys_device * sys_dev) cpumask_clear_cpu(cpu, to_cpumask(cache_dev_map)); for (i = 0; i < num_cache_leaves; i++) - kobject_put(&(INDEX_KOBJECT_PTR(cpu,i)->kobj)); + kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj)); kobject_put(per_cpu(cache_kobject, cpu)); cpuid4_cache_sysfs_exit(cpu); } @@ -977,8 +982,7 @@ static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier = -{ +static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier = { .notifier_call = cacheinfo_cpu_callback, }; diff --git a/arch/x86/kernel/cpu/perfctr-watchdog.c b/arch/x86/kernel/cpu/perfctr-watchdog.c index 5c481f6..8100a29 100644 --- a/arch/x86/kernel/cpu/perfctr-watchdog.c +++ b/arch/x86/kernel/cpu/perfctr-watchdog.c @@ -68,16 +68,16 @@ static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr) /* returns the bit offset of the performance counter register */ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - return (msr - MSR_K7_PERFCTR0); + return msr - MSR_K7_PERFCTR0; case X86_VENDOR_INTEL: if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) - return (msr - MSR_ARCH_PERFMON_PERFCTR0); + return msr - MSR_ARCH_PERFMON_PERFCTR0; switch (boot_cpu_data.x86) { case 6: - return (msr - MSR_P6_PERFCTR0); + return msr - MSR_P6_PERFCTR0; case 15: - return (msr - MSR_P4_BPU_PERFCTR0); + return msr - MSR_P4_BPU_PERFCTR0; } } return 0; @@ -92,16 +92,16 @@ static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr) /* returns the bit offset of the event selection register */ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - return (msr - MSR_K7_EVNTSEL0); + return msr - MSR_K7_EVNTSEL0; case X86_VENDOR_INTEL: if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) - return (msr - MSR_ARCH_PERFMON_EVENTSEL0); + return msr - MSR_ARCH_PERFMON_EVENTSEL0; switch (boot_cpu_data.x86) { case 6: - return (msr - MSR_P6_EVNTSEL0); + return msr - MSR_P6_EVNTSEL0; case 15: - return (msr - MSR_P4_BSU_ESCR0); + return msr - MSR_P4_BSU_ESCR0; } } return 0; @@ -113,7 +113,7 @@ int avail_to_resrv_perfctr_nmi_bit(unsigned int counter) { BUG_ON(counter > NMI_MAX_COUNTER_BITS); - return (!test_bit(counter, perfctr_nmi_owner)); + return !test_bit(counter, perfctr_nmi_owner); } /* checks the an msr for availability */ @@ -124,7 +124,7 @@ int avail_to_resrv_perfctr_nmi(unsigned int msr) counter = nmi_perfctr_msr_to_bit(msr); BUG_ON(counter > NMI_MAX_COUNTER_BITS); - return (!test_bit(counter, perfctr_nmi_owner)); + return !test_bit(counter, perfctr_nmi_owner); } EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit); @@ -237,7 +237,7 @@ static unsigned int adjust_for_32bit_ctr(unsigned int hz) */ counter_val = (u64)cpu_khz * 1000; do_div(counter_val, retval); - if (counter_val > 0x7fffffffULL) { + if (counter_val > 0x7fffffffULL) { u64 count = (u64)cpu_khz * 1000; do_div(count, 0x7fffffffUL); retval = count + 1; @@ -251,7 +251,7 @@ static void write_watchdog_counter(unsigned int perfctr_msr, u64 count = (u64)cpu_khz * 1000; do_div(count, nmi_hz); - if(descr) + if (descr) pr_debug("setting %s to -0x%08Lx\n", descr, count); wrmsrl(perfctr_msr, 0 - count); } @@ -262,7 +262,7 @@ static void write_watchdog_counter32(unsigned int perfctr_msr, u64 count = (u64)cpu_khz * 1000; do_div(count, nmi_hz); - if(descr) + if (descr) pr_debug("setting %s to -0x%08Lx\n", descr, count); wrmsr(perfctr_msr, (u32)(-count), 0); } @@ -296,7 +296,7 @@ static int setup_k7_watchdog(unsigned nmi_hz) /* setup the timer */ wrmsr(evntsel_msr, evntsel, 0); - write_watchdog_counter(perfctr_msr, "K7_PERFCTR0",nmi_hz); + write_watchdog_counter(perfctr_msr, "K7_PERFCTR0", nmi_hz); /* initialize the wd struct before enabling */ wd->perfctr_msr = perfctr_msr; @@ -387,7 +387,7 @@ static int setup_p6_watchdog(unsigned nmi_hz) /* setup the timer */ wrmsr(evntsel_msr, evntsel, 0); nmi_hz = adjust_for_32bit_ctr(nmi_hz); - write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0",nmi_hz); + write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0", nmi_hz); /* initialize the wd struct before enabling */ wd->perfctr_msr = perfctr_msr; @@ -415,7 +415,7 @@ static void __kprobes p6_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz) apic_write(APIC_LVTPC, APIC_DM_NMI); /* P6/ARCH_PERFMON has 32 bit counter write */ - write_watchdog_counter32(wd->perfctr_msr, NULL,nmi_hz); + write_watchdog_counter32(wd->perfctr_msr, NULL, nmi_hz); } static const struct wd_ops p6_wd_ops = { @@ -490,9 +490,9 @@ static int setup_p4_watchdog(unsigned nmi_hz) if (smp_num_siblings == 2) { unsigned int ebx, apicid; - ebx = cpuid_ebx(1); - apicid = (ebx >> 24) & 0xff; - ht_num = apicid & 1; + ebx = cpuid_ebx(1); + apicid = (ebx >> 24) & 0xff; + ht_num = apicid & 1; } else #endif ht_num = 0; @@ -544,7 +544,7 @@ static int setup_p4_watchdog(unsigned nmi_hz) } evntsel = P4_ESCR_EVENT_SELECT(0x3F) - | P4_ESCR_OS + | P4_ESCR_OS | P4_ESCR_USR; cccr_val |= P4_CCCR_THRESHOLD(15) @@ -612,7 +612,7 @@ static void __kprobes p4_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz) { unsigned dummy; /* - * P4 quirks: + * P4 quirks: * - An overflown perfctr will assert its interrupt * until the OVF flag in its CCCR is cleared. * - LVTPC is masked on interrupt and must be @@ -662,7 +662,8 @@ static int setup_intel_arch_watchdog(unsigned nmi_hz) * NOTE: Corresponding bit = 0 in ebx indicates event present. */ cpuid(10, &(eax.full), &ebx, &unused, &unused); - if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) || + if ((eax.split.mask_length < + (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) || (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT)) return 0; diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c index d5e3039..1e90434 100644 --- a/arch/x86/kernel/cpu/proc.c +++ b/arch/x86/kernel/cpu/proc.c @@ -128,7 +128,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (i < ARRAY_SIZE(x86_power_flags) && x86_power_flags[i]) seq_printf(m, "%s%s", - x86_power_flags[i][0]?" ":"", + x86_power_flags[i][0] ? " " : "", x86_power_flags[i]); else seq_printf(m, " [%d]", i); diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index 284c399..bc24f51 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -49,17 +49,17 @@ static inline int __vmware_platform(void) static unsigned long __vmware_get_tsc_khz(void) { - uint64_t tsc_hz; - uint32_t eax, ebx, ecx, edx; + uint64_t tsc_hz; + uint32_t eax, ebx, ecx, edx; - VMWARE_PORT(GETHZ, eax, ebx, ecx, edx); + VMWARE_PORT(GETHZ, eax, ebx, ecx, edx); - if (ebx == UINT_MAX) - return 0; - tsc_hz = eax | (((uint64_t)ebx) << 32); - do_div(tsc_hz, 1000); - BUG_ON(tsc_hz >> 32); - return tsc_hz; + if (ebx == UINT_MAX) + return 0; + tsc_hz = eax | (((uint64_t)ebx) << 32); + do_div(tsc_hz, 1000); + BUG_ON(tsc_hz >> 32); + return tsc_hz; } /* -- cgit v0.10.2 From 99d27e1c59e34869605de625b033c52163f5bfa7 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 9 Jul 2009 20:30:57 +0800 Subject: crypto: shash - Export/import hash state only This patch replaces the full descriptor export with an export of the partial hash state. This allows the use of a consistent export format across all implementations of a given algorithm. This is useful because a number of cases require the use of the partial hash state, e.g., PadLock can use the SHA1 hash state to get around the fact that it can only hash contiguous data chunks. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 23e05a1..14a3b70 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -172,19 +172,15 @@ int crypto_shash_digest(struct shash_desc *desc, const u8 *data, } EXPORT_SYMBOL_GPL(crypto_shash_digest); -int crypto_shash_import(struct shash_desc *desc, const u8 *in) +static int shash_no_export(struct shash_desc *desc, void *out) { - struct crypto_shash *tfm = desc->tfm; - struct shash_alg *alg = crypto_shash_alg(tfm); - - memcpy(shash_desc_ctx(desc), in, crypto_shash_descsize(tfm)); - - if (alg->reinit) - return alg->reinit(desc); + return -ENOSYS; +} - return 0; +static int shash_no_import(struct shash_desc *desc, const void *in) +{ + return -ENOSYS; } -EXPORT_SYMBOL_GPL(crypto_shash_import); static int shash_async_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) @@ -484,12 +480,19 @@ static int shash_prepare_alg(struct shash_alg *alg) struct crypto_alg *base = &alg->base; if (alg->digestsize > PAGE_SIZE / 8 || - alg->descsize > PAGE_SIZE / 8) + alg->descsize > PAGE_SIZE / 8 || + alg->statesize > PAGE_SIZE / 8) return -EINVAL; base->cra_type = &crypto_shash_type; base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_SHASH; + + if (!alg->import) + alg->import = shash_no_import; + if (!alg->export) + alg->export = shash_no_export; + return 0; } diff --git a/include/crypto/hash.h b/include/crypto/hash.h index d56bb71..3c4cce6 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -24,7 +24,6 @@ struct shash_desc { struct shash_alg { int (*init)(struct shash_desc *desc); - int (*reinit)(struct shash_desc *desc); int (*update)(struct shash_desc *desc, const u8 *data, unsigned int len); int (*final)(struct shash_desc *desc, u8 *out); @@ -32,11 +31,14 @@ struct shash_alg { unsigned int len, u8 *out); int (*digest)(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out); + int (*export)(struct shash_desc *desc, void *out); + int (*import)(struct shash_desc *desc, const void *in); int (*setkey)(struct crypto_shash *tfm, const u8 *key, unsigned int keylen); unsigned int descsize; unsigned int digestsize; + unsigned int statesize; struct crypto_alg base; }; @@ -251,6 +253,11 @@ static inline unsigned int crypto_shash_digestsize(struct crypto_shash *tfm) return crypto_shash_alg(tfm)->digestsize; } +static inline unsigned int crypto_shash_statesize(struct crypto_shash *tfm) +{ + return crypto_shash_alg(tfm)->statesize; +} + static inline u32 crypto_shash_get_flags(struct crypto_shash *tfm) { return crypto_tfm_get_flags(crypto_shash_tfm(tfm)); @@ -281,12 +288,15 @@ int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key, int crypto_shash_digest(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out); -static inline void crypto_shash_export(struct shash_desc *desc, u8 *out) +static inline int crypto_shash_export(struct shash_desc *desc, void *out) { - memcpy(out, shash_desc_ctx(desc), crypto_shash_descsize(desc->tfm)); + return crypto_shash_alg(desc->tfm)->export(desc, out); } -int crypto_shash_import(struct shash_desc *desc, const u8 *in); +static inline int crypto_shash_import(struct shash_desc *desc, const void *in) +{ + return crypto_shash_alg(desc->tfm)->import(desc, in); +} static inline int crypto_shash_init(struct shash_desc *desc) { -- cgit v0.10.2 From 8267adab9433593adb09d94626475c2a5921f111 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 9 Jul 2009 20:36:44 +0800 Subject: crypto: shash - Move finup/digest null checks to registration time This patch moves the run-time null finup/digest checks to the shash_prepare_alg function which is run at registration time. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 14a3b70..f7fcc65 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -142,8 +142,7 @@ int crypto_shash_finup(struct shash_desc *desc, const u8 *data, struct shash_alg *shash = crypto_shash_alg(tfm); unsigned long alignmask = crypto_shash_alignmask(tfm); - if (((unsigned long)data | (unsigned long)out) & alignmask || - !shash->finup) + if (((unsigned long)data | (unsigned long)out) & alignmask) return shash_finup_unaligned(desc, data, len, out); return shash->finup(desc, data, len, out); @@ -164,8 +163,7 @@ int crypto_shash_digest(struct shash_desc *desc, const u8 *data, struct shash_alg *shash = crypto_shash_alg(tfm); unsigned long alignmask = crypto_shash_alignmask(tfm); - if (((unsigned long)data | (unsigned long)out) & alignmask || - !shash->digest) + if (((unsigned long)data | (unsigned long)out) & alignmask) return shash_digest_unaligned(desc, data, len, out); return shash->digest(desc, data, len, out); @@ -488,6 +486,10 @@ static int shash_prepare_alg(struct shash_alg *alg) base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_SHASH; + if (!alg->finup) + alg->finup = shash_finup_unaligned; + if (!alg->digest) + alg->digest = shash_digest_unaligned; if (!alg->import) alg->import = shash_no_import; if (!alg->export) -- cgit v0.10.2 From e2a7ce4e185a94462698cc0e5192495ee3d22a2f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 9 Jul 2009 21:27:13 +0800 Subject: crypto: sha1_generic - Add export/import support This patch adds export/import support to sha1_generic. The exported type is defined by struct sha1_state, which is basically the entire descriptor state of sha1_generic. Signed-off-by: Herbert Xu diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c index 9efef20..0416091 100644 --- a/crypto/sha1_generic.c +++ b/crypto/sha1_generic.c @@ -25,31 +25,21 @@ #include #include -struct sha1_ctx { - u64 count; - u32 state[5]; - u8 buffer[64]; -}; - static int sha1_init(struct shash_desc *desc) { - struct sha1_ctx *sctx = shash_desc_ctx(desc); + struct sha1_state *sctx = shash_desc_ctx(desc); - static const struct sha1_ctx initstate = { - 0, - { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, - { 0, } + *sctx = (struct sha1_state){ + .state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, }; - *sctx = initstate; - return 0; } static int sha1_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - struct sha1_ctx *sctx = shash_desc_ctx(desc); + struct sha1_state *sctx = shash_desc_ctx(desc); unsigned int partial, done; const u8 *src; @@ -85,7 +75,7 @@ static int sha1_update(struct shash_desc *desc, const u8 *data, /* Add padding and return the message digest. */ static int sha1_final(struct shash_desc *desc, u8 *out) { - struct sha1_ctx *sctx = shash_desc_ctx(desc); + struct sha1_state *sctx = shash_desc_ctx(desc); __be32 *dst = (__be32 *)out; u32 i, index, padlen; __be64 bits; @@ -111,12 +101,31 @@ static int sha1_final(struct shash_desc *desc, u8 *out) return 0; } +static int sha1_export(struct shash_desc *desc, void *out) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int sha1_import(struct shash_desc *desc, const void *in) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + static struct shash_alg alg = { .digestsize = SHA1_DIGEST_SIZE, .init = sha1_init, .update = sha1_update, .final = sha1_final, - .descsize = sizeof(struct sha1_ctx), + .export = sha1_export, + .import = sha1_import, + .descsize = sizeof(struct sha1_state), + .statesize = sizeof(struct sha1_state), .base = { .cra_name = "sha1", .cra_driver_name= "sha1-generic", diff --git a/include/crypto/sha.h b/include/crypto/sha.h index c0ccc2b..922a248 100644 --- a/include/crypto/sha.h +++ b/include/crypto/sha.h @@ -5,6 +5,8 @@ #ifndef _CRYPTO_SHA_H #define _CRYPTO_SHA_H +#include + #define SHA1_DIGEST_SIZE 20 #define SHA1_BLOCK_SIZE 64 @@ -62,4 +64,10 @@ #define SHA512_H6 0x1f83d9abfb41bd6bULL #define SHA512_H7 0x5be0cd19137e2179ULL +struct sha1_state { + u64 count; + u32 state[SHA1_DIGEST_SIZE / 4]; + u8 buffer[SHA1_BLOCK_SIZE]; +}; + #endif -- cgit v0.10.2 From 3d4d277cf88e1980d905707b9c8ca61e8ad6bf0b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 10 Jul 2009 12:54:20 +0800 Subject: crypto: sha256_generic - Use 64-bit counter like sha1 This patch replaces the two 32-bit counter code in sha256_generic with the simpler 64-bit counter code from sha1. Signed-off-by: Herbert Xu diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index 6349d83..e58c71b 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -26,7 +26,7 @@ #include struct sha256_ctx { - u32 count[2]; + u64 count; u32 state[8]; u8 buf[128]; }; @@ -231,8 +231,7 @@ static int sha224_init(struct shash_desc *desc) sctx->state[5] = SHA224_H5; sctx->state[6] = SHA224_H6; sctx->state[7] = SHA224_H7; - sctx->count[0] = 0; - sctx->count[1] = 0; + sctx->count = 0; return 0; } @@ -248,7 +247,7 @@ static int sha256_init(struct shash_desc *desc) sctx->state[5] = SHA256_H5; sctx->state[6] = SHA256_H6; sctx->state[7] = SHA256_H7; - sctx->count[0] = sctx->count[1] = 0; + sctx->count = 0; return 0; } @@ -257,33 +256,30 @@ static int sha256_update(struct shash_desc *desc, const u8 *data, unsigned int len) { struct sha256_ctx *sctx = shash_desc_ctx(desc); - unsigned int i, index, part_len; - - /* Compute number of bytes mod 128 */ - index = (unsigned int)((sctx->count[0] >> 3) & 0x3f); - - /* Update number of bits */ - if ((sctx->count[0] += (len << 3)) < (len << 3)) { - sctx->count[1]++; - sctx->count[1] += (len >> 29); + unsigned int partial, done; + const u8 *src; + + partial = sctx->count & 0x3f; + sctx->count += len; + done = 0; + src = data; + + if ((partial + len) > 63) { + if (partial) { + done = -partial; + memcpy(sctx->buf + partial, data, done + 64); + src = sctx->buf; + } + + do { + sha256_transform(sctx->state, src); + done += 64; + src = data + done; + } while (done + 63 < len); + + partial = 0; } - - part_len = 64 - index; - - /* Transform as many times as possible. */ - if (len >= part_len) { - memcpy(&sctx->buf[index], data, part_len); - sha256_transform(sctx->state, sctx->buf); - - for (i = part_len; i + 63 < len; i += 64) - sha256_transform(sctx->state, &data[i]); - index = 0; - } else { - i = 0; - } - - /* Buffer remaining input */ - memcpy(&sctx->buf[index], &data[i], len-i); + memcpy(sctx->buf + partial, src, len - done); return 0; } @@ -292,22 +288,21 @@ static int sha256_final(struct shash_desc *desc, u8 *out) { struct sha256_ctx *sctx = shash_desc_ctx(desc); __be32 *dst = (__be32 *)out; - __be32 bits[2]; + __be64 bits; unsigned int index, pad_len; int i; static const u8 padding[64] = { 0x80, }; /* Save number of bits */ - bits[1] = cpu_to_be32(sctx->count[0]); - bits[0] = cpu_to_be32(sctx->count[1]); + bits = cpu_to_be64(sctx->count << 3); /* Pad out to 56 mod 64. */ - index = (sctx->count[0] >> 3) & 0x3f; + index = sctx->count & 0x3f; pad_len = (index < 56) ? (56 - index) : ((64+56) - index); sha256_update(desc, padding, pad_len); /* Append length (before padding) */ - sha256_update(desc, (const u8 *)bits, sizeof(bits)); + sha256_update(desc, (const u8 *)&bits, sizeof(bits)); /* Store state in digest */ for (i = 0; i < 8; i++) -- cgit v0.10.2 From 9b2fda7b94a769af13c24582739e50664b0e27a8 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 10 Jul 2009 13:00:27 +0800 Subject: crypto: sha256_generic - Add export/import support This patch adds export/import support to sha256_generic. The exported type is defined by struct sha256_state, which is basically the entire descriptor state of sha256_generic. Signed-off-by: Herbert Xu diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index e58c71b..c48459e 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -25,12 +25,6 @@ #include #include -struct sha256_ctx { - u64 count; - u32 state[8]; - u8 buf[128]; -}; - static inline u32 Ch(u32 x, u32 y, u32 z) { return z ^ (x & (y ^ z)); @@ -222,7 +216,7 @@ static void sha256_transform(u32 *state, const u8 *input) static int sha224_init(struct shash_desc *desc) { - struct sha256_ctx *sctx = shash_desc_ctx(desc); + struct sha256_state *sctx = shash_desc_ctx(desc); sctx->state[0] = SHA224_H0; sctx->state[1] = SHA224_H1; sctx->state[2] = SHA224_H2; @@ -238,7 +232,7 @@ static int sha224_init(struct shash_desc *desc) static int sha256_init(struct shash_desc *desc) { - struct sha256_ctx *sctx = shash_desc_ctx(desc); + struct sha256_state *sctx = shash_desc_ctx(desc); sctx->state[0] = SHA256_H0; sctx->state[1] = SHA256_H1; sctx->state[2] = SHA256_H2; @@ -255,7 +249,7 @@ static int sha256_init(struct shash_desc *desc) static int sha256_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - struct sha256_ctx *sctx = shash_desc_ctx(desc); + struct sha256_state *sctx = shash_desc_ctx(desc); unsigned int partial, done; const u8 *src; @@ -286,7 +280,7 @@ static int sha256_update(struct shash_desc *desc, const u8 *data, static int sha256_final(struct shash_desc *desc, u8 *out) { - struct sha256_ctx *sctx = shash_desc_ctx(desc); + struct sha256_state *sctx = shash_desc_ctx(desc); __be32 *dst = (__be32 *)out; __be64 bits; unsigned int index, pad_len; @@ -326,12 +320,31 @@ static int sha224_final(struct shash_desc *desc, u8 *hash) return 0; } +static int sha256_export(struct shash_desc *desc, void *out) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int sha256_import(struct shash_desc *desc, const void *in) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + static struct shash_alg sha256 = { .digestsize = SHA256_DIGEST_SIZE, .init = sha256_init, .update = sha256_update, .final = sha256_final, - .descsize = sizeof(struct sha256_ctx), + .export = sha256_export, + .import = sha256_import, + .descsize = sizeof(struct sha256_state), + .statesize = sizeof(struct sha256_state), .base = { .cra_name = "sha256", .cra_driver_name= "sha256-generic", @@ -346,7 +359,7 @@ static struct shash_alg sha224 = { .init = sha224_init, .update = sha256_update, .final = sha224_final, - .descsize = sizeof(struct sha256_ctx), + .descsize = sizeof(struct sha256_state), .base = { .cra_name = "sha224", .cra_driver_name= "sha224-generic", diff --git a/include/crypto/sha.h b/include/crypto/sha.h index 922a248..88ef5eb 100644 --- a/include/crypto/sha.h +++ b/include/crypto/sha.h @@ -70,4 +70,10 @@ struct sha1_state { u8 buffer[SHA1_BLOCK_SIZE]; }; +struct sha256_state { + u64 count; + u32 state[SHA256_DIGEST_SIZE / 4]; + u8 buf[SHA256_BLOCK_SIZE]; +}; + #endif -- cgit v0.10.2 From 406f104b4172de7452702c6810807c1b0132ba22 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 10 Jul 2009 13:18:26 +0800 Subject: crypto: sha1-s390 - Add export/import support This patch adds export/import support to sha1-s390. The exported type is defined by struct sha1_state, which is basically the entire descriptor state of sha1_generic. Signed-off-by: Herbert Xu diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index e85ba34..2c5ec79 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -46,12 +46,38 @@ static int sha1_init(struct shash_desc *desc) return 0; } +static int sha1_export(struct shash_desc *desc, void *out) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + struct sha1_state *octx = out; + + octx->count = sctx->count; + memcpy(octx->state, sctx->state, sizeof(octx->state)); + memcpy(octx->buffer, sctx->buf, sizeof(octx->buffer)); + return 0; +} + +static int sha1_import(struct shash_desc *desc, const u8 *in) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + struct sha1_state *ictx = in; + + sctx->count = ictx->count; + memcpy(sctx->state, ictx->state, sizeof(ictx->state)); + memcpy(sctx->buf, ictx->buffer, sizeof(ictx->buffer)); + sctx->func = KIMD_SHA_1; + return 0; +} + static struct shash_alg alg = { .digestsize = SHA1_DIGEST_SIZE, .init = sha1_init, .update = s390_sha_update, .final = s390_sha_final, + .export = sha1_export, + .import = sha1_import, .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha1_state), .base = { .cra_name = "sha1", .cra_driver_name= "sha1-s390", -- cgit v0.10.2 From f63559bef380a95093408691c1081f07da755b74 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 10 Jul 2009 13:20:32 +0800 Subject: crypto: sha256-s390 - Add export/import support This patch adds export/import support to sha256-s390. The exported type is defined by struct sha256_state, which is basically the entire descriptor state of sha256_generic. Signed-off-by: Herbert Xu diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index f9fefc5..943a669 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -42,12 +42,38 @@ static int sha256_init(struct shash_desc *desc) return 0; } +static int sha256_export(struct shash_desc *desc, void *out) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + struct sha256_state *octx = out; + + octx->count = sctx->count; + memcpy(octx->state, sctx->state, sizeof(octx->state)); + memcpy(octx->buf, sctx->buf, sizeof(octx->buf)); + return 0; +} + +static int sha256_import(struct shash_desc *desc, const u8 *in) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + struct sha256_state *ictx = in; + + sctx->count = ictx->count; + memcpy(sctx->state, ictx->state, sizeof(ictx->state)); + memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf)); + sctx->func = KIMD_SHA_256; + return 0; +} + static struct shash_alg alg = { .digestsize = SHA256_DIGEST_SIZE, .init = sha256_init, .update = s390_sha_update, .final = s390_sha_final, + .export = sha256_export, + .import = sha256_import, .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha256_state), .base = { .cra_name = "sha256", .cra_driver_name= "sha256-s390", -- cgit v0.10.2 From 7d024608265eb815ae4ce1e5da097ec9d800dda4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 10 Jul 2009 17:26:44 +0800 Subject: crypto: padlock - Use shash fallback for sha This patch changes padlock sha fallback to shash instead of hash. Signed-off-by: Herbert Xu diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index a2c8e85..868da54 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -12,28 +12,24 @@ * */ -#include +#include #include #include #include #include #include -#include #include #include #include #include #include "padlock.h" -#define SHA1_DEFAULT_FALLBACK "sha1-generic" -#define SHA256_DEFAULT_FALLBACK "sha256-generic" - struct padlock_sha_ctx { char *data; size_t used; int bypass; void (*f_sha_padlock)(const char *in, char *out, int count); - struct hash_desc fallback; + struct shash_desc *fallback; }; static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm) @@ -47,21 +43,26 @@ static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm) static struct crypto_alg sha1_alg, sha256_alg; -static void padlock_sha_bypass(struct crypto_tfm *tfm) +static int padlock_sha_bypass(struct crypto_tfm *tfm) { + int err = 0; + if (ctx(tfm)->bypass) - return; + goto out; - crypto_hash_init(&ctx(tfm)->fallback); - if (ctx(tfm)->data && ctx(tfm)->used) { - struct scatterlist sg; + err = crypto_shash_init(ctx(tfm)->fallback); + if (err) + goto out; - sg_init_one(&sg, ctx(tfm)->data, ctx(tfm)->used); - crypto_hash_update(&ctx(tfm)->fallback, &sg, sg.length); - } + if (ctx(tfm)->data && ctx(tfm)->used) + err = crypto_shash_update(ctx(tfm)->fallback, ctx(tfm)->data, + ctx(tfm)->used); ctx(tfm)->used = 0; ctx(tfm)->bypass = 1; + +out: + return err; } static void padlock_sha_init(struct crypto_tfm *tfm) @@ -73,15 +74,18 @@ static void padlock_sha_init(struct crypto_tfm *tfm) static void padlock_sha_update(struct crypto_tfm *tfm, const uint8_t *data, unsigned int length) { + int err; + /* Our buffer is always one page. */ if (unlikely(!ctx(tfm)->bypass && - (ctx(tfm)->used + length > PAGE_SIZE))) - padlock_sha_bypass(tfm); + (ctx(tfm)->used + length > PAGE_SIZE))) { + err = padlock_sha_bypass(tfm); + BUG_ON(err); + } if (unlikely(ctx(tfm)->bypass)) { - struct scatterlist sg; - sg_init_one(&sg, (uint8_t *)data, length); - crypto_hash_update(&ctx(tfm)->fallback, &sg, length); + err = crypto_shash_update(ctx(tfm)->fallback, data, length); + BUG_ON(err); return; } @@ -151,8 +155,11 @@ static void padlock_do_sha256(const char *in, char *out, int count) static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out) { + int err; + if (unlikely(ctx(tfm)->bypass)) { - crypto_hash_final(&ctx(tfm)->fallback, out); + err = crypto_shash_final(ctx(tfm)->fallback, out); + BUG_ON(err); ctx(tfm)->bypass = 0; return; } @@ -166,27 +173,41 @@ static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out) static int padlock_cra_init(struct crypto_tfm *tfm) { const char *fallback_driver_name = tfm->__crt_alg->cra_name; - struct crypto_hash *fallback_tfm; + struct crypto_shash *fallback_tfm; + int err = -ENOMEM; /* For now we'll allocate one page. This * could eventually be configurable one day. */ ctx(tfm)->data = (char *)__get_free_page(GFP_KERNEL); if (!ctx(tfm)->data) - return -ENOMEM; + goto out; /* Allocate a fallback and abort if it failed. */ - fallback_tfm = crypto_alloc_hash(fallback_driver_name, 0, - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK); + fallback_tfm = crypto_alloc_shash(fallback_driver_name, 0, + CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(fallback_tfm)) { printk(KERN_WARNING PFX "Fallback driver '%s' could not be loaded!\n", fallback_driver_name); - free_page((unsigned long)(ctx(tfm)->data)); - return PTR_ERR(fallback_tfm); + err = PTR_ERR(fallback_tfm); + goto out_free_page; } - ctx(tfm)->fallback.tfm = fallback_tfm; + ctx(tfm)->fallback = kmalloc(sizeof(struct shash_desc) + + crypto_shash_descsize(fallback_tfm), + GFP_KERNEL); + if (!ctx(tfm)->fallback) + goto out_free_tfm; + + ctx(tfm)->fallback->tfm = fallback_tfm; + ctx(tfm)->fallback->flags = 0; return 0; + +out_free_tfm: + crypto_free_shash(fallback_tfm); +out_free_page: + free_page((unsigned long)(ctx(tfm)->data)); +out: + return err; } static int padlock_sha1_cra_init(struct crypto_tfm *tfm) @@ -210,8 +231,9 @@ static void padlock_cra_exit(struct crypto_tfm *tfm) ctx(tfm)->data = NULL; } - crypto_free_hash(ctx(tfm)->fallback.tfm); - ctx(tfm)->fallback.tfm = NULL; + crypto_free_shash(ctx(tfm)->fallback->tfm); + + kzfree(ctx(tfm)->fallback); } static struct crypto_alg sha1_alg = { -- cgit v0.10.2 From 57cfe44bccb0e38ddb44a34a42f517deef1f4e82 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 11 Jul 2009 22:17:39 +0800 Subject: crypto: shash - Move null setkey check to registration time This patch moves the run-time null setkey check to shash_prepare_alg just like we did for finup/digest. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index f7fcc65..131e14d 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -22,6 +22,12 @@ static const struct crypto_type crypto_shash_type; +static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, + unsigned int keylen) +{ + return -ENOSYS; +} + static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key, unsigned int keylen) { @@ -50,9 +56,6 @@ int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key, struct shash_alg *shash = crypto_shash_alg(tfm); unsigned long alignmask = crypto_shash_alignmask(tfm); - if (!shash->setkey) - return -ENOSYS; - if ((unsigned long)key & alignmask) return shash_setkey_unaligned(tfm, key, keylen); @@ -494,6 +497,8 @@ static int shash_prepare_alg(struct shash_alg *alg) alg->import = shash_no_import; if (!alg->export) alg->export = shash_no_export; + if (!alg->setkey) + alg->setkey = shash_no_setkey; return 0; } -- cgit v0.10.2 From aef73cfcb913eae3d0deeb60eb385f75039db40b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 11 Jul 2009 22:22:14 +0800 Subject: crypto: async - Use kzfree for requests This patch changes the kfree call to kzfree for async requests. As the request may contain sensitive data it needs to be zeroed before it can be reallocated by others. Signed-off-by: Herbert Xu diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 3c4cce6..f74214a 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -186,7 +186,7 @@ static inline struct ahash_request *ahash_request_alloc( static inline void ahash_request_free(struct ahash_request *req) { - kfree(req); + kzfree(req); } static inline struct ahash_request *ahash_request_cast( diff --git a/include/linux/crypto.h b/include/linux/crypto.h index ec29fa2..274f9c7 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -770,7 +770,7 @@ static inline struct ablkcipher_request *ablkcipher_request_alloc( static inline void ablkcipher_request_free(struct ablkcipher_request *req) { - kfree(req); + kzfree(req); } static inline void ablkcipher_request_set_callback( @@ -901,7 +901,7 @@ static inline struct aead_request *aead_request_alloc(struct crypto_aead *tfm, static inline void aead_request_free(struct aead_request *req) { - kfree(req); + kzfree(req); } static inline void aead_request_set_callback(struct aead_request *req, -- cgit v0.10.2 From 487420df79f1d9f5b9de74c9bef378609c475a39 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 08:32:06 +0000 Subject: netlink: remove unused exports I added those myself in commits b4ff4f04 and 84659eb5, but I see no reason now why they should be exported, only generic netlink uses them which cannot be modular. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 2936fa3..d7d1b82 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1541,7 +1541,6 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups) kfree(old); return err; } -EXPORT_SYMBOL(netlink_change_ngroups); /** * netlink_clear_multicast_users - kick off multicast listeners @@ -1564,7 +1563,6 @@ void netlink_clear_multicast_users(struct sock *ksk, unsigned int group) netlink_table_ungrab(); } -EXPORT_SYMBOL(netlink_clear_multicast_users); void netlink_set_nonroot(int protocol, unsigned int flags) { -- cgit v0.10.2 From 6c04bb18ddd633b7feac2c8fe2ae0bf61d20ca7a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 09:51:32 +0000 Subject: netlink: use call_rcu for netlink_change_ngroups For the network namespace work in generic netlink I need to be able to call this function under rcu_read_lock(), otherwise the locking becomes a nightmare and more locks would be needed. Instead, just embed a struct rcu_head (actually a struct listeners_rcu_head that also carries the pointer to the memory block) into the listeners memory so we can use call_rcu() instead of synchronising and then freeing. No rcu_barrier() is needed since this code cannot be modular. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d7d1b82..d46da6c 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -83,6 +83,11 @@ struct netlink_sock { struct module *module; }; +struct listeners_rcu_head { + struct rcu_head rcu_head; + void *ptr; +}; + #define NETLINK_KERNEL_SOCKET 0x1 #define NETLINK_RECV_PKTINFO 0x2 #define NETLINK_BROADCAST_SEND_ERROR 0x4 @@ -1453,7 +1458,8 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, if (groups < 32) groups = 32; - listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL); + listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head), + GFP_KERNEL); if (!listeners) goto out_sock_release; @@ -1501,6 +1507,14 @@ netlink_kernel_release(struct sock *sk) EXPORT_SYMBOL(netlink_kernel_release); +static void netlink_free_old_listeners(struct rcu_head *rcu_head) +{ + struct listeners_rcu_head *lrh; + + lrh = container_of(rcu_head, struct listeners_rcu_head, rcu_head); + kfree(lrh->ptr); +} + /** * netlink_change_ngroups - change number of multicast groups * @@ -1516,6 +1530,7 @@ EXPORT_SYMBOL(netlink_kernel_release); int netlink_change_ngroups(struct sock *sk, unsigned int groups) { unsigned long *listeners, *old = NULL; + struct listeners_rcu_head *old_rcu_head; struct netlink_table *tbl = &nl_table[sk->sk_protocol]; int err = 0; @@ -1524,7 +1539,9 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups) netlink_table_grab(); if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) { - listeners = kzalloc(NLGRPSZ(groups), GFP_ATOMIC); + listeners = kzalloc(NLGRPSZ(groups) + + sizeof(struct listeners_rcu_head), + GFP_ATOMIC); if (!listeners) { err = -ENOMEM; goto out_ungrab; @@ -1532,13 +1549,22 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups) old = tbl->listeners; memcpy(listeners, old, NLGRPSZ(tbl->groups)); rcu_assign_pointer(tbl->listeners, listeners); + /* + * Free the old memory after an RCU grace period so we + * don't leak it. We use call_rcu() here in order to be + * able to call this function from atomic contexts. The + * allocation of this memory will have reserved enough + * space for struct listeners_rcu_head at the end. + */ + old_rcu_head = (void *)(tbl->listeners + + NLGRPLONGS(tbl->groups)); + old_rcu_head->ptr = old; + call_rcu(&old_rcu_head->rcu_head, netlink_free_old_listeners); } tbl->groups = groups; out_ungrab: netlink_table_ungrab(); - synchronize_rcu(); - kfree(old); return err; } -- cgit v0.10.2 From 11a28d373ed2539a110d56419457e2e7db221ac7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 09:51:33 +0000 Subject: net: make namespace iteration possible under RCU All we need to take care of is using proper RCU list add/del primitives and inserting a synchronize_rcu() at one place to make sure the exit notifiers are run after everybody has stopped iterating the list. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index ded434b..b34a6ee 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -208,6 +208,9 @@ static inline struct net *read_pnet(struct net * const *pnet) #define for_each_net(VAR) \ list_for_each_entry(VAR, &net_namespace_list, list) +#define for_each_net_rcu(VAR) \ + list_for_each_entry_rcu(VAR, &net_namespace_list, list) + #ifdef CONFIG_NET_NS #define __net_init #define __net_exit diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index b7292a2..5cd0b22 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -127,7 +128,7 @@ static struct net *net_create(void) rv = setup_net(net); if (rv == 0) { rtnl_lock(); - list_add_tail(&net->list, &net_namespace_list); + list_add_tail_rcu(&net->list, &net_namespace_list); rtnl_unlock(); } mutex_unlock(&net_mutex); @@ -156,9 +157,16 @@ static void cleanup_net(struct work_struct *work) /* Don't let anyone else find us. */ rtnl_lock(); - list_del(&net->list); + list_del_rcu(&net->list); rtnl_unlock(); + /* + * Another CPU might be rcu-iterating the list, wait for it. + * This needs to be before calling the exit() notifiers, so + * the rcu_barrier() below isn't sufficient alone. + */ + synchronize_rcu(); + /* Run all of the network namespace exit methods */ list_for_each_entry_reverse(ops, &pernet_list, list) { if (ops->exit) @@ -219,7 +227,7 @@ static int __init net_ns_init(void) panic("Could not setup the initial network namespace"); rtnl_lock(); - list_add_tail(&init_net.list, &net_namespace_list); + list_add_tail_rcu(&init_net.list, &net_namespace_list); rtnl_unlock(); mutex_unlock(&net_mutex); -- cgit v0.10.2 From 134e63756d5f3d0f7604dfcca847b09d1b14fd66 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 09:51:34 +0000 Subject: genetlink: make netns aware This makes generic netlink network namespace aware. No generic netlink families except for the controller family are made namespace aware, they need to be checked one by one and then set the family->netnsok member to true. A new function genlmsg_multicast_netns() is introduced to allow sending a multicast message in a given namespace, for example when it applies to an object that lives in that namespace, a new function genlmsg_multicast_allns() to send a message to all network namespaces (for objects that do not have an associated netns). The function genlmsg_multicast() is changed to multicast the message in just init_net, which is currently correct for all generic netlink families since they only work in init_net right now. Some will later want to work in all net namespaces because they do not care about the netns at all -- those will have to be converted to use one of the new functions genlmsg_multicast_allns() or genlmsg_multicast_netns() whenever they are made netns aware in some way. After this patch families can easily decide whether or not they should be available in all net namespaces. Many genl families us it for objects not related to networking and should therefore be available in all namespaces, but that will have to be done on a per family basis. Note that this doesn't touch on the checkpoint/restart problem where network namespaces could be used, genl families and multicast groups are numbered globally and I see no easy way of changing that, especially since it must be possible to multicast to all network namespaces for those families that do not care about netns. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c index ccc9d62..55ea369 100644 --- a/fs/dlm/netlink.c +++ b/fs/dlm/netlink.c @@ -63,7 +63,7 @@ static int send_data(struct sk_buff *skb) return rv; } - return genlmsg_unicast(skb, listener_nlpid); + return genlmsg_unicast(&init_net, skb, listener_nlpid); } static int user_cmd(struct sk_buff *skb, struct genl_info *info) diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 1b0e3ee..2a1c0687 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -3,6 +3,7 @@ #include #include +#include /** * struct genl_multicast_group - generic netlink multicast group @@ -27,6 +28,8 @@ struct genl_multicast_group * @name: name of family * @version: protocol version * @maxattr: maximum number of attributes supported + * @netnsok: set to true if the family can handle network + * namespaces and should be presented in all of them * @attrbuf: buffer to store parsed attributes * @ops_list: list of all assigned operations * @family_list: family list @@ -39,6 +42,7 @@ struct genl_family char name[GENL_NAMSIZ]; unsigned int version; unsigned int maxattr; + bool netnsok; struct nlattr ** attrbuf; /* private */ struct list_head ops_list; /* private */ struct list_head family_list; /* private */ @@ -62,8 +66,32 @@ struct genl_info struct genlmsghdr * genlhdr; void * userhdr; struct nlattr ** attrs; +#ifdef CONFIG_NET_NS + struct net * _net; +#endif }; +#ifdef CONFIG_NET_NS +static inline struct net *genl_info_net(struct genl_info *info) +{ + return info->_net; +} + +static inline void genl_info_net_set(struct genl_info *info, struct net *net) +{ + info->_net = net; +} +#else +static inline struct net *genl_info_net(struct genl_info *info) +{ + return &init_net; +} + +static inline void genl_info_net_set(struct genl_info *info, struct net *net) +{ +} +#endif + /** * struct genl_ops - generic netlink operations * @cmd: command identifier @@ -98,8 +126,6 @@ extern int genl_register_mc_group(struct genl_family *family, extern void genl_unregister_mc_group(struct genl_family *family, struct genl_multicast_group *grp); -extern struct sock *genl_sock; - /** * genlmsg_put - Add generic netlink header to netlink message * @skb: socket buffer holding the message @@ -170,7 +196,21 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr) } /** - * genlmsg_multicast - multicast a netlink message + * genlmsg_multicast_netns - multicast a netlink message to a specific netns + * @net: the net namespace + * @skb: netlink message as socket buffer + * @pid: own netlink pid to avoid sending to yourself + * @group: multicast group id + * @flags: allocation flags + */ +static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb, + u32 pid, unsigned int group, gfp_t flags) +{ + return nlmsg_multicast(net->genl_sock, skb, pid, group, flags); +} + +/** + * genlmsg_multicast - multicast a netlink message to the default netns * @skb: netlink message as socket buffer * @pid: own netlink pid to avoid sending to yourself * @group: multicast group id @@ -179,17 +219,29 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr) static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid, unsigned int group, gfp_t flags) { - return nlmsg_multicast(genl_sock, skb, pid, group, flags); + return genlmsg_multicast_netns(&init_net, skb, pid, group, flags); } /** + * genlmsg_multicast_allns - multicast a netlink message to all net namespaces + * @skb: netlink message as socket buffer + * @pid: own netlink pid to avoid sending to yourself + * @group: multicast group id + * @flags: allocation flags + * + * This function must hold the RTNL or rcu_read_lock(). + */ +int genlmsg_multicast_allns(struct sk_buff *skb, u32 pid, + unsigned int group, gfp_t flags); + +/** * genlmsg_unicast - unicast a netlink message * @skb: netlink message as socket buffer * @pid: netlink pid of the destination socket */ -static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid) +static inline int genlmsg_unicast(struct net *net, struct sk_buff *skb, u32 pid) { - return nlmsg_unicast(genl_sock, skb, pid); + return nlmsg_unicast(net->genl_sock, skb, pid); } /** @@ -199,7 +251,7 @@ static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid) */ static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info) { - return genlmsg_unicast(skb, info->snd_pid); + return genlmsg_unicast(genl_info_net(info), skb, info->snd_pid); } /** diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index b34a6ee..3173d12 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -26,6 +26,7 @@ struct net_device; struct sock; struct ctl_table_header; struct net_generic; +struct sock; struct net { atomic_t count; /* To decided when the network @@ -57,6 +58,7 @@ struct net { spinlock_t rules_mod_lock; struct sock *rtnl; /* rtnetlink socket */ + struct sock *genl_sock; struct netns_core core; struct netns_mib mib; diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 888adbc..ea8384d 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -108,7 +108,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp, /* * Send taskstats data in @skb to listener with nl_pid @pid */ -static int send_reply(struct sk_buff *skb, pid_t pid) +static int send_reply(struct sk_buff *skb, struct genl_info *info) { struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb)); void *reply = genlmsg_data(genlhdr); @@ -120,7 +120,7 @@ static int send_reply(struct sk_buff *skb, pid_t pid) return rc; } - return genlmsg_unicast(skb, pid); + return genlmsg_reply(skb, info); } /* @@ -150,7 +150,7 @@ static void send_cpu_listeners(struct sk_buff *skb, if (!skb_next) break; } - rc = genlmsg_unicast(skb_cur, s->pid); + rc = genlmsg_unicast(&init_net, skb_cur, s->pid); if (rc == -ECONNREFUSED) { s->valid = 0; delcount++; @@ -418,7 +418,7 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) goto err; } - rc = send_reply(rep_skb, info->snd_pid); + rc = send_reply(rep_skb, info); err: fput_light(file, fput_needed); @@ -487,7 +487,7 @@ free_return_rc: } else goto err; - return send_reply(rep_skb, info->snd_pid); + return send_reply(rep_skb, info); err: nlmsg_free(rep_skb); return rc; diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c index 8dd7ed7..476b307 100644 --- a/net/irda/irnetlink.c +++ b/net/irda/irnetlink.c @@ -115,7 +115,7 @@ static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info) genlmsg_end(msg, hdr); - return genlmsg_unicast(msg, info->snd_pid); + return genlmsg_reply(msg, info); err_out: nlmsg_free(msg); diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 7c1333c..2d24d81 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3231,7 +3231,7 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info) } genlmsg_end(msg, reply); - ret = genlmsg_unicast(msg, info->snd_pid); + ret = genlmsg_reply(msg, info); goto out; nla_put_failure: diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index eed4c6a..575c643 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -18,8 +18,6 @@ #include #include -struct sock *genl_sock = NULL; - static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */ static inline void genl_lock(void) @@ -175,10 +173,31 @@ int genl_register_mc_group(struct genl_family *family, mc_groups_longs++; } - err = netlink_change_ngroups(genl_sock, - mc_groups_longs * BITS_PER_LONG); - if (err) - goto out; + if (family->netnsok) { + struct net *net; + + rcu_read_lock(); + for_each_net_rcu(net) { + err = netlink_change_ngroups(net->genl_sock, + mc_groups_longs * BITS_PER_LONG); + if (err) { + /* + * No need to roll back, can only fail if + * memory allocation fails and then the + * number of _possible_ groups has been + * increased on some sockets which is ok. + */ + rcu_read_unlock(); + goto out; + } + } + rcu_read_unlock(); + } else { + err = netlink_change_ngroups(init_net.genl_sock, + mc_groups_longs * BITS_PER_LONG); + if (err) + goto out; + } grp->id = id; set_bit(id, mc_groups); @@ -195,8 +214,14 @@ EXPORT_SYMBOL(genl_register_mc_group); static void __genl_unregister_mc_group(struct genl_family *family, struct genl_multicast_group *grp) { + struct net *net; BUG_ON(grp->family != family); - netlink_clear_multicast_users(genl_sock, grp->id); + + rcu_read_lock(); + for_each_net_rcu(net) + netlink_clear_multicast_users(net->genl_sock, grp->id); + rcu_read_unlock(); + clear_bit(grp->id, mc_groups); list_del(&grp->list); genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp); @@ -467,6 +492,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { struct genl_ops *ops; struct genl_family *family; + struct net *net = sock_net(skb->sk); struct genl_info info; struct genlmsghdr *hdr = nlmsg_data(nlh); int hdrlen, err; @@ -475,6 +501,10 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (family == NULL) return -ENOENT; + /* this family doesn't exist in this netns */ + if (!family->netnsok && !net_eq(net, &init_net)) + return -ENOENT; + hdrlen = GENL_HDRLEN + family->hdrsize; if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) return -EINVAL; @@ -492,7 +522,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return -EOPNOTSUPP; genl_unlock(); - err = netlink_dump_start(genl_sock, skb, nlh, + err = netlink_dump_start(net->genl_sock, skb, nlh, ops->dumpit, ops->done); genl_lock(); return err; @@ -514,6 +544,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) info.genlhdr = nlmsg_data(nlh); info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; info.attrs = family->attrbuf; + genl_info_net_set(&info, net); return ops->doit(skb, &info); } @@ -534,6 +565,7 @@ static struct genl_family genl_ctrl = { .name = "nlctrl", .version = 0x2, .maxattr = CTRL_ATTR_MAX, + .netnsok = true, }; static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, @@ -650,6 +682,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) int i, n = 0; struct genl_family *rt; + struct net *net = sock_net(skb->sk); int chains_to_skip = cb->args[0]; int fams_to_skip = cb->args[1]; @@ -658,6 +691,8 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) continue; n = 0; list_for_each_entry(rt, genl_family_chain(i), family_list) { + if (!rt->netnsok && !net_eq(net, &init_net)) + continue; if (++n < fams_to_skip) continue; if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).pid, @@ -729,6 +764,7 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) if (info->attrs[CTRL_ATTR_FAMILY_ID]) { u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]); res = genl_family_find_byid(id); + err = -ENOENT; } if (info->attrs[CTRL_ATTR_FAMILY_NAME]) { @@ -736,49 +772,61 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]); res = genl_family_find_byname(name); + err = -ENOENT; } - if (res == NULL) { - err = -ENOENT; - goto errout; + if (res == NULL) + return err; + + if (!res->netnsok && !net_eq(genl_info_net(info), &init_net)) { + /* family doesn't exist here */ + return -ENOENT; } msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq, CTRL_CMD_NEWFAMILY); - if (IS_ERR(msg)) { - err = PTR_ERR(msg); - goto errout; - } + if (IS_ERR(msg)) + return PTR_ERR(msg); - err = genlmsg_reply(msg, info); -errout: - return err; + return genlmsg_reply(msg, info); } static int genl_ctrl_event(int event, void *data) { struct sk_buff *msg; + struct genl_family *family; + struct genl_multicast_group *grp; - if (genl_sock == NULL) + /* genl is still initialising */ + if (!init_net.genl_sock) return 0; switch (event) { case CTRL_CMD_NEWFAMILY: case CTRL_CMD_DELFAMILY: - msg = ctrl_build_family_msg(data, 0, 0, event); - if (IS_ERR(msg)) - return PTR_ERR(msg); - - genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL); + family = data; + msg = ctrl_build_family_msg(family, 0, 0, event); break; case CTRL_CMD_NEWMCAST_GRP: case CTRL_CMD_DELMCAST_GRP: + grp = data; + family = grp->family; msg = ctrl_build_mcgrp_msg(data, 0, 0, event); - if (IS_ERR(msg)) - return PTR_ERR(msg); - - genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL); break; + default: + return -EINVAL; + } + + if (IS_ERR(msg)) + return PTR_ERR(msg); + + if (!family->netnsok) { + genlmsg_multicast_netns(&init_net, msg, 0, + GENL_ID_CTRL, GFP_KERNEL); + } else { + rcu_read_lock(); + genlmsg_multicast_allns(msg, 0, GENL_ID_CTRL, GFP_ATOMIC); + rcu_read_unlock(); } return 0; @@ -795,6 +843,33 @@ static struct genl_multicast_group notify_grp = { .name = "notify", }; +static int __net_init genl_pernet_init(struct net *net) +{ + /* we'll bump the group number right afterwards */ + net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, 0, + genl_rcv, &genl_mutex, + THIS_MODULE); + + if (!net->genl_sock && net_eq(net, &init_net)) + panic("GENL: Cannot initialize generic netlink\n"); + + if (!net->genl_sock) + return -ENOMEM; + + return 0; +} + +static void __net_exit genl_pernet_exit(struct net *net) +{ + netlink_kernel_release(net->genl_sock); + net->genl_sock = NULL; +} + +static struct pernet_operations genl_pernet_ops = { + .init = genl_pernet_init, + .exit = genl_pernet_exit, +}; + static int __init genl_init(void) { int i, err; @@ -804,36 +879,67 @@ static int __init genl_init(void) err = genl_register_family(&genl_ctrl); if (err < 0) - goto errout; + goto problem; err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops); if (err < 0) - goto errout_register; + goto problem; netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV); - /* we'll bump the group number right afterwards */ - genl_sock = netlink_kernel_create(&init_net, NETLINK_GENERIC, 0, - genl_rcv, &genl_mutex, THIS_MODULE); - if (genl_sock == NULL) - panic("GENL: Cannot initialize generic netlink\n"); + err = register_pernet_subsys(&genl_pernet_ops); + if (err) + goto problem; err = genl_register_mc_group(&genl_ctrl, ¬ify_grp); if (err < 0) - goto errout_register; + goto problem; return 0; -errout_register: - genl_unregister_family(&genl_ctrl); -errout: +problem: panic("GENL: Cannot register controller: %d\n", err); } subsys_initcall(genl_init); -EXPORT_SYMBOL(genl_sock); EXPORT_SYMBOL(genl_register_ops); EXPORT_SYMBOL(genl_unregister_ops); EXPORT_SYMBOL(genl_register_family); EXPORT_SYMBOL(genl_unregister_family); + +static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group, + gfp_t flags) +{ + struct sk_buff *tmp; + struct net *net, *prev = NULL; + int err; + + for_each_net_rcu(net) { + if (prev) { + tmp = skb_clone(skb, flags); + if (!tmp) { + err = -ENOMEM; + goto error; + } + err = nlmsg_multicast(prev->genl_sock, tmp, + pid, group, flags); + if (err) + goto error; + } + + prev = net; + } + + return nlmsg_multicast(prev->genl_sock, skb, pid, group, flags); + error: + kfree_skb(skb); + return err; +} + +int genlmsg_multicast_allns(struct sk_buff *skb, u32 pid, unsigned int group, + gfp_t flags) +{ + return genlmsg_mcast(skb, pid, group, flags); +} +EXPORT_SYMBOL(genlmsg_multicast_allns); diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 3c57005..7bda8e3 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -62,7 +62,7 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info) rep_nlh = nlmsg_hdr(rep_buf); memcpy(rep_nlh, req_nlh, hdr_space); rep_nlh->nlmsg_len = rep_buf->len; - genlmsg_unicast(rep_buf, NETLINK_CB(skb).pid); + genlmsg_unicast(&init_net, rep_buf, NETLINK_CB(skb).pid); } return 0; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9deb12f..2a04beb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -413,7 +413,7 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) cfg80211_unlock_rdev(dev); - return genlmsg_unicast(msg, info->snd_pid); + return genlmsg_reply(msg, info); out_free: nlmsg_free(msg); @@ -739,7 +739,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) dev_put(netdev); cfg80211_unlock_rdev(dev); - return genlmsg_unicast(msg, info->snd_pid); + return genlmsg_reply(msg, info); out_free: nlmsg_free(msg); @@ -1030,7 +1030,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) goto nla_put_failure; genlmsg_end(msg, hdr); - err = genlmsg_unicast(msg, info->snd_pid); + err = genlmsg_reply(msg, info); goto out; nla_put_failure: @@ -1618,7 +1618,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) dev, mac_addr, &sinfo) < 0) goto out_free; - err = genlmsg_unicast(msg, info->snd_pid); + err = genlmsg_reply(msg, info); goto out; out_free: @@ -2087,7 +2087,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) dev, dst, next_hop, &pinfo) < 0) goto out_free; - err = genlmsg_unicast(msg, info->snd_pid); + err = genlmsg_reply(msg, info); goto out; out_free: @@ -2436,7 +2436,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, cur_params.dot11MeshHWMPnetDiameterTraversalTime); nla_nest_end(msg, pinfoattr); genlmsg_end(msg, hdr); - err = genlmsg_unicast(msg, info->snd_pid); + err = genlmsg_reply(msg, info); goto out; nla_put_failure: @@ -2624,7 +2624,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) nla_nest_end(msg, nl_reg_rules); genlmsg_end(msg, hdr); - err = genlmsg_unicast(msg, info->snd_pid); + err = genlmsg_reply(msg, info); goto out; nla_put_failure: -- cgit v0.10.2 From 30ffee8480c13fbcf8ab6c28e31f79dfff683117 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 09:51:35 +0000 Subject: net: move and export get_net_ns_by_pid The function get_net_ns_by_pid(), to get a network namespace from a pid_t, will be required in cfg80211 as well. Therefore, let's move it to net_namespace.c and export it. We can't make it a static inline in the !NETNS case because it needs to verify that the given pid even exists (and return -ESRCH). Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 3173d12..3882db1 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -108,6 +108,8 @@ static inline struct net *copy_net_ns(unsigned long flags, struct net *net_ns) extern struct list_head net_namespace_list; +extern struct net *get_net_ns_by_pid(pid_t pid); + #ifdef CONFIG_NET_NS extern void __put_net(struct net *net); diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 5cd0b22..ddd2cd2 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -201,6 +202,26 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) } #endif +struct net *get_net_ns_by_pid(pid_t pid) +{ + struct task_struct *tsk; + struct net *net; + + /* Lookup the network namespace */ + net = ERR_PTR(-ESRCH); + rcu_read_lock(); + tsk = find_task_by_vpid(pid); + if (tsk) { + struct nsproxy *nsproxy; + nsproxy = task_nsproxy(tsk); + if (nsproxy) + net = get_net(nsproxy->net_ns); + } + rcu_read_unlock(); + return net; +} +EXPORT_SYMBOL_GPL(get_net_ns_by_pid); + static int __init net_ns_init(void) { struct net_generic *ng; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index d78030f..b44775f 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -52,6 +51,7 @@ #include #include #include +#include struct rtnl_link { @@ -725,25 +725,6 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { [IFLA_INFO_DATA] = { .type = NLA_NESTED }, }; -static struct net *get_net_ns_by_pid(pid_t pid) -{ - struct task_struct *tsk; - struct net *net; - - /* Lookup the network namespace */ - net = ERR_PTR(-ESRCH); - rcu_read_lock(); - tsk = find_task_by_vpid(pid); - if (tsk) { - struct nsproxy *nsproxy; - nsproxy = task_nsproxy(tsk); - if (nsproxy) - net = get_net(nsproxy->net_ns); - } - rcu_read_unlock(); - return net; -} - static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) { if (dev) { -- cgit v0.10.2 From d7ca4cc01fd154f2da30ae6dae160fa5800af758 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Thu, 9 Jul 2009 08:09:47 +0000 Subject: udpv4: Handle large incoming UDP/IPv4 packets and support software UFO. - validate and forward GSO UDP/IPv4 packets from untrusted sources. - do software UFO if the outgoing device doesn't support UFO. Signed-off-by: Sridhar Samudrala Acked-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/net/udp.h b/include/net/udp.h index 90e6ce5..5fb029f 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -207,4 +207,7 @@ extern void udp4_proc_exit(void); #endif extern void udp_init(void); + +extern int udp4_ufo_send_check(struct sk_buff *skb); +extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features); #endif /* _UDP_H */ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 566ea6c..197d024 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1187,6 +1187,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features) int proto; int ihl; int id; + unsigned int offset = 0; if (!(features & NETIF_F_V4_CSUM)) features &= ~NETIF_F_SG; @@ -1229,7 +1230,14 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features) skb = segs; do { iph = ip_hdr(skb); - iph->id = htons(id++); + if (proto == IPPROTO_UDP) { + iph->id = htons(id); + iph->frag_off = htons(offset >> 3); + if (skb->next != NULL) + iph->frag_off |= htons(IP_MF); + offset += (skb->len - skb->mac_len - iph->ihl * 4); + } else + iph->id = htons(id++); iph->tot_len = htons(skb->len - skb->mac_len); iph->check = 0; iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl); @@ -1425,6 +1433,8 @@ static struct net_protocol tcp_protocol = { static struct net_protocol udp_protocol = { .handler = udp_rcv, .err_handler = udp_err, + .gso_send_check = udp4_ufo_send_check, + .gso_segment = udp4_ufo_fragment, .no_policy = 1, .netns_ok = 1, }; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 80e3812..7bc2d08 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1816,6 +1816,67 @@ void __init udp_init(void) sysctl_udp_wmem_min = SK_MEM_QUANTUM; } +int udp4_ufo_send_check(struct sk_buff *skb) +{ + const struct iphdr *iph; + struct udphdr *uh; + + if (!pskb_may_pull(skb, sizeof(*uh))) + return -EINVAL; + + iph = ip_hdr(skb); + uh = udp_hdr(skb); + + uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, + IPPROTO_UDP, 0); + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + skb->ip_summed = CHECKSUM_PARTIAL; + return 0; +} + +struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features) +{ + struct sk_buff *segs = ERR_PTR(-EINVAL); + unsigned int mss; + int offset; + __wsum csum; + + mss = skb_shinfo(skb)->gso_size; + if (unlikely(skb->len <= mss)) + goto out; + + if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { + /* Packet is from an untrusted source, reset gso_segs. */ + int type = skb_shinfo(skb)->gso_type; + + if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) || + !(type & (SKB_GSO_UDP)))) + goto out; + + skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); + + segs = NULL; + goto out; + } + + /* Do software UFO. Complete and fill in the UDP checksum as HW cannot + * do checksum of UDP packets sent as multiple IP fragments. + */ + offset = skb->csum_start - skb_headroom(skb); + csum = skb_checksum(skb, offset, skb->len- offset, 0); + offset += skb->csum_offset; + *(__sum16 *)(skb->data + offset) = csum_fold(csum); + skb->ip_summed = CHECKSUM_NONE; + + /* Fragment the skb. IP headers of the fragments are updated in + * inet_gso_segment() + */ + segs = skb_segment(skb, features); +out: + return segs; +} + EXPORT_SYMBOL(udp_disconnect); EXPORT_SYMBOL(udp_ioctl); EXPORT_SYMBOL(udp_prot); -- cgit v0.10.2 From 493c6be3fedfe24aa676949b237b9b104d911abf Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Thu, 9 Jul 2009 08:09:54 +0000 Subject: udpv6: Fix HW checksum support for outgoing UFO packets - add HW checksum support for outgoing large UDP/IPv6 packets destined for a UFO enabled device. Signed-off-by: Sridhar Samudrala Acked-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 33b59bd..f31b1b9 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -638,6 +638,47 @@ static void udp_v6_flush_pending_frames(struct sock *sk) } } +/** + * udp6_hwcsum_outgoing - handle outgoing HW checksumming + * @sk: socket we are sending on + * @skb: sk_buff containing the filled-in UDP header + * (checksum field must be zeroed out) + */ +static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, + const struct in6_addr *saddr, + const struct in6_addr *daddr, int len) +{ + unsigned int offset; + struct udphdr *uh = udp_hdr(skb); + __wsum csum = 0; + + if (skb_queue_len(&sk->sk_write_queue) == 1) { + /* Only one fragment on the socket. */ + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + uh->check = ~csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, 0); + } else { + /* + * HW-checksum won't work as there are two or more + * fragments on the socket so that all csums of sk_buffs + * should be together + */ + offset = skb_transport_offset(skb); + skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); + + skb->ip_summed = CHECKSUM_NONE; + + skb_queue_walk(&sk->sk_write_queue, skb) { + csum = csum_add(csum, skb->csum); + } + + uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, + csum); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + } +} + /* * Sending */ @@ -668,7 +709,11 @@ static int udp_v6_push_pending_frames(struct sock *sk) if (is_udplite) csum = udplite_csum_outgoing(sk, skb); - else + else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ + udp6_hwcsum_outgoing(sk, skb, &fl->fl6_src, &fl->fl6_dst, + up->len); + goto send; + } else csum = udp_csum_outgoing(sk, skb); /* add protocol-dependent pseudo-header */ @@ -677,6 +722,7 @@ static int udp_v6_push_pending_frames(struct sock *sk) if (uh->check == 0) uh->check = CSUM_MANGLED_0; +send: err = ip6_push_pending_frames(sk); out: up->len = 0; -- cgit v0.10.2 From c31d5326902cebffcd83b1aede67a0e0ac923090 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Thu, 9 Jul 2009 08:09:58 +0000 Subject: udpv6: Fix gso_size setting in ip6_ufo_append_data - fix gso_size setting for ipv6 fragment to be a multiple of 8 bytes. Signed-off-by: Sridhar Samudrala Acked-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 7c76e3d..1c6f0fc 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1087,9 +1087,11 @@ static inline int ip6_ufo_append_data(struct sock *sk, if (!err) { struct frag_hdr fhdr; - /* specify the length of each IP datagram fragment*/ - skb_shinfo(skb)->gso_size = mtu - fragheaderlen - - sizeof(struct frag_hdr); + /* Specify the length of each IPv6 datagram fragment. + * It has to be a multiple of 8. + */ + skb_shinfo(skb)->gso_size = (mtu - fragheaderlen - + sizeof(struct frag_hdr)) & ~7; skb_shinfo(skb)->gso_type = SKB_GSO_UDP; ipv6_select_ident(skb, &fhdr); skb_shinfo(skb)->ip6_frag_id = fhdr.identification; -- cgit v0.10.2 From 7ea2f2c5a66e4e9a8d96296ac47ad895c467ee1d Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Thu, 9 Jul 2009 08:10:01 +0000 Subject: udpv6: Remove unused skb argument of ipv6_select_ident() - move ipv6_select_ident() inline function to ipv6.h and remove the unused skb argument Signed-off-by: Sridhar Samudrala Acked-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/net/ipv6.h b/include/net/ipv6.h index f27fd83..ad9a511 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -441,6 +441,18 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); } +static __inline__ void ipv6_select_ident(struct frag_hdr *fhdr) +{ + static u32 ipv6_fragmentation_id = 1; + static DEFINE_SPINLOCK(ip6_id_lock); + + spin_lock_bh(&ip6_id_lock); + fhdr->identification = htonl(ipv6_fragmentation_id); + if (++ipv6_fragmentation_id == 0) + ipv6_fragmentation_id = 1; + spin_unlock_bh(&ip6_id_lock); +} + /* * Prototypes exported by ipv6 */ diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 1c6f0fc..dd1a980 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -57,18 +57,6 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); -static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr) -{ - static u32 ipv6_fragmentation_id = 1; - static DEFINE_SPINLOCK(ip6_id_lock); - - spin_lock_bh(&ip6_id_lock); - fhdr->identification = htonl(ipv6_fragmentation_id); - if (++ipv6_fragmentation_id == 0) - ipv6_fragmentation_id = 1; - spin_unlock_bh(&ip6_id_lock); -} - int __ip6_local_out(struct sk_buff *skb) { int len; @@ -706,7 +694,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) skb_reset_network_header(skb); memcpy(skb_network_header(skb), tmp_hdr, hlen); - ipv6_select_ident(skb, fh); + ipv6_select_ident(fh); fh->nexthdr = nexthdr; fh->reserved = 0; fh->frag_off = htons(IP6_MF); @@ -844,7 +832,7 @@ slow_path: fh->nexthdr = nexthdr; fh->reserved = 0; if (!frag_id) { - ipv6_select_ident(skb, fh); + ipv6_select_ident(fh); frag_id = fh->identification; } else fh->identification = frag_id; @@ -1093,7 +1081,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, skb_shinfo(skb)->gso_size = (mtu - fragheaderlen - sizeof(struct frag_hdr)) & ~7; skb_shinfo(skb)->gso_type = SKB_GSO_UDP; - ipv6_select_ident(skb, &fhdr); + ipv6_select_ident(&fhdr); skb_shinfo(skb)->ip6_frag_id = fhdr.identification; __skb_queue_tail(&sk->sk_write_queue, skb); -- cgit v0.10.2 From ba73542585a4a3c8a708f502e62e6e63dd74b66c Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Thu, 9 Jul 2009 08:10:04 +0000 Subject: udpv6: Handle large incoming UDP/IPv6 packets and support software UFO - validate and forward GSO UDP/IPv6 packets from untrusted sources. - do software UFO if the outgoing device doesn't support UFO. Signed-off-by: Sridhar Samudrala Acked-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index caa0278..bf85d5f9 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -772,6 +772,11 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) struct sk_buff *segs = ERR_PTR(-EINVAL); struct ipv6hdr *ipv6h; struct inet6_protocol *ops; + int proto; + struct frag_hdr *fptr; + unsigned int unfrag_ip6hlen; + u8 *prevhdr; + int offset = 0; if (!(features & NETIF_F_V6_CSUM)) features &= ~NETIF_F_SG; @@ -791,10 +796,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) __skb_pull(skb, sizeof(*ipv6h)); segs = ERR_PTR(-EPROTONOSUPPORT); + proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); rcu_read_lock(); - ops = rcu_dereference(inet6_protos[ - ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]); - + ops = rcu_dereference(inet6_protos[proto]); if (likely(ops && ops->gso_segment)) { skb_reset_transport_header(skb); segs = ops->gso_segment(skb, features); @@ -808,6 +812,16 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) ipv6h = ipv6_hdr(skb); ipv6h->payload_len = htons(skb->len - skb->mac_len - sizeof(*ipv6h)); + if (proto == IPPROTO_UDP) { + unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); + fptr = (struct frag_hdr *)(skb_network_header(skb) + + unfrag_ip6hlen); + fptr->frag_off = htons(offset); + if (skb->next != NULL) + fptr->frag_off |= htons(IP6_MF); + offset += (ntohs(ipv6h->payload_len) - + sizeof(struct frag_hdr)); + } } out: diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index f31b1b9..d79fa67 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1078,9 +1078,102 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, } #endif +static int udp6_ufo_send_check(struct sk_buff *skb) +{ + struct ipv6hdr *ipv6h; + struct udphdr *uh; + + if (!pskb_may_pull(skb, sizeof(*uh))) + return -EINVAL; + + ipv6h = ipv6_hdr(skb); + uh = udp_hdr(skb); + + uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, + IPPROTO_UDP, 0); + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + skb->ip_summed = CHECKSUM_PARTIAL; + return 0; +} + +static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, int features) +{ + struct sk_buff *segs = ERR_PTR(-EINVAL); + unsigned int mss; + unsigned int unfrag_ip6hlen, unfrag_len; + struct frag_hdr *fptr; + u8 *mac_start, *prevhdr; + u8 nexthdr; + u8 frag_hdr_sz = sizeof(struct frag_hdr); + int offset; + __wsum csum; + + mss = skb_shinfo(skb)->gso_size; + if (unlikely(skb->len <= mss)) + goto out; + + if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { + /* Packet is from an untrusted source, reset gso_segs. */ + int type = skb_shinfo(skb)->gso_type; + + if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) || + !(type & (SKB_GSO_UDP)))) + goto out; + + skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); + + segs = NULL; + goto out; + } + + /* Do software UFO. Complete and fill in the UDP checksum as HW cannot + * do checksum of UDP packets sent as multiple IP fragments. + */ + offset = skb->csum_start - skb_headroom(skb); + csum = skb_checksum(skb, offset, skb->len- offset, 0); + offset += skb->csum_offset; + *(__sum16 *)(skb->data + offset) = csum_fold(csum); + skb->ip_summed = CHECKSUM_NONE; + + /* Check if there is enough headroom to insert fragment header. */ + if ((skb_headroom(skb) < frag_hdr_sz) && + pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC)) + goto out; + + /* Find the unfragmentable header and shift it left by frag_hdr_sz + * bytes to insert fragment header. + */ + unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); + nexthdr = *prevhdr; + *prevhdr = NEXTHDR_FRAGMENT; + unfrag_len = skb_network_header(skb) - skb_mac_header(skb) + + unfrag_ip6hlen; + mac_start = skb_mac_header(skb); + memmove(mac_start-frag_hdr_sz, mac_start, unfrag_len); + + skb->mac_header -= frag_hdr_sz; + skb->network_header -= frag_hdr_sz; + + fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen); + fptr->nexthdr = nexthdr; + fptr->reserved = 0; + ipv6_select_ident(fptr); + + /* Fragment the skb. ipv6 header and the remaining fields of the + * fragment header are updated in ipv6_gso_segment() + */ + segs = skb_segment(skb, features); + +out: + return segs; +} + static struct inet6_protocol udpv6_protocol = { .handler = udpv6_rcv, .err_handler = udpv6_err, + .gso_send_check = udp6_ufo_send_check, + .gso_segment = udp6_ufo_fragment, .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; -- cgit v0.10.2 From 8113a8d80f4c6a3dc3724b39b470f3fee9c426b6 Mon Sep 17 00:00:00 2001 From: Thomas Liu Date: Fri, 10 Jul 2009 10:31:04 -0400 Subject: SELinux: Convert avc_audit to use lsm_audit.h Convert avc_audit in security/selinux/avc.c to use lsm_audit.h, for better maintainability and for less code duplication. - changed selinux to use common_audit_data instead of avc_audit_data - eliminated code in avc.c and used code from lsm_audit.h instead. I have tested to make sure that the avcs look the same before and after this patch. Signed-off-by: Thomas Liu Acked-by: Eric Paris Signed-off-by: James Morris diff --git a/security/Makefile b/security/Makefile index c67557c..8dcc1fd 100644 --- a/security/Makefile +++ b/security/Makefile @@ -16,9 +16,7 @@ obj-$(CONFIG_SECURITYFS) += inode.o # Must precede capability.o in order to stack properly. obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o -ifeq ($(CONFIG_AUDIT),y) -obj-$(CONFIG_SECURITY_SMACK) += lsm_audit.o -endif +obj-$(CONFIG_AUDIT) += lsm_audit.o obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 236aaa2..d9fd224 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -492,23 +492,50 @@ out: return node; } -static inline void avc_print_ipv6_addr(struct audit_buffer *ab, - struct in6_addr *addr, __be16 port, - char *name1, char *name2) +/** + * avc_audit_pre_callback - SELinux specific information + * will be called by generic audit code + * @ab: the audit buffer + * @a: audit_data + */ +static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) { - if (!ipv6_addr_any(addr)) - audit_log_format(ab, " %s=%pI6", name1, addr); - if (port) - audit_log_format(ab, " %s=%d", name2, ntohs(port)); + struct common_audit_data *ad = a; + struct av_decision *avd = ad->selinux_audit_data.avd; + u32 requested = ad->selinux_audit_data.requested; + int result = ad->selinux_audit_data.result; + u32 denied, audited; + denied = requested & ~avd->allowed; + if (denied) { + audited = denied; + if (!(audited & avd->auditdeny)) + return; + } else if (result) { + audited = denied = requested; + } else { + audited = requested; + if (!(audited & avd->auditallow)) + return; + } + audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); + avc_dump_av(ab, ad->selinux_audit_data.tclass, + ad->selinux_audit_data.audited); + audit_log_format(ab, " for "); } -static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, - __be16 port, char *name1, char *name2) +/** + * avc_audit_post_callback - SELinux specific information + * will be called by generic audit code + * @ab: the audit buffer + * @a: audit_data + */ +static void avc_audit_post_callback(struct audit_buffer *ab, void *a) { - if (addr) - audit_log_format(ab, " %s=%pI4", name1, &addr); - if (port) - audit_log_format(ab, " %s=%d", name2, ntohs(port)); + struct common_audit_data *ad = a; + audit_log_format(ab, " "); + avc_dump_query(ab, ad->selinux_audit_data.ssid, + ad->selinux_audit_data.tsid, + ad->selinux_audit_data.tclass); } /** @@ -532,163 +559,14 @@ static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, */ void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct av_decision *avd, int result, struct avc_audit_data *a) + struct av_decision *avd, int result, struct common_audit_data *a) { - struct task_struct *tsk = current; - struct inode *inode = NULL; - u32 denied, audited; - struct audit_buffer *ab; - - denied = requested & ~avd->allowed; - if (denied) { - audited = denied; - if (!(audited & avd->auditdeny)) - return; - } else if (result) { - audited = denied = requested; - } else { - audited = requested; - if (!(audited & avd->auditallow)) - return; - } - - ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); - if (!ab) - return; /* audit_panic has been called */ - audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); - avc_dump_av(ab, tclass, audited); - audit_log_format(ab, " for "); - if (a && a->tsk) - tsk = a->tsk; - if (tsk && tsk->pid) { - audit_log_format(ab, " pid=%d comm=", tsk->pid); - audit_log_untrustedstring(ab, tsk->comm); - } - if (a) { - switch (a->type) { - case AVC_AUDIT_DATA_IPC: - audit_log_format(ab, " key=%d", a->u.ipc_id); - break; - case AVC_AUDIT_DATA_CAP: - audit_log_format(ab, " capability=%d", a->u.cap); - break; - case AVC_AUDIT_DATA_FS: - if (a->u.fs.path.dentry) { - struct dentry *dentry = a->u.fs.path.dentry; - if (a->u.fs.path.mnt) { - audit_log_d_path(ab, "path=", - &a->u.fs.path); - } else { - audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, dentry->d_name.name); - } - inode = dentry->d_inode; - } else if (a->u.fs.inode) { - struct dentry *dentry; - inode = a->u.fs.inode; - dentry = d_find_alias(inode); - if (dentry) { - audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, dentry->d_name.name); - dput(dentry); - } - } - if (inode) - audit_log_format(ab, " dev=%s ino=%lu", - inode->i_sb->s_id, - inode->i_ino); - break; - case AVC_AUDIT_DATA_NET: - if (a->u.net.sk) { - struct sock *sk = a->u.net.sk; - struct unix_sock *u; - int len = 0; - char *p = NULL; - - switch (sk->sk_family) { - case AF_INET: { - struct inet_sock *inet = inet_sk(sk); - - avc_print_ipv4_addr(ab, inet->rcv_saddr, - inet->sport, - "laddr", "lport"); - avc_print_ipv4_addr(ab, inet->daddr, - inet->dport, - "faddr", "fport"); - break; - } - case AF_INET6: { - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *inet6 = inet6_sk(sk); - - avc_print_ipv6_addr(ab, &inet6->rcv_saddr, - inet->sport, - "laddr", "lport"); - avc_print_ipv6_addr(ab, &inet6->daddr, - inet->dport, - "faddr", "fport"); - break; - } - case AF_UNIX: - u = unix_sk(sk); - if (u->dentry) { - struct path path = { - .dentry = u->dentry, - .mnt = u->mnt - }; - audit_log_d_path(ab, "path=", - &path); - break; - } - if (!u->addr) - break; - len = u->addr->len-sizeof(short); - p = &u->addr->name->sun_path[0]; - audit_log_format(ab, " path="); - if (*p) - audit_log_untrustedstring(ab, p); - else - audit_log_n_hex(ab, p, len); - break; - } - } - - switch (a->u.net.family) { - case AF_INET: - avc_print_ipv4_addr(ab, a->u.net.v4info.saddr, - a->u.net.sport, - "saddr", "src"); - avc_print_ipv4_addr(ab, a->u.net.v4info.daddr, - a->u.net.dport, - "daddr", "dest"); - break; - case AF_INET6: - avc_print_ipv6_addr(ab, &a->u.net.v6info.saddr, - a->u.net.sport, - "saddr", "src"); - avc_print_ipv6_addr(ab, &a->u.net.v6info.daddr, - a->u.net.dport, - "daddr", "dest"); - break; - } - if (a->u.net.netif > 0) { - struct net_device *dev; - - /* NOTE: we always use init's namespace */ - dev = dev_get_by_index(&init_net, - a->u.net.netif); - if (dev) { - audit_log_format(ab, " netif=%s", - dev->name); - dev_put(dev); - } - } - break; - } - } - audit_log_format(ab, " "); - avc_dump_query(ab, ssid, tsid, tclass); - audit_log_end(ab); + a->selinux_audit_data.avd = avd; + a->selinux_audit_data.tclass = tclass; + a->selinux_audit_data.requested = requested; + a->lsm_pre_audit = avc_audit_pre_callback; + a->lsm_post_audit = avc_audit_post_callback; + common_lsm_audit(a); } /** @@ -956,7 +834,7 @@ out: * another -errno upon other errors. */ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, - u32 requested, struct avc_audit_data *auditdata) + u32 requested, struct common_audit_data *auditdata) { struct av_decision avd; int rc; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2081055..a7de261 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1478,14 +1478,14 @@ static int task_has_capability(struct task_struct *tsk, const struct cred *cred, int cap, int audit) { - struct avc_audit_data ad; + struct common_audit_data ad; struct av_decision avd; u16 sclass; u32 sid = cred_sid(cred); u32 av = CAP_TO_MASK(cap); int rc; - AVC_AUDIT_DATA_INIT(&ad, CAP); + COMMON_AUDIT_DATA_INIT(&ad, CAP); ad.tsk = tsk; ad.u.cap = cap; @@ -1524,10 +1524,10 @@ static int task_has_system(struct task_struct *tsk, static int inode_has_perm(const struct cred *cred, struct inode *inode, u32 perms, - struct avc_audit_data *adp) + struct common_audit_data *adp) { struct inode_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid; if (unlikely(IS_PRIVATE(inode))) @@ -1538,7 +1538,7 @@ static int inode_has_perm(const struct cred *cred, if (!adp) { adp = &ad; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.inode = inode; } @@ -1554,9 +1554,9 @@ static inline int dentry_has_perm(const struct cred *cred, u32 av) { struct inode *inode = dentry->d_inode; - struct avc_audit_data ad; + struct common_audit_data ad; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.mnt = mnt; ad.u.fs.path.dentry = dentry; return inode_has_perm(cred, inode, av, &ad); @@ -1576,11 +1576,11 @@ static int file_has_perm(const struct cred *cred, { struct file_security_struct *fsec = file->f_security; struct inode *inode = file->f_path.dentry->d_inode; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = cred_sid(cred); int rc; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path = file->f_path; if (sid != fsec->sid) { @@ -1611,7 +1611,7 @@ static int may_create(struct inode *dir, struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; u32 sid, newsid; - struct avc_audit_data ad; + struct common_audit_data ad; int rc; dsec = dir->i_security; @@ -1620,7 +1620,7 @@ static int may_create(struct inode *dir, sid = tsec->sid; newsid = tsec->create_sid; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, @@ -1664,7 +1664,7 @@ static int may_link(struct inode *dir, { struct inode_security_struct *dsec, *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); u32 av; int rc; @@ -1672,7 +1672,7 @@ static int may_link(struct inode *dir, dsec = dir->i_security; isec = dentry->d_inode->i_security; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; av = DIR__SEARCH; @@ -1707,7 +1707,7 @@ static inline int may_rename(struct inode *old_dir, struct dentry *new_dentry) { struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); u32 av; int old_is_dir, new_is_dir; @@ -1718,7 +1718,7 @@ static inline int may_rename(struct inode *old_dir, old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); new_dsec = new_dir->i_security; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = old_dentry; rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, @@ -1760,7 +1760,7 @@ static inline int may_rename(struct inode *old_dir, static int superblock_has_perm(const struct cred *cred, struct super_block *sb, u32 perms, - struct avc_audit_data *ad) + struct common_audit_data *ad) { struct superblock_security_struct *sbsec; u32 sid = cred_sid(cred); @@ -2100,7 +2100,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) const struct task_security_struct *old_tsec; struct task_security_struct *new_tsec; struct inode_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; struct inode *inode = bprm->file->f_path.dentry->d_inode; int rc; @@ -2138,7 +2138,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) return rc; } - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path = bprm->file->f_path; if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) @@ -2231,7 +2231,7 @@ extern struct dentry *selinux_null; static inline void flush_unauthorized_files(const struct cred *cred, struct files_struct *files) { - struct avc_audit_data ad; + struct common_audit_data ad; struct file *file, *devnull = NULL; struct tty_struct *tty; struct fdtable *fdt; @@ -2265,7 +2265,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, /* Revalidate access to inherited open files. */ - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); spin_lock(&files->file_lock); for (;;) { @@ -2514,7 +2514,7 @@ out: static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) { const struct cred *cred = current_cred(); - struct avc_audit_data ad; + struct common_audit_data ad; int rc; rc = superblock_doinit(sb, data); @@ -2525,7 +2525,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) if (flags & MS_KERNMOUNT) return 0; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = sb->s_root; return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); } @@ -2533,9 +2533,9 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) static int selinux_sb_statfs(struct dentry *dentry) { const struct cred *cred = current_cred(); - struct avc_audit_data ad; + struct common_audit_data ad; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry->d_sb->s_root; return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); } @@ -2755,7 +2755,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, struct inode *inode = dentry->d_inode; struct inode_security_struct *isec = inode->i_security; struct superblock_security_struct *sbsec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 newsid, sid = current_sid(); int rc = 0; @@ -2769,7 +2769,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, if (!is_owner_or_cap(inode)) return -EPERM; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; rc = avc_has_perm(sid, isec->sid, isec->sclass, @@ -3401,7 +3401,7 @@ static void selinux_task_to_inode(struct task_struct *p, /* Returns error only if unable to parse addresses */ static int selinux_parse_skb_ipv4(struct sk_buff *skb, - struct avc_audit_data *ad, u8 *proto) + struct common_audit_data *ad, u8 *proto) { int offset, ihlen, ret = -EINVAL; struct iphdr _iph, *ih; @@ -3482,7 +3482,7 @@ out: /* Returns error only if unable to parse addresses */ static int selinux_parse_skb_ipv6(struct sk_buff *skb, - struct avc_audit_data *ad, u8 *proto) + struct common_audit_data *ad, u8 *proto) { u8 nexthdr; int ret = -EINVAL, offset; @@ -3553,7 +3553,7 @@ out: #endif /* IPV6 */ -static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, +static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad, char **_addrp, int src, u8 *proto) { char *addrp; @@ -3635,7 +3635,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, u32 perms) { struct inode_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid; int err = 0; @@ -3645,7 +3645,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, goto out; sid = task_sid(task); - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = sock->sk; err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); @@ -3732,7 +3732,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in if (family == PF_INET || family == PF_INET6) { char *addrp; struct inode_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; struct sockaddr_in *addr4 = NULL; struct sockaddr_in6 *addr6 = NULL; unsigned short snum; @@ -3761,7 +3761,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in snum, &sid); if (err) goto out; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sport = htons(snum); ad.u.net.family = family; err = avc_has_perm(isec->sid, sid, @@ -3794,7 +3794,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in if (err) goto out; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sport = htons(snum); ad.u.net.family = family; @@ -3828,7 +3828,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, isec = SOCK_INODE(sock)->i_security; if (isec->sclass == SECCLASS_TCP_SOCKET || isec->sclass == SECCLASS_DCCP_SOCKET) { - struct avc_audit_data ad; + struct common_audit_data ad; struct sockaddr_in *addr4 = NULL; struct sockaddr_in6 *addr6 = NULL; unsigned short snum; @@ -3853,7 +3853,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, perm = (isec->sclass == SECCLASS_TCP_SOCKET) ? TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.dport = htons(snum); ad.u.net.family = sk->sk_family; err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad); @@ -3943,13 +3943,13 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, struct sk_security_struct *ssec; struct inode_security_struct *isec; struct inode_security_struct *other_isec; - struct avc_audit_data ad; + struct common_audit_data ad; int err; isec = SOCK_INODE(sock)->i_security; other_isec = SOCK_INODE(other)->i_security; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = other->sk; err = avc_has_perm(isec->sid, other_isec->sid, @@ -3975,13 +3975,13 @@ static int selinux_socket_unix_may_send(struct socket *sock, { struct inode_security_struct *isec; struct inode_security_struct *other_isec; - struct avc_audit_data ad; + struct common_audit_data ad; int err; isec = SOCK_INODE(sock)->i_security; other_isec = SOCK_INODE(other)->i_security; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = other->sk; err = avc_has_perm(isec->sid, other_isec->sid, @@ -3994,7 +3994,7 @@ static int selinux_socket_unix_may_send(struct socket *sock, static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, u32 peer_sid, - struct avc_audit_data *ad) + struct common_audit_data *ad) { int err; u32 if_sid; @@ -4022,10 +4022,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, struct sk_security_struct *sksec = sk->sk_security; u32 peer_sid; u32 sk_sid = sksec->sid; - struct avc_audit_data ad; + struct common_audit_data ad; char *addrp; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = skb->iif; ad.u.net.family = family; err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); @@ -4063,7 +4063,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) struct sk_security_struct *sksec = sk->sk_security; u16 family = sk->sk_family; u32 sk_sid = sksec->sid; - struct avc_audit_data ad; + struct common_audit_data ad; char *addrp; u8 secmark_active; u8 peerlbl_active; @@ -4087,7 +4087,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) if (!secmark_active && !peerlbl_active) return 0; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = skb->iif; ad.u.net.family = family; err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); @@ -4345,7 +4345,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, int err; char *addrp; u32 peer_sid; - struct avc_audit_data ad; + struct common_audit_data ad; u8 secmark_active; u8 netlbl_active; u8 peerlbl_active; @@ -4362,7 +4362,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) return NF_DROP; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = ifindex; ad.u.net.family = family; if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) @@ -4450,7 +4450,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, { struct sock *sk = skb->sk; struct sk_security_struct *sksec; - struct avc_audit_data ad; + struct common_audit_data ad; char *addrp; u8 proto; @@ -4458,7 +4458,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, return NF_ACCEPT; sksec = sk->sk_security; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = ifindex; ad.u.net.family = family; if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) @@ -4482,7 +4482,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, u32 secmark_perm; u32 peer_sid; struct sock *sk; - struct avc_audit_data ad; + struct common_audit_data ad; char *addrp; u8 secmark_active; u8 peerlbl_active; @@ -4541,7 +4541,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, secmark_perm = PACKET__SEND; } - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = ifindex; ad.u.net.family = family; if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) @@ -4611,13 +4611,13 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) static int selinux_netlink_recv(struct sk_buff *skb, int capability) { int err; - struct avc_audit_data ad; + struct common_audit_data ad; err = cap_netlink_recv(skb, capability); if (err) return err; - AVC_AUDIT_DATA_INIT(&ad, CAP); + COMMON_AUDIT_DATA_INIT(&ad, CAP); ad.u.cap = capability; return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, @@ -4676,12 +4676,12 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, u32 perms) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); isec = ipc_perms->security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = ipc_perms->key; return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); @@ -4701,7 +4701,7 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg) static int selinux_msg_queue_alloc_security(struct msg_queue *msq) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); int rc; @@ -4711,7 +4711,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) isec = msq->q_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, @@ -4731,12 +4731,12 @@ static void selinux_msg_queue_free_security(struct msg_queue *msq) static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); isec = msq->q_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, @@ -4775,7 +4775,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, { struct ipc_security_struct *isec; struct msg_security_struct *msec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); int rc; @@ -4796,7 +4796,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, return rc; } - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; /* Can this process write to the queue? */ @@ -4820,14 +4820,14 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, { struct ipc_security_struct *isec; struct msg_security_struct *msec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = task_sid(target); int rc; isec = msq->q_perm.security; msec = msg->security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; rc = avc_has_perm(sid, isec->sid, @@ -4842,7 +4842,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, static int selinux_shm_alloc_security(struct shmid_kernel *shp) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); int rc; @@ -4852,7 +4852,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) isec = shp->shm_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = shp->shm_perm.key; rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, @@ -4872,12 +4872,12 @@ static void selinux_shm_free_security(struct shmid_kernel *shp) static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); isec = shp->shm_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = shp->shm_perm.key; return avc_has_perm(sid, isec->sid, SECCLASS_SHM, @@ -4934,7 +4934,7 @@ static int selinux_shm_shmat(struct shmid_kernel *shp, static int selinux_sem_alloc_security(struct sem_array *sma) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); int rc; @@ -4944,7 +4944,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) isec = sma->sem_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = sma->sem_perm.key; rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, @@ -4964,12 +4964,12 @@ static void selinux_sem_free_security(struct sem_array *sma) static int selinux_sem_associate(struct sem_array *sma, int semflg) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); isec = sma->sem_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = sma->sem_perm.key; return avc_has_perm(sid, isec->sid, SECCLASS_SEM, diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index ae4c3a0..e94e82f 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -36,48 +37,6 @@ struct inode; struct sock; struct sk_buff; -/* Auxiliary data to use in generating the audit record. */ -struct avc_audit_data { - char type; -#define AVC_AUDIT_DATA_FS 1 -#define AVC_AUDIT_DATA_NET 2 -#define AVC_AUDIT_DATA_CAP 3 -#define AVC_AUDIT_DATA_IPC 4 - struct task_struct *tsk; - union { - struct { - struct path path; - struct inode *inode; - } fs; - struct { - int netif; - struct sock *sk; - u16 family; - __be16 dport; - __be16 sport; - union { - struct { - __be32 daddr; - __be32 saddr; - } v4; - struct { - struct in6_addr daddr; - struct in6_addr saddr; - } v6; - } fam; - } net; - int cap; - int ipc_id; - } u; -}; - -#define v4info fam.v4 -#define v6info fam.v6 - -/* Initialize an AVC audit data structure. */ -#define AVC_AUDIT_DATA_INIT(_d,_t) \ - { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; } - /* * AVC statistics */ @@ -98,7 +57,9 @@ void __init avc_init(void); void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct av_decision *avd, int result, struct avc_audit_data *auditdata); + struct av_decision *avd, + int result, + struct common_audit_data *a); #define AVC_STRICT 1 /* Ignore permissive mode. */ int avc_has_perm_noaudit(u32 ssid, u32 tsid, @@ -108,7 +69,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct avc_audit_data *auditdata); + struct common_audit_data *auditdata); u32 avc_policy_seqno(void); diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index b4b5b9b..8d73842 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h @@ -59,7 +59,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, struct sk_buff *skb, u16 family, - struct avc_audit_data *ad); + struct common_audit_data *ad); int selinux_netlbl_socket_setsockopt(struct socket *sock, int level, int optname); @@ -129,7 +129,7 @@ static inline int selinux_netlbl_socket_post_create(struct sock *sk, static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, struct sk_buff *skb, u16 family, - struct avc_audit_data *ad) + struct common_audit_data *ad) { return 0; } diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 289e24b..13128f9 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -41,9 +41,9 @@ static inline int selinux_xfrm_enabled(void) } int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, - struct avc_audit_data *ad); + struct common_audit_data *ad); int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad, u8 proto); + struct common_audit_data *ad, u8 proto); int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); static inline void selinux_xfrm_notify_policyload(void) @@ -57,13 +57,13 @@ static inline int selinux_xfrm_enabled(void) } static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad) + struct common_audit_data *ad) { return 0; } static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad, u8 proto) + struct common_audit_data *ad, u8 proto) { return 0; } diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 2e98441..e688237 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -342,7 +342,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family) int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, struct sk_buff *skb, u16 family, - struct avc_audit_data *ad) + struct common_audit_data *ad) { int rc; u32 nlbl_sid; diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 72b1845..f3cb9ed 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -401,7 +401,7 @@ int selinux_xfrm_state_delete(struct xfrm_state *x) * gone thru the IPSec process. */ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad) + struct common_audit_data *ad) { int i, rc = 0; struct sec_path *sp; @@ -442,7 +442,7 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, * checked in the selinux_xfrm_state_pol_flow_match hook above. */ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad, u8 proto) + struct common_audit_data *ad, u8 proto) { struct dst_entry *dst; int rc = 0; -- cgit v0.10.2 From b3a633c8527ef155b1a4e22e8f5abc58f7af54c9 Mon Sep 17 00:00:00 2001 From: Julien Tinnes Date: Fri, 10 Jul 2009 10:46:30 -0700 Subject: personality handling: fix PER_CLEAR_ON_SETID for security reasons We have found that the current PER_CLEAR_ON_SETID mask on Linux doesn't include neither ADDR_COMPAT_LAYOUT, nor MMAP_PAGE_ZERO. The current mask is READ_IMPLIES_EXEC|ADDR_NO_RANDOMIZE. We believe it is important to add MMAP_PAGE_ZERO, because by using this personality it is possible to have the first page mapped inside a process running as setuid root. This could be used in those scenarios: - Exploiting a NULL pointer dereference issue in a setuid root binary - Bypassing the mmap_min_addr restrictions of the Linux kernel: by running a setuid binary that would drop privileges before giving us control back (for instance by loading a user-supplied library), we could get the first page mapped in a process we control. By further using mremap and mprotect on this mapping, we can then completely bypass the mmap_min_addr restrictions. Less importantly, we believe ADDR_COMPAT_LAYOUT should also be added since on x86 32bits it will in practice disable most of the address space layout randomization (only the stack will remain randomized). Signed-off-by: Julien Tinnes Signed-off-by: Tavis Ormandy Acked-by: Christoph Hellwig Acked-by: Kees Cook Signed-off-by: James Morris diff --git a/include/linux/personality.h b/include/linux/personality.h index a84e9ff..b7f578d 100644 --- a/include/linux/personality.h +++ b/include/linux/personality.h @@ -40,7 +40,11 @@ enum { * Security-relevant compatibility flags that must be * cleared upon setuid or setgid exec: */ -#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC|ADDR_NO_RANDOMIZE) +#define PER_CLEAR_ON_SETID \ + (READ_IMPLIES_EXEC | \ + ADDR_NO_RANDOMIZE | \ + ADDR_COMPAT_LAYOUT | \ + MMAP_PAGE_ZERO) /* * Personality types. -- cgit v0.10.2 From be940d6279c30a2d7c4e8d1d5435f957f594d66d Mon Sep 17 00:00:00 2001 From: James Morris Date: Mon, 13 Jul 2009 10:39:36 +1000 Subject: Revert "SELinux: Convert avc_audit to use lsm_audit.h" This reverts commit 8113a8d80f4c6a3dc3724b39b470f3fee9c426b6. The patch causes a stack overflow on my system during boot. Signed-off-by: James Morris diff --git a/security/Makefile b/security/Makefile index 8dcc1fd..c67557c 100644 --- a/security/Makefile +++ b/security/Makefile @@ -16,7 +16,9 @@ obj-$(CONFIG_SECURITYFS) += inode.o # Must precede capability.o in order to stack properly. obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o -obj-$(CONFIG_AUDIT) += lsm_audit.o +ifeq ($(CONFIG_AUDIT),y) +obj-$(CONFIG_SECURITY_SMACK) += lsm_audit.o +endif obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o diff --git a/security/selinux/avc.c b/security/selinux/avc.c index d9fd224..236aaa2 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -492,50 +492,23 @@ out: return node; } -/** - * avc_audit_pre_callback - SELinux specific information - * will be called by generic audit code - * @ab: the audit buffer - * @a: audit_data - */ -static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) +static inline void avc_print_ipv6_addr(struct audit_buffer *ab, + struct in6_addr *addr, __be16 port, + char *name1, char *name2) { - struct common_audit_data *ad = a; - struct av_decision *avd = ad->selinux_audit_data.avd; - u32 requested = ad->selinux_audit_data.requested; - int result = ad->selinux_audit_data.result; - u32 denied, audited; - denied = requested & ~avd->allowed; - if (denied) { - audited = denied; - if (!(audited & avd->auditdeny)) - return; - } else if (result) { - audited = denied = requested; - } else { - audited = requested; - if (!(audited & avd->auditallow)) - return; - } - audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); - avc_dump_av(ab, ad->selinux_audit_data.tclass, - ad->selinux_audit_data.audited); - audit_log_format(ab, " for "); + if (!ipv6_addr_any(addr)) + audit_log_format(ab, " %s=%pI6", name1, addr); + if (port) + audit_log_format(ab, " %s=%d", name2, ntohs(port)); } -/** - * avc_audit_post_callback - SELinux specific information - * will be called by generic audit code - * @ab: the audit buffer - * @a: audit_data - */ -static void avc_audit_post_callback(struct audit_buffer *ab, void *a) +static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, + __be16 port, char *name1, char *name2) { - struct common_audit_data *ad = a; - audit_log_format(ab, " "); - avc_dump_query(ab, ad->selinux_audit_data.ssid, - ad->selinux_audit_data.tsid, - ad->selinux_audit_data.tclass); + if (addr) + audit_log_format(ab, " %s=%pI4", name1, &addr); + if (port) + audit_log_format(ab, " %s=%d", name2, ntohs(port)); } /** @@ -559,14 +532,163 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) */ void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct av_decision *avd, int result, struct common_audit_data *a) + struct av_decision *avd, int result, struct avc_audit_data *a) { - a->selinux_audit_data.avd = avd; - a->selinux_audit_data.tclass = tclass; - a->selinux_audit_data.requested = requested; - a->lsm_pre_audit = avc_audit_pre_callback; - a->lsm_post_audit = avc_audit_post_callback; - common_lsm_audit(a); + struct task_struct *tsk = current; + struct inode *inode = NULL; + u32 denied, audited; + struct audit_buffer *ab; + + denied = requested & ~avd->allowed; + if (denied) { + audited = denied; + if (!(audited & avd->auditdeny)) + return; + } else if (result) { + audited = denied = requested; + } else { + audited = requested; + if (!(audited & avd->auditallow)) + return; + } + + ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); + if (!ab) + return; /* audit_panic has been called */ + audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); + avc_dump_av(ab, tclass, audited); + audit_log_format(ab, " for "); + if (a && a->tsk) + tsk = a->tsk; + if (tsk && tsk->pid) { + audit_log_format(ab, " pid=%d comm=", tsk->pid); + audit_log_untrustedstring(ab, tsk->comm); + } + if (a) { + switch (a->type) { + case AVC_AUDIT_DATA_IPC: + audit_log_format(ab, " key=%d", a->u.ipc_id); + break; + case AVC_AUDIT_DATA_CAP: + audit_log_format(ab, " capability=%d", a->u.cap); + break; + case AVC_AUDIT_DATA_FS: + if (a->u.fs.path.dentry) { + struct dentry *dentry = a->u.fs.path.dentry; + if (a->u.fs.path.mnt) { + audit_log_d_path(ab, "path=", + &a->u.fs.path); + } else { + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, dentry->d_name.name); + } + inode = dentry->d_inode; + } else if (a->u.fs.inode) { + struct dentry *dentry; + inode = a->u.fs.inode; + dentry = d_find_alias(inode); + if (dentry) { + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, dentry->d_name.name); + dput(dentry); + } + } + if (inode) + audit_log_format(ab, " dev=%s ino=%lu", + inode->i_sb->s_id, + inode->i_ino); + break; + case AVC_AUDIT_DATA_NET: + if (a->u.net.sk) { + struct sock *sk = a->u.net.sk; + struct unix_sock *u; + int len = 0; + char *p = NULL; + + switch (sk->sk_family) { + case AF_INET: { + struct inet_sock *inet = inet_sk(sk); + + avc_print_ipv4_addr(ab, inet->rcv_saddr, + inet->sport, + "laddr", "lport"); + avc_print_ipv4_addr(ab, inet->daddr, + inet->dport, + "faddr", "fport"); + break; + } + case AF_INET6: { + struct inet_sock *inet = inet_sk(sk); + struct ipv6_pinfo *inet6 = inet6_sk(sk); + + avc_print_ipv6_addr(ab, &inet6->rcv_saddr, + inet->sport, + "laddr", "lport"); + avc_print_ipv6_addr(ab, &inet6->daddr, + inet->dport, + "faddr", "fport"); + break; + } + case AF_UNIX: + u = unix_sk(sk); + if (u->dentry) { + struct path path = { + .dentry = u->dentry, + .mnt = u->mnt + }; + audit_log_d_path(ab, "path=", + &path); + break; + } + if (!u->addr) + break; + len = u->addr->len-sizeof(short); + p = &u->addr->name->sun_path[0]; + audit_log_format(ab, " path="); + if (*p) + audit_log_untrustedstring(ab, p); + else + audit_log_n_hex(ab, p, len); + break; + } + } + + switch (a->u.net.family) { + case AF_INET: + avc_print_ipv4_addr(ab, a->u.net.v4info.saddr, + a->u.net.sport, + "saddr", "src"); + avc_print_ipv4_addr(ab, a->u.net.v4info.daddr, + a->u.net.dport, + "daddr", "dest"); + break; + case AF_INET6: + avc_print_ipv6_addr(ab, &a->u.net.v6info.saddr, + a->u.net.sport, + "saddr", "src"); + avc_print_ipv6_addr(ab, &a->u.net.v6info.daddr, + a->u.net.dport, + "daddr", "dest"); + break; + } + if (a->u.net.netif > 0) { + struct net_device *dev; + + /* NOTE: we always use init's namespace */ + dev = dev_get_by_index(&init_net, + a->u.net.netif); + if (dev) { + audit_log_format(ab, " netif=%s", + dev->name); + dev_put(dev); + } + } + break; + } + } + audit_log_format(ab, " "); + avc_dump_query(ab, ssid, tsid, tclass); + audit_log_end(ab); } /** @@ -834,7 +956,7 @@ out: * another -errno upon other errors. */ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, - u32 requested, struct common_audit_data *auditdata) + u32 requested, struct avc_audit_data *auditdata) { struct av_decision avd; int rc; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a7de261..2081055 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1478,14 +1478,14 @@ static int task_has_capability(struct task_struct *tsk, const struct cred *cred, int cap, int audit) { - struct common_audit_data ad; + struct avc_audit_data ad; struct av_decision avd; u16 sclass; u32 sid = cred_sid(cred); u32 av = CAP_TO_MASK(cap); int rc; - COMMON_AUDIT_DATA_INIT(&ad, CAP); + AVC_AUDIT_DATA_INIT(&ad, CAP); ad.tsk = tsk; ad.u.cap = cap; @@ -1524,10 +1524,10 @@ static int task_has_system(struct task_struct *tsk, static int inode_has_perm(const struct cred *cred, struct inode *inode, u32 perms, - struct common_audit_data *adp) + struct avc_audit_data *adp) { struct inode_security_struct *isec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid; if (unlikely(IS_PRIVATE(inode))) @@ -1538,7 +1538,7 @@ static int inode_has_perm(const struct cred *cred, if (!adp) { adp = &ad; - COMMON_AUDIT_DATA_INIT(&ad, FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.inode = inode; } @@ -1554,9 +1554,9 @@ static inline int dentry_has_perm(const struct cred *cred, u32 av) { struct inode *inode = dentry->d_inode; - struct common_audit_data ad; + struct avc_audit_data ad; - COMMON_AUDIT_DATA_INIT(&ad, FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.mnt = mnt; ad.u.fs.path.dentry = dentry; return inode_has_perm(cred, inode, av, &ad); @@ -1576,11 +1576,11 @@ static int file_has_perm(const struct cred *cred, { struct file_security_struct *fsec = file->f_security; struct inode *inode = file->f_path.dentry->d_inode; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = cred_sid(cred); int rc; - COMMON_AUDIT_DATA_INIT(&ad, FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path = file->f_path; if (sid != fsec->sid) { @@ -1611,7 +1611,7 @@ static int may_create(struct inode *dir, struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; u32 sid, newsid; - struct common_audit_data ad; + struct avc_audit_data ad; int rc; dsec = dir->i_security; @@ -1620,7 +1620,7 @@ static int may_create(struct inode *dir, sid = tsec->sid; newsid = tsec->create_sid; - COMMON_AUDIT_DATA_INIT(&ad, FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, @@ -1664,7 +1664,7 @@ static int may_link(struct inode *dir, { struct inode_security_struct *dsec, *isec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = current_sid(); u32 av; int rc; @@ -1672,7 +1672,7 @@ static int may_link(struct inode *dir, dsec = dir->i_security; isec = dentry->d_inode->i_security; - COMMON_AUDIT_DATA_INIT(&ad, FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; av = DIR__SEARCH; @@ -1707,7 +1707,7 @@ static inline int may_rename(struct inode *old_dir, struct dentry *new_dentry) { struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = current_sid(); u32 av; int old_is_dir, new_is_dir; @@ -1718,7 +1718,7 @@ static inline int may_rename(struct inode *old_dir, old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); new_dsec = new_dir->i_security; - COMMON_AUDIT_DATA_INIT(&ad, FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = old_dentry; rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, @@ -1760,7 +1760,7 @@ static inline int may_rename(struct inode *old_dir, static int superblock_has_perm(const struct cred *cred, struct super_block *sb, u32 perms, - struct common_audit_data *ad) + struct avc_audit_data *ad) { struct superblock_security_struct *sbsec; u32 sid = cred_sid(cred); @@ -2100,7 +2100,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) const struct task_security_struct *old_tsec; struct task_security_struct *new_tsec; struct inode_security_struct *isec; - struct common_audit_data ad; + struct avc_audit_data ad; struct inode *inode = bprm->file->f_path.dentry->d_inode; int rc; @@ -2138,7 +2138,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) return rc; } - COMMON_AUDIT_DATA_INIT(&ad, FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path = bprm->file->f_path; if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) @@ -2231,7 +2231,7 @@ extern struct dentry *selinux_null; static inline void flush_unauthorized_files(const struct cred *cred, struct files_struct *files) { - struct common_audit_data ad; + struct avc_audit_data ad; struct file *file, *devnull = NULL; struct tty_struct *tty; struct fdtable *fdt; @@ -2265,7 +2265,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, /* Revalidate access to inherited open files. */ - COMMON_AUDIT_DATA_INIT(&ad, FS); + AVC_AUDIT_DATA_INIT(&ad, FS); spin_lock(&files->file_lock); for (;;) { @@ -2514,7 +2514,7 @@ out: static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) { const struct cred *cred = current_cred(); - struct common_audit_data ad; + struct avc_audit_data ad; int rc; rc = superblock_doinit(sb, data); @@ -2525,7 +2525,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) if (flags & MS_KERNMOUNT) return 0; - COMMON_AUDIT_DATA_INIT(&ad, FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = sb->s_root; return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); } @@ -2533,9 +2533,9 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) static int selinux_sb_statfs(struct dentry *dentry) { const struct cred *cred = current_cred(); - struct common_audit_data ad; + struct avc_audit_data ad; - COMMON_AUDIT_DATA_INIT(&ad, FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry->d_sb->s_root; return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); } @@ -2755,7 +2755,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, struct inode *inode = dentry->d_inode; struct inode_security_struct *isec = inode->i_security; struct superblock_security_struct *sbsec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 newsid, sid = current_sid(); int rc = 0; @@ -2769,7 +2769,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, if (!is_owner_or_cap(inode)) return -EPERM; - COMMON_AUDIT_DATA_INIT(&ad, FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; rc = avc_has_perm(sid, isec->sid, isec->sclass, @@ -3401,7 +3401,7 @@ static void selinux_task_to_inode(struct task_struct *p, /* Returns error only if unable to parse addresses */ static int selinux_parse_skb_ipv4(struct sk_buff *skb, - struct common_audit_data *ad, u8 *proto) + struct avc_audit_data *ad, u8 *proto) { int offset, ihlen, ret = -EINVAL; struct iphdr _iph, *ih; @@ -3482,7 +3482,7 @@ out: /* Returns error only if unable to parse addresses */ static int selinux_parse_skb_ipv6(struct sk_buff *skb, - struct common_audit_data *ad, u8 *proto) + struct avc_audit_data *ad, u8 *proto) { u8 nexthdr; int ret = -EINVAL, offset; @@ -3553,7 +3553,7 @@ out: #endif /* IPV6 */ -static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad, +static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, char **_addrp, int src, u8 *proto) { char *addrp; @@ -3635,7 +3635,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, u32 perms) { struct inode_security_struct *isec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid; int err = 0; @@ -3645,7 +3645,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, goto out; sid = task_sid(task); - COMMON_AUDIT_DATA_INIT(&ad, NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = sock->sk; err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); @@ -3732,7 +3732,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in if (family == PF_INET || family == PF_INET6) { char *addrp; struct inode_security_struct *isec; - struct common_audit_data ad; + struct avc_audit_data ad; struct sockaddr_in *addr4 = NULL; struct sockaddr_in6 *addr6 = NULL; unsigned short snum; @@ -3761,7 +3761,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in snum, &sid); if (err) goto out; - COMMON_AUDIT_DATA_INIT(&ad, NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sport = htons(snum); ad.u.net.family = family; err = avc_has_perm(isec->sid, sid, @@ -3794,7 +3794,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in if (err) goto out; - COMMON_AUDIT_DATA_INIT(&ad, NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sport = htons(snum); ad.u.net.family = family; @@ -3828,7 +3828,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, isec = SOCK_INODE(sock)->i_security; if (isec->sclass == SECCLASS_TCP_SOCKET || isec->sclass == SECCLASS_DCCP_SOCKET) { - struct common_audit_data ad; + struct avc_audit_data ad; struct sockaddr_in *addr4 = NULL; struct sockaddr_in6 *addr6 = NULL; unsigned short snum; @@ -3853,7 +3853,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, perm = (isec->sclass == SECCLASS_TCP_SOCKET) ? TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; - COMMON_AUDIT_DATA_INIT(&ad, NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.dport = htons(snum); ad.u.net.family = sk->sk_family; err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad); @@ -3943,13 +3943,13 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, struct sk_security_struct *ssec; struct inode_security_struct *isec; struct inode_security_struct *other_isec; - struct common_audit_data ad; + struct avc_audit_data ad; int err; isec = SOCK_INODE(sock)->i_security; other_isec = SOCK_INODE(other)->i_security; - COMMON_AUDIT_DATA_INIT(&ad, NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = other->sk; err = avc_has_perm(isec->sid, other_isec->sid, @@ -3975,13 +3975,13 @@ static int selinux_socket_unix_may_send(struct socket *sock, { struct inode_security_struct *isec; struct inode_security_struct *other_isec; - struct common_audit_data ad; + struct avc_audit_data ad; int err; isec = SOCK_INODE(sock)->i_security; other_isec = SOCK_INODE(other)->i_security; - COMMON_AUDIT_DATA_INIT(&ad, NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = other->sk; err = avc_has_perm(isec->sid, other_isec->sid, @@ -3994,7 +3994,7 @@ static int selinux_socket_unix_may_send(struct socket *sock, static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, u32 peer_sid, - struct common_audit_data *ad) + struct avc_audit_data *ad) { int err; u32 if_sid; @@ -4022,10 +4022,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, struct sk_security_struct *sksec = sk->sk_security; u32 peer_sid; u32 sk_sid = sksec->sid; - struct common_audit_data ad; + struct avc_audit_data ad; char *addrp; - COMMON_AUDIT_DATA_INIT(&ad, NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = skb->iif; ad.u.net.family = family; err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); @@ -4063,7 +4063,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) struct sk_security_struct *sksec = sk->sk_security; u16 family = sk->sk_family; u32 sk_sid = sksec->sid; - struct common_audit_data ad; + struct avc_audit_data ad; char *addrp; u8 secmark_active; u8 peerlbl_active; @@ -4087,7 +4087,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) if (!secmark_active && !peerlbl_active) return 0; - COMMON_AUDIT_DATA_INIT(&ad, NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = skb->iif; ad.u.net.family = family; err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); @@ -4345,7 +4345,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, int err; char *addrp; u32 peer_sid; - struct common_audit_data ad; + struct avc_audit_data ad; u8 secmark_active; u8 netlbl_active; u8 peerlbl_active; @@ -4362,7 +4362,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) return NF_DROP; - COMMON_AUDIT_DATA_INIT(&ad, NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = ifindex; ad.u.net.family = family; if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) @@ -4450,7 +4450,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, { struct sock *sk = skb->sk; struct sk_security_struct *sksec; - struct common_audit_data ad; + struct avc_audit_data ad; char *addrp; u8 proto; @@ -4458,7 +4458,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, return NF_ACCEPT; sksec = sk->sk_security; - COMMON_AUDIT_DATA_INIT(&ad, NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = ifindex; ad.u.net.family = family; if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) @@ -4482,7 +4482,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, u32 secmark_perm; u32 peer_sid; struct sock *sk; - struct common_audit_data ad; + struct avc_audit_data ad; char *addrp; u8 secmark_active; u8 peerlbl_active; @@ -4541,7 +4541,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, secmark_perm = PACKET__SEND; } - COMMON_AUDIT_DATA_INIT(&ad, NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = ifindex; ad.u.net.family = family; if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) @@ -4611,13 +4611,13 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) static int selinux_netlink_recv(struct sk_buff *skb, int capability) { int err; - struct common_audit_data ad; + struct avc_audit_data ad; err = cap_netlink_recv(skb, capability); if (err) return err; - COMMON_AUDIT_DATA_INIT(&ad, CAP); + AVC_AUDIT_DATA_INIT(&ad, CAP); ad.u.cap = capability; return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, @@ -4676,12 +4676,12 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, u32 perms) { struct ipc_security_struct *isec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = current_sid(); isec = ipc_perms->security; - COMMON_AUDIT_DATA_INIT(&ad, IPC); + AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = ipc_perms->key; return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); @@ -4701,7 +4701,7 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg) static int selinux_msg_queue_alloc_security(struct msg_queue *msq) { struct ipc_security_struct *isec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = current_sid(); int rc; @@ -4711,7 +4711,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) isec = msq->q_perm.security; - COMMON_AUDIT_DATA_INIT(&ad, IPC); + AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, @@ -4731,12 +4731,12 @@ static void selinux_msg_queue_free_security(struct msg_queue *msq) static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) { struct ipc_security_struct *isec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = current_sid(); isec = msq->q_perm.security; - COMMON_AUDIT_DATA_INIT(&ad, IPC); + AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, @@ -4775,7 +4775,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, { struct ipc_security_struct *isec; struct msg_security_struct *msec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = current_sid(); int rc; @@ -4796,7 +4796,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, return rc; } - COMMON_AUDIT_DATA_INIT(&ad, IPC); + AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; /* Can this process write to the queue? */ @@ -4820,14 +4820,14 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, { struct ipc_security_struct *isec; struct msg_security_struct *msec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = task_sid(target); int rc; isec = msq->q_perm.security; msec = msg->security; - COMMON_AUDIT_DATA_INIT(&ad, IPC); + AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; rc = avc_has_perm(sid, isec->sid, @@ -4842,7 +4842,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, static int selinux_shm_alloc_security(struct shmid_kernel *shp) { struct ipc_security_struct *isec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = current_sid(); int rc; @@ -4852,7 +4852,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) isec = shp->shm_perm.security; - COMMON_AUDIT_DATA_INIT(&ad, IPC); + AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = shp->shm_perm.key; rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, @@ -4872,12 +4872,12 @@ static void selinux_shm_free_security(struct shmid_kernel *shp) static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) { struct ipc_security_struct *isec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = current_sid(); isec = shp->shm_perm.security; - COMMON_AUDIT_DATA_INIT(&ad, IPC); + AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = shp->shm_perm.key; return avc_has_perm(sid, isec->sid, SECCLASS_SHM, @@ -4934,7 +4934,7 @@ static int selinux_shm_shmat(struct shmid_kernel *shp, static int selinux_sem_alloc_security(struct sem_array *sma) { struct ipc_security_struct *isec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = current_sid(); int rc; @@ -4944,7 +4944,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) isec = sma->sem_perm.security; - COMMON_AUDIT_DATA_INIT(&ad, IPC); + AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = sma->sem_perm.key; rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, @@ -4964,12 +4964,12 @@ static void selinux_sem_free_security(struct sem_array *sma) static int selinux_sem_associate(struct sem_array *sma, int semflg) { struct ipc_security_struct *isec; - struct common_audit_data ad; + struct avc_audit_data ad; u32 sid = current_sid(); isec = sma->sem_perm.security; - COMMON_AUDIT_DATA_INIT(&ad, IPC); + AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = sma->sem_perm.key; return avc_has_perm(sid, isec->sid, SECCLASS_SEM, diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index e94e82f..ae4c3a0 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -37,6 +36,48 @@ struct inode; struct sock; struct sk_buff; +/* Auxiliary data to use in generating the audit record. */ +struct avc_audit_data { + char type; +#define AVC_AUDIT_DATA_FS 1 +#define AVC_AUDIT_DATA_NET 2 +#define AVC_AUDIT_DATA_CAP 3 +#define AVC_AUDIT_DATA_IPC 4 + struct task_struct *tsk; + union { + struct { + struct path path; + struct inode *inode; + } fs; + struct { + int netif; + struct sock *sk; + u16 family; + __be16 dport; + __be16 sport; + union { + struct { + __be32 daddr; + __be32 saddr; + } v4; + struct { + struct in6_addr daddr; + struct in6_addr saddr; + } v6; + } fam; + } net; + int cap; + int ipc_id; + } u; +}; + +#define v4info fam.v4 +#define v6info fam.v6 + +/* Initialize an AVC audit data structure. */ +#define AVC_AUDIT_DATA_INIT(_d,_t) \ + { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; } + /* * AVC statistics */ @@ -57,9 +98,7 @@ void __init avc_init(void); void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct av_decision *avd, - int result, - struct common_audit_data *a); + struct av_decision *avd, int result, struct avc_audit_data *auditdata); #define AVC_STRICT 1 /* Ignore permissive mode. */ int avc_has_perm_noaudit(u32 ssid, u32 tsid, @@ -69,7 +108,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct common_audit_data *auditdata); + struct avc_audit_data *auditdata); u32 avc_policy_seqno(void); diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 8d73842..b4b5b9b 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h @@ -59,7 +59,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, struct sk_buff *skb, u16 family, - struct common_audit_data *ad); + struct avc_audit_data *ad); int selinux_netlbl_socket_setsockopt(struct socket *sock, int level, int optname); @@ -129,7 +129,7 @@ static inline int selinux_netlbl_socket_post_create(struct sock *sk, static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, struct sk_buff *skb, u16 family, - struct common_audit_data *ad) + struct avc_audit_data *ad) { return 0; } diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 13128f9..289e24b 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -41,9 +41,9 @@ static inline int selinux_xfrm_enabled(void) } int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, - struct common_audit_data *ad); + struct avc_audit_data *ad); int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct common_audit_data *ad, u8 proto); + struct avc_audit_data *ad, u8 proto); int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); static inline void selinux_xfrm_notify_policyload(void) @@ -57,13 +57,13 @@ static inline int selinux_xfrm_enabled(void) } static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, - struct common_audit_data *ad) + struct avc_audit_data *ad) { return 0; } static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct common_audit_data *ad, u8 proto) + struct avc_audit_data *ad, u8 proto) { return 0; } diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index e688237..2e98441 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -342,7 +342,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family) int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, struct sk_buff *skb, u16 family, - struct common_audit_data *ad) + struct avc_audit_data *ad) { int rc; u32 nlbl_sid; diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index f3cb9ed..72b1845 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -401,7 +401,7 @@ int selinux_xfrm_state_delete(struct xfrm_state *x) * gone thru the IPSec process. */ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, - struct common_audit_data *ad) + struct avc_audit_data *ad) { int i, rc = 0; struct sec_path *sp; @@ -442,7 +442,7 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, * checked in the selinux_xfrm_state_pol_flow_match hook above. */ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct common_audit_data *ad, u8 proto) + struct avc_audit_data *ad, u8 proto) { struct dst_entry *dst; int rc = 0; -- cgit v0.10.2 From df5ede82588487db1894933af217e4aa710978d5 Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Wed, 8 Jul 2009 18:06:47 +0000 Subject: net: remove redundant sched/ in net/Makefile Remove redundant sched/ in net/Makefile. sched/ is contained in previous: obj-$(CONFIG_NET) += ethernet/ 802/ sched/ netlink/, so the later obj-$(CONFIG_NET_SCHED) += sched/ isn't necessary. Signed-off-by: Changli Gao ---- Makefile | 1 - 1 file changed, 1 deletion(-) Signed-off-by: David S. Miller diff --git a/net/Makefile b/net/Makefile index ba324ae..1542e72 100644 --- a/net/Makefile +++ b/net/Makefile @@ -24,7 +24,6 @@ obj-y += ipv6/ endif obj-$(CONFIG_PACKET) += packet/ obj-$(CONFIG_NET_KEY) += key/ -obj-$(CONFIG_NET_SCHED) += sched/ obj-$(CONFIG_BRIDGE) += bridge/ obj-$(CONFIG_NET_DSA) += dsa/ obj-$(CONFIG_IPX) += ipx/ -- cgit v0.10.2 From 440c1ce178d6a6743e02d136a55b2de3f6d62a20 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Fri, 10 Jul 2009 15:33:49 +0000 Subject: dropmon: remove duplicated #include Remove duplicated #include('s) in include/linux/net_dropmon.h Signed-off-by: Huang Weiyi Signed-off-by: David S. Miller diff --git a/include/linux/net_dropmon.h b/include/linux/net_dropmon.h index 3ceb0cc..2a73946 100644 --- a/include/linux/net_dropmon.h +++ b/include/linux/net_dropmon.h @@ -3,7 +3,6 @@ #include #include -#include struct net_dm_drop_point { __u8 pc[8]; -- cgit v0.10.2 From 8e321c4f72e2fb580a091317ba0fb2941f637ce1 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 11 Jul 2009 10:03:55 +0000 Subject: drivers/net/bonding: Adjust constant name AD_SHORT_TIMEOUT and AD_STATE_LACP_ACTIVITY have the same value, but AD_STATE_LACP_ACTIVITY better reflects the intended semantics. [ J adds: AD_STATE_LACP_ACTIVITY is a value defined by the standard, and should be set here in accordance with 802.3ad 43.4.12; AD_SHORT_TIMEOUT is a constant specific to the Linux 802.3ad implementation that happens to have the same value ] The semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ struct port_params p; @@ * p.port_state |= AD_SHORT_TIMEOUT // Signed-off-by: Julia Lawall Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 0e7dfe0..be799d2 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1109,7 +1109,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) //mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port. port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION; port->sm_vars &= ~AD_PORT_MATCHED; - port->partner_oper.port_state |= AD_SHORT_TIMEOUT; + port->partner_oper.port_state |= + AD_STATE_LACP_ACTIVITY; port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT)); port->actor_oper_port_state |= AD_STATE_EXPIRED; break; -- cgit v0.10.2 From 33e319fba727708ee45fec70091c498da4e8f606 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 13 Jul 2009 02:20:10 +0200 Subject: ASoC: Keep index within stac9766_reg[] Keep index within stac9766_reg[] Signed-off-by: Roel Kluin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 8ad4b7b..befc648 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -149,7 +149,7 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, stac9766_ac97_write(codec, AC97_INT_PAGING, 1); return 0; } - if (reg / 2 > ARRAY_SIZE(stac9766_reg)) + if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) return -EIO; soc_ac97_ops.write(codec->ac97, reg, val); @@ -168,7 +168,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, stac9766_ac97_write(codec, AC97_INT_PAGING, 1); return val; } - if (reg / 2 > ARRAY_SIZE(stac9766_reg)) + if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) return -EIO; if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || -- cgit v0.10.2 From 97fd5bc7f2e442482a7a6cc4bc2a286cbb5f4754 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 13 Jul 2009 11:17:49 -0700 Subject: net: Rename lookup_neigh_params function Rename lookup_neigh_params to lookup_neigh_parms as the struct is named neigh_parms and all other functions dealing with the struct carry neigh_parms in their names. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 163b4f5..c6f9ad8 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1316,7 +1316,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, } EXPORT_SYMBOL(pneigh_enqueue); -static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, +static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl, struct net *net, int ifindex) { struct neigh_parms *p; @@ -1337,7 +1337,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, struct net *net = dev_net(dev); const struct net_device_ops *ops = dev->netdev_ops; - ref = lookup_neigh_params(tbl, net, 0); + ref = lookup_neigh_parms(tbl, net, 0); if (!ref) return NULL; @@ -1906,7 +1906,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) if (tbp[NDTPA_IFINDEX]) ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]); - p = lookup_neigh_params(tbl, net, ifindex); + p = lookup_neigh_parms(tbl, net, ifindex); if (p == NULL) { err = -ENOENT; goto errout_tbl_lock; -- cgit v0.10.2 From 087d53ab11d538ce57b8a8e0ef899d7ee6a38548 Mon Sep 17 00:00:00 2001 From: Rongrong Cao Date: Fri, 10 Jul 2009 20:13:30 +0100 Subject: ASoC: fix checking for external widgets bug In SOC DAPM layer of SOUND subsystem, when add signal route (in the function snd_soc_dapm_add_route() ), the original code has wrong logic when dapm layer check each widget whether an external one. Signed-off-by: Rongrong Cao Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a40594f..c68c204 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1293,8 +1293,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, if (wsink->id == snd_soc_dapm_input) { if (wsource->id == snd_soc_dapm_micbias || wsource->id == snd_soc_dapm_mic || - wsink->id == snd_soc_dapm_line || - wsink->id == snd_soc_dapm_output) + wsource->id == snd_soc_dapm_line || + wsource->id == snd_soc_dapm_output) wsink->ext = 1; } if (wsource->id == snd_soc_dapm_output) { -- cgit v0.10.2 From a27e304b5c0bd7a3d6f337fd107a0a93d8687821 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Mon, 13 Jul 2009 14:50:39 -0700 Subject: ASoC: spdif codec: enable use by modules Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c index 218b33a..ca9e997 100644 --- a/sound/soc/codecs/spdif_transciever.c +++ b/sound/soc/codecs/spdif_transciever.c @@ -34,6 +34,7 @@ struct snd_soc_dai dit_stub_dai = { .formats = STUB_FORMATS, }, }; +EXPORT_SYMBOL_GPL(dit_stub_dai); static int spdif_dit_probe(struct platform_device *pdev) { -- cgit v0.10.2 From 0a0cf58d93b49bdd3ba6049a5536e76c32ef7f88 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Mon, 13 Jul 2009 14:50:40 -0700 Subject: ASoC: spdif: set module licence to GPL Without MODULE_LICENCE("GPL"), when built as a module it will fail to load because it uses other GPL symbols from kernel. Signed-off-by: Kevin Hilman Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c index ca9e997..a631911 100644 --- a/sound/soc/codecs/spdif_transciever.c +++ b/sound/soc/codecs/spdif_transciever.c @@ -21,6 +21,8 @@ #include "spdif_transciever.h" +MODULE_LICENSE("GPL"); + #define STUB_RATES SNDRV_PCM_RATE_8000_96000 #define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE -- cgit v0.10.2 From 47db8e89ac04377fc4de9278d0a3d6e599c04b95 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Mon, 13 Jul 2009 23:05:11 +0100 Subject: ASoC: fixes multiple typos in comments, no functional change Signed-off-by: Peter Meerwald Signed-off-by: Mark Brown diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 352d7ee..05991b0 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -27,8 +27,8 @@ struct snd_pcm_substream; #define SND_SOC_DAIFMT_I2S 0 /* I2S mode */ #define SND_SOC_DAIFMT_RIGHT_J 1 /* Right Justified mode */ #define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */ -#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM LRC */ -#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM LRC */ +#define SND_SOC_DAIFMT_DSP_A 3 /* L data MSB after FRM LRC */ +#define SND_SOC_DAIFMT_DSP_B 4 /* L data MSB during FRM LRC */ #define SND_SOC_DAIFMT_AC97 5 /* AC97 */ /* left and right justified also known as MSB and LSB respectively */ @@ -38,7 +38,7 @@ struct snd_pcm_substream; /* * DAI Clock gating. * - * DAI bit clocks can be be gated (disabled) when not the DAI is not + * DAI bit clocks can be be gated (disabled) when the DAI is not * sending or receiving PCM data in a frame. This can be used to save power. */ #define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */ @@ -51,21 +51,21 @@ struct snd_pcm_substream; * format. */ #define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */ -#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */ -#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */ -#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */ +#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal BCLK + inv FRM */ +#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert BCLK + nor FRM */ +#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert BCLK + FRM */ /* * DAI hardware clock masters. * * This is wrt the codec, the inverse is true for the interface - * i.e. if the codec is clk and frm master then the interface is + * i.e. if the codec is clk and FRM master then the interface is * clk and frame slave. */ -#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */ -#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */ +#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & FRM master */ +#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & FRM master */ #define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */ -#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */ +#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & FRM slave */ #define SND_SOC_DAIFMT_FORMAT_MASK 0x000f #define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 @@ -116,12 +116,12 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); /* * Digital Audio Interface. * - * Describes the Digital Audio Interface in terms of it's ALSA, DAI and AC97 - * operations an capabilities. Codec and platfom drivers will register a this + * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97 + * operations and capabilities. Codec and platform drivers will register this * structure for every DAI they have. * * This structure covers the clocking, formating and ALSA operations for each - * interface a + * interface. */ struct snd_soc_dai_ops { /* -- cgit v0.10.2 From 113adefc73c291f93f875fe515a46d8f76252fff Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 12:50:12 +0800 Subject: crypto: shash - Make descsize a run-time attribute This patch changes descsize to a run-time attribute so that implementations can change it in their init functions. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 131e14d..d8e0f8f 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -300,14 +300,16 @@ static int crypto_init_shash_ops_async(struct crypto_tfm *tfm) static int shash_compat_setkey(struct crypto_hash *tfm, const u8 *key, unsigned int keylen) { - struct shash_desc *desc = crypto_hash_ctx(tfm); + struct shash_desc **descp = crypto_hash_ctx(tfm); + struct shash_desc *desc = *descp; return crypto_shash_setkey(desc->tfm, key, keylen); } static int shash_compat_init(struct hash_desc *hdesc) { - struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm); + struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm); + struct shash_desc *desc = *descp; desc->flags = hdesc->flags; @@ -317,7 +319,8 @@ static int shash_compat_init(struct hash_desc *hdesc) static int shash_compat_update(struct hash_desc *hdesc, struct scatterlist *sg, unsigned int len) { - struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm); + struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm); + struct shash_desc *desc = *descp; struct crypto_hash_walk walk; int nbytes; @@ -330,7 +333,9 @@ static int shash_compat_update(struct hash_desc *hdesc, struct scatterlist *sg, static int shash_compat_final(struct hash_desc *hdesc, u8 *out) { - return crypto_shash_final(crypto_hash_ctx(hdesc->tfm), out); + struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm); + + return crypto_shash_final(*descp, out); } static int shash_compat_digest(struct hash_desc *hdesc, struct scatterlist *sg, @@ -340,7 +345,8 @@ static int shash_compat_digest(struct hash_desc *hdesc, struct scatterlist *sg, int err; if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) { - struct shash_desc *desc = crypto_hash_ctx(hdesc->tfm); + struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm); + struct shash_desc *desc = *descp; void *data; desc->flags = hdesc->flags; @@ -368,9 +374,11 @@ out: static void crypto_exit_shash_ops_compat(struct crypto_tfm *tfm) { - struct shash_desc *desc= crypto_tfm_ctx(tfm); + struct shash_desc **descp = crypto_tfm_ctx(tfm); + struct shash_desc *desc = *descp; crypto_free_shash(desc->tfm); + kzfree(desc); } static int crypto_init_shash_ops_compat(struct crypto_tfm *tfm) @@ -378,8 +386,9 @@ static int crypto_init_shash_ops_compat(struct crypto_tfm *tfm) struct hash_tfm *crt = &tfm->crt_hash; struct crypto_alg *calg = tfm->__crt_alg; struct shash_alg *alg = __crypto_shash_alg(calg); - struct shash_desc *desc = crypto_tfm_ctx(tfm); + struct shash_desc **descp = crypto_tfm_ctx(tfm); struct crypto_shash *shash; + struct shash_desc *desc; if (!crypto_mod_get(calg)) return -EAGAIN; @@ -390,6 +399,14 @@ static int crypto_init_shash_ops_compat(struct crypto_tfm *tfm) return PTR_ERR(shash); } + desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(shash), + GFP_KERNEL); + if (!desc) { + crypto_free_shash(shash); + return -ENOMEM; + } + + *descp = desc; desc->tfm = shash; tfm->exit = crypto_exit_shash_ops_compat; @@ -419,11 +436,9 @@ static int crypto_init_shash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) static unsigned int crypto_shash_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) { - struct shash_alg *salg = __crypto_shash_alg(alg); - switch (mask & CRYPTO_ALG_TYPE_MASK) { case CRYPTO_ALG_TYPE_HASH_MASK: - return sizeof(struct shash_desc) + salg->descsize; + return sizeof(struct shash_desc *); case CRYPTO_ALG_TYPE_AHASH_MASK: return sizeof(struct crypto_shash *); } @@ -434,6 +449,9 @@ static unsigned int crypto_shash_ctxsize(struct crypto_alg *alg, u32 type, static int crypto_shash_init_tfm(struct crypto_tfm *tfm, const struct crypto_type *frontend) { + struct crypto_shash *hash = __crypto_shash_cast(tfm); + + hash->descsize = crypto_shash_alg(hash)->descsize; return 0; } @@ -452,7 +470,6 @@ static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "type : shash\n"); seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); seq_printf(m, "digestsize : %u\n", salg->digestsize); - seq_printf(m, "descsize : %u\n", salg->descsize); } static const struct crypto_type crypto_shash_type = { diff --git a/include/crypto/hash.h b/include/crypto/hash.h index f74214a..fcc02d9 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -48,6 +48,7 @@ struct crypto_ahash { }; struct crypto_shash { + unsigned int descsize; struct crypto_tfm base; }; @@ -275,7 +276,7 @@ static inline void crypto_shash_clear_flags(struct crypto_shash *tfm, u32 flags) static inline unsigned int crypto_shash_descsize(struct crypto_shash *tfm) { - return crypto_shash_alg(tfm)->descsize; + return tfm->descsize; } static inline void *shash_desc_ctx(struct shash_desc *desc) diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 069b93e..2d1b10f 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -135,7 +135,7 @@ static inline void *crypto_shash_ctx_aligned(struct crypto_shash *tfm) static inline struct crypto_shash *__crypto_shash_cast(struct crypto_tfm *tfm) { - return (struct crypto_shash *)tfm; + return container_of(tfm, struct crypto_shash, base); } #endif /* _CRYPTO_INTERNAL_HASH_H */ -- cgit v0.10.2 From bbbee4679afd7c29a58087f133ffe241597f3144 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 11 Jul 2009 18:16:16 +0800 Subject: crypto: padlock - Switch sha to shash This patch converts the padlock-sha implementation to shash. In doing so the existing mechanism of storing the data until final is no longer viable as we do not have a way of allocating data in crypto_shash_init and then reliably freeing it. This is just as well because a better way of handling the problem is to hash everything but the last chunk using normal sha code and then provide the intermediate result to the padlock device. This is good enough because the primary application of padlock-sha is IPsec and there the data is laid out in the form of an hmac header followed by the rest of the packet. In essence we can provide all the data to the padlock as the hmac header only needs to be hashed once. Signed-off-by: Herbert Xu diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 5b27692..1bb4b7fe 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -13,7 +13,6 @@ if CRYPTO_HW config CRYPTO_DEV_PADLOCK tristate "Support for VIA PadLock ACE" depends on X86 && !UML - select CRYPTO_ALGAPI help Some VIA processors come with an integrated crypto engine (so called VIA PadLock ACE, Advanced Cryptography Engine) @@ -39,6 +38,7 @@ config CRYPTO_DEV_PADLOCK_AES config CRYPTO_DEV_PADLOCK_SHA tristate "PadLock driver for SHA1 and SHA256 algorithms" depends on CRYPTO_DEV_PADLOCK + select CRYPTO_HASH select CRYPTO_SHA1 select CRYPTO_SHA256 help diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index 868da54..fb6e6c3 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -24,73 +24,31 @@ #include #include "padlock.h" -struct padlock_sha_ctx { - char *data; - size_t used; - int bypass; - void (*f_sha_padlock)(const char *in, char *out, int count); - struct shash_desc *fallback; +struct padlock_sha_desc { + struct shash_desc fallback; }; -static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm) -{ - return crypto_tfm_ctx(tfm); -} - -/* We'll need aligned address on the stack */ -#define NEAREST_ALIGNED(ptr) \ - ((void *)ALIGN((size_t)(ptr), PADLOCK_ALIGNMENT)) - -static struct crypto_alg sha1_alg, sha256_alg; +struct padlock_sha_ctx { + struct crypto_shash *fallback; +}; -static int padlock_sha_bypass(struct crypto_tfm *tfm) +static int padlock_sha_init(struct shash_desc *desc) { - int err = 0; - - if (ctx(tfm)->bypass) - goto out; + struct padlock_sha_desc *dctx = shash_desc_ctx(desc); + struct padlock_sha_ctx *ctx = crypto_shash_ctx(desc->tfm); - err = crypto_shash_init(ctx(tfm)->fallback); - if (err) - goto out; - - if (ctx(tfm)->data && ctx(tfm)->used) - err = crypto_shash_update(ctx(tfm)->fallback, ctx(tfm)->data, - ctx(tfm)->used); - - ctx(tfm)->used = 0; - ctx(tfm)->bypass = 1; - -out: - return err; + dctx->fallback.tfm = ctx->fallback; + dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + return crypto_shash_init(&dctx->fallback); } -static void padlock_sha_init(struct crypto_tfm *tfm) +static int padlock_sha_update(struct shash_desc *desc, + const u8 *data, unsigned int length) { - ctx(tfm)->used = 0; - ctx(tfm)->bypass = 0; -} + struct padlock_sha_desc *dctx = shash_desc_ctx(desc); -static void padlock_sha_update(struct crypto_tfm *tfm, - const uint8_t *data, unsigned int length) -{ - int err; - - /* Our buffer is always one page. */ - if (unlikely(!ctx(tfm)->bypass && - (ctx(tfm)->used + length > PAGE_SIZE))) { - err = padlock_sha_bypass(tfm); - BUG_ON(err); - } - - if (unlikely(ctx(tfm)->bypass)) { - err = crypto_shash_update(ctx(tfm)->fallback, data, length); - BUG_ON(err); - return; - } - - memcpy(ctx(tfm)->data + ctx(tfm)->used, data, length); - ctx(tfm)->used += length; + dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + return crypto_shash_update(&dctx->fallback, data, length); } static inline void padlock_output_block(uint32_t *src, @@ -100,88 +58,138 @@ static inline void padlock_output_block(uint32_t *src, *dst++ = swab32(*src++); } -static void padlock_do_sha1(const char *in, char *out, int count) +static int padlock_sha1_finup(struct shash_desc *desc, const u8 *in, + unsigned int count, u8 *out) { /* We can't store directly to *out as it may be unaligned. */ /* BTW Don't reduce the buffer size below 128 Bytes! * PadLock microcode needs it that big. */ - char buf[128+16]; - char *result = NEAREST_ALIGNED(buf); + char result[128] __attribute__ ((aligned(PADLOCK_ALIGNMENT))); + struct padlock_sha_desc *dctx = shash_desc_ctx(desc); + struct sha1_state state; + unsigned int space; + unsigned int leftover; int ts_state; + int err; + + dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + err = crypto_shash_export(&dctx->fallback, &state); + if (err) + goto out; + + if (state.count + count > ULONG_MAX) + return crypto_shash_finup(&dctx->fallback, in, count, out); + + leftover = ((state.count - 1) & (SHA1_BLOCK_SIZE - 1)) + 1; + space = SHA1_BLOCK_SIZE - leftover; + if (space) { + if (count > space) { + err = crypto_shash_update(&dctx->fallback, in, space) ?: + crypto_shash_export(&dctx->fallback, &state); + if (err) + goto out; + count -= space; + in += space; + } else { + memcpy(state.buffer + leftover, in, count); + in = state.buffer; + count += leftover; + } + } + + memcpy(result, &state.state, SHA1_DIGEST_SIZE); - ((uint32_t *)result)[0] = SHA1_H0; - ((uint32_t *)result)[1] = SHA1_H1; - ((uint32_t *)result)[2] = SHA1_H2; - ((uint32_t *)result)[3] = SHA1_H3; - ((uint32_t *)result)[4] = SHA1_H4; - /* prevent taking the spurious DNA fault with padlock. */ ts_state = irq_ts_save(); asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */ - : "+S"(in), "+D"(result) - : "c"(count), "a"(0)); + : \ + : "c"(state.count + count), "a"(state.count), \ + "S"(in), "D"(result)); irq_ts_restore(ts_state); padlock_output_block((uint32_t *)result, (uint32_t *)out, 5); + +out: + return err; } -static void padlock_do_sha256(const char *in, char *out, int count) +static int padlock_sha1_final(struct shash_desc *desc, u8 *out) +{ + u8 buf[4]; + + return padlock_sha1_finup(desc, buf, 0, out); +} + +static int padlock_sha256_finup(struct shash_desc *desc, const u8 *in, + unsigned int count, u8 *out) { /* We can't store directly to *out as it may be unaligned. */ /* BTW Don't reduce the buffer size below 128 Bytes! * PadLock microcode needs it that big. */ - char buf[128+16]; - char *result = NEAREST_ALIGNED(buf); + char result[128] __attribute__ ((aligned(PADLOCK_ALIGNMENT))); + struct padlock_sha_desc *dctx = shash_desc_ctx(desc); + struct sha256_state state; + unsigned int space; + unsigned int leftover; int ts_state; + int err; - ((uint32_t *)result)[0] = SHA256_H0; - ((uint32_t *)result)[1] = SHA256_H1; - ((uint32_t *)result)[2] = SHA256_H2; - ((uint32_t *)result)[3] = SHA256_H3; - ((uint32_t *)result)[4] = SHA256_H4; - ((uint32_t *)result)[5] = SHA256_H5; - ((uint32_t *)result)[6] = SHA256_H6; - ((uint32_t *)result)[7] = SHA256_H7; + dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + err = crypto_shash_export(&dctx->fallback, &state); + if (err) + goto out; + + if (state.count + count > ULONG_MAX) + return crypto_shash_finup(&dctx->fallback, in, count, out); + + leftover = ((state.count - 1) & (SHA256_BLOCK_SIZE - 1)) + 1; + space = SHA256_BLOCK_SIZE - leftover; + if (space) { + if (count > space) { + err = crypto_shash_update(&dctx->fallback, in, space) ?: + crypto_shash_export(&dctx->fallback, &state); + if (err) + goto out; + count -= space; + in += space; + } else { + memcpy(state.buf + leftover, in, count); + in = state.buf; + count += leftover; + } + } + + memcpy(result, &state.state, SHA256_DIGEST_SIZE); /* prevent taking the spurious DNA fault with padlock. */ ts_state = irq_ts_save(); asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */ - : "+S"(in), "+D"(result) - : "c"(count), "a"(0)); + : \ + : "c"(state.count + count), "a"(state.count), \ + "S"(in), "D"(result)); irq_ts_restore(ts_state); padlock_output_block((uint32_t *)result, (uint32_t *)out, 8); + +out: + return err; } -static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out) +static int padlock_sha256_final(struct shash_desc *desc, u8 *out) { - int err; - - if (unlikely(ctx(tfm)->bypass)) { - err = crypto_shash_final(ctx(tfm)->fallback, out); - BUG_ON(err); - ctx(tfm)->bypass = 0; - return; - } + u8 buf[4]; - /* Pass the input buffer to PadLock microcode... */ - ctx(tfm)->f_sha_padlock(ctx(tfm)->data, out, ctx(tfm)->used); - - ctx(tfm)->used = 0; + return padlock_sha256_finup(desc, buf, 0, out); } static int padlock_cra_init(struct crypto_tfm *tfm) { + struct crypto_shash *hash = __crypto_shash_cast(tfm); const char *fallback_driver_name = tfm->__crt_alg->cra_name; + struct padlock_sha_ctx *ctx = crypto_tfm_ctx(tfm); struct crypto_shash *fallback_tfm; int err = -ENOMEM; - /* For now we'll allocate one page. This - * could eventually be configurable one day. */ - ctx(tfm)->data = (char *)__get_free_page(GFP_KERNEL); - if (!ctx(tfm)->data) - goto out; - /* Allocate a fallback and abort if it failed. */ fallback_tfm = crypto_alloc_shash(fallback_driver_name, 0, CRYPTO_ALG_NEED_FALLBACK); @@ -189,94 +197,63 @@ static int padlock_cra_init(struct crypto_tfm *tfm) printk(KERN_WARNING PFX "Fallback driver '%s' could not be loaded!\n", fallback_driver_name); err = PTR_ERR(fallback_tfm); - goto out_free_page; + goto out; } - ctx(tfm)->fallback = kmalloc(sizeof(struct shash_desc) + - crypto_shash_descsize(fallback_tfm), - GFP_KERNEL); - if (!ctx(tfm)->fallback) - goto out_free_tfm; - - ctx(tfm)->fallback->tfm = fallback_tfm; - ctx(tfm)->fallback->flags = 0; + ctx->fallback = fallback_tfm; + hash->descsize += crypto_shash_descsize(fallback_tfm); return 0; -out_free_tfm: - crypto_free_shash(fallback_tfm); -out_free_page: - free_page((unsigned long)(ctx(tfm)->data)); out: return err; } -static int padlock_sha1_cra_init(struct crypto_tfm *tfm) -{ - ctx(tfm)->f_sha_padlock = padlock_do_sha1; - - return padlock_cra_init(tfm); -} - -static int padlock_sha256_cra_init(struct crypto_tfm *tfm) -{ - ctx(tfm)->f_sha_padlock = padlock_do_sha256; - - return padlock_cra_init(tfm); -} - static void padlock_cra_exit(struct crypto_tfm *tfm) { - if (ctx(tfm)->data) { - free_page((unsigned long)(ctx(tfm)->data)); - ctx(tfm)->data = NULL; - } - - crypto_free_shash(ctx(tfm)->fallback->tfm); + struct padlock_sha_ctx *ctx = crypto_tfm_ctx(tfm); - kzfree(ctx(tfm)->fallback); + crypto_free_shash(ctx->fallback); } -static struct crypto_alg sha1_alg = { - .cra_name = "sha1", - .cra_driver_name = "sha1-padlock", - .cra_priority = PADLOCK_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_DIGEST | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct padlock_sha_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(sha1_alg.cra_list), - .cra_init = padlock_sha1_cra_init, - .cra_exit = padlock_cra_exit, - .cra_u = { - .digest = { - .dia_digestsize = SHA1_DIGEST_SIZE, - .dia_init = padlock_sha_init, - .dia_update = padlock_sha_update, - .dia_final = padlock_sha_final, - } +static struct shash_alg sha1_alg = { + .digestsize = SHA1_DIGEST_SIZE, + .init = padlock_sha_init, + .update = padlock_sha_update, + .finup = padlock_sha1_finup, + .final = padlock_sha1_final, + .descsize = sizeof(struct padlock_sha_desc), + .base = { + .cra_name = "sha1", + .cra_driver_name = "sha1-padlock", + .cra_priority = PADLOCK_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct padlock_sha_ctx), + .cra_module = THIS_MODULE, + .cra_init = padlock_cra_init, + .cra_exit = padlock_cra_exit, } }; -static struct crypto_alg sha256_alg = { - .cra_name = "sha256", - .cra_driver_name = "sha256-padlock", - .cra_priority = PADLOCK_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_DIGEST | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = SHA256_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct padlock_sha_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(sha256_alg.cra_list), - .cra_init = padlock_sha256_cra_init, - .cra_exit = padlock_cra_exit, - .cra_u = { - .digest = { - .dia_digestsize = SHA256_DIGEST_SIZE, - .dia_init = padlock_sha_init, - .dia_update = padlock_sha_update, - .dia_final = padlock_sha_final, - } +static struct shash_alg sha256_alg = { + .digestsize = SHA256_DIGEST_SIZE, + .init = padlock_sha_init, + .update = padlock_sha_update, + .finup = padlock_sha256_finup, + .final = padlock_sha256_final, + .descsize = sizeof(struct padlock_sha_desc), + .base = { + .cra_name = "sha256", + .cra_driver_name = "sha256-padlock", + .cra_priority = PADLOCK_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct padlock_sha_ctx), + .cra_module = THIS_MODULE, + .cra_init = padlock_cra_init, + .cra_exit = padlock_cra_exit, } }; @@ -294,11 +271,11 @@ static int __init padlock_init(void) return -ENODEV; } - rc = crypto_register_alg(&sha1_alg); + rc = crypto_register_shash(&sha1_alg); if (rc) goto out; - rc = crypto_register_alg(&sha256_alg); + rc = crypto_register_shash(&sha256_alg); if (rc) goto out_unreg1; @@ -307,7 +284,7 @@ static int __init padlock_init(void) return 0; out_unreg1: - crypto_unregister_alg(&sha1_alg); + crypto_unregister_shash(&sha1_alg); out: printk(KERN_ERR PFX "VIA PadLock SHA1/SHA256 initialization failed.\n"); return rc; @@ -315,8 +292,8 @@ out: static void __exit padlock_fini(void) { - crypto_unregister_alg(&sha1_alg); - crypto_unregister_alg(&sha256_alg); + crypto_unregister_shash(&sha1_alg); + crypto_unregister_shash(&sha256_alg); } module_init(padlock_init); -- cgit v0.10.2 From 8bd1209cfff246ce6dfae86837467a01236f9cb6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 9 Jul 2009 12:43:37 +0800 Subject: crypto: hmac - Switch to shash This patch changes hmac to the new shash interface. Signed-off-by: Herbert Xu diff --git a/crypto/hmac.c b/crypto/hmac.c index 0ad39c3..e373427 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -27,7 +27,7 @@ #include struct hmac_ctx { - struct crypto_hash *child; + struct shash_desc *desc; }; static inline void *align_ptr(void *p, unsigned int align) @@ -35,57 +35,33 @@ static inline void *align_ptr(void *p, unsigned int align) return (void *)ALIGN((unsigned long)p, align); } -static inline struct hmac_ctx *hmac_ctx(struct crypto_hash *tfm) +static inline struct hmac_ctx *hmac_ctx(struct crypto_shash *tfm) { - return align_ptr(crypto_hash_ctx_aligned(tfm) + - crypto_hash_blocksize(tfm) * 2 + - crypto_hash_digestsize(tfm), sizeof(void *)); + return align_ptr(crypto_shash_ctx_aligned(tfm) + + crypto_shash_blocksize(tfm) * 2 + + crypto_shash_digestsize(tfm), + crypto_tfm_ctx_alignment()); } -static int hmac_setkey(struct crypto_hash *parent, +static int hmac_setkey(struct crypto_shash *parent, const u8 *inkey, unsigned int keylen) { - int bs = crypto_hash_blocksize(parent); - int ds = crypto_hash_digestsize(parent); - char *ipad = crypto_hash_ctx_aligned(parent); + int bs = crypto_shash_blocksize(parent); + int ds = crypto_shash_digestsize(parent); + char *ipad = crypto_shash_ctx_aligned(parent); char *opad = ipad + bs; char *digest = opad + bs; - struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *)); - struct crypto_hash *tfm = ctx->child; + struct hmac_ctx *ctx = align_ptr(digest + ds, + crypto_tfm_ctx_alignment()); unsigned int i; if (keylen > bs) { - struct hash_desc desc; - struct scatterlist tmp; - int tmplen; int err; - desc.tfm = tfm; - desc.flags = crypto_hash_get_flags(parent); - desc.flags &= CRYPTO_TFM_REQ_MAY_SLEEP; + ctx->desc->flags = crypto_shash_get_flags(parent) & + CRYPTO_TFM_REQ_MAY_SLEEP; - err = crypto_hash_init(&desc); - if (err) - return err; - - tmplen = bs * 2 + ds; - sg_init_one(&tmp, ipad, tmplen); - - for (; keylen > tmplen; inkey += tmplen, keylen -= tmplen) { - memcpy(ipad, inkey, tmplen); - err = crypto_hash_update(&desc, &tmp, tmplen); - if (err) - return err; - } - - if (keylen) { - memcpy(ipad, inkey, keylen); - err = crypto_hash_update(&desc, &tmp, keylen); - if (err) - return err; - } - - err = crypto_hash_final(&desc, digest); + err = crypto_shash_digest(ctx->desc, inkey, keylen, digest); if (err) return err; @@ -105,181 +81,162 @@ static int hmac_setkey(struct crypto_hash *parent, return 0; } -static int hmac_init(struct hash_desc *pdesc) +static int hmac_init(struct shash_desc *pdesc) { - struct crypto_hash *parent = pdesc->tfm; - int bs = crypto_hash_blocksize(parent); - int ds = crypto_hash_digestsize(parent); - char *ipad = crypto_hash_ctx_aligned(parent); - struct hmac_ctx *ctx = align_ptr(ipad + bs * 2 + ds, sizeof(void *)); - struct hash_desc desc; - struct scatterlist tmp; - int err; - - desc.tfm = ctx->child; - desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - sg_init_one(&tmp, ipad, bs); - - err = crypto_hash_init(&desc); - if (unlikely(err)) - return err; - - return crypto_hash_update(&desc, &tmp, bs); + struct crypto_shash *parent = pdesc->tfm; + int bs = crypto_shash_blocksize(parent); + int ds = crypto_shash_digestsize(parent); + char *ipad = crypto_shash_ctx_aligned(parent); + struct hmac_ctx *ctx = align_ptr(ipad + bs * 2 + ds, + crypto_tfm_ctx_alignment()); + struct shash_desc *desc = shash_desc_ctx(pdesc); + + desc->tfm = ctx->desc->tfm; + desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + + return crypto_shash_init(desc) ?: + crypto_shash_update(desc, ipad, bs); } -static int hmac_update(struct hash_desc *pdesc, - struct scatterlist *sg, unsigned int nbytes) +static int hmac_update(struct shash_desc *pdesc, + const u8 *data, unsigned int nbytes) { - struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm); - struct hash_desc desc; + struct shash_desc *desc = shash_desc_ctx(pdesc); - desc.tfm = ctx->child; - desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - return crypto_hash_update(&desc, sg, nbytes); + return crypto_shash_update(desc, data, nbytes); } -static int hmac_final(struct hash_desc *pdesc, u8 *out) +static int hmac_final(struct shash_desc *pdesc, u8 *out) { - struct crypto_hash *parent = pdesc->tfm; - int bs = crypto_hash_blocksize(parent); - int ds = crypto_hash_digestsize(parent); - char *opad = crypto_hash_ctx_aligned(parent) + bs; + struct crypto_shash *parent = pdesc->tfm; + int bs = crypto_shash_blocksize(parent); + int ds = crypto_shash_digestsize(parent); + char *opad = crypto_shash_ctx_aligned(parent) + bs; char *digest = opad + bs; - struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *)); - struct hash_desc desc; - struct scatterlist tmp; - int err; - - desc.tfm = ctx->child; - desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - sg_init_one(&tmp, opad, bs + ds); + struct shash_desc *desc = shash_desc_ctx(pdesc); - err = crypto_hash_final(&desc, digest); - if (unlikely(err)) - return err; + desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - return crypto_hash_digest(&desc, &tmp, bs + ds, out); + return crypto_shash_final(desc, digest) ?: + crypto_shash_digest(desc, opad, bs + ds, out); } -static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg, - unsigned int nbytes, u8 *out) +static int hmac_finup(struct shash_desc *pdesc, const u8 *data, + unsigned int nbytes, u8 *out) { - struct crypto_hash *parent = pdesc->tfm; - int bs = crypto_hash_blocksize(parent); - int ds = crypto_hash_digestsize(parent); - char *ipad = crypto_hash_ctx_aligned(parent); - char *opad = ipad + bs; - char *digest = opad + bs; - struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *)); - struct hash_desc desc; - struct scatterlist sg1[2]; - struct scatterlist sg2[1]; - int err; - desc.tfm = ctx->child; - desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - - sg_init_table(sg1, 2); - sg_set_buf(sg1, ipad, bs); - scatterwalk_sg_chain(sg1, 2, sg); + struct crypto_shash *parent = pdesc->tfm; + int bs = crypto_shash_blocksize(parent); + int ds = crypto_shash_digestsize(parent); + char *opad = crypto_shash_ctx_aligned(parent) + bs; + char *digest = opad + bs; + struct shash_desc *desc = shash_desc_ctx(pdesc); - sg_init_table(sg2, 1); - sg_set_buf(sg2, opad, bs + ds); + desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - err = crypto_hash_digest(&desc, sg1, nbytes + bs, digest); - if (unlikely(err)) - return err; - - return crypto_hash_digest(&desc, sg2, bs + ds, out); + return crypto_shash_finup(desc, data, nbytes, digest) ?: + crypto_shash_digest(desc, opad, bs + ds, out); } static int hmac_init_tfm(struct crypto_tfm *tfm) { - struct crypto_hash *hash; + struct crypto_shash *parent = __crypto_shash_cast(tfm); + struct crypto_shash *hash; struct crypto_instance *inst = (void *)tfm->__crt_alg; - struct crypto_spawn *spawn = crypto_instance_ctx(inst); - struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm)); + struct crypto_shash_spawn *spawn = crypto_instance_ctx(inst); + struct hmac_ctx *ctx = hmac_ctx(parent); - hash = crypto_spawn_hash(spawn); + hash = crypto_spawn_shash(spawn); if (IS_ERR(hash)) return PTR_ERR(hash); - ctx->child = hash; + parent->descsize = sizeof(struct shash_desc) + + crypto_shash_descsize(hash); + + ctx->desc = kmalloc(parent->descsize, GFP_KERNEL); + if (!ctx->desc) { + crypto_free_shash(hash); + return -ENOMEM; + } + + ctx->desc->tfm = hash; return 0; } static void hmac_exit_tfm(struct crypto_tfm *tfm) { - struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm)); - crypto_free_hash(ctx->child); + struct hmac_ctx *ctx = hmac_ctx(__crypto_shash_cast(tfm)); + crypto_free_shash(ctx->desc->tfm); + kzfree(ctx->desc); } -static void hmac_free(struct crypto_instance *inst) +static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) { - crypto_drop_spawn(crypto_instance_ctx(inst)); - kfree(inst); -} - -static struct crypto_instance *hmac_alloc(struct rtattr **tb) -{ - struct crypto_instance *inst; + struct shash_instance *inst; struct crypto_alg *alg; + struct shash_alg *salg; int err; int ds; - err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH); + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH); if (err) - return ERR_PTR(err); - - alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH, - CRYPTO_ALG_TYPE_HASH_MASK); - if (IS_ERR(alg)) - return ERR_CAST(alg); - - inst = ERR_PTR(-EINVAL); - ds = alg->cra_type == &crypto_hash_type ? - alg->cra_hash.digestsize : - alg->cra_type ? - __crypto_shash_alg(alg)->digestsize : - alg->cra_digest.dia_digestsize; + return err; + + salg = shash_attr_alg(tb[1], 0, 0); + if (IS_ERR(salg)) + return PTR_ERR(salg); + + err = -EINVAL; + ds = salg->digestsize; + alg = &salg->base; if (ds > alg->cra_blocksize) goto out_put_alg; - inst = crypto_alloc_instance("hmac", alg); + inst = shash_alloc_instance("hmac", alg); if (IS_ERR(inst)) goto out_put_alg; - inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH; - inst->alg.cra_priority = alg->cra_priority; - inst->alg.cra_blocksize = alg->cra_blocksize; - inst->alg.cra_alignmask = alg->cra_alignmask; - inst->alg.cra_type = &crypto_hash_type; + err = crypto_init_shash_spawn(shash_instance_ctx(inst), salg, + shash_crypto_instance(inst)); + if (err) + goto out_free_inst; + + inst->alg.base.cra_priority = alg->cra_priority; + inst->alg.base.cra_blocksize = alg->cra_blocksize; + inst->alg.base.cra_alignmask = alg->cra_alignmask; - inst->alg.cra_hash.digestsize = ds; + inst->alg.digestsize = ds; - inst->alg.cra_ctxsize = sizeof(struct hmac_ctx) + - ALIGN(inst->alg.cra_blocksize * 2 + ds, - sizeof(void *)); + inst->alg.base.cra_ctxsize = sizeof(struct hmac_ctx) + + ALIGN(alg->cra_blocksize * 2 + ds, + crypto_tfm_ctx_alignment()); - inst->alg.cra_init = hmac_init_tfm; - inst->alg.cra_exit = hmac_exit_tfm; + inst->alg.base.cra_init = hmac_init_tfm; + inst->alg.base.cra_exit = hmac_exit_tfm; - inst->alg.cra_hash.init = hmac_init; - inst->alg.cra_hash.update = hmac_update; - inst->alg.cra_hash.final = hmac_final; - inst->alg.cra_hash.digest = hmac_digest; - inst->alg.cra_hash.setkey = hmac_setkey; + inst->alg.init = hmac_init; + inst->alg.update = hmac_update; + inst->alg.final = hmac_final; + inst->alg.finup = hmac_finup; + inst->alg.setkey = hmac_setkey; + + err = shash_register_instance(tmpl, inst); + if (err) { +out_free_inst: + shash_free_instance(shash_crypto_instance(inst)); + } out_put_alg: crypto_mod_put(alg); - return inst; + return err; } static struct crypto_template hmac_tmpl = { .name = "hmac", - .alloc = hmac_alloc, - .free = hmac_free, + .create = hmac_create, + .free = shash_free_instance, .module = THIS_MODULE, }; -- cgit v0.10.2 From 3106caab617c75c9a47706af3a8017318207be2d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 12 Jul 2009 12:48:32 +0800 Subject: crypto: xcbc - Switch to shash This patch converts the xcbc algorithm to the new shash type. Signed-off-by: Herbert Xu diff --git a/crypto/xcbc.c b/crypto/xcbc.c index b63b633..b2cc855 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c @@ -19,15 +19,9 @@ * Kazunori Miyazawa */ -#include -#include +#include #include -#include #include -#include -#include -#include -#include static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x02020202, 0x02020202, 0x02020202, 0x02020202, @@ -66,10 +60,10 @@ static void xor_128(u8 *a, const u8 *b, unsigned int bs) ((u32 *)a)[3] ^= ((u32 *)b)[3]; } -static int _crypto_xcbc_digest_setkey(struct crypto_hash *parent, +static int _crypto_xcbc_digest_setkey(struct crypto_shash *parent, struct crypto_xcbc_ctx *ctx) { - int bs = crypto_hash_blocksize(parent); + int bs = crypto_shash_blocksize(parent); int err = 0; u8 key1[bs]; @@ -81,10 +75,10 @@ static int _crypto_xcbc_digest_setkey(struct crypto_hash *parent, return crypto_cipher_setkey(ctx->child, key1, bs); } -static int crypto_xcbc_digest_setkey(struct crypto_hash *parent, +static int crypto_xcbc_digest_setkey(struct crypto_shash *parent, const u8 *inkey, unsigned int keylen) { - struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); + struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(parent); if (keylen != crypto_cipher_blocksize(ctx->child)) return -EINVAL; @@ -96,10 +90,10 @@ static int crypto_xcbc_digest_setkey(struct crypto_hash *parent, return _crypto_xcbc_digest_setkey(parent, ctx); } -static int crypto_xcbc_digest_init(struct hash_desc *pdesc) +static int crypto_xcbc_digest_init(struct shash_desc *pdesc) { - struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(pdesc->tfm); - int bs = crypto_hash_blocksize(pdesc->tfm); + struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(pdesc->tfm); + int bs = crypto_shash_blocksize(pdesc->tfm); ctx->len = 0; memset(ctx->odds, 0, bs); @@ -108,102 +102,55 @@ static int crypto_xcbc_digest_init(struct hash_desc *pdesc) return 0; } -static int crypto_xcbc_digest_update2(struct hash_desc *pdesc, - struct scatterlist *sg, - unsigned int nbytes) +static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p, + unsigned int len) { - struct crypto_hash *parent = pdesc->tfm; - struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); + struct crypto_shash *parent = pdesc->tfm; + struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(parent); struct crypto_cipher *tfm = ctx->child; - int bs = crypto_hash_blocksize(parent); - - for (;;) { - struct page *pg = sg_page(sg); - unsigned int offset = sg->offset; - unsigned int slen = sg->length; - - if (unlikely(slen > nbytes)) - slen = nbytes; - - nbytes -= slen; - - while (slen > 0) { - unsigned int len = min(slen, ((unsigned int)(PAGE_SIZE)) - offset); - char *p = crypto_kmap(pg, 0) + offset; - - /* checking the data can fill the block */ - if ((ctx->len + len) <= bs) { - memcpy(ctx->odds + ctx->len, p, len); - ctx->len += len; - slen -= len; - - /* checking the rest of the page */ - if (len + offset >= PAGE_SIZE) { - offset = 0; - pg++; - } else - offset += len; - - crypto_kunmap(p, 0); - crypto_yield(pdesc->flags); - continue; - } - - /* filling odds with new data and encrypting it */ - memcpy(ctx->odds + ctx->len, p, bs - ctx->len); - len -= bs - ctx->len; - p += bs - ctx->len; - - ctx->xor(ctx->prev, ctx->odds, bs); - crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev); - - /* clearing the length */ - ctx->len = 0; - - /* encrypting the rest of data */ - while (len > bs) { - ctx->xor(ctx->prev, p, bs); - crypto_cipher_encrypt_one(tfm, ctx->prev, - ctx->prev); - p += bs; - len -= bs; - } - - /* keeping the surplus of blocksize */ - if (len) { - memcpy(ctx->odds, p, len); - ctx->len = len; - } - crypto_kunmap(p, 0); - crypto_yield(pdesc->flags); - slen -= min(slen, ((unsigned int)(PAGE_SIZE)) - offset); - offset = 0; - pg++; - } - - if (!nbytes) - break; - sg = scatterwalk_sg_next(sg); + int bs = crypto_shash_blocksize(parent); + + /* checking the data can fill the block */ + if ((ctx->len + len) <= bs) { + memcpy(ctx->odds + ctx->len, p, len); + ctx->len += len; + return 0; } - return 0; -} + /* filling odds with new data and encrypting it */ + memcpy(ctx->odds + ctx->len, p, bs - ctx->len); + len -= bs - ctx->len; + p += bs - ctx->len; -static int crypto_xcbc_digest_update(struct hash_desc *pdesc, - struct scatterlist *sg, - unsigned int nbytes) -{ - if (WARN_ON_ONCE(in_irq())) - return -EDEADLK; - return crypto_xcbc_digest_update2(pdesc, sg, nbytes); + ctx->xor(ctx->prev, ctx->odds, bs); + crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev); + + /* clearing the length */ + ctx->len = 0; + + /* encrypting the rest of data */ + while (len > bs) { + ctx->xor(ctx->prev, p, bs); + crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev); + p += bs; + len -= bs; + } + + /* keeping the surplus of blocksize */ + if (len) { + memcpy(ctx->odds, p, len); + ctx->len = len; + } + + return 0; } -static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out) +static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out) { - struct crypto_hash *parent = pdesc->tfm; - struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); + struct crypto_shash *parent = pdesc->tfm; + struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(parent); struct crypto_cipher *tfm = ctx->child; - int bs = crypto_hash_blocksize(parent); + int bs = crypto_shash_blocksize(parent); int err = 0; if (ctx->len == bs) { @@ -248,24 +195,13 @@ static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out) return 0; } -static int crypto_xcbc_digest(struct hash_desc *pdesc, - struct scatterlist *sg, unsigned int nbytes, u8 *out) -{ - if (WARN_ON_ONCE(in_irq())) - return -EDEADLK; - - crypto_xcbc_digest_init(pdesc); - crypto_xcbc_digest_update2(pdesc, sg, nbytes); - return crypto_xcbc_digest_final(pdesc, out); -} - static int xcbc_init_tfm(struct crypto_tfm *tfm) { struct crypto_cipher *cipher; struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); - struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm)); - int bs = crypto_hash_blocksize(__crypto_hash_cast(tfm)); + struct crypto_xcbc_ctx *ctx = crypto_tfm_ctx(tfm); + int bs = crypto_tfm_alg_blocksize(tfm); cipher = crypto_spawn_cipher(spawn); if (IS_ERR(cipher)) @@ -289,70 +225,73 @@ static int xcbc_init_tfm(struct crypto_tfm *tfm) static void xcbc_exit_tfm(struct crypto_tfm *tfm) { - struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(__crypto_hash_cast(tfm)); + struct crypto_xcbc_ctx *ctx = crypto_tfm_ctx(tfm); crypto_free_cipher(ctx->child); } -static struct crypto_instance *xcbc_alloc(struct rtattr **tb) +static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb) { - struct crypto_instance *inst; + struct shash_instance *inst; struct crypto_alg *alg; int err; - err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH); + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH); if (err) - return ERR_PTR(err); + return err; alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, CRYPTO_ALG_TYPE_MASK); if (IS_ERR(alg)) - return ERR_CAST(alg); + return PTR_ERR(alg); switch(alg->cra_blocksize) { case 16: break; default: - inst = ERR_PTR(-EINVAL); goto out_put_alg; } - inst = crypto_alloc_instance("xcbc", alg); + inst = shash_alloc_instance("xcbc", alg); if (IS_ERR(inst)) goto out_put_alg; - inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH; - inst->alg.cra_priority = alg->cra_priority; - inst->alg.cra_blocksize = alg->cra_blocksize; - inst->alg.cra_alignmask = alg->cra_alignmask; - inst->alg.cra_type = &crypto_hash_type; - - inst->alg.cra_hash.digestsize = alg->cra_blocksize; - inst->alg.cra_ctxsize = sizeof(struct crypto_xcbc_ctx) + - ALIGN(inst->alg.cra_blocksize * 3, sizeof(void *)); - inst->alg.cra_init = xcbc_init_tfm; - inst->alg.cra_exit = xcbc_exit_tfm; - - inst->alg.cra_hash.init = crypto_xcbc_digest_init; - inst->alg.cra_hash.update = crypto_xcbc_digest_update; - inst->alg.cra_hash.final = crypto_xcbc_digest_final; - inst->alg.cra_hash.digest = crypto_xcbc_digest; - inst->alg.cra_hash.setkey = crypto_xcbc_digest_setkey; + err = crypto_init_spawn(shash_instance_ctx(inst), alg, + shash_crypto_instance(inst), + CRYPTO_ALG_TYPE_MASK); + if (err) + goto out_free_inst; + + inst->alg.base.cra_priority = alg->cra_priority; + inst->alg.base.cra_blocksize = alg->cra_blocksize; + inst->alg.base.cra_alignmask = alg->cra_alignmask; + + inst->alg.digestsize = alg->cra_blocksize; + inst->alg.base.cra_ctxsize = sizeof(struct crypto_xcbc_ctx) + + ALIGN(alg->cra_blocksize * 3, + sizeof(void *)); + inst->alg.base.cra_init = xcbc_init_tfm; + inst->alg.base.cra_exit = xcbc_exit_tfm; + + inst->alg.init = crypto_xcbc_digest_init; + inst->alg.update = crypto_xcbc_digest_update; + inst->alg.final = crypto_xcbc_digest_final; + inst->alg.setkey = crypto_xcbc_digest_setkey; + + err = shash_register_instance(tmpl, inst); + if (err) { +out_free_inst: + shash_free_instance(shash_crypto_instance(inst)); + } out_put_alg: crypto_mod_put(alg); - return inst; -} - -static void xcbc_free(struct crypto_instance *inst) -{ - crypto_drop_spawn(crypto_instance_ctx(inst)); - kfree(inst); + return err; } static struct crypto_template crypto_xcbc_tmpl = { .name = "xcbc", - .alloc = xcbc_alloc, - .free = xcbc_free, + .create = xcbc_create, + .free = shash_free_instance, .module = THIS_MODULE, }; -- cgit v0.10.2 From 9ef074fa9b525f7fc7a35d0761f3d4ed01fe8252 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 12 Jul 2009 12:50:11 +0800 Subject: crypto: authenc - Remove reference to crypto_hash Now that there are no more legacy hash implementations we can remove the reference to crypto_hash. Signed-off-by: Herbert Xu diff --git a/crypto/authenc.c b/crypto/authenc.c index 5793b64..2e16ce0 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -436,11 +436,7 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) inst->alg.cra_type = &crypto_aead_type; inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize; - inst->alg.cra_aead.maxauthsize = auth->cra_type == &crypto_hash_type ? - auth->cra_hash.digestsize : - auth->cra_type ? - __crypto_shash_alg(auth)->digestsize : - auth->cra_digest.dia_digestsize; + inst->alg.cra_aead.maxauthsize = __crypto_shash_alg(auth)->digestsize; inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx); -- cgit v0.10.2 From 6941c3a0aabb6ad4167827360f384e9daed7dd7f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 12 Jul 2009 13:58:04 +0800 Subject: crypto: hash - Remove legacy hash/digest implementaion This patch removes the implementation of hash and digest now that no algorithms use them anymore. The interface though will remain until the users are converted across. Signed-off-by: Herbert Xu diff --git a/crypto/Makefile b/crypto/Makefile index 673d9f7..3c961b4 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_CRYPTO) += crypto.o -crypto-objs := api.o cipher.o digest.o compress.o +crypto-objs := api.o cipher.o compress.o obj-$(CONFIG_CRYPTO_WORKQUEUE) += crypto_wq.o @@ -22,7 +22,6 @@ obj-$(CONFIG_CRYPTO_BLKCIPHER2) += chainiv.o obj-$(CONFIG_CRYPTO_BLKCIPHER2) += eseqiv.o obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o -crypto_hash-objs := hash.o crypto_hash-objs += ahash.o crypto_hash-objs += shash.o obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o diff --git a/crypto/api.c b/crypto/api.c index ba81221..c8ac18f 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -285,13 +285,6 @@ static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask) switch (crypto_tfm_alg_type(tfm)) { case CRYPTO_ALG_TYPE_CIPHER: return crypto_init_cipher_ops(tfm); - - case CRYPTO_ALG_TYPE_DIGEST: - if ((mask & CRYPTO_ALG_TYPE_HASH_MASK) != - CRYPTO_ALG_TYPE_HASH_MASK) - return crypto_init_digest_ops_async(tfm); - else - return crypto_init_digest_ops(tfm); case CRYPTO_ALG_TYPE_COMPRESS: return crypto_init_compress_ops(tfm); @@ -318,11 +311,7 @@ static void crypto_exit_ops(struct crypto_tfm *tfm) case CRYPTO_ALG_TYPE_CIPHER: crypto_exit_cipher_ops(tfm); break; - - case CRYPTO_ALG_TYPE_DIGEST: - crypto_exit_digest_ops(tfm); - break; - + case CRYPTO_ALG_TYPE_COMPRESS: crypto_exit_compress_ops(tfm); break; @@ -349,11 +338,7 @@ static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) case CRYPTO_ALG_TYPE_CIPHER: len += crypto_cipher_ctxsize(alg); break; - - case CRYPTO_ALG_TYPE_DIGEST: - len += crypto_digest_ctxsize(alg); - break; - + case CRYPTO_ALG_TYPE_COMPRESS: len += crypto_compress_ctxsize(alg); break; diff --git a/crypto/internal.h b/crypto/internal.h index 7efa4d0..030e229 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -60,18 +60,6 @@ static inline void crypto_exit_proc(void) { } #endif -static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg) -{ - unsigned int len = alg->cra_ctxsize; - - if (alg->cra_alignmask) { - len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1); - len += alg->cra_digest.dia_digestsize; - } - - return len; -} - static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg) { return alg->cra_ctxsize; @@ -86,12 +74,9 @@ struct crypto_alg *crypto_mod_get(struct crypto_alg *alg); struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask); struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask); -int crypto_init_digest_ops(struct crypto_tfm *tfm); -int crypto_init_digest_ops_async(struct crypto_tfm *tfm); int crypto_init_cipher_ops(struct crypto_tfm *tfm); int crypto_init_compress_ops(struct crypto_tfm *tfm); -void crypto_exit_digest_ops(struct crypto_tfm *tfm); void crypto_exit_cipher_ops(struct crypto_tfm *tfm); void crypto_exit_compress_ops(struct crypto_tfm *tfm); -- cgit v0.10.2 From 7eddf95ec5440d60f10963f453e27f82f394044e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 12 Jul 2009 21:25:20 +0800 Subject: crypto: shash - Export async functions This patch exports the async functions so that they can be reused by cryptd when it switches over to using shash. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index d8e0f8f..3b1b06b 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -202,9 +202,8 @@ static int shash_async_init(struct ahash_request *req) return crypto_shash_init(desc); } -static int shash_async_update(struct ahash_request *req) +int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc) { - struct shash_desc *desc = ahash_request_ctx(req); struct crypto_hash_walk walk; int nbytes; @@ -214,13 +213,19 @@ static int shash_async_update(struct ahash_request *req) return nbytes; } +EXPORT_SYMBOL_GPL(shash_ahash_update); + +static int shash_async_update(struct ahash_request *req) +{ + return shash_ahash_update(req, ahash_request_ctx(req)); +} static int shash_async_final(struct ahash_request *req) { return crypto_shash_final(ahash_request_ctx(req), req->result); } -static int shash_async_digest(struct ahash_request *req) +int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) { struct scatterlist *sg = req->src; unsigned int offset = sg->offset; @@ -228,34 +233,31 @@ static int shash_async_digest(struct ahash_request *req) int err; if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) { - struct crypto_shash **ctx = - crypto_ahash_ctx(crypto_ahash_reqtfm(req)); - struct shash_desc *desc = ahash_request_ctx(req); void *data; - desc->tfm = *ctx; - desc->flags = req->base.flags; - data = crypto_kmap(sg_page(sg), 0); err = crypto_shash_digest(desc, data + offset, nbytes, req->result); crypto_kunmap(data, 0); crypto_yield(desc->flags); - goto out; - } + } else + err = crypto_shash_init(desc) ?: + shash_ahash_update(req, desc) ?: + crypto_shash_final(desc, req->result); - err = shash_async_init(req); - if (err) - goto out; + return err; +} +EXPORT_SYMBOL_GPL(shash_ahash_digest); - err = shash_async_update(req); - if (err) - goto out; +static int shash_async_digest(struct ahash_request *req) +{ + struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); + struct shash_desc *desc = ahash_request_ctx(req); - err = shash_async_final(req); + desc->tfm = *ctx; + desc->flags = req->base.flags; -out: - return err; + return shash_ahash_digest(req, desc); } static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm) diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 2d1b10f..6e28349 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -63,6 +63,9 @@ int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn, struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask); +int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc); +int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc); + static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm) { return crypto_tfm_ctx(&tfm->base); -- cgit v0.10.2 From 46309d8938122dff2fe59bf163307989cd22ea4a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 12 Jul 2009 21:38:59 +0800 Subject: crypto: cryptd - Use shash algorithms This patch changes cryptd to use shash algorithms instead of the legacy hash interface. Signed-off-by: Herbert Xu diff --git a/crypto/cryptd.c b/crypto/cryptd.c index ae5fa99..ef5720c 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -39,6 +39,11 @@ struct cryptd_instance_ctx { struct cryptd_queue *queue; }; +struct hashd_instance_ctx { + struct crypto_shash_spawn spawn; + struct cryptd_queue *queue; +}; + struct cryptd_blkcipher_ctx { struct crypto_blkcipher *child; }; @@ -48,11 +53,12 @@ struct cryptd_blkcipher_request_ctx { }; struct cryptd_hash_ctx { - struct crypto_hash *child; + struct crypto_shash *child; }; struct cryptd_hash_request_ctx { crypto_completion_t complete; + struct shash_desc desc; }; static void cryptd_queue_worker(struct work_struct *work); @@ -250,13 +256,12 @@ static void cryptd_blkcipher_exit_tfm(struct crypto_tfm *tfm) } static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg, - struct cryptd_queue *queue) + unsigned int tail) { struct crypto_instance *inst; - struct cryptd_instance_ctx *ctx; int err; - inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); + inst = kzalloc(sizeof(*inst) + tail, GFP_KERNEL); if (!inst) { inst = ERR_PTR(-ENOMEM); goto out; @@ -267,14 +272,6 @@ static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg, "cryptd(%s)", alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) goto out_free_inst; - ctx = crypto_instance_ctx(inst); - err = crypto_init_spawn(&ctx->spawn, alg, inst, - CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); - if (err) - goto out_free_inst; - - ctx->queue = queue; - memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); inst->alg.cra_priority = alg->cra_priority + 50; @@ -293,18 +290,28 @@ out_free_inst: static struct crypto_instance *cryptd_alloc_blkcipher( struct rtattr **tb, struct cryptd_queue *queue) { + struct cryptd_instance_ctx *ctx; struct crypto_instance *inst; struct crypto_alg *alg; + int err; alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER, CRYPTO_ALG_TYPE_MASK); if (IS_ERR(alg)) return ERR_CAST(alg); - inst = cryptd_alloc_instance(alg, queue); + inst = cryptd_alloc_instance(alg, sizeof(*ctx)); if (IS_ERR(inst)) goto out_put_alg; + ctx = crypto_instance_ctx(inst); + ctx->queue = queue; + + err = crypto_init_spawn(&ctx->spawn, alg, inst, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + if (err) + goto out_free_inst; + inst->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC; inst->alg.cra_type = &crypto_ablkcipher_type; @@ -326,23 +333,28 @@ static struct crypto_instance *cryptd_alloc_blkcipher( out_put_alg: crypto_mod_put(alg); return inst; + +out_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out_put_alg; } static int cryptd_hash_init_tfm(struct crypto_tfm *tfm) { struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); - struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst); - struct crypto_spawn *spawn = &ictx->spawn; + struct hashd_instance_ctx *ictx = crypto_instance_ctx(inst); + struct crypto_shash_spawn *spawn = &ictx->spawn; struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm); - struct crypto_hash *cipher; + struct crypto_shash *hash; - cipher = crypto_spawn_hash(spawn); - if (IS_ERR(cipher)) - return PTR_ERR(cipher); + hash = crypto_spawn_shash(spawn); + if (IS_ERR(hash)) + return PTR_ERR(hash); - ctx->child = cipher; - tfm->crt_ahash.reqsize = - sizeof(struct cryptd_hash_request_ctx); + ctx->child = hash; + tfm->crt_ahash.reqsize = sizeof(struct cryptd_hash_request_ctx) + + crypto_shash_descsize(hash); return 0; } @@ -350,22 +362,22 @@ static void cryptd_hash_exit_tfm(struct crypto_tfm *tfm) { struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm); - crypto_free_hash(ctx->child); + crypto_free_shash(ctx->child); } static int cryptd_hash_setkey(struct crypto_ahash *parent, const u8 *key, unsigned int keylen) { struct cryptd_hash_ctx *ctx = crypto_ahash_ctx(parent); - struct crypto_hash *child = ctx->child; + struct crypto_shash *child = ctx->child; int err; - crypto_hash_clear_flags(child, CRYPTO_TFM_REQ_MASK); - crypto_hash_set_flags(child, crypto_ahash_get_flags(parent) & - CRYPTO_TFM_REQ_MASK); - err = crypto_hash_setkey(child, key, keylen); - crypto_ahash_set_flags(parent, crypto_hash_get_flags(child) & - CRYPTO_TFM_RES_MASK); + crypto_shash_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_shash_set_flags(child, crypto_ahash_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_shash_setkey(child, key, keylen); + crypto_ahash_set_flags(parent, crypto_shash_get_flags(child) & + CRYPTO_TFM_RES_MASK); return err; } @@ -385,21 +397,19 @@ static int cryptd_hash_enqueue(struct ahash_request *req, static void cryptd_hash_init(struct crypto_async_request *req_async, int err) { - struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); - struct crypto_hash *child = ctx->child; - struct ahash_request *req = ahash_request_cast(req_async); - struct cryptd_hash_request_ctx *rctx; - struct hash_desc desc; - - rctx = ahash_request_ctx(req); + struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); + struct crypto_shash *child = ctx->child; + struct ahash_request *req = ahash_request_cast(req_async); + struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req); + struct shash_desc *desc = &rctx->desc; if (unlikely(err == -EINPROGRESS)) goto out; - desc.tfm = child; - desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; + desc->tfm = child; + desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; - err = crypto_hash_crt(child)->init(&desc); + err = crypto_shash_init(desc); req->base.complete = rctx->complete; @@ -416,23 +426,15 @@ static int cryptd_hash_init_enqueue(struct ahash_request *req) static void cryptd_hash_update(struct crypto_async_request *req_async, int err) { - struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); - struct crypto_hash *child = ctx->child; - struct ahash_request *req = ahash_request_cast(req_async); + struct ahash_request *req = ahash_request_cast(req_async); struct cryptd_hash_request_ctx *rctx; - struct hash_desc desc; rctx = ahash_request_ctx(req); if (unlikely(err == -EINPROGRESS)) goto out; - desc.tfm = child; - desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; - - err = crypto_hash_crt(child)->update(&desc, - req->src, - req->nbytes); + err = shash_ahash_update(req, &rctx->desc); req->base.complete = rctx->complete; @@ -449,21 +451,13 @@ static int cryptd_hash_update_enqueue(struct ahash_request *req) static void cryptd_hash_final(struct crypto_async_request *req_async, int err) { - struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); - struct crypto_hash *child = ctx->child; - struct ahash_request *req = ahash_request_cast(req_async); - struct cryptd_hash_request_ctx *rctx; - struct hash_desc desc; - - rctx = ahash_request_ctx(req); + struct ahash_request *req = ahash_request_cast(req_async); + struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req); if (unlikely(err == -EINPROGRESS)) goto out; - desc.tfm = child; - desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; - - err = crypto_hash_crt(child)->final(&desc, req->result); + err = crypto_shash_final(&rctx->desc, req->result); req->base.complete = rctx->complete; @@ -480,24 +474,19 @@ static int cryptd_hash_final_enqueue(struct ahash_request *req) static void cryptd_hash_digest(struct crypto_async_request *req_async, int err) { - struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); - struct crypto_hash *child = ctx->child; - struct ahash_request *req = ahash_request_cast(req_async); - struct cryptd_hash_request_ctx *rctx; - struct hash_desc desc; - - rctx = ahash_request_ctx(req); + struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); + struct crypto_shash *child = ctx->child; + struct ahash_request *req = ahash_request_cast(req_async); + struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req); + struct shash_desc *desc = &rctx->desc; if (unlikely(err == -EINPROGRESS)) goto out; - desc.tfm = child; - desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; + desc->tfm = child; + desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; - err = crypto_hash_crt(child)->digest(&desc, - req->src, - req->nbytes, - req->result); + err = shash_ahash_digest(req, desc); req->base.complete = rctx->complete; @@ -515,22 +504,32 @@ static int cryptd_hash_digest_enqueue(struct ahash_request *req) static struct crypto_instance *cryptd_alloc_hash( struct rtattr **tb, struct cryptd_queue *queue) { + struct hashd_instance_ctx *ctx; struct crypto_instance *inst; + struct shash_alg *salg; struct crypto_alg *alg; + int err; - alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH, - CRYPTO_ALG_TYPE_HASH_MASK); - if (IS_ERR(alg)) - return ERR_PTR(PTR_ERR(alg)); + salg = shash_attr_alg(tb[1], 0, 0); + if (IS_ERR(salg)) + return ERR_CAST(salg); - inst = cryptd_alloc_instance(alg, queue); + alg = &salg->base; + inst = cryptd_alloc_instance(alg, sizeof(*ctx)); if (IS_ERR(inst)) goto out_put_alg; + ctx = crypto_instance_ctx(inst); + ctx->queue = queue; + + err = crypto_init_shash_spawn(&ctx->spawn, salg, inst); + if (err) + goto out_free_inst; + inst->alg.cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC; inst->alg.cra_type = &crypto_ahash_type; - inst->alg.cra_ahash.digestsize = alg->cra_hash.digestsize; + inst->alg.cra_ahash.digestsize = salg->digestsize; inst->alg.cra_ctxsize = sizeof(struct cryptd_hash_ctx); inst->alg.cra_init = cryptd_hash_init_tfm; @@ -545,6 +544,11 @@ static struct crypto_instance *cryptd_alloc_hash( out_put_alg: crypto_mod_put(alg); return inst; + +out_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out_put_alg; } static struct cryptd_queue queue; -- cgit v0.10.2 From fc00127fb67b2a7d2b66f0f4096a5367b581f045 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 12 Jul 2009 23:05:48 +0800 Subject: crypto: ahash - Add crypto_ahash_set_reqsize This patch adds the helper crypto_ahash_set_reqsize so that implementations do not directly access the crypto_ahash structure. Signed-off-by: Herbert Xu diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 6e28349..5e45818 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -77,6 +77,12 @@ static inline struct ahash_alg *crypto_ahash_alg( return &crypto_ahash_tfm(tfm)->__crt_alg->cra_ahash; } +static inline void crypto_ahash_set_reqsize(struct crypto_ahash *tfm, + unsigned int reqsize) +{ + crypto_ahash_crt(tfm)->reqsize = reqsize; +} + static inline int ahash_enqueue_request(struct crypto_queue *queue, struct ahash_request *request) { -- cgit v0.10.2 From 0d6669e2ba60ce5f5d4def6ab453f03567cc738e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 12 Jul 2009 23:06:33 +0800 Subject: crypto: cryptd - Use crypto_ahash_set_reqsize This patch makes cryptd use crypto_ahash_set_reqsize to avoid accessing crypto_ahash directly. Signed-off-by: Herbert Xu diff --git a/crypto/cryptd.c b/crypto/cryptd.c index ef5720c..6e6722e 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -353,8 +353,9 @@ static int cryptd_hash_init_tfm(struct crypto_tfm *tfm) return PTR_ERR(hash); ctx->child = hash; - tfm->crt_ahash.reqsize = sizeof(struct cryptd_hash_request_ctx) + - crypto_shash_descsize(hash); + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), + sizeof(struct cryptd_hash_request_ctx) + + crypto_shash_descsize(hash)); return 0; } -- cgit v0.10.2 From 6b1679f4a006acb5d76f8df686aa44c63d2555b4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 12 Jul 2009 23:08:28 +0800 Subject: crypto: crypto4xx - Use crypto_ahash_set_reqsize This patch makes crypto4xx use crypto_ahash_set_reqsize to avoid accessing crypto_ahash directly. Signed-off-by: Herbert Xu diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c index 61b6e1b..a33243c 100644 --- a/drivers/crypto/amcc/crypto4xx_alg.c +++ b/drivers/crypto/amcc/crypto4xx_alg.c @@ -208,7 +208,8 @@ static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm, } } - tfm->crt_ahash.reqsize = sizeof(struct crypto4xx_ctx); + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), + sizeof(struct crypto4xx_ctx)); sa = (struct dynamic_sa_ctl *) ctx->sa_in; set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV, SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA, diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 4c0dfb2..cb7be42 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1001,7 +1001,8 @@ static int crypto4xx_alg_init(struct crypto_tfm *tfm) if (alg->cra_type == &crypto_ablkcipher_type) tfm->crt_ablkcipher.reqsize = sizeof(struct crypto4xx_ctx); else if (alg->cra_type == &crypto_ahash_type) - tfm->crt_ahash.reqsize = sizeof(struct crypto4xx_ctx); + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), + sizeof(struct crypto4xx_ctx)); return 0; } -- cgit v0.10.2 From 2ca33da1dea3ba53d1425226a6bac073c5e8568c Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 13 Jul 2009 20:46:25 +0800 Subject: crypto: api - Remove frontend argument from extsize/init_tfm As the extsize and init_tfm functions belong to the frontend the frontend argument is superfluous. Signed-off-by: Herbert Xu diff --git a/crypto/api.c b/crypto/api.c index c8ac18f..798526d 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -457,7 +457,7 @@ void *crypto_create_tfm(struct crypto_alg *alg, int err = -ENOMEM; tfmsize = frontend->tfmsize; - total = tfmsize + sizeof(*tfm) + frontend->extsize(alg, frontend); + total = tfmsize + sizeof(*tfm) + frontend->extsize(alg); mem = kzalloc(total, GFP_KERNEL); if (mem == NULL) @@ -466,7 +466,7 @@ void *crypto_create_tfm(struct crypto_alg *alg, tfm = (struct crypto_tfm *)(mem + tfmsize); tfm->__crt_alg = alg; - err = frontend->init_tfm(tfm, frontend); + err = frontend->init_tfm(tfm); if (err) goto out_free_tfm; diff --git a/crypto/pcompress.c b/crypto/pcompress.c index bcadc03..f7c4a7d7 100644 --- a/crypto/pcompress.c +++ b/crypto/pcompress.c @@ -36,14 +36,12 @@ static int crypto_pcomp_init(struct crypto_tfm *tfm, u32 type, u32 mask) return 0; } -static unsigned int crypto_pcomp_extsize(struct crypto_alg *alg, - const struct crypto_type *frontend) +static unsigned int crypto_pcomp_extsize(struct crypto_alg *alg) { return alg->cra_ctxsize; } -static int crypto_pcomp_init_tfm(struct crypto_tfm *tfm, - const struct crypto_type *frontend) +static int crypto_pcomp_init_tfm(struct crypto_tfm *tfm) { return 0; } diff --git a/crypto/shash.c b/crypto/shash.c index 3b1b06b..7063e14 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -448,8 +448,7 @@ static unsigned int crypto_shash_ctxsize(struct crypto_alg *alg, u32 type, return 0; } -static int crypto_shash_init_tfm(struct crypto_tfm *tfm, - const struct crypto_type *frontend) +static int crypto_shash_init_tfm(struct crypto_tfm *tfm) { struct crypto_shash *hash = __crypto_shash_cast(tfm); @@ -457,8 +456,7 @@ static int crypto_shash_init_tfm(struct crypto_tfm *tfm, return 0; } -static unsigned int crypto_shash_extsize(struct crypto_alg *alg, - const struct crypto_type *frontend) +static unsigned int crypto_shash_extsize(struct crypto_alg *alg) { return alg->cra_ctxsize; } diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 1d15a92..7635fde 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -22,11 +22,9 @@ struct seq_file; struct crypto_type { unsigned int (*ctxsize)(struct crypto_alg *alg, u32 type, u32 mask); - unsigned int (*extsize)(struct crypto_alg *alg, - const struct crypto_type *frontend); + unsigned int (*extsize)(struct crypto_alg *alg); int (*init)(struct crypto_tfm *tfm, u32 type, u32 mask); - int (*init_tfm)(struct crypto_tfm *tfm, - const struct crypto_type *frontend); + int (*init_tfm)(struct crypto_tfm *tfm); void (*show)(struct seq_file *m, struct crypto_alg *alg); struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask); -- cgit v0.10.2 From 88056ec346ccf41f63dbc7080b24b5fd19d1358d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 12:28:26 +0800 Subject: crypto: ahash - Convert to new style algorithms This patch converts crypto_ahash to the new style. The old ahash algorithm type is retained until the existing ahash implementations are also converted. All ahash users will automatically get the new crypto_ahash type. Signed-off-by: Herbert Xu diff --git a/crypto/ahash.c b/crypto/ahash.c index f347637..8385193 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -24,6 +24,12 @@ #include "internal.h" +static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash) +{ + return container_of(crypto_hash_alg_common(hash), struct ahash_alg, + halg); +} + static int hash_walk_next(struct crypto_hash_walk *walk) { unsigned int alignmask = walk->alignmask; @@ -169,30 +175,11 @@ static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, return -ENOSYS; } -int crypto_ahash_import(struct ahash_request *req, const u8 *in) -{ - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct ahash_alg *alg = crypto_ahash_alg(tfm); - - memcpy(ahash_request_ctx(req), in, crypto_ahash_reqsize(tfm)); - - if (alg->reinit) - alg->reinit(req); - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_ahash_import); - -static unsigned int crypto_ahash_ctxsize(struct crypto_alg *alg, u32 type, - u32 mask) -{ - return alg->cra_ctxsize; -} - static int crypto_init_ahash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { - struct ahash_alg *alg = &tfm->__crt_alg->cra_ahash; - struct ahash_tfm *crt = &tfm->crt_ahash; + struct old_ahash_alg *alg = &tfm->__crt_alg->cra_ahash; + struct crypto_ahash *crt = __crypto_ahash_cast(tfm); + struct ahash_alg *nalg = crypto_ahash_alg(crt); if (alg->digestsize > PAGE_SIZE / 8) return -EINVAL; @@ -204,9 +191,42 @@ static int crypto_init_ahash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) crt->setkey = alg->setkey ? ahash_setkey : ahash_nosetkey; crt->digestsize = alg->digestsize; + nalg->setkey = alg->setkey; + nalg->halg.digestsize = alg->digestsize; + return 0; } +static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_ahash *hash = __crypto_ahash_cast(tfm); + struct ahash_alg *alg = crypto_ahash_alg(hash); + struct old_ahash_alg *oalg = crypto_old_ahash_alg(hash); + + if (tfm->__crt_alg->cra_type != &crypto_ahash_type) + return crypto_init_shash_ops_async(tfm); + + if (oalg->init) + return crypto_init_ahash_ops(tfm, 0, 0); + + hash->init = alg->init; + hash->update = alg->update; + hash->final = alg->final; + hash->digest = alg->digest; + hash->setkey = alg->setkey ? ahash_setkey : ahash_nosetkey; + hash->digestsize = alg->halg.digestsize; + + return 0; +} + +static unsigned int crypto_ahash_extsize(struct crypto_alg *alg) +{ + if (alg->cra_type == &crypto_ahash_type) + return alg->cra_ctxsize; + + return sizeof(struct crypto_shash *); +} + static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) __attribute__ ((unused)); static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) @@ -215,17 +235,29 @@ static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? "yes" : "no"); seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); - seq_printf(m, "digestsize : %u\n", alg->cra_ahash.digestsize); + seq_printf(m, "digestsize : %u\n", + __crypto_hash_alg_common(alg)->digestsize); } const struct crypto_type crypto_ahash_type = { - .ctxsize = crypto_ahash_ctxsize, - .init = crypto_init_ahash_ops, + .extsize = crypto_ahash_extsize, + .init_tfm = crypto_ahash_init_tfm, #ifdef CONFIG_PROC_FS .show = crypto_ahash_show, #endif + .maskclear = ~CRYPTO_ALG_TYPE_MASK, + .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, + .type = CRYPTO_ALG_TYPE_AHASH, + .tfmsize = offsetof(struct crypto_ahash, base), }; EXPORT_SYMBOL_GPL(crypto_ahash_type); +struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type, + u32 mask) +{ + return crypto_alloc_tfm(alg_name, &crypto_ahash_type, type, mask); +} +EXPORT_SYMBOL_GPL(crypto_alloc_ahash); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Asynchronous cryptographic hash type"); diff --git a/crypto/shash.c b/crypto/shash.c index 7063e14..615a5f4 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -267,11 +267,11 @@ static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm) crypto_free_shash(*ctx); } -static int crypto_init_shash_ops_async(struct crypto_tfm *tfm) +int crypto_init_shash_ops_async(struct crypto_tfm *tfm) { struct crypto_alg *calg = tfm->__crt_alg; struct shash_alg *alg = __crypto_shash_alg(calg); - struct ahash_tfm *crt = &tfm->crt_ahash; + struct crypto_ahash *crt = __crypto_ahash_cast(tfm); struct crypto_shash **ctx = crypto_tfm_ctx(tfm); struct crypto_shash *shash; @@ -428,8 +428,6 @@ static int crypto_init_shash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) switch (mask & CRYPTO_ALG_TYPE_MASK) { case CRYPTO_ALG_TYPE_HASH_MASK: return crypto_init_shash_ops_compat(tfm); - case CRYPTO_ALG_TYPE_AHASH_MASK: - return crypto_init_shash_ops_async(tfm); } return -EINVAL; @@ -441,8 +439,6 @@ static unsigned int crypto_shash_ctxsize(struct crypto_alg *alg, u32 type, switch (mask & CRYPTO_ALG_TYPE_MASK) { case CRYPTO_ALG_TYPE_HASH_MASK: return sizeof(struct shash_desc *); - case CRYPTO_ALG_TYPE_AHASH_MASK: - return sizeof(struct crypto_shash *); } return 0; diff --git a/include/crypto/hash.h b/include/crypto/hash.h index fcc02d9..262861d 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -15,6 +15,39 @@ #include +struct crypto_ahash; + +struct hash_alg_common { + unsigned int digestsize; + unsigned int statesize; + + struct crypto_alg base; +}; + +struct ahash_request { + struct crypto_async_request base; + + unsigned int nbytes; + struct scatterlist *src; + u8 *result; + + void *__ctx[] CRYPTO_MINALIGN_ATTR; +}; + +struct ahash_alg { + int (*init)(struct ahash_request *req); + int (*update)(struct ahash_request *req); + int (*final)(struct ahash_request *req); + int (*finup)(struct ahash_request *req); + int (*digest)(struct ahash_request *req); + int (*export)(struct ahash_request *req, void *out); + int (*import)(struct ahash_request *req, const void *in); + int (*setkey)(struct crypto_ahash *tfm, const u8 *key, + unsigned int keylen); + + struct hash_alg_common halg; +}; + struct shash_desc { struct crypto_shash *tfm; u32 flags; @@ -37,6 +70,8 @@ struct shash_alg { unsigned int keylen); unsigned int descsize; + + /* These fields must match hash_alg_common. */ unsigned int digestsize; unsigned int statesize; @@ -44,6 +79,18 @@ struct shash_alg { }; struct crypto_ahash { + int (*init)(struct ahash_request *req); + int (*update)(struct ahash_request *req); + int (*final)(struct ahash_request *req); + int (*finup)(struct ahash_request *req); + int (*digest)(struct ahash_request *req); + int (*export)(struct ahash_request *req, void *out); + int (*import)(struct ahash_request *req, const void *in); + int (*setkey)(struct crypto_ahash *tfm, const u8 *key, + unsigned int keylen); + + unsigned int digestsize; + unsigned int reqsize; struct crypto_tfm base; }; @@ -54,19 +101,11 @@ struct crypto_shash { static inline struct crypto_ahash *__crypto_ahash_cast(struct crypto_tfm *tfm) { - return (struct crypto_ahash *)tfm; + return container_of(tfm, struct crypto_ahash, base); } -static inline struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, - u32 type, u32 mask) -{ - type &= ~CRYPTO_ALG_TYPE_MASK; - mask &= ~CRYPTO_ALG_TYPE_MASK; - type |= CRYPTO_ALG_TYPE_AHASH; - mask |= CRYPTO_ALG_TYPE_AHASH_MASK; - - return __crypto_ahash_cast(crypto_alloc_base(alg_name, type, mask)); -} +struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type, + u32 mask); static inline struct crypto_tfm *crypto_ahash_tfm(struct crypto_ahash *tfm) { @@ -75,7 +114,7 @@ static inline struct crypto_tfm *crypto_ahash_tfm(struct crypto_ahash *tfm) static inline void crypto_free_ahash(struct crypto_ahash *tfm) { - crypto_free_tfm(crypto_ahash_tfm(tfm)); + crypto_destroy_tfm(tfm, crypto_ahash_tfm(tfm)); } static inline unsigned int crypto_ahash_alignmask( @@ -84,14 +123,26 @@ static inline unsigned int crypto_ahash_alignmask( return crypto_tfm_alg_alignmask(crypto_ahash_tfm(tfm)); } -static inline struct ahash_tfm *crypto_ahash_crt(struct crypto_ahash *tfm) +static inline struct hash_alg_common *__crypto_hash_alg_common( + struct crypto_alg *alg) { - return &crypto_ahash_tfm(tfm)->crt_ahash; + return container_of(alg, struct hash_alg_common, base); +} + +static inline struct hash_alg_common *crypto_hash_alg_common( + struct crypto_ahash *tfm) +{ + return __crypto_hash_alg_common(crypto_ahash_tfm(tfm)->__crt_alg); } static inline unsigned int crypto_ahash_digestsize(struct crypto_ahash *tfm) { - return crypto_ahash_crt(tfm)->digestsize; + return tfm->digestsize; +} + +static inline unsigned int crypto_ahash_statesize(struct crypto_ahash *tfm) +{ + return crypto_hash_alg_common(tfm)->statesize; } static inline u32 crypto_ahash_get_flags(struct crypto_ahash *tfm) @@ -117,7 +168,7 @@ static inline struct crypto_ahash *crypto_ahash_reqtfm( static inline unsigned int crypto_ahash_reqsize(struct crypto_ahash *tfm) { - return crypto_ahash_crt(tfm)->reqsize; + return tfm->reqsize; } static inline void *ahash_request_ctx(struct ahash_request *req) @@ -128,41 +179,37 @@ static inline void *ahash_request_ctx(struct ahash_request *req) static inline int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) { - struct ahash_tfm *crt = crypto_ahash_crt(tfm); - - return crt->setkey(tfm, key, keylen); + return tfm->setkey(tfm, key, keylen); } static inline int crypto_ahash_digest(struct ahash_request *req) { - struct ahash_tfm *crt = crypto_ahash_crt(crypto_ahash_reqtfm(req)); - return crt->digest(req); + return crypto_ahash_reqtfm(req)->digest(req); } -static inline void crypto_ahash_export(struct ahash_request *req, u8 *out) +static inline int crypto_ahash_export(struct ahash_request *req, void *out) { - memcpy(out, ahash_request_ctx(req), - crypto_ahash_reqsize(crypto_ahash_reqtfm(req))); + return crypto_ahash_reqtfm(req)->export(req, out); } -int crypto_ahash_import(struct ahash_request *req, const u8 *in); +static inline int crypto_ahash_import(struct ahash_request *req, const void *in) +{ + return crypto_ahash_reqtfm(req)->import(req, in); +} static inline int crypto_ahash_init(struct ahash_request *req) { - struct ahash_tfm *crt = crypto_ahash_crt(crypto_ahash_reqtfm(req)); - return crt->init(req); + return crypto_ahash_reqtfm(req)->init(req); } static inline int crypto_ahash_update(struct ahash_request *req) { - struct ahash_tfm *crt = crypto_ahash_crt(crypto_ahash_reqtfm(req)); - return crt->update(req); + return crypto_ahash_reqtfm(req)->update(req); } static inline int crypto_ahash_final(struct ahash_request *req) { - struct ahash_tfm *crt = crypto_ahash_crt(crypto_ahash_reqtfm(req)); - return crt->final(req); + return crypto_ahash_reqtfm(req)->final(req); } static inline void ahash_request_set_tfm(struct ahash_request *req, diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 5e45818..08bdffa 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -51,6 +51,9 @@ int crypto_hash_walk_first_compat(struct hash_desc *hdesc, struct crypto_hash_walk *walk, struct scatterlist *sg, unsigned int len); +int crypto_register_ahash(struct ahash_alg *alg); +int crypto_unregister_ahash(struct ahash_alg *alg); + int crypto_register_shash(struct shash_alg *alg); int crypto_unregister_shash(struct shash_alg *alg); int shash_register_instance(struct crypto_template *tmpl, @@ -66,12 +69,14 @@ struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask); int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc); int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc); +int crypto_init_shash_ops_async(struct crypto_tfm *tfm); + static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm) { - return crypto_tfm_ctx(&tfm->base); + return crypto_tfm_ctx(crypto_ahash_tfm(tfm)); } -static inline struct ahash_alg *crypto_ahash_alg( +static inline struct old_ahash_alg *crypto_old_ahash_alg( struct crypto_ahash *tfm) { return &crypto_ahash_tfm(tfm)->__crt_alg->cra_ahash; @@ -80,7 +85,7 @@ static inline struct ahash_alg *crypto_ahash_alg( static inline void crypto_ahash_set_reqsize(struct crypto_ahash *tfm, unsigned int reqsize) { - crypto_ahash_crt(tfm)->reqsize = reqsize; + tfm->reqsize = reqsize; } static inline int ahash_enqueue_request(struct crypto_queue *queue, diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 274f9c7..9e7e9b6 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -120,6 +120,7 @@ struct crypto_rng; struct crypto_tfm; struct crypto_type; struct aead_givcrypt_request; +struct ahash_request; struct skcipher_givcrypt_request; typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err); @@ -146,16 +147,6 @@ struct ablkcipher_request { void *__ctx[] CRYPTO_MINALIGN_ATTR; }; -struct ahash_request { - struct crypto_async_request base; - - unsigned int nbytes; - struct scatterlist *src; - u8 *result; - - void *__ctx[] CRYPTO_MINALIGN_ATTR; -}; - /** * struct aead_request - AEAD request * @base: Common attributes for async crypto requests @@ -220,7 +211,7 @@ struct ablkcipher_alg { unsigned int ivsize; }; -struct ahash_alg { +struct old_ahash_alg { int (*init)(struct ahash_request *req); int (*reinit)(struct ahash_request *req); int (*update)(struct ahash_request *req); @@ -346,7 +337,7 @@ struct crypto_alg { struct cipher_alg cipher; struct digest_alg digest; struct hash_alg hash; - struct ahash_alg ahash; + struct old_ahash_alg ahash; struct compress_alg compress; struct rng_alg rng; } cra_u; @@ -433,18 +424,6 @@ struct hash_tfm { unsigned int digestsize; }; -struct ahash_tfm { - int (*init)(struct ahash_request *req); - int (*update)(struct ahash_request *req); - int (*final)(struct ahash_request *req); - int (*digest)(struct ahash_request *req); - int (*setkey)(struct crypto_ahash *tfm, const u8 *key, - unsigned int keylen); - - unsigned int digestsize; - unsigned int reqsize; -}; - struct compress_tfm { int (*cot_compress)(struct crypto_tfm *tfm, const u8 *src, unsigned int slen, @@ -465,7 +444,6 @@ struct rng_tfm { #define crt_blkcipher crt_u.blkcipher #define crt_cipher crt_u.cipher #define crt_hash crt_u.hash -#define crt_ahash crt_u.ahash #define crt_compress crt_u.compress #define crt_rng crt_u.rng @@ -479,7 +457,6 @@ struct crypto_tfm { struct blkcipher_tfm blkcipher; struct cipher_tfm cipher; struct hash_tfm hash; - struct ahash_tfm ahash; struct compress_tfm compress; struct rng_tfm rng; } crt_u; -- cgit v0.10.2 From 01c2dece4316dadc0f9fad1ad0b56d493980e492 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 14:06:06 +0800 Subject: crypto: ahash - Add instance/spawn support This patch adds support for creating ahash instances and using ahash as spawns. Signed-off-by: Herbert Xu diff --git a/crypto/ahash.c b/crypto/ahash.c index 8385193..7f599d2 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -259,5 +259,77 @@ struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type, } EXPORT_SYMBOL_GPL(crypto_alloc_ahash); +static int ahash_prepare_alg(struct ahash_alg *alg) +{ + struct crypto_alg *base = &alg->halg.base; + + if (alg->halg.digestsize > PAGE_SIZE / 8 || + alg->halg.statesize > PAGE_SIZE / 8) + return -EINVAL; + + base->cra_type = &crypto_ahash_type; + base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; + base->cra_flags |= CRYPTO_ALG_TYPE_AHASH; + + return 0; +} + +int crypto_register_ahash(struct ahash_alg *alg) +{ + struct crypto_alg *base = &alg->halg.base; + int err; + + err = ahash_prepare_alg(alg); + if (err) + return err; + + return crypto_register_alg(base); +} +EXPORT_SYMBOL_GPL(crypto_register_ahash); + +int crypto_unregister_ahash(struct ahash_alg *alg) +{ + return crypto_unregister_alg(&alg->halg.base); +} +EXPORT_SYMBOL_GPL(crypto_unregister_ahash); + +int ahash_register_instance(struct crypto_template *tmpl, + struct ahash_instance *inst) +{ + int err; + + err = ahash_prepare_alg(&inst->alg); + if (err) + return err; + + return crypto_register_instance(tmpl, ahash_crypto_instance(inst)); +} +EXPORT_SYMBOL_GPL(ahash_register_instance); + +void ahash_free_instance(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(ahash_instance(inst)); +} +EXPORT_SYMBOL_GPL(ahash_free_instance); + +int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn, + struct hash_alg_common *alg, + struct crypto_instance *inst) +{ + return crypto_init_spawn2(&spawn->base, &alg->base, inst, + &crypto_ahash_type); +} +EXPORT_SYMBOL_GPL(crypto_init_ahash_spawn); + +struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask) +{ + struct crypto_alg *alg; + + alg = crypto_attr_alg2(rta, &crypto_ahash_type, type, mask); + return IS_ERR(alg) ? ERR_CAST(alg) : __crypto_hash_alg_common(alg); +} +EXPORT_SYMBOL_GPL(ahash_attr_alg); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Asynchronous cryptographic hash type"); diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 08bdffa..34eda23 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -34,10 +34,18 @@ struct crypto_hash_walk { unsigned int flags; }; +struct ahash_instance { + struct ahash_alg alg; +}; + struct shash_instance { struct shash_alg alg; }; +struct crypto_ahash_spawn { + struct crypto_spawn base; +}; + struct crypto_shash_spawn { struct crypto_spawn base; }; @@ -53,6 +61,15 @@ int crypto_hash_walk_first_compat(struct hash_desc *hdesc, int crypto_register_ahash(struct ahash_alg *alg); int crypto_unregister_ahash(struct ahash_alg *alg); +int ahash_register_instance(struct crypto_template *tmpl, + struct ahash_instance *inst); +void ahash_free_instance(struct crypto_instance *inst); + +int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn, + struct hash_alg_common *alg, + struct crypto_instance *inst); + +struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask); int crypto_register_shash(struct shash_alg *alg); int crypto_unregister_shash(struct shash_alg *alg); @@ -88,6 +105,40 @@ static inline void crypto_ahash_set_reqsize(struct crypto_ahash *tfm, tfm->reqsize = reqsize; } +static inline struct crypto_instance *ahash_crypto_instance( + struct ahash_instance *inst) +{ + return container_of(&inst->alg.halg.base, struct crypto_instance, alg); +} + +static inline struct ahash_instance *ahash_instance( + struct crypto_instance *inst) +{ + return container_of(&inst->alg, struct ahash_instance, alg.halg.base); +} + +static inline void *ahash_instance_ctx(struct ahash_instance *inst) +{ + return crypto_instance_ctx(ahash_crypto_instance(inst)); +} + +static inline unsigned int ahash_instance_headroom(void) +{ + return sizeof(struct ahash_alg) - sizeof(struct crypto_alg); +} + +static inline struct ahash_instance *ahash_alloc_instance( + const char *name, struct crypto_alg *alg) +{ + return crypto_alloc_instance2(name, alg, ahash_instance_headroom()); +} + +static inline struct crypto_ahash *crypto_spawn_ahash( + struct crypto_ahash_spawn *spawn) +{ + return crypto_spawn_tfm2(&spawn->base); +} + static inline int ahash_enqueue_request(struct crypto_queue *queue, struct ahash_request *request) { -- cgit v0.10.2 From 7be380f7201064f704a128b78ac01a62dbd10162 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 16:06:54 +0800 Subject: crypto: tcrypt - Add mask parameter This patch adds a mask parameter to complement the existing type parameter. This is useful when instantiating algorithms that require a mask other than the default, e.g., ahash algorithms. Signed-off-by: Herbert Xu diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index a890a6792..5a375e8 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -47,6 +47,7 @@ static unsigned int sec; static char *alg = NULL; static u32 type; +static u32 mask; static int mode; static char *tvmem[TVMEMSIZE]; @@ -887,9 +888,10 @@ static int do_test(int m) return ret; } -static int do_alg_test(const char *alg, u32 type) +static int do_alg_test(const char *alg, u32 type, u32 mask) { - return crypto_has_alg(alg, type, CRYPTO_ALG_TYPE_MASK) ? 0 : -ENOENT; + return crypto_has_alg(alg, type, mask ?: CRYPTO_ALG_TYPE_MASK) ? + 0 : -ENOENT; } static int __init tcrypt_mod_init(void) @@ -904,7 +906,7 @@ static int __init tcrypt_mod_init(void) } if (alg) - err = do_alg_test(alg, type); + err = do_alg_test(alg, type, mask); else err = do_test(mode); @@ -941,6 +943,7 @@ module_exit(tcrypt_mod_fini); module_param(alg, charp, 0); module_param(type, uint, 0); +module_param(mask, uint, 0); module_param(mode, int, 0); module_param(sec, uint, 0); MODULE_PARM_DESC(sec, "Length in seconds of speed tests " -- cgit v0.10.2 From 52861c7cd711fac97b37ae0f4842a9ad26ecae72 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 18:30:24 +0800 Subject: crypto: hash - Add helpers to free spawns This patch adds the helpers crypto_drop_ahash and crypto_drop_shash so that these spawns can be dropped without ugly casts. Signed-off-by: Herbert Xu diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 34eda23..9d30316 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -69,6 +69,11 @@ int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn, struct hash_alg_common *alg, struct crypto_instance *inst); +static inline void crypto_drop_ahash(struct crypto_ahash_spawn *spawn) +{ + crypto_drop_spawn(&spawn->base); +} + struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask); int crypto_register_shash(struct shash_alg *alg); @@ -81,6 +86,11 @@ int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn, struct shash_alg *alg, struct crypto_instance *inst); +static inline void crypto_drop_shash(struct crypto_shash_spawn *spawn) +{ + crypto_drop_spawn(&spawn->base); +} + struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask); int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc); -- cgit v0.10.2 From 9cd899a32f611eb6328014f1d9e0ba31977812d9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 18:45:45 +0800 Subject: crypto: cryptd - Switch to template create API This patch changes cryptd to use the template->create function instead of alloc in anticipation for the switch to new style ahash algorithms. Signed-off-by: Herbert Xu diff --git a/crypto/cryptd.c b/crypto/cryptd.c index 6e6722e..ad58f51 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -287,8 +287,9 @@ out_free_inst: goto out; } -static struct crypto_instance *cryptd_alloc_blkcipher( - struct rtattr **tb, struct cryptd_queue *queue) +static int cryptd_create_blkcipher(struct crypto_template *tmpl, + struct rtattr **tb, + struct cryptd_queue *queue) { struct cryptd_instance_ctx *ctx; struct crypto_instance *inst; @@ -298,7 +299,7 @@ static struct crypto_instance *cryptd_alloc_blkcipher( alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER, CRYPTO_ALG_TYPE_MASK); if (IS_ERR(alg)) - return ERR_CAST(alg); + return PTR_ERR(alg); inst = cryptd_alloc_instance(alg, sizeof(*ctx)); if (IS_ERR(inst)) @@ -330,14 +331,16 @@ static struct crypto_instance *cryptd_alloc_blkcipher( inst->alg.cra_ablkcipher.encrypt = cryptd_blkcipher_encrypt_enqueue; inst->alg.cra_ablkcipher.decrypt = cryptd_blkcipher_decrypt_enqueue; + err = crypto_register_instance(tmpl, inst); + if (err) { + crypto_drop_spawn(&ctx->spawn); +out_free_inst: + kfree(inst); + } + out_put_alg: crypto_mod_put(alg); - return inst; - -out_free_inst: - kfree(inst); - inst = ERR_PTR(err); - goto out_put_alg; + return err; } static int cryptd_hash_init_tfm(struct crypto_tfm *tfm) @@ -502,8 +505,8 @@ static int cryptd_hash_digest_enqueue(struct ahash_request *req) return cryptd_hash_enqueue(req, cryptd_hash_digest); } -static struct crypto_instance *cryptd_alloc_hash( - struct rtattr **tb, struct cryptd_queue *queue) +static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb, + struct cryptd_queue *queue) { struct hashd_instance_ctx *ctx; struct crypto_instance *inst; @@ -513,7 +516,7 @@ static struct crypto_instance *cryptd_alloc_hash( salg = shash_attr_alg(tb[1], 0, 0); if (IS_ERR(salg)) - return ERR_CAST(salg); + return PTR_ERR(salg); alg = &salg->base; inst = cryptd_alloc_instance(alg, sizeof(*ctx)); @@ -542,34 +545,36 @@ static struct crypto_instance *cryptd_alloc_hash( inst->alg.cra_ahash.setkey = cryptd_hash_setkey; inst->alg.cra_ahash.digest = cryptd_hash_digest_enqueue; + err = crypto_register_instance(tmpl, inst); + if (err) { + crypto_drop_shash(&ctx->spawn); +out_free_inst: + kfree(inst); + } + out_put_alg: crypto_mod_put(alg); - return inst; - -out_free_inst: - kfree(inst); - inst = ERR_PTR(err); - goto out_put_alg; + return err; } static struct cryptd_queue queue; -static struct crypto_instance *cryptd_alloc(struct rtattr **tb) +static int cryptd_create(struct crypto_template *tmpl, struct rtattr **tb) { struct crypto_attr_type *algt; algt = crypto_get_attr_type(tb); if (IS_ERR(algt)) - return ERR_CAST(algt); + return PTR_ERR(algt); switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) { case CRYPTO_ALG_TYPE_BLKCIPHER: - return cryptd_alloc_blkcipher(tb, &queue); + return cryptd_create_blkcipher(tmpl, tb, &queue); case CRYPTO_ALG_TYPE_DIGEST: - return cryptd_alloc_hash(tb, &queue); + return cryptd_create_hash(tmpl, tb, &queue); } - return ERR_PTR(-EINVAL); + return -EINVAL; } static void cryptd_free(struct crypto_instance *inst) @@ -582,7 +587,7 @@ static void cryptd_free(struct crypto_instance *inst) static struct crypto_template cryptd_tmpl = { .name = "cryptd", - .alloc = cryptd_alloc, + .create = cryptd_create, .free = cryptd_free, .module = THIS_MODULE, }; diff --git a/crypto/internal.h b/crypto/internal.h index 030e229..2d22636 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -97,9 +97,6 @@ struct crypto_alg *crypto_find_alg(const char *alg_name, void *crypto_alloc_tfm(const char *alg_name, const struct crypto_type *frontend, u32 type, u32 mask); -int crypto_register_instance(struct crypto_template *tmpl, - struct crypto_instance *inst); - int crypto_register_notifier(struct notifier_block *nb); int crypto_unregister_notifier(struct notifier_block *nb); int crypto_probing_notify(unsigned long val, void *v); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 7635fde..9de6c38 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -114,6 +114,9 @@ int crypto_register_template(struct crypto_template *tmpl); void crypto_unregister_template(struct crypto_template *tmpl); struct crypto_template *crypto_lookup_template(const char *name); +int crypto_register_instance(struct crypto_template *tmpl, + struct crypto_instance *inst); + int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg, struct crypto_instance *inst, u32 mask); int crypto_init_spawn2(struct crypto_spawn *spawn, struct crypto_alg *alg, -- cgit v0.10.2 From 0b535adfb102bac1edb046444172b6b77d99bc92 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 19:11:32 +0800 Subject: crypto: cryptd - Switch to new style ahash This patch changes cryptd to use the new style ahash type. In particular, the instance is enlarged to encapsulate the new ahash_alg structure. Signed-off-by: Herbert Xu diff --git a/crypto/cryptd.c b/crypto/cryptd.c index ad58f51..5dabb7d 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -255,17 +255,18 @@ static void cryptd_blkcipher_exit_tfm(struct crypto_tfm *tfm) crypto_free_blkcipher(ctx->child); } -static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg, - unsigned int tail) +static void *cryptd_alloc_instance(struct crypto_alg *alg, unsigned int head, + unsigned int tail) { + char *p; struct crypto_instance *inst; int err; - inst = kzalloc(sizeof(*inst) + tail, GFP_KERNEL); - if (!inst) { - inst = ERR_PTR(-ENOMEM); - goto out; - } + p = kzalloc(head + sizeof(*inst) + tail, GFP_KERNEL); + if (!p) + return ERR_PTR(-ENOMEM); + + inst = (void *)(p + head); err = -ENAMETOOLONG; if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, @@ -279,11 +280,11 @@ static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg, inst->alg.cra_alignmask = alg->cra_alignmask; out: - return inst; + return p; out_free_inst: - kfree(inst); - inst = ERR_PTR(err); + kfree(p); + p = ERR_PTR(err); goto out; } @@ -301,7 +302,7 @@ static int cryptd_create_blkcipher(struct crypto_template *tmpl, if (IS_ERR(alg)) return PTR_ERR(alg); - inst = cryptd_alloc_instance(alg, sizeof(*ctx)); + inst = cryptd_alloc_instance(alg, 0, sizeof(*ctx)); if (IS_ERR(inst)) goto out_put_alg; @@ -509,7 +510,7 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb, struct cryptd_queue *queue) { struct hashd_instance_ctx *ctx; - struct crypto_instance *inst; + struct ahash_instance *inst; struct shash_alg *salg; struct crypto_alg *alg; int err; @@ -519,33 +520,34 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb, return PTR_ERR(salg); alg = &salg->base; - inst = cryptd_alloc_instance(alg, sizeof(*ctx)); + inst = cryptd_alloc_instance(alg, ahash_instance_headroom(), + sizeof(*ctx)); if (IS_ERR(inst)) goto out_put_alg; - ctx = crypto_instance_ctx(inst); + ctx = ahash_instance_ctx(inst); ctx->queue = queue; - err = crypto_init_shash_spawn(&ctx->spawn, salg, inst); + err = crypto_init_shash_spawn(&ctx->spawn, salg, + ahash_crypto_instance(inst)); if (err) goto out_free_inst; - inst->alg.cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC; - inst->alg.cra_type = &crypto_ahash_type; + inst->alg.halg.base.cra_flags = CRYPTO_ALG_ASYNC; - inst->alg.cra_ahash.digestsize = salg->digestsize; - inst->alg.cra_ctxsize = sizeof(struct cryptd_hash_ctx); + inst->alg.halg.digestsize = salg->digestsize; + inst->alg.halg.base.cra_ctxsize = sizeof(struct cryptd_hash_ctx); - inst->alg.cra_init = cryptd_hash_init_tfm; - inst->alg.cra_exit = cryptd_hash_exit_tfm; + inst->alg.halg.base.cra_init = cryptd_hash_init_tfm; + inst->alg.halg.base.cra_exit = cryptd_hash_exit_tfm; - inst->alg.cra_ahash.init = cryptd_hash_init_enqueue; - inst->alg.cra_ahash.update = cryptd_hash_update_enqueue; - inst->alg.cra_ahash.final = cryptd_hash_final_enqueue; - inst->alg.cra_ahash.setkey = cryptd_hash_setkey; - inst->alg.cra_ahash.digest = cryptd_hash_digest_enqueue; + inst->alg.init = cryptd_hash_init_enqueue; + inst->alg.update = cryptd_hash_update_enqueue; + inst->alg.final = cryptd_hash_final_enqueue; + inst->alg.setkey = cryptd_hash_setkey; + inst->alg.digest = cryptd_hash_digest_enqueue; - err = crypto_register_instance(tmpl, inst); + err = ahash_register_instance(tmpl, inst); if (err) { crypto_drop_shash(&ctx->spawn); out_free_inst: @@ -580,6 +582,14 @@ static int cryptd_create(struct crypto_template *tmpl, struct rtattr **tb) static void cryptd_free(struct crypto_instance *inst) { struct cryptd_instance_ctx *ctx = crypto_instance_ctx(inst); + struct hashd_instance_ctx *hctx = crypto_instance_ctx(inst); + + switch (inst->alg.cra_flags & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_AHASH: + crypto_drop_shash(&hctx->spawn); + kfree(ahash_instance(inst)); + return; + } crypto_drop_spawn(&ctx->spawn); kfree(inst); -- cgit v0.10.2 From 4dc10c0142ce0af8c20ec44dc6928ae63ad4f73a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 20:21:46 +0800 Subject: crypto: crypto4xx - Switch to new style ahash This patch changes crypto4xx to use the new style ahash type. In particular, we now use ahash_alg to define ahash algorithms instead of crypto_alg. This is achieved by introducing a union that encapsulates the new type and the existing crypto_alg structure. They're told apart through a u32 field containing the type value. Signed-off-by: Herbert Xu diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index cb7be42..857e35e 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -31,8 +31,6 @@ #include #include #include -#include -#include #include #include #include "crypto4xx_reg_def.h" @@ -998,11 +996,15 @@ static int crypto4xx_alg_init(struct crypto_tfm *tfm) ctx->sa_out_dma_addr = 0; ctx->sa_len = 0; - if (alg->cra_type == &crypto_ablkcipher_type) + switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { + default: tfm->crt_ablkcipher.reqsize = sizeof(struct crypto4xx_ctx); - else if (alg->cra_type == &crypto_ahash_type) + break; + case CRYPTO_ALG_TYPE_AHASH: crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), sizeof(struct crypto4xx_ctx)); + break; + } return 0; } @@ -1016,7 +1018,8 @@ static void crypto4xx_alg_exit(struct crypto_tfm *tfm) } int crypto4xx_register_alg(struct crypto4xx_device *sec_dev, - struct crypto_alg *crypto_alg, int array_size) + struct crypto4xx_alg_common *crypto_alg, + int array_size) { struct crypto4xx_alg *alg; int i; @@ -1028,13 +1031,18 @@ int crypto4xx_register_alg(struct crypto4xx_device *sec_dev, return -ENOMEM; alg->alg = crypto_alg[i]; - INIT_LIST_HEAD(&alg->alg.cra_list); - if (alg->alg.cra_init == NULL) - alg->alg.cra_init = crypto4xx_alg_init; - if (alg->alg.cra_exit == NULL) - alg->alg.cra_exit = crypto4xx_alg_exit; alg->dev = sec_dev; - rc = crypto_register_alg(&alg->alg); + + switch (alg->alg.type) { + case CRYPTO_ALG_TYPE_AHASH: + rc = crypto_register_ahash(&alg->alg.u.hash); + break; + + default: + rc = crypto_register_alg(&alg->alg.u.cipher); + break; + } + if (rc) { list_del(&alg->entry); kfree(alg); @@ -1052,7 +1060,14 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev) list_for_each_entry_safe(alg, tmp, &sec_dev->alg_list, entry) { list_del(&alg->entry); - crypto_unregister_alg(&alg->alg); + switch (alg->alg.type) { + case CRYPTO_ALG_TYPE_AHASH: + crypto_unregister_ahash(&alg->alg.u.hash); + break; + + default: + crypto_unregister_alg(&alg->alg.u.cipher); + } kfree(alg); } } @@ -1105,17 +1120,18 @@ static irqreturn_t crypto4xx_ce_interrupt_handler(int irq, void *data) /** * Supported Crypto Algorithms */ -struct crypto_alg crypto4xx_alg[] = { +struct crypto4xx_alg_common crypto4xx_alg[] = { /* Crypto AES modes */ - { + { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .u.cipher = { .cra_name = "cbc(aes)", .cra_driver_name = "cbc-aes-ppc4xx", .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, + .cra_init = crypto4xx_alg_init, + .cra_exit = crypto4xx_alg_exit, .cra_module = THIS_MODULE, .cra_u = { .ablkcipher = { @@ -1127,29 +1143,26 @@ struct crypto_alg crypto4xx_alg[] = { .decrypt = crypto4xx_decrypt, } } - }, + }}, /* Hash SHA1 */ - { - .cra_name = "sha1", - .cra_driver_name = "sha1-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_ahash_type, - .cra_init = crypto4xx_sha1_alg_init, - .cra_module = THIS_MODULE, - .cra_u = { - .ahash = { - .digestsize = SHA1_DIGEST_SIZE, - .init = crypto4xx_hash_init, - .update = crypto4xx_hash_update, - .final = crypto4xx_hash_final, - .digest = crypto4xx_hash_digest, - } + { .type = CRYPTO_ALG_TYPE_AHASH, .u.hash = { + .init = crypto4xx_hash_init, + .update = crypto4xx_hash_update, + .final = crypto4xx_hash_final, + .digest = crypto4xx_hash_digest, + .halg.digestsize = SHA1_DIGEST_SIZE, + .halg.base = { + .cra_name = "sha1", + .cra_driver_name = "sha1-ppc4xx", + .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto4xx_ctx), + .cra_init = crypto4xx_sha1_alg_init, + .cra_exit = crypto4xx_alg_exit, + .cra_module = THIS_MODULE, } - }, + }}, }; /** diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index 1ef1034..da9cbe3 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -22,6 +22,8 @@ #ifndef __CRYPTO4XX_CORE_H__ #define __CRYPTO4XX_CORE_H__ +#include + #define PPC460SX_SDR0_SRST 0x201 #define PPC405EX_SDR0_SRST 0x200 #define PPC460EX_SDR0_SRST 0x201 @@ -138,14 +140,31 @@ struct crypto4xx_req_ctx { u16 sa_len; }; +struct crypto4xx_alg_common { + u32 type; + union { + struct crypto_alg cipher; + struct ahash_alg hash; + } u; +}; + struct crypto4xx_alg { struct list_head entry; - struct crypto_alg alg; + struct crypto4xx_alg_common alg; struct crypto4xx_device *dev; }; -#define crypto_alg_to_crypto4xx_alg(x) \ - container_of(x, struct crypto4xx_alg, alg) +static inline struct crypto4xx_alg *crypto_alg_to_crypto4xx_alg( + struct crypto_alg *x) +{ + switch (x->cra_flags & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_AHASH: + return container_of(__crypto_ahash_alg(x), + struct crypto4xx_alg, alg.u.hash); + } + + return container_of(x, struct crypto4xx_alg, alg.u.cipher); +} extern int crypto4xx_alloc_sa(struct crypto4xx_ctx *ctx, u32 size); extern void crypto4xx_free_sa(struct crypto4xx_ctx *ctx); diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 9d30316..e3a8251 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -103,6 +103,12 @@ static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm) return crypto_tfm_ctx(crypto_ahash_tfm(tfm)); } +static inline struct ahash_alg *__crypto_ahash_alg(struct crypto_alg *alg) +{ + return container_of(__crypto_hash_alg_common(alg), struct ahash_alg, + halg); +} + static inline struct old_ahash_alg *crypto_old_ahash_alg( struct crypto_ahash *tfm) { -- cgit v0.10.2 From 500b3e3c3dc8e4845b77ae81e5b7b085ab183ce6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 20:29:57 +0800 Subject: crypto: ahash - Remove old_ahash_alg Now that all ahash implementations have been converted to the new ahash type, we can remove old_ahash_alg and its associated support. Signed-off-by: Herbert Xu diff --git a/crypto/ahash.c b/crypto/ahash.c index 7f599d2..cc824ef2 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -175,46 +175,19 @@ static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, return -ENOSYS; } -static int crypto_init_ahash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) -{ - struct old_ahash_alg *alg = &tfm->__crt_alg->cra_ahash; - struct crypto_ahash *crt = __crypto_ahash_cast(tfm); - struct ahash_alg *nalg = crypto_ahash_alg(crt); - - if (alg->digestsize > PAGE_SIZE / 8) - return -EINVAL; - - crt->init = alg->init; - crt->update = alg->update; - crt->final = alg->final; - crt->digest = alg->digest; - crt->setkey = alg->setkey ? ahash_setkey : ahash_nosetkey; - crt->digestsize = alg->digestsize; - - nalg->setkey = alg->setkey; - nalg->halg.digestsize = alg->digestsize; - - return 0; -} - static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) { struct crypto_ahash *hash = __crypto_ahash_cast(tfm); struct ahash_alg *alg = crypto_ahash_alg(hash); - struct old_ahash_alg *oalg = crypto_old_ahash_alg(hash); if (tfm->__crt_alg->cra_type != &crypto_ahash_type) return crypto_init_shash_ops_async(tfm); - if (oalg->init) - return crypto_init_ahash_ops(tfm, 0, 0); - hash->init = alg->init; hash->update = alg->update; hash->final = alg->final; hash->digest = alg->digest; hash->setkey = alg->setkey ? ahash_setkey : ahash_nosetkey; - hash->digestsize = alg->halg.digestsize; return 0; } diff --git a/crypto/shash.c b/crypto/shash.c index 615a5f4..fd92c03 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -270,7 +270,6 @@ static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm) int crypto_init_shash_ops_async(struct crypto_tfm *tfm) { struct crypto_alg *calg = tfm->__crt_alg; - struct shash_alg *alg = __crypto_shash_alg(calg); struct crypto_ahash *crt = __crypto_ahash_cast(tfm); struct crypto_shash **ctx = crypto_tfm_ctx(tfm); struct crypto_shash *shash; @@ -293,7 +292,6 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm) crt->digest = shash_async_digest; crt->setkey = shash_async_setkey; - crt->digestsize = alg->digestsize; crt->reqsize = sizeof(struct shash_desc) + crypto_shash_descsize(shash); return 0; diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 262861d..45c2bdd 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -89,7 +89,6 @@ struct crypto_ahash { int (*setkey)(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen); - unsigned int digestsize; unsigned int reqsize; struct crypto_tfm base; }; @@ -137,7 +136,7 @@ static inline struct hash_alg_common *crypto_hash_alg_common( static inline unsigned int crypto_ahash_digestsize(struct crypto_ahash *tfm) { - return tfm->digestsize; + return crypto_hash_alg_common(tfm)->digestsize; } static inline unsigned int crypto_ahash_statesize(struct crypto_ahash *tfm) diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index e3a8251..179dd8f 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -109,12 +109,6 @@ static inline struct ahash_alg *__crypto_ahash_alg(struct crypto_alg *alg) halg); } -static inline struct old_ahash_alg *crypto_old_ahash_alg( - struct crypto_ahash *tfm) -{ - return &crypto_ahash_tfm(tfm)->__crt_alg->cra_ahash; -} - static inline void crypto_ahash_set_reqsize(struct crypto_ahash *tfm, unsigned int reqsize) { diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 9e7e9b6..fd92988 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -115,12 +115,10 @@ struct crypto_async_request; struct crypto_aead; struct crypto_blkcipher; struct crypto_hash; -struct crypto_ahash; struct crypto_rng; struct crypto_tfm; struct crypto_type; struct aead_givcrypt_request; -struct ahash_request; struct skcipher_givcrypt_request; typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err); @@ -211,18 +209,6 @@ struct ablkcipher_alg { unsigned int ivsize; }; -struct old_ahash_alg { - int (*init)(struct ahash_request *req); - int (*reinit)(struct ahash_request *req); - int (*update)(struct ahash_request *req); - int (*final)(struct ahash_request *req); - int (*digest)(struct ahash_request *req); - int (*setkey)(struct crypto_ahash *tfm, const u8 *key, - unsigned int keylen); - - unsigned int digestsize; -}; - struct aead_alg { int (*setkey)(struct crypto_aead *tfm, const u8 *key, unsigned int keylen); @@ -309,7 +295,6 @@ struct rng_alg { #define cra_cipher cra_u.cipher #define cra_digest cra_u.digest #define cra_hash cra_u.hash -#define cra_ahash cra_u.ahash #define cra_compress cra_u.compress #define cra_rng cra_u.rng @@ -337,7 +322,6 @@ struct crypto_alg { struct cipher_alg cipher; struct digest_alg digest; struct hash_alg hash; - struct old_ahash_alg ahash; struct compress_alg compress; struct rng_alg rng; } cra_u; -- cgit v0.10.2 From 8045a4c293d36c61656a20d581b11f7f0cd7acd5 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 7 Jul 2009 19:30:25 +0200 Subject: x86/oprofile: Fix cast of counter value When casting the counter value to a 64 bit value in 32 bit mode, sign extension may lead to broken counter values. This patch fixes this by casting to (u64) instead of (s64). Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index e95268e..7ca8306 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -111,7 +111,7 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, if (counter_config[i].enabled && msrs->counters[i].addr) { reset_value[i] = counter_config[i].count; wrmsrl(msrs->counters[i].addr, - -(s64)counter_config[i].count); + -(u64)counter_config[i].count); rdmsrl(msrs->controls[i].addr, val); val &= model->reserved; val |= op_x86_get_ctrl(model, &counter_config[i]); @@ -237,7 +237,7 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, if (val & OP_CTR_OVERFLOW) continue; oprofile_add_sample(regs, i); - wrmsrl(msrs->counters[i].addr, -(s64)reset_value[i]); + wrmsrl(msrs->counters[i].addr, -(u64)reset_value[i]); } op_amd_handle_ibs(regs, msrs); diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index f01e53b..9db9e36 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -580,7 +580,7 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); wrmsrl(p4_counters[VIRT_CTR(stag, i)].counter_address, - -(s64)counter_config[i].count); + -(u64)counter_config[i].count); } else { reset_value[i] = 0; } @@ -625,11 +625,11 @@ static int p4_check_ctrs(struct pt_regs * const regs, if (CCCR_OVF_P(low) || !(ctr & OP_CTR_OVERFLOW)) { oprofile_add_sample(regs, i); wrmsrl(p4_counters[real].counter_address, - -(s64)reset_value[i]); + -(u64)reset_value[i]); CCCR_CLEAR_OVF(low); wrmsr(p4_counters[real].cccr_address, low, high); wrmsrl(p4_counters[real].counter_address, - -(s64)reset_value[i]); + -(u64)reset_value[i]); } } -- cgit v0.10.2 From 8c32c516eb1c1f9c14d25478442137c698788975 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 21:35:36 +0800 Subject: crypto: hash - Zap unaligned buffers Some unaligned buffers on the stack weren't zapped properly which may cause secret data to be leaked. This patch fixes them by doing a zero memset. It is also possible for us to place random kernel stack contents in the digest buffer if a digest operation fails. This is fixed by only copying if the operation succeeded. Signed-off-by: Herbert Xu diff --git a/crypto/ahash.c b/crypto/ahash.c index cc824ef2..1576f95 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -152,8 +152,7 @@ static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); memcpy(alignbuffer, key, keylen); ret = ahash->setkey(tfm, alignbuffer, keylen); - memset(alignbuffer, 0, keylen); - kfree(buffer); + kzfree(buffer); return ret; } diff --git a/crypto/shash.c b/crypto/shash.c index fd92c03..e543283 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -45,8 +45,7 @@ static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key, alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); memcpy(alignbuffer, key, keylen); err = shash->setkey(tfm, alignbuffer, keylen); - memset(alignbuffer, 0, keylen); - kfree(buffer); + kzfree(buffer); return err; } @@ -79,13 +78,16 @@ static int shash_update_unaligned(struct shash_desc *desc, const u8 *data, ((unsigned long)data & alignmask); u8 buf[shash_align_buffer_size(unaligned_len, alignmask)] __attribute__ ((aligned)); + int err; if (unaligned_len > len) unaligned_len = len; memcpy(buf, data, unaligned_len); + err = shash->update(desc, buf, unaligned_len); + memset(buf, 0, unaligned_len); - return shash->update(desc, buf, unaligned_len) ?: + return err ?: shash->update(desc, data + unaligned_len, len - unaligned_len); } @@ -114,7 +116,13 @@ static int shash_final_unaligned(struct shash_desc *desc, u8 *out) int err; err = shash->final(desc, buf); + if (err) + goto out; + memcpy(out, buf, ds); + +out: + memset(buf, 0, ds); return err; } -- cgit v0.10.2 From 0e2d3a126338ebb213c8e32d8d1d8936d8e62d43 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 21:43:56 +0800 Subject: crypto: shash - Fix alignment in unaligned operations When we encounter an unaligned pointer we are supposed to copy it to a temporary aligned location. However the temporary buffer isn't aligned properly. This patch fixes that. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index e543283..171c8f0 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -76,8 +76,9 @@ static int shash_update_unaligned(struct shash_desc *desc, const u8 *data, unsigned long alignmask = crypto_shash_alignmask(tfm); unsigned int unaligned_len = alignmask + 1 - ((unsigned long)data & alignmask); - u8 buf[shash_align_buffer_size(unaligned_len, alignmask)] + u8 ubuf[shash_align_buffer_size(unaligned_len, alignmask)] __attribute__ ((aligned)); + u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1); int err; if (unaligned_len > len) @@ -111,8 +112,9 @@ static int shash_final_unaligned(struct shash_desc *desc, u8 *out) unsigned long alignmask = crypto_shash_alignmask(tfm); struct shash_alg *shash = crypto_shash_alg(tfm); unsigned int ds = crypto_shash_digestsize(tfm); - u8 buf[shash_align_buffer_size(ds, alignmask)] + u8 ubuf[shash_align_buffer_size(ds, alignmask)] __attribute__ ((aligned)); + u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1); int err; err = shash->final(desc, buf); -- cgit v0.10.2 From 093900c2b964da73daf234374225b5ce5d49f941 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 21:48:35 +0800 Subject: crypto: ahash - Use GFP_KERNEL in unaligned setkey We currently use GFP_ATOMIC in the unaligned setkey function to allocate the temporary aligned buffer. Since setkey must be called in a sleepable context, we can use GFP_KERNEL instead. Signed-off-by: Herbert Xu diff --git a/crypto/ahash.c b/crypto/ahash.c index 1576f95..a196055 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -145,7 +145,7 @@ static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, unsigned long absize; absize = keylen + alignmask; - buffer = kmalloc(absize, GFP_ATOMIC); + buffer = kmalloc(absize, GFP_KERNEL); if (!buffer) return -ENOMEM; -- cgit v0.10.2 From 44ab9a6b0e909145d42615493952fe986b1ce5c2 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 18:33:02 +0200 Subject: x86/oprofile: Rework and simplify nmi_cpu_setup() This patch removes the function nmi_save_registers(). Per-cpu code is now executed only in the function nmi_cpu_setup(). Also, it renames the per-cpu function nmi_restore_registers() to nmi_cpu_restore_registers(). Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 93df76d..25da1e17 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -87,13 +87,6 @@ static void nmi_cpu_save_registers(struct op_msrs *msrs) } } -static void nmi_save_registers(void *dummy) -{ - int cpu = smp_processor_id(); - struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); - nmi_cpu_save_registers(msrs); -} - static void free_msrs(void) { int i; @@ -137,6 +130,7 @@ static void nmi_cpu_setup(void *dummy) { int cpu = smp_processor_id(); struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); + nmi_cpu_save_registers(msrs); spin_lock(&oprofilefs_lock); model->setup_ctrs(model, msrs); spin_unlock(&oprofilefs_lock); @@ -182,13 +176,12 @@ static int nmi_setup(void) } } - on_each_cpu(nmi_save_registers, NULL, 1); on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; return 0; } -static void nmi_restore_registers(struct op_msrs *msrs) +static void nmi_cpu_restore_registers(struct op_msrs *msrs) { struct op_msr *counters = msrs->counters; struct op_msr *controls = msrs->controls; @@ -220,7 +213,7 @@ static void nmi_cpu_shutdown(void *dummy) apic_write(APIC_LVTERR, v | APIC_LVT_MASKED); apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu)); apic_write(APIC_LVTERR, v); - nmi_restore_registers(msrs); + nmi_cpu_restore_registers(msrs); } static void nmi_shutdown(void) -- cgit v0.10.2 From 6e63ea4b0b14ff5fb8a3ca704fcda7d28b95f079 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 7 Jul 2009 19:25:39 +0200 Subject: x86/oprofile: Whitespaces changes only This patch fixes whitespace changes of code that will be touched in follow-on patches. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 25da1e17..fca8dc94 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -516,12 +516,12 @@ int __init op_nmi_init(struct oprofile_operations *ops) register_cpu_notifier(&oprofile_cpu_nb); #endif /* default values, can be overwritten by model */ - ops->create_files = nmi_create_files; - ops->setup = nmi_setup; - ops->shutdown = nmi_shutdown; - ops->start = nmi_start; - ops->stop = nmi_stop; - ops->cpu_type = cpu_type; + ops->create_files = nmi_create_files; + ops->setup = nmi_setup; + ops->shutdown = nmi_shutdown; + ops->start = nmi_start; + ops->stop = nmi_stop; + ops->cpu_type = cpu_type; if (model->init) ret = model->init(ops); diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 7ca8306..f676f88 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -91,7 +91,7 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, int i; /* clear all counters */ - for (i = 0 ; i < NUM_CONTROLS; ++i) { + for (i = 0; i < NUM_CONTROLS; ++i) { if (unlikely(!msrs->controls[i].addr)) continue; rdmsrl(msrs->controls[i].addr, val); @@ -229,7 +229,7 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, u64 val; int i; - for (i = 0 ; i < NUM_COUNTERS; ++i) { + for (i = 0; i < NUM_COUNTERS; ++i) { if (!reset_value[i]) continue; rdmsrl(msrs->counters[i].addr, val); @@ -250,7 +250,7 @@ static void op_amd_start(struct op_msrs const * const msrs) { u64 val; int i; - for (i = 0 ; i < NUM_COUNTERS ; ++i) { + for (i = 0; i < NUM_COUNTERS; ++i) { if (reset_value[i]) { rdmsrl(msrs->controls[i].addr, val); val |= ARCH_PERFMON_EVENTSEL0_ENABLE; @@ -270,7 +270,7 @@ static void op_amd_stop(struct op_msrs const * const msrs) * Subtle: stop on all counters to avoid race with setting our * pm callback */ - for (i = 0 ; i < NUM_COUNTERS ; ++i) { + for (i = 0; i < NUM_COUNTERS; ++i) { if (!reset_value[i]) continue; rdmsrl(msrs->controls[i].addr, val); @@ -285,11 +285,11 @@ static void op_amd_shutdown(struct op_msrs const * const msrs) { int i; - for (i = 0 ; i < NUM_COUNTERS ; ++i) { + for (i = 0; i < NUM_COUNTERS; ++i) { if (msrs->counters[i].addr) release_perfctr_nmi(MSR_K7_PERFCTR0 + i); } - for (i = 0 ; i < NUM_CONTROLS ; ++i) { + for (i = 0; i < NUM_CONTROLS; ++i) { if (msrs->controls[i].addr) release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); } diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 9db9e36..5921b7f 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -558,7 +558,7 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, } /* clear the cccrs we will use */ - for (i = 0 ; i < num_counters ; i++) { + for (i = 0; i < num_counters; i++) { if (unlikely(!msrs->controls[i].addr)) continue; rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); @@ -575,7 +575,7 @@ static void p4_setup_ctrs(struct op_x86_model_spec const *model, } /* setup all counters */ - for (i = 0 ; i < num_counters ; ++i) { + for (i = 0; i < num_counters; ++i) { if (counter_config[i].enabled && msrs->controls[i].addr) { reset_value[i] = counter_config[i].count; pmc_setup_one_p4_counter(i); @@ -678,7 +678,7 @@ static void p4_shutdown(struct op_msrs const * const msrs) { int i; - for (i = 0 ; i < num_counters ; ++i) { + for (i = 0; i < num_counters; ++i) { if (msrs->counters[i].addr) release_perfctr_nmi(msrs->counters[i].addr); } @@ -687,7 +687,7 @@ static void p4_shutdown(struct op_msrs const * const msrs) * conjunction with the counter registers (hence the starting offset). * This saves a few bits. */ - for (i = num_counters ; i < num_controls ; ++i) { + for (i = num_counters; i < num_controls; ++i) { if (msrs->controls[i].addr) release_evntsel_nmi(msrs->controls[i].addr); } diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index cd72d5c..570d717 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -81,7 +81,7 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, } /* clear all counters */ - for (i = 0 ; i < num_counters; ++i) { + for (i = 0; i < num_counters; ++i) { if (unlikely(!msrs->controls[i].addr)) continue; rdmsrl(msrs->controls[i].addr, val); @@ -125,7 +125,7 @@ static int ppro_check_ctrs(struct pt_regs * const regs, if (unlikely(!reset_value)) goto out; - for (i = 0 ; i < num_counters; ++i) { + for (i = 0; i < num_counters; ++i) { if (!reset_value[i]) continue; rdmsrl(msrs->counters[i].addr, val); @@ -188,11 +188,11 @@ static void ppro_shutdown(struct op_msrs const * const msrs) { int i; - for (i = 0 ; i < num_counters ; ++i) { + for (i = 0; i < num_counters; ++i) { if (msrs->counters[i].addr) release_perfctr_nmi(MSR_P6_PERFCTR0 + i); } - for (i = 0 ; i < num_counters ; ++i) { + for (i = 0; i < num_counters; ++i) { if (msrs->controls[i].addr) release_evntsel_nmi(MSR_P6_EVNTSEL0 + i); } -- cgit v0.10.2 From 18d02bc32c0b35726b2a6a3699a0c44e5e8f6c94 Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Tue, 14 Jul 2009 10:01:39 -0400 Subject: ASoC: Blackfin AC97: fix resume handling There is no need to manually start playback/capture ourselves as the PCM driver will handle things for us. Signed-off-by: Cliff Cai Signed-off-by: Mike Frysinger Signed-off-by: Mark Brown diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index b1ed423..2758b90 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -277,28 +277,24 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai) if (!dai->active) return 0; - ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); + ret = sport_set_multichannel(sport, 16, 0x1F, 1); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; } - ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1)); + ret = sport_config_rx(sport, IRFS, 0xF, 0, (16*16-1)); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; } - ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1)); + ret = sport_config_tx(sport, ITFS, 0xF, 0, (16*16-1)); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; } - if (dai->capture.active) - sport_rx_start(sport); - if (dai->playback.active) - sport_tx_start(sport); return 0; } -- cgit v0.10.2 From 82d76f4d9fbf7d951d63e7056fd9911ada507bd1 Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Tue, 14 Jul 2009 10:01:40 -0400 Subject: ASoC: Blackfin I2S: fix resume handling There is no need to manually start playback/capture ourselves as the PCM driver will handle things for us. Signed-off-by: Cliff Cai Signed-off-by: Mike Frysinger Signed-off-by: Mark Brown diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index af06904..876abad 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -259,22 +259,18 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai) if (!dai->active) return 0; - ret = sport_config_rx(sport_handle, RFSR | RCKFE, RSFSE|0x1f, 0, 0); + ret = sport_config_rx(sport, RFSR | RCKFE, RSFSE|0x1f, 0, 0); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; } - ret = sport_config_tx(sport_handle, TFSR | TCKFE, TSFSE|0x1f, 0, 0); + ret = sport_config_tx(sport, TFSR | TCKFE, TSFSE|0x1f, 0, 0); if (ret) { pr_err("SPORT is busy!\n"); return -EBUSY; } - if (dai->capture.active) - sport_rx_start(sport); - if (dai->playback.active) - sport_tx_start(sport); return 0; } -- cgit v0.10.2 From 6b2b171a774af256082635b53ac387b1613b7b4c Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 02:53:50 -0700 Subject: x86/acpi: acpi_parse_madt_ioapic_entries: remove redundant braces We don't put braces around a single statement. Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 6b8ca3a..ce31c1a 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1179,9 +1179,8 @@ static int __init acpi_parse_madt_ioapic_entries(void) * If MPS is present, it will handle them, * otherwise the system will stay in PIC mode */ - if (acpi_disabled || acpi_noirq) { + if (acpi_disabled || acpi_noirq) return -ENODEV; - } if (!cpu_has_apic) return -ENODEV; -- cgit v0.10.2 From 2f210deba9887dd9143b63b217506f1ac152e91c Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 02:55:22 -0700 Subject: x86/ioapic.c: ioapic_modify_irq is too large to inline If ioapic_modify_irq() is marked inline, it gets inlined several times. Un-inlining it saves around 200 bytes in .text for me. Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 90b5e6e..82271eb 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -556,9 +556,9 @@ static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node, add_pin_to_irq_node(cfg, node, newapic, newpin); } -static inline void io_apic_modify_irq(struct irq_cfg *cfg, - int mask_and, int mask_or, - void (*final)(struct irq_pin_list *entry)) +static void io_apic_modify_irq(struct irq_cfg *cfg, + int mask_and, int mask_or, + void (*final)(struct irq_pin_list *entry)) { int pin; struct irq_pin_list *entry; -- cgit v0.10.2 From 890aeacf64c55a7ada7054a140d249ab13899f2d Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 02:57:43 -0700 Subject: x86/ioapic.c: unify __mask_IO_APIC_irq() The main difference between 32 and 64-bit __mask_IO_APIC_irq() does a readback from the I/O APIC to synchronize it. If there's a hardware requirement to do a readback sync after updating an APIC register, then it will be a hardware requrement regardless of whether the kernel is compiled 32 or 64-bit. Unify __mask_IO_APIC_irq() using the 64-bit version which always syncs with io_apic_sync(). Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 82271eb..f8aa546 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -580,7 +580,6 @@ static void __unmask_IO_APIC_irq(struct irq_cfg *cfg) io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, 0, NULL); } -#ifdef CONFIG_X86_64 static void io_apic_sync(struct irq_pin_list *entry) { /* @@ -596,12 +595,8 @@ static void __mask_IO_APIC_irq(struct irq_cfg *cfg) { io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync); } -#else /* CONFIG_X86_32 */ -static void __mask_IO_APIC_irq(struct irq_cfg *cfg) -{ - io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, NULL); -} +#ifdef CONFIG_X86_32 static void __mask_and_edge_IO_APIC_irq(struct irq_cfg *cfg) { io_apic_modify_irq(cfg, ~IO_APIC_REDIR_LEVEL_TRIGGER, -- cgit v0.10.2 From 916a0fe739f151664f7f07b42543ae6fd4caec49 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 03:00:22 -0700 Subject: x86/ioapic.c: remove #ifdef for 82093AA workaround While no 64-bit hardware will have a version 0x11 I/O APIC which needs the level/edge bug workaround, that's not a particular reason to use CONFIG_X86_32 to #ifdef the code out. Most 32-bit machines will no longer need the workaround either, so the test to see whether it is necessary should be more fine-grained than "32-bit=yes, 64-bit=no". (Also fix formatting of block comment.) Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index f8aa546..1a34144 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -596,7 +596,6 @@ static void __mask_IO_APIC_irq(struct irq_cfg *cfg) io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync); } -#ifdef CONFIG_X86_32 static void __mask_and_edge_IO_APIC_irq(struct irq_cfg *cfg) { io_apic_modify_irq(cfg, ~IO_APIC_REDIR_LEVEL_TRIGGER, @@ -608,7 +607,6 @@ static void __unmask_and_level_IO_APIC_irq(struct irq_cfg *cfg) io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, IO_APIC_REDIR_LEVEL_TRIGGER, NULL); } -#endif /* CONFIG_X86_32 */ static void mask_IO_APIC_irq_desc(struct irq_desc *desc) { @@ -2510,11 +2508,8 @@ atomic_t irq_mis_count; static void ack_apic_level(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); - -#ifdef CONFIG_X86_32 unsigned long v; int i; -#endif struct irq_cfg *cfg; int do_unmask_irq = 0; @@ -2527,31 +2522,28 @@ static void ack_apic_level(unsigned int irq) } #endif -#ifdef CONFIG_X86_32 /* - * It appears there is an erratum which affects at least version 0x11 - * of I/O APIC (that's the 82093AA and cores integrated into various - * chipsets). Under certain conditions a level-triggered interrupt is - * erroneously delivered as edge-triggered one but the respective IRR - * bit gets set nevertheless. As a result the I/O unit expects an EOI - * message but it will never arrive and further interrupts are blocked - * from the source. The exact reason is so far unknown, but the - * phenomenon was observed when two consecutive interrupt requests - * from a given source get delivered to the same CPU and the source is - * temporarily disabled in between. - * - * A workaround is to simulate an EOI message manually. We achieve it - * by setting the trigger mode to edge and then to level when the edge - * trigger mode gets detected in the TMR of a local APIC for a - * level-triggered interrupt. We mask the source for the time of the - * operation to prevent an edge-triggered interrupt escaping meanwhile. - * The idea is from Manfred Spraul. --macro - */ + * It appears there is an erratum which affects at least version 0x11 + * of I/O APIC (that's the 82093AA and cores integrated into various + * chipsets). Under certain conditions a level-triggered interrupt is + * erroneously delivered as edge-triggered one but the respective IRR + * bit gets set nevertheless. As a result the I/O unit expects an EOI + * message but it will never arrive and further interrupts are blocked + * from the source. The exact reason is so far unknown, but the + * phenomenon was observed when two consecutive interrupt requests + * from a given source get delivered to the same CPU and the source is + * temporarily disabled in between. + * + * A workaround is to simulate an EOI message manually. We achieve it + * by setting the trigger mode to edge and then to level when the edge + * trigger mode gets detected in the TMR of a local APIC for a + * level-triggered interrupt. We mask the source for the time of the + * operation to prevent an edge-triggered interrupt escaping meanwhile. + * The idea is from Manfred Spraul. --macro + */ cfg = desc->chip_data; i = cfg->vector; - v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); -#endif /* * We must acknowledge the irq before we move it or the acknowledge will @@ -2593,7 +2585,7 @@ static void ack_apic_level(unsigned int irq) unmask_IO_APIC_irq_desc(desc); } -#ifdef CONFIG_X86_32 + /* Tail end of version 0x11 I/O APIC bug workaround */ if (!(v & (1 << (i & 0x1f)))) { atomic_inc(&irq_mis_count); spin_lock(&ioapic_lock); @@ -2601,7 +2593,6 @@ static void ack_apic_level(unsigned int irq) __unmask_and_level_IO_APIC_irq(cfg); spin_unlock(&ioapic_lock); } -#endif } #ifdef CONFIG_INTR_REMAP -- cgit v0.10.2 From 83c21bedf63ce92a2dd82ae2c7a96179b0aa4372 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 03:13:04 -0700 Subject: x86/ioapic.c: remove redundant declaration of irq_pin_list The structure is defined immediately below, so there's no need to forward declare it. Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 1a34144..ec52e0c 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -116,8 +116,6 @@ static int __init parse_noapic(char *str) } early_param("noapic", parse_noapic); -struct irq_pin_list; - /* * This is performance-critical, we want to do it O(1) * -- cgit v0.10.2 From 8e13d697febc1ba17e70ed88789255c8bc25aa41 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 03:14:59 -0700 Subject: x86/ioapic.c: move lost comment to what seems like appropriate place The comment got separated from its subject, so move it to what appears to be the right place, and update to describe the current structure. Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index ec52e0c..a097a77 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -116,13 +116,6 @@ static int __init parse_noapic(char *str) } early_param("noapic", parse_noapic); -/* - * This is performance-critical, we want to do it O(1) - * - * the indexing order of this array favors 1:1 mappings - * between pins and IRQs. - */ - struct irq_pin_list { int apic, pin; struct irq_pin_list *next; @@ -137,6 +130,11 @@ static struct irq_pin_list *get_one_free_irq_2_pin(int node) return pin; } +/* + * This is performance-critical, we want to do it O(1) + * + * Most irqs are mapped 1:1 with pins. + */ struct irq_cfg { struct irq_pin_list *irq_2_pin; cpumask_var_t domain; -- cgit v0.10.2 From d8c52063ed85dda61b70bc05b90711478db5dc17 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 03:17:58 -0700 Subject: x86/ioapic.c: convert io_apic_level_ack_pending loop to normal for() loop Convert the unconventional loop in io_apic_level_ack_pending() to a conventional for() loop. Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index a097a77..0d04018 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -410,13 +410,10 @@ static bool io_apic_level_ack_pending(struct irq_cfg *cfg) unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); - entry = cfg->irq_2_pin; - for (;;) { + for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) { unsigned int reg; int pin; - if (!entry) - break; pin = entry->pin; reg = io_apic_read(entry->apic, 0x10 + pin*2); /* Is the remote IRR bit set? */ @@ -424,9 +421,6 @@ static bool io_apic_level_ack_pending(struct irq_cfg *cfg) spin_unlock_irqrestore(&ioapic_lock, flags); return true; } - if (!entry->next) - break; - entry = entry->next; } spin_unlock_irqrestore(&ioapic_lock, flags); -- cgit v0.10.2 From 875e68ec32fc5495f3edf987aaae1c52306184b7 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 03:24:11 -0700 Subject: x86/ioapic.c: simplify add_pin_to_irq_node() Rather than duplicating the same alloc/init code twice, restructure the function to look for duplicates and then add an entry if none is found. This function is not performance critical; all but one of its callers are __init functions, and the non-__init caller is for PCI device setup. Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 0d04018..d9e8f19 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -490,34 +490,22 @@ static void ioapic_mask_entry(int apic, int pin) */ static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin) { - struct irq_pin_list *entry; + struct irq_pin_list **entryp, *entry; - entry = cfg->irq_2_pin; - if (!entry) { - entry = get_one_free_irq_2_pin(node); - if (!entry) { - printk(KERN_ERR "can not alloc irq_2_pin to add %d - %d\n", - apic, pin); - return; - } - cfg->irq_2_pin = entry; - entry->apic = apic; - entry->pin = pin; - return; - } - - while (entry->next) { + for (entryp = &cfg->irq_2_pin; + *entryp != NULL; + entryp = &(*entryp)->next) { + entry = *entryp; /* not again, please */ if (entry->apic == apic && entry->pin == pin) return; - - entry = entry->next; } - entry->next = get_one_free_irq_2_pin(node); - entry = entry->next; + entry = get_one_free_irq_2_pin(node); entry->apic = apic; entry->pin = pin; + + *entryp = entry; } /* -- cgit v0.10.2 From 535b64291a9d1ff8bc54642494a5fce27e1e1170 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 03:29:26 -0700 Subject: x86/ioapic.c: convert replace_pin_at_irq_node to conventional for() loop Use a conventional for() loop in replace_pin_at_irq_node(). Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index d9e8f19..9386976 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -515,10 +515,10 @@ static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node, int oldapic, int oldpin, int newapic, int newpin) { - struct irq_pin_list *entry = cfg->irq_2_pin; + struct irq_pin_list *entry; int replaced = 0; - while (entry) { + for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) { if (entry->apic == oldapic && entry->pin == oldpin) { entry->apic = newapic; entry->pin = newpin; @@ -526,7 +526,6 @@ static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node, /* every one is different, right? */ break; } - entry = entry->next; } /* why? call replace before add? */ -- cgit v0.10.2 From 4eea6fff612f54380dd642b045bf03ac0613fe3e Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 03:32:15 -0700 Subject: x86/ioapic.c: clean up replace_pin_at_irq_node logic and comments There's no need for a control variable in replace_pin_at_irq_node(); it can just return if it finds the old apic/pin to replace. If the loop terminates, then it didn't find the old apic/pin, so it can add the new ones. Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 9386976..8245e62 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -512,25 +512,22 @@ static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin * Reroute an IRQ to a different pin. */ static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node, - int oldapic, int oldpin, - int newapic, int newpin) + int oldapic, int oldpin, + int newapic, int newpin) { struct irq_pin_list *entry; - int replaced = 0; for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) { if (entry->apic == oldapic && entry->pin == oldpin) { entry->apic = newapic; entry->pin = newpin; - replaced = 1; /* every one is different, right? */ - break; + return; } } - /* why? call replace before add? */ - if (!replaced) - add_pin_to_irq_node(cfg, node, newapic, newpin); + /* old apic/pin didn't exist, so just add new ones */ + add_pin_to_irq_node(cfg, node, newapic, newpin); } static void io_apic_modify_irq(struct irq_cfg *cfg, -- cgit v0.10.2 From 638f2f8c52a92c15ebda9e50d84c1ab56fc42e42 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 03:37:52 -0700 Subject: x86/ioapic.c: convert __target_IO_APIC_irq to conventional for() loop Use a normal for() loop in __target_IO_APIC_irq(). Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 8245e62..17883cd 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2236,13 +2236,9 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq struct irq_pin_list *entry; u8 vector = cfg->vector; - entry = cfg->irq_2_pin; - for (;;) { + for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) { unsigned int reg; - if (!entry) - break; - apic = entry->apic; pin = entry->pin; /* @@ -2255,9 +2251,6 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq reg &= ~IO_APIC_REDIR_VECTOR_MASK; reg |= vector; io_apic_modify(apic, 0x10 + pin*2, reg); - if (!entry->next) - break; - entry = entry->next; } } -- cgit v0.10.2 From e25371d60cb06a44d7a32d7966ab9bfbeacb9390 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 8 Jun 2009 03:49:01 -0700 Subject: x86/ioapic.c: unify ioapic_retrigger_irq() The 32 and 64-bit versions of ioapic_retrigger_irq() are identical except the 64-bit one takes vector_lock. vector_lock is defined and used on 32-bit too, so just use a common ioapic_retrigger_irq(). Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 17883cd..cf51b0b 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2178,7 +2178,6 @@ static unsigned int startup_ioapic_irq(unsigned int irq) return was_pending; } -#ifdef CONFIG_X86_64 static int ioapic_retrigger_irq(unsigned int irq) { @@ -2191,14 +2190,6 @@ static int ioapic_retrigger_irq(unsigned int irq) return 1; } -#else -static int ioapic_retrigger_irq(unsigned int irq) -{ - apic->send_IPI_self(irq_cfg(irq)->vector); - - return 1; -} -#endif /* * Level and edge triggered IO-APIC interrupts need different handling, -- cgit v0.10.2 From 66f6ce5e52f2f209d5bf1f06167cec888f4f4c13 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 15 Jul 2009 12:40:40 +0800 Subject: crypto: ahash - Add unaligned handling and default operations This patch exports the finup operation where available and adds a default finup operation for ahash. The operations final, finup and digest also will now deal with unaligned result pointers by copying it. Finally export/import operations are will now be exported too. Signed-off-by: Herbert Xu diff --git a/crypto/ahash.c b/crypto/ahash.c index a196055..ac0798d 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -24,6 +24,13 @@ #include "internal.h" +struct ahash_request_priv { + crypto_completion_t complete; + void *data; + u8 *result; + void *ubuf[] CRYPTO_MINALIGN_ATTR; +}; + static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash) { return container_of(crypto_hash_alg_common(hash), struct ahash_alg, @@ -156,7 +163,7 @@ static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, return ret; } -static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key, +int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) { struct ahash_alg *ahash = crypto_ahash_alg(tfm); @@ -167,6 +174,7 @@ static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key, return ahash->setkey(tfm, key, keylen); } +EXPORT_SYMBOL_GPL(crypto_ahash_setkey); static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) @@ -174,19 +182,209 @@ static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, return -ENOSYS; } +static inline unsigned int ahash_align_buffer_size(unsigned len, + unsigned long mask) +{ + return len + (mask & ~(crypto_tfm_ctx_alignment() - 1)); +} + +static void ahash_op_unaligned_finish(struct ahash_request *req, int err) +{ + struct ahash_request_priv *priv = req->priv; + + if (err == -EINPROGRESS) + return; + + if (!err) + memcpy(priv->result, req->result, + crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); + + kzfree(priv); +} + +static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) +{ + struct ahash_request *areq = req->data; + struct ahash_request_priv *priv = areq->priv; + crypto_completion_t complete = priv->complete; + void *data = priv->data; + + ahash_op_unaligned_finish(areq, err); + + complete(data, err); +} + +static int ahash_op_unaligned(struct ahash_request *req, + int (*op)(struct ahash_request *)) +{ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + unsigned long alignmask = crypto_ahash_alignmask(tfm); + unsigned int ds = crypto_ahash_digestsize(tfm); + struct ahash_request_priv *priv; + int err; + + priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), + (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_ATOMIC : GFP_ATOMIC); + if (!priv) + return -ENOMEM; + + priv->result = req->result; + priv->complete = req->base.complete; + priv->data = req->base.data; + + req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); + req->base.complete = ahash_op_unaligned_done; + req->base.data = req; + req->priv = priv; + + err = op(req); + ahash_op_unaligned_finish(req, err); + + return err; +} + +static int crypto_ahash_op(struct ahash_request *req, + int (*op)(struct ahash_request *)) +{ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + unsigned long alignmask = crypto_ahash_alignmask(tfm); + + if ((unsigned long)req->result & alignmask) + return ahash_op_unaligned(req, op); + + return op(req); +} + +int crypto_ahash_final(struct ahash_request *req) +{ + return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final); +} +EXPORT_SYMBOL_GPL(crypto_ahash_final); + +int crypto_ahash_finup(struct ahash_request *req) +{ + return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup); +} +EXPORT_SYMBOL_GPL(crypto_ahash_finup); + +int crypto_ahash_digest(struct ahash_request *req) +{ + return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->digest); +} +EXPORT_SYMBOL_GPL(crypto_ahash_digest); + +static void ahash_def_finup_finish2(struct ahash_request *req, int err) +{ + struct ahash_request_priv *priv = req->priv; + + if (err == -EINPROGRESS) + return; + + if (!err) + memcpy(priv->result, req->result, + crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); + + kzfree(priv); +} + +static void ahash_def_finup_done2(struct crypto_async_request *req, int err) +{ + struct ahash_request *areq = req->data; + struct ahash_request_priv *priv = areq->priv; + crypto_completion_t complete = priv->complete; + void *data = priv->data; + + ahash_def_finup_finish2(areq, err); + + complete(data, err); +} + +static int ahash_def_finup_finish1(struct ahash_request *req, int err) +{ + if (err) + goto out; + + req->base.complete = ahash_def_finup_done2; + req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + err = crypto_ahash_reqtfm(req)->final(req); + +out: + ahash_def_finup_finish2(req, err); + return err; +} + +static void ahash_def_finup_done1(struct crypto_async_request *req, int err) +{ + struct ahash_request *areq = req->data; + struct ahash_request_priv *priv = areq->priv; + crypto_completion_t complete = priv->complete; + void *data = priv->data; + + err = ahash_def_finup_finish1(areq, err); + + complete(data, err); +} + +static int ahash_def_finup(struct ahash_request *req) +{ + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + unsigned long alignmask = crypto_ahash_alignmask(tfm); + unsigned int ds = crypto_ahash_digestsize(tfm); + struct ahash_request_priv *priv; + + priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), + (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_ATOMIC : GFP_ATOMIC); + if (!priv) + return -ENOMEM; + + priv->result = req->result; + priv->complete = req->base.complete; + priv->data = req->base.data; + + req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); + req->base.complete = ahash_def_finup_done1; + req->base.data = req; + req->priv = priv; + + return ahash_def_finup_finish1(req, tfm->update(req)); +} + +static int ahash_no_export(struct ahash_request *req, void *out) +{ + return -ENOSYS; +} + +static int ahash_no_import(struct ahash_request *req, const void *in) +{ + return -ENOSYS; +} + static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) { struct crypto_ahash *hash = __crypto_ahash_cast(tfm); struct ahash_alg *alg = crypto_ahash_alg(hash); + hash->setkey = ahash_nosetkey; + hash->export = ahash_no_export; + hash->import = ahash_no_import; + if (tfm->__crt_alg->cra_type != &crypto_ahash_type) return crypto_init_shash_ops_async(tfm); hash->init = alg->init; hash->update = alg->update; - hash->final = alg->final; + hash->final = alg->final; + hash->finup = alg->finup ?: ahash_def_finup; hash->digest = alg->digest; - hash->setkey = alg->setkey ? ahash_setkey : ahash_nosetkey; + + if (alg->setkey) + hash->setkey = alg->setkey; + if (alg->export) + hash->export = alg->export; + if (alg->import) + hash->import = alg->import; return 0; } diff --git a/crypto/shash.c b/crypto/shash.c index 171c8f0..834d9d2 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -235,6 +235,33 @@ static int shash_async_final(struct ahash_request *req) return crypto_shash_final(ahash_request_ctx(req), req->result); } +int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc) +{ + struct crypto_hash_walk walk; + int nbytes; + + for (nbytes = crypto_hash_walk_first(req, &walk); nbytes > 0; + nbytes = crypto_hash_walk_done(&walk, nbytes)) + nbytes = crypto_hash_walk_last(&walk) ? + crypto_shash_finup(desc, walk.data, nbytes, + req->result) : + crypto_shash_update(desc, walk.data, nbytes); + + return nbytes; +} +EXPORT_SYMBOL_GPL(shash_ahash_finup); + +static int shash_async_finup(struct ahash_request *req) +{ + struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); + struct shash_desc *desc = ahash_request_ctx(req); + + desc->tfm = *ctx; + desc->flags = req->base.flags; + + return shash_ahash_finup(req, desc); +} + int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) { struct scatterlist *sg = req->src; @@ -252,8 +279,7 @@ int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) crypto_yield(desc->flags); } else err = crypto_shash_init(desc) ?: - shash_ahash_update(req, desc) ?: - crypto_shash_final(desc, req->result); + shash_ahash_finup(req, desc); return err; } @@ -270,6 +296,16 @@ static int shash_async_digest(struct ahash_request *req) return shash_ahash_digest(req, desc); } +static int shash_async_export(struct ahash_request *req, void *out) +{ + return crypto_shash_export(ahash_request_ctx(req), out); +} + +static int shash_async_import(struct ahash_request *req, const void *in) +{ + return crypto_shash_import(ahash_request_ctx(req), in); +} + static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm) { struct crypto_shash **ctx = crypto_tfm_ctx(tfm); @@ -280,6 +316,7 @@ static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm) int crypto_init_shash_ops_async(struct crypto_tfm *tfm) { struct crypto_alg *calg = tfm->__crt_alg; + struct shash_alg *alg = __crypto_shash_alg(calg); struct crypto_ahash *crt = __crypto_ahash_cast(tfm); struct crypto_shash **ctx = crypto_tfm_ctx(tfm); struct crypto_shash *shash; @@ -298,9 +335,16 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm) crt->init = shash_async_init; crt->update = shash_async_update; - crt->final = shash_async_final; + crt->final = shash_async_final; + crt->finup = shash_async_finup; crt->digest = shash_async_digest; - crt->setkey = shash_async_setkey; + + if (alg->setkey) + crt->setkey = shash_async_setkey; + if (alg->export) + crt->export = shash_async_export; + if (alg->setkey) + crt->import = shash_async_import; crt->reqsize = sizeof(struct shash_desc) + crypto_shash_descsize(shash); diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 45c2bdd..3e89ce1 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -31,6 +31,9 @@ struct ahash_request { struct scatterlist *src; u8 *result; + /* This field may only be used by the ahash API code. */ + void *priv; + void *__ctx[] CRYPTO_MINALIGN_ATTR; }; @@ -175,16 +178,11 @@ static inline void *ahash_request_ctx(struct ahash_request *req) return req->__ctx; } -static inline int crypto_ahash_setkey(struct crypto_ahash *tfm, - const u8 *key, unsigned int keylen) -{ - return tfm->setkey(tfm, key, keylen); -} - -static inline int crypto_ahash_digest(struct ahash_request *req) -{ - return crypto_ahash_reqtfm(req)->digest(req); -} +int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, + unsigned int keylen); +int crypto_ahash_finup(struct ahash_request *req); +int crypto_ahash_final(struct ahash_request *req); +int crypto_ahash_digest(struct ahash_request *req); static inline int crypto_ahash_export(struct ahash_request *req, void *out) { @@ -206,11 +204,6 @@ static inline int crypto_ahash_update(struct ahash_request *req) return crypto_ahash_reqtfm(req)->update(req); } -static inline int crypto_ahash_final(struct ahash_request *req) -{ - return crypto_ahash_reqtfm(req)->final(req); -} - static inline void ahash_request_set_tfm(struct ahash_request *req, struct crypto_ahash *tfm) { diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 179dd8f..5bfad8c 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -59,6 +59,11 @@ int crypto_hash_walk_first_compat(struct hash_desc *hdesc, struct crypto_hash_walk *walk, struct scatterlist *sg, unsigned int len); +static inline int crypto_hash_walk_last(struct crypto_hash_walk *walk) +{ + return !(walk->entrylen | walk->total); +} + int crypto_register_ahash(struct ahash_alg *alg); int crypto_unregister_ahash(struct ahash_alg *alg); int ahash_register_instance(struct crypto_template *tmpl, @@ -94,6 +99,7 @@ static inline void crypto_drop_shash(struct crypto_shash_spawn *spawn) struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask); int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc); +int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc); int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc); int crypto_init_shash_ops_async(struct crypto_tfm *tfm); -- cgit v0.10.2 From 305f9db22d62da10c43c7fd7554ec923c2b8727e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 15 Jul 2009 15:11:08 +0800 Subject: crypto: crypto4xx - Disable SHA implementation The crypto4xx SHA implementation keeps the hash state in the tfm data structure. This breaks a fundamental requirement of ahash implementations that they must be reentrant. This patch disables the broken implementation. Signed-off-by: Herbert Xu diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 857e35e..46e899a 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1144,25 +1144,6 @@ struct crypto4xx_alg_common crypto4xx_alg[] = { } } }}, - /* Hash SHA1 */ - { .type = CRYPTO_ALG_TYPE_AHASH, .u.hash = { - .init = crypto4xx_hash_init, - .update = crypto4xx_hash_update, - .final = crypto4xx_hash_final, - .digest = crypto4xx_hash_digest, - .halg.digestsize = SHA1_DIGEST_SIZE, - .halg.base = { - .cra_name = "sha1", - .cra_driver_name = "sha1-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_init = crypto4xx_sha1_alg_init, - .cra_exit = crypto4xx_alg_exit, - .cra_module = THIS_MODULE, - } - }}, }; /** -- cgit v0.10.2 From 05ed8758fa30e088766905d0d600aa393e144353 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Wed, 15 Jul 2009 16:51:04 +0800 Subject: crypto: cryptd - Fix uninitialized return value If cryptd_alloc_instance() fails, the return value is uninitialized. This patch fixes this by setting the return value. Signed-off-by: Steffen Klassert Signed-off-by: Herbert Xu diff --git a/crypto/cryptd.c b/crypto/cryptd.c index 5dabb7d..fbd26f9 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -303,6 +303,7 @@ static int cryptd_create_blkcipher(struct crypto_template *tmpl, return PTR_ERR(alg); inst = cryptd_alloc_instance(alg, 0, sizeof(*ctx)); + err = PTR_ERR(inst); if (IS_ERR(inst)) goto out_put_alg; @@ -522,6 +523,7 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb, alg = &salg->base; inst = cryptd_alloc_instance(alg, ahash_instance_headroom(), sizeof(*ctx)); + err = PTR_ERR(inst); if (IS_ERR(inst)) goto out_put_alg; -- cgit v0.10.2 From 3b3fc322d9c92e8bbfcecf739f1a3d10ded7f2cd Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 15 Jul 2009 16:52:55 +0800 Subject: crypto: hmac - Fix incorrect error value when creating instance If shash_alloc_instance() fails, we return the wrong error value. This patch fixes it. Signed-off-by: Herbert Xu diff --git a/crypto/hmac.c b/crypto/hmac.c index e373427..02aa53e 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -195,6 +195,7 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) goto out_put_alg; inst = shash_alloc_instance("hmac", alg); + err = PTR_ERR(inst); if (IS_ERR(inst)) goto out_put_alg; -- cgit v0.10.2 From b5ebd44eb7559ea6135d536bafd02323d2ef0547 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 15 Jul 2009 16:53:33 +0800 Subject: crypto: xcbc - Fix incorrect error value when creating instance If shash_alloc_instance() fails, we return the wrong error value. This patch fixes it. Signed-off-by: Herbert Xu diff --git a/crypto/xcbc.c b/crypto/xcbc.c index b2cc855..3b991bf 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c @@ -252,6 +252,7 @@ static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb) } inst = shash_alloc_instance("xcbc", alg); + err = PTR_ERR(inst); if (IS_ERR(inst)) goto out_put_alg; -- cgit v0.10.2 From e465d544fab81aa122f86a50418f4be7f1fcf066 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 15 Jul 2009 10:01:30 +0100 Subject: ASoC: Fix sample rate lookup in WM8993 We need to use the best value we picked, not the last value we looked at. Reported-by: Stephen Rothwell Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 3e5c65a..f9c49b3 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1796,7 +1796,8 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream, } dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n", sample_rates[best].rate); - clocking3 |= (sample_rates[i].sample_rate << WM8993_SAMPLE_RATE_SHIFT); + clocking3 |= (sample_rates[best].sample_rate + << WM8993_SAMPLE_RATE_SHIFT); /* BCLK_DIV */ best = 0; -- cgit v0.10.2 From 468b8fde24d49f5b34e9152981824b9d4ecd1a2e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 13 Jul 2009 11:39:29 +0200 Subject: sound: usb-audio: Xonar U1 digital output support Add support for the Asus Xonar U1. This device is mostly class compliant, but the digital output requires a vendor-specific request. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 4bd3a7a..8452697 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -86,6 +86,7 @@ struct usb_mixer_interface { u8 rc_buffer[6]; u8 audigy2nx_leds[3]; + u8 xonar_u1_status; }; @@ -2018,6 +2019,58 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, } } +static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02); + return 0; +} + +static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + u8 old_status, new_status; + int err, changed; + + old_status = mixer->xonar_u1_status; + if (ucontrol->value.integer.value[0]) + new_status = old_status | 0x02; + else + new_status = old_status & ~0x02; + changed = new_status != old_status; + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 50, 0, &new_status, 1, 100); + if (err < 0) + return err; + mixer->xonar_u1_status = new_status; + return changed; +} + +static struct snd_kcontrol_new snd_xonar_u1_output_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = snd_xonar_u1_switch_get, + .put = snd_xonar_u1_switch_put, +}; + +static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) +{ + int err; + + err = snd_ctl_add(mixer->chip->card, + snd_ctl_new1(&snd_xonar_u1_output_switch, mixer)); + if (err < 0) + return err; + mixer->xonar_u1_status = 0x05; + return 0; +} + int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, int ignore_error) { @@ -2060,6 +2113,13 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, snd_audigy2nx_proc_read); } + if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) || + mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) { + err = snd_xonar_u1_controls_create(mixer); + if (err < 0) + goto _error; + } + err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); if (err < 0) goto _error; -- cgit v0.10.2 From f907ed94f993b0cd366c26eaa88b90c5454203ae Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 13 Jul 2009 13:30:22 +0200 Subject: seq-midi: always log message on output overrun It turns out that the main cause of output buffer overruns is not slow drivers but applications that generate too many messages. Therefore, it makes more sense to make that error message always visible, and to rate-limit it. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 4d26146..3810c52 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -120,7 +120,8 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i return -EINVAL; runtime = substream->runtime; if ((tmp = runtime->avail) < count) { - snd_printd("warning, output event was lost (count = %i, available = %i)\n", count, tmp); + if (printk_ratelimit()) + snd_printk(KERN_ERR "MIDI output buffer overrun\n"); return -ENOMEM; } if (snd_rawmidi_kernel_write(substream, buf, count) < count) -- cgit v0.10.2 From 4773d1fb8f37612336d2c929058bf96d3a1624b1 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 13 Jul 2009 13:40:36 +0200 Subject: sound: usb-audio: use multiple input URBs Some newer USB MIDI interfaces use rather small packet sizes, so to get enough bandwidth, we have to be able to receive multiple packets in one USB frame, so we have to use multiple URBs. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 2fb35cc..cc17401 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -62,6 +62,8 @@ */ #define ERROR_DELAY_JIFFIES (HZ / 10) +#define INPUT_URBS 7 + MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("USB Audio/MIDI helper module"); @@ -143,7 +145,7 @@ struct snd_usb_midi_out_endpoint { struct snd_usb_midi_in_endpoint { struct snd_usb_midi* umidi; - struct urb* urb; + struct urb* urbs[INPUT_URBS]; struct usbmidi_in_port { struct snd_rawmidi_substream *substream; u8 running_status_length; @@ -306,7 +308,7 @@ static void snd_usbmidi_out_tasklet(unsigned long data) static void snd_usbmidi_error_timer(unsigned long data) { struct snd_usb_midi *umidi = (struct snd_usb_midi *)data; - int i; + unsigned int i, j; spin_lock(&umidi->disc_lock); if (umidi->disconnected) { @@ -317,8 +319,10 @@ static void snd_usbmidi_error_timer(unsigned long data) struct snd_usb_midi_in_endpoint *in = umidi->endpoints[i].in; if (in && in->error_resubmit) { in->error_resubmit = 0; - in->urb->dev = umidi->chip->dev; - snd_usbmidi_submit_urb(in->urb, GFP_ATOMIC); + for (j = 0; j < INPUT_URBS; ++j) { + in->urbs[j]->dev = umidi->chip->dev; + snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC); + } } if (umidi->endpoints[i].out) snd_usbmidi_do_output(umidi->endpoints[i].out); @@ -922,12 +926,16 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = { */ static void snd_usbmidi_in_endpoint_delete(struct snd_usb_midi_in_endpoint* ep) { - if (ep->urb) { - usb_buffer_free(ep->umidi->chip->dev, - ep->urb->transfer_buffer_length, - ep->urb->transfer_buffer, - ep->urb->transfer_dma); - usb_free_urb(ep->urb); + unsigned int i; + + for (i = 0; i < INPUT_URBS; ++i) { + if (ep->urbs[i]) { + usb_buffer_free(ep->umidi->chip->dev, + ep->urbs[i]->transfer_buffer_length, + ep->urbs[i]->transfer_buffer, + ep->urbs[i]->transfer_dma); + usb_free_urb(ep->urbs[i]); + } } kfree(ep); } @@ -943,6 +951,7 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, void* buffer; unsigned int pipe; int length; + unsigned int i; rep->in = NULL; ep = kzalloc(sizeof(*ep), GFP_KERNEL); @@ -950,30 +959,36 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, return -ENOMEM; ep->umidi = umidi; - ep->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ep->urb) { - snd_usbmidi_in_endpoint_delete(ep); - return -ENOMEM; + for (i = 0; i < INPUT_URBS; ++i) { + ep->urbs[i] = usb_alloc_urb(0, GFP_KERNEL); + if (!ep->urbs[i]) { + snd_usbmidi_in_endpoint_delete(ep); + return -ENOMEM; + } } if (ep_info->in_interval) pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep); else pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep); length = usb_maxpacket(umidi->chip->dev, pipe, 0); - buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL, - &ep->urb->transfer_dma); - if (!buffer) { - snd_usbmidi_in_endpoint_delete(ep); - return -ENOMEM; + for (i = 0; i < INPUT_URBS; ++i) { + buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL, + &ep->urbs[i]->transfer_dma); + if (!buffer) { + snd_usbmidi_in_endpoint_delete(ep); + return -ENOMEM; + } + if (ep_info->in_interval) + usb_fill_int_urb(ep->urbs[i], umidi->chip->dev, + pipe, buffer, length, + snd_usbmidi_in_urb_complete, + ep, ep_info->in_interval); + else + usb_fill_bulk_urb(ep->urbs[i], umidi->chip->dev, + pipe, buffer, length, + snd_usbmidi_in_urb_complete, ep); + ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; } - if (ep_info->in_interval) - usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer, - length, snd_usbmidi_in_urb_complete, ep, - ep_info->in_interval); - else - usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, - length, snd_usbmidi_in_urb_complete, ep); - ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; rep->in = ep; return 0; @@ -1090,7 +1105,7 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi) void snd_usbmidi_disconnect(struct list_head* p) { struct snd_usb_midi* umidi; - int i; + unsigned int i, j; umidi = list_entry(p, struct snd_usb_midi, list); /* @@ -1111,7 +1126,8 @@ void snd_usbmidi_disconnect(struct list_head* p) umidi->usb_protocol_ops->finish_out_endpoint(ep->out); } if (ep->in) - usb_kill_urb(ep->in->urb); + for (j = 0; j < INPUT_URBS; ++j) + usb_kill_urb(ep->in->urbs[j]); /* free endpoints here; later call can result in Oops */ if (ep->out) { snd_usbmidi_out_endpoint_delete(ep->out); @@ -1692,20 +1708,25 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, void snd_usbmidi_input_stop(struct list_head* p) { struct snd_usb_midi* umidi; - int i; + unsigned int i, j; umidi = list_entry(p, struct snd_usb_midi, list); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; if (ep->in) - usb_kill_urb(ep->in->urb); + for (j = 0; j < INPUT_URBS; ++j) + usb_kill_urb(ep->in->urbs[j]); } } static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) { - if (ep) { - struct urb* urb = ep->urb; + unsigned int i; + + if (!ep) + return; + for (i = 0; i < INPUT_URBS; ++i) { + struct urb* urb = ep->urbs[i]; urb->dev = ep->umidi->chip->dev; snd_usbmidi_submit_urb(urb, GFP_KERNEL); } -- cgit v0.10.2 From ed4affa53229701be7be4f7f84ba84164135d7e8 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 13 Jul 2009 13:43:59 +0200 Subject: sound: usb-audio: use multiple output URBs Some newer USB MIDI interfaces use rather small packet sizes, so to get enough bandwidth, we have to be able to send multiple packets in one USB frame, so we have to use multiple URBs. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index cc17401..32d70cc 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -62,6 +62,7 @@ */ #define ERROR_DELAY_JIFFIES (HZ / 10) +#define OUTPUT_URBS 7 #define INPUT_URBS 7 @@ -92,7 +93,7 @@ struct snd_usb_midi_endpoint; struct usb_protocol_ops { void (*input)(struct snd_usb_midi_in_endpoint*, uint8_t*, int); - void (*output)(struct snd_usb_midi_out_endpoint*); + void (*output)(struct snd_usb_midi_out_endpoint *ep, struct urb *urb); void (*output_packet)(struct urb*, uint8_t, uint8_t, uint8_t, uint8_t); void (*init_out_endpoint)(struct snd_usb_midi_out_endpoint*); void (*finish_out_endpoint)(struct snd_usb_midi_out_endpoint*); @@ -118,8 +119,11 @@ struct snd_usb_midi { struct snd_usb_midi_out_endpoint { struct snd_usb_midi* umidi; - struct urb* urb; - int urb_active; + struct out_urb_context { + struct urb *urb; + struct snd_usb_midi_out_endpoint *ep; + } urbs[OUTPUT_URBS]; + unsigned int active_urbs; int max_transfer; /* size of urb buffer */ struct tasklet_struct tasklet; @@ -253,10 +257,11 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb) static void snd_usbmidi_out_urb_complete(struct urb* urb) { - struct snd_usb_midi_out_endpoint* ep = urb->context; + struct out_urb_context *context = urb->context; + struct snd_usb_midi_out_endpoint* ep = context->ep; spin_lock(&ep->buffer_lock); - ep->urb_active = 0; + ep->active_urbs &= ~(1 << (context - ep->urbs)); spin_unlock(&ep->buffer_lock); if (urb->status < 0) { int err = snd_usbmidi_urb_error(urb->status); @@ -276,23 +281,37 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb) */ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) { - struct urb* urb = ep->urb; + unsigned int urb_index; + struct urb* urb; unsigned long flags; spin_lock_irqsave(&ep->buffer_lock, flags); - if (ep->urb_active || ep->umidi->chip->shutdown) { + if (ep->umidi->chip->shutdown) { spin_unlock_irqrestore(&ep->buffer_lock, flags); return; } - urb->transfer_buffer_length = 0; - ep->umidi->usb_protocol_ops->output(ep); + for (;;) { + urb = NULL; + for (urb_index = 0; urb_index < OUTPUT_URBS; ++urb_index) + if (!(ep->active_urbs & (1 << urb_index))) { + urb = ep->urbs[urb_index].urb; + break; + } + if (!urb) + break; + + urb->transfer_buffer_length = 0; + ep->umidi->usb_protocol_ops->output(ep, urb); + if (urb->transfer_buffer_length == 0) + break; - if (urb->transfer_buffer_length > 0) { dump_urb("sending", urb->transfer_buffer, urb->transfer_buffer_length); urb->dev = ep->umidi->chip->dev; - ep->urb_active = snd_usbmidi_submit_urb(urb, GFP_ATOMIC) >= 0; + if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0) + break; + ep->active_urbs |= 1 << urb_index; } spin_unlock_irqrestore(&ep->buffer_lock, flags); } @@ -334,13 +353,14 @@ static void snd_usbmidi_error_timer(unsigned long data) static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep, const void *data, int len) { - int err; + int err = 0; void *buf = kmemdup(data, len, GFP_KERNEL); if (!buf) return -ENOMEM; dump_urb("sending", buf, len); - err = usb_bulk_msg(ep->umidi->chip->dev, ep->urb->pipe, buf, len, - NULL, 250); + if (ep->urbs[0].urb) + err = usb_bulk_msg(ep->umidi->chip->dev, ep->urbs[0].urb->pipe, + buf, len, NULL, 250); kfree(buf); return err; } @@ -558,9 +578,9 @@ static void snd_usbmidi_transmit_byte(struct usbmidi_out_port* port, } } -static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { - struct urb* urb = ep->urb; int p; /* FIXME: lower-numbered ports can starve higher-numbered ports */ @@ -617,14 +637,15 @@ static void snd_usbmidi_novation_input(struct snd_usb_midi_in_endpoint* ep, snd_usbmidi_input_data(ep, 0, &buffer[2], buffer[0] - 1); } -static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { uint8_t* transfer_buffer; int count; if (!ep->ports[0].active) return; - transfer_buffer = ep->urb->transfer_buffer; + transfer_buffer = urb->transfer_buffer; count = snd_rawmidi_transmit(ep->ports[0].substream, &transfer_buffer[2], ep->max_transfer - 2); @@ -634,7 +655,7 @@ static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep) } transfer_buffer[0] = 0; transfer_buffer[1] = count; - ep->urb->transfer_buffer_length = 2 + count; + urb->transfer_buffer_length = 2 + count; } static struct usb_protocol_ops snd_usbmidi_novation_ops = { @@ -652,20 +673,21 @@ static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep, snd_usbmidi_input_data(ep, 0, buffer, buffer_length); } -static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { int count; if (!ep->ports[0].active) return; count = snd_rawmidi_transmit(ep->ports[0].substream, - ep->urb->transfer_buffer, + urb->transfer_buffer, ep->max_transfer); if (count < 1) { ep->ports[0].active = 0; return; } - ep->urb->transfer_buffer_length = count; + urb->transfer_buffer_length = count; } static struct usb_protocol_ops snd_usbmidi_raw_ops = { @@ -685,23 +707,25 @@ static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep, snd_usbmidi_input_data(ep, 0, buffer, buffer_length); } -static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep) +static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, + struct urb *urb) { int count; if (!ep->ports[0].active) return; - count = ep->urb->dev->speed == USB_SPEED_HIGH ? 1 : 2; + count = snd_usb_get_speed(ep->umidi->chip->dev) == USB_SPEED_HIGH + ? 1 : 2; count = snd_rawmidi_transmit(ep->ports[0].substream, - ep->urb->transfer_buffer, + urb->transfer_buffer, count); if (count < 1) { ep->ports[0].active = 0; return; } - memset(ep->urb->transfer_buffer + count, 0xFD, 9 - count); - ep->urb->transfer_buffer_length = count; + memset(urb->transfer_buffer + count, 0xFD, 9 - count); + urb->transfer_buffer_length = count; } static struct usb_protocol_ops snd_usbmidi_122l_ops = { @@ -790,10 +814,11 @@ static void snd_usbmidi_emagic_input(struct snd_usb_midi_in_endpoint* ep, } } -static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { int port0 = ep->current_port; - uint8_t* buf = ep->urb->transfer_buffer; + uint8_t* buf = urb->transfer_buffer; int buf_free = ep->max_transfer; int length, i; @@ -833,7 +858,7 @@ static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep) *buf = 0xff; --buf_free; } - ep->urb->transfer_buffer_length = ep->max_transfer - buf_free; + urb->transfer_buffer_length = ep->max_transfer - buf_free; } static struct usb_protocol_ops snd_usbmidi_emagic_ops = { @@ -920,6 +945,14 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = { .trigger = snd_usbmidi_input_trigger }; +static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb, + unsigned int buffer_length) +{ + usb_buffer_free(umidi->chip->dev, buffer_length, + urb->transfer_buffer, urb->transfer_dma); + usb_free_urb(urb); +} + /* * Frees an input endpoint. * May be called when ep hasn't been initialized completely. @@ -928,15 +961,10 @@ static void snd_usbmidi_in_endpoint_delete(struct snd_usb_midi_in_endpoint* ep) { unsigned int i; - for (i = 0; i < INPUT_URBS; ++i) { - if (ep->urbs[i]) { - usb_buffer_free(ep->umidi->chip->dev, - ep->urbs[i]->transfer_buffer_length, - ep->urbs[i]->transfer_buffer, - ep->urbs[i]->transfer_dma); - usb_free_urb(ep->urbs[i]); - } - } + for (i = 0; i < INPUT_URBS; ++i) + if (ep->urbs[i]) + free_urb_and_buffer(ep->umidi, ep->urbs[i], + ep->urbs[i]->transfer_buffer_length); kfree(ep); } @@ -1009,12 +1037,12 @@ static unsigned int snd_usbmidi_count_bits(unsigned int x) */ static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint* ep) { - if (ep->urb) { - usb_buffer_free(ep->umidi->chip->dev, ep->max_transfer, - ep->urb->transfer_buffer, - ep->urb->transfer_dma); - usb_free_urb(ep->urb); - } + unsigned int i; + + for (i = 0; i < OUTPUT_URBS; ++i) + if (ep->urbs[i].urb) + free_urb_and_buffer(ep->umidi, ep->urbs[i].urb, + ep->max_transfer); kfree(ep); } @@ -1026,7 +1054,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, struct snd_usb_midi_endpoint* rep) { struct snd_usb_midi_out_endpoint* ep; - int i; + unsigned int i; unsigned int pipe; void* buffer; @@ -1036,35 +1064,42 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, return -ENOMEM; ep->umidi = umidi; - ep->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ep->urb) { - snd_usbmidi_out_endpoint_delete(ep); - return -ENOMEM; + for (i = 0; i < OUTPUT_URBS; ++i) { + ep->urbs[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ep->urbs[i].urb) { + snd_usbmidi_out_endpoint_delete(ep); + return -ENOMEM; + } + ep->urbs[i].ep = ep; } if (ep_info->out_interval) pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep); else pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ - /* FIXME: we need more URBs to get reasonable bandwidth here: */ ep->max_transfer = 4; else ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1); - buffer = usb_buffer_alloc(umidi->chip->dev, ep->max_transfer, - GFP_KERNEL, &ep->urb->transfer_dma); - if (!buffer) { - snd_usbmidi_out_endpoint_delete(ep); - return -ENOMEM; + for (i = 0; i < OUTPUT_URBS; ++i) { + buffer = usb_buffer_alloc(umidi->chip->dev, + ep->max_transfer, GFP_KERNEL, + &ep->urbs[i].urb->transfer_dma); + if (!buffer) { + snd_usbmidi_out_endpoint_delete(ep); + return -ENOMEM; + } + if (ep_info->out_interval) + usb_fill_int_urb(ep->urbs[i].urb, umidi->chip->dev, + pipe, buffer, ep->max_transfer, + snd_usbmidi_out_urb_complete, + &ep->urbs[i], ep_info->out_interval); + else + usb_fill_bulk_urb(ep->urbs[i].urb, umidi->chip->dev, + pipe, buffer, ep->max_transfer, + snd_usbmidi_out_urb_complete, + &ep->urbs[i]); + ep->urbs[i].urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; } - if (ep_info->out_interval) - usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer, - ep->max_transfer, snd_usbmidi_out_urb_complete, - ep, ep_info->out_interval); - else - usb_fill_bulk_urb(ep->urb, umidi->chip->dev, - pipe, buffer, ep->max_transfer, - snd_usbmidi_out_urb_complete, ep); - ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; spin_lock_init(&ep->buffer_lock); tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep); @@ -1120,8 +1155,9 @@ void snd_usbmidi_disconnect(struct list_head* p) struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; if (ep->out) tasklet_kill(&ep->out->tasklet); - if (ep->out && ep->out->urb) { - usb_kill_urb(ep->out->urb); + if (ep->out) { + for (j = 0; j < OUTPUT_URBS; ++j) + usb_kill_urb(ep->out->urbs[j].urb); if (umidi->usb_protocol_ops->finish_out_endpoint) umidi->usb_protocol_ops->finish_out_endpoint(ep->out); } -- cgit v0.10.2 From a65dd997b3cf057f6524466cf8dfb8382c132bd5 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 13 Jul 2009 13:48:36 +0200 Subject: sound: usb-audio: add MIDI drain callback When draining, instead of waiting for fifty milliseconds, just wait for the currently active URBs to complete. This cuts the usual waiting time down to one USB frame, or zero in the common case when there is no URB. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 32d70cc..0eff19c 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -124,9 +125,10 @@ struct snd_usb_midi_out_endpoint { struct snd_usb_midi_out_endpoint *ep; } urbs[OUTPUT_URBS]; unsigned int active_urbs; + unsigned int drain_urbs; int max_transfer; /* size of urb buffer */ struct tasklet_struct tasklet; - + unsigned int next_urb; spinlock_t buffer_lock; struct usbmidi_out_port { @@ -145,6 +147,8 @@ struct snd_usb_midi_out_endpoint { uint8_t data[2]; } ports[0x10]; int current_port; + + wait_queue_head_t drain_wait; }; struct snd_usb_midi_in_endpoint { @@ -259,9 +263,15 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb) { struct out_urb_context *context = urb->context; struct snd_usb_midi_out_endpoint* ep = context->ep; + unsigned int urb_index; spin_lock(&ep->buffer_lock); - ep->active_urbs &= ~(1 << (context - ep->urbs)); + urb_index = context - ep->urbs; + ep->active_urbs &= ~(1 << urb_index); + if (unlikely(ep->drain_urbs)) { + ep->drain_urbs &= ~(1 << urb_index); + wake_up(&ep->drain_wait); + } spin_unlock(&ep->buffer_lock); if (urb->status < 0) { int err = snd_usbmidi_urb_error(urb->status); @@ -291,28 +301,28 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) return; } + urb_index = ep->next_urb; for (;;) { - urb = NULL; - for (urb_index = 0; urb_index < OUTPUT_URBS; ++urb_index) - if (!(ep->active_urbs & (1 << urb_index))) { - urb = ep->urbs[urb_index].urb; + if (!(ep->active_urbs & (1 << urb_index))) { + urb = ep->urbs[urb_index].urb; + urb->transfer_buffer_length = 0; + ep->umidi->usb_protocol_ops->output(ep, urb); + if (urb->transfer_buffer_length == 0) break; - } - if (!urb) - break; - - urb->transfer_buffer_length = 0; - ep->umidi->usb_protocol_ops->output(ep, urb); - if (urb->transfer_buffer_length == 0) - break; - dump_urb("sending", urb->transfer_buffer, - urb->transfer_buffer_length); - urb->dev = ep->umidi->chip->dev; - if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0) + dump_urb("sending", urb->transfer_buffer, + urb->transfer_buffer_length); + urb->dev = ep->umidi->chip->dev; + if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0) + break; + ep->active_urbs |= 1 << urb_index; + } + if (++urb_index >= OUTPUT_URBS) + urb_index = 0; + if (urb_index == ep->next_urb) break; - ep->active_urbs |= 1 << urb_index; } + ep->next_urb = urb_index; spin_unlock_irqrestore(&ep->buffer_lock, flags); } @@ -913,6 +923,35 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, } } +static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream) +{ + struct usbmidi_out_port* port = substream->runtime->private_data; + struct snd_usb_midi_out_endpoint *ep = port->ep; + unsigned int drain_urbs; + DEFINE_WAIT(wait); + long timeout = msecs_to_jiffies(50); + + /* + * The substream buffer is empty, but some data might still be in the + * currently active URBs, so we have to wait for those to complete. + */ + spin_lock_irq(&ep->buffer_lock); + drain_urbs = ep->active_urbs; + if (drain_urbs) { + ep->drain_urbs |= drain_urbs; + do { + prepare_to_wait(&ep->drain_wait, &wait, + TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&ep->buffer_lock); + timeout = schedule_timeout(timeout); + spin_lock_irq(&ep->buffer_lock); + drain_urbs &= ep->drain_urbs; + } while (drain_urbs && timeout); + finish_wait(&ep->drain_wait, &wait); + } + spin_unlock_irq(&ep->buffer_lock); +} + static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) { return 0; @@ -937,6 +976,7 @@ static struct snd_rawmidi_ops snd_usbmidi_output_ops = { .open = snd_usbmidi_output_open, .close = snd_usbmidi_output_close, .trigger = snd_usbmidi_output_trigger, + .drain = snd_usbmidi_output_drain, }; static struct snd_rawmidi_ops snd_usbmidi_input_ops = { @@ -1103,6 +1143,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, spin_lock_init(&ep->buffer_lock); tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep); + init_waitqueue_head(&ep->drain_wait); for (i = 0; i < 0x10; ++i) if (ep_info->out_cables & (1 << i)) { -- cgit v0.10.2 From b86c87288c2205376ee213d6a03ac9422faf014a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 13 Jul 2009 13:50:17 +0200 Subject: sound: seq_midi: do not send MIDI reset when closing Sending a MIDI reset message when closing a port is wrong because we only want to shut the device up, not to reset all settings. Furthermore, many devices ignore this message. Fortunately, the RawMIDI layer already shuts the device up, so we can ignore this matter here. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 3810c52..45cf5c1 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -249,12 +249,9 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info static int midisynth_unuse(void *private_data, struct snd_seq_port_subscribe *info) { struct seq_midisynth *msynth = private_data; - unsigned char buf = 0xff; /* MIDI reset */ if (snd_BUG_ON(!msynth->output_rfile.output)) return -EINVAL; - /* sending single MIDI reset message to shut the device up */ - snd_rawmidi_kernel_write(msynth->output_rfile.output, &buf, 1); snd_rawmidi_drain_output(msynth->output_rfile.output); return snd_rawmidi_kernel_release(&msynth->output_rfile); } -- cgit v0.10.2 From 08d033405a5a537d4197dad0fcb6be47062be2a9 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 13 Jul 2009 13:50:57 +0200 Subject: sound: seq_oss_midi: remove magic numbers Instead of using magic numbers for the controlles sent when resetting a port, use the symbols from asoundef.h. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 0a711d2..9dfb2f7 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -20,6 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include "seq_oss_midi.h" #include "seq_oss_readq.h" #include "seq_oss_timer.h" @@ -476,19 +477,20 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev) ev.source.port = dp->port; if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) { ev.type = SNDRV_SEQ_EVENT_SENSING; - snd_seq_oss_dispatch(dp, &ev, 0, 0); /* active sensing */ + snd_seq_oss_dispatch(dp, &ev, 0, 0); } for (c = 0; c < 16; c++) { ev.type = SNDRV_SEQ_EVENT_CONTROLLER; ev.data.control.channel = c; - ev.data.control.param = 123; - snd_seq_oss_dispatch(dp, &ev, 0, 0); /* all notes off */ + ev.data.control.param = MIDI_CTL_ALL_NOTES_OFF; + snd_seq_oss_dispatch(dp, &ev, 0, 0); if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) { - ev.data.control.param = 121; - snd_seq_oss_dispatch(dp, &ev, 0, 0); /* reset all controllers */ + ev.data.control.param = + MIDI_CTL_RESET_CONTROLLERS; + snd_seq_oss_dispatch(dp, &ev, 0, 0); ev.type = SNDRV_SEQ_EVENT_PITCHBEND; ev.data.control.value = 0; - snd_seq_oss_dispatch(dp, &ev, 0, 0); /* bender off */ + snd_seq_oss_dispatch(dp, &ev, 0, 0); } } } -- cgit v0.10.2 From 2d4b842014dc76a81abced47ef27177eedb9deba Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 13 Jul 2009 13:52:46 +0200 Subject: sound: rawmidi: disable active-sensing-on-close by default Sending an Active Sensing message when closing a port can interfere with the following data if the port is reopened and a note-on is sent before the device's timeout has elapsed. Therefore, it is better to disable this setting by default. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 473247c..c0adc14 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -274,7 +274,7 @@ static int open_substream(struct snd_rawmidi *rmidi, return err; substream->opened = 1; if (substream->use_count++ == 0) - substream->active_sensing = 1; + substream->active_sensing = 0; if (mode & SNDRV_RAWMIDI_LFLG_APPEND) substream->append = 1; rmidi->streams[substream->stream].substream_opened++; diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 45cf5c1..ebaf1b5 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -237,6 +237,7 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info memset(¶ms, 0, sizeof(params)); params.avail_min = 1; params.buffer_size = output_buffer_size; + params.no_active_sensing = 1; if ((err = snd_rawmidi_output_params(msynth->output_rfile.output, ¶ms)) < 0) { snd_rawmidi_kernel_release(&msynth->output_rfile); return err; -- cgit v0.10.2 From 78df617acf83745908ae71f322e084284054ea66 Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Sun, 12 Jul 2009 22:17:54 +0200 Subject: ALSA: azt3328: fix previous breakage, improve suspend, cleanups - fix my previous codec activity breakage (_non-warned_ variable assignment issue) - convert suspend/resume to 32bit I/O access (I/O is painful; to improve suspend/resume performance) - change DEBUG_PLAY_REC to DEBUG_CODEC for consistency - printk cleanup - some logging improvements - minor cleanup/improvements The variable assignment issue above was a conditional assignment to the call_function variable (this ended with the non-preinitialized variable not getting assigned in some cases, thus a dangling stack value, yet gcc 4.3.3 unbelievably did _NOT_ warn about it in this case!!), needed to change this into _always_ assigning the check result. Practical result of this bug was that when shutting down _either_ playback or capture, _both_ streams dropped dead :P Tested, working (plus resume) and checkpatch.pl:ed on 2.6.30-rc5, applies cleanly to 2.6.30 proper with my previous (committed) patches applied. Signed-off-by: Andreas Mohr Signed-off-by: Takashi Iwai diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 39dfdaa..8451a01 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -15,7 +15,7 @@ * has very good support out of the box; * just to make sure that the right people hit this and get to know that, * despite the high level of Internet ignorance - as usual :-P - - * about Linux support for this card) + * about very good support for this card - on Linux!) * * GPL LICENSE * This program is free software; you can redistribute it and/or modify @@ -222,22 +222,23 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); #define DEBUG_MISC 0 #define DEBUG_CALLS 0 #define DEBUG_MIXER 0 -#define DEBUG_PLAY_REC 0 +#define DEBUG_CODEC 0 #define DEBUG_IO 0 #define DEBUG_TIMER 0 #define DEBUG_GAME 0 +#define DEBUG_PM 0 #define MIXER_TESTING 0 #if DEBUG_MISC -#define snd_azf3328_dbgmisc(format, args...) printk(KERN_ERR format, ##args) +#define snd_azf3328_dbgmisc(format, args...) printk(KERN_DEBUG format, ##args) #else #define snd_azf3328_dbgmisc(format, args...) #endif #if DEBUG_CALLS #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) -#define snd_azf3328_dbgcallenter() printk(KERN_ERR "--> %s\n", __func__) -#define snd_azf3328_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__) +#define snd_azf3328_dbgcallenter() printk(KERN_DEBUG "--> %s\n", __func__) +#define snd_azf3328_dbgcallleave() printk(KERN_DEBUG "<-- %s\n", __func__) #else #define snd_azf3328_dbgcalls(format, args...) #define snd_azf3328_dbgcallenter() @@ -250,10 +251,10 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); #define snd_azf3328_dbgmixer(format, args...) #endif -#if DEBUG_PLAY_REC -#define snd_azf3328_dbgplay(format, args...) printk(KERN_DEBUG format, ##args) +#if DEBUG_CODEC +#define snd_azf3328_dbgcodec(format, args...) printk(KERN_DEBUG format, ##args) #else -#define snd_azf3328_dbgplay(format, args...) +#define snd_azf3328_dbgcodec(format, args...) #endif #if DEBUG_MISC @@ -268,6 +269,12 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); #define snd_azf3328_dbggame(format, args...) #endif +#if DEBUG_PM +#define snd_azf3328_dbgpm(format, args...) printk(KERN_DEBUG format, ##args) +#else +#define snd_azf3328_dbgpm(format, args...) +#endif + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); @@ -334,12 +341,12 @@ struct snd_azf3328 { #ifdef CONFIG_PM /* register value containers for power management - * Note: not always full I/O range preserved (just like Win driver!) */ - u16 saved_regs_ctrl[AZF_IO_SIZE_CTRL_PM / 2]; - u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2]; - u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; - u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2]; - u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2]; + * Note: not always full I/O range preserved (similar to Win driver!) */ + u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4]; + u32 saved_regs_game[AZF_ALIGN(AZF_IO_SIZE_GAME_PM) / 4]; + u32 saved_regs_mpu[AZF_ALIGN(AZF_IO_SIZE_MPU_PM) / 4]; + u32 saved_regs_opl3[AZF_ALIGN(AZF_IO_SIZE_OPL3_PM) / 4]; + u32 saved_regs_mixer[AZF_ALIGN(AZF_IO_SIZE_MIXER_PM) / 4]; #endif }; @@ -1029,19 +1036,20 @@ snd_azf3328_ctrl_reg_6AH_update(struct snd_azf3328 *chip, bool enable ) { - if (enable) - chip->shadow_reg_ctrl_6AH &= ~bitmask; - else + bool do_mask = !enable; + if (do_mask) chip->shadow_reg_ctrl_6AH |= bitmask; - snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n", - bitmask, enable, chip->shadow_reg_ctrl_6AH); + else + chip->shadow_reg_ctrl_6AH &= ~bitmask; + snd_azf3328_dbgcodec("6AH_update mask 0x%04x do_mask %d: val 0x%04x\n", + bitmask, do_mask, chip->shadow_reg_ctrl_6AH); snd_azf3328_ctrl_outw(chip, IDX_IO_6AH, chip->shadow_reg_ctrl_6AH); } static inline void snd_azf3328_ctrl_enable_codecs(struct snd_azf3328 *chip, bool enable) { - snd_azf3328_dbgplay("codec_enable %d\n", enable); + snd_azf3328_dbgcodec("codec_enable %d\n", enable); /* no idea what exactly is being done here, but I strongly assume it's * PM related */ snd_azf3328_ctrl_reg_6AH_update( @@ -1058,7 +1066,7 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; bool need_change = (codec->running != enable); - snd_azf3328_dbgplay( + snd_azf3328_dbgcodec( "codec_activity: %s codec, enable %d, need_change %d\n", codec->name, enable, need_change ); @@ -1081,11 +1089,11 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, (which globally shuts down operation of codecs) only in case the other codecs are currently not active either! */ - if ((!chip->codecs[peer_codecs[codec_type].other1] - .running) - && (!chip->codecs[peer_codecs[codec_type].other2] - .running)) - call_function = 1; + call_function = + ((!chip->codecs[peer_codecs[codec_type].other1] + .running) + && (!chip->codecs[peer_codecs[codec_type].other2] + .running)); } if (call_function) snd_azf3328_ctrl_enable_codecs(chip, enable); @@ -1097,8 +1105,8 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, chip, codec_type ); + codec->running = enable; } - codec->running = enable; } static void @@ -1114,15 +1122,16 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, if (!codec->running) { /* AZF3328 uses a two buffer pointer DMA transfer approach */ - unsigned long flags; + unsigned long flags, addr_area2; /* width 32bit (prevent overflow): */ - u32 addr_area2, count_areas, lengths; + u32 count_areas, lengths; count_areas = size/2; addr_area2 = addr+count_areas; count_areas--; /* max. index */ - snd_azf3328_dbgplay("set DMA: buf1 %08lx[%lu], buf2 %08lx[%lu]\n", addr, count_areas, addr_area2, count_areas); + snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n", + addr, count_areas, addr_area2, count_areas); /* build combined I/O buffer length word */ lengths = (count_areas << 16) | (count_areas); @@ -1176,7 +1185,7 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, switch (cmd) { case SNDRV_PCM_TRIGGER_START: - snd_azf3328_dbgplay("START %s\n", codec->name); + snd_azf3328_dbgcodec("START %s\n", codec->name); if (is_playback_codec) { /* mute WaveOut (avoid clicking during setup) */ @@ -1243,10 +1252,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, ); } - snd_azf3328_dbgplay("STARTED %s\n", codec->name); + snd_azf3328_dbgcodec("STARTED %s\n", codec->name); break; case SNDRV_PCM_TRIGGER_RESUME: - snd_azf3328_dbgplay("RESUME %s\n", codec->name); + snd_azf3328_dbgcodec("RESUME %s\n", codec->name); /* resume codec if we were active */ spin_lock(&chip->reg_lock); if (codec->running) @@ -1258,7 +1267,7 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, spin_unlock(&chip->reg_lock); break; case SNDRV_PCM_TRIGGER_STOP: - snd_azf3328_dbgplay("STOP %s\n", codec->name); + snd_azf3328_dbgcodec("STOP %s\n", codec->name); if (is_playback_codec) { /* mute WaveOut (avoid clicking during setup) */ @@ -1294,10 +1303,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, ); } - snd_azf3328_dbgplay("STOPPED %s\n", codec->name); + snd_azf3328_dbgcodec("STOPPED %s\n", codec->name); break; case SNDRV_PCM_TRIGGER_SUSPEND: - snd_azf3328_dbgplay("SUSPEND %s\n", codec->name); + snd_azf3328_dbgcodec("SUSPEND %s\n", codec->name); /* make sure codec is stopped */ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, snd_azf3328_codec_inw( @@ -1312,7 +1321,7 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); break; default: - printk(KERN_ERR "FIXME: unknown trigger mode!\n"); + snd_printk(KERN_ERR "FIXME: unknown trigger mode!\n"); return -EINVAL; } @@ -1358,7 +1367,7 @@ snd_azf3328_codec_pointer(struct snd_pcm_substream *substream, /* calculate offset */ result -= bufptr; frmres = bytes_to_frames( substream->runtime, result); - snd_azf3328_dbgplay("%s @ 0x%8lx, frames %8ld\n", + snd_azf3328_dbgcodec("%s @ 0x%8lx, frames %8ld\n", codec->name, result, frmres); return frmres; } @@ -1607,7 +1616,7 @@ snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip) static inline void snd_azf3328_irq_log_unknown_type(u8 which) { - snd_azf3328_dbgplay( + snd_azf3328_dbgcodec( "azt3328: unknown IRQ type (%x) occurred, please report!\n", which ); @@ -1636,12 +1645,9 @@ snd_azf3328_codec_interrupt(struct snd_azf3328 *chip, u8 status) snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); spin_unlock(&chip->reg_lock); - if ((chip->pcm[codec_type]) - && (chip->codecs[codec_type].substream)) { - snd_pcm_period_elapsed( - chip->codecs[codec_type].substream - ); - snd_azf3328_dbgplay("%s period done (#%x), @ %x\n", + if ((chip->pcm[codec_type]) && (codec->substream)) { + snd_pcm_period_elapsed(codec->substream); + snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n", codec->name, which, snd_azf3328_codec_inl( @@ -1660,7 +1666,7 @@ snd_azf3328_interrupt(int irq, void *dev_id) { struct snd_azf3328 *chip = dev_id; u8 status; -#if DEBUG_PLAY_REC +#if DEBUG_CODEC static unsigned long irq_count; #endif @@ -1673,14 +1679,14 @@ snd_azf3328_interrupt(int irq, void *dev_id) )) return IRQ_NONE; /* must be interrupt for another device */ - snd_azf3328_dbgplay( + snd_azf3328_dbgcodec( "irq_count %ld! IDX_IO_IRQSTATUS %04x\n", irq_count++ /* debug-only */, status ); if (status & IRQ_TIMER) { - /* snd_azf3328_dbgplay("timer %ld\n", + /* snd_azf3328_dbgcodec("timer %ld\n", snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK ); */ @@ -1690,7 +1696,7 @@ snd_azf3328_interrupt(int irq, void *dev_id) spin_lock(&chip->reg_lock); snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); spin_unlock(&chip->reg_lock); - snd_azf3328_dbgplay("azt3328: timer IRQ\n"); + snd_azf3328_dbgcodec("azt3328: timer IRQ\n"); } if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) @@ -1706,7 +1712,7 @@ snd_azf3328_interrupt(int irq, void *dev_id) /* hmm, do we have to ack the IRQ here somehow? * If so, then I don't know how yet... */ - snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); + snd_azf3328_dbgcodec("azt3328: MPU401 IRQ\n"); } return IRQ_HANDLED; } @@ -2091,7 +2097,7 @@ snd_azf3328_test_bit(unsigned unsigned reg, int bit) outb(val, reg); - printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", + printk(KERN_DEBUG "reg %04x bit %d: %02x %02x %02x\n", reg, bit, val, valoff, valon ); } @@ -2298,8 +2304,11 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) card->private_data = chip; + /* chose to use MPU401_HW_AZT2320 ID instead of MPU401_HW_MPU401, + since our hardware ought to be similar, thus use same ID. */ err = snd_mpu401_uart_new( - card, 0, MPU401_HW_MPU401, chip->mpu_io, MPU401_INFO_INTEGRATED, + card, 0, + MPU401_HW_AZT2320, chip->mpu_io, MPU401_INFO_INTEGRATED, pci->irq, 0, &chip->rmidi ); if (err < 0) { @@ -2342,7 +2351,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) goto out_err; #ifdef MODULE - printk( + printk(KERN_INFO "azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n" "azt3328: Hardware was completely undocumented, unfortunately.\n" "azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n" @@ -2377,37 +2386,52 @@ snd_azf3328_remove(struct pci_dev *pci) } #ifdef CONFIG_PM +static inline void +snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs) +{ + unsigned reg; + + for (reg = 0; reg < count; ++reg) { + *saved_regs = inl(io_addr); + snd_azf3328_dbgpm("suspend: io 0x%04lx: 0x%08x\n", + io_addr, *saved_regs); + ++saved_regs; + io_addr += sizeof(*saved_regs); + } +} + static int snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct snd_azf3328 *chip = card->private_data; - unsigned reg; + u16 *saved_regs_ctrl_u16; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]); snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]); - for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) - chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2); + snd_azf3328_suspend_regs(chip->mixer_io, + ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer); /* make sure to disable master volume etc. to prevent looping sound */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); - for (reg = 0; reg < AZF_IO_SIZE_CTRL_PM / 2; ++reg) - chip->saved_regs_ctrl[reg] = inw(chip->ctrl_io + reg * 2); + snd_azf3328_suspend_regs(chip->ctrl_io, + ARRAY_SIZE(chip->saved_regs_ctrl), chip->saved_regs_ctrl); /* manually store the one currently relevant write-only reg, too */ - chip->saved_regs_ctrl[IDX_IO_6AH / 2] = chip->shadow_reg_ctrl_6AH; + saved_regs_ctrl_u16 = (u16 *)chip->saved_regs_ctrl; + saved_regs_ctrl_u16[IDX_IO_6AH / 2] = chip->shadow_reg_ctrl_6AH; - for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) - chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) - chip->saved_regs_mpu[reg] = inw(chip->mpu_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) - chip->saved_regs_opl3[reg] = inw(chip->opl3_io + reg * 2); + snd_azf3328_suspend_regs(chip->game_io, + ARRAY_SIZE(chip->saved_regs_game), chip->saved_regs_game); + snd_azf3328_suspend_regs(chip->mpu_io, + ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu); + snd_azf3328_suspend_regs(chip->opl3_io, + ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3); pci_disable_device(pci); pci_save_state(pci); @@ -2415,12 +2439,28 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) return 0; } +static inline void +snd_azf3328_resume_regs(const u32 *saved_regs, + unsigned long io_addr, + unsigned count +) +{ + unsigned reg; + + for (reg = 0; reg < count; ++reg) { + outl(*saved_regs, io_addr); + snd_azf3328_dbgpm("resume: io 0x%04lx: 0x%08x --> 0x%08x\n", + io_addr, *saved_regs, inl(io_addr)); + ++saved_regs; + io_addr += sizeof(*saved_regs); + } +} + static int snd_azf3328_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); const struct snd_azf3328 *chip = card->private_data; - unsigned reg; pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); @@ -2432,16 +2472,24 @@ snd_azf3328_resume(struct pci_dev *pci) } pci_set_master(pci); - for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) - outw(chip->saved_regs_game[reg], chip->game_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) - outw(chip->saved_regs_mpu[reg], chip->mpu_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) - outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) - outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2); - for (reg = 0; reg < AZF_IO_SIZE_CTRL_PM / 2; ++reg) - outw(chip->saved_regs_ctrl[reg], chip->ctrl_io + reg * 2); + snd_azf3328_resume_regs(chip->saved_regs_game, chip->game_io, + ARRAY_SIZE(chip->saved_regs_game)); + snd_azf3328_resume_regs(chip->saved_regs_mpu, chip->mpu_io, + ARRAY_SIZE(chip->saved_regs_mpu)); + snd_azf3328_resume_regs(chip->saved_regs_opl3, chip->opl3_io, + ARRAY_SIZE(chip->saved_regs_opl3)); + + snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io, + ARRAY_SIZE(chip->saved_regs_mixer)); + + /* unfortunately with 32bit transfers, IDX_MIXER_PLAY_MASTER (0x02) + and IDX_MIXER_RESET (offset 0x00) get touched at the same time, + resulting in a mixer reset condition persisting until _after_ + master vol was restored. Thus master vol needs an extra restore. */ + outw(((u16 *)chip->saved_regs_mixer)[1], chip->mixer_io + 2); + + snd_azf3328_resume_regs(chip->saved_regs_ctrl, chip->ctrl_io, + ARRAY_SIZE(chip->saved_regs_ctrl)); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h index 11d4b10..6f46b97 100644 --- a/sound/pci/azt3328.h +++ b/sound/pci/azt3328.h @@ -120,8 +120,10 @@ enum azf_freq_t { #define IDX_IO_IRQSTATUS 0x64 /* some IRQ bit in here might also be used to signal a power-management timer * timeout, to request shutdown of the chip (e.g. AD1815JS has such a thing). - * Some OPL3 hardware (e.g. in LM4560) has some special timer hardware which - * can trigger an OPL3 timer IRQ, so maybe there's such a thing as well... */ + * OPL3 hardware contains several timers which confusingly in most cases + * are NOT routed to an IRQ, but some designs (e.g. LM4560) DO support that, + * so I wouldn't be surprised at all to discover that AZF3328 + * supports that thing as well... */ #define IRQ_PLAYBACK 0x0001 #define IRQ_RECORDING 0x0002 @@ -129,8 +131,8 @@ enum azf_freq_t { #define IRQ_GAMEPORT 0x0008 /* Interrupt of Digital(ly) Enhanced Game Port */ #define IRQ_MPU401 0x0010 #define IRQ_TIMER 0x0020 /* DirectX timer */ - #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly I2S port? */ - #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly I2S port? */ + #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly OPL3 timer? */ + #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly OPL3 timer? */ #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ /* this is set to e.g. 0x3ff or 0x300, and writable; * maybe some buffer limit, but I couldn't find out more, PU:0x00ff: */ @@ -193,7 +195,7 @@ enum azf_freq_t { /*** Gameport area port indices ***/ /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ #define AZF_IO_SIZE_GAME 0x08 -#define AZF_IO_SIZE_GAME_PM 0x06 +#define AZF_IO_SIZE_GAME_PM 0x06 enum { AZF_GAME_LEGACY_IO_PORT = 0x200 @@ -274,6 +276,7 @@ enum { #define AZF_IO_SIZE_MPU_PM 0x04 /*** OPL3 synth ***/ +/* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ #define AZF_IO_SIZE_OPL3 0x08 #define AZF_IO_SIZE_OPL3_PM 0x06 /* hmm, given that a standard OPL3 has 4 registers only, @@ -333,4 +336,7 @@ enum { #define SET_CHAN_LEFT 1 #define SET_CHAN_RIGHT 2 +/* helper macro to align I/O port ranges to 32bit I/O width */ +#define AZF_ALIGN(x) (((x) + 3) & (~3)) + #endif /* __SOUND_AZT3328_H */ -- cgit v0.10.2 From 4b75e9476737dffef44a66818a4a481edd2512a1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 15 Jul 2009 10:36:51 +0100 Subject: ASoC: Error out if we can't determine a suitable WM9081 sysclk Due to the flexibility of the WM9081 FLL this should never happen in a real system. Reported-by: Jaswinder Singh Rajput Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index dbe2059..156f2a4 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -707,6 +707,10 @@ static int configure_clock(struct snd_soc_codec *codec) target > 3000000) break; } + + if (i == ARRAY_SIZE(clk_sys_rates)) + return -EINVAL; + } else if (wm9081->fs) { for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) { new_sysclk = clk_sys_rates[i].ratio @@ -714,6 +718,10 @@ static int configure_clock(struct snd_soc_codec *codec) if (new_sysclk > 3000000) break; } + + if (i == ARRAY_SIZE(clk_sys_rates)) + return -EINVAL; + } else { new_sysclk = 12288000; } -- cgit v0.10.2 From faae890883624e14a328863eafabf54a36698774 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 15 Jul 2009 18:37:48 +0800 Subject: crypto: padlock - Fix compile error on i386 The previous change to allow hashing from states other than the initial broke compilation on i386 because the inline assembly tried to squeeze a u64 into a 32-bit register. As we've already checked for 32-bit overflows we can simply truncate it to u32, or unsigned long so that we don't truncate at all on x86-64. Signed-off-by: Herbert Xu diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index fb6e6c3..a936ba4 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -103,7 +103,8 @@ static int padlock_sha1_finup(struct shash_desc *desc, const u8 *in, ts_state = irq_ts_save(); asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */ : \ - : "c"(state.count + count), "a"(state.count), \ + : "c"((unsigned long)state.count + count), \ + "a"((unsigned long)state.count), \ "S"(in), "D"(result)); irq_ts_restore(ts_state); @@ -165,7 +166,8 @@ static int padlock_sha256_finup(struct shash_desc *desc, const u8 *in, ts_state = irq_ts_save(); asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */ : \ - : "c"(state.count + count), "a"(state.count), \ + : "c"((unsigned long)state.count + count), \ + "a"((unsigned long)state.count), \ "S"(in), "D"(result)); irq_ts_restore(ts_state); -- cgit v0.10.2 From a70c522520d967844c01fa01459edc698fc54544 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 15 Jul 2009 20:39:05 +0800 Subject: crypto: ahash - Fix setkey crash When the alignment check was made unconditional for ahash we may end up crashing on shash algorithms because we're always calling alg->setkey instead of tfm->setkey. This patch fixes it. Signed-off-by: Herbert Xu diff --git a/crypto/ahash.c b/crypto/ahash.c index ac0798d..28a33d0 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -145,7 +145,6 @@ int crypto_hash_walk_first_compat(struct hash_desc *hdesc, static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) { - struct ahash_alg *ahash = crypto_ahash_alg(tfm); unsigned long alignmask = crypto_ahash_alignmask(tfm); int ret; u8 *buffer, *alignbuffer; @@ -158,7 +157,7 @@ static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); memcpy(alignbuffer, key, keylen); - ret = ahash->setkey(tfm, alignbuffer, keylen); + ret = tfm->setkey(tfm, alignbuffer, keylen); kzfree(buffer); return ret; } @@ -166,13 +165,12 @@ static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) { - struct ahash_alg *ahash = crypto_ahash_alg(tfm); unsigned long alignmask = crypto_ahash_alignmask(tfm); if ((unsigned long)key & alignmask) return ahash_setkey_unaligned(tfm, key, keylen); - return ahash->setkey(tfm, key, keylen); + return tfm->setkey(tfm, key, keylen); } EXPORT_SYMBOL_GPL(crypto_ahash_setkey); -- cgit v0.10.2 From fa64966473830219fe74952029ddb0e981a87749 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 15 Jul 2009 21:16:05 +0800 Subject: crypto: shash - Fix digest size offset When an shash algorithm is exported as ahash, ahash will access its digest size through hash_alg_common. That's why the shash layout needs to match hash_alg_common. This wasn't the case because the alignment weren't identical. This patch fixes the problem. Signed-off-by: Herbert Xu diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 3e89ce1..26cb1eb 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -75,7 +75,8 @@ struct shash_alg { unsigned int descsize; /* These fields must match hash_alg_common. */ - unsigned int digestsize; + unsigned int digestsize + __attribute__ ((aligned(__alignof__(struct hash_alg_common)))); unsigned int statesize; struct crypto_alg base; -- cgit v0.10.2 From cbc86b9161b40f95caee0e56381b68956fc28cc4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 15 Jul 2009 21:26:41 +0800 Subject: crypto: shash - Fix async finup handling of null digest When shash_ahash_finup encounters a null request, we end up not calling the underlying final function. This patch fixes that. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 834d9d2..7713b52 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -240,12 +240,17 @@ int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc) struct crypto_hash_walk walk; int nbytes; - for (nbytes = crypto_hash_walk_first(req, &walk); nbytes > 0; - nbytes = crypto_hash_walk_done(&walk, nbytes)) + nbytes = crypto_hash_walk_first(req, &walk); + if (!nbytes) + return crypto_shash_final(desc, req->result); + + do { nbytes = crypto_hash_walk_last(&walk) ? crypto_shash_finup(desc, walk.data, nbytes, req->result) : crypto_shash_update(desc, walk.data, nbytes); + nbytes = crypto_hash_walk_done(&walk, nbytes); + } while (nbytes > 0); return nbytes; } -- cgit v0.10.2 From b333b3d22822cf9b295990866798e9239c9dee72 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 Jun 2009 01:34:48 +0000 Subject: wireless extensions: make netns aware This makes wireless extensions netns aware. The tasklet sending the events is converted to a work struct so that we can rtnl_lock() in it. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 3882db1..5c5136f 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -80,6 +80,9 @@ struct net { #ifdef CONFIG_XFRM struct netns_xfrm xfrm; #endif +#ifdef CONFIG_WIRELESS_EXT + struct sk_buff_head wext_nlevents; +#endif struct net_generic *gen; }; diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 425f7d5..db8351a 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -1257,48 +1257,48 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, } #endif -/************************* EVENT PROCESSING *************************/ -/* - * Process events generated by the wireless layer or the driver. - * Most often, the event will be propagated through rtnetlink - */ +static int __net_init wext_pernet_init(struct net *net) +{ + skb_queue_head_init(&net->wext_nlevents); + return 0; +} -/* ---------------------------------------------------------------- */ -/* - * Locking... - * ---------- - * - * Thanks to Herbert Xu for fixing - * the locking issue in here and implementing this code ! - * - * The issue : wireless_send_event() is often called in interrupt context, - * while the Netlink layer can never be called in interrupt context. - * The fully formed RtNetlink events are queued, and then a tasklet is run - * to feed those to Netlink. - * The skb_queue is interrupt safe, and its lock is not held while calling - * Netlink, so there is no possibility of dealock. - * Jean II - */ +static void __net_exit wext_pernet_exit(struct net *net) +{ + skb_queue_purge(&net->wext_nlevents); +} -static struct sk_buff_head wireless_nlevent_queue; +static struct pernet_operations wext_pernet_ops = { + .init = wext_pernet_init, + .exit = wext_pernet_exit, +}; static int __init wireless_nlevent_init(void) { - skb_queue_head_init(&wireless_nlevent_queue); + return register_pernet_subsys(&wext_pernet_ops); return 0; } subsys_initcall(wireless_nlevent_init); -static void wireless_nlevent_process(unsigned long data) +/* Process events generated by the wireless layer or the driver. */ +static void wireless_nlevent_process(struct work_struct *work) { struct sk_buff *skb; + struct net *net; + + rtnl_lock(); - while ((skb = skb_dequeue(&wireless_nlevent_queue))) - rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); + for_each_net(net) { + while ((skb = skb_dequeue(&net->wext_nlevents))) + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, + GFP_KERNEL); + } + + rtnl_unlock(); } -static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); +static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process); /* ---------------------------------------------------------------- */ /* @@ -1348,9 +1348,6 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) struct sk_buff *skb; int err; - if (!net_eq(dev_net(dev), &init_net)) - return; - skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!skb) return; @@ -1363,8 +1360,8 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) } NETLINK_CB(skb).dst_group = RTNLGRP_LINK; - skb_queue_tail(&wireless_nlevent_queue, skb); - tasklet_schedule(&wireless_nlevent_tasklet); + skb_queue_tail(&dev_net(dev)->wext_nlevents, skb); + schedule_work(&wireless_nlevent_work); } /* ---------------------------------------------------------------- */ -- cgit v0.10.2 From 4f45b2cd4e78b5e49d7d41548345b879d3fdfeae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 Jun 2009 01:34:49 +0000 Subject: wext: optimise, comment and fix event sending The current function for sending events first allocates the event stream buffer, and then an skb to copy the event stream into. This can be done in one go. Also, the current function leaks kernel data to userspace in a 4 uninitialised bytes, initialise those explicitly. Finally also add a few useful comments, as opposed to the current comments. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/net/wireless/wext.c b/net/wireless/wext.c index db8351a..ee35e64 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -1300,22 +1300,15 @@ static void wireless_nlevent_process(struct work_struct *work) static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process); -/* ---------------------------------------------------------------- */ -/* - * Fill a rtnetlink message with our event data. - * Note that we propage only the specified event and don't dump the - * current wireless config. Dumping the wireless config is far too - * expensive (for each parameter, the driver need to query the hardware). - */ -static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev, - int type, char *event, int event_len) +static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev, + struct sk_buff *skb) { struct ifinfomsg *r; struct nlmsghdr *nlh; - nlh = nlmsg_put(skb, 0, 0, type, sizeof(*r), 0); - if (nlh == NULL) - return -EMSGSIZE; + nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0); + if (!nlh) + return NULL; r = nlmsg_data(nlh); r->ifi_family = AF_UNSPEC; @@ -1326,45 +1319,14 @@ static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev, r->ifi_change = 0; /* Wireless changes don't affect those flags */ NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); - /* Add the wireless events in the netlink packet */ - NLA_PUT(skb, IFLA_WIRELESS, event_len, event); - - return nlmsg_end(skb, nlh); -nla_put_failure: + return nlh; + nla_put_failure: nlmsg_cancel(skb, nlh); - return -EMSGSIZE; + return NULL; } -/* ---------------------------------------------------------------- */ -/* - * Create and broadcast and send it on the standard rtnetlink socket - * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c - * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field - * within a RTM_NEWLINK event. - */ -static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) -{ - struct sk_buff *skb; - int err; - - skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); - if (!skb) - return; - err = rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, event, event_len); - if (err < 0) { - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - return; - } - - NETLINK_CB(skb).dst_group = RTNLGRP_LINK; - skb_queue_tail(&dev_net(dev)->wext_nlevents, skb); - schedule_work(&wireless_nlevent_work); -} - -/* ---------------------------------------------------------------- */ /* * Main event dispatcher. Called from other parts and drivers. * Send the event on the appropriate channels. @@ -1383,6 +1345,9 @@ void wireless_send_event(struct net_device * dev, int wrqu_off = 0; /* Offset in wrqu */ /* Don't "optimise" the following variable, it will crash */ unsigned cmd_index; /* *MUST* be unsigned */ + struct sk_buff *skb; + struct nlmsghdr *nlh; + struct nlattr *nla; /* Get the description of the Event */ if (cmd <= SIOCIWLAST) { @@ -1430,25 +1395,60 @@ void wireless_send_event(struct net_device * dev, hdr_len = event_type_size[descr->header_type]; event_len = hdr_len + extra_len; - /* Create temporary buffer to hold the event */ - event = kmalloc(event_len, GFP_ATOMIC); - if (event == NULL) + /* + * The problem for 64/32 bit. + * + * On 64-bit, a regular event is laid out as follows: + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + * | event.len | event.cmd | p a d d i n g | + * | wrqu data ... (with the correct size) | + * + * This padding exists because we manipulate event->u, + * and 'event' is not packed. + * + * An iw_point event is laid out like this instead: + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + * | event.len | event.cmd | p a d d i n g | + * | iwpnt.len | iwpnt.flg | p a d d i n g | + * | extra data ... + * + * The second padding exists because struct iw_point is extended, + * but this depends on the platform... + * + * On 32-bit, all the padding shouldn't be there. + */ + + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + return; + + /* Send via the RtNetlink event channel */ + nlh = rtnetlink_ifinfo_prep(dev, skb); + if (WARN_ON(!nlh)) { + kfree_skb(skb); + return; + } + + /* Add the wireless events in the netlink packet */ + nla = nla_reserve(skb, IFLA_WIRELESS, event_len); + if (!nla) { + kfree_skb(skb); return; + } + event = nla_data(nla); - /* Fill event */ + /* Fill event - first clear to avoid data leaking */ + memset(event, 0, hdr_len); event->len = event_len; event->cmd = cmd; memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); - if (extra) + if (extra_len) memcpy(((char *) event) + hdr_len, extra, extra_len); - /* Send via the RtNetlink event channel */ - rtmsg_iwinfo(dev, (char *) event, event_len); - - /* Cleanup */ - kfree(event); + nlmsg_end(skb, nlh); - return; /* Always success, I guess ;-) */ + skb_queue_tail(&dev_net(dev)->wext_nlevents, skb); + schedule_work(&wireless_nlevent_work); } EXPORT_SYMBOL(wireless_send_event); -- cgit v0.10.2 From 1dacc76d0014a034b8aca14237c127d7c19d7726 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 11:26:02 +0000 Subject: net/compat/wext: send different messages to compat tasks Wireless extensions have the unfortunate problem that events are multicast netlink messages, and are not independent of pointer size. Thus, currently 32-bit tasks on 64-bit platforms cannot properly receive events and fail with all kinds of strange problems, for instance wpa_supplicant never notices disassociations, due to the way the 64-bit event looks (to a 32-bit process), the fact that the address is all zeroes is lost, it thinks instead it is 00:00:00:00:01:00. The same problem existed with the ioctls, until David Miller fixed those some time ago in an heroic effort. A different problem caused by this is that we cannot send the ASSOCREQIE/ASSOCRESPIE events because sending them causes a 32-bit wpa_supplicant on a 64-bit system to overwrite its internal information, which is worse than it not getting the information at all -- so we currently resort to sending a custom string event that it then parses. This, however, has a severe size limitation we are frequently hitting with modern access points; this limitation would can be lifted after this patch by sending the correct binary, not custom, event. A similar problem apparently happens for some other netlink users on x86_64 with 32-bit tasks due to the alignment for 64-bit quantities. In order to fix these problems, I have implemented a way to send compat messages to tasks. When sending an event, we send the non-compat event data together with a compat event data in skb_shinfo(main_skb)->frag_list. Then, when the event is read from the socket, the netlink code makes sure to pass out only the skb that is compatible with the task. This approach was suggested by David Miller, my original approach required always sending two skbs but that had various small problems. To determine whether compat is needed or not, I have used the MSG_CMSG_COMPAT flag, and adjusted the call path for recv and recvfrom to include it, even if those calls do not have a cmsg parameter. I have not solved one small part of the problem, and I don't think it is necessary to: if a 32-bit application uses read() rather than any form of recvmsg() it will still get the wrong (64-bit) event. However, neither do applications actually do this, nor would it be a regression. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 15874f9..7c4a94f 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -164,7 +164,7 @@ EXPORT(sysn32_call_table) PTR sys_connect PTR sys_accept PTR sys_sendto - PTR sys_recvfrom + PTR compat_sys_recvfrom PTR compat_sys_sendmsg /* 6045 */ PTR compat_sys_recvmsg PTR sys_shutdown diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 781e0f1..821fc97 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -378,8 +378,8 @@ sys_call_table: PTR sys_getsockname PTR sys_getsockopt PTR sys_listen - PTR sys_recv /* 4175 */ - PTR sys_recvfrom + PTR compat_sys_recv /* 4175 */ + PTR compat_sys_recvfrom PTR compat_sys_recvmsg PTR sys_send PTR compat_sys_sendmsg diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S index f061c4d..3762f6c 100644 --- a/arch/sparc/kernel/sys32.S +++ b/arch/sparc/kernel/sys32.S @@ -121,7 +121,7 @@ SIGN2(sys32_syslog, sys_syslog, %o0, %o2) SIGN1(sys32_umask, sys_umask, %o0) SIGN3(sys32_tgkill, sys_tgkill, %o0, %o1, %o2) SIGN1(sys32_sendto, sys_sendto, %o0) -SIGN1(sys32_recvfrom, sys_recvfrom, %o0) +SIGN1(sys32_recvfrom, compat_sys_recvfrom, %o0) SIGN3(sys32_socket, sys_socket, %o0, %o1, %o2) SIGN2(sys32_connect, sys_connect, %o0, %o2) SIGN2(sys32_bind, sys_bind, %o0, %o2) diff --git a/include/linux/wireless.h b/include/linux/wireless.h index cb24204..5b4c6c7 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -1132,6 +1132,14 @@ struct __compat_iw_event { }; #define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer) #define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length) + +/* Size of the various events for compat */ +#define IW_EV_COMPAT_CHAR_LEN (IW_EV_COMPAT_LCP_LEN + IFNAMSIZ) +#define IW_EV_COMPAT_UINT_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(__u32)) +#define IW_EV_COMPAT_FREQ_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq)) +#define IW_EV_COMPAT_PARAM_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param)) +#define IW_EV_COMPAT_ADDR_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr)) +#define IW_EV_COMPAT_QUAL_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality)) #define IW_EV_COMPAT_POINT_LEN \ (IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \ IW_EV_COMPAT_POINT_OFF) diff --git a/net/Kconfig b/net/Kconfig index 7051b97..041c35e 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -23,6 +23,26 @@ menuconfig NET if NET +config WANT_COMPAT_NETLINK_MESSAGES + bool + help + This option can be selected by other options that need compat + netlink messages. + +config COMPAT_NETLINK_MESSAGES + def_bool y + depends on COMPAT + depends on WIRELESS_EXT || WANT_COMPAT_NETLINK_MESSAGES + help + This option makes it possible to send different netlink messages + to tasks depending on whether the task is a compat task or not. To + achieve this, you need to set skb_shinfo(skb)->frag_list to the + compat skb before sending the skb, the netlink code will sort out + which message to actually pass to the task. + + Newly written code should NEVER need this option but do + compat-independent messages instead! + menu "Networking options" source "net/packet/Kconfig" diff --git a/net/compat.c b/net/compat.c index 8d73905..12728b1 100644 --- a/net/compat.c +++ b/net/compat.c @@ -743,6 +743,18 @@ asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, uns return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT); } +asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned flags) +{ + return sys_recv(fd, buf, len, flags | MSG_CMSG_COMPAT); +} + +asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len, + unsigned flags, struct sockaddr __user *addr, + int __user *addrlen) +{ + return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen); +} + asmlinkage long compat_sys_socketcall(int call, u32 __user *args) { int ret; @@ -788,10 +800,11 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args) ret = sys_sendto(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), a[5]); break; case SYS_RECV: - ret = sys_recv(a0, compat_ptr(a1), a[2], a[3]); + ret = compat_sys_recv(a0, compat_ptr(a1), a[2], a[3]); break; case SYS_RECVFROM: - ret = sys_recvfrom(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), compat_ptr(a[5])); + ret = compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3], + compat_ptr(a[4]), compat_ptr(a[5])); break; case SYS_SHUTDOWN: ret = sys_shutdown(a0,a1); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d46da6c..da3163d 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1361,7 +1361,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, struct netlink_sock *nlk = nlk_sk(sk); int noblock = flags&MSG_DONTWAIT; size_t copied; - struct sk_buff *skb; + struct sk_buff *skb, *frag __maybe_unused = NULL; int err; if (flags&MSG_OOB) @@ -1373,6 +1373,35 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, if (skb == NULL) goto out; +#ifdef CONFIG_COMPAT_NETLINK_MESSAGES + if (unlikely(skb_shinfo(skb)->frag_list)) { + bool need_compat = !!(flags & MSG_CMSG_COMPAT); + + /* + * If this skb has a frag_list, then here that means that + * we will have to use the frag_list skb for compat tasks + * and the regular skb for non-compat tasks. + * + * The skb might (and likely will) be cloned, so we can't + * just reset frag_list and go on with things -- we need to + * keep that. For the compat case that's easy -- simply get + * a reference to the compat skb and free the regular one + * including the frag. For the non-compat case, we need to + * avoid sending the frag to the user -- so assign NULL but + * restore it below before freeing the skb. + */ + if (need_compat) { + struct sk_buff *compskb = skb_shinfo(skb)->frag_list; + skb_get(compskb); + kfree_skb(skb); + skb = compskb; + } else { + frag = skb_shinfo(skb)->frag_list; + skb_shinfo(skb)->frag_list = NULL; + } + } +#endif + msg->msg_namelen = 0; copied = skb->len; @@ -1403,6 +1432,11 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, siocb->scm->creds = *NETLINK_CREDS(skb); if (flags & MSG_TRUNC) copied = skb->len; + +#ifdef CONFIG_COMPAT_NETLINK_MESSAGES + skb_shinfo(skb)->frag_list = frag; +#endif + skb_free_datagram(sk, skb); if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) diff --git a/net/wireless/wext.c b/net/wireless/wext.c index ee35e64..3fe3c2c 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -417,6 +417,21 @@ static const int event_type_size[] = { IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ }; +#ifdef CONFIG_COMPAT +static const int compat_event_type_size[] = { + IW_EV_COMPAT_LCP_LEN, /* IW_HEADER_TYPE_NULL */ + 0, + IW_EV_COMPAT_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, + IW_EV_COMPAT_UINT_LEN, /* IW_HEADER_TYPE_UINT */ + IW_EV_COMPAT_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ + IW_EV_COMPAT_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, + IW_EV_COMPAT_POINT_LEN, /* Without variable payload */ + IW_EV_COMPAT_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ + IW_EV_COMPAT_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ +}; +#endif /************************ COMMON SUBROUTINES ************************/ /* @@ -1348,6 +1363,22 @@ void wireless_send_event(struct net_device * dev, struct sk_buff *skb; struct nlmsghdr *nlh; struct nlattr *nla; +#ifdef CONFIG_COMPAT + struct __compat_iw_event *compat_event; + struct compat_iw_point compat_wrqu; + struct sk_buff *compskb; +#endif + + /* + * Nothing in the kernel sends scan events with data, be safe. + * This is necessary because we cannot fix up scan event data + * for compat, due to being contained in 'extra', but normally + * applications are required to retrieve the scan data anyway + * and no data is included in the event, this codifies that + * practice. + */ + if (WARN_ON(cmd == SIOCGIWSCAN && extra)) + extra = NULL; /* Get the description of the Event */ if (cmd <= SIOCIWLAST) { @@ -1446,7 +1477,54 @@ void wireless_send_event(struct net_device * dev, memcpy(((char *) event) + hdr_len, extra, extra_len); nlmsg_end(skb, nlh); +#ifdef CONFIG_COMPAT + hdr_len = compat_event_type_size[descr->header_type]; + event_len = hdr_len + extra_len; + compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!compskb) { + kfree_skb(skb); + return; + } + + /* Send via the RtNetlink event channel */ + nlh = rtnetlink_ifinfo_prep(dev, compskb); + if (WARN_ON(!nlh)) { + kfree_skb(skb); + kfree_skb(compskb); + return; + } + + /* Add the wireless events in the netlink packet */ + nla = nla_reserve(compskb, IFLA_WIRELESS, event_len); + if (!nla) { + kfree_skb(skb); + kfree_skb(compskb); + return; + } + compat_event = nla_data(nla); + + compat_event->len = event_len; + compat_event->cmd = cmd; + if (descr->header_type == IW_HEADER_TYPE_POINT) { + compat_wrqu.length = wrqu->data.length; + compat_wrqu.flags = wrqu->data.flags; + memcpy(&compat_event->pointer, + ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF, + hdr_len - IW_EV_COMPAT_LCP_LEN); + if (extra_len) + memcpy(((char *) compat_event) + hdr_len, + extra, extra_len); + } else { + /* extra_len must be zero, so no if (extra) needed */ + memcpy(&compat_event->pointer, wrqu, + hdr_len - IW_EV_COMPAT_LCP_LEN); + } + + nlmsg_end(compskb, nlh); + + skb_shinfo(skb)->frag_list = compskb; +#endif skb_queue_tail(&dev_net(dev)->wext_nlevents, skb); schedule_work(&wireless_nlevent_work); } -- cgit v0.10.2 From d0af93db12639c425adee795fabadedb52182346 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Wed, 15 Jul 2009 20:33:47 +0900 Subject: ASoC: add SOC_DOUBLE_EXT_TLV control type This is a macro for double controls with special callback function and TLV. The SOC_DOUBLE_EXT_TLV needs one register and two shifts for double controls. Signed-off-by: Joonyoung Shim Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 94fcc65..795a6b4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -135,6 +135,17 @@ .info = snd_soc_info_volsw, \ .get = xhandler_get, .put = xhandler_put, \ .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } +#define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\ + xhandler_get, xhandler_put, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ + .max = xmax, .invert = xinvert} } #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_bool_ext, \ -- cgit v0.10.2 From 3ce91d5a5a47eca6308c0a64f768c7a4466e0407 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Wed, 15 Jul 2009 20:33:50 +0900 Subject: ASoC: add SOC_DOUBLE_R_EXT_TLV control type This is a macro for double controls with special callback function and TLV. The SOC_DOUBLE_R_EXT_TLV needs two registers and one shift for double controls. Signed-off-by: Joonyoung Shim Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 795a6b4..756fb59 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -146,6 +146,17 @@ .private_value = (unsigned long)&(struct soc_mixer_control) \ {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ .max = xmax, .invert = xinvert} } +#define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\ + xhandler_get, xhandler_put, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw_2r, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ + .max = xmax, .invert = xinvert} } #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_bool_ext, \ -- cgit v0.10.2 From 9db9ed977d4f1a317f5f4d467d43025fa27223d8 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Wed, 15 Jul 2009 20:34:00 +0900 Subject: ASoC: MAX9877: add MAX9877 amp driver The MAX9877 combines a high-efficiency Class D audio power amplifier with a stereo Class AB capacitor-less DirectDrive headphone amplifier. The max9877_add_controls() is called to register the MAX9877 specific controls on machine specific init() of the machine driver. The datasheet for the MAX9877 can find at the following url: http://datasheets.maxim-ic.com/en/ds/MAX9877.pdf [Slight edit to sort the ALL_CODECS entries -- broonie.] Signed-off-by: Joonyoung Shim Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b674d3a..4219a41 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -17,6 +17,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C select SND_SOC_CS4270 if I2C + select SND_SOC_MAX9877 if I2C select SND_SOC_PCM3008 select SND_SOC_SPDIF select SND_SOC_SSM2602 if I2C @@ -188,3 +189,7 @@ config SND_SOC_WM9712 config SND_SOC_WM9713 tristate + +# Amp +config SND_SOC_MAX9877 + tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 301eb08..cf111c9 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -38,6 +38,9 @@ snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o +# Amp +snd-soc-max9877-objs := max9877.o + obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o @@ -77,3 +80,6 @@ obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o + +# Amp +obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c new file mode 100644 index 0000000..7df9a7c --- /dev/null +++ b/sound/soc/codecs/max9877.c @@ -0,0 +1,270 @@ +/* + * max9877.c -- amp driver for max9877 + * + * Copyright (C) 2009 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * + * 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 +#include +#include +#include +#include + +#include "max9877.h" + +static struct i2c_client *i2c; + +static u8 max9877_regs[5] = { 0x40, 0x00, 0x00, 0x00, 0x49 }; + +static void max9877_write_regs(void) +{ + if (i2c_master_send(i2c, max9877_regs, 5) != 5) + dev_err(&i2c->dev, "i2c write failed\n"); +} + +static int max9877_get_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int reg = mc->reg; + int reg2 = mc->rreg; + int shift = mc->shift; + int mask = mc->max; + + ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask; + + if (reg2) + ucontrol->value.integer.value[1] = + (max9877_regs[reg2] >> shift) & mask; + + return 0; +} + +static int max9877_set_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int reg = mc->reg; + int reg2 = mc->rreg; + int shift = mc->shift; + int mask = mc->max; + int change = 1; + int change2 = 1; + int ret = 0; + + if (((max9877_regs[reg] >> shift) & mask) == + ucontrol->value.integer.value[0]) + change = 0; + + if (reg2) + if (((max9877_regs[reg2] >> shift) & mask) == + ucontrol->value.integer.value[1]) + change2 = 0; + + if (change) { + max9877_regs[reg] &= ~(mask << shift); + max9877_regs[reg] |= ucontrol->value.integer.value[0] << shift; + ret = change; + } + + if (reg2 && change2) { + max9877_regs[reg2] &= ~(mask << shift); + max9877_regs[reg2] |= ucontrol->value.integer.value[1] << shift; + ret = change2; + } + + if (ret) + max9877_write_regs(); + + return ret; +} + +static int max9877_get_out_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 value = max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK; + + if (value) + value -= 1; + + ucontrol->value.integer.value[0] = value; + return 0; +} + +static int max9877_set_out_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 value = ucontrol->value.integer.value[0]; + + if (value) + value += 1; + + if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK) == value) + return 0; + + max9877_regs[MAX9877_OUTPUT_MODE] |= value; + max9877_write_regs(); + return 1; +} + +static int max9877_get_osc_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 value = (max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK); + + value = value >> MAX9877_OSC_OFFSET; + + ucontrol->value.integer.value[0] = value; + return 0; +} + +static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 value = ucontrol->value.integer.value[0]; + + value = value << MAX9877_OSC_OFFSET; + if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK) == value) + return 0; + + max9877_regs[MAX9877_OUTPUT_MODE] |= value; + max9877_write_regs(); + return 1; +} + +static const unsigned int max9877_pgain_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 1, TLV_DB_SCALE_ITEM(0, 900, 0), + 2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0), +}; + +static const unsigned int max9877_output_tlv[] = { + TLV_DB_RANGE_HEAD(4), + 0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1), + 8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0), + 16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0), + 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0), +}; + +static const char *max9877_out_mode[] = { + "INA -> SPK", + "INA -> HP", + "INA -> SPK and HP", + "INB -> SPK", + "INB -> HP", + "INB -> SPK and HP", + "INA + INB -> SPK", + "INA + INB -> HP", + "INA + INB -> SPK and HP", +}; + +static const char *max9877_osc_mode[] = { + "1176KHz", + "1100KHz", + "700KHz", +}; + +static const struct soc_enum max9877_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_out_mode), max9877_out_mode), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode), +}; + +static const struct snd_kcontrol_new max9877_controls[] = { + SOC_SINGLE_EXT_TLV("MAX9877 PGAINA Playback Volume", + MAX9877_INPUT_MODE, 0, 2, 0, + max9877_get_reg, max9877_set_reg, max9877_pgain_tlv), + SOC_SINGLE_EXT_TLV("MAX9877 PGAINB Playback Volume", + MAX9877_INPUT_MODE, 2, 2, 0, + max9877_get_reg, max9877_set_reg, max9877_pgain_tlv), + SOC_SINGLE_EXT_TLV("MAX9877 Amp Speaker Playback Volume", + MAX9877_SPK_VOLUME, 0, 31, 0, + max9877_get_reg, max9877_set_reg, max9877_output_tlv), + SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume", + MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0, + max9877_get_reg, max9877_set_reg, max9877_output_tlv), + SOC_SINGLE_EXT("MAX9877 INB Stereo Switch", + MAX9877_INPUT_MODE, 4, 1, 1, + max9877_get_reg, max9877_set_reg), + SOC_SINGLE_EXT("MAX9877 INA Stereo Switch", + MAX9877_INPUT_MODE, 5, 1, 1, + max9877_get_reg, max9877_set_reg), + SOC_SINGLE_EXT("MAX9877 Zero-crossing detection Switch", + MAX9877_INPUT_MODE, 6, 1, 0, + max9877_get_reg, max9877_set_reg), + SOC_SINGLE_EXT("MAX9877 Bypass Mode Switch", + MAX9877_OUTPUT_MODE, 6, 1, 0, + max9877_get_reg, max9877_set_reg), + SOC_SINGLE_EXT("MAX9877 Shutdown Mode Switch", + MAX9877_OUTPUT_MODE, 7, 1, 1, + max9877_get_reg, max9877_set_reg), + SOC_ENUM_EXT("MAX9877 Output Mode", max9877_enum[0], + max9877_get_out_mode, max9877_set_out_mode), + SOC_ENUM_EXT("MAX9877 Oscillator Mode", max9877_enum[1], + max9877_get_osc_mode, max9877_set_osc_mode), +}; + +/* This function is called from ASoC machine driver */ +int max9877_add_controls(struct snd_soc_codec *codec) +{ + return snd_soc_add_controls(codec, max9877_controls, + ARRAY_SIZE(max9877_controls)); +} +EXPORT_SYMBOL_GPL(max9877_add_controls); + +static int __devinit max9877_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + i2c = client; + + max9877_write_regs(); + + return 0; +} + +static __devexit int max9877_i2c_remove(struct i2c_client *client) +{ + i2c = NULL; + + return 0; +} + +static const struct i2c_device_id max9877_i2c_id[] = { + { "max9877", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max9877_i2c_id); + +static struct i2c_driver max9877_i2c_driver = { + .driver = { + .name = "max9877", + .owner = THIS_MODULE, + }, + .probe = max9877_i2c_probe, + .remove = __devexit_p(max9877_i2c_remove), + .id_table = max9877_i2c_id, +}; + +static int __init max9877_init(void) +{ + return i2c_add_driver(&max9877_i2c_driver); +} +module_init(max9877_init); + +static void __exit max9877_exit(void) +{ + i2c_del_driver(&max9877_i2c_driver); +} +module_exit(max9877_exit); + +MODULE_DESCRIPTION("ASoC MAX9877 amp driver"); +MODULE_AUTHOR("Joonyoung Shim "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max9877.h b/sound/soc/codecs/max9877.h new file mode 100644 index 0000000..6da7229 --- /dev/null +++ b/sound/soc/codecs/max9877.h @@ -0,0 +1,37 @@ +/* + * max9877.h -- amp driver for max9877 + * + * Copyright (C) 2009 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * + * 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. + * + */ + +#ifndef _MAX9877_H +#define _MAX9877_H + +#define MAX9877_INPUT_MODE 0x00 +#define MAX9877_SPK_VOLUME 0x01 +#define MAX9877_HPL_VOLUME 0x02 +#define MAX9877_HPR_VOLUME 0x03 +#define MAX9877_OUTPUT_MODE 0x04 + +/* MAX9877_INPUT_MODE */ +#define MAX9877_INB (1 << 4) +#define MAX9877_INA (1 << 5) +#define MAX9877_ZCD (1 << 6) + +/* MAX9877_OUTPUT_MODE */ +#define MAX9877_OUTMODE_MASK (15 << 0) +#define MAX9877_OSC_MASK (3 << 4) +#define MAX9877_OSC_OFFSET 4 +#define MAX9877_BYPASS (1 << 6) +#define MAX9877_SHDN (1 << 7) + +extern int max9877_add_controls(struct snd_soc_codec *codec); + +#endif -- cgit v0.10.2 From c86ae82605ef92594a0de809a8c588ae955fed63 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Jul 2009 11:31:10 -0700 Subject: gianfar: remove unused DECLARE_MAC_BUF The use of it was converted to %pM, but the variable stuck -- remove it now to not cause spurious warnings. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 4ae1d25..21f5b0a 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -304,7 +304,6 @@ static int gfar_probe(struct of_device *ofdev, u32 tempval; struct net_device *dev = NULL; struct gfar_private *priv = NULL; - DECLARE_MAC_BUF(mac); int err = 0; int len_devname; -- cgit v0.10.2 From e9b25f16cda88b33fe15b30c009912e6c471edda Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 16 Jul 2009 10:33:27 +0800 Subject: crypto: padlock - Fix hashing of partial blocks When we encounter partial blocks in finup, we'll invoke the xsha instruction with a bogus count that is not a multiple of the block size. This patch fixes it. Signed-off-by: Herbert Xu diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index a936ba4..76cb6b3 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -94,6 +94,7 @@ static int padlock_sha1_finup(struct shash_desc *desc, const u8 *in, memcpy(state.buffer + leftover, in, count); in = state.buffer; count += leftover; + state.count &= ~(SHA1_BLOCK_SIZE - 1); } } @@ -157,6 +158,7 @@ static int padlock_sha256_finup(struct shash_desc *desc, const u8 *in, memcpy(state.buf + leftover, in, count); in = state.buf; count += leftover; + state.count &= ~(SHA1_BLOCK_SIZE - 1); } } -- cgit v0.10.2 From 3e46a447396df99e2367fe1564651abaacc19c13 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Wed, 15 Jul 2009 10:42:09 -0700 Subject: ASoC: davinci: don't use clock names clock name strings are no longer passed on platform_data. Instead, we rely entirely on struct device and clkdev to find the right clock. Signed-off-by: Kevin Hilman Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index f7330e1..e5cd97b 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -528,7 +528,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) goto err_release_region; } - dev->clk = clk_get(&pdev->dev, pdata->clk_name); + dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) { ret = -ENODEV; goto err_free_mem; diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index b27aab6..f0c0347 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -764,7 +764,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) } pdata = pdev->dev.platform_data; - dev->clk = clk_get(&pdev->dev, pdata->clk_name); + dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) { ret = -ENODEV; goto err_release_region; -- cgit v0.10.2 From 1274738d85d0e25c4f82d83f50a6bcbe2397e9ea Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Thu, 16 Jul 2009 16:00:05 +0800 Subject: ASoC: new ad1938 codec driver based on asoc Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 4219a41..57f5b73 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -12,6 +12,7 @@ config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" select SND_SOC_L3 select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS + select SND_SOC_AD1938 if SPI_MASTER select SND_SOC_AD1980 if SND_SOC_AC97_BUS select SND_SOC_AD73311 if I2C select SND_SOC_AK4104 if SPI_MASTER @@ -66,6 +67,9 @@ config SND_SOC_AC97_CODEC tristate select SND_AC97_CODEC +config SND_SOC_AD1938 + tristate + config SND_SOC_AD1980 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf111c9..9a92f55 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -1,4 +1,5 @@ snd-soc-ac97-objs := ac97.o +snd-soc-ad1938-objs := ad1938.o snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o snd-soc-ak4104-objs := ak4104.o @@ -42,6 +43,7 @@ snd-soc-wm9713-objs := wm9713.o snd-soc-max9877-objs := max9877.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o +obj-$(CONFIG_SND_SOC_AD1938) += snd-soc-ad1938.o obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c new file mode 100644 index 0000000..3dc8091 --- /dev/null +++ b/sound/soc/codecs/ad1938.c @@ -0,0 +1,652 @@ +/* + * File: sound/soc/codecs/ad1938.c + * Author: Barry Song + * + * Created: June 04 2009 + * Description: Driver for AD1938 sound chip + * + * Modified: + * Copyright 2009 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or 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 "ad1938.h" + +/* codec private data */ +struct ad1938_priv { + struct snd_soc_codec codec; + u8 reg_cache[AD1938_NUM_REGS]; + +}; + +static struct snd_soc_codec *ad1938_codec; +struct snd_soc_codec_device soc_codec_dev_ad1938; +static int ad1938_register(struct ad1938_priv *ad1938); +static void ad1938_unregister(struct ad1938_priv *ad1938); + +/* + * AD1938 volume/mute/de-emphasis etc. controls + */ +static const char *ad1938_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"}; + +static const struct soc_enum ad1938_deemp_enum = + SOC_ENUM_SINGLE(AD1938_DAC_CTRL2, 1, 4, ad1938_deemp); + +static const struct snd_kcontrol_new ad1938_snd_controls[] = { + /* DAC volume control */ + SOC_DOUBLE_R("DAC1 Volume", AD1938_DAC_L1_VOL, + AD1938_DAC_R1_VOL, 0, 0xFF, 1), + SOC_DOUBLE_R("DAC2 Volume", AD1938_DAC_L2_VOL, + AD1938_DAC_R2_VOL, 0, 0xFF, 1), + SOC_DOUBLE_R("DAC3 Volume", AD1938_DAC_L3_VOL, + AD1938_DAC_R3_VOL, 0, 0xFF, 1), + SOC_DOUBLE_R("DAC4 Volume", AD1938_DAC_L4_VOL, + AD1938_DAC_R4_VOL, 0, 0xFF, 1), + + /* ADC switch control */ + SOC_DOUBLE("ADC1 Switch", AD1938_ADC_CTRL0, AD1938_ADCL1_MUTE, AD1938_ADCR1_MUTE, 1, 1), + SOC_DOUBLE("ADC2 Switch", AD1938_ADC_CTRL0, AD1938_ADCL2_MUTE, AD1938_ADCR2_MUTE, 1, 1), + + /* DAC switch control */ + SOC_DOUBLE("DAC1 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL1_MUTE, AD1938_DACR1_MUTE, 1, 1), + SOC_DOUBLE("DAC2 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL2_MUTE, AD1938_DACR2_MUTE, 1, 1), + SOC_DOUBLE("DAC3 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL3_MUTE, AD1938_DACR3_MUTE, 1, 1), + SOC_DOUBLE("DAC4 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL4_MUTE, AD1938_DACR4_MUTE, 1, 1), + + /* ADC high-pass filter */ + SOC_SINGLE("ADC High Pass Filter Switch", AD1938_ADC_CTRL0, + AD1938_ADC_HIGHPASS_FILTER, 1, 0), + + /* DAC de-emphasis */ + SOC_ENUM("Playback Deemphasis", ad1938_deemp_enum), +}; + +static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1), + SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0), +}; + +static const struct snd_soc_dapm_route audio_paths[] = { + { "DAC", NULL, "ADC_PWR" }, + { "ADC", NULL, "ADC_PWR" }, +}; + +/* + * DAI ops entries + */ + +static int ad1938_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + int reg; + + reg = codec->read(codec, AD1938_DAC_CTRL2); + reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg & (~AD1938_DAC_MASTER_MUTE); + codec->write(codec, AD1938_DAC_CTRL2, reg); + + return 0; +} + +static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd) +{ + int reg = codec->read(codec, AD1938_PLL_CLK_CTRL0); + reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg | AD1938_PLL_POWERDOWN; + codec->write(codec, AD1938_PLL_CLK_CTRL0, reg); + + return 0; +} + +static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int mask, int slots) +{ + struct snd_soc_codec *codec = dai->codec; + int dac_reg = codec->read(codec, AD1938_DAC_CTRL1); + int adc_reg = codec->read(codec, AD1938_ADC_CTRL2); + + dac_reg &= ~AD1938_DAC_CHAN_MASK; + adc_reg &= ~AD1938_ADC_CHAN_MASK; + + switch(slots) { + case 2: + dac_reg |= AD1938_DAC_2_CHANNELS << AD1938_DAC_CHAN_SHFT; + adc_reg |= AD1938_ADC_2_CHANNELS << AD1938_ADC_CHAN_SHFT; + break; + case 4: + dac_reg |= AD1938_DAC_4_CHANNELS << AD1938_DAC_CHAN_SHFT; + adc_reg |= AD1938_ADC_4_CHANNELS << AD1938_ADC_CHAN_SHFT; + break; + case 8: + dac_reg |= AD1938_DAC_8_CHANNELS << AD1938_DAC_CHAN_SHFT; + adc_reg |= AD1938_ADC_8_CHANNELS << AD1938_ADC_CHAN_SHFT; + break; + case 16: + dac_reg |= AD1938_DAC_16_CHANNELS << AD1938_DAC_CHAN_SHFT; + adc_reg |= AD1938_ADC_16_CHANNELS << AD1938_ADC_CHAN_SHFT; + break; + default: + return -EINVAL; + } + + codec->write(codec, AD1938_DAC_CTRL1, dac_reg); + codec->write(codec, AD1938_ADC_CTRL2, adc_reg); + + return 0; +} + +static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int adc_reg, dac_reg; + + adc_reg = codec->read(codec, AD1938_ADC_CTRL2); + dac_reg = codec->read(codec, AD1938_DAC_CTRL1); + + /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S with TDM) + * and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) + */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + adc_reg &= ~AD1938_ADC_SERFMT_MASK; + adc_reg |= AD1938_ADC_SERFMT_TDM; + break; + case SND_SOC_DAIFMT_DSP_A: + adc_reg &= ~AD1938_ADC_SERFMT_MASK; + adc_reg |= AD1938_ADC_SERFMT_AUX; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */ + adc_reg &= ~AD1938_ADC_LEFT_HIGH; + adc_reg &= ~AD1938_ADC_BCLK_INV; + dac_reg &= ~AD1938_DAC_LEFT_HIGH; + dac_reg &= ~AD1938_DAC_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */ + adc_reg |= AD1938_ADC_LEFT_HIGH; + adc_reg &= ~AD1938_ADC_BCLK_INV; + dac_reg |= AD1938_DAC_LEFT_HIGH; + dac_reg &= ~AD1938_DAC_BCLK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */ + adc_reg &= ~AD1938_ADC_LEFT_HIGH; + adc_reg |= AD1938_ADC_BCLK_INV; + dac_reg &= ~AD1938_DAC_LEFT_HIGH; + dac_reg |= AD1938_DAC_BCLK_INV; + break; + + case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */ + adc_reg |= AD1938_ADC_LEFT_HIGH; + adc_reg |= AD1938_ADC_BCLK_INV; + dac_reg |= AD1938_DAC_LEFT_HIGH; + dac_reg |= AD1938_DAC_BCLK_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */ + adc_reg |= AD1938_ADC_LCR_MASTER; + adc_reg |= AD1938_ADC_BCLK_MASTER; + dac_reg |= AD1938_DAC_LCR_MASTER; + dac_reg |= AD1938_DAC_BCLK_MASTER; + break; + case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */ + adc_reg |= AD1938_ADC_LCR_MASTER; + adc_reg &= ~AD1938_ADC_BCLK_MASTER; + dac_reg |= AD1938_DAC_LCR_MASTER; + dac_reg &= ~AD1938_DAC_BCLK_MASTER; + break; + case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */ + adc_reg &= ~AD1938_ADC_LCR_MASTER; + adc_reg |= AD1938_ADC_BCLK_MASTER; + dac_reg &= ~AD1938_DAC_LCR_MASTER; + dac_reg |= AD1938_DAC_BCLK_MASTER; + break; + case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */ + adc_reg &= ~AD1938_ADC_LCR_MASTER; + adc_reg &= ~AD1938_ADC_BCLK_MASTER; + dac_reg &= ~AD1938_DAC_LCR_MASTER; + dac_reg &= ~AD1938_DAC_BCLK_MASTER; + break; + default: + return -EINVAL; + } + + codec->write(codec, AD1938_ADC_CTRL2, adc_reg); + codec->write(codec, AD1938_DAC_CTRL1, dac_reg); + + return 0; +} + +static int ad1938_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int word_len = 0, reg = 0; + + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + word_len = 3; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + word_len = 1; + break; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S32_LE: + word_len = 0; + break; + } + + reg = codec->read(codec, AD1938_DAC_CTRL2); + reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len; + codec->write(codec, AD1938_DAC_CTRL2, reg); + + reg = codec->read(codec, AD1938_ADC_CTRL1); + reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len; + codec->write(codec, AD1938_ADC_CTRL1, reg); + + return 0; +} + +static int ad1938_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + ad1938_pll_powerctrl(codec, 1); + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + case SND_SOC_BIAS_OFF: + ad1938_pll_powerctrl(codec, 0); + break; + } + codec->bias_level = level; + return 0; +} + +/* + * interface to read/write ad1938 register + */ + +#define AD1938_SPI_ADDR 0x4 +#define AD1938_SPI_READ 0x1 +#define AD1938_SPI_BUFLEN 3 + +/* + * write to the ad1938 register space + */ + +static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 *reg_cache = codec->reg_cache; + int ret = 0; + + if(value != reg_cache[reg]) { + uint8_t buf[AD1938_SPI_BUFLEN]; + struct spi_transfer t = { + .tx_buf = buf, + .len = AD1938_SPI_BUFLEN, + }; + struct spi_message m; + + buf[0] = AD1938_SPI_ADDR << 1; + buf[1] = reg; + buf[2] = value; + spi_message_init(&m); + spi_message_add_tail(&t, &m); + if((ret = spi_sync(codec->control_data, &m)) == 0) + reg_cache[reg] = value; + } + + return ret; +} + +/* + * read from the ad1938 register space cache + */ + +static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *reg_cache = codec->reg_cache; + + if (reg >= codec->reg_cache_size) + return -EINVAL; + + return reg_cache[reg]; +} + +/* + * read from the ad1938 register space + */ + +static unsigned int ad1938_read_reg(struct snd_soc_codec *codec, unsigned int reg) +{ + char w_buf[AD1938_SPI_BUFLEN]; + char r_buf[AD1938_SPI_BUFLEN]; + int ret; + + struct spi_transfer t = { + .tx_buf = w_buf, + .rx_buf = r_buf, + .len = AD1938_SPI_BUFLEN, + }; + struct spi_message m; + + w_buf[0] = (AD1938_SPI_ADDR << 1) | AD1938_SPI_READ; + w_buf[1] = reg; + w_buf[2] = 0; + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + ret = spi_sync(codec->control_data, &m); + if (ret == 0) + return r_buf[2]; + else + return -EIO; +} + +static int ad1938_fill_cache(struct snd_soc_codec *codec) +{ + int i; + u8 *reg_cache = codec->reg_cache; + struct spi_device *spi = codec->control_data; + + for (i = 0; i < codec->reg_cache_size; i++) { + int ret = ad1938_read_reg(codec, i); + if (ret == -EIO) { + dev_err(&spi->dev, "AD1938 SPI read failure\n"); + return ret; + } + reg_cache[i] = ret; + } + + return 0; +} + +static int __devinit ad1938_spi_probe(struct spi_device *spi) +{ + struct snd_soc_codec *codec; + struct ad1938_priv *ad1938; + + ad1938 = kzalloc(sizeof(struct ad1938_priv), GFP_KERNEL); + if (ad1938 == NULL) + return -ENOMEM; + + codec = &ad1938->codec; + codec->control_data = spi; + codec->dev = &spi->dev; + + spi->dev.driver_data = ad1938; + + return ad1938_register(ad1938); +} + +static int __devexit ad1938_spi_remove(struct spi_device *spi) +{ + struct ad1938_priv *ad1938 = spi->dev.driver_data; + + ad1938_unregister(ad1938); + return 0; +} + +static struct spi_driver ad1938_spi_driver = { + .driver = { + .name = "ad1938-spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ad1938_spi_probe, + .remove = __devexit_p(ad1938_spi_remove), +}; + +static struct snd_soc_dai_ops ad1938_dai_ops = { + .hw_params = ad1938_hw_params, + .digital_mute = ad1938_mute, + .set_tdm_slot = ad1938_set_tdm_slot, + .set_fmt = ad1938_set_dai_fmt, +}; + +/* codec DAI instance */ +struct snd_soc_dai ad1938_dai = { + .name = "AD1938", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &ad1938_dai_ops, +}; +EXPORT_SYMBOL_GPL(ad1938_dai); + +static int ad1938_register(struct ad1938_priv *ad1938) +{ + int ret; + struct snd_soc_codec *codec = &ad1938->codec; + + if (ad1938_codec) { + dev_err(codec->dev, "Another ad1938 is registered\n"); + return -EINVAL; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + codec->private_data = ad1938; + codec->reg_cache = ad1938->reg_cache; + codec->reg_cache_size = AD1938_NUM_REGS; + codec->name = "AD1938"; + codec->owner = THIS_MODULE; + codec->dai = &ad1938_dai; + codec->num_dai = 1; + codec->write = ad1938_write_reg; + codec->read = ad1938_read_reg_cache; + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + ad1938_dai.dev = codec->dev; + ad1938_codec = codec; + + /* default setting for ad1938 */ + codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0); /* unmute dac channels */ + codec->write(codec, AD1938_DAC_CTRL2, 0x1A); /* de-emphasis: 48kHz, powedown dac */ + codec->write(codec, AD1938_DAC_CTRL0, 0x21); /* powerdown dac, dac tdm mode */ + codec->write(codec, AD1938_ADC_CTRL0, 0x3); /* high-pass filter enable */ + codec->write(codec, AD1938_ADC_CTRL1, 0x43); /* sata delay=1, adc aux mode */ + codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); /* pll input:mclki/xi */ + codec->write(codec, AD1938_PLL_CLK_CTRL1, 0x04); + + ad1938_fill_cache(codec); + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; + } + + ret = snd_soc_register_dai(&ad1938_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } + + return 0; +} + +static void ad1938_unregister(struct ad1938_priv *ad1938) +{ + ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&ad1938_dai); + snd_soc_unregister_codec(&ad1938->codec); + kfree(ad1938); + ad1938_codec = NULL; +} + +static int ad1938_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (ad1938_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = ad1938_codec; + codec = ad1938_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, ad1938_snd_controls, + ARRAY_SIZE(ad1938_snd_controls)); + snd_soc_dapm_new_controls(codec, ad1938_dapm_widgets, + ARRAY_SIZE(ad1938_dapm_widgets)); + snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); + snd_soc_dapm_new_widgets(codec); + + ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +/* power down chip */ +static int ad1938_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +#ifdef CONFIG_PM +static int ad1938_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + ad1938_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int ad1938_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + if (codec->suspend_bias_level == SND_SOC_BIAS_ON) + ad1938_set_bias_level(codec, SND_SOC_BIAS_ON); + + return 0; +} +#else +#define ad1938_suspend NULL +#define ad1938_resume NULL +#endif + +struct snd_soc_codec_device soc_codec_dev_ad1938 = { + .probe = ad1938_probe, + .remove = ad1938_remove, + .suspend = ad1938_suspend, + .resume = ad1938_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938); + +static int __init ad1938_init(void) +{ + int ret; + + ret = spi_register_driver(&ad1938_spi_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register ad1938 SPI driver: %d\n", + ret); + } + + return ret; +} +module_init(ad1938_init); + +static void __exit ad1938_exit(void) +{ + spi_unregister_driver(&ad1938_spi_driver); +} +module_exit(ad1938_exit); + +MODULE_DESCRIPTION("ASoC ad1938 driver"); +MODULE_AUTHOR("Barry Song "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ad1938.h b/sound/soc/codecs/ad1938.h new file mode 100644 index 0000000..fe3c48c --- /dev/null +++ b/sound/soc/codecs/ad1938.h @@ -0,0 +1,100 @@ +/* + * File: sound/soc/codecs/ad1836.h + * Based on: + * Author: Barry Song + * + * Created: May 25, 2009 + * Description: definitions for AD1938 registers + * + * Modified: + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __AD1938_H__ +#define __AD1938_H__ + +#define AD1938_PLL_CLK_CTRL0 0 +#define AD1938_PLL_POWERDOWN 0x01 +#define AD1938_PLL_CLK_CTRL1 1 +#define AD1938_DAC_CTRL0 2 +#define AD1938_DAC_POWERDOWN 0x01 +#define AD1938_DAC_SERFMT_MASK 0xC0 +#define AD1938_DAC_SERFMT_STEREO (0 << 6) +#define AD1938_DAC_SERFMT_TDM (1 << 6) +#define AD1938_DAC_CTRL1 3 +#define AD1938_DAC_2_CHANNELS 0 +#define AD1938_DAC_4_CHANNELS 1 +#define AD1938_DAC_8_CHANNELS 2 +#define AD1938_DAC_16_CHANNELS 3 +#define AD1938_DAC_CHAN_SHFT 1 +#define AD1938_DAC_CHAN_MASK (3 << AD1938_DAC_CHAN_SHFT) +#define AD1938_DAC_LCR_MASTER (1 << 4) +#define AD1938_DAC_BCLK_MASTER (1 << 5) +#define AD1938_DAC_LEFT_HIGH (1 << 3) +#define AD1938_DAC_BCLK_INV (1 << 7) +#define AD1938_DAC_CTRL2 4 +#define AD1938_DAC_WORD_LEN_MASK 0xC +#define AD1938_DAC_MASTER_MUTE 1 +#define AD1938_DAC_CHNL_MUTE 5 +#define AD1938_DACL1_MUTE 0 +#define AD1938_DACR1_MUTE 1 +#define AD1938_DACL2_MUTE 2 +#define AD1938_DACR2_MUTE 3 +#define AD1938_DACL3_MUTE 4 +#define AD1938_DACR3_MUTE 5 +#define AD1938_DACL4_MUTE 6 +#define AD1938_DACR4_MUTE 7 +#define AD1938_DAC_L1_VOL 6 +#define AD1938_DAC_R1_VOL 7 +#define AD1938_DAC_L2_VOL 8 +#define AD1938_DAC_R2_VOL 9 +#define AD1938_DAC_L3_VOL 10 +#define AD1938_DAC_R3_VOL 11 +#define AD1938_DAC_L4_VOL 12 +#define AD1938_DAC_R4_VOL 13 +#define AD1938_ADC_CTRL0 14 +#define AD1938_ADC_POWERDOWN 0x01 +#define AD1938_ADC_HIGHPASS_FILTER 1 +#define AD1938_ADCL1_MUTE 2 +#define AD1938_ADCR1_MUTE 3 +#define AD1938_ADCL2_MUTE 4 +#define AD1938_ADCR2_MUTE 5 +#define AD1938_ADC_CTRL1 15 +#define AD1938_ADC_SERFMT_MASK 0x60 +#define AD1938_ADC_SERFMT_STEREO (0 << 5) +#define AD1938_ADC_SERFMT_TDM (1 << 2) +#define AD1938_ADC_SERFMT_AUX (2 << 5) +#define AD1938_ADC_WORD_LEN_MASK 0x3 +#define AD1938_ADC_CTRL2 16 +#define AD1938_ADC_2_CHANNELS 0 +#define AD1938_ADC_4_CHANNELS 1 +#define AD1938_ADC_8_CHANNELS 2 +#define AD1938_ADC_16_CHANNELS 3 +#define AD1938_ADC_CHAN_SHFT 4 +#define AD1938_ADC_CHAN_MASK (3 << AD1938_ADC_CHAN_SHFT) +#define AD1938_ADC_LCR_MASTER (1 << 3) +#define AD1938_ADC_BCLK_MASTER (1 << 6) +#define AD1938_ADC_LEFT_HIGH (1 << 2) +#define AD1938_ADC_BCLK_INV (1 << 1) + +#define AD1938_NUM_REGS 17 + +extern struct snd_soc_dai ad1938_dai; +extern struct snd_soc_codec_device soc_codec_dev_ad1938; +#endif -- cgit v0.10.2 From 2a549c364aa11e658ae14b71861d25474e5808cf Mon Sep 17 00:00:00 2001 From: Sachin Sant Date: Thu, 16 Jul 2009 19:58:42 +0800 Subject: crypto: s390 - Fix sha build failure Use struct s390_sha_ctx instead of sha1/sha256_state struct to fix s390 crypto build break. Signed-off-by: Sachin Sant Signed-off-by: Herbert Xu diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index 2c5ec79..4a94378 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -59,7 +59,7 @@ static int sha1_export(struct shash_desc *desc, void *out) static int sha1_import(struct shash_desc *desc, const u8 *in) { - struct sha1_state *sctx = shash_desc_ctx(desc); + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); struct sha1_state *ictx = in; sctx->count = ictx->count; diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index 943a669..2bab519 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -55,7 +55,7 @@ static int sha256_export(struct shash_desc *desc, void *out) static int sha256_import(struct shash_desc *desc, const u8 *in) { - struct sha256_state *sctx = shash_desc_ctx(desc); + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); struct sha256_state *ictx = in; sctx->count = ictx->count; -- cgit v0.10.2 From 0fb67e982a1749b2cd477709838bf866028970ce Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 16 Jul 2009 14:46:57 +0100 Subject: ALSA: hda - Add CX20582 and OLPC XO-1.5 support This adds support for the Conexant CX20582 codec, based on code from http://www.linuxant.com/alsa-driver/alsa-driver-linuxant-1.0.19ppch12-1.noarch.rpm.zip This is the codec to be shipped in the OLPC XO-1.5, so this patch also includes an XO-specific profile. Resultant configuration: http://dev.laptop.org/~dsd/20090713/codec0.txt http://dev.laptop.org/~dsd/20090713/codec0.svg As the Linuxant code is structured differently to the other codecs, I was unable to cleanly reimplement everything in the generic and Dell profiles as more info is needed (e.g. codec graphs). I simplified those profiles so that hopefully it will not break anyone's audio. If it does, it may be worth returning -ENODEV from patch_cx5066 on non-OLPC systems, and then fixing snd_hda_codec_configure() to fall back on the generic parser, at least until support for other systems is figured out. Signed-off-by: Daniel Drake Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ac868c5..9d899ed 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -108,6 +108,8 @@ struct conexant_spec { struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; + unsigned int dell_automute; + unsigned int port_d_mode; }; static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, @@ -1908,6 +1910,480 @@ static int patch_cxt5051(struct hda_codec *codec) return 0; } +/* Conexant 5066 specific */ + +static hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; +static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; +static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; +#define CXT5066_SPDIF_OUT 0x21 + +static struct hda_channel_mode cxt5066_modes[1] = { + { 2, NULL }, +}; + +static void cxt5066_update_speaker(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + unsigned int pinctl; + + snd_printdd("CXT5066: update speaker, hp_present=%d\n", + spec->hp_present); + + /* Port A (HP) */ + pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0; + snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl); + + /* Port D (HP/LO) */ + pinctl = ((spec->hp_present & 2) && spec->cur_eapd) + ? spec->port_d_mode : 0; + snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl); + + /* CLASS_D AMP */ + pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl); + + if (spec->dell_automute) { + /* DELL AIO Port Rule: PortA > PortD > IntSpk */ + pinctl = (!(spec->hp_present & 1) && spec->cur_eapd) + ? PIN_OUT : 0; + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); + } +} + +/* turn on/off EAPD (+ mute HP) as a master switch */ +static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + + if (!cxt_eapd_put(kcontrol, ucontrol)) + return 0; + + cxt5066_update_speaker(codec); + return 1; +} + +/* toggle input of built-in and mic jack appropriately */ +static void cxt5066_automic(struct hda_codec *codec) +{ + static struct hda_verb ext_mic_present[] = { + /* enable external mic, port B */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + + /* switch to external mic input */ + {0x17, AC_VERB_SET_CONNECT_SEL, 0}, + + /* disable internal mic, port C */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {} + }; + static struct hda_verb ext_mic_absent[] = { + /* enable internal mic, port C */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + + /* switch to internal mic input */ + {0x17, AC_VERB_SET_CONNECT_SEL, 1}, + + /* disable external mic, port B */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {} + }; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x1a, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + if (present) { + snd_printdd("CXT5066: external microphone detected\n"); + snd_hda_sequence_write(codec, ext_mic_present); + } else { + snd_printdd("CXT5066: external microphone absent\n"); + snd_hda_sequence_write(codec, ext_mic_absent); + } +} + +/* mute internal speaker if HP is plugged */ +static void cxt5066_hp_automute(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + unsigned int portA, portD; + + /* Port A */ + portA = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + + /* Port D */ + portD = (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE) << 1; + + spec->hp_present = !!(portA | portD); + snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", + portA, portD, spec->hp_present); + cxt5066_update_speaker(codec); +} + +/* unsolicited event for jack sensing */ +static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) +{ + snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); + switch (res >> 26) { + case CONEXANT_HP_EVENT: + cxt5066_hp_automute(codec); + break; + case CONEXANT_MIC_EVENT: + cxt5066_automic(codec); + break; + } +} + +static const struct hda_input_mux cxt5066_analog_mic_boost = { + .num_items = 5, + .items = { + { "0dB", 0 }, + { "10dB", 1 }, + { "20dB", 2 }, + { "30dB", 3 }, + { "40dB", 4 }, + }, +}; + +static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + return snd_hda_input_mux_info(&cxt5066_analog_mic_boost, uinfo); +} + +static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + int val; + + val = snd_hda_codec_read(codec, 0x17, 0, + AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_OUTPUT); + + ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN; + return 0; +} + +static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; + unsigned int idx; + + if (!imux->num_items) + return 0; + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + + snd_hda_codec_write_cache(codec, 0x17, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | + imux->items[idx].index); + + return 1; +} + +static struct hda_input_mux cxt5066_capture_source = { + .num_items = 4, + .items = { + { "Mic B", 0 }, + { "Mic C", 1 }, + { "Mic E", 2 }, + { "Mic F", 3 }, + }, +}; + +static struct hda_bind_ctls cxt5066_bind_capture_vol_others = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), + 0 + }, +}; + +static struct hda_bind_ctls cxt5066_bind_capture_sw_others = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), + 0 + }, +}; + +static struct snd_kcontrol_new cxt5066_mixer_master[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), + {} +}; + +static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, + .info = snd_hda_mixer_amp_volume_info, + .get = snd_hda_mixer_amp_volume_get, + .put = snd_hda_mixer_amp_volume_put, + .tlv = { .c = snd_hda_mixer_amp_tlv }, + /* offset by 28 volume steps to limit minimum gain to -46dB */ + .private_value = + HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28), + }, + {} +}; + +static struct snd_kcontrol_new cxt5066_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = cxt_eapd_info, + .get = cxt_eapd_get, + .put = cxt5066_hp_master_sw_put, + .private_value = 0x1d, + }, + + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Mic Boost Capture Enum", + .info = cxt5066_mic_boost_mux_enum_info, + .get = cxt5066_mic_boost_mux_enum_get, + .put = cxt5066_mic_boost_mux_enum_put, + }, + + HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), + HDA_BIND_SW("Capture Switch", &cxt5066_bind_capture_sw_others), + {} +}; + +static struct hda_verb cxt5066_init_verbs[] = { + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ + {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ + + /* Speakers */ + {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* HP, Amp */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* DAC1 */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* no digital microphone support yet */ + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + + /* Audio input selector */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, + + /* SPDIF route: PCM */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, + {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, + + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* EAPD */ + {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ + + /* not handling these yet */ + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, + { } /* end */ +}; + +static struct hda_verb cxt5066_init_verbs_olpc[] = { + /* Port A: headphones */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* Port B: external microphone */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + + /* Port C: internal microphone */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + + /* Port D: unused */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + + /* Port E: unused, but has primary EAPD */ + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ + + /* Port F: unused */ + {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + + /* Port G: internal speakers */ + {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* DAC1 */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* DAC2: unused */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + + /* Disable digital microphone port */ + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + + /* Audio input selectors */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + + /* Disable SPDIF */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + + /* enable unsolicited events for Port A and B */ + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, + { } /* end */ +}; + +static struct hda_verb cxt5066_init_verbs_portd_lo[] = { + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + { } /* end */ +}; + +/* initialize jack-sensing, too */ +static int cxt5066_init(struct hda_codec *codec) +{ + snd_printdd("CXT5066: init\n"); + conexant_init(codec); + if (codec->patch_ops.unsol_event) { + cxt5066_hp_automute(codec); + cxt5066_automic(codec); + } + return 0; +} + +enum { + CXT5066_LAPTOP, /* Laptops w/ EAPD support */ + CXT5066_DELL_LAPTOP, /* Dell Laptop */ + CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ + CXT5066_MODELS +}; + +static const char *cxt5066_models[CXT5066_MODELS] = { + [CXT5066_LAPTOP] = "laptop", + [CXT5066_DELL_LAPTOP] = "dell-laptop", + [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", +}; + +static struct snd_pci_quirk cxt5066_cfg_tbl[] = { + SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", + CXT5066_LAPTOP), + SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", + CXT5066_DELL_LAPTOP), + {} +}; + +static int patch_cxt5066(struct hda_codec *codec) +{ + struct conexant_spec *spec; + int board_config; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + codec->spec = spec; + + codec->patch_ops = conexant_patch_ops; + codec->patch_ops.init = cxt5066_init; + + spec->dell_automute = 0; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); + spec->multiout.dac_nids = cxt5066_dac_nids; + spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT; + spec->num_adc_nids = 1; + spec->adc_nids = cxt5066_adc_nids; + spec->capsrc_nids = cxt5066_capsrc_nids; + spec->input_mux = &cxt5066_capture_source; + + spec->port_d_mode = PIN_HP; + + spec->num_init_verbs = 1; + spec->init_verbs[0] = cxt5066_init_verbs; + spec->num_channel_mode = ARRAY_SIZE(cxt5066_modes); + spec->channel_mode = cxt5066_modes; + spec->cur_adc = 0; + spec->cur_adc_idx = 0; + + board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, + cxt5066_models, cxt5066_cfg_tbl); + switch (board_config) { + default: + case CXT5066_LAPTOP: + spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; + spec->mixers[spec->num_mixers++] = cxt5066_mixers; + break; + case CXT5066_DELL_LAPTOP: + spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; + spec->mixers[spec->num_mixers++] = cxt5066_mixers; + + spec->port_d_mode = PIN_OUT; + spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_portd_lo; + spec->num_init_verbs++; + spec->dell_automute = 1; + break; + case CXT5066_OLPC_XO_1_5: + codec->patch_ops.unsol_event = cxt5066_unsol_event; + spec->init_verbs[0] = cxt5066_init_verbs_olpc; + spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; + spec->mixers[spec->num_mixers++] = cxt5066_mixers; + spec->port_d_mode = 0; + + /* no S/PDIF out */ + spec->multiout.dig_out_nid = 0; + + /* input source automatically selected */ + spec->input_mux = NULL; + break; + } + + return 0; +} /* */ @@ -1919,12 +2395,15 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_cxt5047 }, { .id = 0x14f15051, .name = "CX20561 (Hermosa)", .patch = patch_cxt5051 }, + { .id = 0x14f15066, .name = "CX20582 (Pebble)", + .patch = patch_cxt5066 }, {} /* terminator */ }; MODULE_ALIAS("snd-hda-codec-id:14f15045"); MODULE_ALIAS("snd-hda-codec-id:14f15047"); MODULE_ALIAS("snd-hda-codec-id:14f15051"); +MODULE_ALIAS("snd-hda-codec-id:14f15066"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Conexant HD-audio codec"); -- cgit v0.10.2 From 713c0ecdb888e9ef6f085e828555455c5916b07f Mon Sep 17 00:00:00 2001 From: Sten Spans Date: Thu, 16 Jul 2009 09:41:39 +0200 Subject: security: fix security_file_lock cmd argument Pass posix-translated lock operations to security_file_lock when invoked via sys_flock. Signed-off-by: Sten Spans Signed-off-by: James Morris diff --git a/fs/locks.c b/fs/locks.c index b6440f5..52366e8 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1591,7 +1591,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) if (can_sleep) lock->fl_flags |= FL_SLEEP; - error = security_file_lock(filp, cmd); + error = security_file_lock(filp, lock->fl_type); if (error) goto out_free; -- cgit v0.10.2 From da706d8bc833e7153622435560422e653bdb2e94 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Wed, 15 Jul 2009 16:27:30 +0800 Subject: ring_buffer: Fix warning while ignoring cmpxchg return value kernel/trace/ring_buffer.c: In function 'rb_tail_page_update': kernel/trace/ring_buffer.c:849: warning: value computed is not used kernel/trace/ring_buffer.c:850: warning: value computed is not used Add "(void)"s to fix this warning, because we don't need here to handle the fail case of cmpxchg, it's fine if an interrupt already did the job. Changed from V1: Add a comment(which is written by Steven) for it. Signed-off-by: Lai Jiangshan Acked-by: Steven Rostedt Signed-off-by: Frederic Weisbecker diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index e648ba4..51633d7 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -845,9 +845,14 @@ static int rb_tail_page_update(struct ring_buffer_per_cpu *cpu_buffer, * This will only succeed if an interrupt did * not come in and change it. In which case, we * do not want to modify it. + * + * We add (void) to let the compiler know that we do not care + * about the return value of these functions. We use the + * cmpxchg to only update if an interrupt did not already + * do it for us. If the cmpxchg fails, we don't care. */ - local_cmpxchg(&next_page->write, old_write, val); - local_cmpxchg(&next_page->entries, old_entries, eval); + (void)local_cmpxchg(&next_page->write, old_write, val); + (void)local_cmpxchg(&next_page->entries, old_entries, eval); /* * No need to worry about races with clearing out the commit. -- cgit v0.10.2 From d2e3ee9b29f5de5b01e611b04e6fb29760589b01 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 17 Jul 2009 09:09:36 +1000 Subject: kernel: fix is_single_threaded - Fix the comment, is_single_threaded(p) actually means that nobody shares ->mm with p. I think this helper should be renamed, and it should not have arguments. With or without this patch it must not be used unless p == current, otherwise we can't safely use p->signal or p->mm. - "if (atomic_read(&p->signal->count) != 1)" is not right when we have a zombie group leader, use signal->live instead. - Add PF_KTHREAD check to skip kernel threads which may borrow p->mm, otherwise we can return the wrong "false". - Use for_each_process() instead of do_each_thread(), all threads must use the same ->mm. - Use down_write(mm->mmap_sem) + rcu_read_lock() instead of tasklist_lock to iterate over the process list. If there is another CLONE_VM process it can't pass exit_mm() which takes the same mm->mmap_sem. We can miss a freshly forked CLONE_VM task, but this doesn't matter because we must see its parent and return false. Signed-off-by: Oleg Nesterov Cc: David Howells Cc: James Morris Cc: Roland McGrath Cc: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: James Morris diff --git a/lib/is_single_threaded.c b/lib/is_single_threaded.c index f1ed2fe..2762516 100644 --- a/lib/is_single_threaded.c +++ b/lib/is_single_threaded.c @@ -12,34 +12,44 @@ #include -/** - * is_single_threaded - Determine if a thread group is single-threaded or not - * @p: A task in the thread group in question - * - * This returns true if the thread group to which a task belongs is single - * threaded, false if it is not. +/* + * Returns true if the task does not share ->mm with another thread/process. */ -bool is_single_threaded(struct task_struct *p) +bool is_single_threaded(struct task_struct *task) { - struct task_struct *g, *t; - struct mm_struct *mm = p->mm; - - if (atomic_read(&p->signal->count) != 1) - goto no; - - if (atomic_read(&p->mm->mm_users) != 1) { - read_lock(&tasklist_lock); - do_each_thread(g, t) { - if (t->mm == mm && t != p) - goto no_unlock; - } while_each_thread(g, t); - read_unlock(&tasklist_lock); - } + struct mm_struct *mm = task->mm; + struct task_struct *p, *t; + bool ret; + + might_sleep(); + + if (atomic_read(&task->signal->live) != 1) + return false; - return true; + if (atomic_read(&mm->mm_users) == 1) + return true; + + ret = false; + down_write(&mm->mmap_sem); + rcu_read_lock(); + for_each_process(p) { + if (unlikely(p->flags & PF_KTHREAD)) + continue; + if (unlikely(p == task->group_leader)) + continue; + + t = p; + do { + if (unlikely(t->mm == mm)) + goto found; + if (likely(t->mm)) + break; + } while_each_thread(p, t); + } + ret = true; +found: + rcu_read_unlock(); + up_write(&mm->mmap_sem); -no_unlock: - read_unlock(&tasklist_lock); -no: - return false; + return ret; } -- cgit v0.10.2 From 5bb459bb45d1ad3c177485dcf0af01580aa31125 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 10 Jul 2009 03:48:23 +0200 Subject: kernel: rename is_single_threaded(task) to current_is_single_threaded(void) - is_single_threaded(task) is not safe unless task == current, we can't use task->signal or task->mm. - it doesn't make sense unless task == current, the task can fork right after the check. Rename it to current_is_single_threaded() and kill the argument. Signed-off-by: Oleg Nesterov Acked-by: David Howells Signed-off-by: James Morris diff --git a/include/linux/sched.h b/include/linux/sched.h index 16a982e..0839a2c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2075,7 +2075,7 @@ static inline unsigned long wait_task_inactive(struct task_struct *p, #define for_each_process(p) \ for (p = &init_task ; (p = next_task(p)) != &init_task ; ) -extern bool is_single_threaded(struct task_struct *); +extern bool current_is_single_threaded(void); /* * Careful: do_each_thread/while_each_thread is a double loop so diff --git a/lib/is_single_threaded.c b/lib/is_single_threaded.c index 2762516..4340109 100644 --- a/lib/is_single_threaded.c +++ b/lib/is_single_threaded.c @@ -15,8 +15,9 @@ /* * Returns true if the task does not share ->mm with another thread/process. */ -bool is_single_threaded(struct task_struct *task) +bool current_is_single_threaded(void) { + struct task_struct *task = current; struct mm_struct *mm = task->mm; struct task_struct *p, *t; bool ret; diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 276d278..ed929af 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -702,7 +702,7 @@ long join_session_keyring(const char *name) /* only permit this if there's a single thread in the thread group - * this avoids us having to adjust the creds on all threads and risking * ENOMEM */ - if (!is_single_threaded(current)) + if (!current_is_single_threaded()) return -EMLINK; new = prepare_creds(); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2081055..e65677d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5187,7 +5187,7 @@ static int selinux_setprocattr(struct task_struct *p, /* Only allow single threaded processes to change context */ error = -EPERM; - if (!is_single_threaded(p)) { + if (!current_is_single_threaded()) { error = security_bounded_transition(tsec->sid, sid); if (error) goto abort_change; -- cgit v0.10.2 From 967cc5371113f9806b39a2ebb2174af2883d96fe Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Thu, 9 Jul 2009 23:28:49 +0200 Subject: kernel: is_current_single_threaded: don't use ->mmap_sem is_current_single_threaded() can safely miss a freshly forked CLONE_VM task, but in this case it must not miss its parent. That is why we take mm->mmap_sem for writing to make sure a thread/task with the same ->mm can't pass exit_mm() and disappear. However we can avoid ->mmap_sem and rely on rcu/barriers: - if we do not see the exiting parent on thread/process list we see the result of list_del_rcu(), in this case we must also see the result of list_add_rcu() which does wmb(). - if we do see the parent but its ->mm == NULL, we need rmb() to make sure we can't miss the child. Signed-off-by: Oleg Nesterov Acked-by: David Howells Signed-off-by: James Morris diff --git a/lib/is_single_threaded.c b/lib/is_single_threaded.c index 4340109..bd2bea9 100644 --- a/lib/is_single_threaded.c +++ b/lib/is_single_threaded.c @@ -22,8 +22,6 @@ bool current_is_single_threaded(void) struct task_struct *p, *t; bool ret; - might_sleep(); - if (atomic_read(&task->signal->live) != 1) return false; @@ -31,7 +29,6 @@ bool current_is_single_threaded(void) return true; ret = false; - down_write(&mm->mmap_sem); rcu_read_lock(); for_each_process(p) { if (unlikely(p->flags & PF_KTHREAD)) @@ -45,12 +42,17 @@ bool current_is_single_threaded(void) goto found; if (likely(t->mm)) break; + /* + * t->mm == NULL. Make sure next_thread/next_task + * will see other CLONE_VM tasks which might be + * forked before exiting. + */ + smp_rmb(); } while_each_thread(p, t); } ret = true; found: rcu_read_unlock(); - up_write(&mm->mmap_sem); return ret; } -- cgit v0.10.2 From 64fbcd162819bddaf0d99e78b16371b655aa5dee Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Wed, 15 Jul 2009 12:32:15 +0800 Subject: tracing/function: Simplify __ftrace_replace_code() Rewrite the __ftrace_replace_code() function, simplify it, but don't change the code's logic. First, we get the state we want to set, if the record has the same state, then do nothing, otherwise enable/disable it. Signed-off-by: Xiao Guangrong Reviewed-by: Li Zefan Signed-off-by: Frederic Weisbecker diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index bce9e01..217caec 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1017,71 +1017,35 @@ static int __ftrace_replace_code(struct dyn_ftrace *rec, int enable) { unsigned long ftrace_addr; - unsigned long ip, fl; + unsigned long flag = 0UL; ftrace_addr = (unsigned long)FTRACE_ADDR; - ip = rec->ip; - /* - * If this record is not to be traced and - * it is not enabled then do nothing. + * If this record is not to be traced or we want to disable it, + * then disable it. * - * If this record is not to be traced and - * it is enabled then disable it. + * If we want to enable it and filtering is off, then enable it. * + * If we want to enable it and filtering is on, enable it only if + * it's filtered */ - if (rec->flags & FTRACE_FL_NOTRACE) { - if (rec->flags & FTRACE_FL_ENABLED) - rec->flags &= ~FTRACE_FL_ENABLED; - else - return 0; - - } else if (ftrace_filtered && enable) { - /* - * Filtering is on: - */ - - fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_ENABLED); - - /* Record is filtered and enabled, do nothing */ - if (fl == (FTRACE_FL_FILTER | FTRACE_FL_ENABLED)) - return 0; - - /* Record is not filtered or enabled, do nothing */ - if (!fl) - return 0; - - /* Record is not filtered but enabled, disable it */ - if (fl == FTRACE_FL_ENABLED) - rec->flags &= ~FTRACE_FL_ENABLED; - else - /* Otherwise record is filtered but not enabled, enable it */ - rec->flags |= FTRACE_FL_ENABLED; - } else { - /* Disable or not filtered */ - - if (enable) { - /* if record is enabled, do nothing */ - if (rec->flags & FTRACE_FL_ENABLED) - return 0; - - rec->flags |= FTRACE_FL_ENABLED; - - } else { + if (enable && !(rec->flags & FTRACE_FL_NOTRACE)) { + if (!ftrace_filtered || (rec->flags & FTRACE_FL_FILTER)) + flag = FTRACE_FL_ENABLED; + } - /* if record is not enabled, do nothing */ - if (!(rec->flags & FTRACE_FL_ENABLED)) - return 0; + /* If the state of this record hasn't changed, then do nothing */ + if ((rec->flags & FTRACE_FL_ENABLED) == flag) + return 0; - rec->flags &= ~FTRACE_FL_ENABLED; - } + if (flag) { + rec->flags |= FTRACE_FL_ENABLED; + return ftrace_make_call(rec, ftrace_addr); } - if (rec->flags & FTRACE_FL_ENABLED) - return ftrace_make_call(rec, ftrace_addr); - else - return ftrace_make_nop(NULL, rec, ftrace_addr); + rec->flags &= ~FTRACE_FL_ENABLED; + return ftrace_make_nop(NULL, rec, ftrace_addr); } static void ftrace_replace_code(int enable) -- cgit v0.10.2 From 79173bf556417a737e9d2e096e0788452ec30a61 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 16 Jul 2009 14:17:11 +0800 Subject: tracing/trace_stack: Cleanup for trace_lookup_stack() We can directly use %pF input format instead of sprint_symbol() and %s input format. Signed-off-by: Xiao Guangrong Reviewed-by: Li Zefan Signed-off-by: Frederic Weisbecker diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index e644af9..a4dc8d9 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -234,15 +234,8 @@ static void t_stop(struct seq_file *m, void *p) static int trace_lookup_stack(struct seq_file *m, long i) { unsigned long addr = stack_dump_trace[i]; -#ifdef CONFIG_KALLSYMS - char str[KSYM_SYMBOL_LEN]; - sprint_symbol(str, addr); - - return seq_printf(m, "%s\n", str); -#else - return seq_printf(m, "%p\n", (void*)addr); -#endif + return seq_printf(m, "%pF\n", (void *)addr); } static void print_disabled(struct seq_file *m) -- cgit v0.10.2 From 6f2f3cf00ee32f75ba007a46bab88a54d68a5deb Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 16 Jul 2009 14:21:08 +0800 Subject: tracing/function: Cleanup for function tracer We can directly use %pf input format instead of kallsyms_lookup() and %s input format Signed-off-by: Xiao Guangrong Reviewed-by: Li Zefan Signed-off-by: Frederic Weisbecker diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 217caec..80a97a5 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1403,18 +1403,13 @@ static int t_hash_show(struct seq_file *m, void *v) { struct ftrace_func_probe *rec; struct hlist_node *hnd = v; - char str[KSYM_SYMBOL_LEN]; rec = hlist_entry(hnd, struct ftrace_func_probe, node); if (rec->ops->print) return rec->ops->print(m, rec->ip, rec->ops, rec->data); - kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); - seq_printf(m, "%s:", str); - - kallsyms_lookup((unsigned long)rec->ops->func, NULL, NULL, NULL, str); - seq_printf(m, "%s", str); + seq_printf(m, "%pf:%pf", (void *)rec->ip, (void *)rec->ops->func); if (rec->data) seq_printf(m, ":%p", rec->data); @@ -1512,7 +1507,6 @@ static int t_show(struct seq_file *m, void *v) { struct ftrace_iterator *iter = m->private; struct dyn_ftrace *rec = v; - char str[KSYM_SYMBOL_LEN]; if (iter->flags & FTRACE_ITER_HASH) return t_hash_show(m, v); @@ -1525,9 +1519,7 @@ static int t_show(struct seq_file *m, void *v) if (!rec) return 0; - kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); - - seq_printf(m, "%s\n", str); + seq_printf(m, "%pf\n", (void *)rec->ip); return 0; } @@ -2508,7 +2500,6 @@ static void g_stop(struct seq_file *m, void *p) static int g_show(struct seq_file *m, void *v) { unsigned long *ptr = v; - char str[KSYM_SYMBOL_LEN]; if (!ptr) return 0; @@ -2518,9 +2509,7 @@ static int g_show(struct seq_file *m, void *v) return 0; } - kallsyms_lookup(*ptr, NULL, NULL, NULL, str); - - seq_printf(m, "%s\n", str); + seq_printf(m, "%pf\n", v); return 0; } diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index 7402144..b53dc99 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c @@ -288,11 +288,9 @@ static int ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip, struct ftrace_probe_ops *ops, void *data) { - char str[KSYM_SYMBOL_LEN]; long count = (long)data; - kallsyms_lookup(ip, NULL, NULL, NULL, str); - seq_printf(m, "%s:", str); + seq_printf(m, "%pf:", (void *)ip); if (ops == &traceon_probe_ops) seq_printf(m, "traceon"); -- cgit v0.10.2 From 416c8fe3cdcd2d46a6ca12d8ec6143c62d8569d9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Jul 2009 07:48:03 +0200 Subject: ASoC: Kill direct accesses to driver_data Replaced with dev_{get|set}_drvdata(). Signed-off-by: Takashi Iwai diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 3dc8091..5a7d00c 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -420,14 +420,14 @@ static int __devinit ad1938_spi_probe(struct spi_device *spi) codec->control_data = spi; codec->dev = &spi->dev; - spi->dev.driver_data = ad1938; + dev_set_drvdata(&spi->dev, ad1938); return ad1938_register(ad1938); } static int __devexit ad1938_spi_remove(struct spi_device *spi) { - struct ad1938_priv *ad1938 = spi->dev.driver_data; + struct ad1938_priv *ad1938 = dev_get_drvdata(&spi->dev); ad1938_unregister(ad1938); return 0; -- cgit v0.10.2 From 9176b672c29baaa94cdff4eedf1350a3b553d9ea Mon Sep 17 00:00:00 2001 From: Andiry Brienza Date: Fri, 17 Jul 2009 11:32:32 +0800 Subject: ALSA: hda - Add support for new AMD HD audio devices Add support for new AMD HD audio devices. Use generic driver to detect HD audio devices with Vendor ID AMD. Signed-off-by: Andiry Xu Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index a7cf349..4db854b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2634,11 +2634,15 @@ static struct pci_device_id azx_ids[] = { /* this entry seems still valid -- i.e. without emu20kx chip */ { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC }, #endif - /* AMD Generic, PCI class code and Vendor ID for HD Audio */ + /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, .driver_data = AZX_DRIVER_GENERIC }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_ANY_ID), + .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, + .class_mask = 0xffffff, + .driver_data = AZX_DRIVER_GENERIC }, { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); -- cgit v0.10.2 From 6430aeeb30b478d4ef25f988b1fde6f6ae83adb5 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 17 Jul 2009 16:49:19 +0800 Subject: ALSA: hda - add bounds checking for the codec command fields A recent bug involves passing auto detected >0x7f NID to codec command, creating an invalid codec addr field, and finally lead to cmd timeout and fall back into single command mode. Jaroslav fixed that bug in alc880_parse_auto_config(). It would be safer to further check the bounds of all cmd fields. Cc: Jaroslav Kysela Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ec352c6..d9d3262 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -150,7 +150,14 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, { u32 val; - val = (u32)(codec->addr & 0x0f) << 28; + if ((codec->addr & ~0xf) | (direct & ~1) | (nid & ~0x7f) | + (verb & ~0xfff) | (parm & ~0xff)) { + printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n", + codec->addr, direct, nid, verb, parm); + return ~0; + } + + val = (u32)codec->addr << 28; val |= (u32)direct << 27; val |= (u32)nid << 20; val |= verb << 8; @@ -167,6 +174,9 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, struct hda_bus *bus = codec->bus; int err; + if (cmd == ~0) + return -1; + if (res) *res = -1; again: -- cgit v0.10.2 From c5910a703889cf44ac1aa9405642a7d3b5bc6f24 Mon Sep 17 00:00:00 2001 From: "Candelaria Villareal, Jorge" Date: Tue, 14 Jul 2009 20:04:08 -0500 Subject: ASoC: SDP3430: Add support for EXTMUTE using TWL GPIO6 Board sdp3430 has hardware support for EXTMUTE using TWL4030 GPIO6 line, controlled by register INTBR_PMBR1. Machine driver takes care of enabling gpio line through i2c and codec driver manipulates the line during headset ramp up/down sequence. Signed-off-by: Jorge Eduardo Candelaria Signed-off-by: Mark Brown diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index c51594d..f7e5b74 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -39,6 +40,9 @@ #include "omap-pcm.h" #include "../codecs/twl4030.h" +#define TWL4030_INTBR_PMBR1 0x0D +#define EXTMUTE(value) (value << 2) + static struct snd_soc_card snd_soc_sdp3430; static int sdp3430_hw_params(struct snd_pcm_substream *substream, @@ -280,6 +284,7 @@ static struct snd_soc_card snd_soc_sdp3430 = { static struct twl4030_setup_data twl4030_setup = { .ramp_delay_value = 3, .sysclk = 26000, + .hs_extmute = 1, }; /* Audio subsystem */ @@ -312,6 +317,10 @@ static int __init sdp3430_soc_init(void) *(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */ *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */ + /* Set TWL4030 GPIO6 as EXTMUTE signal */ + twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, EXTMUTE(0x02), + TWL4030_MODULE_INTBR); + ret = platform_device_add(sdp3430_snd_device); if (ret) goto err1; -- cgit v0.10.2 From 82e1b804b03defe46fb69ffd2c8b19e6649bcb0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Jul 2009 12:47:34 +0200 Subject: ALSA: hda - Fix the previous sanity check in make_codec_cmd() The newly added sanity-check for a codec verb can be better written with logical ORs. Also, the parameter can be more than 8bit. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d9d3262..35f0f22 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -150,8 +150,8 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, { u32 val; - if ((codec->addr & ~0xf) | (direct & ~1) | (nid & ~0x7f) | - (verb & ~0xfff) | (parm & ~0xff)) { + if ((codec->addr & ~0xf) || (direct & ~1) || (nid & ~0x7f) || + (verb & ~0xfff) || (parm & ~0xffff)) { printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n", codec->addr, direct, nid, verb, parm); return ~0; -- cgit v0.10.2 From 3f3b7c1aed70fa25c6811f830c5fb1a7054681ae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Jul 2009 14:36:59 +0200 Subject: ALSA: hda - Fix ALC268 parser for mono speaker - Parse the mono output pin 0x16 correctly even as the primary output - Create "Speaker" volume control if the primary output is a speaker - Fix the wrong direction of (optional) "Mono" switch Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7967f8f..507a772 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -11816,26 +11816,38 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, const char *ctlname, int idx) { char name[32]; + hda_nid_t dac; int err; sprintf(name, "%s Playback Volume", ctlname); - if (nid == 0x14) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(0x02, 3, idx, - HDA_OUTPUT)); - if (err < 0) - return err; - } else if (nid == 0x15) { + switch (nid) { + case 0x14: + case 0x16: + dac = 0x02; + break; + case 0x15: + dac = 0x03; + break; + default: + return 0; + } + if (spec->multiout.dac_nids[0] != dac && + spec->multiout.dac_nids[1] != dac) { err = add_control(spec, ALC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(0x03, 3, idx, + HDA_COMPOSE_AMP_VAL(dac, 3, idx, HDA_OUTPUT)); if (err < 0) return err; - } else - return -1; + spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; + } + sprintf(name, "%s Playback Switch", ctlname); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + if (nid != 0x16) + err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); + else /* mono */ + err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT)); if (err < 0) return err; return 0; @@ -11848,14 +11860,19 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, hda_nid_t nid; int err; - spec->multiout.num_dacs = 2; /* only use one dac */ spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.dac_nids[0] = 2; - spec->multiout.dac_nids[1] = 3; nid = cfg->line_out_pins[0]; - if (nid) - alc268_new_analog_output(spec, nid, "Front", 0); + if (nid) { + const char *name; + if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + name = "Speaker"; + else + name = "Front"; + err = alc268_new_analog_output(spec, nid, name, 0); + if (err < 0) + return err; + } nid = cfg->speaker_pins[0]; if (nid == 0x1d) { @@ -11864,16 +11881,23 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); if (err < 0) return err; + } else { + err = alc268_new_analog_output(spec, nid, "Speaker", 0); + if (err < 0) + return err; } nid = cfg->hp_pins[0]; - if (nid) - alc268_new_analog_output(spec, nid, "Headphone", 0); + if (nid) { + err = alc268_new_analog_output(spec, nid, "Headphone", 0); + if (err < 0) + return err; + } nid = cfg->line_out_pins[1] | cfg->line_out_pins[2]; if (nid == 0x16) { err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Mono Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT)); + HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT)); if (err < 0) return err; } -- cgit v0.10.2 From 652f6787c082a174f0bbfa7f895b65b03d8d46c9 Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Fri, 17 Jul 2009 02:27:07 +0000 Subject: fs_enet/mii-fec.c: fix MII speed calculation The MII speed calculation was based on the CPU clock (ppc_proc_freq), but for MPC512x we must use the bus clock instead. This patch makes it use the correct clock and makes sure we don't clobber reserved bits in the MII_SPEED register. Signed-off-by: Wolfgang Denk Cc: Grant Likely Cc: Kumar Gala Cc: Acked-by: Grant Likely Signed-off-by: David S. Miller diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 75a0999..a2d69c1 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "fs_enet.h" #include "fec.h" @@ -103,11 +104,11 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus) static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) { - struct device_node *np = NULL; struct resource res; struct mii_bus *new_bus; struct fec_info *fec; - int ret = -ENOMEM, i; + int (*get_bus_freq)(struct device_node *) = match->data; + int ret = -ENOMEM, clock, speed; new_bus = mdiobus_alloc(); if (!new_bus) @@ -133,13 +134,35 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, if (!fec->fecp) goto out_fec; - fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1; + if (get_bus_freq) { + clock = get_bus_freq(ofdev->node); + if (!clock) { + /* Use maximum divider if clock is unknown */ + dev_warn(&ofdev->dev, "could not determine IPS clock\n"); + clock = 0x3F * 5000000; + } + } else + clock = ppc_proc_freq; + + /* + * Scale for a MII clock <= 2.5 MHz + * Note that only 6 bits (25:30) are available for MII speed. + */ + speed = (clock + 4999999) / 5000000; + if (speed > 0x3F) { + speed = 0x3F; + dev_err(&ofdev->dev, + "MII clock (%d Hz) exceeds max (2.5 MHz)\n", + clock / speed); + } + + fec->mii_speed = speed << 1; setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII); - out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed); + clrsetbits_be32(&fec->fecp->fec_mii_speed, 0x7E, fec->mii_speed); new_bus->phy_mask = ~0; new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); @@ -188,6 +211,12 @@ static struct of_device_id fs_enet_mdio_fec_match[] = { { .compatible = "fsl,pq1-fec-mdio", }, +#if defined(CONFIG_PPC_MPC512x) + { + .compatible = "fsl,mpc5121-fec-mdio", + .data = mpc5xxx_get_bus_frequency, + }, +#endif {}, }; -- cgit v0.10.2 From c482c568577a2b31716e1019f2868bda7cf5629c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 17 Jul 2009 00:26:32 +0000 Subject: udp: cleanups Pure style cleanups. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7bc2d08..29ebb0d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -110,11 +110,12 @@ struct udp_table udp_table; EXPORT_SYMBOL(udp_table); int sysctl_udp_mem[3] __read_mostly; -int sysctl_udp_rmem_min __read_mostly; -int sysctl_udp_wmem_min __read_mostly; - EXPORT_SYMBOL(sysctl_udp_mem); + +int sysctl_udp_rmem_min __read_mostly; EXPORT_SYMBOL(sysctl_udp_rmem_min); + +int sysctl_udp_wmem_min __read_mostly; EXPORT_SYMBOL(sysctl_udp_wmem_min); atomic_t udp_memory_allocated; @@ -158,7 +159,7 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num, */ int udp_lib_get_port(struct sock *sk, unsigned short snum, int (*saddr_comp)(const struct sock *sk1, - const struct sock *sk2 ) ) + const struct sock *sk2)) { struct udp_hslot *hslot; struct udp_table *udptable = sk->sk_prot->h.udp_table; @@ -221,14 +222,15 @@ fail_unlock: fail: return error; } +EXPORT_SYMBOL(udp_lib_get_port); static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) { struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); - return ( !ipv6_only_sock(sk2) && - (!inet1->rcv_saddr || !inet2->rcv_saddr || - inet1->rcv_saddr == inet2->rcv_saddr )); + return (!ipv6_only_sock(sk2) && + (!inet1->rcv_saddr || !inet2->rcv_saddr || + inet1->rcv_saddr == inet2->rcv_saddr)); } int udp_v4_get_port(struct sock *sk, unsigned short snum) @@ -383,8 +385,8 @@ found: void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) { struct inet_sock *inet; - struct iphdr *iph = (struct iphdr*)skb->data; - struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2)); + struct iphdr *iph = (struct iphdr *)skb->data; + struct udphdr *uh = (struct udphdr *)(skb->data+(iph->ihl<<2)); const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; struct sock *sk; @@ -439,7 +441,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) if (!harderr || sk->sk_state != TCP_ESTABLISHED) goto out; } else { - ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); + ip_icmp_error(sk, skb, err, uh->dest, info, (u8 *)(uh+1)); } sk->sk_err = err; sk->sk_error_report(sk); @@ -474,7 +476,7 @@ EXPORT_SYMBOL(udp_flush_pending_frames); * (checksum field must be zeroed out) */ static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, - __be32 src, __be32 dst, int len ) + __be32 src, __be32 dst, int len) { unsigned int offset; struct udphdr *uh = udp_hdr(skb); @@ -545,7 +547,7 @@ static int udp_push_pending_frames(struct sock *sk) } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ - udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); + udp4_hwcsum_outgoing(sk, skb, fl->fl4_src, fl->fl4_dst, up->len); goto send; } else /* `normal' UDP */ @@ -553,7 +555,7 @@ static int udp_push_pending_frames(struct sock *sk) /* add protocol-dependent pseudo-header */ uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, - sk->sk_protocol, csum ); + sk->sk_protocol, csum); if (uh->check == 0) uh->check = CSUM_MANGLED_0; @@ -592,7 +594,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, * Check the flags. */ - if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ + if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */ return -EOPNOTSUPP; ipc.opt = NULL; @@ -619,7 +621,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, * Get and verify the address. */ if (msg->msg_name) { - struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; + struct sockaddr_in * usin = (struct sockaddr_in *)msg->msg_name; if (msg->msg_namelen < sizeof(*usin)) return -EINVAL; if (usin->sin_family != AF_INET) { @@ -684,7 +686,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } if (connected) - rt = (struct rtable*)sk_dst_check(sk, 0); + rt = (struct rtable *)sk_dst_check(sk, 0); if (rt == NULL) { struct flowi fl = { .oif = ipc.oif, @@ -782,6 +784,7 @@ do_confirm: err = 0; goto out; } +EXPORT_SYMBOL(udp_sendmsg); int udp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) @@ -871,6 +874,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) return 0; } +EXPORT_SYMBOL(udp_ioctl); /* * This should be easy, if there is something there we @@ -892,7 +896,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, * Check any passed addresses */ if (addr_len) - *addr_len=sizeof(*sin); + *addr_len = sizeof(*sin); if (flags & MSG_ERRQUEUE) return ip_recv_error(sk, msg, len); @@ -923,9 +927,11 @@ try_again: if (skb_csum_unnecessary(skb)) err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), - msg->msg_iov, copied ); + msg->msg_iov, copied); else { - err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); + err = skb_copy_and_csum_datagram_iovec(skb, + sizeof(struct udphdr), + msg->msg_iov); if (err == -EINVAL) goto csum_copy_err; @@ -941,8 +947,7 @@ try_again: sock_recv_timestamp(msg, sk, skb); /* Copy the address. */ - if (sin) - { + if (sin) { sin->sin_family = AF_INET; sin->sin_port = udp_hdr(skb)->source; sin->sin_addr.s_addr = ip_hdr(skb)->saddr; @@ -995,6 +1000,7 @@ int udp_disconnect(struct sock *sk, int flags) sk_dst_reset(sk); return 0; } +EXPORT_SYMBOL(udp_disconnect); void udp_lib_unhash(struct sock *sk) { @@ -1044,7 +1050,7 @@ drop: * Note that in the success and error cases, the skb is assumed to * have either been requeued or freed. */ -int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { struct udp_sock *up = udp_sk(sk); int rc; @@ -1214,7 +1220,7 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, if (uh->check == 0) { skb->ip_summed = CHECKSUM_UNNECESSARY; } else if (skb->ip_summed == CHECKSUM_COMPLETE) { - if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, + if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, proto, skb->csum)) skb->ip_summed = CHECKSUM_UNNECESSARY; } @@ -1355,7 +1361,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, int err = 0; int is_udplite = IS_UDPLITE(sk); - if (optlenf_flags & O_NONBLOCK) && - !(sk->sk_shutdown & RCV_SHUTDOWN)){ + if ((mask & POLLRDNORM) && + !(file->f_flags & O_NONBLOCK) && + !(sk->sk_shutdown & RCV_SHUTDOWN)) { struct sk_buff_head *rcvq = &sk->sk_receive_queue; struct sk_buff *skb; @@ -1552,6 +1560,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) return mask; } +EXPORT_SYMBOL(udp_poll); struct proto udp_prot = { .name = "UDP", @@ -1582,6 +1591,7 @@ struct proto udp_prot = { .compat_getsockopt = compat_udp_getsockopt, #endif }; +EXPORT_SYMBOL(udp_prot); /* ------------------------------------------------------------------------ */ #ifdef CONFIG_PROC_FS @@ -1703,11 +1713,13 @@ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) rc = -ENOMEM; return rc; } +EXPORT_SYMBOL(udp_proc_register); void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo) { proc_net_remove(net, afinfo->name); } +EXPORT_SYMBOL(udp_proc_unregister); /* ------------------------------------------------------------------------ */ static void udp4_format_sock(struct sock *sp, struct seq_file *f, @@ -1741,7 +1753,7 @@ int udp4_seq_show(struct seq_file *seq, void *v) int len; udp4_format_sock(v, seq, state->bucket, &len); - seq_printf(seq, "%*s\n", 127 - len ,""); + seq_printf(seq, "%*s\n", 127 - len, ""); } return 0; } @@ -1864,7 +1876,7 @@ struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features) * do checksum of UDP packets sent as multiple IP fragments. */ offset = skb->csum_start - skb_headroom(skb); - csum = skb_checksum(skb, offset, skb->len- offset, 0); + csum = skb_checksum(skb, offset, skb->len - offset, 0); offset += skb->csum_offset; *(__sum16 *)(skb->data + offset) = csum_fold(csum); skb->ip_summed = CHECKSUM_NONE; @@ -1877,16 +1889,3 @@ out: return segs; } -EXPORT_SYMBOL(udp_disconnect); -EXPORT_SYMBOL(udp_ioctl); -EXPORT_SYMBOL(udp_prot); -EXPORT_SYMBOL(udp_sendmsg); -EXPORT_SYMBOL(udp_lib_getsockopt); -EXPORT_SYMBOL(udp_lib_setsockopt); -EXPORT_SYMBOL(udp_poll); -EXPORT_SYMBOL(udp_lib_get_port); - -#ifdef CONFIG_PROC_FS -EXPORT_SYMBOL(udp_proc_register); -EXPORT_SYMBOL(udp_proc_unregister); -#endif -- cgit v0.10.2 From f4ec443b2b27ecb401eee35a7bea330438556c7e Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 16 Jul 2009 15:50:12 +0000 Subject: ixgbe: Remove legacy descriptor support The ethtool offline test is the only consumer of the legacy descriptors. Update that path to only use advanced descriptors, and remove all support for legacy descriptors. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index cd22323..2a93e11 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -229,10 +229,6 @@ struct ixgbe_q_vector { #define IXGBE_TX_CTXTDESC_ADV(R, i) \ (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i])) -#define IXGBE_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) -#define IXGBE_TX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_tx_desc) -#define IXGBE_RX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_rx_desc) - #define IXGBE_MAX_JUMBO_FRAME_SIZE 16128 #ifdef IXGBE_FCOE /* Use 3K as the baby jumbo frame size for FCoE */ diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 2a97800..1464b33 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1440,7 +1440,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) goto err_nomem; } - tx_ring->size = tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc); + tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc); tx_ring->size = ALIGN(tx_ring->size, 4096); if (!(tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, &tx_ring->dma))) { @@ -1454,7 +1454,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0), ((u64) tx_ring->dma >> 32)); IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0), - tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc)); + tx_ring->count * sizeof(union ixgbe_adv_tx_desc)); IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0); IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0); @@ -1472,7 +1472,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data); for (i = 0; i < tx_ring->count; i++) { - struct ixgbe_legacy_tx_desc *desc = IXGBE_TX_DESC(*tx_ring, i); + union ixgbe_adv_tx_desc *desc = IXGBE_TX_DESC_ADV(*tx_ring, i); struct sk_buff *skb; unsigned int size = 1024; @@ -1486,13 +1486,18 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) tx_ring->tx_buffer_info[i].length = skb->len; tx_ring->tx_buffer_info[i].dma = pci_map_single(pdev, skb->data, skb->len, - PCI_DMA_TODEVICE); - desc->buffer_addr = cpu_to_le64(tx_ring->tx_buffer_info[i].dma); - desc->lower.data = cpu_to_le32(skb->len); - desc->lower.data |= cpu_to_le32(IXGBE_TXD_CMD_EOP | - IXGBE_TXD_CMD_IFCS | - IXGBE_TXD_CMD_RS); - desc->upper.data = 0; + PCI_DMA_TODEVICE); + desc->read.buffer_addr = + cpu_to_le64(tx_ring->tx_buffer_info[i].dma); + desc->read.cmd_type_len = cpu_to_le32(skb->len); + desc->read.cmd_type_len |= cpu_to_le32(IXGBE_TXD_CMD_EOP | + IXGBE_TXD_CMD_IFCS | + IXGBE_TXD_CMD_RS); + desc->read.olinfo_status = 0; + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + desc->read.olinfo_status |= + (skb->len << IXGBE_ADVTXD_PAYLEN_SHIFT); + } /* Setup Rx Descriptor ring and Rx buffers */ @@ -1508,7 +1513,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) goto err_nomem; } - rx_ring->size = rx_ring->count * sizeof(struct ixgbe_legacy_rx_desc); + rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc); rx_ring->size = ALIGN(rx_ring->size, 4096); if (!(rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size, &rx_ring->dma))) { @@ -1566,8 +1571,8 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl); for (i = 0; i < rx_ring->count; i++) { - struct ixgbe_legacy_rx_desc *rx_desc = - IXGBE_RX_DESC(*rx_ring, i); + union ixgbe_adv_rx_desc *rx_desc = + IXGBE_RX_DESC_ADV(*rx_ring, i); struct sk_buff *skb; skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL); @@ -1580,7 +1585,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) rx_ring->rx_buffer_info[i].dma = pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048, PCI_DMA_FROMDEVICE); - rx_desc->buffer_addr = + rx_desc->read.pkt_addr = cpu_to_le64(rx_ring->rx_buffer_info[i].dma); memset(skb->data, 0x00, skb->len); } diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index fa87309..8fb6ade 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1893,27 +1893,6 @@ enum ixgbe_fdir_pballoc_type { #define IXGBE_FDIR_INIT_DONE_POLL 10 #define IXGBE_FDIRCMD_CMD_POLL 10 -/* Transmit Descriptor - Legacy */ -struct ixgbe_legacy_tx_desc { - u64 buffer_addr; /* Address of the descriptor's data buffer */ - union { - __le32 data; - struct { - __le16 length; /* Data buffer length */ - u8 cso; /* Checksum offset */ - u8 cmd; /* Descriptor control */ - } flags; - } lower; - union { - __le32 data; - struct { - u8 status; /* Descriptor status */ - u8 css; /* Checksum start */ - __le16 vlan; - } fields; - } upper; -}; - /* Transmit Descriptor - Advanced */ union ixgbe_adv_tx_desc { struct { @@ -1928,16 +1907,6 @@ union ixgbe_adv_tx_desc { } wb; }; -/* Receive Descriptor - Legacy */ -struct ixgbe_legacy_rx_desc { - __le64 buffer_addr; /* Address of the descriptor's data buffer */ - __le16 length; /* Length of data DMAed into data buffer */ - __le16 csum; /* Packet checksum */ - u8 status; /* Descriptor status */ - u8 errors; /* Descriptor Errors */ - __le16 vlan; -}; - /* Receive Descriptor - Advanced */ union ixgbe_adv_rx_desc { struct { -- cgit v0.10.2 From 078788b6a68828c1caf395b48110535e051cd623 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 16 Jul 2009 15:50:32 +0000 Subject: ixgbe: Make sure boolean assignments from bitwise operations done correctly When the link comes up, the driver detects which flow control settings are active. This is done using bitwise operations directly from the hardware registers, and assumes the proper boolean assignment. Make this an explicit boolean value before assignment to the bool. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index e3442f4..09394c1 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4643,13 +4643,13 @@ static void ixgbe_watchdog_task(struct work_struct *work) if (hw->mac.type == ixgbe_mac_82599EB) { u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN); u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG); - flow_rx = (mflcn & IXGBE_MFLCN_RFCE); - flow_tx = (fccfg & IXGBE_FCCFG_TFCE_802_3X); + flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE); + flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X); } else { u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL); u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); - flow_rx = (frctl & IXGBE_FCTRL_RFCE); - flow_tx = (rmcs & IXGBE_RMCS_TFCE_802_3X); + flow_rx = !!(frctl & IXGBE_FCTRL_RFCE); + flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X); } printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, " -- cgit v0.10.2 From 3845bec0f33f7c2604ba985f6f80983d0c139d46 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 16 Jul 2009 15:50:52 +0000 Subject: ixgbe: Add device support for a new copper 82598 device This adds support for a new copper device for 82598, device id 0x150b. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index b992304..ed0bb3b 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -269,6 +269,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) media_type = ixgbe_media_type_fiber; break; case IXGBE_DEV_ID_82598AT: + case IXGBE_DEV_ID_82598AT2: media_type = ixgbe_media_type_copper; break; default: diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 09394c1..a3bbcfd 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -74,6 +74,8 @@ static struct pci_device_id ixgbe_pci_tbl[] = { board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT), board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT2), + board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 8fb6ade..17ee389 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -42,6 +42,7 @@ #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 #define IXGBE_DEV_ID_82598EB_SFP_LOM 0x10DB #define IXGBE_DEV_ID_82598AT 0x10C8 +#define IXGBE_DEV_ID_82598AT2 0x150B #define IXGBE_DEV_ID_82598EB_CX4 0x10DD #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC #define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1 -- cgit v0.10.2 From bbf50e4df11ea5b9d2f625be2a1cea3ec0352890 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 16 Jul 2009 15:51:11 +0000 Subject: ixgbe: Bump version number Keep the version number marching along as updates come in. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index a3bbcfd..79f60e8 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -48,7 +48,7 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; -#define DRV_VERSION "2.0.34-k2" +#define DRV_VERSION "2.0.37-k2" const char ixgbe_driver_version[] = DRV_VERSION; static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation."; -- cgit v0.10.2 From 5c5167515d80f78f6bb538492c423adcae31ad65 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Tue, 14 Jul 2009 14:21:02 +0000 Subject: virtio-net: Allow UFO feature to be set and advertised. - Allow setting UFO on virtio-net and advertise to host. Signed-off-by: Sridhar Samudrala Acked-by: Rusty Russell Signed-off-by: David S. Miller diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 2a6e81d..a6f903f 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -774,6 +774,7 @@ static struct ethtool_ops virtnet_ethtool_ops = { .set_tx_csum = virtnet_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = ethtool_op_set_tso, + .set_ufo = ethtool_op_set_ufo, .get_link = ethtool_op_get_link, }; @@ -1005,7 +1006,7 @@ static unsigned int features[] = { VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, - VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */ + VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, VIRTIO_F_NOTIFY_ON_EMPTY, -- cgit v0.10.2 From e36aa25a533962b08402530e8443ac804a454e27 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Tue, 14 Jul 2009 14:21:04 +0000 Subject: tun: Allow tap device to send/receive UFO packets. - Allow setting UFO on tap device and handle UFO packets. Signed-off-by: Sridhar Samudrala --------------------------------------------------------- Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index dfc1054..a998b6a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -641,6 +641,9 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, case VIRTIO_NET_HDR_GSO_TCPV6: skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; break; + case VIRTIO_NET_HDR_GSO_UDP: + skb_shinfo(skb)->gso_type = SKB_GSO_UDP; + break; default: tun->dev->stats.rx_frame_errors++; kfree_skb(skb); @@ -726,6 +729,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (sinfo->gso_type & SKB_GSO_TCPV6) gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + else if (sinfo->gso_type & SKB_GSO_UDP) + gso.gso_type = VIRTIO_NET_HDR_GSO_UDP; else BUG(); if (sinfo->gso_type & SKB_GSO_TCP_ECN) @@ -1073,7 +1078,8 @@ static int set_offload(struct net_device *dev, unsigned long arg) old_features = dev->features; /* Unset features, set them as we chew on the arg. */ features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST - |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6)); + |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6 + |NETIF_F_UFO)); if (arg & TUN_F_CSUM) { features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; @@ -1090,6 +1096,11 @@ static int set_offload(struct net_device *dev, unsigned long arg) features |= NETIF_F_TSO6; arg &= ~(TUN_F_TSO4|TUN_F_TSO6); } + + if (arg & TUN_F_UFO) { + features |= NETIF_F_UFO; + arg &= ~TUN_F_UFO; + } } /* This gives the user a way to test for new features in future by diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 915ba57..3f5fd52 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -62,6 +62,7 @@ #define TUN_F_TSO4 0x02 /* I can handle TSO for IPv4 packets */ #define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */ #define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */ +#define TUN_F_UFO 0x10 /* I can handle UFO packets */ /* Protocol info prepended to the packets (when IFF_NO_PI is not set) */ #define TUN_PKT_STRIP 0x0001 -- cgit v0.10.2 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 diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c index f688eba..50d5ce4 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 c5afc98..85e5dc0 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 c769ef2..d478aef 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 fd336c5..3f45669 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 fad25b7..8472418 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 ca5b464..e98baf6 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 fdf7285..52ccb3d 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 b68d278..47ebf41 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 v0.10.2 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 diff --git a/Documentation/connector/connector.txt b/Documentation/connector/connector.txt index ad6e0ba..81e6bf6 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 v0.10.2 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 diff --git a/Documentation/connector/Makefile b/Documentation/connector/Makefile index 8df1a72..d98e4df 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 50d5ce4..6e73190 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 d738cde..a8e4d58 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 v0.10.2 From 8aa2df53088f024b13cb005956bd6da94cc1fd2d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 17 Jul 2009 21:53:49 +0100 Subject: ASoC: Bodge around GCC 4.4.0 flow analysis bug in GCC 4.4.0 GCC 4.4.0 doesn't appear to be able to spot that we don't apply any FLL configuration if the output frequency is zero. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 0bf903f..b9ef4d9 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1022,10 +1022,15 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, if (freq_in == wm8400->fll_in && freq_out == wm8400->fll_out) return 0; - if (freq_out != 0) { + if (freq_out) { ret = fll_factors(wm8400, &factors, freq_in, freq_out); if (ret != 0) return ret; + } else { + /* Bodge GCC 4.4.0 uninitialised variable warning - it + * doesn't seem capable of working out that we exit if + * freq_out is 0 before any of the uses. */ + memset(&factors, 0, sizeof(factors)); } wm8400->fll_out = freq_out; @@ -1040,7 +1045,7 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, reg &= ~WM8400_FLL_OSC_ENA; wm8400_write(codec, WM8400_FLL_CONTROL_1, reg); - if (freq_out == 0) + if (!freq_out) return 0; reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK); -- cgit v0.10.2 From 0c11f655553c84bb695fdd5ea8b19d42b41b7133 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 17 Jul 2009 22:13:01 +0100 Subject: ASoC: Fix FLL reference clock division setup in WM8993 Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index f9c49b3..e246ca0 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -345,8 +345,10 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, /* Fref must be <=13.5MHz */ div = 1; + fll_div->fll_clk_ref_div = 0; while ((Fref / div) > 13500000) { div *= 2; + fll_div->fll_clk_ref_div++; if (div > 8) { pr_err("Can't scale %dMHz input down to <=13.5MHz\n", -- cgit v0.10.2 From bca146578c863a1f37cb191995317e855a0364e1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 18 Jul 2009 11:09:42 +0100 Subject: ASoC: Fix checkpatch issues in AD1938 Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 5a7d00c..ffc97c9 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -43,9 +43,8 @@ /* codec private data */ struct ad1938_priv { - struct snd_soc_codec codec; + struct snd_soc_codec codec; u8 reg_cache[AD1938_NUM_REGS]; - }; static struct snd_soc_codec *ad1938_codec; @@ -136,7 +135,7 @@ static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, dac_reg &= ~AD1938_DAC_CHAN_MASK; adc_reg &= ~AD1938_ADC_CHAN_MASK; - switch(slots) { + switch (slots) { case 2: dac_reg |= AD1938_DAC_2_CHANNELS << AD1938_DAC_CHAN_SHFT; adc_reg |= AD1938_ADC_2_CHANNELS << AD1938_ADC_CHAN_SHFT; @@ -324,7 +323,7 @@ static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg, u8 *reg_cache = codec->reg_cache; int ret = 0; - if(value != reg_cache[reg]) { + if (value != reg_cache[reg]) { uint8_t buf[AD1938_SPI_BUFLEN]; struct spi_transfer t = { .tx_buf = buf, @@ -337,7 +336,8 @@ static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg, buf[2] = value; spi_message_init(&m); spi_message_add_tail(&t, &m); - if((ret = spi_sync(codec->control_data, &m)) == 0) + ret = spi_sync(codec->control_data, &m); + if (ret == 0) reg_cache[reg] = value; } @@ -349,14 +349,14 @@ static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg, */ static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) + unsigned int reg) { - u8 *reg_cache = codec->reg_cache; + u8 *reg_cache = codec->reg_cache; - if (reg >= codec->reg_cache_size) - return -EINVAL; + if (reg >= codec->reg_cache_size) + return -EINVAL; - return reg_cache[reg]; + return reg_cache[reg]; } /* @@ -391,20 +391,20 @@ static unsigned int ad1938_read_reg(struct snd_soc_codec *codec, unsigned int re static int ad1938_fill_cache(struct snd_soc_codec *codec) { - int i; - u8 *reg_cache = codec->reg_cache; - struct spi_device *spi = codec->control_data; - - for (i = 0; i < codec->reg_cache_size; i++) { - int ret = ad1938_read_reg(codec, i); - if (ret == -EIO) { - dev_err(&spi->dev, "AD1938 SPI read failure\n"); - return ret; - } - reg_cache[i] = ret; - } - - return 0; + int i; + u8 *reg_cache = codec->reg_cache; + struct spi_device *spi = codec->control_data; + + for (i = 0; i < codec->reg_cache_size; i++) { + int ret = ad1938_read_reg(codec, i); + if (ret == -EIO) { + dev_err(&spi->dev, "AD1938 SPI read failure\n"); + return ret; + } + reg_cache[i] = ret; + } + + return 0; } static int __devinit ad1938_spi_probe(struct spi_device *spi) @@ -498,8 +498,8 @@ static int ad1938_register(struct ad1938_priv *ad1938) INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); - ad1938_dai.dev = codec->dev; - ad1938_codec = codec; + ad1938_dai.dev = codec->dev; + ad1938_codec = codec; /* default setting for ad1938 */ codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0); /* unmute dac channels */ @@ -512,85 +512,85 @@ static int ad1938_register(struct ad1938_priv *ad1938) ad1938_fill_cache(codec); - ret = snd_soc_register_codec(codec); - if (ret != 0) { - dev_err(codec->dev, "Failed to register codec: %d\n", ret); - return ret; - } + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; + } - ret = snd_soc_register_dai(&ad1938_dai); - if (ret != 0) { - dev_err(codec->dev, "Failed to register DAI: %d\n", ret); - snd_soc_unregister_codec(codec); - return ret; - } + ret = snd_soc_register_dai(&ad1938_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } - return 0; + return 0; } static void ad1938_unregister(struct ad1938_priv *ad1938) { - ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF); - snd_soc_unregister_dai(&ad1938_dai); - snd_soc_unregister_codec(&ad1938->codec); - kfree(ad1938); - ad1938_codec = NULL; + ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&ad1938_dai); + snd_soc_unregister_codec(&ad1938->codec); + kfree(ad1938); + ad1938_codec = NULL; } static int ad1938_probe(struct platform_device *pdev) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - int ret = 0; - - if (ad1938_codec == NULL) { - dev_err(&pdev->dev, "Codec device not registered\n"); - return -ENODEV; - } - - socdev->card->codec = ad1938_codec; - codec = ad1938_codec; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(codec->dev, "failed to create pcms: %d\n", ret); - goto pcm_err; - } - - snd_soc_add_controls(codec, ad1938_snd_controls, - ARRAY_SIZE(ad1938_snd_controls)); - snd_soc_dapm_new_controls(codec, ad1938_dapm_widgets, - ARRAY_SIZE(ad1938_dapm_widgets)); + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (ad1938_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = ad1938_codec; + codec = ad1938_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, ad1938_snd_controls, + ARRAY_SIZE(ad1938_snd_controls)); + snd_soc_dapm_new_controls(codec, ad1938_dapm_widgets, + ARRAY_SIZE(ad1938_dapm_widgets)); snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); snd_soc_dapm_new_widgets(codec); ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY); ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto card_err; + } - return ret; + return ret; card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); pcm_err: - return ret; + return ret; } /* power down chip */ static int ad1938_remove(struct platform_device *pdev) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_device *socdev = platform_get_drvdata(pdev); - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); - return 0; + return 0; } #ifdef CONFIG_PM -- cgit v0.10.2 From 566b0aaf798a0dddfc455d1a5b05c424c6686c65 Mon Sep 17 00:00:00 2001 From: "jolsa@redhat.com" Date: Thu, 16 Jul 2009 21:44:26 +0200 Subject: tracing: Remove unused fields/variables Signed-off-by: Jiri Olsa Cc: rostedt@goodmis.org LKML-Reference: <1247773468-11594-2-git-send-email-jolsa@redhat.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 6227dc8..24e3ff5 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1339,7 +1339,6 @@ struct ftrace_iterator { unsigned flags; unsigned char buffer[FTRACE_BUFF_MAX+1]; unsigned buffer_idx; - unsigned filtered; }; static void * @@ -2268,7 +2267,6 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, } if (isspace(ch)) { - iter->filtered++; iter->buffer[iter->buffer_idx] = 0; ret = ftrace_process_regex(iter->buffer, iter->buffer_idx, enable); @@ -2399,7 +2397,6 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) iter = file->private_data; if (iter->buffer_idx) { - iter->filtered++; iter->buffer[iter->buffer_idx] = 0; ftrace_match_records(iter->buffer, iter->buffer_idx, enable); } diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 60a4948..e30e6b1 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4265,7 +4265,6 @@ void ftrace_dump(void) __init static int tracer_alloc_buffers(void) { - struct trace_array_cpu *data; int ring_buf_size; int i; int ret = -ENOMEM; @@ -4315,7 +4314,7 @@ __init static int tracer_alloc_buffers(void) /* Allocate the first page for all buffers */ for_each_tracing_cpu(i) { - data = global_trace.data[i] = &per_cpu(global_trace_cpu, i); + global_trace.data[i] = &per_cpu(global_trace_cpu, i); max_tr.data[i] = &per_cpu(max_data, i); } -- cgit v0.10.2 From d34a4debef933061924ee17c2ede33f5c44925fb Mon Sep 17 00:00:00 2001 From: "jolsa@redhat.com" Date: Thu, 16 Jul 2009 21:44:28 +0200 Subject: tracing: Remove .globl in the scripts/recordmcount.pl doc I was reading throught the recordmcount.pl starting comment, and spotted a tiny discrepancy. The second example is about my_func not being global, but the example code has the ".globl my_func" statement just moved. Signed-off-by: Jiri Olsa Cc: rostedt@goodmis.org LKML-Reference: <1247773468-11594-4-git-send-email-jolsa@redhat.com> Signed-off-by: Ingo Molnar diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 7109e2b..db4ebe1 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -57,7 +57,6 @@ # call mcount (offset: 0x5) # [...] # ret -# .globl my_func # other_func: # [...] # call mcount (offset: 0x1b) -- cgit v0.10.2 From e7aaaa6934636d7a6cadd9e2a05250fbb6a34f65 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: sched: Drop the need_resched() loop from cond_resched() The schedule() function is a loop that reschedules the current task while the TIF_NEED_RESCHED flag is set: void schedule(void) { need_resched: /* schedule code */ if (need_resched()) goto need_resched; } And cond_resched() repeat this loop: do { add_preempt_count(PREEMPT_ACTIVE); schedule(); sub_preempt_count(PREEMPT_ACTIVE); } while(need_resched()); This loop is needless because schedule() already did the check and nothing can set TIF_NEED_RESCHED between schedule() exit and the loop check in need_resched(). Then remove this needless loop. Signed-off-by: Frederic Weisbecker Acked-by: Peter Zijlstra Signed-off-by: Peter Zijlstra LKML-Reference: <1247725694-6082-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 03f7e3f..4c5ee84 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6618,11 +6618,9 @@ static void __cond_resched(void) * PREEMPT_ACTIVE, which could trigger a second * cond_resched() call. */ - do { - add_preempt_count(PREEMPT_ACTIVE); - schedule(); - sub_preempt_count(PREEMPT_ACTIVE); - } while (need_resched()); + add_preempt_count(PREEMPT_ACTIVE); + schedule(); + sub_preempt_count(PREEMPT_ACTIVE); } int __sched _cond_resched(void) -- cgit v0.10.2 From 4b2155678d7cc7b5f45d6b36049091376c3408a2 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: sched: Remove obsolete comment in __cond_resched() Remove the outdated comment from __cond_resched() related to the now removed Big Kernel Semaphore. Reported-by: Arnd Bergmann Reported-by: Ingo Molnar Signed-off-by: Frederic Weisbecker Signed-off-by: Peter Zijlstra LKML-Reference: <1247725694-6082-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 4c5ee84..4d39e96 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6613,11 +6613,6 @@ static void __cond_resched(void) #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP __might_sleep(__FILE__, __LINE__); #endif - /* - * The BKS might be reacquired before we have dropped - * PREEMPT_ACTIVE, which could trigger a second - * cond_resched() call. - */ add_preempt_count(PREEMPT_ACTIVE); schedule(); sub_preempt_count(PREEMPT_ACTIVE); -- cgit v0.10.2 From e09758fae8ccde97e026c704319eaa18d488dc86 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: sched: Cover the CONFIG_DEBUG_SPINLOCK_SLEEP off-case for __might_sleep() Cover the off case for __might_sleep(), so that we avoid #ifdefs in files that make use of it. Especially, this prepares for the __might_sleep() pull up on cond_resched(). Signed-off-by: Frederic Weisbecker Signed-off-by: Peter Zijlstra LKML-Reference: <1247725694-6082-3-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/kernel.h b/include/linux/kernel.h index d6320a3..b804f69 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -139,6 +139,7 @@ extern int _cond_resched(void); # define might_sleep() \ do { __might_sleep(__FILE__, __LINE__); might_resched(); } while (0) #else + static inline void __might_sleep(char *file, int line) { } # define might_sleep() do { might_resched(); } while (0) #endif diff --git a/kernel/sched.c b/kernel/sched.c index 4d39e96..370a6c3 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6610,9 +6610,8 @@ static inline int should_resched(void) static void __cond_resched(void) { -#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP __might_sleep(__FILE__, __LINE__); -#endif + add_preempt_count(PREEMPT_ACTIVE); schedule(); sub_preempt_count(PREEMPT_ACTIVE); -- cgit v0.10.2 From e4aafea2d4bde8b44d6500c4ee7195bbfc51269e Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: sched: Add a preempt count base offset to __might_sleep() Add a preempt count base offset to compare against the current preempt level count. It prepares to pull up the might_sleep check from cond_resched() to cond_resched_lock() and cond_resched_bh(). For these two helpers, we need to respectively ensure that once we'll unlock the given spinlock / reenable local softirqs, we will reach a sleepable state. Signed-off-by: Frederic Weisbecker [ Move and rename preempt_count_equals() ] Signed-off-by: Peter Zijlstra LKML-Reference: <1247725694-6082-4-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/kernel.h b/include/linux/kernel.h index b804f69..2b5b1e0 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -125,7 +125,7 @@ extern int _cond_resched(void); #endif #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP - void __might_sleep(char *file, int line); + void __might_sleep(char *file, int line, int preempt_offset); /** * might_sleep - annotation for functions that can sleep * @@ -137,9 +137,9 @@ extern int _cond_resched(void); * supposed to. */ # define might_sleep() \ - do { __might_sleep(__FILE__, __LINE__); might_resched(); } while (0) + do { __might_sleep(__FILE__, __LINE__, 0); might_resched(); } while (0) #else - static inline void __might_sleep(char *file, int line) { } + static inline void __might_sleep(char *file, int line, int preempt_offset) { } # define might_sleep() do { might_resched(); } while (0) #endif diff --git a/kernel/sched.c b/kernel/sched.c index 370a6c3..3ff4d00 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6610,7 +6610,7 @@ static inline int should_resched(void) static void __cond_resched(void) { - __might_sleep(__FILE__, __LINE__); + __might_sleep(__FILE__, __LINE__, 0); add_preempt_count(PREEMPT_ACTIVE); schedule(); @@ -9429,13 +9429,20 @@ void __init sched_init(void) } #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP -void __might_sleep(char *file, int line) +static inline int preempt_count_equals(int preempt_offset) +{ + int nested = preempt_count() & ~PREEMPT_ACTIVE; + + return (nested == PREEMPT_INATOMIC_BASE + preempt_offset); +} + +void __might_sleep(char *file, int line, int preempt_offset) { #ifdef in_atomic static unsigned long prev_jiffy; /* ratelimiting */ - if ((!in_atomic() && !irqs_disabled()) || - system_state != SYSTEM_RUNNING || oops_in_progress) + if ((preempt_count_equals(preempt_offset) && !irqs_disabled()) || + system_state != SYSTEM_RUNNING || oops_in_progress) return; if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) return; -- cgit v0.10.2 From 6f80bd985fe242c2e6a8b6209ed20b0495d3d63b Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: sched: Remove the CONFIG_PREEMPT_BKL case definition of cond_resched() CONFIG_PREEMPT_BKL doesn't exist anymore. So remove this config-on case definition of cond_resched(). Reported-by: Peter Zijlstra Reported-by: Ingo Molnar Signed-off-by: Frederic Weisbecker Signed-off-by: Peter Zijlstra LKML-Reference: <1247725694-6082-5-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 9bada20..e2bdf18 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2285,17 +2285,12 @@ static inline int need_resched(void) * cond_resched_softirq() will enable bhs before scheduling. */ extern int _cond_resched(void); -#ifdef CONFIG_PREEMPT_BKL -static inline int cond_resched(void) -{ - return 0; -} -#else + static inline int cond_resched(void) { return _cond_resched(); } -#endif + extern int cond_resched_lock(spinlock_t * lock); extern int cond_resched_softirq(void); static inline int cond_resched_bkl(void) -- cgit v0.10.2 From 613afbf83298efaead05ebcac23d2285609d7160 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: sched: Pull up the might_sleep() check into cond_resched() might_sleep() is called late-ish in cond_resched(), after the need_resched()/preempt enabled/system running tests are checked. It's better to check the sleeps while atomic earlier and not depend on some environment datas that reduce the chances to detect a problem. Also define cond_resched_*() helpers as macros, so that the FILE/LINE reported in the sleeping while atomic warning displays the real origin and not sched.h Changes in v2: - Call __might_sleep() directly instead of might_sleep() which may call cond_resched() - Turn cond_resched() into a macro so that the file:line couple reported refers to the caller of cond_resched() and not __cond_resched() itself. Changes in v3: - Also propagate this __might_sleep() pull up to cond_resched_lock() and cond_resched_softirq() Signed-off-by: Frederic Weisbecker Signed-off-by: Peter Zijlstra LKML-Reference: <1247725694-6082-6-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/fs/dcache.c b/fs/dcache.c index 9e5cd3c..a100fa3 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "internal.h" int sysctl_vfs_cache_pressure __read_mostly = 100; diff --git a/include/linux/sched.h b/include/linux/sched.h index e2bdf18..c41d424 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2286,17 +2286,26 @@ static inline int need_resched(void) */ extern int _cond_resched(void); -static inline int cond_resched(void) -{ - return _cond_resched(); -} +#define cond_resched() ({ \ + __might_sleep(__FILE__, __LINE__, 0); \ + _cond_resched(); \ +}) -extern int cond_resched_lock(spinlock_t * lock); -extern int cond_resched_softirq(void); -static inline int cond_resched_bkl(void) -{ - return _cond_resched(); -} +extern int __cond_resched_lock(spinlock_t *lock); + +#define cond_resched_lock(lock) ({ \ + __might_sleep(__FILE__, __LINE__, PREEMPT_OFFSET); \ + __cond_resched_lock(lock); \ +}) + +extern int __cond_resched_softirq(void); + +#define cond_resched_softirq() ({ \ + __might_sleep(__FILE__, __LINE__, SOFTIRQ_OFFSET); \ + __cond_resched_softirq(); \ +}) + +#define cond_resched_bkl() cond_resched() /* * Does a critical section need to be broken due to another diff --git a/kernel/sched.c b/kernel/sched.c index 3ff4d00..1f7919a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6610,8 +6610,6 @@ static inline int should_resched(void) static void __cond_resched(void) { - __might_sleep(__FILE__, __LINE__, 0); - add_preempt_count(PREEMPT_ACTIVE); schedule(); sub_preempt_count(PREEMPT_ACTIVE); @@ -6628,14 +6626,14 @@ int __sched _cond_resched(void) EXPORT_SYMBOL(_cond_resched); /* - * cond_resched_lock() - if a reschedule is pending, drop the given lock, + * __cond_resched_lock() - if a reschedule is pending, drop the given lock, * call schedule, and on return reacquire the lock. * * This works OK both with and without CONFIG_PREEMPT. We do strange low-level * operations here to prevent schedule() from being called twice (once via * spin_unlock(), once by hand). */ -int cond_resched_lock(spinlock_t *lock) +int __cond_resched_lock(spinlock_t *lock) { int resched = should_resched(); int ret = 0; @@ -6651,9 +6649,9 @@ int cond_resched_lock(spinlock_t *lock) } return ret; } -EXPORT_SYMBOL(cond_resched_lock); +EXPORT_SYMBOL(__cond_resched_lock); -int __sched cond_resched_softirq(void) +int __sched __cond_resched_softirq(void) { BUG_ON(!in_softirq()); @@ -6665,7 +6663,7 @@ int __sched cond_resched_softirq(void) } return 0; } -EXPORT_SYMBOL(cond_resched_softirq); +EXPORT_SYMBOL(__cond_resched_softirq); /** * yield - yield the current processor to other threads. -- cgit v0.10.2 From def01bc53d03881acfc393bd10a5c7575187e008 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: sched: Convert the only user of cond_resched_bkl to use cond_resched() fs/locks.c:flock_lock_file() is the only user of cond_resched_bkl() This helper doesn't do anything more than cond_resched(). The latter naming is enough to explain that we are rescheduling if needed. The bkl suffix suggests another semantics but it's actually a synonym of cond_resched(). Reported-by: Peter Zijlstra Signed-off-by: Frederic Weisbecker Signed-off-by: Peter Zijlstra LKML-Reference: <1247725694-6082-7-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/fs/locks.c b/fs/locks.c index b6440f5..2eb8197 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -768,7 +768,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) * give it the opportunity to lock the file. */ if (found) - cond_resched_bkl(); + cond_resched(); find_conflict: for_each_lock(inode, before) { diff --git a/include/linux/sched.h b/include/linux/sched.h index c41d424..cbbfca6 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2305,8 +2305,6 @@ extern int __cond_resched_softirq(void); __cond_resched_softirq(); \ }) -#define cond_resched_bkl() cond_resched() - /* * Does a critical section need to be broken due to another * task waiting?: (technically does not depend on CONFIG_PREEMPT, -- cgit v0.10.2 From 254e0a6bff87ab8b22293c4bd1443507df698407 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 19 Jul 2009 00:08:54 +0900 Subject: x86: Use get_desc_base() Use get_desc_base() to get the base address in desc_struct Signed-off-by: Akinobu Mita LKML-Reference: <20090718150853.GA11294@localhost.localdomain> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/doublefault_32.c b/arch/x86/kernel/doublefault_32.c index b4f14c6..37250fe 100644 --- a/arch/x86/kernel/doublefault_32.c +++ b/arch/x86/kernel/doublefault_32.c @@ -27,9 +27,7 @@ static void doublefault_fn(void) if (ptr_ok(gdt)) { gdt += GDT_ENTRY_TSS << 3; - tss = *(u16 *)(gdt+2); - tss += *(u8 *)(gdt+4) << 16; - tss += *(u8 *)(gdt+7) << 24; + tss = get_desc_base((struct desc_struct *)gdt); printk(KERN_EMERG "double fault, tss at %08lx\n", tss); if (ptr_ok(tss)) { diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c index e8b9863..3149032 100644 --- a/arch/x86/kernel/step.c +++ b/arch/x86/kernel/step.c @@ -4,6 +4,7 @@ #include #include #include +#include unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs) { @@ -23,7 +24,7 @@ unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *re * and APM bios ones we just ignore here. */ if ((seg & SEGMENT_TI_MASK) == SEGMENT_LDT) { - u32 *desc; + struct desc_struct *desc; unsigned long base; seg &= ~7UL; @@ -33,12 +34,10 @@ unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *re addr = -1L; /* bogus selector, access would fault */ else { desc = child->mm->context.ldt + seg; - base = ((desc[0] >> 16) | - ((desc[1] & 0xff) << 16) | - (desc[1] & 0xff000000)); + base = get_desc_base(desc); /* 16-bit code segment? */ - if (!((desc[1] >> 22) & 1)) + if (!desc->d) addr &= 0xffff; addr += base; } -- cgit v0.10.2 From fde0312d01b60a3fd5dc56e69a9613defbbc7097 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 19 Jul 2009 00:09:56 +0900 Subject: x86: Remove unused patch_espfix_desc() patch_espfix_desc() is not used after commit dc4c2a0aed3b09f6e255bd5c3faa50fe6e0b2ded Signed-off-by: Akinobu Mita LKML-Reference: <20090718150955.GB11294@localhost.localdomain> Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index bfd74c0..4da91ad 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -81,9 +81,7 @@ extern int panic_on_unrecovered_nmi; void math_error(void __user *); void math_emulate(struct math_emu_info *); -#ifdef CONFIG_X86_32 -unsigned long patch_espfix_desc(unsigned long, unsigned long); -#else +#ifndef CONFIG_X86_32 asmlinkage void smp_thermal_interrupt(void); asmlinkage void mce_threshold_interrupt(void); #endif diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 5204332..2367941 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -786,27 +786,6 @@ do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) #endif } -#ifdef CONFIG_X86_32 -unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) -{ - struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id()); - unsigned long base = (kesp - uesp) & -THREAD_SIZE; - unsigned long new_kesp = kesp - base; - unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; - __u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS]; - - /* Set up base for espfix segment */ - desc &= 0x00f0ff0000000000ULL; - desc |= ((((__u64)base) << 16) & 0x000000ffffff0000ULL) | - ((((__u64)base) << 32) & 0xff00000000000000ULL) | - ((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) | - (lim_pages & 0xffff); - *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc; - - return new_kesp; -} -#endif - asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) { } -- cgit v0.10.2 From 57594742a2b545f8f114cda34f15650be8ae976d Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 19 Jul 2009 00:11:06 +0900 Subject: x86: Introduce set_desc_base() and set_desc_limit() Rename set_base()/set_limit to set_desc_base()/set_desc_limit() and rewrite them in C. These are naturally introduced by the idea of get_desc_base()/get_desc_limit(). The conversion actually found the bug in apm_32.c: bad_bios_desc is written at run-time, but it is defined const variable. Signed-off-by: Akinobu Mita LKML-Reference: <20090718151105.GC11294@localhost.localdomain> Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h index c993e9e..e8de2f6 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h @@ -291,11 +291,24 @@ static inline unsigned long get_desc_base(const struct desc_struct *desc) return desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24); } +static inline void set_desc_base(struct desc_struct *desc, unsigned long base) +{ + desc->base0 = base & 0xffff; + desc->base1 = (base >> 16) & 0xff; + desc->base2 = (base >> 24) & 0xff; +} + static inline unsigned long get_desc_limit(const struct desc_struct *desc) { return desc->limit0 | (desc->limit << 16); } +static inline void set_desc_limit(struct desc_struct *desc, unsigned long limit) +{ + desc->limit0 = limit & 0xffff; + desc->limit = (limit >> 16) & 0xf; +} + static inline void _set_gate(int gate, unsigned type, void *addr, unsigned dpl, unsigned ist, unsigned seg) { diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h index c2d742c..cdc5e0b 100644 --- a/arch/x86/include/asm/stackprotector.h +++ b/arch/x86/include/asm/stackprotector.h @@ -90,9 +90,7 @@ static inline void setup_stack_canary_segment(int cpu) struct desc_struct desc; desc = gdt_table[GDT_ENTRY_STACK_CANARY]; - desc.base0 = canary & 0xffff; - desc.base1 = (canary >> 16) & 0xff; - desc.base2 = (canary >> 24) & 0xff; + set_desc_base(&desc, canary); write_gdt_entry(gdt_table, GDT_ENTRY_STACK_CANARY, &desc, DESCTYPE_S); #endif } diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h index 643c59b..75c49c7 100644 --- a/arch/x86/include/asm/system.h +++ b/arch/x86/include/asm/system.h @@ -150,33 +150,6 @@ do { \ #endif #ifdef __KERNEL__ -#define _set_base(addr, base) do { unsigned long __pr; \ -__asm__ __volatile__ ("movw %%dx,%1\n\t" \ - "rorl $16,%%edx\n\t" \ - "movb %%dl,%2\n\t" \ - "movb %%dh,%3" \ - :"=&d" (__pr) \ - :"m" (*((addr)+2)), \ - "m" (*((addr)+4)), \ - "m" (*((addr)+7)), \ - "0" (base) \ - ); } while (0) - -#define _set_limit(addr, limit) do { unsigned long __lr; \ -__asm__ __volatile__ ("movw %%dx,%1\n\t" \ - "rorl $16,%%edx\n\t" \ - "movb %2,%%dh\n\t" \ - "andb $0xf0,%%dh\n\t" \ - "orb %%dh,%%dl\n\t" \ - "movb %%dl,%2" \ - :"=&d" (__lr) \ - :"m" (*(addr)), \ - "m" (*((addr)+6)), \ - "0" (limit) \ - ); } while (0) - -#define set_base(ldt, base) _set_base(((char *)&(ldt)) , (base)) -#define set_limit(ldt, limit) _set_limit(((char *)&(ldt)) , ((limit)-1)) extern void native_load_gs_index(unsigned); diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 79302e9..b5e841b 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -403,7 +403,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); static struct apm_user *user_list; static DEFINE_SPINLOCK(user_list_lock); -static const struct desc_struct bad_bios_desc = { { { 0, 0x00409200 } } }; +static struct desc_struct bad_bios_desc = { { { 0, 0x00409200 } } }; static const char driver_version[] = "1.16ac"; /* no spaces */ @@ -2337,8 +2337,8 @@ static int __init apm_init(void) * This is for buggy BIOS's that refer to (real mode) segment 0x40 * even though they are called in protected mode. */ - set_base(bad_bios_desc, __va((unsigned long)0x40 << 4)); - _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4)); + set_desc_base(&bad_bios_desc, (unsigned long)__va(0x40UL << 4)); + set_desc_limit(&bad_bios_desc, 4095 - (0x40 << 4)); /* * Set up the long jump entry point to the APM BIOS, which is called @@ -2358,12 +2358,12 @@ static int __init apm_init(void) * code to that CPU. */ gdt = get_cpu_gdt_table(0); - set_base(gdt[APM_CS >> 3], - __va((unsigned long)apm_info.bios.cseg << 4)); - set_base(gdt[APM_CS_16 >> 3], - __va((unsigned long)apm_info.bios.cseg_16 << 4)); - set_base(gdt[APM_DS >> 3], - __va((unsigned long)apm_info.bios.dseg << 4)); + set_desc_base(&gdt[APM_CS >> 3], + (unsigned long)__va((unsigned long)apm_info.bios.cseg << 4)); + set_desc_base(&gdt[APM_CS_16 >> 3], + (unsigned long)__va((unsigned long)apm_info.bios.cseg_16 << 4)); + set_desc_base(&gdt[APM_DS >> 3], + (unsigned long)__va((unsigned long)apm_info.bios.dseg << 4)); proc_create("apm", 0, NULL, &apm_file_ops); diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index 7e6b5a3..45ad3e9 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -55,9 +55,9 @@ __asm__(".text \n" #define Q2_SET_SEL(cpu, selname, address, size) \ do { \ -struct desc_struct *gdt = get_cpu_gdt_table((cpu)); \ -set_base(gdt[(selname) >> 3], (u32)(address)); \ -set_limit(gdt[(selname) >> 3], size); \ + struct desc_struct *gdt = get_cpu_gdt_table((cpu)); \ + set_desc_base(&gdt[(selname) >> 3], (u32)(address)); \ + set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \ } while(0) static struct desc_struct bad_bios_desc; @@ -479,16 +479,17 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) bad_bios_desc.a = 0; bad_bios_desc.b = 0x00409200; - set_base(bad_bios_desc, __va((unsigned long)0x40 << 4)); - _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4)); + set_desc_base(&bad_bios_desc, (unsigned long)__va(0x40UL << 4)); + set_desc_limit(&bad_bios_desc, 4095 - (0x40 << 4)); for_each_possible_cpu(i) { struct desc_struct *gdt = get_cpu_gdt_table(i); if (!gdt) continue; - set_base(gdt[GDT_ENTRY_PNPBIOS_CS32], &pnp_bios_callfunc); - set_base(gdt[GDT_ENTRY_PNPBIOS_CS16], - __va(header->fields.pm16cseg)); - set_base(gdt[GDT_ENTRY_PNPBIOS_DS], - __va(header->fields.pm16dseg)); + set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS32], + (unsigned long)&pnp_bios_callfunc); + set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS16], + (unsigned long)__va(header->fields.pm16cseg)); + set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_DS], + (unsigned long)__va(header->fields.pm16dseg)); } } -- cgit v0.10.2 From 1c388ad054fb1ead3dc354b1719570b99e464135 Mon Sep 17 00:00:00 2001 From: Paul Menage Date: Fri, 17 Jul 2009 16:16:18 -0700 Subject: include/linux/cred.h: work around gcc-4.2.4 warning in get_cred() With gcc 4.2.4 (building UML) I get the warning include/linux/cred.h: In function 'get_cred': include/linux/cred.h:189: warning: passing argument 1 of 'get_new_cred' discards qualifiers from pointer target type Inserting an additional local variable appears to keep the compiler happy, although it's not clear to me why this should be needed. Signed-off-by: Paul Menage Signed-off-by: Andrew Morton Acked-by: David Howells Signed-off-by: James Morris diff --git a/include/linux/cred.h b/include/linux/cred.h index 4fa9996..b3c76e8 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -186,7 +186,8 @@ static inline struct cred *get_new_cred(struct cred *cred) */ static inline const struct cred *get_cred(const struct cred *cred) { - return get_new_cred((struct cred *) cred); + struct cred *nonconst_cred = (struct cred *) cred; + return get_new_cred(nonconst_cred); } /** -- cgit v0.10.2 From bc5304b6fb6c572452b538512761a126f0e0b0d8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Jul 2009 13:41:35 +0200 Subject: ALSA: ctxfi - Native timer support for emu20k2 Added the native timer support for emu20k2, which gives much more accurate update timing than the system timer. Signed-off-by: Takashi Iwai diff --git a/sound/pci/ctxfi/ct20k2reg.h b/sound/pci/ctxfi/ct20k2reg.h index 2d07986..e0394e3 100644 --- a/sound/pci/ctxfi/ct20k2reg.h +++ b/sound/pci/ctxfi/ct20k2reg.h @@ -11,9 +11,12 @@ /* Timer Registers */ -#define TIMER_TIMR 0x1B7004 -#define INTERRUPT_GIP 0x1B7010 -#define INTERRUPT_GIE 0x1B7014 +#define WC 0x1b7000 +#define TIMR 0x1b7004 +# define TIMR_IE (1<<15) +# define TIMR_IP (1<<14) +#define GIP 0x1b7010 +#define GIE 0x1b7014 /* I2C Registers */ #define I2C_IF_ADDRESS 0x1B9000 diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index dec46d0..0c4db2d 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -1112,6 +1112,26 @@ static int daio_mgr_put_ctrl_blk(void *blk) return 0; } +/* Timer interrupt */ +static int set_timer_irq(struct hw *hw, int enable) +{ + hw_write_20kx(hw, GIE, enable ? IT_INT : 0); + return 0; +} + +static int set_timer_tick(struct hw *hw, unsigned int ticks) +{ + if (ticks) + ticks |= TIMR_IE | TIMR_IP; + hw_write_20kx(hw, TIMR, ticks); + return 0; +} + +static unsigned int get_wc(struct hw *hw) +{ + return hw_read_20kx(hw, WC); +} + /* Card hardware initialization block */ struct dac_conf { unsigned int msr; /* master sample rate in rsrs */ @@ -1841,6 +1861,22 @@ static int hw_have_digit_io_switch(struct hw *hw) return 0; } +static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id) +{ + struct hw *hw = dev_id; + unsigned int status; + + status = hw_read_20kx(hw, GIP); + if (!status) + return IRQ_NONE; + + if (hw->irq_callback) + hw->irq_callback(hw->irq_callback_data, status); + + hw_write_20kx(hw, GIP, status); + return IRQ_HANDLED; +} + static int hw_card_start(struct hw *hw) { int err = 0; @@ -1879,12 +1915,15 @@ static int hw_card_start(struct hw *hw) set_field(&gctl, GCTL_UAA, 0); hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); - /*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED, - atc->chip_details->nm_card, hw))) { - goto error3; + if (hw->irq < 0) { + err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED, + "ctxfi", hw); + if (err < 0) { + printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); + goto error2; + } + hw->irq = pci->irq; } - hw->irq = pci->irq; - */ pci_set_master(pci); @@ -1972,7 +2011,7 @@ static int hw_card_init(struct hw *hw, struct card_conf *info) hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); /* Reset all global pending interrupts */ - hw_write_20kx(hw, INTERRUPT_GIE, 0); + hw_write_20kx(hw, GIE, 0); /* Reset all SRC pending interrupts */ hw_write_20kx(hw, SRC_IP, 0); @@ -2149,6 +2188,10 @@ static struct hw ct20k2_preset __devinitdata = { .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt, .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr, .daio_mgr_commit_write = daio_mgr_commit_write, + + .set_timer_irq = set_timer_irq, + .set_timer_tick = set_timer_tick, + .get_wc = get_wc, }; int __devinit create_20k2_hw_obj(struct hw **rhw) -- cgit v0.10.2 From 4d4036e0e7299c6cbb2d2421b4b30b7a409ce61a Mon Sep 17 00:00:00 2001 From: Jason Yeh Date: Wed, 8 Jul 2009 13:49:38 +0200 Subject: oprofile: Implement performance counter multiplexing The number of hardware counters is limited. The multiplexing feature enables OProfile to gather more events than counters are provided by the hardware. This is realized by switching between events at an user specified time interval. A new file (/dev/oprofile/time_slice) is added for the user to specify the timer interval in ms. If the number of events to profile is higher than the number of hardware counters available, the patch will schedule a work queue that switches the event counter and re-writes the different sets of values into it. The switching mechanism needs to be implemented for each architecture to support multiplexing. This patch only implements AMD CPU support, but multiplexing can be easily extended for other models and architectures. There are follow-on patches that rework parts of this patch. Signed-off-by: Jason Yeh Signed-off-by: Robert Richter diff --git a/arch/Kconfig b/arch/Kconfig index 99193b1..beea3cc 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -30,6 +30,18 @@ config OPROFILE_IBS If unsure, say N. +config OPROFILE_EVENT_MULTIPLEX + bool "OProfile multiplexing support (EXPERIMENTAL)" + default n + depends on OPROFILE && X86 + help + The number of hardware counters is limited. The multiplexing + feature enables OProfile to gather more events than counters + are provided by the hardware. This is realized by switching + between events at an user specified time interval. + + If unsure, say N. + config HAVE_OPROFILE bool diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index fca8dc94..e54f6a0 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -1,11 +1,14 @@ /** * @file nmi_int.c * - * @remark Copyright 2002-2008 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon * @author Robert Richter + * @author Barry Kasindorf + * @author Jason Yeh + * @author Suravee Suthikulpanit */ #include @@ -24,6 +27,12 @@ #include "op_counter.h" #include "op_x86_model.h" + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +DEFINE_PER_CPU(int, switch_index); +#endif + + static struct op_x86_model_spec const *model; static DEFINE_PER_CPU(struct op_msrs, cpu_msrs); static DEFINE_PER_CPU(unsigned long, saved_lvtpc); @@ -31,6 +40,13 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc); /* 0 == registered but off, 1 == registered and on */ static int nmi_enabled = 0; + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +extern atomic_t multiplex_counter; +#endif + +struct op_counter_config counter_config[OP_MAX_COUNTER]; + /* common functions */ u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, @@ -95,6 +111,11 @@ static void free_msrs(void) per_cpu(cpu_msrs, i).counters = NULL; kfree(per_cpu(cpu_msrs, i).controls); per_cpu(cpu_msrs, i).controls = NULL; + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + kfree(per_cpu(cpu_msrs, i).multiplex); + per_cpu(cpu_msrs, i).multiplex = NULL; +#endif } } @@ -103,6 +124,9 @@ static int allocate_msrs(void) int success = 1; size_t controls_size = sizeof(struct op_msr) * model->num_controls; size_t counters_size = sizeof(struct op_msr) * model->num_counters; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + size_t multiplex_size = sizeof(struct op_msr) * model->num_virt_counters; +#endif int i; for_each_possible_cpu(i) { @@ -118,6 +142,14 @@ static int allocate_msrs(void) success = 0; break; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + per_cpu(cpu_msrs, i).multiplex = + kmalloc(multiplex_size, GFP_KERNEL); + if (!per_cpu(cpu_msrs, i).multiplex) { + success = 0; + break; + } +#endif } if (!success) @@ -126,6 +158,25 @@ static int allocate_msrs(void) return success; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void nmi_setup_cpu_mux(struct op_msrs const * const msrs) +{ + int i; + struct op_msr *multiplex = msrs->multiplex; + + for (i = 0; i < model->num_virt_counters; ++i) { + if (counter_config[i].enabled) { + multiplex[i].saved = -(u64)counter_config[i].count; + } else { + multiplex[i].addr = 0; + multiplex[i].saved = 0; + } + } +} + +#endif + static void nmi_cpu_setup(void *dummy) { int cpu = smp_processor_id(); @@ -133,6 +184,9 @@ static void nmi_cpu_setup(void *dummy) nmi_cpu_save_registers(msrs); spin_lock(&oprofilefs_lock); model->setup_ctrs(model, msrs); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + nmi_setup_cpu_mux(msrs); +#endif spin_unlock(&oprofilefs_lock); per_cpu(saved_lvtpc, cpu) = apic_read(APIC_LVTPC); apic_write(APIC_LVTPC, APIC_DM_NMI); @@ -173,14 +227,52 @@ static int nmi_setup(void) memcpy(per_cpu(cpu_msrs, cpu).controls, per_cpu(cpu_msrs, 0).controls, sizeof(struct op_msr) * model->num_controls); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + memcpy(per_cpu(cpu_msrs, cpu).multiplex, + per_cpu(cpu_msrs, 0).multiplex, + sizeof(struct op_msr) * model->num_virt_counters); +#endif } - } on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; return 0; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs) +{ + unsigned int si = __get_cpu_var(switch_index); + struct op_msr *multiplex = msrs->multiplex; + unsigned int i; + + for (i = 0; i < model->num_counters; ++i) { + int offset = i + si; + if (multiplex[offset].addr) { + rdmsrl(multiplex[offset].addr, + multiplex[offset].saved); + } + } +} + +static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs) +{ + unsigned int si = __get_cpu_var(switch_index); + struct op_msr *multiplex = msrs->multiplex; + unsigned int i; + + for (i = 0; i < model->num_counters; ++i) { + int offset = i + si; + if (multiplex[offset].addr) { + wrmsrl(multiplex[offset].addr, + multiplex[offset].saved); + } + } +} + +#endif + static void nmi_cpu_restore_registers(struct op_msrs *msrs) { struct op_msr *counters = msrs->counters; @@ -214,6 +306,9 @@ static void nmi_cpu_shutdown(void *dummy) apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu)); apic_write(APIC_LVTERR, v); nmi_cpu_restore_registers(msrs); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + __get_cpu_var(switch_index) = 0; +#endif } static void nmi_shutdown(void) @@ -252,16 +347,15 @@ static void nmi_stop(void) on_each_cpu(nmi_cpu_stop, NULL, 1); } -struct op_counter_config counter_config[OP_MAX_COUNTER]; - static int nmi_create_files(struct super_block *sb, struct dentry *root) { unsigned int i; - for (i = 0; i < model->num_counters; ++i) { + for (i = 0; i < model->num_virt_counters; ++i) { struct dentry *dir; char buf[4]; +#ifndef CONFIG_OPROFILE_EVENT_MULTIPLEX /* quick little hack to _not_ expose a counter if it is not * available for use. This should protect userspace app. * NOTE: assumes 1:1 mapping here (that counters are organized @@ -269,6 +363,7 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) */ if (unlikely(!avail_to_resrv_perfctr_nmi_bit(i))) continue; +#endif /* CONFIG_OPROFILE_EVENT_MULTIPLEX */ snprintf(buf, sizeof(buf), "%d", i); dir = oprofilefs_mkdir(sb, root, buf); @@ -283,6 +378,57 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) return 0; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void nmi_cpu_switch(void *dummy) +{ + int cpu = smp_processor_id(); + int si = per_cpu(switch_index, cpu); + struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); + + nmi_cpu_stop(NULL); + nmi_cpu_save_mpx_registers(msrs); + + /* move to next set */ + si += model->num_counters; + if ((si > model->num_virt_counters) || (counter_config[si].count == 0)) + per_cpu(switch_index, cpu) = 0; + else + per_cpu(switch_index, cpu) = si; + + model->switch_ctrl(model, msrs); + nmi_cpu_restore_mpx_registers(msrs); + + nmi_cpu_start(NULL); +} + + +/* + * Quick check to see if multiplexing is necessary. + * The check should be sufficient since counters are used + * in ordre. + */ +static int nmi_multiplex_on(void) +{ + return counter_config[model->num_counters].count ? 0 : -EINVAL; +} + +static int nmi_switch_event(void) +{ + if (!model->switch_ctrl) + return -ENOSYS; /* not implemented */ + if (nmi_multiplex_on() < 0) + return -EINVAL; /* not necessary */ + + on_each_cpu(nmi_cpu_switch, NULL, 1); + + atomic_inc(&multiplex_counter); + + return 0; +} + +#endif + #ifdef CONFIG_SMP static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, void *data) @@ -516,12 +662,18 @@ int __init op_nmi_init(struct oprofile_operations *ops) register_cpu_notifier(&oprofile_cpu_nb); #endif /* default values, can be overwritten by model */ +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + __raw_get_cpu_var(switch_index) = 0; +#endif ops->create_files = nmi_create_files; ops->setup = nmi_setup; ops->shutdown = nmi_shutdown; ops->start = nmi_start; ops->stop = nmi_stop; ops->cpu_type = cpu_type; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + ops->switch_events = nmi_switch_event; +#endif if (model->init) ret = model->init(ops); diff --git a/arch/x86/oprofile/op_counter.h b/arch/x86/oprofile/op_counter.h index 91b6a11..e28398d 100644 --- a/arch/x86/oprofile/op_counter.h +++ b/arch/x86/oprofile/op_counter.h @@ -10,7 +10,7 @@ #ifndef OP_COUNTER_H #define OP_COUNTER_H -#define OP_MAX_COUNTER 8 +#define OP_MAX_COUNTER 32 /* Per-perfctr configuration as set via * oprofilefs. diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index f676f88..fdbed3a 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -9,12 +9,15 @@ * @author Philippe Elie * @author Graydon Hoare * @author Robert Richter - * @author Barry Kasindorf + * @author Barry Kasindorf + * @author Jason Yeh + * @author Suravee Suthikulpanit */ #include #include #include +#include #include #include @@ -25,12 +28,23 @@ #define NUM_COUNTERS 4 #define NUM_CONTROLS 4 +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +#define NUM_VIRT_COUNTERS 32 +#define NUM_VIRT_CONTROLS 32 +#else +#define NUM_VIRT_COUNTERS NUM_COUNTERS +#define NUM_VIRT_CONTROLS NUM_CONTROLS +#endif + #define OP_EVENT_MASK 0x0FFF #define OP_CTR_OVERFLOW (1ULL<<31) #define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21)) -static unsigned long reset_value[NUM_COUNTERS]; +static unsigned long reset_value[NUM_VIRT_COUNTERS]; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +DECLARE_PER_CPU(int, switch_index); +#endif #ifdef CONFIG_OPROFILE_IBS @@ -82,6 +96,16 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) else msrs->controls[i].addr = 0; } + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + for (i = 0; i < NUM_VIRT_COUNTERS; i++) { + int hw_counter = i % NUM_CONTROLS; + if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) + msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter; + else + msrs->multiplex[i].addr = 0; + } +#endif } static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, @@ -90,6 +114,15 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, u64 val; int i; + /* setup reset_value */ + for (i = 0; i < NUM_VIRT_COUNTERS; ++i) { + if (counter_config[i].enabled) { + reset_value[i] = counter_config[i].count; + } else { + reset_value[i] = 0; + } + } + /* clear all counters */ for (i = 0; i < NUM_CONTROLS; ++i) { if (unlikely(!msrs->controls[i].addr)) @@ -108,20 +141,49 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { - if (counter_config[i].enabled && msrs->counters[i].addr) { - reset_value[i] = counter_config[i].count; - wrmsrl(msrs->counters[i].addr, - -(u64)counter_config[i].count); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + int offset = i + __get_cpu_var(switch_index); +#else + int offset = i; +#endif + if (counter_config[offset].enabled && msrs->counters[i].addr) { + /* setup counter registers */ + wrmsrl(msrs->counters[i].addr, -(u64)reset_value[offset]); + + /* setup control registers */ rdmsrl(msrs->controls[i].addr, val); val &= model->reserved; - val |= op_x86_get_ctrl(model, &counter_config[i]); + val |= op_x86_get_ctrl(model, &counter_config[offset]); + wrmsrl(msrs->controls[i].addr, val); + } + } +} + + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void op_amd_switch_ctrl(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs) +{ + u64 val; + int i; + + /* enable active counters */ + for (i = 0; i < NUM_COUNTERS; ++i) { + int offset = i + __get_cpu_var(switch_index); + if (counter_config[offset].enabled) { + /* setup control registers */ + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[offset]); wrmsrl(msrs->controls[i].addr, val); - } else { - reset_value[i] = 0; } } } +#endif + + #ifdef CONFIG_OPROFILE_IBS static inline int @@ -230,14 +292,19 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, int i; for (i = 0; i < NUM_COUNTERS; ++i) { - if (!reset_value[i]) +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + int offset = i + __get_cpu_var(switch_index); +#else + int offset = i; +#endif + if (!reset_value[offset]) continue; rdmsrl(msrs->counters[i].addr, val); /* bit is clear if overflowed: */ if (val & OP_CTR_OVERFLOW) continue; - oprofile_add_sample(regs, i); - wrmsrl(msrs->counters[i].addr, -(u64)reset_value[i]); + oprofile_add_sample(regs, offset); + wrmsrl(msrs->counters[i].addr, -(u64)reset_value[offset]); } op_amd_handle_ibs(regs, msrs); @@ -250,8 +317,14 @@ static void op_amd_start(struct op_msrs const * const msrs) { u64 val; int i; + for (i = 0; i < NUM_COUNTERS; ++i) { - if (reset_value[i]) { +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + int offset = i + __get_cpu_var(switch_index); +#else + int offset = i; +#endif + if (reset_value[offset]) { rdmsrl(msrs->controls[i].addr, val); val |= ARCH_PERFMON_EVENTSEL0_ENABLE; wrmsrl(msrs->controls[i].addr, val); @@ -271,7 +344,11 @@ static void op_amd_stop(struct op_msrs const * const msrs) * pm callback */ for (i = 0; i < NUM_COUNTERS; ++i) { +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + if (!reset_value[i + per_cpu(switch_index, smp_processor_id())]) +#else if (!reset_value[i]) +#endif continue; rdmsrl(msrs->controls[i].addr, val); val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; @@ -289,7 +366,7 @@ static void op_amd_shutdown(struct op_msrs const * const msrs) if (msrs->counters[i].addr) release_perfctr_nmi(MSR_K7_PERFCTR0 + i); } - for (i = 0; i < NUM_CONTROLS; ++i) { + for (i = 0; i < NUM_COUNTERS; ++i) { if (msrs->controls[i].addr) release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); } @@ -463,6 +540,8 @@ static void op_amd_exit(void) {} struct op_x86_model_spec const op_amd_spec = { .num_counters = NUM_COUNTERS, .num_controls = NUM_CONTROLS, + .num_virt_counters = NUM_VIRT_COUNTERS, + .num_virt_controls = NUM_VIRT_CONTROLS, .reserved = MSR_AMD_EVENTSEL_RESERVED, .event_mask = OP_EVENT_MASK, .init = op_amd_init, @@ -473,4 +552,7 @@ struct op_x86_model_spec const op_amd_spec = { .start = &op_amd_start, .stop = &op_amd_stop, .shutdown = &op_amd_shutdown, +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + .switch_ctrl = &op_amd_switch_ctrl, +#endif }; diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 5921b7f..65b9237 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -698,6 +698,8 @@ static void p4_shutdown(struct op_msrs const * const msrs) struct op_x86_model_spec const op_p4_ht2_spec = { .num_counters = NUM_COUNTERS_HT2, .num_controls = NUM_CONTROLS_HT2, + .num_virt_counters = NUM_COUNTERS_HT2, + .num_virt_controls = NUM_CONTROLS_HT2, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, @@ -710,6 +712,8 @@ struct op_x86_model_spec const op_p4_ht2_spec = { struct op_x86_model_spec const op_p4_spec = { .num_counters = NUM_COUNTERS_NON_HT, .num_controls = NUM_CONTROLS_NON_HT, + .num_virt_counters = NUM_COUNTERS_NON_HT, + .num_virt_controls = NUM_CONTROLS_NON_HT, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 570d717..098cbca 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -206,6 +206,8 @@ static void ppro_shutdown(struct op_msrs const * const msrs) struct op_x86_model_spec const op_ppro_spec = { .num_counters = 2, .num_controls = 2, + .num_virt_counters = 2, + .num_virt_controls = 2, .reserved = MSR_PPRO_EVENTSEL_RESERVED, .fill_in_addresses = &ppro_fill_in_addresses, .setup_ctrs = &ppro_setup_ctrs, diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 5054898..0d07d23 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -23,6 +23,7 @@ struct op_msr { struct op_msrs { struct op_msr *counters; struct op_msr *controls; + struct op_msr *multiplex; }; struct pt_regs; @@ -35,6 +36,8 @@ struct oprofile_operations; struct op_x86_model_spec { unsigned int num_counters; unsigned int num_controls; + unsigned int num_virt_counters; + unsigned int num_virt_controls; u64 reserved; u16 event_mask; int (*init)(struct oprofile_operations *ops); @@ -47,6 +50,10 @@ struct op_x86_model_spec { void (*start)(struct op_msrs const * const msrs); void (*stop)(struct op_msrs const * const msrs); void (*shutdown)(struct op_msrs const * const msrs); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + void (*switch_ctrl)(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs); +#endif }; struct op_counter_config; diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 3cffce9..7bc64af 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include "oprof.h" @@ -27,6 +29,15 @@ unsigned long oprofile_backtrace_depth; static unsigned long is_setup; static DEFINE_MUTEX(start_mutex); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void switch_worker(struct work_struct *work); +static DECLARE_DELAYED_WORK(switch_work, switch_worker); +unsigned long timeout_jiffies; +#define MULTIPLEXING_TIMER_DEFAULT 1 + +#endif + /* timer 0 - use performance monitoring hardware if available 1 - use the timer int mechanism regardless @@ -87,6 +98,20 @@ out: return err; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void start_switch_worker(void) +{ + schedule_delayed_work(&switch_work, timeout_jiffies); +} + +static void switch_worker(struct work_struct *work) +{ + if (!oprofile_ops.switch_events()) + start_switch_worker(); +} + +#endif /* Actually start profiling (echo 1>/dev/oprofile/enable) */ int oprofile_start(void) @@ -108,6 +133,11 @@ int oprofile_start(void) if ((err = oprofile_ops.start())) goto out; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + if (oprofile_ops.switch_events) + start_switch_worker(); +#endif + oprofile_started = 1; out: mutex_unlock(&start_mutex); @@ -123,6 +153,11 @@ void oprofile_stop(void) goto out; oprofile_ops.stop(); oprofile_started = 0; + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + cancel_delayed_work_sync(&switch_work); +#endif + /* wake up the daemon to read what remains */ wake_up_buffer_waiter(); out: @@ -155,6 +190,36 @@ post_sync: mutex_unlock(&start_mutex); } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +/* User inputs in ms, converts to jiffies */ +int oprofile_set_timeout(unsigned long val_msec) +{ + int err = 0; + + mutex_lock(&start_mutex); + + if (oprofile_started) { + err = -EBUSY; + goto out; + } + + if (!oprofile_ops.switch_events) { + err = -EINVAL; + goto out; + } + + timeout_jiffies = msecs_to_jiffies(val_msec); + if (timeout_jiffies == MAX_JIFFY_OFFSET) + timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); + +out: + mutex_unlock(&start_mutex); + return err; + +} + +#endif int oprofile_set_backtrace(unsigned long val) { @@ -179,10 +244,23 @@ out: return err; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void __init oprofile_multiplexing_init(void) +{ + timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); +} + +#endif + static int __init oprofile_init(void) { int err; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + oprofile_multiplexing_init(); +#endif + err = oprofile_arch_init(&oprofile_ops); if (err < 0 || timer) { diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index c288d3c..ee38abc 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -27,6 +27,7 @@ extern unsigned long oprofile_buffer_watershed; extern struct oprofile_operations oprofile_ops; extern unsigned long oprofile_started; extern unsigned long oprofile_backtrace_depth; +extern unsigned long timeout_jiffies; struct super_block; struct dentry; @@ -35,5 +36,6 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root); void oprofile_timer_init(struct oprofile_operations *ops); int oprofile_set_backtrace(unsigned long depth); +int oprofile_set_timeout(unsigned long time); #endif /* OPROF_H */ diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 5d36ffc..468ec3e 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -9,6 +9,7 @@ #include #include +#include #include "event_buffer.h" #include "oprofile_stats.h" @@ -22,6 +23,45 @@ unsigned long oprofile_buffer_size; unsigned long oprofile_cpu_buffer_size; unsigned long oprofile_buffer_watershed; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static ssize_t timeout_read(struct file *file, char __user *buf, + size_t count, loff_t *offset) +{ + return oprofilefs_ulong_to_user(jiffies_to_msecs(timeout_jiffies), + buf, count, offset); +} + + +static ssize_t timeout_write(struct file *file, char const __user *buf, + size_t count, loff_t *offset) +{ + unsigned long val; + int retval; + + if (*offset) + return -EINVAL; + + retval = oprofilefs_ulong_from_user(&val, buf, count); + if (retval) + return retval; + + retval = oprofile_set_timeout(val); + + if (retval) + return retval; + return count; +} + + +static const struct file_operations timeout_fops = { + .read = timeout_read, + .write = timeout_write, +}; + +#endif + + static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { return oprofilefs_ulong_to_user(oprofile_backtrace_depth, buf, count, @@ -139,6 +179,9 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root) oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops); oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + oprofilefs_create_file(sb, root, "time_slice", &timeout_fops); +#endif oprofile_create_stats_files(sb, root); if (oprofile_ops.create_files) oprofile_ops.create_files(sb, root); diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 3c2270a..77a57a6 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -16,6 +16,9 @@ #include "cpu_buffer.h" struct oprofile_stat_struct oprofile_stats; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +atomic_t multiplex_counter; +#endif void oprofile_reset_stats(void) { @@ -34,6 +37,9 @@ void oprofile_reset_stats(void) atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); atomic_set(&oprofile_stats.bt_lost_no_mapping, 0); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + atomic_set(&multiplex_counter, 0); +#endif } @@ -76,4 +82,8 @@ void oprofile_create_stats_files(struct super_block *sb, struct dentry *root) &oprofile_stats.event_lost_overflow); oprofilefs_create_ro_atomic(sb, dir, "bt_lost_no_mapping", &oprofile_stats.bt_lost_no_mapping); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + oprofilefs_create_ro_atomic(sb, dir, "multiplex_counter", + &multiplex_counter); +#endif } diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index d68d2ed..5171639 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -67,6 +67,9 @@ struct oprofile_operations { /* Initiate a stack backtrace. Optional. */ void (*backtrace)(struct pt_regs * const regs, unsigned int depth); + + /* Multiplex between different events. Optional. */ + int (*switch_events)(void); /* CPU identification string. */ char * cpu_type; }; -- cgit v0.10.2 From 2e477c9bd2bb6a1606e498adb53ba913378ecdf2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 20 Jul 2009 07:35:37 -0700 Subject: vlan: Propagate physical MTU changes When the physical MTU changes we want to ensure that all existing VLAN device MTUs do not exceed the new underlying MTU. This patch adds that propagation. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index fe64908..6d37b7e 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -468,6 +468,19 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, } break; + case NETDEV_CHANGEMTU: + for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + vlandev = vlan_group_get_device(grp, i); + if (!vlandev) + continue; + + if (vlandev->mtu <= dev->mtu) + continue; + + dev_set_mtu(vlandev, dev->mtu); + } + break; + case NETDEV_FEAT_CHANGE: /* Propagate device features to underlying device */ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { -- cgit v0.10.2 From c3059477fce2d956a0bb3e04357324780c5d8eeb Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Tue, 14 Jul 2009 08:33:08 +0000 Subject: ipv4: Use synchronize_rcu() during trie_rebalance() During trie_rebalance() we free memory after resizing with call_rcu(), but large updates, especially with PREEMPT_NONE configs, can cause memory stresses, so this patch calls synchronize_rcu() in tnode_free_flush() after each sync_pages to guarantee such freeing (especially before resizing the root node). The value of sync_pages = 128 is based on Pawel Staszewski's tests as the lowest which doesn't hinder updating times. (For testing purposes there was a sysfs module parameter to change it on demand, but it's removed until we're sure it could be really useful.) The patch is based on suggestions by: Paul E. McKenney Reported-by: Pawel Staszewski Tested-by: Pawel Staszewski Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 63c2fa7..58ba9f4 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -164,6 +164,14 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn); static struct tnode *halve(struct trie *t, struct tnode *tn); /* tnodes to free after resize(); protected by RTNL */ static struct tnode *tnode_free_head; +static size_t tnode_free_size; + +/* + * synchronize_rcu after call_rcu for that many pages; it should be especially + * useful before resizing the root node with PREEMPT_NONE configs; the value was + * obtained experimentally, aiming to avoid visible slowdown. + */ +static const int sync_pages = 128; static struct kmem_cache *fn_alias_kmem __read_mostly; static struct kmem_cache *trie_leaf_kmem __read_mostly; @@ -393,6 +401,8 @@ static void tnode_free_safe(struct tnode *tn) BUG_ON(IS_LEAF(tn)); tn->tnode_free = tnode_free_head; tnode_free_head = tn; + tnode_free_size += sizeof(struct tnode) + + (sizeof(struct node *) << tn->bits); } static void tnode_free_flush(void) @@ -404,6 +414,11 @@ static void tnode_free_flush(void) tn->tnode_free = NULL; tnode_free(tn); } + + if (tnode_free_size >= PAGE_SIZE * sync_pages) { + tnode_free_size = 0; + synchronize_rcu(); + } } static struct leaf *leaf_new(void) -- cgit v0.10.2 From be916cdebe4dc720a23b1a9bb589f2c22afd6589 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Tue, 14 Jul 2009 09:41:00 +0000 Subject: ipv4: Fix inflate_threshold_root automatically During large updates there could be triggered warnings like: "Fix inflate_threshold_root. Now=25 size=11 bits" if inflate() of the root node isn't finished in 10 loops. It should be much rarer now, after changing the threshold from 15 to 25, and a temporary problem, so this patch tries to handle it automatically using a fix variable to increase by one inflate threshold for next root resizes (up to the 35 limit, max fix = 10). The fix variable is decreased when root's inflate() finishes below 7 loops (even if some other, smaller table/ trie is updated -- for simplicity the fix variable is global for now). Reported-by: Pawel Staszewski Reported-by: Jorge Boncompte [DTI2] Tested-by: Pawel Staszewski Signed-off-by: Jarek Poplawski Signed-off-by: Robert Olsson Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 58ba9f4..5741d13 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -327,6 +327,8 @@ static const int inflate_threshold = 50; static const int halve_threshold_root = 15; static const int inflate_threshold_root = 25; +static int inflate_threshold_root_fix; +#define INFLATE_FIX_MAX 10 /* a comment in resize() */ static void __alias_free_mem(struct rcu_head *head) { @@ -617,7 +619,8 @@ static struct node *resize(struct trie *t, struct tnode *tn) /* Keep root node larger */ if (!tn->parent) - inflate_threshold_use = inflate_threshold_root; + inflate_threshold_use = inflate_threshold_root + + inflate_threshold_root_fix; else inflate_threshold_use = inflate_threshold; @@ -641,15 +644,27 @@ static struct node *resize(struct trie *t, struct tnode *tn) } if (max_resize < 0) { - if (!tn->parent) - pr_warning("Fix inflate_threshold_root." - " Now=%d size=%d bits\n", - inflate_threshold_root, tn->bits); - else + if (!tn->parent) { + /* + * It was observed that during large updates even + * inflate_threshold_root = 35 might be needed to avoid + * this warning; but it should be temporary, so let's + * try to handle this automatically. + */ + if (inflate_threshold_root_fix < INFLATE_FIX_MAX) + inflate_threshold_root_fix++; + else + pr_warning("Fix inflate_threshold_root." + " Now=%d size=%d bits fix=%d\n", + inflate_threshold_root, tn->bits, + inflate_threshold_root_fix); + } else { pr_warning("Fix inflate_threshold." " Now=%d size=%d bits\n", inflate_threshold, tn->bits); - } + } + } else if (max_resize > 3 && !tn->parent && inflate_threshold_root_fix) + inflate_threshold_root_fix--; check_tnode(tn); -- cgit v0.10.2 From b902e5735272b6a79fe2853180b2ad6658aa9678 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Tue, 14 Jul 2009 11:20:32 +0000 Subject: ipv4: fib_trie: Use tnode_get_child_rcu() and node_parent_rcu() in lookups While looking for other fib_trie problems reported by Pawel Staszewski I noticed there are a few uses of tnode_get_child() and node_parent() in lookups instead of their rcu versions. Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 5741d13..d58b491 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1465,7 +1465,7 @@ static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length), pos, bits); - n = tnode_get_child(pn, cindex); + n = tnode_get_child_rcu(pn, cindex); if (n == NULL) { #ifdef CONFIG_IP_FIB_TRIE_STATS @@ -1600,7 +1600,7 @@ backtrace: if (chopped_off <= pn->bits) { cindex &= ~(1 << (chopped_off-1)); } else { - struct tnode *parent = node_parent((struct node *) pn); + struct tnode *parent = node_parent_rcu((struct node *) pn); if (!parent) goto failed; @@ -1813,7 +1813,7 @@ static struct leaf *trie_firstleaf(struct trie *t) static struct leaf *trie_nextleaf(struct leaf *l) { struct node *c = (struct node *) l; - struct tnode *p = node_parent(c); + struct tnode *p = node_parent_rcu(c); if (!p) return NULL; /* trie with just one leaf */ -- cgit v0.10.2 From 5e766e3e433fa2d5d2fdfd8e2432804c91393387 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 8 Jul 2009 14:54:17 +0200 Subject: x86/oprofile: Fix usage of NUM_CONTROLS/NUM_COUNTERS macros Use the corresponding macros when iterating over counter and control registers. Since NUM_CONTROLS and NUM_COUNTERS are equal for AMD cpus the fix is more a cosmetical change. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index fdbed3a..dcfd450 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -99,7 +99,7 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX for (i = 0; i < NUM_VIRT_COUNTERS; i++) { - int hw_counter = i % NUM_CONTROLS; + int hw_counter = i % NUM_COUNTERS; if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter; else @@ -366,7 +366,7 @@ static void op_amd_shutdown(struct op_msrs const * const msrs) if (msrs->counters[i].addr) release_perfctr_nmi(MSR_K7_PERFCTR0 + i); } - for (i = 0; i < NUM_COUNTERS; ++i) { + for (i = 0; i < NUM_CONTROLS; ++i) { if (msrs->controls[i].addr) release_evntsel_nmi(MSR_K7_EVNTSEL0 + i); } -- cgit v0.10.2 From 82a225283fb0d9438549595d9e6f3ecc42b42ad6 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 16:29:34 +0200 Subject: x86/oprofile: Use per_cpu() instead of __get_cpu_var() __get_cpu_var() calls smp_processor_id(). When the cpu id is already known, instead use per_cpu() to avoid generating the id again. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index e54f6a0..8cd4658 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -294,7 +294,7 @@ static void nmi_cpu_shutdown(void *dummy) { unsigned int v; int cpu = smp_processor_id(); - struct op_msrs *msrs = &__get_cpu_var(cpu_msrs); + struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); /* restoring APIC_LVTPC can trigger an apic error because the delivery * mode and vector nr combination can be illegal. That's by design: on @@ -307,7 +307,7 @@ static void nmi_cpu_shutdown(void *dummy) apic_write(APIC_LVTERR, v); nmi_cpu_restore_registers(msrs); #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - __get_cpu_var(switch_index) = 0; + per_cpu(switch_index, cpu) = 0; #endif } -- cgit v0.10.2 From 6bfccd099c2841e1c42530f1b6d2553bfa13be3a Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 19:23:50 +0200 Subject: x86/oprofile: Fix initialization of switch_index Variable switch_index must be initialized for each cpu. This patch fixes the initialization by moving it to the per-cpu init function nmi_cpu_setup(). Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 8cd4658..b211d33 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -160,7 +160,7 @@ static int allocate_msrs(void) #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX -static void nmi_setup_cpu_mux(struct op_msrs const * const msrs) +static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { int i; struct op_msr *multiplex = msrs->multiplex; @@ -173,8 +173,15 @@ static void nmi_setup_cpu_mux(struct op_msrs const * const msrs) multiplex[i].saved = 0; } } + + per_cpu(switch_index, cpu) = 0; } +#else + +static inline void +nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { } + #endif static void nmi_cpu_setup(void *dummy) @@ -184,9 +191,7 @@ static void nmi_cpu_setup(void *dummy) nmi_cpu_save_registers(msrs); spin_lock(&oprofilefs_lock); model->setup_ctrs(model, msrs); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - nmi_setup_cpu_mux(msrs); -#endif + nmi_cpu_setup_mux(cpu, msrs); spin_unlock(&oprofilefs_lock); per_cpu(saved_lvtpc, cpu) = apic_read(APIC_LVTPC); apic_write(APIC_LVTPC, APIC_DM_NMI); @@ -662,9 +667,6 @@ int __init op_nmi_init(struct oprofile_operations *ops) register_cpu_notifier(&oprofile_cpu_nb); #endif /* default values, can be overwritten by model */ -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - __raw_get_cpu_var(switch_index) = 0; -#endif ops->create_files = nmi_create_files; ops->setup = nmi_setup; ops->shutdown = nmi_shutdown; -- cgit v0.10.2 From 2051cade7ccbe45a8bf8b7809d56b23d6d75ad03 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 15 Jul 2009 15:44:18 +0200 Subject: oprofile: oprofile_set_timeout(), return with error for invalid args Return with -EINVAL for invalid parameters instead of setting the default value in oprofile_set_timeout(). Signed-off-by: Robert Richter diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 7bc64af..42c9c76 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -196,6 +196,7 @@ post_sync: int oprofile_set_timeout(unsigned long val_msec) { int err = 0; + unsigned long time_slice; mutex_lock(&start_mutex); @@ -209,9 +210,13 @@ int oprofile_set_timeout(unsigned long val_msec) goto out; } - timeout_jiffies = msecs_to_jiffies(val_msec); - if (timeout_jiffies == MAX_JIFFY_OFFSET) - timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); + time_slice = msecs_to_jiffies(val_msec); + if (time_slice == MAX_JIFFY_OFFSET) { + err = -EINVAL; + goto out; + } + + timeout_jiffies = time_slice; out: mutex_unlock(&start_mutex); -- cgit v0.10.2 From afe1b50fe6aa56093e9234bdc08779e9fe20b5bf Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 15 Jul 2009 15:19:29 +0200 Subject: oprofile: Rename variable timeout_jiffies and move to oprofile_files.c This patch renames timeout_jiffies into an oprofile specific name. The macro MULTIPLEXING_TIMER_DEFAULT is changed too. Also, since this variable is controlled using oprofilefs, its definition is moved to oprofile_files.c. Signed-off-by: Robert Richter diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 42c9c76..2b33de7 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -33,8 +33,7 @@ static DEFINE_MUTEX(start_mutex); static void switch_worker(struct work_struct *work); static DECLARE_DELAYED_WORK(switch_work, switch_worker); -unsigned long timeout_jiffies; -#define MULTIPLEXING_TIMER_DEFAULT 1 +#define TIME_SLICE_DEFAULT 1 #endif @@ -102,7 +101,7 @@ out: static void start_switch_worker(void) { - schedule_delayed_work(&switch_work, timeout_jiffies); + schedule_delayed_work(&switch_work, oprofile_time_slice); } static void switch_worker(struct work_struct *work) @@ -216,7 +215,7 @@ int oprofile_set_timeout(unsigned long val_msec) goto out; } - timeout_jiffies = time_slice; + oprofile_time_slice = time_slice; out: mutex_unlock(&start_mutex); @@ -253,7 +252,7 @@ out: static void __init oprofile_multiplexing_init(void) { - timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); + oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT); } #endif diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index ee38abc..cb92f5c 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -24,10 +24,11 @@ struct oprofile_operations; extern unsigned long oprofile_buffer_size; extern unsigned long oprofile_cpu_buffer_size; extern unsigned long oprofile_buffer_watershed; +extern unsigned long oprofile_time_slice; + extern struct oprofile_operations oprofile_ops; extern unsigned long oprofile_started; extern unsigned long oprofile_backtrace_depth; -extern unsigned long timeout_jiffies; struct super_block; struct dentry; diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 468ec3e..4c5b947 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -22,14 +22,15 @@ unsigned long oprofile_buffer_size; unsigned long oprofile_cpu_buffer_size; unsigned long oprofile_buffer_watershed; +unsigned long oprofile_time_slice; #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX static ssize_t timeout_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { - return oprofilefs_ulong_to_user(jiffies_to_msecs(timeout_jiffies), - buf, count, offset); + return oprofilefs_ulong_to_user(jiffies_to_msecs(oprofile_time_slice), + buf, count, offset); } -- cgit v0.10.2 From 16422a6e2d16a39861ae5b0b11d9b411a245ab83 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 15 Jul 2009 15:44:18 +0200 Subject: oprofile: Remove oprofile_multiplexing_init() oprofile_multiplexing_init() can be removed when moving the initialization of oprofile_time_slice to oprofile_create_files(). Signed-off-by: Robert Richter diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 2b33de7..fa6cccd 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -33,7 +33,6 @@ static DEFINE_MUTEX(start_mutex); static void switch_worker(struct work_struct *work); static DECLARE_DELAYED_WORK(switch_work, switch_worker); -#define TIME_SLICE_DEFAULT 1 #endif @@ -248,23 +247,10 @@ out: return err; } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void __init oprofile_multiplexing_init(void) -{ - oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT); -} - -#endif - static int __init oprofile_init(void) { int err; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - oprofile_multiplexing_init(); -#endif - err = oprofile_arch_init(&oprofile_ops); if (err < 0 || timer) { diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 4c5b947..bbd7516 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -18,6 +18,7 @@ #define BUFFER_SIZE_DEFAULT 131072 #define CPU_BUFFER_SIZE_DEFAULT 8192 #define BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ +#define TIME_SLICE_DEFAULT 1 unsigned long oprofile_buffer_size; unsigned long oprofile_cpu_buffer_size; @@ -170,6 +171,7 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root) oprofile_buffer_size = BUFFER_SIZE_DEFAULT; oprofile_cpu_buffer_size = CPU_BUFFER_SIZE_DEFAULT; oprofile_buffer_watershed = BUFFER_WATERSHED_DEFAULT; + oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT); oprofilefs_create_file(sb, root, "enable", &enable_fops); oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); -- cgit v0.10.2 From a5659d17adb815fb35e11745e2f39c3f0bfd579f Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 19 Jun 2009 16:45:34 +0200 Subject: oprofile: Grouping multiplexing code in oprof.c This patch moves multiplexing code to a single section of code. This reduces the use of #ifdefs especially within functions. Signed-off-by: Robert Richter diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index fa6cccd..a48294a 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -29,13 +29,6 @@ unsigned long oprofile_backtrace_depth; static unsigned long is_setup; static DEFINE_MUTEX(start_mutex); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void switch_worker(struct work_struct *work); -static DECLARE_DELAYED_WORK(switch_work, switch_worker); - -#endif - /* timer 0 - use performance monitoring hardware if available 1 - use the timer int mechanism regardless @@ -98,9 +91,18 @@ out: #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +static void switch_worker(struct work_struct *work); +static DECLARE_DELAYED_WORK(switch_work, switch_worker); + static void start_switch_worker(void) { - schedule_delayed_work(&switch_work, oprofile_time_slice); + if (oprofile_ops.switch_events) + schedule_delayed_work(&switch_work, oprofile_time_slice); +} + +static void stop_switch_worker(void) +{ + cancel_delayed_work_sync(&switch_work); } static void switch_worker(struct work_struct *work) @@ -109,6 +111,43 @@ static void switch_worker(struct work_struct *work) start_switch_worker(); } +/* User inputs in ms, converts to jiffies */ +int oprofile_set_timeout(unsigned long val_msec) +{ + int err = 0; + unsigned long time_slice; + + mutex_lock(&start_mutex); + + if (oprofile_started) { + err = -EBUSY; + goto out; + } + + if (!oprofile_ops.switch_events) { + err = -EINVAL; + goto out; + } + + time_slice = msecs_to_jiffies(val_msec); + if (time_slice == MAX_JIFFY_OFFSET) { + err = -EINVAL; + goto out; + } + + oprofile_time_slice = time_slice; + +out: + mutex_unlock(&start_mutex); + return err; + +} + +#else + +static inline void start_switch_worker(void) { } +static inline void stop_switch_worker(void) { } + #endif /* Actually start profiling (echo 1>/dev/oprofile/enable) */ @@ -131,10 +170,7 @@ int oprofile_start(void) if ((err = oprofile_ops.start())) goto out; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - if (oprofile_ops.switch_events) - start_switch_worker(); -#endif + start_switch_worker(); oprofile_started = 1; out: @@ -152,9 +188,7 @@ void oprofile_stop(void) oprofile_ops.stop(); oprofile_started = 0; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - cancel_delayed_work_sync(&switch_work); -#endif + stop_switch_worker(); /* wake up the daemon to read what remains */ wake_up_buffer_waiter(); @@ -188,42 +222,6 @@ post_sync: mutex_unlock(&start_mutex); } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -/* User inputs in ms, converts to jiffies */ -int oprofile_set_timeout(unsigned long val_msec) -{ - int err = 0; - unsigned long time_slice; - - mutex_lock(&start_mutex); - - if (oprofile_started) { - err = -EBUSY; - goto out; - } - - if (!oprofile_ops.switch_events) { - err = -EINVAL; - goto out; - } - - time_slice = msecs_to_jiffies(val_msec); - if (time_slice == MAX_JIFFY_OFFSET) { - err = -EINVAL; - goto out; - } - - oprofile_time_slice = time_slice; - -out: - mutex_unlock(&start_mutex); - return err; - -} - -#endif - int oprofile_set_backtrace(unsigned long val) { int err = 0; -- cgit v0.10.2 From d8471ad3ab613a1ba7abd3aad46659de39a2871c Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 16 Jul 2009 13:04:43 +0200 Subject: oprofile: Introduce op_x86_phys_to_virt() This new function translates physical to virtual counter numbers. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index b211d33..02b57b8 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -27,12 +27,6 @@ #include "op_counter.h" #include "op_x86_model.h" - -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX -DEFINE_PER_CPU(int, switch_index); -#endif - - static struct op_x86_model_spec const *model; static DEFINE_PER_CPU(struct op_msrs, cpu_msrs); static DEFINE_PER_CPU(unsigned long, saved_lvtpc); @@ -103,6 +97,21 @@ static void nmi_cpu_save_registers(struct op_msrs *msrs) } } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static DEFINE_PER_CPU(int, switch_index); + +inline int op_x86_phys_to_virt(int phys) +{ + return __get_cpu_var(switch_index) + phys; +} + +#else + +inline int op_x86_phys_to_virt(int phys) { return phys; } + +#endif + static void free_msrs(void) { int i; @@ -248,31 +257,25 @@ static int nmi_setup(void) static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs) { - unsigned int si = __get_cpu_var(switch_index); struct op_msr *multiplex = msrs->multiplex; - unsigned int i; + int i; for (i = 0; i < model->num_counters; ++i) { - int offset = i + si; - if (multiplex[offset].addr) { - rdmsrl(multiplex[offset].addr, - multiplex[offset].saved); - } + int virt = op_x86_phys_to_virt(i); + if (multiplex[virt].addr) + rdmsrl(multiplex[virt].addr, multiplex[virt].saved); } } static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs) { - unsigned int si = __get_cpu_var(switch_index); struct op_msr *multiplex = msrs->multiplex; - unsigned int i; + int i; for (i = 0; i < model->num_counters; ++i) { - int offset = i + si; - if (multiplex[offset].addr) { - wrmsrl(multiplex[offset].addr, - multiplex[offset].saved); - } + int virt = op_x86_phys_to_virt(i); + if (multiplex[virt].addr) + wrmsrl(multiplex[virt].addr, multiplex[virt].saved); } } diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index dcfd450..67f830d 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -42,9 +42,6 @@ #define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21)) static unsigned long reset_value[NUM_VIRT_COUNTERS]; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX -DECLARE_PER_CPU(int, switch_index); -#endif #ifdef CONFIG_OPROFILE_IBS @@ -141,21 +138,20 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - int offset = i + __get_cpu_var(switch_index); -#else - int offset = i; -#endif - if (counter_config[offset].enabled && msrs->counters[i].addr) { - /* setup counter registers */ - wrmsrl(msrs->counters[i].addr, -(u64)reset_value[offset]); - - /* setup control registers */ - rdmsrl(msrs->controls[i].addr, val); - val &= model->reserved; - val |= op_x86_get_ctrl(model, &counter_config[offset]); - wrmsrl(msrs->controls[i].addr, val); - } + int virt = op_x86_phys_to_virt(i); + if (!counter_config[virt].enabled) + continue; + if (!msrs->counters[i].addr) + continue; + + /* setup counter registers */ + wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]); + + /* setup control registers */ + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[virt]); + wrmsrl(msrs->controls[i].addr, val); } } @@ -170,14 +166,13 @@ static void op_amd_switch_ctrl(struct op_x86_model_spec const *model, /* enable active counters */ for (i = 0; i < NUM_COUNTERS; ++i) { - int offset = i + __get_cpu_var(switch_index); - if (counter_config[offset].enabled) { - /* setup control registers */ - rdmsrl(msrs->controls[i].addr, val); - val &= model->reserved; - val |= op_x86_get_ctrl(model, &counter_config[offset]); - wrmsrl(msrs->controls[i].addr, val); - } + int virt = op_x86_phys_to_virt(i); + if (!counter_config[virt].enabled) + continue; + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[virt]); + wrmsrl(msrs->controls[i].addr, val); } } @@ -292,19 +287,15 @@ static int op_amd_check_ctrs(struct pt_regs * const regs, int i; for (i = 0; i < NUM_COUNTERS; ++i) { -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - int offset = i + __get_cpu_var(switch_index); -#else - int offset = i; -#endif - if (!reset_value[offset]) + int virt = op_x86_phys_to_virt(i); + if (!reset_value[virt]) continue; rdmsrl(msrs->counters[i].addr, val); /* bit is clear if overflowed: */ if (val & OP_CTR_OVERFLOW) continue; - oprofile_add_sample(regs, offset); - wrmsrl(msrs->counters[i].addr, -(u64)reset_value[offset]); + oprofile_add_sample(regs, virt); + wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]); } op_amd_handle_ibs(regs, msrs); @@ -319,16 +310,11 @@ static void op_amd_start(struct op_msrs const * const msrs) int i; for (i = 0; i < NUM_COUNTERS; ++i) { -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - int offset = i + __get_cpu_var(switch_index); -#else - int offset = i; -#endif - if (reset_value[offset]) { - rdmsrl(msrs->controls[i].addr, val); - val |= ARCH_PERFMON_EVENTSEL0_ENABLE; - wrmsrl(msrs->controls[i].addr, val); - } + if (!reset_value[op_x86_phys_to_virt(i)]) + continue; + rdmsrl(msrs->controls[i].addr, val); + val |= ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(msrs->controls[i].addr, val); } op_amd_start_ibs(); @@ -344,11 +330,7 @@ static void op_amd_stop(struct op_msrs const * const msrs) * pm callback */ for (i = 0; i < NUM_COUNTERS; ++i) { -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - if (!reset_value[i + per_cpu(switch_index, smp_processor_id())]) -#else - if (!reset_value[i]) -#endif + if (!reset_value[op_x86_phys_to_virt(i)]) continue; rdmsrl(msrs->controls[i].addr, val); val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 0d07d23..e874dc3 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -60,6 +60,7 @@ struct op_counter_config; extern u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, struct op_counter_config *counter_config); +extern int op_x86_phys_to_virt(int phys); extern struct op_x86_model_spec const op_ppro_spec; extern struct op_x86_model_spec const op_p4_spec; -- cgit v0.10.2 From 7e7478c6bc0e011d2854b21f190cc3a1dba89905 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 16 Jul 2009 13:09:53 +0200 Subject: oprofile: Grouping multiplexing code in op_model_amd.c This patch moves some multiplexing code to the new function op_mux_fill_in_addresses(). Also, the whole multiplexing code is now at a single location. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 67f830d..644980f 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -74,6 +74,45 @@ static struct op_ibs_config ibs_config; #endif +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void op_mux_fill_in_addresses(struct op_msrs * const msrs) +{ + int i; + + for (i = 0; i < NUM_VIRT_COUNTERS; i++) { + int hw_counter = i % NUM_COUNTERS; + if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) + msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter; + else + msrs->multiplex[i].addr = 0; + } +} + +static void op_mux_switch_ctrl(struct op_x86_model_spec const *model, + struct op_msrs const * const msrs) +{ + u64 val; + int i; + + /* enable active counters */ + for (i = 0; i < NUM_COUNTERS; ++i) { + int virt = op_x86_phys_to_virt(i); + if (!counter_config[virt].enabled) + continue; + rdmsrl(msrs->controls[i].addr, val); + val &= model->reserved; + val |= op_x86_get_ctrl(model, &counter_config[virt]); + wrmsrl(msrs->controls[i].addr, val); + } +} + +#else + +static inline void op_mux_fill_in_addresses(struct op_msrs * const msrs) { } + +#endif + /* functions for op_amd_spec */ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) @@ -94,15 +133,7 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) msrs->controls[i].addr = 0; } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - for (i = 0; i < NUM_VIRT_COUNTERS; i++) { - int hw_counter = i % NUM_COUNTERS; - if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) - msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter; - else - msrs->multiplex[i].addr = 0; - } -#endif + op_mux_fill_in_addresses(msrs); } static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, @@ -155,30 +186,6 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, } } - -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void op_amd_switch_ctrl(struct op_x86_model_spec const *model, - struct op_msrs const * const msrs) -{ - u64 val; - int i; - - /* enable active counters */ - for (i = 0; i < NUM_COUNTERS; ++i) { - int virt = op_x86_phys_to_virt(i); - if (!counter_config[virt].enabled) - continue; - rdmsrl(msrs->controls[i].addr, val); - val &= model->reserved; - val |= op_x86_get_ctrl(model, &counter_config[virt]); - wrmsrl(msrs->controls[i].addr, val); - } -} - -#endif - - #ifdef CONFIG_OPROFILE_IBS static inline int @@ -535,6 +542,6 @@ struct op_x86_model_spec const op_amd_spec = { .stop = &op_amd_stop, .shutdown = &op_amd_shutdown, #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - .switch_ctrl = &op_amd_switch_ctrl, + .switch_ctrl = &op_mux_switch_ctrl, #endif }; -- cgit v0.10.2 From 6ab82f958a5dca591a6ea17a3ca6f2aca06f4f2f Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 14:40:04 +0200 Subject: x86/oprofile: Implement multiplexing setup/shutdown functions This patch implements nmi_setup_mux() and nmi_shutdown_mux() functions to setup/shutdown multiplexing. Multiplexing code in nmi_int.c is now much more separated. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 02b57b8..674fa37 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -106,9 +106,35 @@ inline int op_x86_phys_to_virt(int phys) return __get_cpu_var(switch_index) + phys; } +static void nmi_shutdown_mux(void) +{ + int i; + for_each_possible_cpu(i) { + kfree(per_cpu(cpu_msrs, i).multiplex); + per_cpu(cpu_msrs, i).multiplex = NULL; + per_cpu(switch_index, i) = 0; + } +} + +static int nmi_setup_mux(void) +{ + size_t multiplex_size = + sizeof(struct op_msr) * model->num_virt_counters; + int i; + for_each_possible_cpu(i) { + per_cpu(cpu_msrs, i).multiplex = + kmalloc(multiplex_size, GFP_KERNEL); + if (!per_cpu(cpu_msrs, i).multiplex) + return 0; + } + return 1; +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } +static inline void nmi_shutdown_mux(void) { } +static inline int nmi_setup_mux(void) { return 1; } #endif @@ -120,51 +146,27 @@ static void free_msrs(void) per_cpu(cpu_msrs, i).counters = NULL; kfree(per_cpu(cpu_msrs, i).controls); per_cpu(cpu_msrs, i).controls = NULL; - -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - kfree(per_cpu(cpu_msrs, i).multiplex); - per_cpu(cpu_msrs, i).multiplex = NULL; -#endif } } static int allocate_msrs(void) { - int success = 1; size_t controls_size = sizeof(struct op_msr) * model->num_controls; size_t counters_size = sizeof(struct op_msr) * model->num_counters; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - size_t multiplex_size = sizeof(struct op_msr) * model->num_virt_counters; -#endif int i; for_each_possible_cpu(i) { per_cpu(cpu_msrs, i).counters = kmalloc(counters_size, - GFP_KERNEL); - if (!per_cpu(cpu_msrs, i).counters) { - success = 0; - break; - } + GFP_KERNEL); + if (!per_cpu(cpu_msrs, i).counters) + return 0; per_cpu(cpu_msrs, i).controls = kmalloc(controls_size, - GFP_KERNEL); - if (!per_cpu(cpu_msrs, i).controls) { - success = 0; - break; - } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - per_cpu(cpu_msrs, i).multiplex = - kmalloc(multiplex_size, GFP_KERNEL); - if (!per_cpu(cpu_msrs, i).multiplex) { - success = 0; - break; - } -#endif + GFP_KERNEL); + if (!per_cpu(cpu_msrs, i).controls) + return 0; } - if (!success) - free_msrs(); - - return success; + return 1; } #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX @@ -218,11 +220,15 @@ static int nmi_setup(void) int cpu; if (!allocate_msrs()) - return -ENOMEM; + err = -ENOMEM; + else if (!nmi_setup_mux()) + err = -ENOMEM; + else + err = register_die_notifier(&profile_exceptions_nb); - err = register_die_notifier(&profile_exceptions_nb); if (err) { free_msrs(); + nmi_shutdown_mux(); return err; } @@ -314,9 +320,6 @@ static void nmi_cpu_shutdown(void *dummy) apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu)); apic_write(APIC_LVTERR, v); nmi_cpu_restore_registers(msrs); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - per_cpu(switch_index, cpu) = 0; -#endif } static void nmi_shutdown(void) @@ -326,6 +329,7 @@ static void nmi_shutdown(void) nmi_enabled = 0; on_each_cpu(nmi_cpu_shutdown, NULL, 1); unregister_die_notifier(&profile_exceptions_nb); + nmi_shutdown_mux(); msrs = &get_cpu_var(cpu_msrs); model->shutdown(msrs); free_msrs(); -- cgit v0.10.2 From 48fb4b46712c7d3e8adc79826311abd9ccbf7f1d Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 14:38:49 +0200 Subject: x86/oprofile: Moving nmi_setup_cpu_mux() in nmi_int.c This patch moves some code in nmi_int.c to get a single separate multiplexing code section. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 674fa37..b1edfc9 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -130,11 +130,30 @@ static int nmi_setup_mux(void) return 1; } +static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) +{ + int i; + struct op_msr *multiplex = msrs->multiplex; + + for (i = 0; i < model->num_virt_counters; ++i) { + if (counter_config[i].enabled) { + multiplex[i].saved = -(u64)counter_config[i].count; + } else { + multiplex[i].addr = 0; + multiplex[i].saved = 0; + } + } + + per_cpu(switch_index, cpu) = 0; +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } static inline void nmi_shutdown_mux(void) { } static inline int nmi_setup_mux(void) { return 1; } +static inline void +nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { } #endif @@ -169,32 +188,6 @@ static int allocate_msrs(void) return 1; } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) -{ - int i; - struct op_msr *multiplex = msrs->multiplex; - - for (i = 0; i < model->num_virt_counters; ++i) { - if (counter_config[i].enabled) { - multiplex[i].saved = -(u64)counter_config[i].count; - } else { - multiplex[i].addr = 0; - multiplex[i].saved = 0; - } - } - - per_cpu(switch_index, cpu) = 0; -} - -#else - -static inline void -nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { } - -#endif - static void nmi_cpu_setup(void *dummy) { int cpu = smp_processor_id(); -- cgit v0.10.2 From d0f585dd20010f8479e56b5c6f391ef18e26877e Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 14:38:49 +0200 Subject: x86/oprofile: Moving nmi_cpu_save/restore_mpx_registers() in nmi_int.c This patch moves some code in nmi_int.c to get a single separate multiplexing code section. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index b1edfc9..f38c5cf 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -147,6 +147,30 @@ static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) per_cpu(switch_index, cpu) = 0; } +static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs) +{ + struct op_msr *multiplex = msrs->multiplex; + int i; + + for (i = 0; i < model->num_counters; ++i) { + int virt = op_x86_phys_to_virt(i); + if (multiplex[virt].addr) + rdmsrl(multiplex[virt].addr, multiplex[virt].saved); + } +} + +static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs) +{ + struct op_msr *multiplex = msrs->multiplex; + int i; + + for (i = 0; i < model->num_counters; ++i) { + int virt = op_x86_phys_to_virt(i); + if (multiplex[virt].addr) + wrmsrl(multiplex[virt].addr, multiplex[virt].saved); + } +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } @@ -252,34 +276,6 @@ static int nmi_setup(void) return 0; } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs) -{ - struct op_msr *multiplex = msrs->multiplex; - int i; - - for (i = 0; i < model->num_counters; ++i) { - int virt = op_x86_phys_to_virt(i); - if (multiplex[virt].addr) - rdmsrl(multiplex[virt].addr, multiplex[virt].saved); - } -} - -static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs) -{ - struct op_msr *multiplex = msrs->multiplex; - int i; - - for (i = 0; i < model->num_counters; ++i) { - int virt = op_x86_phys_to_virt(i); - if (multiplex[virt].addr) - wrmsrl(multiplex[virt].addr, multiplex[virt].saved); - } -} - -#endif - static void nmi_cpu_restore_registers(struct op_msrs *msrs) { struct op_msr *counters = msrs->counters; -- cgit v0.10.2 From b28d1b923ab52d535c0719155dccf3b3d98bab9f Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 14:38:49 +0200 Subject: x86/oprofile: Moving nmi_cpu_switch() in nmi_int.c This patch moves some code in nmi_int.c to get a single separate multiplexing code section. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index f38c5cf..998c7dc 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -97,6 +97,29 @@ static void nmi_cpu_save_registers(struct op_msrs *msrs) } } +static void nmi_cpu_start(void *dummy) +{ + struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); + model->start(msrs); +} + +static int nmi_start(void) +{ + on_each_cpu(nmi_cpu_start, NULL, 1); + return 0; +} + +static void nmi_cpu_stop(void *dummy) +{ + struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); + model->stop(msrs); +} + +static void nmi_stop(void) +{ + on_each_cpu(nmi_cpu_stop, NULL, 1); +} + #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX static DEFINE_PER_CPU(int, switch_index); @@ -171,6 +194,53 @@ static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs) } } +static void nmi_cpu_switch(void *dummy) +{ + int cpu = smp_processor_id(); + int si = per_cpu(switch_index, cpu); + struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); + + nmi_cpu_stop(NULL); + nmi_cpu_save_mpx_registers(msrs); + + /* move to next set */ + si += model->num_counters; + if ((si > model->num_virt_counters) || (counter_config[si].count == 0)) + per_cpu(switch_index, cpu) = 0; + else + per_cpu(switch_index, cpu) = si; + + model->switch_ctrl(model, msrs); + nmi_cpu_restore_mpx_registers(msrs); + + nmi_cpu_start(NULL); +} + + +/* + * Quick check to see if multiplexing is necessary. + * The check should be sufficient since counters are used + * in ordre. + */ +static int nmi_multiplex_on(void) +{ + return counter_config[model->num_counters].count ? 0 : -EINVAL; +} + +static int nmi_switch_event(void) +{ + if (!model->switch_ctrl) + return -ENOSYS; /* not implemented */ + if (nmi_multiplex_on() < 0) + return -EINVAL; /* not necessary */ + + on_each_cpu(nmi_cpu_switch, NULL, 1); + + atomic_inc(&multiplex_counter); + + return 0; +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } @@ -325,29 +395,6 @@ static void nmi_shutdown(void) put_cpu_var(cpu_msrs); } -static void nmi_cpu_start(void *dummy) -{ - struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); - model->start(msrs); -} - -static int nmi_start(void) -{ - on_each_cpu(nmi_cpu_start, NULL, 1); - return 0; -} - -static void nmi_cpu_stop(void *dummy) -{ - struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); - model->stop(msrs); -} - -static void nmi_stop(void) -{ - on_each_cpu(nmi_cpu_stop, NULL, 1); -} - static int nmi_create_files(struct super_block *sb, struct dentry *root) { unsigned int i; @@ -379,57 +426,6 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) return 0; } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void nmi_cpu_switch(void *dummy) -{ - int cpu = smp_processor_id(); - int si = per_cpu(switch_index, cpu); - struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); - - nmi_cpu_stop(NULL); - nmi_cpu_save_mpx_registers(msrs); - - /* move to next set */ - si += model->num_counters; - if ((si > model->num_virt_counters) || (counter_config[si].count == 0)) - per_cpu(switch_index, cpu) = 0; - else - per_cpu(switch_index, cpu) = si; - - model->switch_ctrl(model, msrs); - nmi_cpu_restore_mpx_registers(msrs); - - nmi_cpu_start(NULL); -} - - -/* - * Quick check to see if multiplexing is necessary. - * The check should be sufficient since counters are used - * in ordre. - */ -static int nmi_multiplex_on(void) -{ - return counter_config[model->num_counters].count ? 0 : -EINVAL; -} - -static int nmi_switch_event(void) -{ - if (!model->switch_ctrl) - return -ENOSYS; /* not implemented */ - if (nmi_multiplex_on() < 0) - return -EINVAL; /* not necessary */ - - on_each_cpu(nmi_cpu_switch, NULL, 1); - - atomic_inc(&multiplex_counter); - - return 0; -} - -#endif - #ifdef CONFIG_SMP static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, void *data) -- cgit v0.10.2 From 259a83a8abdb9d2664819ec80ad12ebaeb251e32 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 15:12:35 +0200 Subject: x86/oprofile: Remove const qualifier from struct op_x86_model_spec This patch removes the const qualifier from struct op_x86_model_spec to make model parameters changable. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 998c7dc..826f391 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -27,7 +27,7 @@ #include "op_counter.h" #include "op_x86_model.h" -static struct op_x86_model_spec const *model; +static struct op_x86_model_spec *model; static DEFINE_PER_CPU(struct op_msrs, cpu_msrs); static DEFINE_PER_CPU(unsigned long, saved_lvtpc); @@ -542,7 +542,7 @@ module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0); static int __init ppro_init(char **cpu_type) { __u8 cpu_model = boot_cpu_data.x86_model; - struct op_x86_model_spec const *spec = &op_ppro_spec; /* default */ + struct op_x86_model_spec *spec = &op_ppro_spec; /* default */ if (force_arch_perfmon && cpu_has_arch_perfmon) return 0; diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 644980f..39604b4 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -526,7 +526,7 @@ static void op_amd_exit(void) {} #endif /* CONFIG_OPROFILE_IBS */ -struct op_x86_model_spec const op_amd_spec = { +struct op_x86_model_spec op_amd_spec = { .num_counters = NUM_COUNTERS, .num_controls = NUM_CONTROLS, .num_virt_counters = NUM_VIRT_COUNTERS, diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 65b9237..40df028 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -695,7 +695,7 @@ static void p4_shutdown(struct op_msrs const * const msrs) #ifdef CONFIG_SMP -struct op_x86_model_spec const op_p4_ht2_spec = { +struct op_x86_model_spec op_p4_ht2_spec = { .num_counters = NUM_COUNTERS_HT2, .num_controls = NUM_CONTROLS_HT2, .num_virt_counters = NUM_COUNTERS_HT2, @@ -709,7 +709,7 @@ struct op_x86_model_spec const op_p4_ht2_spec = { }; #endif -struct op_x86_model_spec const op_p4_spec = { +struct op_x86_model_spec op_p4_spec = { .num_counters = NUM_COUNTERS_NON_HT, .num_controls = NUM_CONTROLS_NON_HT, .num_virt_counters = NUM_COUNTERS_NON_HT, diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 098cbca..659f3b6 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -203,7 +203,7 @@ static void ppro_shutdown(struct op_msrs const * const msrs) } -struct op_x86_model_spec const op_ppro_spec = { +struct op_x86_model_spec op_ppro_spec = { .num_counters = 2, .num_controls = 2, .num_virt_counters = 2, diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index e874dc3..0c886fa 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -62,10 +62,10 @@ extern u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, struct op_counter_config *counter_config); extern int op_x86_phys_to_virt(int phys); -extern struct op_x86_model_spec const op_ppro_spec; -extern struct op_x86_model_spec const op_p4_spec; -extern struct op_x86_model_spec const op_p4_ht2_spec; -extern struct op_x86_model_spec const op_amd_spec; +extern struct op_x86_model_spec op_ppro_spec; +extern struct op_x86_model_spec op_p4_spec; +extern struct op_x86_model_spec op_p4_ht2_spec; +extern struct op_x86_model_spec op_amd_spec; extern struct op_x86_model_spec op_arch_perfmon_spec; #endif /* OP_X86_MODEL_H */ -- cgit v0.10.2 From 2904a527575344a804fdd82b1f8d09a8731d8d49 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 12:33:41 +0200 Subject: x86/oprofile: Remove unused num_virt_controls from struct op_x86_model_spec The member num_virt_controls of struct op_x86_model_spec is not used. This patch removes it. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 39604b4..dce69b5 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -530,7 +530,6 @@ struct op_x86_model_spec op_amd_spec = { .num_counters = NUM_COUNTERS, .num_controls = NUM_CONTROLS, .num_virt_counters = NUM_VIRT_COUNTERS, - .num_virt_controls = NUM_VIRT_CONTROLS, .reserved = MSR_AMD_EVENTSEL_RESERVED, .event_mask = OP_EVENT_MASK, .init = op_amd_init, diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 40df028..0a4f2de 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -699,7 +699,6 @@ struct op_x86_model_spec op_p4_ht2_spec = { .num_counters = NUM_COUNTERS_HT2, .num_controls = NUM_CONTROLS_HT2, .num_virt_counters = NUM_COUNTERS_HT2, - .num_virt_controls = NUM_CONTROLS_HT2, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, @@ -713,7 +712,6 @@ struct op_x86_model_spec op_p4_spec = { .num_counters = NUM_COUNTERS_NON_HT, .num_controls = NUM_CONTROLS_NON_HT, .num_virt_counters = NUM_COUNTERS_NON_HT, - .num_virt_controls = NUM_CONTROLS_NON_HT, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 659f3b6..753a02a 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -207,7 +207,6 @@ struct op_x86_model_spec op_ppro_spec = { .num_counters = 2, .num_controls = 2, .num_virt_counters = 2, - .num_virt_controls = 2, .reserved = MSR_PPRO_EVENTSEL_RESERVED, .fill_in_addresses = &ppro_fill_in_addresses, .setup_ctrs = &ppro_setup_ctrs, diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 0c886fa..4e2e7c2 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -37,7 +37,6 @@ struct op_x86_model_spec { unsigned int num_counters; unsigned int num_controls; unsigned int num_virt_counters; - unsigned int num_virt_controls; u64 reserved; u16 event_mask; int (*init)(struct oprofile_operations *ops); -- cgit v0.10.2 From 52471c67ee2fa5ed6f700ef57bf27833c63b2192 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 6 Jul 2009 14:43:55 +0200 Subject: x86/oprofile: Modify initialization of num_virt_counters Models that do not yet support counter multiplexing have to setup num_virt_counters. This patch implements the setup from num_counters if num_virt_counters is not set. Thus, num_virt_counters must be setup only for multiplexing support. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 826f391..82ee2951 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -674,6 +674,9 @@ int __init op_nmi_init(struct oprofile_operations *ops) if (ret) return ret; + if (!model->num_virt_counters) + model->num_virt_counters = model->num_counters; + init_sysfs(); using_nmi = 1; printk(KERN_INFO "oprofile: using NMI interrupt.\n"); diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 0a4f2de..ac6b354 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -698,7 +698,6 @@ static void p4_shutdown(struct op_msrs const * const msrs) struct op_x86_model_spec op_p4_ht2_spec = { .num_counters = NUM_COUNTERS_HT2, .num_controls = NUM_CONTROLS_HT2, - .num_virt_counters = NUM_COUNTERS_HT2, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, @@ -711,7 +710,6 @@ struct op_x86_model_spec op_p4_ht2_spec = { struct op_x86_model_spec op_p4_spec = { .num_counters = NUM_COUNTERS_NON_HT, .num_controls = NUM_CONTROLS_NON_HT, - .num_virt_counters = NUM_COUNTERS_NON_HT, .fill_in_addresses = &p4_fill_in_addresses, .setup_ctrs = &p4_setup_ctrs, .check_ctrs = &p4_check_ctrs, diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 753a02a..4899215 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -206,7 +206,6 @@ static void ppro_shutdown(struct op_msrs const * const msrs) struct op_x86_model_spec op_ppro_spec = { .num_counters = 2, .num_controls = 2, - .num_virt_counters = 2, .reserved = MSR_PPRO_EVENTSEL_RESERVED, .fill_in_addresses = &ppro_fill_in_addresses, .setup_ctrs = &ppro_setup_ctrs, -- cgit v0.10.2 From 39e97f40c3a5e71de0532368deaa683e09b74ba2 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 15:11:45 +0200 Subject: x86/oprofile: Add function has_mux() to check multiplexing support The check is used to prevent running multiplexing code for models not supporting multiplexing. Before, the code was running but without effect. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 82ee2951..dca7240 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -124,6 +124,11 @@ static void nmi_stop(void) static DEFINE_PER_CPU(int, switch_index); +static inline int has_mux(void) +{ + return !!model->switch_ctrl; +} + inline int op_x86_phys_to_virt(int phys) { return __get_cpu_var(switch_index) + phys; @@ -132,6 +137,10 @@ inline int op_x86_phys_to_virt(int phys) static void nmi_shutdown_mux(void) { int i; + + if (!has_mux()) + return; + for_each_possible_cpu(i) { kfree(per_cpu(cpu_msrs, i).multiplex); per_cpu(cpu_msrs, i).multiplex = NULL; @@ -144,12 +153,17 @@ static int nmi_setup_mux(void) size_t multiplex_size = sizeof(struct op_msr) * model->num_virt_counters; int i; + + if (!has_mux()) + return 1; + for_each_possible_cpu(i) { per_cpu(cpu_msrs, i).multiplex = kmalloc(multiplex_size, GFP_KERNEL); if (!per_cpu(cpu_msrs, i).multiplex) return 0; } + return 1; } @@ -158,6 +172,9 @@ static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) int i; struct op_msr *multiplex = msrs->multiplex; + if (!has_mux()) + return; + for (i = 0; i < model->num_virt_counters; ++i) { if (counter_config[i].enabled) { multiplex[i].saved = -(u64)counter_config[i].count; @@ -229,7 +246,7 @@ static int nmi_multiplex_on(void) static int nmi_switch_event(void) { - if (!model->switch_ctrl) + if (!has_mux()) return -ENOSYS; /* not implemented */ if (nmi_multiplex_on() < 0) return -EINVAL; /* not necessary */ -- cgit v0.10.2 From 5280514471c2803776701c43c027038decac1103 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 16:02:44 +0200 Subject: x86/oprofile: Enable multiplexing only if the model supports it This patch checks if the model supports multiplexing. Only then multiplexing will be enabled. The code is added to the common x86 initialization. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index dca7240..f0fb447 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -258,6 +258,12 @@ static int nmi_switch_event(void) return 0; } +static inline void mux_init(struct oprofile_operations *ops) +{ + if (has_mux()) + ops->switch_events = nmi_switch_event; +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } @@ -265,6 +271,7 @@ static inline void nmi_shutdown_mux(void) { } static inline int nmi_setup_mux(void) { return 1; } static inline void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { } +static inline void mux_init(struct oprofile_operations *ops) { } #endif @@ -682,9 +689,6 @@ int __init op_nmi_init(struct oprofile_operations *ops) ops->start = nmi_start; ops->stop = nmi_stop; ops->cpu_type = cpu_type; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - ops->switch_events = nmi_switch_event; -#endif if (model->init) ret = model->init(ops); @@ -694,6 +698,8 @@ int __init op_nmi_init(struct oprofile_operations *ops) if (!model->num_virt_counters) model->num_virt_counters = model->num_counters; + mux_init(ops); + init_sysfs(); using_nmi = 1; printk(KERN_INFO "oprofile: using NMI interrupt.\n"); -- cgit v0.10.2 From 4d015f79e972cea1761cfee8872b1c0992ccd8b2 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 21:42:51 +0200 Subject: x86/oprofile: Implement mux_clone() To setup a counter for all cpus, its structure is cloned from cpu 0. This patch implements mux_clone() to do this part for multiplexing data. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index f0fb447..da6d2ab 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -264,6 +264,16 @@ static inline void mux_init(struct oprofile_operations *ops) ops->switch_events = nmi_switch_event; } +static void mux_clone(int cpu) +{ + if (!has_mux()) + return; + + memcpy(per_cpu(cpu_msrs, cpu).multiplex, + per_cpu(cpu_msrs, 0).multiplex, + sizeof(struct op_msr) * model->num_virt_counters); +} + #else inline int op_x86_phys_to_virt(int phys) { return phys; } @@ -272,6 +282,7 @@ static inline int nmi_setup_mux(void) { return 1; } static inline void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { } static inline void mux_init(struct oprofile_operations *ops) { } +static void mux_clone(int cpu) { } #endif @@ -350,20 +361,18 @@ static int nmi_setup(void) /* Assume saved/restored counters are the same on all CPUs */ model->fill_in_addresses(&per_cpu(cpu_msrs, 0)); for_each_possible_cpu(cpu) { - if (cpu != 0) { - memcpy(per_cpu(cpu_msrs, cpu).counters, - per_cpu(cpu_msrs, 0).counters, - sizeof(struct op_msr) * model->num_counters); - - memcpy(per_cpu(cpu_msrs, cpu).controls, - per_cpu(cpu_msrs, 0).controls, - sizeof(struct op_msr) * model->num_controls); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - memcpy(per_cpu(cpu_msrs, cpu).multiplex, - per_cpu(cpu_msrs, 0).multiplex, - sizeof(struct op_msr) * model->num_virt_counters); -#endif - } + if (!cpu) + continue; + + memcpy(per_cpu(cpu_msrs, cpu).counters, + per_cpu(cpu_msrs, 0).counters, + sizeof(struct op_msr) * model->num_counters); + + memcpy(per_cpu(cpu_msrs, cpu).controls, + per_cpu(cpu_msrs, 0).controls, + sizeof(struct op_msr) * model->num_controls); + + mux_clone(cpu); } on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; -- cgit v0.10.2 From 1b294f5960cd89e49eeb3e797860c552b03f2272 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 14:56:25 +0200 Subject: oprofile: Adding switch counter to oprofile statistic variables This patch moves the multiplexing switch counter from x86 code to common oprofile statistic variables. Now the value will be available and usable for all architectures. The initialization and incrementation also moved to common code. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index da6d2ab..7b3362f 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -34,11 +34,6 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc); /* 0 == registered but off, 1 == registered and on */ static int nmi_enabled = 0; - -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX -extern atomic_t multiplex_counter; -#endif - struct op_counter_config counter_config[OP_MAX_COUNTER]; /* common functions */ @@ -253,8 +248,6 @@ static int nmi_switch_event(void) on_each_cpu(nmi_cpu_switch, NULL, 1); - atomic_inc(&multiplex_counter); - return 0; } diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index a48294a..dc8a042 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -107,8 +107,11 @@ static void stop_switch_worker(void) static void switch_worker(struct work_struct *work) { - if (!oprofile_ops.switch_events()) - start_switch_worker(); + if (oprofile_ops.switch_events()) + return; + + atomic_inc(&oprofile_stats.multiplex_counter); + start_switch_worker(); } /* User inputs in ms, converts to jiffies */ diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 77a57a6..61689e8 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -16,9 +16,6 @@ #include "cpu_buffer.h" struct oprofile_stat_struct oprofile_stats; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX -atomic_t multiplex_counter; -#endif void oprofile_reset_stats(void) { @@ -37,9 +34,7 @@ void oprofile_reset_stats(void) atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); atomic_set(&oprofile_stats.bt_lost_no_mapping, 0); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - atomic_set(&multiplex_counter, 0); -#endif + atomic_set(&oprofile_stats.multiplex_counter, 0); } @@ -84,6 +79,6 @@ void oprofile_create_stats_files(struct super_block *sb, struct dentry *root) &oprofile_stats.bt_lost_no_mapping); #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX oprofilefs_create_ro_atomic(sb, dir, "multiplex_counter", - &multiplex_counter); + &oprofile_stats.multiplex_counter); #endif } diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h index 3da0d08..0b54e46 100644 --- a/drivers/oprofile/oprofile_stats.h +++ b/drivers/oprofile/oprofile_stats.h @@ -17,6 +17,7 @@ struct oprofile_stat_struct { atomic_t sample_lost_no_mapping; atomic_t bt_lost_no_mapping; atomic_t event_lost_overflow; + atomic_t multiplex_counter; }; extern struct oprofile_stat_struct oprofile_stats; -- cgit v0.10.2 From 61d149d5248ad7428801cdede0f5fcc2b90cd61c Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 10 Jul 2009 15:47:17 +0200 Subject: x86/oprofile: Implement op_x86_virt_to_phys() This patch implements a common x86 function to convert virtual counter numbers to physical. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 7b3362f..5856e61 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -129,6 +129,11 @@ inline int op_x86_phys_to_virt(int phys) return __get_cpu_var(switch_index) + phys; } +inline int op_x86_virt_to_phys(int virt) +{ + return virt % model->num_counters; +} + static void nmi_shutdown_mux(void) { int i; @@ -270,6 +275,7 @@ static void mux_clone(int cpu) #else inline int op_x86_phys_to_virt(int phys) { return phys; } +inline int op_x86_virt_to_phys(int virt) { return virt; } static inline void nmi_shutdown_mux(void) { } static inline int nmi_setup_mux(void) { return 1; } static inline void diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index dce69b5..1ea1982 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -81,7 +81,7 @@ static void op_mux_fill_in_addresses(struct op_msrs * const msrs) int i; for (i = 0; i < NUM_VIRT_COUNTERS; i++) { - int hw_counter = i % NUM_COUNTERS; + int hw_counter = op_x86_virt_to_phys(i); if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i)) msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter; else diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 4e2e7c2..b837761 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h @@ -60,6 +60,7 @@ struct op_counter_config; extern u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, struct op_counter_config *counter_config); extern int op_x86_phys_to_virt(int phys); +extern int op_x86_virt_to_phys(int virt); extern struct op_x86_model_spec op_ppro_spec; extern struct op_x86_model_spec op_p4_spec; -- cgit v0.10.2 From 11be1a7b54283021777f409aa983ce125945e67c Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 10 Jul 2009 18:15:21 +0200 Subject: x86/oprofile: Add counter reservation check for virtual counters This patch adds a check for the availability of a counter. A virtual counter is used only if its physical counter is not reserved. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 5856e61..cb88b1a 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -435,15 +435,13 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) struct dentry *dir; char buf[4]; -#ifndef CONFIG_OPROFILE_EVENT_MULTIPLEX /* quick little hack to _not_ expose a counter if it is not * available for use. This should protect userspace app. * NOTE: assumes 1:1 mapping here (that counters are organized * sequentially in their struct assignment). */ - if (unlikely(!avail_to_resrv_perfctr_nmi_bit(i))) + if (!avail_to_resrv_perfctr_nmi_bit(op_x86_virt_to_phys(i))) continue; -#endif /* CONFIG_OPROFILE_EVENT_MULTIPLEX */ snprintf(buf, sizeof(buf), "%d", i); dir = oprofilefs_mkdir(sb, root, buf); -- cgit v0.10.2 From c550091edd6fac2ed9dac1b30d986b6c58b216fa Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 16 Jul 2009 13:11:16 +0200 Subject: x86/oprofile: Small coding style fixes Some small coding style fixes. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 1ea1982..827beec 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -144,11 +144,10 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, /* setup reset_value */ for (i = 0; i < NUM_VIRT_COUNTERS; ++i) { - if (counter_config[i].enabled) { + if (counter_config[i].enabled) reset_value[i] = counter_config[i].count; - } else { + else reset_value[i] = 0; - } } /* clear all counters */ -- cgit v0.10.2 From 68fd60a8c8bca6af51805c45f286f0f2572ac977 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Thu, 16 Jul 2009 10:53:34 +0800 Subject: tracing/events: add missing type info of dynamic arrays The format file doesn't contain enough information for __dynamic_array/__string. The type name is missing. Before: # cat format: name: irq_handler_entry ... field:__data_loc name; offset:16; size:2; After: # cat format: name: irq_handler_entry ... field:__data_loc char[] name; offset:16; size:2; Signed-off-by: Lai Jiangshan LKML-Reference: <4A5E962E.9020900@cn.fujitsu.com> Signed-off-by: Li Zefan Acked-by: Frederic Weisbecker Signed-off-by: Steven Rostedt diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 1867553..cc78943 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -120,7 +120,7 @@ #undef __dynamic_array #define __dynamic_array(type, item, len) \ - ret = trace_seq_printf(s, "\tfield:__data_loc " #item ";\t" \ + ret = trace_seq_printf(s, "\tfield:__data_loc " #type "[] " #item ";\t"\ "offset:%u;\tsize:%u;\n", \ (unsigned int)offsetof(typeof(field), \ __data_loc_##item), \ @@ -279,7 +279,7 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ #undef __dynamic_array #define __dynamic_array(type, item, len) \ - ret = trace_define_field(event_call, "__data_loc" "[" #type "]", #item,\ + ret = trace_define_field(event_call, "__data_loc " #type "[]", #item, \ offsetof(typeof(field), __data_loc_##item), \ sizeof(field.__data_loc_##item), 0); -- cgit v0.10.2 From 27e0955184a70c4bd4542ee2da18c749b4f43345 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Fri, 17 Jul 2009 08:01:54 +0000 Subject: b44: strncpy does not null terminate string strlcpy() will always null terminate the string. Also use the sizeof(version) to strlcopy() the version string. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 36d4d37..1f7f015 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1756,15 +1756,15 @@ static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *inf struct b44 *bp = netdev_priv(dev); struct ssb_bus *bus = bp->sdev->bus; - strncpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); - strncpy(info->version, DRV_MODULE_VERSION, sizeof(info->driver)); + strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); + strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version)); switch (bus->bustype) { case SSB_BUSTYPE_PCI: - strncpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info)); + strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info)); break; case SSB_BUSTYPE_PCMCIA: case SSB_BUSTYPE_SSB: - strncpy(info->bus_info, "SSB", sizeof(info->bus_info)); + strlcpy(info->bus_info, "SSB", sizeof(info->bus_info)); break; } } -- cgit v0.10.2 From 4edf547b4d0f886acf5aa5a0c8f8edbaff280830 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Jul 2009 06:16:34 +0000 Subject: net: explain netns notifiers a little better Eric explained this to me -- and afterwards the comment made sense, but not before. Add the the critical point about interfaces having to be gone from the netns before subsys notifiers are called. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 5c5136f..a120284 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -239,13 +239,15 @@ struct pernet_operations { * needs per network namespace operations use device pernet operations, * otherwise use pernet subsys operations. * - * This is critically important. Most of the network code cleanup - * runs with the assumption that dev_remove_pack has been called so no - * new packets will arrive during and after the cleanup functions have - * been called. dev_remove_pack is not per namespace so instead the - * guarantee of no more packets arriving in a network namespace is - * provided by ensuring that all network devices and all sockets have - * left the network namespace before the cleanup methods are called. + * Network interfaces need to be removed from a dying netns _before_ + * subsys notifiers can be called, as most of the network code cleanup + * (which is done from subsys notifiers) runs with the assumption that + * dev_remove_pack has been called so no new packets will arrive during + * and after the cleanup functions have been called. dev_remove_pack + * is not per namespace so instead the guarantee of no more packets + * arriving in a network namespace is provided by ensuring that all + * network devices and all sockets have left the network namespace + * before the cleanup methods are called. * * For the longest time the ipv4 icmp code was registered as a pernet * device which caused kernel oops, and panics during network -- cgit v0.10.2 From 3ba23ade464cca7c4a7ba5628c613339d3f2e161 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:22 +0000 Subject: RDS: Set retry_count to 2 and make modifiable via modparam This will be default cause IB connections to failover faster, but allow a longer retry count to be used if desired. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib.c b/net/rds/ib.c index b9bcd32..27abdd3 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -43,11 +43,14 @@ unsigned int fmr_pool_size = RDS_FMR_POOL_SIZE; unsigned int fmr_message_size = RDS_FMR_SIZE + 1; /* +1 allows for unaligned MRs */ +unsigned int rds_ib_retry_count = RDS_IB_DEFAULT_RETRY_COUNT; module_param(fmr_pool_size, int, 0444); MODULE_PARM_DESC(fmr_pool_size, " Max number of fmr per HCA"); module_param(fmr_message_size, int, 0444); MODULE_PARM_DESC(fmr_message_size, " Max size of a RDMA transfer"); +module_param(rds_ib_retry_count, int, 0444); +MODULE_PARM_DESC(rds_ib_retry_count, " Number of hw retries before reporting an error"); struct list_head rds_ib_devices; diff --git a/net/rds/ib.h b/net/rds/ib.h index 455ae73..420afb9 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -15,6 +15,8 @@ #define RDS_IB_DEFAULT_RECV_WR 1024 #define RDS_IB_DEFAULT_SEND_WR 256 +#define RDS_IB_DEFAULT_RETRY_COUNT 2 + #define RDS_IB_SUPPORTED_PROTOCOLS 0x00000003 /* minor versions supported */ extern struct list_head rds_ib_devices; @@ -247,6 +249,7 @@ extern struct ib_client rds_ib_client; extern unsigned int fmr_pool_size; extern unsigned int fmr_message_size; +extern unsigned int rds_ib_retry_count; extern spinlock_t ib_nodev_conns_lock; extern struct list_head ib_nodev_conns; diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index f8e40e1..605c032 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -145,7 +145,7 @@ static void rds_ib_cm_fill_conn_param(struct rds_connection *conn, /* XXX tune these? */ conn_param->responder_resources = 1; conn_param->initiator_depth = 1; - conn_param->retry_count = 7; + conn_param->retry_count = min_t(unsigned int, rds_ib_retry_count, 7); conn_param->rnr_retry_count = 7; if (dp) { -- cgit v0.10.2 From 9ddbcfa098bae757d3760dd1dbf2847a0bd5a525 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:23 +0000 Subject: RDS/IB: Improve RDS protocol version checking RDS on IB uses privdata to do protocol version negotiation. Apparently the IB stack will return a larger privdata buffer than the struct we were expecting. Just to be extra-sure, this patch adds some checks in this area. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 605c032..0964ac5 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -98,7 +98,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even struct ib_qp_attr qp_attr; int err; - if (event->param.conn.private_data_len) { + if (event->param.conn.private_data_len >= sizeof(*dp)) { dp = event->param.conn.private_data; rds_ib_set_protocol(conn, @@ -344,19 +344,32 @@ out: return ret; } -static u32 rds_ib_protocol_compatible(const struct rds_ib_connect_private *dp) +static u32 rds_ib_protocol_compatible(struct rdma_cm_event *event) { + const struct rds_ib_connect_private *dp = event->param.conn.private_data; u16 common; u32 version = 0; - /* rdma_cm private data is odd - when there is any private data in the + /* + * rdma_cm private data is odd - when there is any private data in the * request, we will be given a pretty large buffer without telling us the * original size. The only way to tell the difference is by looking at * the contents, which are initialized to zero. * If the protocol version fields aren't set, this is a connection attempt * from an older version. This could could be 3.0 or 2.0 - we can't tell. - * We really should have changed this for OFED 1.3 :-( */ - if (dp->dp_protocol_major == 0) + * We really should have changed this for OFED 1.3 :-( + */ + + /* Be paranoid. RDS always has privdata */ + if (!event->param.conn.private_data_len) { + printk(KERN_NOTICE "RDS incoming connection has no private data, " + "rejecting\n"); + return 0; + } + + /* Even if len is crap *now* I still want to check it. -ASG */ + if (event->param.conn.private_data_len < sizeof (*dp) + || dp->dp_protocol_major == 0) return RDS_PROTOCOL_3_0; common = be16_to_cpu(dp->dp_protocol_minor_mask) & RDS_IB_SUPPORTED_PROTOCOLS; @@ -388,7 +401,7 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id, int err, destroy = 1; /* Check whether the remote protocol version matches ours. */ - version = rds_ib_protocol_compatible(dp); + version = rds_ib_protocol_compatible(event); if (!version) goto out; -- cgit v0.10.2 From 02a6a2592e41d27644d647f3bce23598649961bc Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:24 +0000 Subject: RDS/IB: Handle connections using RDS 3.0 wire protocol The big differences between RDS 3.0 and 3.1 are protocol-level flow control, and with 3.1 the header is in front of the data. The header always ends up in the header buffer, and the data goes in the data page. In 3.0 our "header" is a trailer, and will end up either in the data page, the header buffer, or split across the two. Since 3.1 is backwards- compatible with 3.0, we need to continue to support these cases. This patch does that -- if using RDS 3.0 wire protocol, it will copy the header from wherever it ended up into the header buffer. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib.h b/net/rds/ib.h index 420afb9..c0de7af 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -358,17 +358,25 @@ extern ctl_table rds_ib_sysctl_table[]; /* * Helper functions for getting/setting the header and data SGEs in * RDS packets (not RDMA) + * + * From version 3.1 onwards, header is in front of data in the sge. */ static inline struct ib_sge * rds_ib_header_sge(struct rds_ib_connection *ic, struct ib_sge *sge) { - return &sge[0]; + if (ic->conn->c_version > RDS_PROTOCOL_3_0) + return &sge[0]; + else + return &sge[1]; } static inline struct ib_sge * rds_ib_data_sge(struct rds_ib_connection *ic, struct ib_sge *sge) { - return &sge[1]; + if (ic->conn->c_version > RDS_PROTOCOL_3_0) + return &sge[1]; + else + return &sge[0]; } #endif diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 0964ac5..1eb0c29 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -101,10 +101,13 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even if (event->param.conn.private_data_len >= sizeof(*dp)) { dp = event->param.conn.private_data; - rds_ib_set_protocol(conn, + /* make sure it isn't empty data */ + if (dp->dp_protocol_major) { + rds_ib_set_protocol(conn, RDS_PROTOCOL(dp->dp_protocol_major, - dp->dp_protocol_minor)); - rds_ib_set_flow_control(conn, be32_to_cpu(dp->dp_credit)); + dp->dp_protocol_minor)); + rds_ib_set_flow_control(conn, be32_to_cpu(dp->dp_credit)); + } } printk(KERN_NOTICE "RDS/IB: connected to %pI4 version %u.%u%s\n", diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index 5709bad..28bdcdc 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -555,6 +555,47 @@ u64 rds_ib_piggyb_ack(struct rds_ib_connection *ic) return rds_ib_get_ack(ic); } +static struct rds_header *rds_ib_get_header(struct rds_connection *conn, + struct rds_ib_recv_work *recv, + u32 data_len) +{ + struct rds_ib_connection *ic = conn->c_transport_data; + void *hdr_buff = &ic->i_recv_hdrs[recv - ic->i_recvs]; + void *addr; + u32 misplaced_hdr_bytes; + + /* + * Support header at the front (RDS 3.1+) as well as header-at-end. + * + * Cases: + * 1) header all in header buff (great!) + * 2) header all in data page (copy all to header buff) + * 3) header split across hdr buf + data page + * (move bit in hdr buff to end before copying other bit from data page) + */ + if (conn->c_version > RDS_PROTOCOL_3_0 || data_len == RDS_FRAG_SIZE) + return hdr_buff; + + if (data_len <= (RDS_FRAG_SIZE - sizeof(struct rds_header))) { + addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0); + memcpy(hdr_buff, + addr + recv->r_frag->f_offset + data_len, + sizeof(struct rds_header)); + kunmap_atomic(addr, KM_SOFTIRQ0); + return hdr_buff; + } + + misplaced_hdr_bytes = (sizeof(struct rds_header) - (RDS_FRAG_SIZE - data_len)); + + memmove(hdr_buff + misplaced_hdr_bytes, hdr_buff, misplaced_hdr_bytes); + + addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0); + memcpy(hdr_buff, addr + recv->r_frag->f_offset + data_len, + sizeof(struct rds_header) - misplaced_hdr_bytes); + kunmap_atomic(addr, KM_SOFTIRQ0); + return hdr_buff; +} + /* * It's kind of lame that we're copying from the posted receive pages into * long-lived bitmaps. We could have posted the bitmaps and rdma written into @@ -667,7 +708,7 @@ static void rds_ib_process_recv(struct rds_connection *conn, } byte_len -= sizeof(struct rds_header); - ihdr = &ic->i_recv_hdrs[recv - ic->i_recvs]; + ihdr = rds_ib_get_header(conn, recv, byte_len); /* Validate the checksum. */ if (!rds_message_verify_checksum(ihdr)) { -- cgit v0.10.2 From 8dacd57e7ebc307d4d7c27c5d1caada4c4e63ebd Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:25 +0000 Subject: RDS/IB: Fix printk to indicate remote IP, not local Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 1eb0c29..f621086 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -111,7 +111,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even } printk(KERN_NOTICE "RDS/IB: connected to %pI4 version %u.%u%s\n", - &conn->c_laddr, + &conn->c_faddr, RDS_PROTOCOL_MAJOR(conn->c_version), RDS_PROTOCOL_MINOR(conn->c_version), ic->i_flowctl ? ", flow control" : ""); -- cgit v0.10.2 From 92c330b9e93ce70a8c45a6b8b0a551321d783feb Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:26 +0000 Subject: RDS/RDMA: Fix cut-n-paste errors in printks in rdma_transport.c Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/rdma_transport.c b/net/rds/rdma_transport.c index 7d0f901..981a5e6 100644 --- a/net/rds/rdma_transport.c +++ b/net/rds/rdma_transport.c @@ -101,7 +101,7 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id, break; case RDMA_CM_EVENT_DISCONNECTED: - printk(KERN_WARNING "RDS/IW: DISCONNECT event - dropping connection " + printk(KERN_WARNING "RDS/RDMA: DISCONNECT event - dropping connection " "%pI4->%pI4\n", &conn->c_laddr, &conn->c_faddr); rds_conn_drop(conn); @@ -132,7 +132,7 @@ static int __init rds_rdma_listen_init(void) cm_id = rdma_create_id(rds_rdma_cm_event_handler, NULL, RDMA_PS_TCP); if (IS_ERR(cm_id)) { ret = PTR_ERR(cm_id); - printk(KERN_ERR "RDS/IW: failed to setup listener, " + printk(KERN_ERR "RDS/RDMA: failed to setup listener, " "rdma_create_id() returned %d\n", ret); goto out; } @@ -147,14 +147,14 @@ static int __init rds_rdma_listen_init(void) */ ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin); if (ret) { - printk(KERN_ERR "RDS/IW: failed to setup listener, " + printk(KERN_ERR "RDS/RDMA: failed to setup listener, " "rdma_bind_addr() returned %d\n", ret); goto out; } ret = rdma_listen(cm_id, 128); if (ret) { - printk(KERN_ERR "RDS/IW: failed to setup listener, " + printk(KERN_ERR "RDS/RDMA: failed to setup listener, " "rdma_listen() returned %d\n", ret); goto out; } -- cgit v0.10.2 From 597ddd50e1c07ac55ac7742442690efcf16a37f5 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:27 +0000 Subject: RDS/IB: Rename byte_len to data_len to enhance readability Of course len is in bytes. Calling it data_len hopefully indicates a little better what the variable is actually for. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index 28bdcdc..cd7a6cf 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -686,7 +686,7 @@ struct rds_ib_ack_state { }; static void rds_ib_process_recv(struct rds_connection *conn, - struct rds_ib_recv_work *recv, u32 byte_len, + struct rds_ib_recv_work *recv, u32 data_len, struct rds_ib_ack_state *state) { struct rds_ib_connection *ic = conn->c_transport_data; @@ -696,9 +696,9 @@ static void rds_ib_process_recv(struct rds_connection *conn, /* XXX shut down the connection if port 0,0 are seen? */ rdsdebug("ic %p ibinc %p recv %p byte len %u\n", ic, ibinc, recv, - byte_len); + data_len); - if (byte_len < sizeof(struct rds_header)) { + if (data_len < sizeof(struct rds_header)) { rds_ib_conn_error(conn, "incoming message " "from %pI4 didn't inclue a " "header, disconnecting and " @@ -706,9 +706,9 @@ static void rds_ib_process_recv(struct rds_connection *conn, &conn->c_faddr); return; } - byte_len -= sizeof(struct rds_header); + data_len -= sizeof(struct rds_header); - ihdr = rds_ib_get_header(conn, recv, byte_len); + ihdr = rds_ib_get_header(conn, recv, data_len); /* Validate the checksum. */ if (!rds_message_verify_checksum(ihdr)) { @@ -728,7 +728,7 @@ static void rds_ib_process_recv(struct rds_connection *conn, if (ihdr->h_credit) rds_ib_send_add_credits(conn, ihdr->h_credit); - if (ihdr->h_sport == 0 && ihdr->h_dport == 0 && byte_len == 0) { + if (ihdr->h_sport == 0 && ihdr->h_dport == 0 && data_len == 0) { /* This is an ACK-only packet. The fact that it gets * special treatment here is that historically, ACKs * were rather special beasts. -- cgit v0.10.2 From 9099707ded4b3aeda7b1a6c1c87076bd18578d24 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:28 +0000 Subject: RDS: Don't set c_version in __rds_conn_create() Protocol negotiation is logically a property of the transports, so rds core need not set it. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/connection.c b/net/rds/connection.c index d14445c..605fe3f 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -155,7 +155,6 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, } INIT_HLIST_NODE(&conn->c_hash_node); - conn->c_version = RDS_PROTOCOL_3_0; conn->c_laddr = laddr; conn->c_faddr = faddr; spin_lock_init(&conn->c_lock); -- cgit v0.10.2 From e11d912a7dd4dfe388f38ba3080a6d067a57b23d Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:29 +0000 Subject: RDS/IB: Move tx/rx ring init and refill to later Since RDS 3.0 and 3.1 have different packet formats, we need to wait until after protocol negotiation is complete to layout the rx buffers. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index f621086..0ad749c 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -116,6 +116,16 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even RDS_PROTOCOL_MINOR(conn->c_version), ic->i_flowctl ? ", flow control" : ""); + /* + * Init rings and fill recv. this needs to wait until protocol negotiation + * is complete, since ring layout is different from 3.0 to 3.1. + */ + rds_ib_send_init_ring(ic); + rds_ib_recv_init_ring(ic); + /* Post receive buffers - as a side effect, this will update + * the posted credit count. */ + rds_ib_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 1); + /* Tune RNR behavior */ rds_ib_tune_rnr(ic, &qp_attr); @@ -324,7 +334,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn) rdsdebug("send allocation failed\n"); goto out; } - rds_ib_send_init_ring(ic); + memset(ic->i_sends, 0, ic->i_send_ring.w_nr * sizeof(struct rds_ib_send_work)); ic->i_recvs = vmalloc(ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work)); if (ic->i_recvs == NULL) { @@ -332,14 +342,10 @@ static int rds_ib_setup_qp(struct rds_connection *conn) rdsdebug("recv allocation failed\n"); goto out; } + memset(ic->i_recvs, 0, ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work)); - rds_ib_recv_init_ring(ic); rds_ib_recv_init_ack(ic); - /* Post receive buffers - as a side effect, this will update - * the posted credit count. */ - rds_ib_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 1); - rdsdebug("conn %p pd %p mr %p cq %p %p\n", conn, ic->i_pd, ic->i_mr, ic->i_send_cq, ic->i_recv_cq); -- cgit v0.10.2 From 68cb01c1ba312add7c7cc7da1bbe98b3071904d1 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:30 +0000 Subject: RDS/IB: Disable flow control in sysctl and explain why Backwards compatibility with rds 3.0 causes protocol- based flow control to be disabled as a side-effect. I don't want to pull out FC support from the IB transport but I do want to document and keep the sysctl consistent if possible. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib_sysctl.c b/net/rds/ib_sysctl.c index d87830d..84b5ffcb 100644 --- a/net/rds/ib_sysctl.c +++ b/net/rds/ib_sysctl.c @@ -53,7 +53,17 @@ unsigned long rds_ib_sysctl_max_unsig_bytes = (16 << 20); static unsigned long rds_ib_sysctl_max_unsig_bytes_min = 1; static unsigned long rds_ib_sysctl_max_unsig_bytes_max = ~0UL; -unsigned int rds_ib_sysctl_flow_control = 1; +/* + * This sysctl does nothing. + * + * Backwards compatibility with RDS 3.0 wire protocol + * disables initial FC credit exchange. + * If it's ever possible to drop 3.0 support, + * setting this to 1 and moving init/refill of send/recv + * rings from ib_cm_connect_complete() back into ib_setup_qp() + * will cause credits to be added before protocol negotiation. + */ +unsigned int rds_ib_sysctl_flow_control = 0; ctl_table rds_ib_sysctl_table[] = { { -- cgit v0.10.2 From fdf6e6b4afd8a56fa58f70a3950bd7ea7fbaef5f Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:31 +0000 Subject: RDS/IB: Drop connection when a fatal QP event is received Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 0ad749c..c2d372f 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -203,9 +203,9 @@ static void rds_ib_qp_event_handler(struct ib_event *event, void *data) rdma_notify(ic->i_cm_id, IB_EVENT_COMM_EST); break; default: - printk(KERN_WARNING "RDS/ib: unhandled QP event %u " - "on connection to %pI4\n", event->event, - &conn->c_faddr); + rds_ib_conn_error(conn, "RDS/IB: Fatal QP Event %u " + "- connection %pI4->%pI4, reconnecting\n", + event->event, &conn->c_laddr, &conn->c_faddr); break; } } -- cgit v0.10.2 From edacaeae52ade6cbb3a0704db32a9fb4a219dee3 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:32 +0000 Subject: RDS: Fix completion notifications on blocking sockets Completion or congestion notifications were not being checked if the socket went to sleep. This patch fixes that. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/recv.c b/net/rds/recv.c index f2118c5..86bc1a0 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -409,18 +409,18 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, if (msg_flags & MSG_OOB) goto out; - /* If there are pending notifications, do those - and nothing else */ - if (!list_empty(&rs->rs_notify_queue)) { - ret = rds_notify_queue_get(rs, msg); - goto out; - } + while (1) { + /* If there are pending notifications, do those - and nothing else */ + if (!list_empty(&rs->rs_notify_queue)) { + ret = rds_notify_queue_get(rs, msg); + break; + } - if (rs->rs_cong_notify) { - ret = rds_notify_cong(rs, msg); - goto out; - } + if (rs->rs_cong_notify) { + ret = rds_notify_cong(rs, msg); + break; + } - while (1) { if (!rds_next_incoming(rs, &inc)) { if (nonblock) { ret = -EAGAIN; @@ -428,7 +428,9 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, } timeo = wait_event_interruptible_timeout(*sk->sk_sleep, - rds_next_incoming(rs, &inc), + (!list_empty(&rs->rs_notify_queue) + || rs->rs_cong_notify + || rds_next_incoming(rs, &inc)), timeo); rdsdebug("recvmsg woke inc %p timeo %ld\n", inc, timeo); -- cgit v0.10.2 From a870d62726721785c34fa73d852bd35e5d1b295b Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:33 +0000 Subject: RDS/IB: Always use PAGE_SIZE for FMR page size While FMRs allow significant flexibility in what size of pages they can use, we really just want FMR pages to match CPU page size. Roland says we can count on this always being supported, so this simplifies things. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib.c b/net/rds/ib.c index 27abdd3..868559a 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -85,9 +85,6 @@ void rds_ib_add_one(struct ib_device *device) rds_ibdev->max_wrs = dev_attr->max_qp_wr; rds_ibdev->max_sge = min(dev_attr->max_sge, RDS_IB_MAX_SGE); - rds_ibdev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1); - rds_ibdev->fmr_page_size = 1 << rds_ibdev->fmr_page_shift; - rds_ibdev->fmr_page_mask = ~((u64) rds_ibdev->fmr_page_size - 1); rds_ibdev->fmr_max_remaps = dev_attr->max_map_per_fmr?: 32; rds_ibdev->max_fmrs = dev_attr->max_fmr ? min_t(unsigned int, dev_attr->max_fmr, fmr_pool_size) : diff --git a/net/rds/ib.h b/net/rds/ib.h index c0de7af..1378b85 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -159,9 +159,6 @@ struct rds_ib_device { struct ib_pd *pd; struct ib_mr *mr; struct rds_ib_mr_pool *mr_pool; - int fmr_page_shift; - int fmr_page_size; - u64 fmr_page_mask; unsigned int fmr_max_remaps; unsigned int max_fmrs; int max_sge; diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index 81033af..ef3ab5b 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -211,7 +211,7 @@ struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev) pool->fmr_attr.max_pages = fmr_message_size; pool->fmr_attr.max_maps = rds_ibdev->fmr_max_remaps; - pool->fmr_attr.page_shift = rds_ibdev->fmr_page_shift; + pool->fmr_attr.page_shift = PAGE_SHIFT; pool->max_free_pinned = rds_ibdev->max_fmrs * fmr_message_size / 4; /* We never allow more than max_items MRs to be allocated. @@ -349,13 +349,13 @@ static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibm unsigned int dma_len = ib_sg_dma_len(dev, &scat[i]); u64 dma_addr = ib_sg_dma_address(dev, &scat[i]); - if (dma_addr & ~rds_ibdev->fmr_page_mask) { + if (dma_addr & ~PAGE_MASK) { if (i > 0) return -EINVAL; else ++page_cnt; } - if ((dma_addr + dma_len) & ~rds_ibdev->fmr_page_mask) { + if ((dma_addr + dma_len) & ~PAGE_MASK) { if (i < sg_dma_len - 1) return -EINVAL; else @@ -365,7 +365,7 @@ static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibm len += dma_len; } - page_cnt += len >> rds_ibdev->fmr_page_shift; + page_cnt += len >> PAGE_SHIFT; if (page_cnt > fmr_message_size) return -EINVAL; @@ -378,9 +378,9 @@ static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibm unsigned int dma_len = ib_sg_dma_len(dev, &scat[i]); u64 dma_addr = ib_sg_dma_address(dev, &scat[i]); - for (j = 0; j < dma_len; j += rds_ibdev->fmr_page_size) + for (j = 0; j < dma_len; j += PAGE_SIZE) dma_pages[page_cnt++] = - (dma_addr & rds_ibdev->fmr_page_mask) + j; + (dma_addr & PAGE_MASK) + j; } ret = ib_map_phys_fmr(ibmr->fmr, -- cgit v0.10.2 From 404bb72a56e553febe1055f98347a7a3e3145759 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:34 +0000 Subject: RDS/IW: Remove page_shift variable from iwarp transport The existing code treated page_shift as a variable, when in fact we always want to have the fastreg page size be the same as the arch's page size -- and it is, so this doesn't need to be a variable. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/iw.c b/net/rds/iw.c index d16e1cb..2e6b495 100644 --- a/net/rds/iw.c +++ b/net/rds/iw.c @@ -83,8 +83,6 @@ void rds_iw_add_one(struct ib_device *device) rds_iwdev->max_wrs = dev_attr->max_qp_wr; rds_iwdev->max_sge = min(dev_attr->max_sge, RDS_IW_MAX_SGE); - rds_iwdev->page_shift = max(PAGE_SHIFT, ffs(dev_attr->page_size_cap) - 1); - rds_iwdev->dev = device; rds_iwdev->pd = ib_alloc_pd(device); if (IS_ERR(rds_iwdev->pd)) diff --git a/net/rds/iw.h b/net/rds/iw.h index 0715dde..dd72b62 100644 --- a/net/rds/iw.h +++ b/net/rds/iw.h @@ -181,7 +181,6 @@ struct rds_iw_device { struct ib_pd *pd; struct ib_mr *mr; struct rds_iw_mr_pool *mr_pool; - int page_shift; int max_sge; unsigned int max_wrs; unsigned int dma_local_lkey:1; diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c index dcdb37d..de4a1b1 100644 --- a/net/rds/iw_rdma.c +++ b/net/rds/iw_rdma.c @@ -263,18 +263,12 @@ static void rds_iw_set_scatterlist(struct rds_iw_scatterlist *sg, } static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev, - struct rds_iw_scatterlist *sg, - unsigned int dma_page_shift) + struct rds_iw_scatterlist *sg) { struct ib_device *dev = rds_iwdev->dev; u64 *dma_pages = NULL; - u64 dma_mask; - unsigned int dma_page_size; int i, j, ret; - dma_page_size = 1 << dma_page_shift; - dma_mask = dma_page_size - 1; - WARN_ON(sg->dma_len); sg->dma_len = ib_dma_map_sg(dev, sg->list, sg->len, DMA_BIDIRECTIONAL); @@ -295,18 +289,18 @@ static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev, sg->bytes += dma_len; end_addr = dma_addr + dma_len; - if (dma_addr & dma_mask) { + if (dma_addr & PAGE_MASK) { if (i > 0) goto out_unmap; - dma_addr &= ~dma_mask; + dma_addr &= ~PAGE_MASK; } - if (end_addr & dma_mask) { + if (end_addr & PAGE_MASK) { if (i < sg->dma_len - 1) goto out_unmap; - end_addr = (end_addr + dma_mask) & ~dma_mask; + end_addr = (end_addr + PAGE_MASK) & ~PAGE_MASK; } - sg->dma_npages += (end_addr - dma_addr) >> dma_page_shift; + sg->dma_npages += (end_addr - dma_addr) >> PAGE_SHIFT; } /* Now gather the dma addrs into one list */ @@ -325,8 +319,8 @@ static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev, u64 end_addr; end_addr = dma_addr + dma_len; - dma_addr &= ~dma_mask; - for (; dma_addr < end_addr; dma_addr += dma_page_size) + dma_addr &= ~PAGE_MASK; + for (; dma_addr < end_addr; dma_addr += PAGE_SIZE) dma_pages[j++] = dma_addr; BUG_ON(j > sg->dma_npages); } @@ -727,7 +721,7 @@ static int rds_iw_rdma_build_fastreg(struct rds_iw_mapping *mapping) f_wr.wr.fast_reg.rkey = mapping->m_rkey; f_wr.wr.fast_reg.page_list = ibmr->page_list; f_wr.wr.fast_reg.page_list_len = mapping->m_sg.dma_len; - f_wr.wr.fast_reg.page_shift = ibmr->device->page_shift; + f_wr.wr.fast_reg.page_shift = PAGE_SHIFT; f_wr.wr.fast_reg.access_flags = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ | IB_ACCESS_REMOTE_WRITE; @@ -780,9 +774,7 @@ static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool, rds_iw_set_scatterlist(&mapping->m_sg, sg, sg_len); - dma_pages = rds_iw_map_scatterlist(rds_iwdev, - &mapping->m_sg, - rds_iwdev->page_shift); + dma_pages = rds_iw_map_scatterlist(rds_iwdev, &mapping->m_sg); if (IS_ERR(dma_pages)) { ret = PTR_ERR(dma_pages); dma_pages = NULL; diff --git a/net/rds/iw_send.c b/net/rds/iw_send.c index 44a6a05..1f5abe3 100644 --- a/net/rds/iw_send.c +++ b/net/rds/iw_send.c @@ -779,7 +779,7 @@ static void rds_iw_build_send_fastreg(struct rds_iw_device *rds_iwdev, struct rd send->s_wr.wr.fast_reg.rkey = send->s_mr->rkey; send->s_wr.wr.fast_reg.page_list = send->s_page_list; send->s_wr.wr.fast_reg.page_list_len = nent; - send->s_wr.wr.fast_reg.page_shift = rds_iwdev->page_shift; + send->s_wr.wr.fast_reg.page_shift = PAGE_SHIFT; send->s_wr.wr.fast_reg.access_flags = IB_ACCESS_REMOTE_WRITE; send->s_wr.wr.fast_reg.iova_start = sg_addr; -- cgit v0.10.2 From ed9e352a350ec85eb354046e0db6a86019620f53 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:35 +0000 Subject: RDS/IW: Remove dead code In iWARP code, node_type will always be RNIC Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/iw.c b/net/rds/iw.c index 2e6b495..f5e9a29 100644 --- a/net/rds/iw.c +++ b/net/rds/iw.c @@ -89,15 +89,10 @@ void rds_iw_add_one(struct ib_device *device) goto free_dev; if (!rds_iwdev->dma_local_lkey) { - if (device->node_type != RDMA_NODE_RNIC) { - rds_iwdev->mr = ib_get_dma_mr(rds_iwdev->pd, - IB_ACCESS_LOCAL_WRITE); - } else { - rds_iwdev->mr = ib_get_dma_mr(rds_iwdev->pd, - IB_ACCESS_REMOTE_READ | - IB_ACCESS_REMOTE_WRITE | - IB_ACCESS_LOCAL_WRITE); - } + rds_iwdev->mr = ib_get_dma_mr(rds_iwdev->pd, + IB_ACCESS_REMOTE_READ | + IB_ACCESS_REMOTE_WRITE | + IB_ACCESS_LOCAL_WRITE); if (IS_ERR(rds_iwdev->mr)) goto err_pd; } else -- cgit v0.10.2 From cb24405e67e56cbef51b5e4d0bb0a0fde167261f Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 17 Jul 2009 13:13:36 +0000 Subject: RDS: Refactor end of __conn_create for readability Add a comment for what's going on. Remove negative logic. I find this much easier to understand quickly, although there are a few lines duplicated. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/connection.c b/net/rds/connection.c index 605fe3f..b420a20 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -126,7 +126,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, struct rds_transport *trans, gfp_t gfp, int is_outgoing) { - struct rds_connection *conn, *tmp, *parent = NULL; + struct rds_connection *conn, *parent = NULL; struct hlist_head *head = rds_conn_bucket(laddr, faddr); unsigned long flags; int ret; @@ -210,26 +210,40 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, trans->t_name ? trans->t_name : "[unknown]", is_outgoing ? "(outgoing)" : ""); + /* + * Since we ran without holding the conn lock, someone could + * have created the same conn (either normal or passive) in the + * interim. We check while holding the lock. If we won, we complete + * init and return our conn. If we lost, we rollback and return the + * other one. + */ spin_lock_irqsave(&rds_conn_lock, flags); - if (parent == NULL) { - tmp = rds_conn_lookup(head, laddr, faddr, trans); - if (tmp == NULL) - hlist_add_head(&conn->c_hash_node, head); - } else { - tmp = parent->c_passive; - if (!tmp) + if (parent) { + /* Creating passive conn */ + if (parent->c_passive) { + trans->conn_free(conn->c_transport_data); + kmem_cache_free(rds_conn_slab, conn); + conn = parent->c_passive; + } else { parent->c_passive = conn; - } - - if (tmp) { - trans->conn_free(conn->c_transport_data); - kmem_cache_free(rds_conn_slab, conn); - conn = tmp; + rds_cong_add_conn(conn); + rds_conn_count++; + } } else { - rds_cong_add_conn(conn); - rds_conn_count++; + /* Creating normal conn */ + struct rds_connection *found; + + found = rds_conn_lookup(head, laddr, faddr, trans); + if (found) { + trans->conn_free(conn->c_transport_data); + kmem_cache_free(rds_conn_slab, conn); + conn = found; + } else { + hlist_add_head(&conn->c_hash_node, head); + rds_cong_add_conn(conn); + rds_conn_count++; + } } - spin_unlock_irqrestore(&rds_conn_lock, flags); out: -- cgit v0.10.2 From 7d536cb3fb9993bdcd5a2fbaa6b0670ded4e101c Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Thu, 16 Jul 2009 10:54:02 +0800 Subject: tracing/events: record the size of dynamic arrays When a dynamic array is defined, we add __data_loc_foo in trace_entry to record the offset of the array, but the size of the array is not recorded, which causes 2 problems: - the event filter just compares the first 2 chars of the strings. - parsers can't parse dynamic arrays. So we encode the size of each dynamic array in the higher 16 bits of __data_loc_foo, while the offset is in lower 16 bits. Signed-off-by: Li Zefan LKML-Reference: <4A5E964A.9000403@cn.fujitsu.com> Acked-by: Frederic Weisbecker Signed-off-by: Steven Rostedt diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index cc78943..3cbb96e 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -25,7 +25,7 @@ #define __array(type, item, len) type item[len]; #undef __dynamic_array -#define __dynamic_array(type, item, len) unsigned short __data_loc_##item; +#define __dynamic_array(type, item, len) u32 __data_loc_##item; #undef __string #define __string(item, src) __dynamic_array(char, item, -1) @@ -51,13 +51,14 @@ * Include the following: * * struct ftrace_data_offsets_ { - * int ; - * int ; + * u32 ; + * u32 ; * [...] * }; * - * The __dynamic_array() macro will create each int , this is + * The __dynamic_array() macro will create each u32 , this is * to keep the offset of each array from the beginning of the event. + * The size of an array is also encoded, in the higher 16 bits of . */ #undef __field @@ -67,7 +68,7 @@ #define __array(type, item, len) #undef __dynamic_array -#define __dynamic_array(type, item, len) int item; +#define __dynamic_array(type, item, len) u32 item; #undef __string #define __string(item, src) __dynamic_array(char, item, -1) @@ -207,7 +208,7 @@ ftrace_format_##call(struct trace_seq *s) \ #undef __get_dynamic_array #define __get_dynamic_array(field) \ - ((void *)__entry + __entry->__data_loc_##field) + ((void *)__entry + (__entry->__data_loc_##field & 0xffff)) #undef __get_str #define __get_str(field) (char *)__get_dynamic_array(field) @@ -325,6 +326,7 @@ ftrace_define_fields_##call(void) \ #define __dynamic_array(type, item, len) \ __data_offsets->item = __data_size + \ offsetof(typeof(*entry), __data); \ + __data_offsets->item |= (len * sizeof(type)) << 16; \ __data_size += (len) * sizeof(type); #undef __string diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index b9aae72..1c80ef7 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -176,11 +176,13 @@ static int filter_pred_string(struct filter_pred *pred, void *event, static int filter_pred_strloc(struct filter_pred *pred, void *event, int val1, int val2) { - unsigned short str_loc = *(unsigned short *)(event + pred->offset); + u32 str_item = *(u32 *)(event + pred->offset); + int str_loc = str_item & 0xffff; + int str_len = str_item >> 16; char *addr = (char *)(event + str_loc); int cmp, match; - cmp = strncmp(addr, pred->str_val, pred->str_len); + cmp = strncmp(addr, pred->str_val, str_len); match = (!cmp) ^ pred->not; -- cgit v0.10.2 From ff4e9da2330beb8d64498a513d3f9694e941b01a Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Mon, 22 Jun 2009 10:33:07 +0800 Subject: tracing: cleanup for tracing_trace_options_read() '\n' is already appended, and what we need is just an extra space for the '\0'. Signed-off-by: Xiao Guangrong LKML-Reference: <4A3EED63.3090908@cn.fujitsu.com> Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index e30e6b1..38a4a3e 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -2256,8 +2256,8 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf, len += 3; /* "no" and newline */ } - /* +2 for \n and \0 */ - buf = kmalloc(len + 2, GFP_KERNEL); + /* +1 for \0 */ + buf = kmalloc(len + 1, GFP_KERNEL); if (!buf) { mutex_unlock(&trace_types_lock); return -ENOMEM; @@ -2280,7 +2280,7 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf, } mutex_unlock(&trace_types_lock); - WARN_ON(r >= len + 2); + WARN_ON(r >= len + 1); r = simple_read_from_buffer(ubuf, cnt, ppos, buf, r); -- cgit v0.10.2 From 1f9963cbb0280e0cd554161e00f1a0eeddbf1ae1 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 20 Jul 2009 10:20:53 +0800 Subject: tracing/filters: improve subsystem filter Currently a subsystem filter should be applicable to all events under the subsystem, and if it failed, all the event filters will be cleared. Those behaviors make subsys filter much less useful: # echo 'vec == 1' > irq/softirq_entry/filter # echo 'irq == 5' > irq/filter bash: echo: write error: Invalid argument # cat irq/softirq_entry/filter none I'd expect it set the filter for irq_handler_entry/exit, and not touch softirq_entry/exit. The basic idea is, try to see if the filter can be applied to which events, and then just apply to the those events: # echo 'vec == 1' > softirq_entry/filter # echo 'irq == 5' > filter # cat irq_handler_entry/filter irq == 5 # cat softirq_entry/filter vec == 1 Changelog for v2: - do some cleanups to address Frederic's comments. Inspired-by: Steven Rostedt Signed-off-by: Li Zefan Acked-by: Frederic Weisbecker LKML-Reference: <4A63D485.7030703@cn.fujitsu.com> Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 5c093ff..26d3673 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -101,6 +101,8 @@ void trace_current_buffer_discard_commit(struct ring_buffer_event *event); void tracing_record_cmdline(struct task_struct *tsk); +struct event_filter; + struct ftrace_event_call { struct list_head list; char *name; @@ -116,7 +118,7 @@ struct ftrace_event_call { int (*define_fields)(void); struct list_head fields; int filter_active; - void *filter; + struct event_filter *filter; void *mod; #ifdef CONFIG_EVENT_PROFILE diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 94305c7..758b0db 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -750,13 +750,14 @@ struct event_filter { int n_preds; struct filter_pred **preds; char *filter_string; + bool no_reset; }; struct event_subsystem { struct list_head list; const char *name; struct dentry *entry; - void *filter; + struct event_filter *filter; int nr_events; }; diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 1c80ef7..27c2dbe 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -420,7 +420,14 @@ oom: } EXPORT_SYMBOL_GPL(init_preds); -static void filter_free_subsystem_preds(struct event_subsystem *system) +enum { + FILTER_DISABLE_ALL, + FILTER_INIT_NO_RESET, + FILTER_SKIP_NO_RESET, +}; + +static void filter_free_subsystem_preds(struct event_subsystem *system, + int flag) { struct ftrace_event_call *call; @@ -428,6 +435,14 @@ static void filter_free_subsystem_preds(struct event_subsystem *system) if (!call->define_fields) continue; + if (flag == FILTER_INIT_NO_RESET) { + call->filter->no_reset = false; + continue; + } + + if (flag == FILTER_SKIP_NO_RESET && call->filter->no_reset) + continue; + if (!strcmp(call->system, system->name)) { filter_disable_preds(call); remove_filter_string(call->filter); @@ -529,7 +544,8 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size, static int filter_add_pred(struct filter_parse_state *ps, struct ftrace_event_call *call, - struct filter_pred *pred) + struct filter_pred *pred, + bool dry_run) { struct ftrace_event_field *field; filter_pred_fn_t fn; @@ -541,10 +557,12 @@ static int filter_add_pred(struct filter_parse_state *ps, if (pred->op == OP_AND) { pred->pop_n = 2; - return filter_add_pred_fn(ps, call, pred, filter_pred_and); + fn = filter_pred_and; + goto add_pred_fn; } else if (pred->op == OP_OR) { pred->pop_n = 2; - return filter_add_pred_fn(ps, call, pred, filter_pred_or); + fn = filter_pred_or; + goto add_pred_fn; } field = find_event_field(call, pred->field_name); @@ -567,9 +585,6 @@ static int filter_add_pred(struct filter_parse_state *ps, else fn = filter_pred_strloc; pred->str_len = field->size; - if (pred->op == OP_NE) - pred->not = 1; - return filter_add_pred_fn(ps, call, pred, fn); } else { if (field->is_signed) ret = strict_strtoll(pred->str_val, 0, &val); @@ -580,27 +595,33 @@ static int filter_add_pred(struct filter_parse_state *ps, return -EINVAL; } pred->val = val; - } - fn = select_comparison_fn(pred->op, field->size, field->is_signed); - if (!fn) { - parse_error(ps, FILT_ERR_INVALID_OP, 0); - return -EINVAL; + fn = select_comparison_fn(pred->op, field->size, + field->is_signed); + if (!fn) { + parse_error(ps, FILT_ERR_INVALID_OP, 0); + return -EINVAL; + } } if (pred->op == OP_NE) pred->not = 1; - return filter_add_pred_fn(ps, call, pred, fn); +add_pred_fn: + if (!dry_run) + return filter_add_pred_fn(ps, call, pred, fn); + return 0; } static int filter_add_subsystem_pred(struct filter_parse_state *ps, struct event_subsystem *system, struct filter_pred *pred, - char *filter_string) + char *filter_string, + bool dry_run) { struct ftrace_event_call *call; int err = 0; + bool fail = true; list_for_each_entry(call, &ftrace_events, list) { @@ -610,16 +631,24 @@ static int filter_add_subsystem_pred(struct filter_parse_state *ps, if (strcmp(call->system, system->name)) continue; - err = filter_add_pred(ps, call, pred); - if (err) { - filter_free_subsystem_preds(system); - parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); - goto out; - } - replace_filter_string(call->filter, filter_string); + if (call->filter->no_reset) + continue; + + err = filter_add_pred(ps, call, pred, dry_run); + if (err) + call->filter->no_reset = true; + else + fail = false; + + if (!dry_run) + replace_filter_string(call->filter, filter_string); } -out: - return err; + + if (fail) { + parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); + return err; + } + return 0; } static void parse_init(struct filter_parse_state *ps, @@ -978,12 +1007,14 @@ static int check_preds(struct filter_parse_state *ps) static int replace_preds(struct event_subsystem *system, struct ftrace_event_call *call, struct filter_parse_state *ps, - char *filter_string) + char *filter_string, + bool dry_run) { char *operand1 = NULL, *operand2 = NULL; struct filter_pred *pred; struct postfix_elt *elt; int err; + int n_preds = 0; err = check_preds(ps); if (err) @@ -1002,19 +1033,14 @@ static int replace_preds(struct event_subsystem *system, continue; } + if (n_preds++ == MAX_FILTER_PRED) { + parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); + return -ENOSPC; + } + if (elt->op == OP_AND || elt->op == OP_OR) { pred = create_logical_pred(elt->op); - if (call) - err = filter_add_pred(ps, call, pred); - else - err = filter_add_subsystem_pred(ps, system, - pred, filter_string); - filter_free_pred(pred); - if (err) - return err; - - operand1 = operand2 = NULL; - continue; + goto add_pred; } if (!operand1 || !operand2) { @@ -1023,11 +1049,12 @@ static int replace_preds(struct event_subsystem *system, } pred = create_pred(elt->op, operand1, operand2); +add_pred: if (call) - err = filter_add_pred(ps, call, pred); + err = filter_add_pred(ps, call, pred, false); else err = filter_add_subsystem_pred(ps, system, pred, - filter_string); + filter_string, dry_run); filter_free_pred(pred); if (err) return err; @@ -1068,7 +1095,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) goto out; } - err = replace_preds(NULL, call, ps, filter_string); + err = replace_preds(NULL, call, ps, filter_string, false); if (err) append_filter_err(ps, call->filter); @@ -1092,7 +1119,7 @@ int apply_subsystem_event_filter(struct event_subsystem *system, mutex_lock(&event_mutex); if (!strcmp(strstrip(filter_string), "0")) { - filter_free_subsystem_preds(system); + filter_free_subsystem_preds(system, FILTER_DISABLE_ALL); remove_filter_string(system->filter); mutex_unlock(&event_mutex); return 0; @@ -1103,7 +1130,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system, if (!ps) goto out_unlock; - filter_free_subsystem_preds(system); replace_filter_string(system->filter, filter_string); parse_init(ps, filter_ops, filter_string); @@ -1113,9 +1139,23 @@ int apply_subsystem_event_filter(struct event_subsystem *system, goto out; } - err = replace_preds(system, NULL, ps, filter_string); - if (err) + filter_free_subsystem_preds(system, FILTER_INIT_NO_RESET); + + /* try to see the filter can be applied to which events */ + err = replace_preds(system, NULL, ps, filter_string, true); + if (err) { + append_filter_err(ps, system->filter); + goto out; + } + + filter_free_subsystem_preds(system, FILTER_SKIP_NO_RESET); + + /* really apply the filter to the events */ + err = replace_preds(system, NULL, ps, filter_string, false); + if (err) { append_filter_err(ps, system->filter); + filter_free_subsystem_preds(system, 2); + } out: filter_opstack_clear(ps); -- cgit v0.10.2 From 3c2b8d180a47d041e9101ead27e49d237df0f1d1 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Tue, 21 Jul 2009 11:13:25 -0700 Subject: mcastv6: Local variable shadows function argument The local variable 'idev' shadows the function argument 'idev' to ip6_mc_add_src(). Fixed by removing the local declaration, as pmc->idev should be identical with 'idev' passed as argument. Signed-off-by: Gerrit Renker Acked-by: David L Stevens Signed-off-by: David S. Miller diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 4b264ed..71c3dac 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2107,7 +2107,6 @@ static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca, for (j=0; jmca_sfcount[MCAST_EXCLUDE] != 0)) { - struct inet6_dev *idev = pmc->idev; struct ip6_sf_list *psf; /* filter mode change */ -- cgit v0.10.2 From 279abdf59c766a06db89b50c6d3615b4f2b19ed3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:22 +0000 Subject: bnx2x: Stop management traffic in loopback test Since management traffic cannot go on the wire while configured to loopback, simply stop it to avoid race condition when the MAC is set to loopback in the middle of a packet Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 6c67be6..177cb46 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -9691,8 +9691,15 @@ static void bnx2x_self_test(struct net_device *dev, etest->flags &= ~ETH_TEST_FL_OFFLINE; if (etest->flags & ETH_TEST_FL_OFFLINE) { + int port = BP_PORT(bp); + u32 val; u8 link_up; + /* save current value of input enable for TX port IF */ + val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4); + /* disable input for TX port IF */ + REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0); + link_up = bp->link_vars.link_up; bnx2x_nic_unload(bp, UNLOAD_NORMAL); bnx2x_nic_load(bp, LOAD_DIAG); @@ -9712,6 +9719,10 @@ static void bnx2x_self_test(struct net_device *dev, etest->flags |= ETH_TEST_FL_FAILED; bnx2x_nic_unload(bp, UNLOAD_NORMAL); + + /* restore input for TX port IF */ + REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val); + bnx2x_nic_load(bp, LOAD_NORMAL); /* wait until link state is restored */ bnx2x_wait_for_link(bp, link_up); diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index b8ce6fc..6d77730 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -1660,6 +1660,8 @@ #define NIG_REG_EGRESS_PBF0_IN_EN 0x100cc /* [RW 1] Input enable for TX PBF user packet port1 IF */ #define NIG_REG_EGRESS_PBF1_IN_EN 0x100d0 +/* [RW 1] Input enable for TX UMP management packet port0 IF */ +#define NIG_REG_EGRESS_UMP0_IN_EN 0x100d4 /* [RW 1] Input enable for RX_EMAC0 IF */ #define NIG_REG_EMAC0_IN_EN 0x100a4 /* [RW 1] output enable for TX EMAC pause port 0 IF */ -- cgit v0.10.2 From fd4ef40d5977e1c226e9cd9659398e82cc4a1e85 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:27 +0000 Subject: bnx2x: Fan failure Setup fan failure for different PHY types or according to nvram settings Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h index 03c6242..41c6dcb 100644 --- a/drivers/net/bnx2x_hsi.h +++ b/drivers/net/bnx2x_hsi.h @@ -91,6 +91,21 @@ struct shared_hw_cfg { /* NVRAM Offset */ #define SHARED_HW_CFG_HIDE_PORT1 0x00002000 + /* The fan failure mechanism is usually related to the PHY type + since the power consumption of the board is determined by the PHY. + Currently, fan is required for most designs with SFX7101, BCM8727 + and BCM8481. If a fan is not required for a board which uses one + of those PHYs, this field should be set to "Disabled". If a fan is + required for a different PHY type, this option should be set to + "Enabled". + The fan failure indication is expected on + SPIO5 */ +#define SHARED_HW_CFG_FAN_FAILURE_MASK 0x00180000 +#define SHARED_HW_CFG_FAN_FAILURE_SHIFT 19 +#define SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE 0x00000000 +#define SHARED_HW_CFG_FAN_FAILURE_DISABLED 0x00080000 +#define SHARED_HW_CFG_FAN_FAILURE_ENABLED 0x00100000 + u32 power_dissipated; /* 0x11c */ #define SHARED_HW_CFG_POWER_DIS_CMN_MASK 0xff000000 #define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT 24 diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 177cb46..ae8b7b5 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -2598,6 +2598,22 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) } } +static inline void bnx2x_fan_failure(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + + /* mark the failure */ + bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; + bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE; + SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config, + bp->link_params.ext_phy_config); + + /* log the failure */ + printk(KERN_ERR PFX "Fan Failure on Network Controller %s has caused" + " the driver to shutdown the card to prevent permanent" + " damage. Please contact Dell Support for assistance\n", + bp->dev->name); +} static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) { int port = BP_PORT(bp); @@ -2615,36 +2631,21 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) BNX2X_ERR("SPIO5 hw attention\n"); + /* Fan failure attention */ switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - /* Fan failure attention */ - - /* The PHY reset is controlled by GPIO 1 */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_LOW, port); /* Low power mode is controlled by GPIO 2 */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, MISC_REGISTERS_GPIO_OUTPUT_LOW, port); - /* mark the failure */ - bp->link_params.ext_phy_config &= - ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; - bp->link_params.ext_phy_config |= - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE; - SHMEM_WR(bp, - dev_info.port_hw_config[port]. - external_phy_config, - bp->link_params.ext_phy_config); - /* log the failure */ - printk(KERN_ERR PFX "Fan Failure on Network" - " Controller %s has caused the driver to" - " shutdown the card to prevent permanent" - " damage. Please contact Dell Support for" - " assistance\n", bp->dev->name); + /* The PHY reset is controlled by GPIO 1 */ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW, port); break; default: break; } + bnx2x_fan_failure(bp); } if (attn & (AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 | @@ -5509,6 +5510,58 @@ static void bnx2x_reset_common(struct bnx2x *bp) REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403); } + +static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp) +{ + u32 val; + u8 port; + u8 is_required = 0; + + val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) & + SHARED_HW_CFG_FAN_FAILURE_MASK; + + if (val == SHARED_HW_CFG_FAN_FAILURE_ENABLED) + is_required = 1; + + /* + * The fan failure mechanism is usually related to the PHY type since + * the power consumption of the board is affected by the PHY. Currently, + * fan is required for most designs with SFX7101, BCM8727 and BCM8481. + */ + else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE) + for (port = PORT_0; port < PORT_MAX; port++) { + u32 phy_type = + SHMEM_RD(bp, dev_info.port_hw_config[port]. + external_phy_config) & + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; + is_required |= + ((phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) || + (phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481)); + } + + DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required); + + if (is_required == 0) + return; + + /* Fan failure is indicated by SPIO 5 */ + bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5, + MISC_REGISTERS_SPIO_INPUT_HI_Z); + + /* set to active low mode */ + val = REG_RD(bp, MISC_REG_SPIO_INT); + val |= ((1 << MISC_REGISTERS_SPIO_5) << + MISC_REGISTERS_SPIO_INT_OLD_SET_POS); + REG_WR(bp, MISC_REG_SPIO_INT, val); + + /* enable interrupt to signal the IGU */ + val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN); + val |= (1 << MISC_REGISTERS_SPIO_5); + REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val); +} + static int bnx2x_init_common(struct bnx2x *bp) { u32 val, i; @@ -5738,27 +5791,12 @@ static int bnx2x_init_common(struct bnx2x *bp) bp->port.need_hw_lock = 1; break; - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - /* Fan failure is indicated by SPIO 5 */ - bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5, - MISC_REGISTERS_SPIO_INPUT_HI_Z); - - /* set to active low mode */ - val = REG_RD(bp, MISC_REG_SPIO_INT); - val |= ((1 << MISC_REGISTERS_SPIO_5) << - MISC_REGISTERS_SPIO_INT_OLD_SET_POS); - REG_WR(bp, MISC_REG_SPIO_INT, val); - - /* enable interrupt to signal the IGU */ - val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN); - val |= (1 << MISC_REGISTERS_SPIO_5); - REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val); - break; - default: break; } + bnx2x_setup_fan_failure_detection(bp); + /* clear PXP2 attentions */ REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0); -- cgit v0.10.2 From eb8da205a6cac953a46a247b8dd19505eba944e2 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:30 +0000 Subject: bnx2x: Fan failure early detection Check if fan failure happened before the driver was loaded and notify the user Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index ae8b7b5..d946c9e 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -5185,6 +5185,11 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) mmiowb(); bnx2x_int_enable(bp); + + /* Check for SPIO5 */ + bnx2x_attn_int_deasserted0(bp, + REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + BP_PORT(bp)*4) & + AEU_INPUTS_ATTN_BITS_SPIO5); } /* end of nic init */ -- cgit v0.10.2 From 37dbbf32a0d45f0ed88f92cb6d0c35f4809e3a8e Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:33 +0000 Subject: bnx2x: Adding some mmiowb Signed-off-by: Vlad Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index d946c9e..f20df6d 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -652,6 +652,11 @@ static void bnx2x_int_enable(struct bnx2x *bp) val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx"))); REG_WR(bp, addr, val); + /* + * Ensure that HC_CONFIG is written before leading/trailing edge config + */ + mmiowb(); + barrier(); if (CHIP_IS_E1H(bp)) { /* init leading/trailing edge */ @@ -666,6 +671,9 @@ static void bnx2x_int_enable(struct bnx2x *bp) REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val); REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val); } + + /* Make sure that interrupts are indeed enabled from here on */ + mmiowb(); } static void bnx2x_int_disable(struct bnx2x *bp) @@ -739,6 +747,10 @@ static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id, DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n", (*(u32 *)&igu_ack), hc_addr); REG_WR(bp, hc_addr, (*(u32 *)&igu_ack)); + + /* Make sure that ACK is written */ + mmiowb(); + barrier(); } static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp) @@ -2429,9 +2441,14 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, bp->spq_prod_idx++; } + /* Make sure that BD data is updated before writing the producer */ + wmb(); + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func), bp->spq_prod_idx); + mmiowb(); + spin_unlock_bh(&bp->spq_lock); return 0; } -- cgit v0.10.2 From e15107065d073714dc47cf6b80c8bf5eea1bf18b Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:41 +0000 Subject: bnx2x: SMP-safe inter_sem Signed-off-by: Vlad Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index f20df6d..18c3803 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -706,6 +706,8 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw) /* disable interrupt handling */ atomic_inc(&bp->intr_sem); + smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */ + if (disable_hw) /* prevent the HW from sending interrupts */ bnx2x_int_disable(bp); @@ -6642,7 +6644,12 @@ static void bnx2x_napi_disable(struct bnx2x *bp) static void bnx2x_netif_start(struct bnx2x *bp) { - if (atomic_dec_and_test(&bp->intr_sem)) { + int intr_sem; + + intr_sem = atomic_dec_and_test(&bp->intr_sem); + smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */ + + if (intr_sem) { if (netif_running(bp->dev)) { bnx2x_napi_enable(bp); bnx2x_int_enable(bp); @@ -8229,6 +8236,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) /* Disable interrupt handling until HW is initialized */ atomic_set(&bp->intr_sem, 1); + smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */ mutex_init(&bp->port.phy_mutex); -- cgit v0.10.2 From 5316bc0b9adbefe24f149b12caeddc30df6f04e1 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:43 +0000 Subject: bnx2x: Update vlan_features As noted by Or Gerlitz , the vlan_features was not updated Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 18c3803..b404a9b 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -9310,9 +9310,17 @@ static int bnx2x_set_tso(struct net_device *dev, u32 data) if (data) { dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); dev->features |= NETIF_F_TSO6; +#ifdef BCM_VLAN + dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->vlan_features |= NETIF_F_TSO6; +#endif } else { dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); dev->features &= ~NETIF_F_TSO6; +#ifdef BCM_VLAN + dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->vlan_features &= ~NETIF_F_TSO6; +#endif } return 0; @@ -11143,12 +11151,19 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, dev->features |= NETIF_F_HW_CSUM; if (bp->flags & USING_DAC_FLAG) dev->features |= NETIF_F_HIGHDMA; + dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->features |= NETIF_F_TSO6; #ifdef BCM_VLAN dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG); + + dev->vlan_features |= NETIF_F_SG; + dev->vlan_features |= NETIF_F_HW_CSUM; + if (bp->flags & USING_DAC_FLAG) + dev->vlan_features |= NETIF_F_HIGHDMA; + dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->vlan_features |= NETIF_F_TSO6; #endif - dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->features |= NETIF_F_TSO6; return 0; -- cgit v0.10.2 From 4d295db0efd2ccf06edb7a45ad885b40c56b7161 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:47 +0000 Subject: bnx2x: Supporting BCM8727 PHY Adding support for BCM8727 - a dual port SFP+ PHY. That includes verification of the optic module vendor and part number - the list of approved modules resides on the nvram and the module is verified by the FW. Since not all users would like to use this verification feature, it can be disabled. The default behavior is to issue a warning if the module is not approved, but still allow using it - but it is also possible to disable the link if the module is not approved. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 85a737c..8b6e83d 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -1006,6 +1006,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port); int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); +u32 bnx2x_fw_command(struct bnx2x *bp, u32 command); static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, int wait) diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h index 41c6dcb..7de83c4 100644 --- a/drivers/net/bnx2x_hsi.h +++ b/drivers/net/bnx2x_hsi.h @@ -248,6 +248,8 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726 0x00000600 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481 0x00000700 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101 0x00000800 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 0x00000900 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC 0x00000a00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00 @@ -358,10 +360,16 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */ #define PORT_FEATURE_MBA_ENABLED 0x02000000 #define PORT_FEATURE_MFW_ENABLED 0x04000000 - /* Check the optic vendor via i2c before allowing it to be used by - SW */ -#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLED 0x00000000 -#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED 0x08000000 + /* Reserved bits: 28-29 */ + /* Check the optic vendor via i2c against a list of approved modules + in a separate nvram image */ +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK 0xE0000000 +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_SHIFT 29 +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT 0x00000000 +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER 0x20000000 +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_WARNING_MSG 0x40000000 +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN 0x60000000 + u32 wol_config; /* Default is used when driver sets to "auto" mode */ @@ -657,6 +665,12 @@ struct drv_func_mb { #define DRV_MSG_CODE_GET_UPGRADE_KEY 0x81000000 #define DRV_MSG_CODE_GET_MANUF_KEY 0x82000000 #define DRV_MSG_CODE_LOAD_L2B_PRAM 0x90000000 + /* + * The optic module verification commands requris bootcode + * v5.0.6 or later + */ +#define DRV_MSG_CODE_VRFY_OPT_MDL 0xa0000000 +#define REQ_BC_VER_4_VRFY_OPT_MDL 0x00050006 #define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000 #define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000 @@ -691,6 +705,9 @@ struct drv_func_mb { #define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE 0x90220000 #define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE 0x90230000 #define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE 0x90240000 +#define FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS 0xa0100000 +#define FW_MSG_CODE_VRFY_OPT_MDL_INVLD_IMG 0xa0200000 +#define FW_MSG_CODE_VRFY_OPT_MDL_UNAPPROVED 0xa0300000 #define FW_MSG_CODE_LIC_CHALLENGE 0xff010000 #define FW_MSG_CODE_LIC_RESPONSE 0xff020000 diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index ed648ac..b9c85a2 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -139,21 +139,26 @@ #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21 + +#define SFP_EEPROM_COMP_CODE_ADDR 0x3 + #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4) + #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5) + #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6) + #define SFP_EEPROM_FC_TX_TECH_ADDR 0x8 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8 -#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14 -#define SFP_EEPROM_VENDOR_NAME_SIZE 16 + #define SFP_EEPROM_OPTIONS_ADDR 0x40 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1 #define SFP_EEPROM_OPTIONS_SIZE 2 -#define SFP_MODULE_TYPE_UNKNOWN 0x0 -#define SFP_MODULE_TYPE_LC 0x1 -#define SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE 0x2 -#define SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE 0x3 +#define EDC_MODE_LINEAR 0x0022 +#define EDC_MODE_LIMITING 0x0044 +#define EDC_MODE_PASSIVE_DAC 0x0055 + + -#define SFP_LIMITING_MODE_VALUE 0x0044 /**********************************************************/ /* INTERFACE */ /**********************************************************/ @@ -793,6 +798,7 @@ static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port) switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: /* All MDC/MDIO is directed through single EMAC */ if (REG_RD(bp, NIG_REG_PORT_SWAP)) emac_base = GRCBASE_EMAC0; @@ -1887,6 +1893,10 @@ static void bnx2x_ext_phy_reset(struct link_params *params, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040); break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: /* Restore normal power mode*/ @@ -2171,13 +2181,15 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params) } -static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port, - u8 ext_phy_addr, u32 shmem_base) +static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port, + u8 ext_phy_addr, + u32 ext_phy_type, + u32 shmem_base) { /* Boot port from external ROM */ /* EDC grst */ bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, @@ -2185,21 +2197,21 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port, /* ucode reboot and rst */ bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x008c); bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL1, 0x0001); /* Reset internal microprocessor */ bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, @@ -2207,7 +2219,7 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port, /* Release srst bit */ bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, @@ -2218,17 +2230,36 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port, /* Clear ser_boot_ctl bit */ bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL1, 0x0000); bnx2x_save_bcm_spirom_ver(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, shmem_base); } +static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port, + u8 ext_phy_addr, + u32 shmem_base) +{ + bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + shmem_base); +} + +static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port, + u8 ext_phy_addr, + u32 shmem_base) +{ + bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + shmem_base); + +} + static void bnx2x_bcm8726_external_rom_boot(struct link_params *params) { struct bnx2x *bp = params->bp; @@ -2258,9 +2289,10 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params) MDIO_PMA_REG_GEN_CTRL, MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET); + /* Set PLL register value to be same like in P13 ver */ bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_GEN_CTRL2, + MDIO_PMA_REG_PLL_CTRL, 0x73A0); /* Clear soft reset. @@ -2285,15 +2317,16 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params) params->shmem_base); } -static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port, - u8 ext_phy_addr, u8 tx_en) +static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port, + u32 ext_phy_type, u8 ext_phy_addr, + u8 tx_en) { u16 val; DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n", tx_en, port); /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/ bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, @@ -2305,18 +2338,19 @@ static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port, val |= (1<<15); bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, val); } - -static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, - u8 byte_cnt, u8 *o_buf) { +static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params, + u16 addr, u8 byte_cnt, u8 *o_buf) +{ struct bnx2x *bp = params->bp; - u16 val, i; + u16 val = 0; + u16 i; u8 port = params->port; u8 ext_phy_addr = ((params->ext_phy_config & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> @@ -2332,7 +2366,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT, + MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT, (byte_cnt | 0xa000)); /* Set the read command address */ @@ -2340,7 +2374,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR, + MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR, addr); /* Activate read command */ @@ -2348,7 +2382,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8726_TWO_WIRE_CTRL, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, 0x2c0f); /* Wait up to 500us for command complete status */ @@ -2357,18 +2391,18 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val); - if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) == - MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) break; udelay(5); } - if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) != - MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) { + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) != + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) { DP(NETIF_MSG_LINK, "Got bad status 0x%x when reading from SFP+ EEPROM\n", - (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK)); + (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK)); return -EINVAL; } @@ -2387,29 +2421,147 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val); - if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) == - MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE) + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) + return 0;; + msleep(1); + } + return -EINVAL; +} + +static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params, + u16 addr, u8 byte_cnt, u8 *o_buf) +{ + struct bnx2x *bp = params->bp; + u16 val, i; + u8 port = params->port; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + + if (byte_cnt > 16) { + DP(NETIF_MSG_LINK, "Reading from eeprom is" + " is limited to 0xf\n"); + return -EINVAL; + } + + /* Need to read from 1.8000 to clear it */ + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, + &val); + + /* Set the read command byte count */ + bnx2x_cl45_write(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT, + ((byte_cnt < 2) ? 2 : byte_cnt)); + + /* Set the read command address */ + bnx2x_cl45_write(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR, + addr); + /* Set the destination address */ + bnx2x_cl45_write(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0x8004, + MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF); + + /* Activate read command */ + bnx2x_cl45_write(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, + 0x8002); + /* Wait appropriate time for two-wire command to finish before + polling the status register */ + msleep(1); + + /* Wait up to 500us for command complete status */ + for (i = 0; i < 100; i++) { + bnx2x_cl45_read(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) + break; + udelay(5); + } + + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) != + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) { + DP(NETIF_MSG_LINK, + "Got bad status 0x%x when reading from SFP+ EEPROM\n", + (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK)); + return -EINVAL; + } + + /* Read the buffer */ + for (i = 0; i < byte_cnt; i++) { + bnx2x_cl45_read(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val); + o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK); + } + + for (i = 0; i < 100; i++) { + bnx2x_cl45_read(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) return 0;; msleep(1); } + return -EINVAL; } +u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, + u8 byte_cnt, u8 *o_buf) +{ + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) + return bnx2x_8726_read_sfp_module_eeprom(params, addr, + byte_cnt, o_buf); + else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) + return bnx2x_8727_read_sfp_module_eeprom(params, addr, + byte_cnt, o_buf); + return -EINVAL; +} -static u8 bnx2x_get_sfp_module_type(struct link_params *params, - u8 *module_type) +static u8 bnx2x_get_edc_mode(struct link_params *params, + u16 *edc_mode) { struct bnx2x *bp = params->bp; - u8 val; - *module_type = SFP_MODULE_TYPE_UNKNOWN; + u8 val, check_limiting_mode = 0; + *edc_mode = EDC_MODE_LIMITING; /* First check for copper cable */ if (bnx2x_read_sfp_module_eeprom(params, SFP_EEPROM_CON_TYPE_ADDR, 1, &val) != 0) { - DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM"); + DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n"); return -EINVAL; } @@ -2433,13 +2585,13 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params, if (copper_module_type & SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) { DP(NETIF_MSG_LINK, "Active Copper cable detected\n"); - *module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE; + check_limiting_mode = 1; } else if (copper_module_type & SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) { DP(NETIF_MSG_LINK, "Passive Copper" " cable detected\n"); - *module_type = - SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE; + *edc_mode = + EDC_MODE_PASSIVE_DAC; } else { DP(NETIF_MSG_LINK, "Unknown copper-cable-" "type 0x%x !!!\n", copper_module_type); @@ -2449,7 +2601,7 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params, } case SFP_EEPROM_CON_TYPE_VAL_LC: DP(NETIF_MSG_LINK, "Optic module detected\n"); - *module_type = SFP_MODULE_TYPE_LC; + check_limiting_mode = 1; break; default: @@ -2457,89 +2609,92 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params, val); return -EINVAL; } + + if (check_limiting_mode) { + u8 options[SFP_EEPROM_OPTIONS_SIZE]; + if (bnx2x_read_sfp_module_eeprom(params, + SFP_EEPROM_OPTIONS_ADDR, + SFP_EEPROM_OPTIONS_SIZE, + options) != 0) { + DP(NETIF_MSG_LINK, "Failed to read Option" + " field from module EEPROM\n"); + return -EINVAL; + } + if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK)) + *edc_mode = EDC_MODE_LINEAR; + else + *edc_mode = EDC_MODE_LIMITING; + } + DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode); return 0; } - /* This function read the relevant field from the module ( SFP+ ), and verify it is compliant with this board */ -static u8 bnx2x_verify_sfp_module(struct link_params *params, - u8 module_type) +static u8 bnx2x_verify_sfp_module(struct link_params *params) { struct bnx2x *bp = params->bp; - u8 *str_p, *tmp_buf; - u16 i; - -#define COMPLIANCE_STR_CNT 6 - u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT", - "FINISAR CORP. ", "Amphenol"}; - u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE]; - /* Passive Copper cables are allowed to participate, - since the module is hardwired to the copper cable */ - - if (!(params->feature_config_flags & - FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) { + u32 val; + u32 fw_resp; + char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1]; + char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1]; + + val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port].config)); + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) { DP(NETIF_MSG_LINK, "NOT enforcing module verification\n"); return 0; } - if (module_type != SFP_MODULE_TYPE_LC) { - DP(NETIF_MSG_LINK, "No need to verify copper cable\n"); + /* Ask the FW to validate the module */ + if (!(params->feature_config_flags & + FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) { + DP(NETIF_MSG_LINK, "FW does not support OPT MDL " + "verification\n"); + return -EINVAL; + } + + fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL); + if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) { + DP(NETIF_MSG_LINK, "Approved module\n"); return 0; } - /* In case of non copper cable or Active copper cable, - verify that the SFP+ module is compliant with this board*/ + /* format the warning message */ if (bnx2x_read_sfp_module_eeprom(params, SFP_EEPROM_VENDOR_NAME_ADDR, SFP_EEPROM_VENDOR_NAME_SIZE, - buf) != 0) { - DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from" - " module EEPROM\n"); - return -EINVAL; - } - for (i = 0; i < COMPLIANCE_STR_CNT; i++) { - str_p = compliance_str[i]; - tmp_buf = buf; - while (*str_p) { - if ((u8)(*tmp_buf) != (u8)(*str_p)) - break; - str_p++; - tmp_buf++; - } + (u8 *)vendor_name)) + vendor_name[0] = '\0'; + else + vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0'; + if (bnx2x_read_sfp_module_eeprom(params, + SFP_EEPROM_PART_NO_ADDR, + SFP_EEPROM_PART_NO_SIZE, + (u8 *)vendor_pn)) + vendor_pn[0] = '\0'; + else + vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0'; - if (!(*str_p)) { - DP(NETIF_MSG_LINK, "SFP+ Module verified, " - "index=%x\n", i); - return 0; - } - } - DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n"); + printk(KERN_INFO PFX "Warning: " + "Unqualified SFP+ module " + "detected on %s, Port %d from %s part number %s\n" + , bp->dev->name, params->port, + vendor_name, vendor_pn); return -EINVAL; } - static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params, - u8 module_type) + u16 edc_mode) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 options[SFP_EEPROM_OPTIONS_SIZE]; - u8 limiting_mode; u8 ext_phy_addr = ((params->ext_phy_config & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); u16 cur_limiting_mode; - if (bnx2x_read_sfp_module_eeprom(params, - SFP_EEPROM_OPTIONS_ADDR, - SFP_EEPROM_OPTIONS_SIZE, - options) != 0) { - DP(NETIF_MSG_LINK, "Failed to read Option field from" - " module EEPROM\n"); - return -EINVAL; - } - limiting_mode = !(options[0] & - SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK); bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, @@ -2550,26 +2705,23 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params, DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n", cur_limiting_mode); - if (limiting_mode && - (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) { + if (edc_mode == EDC_MODE_LIMITING) { DP(NETIF_MSG_LINK, - "Module options = 0x%x.Setting LIMITING MODE\n", - options[0]); + "Setting LIMITING MODE\n"); bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER2, - SFP_LIMITING_MODE_VALUE); + EDC_MODE_LIMITING); } else { /* LRM mode ( default )*/ - DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n", - options[0]); + DP(NETIF_MSG_LINK, "Setting LRM MODE\n"); /* Changing to LRM mode takes quite few seconds. So do it only if current mode is limiting ( default is LRM )*/ - if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE) + if (cur_limiting_mode != EDC_MODE_LIMITING) return 0; bnx2x_cl45_write(bp, port, @@ -2600,6 +2752,56 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params, return 0; } +static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params, + u16 edc_mode) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u16 phy_identifier; + u16 rom_ver2_val; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + &phy_identifier); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + (phy_identifier & ~(1<<9))); + + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + &rom_ver2_val); + /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff)); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + (phy_identifier | (1<<9))); + + return 0; +} + + static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params) { u8 val; @@ -2619,61 +2821,114 @@ static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params) return -EINVAL; } +static void bnx2x_8727_power_module(struct bnx2x *bp, + struct link_params *params, + u8 ext_phy_addr, u8 is_power_up) { + /* Make sure GPIOs are not using for LED mode */ + u16 val; + u8 port = params->port; + /* + * In the GPIO register, bit 4 is use to detemine if the GPIOs are + * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for + * output + * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0 + * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1 + * where the 1st bit is the over-current(only input), and 2nd bit is + * for power( only output ) + */ + + /* + * In case of NOC feature is disabled and power is up, set GPIO control + * as input to enable listening of over-current indication + */ + + if (!(params->feature_config_flags & + FEATURE_CONFIG_BCM8727_NOC) && is_power_up) + val = (1<<4); + else + /* + * Set GPIO control to OUTPUT, and set the power bit + * to according to the is_power_up + */ + val = ((!(is_power_up)) << 1); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_GPIO_CTRL, + val); +} + static u8 bnx2x_sfp_module_detection(struct link_params *params) { struct bnx2x *bp = params->bp; - u8 module_type; + u16 edc_mode; + u8 rc = 0; u8 ext_phy_addr = ((params->ext_phy_config & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); - - if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) { - DP(NETIF_MSG_LINK, "Module detection is not required " - "for this phy\n"); - return 0; - } + u32 val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port].config)); DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n", params->port); - if (bnx2x_get_sfp_module_type(params, - &module_type) != 0) { + if (bnx2x_get_edc_mode(params, &edc_mode) != 0) { DP(NETIF_MSG_LINK, "Failed to get valid module type\n"); - if (!(params->feature_config_flags & - FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) { - /* In case module detection is disabled, it trys to - link up. The issue that can happen here is LRM / - LIMITING mode which set according to the module-type*/ - DP(NETIF_MSG_LINK, "Unable to read module-type." - "Probably due to Bit Stretching." - " Proceeding...\n"); - } else { - return -EINVAL; - } - } else if (bnx2x_verify_sfp_module(params, module_type) != + return -EINVAL; + } else if (bnx2x_verify_sfp_module(params) != 0) { /* check SFP+ module compatibility */ DP(NETIF_MSG_LINK, "Module verification failed!!\n"); + rc = -EINVAL; /* Turn on fault module-detected led */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, MISC_REGISTERS_GPIO_HIGH, params->port); - return -EINVAL; + if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) && + ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) { + /* Shutdown SFP+ module */ + DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n"); + bnx2x_8727_power_module(bp, params, + ext_phy_addr, 0); + return rc; + } + } else { + /* Turn off fault module-detected led */ + DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n"); + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, + MISC_REGISTERS_GPIO_LOW, + params->port); } - /* Turn off fault module-detected led */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_LOW, - params->port); + /* power up the SFP module */ + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) + bnx2x_8727_power_module(bp, params, ext_phy_addr, 1); - /* Check and set limiting mode / LRM mode */ - bnx2x_bcm8726_set_limiting_mode(params, module_type); + /* Check and set limiting mode / LRM mode on 8726. + On 8727 it is done automatically */ + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) + bnx2x_bcm8726_set_limiting_mode(params, edc_mode); + else + bnx2x_bcm8727_set_limiting_mode(params, edc_mode); + /* + * Enable transmit for this module if the module is approved, or + * if unapproved modules should also enable the Tx laser + */ + if (rc == 0 || + (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) != + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + bnx2x_sfp_set_transmitter(bp, params->port, + ext_phy_type, ext_phy_addr, 1); + else + bnx2x_sfp_set_transmitter(bp, params->port, + ext_phy_type, ext_phy_addr, 0); - /* Enable transmit for this module */ - bnx2x_bcm8726_set_transmitter(bp, params->port, - ext_phy_addr, 1); - return 0; + return rc; } void bnx2x_handle_module_detect_int(struct link_params *params) @@ -2696,8 +2951,8 @@ void bnx2x_handle_module_detect_int(struct link_params *params) MISC_REGISTERS_GPIO_INT_OUTPUT_CLR, port); - if (bnx2x_wait_for_sfp_module_initialized(params) - == 0) + if (bnx2x_wait_for_sfp_module_initialized(params) == + 0) bnx2x_sfp_module_detection(params); else DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n"); @@ -2705,13 +2960,22 @@ void bnx2x_handle_module_detect_int(struct link_params *params) u8 ext_phy_addr = ((params->ext_phy_config & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u32 ext_phy_type = + XGXS_EXT_PHY_TYPE(params->ext_phy_config); + u32 val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port]. + config)); + bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3, MISC_REGISTERS_GPIO_INT_OUTPUT_SET, port); /* Module was plugged out. */ /* Disable transmit for this module */ - bnx2x_bcm8726_set_transmitter(bp, params->port, - ext_phy_addr, 0); + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + bnx2x_sfp_set_transmitter(bp, params->port, + ext_phy_type, ext_phy_addr, 0); } } @@ -3160,6 +3424,9 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) driver is loaded, it reset all registers, including the transmitter */ bnx2x_sfp_module_detection(params); + + /* Set Flow control */ + bnx2x_ext_phy_set_pause(params, vars); if (params->req_line_speed == SPEED_1000) { DP(NETIF_MSG_LINK, "Setting 1G force\n"); bnx2x_cl45_write(bp, params->port, ext_phy_type, @@ -3450,43 +3717,224 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ((val & (1<<7)) > 0)); break; } - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: { - u16 fw_ver1, fw_ver2; - DP(NETIF_MSG_LINK, - "Setting the SFX7101 LASI indication\n"); + u16 tmp1; + u16 rx_alarm_ctrl_val; + u16 lasi_ctrl_val; + /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */ + + u16 mod_abs; + rx_alarm_ctrl_val = (1<<2) | (1<<5) ; + lasi_ctrl_val = 0x0004; + + DP(NETIF_MSG_LINK, "Initializing BCM8727\n"); + /* enable LASI */ bnx2x_cl45_write(bp, params->port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_LASI_CTRL, 0x1); - DP(NETIF_MSG_LINK, - "Setting the SFX7101 LED to blink on traffic\n"); + MDIO_PMA_REG_RX_ALARM_CTRL, + rx_alarm_ctrl_val); + bnx2x_cl45_write(bp, params->port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_7107_LED_CNTL, (1<<3)); + MDIO_PMA_REG_LASI_CTRL, + lasi_ctrl_val); - bnx2x_ext_phy_set_pause(params, vars); - /* Restart autoneg */ + /* Initially configure MOD_ABS to interrupt when + module is presence( bit 8) */ bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, - MDIO_AN_DEVAD, - MDIO_AN_REG_CTRL, &val); - val |= 0x200; + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs); + /* Set EDC off by setting OPTXLOS signal input to low + (bit 9). + When the EDC is off it locks onto a reference clock and + avoids becoming 'lost'.*/ + mod_abs &= ~((1<<8) | (1<<9)); bnx2x_cl45_write(bp, params->port, ext_phy_type, ext_phy_addr, - MDIO_AN_DEVAD, - MDIO_AN_REG_CTRL, val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); - /* Save spirom version */ - bnx2x_cl45_read(bp, params->port, ext_phy_type, - ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_7101_VER1, &fw_ver1); + /* Make MOD_ABS give interrupt on change */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_OPT_CTRL, + &val); + val |= (1<<12); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_OPT_CTRL, + val); + + /* Set 8727 GPIOs to input to allow reading from the + 8727 GPIO0 status which reflect SFP+ module + over-current */ + + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_OPT_CTRL, + &val); + val &= 0xff8f; /* Reset bits 4-6 */ + bnx2x_cl45_write(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_OPT_CTRL, + val); + + bnx2x_8727_power_module(bp, params, ext_phy_addr, 1); + bnx2x_bcm8073_set_xaui_low_power_mode(params); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_M8051_MSGOUT_REG, + &tmp1); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &tmp1); + + /* Set option 1G speed */ + if (params->req_line_speed == SPEED_1000) { + + DP(NETIF_MSG_LINK, "Setting 1G force\n"); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0x40); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_10G_CTRL2, 0xD); + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_10G_CTRL2, &tmp1); + DP(NETIF_MSG_LINK, "1.7 = 0x%x \n", tmp1); + + } else if ((params->req_line_speed == + SPEED_AUTO_NEG) && + ((params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) { + + DP(NETIF_MSG_LINK, "Setting 1G clause37 \n"); + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_AN_DEVAD, + MDIO_PMA_REG_8727_MISC_CTRL, 0); + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_AN, 0x1300); + } else { + /* Since the 8727 has only single reset pin, + need to set the 10G registers although it is + default */ + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_AN_DEVAD, + MDIO_AN_REG_CTRL, 0x0020); + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_AN_DEVAD, + 0x7, 0x0100); + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0x2040); + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_PMA_DEVAD, + MDIO_PMA_REG_10G_CTRL2, 0x0008); + } + + /* Set 2-wire transfer rate to 400Khz since 100Khz + is not operational */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR, + 0xa101); + + /* Set TX PreEmphasis if needed */ + if ((params->feature_config_flags & + FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) { + DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x," + "TX_CTRL2 0x%x\n", + params->xgxs_config_tx[0], + params->xgxs_config_tx[1]); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_TX_CTRL1, + params->xgxs_config_tx[0]); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_TX_CTRL2, + params->xgxs_config_tx[1]); + } + + break; + } + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + { + u16 fw_ver1, fw_ver2; + DP(NETIF_MSG_LINK, + "Setting the SFX7101 LASI indication\n"); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_CTRL, 0x1); + DP(NETIF_MSG_LINK, + "Setting the SFX7101 LED to blink on traffic\n"); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7107_LED_CNTL, (1<<3)); + + bnx2x_ext_phy_set_pause(params, vars); + /* Restart autoneg */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CTRL, &val); + val |= 0x200; + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CTRL, val); + + /* Save spirom version */ + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_VER1, &fw_ver1); bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, @@ -3561,6 +4009,99 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) return rc; } +static void bnx2x_8727_handle_mod_abs(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 mod_abs, rx_alarm_status; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u32 val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port]. + config)); + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs); + if (mod_abs & (1<<8)) { + + /* Module is absent */ + DP(NETIF_MSG_LINK, "MOD_ABS indication " + "show module is absent\n"); + + /* 1. Set mod_abs to detect next module + presence event + 2. Set EDC off by setting OPTXLOS signal input to low + (bit 9). + When the EDC is off it locks onto a reference clock and + avoids becoming 'lost'.*/ + mod_abs &= ~((1<<8)|(1<<9)); + bnx2x_cl45_write(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); + + /* Clear RX alarm since it stays up as long as + the mod_abs wasn't changed */ + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &rx_alarm_status); + + } else { + /* Module is present */ + DP(NETIF_MSG_LINK, "MOD_ABS indication " + "show module is present\n"); + /* First thing, disable transmitter, + and if the module is ok, the + module_detection will enable it*/ + + /* 1. Set mod_abs to detect next module + absent event ( bit 8) + 2. Restore the default polarity of the OPRXLOS signal and + this signal will then correctly indicate the presence or + absence of the Rx signal. (bit 9) */ + mod_abs |= ((1<<8)|(1<<9)); + bnx2x_cl45_write(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); + + /* Clear RX alarm since it stays up as long as + the mod_abs wasn't changed. This is need to be done + before calling the module detection, otherwise it will clear + the link update alarm */ + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &rx_alarm_status); + + + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + bnx2x_sfp_set_transmitter(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, 0); + + if (bnx2x_wait_for_sfp_module_initialized(params) + == 0) + bnx2x_sfp_module_detection(params); + else + DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n"); + } + + DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", + rx_alarm_status); + /* No need to check link status in case of + module plugged in/out */ +} + static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, struct link_vars *vars) @@ -3602,8 +4143,19 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd); - DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd); - ext_phy_link_up = (rx_sd & 0x1); + + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + 1, + 0xc809, &val1); + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + 1, + 0xc809, &val1); + + DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1); + ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) + && ((val1 & (1<<8)) == 0)); if (ext_phy_link_up) vars->line_speed = SPEED_10000; break; @@ -3678,8 +4230,160 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, else vars->line_speed = SPEED_10000; } + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + { + u16 link_status = 0; + u16 rx_alarm_status; + /* Check the LASI */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &rx_alarm_status); + + DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", + rx_alarm_status); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_STATUS, &val1); + + DP(NETIF_MSG_LINK, + "8727 LASI status 0x%x\n", + val1); + + /* Clear MSG-OUT */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_M8051_MSGOUT_REG, + &val1); + + /* + * If a module is present and there is need to check + * for over current + */ + if (!(params->feature_config_flags & + FEATURE_CONFIG_BCM8727_NOC) && + !(rx_alarm_status & (1<<5))) { + /* Check over-current using 8727 GPIO0 input*/ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_GPIO_CTRL, + &val1); + + if ((val1 & (1<<8)) == 0) { + DP(NETIF_MSG_LINK, "8727 Power fault" + " has been detected on port" + " %d\n", params->port); + printk(KERN_ERR PFX "Error: Power" + " fault on %s Port %d has" + " been detected and the" + " power to that SFP+ module" + " has been removed to prevent" + " failure of the card. Please" + " remove the SFP+ module and" + " restart the system to clear" + " this error.\n" + , bp->dev->name, params->port); + /* + * Disable all RX_ALARMs except for + * mod_abs + */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM_CTRL, + (1<<5)); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + &val1); + /* Wait for module_absent_event */ + val1 |= (1<<8); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + val1); + /* Clear RX alarm */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, + &rx_alarm_status); + break; + } + } /* Over current check */ + + /* When module absent bit is set, check module */ + if (rx_alarm_status & (1<<5)) { + bnx2x_8727_handle_mod_abs(params); + /* Enable all mod_abs and link detection bits */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM_CTRL, + ((1<<5) | (1<<2))); + } + + /* If transmitter is disabled, + ignore false link up indication */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + &val1); + if (val1 & (1<<15)) { + DP(NETIF_MSG_LINK, "Tx is disabled\n"); + ext_phy_link_up = 0; + break; + } + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_SPEED_LINK_STATUS, + &link_status); + /* Bits 0..2 --> speed detected, + bits 13..15--> link is down */ + if ((link_status & (1<<2)) && + (!(link_status & (1<<15)))) { + ext_phy_link_up = 1; + vars->line_speed = SPEED_10000; + } else if ((link_status & (1<<0)) && + (!(link_status & (1<<13)))) { + ext_phy_link_up = 1; + vars->line_speed = SPEED_1000; + DP(NETIF_MSG_LINK, + "port %x: External link" + " up in 1G\n", params->port); + } else { + ext_phy_link_up = 0; + DP(NETIF_MSG_LINK, + "port %x: External link" + " is down\n", params->port); + } break; + } + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: { @@ -4241,6 +4945,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: @@ -4842,10 +5547,6 @@ static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr) PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001); - - /* Disable Transmitter */ - bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0); - } u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, @@ -4858,6 +5559,11 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, u32 chip_id = params->chip_id; u8 port = params->port; u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); + u32 val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port]. + config)); + /* disable attentions */ vars->link_status = 0; @@ -4892,6 +5598,21 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + { + + /* Disable Transmitter */ + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + bnx2x_sfp_set_transmitter(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, 0); + break; + } case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: DP(NETIF_MSG_LINK, "Setting 8073 port %d into " "low power mode\n", @@ -5216,6 +5937,74 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) } +static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) +{ + u8 ext_phy_addr[PORT_MAX]; + s8 port; + u32 swap_val, swap_override; + DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n"); + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + + bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override)); + msleep(5); + + /* PART1 - Reset both phys */ + for (port = PORT_MAX - 1; port >= PORT_0; port--) { + /* Extract the ext phy address for the port */ + u32 ext_phy_config = REG_RD(bp, shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].external_phy_config)); + + /* disable attentions */ + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + ext_phy_addr[port] = ((ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + + /* Reset the phy */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + 1<<15); + } + + /* Add delay of 150ms after reset */ + msleep(150); + + /* PART2 - Download firmware to both phys */ + for (port = PORT_MAX - 1; port >= PORT_0; port--) { + u16 fw_ver1; + + bnx2x_bcm8727_external_rom_boot(bp, port, + ext_phy_addr[port], shmem_base); + + bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER1, &fw_ver1); + if (fw_ver1 == 0 || fw_ver1 == 0x4321) { + DP(NETIF_MSG_LINK, + "bnx2x_8073_common_init_phy port %x:" + "Download failed. fw version = 0x%x\n", + port, fw_ver1); + return -EINVAL; + } + + } + + + + return 0; +} + static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) { @@ -5274,6 +6063,12 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base) rc = bnx2x_8073_common_init_phy(bp, shmem_base); break; } + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC: + rc = bnx2x_8727_common_init_phy(bp, shmem_base); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: /* GPIO1 affects both ports, so there's need to pull it for single port alone */ diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index 19a866d..d25ef45 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -39,7 +39,13 @@ #define SPEED_15000 15000 #define SPEED_16000 16000 - +#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14 +#define SFP_EEPROM_VENDOR_NAME_SIZE 16 +#define SFP_EEPROM_VENDOR_OUI_ADDR 0x25 +#define SFP_EEPROM_VENDOR_OUI_SIZE 3 +#define SFP_EEPROM_PART_NO_ADDR 0x28 +#define SFP_EEPROM_PART_NO_SIZE 16 +#define PWR_FLT_ERR_MSG_LEN 250 /***********************************************************/ /* Structs */ /***********************************************************/ @@ -91,7 +97,8 @@ struct link_params { u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */ u32 feature_config_flags; #define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0) -#define FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED (2<<0) +#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2) +#define FEATURE_CONFIG_BCM8727_NOC (1<<3) /* Device pointer passed to all callback functions */ struct bnx2x *bp; }; @@ -181,4 +188,7 @@ u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars); u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base); +u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, + u8 byte_cnt, u8 *o_buf); + #endif /* BNX2X_LINK_H */ diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index b404a9b..197dbe4 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -2637,7 +2637,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) { int port = BP_PORT(bp); int reg_offset; - u32 val; + u32 val, swap_val, swap_override; reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); @@ -2661,6 +2661,17 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) MISC_REGISTERS_GPIO_OUTPUT_LOW, port); break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + /* The PHY reset is controlled by GPIO 1 */ + /* fake the port number to cancel the swap done in + set_gpio() */ + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + port = (swap_val && swap_override) ^ 1; + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW, port); + break; + default: break; } @@ -5562,6 +5573,8 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp) ((phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) || (phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) || + (phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481)); } @@ -5812,6 +5825,7 @@ static int bnx2x_init_common(struct bnx2x *bp) case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: bp->port.need_hw_lock = 1; break; @@ -6050,10 +6064,15 @@ static int bnx2x_init_port(struct bnx2x *bp) break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: /* add SPIO 5 to group 0 */ - val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + { + u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + val = REG_RD(bp, reg_addr); val |= AEU_INPUTS_ATTN_BITS_SPIO5; - REG_WR(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, val); + REG_WR(bp, reg_addr, val); + } break; default: @@ -6203,7 +6222,7 @@ init_hw_err: } /* send the MCP a request, block until there is a reply */ -static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) +u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) { int func = BP_FUNC(bp); u32 seq = ++bp->fw_seq; @@ -7676,6 +7695,9 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) BNX2X_ERR("This driver needs bc_ver %X but found %X," " please upgrade BC\n", BNX2X_BC_VER, val); } + bp->link_params.feature_config_flags |= + (val >= REQ_BC_VER_4_VRFY_OPT_MDL) ? + FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0; if (BP_E1HVN(bp) == 0) { pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc); @@ -7836,6 +7858,18 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp, SUPPORTED_Asym_Pause); break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n", + ext_phy_type); + + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n", ext_phy_type); @@ -8099,6 +8133,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) bp->link_params.ext_phy_config = SHMEM_RD(bp, dev_info.port_hw_config[port].external_phy_config); + /* BCM8727_NOC => BCM8727 no over current */ + if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) { + bp->link_params.ext_phy_config &= + ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; + bp->link_params.ext_phy_config |= + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727; + bp->link_params.feature_config_flags |= + FEATURE_CONFIG_BCM8727_NOC; + } + bp->link_params.speed_cap_mask = SHMEM_RD(bp, dev_info.port_hw_config[port].speed_capability_mask); @@ -8119,17 +8164,10 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff); } - config = SHMEM_RD(bp, dev_info.port_feature_config[port].config); - if (config & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED) - bp->link_params.feature_config_flags |= - FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED; - else - bp->link_params.feature_config_flags &= - ~FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED; - /* If the device is capable of WoL, set the default state according * to the HW */ + config = SHMEM_RD(bp, dev_info.port_feature_config[port].config); bp->wol = (!(bp->flags & NO_WOL_FLAG) && (config & PORT_FEATURE_WOL_ENABLED)); @@ -8139,8 +8177,8 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) bp->link_params.ext_phy_config, bp->link_params.speed_cap_mask, bp->port.link_config); - bp->link_params.switch_cfg = (bp->port.link_config & - PORT_FEATURE_CONNECTED_SWITCH_MASK); + bp->link_params.switch_cfg |= (bp->port.link_config & + PORT_FEATURE_CONNECTED_SWITCH_MASK); bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg); bnx2x_link_settings_requested(bp); @@ -8336,6 +8374,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: cmd->port = PORT_FIBRE; break; diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 6d77730..d771168 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -5845,25 +5845,33 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_PMA_REG_ROM_VER2 0xca1a #define MDIO_PMA_REG_EDC_FFE_MAIN 0xca1b #define MDIO_PMA_REG_PLL_BANDWIDTH 0xca1d -#define MDIO_PMA_REG_GEN_CTRL2 0xca1e +#define MDIO_PMA_REG_PLL_CTRL 0xca1e #define MDIO_PMA_REG_MISC_CTRL0 0xca23 #define MDIO_PMA_REG_LRM_MODE 0xca3f #define MDIO_PMA_REG_CDR_BANDWIDTH 0xca46 #define MDIO_PMA_REG_MISC_CTRL1 0xca85 -#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL 0x8000 -#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK 0x000c -#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE 0x0000 -#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE 0x0004 -#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IN_PROGRESS 0x0008 -#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_FAILED 0x000c -#define MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT 0x8002 -#define MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR 0x8003 +#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL 0x8000 +#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK 0x000c +#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE 0x0000 +#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE 0x0004 +#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IN_PROGRESS 0x0008 +#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_FAILED 0x000c +#define MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT 0x8002 +#define MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR 0x8003 #define MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF 0xc820 #define MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK 0xff #define MDIO_PMA_REG_8726_TX_CTRL1 0xca01 #define MDIO_PMA_REG_8726_TX_CTRL2 0xca05 +#define MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR 0x8005 +#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF 0x8007 +#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK 0xff +#define MDIO_PMA_REG_8727_MISC_CTRL 0x8309 +#define MDIO_PMA_REG_8727_TX_CTRL1 0xca02 +#define MDIO_PMA_REG_8727_TX_CTRL2 0xca05 +#define MDIO_PMA_REG_8727_PCS_OPT_CTRL 0xc808 +#define MDIO_PMA_REG_8727_GPIO_CTRL 0xc80e #define MDIO_PMA_REG_8073_CHIP_REV 0xc801 #define MDIO_PMA_REG_8073_SPEED_LINK_STATUS 0xc820 -- cgit v0.10.2 From ba71d3134176b9791aab7cb78242b6ba1428aac8 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:49 +0000 Subject: bnx2x: Set LED in loopback test Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index b9c85a2..a24bc51 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -5494,6 +5494,11 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) } REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); + + bnx2x_set_led(bp, params->port, LED_MODE_OPER, + vars->line_speed, params->hw_led_mode, + params->chip_id); + } else /* No loopback */ { -- cgit v0.10.2 From 5b6402d10328beb8a9b351ac65a31326ed5fe847 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:51 +0000 Subject: bnx2x: Missing parenthesis might result with wrong casting Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 8b6e83d..8bd80fc 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -160,7 +160,7 @@ struct sw_rx_page { #define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT) #define SGE_PAGE_SIZE PAGE_SIZE #define SGE_PAGE_SHIFT PAGE_SHIFT -#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))addr) +#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))(addr)) /* SGE ring related macros */ #define NUM_RX_SGE_PAGES 2 -- cgit v0.10.2 From e8834a63bddf87f7b85955d1ba60d28343d88469 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:55 +0000 Subject: bnx2x: Version 1.48.113-1 Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 197dbe4..c4c42b3 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -56,8 +56,8 @@ #include "bnx2x_init_ops.h" #include "bnx2x_dump.h" -#define DRV_MODULE_VERSION "1.48.105-1" -#define DRV_MODULE_RELDATE "2009/04/22" +#define DRV_MODULE_VERSION "1.48.113-1" +#define DRV_MODULE_RELDATE "2009/07/21" #define BNX2X_BC_VER 0x040200 #include -- cgit v0.10.2 From ed0f19b23754dc24f9a2d3c266a36277410f4686 Mon Sep 17 00:00:00 2001 From: John Bonesio Date: Tue, 21 Jul 2009 13:15:40 -0700 Subject: ASoC: MPC5200: Increase the delay time between resets Reset was failing with the original udelay(50) between the code in psc_ac97_cold_reset() and the call to psc_ac97_warm_reset(). Through testing it was found that a delay of 1ms was necessary for the cold_reset code to consistently complete successfully. Signed-off-by: John Bonesio Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index 7eb5499..c4ae3e0 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -112,7 +113,7 @@ static void psc_ac97_cold_reset(struct snd_ac97 *ac97) out_8(®s->op1, MPC52xx_PSC_OP_RES); udelay(10); out_8(®s->op0, MPC52xx_PSC_OP_RES); - udelay(50); + msleep(1); psc_ac97_warm_reset(ac97); } -- cgit v0.10.2 From 25cbf465207e9616e9b7d362ee166abf296d4c1e Mon Sep 17 00:00:00 2001 From: javier Martin Date: Tue, 21 Jul 2009 11:15:06 +0200 Subject: ASoC: Correct a bug with "ADC Inversion Switch" in wm8974 codec. This corrects a bug with ADC Inversion Switch in wm8974 codec. Signed-off-by: Javier Martin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index c400e5d..5104c8a 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -162,7 +162,7 @@ SOC_SINGLE_TLV("PCM Volume", WM8974_DACVOL, 0, 255, 0, digital_tlv), SOC_SINGLE("High Pass Filter Switch", WM8974_ADC, 8, 1, 0), SOC_SINGLE("High Pass Cut Off", WM8974_ADC, 4, 7, 0), -SOC_SINGLE("ADC Inversion Switch", WM8974_COMP, 0, 1, 0), +SOC_SINGLE("ADC Inversion Switch", WM8974_ADC, 0, 1, 0), SOC_SINGLE_TLV("Capture Volume", WM8974_ADCVOL, 0, 255, 0, digital_tlv), -- cgit v0.10.2 From 6fba00d176ab73b15bb8e31f261582943429a92b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 22 Jul 2009 11:10:22 +0800 Subject: crypto: cryptd - Add finup/export/import for hash This patch adds the finup/export/import functions to the cryptd ahash implementation. We simply invoke the underlying shash operations. Signed-off-by: Herbert Xu diff --git a/crypto/cryptd.c b/crypto/cryptd.c index fbd26f9..2eb7058 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -478,6 +478,29 @@ static int cryptd_hash_final_enqueue(struct ahash_request *req) return cryptd_hash_enqueue(req, cryptd_hash_final); } +static void cryptd_hash_finup(struct crypto_async_request *req_async, int err) +{ + struct ahash_request *req = ahash_request_cast(req_async); + struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req); + + if (unlikely(err == -EINPROGRESS)) + goto out; + + err = shash_ahash_finup(req, &rctx->desc); + + req->base.complete = rctx->complete; + +out: + local_bh_disable(); + rctx->complete(&req->base, err); + local_bh_enable(); +} + +static int cryptd_hash_finup_enqueue(struct ahash_request *req) +{ + return cryptd_hash_enqueue(req, cryptd_hash_finup); +} + static void cryptd_hash_digest(struct crypto_async_request *req_async, int err) { struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(req_async->tfm); @@ -507,6 +530,20 @@ static int cryptd_hash_digest_enqueue(struct ahash_request *req) return cryptd_hash_enqueue(req, cryptd_hash_digest); } +static int cryptd_hash_export(struct ahash_request *req, void *out) +{ + struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req); + + return crypto_shash_export(&rctx->desc, out); +} + +static int cryptd_hash_import(struct ahash_request *req, const void *in) +{ + struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req); + + return crypto_shash_import(&rctx->desc, in); +} + static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb, struct cryptd_queue *queue) { @@ -546,6 +583,9 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb, inst->alg.init = cryptd_hash_init_enqueue; inst->alg.update = cryptd_hash_update_enqueue; inst->alg.final = cryptd_hash_final_enqueue; + inst->alg.finup = cryptd_hash_finup_enqueue; + inst->alg.export = cryptd_hash_export; + inst->alg.import = cryptd_hash_import; inst->alg.setkey = cryptd_hash_setkey; inst->alg.digest = cryptd_hash_digest_enqueue; -- cgit v0.10.2 From b588ef6e69bfc0944a17dc673ee166a00fa23de2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 22 Jul 2009 13:04:37 +0800 Subject: crypto: xcbc - Use crypto_xor This patch replaces the local xor function with the generic crypto_xor function. Signed-off-by: Herbert Xu diff --git a/crypto/xcbc.c b/crypto/xcbc.c index 3b991bf..9d502e6 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c @@ -47,19 +47,10 @@ struct crypto_xcbc_ctx { u8 *prev; u8 *key; u8 *consts; - void (*xor)(u8 *a, const u8 *b, unsigned int bs); unsigned int keylen; unsigned int len; }; -static void xor_128(u8 *a, const u8 *b, unsigned int bs) -{ - ((u32 *)a)[0] ^= ((u32 *)b)[0]; - ((u32 *)a)[1] ^= ((u32 *)b)[1]; - ((u32 *)a)[2] ^= ((u32 *)b)[2]; - ((u32 *)a)[3] ^= ((u32 *)b)[3]; -} - static int _crypto_xcbc_digest_setkey(struct crypto_shash *parent, struct crypto_xcbc_ctx *ctx) { @@ -122,7 +113,7 @@ static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p, len -= bs - ctx->len; p += bs - ctx->len; - ctx->xor(ctx->prev, ctx->odds, bs); + crypto_xor(ctx->prev, ctx->odds, bs); crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev); /* clearing the length */ @@ -130,7 +121,7 @@ static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p, /* encrypting the rest of data */ while (len > bs) { - ctx->xor(ctx->prev, p, bs); + crypto_xor(ctx->prev, p, bs); crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev); p += bs; len -= bs; @@ -162,8 +153,8 @@ static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out) crypto_cipher_encrypt_one(tfm, key2, (u8 *)(ctx->consts + bs)); - ctx->xor(ctx->prev, ctx->odds, bs); - ctx->xor(ctx->prev, key2, bs); + crypto_xor(ctx->prev, ctx->odds, bs); + crypto_xor(ctx->prev, key2, bs); _crypto_xcbc_digest_setkey(parent, ctx); crypto_cipher_encrypt_one(tfm, out, ctx->prev); @@ -184,8 +175,8 @@ static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out) crypto_cipher_encrypt_one(tfm, key3, (u8 *)(ctx->consts + bs * 2)); - ctx->xor(ctx->prev, ctx->odds, bs); - ctx->xor(ctx->prev, key3, bs); + crypto_xor(ctx->prev, ctx->odds, bs); + crypto_xor(ctx->prev, key3, bs); _crypto_xcbc_digest_setkey(parent, ctx); @@ -209,7 +200,6 @@ static int xcbc_init_tfm(struct crypto_tfm *tfm) switch(bs) { case 16: - ctx->xor = xor_128; break; default: return -EINVAL; -- cgit v0.10.2 From ac95301f271f32901e4007096aa3516def49eed2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 22 Jul 2009 14:37:15 +0800 Subject: crypto: xcbc - Fix shash conversion Although xcbc was converted to shash, it didn't obey the new requirement that all hash state must be stored in the descriptor rather than the transform. This patch fixes this issue and also optimises away the rekeying by precomputing K2 and K3 within setkey. Signed-off-by: Herbert Xu diff --git a/crypto/xcbc.c b/crypto/xcbc.c index 9d502e6..1e30b31 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c @@ -26,69 +26,67 @@ static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x03030303, 0x03030303, 0x03030303, 0x03030303}; + /* * +------------------------ * | * +------------------------ - * | crypto_xcbc_ctx + * | xcbc_tfm_ctx * +------------------------ - * | odds (block size) + * | consts (block size * 2) * +------------------------ - * | prev (block size) + */ +struct xcbc_tfm_ctx { + struct crypto_cipher *child; + u8 ctx[]; +}; + +/* * +------------------------ - * | key (block size) + * | * +------------------------ - * | consts (block size * 3) + * | xcbc_desc_ctx + * +------------------------ + * | odds (block size) + * +------------------------ + * | prev (block size) * +------------------------ */ -struct crypto_xcbc_ctx { - struct crypto_cipher *child; - u8 *odds; - u8 *prev; - u8 *key; - u8 *consts; - unsigned int keylen; +struct xcbc_desc_ctx { unsigned int len; + u8 ctx[]; }; -static int _crypto_xcbc_digest_setkey(struct crypto_shash *parent, - struct crypto_xcbc_ctx *ctx) +static int crypto_xcbc_digest_setkey(struct crypto_shash *parent, + const u8 *inkey, unsigned int keylen) { + unsigned long alignmask = crypto_shash_alignmask(parent); + struct xcbc_tfm_ctx *ctx = crypto_shash_ctx(parent); int bs = crypto_shash_blocksize(parent); + u8 *consts = PTR_ALIGN(&ctx->ctx[0], alignmask + 1); int err = 0; u8 key1[bs]; - if ((err = crypto_cipher_setkey(ctx->child, ctx->key, ctx->keylen))) - return err; + if ((err = crypto_cipher_setkey(ctx->child, inkey, keylen))) + return err; - crypto_cipher_encrypt_one(ctx->child, key1, ctx->consts); + crypto_cipher_encrypt_one(ctx->child, consts, (u8 *)ks + bs); + crypto_cipher_encrypt_one(ctx->child, consts + bs, (u8 *)ks + bs * 2); + crypto_cipher_encrypt_one(ctx->child, key1, (u8 *)ks); return crypto_cipher_setkey(ctx->child, key1, bs); -} - -static int crypto_xcbc_digest_setkey(struct crypto_shash *parent, - const u8 *inkey, unsigned int keylen) -{ - struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(parent); - - if (keylen != crypto_cipher_blocksize(ctx->child)) - return -EINVAL; - ctx->keylen = keylen; - memcpy(ctx->key, inkey, keylen); - ctx->consts = (u8*)ks; - - return _crypto_xcbc_digest_setkey(parent, ctx); } static int crypto_xcbc_digest_init(struct shash_desc *pdesc) { - struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(pdesc->tfm); + unsigned long alignmask = crypto_shash_alignmask(pdesc->tfm); + struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc); int bs = crypto_shash_blocksize(pdesc->tfm); + u8 *prev = PTR_ALIGN(&ctx->ctx[0], alignmask + 1) + bs; ctx->len = 0; - memset(ctx->odds, 0, bs); - memset(ctx->prev, 0, bs); + memset(prev, 0, bs); return 0; } @@ -97,39 +95,43 @@ static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p, unsigned int len) { struct crypto_shash *parent = pdesc->tfm; - struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(parent); - struct crypto_cipher *tfm = ctx->child; + unsigned long alignmask = crypto_shash_alignmask(parent); + struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent); + struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc); + struct crypto_cipher *tfm = tctx->child; int bs = crypto_shash_blocksize(parent); + u8 *odds = PTR_ALIGN(&ctx->ctx[0], alignmask + 1); + u8 *prev = odds + bs; /* checking the data can fill the block */ if ((ctx->len + len) <= bs) { - memcpy(ctx->odds + ctx->len, p, len); + memcpy(odds + ctx->len, p, len); ctx->len += len; return 0; } /* filling odds with new data and encrypting it */ - memcpy(ctx->odds + ctx->len, p, bs - ctx->len); + memcpy(odds + ctx->len, p, bs - ctx->len); len -= bs - ctx->len; p += bs - ctx->len; - crypto_xor(ctx->prev, ctx->odds, bs); - crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev); + crypto_xor(prev, odds, bs); + crypto_cipher_encrypt_one(tfm, prev, prev); /* clearing the length */ ctx->len = 0; /* encrypting the rest of data */ while (len > bs) { - crypto_xor(ctx->prev, p, bs); - crypto_cipher_encrypt_one(tfm, ctx->prev, ctx->prev); + crypto_xor(prev, p, bs); + crypto_cipher_encrypt_one(tfm, prev, prev); p += bs; len -= bs; } /* keeping the surplus of blocksize */ if (len) { - memcpy(ctx->odds, p, len); + memcpy(odds, p, len); ctx->len = len; } @@ -139,29 +141,20 @@ static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p, static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out) { struct crypto_shash *parent = pdesc->tfm; - struct crypto_xcbc_ctx *ctx = crypto_shash_ctx(parent); - struct crypto_cipher *tfm = ctx->child; + unsigned long alignmask = crypto_shash_alignmask(parent); + struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent); + struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc); + struct crypto_cipher *tfm = tctx->child; int bs = crypto_shash_blocksize(parent); - int err = 0; + u8 *consts = PTR_ALIGN(&tctx->ctx[0], alignmask + 1); + u8 *odds = PTR_ALIGN(&ctx->ctx[0], alignmask + 1); + u8 *prev = odds + bs; + unsigned int offset = 0; - if (ctx->len == bs) { - u8 key2[bs]; - - if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0) - return err; - - crypto_cipher_encrypt_one(tfm, key2, - (u8 *)(ctx->consts + bs)); - - crypto_xor(ctx->prev, ctx->odds, bs); - crypto_xor(ctx->prev, key2, bs); - _crypto_xcbc_digest_setkey(parent, ctx); - - crypto_cipher_encrypt_one(tfm, out, ctx->prev); - } else { - u8 key3[bs]; + if (ctx->len != bs) { unsigned int rlen; - u8 *p = ctx->odds + ctx->len; + u8 *p = odds + ctx->len; + *p = 0x80; p++; @@ -169,19 +162,13 @@ static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out) if (rlen) memset(p, 0, rlen); - if ((err = crypto_cipher_setkey(tfm, ctx->key, ctx->keylen)) != 0) - return err; - - crypto_cipher_encrypt_one(tfm, key3, - (u8 *)(ctx->consts + bs * 2)); + offset += bs; + } - crypto_xor(ctx->prev, ctx->odds, bs); - crypto_xor(ctx->prev, key3, bs); + crypto_xor(prev, odds, bs); + crypto_xor(prev, consts + offset, bs); - _crypto_xcbc_digest_setkey(parent, ctx); - - crypto_cipher_encrypt_one(tfm, out, ctx->prev); - } + crypto_cipher_encrypt_one(tfm, out, prev); return 0; } @@ -191,31 +178,20 @@ static int xcbc_init_tfm(struct crypto_tfm *tfm) struct crypto_cipher *cipher; struct crypto_instance *inst = (void *)tfm->__crt_alg; struct crypto_spawn *spawn = crypto_instance_ctx(inst); - struct crypto_xcbc_ctx *ctx = crypto_tfm_ctx(tfm); - int bs = crypto_tfm_alg_blocksize(tfm); + struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm); cipher = crypto_spawn_cipher(spawn); if (IS_ERR(cipher)) return PTR_ERR(cipher); - switch(bs) { - case 16: - break; - default: - return -EINVAL; - } - ctx->child = cipher; - ctx->odds = (u8*)(ctx+1); - ctx->prev = ctx->odds + bs; - ctx->key = ctx->prev + bs; return 0; }; static void xcbc_exit_tfm(struct crypto_tfm *tfm) { - struct crypto_xcbc_ctx *ctx = crypto_tfm_ctx(tfm); + struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm); crypto_free_cipher(ctx->child); } @@ -254,12 +230,18 @@ static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.base.cra_priority = alg->cra_priority; inst->alg.base.cra_blocksize = alg->cra_blocksize; - inst->alg.base.cra_alignmask = alg->cra_alignmask; + inst->alg.base.cra_alignmask = alg->cra_alignmask | 3; inst->alg.digestsize = alg->cra_blocksize; - inst->alg.base.cra_ctxsize = sizeof(struct crypto_xcbc_ctx) + - ALIGN(alg->cra_blocksize * 3, - sizeof(void *)); + inst->alg.descsize = ALIGN(sizeof(struct xcbc_desc_ctx), + crypto_tfm_ctx_alignment()) + + (alg->cra_alignmask & + ~(crypto_tfm_ctx_alignment() - 1)) + + alg->cra_blocksize * 2; + + inst->alg.base.cra_ctxsize = ALIGN(sizeof(struct xcbc_tfm_ctx), + alg->cra_alignmask) + + alg->cra_blocksize * 2; inst->alg.base.cra_init = xcbc_init_tfm; inst->alg.base.cra_exit = xcbc_exit_tfm; -- cgit v0.10.2 From 1f38ad8389bbca038d320c29d30aa1d6ed96b48d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 22 Jul 2009 11:48:18 +0800 Subject: crypto: sha512 - Export struct sha512_state This patch renames struct sha512_ctx and exports it as struct sha512_state so that other sha512 implementations can use it as the reference structure for exporting their state. Signed-off-by: Herbert Xu diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index 3bea38d..4fe95eb 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -21,12 +21,6 @@ #include #include -struct sha512_ctx { - u64 state[8]; - u32 count[4]; - u8 buf[128]; -}; - static DEFINE_PER_CPU(u64[80], msg_schedule); static inline u64 Ch(u64 x, u64 y, u64 z) @@ -141,7 +135,7 @@ sha512_transform(u64 *state, const u8 *input) static int sha512_init(struct shash_desc *desc) { - struct sha512_ctx *sctx = shash_desc_ctx(desc); + struct sha512_state *sctx = shash_desc_ctx(desc); sctx->state[0] = SHA512_H0; sctx->state[1] = SHA512_H1; sctx->state[2] = SHA512_H2; @@ -158,7 +152,7 @@ sha512_init(struct shash_desc *desc) static int sha384_init(struct shash_desc *desc) { - struct sha512_ctx *sctx = shash_desc_ctx(desc); + struct sha512_state *sctx = shash_desc_ctx(desc); sctx->state[0] = SHA384_H0; sctx->state[1] = SHA384_H1; sctx->state[2] = SHA384_H2; @@ -175,7 +169,7 @@ sha384_init(struct shash_desc *desc) static int sha512_update(struct shash_desc *desc, const u8 *data, unsigned int len) { - struct sha512_ctx *sctx = shash_desc_ctx(desc); + struct sha512_state *sctx = shash_desc_ctx(desc); unsigned int i, index, part_len; @@ -214,7 +208,7 @@ sha512_update(struct shash_desc *desc, const u8 *data, unsigned int len) static int sha512_final(struct shash_desc *desc, u8 *hash) { - struct sha512_ctx *sctx = shash_desc_ctx(desc); + struct sha512_state *sctx = shash_desc_ctx(desc); static u8 padding[128] = { 0x80, }; __be64 *dst = (__be64 *)hash; __be32 bits[4]; @@ -240,7 +234,7 @@ sha512_final(struct shash_desc *desc, u8 *hash) dst[i] = cpu_to_be64(sctx->state[i]); /* Zeroize sensitive information. */ - memset(sctx, 0, sizeof(struct sha512_ctx)); + memset(sctx, 0, sizeof(struct sha512_state)); return 0; } @@ -262,7 +256,7 @@ static struct shash_alg sha512 = { .init = sha512_init, .update = sha512_update, .final = sha512_final, - .descsize = sizeof(struct sha512_ctx), + .descsize = sizeof(struct sha512_state), .base = { .cra_name = "sha512", .cra_flags = CRYPTO_ALG_TYPE_SHASH, @@ -276,7 +270,7 @@ static struct shash_alg sha384 = { .init = sha384_init, .update = sha512_update, .final = sha384_final, - .descsize = sizeof(struct sha512_ctx), + .descsize = sizeof(struct sha512_state), .base = { .cra_name = "sha384", .cra_flags = CRYPTO_ALG_TYPE_SHASH, diff --git a/include/crypto/sha.h b/include/crypto/sha.h index 88ef5eb..45b25cc 100644 --- a/include/crypto/sha.h +++ b/include/crypto/sha.h @@ -76,4 +76,10 @@ struct sha256_state { u8 buf[SHA256_BLOCK_SIZE]; }; +struct sha512_state { + u64 state[8]; + u32 count[4]; + u8 buf[128]; +}; + #endif -- cgit v0.10.2 From 13887ed6888dad1608eb9530ebd83b6ba29db577 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 22 Jul 2009 12:22:43 +0800 Subject: crypto: sha512_generic - Use 64-bit counters This patch replaces the 32-bit counters in sha512_generic with 64-bit counters. It also switches the bit count to the simpler byte count. Signed-off-by: Herbert Xu diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index 4fe95eb..9ed9f60 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -144,7 +144,7 @@ sha512_init(struct shash_desc *desc) sctx->state[5] = SHA512_H5; sctx->state[6] = SHA512_H6; sctx->state[7] = SHA512_H7; - sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0; + sctx->count[0] = sctx->count[1] = 0; return 0; } @@ -161,7 +161,7 @@ sha384_init(struct shash_desc *desc) sctx->state[5] = SHA384_H5; sctx->state[6] = SHA384_H6; sctx->state[7] = SHA384_H7; - sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0; + sctx->count[0] = sctx->count[1] = 0; return 0; } @@ -174,15 +174,11 @@ sha512_update(struct shash_desc *desc, const u8 *data, unsigned int len) unsigned int i, index, part_len; /* Compute number of bytes mod 128 */ - index = (unsigned int)((sctx->count[0] >> 3) & 0x7F); - - /* Update number of bits */ - if ((sctx->count[0] += (len << 3)) < (len << 3)) { - if ((sctx->count[1] += 1) < 1) - if ((sctx->count[2] += 1) < 1) - sctx->count[3]++; - sctx->count[1] += (len >> 29); - } + index = sctx->count[0] & 0x7f; + + /* Update number of bytes */ + if (!(sctx->count[0] += len)) + sctx->count[1]++; part_len = 128 - index; @@ -211,18 +207,16 @@ sha512_final(struct shash_desc *desc, u8 *hash) struct sha512_state *sctx = shash_desc_ctx(desc); static u8 padding[128] = { 0x80, }; __be64 *dst = (__be64 *)hash; - __be32 bits[4]; + __be64 bits[2]; unsigned int index, pad_len; int i; /* Save number of bits */ - bits[3] = cpu_to_be32(sctx->count[0]); - bits[2] = cpu_to_be32(sctx->count[1]); - bits[1] = cpu_to_be32(sctx->count[2]); - bits[0] = cpu_to_be32(sctx->count[3]); + bits[1] = cpu_to_be64(sctx->count[0] << 3); + bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61); /* Pad out to 112 mod 128. */ - index = (sctx->count[0] >> 3) & 0x7f; + index = sctx->count[0] & 0x7f; pad_len = (index < 112) ? (112 - index) : ((128+112) - index); sha512_update(desc, padding, pad_len); diff --git a/include/crypto/sha.h b/include/crypto/sha.h index 45b25cc..069e85b 100644 --- a/include/crypto/sha.h +++ b/include/crypto/sha.h @@ -77,9 +77,9 @@ struct sha256_state { }; struct sha512_state { - u64 state[8]; - u32 count[4]; - u8 buf[128]; + u64 count[2]; + u64 state[SHA512_DIGEST_SIZE / 8]; + u8 buf[SHA512_BLOCK_SIZE]; }; #endif -- cgit v0.10.2 From 9fadfd1adff28a8895de8df9e8a778c44958840f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 22 Jul 2009 12:29:41 +0800 Subject: crypto: sha512-s390 - Add export/import support This patch adds export/import support to sha512-s390 (which includes sha384-s390). The exported type is defined by struct sha512_state, which is basically the entire descriptor state of sha512_generic. Since sha512-s390 only supports a 64-bit byte count the import function will reject anything that exceeds that. Signed-off-by: Herbert Xu diff --git a/arch/s390/crypto/sha512_s390.c b/arch/s390/crypto/sha512_s390.c index 83192bf..b4b3438 100644 --- a/arch/s390/crypto/sha512_s390.c +++ b/arch/s390/crypto/sha512_s390.c @@ -13,7 +13,10 @@ * */ #include +#include +#include #include +#include #include #include "sha.h" @@ -37,12 +40,42 @@ static int sha512_init(struct shash_desc *desc) return 0; } +static int sha512_export(struct shash_desc *desc, void *out) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + struct sha512_state *octx = out; + + octx->count[0] = sctx->count; + octx->count[1] = 0; + memcpy(octx->state, sctx->state, sizeof(octx->state)); + memcpy(octx->buf, sctx->buf, sizeof(octx->buf)); + return 0; +} + +static int sha512_import(struct shash_desc *desc, const u8 *in) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + struct sha512_state *ictx = in; + + if (unlikely(ictx->count[1])) + return -ERANGE; + sctx->count = ictx->count[0]; + + memcpy(sctx->state, ictx->state, sizeof(ictx->state)); + memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf)); + sctx->func = KIMD_SHA_512; + return 0; +} + static struct shash_alg sha512_alg = { .digestsize = SHA512_DIGEST_SIZE, .init = sha512_init, .update = s390_sha_update, .final = s390_sha_final, + .export = sha512_export, + .import = sha512_import, .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha512_state), .base = { .cra_name = "sha512", .cra_driver_name= "sha512-s390", @@ -78,7 +111,10 @@ static struct shash_alg sha384_alg = { .init = sha384_init, .update = s390_sha_update, .final = s390_sha_final, + .export = sha512_export, + .import = sha512_import, .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha512_state), .base = { .cra_name = "sha384", .cra_driver_name= "sha384-s390", -- cgit v0.10.2 From f592682f9fca18d336ac068a1abc8507b4a1d936 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 22 Jul 2009 12:37:06 +0800 Subject: crypto: shash - Require all algorithms to support export/import This patch provides a default export/import function for all shash algorithms. It simply copies the descriptor context as is done by sha1_generic. This in essence means that all existing shash algorithms now support export/import. This is something that will be depended upon in implementations such as hmac. Therefore all new shash and ahash implementations must support export/import. For those that cannot obtain a partial result, padlock-sha's fallback model should be used so that a partial result is always available. Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 7713b52..98b7f46 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -183,14 +183,16 @@ int crypto_shash_digest(struct shash_desc *desc, const u8 *data, } EXPORT_SYMBOL_GPL(crypto_shash_digest); -static int shash_no_export(struct shash_desc *desc, void *out) +static int shash_default_export(struct shash_desc *desc, void *out) { - return -ENOSYS; + memcpy(out, shash_desc_ctx(desc), crypto_shash_descsize(desc->tfm)); + return 0; } -static int shash_no_import(struct shash_desc *desc, const void *in) +static int shash_default_import(struct shash_desc *desc, const void *in) { - return -ENOSYS; + memcpy(shash_desc_ctx(desc), in, crypto_shash_descsize(desc->tfm)); + return 0; } static int shash_async_setkey(struct crypto_ahash *tfm, const u8 *key, @@ -563,10 +565,11 @@ static int shash_prepare_alg(struct shash_alg *alg) alg->finup = shash_finup_unaligned; if (!alg->digest) alg->digest = shash_digest_unaligned; - if (!alg->import) - alg->import = shash_no_import; - if (!alg->export) - alg->export = shash_no_export; + if (!alg->export) { + alg->export = shash_default_export; + alg->import = shash_default_import; + alg->statesize = alg->descsize; + } if (!alg->setkey) alg->setkey = shash_no_setkey; -- cgit v0.10.2 From e458a48f8776d624d05246471501c6086adb1d7a Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Wed, 22 Jul 2009 14:09:08 +0900 Subject: ASoC: MAX9877: separate callback functions The callback function to control register was used by whole controls in MAX9877 driver, but this causes using many if statement for double register control or invert. So, the callback function for double register control is separate differently, and the code for invert is added in the callback function. Signed-off-by: Joonyoung Shim Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 7df9a7c..a1f1119 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -34,16 +34,16 @@ static int max9877_get_reg(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - int reg = mc->reg; - int reg2 = mc->rreg; - int shift = mc->shift; - int mask = mc->max; + unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + unsigned int mask = mc->max; + unsigned int invert = mc->invert; ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask; - if (reg2) - ucontrol->value.integer.value[1] = - (max9877_regs[reg2] >> shift) & mask; + if (invert) + ucontrol->value.integer.value[0] = + mask - ucontrol->value.integer.value[0]; return 0; } @@ -53,39 +53,69 @@ static int max9877_set_reg(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - int reg = mc->reg; - int reg2 = mc->rreg; - int shift = mc->shift; - int mask = mc->max; - int change = 1; - int change2 = 1; - int ret = 0; - - if (((max9877_regs[reg] >> shift) & mask) == - ucontrol->value.integer.value[0]) + unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + unsigned int mask = mc->max; + unsigned int invert = mc->invert; + unsigned int val = (ucontrol->value.integer.value[0] & mask); + + if (invert) + val = mask - val; + + if (((max9877_regs[reg] >> shift) & mask) == val) + return 0; + + max9877_regs[reg] &= ~(mask << shift); + max9877_regs[reg] |= val << shift; + max9877_write_regs(); + + return 1; +} + +static int max9877_get_2reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + unsigned int reg2 = mc->rreg; + unsigned int shift = mc->shift; + unsigned int mask = mc->max; + + ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask; + ucontrol->value.integer.value[1] = (max9877_regs[reg2] >> shift) & mask; + + return 0; +} + +static int max9877_set_2reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + unsigned int reg2 = mc->rreg; + unsigned int shift = mc->shift; + unsigned int mask = mc->max; + unsigned int val = (ucontrol->value.integer.value[0] & mask); + unsigned int val2 = (ucontrol->value.integer.value[1] & mask); + unsigned int change = 1; + + if (((max9877_regs[reg] >> shift) & mask) == val) change = 0; - if (reg2) - if (((max9877_regs[reg2] >> shift) & mask) == - ucontrol->value.integer.value[1]) - change2 = 0; + if (((max9877_regs[reg2] >> shift) & mask) == val2) + change = 0; if (change) { max9877_regs[reg] &= ~(mask << shift); - max9877_regs[reg] |= ucontrol->value.integer.value[0] << shift; - ret = change; - } - - if (reg2 && change2) { + max9877_regs[reg] |= val << shift; max9877_regs[reg2] &= ~(mask << shift); - max9877_regs[reg2] |= ucontrol->value.integer.value[1] << shift; - ret = change2; - } - - if (ret) + max9877_regs[reg2] |= val2 << shift; max9877_write_regs(); + } - return ret; + return change; } static int max9877_get_out_mode(struct snd_kcontrol *kcontrol, @@ -190,7 +220,7 @@ static const struct snd_kcontrol_new max9877_controls[] = { max9877_get_reg, max9877_set_reg, max9877_output_tlv), SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume", MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0, - max9877_get_reg, max9877_set_reg, max9877_output_tlv), + max9877_get_2reg, max9877_set_2reg, max9877_output_tlv), SOC_SINGLE_EXT("MAX9877 INB Stereo Switch", MAX9877_INPUT_MODE, 4, 1, 1, max9877_get_reg, max9877_set_reg), -- cgit v0.10.2 From 05ff7e11b78f18ff6819d2c260b7bcc7da0c8f46 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 22 Jul 2009 12:39:24 +0200 Subject: ALSA: hda - Reduce click noise at power-saving Add some tricks to reduce the click noise at powering down to D3 in the power saving mode on STAC/IDT codecs. The key seems to be to reset PINs before the power-down, and some delay before entering D3. The needed delay is significantly long, but I don't know why. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d686f4f..3ecb45d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2367,9 +2367,14 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, hda_nid_t nid; int i; - snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, + /* this delay seems necessary to avoid click noise at power-down */ + if (power_state == AC_PWRST_D3) + msleep(100); + snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state); - msleep(10); /* partial workaround for "azx_get_response timeout" */ + /* partial workaround for "azx_get_response timeout" */ + if (power_state == AC_PWRST_D0) + msleep(10); nid = codec->start_nid; for (i = 0; i < codec->num_nodes; i++, nid++) { diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 41b5b3a..00c702d 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4745,6 +4745,20 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) { struct sigmatel_spec *spec = codec->spec; + int i; + hda_nid_t nid; + + /* reset each pin before powering down DAC/ADC to avoid click noise */ + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { + unsigned int wcaps = get_wcaps(codec, nid); + unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> + AC_WCAP_TYPE_SHIFT; + if (wid_type == AC_WID_PIN) + snd_hda_codec_read(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + } + if (spec->eapd_mask) stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data & -- cgit v0.10.2 From 1c20930a41c623a2281e754f9321cd0feb01ceb9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 22 Jul 2009 15:17:45 +0200 Subject: ALSA: hda - Fix ALC861 auto-mode parser Fix the logic of ALC861 auto-mode parser for the outputs. Instead of assuming the fixed DAC list, parse the conection and assign the DAC dynamically. Also, unmute the unused output connections to avoid noises on inputs. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 454df58..b2ea432 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -13685,23 +13685,23 @@ static struct hda_verb alc861_auto_init_verbs[] = { {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */ @@ -13773,64 +13773,97 @@ static struct hda_input_mux alc861_capture_source = { }, }; +static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t mix, srcs[5]; + int i, j, num; + + if (snd_hda_get_connections(codec, pin, &mix, 1) != 1) + return 0; + num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs)); + if (num < 0) + return 0; + for (i = 0; i < num; i++) { + unsigned int type; + type = (get_wcaps(codec, srcs[i]) & AC_WCAP_TYPE) + >> AC_WCAP_TYPE_SHIFT; + if (type != AC_WID_AUD_OUT) + continue; + for (j = 0; j < spec->multiout.num_dacs; j++) + if (spec->multiout.dac_nids[j] == srcs[i]) + break; + if (j >= spec->multiout.num_dacs) + return srcs[i]; + } + return 0; +} + /* fill in the dac_nids table from the parsed pin configuration */ -static int alc861_auto_fill_dac_nids(struct alc_spec *spec, +static int alc861_auto_fill_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { + struct alc_spec *spec = codec->spec; int i; - hda_nid_t nid; + hda_nid_t nid, dac; spec->multiout.dac_nids = spec->private_dac_nids; for (i = 0; i < cfg->line_outs; i++) { nid = cfg->line_out_pins[i]; - if (nid) { - if (i >= ARRAY_SIZE(alc861_dac_nids)) - continue; - spec->multiout.dac_nids[i] = alc861_dac_nids[i]; - } + dac = alc861_look_for_dac(codec, nid); + if (!dac) + continue; + spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; } - spec->multiout.num_dacs = cfg->line_outs; return 0; } +static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx, + hda_nid_t nid, unsigned int chs) +{ + char name[32]; + snprintf(name, sizeof(name), "%s Playback Switch", pfx); + return add_control(codec->spec, ALC_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); +} + /* add playback controls from the parsed DAC table */ -static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec, +static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - char name[32]; + struct alc_spec *spec = codec->spec; static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; hda_nid_t nid; - int i, idx, err; + int i, err; + + if (cfg->line_outs == 1) { + const char *pfx = NULL; + if (!cfg->hp_outs) + pfx = "Master"; + else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + pfx = "Speaker"; + if (pfx) { + nid = spec->multiout.dac_nids[0]; + return alc861_create_out_sw(codec, pfx, nid, 3); + } + } for (i = 0; i < cfg->line_outs; i++) { nid = spec->multiout.dac_nids[i]; if (!nid) continue; - if (nid == 0x05) { + if (i == 2) { /* Center/LFE */ - err = add_control(spec, ALC_CTL_BIND_MUTE, - "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, - HDA_OUTPUT)); + err = alc861_create_out_sw(codec, "Center", nid, 1); if (err < 0) return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, - HDA_OUTPUT)); + err = alc861_create_out_sw(codec, "LFE", nid, 2); if (err < 0) return err; } else { - for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1; - idx++) - if (nid == alc861_dac_nids[idx]) - break; - sprintf(name, "%s Playback Switch", chname[idx]); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - HDA_OUTPUT)); + err = alc861_create_out_sw(codec, chname[i], nid, 3); if (err < 0) return err; } @@ -13838,8 +13871,9 @@ static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec, return 0; } -static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) +static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) { + struct alc_spec *spec = codec->spec; int err; hda_nid_t nid; @@ -13847,21 +13881,22 @@ static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) return 0; if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) { - nid = 0x03; - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Headphone Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - spec->multiout.hp_nid = nid; + nid = alc861_look_for_dac(codec, pin); + if (nid) { + err = alc861_create_out_sw(codec, "Headphone", nid, 3); + if (err < 0) + return err; + spec->multiout.hp_nid = nid; + } } return 0; } /* create playback/capture controls for input pins */ -static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, +static int alc861_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { + struct alc_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx, idx1; @@ -13905,12 +13940,29 @@ static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, - int pin_type, int dac_idx) + int pin_type, hda_nid_t dac) { + hda_nid_t mix, srcs[5]; + int i, num; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); - snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE, + snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + if (snd_hda_get_connections(codec, nid, &mix, 1) != 1) + return; + num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs)); + if (num < 0) + return; + for (i = 0; i < num; i++) { + unsigned int mute; + if (srcs[i] == dac || srcs[i] == 0x15) + mute = AMP_IN_UNMUTE(i); + else + mute = AMP_IN_MUTE(i); + snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE, + mute); + } } static void alc861_auto_init_multi_out(struct hda_codec *codec) @@ -13933,12 +13985,13 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec) hda_nid_t pin; pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ + if (pin) alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, - spec->multiout.dac_nids[0]); + spec->multiout.hp_nid); pin = spec->autocfg.speaker_pins[0]; if (pin) - alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); + alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, + spec->multiout.dac_nids[0]); } static void alc861_auto_init_analog_input(struct hda_codec *codec) @@ -13970,16 +14023,16 @@ static int alc861_parse_auto_config(struct hda_codec *codec) if (!spec->autocfg.line_outs) return 0; /* can't find valid BIOS pin config */ - err = alc861_auto_fill_dac_nids(spec, &spec->autocfg); + err = alc861_auto_fill_dac_nids(codec, &spec->autocfg); if (err < 0) return err; - err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg); + err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; - err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = alc861_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; -- cgit v0.10.2 From 052960483833f81603450e2a3cfa7a5ee98eedd4 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 22 Jul 2009 14:38:58 +0200 Subject: ALSA: hda_generic: do not read connections for widged with an unknown type Reading node connections for an unknown widget can confuse HDA codec bus. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 1d5797a..da3e1ed 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -121,11 +121,17 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid if (node == NULL) return -ENOMEM; node->nid = nid; - nconns = snd_hda_get_connections(codec, nid, conn_list, - HDA_MAX_CONNECTIONS); - if (nconns < 0) { - kfree(node); - return nconns; + node->wid_caps = get_wcaps(codec, nid); + node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + if (node->type <= AC_WID_BEEP || node->type == AC_WID_VENDOR) { + nconns = snd_hda_get_connections(codec, nid, conn_list, + HDA_MAX_CONNECTIONS); + if (nconns < 0) { + kfree(node); + return nconns; + } + } else { + nconns = 0; } if (nconns <= ARRAY_SIZE(node->slist)) node->conn_list = node->slist; @@ -140,8 +146,6 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid } memcpy(node->conn_list, conn_list, nconns * sizeof(hda_nid_t)); node->nconns = nconns; - node->wid_caps = get_wcaps(codec, nid); - node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; if (node->type == AC_WID_PIN) { node->pin_caps = snd_hda_query_pin_caps(codec, node->nid); -- cgit v0.10.2 From 254da007f93f79ee773788cbb38f24dfab9590f5 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 22 Jul 2009 15:31:03 +0200 Subject: ALSA: hda_generic: use AC_WCAP_CONN_LIST check for widget connections Previous patch used widget type, but the presence flag of the connection list is in the widget capabilities. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index da3e1ed..bccb62a 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -123,7 +123,7 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid node->nid = nid; node->wid_caps = get_wcaps(codec, nid); node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (node->type <= AC_WID_BEEP || node->type == AC_WID_VENDOR) { + if (node->wid_caps & AC_WCAP_CONN_LIST) { nconns = snd_hda_get_connections(codec, nid, conn_list, HDA_MAX_CONNECTIONS); if (nconns < 0) { -- cgit v0.10.2 From 16a433d8b38720a816736d59a62e705c19e31600 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 22 Jul 2009 16:20:40 +0200 Subject: ALSA: hda-intel: Cleanups for widget connection list handling This patch adds a check to snd_hda_get_connections() routine for presence of AC_WCAP_CONN_LIST. Also, make sure that negative error codes from noted route are handled on all places as errors. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3ecb45d..aa55407 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -306,6 +306,12 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, if (snd_BUG_ON(!conn_list || max_conns <= 0)) return -EINVAL; + if ((get_wcaps(codec, nid) & AC_WCAP_CONN_LIST) == 0) { + snd_printk(KERN_WARNING "hda_codec: " + "connection list not available for 0x%x\n", nid); + return -EINVAL; + } + parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN); if (parm & AC_CLIST_LONG) { /* long form */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b2ea432..728f2a7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4501,12 +4501,6 @@ static int alc880_parse_auto_config(struct hda_codec *codec) &dig_nid, 1); if (err < 0) continue; - if (dig_nid > 0x7f) { - printk(KERN_ERR "alc880_auto: invalid dig_nid " - "connection 0x%x for NID 0x%x\n", dig_nid, - spec->autocfg.dig_out_pins[i]); - continue; - } if (!i) spec->multiout.dig_out_nid = dig_nid; else { diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 00c702d..948600d 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3389,7 +3389,7 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec) spec->mono_nid, con_lst, HDA_MAX_NUM_INPUTS); - if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels)) + if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels)) return -EINVAL; for (i = 0; i < num_cons; i++) { @@ -3535,7 +3535,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec) spec->smux_nids[0], con_lst, HDA_MAX_NUM_INPUTS); - if (!num_cons) + if (num_cons <= 0) return -EINVAL; if (!labels) @@ -3742,7 +3742,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out if (snd_hda_get_connections(codec, spec->autocfg.mono_out_pin, conn_list, 1) && snd_hda_get_connections(codec, conn_list[0], - conn_list, 1)) { + conn_list, 1) > 0) { int wcaps = get_wcaps(codec, conn_list[0]); int wid_type = (wcaps & AC_WCAP_TYPE) @@ -5169,6 +5169,8 @@ again: num_dacs = snd_hda_get_connections(codec, nid, conn, STAC92HD83_DAC_COUNT + 1) - 1; + if (num_dacs < 0) + num_dacs = STAC92HD83_DAC_COUNT; /* set port X to select the last DAC */ -- cgit v0.10.2 From 35ebf6e7210dc0f7c612856513a8489a1da9de7e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 22 Jul 2009 17:12:34 +0200 Subject: ALSA: ctxfi - Simple code clean up - replace NULL == xxx with !xxx - replace NULL != xxx with xxx - similar trivial cleanups Signed-off-by: Takashi Iwai diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c index a7f4a67..fee35cf 100644 --- a/sound/pci/ctxfi/ctamixer.c +++ b/sound/pci/ctxfi/ctamixer.c @@ -63,7 +63,7 @@ static int amixer_set_input(struct amixer *amixer, struct rsc *rsc) hw = amixer->rsc.hw; hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE); amixer->input = rsc; - if (NULL == rsc) + if (!rsc) hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT); else hw->amixer_set_x(amixer->rsc.ctrl_blk, @@ -99,7 +99,7 @@ static int amixer_set_sum(struct amixer *amixer, struct sum *sum) hw = amixer->rsc.hw; amixer->sum = sum; - if (NULL == sum) { + if (!sum) { hw->amixer_set_se(amixer->rsc.ctrl_blk, 0); } else { hw->amixer_set_se(amixer->rsc.ctrl_blk, 1); @@ -124,20 +124,20 @@ static int amixer_commit_write(struct amixer *amixer) /* Program master and conjugate resources */ amixer->rsc.ops->master(&amixer->rsc); - if (NULL != input) + if (input) input->ops->master(input); - if (NULL != sum) + if (sum) sum->rsc.ops->master(&sum->rsc); for (i = 0; i < amixer->rsc.msr; i++) { hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk); - if (NULL != input) { + if (input) { hw->amixer_set_x(amixer->rsc.ctrl_blk, input->ops->output_slot(input)); input->ops->next_conj(input); } - if (NULL != sum) { + if (sum) { hw->amixer_set_sadr(amixer->rsc.ctrl_blk, sum->rsc.ops->index(&sum->rsc)); sum->rsc.ops->next_conj(&sum->rsc); @@ -147,10 +147,10 @@ static int amixer_commit_write(struct amixer *amixer) amixer->rsc.ops->next_conj(&amixer->rsc); } amixer->rsc.ops->master(&amixer->rsc); - if (NULL != input) + if (input) input->ops->master(input); - if (NULL != sum) + if (sum) sum->rsc.ops->master(&sum->rsc); return 0; @@ -303,7 +303,7 @@ int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr) *ramixer_mgr = NULL; amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL); - if (NULL == amixer_mgr) + if (!amixer_mgr) return -ENOMEM; err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw); @@ -456,7 +456,7 @@ int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr) *rsum_mgr = NULL; sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL); - if (NULL == sum_mgr) + if (!sum_mgr) return -ENOMEM; err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw); diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index a49c766..b1b3a64 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -136,7 +136,7 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) struct snd_pcm_runtime *runtime; struct ct_vm *vm; - if (NULL == apcm->substream) + if (!apcm->substream) return 0; runtime = apcm->substream->runtime; @@ -144,7 +144,7 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes); - if (NULL == apcm->vm_block) + if (!apcm->vm_block) return -ENOENT; return 0; @@ -154,7 +154,7 @@ static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) { struct ct_vm *vm; - if (NULL == apcm->vm_block) + if (!apcm->vm_block) return; vm = atc->vm; @@ -231,16 +231,16 @@ atc_get_pitch(unsigned int input_rate, unsigned int output_rate) static int select_rom(unsigned int pitch) { - if ((pitch > 0x00428f5c) && (pitch < 0x01b851ec)) { + if (pitch > 0x00428f5c && pitch < 0x01b851ec) { /* 0.26 <= pitch <= 1.72 */ return 1; - } else if ((0x01d66666 == pitch) || (0x01d66667 == pitch)) { + } else if (pitch == 0x01d66666 || pitch == 0x01d66667) { /* pitch == 1.8375 */ return 2; - } else if (0x02000000 == pitch) { + } else if (pitch == 0x02000000) { /* pitch == 2 */ return 3; - } else if ((pitch >= 0x0) && (pitch <= 0x08000000)) { + } else if (pitch >= 0x0 && pitch <= 0x08000000) { /* 0 <= pitch <= 8 */ return 0; } else { @@ -283,7 +283,7 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) /* Get AMIXER resource */ n_amixer = (n_amixer < 2) ? 2 : n_amixer; apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); - if (NULL == apcm->amixers) { + if (!apcm->amixers) { err = -ENOMEM; goto error1; } @@ -311,7 +311,7 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) INIT_VOL, atc->pcm[i+device*2]); mutex_unlock(&atc->atc_mutex); src = src->ops->next_interleave(src); - if (NULL == src) + if (!src) src = apcm->src; } @@ -334,7 +334,7 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) struct srcimp *srcimp; int i; - if (NULL != apcm->srcimps) { + if (apcm->srcimps) { for (i = 0; i < apcm->n_srcimp; i++) { srcimp = apcm->srcimps[i]; srcimp->ops->unmap(srcimp); @@ -345,7 +345,7 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) apcm->srcimps = NULL; } - if (NULL != apcm->srccs) { + if (apcm->srccs) { for (i = 0; i < apcm->n_srcc; i++) { src_mgr->put_src(src_mgr, apcm->srccs[i]); apcm->srccs[i] = NULL; @@ -354,7 +354,7 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) apcm->srccs = NULL; } - if (NULL != apcm->amixers) { + if (apcm->amixers) { for (i = 0; i < apcm->n_amixer; i++) { amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]); apcm->amixers[i] = NULL; @@ -363,17 +363,17 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) apcm->amixers = NULL; } - if (NULL != apcm->mono) { + if (apcm->mono) { sum_mgr->put_sum(sum_mgr, apcm->mono); apcm->mono = NULL; } - if (NULL != apcm->src) { + if (apcm->src) { src_mgr->put_src(src_mgr, apcm->src); apcm->src = NULL; } - if (NULL != apcm->vm_block) { + if (apcm->vm_block) { /* Undo device virtual mem map */ ct_unmap_audio_buffer(atc, apcm); apcm->vm_block = NULL; @@ -419,7 +419,7 @@ static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm) src->ops->set_state(src, SRC_STATE_OFF); src->ops->commit_write(src); - if (NULL != apcm->srccs) { + if (apcm->srccs) { for (i = 0; i < apcm->n_srcc; i++) { src = apcm->srccs[i]; src->ops->set_bm(src, 0); @@ -544,18 +544,18 @@ atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) if (n_srcc) { apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL); - if (NULL == apcm->srccs) + if (!apcm->srccs) return -ENOMEM; } if (n_amixer) { apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); - if (NULL == apcm->amixers) { + if (!apcm->amixers) { err = -ENOMEM; goto error1; } } apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL); - if (NULL == apcm->srcimps) { + if (!apcm->srcimps) { err = -ENOMEM; goto error1; } @@ -818,7 +818,7 @@ static int spdif_passthru_playback_get_resources(struct ct_atc *atc, /* Get AMIXER resource */ n_amixer = (n_amixer < 2) ? 2 : n_amixer; apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); - if (NULL == apcm->amixers) { + if (!apcm->amixers) { err = -ENOMEM; goto error1; } @@ -919,7 +919,7 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) amixer = apcm->amixers[i]; amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); src = src->ops->next_interleave(src); - if (NULL == src) + if (!src) src = apcm->src; } /* Connect to SPDIFOO */ @@ -1121,7 +1121,7 @@ static int atc_release_resources(struct ct_atc *atc) struct ct_mixer *mixer = NULL; /* disconnect internal mixer objects */ - if (NULL != atc->mixer) { + if (atc->mixer) { mixer = atc->mixer; mixer->set_input_left(mixer, MIX_LINE_IN, NULL); mixer->set_input_right(mixer, MIX_LINE_IN, NULL); @@ -1131,7 +1131,7 @@ static int atc_release_resources(struct ct_atc *atc) mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); } - if (NULL != atc->daios) { + if (atc->daios) { daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; for (i = 0; i < atc->n_daio; i++) { daio = atc->daios[i]; @@ -1149,7 +1149,7 @@ static int atc_release_resources(struct ct_atc *atc) atc->daios = NULL; } - if (NULL != atc->pcm) { + if (atc->pcm) { sum_mgr = atc->rsc_mgrs[SUM]; for (i = 0; i < atc->n_pcm; i++) sum_mgr->put_sum(sum_mgr, atc->pcm[i]); @@ -1158,7 +1158,7 @@ static int atc_release_resources(struct ct_atc *atc) atc->pcm = NULL; } - if (NULL != atc->srcs) { + if (atc->srcs) { src_mgr = atc->rsc_mgrs[SRC]; for (i = 0; i < atc->n_src; i++) src_mgr->put_src(src_mgr, atc->srcs[i]); @@ -1167,7 +1167,7 @@ static int atc_release_resources(struct ct_atc *atc) atc->srcs = NULL; } - if (NULL != atc->srcimps) { + if (atc->srcimps) { srcimp_mgr = atc->rsc_mgrs[SRCIMP]; for (i = 0; i < atc->n_srcimp; i++) { srcimp = atc->srcimps[i]; @@ -1185,7 +1185,7 @@ static int ct_atc_destroy(struct ct_atc *atc) { int i = 0; - if (NULL == atc) + if (!atc) return 0; if (atc->timer) { @@ -1196,21 +1196,20 @@ static int ct_atc_destroy(struct ct_atc *atc) atc_release_resources(atc); /* Destroy internal mixer objects */ - if (NULL != atc->mixer) + if (atc->mixer) ct_mixer_destroy(atc->mixer); for (i = 0; i < NUM_RSCTYP; i++) { - if ((NULL != rsc_mgr_funcs[i].destroy) && - (NULL != atc->rsc_mgrs[i])) + if (rsc_mgr_funcs[i].destroy && atc->rsc_mgrs[i]) rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]); } - if (NULL != atc->hw) + if (atc->hw) destroy_hw_obj((struct hw *)atc->hw); /* Destroy device virtual memory manager object */ - if (NULL != atc->vm) { + if (atc->vm) { ct_vm_destroy(atc->vm); atc->vm = NULL; } @@ -1275,7 +1274,7 @@ int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc) alsa_dev_funcs[MIXER].public_name = atc->chip_name; for (i = 0; i < NUM_CTALSADEVS; i++) { - if (NULL == alsa_dev_funcs[i].create) + if (!alsa_dev_funcs[i].create) continue; err = alsa_dev_funcs[i].create(atc, i, @@ -1312,7 +1311,7 @@ static int __devinit atc_create_hw_devs(struct ct_atc *atc) return err; for (i = 0; i < NUM_RSCTYP; i++) { - if (NULL == rsc_mgr_funcs[i].create) + if (!rsc_mgr_funcs[i].create) continue; err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); @@ -1339,19 +1338,19 @@ static int atc_get_resources(struct ct_atc *atc) int err, i; atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL); - if (NULL == atc->daios) + if (!atc->daios) return -ENOMEM; atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); - if (NULL == atc->srcs) + if (!atc->srcs) return -ENOMEM; atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); - if (NULL == atc->srcimps) + if (!atc->srcimps) return -ENOMEM; atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL); - if (NULL == atc->pcm) + if (!atc->pcm) return -ENOMEM; daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; @@ -1648,7 +1647,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, *ratc = NULL; atc = kzalloc(sizeof(*atc), GFP_KERNEL); - if (NULL == atc) + if (!atc) return -ENOMEM; /* Set operations */ diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index deb6cfa..af56eb9 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -173,7 +173,7 @@ static int dao_set_left_input(struct dao *dao, struct rsc *input) int i; entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL); - if (NULL == entry) + if (!entry) return -ENOMEM; /* Program master and conjugate resources */ @@ -201,7 +201,7 @@ static int dao_set_right_input(struct dao *dao, struct rsc *input) int i; entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL); - if (NULL == entry) + if (!entry) return -ENOMEM; /* Program master and conjugate resources */ @@ -228,7 +228,7 @@ static int dao_clear_left_input(struct dao *dao) struct daio *daio = &dao->daio; int i; - if (NULL == dao->imappers[0]) + if (!dao->imappers[0]) return 0; entry = dao->imappers[0]; @@ -252,7 +252,7 @@ static int dao_clear_right_input(struct dao *dao) struct daio *daio = &dao->daio; int i; - if (NULL == dao->imappers[daio->rscl.msr]) + if (!dao->imappers[daio->rscl.msr]) return 0; entry = dao->imappers[daio->rscl.msr]; @@ -408,7 +408,7 @@ static int dao_rsc_init(struct dao *dao, return err; dao->imappers = kzalloc(sizeof(void *)*desc->msr*2, GFP_KERNEL); - if (NULL == dao->imappers) { + if (!dao->imappers) { err = -ENOMEM; goto error1; } @@ -442,11 +442,11 @@ error1: static int dao_rsc_uninit(struct dao *dao) { - if (NULL != dao->imappers) { - if (NULL != dao->imappers[0]) + if (dao->imappers) { + if (dao->imappers[0]) dao_clear_left_input(dao); - if (NULL != dao->imappers[dao->daio.rscl.msr]) + if (dao->imappers[dao->daio.rscl.msr]) dao_clear_right_input(dao); kfree(dao->imappers); @@ -555,7 +555,7 @@ static int get_daio_rsc(struct daio_mgr *mgr, /* Allocate mem for daio resource */ if (desc->type <= DAIO_OUT_MAX) { dao = kzalloc(sizeof(*dao), GFP_KERNEL); - if (NULL == dao) { + if (!dao) { err = -ENOMEM; goto error; } @@ -566,7 +566,7 @@ static int get_daio_rsc(struct daio_mgr *mgr, *rdaio = &dao->daio; } else { dai = kzalloc(sizeof(*dai), GFP_KERNEL); - if (NULL == dai) { + if (!dai) { err = -ENOMEM; goto error; } @@ -583,9 +583,9 @@ static int get_daio_rsc(struct daio_mgr *mgr, return 0; error: - if (NULL != dao) + if (dao) kfree(dao); - else if (NULL != dai) + else if (dai) kfree(dai); spin_lock_irqsave(&mgr->mgr_lock, flags); @@ -663,7 +663,7 @@ static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry) int err; spin_lock_irqsave(&mgr->imap_lock, flags); - if ((0 == entry->addr) && (mgr->init_imap_added)) { + if (!entry->addr && mgr->init_imap_added) { input_mapper_delete(&mgr->imappers, mgr->init_imap, daio_map_op, mgr); mgr->init_imap_added = 0; @@ -707,7 +707,7 @@ int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr) *rdaio_mgr = NULL; daio_mgr = kzalloc(sizeof(*daio_mgr), GFP_KERNEL); - if (NULL == daio_mgr) + if (!daio_mgr) return -ENOMEM; err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw); @@ -718,7 +718,7 @@ int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr) spin_lock_init(&daio_mgr->imap_lock); INIT_LIST_HEAD(&daio_mgr->imappers); entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (NULL == entry) { + if (!entry) { err = -ENOMEM; goto error2; } diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index ad3e1d1..0cf400f 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -168,7 +168,7 @@ static int src_get_rsc_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -494,7 +494,7 @@ static int src_mgr_get_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -515,7 +515,7 @@ static int srcimp_mgr_get_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -702,7 +702,7 @@ static int amixer_rsc_get_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -723,7 +723,7 @@ static int amixer_mgr_get_ctrl_blk(void **rblk) *rblk = NULL; /*blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk;*/ @@ -909,7 +909,7 @@ static int dai_get_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -958,7 +958,7 @@ static int dao_get_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -1152,7 +1152,7 @@ static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; blk->i2sctl = hw_read_20kx(hw, I2SCTL); @@ -1808,7 +1808,7 @@ static int uaa_to_xfi(struct pci_dev *pci) /* By default, Hendrix card UAA Bar0 should be using memory... */ io_base = pci_resource_start(pci, 0); mem_base = ioremap(io_base, pci_resource_len(pci, 0)); - if (NULL == mem_base) + if (!mem_base) return -ENOENT; /* Read current mode from Mode Change Register */ @@ -1977,7 +1977,7 @@ static int hw_card_shutdown(struct hw *hw) hw->irq = -1; - if (NULL != ((void *)hw->mem_base)) + if (hw->mem_base) iounmap((void *)hw->mem_base); hw->mem_base = (unsigned long)NULL; @@ -2274,7 +2274,7 @@ int __devinit create_20k1_hw_obj(struct hw **rhw) *rhw = NULL; hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL); - if (NULL == hw20k1) + if (!hw20k1) return -ENOMEM; spin_lock_init(&hw20k1->reg_20k1_lock); diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index 0c4db2d..b6b11bf 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -166,7 +166,7 @@ static int src_get_rsc_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -492,7 +492,7 @@ static int src_mgr_get_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -513,7 +513,7 @@ static int srcimp_mgr_get_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -702,7 +702,7 @@ static int amixer_rsc_get_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -891,7 +891,7 @@ static int dai_get_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -941,7 +941,7 @@ static int dao_get_ctrl_blk(void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; *rblk = blk; @@ -1092,7 +1092,7 @@ static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk) *rblk = NULL; blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) + if (!blk) return -ENOMEM; for (i = 0; i < 8; i++) { @@ -1904,7 +1904,7 @@ static int hw_card_start(struct hw *hw) hw->io_base = pci_resource_start(hw->pci, 2); hw->mem_base = (unsigned long)ioremap(hw->io_base, pci_resource_len(hw->pci, 2)); - if (NULL == (void *)hw->mem_base) { + if (!hw->mem_base) { err = -ENOENT; goto error2; } @@ -1962,7 +1962,7 @@ static int hw_card_shutdown(struct hw *hw) hw->irq = -1; - if (NULL != ((void *)hw->mem_base)) + if (hw->mem_base) iounmap((void *)hw->mem_base); hw->mem_base = (unsigned long)NULL; diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c index f26d7cd..15c1e72 100644 --- a/sound/pci/ctxfi/ctmixer.c +++ b/sound/pci/ctxfi/ctmixer.c @@ -654,7 +654,7 @@ ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new) int err; kctl = snd_ctl_new1(new, mixer->atc); - if (NULL == kctl) + if (!kctl) return -ENOMEM; if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface) @@ -837,17 +837,17 @@ static int ct_mixer_get_mem(struct ct_mixer **rmixer) *rmixer = NULL; /* Allocate mem for mixer obj */ mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); - if (NULL == mixer) + if (!mixer) return -ENOMEM; mixer->amixers = kzalloc(sizeof(void *)*(NUM_CT_AMIXERS*CHN_NUM), GFP_KERNEL); - if (NULL == mixer->amixers) { + if (!mixer->amixers) { err = -ENOMEM; goto error1; } mixer->sums = kzalloc(sizeof(void *)*(NUM_CT_SUMS*CHN_NUM), GFP_KERNEL); - if (NULL == mixer->sums) { + if (!mixer->sums) { err = -ENOMEM; goto error2; } diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index 60ea231..d0dc227 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -97,7 +97,7 @@ static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm) { struct ct_atc_pcm *apcm = atc_pcm; - if (NULL == apcm->substream) + if (!apcm->substream) return; snd_pcm_period_elapsed(apcm->substream); @@ -123,7 +123,7 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream) int err; apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); - if (NULL == apcm) + if (!apcm) return -ENOMEM; apcm->substream = substream; @@ -271,7 +271,7 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream) int err; apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); - if (NULL == apcm) + if (!apcm) return -ENOMEM; apcm->started = 0; diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c index 889c495..7dfaf67 100644 --- a/sound/pci/ctxfi/ctresource.c +++ b/sound/pci/ctxfi/ctresource.c @@ -144,7 +144,7 @@ int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw) rsc->msr = msr; rsc->hw = hw; rsc->ops = &rsc_generic_ops; - if (NULL == hw) { + if (!hw) { rsc->ctrl_blk = NULL; return 0; } @@ -216,7 +216,7 @@ int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, mgr->type = NUM_RSCTYP; mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL); - if (NULL == mgr->rscs) + if (!mgr->rscs) return -ENOMEM; switch (type) { diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index df43a5c..c749fa7 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -441,7 +441,7 @@ get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc) else src = kzalloc(sizeof(*src), GFP_KERNEL); - if (NULL == src) { + if (!src) { err = -ENOMEM; goto error1; } @@ -550,7 +550,7 @@ int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr) *rsrc_mgr = NULL; src_mgr = kzalloc(sizeof(*src_mgr), GFP_KERNEL); - if (NULL == src_mgr) + if (!src_mgr) return -ENOMEM; err = rsc_mgr_init(&src_mgr->mgr, SRC, SRC_RESOURCE_NUM, hw); @@ -679,7 +679,7 @@ static int srcimp_rsc_init(struct srcimp *srcimp, /* Reserve memory for imapper nodes */ srcimp->imappers = kzalloc(sizeof(struct imapper)*desc->msr, GFP_KERNEL); - if (NULL == srcimp->imappers) { + if (!srcimp->imappers) { err = -ENOMEM; goto error1; } @@ -833,7 +833,7 @@ int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr) *rsrcimp_mgr = NULL; srcimp_mgr = kzalloc(sizeof(*srcimp_mgr), GFP_KERNEL); - if (NULL == srcimp_mgr) + if (!srcimp_mgr) return -ENOMEM; err = rsc_mgr_init(&srcimp_mgr->mgr, SRCIMP, SRCIMP_RESOURCE_NUM, hw); @@ -844,7 +844,7 @@ int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr) spin_lock_init(&srcimp_mgr->imap_lock); INIT_LIST_HEAD(&srcimp_mgr->imappers); entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (NULL == entry) { + if (!entry) { err = -ENOMEM; goto error2; } diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 67665a7..6b78752 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -60,7 +60,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size) } block = kzalloc(sizeof(*block), GFP_KERNEL); - if (NULL == block) + if (!block) goto out; block->addr = entry->addr; @@ -181,7 +181,7 @@ int ct_vm_create(struct ct_vm **rvm) *rvm = NULL; vm = kzalloc(sizeof(*vm), GFP_KERNEL); - if (NULL == vm) + if (!vm) return -ENOMEM; mutex_init(&vm->lock); @@ -189,7 +189,7 @@ int ct_vm_create(struct ct_vm **rvm) /* Allocate page table pages */ for (i = 0; i < CT_PTP_NUM; i++) { vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (NULL == vm->ptp[i]) + if (!vm->ptp[i]) break; } if (!i) { -- cgit v0.10.2 From d756b2774829c746e0cf2967802cbd41967eda65 Mon Sep 17 00:00:00 2001 From: "Lopez Cruz, Misael" Date: Wed, 22 Jul 2009 20:45:03 -0500 Subject: ASoC: OMAP: Staticise pcm creation function of omap-pcm Signed-off-by: Misael Lopez Cruz Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 84a1950..c3c931d 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -330,7 +330,7 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm) } } -int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, +static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { int ret = 0; -- cgit v0.10.2 From 87a8c3702e40028468a2d0ef6dab7627dab60c86 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 23 Jul 2009 10:58:29 +0200 Subject: ALSA: hda - Add better Intel IbexPeak platform support Here are the new sound enabling patches for IbexPeak. Summary of tested features: - playback - Front Headphone: OK - 8 channel audio: Front/Rear/CLFE/Side all OK - recording - Front Mic/Rear Mic: both OK (front/rear/line mics are selectable in the "Input source" alsamixer control) - Line In: not working (in 6ch mode, its amp/mute, direction and route all looks fine, so I'm a little puzzled) (hopefully no one will care this feature) - digital SPDIF input/output: not tested (no equipment) Signed-off-by: Wu Fengguang Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index fcc77fe..032850e 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -685,6 +685,7 @@ static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, + { .id = 0x80860054, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; @@ -694,6 +695,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862801"); MODULE_ALIAS("snd-hda-codec-id:80862802"); MODULE_ALIAS("snd-hda-codec-id:80862803"); MODULE_ALIAS("snd-hda-codec-id:80862804"); +MODULE_ALIAS("snd-hda-codec-id:80860054"); MODULE_ALIAS("snd-hda-codec-id:10951392"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 728f2a7..b5b36b8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -235,6 +235,8 @@ enum { ALC883_FUJITSU_PI2515, ALC888_FUJITSU_XA3530, ALC883_3ST_6ch_INTEL, + ALC889A_INTEL, + ALC889_INTEL, ALC888_ASUS_M90V, ALC888_ASUS_EEE1601, ALC889A_MB31, @@ -1027,6 +1029,16 @@ static void alc888_coef_init(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x3030); } +static void alc889_coef_init(struct hda_codec *codec) +{ + unsigned int tmp; + + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); + tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010); +} + static void alc_auto_init_amp(struct hda_codec *codec, int type) { unsigned int tmp; @@ -1084,15 +1096,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) case 0x10ec0885: case 0x10ec0887: case 0x10ec0889: - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x20, 0, - AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, - tmp | 0x2010); + alc889_coef_init(codec); break; case 0x10ec0888: alc888_coef_init(codec); @@ -6348,6 +6352,15 @@ static struct hda_input_mux alc882_capture_source = { #define alc883_capture_source alc882_capture_source +static struct hda_input_mux alc889_capture_source = { + .num_items = 3, + .items = { + { "Front Mic", 0x0 }, + { "Mic", 0x3 }, + { "Line", 0x2 }, + }, +}; + static struct hda_input_mux mb5_capture_source = { .num_items = 3, .items = { @@ -6671,6 +6684,46 @@ static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { /* * 6ch mode */ +static struct hda_verb alc889_ch6_intel_init[] = { + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static struct hda_verb alc889_ch8_intel_init[] = { + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 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, 0x03 }, + { } /* end */ +}; + +static struct hda_channel_mode alc889_8ch_intel_modes[2] = { + { 6, alc889_ch6_intel_init }, + { 8, alc889_ch8_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 }, @@ -6929,6 +6982,103 @@ static struct hda_verb alc882_eapd_verbs[] = { { } }; +static struct hda_verb alc889_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + + +static struct hda_verb alc885_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)}, + {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(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + + /* Front HP Pin: output 0 (0x0c) */ + {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, 0x00}, + /* 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) */ + {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, 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% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, 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}, + + /* Mixer elements: 0x18, , 0x1a, 0x1b */ + /* Input mixer1 */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + + { } +}; + +static struct hda_verb alc885_init_input_verbs[] = { + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + { } +}; + + +/* Unmute Selector 24h and set the default input to front mic */ +static struct hda_verb alc889_init_input_verbs[] = { + {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + { } +}; + + #define alc883_init_verbs alc882_base_init_verbs /* Mac Pro test */ @@ -7497,6 +7647,30 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc885_8ch_intel_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("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + 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, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + static struct snd_kcontrol_new alc883_fivestack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -8340,6 +8514,8 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", + [ALC889A_INTEL] = "intel-alc889a", + [ALC889_INTEL] = "intel-x58", [ALC1200_ASUS_P5Q] = "asus-p5q", [ALC889A_MB31] = "mb31", [ALC883_SONY_VAIO_TT] = "sony-vaio-tt", @@ -8459,7 +8635,9 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { 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, 0x0022, "DX58SO", ALC889_INTEL), + SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL), + SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL), SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), {} @@ -8675,6 +8853,40 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_3stack_6ch_intel, }, + [ALC889A_INTEL] = { + .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, + .init_verbs = { alc885_init_verbs, alc885_init_input_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), + .adc_nids = alc889_adc_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .slave_dig_outs = alc883_slave_dig_outs, + .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes), + .channel_mode = alc889_8ch_intel_modes, + .capsrc_nids = alc889_capsrc_nids, + .input_mux = &alc889_capture_source, + .need_dac_fix = 1, + }, + [ALC889_INTEL] = { + .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, + .init_verbs = { alc885_init_verbs, alc889_init_input_verbs, + alc889_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), + .adc_nids = alc889_adc_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .slave_dig_outs = alc883_slave_dig_outs, + .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes), + .channel_mode = alc889_8ch_intel_modes, + .capsrc_nids = alc889_capsrc_nids, + .input_mux = &alc889_capture_source, + .init_hook = alc889_coef_init, + .need_dac_fix = 1, + }, [ALC883_6ST_DIG] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs }, -- cgit v0.10.2 From 459dc35233c88d9eb7c5d0e6c086122751e64750 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 22 Jul 2009 05:22:28 +0200 Subject: ASoC: Add support for Conexant CX20442-11 voice modem codec This patch adds support for Conexant CX20442-11 voice modem codec, suitable for use by the ASoC board driver for Amstrad E3 (Delta) videophone. Related sound card driver will follow. This codec is an optional part of the Conexant SmartV three chip modem design. As such, documentation for its proprietary digital audio interface is not available. However, on Amstrad Delta board, thanks to Mark Underwood who created an initial, omap-alsa based sound driver a few years ago[1], the codec has been discovered to be accessible not only from the modem side, but also over the OMAP McBSP based CPU DAI. Thus, the driver can be used by any sound card that can access the codec DAI directly. The DAI configuration parameters (sample rate and format, number of channels) has been selected out empirically for best user experience. The codec analogue interface consists of two pairs of analogue I/O pins: speakerphone interface or telephone handset/headset interface. Furthermore, it seams to provide two operation modes for speakerphone I/O: standard and advanced, with automatic gain control and echo cancelation. Even if the codec control interface is unknown and not available, all those interfaces and modes can be selected over the modem chip using V.253 commands. The driver is able to issue necessary commands over a suitable hw_write function if provided by a sound card driver. Otherwise, the codec can be controlled over the modem from userspace while inactive. Even if nothig is known about the codec internal power management capabilities, DAPM widgets has been used to model the codec audio map. Automatically performed powering up/down of those virtual widgets results in corresponding V.253 commands being issued. Some driver features/oddities may be board specific, but I have no way to verify that with any board other than Amstrad Delta. [1] http://www.earth.li/pipermail/e3-hacking/2006-April/000481.html Created and tested against linux-2.6.31-rc3. Applies and works with linux-omap-2.6 commit 7c5cb7862d32cb344be7831d466535d5255e35ac as well. Signed-off-by: Janusz Krzysztofik Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 57f5b73..fdfc502 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -94,6 +94,9 @@ config SND_SOC_CS4270_VD33_ERRATA bool depends on SND_SOC_CS4270 +config SND_SOC_CX20442 + tristate + config SND_SOC_L3 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9a92f55..1131d6d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -5,6 +5,7 @@ snd-soc-ad73311-objs := ad73311.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o snd-soc-cs4270-objs := cs4270.o +snd-soc-cx20442-objs := cx20442.o snd-soc-l3-objs := l3.o snd-soc-pcm3008-objs := pcm3008.o snd-soc-spdif-objs := spdif_transciever.o @@ -49,6 +50,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o +obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c new file mode 100644 index 0000000..f64483c --- /dev/null +++ b/sound/soc/codecs/cx20442.c @@ -0,0 +1,395 @@ +/* + * cx20442.c -- CX20442 ALSA Soc Audio driver + * + * Copyright 2009 Janusz Krzysztofik + * + * Initially based on sound/soc/codecs/wm8400.c + * Copyright 2008, 2009 Wolfson Microelectronics PLC. + * Author: Mark Brown + * + * 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 +#include +#include + +#include "cx20442.h" + + +struct cx20442_priv { + struct snd_soc_codec codec; + u8 reg_cache[1]; +}; + +#define CX20442_PM 0x0 + +#define CX20442_TELIN 0 +#define CX20442_TELOUT 1 +#define CX20442_MIC 2 +#define CX20442_SPKOUT 3 +#define CX20442_AGC 4 + +static const struct snd_soc_dapm_widget cx20442_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("TELOUT"), + SND_SOC_DAPM_OUTPUT("SPKOUT"), + SND_SOC_DAPM_OUTPUT("AGCOUT"), + + SND_SOC_DAPM_MIXER("SPKOUT Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_PGA("TELOUT Amp", CX20442_PM, CX20442_TELOUT, 0, NULL, 0), + SND_SOC_DAPM_PGA("SPKOUT Amp", CX20442_PM, CX20442_SPKOUT, 0, NULL, 0), + SND_SOC_DAPM_PGA("SPKOUT AGC", CX20442_PM, CX20442_AGC, 0, NULL, 0), + + SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MICBIAS("TELIN Bias", CX20442_PM, CX20442_TELIN, 0), + SND_SOC_DAPM_MICBIAS("MIC Bias", CX20442_PM, CX20442_MIC, 0), + + SND_SOC_DAPM_PGA("MIC AGC", CX20442_PM, CX20442_AGC, 0, NULL, 0), + + SND_SOC_DAPM_INPUT("TELIN"), + SND_SOC_DAPM_INPUT("MIC"), + SND_SOC_DAPM_INPUT("AGCIN"), +}; + +static const struct snd_soc_dapm_route cx20442_audio_map[] = { + {"TELOUT", NULL, "TELOUT Amp"}, + + {"SPKOUT", NULL, "SPKOUT Mixer"}, + {"SPKOUT Mixer", NULL, "SPKOUT Amp"}, + + {"TELOUT Amp", NULL, "DAC"}, + {"SPKOUT Amp", NULL, "DAC"}, + + {"SPKOUT Mixer", NULL, "SPKOUT AGC"}, + {"SPKOUT AGC", NULL, "AGCIN"}, + + {"AGCOUT", NULL, "MIC AGC"}, + {"MIC AGC", NULL, "MIC"}, + + {"MIC Bias", NULL, "MIC"}, + {"Input Mixer", NULL, "MIC Bias"}, + + {"TELIN Bias", NULL, "TELIN"}, + {"Input Mixer", NULL, "TELIN Bias"}, + + {"ADC", NULL, "Input Mixer"}, +}; + +static int cx20442_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, cx20442_dapm_widgets, + ARRAY_SIZE(cx20442_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, cx20442_audio_map, + ARRAY_SIZE(cx20442_audio_map)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *reg_cache = codec->reg_cache; + + if (reg >= codec->reg_cache_size) + return -EINVAL; + + return reg_cache[reg]; +} + +enum v253_vls { + V253_VLS_NONE = 0, + V253_VLS_T, + V253_VLS_L, + V253_VLS_LT, + V253_VLS_S, + V253_VLS_ST, + V253_VLS_M, + V253_VLS_MST, + V253_VLS_S1, + V253_VLS_S1T, + V253_VLS_MS1T, + V253_VLS_M1, + V253_VLS_M1ST, + V253_VLS_M1S1T, + V253_VLS_H, + V253_VLS_HT, + V253_VLS_MS, + V253_VLS_MS1, + V253_VLS_M1S, + V253_VLS_M1S1, + V253_VLS_TEST, +}; + +static int cx20442_pm_to_v253_vls(u8 value) +{ + switch(value & ~(1 << CX20442_AGC)) { + case 0: + return V253_VLS_T; + case (1 << CX20442_SPKOUT): + return V253_VLS_S1; + case (1 << CX20442_MIC): + return V253_VLS_M1; + case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC): + return V253_VLS_M1S1; + case (1 << CX20442_TELOUT): + case (1 << CX20442_TELIN): + case (1 << CX20442_TELOUT) | (1 << CX20442_TELIN): + return V253_VLS_L; + case (1 << CX20442_TELOUT) | (1 << CX20442_MIC): + return V253_VLS_NONE; + } + return -EINVAL; +} +static int cx20442_pm_to_v253_vsp(u8 value) +{ + switch(value & ~(1 << CX20442_AGC)) { + case (1 << CX20442_SPKOUT): + case (1 << CX20442_MIC): + case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC): + return (bool)(value & (1 << CX20442_AGC)); + } + return (value & (1 << CX20442_AGC)) ? -EINVAL : 0; +} + +static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 *reg_cache = codec->reg_cache; + int vls, vsp, old, len; + char buf[18]; + + if (reg >= codec->reg_cache_size) + return -EINVAL; + + if (!codec->hw_write || !codec->control_data) + return -EIO; + + old = reg_cache[reg]; + reg_cache[reg] = value; + + vls = cx20442_pm_to_v253_vls(value); + if (vls < 0) + return vls; + + vsp = cx20442_pm_to_v253_vsp(value); + if (vsp < 0 ) + return vsp; + + if ((vls == V253_VLS_T) || + (vls == cx20442_pm_to_v253_vls(old))) { + if (vsp == cx20442_pm_to_v253_vsp(old)) + return 0; + len = snprintf(buf, ARRAY_SIZE(buf), "at+vsp=%d\r", vsp); + } else if (vsp == cx20442_pm_to_v253_vsp(old)) + len = snprintf(buf, ARRAY_SIZE(buf), "at+vls=%d\r", vls); + else + len = snprintf(buf, ARRAY_SIZE(buf), + "at+vls=%d;+vsp=%d\r", vls, vsp); + + if (unlikely(len > (ARRAY_SIZE(buf) - 1))) + return -ENOMEM; + + if (codec->hw_write(codec->control_data, buf, len) != len) + return -EIO; + + return 0; +} + +struct snd_soc_dai cx20442_dai = { + .name = "CX20442", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}; +EXPORT_SYMBOL_GPL(cx20442_dai); + +static struct snd_soc_codec *cx20442_codec; + +static int cx20442_codec_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret; + + if(!cx20442_codec) { + dev_err(&pdev->dev, "cx20442 not yet discovered\n"); + return -ENODEV; + } + codec = cx20442_codec; + + socdev->card->codec = codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(&pdev->dev, "failed to create pcms\n"); + goto pcm_err; + } + + cx20442_add_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register card\n"); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +/* power down chip */ +static int cx20442_codec_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device cx20442_codec_dev = { + .probe = cx20442_codec_probe, + .remove = cx20442_codec_remove, +}; +EXPORT_SYMBOL_GPL(cx20442_codec_dev); + +static int cx20442_register(struct cx20442_priv *cx20442) +{ + struct snd_soc_codec *codec = &cx20442->codec; + int ret; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->name = "CX20442"; + codec->owner = THIS_MODULE; + codec->private_data = cx20442; + + codec->dai = &cx20442_dai; + codec->num_dai = 1; + + codec->reg_cache = &cx20442->reg_cache; + codec->reg_cache_size = ARRAY_SIZE(cx20442->reg_cache); + codec->read = cx20442_read_reg_cache; + codec->write = cx20442_write; + + codec->bias_level = SND_SOC_BIAS_OFF; + + cx20442_dai.dev = codec->dev; + + cx20442_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + //dev_err(&dev->dev, "Failed to register codec: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dai(&cx20442_dai); + if (ret != 0) { + //dev_err(&dev->dev, "Failed to register DAI: %d\n", ret); + goto err_codec; + } + + return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err: + cx20442_codec = NULL; + kfree(cx20442); + return ret; +} + +static void cx20442_unregister(struct cx20442_priv *cx20442) +{ + snd_soc_unregister_dai(&cx20442_dai); + snd_soc_unregister_codec(&cx20442->codec); + + cx20442_codec = NULL; + kfree(cx20442); +} + +static int cx20442_platform_probe(struct platform_device *pdev) +{ + struct cx20442_priv *cx20442; + struct snd_soc_codec *codec; + + cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL); + if (cx20442 == NULL) + return -ENOMEM; + + codec = &cx20442->codec; + + codec->control_data = NULL; + codec->hw_write = NULL; + codec->pop_time = 0; + + codec->dev = &pdev->dev; + platform_set_drvdata(pdev, cx20442); + + return cx20442_register(cx20442); +} + +static int __exit cx20442_platform_remove(struct platform_device *pdev) +{ + struct cx20442_priv *cx20442 = platform_get_drvdata(pdev); + + cx20442_unregister(cx20442); + return 0; +} + +static struct platform_driver cx20442_platform_driver = { + .driver = { + .name = "cx20442", + .owner = THIS_MODULE, + }, + .probe = cx20442_platform_probe, + .remove = __exit_p(cx20442_platform_remove), +}; + +static int __init cx20442_init(void) +{ + return platform_driver_register(&cx20442_platform_driver); +} +module_init(cx20442_init); + +static void __exit cx20442_exit(void) +{ + platform_driver_unregister(&cx20442_platform_driver); +} +module_exit(cx20442_exit); + +MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver"); +MODULE_AUTHOR("Janusz Krzysztofik"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cx20442-codec"); diff --git a/sound/soc/codecs/cx20442.h b/sound/soc/codecs/cx20442.h new file mode 100644 index 0000000..d0a4f29 --- /dev/null +++ b/sound/soc/codecs/cx20442.h @@ -0,0 +1,19 @@ +/* + * cx20442.h -- audio driver for CX20442 + * + * Copyright 2009 Janusz Krzysztofik + * + * 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. + * + */ + +#ifndef _CX20442_CODEC_H +#define _CX20442_CODEC_H + +extern struct snd_soc_dai cx20442_dai; +extern struct snd_soc_codec_device cx20442_codec_dev; + +#endif -- cgit v0.10.2 From a7569afa8b79ca9272b0d7544335bc05b5b721d6 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 23 Jul 2009 17:33:17 +0900 Subject: ASoC: MAX9877: fix write operation for register The MAX9877 needs an address of start register when we write values to registers through i2c_master_send(), but the code for this was missed in max9877_write_regs(). If the value of control is 0 in the max9877_set_out_mode(), the value is not increased to 1, but actually the value to write to the register should be 1. And the register bits for out_mode and osc_mode should be cleared before writing. Signed-off-by: Joonyoung Shim Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index a1f1119..9e7e964 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -25,7 +25,14 @@ static u8 max9877_regs[5] = { 0x40, 0x00, 0x00, 0x00, 0x49 }; static void max9877_write_regs(void) { - if (i2c_master_send(i2c, max9877_regs, 5) != 5) + unsigned int i; + u8 data[6]; + + data[0] = MAX9877_INPUT_MODE; + for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) + data[i + 1] = max9877_regs[i]; + + if (i2c_master_send(i2c, data, 6) != 6) dev_err(&i2c->dev, "i2c write failed\n"); } @@ -135,12 +142,12 @@ static int max9877_set_out_mode(struct snd_kcontrol *kcontrol, { u8 value = ucontrol->value.integer.value[0]; - if (value) - value += 1; + value += 1; if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK) == value) return 0; + max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OUTMODE_MASK; max9877_regs[MAX9877_OUTPUT_MODE] |= value; max9877_write_regs(); return 1; @@ -166,6 +173,7 @@ static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol, if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK) == value) return 0; + max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OSC_MASK; max9877_regs[MAX9877_OUTPUT_MODE] |= value; max9877_write_regs(); return 1; -- cgit v0.10.2 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 diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index a1895d7..4c95a6c 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 v0.10.2 From 474828a40f6ddab6e2a3475a19c5c84aa3ec7d60 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 22 Jul 2009 13:01:03 +0200 Subject: ALSA: Allow passing platform_data to devices attached to AC97 bus This patch allows passing platform_data to devices attached to AC97 bus (like touchscreens, battery measurement chips ...). Signed-off-by: Marek Vasut Signed-off-by: Mark Brown diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 251fc1c..9b1c098 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -642,4 +642,10 @@ int snd_ac97_pcm_double_rate_rules(struct snd_pcm_runtime *runtime); /* ad hoc AC97 device driver access */ extern struct bus_type ac97_bus_type; +/* AC97 platform_data adding function */ +static inline void snd_ac97_dev_add_pdata(struct snd_ac97 *ac97, void *data) +{ + ac97->dev.platform_data = data; +} + #endif /* __SOUND_AC97_CODEC_H */ diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 05991b0..25d62ac 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -179,6 +179,7 @@ struct snd_soc_dai { int ac97_control; struct device *dev; + void *ac97_pdata; /* platform_data for the ac97 codec */ /* DAI callbacks */ int (*probe)(struct platform_device *pdev, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8bf49a4..5eabb71 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1461,8 +1462,11 @@ int snd_soc_init_card(struct snd_soc_device *socdev) continue; } } - if (card->dai_link[i].codec_dai->ac97_control) + if (card->dai_link[i].codec_dai->ac97_control) { ac97 = 1; + snd_ac97_dev_add_pdata(codec->ac97, + card->dai_link[i].cpu_dai->ac97_pdata); + } } snprintf(codec->card->shortname, sizeof(codec->card->shortname), "%s", card->name); -- cgit v0.10.2 From 878fa89f97954337d1dc41f0ccc3a8b5f89cfbc7 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Wed, 22 Jul 2009 18:51:24 +0200 Subject: IEEE80154: Add documentation to the IEEE80154 netlink and fakehard driver This adds some perfunctory documentation comments to the IEEE 802.15.4 fakehard.c driver (Fake hard MAC) and the nl802154.h (outgoing netlink messages) header. These comments are not necessarily complete, but they do reference the IEEE 802.15.4-2006 document where possible. Signed-off-by: Daniel Silverstone diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 0384144..9ec07e8 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -31,6 +31,12 @@ #include #include +/** + * fake_get_pan_id - Retrieve the PAN ID of the device. + * @dev: The network device to retrieve the PAN of. + * + * Return the ID of the PAN from the PIB. + */ static u16 fake_get_pan_id(struct net_device *dev) { BUG_ON(dev->type != ARPHRD_IEEE802154); @@ -38,6 +44,14 @@ static u16 fake_get_pan_id(struct net_device *dev) return 0xeba1; } +/** + * fake_get_short_addr - Retrieve the short address of the device. + * @dev: The network device to retrieve the short address of. + * + * Returns the IEEE 802.15.4 short-form address cached for this + * device. If the device has not yet had a short address assigned + * then this should return 0xFFFF to indicate a lack of association. + */ static u16 fake_get_short_addr(struct net_device *dev) { BUG_ON(dev->type != ARPHRD_IEEE802154); @@ -45,6 +59,19 @@ static u16 fake_get_short_addr(struct net_device *dev) return 0x1; } +/** + * fake_get_dsn - Retrieve the DSN of the device. + * @dev: The network device to retrieve the DSN for. + * + * Returns the IEEE 802.15.4 DSN for the network device. + * The DSN is the sequence number which will be added to each + * packet or MAC command frame by the MAC during transmission. + * + * DSN means 'Data Sequence Number'. + * + * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006 + * document. + */ static u8 fake_get_dsn(struct net_device *dev) { BUG_ON(dev->type != ARPHRD_IEEE802154); @@ -52,6 +79,19 @@ static u8 fake_get_dsn(struct net_device *dev) return 0x00; /* DSN are implemented in HW, so return just 0 */ } +/** + * fake_get_bsn - Retrieve the BSN of the device. + * @dev: The network device to retrieve the BSN for. + * + * Returns the IEEE 802.15.4 BSN for the network device. + * The BSN is the sequence number which will be added to each + * beacon frame sent by the MAC. + * + * BSN means 'Beacon Sequence Number'. + * + * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006 + * document. + */ static u8 fake_get_bsn(struct net_device *dev) { BUG_ON(dev->type != ARPHRD_IEEE802154); @@ -59,6 +99,19 @@ static u8 fake_get_bsn(struct net_device *dev) return 0x00; /* BSN are implemented in HW, so return just 0 */ } +/** + * fake_assoc_req - Make an association request to the HW. + * @dev: The network device which we are associating to a network. + * @addr: The coordinator with which we wish to associate. + * @channel: The channel on which to associate. + * @cap: The capability information field to use in the association. + * + * Start an association with a coordinator. The coordinator's address + * and PAN ID can be found in @addr. + * + * Note: This is in section 7.3.1 and 7.5.3.1 of the IEEE + * 802.15.4-2006 document. + */ static int fake_assoc_req(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 cap) { @@ -67,18 +120,70 @@ static int fake_assoc_req(struct net_device *dev, IEEE802154_SUCCESS); } +/** + * fake_assoc_resp - Send an association response to a device. + * @dev: The network device on which to send the response. + * @addr: The address of the device to respond to. + * @short_addr: The assigned short address for the device (if any). + * @status: The result of the association request. + * + * Queue the association response of the coordinator to another + * device's attempt to associate with the network which we + * coordinate. This is then added to the indirect-send queue to be + * transmitted to the end device when it polls for data. + * + * Note: This is in section 7.3.2 and 7.5.3.1 of the IEEE + * 802.15.4-2006 document. + */ static int fake_assoc_resp(struct net_device *dev, struct ieee802154_addr *addr, u16 short_addr, u8 status) { return 0; } +/** + * fake_disassoc_req - Disassociate a device from a network. + * @dev: The network device on which we're disassociating a device. + * @addr: The device to disassociate from the network. + * @reason: The reason to give to the device for being disassociated. + * + * This sends a disassociation notification to the device being + * disassociated from the network. + * + * Note: This is in section 7.5.3.2 of the IEEE 802.15.4-2006 + * document, with the reason described in 7.3.3.2. + */ static int fake_disassoc_req(struct net_device *dev, struct ieee802154_addr *addr, u8 reason) { return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS); } +/** + * fake_start_req - Start an IEEE 802.15.4 PAN. + * @dev: The network device on which to start the PAN. + * @addr: The coordinator address to use when starting the PAN. + * @channel: The channel on which to start the PAN. + * @bcn_ord: Beacon order. + * @sf_ord: Superframe order. + * @pan_coord: Whether or not we are the PAN coordinator or just + * requesting a realignment perhaps? + * @blx: Battery Life Extension feature bitfield. + * @coord_realign: Something to realign something else. + * + * If pan_coord is non-zero then this starts a network with the + * provided parameters, otherwise it attempts a coordinator + * realignment of the stated network instead. + * + * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006 + * document, with 7.3.8 describing coordinator realignment. + * + * Note: There is currently no way to notify the coordinator userland + * program of whether or not the PAN has started successfully. As + * such, the coordinator program cannot know when the MAC has + * completed starting the network and will simply have to assume + * completeness based on some form of time delay. + */ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, @@ -87,6 +192,21 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, return 0; } +/** + * fake_scan_req - Start a channel scan. + * @dev: The network device on which to perform a channel scan. + * @type: The type of scan to perform. + * @channels: The channel bitmask to scan. + * @duration: How long to spend on each channel. + * + * This starts either a passive (energy) scan or an active (PAN) scan + * on the channels indicated in the @channels bitmask. The duration of + * the scan is measured in terms of superframe duration. Specifically, + * the scan will spend aBaseSuperFrameDuration * ((2^n) + 1) on each + * channel. + * + * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document. + */ static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, u8 duration) { diff --git a/include/net/ieee802154/nl802154.h b/include/net/ieee802154/nl802154.h index 78efcdf..6096096 100644 --- a/include/net/ieee802154/nl802154.h +++ b/include/net/ieee802154/nl802154.h @@ -24,17 +24,93 @@ struct net_device; struct ieee802154_addr; +/** + * ieee802154_nl_assoc_indic - Notify userland of an association request. + * @dev: The network device on which this association request was + * received. + * @addr: The address of the device requesting association. + * @cap: The capability information field from the device. + * + * This informs a userland coordinator of a device requesting to + * associate with the PAN controlled by the coordinator. + * + * Note: This is in section 7.3.1 of the IEEE 802.15.4-2006 document. + */ int ieee802154_nl_assoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 cap); + +/** + * ieee802154_nl_assoc_confirm - Notify userland of association. + * @dev: The device which has completed association. + * @short_addr: The short address assigned to the device. + * @status: The status of the association. + * + * Inform userland of the result of an association request. If the + * association request included asking the coordinator to allocate + * a short address then it is returned in @short_addr. + * + * Note: This is in section 7.3.2 of the IEEE 802.15.4 document. + */ int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, u8 status); + +/** + * ieee802154_nl_disassoc_indic - Notify userland of disassociation. + * @dev: The device on which disassociation was indicated. + * @addr: The device which is disassociating. + * @reason: The reason for the disassociation. + * + * Inform userland that a device has disassociated from the network. + * + * Note: This is in section 7.3.3 of the IEEE 802.15.4 document. + */ int ieee802154_nl_disassoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 reason); + +/** + * ieee802154_nl_disassoc_confirm - Notify userland of disassociation + * completion. + * @dev: The device on which disassociation was ordered. + * @status: The result of the disassociation. + * + * Inform userland of the result of requesting that a device + * disassociate, or the result of requesting that we disassociate from + * a PAN managed by another coordinator. + * + * Note: This is in section 7.1.4.3 of the IEEE 802.15.4 document. + */ int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status); + +/** + * ieee802154_nl_scan_confirm - Notify userland of completion of scan. + * @dev: The device which was instructed to scan. + * @status: The status of the scan operation. + * @scan_type: What type of scan was performed. + * @unscanned: Any channels that the device was unable to scan. + * @edl: The energy levels (if a passive scan). + * + * + * Note: This is in section 7.1.11 of the IEEE 802.15.4 document. + * Note: This API does not permit the return of an active scan result. + */ int ieee802154_nl_scan_confirm(struct net_device *dev, u8 status, u8 scan_type, u32 unscanned, u8 *edl/*, struct list_head *pan_desc_list */); + +/** + * ieee802154_nl_beacon_indic - Notify userland of a received beacon. + * @dev: The device on which a beacon was received. + * @panid: The PAN of the coordinator. + * @coord_addr: The short address of the coordinator on that PAN. + * + * Note: This is in section 7.1.5 of the IEEE 802.15.4 document. + * Note: This API does not provide extended information such as what + * channel the PAN is on or what the LQI of the beacon frame was on + * receipt. + * Note: This API cannot indicate a beacon frame for a coordinator + * operating in long addressing mode. + */ int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, u16 coord_addr); -- cgit v0.10.2 From f0166e5e3cdab66d5a31f796ce18e21fd3ce99dc Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 23 Jul 2009 16:56:29 +0400 Subject: ieee802154: move headers out of extra directory include/net/ieee802154/af_ieee802154.h (and others) naming seems to be too long and redundant. Drop one level of subdirectories. Signed-off-by: Dmitry Eremin-Solenikov diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 9ec07e8..8a52e6e 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -26,10 +26,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include /** * fake_get_pan_id - Retrieve the PAN ID of the device. diff --git a/include/net/af_ieee802154.h b/include/net/af_ieee802154.h new file mode 100644 index 0000000..0d78605 --- /dev/null +++ b/include/net/af_ieee802154.h @@ -0,0 +1,60 @@ +/* + * IEEE 802.15.4 inteface for userspace + * + * Copyright 2007, 2008 Siemens AG + * + * 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 published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + */ + +#ifndef _AF_IEEE802154_H +#define _AF_IEEE802154_H + +#include /* for sa_family_t */ + +enum { + IEEE802154_ADDR_NONE = 0x0, + /* RESERVED = 0x01, */ + IEEE802154_ADDR_SHORT = 0x2, /* 16-bit address + PANid */ + IEEE802154_ADDR_LONG = 0x3, /* 64-bit address + PANid */ +}; + +/* address length, octets */ +#define IEEE802154_ADDR_LEN 8 + +struct ieee802154_addr { + int addr_type; + u16 pan_id; + union { + u8 hwaddr[IEEE802154_ADDR_LEN]; + u16 short_addr; + }; +}; + +#define IEEE802154_PANID_BROADCAST 0xffff +#define IEEE802154_ADDR_BROADCAST 0xffff +#define IEEE802154_ADDR_UNDEF 0xfffe + +struct sockaddr_ieee802154 { + sa_family_t family; /* AF_IEEE802154 */ + struct ieee802154_addr addr; +}; + +/* master device */ +#define IEEE802154_SIOC_ADD_SLAVE (SIOCDEVPRIVATE + 0) + +#endif diff --git a/include/net/ieee802154.h b/include/net/ieee802154.h new file mode 100644 index 0000000..d52685d --- /dev/null +++ b/include/net/ieee802154.h @@ -0,0 +1,160 @@ +/* + * IEEE802.15.4-2003 specification + * + * Copyright (C) 2007, 2008 Siemens AG + * + * 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 published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Pavel Smolenskiy + * Maxim Gorbachyov + * Maxim Osipov + * Dmitry Eremin-Solenikov + */ + +#ifndef NET_IEEE802154_H +#define NET_IEEE802154_H + +#define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */ +#define IEEE802154_FC_TYPE_DATA 0x1 /* Frame is data */ +#define IEEE802154_FC_TYPE_ACK 0x2 /* Frame is acknowledgment */ +#define IEEE802154_FC_TYPE_MAC_CMD 0x3 /* Frame is MAC command */ + +#define IEEE802154_FC_TYPE_SHIFT 0 +#define IEEE802154_FC_TYPE_MASK ((1 << 3) - 1) +#define IEEE802154_FC_TYPE(x) ((x & IEEE802154_FC_TYPE_MASK) >> IEEE802154_FC_TYPE_SHIFT) +#define IEEE802154_FC_SET_TYPE(v, x) do { \ + v = (((v) & ~IEEE802154_FC_TYPE_MASK) | \ + (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \ + } while (0) + +#define IEEE802154_FC_SECEN (1 << 3) +#define IEEE802154_FC_FRPEND (1 << 4) +#define IEEE802154_FC_ACK_REQ (1 << 5) +#define IEEE802154_FC_INTRA_PAN (1 << 6) + +#define IEEE802154_FC_SAMODE_SHIFT 14 +#define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT) +#define IEEE802154_FC_DAMODE_SHIFT 10 +#define IEEE802154_FC_DAMODE_MASK (3 << IEEE802154_FC_DAMODE_SHIFT) + +#define IEEE802154_FC_SAMODE(x) \ + (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT) + +#define IEEE802154_FC_DAMODE(x) \ + (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT) + + +/* MAC's Command Frames Identifiers */ +#define IEEE802154_CMD_ASSOCIATION_REQ 0x01 +#define IEEE802154_CMD_ASSOCIATION_RESP 0x02 +#define IEEE802154_CMD_DISASSOCIATION_NOTIFY 0x03 +#define IEEE802154_CMD_DATA_REQ 0x04 +#define IEEE802154_CMD_PANID_CONFLICT_NOTIFY 0x05 +#define IEEE802154_CMD_ORPHAN_NOTIFY 0x06 +#define IEEE802154_CMD_BEACON_REQ 0x07 +#define IEEE802154_CMD_COORD_REALIGN_NOTIFY 0x08 +#define IEEE802154_CMD_GTS_REQ 0x09 + +/* + * The return values of MAC operations + */ +enum { + /* + * The requested operation was completed successfully. + * For a transmission request, this value indicates + * a successful transmission. + */ + IEEE802154_SUCCESS = 0x0, + + /* The beacon was lost following a synchronization request. */ + IEEE802154_BEACON_LOSS = 0xe0, + /* + * A transmission could not take place due to activity on the + * channel, i.e., the CSMA-CA mechanism has failed. + */ + IEEE802154_CHNL_ACCESS_FAIL = 0xe1, + /* The GTS request has been denied by the PAN coordinator. */ + IEEE802154_DENINED = 0xe2, + /* The attempt to disable the transceiver has failed. */ + IEEE802154_DISABLE_TRX_FAIL = 0xe3, + /* + * The received frame induces a failed security check according to + * the security suite. + */ + IEEE802154_FAILED_SECURITY_CHECK = 0xe4, + /* + * The frame resulting from secure processing has a length that is + * greater than aMACMaxFrameSize. + */ + IEEE802154_FRAME_TOO_LONG = 0xe5, + /* + * The requested GTS transmission failed because the specified GTS + * either did not have a transmit GTS direction or was not defined. + */ + IEEE802154_INVALID_GTS = 0xe6, + /* + * A request to purge an MSDU from the transaction queue was made using + * an MSDU handle that was not found in the transaction table. + */ + IEEE802154_INVALID_HANDLE = 0xe7, + /* A parameter in the primitive is out of the valid range.*/ + IEEE802154_INVALID_PARAMETER = 0xe8, + /* No acknowledgment was received after aMaxFrameRetries. */ + IEEE802154_NO_ACK = 0xe9, + /* A scan operation failed to find any network beacons.*/ + IEEE802154_NO_BEACON = 0xea, + /* No response data were available following a request. */ + IEEE802154_NO_DATA = 0xeb, + /* The operation failed because a short address was not allocated. */ + IEEE802154_NO_SHORT_ADDRESS = 0xec, + /* + * A receiver enable request was unsuccessful because it could not be + * completed within the CAP. + */ + IEEE802154_OUT_OF_CAP = 0xed, + /* + * A PAN identifier conflict has been detected and communicated to the + * PAN coordinator. + */ + IEEE802154_PANID_CONFLICT = 0xee, + /* A coordinator realignment command has been received. */ + IEEE802154_REALIGMENT = 0xef, + /* The transaction has expired and its information discarded. */ + IEEE802154_TRANSACTION_EXPIRED = 0xf0, + /* There is no capacity to store the transaction. */ + IEEE802154_TRANSACTION_OVERFLOW = 0xf1, + /* + * The transceiver was in the transmitter enabled state when the + * receiver was requested to be enabled. + */ + IEEE802154_TX_ACTIVE = 0xf2, + /* The appropriate key is not available in the ACL. */ + IEEE802154_UNAVAILABLE_KEY = 0xf3, + /* + * A SET/GET request was issued with the identifier of a PIB attribute + * that is not supported. + */ + IEEE802154_UNSUPPORTED_ATTR = 0xf4, + /* + * A request to perform a scan operation failed because the MLME was + * in the process of performing a previously initiated scan operation. + */ + IEEE802154_SCAN_IN_PROGRESS = 0xfc, +}; + + +#endif + + diff --git a/include/net/ieee802154/af_ieee802154.h b/include/net/ieee802154/af_ieee802154.h deleted file mode 100644 index 0d78605..0000000 --- a/include/net/ieee802154/af_ieee802154.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * IEEE 802.15.4 inteface for userspace - * - * Copyright 2007, 2008 Siemens AG - * - * 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 published by the Free Software Foundation. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Written by: - * Sergey Lapin - * Dmitry Eremin-Solenikov - */ - -#ifndef _AF_IEEE802154_H -#define _AF_IEEE802154_H - -#include /* for sa_family_t */ - -enum { - IEEE802154_ADDR_NONE = 0x0, - /* RESERVED = 0x01, */ - IEEE802154_ADDR_SHORT = 0x2, /* 16-bit address + PANid */ - IEEE802154_ADDR_LONG = 0x3, /* 64-bit address + PANid */ -}; - -/* address length, octets */ -#define IEEE802154_ADDR_LEN 8 - -struct ieee802154_addr { - int addr_type; - u16 pan_id; - union { - u8 hwaddr[IEEE802154_ADDR_LEN]; - u16 short_addr; - }; -}; - -#define IEEE802154_PANID_BROADCAST 0xffff -#define IEEE802154_ADDR_BROADCAST 0xffff -#define IEEE802154_ADDR_UNDEF 0xfffe - -struct sockaddr_ieee802154 { - sa_family_t family; /* AF_IEEE802154 */ - struct ieee802154_addr addr; -}; - -/* master device */ -#define IEEE802154_SIOC_ADD_SLAVE (SIOCDEVPRIVATE + 0) - -#endif diff --git a/include/net/ieee802154/mac_def.h b/include/net/ieee802154/mac_def.h deleted file mode 100644 index 8cb6846..0000000 --- a/include/net/ieee802154/mac_def.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * IEEE802.15.4-2003 specification - * - * Copyright (C) 2007, 2008 Siemens AG - * - * 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 published by the Free Software Foundation. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Written by: - * Pavel Smolenskiy - * Maxim Gorbachyov - * Maxim Osipov - * Dmitry Eremin-Solenikov - */ - -#ifndef IEEE802154_MAC_DEF_H -#define IEEE802154_MAC_DEF_H - -#define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */ -#define IEEE802154_FC_TYPE_DATA 0x1 /* Frame is data */ -#define IEEE802154_FC_TYPE_ACK 0x2 /* Frame is acknowledgment */ -#define IEEE802154_FC_TYPE_MAC_CMD 0x3 /* Frame is MAC command */ - -#define IEEE802154_FC_TYPE_SHIFT 0 -#define IEEE802154_FC_TYPE_MASK ((1 << 3) - 1) -#define IEEE802154_FC_TYPE(x) ((x & IEEE802154_FC_TYPE_MASK) >> IEEE802154_FC_TYPE_SHIFT) -#define IEEE802154_FC_SET_TYPE(v, x) do { \ - v = (((v) & ~IEEE802154_FC_TYPE_MASK) | \ - (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \ - } while (0) - -#define IEEE802154_FC_SECEN (1 << 3) -#define IEEE802154_FC_FRPEND (1 << 4) -#define IEEE802154_FC_ACK_REQ (1 << 5) -#define IEEE802154_FC_INTRA_PAN (1 << 6) - -#define IEEE802154_FC_SAMODE_SHIFT 14 -#define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT) -#define IEEE802154_FC_DAMODE_SHIFT 10 -#define IEEE802154_FC_DAMODE_MASK (3 << IEEE802154_FC_DAMODE_SHIFT) - -#define IEEE802154_FC_SAMODE(x) \ - (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT) - -#define IEEE802154_FC_DAMODE(x) \ - (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT) - - -/* MAC's Command Frames Identifiers */ -#define IEEE802154_CMD_ASSOCIATION_REQ 0x01 -#define IEEE802154_CMD_ASSOCIATION_RESP 0x02 -#define IEEE802154_CMD_DISASSOCIATION_NOTIFY 0x03 -#define IEEE802154_CMD_DATA_REQ 0x04 -#define IEEE802154_CMD_PANID_CONFLICT_NOTIFY 0x05 -#define IEEE802154_CMD_ORPHAN_NOTIFY 0x06 -#define IEEE802154_CMD_BEACON_REQ 0x07 -#define IEEE802154_CMD_COORD_REALIGN_NOTIFY 0x08 -#define IEEE802154_CMD_GTS_REQ 0x09 - -/* - * The return values of MAC operations - */ -enum { - /* - * The requested operation was completed successfully. - * For a transmission request, this value indicates - * a successful transmission. - */ - IEEE802154_SUCCESS = 0x0, - - /* The beacon was lost following a synchronization request. */ - IEEE802154_BEACON_LOSS = 0xe0, - /* - * A transmission could not take place due to activity on the - * channel, i.e., the CSMA-CA mechanism has failed. - */ - IEEE802154_CHNL_ACCESS_FAIL = 0xe1, - /* The GTS request has been denied by the PAN coordinator. */ - IEEE802154_DENINED = 0xe2, - /* The attempt to disable the transceiver has failed. */ - IEEE802154_DISABLE_TRX_FAIL = 0xe3, - /* - * The received frame induces a failed security check according to - * the security suite. - */ - IEEE802154_FAILED_SECURITY_CHECK = 0xe4, - /* - * The frame resulting from secure processing has a length that is - * greater than aMACMaxFrameSize. - */ - IEEE802154_FRAME_TOO_LONG = 0xe5, - /* - * The requested GTS transmission failed because the specified GTS - * either did not have a transmit GTS direction or was not defined. - */ - IEEE802154_INVALID_GTS = 0xe6, - /* - * A request to purge an MSDU from the transaction queue was made using - * an MSDU handle that was not found in the transaction table. - */ - IEEE802154_INVALID_HANDLE = 0xe7, - /* A parameter in the primitive is out of the valid range.*/ - IEEE802154_INVALID_PARAMETER = 0xe8, - /* No acknowledgment was received after aMaxFrameRetries. */ - IEEE802154_NO_ACK = 0xe9, - /* A scan operation failed to find any network beacons.*/ - IEEE802154_NO_BEACON = 0xea, - /* No response data were available following a request. */ - IEEE802154_NO_DATA = 0xeb, - /* The operation failed because a short address was not allocated. */ - IEEE802154_NO_SHORT_ADDRESS = 0xec, - /* - * A receiver enable request was unsuccessful because it could not be - * completed within the CAP. - */ - IEEE802154_OUT_OF_CAP = 0xed, - /* - * A PAN identifier conflict has been detected and communicated to the - * PAN coordinator. - */ - IEEE802154_PANID_CONFLICT = 0xee, - /* A coordinator realignment command has been received. */ - IEEE802154_REALIGMENT = 0xef, - /* The transaction has expired and its information discarded. */ - IEEE802154_TRANSACTION_EXPIRED = 0xf0, - /* There is no capacity to store the transaction. */ - IEEE802154_TRANSACTION_OVERFLOW = 0xf1, - /* - * The transceiver was in the transmitter enabled state when the - * receiver was requested to be enabled. - */ - IEEE802154_TX_ACTIVE = 0xf2, - /* The appropriate key is not available in the ACL. */ - IEEE802154_UNAVAILABLE_KEY = 0xf3, - /* - * A SET/GET request was issued with the identifier of a PIB attribute - * that is not supported. - */ - IEEE802154_UNSUPPORTED_ATTR = 0xf4, - /* - * A request to perform a scan operation failed because the MLME was - * in the process of performing a previously initiated scan operation. - */ - IEEE802154_SCAN_IN_PROGRESS = 0xfc, -}; - - -#endif - - diff --git a/include/net/ieee802154/netdevice.h b/include/net/ieee802154/netdevice.h deleted file mode 100644 index e2506af..0000000 --- a/include/net/ieee802154/netdevice.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * An interface between IEEE802.15.4 device and rest of the kernel. - * - * Copyright (C) 2007, 2008, 2009 Siemens AG - * - * 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 published by the Free Software Foundation. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Written by: - * Pavel Smolenskiy - * Maxim Gorbachyov - * Maxim Osipov - * Dmitry Eremin-Solenikov - */ - -#ifndef IEEE802154_NETDEVICE_H -#define IEEE802154_NETDEVICE_H - -/* - * A control block of skb passed between the ARPHRD_IEEE802154 device - * and other stack parts. - */ -struct ieee802154_mac_cb { - u8 lqi; - struct ieee802154_addr sa; - struct ieee802154_addr da; - u8 flags; - u8 seq; -}; - -static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb) -{ - return (struct ieee802154_mac_cb *)skb->cb; -} - -#define MAC_CB_FLAG_TYPEMASK ((1 << 3) - 1) - -#define MAC_CB_FLAG_ACKREQ (1 << 3) -#define MAC_CB_FLAG_SECEN (1 << 4) -#define MAC_CB_FLAG_INTRAPAN (1 << 5) - -static inline int mac_cb_is_ackreq(struct sk_buff *skb) -{ - return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ; -} - -static inline int mac_cb_is_secen(struct sk_buff *skb) -{ - return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN; -} - -static inline int mac_cb_is_intrapan(struct sk_buff *skb) -{ - return mac_cb(skb)->flags & MAC_CB_FLAG_INTRAPAN; -} - -static inline int mac_cb_type(struct sk_buff *skb) -{ - return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK; -} - -#define IEEE802154_MAC_SCAN_ED 0 -#define IEEE802154_MAC_SCAN_ACTIVE 1 -#define IEEE802154_MAC_SCAN_PASSIVE 2 -#define IEEE802154_MAC_SCAN_ORPHAN 3 - -/* - * This should be located at net_device->ml_priv - */ -struct ieee802154_mlme_ops { - int (*assoc_req)(struct net_device *dev, - struct ieee802154_addr *addr, - u8 channel, u8 cap); - int (*assoc_resp)(struct net_device *dev, - struct ieee802154_addr *addr, - u16 short_addr, u8 status); - int (*disassoc_req)(struct net_device *dev, - struct ieee802154_addr *addr, - u8 reason); - int (*start_req)(struct net_device *dev, - struct ieee802154_addr *addr, - u8 channel, u8 bcn_ord, u8 sf_ord, - u8 pan_coord, u8 blx, u8 coord_realign); - int (*scan_req)(struct net_device *dev, - u8 type, u32 channels, u8 duration); - - /* - * FIXME: these should become the part of PIB/MIB interface. - * However we still don't have IB interface of any kind - */ - u16 (*get_pan_id)(struct net_device *dev); - u16 (*get_short_addr)(struct net_device *dev); - u8 (*get_dsn)(struct net_device *dev); - u8 (*get_bsn)(struct net_device *dev); -}; - -static inline struct ieee802154_mlme_ops *ieee802154_mlme_ops( - struct net_device *dev) -{ - return dev->ml_priv; -} - -#endif - - diff --git a/include/net/ieee802154/nl802154.h b/include/net/ieee802154/nl802154.h deleted file mode 100644 index 6096096..0000000 --- a/include/net/ieee802154/nl802154.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * nl802154.h - * - * Copyright (C) 2007, 2008, 2009 Siemens AG - * - * 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 published by the Free Software Foundation. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#ifndef IEEE802154_NL_H -#define IEEE802154_NL_H - -struct net_device; -struct ieee802154_addr; - -/** - * ieee802154_nl_assoc_indic - Notify userland of an association request. - * @dev: The network device on which this association request was - * received. - * @addr: The address of the device requesting association. - * @cap: The capability information field from the device. - * - * This informs a userland coordinator of a device requesting to - * associate with the PAN controlled by the coordinator. - * - * Note: This is in section 7.3.1 of the IEEE 802.15.4-2006 document. - */ -int ieee802154_nl_assoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 cap); - -/** - * ieee802154_nl_assoc_confirm - Notify userland of association. - * @dev: The device which has completed association. - * @short_addr: The short address assigned to the device. - * @status: The status of the association. - * - * Inform userland of the result of an association request. If the - * association request included asking the coordinator to allocate - * a short address then it is returned in @short_addr. - * - * Note: This is in section 7.3.2 of the IEEE 802.15.4 document. - */ -int ieee802154_nl_assoc_confirm(struct net_device *dev, - u16 short_addr, u8 status); - -/** - * ieee802154_nl_disassoc_indic - Notify userland of disassociation. - * @dev: The device on which disassociation was indicated. - * @addr: The device which is disassociating. - * @reason: The reason for the disassociation. - * - * Inform userland that a device has disassociated from the network. - * - * Note: This is in section 7.3.3 of the IEEE 802.15.4 document. - */ -int ieee802154_nl_disassoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 reason); - -/** - * ieee802154_nl_disassoc_confirm - Notify userland of disassociation - * completion. - * @dev: The device on which disassociation was ordered. - * @status: The result of the disassociation. - * - * Inform userland of the result of requesting that a device - * disassociate, or the result of requesting that we disassociate from - * a PAN managed by another coordinator. - * - * Note: This is in section 7.1.4.3 of the IEEE 802.15.4 document. - */ -int ieee802154_nl_disassoc_confirm(struct net_device *dev, - u8 status); - -/** - * ieee802154_nl_scan_confirm - Notify userland of completion of scan. - * @dev: The device which was instructed to scan. - * @status: The status of the scan operation. - * @scan_type: What type of scan was performed. - * @unscanned: Any channels that the device was unable to scan. - * @edl: The energy levels (if a passive scan). - * - * - * Note: This is in section 7.1.11 of the IEEE 802.15.4 document. - * Note: This API does not permit the return of an active scan result. - */ -int ieee802154_nl_scan_confirm(struct net_device *dev, - u8 status, u8 scan_type, u32 unscanned, - u8 *edl/*, struct list_head *pan_desc_list */); - -/** - * ieee802154_nl_beacon_indic - Notify userland of a received beacon. - * @dev: The device on which a beacon was received. - * @panid: The PAN of the coordinator. - * @coord_addr: The short address of the coordinator on that PAN. - * - * Note: This is in section 7.1.5 of the IEEE 802.15.4 document. - * Note: This API does not provide extended information such as what - * channel the PAN is on or what the LQI of the beacon frame was on - * receipt. - * Note: This API cannot indicate a beacon frame for a coordinator - * operating in long addressing mode. - */ -int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, - u16 coord_addr); - -#endif diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h new file mode 100644 index 0000000..e2506af --- /dev/null +++ b/include/net/ieee802154_netdev.h @@ -0,0 +1,115 @@ +/* + * An interface between IEEE802.15.4 device and rest of the kernel. + * + * Copyright (C) 2007, 2008, 2009 Siemens AG + * + * 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 published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Pavel Smolenskiy + * Maxim Gorbachyov + * Maxim Osipov + * Dmitry Eremin-Solenikov + */ + +#ifndef IEEE802154_NETDEVICE_H +#define IEEE802154_NETDEVICE_H + +/* + * A control block of skb passed between the ARPHRD_IEEE802154 device + * and other stack parts. + */ +struct ieee802154_mac_cb { + u8 lqi; + struct ieee802154_addr sa; + struct ieee802154_addr da; + u8 flags; + u8 seq; +}; + +static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb) +{ + return (struct ieee802154_mac_cb *)skb->cb; +} + +#define MAC_CB_FLAG_TYPEMASK ((1 << 3) - 1) + +#define MAC_CB_FLAG_ACKREQ (1 << 3) +#define MAC_CB_FLAG_SECEN (1 << 4) +#define MAC_CB_FLAG_INTRAPAN (1 << 5) + +static inline int mac_cb_is_ackreq(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ; +} + +static inline int mac_cb_is_secen(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN; +} + +static inline int mac_cb_is_intrapan(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_INTRAPAN; +} + +static inline int mac_cb_type(struct sk_buff *skb) +{ + return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK; +} + +#define IEEE802154_MAC_SCAN_ED 0 +#define IEEE802154_MAC_SCAN_ACTIVE 1 +#define IEEE802154_MAC_SCAN_PASSIVE 2 +#define IEEE802154_MAC_SCAN_ORPHAN 3 + +/* + * This should be located at net_device->ml_priv + */ +struct ieee802154_mlme_ops { + int (*assoc_req)(struct net_device *dev, + struct ieee802154_addr *addr, + u8 channel, u8 cap); + int (*assoc_resp)(struct net_device *dev, + struct ieee802154_addr *addr, + u16 short_addr, u8 status); + int (*disassoc_req)(struct net_device *dev, + struct ieee802154_addr *addr, + u8 reason); + int (*start_req)(struct net_device *dev, + struct ieee802154_addr *addr, + u8 channel, u8 bcn_ord, u8 sf_ord, + u8 pan_coord, u8 blx, u8 coord_realign); + int (*scan_req)(struct net_device *dev, + u8 type, u32 channels, u8 duration); + + /* + * FIXME: these should become the part of PIB/MIB interface. + * However we still don't have IB interface of any kind + */ + u16 (*get_pan_id)(struct net_device *dev); + u16 (*get_short_addr)(struct net_device *dev); + u8 (*get_dsn)(struct net_device *dev); + u8 (*get_bsn)(struct net_device *dev); +}; + +static inline struct ieee802154_mlme_ops *ieee802154_mlme_ops( + struct net_device *dev) +{ + return dev->ml_priv; +} + +#endif + + diff --git a/include/net/nl802154.h b/include/net/nl802154.h new file mode 100644 index 0000000..6096096 --- /dev/null +++ b/include/net/nl802154.h @@ -0,0 +1,117 @@ +/* + * nl802154.h + * + * Copyright (C) 2007, 2008, 2009 Siemens AG + * + * 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 published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef IEEE802154_NL_H +#define IEEE802154_NL_H + +struct net_device; +struct ieee802154_addr; + +/** + * ieee802154_nl_assoc_indic - Notify userland of an association request. + * @dev: The network device on which this association request was + * received. + * @addr: The address of the device requesting association. + * @cap: The capability information field from the device. + * + * This informs a userland coordinator of a device requesting to + * associate with the PAN controlled by the coordinator. + * + * Note: This is in section 7.3.1 of the IEEE 802.15.4-2006 document. + */ +int ieee802154_nl_assoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 cap); + +/** + * ieee802154_nl_assoc_confirm - Notify userland of association. + * @dev: The device which has completed association. + * @short_addr: The short address assigned to the device. + * @status: The status of the association. + * + * Inform userland of the result of an association request. If the + * association request included asking the coordinator to allocate + * a short address then it is returned in @short_addr. + * + * Note: This is in section 7.3.2 of the IEEE 802.15.4 document. + */ +int ieee802154_nl_assoc_confirm(struct net_device *dev, + u16 short_addr, u8 status); + +/** + * ieee802154_nl_disassoc_indic - Notify userland of disassociation. + * @dev: The device on which disassociation was indicated. + * @addr: The device which is disassociating. + * @reason: The reason for the disassociation. + * + * Inform userland that a device has disassociated from the network. + * + * Note: This is in section 7.3.3 of the IEEE 802.15.4 document. + */ +int ieee802154_nl_disassoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 reason); + +/** + * ieee802154_nl_disassoc_confirm - Notify userland of disassociation + * completion. + * @dev: The device on which disassociation was ordered. + * @status: The result of the disassociation. + * + * Inform userland of the result of requesting that a device + * disassociate, or the result of requesting that we disassociate from + * a PAN managed by another coordinator. + * + * Note: This is in section 7.1.4.3 of the IEEE 802.15.4 document. + */ +int ieee802154_nl_disassoc_confirm(struct net_device *dev, + u8 status); + +/** + * ieee802154_nl_scan_confirm - Notify userland of completion of scan. + * @dev: The device which was instructed to scan. + * @status: The status of the scan operation. + * @scan_type: What type of scan was performed. + * @unscanned: Any channels that the device was unable to scan. + * @edl: The energy levels (if a passive scan). + * + * + * Note: This is in section 7.1.11 of the IEEE 802.15.4 document. + * Note: This API does not permit the return of an active scan result. + */ +int ieee802154_nl_scan_confirm(struct net_device *dev, + u8 status, u8 scan_type, u32 unscanned, + u8 *edl/*, struct list_head *pan_desc_list */); + +/** + * ieee802154_nl_beacon_indic - Notify userland of a received beacon. + * @dev: The device on which a beacon was received. + * @panid: The PAN of the coordinator. + * @coord_addr: The short address of the coordinator on that PAN. + * + * Note: This is in section 7.1.5 of the IEEE 802.15.4 document. + * Note: This API does not provide extended information such as what + * channel the PAN is on or what the LQI of the beacon frame was on + * receipt. + * Note: This API cannot indicate a beacon frame for a coordinator + * operating in long addressing mode. + */ +int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, + u16 coord_addr); + +#endif diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index 3bb6bdb..69c8d92 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c @@ -34,8 +34,8 @@ #include #include -#include -#include +#include +#include #include "af802154.h" diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 14d3984..53dd912 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -26,9 +26,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 27eda9f..a615b9d 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -27,9 +27,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include static unsigned int ieee802154_seq_num; diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index fca44d5..ea8d1f1 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include "af802154.h" -- cgit v0.10.2 From c1dc13e9d0bc35a8d85bf4238c48c1b627d48f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Tue, 21 Jul 2009 01:57:57 +0000 Subject: Phonet: sockets list through proc_fs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This provides a list of sockets with their Phonet bind addresses and some socket debug informations through /proc/net/phonet. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h index 29d1267..44c923c 100644 --- a/include/net/phonet/pn_dev.h +++ b/include/net/phonet/pn_dev.h @@ -49,4 +49,6 @@ void phonet_address_notify(int event, struct net_device *dev, u8 addr); #define PN_NO_ADDR 0xff +extern const struct file_operations pn_sock_seq_fops; + #endif diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index b0d6ddd..5107b79 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -218,6 +218,11 @@ static int phonet_init_net(struct net *net) if (!pnn) return -ENOMEM; + if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops)) { + kfree(pnn); + return -ENOMEM; + } + INIT_LIST_HEAD(&pnn->pndevs.list); spin_lock_init(&pnn->pndevs.lock); net_assign_generic(net, phonet_net_id, pnn); @@ -233,6 +238,8 @@ static void phonet_exit_net(struct net *net) for_each_netdev(net, dev) phonet_device_destroy(dev); rtnl_unlock(); + + proc_net_remove(net, "phonet"); kfree(pnn); } diff --git a/net/phonet/socket.c b/net/phonet/socket.c index ada2a35..aa1617a 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -412,3 +412,99 @@ found: return 0; } EXPORT_SYMBOL(pn_sock_get_port); + +static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos) +{ + struct net *net = seq_file_net(seq); + struct hlist_node *node; + struct sock *sknode; + + sk_for_each(sknode, node, &pnsocks.hlist) { + if (!net_eq(net, sock_net(sknode))) + continue; + if (!pos) + return sknode; + pos--; + } + return NULL; +} + +static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk) +{ + struct net *net = seq_file_net(seq); + + do + sk = sk_next(sk); + while (sk && !net_eq(net, sock_net(sk))); + + return sk; +} + +static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(pnsocks.lock) +{ + spin_lock_bh(&pnsocks.lock); + return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; +} + +static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct sock *sk; + + if (v == SEQ_START_TOKEN) + sk = pn_sock_get_idx(seq, 0); + else + sk = pn_sock_get_next(seq, v); + (*pos)++; + return sk; +} + +static void pn_sock_seq_stop(struct seq_file *seq, void *v) + __releases(pnsocks.lock) +{ + spin_unlock_bh(&pnsocks.lock); +} + +static int pn_sock_seq_show(struct seq_file *seq, void *v) +{ + int len; + + if (v == SEQ_START_TOKEN) + seq_printf(seq, "%s%n", "pt loc rem rs st tx_queue rx_queue " + " uid inode ref pointer drops", &len); + else { + struct sock *sk = v; + struct pn_sock *pn = pn_sk(sk); + + seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu " + "%d %p %d%n", + sk->sk_protocol, pn->sobject, 0, pn->resource, + sk->sk_state, + sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk), + sock_i_uid(sk), sock_i_ino(sk), + atomic_read(&sk->sk_refcnt), sk, + atomic_read(&sk->sk_drops), &len); + } + seq_printf(seq, "%*s\n", 127 - len, ""); + return 0; +} + +static const struct seq_operations pn_sock_seq_ops = { + .start = pn_sock_seq_start, + .next = pn_sock_seq_next, + .stop = pn_sock_seq_stop, + .show = pn_sock_seq_show, +}; + +static int pn_sock_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &pn_sock_seq_ops); +} + +const struct file_operations pn_sock_seq_fops = { + .owner = THIS_MODULE, + .open = pn_sock_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; -- cgit v0.10.2 From 2e2fb4b33d62c742019774c5e6e47711a3d60505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Tue, 21 Jul 2009 01:57:59 +0000 Subject: Phonet: account for dropped RX packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/net/phonet/pep.c b/net/phonet/pep.c index eef833e..b8252d2 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -346,8 +346,10 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) break; case PNS_PEP_CTRL_REQ: - if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) + if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) { + atomic_inc(&sk->sk_drops); break; + } __skb_pull(skb, 4); queue = &pn->ctrlreq_queue; goto queue; @@ -358,10 +360,13 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) err = sock_queue_rcv_skb(sk, skb); if (!err) return 0; + if (err == -ENOMEM) + atomic_inc(&sk->sk_drops); break; } if (pn->rx_credits == 0) { + atomic_inc(&sk->sk_drops); err = -ENOBUFS; break; } -- cgit v0.10.2 From 2eee40c7f7c3734b28456169b2945e07d5ac0e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Tue, 21 Jul 2009 01:57:58 +0000 Subject: Phonet: dropped datagrams accounting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The per-socket drop count is visible via /proc/net/phonet. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c index e087862..ef5c75c 100644 --- a/net/phonet/datagram.c +++ b/net/phonet/datagram.c @@ -159,8 +159,11 @@ out_nofree: static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb) { int err = sock_queue_rcv_skb(sk, skb); - if (err < 0) + if (err < 0) { kfree_skb(skb); + if (err == -ENOMEM) + atomic_inc(&sk->sk_drops); + } return err ? NET_RX_DROP : NET_RX_SUCCESS; } -- cgit v0.10.2 From 5be93b9a865344cf69958777c8d7c6f758cba416 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 21 Jul 2009 12:36:19 -0700 Subject: be2net: Add GRO support to the be2net driver. LRO is not supported anymore. This patch removes support for INET_LRO and switches over to GRO. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/Kconfig b/drivers/net/benet/Kconfig index c6934f1..fdb6e81 100644 --- a/drivers/net/benet/Kconfig +++ b/drivers/net/benet/Kconfig @@ -1,7 +1,6 @@ config BE2NET tristate "ServerEngines' 10Gbps NIC - BladeEngine 2" depends on PCI && INET - select INET_LRO help This driver implements the NIC functionality for ServerEngines' 10Gbps network adapter - BladeEngine 2. diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 5b4bf3d..41cddbe 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -28,11 +28,10 @@ #include #include #include -#include #include "be_hw.h" -#define DRV_VER "2.0.348" +#define DRV_VER "2.0.400" #define DRV_NAME "be2net" #define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" #define OC_NAME "Emulex OneConnect 10Gbps NIC" @@ -72,9 +71,6 @@ static inline char *nic_name(struct pci_dev *pdev) #define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST) -#define BE_MAX_LRO_DESCRIPTORS 16 -#define BE_MAX_FRAGS_PER_FRAME (min((u32) 16, (u32) MAX_SKB_FRAGS)) - struct be_dma_mem { void *va; dma_addr_t dma; @@ -189,8 +185,6 @@ struct be_drvr_stats { u32 be_polls; /* number of times NAPI called poll function */ u32 be_rx_events; /* number of ucast rx completion events */ u32 be_rx_compl; /* number of rx completion entries processed */ - u32 be_lro_hgram_data[8]; /* histogram of LRO data packets */ - u32 be_lro_hgram_ack[8]; /* histogram of LRO ACKs */ ulong be_rx_jiffies; u64 be_rx_bytes; u64 be_rx_bytes_prev; @@ -233,8 +227,6 @@ struct be_rx_obj { struct be_queue_info q; struct be_queue_info cq; struct be_rx_page_info page_info_tbl[RX_Q_LEN]; - struct net_lro_mgr lro_mgr; - struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS]; }; #define BE_NUM_MSIX_VECTORS 2 /* 1 each for Tx and Rx */ @@ -271,7 +263,6 @@ struct be_adapter { /* Ethtool knobs and info */ bool rx_csum; /* BE card must perform rx-checksumming */ - u32 max_rx_coal; char fw_ver[FW_VER_LEN]; u32 if_handle; /* Used to configure filtering */ u32 pmac_id; /* MAC addr handle used by BE card */ diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index cccc541..f3f0f91 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -127,8 +127,6 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; - coalesce->rx_max_coalesced_frames = adapter->max_rx_coal; - coalesce->rx_coalesce_usecs = rx_eq->cur_eqd; coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd; coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd; @@ -144,8 +142,7 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) } /* - * This routine is used to set interrup coalescing delay *as well as* - * the number of pkts to coalesce for LRO. + * This routine is used to set interrup coalescing delay */ static int be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) @@ -161,10 +158,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) if (coalesce->use_adaptive_tx_coalesce == 1) return -EINVAL; - adapter->max_rx_coal = coalesce->rx_max_coalesced_frames; - if (adapter->max_rx_coal > BE_MAX_FRAGS_PER_FRAME) - adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME; - /* if AIC is being turned on now, start with an EQD of 0 */ if (rx_eq->enable_aic == 0 && coalesce->use_adaptive_rx_coalesce == 1) { diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index c43f6a1..45df8e2 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -742,7 +742,7 @@ done: return; } -/* Process the RX completion indicated by rxcp when LRO is disabled */ +/* Process the RX completion indicated by rxcp when GRO is disabled */ static void be_rx_compl_process(struct be_adapter *adapter, struct be_eth_rx_compl *rxcp) { @@ -789,13 +789,14 @@ static void be_rx_compl_process(struct be_adapter *adapter, return; } -/* Process the RX completion indicated by rxcp when LRO is enabled */ -static void be_rx_compl_process_lro(struct be_adapter *adapter, +/* Process the RX completion indicated by rxcp when GRO is enabled */ +static void be_rx_compl_process_gro(struct be_adapter *adapter, struct be_eth_rx_compl *rxcp) { struct be_rx_page_info *page_info; - struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME]; + struct sk_buff *skb = NULL; struct be_queue_info *rxq = &adapter->rx_obj.q; + struct be_eq_obj *eq_obj = &adapter->rx_eq; u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len; u16 i, rxq_idx = 0, vid, j; @@ -804,6 +805,12 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter, vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); + skb = napi_get_frags(&eq_obj->napi); + if (!skb) { + be_rx_compl_discard(adapter, rxcp); + return; + } + remaining = pkt_size; for (i = 0, j = -1; i < num_rcvd; i++) { page_info = get_rx_page_info(adapter, rxq_idx); @@ -814,13 +821,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter, if (i == 0 || page_info->page_offset == 0) { /* First frag or Fresh page */ j++; - rx_frags[j].page = page_info->page; - rx_frags[j].page_offset = page_info->page_offset; - rx_frags[j].size = 0; + skb_shinfo(skb)->frags[j].page = page_info->page; + skb_shinfo(skb)->frags[j].page_offset = + page_info->page_offset; + skb_shinfo(skb)->frags[j].size = 0; } else { put_page(page_info->page); } - rx_frags[j].size += curr_frag_len; + skb_shinfo(skb)->frags[j].size += curr_frag_len; remaining -= curr_frag_len; index_inc(&rxq_idx, rxq->len); @@ -828,9 +836,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter, } BUG_ON(j > MAX_SKB_FRAGS); + skb_shinfo(skb)->nr_frags = j + 1; + skb->len = pkt_size; + skb->data_len = pkt_size; + skb->truesize += pkt_size; + skb->ip_summed = CHECKSUM_UNNECESSARY; + if (likely(!vlanf)) { - lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size, - pkt_size, NULL, 0); + napi_gro_frags(&eq_obj->napi); } else { vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp); vid = be16_to_cpu(vid); @@ -838,9 +851,7 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter, if (!adapter->vlan_grp || adapter->num_vlans == 0) return; - lro_vlan_hwaccel_receive_frags(&adapter->rx_obj.lro_mgr, - rx_frags, pkt_size, pkt_size, adapter->vlan_grp, - vid, NULL, 0); + vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid); } be_rx_stats_update(adapter, pkt_size, num_rcvd); @@ -1183,7 +1194,6 @@ static int be_rx_queues_create(struct be_adapter *adapter) struct be_queue_info *eq, *q, *cq; int rc; - adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME; adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE; adapter->rx_eq.max_eqd = BE_MAX_EQD; adapter->rx_eq.min_eqd = 0; @@ -1305,7 +1315,7 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev) return IRQ_HANDLED; } -static inline bool do_lro(struct be_adapter *adapter, +static inline bool do_gro(struct be_adapter *adapter, struct be_eth_rx_compl *rxcp) { int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp); @@ -1314,8 +1324,7 @@ static inline bool do_lro(struct be_adapter *adapter, if (err) drvr_stats(adapter)->be_rxcp_err++; - return (!tcp_frame || err || (adapter->max_rx_coal <= 1)) ? - false : true; + return (tcp_frame && !err) ? true : false; } int be_poll_rx(struct napi_struct *napi, int budget) @@ -1332,16 +1341,14 @@ int be_poll_rx(struct napi_struct *napi, int budget) if (!rxcp) break; - if (do_lro(adapter, rxcp)) - be_rx_compl_process_lro(adapter, rxcp); + if (do_gro(adapter, rxcp)) + be_rx_compl_process_gro(adapter, rxcp); else be_rx_compl_process(adapter, rxcp); be_rx_compl_reset(rxcp); } - lro_flush_all(&adapter->rx_obj.lro_mgr); - /* Refill the queue */ if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM) be_post_rx_frags(adapter); @@ -1656,57 +1663,6 @@ static int be_close(struct net_device *netdev) return 0; } -static int be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, - void **ip_hdr, void **tcpudp_hdr, - u64 *hdr_flags, void *priv) -{ - struct ethhdr *eh; - struct vlan_ethhdr *veh; - struct iphdr *iph; - u8 *va = page_address(frag->page) + frag->page_offset; - unsigned long ll_hlen; - - prefetch(va); - eh = (struct ethhdr *)va; - *mac_hdr = eh; - ll_hlen = ETH_HLEN; - if (eh->h_proto != htons(ETH_P_IP)) { - if (eh->h_proto == htons(ETH_P_8021Q)) { - veh = (struct vlan_ethhdr *)va; - if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP)) - return -1; - - ll_hlen += VLAN_HLEN; - } else { - return -1; - } - } - *hdr_flags = LRO_IPV4; - iph = (struct iphdr *)(va + ll_hlen); - *ip_hdr = iph; - if (iph->protocol != IPPROTO_TCP) - return -1; - *hdr_flags |= LRO_TCP; - *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2); - - return 0; -} - -static void be_lro_init(struct be_adapter *adapter, struct net_device *netdev) -{ - struct net_lro_mgr *lro_mgr; - - lro_mgr = &adapter->rx_obj.lro_mgr; - lro_mgr->dev = netdev; - lro_mgr->features = LRO_F_NAPI; - lro_mgr->ip_summed = CHECKSUM_UNNECESSARY; - lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; - lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS; - lro_mgr->lro_arr = adapter->rx_obj.lro_desc; - lro_mgr->get_frag_header = be_get_frag_header; - lro_mgr->max_aggr = BE_MAX_FRAGS_PER_FRAME; -} - static struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, @@ -1727,7 +1683,7 @@ static void be_netdev_init(struct net_device *netdev) netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM; + NETIF_F_IPV6_CSUM | NETIF_F_GRO; netdev->flags |= IFF_MULTICAST; @@ -1737,8 +1693,6 @@ static void be_netdev_init(struct net_device *netdev) SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); - be_lro_init(adapter, netdev); - netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx, BE_NAPI_WEIGHT); netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc, -- cgit v0.10.2 From 69222e2cb01ac3faaa8ca758c5ee036c191b8b9f Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 21 Jul 2009 12:37:18 -0700 Subject: dm9000: switch to dev_pm_ops Signed-off-by: Mike Rapoport Acked-by: Ben Dooks Signed-off-by: David S. Miller diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 8603806..a2bc415 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1483,9 +1483,10 @@ out: } static int -dm9000_drv_suspend(struct platform_device *dev, pm_message_t state) +dm9000_drv_suspend(struct device *dev) { - struct net_device *ndev = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); board_info_t *db; if (ndev) { @@ -1501,9 +1502,10 @@ dm9000_drv_suspend(struct platform_device *dev, pm_message_t state) } static int -dm9000_drv_resume(struct platform_device *dev) +dm9000_drv_resume(struct device *dev) { - struct net_device *ndev = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); board_info_t *db = netdev_priv(ndev); if (ndev) { @@ -1520,6 +1522,11 @@ dm9000_drv_resume(struct platform_device *dev) return 0; } +static struct dev_pm_ops dm9000_drv_pm_ops = { + .suspend = dm9000_drv_suspend, + .resume = dm9000_drv_resume, +}; + static int __devexit dm9000_drv_remove(struct platform_device *pdev) { @@ -1539,11 +1546,10 @@ static struct platform_driver dm9000_driver = { .driver = { .name = "dm9000", .owner = THIS_MODULE, + .pm = &dm9000_drv_pm_ops, }, .probe = dm9000_probe, .remove = __devexit_p(dm9000_drv_remove), - .suspend = dm9000_drv_suspend, - .resume = dm9000_drv_resume, }; static int __init -- cgit v0.10.2 From dd52856ba24ed2f67679c86f207e5a9bab1eb93b Mon Sep 17 00:00:00 2001 From: Sebastian Haas Date: Tue, 21 Jul 2009 12:38:13 -0700 Subject: can: sja1000: Add support for the new 4 channel EMS CPC-PCI cards This patch adds support to the ems_pci driver for the new, v2, 4 channel CPC-PCI/PCIe/104P CAN cards from EMS Dr. Thomas Wuensche. Signed-off-by: Sebastian Haas Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 33821a8..30ae55d 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -61,11 +61,12 @@ config CAN_SJA1000_OF_PLATFORM you may want to enable this option. config CAN_EMS_PCI - tristate "EMS CPC-PCI and CPC-PCIe Card" + tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card" depends on PCI && CAN_SJA1000 ---help--- - This driver is for the one or two channel CPC-PCI and CPC-PCIe - cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de). + This driver is for the one, two or four channel CPC-PCI, + CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche + (http://www.ems-wuensche.de). config CAN_KVASER_PCI tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards" diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c index 121b641..7d84b8a 100644 --- a/drivers/net/can/sja1000/ems_pci.c +++ b/drivers/net/can/sja1000/ems_pci.c @@ -32,13 +32,16 @@ #define DRV_NAME "ems_pci" MODULE_AUTHOR("Sebastian Haas "); -MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards"); -MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card"); +MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe/104P CAN cards"); +MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe/104P CAN card"); MODULE_LICENSE("GPL v2"); -#define EMS_PCI_MAX_CHAN 2 +#define EMS_PCI_V1_MAX_CHAN 2 +#define EMS_PCI_V2_MAX_CHAN 4 +#define EMS_PCI_MAX_CHAN EMS_PCI_V2_MAX_CHAN struct ems_pci_card { + int version; int channels; struct pci_dev *pci_dev; @@ -63,12 +66,22 @@ struct ems_pci_card { #define PITA2_MISC_CONFIG 0x04000000 /* Multiplexed parallel interface */ /* + * Register definitions for the PLX 9030 + */ +#define PLX_ICSR 0x4c /* Interrupt Control/Status register */ +#define PLX_ICSR_LINTI1_ENA 0x0001 /* LINTi1 Enable */ +#define PLX_ICSR_PCIINT_ENA 0x0040 /* PCI Interrupt Enable */ +#define PLX_ICSR_LINTI1_CLR 0x0400 /* Local Edge Triggerable Interrupt Clear */ +#define PLX_ICSR_ENA_CLR (PLX_ICSR_LINTI1_ENA | PLX_ICSR_PCIINT_ENA | \ + PLX_ICSR_LINTI1_CLR) + +/* * The board configuration is probably following: * RX1 is connected to ground. * TX1 is not connected. * CLKO is not connected. * Setting the OCR register to 0xDA is a good idea. - * This means normal output mode , push-pull and the correct polarity. + * This means normal output mode, push-pull and the correct polarity. */ #define EMS_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL) @@ -79,17 +92,21 @@ struct ems_pci_card { * is driven by the first one CLKOUT output. */ #define EMS_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK) -#define EMS_PCI_MEM_SIZE 4096 /* Size of the remapped io-memory */ + +#define EMS_PCI_V1_BASE_BAR 1 +#define EMS_PCI_V1_MEM_SIZE 4096 +#define EMS_PCI_V2_BASE_BAR 2 +#define EMS_PCI_V2_MEM_SIZE 128 #define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */ #define EMS_PCI_CAN_CTRL_SIZE 0x200 /* memory size for each controller */ -#define EMS_PCI_PORT_BYTES 0x4 /* Each register occupies 4 bytes */ - -#define EMS_PCI_VENDOR_ID 0x110a /* PCI device and vendor ID */ -#define EMS_PCI_DEVICE_ID 0x2104 - static struct pci_device_id ems_pci_tbl[] = { - {EMS_PCI_VENDOR_ID, EMS_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + /* CPC-PCI v1 */ + {PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,}, + /* CPC-PCI v2 */ + {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4000}, + /* CPC-104P v2 */ + {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4002}, {0,} }; MODULE_DEVICE_TABLE(pci, ems_pci_tbl); @@ -97,28 +114,47 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl); /* * Helper to read internal registers from card logic (not CAN) */ -static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port) +static u8 ems_pci_v1_readb(struct ems_pci_card *card, unsigned int port) { - return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES)); + return readb(card->base_addr + (port * 4)); } -static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port) +static u8 ems_pci_v1_read_reg(const struct sja1000_priv *priv, int port) { - return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES)); + return readb(priv->reg_base + (port * 4)); } -static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val) +static void ems_pci_v1_write_reg(const struct sja1000_priv *priv, + int port, u8 val) { - writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES)); + writeb(val, priv->reg_base + (port * 4)); } -static void ems_pci_post_irq(const struct sja1000_priv *priv) +static void ems_pci_v1_post_irq(const struct sja1000_priv *priv) { struct ems_pci_card *card = (struct ems_pci_card *)priv->priv; /* reset int flag of pita */ - writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, card->conf_addr - + PITA2_ICR); + writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, + card->conf_addr + PITA2_ICR); +} + +static u8 ems_pci_v2_read_reg(const struct sja1000_priv *priv, int port) +{ + return readb(priv->reg_base + port); +} + +static void ems_pci_v2_write_reg(const struct sja1000_priv *priv, + int port, u8 val) +{ + writeb(val, priv->reg_base + port); +} + +static void ems_pci_v2_post_irq(const struct sja1000_priv *priv) +{ + struct ems_pci_card *card = (struct ems_pci_card *)priv->priv; + + writel(PLX_ICSR_ENA_CLR, card->conf_addr + PLX_ICSR); } /* @@ -130,12 +166,12 @@ static inline int ems_pci_check_chan(const struct sja1000_priv *priv) unsigned char res; /* Make sure SJA1000 is in reset mode */ - ems_pci_write_reg(priv, REG_MOD, 1); + priv->write_reg(priv, REG_MOD, 1); - ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN); + priv->write_reg(priv, REG_CDR, CDR_PELICAN); /* read reset-values */ - res = ems_pci_read_reg(priv, REG_CDR); + res = priv->read_reg(priv, REG_CDR); if (res == CDR_PELICAN) return 1; @@ -188,6 +224,7 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, struct sja1000_priv *priv; struct net_device *dev; struct ems_pci_card *card; + int max_chan, mem_size, base_bar; int err, i; /* Enabling PCI device */ @@ -210,37 +247,52 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, card->channels = 0; - /* Remap PITA configuration space, and controller memory area */ - card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE); + if (pdev->vendor == PCI_VENDOR_ID_PLX) { + card->version = 2; /* CPC-PCI v2 */ + max_chan = EMS_PCI_V2_MAX_CHAN; + base_bar = EMS_PCI_V2_BASE_BAR; + mem_size = EMS_PCI_V2_MEM_SIZE; + } else { + card->version = 1; /* CPC-PCI v1 */ + max_chan = EMS_PCI_V1_MAX_CHAN; + base_bar = EMS_PCI_V1_BASE_BAR; + mem_size = EMS_PCI_V1_MEM_SIZE; + } + + /* Remap configuration space and controller memory area */ + card->conf_addr = pci_iomap(pdev, 0, mem_size); if (card->conf_addr == NULL) { err = -ENOMEM; goto failure_cleanup; } - card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE); + card->base_addr = pci_iomap(pdev, base_bar, mem_size); if (card->base_addr == NULL) { err = -ENOMEM; goto failure_cleanup; } - /* Configure PITA-2 parallel interface (enable MUX) */ - writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC); - - /* Check for unique EMS CAN signature */ - if (ems_pci_readb(card, 0) != 0x55 || - ems_pci_readb(card, 1) != 0xAA || - ems_pci_readb(card, 2) != 0x01 || - ems_pci_readb(card, 3) != 0xCB || - ems_pci_readb(card, 4) != 0x11) { - dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n"); - err = -ENODEV; - goto failure_cleanup; + if (card->version == 1) { + /* Configure PITA-2 parallel interface (enable MUX) */ + writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC); + + /* Check for unique EMS CAN signature */ + if (ems_pci_v1_readb(card, 0) != 0x55 || + ems_pci_v1_readb(card, 1) != 0xAA || + ems_pci_v1_readb(card, 2) != 0x01 || + ems_pci_v1_readb(card, 3) != 0xCB || + ems_pci_v1_readb(card, 4) != 0x11) { + dev_err(&pdev->dev, + "Not EMS Dr. Thomas Wuensche interface\n"); + err = -ENODEV; + goto failure_cleanup; + } } ems_pci_card_reset(card); /* Detect available channels */ - for (i = 0; i < EMS_PCI_MAX_CHAN; i++) { + for (i = 0; i < max_chan; i++) { dev = alloc_sja1000dev(0); if (dev == NULL) { err = -ENOMEM; @@ -255,20 +307,32 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, dev->irq = pdev->irq; priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET + (i * EMS_PCI_CAN_CTRL_SIZE); + if (card->version == 1) { + priv->read_reg = ems_pci_v1_read_reg; + priv->write_reg = ems_pci_v1_write_reg; + priv->post_irq = ems_pci_v1_post_irq; + } else { + priv->read_reg = ems_pci_v2_read_reg; + priv->write_reg = ems_pci_v2_write_reg; + priv->post_irq = ems_pci_v2_post_irq; + } /* Check if channel is present */ if (ems_pci_check_chan(priv)) { - priv->read_reg = ems_pci_read_reg; - priv->write_reg = ems_pci_write_reg; - priv->post_irq = ems_pci_post_irq; priv->can.clock.freq = EMS_PCI_CAN_CLOCK; priv->ocr = EMS_PCI_OCR; priv->cdr = EMS_PCI_CDR; SET_NETDEV_DEV(dev, &pdev->dev); - /* Enable interrupts from card */ - writel(PITA2_ICR_INT0_EN, card->conf_addr + PITA2_ICR); + if (card->version == 1) + /* reset int flag of pita */ + writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, + card->conf_addr + PITA2_ICR); + else + /* enable IRQ in PLX 9030 */ + writel(PLX_ICSR_ENA_CLR, + card->conf_addr + PLX_ICSR); /* Register SJA1000 device */ err = register_sja1000dev(dev); -- cgit v0.10.2 From 27a242e92f77c955433ce0347533f401ecdcd0f3 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 21 Jul 2009 12:50:02 -0700 Subject: veth: Zero timestamp in xmit path. This patch zero's the timestamp before handing the packet to the peer interface. This lets the peer recalculate the rx timestamp if it cares about timestamps. Signed-off-by: Ben Greear Signed-off-by: David S. Miller diff --git a/drivers/net/veth.c b/drivers/net/veth.c index f1d753d..190f784 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -171,6 +171,7 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len > (rcv->mtu + MTU_PAD)) goto rx_drop; + skb->tstamp.tv64 = 0; skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, rcv); if (dev->features & NETIF_F_NO_CSUM) -- cgit v0.10.2 From a65a688182cd7f5b69bd6dd9022be96ea771642c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 21 Jul 2009 11:25:26 +0000 Subject: net: move sgiseeq's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to sgiseeq_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Cc: Wang Chen Cc: David S. Miller Cc: Andrew Morton Cc: Jeff Garzik Cc: Thomas Bogendoerfer Acked-by: Ralf Baechle Cc: Greg Kroah-Hartman Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 78f6008..ecf3279f 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -720,7 +720,7 @@ static const struct net_device_ops sgiseeq_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static int __init sgiseeq_probe(struct platform_device *pdev) +static int __devinit sgiseeq_probe(struct platform_device *pdev) { struct sgiseeq_platform_data *pd = pdev->dev.platform_data; struct hpc3_regs *hpcregs = pd->hpc; -- cgit v0.10.2 From 2e76baea67fa74442938afd3417170b28e7aac86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 21 Jul 2009 11:25:22 +0000 Subject: net: move jazzsonic's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to jazz_sonic_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. As noticed by Geert Uytterhoeven sonic_probe1 is called by jazz_sonic_probe, so the former has to move to .devinit.text, too. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Acked-by: Ralf Baechle Cc: Jeff Garzik Cc: David S. Miller Cc: Thomas Bogendoerfer Cc: Finn Thain Cc: Geert Uytterhoeven Cc: Andrew Morton Cc: netdev@vger.kernel.org Cc: Greg Kroah-Hartman Signed-off-by: David S. Miller diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index d12106b..8baf595 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -108,7 +108,7 @@ static const struct net_device_ops sonic_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, }; -static int __init sonic_probe1(struct net_device *dev) +static int __devinit sonic_probe1(struct net_device *dev) { static unsigned version_printed; unsigned int silicon_revision; @@ -211,7 +211,7 @@ out: * Probe for a SONIC ethernet controller on a Mips Jazz board. * Actually probing is superfluous but we're paranoid. */ -static int __init jazz_sonic_probe(struct platform_device *pdev) +static int __devinit jazz_sonic_probe(struct platform_device *pdev) { struct net_device *dev; struct sonic_local *lp; -- cgit v0.10.2 From dd93667711761362b393cfbd5959bb11aa1fa80d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 21 Jul 2009 11:25:24 +0000 Subject: net: move meth's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to meth_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Cc: David S. Miller Cc: Thomas Bogendoerfer Cc: Christoph Lameter Cc: Jeff Garzik Acked-by: Ralf Baechle Cc: Andrew Morton Cc: netdev@vger.kernel.org Cc: Greg Kroah-Hartman Signed-off-by: David S. Miller diff --git a/drivers/net/meth.c b/drivers/net/meth.c index abea35d..92ceb68 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -784,7 +784,7 @@ static const struct net_device_ops meth_netdev_ops = { /* * The init function. */ -static int __init meth_probe(struct platform_device *pdev) +static int __devinit meth_probe(struct platform_device *pdev) { struct net_device *dev; struct meth_private *priv; -- cgit v0.10.2 From ffe8553f8871dabf61d49e7f97a2c6cbc7dc23cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 21 Jul 2009 11:25:25 +0000 Subject: net: move sb1250-mac's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to sbmac_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Cc: Weiwei Wang Cc: Jeff Garzik Cc: David S. Miller Cc: Stephen Hemminger Acked-by: Maciej W. Rozycki Cc: Andrew Morton Cc: Greg Kroah-Hartman Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 4c2450b..508551f 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2688,7 +2688,7 @@ static int sbmac_poll(struct napi_struct *napi, int budget) } -static int __init sbmac_probe(struct platform_device *pldev) +static int __devinit sbmac_probe(struct platform_device *pldev) { struct net_device *dev; struct sbmac_softc *sc; -- cgit v0.10.2 From 0c9cd395faca5ccf549e2bcb6b09086962c112b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 21 Jul 2009 11:25:27 +0000 Subject: net: move xtsonic's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to xtsonic_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Cc: Chris Zankel Cc: David S. Miller Cc: Andrew Morton Cc: Greg Kroah-Hartman Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c index 5a4ad15..0c44135 100644 --- a/drivers/net/xtsonic.c +++ b/drivers/net/xtsonic.c @@ -239,7 +239,7 @@ out: * Actually probing is superfluous but we're paranoid. */ -int __init xtsonic_probe(struct platform_device *pdev) +int __devinit xtsonic_probe(struct platform_device *pdev) { struct net_device *dev; struct sonic_local *lp; -- cgit v0.10.2 From c9a73cdb772a487b2c59c2711ad8b10d58cbaca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 21 Jul 2009 11:25:23 +0000 Subject: net: move macsonic's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to mac_sonic_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. Various other functions that are called by mac_sonic_probe need to move to .devinit.text, too. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Cc: Jeff Garzik Cc: David S. Miller Tested-by: Finn Thain Cc: Geert Uytterhoeven Cc: Andrew Morton Cc: netdev@vger.kernel.org Cc: Greg Kroah-Hartman Signed-off-by: David S. Miller diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index acd143d..8f492c7 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -179,7 +179,7 @@ static const struct net_device_ops macsonic_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, }; -static int __init macsonic_init(struct net_device *dev) +static int __devinit macsonic_init(struct net_device *dev) { struct sonic_local* lp = netdev_priv(dev); @@ -223,7 +223,7 @@ static int __init macsonic_init(struct net_device *dev) return 0; } -static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev) +static int __devinit mac_onboard_sonic_ethernet_addr(struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; @@ -288,7 +288,7 @@ static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev) } else return 0; } -static int __init mac_onboard_sonic_probe(struct net_device *dev) +static int __devinit mac_onboard_sonic_probe(struct net_device *dev) { /* Bwahahaha */ static int once_is_more_than_enough; @@ -409,7 +409,7 @@ static int __init mac_onboard_sonic_probe(struct net_device *dev) return macsonic_init(dev); } -static int __init mac_nubus_sonic_ethernet_addr(struct net_device *dev, +static int __devinit mac_nubus_sonic_ethernet_addr(struct net_device *dev, unsigned long prom_addr, int id) { @@ -424,7 +424,7 @@ static int __init mac_nubus_sonic_ethernet_addr(struct net_device *dev, return 0; } -static int __init macsonic_ident(struct nubus_dev *ndev) +static int __devinit macsonic_ident(struct nubus_dev *ndev) { if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC && ndev->dr_sw == NUBUS_DRSW_SONIC_LC) @@ -449,7 +449,7 @@ static int __init macsonic_ident(struct nubus_dev *ndev) return -1; } -static int __init mac_nubus_sonic_probe(struct net_device *dev) +static int __devinit mac_nubus_sonic_probe(struct net_device *dev) { static int slots; struct nubus_dev* ndev = NULL; @@ -562,7 +562,7 @@ static int __init mac_nubus_sonic_probe(struct net_device *dev) return macsonic_init(dev); } -static int __init mac_sonic_probe(struct platform_device *pdev) +static int __devinit mac_sonic_probe(struct platform_device *pdev) { struct net_device *dev; struct sonic_local *lp; -- cgit v0.10.2 From 40d4e3dfc2f56ad85ecca29c7f9a0194bbb833c0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 21 Jul 2009 21:57:59 +0000 Subject: af_packet: style cleanups Some style cleanups to match current code practices. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ebe5718..d3d52c6 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -137,8 +137,7 @@ dev->hard_header == NULL (ll header is added by device, we cannot control it) /* Private packet socket structures. */ -struct packet_mclist -{ +struct packet_mclist { struct packet_mclist *next; int ifindex; int count; @@ -149,8 +148,7 @@ struct packet_mclist /* identical to struct packet_mreq except it has * a longer address field. */ -struct packet_mreq_max -{ +struct packet_mreq_max { int mr_ifindex; unsigned short mr_type; unsigned short mr_alen; @@ -162,7 +160,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing, int tx_ring); struct packet_ring_buffer { - char * *pg_vec; + char **pg_vec; unsigned int head; unsigned int frames_per_block; unsigned int frame_size; @@ -239,7 +237,7 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status) flush_dcache_page(virt_to_page(&h.h2->tp_status)); break; default: - printk(KERN_ERR "TPACKET version not supported\n"); + pr_err("TPACKET version not supported\n"); BUG(); } @@ -265,7 +263,7 @@ static int __packet_get_status(struct packet_sock *po, void *frame) flush_dcache_page(virt_to_page(&h.h2->tp_status)); return h.h2->tp_status; default: - printk(KERN_ERR "TPACKET version not supported\n"); + pr_err("TPACKET version not supported\n"); BUG(); return 0; } @@ -327,7 +325,7 @@ static void packet_sock_destruct(struct sock *sk) WARN_ON(atomic_read(&sk->sk_wmem_alloc)); if (!sock_flag(sk, SOCK_DEAD)) { - printk("Attempt to release alive packet socket: %p\n", sk); + pr_err("Attempt to release alive packet socket: %p\n", sk); return; } @@ -339,7 +337,8 @@ static const struct proto_ops packet_ops; static const struct proto_ops packet_ops_spkt; -static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) +static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) { struct sock *sk; struct sockaddr_pkt *spkt; @@ -368,7 +367,8 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct if (dev_net(dev) != sock_net(sk)) goto out; - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + skb = skb_share_check(skb, GFP_ATOMIC); + if (skb == NULL) goto oom; /* drop any routing info */ @@ -394,7 +394,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct * to prevent sockets using all the memory up. */ - if (sock_queue_rcv_skb(sk,skb) == 0) + if (sock_queue_rcv_skb(sk, skb) == 0) return 0; out: @@ -413,25 +413,23 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; - struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name; + struct sockaddr_pkt *saddr = (struct sockaddr_pkt *)msg->msg_name; struct sk_buff *skb; struct net_device *dev; - __be16 proto=0; + __be16 proto = 0; int err; /* * Get and verify the address. */ - if (saddr) - { + if (saddr) { if (msg->msg_namelen < sizeof(struct sockaddr)) - return(-EINVAL); - if (msg->msg_namelen==sizeof(struct sockaddr_pkt)) - proto=saddr->spkt_protocol; - } - else - return(-ENOTCONN); /* SOCK_PACKET must be sent giving an address */ + return -EINVAL; + if (msg->msg_namelen == sizeof(struct sockaddr_pkt)) + proto = saddr->spkt_protocol; + } else + return -ENOTCONN; /* SOCK_PACKET must be sent giving an address */ /* * Find the device first to size check it @@ -448,8 +446,8 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, goto out_unlock; /* - * You may not queue a frame bigger than the mtu. This is the lowest level - * raw protocol and you must do your own fragmentation at this level. + * You may not queue a frame bigger than the mtu. This is the lowest level + * raw protocol and you must do your own fragmentation at this level. */ err = -EMSGSIZE; @@ -460,9 +458,9 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, skb = sock_wmalloc(sk, len + LL_RESERVED_SPACE(dev), 0, GFP_KERNEL); /* - * If the write buffer is full, then tough. At this level the user gets to - * deal with the problem - do your own algorithmic backoffs. That's far - * more flexible. + * If the write buffer is full, then tough. At this level the user + * gets to deal with the problem - do your own algorithmic backoffs. + * That's far more flexible. */ if (skb == NULL) @@ -488,7 +486,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, } /* Returns -EFAULT on error */ - err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); + err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); skb->protocol = proto; skb->dev = dev; skb->priority = sk->sk_priority; @@ -501,7 +499,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, dev_queue_xmit(skb); dev_put(dev); - return(len); + return len; out_free: kfree_skb(skb); @@ -537,12 +535,13 @@ static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk, we will not harm anyone. */ -static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) +static int packet_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) { struct sock *sk; struct sockaddr_ll *sll; struct packet_sock *po; - u8 * skb_head = skb->data; + u8 *skb_head = skb->data; int skb_len = skb->len; unsigned int snaplen, res; @@ -648,7 +647,8 @@ drop: } #ifdef CONFIG_PACKET_MMAP -static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) +static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) { struct sock *sk; struct packet_sock *po; @@ -658,7 +658,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe struct tpacket2_hdr *h2; void *raw; } h; - u8 * skb_head = skb->data; + u8 *skb_head = skb->data; int skb_len = skb->len; unsigned int snaplen, res; unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER; @@ -821,7 +821,7 @@ ring_is_full: static void tpacket_destruct_skb(struct sk_buff *skb) { struct packet_sock *po = pkt_sk(skb->sk); - void * ph; + void *ph; BUG_ON(skb == NULL); @@ -836,9 +836,9 @@ static void tpacket_destruct_skb(struct sk_buff *skb) sock_wfree(skb); } -static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb, - void * frame, struct net_device *dev, int size_max, - __be16 proto, unsigned char * addr) +static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, + void *frame, struct net_device *dev, int size_max, + __be16 proto, unsigned char *addr) { union { struct tpacket_hdr *h1; @@ -867,8 +867,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb, break; } if (unlikely(tp_len > size_max)) { - printk(KERN_ERR "packet size is too long (%d > %d)\n", - tp_len, size_max); + pr_err("packet size is too long (%d > %d)\n", tp_len, size_max); return -EMSGSIZE; } @@ -883,12 +882,11 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb, NULL, tp_len); if (unlikely(err < 0)) return -EINVAL; - } else if (dev->hard_header_len ) { + } else if (dev->hard_header_len) { /* net device doesn't like empty head */ if (unlikely(tp_len <= dev->hard_header_len)) { - printk(KERN_ERR "packet size is too short " - "(%d < %d)\n", tp_len, - dev->hard_header_len); + pr_err("packet size is too short (%d < %d)\n", + tp_len, dev->hard_header_len); return -EINVAL; } @@ -917,9 +915,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb, nr_frags = skb_shinfo(skb)->nr_frags; if (unlikely(nr_frags >= MAX_SKB_FRAGS)) { - printk(KERN_ERR "Packet exceed the number " - "of skb frags(%lu)\n", - MAX_SKB_FRAGS); + pr_err("Packet exceed the number of skb frags(%lu)\n", + MAX_SKB_FRAGS); return -EFAULT; } @@ -944,8 +941,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) struct net_device *dev; __be16 proto; int ifindex, err, reserve = 0; - void * ph; - struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name; + void *ph; + struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name; int tp_len, size_max; unsigned char *addr; int len_sum = 0; @@ -1038,8 +1035,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) goto out_xmit; packet_increment_head(&po->tx_ring); len_sum += tp_len; - } - while (likely((ph != NULL) || ((!(msg->msg_flags & MSG_DONTWAIT)) + } while (likely((ph != NULL) || ((!(msg->msg_flags & MSG_DONTWAIT)) && (atomic_read(&po->tx_ring.pending)))) ); @@ -1064,7 +1060,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; - struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name; + struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name; struct sk_buff *skb; struct net_device *dev; __be16 proto; @@ -1110,7 +1106,7 @@ static int packet_snd(struct socket *sock, skb = sock_alloc_send_skb(sk, len + LL_ALLOCATED_SPACE(dev), msg->msg_flags & MSG_DONTWAIT, &err); - if (skb==NULL) + if (skb == NULL) goto out_unlock; skb_reserve(skb, LL_RESERVED_SPACE(dev)); @@ -1122,7 +1118,7 @@ static int packet_snd(struct socket *sock, goto out_free; /* Returns -EFAULT on error */ - err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); + err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); if (err) goto out_free; @@ -1140,7 +1136,7 @@ static int packet_snd(struct socket *sock, dev_put(dev); - return(len); + return len; out_free: kfree_skb(skb); @@ -1283,9 +1279,10 @@ out_unlock: * Bind a packet socket to a device */ -static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int addr_len) +static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, + int addr_len) { - struct sock *sk=sock->sk; + struct sock *sk = sock->sk; char name[15]; struct net_device *dev; int err = -ENODEV; @@ -1296,7 +1293,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add if (addr_len != sizeof(struct sockaddr)) return -EINVAL; - strlcpy(name,uaddr->sa_data,sizeof(name)); + strlcpy(name, uaddr->sa_data, sizeof(name)); dev = dev_get_by_name(sock_net(sk), name); if (dev) { @@ -1308,8 +1305,8 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { - struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr; - struct sock *sk=sock->sk; + struct sockaddr_ll *sll = (struct sockaddr_ll *)uaddr; + struct sock *sk = sock->sk; struct net_device *dev = NULL; int err; @@ -1404,7 +1401,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol) sk_add_node(sk, &net->packet.sklist); sock_prot_inuse_add(net, &packet_proto, 1); write_unlock_bh(&net->packet.sklist_lock); - return(0); + return 0; out: return err; } @@ -1441,7 +1438,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, * but then it will block. */ - skb=skb_recv_datagram(sk,flags,flags&MSG_DONTWAIT,&err); + skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); /* * An error occurred so return it. Because skb_recv_datagram() @@ -1469,10 +1466,9 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, */ copied = skb->len; - if (copied > len) - { - copied=len; - msg->msg_flags|=MSG_TRUNC; + if (copied > len) { + copied = len; + msg->msg_flags |= MSG_TRUNC; } err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); @@ -1539,7 +1535,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, struct net_device *dev; struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); - struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr; + struct sockaddr_ll *sll = (struct sockaddr_ll *)uaddr; if (peer) return -EOPNOTSUPP; @@ -1584,14 +1580,15 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i, else return dev_unicast_delete(dev, i->addr); break; - default:; + default: + break; } return 0; } static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what) { - for ( ; i; i=i->next) { + for ( ; i; i = i->next) { if (i->ifindex == dev->ifindex) packet_dev_mc(dev, i, what); } @@ -1693,7 +1690,8 @@ static void packet_flush_mclist(struct sock *sk) struct net_device *dev; po->mclist = ml->next; - if ((dev = dev_get_by_index(sock_net(sk), ml->ifindex)) != NULL) { + dev = dev_get_by_index(sock_net(sk), ml->ifindex); + if (dev != NULL) { packet_dev_mc(dev, ml, -1); dev_put(dev); } @@ -1723,7 +1721,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv return -EINVAL; if (len > sizeof(mreq)) len = sizeof(mreq); - if (copy_from_user(&mreq,optval,len)) + if (copy_from_user(&mreq, optval, len)) return -EFAULT; if (len < (mreq.mr_alen + offsetof(struct packet_mreq, mr_address))) return -EINVAL; @@ -1740,9 +1738,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv { struct tpacket_req req; - if (optlencopy_thresh = val; @@ -1985,51 +1983,51 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, struct sock *sk = sock->sk; switch (cmd) { - case SIOCOUTQ: - { - int amount = sk_wmem_alloc_get(sk); + case SIOCOUTQ: + { + int amount = sk_wmem_alloc_get(sk); - return put_user(amount, (int __user *)arg); - } - case SIOCINQ: - { - struct sk_buff *skb; - int amount = 0; - - spin_lock_bh(&sk->sk_receive_queue.lock); - skb = skb_peek(&sk->sk_receive_queue); - if (skb) - amount = skb->len; - spin_unlock_bh(&sk->sk_receive_queue.lock); - return put_user(amount, (int __user *)arg); - } - case SIOCGSTAMP: - return sock_get_timestamp(sk, (struct timeval __user *)arg); - case SIOCGSTAMPNS: - return sock_get_timestampns(sk, (struct timespec __user *)arg); + return put_user(amount, (int __user *)arg); + } + case SIOCINQ: + { + struct sk_buff *skb; + int amount = 0; + + spin_lock_bh(&sk->sk_receive_queue.lock); + skb = skb_peek(&sk->sk_receive_queue); + if (skb) + amount = skb->len; + spin_unlock_bh(&sk->sk_receive_queue.lock); + return put_user(amount, (int __user *)arg); + } + case SIOCGSTAMP: + return sock_get_timestamp(sk, (struct timeval __user *)arg); + case SIOCGSTAMPNS: + return sock_get_timestampns(sk, (struct timespec __user *)arg); #ifdef CONFIG_INET - case SIOCADDRT: - case SIOCDELRT: - case SIOCDARP: - case SIOCGARP: - case SIOCSARP: - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCSIFFLAGS: - if (!net_eq(sock_net(sk), &init_net)) - return -ENOIOCTLCMD; - return inet_dgram_ops.ioctl(sock, cmd, arg); + case SIOCADDRT: + case SIOCDELRT: + case SIOCDARP: + case SIOCGARP: + case SIOCSARP: + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCSIFFLAGS: + if (!net_eq(sock_net(sk), &init_net)) + return -ENOIOCTLCMD; + return inet_dgram_ops.ioctl(sock, cmd, arg); #endif - default: - return -ENOIOCTLCMD; + default: + return -ENOIOCTLCMD; } return 0; } @@ -2039,7 +2037,7 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, #define packet_poll datagram_poll #else -static unsigned int packet_poll(struct file * file, struct socket *sock, +static unsigned int packet_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; @@ -2069,7 +2067,7 @@ static unsigned int packet_poll(struct file * file, struct socket *sock, static void packet_mm_open(struct vm_area_struct *vma) { struct file *file = vma->vm_file; - struct socket * sock = file->private_data; + struct socket *sock = file->private_data; struct sock *sk = sock->sk; if (sk) @@ -2079,7 +2077,7 @@ static void packet_mm_open(struct vm_area_struct *vma) static void packet_mm_close(struct vm_area_struct *vma) { struct file *file = vma->vm_file; - struct socket * sock = file->private_data; + struct socket *sock = file->private_data; struct sock *sk = sock->sk; if (sk) @@ -2087,8 +2085,8 @@ static void packet_mm_close(struct vm_area_struct *vma) } static struct vm_operations_struct packet_mmap_ops = { - .open = packet_mm_open, - .close =packet_mm_close, + .open = packet_mm_open, + .close = packet_mm_close, }; static void free_pg_vec(char **pg_vec, unsigned int order, unsigned int len) @@ -2239,8 +2237,8 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, skb_queue_purge(rb_queue); #undef XC if (atomic_read(&po->mapped)) - printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n", - atomic_read(&po->mapped)); + pr_err("packet_mmap: vma is busy: %d\n", + atomic_read(&po->mapped)); } mutex_unlock(&po->pg_vec_lock); @@ -2303,7 +2301,7 @@ static int packet_mmap(struct file *file, struct socket *sock, int pg_num; for (pg_num = 0; pg_num < rb->pg_vec_pages; - pg_num++,page++) { + pg_num++, page++) { err = vm_insert_page(vma, start, page); if (unlikely(err)) goto out; @@ -2372,7 +2370,7 @@ static struct net_proto_family packet_family_ops = { }; static struct notifier_block packet_netdev_notifier = { - .notifier_call =packet_notifier, + .notifier_call = packet_notifier, }; #ifdef CONFIG_PROC_FS @@ -2402,7 +2400,7 @@ static void *packet_seq_next(struct seq_file *seq, void *v, loff_t *pos) ++*pos; return (v == SEQ_START_TOKEN) ? sk_head(&net->packet.sklist) - : sk_next((struct sock*)v) ; + : sk_next((struct sock *)v) ; } static void packet_seq_stop(struct seq_file *seq, void *v) @@ -2430,7 +2428,7 @@ static int packet_seq_show(struct seq_file *seq, void *v) po->running, atomic_read(&s->sk_rmem_alloc), sock_i_uid(s), - sock_i_ino(s) ); + sock_i_ino(s)); } return 0; -- cgit v0.10.2 From 67edfef78639573e9b01c26295a935349aab6fa3 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 21 Jul 2009 23:00:40 +0000 Subject: TCP: Add comments to (near) all functions in tcp_output.c v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While looking for something else I spent some time adding one liner comments to the tcp_output.c functions that didn't have any. That makes the comments more consistent. I hope I documented everything right. No code changes. v2: Incorporated feedback from Ilpo. v3: Change style of one liner comments, add a few more comments. Signed-off-by: Andi Kleen Acked-by: Ilpo Järvinen Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 5bdf08d..c464892 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -59,6 +59,7 @@ int sysctl_tcp_base_mss __read_mostly = 512; /* By default, RFC2861 behavior. */ int sysctl_tcp_slow_start_after_idle __read_mostly = 1; +/* Account for new data that has been sent to the network. */ static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); @@ -142,6 +143,7 @@ static void tcp_cwnd_restart(struct sock *sk, struct dst_entry *dst) tp->snd_cwnd_used = 0; } +/* Congestion state accounting after a packet has been sent. */ static void tcp_event_data_sent(struct tcp_sock *tp, struct sk_buff *skb, struct sock *sk) { @@ -161,6 +163,7 @@ static void tcp_event_data_sent(struct tcp_sock *tp, icsk->icsk_ack.pingpong = 1; } +/* Account for an ACK we sent. */ static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts) { tcp_dec_quickack_mode(sk, pkts); @@ -276,6 +279,7 @@ static u16 tcp_select_window(struct sock *sk) return new_win; } +/* Packet ECN state for a SYN-ACK */ static inline void TCP_ECN_send_synack(struct tcp_sock *tp, struct sk_buff *skb) { TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_CWR; @@ -283,6 +287,7 @@ static inline void TCP_ECN_send_synack(struct tcp_sock *tp, struct sk_buff *skb) TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_ECE; } +/* Packet ECN state for a SYN. */ static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); @@ -301,6 +306,9 @@ TCP_ECN_make_synack(struct request_sock *req, struct tcphdr *th) th->ece = 1; } +/* Set up ECN state for a packet on a ESTABLISHED socket that is about to + * be sent. + */ static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb, int tcp_header_len) { @@ -362,7 +370,9 @@ struct tcp_out_options { __u32 tsval, tsecr; /* need to include OPTION_TS */ }; -/* Beware: Something in the Internet is very sensitive to the ordering of +/* Write previously computed TCP options to the packet. + * + * Beware: Something in the Internet is very sensitive to the ordering of * TCP options, we learned this through the hard way, so be careful here. * Luckily we can at least blame others for their non-compliance but from * inter-operatibility perspective it seems that we're somewhat stuck with @@ -445,6 +455,9 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, } } +/* Compute TCP options for SYN packets. This is not the final + * network wire format yet. + */ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, struct tcp_out_options *opts, struct tcp_md5sig_key **md5) { @@ -493,6 +506,7 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, return size; } +/* Set up TCP options for SYN-ACKs. */ static unsigned tcp_synack_options(struct sock *sk, struct request_sock *req, unsigned mss, struct sk_buff *skb, @@ -541,6 +555,9 @@ static unsigned tcp_synack_options(struct sock *sk, return size; } +/* Compute TCP options for ESTABLISHED sockets. This is not the + * final wire format yet. + */ static unsigned tcp_established_options(struct sock *sk, struct sk_buff *skb, struct tcp_out_options *opts, struct tcp_md5sig_key **md5) { @@ -705,7 +722,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, return net_xmit_eval(err); } -/* This routine just queue's the buffer +/* This routine just queues the buffer for sending. * * NOTE: probe0 timer is not checked, do not forget tcp_push_pending_frames, * otherwise socket can stall. @@ -722,6 +739,7 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) sk_mem_charge(sk, skb->truesize); } +/* Initialize TSO segments for a packet. */ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned int mss_now) { @@ -909,6 +927,7 @@ static void __pskb_trim_head(struct sk_buff *skb, int len) skb->len = skb->data_len; } +/* Remove acked data from a packet in the transmit queue. */ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) { if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) @@ -937,7 +956,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) return 0; } -/* Not accounting for SACKs here. */ +/* Calculate MSS. Not accounting for SACKs here. */ int tcp_mtu_to_mss(struct sock *sk, int pmtu) { struct tcp_sock *tp = tcp_sk(sk); @@ -981,6 +1000,7 @@ int tcp_mss_to_mtu(struct sock *sk, int mss) return mtu; } +/* MTU probing init per socket */ void tcp_mtup_init(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); @@ -1143,7 +1163,8 @@ static inline unsigned int tcp_cwnd_test(struct tcp_sock *tp, return 0; } -/* This must be invoked the first time we consider transmitting +/* Intialize TSO state of a skb. + * This must be invoked the first time we consider transmitting * SKB onto the wire. */ static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb, @@ -1158,6 +1179,7 @@ static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb, return tso_segs; } +/* Minshall's variant of the Nagle send check. */ static inline int tcp_minshall_check(const struct tcp_sock *tp) { return after(tp->snd_sml, tp->snd_una) && @@ -1242,6 +1264,7 @@ static unsigned int tcp_snd_test(struct sock *sk, struct sk_buff *skb, return cwnd_quota; } +/* Test if sending is allowed right now. */ int tcp_may_send_now(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); @@ -1378,6 +1401,10 @@ send_now: } /* Create a new MTU probe if we are ready. + * MTU probe is regularly attempting to increase the path MTU by + * deliberately sending larger packets. This discovers routing + * changes resulting in larger path MTUs. + * * Returns 0 if we should wait to probe (no cwnd available), * 1 if a probe was sent, * -1 otherwise @@ -1790,6 +1817,7 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb) sk_wmem_free_skb(sk, next_skb); } +/* Check if coalescing SKBs is legal. */ static int tcp_can_collapse(struct sock *sk, struct sk_buff *skb) { if (tcp_skb_pcount(skb) > 1) @@ -1808,6 +1836,9 @@ static int tcp_can_collapse(struct sock *sk, struct sk_buff *skb) return 1; } +/* Collapse packets in the retransmit queue to make to create + * less packets on the wire. This is only done on retransmission. + */ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to, int space) { @@ -1957,6 +1988,9 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) return err; } +/* Check if we forward retransmits are possible in the current + * window/congestion state. + */ static int tcp_can_forward_retransmit(struct sock *sk) { const struct inet_connection_sock *icsk = inet_csk(sk); @@ -2145,7 +2179,8 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority) TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTRSTS); } -/* WARNING: This routine must only be called when we have already sent +/* Send a crossed SYN-ACK during socket establishment. + * WARNING: This routine must only be called when we have already sent * a SYN packet that crossed the incoming SYN that caused this routine * to get called. If this assumption fails then the initial rcv_wnd * and rcv_wscale values will not be correct. @@ -2180,9 +2215,7 @@ int tcp_send_synack(struct sock *sk) return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); } -/* - * Prepare a SYN-ACK. - */ +/* Prepare a SYN-ACK. */ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, struct request_sock *req) { @@ -2269,9 +2302,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, return skb; } -/* - * Do all connect socket setups that can be done AF independent. - */ +/* Do all connect socket setups that can be done AF independent. */ static void tcp_connect_init(struct sock *sk) { struct dst_entry *dst = __sk_dst_get(sk); @@ -2330,9 +2361,7 @@ static void tcp_connect_init(struct sock *sk) tcp_clear_retrans(tp); } -/* - * Build a SYN and send it off. - */ +/* Build a SYN and send it off. */ int tcp_connect(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); @@ -2493,6 +2522,7 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent) return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC); } +/* Initiate keepalive or window probe from timer. */ int tcp_write_wakeup(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); -- cgit v0.10.2 From 83c98a8cd04dd0f848574370594886ba3bf56750 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 21 Jul 2009 09:15:49 +0000 Subject: Remove unused zero-copy code from velocity NIC driver. This code hasn't been enabled in forever. Signed-off-by: Dave Jones Signed-off-by: David S. Miller diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 42365e5..4ebe2ca 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -976,9 +976,6 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi dev->netdev_ops = &velocity_netdev_ops; dev->ethtool_ops = &velocity_ethtool_ops; -#ifdef VELOCITY_ZERO_COPY_SUPPORT - dev->features |= NETIF_F_SG; -#endif dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_VLAN_RX; @@ -1849,11 +1846,7 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_ pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); for (i = 0; i < tdinfo->nskb_dma; i++) { -#ifdef VELOCITY_ZERO_COPY_SUPPORT - pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], le16_to_cpu(td->tdesc1.len), PCI_DMA_TODEVICE); -#else pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE); -#endif tdinfo->skb_dma[i] = 0; } } @@ -2095,13 +2088,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) len = cpu_to_le16(pktlen); -#ifdef VELOCITY_ZERO_COPY_SUPPORT - if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) { - kfree_skb(skb); - return NETDEV_TX_OK; - } -#endif - spin_lock_irqsave(&vptr->lock, flags); index = vptr->tx.curr[qnum]; @@ -2111,59 +2097,18 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) td_ptr->tdesc1.TCR = TCR0_TIC; td_ptr->td_buf[0].size &= ~TD_QUEUE; -#ifdef VELOCITY_ZERO_COPY_SUPPORT - if (skb_shinfo(skb)->nr_frags > 0) { - int nfrags = skb_shinfo(skb)->nr_frags; - tdinfo->skb = skb; - if (nfrags > 6) { - skb_copy_from_linear_data(skb, tdinfo->buf, skb->len); - tdinfo->skb_dma[0] = tdinfo->buf_dma; - td_ptr->tdesc0.len = len; - td_ptr->tx.buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); - td_ptr->tx.buf[0].pa_high = 0; - td_ptr->tx.buf[0].size = len; /* queue is 0 anyway */ - tdinfo->nskb_dma = 1; - } else { - int i = 0; - tdinfo->nskb_dma = 0; - tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data, - skb_headlen(skb), PCI_DMA_TODEVICE); - - td_ptr->tdesc0.len = len; - - /* FIXME: support 48bit DMA later */ - td_ptr->tx.buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma); - td_ptr->tx.buf[i].pa_high = 0; - td_ptr->tx.buf[i].size = cpu_to_le16(skb_headlen(skb)); - - for (i = 0; i < nfrags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - void *addr = (void *)page_address(frag->page) + frag->page_offset; - - tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE); - - td_ptr->tx.buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]); - td_ptr->tx.buf[i + 1].pa_high = 0; - td_ptr->tx.buf[i + 1].size = cpu_to_le16(frag->size); - } - tdinfo->nskb_dma = i - 1; - } + /* + * Map the linear network buffer into PCI space and + * add it to the transmit ring. + */ + tdinfo->skb = skb; + tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); + td_ptr->tdesc0.len = len; + td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); + td_ptr->td_buf[0].pa_high = 0; + td_ptr->td_buf[0].size = len; + tdinfo->nskb_dma = 1; - } else -#endif - { - /* - * Map the linear network buffer into PCI space and - * add it to the transmit ring. - */ - tdinfo->skb = skb; - tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); - td_ptr->tdesc0.len = len; - td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); - td_ptr->td_buf[0].pa_high = 0; - td_ptr->td_buf[0].size = len; - tdinfo->nskb_dma = 1; - } td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16; if (vptr->vlgrp && vlan_tx_tag_present(skb)) { -- cgit v0.10.2 From c40674001b162f9218ba2a6f26188177c6a4e763 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 20 Jul 2009 17:35:21 +0000 Subject: Fix up CodingStyle problems in via-velocity.c Signed-off-by: Dave Jones Signed-off-by: David S. Miller diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 4ebe2ca..d6a92b7 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -61,9 +61,9 @@ #include #include #include -#include +#include #include -#include +#include #include #include #include @@ -81,7 +81,7 @@ #include "via-velocity.h" -static int velocity_nics = 0; +static int velocity_nics; static int msglevel = MSG_LEVEL_INFO; /** @@ -93,7 +93,7 @@ static int msglevel = MSG_LEVEL_INFO; * provided mask buffer. */ -static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask) +static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask) { int i; @@ -111,7 +111,6 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask) /* Select mar */ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - } @@ -123,7 +122,7 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask) * Store a new mask into a CAM */ -static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask) +static void mac_set_cam_mask(struct mac_regs __iomem *regs, u8 *mask) { int i; /* Select CAM mask */ @@ -131,9 +130,9 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask) writeb(CAMADDR_CAMEN, ®s->CAMADDR); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) writeb(*mask++, &(regs->MARCAM[i])); - } + /* disable CAMEN */ writeb(0, ®s->CAMADDR); @@ -141,7 +140,7 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask) BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); } -static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask) +static void mac_set_vlan_cam_mask(struct mac_regs __iomem *regs, u8 *mask) { int i; /* Select CAM mask */ @@ -149,9 +148,9 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask) writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, ®s->CAMADDR); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) writeb(*mask++, &(regs->MARCAM[i])); - } + /* disable CAMEN */ writeb(0, ®s->CAMADDR); @@ -168,7 +167,7 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask) * Load an address or vlan tag into a CAM */ -static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr) +static void mac_set_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr) { int i; @@ -179,9 +178,9 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr) writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) writeb(*addr++, &(regs->MARCAM[i])); - } + BYTE_REG_BITS_ON(CAMCR_CAMWR, ®s->CAMCR); udelay(10); @@ -192,7 +191,7 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr) BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); } -static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx, +static void mac_set_vlan_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr) { @@ -224,7 +223,7 @@ static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx, * the rest of the logic from the result of sleep/wakeup */ -static void mac_wol_reset(struct mac_regs __iomem * regs) +static void mac_wol_reset(struct mac_regs __iomem *regs) { /* Turn off SWPTAG right after leaving power mode */ @@ -253,10 +252,10 @@ MODULE_AUTHOR("VIA Networking Technologies, Inc."); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"); -#define VELOCITY_PARAM(N,D) \ - static int N[MAX_UNITS]=OPTION_DEFAULT;\ +#define VELOCITY_PARAM(N, D) \ + static int N[MAX_UNITS] = OPTION_DEFAULT;\ module_param_array(N, int, NULL, 0); \ - MODULE_PARM_DESC(N, D); + MODULE_PARM_DESC(N, D); #define RX_DESC_MIN 64 #define RX_DESC_MAX 255 @@ -336,8 +335,8 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability"); 4: indicate 10Mbps full duplex mode Note: - if EEPROM have been set to the force mode, this option is ignored - by driver. + if EEPROM have been set to the force mode, this option is ignored + by driver. */ VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode"); @@ -391,14 +390,14 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status); static u32 velocity_get_link(struct net_device *dev); static u32 velocity_get_opt_media_mode(struct velocity_info *vptr); static void velocity_print_link_status(struct velocity_info *vptr); -static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs); +static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs); static void velocity_shutdown(struct velocity_info *vptr); static void enable_flow_control_ability(struct velocity_info *vptr); -static void enable_mii_autopoll(struct mac_regs __iomem * regs); -static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 * pdata); +static void enable_mii_autopoll(struct mac_regs __iomem *regs); +static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 *pdata); static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data); -static u32 mii_check_media_mode(struct mac_regs __iomem * regs); -static u32 check_connection_type(struct mac_regs __iomem * regs); +static u32 mii_check_media_mode(struct mac_regs __iomem *regs); +static u32 check_connection_type(struct mac_regs __iomem *regs); static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status); #ifdef CONFIG_PM @@ -550,7 +549,7 @@ static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, * we don't duplicate code for each option. */ -static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, const char *devname) +static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag, char *name, const char *devname) { (*opt) &= (~flag); if (val == -1) @@ -604,7 +603,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index, static void velocity_init_cam_filter(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */ WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, ®s->MCFG); @@ -647,19 +646,19 @@ static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) { struct velocity_info *vptr = netdev_priv(dev); - spin_lock_irq(&vptr->lock); + spin_lock_irq(&vptr->lock); velocity_init_cam_filter(vptr); - spin_unlock_irq(&vptr->lock); + spin_unlock_irq(&vptr->lock); } static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { struct velocity_info *vptr = netdev_priv(dev); - spin_lock_irq(&vptr->lock); + spin_lock_irq(&vptr->lock); vlan_group_set_device(vptr->vlgrp, vid, NULL); velocity_init_cam_filter(vptr); - spin_unlock_irq(&vptr->lock); + spin_unlock_irq(&vptr->lock); } static void velocity_init_rx_ring_indexes(struct velocity_info *vptr) @@ -678,7 +677,7 @@ static void velocity_init_rx_ring_indexes(struct velocity_info *vptr) static void velocity_rx_reset(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; int i; velocity_init_rx_ring_indexes(vptr); @@ -707,7 +706,7 @@ static void velocity_rx_reset(struct velocity_info *vptr) static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; int i, mii_status; mac_wol_reset(regs); @@ -750,9 +749,9 @@ static void velocity_init_registers(struct velocity_info *vptr, mdelay(5); mac_eeprom_reload(regs); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) writeb(vptr->dev->dev_addr[i], &(regs->PAR[i])); - } + /* * clear Pre_ACPI bit. */ @@ -829,7 +828,7 @@ static void velocity_init_registers(struct velocity_info *vptr, static int velocity_soft_reset(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; int i = 0; writel(CR0_SFRST, ®s->CR0Set); @@ -881,7 +880,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi const char *drv_string; const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data]; struct velocity_info *vptr; - struct mac_regs __iomem * regs; + struct mac_regs __iomem *regs; int ret = -ENOMEM; /* FIXME: this driver, like almost all other ethernet drivers, @@ -1311,7 +1310,7 @@ static int velocity_init_td_ring(struct velocity_info *vptr) sizeof(struct velocity_td_info), GFP_KERNEL); if (!vptr->tx.infos[j]) { - while(--j >= 0) + while (--j >= 0) kfree(vptr->tx.infos[j]); return -ENOMEM; } @@ -1328,15 +1327,14 @@ static int velocity_init_td_ring(struct velocity_info *vptr) static void velocity_free_td_ring_entry(struct velocity_info *vptr, int q, int n) { - struct velocity_td_info * td_info = &(vptr->tx.infos[q][n]); + struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]); int i; if (td_info == NULL) return; if (td_info->skb) { - for (i = 0; i < td_info->nskb_dma; i++) - { + for (i = 0; i < td_info->nskb_dma; i++) { if (td_info->skb_dma[i]) { pci_unmap_single(vptr->pdev, td_info->skb_dma[i], td_info->skb->len, PCI_DMA_TODEVICE); @@ -1363,10 +1361,9 @@ static void velocity_free_td_ring(struct velocity_info *vptr) for (j = 0; j < vptr->tx.numq; j++) { if (vptr->tx.infos[j] == NULL) continue; - for (i = 0; i < vptr->options.numtx; i++) { + for (i = 0; i < vptr->options.numtx; i++) velocity_free_td_ring_entry(vptr, j, i); - } kfree(vptr->tx.infos[j]); vptr->tx.infos[j] = NULL; } @@ -1447,9 +1444,8 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) if (rd->rdesc1.CSM & CSM_IPOK) { if ((rd->rdesc1.CSM & CSM_TCPKT) || (rd->rdesc1.CSM & CSM_UDPKT)) { - if (!(rd->rdesc1.CSM & CSM_TUPOK)) { + if (!(rd->rdesc1.CSM & CSM_TUPOK)) return; - } } skb->ip_summed = CHECKSUM_UNNECESSARY; } @@ -1671,9 +1667,8 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status) } vptr->tx.tail[qnum] = idx; - if (AVAIL_TD(vptr, qnum) < 1) { + if (AVAIL_TD(vptr, qnum) < 1) full = 1; - } } /* * Look to see if we should kick the transmit network @@ -1751,7 +1746,7 @@ static void velocity_error(struct velocity_info *vptr, int status) { if (status & ISR_TXSTLI) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(®s->TDIdx[0])); BYTE_REG_BITS_ON(TXESR_TDSTR, ®s->TXESR); @@ -1763,7 +1758,7 @@ static void velocity_error(struct velocity_info *vptr, int status) } if (status & ISR_SRCI) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; int linked; if (vptr->options.spd_dpx == SPD_DPX_AUTO) { @@ -1783,11 +1778,10 @@ static void velocity_error(struct velocity_info *vptr, int status) /* * Only enable CD heart beat counter in 10HD mode */ - if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) { + if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); - } else { + else BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); - } } /* * Get link status from PHYSR0 @@ -2023,7 +2017,7 @@ out_0: static void velocity_shutdown(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; mac_disable_int(regs); writel(CR0_STOP, ®s->CR0Set); writew(0xFFFF, ®s->TDCSRClr); @@ -2195,8 +2189,7 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance) if (isr_status & (ISR_PTXI | ISR_PPTXI)) max_count += velocity_tx_srv(vptr, isr_status); isr_status = mac_read_isr(vptr->mac_regs); - if (max_count > vptr->options.int_works) - { + if (max_count > vptr->options.int_works) { printk(KERN_WARNING "%s: excessive work at interrupt.\n", dev->name); max_count = 0; @@ -2221,7 +2214,7 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance) static void velocity_set_multi(struct net_device *dev) { struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; u8 rx_mode; int i; struct dev_mc_list *mclist; @@ -2270,7 +2263,7 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev) struct velocity_info *vptr = netdev_priv(dev); /* If the hardware is down, don't touch MII */ - if(!netif_running(dev)) + if (!netif_running(dev)) return &dev->stats; spin_lock_irq(&vptr->lock); @@ -2473,7 +2466,7 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status) * Turn off the autopoll and wait for it to disable on the chip */ -static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs) +static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs) { u16 ww; @@ -2494,7 +2487,7 @@ static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs) * hardware. Wait for it to enable. */ -static void enable_mii_autopoll(struct mac_regs __iomem * regs) +static void enable_mii_autopoll(struct mac_regs __iomem *regs) { int ii; @@ -2644,7 +2637,7 @@ static void mii_set_auto_on(struct velocity_info *vptr) /* -static void mii_set_auto_off(struct velocity_info * vptr) +static void mii_set_auto_off(struct velocity_info *vptr) { MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); } @@ -2698,7 +2691,7 @@ static void set_mii_flow_control(struct velocity_info *vptr) static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) { u32 curr_status; - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; vptr->mii_status = mii_check_media_mode(vptr->mac_regs); curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL); @@ -2717,9 +2710,8 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) } */ - if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) { + if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs); - } /* * If connection type is AUTO @@ -2768,11 +2760,11 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); - if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) { + if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); - } else { + else BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); - } + /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */ velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR); ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)); @@ -2805,7 +2797,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) * accordingly */ -static u32 mii_check_media_mode(struct mac_regs __iomem * regs) +static u32 mii_check_media_mode(struct mac_regs __iomem *regs) { u32 status = 0; u16 ANAR; @@ -2841,7 +2833,7 @@ static u32 mii_check_media_mode(struct mac_regs __iomem * regs) return status; } -static u32 check_connection_type(struct mac_regs __iomem * regs) +static u32 check_connection_type(struct mac_regs __iomem *regs) { u32 status = 0; u8 PHYSR0; @@ -2886,7 +2878,7 @@ static u32 check_connection_type(struct mac_regs __iomem * regs) static void enable_flow_control_ability(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; switch (vptr->options.flow_cntl) { @@ -2963,7 +2955,7 @@ static void velocity_ethtool_down(struct net_device *dev) static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; u32 status; status = check_connection_type(vptr->mac_regs); @@ -3020,7 +3012,7 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd static u32 velocity_get_link(struct net_device *dev) { struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, ®s->PHYSR0) ? 1 : 0; } @@ -3116,7 +3108,7 @@ static const struct ethtool_ops velocity_ethtool_ops = { static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; unsigned long flags; struct mii_ioctl_data *miidata = if_mii(ifr); int err; @@ -3128,7 +3120,7 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd case SIOCGMIIREG: if (!capable(CAP_NET_ADMIN)) return -EPERM; - if(velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0) + if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0) return -ETIMEDOUT; break; case SIOCSMIIREG: @@ -3138,7 +3130,7 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in); spin_unlock_irqrestore(&vptr->lock, flags); check_connection_type(vptr->mac_regs); - if(err) + if (err) return err; break; default: @@ -3160,9 +3152,9 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd * power down states */ -static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context) +static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; u16 i; u8 __iomem *ptr = (u8 __iomem *)regs; @@ -3188,13 +3180,12 @@ static void velocity_save_context(struct velocity_info *vptr, struct velocity_co static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; int i; u8 __iomem *ptr = (u8 __iomem *)regs; - for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) { + for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) writel(*((u32 *) (context->mac_reg + i)), ptr + i); - } /* Just skip cr0 */ for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) { @@ -3204,18 +3195,14 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity writeb(*((u8 *) (context->mac_reg + i)), ptr + i); } - for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) { + for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) writel(*((u32 *) (context->mac_reg + i)), ptr + i); - } - for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) { + for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) writel(*((u32 *) (context->mac_reg + i)), ptr + i); - } - for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) { + for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) writeb(*((u8 *) (context->mac_reg + i)), ptr + i); - } - } /** @@ -3227,7 +3214,7 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity * we are interested in. */ -static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) +static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern) { u16 crc = 0xFFFF; u8 mask; @@ -3266,7 +3253,7 @@ static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) static int velocity_set_wol(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; static u8 buf[256]; int i; @@ -3284,9 +3271,8 @@ static int velocity_set_wol(struct velocity_info *vptr) writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), ®s->WOLCRSet); */ - if (vptr->wol_opts & VELOCITY_WOL_UCAST) { + if (vptr->wol_opts & VELOCITY_WOL_UCAST) writew(WOLCR_UNICAST_EN, ®s->WOLCRSet); - } if (vptr->wol_opts & VELOCITY_WOL_ARP) { struct arp_packet *arp = (struct arp_packet *) buf; @@ -3347,7 +3333,7 @@ static int velocity_suspend(struct pci_dev *pdev, pm_message_t state) struct velocity_info *vptr = netdev_priv(dev); unsigned long flags; - if(!netif_running(vptr->dev)) + if (!netif_running(vptr->dev)) return 0; netif_device_detach(vptr->dev); @@ -3382,7 +3368,7 @@ static int velocity_resume(struct pci_dev *pdev) unsigned long flags; int i; - if(!netif_running(vptr->dev)) + if (!netif_running(vptr->dev)) return 0; pci_set_power_state(pdev, PCI_D0); @@ -3399,9 +3385,8 @@ static int velocity_resume(struct pci_dev *pdev) velocity_tx_srv(vptr, 0); for (i = 0; i < vptr->tx.numq; i++) { - if (vptr->tx.used[i]) { + if (vptr->tx.used[i]) mac_tx_queue_wake(vptr->mac_regs, i); - } } mac_enable_int(vptr->mac_regs); -- cgit v0.10.2 From 2cf71d2e388cb0076b03f40f2fadfc590c228461 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 23 Jul 2009 18:11:12 -0700 Subject: Remove unnecessary forward declarations from velocity NIC driver. By moving functions to before their first call, we eliminate the need to define forward references. Signed-off-by: Dave Jones Signed-off-by: David S. Miller diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index d6a92b7..47be41a 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -92,7 +92,6 @@ static int msglevel = MSG_LEVEL_INFO; * Fetch the mask bits of the selected CAM and store them into the * provided mask buffer. */ - static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask) { int i; @@ -121,7 +120,6 @@ static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask) * * Store a new mask into a CAM */ - static void mac_set_cam_mask(struct mac_regs __iomem *regs, u8 *mask) { int i; @@ -166,7 +164,6 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem *regs, u8 *mask) * * Load an address or vlan tag into a CAM */ - static void mac_set_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr) { int i; @@ -222,7 +219,6 @@ static void mac_set_vlan_cam(struct mac_regs __iomem *regs, int idx, * reset the Wake on lan features. This function doesn't restore * the rest of the logic from the result of sleep/wakeup */ - static void mac_wol_reset(struct mac_regs __iomem *regs) { @@ -241,7 +237,6 @@ static void mac_wol_reset(struct mac_regs __iomem *regs) writew(0xFFFF, ®s->WOLSRClr); } -static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static const struct ethtool_ops velocity_ethtool_ops; /* @@ -369,76 +364,14 @@ static int rx_copybreak = 200; module_param(rx_copybreak, int, 0644); MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); -static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, - const struct velocity_info_tbl *info); -static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev); -static void velocity_print_info(struct velocity_info *vptr); -static int velocity_open(struct net_device *dev); -static int velocity_change_mtu(struct net_device *dev, int mtu); -static int velocity_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t velocity_intr(int irq, void *dev_instance); -static void velocity_set_multi(struct net_device *dev); -static struct net_device_stats *velocity_get_stats(struct net_device *dev); -static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int velocity_close(struct net_device *dev); -static int velocity_receive_frame(struct velocity_info *, int idx); -static int velocity_alloc_rx_buf(struct velocity_info *, int idx); -static void velocity_free_rd_ring(struct velocity_info *vptr); -static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *); -static int velocity_soft_reset(struct velocity_info *vptr); -static void mii_init(struct velocity_info *vptr, u32 mii_status); -static u32 velocity_get_link(struct net_device *dev); -static u32 velocity_get_opt_media_mode(struct velocity_info *vptr); -static void velocity_print_link_status(struct velocity_info *vptr); -static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs); -static void velocity_shutdown(struct velocity_info *vptr); -static void enable_flow_control_ability(struct velocity_info *vptr); -static void enable_mii_autopoll(struct mac_regs __iomem *regs); -static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 *pdata); -static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data); -static u32 mii_check_media_mode(struct mac_regs __iomem *regs); -static u32 check_connection_type(struct mac_regs __iomem *regs); -static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status); - #ifdef CONFIG_PM - -static int velocity_suspend(struct pci_dev *pdev, pm_message_t state); -static int velocity_resume(struct pci_dev *pdev); - static DEFINE_SPINLOCK(velocity_dev_list_lock); static LIST_HEAD(velocity_dev_list); - -#endif - -#if defined(CONFIG_PM) && defined(CONFIG_INET) - -static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr); - -static struct notifier_block velocity_inetaddr_notifier = { - .notifier_call = velocity_netdev_event, -}; - -static void velocity_register_notifier(void) -{ - register_inetaddr_notifier(&velocity_inetaddr_notifier); -} - -static void velocity_unregister_notifier(void) -{ - unregister_inetaddr_notifier(&velocity_inetaddr_notifier); -} - -#else - -#define velocity_register_notifier() do {} while (0) -#define velocity_unregister_notifier() do {} while (0) - #endif /* * Internal board variants. At the moment we have only one */ - static struct velocity_info_tbl chip_info_table[] = { {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL}, { } @@ -448,7 +381,6 @@ static struct velocity_info_tbl chip_info_table[] = { * Describe the PCI device identifiers that we support in this * device driver. Used for hotplug autoloading. */ - static const struct pci_device_id velocity_id_table[] __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) }, { } @@ -463,7 +395,6 @@ MODULE_DEVICE_TABLE(pci, velocity_id_table); * Given a chip identifier return a suitable description. Returns * a pointer a static string valid while the driver is loaded. */ - static const char __devinit *get_chip_name(enum chip_type chip_id) { int i; @@ -481,7 +412,6 @@ static const char __devinit *get_chip_name(enum chip_type chip_id) * unload for each active device that is present. Disconnects * the device from the network layer and frees all the resources */ - static void __devexit velocity_remove1(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -519,7 +449,6 @@ static void __devexit velocity_remove1(struct pci_dev *pdev) * all the verification and checking as well as reporting so that * we don't duplicate code for each option. */ - static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, const char *devname) { if (val == -1) @@ -548,7 +477,6 @@ static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, * all the verification and checking as well as reporting so that * we don't duplicate code for each option. */ - static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag, char *name, const char *devname) { (*opt) &= (~flag); @@ -574,7 +502,6 @@ static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag * Turn the module and command options into a single structure * for the current device */ - static void __devinit velocity_get_options(struct velocity_opt *opts, int index, const char *devname) { @@ -600,7 +527,6 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index, * Initialize the content addressable memory used for filters. Load * appropriately according to the presence of VLAN */ - static void velocity_init_cam_filter(struct velocity_info *vptr) { struct mac_regs __iomem *regs = vptr->mac_regs; @@ -673,7 +599,6 @@ static void velocity_init_rx_ring_indexes(struct velocity_info *vptr) * Reset the ownership and status for the receive ring side. * Hand all the receive queue to the NIC. */ - static void velocity_rx_reset(struct velocity_info *vptr) { @@ -695,883 +620,846 @@ static void velocity_rx_reset(struct velocity_info *vptr) } /** - * velocity_init_registers - initialise MAC registers - * @vptr: velocity to init - * @type: type of initialisation (hot or cold) + * velocity_get_opt_media_mode - get media selection + * @vptr: velocity adapter * - * Initialise the MAC on a reset or on first set up on the - * hardware. + * Get the media mode stored in EEPROM or module options and load + * mii_status accordingly. The requested link state information + * is also returned. */ - -static void velocity_init_registers(struct velocity_info *vptr, - enum velocity_init_type type) +static u32 velocity_get_opt_media_mode(struct velocity_info *vptr) { - struct mac_regs __iomem *regs = vptr->mac_regs; - int i, mii_status; - - mac_wol_reset(regs); - - switch (type) { - case VELOCITY_INIT_RESET: - case VELOCITY_INIT_WOL: - - netif_stop_queue(vptr->dev); - - /* - * Reset RX to prevent RX pointer not on the 4X location - */ - velocity_rx_reset(vptr); - mac_rx_queue_run(regs); - mac_rx_queue_wake(regs); - - mii_status = velocity_get_opt_media_mode(vptr); - if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { - velocity_print_link_status(vptr); - if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) - netif_wake_queue(vptr->dev); - } - - enable_flow_control_ability(vptr); - - mac_clear_isr(regs); - writel(CR0_STOP, ®s->CR0Clr); - writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), - ®s->CR0Set); + u32 status = 0; + switch (vptr->options.spd_dpx) { + case SPD_DPX_AUTO: + status = VELOCITY_AUTONEG_ENABLE; break; + case SPD_DPX_100_FULL: + status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL; + break; + case SPD_DPX_10_FULL: + status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL; + break; + case SPD_DPX_100_HALF: + status = VELOCITY_SPEED_100; + break; + case SPD_DPX_10_HALF: + status = VELOCITY_SPEED_10; + break; + } + vptr->mii_status = status; + return status; +} - case VELOCITY_INIT_COLD: - default: - /* - * Do reset - */ - velocity_soft_reset(vptr); - mdelay(5); - - mac_eeprom_reload(regs); - for (i = 0; i < 6; i++) - writeb(vptr->dev->dev_addr[i], &(regs->PAR[i])); - - /* - * clear Pre_ACPI bit. - */ - BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA)); - mac_set_rx_thresh(regs, vptr->options.rx_thresh); - mac_set_dma_length(regs, vptr->options.DMA_length); - - writeb(WOLCFG_SAM | WOLCFG_SAB, ®s->WOLCFGSet); - /* - * Back off algorithm use original IEEE standard - */ - BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), ®s->CFGB); +/** + * safe_disable_mii_autopoll - autopoll off + * @regs: velocity registers + * + * Turn off the autopoll and wait for it to disable on the chip + */ +static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs) +{ + u16 ww; - /* - * Init CAM filter - */ - velocity_init_cam_filter(vptr); + /* turn off MAUTO */ + writeb(0, ®s->MIICR); + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + udelay(1); + if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) + break; + } +} - /* - * Set packet filter: Receive directed and broadcast address - */ - velocity_set_multi(vptr->dev); +/** + * enable_mii_autopoll - turn on autopolling + * @regs: velocity registers + * + * Enable the MII link status autopoll feature on the Velocity + * hardware. Wait for it to enable. + */ +static void enable_mii_autopoll(struct mac_regs __iomem *regs) +{ + int ii; - /* - * Enable MII auto-polling - */ - enable_mii_autopoll(regs); + writeb(0, &(regs->MIICR)); + writeb(MIIADR_SWMPL, ®s->MIIADR); - vptr->int_mask = INT_MASK_DEF; + for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { + udelay(1); + if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) + break; + } - writel(vptr->rx.pool_dma, ®s->RDBaseLo); - writew(vptr->options.numrx - 1, ®s->RDCSize); - mac_rx_queue_run(regs); - mac_rx_queue_wake(regs); + writeb(MIICR_MAUTO, ®s->MIICR); - writew(vptr->options.numtx - 1, ®s->TDCSize); + for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { + udelay(1); + if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) + break; + } - for (i = 0; i < vptr->tx.numq; i++) { - writel(vptr->tx.pool_dma[i], ®s->TDBaseLo[i]); - mac_tx_queue_run(regs, i); - } +} - init_flow_control_register(vptr); +/** + * velocity_mii_read - read MII data + * @regs: velocity registers + * @index: MII register index + * @data: buffer for received data + * + * Perform a single read of an MII 16bit register. Returns zero + * on success or -ETIMEDOUT if the PHY did not respond. + */ +static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data) +{ + u16 ww; - writel(CR0_STOP, ®s->CR0Clr); - writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), ®s->CR0Set); + /* + * Disable MIICR_MAUTO, so that mii addr can be set normally + */ + safe_disable_mii_autopoll(regs); - mii_status = velocity_get_opt_media_mode(vptr); - netif_stop_queue(vptr->dev); + writeb(index, ®s->MIIADR); - mii_init(vptr, mii_status); + BYTE_REG_BITS_ON(MIICR_RCMD, ®s->MIICR); - if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { - velocity_print_link_status(vptr); - if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) - netif_wake_queue(vptr->dev); - } + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + if (!(readb(®s->MIICR) & MIICR_RCMD)) + break; + } - enable_flow_control_ability(vptr); - mac_hw_mibs_init(regs); - mac_write_int_mask(vptr->int_mask, regs); - mac_clear_isr(regs); + *data = readw(®s->MIIDATA); - } + enable_mii_autopoll(regs); + if (ww == W_MAX_TIMEOUT) + return -ETIMEDOUT; + return 0; } + /** - * velocity_soft_reset - soft reset - * @vptr: velocity to reset + * mii_check_media_mode - check media state + * @regs: velocity registers * - * Kick off a soft reset of the velocity adapter and then poll - * until the reset sequence has completed before returning. + * Check the current MII status and determine the link status + * accordingly */ - -static int velocity_soft_reset(struct velocity_info *vptr) +static u32 mii_check_media_mode(struct mac_regs __iomem *regs) { - struct mac_regs __iomem *regs = vptr->mac_regs; - int i = 0; + u32 status = 0; + u16 ANAR; - writel(CR0_SFRST, ®s->CR0Set); + if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs)) + status |= VELOCITY_LINK_FAIL; - for (i = 0; i < W_MAX_TIMEOUT; i++) { - udelay(5); - if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, ®s->CR0Set)) - break; + if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs)) + status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL; + else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs)) + status |= (VELOCITY_SPEED_1000); + else { + velocity_mii_read(regs, MII_REG_ANAR, &ANAR); + if (ANAR & ANAR_TXFD) + status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL); + else if (ANAR & ANAR_TX) + status |= VELOCITY_SPEED_100; + else if (ANAR & ANAR_10FD) + status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL); + else + status |= (VELOCITY_SPEED_10); } - if (i == W_MAX_TIMEOUT) { - writel(CR0_FORSRST, ®s->CR0Set); - /* FIXME: PCI POSTING */ - /* delay 2ms */ - mdelay(2); + if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { + velocity_mii_read(regs, MII_REG_ANAR, &ANAR); + if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) + == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { + if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs)) + status |= VELOCITY_AUTONEG_ENABLE; + } } - return 0; -} -static const struct net_device_ops velocity_netdev_ops = { - .ndo_open = velocity_open, - .ndo_stop = velocity_close, - .ndo_start_xmit = velocity_xmit, - .ndo_get_stats = velocity_get_stats, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, - .ndo_set_multicast_list = velocity_set_multi, - .ndo_change_mtu = velocity_change_mtu, - .ndo_do_ioctl = velocity_ioctl, - .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid, - .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid, - .ndo_vlan_rx_register = velocity_vlan_rx_register, -}; + return status; +} /** - * velocity_found1 - set up discovered velocity card - * @pdev: PCI device - * @ent: PCI device table entry that matched + * velocity_mii_write - write MII data + * @regs: velocity registers + * @index: MII register index + * @data: 16bit data for the MII register * - * Configure a discovered adapter from scratch. Return a negative - * errno error code on failure paths. + * Perform a single write to an MII 16bit register. Returns zero + * on success or -ETIMEDOUT if the PHY did not respond. */ - -static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent) +static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data) { - static int first = 1; - struct net_device *dev; - int i; - const char *drv_string; - const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data]; - struct velocity_info *vptr; - struct mac_regs __iomem *regs; - int ret = -ENOMEM; + u16 ww; - /* FIXME: this driver, like almost all other ethernet drivers, - * can support more than MAX_UNITS. + /* + * Disable MIICR_MAUTO, so that mii addr can be set normally */ - if (velocity_nics >= MAX_UNITS) { - dev_notice(&pdev->dev, "already found %d NICs.\n", - velocity_nics); - return -ENODEV; - } + safe_disable_mii_autopoll(regs); - dev = alloc_etherdev(sizeof(struct velocity_info)); - if (!dev) { - dev_err(&pdev->dev, "allocate net device failed.\n"); - goto out; + /* MII reg offset */ + writeb(mii_addr, ®s->MIIADR); + /* set MII data */ + writew(data, ®s->MIIDATA); + + /* turn on MIICR_WCMD */ + BYTE_REG_BITS_ON(MIICR_WCMD, ®s->MIICR); + + /* W_MAX_TIMEOUT is the timeout period */ + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + udelay(5); + if (!(readb(®s->MIICR) & MIICR_WCMD)) + break; } + enable_mii_autopoll(regs); - /* Chain it all together */ + if (ww == W_MAX_TIMEOUT) + return -ETIMEDOUT; + return 0; +} - SET_NETDEV_DEV(dev, &pdev->dev); - vptr = netdev_priv(dev); +/** + * set_mii_flow_control - flow control setup + * @vptr: velocity interface + * + * Set up the flow control on this interface according to + * the supplied user/eeprom options. + */ +static void set_mii_flow_control(struct velocity_info *vptr) +{ + /*Enable or Disable PAUSE in ANAR */ + switch (vptr->options.flow_cntl) { + case FLOW_CNTL_TX: + MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; + case FLOW_CNTL_RX: + MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; - if (first) { - printk(KERN_INFO "%s Ver. %s\n", - VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION); - printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n"); - printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n"); - first = 0; - } + case FLOW_CNTL_TX_RX: + MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; - velocity_init_info(pdev, vptr, info); + case FLOW_CNTL_DISABLE: + MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; + default: + break; + } +} - vptr->dev = dev; +/** + * mii_set_auto_on - autonegotiate on + * @vptr: velocity + * + * Enable autonegotation on this interface + */ +static void mii_set_auto_on(struct velocity_info *vptr) +{ + if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs)) + MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs); + else + MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); +} - dev->irq = pdev->irq; +static u32 check_connection_type(struct mac_regs __iomem *regs) +{ + u32 status = 0; + u8 PHYSR0; + u16 ANAR; + PHYSR0 = readb(®s->PHYSR0); - ret = pci_enable_device(pdev); - if (ret < 0) - goto err_free_dev; + /* + if (!(PHYSR0 & PHYSR0_LINKGD)) + status|=VELOCITY_LINK_FAIL; + */ - ret = velocity_get_pci_info(vptr, pdev); - if (ret < 0) { - /* error message already printed */ - goto err_disable; - } + if (PHYSR0 & PHYSR0_FDPX) + status |= VELOCITY_DUPLEX_FULL; - ret = pci_request_regions(pdev, VELOCITY_NAME); - if (ret < 0) { - dev_err(&pdev->dev, "No PCI resources.\n"); - goto err_disable; - } + if (PHYSR0 & PHYSR0_SPDG) + status |= VELOCITY_SPEED_1000; + else if (PHYSR0 & PHYSR0_SPD10) + status |= VELOCITY_SPEED_10; + else + status |= VELOCITY_SPEED_100; - regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE); - if (regs == NULL) { - ret = -EIO; - goto err_release_res; + if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { + velocity_mii_read(regs, MII_REG_ANAR, &ANAR); + if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) + == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { + if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs)) + status |= VELOCITY_AUTONEG_ENABLE; + } } - vptr->mac_regs = regs; - - mac_wol_reset(regs); + return status; +} - dev->base_addr = vptr->ioaddr; - for (i = 0; i < 6; i++) - dev->dev_addr[i] = readb(®s->PAR[i]); +/** + * velocity_set_media_mode - set media mode + * @mii_status: old MII link state + * + * Check the media link state and configure the flow control + * PHY and also velocity hardware setup accordingly. In particular + * we need to set up CD polling and frame bursting. + */ +static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) +{ + u32 curr_status; + struct mac_regs __iomem *regs = vptr->mac_regs; - drv_string = dev_driver_string(&pdev->dev); + vptr->mii_status = mii_check_media_mode(vptr->mac_regs); + curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL); - velocity_get_options(&vptr->options, velocity_nics, drv_string); + /* Set mii link status */ + set_mii_flow_control(vptr); /* - * Mask out the options cannot be set to the chip + Check if new status is consisent with current status + if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE) + || (mii_status==curr_status)) { + vptr->mii_status=mii_check_media_mode(vptr->mac_regs); + vptr->mii_status=check_connection_type(vptr->mac_regs); + VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n"); + return 0; + } */ - vptr->options.flags &= info->flags; + if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) + MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs); /* - * Enable the chip specified capbilities + * If connection type is AUTO */ + if (mii_status & VELOCITY_AUTONEG_ENABLE) { + VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n"); + /* clear force MAC mode bit */ + BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); + /* set duplex mode of MAC according to duplex mode of MII */ + MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); + MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); - vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL); + /* enable AUTO-NEGO mode */ + mii_set_auto_on(vptr); + } else { + u16 ANAR; + u8 CHIPGCR; - vptr->wol_opts = vptr->options.wol_opts; - vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + /* + * 1. if it's 3119, disable frame bursting in halfduplex mode + * and enable it in fullduplex mode + * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR + * 3. only enable CD heart beat counter in 10HD mode + */ - vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs); + /* set force MAC mode bit */ + BYTE_REG_BITS_ON(CHIPGCR_FCMODE, ®s->CHIPGCR); - dev->irq = pdev->irq; - dev->netdev_ops = &velocity_netdev_ops; - dev->ethtool_ops = &velocity_ethtool_ops; + CHIPGCR = readb(®s->CHIPGCR); + CHIPGCR &= ~CHIPGCR_FCGMII; - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | - NETIF_F_HW_VLAN_RX; + if (mii_status & VELOCITY_DUPLEX_FULL) { + CHIPGCR |= CHIPGCR_FCFDX; + writeb(CHIPGCR, ®s->CHIPGCR); + VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n"); + if (vptr->rev_id < REV_ID_VT3216_A0) + BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); + } else { + CHIPGCR &= ~CHIPGCR_FCFDX; + VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n"); + writeb(CHIPGCR, ®s->CHIPGCR); + if (vptr->rev_id < REV_ID_VT3216_A0) + BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); + } - if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) - dev->features |= NETIF_F_IP_CSUM; + MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); - ret = register_netdev(dev); - if (ret < 0) - goto err_iounmap; + if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) + BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); + else + BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); - if (!velocity_get_link(dev)) { - netif_carrier_off(dev); - vptr->mii_status |= VELOCITY_LINK_FAIL; + /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */ + velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR); + ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)); + if (mii_status & VELOCITY_SPEED_100) { + if (mii_status & VELOCITY_DUPLEX_FULL) + ANAR |= ANAR_TXFD; + else + ANAR |= ANAR_TX; + } else { + if (mii_status & VELOCITY_DUPLEX_FULL) + ANAR |= ANAR_10FD; + else + ANAR |= ANAR_10; + } + velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR); + /* enable AUTO-NEGO mode */ + mii_set_auto_on(vptr); + /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */ } + /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */ + /* vptr->mii_status=check_connection_type(vptr->mac_regs); */ + return VELOCITY_LINK_CHANGE; +} - velocity_print_info(vptr); - pci_set_drvdata(pdev, dev); +/** + * velocity_print_link_status - link status reporting + * @vptr: velocity to report on + * + * Turn the link status of the velocity card into a kernel log + * description of the new link state, detailing speed and duplex + * status + */ +static void velocity_print_link_status(struct velocity_info *vptr) +{ - /* and leave the chip powered down */ + if (vptr->mii_status & VELOCITY_LINK_FAIL) { + VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name); + } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) { + VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name); - pci_set_power_state(pdev, PCI_D3hot); -#ifdef CONFIG_PM - { - unsigned long flags; + if (vptr->mii_status & VELOCITY_SPEED_1000) + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps"); + else if (vptr->mii_status & VELOCITY_SPEED_100) + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps"); + else + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps"); - spin_lock_irqsave(&velocity_dev_list_lock, flags); - list_add(&vptr->list, &velocity_dev_list); - spin_unlock_irqrestore(&velocity_dev_list_lock, flags); + if (vptr->mii_status & VELOCITY_DUPLEX_FULL) + VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n"); + else + VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n"); + } else { + VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name); + switch (vptr->options.spd_dpx) { + case SPD_DPX_100_HALF: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n"); + break; + case SPD_DPX_100_FULL: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n"); + break; + case SPD_DPX_10_HALF: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n"); + break; + case SPD_DPX_10_FULL: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n"); + break; + default: + break; + } } -#endif - velocity_nics++; -out: - return ret; - -err_iounmap: - iounmap(regs); -err_release_res: - pci_release_regions(pdev); -err_disable: - pci_disable_device(pdev); -err_free_dev: - free_netdev(dev); - goto out; } /** - * velocity_print_info - per driver data - * @vptr: velocity + * enable_flow_control_ability - flow control + * @vptr: veloity to configure * - * Print per driver data as the kernel driver finds Velocity - * hardware + * Set up flow control according to the flow control options + * determined by the eeprom/configuration. */ - -static void __devinit velocity_print_info(struct velocity_info *vptr) +static void enable_flow_control_ability(struct velocity_info *vptr) { - struct net_device *dev = vptr->dev; - printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id)); - printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", - dev->name, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); -} + struct mac_regs __iomem *regs = vptr->mac_regs; -/** - * velocity_init_info - init private data - * @pdev: PCI device - * @vptr: Velocity info - * @info: Board type - * - * Set up the initial velocity_info struct for the device that has been - * discovered. - */ + switch (vptr->options.flow_cntl) { -static void __devinit velocity_init_info(struct pci_dev *pdev, - struct velocity_info *vptr, - const struct velocity_info_tbl *info) -{ - memset(vptr, 0, sizeof(struct velocity_info)); + case FLOW_CNTL_DEFAULT: + if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, ®s->PHYSR0)) + writel(CR0_FDXRFCEN, ®s->CR0Set); + else + writel(CR0_FDXRFCEN, ®s->CR0Clr); + + if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, ®s->PHYSR0)) + writel(CR0_FDXTFCEN, ®s->CR0Set); + else + writel(CR0_FDXTFCEN, ®s->CR0Clr); + break; + + case FLOW_CNTL_TX: + writel(CR0_FDXTFCEN, ®s->CR0Set); + writel(CR0_FDXRFCEN, ®s->CR0Clr); + break; + + case FLOW_CNTL_RX: + writel(CR0_FDXRFCEN, ®s->CR0Set); + writel(CR0_FDXTFCEN, ®s->CR0Clr); + break; + + case FLOW_CNTL_TX_RX: + writel(CR0_FDXTFCEN, ®s->CR0Set); + writel(CR0_FDXRFCEN, ®s->CR0Set); + break; + + case FLOW_CNTL_DISABLE: + writel(CR0_FDXRFCEN, ®s->CR0Clr); + writel(CR0_FDXTFCEN, ®s->CR0Clr); + break; + + default: + break; + } - vptr->pdev = pdev; - vptr->chip_id = info->chip_id; - vptr->tx.numq = info->txqueue; - vptr->multicast_limit = MCAM_SIZE; - spin_lock_init(&vptr->lock); - INIT_LIST_HEAD(&vptr->list); } /** - * velocity_get_pci_info - retrieve PCI info for device - * @vptr: velocity device - * @pdev: PCI device it matches + * velocity_soft_reset - soft reset + * @vptr: velocity to reset * - * Retrieve the PCI configuration space data that interests us from - * the kernel PCI layer + * Kick off a soft reset of the velocity adapter and then poll + * until the reset sequence has completed before returning. */ - -static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev) +static int velocity_soft_reset(struct velocity_info *vptr) { - vptr->rev_id = pdev->revision; - - pci_set_master(pdev); - - vptr->ioaddr = pci_resource_start(pdev, 0); - vptr->memaddr = pci_resource_start(pdev, 1); + struct mac_regs __iomem *regs = vptr->mac_regs; + int i = 0; - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) { - dev_err(&pdev->dev, - "region #0 is not an I/O resource, aborting.\n"); - return -EINVAL; - } + writel(CR0_SFRST, ®s->CR0Set); - if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) { - dev_err(&pdev->dev, - "region #1 is an I/O resource, aborting.\n"); - return -EINVAL; + for (i = 0; i < W_MAX_TIMEOUT; i++) { + udelay(5); + if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, ®s->CR0Set)) + break; } - if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) { - dev_err(&pdev->dev, "region #1 is too small.\n"); - return -EINVAL; + if (i == W_MAX_TIMEOUT) { + writel(CR0_FORSRST, ®s->CR0Set); + /* FIXME: PCI POSTING */ + /* delay 2ms */ + mdelay(2); } - vptr->pdev = pdev; - return 0; } /** - * velocity_init_dma_rings - set up DMA rings - * @vptr: Velocity to set up + * velocity_set_multi - filter list change callback + * @dev: network device * - * Allocate PCI mapped DMA rings for the receive and transmit layer - * to use. - */ - -static int velocity_init_dma_rings(struct velocity_info *vptr) -{ - struct velocity_opt *opt = &vptr->options; - const unsigned int rx_ring_size = opt->numrx * sizeof(struct rx_desc); - const unsigned int tx_ring_size = opt->numtx * sizeof(struct tx_desc); - struct pci_dev *pdev = vptr->pdev; - dma_addr_t pool_dma; - void *pool; - unsigned int i; - - /* - * Allocate all RD/TD rings a single pool. - * - * pci_alloc_consistent() fulfills the requirement for 64 bytes - * alignment - */ - pool = pci_alloc_consistent(pdev, tx_ring_size * vptr->tx.numq + - rx_ring_size, &pool_dma); - if (!pool) { - dev_err(&pdev->dev, "%s : DMA memory allocation failed.\n", - vptr->dev->name); - return -ENOMEM; - } - - vptr->rx.ring = pool; - vptr->rx.pool_dma = pool_dma; - - pool += rx_ring_size; - pool_dma += rx_ring_size; - - for (i = 0; i < vptr->tx.numq; i++) { - vptr->tx.rings[i] = pool; - vptr->tx.pool_dma[i] = pool_dma; - pool += tx_ring_size; - pool_dma += tx_ring_size; - } - - return 0; -} - -/** - * velocity_free_dma_rings - free PCI ring pointers - * @vptr: Velocity to free from - * - * Clean up the PCI ring buffers allocated to this velocity. + * Called by the network layer when the filter lists need to change + * for a velocity adapter. Reload the CAMs with the new address + * filter ruleset. */ - -static void velocity_free_dma_rings(struct velocity_info *vptr) -{ - const int size = vptr->options.numrx * sizeof(struct rx_desc) + - vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq; - - pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma); -} - -static void velocity_give_many_rx_descs(struct velocity_info *vptr) +static void velocity_set_multi(struct net_device *dev) { + struct velocity_info *vptr = netdev_priv(dev); struct mac_regs __iomem *regs = vptr->mac_regs; - int avail, dirty, unusable; - - /* - * RD number must be equal to 4X per hardware spec - * (programming guide rev 1.20, p.13) - */ - if (vptr->rx.filled < 4) - return; - - wmb(); - - unusable = vptr->rx.filled & 0x0003; - dirty = vptr->rx.dirty - unusable; - for (avail = vptr->rx.filled & 0xfffc; avail; avail--) { - dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1; - vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC; - } - - writew(vptr->rx.filled & 0xfffc, ®s->RBRDU); - vptr->rx.filled = unusable; -} - -static int velocity_rx_refill(struct velocity_info *vptr) -{ - int dirty = vptr->rx.dirty, done = 0; - - do { - struct rx_desc *rd = vptr->rx.ring + dirty; + u8 rx_mode; + int i; + struct dev_mc_list *mclist; - /* Fine for an all zero Rx desc at init time as well */ - if (rd->rdesc0.len & OWNED_BY_NIC) - break; + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + writel(0xffffffff, ®s->MARCAM[0]); + writel(0xffffffff, ®s->MARCAM[4]); + rx_mode = (RCR_AM | RCR_AB | RCR_PROM); + } else if ((dev->mc_count > vptr->multicast_limit) + || (dev->flags & IFF_ALLMULTI)) { + writel(0xffffffff, ®s->MARCAM[0]); + writel(0xffffffff, ®s->MARCAM[4]); + rx_mode = (RCR_AM | RCR_AB); + } else { + int offset = MCAM_SIZE - vptr->multicast_limit; + mac_get_cam_mask(regs, vptr->mCAMmask); - if (!vptr->rx.info[dirty].skb) { - if (velocity_alloc_rx_buf(vptr, dirty) < 0) - break; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { + mac_set_cam(regs, i + offset, mclist->dmi_addr); + vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7); } - done++; - dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0; - } while (dirty != vptr->rx.curr); - if (done) { - vptr->rx.dirty = dirty; - vptr->rx.filled += done; + mac_set_cam_mask(regs, vptr->mCAMmask); + rx_mode = RCR_AM | RCR_AB | RCR_AP; } + if (dev->mtu > 1500) + rx_mode |= RCR_AL; - return done; -} + BYTE_REG_BITS_ON(rx_mode, ®s->RCR); -static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu) -{ - vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32; } -/** - * velocity_init_rd_ring - set up receive ring - * @vptr: velocity to configure - * - * Allocate and set up the receive buffers for each ring slot and - * assign them to the network adapter. +/* + * MII access , media link mode setting functions */ -static int velocity_init_rd_ring(struct velocity_info *vptr) -{ - int ret = -ENOMEM; - - vptr->rx.info = kcalloc(vptr->options.numrx, - sizeof(struct velocity_rd_info), GFP_KERNEL); - if (!vptr->rx.info) - goto out; - - velocity_init_rx_ring_indexes(vptr); - - if (velocity_rx_refill(vptr) != vptr->options.numrx) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR - "%s: failed to allocate RX buffer.\n", vptr->dev->name); - velocity_free_rd_ring(vptr); - goto out; - } - - ret = 0; -out: - return ret; -} - /** - * velocity_free_rd_ring - free receive ring - * @vptr: velocity to clean up + * mii_init - set up MII + * @vptr: velocity adapter + * @mii_status: links tatus * - * Free the receive buffers for each ring slot and any - * attached socket buffers that need to go away. + * Set up the PHY for the current link state. */ - -static void velocity_free_rd_ring(struct velocity_info *vptr) +static void mii_init(struct velocity_info *vptr, u32 mii_status) { - int i; - - if (vptr->rx.info == NULL) - return; - - for (i = 0; i < vptr->options.numrx; i++) { - struct velocity_rd_info *rd_info = &(vptr->rx.info[i]); - struct rx_desc *rd = vptr->rx.ring + i; - - memset(rd, 0, sizeof(*rd)); + u16 BMCR; - if (!rd_info->skb) - continue; - pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz, - PCI_DMA_FROMDEVICE); - rd_info->skb_dma = 0; + switch (PHYID_GET_PHY_ID(vptr->phy_id)) { + case PHYID_CICADA_CS8201: + /* + * Reset to hardware default + */ + MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); + /* + * Turn on ECHODIS bit in NWay-forced full mode and turn it + * off it in NWay-forced half mode for NWay-forced v.s. + * legacy-forced issue. + */ + if (vptr->mii_status & VELOCITY_DUPLEX_FULL) + MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + else + MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + /* + * Turn on Link/Activity LED enable bit for CIS8201 + */ + MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs); + break; + case PHYID_VT3216_32BIT: + case PHYID_VT3216_64BIT: + /* + * Reset to hardware default + */ + MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); + /* + * Turn on ECHODIS bit in NWay-forced full mode and turn it + * off it in NWay-forced half mode for NWay-forced v.s. + * legacy-forced issue + */ + if (vptr->mii_status & VELOCITY_DUPLEX_FULL) + MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + else + MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + break; - dev_kfree_skb(rd_info->skb); - rd_info->skb = NULL; + case PHYID_MARVELL_1000: + case PHYID_MARVELL_1000S: + /* + * Assert CRS on Transmit + */ + MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs); + /* + * Reset to hardware default + */ + MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); + break; + default: + ; + } + velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR); + if (BMCR & BMCR_ISO) { + BMCR &= ~BMCR_ISO; + velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR); } - - kfree(vptr->rx.info); - vptr->rx.info = NULL; } + /** - * velocity_init_td_ring - set up transmit ring - * @vptr: velocity + * velocity_init_registers - initialise MAC registers + * @vptr: velocity to init + * @type: type of initialisation (hot or cold) * - * Set up the transmit ring and chain the ring pointers together. - * Returns zero on success or a negative posix errno code for - * failure. + * Initialise the MAC on a reset or on first set up on the + * hardware. */ - -static int velocity_init_td_ring(struct velocity_info *vptr) +static void velocity_init_registers(struct velocity_info *vptr, + enum velocity_init_type type) { - dma_addr_t curr; - int j; - - /* Init the TD ring entries */ - for (j = 0; j < vptr->tx.numq; j++) { - curr = vptr->tx.pool_dma[j]; - - vptr->tx.infos[j] = kcalloc(vptr->options.numtx, - sizeof(struct velocity_td_info), - GFP_KERNEL); - if (!vptr->tx.infos[j]) { - while (--j >= 0) - kfree(vptr->tx.infos[j]); - return -ENOMEM; - } + struct mac_regs __iomem *regs = vptr->mac_regs; + int i, mii_status; - vptr->tx.tail[j] = vptr->tx.curr[j] = vptr->tx.used[j] = 0; - } - return 0; -} + mac_wol_reset(regs); -/* - * FIXME: could we merge this with velocity_free_tx_buf ? - */ + switch (type) { + case VELOCITY_INIT_RESET: + case VELOCITY_INIT_WOL: -static void velocity_free_td_ring_entry(struct velocity_info *vptr, - int q, int n) -{ - struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]); - int i; + netif_stop_queue(vptr->dev); - if (td_info == NULL) - return; + /* + * Reset RX to prevent RX pointer not on the 4X location + */ + velocity_rx_reset(vptr); + mac_rx_queue_run(regs); + mac_rx_queue_wake(regs); - if (td_info->skb) { - for (i = 0; i < td_info->nskb_dma; i++) { - if (td_info->skb_dma[i]) { - pci_unmap_single(vptr->pdev, td_info->skb_dma[i], - td_info->skb->len, PCI_DMA_TODEVICE); - td_info->skb_dma[i] = 0; - } + mii_status = velocity_get_opt_media_mode(vptr); + if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { + velocity_print_link_status(vptr); + if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) + netif_wake_queue(vptr->dev); } - dev_kfree_skb(td_info->skb); - td_info->skb = NULL; - } -} - -/** - * velocity_free_td_ring - free td ring - * @vptr: velocity - * - * Free up the transmit ring for this particular velocity adapter. - * We free the ring contents but not the ring itself. - */ - -static void velocity_free_td_ring(struct velocity_info *vptr) -{ - int i, j; - - for (j = 0; j < vptr->tx.numq; j++) { - if (vptr->tx.infos[j] == NULL) - continue; - for (i = 0; i < vptr->options.numtx; i++) - velocity_free_td_ring_entry(vptr, j, i); - kfree(vptr->tx.infos[j]); - vptr->tx.infos[j] = NULL; - } -} + enable_flow_control_ability(vptr); -/** - * velocity_rx_srv - service RX interrupt - * @vptr: velocity - * @status: adapter status (unused) - * - * Walk the receive ring of the velocity adapter and remove - * any received packets from the receive queue. Hand the ring - * slots back to the adapter for reuse. - */ + mac_clear_isr(regs); + writel(CR0_STOP, ®s->CR0Clr); + writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), + ®s->CR0Set); -static int velocity_rx_srv(struct velocity_info *vptr, int status) -{ - struct net_device_stats *stats = &vptr->dev->stats; - int rd_curr = vptr->rx.curr; - int works = 0; + break; - do { - struct rx_desc *rd = vptr->rx.ring + rd_curr; + case VELOCITY_INIT_COLD: + default: + /* + * Do reset + */ + velocity_soft_reset(vptr); + mdelay(5); - if (!vptr->rx.info[rd_curr].skb) - break; + mac_eeprom_reload(regs); + for (i = 0; i < 6; i++) + writeb(vptr->dev->dev_addr[i], &(regs->PAR[i])); - if (rd->rdesc0.len & OWNED_BY_NIC) - break; + /* + * clear Pre_ACPI bit. + */ + BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA)); + mac_set_rx_thresh(regs, vptr->options.rx_thresh); + mac_set_dma_length(regs, vptr->options.DMA_length); - rmb(); + writeb(WOLCFG_SAM | WOLCFG_SAB, ®s->WOLCFGSet); + /* + * Back off algorithm use original IEEE standard + */ + BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), ®s->CFGB); /* - * Don't drop CE or RL error frame although RXOK is off + * Init CAM filter */ - if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) { - if (velocity_receive_frame(vptr, rd_curr) < 0) - stats->rx_dropped++; - } else { - if (rd->rdesc0.RSR & RSR_CRC) - stats->rx_crc_errors++; - if (rd->rdesc0.RSR & RSR_FAE) - stats->rx_frame_errors++; + velocity_init_cam_filter(vptr); - stats->rx_dropped++; - } + /* + * Set packet filter: Receive directed and broadcast address + */ + velocity_set_multi(vptr->dev); - rd->size |= RX_INTEN; + /* + * Enable MII auto-polling + */ + enable_mii_autopoll(regs); - rd_curr++; - if (rd_curr >= vptr->options.numrx) - rd_curr = 0; - } while (++works <= 15); + vptr->int_mask = INT_MASK_DEF; - vptr->rx.curr = rd_curr; + writel(vptr->rx.pool_dma, ®s->RDBaseLo); + writew(vptr->options.numrx - 1, ®s->RDCSize); + mac_rx_queue_run(regs); + mac_rx_queue_wake(regs); - if ((works > 0) && (velocity_rx_refill(vptr) > 0)) - velocity_give_many_rx_descs(vptr); + writew(vptr->options.numtx - 1, ®s->TDCSize); - VAR_USED(stats); - return works; -} + for (i = 0; i < vptr->tx.numq; i++) { + writel(vptr->tx.pool_dma[i], ®s->TDBaseLo[i]); + mac_tx_queue_run(regs, i); + } -/** - * velocity_rx_csum - checksum process - * @rd: receive packet descriptor - * @skb: network layer packet buffer - * - * Process the status bits for the received packet and determine - * if the checksum was computed and verified by the hardware - */ + init_flow_control_register(vptr); -static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) -{ - skb->ip_summed = CHECKSUM_NONE; + writel(CR0_STOP, ®s->CR0Clr); + writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), ®s->CR0Set); - if (rd->rdesc1.CSM & CSM_IPKT) { - if (rd->rdesc1.CSM & CSM_IPOK) { - if ((rd->rdesc1.CSM & CSM_TCPKT) || - (rd->rdesc1.CSM & CSM_UDPKT)) { - if (!(rd->rdesc1.CSM & CSM_TUPOK)) - return; - } - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - } -} + mii_status = velocity_get_opt_media_mode(vptr); + netif_stop_queue(vptr->dev); -/** - * velocity_rx_copy - in place Rx copy for small packets - * @rx_skb: network layer packet buffer candidate - * @pkt_size: received data size - * @rd: receive packet descriptor - * @dev: network device - * - * Replace the current skb that is scheduled for Rx processing by a - * shorter, immediatly allocated skb, if the received packet is small - * enough. This function returns a negative value if the received - * packet is too big or if memory is exhausted. - */ -static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, - struct velocity_info *vptr) -{ - int ret = -1; - if (pkt_size < rx_copybreak) { - struct sk_buff *new_skb; + mii_init(vptr, mii_status); - new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2); - if (new_skb) { - new_skb->ip_summed = rx_skb[0]->ip_summed; - skb_reserve(new_skb, 2); - skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size); - *rx_skb = new_skb; - ret = 0; + if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { + velocity_print_link_status(vptr); + if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) + netif_wake_queue(vptr->dev); } + enable_flow_control_ability(vptr); + mac_hw_mibs_init(regs); + mac_write_int_mask(vptr->int_mask, regs); + mac_clear_isr(regs); + } - return ret; } -/** - * velocity_iph_realign - IP header alignment - * @vptr: velocity we are handling - * @skb: network layer packet buffer - * @pkt_size: received data size - * - * Align IP header on a 2 bytes boundary. This behavior can be - * configured by the user. - */ -static inline void velocity_iph_realign(struct velocity_info *vptr, - struct sk_buff *skb, int pkt_size) +static void velocity_give_many_rx_descs(struct velocity_info *vptr) { - if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { - memmove(skb->data + 2, skb->data, pkt_size); - skb_reserve(skb, 2); + struct mac_regs __iomem *regs = vptr->mac_regs; + int avail, dirty, unusable; + + /* + * RD number must be equal to 4X per hardware spec + * (programming guide rev 1.20, p.13) + */ + if (vptr->rx.filled < 4) + return; + + wmb(); + + unusable = vptr->rx.filled & 0x0003; + dirty = vptr->rx.dirty - unusable; + for (avail = vptr->rx.filled & 0xfffc; avail; avail--) { + dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1; + vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC; } + + writew(vptr->rx.filled & 0xfffc, ®s->RBRDU); + vptr->rx.filled = unusable; } /** - * velocity_receive_frame - received packet processor - * @vptr: velocity we are handling - * @idx: ring index + * velocity_init_dma_rings - set up DMA rings + * @vptr: Velocity to set up * - * A packet has arrived. We process the packet and if appropriate - * pass the frame up the network stack + * Allocate PCI mapped DMA rings for the receive and transmit layer + * to use. */ - -static int velocity_receive_frame(struct velocity_info *vptr, int idx) +static int velocity_init_dma_rings(struct velocity_info *vptr) { - void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int); - struct net_device_stats *stats = &vptr->dev->stats; - struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]); - struct rx_desc *rd = &(vptr->rx.ring[idx]); - int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff; - struct sk_buff *skb; - - if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) { - VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame span multple RDs.\n", vptr->dev->name); - stats->rx_length_errors++; - return -EINVAL; - } - - if (rd->rdesc0.RSR & RSR_MAR) - stats->multicast++; - - skb = rd_info->skb; - - pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma, - vptr->rx.buf_sz, PCI_DMA_FROMDEVICE); + struct velocity_opt *opt = &vptr->options; + const unsigned int rx_ring_size = opt->numrx * sizeof(struct rx_desc); + const unsigned int tx_ring_size = opt->numtx * sizeof(struct tx_desc); + struct pci_dev *pdev = vptr->pdev; + dma_addr_t pool_dma; + void *pool; + unsigned int i; /* - * Drop frame not meeting IEEE 802.3 + * Allocate all RD/TD rings a single pool. + * + * pci_alloc_consistent() fulfills the requirement for 64 bytes + * alignment */ - - if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) { - if (rd->rdesc0.RSR & RSR_RL) { - stats->rx_length_errors++; - return -EINVAL; - } - } - - pci_action = pci_dma_sync_single_for_device; - - velocity_rx_csum(rd, skb); - - if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) { - velocity_iph_realign(vptr, skb, pkt_len); - pci_action = pci_unmap_single; - rd_info->skb = NULL; + pool = pci_alloc_consistent(pdev, tx_ring_size * vptr->tx.numq + + rx_ring_size, &pool_dma); + if (!pool) { + dev_err(&pdev->dev, "%s : DMA memory allocation failed.\n", + vptr->dev->name); + return -ENOMEM; } - pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz, - PCI_DMA_FROMDEVICE); - - skb_put(skb, pkt_len - 4); - skb->protocol = eth_type_trans(skb, vptr->dev); + vptr->rx.ring = pool; + vptr->rx.pool_dma = pool_dma; - if (vptr->vlgrp && (rd->rdesc0.RSR & RSR_DETAG)) { - vlan_hwaccel_rx(skb, vptr->vlgrp, - swab16(le16_to_cpu(rd->rdesc1.PQTAG))); - } else - netif_rx(skb); + pool += rx_ring_size; + pool_dma += rx_ring_size; - stats->rx_bytes += pkt_len; + for (i = 0; i < vptr->tx.numq; i++) { + vptr->tx.rings[i] = pool; + vptr->tx.pool_dma[i] = pool_dma; + pool += tx_ring_size; + pool_dma += tx_ring_size; + } return 0; } +static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu) +{ + vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32; +} + /** * velocity_alloc_rx_buf - allocate aligned receive buffer * @vptr: velocity @@ -1582,7 +1470,6 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) * requires *64* byte alignment of the buffer which makes life * less fun than would be ideal. */ - static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) { struct rx_desc *rd = &(vptr->rx.ring[idx]); @@ -1611,243 +1498,146 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) return 0; } -/** - * tx_srv - transmit interrupt service - * @vptr; Velocity - * @status: - * - * Scan the queues looking for transmitted packets that - * we can complete and clean up. Update any statistics as - * necessary/ - */ -static int velocity_tx_srv(struct velocity_info *vptr, u32 status) +static int velocity_rx_refill(struct velocity_info *vptr) { - struct tx_desc *td; - int qnum; - int full = 0; - int idx; - int works = 0; - struct velocity_td_info *tdinfo; - struct net_device_stats *stats = &vptr->dev->stats; - - for (qnum = 0; qnum < vptr->tx.numq; qnum++) { - for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0; - idx = (idx + 1) % vptr->options.numtx) { + int dirty = vptr->rx.dirty, done = 0; - /* - * Get Tx Descriptor - */ - td = &(vptr->tx.rings[qnum][idx]); - tdinfo = &(vptr->tx.infos[qnum][idx]); + do { + struct rx_desc *rd = vptr->rx.ring + dirty; - if (td->tdesc0.len & OWNED_BY_NIC) - break; + /* Fine for an all zero Rx desc at init time as well */ + if (rd->rdesc0.len & OWNED_BY_NIC) + break; - if ((works++ > 15)) + if (!vptr->rx.info[dirty].skb) { + if (velocity_alloc_rx_buf(vptr, dirty) < 0) break; - - if (td->tdesc0.TSR & TSR0_TERR) { - stats->tx_errors++; - stats->tx_dropped++; - if (td->tdesc0.TSR & TSR0_CDH) - stats->tx_heartbeat_errors++; - if (td->tdesc0.TSR & TSR0_CRS) - stats->tx_carrier_errors++; - if (td->tdesc0.TSR & TSR0_ABT) - stats->tx_aborted_errors++; - if (td->tdesc0.TSR & TSR0_OWC) - stats->tx_window_errors++; - } else { - stats->tx_packets++; - stats->tx_bytes += tdinfo->skb->len; - } - velocity_free_tx_buf(vptr, tdinfo); - vptr->tx.used[qnum]--; } - vptr->tx.tail[qnum] = idx; + done++; + dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0; + } while (dirty != vptr->rx.curr); - if (AVAIL_TD(vptr, qnum) < 1) - full = 1; - } - /* - * Look to see if we should kick the transmit network - * layer for more work. - */ - if (netif_queue_stopped(vptr->dev) && (full == 0) - && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) { - netif_wake_queue(vptr->dev); + if (done) { + vptr->rx.dirty = dirty; + vptr->rx.filled += done; } - return works; + + return done; } /** - * velocity_print_link_status - link status reporting - * @vptr: velocity to report on + * velocity_free_rd_ring - free receive ring + * @vptr: velocity to clean up * - * Turn the link status of the velocity card into a kernel log - * description of the new link state, detailing speed and duplex - * status + * Free the receive buffers for each ring slot and any + * attached socket buffers that need to go away. */ - -static void velocity_print_link_status(struct velocity_info *vptr) +static void velocity_free_rd_ring(struct velocity_info *vptr) { + int i; - if (vptr->mii_status & VELOCITY_LINK_FAIL) { - VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name); - } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) { - VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name); - - if (vptr->mii_status & VELOCITY_SPEED_1000) - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps"); - else if (vptr->mii_status & VELOCITY_SPEED_100) - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps"); - else - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps"); - - if (vptr->mii_status & VELOCITY_DUPLEX_FULL) - VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n"); - else - VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n"); - } else { - VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name); - switch (vptr->options.spd_dpx) { - case SPD_DPX_100_HALF: - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n"); - break; - case SPD_DPX_100_FULL: - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n"); - break; - case SPD_DPX_10_HALF: - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n"); - break; - case SPD_DPX_10_FULL: - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n"); - break; - default: - break; - } - } -} - -/** - * velocity_error - handle error from controller - * @vptr: velocity - * @status: card status - * - * Process an error report from the hardware and attempt to recover - * the card itself. At the moment we cannot recover from some - * theoretically impossible errors but this could be fixed using - * the pci_device_failed logic to bounce the hardware - * - */ + if (vptr->rx.info == NULL) + return; -static void velocity_error(struct velocity_info *vptr, int status) -{ + for (i = 0; i < vptr->options.numrx; i++) { + struct velocity_rd_info *rd_info = &(vptr->rx.info[i]); + struct rx_desc *rd = vptr->rx.ring + i; - if (status & ISR_TXSTLI) { - struct mac_regs __iomem *regs = vptr->mac_regs; + memset(rd, 0, sizeof(*rd)); - printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(®s->TDIdx[0])); - BYTE_REG_BITS_ON(TXESR_TDSTR, ®s->TXESR); - writew(TRDCSR_RUN, ®s->TDCSRClr); - netif_stop_queue(vptr->dev); + if (!rd_info->skb) + continue; + pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz, + PCI_DMA_FROMDEVICE); + rd_info->skb_dma = 0; - /* FIXME: port over the pci_device_failed code and use it - here */ + dev_kfree_skb(rd_info->skb); + rd_info->skb = NULL; } - if (status & ISR_SRCI) { - struct mac_regs __iomem *regs = vptr->mac_regs; - int linked; - - if (vptr->options.spd_dpx == SPD_DPX_AUTO) { - vptr->mii_status = check_connection_type(regs); + kfree(vptr->rx.info); + vptr->rx.info = NULL; +} - /* - * If it is a 3119, disable frame bursting in - * halfduplex mode and enable it in fullduplex - * mode - */ - if (vptr->rev_id < REV_ID_VT3216_A0) { - if (vptr->mii_status | VELOCITY_DUPLEX_FULL) - BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); - else - BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); - } - /* - * Only enable CD heart beat counter in 10HD mode - */ - if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) - BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); - else - BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); - } - /* - * Get link status from PHYSR0 - */ - linked = readb(®s->PHYSR0) & PHYSR0_LINKGD; - if (linked) { - vptr->mii_status &= ~VELOCITY_LINK_FAIL; - netif_carrier_on(vptr->dev); - } else { - vptr->mii_status |= VELOCITY_LINK_FAIL; - netif_carrier_off(vptr->dev); - } - velocity_print_link_status(vptr); - enable_flow_control_ability(vptr); +/** + * velocity_init_rd_ring - set up receive ring + * @vptr: velocity to configure + * + * Allocate and set up the receive buffers for each ring slot and + * assign them to the network adapter. + */ +static int velocity_init_rd_ring(struct velocity_info *vptr) +{ + int ret = -ENOMEM; - /* - * Re-enable auto-polling because SRCI will disable - * auto-polling - */ + vptr->rx.info = kcalloc(vptr->options.numrx, + sizeof(struct velocity_rd_info), GFP_KERNEL); + if (!vptr->rx.info) + goto out; - enable_mii_autopoll(regs); + velocity_init_rx_ring_indexes(vptr); - if (vptr->mii_status & VELOCITY_LINK_FAIL) - netif_stop_queue(vptr->dev); - else - netif_wake_queue(vptr->dev); + if (velocity_rx_refill(vptr) != vptr->options.numrx) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: failed to allocate RX buffer.\n", vptr->dev->name); + velocity_free_rd_ring(vptr); + goto out; + } - }; - if (status & ISR_MIBFI) - velocity_update_hw_mibs(vptr); - if (status & ISR_LSTEI) - mac_rx_queue_wake(vptr->mac_regs); + ret = 0; +out: + return ret; } /** - * velocity_free_tx_buf - free transmit buffer - * @vptr: velocity - * @tdinfo: buffer + * velocity_init_td_ring - set up transmit ring + * @vptr: velocity * - * Release an transmit buffer. If the buffer was preallocated then - * recycle it, if not then unmap the buffer. + * Set up the transmit ring and chain the ring pointers together. + * Returns zero on success or a negative posix errno code for + * failure. */ - -static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo) +static int velocity_init_td_ring(struct velocity_info *vptr) { - struct sk_buff *skb = tdinfo->skb; - int i; - int pktlen; + dma_addr_t curr; + int j; - /* - * Don't unmap the pre-allocated tx_bufs - */ - if (tdinfo->skb_dma) { + /* Init the TD ring entries */ + for (j = 0; j < vptr->tx.numq; j++) { + curr = vptr->tx.pool_dma[j]; - pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); - for (i = 0; i < tdinfo->nskb_dma; i++) { - pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE); - tdinfo->skb_dma[i] = 0; + vptr->tx.infos[j] = kcalloc(vptr->options.numtx, + sizeof(struct velocity_td_info), + GFP_KERNEL); + if (!vptr->tx.infos[j]) { + while (--j >= 0) + kfree(vptr->tx.infos[j]); + return -ENOMEM; } + + vptr->tx.tail[j] = vptr->tx.curr[j] = vptr->tx.used[j] = 0; } - dev_kfree_skb_irq(skb); - tdinfo->skb = NULL; + return 0; +} + +/** + * velocity_free_dma_rings - free PCI ring pointers + * @vptr: Velocity to free from + * + * Clean up the PCI ring buffers allocated to this velocity. + */ +static void velocity_free_dma_rings(struct velocity_info *vptr) +{ + const int size = vptr->options.numrx * sizeof(struct rx_desc) + + vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq; + + pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma); } + static int velocity_init_rings(struct velocity_info *vptr, int mtu) { int ret; @@ -1875,1138 +1665,979 @@ err_free_dma_rings_0: goto out; } -static void velocity_free_rings(struct velocity_info *vptr) -{ - velocity_free_td_ring(vptr); - velocity_free_rd_ring(vptr); - velocity_free_dma_rings(vptr); -} - /** - * velocity_open - interface activation callback - * @dev: network layer device to open - * - * Called when the network layer brings the interface up. Returns - * a negative posix error code on failure, or zero on success. + * velocity_free_tx_buf - free transmit buffer + * @vptr: velocity + * @tdinfo: buffer * - * All the ring allocation and set up is done on open for this - * adapter to minimise memory usage when inactive + * Release an transmit buffer. If the buffer was preallocated then + * recycle it, if not then unmap the buffer. */ - -static int velocity_open(struct net_device *dev) +static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo) { - struct velocity_info *vptr = netdev_priv(dev); - int ret; - - ret = velocity_init_rings(vptr, dev->mtu); - if (ret < 0) - goto out; - - /* Ensure chip is running */ - pci_set_power_state(vptr->pdev, PCI_D0); - - velocity_give_many_rx_descs(vptr); + struct sk_buff *skb = tdinfo->skb; + int i; + int pktlen; - velocity_init_registers(vptr, VELOCITY_INIT_COLD); + /* + * Don't unmap the pre-allocated tx_bufs + */ + if (tdinfo->skb_dma) { - ret = request_irq(vptr->pdev->irq, &velocity_intr, IRQF_SHARED, - dev->name, dev); - if (ret < 0) { - /* Power down the chip */ - pci_set_power_state(vptr->pdev, PCI_D3hot); - velocity_free_rings(vptr); - goto out; + pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); + for (i = 0; i < tdinfo->nskb_dma; i++) { + pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE); + tdinfo->skb_dma[i] = 0; + } } - - mac_enable_int(vptr->mac_regs); - netif_start_queue(dev); - vptr->flags |= VELOCITY_FLAGS_OPENED; -out: - return ret; + dev_kfree_skb_irq(skb); + tdinfo->skb = NULL; } -/** - * velocity_change_mtu - MTU change callback - * @dev: network device - * @new_mtu: desired MTU - * - * Handle requests from the networking layer for MTU change on - * this interface. It gets called on a change by the network layer. - * Return zero for success or negative posix error code. - */ -static int velocity_change_mtu(struct net_device *dev, int new_mtu) +/* + * FIXME: could we merge this with velocity_free_tx_buf ? + */ +static void velocity_free_td_ring_entry(struct velocity_info *vptr, + int q, int n) { - struct velocity_info *vptr = netdev_priv(dev); - int ret = 0; - - if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n", - vptr->dev->name); - ret = -EINVAL; - goto out_0; - } - - if (!netif_running(dev)) { - dev->mtu = new_mtu; - goto out_0; - } + struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]); + int i; - if (dev->mtu != new_mtu) { - struct velocity_info *tmp_vptr; - unsigned long flags; - struct rx_info rx; - struct tx_info tx; + if (td_info == NULL) + return; - tmp_vptr = kzalloc(sizeof(*tmp_vptr), GFP_KERNEL); - if (!tmp_vptr) { - ret = -ENOMEM; - goto out_0; + if (td_info->skb) { + for (i = 0; i < td_info->nskb_dma; i++) { + if (td_info->skb_dma[i]) { + pci_unmap_single(vptr->pdev, td_info->skb_dma[i], + td_info->skb->len, PCI_DMA_TODEVICE); + td_info->skb_dma[i] = 0; + } } - - tmp_vptr->dev = dev; - tmp_vptr->pdev = vptr->pdev; - tmp_vptr->options = vptr->options; - tmp_vptr->tx.numq = vptr->tx.numq; - - ret = velocity_init_rings(tmp_vptr, new_mtu); - if (ret < 0) - goto out_free_tmp_vptr_1; - - spin_lock_irqsave(&vptr->lock, flags); - - netif_stop_queue(dev); - velocity_shutdown(vptr); - - rx = vptr->rx; - tx = vptr->tx; - - vptr->rx = tmp_vptr->rx; - vptr->tx = tmp_vptr->tx; - - tmp_vptr->rx = rx; - tmp_vptr->tx = tx; - - dev->mtu = new_mtu; - - velocity_give_many_rx_descs(vptr); - - velocity_init_registers(vptr, VELOCITY_INIT_COLD); - - mac_enable_int(vptr->mac_regs); - netif_start_queue(dev); - - spin_unlock_irqrestore(&vptr->lock, flags); - - velocity_free_rings(tmp_vptr); - -out_free_tmp_vptr_1: - kfree(tmp_vptr); + dev_kfree_skb(td_info->skb); + td_info->skb = NULL; } -out_0: - return ret; -} - -/** - * velocity_shutdown - shut down the chip - * @vptr: velocity to deactivate - * - * Shuts down the internal operations of the velocity and - * disables interrupts, autopolling, transmit and receive - */ - -static void velocity_shutdown(struct velocity_info *vptr) -{ - struct mac_regs __iomem *regs = vptr->mac_regs; - mac_disable_int(regs); - writel(CR0_STOP, ®s->CR0Set); - writew(0xFFFF, ®s->TDCSRClr); - writeb(0xFF, ®s->RDCSRClr); - safe_disable_mii_autopoll(regs); - mac_clear_isr(regs); } /** - * velocity_close - close adapter callback - * @dev: network device + * velocity_free_td_ring - free td ring + * @vptr: velocity * - * Callback from the network layer when the velocity is being - * deactivated by the network layer - */ - -static int velocity_close(struct net_device *dev) -{ - struct velocity_info *vptr = netdev_priv(dev); - - netif_stop_queue(dev); - velocity_shutdown(vptr); + * Free up the transmit ring for this particular velocity adapter. + * We free the ring contents but not the ring itself. + */ +static void velocity_free_td_ring(struct velocity_info *vptr) +{ + int i, j; - if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) - velocity_get_ip(vptr); - if (dev->irq != 0) - free_irq(dev->irq, dev); + for (j = 0; j < vptr->tx.numq; j++) { + if (vptr->tx.infos[j] == NULL) + continue; + for (i = 0; i < vptr->options.numtx; i++) + velocity_free_td_ring_entry(vptr, j, i); - /* Power down the chip */ - pci_set_power_state(vptr->pdev, PCI_D3hot); + kfree(vptr->tx.infos[j]); + vptr->tx.infos[j] = NULL; + } +} - velocity_free_rings(vptr); - vptr->flags &= (~VELOCITY_FLAGS_OPENED); - return 0; +static void velocity_free_rings(struct velocity_info *vptr) +{ + velocity_free_td_ring(vptr); + velocity_free_rd_ring(vptr); + velocity_free_dma_rings(vptr); } /** - * velocity_xmit - transmit packet callback - * @skb: buffer to transmit - * @dev: network device + * velocity_error - handle error from controller + * @vptr: velocity + * @status: card status + * + * Process an error report from the hardware and attempt to recover + * the card itself. At the moment we cannot recover from some + * theoretically impossible errors but this could be fixed using + * the pci_device_failed logic to bounce the hardware * - * Called by the networ layer to request a packet is queued to - * the velocity. Returns zero on success. */ - -static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) +static void velocity_error(struct velocity_info *vptr, int status) { - struct velocity_info *vptr = netdev_priv(dev); - int qnum = 0; - struct tx_desc *td_ptr; - struct velocity_td_info *tdinfo; - unsigned long flags; - int pktlen; - __le16 len; - int index; - - - if (skb_padto(skb, ETH_ZLEN)) - goto out; - pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); - len = cpu_to_le16(pktlen); + if (status & ISR_TXSTLI) { + struct mac_regs __iomem *regs = vptr->mac_regs; - spin_lock_irqsave(&vptr->lock, flags); + printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(®s->TDIdx[0])); + BYTE_REG_BITS_ON(TXESR_TDSTR, ®s->TXESR); + writew(TRDCSR_RUN, ®s->TDCSRClr); + netif_stop_queue(vptr->dev); - index = vptr->tx.curr[qnum]; - td_ptr = &(vptr->tx.rings[qnum][index]); - tdinfo = &(vptr->tx.infos[qnum][index]); + /* FIXME: port over the pci_device_failed code and use it + here */ + } - td_ptr->tdesc1.TCR = TCR0_TIC; - td_ptr->td_buf[0].size &= ~TD_QUEUE; + if (status & ISR_SRCI) { + struct mac_regs __iomem *regs = vptr->mac_regs; + int linked; - /* - * Map the linear network buffer into PCI space and - * add it to the transmit ring. - */ - tdinfo->skb = skb; - tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); - td_ptr->tdesc0.len = len; - td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); - td_ptr->td_buf[0].pa_high = 0; - td_ptr->td_buf[0].size = len; - tdinfo->nskb_dma = 1; + if (vptr->options.spd_dpx == SPD_DPX_AUTO) { + vptr->mii_status = check_connection_type(regs); - td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16; + /* + * If it is a 3119, disable frame bursting in + * halfduplex mode and enable it in fullduplex + * mode + */ + if (vptr->rev_id < REV_ID_VT3216_A0) { + if (vptr->mii_status | VELOCITY_DUPLEX_FULL) + BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); + else + BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); + } + /* + * Only enable CD heart beat counter in 10HD mode + */ + if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) + BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); + else + BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); + } + /* + * Get link status from PHYSR0 + */ + linked = readb(®s->PHYSR0) & PHYSR0_LINKGD; - if (vptr->vlgrp && vlan_tx_tag_present(skb)) { - td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb)); - td_ptr->tdesc1.TCR |= TCR0_VETAG; - } + if (linked) { + vptr->mii_status &= ~VELOCITY_LINK_FAIL; + netif_carrier_on(vptr->dev); + } else { + vptr->mii_status |= VELOCITY_LINK_FAIL; + netif_carrier_off(vptr->dev); + } - /* - * Handle hardware checksum - */ - if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM) - && (skb->ip_summed == CHECKSUM_PARTIAL)) { - const struct iphdr *ip = ip_hdr(skb); - if (ip->protocol == IPPROTO_TCP) - td_ptr->tdesc1.TCR |= TCR0_TCPCK; - else if (ip->protocol == IPPROTO_UDP) - td_ptr->tdesc1.TCR |= (TCR0_UDPCK); - td_ptr->tdesc1.TCR |= TCR0_IPCK; - } - { + velocity_print_link_status(vptr); + enable_flow_control_ability(vptr); - int prev = index - 1; + /* + * Re-enable auto-polling because SRCI will disable + * auto-polling + */ - if (prev < 0) - prev = vptr->options.numtx - 1; - td_ptr->tdesc0.len |= OWNED_BY_NIC; - vptr->tx.used[qnum]++; - vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx; + enable_mii_autopoll(regs); - if (AVAIL_TD(vptr, qnum) < 1) - netif_stop_queue(dev); + if (vptr->mii_status & VELOCITY_LINK_FAIL) + netif_stop_queue(vptr->dev); + else + netif_wake_queue(vptr->dev); - td_ptr = &(vptr->tx.rings[qnum][prev]); - td_ptr->td_buf[0].size |= TD_QUEUE; - mac_tx_queue_wake(vptr->mac_regs, qnum); - } - dev->trans_start = jiffies; - spin_unlock_irqrestore(&vptr->lock, flags); -out: - return NETDEV_TX_OK; + }; + if (status & ISR_MIBFI) + velocity_update_hw_mibs(vptr); + if (status & ISR_LSTEI) + mac_rx_queue_wake(vptr->mac_regs); } /** - * velocity_intr - interrupt callback - * @irq: interrupt number - * @dev_instance: interrupting device + * tx_srv - transmit interrupt service + * @vptr; Velocity + * @status: * - * Called whenever an interrupt is generated by the velocity - * adapter IRQ line. We may not be the source of the interrupt - * and need to identify initially if we are, and if not exit as - * efficiently as possible. + * Scan the queues looking for transmitted packets that + * we can complete and clean up. Update any statistics as + * necessary/ */ - -static irqreturn_t velocity_intr(int irq, void *dev_instance) +static int velocity_tx_srv(struct velocity_info *vptr, u32 status) { - struct net_device *dev = dev_instance; - struct velocity_info *vptr = netdev_priv(dev); - u32 isr_status; - int max_count = 0; + struct tx_desc *td; + int qnum; + int full = 0; + int idx; + int works = 0; + struct velocity_td_info *tdinfo; + struct net_device_stats *stats = &vptr->dev->stats; + for (qnum = 0; qnum < vptr->tx.numq; qnum++) { + for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0; + idx = (idx + 1) % vptr->options.numtx) { - spin_lock(&vptr->lock); - isr_status = mac_read_isr(vptr->mac_regs); + /* + * Get Tx Descriptor + */ + td = &(vptr->tx.rings[qnum][idx]); + tdinfo = &(vptr->tx.infos[qnum][idx]); - /* Not us ? */ - if (isr_status == 0) { - spin_unlock(&vptr->lock); - return IRQ_NONE; - } + if (td->tdesc0.len & OWNED_BY_NIC) + break; - mac_disable_int(vptr->mac_regs); + if ((works++ > 15)) + break; + + if (td->tdesc0.TSR & TSR0_TERR) { + stats->tx_errors++; + stats->tx_dropped++; + if (td->tdesc0.TSR & TSR0_CDH) + stats->tx_heartbeat_errors++; + if (td->tdesc0.TSR & TSR0_CRS) + stats->tx_carrier_errors++; + if (td->tdesc0.TSR & TSR0_ABT) + stats->tx_aborted_errors++; + if (td->tdesc0.TSR & TSR0_OWC) + stats->tx_window_errors++; + } else { + stats->tx_packets++; + stats->tx_bytes += tdinfo->skb->len; + } + velocity_free_tx_buf(vptr, tdinfo); + vptr->tx.used[qnum]--; + } + vptr->tx.tail[qnum] = idx; + if (AVAIL_TD(vptr, qnum) < 1) + full = 1; + } /* - * Keep processing the ISR until we have completed - * processing and the isr_status becomes zero + * Look to see if we should kick the transmit network + * layer for more work. */ + if (netif_queue_stopped(vptr->dev) && (full == 0) + && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) { + netif_wake_queue(vptr->dev); + } + return works; +} + +/** + * velocity_rx_csum - checksum process + * @rd: receive packet descriptor + * @skb: network layer packet buffer + * + * Process the status bits for the received packet and determine + * if the checksum was computed and verified by the hardware + */ +static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; - while (isr_status != 0) { - mac_write_isr(vptr->mac_regs, isr_status); - if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI))) - velocity_error(vptr, isr_status); - if (isr_status & (ISR_PRXI | ISR_PPRXI)) - max_count += velocity_rx_srv(vptr, isr_status); - if (isr_status & (ISR_PTXI | ISR_PPTXI)) - max_count += velocity_tx_srv(vptr, isr_status); - isr_status = mac_read_isr(vptr->mac_regs); - if (max_count > vptr->options.int_works) { - printk(KERN_WARNING "%s: excessive work at interrupt.\n", - dev->name); - max_count = 0; + if (rd->rdesc1.CSM & CSM_IPKT) { + if (rd->rdesc1.CSM & CSM_IPOK) { + if ((rd->rdesc1.CSM & CSM_TCPKT) || + (rd->rdesc1.CSM & CSM_UDPKT)) { + if (!(rd->rdesc1.CSM & CSM_TUPOK)) + return; + } + skb->ip_summed = CHECKSUM_UNNECESSARY; } } - spin_unlock(&vptr->lock); - mac_enable_int(vptr->mac_regs); - return IRQ_HANDLED; - } - /** - * velocity_set_multi - filter list change callback + * velocity_rx_copy - in place Rx copy for small packets + * @rx_skb: network layer packet buffer candidate + * @pkt_size: received data size + * @rd: receive packet descriptor * @dev: network device * - * Called by the network layer when the filter lists need to change - * for a velocity adapter. Reload the CAMs with the new address - * filter ruleset. + * Replace the current skb that is scheduled for Rx processing by a + * shorter, immediatly allocated skb, if the received packet is small + * enough. This function returns a negative value if the received + * packet is too big or if memory is exhausted. */ - -static void velocity_set_multi(struct net_device *dev) +static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, + struct velocity_info *vptr) { - struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem *regs = vptr->mac_regs; - u8 rx_mode; - int i; - struct dev_mc_list *mclist; - - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - writel(0xffffffff, ®s->MARCAM[0]); - writel(0xffffffff, ®s->MARCAM[4]); - rx_mode = (RCR_AM | RCR_AB | RCR_PROM); - } else if ((dev->mc_count > vptr->multicast_limit) - || (dev->flags & IFF_ALLMULTI)) { - writel(0xffffffff, ®s->MARCAM[0]); - writel(0xffffffff, ®s->MARCAM[4]); - rx_mode = (RCR_AM | RCR_AB); - } else { - int offset = MCAM_SIZE - vptr->multicast_limit; - mac_get_cam_mask(regs, vptr->mCAMmask); + int ret = -1; + if (pkt_size < rx_copybreak) { + struct sk_buff *new_skb; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { - mac_set_cam(regs, i + offset, mclist->dmi_addr); - vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7); + new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2); + if (new_skb) { + new_skb->ip_summed = rx_skb[0]->ip_summed; + skb_reserve(new_skb, 2); + skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size); + *rx_skb = new_skb; + ret = 0; } - mac_set_cam_mask(regs, vptr->mCAMmask); - rx_mode = RCR_AM | RCR_AB | RCR_AP; } - if (dev->mtu > 1500) - rx_mode |= RCR_AL; - - BYTE_REG_BITS_ON(rx_mode, ®s->RCR); - + return ret; } /** - * velocity_get_status - statistics callback - * @dev: network device + * velocity_iph_realign - IP header alignment + * @vptr: velocity we are handling + * @skb: network layer packet buffer + * @pkt_size: received data size * - * Callback from the network layer to allow driver statistics - * to be resynchronized with hardware collected state. In the - * case of the velocity we need to pull the MIB counters from - * the hardware into the counters before letting the network - * layer display them. + * Align IP header on a 2 bytes boundary. This behavior can be + * configured by the user. */ - -static struct net_device_stats *velocity_get_stats(struct net_device *dev) +static inline void velocity_iph_realign(struct velocity_info *vptr, + struct sk_buff *skb, int pkt_size) { - struct velocity_info *vptr = netdev_priv(dev); + if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { + memmove(skb->data + 2, skb->data, pkt_size); + skb_reserve(skb, 2); + } +} - /* If the hardware is down, don't touch MII */ - if (!netif_running(dev)) - return &dev->stats; - spin_lock_irq(&vptr->lock); - velocity_update_hw_mibs(vptr); - spin_unlock_irq(&vptr->lock); +/** + * velocity_receive_frame - received packet processor + * @vptr: velocity we are handling + * @idx: ring index + * + * A packet has arrived. We process the packet and if appropriate + * pass the frame up the network stack + */ +static int velocity_receive_frame(struct velocity_info *vptr, int idx) +{ + void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int); + struct net_device_stats *stats = &vptr->dev->stats; + struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]); + struct rx_desc *rd = &(vptr->rx.ring[idx]); + int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff; + struct sk_buff *skb; - dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts]; - dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts]; - dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors]; + if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) { + VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame span multple RDs.\n", vptr->dev->name); + stats->rx_length_errors++; + return -EINVAL; + } -// unsigned long rx_dropped; /* no space in linux buffers */ - dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions]; - /* detailed rx_errors: */ -// unsigned long rx_length_errors; -// unsigned long rx_over_errors; /* receiver ring buff overflow */ - dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE]; -// unsigned long rx_frame_errors; /* recv'd frame alignment error */ -// unsigned long rx_fifo_errors; /* recv'r fifo overrun */ -// unsigned long rx_missed_errors; /* receiver missed packet */ + if (rd->rdesc0.RSR & RSR_MAR) + stats->multicast++; - /* detailed tx_errors */ -// unsigned long tx_fifo_errors; + skb = rd_info->skb; - return &dev->stats; -} + pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma, + vptr->rx.buf_sz, PCI_DMA_FROMDEVICE); + /* + * Drop frame not meeting IEEE 802.3 + */ -/** - * velocity_ioctl - ioctl entry point - * @dev: network device - * @rq: interface request ioctl - * @cmd: command code - * - * Called when the user issues an ioctl request to the network - * device in question. The velocity interface supports MII. - */ + if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) { + if (rd->rdesc0.RSR & RSR_RL) { + stats->rx_length_errors++; + return -EINVAL; + } + } -static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct velocity_info *vptr = netdev_priv(dev); - int ret; + pci_action = pci_dma_sync_single_for_device; - /* If we are asked for information and the device is power - saving then we need to bring the device back up to talk to it */ + velocity_rx_csum(rd, skb); - if (!netif_running(dev)) - pci_set_power_state(vptr->pdev, PCI_D0); + if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) { + velocity_iph_realign(vptr, skb, pkt_len); + pci_action = pci_unmap_single; + rd_info->skb = NULL; + } - switch (cmd) { - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCSMIIREG: /* Write to MII PHY register. */ - ret = velocity_mii_ioctl(dev, rq, cmd); - break; + pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz, + PCI_DMA_FROMDEVICE); - default: - ret = -EOPNOTSUPP; - } - if (!netif_running(dev)) - pci_set_power_state(vptr->pdev, PCI_D3hot); + skb_put(skb, pkt_len - 4); + skb->protocol = eth_type_trans(skb, vptr->dev); + + if (vptr->vlgrp && (rd->rdesc0.RSR & RSR_DETAG)) { + vlan_hwaccel_rx(skb, vptr->vlgrp, + swab16(le16_to_cpu(rd->rdesc1.PQTAG))); + } else + netif_rx(skb); + stats->rx_bytes += pkt_len; - return ret; + return 0; } -/* - * Definition for our device driver. The PCI layer interface - * uses this to handle all our card discover and plugging - */ - -static struct pci_driver velocity_driver = { - .name = VELOCITY_NAME, - .id_table = velocity_id_table, - .probe = velocity_found1, - .remove = __devexit_p(velocity_remove1), -#ifdef CONFIG_PM - .suspend = velocity_suspend, - .resume = velocity_resume, -#endif -}; /** - * velocity_init_module - load time function + * velocity_rx_srv - service RX interrupt + * @vptr: velocity + * @status: adapter status (unused) * - * Called when the velocity module is loaded. The PCI driver - * is registered with the PCI layer, and in turn will call - * the probe functions for each velocity adapter installed - * in the system. + * Walk the receive ring of the velocity adapter and remove + * any received packets from the receive queue. Hand the ring + * slots back to the adapter for reuse. */ - -static int __init velocity_init_module(void) +static int velocity_rx_srv(struct velocity_info *vptr, int status) { - int ret; + struct net_device_stats *stats = &vptr->dev->stats; + int rd_curr = vptr->rx.curr; + int works = 0; + + do { + struct rx_desc *rd = vptr->rx.ring + rd_curr; + + if (!vptr->rx.info[rd_curr].skb) + break; + + if (rd->rdesc0.len & OWNED_BY_NIC) + break; + + rmb(); - velocity_register_notifier(); - ret = pci_register_driver(&velocity_driver); - if (ret < 0) - velocity_unregister_notifier(); - return ret; -} + /* + * Don't drop CE or RL error frame although RXOK is off + */ + if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) { + if (velocity_receive_frame(vptr, rd_curr) < 0) + stats->rx_dropped++; + } else { + if (rd->rdesc0.RSR & RSR_CRC) + stats->rx_crc_errors++; + if (rd->rdesc0.RSR & RSR_FAE) + stats->rx_frame_errors++; -/** - * velocity_cleanup - module unload - * - * When the velocity hardware is unloaded this function is called. - * It will clean up the notifiers and the unregister the PCI - * driver interface for this hardware. This in turn cleans up - * all discovered interfaces before returning from the function - */ + stats->rx_dropped++; + } -static void __exit velocity_cleanup_module(void) -{ - velocity_unregister_notifier(); - pci_unregister_driver(&velocity_driver); -} + rd->size |= RX_INTEN; -module_init(velocity_init_module); -module_exit(velocity_cleanup_module); + rd_curr++; + if (rd_curr >= vptr->options.numrx) + rd_curr = 0; + } while (++works <= 15); + vptr->rx.curr = rd_curr; -/* - * MII access , media link mode setting functions - */ + if ((works > 0) && (velocity_rx_refill(vptr) > 0)) + velocity_give_many_rx_descs(vptr); + + VAR_USED(stats); + return works; +} /** - * mii_init - set up MII - * @vptr: velocity adapter - * @mii_status: links tatus + * velocity_intr - interrupt callback + * @irq: interrupt number + * @dev_instance: interrupting device * - * Set up the PHY for the current link state. + * Called whenever an interrupt is generated by the velocity + * adapter IRQ line. We may not be the source of the interrupt + * and need to identify initially if we are, and if not exit as + * efficiently as possible. */ - -static void mii_init(struct velocity_info *vptr, u32 mii_status) +static irqreturn_t velocity_intr(int irq, void *dev_instance) { - u16 BMCR; + struct net_device *dev = dev_instance; + struct velocity_info *vptr = netdev_priv(dev); + u32 isr_status; + int max_count = 0; - switch (PHYID_GET_PHY_ID(vptr->phy_id)) { - case PHYID_CICADA_CS8201: - /* - * Reset to hardware default - */ - MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); - /* - * Turn on ECHODIS bit in NWay-forced full mode and turn it - * off it in NWay-forced half mode for NWay-forced v.s. - * legacy-forced issue. - */ - if (vptr->mii_status & VELOCITY_DUPLEX_FULL) - MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); - else - MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); - /* - * Turn on Link/Activity LED enable bit for CIS8201 - */ - MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs); - break; - case PHYID_VT3216_32BIT: - case PHYID_VT3216_64BIT: - /* - * Reset to hardware default - */ - MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); - /* - * Turn on ECHODIS bit in NWay-forced full mode and turn it - * off it in NWay-forced half mode for NWay-forced v.s. - * legacy-forced issue - */ - if (vptr->mii_status & VELOCITY_DUPLEX_FULL) - MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); - else - MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); - break; - case PHYID_MARVELL_1000: - case PHYID_MARVELL_1000S: - /* - * Assert CRS on Transmit - */ - MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs); - /* - * Reset to hardware default - */ - MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); - break; - default: - ; - } - velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR); - if (BMCR & BMCR_ISO) { - BMCR &= ~BMCR_ISO; - velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR); + spin_lock(&vptr->lock); + isr_status = mac_read_isr(vptr->mac_regs); + + /* Not us ? */ + if (isr_status == 0) { + spin_unlock(&vptr->lock); + return IRQ_NONE; } -} -/** - * safe_disable_mii_autopoll - autopoll off - * @regs: velocity registers - * - * Turn off the autopoll and wait for it to disable on the chip - */ + mac_disable_int(vptr->mac_regs); -static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs) -{ - u16 ww; + /* + * Keep processing the ISR until we have completed + * processing and the isr_status becomes zero + */ - /* turn off MAUTO */ - writeb(0, ®s->MIICR); - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - udelay(1); - if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) - break; + while (isr_status != 0) { + mac_write_isr(vptr->mac_regs, isr_status); + if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI))) + velocity_error(vptr, isr_status); + if (isr_status & (ISR_PRXI | ISR_PPRXI)) + max_count += velocity_rx_srv(vptr, isr_status); + if (isr_status & (ISR_PTXI | ISR_PPTXI)) + max_count += velocity_tx_srv(vptr, isr_status); + isr_status = mac_read_isr(vptr->mac_regs); + if (max_count > vptr->options.int_works) { + printk(KERN_WARNING "%s: excessive work at interrupt.\n", + dev->name); + max_count = 0; + } } + spin_unlock(&vptr->lock); + mac_enable_int(vptr->mac_regs); + return IRQ_HANDLED; + } /** - * enable_mii_autopoll - turn on autopolling - * @regs: velocity registers + * velocity_open - interface activation callback + * @dev: network layer device to open * - * Enable the MII link status autopoll feature on the Velocity - * hardware. Wait for it to enable. + * Called when the network layer brings the interface up. Returns + * a negative posix error code on failure, or zero on success. + * + * All the ring allocation and set up is done on open for this + * adapter to minimise memory usage when inactive */ - -static void enable_mii_autopoll(struct mac_regs __iomem *regs) +static int velocity_open(struct net_device *dev) { - int ii; + struct velocity_info *vptr = netdev_priv(dev); + int ret; - writeb(0, &(regs->MIICR)); - writeb(MIIADR_SWMPL, ®s->MIIADR); + ret = velocity_init_rings(vptr, dev->mtu); + if (ret < 0) + goto out; - for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { - udelay(1); - if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) - break; - } + /* Ensure chip is running */ + pci_set_power_state(vptr->pdev, PCI_D0); - writeb(MIICR_MAUTO, ®s->MIICR); + velocity_give_many_rx_descs(vptr); - for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { - udelay(1); - if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) - break; + velocity_init_registers(vptr, VELOCITY_INIT_COLD); + + ret = request_irq(vptr->pdev->irq, &velocity_intr, IRQF_SHARED, + dev->name, dev); + if (ret < 0) { + /* Power down the chip */ + pci_set_power_state(vptr->pdev, PCI_D3hot); + velocity_free_rings(vptr); + goto out; } + mac_enable_int(vptr->mac_regs); + netif_start_queue(dev); + vptr->flags |= VELOCITY_FLAGS_OPENED; +out: + return ret; } /** - * velocity_mii_read - read MII data - * @regs: velocity registers - * @index: MII register index - * @data: buffer for received data + * velocity_shutdown - shut down the chip + * @vptr: velocity to deactivate * - * Perform a single read of an MII 16bit register. Returns zero - * on success or -ETIMEDOUT if the PHY did not respond. + * Shuts down the internal operations of the velocity and + * disables interrupts, autopolling, transmit and receive */ - -static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data) +static void velocity_shutdown(struct velocity_info *vptr) { - u16 ww; - - /* - * Disable MIICR_MAUTO, so that mii addr can be set normally - */ + struct mac_regs __iomem *regs = vptr->mac_regs; + mac_disable_int(regs); + writel(CR0_STOP, ®s->CR0Set); + writew(0xFFFF, ®s->TDCSRClr); + writeb(0xFF, ®s->RDCSRClr); safe_disable_mii_autopoll(regs); + mac_clear_isr(regs); +} - writeb(index, ®s->MIIADR); +/** + * velocity_change_mtu - MTU change callback + * @dev: network device + * @new_mtu: desired MTU + * + * Handle requests from the networking layer for MTU change on + * this interface. It gets called on a change by the network layer. + * Return zero for success or negative posix error code. + */ +static int velocity_change_mtu(struct net_device *dev, int new_mtu) +{ + struct velocity_info *vptr = netdev_priv(dev); + int ret = 0; - BYTE_REG_BITS_ON(MIICR_RCMD, ®s->MIICR); + if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n", + vptr->dev->name); + ret = -EINVAL; + goto out_0; + } - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(readb(®s->MIICR) & MIICR_RCMD)) - break; + if (!netif_running(dev)) { + dev->mtu = new_mtu; + goto out_0; } - *data = readw(®s->MIIDATA); + if (dev->mtu != new_mtu) { + struct velocity_info *tmp_vptr; + unsigned long flags; + struct rx_info rx; + struct tx_info tx; - enable_mii_autopoll(regs); - if (ww == W_MAX_TIMEOUT) - return -ETIMEDOUT; - return 0; -} + tmp_vptr = kzalloc(sizeof(*tmp_vptr), GFP_KERNEL); + if (!tmp_vptr) { + ret = -ENOMEM; + goto out_0; + } -/** - * velocity_mii_write - write MII data - * @regs: velocity registers - * @index: MII register index - * @data: 16bit data for the MII register - * - * Perform a single write to an MII 16bit register. Returns zero - * on success or -ETIMEDOUT if the PHY did not respond. - */ + tmp_vptr->dev = dev; + tmp_vptr->pdev = vptr->pdev; + tmp_vptr->options = vptr->options; + tmp_vptr->tx.numq = vptr->tx.numq; -static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data) -{ - u16 ww; + ret = velocity_init_rings(tmp_vptr, new_mtu); + if (ret < 0) + goto out_free_tmp_vptr_1; - /* - * Disable MIICR_MAUTO, so that mii addr can be set normally - */ - safe_disable_mii_autopoll(regs); + spin_lock_irqsave(&vptr->lock, flags); - /* MII reg offset */ - writeb(mii_addr, ®s->MIIADR); - /* set MII data */ - writew(data, ®s->MIIDATA); + netif_stop_queue(dev); + velocity_shutdown(vptr); - /* turn on MIICR_WCMD */ - BYTE_REG_BITS_ON(MIICR_WCMD, ®s->MIICR); + rx = vptr->rx; + tx = vptr->tx; - /* W_MAX_TIMEOUT is the timeout period */ - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - udelay(5); - if (!(readb(®s->MIICR) & MIICR_WCMD)) - break; - } - enable_mii_autopoll(regs); + vptr->rx = tmp_vptr->rx; + vptr->tx = tmp_vptr->tx; - if (ww == W_MAX_TIMEOUT) - return -ETIMEDOUT; - return 0; -} + tmp_vptr->rx = rx; + tmp_vptr->tx = tx; -/** - * velocity_get_opt_media_mode - get media selection - * @vptr: velocity adapter - * - * Get the media mode stored in EEPROM or module options and load - * mii_status accordingly. The requested link state information - * is also returned. - */ + dev->mtu = new_mtu; -static u32 velocity_get_opt_media_mode(struct velocity_info *vptr) -{ - u32 status = 0; + velocity_give_many_rx_descs(vptr); - switch (vptr->options.spd_dpx) { - case SPD_DPX_AUTO: - status = VELOCITY_AUTONEG_ENABLE; - break; - case SPD_DPX_100_FULL: - status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL; - break; - case SPD_DPX_10_FULL: - status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL; - break; - case SPD_DPX_100_HALF: - status = VELOCITY_SPEED_100; - break; - case SPD_DPX_10_HALF: - status = VELOCITY_SPEED_10; - break; - } - vptr->mii_status = status; - return status; -} + velocity_init_registers(vptr, VELOCITY_INIT_COLD); -/** - * mii_set_auto_on - autonegotiate on - * @vptr: velocity - * - * Enable autonegotation on this interface - */ + mac_enable_int(vptr->mac_regs); + netif_start_queue(dev); -static void mii_set_auto_on(struct velocity_info *vptr) -{ - if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs)) - MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs); - else - MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); -} + spin_unlock_irqrestore(&vptr->lock, flags); + velocity_free_rings(tmp_vptr); -/* -static void mii_set_auto_off(struct velocity_info *vptr) -{ - MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); +out_free_tmp_vptr_1: + kfree(tmp_vptr); + } +out_0: + return ret; } -*/ /** - * set_mii_flow_control - flow control setup - * @vptr: velocity interface + * velocity_mii_ioctl - MII ioctl handler + * @dev: network device + * @ifr: the ifreq block for the ioctl + * @cmd: the command * - * Set up the flow control on this interface according to - * the supplied user/eeprom options. + * Process MII requests made via ioctl from the network layer. These + * are used by tools like kudzu to interrogate the link state of the + * hardware */ - -static void set_mii_flow_control(struct velocity_info *vptr) +static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - /*Enable or Disable PAUSE in ANAR */ - switch (vptr->options.flow_cntl) { - case FLOW_CNTL_TX: - MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); - break; + struct velocity_info *vptr = netdev_priv(dev); + struct mac_regs __iomem *regs = vptr->mac_regs; + unsigned long flags; + struct mii_ioctl_data *miidata = if_mii(ifr); + int err; - case FLOW_CNTL_RX: - MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + switch (cmd) { + case SIOCGMIIPHY: + miidata->phy_id = readb(®s->MIIADR) & 0x1f; break; - - case FLOW_CNTL_TX_RX: - MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0) + return -ETIMEDOUT; break; - - case FLOW_CNTL_DISABLE: - MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + spin_lock_irqsave(&vptr->lock, flags); + err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in); + spin_unlock_irqrestore(&vptr->lock, flags); + check_connection_type(vptr->mac_regs); + if (err) + return err; break; default: - break; + return -EOPNOTSUPP; } + return 0; } + /** - * velocity_set_media_mode - set media mode - * @mii_status: old MII link state + * velocity_ioctl - ioctl entry point + * @dev: network device + * @rq: interface request ioctl + * @cmd: command code * - * Check the media link state and configure the flow control - * PHY and also velocity hardware setup accordingly. In particular - * we need to set up CD polling and frame bursting. + * Called when the user issues an ioctl request to the network + * device in question. The velocity interface supports MII. */ +static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct velocity_info *vptr = netdev_priv(dev); + int ret; -static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) -{ - u32 curr_status; - struct mac_regs __iomem *regs = vptr->mac_regs; - - vptr->mii_status = mii_check_media_mode(vptr->mac_regs); - curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL); - - /* Set mii link status */ - set_mii_flow_control(vptr); - - /* - Check if new status is consisent with current status - if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE) - || (mii_status==curr_status)) { - vptr->mii_status=mii_check_media_mode(vptr->mac_regs); - vptr->mii_status=check_connection_type(vptr->mac_regs); - VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n"); - return 0; - } - */ - - if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) - MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs); - - /* - * If connection type is AUTO - */ - if (mii_status & VELOCITY_AUTONEG_ENABLE) { - VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n"); - /* clear force MAC mode bit */ - BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); - /* set duplex mode of MAC according to duplex mode of MII */ - MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); - MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); - - /* enable AUTO-NEGO mode */ - mii_set_auto_on(vptr); - } else { - u16 ANAR; - u8 CHIPGCR; - - /* - * 1. if it's 3119, disable frame bursting in halfduplex mode - * and enable it in fullduplex mode - * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR - * 3. only enable CD heart beat counter in 10HD mode - */ - - /* set force MAC mode bit */ - BYTE_REG_BITS_ON(CHIPGCR_FCMODE, ®s->CHIPGCR); + /* If we are asked for information and the device is power + saving then we need to bring the device back up to talk to it */ - CHIPGCR = readb(®s->CHIPGCR); - CHIPGCR &= ~CHIPGCR_FCGMII; + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D0); - if (mii_status & VELOCITY_DUPLEX_FULL) { - CHIPGCR |= CHIPGCR_FCFDX; - writeb(CHIPGCR, ®s->CHIPGCR); - VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n"); - if (vptr->rev_id < REV_ID_VT3216_A0) - BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); - } else { - CHIPGCR &= ~CHIPGCR_FCFDX; - VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n"); - writeb(CHIPGCR, ®s->CHIPGCR); - if (vptr->rev_id < REV_ID_VT3216_A0) - BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); - } + switch (cmd) { + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCSMIIREG: /* Write to MII PHY register. */ + ret = velocity_mii_ioctl(dev, rq, cmd); + break; - MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); + default: + ret = -EOPNOTSUPP; + } + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D3hot); - if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) - BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); - else - BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); - /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */ - velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR); - ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)); - if (mii_status & VELOCITY_SPEED_100) { - if (mii_status & VELOCITY_DUPLEX_FULL) - ANAR |= ANAR_TXFD; - else - ANAR |= ANAR_TX; - } else { - if (mii_status & VELOCITY_DUPLEX_FULL) - ANAR |= ANAR_10FD; - else - ANAR |= ANAR_10; - } - velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR); - /* enable AUTO-NEGO mode */ - mii_set_auto_on(vptr); - /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */ - } - /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */ - /* vptr->mii_status=check_connection_type(vptr->mac_regs); */ - return VELOCITY_LINK_CHANGE; + return ret; } /** - * mii_check_media_mode - check media state - * @regs: velocity registers + * velocity_get_status - statistics callback + * @dev: network device * - * Check the current MII status and determine the link status - * accordingly + * Callback from the network layer to allow driver statistics + * to be resynchronized with hardware collected state. In the + * case of the velocity we need to pull the MIB counters from + * the hardware into the counters before letting the network + * layer display them. */ - -static u32 mii_check_media_mode(struct mac_regs __iomem *regs) +static struct net_device_stats *velocity_get_stats(struct net_device *dev) { - u32 status = 0; - u16 ANAR; + struct velocity_info *vptr = netdev_priv(dev); - if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs)) - status |= VELOCITY_LINK_FAIL; + /* If the hardware is down, don't touch MII */ + if (!netif_running(dev)) + return &dev->stats; - if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs)) - status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL; - else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs)) - status |= (VELOCITY_SPEED_1000); - else { - velocity_mii_read(regs, MII_REG_ANAR, &ANAR); - if (ANAR & ANAR_TXFD) - status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL); - else if (ANAR & ANAR_TX) - status |= VELOCITY_SPEED_100; - else if (ANAR & ANAR_10FD) - status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL); - else - status |= (VELOCITY_SPEED_10); - } + spin_lock_irq(&vptr->lock); + velocity_update_hw_mibs(vptr); + spin_unlock_irq(&vptr->lock); - if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { - velocity_mii_read(regs, MII_REG_ANAR, &ANAR); - if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) - == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { - if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs)) - status |= VELOCITY_AUTONEG_ENABLE; - } - } + dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts]; + dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts]; + dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors]; - return status; +// unsigned long rx_dropped; /* no space in linux buffers */ + dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions]; + /* detailed rx_errors: */ +// unsigned long rx_length_errors; +// unsigned long rx_over_errors; /* receiver ring buff overflow */ + dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE]; +// unsigned long rx_frame_errors; /* recv'd frame alignment error */ +// unsigned long rx_fifo_errors; /* recv'r fifo overrun */ +// unsigned long rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ +// unsigned long tx_fifo_errors; + + return &dev->stats; } -static u32 check_connection_type(struct mac_regs __iomem *regs) +/** + * velocity_close - close adapter callback + * @dev: network device + * + * Callback from the network layer when the velocity is being + * deactivated by the network layer + */ +static int velocity_close(struct net_device *dev) { - u32 status = 0; - u8 PHYSR0; - u16 ANAR; - PHYSR0 = readb(®s->PHYSR0); + struct velocity_info *vptr = netdev_priv(dev); - /* - if (!(PHYSR0 & PHYSR0_LINKGD)) - status|=VELOCITY_LINK_FAIL; - */ + netif_stop_queue(dev); + velocity_shutdown(vptr); - if (PHYSR0 & PHYSR0_FDPX) - status |= VELOCITY_DUPLEX_FULL; + if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) + velocity_get_ip(vptr); + if (dev->irq != 0) + free_irq(dev->irq, dev); - if (PHYSR0 & PHYSR0_SPDG) - status |= VELOCITY_SPEED_1000; - else if (PHYSR0 & PHYSR0_SPD10) - status |= VELOCITY_SPEED_10; - else - status |= VELOCITY_SPEED_100; + /* Power down the chip */ + pci_set_power_state(vptr->pdev, PCI_D3hot); - if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { - velocity_mii_read(regs, MII_REG_ANAR, &ANAR); - if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) - == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { - if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs)) - status |= VELOCITY_AUTONEG_ENABLE; - } - } + velocity_free_rings(vptr); - return status; + vptr->flags &= (~VELOCITY_FLAGS_OPENED); + return 0; } /** - * enable_flow_control_ability - flow control - * @vptr: veloity to configure + * velocity_xmit - transmit packet callback + * @skb: buffer to transmit + * @dev: network device * - * Set up flow control according to the flow control options - * determined by the eeprom/configuration. + * Called by the networ layer to request a packet is queued to + * the velocity. Returns zero on success. */ - -static void enable_flow_control_ability(struct velocity_info *vptr) +static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) { + struct velocity_info *vptr = netdev_priv(dev); + int qnum = 0; + struct tx_desc *td_ptr; + struct velocity_td_info *tdinfo; + unsigned long flags; + int pktlen; + __le16 len; + int index; - struct mac_regs __iomem *regs = vptr->mac_regs; + if (skb_padto(skb, ETH_ZLEN)) + goto out; + pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); - switch (vptr->options.flow_cntl) { + len = cpu_to_le16(pktlen); - case FLOW_CNTL_DEFAULT: - if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, ®s->PHYSR0)) - writel(CR0_FDXRFCEN, ®s->CR0Set); - else - writel(CR0_FDXRFCEN, ®s->CR0Clr); + spin_lock_irqsave(&vptr->lock, flags); - if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, ®s->PHYSR0)) - writel(CR0_FDXTFCEN, ®s->CR0Set); - else - writel(CR0_FDXTFCEN, ®s->CR0Clr); - break; + index = vptr->tx.curr[qnum]; + td_ptr = &(vptr->tx.rings[qnum][index]); + tdinfo = &(vptr->tx.infos[qnum][index]); - case FLOW_CNTL_TX: - writel(CR0_FDXTFCEN, ®s->CR0Set); - writel(CR0_FDXRFCEN, ®s->CR0Clr); - break; + td_ptr->tdesc1.TCR = TCR0_TIC; + td_ptr->td_buf[0].size &= ~TD_QUEUE; - case FLOW_CNTL_RX: - writel(CR0_FDXRFCEN, ®s->CR0Set); - writel(CR0_FDXTFCEN, ®s->CR0Clr); - break; + /* + * Map the linear network buffer into PCI space and + * add it to the transmit ring. + */ + tdinfo->skb = skb; + tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); + td_ptr->tdesc0.len = len; + td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); + td_ptr->td_buf[0].pa_high = 0; + td_ptr->td_buf[0].size = len; + tdinfo->nskb_dma = 1; + + td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16; + + if (vptr->vlgrp && vlan_tx_tag_present(skb)) { + td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + td_ptr->tdesc1.TCR |= TCR0_VETAG; + } + + /* + * Handle hardware checksum + */ + if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM) + && (skb->ip_summed == CHECKSUM_PARTIAL)) { + const struct iphdr *ip = ip_hdr(skb); + if (ip->protocol == IPPROTO_TCP) + td_ptr->tdesc1.TCR |= TCR0_TCPCK; + else if (ip->protocol == IPPROTO_UDP) + td_ptr->tdesc1.TCR |= (TCR0_UDPCK); + td_ptr->tdesc1.TCR |= TCR0_IPCK; + } + { - case FLOW_CNTL_TX_RX: - writel(CR0_FDXTFCEN, ®s->CR0Set); - writel(CR0_FDXRFCEN, ®s->CR0Set); - break; + int prev = index - 1; - case FLOW_CNTL_DISABLE: - writel(CR0_FDXRFCEN, ®s->CR0Clr); - writel(CR0_FDXTFCEN, ®s->CR0Clr); - break; + if (prev < 0) + prev = vptr->options.numtx - 1; + td_ptr->tdesc0.len |= OWNED_BY_NIC; + vptr->tx.used[qnum]++; + vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx; - default: - break; - } + if (AVAIL_TD(vptr, qnum) < 1) + netif_stop_queue(dev); + td_ptr = &(vptr->tx.rings[qnum][prev]); + td_ptr->td_buf[0].size |= TD_QUEUE; + mac_tx_queue_wake(vptr->mac_regs, qnum); + } + dev->trans_start = jiffies; + spin_unlock_irqrestore(&vptr->lock, flags); +out: + return NETDEV_TX_OK; } +static const struct net_device_ops velocity_netdev_ops = { + .ndo_open = velocity_open, + .ndo_stop = velocity_close, + .ndo_start_xmit = velocity_xmit, + .ndo_get_stats = velocity_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_set_multicast_list = velocity_set_multi, + .ndo_change_mtu = velocity_change_mtu, + .ndo_do_ioctl = velocity_ioctl, + .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid, + .ndo_vlan_rx_register = velocity_vlan_rx_register, +}; + /** - * velocity_ethtool_up - pre hook for ethtool - * @dev: network device + * velocity_init_info - init private data + * @pdev: PCI device + * @vptr: Velocity info + * @info: Board type * - * Called before an ethtool operation. We need to make sure the - * chip is out of D3 state before we poke at it. + * Set up the initial velocity_info struct for the device that has been + * discovered. */ - -static int velocity_ethtool_up(struct net_device *dev) +static void __devinit velocity_init_info(struct pci_dev *pdev, + struct velocity_info *vptr, + const struct velocity_info_tbl *info) { - struct velocity_info *vptr = netdev_priv(dev); - if (!netif_running(dev)) - pci_set_power_state(vptr->pdev, PCI_D0); - return 0; + memset(vptr, 0, sizeof(struct velocity_info)); + + vptr->pdev = pdev; + vptr->chip_id = info->chip_id; + vptr->tx.numq = info->txqueue; + vptr->multicast_limit = MCAM_SIZE; + spin_lock_init(&vptr->lock); + INIT_LIST_HEAD(&vptr->list); } /** - * velocity_ethtool_down - post hook for ethtool - * @dev: network device + * velocity_get_pci_info - retrieve PCI info for device + * @vptr: velocity device + * @pdev: PCI device it matches * - * Called after an ethtool operation. Restore the chip back to D3 - * state if it isn't running. + * Retrieve the PCI configuration space data that interests us from + * the kernel PCI layer */ - -static void velocity_ethtool_down(struct net_device *dev) +static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev) { - struct velocity_info *vptr = netdev_priv(dev); - if (!netif_running(dev)) - pci_set_power_state(vptr->pdev, PCI_D3hot); -} + vptr->rev_id = pdev->revision; -static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem *regs = vptr->mac_regs; - u32 status; - status = check_connection_type(vptr->mac_regs); + pci_set_master(pdev); - cmd->supported = SUPPORTED_TP | - SUPPORTED_Autoneg | - SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full; - if (status & VELOCITY_SPEED_1000) - cmd->speed = SPEED_1000; - else if (status & VELOCITY_SPEED_100) - cmd->speed = SPEED_100; - else - cmd->speed = SPEED_10; - cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE; - cmd->port = PORT_TP; - cmd->transceiver = XCVR_INTERNAL; - cmd->phy_address = readb(®s->MIIADR) & 0x1F; + vptr->ioaddr = pci_resource_start(pdev, 0); + vptr->memaddr = pci_resource_start(pdev, 1); - if (status & VELOCITY_DUPLEX_FULL) - cmd->duplex = DUPLEX_FULL; - else - cmd->duplex = DUPLEX_HALF; + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) { + dev_err(&pdev->dev, + "region #0 is not an I/O resource, aborting.\n"); + return -EINVAL; + } + + if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) { + dev_err(&pdev->dev, + "region #1 is an I/O resource, aborting.\n"); + return -EINVAL; + } + + if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) { + dev_err(&pdev->dev, "region #1 is too small.\n"); + return -EINVAL; + } + vptr->pdev = pdev; return 0; } -static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +/** + * velocity_print_info - per driver data + * @vptr: velocity + * + * Print per driver data as the kernel driver finds Velocity + * hardware + */ +static void __devinit velocity_print_info(struct velocity_info *vptr) { - struct velocity_info *vptr = netdev_priv(dev); - u32 curr_status; - u32 new_status = 0; - int ret = 0; - - curr_status = check_connection_type(vptr->mac_regs); - curr_status &= (~VELOCITY_LINK_FAIL); - - new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0); - new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0); - new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0); - new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0); - - if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE))) - ret = -EINVAL; - else - velocity_set_media_mode(vptr, new_status); + struct net_device *dev = vptr->dev; - return ret; + printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id)); + printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", + dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); } static u32 velocity_get_link(struct net_device *dev) @@ -3016,195 +2647,165 @@ static u32 velocity_get_link(struct net_device *dev) return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, ®s->PHYSR0) ? 1 : 0; } -static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct velocity_info *vptr = netdev_priv(dev); - strcpy(info->driver, VELOCITY_NAME); - strcpy(info->version, VELOCITY_VERSION); - strcpy(info->bus_info, pci_name(vptr->pdev)); -} -static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +/** + * velocity_found1 - set up discovered velocity card + * @pdev: PCI device + * @ent: PCI device table entry that matched + * + * Configure a discovered adapter from scratch. Return a negative + * errno error code on failure paths. + */ +static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct velocity_info *vptr = netdev_priv(dev); - wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP; - wol->wolopts |= WAKE_MAGIC; - /* - if (vptr->wol_opts & VELOCITY_WOL_PHY) - wol.wolopts|=WAKE_PHY; - */ - if (vptr->wol_opts & VELOCITY_WOL_UCAST) - wol->wolopts |= WAKE_UCAST; - if (vptr->wol_opts & VELOCITY_WOL_ARP) - wol->wolopts |= WAKE_ARP; - memcpy(&wol->sopass, vptr->wol_passwd, 6); -} + static int first = 1; + struct net_device *dev; + int i; + const char *drv_string; + const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data]; + struct velocity_info *vptr; + struct mac_regs __iomem *regs; + int ret = -ENOMEM; -static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - struct velocity_info *vptr = netdev_priv(dev); + /* FIXME: this driver, like almost all other ethernet drivers, + * can support more than MAX_UNITS. + */ + if (velocity_nics >= MAX_UNITS) { + dev_notice(&pdev->dev, "already found %d NICs.\n", + velocity_nics); + return -ENODEV; + } - if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP))) - return -EFAULT; - vptr->wol_opts = VELOCITY_WOL_MAGIC; + dev = alloc_etherdev(sizeof(struct velocity_info)); + if (!dev) { + dev_err(&pdev->dev, "allocate net device failed.\n"); + goto out; + } - /* - if (wol.wolopts & WAKE_PHY) { - vptr->wol_opts|=VELOCITY_WOL_PHY; - vptr->flags |=VELOCITY_FLAGS_WOL_ENABLED; - } - */ + /* Chain it all together */ - if (wol->wolopts & WAKE_MAGIC) { - vptr->wol_opts |= VELOCITY_WOL_MAGIC; - vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + SET_NETDEV_DEV(dev, &pdev->dev); + vptr = netdev_priv(dev); + + + if (first) { + printk(KERN_INFO "%s Ver. %s\n", + VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION); + printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n"); + printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n"); + first = 0; + } + + velocity_init_info(pdev, vptr, info); + + vptr->dev = dev; + + dev->irq = pdev->irq; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err_free_dev; + + ret = velocity_get_pci_info(vptr, pdev); + if (ret < 0) { + /* error message already printed */ + goto err_disable; } - if (wol->wolopts & WAKE_UCAST) { - vptr->wol_opts |= VELOCITY_WOL_UCAST; - vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + + ret = pci_request_regions(pdev, VELOCITY_NAME); + if (ret < 0) { + dev_err(&pdev->dev, "No PCI resources.\n"); + goto err_disable; } - if (wol->wolopts & WAKE_ARP) { - vptr->wol_opts |= VELOCITY_WOL_ARP; - vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + + regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE); + if (regs == NULL) { + ret = -EIO; + goto err_release_res; } - memcpy(vptr->wol_passwd, wol->sopass, 6); - return 0; -} -static u32 velocity_get_msglevel(struct net_device *dev) -{ - return msglevel; -} + vptr->mac_regs = regs; -static void velocity_set_msglevel(struct net_device *dev, u32 value) -{ - msglevel = value; -} + mac_wol_reset(regs); -static const struct ethtool_ops velocity_ethtool_ops = { - .get_settings = velocity_get_settings, - .set_settings = velocity_set_settings, - .get_drvinfo = velocity_get_drvinfo, - .get_wol = velocity_ethtool_get_wol, - .set_wol = velocity_ethtool_set_wol, - .get_msglevel = velocity_get_msglevel, - .set_msglevel = velocity_set_msglevel, - .get_link = velocity_get_link, - .begin = velocity_ethtool_up, - .complete = velocity_ethtool_down -}; + dev->base_addr = vptr->ioaddr; -/** - * velocity_mii_ioctl - MII ioctl handler - * @dev: network device - * @ifr: the ifreq block for the ioctl - * @cmd: the command - * - * Process MII requests made via ioctl from the network layer. These - * are used by tools like kudzu to interrogate the link state of the - * hardware - */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = readb(®s->PAR[i]); -static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem *regs = vptr->mac_regs; - unsigned long flags; - struct mii_ioctl_data *miidata = if_mii(ifr); - int err; - switch (cmd) { - case SIOCGMIIPHY: - miidata->phy_id = readb(®s->MIIADR) & 0x1f; - break; - case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0) - return -ETIMEDOUT; - break; - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - spin_lock_irqsave(&vptr->lock, flags); - err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in); - spin_unlock_irqrestore(&vptr->lock, flags); - check_connection_type(vptr->mac_regs); - if (err) - return err; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} + drv_string = dev_driver_string(&pdev->dev); -#ifdef CONFIG_PM + velocity_get_options(&vptr->options, velocity_nics, drv_string); -/** - * velocity_save_context - save registers - * @vptr: velocity - * @context: buffer for stored context - * - * Retrieve the current configuration from the velocity hardware - * and stash it in the context structure, for use by the context - * restore functions. This allows us to save things we need across - * power down states - */ + /* + * Mask out the options cannot be set to the chip + */ -static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context) -{ - struct mac_regs __iomem *regs = vptr->mac_regs; - u16 i; - u8 __iomem *ptr = (u8 __iomem *)regs; + vptr->options.flags &= info->flags; - for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4) - *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + /* + * Enable the chip specified capbilities + */ - for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4) - *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL); - for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) - *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + vptr->wol_opts = vptr->options.wol_opts; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; -} + vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs); -/** - * velocity_restore_context - restore registers - * @vptr: velocity - * @context: buffer for stored context - * - * Reload the register configuration from the velocity context - * created by velocity_save_context. - */ + dev->irq = pdev->irq; + dev->netdev_ops = &velocity_netdev_ops; + dev->ethtool_ops = &velocity_ethtool_ops; -static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context) -{ - struct mac_regs __iomem *regs = vptr->mac_regs; - int i; - u8 __iomem *ptr = (u8 __iomem *)regs; + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | + NETIF_F_HW_VLAN_RX; - for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) - writel(*((u32 *) (context->mac_reg + i)), ptr + i); + if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) + dev->features |= NETIF_F_IP_CSUM; - /* Just skip cr0 */ - for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) { - /* Clear */ - writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4); - /* Set */ - writeb(*((u8 *) (context->mac_reg + i)), ptr + i); + ret = register_netdev(dev); + if (ret < 0) + goto err_iounmap; + + if (!velocity_get_link(dev)) { + netif_carrier_off(dev); + vptr->mii_status |= VELOCITY_LINK_FAIL; } - for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) - writel(*((u32 *) (context->mac_reg + i)), ptr + i); + velocity_print_info(vptr); + pci_set_drvdata(pdev, dev); - for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) - writel(*((u32 *) (context->mac_reg + i)), ptr + i); + /* and leave the chip powered down */ - for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) - writeb(*((u8 *) (context->mac_reg + i)), ptr + i); + pci_set_power_state(pdev, PCI_D3hot); +#ifdef CONFIG_PM + { + unsigned long flags; + + spin_lock_irqsave(&velocity_dev_list_lock, flags); + list_add(&vptr->list, &velocity_dev_list); + spin_unlock_irqrestore(&velocity_dev_list_lock, flags); + } +#endif + velocity_nics++; +out: + return ret; + +err_iounmap: + iounmap(regs); +err_release_res: + pci_release_regions(pdev); +err_disable: + pci_disable_device(pdev); +err_free_dev: + free_netdev(dev); + goto out; } + +#ifdef CONFIG_PM /** * wol_calc_crc - WOL CRC * @pattern: data pattern @@ -3213,7 +2814,6 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity * Compute the wake on lan crc hashes for the packet header * we are interested in. */ - static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern) { u16 crc = 0xFFFF; @@ -3250,7 +2850,6 @@ static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern) * * FIXME: check static buffer is safe here */ - static int velocity_set_wol(struct velocity_info *vptr) { struct mac_regs __iomem *regs = vptr->mac_regs; @@ -3327,6 +2926,33 @@ static int velocity_set_wol(struct velocity_info *vptr) return 0; } +/** + * velocity_save_context - save registers + * @vptr: velocity + * @context: buffer for stored context + * + * Retrieve the current configuration from the velocity hardware + * and stash it in the context structure, for use by the context + * restore functions. This allows us to save things we need across + * power down states + */ +static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context) +{ + struct mac_regs __iomem *regs = vptr->mac_regs; + u16 i; + u8 __iomem *ptr = (u8 __iomem *)regs; + + for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4) + *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + + for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4) + *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + + for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) + *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + +} + static int velocity_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); @@ -3354,11 +2980,46 @@ static int velocity_suspend(struct pci_dev *pdev, pm_message_t state) pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); } -#else - pci_set_power_state(pdev, pci_choose_state(pdev, state)); -#endif - spin_unlock_irqrestore(&vptr->lock, flags); - return 0; +#else + pci_set_power_state(pdev, pci_choose_state(pdev, state)); +#endif + spin_unlock_irqrestore(&vptr->lock, flags); + return 0; +} + +/** + * velocity_restore_context - restore registers + * @vptr: velocity + * @context: buffer for stored context + * + * Reload the register configuration from the velocity context + * created by velocity_save_context. + */ +static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context) +{ + struct mac_regs __iomem *regs = vptr->mac_regs; + int i; + u8 __iomem *ptr = (u8 __iomem *)regs; + + for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) + writel(*((u32 *) (context->mac_reg + i)), ptr + i); + + /* Just skip cr0 */ + for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) { + /* Clear */ + writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4); + /* Set */ + writeb(*((u8 *) (context->mac_reg + i)), ptr + i); + } + + for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) + writel(*((u32 *) (context->mac_reg + i)), ptr + i); + + for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) + writel(*((u32 *) (context->mac_reg + i)), ptr + i); + + for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) + writeb(*((u8 *) (context->mac_reg + i)), ptr + i); } static int velocity_resume(struct pci_dev *pdev) @@ -3395,9 +3056,190 @@ static int velocity_resume(struct pci_dev *pdev) return 0; } +#endif -#ifdef CONFIG_INET +/* + * Definition for our device driver. The PCI layer interface + * uses this to handle all our card discover and plugging + */ +static struct pci_driver velocity_driver = { + .name = VELOCITY_NAME, + .id_table = velocity_id_table, + .probe = velocity_found1, + .remove = __devexit_p(velocity_remove1), +#ifdef CONFIG_PM + .suspend = velocity_suspend, + .resume = velocity_resume, +#endif +}; + + +/** + * velocity_ethtool_up - pre hook for ethtool + * @dev: network device + * + * Called before an ethtool operation. We need to make sure the + * chip is out of D3 state before we poke at it. + */ +static int velocity_ethtool_up(struct net_device *dev) +{ + struct velocity_info *vptr = netdev_priv(dev); + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D0); + return 0; +} + +/** + * velocity_ethtool_down - post hook for ethtool + * @dev: network device + * + * Called after an ethtool operation. Restore the chip back to D3 + * state if it isn't running. + */ +static void velocity_ethtool_down(struct net_device *dev) +{ + struct velocity_info *vptr = netdev_priv(dev); + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D3hot); +} + +static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct velocity_info *vptr = netdev_priv(dev); + struct mac_regs __iomem *regs = vptr->mac_regs; + u32 status; + status = check_connection_type(vptr->mac_regs); + + cmd->supported = SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full; + if (status & VELOCITY_SPEED_1000) + cmd->speed = SPEED_1000; + else if (status & VELOCITY_SPEED_100) + cmd->speed = SPEED_100; + else + cmd->speed = SPEED_10; + cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + cmd->port = PORT_TP; + cmd->transceiver = XCVR_INTERNAL; + cmd->phy_address = readb(®s->MIIADR) & 0x1F; + + if (status & VELOCITY_DUPLEX_FULL) + cmd->duplex = DUPLEX_FULL; + else + cmd->duplex = DUPLEX_HALF; + + return 0; +} + +static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct velocity_info *vptr = netdev_priv(dev); + u32 curr_status; + u32 new_status = 0; + int ret = 0; + + curr_status = check_connection_type(vptr->mac_regs); + curr_status &= (~VELOCITY_LINK_FAIL); + + new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0); + new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0); + new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0); + new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0); + + if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE))) + ret = -EINVAL; + else + velocity_set_media_mode(vptr, new_status); + + return ret; +} + +static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct velocity_info *vptr = netdev_priv(dev); + strcpy(info->driver, VELOCITY_NAME); + strcpy(info->version, VELOCITY_VERSION); + strcpy(info->bus_info, pci_name(vptr->pdev)); +} + +static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct velocity_info *vptr = netdev_priv(dev); + wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP; + wol->wolopts |= WAKE_MAGIC; + /* + if (vptr->wol_opts & VELOCITY_WOL_PHY) + wol.wolopts|=WAKE_PHY; + */ + if (vptr->wol_opts & VELOCITY_WOL_UCAST) + wol->wolopts |= WAKE_UCAST; + if (vptr->wol_opts & VELOCITY_WOL_ARP) + wol->wolopts |= WAKE_ARP; + memcpy(&wol->sopass, vptr->wol_passwd, 6); +} + +static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct velocity_info *vptr = netdev_priv(dev); + + if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP))) + return -EFAULT; + vptr->wol_opts = VELOCITY_WOL_MAGIC; + + /* + if (wol.wolopts & WAKE_PHY) { + vptr->wol_opts|=VELOCITY_WOL_PHY; + vptr->flags |=VELOCITY_FLAGS_WOL_ENABLED; + } + */ + + if (wol->wolopts & WAKE_MAGIC) { + vptr->wol_opts |= VELOCITY_WOL_MAGIC; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + } + if (wol->wolopts & WAKE_UCAST) { + vptr->wol_opts |= VELOCITY_WOL_UCAST; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + } + if (wol->wolopts & WAKE_ARP) { + vptr->wol_opts |= VELOCITY_WOL_ARP; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + } + memcpy(vptr->wol_passwd, wol->sopass, 6); + return 0; +} + +static u32 velocity_get_msglevel(struct net_device *dev) +{ + return msglevel; +} + +static void velocity_set_msglevel(struct net_device *dev, u32 value) +{ + msglevel = value; +} + +static const struct ethtool_ops velocity_ethtool_ops = { + .get_settings = velocity_get_settings, + .set_settings = velocity_set_settings, + .get_drvinfo = velocity_get_drvinfo, + .get_wol = velocity_ethtool_get_wol, + .set_wol = velocity_ethtool_set_wol, + .get_msglevel = velocity_get_msglevel, + .set_msglevel = velocity_set_msglevel, + .get_link = velocity_get_link, + .begin = velocity_ethtool_up, + .complete = velocity_ethtool_down +}; +#ifdef CONFIG_PM +#ifdef CONFIG_INET static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) { struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; @@ -3419,6 +3261,63 @@ static int velocity_netdev_event(struct notifier_block *nb, unsigned long notifi return NOTIFY_DONE; } +#endif /* CONFIG_INET */ +#endif /* CONFIG_PM */ -#endif -#endif +#if defined(CONFIG_PM) && defined(CONFIG_INET) +static struct notifier_block velocity_inetaddr_notifier = { + .notifier_call = velocity_netdev_event, +}; + +static void velocity_register_notifier(void) +{ + register_inetaddr_notifier(&velocity_inetaddr_notifier); +} + +static void velocity_unregister_notifier(void) +{ + unregister_inetaddr_notifier(&velocity_inetaddr_notifier); +} + +#else + +#define velocity_register_notifier() do {} while (0) +#define velocity_unregister_notifier() do {} while (0) + +#endif /* defined(CONFIG_PM) && defined(CONFIG_INET) */ + +/** + * velocity_init_module - load time function + * + * Called when the velocity module is loaded. The PCI driver + * is registered with the PCI layer, and in turn will call + * the probe functions for each velocity adapter installed + * in the system. + */ +static int __init velocity_init_module(void) +{ + int ret; + + velocity_register_notifier(); + ret = pci_register_driver(&velocity_driver); + if (ret < 0) + velocity_unregister_notifier(); + return ret; +} + +/** + * velocity_cleanup - module unload + * + * When the velocity hardware is unloaded this function is called. + * It will clean up the notifiers and the unregister the PCI + * driver interface for this hardware. This in turn cleans up + * all discovered interfaces before returning from the function + */ +static void __exit velocity_cleanup_module(void) +{ + velocity_unregister_notifier(); + pci_unregister_driver(&velocity_driver); +} + +module_init(velocity_init_module); +module_exit(velocity_cleanup_module); -- cgit v0.10.2 From 5a6338db37885af06760d40cad589316e48431e9 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 20 Jul 2009 17:40:48 +0000 Subject: Fix typos in comments in via-velocity header. Signed-off-by: Dave Jones Signed-off-by: David S. Miller diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index 4cd3f6c..2f00c13 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -96,8 +96,8 @@ * Bits in the CSM register */ -#define CSM_IPOK 0x40 //IP Checkusm validatiaon ok -#define CSM_TUPOK 0x20 //TCP/UDP Checkusm validatiaon ok +#define CSM_IPOK 0x40 //IP Checksum validation ok +#define CSM_TUPOK 0x20 //TCP/UDP Checksum validation ok #define CSM_FRAG 0x10 //Fragment IP datagram #define CSM_IPKT 0x04 //Received an IP packet #define CSM_TCPKT 0x02 //Received a TCP packet @@ -819,7 +819,7 @@ enum velocity_owner { * Bits in the EECSR register */ -#define EECSR_EMBP 0x40 /* eeprom embeded programming */ +#define EECSR_EMBP 0x40 /* eeprom embedded programming */ #define EECSR_RELOAD 0x20 /* eeprom content reload */ #define EECSR_DPM 0x10 /* eeprom direct programming */ #define EECSR_ECS 0x08 /* eeprom CS pin */ -- cgit v0.10.2 From 5befbd5a7e9c814d145f15b4281c88da96fb1aa9 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 24 Jul 2009 13:56:31 +0800 Subject: crypto: ahash - Use GFP_KERNEL on allocation if the request can sleep ahash_op_unaligned() and ahash_def_finup() allocate memory atomically, regardless whether the request can sleep or not. This patch changes this to use GFP_KERNEL if the request can sleep. Signed-off-by: Steffen Klassert Signed-off-by: Herbert Xu diff --git a/crypto/ahash.c b/crypto/ahash.c index 28a33d0..33a4ff4 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -223,7 +223,7 @@ static int ahash_op_unaligned(struct ahash_request *req, priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? - GFP_ATOMIC : GFP_ATOMIC); + GFP_KERNEL : GFP_ATOMIC); if (!priv) return -ENOMEM; @@ -333,7 +333,7 @@ static int ahash_def_finup(struct ahash_request *req) priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? - GFP_ATOMIC : GFP_ATOMIC); + GFP_KERNEL : GFP_ATOMIC); if (!priv) return -ENOMEM; -- cgit v0.10.2 From 0044f3eda9a778ab63c2a5eafede3803f01b0b97 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 24 Jul 2009 13:57:13 +0800 Subject: crypto: shash - Test for the algorithms import function before exporting it crypto_init_shash_ops_async() tests for setkey and not for import before exporting the algorithms import function to ahash. This patch fixes this. Signed-off-by: Steffen Klassert Signed-off-by: Herbert Xu diff --git a/crypto/shash.c b/crypto/shash.c index 98b7f46..91f7b9d 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -350,7 +350,7 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm) crt->setkey = shash_async_setkey; if (alg->export) crt->export = shash_async_export; - if (alg->setkey) + if (alg->import) crt->import = shash_async_import; crt->reqsize = sizeof(struct shash_desc) + crypto_shash_descsize(shash); -- cgit v0.10.2 From 7b4ffcf953f091a815df081911c5e75c8a38418d Mon Sep 17 00:00:00 2001 From: Phil Carmody Date: Fri, 24 Jul 2009 13:59:17 +0800 Subject: crypto: aes - Undefined behaviour in crypto_aes_expand_key It's undefined behaviour in C to write outside the bounds of an array. The key expansion routine takes a shortcut of creating 8 words at a time, but this creates 4 additional words which don't fit in the array. As everyone is hopefully now aware, GCC is at liberty to make any assumptions and optimisations it likes in situations where it can detect that UB has occured, up to and including nasal demons, and as the indices being accessed in the array are trivially calculable, it's rash to invite gcc to do take any liberties at all. Signed-off-by: Phil Carmody Signed-off-by: Herbert Xu diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c index b8b66ec..e78b7ee 100644 --- a/crypto/aes_generic.c +++ b/crypto/aes_generic.c @@ -1174,7 +1174,7 @@ EXPORT_SYMBOL_GPL(crypto_il_tab); ctx->key_enc[6 * i + 11] = t; \ } while (0) -#define loop8(i) do { \ +#define loop8tophalf(i) do { \ t = ror32(t, 8); \ t = ls_box(t) ^ rco_tab[i]; \ t ^= ctx->key_enc[8 * i]; \ @@ -1185,6 +1185,10 @@ EXPORT_SYMBOL_GPL(crypto_il_tab); ctx->key_enc[8 * i + 10] = t; \ t ^= ctx->key_enc[8 * i + 3]; \ ctx->key_enc[8 * i + 11] = t; \ +} while (0) + +#define loop8(i) do { \ + loop8tophalf(i); \ t = ctx->key_enc[8 * i + 4] ^ ls_box(t); \ ctx->key_enc[8 * i + 12] = t; \ t ^= ctx->key_enc[8 * i + 5]; \ @@ -1245,8 +1249,9 @@ int crypto_aes_expand_key(struct crypto_aes_ctx *ctx, const u8 *in_key, ctx->key_enc[5] = le32_to_cpu(key[5]); ctx->key_enc[6] = le32_to_cpu(key[6]); t = ctx->key_enc[7] = le32_to_cpu(key[7]); - for (i = 0; i < 7; ++i) + for (i = 0; i < 6; ++i) loop8(i); + loop8tophalf(i); break; } -- cgit v0.10.2 From 0b767b4df360bd442434d9d40b8a495e64202254 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 24 Jul 2009 15:18:41 +0800 Subject: crypto: hmac - Prehash ipad/opad This patch uses crypto_shash_export/crypto_shash_import to prehash ipad/opad to speed up hmac. This is partly based on a similar patch by Steffen Klassert. Signed-off-by: Herbert Xu diff --git a/crypto/hmac.c b/crypto/hmac.c index 02aa53e..15c2eb5 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -27,7 +27,7 @@ #include struct hmac_ctx { - struct shash_desc *desc; + struct crypto_shash *hash; }; static inline void *align_ptr(void *p, unsigned int align) @@ -38,8 +38,7 @@ static inline void *align_ptr(void *p, unsigned int align) static inline struct hmac_ctx *hmac_ctx(struct crypto_shash *tfm) { return align_ptr(crypto_shash_ctx_aligned(tfm) + - crypto_shash_blocksize(tfm) * 2 + - crypto_shash_digestsize(tfm), + crypto_shash_statesize(tfm) * 2, crypto_tfm_ctx_alignment()); } @@ -48,28 +47,33 @@ static int hmac_setkey(struct crypto_shash *parent, { int bs = crypto_shash_blocksize(parent); int ds = crypto_shash_digestsize(parent); + int ss = crypto_shash_statesize(parent); char *ipad = crypto_shash_ctx_aligned(parent); - char *opad = ipad + bs; - char *digest = opad + bs; - struct hmac_ctx *ctx = align_ptr(digest + ds, + char *opad = ipad + ss; + struct hmac_ctx *ctx = align_ptr(opad + ss, crypto_tfm_ctx_alignment()); + struct crypto_shash *hash = ctx->hash; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(hash)]; + } desc; unsigned int i; + desc.shash.tfm = hash; + desc.shash.flags = crypto_shash_get_flags(parent) & + CRYPTO_TFM_REQ_MAY_SLEEP; + if (keylen > bs) { int err; - ctx->desc->flags = crypto_shash_get_flags(parent) & - CRYPTO_TFM_REQ_MAY_SLEEP; - - err = crypto_shash_digest(ctx->desc, inkey, keylen, digest); + err = crypto_shash_digest(&desc.shash, inkey, keylen, ipad); if (err) return err; - inkey = digest; keylen = ds; - } + } else + memcpy(ipad, inkey, keylen); - memcpy(ipad, inkey, keylen); memset(ipad + keylen, 0, bs - keylen); memcpy(opad, ipad, bs); @@ -78,24 +82,37 @@ static int hmac_setkey(struct crypto_shash *parent, opad[i] ^= 0x5c; } - return 0; + return crypto_shash_init(&desc.shash) ?: + crypto_shash_update(&desc.shash, ipad, bs) ?: + crypto_shash_export(&desc.shash, ipad) ?: + crypto_shash_init(&desc.shash) ?: + crypto_shash_update(&desc.shash, opad, bs) ?: + crypto_shash_export(&desc.shash, opad); } -static int hmac_init(struct shash_desc *pdesc) +static int hmac_export(struct shash_desc *pdesc, void *out) +{ + struct shash_desc *desc = shash_desc_ctx(pdesc); + + desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + + return crypto_shash_export(desc, out); +} + +static int hmac_import(struct shash_desc *pdesc, const void *in) { - struct crypto_shash *parent = pdesc->tfm; - int bs = crypto_shash_blocksize(parent); - int ds = crypto_shash_digestsize(parent); - char *ipad = crypto_shash_ctx_aligned(parent); - struct hmac_ctx *ctx = align_ptr(ipad + bs * 2 + ds, - crypto_tfm_ctx_alignment()); struct shash_desc *desc = shash_desc_ctx(pdesc); + struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm); - desc->tfm = ctx->desc->tfm; + desc->tfm = ctx->hash; desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - return crypto_shash_init(desc) ?: - crypto_shash_update(desc, ipad, bs); + return crypto_shash_import(desc, in); +} + +static int hmac_init(struct shash_desc *pdesc) +{ + return hmac_import(pdesc, crypto_shash_ctx_aligned(pdesc->tfm)); } static int hmac_update(struct shash_desc *pdesc, @@ -111,16 +128,16 @@ static int hmac_update(struct shash_desc *pdesc, static int hmac_final(struct shash_desc *pdesc, u8 *out) { struct crypto_shash *parent = pdesc->tfm; - int bs = crypto_shash_blocksize(parent); int ds = crypto_shash_digestsize(parent); - char *opad = crypto_shash_ctx_aligned(parent) + bs; - char *digest = opad + bs; + int ss = crypto_shash_statesize(parent); + char *opad = crypto_shash_ctx_aligned(parent) + ss; struct shash_desc *desc = shash_desc_ctx(pdesc); desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - return crypto_shash_final(desc, digest) ?: - crypto_shash_digest(desc, opad, bs + ds, out); + return crypto_shash_final(desc, out) ?: + crypto_shash_import(desc, opad) ?: + crypto_shash_finup(desc, out, ds, out); } static int hmac_finup(struct shash_desc *pdesc, const u8 *data, @@ -128,16 +145,16 @@ static int hmac_finup(struct shash_desc *pdesc, const u8 *data, { struct crypto_shash *parent = pdesc->tfm; - int bs = crypto_shash_blocksize(parent); int ds = crypto_shash_digestsize(parent); - char *opad = crypto_shash_ctx_aligned(parent) + bs; - char *digest = opad + bs; + int ss = crypto_shash_statesize(parent); + char *opad = crypto_shash_ctx_aligned(parent) + ss; struct shash_desc *desc = shash_desc_ctx(pdesc); desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - return crypto_shash_finup(desc, data, nbytes, digest) ?: - crypto_shash_digest(desc, opad, bs + ds, out); + return crypto_shash_finup(desc, data, nbytes, out) ?: + crypto_shash_import(desc, opad) ?: + crypto_shash_finup(desc, out, ds, out); } static int hmac_init_tfm(struct crypto_tfm *tfm) @@ -155,21 +172,14 @@ static int hmac_init_tfm(struct crypto_tfm *tfm) parent->descsize = sizeof(struct shash_desc) + crypto_shash_descsize(hash); - ctx->desc = kmalloc(parent->descsize, GFP_KERNEL); - if (!ctx->desc) { - crypto_free_shash(hash); - return -ENOMEM; - } - - ctx->desc->tfm = hash; + ctx->hash = hash; return 0; } static void hmac_exit_tfm(struct crypto_tfm *tfm) { struct hmac_ctx *ctx = hmac_ctx(__crypto_shash_cast(tfm)); - crypto_free_shash(ctx->desc->tfm); - kzfree(ctx->desc); + crypto_free_shash(ctx->hash); } static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) @@ -179,6 +189,7 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) struct shash_alg *salg; int err; int ds; + int ss; err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH); if (err) @@ -190,8 +201,10 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) err = -EINVAL; ds = salg->digestsize; + ss = salg->statesize; alg = &salg->base; - if (ds > alg->cra_blocksize) + if (ds > alg->cra_blocksize || + ss < alg->cra_blocksize) goto out_put_alg; inst = shash_alloc_instance("hmac", alg); @@ -208,11 +221,12 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.base.cra_blocksize = alg->cra_blocksize; inst->alg.base.cra_alignmask = alg->cra_alignmask; + ss = ALIGN(ss, alg->cra_alignmask + 1); inst->alg.digestsize = ds; + inst->alg.statesize = ss; inst->alg.base.cra_ctxsize = sizeof(struct hmac_ctx) + - ALIGN(alg->cra_blocksize * 2 + ds, - crypto_tfm_ctx_alignment()); + ALIGN(ss * 2, crypto_tfm_ctx_alignment()); inst->alg.base.cra_init = hmac_init_tfm; inst->alg.base.cra_exit = hmac_exit_tfm; @@ -221,6 +235,8 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.update = hmac_update; inst->alg.final = hmac_final; inst->alg.finup = hmac_finup; + inst->alg.export = hmac_export; + inst->alg.import = hmac_import; inst->alg.setkey = hmac_setkey; err = shash_register_instance(tmpl, inst); -- cgit v0.10.2 From ab300465676b0c0559af62d57ec9a902f5680b03 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 24 Jul 2009 15:26:15 +0800 Subject: crypto: api - Fix aligned ctx helper The aligned ctx helper was using a bogus alignment value thas was one off the correct value. Fortunately the current users do not require anything beyond the natural alignment of the platform so this hasn't caused a problem. This patch fixes that and also removes the unnecessary minimum check since if the alignment is less than the natural alignment then the subsequent ALIGN operation should be a noop. Signed-off-by: Herbert Xu diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 9de6c38..3f38814 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -175,12 +175,8 @@ int blkcipher_walk_virt_block(struct blkcipher_desc *desc, static inline void *crypto_tfm_ctx_aligned(struct crypto_tfm *tfm) { - unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm); - unsigned long align = crypto_tfm_alg_alignmask(tfm); - - if (align <= crypto_tfm_ctx_alignment()) - align = 1; - return (void *)ALIGN(addr, align); + return PTR_ALIGN(crypto_tfm_ctx(tfm), + crypto_tfm_alg_alignmask(tfm) + 1); } static inline struct crypto_instance *crypto_tfm_alg_instance( -- cgit v0.10.2 From a004cd42181409eda70804ded240a791f4564d61 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 21 Jul 2009 09:54:05 +0200 Subject: sched: Fix return value of migration_init() migration_init() returns the return value of the hotplug notifier. In the success case this is NOTIFY_OK which is 1. initcall_debug evaluates that as an error code because init calls are expected to return 0 on success. Signed-off-by: Thomas Gleixner diff --git a/kernel/sched.c b/kernel/sched.c index 1f7919a..953f037 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -7654,7 +7654,7 @@ static int __init migration_init(void) migration_call(&migration_notifier, CPU_ONLINE, cpu); register_cpu_notifier(&migration_notifier); - return err; + return 0; } early_initcall(migration_init); #endif -- cgit v0.10.2 From c94aa5ca3088018d2a7a9bd3258aefffe29df265 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: lockdep: Print the shortest dependency chain if finding a circle Currently lockdep will print the 1st circle detected if it exists when acquiring a new (next) lock. This patch prints the shortest path from the next lock to be acquired to the previous held lock if a circle is found. The patch still uses the current method to check circle, and once the circle is found, breadth-first search algorithem is used to compute the shortest path from the next lock to the previous lock in the forward lock dependency graph. Printing the shortest path will shorten the dependency chain, and make troubleshooting for possible circular locking easier. Signed-off-by: Ming Lei Signed-off-by: Peter Zijlstra LKML-Reference: <1246201486-7308-2-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index b25d1b5..9ec026f 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -149,6 +149,12 @@ struct lock_list { struct lock_class *class; struct stack_trace trace; int distance; + + /*The parent field is used to implement breadth-first search,and + *the bit 0 is reused to indicate if the lock has been accessed + *in BFS. + */ + struct lock_list *parent; }; /* diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 8bbeef9..93dc70d 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -897,6 +897,79 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, return 1; } +static struct circular_queue lock_cq; +static int __search_shortest_path(struct lock_list *source_entry, + struct lock_class *target, + struct lock_list **target_entry, + int forward) +{ + struct lock_list *entry; + struct circular_queue *cq = &lock_cq; + int ret = 1; + + __cq_init(cq); + + mark_lock_accessed(source_entry, NULL); + if (source_entry->class == target) { + *target_entry = source_entry; + ret = 0; + goto exit; + } + + __cq_enqueue(cq, (unsigned long)source_entry); + + while (!__cq_empty(cq)) { + struct lock_list *lock; + struct list_head *head; + + __cq_dequeue(cq, (unsigned long *)&lock); + + if (!lock->class) { + ret = -2; + goto exit; + } + + if (forward) + head = &lock->class->locks_after; + else + head = &lock->class->locks_before; + + list_for_each_entry(entry, head, entry) { + if (!lock_accessed(entry)) { + mark_lock_accessed(entry, lock); + if (entry->class == target) { + *target_entry = entry; + ret = 0; + goto exit; + } + + if (__cq_enqueue(cq, (unsigned long)entry)) { + ret = -1; + goto exit; + } + } + } + } +exit: + return ret; +} + +static inline int __search_forward_shortest_path(struct lock_list *src_entry, + struct lock_class *target, + struct lock_list **target_entry) +{ + return __search_shortest_path(src_entry, target, target_entry, 1); + +} + +static inline int __search_backward_shortest_path(struct lock_list *src_entry, + struct lock_class *target, + struct lock_list **target_entry) +{ + return __search_shortest_path(src_entry, target, target_entry, 0); + +} + /* * Recursive, forwards-direction lock-dependency checking, used for * both noncyclic checking and for hardirq-unsafe/softirq-unsafe @@ -934,7 +1007,7 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth) { struct task_struct *curr = current; - if (!debug_locks_off_graph_unlock() || debug_locks_silent) + if (debug_locks_silent) return 0; printk("\n=======================================================\n"); @@ -954,19 +1027,41 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth) return 0; } -static noinline int print_circular_bug_tail(void) +static noinline int print_circular_bug(void) { struct task_struct *curr = current; struct lock_list this; + struct lock_list *target; + struct lock_list *parent; + int result; + unsigned long depth; - if (debug_locks_silent) + if (!debug_locks_off_graph_unlock() || debug_locks_silent) return 0; this.class = hlock_class(check_source); if (!save_trace(&this.trace)) return 0; - print_circular_bug_entry(&this, 0); + result = __search_forward_shortest_path(&this, + hlock_class(check_target), + &target); + if (result) { + printk("\n%s:search shortest path failed:%d\n", __func__, + result); + return 0; + } + + depth = get_lock_depth(target); + + print_circular_bug_header(target, depth); + + parent = get_lock_parent(target); + + while (parent) { + print_circular_bug_entry(parent, --depth); + parent = get_lock_parent(parent); + } printk("\nother info that might help us debug this:\n\n"); lockdep_print_held_locks(curr); @@ -1072,14 +1167,15 @@ check_noncircular(struct lock_class *source, unsigned int depth) */ list_for_each_entry(entry, &source->locks_after, entry) { if (entry->class == hlock_class(check_target)) - return print_circular_bug_header(entry, depth+1); + return 2; debug_atomic_inc(&nr_cyclic_checks); - if (!check_noncircular(entry->class, depth+1)) - return print_circular_bug_entry(entry, depth+1); + if (check_noncircular(entry->class, depth+1) == 2) + return 2; } return 1; } + #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING) /* * Forwards and backwards subgraph searching, for the purposes of @@ -1484,8 +1580,9 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, */ check_source = next; check_target = prev; - if (!(check_noncircular(hlock_class(next), 0))) - return print_circular_bug_tail(); + if (check_noncircular(hlock_class(next), 0) == 2) + return print_circular_bug(); + if (!check_prev_add_irq(curr, prev, next)) return 0; diff --git a/kernel/lockdep_internals.h b/kernel/lockdep_internals.h index 699a2ac..6f48d37 100644 --- a/kernel/lockdep_internals.h +++ b/kernel/lockdep_internals.h @@ -136,3 +136,86 @@ extern atomic_t nr_find_usage_backwards_recursions; # define debug_atomic_dec(ptr) do { } while (0) # define debug_atomic_read(ptr) 0 #endif + +/* The circular_queue and helpers is used to implement the + * breadth-first search(BFS)algorithem, by which we can build + * the shortest path from the next lock to be acquired to the + * previous held lock if there is a circular between them. + * */ +#define MAX_CIRCULAR_QUE_SIZE 4096UL +struct circular_queue{ + unsigned long element[MAX_CIRCULAR_QUE_SIZE]; + unsigned int front, rear; +}; + +#define LOCK_ACCESSED 1UL +#define LOCK_ACCESSED_MASK (~LOCK_ACCESSED) + +static inline void __cq_init(struct circular_queue *cq) +{ + cq->front = cq->rear = 0; +} + +static inline int __cq_empty(struct circular_queue *cq) +{ + return (cq->front == cq->rear); +} + +static inline int __cq_full(struct circular_queue *cq) +{ + return ((cq->rear + 1)%MAX_CIRCULAR_QUE_SIZE) == cq->front; +} + +static inline int __cq_enqueue(struct circular_queue *cq, unsigned long elem) +{ + if (__cq_full(cq)) + return -1; + + cq->element[cq->rear] = elem; + cq->rear = (cq->rear + 1)%MAX_CIRCULAR_QUE_SIZE; + return 0; +} + +static inline int __cq_dequeue(struct circular_queue *cq, unsigned long *elem) +{ + if (__cq_empty(cq)) + return -1; + + *elem = cq->element[cq->front]; + cq->front = (cq->front + 1)%MAX_CIRCULAR_QUE_SIZE; + return 0; +} + +static inline int __cq_get_elem_count(struct circular_queue *cq) +{ + return (cq->rear - cq->front)%MAX_CIRCULAR_QUE_SIZE; +} + +static inline void mark_lock_accessed(struct lock_list *lock, + struct lock_list *parent) +{ + lock->parent = (void *) parent + LOCK_ACCESSED; +} + +static inline unsigned long lock_accessed(struct lock_list *lock) +{ + return (unsigned long)lock->parent & LOCK_ACCESSED; +} + +static inline struct lock_list *get_lock_parent(struct lock_list *child) +{ + return (struct lock_list *) + ((unsigned long)child->parent & LOCK_ACCESSED_MASK); +} + +static inline unsigned long get_lock_depth(struct lock_list *child) +{ + unsigned long depth = 0; + struct lock_list *parent; + + while ((parent = get_lock_parent(child))) { + child = parent; + depth++; + } + return depth; +} -- cgit v0.10.2 From d588e46155e9c51217b9840db1e94a0f594c1af2 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: lockdep: Improve implementation of BFS 1,replace %MAX_CIRCULAR_QUE_SIZE with &(MAX_CIRCULAR_QUE_SIZE-1) since we define MAX_CIRCULAR_QUE_SIZE as power of 2; 2,use bitmap to mark if a lock is accessed in BFS in order to clear it quickly, because we may search a graph many times. Signed-off-by: Ming Lei Signed-off-by: Peter Zijlstra LKML-Reference: <1246201486-7308-3-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 93dc70d..5dcca26 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -42,7 +42,7 @@ #include #include #include - +#include #include #include "lockdep_internals.h" @@ -118,7 +118,7 @@ static inline int debug_locks_off_graph_unlock(void) static int lockdep_initialized; unsigned long nr_list_entries; -static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES]; +struct lock_list list_entries[MAX_LOCKDEP_ENTRIES]; /* * All data structures here are protected by the global debug_lock. @@ -897,30 +897,38 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, return 1; } +unsigned long bfs_accessed[BITS_TO_LONGS(MAX_LOCKDEP_ENTRIES)]; static struct circular_queue lock_cq; + static int __search_shortest_path(struct lock_list *source_entry, struct lock_class *target, struct lock_list **target_entry, int forward) { struct lock_list *entry; + struct list_head *head; struct circular_queue *cq = &lock_cq; int ret = 1; - __cq_init(cq); - - mark_lock_accessed(source_entry, NULL); if (source_entry->class == target) { *target_entry = source_entry; ret = 0; goto exit; } + if (forward) + head = &source_entry->class->locks_after; + else + head = &source_entry->class->locks_before; + + if (list_empty(head)) + goto exit; + + __cq_init(cq); __cq_enqueue(cq, (unsigned long)source_entry); while (!__cq_empty(cq)) { struct lock_list *lock; - struct list_head *head; __cq_dequeue(cq, (unsigned long *)&lock); @@ -1040,6 +1048,7 @@ static noinline int print_circular_bug(void) return 0; this.class = hlock_class(check_source); + this.parent = NULL; if (!save_trace(&this.trace)) return 0; @@ -1580,10 +1589,10 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, */ check_source = next; check_target = prev; + if (check_noncircular(hlock_class(next), 0) == 2) return print_circular_bug(); - if (!check_prev_add_irq(curr, prev, next)) return 0; diff --git a/kernel/lockdep_internals.h b/kernel/lockdep_internals.h index 6f48d37..c2f6594 100644 --- a/kernel/lockdep_internals.h +++ b/kernel/lockdep_internals.h @@ -137,23 +137,28 @@ extern atomic_t nr_find_usage_backwards_recursions; # define debug_atomic_read(ptr) 0 #endif + +extern unsigned long nr_list_entries; +extern struct lock_list list_entries[MAX_LOCKDEP_ENTRIES]; +extern unsigned long bfs_accessed[]; + +/*For good efficiency of modular, we use power of 2*/ +#define MAX_CIRCULAR_QUE_SIZE 4096UL + /* The circular_queue and helpers is used to implement the * breadth-first search(BFS)algorithem, by which we can build * the shortest path from the next lock to be acquired to the * previous held lock if there is a circular between them. * */ -#define MAX_CIRCULAR_QUE_SIZE 4096UL struct circular_queue{ unsigned long element[MAX_CIRCULAR_QUE_SIZE]; unsigned int front, rear; }; -#define LOCK_ACCESSED 1UL -#define LOCK_ACCESSED_MASK (~LOCK_ACCESSED) - static inline void __cq_init(struct circular_queue *cq) { cq->front = cq->rear = 0; + bitmap_zero(bfs_accessed, MAX_LOCKDEP_ENTRIES); } static inline int __cq_empty(struct circular_queue *cq) @@ -163,7 +168,7 @@ static inline int __cq_empty(struct circular_queue *cq) static inline int __cq_full(struct circular_queue *cq) { - return ((cq->rear + 1)%MAX_CIRCULAR_QUE_SIZE) == cq->front; + return ((cq->rear + 1)&(MAX_CIRCULAR_QUE_SIZE-1)) == cq->front; } static inline int __cq_enqueue(struct circular_queue *cq, unsigned long elem) @@ -172,7 +177,7 @@ static inline int __cq_enqueue(struct circular_queue *cq, unsigned long elem) return -1; cq->element[cq->rear] = elem; - cq->rear = (cq->rear + 1)%MAX_CIRCULAR_QUE_SIZE; + cq->rear = (cq->rear + 1)&(MAX_CIRCULAR_QUE_SIZE-1); return 0; } @@ -182,30 +187,36 @@ static inline int __cq_dequeue(struct circular_queue *cq, unsigned long *elem) return -1; *elem = cq->element[cq->front]; - cq->front = (cq->front + 1)%MAX_CIRCULAR_QUE_SIZE; + cq->front = (cq->front + 1)&(MAX_CIRCULAR_QUE_SIZE-1); return 0; } static inline int __cq_get_elem_count(struct circular_queue *cq) { - return (cq->rear - cq->front)%MAX_CIRCULAR_QUE_SIZE; + return (cq->rear - cq->front)&(MAX_CIRCULAR_QUE_SIZE-1); } static inline void mark_lock_accessed(struct lock_list *lock, struct lock_list *parent) { - lock->parent = (void *) parent + LOCK_ACCESSED; + unsigned long nr; + nr = lock - list_entries; + WARN_ON(nr >= nr_list_entries); + lock->parent = parent; + set_bit(nr, bfs_accessed); } static inline unsigned long lock_accessed(struct lock_list *lock) { - return (unsigned long)lock->parent & LOCK_ACCESSED; + unsigned long nr; + nr = lock - list_entries; + WARN_ON(nr >= nr_list_entries); + return test_bit(nr, bfs_accessed); } static inline struct lock_list *get_lock_parent(struct lock_list *child) { - return (struct lock_list *) - ((unsigned long)child->parent & LOCK_ACCESSED_MASK); + return child->parent; } static inline unsigned long get_lock_depth(struct lock_list *child) -- cgit v0.10.2 From 9e2d551ea0d767c0d624965f0c273e942f4be536 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: lockdep: Introduce match function to BFS 1,introduce match() to BFS in order to make it usable to match different pattern; 2,also rename some functions to make them more suitable. Signed-off-by: Ming Lei Signed-off-by: Peter Zijlstra LKML-Reference: <1246201486-7308-4-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 5dcca26..ce6d09e 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -900,17 +900,18 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, unsigned long bfs_accessed[BITS_TO_LONGS(MAX_LOCKDEP_ENTRIES)]; static struct circular_queue lock_cq; -static int __search_shortest_path(struct lock_list *source_entry, - struct lock_class *target, - struct lock_list **target_entry, - int forward) +static int __bfs(struct lock_list *source_entry, + void *data, + int (*match)(struct lock_list *entry, void *data), + struct lock_list **target_entry, + int forward) { struct lock_list *entry; struct list_head *head; struct circular_queue *cq = &lock_cq; int ret = 1; - if (source_entry->class == target) { + if (match(source_entry, data)) { *target_entry = source_entry; ret = 0; goto exit; @@ -945,7 +946,7 @@ static int __search_shortest_path(struct lock_list *source_entry, list_for_each_entry(entry, head, entry) { if (!lock_accessed(entry)) { mark_lock_accessed(entry, lock); - if (entry->class == target) { + if (match(entry, data)) { *target_entry = entry; ret = 0; goto exit; @@ -962,19 +963,21 @@ exit: return ret; } -static inline int __search_forward_shortest_path(struct lock_list *src_entry, - struct lock_class *target, - struct lock_list **target_entry) +static inline int __bfs_forward(struct lock_list *src_entry, + void *data, + int (*match)(struct lock_list *entry, void *data), + struct lock_list **target_entry) { - return __search_shortest_path(src_entry, target, target_entry, 1); + return __bfs(src_entry, data, match, target_entry, 1); } -static inline int __search_backward_shortest_path(struct lock_list *src_entry, - struct lock_class *target, - struct lock_list **target_entry) +static inline int __bfs_backward(struct lock_list *src_entry, + void *data, + int (*match)(struct lock_list *entry, void *data), + struct lock_list **target_entry) { - return __search_shortest_path(src_entry, target, target_entry, 0); + return __bfs(src_entry, data, match, target_entry, 0); } @@ -1035,6 +1038,11 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth) return 0; } +static inline int class_equal(struct lock_list *entry, void *data) +{ + return entry->class == data; +} + static noinline int print_circular_bug(void) { struct task_struct *curr = current; @@ -1052,9 +1060,10 @@ static noinline int print_circular_bug(void) if (!save_trace(&this.trace)) return 0; - result = __search_forward_shortest_path(&this, - hlock_class(check_target), - &target); + result = __bfs_forward(&this, + hlock_class(check_target), + class_equal, + &target); if (result) { printk("\n%s:search shortest path failed:%d\n", __func__, result); -- cgit v0.10.2 From db0002a32f31060ca900b533d93a074ddf7d5b61 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: lockdep: Implement check_noncircular() by BFS This patch uses BFS to implement check_noncircular() and prints the generated shortest circle if exists. Signed-off-by: Ming Lei Signed-off-by: Peter Zijlstra LKML-Reference: <1246201486-7308-5-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index ce6d09e..5609d30 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -985,12 +985,7 @@ static inline int __bfs_backward(struct lock_list *src_entry, * Recursive, forwards-direction lock-dependency checking, used for * both noncyclic checking and for hardirq-unsafe/softirq-unsafe * checking. - * - * (to keep the stackframe of the recursive functions small we - * use these global variables, and we also mark various helper - * functions as noinline.) */ -static struct held_lock *check_source, *check_target; /* * Print a dependency chain entry (this is only done when a deadlock @@ -1014,7 +1009,9 @@ print_circular_bug_entry(struct lock_list *target, unsigned int depth) * header first: */ static noinline int -print_circular_bug_header(struct lock_list *entry, unsigned int depth) +print_circular_bug_header(struct lock_list *entry, unsigned int depth, + struct held_lock *check_src, + struct held_lock *check_tgt) { struct task_struct *curr = current; @@ -1027,9 +1024,9 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth) printk( "-------------------------------------------------------\n"); printk("%s/%d is trying to acquire lock:\n", curr->comm, task_pid_nr(curr)); - print_lock(check_source); + print_lock(check_src); printk("\nbut task is already holding lock:\n"); - print_lock(check_target); + print_lock(check_tgt); printk("\nwhich lock already depends on the new lock.\n\n"); printk("\nthe existing dependency chain (in reverse order) is:\n"); @@ -1043,36 +1040,24 @@ static inline int class_equal(struct lock_list *entry, void *data) return entry->class == data; } -static noinline int print_circular_bug(void) +static noinline int print_circular_bug(struct lock_list *this, + struct lock_list *target, + struct held_lock *check_src, + struct held_lock *check_tgt) { struct task_struct *curr = current; - struct lock_list this; - struct lock_list *target; struct lock_list *parent; - int result; unsigned long depth; if (!debug_locks_off_graph_unlock() || debug_locks_silent) return 0; - this.class = hlock_class(check_source); - this.parent = NULL; - if (!save_trace(&this.trace)) + if (!save_trace(&this->trace)) return 0; - result = __bfs_forward(&this, - hlock_class(check_target), - class_equal, - &target); - if (result) { - printk("\n%s:search shortest path failed:%d\n", __func__, - result); - return 0; - } - depth = get_lock_depth(target); - print_circular_bug_header(target, depth); + print_circular_bug_header(target, depth, check_src, check_tgt); parent = get_lock_parent(target); @@ -1090,6 +1075,16 @@ static noinline int print_circular_bug(void) return 0; } +static noinline int print_bfs_bug(int ret) +{ + if (!debug_locks_off_graph_unlock()) + return 0; + + WARN(1, "lockdep bfs error:%d\n", ret); + + return 0; +} + #define RECURSION_LIMIT 40 static int noinline print_infinite_recursion_bug(void) @@ -1168,31 +1163,17 @@ unsigned long lockdep_count_backward_deps(struct lock_class *class) * lead to . Print an error and return 0 if it does. */ static noinline int -check_noncircular(struct lock_class *source, unsigned int depth) +check_noncircular(struct lock_list *root, struct lock_class *target, + struct lock_list **target_entry) { - struct lock_list *entry; + int result; - if (lockdep_dependency_visit(source, depth)) - return 1; + debug_atomic_inc(&nr_cyclic_checks); - debug_atomic_inc(&nr_cyclic_check_recursions); - if (depth > max_recursion_depth) - max_recursion_depth = depth; - if (depth >= RECURSION_LIMIT) - return print_infinite_recursion_bug(); - /* - * Check this lock's dependency list: - */ - list_for_each_entry(entry, &source->locks_after, entry) { - if (entry->class == hlock_class(check_target)) - return 2; - debug_atomic_inc(&nr_cyclic_checks); - if (check_noncircular(entry->class, depth+1) == 2) - return 2; - } - return 1; -} + result = __bfs_forward(root, target, class_equal, target_entry); + return result; +} #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING) /* @@ -1586,6 +1567,8 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, { struct lock_list *entry; int ret; + struct lock_list this; + struct lock_list *uninitialized_var(target_entry); /* * Prove that the new -> dependency would not @@ -1596,11 +1579,13 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, * We are using global variables to control the recursion, to * keep the stackframe size of the recursive functions low: */ - check_source = next; - check_target = prev; - - if (check_noncircular(hlock_class(next), 0) == 2) - return print_circular_bug(); + this.class = hlock_class(next); + this.parent = NULL; + ret = check_noncircular(&this, hlock_class(prev), &target_entry); + if (unlikely(!ret)) + return print_circular_bug(&this, target_entry, next, prev); + else if (unlikely(ret < 0)) + return print_bfs_bug(ret); if (!check_prev_add_irq(curr, prev, next)) return 0; -- cgit v0.10.2 From d7aaba140a09b7a2295aec061629c880f088de3d Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: lockdep: Implement find_usage_*wards by BFS This patch uses BFS to implement find_usage_*wards(),which was originally writen by DFS. Signed-off-by: Ming Lei Signed-off-by: Peter Zijlstra LKML-Reference: <1246201486-7308-6-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 5609d30..b3ade50 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -963,7 +963,7 @@ exit: return ret; } -static inline int __bfs_forward(struct lock_list *src_entry, +static inline int __bfs_forwards(struct lock_list *src_entry, void *data, int (*match)(struct lock_list *entry, void *data), struct lock_list **target_entry) @@ -972,7 +972,7 @@ static inline int __bfs_forward(struct lock_list *src_entry, } -static inline int __bfs_backward(struct lock_list *src_entry, +static inline int __bfs_backwards(struct lock_list *src_entry, void *data, int (*match)(struct lock_list *entry, void *data), struct lock_list **target_entry) @@ -1085,18 +1085,6 @@ static noinline int print_bfs_bug(int ret) return 0; } -#define RECURSION_LIMIT 40 - -static int noinline print_infinite_recursion_bug(void) -{ - if (!debug_locks_off_graph_unlock()) - return 0; - - WARN_ON(1); - - return 0; -} - unsigned long __lockdep_count_forward_deps(struct lock_class *class, unsigned int depth) { @@ -1170,7 +1158,7 @@ check_noncircular(struct lock_list *root, struct lock_class *target, debug_atomic_inc(&nr_cyclic_checks); - result = __bfs_forward(root, target, class_equal, target_entry); + result = __bfs_forwards(root, target, class_equal, target_entry); return result; } @@ -1181,101 +1169,70 @@ check_noncircular(struct lock_list *root, struct lock_class *target, * proving that two subgraphs can be connected by a new dependency * without creating any illegal irq-safe -> irq-unsafe lock dependency. */ -static enum lock_usage_bit find_usage_bit; static struct lock_class *forwards_match, *backwards_match; + +#define BFS_PROCESS_RET(ret) do { \ + if (ret < 0) \ + return print_bfs_bug(ret); \ + if (ret == 1) \ + return 1; \ + } while (0) + +static inline int usage_match(struct lock_list *entry, void *bit) +{ + return entry->class->usage_mask & (1 << (enum lock_usage_bit)bit); +} + + + /* * Find a node in the forwards-direction dependency sub-graph starting - * at that matches . + * at @root->class that matches @bit. * - * Return 2 if such a node exists in the subgraph, and put that node - * into . + * Return 0 if such a node exists in the subgraph, and put that node + * into *@target_entry. * - * Return 1 otherwise and keep unchanged. - * Return 0 on error. + * Return 1 otherwise and keep *@target_entry unchanged. + * Return <0 on error. */ -static noinline int -find_usage_forwards(struct lock_class *source, unsigned int depth) +static int +find_usage_forwards(struct lock_list *root, enum lock_usage_bit bit, + struct lock_list **target_entry) { - struct lock_list *entry; - int ret; - - if (lockdep_dependency_visit(source, depth)) - return 1; - - if (depth > max_recursion_depth) - max_recursion_depth = depth; - if (depth >= RECURSION_LIMIT) - return print_infinite_recursion_bug(); + int result; debug_atomic_inc(&nr_find_usage_forwards_checks); - if (source->usage_mask & (1 << find_usage_bit)) { - forwards_match = source; - return 2; - } - /* - * Check this lock's dependency list: - */ - list_for_each_entry(entry, &source->locks_after, entry) { - debug_atomic_inc(&nr_find_usage_forwards_recursions); - ret = find_usage_forwards(entry->class, depth+1); - if (ret == 2 || ret == 0) - return ret; - } - return 1; + result = __bfs_forwards(root, (void *)bit, usage_match, target_entry); + + return result; } /* * Find a node in the backwards-direction dependency sub-graph starting - * at that matches . + * at @root->class that matches @bit. * - * Return 2 if such a node exists in the subgraph, and put that node - * into . + * Return 0 if such a node exists in the subgraph, and put that node + * into *@target_entry. * - * Return 1 otherwise and keep unchanged. - * Return 0 on error. + * Return 1 otherwise and keep *@target_entry unchanged. + * Return <0 on error. */ -static noinline int -find_usage_backwards(struct lock_class *source, unsigned int depth) +static int +find_usage_backwards(struct lock_list *root, enum lock_usage_bit bit, + struct lock_list **target_entry) { - struct lock_list *entry; - int ret; - - if (lockdep_dependency_visit(source, depth)) - return 1; - - if (!__raw_spin_is_locked(&lockdep_lock)) - return DEBUG_LOCKS_WARN_ON(1); - - if (depth > max_recursion_depth) - max_recursion_depth = depth; - if (depth >= RECURSION_LIMIT) - return print_infinite_recursion_bug(); + int result; debug_atomic_inc(&nr_find_usage_backwards_checks); - if (source->usage_mask & (1 << find_usage_bit)) { - backwards_match = source; - return 2; - } - if (!source && debug_locks_off_graph_unlock()) { - WARN_ON(1); - return 0; - } + result = __bfs_backwards(root, (void *)bit, usage_match, target_entry); - /* - * Check this lock's dependency list: - */ - list_for_each_entry(entry, &source->locks_before, entry) { - debug_atomic_inc(&nr_find_usage_backwards_recursions); - ret = find_usage_backwards(entry->class, depth+1); - if (ret == 2 || ret == 0) - return ret; - } - return 1; + return result; } + static int print_bad_irq_dependency(struct task_struct *curr, struct held_lock *prev, @@ -1343,18 +1300,21 @@ check_usage(struct task_struct *curr, struct held_lock *prev, enum lock_usage_bit bit_forwards, const char *irqclass) { int ret; + struct lock_list this; + struct lock_list *uninitialized_var(target_entry); + + this.parent = NULL; + + this.class = hlock_class(prev); + ret = find_usage_backwards(&this, bit_backwards, &target_entry); + BFS_PROCESS_RET(ret); + backwards_match = target_entry->class; + + this.class = hlock_class(next); + ret = find_usage_forwards(&this, bit_forwards, &target_entry); + BFS_PROCESS_RET(ret); + forwards_match = target_entry->class; - find_usage_bit = bit_backwards; - /* fills in */ - ret = find_usage_backwards(hlock_class(prev), 0); - if (!ret || ret == 1) - return ret; - - find_usage_bit = bit_forwards; - ret = find_usage_forwards(hlock_class(next), 0); - if (!ret || ret == 1) - return ret; - /* ret == 2 */ return print_bad_irq_dependency(curr, prev, next, bit_backwards, bit_forwards, irqclass); } @@ -2029,14 +1989,16 @@ check_usage_forwards(struct task_struct *curr, struct held_lock *this, enum lock_usage_bit bit, const char *irqclass) { int ret; + struct lock_list root; + struct lock_list *uninitialized_var(target_entry); - find_usage_bit = bit; - /* fills in */ - ret = find_usage_forwards(hlock_class(this), 0); - if (!ret || ret == 1) - return ret; + root.parent = NULL; + root.class = hlock_class(this); + ret = find_usage_forwards(&root, bit, &target_entry); + BFS_PROCESS_RET(ret); - return print_irq_inversion_bug(curr, forwards_match, this, 1, irqclass); + return print_irq_inversion_bug(curr, target_entry->class, + this, 1, irqclass); } /* @@ -2048,14 +2010,16 @@ check_usage_backwards(struct task_struct *curr, struct held_lock *this, enum lock_usage_bit bit, const char *irqclass) { int ret; + struct lock_list root; + struct lock_list *uninitialized_var(target_entry); - find_usage_bit = bit; - /* fills in */ - ret = find_usage_backwards(hlock_class(this), 0); - if (!ret || ret == 1) - return ret; + root.parent = NULL; + root.class = hlock_class(this); + ret = find_usage_backwards(&root, bit, &target_entry); + BFS_PROCESS_RET(ret); - return print_irq_inversion_bug(curr, backwards_match, this, 0, irqclass); + return print_irq_inversion_bug(curr, target_entry->class, + this, 1, irqclass); } void print_irqtrace_events(struct task_struct *curr) -- cgit v0.10.2 From 24208ca76707581a097c01a73fd63781e73d3404 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: lockdep: Introduce print_shortest_lock_dependencies Since the shortest lock dependencies' path may be obtained by BFS, we print the shortest one by print_shortest_lock_dependencies(). Signed-off-by: Ming Lei Signed-off-by: Peter Zijlstra LKML-Reference: <1246201486-7308-7-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index b3ade50..938dc50 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -576,6 +576,36 @@ static void print_lock_class_header(struct lock_class *class, int depth) } /* + * printk the shortest lock dependencies from @start to @end in reverse order: + */ +static void __used +print_shortest_lock_dependencies(struct lock_list *leaf, + struct lock_list *root) +{ + struct lock_list *entry = leaf; + int depth; + + /*compute depth from generated tree by BFS*/ + depth = get_lock_depth(leaf); + + do { + print_lock_class_header(entry->class, depth); + printk("%*s ... acquired at:\n", depth, ""); + print_stack_trace(&entry->trace, 2); + printk("\n"); + + if (depth == 0 && (entry != root)) { + printk("lockdep:%s bad BFS generated tree\n", __func__); + break; + } + + entry = get_lock_parent(entry); + depth--; + } while (entry && (depth >= 0)); + + return; +} +/* * printk all lock dependencies starting at : */ static void __used @@ -992,7 +1022,7 @@ static inline int __bfs_backwards(struct lock_list *src_entry, * has been detected): */ static noinline int -print_circular_bug_entry(struct lock_list *target, unsigned int depth) +print_circular_bug_entry(struct lock_list *target, int depth) { if (debug_locks_silent) return 0; @@ -1047,7 +1077,7 @@ static noinline int print_circular_bug(struct lock_list *this, { struct task_struct *curr = current; struct lock_list *parent; - unsigned long depth; + int depth; if (!debug_locks_off_graph_unlock() || debug_locks_silent) return 0; @@ -1169,7 +1199,6 @@ check_noncircular(struct lock_list *root, struct lock_class *target, * proving that two subgraphs can be connected by a new dependency * without creating any illegal irq-safe -> irq-unsafe lock dependency. */ -static struct lock_class *forwards_match, *backwards_match; #define BFS_PROCESS_RET(ret) do { \ @@ -1235,6 +1264,10 @@ find_usage_backwards(struct lock_list *root, enum lock_usage_bit bit, static int print_bad_irq_dependency(struct task_struct *curr, + struct lock_list *prev_root, + struct lock_list *next_root, + struct lock_list *backwards_entry, + struct lock_list *forwards_entry, struct held_lock *prev, struct held_lock *next, enum lock_usage_bit bit1, @@ -1267,26 +1300,32 @@ print_bad_irq_dependency(struct task_struct *curr, printk("\nbut this new dependency connects a %s-irq-safe lock:\n", irqclass); - print_lock_name(backwards_match); + print_lock_name(backwards_entry->class); printk("\n... which became %s-irq-safe at:\n", irqclass); - print_stack_trace(backwards_match->usage_traces + bit1, 1); + print_stack_trace(backwards_entry->class->usage_traces + bit1, 1); printk("\nto a %s-irq-unsafe lock:\n", irqclass); - print_lock_name(forwards_match); + print_lock_name(forwards_entry->class); printk("\n... which became %s-irq-unsafe at:\n", irqclass); printk("..."); - print_stack_trace(forwards_match->usage_traces + bit2, 1); + print_stack_trace(forwards_entry->class->usage_traces + bit2, 1); printk("\nother info that might help us debug this:\n\n"); lockdep_print_held_locks(curr); - printk("\nthe %s-irq-safe lock's dependencies:\n", irqclass); - print_lock_dependencies(backwards_match, 0); + printk("\nthe dependencies between %s-irq-safe lock", irqclass); + printk(" and the holding lock:\n"); + if (!save_trace(&prev_root->trace)) + return 0; + print_shortest_lock_dependencies(backwards_entry, prev_root); - printk("\nthe %s-irq-unsafe lock's dependencies:\n", irqclass); - print_lock_dependencies(forwards_match, 0); + printk("\nthe dependencies between the lock to be acquired"); + printk(" and %s-irq-unsafe lock:\n", irqclass); + if (!save_trace(&next_root->trace)) + return 0; + print_shortest_lock_dependencies(forwards_entry, next_root); printk("\nstack backtrace:\n"); dump_stack(); @@ -1300,22 +1339,24 @@ check_usage(struct task_struct *curr, struct held_lock *prev, enum lock_usage_bit bit_forwards, const char *irqclass) { int ret; - struct lock_list this; + struct lock_list this, that; struct lock_list *uninitialized_var(target_entry); + struct lock_list *uninitialized_var(target_entry1); this.parent = NULL; this.class = hlock_class(prev); ret = find_usage_backwards(&this, bit_backwards, &target_entry); BFS_PROCESS_RET(ret); - backwards_match = target_entry->class; - this.class = hlock_class(next); - ret = find_usage_forwards(&this, bit_forwards, &target_entry); + that.parent = NULL; + that.class = hlock_class(next); + ret = find_usage_forwards(&that, bit_forwards, &target_entry1); BFS_PROCESS_RET(ret); - forwards_match = target_entry->class; - return print_bad_irq_dependency(curr, prev, next, + return print_bad_irq_dependency(curr, &this, &that, + target_entry, target_entry1, + prev, next, bit_backwards, bit_forwards, irqclass); } @@ -1944,7 +1985,8 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this, * print irq inversion bug: */ static int -print_irq_inversion_bug(struct task_struct *curr, struct lock_class *other, +print_irq_inversion_bug(struct task_struct *curr, + struct lock_list *root, struct lock_list *other, struct held_lock *this, int forwards, const char *irqclass) { @@ -1962,17 +2004,16 @@ print_irq_inversion_bug(struct task_struct *curr, struct lock_class *other, printk("but this lock took another, %s-unsafe lock in the past:\n", irqclass); else printk("but this lock was taken by another, %s-safe lock in the past:\n", irqclass); - print_lock_name(other); + print_lock_name(other->class); printk("\n\nand interrupts could create inverse lock ordering between them.\n\n"); printk("\nother info that might help us debug this:\n"); lockdep_print_held_locks(curr); - printk("\nthe first lock's dependencies:\n"); - print_lock_dependencies(hlock_class(this), 0); - - printk("\nthe second lock's dependencies:\n"); - print_lock_dependencies(other, 0); + printk("\nthe shortest dependencies between 2nd lock and 1st lock:\n"); + if (!save_trace(&root->trace)) + return 0; + print_shortest_lock_dependencies(other, root); printk("\nstack backtrace:\n"); dump_stack(); @@ -1997,7 +2038,7 @@ check_usage_forwards(struct task_struct *curr, struct held_lock *this, ret = find_usage_forwards(&root, bit, &target_entry); BFS_PROCESS_RET(ret); - return print_irq_inversion_bug(curr, target_entry->class, + return print_irq_inversion_bug(curr, &root, target_entry, this, 1, irqclass); } @@ -2018,7 +2059,7 @@ check_usage_backwards(struct task_struct *curr, struct held_lock *this, ret = find_usage_backwards(&root, bit, &target_entry); BFS_PROCESS_RET(ret); - return print_irq_inversion_bug(curr, target_entry->class, + return print_irq_inversion_bug(curr, &root, target_entry, this, 1, irqclass); } diff --git a/kernel/lockdep_internals.h b/kernel/lockdep_internals.h index c2f6594..b115aaa 100644 --- a/kernel/lockdep_internals.h +++ b/kernel/lockdep_internals.h @@ -219,9 +219,9 @@ static inline struct lock_list *get_lock_parent(struct lock_list *child) return child->parent; } -static inline unsigned long get_lock_depth(struct lock_list *child) +static inline int get_lock_depth(struct lock_list *child) { - unsigned long depth = 0; + int depth = 0; struct lock_list *parent; while ((parent = get_lock_parent(child))) { -- cgit v0.10.2 From ef681026ff85c49b7399ceec3eb62bbbcce605e8 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: lockdep: Implement lockdep_count_*ward_deps by BFS Implement lockdep_count_{for,back}ward using BFS. Signed-off-by: Ming Lei Signed-off-by: Peter Zijlstra LKML-Reference: <1246201486-7308-8-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 938dc50..b896f23 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -1115,61 +1115,59 @@ static noinline int print_bfs_bug(int ret) return 0; } -unsigned long __lockdep_count_forward_deps(struct lock_class *class, - unsigned int depth) +static int noop_count(struct lock_list *entry, void *data) { - struct lock_list *entry; - unsigned long ret = 1; + (*(unsigned long *)data)++; + return 0; +} - if (lockdep_dependency_visit(class, depth)) - return 0; +unsigned long __lockdep_count_forward_deps(struct lock_list *this) +{ + unsigned long count = 0; + struct lock_list *uninitialized_var(target_entry); - /* - * Recurse this class's dependency list: - */ - list_for_each_entry(entry, &class->locks_after, entry) - ret += __lockdep_count_forward_deps(entry->class, depth + 1); + __bfs_forwards(this, (void *)&count, noop_count, &target_entry); - return ret; + return count; } - unsigned long lockdep_count_forward_deps(struct lock_class *class) { unsigned long ret, flags; + struct lock_list this; + + this.parent = NULL; + this.class = class; local_irq_save(flags); __raw_spin_lock(&lockdep_lock); - ret = __lockdep_count_forward_deps(class, 0); + ret = __lockdep_count_forward_deps(&this); __raw_spin_unlock(&lockdep_lock); local_irq_restore(flags); return ret; } -unsigned long __lockdep_count_backward_deps(struct lock_class *class, - unsigned int depth) +unsigned long __lockdep_count_backward_deps(struct lock_list *this) { - struct lock_list *entry; - unsigned long ret = 1; + unsigned long count = 0; + struct lock_list *uninitialized_var(target_entry); - if (lockdep_dependency_visit(class, depth)) - return 0; - /* - * Recurse this class's dependency list: - */ - list_for_each_entry(entry, &class->locks_before, entry) - ret += __lockdep_count_backward_deps(entry->class, depth + 1); + __bfs_backwards(this, (void *)&count, noop_count, &target_entry); - return ret; + return count; } unsigned long lockdep_count_backward_deps(struct lock_class *class) { unsigned long ret, flags; + struct lock_list this; + + this.parent = NULL; + this.class = class; local_irq_save(flags); __raw_spin_lock(&lockdep_lock); - ret = __lockdep_count_backward_deps(class, 0); + ret = __lockdep_count_backward_deps(&this); __raw_spin_unlock(&lockdep_lock); local_irq_restore(flags); -- cgit v0.10.2 From 4dd861d6467007681991d8ec079d928db2018cbb Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: lockdep: Update memory usage introduced by BFS Also account the BFS memory usage. Signed-off-by: Ming Lei [ fix build for !PROVE_LOCKING ] Signed-off-by: Peter Zijlstra LKML-Reference: <1246201486-7308-9-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index b896f23..6358cf7 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -3429,7 +3429,11 @@ void __init lockdep_info(void) sizeof(struct list_head) * CLASSHASH_SIZE + sizeof(struct lock_list) * MAX_LOCKDEP_ENTRIES + sizeof(struct lock_chain) * MAX_LOCKDEP_CHAINS + - sizeof(struct list_head) * CHAINHASH_SIZE) / 1024); + sizeof(struct list_head) * CHAINHASH_SIZE) / 1024 +#ifdef CONFIG_PROVE_LOCKING + + sizeof(struct circular_queue) + sizeof(bfs_accessed) +#endif + ); printk(" per task-struct memory footprint: %lu bytes\n", sizeof(struct held_lock) * MAX_LOCK_DEPTH); -- cgit v0.10.2 From 12f3dfd022d7e616757a94f0538d3d525d806a16 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: lockdep: Add statistics info for max bfs queue depth Add BFS statistics to the existing lockdep stats. Signed-off-by: Ming Lei Signed-off-by: Peter Zijlstra LKML-Reference: <1246201486-7308-10-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 6358cf7..744da62 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -929,7 +929,7 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, unsigned long bfs_accessed[BITS_TO_LONGS(MAX_LOCKDEP_ENTRIES)]; static struct circular_queue lock_cq; - +unsigned int max_bfs_queue_depth; static int __bfs(struct lock_list *source_entry, void *data, int (*match)(struct lock_list *entry, void *data), @@ -975,6 +975,7 @@ static int __bfs(struct lock_list *source_entry, list_for_each_entry(entry, head, entry) { if (!lock_accessed(entry)) { + unsigned int cq_depth; mark_lock_accessed(entry, lock); if (match(entry, data)) { *target_entry = entry; @@ -986,6 +987,9 @@ static int __bfs(struct lock_list *source_entry, ret = -1; goto exit; } + cq_depth = __cq_get_elem_count(cq); + if (max_bfs_queue_depth < cq_depth) + max_bfs_queue_depth = cq_depth; } } } diff --git a/kernel/lockdep_internals.h b/kernel/lockdep_internals.h index b115aaa..6baa880 100644 --- a/kernel/lockdep_internals.h +++ b/kernel/lockdep_internals.h @@ -138,6 +138,7 @@ extern atomic_t nr_find_usage_backwards_recursions; #endif +extern unsigned int max_bfs_queue_depth; extern unsigned long nr_list_entries; extern struct lock_list list_entries[MAX_LOCKDEP_ENTRIES]; extern unsigned long bfs_accessed[]; @@ -191,7 +192,7 @@ static inline int __cq_dequeue(struct circular_queue *cq, unsigned long *elem) return 0; } -static inline int __cq_get_elem_count(struct circular_queue *cq) +static inline unsigned int __cq_get_elem_count(struct circular_queue *cq) { return (cq->rear - cq->front)&(MAX_CIRCULAR_QUE_SIZE-1); } diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index d7135aa..9a1bf34 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c @@ -411,6 +411,8 @@ static int lockdep_stats_show(struct seq_file *m, void *v) max_lockdep_depth); seq_printf(m, " max recursion depth: %11u\n", max_recursion_depth); + seq_printf(m, " max bfs queue depth: %11u\n", + max_bfs_queue_depth); lockdep_stats_debug_show(m); seq_printf(m, " debug_locks: %11u\n", debug_locks); -- cgit v0.10.2 From af012961450949ea297b209e091bd1a3805b8a0a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 16 Jul 2009 15:44:29 +0200 Subject: lockdep: BFS cleanup Some cleanups of the lockdep code after the BFS series: - Remove the last traces of the generation id - Fixup comment style - Move the bfs routines into lockdep.c - Cleanup the bfs routines [ tom.leiming@gmail.com: Fix crash ] Signed-off-by: Peter Zijlstra LKML-Reference: <1246201486-7308-11-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 9ec026f..12aabfc 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -58,7 +58,6 @@ struct lock_class { struct lockdep_subclass_key *key; unsigned int subclass; - unsigned int dep_gen_id; /* * IRQ/softirq usage tracking bits: @@ -150,9 +149,9 @@ struct lock_list { struct stack_trace trace; int distance; - /*The parent field is used to implement breadth-first search,and - *the bit 0 is reused to indicate if the lock has been accessed - *in BFS. + /* + * The parent field is used to implement breadth-first search, and the + * bit 0 is reused to indicate if the lock has been accessed in BFS. */ struct lock_list *parent; }; diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 744da62..1cedb00 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -43,6 +43,7 @@ #include #include #include + #include #include "lockdep_internals.h" @@ -118,7 +119,7 @@ static inline int debug_locks_off_graph_unlock(void) static int lockdep_initialized; unsigned long nr_list_entries; -struct lock_list list_entries[MAX_LOCKDEP_ENTRIES]; +static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES]; /* * All data structures here are protected by the global debug_lock. @@ -390,19 +391,6 @@ unsigned int nr_process_chains; unsigned int max_lockdep_depth; unsigned int max_recursion_depth; -static unsigned int lockdep_dependency_gen_id; - -static bool lockdep_dependency_visit(struct lock_class *source, - unsigned int depth) -{ - if (!depth) - lockdep_dependency_gen_id++; - if (source->dep_gen_id == lockdep_dependency_gen_id) - return true; - source->dep_gen_id = lockdep_dependency_gen_id; - return false; -} - #ifdef CONFIG_DEBUG_LOCKDEP /* * We cannot printk in early bootup code. Not even early_printk() @@ -551,88 +539,6 @@ static void lockdep_print_held_locks(struct task_struct *curr) } } -static void print_lock_class_header(struct lock_class *class, int depth) -{ - int bit; - - printk("%*s->", depth, ""); - print_lock_name(class); - printk(" ops: %lu", class->ops); - printk(" {\n"); - - for (bit = 0; bit < LOCK_USAGE_STATES; bit++) { - if (class->usage_mask & (1 << bit)) { - int len = depth; - - len += printk("%*s %s", depth, "", usage_str[bit]); - len += printk(" at:\n"); - print_stack_trace(class->usage_traces + bit, len); - } - } - printk("%*s }\n", depth, ""); - - printk("%*s ... key at: ",depth,""); - print_ip_sym((unsigned long)class->key); -} - -/* - * printk the shortest lock dependencies from @start to @end in reverse order: - */ -static void __used -print_shortest_lock_dependencies(struct lock_list *leaf, - struct lock_list *root) -{ - struct lock_list *entry = leaf; - int depth; - - /*compute depth from generated tree by BFS*/ - depth = get_lock_depth(leaf); - - do { - print_lock_class_header(entry->class, depth); - printk("%*s ... acquired at:\n", depth, ""); - print_stack_trace(&entry->trace, 2); - printk("\n"); - - if (depth == 0 && (entry != root)) { - printk("lockdep:%s bad BFS generated tree\n", __func__); - break; - } - - entry = get_lock_parent(entry); - depth--; - } while (entry && (depth >= 0)); - - return; -} -/* - * printk all lock dependencies starting at : - */ -static void __used -print_lock_dependencies(struct lock_class *class, int depth) -{ - struct lock_list *entry; - - if (lockdep_dependency_visit(class, depth)) - return; - - if (DEBUG_LOCKS_WARN_ON(depth >= 20)) - return; - - print_lock_class_header(class, depth); - - list_for_each_entry(entry, &class->locks_after, entry) { - if (DEBUG_LOCKS_WARN_ON(!entry->class)) - return; - - print_lock_dependencies(entry->class, depth + 1); - - printk("%*s ... acquired at:\n",depth,""); - print_stack_trace(&entry->trace, 2); - printk("\n"); - } -} - static void print_kernel_version(void) { printk("%s %.*s\n", init_utsname()->release, @@ -927,14 +833,106 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, return 1; } -unsigned long bfs_accessed[BITS_TO_LONGS(MAX_LOCKDEP_ENTRIES)]; -static struct circular_queue lock_cq; +/*For good efficiency of modular, we use power of 2*/ +#define MAX_CIRCULAR_QUEUE_SIZE 4096UL +#define CQ_MASK (MAX_CIRCULAR_QUEUE_SIZE-1) + +/* The circular_queue and helpers is used to implement the + * breadth-first search(BFS)algorithem, by which we can build + * the shortest path from the next lock to be acquired to the + * previous held lock if there is a circular between them. + * */ +struct circular_queue { + unsigned long element[MAX_CIRCULAR_QUEUE_SIZE]; + unsigned int front, rear; +}; + +static struct circular_queue lock_cq; +static unsigned long bfs_accessed[BITS_TO_LONGS(MAX_LOCKDEP_ENTRIES)]; + unsigned int max_bfs_queue_depth; + +static inline void __cq_init(struct circular_queue *cq) +{ + cq->front = cq->rear = 0; + bitmap_zero(bfs_accessed, MAX_LOCKDEP_ENTRIES); +} + +static inline int __cq_empty(struct circular_queue *cq) +{ + return (cq->front == cq->rear); +} + +static inline int __cq_full(struct circular_queue *cq) +{ + return ((cq->rear + 1) & CQ_MASK) == cq->front; +} + +static inline int __cq_enqueue(struct circular_queue *cq, unsigned long elem) +{ + if (__cq_full(cq)) + return -1; + + cq->element[cq->rear] = elem; + cq->rear = (cq->rear + 1) & CQ_MASK; + return 0; +} + +static inline int __cq_dequeue(struct circular_queue *cq, unsigned long *elem) +{ + if (__cq_empty(cq)) + return -1; + + *elem = cq->element[cq->front]; + cq->front = (cq->front + 1) & CQ_MASK; + return 0; +} + +static inline unsigned int __cq_get_elem_count(struct circular_queue *cq) +{ + return (cq->rear - cq->front) & CQ_MASK; +} + +static inline void mark_lock_accessed(struct lock_list *lock, + struct lock_list *parent) +{ + unsigned long nr; + nr = lock - list_entries; + WARN_ON(nr >= nr_list_entries); + lock->parent = parent; + set_bit(nr, bfs_accessed); +} + +static inline unsigned long lock_accessed(struct lock_list *lock) +{ + unsigned long nr; + nr = lock - list_entries; + WARN_ON(nr >= nr_list_entries); + return test_bit(nr, bfs_accessed); +} + +static inline struct lock_list *get_lock_parent(struct lock_list *child) +{ + return child->parent; +} + +static inline int get_lock_depth(struct lock_list *child) +{ + int depth = 0; + struct lock_list *parent; + + while ((parent = get_lock_parent(child))) { + child = parent; + depth++; + } + return depth; +} + static int __bfs(struct lock_list *source_entry, - void *data, - int (*match)(struct lock_list *entry, void *data), - struct lock_list **target_entry, - int forward) + void *data, + int (*match)(struct lock_list *entry, void *data), + struct lock_list **target_entry, + int forward) { struct lock_list *entry; struct list_head *head; @@ -1202,14 +1200,6 @@ check_noncircular(struct lock_list *root, struct lock_class *target, * without creating any illegal irq-safe -> irq-unsafe lock dependency. */ - -#define BFS_PROCESS_RET(ret) do { \ - if (ret < 0) \ - return print_bfs_bug(ret); \ - if (ret == 1) \ - return 1; \ - } while (0) - static inline int usage_match(struct lock_list *entry, void *bit) { return entry->class->usage_mask & (1 << (enum lock_usage_bit)bit); @@ -1263,6 +1253,60 @@ find_usage_backwards(struct lock_list *root, enum lock_usage_bit bit, return result; } +static void print_lock_class_header(struct lock_class *class, int depth) +{ + int bit; + + printk("%*s->", depth, ""); + print_lock_name(class); + printk(" ops: %lu", class->ops); + printk(" {\n"); + + for (bit = 0; bit < LOCK_USAGE_STATES; bit++) { + if (class->usage_mask & (1 << bit)) { + int len = depth; + + len += printk("%*s %s", depth, "", usage_str[bit]); + len += printk(" at:\n"); + print_stack_trace(class->usage_traces + bit, len); + } + } + printk("%*s }\n", depth, ""); + + printk("%*s ... key at: ",depth,""); + print_ip_sym((unsigned long)class->key); +} + +/* + * printk the shortest lock dependencies from @start to @end in reverse order: + */ +static void __used +print_shortest_lock_dependencies(struct lock_list *leaf, + struct lock_list *root) +{ + struct lock_list *entry = leaf; + int depth; + + /*compute depth from generated tree by BFS*/ + depth = get_lock_depth(leaf); + + do { + print_lock_class_header(entry->class, depth); + printk("%*s ... acquired at:\n", depth, ""); + print_stack_trace(&entry->trace, 2); + printk("\n"); + + if (depth == 0 && (entry != root)) { + printk("lockdep:%s bad BFS generated tree\n", __func__); + break; + } + + entry = get_lock_parent(entry); + depth--; + } while (entry && (depth >= 0)); + + return; +} static int print_bad_irq_dependency(struct task_struct *curr, @@ -1349,12 +1393,18 @@ check_usage(struct task_struct *curr, struct held_lock *prev, this.class = hlock_class(prev); ret = find_usage_backwards(&this, bit_backwards, &target_entry); - BFS_PROCESS_RET(ret); + if (ret < 0) + return print_bfs_bug(ret); + if (ret == 1) + return ret; that.parent = NULL; that.class = hlock_class(next); ret = find_usage_forwards(&that, bit_forwards, &target_entry1); - BFS_PROCESS_RET(ret); + if (ret < 0) + return print_bfs_bug(ret); + if (ret == 1) + return ret; return print_bad_irq_dependency(curr, &this, &that, target_entry, target_entry1, @@ -2038,7 +2088,10 @@ check_usage_forwards(struct task_struct *curr, struct held_lock *this, root.parent = NULL; root.class = hlock_class(this); ret = find_usage_forwards(&root, bit, &target_entry); - BFS_PROCESS_RET(ret); + if (ret < 0) + return print_bfs_bug(ret); + if (ret == 1) + return ret; return print_irq_inversion_bug(curr, &root, target_entry, this, 1, irqclass); @@ -2059,7 +2112,10 @@ check_usage_backwards(struct task_struct *curr, struct held_lock *this, root.parent = NULL; root.class = hlock_class(this); ret = find_usage_backwards(&root, bit, &target_entry); - BFS_PROCESS_RET(ret); + if (ret < 0) + return print_bfs_bug(ret); + if (ret == 1) + return ret; return print_irq_inversion_bug(curr, &root, target_entry, this, 1, irqclass); diff --git a/kernel/lockdep_internals.h b/kernel/lockdep_internals.h index 6baa880..a2ee95a 100644 --- a/kernel/lockdep_internals.h +++ b/kernel/lockdep_internals.h @@ -91,6 +91,8 @@ extern unsigned int nr_process_chains; extern unsigned int max_lockdep_depth; extern unsigned int max_recursion_depth; +extern unsigned int max_bfs_queue_depth; + #ifdef CONFIG_PROVE_LOCKING extern unsigned long lockdep_count_forward_deps(struct lock_class *); extern unsigned long lockdep_count_backward_deps(struct lock_class *); @@ -136,98 +138,3 @@ extern atomic_t nr_find_usage_backwards_recursions; # define debug_atomic_dec(ptr) do { } while (0) # define debug_atomic_read(ptr) 0 #endif - - -extern unsigned int max_bfs_queue_depth; -extern unsigned long nr_list_entries; -extern struct lock_list list_entries[MAX_LOCKDEP_ENTRIES]; -extern unsigned long bfs_accessed[]; - -/*For good efficiency of modular, we use power of 2*/ -#define MAX_CIRCULAR_QUE_SIZE 4096UL - -/* The circular_queue and helpers is used to implement the - * breadth-first search(BFS)algorithem, by which we can build - * the shortest path from the next lock to be acquired to the - * previous held lock if there is a circular between them. - * */ -struct circular_queue{ - unsigned long element[MAX_CIRCULAR_QUE_SIZE]; - unsigned int front, rear; -}; - -static inline void __cq_init(struct circular_queue *cq) -{ - cq->front = cq->rear = 0; - bitmap_zero(bfs_accessed, MAX_LOCKDEP_ENTRIES); -} - -static inline int __cq_empty(struct circular_queue *cq) -{ - return (cq->front == cq->rear); -} - -static inline int __cq_full(struct circular_queue *cq) -{ - return ((cq->rear + 1)&(MAX_CIRCULAR_QUE_SIZE-1)) == cq->front; -} - -static inline int __cq_enqueue(struct circular_queue *cq, unsigned long elem) -{ - if (__cq_full(cq)) - return -1; - - cq->element[cq->rear] = elem; - cq->rear = (cq->rear + 1)&(MAX_CIRCULAR_QUE_SIZE-1); - return 0; -} - -static inline int __cq_dequeue(struct circular_queue *cq, unsigned long *elem) -{ - if (__cq_empty(cq)) - return -1; - - *elem = cq->element[cq->front]; - cq->front = (cq->front + 1)&(MAX_CIRCULAR_QUE_SIZE-1); - return 0; -} - -static inline unsigned int __cq_get_elem_count(struct circular_queue *cq) -{ - return (cq->rear - cq->front)&(MAX_CIRCULAR_QUE_SIZE-1); -} - -static inline void mark_lock_accessed(struct lock_list *lock, - struct lock_list *parent) -{ - unsigned long nr; - nr = lock - list_entries; - WARN_ON(nr >= nr_list_entries); - lock->parent = parent; - set_bit(nr, bfs_accessed); -} - -static inline unsigned long lock_accessed(struct lock_list *lock) -{ - unsigned long nr; - nr = lock - list_entries; - WARN_ON(nr >= nr_list_entries); - return test_bit(nr, bfs_accessed); -} - -static inline struct lock_list *get_lock_parent(struct lock_list *child) -{ - return child->parent; -} - -static inline int get_lock_depth(struct lock_list *child) -{ - int depth = 0; - struct lock_list *parent; - - while ((parent = get_lock_parent(child))) { - child = parent; - depth++; - } - return depth; -} -- cgit v0.10.2 From 178b699c25c39f042c3c2446e6bd5dbed18c0442 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Fri, 24 Jul 2009 02:48:57 +0200 Subject: ASoC: Jack handling enhancements as suggested by subsystem maintainer The patch adds a few small enhancements to the ASoC jack handling, as suggested by Mark in his comments to my Amstrad Delta driver, and a few fixes for related bugs found while learning Mark's code and testing results. Enhancements: 1. Update status of an ASoC jack while associating it with new gpios. 2. Really update DAPM pins while associating them with an ASoC jack. 3. Export ASoC jack gpios over gpiolib sysfs for diagnostic purposes. Fixes: 1. Apply mask on jack status report before using it, just for case. 2. While updating jack associated DAPM pins, use full resulting jack status, not the status report passed as an argument. Created and tested on linux-2.6.31-rc3 Signed-off-by: Janusz Krzysztofik Signed-off-by: Mark Brown diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 28346fb..4aa7d8f 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -73,14 +73,15 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) oldstatus = jack->status; jack->status &= ~mask; - jack->status |= status; + jack->status |= status & mask; - /* The DAPM sync is expensive enough to be worth skipping */ - if (jack->status == oldstatus) + /* The DAPM sync is expensive enough to be worth skipping. + * However, empty mask means pin synchronization is desired. */ + if (mask && (jack->status == oldstatus)) goto out; list_for_each_entry(pin, &jack->pins, list) { - enable = pin->mask & status; + enable = pin->mask & jack->status; if (pin->invert) enable = !enable; @@ -228,8 +229,16 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, if (ret) goto err; +#ifdef CONFIG_GPIO_SYSFS + /* Expose GPIO value over sysfs for diagnostic purposes */ + gpio_export(gpios[i].gpio, false); +#endif + INIT_WORK(&gpios[i].work, gpio_work); gpios[i].jack = jack; + + /* Update initial jack status */ + snd_soc_jack_gpio_detect(&gpios[i]); } return 0; @@ -258,6 +267,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, int i; for (i = 0; i < count; i++) { +#ifdef CONFIG_GPIO_SYSFS + gpio_unexport(gpios[i].gpio); +#endif free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]); gpio_free(gpios[i].gpio); gpios[i].jack = NULL; -- cgit v0.10.2 From 4ce2f2fe61002ab35c9333d52c95b5ff9e949f50 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 23 Jul 2009 22:16:56 +0200 Subject: ASoC: Switch palm27x-asoc to jack detection api This patch removes the old method of jack detection from palm27x-asoc driver and adds jack detection api. It also removes some other (now) useless stuff from the driver and corrects pin configuration for the codec. Signed-off-by: Marek Vasut Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index e6102fd..1f96e32 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -17,13 +17,12 @@ #include #include #include -#include -#include #include #include #include #include +#include #include #include @@ -33,90 +32,31 @@ #include "pxa2xx-pcm.h" #include "pxa2xx-ac97.h" -static int palm27x_jack_func = 1; -static int palm27x_spk_func = 1; -static int palm27x_ep_gpio = -1; +static struct snd_soc_jack hs_jack; -static void palm27x_ext_control(struct snd_soc_codec *codec) -{ - if (!palm27x_spk_func) - snd_soc_dapm_enable_pin(codec, "Speaker"); - else - snd_soc_dapm_disable_pin(codec, "Speaker"); - - if (!palm27x_jack_func) - snd_soc_dapm_enable_pin(codec, "Headphone Jack"); - else - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - - snd_soc_dapm_sync(codec); -} - -static int palm27x_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->socdev->card->codec; - - /* check the jack status at stream startup */ - palm27x_ext_control(codec); - return 0; -} - -static struct snd_soc_ops palm27x_ops = { - .startup = palm27x_startup, +/* Headphones jack detection DAPM pins */ +static struct snd_soc_jack_pin hs_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, }; -static irqreturn_t palm27x_interrupt(int irq, void *v) -{ - palm27x_spk_func = gpio_get_value(palm27x_ep_gpio); - palm27x_jack_func = !palm27x_spk_func; - return IRQ_HANDLED; -} - -static int palm27x_get_jack(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = palm27x_jack_func; - return 0; -} - -static int palm27x_set_jack(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - - if (palm27x_jack_func == ucontrol->value.integer.value[0]) - return 0; - - palm27x_jack_func = ucontrol->value.integer.value[0]; - palm27x_ext_control(codec); - return 1; -} - -static int palm27x_get_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = palm27x_spk_func; - return 0; -} - -static int palm27x_set_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - - if (palm27x_spk_func == ucontrol->value.integer.value[0]) - return 0; - - palm27x_spk_func = ucontrol->value.integer.value[0]; - palm27x_ext_control(codec); - return 1; -} +/* Headphones jack detection gpios */ +static struct snd_soc_jack_gpio hs_jack_gpios[] = { + [0] = { + /* gpio is set on per-platform basis */ + .name = "hp-gpio", + .report = SND_JACK_HEADPHONE, + .debounce_time = 200, + }, +}; -/* PalmTX machine dapm widgets */ +/* Palm27x machine dapm widgets */ static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_SPK("Ext. Speaker", NULL), + SND_SOC_DAPM_MIC("Ext. Microphone", NULL), }; /* PalmTX audio map */ @@ -126,46 +66,66 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Headphone Jack", NULL, "HPOUTR"}, /* ext speaker connected to ROUT2, LOUT2 */ - {"Speaker", NULL, "LOUT2"}, - {"Speaker", NULL, "ROUT2"}, -}; + {"Ext. Speaker", NULL, "LOUT2"}, + {"Ext. Speaker", NULL, "ROUT2"}, -static const char *jack_function[] = {"Headphone", "Off"}; -static const char *spk_function[] = {"On", "Off"}; -static const struct soc_enum palm27x_enum[] = { - SOC_ENUM_SINGLE_EXT(2, jack_function), - SOC_ENUM_SINGLE_EXT(2, spk_function), + /* mic connected to MIC1 */ + {"Ext. Microphone", NULL, "MIC1"}, }; -static const struct snd_kcontrol_new palm27x_controls[] = { - SOC_ENUM_EXT("Jack Function", palm27x_enum[0], palm27x_get_jack, - palm27x_set_jack), - SOC_ENUM_EXT("Speaker Function", palm27x_enum[1], palm27x_get_spk, - palm27x_set_spk), -}; +static struct snd_soc_card palm27x_asoc; static int palm27x_ac97_init(struct snd_soc_codec *codec) { int err; + /* add palm27x specific widgets */ + err = snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets, + ARRAY_SIZE(palm27x_dapm_widgets)); + if (err) + return err; + + /* set up palm27x specific audio path audio_map */ + err = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + if (err) + return err; + + /* connected pins */ + if (machine_is_palmld()) + snd_soc_dapm_enable_pin(codec, "MIC1"); + snd_soc_dapm_enable_pin(codec, "HPOUTL"); + snd_soc_dapm_enable_pin(codec, "HPOUTR"); + snd_soc_dapm_enable_pin(codec, "LOUT2"); + snd_soc_dapm_enable_pin(codec, "ROUT2"); + + /* not connected pins */ snd_soc_dapm_nc_pin(codec, "OUT3"); snd_soc_dapm_nc_pin(codec, "MONOOUT"); + snd_soc_dapm_nc_pin(codec, "LINEINL"); + snd_soc_dapm_nc_pin(codec, "LINEINR"); + snd_soc_dapm_nc_pin(codec, "PCBEEP"); + snd_soc_dapm_nc_pin(codec, "PHONE"); + snd_soc_dapm_nc_pin(codec, "MIC2"); + + err = snd_soc_dapm_sync(codec); + if (err) + return err; - /* add palm27x specific controls */ - err = snd_soc_add_controls(codec, palm27x_controls, - ARRAY_SIZE(palm27x_controls)); - if (err < 0) + /* Jack detection API stuff */ + err = snd_soc_jack_new(&palm27x_asoc, "Headphone Jack", + SND_JACK_HEADPHONE, &hs_jack); + if (err) return err; - /* add palm27x specific widgets */ - snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets, - ARRAY_SIZE(palm27x_dapm_widgets)); + err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), + hs_jack_pins); + if (err) + return err; - /* set up palm27x specific audio path audio_map */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + err = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), + hs_jack_gpios); - snd_soc_dapm_sync(codec); - return 0; + return err; } static struct snd_soc_dai_link palm27x_dai[] = { @@ -175,14 +135,12 @@ static struct snd_soc_dai_link palm27x_dai[] = { .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], .init = palm27x_ac97_init, - .ops = &palm27x_ops, }, { .name = "AC97 Aux", .stream_name = "AC97 Aux", .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], - .ops = &palm27x_ops, }, }; @@ -208,27 +166,17 @@ static int palm27x_asoc_probe(struct platform_device *pdev) machine_is_palmld() || machine_is_palmte2())) return -ENODEV; - if (pdev->dev.platform_data) - palm27x_ep_gpio = ((struct palm27x_asoc_info *) - (pdev->dev.platform_data))->jack_gpio; - - ret = gpio_request(palm27x_ep_gpio, "Headphone Jack"); - if (ret) - return ret; - ret = gpio_direction_input(palm27x_ep_gpio); - if (ret) - goto err_alloc; + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "please supply platform_data\n"); + return -ENODEV; + } - if (request_irq(gpio_to_irq(palm27x_ep_gpio), palm27x_interrupt, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "Headphone jack", NULL)) - goto err_alloc; + hs_jack_gpios[0].gpio = ((struct palm27x_asoc_info *) + (pdev->dev.platform_data))->jack_gpio; palm27x_snd_device = platform_device_alloc("soc-audio", -1); - if (!palm27x_snd_device) { - ret = -ENOMEM; - goto err_dev; - } + if (!palm27x_snd_device) + return -ENOMEM; platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata); palm27x_snd_devdata.dev = &palm27x_snd_device->dev; @@ -241,18 +189,12 @@ static int palm27x_asoc_probe(struct platform_device *pdev) put_device: platform_device_put(palm27x_snd_device); -err_dev: - free_irq(gpio_to_irq(palm27x_ep_gpio), NULL); -err_alloc: - gpio_free(palm27x_ep_gpio); return ret; } static int __devexit palm27x_asoc_remove(struct platform_device *pdev) { - free_irq(gpio_to_irq(palm27x_ep_gpio), NULL); - gpio_free(palm27x_ep_gpio); platform_device_unregister(palm27x_snd_device); return 0; } -- cgit v0.10.2 From 99783e2cde6eccbd31efeb03a79f26bb5f239c36 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:54:43 +0200 Subject: mac80211: fix sparse warning ieee80211_testmode_cmd can very well be static. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 36f8f24..52928ad 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1293,7 +1293,7 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy) } #ifdef CONFIG_NL80211_TESTMODE -int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) +static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) { struct ieee80211_local *local = wiphy_priv(wiphy); -- cgit v0.10.2 From 0a2b8bb24d4eb67788edd71d1ef8aa86c2e17e0f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 13:46:22 +0200 Subject: mac80211: driver operation debugging This makes mac80211 use the event tracing framework to log all operations as given to the driver. This will need to be extended with more information, but as a start it should be good. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 182c9c5..19a4c66 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -206,3 +206,15 @@ config MAC80211_DEBUG_COUNTERS and show them in debugfs. If unsure, say N. + +config MAC80211_DRIVER_API_TRACER + bool "Driver API tracer" + depends on MAC80211_DEBUG_MENU + depends on EVENT_TRACING + help + Say Y here to make mac80211 register with the ftrace + framework for the driver API -- you can see which + driver methods it is calling then by looking at the + trace. + + If unsure, say N. diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 0e3ab88..91284a7 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -41,6 +41,9 @@ mac80211-$(CONFIG_MAC80211_MESH) += \ mac80211-$(CONFIG_PM) += pm.o +mac80211-$(CONFIG_MAC80211_DRIVER_API_TRACER) += driver-trace.o +CFLAGS_driver-trace.o := -I$(src) + # objects for PID algorithm rc80211_pid-y := rc80211_pid_algo.o rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index b13446a..4100c36 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -3,6 +3,7 @@ #include #include "ieee80211_i.h" +#include "driver-trace.h" static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb) { @@ -11,29 +12,37 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb) static inline int drv_start(struct ieee80211_local *local) { - return local->ops->start(&local->hw); + int ret = local->ops->start(&local->hw); + trace_drv_start(local, ret); + return ret; } static inline void drv_stop(struct ieee80211_local *local) { local->ops->stop(&local->hw); + trace_drv_stop(local); } static inline int drv_add_interface(struct ieee80211_local *local, struct ieee80211_if_init_conf *conf) { - return local->ops->add_interface(&local->hw, conf); + int ret = local->ops->add_interface(&local->hw, conf); + trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret); + return ret; } static inline void drv_remove_interface(struct ieee80211_local *local, struct ieee80211_if_init_conf *conf) { local->ops->remove_interface(&local->hw, conf); + trace_drv_remove_interface(local, conf->mac_addr, conf->vif); } static inline int drv_config(struct ieee80211_local *local, u32 changed) { - return local->ops->config(&local->hw, changed); + int ret = local->ops->config(&local->hw, changed); + trace_drv_config(local, changed, ret); + return ret; } static inline void drv_bss_info_changed(struct ieee80211_local *local, @@ -43,6 +52,7 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, { if (local->ops->bss_info_changed) local->ops->bss_info_changed(&local->hw, vif, info, changed); + trace_drv_bss_info_changed(local, vif, info, changed); } static inline void drv_configure_filter(struct ieee80211_local *local, @@ -53,14 +63,18 @@ static inline void drv_configure_filter(struct ieee80211_local *local, { local->ops->configure_filter(&local->hw, changed_flags, total_flags, mc_count, mc_list); + trace_drv_configure_filter(local, changed_flags, total_flags, + mc_count); } static inline int drv_set_tim(struct ieee80211_local *local, struct ieee80211_sta *sta, bool set) { + int ret = 0; if (local->ops->set_tim) - return local->ops->set_tim(&local->hw, sta, set); - return 0; + ret = local->ops->set_tim(&local->hw, sta, set); + trace_drv_set_tim(local, sta, set, ret); + return ret; } static inline int drv_set_key(struct ieee80211_local *local, @@ -68,7 +82,9 @@ static inline int drv_set_key(struct ieee80211_local *local, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - return local->ops->set_key(&local->hw, cmd, vif, sta, key); + int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key); + trace_drv_set_key(local, cmd, vif, sta, key, ret); + return ret; } static inline void drv_update_tkip_key(struct ieee80211_local *local, @@ -79,32 +95,41 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, if (local->ops->update_tkip_key) local->ops->update_tkip_key(&local->hw, conf, address, iv32, phase1key); + trace_drv_update_tkip_key(local, conf, address, iv32); } static inline int drv_hw_scan(struct ieee80211_local *local, struct cfg80211_scan_request *req) { - return local->ops->hw_scan(&local->hw, req); + int ret = local->ops->hw_scan(&local->hw, req); + trace_drv_hw_scan(local, req, ret); + return ret; } static inline void drv_sw_scan_start(struct ieee80211_local *local) { if (local->ops->sw_scan_start) local->ops->sw_scan_start(&local->hw); + trace_drv_sw_scan_start(local); } static inline void drv_sw_scan_complete(struct ieee80211_local *local) { if (local->ops->sw_scan_complete) local->ops->sw_scan_complete(&local->hw); + trace_drv_sw_scan_complete(local); } static inline int drv_get_stats(struct ieee80211_local *local, struct ieee80211_low_level_stats *stats) { - if (!local->ops->get_stats) - return -EOPNOTSUPP; - return local->ops->get_stats(&local->hw, stats); + int ret = -EOPNOTSUPP; + + if (local->ops->get_stats) + ret = local->ops->get_stats(&local->hw, stats); + trace_drv_get_stats(local, stats, ret); + + return ret; } static inline void drv_get_tkip_seq(struct ieee80211_local *local, @@ -112,14 +137,17 @@ static inline void drv_get_tkip_seq(struct ieee80211_local *local, { if (local->ops->get_tkip_seq) local->ops->get_tkip_seq(&local->hw, hw_key_idx, iv32, iv16); + trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16); } static inline int drv_set_rts_threshold(struct ieee80211_local *local, u32 value) { + int ret = 0; if (local->ops->set_rts_threshold) - return local->ops->set_rts_threshold(&local->hw, value); - return 0; + ret = local->ops->set_rts_threshold(&local->hw, value); + trace_drv_set_rts_threshold(local, value, ret); + return ret; } static inline void drv_sta_notify(struct ieee80211_local *local, @@ -129,46 +157,57 @@ static inline void drv_sta_notify(struct ieee80211_local *local, { if (local->ops->sta_notify) local->ops->sta_notify(&local->hw, vif, cmd, sta); + trace_drv_sta_notify(local, vif, cmd, sta); } static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, const struct ieee80211_tx_queue_params *params) { + int ret = -EOPNOTSUPP; if (local->ops->conf_tx) - return local->ops->conf_tx(&local->hw, queue, params); - return -EOPNOTSUPP; + ret = local->ops->conf_tx(&local->hw, queue, params); + trace_drv_conf_tx(local, queue, params, ret); + return ret; } static inline int drv_get_tx_stats(struct ieee80211_local *local, struct ieee80211_tx_queue_stats *stats) { - return local->ops->get_tx_stats(&local->hw, stats); + int ret = local->ops->get_tx_stats(&local->hw, stats); + trace_drv_get_tx_stats(local, stats, ret); + return ret; } static inline u64 drv_get_tsf(struct ieee80211_local *local) { + u64 ret = -1ULL; if (local->ops->get_tsf) - return local->ops->get_tsf(&local->hw); - return -1ULL; + ret = local->ops->get_tsf(&local->hw); + trace_drv_get_tsf(local, ret); + return ret; } static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) { if (local->ops->set_tsf) local->ops->set_tsf(&local->hw, tsf); + trace_drv_set_tsf(local, tsf); } static inline void drv_reset_tsf(struct ieee80211_local *local) { if (local->ops->reset_tsf) local->ops->reset_tsf(&local->hw); + trace_drv_reset_tsf(local); } static inline int drv_tx_last_beacon(struct ieee80211_local *local) { + int ret = 1; if (local->ops->tx_last_beacon) - return local->ops->tx_last_beacon(&local->hw); - return 1; + ret = local->ops->tx_last_beacon(&local->hw); + trace_drv_tx_last_beacon(local, ret); + return ret; } static inline int drv_ampdu_action(struct ieee80211_local *local, @@ -176,10 +215,12 @@ static inline int drv_ampdu_action(struct ieee80211_local *local, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { + int ret = -EOPNOTSUPP; if (local->ops->ampdu_action) - return local->ops->ampdu_action(&local->hw, action, - sta, tid, ssn); - return -EOPNOTSUPP; + ret = local->ops->ampdu_action(&local->hw, action, + sta, tid, ssn); + trace_drv_ampdu_action(local, action, sta, tid, ssn, ret); + return ret; } diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c new file mode 100644 index 0000000..6da6f79 --- /dev/null +++ b/net/mac80211/driver-trace.c @@ -0,0 +1,6 @@ +/* bug in tracepoint.h, it should include this */ +#include + +#include "driver-ops.h" +#define CREATE_TRACE_POINTS +#include "driver-trace.h" diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h new file mode 100644 index 0000000..48c93d1 --- /dev/null +++ b/net/mac80211/driver-trace.h @@ -0,0 +1,648 @@ +#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define __MAC80211_DRIVER_TRACE + +#include +#include +#include "ieee80211_i.h" + +#ifndef CONFIG_MAC80211_DRIVER_API_TRACER +#undef TRACE_EVENT +#define TRACE_EVENT(name, proto, ...) \ +static inline void trace_ ## name(proto) {} +#endif + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mac80211 + +#define MAXNAME 32 +#define LOCAL_ENTRY __array(char, wiphy_name, 32) +#define LOCAL_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(local->hw.wiphy), MAXNAME) +#define LOCAL_PR_FMT "%s" +#define LOCAL_PR_ARG __entry->wiphy_name + +#define STA_ENTRY __array(char, sta_addr, ETH_ALEN) +#define STA_ASSIGN (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN)) +#define STA_PR_FMT " sta:%pM" +#define STA_PR_ARG __entry->sta_addr + +#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, vif) +#define VIF_ASSIGN __entry->vif_type = vif ? vif->type : 0; __entry->vif = vif +#define VIF_PR_FMT " vif:%p(%d)" +#define VIF_PR_ARG __entry->vif, __entry->vif_type + +TRACE_EVENT(drv_start, + TP_PROTO(struct ieee80211_local *local, int ret), + + TP_ARGS(local, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_stop, + TP_PROTO(struct ieee80211_local *local), + + TP_ARGS(local), + + TP_STRUCT__entry( + LOCAL_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_add_interface, + TP_PROTO(struct ieee80211_local *local, + const u8 *addr, + struct ieee80211_vif *vif, + int ret), + + TP_ARGS(local, addr, vif, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __array(char, addr, 6) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + memcpy(__entry->addr, addr, 6); + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " addr:%pM ret:%d", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr, __entry->ret + ) +); + +TRACE_EVENT(drv_remove_interface, + TP_PROTO(struct ieee80211_local *local, + const u8 *addr, struct ieee80211_vif *vif), + + TP_ARGS(local, addr, vif), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __array(char, addr, 6) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + memcpy(__entry->addr, addr, 6); + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr + ) +); + +TRACE_EVENT(drv_config, + TP_PROTO(struct ieee80211_local *local, + u32 changed, + int ret), + + TP_ARGS(local, changed, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u32, changed) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->changed = changed; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " ch:%#x ret:%d", + LOCAL_PR_ARG, __entry->changed, __entry->ret + ) +); + +TRACE_EVENT(drv_bss_info_changed, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed), + + TP_ARGS(local, vif, info, changed), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(bool, assoc) + __field(u16, aid) + __field(bool, cts) + __field(bool, shortpre) + __field(bool, shortslot) + __field(u8, dtimper) + __field(u16, bcnint) + __field(u16, assoc_cap) + __field(u64, timestamp) + __field(u32, basic_rates) + __field(u32, changed) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->changed = changed; + __entry->aid = info->aid; + __entry->assoc = info->assoc; + __entry->shortpre = info->use_short_preamble; + __entry->cts = info->use_cts_prot; + __entry->shortslot = info->use_short_slot; + __entry->dtimper = info->dtim_period; + __entry->bcnint = info->beacon_int; + __entry->assoc_cap = info->assoc_capability; + __entry->timestamp = info->timestamp; + __entry->basic_rates = info->basic_rates; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " changed:%#x", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed + ) +); + +TRACE_EVENT(drv_configure_filter, + TP_PROTO(struct ieee80211_local *local, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count), + + TP_ARGS(local, changed_flags, total_flags, mc_count), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(unsigned int, changed) + __field(unsigned int, total) + __field(int, mc) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->changed = changed_flags; + __entry->total = *total_flags; + __entry->mc = mc_count; + ), + + TP_printk( + LOCAL_PR_FMT " changed:%#x total:%#x mc:%d", + LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc + ) +); + +TRACE_EVENT(drv_set_tim, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sta *sta, bool set, int ret), + + TP_ARGS(local, sta, set, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + STA_ENTRY + __field(bool, set) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + STA_ASSIGN; + __entry->set = set; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT STA_PR_FMT " set:%d ret:%d", + LOCAL_PR_ARG, STA_PR_FMT, __entry->set, __entry->ret + ) +); + +TRACE_EVENT(drv_set_key, + TP_PROTO(struct ieee80211_local *local, + enum set_key_cmd cmd, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, int ret), + + TP_ARGS(local, cmd, vif, sta, key, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + STA_ENTRY + __field(enum ieee80211_key_alg, alg) + __field(u8, hw_key_idx) + __field(u8, flags) + __field(s8, keyidx) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + STA_ASSIGN; + __entry->alg = key->alg; + __entry->flags = key->flags; + __entry->keyidx = key->keyidx; + __entry->hw_key_idx = key->hw_key_idx; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ret:%d", + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret + ) +); + +TRACE_EVENT(drv_update_tkip_key, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_key_conf *conf, + const u8 *address, u32 iv32), + + TP_ARGS(local, conf, address, iv32), + + TP_STRUCT__entry( + LOCAL_ENTRY + __array(u8, addr, 6) + __field(u32, iv32) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + memcpy(__entry->addr, address, 6); + __entry->iv32 = iv32; + ), + + TP_printk( + LOCAL_PR_FMT " addr:%pM iv32:%#x", + LOCAL_PR_ARG, __entry->addr, __entry->iv32 + ) +); + +TRACE_EVENT(drv_hw_scan, + TP_PROTO(struct ieee80211_local *local, + struct cfg80211_scan_request *req, int ret), + + TP_ARGS(local, req, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " ret:%d", + LOCAL_PR_ARG, __entry->ret + ) +); + +TRACE_EVENT(drv_sw_scan_start, + TP_PROTO(struct ieee80211_local *local), + + TP_ARGS(local), + + TP_STRUCT__entry( + LOCAL_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_sw_scan_complete, + TP_PROTO(struct ieee80211_local *local), + + TP_ARGS(local), + + TP_STRUCT__entry( + LOCAL_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_get_stats, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_low_level_stats *stats, + int ret), + + TP_ARGS(local, stats, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, ret) + __field(unsigned int, ackfail) + __field(unsigned int, rtsfail) + __field(unsigned int, fcserr) + __field(unsigned int, rtssucc) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + __entry->ackfail = stats->dot11ACKFailureCount; + __entry->rtsfail = stats->dot11RTSFailureCount; + __entry->fcserr = stats->dot11FCSErrorCount; + __entry->rtssucc = stats->dot11RTSSuccessCount; + ), + + TP_printk( + LOCAL_PR_FMT " ret:%d", + LOCAL_PR_ARG, __entry->ret + ) +); + +TRACE_EVENT(drv_get_tkip_seq, + TP_PROTO(struct ieee80211_local *local, + u8 hw_key_idx, u32 *iv32, u16 *iv16), + + TP_ARGS(local, hw_key_idx, iv32, iv16), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u8, hw_key_idx) + __field(u32, iv32) + __field(u16, iv16) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->hw_key_idx = hw_key_idx; + __entry->iv32 = *iv32; + __entry->iv16 = *iv16; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_set_rts_threshold, + TP_PROTO(struct ieee80211_local *local, u32 value, int ret), + + TP_ARGS(local, value, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u32, value) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + __entry->value = value; + ), + + TP_printk( + LOCAL_PR_FMT " value:%d ret:%d", + LOCAL_PR_ARG, __entry->value, __entry->ret + ) +); + +TRACE_EVENT(drv_sta_notify, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta), + + TP_ARGS(local, vif, cmd, sta), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + STA_ENTRY + __field(u32, cmd) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + STA_ASSIGN; + __entry->cmd = cmd; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " cmd:%d", + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->cmd + ) +); + +TRACE_EVENT(drv_conf_tx, + TP_PROTO(struct ieee80211_local *local, u16 queue, + const struct ieee80211_tx_queue_params *params, + int ret), + + TP_ARGS(local, queue, params, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u16, queue) + __field(u16, txop) + __field(u16, cw_min) + __field(u16, cw_max) + __field(u8, aifs) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->queue = queue; + __entry->ret = ret; + __entry->txop = params->txop; + __entry->cw_max = params->cw_max; + __entry->cw_min = params->cw_min; + __entry->aifs = params->aifs; + ), + + TP_printk( + LOCAL_PR_FMT " queue:%d ret:%d", + LOCAL_PR_ARG, __entry->queue, __entry->ret + ) +); + +TRACE_EVENT(drv_get_tx_stats, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_tx_queue_stats *stats, + int ret), + + TP_ARGS(local, stats, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " ret:%d", + LOCAL_PR_ARG, __entry->ret + ) +); + +TRACE_EVENT(drv_get_tsf, + TP_PROTO(struct ieee80211_local *local, u64 ret), + + TP_ARGS(local, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u64, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " ret:%llu", + LOCAL_PR_ARG, (unsigned long long)__entry->ret + ) +); + +TRACE_EVENT(drv_set_tsf, + TP_PROTO(struct ieee80211_local *local, u64 tsf), + + TP_ARGS(local, tsf), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u64, tsf) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->tsf = tsf; + ), + + TP_printk( + LOCAL_PR_FMT " tsf:%llu", + LOCAL_PR_ARG, (unsigned long long)__entry->tsf + ) +); + +TRACE_EVENT(drv_reset_tsf, + TP_PROTO(struct ieee80211_local *local), + + TP_ARGS(local), + + TP_STRUCT__entry( + LOCAL_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_tx_last_beacon, + TP_PROTO(struct ieee80211_local *local, int ret), + + TP_ARGS(local, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " ret:%d", + LOCAL_PR_ARG, __entry->ret + ) +); + +TRACE_EVENT(drv_ampdu_action, + TP_PROTO(struct ieee80211_local *local, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, + u16 *ssn, int ret), + + TP_ARGS(local, action, sta, tid, ssn, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + STA_ENTRY + __field(u32, action) + __field(u16, tid) + __field(u16, ssn) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + STA_ASSIGN; + __entry->ret = ret; + __entry->action = action; + __entry->tid = tid; + __entry->ssn = *ssn; + ), + + TP_printk( + LOCAL_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d", + LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret + ) +); +#endif /* __MAC80211_DRIVER_TRACE */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE driver-trace +#include -- cgit v0.10.2 From e0f114e82e3781087a0ad0e92c94ff0d55012c1a Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 7 Jul 2009 19:08:07 +0200 Subject: p54: re-enable power save feature This patch re-enables p54's power save features and adds a workaround which temporarily alters the device's power state in order to allow ps-polls to be sent and buffered data to be retrieved during psm. (Incorporates patch originally posted as "p54: fix beacon template dtim IE corruption". -- JWL) Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index dc4f3f5..349375f 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -585,7 +585,8 @@ int p54_set_ps(struct p54_common *priv) unsigned int i; u16 mode; - if (priv->hw->conf.flags & IEEE80211_CONF_PS) + if (priv->hw->conf.flags & IEEE80211_CONF_PS && + !priv->powersave_override) mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM | P54_PSM_CHECKSUM | P54_PSM_MCBC; else @@ -607,8 +608,8 @@ int p54_set_ps(struct p54_common *priv) psm->beacon_rssi_skip_max = 200; psm->rssi_delta_threshold = 0; - psm->nr = 10; - psm->exclude[0] = 0; + psm->nr = 1; + psm->exclude[0] = WLAN_EID_TIM; p54_tx(priv, skb); return 0; diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h index 0496cff..af35cfc 100644 --- a/drivers/net/wireless/p54/lmac.h +++ b/drivers/net/wireless/p54/lmac.h @@ -548,4 +548,7 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot, int p54_download_eeprom(struct p54_common *priv, void *buf, u16 offset, u16 len); +/* utility */ +u8 *p54_find_ie(struct sk_buff *skb, u8 ie); + #endif /* LMAC_H */ diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index f9b4f6a..c9a0545 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -65,51 +65,64 @@ static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, return p54_update_beacon_tim(priv, sta->aid, set); } -static int p54_beacon_format_ie_tim(struct sk_buff *skb) +u8 *p54_find_ie(struct sk_buff *skb, u8 ie) { - /* - * the good excuse for this mess is ... the firmware. - * The dummy TIM MUST be at the end of the beacon frame, - * because it'll be overwritten! - */ - struct ieee80211_mgmt *mgmt = (void *)skb->data; u8 *pos, *end; if (skb->len <= sizeof(mgmt)) - return -EINVAL; + return NULL; pos = (u8 *)mgmt->u.beacon.variable; end = skb->data + skb->len; while (pos < end) { if (pos + 2 + pos[1] > end) - return -EINVAL; + return NULL; - if (pos[0] == WLAN_EID_TIM) { - u8 dtim_len = pos[1]; - u8 dtim_period = pos[3]; - u8 *next = pos + 2 + dtim_len; + if (pos[0] == ie) + return pos; - if (dtim_len < 3) - return -EINVAL; + pos += 2 + pos[1]; + } + return NULL; +} - memmove(pos, next, end - next); +static int p54_beacon_format_ie_tim(struct sk_buff *skb) +{ + /* + * the good excuse for this mess is ... the firmware. + * The dummy TIM MUST be at the end of the beacon frame, + * because it'll be overwritten! + */ + u8 *tim; + u8 dtim_len; + u8 dtim_period; + u8 *next; - if (dtim_len > 3) - skb_trim(skb, skb->len - (dtim_len - 3)); + tim = p54_find_ie(skb, WLAN_EID_TIM); + if (!tim) + return 0; - pos = end - (dtim_len + 2); + dtim_len = tim[1]; + dtim_period = tim[3]; + next = tim + 2 + dtim_len; + + if (dtim_len < 3) + return -EINVAL; + + memmove(tim, next, skb_tail_pointer(skb) - next); + tim = skb_tail_pointer(skb) - (dtim_len + 2); + + /* add the dummy at the end */ + tim[0] = WLAN_EID_TIM; + tim[1] = 3; + tim[2] = 0; + tim[3] = dtim_period; + tim[4] = 0; + + if (dtim_len > 3) + skb_trim(skb, skb->len - (dtim_len - 3)); - /* add the dummy at the end */ - pos[0] = WLAN_EID_TIM; - pos[1] = 3; - pos[2] = 0; - pos[3] = dtim_period; - pos[4] = 0; - return 0; - } - pos += 2 + pos[1]; - } return 0; } @@ -384,6 +397,9 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, priv->wakeup_timer = info->beacon_int * info->dtim_period * 5; p54_setup_mac(priv); + } else { + priv->wakeup_timer = 500; + priv->aid = 0; } } @@ -517,6 +533,9 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) skb_queue_head_init(&priv->tx_pending); dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_NOISE_DBM; dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 19d085c..6772ed5 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -208,6 +208,7 @@ struct p54_common { u32 tsf_low32, tsf_high32; u32 basic_rate_mask; u16 aid; + bool powersave_override; __le32 beacon_req_id; /* cryptographic engine information */ diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 6426d2ca..01eadb1 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -288,6 +288,45 @@ static int p54_rssi_to_dbm(struct p54_common *priv, int rssi) priv->rssical_db[band].add) / 4; } +/* + * Even if the firmware is capable of dealing with incoming traffic, + * while dozing, we have to prepared in case mac80211 uses PS-POLL + * to retrieve outstanding frames from our AP. + * (see comment in net/mac80211/mlme.c @ line 1993) + */ +static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (void *) skb->data; + struct ieee80211_tim_ie *tim_ie; + u8 *tim; + u8 tim_len; + bool new_psm; + + /* only beacons have a TIM IE */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + if (!priv->aid) + return; + + /* only consider beacons from the associated BSSID */ + if (compare_ether_addr(hdr->addr3, priv->bssid)) + return; + + tim = p54_find_ie(skb, WLAN_EID_TIM); + if (!tim) + return; + + tim_len = tim[1]; + tim_ie = (struct ieee80211_tim_ie *) &tim[2]; + + new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid); + if (new_psm != priv->powersave_override) { + priv->powersave_override = new_psm; + p54_set_ps(priv); + } +} + static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb) { struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; @@ -340,6 +379,9 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb) skb_pull(skb, header_len); skb_trim(skb, le16_to_cpu(hdr->len)); + if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS)) + p54_pspoll_workaround(priv, skb); + ieee80211_rx_irqsafe(priv->hw, skb); queue_delayed_work(priv->hw->workqueue, &priv->work, -- cgit v0.10.2 From a71d62dbf3f0523b7a456333196cb26cf783fe92 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 23:41:27 +0200 Subject: cfg80211: fix race in giwrate cfg80211_wext_giwrate doesn't lock the wdev, so it cannot access current_bss race-free. Also, there's little point in trying to ask the driver for an AP that it never told us about, so avoid that case. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 9d101d5..5088d89 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1127,7 +1127,7 @@ int cfg80211_wext_giwrate(struct net_device *dev, struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); /* we are under RTNL - globally locked - so can use a static struct */ static struct station_info sinfo; - u8 *addr; + u8 addr[ETH_ALEN]; int err; if (wdev->iftype != NL80211_IFTYPE_STATION) @@ -1136,12 +1136,15 @@ int cfg80211_wext_giwrate(struct net_device *dev, if (!rdev->ops->get_station) return -EOPNOTSUPP; + err = 0; + wdev_lock(wdev); if (wdev->current_bss) - addr = wdev->current_bss->pub.bssid; - else if (wdev->wext.connect.bssid) - addr = wdev->wext.connect.bssid; + memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN); else - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + wdev_unlock(wdev); + if (err) + return err; err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo); if (err) -- cgit v0.10.2 From 4bde0f7d1dca0a7d886997eb8dee3fb47a6484e4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 23:46:51 +0200 Subject: cfg80211: fix two buglets This fixes two small bugs: 1) the connect variable is already initialised, and the assignment to auth_type overwrites the previous setting with a wrong value 2) when all authentication attempts fail, we need to report that we couldn't connect Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4478760..a00fd64 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3680,10 +3680,6 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) wiphy = &rdev->wiphy; - connect.bssid = NULL; - connect.channel = NULL; - connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; - if (info->attrs[NL80211_ATTR_MAC]) connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index df9173f..79ca56c 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -295,9 +295,8 @@ void cfg80211_sme_rx_auth(struct net_device *dev, wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; schedule_work(&rdev->conn_work); } else if (status_code != WLAN_STATUS_SUCCESS) { - wdev->sme_state = CFG80211_SME_IDLE; - kfree(wdev->conn); - wdev->conn = NULL; + __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, + status_code, false); } else if (wdev->sme_state == CFG80211_SME_CONNECTING && wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; -- cgit v0.10.2 From 10c836d7896e9d7b683a76f3cac3c289d8da72ef Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 9 Jul 2009 14:42:16 -0700 Subject: mac80211: Assign next hop address to pending mesh frames Assign next hop address to pending mesh frames once the path is resolved. Regression. Frames transmitted when a mesh path was wating to be resolved were being transmitted with an invalid Receiver Address. [Changes since v1] Suggested by Johannes: - Improved frame_queue traversal - Narower RCU scope Signed-off-by: Javier Cardona Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 479597e..f0304bf 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -55,7 +55,25 @@ static DEFINE_RWLOCK(pathtbl_resize_lock); */ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) { + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + struct sk_buff_head tmpq; + unsigned long flags; + rcu_assign_pointer(mpath->next_hop, sta); + + __skb_queue_head_init(&tmpq); + + spin_lock_irqsave(&mpath->frame_queue.lock, flags); + + while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) { + hdr = (struct ieee80211_hdr *) skb->data; + memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); + __skb_queue_tail(&tmpq, skb); + } + + skb_queue_splice(&tmpq, &mpath->frame_queue); + spin_unlock_irqrestore(&mpath->frame_queue.lock, flags); } -- cgit v0.10.2 From b9454e83cac42fcdc90bfbfba479132bd6629455 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 8 Jul 2009 13:29:08 +0200 Subject: nl80211: introduce new key attributes We will soon want to nest key attributes into some new attribute for configuring static WEP keys at connect() and ibss_join() time, so we need nested attributes for that. However, key attributes right now are 'global'. This patch thus introduces new nested attributes for the key settings and functions for parsing them. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index e496a2d..48e0913 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -567,6 +567,9 @@ enum nl80211_commands { * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE * commands to specify using a reassociate frame * + * @NL80211_ATTR_KEY: key information in a nested attribute with + * %NL80211_KEY_* sub-attributes + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -692,6 +695,8 @@ enum nl80211_attrs { NL80211_ATTR_PREV_BSSID, + NL80211_ATTR_KEY, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -720,6 +725,7 @@ enum nl80211_attrs { #define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP #define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES +#define NL80211_ATTR_KEY NL80211_ATTR_KEY #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_REG_RULES 32 @@ -1320,4 +1326,34 @@ enum nl80211_wpa_versions { NL80211_WPA_VERSION_2 = 1 << 1, }; +/** + * enum nl80211_key_attributes - key attributes + * @__NL80211_KEY_INVALID: invalid + * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of + * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC + * keys + * @NL80211_KEY_IDX: key ID (u8, 0-3) + * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 + * section 7.3.2.25.1, e.g. 0x000FAC04) + * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and + * CCMP keys, each six bytes in little endian + * @NL80211_KEY_DEFAULT: flag indicating default key + * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key + * @__NL80211_KEY_AFTER_LAST: internal + * @NL80211_KEY_MAX: highest key attribute + */ +enum nl80211_key_attributes { + __NL80211_KEY_INVALID, + NL80211_KEY_DATA, + NL80211_KEY_IDX, + NL80211_KEY_CIPHER, + NL80211_KEY_SEQ, + NL80211_KEY_DEFAULT, + NL80211_KEY_DEFAULT_MGMT, + + /* keep last */ + __NL80211_KEY_AFTER_LAST, + NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a00fd64..50cf593 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -73,6 +73,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, + [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, @@ -134,6 +135,18 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, }; +/* policy for the attributes */ +static struct nla_policy +nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = { + [NL80211_KEY_DATA] = { .type = NLA_BINARY, + .len = WLAN_MAX_KEY_LEN }, + [NL80211_KEY_IDX] = { .type = NLA_U8 }, + [NL80211_KEY_CIPHER] = { .type = NLA_U32 }, + [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, + [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, + [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, +}; + /* IE validation */ static bool is_valid_ie_attr(const struct nlattr *attr) { @@ -198,6 +211,100 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, /* netlink command implementations */ +struct key_parse { + struct key_params p; + int idx; + bool def, defmgmt; +}; + +static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) +{ + struct nlattr *tb[NL80211_KEY_MAX + 1]; + int err = nla_parse_nested(tb, NL80211_KEY_MAX, key, + nl80211_key_policy); + if (err) + return err; + + k->def = !!tb[NL80211_KEY_DEFAULT]; + k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT]; + + if (tb[NL80211_KEY_IDX]) + k->idx = nla_get_u8(tb[NL80211_KEY_IDX]); + + if (tb[NL80211_KEY_DATA]) { + k->p.key = nla_data(tb[NL80211_KEY_DATA]); + k->p.key_len = nla_len(tb[NL80211_KEY_DATA]); + } + + if (tb[NL80211_KEY_SEQ]) { + k->p.seq = nla_data(tb[NL80211_KEY_SEQ]); + k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]); + } + + if (tb[NL80211_KEY_CIPHER]) + k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); + + return 0; +} + +static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) +{ + if (info->attrs[NL80211_ATTR_KEY_DATA]) { + k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]); + k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); + } + + if (info->attrs[NL80211_ATTR_KEY_SEQ]) { + k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]); + k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]); + } + + if (info->attrs[NL80211_ATTR_KEY_IDX]) + k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); + + if (info->attrs[NL80211_ATTR_KEY_CIPHER]) + k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]); + + k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; + k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; + + return 0; +} + +static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) +{ + int err; + + memset(k, 0, sizeof(*k)); + k->idx = -1; + + if (info->attrs[NL80211_ATTR_KEY]) + err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); + else + err = nl80211_parse_key_old(info, k); + + if (err) + return err; + + if (k->def && k->defmgmt) + return -EINVAL; + + if (k->idx != -1) { + if (k->defmgmt) { + if (k->idx < 4 || k->idx > 5) + return -EINVAL; + } else if (k->def) { + if (k->idx < 0 || k->idx > 3) + return -EINVAL; + } else { + if (k->idx < 0 || k->idx > 5) + return -EINVAL; + } + } + + return 0; +} + static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct cfg80211_registered_device *dev) { @@ -943,10 +1050,12 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) struct get_key_cookie { struct sk_buff *msg; int error; + int idx; }; static void get_key_callback(void *c, struct key_params *params) { + struct nlattr *key; struct get_key_cookie *cookie = c; if (params->key) @@ -961,6 +1070,26 @@ static void get_key_callback(void *c, struct key_params *params) NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER, params->cipher); + key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY); + if (!key) + goto nla_put_failure; + + if (params->key) + NLA_PUT(cookie->msg, NL80211_KEY_DATA, + params->key_len, params->key); + + if (params->seq) + NLA_PUT(cookie->msg, NL80211_KEY_SEQ, + params->seq_len, params->seq); + + if (params->cipher) + NLA_PUT_U32(cookie->msg, NL80211_KEY_CIPHER, + params->cipher); + + NLA_PUT_U8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx); + + nla_nest_end(cookie->msg, key); + return; nla_put_failure: cookie->error = 1; @@ -1014,6 +1143,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) } cookie.msg = msg; + cookie.idx = key_idx; NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); @@ -1049,26 +1179,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; + struct key_parse key; int err; struct net_device *dev; - u8 key_idx; int (*func)(struct wiphy *wiphy, struct net_device *netdev, u8 key_index); - if (!info->attrs[NL80211_ATTR_KEY_IDX]) - return -EINVAL; - - key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); + err = nl80211_parse_key(info, &key); + if (err) + return err; - if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) { - if (key_idx < 4 || key_idx > 5) - return -EINVAL; - } else if (key_idx > 3) + if (key.idx < 0) return -EINVAL; - /* currently only support setting default key */ - if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] && - !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) + /* only support setting default key */ + if (!key.def && !key.defmgmt) return -EINVAL; rtnl_lock(); @@ -1077,7 +1202,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) if (err) goto unlock_rtnl; - if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) + if (key.def) func = rdev->ops->set_default_key; else func = rdev->ops->set_default_mgmt_key; @@ -1087,13 +1212,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) goto out; } - err = func(&rdev->wiphy, dev, key_idx); + err = func(&rdev->wiphy, dev, key.idx); #ifdef CONFIG_WIRELESS_EXT if (!err) { if (func == rdev->ops->set_default_key) - dev->ieee80211_ptr->wext.default_key = key_idx; + dev->ieee80211_ptr->wext.default_key = key.idx; else - dev->ieee80211_ptr->wext.default_mgmt_key = key_idx; + dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; } #endif @@ -1112,34 +1237,20 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev; int err, i; struct net_device *dev; - struct key_params params; - u8 key_idx = 0; + struct key_parse key; u8 *mac_addr = NULL; - memset(¶ms, 0, sizeof(params)); + err = nl80211_parse_key(info, &key); + if (err) + return err; - if (!info->attrs[NL80211_ATTR_KEY_CIPHER]) + if (!key.p.key) return -EINVAL; - if (info->attrs[NL80211_ATTR_KEY_DATA]) { - params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]); - params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); - } - - if (info->attrs[NL80211_ATTR_KEY_SEQ]) { - params.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]); - params.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]); - } - - if (info->attrs[NL80211_ATTR_KEY_IDX]) - key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); - - params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]); - if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (cfg80211_validate_key_settings(¶ms, key_idx, mac_addr)) + if (cfg80211_validate_key_settings(&key.p, key.idx, mac_addr)) return -EINVAL; rtnl_lock(); @@ -1149,7 +1260,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) goto unlock_rtnl; for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) - if (params.cipher == rdev->wiphy.cipher_suites[i]) + if (key.p.cipher == rdev->wiphy.cipher_suites[i]) break; if (i == rdev->wiphy.n_cipher_suites) { err = -EINVAL; @@ -1161,7 +1272,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) goto out; } - err = rdev->ops->add_key(&rdev->wiphy, dev, key_idx, mac_addr, ¶ms); + err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, mac_addr, &key.p); out: cfg80211_unlock_rdev(rdev); @@ -1177,14 +1288,12 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev; int err; struct net_device *dev; - u8 key_idx = 0; u8 *mac_addr = NULL; + struct key_parse key; - if (info->attrs[NL80211_ATTR_KEY_IDX]) - key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); - - if (key_idx > 5) - return -EINVAL; + err = nl80211_parse_key(info, &key); + if (err) + return err; if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); @@ -1200,13 +1309,13 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) goto out; } - err = rdev->ops->del_key(&rdev->wiphy, dev, key_idx, mac_addr); + err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); #ifdef CONFIG_WIRELESS_EXT if (!err) { - if (key_idx == dev->ieee80211_ptr->wext.default_key) + if (key.idx == dev->ieee80211_ptr->wext.default_key) dev->ieee80211_ptr->wext.default_key = -1; - else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key) + else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key) dev->ieee80211_ptr->wext.default_mgmt_key = -1; } #endif -- cgit v0.10.2 From fffd0934b9390f34bec45762192b7edd3b12b4b5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 8 Jul 2009 14:22:54 +0200 Subject: cfg80211: rework key operation This reworks the key operation in cfg80211, and now only allows, from userspace, configuring keys (via nl80211) after the connection has been established (in managed mode), the IBSS been joined (in IBSS mode), at any time (in AP[_VLAN] modes) or never for all the other modes. In order to do shared key authentication correctly, it is now possible to give a WEP key to the AUTH command. To configure static WEP keys, these are given to the CONNECT or IBSS_JOIN command directly, for a userspace SME it is assumed it will configure it properly after the connection has been established. Since mac80211 used to check the default key in IBSS mode to see whether or not the network is protected, it needs an update in that area, as well as an update to make use of the WEP key passed to auth() for shared key authentication. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 48e0913..b043b78 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -569,6 +569,9 @@ enum nl80211_commands { * * @NL80211_ATTR_KEY: key information in a nested attribute with * %NL80211_KEY_* sub-attributes + * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect() + * and join_ibss(), key information is in a nested attribute each + * with %NL80211_KEY_* sub-attributes * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -696,6 +699,7 @@ enum nl80211_attrs { NL80211_ATTR_PREV_BSSID, NL80211_ATTR_KEY, + NL80211_ATTR_KEYS, /* add attributes here, update the policy in nl80211.c */ @@ -726,6 +730,7 @@ enum nl80211_attrs { #define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES #define NL80211_ATTR_KEY NL80211_ATTR_KEY +#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_REG_RULES 32 diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 83c2c72..65a5cbc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -647,12 +647,17 @@ struct cfg80211_crypto_settings { * @auth_type: Authentication type (algorithm) * @ie: Extra IEs to add to Authentication frame or %NULL * @ie_len: Length of ie buffer in octets + * @key_len: length of WEP key for shared key authentication + * @key_idx: index of WEP key for shared key authentication + * @key: WEP key for shared key authentication */ struct cfg80211_auth_request { struct cfg80211_bss *bss; const u8 *ie; size_t ie_len; enum nl80211_auth_type auth_type; + const u8 *key; + u8 key_len, key_idx; }; /** @@ -727,6 +732,8 @@ struct cfg80211_disassoc_request { * @ie: information element(s) to include in the beacon * @ie_len: length of that * @beacon_interval: beacon interval to use + * @privacy: this is a protected network, keys will be configured + * after joining */ struct cfg80211_ibss_params { u8 *ssid; @@ -736,6 +743,7 @@ struct cfg80211_ibss_params { u8 ssid_len, ie_len; u16 beacon_interval; bool channel_fixed; + bool privacy; }; /** @@ -755,6 +763,9 @@ struct cfg80211_ibss_params { * @assoc_ie_len: Length of assoc_ie in octets * @privacy: indicates whether privacy-enabled APs should be used * @crypto: crypto settings + * @key_len: length of WEP key for shared key authentication + * @key_idx: index of WEP key for shared key authentication + * @key: WEP key for shared key authentication */ struct cfg80211_connect_params { struct ieee80211_channel *channel; @@ -766,6 +777,8 @@ struct cfg80211_connect_params { size_t ie_len; bool privacy; struct cfg80211_crypto_settings crypto; + const u8 *key; + u8 key_len, key_idx; }; /** @@ -1223,9 +1236,10 @@ extern void wiphy_unregister(struct wiphy *wiphy); */ extern void wiphy_free(struct wiphy *wiphy); -/* internal struct */ +/* internal structs */ struct cfg80211_conn; struct cfg80211_internal_bss; +struct cfg80211_cached_keys; #define MAX_AUTH_BSSES 4 @@ -1267,6 +1281,7 @@ struct wireless_dev { CFG80211_SME_CONNECTED, } sme_state; struct cfg80211_conn *conn; + struct cfg80211_cached_keys *connect_keys; struct list_head event_list; spinlock_t event_lock; @@ -1280,6 +1295,7 @@ struct wireless_dev { struct { struct cfg80211_ibss_params ibss; struct cfg80211_connect_params connect; + struct cfg80211_cached_keys *keys; u8 *ie; size_t ie_len; u8 bssid[ETH_ALEN]; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 15d5a53..8e22200 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -57,7 +57,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, */ if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0, - sdata->u.ibss.bssid, 0); + sdata->u.ibss.bssid, NULL, 0, 0); } static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, @@ -494,7 +494,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) capability = WLAN_CAPABILITY_IBSS; - if (sdata->default_key) + if (ifibss->privacy) capability |= WLAN_CAPABILITY_PRIVACY; else sdata->drop_unencrypted = 0; @@ -524,9 +524,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) return; capability = WLAN_CAPABILITY_IBSS; - if (sdata->default_key) + if (ifibss->privacy) capability |= WLAN_CAPABILITY_PRIVACY; - if (ifibss->fixed_bssid) bssid = ifibss->bssid; if (ifibss->fixed_channel) @@ -872,6 +871,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, } else sdata->u.ibss.fixed_bssid = false; + sdata->u.ibss.privacy = params->privacy; + sdata->vif.bss_conf.beacon_int = params->beacon_interval; sdata->u.ibss.channel = params->channel; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 327aabc..06b3411 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -247,6 +247,9 @@ struct ieee80211_mgd_work { int tries; + u8 key[WLAN_KEY_LEN_WEP104]; + u8 key_len, key_idx; + /* must be last */ u8 ie[0]; /* for auth or assoc frame, not probe */ }; @@ -321,6 +324,7 @@ struct ieee80211_if_ibss { bool fixed_bssid; bool fixed_channel; + bool privacy; u8 bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; @@ -1093,8 +1097,8 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, - u8 *extra, size_t extra_len, - const u8 *bssid, int encrypt); + u8 *extra, size_t extra_len, const u8 *bssid, + const u8 *key, u8 key_len, u8 key_idx); int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, const u8 *ie, size_t ie_len); void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c9db964..8e4a604 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -954,7 +954,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, sdata->dev->name, wk->bss->cbss.bssid, wk->tries); ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, - wk->bss->cbss.bssid, 0); + wk->bss->cbss.bssid, NULL, 0, 0); wk->auth_transaction = 2; wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; @@ -1176,7 +1176,8 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, return; ieee80211_send_auth(sdata, 3, wk->auth_alg, elems.challenge - 2, elems.challenge_len + 2, - wk->bss->cbss.bssid, 1); + wk->bss->cbss.bssid, + wk->key, wk->key_len, wk->key_idx); wk->auth_transaction = 4; } @@ -2175,6 +2176,12 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, wk->ie_len = req->ie_len; } + if (req->key && req->key_len) { + wk->key_len = req->key_len; + wk->key_idx = req->key_idx; + memcpy(wk->key, req->key, req->key_len); + } + ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); memcpy(wk->ssid, ssid + 2, ssid[1]); wk->ssid_len = ssid[1]; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 915e777..dbf66b5 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -31,6 +31,7 @@ #include "mesh.h" #include "wme.h" #include "led.h" +#include "wep.h" /* privid for wiphys to determine whether they belong to us or not */ void *mac80211_wiphy_privid = &mac80211_wiphy_privid; @@ -804,12 +805,13 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, - u8 *extra, size_t extra_len, - const u8 *bssid, int encrypt) + u8 *extra, size_t extra_len, const u8 *bssid, + const u8 *key, u8 key_len, u8 key_idx) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; + int err; skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 6 + extra_len); @@ -824,8 +826,6 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, memset(mgmt, 0, 24 + 6); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); - if (encrypt) - mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); memcpy(mgmt->da, bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, bssid, ETH_ALEN); @@ -835,7 +835,13 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, if (extra) memcpy(skb_put(skb, extra_len), extra, extra_len); - ieee80211_tx_skb(sdata, skb, encrypt); + if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) { + mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx); + WARN_ON(err); + } + + ieee80211_tx_skb(sdata, skb, 0); } int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 4fafb2d..8a980f1 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -144,9 +144,9 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, * * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) */ -static int ieee80211_wep_encrypt(struct ieee80211_local *local, - struct sk_buff *skb, - const u8 *key, int keylen, int keyidx) +int ieee80211_wep_encrypt(struct ieee80211_local *local, + struct sk_buff *skb, + const u8 *key, int keylen, int keyidx) { u8 *iv; size_t len; diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 85219de..fe29d7e 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -20,6 +20,9 @@ int ieee80211_wep_init(struct ieee80211_local *local); void ieee80211_wep_free(struct ieee80211_local *local); void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); +int ieee80211_wep_encrypt(struct ieee80211_local *local, + struct sk_buff *skb, + const u8 *key, int keylen, int keyidx); int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); diff --git a/net/wireless/core.c b/net/wireless/core.c index 1a78b3c..97cc596 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -666,14 +666,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev_lock(wdev); switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: - if (wdev->wext.ibss.ssid_len) - __cfg80211_join_ibss(rdev, dev, - &wdev->wext.ibss); + cfg80211_ibss_wext_join(rdev, wdev); break; case NL80211_IFTYPE_STATION: - if (wdev->wext.connect.ssid_len) - __cfg80211_connect(rdev, dev, - &wdev->wext.connect); + cfg80211_mgd_wext_connect(rdev, wdev); break; default: break; @@ -690,6 +686,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, } mutex_unlock(&rdev->devlist_mtx); mutex_destroy(&wdev->mtx); +#ifdef CONFIG_WIRELESS_EXT + kfree(wdev->wext.keys); +#endif break; case NETDEV_PRE_UP: if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) diff --git a/net/wireless/core.h b/net/wireless/core.h index e46cd6e..2ec8ddb 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -238,6 +238,12 @@ struct cfg80211_event { }; }; +struct cfg80211_cached_keys { + struct key_params params[6]; + u8 data[6][WLAN_MAX_KEY_LEN]; + int def, defmgmt; +}; + /* free object */ extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); @@ -256,14 +262,18 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev, /* IBSS */ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct cfg80211_ibss_params *params); + struct cfg80211_ibss_params *params, + struct cfg80211_cached_keys *connkeys); int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct cfg80211_ibss_params *params); + struct cfg80211_ibss_params *params, + struct cfg80211_cached_keys *connkeys); void cfg80211_clear_ibss(struct net_device *dev, bool nowext); int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, bool nowext); void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); +int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev); /* MLME */ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, @@ -272,12 +282,14 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, - const u8 *ie, int ie_len); + const u8 *ie, int ie_len, + const u8 *key, int key_len, int key_idx); int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, - const u8 *ie, int ie_len); + const u8 *ie, int ie_len, + const u8 *key, int key_len, int key_idx); int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, @@ -310,10 +322,12 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, /* SME */ int __cfg80211_connect(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct cfg80211_connect_params *connect); + struct cfg80211_connect_params *connect, + struct cfg80211_cached_keys *connkeys); int cfg80211_connect(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct cfg80211_connect_params *connect); + struct cfg80211_connect_params *connect, + struct cfg80211_cached_keys *connkeys); int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, struct net_device *dev, u16 reason, bool wextev); @@ -323,11 +337,14 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, const u8 *req_ie, size_t req_ie_len, const u8 *resp_ie, size_t resp_ie_len); +int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev); void cfg80211_conn_work(struct work_struct *work); /* internal helpers */ -int cfg80211_validate_key_settings(struct key_params *params, int key_idx, +int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, + struct key_params *params, int key_idx, const u8 *mac_addr); void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, size_t ie_len, u16 reason, bool from_ap); @@ -335,5 +352,6 @@ void cfg80211_sme_scan_done(struct net_device *dev); void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); void cfg80211_sme_disassoc(struct net_device *dev, int idx); void __cfg80211_scan_done(struct work_struct *wk); +void cfg80211_upload_connect_keys(struct wireless_dev *wdev); #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 99ef936..9394e78 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -39,6 +39,8 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) cfg80211_hold_bss(bss_from_pub(bss)); wdev->current_bss = bss_from_pub(bss); + cfg80211_upload_connect_keys(wdev); + nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, GFP_KERNEL); #ifdef CONFIG_WIRELESS_EXT @@ -71,7 +73,8 @@ EXPORT_SYMBOL(cfg80211_ibss_joined); int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct cfg80211_ibss_params *params) + struct cfg80211_ibss_params *params, + struct cfg80211_cached_keys *connkeys) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; @@ -81,13 +84,18 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, if (wdev->ssid_len) return -EALREADY; + if (WARN_ON(wdev->connect_keys)) + kfree(wdev->connect_keys); + wdev->connect_keys = connkeys; + #ifdef CONFIG_WIRELESS_EXT wdev->wext.ibss.channel = params->channel; #endif err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); - - if (err) + if (err) { + wdev->connect_keys = NULL; return err; + } memcpy(wdev->ssid, params->ssid, params->ssid_len); wdev->ssid_len = params->ssid_len; @@ -97,13 +105,14 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct cfg80211_ibss_params *params) + struct cfg80211_ibss_params *params, + struct cfg80211_cached_keys *connkeys) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; wdev_lock(wdev); - err = __cfg80211_join_ibss(rdev, dev, params); + err = __cfg80211_join_ibss(rdev, dev, params, connkeys); wdev_unlock(wdev); return err; @@ -112,9 +121,22 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) { struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int i; ASSERT_WDEV_LOCK(wdev); + kfree(wdev->connect_keys); + wdev->connect_keys = NULL; + + /* + * Delete all the keys ... pairwise keys can't really + * exist any more anyway, but default keys might. + */ + if (rdev->ops->del_key) + for (i = 0; i < 6; i++) + rdev->ops->del_key(wdev->wiphy, dev, i, NULL); + if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); cfg80211_put_bss(&wdev->current_bss->pub); @@ -172,11 +194,14 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, } #ifdef CONFIG_WIRELESS_EXT -static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev) +int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) { + struct cfg80211_cached_keys *ck = NULL; enum ieee80211_band band; - int i; + int i, err; + + ASSERT_WDEV_LOCK(wdev); if (!wdev->wext.ibss.beacon_interval) wdev->wext.ibss.beacon_interval = 100; @@ -216,8 +241,24 @@ static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, if (!netif_running(wdev->netdev)) return 0; - return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy), - wdev->netdev, &wdev->wext.ibss); + if (wdev->wext.keys) + wdev->wext.keys->def = wdev->wext.default_key; + + wdev->wext.ibss.privacy = wdev->wext.default_key != -1; + + if (wdev->wext.keys) { + ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); + if (!ck) + return -ENOMEM; + for (i = 0; i < 6; i++) + ck->params[i].key = ck->data[i]; + } + err = __cfg80211_join_ibss(rdev, wdev->netdev, + &wdev->wext.ibss, ck); + if (err) + kfree(ck); + + return err; } int cfg80211_ibss_wext_siwfreq(struct net_device *dev, @@ -265,7 +306,11 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, wdev->wext.ibss.channel_fixed = false; } - return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); + wdev_lock(wdev); + err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); + wdev_unlock(wdev); + + return err; } /* temporary symbol - mark GPL - in the future the handler won't be */ EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq); @@ -333,7 +378,11 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, memcpy(wdev->wext.ibss.ssid, ssid, len); wdev->wext.ibss.ssid_len = len; - return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); + wdev_lock(wdev); + err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); + wdev_unlock(wdev); + + return err; } /* temporary symbol - mark GPL - in the future the handler won't be */ EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid); @@ -414,7 +463,11 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, } else wdev->wext.ibss.bssid = NULL; - return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); + wdev_lock(wdev); + err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); + wdev_unlock(wdev); + + return err; } /* temporary symbol - mark GPL - in the future the handler won't be */ EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 1b2ca1f..8e4ce2f 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -328,7 +328,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, - const u8 *ie, int ie_len) + const u8 *ie, int ie_len, + const u8 *key, int key_len, int key_idx) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_auth_request req; @@ -337,6 +338,10 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); + if (auth_type == NL80211_AUTHTYPE_SHARED_KEY) + if (!key || !key_len || key_idx < 0 || key_idx > 4) + return -EINVAL; + if (wdev->current_bss && memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0) return -EALREADY; @@ -359,6 +364,9 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, req.auth_type = auth_type; req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + req.key = key; + req.key_len = key_len; + req.key_idx = key_idx; if (!req.bss) return -ENOENT; @@ -396,13 +404,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, - const u8 *ie, int ie_len) + const u8 *ie, int ie_len, + const u8 *key, int key_len, int key_idx) { int err; wdev_lock(dev->ieee80211_ptr); err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, - ssid, ssid_len, ie, ie_len); + ssid, ssid_len, ie, ie_len, + key, key_len, key_idx); wdev_unlock(dev->ieee80211_ptr); return err; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 50cf593..45c5f9c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -138,8 +138,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { /* policy for the attributes */ static struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = { - [NL80211_KEY_DATA] = { .type = NLA_BINARY, - .len = WLAN_MAX_KEY_LEN }, + [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, [NL80211_KEY_IDX] = { .type = NLA_U8 }, [NL80211_KEY_CIPHER] = { .type = NLA_U32 }, [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, @@ -305,6 +304,83 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) return 0; } +static struct cfg80211_cached_keys * +nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, + struct nlattr *keys) +{ + struct key_parse parse; + struct nlattr *key; + struct cfg80211_cached_keys *result; + int rem, err, def = 0; + + result = kzalloc(sizeof(*result), GFP_KERNEL); + if (!result) + return ERR_PTR(-ENOMEM); + + result->def = -1; + result->defmgmt = -1; + + nla_for_each_nested(key, keys, rem) { + memset(&parse, 0, sizeof(parse)); + parse.idx = -1; + + err = nl80211_parse_key_new(key, &parse); + if (err) + goto error; + err = -EINVAL; + if (!parse.p.key) + goto error; + if (parse.idx < 0 || parse.idx > 4) + goto error; + if (parse.def) { + if (def) + goto error; + def = 1; + result->def = parse.idx; + } else if (parse.defmgmt) + goto error; + err = cfg80211_validate_key_settings(rdev, &parse.p, + parse.idx, NULL); + if (err) + goto error; + result->params[parse.idx].cipher = parse.p.cipher; + result->params[parse.idx].key_len = parse.p.key_len; + result->params[parse.idx].key = result->data[parse.idx]; + memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len); + } + + return result; + error: + kfree(result); + return ERR_PTR(err); +} + +static int nl80211_key_allowed(struct wireless_dev *wdev) +{ + ASSERT_WDEV_LOCK(wdev); + + if (!netif_running(wdev->netdev)) + return -ENETDOWN; + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + break; + case NL80211_IFTYPE_ADHOC: + if (!wdev->current_bss) + return -ENOLINK; + break; + case NL80211_IFTYPE_STATION: + if (wdev->sme_state != CFG80211_SME_CONNECTED) + return -ENOLINK; + break; + default: + return -EINVAL; + } + + return 0; +} + static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct cfg80211_registered_device *dev) { @@ -1212,7 +1288,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) goto out; } - err = func(&rdev->wiphy, dev, key.idx); + wdev_lock(dev->ieee80211_ptr); + err = nl80211_key_allowed(dev->ieee80211_ptr); + if (!err) + err = func(&rdev->wiphy, dev, key.idx); + #ifdef CONFIG_WIRELESS_EXT if (!err) { if (func == rdev->ops->set_default_key) @@ -1221,6 +1301,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; } #endif + wdev_unlock(dev->ieee80211_ptr); out: cfg80211_unlock_rdev(rdev); @@ -1235,7 +1316,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; - int err, i; + int err; struct net_device *dev; struct key_parse key; u8 *mac_addr = NULL; @@ -1250,29 +1331,28 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (cfg80211_validate_key_settings(&key.p, key.idx, mac_addr)) - return -EINVAL; - rtnl_lock(); err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); if (err) goto unlock_rtnl; - for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) - if (key.p.cipher == rdev->wiphy.cipher_suites[i]) - break; - if (i == rdev->wiphy.n_cipher_suites) { - err = -EINVAL; + if (!rdev->ops->add_key) { + err = -EOPNOTSUPP; goto out; } - if (!rdev->ops->add_key) { - err = -EOPNOTSUPP; + if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) { + err = -EINVAL; goto out; } - err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, mac_addr, &key.p); + wdev_lock(dev->ieee80211_ptr); + err = nl80211_key_allowed(dev->ieee80211_ptr); + if (!err) + err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, + mac_addr, &key.p); + wdev_unlock(dev->ieee80211_ptr); out: cfg80211_unlock_rdev(rdev); @@ -1309,7 +1389,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) goto out; } - err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); + wdev_lock(dev->ieee80211_ptr); + err = nl80211_key_allowed(dev->ieee80211_ptr); + if (!err) + err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); #ifdef CONFIG_WIRELESS_EXT if (!err) { @@ -1319,6 +1402,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->wext.default_mgmt_key = -1; } #endif + wdev_unlock(dev->ieee80211_ptr); out: cfg80211_unlock_rdev(rdev); @@ -3159,6 +3243,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) const u8 *bssid, *ssid, *ie = NULL; int err, ssid_len, ie_len = 0; enum nl80211_auth_type auth_type; + struct key_parse key; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; @@ -3175,6 +3260,25 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) return -EINVAL; + err = nl80211_parse_key(info, &key); + if (err) + return err; + + if (key.idx >= 0) { + if (!key.p.key || !key.p.key_len) + return -EINVAL; + if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || + key.p.key_len != WLAN_KEY_LEN_WEP40) && + (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 || + key.p.key_len != WLAN_KEY_LEN_WEP104)) + return -EINVAL; + if (key.idx > 4) + return -EINVAL; + } else { + key.p.key_len = 0; + key.p.key = NULL; + } + rtnl_lock(); err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); @@ -3219,7 +3323,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) } err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, - ssid, ssid_len, ie, ie_len); + ssid, ssid_len, ie, ie_len, + key.p.key, key.p.key_len, key.idx); out: cfg80211_unlock_rdev(rdev); @@ -3506,6 +3611,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) struct net_device *dev; struct cfg80211_ibss_params ibss; struct wiphy *wiphy; + struct cfg80211_cached_keys *connkeys = NULL; int err; memset(&ibss, 0, sizeof(ibss)); @@ -3570,13 +3676,26 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) } ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; + ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; + + if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { + connkeys = nl80211_parse_connkeys(rdev, + info->attrs[NL80211_ATTR_KEYS]); + if (IS_ERR(connkeys)) { + err = PTR_ERR(connkeys); + connkeys = NULL; + goto out; + } + } - err = cfg80211_join_ibss(rdev, dev, &ibss); + err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); out: cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: + if (err) + kfree(connkeys); rtnl_unlock(); return err; } @@ -3746,6 +3865,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) struct net_device *dev; struct cfg80211_connect_params connect; struct wiphy *wiphy; + struct cfg80211_cached_keys *connkeys = NULL; int err; memset(&connect, 0, sizeof(connect)); @@ -3810,12 +3930,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) } } - err = cfg80211_connect(rdev, dev, &connect); + if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { + connkeys = nl80211_parse_connkeys(rdev, + info->attrs[NL80211_ATTR_KEYS]); + if (IS_ERR(connkeys)) { + err = PTR_ERR(connkeys); + connkeys = NULL; + goto out; + } + } + + err = cfg80211_connect(rdev, dev, &connect, connkeys); out: cfg80211_unlock_rdev(rdev); dev_put(dev); unlock_rtnl: + if (err) + kfree(connkeys); rtnl_unlock(); return err; } diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 79ca56c..d635a99 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -125,7 +125,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) params->channel, params->auth_type, params->bssid, params->ssid, params->ssid_len, - NULL, 0); + NULL, 0, + params->key, params->key_len, + params->key_idx); case CFG80211_CONN_ASSOCIATE_NEXT: BUG_ON(!rdev->ops->assoc); wdev->conn->state = CFG80211_CONN_ASSOCIATING; @@ -279,8 +281,12 @@ void cfg80211_sme_rx_auth(struct net_device *dev, /* select automatically between only open, shared, leap */ switch (wdev->conn->params.auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: - wdev->conn->params.auth_type = - NL80211_AUTHTYPE_SHARED_KEY; + if (wdev->connect_keys) + wdev->conn->params.auth_type = + NL80211_AUTHTYPE_SHARED_KEY; + else + wdev->conn->params.auth_type = + NL80211_AUTHTYPE_NETWORK_EAP; break; case NL80211_AUTHTYPE_SHARED_KEY: wdev->conn->params.auth_type = @@ -353,10 +359,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, #endif if (status == WLAN_STATUS_SUCCESS && - wdev->sme_state == CFG80211_SME_IDLE) { - wdev->sme_state = CFG80211_SME_CONNECTED; - return; - } + wdev->sme_state == CFG80211_SME_IDLE) + goto success; if (wdev->sme_state != CFG80211_SME_CONNECTING) return; @@ -370,24 +374,29 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (wdev->conn) wdev->conn->state = CFG80211_CONN_IDLE; - if (status == WLAN_STATUS_SUCCESS) { - bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, - wdev->ssid, wdev->ssid_len, - WLAN_CAPABILITY_ESS, - WLAN_CAPABILITY_ESS); - - if (WARN_ON(!bss)) - return; - - cfg80211_hold_bss(bss_from_pub(bss)); - wdev->current_bss = bss_from_pub(bss); - - wdev->sme_state = CFG80211_SME_CONNECTED; - } else { + if (status != WLAN_STATUS_SUCCESS) { wdev->sme_state = CFG80211_SME_IDLE; kfree(wdev->conn); wdev->conn = NULL; + kfree(wdev->connect_keys); + wdev->connect_keys = NULL; + return; } + + bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, + wdev->ssid, wdev->ssid_len, + WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); + + if (WARN_ON(!bss)) + return; + + cfg80211_hold_bss(bss_from_pub(bss)); + wdev->current_bss = bss_from_pub(bss); + + success: + wdev->sme_state = CFG80211_SME_CONNECTED; + cfg80211_upload_connect_keys(wdev); } void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, @@ -516,6 +525,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, size_t ie_len, u16 reason, bool from_ap) { struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int i; #ifdef CONFIG_WIRELESS_EXT union iwreq_data wrqu; #endif @@ -543,8 +554,15 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, wdev->conn = NULL; } - nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, - reason, ie, ie_len, from_ap); + nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); + + /* + * Delete all the keys ... pairwise keys can't really + * exist any more anyway, but default keys might. + */ + if (rdev->ops->del_key) + for (i = 0; i < 6; i++) + rdev->ops->del_key(wdev->wiphy, dev, i, NULL); #ifdef CONFIG_WIRELESS_EXT memset(&wrqu, 0, sizeof(wrqu)); @@ -580,7 +598,8 @@ EXPORT_SYMBOL(cfg80211_disconnected); int __cfg80211_connect(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct cfg80211_connect_params *connect) + struct cfg80211_connect_params *connect, + struct cfg80211_cached_keys *connkeys) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; @@ -590,6 +609,24 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, if (wdev->sme_state != CFG80211_SME_IDLE) return -EALREADY; + if (WARN_ON(wdev->connect_keys)) { + kfree(wdev->connect_keys); + wdev->connect_keys = NULL; + } + + if (connkeys && connkeys->def >= 0) { + int idx; + + idx = connkeys->def; + /* If given a WEP key we may need it for shared key auth */ + if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 || + connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) { + connect->key_idx = idx; + connect->key = connkeys->params[idx].key; + connect->key_len = connkeys->params[idx].key_len; + } + } + if (!rdev->ops->connect) { if (!rdev->ops->auth || !rdev->ops->assoc) return -EOPNOTSUPP; @@ -640,6 +677,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, cfg80211_get_conn_bss(wdev); wdev->sme_state = CFG80211_SME_CONNECTING; + wdev->connect_keys = connkeys; /* we're good if we have both BSSID and channel */ if (wdev->conn->params.bssid && wdev->conn->params.channel) { @@ -662,13 +700,16 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, kfree(wdev->conn); wdev->conn = NULL; wdev->sme_state = CFG80211_SME_IDLE; + wdev->connect_keys = NULL; } return err; } else { wdev->sme_state = CFG80211_SME_CONNECTING; + wdev->connect_keys = connkeys; err = rdev->ops->connect(&rdev->wiphy, dev, connect); if (err) { + wdev->connect_keys = NULL; wdev->sme_state = CFG80211_SME_IDLE; return err; } @@ -682,12 +723,13 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, int cfg80211_connect(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct cfg80211_connect_params *connect) + struct cfg80211_connect_params *connect, + struct cfg80211_cached_keys *connkeys) { int err; wdev_lock(dev->ieee80211_ptr); - err = __cfg80211_connect(rdev, dev, connect); + err = __cfg80211_connect(rdev, dev, connect, connkeys); wdev_unlock(dev->ieee80211_ptr); return err; @@ -704,6 +746,9 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, if (wdev->sme_state == CFG80211_SME_IDLE) return -EINVAL; + kfree(wdev->connect_keys); + wdev->connect_keys = NULL; + if (!rdev->ops->disconnect) { if (!rdev->ops->deauth) return -EOPNOTSUPP; diff --git a/net/wireless/util.c b/net/wireless/util.c index 28f8f96..4bab380 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -141,9 +141,12 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) set_mandatory_flags_band(wiphy->bands[band], band); } -int cfg80211_validate_key_settings(struct key_params *params, int key_idx, +int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, + struct key_params *params, int key_idx, const u8 *mac_addr) { + int i; + if (key_idx > 5) return -EINVAL; @@ -197,6 +200,12 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx, } } + for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) + if (params->cipher == rdev->wiphy.cipher_suites[i]) + break; + if (i == rdev->wiphy.n_cipher_suites) + return -EINVAL; + return 0; } @@ -523,3 +532,33 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie) return NULL; } EXPORT_SYMBOL(ieee80211_bss_get_ie); + +void cfg80211_upload_connect_keys(struct wireless_dev *wdev) +{ + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct net_device *dev = wdev->netdev; + int i; + + if (!wdev->connect_keys) + return; + + for (i = 0; i < 6; i++) { + if (!wdev->connect_keys->params[i].cipher) + continue; + if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, + &wdev->connect_keys->params[i])) + printk(KERN_ERR "%s: failed to set key %d\n", + dev->name, i); + if (wdev->connect_keys->def == i) + if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) + printk(KERN_ERR "%s: failed to set defkey %d\n", + dev->name, i); + if (wdev->connect_keys->defmgmt == i) + if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) + printk(KERN_ERR "%s: failed to set mgtdef %d\n", + dev->name, i); + } + + kfree(wdev->connect_keys); + wdev->connect_keys = NULL; +} diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 5088d89..5d01763 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -453,15 +453,32 @@ int cfg80211_wext_giwretry(struct net_device *dev, } EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); -static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *addr, - bool remove, bool tx_key, int idx, - struct key_params *params) +static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *addr, + bool remove, bool tx_key, int idx, + struct key_params *params) { struct wireless_dev *wdev = dev->ieee80211_ptr; - int err; + int err, i; + + if (!wdev->wext.keys) { + wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), + GFP_KERNEL); + if (!wdev->wext.keys) + return -ENOMEM; + for (i = 0; i < 6; i++) + wdev->wext.keys->params[i].key = + wdev->wext.keys->data[i]; + } + + if (wdev->iftype != NL80211_IFTYPE_ADHOC && + wdev->iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + if (!wdev->current_bss) + return -ENOLINK; + if (!rdev->ops->set_default_mgmt_key) return -EOPNOTSUPP; @@ -471,8 +488,14 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, return -EINVAL; if (remove) { - err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); + err = 0; + if (wdev->current_bss) + err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); if (!err) { + if (!addr) { + wdev->wext.keys->params[idx].key_len = 0; + wdev->wext.keys->params[idx].cipher = 0; + } if (idx == wdev->wext.default_key) wdev->wext.default_key = -1; else if (idx == wdev->wext.default_mgmt_key) @@ -486,36 +509,64 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, return 0; return err; - } else { - if (addr) - tx_key = false; + } - if (cfg80211_validate_key_settings(params, idx, addr)) - return -EINVAL; + if (addr) + tx_key = false; + if (cfg80211_validate_key_settings(rdev, params, idx, addr)) + return -EINVAL; + + err = 0; + if (wdev->current_bss) err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); - if (err) - return err; + if (err) + return err; + + if (!addr) { + wdev->wext.keys->params[idx] = *params; + memcpy(wdev->wext.keys->data[idx], + params->key, params->key_len); + wdev->wext.keys->params[idx].key = + wdev->wext.keys->data[idx]; + } - if (tx_key || (!addr && wdev->wext.default_key == -1)) { + if (params->cipher != WLAN_CIPHER_SUITE_AES_CMAC && + (tx_key || (!addr && wdev->wext.default_key == -1))) { + if (wdev->current_bss) err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx); - if (!err) - wdev->wext.default_key = idx; - return err; - } + if (!err) + wdev->wext.default_key = idx; + return err; + } - if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && - (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { + if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && + (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { + if (wdev->current_bss) err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, dev, idx); - if (!err) - wdev->wext.default_mgmt_key = idx; - return err; - } - - return 0; + if (!err) + wdev->wext.default_mgmt_key = idx; + return err; } + + return 0; +} + +static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *addr, + bool remove, bool tx_key, int idx, + struct key_params *params) +{ + int err; + + wdev_lock(dev->ieee80211_ptr); + err = __cfg80211_set_encryption(rdev, dev, addr, remove, + tx_key, idx, params); + wdev_unlock(dev->ieee80211_ptr); + + return err; } int cfg80211_wext_siwencode(struct net_device *dev, @@ -528,6 +579,10 @@ int cfg80211_wext_siwencode(struct net_device *dev, bool remove = false; struct key_params params; + if (wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_ADHOC) + return -EOPNOTSUPP; + /* no use -- only MFP (set_default_mgmt_key) is optional */ if (!rdev->ops->del_key || !rdev->ops->add_key || @@ -548,9 +603,14 @@ int cfg80211_wext_siwencode(struct net_device *dev, remove = true; else if (erq->length == 0) { /* No key data - just set the default TX key index */ - err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx); + err = 0; + wdev_lock(wdev); + if (wdev->current_bss) + err = rdev->ops->set_default_key(&rdev->wiphy, + dev, idx); if (!err) wdev->wext.default_key = idx; + wdev_unlock(wdev); return err; } @@ -583,6 +643,10 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, struct key_params params; u32 cipher; + if (wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_ADHOC) + return -EOPNOTSUPP; + /* no use -- only MFP (set_default_mgmt_key) is optional */ if (!rdev->ops->del_key || !rdev->ops->add_key || @@ -656,37 +720,15 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, } EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); -struct giwencode_cookie { - size_t buflen; - char *keybuf; -}; - -static void giwencode_get_key_cb(void *cookie, struct key_params *params) -{ - struct giwencode_cookie *data = cookie; - - if (!params->key) { - data->buflen = 0; - return; - } - - data->buflen = min_t(size_t, data->buflen, params->key_len); - memcpy(data->keybuf, params->key, data->buflen); -} - int cfg80211_wext_giwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); - int idx, err; - struct giwencode_cookie data = { - .keybuf = keybuf, - .buflen = erq->length, - }; + int idx; - if (!rdev->ops->get_key) + if (wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; idx = erq->flags & IW_ENCODE_INDEX; @@ -701,21 +743,18 @@ int cfg80211_wext_giwencode(struct net_device *dev, erq->flags = idx + 1; - err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data, - giwencode_get_key_cb); - if (!err) { - erq->length = data.buflen; - erq->flags |= IW_ENCODE_ENABLED; - return 0; - } - - if (err == -ENOENT) { + if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) { erq->flags |= IW_ENCODE_DISABLED; erq->length = 0; return 0; } - return err; + erq->length = min_t(size_t, erq->length, + wdev->wext.keys->params[idx].key_len); + memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length); + erq->flags |= IW_ENCODE_ENABLED; + + return 0; } EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 6f75aaa7f..c33ea9a 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -10,10 +10,11 @@ #include #include "nl80211.h" -static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev) +int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) { - int err; + struct cfg80211_cached_keys *ck = NULL; + int err, i; ASSERT_RDEV_LOCK(rdev); ASSERT_WDEV_LOCK(wdev); @@ -25,10 +26,25 @@ static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, wdev->wext.connect.ie_len = wdev->wext.ie_len; wdev->wext.connect.privacy = wdev->wext.default_key != -1; - err = 0; - if (wdev->wext.connect.ssid_len != 0) - err = __cfg80211_connect(rdev, wdev->netdev, - &wdev->wext.connect); + if (wdev->wext.keys) { + wdev->wext.keys->def = wdev->wext.default_key; + wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key; + } + + if (!wdev->wext.connect.ssid_len) + return 0; + + if (wdev->wext.keys) { + ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); + if (!ck) + return -ENOMEM; + for (i = 0; i < 6; i++) + ck->params[i].key = ck->data[i]; + } + err = __cfg80211_connect(rdev, wdev->netdev, + &wdev->wext.connect, ck); + if (err) + kfree(ck); return err; } -- cgit v0.10.2 From f874011bb01e7fb19904db7f739bb343a0a53fd5 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Wed, 8 Jul 2009 22:03:13 +0200 Subject: wireless: fix supported cards for rtl8187 Different revisions of WUSB54GC-EU use different chipsets - v2 uses rtl8187, but v3 uses Ralink RT3070. Signed-off-by: Marcin Slusarz Cc: Przemyslaw Kulczycki Cc: John W. Linville Cc: Linux wireless Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 5bc00db..7d5902d 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -431,7 +431,7 @@ config RTL8187 ASUS P5B Deluxe Toshiba Satellite Pro series of laptops Asus Wireless Link - Linksys WUSB54GC-EU + Linksys WUSB54GC-EU v2 Thanks to Realtek for their support! -- cgit v0.10.2 From 80e5b06a1b0d9a6aa88dc5c9e93ba49510c52b45 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 9 Jul 2009 16:59:49 +0800 Subject: cfg80211: fix NULL dereference in IBSS SIOCGIWAP This patch avoids memcpy from wdev->wext.ibss.bssid if it is NULL. This could happen if we SIOCGIWAP before SIOCSIWAP. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 9394e78..8b65e21 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -487,8 +487,11 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, wdev_lock(wdev); if (wdev->current_bss) memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); - else + else if (wdev->wext.ibss.bssid) memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); + else + memset(ap_addr->sa_data, 0, ETH_ALEN); + wdev_unlock(wdev); return 0; -- cgit v0.10.2 From f5ad69fa47e7b204d0032d569812544cd9a351fb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 9 Jul 2009 10:33:36 -0700 Subject: iwlwifi: move show_qos to debugfs This move the show_qos file from sysfs to debugfs because the "one value per file" sysfs rule. The file is located in /sys/kernel/debug/ieee80211/phy0/iwlagn/data Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e2cc599..ad50022 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2627,26 +2627,6 @@ static ssize_t show_power_level(struct device *d, static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, store_power_level); -static ssize_t show_qos(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - char *p = buf; - int q; - - for (q = 0; q < AC_NUM; q++) { - p += sprintf(p, "\tcw_min\tcw_max\taifsn\ttxop\n"); - p += sprintf(p, "AC[%d]\t%u\t%u\t%u\t%u\n", q, - priv->qos_data.def_qos_parm.ac[q].cw_min, - priv->qos_data.def_qos_parm.ac[q].cw_max, - priv->qos_data.def_qos_parm.ac[q].aifsn, - priv->qos_data.def_qos_parm.ac[q].edca_txop); - } - - return p - buf + 1; -} - -static DEVICE_ATTR(qos, S_IRUGO, show_qos, NULL); static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) @@ -2747,7 +2727,6 @@ static struct attribute *iwl_sysfs_entries[] = { &dev_attr_debug_level.attr, #endif &dev_attr_version.attr, - &dev_attr_qos.attr, NULL }; diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 65bbce0..1555676 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -82,6 +82,7 @@ struct iwl_debugfs { struct dentry *file_channels; struct dentry *file_status; struct dentry *file_interrupt; + struct dentry *file_qos; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index f32ac74..e38ec81 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -566,6 +566,28 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0, i; + char buf[256]; + const size_t bufsz = sizeof(buf); + ssize_t ret; + + for (i = 0; i < AC_NUM; i++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\tcw_min\tcw_max\taifsn\ttxop\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "AC[%d]\t%u\t%u\t%u\t%u\n", i, + priv->qos_data.def_qos_parm.ac[i].cw_min, + priv->qos_data.def_qos_parm.ac[i].cw_max, + priv->qos_data.def_qos_parm.ac[i].aifsn, + priv->qos_data.def_qos_parm.ac[i].edca_txop); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); @@ -576,6 +598,7 @@ DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_WRITE_FILE_OPS(interrupt); +DEBUGFS_READ_FILE_OPS(qos); /* * Create the debugfs files and directories @@ -612,6 +635,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_FILE(status, data); DEBUGFS_ADD_FILE(interrupt, data); + DEBUGFS_ADD_FILE(qos, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -646,6 +670,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos); DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); -- cgit v0.10.2 From fcf89d05404dafcde581d44dfa89bd8c8def27f9 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 9 Jul 2009 10:33:38 -0700 Subject: iwlwifi: fix permissions on debugfs files debugfs files are created with 644 permissions which gives everybody read access. This presents a security issue if a user opens the file and holds it open at the time the driver removes the file. At this point invalid memory will be accessed. Fix this by only allowing root to read debugfs files. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index e38ec81..0b9e824 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -49,7 +49,8 @@ #define DEBUGFS_ADD_FILE(name, parent) do { \ dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \ + debugfs_create_file(#name, S_IWUSR | S_IRUSR, \ + dbgfs->dir_##parent, priv, \ &iwl_dbgfs_##name##_ops); \ if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \ goto err; \ @@ -57,7 +58,8 @@ #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \ + debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \ + dbgfs->dir_##parent, ptr); \ if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ || !dbgfs->dbgfs_##parent##_files.file_##name) \ goto err; \ @@ -65,7 +67,7 @@ #define DEBUGFS_ADD_X32(name, parent, ptr) do { \ dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_x32(#name, 0444, dbgfs->dir_##parent, ptr); \ + debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr); \ if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ || !dbgfs->dbgfs_##parent##_files.file_##name) \ goto err; \ -- cgit v0.10.2 From 5905a1aa71488b5f78822100c865ed7c4f9fcd8f Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 9 Jul 2009 10:33:40 -0700 Subject: iwl3945: cleanup number of queues settings * Rename maximum number of queue (TFD_QUEUE_MAX) to IWL39_NUM_QUEUES to be consistent with rest of iwlwifi. * Remove unused defines. * Fix loops that iterate over number of TX queues to stop when maximum is reached (currently it is maximum + 1). * Remove queues_num module parameter as it is not used. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 73f93a0..b569c6f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -232,9 +232,8 @@ struct iwl3945_eeprom { #define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */ #define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */ -#define TFD_QUEUE_MIN 0 -#define TFD_QUEUE_MAX 5 /* 4 DATA + 1 CMD */ - +/* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */ +#define IWL39_NUM_QUEUES 5 #define IWL_NUM_SCAN_RATES (2) #define IWL_DEFAULT_TX_RETRY 15 @@ -280,8 +279,6 @@ struct iwl3945_eeprom { /* Size of uCode instruction memory in bootstrap state machine */ #define IWL39_MAX_BSM_SIZE IWL39_RTC_INST_SIZE -#define IWL39_MAX_NUM_QUEUES 8 - static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr) { return (addr >= IWL39_RTC_DATA_LOWER_BOUND) && diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index b0246db..1227ed2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -963,7 +963,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) goto error; /* Tx queue(s) */ - for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) { + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, @@ -1140,7 +1140,7 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv) int txq_id; /* Tx queues */ - for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) if (txq_id == IWL_CMD_QUEUE_NUM) iwl_cmd_queue_free(priv); else @@ -1156,7 +1156,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); /* reset TFD queues */ - for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) { + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0); iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS, FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id), @@ -2552,7 +2552,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) } /* Assign number of Usable TX queues */ - priv->hw_params.max_txq_num = TFD_QUEUE_MAX; + priv->hw_params.max_txq_num = IWL39_NUM_QUEUES; priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index fbb3a57..f2ffc48 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -111,9 +111,6 @@ enum iwl3945_antenna { #define IWL_TX_FIFO_HCCA_2 6 #define IWL_TX_FIFO_NONE 7 -/* Minimum number of queues. MAX_NUM is defined in hw specific files */ -#define IWL_MIN_NUM_QUEUES 4 - #define IEEE80211_DATA_LEN 2304 #define IEEE80211_4ADDR_LEN 30 #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 7ff95f8..c9b3ea9 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -89,7 +89,7 @@ MODULE_LICENSE("GPL"); /* module parameters */ struct iwl_mod_params iwl3945_mod_params = { - .num_of_queues = IWL39_MAX_NUM_QUEUES, + .num_of_queues = IWL39_NUM_QUEUES, /* Not used */ .sw_crypto = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -3947,15 +3947,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv = hw->priv; SET_IEEE80211_DEV(hw, &pdev->dev); - if ((iwl3945_mod_params.num_of_queues > IWL39_MAX_NUM_QUEUES) || - (iwl3945_mod_params.num_of_queues < IWL_MIN_NUM_QUEUES)) { - IWL_ERR(priv, - "invalid queues_num, should be between %d and %d\n", - IWL_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES); - err = -EINVAL; - goto out_ieee80211_free_hw; - } - /* * Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. @@ -4272,10 +4263,6 @@ module_param_named(debug, iwl3945_mod_params.debug, uint, 0444); MODULE_PARM_DESC(debug, "debug output mask"); module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); - -module_param_named(queues_num, iwl3945_mod_params.num_of_queues, int, 0444); -MODULE_PARM_DESC(queues_num, "number of hw queues."); - module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444); MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error"); -- cgit v0.10.2 From 01a7e08436929271c6173b5daf3e193ef5b3561a Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 9 Jul 2009 10:33:41 -0700 Subject: iwlagn: fix minimum number of queues setting We need to provide a reasonable minimum that will result in a working setup if used. Set minimum to be 10 to provide for 4 standard TX queues + 1 command queue + 2 (unused) HCCA queues + 4 HT queues (one per AC). We allow the user to change the number of queues used via a module parameter and use this minimum value to check if it is valid. Without this patch a user can select a value for the number of queues that will result in a failing setup. Signed-off-by: Reinette Chatre Reviewed-by: Tomas Winkler Acked-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1a2fe37..b989d5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -258,8 +258,10 @@ struct iwl_channel_info { #define IWL_TX_FIFO_HCCA_2 6 #define IWL_TX_FIFO_NONE 7 -/* Minimum number of queues. MAX_NUM is defined in hw specific files */ -#define IWL_MIN_NUM_QUEUES 4 +/* Minimum number of queues. MAX_NUM is defined in hw specific files. + * Set the minimum to accommodate the 4 standard TX queues, 1 command + * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */ +#define IWL_MIN_NUM_QUEUES 10 /* Power management (not Tx power) structures */ -- cgit v0.10.2 From ca386f3137eb68621fadba546d9eb35ac2f82de3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 02:39:48 +0200 Subject: mac80211: fix multi-use timer We have, sometimes, multiple things that want to run but don't have their own timer. Introduce a new function to mac80211's mlme run_again() that makes sure that the timer will run again at the _first_ needed time, use that function and also properly reprogram the timer once it fired. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8e4a604..c1114bb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -72,6 +72,26 @@ static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) WARN_ON(!mutex_is_locked(&ifmgd->mtx)); } +/* + * We can have multiple work items (and connection probing) + * scheduling this timer, but we need to take care to only + * reschedule it when it should fire _earlier_ than it was + * asked for before, or if it's not pending right now. This + * function ensures that. Note that it then is required to + * run this function for all timeouts after the first one + * has happened -- the work that runs from this timer will + * do that. + */ +static void run_again(struct ieee80211_if_managed *ifmgd, + unsigned long timeout) +{ + ASSERT_MGD_MTX(ifmgd); + + if (!timer_pending(&ifmgd->timer) || + time_before(timeout, ifmgd->timer.expires)) + mod_timer(&ifmgd->timer, timeout); +} + static int ecw2cw(int ecw) { return (1 << ecw) - 1; @@ -916,7 +936,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0); wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - mod_timer(&ifmgd->timer, wk->timeout); + run_again(ifmgd, wk->timeout); return RX_MGMT_NONE; } @@ -958,7 +978,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, wk->auth_transaction = 2; wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - mod_timer(&ifmgd->timer, wk->timeout); + run_again(ifmgd, wk->timeout); return RX_MGMT_NONE; } @@ -1079,7 +1099,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata, ieee80211_send_assoc(sdata, wk); wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; - mod_timer(&ifmgd->timer, wk->timeout); + run_again(ifmgd, wk->timeout); return RX_MGMT_NONE; } @@ -1140,7 +1160,7 @@ void ieee80211_beacon_loss_work(struct work_struct *work) ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, ssid + 2, ssid[1], NULL, 0); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); + run_again(ifmgd, jiffies + IEEE80211_PROBE_WAIT); out: mutex_unlock(&ifmgd->mtx); } @@ -1350,8 +1370,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, sdata->dev->name, tu, ms); wk->timeout = jiffies + msecs_to_jiffies(ms); if (ms > IEEE80211_ASSOC_TIMEOUT) - mod_timer(&ifmgd->timer, - jiffies + msecs_to_jiffies(ms)); + run_again(ifmgd, jiffies + msecs_to_jiffies(ms)); return RX_MGMT_NONE; } @@ -1981,8 +2000,15 @@ static void ieee80211_sta_work(struct work_struct *work) } list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { - if (time_before(jiffies, wk->timeout)) + if (time_is_after_jiffies(wk->timeout)) { + /* + * This work item isn't supposed to be worked on + * right now, but take care to adjust the timer + * properly. + */ + run_again(ifmgd, wk->timeout); continue; + } switch (wk->state) { default: -- cgit v0.10.2 From b291ba11181d46dfbd2d7a5c00a5f3335228191e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 15:29:03 +0200 Subject: mac80211: monitor the connection With the recent MLME rework I accidentally removed the connection monitoring code. In order to add it back, this patch will add new code to monitor both for beacon loss and for the connection actually working, with possibly separate triggers. When no unicast frames have been received from the AP for (currently) two seconds, we will send the AP a probe request. Also, when we don't see beacons from the AP for two seconds, we do the same (but those times need not be the same due to the way the code is now written). Additionally, clean up the parameters to the ieee80211_set_disassoc() function that I need here, those are all useless except sdata. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 06b3411..a34bca2 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -256,12 +256,13 @@ struct ieee80211_mgd_work { /* flags used in struct ieee80211_if_managed.flags */ enum ieee80211_sta_flags { - IEEE80211_STA_PROBEREQ_POLL = BIT(3), - IEEE80211_STA_CONTROL_PORT = BIT(4), - IEEE80211_STA_WMM_ENABLED = BIT(5), - IEEE80211_STA_DISABLE_11N = BIT(6), - IEEE80211_STA_CSA_RECEIVED = BIT(7), - IEEE80211_STA_MFP_ENABLED = BIT(8), + IEEE80211_STA_BEACON_POLL = BIT(0), + IEEE80211_STA_CONNECTION_POLL = BIT(1), + IEEE80211_STA_CONTROL_PORT = BIT(2), + IEEE80211_STA_WMM_ENABLED = BIT(3), + IEEE80211_STA_DISABLE_11N = BIT(4), + IEEE80211_STA_CSA_RECEIVED = BIT(5), + IEEE80211_STA_MFP_ENABLED = BIT(6), }; /* flags for MLME request */ @@ -271,11 +272,16 @@ enum ieee80211_sta_request { struct ieee80211_if_managed { struct timer_list timer; + struct timer_list conn_mon_timer; + struct timer_list bcn_mon_timer; struct timer_list chswitch_timer; struct work_struct work; + struct work_struct monitor_work; struct work_struct chswitch_work; struct work_struct beacon_loss_work; + unsigned long probe_timeout; + struct mutex mtx; struct ieee80211_bss *associated; struct list_head work_list; @@ -292,8 +298,6 @@ struct ieee80211_if_managed { unsigned long request; - unsigned long last_beacon; - unsigned int flags; u32 beacon_crc; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c1114bb..18dad22 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -31,8 +31,23 @@ #define IEEE80211_AUTH_MAX_TRIES 3 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_ASSOC_MAX_TRIES 3 -#define IEEE80211_MONITORING_INTERVAL (2 * HZ) -#define IEEE80211_PROBE_WAIT (HZ / 5) + +/* + * beacon loss detection timeout + * XXX: should depend on beacon interval + */ +#define IEEE80211_BEACON_LOSS_TIME (2 * HZ) +/* + * Time the connection can be idle before we probe + * it to see if we can still talk to the AP. + */ +#define IEEE80211_CONNECTION_IDLE_TIME (2 * HZ) +/* + * Time we wait for a probe response after sending + * a probe request because of beacon loss or for + * checking the connection still works. + */ +#define IEEE80211_PROBE_WAIT (HZ / 5) #define TMR_RUNNING_TIMER 0 #define TMR_RUNNING_CHANSW 1 @@ -92,6 +107,15 @@ static void run_again(struct ieee80211_if_managed *ifmgd, mod_timer(&ifmgd->timer, timeout); } +static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata) +{ + if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER) + return; + + mod_timer(&sdata->u.mgd.bcn_mon_timer, + round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME)); +} + static int ecw2cw(int ecw) { return (1 << ecw) - 1; @@ -666,7 +690,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) if (count == 1 && found->u.mgd.powersave && found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && - !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { + !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | + IEEE80211_STA_CONNECTION_POLL))) { s32 beaconint_us; if (latency < 0) @@ -872,6 +897,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, sdata->u.mgd.associated = bss; memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); + /* just to be sure */ + sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | + IEEE80211_STA_BEACON_POLL); + ieee80211_led_assoc(local, 1); sdata->vif.bss_conf.assoc = 1; @@ -983,16 +1012,21 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; } -static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, - const u8 *bssid, bool deauth) +static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; struct sta_info *sta; u32 changed = 0, config_changed = 0; + u8 bssid[ETH_ALEN]; ASSERT_MGD_MTX(ifmgd); + if (WARN_ON(!ifmgd->associated)) + return; + + memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); + ifmgd->associated = NULL; memset(ifmgd->bssid, 0, ETH_ALEN); @@ -1112,32 +1146,22 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, * from AP because we know that the connection is working both ways * at that time. But multicast frames (and hence also beacons) must * be ignored here, because we need to trigger the timer during - * data idle periods for sending the periodical probe request to - * the AP. + * data idle periods for sending the periodic probe request to the + * AP we're connected to. */ - if (!is_multicast_ether_addr(hdr->addr1)) - mod_timer(&sdata->u.mgd.timer, - jiffies + IEEE80211_MONITORING_INTERVAL); + if (is_multicast_ether_addr(hdr->addr1)) + return; + + mod_timer(&sdata->u.mgd.conn_mon_timer, + round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); } -void ieee80211_beacon_loss_work(struct work_struct *work) +static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, + bool beacon) { - struct ieee80211_sub_if_data *sdata = - container_of(work, struct ieee80211_sub_if_data, - u.mgd.beacon_loss_work); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; const u8 *ssid; - - /* - * The driver has already reported this event and we have - * already sent a probe request. Maybe the AP died and the - * driver keeps reporting until we disassociate... We have - * to ignore that because otherwise we would continually - * reset the timer and never check whether we received a - * probe response! - */ - if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) - return; + bool already = false; mutex_lock(&ifmgd->mtx); @@ -1145,12 +1169,35 @@ void ieee80211_beacon_loss_work(struct work_struct *work) goto out; #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: driver reports beacon loss from AP " + if (beacon && net_ratelimit()) + printk(KERN_DEBUG "%s: detected beacon loss from AP " "- sending probe request\n", sdata->dev->name); #endif - ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; + /* + * The driver/our work has already reported this event or the + * connection monitoring has kicked in and we have already sent + * a probe request. Or maybe the AP died and the driver keeps + * reporting until we disassociate... + * + * In either case we have to ignore the current call to this + * function (except for setting the correct probe reason bit) + * because otherwise we would reset the timer every time and + * never check whether we received a probe response! + */ + if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | + IEEE80211_STA_CONNECTION_POLL)) + already = true; + + if (beacon) + ifmgd->flags |= IEEE80211_STA_BEACON_POLL; + else + ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL; + + if (already) + goto out; + + ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; mutex_lock(&sdata->local->iflist_mtx); ieee80211_recalc_ps(sdata->local, -1); @@ -1160,11 +1207,21 @@ void ieee80211_beacon_loss_work(struct work_struct *work) ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, ssid + 2, ssid[1], NULL, 0); - run_again(ifmgd, jiffies + IEEE80211_PROBE_WAIT); + run_again(ifmgd, ifmgd->probe_timeout); + out: mutex_unlock(&ifmgd->mtx); } +void ieee80211_beacon_loss_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, + u.mgd.beacon_loss_work); + + ieee80211_mgd_probe_ap(sdata, true); +} + void ieee80211_beacon_loss(struct ieee80211_vif *vif) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -1278,7 +1335,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, sdata->dev->name, bssid, reason_code); if (!wk) { - ieee80211_set_disassoc(sdata, bssid, true); + ieee80211_set_disassoc(sdata); } else { list_del(&wk->list); kfree(wk); @@ -1311,7 +1368,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", sdata->dev->name, reason_code); - ieee80211_set_disassoc(sdata, ifmgd->associated->cbss.bssid, false); + ieee80211_set_disassoc(sdata); return RX_MGMT_CFG80211_DISASSOC; } @@ -1412,9 +1469,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; } - /* update new sta with its last rx activity */ - sta->last_rx = jiffies; - set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP); if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) @@ -1517,10 +1571,11 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ieee80211_set_associated(sdata, wk->bss, changed); /* - * initialise the time of last beacon to be the association time, - * otherwise beacon loss check will trigger immediately + * Start timer to probe the connection to the AP now. + * Also start the timer that will detect beacon loss. */ - ifmgd->last_beacon = jiffies; + ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); + mod_beacon_timer(sdata); list_del(&wk->list); kfree(wk); @@ -1604,11 +1659,22 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, if (ifmgd->associated && memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && - ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { - ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + ifmgd->flags & (IEEE80211_STA_BEACON_POLL | + IEEE80211_STA_CONNECTION_POLL)) { + ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | + IEEE80211_STA_BEACON_POLL); mutex_lock(&sdata->local->iflist_mtx); ieee80211_recalc_ps(sdata->local, -1); mutex_unlock(&sdata->local->iflist_mtx); + /* + * We've received a probe response, but are not sure whether + * we have or will be receiving any beacons or data, so let's + * schedule the timers again, just in case. + */ + mod_beacon_timer(sdata); + mod_timer(&ifmgd->conn_mon_timer, + round_jiffies_up(jiffies + + IEEE80211_CONNECTION_IDLE_TIME)); } } @@ -1658,27 +1724,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (rx_status->freq != local->hw.conf.channel->center_freq) return; - if (WARN_ON(!ifmgd->associated)) + /* + * We might have received a number of frames, among them a + * disassoc frame and a beacon... + */ + if (!ifmgd->associated) return; bssid = ifmgd->associated->cbss.bssid; - if (WARN_ON(memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)) + /* + * And in theory even frames from a different AP we were just + * associated to a split-second ago! + */ + if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0) return; - if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { + if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: cancelling probereq poll due " "to a received beacon\n", sdata->dev->name); } #endif - ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; mutex_lock(&local->iflist_mtx); ieee80211_recalc_ps(local, -1); mutex_unlock(&local->iflist_mtx); } + /* + * Push the beacon loss detection into the future since + * we are processing a beacon from the AP just now. + */ + mod_beacon_timer(sdata); + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, len - baselen, &elems, @@ -1980,6 +2060,37 @@ static void ieee80211_sta_work(struct work_struct *work) /* then process the rest of the work */ mutex_lock(&ifmgd->mtx); + if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | + IEEE80211_STA_CONNECTION_POLL) && + ifmgd->associated) { + if (time_is_after_jiffies(ifmgd->probe_timeout)) + run_again(ifmgd, ifmgd->probe_timeout); + else { + u8 bssid[ETH_ALEN]; + /* + * We actually lost the connection ... or did we? + * Let's make sure! + */ + ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | + IEEE80211_STA_BEACON_POLL); + memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); + printk(KERN_DEBUG "No probe response from AP %pM" + " after %dms, disconnecting.\n", + bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); + ieee80211_set_disassoc(sdata); + mutex_unlock(&ifmgd->mtx); + /* + * must be outside lock due to cfg80211, + * but that's not a problem. + */ + ieee80211_send_deauth_disassoc(sdata, bssid, + IEEE80211_STYPE_DEAUTH, + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, + NULL); + mutex_lock(&ifmgd->mtx); + } + } + list_for_each_entry(wk, &ifmgd->work_list, list) { if (wk->state != IEEE80211_MGD_STATE_IDLE) { anybusy = true; @@ -2067,15 +2178,51 @@ static void ieee80211_sta_work(struct work_struct *work) ieee80211_recalc_idle(local); } +static void ieee80211_sta_bcn_mon_timer(unsigned long data) +{ + struct ieee80211_sub_if_data *sdata = + (struct ieee80211_sub_if_data *) data; + struct ieee80211_local *local = sdata->local; + + if (local->quiescing) + return; + + queue_work(sdata->local->hw.workqueue, + &sdata->u.mgd.beacon_loss_work); +} + +static void ieee80211_sta_conn_mon_timer(unsigned long data) +{ + struct ieee80211_sub_if_data *sdata = + (struct ieee80211_sub_if_data *) data; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; + + if (local->quiescing) + return; + + queue_work(local->hw.workqueue, &ifmgd->monitor_work); +} + +static void ieee80211_sta_monitor_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, + u.mgd.monitor_work); + + ieee80211_mgd_probe_ap(sdata, false); +} + static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) { if (sdata->vif.type == NL80211_IFTYPE_STATION) { - /* - * Need to update last_beacon to avoid beacon loss - * test to trigger. - */ - sdata->u.mgd.last_beacon = jiffies; + sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL | + IEEE80211_STA_CONNECTION_POLL); + /* let's probe the connection once */ + queue_work(sdata->local->hw.workqueue, + &sdata->u.mgd.monitor_work); + /* and do all the other regular work too */ queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); } @@ -2100,6 +2247,11 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) cancel_work_sync(&ifmgd->chswitch_work); if (del_timer_sync(&ifmgd->chswitch_timer)) set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); + + cancel_work_sync(&ifmgd->monitor_work); + /* these will just be re-established on connection */ + del_timer_sync(&ifmgd->conn_mon_timer); + del_timer_sync(&ifmgd->bcn_mon_timer); } void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) @@ -2120,10 +2272,15 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) ifmgd = &sdata->u.mgd; INIT_WORK(&ifmgd->work, ieee80211_sta_work); + INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work); INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); setup_timer(&ifmgd->timer, ieee80211_sta_timer, (unsigned long) sdata); + setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, + (unsigned long) sdata); + setup_timer(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer, + (unsigned long) sdata); setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, (unsigned long) sdata); skb_queue_head_init(&ifmgd->skb_queue); @@ -2323,7 +2480,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { bssid = req->bss->bssid; - ieee80211_set_disassoc(sdata, bssid, true); + ieee80211_set_disassoc(sdata); } else list_for_each_entry(wk, &ifmgd->work_list, list) { if (&wk->bss->cbss == req->bss) { bssid = req->bss->bssid; @@ -2365,7 +2522,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return -ENOLINK; } - ieee80211_set_disassoc(sdata, req->bss->bssid, false); + ieee80211_set_disassoc(sdata); mutex_unlock(&ifmgd->mtx); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index fe6b990..b513fb7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -833,28 +833,22 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (!sta) return RX_CONTINUE; - /* Update last_rx only for IBSS packets which are for the current - * BSSID to avoid keeping the current IBSS network alive in cases where - * other STAs are using different BSSID. */ + /* + * Update last_rx only for IBSS packets which are for the current + * BSSID to avoid keeping the current IBSS network alive in cases + * where other STAs start using different BSSID. + */ if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, NL80211_IFTYPE_ADHOC); if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) sta->last_rx = jiffies; - } else - if (!is_multicast_ether_addr(hdr->addr1) || - rx->sdata->vif.type == NL80211_IFTYPE_STATION) { - /* Update last_rx only for unicast frames in order to prevent - * the Probe Request frames (the only broadcast frames from a - * STA in infrastructure mode) from keeping a connection alive. + } else if (!is_multicast_ether_addr(hdr->addr1)) { + /* * Mesh beacons will update last_rx when if they are found to * match the current local configuration when processed. */ - if (rx->sdata->vif.type == NL80211_IFTYPE_STATION && - ieee80211_is_beacon(hdr->frame_control)) { - rx->sdata->u.mgd.last_beacon = jiffies; - } else - sta->last_rx = jiffies; + sta->last_rx = jiffies; } if (!(rx->flags & IEEE80211_RX_RA_MATCH)) -- cgit v0.10.2 From ec3f149017ef3fd21343b1dcec3589eec6ba5dd5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 02:45:38 +0200 Subject: cfg80211: fix a locking bug The cfg80211_sme_disassoc() function is already holding a lock here that cfg80211_mlme_deauth() would take, so it needs to use __cfg80211_mlme_deauth() instead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/sme.c b/net/wireless/sme.c index d635a99..10ed366 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -826,8 +826,8 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx) return; memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); - if (cfg80211_mlme_deauth(rdev, dev, bssid, - NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) { + if (__cfg80211_mlme_deauth(rdev, dev, bssid, + NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) { /* whatever -- assume gone anyway */ cfg80211_unhold_bss(wdev->auth_bsses[idx]); cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); -- cgit v0.10.2 From a43816df2a1a61effcb701037bdf63621d066182 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 11:39:26 +0200 Subject: mac80211: mesh: fix two small problems 1) there's a spin_lock() that needs to be spin_lock_bh() 2) action frames of size 24 might cause an out-of-bounds memory access (for the 25th byte only, so no big deal) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 542ea02..8a97b14 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -685,9 +685,12 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) fc = le16_to_cpu(mgmt->frame_control); switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_ACTION: + if (skb->len < IEEE80211_MIN_ACTION_SIZE) + return RX_DROP_MONITOR; + /* fall through */ case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: - case IEEE80211_STYPE_ACTION: skb_queue_tail(&ifmsh->skb_queue, skb); queue_work(local->hw.workqueue, &ifmsh->work); return RX_QUEUED; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index f49ef28..8e86e91 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -686,11 +686,11 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) u8 ttl, dst_flags; u32 lifetime; - spin_lock(&ifmsh->mesh_preq_queue_lock); + spin_lock_bh(&ifmsh->mesh_preq_queue_lock); if (!ifmsh->preq_queue_len || time_before(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) { - spin_unlock(&ifmsh->mesh_preq_queue_lock); + spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); return; } @@ -698,7 +698,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) struct mesh_preq_queue, list); list_del(&preq_node->list); --ifmsh->preq_queue_len; - spin_unlock(&ifmsh->mesh_preq_queue_lock); + spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); rcu_read_lock(); mpath = mesh_path_lookup(preq_node->dst, sdata); -- cgit v0.10.2 From ca3dbc20d47ae43c201c215259d078e227bfcf01 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Fri, 10 Jul 2009 14:54:58 +0200 Subject: cfg80211: update misleading comment In cfg80211_scan_request n_channels refers to the total number of channels to scan. Update the misleading comment accordingly. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 65a5cbc..a981ca8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -538,7 +538,7 @@ struct cfg80211_ssid { * @ssids: SSIDs to scan for (active scan only) * @n_ssids: number of SSIDs * @channels: channels to scan on. - * @n_channels: number of channels for each band + * @n_channels: total number of channels to scan * @ie: optional information element(s) to add into Probe Request or %NULL * @ie_len: length of ie in octets * @wiphy: the wiphy this was for -- cgit v0.10.2 From c56c5714f12808e3f702817e72a78dd12f1704eb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 16:54:07 +0200 Subject: cfg80211: fix wext stats Instead of using the wext BSSID which may be NULL if you haven't explicitly set one, we should instead use the current_bss pointer -- if that's NULL we aren't connected anyway. Fixes missing signal quality output reported to me internally at Intel. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 5d01763..aa80c0c 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1209,7 +1209,7 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) /* we are under RTNL - globally locked - so can use static structs */ static struct iw_statistics wstats; static struct station_info sinfo; - u8 *addr; + u8 bssid[ETH_ALEN]; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) return NULL; @@ -1217,11 +1217,16 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) if (!rdev->ops->get_station) return NULL; - addr = wdev->wext.connect.bssid; - if (!addr) + /* Grab BSSID of current BSS, if any */ + wdev_lock(wdev); + if (!wdev->current_bss) { + wdev_unlock(wdev); return NULL; + } + memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); + wdev_unlock(wdev); - if (rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo)) + if (rdev->ops->get_station(&rdev->wiphy, dev, bssid, &sinfo)) return NULL; memset(&wstats, 0, sizeof(wstats)); -- cgit v0.10.2 From 4b14c96dfbf068acb85c3fa2446b3949c0230deb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 16:56:59 +0200 Subject: mac80211_hwsim: report fixed signal strength There's no reason to think that hwsim has any actual signal strength, but for testing it is very useful to have it report _some_ value to the stack so I can see if the value ends up being reported correctly Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index e9b5442..78431ab 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -406,7 +406,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, rx_status.freq = data->channel->center_freq; rx_status.band = data->channel->band; rx_status.rate_idx = info->control.rates[0].idx; - /* TODO: simulate signal strength (and optional packet drop) */ + /* TODO: simulate real signal strength (and optional packet loss) */ + rx_status.signal = -50; if (data->ps != PS_DISABLED) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); @@ -1024,7 +1025,8 @@ static int __init init_mac80211_hwsim(void) BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MESH_POINT); - hw->flags = IEEE80211_HW_MFP_CAPABLE; + hw->flags = IEEE80211_HW_MFP_CAPABLE | + IEEE80211_HW_SIGNAL_DBM; /* ask mac80211 to reserve space for magic */ hw->vif_data_size = sizeof(struct hwsim_vif_priv); -- cgit v0.10.2 From 908d4369a394e816767d566d9c3d15a5af8c1c55 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 17:53:34 +0200 Subject: cfg80211: don't look at wdev->ssid for giwessid This variable is only used internally, _while_ connected. If we use it, the sequence # iwconfig wlan1 essid foo # iwconfig wlan1 essid "" # iwconfig will still display "foo" as the SSID afterwards, which is obviously quite bogus. Fix this by only displaying the wext SSID, if present. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index c33ea9a..cd5764f 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -209,11 +209,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, data->flags = 0; wdev_lock(wdev); - if (wdev->ssid_len) { - data->flags = 1; - data->length = wdev->ssid_len; - memcpy(ssid, wdev->ssid, data->length); - } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { + if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { data->flags = 1; data->length = wdev->wext.connect.ssid_len; memcpy(ssid, wdev->wext.connect.ssid, data->length); -- cgit v0.10.2 From 4697fe4f78df14d37cffa7e8d27cbb02a351c139 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 18:35:49 +0200 Subject: cfg80211: fix wext setting SSID Pavel reported that you can't set the SSID from "foo" to "bar". I tried reproducing, but used different values, with different lengths, and thus never saw the obvious problem. Reported-by: Pavel Roskin Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index cd5764f..82e913a 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -166,7 +166,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, if (wdev->wext.connect.ssid && len && len == wdev->wext.connect.ssid_len && - memcmp(wdev->wext.connect.ssid, ssid, len)) + memcmp(wdev->wext.connect.ssid, ssid, len) == 0) goto out; if (wdev->sme_state != CFG80211_SME_IDLE) { -- cgit v0.10.2 From 48ab905d1a81b7df33a33def04a890e4e0c51460 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 18:42:31 +0200 Subject: nl80211: report BSS status When connected to a BSS, or joined to an IBSS, we'll want to know in userspace without using wireless extensions, so report the BSS status in the BSS list. Userspace can query the BSS list, display all the information and retrieve the station information as well. For example (from hwsim): $ iw dev wlan1 scan dump BSS 02:00:00:00:00:00 (on wlan1) -- associated freq: 2462 beacon interval: 100 capability: ESS ShortSlotTime (0x0401) signal: -50.00 dBm SSID: j Supported rates: 1.0* 2.0* 5.5* 11.0* 6.0 9.0 12.0 18.0 DS Paramater set: channel 11 ERP: Extended supported rates: 24.0 36.0 48.0 54.0 Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index b043b78..962e223 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1260,6 +1260,7 @@ enum nl80211_channel_type { * in mBm (100 * dBm) (s32) * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon * in unspecified units, scaled to 0..100 (u8) + * @NL80211_BSS_STATUS: status, if this BSS is "used" * @__NL80211_BSS_AFTER_LAST: internal * @NL80211_BSS_MAX: highest BSS attribute */ @@ -1273,6 +1274,7 @@ enum nl80211_bss { NL80211_BSS_INFORMATION_ELEMENTS, NL80211_BSS_SIGNAL_MBM, NL80211_BSS_SIGNAL_UNSPEC, + NL80211_BSS_STATUS, /* keep last */ __NL80211_BSS_AFTER_LAST, @@ -1280,6 +1282,15 @@ enum nl80211_bss { }; /** + * enum nl80211_bss_status - BSS "status" + */ +enum nl80211_bss_status { + NL80211_BSS_STATUS_AUTHENTICATED, + NL80211_BSS_STATUS_ASSOCIATED, + NL80211_BSS_STATUS_IBSS_JOINED, +}; + +/** * enum nl80211_auth_type - AuthenticationType * * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 45c5f9c..da450ef 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3094,11 +3094,15 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct cfg80211_registered_device *rdev, - struct net_device *dev, - struct cfg80211_bss *res) + struct wireless_dev *wdev, + struct cfg80211_internal_bss *intbss) { + struct cfg80211_bss *res = &intbss->pub; void *hdr; struct nlattr *bss; + int i; + + ASSERT_WDEV_LOCK(wdev); hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_SCAN_RESULTS); @@ -3107,7 +3111,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION, rdev->bss_generation); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); bss = nla_nest_start(msg, NL80211_ATTR_BSS); if (!bss) @@ -3136,6 +3140,28 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, break; } + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + if (intbss == wdev->current_bss) + NLA_PUT_U32(msg, NL80211_BSS_STATUS, + NL80211_BSS_STATUS_ASSOCIATED); + else for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (intbss != wdev->auth_bsses[i]) + continue; + NLA_PUT_U32(msg, NL80211_BSS_STATUS, + NL80211_BSS_STATUS_AUTHENTICATED); + break; + } + break; + case NL80211_IFTYPE_ADHOC: + if (intbss == wdev->current_bss) + NLA_PUT_U32(msg, NL80211_BSS_STATUS, + NL80211_BSS_STATUS_IBSS_JOINED); + break; + default: + break; + } + nla_nest_end(msg, bss); return genlmsg_end(msg, hdr); @@ -3148,9 +3174,10 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) { - struct cfg80211_registered_device *dev; - struct net_device *netdev; + struct cfg80211_registered_device *rdev; + struct net_device *dev; struct cfg80211_internal_bss *scan; + struct wireless_dev *wdev; int ifidx = cb->args[0]; int start = cb->args[1], idx = 0; int err; @@ -3171,39 +3198,43 @@ static int nl80211_dump_scan(struct sk_buff *skb, cb->args[0] = ifidx; } - netdev = dev_get_by_index(&init_net, ifidx); - if (!netdev) + dev = dev_get_by_index(&init_net, ifidx); + if (!dev) return -ENODEV; - dev = cfg80211_get_dev_from_ifindex(ifidx); - if (IS_ERR(dev)) { - err = PTR_ERR(dev); + rdev = cfg80211_get_dev_from_ifindex(ifidx); + if (IS_ERR(rdev)) { + err = PTR_ERR(rdev); goto out_put_netdev; } - spin_lock_bh(&dev->bss_lock); - cfg80211_bss_expire(dev); + wdev = dev->ieee80211_ptr; - list_for_each_entry(scan, &dev->bss_list, list) { + wdev_lock(wdev); + spin_lock_bh(&rdev->bss_lock); + cfg80211_bss_expire(rdev); + + list_for_each_entry(scan, &rdev->bss_list, list) { if (++idx <= start) continue; if (nl80211_send_bss(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - dev, netdev, &scan->pub) < 0) { + rdev, wdev, scan) < 0) { idx--; goto out; } } out: - spin_unlock_bh(&dev->bss_lock); + spin_unlock_bh(&rdev->bss_lock); + wdev_unlock(wdev); cb->args[1] = idx; err = skb->len; - cfg80211_unlock_rdev(dev); + cfg80211_unlock_rdev(rdev); out_put_netdev: - dev_put(netdev); + dev_put(dev); return err; } -- cgit v0.10.2 From 930c06f27120fa8cf0bfb6fa000a701cfaf01ed6 Mon Sep 17 00:00:00 2001 From: Stefan Steuerwald Date: Fri, 10 Jul 2009 20:42:55 +0200 Subject: rt2x00: Implement set_tim callback for all drivers Implement set_tim callback for all rt2x00 drivers, this makes the device wake up powersaving stations properly while in AP mode. The only way to update the beacon is by simply calling mac80211 and requesting the new beacon. This means the set_tim() event is mostly the same as a beacon_done() event which was already defined in rt2x00lib. Signed-off-by: Stefan Steuerwald Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index d8035e3..30185ad 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1561,6 +1561,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2400pci_conf_tx, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c123e28..3b31715 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1860,6 +1860,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 00611b3..de48c5c 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1896,6 +1896,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index a204e66..66e001c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2786,6 +2786,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .get_tkip_seq = rt2800usb_get_tkip_seq, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 71f37cb..3e17717 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -963,6 +963,8 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list); +int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set); #ifdef CONFIG_RT2X00_LIB_CRYPTO int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index b7e0ddd..3425984 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -454,6 +454,16 @@ static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len) sizeof(crypto->rx_mic)); } +int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt2x00lib_beacondone(rt2x00dev); + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_set_tim); + int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 8a49d99..b435c14 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2716,6 +2716,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ad2898c..4f9b177 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2241,6 +2241,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, -- cgit v0.10.2 From 596a07c18b35c9df2fb212856241ae0dfe3162b9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 11 Jul 2009 00:17:32 +0200 Subject: cfg80211: fix more bugs in mlme handling The "what-was-I-thinking-if-anything" patch. Clearly, if cfg80211_send_disassoc() does wdev_lock() and then calls __cfg80211_send_disassoc(), the latter shouldn't lock again. And the sme_state test is ... no further comments. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 8e4ce2f..5b9b221 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -178,12 +178,12 @@ static void __cfg80211_send_disassoc(struct net_device *dev, bool from_ap; bool done = false; - wdev_lock(wdev); + ASSERT_WDEV_LOCK(wdev); nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); - if (!wdev->sme_state == CFG80211_SME_CONNECTED) - goto out; + if (wdev->sme_state != CFG80211_SME_CONNECTED) + return; if (wdev->current_bss && memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) { @@ -205,8 +205,6 @@ static void __cfg80211_send_disassoc(struct net_device *dev, from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); - out: - wdev_unlock(wdev); } void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, -- cgit v0.10.2 From 1a9b6679adfb8ef1f1f3dbb7ebd2ee72e2ea4b56 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 11 Jul 2009 01:22:26 +0200 Subject: p54: generate channel list dynamically This patch enhances the eeprom parser to generate customized channel list for every device. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index a2a044e..549ef2d 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -41,30 +42,6 @@ static struct ieee80211_rate p54_bgrates[] = { { .bitrate = 540, .hw_value = 11, }, }; -static struct ieee80211_channel p54_bgchannels[] = { - { .center_freq = 2412, .hw_value = 1, }, - { .center_freq = 2417, .hw_value = 2, }, - { .center_freq = 2422, .hw_value = 3, }, - { .center_freq = 2427, .hw_value = 4, }, - { .center_freq = 2432, .hw_value = 5, }, - { .center_freq = 2437, .hw_value = 6, }, - { .center_freq = 2442, .hw_value = 7, }, - { .center_freq = 2447, .hw_value = 8, }, - { .center_freq = 2452, .hw_value = 9, }, - { .center_freq = 2457, .hw_value = 10, }, - { .center_freq = 2462, .hw_value = 11, }, - { .center_freq = 2467, .hw_value = 12, }, - { .center_freq = 2472, .hw_value = 13, }, - { .center_freq = 2484, .hw_value = 14, }, -}; - -static struct ieee80211_supported_band band_2GHz = { - .channels = p54_bgchannels, - .n_channels = ARRAY_SIZE(p54_bgchannels), - .bitrates = p54_bgrates, - .n_bitrates = ARRAY_SIZE(p54_bgrates), -}; - static struct ieee80211_rate p54_arates[] = { { .bitrate = 60, .hw_value = 4, }, { .bitrate = 90, .hw_value = 5, }, @@ -76,51 +53,257 @@ static struct ieee80211_rate p54_arates[] = { { .bitrate = 540, .hw_value = 11, }, }; -static struct ieee80211_channel p54_achannels[] = { - { .center_freq = 4920 }, - { .center_freq = 4940 }, - { .center_freq = 4960 }, - { .center_freq = 4980 }, - { .center_freq = 5040 }, - { .center_freq = 5060 }, - { .center_freq = 5080 }, - { .center_freq = 5170 }, - { .center_freq = 5180 }, - { .center_freq = 5190 }, - { .center_freq = 5200 }, - { .center_freq = 5210 }, - { .center_freq = 5220 }, - { .center_freq = 5230 }, - { .center_freq = 5240 }, - { .center_freq = 5260 }, - { .center_freq = 5280 }, - { .center_freq = 5300 }, - { .center_freq = 5320 }, - { .center_freq = 5500 }, - { .center_freq = 5520 }, - { .center_freq = 5540 }, - { .center_freq = 5560 }, - { .center_freq = 5580 }, - { .center_freq = 5600 }, - { .center_freq = 5620 }, - { .center_freq = 5640 }, - { .center_freq = 5660 }, - { .center_freq = 5680 }, - { .center_freq = 5700 }, - { .center_freq = 5745 }, - { .center_freq = 5765 }, - { .center_freq = 5785 }, - { .center_freq = 5805 }, - { .center_freq = 5825 }, +#define CHAN_HAS_CAL BIT(0) +#define CHAN_HAS_LIMIT BIT(1) +#define CHAN_HAS_CURVE BIT(2) +#define CHAN_HAS_ALL (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE) + +struct p54_channel_entry { + u16 freq; + u16 data; + int index; + enum ieee80211_band band; }; -static struct ieee80211_supported_band band_5GHz = { - .channels = p54_achannels, - .n_channels = ARRAY_SIZE(p54_achannels), - .bitrates = p54_arates, - .n_bitrates = ARRAY_SIZE(p54_arates), +struct p54_channel_list { + struct p54_channel_entry *channels; + size_t entries; + size_t max_entries; + size_t band_channel_num[IEEE80211_NUM_BANDS]; }; +static int p54_get_band_from_freq(u16 freq) +{ + /* FIXME: sync these values with the 802.11 spec */ + + if ((freq >= 2412) && (freq <= 2484)) + return IEEE80211_BAND_2GHZ; + + if ((freq >= 4920) && (freq <= 5825)) + return IEEE80211_BAND_5GHZ; + + return -1; +} + +static int p54_compare_channels(const void *_a, + const void *_b) +{ + const struct p54_channel_entry *a = _a; + const struct p54_channel_entry *b = _b; + + return a->index - b->index; +} + +static int p54_fill_band_bitrates(struct ieee80211_hw *dev, + struct ieee80211_supported_band *band_entry, + enum ieee80211_band band) +{ + /* TODO: generate rate array dynamically */ + + switch (band) { + case IEEE80211_BAND_2GHZ: + band_entry->bitrates = p54_bgrates; + band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates); + break; + case IEEE80211_BAND_5GHZ: + band_entry->bitrates = p54_arates; + band_entry->n_bitrates = ARRAY_SIZE(p54_arates); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int p54_generate_band(struct ieee80211_hw *dev, + struct p54_channel_list *list, + enum ieee80211_band band) +{ + struct p54_common *priv = dev->priv; + struct ieee80211_supported_band *tmp, *old; + unsigned int i, j; + int ret = -ENOMEM; + + if ((!list->entries) || (!list->band_channel_num[band])) + return 0; + + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + goto err_out; + + tmp->channels = kzalloc(sizeof(struct ieee80211_channel) * + list->band_channel_num[band], GFP_KERNEL); + if (!tmp->channels) + goto err_out; + + ret = p54_fill_band_bitrates(dev, tmp, band); + if (ret) + goto err_out; + + for (i = 0, j = 0; (j < list->band_channel_num[band]) && + (i < list->entries); i++) { + + if (list->channels[i].band != band) + continue; + + if (list->channels[i].data != CHAN_HAS_ALL) { + printk(KERN_ERR "%s:%s%s%s is/are missing for " + "channel:%d [%d MHz].\n", + wiphy_name(dev->wiphy), + (list->channels[i].data & CHAN_HAS_CAL ? "" : + " [iqauto calibration data]"), + (list->channels[i].data & CHAN_HAS_LIMIT ? "" : + " [output power limits]"), + (list->channels[i].data & CHAN_HAS_CURVE ? "" : + " [curve data]"), + list->channels[i].index, list->channels[i].freq); + } + + tmp->channels[j].band = list->channels[i].band; + tmp->channels[j].center_freq = list->channels[i].freq; + j++; + } + + tmp->n_channels = list->band_channel_num[band]; + old = priv->band_table[band]; + priv->band_table[band] = tmp; + if (old) { + kfree(old->channels); + kfree(old); + } + + return 0; + +err_out: + if (tmp) { + kfree(tmp->channels); + kfree(tmp); + } + + return ret; +} + +static void p54_update_channel_param(struct p54_channel_list *list, + u16 freq, u16 data) +{ + int band, i; + + /* + * usually all lists in the eeprom are mostly sorted. + * so it's very likely that the entry we are looking for + * is right at the end of the list + */ + for (i = list->entries; i >= 0; i--) { + if (freq == list->channels[i].freq) { + list->channels[i].data |= data; + break; + } + } + + if ((i < 0) && (list->entries < list->max_entries)) { + /* entry does not exist yet. Initialize a new one. */ + band = p54_get_band_from_freq(freq); + + /* + * filter out frequencies which don't belong into + * any supported band. + */ + if (band < 0) + return ; + + i = list->entries++; + list->band_channel_num[band]++; + + list->channels[i].freq = freq; + list->channels[i].data = data; + list->channels[i].band = band; + list->channels[i].index = ieee80211_frequency_to_channel(freq); + /* TODO: parse output_limit and fill max_power */ + } +} + +static int p54_generate_channel_lists(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct p54_channel_list *list; + unsigned int i, j, max_channel_num; + int ret = -ENOMEM; + u16 freq; + + if ((priv->iq_autocal_len != priv->curve_data->entries) || + (priv->iq_autocal_len != priv->output_limit->entries)) + printk(KERN_ERR "%s: EEPROM is damaged... you may not be able" + "to use all channels with this device.\n", + wiphy_name(dev->wiphy)); + + max_channel_num = max_t(unsigned int, priv->output_limit->entries, + priv->iq_autocal_len); + max_channel_num = max_t(unsigned int, max_channel_num, + priv->curve_data->entries); + + list = kzalloc(sizeof(*list), GFP_KERNEL); + if (!list) + goto free; + + list->max_entries = max_channel_num; + list->channels = kzalloc(sizeof(struct p54_channel_entry) * + max_channel_num, GFP_KERNEL); + if (!list->channels) + goto free; + + for (i = 0; i < max_channel_num; i++) { + if (i < priv->iq_autocal_len) { + freq = le16_to_cpu(priv->iq_autocal[i].freq); + p54_update_channel_param(list, freq, CHAN_HAS_CAL); + } + + if (i < priv->output_limit->entries) { + freq = le16_to_cpup((__le16 *) (i * + priv->output_limit->entry_size + + priv->output_limit->offset + + priv->output_limit->data)); + + p54_update_channel_param(list, freq, CHAN_HAS_LIMIT); + } + + if (i < priv->curve_data->entries) { + freq = le16_to_cpup((__le16 *) (i * + priv->curve_data->entry_size + + priv->curve_data->offset + + priv->curve_data->data)); + + p54_update_channel_param(list, freq, CHAN_HAS_CURVE); + } + } + + /* sort the list by the channel index */ + sort(list->channels, list->entries, sizeof(struct p54_channel_entry), + p54_compare_channels, NULL); + + for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) { + if (list->band_channel_num[i]) { + ret = p54_generate_band(dev, list, i); + if (ret) + goto free; + + j++; + } + } + if (j == 0) { + /* no useable band available. */ + ret = -EINVAL; + } + +free: + if (list) { + kfree(list->channels); + kfree(list); + } + + return ret; +} + static int p54_convert_rev0(struct ieee80211_hw *dev, struct pda_pa_curve_data *curve_data) { @@ -487,13 +670,19 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) goto err; } + err = p54_generate_channel_lists(dev); + if (err) + goto err; + priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) p54_init_xbow_synth(priv); if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) - dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = + priv->band_table[IEEE80211_BAND_2GHZ]; if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) - dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; + dev->wiphy->bands[IEEE80211_BAND_5GHZ] = + priv->band_table[IEEE80211_BAND_5GHZ]; if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED) priv->rx_diversity_mask = 3; if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED) diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index c9a0545..f19add2 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -598,6 +598,10 @@ EXPORT_SYMBOL_GPL(p54_register_common); void p54_free_common(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; + unsigned int i; + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + kfree(priv->band_table[i]); kfree(priv->iq_autocal); kfree(priv->output_limit); diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 6772ed5..584b156 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -198,6 +198,7 @@ struct p54_common { struct p54_cal_database *curve_data; struct p54_cal_database *output_limit; struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; + struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS]; /* BBP/MAC state */ u8 mac_addr[ETH_ALEN]; -- cgit v0.10.2 From acbadf01ff6727a2c7dc6e12f70ce8d05a16dc06 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 11 Jul 2009 17:24:14 +0200 Subject: ar9170: implement transmit aggregation This patch roughly implements xmit aggregation for ar9170-like device. Not all AP are compatible with the driver(and firmware) yet, so YMMV. A more refined code will definitely need the final HT specification to be available for the public, lots of firmware modification and possibly a redesigned driver just for good measure. Sadly, these conditions won't come true anytime soon... Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index bb97981..e6c3ee3 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -109,11 +109,52 @@ struct ar9170_rxstream_mpdu_merge { bool has_plcp; }; +#define AR9170_NUM_MAX_BA_RETRY 5 +#define AR9170_NUM_TID 16 +#define WME_BA_BMP_SIZE 64 +#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE) + +#define WME_AC_BE 2 +#define WME_AC_BK 3 +#define WME_AC_VI 1 +#define WME_AC_VO 0 + +#define TID_TO_WME_AC(_tid) \ + ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ + (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ + (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ + WME_AC_VO) + +#define BAW_WITHIN(_start, _bawsz, _seqno) \ + ((((_seqno) - (_start)) & 0xfff) < (_bawsz)) + +enum ar9170_tid_state { + AR9170_TID_STATE_INVALID, + AR9170_TID_STATE_SHUTDOWN, + AR9170_TID_STATE_PROGRESS, + AR9170_TID_STATE_COMPLETE, +}; + +struct ar9170_sta_tid { + struct list_head list; + struct sk_buff_head queue; + u8 addr[ETH_ALEN]; + u16 ssn; + u16 tid; + enum ar9170_tid_state state; + bool active; + u8 retry; +}; + #define AR9170_QUEUE_TIMEOUT 64 #define AR9170_TX_TIMEOUT 8 +#define AR9170_BA_TIMEOUT 4 #define AR9170_JANITOR_DELAY 128 #define AR9170_TX_INVALID_RATE 0xffffffff +#define AR9170_NUM_TX_STATUS 128 +#define AR9170_NUM_TX_AGG_MAX 30 + struct ar9170 { struct ieee80211_hw *hw; struct mutex mutex; @@ -187,14 +228,25 @@ struct ar9170 { struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; struct delayed_work tx_janitor; + /* tx ampdu */ + struct sk_buff_head tx_status_ampdu; + spinlock_t tx_ampdu_list_lock; + struct list_head tx_ampdu_list; + unsigned int tx_ampdu_pending; /* rxstream mpdu merge */ struct ar9170_rxstream_mpdu_merge rx_mpdu; struct sk_buff *rx_failover; int rx_failover_missing; + + /* (cached) HW A-MPDU settings */ + u8 global_ampdu_density; + u8 global_ampdu_factor; }; struct ar9170_sta_info { + struct ar9170_sta_tid agg[AR9170_NUM_TID]; + unsigned int ampdu_max_len; }; #define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0) diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 51753ed..cfe6fc7 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -49,6 +49,10 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +static int modparam_ht; +module_param_named(ht, modparam_ht, bool, S_IRUGO); +MODULE_PARM_DESC(ht, "enable MPDU aggregation."); + #define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ .bitrate = (_bitrate), \ .flags = (_flags), \ @@ -148,12 +152,15 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = { .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ IEEE80211_HT_CAP_SGI_40 | \ + IEEE80211_HT_CAP_GRN_FLD | \ IEEE80211_HT_CAP_DSSSCCK40 | \ IEEE80211_HT_CAP_SM_PS, \ .ampdu_factor = 3, \ .ampdu_density = 6, \ .mcs = { \ - .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \ + .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \ + .rx_highest = cpu_to_le16(300), \ + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ }, \ } @@ -174,8 +181,31 @@ static struct ieee80211_supported_band ar9170_band_5GHz = { }; static void ar9170_tx(struct ar9170 *ar); +static bool ar9170_tx_ampdu(struct ar9170 *ar); -#ifdef AR9170_QUEUE_DEBUG +static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr) +{ + return le16_to_cpu(hdr->seq_ctrl) >> 4; +} + +static inline u16 ar9170_get_seq(struct sk_buff *skb) +{ + struct ar9170_tx_control *txc = (void *) skb->data; + return ar9170_get_seq_h((void *) txc->frame_data); +} + +static inline u16 ar9170_get_tid(struct sk_buff *skb) +{ + struct ar9170_tx_control *txc = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) txc->frame_data; + + return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; +} + +#define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff) +#define GET_NEXT_SEQ_FROM_SKB(skb) (GET_NEXT_SEQ(ar9170_get_seq(skb))) + +#if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG) static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) { struct ar9170_tx_control *txc = (void *) skb->data; @@ -183,10 +213,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; struct ieee80211_hdr *hdr = (void *) txc->frame_data; - printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x " + printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d " "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), arinfo->flags, + ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr), le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), jiffies_to_msecs(arinfo->timeout - jiffies)); } @@ -210,7 +240,9 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar, "mismatch %d != %d\n", skb_queue_len(queue), i); printk(KERN_DEBUG "---[ end ]---\n"); } +#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */ +#ifdef AR9170_QUEUE_DEBUG static void ar9170_dump_txqueue(struct ar9170 *ar, struct sk_buff_head *queue) { @@ -220,7 +252,9 @@ static void ar9170_dump_txqueue(struct ar9170 *ar, __ar9170_dump_txqueue(ar, queue); spin_unlock_irqrestore(&queue->lock, flags); } +#endif /* AR9170_QUEUE_DEBUG */ +#ifdef AR9170_QUEUE_STOP_DEBUG static void __ar9170_dump_txstats(struct ar9170 *ar) { int i; @@ -229,20 +263,27 @@ static void __ar9170_dump_txstats(struct ar9170 *ar) wiphy_name(ar->hw->wiphy)); for (i = 0; i < __AR9170_NUM_TXQ; i++) - printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n", - wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit, - ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i])); + printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d " + " stopped:%d\n", wiphy_name(ar->hw->wiphy), i, + ar->tx_stats[i].limit, ar->tx_stats[i].len, + skb_queue_len(&ar->tx_status[i]), + ieee80211_queue_stopped(ar->hw, i)); } +#endif /* AR9170_QUEUE_STOP_DEBUG */ -static void ar9170_dump_txstats(struct ar9170 *ar) +#ifdef AR9170_TXAGG_DEBUG +static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar) { unsigned long flags; - spin_lock_irqsave(&ar->tx_stats_lock, flags); - __ar9170_dump_txstats(ar); - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags); + printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n", + wiphy_name(ar->hw->wiphy)); + __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu); + spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags); } -#endif /* AR9170_QUEUE_DEBUG */ + +#endif /* AR9170_TXAGG_DEBUG */ /* caller must guarantee exclusive access for _bin_ queue. */ static void ar9170_recycle_expired(struct ar9170 *ar, @@ -315,6 +356,70 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, ieee80211_tx_status_irqsafe(ar->hw, skb); } +static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar) +{ + struct sk_buff_head success; + struct sk_buff *skb; + unsigned int i; + unsigned long queue_bitmap = 0; + + skb_queue_head_init(&success); + + while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS) + __skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu)); + + ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success); + +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n", + wiphy_name(ar->hw->wiphy), skb_queue_len(&success)); + __ar9170_dump_txqueue(ar, &success); +#endif /* AR9170_TXAGG_DEBUG */ + + while ((skb = __skb_dequeue(&success))) { + struct ieee80211_tx_info *txinfo; + + queue_bitmap |= BIT(skb_get_queue_mapping(skb)); + + txinfo = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(txinfo); + + txinfo->flags |= IEEE80211_TX_STAT_ACK; + txinfo->status.rates[0].count = 1; + + skb_pull(skb, sizeof(struct ar9170_tx_control)); + ieee80211_tx_status_irqsafe(ar->hw, skb); + } + + for_each_bit(i, &queue_bitmap, BITS_PER_BYTE) { +#ifdef AR9170_QUEUE_STOP_DEBUG + printk(KERN_DEBUG "%s: wake queue %d\n", + wiphy_name(ar->hw->wiphy), i); + __ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_STOP_DEBUG */ + ieee80211_wake_queue(ar->hw, i); + } + + if (queue_bitmap) + ar9170_tx(ar); +} + +static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); + struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; + + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_BA_TIMEOUT); + + skb_queue_tail(&ar->tx_status_ampdu, skb); + ar9170_tx_fake_ampdu_status(ar); + ar->tx_ampdu_pending--; + + if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending) + ar9170_tx_ampdu(ar); +} + void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -336,7 +441,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) spin_unlock_irqrestore(&ar->tx_stats_lock, flags); if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) { - dev_kfree_skb_any(skb); + ar9170_tx_ampdu_callback(ar, skb); } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) { arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_TX_TIMEOUT); @@ -420,6 +525,38 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, return NULL; } +static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r) +{ + struct sk_buff *skb; + struct ieee80211_tx_info *txinfo; + + while (count) { + skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r); + if (!skb) + break; + + txinfo = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(txinfo); + + /* FIXME: maybe more ? */ + txinfo->status.rates[0].count = 1; + + skb_pull(skb, sizeof(struct ar9170_tx_control)); + ieee80211_tx_status_irqsafe(ar->hw, skb); + count--; + } + +#ifdef AR9170_TXAGG_DEBUG + if (count) { + printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more " + "suitable frames left in tx_status queue.\n", + wiphy_name(ar->hw->wiphy), count); + + ar9170_dump_tx_status_ampdu(ar); + } +#endif /* AR9170_TXAGG_DEBUG */ +} + /* * This worker tries to keeps an maintain tx_status queues. * So we can guarantee that incoming tx_status reports are @@ -456,6 +593,8 @@ static void ar9170_tx_janitor(struct work_struct *work) resched = true; } + ar9170_tx_fake_ampdu_status(ar); + if (resched) queue_delayed_work(ar->hw->workqueue, &ar->tx_janitor, @@ -528,8 +667,15 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) break; case 0xc4: + /* BlockACK bitmap */ + break; + case 0xc5: /* BlockACK events */ + ar9170_handle_block_ack(ar, + le16_to_cpu(cmd->ba_fail_cnt.failed), + le16_to_cpu(cmd->ba_fail_cnt.rate)); + ar9170_tx_fake_ampdu_status(ar); break; case 0xc6: @@ -1098,6 +1244,10 @@ static int ar9170_op_start(struct ieee80211_hw *hw) AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ + /* set sane AMPDU defaults */ + ar->global_ampdu_density = 6; + ar->global_ampdu_factor = 3; + ar->bad_hw_nagger = jiffies; err = ar->open(ar); @@ -1143,6 +1293,7 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) flush_workqueue(ar->hw->workqueue); cancel_delayed_work_sync(&ar->tx_janitor); + cancel_delayed_work_sync(&ar->led_work); cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); mutex_lock(&ar->mutex); @@ -1159,9 +1310,40 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) skb_queue_purge(&ar->tx_pending[i]); skb_queue_purge(&ar->tx_status[i]); } + skb_queue_purge(&ar->tx_status_ampdu); + mutex_unlock(&ar->mutex); } +static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ar9170_tx_control *txc = (void *) skb->data; + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU); +} + +static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst, + struct sk_buff *src) +{ + struct ar9170_tx_control *dst_txc, *src_txc; + struct ieee80211_tx_info *dst_info, *src_info; + struct ar9170_tx_info *dst_arinfo, *src_arinfo; + + src_txc = (void *) src->data; + src_info = IEEE80211_SKB_CB(src); + src_arinfo = (void *) src_info->rate_driver_data; + + dst_txc = (void *) dst->data; + dst_info = IEEE80211_SKB_CB(dst); + dst_arinfo = (void *) dst_info->rate_driver_data; + + dst_txc->phy_control = src_txc->phy_control; + + /* same MCS for the whole aggregate */ + memcpy(dst_info->driver_rates, src_info->driver_rates, + sizeof(dst_info->driver_rates)); +} + static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) { struct ieee80211_hdr *hdr; @@ -1230,6 +1412,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK; + goto out; } @@ -1360,6 +1543,159 @@ static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); } +static bool ar9170_tx_ampdu(struct ar9170 *ar) +{ + struct sk_buff_head agg; + struct ar9170_sta_tid *tid_info = NULL, *tmp; + struct sk_buff *skb, *first = NULL; + unsigned long flags, f2; + unsigned int i = 0; + u16 seq, queue, tmpssn; + bool run = false; + + skb_queue_head_init(&agg); + + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + if (list_empty(&ar->tx_ampdu_list)) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: aggregation list is empty.\n", + wiphy_name(ar->hw->wiphy)); +#endif /* AR9170_TXAGG_DEBUG */ + goto out_unlock; + } + + list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) { + if (tid_info->state != AR9170_TID_STATE_COMPLETE) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: dangling aggregation entry!\n", + wiphy_name(ar->hw->wiphy)); +#endif /* AR9170_TXAGG_DEBUG */ + continue; + } + + if (++i > 64) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: enough frames aggregated.\n", + wiphy_name(ar->hw->wiphy)); +#endif /* AR9170_TXAGG_DEBUG */ + break; + } + + queue = TID_TO_WME_AC(tid_info->tid); + + if (skb_queue_len(&ar->tx_pending[queue]) >= + AR9170_NUM_TX_AGG_MAX) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: queue %d full.\n", + wiphy_name(ar->hw->wiphy), queue); +#endif /* AR9170_TXAGG_DEBUG */ + continue; + } + + list_del_init(&tid_info->list); + + spin_lock_irqsave(&tid_info->queue.lock, f2); + tmpssn = seq = tid_info->ssn; + first = skb_peek(&tid_info->queue); + + if (likely(first)) + tmpssn = ar9170_get_seq(first); + + if (unlikely(tmpssn != seq)) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.", + wiphy_name(ar->hw->wiphy), seq, tmpssn); +#endif /* AR9170_TXAGG_DEBUG */ + tid_info->ssn = tmpssn; + } + +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with " + "%d queued frames.\n", wiphy_name(ar->hw->wiphy), + tid_info->tid, tid_info->ssn, + skb_queue_len(&tid_info->queue)); + __ar9170_dump_txqueue(ar, &tid_info->queue); +#endif /* AR9170_TXAGG_DEBUG */ + + while ((skb = skb_peek(&tid_info->queue))) { + if (unlikely(ar9170_get_seq(skb) != seq)) + break; + + __skb_unlink(skb, &tid_info->queue); + tid_info->ssn = seq = GET_NEXT_SEQ(seq); + + if (unlikely(skb_get_queue_mapping(skb) != queue)) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d " + "!match.\n", wiphy_name(ar->hw->wiphy), + tid_info->tid, + TID_TO_WME_AC(tid_info->tid), + skb_get_queue_mapping(skb)); +#endif /* AR9170_TXAGG_DEBUG */ + dev_kfree_skb_any(skb); + continue; + } + + if (unlikely(first == skb)) { + ar9170_tx_prepare_phy(ar, skb); + __skb_queue_tail(&agg, skb); + first = skb; + } else { + ar9170_tx_copy_phy(ar, skb, first); + __skb_queue_tail(&agg, skb); + } + + if (unlikely(skb_queue_len(&agg) == + AR9170_NUM_TX_AGG_MAX)) + break; + } + + if (skb_queue_empty(&tid_info->queue)) + tid_info->active = false; + else + list_add_tail(&tid_info->list, + &ar->tx_ampdu_list); + + spin_unlock_irqrestore(&tid_info->queue.lock, f2); + + if (unlikely(skb_queue_empty(&agg))) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: queued empty list!\n", + wiphy_name(ar->hw->wiphy)); +#endif /* AR9170_TXAGG_DEBUG */ + continue; + } + + /* + * tell the FW/HW that this is the last frame, + * that way it will wait for the immediate block ack. + */ + if (likely(skb_peek_tail(&agg))) + ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg)); + +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n", + wiphy_name(ar->hw->wiphy)); + __ar9170_dump_txqueue(ar, &agg); +#endif /* AR9170_TXAGG_DEBUG */ + + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + + spin_lock_irqsave(&ar->tx_pending[queue].lock, flags); + skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]); + spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags); + run = true; + + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + } + +out_unlock: + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + __skb_queue_purge(&agg); + + return run; +} + static void ar9170_tx(struct ar9170 *ar) { struct sk_buff *skb; @@ -1384,11 +1720,17 @@ static void ar9170_tx(struct ar9170 *ar) printk(KERN_DEBUG "%s: queue %d full\n", wiphy_name(ar->hw->wiphy), i); - __ar9170_dump_txstats(ar); - printk(KERN_DEBUG "stuck frames: ===> \n"); + printk(KERN_DEBUG "%s: stuck frames: ===> \n", + wiphy_name(ar->hw->wiphy)); ar9170_dump_txqueue(ar, &ar->tx_pending[i]); ar9170_dump_txqueue(ar, &ar->tx_status[i]); #endif /* AR9170_QUEUE_DEBUG */ + +#ifdef AR9170_QUEUE_STOP_DEBUG + printk(KERN_DEBUG "%s: stop queue %d\n", + wiphy_name(ar->hw->wiphy), i); + __ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_STOP_DEBUG */ ieee80211_stop_queue(ar->hw, i); spin_unlock_irqrestore(&ar->tx_stats_lock, flags); continue; @@ -1403,8 +1745,6 @@ static void ar9170_tx(struct ar9170 *ar) "remaining slots:%d, needed:%d\n", wiphy_name(ar->hw->wiphy), i, remaining_space, frames); - - ar9170_dump_txstats(ar); #endif /* AR9170_QUEUE_DEBUG */ frames = remaining_space; } @@ -1432,6 +1772,9 @@ static void ar9170_tx(struct ar9170 *ar) arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_TX_TIMEOUT); + if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) + ar->tx_ampdu_pending++; + #ifdef AR9170_QUEUE_DEBUG printk(KERN_DEBUG "%s: send frame q:%d =>\n", wiphy_name(ar->hw->wiphy), i); @@ -1440,6 +1783,9 @@ static void ar9170_tx(struct ar9170 *ar) err = ar->tx(ar, skb); if (unlikely(err)) { + if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) + ar->tx_ampdu_pending--; + frames_failed++; dev_kfree_skb_any(skb); } else { @@ -1461,13 +1807,18 @@ static void ar9170_tx(struct ar9170 *ar) if (unlikely(frames_failed)) { #ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: frames failed =>\n", + printk(KERN_DEBUG "%s: frames failed %d =>\n", wiphy_name(ar->hw->wiphy), frames_failed); #endif /* AR9170_QUEUE_DEBUG */ spin_lock_irqsave(&ar->tx_stats_lock, flags); ar->tx_stats[i].len -= frames_failed; ar->tx_stats[i].count -= frames_failed; +#ifdef AR9170_QUEUE_STOP_DEBUG + printk(KERN_DEBUG "%s: wake queue %d\n", + wiphy_name(ar->hw->wiphy), i); + __ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_STOP_DEBUG */ ieee80211_wake_queue(ar->hw, i); spin_unlock_irqrestore(&ar->tx_stats_lock, flags); } @@ -1479,6 +1830,90 @@ static void ar9170_tx(struct ar9170 *ar) msecs_to_jiffies(AR9170_JANITOR_DELAY)); } +static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ieee80211_tx_info *txinfo; + struct ar9170_sta_info *sta_info; + struct ar9170_sta_tid *agg; + struct sk_buff *iter; + unsigned long flags, f2; + unsigned int max; + u16 tid, seq, qseq; + bool run = false, queue = false; + + tid = ar9170_get_tid(skb); + seq = ar9170_get_seq(skb); + txinfo = IEEE80211_SKB_CB(skb); + sta_info = (void *) txinfo->control.sta->drv_priv; + agg = &sta_info->agg[tid]; + max = sta_info->ampdu_max_len; + + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + + if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: BlockACK session not fully initialized " + "for ESS:%pM tid:%d state:%d.\n", + wiphy_name(ar->hw->wiphy), agg->addr, agg->tid, + agg->state); +#endif /* AR9170_TXAGG_DEBUG */ + goto err_unlock; + } + + if (!agg->active) { + agg->active = true; + agg->ssn = seq; + queue = true; + } + + /* check if seq is within the BA window */ + if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not " + "fit into BA window (%d - %d)\n", + wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn, + (agg->ssn + max) & 0xfff); +#endif /* AR9170_TXAGG_DEBUG */ + goto err_unlock; + } + + spin_lock_irqsave(&agg->queue.lock, f2); + + skb_queue_reverse_walk(&agg->queue, iter) { + qseq = ar9170_get_seq(iter); + + if (GET_NEXT_SEQ(qseq) == seq) { + __skb_queue_after(&agg->queue, iter, skb); + goto queued; + } + } + + __skb_queue_head(&agg->queue, skb); + +queued: + spin_unlock_irqrestore(&agg->queue.lock, f2); + +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: new aggregate %p queued.\n", + wiphy_name(ar->hw->wiphy), skb); + __ar9170_dump_txqueue(ar, &agg->queue); +#endif /* AR9170_TXAGG_DEBUG */ + + if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX) + run = true; + + if (queue) + list_add_tail(&agg->list, &ar->tx_ampdu_list); + + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + return run; + +err_unlock: + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + dev_kfree_skb_irq(skb); + return false; +} + int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ar9170 *ar = hw->priv; @@ -1492,8 +1927,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) info = IEEE80211_SKB_CB(skb); if (info->flags & IEEE80211_TX_CTL_AMPDU) { - /* drop frame, we do not allow TX A-MPDU aggregation yet. */ - goto err_free; + bool run = ar9170_tx_ampdu_queue(ar, skb); + + if (run || !ar->tx_ampdu_pending) + ar9170_tx_ampdu(ar); } else { unsigned int queue = skb_get_queue_mapping(skb); @@ -1931,6 +2368,53 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { + struct ar9170 *ar = hw->priv; + struct ar9170_sta_info *sta_info = (void *) sta->drv_priv; + unsigned int i; + + switch (cmd) { + case STA_NOTIFY_ADD: + memset(sta_info, 0, sizeof(*sta_info)); + + if (!sta->ht_cap.ht_supported) + break; + + if (sta->ht_cap.ampdu_density > ar->global_ampdu_density) + ar->global_ampdu_density = sta->ht_cap.ampdu_density; + + if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor) + ar->global_ampdu_factor = sta->ht_cap.ampdu_factor; + + for (i = 0; i < AR9170_NUM_TID; i++) { + sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN; + sta_info->agg[i].active = false; + sta_info->agg[i].ssn = 0; + sta_info->agg[i].retry = 0; + sta_info->agg[i].tid = i; + INIT_LIST_HEAD(&sta_info->agg[i].list); + skb_queue_head_init(&sta_info->agg[i].queue); + } + + sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor); + break; + + case STA_NOTIFY_REMOVE: + if (!sta->ht_cap.ht_supported) + break; + + for (i = 0; i < AR9170_NUM_TID; i++) { + sta_info->agg[i].state = AR9170_TID_STATE_INVALID; + skb_queue_purge(&sta_info->agg[i].queue); + } + + break; + + default: + break; + } + + if (IS_STARTED(ar) && ar->filter_changed) + queue_work(ar->hw->workqueue, &ar->filter_config_work); } static int ar9170_get_stats(struct ieee80211_hw *hw, @@ -1985,18 +2469,65 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { + struct ar9170 *ar = hw->priv; + struct ar9170_sta_info *sta_info = (void *) sta->drv_priv; + struct ar9170_sta_tid *tid_info = &sta_info->agg[tid]; + unsigned long flags; + + if (!modparam_ht) + return -EOPNOTSUPP; + switch (action) { + case IEEE80211_AMPDU_TX_START: + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + if (tid_info->state != AR9170_TID_STATE_SHUTDOWN || + !list_empty(&tid_info->list)) { + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] " + "is in a very bad state!\n", + wiphy_name(hw->wiphy), sta->addr, tid); +#endif /* AR9170_TXAGG_DEBUG */ + return -EBUSY; + } + + *ssn = tid_info->ssn; + tid_info->state = AR9170_TID_STATE_PROGRESS; + tid_info->active = false; + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + break; + + case IEEE80211_AMPDU_TX_STOP: + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + tid_info->state = AR9170_TID_STATE_SHUTDOWN; + list_del_init(&tid_info->list); + tid_info->active = false; + skb_queue_purge(&tid_info->queue); + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); + break; + + case IEEE80211_AMPDU_TX_OPERATIONAL: +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n", + wiphy_name(hw->wiphy), sta->addr, tid); +#endif /* AR9170_TXAGG_DEBUG */ + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE; + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + break; + case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_STOP: - /* - * Something goes wrong -- RX locks up - * after a while of receiving aggregated - * frames -- not enabling for now. - */ - return -EOPNOTSUPP; + /* Handled by firmware */ + break; + default: return -EOPNOTSUPP; } + + return 0; } static const struct ieee80211_ops ar9170_ops = { @@ -2045,6 +2576,8 @@ void *ar9170_alloc(size_t priv_size) mutex_init(&ar->mutex); spin_lock_init(&ar->cmdlock); spin_lock_init(&ar->tx_stats_lock); + spin_lock_init(&ar->tx_ampdu_list_lock); + skb_queue_head_init(&ar->tx_status_ampdu); for (i = 0; i < __AR9170_NUM_TXQ; i++) { skb_queue_head_init(&ar->tx_status[i]); skb_queue_head_init(&ar->tx_pending[i]); @@ -2053,6 +2586,7 @@ void *ar9170_alloc(size_t priv_size) INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->beacon_work, ar9170_new_beacon); INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); + INIT_LIST_HEAD(&ar->tx_ampdu_list); /* all hw supports 2.4 GHz, so set channel to 1 by default */ ar->channel = &ar9170_2ghz_chantable[0]; @@ -2066,6 +2600,13 @@ void *ar9170_alloc(size_t priv_size) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + if (modparam_ht) { + ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; + } else { + ar9170_band_2GHz.ht_cap.ht_supported = false; + ar9170_band_5GHz.ht_cap.ht_supported = false; + } + ar->hw->queues = __AR9170_NUM_TXQ; ar->hw->extra_tx_headroom = 8; ar->hw->sta_data_size = sizeof(struct ar9170_sta_info); @@ -2091,6 +2632,7 @@ static int ar9170_read_eeprom(struct ar9170 *ar) u8 *eeprom = (void *)&ar->eeprom; u8 *addr = ar->eeprom.mac_address; __le32 offsets[RW]; + unsigned int rx_streams, tx_streams, tx_params = 0; int i, j, err, bands = 0; BUILD_BUG_ON(sizeof(ar->eeprom) & 3); @@ -2127,6 +2669,20 @@ static int ar9170_read_eeprom(struct ar9170 *ar) ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; bands++; } + + rx_streams = hweight8(ar->eeprom.rx_mask); + tx_streams = hweight8(ar->eeprom.tx_mask); + + if (rx_streams != tx_streams) + tx_params = IEEE80211_HT_MCS_TX_RX_DIFF; + + if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS) + tx_params = (tx_streams - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; + + ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params; + ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params; + /* * I measured this, a bandswitch takes roughly * 135 ms and a frequency switch about 80. -- cgit v0.10.2 From 4b9631a4734e25e37c83e72c3e0ffcbb08de5791 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 11 Jul 2009 18:00:19 +0200 Subject: rt2x00: Remove DEVICE_STATE_DISABLED_RADIO_HW The DEVICE_STATE_DISABLED_RADIO_HW flag is only read but never set, it is an ancient part of one of the many versions of the rfkill implementations in rt2x00. It is about time is disappears. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 3e17717..4c76c8d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -594,7 +594,6 @@ enum rt2x00_flags { DEVICE_STATE_INITIALIZED, DEVICE_STATE_STARTED, DEVICE_STATE_ENABLED_RADIO, - DEVICE_STATE_DISABLED_RADIO_HW, /* * Driver requirements diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 4fff3a8..658a63b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -40,8 +40,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) * Don't enable the radio twice. * And check if the hardware button has been disabled. */ - if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || - test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return 0; /* -- cgit v0.10.2 From 323d566eae1ace41bc674863b58fcc474501a2db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Sun, 12 Jul 2009 02:03:48 +0200 Subject: cfg80211: fix disabling WPA via wext (SIOCSIWAUTH) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cfg80211_set_wpa_version completely missed the use case when disabling WPA, considering IW_AUTH_WPA_VERSION_DISABLED an invalid argument. This caused weird error messages in wpa_supplicant. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index aa80c0c..e6731bf 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -880,9 +880,19 @@ static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) wdev->wext.connect.crypto.wpa_versions = 0; if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA | - IW_AUTH_WPA_VERSION_WPA2)) + IW_AUTH_WPA_VERSION_WPA2| + IW_AUTH_WPA_VERSION_DISABLED)) return -EINVAL; + if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) && + (wpa_versions & (IW_AUTH_WPA_VERSION_WPA| + IW_AUTH_WPA_VERSION_WPA2))) + return -EINVAL; + + if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) + wdev->wext.connect.crypto.wpa_versions &= + ~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2); + if (wpa_versions & IW_AUTH_WPA_VERSION_WPA) wdev->wext.connect.crypto.wpa_versions |= NL80211_WPA_VERSION_1; -- cgit v0.10.2 From ec96cfd8215af1cda016837efb266409164e3a30 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 12 Jul 2009 22:05:33 +0200 Subject: drivers/net: Drop unnecessary NULL test The result of container_of should not be NULL. In particular, in this case the argument to the enclosing function has passed though INIT_WORK, which dereferences it, implying that its container cannot be NULL. A simplified version of the semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ identifier fn,work,x,fld; type T; expression E1,E2; statement S; @@ static fn(struct work_struct *work) { ... when != work = E1 x = container_of(work,T,fld) ... when != x = E2 - if (x == NULL) S ... } // Signed-off-by: Julia Lawall Acked-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index d726b3c..2dc1cdb 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -7250,9 +7250,6 @@ static void ipw_bg_qos_activate(struct work_struct *work) struct ipw_priv *priv = container_of(work, struct ipw_priv, qos_activate); - if (priv == NULL) - return; - mutex_lock(&priv->mutex); if (priv->status & STATUS_ASSOCIATED) -- cgit v0.10.2 From 0e2b6286805c419d28a4c1e19e3a121af7449b20 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Jul 2009 13:23:39 +0200 Subject: mac80211: cancel the connection monitor timers/work In "mac80211: monitor the connection" I forgot to add code to cancel the new timers & work when the interface is brought down, which isn't a problem if you just bring it down, but _is_ a problem when you destroy the interface. Correct this lapse. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 4839a2d..090aa5a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -449,16 +449,18 @@ static int ieee80211_stop(struct net_device *dev) case NL80211_IFTYPE_STATION: del_timer_sync(&sdata->u.mgd.chswitch_timer); del_timer_sync(&sdata->u.mgd.timer); + del_timer_sync(&sdata->u.mgd.conn_mon_timer); + del_timer_sync(&sdata->u.mgd.bcn_mon_timer); /* - * If the timer fired while we waited for it, it will have - * requeued the work. Now the work will be running again + * If any of the timers fired while we waited for it, it will + * have queued its work. Now the work will be running again * but will not rearm the timer again because it checks * whether the interface is running, which, at this point, * it no longer is. */ cancel_work_sync(&sdata->u.mgd.work); cancel_work_sync(&sdata->u.mgd.chswitch_work); - + cancel_work_sync(&sdata->u.mgd.monitor_work); cancel_work_sync(&sdata->u.mgd.beacon_loss_work); /* diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 18dad22..e3b3156 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1163,6 +1163,9 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, const u8 *ssid; bool already = false; + if (!netif_running(sdata->dev)) + return; + mutex_lock(&ifmgd->mtx); if (!ifmgd->associated) -- cgit v0.10.2 From 6682588a08b8be34649348051bc0204f7ab401a2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Jul 2009 13:24:44 +0200 Subject: cfg80211: fix unregistration The work that we cancel there requires the cfg80211_mutex, so we can't cancel it under the mutex, which is fine, we can just move it to after the locked section. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 97cc596..6891cd0 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -548,11 +548,6 @@ void wiphy_unregister(struct wiphy *wiphy) /* unlock again before freeing */ mutex_unlock(&rdev->mtx); - cancel_work_sync(&rdev->conn_work); - cancel_work_sync(&rdev->scan_done_wk); - kfree(rdev->scan_req); - flush_work(&rdev->event_work); - cfg80211_debugfs_rdev_del(rdev); /* If this device got a regulatory hint tell core its @@ -564,6 +559,11 @@ void wiphy_unregister(struct wiphy *wiphy) debugfs_remove(rdev->wiphy.debugfsdir); mutex_unlock(&cfg80211_mutex); + + cancel_work_sync(&rdev->conn_work); + cancel_work_sync(&rdev->scan_done_wk); + kfree(rdev->scan_req); + flush_work(&rdev->event_work); } EXPORT_SYMBOL(wiphy_unregister); -- cgit v0.10.2 From 8f75e07aa14107668d33f60fa4d78afa2d7aa22b Mon Sep 17 00:00:00 2001 From: Hin-Tak Leung Date: Mon, 13 Jul 2009 23:20:37 +0100 Subject: zd1211rw: adding Accton Technology Corp (083a:e501) as a ZD1211B device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New device supported by the zd1211rw driver reported to linux-wireless. Device string from lsusb: "ID 083a:e501 Accton Technology Corp. ZD1211B" RF type from dmesg: zd1211b chip 083a:e501 v4810 high 00-1a-2a AL2230_RF pa0 g--NS Signed-off-by: Hin-Tak Leung Tested-by: Adrián Cereto Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 07d7ab6..3868884 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -76,6 +76,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0xe501), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, -- cgit v0.10.2 From 256fc96028f0eae5f7a3f6f77358cdd30a72c988 Mon Sep 17 00:00:00 2001 From: Hin-Tak Leung Date: Tue, 14 Jul 2009 00:05:56 +0100 Subject: rtl8187: updating Kconfig with info of branded devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding more detailed info about Asus motherboards and Ralink devices. Signed-off-by: Hin-Tak Leung Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7d5902d..ca7a8a3 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -428,10 +428,12 @@ config RTL8187 Micronet SP907GK V5 Encore ENUWI-G2 Trendnet TEW-424UB - ASUS P5B Deluxe + ASUS P5B Deluxe/P5K Premium motherboards Toshiba Satellite Pro series of laptops Asus Wireless Link Linksys WUSB54GC-EU v2 + (v1 = rt73usb; v3 is rt2070-based, + use staging/rt3070 or try rt2800usb) Thanks to Realtek for their support! -- cgit v0.10.2 From a94ca4e7af0e6b63ef5345750fad8e1400274ba4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Jul 2009 15:48:11 +0200 Subject: iwlwifi: make some logging functions static/unexport iwl_dump_nic_error_log can be static and iwl_dump_nic_event_log doesn't need to be exported. Signed-off-by: Johannes Berg Acked-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d5cd9a2..b82480a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1290,6 +1290,188 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) } #endif +static const char *desc_lookup_text[] = { + "OK", + "FAIL", + "BAD_PARAM", + "BAD_CHECKSUM", + "NMI_INTERRUPT_WDG", + "SYSASSERT", + "FATAL_ERROR", + "BAD_COMMAND", + "HW_ERROR_TUNE_LOCK", + "HW_ERROR_TEMPERATURE", + "ILLEGAL_CHAN_FREQ", + "VCC_NOT_STABLE", + "FH_ERROR", + "NMI_INTERRUPT_HOST", + "NMI_INTERRUPT_ACTION_PT", + "NMI_INTERRUPT_UNKNOWN", + "UCODE_VERSION_MISMATCH", + "HW_ERROR_ABS_LOCK", + "HW_ERROR_CAL_LOCK_FAIL", + "NMI_INTERRUPT_INST_ACTION_PT", + "NMI_INTERRUPT_DATA_ACTION_PT", + "NMI_TRM_HW_ER", + "NMI_INTERRUPT_TRM", + "NMI_INTERRUPT_BREAK_POINT" + "DEBUG_0", + "DEBUG_1", + "DEBUG_2", + "DEBUG_3", + "UNKNOWN" +}; + +static const char *desc_lookup(int i) +{ + int max = ARRAY_SIZE(desc_lookup_text) - 1; + + if (i < 0 || i > max) + i = max; + + return desc_lookup_text[i]; +} + +#define ERROR_START_OFFSET (1 * sizeof(u32)) +#define ERROR_ELEM_SIZE (7 * sizeof(u32)) + +static void iwl_dump_nic_error_log(struct iwl_priv *priv) +{ + u32 data2, line; + u32 desc, time, count, base, data1; + u32 blink1, blink2, ilink1, ilink2; + + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); + return; + } + + count = iwl_read_targ_mem(priv, base); + + if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { + IWL_ERR(priv, "Start IWL Error Log Dump:\n"); + IWL_ERR(priv, "Status: 0x%08lX, count: %d\n", + priv->status, count); + } + + desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); + blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); + blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); + ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); + ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); + data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); + data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); + line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); + time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); + + IWL_ERR(priv, "Desc Time " + "data1 data2 line\n"); + IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n", + desc_lookup(desc), desc, time, data1, data2, line); + IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n"); + IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, + ilink1, ilink2); + +} + +#define EVENT_START_OFFSET (4 * sizeof(u32)) + +/** + * iwl_print_event_log - Dump error event log to syslog + * + */ +static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode) +{ + u32 i; + u32 base; /* SRAM byte address of event log header */ + u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ + u32 ptr; /* SRAM byte address of log data */ + u32 ev, time, data; /* event log data */ + + if (num_events == 0) + return; + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + + if (mode == 0) + event_size = 2 * sizeof(u32); + else + event_size = 3 * sizeof(u32); + + ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + + /* "time" is actually "data" for mode 0 (no timestamp). + * place event id # at far right for easier visual parsing. */ + for (i = 0; i < num_events; i++) { + ev = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + time = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + if (mode == 0) { + /* data, ev */ + IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); + } else { + data = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", + time, data, ev); + } + } +} + +void iwl_dump_nic_event_log(struct iwl_priv *priv) +{ + u32 base; /* SRAM byte address of event log header */ + u32 capacity; /* event log capacity in # entries */ + u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ + u32 num_wraps; /* # times uCode wrapped to top of log */ + u32 next_entry; /* index of next entry to be written by uCode */ + u32 size; /* # entries that we'll print */ + + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); + return; + } + + /* event log header */ + capacity = iwl_read_targ_mem(priv, base); + mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); + num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); + + size = num_wraps ? capacity : next_entry; + + /* bail out if nothing in log */ + if (size == 0) { + IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); + return; + } + + IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n", + size, num_wraps); + + /* if uCode has wrapped back to top of log, start at the oldest entry, + * i.e the next one that uCode would fill. */ + if (num_wraps) + iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode); + /* (then/else) start at top of log */ + iwl_print_event_log(priv, 0, next_entry, mode); + +} /** * iwl_irq_handle_error - called for HW or SW error interrupt from card */ @@ -2040,191 +2222,6 @@ int iwl_verify_ucode(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_verify_ucode); -static const char *desc_lookup_text[] = { - "OK", - "FAIL", - "BAD_PARAM", - "BAD_CHECKSUM", - "NMI_INTERRUPT_WDG", - "SYSASSERT", - "FATAL_ERROR", - "BAD_COMMAND", - "HW_ERROR_TUNE_LOCK", - "HW_ERROR_TEMPERATURE", - "ILLEGAL_CHAN_FREQ", - "VCC_NOT_STABLE", - "FH_ERROR", - "NMI_INTERRUPT_HOST", - "NMI_INTERRUPT_ACTION_PT", - "NMI_INTERRUPT_UNKNOWN", - "UCODE_VERSION_MISMATCH", - "HW_ERROR_ABS_LOCK", - "HW_ERROR_CAL_LOCK_FAIL", - "NMI_INTERRUPT_INST_ACTION_PT", - "NMI_INTERRUPT_DATA_ACTION_PT", - "NMI_TRM_HW_ER", - "NMI_INTERRUPT_TRM", - "NMI_INTERRUPT_BREAK_POINT" - "DEBUG_0", - "DEBUG_1", - "DEBUG_2", - "DEBUG_3", - "UNKNOWN" -}; - -static const char *desc_lookup(int i) -{ - int max = ARRAY_SIZE(desc_lookup_text) - 1; - - if (i < 0 || i > max) - i = max; - - return desc_lookup_text[i]; -} - -#define ERROR_START_OFFSET (1 * sizeof(u32)) -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) - -void iwl_dump_nic_error_log(struct iwl_priv *priv) -{ - u32 data2, line; - u32 desc, time, count, base, data1; - u32 blink1, blink2, ilink1, ilink2; - - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - else - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); - - if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); - return; - } - - count = iwl_read_targ_mem(priv, base); - - if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { - IWL_ERR(priv, "Start IWL Error Log Dump:\n"); - IWL_ERR(priv, "Status: 0x%08lX, count: %d\n", - priv->status, count); - } - - desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); - blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); - blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); - ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); - ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); - data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); - data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); - line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); - time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); - - IWL_ERR(priv, "Desc Time " - "data1 data2 line\n"); - IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n", - desc_lookup(desc), desc, time, data1, data2, line); - IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n"); - IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, - ilink1, ilink2); - -} -EXPORT_SYMBOL(iwl_dump_nic_error_log); - -#define EVENT_START_OFFSET (4 * sizeof(u32)) - -/** - * iwl_print_event_log - Dump error event log to syslog - * - */ -static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode) -{ - u32 i; - u32 base; /* SRAM byte address of event log header */ - u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ - u32 ptr; /* SRAM byte address of log data */ - u32 ev, time, data; /* event log data */ - - if (num_events == 0) - return; - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - else - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - - if (mode == 0) - event_size = 2 * sizeof(u32); - else - event_size = 3 * sizeof(u32); - - ptr = base + EVENT_START_OFFSET + (start_idx * event_size); - - /* "time" is actually "data" for mode 0 (no timestamp). - * place event id # at far right for easier visual parsing. */ - for (i = 0; i < num_events; i++) { - ev = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - time = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - if (mode == 0) { - /* data, ev */ - IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); - } else { - data = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", - time, data, ev); - } - } -} - -void iwl_dump_nic_event_log(struct iwl_priv *priv) -{ - u32 base; /* SRAM byte address of event log header */ - u32 capacity; /* event log capacity in # entries */ - u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ - u32 num_wraps; /* # times uCode wrapped to top of log */ - u32 next_entry; /* index of next entry to be written by uCode */ - u32 size; /* # entries that we'll print */ - - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - else - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - - if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); - return; - } - - /* event log header */ - capacity = iwl_read_targ_mem(priv, base); - mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); - num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); - next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); - - size = num_wraps ? capacity : next_entry; - - /* bail out if nothing in log */ - if (size == 0) { - IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - return; - } - - IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n", - size, num_wraps); - - /* if uCode has wrapped back to top of log, start at the oldest entry, - * i.e the next one that uCode would fill. */ - if (num_wraps) - iwl_print_event_log(priv, next_entry, - capacity - next_entry, mode); - /* (then/else) start at top of log */ - iwl_print_event_log(priv, 0, next_entry, mode); - -} -EXPORT_SYMBOL(iwl_dump_nic_event_log); - void iwl_rf_kill_ct_config(struct iwl_priv *priv) { struct iwl_ct_kill_config cmd; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a658410..640c464 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -472,7 +472,6 @@ int iwl_pci_resume(struct pci_dev *pdev); /***************************************************** * Error Handling Debugging ******************************************************/ -void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv); void iwl_clear_isr_stats(struct iwl_priv *priv); -- cgit v0.10.2 From fe643414dbf330d6d910e01edd48dd93dc6f2942 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Jul 2009 22:37:13 +0200 Subject: wireless: wl12xx, fix lock imbalance Add omitted mutex_unlock to one of wl12xx_op_start fail paths (when wl12xx_chip_wakeup fails). [v2] Power off the device, because: \= cite from http://marc.info/?l=linux-kernel&m=124755028209880&w=2 If the chip cannot be booted, why should it remain powered on? In some rare cases, the chip might fail to initialize, but can recover if powered off and on again, so turning it off at this point is the right thing to do. =/ Signed-off-by: Jiri Slaby Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index cf5e054..106b0f2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -349,7 +349,7 @@ static int wl1251_op_start(struct ieee80211_hw *hw) ret = wl1251_chip_wakeup(wl); if (ret < 0) - return ret; + goto out; ret = wl->chip.op_boot(wl); if (ret < 0) -- cgit v0.10.2 From b770b43e95a66587fbd8c1841de83da87fbf23ea Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 16 Jul 2009 10:15:09 -0700 Subject: mac80211: drop frames for sta with no valid rate When we're associated we should be able to send data to target sta. If we cannot we may be trying to use the incorrect band to talk to the sta. Lets catch any such cases, warn, and drop the frames to not invalidate assumptions being made on rate control algorithms when they have a valid sta to communicate with. Any such cases should be handled and fixed. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ce7cb1b..d98fac5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2110,6 +2110,17 @@ rate_lowest_index(struct ieee80211_supported_band *sband, return 0; } +static inline +bool rate_usable_index_exists(struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta) +{ + unsigned int i; + + for (i = 0; i < sband->n_bitrates; i++) + if (rate_supported(sta, sband->band, i)) + return true; + return false; +} int ieee80211_rate_control_register(struct rate_control_ops *ops); void ieee80211_rate_control_unregister(struct rate_control_ops *ops); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 60ae086..f3efd4f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -512,6 +512,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) int i, len; bool inval = false, rts = false, short_preamble = false; struct ieee80211_tx_rate_control txrc; + u32 sta_flags; memset(&txrc, 0, sizeof(txrc)); @@ -544,7 +545,26 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) (tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE)))) txrc.short_preamble = short_preamble = true; + sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0; + + /* + * Lets not bother rate control if we're associated and cannot + * talk to the sta. This should not happen. + */ + if (WARN((tx->local->sw_scanning) && + (sta_flags & WLAN_STA_ASSOC) && + !rate_usable_index_exists(sband, &tx->sta->sta), + "%s: Dropped data frame as no usable bitrate found while " + "scanning and associated. Target station: " + "%pM on %d GHz band\n", + tx->dev->name, hdr->addr1, + tx->channel->band ? 5 : 2)) + return TX_DROP; + /* + * If we're associated with the sta at this point we know we can at + * least send the frame at the lowest bit rate. + */ rate_control_get_rate(tx->sdata, tx->sta, &txrc); if (unlikely(info->control.rates[0].idx < 0)) -- cgit v0.10.2 From e43419f9ad99112a2715ee34c634ffeac3bf730d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:54 -0400 Subject: ath9k: downgrade assert in rc.c for invalid rate The case where no vaid rate is found should not happen now but to help debugging and downgrade this to a warn. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index ba06e78..d7f4030 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -741,10 +741,18 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, if (rate > (ath_rc_priv->rate_table_size - 1)) rate = ath_rc_priv->rate_table_size - 1; - ASSERT((rate_table->info[rate].valid && - (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) || - (rate_table->info[rate].valid_single_stream && - !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))); + if (rate_table->info[rate].valid && + (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) + return rate; + + if (rate_table->info[rate].valid_single_stream && + !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)); + return rate; + + /* This should not happen */ + WARN_ON(1); + + rate = ath_rc_priv->valid_rate_index[0]; return rate; } -- cgit v0.10.2 From 0ab216d9727c0728c8b5f9ad627b6955570303d7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:55 -0400 Subject: iwlwifi: remove rs_get_rate workaround This removes the work around implemented for transmitting on an unsupported band on iwlwifi. This was added via the patch: 8e1856e82cb8f541e925738bebfbc473420cda68: iwlwifi: fix rs_get_rate WARN_ON() Cc: Mohamed Abbas Cc: Reinette Chatre Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 5eb538d..b23fd53 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -674,28 +674,20 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, unsigned long flags; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; u16 fc; - u16 rate_mask = 0; + u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0; s8 max_rate_idx = -1; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE(priv, "enter\n"); - if (sta) - rate_mask = sta->supp_rates[sband->band]; - /* Send management frames and NO_ACK data using lowest rate. */ fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !priv_sta) { IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n"); - if (!rate_mask) - info->control.rates[0].idx = - rate_lowest_index(sband, NULL); - else - info->control.rates[0].idx = - rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); if (info->flags & IEEE80211_TX_CTL_NO_ACK) info->control.rates[0].count = 1; return; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index ff20e504..3fea027 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2466,7 +2466,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = priv_sta; int rate_idx; - u64 mask_bit = 0; IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n"); @@ -2481,18 +2480,10 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, lq_sta->max_rate_idx = -1; } - if (sta) - mask_bit = sta->supp_rates[sband->band]; - /* Send management frames and NO_ACK data using lowest rate. */ if (!ieee80211_is_data(hdr->frame_control) || info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) { - if (!mask_bit) - info->control.rates[0].idx = - rate_lowest_index(sband, NULL); - else - info->control.rates[0].idx = - rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); if (info->flags & IEEE80211_TX_CTL_NO_ACK) info->control.rates[0].count = 1; return; -- cgit v0.10.2 From dd1901830ca7baaaae2e58f549f770f215c6f3af Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:56 -0400 Subject: ath9k: cleanup try count for MRR in rate control This has no functional change and just cleans up the code to be more legible and removes a useless variable for Multi Rate Retry. For regular frames we use 2 retries for MRR segments [0-2]. For the last MRR segment [3] we use 4. MRR[0] = 2 MRR[1] = 2 MRR[2] = 2 MRR[3] = 4 Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index eb9d522..3afd7ee 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -164,7 +164,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define WME_NUM_TID 16 #define ATH_TXBUF 512 #define ATH_TXMAXTRY 13 -#define ATH_11N_TXMAXTRY 10 #define ATH_MGT_TXMAXTRY 4 #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 961b0ce..19df788 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1540,7 +1540,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->max_rates = 4; hw->channel_change_time = 5000; hw->max_listen_interval = 10; - hw->max_rate_tries = ATH_11N_TXMAXTRY; + /* Hardware supports 10 but we use 4 */ + hw->max_rate_tries = 4; hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vif); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index d7f4030..a23b66b 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -853,9 +853,21 @@ static void ath_rc_ratefind(struct ath_softc *sc, struct ieee80211_tx_rate *rates = tx_info->control.rates; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; __le16 fc = hdr->frame_control; - u8 try_per_rate = 0, i = 0, rix, nrix; + u8 try_per_rate, i = 0, rix, nrix; int is_probe = 0; + /* + * For Multi Rate Retry we use a different number of + * retry attempt counts. This ends up looking like this: + * + * MRR[0] = 2 + * MRR[1] = 2 + * MRR[2] = 2 + * MRR[3] = 4 + * + */ + try_per_rate = sc->hw->max_rate_tries; + rate_table = sc->cur_rate_table; rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe); nrix = rix; @@ -866,7 +878,6 @@ static void ath_rc_ratefind(struct ath_softc *sc, ath_rc_rate_set_series(rate_table, &rates[i++], txrc, 1, nrix, 0); - try_per_rate = (ATH_11N_TXMAXTRY/4); /* Get the next tried/allowed rate. No RTS for the next series * after the probe rate */ @@ -877,7 +888,6 @@ static void ath_rc_ratefind(struct ath_softc *sc, tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; } else { - try_per_rate = (ATH_11N_TXMAXTRY/4); /* Set the choosen rate. No RTS for first series entry. */ ath_rc_rate_set_series(rate_table, &rates[i++], txrc, try_per_rate, nrix, 0); @@ -885,18 +895,19 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* Fill in the other rates for multirate retry */ for ( ; i < 4; i++) { - u8 try_num; u8 min_rate; - try_num = ((i + 1) == 4) ? - ATH_11N_TXMAXTRY - (try_per_rate * i) : try_per_rate ; + /* Use twice the number of tries for the last MRR segment. */ + if (i + 1 == 4) + try_per_rate = 4; + min_rate = (((i + 1) == 4) && 0); nrix = ath_rc_rate_getidx(sc, ath_rc_priv, rate_table, nrix, 1, min_rate); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, - try_num, nrix, 1); + try_per_rate, nrix, 1); } /* @@ -1529,7 +1540,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, /* * If underrun error is seen assume it as an excessive retry only * if prefetch trigger level have reached the max (0x3f for 5416) - * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY + * Adjust the long retry as if the frame was tried hw->max_rate_tries * times. This affects how ratectrl updates PER for the failed rate. */ if (tx_info_priv->tx.ts_flags & @@ -1544,7 +1555,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, tx_status = 1; ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, - (is_underrun) ? ATH_11N_TXMAXTRY : + (is_underrun) ? sc->hw->max_rate_tries : tx_info_priv->tx.ts_longretry); /* Check if aggregation has to be enabled for this tid */ -- cgit v0.10.2 From 984d021d56f036e5ffbef191cb5e498cf159784d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:57 -0400 Subject: ath9k: remove unused min rate calculation code This is not used, and when we need to get the lowest rate we should simply use mac80211's own rate_lowest_index(sband, sta). Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a23b66b..7b37b27 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -817,28 +817,17 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, static u8 ath_rc_rate_getidx(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, const struct ath_rate_table *rate_table, - u8 rix, u16 stepdown, - u16 min_rate) + u8 rix, u16 stepdown) { u32 j; u8 nextindex = 0; - if (min_rate) { - for (j = RATE_TABLE_SIZE; j > 0; j--) { - if (ath_rc_get_nextlowervalid_txrate(rate_table, - ath_rc_priv, rix, &nextindex)) - rix = nextindex; - else - break; - } - } else { - for (j = stepdown; j > 0; j--) { - if (ath_rc_get_nextlowervalid_txrate(rate_table, - ath_rc_priv, rix, &nextindex)) - rix = nextindex; - else - break; - } + for (j = stepdown; j > 0; j--) { + if (ath_rc_get_nextlowervalid_txrate(rate_table, + ath_rc_priv, rix, &nextindex)) + rix = nextindex; + else + break; } return rix; } @@ -882,7 +871,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, * after the probe rate */ nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1, 0); + rate_table, nrix, 1); ath_rc_rate_set_series(rate_table, &rates[i++], txrc, try_per_rate, nrix, 0); @@ -895,16 +884,12 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* Fill in the other rates for multirate retry */ for ( ; i < 4; i++) { - u8 min_rate; - /* Use twice the number of tries for the last MRR segment. */ if (i + 1 == 4) try_per_rate = 4; - min_rate = (((i + 1) == 4) && 0); - nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1, min_rate); + rate_table, nrix, 1); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, try_per_rate, nrix, 1); -- cgit v0.10.2 From 7466c524a42110e921e79b390b58bfc6ca6d249e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:58 -0400 Subject: ath9k: remove unused stepdown when looking for the next rate This is not used, remove this. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 7b37b27..64cb697 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -817,19 +817,14 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, static u8 ath_rc_rate_getidx(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, const struct ath_rate_table *rate_table, - u8 rix, u16 stepdown) + u8 rix) { - u32 j; u8 nextindex = 0; - - for (j = stepdown; j > 0; j--) { - if (ath_rc_get_nextlowervalid_txrate(rate_table, - ath_rc_priv, rix, &nextindex)) - rix = nextindex; - else - break; - } - return rix; + if (ath_rc_get_nextlowervalid_txrate(rate_table, + ath_rc_priv, rix, &nextindex)) + return nextindex; + else + return rix; } static void ath_rc_ratefind(struct ath_softc *sc, @@ -871,7 +866,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, * after the probe rate */ nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1); + rate_table, nrix); ath_rc_rate_set_series(rate_table, &rates[i++], txrc, try_per_rate, nrix, 0); @@ -889,7 +884,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, try_per_rate = 4; nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1); + rate_table, nrix); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, try_per_rate, nrix, 1); -- cgit v0.10.2 From 20f57215a2ff75f7c2e4004b7583e1fec925679e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:59 -0400 Subject: ath9k: remove pointless wrapper ath_rc_rate_getidx() This is just calling another helper, so just use the other helper directly. This should make it clear that when do not find the next rate we stick to the current one. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 64cb697..03e7df4 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -814,19 +814,6 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, tx_info->control.rts_cts_rate_idx = cix; } -static u8 ath_rc_rate_getidx(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - const struct ath_rate_table *rate_table, - u8 rix) -{ - u8 nextindex = 0; - if (ath_rc_get_nextlowervalid_txrate(rate_table, - ath_rc_priv, rix, &nextindex)) - return nextindex; - else - return rix; -} - static void ath_rc_ratefind(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ieee80211_tx_rate_control *txrc) @@ -865,8 +852,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* Get the next tried/allowed rate. No RTS for the next series * after the probe rate */ - nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix); + ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, + rix, &nrix); ath_rc_rate_set_series(rate_table, &rates[i++], txrc, try_per_rate, nrix, 0); @@ -883,8 +870,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, if (i + 1 == 4) try_per_rate = 4; - nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix); + ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, + rix, &nrix); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, try_per_rate, nrix, 1); -- cgit v0.10.2 From 39448b0a27529f2feecd876729ef0fba25354363 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:00 -0400 Subject: ath9k: rename ath_rc_get_nextlowervalid_txrate() What this does is get us our next lower rate so call it that, ath_rc_get_lower_rix(). Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 03e7df4..c8f800e 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -501,9 +501,9 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) } static inline int -ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, u8 *next_idx) +ath_rc_get_lower_rix(const struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + u8 cur_valid_txrate, u8 *next_idx) { int8_t i; @@ -852,8 +852,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* Get the next tried/allowed rate. No RTS for the next series * after the probe rate */ - ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, - rix, &nrix); + ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix); ath_rc_rate_set_series(rate_table, &rates[i++], txrc, try_per_rate, nrix, 0); @@ -870,8 +869,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, if (i + 1 == 4) try_per_rate = 4; - ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, - rix, &nrix); + ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, try_per_rate, nrix, 1); @@ -1156,8 +1154,8 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 && rate_table->info[tx_rate].ratekbps <= rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { - ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, - (u8)tx_rate, &ath_rc_priv->rate_max_phy); + ath_rc_get_lower_rix(rate_table, ath_rc_priv, + (u8)tx_rate, &ath_rc_priv->rate_max_phy); /* Don't probe for a little while. */ ath_rc_priv->probe_time = now_msec; -- cgit v0.10.2 From 4e6df85dacedbc68b551fdd8677f7df68639c181 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:01 -0400 Subject: ath9k: remove unused ath_rc_isvalid_txmask() Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index c8f800e..b0e3702 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -454,13 +454,6 @@ static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv, ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0; } -static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv, - u8 index) -{ - ASSERT(index <= ath_rc_priv->rate_table_size); - return ath_rc_priv->valid_rate_index[index]; -} - static inline int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv, -- cgit v0.10.2 From dfe80a3fd2199c31d0a2dc24044abaadb64c26c2 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:02 -0400 Subject: ath9k: remove ATH9K_MODE_11B This saves us 2733 bytes. text data bss dec hex filename 252265 3628 1584 257477 3edc5 ath9k-has-b-rate.ko 249905 3628 1584 255117 3e48d ath9k.ko Cc: Derek Smithies Cc: Chittajit Mitra Siged-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index cffb078..a115c8c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3305,7 +3305,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) } if (eeval & AR5416_OPFLAGS_11G) { - set_bit(ATH9K_MODE_11B, pCap->wireless_modes); set_bit(ATH9K_MODE_11G, pCap->wireless_modes); if (ah->config.ht_enable) { if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 9d0b31a..5e40223 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -113,7 +113,6 @@ enum wireless_mode { ATH9K_MODE_11A = 0, - ATH9K_MODE_11B = 2, ATH9K_MODE_11G = 3, ATH9K_MODE_11NA_HT20 = 6, ATH9K_MODE_11NG_HT20 = 7, diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index b0e3702..112a0ec 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -380,27 +380,6 @@ static const struct ath_rate_table ar5416_11g_ratetable = { 0, /* Phy rates allowed initially */ }; -static const struct ath_rate_table ar5416_11b_ratetable = { - 4, - { - { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0x1b, 0x00, (0x80|2), - 0, 0, 1, 0, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1800, 0x1a, 0x04, (0x80|4), - 1, 1, 1, 1, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4300, 0x19, 0x04, (0x80|11), - 1, 2, 2, 2, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 7100, 0x18, 0x04, (0x80|22), - 1, 4, 100, 3, 0 }, - }, - 100, /* probe interval */ - 100, /* rssi reduce interval */ - 0, /* Phy rates allowed initially */ -}; - static inline int8_t median(int8_t a, int8_t b, int8_t c) { if (a >= b) { @@ -1702,8 +1681,6 @@ static struct rate_control_ops ath_rate_ops = { void ath_rate_attach(struct ath_softc *sc) { - sc->hw_rate_table[ATH9K_MODE_11B] = - &ar5416_11b_ratetable; sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable; sc->hw_rate_table[ATH9K_MODE_11G] = -- cgit v0.10.2 From b9b6e15a9481441108ad2527db0187f729c88970 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:03 -0400 Subject: ath9k: remap ATH9K_MODE_* There are a lot of gaps here. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 5e40223..9a4570d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -113,14 +113,14 @@ enum wireless_mode { ATH9K_MODE_11A = 0, - ATH9K_MODE_11G = 3, - ATH9K_MODE_11NA_HT20 = 6, - ATH9K_MODE_11NG_HT20 = 7, - ATH9K_MODE_11NA_HT40PLUS = 8, - ATH9K_MODE_11NA_HT40MINUS = 9, - ATH9K_MODE_11NG_HT40PLUS = 10, - ATH9K_MODE_11NG_HT40MINUS = 11, - ATH9K_MODE_MAX + ATH9K_MODE_11G, + ATH9K_MODE_11NA_HT20, + ATH9K_MODE_11NG_HT20, + ATH9K_MODE_11NA_HT40PLUS, + ATH9K_MODE_11NA_HT40MINUS, + ATH9K_MODE_11NG_HT40PLUS, + ATH9K_MODE_11NG_HT40MINUS, + ATH9K_MODE_MAX, }; enum ath9k_hw_caps { -- cgit v0.10.2 From 201c3b414b4b759f399502b059189d7802bbfbb6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:04 -0400 Subject: ath9k: rename ath_rc_ratefind_ht() to ath_rc_get_highest_rix() The purpose is to find the highest rate we can use. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 112a0ec..96d46d6 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -601,10 +601,11 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, return hi; } -static u8 ath_rc_ratefind_ht(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - const struct ath_rate_table *rate_table, - int *is_probing) +/* Finds the highest rate index we can use */ +static u8 ath_rc_get_highest_rix(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + const struct ath_rate_table *rate_table, + int *is_probing) { u32 dt, best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; @@ -812,7 +813,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, try_per_rate = sc->hw->max_rate_tries; rate_table = sc->cur_rate_table; - rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe); + rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe); nrix = rix; if (is_probe) { -- cgit v0.10.2 From 7682a76df8f4e875e4029d95b799c712ee740ddc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:05 -0400 Subject: ath9k: remove unnecessary IEEE80211_TX_CTL_NO_ACK checks We check for this condition early on in our mac80211 get_rate() callback ath_get_rate(), so remove this check later down the path. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 96d46d6..2c72901 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -777,7 +777,6 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, * just CTS. Note that this is only done for OFDM/HT unicast frames. */ if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) && - !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) && (rate_table->info[rix].phy == WLAN_RC_PHY_OFDM || WLAN_RC_PHY_HT(rate_table->info[rix].phy))) { rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT; @@ -882,9 +881,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, * * FIXME: Fix duration */ - if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) && - (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG))) { + if (ieee80211_has_morefrags(fc) || + (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { rates[1].count = rates[2].count = rates[3].count = 0; rates[1].idx = rates[2].idx = rates[3].idx = 0; rates[0].count = ATH_TXMAXTRY; -- cgit v0.10.2 From e8986436580caf50ebbd3bf8371074aadf95aba5 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:06 -0400 Subject: mac80211: make minstrel/pid RC use ieee80211_is_data(fc) Cc: Felix Fietkau Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 37771ab..5bdce0c 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -75,12 +75,11 @@ use_low_rate(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - u16 fc; + __le16 fc; - fc = le16_to_cpu(hdr->frame_control); + fc = hdr->frame_control; - return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || - (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA); + return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); } diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index a0bef76..5496077 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -280,7 +280,7 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rc_pid_sta_info *spinfo = priv_sta; int rateidx; - u16 fc; + __le16 fc; if (txrc->rts) info->control.rates[0].count = @@ -290,9 +290,8 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, txrc->hw->conf.short_frame_max_tx_count; /* Send management frames and NO_ACK data using lowest rate. */ - fc = le16_to_cpu(hdr->frame_control); - if (!sta || !spinfo || - (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || + fc = hdr->frame_control; + if (!sta || !spinfo || !ieee80211_is_data(fc) || info->flags & IEEE80211_TX_CTL_NO_ACK) { info->control.rates[0].idx = rate_lowest_index(sband, sta); if (info->flags & IEEE80211_TX_CTL_NO_ACK) -- cgit v0.10.2 From 943ab70f6aebfdc0005ef7e58ae982e9ec22224b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:07 -0400 Subject: iwlwifi: use ieee80211_is_data(fc) iwl-agn-rs.c already uses this. Cc: Zhu Yi Cc: Reinette Chatre Cc: ipw3945-devel@lists.sourceforge.net Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index b23fd53..2b77692 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -673,7 +673,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, s8 scale_action = 0; unsigned long flags; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u16 fc; + __le16 fc; u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0; s8 max_rate_idx = -1; struct iwl_priv *priv = (struct iwl_priv *)priv_r; @@ -682,9 +682,8 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, IWL_DEBUG_RATE(priv, "enter\n"); /* Send management frames and NO_ACK data using lowest rate. */ - fc = le16_to_cpu(hdr->frame_control); - if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - info->flags & IEEE80211_TX_CTL_NO_ACK || + fc = hdr->frame_control; + if (!ieee80211_is_data(fc) || info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !priv_sta) { IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n"); info->control.rates[0].idx = rate_lowest_index(sband, sta); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 2addf73..afa1633 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1044,11 +1044,10 @@ EXPORT_SYMBOL(iwl_rxon_add_station); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) { int sta_id; - u16 fc = le16_to_cpu(hdr->frame_control); + __le16 fc = hdr->frame_control; /* If this frame is broadcast or management, use broadcast station id */ - if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || - is_multicast_ether_addr(hdr->addr1)) + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) return priv->hw_params.bcast_sta_id; switch (priv->iw_mode) { -- cgit v0.10.2 From 4c6d4f5c33fbe19b134c1af43af166fee79eb986 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 16 Jul 2009 10:05:41 -0700 Subject: mac80211: add helper for management / no-ack frame rate decision All current rate control algorithms agree to send management and no-ack frames at the lowest rate. They also agree to do this when sta and the private rate control data is NULL. We add a hlper to mac80211 for this and simplify the rate control algorithm code. Developers wishing to make enhancements to rate control algorithms are for broadcast/multicast can opt to not use this in their gate_rate() mac80211 callback. Cc: Zhu Yi Acked-by: Reinette Chatre Cc: ipw3945-devel@lists.sourceforge.net Cc: Gabor Juhos Acked-by: Felix Fietkau Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 2c72901..630fcf4 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1518,23 +1518,11 @@ exit: static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate_control *txrc) { - struct ieee80211_supported_band *sband = txrc->sband; - struct sk_buff *skb = txrc->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; - __le16 fc = hdr->frame_control; - /* lowest rate for management and NO_ACK frames */ - if (!ieee80211_is_data(fc) || - tx_info->flags & IEEE80211_TX_CTL_NO_ACK || !sta) { - tx_info->control.rates[0].idx = rate_lowest_index(sband, sta); - tx_info->control.rates[0].count = - (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ? - 1 : ATH_MGT_TXMAXTRY; + if (rate_control_send_low(sta, priv_sta, txrc)) return; - } /* Find tx rate for unicast frames */ ath_rc_ratefind(sc, ath_rc_priv, txrc); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 2b77692..a16bd41 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -673,7 +673,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, s8 scale_action = 0; unsigned long flags; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc; u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0; s8 max_rate_idx = -1; struct iwl_priv *priv = (struct iwl_priv *)priv_r; @@ -681,16 +680,10 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, IWL_DEBUG_RATE(priv, "enter\n"); - /* Send management frames and NO_ACK data using lowest rate. */ - fc = hdr->frame_control; - if (!ieee80211_is_data(fc) || info->flags & IEEE80211_TX_CTL_NO_ACK || - !sta || !priv_sta) { - IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n"); - info->control.rates[0].idx = rate_lowest_index(sband, sta); - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - info->control.rates[0].count = 1; + if (rate_control_send_low(sta, priv_sta, txrc)) return; - } + + rate_mask = sta->supp_rates[sband->band]; /* get user max rate if set */ max_rate_idx = txrc->max_rate_idx; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 3fea027..6328041 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2481,13 +2481,8 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, } /* Send management frames and NO_ACK data using lowest rate. */ - if (!ieee80211_is_data(hdr->frame_control) || - info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) { - info->control.rates[0].idx = rate_lowest_index(sband, sta); - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - info->control.rates[0].count = 1; + if (rate_control_send_low(sta, priv_sta, txrc)) return; - } rate_idx = lq_sta->last_txrate_idx; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d98fac5..a861259 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2094,6 +2094,29 @@ static inline int rate_supported(struct ieee80211_sta *sta, return (sta == NULL || sta->supp_rates[band] & BIT(index)); } +/** + * rate_control_send_low - helper for drivers for management/no-ack frames + * + * Rate control algorithms that agree to use the lowest rate to + * send management frames and NO_ACK data with the respective hw + * retries should use this in the beginning of their mac80211 get_rate + * callback. If true is returned the rate control can simply return. + * If false is returned we guarantee that sta and sta and priv_sta is + * not null. + * + * Rate control algorithms wishing to do more intelligent selection of + * rate for multicast/broadcast frames may choose to not use this. + * + * @sta: &struct ieee80211_sta pointer to the target destination. Note + * that this may be null. + * @priv_sta: private rate control structure. This may be null. + * @txrc: rate control information we sholud populate for mac80211. + */ +bool rate_control_send_low(struct ieee80211_sta *sta, + void *priv_sta, + struct ieee80211_tx_rate_control *txrc); + + static inline s8 rate_lowest_index(struct ieee80211_supported_band *sband, struct ieee80211_sta *sta) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 4641f00..8ac7a98 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -198,6 +198,35 @@ static void rate_control_release(struct kref *kref) kfree(ctrl_ref); } +static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) +{ + struct sk_buff *skb = txrc->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + __le16 fc; + + fc = hdr->frame_control; + + return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); +} + +bool rate_control_send_low(struct ieee80211_sta *sta, + void *priv_sta, + struct ieee80211_tx_rate_control *txrc) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); + + if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) { + info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta); + info->control.rates[0].count = + (info->flags & IEEE80211_TX_CTL_NO_ACK) ? + 1 : txrc->hw->max_rate_tries; + return true; + } + return false; +} +EXPORT_SYMBOL(rate_control_send_low); + void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_tx_rate_control *txrc) diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 5bdce0c..7c51429 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -70,19 +70,6 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix) return i; } -static inline bool -use_low_rate(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - __le16 fc; - - fc = hdr->frame_control; - - return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); -} - - static void minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) { @@ -231,7 +218,6 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate_control *txrc) { struct sk_buff *skb = txrc->skb; - struct ieee80211_supported_band *sband = txrc->sband; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct minstrel_sta_info *mi = priv_sta; struct minstrel_priv *mp = priv; @@ -244,14 +230,8 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, int mrr_ndx[3]; int sample_rate; - if (!sta || !mi || use_low_rate(skb)) { - ar[0].idx = rate_lowest_index(sband, sta); - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - ar[0].count = 1; - else - ar[0].count = mp->max_retry; + if (rate_control_send_low(sta, priv_sta, txrc)) return; - } mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot; diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 5496077..8c053be 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -276,11 +276,9 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, { struct sk_buff *skb = txrc->skb; struct ieee80211_supported_band *sband = txrc->sband; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rc_pid_sta_info *spinfo = priv_sta; int rateidx; - __le16 fc; if (txrc->rts) info->control.rates[0].count = @@ -290,15 +288,8 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, txrc->hw->conf.short_frame_max_tx_count; /* Send management frames and NO_ACK data using lowest rate. */ - fc = hdr->frame_control; - if (!sta || !spinfo || !ieee80211_is_data(fc) || - info->flags & IEEE80211_TX_CTL_NO_ACK) { - info->control.rates[0].idx = rate_lowest_index(sband, sta); - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - info->control.rates[0].count = 1; - + if (rate_control_send_low(sta, priv_sta, txrc)) return; - } rateidx = spinfo->txrate_idx; -- cgit v0.10.2 From e25739a171d7352168346dbab7f006e1f9275995 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:09 -0400 Subject: ath9k: remove rate control wraper After the cleanup we just use get_rate as a wrapper, skip the wrapper. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 630fcf4..e66734c 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -786,10 +786,11 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, tx_info->control.rts_cts_rate_idx = cix; } -static void ath_rc_ratefind(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_rate_control *txrc) +static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { + struct ath_softc *sc = priv; + struct ath_rate_priv *ath_rc_priv = priv_sta; const struct ath_rate_table *rate_table; struct sk_buff *skb = txrc->skb; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -799,6 +800,9 @@ static void ath_rc_ratefind(struct ath_softc *sc, u8 try_per_rate, i = 0, rix, nrix; int is_probe = 0; + if (rate_control_send_low(sta, priv_sta, txrc)) + return; + /* * For Multi Rate Retry we use a different number of * retry attempt counts. This ends up looking like this: @@ -1515,19 +1519,6 @@ exit: kfree(tx_info_priv); } -static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, - struct ieee80211_tx_rate_control *txrc) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - - if (rate_control_send_low(sta, priv_sta, txrc)) - return; - - /* Find tx rate for unicast frames */ - ath_rc_ratefind(sc, ath_rc_priv, txrc); -} - static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { -- cgit v0.10.2 From 39a4cafe1638bb21f335b210d037cd2cd8ce6c08 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:14:10 -0400 Subject: ath9k: Remove dead code in rate control ath9k rate control is based on only PER (packet error rate), remove unused code which was intented to do rssi based rate selection. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index e66734c..a39b1a7 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -607,47 +607,14 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc, const struct ath_rate_table *rate_table, int *is_probing) { - u32 dt, best_thruput, this_thruput, now_msec; + u32 best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; - int8_t rssi_last, rssi_reduce = 0, index = 0; - - *is_probing = 0; - - rssi_last = median(ath_rc_priv->rssi_last, - ath_rc_priv->rssi_last_prev, - ath_rc_priv->rssi_last_prev2); - - /* - * Age (reduce) last ack rssi based on how old it is. - * The bizarre numbers are so the delta is 160msec, - * meaning we divide by 16. - * 0msec <= dt <= 25msec: don't derate - * 25msec <= dt <= 185msec: derate linearly from 0 to 10dB - * 185msec <= dt: derate by 10dB - */ + int8_t index = 0; now_msec = jiffies_to_msecs(jiffies); - dt = now_msec - ath_rc_priv->rssi_time; - - if (dt >= 185) - rssi_reduce = 10; - else if (dt >= 25) - rssi_reduce = (u8)((dt - 25) >> 4); - - /* Now reduce rssi_last by rssi_reduce */ - if (rssi_last < rssi_reduce) - rssi_last = 0; - else - rssi_last -= rssi_reduce; - - /* - * Now look up the rate in the rssi table and return it. - * If no rates match then we return 0 (lowest rate) - */ - + *is_probing = 0; best_thruput = 0; maxindex = ath_rc_priv->max_valid_rate-1; - minindex = 0; best_rate = minindex; @@ -687,7 +654,6 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc, } rate = best_rate; - ath_rc_priv->rssi_last_lookup = rssi_last; /* * Must check the actual rate (ratekbps) to account for @@ -977,10 +943,6 @@ static bool ath_rc_update_per(struct ath_softc *sc, (nretry_to_per_lookup[retries] >> 3)); } - ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev; - ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last; - ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi; - ath_rc_priv->rssi_time = now_msec; /* * If we got at most one retry then increase the max rate if @@ -1024,18 +986,9 @@ static bool ath_rc_update_per(struct ath_softc *sc, /* * Don't update anything. We don't know if * this was because of collisions or poor signal. - * - * Later: if rssi_ack is close to - * ath_rc_priv->state[txRate].rssi_thres and we see lots - * of retries, then we could increase - * ath_rc_priv->state[txRate].rssi_thres. */ ath_rc_priv->hw_maxretry_pktcnt = 0; } else { - int32_t rssi_ackAvg; - int8_t rssi_thres; - int8_t rssi_ack_vmin; - /* * It worked with no retries. First ignore bogus (small) * rssi_ack values. @@ -1045,43 +998,9 @@ static bool ath_rc_update_per(struct ath_softc *sc, ath_rc_priv->hw_maxretry_pktcnt++; } - if (tx_info_priv->tx.ts_rssi < - rate_table->info[tx_rate].rssi_ack_validmin) - goto exit; - - /* Average the rssi */ - if (tx_rate != ath_rc_priv->rssi_sum_rate) { - ath_rc_priv->rssi_sum_rate = tx_rate; - ath_rc_priv->rssi_sum = - ath_rc_priv->rssi_sum_cnt = 0; - } - - ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi; - ath_rc_priv->rssi_sum_cnt++; - - if (ath_rc_priv->rssi_sum_cnt < 4) - goto exit; - - rssi_ackAvg = - (ath_rc_priv->rssi_sum + 2) / 4; - rssi_thres = - ath_rc_priv->state[tx_rate].rssi_thres; - rssi_ack_vmin = - rate_table->info[tx_rate].rssi_ack_validmin; - - ath_rc_priv->rssi_sum = - ath_rc_priv->rssi_sum_cnt = 0; - - /* Now reduce the current rssi threshold */ - if ((rssi_ackAvg < rssi_thres + 2) && - (rssi_thres > rssi_ack_vmin)) { - ath_rc_priv->state[tx_rate].rssi_thres--; - } - - state_change = true; } } -exit: + return state_change; } @@ -1093,11 +1012,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, struct ath_tx_info_priv *tx_info_priv, int tx_rate, int xretries, int retries) { -#define CHK_RSSI(rate) \ - ((ath_rc_priv->state[(rate)].rssi_thres + \ - rate_table->info[(rate)].rssi_ack_deltamin) > \ - ath_rc_priv->state[(rate)+1].rssi_thres) - u32 now_msec = jiffies_to_msecs(jiffies); int rate; u8 last_per; @@ -1108,13 +1022,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) return; - /* To compensate for some imbalance between ctrl and ext. channel */ - - if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy)) - tx_info_priv->tx.ts_rssi = - tx_info_priv->tx.ts_rssi < 3 ? 0 : - tx_info_priv->tx.ts_rssi - 3; - last_per = ath_rc_priv->state[tx_rate].per; /* Update PER first */ @@ -1136,51 +1043,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_rc_priv->probe_time = now_msec; } - if (state_change) { - /* - * Make sure the rates above this have higher rssi thresholds. - * (Note: Monotonicity is kept within the OFDM rates and - * within the CCK rates. However, no adjustment is - * made to keep the rssi thresholds monotonically - * increasing between the CCK and OFDM rates.) - */ - for (rate = tx_rate; rate < size - 1; rate++) { - if (rate_table->info[rate+1].phy != - rate_table->info[tx_rate].phy) - break; - - if (CHK_RSSI(rate)) { - ath_rc_priv->state[rate+1].rssi_thres = - ath_rc_priv->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin; - } - } - - /* Make sure the rates below this have lower rssi thresholds. */ - for (rate = tx_rate - 1; rate >= 0; rate--) { - if (rate_table->info[rate].phy != - rate_table->info[tx_rate].phy) - break; - - if (CHK_RSSI(rate)) { - if (ath_rc_priv->state[rate+1].rssi_thres < - rate_table->info[rate].rssi_ack_deltamin) - ath_rc_priv->state[rate].rssi_thres = 0; - else { - ath_rc_priv->state[rate].rssi_thres = - ath_rc_priv->state[rate+1].rssi_thres - - rate_table->info[rate].rssi_ack_deltamin; - } - - if (ath_rc_priv->state[rate].rssi_thres < - rate_table->info[rate].rssi_ack_validmin) { - ath_rc_priv->state[rate].rssi_thres = - rate_table->info[rate].rssi_ack_validmin; - } - } - } - } - /* Make sure the rates below this have lower PER */ /* Monotonicity is kept only for rates below the current rate. */ if (ath_rc_priv->state[tx_rate].per < last_per) { @@ -1205,19 +1067,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_rc_priv->state[rate].per; } - /* Every so often, we reduce the thresholds and - * PER (different for CCK and OFDM). */ - if (now_msec - ath_rc_priv->rssi_down_time >= - rate_table->rssi_reduce_interval) { - - for (rate = 0; rate < size; rate++) { - if (ath_rc_priv->state[rate].rssi_thres > - rate_table->info[rate].rssi_ack_validmin) - ath_rc_priv->state[rate].rssi_thres -= 1; - } - ath_rc_priv->rssi_down_time = now_msec; - } - /* Every so often, we reduce the thresholds * and PER (different for CCK and OFDM). */ if (now_msec - ath_rc_priv->per_down_time >= @@ -1233,7 +1082,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_debug_stat_retries(sc, tx_rate, xretries, retries, ath_rc_priv->state[tx_rate].per); -#undef CHK_RSSI } static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, @@ -1369,8 +1217,6 @@ static void ath_rc_init(struct ath_softc *sc, /* Initialize thresholds according to the global rate table */ for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { - ath_rc_priv->state[i].rssi_thres = - rate_table->info[i].rssi_ack_validmin; ath_rc_priv->state[i].per = 0; } @@ -1631,7 +1477,6 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp return NULL; } - rate_priv->rssi_down_time = jiffies_to_msecs(jiffies); rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max; return rate_priv; -- cgit v0.10.2 From ddf4a2db72c1073b31d0ad28911d137b1745cfca Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:14:11 -0400 Subject: ath9k: Remove unused members from rate control structure Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a39b1a7..731967c 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -22,130 +22,130 @@ static const struct ath_rate_table ar5416_11na_ratetable = { { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, - 0, 2, 1, 0, 0, 0, 0, 0 }, + 0, 0, 0, 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, - 0, 3, 1, 1, 1, 1, 1, 0 }, + 0, 1, 1, 1, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, 24, - 2, 4, 2, 2, 2, 2, 2, 0 }, + 2, 2, 2, 2, 2, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, - 2, 6, 2, 3, 3, 3, 3, 0 }, + 2, 3, 3, 3, 3, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, 48, - 4, 10, 3, 4, 4, 4, 4, 0 }, + 4, 4, 4, 4, 4, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, - 4, 14, 3, 5, 5, 5, 5, 0 }, + 4, 5, 5, 5, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, - 4, 20, 3, 6, 6, 6, 6, 0 }, + 4, 6, 6, 6, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, - 4, 23, 3, 7, 7, 7, 7, 0 }, + 4, 7, 7, 7, 7, 0 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, - 0, 2, 3, 8, 24, 8, 24, 3216 }, + 0, 8, 24, 8, 24, 3216 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ 12700, 0x81, 0x00, 1, - 2, 4, 3, 9, 25, 9, 25, 6434 }, + 2, 9, 25, 9, 25, 6434 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ 18800, 0x82, 0x00, 2, - 2, 6, 3, 10, 26, 10, 26, 9650 }, + 2, 10, 26, 10, 26, 9650 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ 25000, 0x83, 0x00, 3, - 4, 10, 3, 11, 27, 11, 27, 12868 }, + 4, 11, 27, 11, 27, 12868 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ 36700, 0x84, 0x00, 4, - 4, 14, 3, 12, 28, 12, 28, 19304 }, + 4, 12, 28, 12, 28, 19304 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ 48100, 0x85, 0x00, 5, - 4, 20, 3, 13, 29, 13, 29, 25740 }, + 4, 13, 29, 13, 29, 25740 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ 53500, 0x86, 0x00, 6, - 4, 23, 3, 14, 30, 14, 30, 28956 }, + 4, 14, 30, 14, 30, 28956 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ 59000, 0x87, 0x00, 7, - 4, 25, 3, 15, 31, 15, 32, 32180 }, + 4, 15, 31, 15, 32, 32180 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ 12700, 0x88, 0x00, - 8, 0, 2, 3, 16, 33, 16, 33, 6430 }, + 8, 3, 16, 33, 16, 33, 6430 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ 24800, 0x89, 0x00, 9, - 2, 4, 3, 17, 34, 17, 34, 12860 }, + 2, 17, 34, 17, 34, 12860 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ 36600, 0x8a, 0x00, 10, - 2, 6, 3, 18, 35, 18, 35, 19300 }, + 2, 18, 35, 18, 35, 19300 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ 48100, 0x8b, 0x00, 11, - 4, 10, 3, 19, 36, 19, 36, 25736 }, + 4, 19, 36, 19, 36, 25736 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ 69500, 0x8c, 0x00, 12, - 4, 14, 3, 20, 37, 20, 37, 38600 }, + 4, 20, 37, 20, 37, 38600 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ 89500, 0x8d, 0x00, 13, - 4, 20, 3, 21, 38, 21, 38, 51472 }, + 4, 21, 38, 21, 38, 51472 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ 98900, 0x8e, 0x00, 14, - 4, 23, 3, 22, 39, 22, 39, 57890 }, + 4, 22, 39, 22, 39, 57890 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ 108300, 0x8f, 0x00, 15, - 4, 25, 3, 23, 40, 23, 41, 64320 }, + 4, 23, 40, 23, 41, 64320 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ 13200, 0x80, 0x00, 0, - 0, 2, 3, 8, 24, 24, 24, 6684 }, + 0, 8, 24, 24, 24, 6684 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ 25900, 0x81, 0x00, 1, - 2, 4, 3, 9, 25, 25, 25, 13368 }, + 2, 9, 25, 25, 25, 13368 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ 38600, 0x82, 0x00, 2, - 2, 6, 3, 10, 26, 26, 26, 20052 }, + 2, 10, 26, 26, 26, 20052 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ 49800, 0x83, 0x00, 3, - 4, 10, 3, 11, 27, 27, 27, 26738 }, + 4, 11, 27, 27, 27, 26738 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ 72200, 0x84, 0x00, 4, - 4, 14, 3, 12, 28, 28, 28, 40104 }, + 4, 12, 28, 28, 28, 40104 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ 92900, 0x85, 0x00, 5, - 4, 20, 3, 13, 29, 29, 29, 53476 }, + 4, 13, 29, 29, 29, 53476 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ 102700, 0x86, 0x00, 6, - 4, 23, 3, 14, 30, 30, 30, 60156 }, + 4, 14, 30, 30, 30, 60156 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ 112000, 0x87, 0x00, 7, - 4, 25, 3, 15, 31, 32, 32, 66840 }, + 4, 15, 31, 32, 32, 66840 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ 122000, 0x87, 0x00, 7, - 4, 25, 3, 15, 31, 32, 32, 74200 }, + 4, 15, 31, 32, 32, 74200 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ 25800, 0x88, 0x00, 8, - 0, 2, 3, 16, 33, 33, 33, 13360 }, + 0, 16, 33, 33, 33, 13360 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ 49800, 0x89, 0x00, 9, - 2, 4, 3, 17, 34, 34, 34, 26720 }, + 2, 17, 34, 34, 34, 26720 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ 71900, 0x8a, 0x00, 10, - 2, 6, 3, 18, 35, 35, 35, 40080 }, + 2, 18, 35, 35, 35, 40080 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ 92500, 0x8b, 0x00, 11, - 4, 10, 3, 19, 36, 36, 36, 53440 }, + 4, 19, 36, 36, 36, 53440 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ 130300, 0x8c, 0x00, 12, - 4, 14, 3, 20, 37, 37, 37, 80160 }, + 4, 20, 37, 37, 37, 80160 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ 162800, 0x8d, 0x00, 13, - 4, 20, 3, 21, 38, 38, 38, 106880 }, + 4, 21, 38, 38, 38, 106880 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ 178200, 0x8e, 0x00, 14, - 4, 23, 3, 22, 39, 39, 39, 120240 }, + 4, 22, 39, 39, 39, 120240 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ 192100, 0x8f, 0x00, 15, - 4, 25, 3, 23, 40, 41, 41, 133600 }, + 4, 23, 40, 41, 41, 133600 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ 207000, 0x8f, 0x00, 15, - 4, 25, 3, 23, 40, 41, 41, 148400 }, + 4, 23, 40, 41, 41, 148400 }, }, 50, /* probe interval */ 50, /* rssi reduce interval */ @@ -160,142 +160,142 @@ static const struct ath_rate_table ar5416_11ng_ratetable = { { { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, - 0, 0, 1, 0, 0, 0, 0, 0 }, + 0, 0, 0, 0, 0, 0 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1900, 0x1a, 0x04, 4, - 1, 1, 1, 1, 1, 1, 1, 0 }, + 1, 1, 1, 1, 1, 0 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4900, 0x19, 0x04, 11, - 2, 2, 2, 2, 2, 2, 2, 0 }, + 2, 2, 2, 2, 2, 0 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 8100, 0x18, 0x04, 22, - 3, 3, 2, 3, 3, 3, 3, 0 }, + 3, 3, 3, 3, 3, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, - 4, 2, 1, 4, 4, 4, 4, 0 }, + 4, 4, 4, 4, 4, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, - 4, 3, 1, 5, 5, 5, 5, 0 }, + 4, 5, 5, 5, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10100, 0x0a, 0x00, 24, - 6, 4, 1, 6, 6, 6, 6, 0 }, + 6, 6, 6, 6, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 14100, 0x0e, 0x00, 36, - 6, 6, 2, 7, 7, 7, 7, 0 }, + 6, 7, 7, 7, 7, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17700, 0x09, 0x00, 48, - 8, 10, 3, 8, 8, 8, 8, 0 }, + 8, 8, 8, 8, 8, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23700, 0x0d, 0x00, 72, - 8, 14, 3, 9, 9, 9, 9, 0 }, + 8, 9, 9, 9, 9, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, - 8, 20, 3, 10, 10, 10, 10, 0 }, + 8, 10, 10, 10, 10, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 30900, 0x0c, 0x00, 108, - 8, 23, 3, 11, 11, 11, 11, 0 }, + 8, 11, 11, 11, 11, 0 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, - 4, 2, 3, 12, 28, 12, 28, 3216 }, + 4, 12, 28, 12, 28, 3216 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ 12700, 0x81, 0x00, 1, - 6, 4, 3, 13, 29, 13, 29, 6434 }, + 6, 13, 29, 13, 29, 6434 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ 18800, 0x82, 0x00, 2, - 6, 6, 3, 14, 30, 14, 30, 9650 }, + 6, 14, 30, 14, 30, 9650 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ 25000, 0x83, 0x00, 3, - 8, 10, 3, 15, 31, 15, 31, 12868 }, + 8, 15, 31, 15, 31, 12868 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ 36700, 0x84, 0x00, 4, - 8, 14, 3, 16, 32, 16, 32, 19304 }, + 8, 16, 32, 16, 32, 19304 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ 48100, 0x85, 0x00, 5, - 8, 20, 3, 17, 33, 17, 33, 25740 }, + 8, 17, 33, 17, 33, 25740 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ 53500, 0x86, 0x00, 6, - 8, 23, 3, 18, 34, 18, 34, 28956 }, + 8, 18, 34, 18, 34, 28956 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ 59000, 0x87, 0x00, 7, - 8, 25, 3, 19, 35, 19, 36, 32180 }, + 8, 19, 35, 19, 36, 32180 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ 12700, 0x88, 0x00, 8, - 4, 2, 3, 20, 37, 20, 37, 6430 }, + 4, 20, 37, 20, 37, 6430 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ 24800, 0x89, 0x00, 9, - 6, 4, 3, 21, 38, 21, 38, 12860 }, + 6, 21, 38, 21, 38, 12860 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ 36600, 0x8a, 0x00, 10, - 6, 6, 3, 22, 39, 22, 39, 19300 }, + 6, 22, 39, 22, 39, 19300 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ 48100, 0x8b, 0x00, 11, - 8, 10, 3, 23, 40, 23, 40, 25736 }, + 8, 23, 40, 23, 40, 25736 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ 69500, 0x8c, 0x00, 12, - 8, 14, 3, 24, 41, 24, 41, 38600 }, + 8, 24, 41, 24, 41, 38600 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ 89500, 0x8d, 0x00, 13, - 8, 20, 3, 25, 42, 25, 42, 51472 }, + 8, 25, 42, 25, 42, 51472 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ 98900, 0x8e, 0x00, 14, - 8, 23, 3, 26, 43, 26, 44, 57890 }, + 8, 26, 43, 26, 44, 57890 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ 108300, 0x8f, 0x00, 15, - 8, 25, 3, 27, 44, 27, 45, 64320 }, + 8, 27, 44, 27, 45, 64320 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ 13200, 0x80, 0x00, 0, - 8, 2, 3, 12, 28, 28, 28, 6684 }, + 8, 12, 28, 28, 28, 6684 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ 25900, 0x81, 0x00, 1, - 8, 4, 3, 13, 29, 29, 29, 13368 }, + 8, 13, 29, 29, 29, 13368 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ 38600, 0x82, 0x00, 2, - 8, 6, 3, 14, 30, 30, 30, 20052 }, + 8, 14, 30, 30, 30, 20052 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ 49800, 0x83, 0x00, 3, - 8, 10, 3, 15, 31, 31, 31, 26738 }, + 8, 15, 31, 31, 31, 26738 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ 72200, 0x84, 0x00, 4, - 8, 14, 3, 16, 32, 32, 32, 40104 }, + 8, 16, 32, 32, 32, 40104 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ 92900, 0x85, 0x00, 5, - 8, 20, 3, 17, 33, 33, 33, 53476 }, + 8, 17, 33, 33, 33, 53476 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ 102700, 0x86, 0x00, 6, - 8, 23, 3, 18, 34, 34, 34, 60156 }, + 8, 18, 34, 34, 34, 60156 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ 112000, 0x87, 0x00, 7, - 8, 23, 3, 19, 35, 36, 36, 66840 }, + 8, 19, 35, 36, 36, 66840 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ 122000, 0x87, 0x00, 7, - 8, 25, 3, 19, 35, 36, 36, 74200 }, + 8, 19, 35, 36, 36, 74200 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ 25800, 0x88, 0x00, 8, - 8, 2, 3, 20, 37, 37, 37, 13360 }, + 8, 20, 37, 37, 37, 13360 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ 49800, 0x89, 0x00, 9, - 8, 4, 3, 21, 38, 38, 38, 26720 }, + 8, 21, 38, 38, 38, 26720 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ 71900, 0x8a, 0x00, 10, - 8, 6, 3, 22, 39, 39, 39, 40080 }, + 8, 22, 39, 39, 39, 40080 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ 92500, 0x8b, 0x00, 11, - 8, 10, 3, 23, 40, 40, 40, 53440 }, + 8, 23, 40, 40, 40, 53440 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ 130300, 0x8c, 0x00, 12, - 8, 14, 3, 24, 41, 41, 41, 80160 }, + 8, 24, 41, 41, 41, 80160 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ 162800, 0x8d, 0x00, 13, - 8, 20, 3, 25, 42, 42, 42, 106880 }, + 8, 25, 42, 42, 42, 106880 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ 178200, 0x8e, 0x00, 14, - 8, 23, 3, 26, 43, 43, 43, 120240 }, + 8, 26, 43, 43, 43, 120240 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ 192100, 0x8f, 0x00, 15, - 8, 23, 3, 27, 44, 45, 45, 133600 }, + 8, 27, 44, 45, 45, 133600 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ 207000, 0x8f, 0x00, 15, - 8, 25, 3, 27, 44, 45, 45, 148400 }, + 8, 27, 44, 45, 45, 148400 }, }, 50, /* probe interval */ 50, /* rssi reduce interval */ @@ -307,28 +307,28 @@ static const struct ath_rate_table ar5416_11a_ratetable = { { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, (0x80|12), - 0, 2, 1, 0, 0 }, + 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, - 0, 3, 1, 1, 0 }, + 0, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, (0x80|24), - 2, 4, 2, 2, 0 }, + 2, 2, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, - 2, 6, 2, 3, 0 }, + 2, 3, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, (0x80|48), - 4, 10, 3, 4, 0 }, + 4, 4, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, - 4, 14, 3, 5, 0 }, + 4, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, - 4, 19, 3, 6, 0 }, + 4, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, - 4, 23, 3, 7, 0 }, + 4, 7, 0 }, }, 50, /* probe interval */ 50, /* rssi reduce interval */ @@ -340,40 +340,40 @@ static const struct ath_rate_table ar5416_11g_ratetable = { { { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, - 0, 0, 1, 0, 0 }, + 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1900, 0x1a, 0x04, 4, - 1, 1, 1, 1, 0 }, + 1, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4900, 0x19, 0x04, 11, - 2, 2, 2, 2, 0 }, + 2, 2, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 8100, 0x18, 0x04, 22, - 3, 3, 2, 3, 0 }, + 3, 3, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, - 4, 2, 1, 4, 0 }, + 4, 4, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, - 4, 3, 1, 5, 0 }, + 4, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, 24, - 6, 4, 1, 6, 0 }, + 6, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, - 6, 6, 2, 7, 0 }, + 6, 7, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, 48, - 8, 10, 3, 8, 0 }, + 8, 8, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, - 8, 14, 3, 9, 0 }, + 8, 9, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, - 8, 19, 3, 10, 0 }, + 8, 10, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, - 8, 23, 3, 11, 0 }, + 8, 11, 0 }, }, 50, /* probe interval */ 50, /* rssi reduce interval */ diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index e3abd76..6797df0 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -112,8 +112,6 @@ struct ath_rate_table { u8 short_preamble; u8 dot11rate; u8 ctrl_rate; - int8_t rssi_ack_validmin; - int8_t rssi_ack_deltamin; u8 base_index; u8 cw40index; u8 sgi_index; @@ -126,7 +124,6 @@ struct ath_rate_table { }; struct ath_tx_ratectrl_state { - int8_t rssi_thres; /* required rssi for this rate (dB) */ u8 per; /* recent estimate of packet error rate (%) */ }; @@ -138,16 +135,7 @@ struct ath_rateset { /** * struct ath_rate_priv - Rate Control priv data * @state: RC state - * @rssi_last: last ACK rssi - * @rssi_last_lookup: last ACK rssi used for lookup - * @rssi_last_prev: previous last ACK rssi - * @rssi_last_prev2: 2nd previous last ACK rssi - * @rssi_sum_cnt: count of rssi_sum for averaging - * @rssi_sum_rate: rate that we are averaging - * @rssi_sum: running sum of rssi for averaging * @probe_rate: rate we are probing at - * @rssi_time: msec timestamp for last ack rssi - * @rssi_down_time: msec timestamp for last down step * @probe_time: msec timestamp for last probe * @hw_maxretry_pktcnt: num of packets since we got HW max retry error * @max_valid_rate: maximum number of valid rate @@ -161,13 +149,6 @@ struct ath_rateset { * @neg_ht_rates: Negotiated HT rates */ struct ath_rate_priv { - int8_t rssi_last; - int8_t rssi_last_lookup; - int8_t rssi_last_prev; - int8_t rssi_last_prev2; - int32_t rssi_sum_cnt; - int32_t rssi_sum_rate; - int32_t rssi_sum; u8 rate_table_size; u8 probe_rate; u8 hw_maxretry_pktcnt; @@ -177,8 +158,6 @@ struct ath_rate_priv { u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; u8 rate_max_phy; - u32 rssi_time; - u32 rssi_down_time; u32 probe_time; u32 per_down_time; u32 probe_interval; -- cgit v0.10.2 From c41304653e120749dae8b04332b92ffb5f4dbbfd Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:14:12 -0400 Subject: ath9k: Use probe interval instead of rssi reduce interval Get rid of rssi reduce interval. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 731967c..a97dd7b 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -148,7 +148,6 @@ static const struct ath_rate_table ar5416_11na_ratetable = { 4, 23, 40, 41, 41, 148400 }, }, 50, /* probe interval */ - 50, /* rssi reduce interval */ WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ }; @@ -298,7 +297,6 @@ static const struct ath_rate_table ar5416_11ng_ratetable = { 8, 27, 44, 45, 45, 148400 }, }, 50, /* probe interval */ - 50, /* rssi reduce interval */ WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ }; @@ -331,7 +329,6 @@ static const struct ath_rate_table ar5416_11a_ratetable = { 4, 7, 0 }, }, 50, /* probe interval */ - 50, /* rssi reduce interval */ 0, /* Phy rates allowed initially */ }; @@ -376,7 +373,6 @@ static const struct ath_rate_table ar5416_11g_ratetable = { 8, 11, 0 }, }, 50, /* probe interval */ - 50, /* rssi reduce interval */ 0, /* Phy rates allowed initially */ }; @@ -1070,7 +1066,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Every so often, we reduce the thresholds * and PER (different for CCK and OFDM). */ if (now_msec - ath_rc_priv->per_down_time >= - rate_table->rssi_reduce_interval) { + rate_table->probe_interval) { for (rate = 0; rate < size; rate++) { ath_rc_priv->state[rate].per = 7 * ath_rc_priv->state[rate].per / 8; diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 6797df0..c794d6c 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -119,7 +119,6 @@ struct ath_rate_table { u32 max_4ms_framelen; } info[RATE_TABLE_SIZE]; u32 probe_interval; - u32 rssi_reduce_interval; u8 initial_ratemax; }; -- cgit v0.10.2 From 922bac602255d4557c289cabba7857c5be332d34 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:14:13 -0400 Subject: ath9k: Nuke struct ath_tx_ratectrl_state Move its only member (u8 per) to struct ath_rate_priv. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a97dd7b..a07efa2 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -636,7 +636,7 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc, * 10-15 and we would be worse off then staying * at the current rate. */ - per_thres = ath_rc_priv->state[rate].per; + per_thres = ath_rc_priv->per[rate]; if (per_thres < 12) per_thres = 12; @@ -881,13 +881,13 @@ static bool ath_rc_update_per(struct ath_softc *sc, 100 * 9 / 10 }; - last_per = ath_rc_priv->state[tx_rate].per; + last_per = ath_rc_priv->per[tx_rate]; if (xretries) { if (xretries == 1) { - ath_rc_priv->state[tx_rate].per += 30; - if (ath_rc_priv->state[tx_rate].per > 100) - ath_rc_priv->state[tx_rate].per = 100; + ath_rc_priv->per[tx_rate] += 30; + if (ath_rc_priv->per[tx_rate] > 100) + ath_rc_priv->per[tx_rate] = 100; } else { /* xretries == 2 */ count = ARRAY_SIZE(nretry_to_per_lookup); @@ -895,7 +895,7 @@ static bool ath_rc_update_per(struct ath_softc *sc, retries = count - 1; /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - ath_rc_priv->state[tx_rate].per = + ath_rc_priv->per[tx_rate] = (u8)(last_per - (last_per >> 3) + (100 >> 3)); } @@ -931,10 +931,10 @@ static bool ath_rc_update_per(struct ath_softc *sc, n_frames = tx_info_priv->n_frames * (retries + 1); cur_per = (100 * n_bad_frames / n_frames) >> 3; new_per = (u8)(last_per - (last_per >> 3) + cur_per); - ath_rc_priv->state[tx_rate].per = new_per; + ath_rc_priv->per[tx_rate] = new_per; } } else { - ath_rc_priv->state[tx_rate].per = + ath_rc_priv->per[tx_rate] = (u8)(last_per - (last_per >> 3) + (nretry_to_per_lookup[retries] >> 3)); } @@ -962,8 +962,8 @@ static bool ath_rc_update_per(struct ath_softc *sc, ath_rc_priv->probe_rate; probe_rate = ath_rc_priv->probe_rate; - if (ath_rc_priv->state[probe_rate].per > 30) - ath_rc_priv->state[probe_rate].per = 20; + if (ath_rc_priv->per[probe_rate] > 30) + ath_rc_priv->per[probe_rate] = 20; ath_rc_priv->probe_rate = 0; @@ -1018,7 +1018,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) return; - last_per = ath_rc_priv->state[tx_rate].per; + last_per = ath_rc_priv->per[tx_rate]; /* Update PER first */ state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, @@ -1029,7 +1029,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, * If this rate looks bad (high PER) then stop using it for * a while (except if we are probing). */ - if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 && + if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 && rate_table->info[tx_rate].ratekbps <= rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { ath_rc_get_lower_rix(rate_table, ath_rc_priv, @@ -1041,26 +1041,26 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Make sure the rates below this have lower PER */ /* Monotonicity is kept only for rates below the current rate. */ - if (ath_rc_priv->state[tx_rate].per < last_per) { + if (ath_rc_priv->per[tx_rate] < last_per) { for (rate = tx_rate - 1; rate >= 0; rate--) { if (rate_table->info[rate].phy != rate_table->info[tx_rate].phy) break; - if (ath_rc_priv->state[rate].per > - ath_rc_priv->state[rate+1].per) { - ath_rc_priv->state[rate].per = - ath_rc_priv->state[rate+1].per; + if (ath_rc_priv->per[rate] > + ath_rc_priv->per[rate+1]) { + ath_rc_priv->per[rate] = + ath_rc_priv->per[rate+1]; } } } /* Maintain monotonicity for rates above the current rate */ for (rate = tx_rate; rate < size - 1; rate++) { - if (ath_rc_priv->state[rate+1].per < - ath_rc_priv->state[rate].per) - ath_rc_priv->state[rate+1].per = - ath_rc_priv->state[rate].per; + if (ath_rc_priv->per[rate+1] < + ath_rc_priv->per[rate]) + ath_rc_priv->per[rate+1] = + ath_rc_priv->per[rate]; } /* Every so often, we reduce the thresholds @@ -1068,15 +1068,15 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (now_msec - ath_rc_priv->per_down_time >= rate_table->probe_interval) { for (rate = 0; rate < size; rate++) { - ath_rc_priv->state[rate].per = - 7 * ath_rc_priv->state[rate].per / 8; + ath_rc_priv->per[rate] = + 7 * ath_rc_priv->per[rate] / 8; } ath_rc_priv->per_down_time = now_msec; } ath_debug_stat_retries(sc, tx_rate, xretries, retries, - ath_rc_priv->state[tx_rate].per); + ath_rc_priv->per[tx_rate]); } @@ -1213,7 +1213,7 @@ static void ath_rc_init(struct ath_softc *sc, /* Initialize thresholds according to the global rate table */ for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { - ath_rc_priv->state[i].per = 0; + ath_rc_priv->per[i] = 0; } /* Determine the valid rates */ diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index c794d6c..fa21a62 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -122,10 +122,6 @@ struct ath_rate_table { u8 initial_ratemax; }; -struct ath_tx_ratectrl_state { - u8 per; /* recent estimate of packet error rate (%) */ -}; - struct ath_rateset { u8 rs_nrates; u8 rs_rates[ATH_RATE_MAX]; @@ -141,6 +137,7 @@ struct ath_rateset { * @per_down_time: msec timestamp for last PER down step * @valid_phy_ratecnt: valid rate count * @rate_max_phy: phy index for the max rate + * @per: PER for every valid rate in % * @probe_interval: interval for ratectrl to probe for other rates * @prev_data_rix: rate idx of last data frame * @ht_cap: HT capabilities @@ -157,12 +154,12 @@ struct ath_rate_priv { u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; u8 rate_max_phy; + u8 per[RATE_TABLE_SIZE]; u32 probe_time; u32 per_down_time; u32 probe_interval; u32 prev_data_rix; u32 tx_triglevel_max; - struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE]; struct ath_rateset neg_rates; struct ath_rateset neg_ht_rates; struct ath_rate_softc *asc; -- cgit v0.10.2 From a59b5a5e684652eec035c869ab8911a1689c8f53 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Tue, 14 Jul 2009 20:17:07 -0400 Subject: ath9k: Manipulate and report the correct RSSI RSSI reported by the RX descriptor requires little manipulation. Manipulate and report the correct RSSI to the stack. This will fix the improper signal levels reported by iwconfig iw dev wlanX station dump. Also the Link Quality reported seems to be varying (falls to zero also sometimes) when iperf is run from STA to AP. Also use the default noise floor for now as the one reported during the caliberation seems to be wrong. The Signal and Link Quality before this patch (taken while TX is in progress from STA to AP) 09:59:13.285428037 Link Quality=29/70 Signal level=-81 dBm 09:59:13.410660084 Link Quality=20/70 Signal level=-90 dBm 09:59:13.586864392 Link Quality=21/70 Signal level=-89 dBm 09:59:13.710296281 Link Quality=21/70 Signal level=-89 dBm 09:59:13.821683064 Link Quality=25/70 Signal level=-85 dBm 09:59:13.933402989 Link Quality=24/70 Signal level=-86 dBm 09:59:14.045839276 Link Quality=26/70 Signal level=-84 dBm 09:59:14.193926673 Link Quality=23/70 Signal level=-87 dBm 09:59:14.306230262 Link Quality=31/70 Signal level=-79 dBm 09:59:14.419459667 Link Quality=26/70 Signal level=-84 dBm 09:59:14.530711167 Link Quality=37/70 Signal level=-73 dBm 09:59:14.642593962 Link Quality=29/70 Signal level=-81 dBm 09:59:14.754361169 Link Quality=21/70 Signal level=-89 dBm 09:59:14.866217355 Link Quality=21/70 Signal level=-89 dBm 09:59:14.976963623 Link Quality=28/70 Signal level=-82 dBm 09:59:15.089149809 Link Quality=26/70 Signal level=-84 dBm 09:59:15.205039887 Link Quality=27/70 Signal level=-83 dBm 09:59:15.316368003 Link Quality=23/70 Signal level=-87 dBm 09:59:15.427684036 Link Quality=36/70 Signal level=-74 dBm 09:59:15.539756380 Link Quality=21/70 Signal level=-89 dBm 09:59:15.650549093 Link Quality=22/70 Signal level=-88 dBm 09:59:15.761171672 Link Quality=32/70 Signal level=-78 dBm 09:59:15.872793750 Link Quality=23/70 Signal level=-87 dBm 09:59:15.984421694 Link Quality=22/70 Signal level=-88 dBm 09:59:16.097315093 Link Quality=21/70 Signal level=-89 dBm The link quality and signal level after this patch (take while TX is in progress from STA to AP) 17:21:25.627848091 Link Quality=65/70 Signal level=-45 dBm 17:21:25.762805607 Link Quality=65/70 Signal level=-45 dBm 17:21:25.875521888 Link Quality=66/70 Signal level=-44 dBm 17:21:25.987468448 Link Quality=66/70 Signal level=-44 dBm 17:21:26.100628151 Link Quality=66/70 Signal level=-44 dBm 17:21:26.213129671 Link Quality=66/70 Signal level=-44 dBm 17:21:26.324923070 Link Quality=65/70 Signal level=-45 dBm 17:21:26.436831357 Link Quality=65/70 Signal level=-45 dBm 17:21:26.610356973 Link Quality=65/70 Signal level=-45 dBm 17:21:26.723340047 Link Quality=65/70 Signal level=-45 dBm 17:21:26.835715293 Link Quality=64/70 Signal level=-46 dBm 17:21:26.949542748 Link Quality=64/70 Signal level=-46 dBm 17:21:27.062261613 Link Quality=65/70 Signal level=-45 dBm 17:21:27.174511563 Link Quality=64/70 Signal level=-46 dBm 17:21:27.287616232 Link Quality=64/70 Signal level=-46 dBm 17:21:27.400598119 Link Quality=64/70 Signal level=-46 dBm 17:21:27.511381404 Link Quality=64/70 Signal level=-46 dBm 17:21:27.624530421 Link Quality=65/70 Signal level=-45 dBm 17:21:27.737807109 Link Quality=64/70 Signal level=-46 dBm 17:21:27.850861352 Link Quality=65/70 Signal level=-45 dBm 17:21:27.963369436 Link Quality=64/70 Signal level=-46 dBm 17:21:28.076582289 Link Quality=64/70 Signal level=-46 dBm Signed-off-by: Senthil Balasubramanian Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3afd7ee..544599b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -290,12 +290,28 @@ struct ath_tx_control { #define ATH_TX_XRETRY 0x02 #define ATH_TX_BAR 0x04 +#define ATH_RSSI_LPF_LEN 10 +#define RSSI_LPF_THRESHOLD -20 +#define ATH9K_RSSI_BAD 0x80 +#define ATH_RSSI_EP_MULTIPLIER (1<<7) +#define ATH_EP_MUL(x, mul) ((x) * (mul)) +#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER)) +#define ATH_LPF_RSSI(x, y, len) \ + ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y)) +#define ATH_RSSI_LPF(x, y) do { \ + if ((y) >= RSSI_LPF_THRESHOLD) \ + x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \ +} while (0) +#define ATH_EP_RND(x, mul) \ + ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) + struct ath_node { struct ath_softc *an_sc; struct ath_atx_tid tid[WME_NUM_TID]; struct ath_atx_ac ac[WME_NUM_AC]; u16 maxampdu; u8 mpdudensity; + int last_rssi; }; struct ath_tx { diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index a32d7e7..1f0c5fe 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -691,15 +691,22 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah, void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah) { int i, j; + s16 noise_floor; + + if (AR_SREV_9280(ah)) + noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE; + else if (AR_SREV_9285(ah)) + noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE; + else + noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE; for (i = 0; i < NUM_NF_READINGS; i++) { ah->nfCalHist[i].currIndex = 0; - ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; + ah->nfCalHist[i].privNF = noise_floor; ah->nfCalHist[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH; for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { - ah->nfCalHist[i].nfCalBuffer[j] = - AR_PHY_CCA_MAX_GOOD_VALUE; + ah->nfCalHist[i].nfCalBuffer[j] = noise_floor; } } } diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index fe5367f..547e697 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -25,7 +25,9 @@ extern const struct ath9k_percal_data adc_dc_cal_multi_sample; extern const struct ath9k_percal_data adc_dc_cal_single_sample; extern const struct ath9k_percal_data adc_init_dc_cal; -#define AR_PHY_CCA_MAX_GOOD_VALUE -85 +#define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE -85 +#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE -112 +#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE -118 #define AR_PHY_CCA_MAX_HIGH_VALUE -62 #define AR_PHY_CCA_MIN_BAD_VALUE -140 #define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 19df788..2ad7184 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -465,6 +465,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + sta->ht_cap.ampdu_factor); an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); + an->last_rssi = ATH_RSSI_DUMMY_MARKER; } } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index b3da81d..61edfab 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -145,6 +145,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, u8 ratecode; __le16 fc; struct ieee80211_hw *hw; + struct ieee80211_sta *sta; + struct ath_node *an; + int last_rssi = ATH_RSSI_DUMMY_MARKER; + hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; @@ -229,11 +233,30 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, } } + rcu_read_lock(); + sta = ieee80211_find_sta(sc->hw, hdr->addr2); + if (sta) { + an = (struct ath_node *) sta->drv_priv; + if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD && + !ds->ds_rxstat.rs_moreaggr) + ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi); + last_rssi = an->last_rssi; + } + rcu_read_unlock(); + + if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) + ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi, + ATH_RSSI_EP_MULTIPLIER); + if (ds->ds_rxstat.rs_rssi < 0) + ds->ds_rxstat.rs_rssi = 0; + else if (ds->ds_rxstat.rs_rssi > 127) + ds->ds_rxstat.rs_rssi = 127; + rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); rx_status->band = hw->conf.channel->band; rx_status->freq = hw->conf.channel->center_freq; rx_status->noise = sc->ani.noise_floor; - rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; + rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi; rx_status->antenna = ds->ds_rxstat.rs_antenna; /* -- cgit v0.10.2 From dd8b15b027d96f7097ae9dbaebd822a114a03c34 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Tue, 14 Jul 2009 20:17:08 -0400 Subject: ath9k: RX stucks during heavy traffic in HT40 mode. Running iperf along with p2p traffic on both TX and RX side then stop one side, then stop the other side, then start it up again, eventually the STA gets into a mode that it can not pass data at all. A hardware workaround for invalid RSSI can make FIFO write pointer to jump over read pointer, causing RX data corruption and repeated DMA. Both TX and RX works fine when the workaround is disabled. To replace the original hardware work around, software looks for frames with post delimiter CRC error and mark the RSSI invalid so that the upperlayer will not use the RSSI associated with this frame. So disable the hardware workaround by updating the appropriate registers. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index d82a0f9..df41ed5 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -1208,6 +1208,19 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, pModal->xatten2Margin[0]); REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); + + /* Set the block 1 value to block 0 value */ + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, + pModal->xatten2Db[0]); } REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, @@ -1215,6 +1228,11 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + if (AR_SREV_9285_11(ah)) REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); } @@ -1239,7 +1257,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); /* Initialize Ant Diversity settings from EEPROM */ - if (pModal->version == 3) { + if (pModal->version >= 3) { ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); regVal = REG_READ(ah, 0x99ac); diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index e2f0a34..f67a2a9 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -2782,7 +2782,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008338, 0x00ff0000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x000107ff }, - { 0x00008344, 0x00581043 }, + { 0x00008344, 0x00481043 }, { 0x00009808, 0x00000000 }, { 0x0000980c, 0xafa68e30 }, { 0x00009810, 0xfd14e000 }, @@ -3439,7 +3439,7 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { {0x00004044, 0x00000000 }, }; -/* AR9285 */ +/* AR9285 Revsion 10*/ static const u_int32_t ar9285Modes_9285[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -3955,7 +3955,7 @@ static const u_int32_t ar9285Common_9285[][2] = { { 0x00008338, 0x00000000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x00010380 }, - { 0x00008344, 0x00581043 }, + { 0x00008344, 0x00481043 }, { 0x00009808, 0x00000000 }, { 0x0000980c, 0xafe68e30 }, { 0x00009810, 0xfd14e000 }, @@ -4121,8 +4121,9 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = { {0x00004044, 0x00000000 }, }; -/* AR9285 v1_2 PCI Register Writes. Created: 03/04/09 */ +/* AR9285 v1_2 PCI Register Writes. Created: 04/13/09 */ static const u_int32_t ar9285Modes_9285_1_2[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, @@ -4139,6 +4140,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 }, { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e }, @@ -4419,6 +4421,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, + { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, @@ -4618,7 +4621,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00008338, 0x00ff0000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x00010380 }, - { 0x00008344, 0x00581043 }, + { 0x00008344, 0x00481043 }, { 0x00009808, 0x00000000 }, { 0x0000980c, 0xafe68e30 }, { 0x00009810, 0xfd14e000 }, @@ -4752,18 +4755,18 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 }, - { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 }, { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 }, { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 }, - { 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 }, - { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 }, - { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 }, - { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 }, - { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 }, - { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 }, { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 }, { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, @@ -4776,13 +4779,13 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 }, { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe }, { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, - { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, - { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, - { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, - { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, - { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, + { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 }, + { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 }, + { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 }, + { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 }, }; static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = { diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 8ae4ec2..6f923e3 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -825,13 +825,29 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; - ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); - ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); - ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); - ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); - ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); - ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); - ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); + if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) { + ds->ds_rxstat.rs_rssi = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ctl0 = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ctl1 = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ctl2 = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ext0 = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ext1 = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ext2 = ATH9K_RSSI_BAD; + } else { + ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); + ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, + AR_RxRSSIAnt00); + ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, + AR_RxRSSIAnt01); + ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, + AR_RxRSSIAnt02); + ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, + AR_RxRSSIAnt10); + ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, + AR_RxRSSIAnt11); + ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, + AR_RxRSSIAnt12); + } if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); else -- cgit v0.10.2 From 164ace38536849966ffa377b1b1132993a5a375d Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Tue, 14 Jul 2009 20:17:09 -0400 Subject: ath9k: Fix TX hang issue with Atheros chipsets The hardware doesn't generate interrupts in some cases and so work around this by monitoring the TX status periodically and reset the chip if required. This behavior of the hardware not generating the TX interrupts can be noticed through ath9k debugfs interrupt statistics when heavy traffic is being sent from STA to AP. One can easily see this behavior when the STA is transmitting at a higher rates. The interrupt statistics in the debugfs interface clearly shows that only RX interrupts alone being generated and TX being stuck. TX should be monitored through a timer and reset the chip only when frames are queued to the hardware but TX interrupts are not generated for the same even after one second. Also, we shouldn't remove holding descriptor from AC queue if it happens to be the only descriptor and schedule TX aggregation regarless of queue depth as it improves scheduling of AMPDUs from software to hardware queue. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 544599b..20bf4a7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -225,6 +225,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) #define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) +#define ATH_TX_COMPLETE_POLL_INT 1000 + enum ATH_AGGR_STATUS { ATH_AGGR_DONE, ATH_AGGR_BAW_CLOSED, @@ -240,6 +242,7 @@ struct ath_txq { u8 axq_aggr_depth; u32 axq_totalqueued; bool stopped; + bool axq_tx_inprogress; struct ath_buf *axq_linkbuf; /* first desc of the last descriptor that contains CTS */ @@ -605,6 +608,7 @@ struct ath_softc { #endif struct ath_bus_ops *bus_ops; struct ath_beacon_config cur_beacon_conf; + struct delayed_work tx_complete_work; }; struct ath_wiphy { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2ad7184..46f4a69 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1259,6 +1259,7 @@ void ath_detach(struct ath_softc *sc) ath_deinit_leds(sc); cancel_work_sync(&sc->chan_work); cancel_delayed_work_sync(&sc->wiphy_work); + cancel_delayed_work_sync(&sc->tx_complete_work); for (i = 0; i < sc->num_sec_wiphy; i++) { struct ath_wiphy *aphy = sc->sec_wiphy[i]; @@ -1979,6 +1980,8 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_wake_queues(hw); + queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0); + mutex_unlock: mutex_unlock(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 5de9878..a3bc431 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -857,6 +857,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_aggr_depth = 0; txq->axq_totalqueued = 0; txq->axq_linkbuf = NULL; + txq->axq_tx_inprogress = false; sc->tx.txqsetup |= 1<tx.txq[qnum]; @@ -1023,6 +1024,10 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); } + spin_lock_bh(&txq->axq_lock); + txq->axq_tx_inprogress = false; + spin_unlock_bh(&txq->axq_lock); + /* flush any pending frames if aggregation is enabled */ if (sc->sc_flags & SC_OP_TXAGGR) { if (!retry_tx) { @@ -1103,8 +1108,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) if (tid->paused) continue; - if ((txq->axq_depth % 2) == 0) - ath_tx_sched_aggr(sc, txq, tid); + ath_tx_sched_aggr(sc, txq, tid); /* * add tid to round-robin queue if more frames @@ -1947,19 +1951,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (bf->bf_stale) { bf_held = bf; if (list_is_last(&bf_held->list, &txq->axq_q)) { - txq->axq_link = NULL; - txq->axq_linkbuf = NULL; spin_unlock_bh(&txq->axq_lock); - - /* - * The holding descriptor is the last - * descriptor in queue. It's safe to remove - * the last holding descriptor in BH context. - */ - spin_lock_bh(&sc->tx.txbuflock); - list_move_tail(&bf_held->list, &sc->tx.txbuf); - spin_unlock_bh(&sc->tx.txbuflock); - break; } else { bf = list_entry(bf_held->list.next, @@ -1996,6 +1988,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) txq->axq_aggr_depth--; txok = (ds->ds_txstat.ts_status == 0); + txq->axq_tx_inprogress = false; spin_unlock_bh(&txq->axq_lock); if (bf_held) { @@ -2029,6 +2022,40 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } } +void ath_tx_complete_poll_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + tx_complete_work.work); + struct ath_txq *txq; + int i; + bool needreset = false; + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) { + txq = &sc->tx.txq[i]; + spin_lock_bh(&txq->axq_lock); + if (txq->axq_depth) { + if (txq->axq_tx_inprogress) { + needreset = true; + spin_unlock_bh(&txq->axq_lock); + break; + } else { + txq->axq_tx_inprogress = true; + } + } + spin_unlock_bh(&txq->axq_lock); + } + + if (needreset) { + DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n"); + ath_reset(sc, false); + } + + queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, + msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT)); +} + + void ath_tx_tasklet(struct ath_softc *sc) { @@ -2069,6 +2096,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) goto err; } + INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); + err: if (error != 0) ath_tx_cleanup(sc); -- cgit v0.10.2 From 8e7f98b5690fc295e3a39b99aeed475d28c60c90 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:17:10 -0400 Subject: ath9k: Remove bogus assert in ath_clone_txbuf() oops, this one should be part of the original patch "ath9k: downgrade assert in ath_clone_txbuf()" Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a3bc431..24663ce 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -242,7 +242,6 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) spin_unlock_bh(&sc->tx.txbuflock); return NULL; } - ASSERT(!list_empty((&sc->tx.txbuf))); tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); list_del(&tbf->list); spin_unlock_bh(&sc->tx.txbuflock); -- cgit v0.10.2 From c41d92dc9d9a1afcec0095c32698ea7deff01098 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:17:11 -0400 Subject: ath9k: Handle tx desc shortage more appropriately Update tx BA window and complete the frame as failed one if we can't clone the holding descriptor due to unavailability of descriptors. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 24663ce..4ff155e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -382,8 +382,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *tbf; tbf = ath_clone_txbuf(sc, bf_last); - if (!tbf) + /* + * Update tx baw and complete the frame with + * failed status if we run out of tx buf + */ + if (!tbf) { + spin_lock_bh(&txq->axq_lock); + ath_tx_update_baw(sc, tid, + bf->bf_seqno); + spin_unlock_bh(&txq->axq_lock); + + bf->bf_state.bf_type |= BUF_XRETRY; + ath_tx_rc_status(bf, ds, nbad, + 0, false); + ath_tx_complete_buf(sc, bf, &bf_head, + 0, 0); break; + } + ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc); list_add_tail(&tbf->list, &bf_head); } else { -- cgit v0.10.2 From ebaa24534ef54a8f665558536dbef3a761a9b841 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:17:12 -0400 Subject: ath9k: Remove pointless ath9k_ps_restore() in ath_detach() Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 46f4a69..90cecce 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1286,7 +1286,6 @@ void ath_detach(struct ath_softc *sc) ath9k_hw_detach(sc->sc_ah); ath9k_exit_debug(sc); - ath9k_ps_restore(sc); } static int ath9k_reg_notifier(struct wiphy *wiphy, -- cgit v0.10.2 From 04717ccd80e5acc500239222684fcf8d2c759a84 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 14 Jul 2009 20:17:13 -0400 Subject: ath9k: serialize ath9k_hw_setpower calls Because ath9k_setpower is called from various contexts, we have to protect it against concurrent calls. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 20bf4a7..b37eb59 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -559,6 +559,7 @@ struct ath_softc { spinlock_t sc_resetlock; spinlock_t sc_serial_rw; spinlock_t ani_lock; + spinlock_t sc_pm_lock; struct mutex mutex; u8 curbssid[ETH_ALEN]; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index a115c8c..6740a6b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2728,7 +2728,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) return true; } -bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) +static bool ath9k_hw_setpower_nolock(struct ath_hw *ah, + enum ath9k_power_mode mode) { int status = true, setChip = true; static const char *modes[] = { @@ -2762,6 +2763,18 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) return status; } +bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags); + ret = ath9k_hw_setpower_nolock(ah, mode); + spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags); + + return ret; +} + /* * Helper for ASPM support. * diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 90cecce..d14f8c9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1316,6 +1316,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) spin_lock_init(&sc->sc_resetlock); spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->ani_lock); + spin_lock_init(&sc->sc_pm_lock); mutex_init(&sc->mutex); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, -- cgit v0.10.2 From 0bc0798b7605664c3ab8d577b398dc7ae0b2e58c Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 14 Jul 2009 20:17:14 -0400 Subject: ath9k: uninline ath9k_ps_{wakeup,restore} functions Uninline these functions before we add functional changes to them. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b37eb59..8b38c0a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -674,27 +674,8 @@ static inline int ath_ahb_init(void) { return 0; }; static inline void ath_ahb_exit(void) {}; #endif -static inline void ath9k_ps_wakeup(struct ath_softc *sc) -{ - if (atomic_inc_return(&sc->ps_usecount) == 1) - if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { - sc->sc_ah->restore_mode = sc->sc_ah->power_mode; - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - } -} - -static inline void ath9k_ps_restore(struct ath_softc *sc) -{ - if (atomic_dec_and_test(&sc->ps_usecount)) - if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && - !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA | - SC_OP_WAIT_FOR_TX_ACK))) - ath9k_hw_setpower(sc->sc_ah, - sc->sc_ah->restore_mode); -} - +void ath9k_ps_wakeup(struct ath_softc *sc); +void ath9k_ps_restore(struct ath_softc *sc); void ath9k_set_bssid_mask(struct ieee80211_hw *hw); int ath9k_wiphy_add(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6740a6b..df278fd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2775,6 +2775,27 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) return ret; } +void ath9k_ps_wakeup(struct ath_softc *sc) +{ + if (atomic_inc_return(&sc->ps_usecount) == 1) + if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { + sc->sc_ah->restore_mode = sc->sc_ah->power_mode; + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); + } +} + +void ath9k_ps_restore(struct ath_softc *sc) +{ + if (atomic_dec_and_test(&sc->ps_usecount)) + if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && + !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK))) + ath9k_hw_setpower(sc->sc_ah, + sc->sc_ah->restore_mode); +} + /* * Helper for ASPM support. * -- cgit v0.10.2 From 709ade9eb8ef06e03526115408e2fc93a9feabbd Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 14 Jul 2009 20:17:15 -0400 Subject: ath9k: serialize ath9k_ps_{wakeup,restore} calls These functions are changing the power mode of the chip, but this may have unpredictable effects, if another code are trying to set the power mode via 'ath9k_hw_setpower' in the same time from another context. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8b38c0a..1576812 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -576,7 +576,7 @@ struct ath_softc { u32 keymax; DECLARE_BITMAP(keymap, ATH_KEYMAX); u8 splitmic; - atomic_t ps_usecount; + unsigned long ps_usecount; enum ath9k_int imask; enum ath9k_ht_extprotspacing ht_extprotspacing; enum ath9k_ht_macmode tx_chan_width; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index df278fd..b9d1a13 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2777,23 +2777,39 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) void ath9k_ps_wakeup(struct ath_softc *sc) { - if (atomic_inc_return(&sc->ps_usecount) == 1) - if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { - sc->sc_ah->restore_mode = sc->sc_ah->power_mode; - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - } + unsigned long flags; + + spin_lock_irqsave(&sc->sc_pm_lock, flags); + if (++sc->ps_usecount != 1) + goto unlock; + + if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { + sc->sc_ah->restore_mode = sc->sc_ah->power_mode; + ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); + } + + unlock: + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); } void ath9k_ps_restore(struct ath_softc *sc) { - if (atomic_dec_and_test(&sc->ps_usecount)) - if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && - !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA | - SC_OP_WAIT_FOR_TX_ACK))) - ath9k_hw_setpower(sc->sc_ah, - sc->sc_ah->restore_mode); + unsigned long flags; + + spin_lock_irqsave(&sc->sc_pm_lock, flags); + if (--sc->ps_usecount != 0) + goto unlock; + + if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && + !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK))) + ath9k_hw_setpower_nolock(sc->sc_ah, + sc->sc_ah->restore_mode); + + unlock: + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); } /* -- cgit v0.10.2 From 64839170be296e6348fbaf83fd103711978669b9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:22:53 -0400 Subject: ath9k: disable radio when all devices are marked idle This uses the new configuration changes indicated up by mac80211 when all interfaces are marked idle. We need to do a little more work as we have our own set of virtual wiphys within ath9k. Only when all virtual wiphys are inactive do we allow an idle state change for a wiphy to trigger disabling the radio. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1576812..751885a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -691,6 +691,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, struct ath_wiphy *selected); bool ath9k_wiphy_scanning(struct ath_softc *sc); void ath9k_wiphy_work(struct work_struct *work); +bool ath9k_all_wiphys_idle(struct ath_softc *sc); void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val); unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d14f8c9..254e787 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2260,9 +2260,28 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ath_softc *sc = aphy->sc; struct ieee80211_conf *conf = &hw->conf; struct ath_hw *ah = sc->sc_ah; + bool all_wiphys_idle = false, disable_radio = false; mutex_lock(&sc->mutex); + /* Leave this as the first check */ + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + + spin_lock_bh(&sc->wiphy_lock); + all_wiphys_idle = ath9k_all_wiphys_idle(sc); + spin_unlock_bh(&sc->wiphy_lock); + + if (conf->flags & IEEE80211_CONF_IDLE){ + if (all_wiphys_idle) + disable_radio = true; + } + else if (all_wiphys_idle) { + ath_radio_enable(sc); + DPRINTF(sc, ATH_DBG_CONFIG, + "not-idle: enabling radio\n"); + } + } + if (changed & IEEE80211_CONF_CHANGE_PS) { if (conf->flags & IEEE80211_CONF_PS) { if (!(ah->caps.hw_caps & @@ -2330,6 +2349,11 @@ skip_chan_change: if (changed & IEEE80211_CONF_CHANGE_POWER) sc->config.txpowlimit = 2 * conf->power_level; + if (disable_radio) { + DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n"); + ath_radio_disable(sc); + } + mutex_unlock(&sc->mutex); return 0; diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 1ff429b..e1d419e 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -660,3 +660,20 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, sc->wiphy_scheduler_int); } + +/* caller must hold wiphy_lock */ +bool ath9k_all_wiphys_idle(struct ath_softc *sc) +{ + unsigned int i; + if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { + return false; + } + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (!aphy) + continue; + if (aphy->state != ATH_WIPHY_INACTIVE) + return false; + } + return true; +} -- cgit v0.10.2 From ae9e4b0d1a43fd66da43918491834f9e5c1b6cca Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:23:15 -0400 Subject: cfg80211: treat ieee80211_regdom hints as user hints We were treating ieee80211_regdom module parameter hints as core hints, this means we were not letting the user help compliance further when using the module parameter. It also meant that users with a device with a custom regulatory domain set (wiphy->custom_regulatory) using this module parameter were being stuck to the original default core static regualtory domain. We fix this by using the static cfg80211_regdomain alpha2 as the core hint and treating the module parameter separately. All iwlwifi and ath5k/ath9k/ar9170 devices which world roam set the wiphy->custom_regulatory. This change allows users using this module parameter to have it trated as a a proper user hint and not have it ignored. Signed-off-by: Luis R. Rodriguez Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2b4a6c6..fb40428 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -113,11 +113,7 @@ static const struct ieee80211_regdomain world_regdom = { static const struct ieee80211_regdomain *cfg80211_world_regdom = &world_regdom; -#ifdef CONFIG_WIRELESS_OLD_REGULATORY -static char *ieee80211_regdom = "US"; -#else static char *ieee80211_regdom = "00"; -#endif module_param(ieee80211_regdom, charp, 0444); MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); @@ -2287,22 +2283,12 @@ int regulatory_init(void) printk(KERN_INFO "cfg80211: Using static regulatory domain info\n"); print_regdomain_info(cfg80211_regdomain); - /* - * The old code still requests for a new regdomain and if - * you have CRDA you get it updated, otherwise you get - * stuck with the static values. Since "EU" is not a valid - * ISO / IEC 3166 alpha2 code we can't expect userpace to - * give us a regulatory domain for it. We need last_request - * iniitalized though so lets just send a request which we - * know will be ignored... this crap will be removed once - * OLD_REG dies. - */ - err = regulatory_hint_core(ieee80211_regdom); #else cfg80211_regdomain = cfg80211_world_regdom; - err = regulatory_hint_core(ieee80211_regdom); #endif + /* We always try to get an update for the static regdomain */ + err = regulatory_hint_core(cfg80211_regdomain->alpha2); if (err) { if (err == -ENOMEM) return err; @@ -2321,6 +2307,13 @@ int regulatory_init(void) #endif } + /* + * Finally, if the user set the module parameter treat it + * as a user hint. + */ + if (!is_world_regdom(ieee80211_regdom)) + regulatory_hint_user(ieee80211_regdom); + return 0; } -- cgit v0.10.2 From 04dc882d601ec6fae5dfcb47c43f7af343e9a135 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Wed, 15 Jul 2009 08:51:17 +0530 Subject: ath9k: Add AR9287 based chipsets' register information. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 5260524..8302aeb 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -574,6 +574,7 @@ #define AR_D_GBL_IFS_SIFS 0x1030 #define AR_D_GBL_IFS_SIFS_M 0x0000FFFF +#define AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR 0x000003AB #define AR_D_GBL_IFS_SIFS_RESV0 0xFFFFFFFF #define AR_D_TXBLK_BASE 0x1038 @@ -589,10 +590,12 @@ #define AR_D_GBL_IFS_SLOT 0x1070 #define AR_D_GBL_IFS_SLOT_M 0x0000FFFF #define AR_D_GBL_IFS_SLOT_RESV0 0xFFFF0000 +#define AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR 0x00000420 #define AR_D_GBL_IFS_EIFS 0x10b0 #define AR_D_GBL_IFS_EIFS_M 0x0000FFFF #define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000 +#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR 0x0000A5EB #define AR_D_GBL_IFS_MISC 0x10f0 #define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007 @@ -738,6 +741,9 @@ #define AR_SREV_REVISION_9285_10 0 #define AR_SREV_REVISION_9285_11 1 #define AR_SREV_REVISION_9285_12 2 +#define AR_SREV_VERSION_9287 0x180 +#define AR_SREV_REVISION_9287_10 0 +#define AR_SREV_REVISION_9287_11 1 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -794,6 +800,21 @@ (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \ AR_SREV_REVISION_9285_12))) +#define AR_SREV_9287(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287)) +#define AR_SREV_9287_10_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287)) +#define AR_SREV_9287_10(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_10)) +#define AR_SREV_9287_11(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_11)) +#define AR_SREV_9287_11_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11))) + #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 #define AR_RAD2133_SREV_MAJOR 0xd0 @@ -809,6 +830,9 @@ #define AR_AHB_PAGE_SIZE_1K 0x00000000 #define AR_AHB_PAGE_SIZE_2K 0x00000008 #define AR_AHB_PAGE_SIZE_4K 0x00000010 +#define AR_AHB_CUSTOM_BURST_EN 0x000000C0 +#define AR_AHB_CUSTOM_BURST_EN_S 6 +#define AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL 3 #define AR_INTR_RTC_IRQ 0x00000001 #define AR_INTR_MAC_IRQ 0x00000002 @@ -885,6 +909,7 @@ enum { #define AR_NUM_GPIO 14 #define AR928X_NUM_GPIO 10 #define AR9285_NUM_GPIO 12 +#define AR9287_NUM_GPIO 11 #define AR_GPIO_IN_OUT 0x4048 #define AR_GPIO_IN_VAL 0x0FFFC000 @@ -893,6 +918,8 @@ enum { #define AR928X_GPIO_IN_VAL_S 10 #define AR9285_GPIO_IN_VAL 0x00FFF000 #define AR9285_GPIO_IN_VAL_S 12 +#define AR9287_GPIO_IN_VAL 0x003FF800 +#define AR9287_GPIO_IN_VAL_S 11 #define AR_GPIO_OE_OUT 0x404c #define AR_GPIO_OE_OUT_DRV 0x3 @@ -1154,6 +1181,33 @@ enum { #define AR9285_AN_TOP4 0x7870 #define AR9285_AN_TOP4_DEFAULT 0x10142c00 +#define AR9287_AN_RF2G3_CH0 0x7808 +#define AR9287_AN_RF2G3_CH1 0x785c +#define AR9287_AN_RF2G3_DB1 0xE0000000 +#define AR9287_AN_RF2G3_DB1_S 29 +#define AR9287_AN_RF2G3_DB2 0x1C000000 +#define AR9287_AN_RF2G3_DB2_S 26 +#define AR9287_AN_RF2G3_OB_CCK 0x03800000 +#define AR9287_AN_RF2G3_OB_CCK_S 23 +#define AR9287_AN_RF2G3_OB_PSK 0x00700000 +#define AR9287_AN_RF2G3_OB_PSK_S 20 +#define AR9287_AN_RF2G3_OB_QAM 0x000E0000 +#define AR9287_AN_RF2G3_OB_QAM_S 17 +#define AR9287_AN_RF2G3_OB_PAL_OFF 0x0001C000 +#define AR9287_AN_RF2G3_OB_PAL_OFF_S 14 + +#define AR9287_AN_TXPC0 0x7898 +#define AR9287_AN_TXPC0_TXPCMODE 0x0000C000 +#define AR9287_AN_TXPC0_TXPCMODE_S 14 +#define AR9287_AN_TXPC0_TXPCMODE_NORMAL 0 +#define AR9287_AN_TXPC0_TXPCMODE_TEST 1 +#define AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE 2 +#define AR9287_AN_TXPC0_TXPCMODE_ATBTEST 3 + +#define AR9287_AN_TOP2 0x78b4 +#define AR9287_AN_TOP2_XPABIAS_LVL 0xC0000000 +#define AR9287_AN_TOP2_XPABIAS_LVL_S 30 + #define AR_STA_ID0 0x8000 #define AR_STA_ID1 0x8004 #define AR_STA_ID1_SADH_MASK 0x0000FFFF @@ -1188,6 +1242,7 @@ enum { #define AR_TIME_OUT_ACK_S 0 #define AR_TIME_OUT_CTS 0x3FFF0000 #define AR_TIME_OUT_CTS_S 16 +#define AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR 0x16001D56 #define AR_RSSI_THR 0x8018 #define AR_RSSI_THR_MASK 0x000000FF @@ -1203,6 +1258,7 @@ enum { #define AR_USEC_TX_LAT_S 14 #define AR_USEC_RX_LAT 0x1F800000 #define AR_USEC_RX_LAT_S 23 +#define AR_USEC_ASYNC_FIFO_DUR 0x12e00074 #define AR_RESET_TSF 0x8020 #define AR_RESET_TSF_ONCE 0x01000000 @@ -1468,6 +1524,10 @@ enum { #define AR_SLP_MIB_CLEAR 0x00000001 #define AR_SLP_MIB_PENDING 0x00000002 +#define AR_MAC_PCU_LOGIC_ANALYZER 0x8264 +#define AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768 0x20000000 + + #define AR_2040_MODE 0x8318 #define AR_2040_JOINED_RX_CLEAR 0x00000001 @@ -1485,6 +1545,39 @@ enum { #define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002 #define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004 +#define AR_PCU_MISC_MODE2_RESERVED 0x00000038 +#define AR_PCU_MISC_MODE2_ADHOC_MCAST_KEYID_ENABLE 0x00000040 +#define AR_PCU_MISC_MODE2_CFP_IGNORE 0x00000080 +#define AR_PCU_MISC_MODE2_MGMT_QOS 0x0000FF00 +#define AR_PCU_MISC_MODE2_MGMT_QOS_S 8 +#define AR_PCU_MISC_MODE2_ENABLE_LOAD_NAV_BEACON_DURATION 0x00010000 +#define AR_PCU_MISC_MODE2_ENABLE_AGGWEP 0x00020000 +#define AR_PCU_MISC_MODE2_HWWAR1 0x00100000 +#define AR_PCU_MISC_MODE2_HWWAR2 0x02000000 +#define AR_PCU_MISC_MODE2_RESERVED2 0xFFFE0000 + +#define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358 +#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400 +#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000 + + +#define AR_AES_MUTE_MASK0 0x805c +#define AR_AES_MUTE_MASK0_FC 0x0000FFFF +#define AR_AES_MUTE_MASK0_QOS 0xFFFF0000 +#define AR_AES_MUTE_MASK0_QOS_S 16 + +#define AR_AES_MUTE_MASK1 0x8060 +#define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF +#define AR_AES_MUTE_MASK1_SEQ_S 0 +#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000 +#define AR_AES_MUTE_MASK1_FC_MGMT_S 16 + +#define AR_RATE_DURATION_0 0x8700 +#define AR_RATE_DURATION_31 0x87CC +#define AR_RATE_DURATION_32 0x8780 +#define AR_RATE_DURATION(_n) (AR_RATE_DURATION_0 + ((_n)<<2)) + + #define AR_KEYTABLE_0 0x8800 #define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32)) #define AR_KEY_CACHE_SIZE 128 -- cgit v0.10.2 From e91d83346ad9b30f44469c92b982206dcd7dcaf0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Jul 2009 17:21:41 +0200 Subject: wireless: remove print_mac uses Use %pM instead, and also remove stray variables declared with DECLARE_MAC_BUF. Signed-off-by: Johannes Berg Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index cfe6fc7..c7287a8 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2628,7 +2628,6 @@ static int ar9170_read_eeprom(struct ar9170 *ar) { #define RW 8 /* number of words to read at once */ #define RB (sizeof(u32) * RW) - DECLARE_MAC_BUF(mbuf); u8 *eeprom = (void *)&ar->eeprom; u8 *addr = ar->eeprom.mac_address; __le32 offsets[RW]; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e71c8d9..3f4360a 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -938,7 +938,6 @@ static void b43_clear_keys(struct b43_wldev *dev) static void b43_dump_keymemory(struct b43_wldev *dev) { unsigned int i, index, offset; - DECLARE_MAC_BUF(macbuf); u8 mac[ETH_ALEN]; u16 algo; u32 rcmta0; @@ -973,8 +972,7 @@ static void b43_dump_keymemory(struct b43_wldev *dev) ((index - 4) * 2) + 1); *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0); *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1); - printk(" MAC: %s", - print_mac(macbuf, mac)); + printk(" MAC: %pM", mac); } else printk(" DEFAULT KEY"); printk("\n"); diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index fbf2649..385b50f 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -129,7 +129,6 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth { struct cmd_ds_802_11_authenticate cmd; int ret = -1; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); @@ -138,8 +137,7 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth cmd.authtype = iw_auth_to_ieee_auth(auth); - lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", - print_mac(mac, bssid), cmd.authtype); + lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype); ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); @@ -342,8 +340,6 @@ static int lbs_associate(struct lbs_private *priv, /* Firmware v9+ indicate authentication suites as a TLV */ if (priv->fwrelease >= 0x09000000) { - DECLARE_MAC_BUF(mac); - auth = (struct mrvl_ie_auth_type *) pos; auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); auth->header.len = cpu_to_le16(2); @@ -351,8 +347,8 @@ static int lbs_associate(struct lbs_private *priv, auth->auth = cpu_to_le16(tmpauth); pos += sizeof(auth->header) + 2; - lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", - print_mac(mac, bss->bssid), priv->secinfo.auth_mode); + lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", + bss->bssid, priv->secinfo.auth_mode); } /* WPA/WPA2 IEs */ diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 78431ab..930f5c7 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -837,7 +837,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) { struct mac80211_hwsim_data *data = dat; struct hwsim_vif_priv *vp = (void *)vif->drv_priv; - DECLARE_MAC_BUF(buf); struct sk_buff *skb; struct ieee80211_pspoll *pspoll; @@ -867,7 +866,6 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, struct ieee80211_vif *vif, int ps) { struct hwsim_vif_priv *vp = (void *)vif->drv_priv; - DECLARE_MAC_BUF(buf); struct sk_buff *skb; struct ieee80211_hdr *hdr; diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b9eded8..4f72547 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2271,7 +2271,6 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, struct mwl8k_cmd_update_sta_db *cmd; struct peer_capability_info *peer_info; struct ieee80211_rate *bitrates = mv_vif->legacy_rates; - DECLARE_MAC_BUF(mac); int rc; __u8 count, *rates; @@ -3480,7 +3479,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, { struct ieee80211_hw *hw; struct mwl8k_priv *priv; - DECLARE_MAC_BUF(mac); int rc; int i; u8 *fw; @@ -3669,8 +3667,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, MWL8K_DESC); printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n", priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]); - printk(KERN_INFO "%s: MAC Address: %s\n", priv->name, - print_mac(mac, hw->wiphy->perm_addr)); + printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name, + hw->wiphy->perm_addr); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 66e001c..f35b3d6 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2220,10 +2220,8 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 106b0f2..509cbef 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -435,11 +435,10 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct wl1251 *wl = hw->priv; - DECLARE_MAC_BUF(mac); int ret = 0; - wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", - conf->type, print_mac(mac, conf->mac_addr)); + wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", + conf->type, conf->mac_addr); mutex_lock(&wl->mutex); -- cgit v0.10.2 From ea9edaf6bc0e3f3a7bd167d9ba369276a30c9953 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 15 Jul 2009 22:49:27 -0500 Subject: hostap_cs: Enable shared interrupts The hostap_cs driver is programmed for exclusive rather that shared interrupts. Signed-off-by: Larry Finger Reported-and-Tested-by: Jack Schneider Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 6337402..ad8eab4 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -666,7 +666,8 @@ static int prism2_config(struct pcmcia_device *link) * irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) { - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | + IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = prism2_interrupt; link->irq.Instance = dev; -- cgit v0.10.2 From 1cc589b9e7d95888bb8cc806c210d8ab5371d40f Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:06 +0800 Subject: iwmc3200wifi: fix UMAC INIT_COMPLETE notification handling The patch fixes the missing UMAC iwm_umac_wifi_in_hdr header in the UMAC INIT_COMPLETE (iwm_umac_notif_init_complete) notification. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 3909477..59ef69c 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -102,7 +102,6 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, error = (struct iwm_umac_notif_error *)buf; fw_err = &error->err; - IWM_ERR(iwm, "%cMAC FW ERROR:\n", (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h index 0af2a3c..c5a14ae 100644 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -615,6 +615,7 @@ struct iwm_umac_notif_alive { } __attribute__ ((packed)); struct iwm_umac_notif_init_complete { + struct iwm_umac_wifi_in_hdr hdr; __le16 status; __le16 reserved; } __attribute__ ((packed)); @@ -643,6 +644,11 @@ struct iwm_fw_error_hdr { __le32 umac_status; __le32 lmac_status; __le32 sdio_status; + __le32 dbm_sample_ctrl; + __le32 dbm_buf_base; + __le32 dbm_buf_end; + __le32 dbm_buf_write_ptr; + __le32 dbm_buf_cycle_cnt; } __attribute__ ((packed)); struct iwm_umac_notif_error { -- cgit v0.10.2 From 3a0e4851c97328ee455a57cb3e4097bb43934a87 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:07 +0800 Subject: iwmc3200wifi: hardware does not support IP checksum The iwmc3200wifi hardware doesn't support IP checksum. So mark the skb->ip_summed to CHECKSUM_NONE instead of CHECKSUM_UNNECESSARY. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 59ef69c..9fb498b 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1359,7 +1359,7 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm, skb->dev = iwm_to_ndev(iwm); skb->protocol = eth_type_trans(skb, ndev); - skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->ip_summed = CHECKSUM_NONE; memset(skb->cb, 0, sizeof(skb->cb)); ndev->stats.rx_packets++; -- cgit v0.10.2 From 49b7772776359b8306ce740bfc52d32b344adc83 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:08 +0800 Subject: iwmc3200wifi: set cipher_suites before registering wiphy We need to specify all the cipher suites we supported. Otherwise cfg80211_validate_key_settings() will fail when we are setting keys. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 54bebba..0aa3895 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -558,6 +558,13 @@ static struct cfg80211_ops iwm_cfg80211_ops = { .set_power_mgmt = iwm_cfg80211_set_power_mgmt, }; +static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) { int ret = 0; @@ -600,6 +607,9 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz; wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wdev->wiphy->cipher_suites = cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + ret = wiphy_register(wdev->wiphy); if (ret < 0) { dev_err(dev, "Couldn't register wiphy device\n"); -- cgit v0.10.2 From 4fdd81f5f2e6fc55b67938f09b3495d679428cd7 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:09 +0800 Subject: iwmc3200wifi: use correct debug level This patch uses TX and RX instead of NTF debug levels in some hot paths. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 9fb498b..218933b 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -218,17 +218,17 @@ static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf, (buf + sizeof(struct iwm_umac_wifi_in_hdr)); hdr = (struct iwm_umac_wifi_in_hdr *)buf; - IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); - - IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n", - le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); - IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); - IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n", - le16_to_cpu(tx_resp->retry_cnt)); - IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); - IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n", - le16_to_cpu(tx_resp->byte_cnt)); - IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); + IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); + + IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n", + le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); + IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); + IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n", + le16_to_cpu(tx_resp->retry_cnt)); + IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); + IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n", + le16_to_cpu(tx_resp->byte_cnt)); + IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); return 0; } @@ -418,8 +418,8 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf, if (IS_ERR(ticket_node)) return PTR_ERR(ticket_node); - IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n", - ticket->id); + IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n", + ticket->id); list_add_tail(&ticket_node->node, &iwm->rx_tickets); /* @@ -454,15 +454,15 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf, u16 id, buf_offset; u32 packet_size; - IWM_DBG_NTF(iwm, DBG, "\n"); + IWM_DBG_RX(iwm, DBG, "\n"); wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); buf_offset = sizeof(struct iwm_umac_wifi_in_hdr); packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr); - IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", - wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); + IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", + wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id); IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size); -- cgit v0.10.2 From 9967d46aa5ba065650d3352ab5d906f56ba17648 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 16 Jul 2009 17:34:10 +0800 Subject: iwmc3200wifi: cfg80211 managed mode port This patch ports iwmc3200wifi to the cfg80211 managed mode API. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 0aa3895..ee40317 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -305,6 +305,25 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, return iwm_reset_profile(iwm); } +int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, + u8 *mac, struct station_info *sinfo) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + + if (memcmp(mac, iwm->bssid, ETH_ALEN)) + return -ENOENT; + + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = iwm->rate * 10; + + if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = iwm->wstats.qual.level; + } + + return 0; +} + int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) { @@ -500,6 +519,179 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return 0; } +static int iwm_set_auth_type(struct iwm_priv *iwm, + enum nl80211_auth_type sme_auth_type) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + switch (sme_auth_type) { + case NL80211_AUTHTYPE_AUTOMATIC: + case NL80211_AUTHTYPE_OPEN_SYSTEM: + IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n"); + *auth_type = UMAC_AUTH_TYPE_OPEN; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { + IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n"); + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + } else { + IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n"); + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } + + break; + default: + IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version) +{ + if (!wpa_version) { + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; + return 0; + } + + if (wpa_version & NL80211_WPA_VERSION_2) + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; + + if (wpa_version & NL80211_WPA_VERSION_1) + iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK; + + return 0; +} + +static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast) +{ + u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : + &iwm->umac_profile->sec.mcast_cipher; + + if (!cipher) { + *profile_cipher = UMAC_CIPHER_TYPE_NONE; + return 0; + } + + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + *profile_cipher = UMAC_CIPHER_TYPE_NONE; + break; + case WLAN_CIPHER_SUITE_WEP40: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; + break; + case WLAN_CIPHER_SUITE_WEP104: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; + break; + case WLAN_CIPHER_SUITE_TKIP: + *profile_cipher = UMAC_CIPHER_TYPE_TKIP; + break; + case WLAN_CIPHER_SUITE_CCMP: + *profile_cipher = UMAC_CIPHER_TYPE_CCMP; + break; + default: + IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt); + + if (key_mgt == WLAN_AKM_SUITE_8021X) + *auth_type = UMAC_AUTH_TYPE_8021X; + else if (key_mgt == WLAN_AKM_SUITE_PSK) { + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + else + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } else { + IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); + return -EINVAL; + } + + return 0; +} + + +static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + struct ieee80211_channel *chan = sme->channel; + int ret; + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + if (!sme->ssid) + return -EINVAL; + + if (chan) + iwm->channel = + ieee80211_frequency_to_channel(chan->center_freq); + + iwm->umac_profile->ssid.ssid_len = sme->ssid_len; + memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len); + + if (sme->bssid) { + IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid); + memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN); + iwm->umac_profile->bss_num = 1; + } else { + memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); + iwm->umac_profile->bss_num = 0; + } + + ret = iwm_set_auth_type(iwm, sme->auth_type); + if (ret < 0) + return ret; + + ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions); + if (ret < 0) + return ret; + + if (sme->crypto.n_ciphers_pairwise) { + ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0], + true); + if (ret < 0) + return ret; + } + + ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false); + if (ret < 0) + return ret; + + if (sme->crypto.n_akm_suites) { + ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]); + if (ret < 0) + return ret; + } + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active); + + if (iwm->umac_profile_active) + return iwm_invalidate_mlme_profile(iwm); + + return 0; +} + static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, enum tx_power_setting type, int dbm) { @@ -549,8 +741,11 @@ static struct cfg80211_ops iwm_cfg80211_ops = { .get_key = iwm_cfg80211_get_key, .del_key = iwm_cfg80211_del_key, .set_default_key = iwm_cfg80211_set_default_key, + .get_station = iwm_cfg80211_get_station, .scan = iwm_cfg80211_scan, .set_wiphy_params = iwm_cfg80211_set_wiphy_params, + .connect = iwm_cfg80211_connect, + .disconnect = iwm_cfg80211_disconnect, .join_ibss = iwm_cfg80211_join_ibss, .leave_ibss = iwm_cfg80211_leave_ibss, .set_tx_power = iwm_cfg80211_set_txpower, diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 218933b..82b572a 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -503,13 +503,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, { struct iwm_umac_notif_assoc_complete *complete = (struct iwm_umac_notif_assoc_complete *)buf; - union iwreq_data wrqu; IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", complete->bssid, complete->status); - memset(&wrqu, 0, sizeof(wrqu)); - clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); switch (le32_to_cpu(complete->status)) { @@ -520,7 +517,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, iwm_link_on(iwm); - memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN); + cfg80211_connect_result(iwm_to_ndev(iwm), + complete->bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_SUCCESS, GFP_KERNEL); break; case UMAC_ASSOC_COMPLETE_FAILURE: clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); @@ -528,6 +528,11 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, iwm->channel = 0; iwm_link_off(iwm); + + cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); default: break; } @@ -537,9 +542,6 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, return 0; } - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL); - return 0; } diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 2e7eaf9..c3c90d5 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -21,31 +21,11 @@ * */ -#include -#include #include -#include -#include #include -#include #include "iwm.h" -#include "umac.h" #include "commands.h" -#include "debug.h" - -static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - struct iw_statistics *wstats = &iwm->wstats; - - if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { - memset(wstats, 0, sizeof(struct iw_statistics)); - wstats->qual.updated = IW_QUAL_ALL_INVALID; - } - - return wstats; -} static int iwm_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, @@ -53,14 +33,12 @@ static int iwm_wext_siwfreq(struct net_device *dev, { struct iwm_priv *iwm = ndev_to_iwm(dev); - if (freq->flags == IW_FREQ_AUTO) - return 0; - - /* frequency/channel can only be set in IBSS mode */ - if (iwm->conf.mode != UMAC_MODE_IBSS) + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: + return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); + default: return -EOPNOTSUPP; - - return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); + } } static int iwm_wext_giwfreq(struct net_device *dev, @@ -69,69 +47,29 @@ static int iwm_wext_giwfreq(struct net_device *dev, { struct iwm_priv *iwm = ndev_to_iwm(dev); - if (iwm->conf.mode == UMAC_MODE_IBSS) + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); - - freq->e = 0; - freq->m = iwm->channel; - - return 0; + case UMAC_MODE_BSS: + return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); + default: + return -EOPNOTSUPP; + } } static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { struct iwm_priv *iwm = ndev_to_iwm(dev); - int ret; - - IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data); - if (iwm->conf.mode == UMAC_MODE_IBSS) + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return -EIO; - - if (is_zero_ether_addr(ap_addr->sa_data) || - is_broadcast_ether_addr(ap_addr->sa_data)) { - IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n", - iwm->umac_profile->bssid[0]); - memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); - iwm->umac_profile->bss_num = 0; - } else { - IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n", - ap_addr->sa_data); - memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data, - ETH_ALEN); - iwm->umac_profile->bss_num = 1; - } - - if (iwm->umac_profile_active) { - int i; - - if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN)) - return 0; - - /* - * If we're clearing the BSSID, and we're associated, - * we have to clear the keys as they're no longer valid. - */ - if (is_zero_ether_addr(ap_addr->sa_data)) { - for (i = 0; i < IWM_NUM_KEYS; i++) - iwm->keys[i].key_len = 0; - } - - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } + case UMAC_MODE_BSS: + return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); + default: + return -EOPNOTSUPP; } - - if (iwm->umac_profile->ssid.ssid_len) - return iwm_send_mlme_profile(iwm); - - return 0; } static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, @@ -143,17 +81,10 @@ static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, case UMAC_MODE_IBSS: return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); case UMAC_MODE_BSS: - if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN); - } else - memset(&ap_addr->sa_data, 0, ETH_ALEN); - break; + return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); default: return -EOPNOTSUPP; } - - return 0; } static int iwm_wext_siwessid(struct net_device *dev, @@ -161,36 +92,15 @@ static int iwm_wext_siwessid(struct net_device *dev, struct iw_point *data, char *ssid) { struct iwm_priv *iwm = ndev_to_iwm(dev); - size_t len = data->length; - int ret; - - IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid); - if (iwm->conf.mode == UMAC_MODE_IBSS) + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return -EIO; - - if (len > 0 && ssid[len - 1] == '\0') - len--; - - if (iwm->umac_profile_active) { - if (iwm->umac_profile->ssid.ssid_len == len && - !memcmp(iwm->umac_profile->ssid.ssid, ssid, len)) - return 0; - - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } + case UMAC_MODE_BSS: + return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); + default: + return -EOPNOTSUPP; } - - iwm->umac_profile->ssid.ssid_len = len; - memcpy(iwm->umac_profile->ssid.ssid, ssid, len); - - return iwm_send_mlme_profile(iwm); } static int iwm_wext_giwessid(struct net_device *dev, @@ -199,174 +109,14 @@ static int iwm_wext_giwessid(struct net_device *dev, { struct iwm_priv *iwm = ndev_to_iwm(dev); - if (iwm->conf.mode == UMAC_MODE_IBSS) + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return -EIO; - - data->length = iwm->umac_profile->ssid.ssid_len; - if (data->length) { - memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length); - data->flags = 1; - } else - data->flags = 0; - - return 0; -} - -static int iwm_wext_giwrate(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rate, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - rate->value = iwm->rate * 1000000; - - return 0; -} - -static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) -{ - if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; - else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK; - else - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; - - return 0; -} - -static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt) -{ - u8 *auth_type = &iwm->umac_profile->sec.auth_type; - - IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt); - - if (key_mgt == IW_AUTH_KEY_MGMT_802_1X) - *auth_type = UMAC_AUTH_TYPE_8021X; - else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) { - if (iwm->umac_profile->sec.flags & - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; - else - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - } else { - IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); - return -EINVAL; - } - - return 0; -} - -static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast) -{ - u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : - &iwm->umac_profile->sec.mcast_cipher; - - switch (cipher) { - case IW_AUTH_CIPHER_NONE: - *profile_cipher = UMAC_CIPHER_TYPE_NONE; - break; - case IW_AUTH_CIPHER_WEP40: - *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; - break; - case IW_AUTH_CIPHER_TKIP: - *profile_cipher = UMAC_CIPHER_TYPE_TKIP; - break; - case IW_AUTH_CIPHER_CCMP: - *profile_cipher = UMAC_CIPHER_TYPE_CCMP; - break; - case IW_AUTH_CIPHER_WEP104: - *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; - break; - default: - IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); - return -ENOTSUPP; - } - - return 0; -} - -static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg) -{ - u8 *auth_type = &iwm->umac_profile->sec.auth_type; - - IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg); - - switch (auth_alg) { - case IW_AUTH_ALG_OPEN_SYSTEM: - *auth_type = UMAC_AUTH_TYPE_OPEN; - break; - case IW_AUTH_ALG_SHARED_KEY: - if (iwm->umac_profile->sec.flags & - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { - if (*auth_type == UMAC_AUTH_TYPE_8021X) - return -EINVAL; - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; - } else { - IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n"); - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - } - break; - case IW_AUTH_ALG_LEAP: - default: - IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg); - return -ENOTSUPP; - } - - return 0; -} - -static int iwm_wext_siwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - int ret; - - if ((data->flags) & - (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT | - IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) { - /* We need to invalidate the current profile */ - if (iwm->umac_profile_active) { - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } - } - } - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - return iwm_set_wpa_version(iwm, data->value); - break; - case IW_AUTH_CIPHER_PAIRWISE: - return iwm_set_cipher(iwm, data->value, 1); - break; - case IW_AUTH_CIPHER_GROUP: - return iwm_set_cipher(iwm, data->value, 0); - break; - case IW_AUTH_KEY_MGMT: - return iwm_set_key_mgt(iwm, data->value); - break; - case IW_AUTH_80211_AUTH_ALG: - return iwm_set_auth_alg(iwm, data->value); - break; + case UMAC_MODE_BSS: + return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); default: - return -ENOTSUPP; + return -EOPNOTSUPP; } - - return 0; -} - -static int iwm_wext_giwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - return 0; } static const iw_handler iwm_handlers[] = @@ -404,7 +154,7 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* SIOCSIWRATE */ - (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */ + (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */ (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ @@ -419,10 +169,10 @@ static const iw_handler iwm_handlers[] = (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* SIOCSIWGENIE */ + (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */ (iw_handler) NULL, /* SIOCGIWGENIE */ - (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */ - (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */ + (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */ + (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */ (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ (iw_handler) NULL, /* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ @@ -432,6 +182,6 @@ static const iw_handler iwm_handlers[] = const struct iw_handler_def iwm_iw_handler_def = { .num_standard = ARRAY_SIZE(iwm_handlers), .standard = (iw_handler *) iwm_handlers, - .get_wireless_stats = iwm_get_wireless_stats, + .get_wireless_stats = cfg80211_wireless_stats, }; -- cgit v0.10.2 From 0e371f1a0c0acd4abfa052b01e7b1f4a71ef6590 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:11 +0800 Subject: iwmc3200wifi: remove setting WEP keys before setting essid support The recent cfg80211 "rework key operation" patch from Johannes Berg makes sure keys are set only after the connection has been established. So we can remove the setting WEP keys before essid support from the driver. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index ee40317..0372658 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -203,32 +203,6 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, return ret; } - /* - * The WEP keys can be set before or after setting the essid. - * We need to handle both cases by simply pushing the keys after - * we send the profile. - * If the profile is not set yet (i.e. we're pushing keys before - * the essid), we set the cipher appropriately. - * If the profile is set, we havent associated yet because our - * cipher was incorrectly set. So we invalidate and send the - * profile again. - */ - if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || - key->cipher == WLAN_CIPHER_SUITE_WEP104) { - u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher; - u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher; - - IWM_DBG_WEXT(iwm, DBG, "WEP key\n"); - - if (key->cipher == WLAN_CIPHER_SUITE_WEP40) - *ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40; - if (key->cipher == WLAN_CIPHER_SUITE_WEP104) - *ucast_cipher = *mcast_cipher = - UMAC_CIPHER_TYPE_WEP_104; - - return iwm_reset_profile(iwm); - } - return iwm_set_key(iwm, 0, key); } -- cgit v0.10.2 From b6c321718e1376b1a55afc63cce090a2c4573417 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:12 +0800 Subject: iwmc3200wifi: make iwm_send_wifi_if_cmd return 0 on success We used to return the result of wait_event_interruptible_timeout() which is the remaining timeout on success. But this information is not used by any of its callers. So we just return 0 on success. This fixed a erroneous return value bug for iwm_set_key(). Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 0d35afe..e6be297 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -87,8 +87,7 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, test_and_clear_bit(oid, &iwm->wifi_ntfy[0]), 3 * HZ); - if (!ret) - ret = -EBUSY; + return ret ? 0 : -EBUSY; } return ret; @@ -480,8 +479,10 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address, target_cmd.eop = 1; ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); - if (ret < 0) + if (ret < 0) { IWM_ERR(iwm, "Couldn't send READ command\n"); + return ret; + } /* When succeding, the send_target routine returns the seq number */ seq_num = ret; @@ -501,7 +502,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address, kfree(cmd); - return ret; + return 0; } int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) @@ -511,7 +512,7 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR), mac_align, sizeof(mac_align)); - if (ret < 0) + if (ret) return ret; if (is_valid_ether_addr(mac_align)) @@ -714,7 +715,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) ret = iwm_send_wifi_if_cmd(iwm, &key_remove, sizeof(struct iwm_umac_key_remove), 1); - if (ret < 0) + if (ret) return ret; iwm->keys[key_idx].key_len = 0; @@ -736,7 +737,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) sizeof(struct iwm_umac_wifi_if)); ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1); - if (ret < 0) { + if (ret) { IWM_ERR(iwm, "Send profile command failed\n"); return ret; } @@ -752,12 +753,12 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) 3 * HZ); ret = iwm_set_key(iwm, 0, key); - if (ret < 0) + if (ret) return ret; if (iwm->default_key == i) { ret = iwm_set_tx_key(iwm, i); - if (ret < 0) + if (ret) return ret; } } @@ -778,15 +779,13 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) invalid.reason = WLAN_REASON_UNSPECIFIED; ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1); - if (ret < 0) + if (ret) return ret; ret = wait_event_interruptible_timeout(iwm->mlme_queue, (iwm->umac_profile_active == 0), 2 * HZ); - if (!ret) - return -EBUSY; - return 0; + return ret ? 0 : -EBUSY; } int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) @@ -869,7 +868,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, } ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0); - if (ret < 0) { + if (ret) { IWM_ERR(iwm, "Couldn't send scan request\n"); return ret; } -- cgit v0.10.2 From 6e5db0a8454b44bf88fa74cf437a507ec08f436d Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:13 +0800 Subject: iwmc3200wifi: remove key caches in driver cfg80211 now guarantees keys are set after connecting. We can remove the key cache code from the driver now. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 0372658..3f5a08f 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -158,34 +158,6 @@ static int iwm_key_init(struct iwm_key *key, u8 key_index, return 0; } -static int iwm_reset_profile(struct iwm_priv *iwm) -{ - int ret; - - if (!iwm->umac_profile_active) - return 0; - - /* - * If there is a current active profile, but no - * default key, it's not worth trying to associate again. - */ - if (iwm->default_key < 0) - return 0; - - /* - * Here we have an active profile, but a key setting changed. - * We thus have to invalidate the current profile, and push the - * new one. Keys will be pushed when association takes place. - */ - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } - - return iwm_send_mlme_profile(iwm); -} - static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, const u8 *mac_addr, struct key_params *params) @@ -245,10 +217,6 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, if (key_index == iwm->default_key) iwm->default_key = -1; - /* If the interface is down, we just cache this */ - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return 0; - return iwm_set_key(iwm, 1, key); } @@ -257,7 +225,6 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, u8 key_index) { struct iwm_priv *iwm = ndev_to_iwm(ndev); - int ret; IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index); @@ -268,15 +235,7 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, iwm->default_key = key_index; - /* If the interface is down, we just cache this */ - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return 0; - - ret = iwm_set_tx_key(iwm, key_index); - if (ret < 0) - return ret; - - return iwm_reset_profile(iwm); + return iwm_set_tx_key(iwm, key_index); } int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index e6be297..0d66370 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -584,12 +584,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; - /* - * We check if our current profile is valid. - * If not, we dont push the key, we just cache them, - * so that with the next siwsessid call, the keys - * will be actually pushed. - */ if (!remove) { ret = iwm_check_profile(iwm); if (ret < 0) @@ -727,7 +721,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) int iwm_send_mlme_profile(struct iwm_priv *iwm) { - int ret, i; + int ret; struct iwm_umac_profile profile; memcpy(&profile, iwm->umac_profile, sizeof(profile)); @@ -742,27 +736,6 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) return ret; } - for (i = 0; i < IWM_NUM_KEYS; i++) - if (iwm->keys[i].key_len) { - struct iwm_key *key = &iwm->keys[i]; - - /* Wait for the profile before sending the keys */ - wait_event_interruptible_timeout(iwm->mlme_queue, - (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) || - test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)), - 3 * HZ); - - ret = iwm_set_key(iwm, 0, key); - if (ret) - return ret; - - if (iwm->default_key == i) { - ret = iwm_set_tx_key(iwm, i); - if (ret) - return ret; - } - } - return 0; } -- cgit v0.10.2 From d4b1a6876f99ae1886cd254f649506af6692ac9f Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:14 +0800 Subject: cfg80211: remove WARN_ON in __cfg80211_sme_scan_done cfg80211_sme_scan_done() can be called (by fullmac cards) with wdev->conn == NULL when CFG80211_SME_CONNECTING. We quit silently instead of WARN_ON in this case. Signed-off-by: Zhu Yi Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 10ed366..e7a8851 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -227,7 +227,7 @@ static void __cfg80211_sme_scan_done(struct net_device *dev) if (wdev->sme_state != CFG80211_SME_CONNECTING) return; - if (WARN_ON(!wdev->conn)) + if (!wdev->conn) return; if (wdev->conn->state != CFG80211_CONN_SCANNING && -- cgit v0.10.2 From 25e83c490be421019997146bdec8645f5bcabcd1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 16 Jul 2009 11:39:04 +0200 Subject: cfg80211: don't optimise wext calls too much In the wext code I tried to not reconnect all the time when the user wasn't really sure what they were doing, like setting the BSSID back to the same value it was. However, this optimisation should only be done while associated so that setting the BSSID back to the same value that it was actually triggers a new association if not currently associated. To achieve, that, put the relevant code into the !IDLE case instead. Signed-off-by: Johannes Berg Tested-by: Kalle Valo Tested-by: Marcel Holtmann Signed-off-by: John W. Linville diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 82e913a..4c689fd 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -72,13 +72,14 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, cfg80211_lock_rdev(rdev); wdev_lock(wdev); - if (wdev->wext.connect.channel == chan) { - err = 0; - goto out; - } - if (wdev->sme_state != CFG80211_SME_IDLE) { bool event = true; + + if (wdev->wext.connect.channel == chan) { + err = 0; + goto out; + } + /* if SSID set, we'll try right again, avoid event */ if (wdev->wext.connect.ssid_len) event = false; @@ -164,13 +165,14 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, err = 0; - if (wdev->wext.connect.ssid && len && - len == wdev->wext.connect.ssid_len && - memcmp(wdev->wext.connect.ssid, ssid, len) == 0) - goto out; - if (wdev->sme_state != CFG80211_SME_IDLE) { bool event = true; + + if (wdev->wext.connect.ssid && len && + len == wdev->wext.connect.ssid_len && + memcmp(wdev->wext.connect.ssid, ssid, len) == 0) + goto out; + /* if SSID set now, we'll try to connect, avoid event */ if (len) event = false; @@ -244,17 +246,17 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); wdev_lock(wdev); - err = 0; - /* both automatic */ - if (!bssid && !wdev->wext.connect.bssid) - goto out; + if (wdev->sme_state != CFG80211_SME_IDLE) { + err = 0; + /* both automatic */ + if (!bssid && !wdev->wext.connect.bssid) + goto out; - /* fixed already - and no change */ - if (wdev->wext.connect.bssid && bssid && - compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) - goto out; + /* fixed already - and no change */ + if (wdev->wext.connect.bssid && bssid && + compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) + goto out; - if (wdev->sme_state != CFG80211_SME_IDLE) { err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), dev, WLAN_REASON_DEAUTH_LEAVING, false); -- cgit v0.10.2 From 12f49a79cd32d97a11f864a7b67660438ee3e6c8 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 16 Jul 2009 20:03:17 +0200 Subject: p54: remove useless code This patch removes some useless checks in recv/xmit code. Acked-by: Larry Finger Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 01eadb1..416400c 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -87,9 +87,6 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb) u32 target_addr = priv->rx_start; u16 len = priv->headroom + skb->len + priv->tailroom + 3; - if (unlikely(WARN_ON(!skb || !priv))) - return -EINVAL; - info = IEEE80211_SKB_CB(skb); range = (void *) info->rate_driver_data; len = (range->extra_len + len) & ~0x3; @@ -111,11 +108,6 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb) range = (void *) info->rate_driver_data; hole_size = range->start_addr - last_addr; - if (!entry->next) { - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - return -ENOSPC; - } - if (!target_skb && hole_size >= len) { target_skb = entry->prev; hole_size -= len; @@ -153,9 +145,6 @@ static void p54_tx_pending(struct p54_common *priv) struct sk_buff *skb; int ret; - if (unlikely(WARN_ON(!priv))) - return ; - skb = skb_dequeue(&priv->tx_pending); if (unlikely(!skb)) return ; @@ -219,7 +208,7 @@ static int p54_tx_qos_accounting_alloc(struct p54_common *priv, static void p54_tx_qos_accounting_free(struct p54_common *priv, struct sk_buff *skb) { - if (skb && IS_DATA_FRAME(skb)) { + if (IS_DATA_FRAME(skb)) { struct p54_hdr *hdr = (void *) skb->data; struct p54_tx_data *data = (void *) hdr->data; unsigned long flags; @@ -266,9 +255,6 @@ static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv, void p54_tx(struct p54_common *priv, struct sk_buff *skb) { - if (unlikely(WARN_ON(!priv))) - return ; - skb_queue_tail(&priv->tx_pending, skb); p54_tx_pending(priv); } -- cgit v0.10.2 From 46df10ae44b4488176bae16da0b31541eb0f8f48 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 16 Jul 2009 20:03:47 +0200 Subject: p54: fix beaconing related firmware crash This patch fixes a firmware crash which can be provoked by changing operation mode. Acked-by: Larry Finger Signed-off-by: Christian Lamparter Tested-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h index af35cfc..04b63ec 100644 --- a/drivers/net/wireless/p54/lmac.h +++ b/drivers/net/wireless/p54/lmac.h @@ -98,6 +98,10 @@ struct p54_hdr { (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL))) +#define GET_HW_QUEUE(skb) \ + (((struct p54_tx_data *)((struct p54_hdr *) \ + skb->data)->data)->hw_queue) + /* * shared interface ID definitions * The interface ID is a unique identification of a specific interface. diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index f19add2..955f6d7 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -130,7 +130,6 @@ static int p54_beacon_update(struct p54_common *priv, struct ieee80211_vif *vif) { struct sk_buff *beacon; - __le32 old_beacon_req_id; int ret; beacon = ieee80211_beacon_get(priv->hw, vif); @@ -140,15 +139,16 @@ static int p54_beacon_update(struct p54_common *priv, if (ret) return ret; - old_beacon_req_id = priv->beacon_req_id; - priv->beacon_req_id = GET_REQ_ID(beacon); - - ret = p54_tx_80211(priv->hw, beacon); - if (ret) { - priv->beacon_req_id = old_beacon_req_id; - return -ENOSPC; - } - + /* + * During operation, the firmware takes care of beaconing. + * The driver only needs to upload a new beacon template, once + * the template was changed by the stack or userspace. + * + * LMAC API 3.2.2 also specifies that the driver does not need + * to cancel the old beacon template by hand, instead the firmware + * will release the previous one through the feedback mechanism. + */ + WARN_ON(p54_tx_80211(priv->hw, beacon)); priv->tsf_high32 = 0; priv->tsf_low32 = 0; @@ -253,9 +253,14 @@ static void p54_remove_interface(struct ieee80211_hw *dev, mutex_lock(&priv->conf_mutex); priv->vif = NULL; - if (priv->beacon_req_id) { + + /* + * LMAC API 3.2.2 states that any active beacon template must be + * canceled by the driver before attempting a mode transition. + */ + if (le32_to_cpu(priv->beacon_req_id) != 0) { p54_tx_cancel(priv, priv->beacon_req_id); - priv->beacon_req_id = cpu_to_le32(0); + wait_for_completion_interruptible_timeout(&priv->beacon_comp, HZ); } priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); @@ -544,6 +549,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) BIT(NL80211_IFTYPE_MESH_POINT); dev->channel_change_time = 1000; /* TODO: find actual value */ + priv->beacon_req_id = cpu_to_le32(0); priv->tx_stats[P54_QUEUE_BEACON].limit = 1; priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1; priv->tx_stats[P54_QUEUE_MGMT].limit = 3; @@ -567,6 +573,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) mutex_init(&priv->conf_mutex); mutex_init(&priv->eeprom_mutex); init_completion(&priv->eeprom_comp); + init_completion(&priv->beacon_comp); INIT_DELAYED_WORK(&priv->work, p54_work); return dev; diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 584b156..1afc394 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -211,6 +211,7 @@ struct p54_common { u16 aid; bool powersave_override; __le32 beacon_req_id; + struct completion beacon_comp; /* cryptographic engine information */ u8 privacy_caps; diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 416400c..0d589d6 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -134,9 +134,13 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb) range = (void *) info->rate_driver_data; range->start_addr = target_addr; range->end_addr = target_addr + len; + data->req_id = cpu_to_le32(target_addr + priv->headroom); + if (IS_DATA_FRAME(skb) && + unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) + priv->beacon_req_id = data->req_id; + __skb_queue_after(&priv->tx_queue, target_skb, skb); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - data->req_id = cpu_to_le32(target_addr + priv->headroom); return 0; } @@ -209,13 +213,19 @@ static void p54_tx_qos_accounting_free(struct p54_common *priv, struct sk_buff *skb) { if (IS_DATA_FRAME(skb)) { - struct p54_hdr *hdr = (void *) skb->data; - struct p54_tx_data *data = (void *) hdr->data; unsigned long flags; spin_lock_irqsave(&priv->tx_stats_lock, flags); - priv->tx_stats[data->hw_queue].len--; + priv->tx_stats[GET_HW_QUEUE(skb)].len--; spin_unlock_irqrestore(&priv->tx_stats_lock, flags); + + if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) { + if (priv->beacon_req_id == GET_REQ_ID(skb)) { + /* this is the active beacon set anymore */ + priv->beacon_req_id = 0; + } + complete(&priv->beacon_comp); + } } p54_wake_queues(priv); } @@ -403,10 +413,6 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb) * and we don't want to confuse the mac80211 stack. */ if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) { - if (entry_data->hw_queue == P54_QUEUE_BEACON && - hdr->req_id == priv->beacon_req_id) - priv->beacon_req_id = cpu_to_le32(0); - dev_kfree_skb_any(entry); return ; } -- cgit v0.10.2 From 436b37c59416d0d8e21430f7980857fc932eb1e6 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 16 Jul 2009 20:05:41 +0200 Subject: p54: fix a fw crash caused by statistic feedback This patch fixes a bug which crawled into the tree with the split-up changes. The memory-manager wasn't aware of the statistic feedback extra_len space requirements and happily placed following frames into the allegedly free spots. Thanks fly out to Larry Finger for taking the time to test all (permutations of) patches and theories all day long. Acked-by: Larry Finger Signed-off-by: Christian Lamparter Tested-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 349375f..21f1901 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -686,6 +686,8 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len, int p54_fetch_statistics(struct p54_common *priv) { + struct ieee80211_tx_info *txinfo; + struct p54_tx_info *p54info; struct sk_buff *skb; skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, @@ -694,6 +696,20 @@ int p54_fetch_statistics(struct p54_common *priv) if (!skb) return -ENOMEM; + /* + * The statistic feedback causes some extra headaches here, if it + * is not to crash/corrupt the firmware data structures. + * + * Unlike all other Control Get OIDs we can not use helpers like + * skb_put to reserve the space for the data we're requesting. + * Instead the extra frame length -which will hold the results later- + * will only be told to the p54_assign_address, so that following + * frames won't be placed into the allegedly empty area. + */ + txinfo = IEEE80211_SKB_CB(skb); + p54info = (void *) txinfo->rate_driver_data; + p54info->extra_len = sizeof(struct p54_statistics); + p54_tx(priv, skb); return 0; } -- cgit v0.10.2 From 02c06e4abc0680afd31bf481a803541556757fb6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:14 -0700 Subject: iwlagn: modify digital SVR for 1000 On 1000, there are two Switching Voltage Regulators (SVR). The first one apply digital voltage level (1.32V) for PCIe block and core. We need to use this regulator to solve a stability issue related to noisy DC2DC line in the silicon. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 85e8bac..3f9da6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -239,6 +239,13 @@ static void iwl5000_nic_config(struct iwl_priv *priv) APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) { + /* Setting digital SVR for 1000 card to 1.32V */ + iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG, + APMG_SVR_DIGITAL_VOLTAGE_1_32, + ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); + } + spin_unlock_irqrestore(&priv->lock, flags); } diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 3b9cac3..d393e8f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -80,6 +80,8 @@ #define APMG_RFKILL_REG (APMG_BASE + 0x0014) #define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c) #define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020) +#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058) +#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C) #define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200) #define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800) @@ -91,7 +93,8 @@ #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) #define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */ #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) - +#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ +#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) -- cgit v0.10.2 From 244294e83f7637e31bbf64060301904860a32051 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:15 -0700 Subject: iwlwifi: fix rx signal quality reporting in dmesg Fix quality incorrectly reported as signal strength value. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 66fe365..fc7edd1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1065,7 +1065,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, iwl_dbg_report_frame(priv, rx_start, len, header, 1); #endif IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", - rx_status.signal, rx_status.noise, rx_status.signal, + rx_status.signal, rx_status.noise, rx_status.qual, (unsigned long long)rx_status.mactime); /* -- cgit v0.10.2 From cc0f555d511a5fe9d4519334c8f674a1dbab9e3a Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Fri, 17 Jul 2009 09:30:16 -0700 Subject: iwlwifi: Handle new firmware file with ucode build number in header Adding new API version to account for change to ucode file format. New header includes the build number of the ucode. This build number is the SVN revision thus allowing for exact correlation to the code that generated it. The header adds the build number so that older ucode images can also be enhanced to include the build in the future. some cleanup in iwl_read_ucode needed to ensure old header not used and reduce unnecessary references through pointer with the data is already in heap variable. Signed-off-by: Jay Sternberg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 1227ed2..14a47c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2786,11 +2786,50 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) return 0; } +#define IWL3945_UCODE_GET(item) \ +static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\ + u32 api_ver) \ +{ \ + return le32_to_cpu(ucode->u.v1.item); \ +} + +static u32 iwl3945_ucode_get_header_size(u32 api_ver) +{ + return UCODE_HEADER_SIZE(1); +} +static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + return 0; +} +static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + return (u8 *) ucode->u.v1.data; +} + +IWL3945_UCODE_GET(inst_size); +IWL3945_UCODE_GET(data_size); +IWL3945_UCODE_GET(init_size); +IWL3945_UCODE_GET(init_data_size); +IWL3945_UCODE_GET(boot_size); + static struct iwl_hcmd_ops iwl3945_hcmd = { .rxon_assoc = iwl3945_send_rxon_assoc, .commit_rxon = iwl3945_commit_rxon, }; +static struct iwl_ucode_ops iwl3945_ucode = { + .get_header_size = iwl3945_ucode_get_header_size, + .get_build = iwl3945_ucode_get_build, + .get_inst_size = iwl3945_ucode_get_inst_size, + .get_data_size = iwl3945_ucode_get_data_size, + .get_init_size = iwl3945_ucode_get_init_size, + .get_init_data_size = iwl3945_ucode_get_init_data_size, + .get_boot_size = iwl3945_ucode_get_boot_size, + .get_data = iwl3945_ucode_get_data, +}; + static struct iwl_lib_ops iwl3945_lib = { .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl3945_hw_txq_free_tfd, @@ -2831,6 +2870,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { }; static struct iwl_ops iwl3945_ops = { + .ucode = &iwl3945_ucode, .lib = &iwl3945_lib, .hcmd = &iwl3945_hcmd, .utils = &iwl3945_hcmd_utils, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index edbb0bf..f4eb683 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2221,12 +2221,50 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->txpower_work); } +#define IWL4965_UCODE_GET(item) \ +static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\ + u32 api_ver) \ +{ \ + return le32_to_cpu(ucode->u.v1.item); \ +} + +static u32 iwl4965_ucode_get_header_size(u32 api_ver) +{ + return UCODE_HEADER_SIZE(1); +} +static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + return 0; +} +static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + return (u8 *) ucode->u.v1.data; +} + +IWL4965_UCODE_GET(inst_size); +IWL4965_UCODE_GET(data_size); +IWL4965_UCODE_GET(init_size); +IWL4965_UCODE_GET(init_data_size); +IWL4965_UCODE_GET(boot_size); + static struct iwl_hcmd_ops iwl4965_hcmd = { .rxon_assoc = iwl4965_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, .set_rxon_chain = iwl_set_rxon_chain, }; +static struct iwl_ucode_ops iwl4965_ucode = { + .get_header_size = iwl4965_ucode_get_header_size, + .get_build = iwl4965_ucode_get_build, + .get_inst_size = iwl4965_ucode_get_inst_size, + .get_data_size = iwl4965_ucode_get_data_size, + .get_init_size = iwl4965_ucode_get_init_size, + .get_init_data_size = iwl4965_ucode_get_init_data_size, + .get_boot_size = iwl4965_ucode_get_boot_size, + .get_data = iwl4965_ucode_get_data, +}; static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .get_hcmd_size = iwl4965_get_hcmd_size, .build_addsta_hcmd = iwl4965_build_addsta_hcmd, @@ -2287,6 +2325,7 @@ static struct iwl_lib_ops iwl4965_lib = { }; static struct iwl_ops iwl4965_ops = { + .ucode = &iwl4965_ucode, .lib = &iwl4965_lib, .hcmd = &iwl4965_hcmd, .utils = &iwl4965_hcmd_utils, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 3f9da6e..74103cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1456,6 +1456,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv, return max_rssi - agc - IWL49_RSSI_OFFSET; } +#define IWL5000_UCODE_GET(item) \ +static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\ + u32 api_ver) \ +{ \ + if (api_ver <= 2) \ + return le32_to_cpu(ucode->u.v1.item); \ + return le32_to_cpu(ucode->u.v2.item); \ +} + +static u32 iwl5000_ucode_get_header_size(u32 api_ver) +{ + if (api_ver <= 2) + return UCODE_HEADER_SIZE(1); + return UCODE_HEADER_SIZE(2); +} + +static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + if (api_ver <= 2) + return 0; + return le32_to_cpu(ucode->u.v2.build); +} + +static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + if (api_ver <= 2) + return (u8 *) ucode->u.v1.data; + return (u8 *) ucode->u.v2.data; +} + +IWL5000_UCODE_GET(inst_size); +IWL5000_UCODE_GET(data_size); +IWL5000_UCODE_GET(init_size); +IWL5000_UCODE_GET(init_data_size); +IWL5000_UCODE_GET(boot_size); + struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, @@ -1471,6 +1509,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { .calc_rssi = iwl5000_calc_rssi, }; +struct iwl_ucode_ops iwl5000_ucode = { + .get_header_size = iwl5000_ucode_get_header_size, + .get_build = iwl5000_ucode_get_build, + .get_inst_size = iwl5000_ucode_get_inst_size, + .get_data_size = iwl5000_ucode_get_data_size, + .get_init_size = iwl5000_ucode_get_init_size, + .get_init_data_size = iwl5000_ucode_get_init_data_size, + .get_boot_size = iwl5000_ucode_get_boot_size, + .get_data = iwl5000_ucode_get_data, +}; + struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, @@ -1572,12 +1621,14 @@ static struct iwl_lib_ops iwl5150_lib = { }; struct iwl_ops iwl5000_ops = { + .ucode = &iwl5000_ucode, .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, }; static struct iwl_ops iwl5150_ops = { + .ucode = &iwl5000_ucode, .lib = &iwl5150_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index bd438d8..26c5d4a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -46,8 +46,8 @@ #include "iwl-5000-hw.h" /* Highest firmware API version supported */ -#define IWL6000_UCODE_API_MAX 2 -#define IWL6050_UCODE_API_MAX 2 +#define IWL6000_UCODE_API_MAX 3 +#define IWL6050_UCODE_API_MAX 3 /* Lowest firmware API version supported */ #define IWL6000_UCODE_API_MIN 1 @@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = { }; static struct iwl_ops iwl6000_ops = { + .ucode = &iwl5000_ucode, .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl6000_hcmd_utils, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ad50022..6b874da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1284,7 +1284,7 @@ static void iwl_nic_start(struct iwl_priv *priv) */ static int iwl_read_ucode(struct iwl_priv *priv) { - struct iwl_ucode *ucode; + struct iwl_ucode_header *ucode; int ret = -EINVAL, index; const struct firmware *ucode_raw; const char *name_pre = priv->cfg->fw_name_pre; @@ -1293,7 +1293,8 @@ static int iwl_read_ucode(struct iwl_priv *priv) char buf[25]; u8 *src; size_t len; - u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; + u32 api_ver, build; + u32 inst_size, data_size, init_size, init_data_size, boot_size; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ @@ -1323,23 +1324,26 @@ static int iwl_read_ucode(struct iwl_priv *priv) if (ret < 0) goto error; - /* Make sure that we got at least our header! */ - if (ucode_raw->size < sizeof(*ucode)) { + /* Make sure that we got at least the v1 header! */ + if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) { IWL_ERR(priv, "File size way too small!\n"); ret = -EINVAL; goto err_release; } /* Data from ucode file: header followed by uCode images */ - ucode = (void *)ucode_raw->data; + ucode = (struct iwl_ucode_header *)ucode_raw->data; priv->ucode_ver = le32_to_cpu(ucode->ver); api_ver = IWL_UCODE_API(priv->ucode_ver); - inst_size = le32_to_cpu(ucode->inst_size); - data_size = le32_to_cpu(ucode->data_size); - init_size = le32_to_cpu(ucode->init_size); - init_data_size = le32_to_cpu(ucode->init_data_size); - boot_size = le32_to_cpu(ucode->boot_size); + build = priv->cfg->ops->ucode->get_build(ucode, api_ver); + inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver); + data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver); + init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver); + init_data_size = + priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver); + boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver); + src = priv->cfg->ops->ucode->get_data(ucode, api_ver); /* api_ver should match the api version forming part of the * firmware filename ... but we don't check for that and only rely @@ -1365,6 +1369,9 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_UCODE_API(priv->ucode_ver), IWL_UCODE_SERIAL(priv->ucode_ver)); + if (build) + IWL_DEBUG_INFO(priv, "Build %u\n", build); + IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", priv->ucode_ver); IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n", @@ -1379,12 +1386,14 @@ static int iwl_read_ucode(struct iwl_priv *priv) boot_size); /* Verify size of file vs. image size info in file's header */ - if (ucode_raw->size < sizeof(*ucode) + + if (ucode_raw->size != + priv->cfg->ops->ucode->get_header_size(api_ver) + inst_size + data_size + init_size + init_data_size + boot_size) { - IWL_DEBUG_INFO(priv, "uCode file size %d too small\n", - (int)ucode_raw->size); + IWL_DEBUG_INFO(priv, + "uCode file size %d does not match expected size\n", + (int)ucode_raw->size); ret = -EINVAL; goto err_release; } @@ -1464,42 +1473,42 @@ static int iwl_read_ucode(struct iwl_priv *priv) /* Copy images into buffers for card's bus-master reads ... */ /* Runtime instructions (first block of data in file) */ - src = &ucode->data[0]; - len = priv->ucode_code.len; + len = inst_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len); memcpy(priv->ucode_code.v_addr, src, len); + src += len; + IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); /* Runtime data (2nd block) * NOTE: Copy into backup buffer will be done in iwl_up() */ - src = &ucode->data[inst_size]; - len = priv->ucode_data.len; + len = data_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len); memcpy(priv->ucode_data.v_addr, src, len); memcpy(priv->ucode_data_backup.v_addr, src, len); + src += len; /* Initialization instructions (3rd block) */ if (init_size) { - src = &ucode->data[inst_size + data_size]; - len = priv->ucode_init.len; + len = init_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n", len); memcpy(priv->ucode_init.v_addr, src, len); + src += len; } /* Initialization data (4th block) */ if (init_data_size) { - src = &ucode->data[inst_size + data_size + init_size]; - len = priv->ucode_init_data.len; + len = init_data_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n", len); memcpy(priv->ucode_init_data.v_addr, src, len); + src += len; } /* Bootstrap instructions (5th block) */ - src = &ucode->data[inst_size + data_size + init_size + init_data_size]; - len = priv->ucode_boot.len; + len = boot_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len); memcpy(priv->ucode_boot.v_addr, src, len); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 640c464..c844fab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -116,6 +116,17 @@ struct iwl_temp_ops { void (*set_ct_kill)(struct iwl_priv *priv); }; +struct iwl_ucode_ops { + u32 (*get_header_size)(u32); + u32 (*get_build)(const struct iwl_ucode_header *, u32); + u32 (*get_inst_size)(const struct iwl_ucode_header *, u32); + u32 (*get_data_size)(const struct iwl_ucode_header *, u32); + u32 (*get_init_size)(const struct iwl_ucode_header *, u32); + u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32); + u32 (*get_boot_size)(const struct iwl_ucode_header *, u32); + u8 * (*get_data)(const struct iwl_ucode_header *, u32); +}; + struct iwl_lib_ops { /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); @@ -171,6 +182,7 @@ struct iwl_lib_ops { }; struct iwl_ops { + const struct iwl_ucode_ops *ucode; const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b989d5c..f4afd0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -66,6 +66,7 @@ extern struct iwl_cfg iwl1000_bgn_cfg; /* shared structures from iwl-5000.c */ extern struct iwl_mod_params iwl50_mod_params; extern struct iwl_ops iwl5000_ops; +extern struct iwl_ucode_ops iwl5000_ucode; extern struct iwl_lib_ops iwl5000_lib; extern struct iwl_hcmd_ops iwl5000_hcmd; extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils; @@ -525,15 +526,29 @@ struct fw_desc { }; /* uCode file layout */ -struct iwl_ucode { - __le32 ver; /* major/minor/API/serial */ - __le32 inst_size; /* bytes of runtime instructions */ - __le32 data_size; /* bytes of runtime data */ - __le32 init_size; /* bytes of initialization instructions */ - __le32 init_data_size; /* bytes of initialization data */ - __le32 boot_size; /* bytes of bootstrap instructions */ - u8 data[0]; /* data in same order as "size" elements */ +struct iwl_ucode_header { + __le32 ver; /* major/minor/API/serial */ + union { + struct { + __le32 inst_size; /* bytes of runtime code */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of init code */ + __le32 init_data_size; /* bytes of init data */ + __le32 boot_size; /* bytes of bootstrap code */ + u8 data[0]; /* in same order as sizes */ + } v1; + struct { + __le32 build; /* build number */ + __le32 inst_size; /* bytes of runtime code */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of init code */ + __le32 init_data_size; /* bytes of init data */ + __le32 boot_size; /* bytes of bootstrap code */ + u8 data[0]; /* in same order as sizes */ + } v2; + } u; }; +#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28) struct iwl4965_ibss_seq { u8 mac[ETH_ALEN]; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c9b3ea9..bd6a067 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2041,7 +2041,7 @@ static void iwl3945_nic_start(struct iwl_priv *priv) */ static int iwl3945_read_ucode(struct iwl_priv *priv) { - struct iwl_ucode *ucode; + const struct iwl_ucode_header *ucode; int ret = -EINVAL, index; const struct firmware *ucode_raw; /* firmware file name contains uCode/driver compatibility version */ @@ -2082,22 +2082,24 @@ static int iwl3945_read_ucode(struct iwl_priv *priv) goto error; /* Make sure that we got at least our header! */ - if (ucode_raw->size < sizeof(*ucode)) { + if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) { IWL_ERR(priv, "File size way too small!\n"); ret = -EINVAL; goto err_release; } /* Data from ucode file: header followed by uCode images */ - ucode = (void *)ucode_raw->data; + ucode = (struct iwl_ucode_header *)ucode_raw->data; priv->ucode_ver = le32_to_cpu(ucode->ver); api_ver = IWL_UCODE_API(priv->ucode_ver); - inst_size = le32_to_cpu(ucode->inst_size); - data_size = le32_to_cpu(ucode->data_size); - init_size = le32_to_cpu(ucode->init_size); - init_data_size = le32_to_cpu(ucode->init_data_size); - boot_size = le32_to_cpu(ucode->boot_size); + inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver); + data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver); + init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver); + init_data_size = + priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver); + boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver); + src = priv->cfg->ops->ucode->get_data(ucode, api_ver); /* api_ver should match the api version forming part of the * firmware filename ... but we don't check for that and only rely @@ -2138,12 +2140,13 @@ static int iwl3945_read_ucode(struct iwl_priv *priv) /* Verify size of file vs. image size info in file's header */ - if (ucode_raw->size < sizeof(*ucode) + + if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) + inst_size + data_size + init_size + init_data_size + boot_size) { - IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n", - ucode_raw->size); + IWL_DEBUG_INFO(priv, + "uCode file size %zd does not match expected size\n", + ucode_raw->size); ret = -EINVAL; goto err_release; } @@ -2226,44 +2229,44 @@ static int iwl3945_read_ucode(struct iwl_priv *priv) /* Copy images into buffers for card's bus-master reads ... */ /* Runtime instructions (first block of data in file) */ - src = &ucode->data[0]; - len = priv->ucode_code.len; + len = inst_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %zd\n", len); memcpy(priv->ucode_code.v_addr, src, len); + src += len; + IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); /* Runtime data (2nd block) * NOTE: Copy into backup buffer will be done in iwl3945_up() */ - src = &ucode->data[inst_size]; - len = priv->ucode_data.len; + len = data_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %zd\n", len); memcpy(priv->ucode_data.v_addr, src, len); memcpy(priv->ucode_data_backup.v_addr, src, len); + src += len; /* Initialization instructions (3rd block) */ if (init_size) { - src = &ucode->data[inst_size + data_size]; - len = priv->ucode_init.len; + len = init_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %zd\n", len); memcpy(priv->ucode_init.v_addr, src, len); + src += len; } /* Initialization data (4th block) */ if (init_data_size) { - src = &ucode->data[inst_size + data_size + init_size]; - len = priv->ucode_init_data.len; + len = init_data_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %zd\n", len); memcpy(priv->ucode_init_data.v_addr, src, len); + src += len; } /* Bootstrap instructions (5th block) */ - src = &ucode->data[inst_size + data_size + init_size + init_data_size]; - len = priv->ucode_boot.len; + len = boot_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %zd\n", len); memcpy(priv->ucode_boot.v_addr, src, len); -- cgit v0.10.2 From 5e215169f466e48561e40d1fa142f02e0e44a3d0 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:17 -0700 Subject: iwlwifi: make led functions generic Led functions are generic for all the devices except 3945, so remove the reference to 4965 Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 5e64252..36d88a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -104,7 +104,7 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) } /* Set led pattern command */ -static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id, +static int iwl_led_pattern(struct iwl_priv *priv, int led_id, unsigned int idx) { struct iwl_led_cmd led_cmd = { @@ -121,7 +121,7 @@ static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id, } /* Set led register off */ -static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id) +static int iwl_led_on_reg(struct iwl_priv *priv, int led_id) { IWL_DEBUG_LED(priv, "led on %d\n", led_id); iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); @@ -130,7 +130,7 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id) #if 0 /* Set led on command */ -static int iwl4965_led_on(struct iwl_priv *priv, int led_id) +static int iwl_led_on(struct iwl_priv *priv, int led_id) { struct iwl_led_cmd led_cmd = { .id = led_id, @@ -142,7 +142,7 @@ static int iwl4965_led_on(struct iwl_priv *priv, int led_id) } /* Set led off command */ -int iwl4965_led_off(struct iwl_priv *priv, int led_id) +int iwl_led_off(struct iwl_priv *priv, int led_id) { struct iwl_led_cmd led_cmd = { .id = led_id, @@ -157,7 +157,7 @@ int iwl4965_led_off(struct iwl_priv *priv, int led_id) /* Set led register off */ -static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id) +static int iwl_led_off_reg(struct iwl_priv *priv, int led_id) { IWL_DEBUG_LED(priv, "LED Reg off\n"); iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); @@ -171,7 +171,7 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id) { IWL_DEBUG_LED(priv, "Associated\n"); priv->allow_blinking = 1; - return iwl4965_led_on_reg(priv, led_id); + return iwl_led_on_reg(priv, led_id); } static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) { @@ -314,7 +314,7 @@ void iwl_leds_background(struct iwl_priv *priv) priv->last_blink_time = 0; if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { priv->last_blink_rate = IWL_SOLID_BLINK_IDX; - iwl4965_led_pattern(priv, IWL_LED_LINK, + iwl_led_pattern(priv, IWL_LED_LINK, IWL_SOLID_BLINK_IDX); } return; @@ -328,7 +328,7 @@ void iwl_leds_background(struct iwl_priv *priv) /* call only if blink rate change */ if (blink_idx != priv->last_blink_rate) - iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx); + iwl_led_pattern(priv, IWL_LED_LINK, blink_idx); priv->last_blink_time = jiffies; priv->last_blink_rate = blink_idx; @@ -351,8 +351,8 @@ int iwl_leds_register(struct iwl_priv *priv) sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio", wiphy_name(priv->hw->wiphy)); - priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg; - priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg; + priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg; + priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg; priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO], @@ -386,7 +386,7 @@ int iwl_leds_register(struct iwl_priv *priv) priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated; priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated; - priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern; + priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern; if (ret) goto exit_fail; @@ -401,7 +401,7 @@ int iwl_leds_register(struct iwl_priv *priv) priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated; priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated; - priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern; + priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern; if (ret) goto exit_fail; -- cgit v0.10.2 From 2d1bb9e58c2b13df13741d1efe1129cf1098405d Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 17 Jul 2009 09:30:18 -0700 Subject: iwlagn: do not send key clear commands when rfkill enabled Do all key clearing except sending sommands to device when rfkill enabled. When rfkill enabled the interface is brought down and will be brought back up correctly after rfkill is enabled again. Same change is not needed for iwl3945 as it ignores return code when sending key clearing command to device. This fixes http://bugzilla.kernel.org/show_bug.cgi?id=13742 Signed-off-by: Reinette Chatre Tested-by: Frans Pop Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index afa1633..7fd806d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -566,6 +566,8 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv, unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); + IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n", + keyconf->keyidx); if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table)) IWL_ERR(priv, "index %d not used in uCode key table.\n", @@ -573,6 +575,11 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv, priv->default_wep_key--; memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0])); + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n"); + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; + } ret = iwl_send_static_wepkey_cmd(priv, 1); IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n", keyconf->keyidx, ret); @@ -853,6 +860,11 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled. \n"); + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; + } ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; -- cgit v0.10.2 From a283c0116b0cc5e82327e50ad4d05f6d4d42c603 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:19 -0700 Subject: iwlwifi: add led debugfs function Adding debugfs file to show current led blinking rate /sys/kernel/debug/ieee80211/phy0/iwlagn/data/led Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 1555676..e4a4dbd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -83,6 +83,9 @@ struct iwl_debugfs { struct dentry *file_status; struct dentry *file_interrupt; struct dentry *file_qos; +#ifdef CONFIG_IWLWIFI_LEDS + struct dentry *file_led; +#endif } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 0b9e824..0ab3463 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -591,6 +591,33 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, return ret; } +#ifdef CONFIG_IWLWIFI_LEDS +static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char buf[256]; + const size_t bufsz = sizeof(buf); + ssize_t ret; + + pos += scnprintf(buf + pos, bufsz - pos, + "allow blinking: %s\n", + (priv->allow_blinking) ? "True" : "False"); + if (priv->allow_blinking) { + pos += scnprintf(buf + pos, bufsz - pos, + "Led blinking rate: %u\n", + priv->last_blink_rate); + pos += scnprintf(buf + pos, bufsz - pos, + "Last blink time: %lu\n", + priv->last_blink_time); + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} +#endif + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); @@ -601,6 +628,9 @@ DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(qos); +#ifdef CONFIG_IWLWIFI_LEDS +DEBUGFS_READ_FILE_OPS(led); +#endif /* * Create the debugfs files and directories @@ -638,6 +668,9 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(status, data); DEBUGFS_ADD_FILE(interrupt, data); DEBUGFS_ADD_FILE(qos, data); +#ifdef CONFIG_IWLWIFI_LEDS + DEBUGFS_ADD_FILE(led, data); +#endif DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -673,6 +706,9 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos); +#ifdef CONFIG_IWLWIFI_LEDS + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led); +#endif DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); -- cgit v0.10.2 From e5108d075c705ed3336163d9ead2b8fe629f680d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:20 -0700 Subject: iwlwifi: Led blinking counting both tx and rx For controlling led blinking, counting both tx and rx data traffic; this will be able to handle traffic in either direction Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 36d88a0..8c81152 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -54,7 +54,7 @@ static const char *led_type_str[] = { static const struct { - u16 tpt; + u16 tpt; /* Mb/s */ u8 on_time; u8 off_time; } blink_tbl[] = @@ -264,13 +264,15 @@ static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led, /* - * calculate blink rate according to last 2 sec Tx/Rx activities + * calculate blink rate according to last second Tx/Rx activities */ static int iwl_get_blink_rate(struct iwl_priv *priv) { int i; - u64 current_tpt = priv->tx_stats[2].bytes; - /* FIXME: + priv->rx_stats[2].bytes; */ + /* count both tx and rx traffic to be able to + * handle traffic in either direction + */ + u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes; s64 tpt = current_tpt - priv->led_tpt; if (tpt < 0) /* wraparound */ -- cgit v0.10.2 From b23a0524a38b146f85be44ae0d71abd2a710f4ab Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:21 -0700 Subject: iwlwifi: checking unknown HW type When deciding NVM type, if the HW type is unknown, report error and exit with -ENOENT. This check should prevent incorrect behavior by assuming the wrong NVM type. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 7d7554a..51eed72 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -159,6 +159,9 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv) /* OTP only valid for CP/PP and after */ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_NONE: + IWL_ERR(priv, "Unknown hardware type\n"); + return -ENOENT; case CSR_HW_REV_TYPE_3945: case CSR_HW_REV_TYPE_4965: case CSR_HW_REV_TYPE_5300: @@ -266,7 +269,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) u32 otpgp; priv->nvm_device_type = iwlcore_get_nvm_type(priv); - + if (priv->nvm_device_type == -ENOENT) + return -ENOENT; /* allocate eeprom */ if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) priv->cfg->eeprom_size = -- cgit v0.10.2 From cce53aa347c1e023d967b1cb1aa393c725aedba5 Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Fri, 17 Jul 2009 09:30:22 -0700 Subject: iwlwifi: update 1000 series API version to match firmware firmware file now contains build number so API needs to be updated. Signed-off-by: Jay Sternberg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 7da52f1..a899be9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -46,7 +46,7 @@ #include "iwl-5000-hw.h" /* Highest firmware API version supported */ -#define IWL1000_UCODE_API_MAX 2 +#define IWL1000_UCODE_API_MAX 3 /* Lowest firmware API version supported */ #define IWL1000_UCODE_API_MIN 1 -- cgit v0.10.2 From 34a66de628b5dcc4a93129610ccd24814935e8cd Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:23 -0700 Subject: iwlwifi: uCode Alive notification with timeout Wait for REPLY_ALIVE notification from init and runtime uCode. based on the type of REPLY_ALIVE, different status bit will be set to wake up the queue: STATUS_INIT_UCODE_ALIVE for init uCode STATUS_RT_UCODE_ALIVE for runtime uCode. If timeout, attempt to download the failing uCode image again. This can only be done for the init ucode images of all iwlagn devices and the runtime ucode image of the 5000 series and up. If there is a problem with the 4965 runtime ucode coming up we restart the interface and thus trigger a new download of the init ucode also. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f4eb683..272409c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Begin load bsm\n"); - priv->ucode_type = UCODE_RT; + priv->ucode_type = UCODE_INIT; /* make sure bootstrap program is no larger than BSM's SRAM size */ if (len > IWL49_MAX_BSM_SIZE) @@ -256,6 +256,8 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) */ static void iwl4965_init_alive_start(struct iwl_priv *priv) { + int ret; + /* Check alive response for "valid" sign from uCode */ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { /* We had an error bringing up the hardware, so take it @@ -287,6 +289,28 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n"); goto restart; } + priv->ucode_type = UCODE_RT; + if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { + IWL_WARN(priv, "Runtime uCode already alive? " + "Waiting for alive anyway\n"); + clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status); + } + ret = wait_event_interruptible_timeout( + priv->wait_command_queue, + test_bit(STATUS_RT_UCODE_ALIVE, &priv->status), + UCODE_ALIVE_TIMEOUT); + if (!ret) { + /* FIXME: if STATUS_RT_UCODE_ALIVE timeout + * go back to restart the download Init uCode again + * this might cause to trap in the restart loop + */ + priv->ucode_type = UCODE_NONE; + if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { + IWL_ERR(priv, "Runtime timeout after %dms\n", + jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); + goto restart; + } + } return; restart: diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6b874da..f61f653a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -533,12 +533,16 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, if (palive->ver_subtype == INITIALIZE_SUBTYPE) { IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); + set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); memcpy(&priv->card_alive_init, &pkt->u.alive_frame, sizeof(struct iwl_init_alive_resp)); pwork = &priv->init_alive_start; } else { IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); + set_bit(STATUS_RT_UCODE_ALIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); memcpy(&priv->card_alive, &pkt->u.alive_frame, sizeof(struct iwl_alive_resp)); pwork = &priv->alive_start; @@ -1782,6 +1786,7 @@ static int __iwl_up(struct iwl_priv *priv) { int i; int ret; + unsigned long status; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); @@ -1859,6 +1864,51 @@ static int __iwl_up(struct iwl_priv *priv) /* start card; "initialize" will load runtime ucode */ iwl_nic_start(priv); + /* Just finish download Init or Runtime uCode image to device + * now we wait here for uCode send REPLY_ALIVE notification + * to indicate uCode is ready. + * 1) For Init uCode image, all iwlagn devices should wait here + * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before + * receive the REPLY_ALIVE notification, go back and try to + * download the Init uCode image again. + * 2) For Runtime uCode image, all iwlagn devices except 4965 + * wait here on STATUS_RT_UCODE_ALIVE status bit; if + * timeout before receive the REPLY_ALIVE notification, go back + * and download the Runtime uCode image again. + * 3) For 4965 Runtime uCode, it will not go through this path, + * need to wait for STATUS_RT_UCODE_ALIVE status bit in + * iwl4965_init_alive_start() function; if timeout, need to + * restart and download Init uCode image. + */ + if (priv->ucode_type == UCODE_INIT) + status = STATUS_INIT_UCODE_ALIVE; + else + status = STATUS_RT_UCODE_ALIVE; + if (test_bit(status, &priv->status)) { + IWL_WARN(priv, + "%s uCode already alive? " + "Waiting for alive anyway\n", + (status == STATUS_INIT_UCODE_ALIVE) + ? "INIT" : "Runtime"); + clear_bit(status, &priv->status); + } + ret = wait_event_interruptible_timeout( + priv->wait_command_queue, + test_bit(status, &priv->status), + UCODE_ALIVE_TIMEOUT); + if (!ret) { + if (!test_bit(status, &priv->status)) { + priv->ucode_type = + (status == STATUS_INIT_UCODE_ALIVE) + ? UCODE_NONE : UCODE_INIT; + IWL_ERR(priv, + "%s timeout after %dms\n", + (status == STATUS_INIT_UCODE_ALIVE) + ? "INIT" : "Runtime", + jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); + continue; + } + } IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b82480a..8655e09 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1341,10 +1341,17 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - else + switch (priv->ucode_type) { + case UCODE_RT: base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + break; + case UCODE_INIT: + base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); + break; + default: + IWL_ERR(priv, "uCode image not available\n"); + return; + } if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); @@ -1396,10 +1403,17 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, if (num_events == 0) return; - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - else + switch (priv->ucode_type) { + case UCODE_RT: base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + break; + case UCODE_INIT: + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + break; + default: + IWL_ERR(priv, "uCode image not available\n"); + return; + } if (mode == 0) event_size = 2 * sizeof(u32); @@ -1436,10 +1450,17 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - else + switch (priv->ucode_type) { + case UCODE_RT: base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + break; + case UCODE_INIT: + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + break; + default: + IWL_ERR(priv, "uCode image not available\n"); + return; + } if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index c844fab..a697b84 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -512,6 +512,8 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 #define STATUS_MODE_PENDING 18 +#define STATUS_INIT_UCODE_ALIVE 19 +#define STATUS_RT_UCODE_ALIVE 20 static inline int iwl_is_ready(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f4afd0c..926df3a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -772,6 +772,8 @@ struct iwl_calib_result { size_t buf_len; }; +#define UCODE_ALIVE_TIMEOUT (5 * HZ) + enum ucode_type { UCODE_NONE = 0, UCODE_INIT, -- cgit v0.10.2 From a562a9dda7f47e7cac58d80bf1ffe441feca510e Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 17 Jul 2009 09:30:24 -0700 Subject: iwlwifi: make debug level more user friendly * Deprecate the "debug50" module parameter used to obtain 5000 series and up debugging. Replace it with "debug" module parameter to match with original driver and be consistent between them. The "debug50" module parameter can still be used, except that the module parameter is not writable in keeping with its previous state. We currently just mark it as "deprecated" and do not have it in the feature-removal-schedule. Some more cleanup of module parameters needs to be done and can then be entered together. * Only make "debug" module parameters visible if the driver is compiled with CONFIG_IWLWIFI_DEBUG. This will eliminate a lot of confusion where users think they have set debug flags but yet cannot see any debug output. * Make module parameters writable. This eliminates the need for the "debug_level" sysfs file, which can now also be deprecated and added to feature-removal-schedule. This file is in significant use though with many iwlwifi documents and text referring users to it. We can thus not take its removal lightly and keep it around. With iwlcore shared between iwlagn and iwl3945 we really do not need debug module parameters for each but can instead have one debug module parameter for the iwlcore module. The same issue is here as with the sysfs file - a lot of iwlwifi documentation and text (like bug reports) rely on iwlagn and iwl3945 having this module parameter, so changing this to a module parameter of iwlcore will have significant impact and we do not do this for that reason. One consequence of this patch is that if a user is running a system with both 3945 and later hardware then the setting of the one module parameter will affect the value of the other. The likelihood of this seems low - and even if this setup is present it does not seem like an issue for both modules to run with the same debug level. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 14a47c0..8ee403c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -502,14 +502,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(priv, IWL_DL_RX, data, length); + iwl_print_hex_dump(IWL_DL_RX, data, length); } static void iwl3945_dbg_report_frame(struct iwl_priv *priv, struct iwl_rx_packet *pkt, struct ieee80211_hdr *header, int group100) { - if (priv->debug_level & IWL_DL_RX) + if (iwl_debug_level & IWL_DL_RX) _iwl3945_dbg_report_frame(priv, pkt, header, group100); } diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 272409c..c30a1b9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2376,8 +2376,6 @@ module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); -module_param_named(debug, iwl4965_mod_params.debug, uint, 0444); -MODULE_PARM_DESC(debug, "debug output mask"); module_param_named( disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 74103cf..702db07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1745,8 +1745,6 @@ MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); MODULE_PARM_DESC(swcrypto50, "using software crypto engine (default 0 [hardware])\n"); -module_param_named(debug50, iwl50_mod_params.debug, uint, 0444); -MODULE_PARM_DESC(debug50, "50XX debug output mask"); module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f61f653a..ff4a546f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -904,7 +904,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & IWL_DL_ISR) { + if (iwl_debug_level & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -939,7 +939,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -1053,7 +1053,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -1084,7 +1084,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) inta = priv->inta; #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & IWL_DL_ISR) { + if (iwl_debug_level & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", @@ -1112,7 +1112,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -2456,14 +2456,16 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, * used for controlling the debug level. * * See the level definitions in iwl for details. + * + * FIXME This file can be deprecated as the module parameter is + * writable and users can thus also change the debug level + * using the /sys/module/iwl3945/parameters/debug file. */ static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = dev_get_drvdata(d); - - return sprintf(buf, "0x%08X\n", priv->debug_level); + return sprintf(buf, "0x%08X\n", iwl_debug_level); } static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, @@ -2477,7 +2479,7 @@ static ssize_t store_debug_level(struct device *d, if (ret) IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); else - priv->debug_level = val; + iwl_debug_level = val; return strnlen(buf, count); } @@ -2829,7 +2831,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. */ if (cfg->mod_params->disable_hw_scan) { - if (cfg->mod_params->debug & IWL_DL_INFO) + if (iwl_debug_level & IWL_DL_INFO) dev_printk(KERN_DEBUG, &(pdev->dev), "Disabling hw_scan\n"); iwl_hw_ops.hw_scan = NULL; @@ -2851,7 +2853,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->inta_mask = CSR_INI_SET_MASK; #ifdef CONFIG_IWLWIFI_DEBUG - priv->debug_level = priv->cfg->mod_params->debug; atomic_set(&priv->restrict_refcnt, 0); #endif @@ -3211,3 +3212,11 @@ static void __exit iwl_exit(void) module_exit(iwl_exit); module_init(iwl_init); + +#ifdef CONFIG_IWLWIFI_DEBUG +module_param_named(debug50, iwl_debug_level, uint, 0444); +MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)"); +module_param_named(debug, iwl_debug_level, uint, 0644); +MODULE_PARM_DESC(debug, "debug output mask"); +#endif + diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8655e09..976004f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -59,6 +59,9 @@ MODULE_LICENSE("GPL"); IWL_RATE_##pp##M_INDEX, \ IWL_RATE_##np##M_INDEX } +u32 iwl_debug_level; +EXPORT_SYMBOL(iwl_debug_level); + static irqreturn_t iwl_isr(int irq, void *data); /* @@ -1275,7 +1278,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) struct iwl_rxon_cmd *rxon = &priv->staging_rxon; IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); - iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n", @@ -1505,7 +1508,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & IWL_DL_FW_ERRORS) { + if (iwl_debug_level & IWL_DL_FW_ERRORS) { iwl_dump_nic_error_log(priv); iwl_dump_nic_event_log(priv); iwl_print_rx_config_cmd(priv); @@ -2004,7 +2007,7 @@ static irqreturn_t iwl_isr(int irq, void *data) } #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " "fh 0x%08x\n", inta, inta_mask, inta_fh); @@ -2311,7 +2314,7 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " "notification for %s:\n", le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a697b84..f82ec9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -190,7 +190,6 @@ struct iwl_ops { struct iwl_mod_params { int sw_crypto; /* def: 0 = using hardware encryption */ - u32 debug; /* def: 0 = minimal debug log messages */ int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index e4a4dbd..9faf0c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -30,6 +30,7 @@ #define __iwl_debug_h__ struct iwl_priv; +extern u32 iwl_debug_level; #define IWL_ERR(p, f, a...) dev_err(&((p)->pci_dev->dev), f, ## a) #define IWL_WARN(p, f, a...) dev_warn(&((p)->pci_dev->dev), f, ## a) @@ -45,7 +46,7 @@ do { \ #ifdef CONFIG_IWLWIFI_DEBUG #define IWL_DEBUG(__priv, level, fmt, args...) \ do { \ - if (__priv->debug_level & (level)) \ + if (iwl_debug_level & (level)) \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ @@ -53,15 +54,15 @@ do { \ #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \ do { \ - if ((__priv->debug_level & (level)) && net_ratelimit()) \ + if ((iwl_debug_level & (level)) && net_ratelimit()) \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ } while (0) -#define iwl_print_hex_dump(priv, level, p, len) \ +#define iwl_print_hex_dump(level, p, len) \ do { \ - if (priv->debug_level & level) \ + if (iwl_debug_level & level) \ print_hex_dump(KERN_DEBUG, "iwl data: ", \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) @@ -103,8 +104,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv); #else #define IWL_DEBUG(__priv, level, fmt, args...) #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) -static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, - void *p, u32 len) +static inline void iwl_print_hex_dump(int level, void *p, u32 len) {} #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 926df3a..0751891 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1111,7 +1111,6 @@ struct iwl_priv { #ifdef CONFIG_IWLWIFI_DEBUG /* debugging info */ - u32 debug_level; u32 framecnt_to_us; atomic_t restrict_refcnt; #ifdef CONFIG_IWLWIFI_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index fc7edd1..5d5f215 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -646,7 +646,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, u32 tsf_low; int rssi; - if (likely(!(priv->debug_level & IWL_DL_RX))) + if (likely(!(iwl_debug_level & IWL_DL_RX))) return; /* MAC header */ @@ -742,7 +742,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(priv, IWL_DL_RX, header, length); + iwl_print_hex_dump(IWL_DL_RX, header, length); } #endif @@ -1061,7 +1061,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, /* Set "1" to report good data frames in groups of 100 */ #ifdef CONFIG_IWLWIFI_DEBUG - if (unlikely(priv->debug_level & IWL_DL_RX)) + if (unlikely(iwl_debug_level & IWL_DL_RX)) iwl_dbg_report_frame(priv, rx_start, len, header, 1); #endif IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 7fd806d..cbe4e26 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1093,7 +1093,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) IWL_DEBUG_DROP(priv, "Station %pM not in station map. " "Defaulting to broadcast...\n", hdr->addr1); - iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; default: diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 7073069..ef7e6bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -869,8 +869,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", le16_to_cpu(out_cmd->hdr.sequence)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags)); - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); + iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); + iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); /* Set up entry for this TFD in Tx byte-count array */ if (info->flags & IEEE80211_TX_CTL_AMPDU) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index bd6a067..221a875 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -612,8 +612,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", le16_to_cpu(out_cmd->hdr.sequence)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags)); - iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx)); - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr, + iwl_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx)); + iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr, ieee80211_hdrlen(fc)); /* @@ -1644,7 +1644,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & IWL_DL_ISR) { + if (iwl_debug_level & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -1679,7 +1679,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -1758,7 +1758,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -3308,13 +3308,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * used for controlling the debug level. * * See the level definitions in iwl for details. + * + * FIXME This file can be deprecated as the module parameter is + * writable and users can thus also change the debug level + * using the /sys/module/iwl3945/parameters/debug file. */ static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = dev_get_drvdata(d); - - return sprintf(buf, "0x%08X\n", priv->debug_level); + return sprintf(buf, "0x%08X\n", iwl_debug_level); } static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, @@ -3328,7 +3330,7 @@ static ssize_t store_debug_level(struct device *d, if (ret) IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf); else - priv->debug_level = val; + iwl_debug_level = val; return strnlen(buf, count); } @@ -3966,7 +3968,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->inta_mask = CSR_INI_SET_MASK; #ifdef CONFIG_IWLWIFI_DEBUG - priv->debug_level = iwl3945_mod_params.debug; atomic_set(&priv->restrict_refcnt, 0); #endif @@ -4262,8 +4263,10 @@ MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using software crypto (default 1 [software])\n"); -module_param_named(debug, iwl3945_mod_params.debug, uint, 0444); +#ifdef CONFIG_IWLWIFI_DEBUG +module_param_named(debug, iwl_debug_level, uint, 0644); MODULE_PARM_DESC(debug, "debug output mask"); +#endif module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444); -- cgit v0.10.2 From 58dba728b1b727cb3d95a1f76ca4e88a1e628ee1 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 17 Jul 2009 09:30:25 -0700 Subject: iwlwifi: clarify hardware error message When a hardware error is detected we need to be clear about that and not create impression that the microcode is able to deal with it. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ff4a546f..b7ac4ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -923,7 +923,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) /* Now service all interrupt bits discovered above. */ if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); + IWL_ERR(priv, "Hardware error detected. Restarting.\n"); /* Tell the device to stop sending interrupts */ iwl_disable_interrupts(priv); @@ -1096,7 +1096,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* Now service all interrupt bits discovered above. */ if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); + IWL_ERR(priv, "Hardware error detected. Restarting.\n"); /* Tell the device to stop sending interrupts */ iwl_disable_interrupts(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 221a875..8891d6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1663,7 +1663,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) /* Now service all interrupt bits discovered above. */ if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); + IWL_ERR(priv, "Hardware error detected. Restarting.\n"); /* Tell the device to stop sending interrupts */ iwl_disable_interrupts(priv); -- cgit v0.10.2 From 4c423a2b0cc3c85137988962e6ba3f01baef0b4e Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 17 Jul 2009 09:30:26 -0700 Subject: iwlwifi: inform user about rfkill state changes rfkill state changes are mostly available through debug messages. These are significant enough to always make user aware of so we turn them into warnings. Also insert a missing newline in some rfkill related debug message. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b7ac4ee..44c7f23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -964,7 +964,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) hw_rf_kill = 1; - IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", + IWL_WARN(priv, "RF_KILL bit toggled to %s.\n", hw_rf_kill ? "disable radio" : "enable radio"); priv->isr_stats.rfkill++; @@ -1137,7 +1137,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) hw_rf_kill = 1; - IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", + IWL_WARN(priv, "RF_KILL bit toggled to %s.\n", hw_rf_kill ? "disable radio" : "enable radio"); priv->isr_stats.rfkill++; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index ef7e6bd..0912987 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -940,7 +940,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) !(cmd->meta.flags & CMD_SIZE_HUGE)); if (iwl_is_rfkill(priv)) { - IWL_DEBUG_INFO(priv, "Not sending command - RF KILL"); + IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n"); return -EIO; } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8891d6e..2cc7e30 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -926,7 +926,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; - IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", + IWL_WARN(priv, "Card state received: HW:%s SW:%s\n", (flags & HW_CARD_DISABLED) ? "Kill" : "On", (flags & SW_CARD_DISABLED) ? "Kill" : "On"); -- cgit v0.10.2 From 30a12a8fbbd530b016277dd2ab65246b516540a8 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:27 -0700 Subject: iwlwifi: change iwl_enable/disable_interrupts to "inline" iwl_enable_interrupts is being called inside the interrupt, change from function call to inline Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 976004f..6aea026 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1749,31 +1749,6 @@ void iwl_uninit_drv(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_uninit_drv); - -void iwl_disable_interrupts(struct iwl_priv *priv) -{ - clear_bit(STATUS_INT_ENABLED, &priv->status); - - /* disable interrupts from uCode/NIC to host */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - /* acknowledge/clear/reset any interrupts still pending - * from uCode or flow handler (Rx/Tx DMA) */ - iwl_write32(priv, CSR_INT, 0xffffffff); - iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); - IWL_DEBUG_ISR(priv, "Disabled interrupts\n"); -} -EXPORT_SYMBOL(iwl_disable_interrupts); - -void iwl_enable_interrupts(struct iwl_priv *priv) -{ - IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); - set_bit(STATUS_INT_ENABLED, &priv->status); - iwl_write32(priv, CSR_INT_MASK, priv->inta_mask); -} -EXPORT_SYMBOL(iwl_enable_interrupts); - - #define ICT_COUNT (PAGE_SIZE/sizeof(u32)) /* Free dram table */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f82ec9e..614ec7c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -458,8 +458,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, /***************************************************** * PCI * *****************************************************/ -void iwl_disable_interrupts(struct iwl_priv *priv); -void iwl_enable_interrupts(struct iwl_priv *priv); irqreturn_t iwl_isr_legacy(int irq, void *data); int iwl_reset_ict(struct iwl_priv *priv); void iwl_disable_ict(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index a1328c3..bd0b12e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -145,4 +145,25 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue) #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue +static inline void iwl_disable_interrupts(struct iwl_priv *priv) +{ + clear_bit(STATUS_INT_ENABLED, &priv->status); + + /* disable interrupts from uCode/NIC to host */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* acknowledge/clear/reset any interrupts still pending + * from uCode or flow handler (Rx/Tx DMA) */ + iwl_write32(priv, CSR_INT, 0xffffffff); + iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); + IWL_DEBUG_ISR(priv, "Disabled interrupts\n"); +} + +static inline void iwl_enable_interrupts(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); + set_bit(STATUS_INT_ENABLED, &priv->status); + iwl_write32(priv, CSR_INT_MASK, priv->inta_mask); +} + #endif /* __iwl_helpers_h__ */ -- cgit v0.10.2 From 4951348109c334f2b839816bd161522d089cb782 Mon Sep 17 00:00:00 2001 From: Luis Correia Date: Fri, 17 Jul 2009 21:39:19 +0200 Subject: rt2x00: Comment spellchecking Fix a bunch of spelling errors in the rt2x00 drivers Signed-off-by: Luis Correia Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index ec3b004..ccd6441 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -928,7 +928,7 @@ #define RXD_W7_RESERVED FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. * NOTE: Logics in rt2400pci for txpower are reversed * compared to the other rt2x00 drivers. A higher txpower diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index ce2f065..54d3795 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -1218,7 +1218,7 @@ #define RXD_W10_DROP FIELD32(0x00000001) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index 5bc46fe..b01edca 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -831,7 +831,7 @@ #define RXD_W3_EIV FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f35b3d6..9efb417 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1910,7 +1910,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, /* * Before the radio can be enabled, the device first has * to be woken up. After that it needs a bit of time - * to be fully awake and the radio can be enabled. + * to be fully awake and then the radio can be enabled. */ rt2800usb_set_state(rt2x00dev, STATE_AWAKE); msleep(1); @@ -1918,7 +1918,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, break; case STATE_RADIO_OFF: /* - * After the radio has been disablee, the device should + * After the radio has been disabled, the device should * be put to sleep for powersaving. */ rt2800usb_disable_radio(rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 61a8be6..2d9dc37 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -1921,7 +1921,7 @@ struct mac_iveiv_entry { #define RXWI_W3_SNR1 FIELD32(0x0000ff00) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. */ #define MIN_G_TXPOWER 0 diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 4c76c8d..cbec91e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -245,7 +245,7 @@ struct link_ant { struct antenna_setup active; /* - * RSSI information for the different antenna's. + * RSSI information for the different antennas. * These statistics are used to determine when * to switch antenna when using software diversity. * @@ -633,7 +633,7 @@ struct rt2x00_dev { * The structure stored in here depends on the * system bus (PCI or USB). * When accessing this variable, the rt2x00dev_{pci,usb} - * macro's should be used for correct typecasting. + * macros should be used for correct typecasting. */ struct device *dev; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 3e019a1..c6e0bcf 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -132,7 +132,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, /* * Failsafe: Make sure we are not sending the * ANTENNA_SW_DIVERSITY state to the driver. - * If that happes fallback to hardware default, + * If that happens, fallback to hardware defaults, * or our own default. * The calls to rt2x00lib_config_antenna_check() * might have caused that we restore back to the already diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index c54eda3..30fbd3b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -129,7 +129,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc) /* Pull buffer to correct size */ skb_pull(skb, txdesc->iv_len); - /* IV/EIV data has officially be stripped */ + /* IV/EIV data has officially been stripped */ skbdesc->flags |= SKBDESC_IV_STRIPPED; } diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index eb9b981..3257075 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -158,7 +158,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) /* * During the last period we have sampled the RSSI - * from both antenna's. It now is time to determine + * from both antennas. It now is time to determine * which antenna demonstrated the best performance. * When we are already on the antenna with the best * performance, then there really is nothing for us diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 3425984..9d31c23 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -341,7 +341,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) int status; /* - * Mac80211 might be calling this function while we are trying + * mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) @@ -587,7 +587,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, int update_bssid = 0; /* - * Mac80211 might be calling this function while we are trying + * mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index b5e0634..47d175a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -29,7 +29,7 @@ #include /** - * DOC: Entrie frame size + * DOC: Entry frame size * * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes, * for USB devices this restriction does not apply, but the value of @@ -45,13 +45,13 @@ /** * DOC: Number of entries per queue * - * Under normal load without fragmentation 12 entries are sufficient + * Under normal load without fragmentation, 12 entries are sufficient * without the queue being filled up to the maximum. When using fragmentation - * and the queue threshold code we need to add some additional margins to + * and the queue threshold code, we need to add some additional margins to * make sure the queue will never (or only under extreme load) fill up * completely. - * Since we don't use preallocated DMA having a large number of queue entries - * will have only minimal impact on the memory requirements for the queue. + * Since we don't use preallocated DMA, having a large number of queue entries + * will have minimal impact on the memory requirements for the queue. */ #define RX_ENTRIES 24 #define TX_ENTRIES 24 diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 861322d..983e52e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -176,8 +176,8 @@ struct rt2x00_field32 { #define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x)) /* - * Macro's to find first set bit in a variable. - * These macro's behaves the same as the __ffs() function with + * Macros to find first set bit in a variable. + * These macros behave the same as the __ffs() functions but * the most important difference that this is done during * compile-time rather then run-time. */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index b435c14..fb95b8c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2312,7 +2312,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) } /* - * Determine number of antenna's. + * Determine number of antennas. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 6c71f77..93eb699 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -1476,7 +1476,7 @@ struct hw_pairwise_ta_entry { #define RXD_W15_RESERVED FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index c8016f6..81fe0be 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -809,7 +809,7 @@ struct hw_pairwise_ta_entry { /* * EEPROM antenna. - * ANTENNA_NUM: Number of antenna's. + * ANTENNA_NUM: Number of antennas. * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only. @@ -1058,7 +1058,7 @@ struct hw_pairwise_ta_entry { #define RXD_W5_RESERVED FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 -- cgit v0.10.2 From da3c821f549419e09b4b64f07d99f52174daae6d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 19 Jul 2009 15:00:39 +0200 Subject: wl12xx: fix spelling Changes (comments and debug output): * couldnt -> couldn't * frmware -> firmware * recevied -> received Signed-off-by: Stefan Weil Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 5a8d21c..a46c92a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -84,7 +84,7 @@ int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id) ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY, default_key, sizeof(*default_key)); if (ret < 0) { - wl1251_error("Couldnt set default key"); + wl1251_error("Couldn't set default key"); goto out; } @@ -231,7 +231,7 @@ int wl1251_acx_feature_cfg(struct wl1251 *wl) ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, feature, sizeof(*feature)); if (ret < 0) { - wl1251_error("Couldnt set HW encryption"); + wl1251_error("Couldn't set HW encryption"); goto out; } diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c index 96a45f5..e7b9aab 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -423,7 +423,7 @@ static void wl1251_irq_work(struct work_struct *work) wl->rx_counter = wl1251_mem_read32(wl, wl->data_path->rx_control_addr); - /* We handle a frmware bug here */ + /* We handle a firmware bug here */ switch ((wl->rx_counter - wl->rx_handled) & 0xf) { case 0: wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); @@ -575,7 +575,7 @@ static int wl1251_hw_init_data_path_config(struct wl1251 *wl) wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), GFP_KERNEL); if (!wl->data_path) { - wl1251_error("Couldnt allocate data path parameters"); + wl1251_error("Couldn't allocate data path parameters"); return -ENOMEM; } diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h index 81156b9..563a3fd 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.h +++ b/drivers/net/wireless/wl12xx/wl1251_rx.h @@ -88,7 +88,7 @@ struct wl1251_rx_descriptor { u8 type; /* - * Recevied Rate: + * Received Rate: * 0x0A - 1MBPS * 0x14 - 2MBPS * 0x37 - 5_5MBPS -- cgit v0.10.2 From 1b7e528b2e39bfed37228eedaaf0665196d8ddc9 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 21 Jun 2009 00:02:14 +0200 Subject: ath9k: wake up the chip for TSF reset If we are in NETWORK SLEEP state, AR_SLP32_TSF_WRITE_STATUS limit always exceeds in 'ath9k_hw_reset_tsf', because reading of the AR_SLP3 register always return with the magic 0xdeadbeef value. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index b9d1a13..9853769 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3842,6 +3842,7 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) { int count; + ath9k_ps_wakeup(ah->ah_sc); count = 0; while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { count++; @@ -3853,6 +3854,7 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) udelay(10); } REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); + ath9k_ps_restore(ah->ah_sc); } bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) -- cgit v0.10.2 From f9b604f6c24ad161e9c9e30a138d5899724225c8 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 21 Jun 2009 00:02:15 +0200 Subject: ath9k: make use ath9k_hw_wait int ath9k_hw_reset_tsf We have a dedicated function for this kind of checks, use that instead of duplicating the code. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9853769..605803a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3840,19 +3840,12 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64) void ath9k_hw_reset_tsf(struct ath_hw *ah) { - int count; - ath9k_ps_wakeup(ah->ah_sc); - count = 0; - while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { - count++; - if (count > 10) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); - break; - } - udelay(10); - } + if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0, + AH_TSF_WRITE_TIMEOUT)) + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); + REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); ath9k_ps_restore(ah->ah_sc); } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 9a4570d..28bffdb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -95,6 +95,7 @@ #define MAX_RATE_POWER 63 #define AH_WAIT_TIMEOUT 100000 /* (us) */ +#define AH_TSF_WRITE_TIMEOUT 100 /* (us) */ #define AH_TIME_QUANTUM 10 #define AR_KEYTABLE_SIZE 128 #define POWER_UP_TIME 200000 -- cgit v0.10.2 From 9ab56078e638efb75ac4ccd27c7196cdfed2e6c8 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 13 Jul 2009 00:10:07 +0200 Subject: arlan: inverted logic? Inverted logic Signed-off-by: Roel Kluin Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index d479f47..f96c634 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1022,7 +1022,7 @@ static int arlan_mac_addr(struct net_device *dev, void *p) ARLAN_DEBUG_ENTRY("arlan_mac_addr"); return -EINVAL; - if (!netif_running(dev)) + if (netif_running(dev)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); -- cgit v0.10.2 From a99d02483a40b9410d8a7af3b653ebc3f106280f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 19 Jul 2009 22:09:32 +0200 Subject: mac80211: do not monitor the connection while scanning mac80211 constantly monitors the connection to the associated AP in order to check if it is out of reach/dead. This is absolutely fine most of the time. Except when there is a scheduled scan for the whole neighborhood. After all this path could trigger while scanning on different channel. Or even worse: this AP probing triggers a WARN_ON in rate_lowest_index when the scan code did a band transition! ( http://www.kerneloops.org/raw.php?rawid=449304 ) Reported-by: Larry Finger Signed-off-by: Christian Lamparter Tested-by: Larry Finger Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e3b3156..523c0d9 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2213,6 +2213,9 @@ static void ieee80211_sta_monitor_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.monitor_work); + if (sdata->local->sw_scanning || sdata->local->hw_scanning) + return; + ieee80211_mgd_probe_ap(sdata, false); } -- cgit v0.10.2 From f742880c9ca733b6c18bfaa0f5ad2a57f37180c2 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 19 Jul 2009 23:21:07 +0200 Subject: mac80211: fix spare warnings in driver-trace.h This patch fixes the following errors: driver-trace.h:148:1: error: cannot size expression driver-trace.h:148:1: error: cannot size expression [...] driver-trace.h:222:1: error: cannot size expression driver-trace.h:71:1: error: incompatible types for operation (<) driver-trace.h:71:1: left side has type void * driver-trace.h:71:1: right side has type int driver-trace.h:99:1: error: incompatible types for operation (<) driver-trace.h:99:1: left side has type void * driver-trace.h:99:1: right side has type int driver-trace.h:148:1: error: incompatible types for operation (<) driver-trace.h:148:1: left side has type void * driver-trace.h:148:1: right side has type int driver-trace.h:222:1: error: cannot size expression driver-trace.h:248:1: error: incompatible types for operation (<) driver-trace.h:248:1: left side has type void * driver-trace.h:248:1: right side has type int driver-trace.h:446:1: error: incompatible types for operation (<) driver-trace.h:446:1: left side has type void * driver-trace.h:446:1: right side has type int Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 48c93d1..5a10da2 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -5,7 +5,7 @@ #include #include "ieee80211_i.h" -#ifndef CONFIG_MAC80211_DRIVER_API_TRACER +#if !defined(CONFIG_MAC80211_DRIVER_API_TRACER) || defined(__CHECKER__) #undef TRACE_EVENT #define TRACE_EVENT(name, proto, ...) \ static inline void trace_ ## name(proto) {} @@ -639,7 +639,7 @@ TRACE_EVENT(drv_ampdu_action, LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret ) ); -#endif /* __MAC80211_DRIVER_TRACE */ +#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH . -- cgit v0.10.2 From e6a3f551bc236010c4d4d99e626e150e98a4c3e6 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 19 Jul 2009 21:53:14 -0500 Subject: p54: Eliminate unnecessary initialization In two places, variables are unnecessilarly initialized to NULL. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 549ef2d..0efe67d 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -529,7 +529,7 @@ static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src, int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; - struct eeprom_pda_wrap *wrap = NULL; + struct eeprom_pda_wrap *wrap; struct pda_entry *entry; unsigned int data_len, entry_len; void *tmp; @@ -722,7 +722,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; int ret = -ENOMEM; - void *eeprom = NULL; + void *eeprom; maxblocksize = EEPROM_READBACK_LEN; if (priv->fw_var >= 0x509) -- cgit v0.10.2 From 1f00fca5c83c1bc5b4ca7e07f2a030bc39c130f2 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jul 2009 11:47:43 +0800 Subject: cfg80211: set_default_key only for WEP We invoke the cfg80211 set_default_key callback only for WEP key configuring. Signed-off-by: Zhu Yi Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index e6731bf..c7351a9 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -531,7 +531,8 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, wdev->wext.keys->data[idx]; } - if (params->cipher != WLAN_CIPHER_SUITE_AES_CMAC && + if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || + params->cipher == WLAN_CIPHER_SUITE_WEP104) && (tx_key || (!addr && wdev->wext.default_key == -1))) { if (wdev->current_bss) err = rdev->ops->set_default_key(&rdev->wiphy, -- cgit v0.10.2 From 3409ff7711bcf70390d5ba8ebde5d913b5266a45 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jul 2009 11:47:44 +0800 Subject: cfg80211: fix typo of IWEVASSOCRESPIE It should be IWEVASSOCREQIE instead. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/net/wireless/sme.c b/net/wireless/sme.c index e7a8851..82de2d9 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -341,7 +341,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (req_ie && status == WLAN_STATUS_SUCCESS) { memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = req_ie_len; - wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); + wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie); } if (resp_ie && status == WLAN_STATUS_SUCCESS) { @@ -474,7 +474,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, if (req_ie) { memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = req_ie_len; - wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, + wireless_send_event(wdev->netdev, IWEVASSOCREQIE, &wrqu, req_ie); } -- cgit v0.10.2 From b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jul 2009 11:47:45 +0800 Subject: iwmc3200wifi: use cfg80211_connect_result to send req/resp IE cfg80211_connect_result() let us specify associate request and response IEs as parameters after we are connected. We use this capability instead of doing it ourselves with WEXT. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 79d9d89..2175a48 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -281,6 +281,11 @@ struct iwm_priv { struct work_struct reset_worker; struct mutex mutex; + u8 *req_ie; + int req_ie_len; + u8 *resp_ie; + int resp_ie_len; + char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 484f110..cf25744 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -497,6 +497,13 @@ void iwm_link_off(struct iwm_priv *iwm) memset(wstats, 0, sizeof(struct iw_statistics)); wstats->qual.updated = IW_QUAL_ALL_INVALID; + kfree(iwm->req_ie); + iwm->req_ie = NULL; + iwm->req_ie_len = 0; + kfree(iwm->resp_ie); + iwm->resp_ie = NULL; + iwm->resp_ie_len = 0; + del_timer_sync(&iwm->watchdog); } diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 82b572a..6743391 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -519,7 +519,8 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, - NULL, 0, NULL, 0, + iwm->req_ie, iwm->req_ie_len, + iwm->resp_ie, iwm->resp_ie_len, WLAN_STATUS_SUCCESS, GFP_KERNEL); break; case UMAC_ASSOC_COMPLETE_FAILURE: @@ -771,37 +772,46 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) { struct iwm_umac_notif_mgt_frame *mgt_frame = - (struct iwm_umac_notif_mgt_frame *)buf; + (struct iwm_umac_notif_mgt_frame *)buf; struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; u8 *ie; - unsigned int event; - union iwreq_data wrqu; IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, le16_to_cpu(mgt_frame->len)); if (ieee80211_is_assoc_req(mgt->frame_control)) { ie = mgt->u.assoc_req.variable;; - event = IWEVASSOCREQIE; + iwm->req_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->req_ie); + iwm->req_ie = kmemdup(mgt->u.assoc_req.variable, + iwm->req_ie_len, GFP_KERNEL); } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { ie = mgt->u.reassoc_req.variable;; - event = IWEVASSOCREQIE; + iwm->req_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->req_ie); + iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable, + iwm->req_ie_len, GFP_KERNEL); } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { ie = mgt->u.assoc_resp.variable;; - event = IWEVASSOCRESPIE; + iwm->resp_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->resp_ie); + iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable, + iwm->resp_ie_len, GFP_KERNEL); } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { ie = mgt->u.reassoc_resp.variable;; - event = IWEVASSOCRESPIE; + iwm->resp_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->resp_ie); + iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, + iwm->resp_ie_len, GFP_KERNEL); } else { IWM_ERR(iwm, "Unsupported management frame"); return 0; } - wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); - - IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length); - wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie); - return 0; } -- cgit v0.10.2 From 9c7c0cdd24e64f9aed39453a1bffc3b3fd16ef99 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jul 2009 11:47:46 +0800 Subject: iwmc3200wifi: fix cfg80211_connect_result is called in IBSS Avoid calling cfg80211_connect_result() in IBSS mode. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 6743391..86079a1 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -517,6 +517,9 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, iwm_link_on(iwm); + if (iwm->conf.mode == UMAC_MODE_IBSS) + goto ibss; + cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, iwm->req_ie, iwm->req_ie_len, @@ -530,6 +533,9 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, iwm_link_off(iwm); + if (iwm->conf.mode == UMAC_MODE_IBSS) + goto ibss; + cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, @@ -538,11 +544,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, break; } - if (iwm->conf.mode == UMAC_MODE_IBSS) { - cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); - return 0; - } + return 0; + ibss: + cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); return 0; } -- cgit v0.10.2 From 971ad01169398170976951d3a9479a29d231c734 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jul 2009 11:47:47 +0800 Subject: iwmc3200wifi: fix a use-after-free bug The patch fixes a use-after-free bug for cmd->seq_num; Reported-by: Dan Carpenter Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c index ee127fe4..c430418 100644 --- a/drivers/net/wireless/iwmc3200wifi/hal.c +++ b/drivers/net/wireless/iwmc3200wifi/hal.c @@ -105,9 +105,9 @@ #include "umac.h" #include "debug.h" -static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, - struct iwm_nonwifi_cmd *cmd, - struct iwm_udma_nonwifi_cmd *udma_cmd) +static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm, + struct iwm_nonwifi_cmd *cmd, + struct iwm_udma_nonwifi_cmd *udma_cmd) { INIT_LIST_HEAD(&cmd->pending); @@ -118,7 +118,7 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, cmd->seq_num = iwm->nonwifi_seq_num; udma_cmd->seq_num = cpu_to_le16(cmd->seq_num); - cmd->seq_num = iwm->nonwifi_seq_num++; + iwm->nonwifi_seq_num++; iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX; if (udma_cmd->resp) @@ -130,6 +130,8 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, cmd->buf.len = 0; memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); + + return cmd->seq_num; } u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm) @@ -369,7 +371,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm, const void *payload) { struct iwm_nonwifi_cmd *cmd; - int ret; + int ret, seq_num; cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL); if (!cmd) { @@ -377,7 +379,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm, return -ENOMEM; } - iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); + seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE || cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) { @@ -393,7 +395,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm, if (ret < 0) return ret; - return cmd->seq_num; + return seq_num; } static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr, -- cgit v0.10.2 From 1e056665e878ce4f91dbfd594f4ebba49ea689c0 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jul 2009 16:12:57 +0800 Subject: cfg80211: avoid setting default_key if add_key fails In cfg80211_upload_connect_keys(), we call add_key, set_default_key and set_default_mgmt_key (if applicable) one by one. If one of these operations fails, we should stop calling the following functions. Because if the key is not added successfully, we should not set it as default key anyway. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/net/wireless/util.c b/net/wireless/util.c index 4bab380..ba387d8 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -546,13 +546,17 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) if (!wdev->connect_keys->params[i].cipher) continue; if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, - &wdev->connect_keys->params[i])) + &wdev->connect_keys->params[i])) { printk(KERN_ERR "%s: failed to set key %d\n", dev->name, i); + continue; + } if (wdev->connect_keys->def == i) - if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) + if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) { printk(KERN_ERR "%s: failed to set defkey %d\n", dev->name, i); + continue; + } if (wdev->connect_keys->defmgmt == i) if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) printk(KERN_ERR "%s: failed to set mgtdef %d\n", -- cgit v0.10.2 From f974cfdd8112a081fb1a402bf77835f28f37fcad Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Mon, 20 Jul 2009 08:00:30 -0400 Subject: ath5k: fix values for bus error bits in ISR2 The new values are taken from the recently open sourced Atheros HAL. Correctness is also confirmed by the users with access to Atheros documentation. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 6809b54a..debad07 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -339,9 +339,9 @@ #define AR5K_SISR2 0x008c /* Register Address [5211+] */ #define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ #define AR5K_SISR2_QCU_TXURN_S 0 -#define AR5K_SISR2_MCABT 0x00100000 /* Master Cycle Abort */ -#define AR5K_SISR2_SSERR 0x00200000 /* Signaled System Error */ -#define AR5K_SISR2_DPERR 0x00400000 /* Bus parity error */ +#define AR5K_SISR2_MCABT 0x00010000 /* Master Cycle Abort */ +#define AR5K_SISR2_SSERR 0x00020000 /* Signaled System Error */ +#define AR5K_SISR2_DPERR 0x00040000 /* Bus parity error */ #define AR5K_SISR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */ #define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */ @@ -430,9 +430,9 @@ #define AR5K_SIMR2 0x00ac /* Register Address [5211+] */ #define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ #define AR5K_SIMR2_QCU_TXURN_S 0 -#define AR5K_SIMR2_MCABT 0x00100000 /* Master Cycle Abort */ -#define AR5K_SIMR2_SSERR 0x00200000 /* Signaled System Error */ -#define AR5K_SIMR2_DPERR 0x00400000 /* Bus parity error */ +#define AR5K_SIMR2_MCABT 0x00010000 /* Master Cycle Abort */ +#define AR5K_SIMR2_SSERR 0x00020000 /* Signaled System Error */ +#define AR5K_SIMR2_DPERR 0x00040000 /* Bus parity error */ #define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */ #define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */ -- cgit v0.10.2 From f298c282a5233126ffe6385c02a9e79f695bed0f Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 21 Jul 2009 14:25:53 +0300 Subject: wl1251: remove accidentally added wl1251_netlink.c Commit "wl1251: add wl1251 prefix to all 1251 files" accidentally added wl1251_netlink.c which contains a private netlink interface. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c deleted file mode 100644 index 67d3d5a..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_netlink.c +++ /dev/null @@ -1,679 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ -#include "wl1251_netlink.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "wl1251.h" -#include "wl1251_spi.h" -#include "wl1251_acx.h" - -/* FIXME: this should be changed as soon as user space catches up */ -#define WL1251_NL_NAME "wl1251" -#define WL1251_NL_VERSION 1 - -#define WL1251_MAX_TEST_LENGTH 1024 -#define WL1251_MAX_NVS_LENGTH 1024 - -enum wl1251_nl_commands { - WL1251_NL_CMD_UNSPEC, - WL1251_NL_CMD_TEST, - WL1251_NL_CMD_INTERROGATE, - WL1251_NL_CMD_CONFIGURE, - WL1251_NL_CMD_PHY_REG_READ, - WL1251_NL_CMD_NVS_PUSH, - WL1251_NL_CMD_REG_WRITE, - WL1251_NL_CMD_REG_READ, - WL1251_NL_CMD_SET_PLT_MODE, - - __WL1251_NL_CMD_AFTER_LAST -}; -#define WL1251_NL_CMD_MAX (__WL1251_NL_CMD_AFTER_LAST - 1) - -enum wl1251_nl_attrs { - WL1251_NL_ATTR_UNSPEC, - WL1251_NL_ATTR_IFNAME, - WL1251_NL_ATTR_CMD_TEST_PARAM, - WL1251_NL_ATTR_CMD_TEST_ANSWER, - WL1251_NL_ATTR_CMD_IE, - WL1251_NL_ATTR_CMD_IE_LEN, - WL1251_NL_ATTR_CMD_IE_BUFFER, - WL1251_NL_ATTR_CMD_IE_ANSWER, - WL1251_NL_ATTR_REG_ADDR, - WL1251_NL_ATTR_REG_VAL, - WL1251_NL_ATTR_NVS_BUFFER, - WL1251_NL_ATTR_NVS_LEN, - WL1251_NL_ATTR_PLT_MODE, - - __WL1251_NL_ATTR_AFTER_LAST -}; -#define WL1251_NL_ATTR_MAX (__WL1251_NL_ATTR_AFTER_LAST - 1) - -static struct genl_family wl1251_nl_family = { - .id = GENL_ID_GENERATE, - .name = WL1251_NL_NAME, - .hdrsize = 0, - .version = WL1251_NL_VERSION, - .maxattr = WL1251_NL_ATTR_MAX, -}; - -static struct net_device *ifname_to_netdev(struct net *net, - struct genl_info *info) -{ - char *ifname; - - if (!info->attrs[WL1251_NL_ATTR_IFNAME]) - return NULL; - - ifname = nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]); - - wl1251_debug(DEBUG_NETLINK, "Looking for %s", ifname); - - return dev_get_by_name(net, ifname); -} - -static struct wl1251 *ifname_to_wl1251(struct net *net, struct genl_info *info) -{ - struct net_device *netdev; - struct wireless_dev *wdev; - struct wiphy *wiphy; - struct ieee80211_hw *hw; - - netdev = ifname_to_netdev(net, info); - if (netdev == NULL) { - wl1251_error("Wrong interface"); - return NULL; - } - - wdev = netdev->ieee80211_ptr; - if (wdev == NULL) { - wl1251_error("ieee80211_ptr is NULL"); - return NULL; - } - - wiphy = wdev->wiphy; - if (wiphy == NULL) { - wl1251_error("wiphy is NULL"); - return NULL; - } - - hw = wiphy_priv(wiphy); - if (hw == NULL) { - wl1251_error("hw is NULL"); - return NULL; - } - - dev_put(netdev); - - return hw->priv; -} - -static int wl1251_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - struct wl1251_command *cmd; - char *buf; - int buf_len, ret, cmd_len; - u8 answer; - - if (!info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]) - return -EINVAL; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - return -EINVAL; - } - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - buf = nla_data(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]); - buf_len = nla_len(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]); - answer = nla_get_u8(info->attrs[WL1251_NL_ATTR_CMD_TEST_ANSWER]); - - cmd->header.id = CMD_TEST; - memcpy(cmd->parameters, buf, buf_len); - cmd_len = sizeof(struct wl1251_cmd_header) + buf_len; - - mutex_lock(&wl->mutex); - ret = wl1251_cmd_test(wl, cmd, cmd_len, answer); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto out; - } - - if (answer) { - struct sk_buff *msg; - void *hdr; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) { - ret = -ENOMEM; - goto out; - } - - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl1251_nl_family, 0, WL1251_NL_CMD_TEST); - if (IS_ERR(hdr)) { - ret = PTR_ERR(hdr); - goto nla_put_failure; - } - - NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, - nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - NLA_PUT(msg, WL1251_NL_ATTR_CMD_TEST_ANSWER, - sizeof(*cmd), cmd); - - ret = genlmsg_end(msg, hdr); - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - wl1251_debug(DEBUG_NETLINK, "TEST cmd sent, answer"); - ret = genlmsg_reply(msg, info); - goto out; - - nla_put_failure: - nlmsg_free(msg); - } else - wl1251_debug(DEBUG_NETLINK, "TEST cmd sent"); - -out: - kfree(cmd); - return ret; -} - -static int wl1251_nl_interrogate(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - struct sk_buff *msg; - int ret = -ENOBUFS, cmd_ie, cmd_ie_len; - struct wl1251_command *cmd; - void *hdr; - - if (!info->attrs[WL1251_NL_ATTR_CMD_IE]) - return -EINVAL; - - if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]) - return -EINVAL; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) - return -ENOMEM; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - ret = -EINVAL; - goto nla_put_failure; - } - - /* acx id */ - cmd_ie = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE]); - - /* maximum length of acx, including all headers */ - cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]); - - wl1251_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)", - cmd_ie, cmd_ie_len); - - mutex_lock(&wl->mutex); - ret = wl1251_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl1251_nl_family, 0, WL1251_NL_CMD_INTERROGATE); - if (IS_ERR(hdr)) { - ret = PTR_ERR(hdr); - goto nla_put_failure; - } - - NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, - nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - NLA_PUT(msg, WL1251_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd); - - ret = genlmsg_end(msg, hdr); - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - kfree(cmd); - return genlmsg_reply(msg, info); - - nla_put_failure: - kfree(cmd); - nlmsg_free(msg); - - return ret; -} - -static int wl1251_nl_configure(struct sk_buff *skb, struct genl_info *info) -{ - int ret = 0, cmd_ie_len, acx_len; - struct acx_header *acx = NULL; - struct sk_buff *msg; - struct wl1251 *wl; - void *cmd_ie; - u16 *id; - - if (!info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]) - return -EINVAL; - - if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]) - return -EINVAL; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) - return -ENOMEM; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - ret = -EINVAL; - goto nla_put_failure; - } - - /* contains the acx header but not the cmd header */ - cmd_ie = nla_data(info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]); - - cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]); - - /* acx id is in the first two bytes */ - id = cmd_ie; - - /* need to add acx_header before cmd_ie, so create a new command */ - acx_len = sizeof(struct acx_header) + cmd_ie_len; - acx = kzalloc(acx_len, GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto nla_put_failure; - } - - /* copy the acx header and the payload */ - memcpy(&acx->id, cmd_ie, cmd_ie_len); - - mutex_lock(&wl->mutex); - ret = wl1251_cmd_configure(wl, *id, acx, acx_len); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - wl1251_debug(DEBUG_NETLINK, "CONFIGURE cmd sent"); - - nla_put_failure: - kfree(acx); - nlmsg_free(msg); - - return ret; -} - -static int wl1251_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - struct sk_buff *msg; - u32 reg_addr, *reg_value = NULL; - int ret = 0; - void *hdr; - - if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) - return -EINVAL; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) - return -ENOMEM; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - ret = -EINVAL; - goto nla_put_failure; - } - - reg_value = kmalloc(sizeof(*reg_value), GFP_KERNEL); - if (!reg_value) { - ret = -ENOMEM; - goto nla_put_failure; - } - - reg_addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); - - wl1251_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr); - - mutex_lock(&wl->mutex); - ret = wl1251_cmd_read_memory(wl, reg_addr, reg_value, - sizeof(*reg_value)); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ); - if (IS_ERR(hdr)) { - ret = PTR_ERR(hdr); - goto nla_put_failure; - } - - NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, - nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - - NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, *reg_value); - - ret = genlmsg_end(msg, hdr); - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - kfree(reg_value); - - return genlmsg_reply(msg, info); - - nla_put_failure: - nlmsg_free(msg); - kfree(reg_value); - - return ret; -} - -static int wl1251_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - int ret = 0; - - if (!info->attrs[WL1251_NL_ATTR_NVS_BUFFER]) - return -EINVAL; - - if (!info->attrs[WL1251_NL_ATTR_NVS_LEN]) - return -EINVAL; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - return -EINVAL; - } - - mutex_lock(&wl->mutex); - wl->nvs_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_NVS_LEN]); - if (wl->nvs_len % 4) { - wl1251_error("NVS size is not multiple of 32: %d", wl->nvs_len); - ret = -EILSEQ; - goto out; - } - - /* If we already have an NVS, we should free it */ - kfree(wl->nvs); - - wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL); - if (wl->nvs == NULL) { - wl1251_error("Can't allocate NVS"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->nvs, - nla_data(info->attrs[WL1251_NL_ATTR_NVS_BUFFER]), - wl->nvs_len); - - wl1251_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes", - wl->nvs_len); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1251_nl_reg_read(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - u32 addr, val; - int ret = 0; - struct sk_buff *msg; - void *hdr; - - if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) - return -EINVAL; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) - return -ENOMEM; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - return -EINVAL; - } - - addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); - - mutex_lock(&wl->mutex); - val = wl1251_reg_read32(wl, addr); - mutex_unlock(&wl->mutex); - - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ); - if (IS_ERR(hdr)) { - ret = PTR_ERR(hdr); - goto nla_put_failure; - } - - NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, - nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - - NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, val); - - ret = genlmsg_end(msg, hdr); - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - return genlmsg_reply(msg, info); - - nla_put_failure: - nlmsg_free(msg); - - return ret; -} - -static int wl1251_nl_reg_write(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - u32 addr, val; - - if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) - return -EINVAL; - - if (!info->attrs[WL1251_NL_ATTR_REG_VAL]) - return -EINVAL; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - return -EINVAL; - } - - addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); - val = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_VAL]); - - mutex_lock(&wl->mutex); - wl1251_reg_write32(wl, addr, val); - mutex_unlock(&wl->mutex); - - return 0; -} - -static int wl1251_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - u32 val; - int ret; - - if (!info->attrs[WL1251_NL_ATTR_PLT_MODE]) - return -EINVAL; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - return -EINVAL; - } - - val = nla_get_u32(info->attrs[WL1251_NL_ATTR_PLT_MODE]); - - switch (val) { - case 0: - ret = wl1251_plt_stop(wl); - break; - case 1: - ret = wl1251_plt_start(wl); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static struct nla_policy wl1251_nl_policy[WL1251_NL_ATTR_MAX + 1] = { - [WL1251_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, - .len = IFNAMSIZ-1 }, - [WL1251_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY, - .len = WL1251_MAX_TEST_LENGTH }, - [WL1251_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 }, - [WL1251_NL_ATTR_CMD_IE] = { .type = NLA_U32 }, - [WL1251_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 }, - [WL1251_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY, - .len = WL1251_MAX_TEST_LENGTH }, - [WL1251_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY, - .len = WL1251_MAX_TEST_LENGTH }, - [WL1251_NL_ATTR_REG_ADDR] = { .type = NLA_U32 }, - [WL1251_NL_ATTR_REG_VAL] = { .type = NLA_U32 }, - [WL1251_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY, - .len = WL1251_MAX_NVS_LENGTH }, - [WL1251_NL_ATTR_NVS_LEN] = { .type = NLA_U32 }, - [WL1251_NL_ATTR_PLT_MODE] = { .type = NLA_U32 }, -}; - -static struct genl_ops wl1251_nl_ops[] = { - { - .cmd = WL1251_NL_CMD_TEST, - .doit = wl1251_nl_test_cmd, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_INTERROGATE, - .doit = wl1251_nl_interrogate, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_CONFIGURE, - .doit = wl1251_nl_configure, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_PHY_REG_READ, - .doit = wl1251_nl_phy_reg_read, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_NVS_PUSH, - .doit = wl1251_nl_nvs_push, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_REG_WRITE, - .doit = wl1251_nl_reg_write, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_REG_READ, - .doit = wl1251_nl_reg_read, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_SET_PLT_MODE, - .doit = wl1251_nl_set_plt_mode, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, -}; - -int wl1251_nl_register(void) -{ - int err, i; - - err = genl_register_family(&wl1251_nl_family); - if (err) - return err; - - for (i = 0; i < ARRAY_SIZE(wl1251_nl_ops); i++) { - err = genl_register_ops(&wl1251_nl_family, &wl1251_nl_ops[i]); - if (err) - goto err_out; - } - return 0; - err_out: - genl_unregister_family(&wl1251_nl_family); - return err; -} - -void wl1251_nl_unregister(void) -{ - genl_unregister_family(&wl1251_nl_family); -} -- cgit v0.10.2 From 270b7588b376968d4db3af01e6d9907814c45552 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 21 Jul 2009 14:26:01 +0300 Subject: wl1251: remove wl1251_plt_start/stop() This Production Line Testing code is currently unused and can be removed. It can be reintroduced when nl80211 test mode implemented for the driver. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 509cbef..da4c688 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -246,60 +246,6 @@ out: mutex_unlock(&wl->mutex); } -int wl1251_plt_start(struct wl1251 *wl) -{ - int ret; - - mutex_lock(&wl->mutex); - - wl1251_notice("power up"); - - if (wl->state != WL1251_STATE_OFF) { - wl1251_error("cannot go into PLT state because not " - "in off state: %d", wl->state); - return -EBUSY; - } - - wl->state = WL1251_STATE_PLT; - - ret = wl1251_chip_wakeup(wl); - if (ret < 0) - return ret; - - ret = wl->chip.op_boot(wl); - if (ret < 0) - return ret; - - wl1251_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); - - ret = wl->chip.op_plt_init(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_plt_stop(struct wl1251 *wl) -{ - mutex_lock(&wl->mutex); - - wl1251_notice("power down"); - - if (wl->state != WL1251_STATE_PLT) { - wl1251_error("cannot power down because not in PLT " - "state: %d", wl->state); - return -EBUSY; - } - - wl1251_disable_interrupts(wl); - wl1251_power_off(wl); - - wl->state = WL1251_STATE_OFF; - - return 0; -} - - static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct wl1251 *wl = hw->priv; -- cgit v0.10.2 From 834da346041cd8969897feea2cdb09269120599f Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 21 Jul 2009 14:26:08 +0300 Subject: MAINTAINERS: add wl1251 wireless driver Add myself as the maintainer for wl1251 driver. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index d119ba9..622bd12 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6466,6 +6466,15 @@ M: mitr@volny.cz S: Maintained F: drivers/input/misc/wistron_btns.c +WL1251 WIRELESS DRIVER +P: Kalle Valo +M: kalle.valo@nokia.com +L: linux-wireless@vger.kernel.org +W: http://wireless.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git +S: Maintained +F: drivers/net/wireless/wl12xx/wl1251* + WL3501 WIRELESS PCMCIA CARD DRIVER P: Arnaldo Carvalho de Melo M: acme@ghostprotocols.net -- cgit v0.10.2 From 2b3daf588965b72d3a9ccff426bfd5516bb73c6a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 21 Jul 2009 13:09:56 -0700 Subject: MAINTAINERS: Update rtl8180 patterns rtl8180 files were moved into a subdirectory by commit 1c740ed2210a0d124674a477ea538468aba47810 Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index 622bd12..df55d24 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4984,7 +4984,7 @@ L: linux-wireless@vger.kernel.org W: http://linuxwireless.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git S: Maintained -F: drivers/net/wireless/rtl818* +F: drivers/net/wireless/rtl818x/rtl8180* RTL8187 WIRELESS DRIVER P: Herton Ronaldo Krzesinski -- cgit v0.10.2 From 95a2b2ef82dc0bd10475c02e9d1fc7c93e708d03 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 21 Jul 2009 21:03:10 -0400 Subject: ath9k: do not stop the queues in driver stop mac80211 will have disabled the queues for us when needed. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 254e787..3436295 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2101,8 +2101,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); - ieee80211_stop_queues(hw); - if (ath9k_wiphy_started(sc)) { mutex_unlock(&sc->mutex); return; /* another wiphy still in use */ -- cgit v0.10.2 From ccc78ec5d463e6c99f4a384be52b31222ffe2e21 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 21 Jul 2009 21:03:42 -0400 Subject: adm8211: remove uneeded code during suspend/resume mac80211 drivers do not need to stop the software queues or call their own stop() callback upon suspend as we do it for drivers. Equally drivers don't have to call their own start() or start the queues as mac80211 will do it for us. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index ecc9383..5695911 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1964,14 +1964,6 @@ static void __devexit adm8211_remove(struct pci_dev *pdev) #ifdef CONFIG_PM static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) { - struct ieee80211_hw *dev = pci_get_drvdata(pdev); - struct adm8211_priv *priv = dev->priv; - - if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { - ieee80211_stop_queues(dev); - adm8211_stop(dev); - } - pci_save_state(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; @@ -1979,17 +1971,8 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) static int adm8211_resume(struct pci_dev *pdev) { - struct ieee80211_hw *dev = pci_get_drvdata(pdev); - struct adm8211_priv *priv = dev->priv; - pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - - if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { - adm8211_start(dev); - ieee80211_wake_queues(dev); - } - return 0; } #endif /* CONFIG_PM */ -- cgit v0.10.2 From c4029083e2acb82229c43b791c07afb089d972ff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2009 17:43:30 +0200 Subject: net: export __dev_addr_sync/__dev_addr_unsync For mac80211, with the master netdev removal, we need to be able to sync a multicast address list onto another list that is not tracked within a netdev, so we need access to the functions doing that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/core/dev.c b/net/core/dev.c index dca8b50..d6c657e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3923,6 +3923,7 @@ int __dev_addr_sync(struct dev_addr_list **to, int *to_count, } return err; } +EXPORT_SYMBOL_GPL(__dev_addr_sync); void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count) @@ -3942,6 +3943,7 @@ void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, da = next; } } +EXPORT_SYMBOL_GPL(__dev_addr_unsync); /** * dev_unicast_sync - Synchronize device's unicast list to another device -- cgit v0.10.2 From 3b8d81e020f77c9da8b85b0685c8cd2ca7c7b150 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2009 17:43:56 +0200 Subject: mac80211: remove master netdev With the internal 'pending' queue system in place, we can simply put packets there instead of pushing them off to the master dev, getting rid of the master interface completely. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a861259..7dd67a1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -241,6 +241,8 @@ struct ieee80211_bss_conf { * it can be sent out. * @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211, * used to indicate that a frame was already retried due to PS + * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, + * used to indicate frame should not be encrypted */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), @@ -259,6 +261,7 @@ enum mac80211_tx_control_flags { IEEE80211_TX_INTFL_RCALGO = BIT(13), IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), IEEE80211_TX_INTFL_RETRIED = BIT(15), + IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), }; /** diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 9e5762a..1958c7c4 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -383,9 +383,6 @@ static void ieee80211_agg_splice_packets(struct ieee80211_local *local, if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) { spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - /* mark queue as pending, it is stopped already */ - __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING, - &local->queue_stop_reasons[queue]); /* copy over remaining packets */ skb_queue_splice_tail_init( &sta->ampdu_mlme.tid_tx[tid]->pending, diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 6c439cd..96991b6 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -175,7 +175,7 @@ static ssize_t queues_read(struct file *file, char __user *user_buf, for (q = 0; q < local->hw.queues; q++) res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q, local->queue_stop_reasons[q], - __netif_subqueue_stopped(local->mdev, q)); + skb_queue_len(&local->pending[q])); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); return simple_read_from_buffer(user_buf, count, ppos, buf, res); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a34bca2..6a01771 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -567,14 +567,9 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_CSA, IEEE80211_QUEUE_STOP_REASON_AGGREGATION, IEEE80211_QUEUE_STOP_REASON_SUSPEND, - IEEE80211_QUEUE_STOP_REASON_PENDING, IEEE80211_QUEUE_STOP_REASON_SKB_ADD, }; -struct ieee80211_master_priv { - struct ieee80211_local *local; -}; - struct ieee80211_local { /* embed the driver visible part. * don't cast (use the static inlines below), but we keep @@ -587,13 +582,20 @@ struct ieee80211_local { /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ spinlock_t queue_stop_reason_lock; - struct net_device *mdev; /* wmaster# - "master" 802.11 device */ int open_count; int monitors, cooked_mntrs; /* number of interfaces with corresponding FIF_ flags */ int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; + + /* protects the aggregated multicast list and filter calls */ + spinlock_t filter_lock; + + /* aggregated multicast list */ + struct dev_addr_list *mc_list; + int mc_count; + bool tim_in_locked_section; /* see ieee80211_beacon_get() */ /* @@ -813,10 +815,6 @@ struct ieee80211_local { static inline struct ieee80211_sub_if_data * IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - BUG_ON(!local || local->mdev == dev); - return netdev_priv(dev); } @@ -996,7 +994,6 @@ void ieee80211_recalc_idle(struct ieee80211_local *local); /* tx handling */ void ieee80211_clear_tx_pending(struct ieee80211_local *local); void ieee80211_tx_pending(unsigned long data); -int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 090aa5a..2f797a8 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -190,10 +190,6 @@ static int ieee80211_open(struct net_device *dev) ETH_ALEN); } - if (compare_ether_addr(null_addr, local->mdev->dev_addr) == 0) - memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, - ETH_ALEN); - /* * Validate the MAC address for this device. */ @@ -229,9 +225,9 @@ static int ieee80211_open(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss++; - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); + spin_unlock_bh(&local->filter_lock); break; default: conf.vif = &sdata->vif; @@ -243,9 +239,9 @@ static int ieee80211_open(struct net_device *dev) if (ieee80211_vif_is_mesh(&sdata->vif)) { local->fif_other_bss++; - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); + spin_unlock_bh(&local->filter_lock); ieee80211_start_mesh(sdata); } @@ -279,10 +275,6 @@ static int ieee80211_open(struct net_device *dev) } if (local->open_count == 0) { - res = dev_open(local->mdev); - WARN_ON(res); - if (res) - goto err_del_interface; tasklet_enable(&local->tx_pending_tasklet); tasklet_enable(&local->tasklet); } @@ -393,7 +385,14 @@ static int ieee80211_stop(struct net_device *dev) if (sdata->flags & IEEE80211_SDATA_PROMISC) atomic_dec(&local->iff_promiscs); - dev_mc_unsync(local->mdev, dev); + netif_addr_lock_bh(dev); + spin_lock_bh(&local->filter_lock); + __dev_addr_unsync(&local->mc_list, &local->mc_count, + &dev->mc_list, &dev->mc_count); + ieee80211_configure_filter(local); + spin_unlock_bh(&local->filter_lock); + netif_addr_unlock_bh(dev); + del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); @@ -442,9 +441,9 @@ static int ieee80211_stop(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss--; - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); + spin_unlock_bh(&local->filter_lock); break; case NL80211_IFTYPE_STATION: del_timer_sync(&sdata->u.mgd.chswitch_timer); @@ -487,9 +486,9 @@ static int ieee80211_stop(struct net_device *dev) local->fif_other_bss--; atomic_dec(&local->iff_allmultis); - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); + spin_unlock_bh(&local->filter_lock); ieee80211_stop_mesh(sdata); } @@ -535,9 +534,6 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_recalc_ps(local, -1); if (local->open_count == 0) { - if (netif_running(local->mdev)) - dev_close(local->mdev); - drv_stop(local); ieee80211_led_radio(local, false); @@ -584,8 +580,11 @@ static void ieee80211_set_multicast_list(struct net_device *dev) atomic_dec(&local->iff_promiscs); sdata->flags ^= IEEE80211_SDATA_PROMISC; } - - dev_mc_sync(local->mdev, dev); + spin_lock_bh(&local->filter_lock); + __dev_addr_sync(&local->mc_list, &local->mc_count, + &dev->mc_list, &dev->mc_count); + ieee80211_configure_filter(local); + spin_unlock_bh(&local->filter_lock); } /* diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5b69f5f..3234f37 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -83,75 +83,14 @@ void ieee80211_configure_filter(struct ieee80211_local *local) new_flags |= (1<<31); drv_configure_filter(local, changed_flags, &new_flags, - local->mdev->mc_count, - local->mdev->mc_list); + local->mc_count, + local->mc_list); WARN_ON(new_flags & (1<<31)); local->filter_flags = new_flags & ~(1<<31); } -/* master interface */ - -static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) -{ - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - return ETH_ALEN; -} - -static const struct header_ops ieee80211_header_ops = { - .create = eth_header, - .parse = header_parse_80211, - .rebuild = eth_rebuild_header, - .cache = eth_header_cache, - .cache_update = eth_header_cache_update, -}; - -static int ieee80211_master_open(struct net_device *dev) -{ - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; - struct ieee80211_sub_if_data *sdata; - int res = -EOPNOTSUPP; - - /* we hold the RTNL here so can safely walk the list */ - list_for_each_entry(sdata, &local->interfaces, list) { - if (netif_running(sdata->dev)) { - res = 0; - break; - } - } - - if (res) - return res; - - netif_tx_start_all_queues(local->mdev); - - return 0; -} - -static int ieee80211_master_stop(struct net_device *dev) -{ - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; - struct ieee80211_sub_if_data *sdata; - - /* we hold the RTNL here so can safely walk the list */ - list_for_each_entry(sdata, &local->interfaces, list) - if (netif_running(sdata->dev)) - dev_close(sdata->dev); - - return 0; -} - -static void ieee80211_master_set_multicast_list(struct net_device *dev) -{ - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; - - ieee80211_configure_filter(local); -} - int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { struct ieee80211_channel *chan, *scan_chan; @@ -310,7 +249,6 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int tmp; - skb->dev = local->mdev; skb->pkt_type = IEEE80211_TX_STATUS_MSG; skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? &local->skb_queue : &local->skb_queue_unreliable, skb); @@ -716,7 +654,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, mutex_init(&local->scan_mtx); spin_lock_init(&local->key_lock); - + spin_lock_init(&local->filter_lock); spin_lock_init(&local->queue_stop_reason_lock); INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); @@ -752,30 +690,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, } EXPORT_SYMBOL(ieee80211_alloc_hw); -static const struct net_device_ops ieee80211_master_ops = { - .ndo_start_xmit = ieee80211_master_start_xmit, - .ndo_open = ieee80211_master_open, - .ndo_stop = ieee80211_master_stop, - .ndo_set_multicast_list = ieee80211_master_set_multicast_list, - .ndo_select_queue = ieee80211_select_queue, -}; - -static void ieee80211_master_setup(struct net_device *mdev) -{ - mdev->type = ARPHRD_IEEE80211; - mdev->netdev_ops = &ieee80211_master_ops; - mdev->header_ops = &ieee80211_header_ops; - mdev->tx_queue_len = 1000; - mdev->addr_len = ETH_ALEN; -} - int ieee80211_register_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); int result; enum ieee80211_band band; - struct net_device *mdev; - struct ieee80211_master_priv *mpriv; int channels, i, j, max_bitrates; bool supp_ht; static const u32 cipher_suites[] = { @@ -874,16 +793,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (hw->queues > IEEE80211_MAX_QUEUES) hw->queues = IEEE80211_MAX_QUEUES; - mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), - "wmaster%d", ieee80211_master_setup, - hw->queues); - if (!mdev) - goto fail_mdev_alloc; - - mpriv = netdev_priv(mdev); - mpriv->local = local; - local->mdev = mdev; - local->hw.workqueue = create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); if (!local->hw.workqueue) { @@ -918,17 +827,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) } rtnl_lock(); - result = dev_alloc_name(local->mdev, local->mdev->name); - if (result < 0) - goto fail_dev; - - memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); - SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); - local->mdev->features |= NETIF_F_NETNS_LOCAL; - - result = register_netdevice(local->mdev); - if (result < 0) - goto fail_dev; result = ieee80211_init_rate_ctrl_alg(local, hw->rate_control_algorithm); @@ -981,9 +879,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ieee80211_led_exit(local); ieee80211_remove_interfaces(local); fail_rate: - unregister_netdevice(local->mdev); - local->mdev = NULL; - fail_dev: rtnl_unlock(); ieee80211_wep_free(local); fail_wep: @@ -992,9 +887,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) debugfs_hw_del(local); destroy_workqueue(local->hw.workqueue); fail_workqueue: - if (local->mdev) - free_netdev(local->mdev); - fail_mdev_alloc: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: kfree(local->int_scan_req.channels); @@ -1019,13 +911,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) * because the driver cannot be handing us frames any * more and the tasklet is killed. */ - - /* First, we remove all virtual interfaces. */ ieee80211_remove_interfaces(local); - /* then, finally, remove the master interface */ - unregister_netdevice(local->mdev); - rtnl_unlock(); ieee80211_clear_tx_pending(local); @@ -1044,7 +931,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); ieee80211_led_exit(local); - free_netdev(local->mdev); kfree(local->int_scan_req.channels); } EXPORT_SYMBOL(ieee80211_unregister_hw); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 8ac7a98..b33efc4 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -287,7 +287,7 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, struct rate_control_ref *ref, *old; ASSERT_RTNL(); - if (local->open_count || netif_running(local->mdev)) + if (local->open_count) return -EBUSY; ref = rate_control_alloc(name, local); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b513fb7..7f33f77 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1478,6 +1478,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) struct ieee80211s_hdr *mesh_hdr; unsigned int hdrlen; struct sk_buff *skb = rx->skb, *fwd_skb; + struct ieee80211_local *local = rx->local; hdr = (struct ieee80211_hdr *) skb->data; hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -1520,6 +1521,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) dropped_frames_ttl); else { struct ieee80211_hdr *fwd_hdr; + struct ieee80211_tx_info *info; + fwd_skb = skb_copy(skb, GFP_ATOMIC); if (!fwd_skb && net_ratelimit()) @@ -1533,9 +1536,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) */ memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN); memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN); - fwd_skb->dev = rx->local->mdev; + info = IEEE80211_SKB_CB(fwd_skb); + memset(info, 0, sizeof(*info)); + info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; fwd_skb->iif = rx->dev->ifindex; - dev_queue_xmit(fwd_skb); + ieee80211_select_queue(local, fwd_skb); + ieee80211_add_pending_skb(local, fwd_skb); } } @@ -1803,8 +1809,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; } -static void ieee80211_rx_michael_mic_report(struct net_device *dev, - struct ieee80211_hdr *hdr, +static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, struct ieee80211_rx_data *rx) { int keyidx; @@ -2114,7 +2119,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, } if ((status->flag & RX_FLAG_MMIC_ERROR)) { - ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); + ieee80211_rx_michael_mic_report(hdr, &rx); return; } @@ -2483,7 +2488,6 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb) BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb)); - skb->dev = local->mdev; skb->pkt_type = IEEE80211_RX_MSG; skb_queue_tail(&local->skb_queue, skb); tasklet_schedule(&local->tasklet); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 5f4f786..7482065 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -294,16 +294,13 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (was_hw_scan) goto done; - netif_tx_lock_bh(local->mdev); - netif_addr_lock(local->mdev); + spin_lock_bh(&local->filter_lock); local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, &local->filter_flags, - local->mdev->mc_count, - local->mdev->mc_list); - - netif_addr_unlock(local->mdev); - netif_tx_unlock_bh(local->mdev); + local->mc_count, + local->mc_list); + spin_unlock_bh(&local->filter_lock); drv_sw_scan_complete(local); @@ -382,13 +379,13 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) local->scan_state = SCAN_SET_CHANNEL; local->scan_channel_idx = 0; - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, &local->filter_flags, - local->mdev->mc_count, - local->mdev->mc_list); - netif_addr_unlock_bh(local->mdev); + local->mc_count, + local->mc_list); + spin_unlock_bh(&local->filter_lock); /* TODO: start scan as soon as all nullfunc frames are ACKed */ queue_delayed_work(local->hw.workqueue, &local->scan_work, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f3efd4f..7adaeb2 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -451,7 +451,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; - if (unlikely(tx->skb->do_not_encrypt)) + if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) tx->key = NULL; else if (tx->sta && (key = rcu_dereference(tx->sta->key))) tx->key = key; @@ -497,7 +497,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) } if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - tx->skb->do_not_encrypt = 1; + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; return TX_CONTINUE; } @@ -774,9 +774,7 @@ static int ieee80211_fragment(struct ieee80211_local *local, memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); skb_copy_queue_mapping(tmp, skb); tmp->priority = skb->priority; - tmp->do_not_encrypt = skb->do_not_encrypt; tmp->dev = skb->dev; - tmp->iif = skb->iif; /* copy header and data */ memcpy(skb_put(tmp, hdrlen), skb->data, hdrlen); @@ -804,7 +802,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) /* * Warn when submitting a fragmented A-MPDU frame and drop it. - * This scenario is handled in __ieee80211_tx_prepare but extra + * This scenario is handled in ieee80211_tx_prepare but extra * caution taken here as fragmented ampdu may cause Tx stop. */ if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU)) @@ -943,11 +941,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, struct ieee80211_radiotap_header *rthdr = (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); sband = tx->local->hw.wiphy->bands[tx->channel->band]; - skb->do_not_encrypt = 1; + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; tx->flags &= ~IEEE80211_TX_FRAGMENTED; /* @@ -985,7 +984,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, skb_trim(skb, skb->len - FCS_LEN); } if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) - tx->skb->do_not_encrypt = 0; + info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT; if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) tx->flags |= IEEE80211_TX_FRAGMENTED; break; @@ -1018,13 +1017,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, * initialises @tx */ static ieee80211_tx_result -__ieee80211_tx_prepare(struct ieee80211_tx_data *tx, - struct sk_buff *skb, - struct net_device *dev) +ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, + struct ieee80211_tx_data *tx, + struct sk_buff *skb) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_local *local = sdata->local; struct ieee80211_hdr *hdr; - struct ieee80211_sub_if_data *sdata; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int hdrlen, tid; u8 *qc, *state; @@ -1032,9 +1030,9 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, memset(tx, 0, sizeof(*tx)); tx->skb = skb; - tx->dev = dev; /* use original interface */ + tx->dev = sdata->dev; /* use original interface */ tx->local = local; - tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); + tx->sdata = sdata; tx->channel = local->hw.conf.channel; /* * Set this flag (used below to indicate "automatic fragmentation"), @@ -1043,7 +1041,6 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, tx->flags |= IEEE80211_TX_FRAGMENTED; /* process and remove the injection radiotap header */ - sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) { if (!__ieee80211_parse_tx_radiotap(tx, skb)) return TX_DROP; @@ -1139,50 +1136,28 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, return TX_CONTINUE; } -/* - * NB: @tx is uninitialised when passed in here - */ -static int ieee80211_tx_prepare(struct ieee80211_local *local, - struct ieee80211_tx_data *tx, - struct sk_buff *skb) -{ - struct net_device *dev; - - dev = dev_get_by_index(&init_net, skb->iif); - if (unlikely(dev && !is_ieee80211_device(local, dev))) { - dev_put(dev); - dev = NULL; - } - if (unlikely(!dev)) - return -ENODEV; - /* - * initialises tx with control - * - * return value is safe to ignore here because this function - * can only be invoked for multicast frames - * - * XXX: clean up - */ - __ieee80211_tx_prepare(tx, skb, dev); - dev_put(dev); - return 0; -} - static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, - struct sta_info *sta) + struct sta_info *sta, + bool txpending) { struct sk_buff *skb = *skbp, *next; struct ieee80211_tx_info *info; + unsigned long flags; int ret, len; bool fragm = false; - local->mdev->trans_start = jiffies; - while (skb) { - if (ieee80211_queue_stopped(&local->hw, - skb_get_queue_mapping(skb))) - return IEEE80211_TX_PENDING; + int q = skb_get_queue_mapping(skb); + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + ret = IEEE80211_TX_OK; + if (local->queue_stop_reasons[q] || + (!txpending && !skb_queue_empty(&local->pending[q]))) + ret = IEEE80211_TX_PENDING; + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + if (ret != IEEE80211_TX_OK) + return ret; info = IEEE80211_SKB_CB(skb); @@ -1254,10 +1229,10 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) return 0; } -static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, - bool txpending) +static void ieee80211_tx(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, bool txpending) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_local *local = sdata->local; struct ieee80211_tx_data tx; ieee80211_tx_result res_prepare; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -1268,8 +1243,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, queue = skb_get_queue_mapping(skb); - WARN_ON(!txpending && !skb_queue_empty(&local->pending[queue])); - if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); return; @@ -1278,7 +1251,7 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); /* initialises tx */ - res_prepare = __ieee80211_tx_prepare(&tx, skb, dev); + res_prepare = ieee80211_tx_prepare(sdata, &tx, skb); if (unlikely(res_prepare == TX_DROP)) { dev_kfree_skb(skb); @@ -1297,7 +1270,7 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, retries = 0; retry: - ret = __ieee80211_tx(local, &tx.skb, tx.sta); + ret = __ieee80211_tx(local, &tx.skb, tx.sta, txpending); switch (ret) { case IEEE80211_TX_OK: break; @@ -1315,34 +1288,35 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - if (__netif_subqueue_stopped(local->mdev, queue)) { + if (local->queue_stop_reasons[queue] || + !skb_queue_empty(&local->pending[queue])) { + /* + * if queue is stopped, queue up frames for later + * transmission from the tasklet + */ do { next = skb->next; skb->next = NULL; if (unlikely(txpending)) - skb_queue_head(&local->pending[queue], - skb); + __skb_queue_head(&local->pending[queue], + skb); else - skb_queue_tail(&local->pending[queue], - skb); + __skb_queue_tail(&local->pending[queue], + skb); } while ((skb = next)); - /* - * Make sure nobody will enable the queue on us - * (without going through the tasklet) nor disable the - * netdev queue underneath the pending handling code. - */ - __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING, - &local->queue_stop_reasons[queue]); - spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } else { + /* + * otherwise retry, but this is a race condition or + * a driver bug (which we warn about if it persists) + */ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); retries++; - if (WARN(retries > 10, "tx refused but queue active")) + if (WARN(retries > 10, "tx refused but queue active\n")) goto drop; goto retry; } @@ -1403,14 +1377,13 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, return 0; } -int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) +static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) { - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; + struct ieee80211_local *local = sdata->local; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct net_device *odev = NULL; - struct ieee80211_sub_if_data *osdata; + struct ieee80211_sub_if_data *tmp_sdata; int headroom; bool may_encrypt; enum { @@ -1419,20 +1392,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) UNKNOWN_ADDRESS, } monitor_iface = NOT_MONITOR; - if (skb->iif) - odev = dev_get_by_index(&init_net, skb->iif); - if (unlikely(odev && !is_ieee80211_device(local, odev))) { - dev_put(odev); - odev = NULL; - } - if (unlikely(!odev)) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Discarded packet with nonexistent " - "originating device\n", dev->name); -#endif - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } + dev_hold(sdata->dev); if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && local->hw.conf.dynamic_ps_timeout > 0 && @@ -1448,26 +1408,21 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); } - memset(info, 0, sizeof(*info)); - info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - osdata = IEEE80211_DEV_TO_SUB_IF(odev); - - if (ieee80211_vif_is_mesh(&osdata->vif) && + if (ieee80211_vif_is_mesh(&sdata->vif) && ieee80211_is_data(hdr->frame_control)) { if (is_multicast_ether_addr(hdr->addr3)) memcpy(hdr->addr1, hdr->addr3, ETH_ALEN); else - if (mesh_nexthop_lookup(skb, osdata)) { - dev_put(odev); - return NETDEV_TX_OK; + if (mesh_nexthop_lookup(skb, sdata)) { + dev_put(sdata->dev); + return; } - if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0) - IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh, - fwded_frames); - } else if (unlikely(osdata->vif.type == NL80211_IFTYPE_MONITOR)) { - struct ieee80211_sub_if_data *sdata; + if (memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) != 0) + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, + fwded_frames); + } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { int hdrlen; u16 len_rthdr; @@ -1491,19 +1446,17 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) */ rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, + list_for_each_entry_rcu(tmp_sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!netif_running(tmp_sdata->dev)) continue; - if (sdata->vif.type != NL80211_IFTYPE_AP) + if (tmp_sdata->vif.type != NL80211_IFTYPE_AP) continue; - if (compare_ether_addr(sdata->dev->dev_addr, + if (compare_ether_addr(tmp_sdata->dev->dev_addr, hdr->addr2)) { - dev_hold(sdata->dev); - dev_put(odev); - osdata = sdata; - odev = osdata->dev; - skb->iif = sdata->dev->ifindex; + dev_hold(tmp_sdata->dev); + dev_put(sdata->dev); + sdata = tmp_sdata; monitor_iface = FOUND_SDATA; break; } @@ -1512,31 +1465,31 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) } } - may_encrypt = !skb->do_not_encrypt; + may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT); - headroom = osdata->local->tx_headroom; + headroom = local->tx_headroom; if (may_encrypt) headroom += IEEE80211_ENCRYPT_HEADROOM; headroom -= skb_headroom(skb); headroom = max_t(int, 0, headroom); - if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) { + if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) { dev_kfree_skb(skb); - dev_put(odev); - return NETDEV_TX_OK; + dev_put(sdata->dev); + return; } - if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN) - osdata = container_of(osdata->bss, - struct ieee80211_sub_if_data, - u.ap); + tmp_sdata = sdata; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + tmp_sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, + u.ap); if (likely(monitor_iface != UNKNOWN_ADDRESS)) - info->control.vif = &osdata->vif; - - ieee80211_tx(odev, skb, false); - dev_put(odev); + info->control.vif = &tmp_sdata->vif; - return NETDEV_TX_OK; + ieee80211_select_queue(local, skb); + ieee80211_tx(sdata, skb, false); + dev_put(sdata->dev); } int ieee80211_monitor_start_xmit(struct sk_buff *skb, @@ -1546,6 +1499,7 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct ieee80211_channel *chan = local->hw.conf.channel; struct ieee80211_radiotap_header *prthdr = (struct ieee80211_radiotap_header *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u16 len_rthdr; /* @@ -1583,15 +1537,9 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, if (unlikely(skb->len < len_rthdr)) goto fail; /* skb too short for claimed rt header extent */ - skb->dev = local->mdev; - /* needed because we set skb device to master */ skb->iif = dev->ifindex; - /* sometimes we do encrypt injected frames, will be fixed - * up in radiotap parser if not wanted */ - skb->do_not_encrypt = 0; - /* * fix up the pointers accounting for the radiotap * header still being in there. We are being given @@ -1606,8 +1554,10 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, skb_set_network_header(skb, len_rthdr); skb_set_transport_header(skb, len_rthdr); - /* pass the radiotap header up to the next stage intact */ - dev_queue_xmit(skb); + memset(info, 0, sizeof(*info)); + + /* pass the radiotap header up to xmit */ + ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb); return NETDEV_TX_OK; fail: @@ -1635,6 +1585,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret = NETDEV_TX_BUSY, head_need; u16 ethertype, hdrlen, meshhdrlen = 0; __le16 fc; @@ -1864,7 +1815,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, skb->iif = dev->ifindex; - skb->dev = local->mdev; dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; @@ -1875,8 +1825,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, skb_set_network_header(skb, nh_pos); skb_set_transport_header(skb, h_pos); + memset(info, 0, sizeof(*info)); + dev->trans_start = jiffies; - dev_queue_xmit(skb); + ieee80211_xmit(sdata, skb); return NETDEV_TX_OK; @@ -1918,7 +1870,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, return true; } - /* validate info->control.vif against skb->iif */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, @@ -1932,12 +1883,13 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, } if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { - ieee80211_tx(dev, skb, true); + /* do not use sdata, it may have been changed above */ + ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true); } else { hdr = (struct ieee80211_hdr *)skb->data; sta = sta_info_get(local, hdr->addr1); - ret = __ieee80211_tx(local, &skb, sta); + ret = __ieee80211_tx(local, &skb, sta, true); if (ret != IEEE80211_TX_OK) result = false; } @@ -1949,59 +1901,43 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, } /* - * Transmit all pending packets. Called from tasklet, locks master device - * TX lock so that no new packets can come in. + * Transmit all pending packets. Called from tasklet. */ void ieee80211_tx_pending(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *)data; - struct net_device *dev = local->mdev; unsigned long flags; int i; - bool next; + bool txok; rcu_read_lock(); - netif_tx_lock_bh(dev); + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); for (i = 0; i < local->hw.queues; i++) { /* * If queue is stopped by something other than due to pending * frames, or we have no pending frames, proceed to next queue. */ - spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - next = false; - if (local->queue_stop_reasons[i] != - BIT(IEEE80211_QUEUE_STOP_REASON_PENDING) || + if (local->queue_stop_reasons[i] || skb_queue_empty(&local->pending[i])) - next = true; - spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); - - if (next) continue; - /* - * start the queue now to allow processing our packets, - * we're under the tx lock here anyway so nothing will - * happen as a result of this - */ - netif_start_subqueue(local->mdev, i); - while (!skb_queue_empty(&local->pending[i])) { - struct sk_buff *skb = skb_dequeue(&local->pending[i]); - - if (!ieee80211_tx_pending_skb(local, skb)) { - skb_queue_head(&local->pending[i], skb); + struct sk_buff *skb = __skb_dequeue(&local->pending[i]); + spin_unlock_irqrestore(&local->queue_stop_reason_lock, + flags); + + txok = ieee80211_tx_pending_skb(local, skb); + if (!txok) + __skb_queue_head(&local->pending[i], skb); + spin_lock_irqsave(&local->queue_stop_reason_lock, + flags); + if (!txok) break; - } } - - /* Start regular packet processing again. */ - if (skb_queue_empty(&local->pending[i])) - ieee80211_wake_queue_by_reason(&local->hw, i, - IEEE80211_QUEUE_STOP_REASON_PENDING); } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); - netif_tx_unlock_bh(dev); rcu_read_unlock(); } @@ -2176,8 +2112,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); - skb->do_not_encrypt = 1; - + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; info->band = band; /* * XXX: For now, always use the lowest rate @@ -2248,9 +2183,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, sdata = vif_to_sdata(vif); bss = &sdata->u.ap; - if (!bss) - return NULL; - rcu_read_lock(); beacon = rcu_dereference(bss->beacon); @@ -2276,7 +2208,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, cpu_to_le16(IEEE80211_FCTL_MOREDATA); } - if (!ieee80211_tx_prepare(local, &tx, skb)) + if (!ieee80211_tx_prepare(sdata, &tx, skb)) break; dev_kfree_skb_any(skb); } @@ -2296,3 +2228,18 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, return skb; } EXPORT_SYMBOL(ieee80211_get_buffered_bc); + +void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, + int encrypt) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + skb_set_mac_header(skb, 0); + skb_set_network_header(skb, 0); + skb_set_transport_header(skb, 0); + + skb->iif = sdata->dev->ifindex; + if (!encrypt) + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + + ieee80211_xmit(sdata, skb); +} diff --git a/net/mac80211/util.c b/net/mac80211/util.c index dbf66b5..7fc5584 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -275,16 +275,12 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, __clear_bit(reason, &local->queue_stop_reasons[queue]); - if (!skb_queue_empty(&local->pending[queue]) && - local->queue_stop_reasons[queue] == - BIT(IEEE80211_QUEUE_STOP_REASON_PENDING)) - tasklet_schedule(&local->tx_pending_tasklet); - if (local->queue_stop_reasons[queue] != 0) /* someone still has this queue stopped */ return; - netif_wake_subqueue(local->mdev, queue); + if (!skb_queue_empty(&local->pending[queue])) + tasklet_schedule(&local->tx_pending_tasklet); } void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, @@ -313,14 +309,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, if (WARN_ON(queue >= hw->queues)) return; - /* - * Only stop if it was previously running, this is necessary - * for correct pending packets handling because there we may - * start (but not wake) the queue and rely on that. - */ - if (!local->queue_stop_reasons[queue]) - netif_stop_subqueue(local->mdev, queue); - __set_bit(reason, &local->queue_stop_reasons[queue]); } @@ -351,8 +339,7 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, spin_lock_irqsave(&local->queue_stop_reason_lock, flags); __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); - __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING); - skb_queue_tail(&local->pending[queue], skb); + __skb_queue_tail(&local->pending[queue], skb); __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } @@ -373,16 +360,12 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, while ((skb = skb_dequeue(skbs))) { ret++; queue = skb_get_queue_mapping(skb); - skb_queue_tail(&local->pending[queue], skb); + __skb_queue_tail(&local->pending[queue], skb); } - for (i = 0; i < hw->queues; i++) { - if (ret) - __ieee80211_stop_queue(hw, i, - IEEE80211_QUEUE_STOP_REASON_PENDING); + for (i = 0; i < hw->queues; i++) __ieee80211_wake_queue(hw, i, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); - } spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); return ret; @@ -413,11 +396,16 @@ EXPORT_SYMBOL(ieee80211_stop_queues); int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); + unsigned long flags; + int ret; if (WARN_ON(queue >= hw->queues)) return true; - return __netif_subqueue_stopped(local->mdev, queue); + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + ret = !!local->queue_stop_reasons[queue]; + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + return ret; } EXPORT_SYMBOL(ieee80211_queue_stopped); @@ -761,20 +749,6 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, ieee80211_set_wmm_default(sdata); } -void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - int encrypt) -{ - skb->dev = sdata->local->mdev; - skb_set_mac_header(skb, 0); - skb_set_network_header(skb, 0); - skb_set_transport_header(skb, 0); - - skb->iif = sdata->dev->ifindex; - skb->do_not_encrypt = !encrypt; - - dev_queue_xmit(skb); -} - u32 ieee80211_mandatory_rates(struct ieee80211_local *local, enum ieee80211_band band) { @@ -1049,9 +1023,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* reconfigure hardware */ ieee80211_hw_config(local, ~0); - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); + spin_unlock_bh(&local->filter_lock); /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 116a923..b19b769 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -85,10 +85,8 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) return ieee802_1d_to_ac[skb->priority]; } -u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) +void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb) { - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 queue; u8 tid; @@ -113,5 +111,5 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) *p = 0; } - return queue; + skb_set_queue_mapping(skb, queue); } diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index 7520d2e..d4fd87c 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -20,6 +20,7 @@ extern const int ieee802_1d_to_ac[8]; -u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb); +void ieee80211_select_queue(struct ieee80211_local *local, + struct sk_buff *skb); #endif /* _WME_H */ -- cgit v0.10.2 From 72bce62775db0315511474e8d8f8e25d25b48366 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2009 17:45:28 +0200 Subject: net: remove unused skb->do_not_encrypt mac80211 required this due to the master netdev, but now it can put all information into skb->cb and this can go. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f2c69a2..df7b23a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -304,7 +304,6 @@ typedef unsigned char *sk_buff_data_t; * @tc_index: Traffic control index * @tc_verd: traffic control verdict * @ndisc_nodetype: router type (from link layer) - * @do_not_encrypt: set to prevent encryption of this frame * @dma_cookie: a cookie to one of several possible DMA operations * done by skb DMA functions * @secmark: security marking @@ -380,12 +379,9 @@ struct sk_buff { #ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; #endif -#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) - __u8 do_not_encrypt:1; -#endif kmemcheck_bitfield_end(flags2); - /* 0/13/14 bit hole */ + /* 0/14 bit hole */ #ifdef CONFIG_NET_DMA dma_cookie_t dma_cookie; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 9e0597d..80a9616 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -559,9 +559,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) #endif #endif new->vlan_tci = old->vlan_tci; -#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) - new->do_not_encrypt = old->do_not_encrypt; -#endif skb_copy_secmark(new, old); } -- cgit v0.10.2 From 3d34deb6737b1ae1f8b7817b57d603807f5d88ea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 18 Jun 2009 17:25:11 +0200 Subject: mac80211: fix ieee80211_xmit call context ieee80211_xmit() cannot be called with tasklets enabled because it is normally called from within a tasklet. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7adaeb2..a204092 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2241,5 +2241,12 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, if (!encrypt) info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + /* + * The other path calling ieee80211_xmit is from the tasklet, + * and while we can handle concurrent transmissions locking + * requirements are that we do not come into tx with bhs on. + */ + local_bh_disable(); ieee80211_xmit(sdata, skb); + local_bh_enable(); } -- cgit v0.10.2 From 249b405cf8145da8a74b70544ae1079d244bdb00 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 7 Jul 2009 10:55:03 -0700 Subject: mac80211: Fix regression in mesh forwarding path. The removal of the master netdev broke the mesh forwarding path. This patch fixes it by using the new internal 'pending' queue. As a result of this change, mesh forwarding no longer does the inefficient 802.11 -> 802.3 -> 802.11 conversion that was done before. [Changes since v1] Suggested by Johannes: - Select queue before adding to mpath queue - ieee80211_add_pending_skb -> ieee80211_add_pending_skbs - Remove unnecessary header wme.h Signed-off-by: Javier Cardona Signed-off-by: Andrey Yurovsky Reviewed-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 8e86e91..e93c37e 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -784,7 +784,6 @@ int mesh_nexthop_lookup(struct sk_buff *skb, mesh_path_add(dst_addr, sdata); mpath = mesh_path_lookup(dst_addr, sdata); if (!mpath) { - dev_kfree_skb(skb); sdata->u.mesh.mshstats.dropped_frames_no_route++; err = -ENOSPC; goto endlookup; @@ -804,6 +803,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, memcpy(hdr->addr1, mpath->next_hop->sta.addr, ETH_ALEN); } else { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!(mpath->flags & MESH_PATH_RESOLVING)) { /* Start discovery only if it is not running yet */ mesh_queue_preq(mpath, PREQ_Q_F_START); @@ -815,6 +815,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, skb_unlink(skb_to_free, &mpath->frame_queue); } + info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; skb_queue_tail(&mpath->frame_queue, skb); if (skb_to_free) mesh_path_discard_frame(skb_to_free, sdata); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index f0304bf..04b9e4d 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -499,11 +499,9 @@ enddel: */ void mesh_path_tx_pending(struct mesh_path *mpath) { - struct sk_buff *skb; - - while ((skb = skb_dequeue(&mpath->frame_queue)) && - (mpath->flags & MESH_PATH_ACTIVE)) - dev_queue_xmit(skb); + if (mpath->flags & MESH_PATH_ACTIVE) + ieee80211_add_pending_skbs(mpath->sdata->local, + &mpath->frame_queue); } /** diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7f33f77..66c797c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1479,10 +1479,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) unsigned int hdrlen; struct sk_buff *skb = rx->skb, *fwd_skb; struct ieee80211_local *local = rx->local; + struct ieee80211_sub_if_data *sdata; hdr = (struct ieee80211_hdr *) skb->data; hdrlen = ieee80211_hdrlen(hdr->frame_control); mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); + sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); if (!ieee80211_is_data(hdr->frame_control)) return RX_CONTINUE; @@ -1492,10 +1494,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){ - struct ieee80211_sub_if_data *sdata; struct mesh_path *mppath; - sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); rcu_read_lock(); mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata); if (!mppath) { @@ -1541,6 +1541,19 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; fwd_skb->iif = rx->dev->ifindex; ieee80211_select_queue(local, fwd_skb); + if (is_multicast_ether_addr(fwd_hdr->addr3)) + memcpy(fwd_hdr->addr1, fwd_hdr->addr3, + ETH_ALEN); + else { + int err = mesh_nexthop_lookup(fwd_skb, sdata); + /* Failed to immediately resolve next hop: + * fwded frame was dropped or will be added + * later to the pending skb queue. */ + if (err) + return RX_DROP_MONITOR; + } + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, + fwded_frames); ieee80211_add_pending_skb(local, fwd_skb); } } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a204092..2572509 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1419,9 +1419,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, dev_put(sdata->dev); return; } - if (memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) != 0) - IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, - fwded_frames); } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { int hdrlen; u16 len_rthdr; -- cgit v0.10.2 From cb3824bade2549d7ad059d5802da43312540fdee Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 14:21:12 +0200 Subject: ISDN: Make isdnhdlc usable for other ISDN drivers isdnhdlc is useful for other ISDN drivers as well. Move the include file to a central location and the source to the central isdn location. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index 02bdca6..022a194 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig @@ -21,8 +21,6 @@ menuconfig ISDN if ISDN -source "drivers/isdn/mISDN/Kconfig" - menuconfig ISDN_I4L tristate "Old ISDN4Linux (deprecated)" ---help--- @@ -41,9 +39,9 @@ menuconfig ISDN_I4L It is still available, though, for use with adapters that are not supported by the new CAPI subsystem yet. -if ISDN_I4L +source "drivers/isdn/mISDN/Kconfig" + source "drivers/isdn/i4l/Kconfig" -endif menuconfig ISDN_CAPI tristate "CAPI 2.0 subsystem" diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig index 7832d8b..3464ebc 100644 --- a/drivers/isdn/hisax/Kconfig +++ b/drivers/isdn/hisax/Kconfig @@ -391,6 +391,7 @@ comment "HiSax sub driver modules" config HISAX_ST5481 tristate "ST5481 USB ISDN modem (EXPERIMENTAL)" depends on USB && EXPERIMENTAL + select ISDN_HDLC select CRC_CCITT select BITREVERSE help @@ -418,11 +419,6 @@ config HISAX_FRITZ_PCIPNP (the latter also needs you to select "ISA Plug and Play support" from the menu "Plug and Play configuration") -config HISAX_HDLC - bool - depends on HISAX_ST5481 - default y - config HISAX_AVM_A1_PCMCIA bool depends on HISAX_AVM_A1_CS diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile index c7a3794..ab638b08 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile @@ -16,10 +16,6 @@ obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o -ifdef CONFIG_HISAX_HDLC -obj-$(CONFIG_ISDN_DRV_HISAX) += isdnhdlc.o -endif - # Multipart objects. hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \ diff --git a/drivers/isdn/hisax/isdnhdlc.c b/drivers/isdn/hisax/isdnhdlc.c deleted file mode 100644 index c69a77a..0000000 --- a/drivers/isdn/hisax/isdnhdlc.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - * isdnhdlc.c -- General purpose ISDN HDLC decoder. - * - *Copyright (C) 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski - * - * 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 "isdnhdlc.h" - -/*-------------------------------------------------------------------*/ - -MODULE_AUTHOR("Wolfgang Mües , " - "Frode Isaksen , " - "Kai Germaschewski "); -MODULE_DESCRIPTION("General purpose ISDN HDLC decoder"); -MODULE_LICENSE("GPL"); - -/*-------------------------------------------------------------------*/ - -enum { - HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7, - HDLC_GET_DATA,HDLC_FAST_FLAG -}; - -enum { - HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG, - HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG, - HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0, - HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED -}; - -void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) -{ - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; - hdlc->state = HDLC_GET_DATA; - hdlc->do_adapt56 = do_adapt56; - hdlc->dchannel = 0; - hdlc->crc = 0; - hdlc->cbin = 0; - hdlc->shift_reg = 0; - hdlc->ffvalue = 0; - hdlc->dstpos = 0; -} - -void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56) -{ - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; - hdlc->do_closing = 0; - hdlc->ffvalue = 0; - if (is_d_channel) { - hdlc->dchannel = 1; - hdlc->state = HDLC_SEND_FIRST_FLAG; - } else { - hdlc->dchannel = 0; - hdlc->state = HDLC_SEND_FAST_FLAG; - hdlc->ffvalue = 0x7e; - } - hdlc->cbin = 0x7e; - hdlc->bit_shift = 0; - if(do_adapt56){ - hdlc->do_adapt56 = 1; - hdlc->data_bits = 0; - hdlc->state = HDLC_SENDFLAG_B0; - } else { - hdlc->do_adapt56 = 0; - hdlc->data_bits = 8; - } - hdlc->shift_reg = 0; -} - -/* - isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. - - The source buffer is scanned for valid HDLC frames looking for - flags (01111110) to indicate the start of a frame. If the start of - the frame is found, the bit stuffing is removed (0 after 5 1's). - When a new flag is found, the complete frame has been received - and the CRC is checked. - If a valid frame is found, the function returns the frame length - excluding the CRC with the bit HDLC_END_OF_FRAME set. - If the beginning of a valid frame is found, the function returns - the length. - If a framing error is found (too many 1s and not a flag) the function - returns the length with the bit HDLC_FRAMING_ERROR set. - If a CRC error is found the function returns the length with the - bit HDLC_CRC_ERROR set. - If the frame length exceeds the destination buffer size, the function - returns the length with the bit HDLC_LENGTH_ERROR set. - - src - source buffer - slen - source buffer length - count - number of bytes removed (decoded) from the source buffer - dst _ destination buffer - dsize - destination buffer size - returns - number of decoded bytes in the destination buffer and status - flag. - */ -int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, - int slen, int *count, unsigned char *dst, int dsize) -{ - int status=0; - - static const unsigned char fast_flag[]={ - 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f - }; - - static const unsigned char fast_flag_value[]={ - 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f - }; - - static const unsigned char fast_abort[]={ - 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff - }; - - *count = slen; - - while(slen > 0){ - if(hdlc->bit_shift==0){ - hdlc->cbin = *src++; - slen--; - hdlc->bit_shift = 8; - if(hdlc->do_adapt56){ - hdlc->bit_shift --; - } - } - - switch(hdlc->state){ - case STOPPED: - return 0; - case HDLC_FAST_IDLE: - if(hdlc->cbin == 0xff){ - hdlc->bit_shift = 0; - break; - } - hdlc->state = HDLC_GET_FLAG_B0; - hdlc->hdlc_bits1 = 0; - hdlc->bit_shift = 8; - break; - case HDLC_GET_FLAG_B0: - if(!(hdlc->cbin & 0x80)) { - hdlc->state = HDLC_GETFLAG_B1A6; - hdlc->hdlc_bits1 = 0; - } else { - if(!hdlc->do_adapt56){ - if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) - hdlc->state = HDLC_FAST_IDLE; - } - } - hdlc->cbin<<=1; - hdlc->bit_shift --; - break; - case HDLC_GETFLAG_B1A6: - if(hdlc->cbin & 0x80){ - hdlc->hdlc_bits1++; - if(hdlc->hdlc_bits1==6){ - hdlc->state = HDLC_GETFLAG_B7; - } - } else { - hdlc->hdlc_bits1 = 0; - } - hdlc->cbin<<=1; - hdlc->bit_shift --; - break; - case HDLC_GETFLAG_B7: - if(hdlc->cbin & 0x80) { - hdlc->state = HDLC_GET_FLAG_B0; - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->crc = 0xffff; - hdlc->shift_reg = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->data_received = 0; - } - hdlc->cbin<<=1; - hdlc->bit_shift --; - break; - case HDLC_GET_DATA: - if(hdlc->cbin & 0x80){ - hdlc->hdlc_bits1++; - switch(hdlc->hdlc_bits1){ - case 6: - break; - case 7: - if(hdlc->data_received) { - // bad frame - status = -HDLC_FRAMING_ERROR; - } - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ - hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=1; - break; - } - } else { - hdlc->state = HDLC_GET_FLAG_B0; - } - break; - default: - hdlc->shift_reg>>=1; - hdlc->shift_reg |= 0x80; - hdlc->data_bits++; - break; - } - } else { - switch(hdlc->hdlc_bits1){ - case 5: - break; - case 6: - if(hdlc->data_received){ - if (hdlc->dstpos < 2) { - status = -HDLC_FRAMING_ERROR; - } else if (hdlc->crc != 0xf0b8){ - // crc error - status = -HDLC_CRC_ERROR; - } else { - // remove CRC - hdlc->dstpos -= 2; - // good frame - status = hdlc->dstpos; - } - } - hdlc->crc = 0xffff; - hdlc->shift_reg = 0; - hdlc->data_bits = 0; - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ - hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; - hdlc->state = HDLC_FAST_FLAG; - hdlc->ffbit_shift = hdlc->bit_shift; - hdlc->bit_shift = 1; - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - break; - default: - hdlc->shift_reg>>=1; - hdlc->data_bits++; - break; - } - hdlc->hdlc_bits1 = 0; - } - if (status) { - hdlc->dstpos = 0; - *count -= slen; - hdlc->cbin <<= 1; - hdlc->bit_shift--; - return status; - } - if(hdlc->data_bits==8){ - hdlc->data_bits = 0; - hdlc->data_received = 1; - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); - - // good byte received - if (hdlc->dstpos < dsize) { - dst[hdlc->dstpos++] = hdlc->shift_reg; - } else { - // frame too long - status = -HDLC_LENGTH_ERROR; - hdlc->dstpos = 0; - } - } - hdlc->cbin <<= 1; - hdlc->bit_shift--; - break; - case HDLC_FAST_FLAG: - if(hdlc->cbin==hdlc->ffvalue){ - hdlc->bit_shift = 0; - break; - } else { - if(hdlc->cbin == 0xff){ - hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=0; - } else if(hdlc->ffbit_shift==8){ - hdlc->state = HDLC_GETFLAG_B7; - break; - } else { - hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; - hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; - if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; - hdlc->data_bits = hdlc->ffbit_shift-1; - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - } - break; - default: - break; - } - } - *count -= slen; - return 0; -} - -/* - isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. - - The bit stream starts with a beginning flag (01111110). After - that each byte is added to the bit stream with bit stuffing added - (0 after 5 1's). - When the last byte has been removed from the source buffer, the - CRC (2 bytes is added) and the frame terminates with the ending flag. - For the dchannel, the idle character (all 1's) is also added at the end. - If this function is called with empty source buffer (slen=0), flags or - idle character will be generated. - - src - source buffer - slen - source buffer length - count - number of bytes removed (encoded) from source buffer - dst _ destination buffer - dsize - destination buffer size - returns - number of encoded bytes in the destination buffer -*/ -int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, - unsigned short slen, int *count, - unsigned char *dst, int dsize) -{ - static const unsigned char xfast_flag_value[] = { - 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e - }; - - int len = 0; - - *count = slen; - - while (dsize > 0) { - if(hdlc->bit_shift==0){ - if(slen && !hdlc->do_closing){ - hdlc->shift_reg = *src++; - slen--; - if (slen == 0) - hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */ - hdlc->bit_shift = 8; - } else { - if(hdlc->state == HDLC_SEND_DATA){ - if(hdlc->data_received){ - hdlc->state = HDLC_SEND_CRC1; - hdlc->crc ^= 0xffff; - hdlc->bit_shift = 8; - hdlc->shift_reg = hdlc->crc & 0xff; - } else if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; - } else { - hdlc->state = HDLC_SENDFLAG_B0; - } - } - - } - } - - switch(hdlc->state){ - case STOPPED: - while (dsize--) - *dst++ = 0xff; - - return dsize; - case HDLC_SEND_FAST_FLAG: - hdlc->do_closing = 0; - if(slen == 0){ - *dst++ = hdlc->ffvalue; - len++; - dsize--; - break; - } - if(hdlc->bit_shift==8){ - hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits); - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - hdlc->data_received = 1; - } - break; - case HDLC_SENDFLAG_B0: - hdlc->do_closing = 0; - hdlc->cbin <<= 1; - hdlc->data_bits++; - hdlc->hdlc_bits1 = 0; - hdlc->state = HDLC_SENDFLAG_B1A6; - break; - case HDLC_SENDFLAG_B1A6: - hdlc->cbin <<= 1; - hdlc->data_bits++; - hdlc->cbin++; - if(++hdlc->hdlc_bits1 == 6) - hdlc->state = HDLC_SENDFLAG_B7; - break; - case HDLC_SENDFLAG_B7: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(slen == 0){ - hdlc->state = HDLC_SENDFLAG_B0; - break; - } - if(hdlc->bit_shift==8){ - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - hdlc->data_received = 1; - } - break; - case HDLC_SEND_FIRST_FLAG: - hdlc->data_received = 1; - if(hdlc->data_bits==8){ - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - break; - } - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->shift_reg & 0x01) - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - } - break; - case HDLC_SEND_DATA: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->bit_shift==8){ - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); - } - if(hdlc->shift_reg & 0x01){ - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - break; - case HDLC_SEND_CRC1: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->shift_reg & 0x01){ - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - if(hdlc->bit_shift==0){ - hdlc->shift_reg = (hdlc->crc >> 8); - hdlc->state = HDLC_SEND_CRC2; - hdlc->bit_shift = 8; - } - break; - case HDLC_SEND_CRC2: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->shift_reg & 0x01){ - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - if(hdlc->bit_shift==0){ - hdlc->shift_reg = 0x7e; - hdlc->state = HDLC_SEND_CLOSING_FLAG; - hdlc->bit_shift = 8; - } - break; - case HDLC_SEND_CLOSING_FLAG: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->shift_reg & 0x01){ - hdlc->cbin++; - } - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->ffvalue = xfast_flag_value[hdlc->data_bits]; - if(hdlc->dchannel){ - hdlc->ffvalue = 0x7e; - hdlc->state = HDLC_SEND_IDLE1; - hdlc->bit_shift = 8-hdlc->data_bits; - if(hdlc->bit_shift==0) - hdlc->state = HDLC_SEND_FAST_IDLE; - } else { - if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; - hdlc->data_received = 0; - } else { - hdlc->state = HDLC_SENDFLAG_B0; - hdlc->data_received = 0; - } - // Finished with this frame, send flags - if (dsize > 1) dsize = 1; - } - } - break; - case HDLC_SEND_IDLE1: - hdlc->do_closing = 0; - hdlc->cbin <<= 1; - hdlc->cbin++; - hdlc->data_bits++; - hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->state = HDLC_SEND_FAST_IDLE; - hdlc->bit_shift = 0; - } - break; - case HDLC_SEND_FAST_IDLE: - hdlc->do_closing = 0; - hdlc->cbin = 0xff; - hdlc->data_bits = 8; - if(hdlc->bit_shift == 8){ - hdlc->cbin = 0x7e; - hdlc->state = HDLC_SEND_FIRST_FLAG; - } else { - *dst++ = hdlc->cbin; - hdlc->bit_shift = hdlc->data_bits = 0; - len++; - dsize = 0; - } - break; - default: - break; - } - if(hdlc->do_adapt56){ - if(hdlc->data_bits==7){ - hdlc->cbin <<= 1; - hdlc->cbin++; - hdlc->data_bits++; - } - } - if(hdlc->data_bits==8){ - *dst++ = hdlc->cbin; - hdlc->data_bits = 0; - len++; - dsize--; - } - } - *count -= slen; - - return len; -} - -EXPORT_SYMBOL(isdnhdlc_rcv_init); -EXPORT_SYMBOL(isdnhdlc_decode); -EXPORT_SYMBOL(isdnhdlc_out_init); -EXPORT_SYMBOL(isdnhdlc_encode); diff --git a/drivers/isdn/hisax/isdnhdlc.h b/drivers/isdn/hisax/isdnhdlc.h deleted file mode 100644 index cf0a95a..0000000 --- a/drivers/isdn/hisax/isdnhdlc.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * isdnhdlc.h -- General purpose ISDN HDLC decoder. - * - * Implementation of a HDLC decoder/encoder in software. - * Neccessary because some ISDN devices don't have HDLC - * controllers. Also included: a bit reversal table. - * - *Copyright (C) 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski - * - * 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 __ISDNHDLC_H__ -#define __ISDNHDLC_H__ - -struct isdnhdlc_vars { - int bit_shift; - int hdlc_bits1; - int data_bits; - int ffbit_shift; // encoding only - int state; - int dstpos; - - unsigned short crc; - - unsigned char cbin; - unsigned char shift_reg; - unsigned char ffvalue; - - unsigned int data_received:1; // set if transferring data - unsigned int dchannel:1; // set if D channel (send idle instead of flags) - unsigned int do_adapt56:1; // set if 56K adaptation - unsigned int do_closing:1; // set if in closing phase (need to send CRC + flag -}; - - -/* - The return value from isdnhdlc_decode is - the frame length, 0 if no complete frame was decoded, - or a negative error number -*/ -#define HDLC_FRAMING_ERROR 1 -#define HDLC_CRC_ERROR 2 -#define HDLC_LENGTH_ERROR 3 - -extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56); - -extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count, - unsigned char *dst, int dsize); - -extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56); - -extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count, - unsigned char *dst,int dsize); - -#endif /* __ISDNHDLC_H__ */ diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h index cff7a63..64f78a8 100644 --- a/drivers/isdn/hisax/st5481.h +++ b/drivers/isdn/hisax/st5481.h @@ -226,7 +226,7 @@ printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) #define INFO(format, arg...) \ printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) -#include "isdnhdlc.h" +#include #include "fsm.h" #include "hisax_if.h" #include diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig index ed3510f..dd744ff 100644 --- a/drivers/isdn/i4l/Kconfig +++ b/drivers/isdn/i4l/Kconfig @@ -2,6 +2,8 @@ # Old ISDN4Linux config # +if ISDN_I4L + config ISDN_PPP bool "Support synchronous PPP" depends on INET @@ -135,3 +137,12 @@ source "drivers/isdn/act2000/Kconfig" source "drivers/isdn/hysdn/Kconfig" endmenu +# end ISDN_I4L +endif + +config ISDN_HDLC + tristate + depends on HISAX_ST5481 + select CRC_CCITT + select BITREVERSE + diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile index 49a06c0..cb9d3bb 100644 --- a/drivers/isdn/i4l/Makefile +++ b/drivers/isdn/i4l/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_ISDN_I4L) += isdn.o obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o +obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o # Multipart objects. diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c new file mode 100644 index 0000000..44ec741 --- /dev/null +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -0,0 +1,603 @@ +/* + * isdnhdlc.c -- General purpose ISDN HDLC decoder. + * + *Copyright (C) 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski + * + * 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 + +/*-------------------------------------------------------------------*/ + +MODULE_AUTHOR("Wolfgang Mües , " + "Frode Isaksen , " + "Kai Germaschewski "); +MODULE_DESCRIPTION("General purpose ISDN HDLC decoder"); +MODULE_LICENSE("GPL"); + +/*-------------------------------------------------------------------*/ + +enum { + HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7, + HDLC_GET_DATA,HDLC_FAST_FLAG +}; + +enum { + HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG, + HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG, + HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0, + HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED +}; + +void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) +{ + hdlc->bit_shift = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->ffbit_shift = 0; + hdlc->data_received = 0; + hdlc->state = HDLC_GET_DATA; + hdlc->do_adapt56 = do_adapt56; + hdlc->dchannel = 0; + hdlc->crc = 0; + hdlc->cbin = 0; + hdlc->shift_reg = 0; + hdlc->ffvalue = 0; + hdlc->dstpos = 0; +} + +void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56) +{ + hdlc->bit_shift = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->ffbit_shift = 0; + hdlc->data_received = 0; + hdlc->do_closing = 0; + hdlc->ffvalue = 0; + if (is_d_channel) { + hdlc->dchannel = 1; + hdlc->state = HDLC_SEND_FIRST_FLAG; + } else { + hdlc->dchannel = 0; + hdlc->state = HDLC_SEND_FAST_FLAG; + hdlc->ffvalue = 0x7e; + } + hdlc->cbin = 0x7e; + hdlc->bit_shift = 0; + if(do_adapt56){ + hdlc->do_adapt56 = 1; + hdlc->data_bits = 0; + hdlc->state = HDLC_SENDFLAG_B0; + } else { + hdlc->do_adapt56 = 0; + hdlc->data_bits = 8; + } + hdlc->shift_reg = 0; +} + +/* + isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. + + The source buffer is scanned for valid HDLC frames looking for + flags (01111110) to indicate the start of a frame. If the start of + the frame is found, the bit stuffing is removed (0 after 5 1's). + When a new flag is found, the complete frame has been received + and the CRC is checked. + If a valid frame is found, the function returns the frame length + excluding the CRC with the bit HDLC_END_OF_FRAME set. + If the beginning of a valid frame is found, the function returns + the length. + If a framing error is found (too many 1s and not a flag) the function + returns the length with the bit HDLC_FRAMING_ERROR set. + If a CRC error is found the function returns the length with the + bit HDLC_CRC_ERROR set. + If the frame length exceeds the destination buffer size, the function + returns the length with the bit HDLC_LENGTH_ERROR set. + + src - source buffer + slen - source buffer length + count - number of bytes removed (decoded) from the source buffer + dst _ destination buffer + dsize - destination buffer size + returns - number of decoded bytes in the destination buffer and status + flag. + */ +int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, + int slen, int *count, unsigned char *dst, int dsize) +{ + int status=0; + + static const unsigned char fast_flag[]={ + 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f + }; + + static const unsigned char fast_flag_value[]={ + 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f + }; + + static const unsigned char fast_abort[]={ + 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff + }; + + *count = slen; + + while(slen > 0){ + if(hdlc->bit_shift==0){ + hdlc->cbin = *src++; + slen--; + hdlc->bit_shift = 8; + if(hdlc->do_adapt56){ + hdlc->bit_shift --; + } + } + + switch(hdlc->state){ + case STOPPED: + return 0; + case HDLC_FAST_IDLE: + if(hdlc->cbin == 0xff){ + hdlc->bit_shift = 0; + break; + } + hdlc->state = HDLC_GET_FLAG_B0; + hdlc->hdlc_bits1 = 0; + hdlc->bit_shift = 8; + break; + case HDLC_GET_FLAG_B0: + if(!(hdlc->cbin & 0x80)) { + hdlc->state = HDLC_GETFLAG_B1A6; + hdlc->hdlc_bits1 = 0; + } else { + if(!hdlc->do_adapt56){ + if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) + hdlc->state = HDLC_FAST_IDLE; + } + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GETFLAG_B1A6: + if(hdlc->cbin & 0x80){ + hdlc->hdlc_bits1++; + if(hdlc->hdlc_bits1==6){ + hdlc->state = HDLC_GETFLAG_B7; + } + } else { + hdlc->hdlc_bits1 = 0; + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GETFLAG_B7: + if(hdlc->cbin & 0x80) { + hdlc->state = HDLC_GET_FLAG_B0; + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->crc = 0xffff; + hdlc->shift_reg = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->data_received = 0; + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GET_DATA: + if(hdlc->cbin & 0x80){ + hdlc->hdlc_bits1++; + switch(hdlc->hdlc_bits1){ + case 6: + break; + case 7: + if(hdlc->data_received) { + // bad frame + status = -HDLC_FRAMING_ERROR; + } + if(!hdlc->do_adapt56){ + if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ + hdlc->state = HDLC_FAST_IDLE; + hdlc->bit_shift=1; + break; + } + } else { + hdlc->state = HDLC_GET_FLAG_B0; + } + break; + default: + hdlc->shift_reg>>=1; + hdlc->shift_reg |= 0x80; + hdlc->data_bits++; + break; + } + } else { + switch(hdlc->hdlc_bits1){ + case 5: + break; + case 6: + if(hdlc->data_received){ + if (hdlc->dstpos < 2) { + status = -HDLC_FRAMING_ERROR; + } else if (hdlc->crc != 0xf0b8){ + // crc error + status = -HDLC_CRC_ERROR; + } else { + // remove CRC + hdlc->dstpos -= 2; + // good frame + status = hdlc->dstpos; + } + } + hdlc->crc = 0xffff; + hdlc->shift_reg = 0; + hdlc->data_bits = 0; + if(!hdlc->do_adapt56){ + if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ + hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; + hdlc->state = HDLC_FAST_FLAG; + hdlc->ffbit_shift = hdlc->bit_shift; + hdlc->bit_shift = 1; + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + break; + default: + hdlc->shift_reg>>=1; + hdlc->data_bits++; + break; + } + hdlc->hdlc_bits1 = 0; + } + if (status) { + hdlc->dstpos = 0; + *count -= slen; + hdlc->cbin <<= 1; + hdlc->bit_shift--; + return status; + } + if(hdlc->data_bits==8){ + hdlc->data_bits = 0; + hdlc->data_received = 1; + hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); + + // good byte received + if (hdlc->dstpos < dsize) { + dst[hdlc->dstpos++] = hdlc->shift_reg; + } else { + // frame too long + status = -HDLC_LENGTH_ERROR; + hdlc->dstpos = 0; + } + } + hdlc->cbin <<= 1; + hdlc->bit_shift--; + break; + case HDLC_FAST_FLAG: + if(hdlc->cbin==hdlc->ffvalue){ + hdlc->bit_shift = 0; + break; + } else { + if(hdlc->cbin == 0xff){ + hdlc->state = HDLC_FAST_IDLE; + hdlc->bit_shift=0; + } else if(hdlc->ffbit_shift==8){ + hdlc->state = HDLC_GETFLAG_B7; + break; + } else { + hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; + hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; + if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; + hdlc->data_bits = hdlc->ffbit_shift-1; + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + } + break; + default: + break; + } + } + *count -= slen; + return 0; +} + +/* + isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. + + The bit stream starts with a beginning flag (01111110). After + that each byte is added to the bit stream with bit stuffing added + (0 after 5 1's). + When the last byte has been removed from the source buffer, the + CRC (2 bytes is added) and the frame terminates with the ending flag. + For the dchannel, the idle character (all 1's) is also added at the end. + If this function is called with empty source buffer (slen=0), flags or + idle character will be generated. + + src - source buffer + slen - source buffer length + count - number of bytes removed (encoded) from source buffer + dst _ destination buffer + dsize - destination buffer size + returns - number of encoded bytes in the destination buffer +*/ +int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, + unsigned short slen, int *count, + unsigned char *dst, int dsize) +{ + static const unsigned char xfast_flag_value[] = { + 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e + }; + + int len = 0; + + *count = slen; + + while (dsize > 0) { + if(hdlc->bit_shift==0){ + if(slen && !hdlc->do_closing){ + hdlc->shift_reg = *src++; + slen--; + if (slen == 0) + hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */ + hdlc->bit_shift = 8; + } else { + if(hdlc->state == HDLC_SEND_DATA){ + if(hdlc->data_received){ + hdlc->state = HDLC_SEND_CRC1; + hdlc->crc ^= 0xffff; + hdlc->bit_shift = 8; + hdlc->shift_reg = hdlc->crc & 0xff; + } else if(!hdlc->do_adapt56){ + hdlc->state = HDLC_SEND_FAST_FLAG; + } else { + hdlc->state = HDLC_SENDFLAG_B0; + } + } + + } + } + + switch(hdlc->state){ + case STOPPED: + while (dsize--) + *dst++ = 0xff; + + return dsize; + case HDLC_SEND_FAST_FLAG: + hdlc->do_closing = 0; + if(slen == 0){ + *dst++ = hdlc->ffvalue; + len++; + dsize--; + break; + } + if(hdlc->bit_shift==8){ + hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits); + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + hdlc->data_received = 1; + } + break; + case HDLC_SENDFLAG_B0: + hdlc->do_closing = 0; + hdlc->cbin <<= 1; + hdlc->data_bits++; + hdlc->hdlc_bits1 = 0; + hdlc->state = HDLC_SENDFLAG_B1A6; + break; + case HDLC_SENDFLAG_B1A6: + hdlc->cbin <<= 1; + hdlc->data_bits++; + hdlc->cbin++; + if(++hdlc->hdlc_bits1 == 6) + hdlc->state = HDLC_SENDFLAG_B7; + break; + case HDLC_SENDFLAG_B7: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(slen == 0){ + hdlc->state = HDLC_SENDFLAG_B0; + break; + } + if(hdlc->bit_shift==8){ + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + hdlc->data_received = 1; + } + break; + case HDLC_SEND_FIRST_FLAG: + hdlc->data_received = 1; + if(hdlc->data_bits==8){ + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + break; + } + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->shift_reg & 0x01) + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + } + break; + case HDLC_SEND_DATA: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->bit_shift==8){ + hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); + } + if(hdlc->shift_reg & 0x01){ + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + break; + case HDLC_SEND_CRC1: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + if(hdlc->bit_shift==0){ + hdlc->shift_reg = (hdlc->crc >> 8); + hdlc->state = HDLC_SEND_CRC2; + hdlc->bit_shift = 8; + } + break; + case HDLC_SEND_CRC2: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + if(hdlc->bit_shift==0){ + hdlc->shift_reg = 0x7e; + hdlc->state = HDLC_SEND_CLOSING_FLAG; + hdlc->bit_shift = 8; + } + break; + case HDLC_SEND_CLOSING_FLAG: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->cbin++; + } + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + hdlc->ffvalue = xfast_flag_value[hdlc->data_bits]; + if(hdlc->dchannel){ + hdlc->ffvalue = 0x7e; + hdlc->state = HDLC_SEND_IDLE1; + hdlc->bit_shift = 8-hdlc->data_bits; + if(hdlc->bit_shift==0) + hdlc->state = HDLC_SEND_FAST_IDLE; + } else { + if(!hdlc->do_adapt56){ + hdlc->state = HDLC_SEND_FAST_FLAG; + hdlc->data_received = 0; + } else { + hdlc->state = HDLC_SENDFLAG_B0; + hdlc->data_received = 0; + } + // Finished with this frame, send flags + if (dsize > 1) dsize = 1; + } + } + break; + case HDLC_SEND_IDLE1: + hdlc->do_closing = 0; + hdlc->cbin <<= 1; + hdlc->cbin++; + hdlc->data_bits++; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + hdlc->state = HDLC_SEND_FAST_IDLE; + hdlc->bit_shift = 0; + } + break; + case HDLC_SEND_FAST_IDLE: + hdlc->do_closing = 0; + hdlc->cbin = 0xff; + hdlc->data_bits = 8; + if(hdlc->bit_shift == 8){ + hdlc->cbin = 0x7e; + hdlc->state = HDLC_SEND_FIRST_FLAG; + } else { + *dst++ = hdlc->cbin; + hdlc->bit_shift = hdlc->data_bits = 0; + len++; + dsize = 0; + } + break; + default: + break; + } + if(hdlc->do_adapt56){ + if(hdlc->data_bits==7){ + hdlc->cbin <<= 1; + hdlc->cbin++; + hdlc->data_bits++; + } + } + if(hdlc->data_bits==8){ + *dst++ = hdlc->cbin; + hdlc->data_bits = 0; + len++; + dsize--; + } + } + *count -= slen; + + return len; +} + +EXPORT_SYMBOL(isdnhdlc_rcv_init); +EXPORT_SYMBOL(isdnhdlc_decode); +EXPORT_SYMBOL(isdnhdlc_out_init); +EXPORT_SYMBOL(isdnhdlc_encode); diff --git a/include/linux/isdn/hdlc.h b/include/linux/isdn/hdlc.h new file mode 100644 index 0000000..cf0a95a --- /dev/null +++ b/include/linux/isdn/hdlc.h @@ -0,0 +1,70 @@ +/* + * isdnhdlc.h -- General purpose ISDN HDLC decoder. + * + * Implementation of a HDLC decoder/encoder in software. + * Neccessary because some ISDN devices don't have HDLC + * controllers. Also included: a bit reversal table. + * + *Copyright (C) 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski + * + * 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 __ISDNHDLC_H__ +#define __ISDNHDLC_H__ + +struct isdnhdlc_vars { + int bit_shift; + int hdlc_bits1; + int data_bits; + int ffbit_shift; // encoding only + int state; + int dstpos; + + unsigned short crc; + + unsigned char cbin; + unsigned char shift_reg; + unsigned char ffvalue; + + unsigned int data_received:1; // set if transferring data + unsigned int dchannel:1; // set if D channel (send idle instead of flags) + unsigned int do_adapt56:1; // set if 56K adaptation + unsigned int do_closing:1; // set if in closing phase (need to send CRC + flag +}; + + +/* + The return value from isdnhdlc_decode is + the frame length, 0 if no complete frame was decoded, + or a negative error number +*/ +#define HDLC_FRAMING_ERROR 1 +#define HDLC_CRC_ERROR 2 +#define HDLC_LENGTH_ERROR 3 + +extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56); + +extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count, + unsigned char *dst, int dsize); + +extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56); + +extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count, + unsigned char *dst,int dsize); + +#endif /* __ISDNHDLC_H__ */ -- cgit v0.10.2 From 6bd4bcd3cd8affc09eaee7efbc037f65f4a71501 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 19:11:09 +0200 Subject: ISDN: Clean up isdnhdlc code Clean up isdnhdlc to meet current code standard. Remove hint to already removed bit reversal table. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c index 44ec741..b80e55a 100644 --- a/drivers/isdn/i4l/isdnhdlc.c +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -1,23 +1,24 @@ /* * isdnhdlc.c -- General purpose ISDN HDLC decoder. * - *Copyright (C) 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski + * Copyright (C) + * 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski * - * 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 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. + * 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. + * 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 @@ -36,20 +37,20 @@ MODULE_LICENSE("GPL"); /*-------------------------------------------------------------------*/ enum { - HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7, - HDLC_GET_DATA,HDLC_FAST_FLAG + HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7, + HDLC_GET_DATA, HDLC_FAST_FLAG }; enum { - HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG, - HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG, - HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0, - HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED + HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG, + HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG, + HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0, + HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED }; -void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) +void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, int do_adapt56) { - hdlc->bit_shift = 0; + hdlc->bit_shift = 0; hdlc->hdlc_bits1 = 0; hdlc->data_bits = 0; hdlc->ffbit_shift = 0; @@ -63,10 +64,12 @@ void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) hdlc->ffvalue = 0; hdlc->dstpos = 0; } +EXPORT_SYMBOL(isdnhdlc_out_init); -void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56) +void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, + int do_adapt56) { - hdlc->bit_shift = 0; + hdlc->bit_shift = 0; hdlc->hdlc_bits1 = 0; hdlc->data_bits = 0; hdlc->ffbit_shift = 0; @@ -83,7 +86,7 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada } hdlc->cbin = 0x7e; hdlc->bit_shift = 0; - if(do_adapt56){ + if (do_adapt56) { hdlc->do_adapt56 = 1; hdlc->data_bits = 0; hdlc->state = HDLC_SENDFLAG_B0; @@ -93,6 +96,25 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada } hdlc->shift_reg = 0; } +EXPORT_SYMBOL(isdnhdlc_rcv_init); + +static int +check_frame(struct isdnhdlc_vars *hdlc) +{ + int status; + + if (hdlc->dstpos < 2) /* too small - framing error */ + status = -HDLC_FRAMING_ERROR; + else if (hdlc->crc != 0xf0b8) /* crc error */ + status = -HDLC_CRC_ERROR; + else { + /* remove CRC */ + hdlc->dstpos -= 2; + /* good frame */ + status = hdlc->dstpos; + } + return status; +} /* isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. @@ -121,40 +143,63 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada returns - number of decoded bytes in the destination buffer and status flag. */ -int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, - int slen, int *count, unsigned char *dst, int dsize) +int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, + int *count, u8 *dst, int dsize) { - int status=0; + int status = 0; - static const unsigned char fast_flag[]={ - 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f + static const unsigned char fast_flag[] = { + 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f }; - static const unsigned char fast_flag_value[]={ - 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f + static const unsigned char fast_flag_value[] = { + 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f }; - static const unsigned char fast_abort[]={ - 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff + static const unsigned char fast_abort[] = { + 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; +#define handle_fast_flag(h) \ + do {\ + if (h->cbin == fast_flag[h->bit_shift]) {\ + h->ffvalue = fast_flag_value[h->bit_shift];\ + h->state = HDLC_FAST_FLAG;\ + h->ffbit_shift = h->bit_shift;\ + h->bit_shift = 1;\ + } else {\ + h->state = HDLC_GET_DATA;\ + h->data_received = 0;\ + } \ + } while (0) + +#define handle_abort(h) \ + do {\ + h->shift_reg = fast_abort[h->ffbit_shift - 1];\ + h->hdlc_bits1 = h->ffbit_shift - 2;\ + if (h->hdlc_bits1 < 0)\ + h->hdlc_bits1 = 0;\ + h->data_bits = h->ffbit_shift - 1;\ + h->state = HDLC_GET_DATA;\ + h->data_received = 0;\ + } while (0) + *count = slen; - while(slen > 0){ - if(hdlc->bit_shift==0){ + while (slen > 0) { + if (hdlc->bit_shift == 0) { hdlc->cbin = *src++; slen--; hdlc->bit_shift = 8; - if(hdlc->do_adapt56){ - hdlc->bit_shift --; - } + if (hdlc->do_adapt56) + hdlc->bit_shift--; } - switch(hdlc->state){ + switch (hdlc->state) { case STOPPED: return 0; case HDLC_FAST_IDLE: - if(hdlc->cbin == 0xff){ + if (hdlc->cbin == 0xff) { hdlc->bit_shift = 0; break; } @@ -163,32 +208,30 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->bit_shift = 8; break; case HDLC_GET_FLAG_B0: - if(!(hdlc->cbin & 0x80)) { + if (!(hdlc->cbin & 0x80)) { hdlc->state = HDLC_GETFLAG_B1A6; hdlc->hdlc_bits1 = 0; } else { - if(!hdlc->do_adapt56){ - if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) + if ((!hdlc->do_adapt56) && + (++hdlc->hdlc_bits1 >= 8) && + (hdlc->bit_shift == 1)) hdlc->state = HDLC_FAST_IDLE; - } } - hdlc->cbin<<=1; - hdlc->bit_shift --; + hdlc->cbin <<= 1; + hdlc->bit_shift--; break; case HDLC_GETFLAG_B1A6: - if(hdlc->cbin & 0x80){ + if (hdlc->cbin & 0x80) { hdlc->hdlc_bits1++; - if(hdlc->hdlc_bits1==6){ + if (hdlc->hdlc_bits1 == 6) hdlc->state = HDLC_GETFLAG_B7; - } - } else { + } else hdlc->hdlc_bits1 = 0; - } - hdlc->cbin<<=1; - hdlc->bit_shift --; + hdlc->cbin <<= 1; + hdlc->bit_shift--; break; case HDLC_GETFLAG_B7: - if(hdlc->cbin & 0x80) { + if (hdlc->cbin & 0x80) { hdlc->state = HDLC_GET_FLAG_B0; } else { hdlc->state = HDLC_GET_DATA; @@ -198,74 +241,55 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->data_bits = 0; hdlc->data_received = 0; } - hdlc->cbin<<=1; - hdlc->bit_shift --; + hdlc->cbin <<= 1; + hdlc->bit_shift--; break; case HDLC_GET_DATA: - if(hdlc->cbin & 0x80){ + if (hdlc->cbin & 0x80) { hdlc->hdlc_bits1++; - switch(hdlc->hdlc_bits1){ + switch (hdlc->hdlc_bits1) { case 6: break; case 7: - if(hdlc->data_received) { - // bad frame + if (hdlc->data_received) + /* bad frame */ status = -HDLC_FRAMING_ERROR; - } - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ - hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=1; + if (!hdlc->do_adapt56) { + if (hdlc->cbin == fast_abort + [hdlc->bit_shift + 1]) { + hdlc->state = + HDLC_FAST_IDLE; + hdlc->bit_shift = 1; break; } - } else { + } else hdlc->state = HDLC_GET_FLAG_B0; - } break; default: - hdlc->shift_reg>>=1; + hdlc->shift_reg >>= 1; hdlc->shift_reg |= 0x80; hdlc->data_bits++; break; } } else { - switch(hdlc->hdlc_bits1){ + switch (hdlc->hdlc_bits1) { case 5: break; case 6: - if(hdlc->data_received){ - if (hdlc->dstpos < 2) { - status = -HDLC_FRAMING_ERROR; - } else if (hdlc->crc != 0xf0b8){ - // crc error - status = -HDLC_CRC_ERROR; - } else { - // remove CRC - hdlc->dstpos -= 2; - // good frame - status = hdlc->dstpos; - } - } + if (hdlc->data_received) + status = check_frame(hdlc); hdlc->crc = 0xffff; hdlc->shift_reg = 0; hdlc->data_bits = 0; - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ - hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; - hdlc->state = HDLC_FAST_FLAG; - hdlc->ffbit_shift = hdlc->bit_shift; - hdlc->bit_shift = 1; - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - } else { + if (!hdlc->do_adapt56) + handle_fast_flag(hdlc); + else { hdlc->state = HDLC_GET_DATA; hdlc->data_received = 0; } break; default: - hdlc->shift_reg>>=1; + hdlc->shift_reg >>= 1; hdlc->data_bits++; break; } @@ -278,16 +302,17 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->bit_shift--; return status; } - if(hdlc->data_bits==8){ + if (hdlc->data_bits == 8) { hdlc->data_bits = 0; hdlc->data_received = 1; - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); + hdlc->crc = crc_ccitt_byte(hdlc->crc, + hdlc->shift_reg); - // good byte received - if (hdlc->dstpos < dsize) { + /* good byte received */ + if (hdlc->dstpos < dsize) dst[hdlc->dstpos++] = hdlc->shift_reg; - } else { - // frame too long + else { + /* frame too long */ status = -HDLC_LENGTH_ERROR; hdlc->dstpos = 0; } @@ -296,24 +321,18 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->bit_shift--; break; case HDLC_FAST_FLAG: - if(hdlc->cbin==hdlc->ffvalue){ + if (hdlc->cbin == hdlc->ffvalue) { hdlc->bit_shift = 0; break; } else { - if(hdlc->cbin == 0xff){ + if (hdlc->cbin == 0xff) { hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=0; - } else if(hdlc->ffbit_shift==8){ + hdlc->bit_shift = 0; + } else if (hdlc->ffbit_shift == 8) { hdlc->state = HDLC_GETFLAG_B7; break; - } else { - hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; - hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; - if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; - hdlc->data_bits = hdlc->ffbit_shift-1; - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } + } else + handle_abort(hdlc); } break; default: @@ -323,7 +342,7 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, *count -= slen; return 0; } - +EXPORT_SYMBOL(isdnhdlc_decode); /* isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. @@ -343,12 +362,11 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, dsize - destination buffer size returns - number of encoded bytes in the destination buffer */ -int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, - unsigned short slen, int *count, - unsigned char *dst, int dsize) +int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, + int *count, u8 *dst, int dsize) { static const unsigned char xfast_flag_value[] = { - 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e + 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e }; int len = 0; @@ -356,31 +374,34 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, *count = slen; while (dsize > 0) { - if(hdlc->bit_shift==0){ - if(slen && !hdlc->do_closing){ + if (hdlc->bit_shift == 0) { + if (slen && !hdlc->do_closing) { hdlc->shift_reg = *src++; slen--; if (slen == 0) - hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */ + /* closing sequence, CRC + flag(s) */ + hdlc->do_closing = 1; hdlc->bit_shift = 8; } else { - if(hdlc->state == HDLC_SEND_DATA){ - if(hdlc->data_received){ + if (hdlc->state == HDLC_SEND_DATA) { + if (hdlc->data_received) { hdlc->state = HDLC_SEND_CRC1; hdlc->crc ^= 0xffff; hdlc->bit_shift = 8; - hdlc->shift_reg = hdlc->crc & 0xff; - } else if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; - } else { - hdlc->state = HDLC_SENDFLAG_B0; - } + hdlc->shift_reg = + hdlc->crc & 0xff; + } else if (!hdlc->do_adapt56) + hdlc->state = + HDLC_SEND_FAST_FLAG; + else + hdlc->state = + HDLC_SENDFLAG_B0; } } } - switch(hdlc->state){ + switch (hdlc->state) { case STOPPED: while (dsize--) *dst++ = 0xff; @@ -388,14 +409,15 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, return dsize; case HDLC_SEND_FAST_FLAG: hdlc->do_closing = 0; - if(slen == 0){ + if (slen == 0) { *dst++ = hdlc->ffvalue; len++; dsize--; break; } - if(hdlc->bit_shift==8){ - hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits); + if (hdlc->bit_shift == 8) { + hdlc->cbin = hdlc->ffvalue >> + (8 - hdlc->data_bits); hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -413,17 +435,17 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->cbin <<= 1; hdlc->data_bits++; hdlc->cbin++; - if(++hdlc->hdlc_bits1 == 6) + if (++hdlc->hdlc_bits1 == 6) hdlc->state = HDLC_SENDFLAG_B7; break; case HDLC_SENDFLAG_B7: hdlc->cbin <<= 1; hdlc->data_bits++; - if(slen == 0){ + if (slen == 0) { hdlc->state = HDLC_SENDFLAG_B0; break; } - if(hdlc->bit_shift==8){ + if (hdlc->bit_shift == 8) { hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -432,7 +454,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, break; case HDLC_SEND_FIRST_FLAG: hdlc->data_received = 1; - if(hdlc->data_bits==8){ + if (hdlc->data_bits == 8) { hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -440,11 +462,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, } hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->shift_reg & 0x01) + if (hdlc->shift_reg & 0x01) hdlc->cbin++; hdlc->shift_reg >>= 1; hdlc->bit_shift--; - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -453,14 +475,14 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_DATA: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->bit_shift==8){ - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); - } - if(hdlc->shift_reg & 0x01){ + if (hdlc->bit_shift == 8) + hdlc->crc = crc_ccitt_byte(hdlc->crc, + hdlc->shift_reg); + if (hdlc->shift_reg & 0x01) { hdlc->hdlc_bits1++; hdlc->cbin++; hdlc->shift_reg >>= 1; @@ -474,11 +496,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_CRC1: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->shift_reg & 0x01){ + if (hdlc->shift_reg & 0x01) { hdlc->hdlc_bits1++; hdlc->cbin++; hdlc->shift_reg >>= 1; @@ -488,7 +510,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->shift_reg >>= 1; hdlc->bit_shift--; } - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->shift_reg = (hdlc->crc >> 8); hdlc->state = HDLC_SEND_CRC2; hdlc->bit_shift = 8; @@ -497,11 +519,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_CRC2: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->shift_reg & 0x01){ + if (hdlc->shift_reg & 0x01) { hdlc->hdlc_bits1++; hdlc->cbin++; hdlc->shift_reg >>= 1; @@ -511,7 +533,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->shift_reg >>= 1; hdlc->bit_shift--; } - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->shift_reg = 0x7e; hdlc->state = HDLC_SEND_CLOSING_FLAG; hdlc->bit_shift = 8; @@ -520,33 +542,36 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_CLOSING_FLAG: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->shift_reg & 0x01){ + if (hdlc->shift_reg & 0x01) hdlc->cbin++; - } hdlc->shift_reg >>= 1; hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->ffvalue = xfast_flag_value[hdlc->data_bits]; - if(hdlc->dchannel){ + if (hdlc->bit_shift == 0) { + hdlc->ffvalue = + xfast_flag_value[hdlc->data_bits]; + if (hdlc->dchannel) { hdlc->ffvalue = 0x7e; hdlc->state = HDLC_SEND_IDLE1; hdlc->bit_shift = 8-hdlc->data_bits; - if(hdlc->bit_shift==0) - hdlc->state = HDLC_SEND_FAST_IDLE; + if (hdlc->bit_shift == 0) + hdlc->state = + HDLC_SEND_FAST_IDLE; } else { - if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; + if (!hdlc->do_adapt56) { + hdlc->state = + HDLC_SEND_FAST_FLAG; hdlc->data_received = 0; } else { hdlc->state = HDLC_SENDFLAG_B0; hdlc->data_received = 0; } - // Finished with this frame, send flags - if (dsize > 1) dsize = 1; + /* Finished this frame, send flags */ + if (dsize > 1) + dsize = 1; } } break; @@ -556,7 +581,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->cbin++; hdlc->data_bits++; hdlc->bit_shift--; - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->state = HDLC_SEND_FAST_IDLE; hdlc->bit_shift = 0; } @@ -565,12 +590,13 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->do_closing = 0; hdlc->cbin = 0xff; hdlc->data_bits = 8; - if(hdlc->bit_shift == 8){ + if (hdlc->bit_shift == 8) { hdlc->cbin = 0x7e; hdlc->state = HDLC_SEND_FIRST_FLAG; } else { *dst++ = hdlc->cbin; - hdlc->bit_shift = hdlc->data_bits = 0; + hdlc->bit_shift = 0; + hdlc->data_bits = 0; len++; dsize = 0; } @@ -578,14 +604,14 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, default: break; } - if(hdlc->do_adapt56){ - if(hdlc->data_bits==7){ + if (hdlc->do_adapt56) { + if (hdlc->data_bits == 7) { hdlc->cbin <<= 1; hdlc->cbin++; hdlc->data_bits++; } } - if(hdlc->data_bits==8){ + if (hdlc->data_bits == 8) { *dst++ = hdlc->cbin; hdlc->data_bits = 0; len++; @@ -596,8 +622,4 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, return len; } - -EXPORT_SYMBOL(isdnhdlc_rcv_init); -EXPORT_SYMBOL(isdnhdlc_decode); -EXPORT_SYMBOL(isdnhdlc_out_init); EXPORT_SYMBOL(isdnhdlc_encode); diff --git a/include/linux/isdn/hdlc.h b/include/linux/isdn/hdlc.h index cf0a95a..8f3540c 100644 --- a/include/linux/isdn/hdlc.h +++ b/include/linux/isdn/hdlc.h @@ -1,27 +1,28 @@ /* - * isdnhdlc.h -- General purpose ISDN HDLC decoder. + * hdlc.h -- General purpose ISDN HDLC decoder. * * Implementation of a HDLC decoder/encoder in software. * Neccessary because some ISDN devices don't have HDLC - * controllers. Also included: a bit reversal table. + * controllers. * - *Copyright (C) 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski + * Copyright (C) + * 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski * - * 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 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. + * 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. + * 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 __ISDNHDLC_H__ @@ -31,20 +32,24 @@ struct isdnhdlc_vars { int bit_shift; int hdlc_bits1; int data_bits; - int ffbit_shift; // encoding only + int ffbit_shift; /* encoding only */ int state; int dstpos; - unsigned short crc; + u16 crc; - unsigned char cbin; - unsigned char shift_reg; - unsigned char ffvalue; + u8 cbin; + u8 shift_reg; + u8 ffvalue; - unsigned int data_received:1; // set if transferring data - unsigned int dchannel:1; // set if D channel (send idle instead of flags) - unsigned int do_adapt56:1; // set if 56K adaptation - unsigned int do_closing:1; // set if in closing phase (need to send CRC + flag + /* set if transferring data */ + u32 data_received:1; + /* set if D channel (send idle instead of flags) */ + u32 dchannel:1; + /* set if 56K adaptation */ + u32 do_adapt56:1; + /* set if in closing phase (need to send CRC + flag) */ + u32 do_closing:1; }; @@ -57,14 +62,15 @@ struct isdnhdlc_vars { #define HDLC_CRC_ERROR 2 #define HDLC_LENGTH_ERROR 3 -extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56); +extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, int do_adapt56); -extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count, - unsigned char *dst, int dsize); +extern int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, + int slen, int *count, u8 *dst, int dsize); -extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56); +extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, + int do_adapt56); -extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count, - unsigned char *dst,int dsize); +extern int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, + u16 slen, int *count, u8 *dst, int dsize); #endif /* __ISDNHDLC_H__ */ -- cgit v0.10.2 From c38fc3bc2ecddd4f5278131603e6964cbed071b2 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 20:31:42 +0200 Subject: ISDN: Add support for none reverse bitstreams to isdnhdc The original isdnhdlc code was developed for devices which had reversed bitorder in the byte stream. Adding code to handle normal bitstreams as well. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c index 0074b60..95b1cdd 100644 --- a/drivers/isdn/hisax/st5481_b.c +++ b/drivers/isdn/hisax/st5481_b.c @@ -218,7 +218,10 @@ static void st5481B_mode(struct st5481_bcs *bcs, int mode) if (bcs->mode != L1_MODE_NULL) { // Open the B channel if (bcs->mode != L1_MODE_TRANS) { - isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K); + u32 features = HDLC_BITREVERSE; + if (bcs->mode == L1_MODE_HDLC_56K) + features |= HDLC_56KBIT; + isdnhdlc_out_init(&b_out->hdlc_state, features); } st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL); diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c index 077991c..39e8e49 100644 --- a/drivers/isdn/hisax/st5481_d.c +++ b/drivers/isdn/hisax/st5481_d.c @@ -417,7 +417,7 @@ static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg) DBG(2,"len=%d",skb->len); - isdnhdlc_out_init(&d_out->hdlc_state, 1, 0); + isdnhdlc_out_init(&d_out->hdlc_state, HDLC_DCHANNEL | HDLC_BITREVERSE); if (test_and_set_bit(buf_nr, &d_out->busy)) { WARNING("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy); diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 2b3a055..10d41c5 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -637,10 +637,13 @@ void st5481_in_mode(struct st5481_in *in, int mode) usb_unlink_urb(in->urb[1]); if (in->mode != L1_MODE_NULL) { - if (in->mode != L1_MODE_TRANS) - isdnhdlc_rcv_init(&in->hdlc_state, - in->mode == L1_MODE_HDLC_56K); - + if (in->mode != L1_MODE_TRANS) { + u32 features = HDLC_BITREVERSE; + + if (in->mode == L1_MODE_HDLC_56K) + features |= HDLC_56KBIT; + isdnhdlc_rcv_init(&in->hdlc_state, features); + } st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL); st5481_usb_device_ctrl_msg(in->adapter, in->counter, in->packet_size, diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c index b80e55a..df345ce 100644 --- a/drivers/isdn/i4l/isdnhdlc.c +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -2,6 +2,7 @@ * isdnhdlc.c -- General purpose ISDN HDLC decoder. * * Copyright (C) + * 2009 Karsten Keil * 2002 Wolfgang Mües * 2001 Frode Isaksen * 2001 Kai Germaschewski @@ -25,6 +26,7 @@ #include #include #include +#include /*-------------------------------------------------------------------*/ @@ -48,35 +50,21 @@ enum { HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED }; -void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, int do_adapt56) +void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) { - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; + memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); hdlc->state = HDLC_GET_DATA; - hdlc->do_adapt56 = do_adapt56; - hdlc->dchannel = 0; - hdlc->crc = 0; - hdlc->cbin = 0; - hdlc->shift_reg = 0; - hdlc->ffvalue = 0; - hdlc->dstpos = 0; + if (features & HDLC_56KBIT) + hdlc->do_adapt56 = 1; + if (features & HDLC_BITREVERSE) + hdlc->do_bitreverse = 1; } EXPORT_SYMBOL(isdnhdlc_out_init); -void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, - int do_adapt56) +void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features) { - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; - hdlc->do_closing = 0; - hdlc->ffvalue = 0; - if (is_d_channel) { + memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); + if (features & HDLC_DCHANNEL) { hdlc->dchannel = 1; hdlc->state = HDLC_SEND_FIRST_FLAG; } else { @@ -85,16 +73,13 @@ void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, hdlc->ffvalue = 0x7e; } hdlc->cbin = 0x7e; - hdlc->bit_shift = 0; - if (do_adapt56) { + if (features & HDLC_56KBIT) { hdlc->do_adapt56 = 1; - hdlc->data_bits = 0; hdlc->state = HDLC_SENDFLAG_B0; - } else { - hdlc->do_adapt56 = 0; + } else hdlc->data_bits = 8; - } - hdlc->shift_reg = 0; + if (features & HDLC_BITREVERSE) + hdlc->do_bitreverse = 1; } EXPORT_SYMBOL(isdnhdlc_rcv_init); @@ -188,7 +173,11 @@ int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, while (slen > 0) { if (hdlc->bit_shift == 0) { - hdlc->cbin = *src++; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + hdlc->cbin = bitrev8(*src++); + else + hdlc->cbin = *src++; slen--; hdlc->bit_shift = 8; if (hdlc->do_adapt56) @@ -405,12 +394,15 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, case STOPPED: while (dsize--) *dst++ = 0xff; - return dsize; case HDLC_SEND_FAST_FLAG: hdlc->do_closing = 0; if (slen == 0) { - *dst++ = hdlc->ffvalue; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->ffvalue); + else + *dst++ = hdlc->ffvalue; len++; dsize--; break; @@ -594,7 +586,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, hdlc->cbin = 0x7e; hdlc->state = HDLC_SEND_FIRST_FLAG; } else { - *dst++ = hdlc->cbin; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->cbin); + else + *dst++ = hdlc->cbin; hdlc->bit_shift = 0; hdlc->data_bits = 0; len++; @@ -612,7 +608,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, } } if (hdlc->data_bits == 8) { - *dst++ = hdlc->cbin; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->cbin); + else + *dst++ = hdlc->cbin; hdlc->data_bits = 0; len++; dsize--; diff --git a/include/linux/isdn/hdlc.h b/include/linux/isdn/hdlc.h index 8f3540c..4b3ecc4 100644 --- a/include/linux/isdn/hdlc.h +++ b/include/linux/isdn/hdlc.h @@ -6,6 +6,7 @@ * controllers. * * Copyright (C) + * 2009 Karsten Keil * 2002 Wolfgang Mües * 2001 Frode Isaksen * 2001 Kai Germaschewski @@ -50,8 +51,14 @@ struct isdnhdlc_vars { u32 do_adapt56:1; /* set if in closing phase (need to send CRC + flag) */ u32 do_closing:1; + /* set if data is bitreverse */ + u32 do_bitreverse:1; }; +/* Feature Flags */ +#define HDLC_56KBIT 0x01 +#define HDLC_DCHANNEL 0x02 +#define HDLC_BITREVERSE 0x04 /* The return value from isdnhdlc_decode is @@ -62,13 +69,12 @@ struct isdnhdlc_vars { #define HDLC_CRC_ERROR 2 #define HDLC_LENGTH_ERROR 3 -extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, int do_adapt56); +extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features); extern int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, int *count, u8 *dst, int dsize); -extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, - int do_adapt56); +extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features); extern int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, int *count, u8 *dst, int dsize); -- cgit v0.10.2 From f3fad223ed69f406f33c9619c256858d5a5fc5c7 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 20:58:33 +0200 Subject: ISDN: Fix isdnhdlc for one byte hdlc packets Normally HDLC packets contain more as one byte (e.g a X25/X75 header). But if you use plain HDLC framing, the current code do not encode 1 byte payloads, this patch fix that. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c index df345ce..c989aa3 100644 --- a/drivers/isdn/i4l/isdnhdlc.c +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -47,7 +47,7 @@ enum { HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG, HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG, HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0, - HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED + HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE }; void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) @@ -362,6 +362,9 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, *count = slen; + /* special handling for one byte frames */ + if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG)) + hdlc->state = HDLC_SENDFLAG_ONE; while (dsize > 0) { if (hdlc->bit_shift == 0) { if (slen && !hdlc->do_closing) { @@ -407,6 +410,8 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, dsize--; break; } + /* fall through */ + case HDLC_SENDFLAG_ONE: if (hdlc->bit_shift == 8) { hdlc->cbin = hdlc->ffvalue >> (8 - hdlc->data_bits); -- cgit v0.10.2 From fb286f0471a04ef646c8e5c79750ae6718183745 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Thu, 9 Jul 2009 10:02:29 +0200 Subject: mISDN: Make clearing B-channel a common function Clearing B-channel is needed in every driver, so it makes sense to have it as common function. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index e1dab30..fd77bb1 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -3416,22 +3416,8 @@ deactivate_bchannel(struct bchannel *bch) u_long flags; spin_lock_irqsave(&hc->lock, flags); - if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { - dev_kfree_skb(bch->next_skb); - bch->next_skb = NULL; - } - if (bch->tx_skb) { - dev_kfree_skb(bch->tx_skb); - bch->tx_skb = NULL; - } - bch->tx_idx = 0; - if (bch->rx_skb) { - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; - } + mISDN_clear_bchannel(bch); hc->chan[bch->slot].coeff_count = 0; - test_and_clear_bit(FLG_ACTIVE, &bch->Flags); - test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); hc->chan[bch->slot].rx_off = 0; hc->chan[bch->slot].conf = -1; mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0); diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 228ffbe..70e6b0e 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1522,22 +1522,8 @@ deactivate_bchannel(struct bchannel *bch) u_long flags; spin_lock_irqsave(&hc->lock, flags); - if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { - dev_kfree_skb(bch->next_skb); - bch->next_skb = NULL; - } - if (bch->tx_skb) { - dev_kfree_skb(bch->tx_skb); - bch->tx_skb = NULL; - } - bch->tx_idx = 0; - if (bch->rx_skb) { - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; - } + mISDN_clear_bchannel(bch); mode_hfcpci(bch, bch->nr, ISDN_P_NONE); - test_and_clear_bit(FLG_ACTIVE, &bch->Flags); - test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); spin_unlock_irqrestore(&hc->lock, flags); } diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 6b7704c..fc46a26 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -1809,21 +1809,7 @@ deactivate_bchannel(struct bchannel *bch) hw->name, __func__, bch->nr); spin_lock_irqsave(&hw->lock, flags); - if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { - dev_kfree_skb(bch->next_skb); - bch->next_skb = NULL; - } - if (bch->tx_skb) { - dev_kfree_skb(bch->tx_skb); - bch->tx_skb = NULL; - } - bch->tx_idx = 0; - if (bch->rx_skb) { - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; - } - clear_bit(FLG_ACTIVE, &bch->Flags); - clear_bit(FLG_TX_BUSY, &bch->Flags); + mISDN_clear_bchannel(bch); spin_unlock_irqrestore(&hw->lock, flags); hfcsusb_setup_bch(bch, ISDN_P_NONE); hfcsusb_stop_endpoint(hw, bch->nr); diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 0481a0c..e8049be 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -114,13 +114,14 @@ mISDN_freedchannel(struct dchannel *ch) } EXPORT_SYMBOL(mISDN_freedchannel); -int -mISDN_freebchannel(struct bchannel *ch) +void +mISDN_clear_bchannel(struct bchannel *ch) { if (ch->tx_skb) { dev_kfree_skb(ch->tx_skb); ch->tx_skb = NULL; } + ch->tx_idx = 0; if (ch->rx_skb) { dev_kfree_skb(ch->rx_skb); ch->rx_skb = NULL; @@ -129,6 +130,16 @@ mISDN_freebchannel(struct bchannel *ch) dev_kfree_skb(ch->next_skb); ch->next_skb = NULL; } + test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); + test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); + test_and_clear_bit(FLG_ACTIVE, &ch->Flags); +} +EXPORT_SYMBOL(mISDN_clear_bchannel); + +int +mISDN_freebchannel(struct bchannel *ch) +{ + mISDN_clear_bchannel(ch); skb_queue_purge(&ch->rqueue); ch->rcount = 0; flush_scheduled_work(); diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h index 7f9831d..4af8414 100644 --- a/include/linux/mISDNhw.h +++ b/include/linux/mISDNhw.h @@ -168,6 +168,7 @@ struct bchannel { extern int mISDN_initdchannel(struct dchannel *, int, void *); extern int mISDN_initbchannel(struct bchannel *, int); extern int mISDN_freedchannel(struct dchannel *); +extern void mISDN_clear_bchannel(struct bchannel *); extern int mISDN_freebchannel(struct bchannel *); extern void queue_ch_frame(struct mISDNchannel *, u_int, int, struct sk_buff *); -- cgit v0.10.2 From cae86d4a4e56eeda1afdea38f230d222edda7dd5 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 22 Jul 2009 19:42:46 +0200 Subject: mISDN: Add driver for Infineon ISDN chipset family This driver supports cards with Infineon ISAC/HSCX, ISACX, IPAC and IPACX chips from various manufacturers. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index 3024566..a8542b8 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -39,3 +39,17 @@ config MISDN_HFCUSB Enable support for USB ISDN TAs with Cologne Chip AG's HFC-S USB ISDN Controller +config MISDN_INFINEON + tristate "Support for cards with Infineon chipset" + depends on MISDN + depends on PCI + select MISDN_IPAC + help + Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX + chip from Infineon (former manufacturer Siemens). + + +config MISDN_IPAC + tristate + depends on MISDN + diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index b040352..2863455 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -6,3 +6,6 @@ obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o +obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o +# chip modules +obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o diff --git a/drivers/isdn/hardware/mISDN/iohelper.h b/drivers/isdn/hardware/mISDN/iohelper.h new file mode 100644 index 0000000..c16a217 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/iohelper.h @@ -0,0 +1,109 @@ +/* + * iohelper.h + * helper for define functions to access ISDN hardware + * supported are memory mapped IO + * indirect port IO (one port for address, one for data) + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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 _IOHELPER_H +#define _IOHELPER_H + +typedef u8 (read_reg_t)(void *, u8); +typedef void (write_reg_t)(void *, u8, u8); +typedef void (fifo_func_t)(void *, u8, u8 *, int); + +struct _ioport { + u32 port; + u32 ale; +}; + +#define IOFUNC_IO(name, hws, ap) \ + static u8 Read##name##_IO(void *p, u8 off) {\ + struct hws *hw = p;\ + return inb(hw->ap.port + off);\ + } \ + static void Write##name##_IO(void *p, u8 off, u8 val) {\ + struct hws *hw = p;\ + outb(val, hw->ap.port + off);\ + } \ + static void ReadFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\ + struct hws *hw = p;\ + insb(hw->ap.port + off, dp, size);\ + } \ + static void WriteFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\ + struct hws *hw = p;\ + outsb(hw->ap.port + off, dp, size);\ + } + +#define IOFUNC_IND(name, hws, ap) \ + static u8 Read##name##_IND(void *p, u8 off) {\ + struct hws *hw = p;\ + outb(off, hw->ap.ale);\ + return inb(hw->ap.port);\ + } \ + static void Write##name##_IND(void *p, u8 off, u8 val) {\ + struct hws *hw = p;\ + outb(off, hw->ap.ale);\ + outb(val, hw->ap.port);\ + } \ + static void ReadFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\ + struct hws *hw = p;\ + outb(off, hw->ap.ale);\ + insb(hw->ap.port, dp, size);\ + } \ + static void WriteFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\ + struct hws *hw = p;\ + outb(off, hw->ap.ale);\ + outsb(hw->ap.port, dp, size);\ + } + +#define IOFUNC_MEMIO(name, hws, typ, adr) \ + static u8 Read##name##_MIO(void *p, u8 off) {\ + struct hws *hw = p;\ + return readb(((typ *)hw->adr) + off);\ + } \ + static void Write##name##_MIO(void *p, u8 off, u8 val) {\ + struct hws *hw = p;\ + writeb(val, ((typ *)hw->adr) + off);\ + } \ + static void ReadFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\ + struct hws *hw = p;\ + while (size--)\ + *dp++ = readb(((typ *)hw->adr) + off);\ + } \ + static void WriteFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\ + struct inf_hw *hw = p;\ + while (size--)\ + writeb(*dp++, ((typ *)hw->adr) + off);\ + } + +#define ASSIGN_FUNC(typ, name, dest) do {\ + dest.read_reg = &Read##name##_##typ;\ + dest.write_reg = &Write##name##_##typ;\ + dest.read_fifo = &ReadFiFo##name##_##typ;\ + dest.write_fifo = &WriteFiFo##name##_##typ;\ + } while (0) +#define ASSIGN_FUNC_IPAC(typ, target) do {\ + ASSIGN_FUNC(typ, ISAC, target.isac);\ + ASSIGN_FUNC(typ, IPAC, target);\ + } while (0) + +#endif \ No newline at end of file diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h new file mode 100644 index 0000000..f9601d5 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/ipac.h @@ -0,0 +1,405 @@ +/* + * + * ipac.h Defines for the Infineon (former Siemens) ISDN + * chip series + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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 "iohelper.h" + +struct isac_hw { + struct dchannel dch; + u32 type; + u32 off; /* offset to isac regs */ + char *name; + spinlock_t *hwlock; /* lock HW acccess */ + read_reg_t *read_reg; + write_reg_t *write_reg; + fifo_func_t *read_fifo; + fifo_func_t *write_fifo; + int (*monitor)(void *, u32, u8 *, int); + void (*release)(struct isac_hw *); + int (*init)(struct isac_hw *); + int (*ctrl)(struct isac_hw *, u32, u_long); + int (*open)(struct isac_hw *, struct channel_req *); + u8 *mon_tx; + u8 *mon_rx; + int mon_txp; + int mon_txc; + int mon_rxp; + struct arcofi_msg *arcofi_list; + struct timer_list arcofitimer; + wait_queue_head_t arcofi_wait; + u8 arcofi_bc; + u8 arcofi_state; + u8 mocr; + u8 adf2; + u8 state; +}; + +struct ipac_hw; + +struct hscx_hw { + struct bchannel bch; + struct ipac_hw *ip; + u8 fifo_size; + u8 off; /* offset to ICA or ICB */ + u8 slot; + char log[64]; +}; + +struct ipac_hw { + struct isac_hw isac; + struct hscx_hw hscx[2]; + char *name; + void *hw; + spinlock_t *hwlock; /* lock HW acccess */ + struct module *owner; + u32 type; + read_reg_t *read_reg; + write_reg_t *write_reg; + fifo_func_t *read_fifo; + fifo_func_t *write_fifo; + void (*release)(struct ipac_hw *); + int (*init)(struct ipac_hw *); + int (*ctrl)(struct ipac_hw *, u32, u_long); + u8 conf; +}; + +#define IPAC_TYPE_ISAC 0x0010 +#define IPAC_TYPE_IPAC 0x0020 +#define IPAC_TYPE_ISACX 0x0040 +#define IPAC_TYPE_IPACX 0x0080 +#define IPAC_TYPE_HSCX 0x0100 + +#define ISAC_USE_ARCOFI 0x1000 + +/* Monitor functions */ +#define MONITOR_RX_0 0x1000 +#define MONITOR_RX_1 0x1001 +#define MONITOR_TX_0 0x2000 +#define MONITOR_TX_1 0x2001 + +/* All registers original Siemens Spec */ +/* IPAC/ISAC registers */ +#define ISAC_MASK 0x20 +#define ISAC_ISTA 0x20 +#define ISAC_STAR 0x21 +#define ISAC_CMDR 0x21 +#define ISAC_EXIR 0x24 +#define ISAC_ADF2 0x39 +#define ISAC_SPCR 0x30 +#define ISAC_ADF1 0x38 +#define ISAC_CIR0 0x31 +#define ISAC_CIX0 0x31 +#define ISAC_CIR1 0x33 +#define ISAC_CIX1 0x33 +#define ISAC_STCR 0x37 +#define ISAC_MODE 0x22 +#define ISAC_RSTA 0x27 +#define ISAC_RBCL 0x25 +#define ISAC_RBCH 0x2A +#define ISAC_TIMR 0x23 +#define ISAC_SQXR 0x3b +#define ISAC_SQRR 0x3b +#define ISAC_MOSR 0x3a +#define ISAC_MOCR 0x3a +#define ISAC_MOR0 0x32 +#define ISAC_MOX0 0x32 +#define ISAC_MOR1 0x34 +#define ISAC_MOX1 0x34 + +#define ISAC_RBCH_XAC 0x80 + +#define IPAC_D_TIN2 0x01 + +/* IPAC/HSCX */ +#define IPAC_ISTAB 0x20 /* RD */ +#define IPAC_MASKB 0x20 /* WR */ +#define IPAC_STARB 0x21 /* RD */ +#define IPAC_CMDRB 0x21 /* WR */ +#define IPAC_MODEB 0x22 /* R/W */ +#define IPAC_EXIRB 0x24 /* RD */ +#define IPAC_RBCLB 0x25 /* RD */ +#define IPAC_RAH1 0x26 /* WR */ +#define IPAC_RAH2 0x27 /* WR */ +#define IPAC_RSTAB 0x27 /* RD */ +#define IPAC_RAL1 0x28 /* R/W */ +#define IPAC_RAL2 0x29 /* WR */ +#define IPAC_RHCRB 0x29 /* RD */ +#define IPAC_XBCL 0x2A /* WR */ +#define IPAC_CCR2 0x2C /* R/W */ +#define IPAC_RBCHB 0x2D /* RD */ +#define IPAC_XBCH 0x2D /* WR */ +#define HSCX_VSTR 0x2E /* RD */ +#define IPAC_RLCR 0x2E /* WR */ +#define IPAC_CCR1 0x2F /* R/W */ +#define IPAC_TSAX 0x30 /* WR */ +#define IPAC_TSAR 0x31 /* WR */ +#define IPAC_XCCR 0x32 /* WR */ +#define IPAC_RCCR 0x33 /* WR */ + +/* IPAC_ISTAB/IPAC_MASKB bits */ +#define IPAC_B_XPR 0x10 +#define IPAC_B_RPF 0x40 +#define IPAC_B_RME 0x80 +#define IPAC_B_ON 0x2F + +/* IPAC_EXIRB bits */ +#define IPAC_B_RFS 0x04 +#define IPAC_B_RFO 0x10 +#define IPAC_B_XDU 0x40 +#define IPAC_B_XMR 0x80 + +/* IPAC special registers */ +#define IPAC_CONF 0xC0 /* R/W */ +#define IPAC_ISTA 0xC1 /* RD */ +#define IPAC_MASK 0xC1 /* WR */ +#define IPAC_ID 0xC2 /* RD */ +#define IPAC_ACFG 0xC3 /* R/W */ +#define IPAC_AOE 0xC4 /* R/W */ +#define IPAC_ARX 0xC5 /* RD */ +#define IPAC_ATX 0xC5 /* WR */ +#define IPAC_PITA1 0xC6 /* R/W */ +#define IPAC_PITA2 0xC7 /* R/W */ +#define IPAC_POTA1 0xC8 /* R/W */ +#define IPAC_POTA2 0xC9 /* R/W */ +#define IPAC_PCFG 0xCA /* R/W */ +#define IPAC_SCFG 0xCB /* R/W */ +#define IPAC_TIMR2 0xCC /* R/W */ + +/* IPAC_ISTA/_MASK bits */ +#define IPAC__EXB 0x01 +#define IPAC__ICB 0x02 +#define IPAC__EXA 0x04 +#define IPAC__ICA 0x08 +#define IPAC__EXD 0x10 +#define IPAC__ICD 0x20 +#define IPAC__INT0 0x40 +#define IPAC__INT1 0x80 +#define IPAC__ON 0xC0 + +/* HSCX ISTA/MASK bits */ +#define HSCX__EXB 0x01 +#define HSCX__EXA 0x02 +#define HSCX__ICA 0x04 + +/* ISAC/ISACX/IPAC/IPACX L1 commands */ +#define ISAC_CMD_TIM 0x0 +#define ISAC_CMD_RS 0x1 +#define ISAC_CMD_SCZ 0x4 +#define ISAC_CMD_SSZ 0x2 +#define ISAC_CMD_AR8 0x8 +#define ISAC_CMD_AR10 0x9 +#define ISAC_CMD_ARL 0xA +#define ISAC_CMD_DUI 0xF + +/* ISAC/ISACX/IPAC/IPACX L1 indications */ +#define ISAC_IND_RS 0x1 +#define ISAC_IND_PU 0x7 +#define ISAC_IND_DR 0x0 +#define ISAC_IND_SD 0x2 +#define ISAC_IND_DIS 0x3 +#define ISAC_IND_EI 0x6 +#define ISAC_IND_RSY 0x4 +#define ISAC_IND_ARD 0x8 +#define ISAC_IND_TI 0xA +#define ISAC_IND_ATI 0xB +#define ISAC_IND_AI8 0xC +#define ISAC_IND_AI10 0xD +#define ISAC_IND_DID 0xF + +/* the new ISACX / IPACX */ +/* D-channel registers */ +#define ISACX_RFIFOD 0x00 /* RD */ +#define ISACX_XFIFOD 0x00 /* WR */ +#define ISACX_ISTAD 0x20 /* RD */ +#define ISACX_MASKD 0x20 /* WR */ +#define ISACX_STARD 0x21 /* RD */ +#define ISACX_CMDRD 0x21 /* WR */ +#define ISACX_MODED 0x22 /* R/W */ +#define ISACX_EXMD1 0x23 /* R/W */ +#define ISACX_TIMR1 0x24 /* R/W */ +#define ISACX_SAP1 0x25 /* WR */ +#define ISACX_SAP2 0x26 /* WR */ +#define ISACX_RBCLD 0x26 /* RD */ +#define ISACX_RBCHD 0x27 /* RD */ +#define ISACX_TEI1 0x27 /* WR */ +#define ISACX_TEI2 0x28 /* WR */ +#define ISACX_RSTAD 0x28 /* RD */ +#define ISACX_TMD 0x29 /* R/W */ +#define ISACX_CIR0 0x2E /* RD */ +#define ISACX_CIX0 0x2E /* WR */ +#define ISACX_CIR1 0x2F /* RD */ +#define ISACX_CIX1 0x2F /* WR */ + +/* Transceiver registers */ +#define ISACX_TR_CONF0 0x30 /* R/W */ +#define ISACX_TR_CONF1 0x31 /* R/W */ +#define ISACX_TR_CONF2 0x32 /* R/W */ +#define ISACX_TR_STA 0x33 /* RD */ +#define ISACX_TR_CMD 0x34 /* R/W */ +#define ISACX_SQRR1 0x35 /* RD */ +#define ISACX_SQXR1 0x35 /* WR */ +#define ISACX_SQRR2 0x36 /* RD */ +#define ISACX_SQXR2 0x36 /* WR */ +#define ISACX_SQRR3 0x37 /* RD */ +#define ISACX_SQXR3 0x37 /* WR */ +#define ISACX_ISTATR 0x38 /* RD */ +#define ISACX_MASKTR 0x39 /* R/W */ +#define ISACX_TR_MODE 0x3A /* R/W */ +#define ISACX_ACFG1 0x3C /* R/W */ +#define ISACX_ACFG2 0x3D /* R/W */ +#define ISACX_AOE 0x3E /* R/W */ +#define ISACX_ARX 0x3F /* RD */ +#define ISACX_ATX 0x3F /* WR */ + +/* IOM: Timeslot, DPS, CDA */ +#define ISACX_CDA10 0x40 /* R/W */ +#define ISACX_CDA11 0x41 /* R/W */ +#define ISACX_CDA20 0x42 /* R/W */ +#define ISACX_CDA21 0x43 /* R/W */ +#define ISACX_CDA_TSDP10 0x44 /* R/W */ +#define ISACX_CDA_TSDP11 0x45 /* R/W */ +#define ISACX_CDA_TSDP20 0x46 /* R/W */ +#define ISACX_CDA_TSDP21 0x47 /* R/W */ +#define ISACX_BCHA_TSDP_BC1 0x48 /* R/W */ +#define ISACX_BCHA_TSDP_BC2 0x49 /* R/W */ +#define ISACX_BCHB_TSDP_BC1 0x4A /* R/W */ +#define ISACX_BCHB_TSDP_BC2 0x4B /* R/W */ +#define ISACX_TR_TSDP_BC1 0x4C /* R/W */ +#define ISACX_TR_TSDP_BC2 0x4D /* R/W */ +#define ISACX_CDA1_CR 0x4E /* R/W */ +#define ISACX_CDA2_CR 0x4F /* R/W */ + +/* IOM: Contol, Sync transfer, Monitor */ +#define ISACX_TR_CR 0x50 /* R/W */ +#define ISACX_TRC_CR 0x50 /* R/W */ +#define ISACX_BCHA_CR 0x51 /* R/W */ +#define ISACX_BCHB_CR 0x52 /* R/W */ +#define ISACX_DCI_CR 0x53 /* R/W */ +#define ISACX_DCIC_CR 0x53 /* R/W */ +#define ISACX_MON_CR 0x54 /* R/W */ +#define ISACX_SDS1_CR 0x55 /* R/W */ +#define ISACX_SDS2_CR 0x56 /* R/W */ +#define ISACX_IOM_CR 0x57 /* R/W */ +#define ISACX_STI 0x58 /* RD */ +#define ISACX_ASTI 0x58 /* WR */ +#define ISACX_MSTI 0x59 /* R/W */ +#define ISACX_SDS_CONF 0x5A /* R/W */ +#define ISACX_MCDA 0x5B /* RD */ +#define ISACX_MOR 0x5C /* RD */ +#define ISACX_MOX 0x5C /* WR */ +#define ISACX_MOSR 0x5D /* RD */ +#define ISACX_MOCR 0x5E /* R/W */ +#define ISACX_MSTA 0x5F /* RD */ +#define ISACX_MCONF 0x5F /* WR */ + +/* Interrupt and general registers */ +#define ISACX_ISTA 0x60 /* RD */ +#define ISACX_MASK 0x60 /* WR */ +#define ISACX_AUXI 0x61 /* RD */ +#define ISACX_AUXM 0x61 /* WR */ +#define ISACX_MODE1 0x62 /* R/W */ +#define ISACX_MODE2 0x63 /* R/W */ +#define ISACX_ID 0x64 /* RD */ +#define ISACX_SRES 0x64 /* WR */ +#define ISACX_TIMR2 0x65 /* R/W */ + +/* Register Bits */ +/* ISACX/IPACX _ISTAD (R) and _MASKD (W) */ +#define ISACX_D_XDU 0x04 +#define ISACX_D_XMR 0x08 +#define ISACX_D_XPR 0x10 +#define ISACX_D_RFO 0x20 +#define ISACX_D_RPF 0x40 +#define ISACX_D_RME 0x80 + +/* ISACX/IPACX _ISTA (R) and _MASK (W) */ +#define ISACX__ICD 0x01 +#define ISACX__MOS 0x02 +#define ISACX__TRAN 0x04 +#define ISACX__AUX 0x08 +#define ISACX__CIC 0x10 +#define ISACX__ST 0x20 +#define IPACX__ICB 0x40 +#define IPACX__ICA 0x80 +#define IPACX__ON 0x2C + +/* ISACX/IPACX _CMDRD (W) */ +#define ISACX_CMDRD_XRES 0x01 +#define ISACX_CMDRD_XME 0x02 +#define ISACX_CMDRD_XTF 0x08 +#define ISACX_CMDRD_STI 0x10 +#define ISACX_CMDRD_RRES 0x40 +#define ISACX_CMDRD_RMC 0x80 + +/* ISACX/IPACX _RSTAD (R) */ +#define ISACX_RSTAD_TA 0x01 +#define ISACX_RSTAD_CR 0x02 +#define ISACX_RSTAD_SA0 0x04 +#define ISACX_RSTAD_SA1 0x08 +#define ISACX_RSTAD_RAB 0x10 +#define ISACX_RSTAD_CRC 0x20 +#define ISACX_RSTAD_RDO 0x40 +#define ISACX_RSTAD_VFR 0x80 + +/* ISACX/IPACX _CIR0 (R) */ +#define ISACX_CIR0_BAS 0x01 +#define ISACX_CIR0_SG 0x08 +#define ISACX_CIR0_CIC1 0x08 +#define ISACX_CIR0_CIC0 0x08 + +/* B-channel registers */ +#define IPACX_OFF_ICA 0x70 +#define IPACX_OFF_ICB 0x80 + +/* ICA: IPACX_OFF_ICA + Reg ICB: IPACX_OFF_ICB + Reg */ + +#define IPACX_ISTAB 0x00 /* RD */ +#define IPACX_MASKB 0x00 /* WR */ +#define IPACX_STARB 0x01 /* RD */ +#define IPACX_CMDRB 0x01 /* WR */ +#define IPACX_MODEB 0x02 /* R/W */ +#define IPACX_EXMB 0x03 /* R/W */ +#define IPACX_RAH1 0x05 /* WR */ +#define IPACX_RAH2 0x06 /* WR */ +#define IPACX_RBCLB 0x06 /* RD */ +#define IPACX_RBCHB 0x07 /* RD */ +#define IPACX_RAL1 0x07 /* WR */ +#define IPACX_RAL2 0x08 /* WR */ +#define IPACX_RSTAB 0x08 /* RD */ +#define IPACX_TMB 0x09 /* R/W */ +#define IPACX_RFIFOB 0x0A /* RD */ +#define IPACX_XFIFOB 0x0A /* WR */ + +/* IPACX_ISTAB / IPACX_MASKB bits */ +#define IPACX_B_XDU 0x04 +#define IPACX_B_XPR 0x10 +#define IPACX_B_RFO 0x20 +#define IPACX_B_RPF 0x40 +#define IPACX_B_RME 0x80 + +#define IPACX_B_ON 0x0B + +extern int mISDNisac_init(struct isac_hw *, void *); +extern irqreturn_t mISDNisac_irq(struct isac_hw *, u8); +extern u32 mISDNipac_init(struct ipac_hw *, void *); +extern irqreturn_t mISDNipac_irq(struct ipac_hw *, int); diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c new file mode 100644 index 0000000..62441ba --- /dev/null +++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c @@ -0,0 +1,1178 @@ +/* + * mISDNinfineon.c + * Support for cards based on following Infineon ISDN chipsets + * - ISAC + HSCX + * - IPAC and IPAC-X + * - ISAC-SX + HSCX + * + * Supported cards: + * - Dialogic Diva 2.0 + * - Dialogic Diva 2.0U + * - Dialogic Diva 2.01 + * - Dialogic Diva 2.02 + * - Sedlbauer Speedwin + * - HST Saphir3 + * - Develo (former ELSA) Microlink PCI (Quickstep 1000) + * - Develo (former ELSA) Quickstep 3000 + * - Berkom Scitel BRIX Quadro + * - Dr.Neuhaus (Sagem) Niccy + * + * + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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 "ipac.h" + +#define INFINEON_REV "1.0" + +static int inf_cnt; +static u32 debug; +static u32 irqloops = 4; + +enum inf_types { + INF_NONE, + INF_DIVA20, + INF_DIVA20U, + INF_DIVA201, + INF_DIVA202, + INF_SPEEDWIN, + INF_SAPHIR3, + INF_QS1000, + INF_QS3000, + INF_NICCY, + INF_SCT_1, + INF_SCT_2, + INF_SCT_3, + INF_SCT_4, + INF_GAZEL_R685, + INF_GAZEL_R753 +}; + +enum addr_mode { + AM_NONE = 0, + AM_IO, + AM_MEMIO, + AM_IND_IO, +}; + +struct inf_cinfo { + enum inf_types typ; + const char *full; + const char *name; + enum addr_mode cfg_mode; + enum addr_mode addr_mode; + u8 cfg_bar; + u8 addr_bar; + void *irqfunc; +}; + +struct _ioaddr { + enum addr_mode mode; + union { + void __iomem *p; + struct _ioport io; + } a; +}; + +struct _iohandle { + enum addr_mode mode; + resource_size_t size; + resource_size_t start; + void __iomem *p; +}; + +struct inf_hw { + struct list_head list; + struct pci_dev *pdev; + const struct inf_cinfo *ci; + char name[MISDN_MAX_IDLEN]; + u32 irq; + u32 irqcnt; + struct _iohandle cfg; + struct _iohandle addr; + struct _ioaddr isac; + struct _ioaddr hscx; + spinlock_t lock; /* HW access lock */ + struct ipac_hw ipac; + struct inf_hw *sc[3]; /* slave cards */ +}; + + +#define PCI_SUBVENDOR_HST_SAPHIR3 0x52 +#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 +#define PCI_SUB_ID_SEDLBAUER 0x01 + +static struct pci_device_id infineon_ids[] __devinitdata = { + { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20}, + { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20U}, + { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA201}, + { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA202}, + { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, + PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0, + INF_SPEEDWIN}, + { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, + PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3}, + { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS1000}, + { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_QS3000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS3000}, + { PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_NICCY}, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0, + INF_SCT_1}, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R685, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R685}, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R753, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753}, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753}, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_OLITEC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753}, + { } +}; +MODULE_DEVICE_TABLE(pci, infineon_ids); + +/* PCI interface specific defines */ +/* Diva 2.0/2.0U */ +#define DIVA_HSCX_PORT 0x00 +#define DIVA_HSCX_ALE 0x04 +#define DIVA_ISAC_PORT 0x08 +#define DIVA_ISAC_ALE 0x0C +#define DIVA_PCI_CTRL 0x10 + +/* DIVA_PCI_CTRL bits */ +#define DIVA_IRQ_BIT 0x01 +#define DIVA_RESET_BIT 0x08 +#define DIVA_EEPROM_CLK 0x40 +#define DIVA_LED_A 0x10 +#define DIVA_LED_B 0x20 +#define DIVA_IRQ_CLR 0x80 + +/* Diva 2.01/2.02 */ +/* Siemens PITA */ +#define PITA_ICR_REG 0x00 +#define PITA_INT0_STATUS 0x02 + +#define PITA_MISC_REG 0x1c +#define PITA_PARA_SOFTRESET 0x01000000 +#define PITA_SER_SOFTRESET 0x02000000 +#define PITA_PARA_MPX_MODE 0x04000000 +#define PITA_INT0_ENABLE 0x00020000 + +/* TIGER 100 Registers */ +#define TIGER_RESET_ADDR 0x00 +#define TIGER_EXTERN_RESET 0x01 +#define TIGER_AUX_CTRL 0x02 +#define TIGER_AUX_DATA 0x03 +#define TIGER_AUX_IRQMASK 0x05 +#define TIGER_AUX_STATUS 0x07 + +/* Tiger AUX BITs */ +#define TIGER_IOMASK 0xdd /* 1 and 5 are inputs */ +#define TIGER_IRQ_BIT 0x02 + +#define TIGER_IPAC_ALE 0xC0 +#define TIGER_IPAC_PORT 0xC8 + +/* ELSA (now Develo) PCI cards */ +#define ELSA_IRQ_ADDR 0x4c +#define ELSA_IRQ_MASK 0x04 +#define QS1000_IRQ_OFF 0x01 +#define QS3000_IRQ_OFF 0x03 +#define QS1000_IRQ_ON 0x41 +#define QS3000_IRQ_ON 0x43 + +/* Dr Neuhaus/Sagem Niccy */ +#define NICCY_ISAC_PORT 0x00 +#define NICCY_HSCX_PORT 0x01 +#define NICCY_ISAC_ALE 0x02 +#define NICCY_HSCX_ALE 0x03 + +#define NICCY_IRQ_CTRL_REG 0x38 +#define NICCY_IRQ_ENABLE 0x001f00 +#define NICCY_IRQ_DISABLE 0xff0000 +#define NICCY_IRQ_BIT 0x800000 + + +/* Scitel PLX */ +#define SCT_PLX_IRQ_ADDR 0x4c +#define SCT_PLX_RESET_ADDR 0x50 +#define SCT_PLX_IRQ_ENABLE 0x41 +#define SCT_PLX_RESET_BIT 0x04 + +/* Gazel */ +#define GAZEL_IPAC_DATA_PORT 0x04 +/* Gazel PLX */ +#define GAZEL_CNTRL 0x50 +#define GAZEL_RESET 0x04 +#define GAZEL_RESET_9050 0x40000000 +#define GAZEL_INCSR 0x4C +#define GAZEL_ISAC_EN 0x08 +#define GAZEL_INT_ISAC 0x20 +#define GAZEL_HSCX_EN 0x01 +#define GAZEL_INT_HSCX 0x04 +#define GAZEL_PCI_EN 0x40 +#define GAZEL_IPAC_EN 0x03 + + +static LIST_HEAD(Cards); +static DEFINE_RWLOCK(card_lock); /* protect Cards */ + +static void +_set_debug(struct inf_hw *card) +{ + card->ipac.isac.dch.debug = debug; + card->ipac.hscx[0].bch.debug = debug; + card->ipac.hscx[1].bch.debug = debug; +} + +static int +set_debug(const char *val, struct kernel_param *kp) +{ + int ret; + struct inf_hw *card; + + ret = param_set_uint(val, kp); + if (!ret) { + read_lock(&card_lock); + list_for_each_entry(card, &Cards, list) + _set_debug(card); + read_unlock(&card_lock); + } + return ret; +} + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(INFINEON_REV); +module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "infineon debug mask"); +module_param(irqloops, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)"); + +/* Interface functions */ + +IOFUNC_IO(ISAC, inf_hw, isac.a.io) +IOFUNC_IO(IPAC, inf_hw, hscx.a.io) +IOFUNC_IND(ISAC, inf_hw, isac.a.io) +IOFUNC_IND(IPAC, inf_hw, hscx.a.io) +IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p) +IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p) + +static irqreturn_t +diva_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u8 val; + + spin_lock(&hw->lock); + val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL); + if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */ + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +diva20x_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u8 val; + + spin_lock(&hw->lock); + val = readb(hw->cfg.p); + if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */ + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */ + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +tiger_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u8 val; + + spin_lock(&hw->lock); + val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS); + if (val & TIGER_IRQ_BIT) { /* for us or shared ? */ + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +elsa_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u8 val; + + spin_lock(&hw->lock); + val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR); + if (!(val & ELSA_IRQ_MASK)) { + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +niccy_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u32 val; + + spin_lock(&hw->lock); + val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */ + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +gazel_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + irqreturn_t ret; + + spin_lock(&hw->lock); + ret = mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return ret; +} + +static irqreturn_t +ipac_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u8 val; + + spin_lock(&hw->lock); + val = hw->ipac.read_reg(hw, IPAC_ISTA); + if (!(val & 0x3f)) { + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static void +enable_hwirq(struct inf_hw *hw) +{ + u16 w; + u32 val; + + switch (hw->ci->typ) { + case INF_DIVA201: + case INF_DIVA202: + writel(PITA_INT0_ENABLE, hw->cfg.p); + break; + case INF_SPEEDWIN: + case INF_SAPHIR3: + outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK); + break; + case INF_QS1000: + outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR); + break; + case INF_QS3000: + outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR); + break; + case INF_NICCY: + val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + val |= NICCY_IRQ_ENABLE;; + outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + break; + case INF_SCT_1: + w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); + w |= SCT_PLX_IRQ_ENABLE; + outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); + break; + case INF_GAZEL_R685: + outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN, + (u32)hw->cfg.start + GAZEL_INCSR); + break; + case INF_GAZEL_R753: + outb(GAZEL_IPAC_EN + GAZEL_PCI_EN, + (u32)hw->cfg.start + GAZEL_INCSR); + break; + default: + break; + } +} + +static void +disable_hwirq(struct inf_hw *hw) +{ + u16 w; + u32 val; + + switch (hw->ci->typ) { + case INF_DIVA201: + case INF_DIVA202: + writel(0, hw->cfg.p); + break; + case INF_SPEEDWIN: + case INF_SAPHIR3: + outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK); + break; + case INF_QS1000: + outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR); + break; + case INF_QS3000: + outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR); + break; + case INF_NICCY: + val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + val &= NICCY_IRQ_DISABLE; + outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + break; + case INF_SCT_1: + w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); + w &= (~SCT_PLX_IRQ_ENABLE); + outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); + break; + case INF_GAZEL_R685: + case INF_GAZEL_R753: + outb(0, (u32)hw->cfg.start + GAZEL_INCSR); + break; + default: + break; + } +} + +static void +ipac_chip_reset(struct inf_hw *hw) +{ + hw->ipac.write_reg(hw, IPAC_POTA2, 0x20); + mdelay(5); + hw->ipac.write_reg(hw, IPAC_POTA2, 0x00); + mdelay(5); + hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf); + hw->ipac.write_reg(hw, IPAC_MASK, 0xc0); +} + +static void +reset_inf(struct inf_hw *hw) +{ + u16 w; + u32 val; + + if (debug & DEBUG_HW) + pr_notice("%s: resetting card\n", hw->name); + switch (hw->ci->typ) { + case INF_DIVA20: + case INF_DIVA20U: + outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL); + mdelay(10); + outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL); + mdelay(10); + /* Workaround PCI9060 */ + outb(9, (u32)hw->cfg.start + 0x69); + outb(DIVA_RESET_BIT | DIVA_LED_A, + (u32)hw->cfg.start + DIVA_PCI_CTRL); + break; + case INF_DIVA201: + writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, + hw->cfg.p + PITA_MISC_REG); + mdelay(1); + writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG); + mdelay(10); + break; + case INF_DIVA202: + writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, + hw->cfg.p + PITA_MISC_REG); + mdelay(1); + writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET, + hw->cfg.p + PITA_MISC_REG); + mdelay(10); + break; + case INF_SPEEDWIN: + case INF_SAPHIR3: + ipac_chip_reset(hw); + hw->ipac.write_reg(hw, IPAC_ACFG, 0xff); + hw->ipac.write_reg(hw, IPAC_AOE, 0x00); + hw->ipac.write_reg(hw, IPAC_PCFG, 0x12); + break; + case INF_QS1000: + case INF_QS3000: + ipac_chip_reset(hw); + hw->ipac.write_reg(hw, IPAC_ACFG, 0x00); + hw->ipac.write_reg(hw, IPAC_AOE, 0x3c); + hw->ipac.write_reg(hw, IPAC_ATX, 0xff); + break; + case INF_NICCY: + break; + case INF_SCT_1: + w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR); + w &= (~SCT_PLX_RESET_BIT); + outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR); + mdelay(10); + w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR); + w |= SCT_PLX_RESET_BIT; + outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR); + mdelay(10); + break; + case INF_GAZEL_R685: + val = inl((u32)hw->cfg.start + GAZEL_CNTRL); + val |= (GAZEL_RESET_9050 + GAZEL_RESET); + outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); + val &= ~(GAZEL_RESET_9050 + GAZEL_RESET); + mdelay(4); + outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); + mdelay(10); + hw->ipac.isac.adf2 = 0x87; + hw->ipac.hscx[0].slot = 0x1f; + hw->ipac.hscx[0].slot = 0x23; + break; + case INF_GAZEL_R753: + val = inl((u32)hw->cfg.start + GAZEL_CNTRL); + val |= (GAZEL_RESET_9050 + GAZEL_RESET); + outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); + val &= ~(GAZEL_RESET_9050 + GAZEL_RESET); + mdelay(4); + outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); + mdelay(10); + ipac_chip_reset(hw); + hw->ipac.write_reg(hw, IPAC_ACFG, 0xff); + hw->ipac.write_reg(hw, IPAC_AOE, 0x00); + hw->ipac.conf = 0x01; /* IOM off */ + break; + default: + return; + } + enable_hwirq(hw); +} + +static int +inf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg) +{ + int ret = 0; + + switch (cmd) { + case HW_RESET_REQ: + reset_inf(hw); + break; + default: + pr_info("%s: %s unknown command %x %lx\n", + hw->name, __func__, cmd, arg); + ret = -EINVAL; + break; + } + return ret; +} + +static int __devinit +init_irq(struct inf_hw *hw) +{ + int ret, cnt = 3; + u_long flags; + + if (!hw->ci->irqfunc) + return -EINVAL; + ret = request_irq(hw->irq, hw->ci->irqfunc, IRQF_SHARED, hw->name, hw); + if (ret) { + pr_info("%s: couldn't get interrupt %d\n", hw->name, hw->irq); + return ret; + } + while (cnt--) { + spin_lock_irqsave(&hw->lock, flags); + reset_inf(hw); + ret = hw->ipac.init(&hw->ipac); + if (ret) { + spin_unlock_irqrestore(&hw->lock, flags); + pr_info("%s: ISAC init failed with %d\n", + hw->name, ret); + break; + } + spin_unlock_irqrestore(&hw->lock, flags); + msleep_interruptible(10); + if (debug & DEBUG_HW) + pr_notice("%s: IRQ %d count %d\n", hw->name, + hw->irq, hw->irqcnt); + if (!hw->irqcnt) { + pr_info("%s: IRQ(%d) got no requests during init %d\n", + hw->name, hw->irq, 3 - cnt); + } else + return 0; + } + free_irq(hw->irq, hw); + return -EIO; +} + +static void +release_io(struct inf_hw *hw) +{ + if (hw->cfg.mode) { + if (hw->cfg.p) { + release_mem_region(hw->cfg.start, hw->cfg.size); + iounmap(hw->cfg.p); + } else + release_region(hw->cfg.start, hw->cfg.size); + hw->cfg.mode = AM_NONE; + } + if (hw->addr.mode) { + if (hw->addr.p) { + release_mem_region(hw->addr.start, hw->addr.size); + iounmap(hw->addr.p); + } else + release_region(hw->addr.start, hw->addr.size); + hw->addr.mode = AM_NONE; + } +} + +static int __devinit +setup_io(struct inf_hw *hw) +{ + int err = 0; + + if (hw->ci->cfg_mode) { + hw->cfg.start = pci_resource_start(hw->pdev, hw->ci->cfg_bar); + hw->cfg.size = pci_resource_len(hw->pdev, hw->ci->cfg_bar); + if (hw->ci->cfg_mode == AM_MEMIO) { + if (!request_mem_region(hw->cfg.start, hw->cfg.size, + hw->name)) + err = -EBUSY; + } else { + if (!request_region(hw->cfg.start, hw->cfg.size, + hw->name)) + err = -EBUSY; + } + if (err) { + pr_info("mISDN: %s config port %lx (%lu bytes)" + "already in use\n", hw->name, + (ulong)hw->cfg.start, (ulong)hw->cfg.size); + return err; + } + if (hw->ci->cfg_mode == AM_MEMIO) + hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size); + hw->cfg.mode = hw->ci->cfg_mode; + if (debug & DEBUG_HW) + pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n", + hw->name, (ulong)hw->cfg.start, + (ulong)hw->cfg.size, hw->ci->cfg_mode); + + } + if (hw->ci->addr_mode) { + hw->addr.start = pci_resource_start(hw->pdev, hw->ci->addr_bar); + hw->addr.size = pci_resource_len(hw->pdev, hw->ci->addr_bar); + if (hw->ci->addr_mode == AM_MEMIO) { + if (!request_mem_region(hw->addr.start, hw->addr.size, + hw->name)) + err = -EBUSY; + } else { + if (!request_region(hw->addr.start, hw->addr.size, + hw->name)) + err = -EBUSY; + } + if (err) { + pr_info("mISDN: %s address port %lx (%lu bytes)" + "already in use\n", hw->name, + (ulong)hw->addr.start, (ulong)hw->addr.size); + return err; + } + if (hw->ci->addr_mode == AM_MEMIO) + hw->addr.p = ioremap(hw->addr.start, hw->addr.size); + hw->addr.mode = hw->ci->addr_mode; + if (debug & DEBUG_HW) + pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n", + hw->name, (ulong)hw->addr.start, + (ulong)hw->addr.size, hw->ci->addr_mode); + + } + + switch (hw->ci->typ) { + case INF_DIVA20: + case INF_DIVA20U: + hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; + hw->isac.mode = hw->cfg.mode; + hw->isac.a.io.ale = (u32)hw->cfg.start + DIVA_ISAC_ALE; + hw->isac.a.io.port = (u32)hw->cfg.start + DIVA_ISAC_PORT; + hw->hscx.mode = hw->cfg.mode; + hw->hscx.a.io.ale = (u32)hw->cfg.start + DIVA_HSCX_ALE; + hw->hscx.a.io.port = (u32)hw->cfg.start + DIVA_HSCX_PORT; + break; + case INF_DIVA201: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.mode = hw->addr.mode; + hw->isac.a.p = hw->addr.p; + hw->hscx.mode = hw->addr.mode; + hw->hscx.a.p = hw->addr.p; + break; + case INF_DIVA202: + hw->ipac.type = IPAC_TYPE_IPACX; + hw->isac.mode = hw->addr.mode; + hw->isac.a.p = hw->addr.p; + hw->hscx.mode = hw->addr.mode; + hw->hscx.a.p = hw->addr.p; + break; + case INF_SPEEDWIN: + case INF_SAPHIR3: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.mode = hw->cfg.mode; + hw->isac.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE; + hw->isac.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT; + hw->hscx.mode = hw->cfg.mode; + hw->hscx.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE; + hw->hscx.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT; + outb(0xff, (ulong)hw->cfg.start); + mdelay(1); + outb(0x00, (ulong)hw->cfg.start); + mdelay(1); + outb(TIGER_IOMASK, (ulong)hw->cfg.start + TIGER_AUX_CTRL); + break; + case INF_QS1000: + case INF_QS3000: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.a.io.ale = (u32)hw->addr.start; + hw->isac.a.io.port = (u32)hw->addr.start + 1; + hw->isac.mode = hw->addr.mode; + hw->hscx.a.io.ale = (u32)hw->addr.start; + hw->hscx.a.io.port = (u32)hw->addr.start + 1; + hw->hscx.mode = hw->addr.mode; + break; + case INF_NICCY: + hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; + hw->isac.mode = hw->addr.mode; + hw->isac.a.io.ale = (u32)hw->addr.start + NICCY_ISAC_ALE; + hw->isac.a.io.port = (u32)hw->addr.start + NICCY_ISAC_PORT; + hw->hscx.mode = hw->addr.mode; + hw->hscx.a.io.ale = (u32)hw->addr.start + NICCY_HSCX_ALE; + hw->hscx.a.io.port = (u32)hw->addr.start + NICCY_HSCX_PORT; + break; + case INF_SCT_1: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.a.io.ale = (u32)hw->addr.start; + hw->isac.a.io.port = hw->isac.a.io.ale + 4; + hw->isac.mode = hw->addr.mode; + hw->hscx.a.io.ale = hw->isac.a.io.ale; + hw->hscx.a.io.port = hw->isac.a.io.port; + hw->hscx.mode = hw->addr.mode; + break; + case INF_SCT_2: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.a.io.ale = (u32)hw->addr.start + 0x08; + hw->isac.a.io.port = hw->isac.a.io.ale + 4; + hw->isac.mode = hw->addr.mode; + hw->hscx.a.io.ale = hw->isac.a.io.ale; + hw->hscx.a.io.port = hw->isac.a.io.port; + hw->hscx.mode = hw->addr.mode; + break; + case INF_SCT_3: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.a.io.ale = (u32)hw->addr.start + 0x10; + hw->isac.a.io.port = hw->isac.a.io.ale + 4; + hw->isac.mode = hw->addr.mode; + hw->hscx.a.io.ale = hw->isac.a.io.ale; + hw->hscx.a.io.port = hw->isac.a.io.port; + hw->hscx.mode = hw->addr.mode; + break; + case INF_SCT_4: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.a.io.ale = (u32)hw->addr.start + 0x20; + hw->isac.a.io.port = hw->isac.a.io.ale + 4; + hw->isac.mode = hw->addr.mode; + hw->hscx.a.io.ale = hw->isac.a.io.ale; + hw->hscx.a.io.port = hw->isac.a.io.port; + hw->hscx.mode = hw->addr.mode; + break; + case INF_GAZEL_R685: + hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; + hw->ipac.isac.off = 0x80; + hw->isac.mode = hw->addr.mode; + hw->isac.a.io.port = (u32)hw->addr.start; + hw->hscx.mode = hw->addr.mode; + hw->hscx.a.io.port = hw->isac.a.io.port; + break; + case INF_GAZEL_R753: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.mode = hw->addr.mode; + hw->isac.a.io.ale = (u32)hw->addr.start; + hw->isac.a.io.port = (u32)hw->addr.start + GAZEL_IPAC_DATA_PORT; + hw->hscx.mode = hw->addr.mode; + hw->hscx.a.io.ale = hw->isac.a.io.ale; + hw->hscx.a.io.port = hw->isac.a.io.port; + break; + default: + return -EINVAL; + } + switch (hw->isac.mode) { + case AM_MEMIO: + ASSIGN_FUNC_IPAC(MIO, hw->ipac); + break; + case AM_IND_IO: + ASSIGN_FUNC_IPAC(IND, hw->ipac); + break; + case AM_IO: + ASSIGN_FUNC_IPAC(IO, hw->ipac); + break; + default: + return -EINVAL; + } + return 0; +} + +static void +release_card(struct inf_hw *card) { + ulong flags; + int i; + + spin_lock_irqsave(&card->lock, flags); + disable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); + card->ipac.isac.release(&card->ipac.isac); + free_irq(card->irq, card); + mISDN_unregister_device(&card->ipac.isac.dch.dev); + release_io(card); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + switch (card->ci->typ) { + case INF_SCT_2: + case INF_SCT_3: + case INF_SCT_4: + break; + case INF_SCT_1: + for (i = 0; i < 3; i++) { + if (card->sc[i]) + release_card(card->sc[i]); + card->sc[i] = NULL; + } + default: + pci_disable_device(card->pdev); + pci_set_drvdata(card->pdev, NULL); + break; + } + kfree(card); + inf_cnt--; +} + +static int __devinit +setup_instance(struct inf_hw *card) +{ + int err; + ulong flags; + + snprintf(card->name, MISDN_MAX_IDLEN - 1, "%s.%d", card->ci->name, + inf_cnt + 1); + write_lock_irqsave(&card_lock, flags); + list_add_tail(&card->list, &Cards); + write_unlock_irqrestore(&card_lock, flags); + + _set_debug(card); + card->ipac.isac.name = card->name; + card->ipac.name = card->name; + card->ipac.owner = THIS_MODULE; + spin_lock_init(&card->lock); + card->ipac.isac.hwlock = &card->lock; + card->ipac.hwlock = &card->lock; + card->ipac.ctrl = (void *)&inf_ctrl; + + err = setup_io(card); + if (err) + goto error_setup; + + card->ipac.isac.dch.dev.Bprotocols = + mISDNipac_init(&card->ipac, card); + + if (card->ipac.isac.dch.dev.Bprotocols == 0) + goto error_setup;; + + err = mISDN_register_device(&card->ipac.isac.dch.dev, + &card->pdev->dev, card->name); + if (err) + goto error; + + err = init_irq(card); + if (!err) { + inf_cnt++; + pr_notice("Infineon %d cards installed\n", inf_cnt); + return 0; + } + mISDN_unregister_device(&card->ipac.isac.dch.dev); +error: + card->ipac.release(&card->ipac); +error_setup: + release_io(card); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + return err; +} + +static const struct inf_cinfo inf_card_info[] = { + { + INF_DIVA20, + "Dialogic Diva 2.0", + "diva20", + AM_IND_IO, AM_NONE, 2, 0, + &diva_irq + }, + { + INF_DIVA20U, + "Dialogic Diva 2.0U", + "diva20U", + AM_IND_IO, AM_NONE, 2, 0, + &diva_irq + }, + { + INF_DIVA201, + "Dialogic Diva 2.01", + "diva201", + AM_MEMIO, AM_MEMIO, 0, 1, + &diva20x_irq + }, + { + INF_DIVA202, + "Dialogic Diva 2.02", + "diva202", + AM_MEMIO, AM_MEMIO, 0, 1, + &diva20x_irq + }, + { + INF_SPEEDWIN, + "Sedlbauer SpeedWin PCI", + "speedwin", + AM_IND_IO, AM_NONE, 0, 0, + &tiger_irq + }, + { + INF_SAPHIR3, + "HST Saphir 3", + "saphir", + AM_IND_IO, AM_NONE, 0, 0, + &tiger_irq + }, + { + INF_QS1000, + "Develo Microlink PCI", + "qs1000", + AM_IO, AM_IND_IO, 1, 3, + &elsa_irq + }, + { + INF_QS3000, + "Develo QuickStep 3000", + "qs3000", + AM_IO, AM_IND_IO, 1, 3, + &elsa_irq + }, + { + INF_NICCY, + "Sagem NICCY", + "niccy", + AM_IO, AM_IND_IO, 0, 1, + &niccy_irq + }, + { + INF_SCT_1, + "SciTel Quadro", + "p1_scitel", + AM_IO, AM_IND_IO, 1, 5, + &ipac_irq + }, + { + INF_SCT_2, + "SciTel Quadro", + "p2_scitel", + AM_NONE, AM_IND_IO, 0, 4, + &ipac_irq + }, + { + INF_SCT_3, + "SciTel Quadro", + "p3_scitel", + AM_NONE, AM_IND_IO, 0, 3, + &ipac_irq + }, + { + INF_SCT_4, + "SciTel Quadro", + "p4_scitel", + AM_NONE, AM_IND_IO, 0, 2, + &ipac_irq + }, + { + INF_GAZEL_R685, + "Gazel R685", + "gazel685", + AM_IO, AM_IO, 1, 2, + &gazel_irq + }, + { + INF_GAZEL_R753, + "Gazel R753", + "gazel753", + AM_IO, AM_IND_IO, 1, 2, + &ipac_irq + }, + { + INF_NONE, + } +}; + +static const struct inf_cinfo * __devinit +get_card_info(enum inf_types typ) +{ + const struct inf_cinfo *ci = inf_card_info; + + while (ci->typ != INF_NONE) { + if (ci->typ == typ) + return ci; + ci++; + } + return NULL; +} + +static int __devinit +inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = -ENOMEM; + struct inf_hw *card; + + card = kzalloc(sizeof(struct inf_hw), GFP_KERNEL); + if (!card) { + pr_info("No memory for Infineon ISDN card\n"); + return err; + } + card->pdev = pdev; + err = pci_enable_device(pdev); + if (err) { + kfree(card); + return err; + } + card->ci = get_card_info(ent->driver_data); + if (!card->ci) { + pr_info("mISDN: do not have informations about adapter at %s\n", + pci_name(pdev)); + kfree(card); + return -EINVAL; + } else + pr_notice("mISDN: found adapter %s at %s\n", + card->ci->full, pci_name(pdev)); + + card->irq = pdev->irq; + pci_set_drvdata(pdev, card); + err = setup_instance(card); + if (err) { + pci_disable_device(card->pdev); + kfree(card); + pci_set_drvdata(pdev, NULL); + } else if (ent->driver_data == INF_SCT_1) { + int i; + struct inf_hw *sc; + + for (i = 1; i < 4; i++) { + sc = kzalloc(sizeof(struct inf_hw), GFP_KERNEL); + if (!sc) { + release_card(card); + return -ENOMEM; + } + sc->irq = card->irq; + sc->pdev = card->pdev; + sc->ci = card->ci + i; + err = setup_instance(sc); + if (err) { + kfree(sc); + release_card(card); + } else + card->sc[i - 1] = sc; + } + } + return err; +} + +static void __devexit +inf_remove(struct pci_dev *pdev) +{ + struct inf_hw *card = pci_get_drvdata(pdev); + + if (card) + release_card(card); + else + pr_debug("%s: drvdata allready removed\n", __func__); +} + +static struct pci_driver infineon_driver = { + .name = "ISDN Infineon pci", + .probe = inf_probe, + .remove = __devexit_p(inf_remove), + .id_table = infineon_ids, +}; + +static int __init +infineon_init(void) +{ + int err; + + pr_notice("Infineon ISDN Driver Rev. %s\n", INFINEON_REV); + err = pci_register_driver(&infineon_driver); + return err; +} + +static void __exit +infineon_cleanup(void) +{ + pci_unregister_driver(&infineon_driver); +} + +module_init(infineon_init); +module_exit(infineon_cleanup); diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c new file mode 100644 index 0000000..613ba04 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -0,0 +1,1655 @@ +/* + * isac.c ISAC specific routines + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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 "ipac.h" + + +#define DBUSY_TIMER_VALUE 80 +#define ARCOFI_USE 1 + +#define ISAC_REV "2.0" + +MODULE_AUTHOR("Karsten Keil"); +MODULE_VERSION(ISAC_REV); +MODULE_LICENSE("GPL v2"); + +#define ReadISAC(is, o) (is->read_reg(is->dch.hw, o + is->off)) +#define WriteISAC(is, o, v) (is->write_reg(is->dch.hw, o + is->off, v)) +#define ReadHSCX(h, o) (h->ip->read_reg(h->ip->hw, h->off + o)) +#define WriteHSCX(h, o, v) (h->ip->write_reg(h->ip->hw, h->off + o, v)) +#define ReadIPAC(ip, o) (ip->read_reg(ip->hw, o)) +#define WriteIPAC(ip, o, v) (ip->write_reg(ip->hw, o, v)) + +static inline void +ph_command(struct isac_hw *isac, u8 command) +{ + pr_debug("%s: ph_command %x\n", isac->name, command); + if (isac->type & IPAC_TYPE_ISACX) + WriteISAC(isac, ISACX_CIX0, (command << 4) | 0xE); + else + WriteISAC(isac, ISAC_CIX0, (command << 2) | 3); +} + +static void +isac_ph_state_change(struct isac_hw *isac) +{ + switch (isac->state) { + case (ISAC_IND_RS): + case (ISAC_IND_EI): + ph_command(isac, ISAC_CMD_DUI); + } + schedule_event(&isac->dch, FLG_PHCHANGE); +} + +static void +isac_ph_state_bh(struct dchannel *dch) +{ + struct isac_hw *isac = container_of(dch, struct isac_hw, dch); + + switch (isac->state) { + case ISAC_IND_RS: + case ISAC_IND_EI: + dch->state = 0; + l1_event(dch->l1, HW_RESET_IND); + break; + case ISAC_IND_DID: + dch->state = 3; + l1_event(dch->l1, HW_DEACT_CNF); + break; + case ISAC_IND_DR: + dch->state = 3; + l1_event(dch->l1, HW_DEACT_IND); + break; + case ISAC_IND_PU: + dch->state = 4; + l1_event(dch->l1, HW_POWERUP_IND); + break; + case ISAC_IND_RSY: + if (dch->state <= 5) { + dch->state = 5; + l1_event(dch->l1, ANYSIGNAL); + } else { + dch->state = 8; + l1_event(dch->l1, LOSTFRAMING); + } + break; + case ISAC_IND_ARD: + dch->state = 6; + l1_event(dch->l1, INFO2); + break; + case ISAC_IND_AI8: + dch->state = 7; + l1_event(dch->l1, INFO4_P8); + break; + case ISAC_IND_AI10: + dch->state = 7; + l1_event(dch->l1, INFO4_P10); + break; + } + pr_debug("%s: TE newstate %x\n", isac->name, dch->state); +} + +void +isac_empty_fifo(struct isac_hw *isac, int count) +{ + u8 *ptr; + + pr_debug("%s: %s %d\n", isac->name, __func__, count); + + if (!isac->dch.rx_skb) { + isac->dch.rx_skb = mI_alloc_skb(isac->dch.maxlen, GFP_ATOMIC); + if (!isac->dch.rx_skb) { + pr_info("%s: D receive out of memory\n", isac->name); + WriteISAC(isac, ISAC_CMDR, 0x80); + return; + } + } + if ((isac->dch.rx_skb->len + count) >= isac->dch.maxlen) { + pr_debug("%s: %s overrun %d\n", isac->name, __func__, + isac->dch.rx_skb->len + count); + WriteISAC(isac, ISAC_CMDR, 0x80); + return; + } + ptr = skb_put(isac->dch.rx_skb, count); + isac->read_fifo(isac->dch.hw, isac->off, ptr, count); + WriteISAC(isac, ISAC_CMDR, 0x80); + if (isac->dch.debug & DEBUG_HW_DFIFO) { + char pfx[MISDN_MAX_IDLEN + 16]; + + snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-recv %s %d ", + isac->name, count); + print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static void +isac_fill_fifo(struct isac_hw *isac) +{ + int count, more; + u8 *ptr; + + if (!isac->dch.tx_skb) + return; + count = isac->dch.tx_skb->len - isac->dch.tx_idx; + if (count <= 0) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + pr_debug("%s: %s %d\n", isac->name, __func__, count); + ptr = isac->dch.tx_skb->data + isac->dch.tx_idx; + isac->dch.tx_idx += count; + isac->write_fifo(isac->dch.hw, isac->off, ptr, count); + WriteISAC(isac, ISAC_CMDR, more ? 0x8 : 0xa); + if (test_and_set_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) { + pr_debug("%s: %s dbusytimer running\n", isac->name, __func__); + del_timer(&isac->dch.timer); + } + init_timer(&isac->dch.timer); + isac->dch.timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); + add_timer(&isac->dch.timer); + if (isac->dch.debug & DEBUG_HW_DFIFO) { + char pfx[MISDN_MAX_IDLEN + 16]; + + snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-send %s %d ", + isac->name, count); + print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static void +isac_rme_irq(struct isac_hw *isac) +{ + u8 val, count; + + val = ReadISAC(isac, ISAC_RSTA); + if ((val & 0x70) != 0x20) { + if (val & 0x40) { + pr_debug("%s: ISAC RDO\n", isac->name); +#ifdef ERROR_STATISTIC + isac->dch.err_rx++; +#endif + } + if (!(val & 0x20)) { + pr_debug("%s: ISAC CRC error\n", isac->name); +#ifdef ERROR_STATISTIC + isac->dch.err_crc++; +#endif + } + WriteISAC(isac, ISAC_CMDR, 0x80); + if (isac->dch.rx_skb) + dev_kfree_skb(isac->dch.rx_skb); + isac->dch.rx_skb = NULL; + } else { + count = ReadISAC(isac, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(isac, count); + recv_Dchannel(&isac->dch); + } +} + +static void +isac_xpr_irq(struct isac_hw *isac) +{ + if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) + del_timer(&isac->dch.timer); + if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) { + isac_fill_fifo(isac); + } else { + if (isac->dch.tx_skb) + dev_kfree_skb(isac->dch.tx_skb); + if (get_next_dframe(&isac->dch)) + isac_fill_fifo(isac); + } +} + +static void +isac_retransmit(struct isac_hw *isac) +{ + if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) + del_timer(&isac->dch.timer); + if (test_bit(FLG_TX_BUSY, &isac->dch.Flags)) { + /* Restart frame */ + isac->dch.tx_idx = 0; + isac_fill_fifo(isac); + } else if (isac->dch.tx_skb) { /* should not happen */ + pr_info("%s: tx_skb exist but not busy\n", isac->name); + test_and_set_bit(FLG_TX_BUSY, &isac->dch.Flags); + isac->dch.tx_idx = 0; + isac_fill_fifo(isac); + } else { + pr_info("%s: ISAC XDU no TX_BUSY\n", isac->name); + if (get_next_dframe(&isac->dch)) + isac_fill_fifo(isac); + } +} + +static void +isac_mos_irq(struct isac_hw *isac) +{ + u8 val; + int ret; + + val = ReadISAC(isac, ISAC_MOSR); + pr_debug("%s: ISAC MOSR %02x\n", isac->name, val); +#if ARCOFI_USE + if (val & 0x08) { + if (!isac->mon_rx) { + isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); + if (!isac->mon_rx) { + pr_info("%s: ISAC MON RX out of memory!\n", + isac->name); + isac->mocr &= 0xf0; + isac->mocr |= 0x0a; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + goto afterMONR0; + } else + isac->mon_rxp = 0; + } + if (isac->mon_rxp >= MAX_MON_FRAME) { + isac->mocr &= 0xf0; + isac->mocr |= 0x0a; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mon_rxp = 0; + pr_debug("%s: ISAC MON RX overflow!\n", isac->name); + goto afterMONR0; + } + isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR0); + pr_debug("%s: ISAC MOR0 %02x\n", isac->name, + isac->mon_rx[isac->mon_rxp - 1]); + if (isac->mon_rxp == 1) { + isac->mocr |= 0x04; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + } + } +afterMONR0: + if (val & 0x80) { + if (!isac->mon_rx) { + isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); + if (!isac->mon_rx) { + pr_info("%s: ISAC MON RX out of memory!\n", + isac->name); + isac->mocr &= 0x0f; + isac->mocr |= 0xa0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + goto afterMONR1; + } else + isac->mon_rxp = 0; + } + if (isac->mon_rxp >= MAX_MON_FRAME) { + isac->mocr &= 0x0f; + isac->mocr |= 0xa0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mon_rxp = 0; + pr_debug("%s: ISAC MON RX overflow!\n", isac->name); + goto afterMONR1; + } + isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR1); + pr_debug("%s: ISAC MOR1 %02x\n", isac->name, + isac->mon_rx[isac->mon_rxp - 1]); + isac->mocr |= 0x40; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + } +afterMONR1: + if (val & 0x04) { + isac->mocr &= 0xf0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mocr |= 0x0a; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + if (isac->monitor) { + ret = isac->monitor(isac->dch.hw, MONITOR_RX_0, + isac->mon_rx, isac->mon_rxp); + if (ret) + kfree(isac->mon_rx); + } else { + pr_info("%s: MONITOR 0 received %d but no user\n", + isac->name, isac->mon_rxp); + kfree(isac->mon_rx); + } + isac->mon_rx = NULL; + isac->mon_rxp = 0; + } + if (val & 0x40) { + isac->mocr &= 0x0f; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mocr |= 0xa0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + if (isac->monitor) { + ret = isac->monitor(isac->dch.hw, MONITOR_RX_1, + isac->mon_rx, isac->mon_rxp); + if (ret) + kfree(isac->mon_rx); + } else { + pr_info("%s: MONITOR 1 received %d but no user\n", + isac->name, isac->mon_rxp); + kfree(isac->mon_rx); + } + isac->mon_rx = NULL; + isac->mon_rxp = 0; + } + if (val & 0x02) { + if ((!isac->mon_tx) || (isac->mon_txc && + (isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) { + isac->mocr &= 0xf0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mocr |= 0x0a; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { + if (isac->monitor) + ret = isac->monitor(isac->dch.hw, + MONITOR_TX_0, NULL, 0); + } + kfree(isac->mon_tx); + isac->mon_tx = NULL; + isac->mon_txc = 0; + isac->mon_txp = 0; + goto AfterMOX0; + } + if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { + if (isac->monitor) + ret = isac->monitor(isac->dch.hw, + MONITOR_TX_0, NULL, 0); + kfree(isac->mon_tx); + isac->mon_tx = NULL; + isac->mon_txc = 0; + isac->mon_txp = 0; + goto AfterMOX0; + } + WriteISAC(isac, ISAC_MOX0, isac->mon_tx[isac->mon_txp++]); + pr_debug("%s: ISAC %02x -> MOX0\n", isac->name, + isac->mon_tx[isac->mon_txp - 1]); + } +AfterMOX0: + if (val & 0x20) { + if ((!isac->mon_tx) || (isac->mon_txc && + (isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) { + isac->mocr &= 0x0f; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mocr |= 0xa0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { + if (isac->monitor) + ret = isac->monitor(isac->dch.hw, + MONITOR_TX_1, NULL, 0); + } + kfree(isac->mon_tx); + isac->mon_tx = NULL; + isac->mon_txc = 0; + isac->mon_txp = 0; + goto AfterMOX1; + } + if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { + if (isac->monitor) + ret = isac->monitor(isac->dch.hw, + MONITOR_TX_1, NULL, 0); + kfree(isac->mon_tx); + isac->mon_tx = NULL; + isac->mon_txc = 0; + isac->mon_txp = 0; + goto AfterMOX1; + } + WriteISAC(isac, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]); + pr_debug("%s: ISAC %02x -> MOX1\n", isac->name, + isac->mon_tx[isac->mon_txp - 1]); + } +AfterMOX1: + val = 0; /* dummy to avoid warning */ +#endif +} + +static void +isac_cisq_irq(struct isac_hw *isac) { + u8 val; + + val = ReadISAC(isac, ISAC_CIR0); + pr_debug("%s: ISAC CIR0 %02X\n", isac->name, val); + if (val & 2) { + pr_debug("%s: ph_state change %x->%x\n", isac->name, + isac->state, (val >> 2) & 0xf); + isac->state = (val >> 2) & 0xf; + isac_ph_state_change(isac); + } + if (val & 1) { + val = ReadISAC(isac, ISAC_CIR1); + pr_debug("%s: ISAC CIR1 %02X\n", isac->name, val); + } +} + +static void +isacsx_cic_irq(struct isac_hw *isac) +{ + u8 val; + + val = ReadISAC(isac, ISACX_CIR0); + pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val); + if (val & ISACX_CIR0_CIC0) { + pr_debug("%s: ph_state change %x->%x\n", isac->name, + isac->state, val >> 4); + isac->state = val >> 4; + isac_ph_state_change(isac); + } +} + +static void +isacsx_rme_irq(struct isac_hw *isac) +{ + int count; + u8 val; + + val = ReadISAC(isac, ISACX_RSTAD); + if ((val & (ISACX_RSTAD_VFR | + ISACX_RSTAD_RDO | + ISACX_RSTAD_CRC | + ISACX_RSTAD_RAB)) + != (ISACX_RSTAD_VFR | ISACX_RSTAD_CRC)) { + pr_debug("%s: RSTAD %#x, dropped\n", isac->name, val); +#ifdef ERROR_STATISTIC + if (val & ISACX_RSTAD_CRC) + isac->dch.err_rx++; + else + isac->dch.err_crc++; +#endif + WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC); + if (isac->dch.rx_skb) + dev_kfree_skb(isac->dch.rx_skb); + isac->dch.rx_skb = NULL; + } else { + count = ReadISAC(isac, ISACX_RBCLD) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(isac, count); + if (isac->dch.rx_skb) { + skb_trim(isac->dch.rx_skb, isac->dch.rx_skb->len - 1); + pr_debug("%s: dchannel received %d\n", isac->name, + isac->dch.rx_skb->len); + recv_Dchannel(&isac->dch); + } + } +} + +irqreturn_t +mISDNisac_irq(struct isac_hw *isac, u8 val) +{ + if (unlikely(!val)) + return IRQ_NONE; + pr_debug("%s: ISAC interrupt %02x\n", isac->name, val); + if (isac->type & IPAC_TYPE_ISACX) { + if (val & ISACX__CIC) + isacsx_cic_irq(isac); + if (val & ISACX__ICD) { + val = ReadISAC(isac, ISACX_ISTAD); + pr_debug("%s: ISTAD %02x\n", isac->name, val); + if (val & ISACX_D_XDU) { + pr_debug("%s: ISAC XDU\n", isac->name); +#ifdef ERROR_STATISTIC + isac->dch.err_tx++; +#endif + isac_retransmit(isac); + } + if (val & ISACX_D_XMR) { + pr_debug("%s: ISAC XMR\n", isac->name); +#ifdef ERROR_STATISTIC + isac->dch.err_tx++; +#endif + isac_retransmit(isac); + } + if (val & ISACX_D_XPR) + isac_xpr_irq(isac); + if (val & ISACX_D_RFO) { + pr_debug("%s: ISAC RFO\n", isac->name); + WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC); + } + if (val & ISACX_D_RME) + isacsx_rme_irq(isac); + if (val & ISACX_D_RPF) + isac_empty_fifo(isac, 0x20); + } + } else { + if (val & 0x80) /* RME */ + isac_rme_irq(isac); + if (val & 0x40) /* RPF */ + isac_empty_fifo(isac, 32); + if (val & 0x10) /* XPR */ + isac_xpr_irq(isac); + if (val & 0x04) /* CISQ */ + isac_cisq_irq(isac); + if (val & 0x20) /* RSC - never */ + pr_debug("%s: ISAC RSC interrupt\n", isac->name); + if (val & 0x02) /* SIN - never */ + pr_debug("%s: ISAC SIN interrupt\n", isac->name); + if (val & 0x01) { /* EXI */ + val = ReadISAC(isac, ISAC_EXIR); + pr_debug("%s: ISAC EXIR %02x\n", isac->name, val); + if (val & 0x80) /* XMR */ + pr_debug("%s: ISAC XMR\n", isac->name); + if (val & 0x40) { /* XDU */ + pr_debug("%s: ISAC XDU\n", isac->name); +#ifdef ERROR_STATISTIC + isac->dch.err_tx++; +#endif + isac_retransmit(isac); + } + if (val & 0x04) /* MOS */ + isac_mos_irq(isac); + } + } + return IRQ_HANDLED; +} +EXPORT_SYMBOL(mISDNisac_irq); + +static int +isac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct isac_hw *isac = container_of(dch, struct isac_hw, dch); + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(isac->hwlock, flags); + ret = dchannel_senddata(dch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + isac_fill_fifo(isac); + ret = 0; + spin_unlock_irqrestore(isac->hwlock, flags); + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(isac->hwlock, flags); + return ret; + case PH_ACTIVATE_REQ: + ret = l1_event(dch->l1, hh->prim); + break; + case PH_DEACTIVATE_REQ: + test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); + ret = l1_event(dch->l1, hh->prim); + break; + } + + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +isac_ctrl(struct isac_hw *isac, u32 cmd, u_long para) +{ + u8 tl = 0; + u_long flags; + + switch (cmd) { + case HW_TESTLOOP: + spin_lock_irqsave(isac->hwlock, flags); + if (!(isac->type & IPAC_TYPE_ISACX)) { + /* TODO: implement for IPAC_TYPE_ISACX */ + if (para & 1) /* B1 */ + tl |= 0x0c; + else if (para & 2) /* B2 */ + tl |= 0x3; + /* we only support IOM2 mode */ + WriteISAC(isac, ISAC_SPCR, tl); + if (tl) + WriteISAC(isac, ISAC_ADF1, 0x8); + else + WriteISAC(isac, ISAC_ADF1, 0x0); + } + spin_unlock_irqrestore(isac->hwlock, flags); + break; + default: + pr_debug("%s: %s unknown command %x %lx\n", isac->name, + __func__, cmd, para); + return -1; + } + return 0; +} + +static int +isac_l1cmd(struct dchannel *dch, u32 cmd) +{ + struct isac_hw *isac = container_of(dch, struct isac_hw, dch); + u_long flags; + + pr_debug("%s: cmd(%x) state(%02x)\n", isac->name, cmd, isac->state); + switch (cmd) { + case INFO3_P8: + spin_lock_irqsave(isac->hwlock, flags); + ph_command(isac, ISAC_CMD_AR8); + spin_unlock_irqrestore(isac->hwlock, flags); + break; + case INFO3_P10: + spin_lock_irqsave(isac->hwlock, flags); + ph_command(isac, ISAC_CMD_AR10); + spin_unlock_irqrestore(isac->hwlock, flags); + break; + case HW_RESET_REQ: + spin_lock_irqsave(isac->hwlock, flags); + if ((isac->state == ISAC_IND_EI) || + (isac->state == ISAC_IND_DR) || + (isac->state == ISAC_IND_RS)) + ph_command(isac, ISAC_CMD_TIM); + else + ph_command(isac, ISAC_CMD_RS); + spin_unlock_irqrestore(isac->hwlock, flags); + break; + case HW_DEACT_REQ: + skb_queue_purge(&dch->squeue); + if (dch->tx_skb) { + dev_kfree_skb(dch->tx_skb); + dch->tx_skb = NULL; + } + dch->tx_idx = 0; + if (dch->rx_skb) { + dev_kfree_skb(dch->rx_skb); + dch->rx_skb = NULL; + } + test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); + if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) + del_timer(&dch->timer); + break; + case HW_POWERUP_REQ: + spin_lock_irqsave(isac->hwlock, flags); + ph_command(isac, ISAC_CMD_TIM); + spin_unlock_irqrestore(isac->hwlock, flags); + break; + case PH_ACTIVATE_IND: + test_and_set_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, + GFP_ATOMIC); + break; + case PH_DEACTIVATE_IND: + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, + GFP_ATOMIC); + break; + default: + pr_debug("%s: %s unknown command %x\n", isac->name, + __func__, cmd); + return -1; + } + return 0; +} + +static void +isac_release(struct isac_hw *isac) +{ + if (isac->type & IPAC_TYPE_ISACX) + WriteISAC(isac, ISACX_MASK, 0xff); + else + WriteISAC(isac, ISAC_MASK, 0xff); + if (isac->dch.timer.function != NULL) { + del_timer(&isac->dch.timer); + isac->dch.timer.function = NULL; + } + kfree(isac->mon_rx); + isac->mon_rx = NULL; + kfree(isac->mon_tx); + isac->mon_tx = NULL; + if (isac->dch.l1) + l1_event(isac->dch.l1, CLOSE_CHANNEL); + mISDN_freedchannel(&isac->dch); +} + +static void +dbusy_timer_handler(struct isac_hw *isac) +{ + int rbch, star; + u_long flags; + + if (test_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) { + spin_lock_irqsave(isac->hwlock, flags); + rbch = ReadISAC(isac, ISAC_RBCH); + star = ReadISAC(isac, ISAC_STAR); + pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n", + isac->name, rbch, star); + if (rbch & ISAC_RBCH_XAC) /* D-Channel Busy */ + test_and_set_bit(FLG_L1_BUSY, &isac->dch.Flags); + else { + /* discard frame; reset transceiver */ + test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags); + if (isac->dch.tx_idx) + isac->dch.tx_idx = 0; + else + pr_info("%s: ISAC D-Channel Busy no tx_idx\n", + isac->name); + /* Transmitter reset */ + WriteISAC(isac, ISAC_CMDR, 0x01); + } + spin_unlock_irqrestore(isac->hwlock, flags); + } +} + +static int +open_dchannel(struct isac_hw *isac, struct channel_req *rq) +{ + pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__, + isac->dch.dev.id, __builtin_return_address(1)); + if (rq->protocol != ISDN_P_TE_S0) + return -EINVAL; + if (rq->adr.channel == 1) + /* E-Channel not supported */ + return -EINVAL; + rq->ch = &isac->dch.dev.D; + rq->ch->protocol = rq->protocol; + if (isac->dch.state == 7) + _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY, + 0, NULL, GFP_KERNEL); + return 0; +} + +static const char *ISACVer[] = +{"2086/2186 V1.1", "2085 B1", "2085 B2", + "2085 V2.3"}; + +static int +isac_init(struct isac_hw *isac) +{ + u8 val; + int err = 0; + + if (!isac->dch.l1) { + err = create_l1(&isac->dch, isac_l1cmd); + if (err) + return err; + } + isac->mon_tx = NULL; + isac->mon_rx = NULL; + isac->dch.timer.function = (void *) dbusy_timer_handler; + isac->dch.timer.data = (long)isac; + init_timer(&isac->dch.timer); + isac->mocr = 0xaa; + if (isac->type & IPAC_TYPE_ISACX) { + /* Disable all IRQ */ + WriteISAC(isac, ISACX_MASK, 0xff); + val = ReadISAC(isac, ISACX_STARD); + pr_debug("%s: ISACX STARD %x\n", isac->name, val); + val = ReadISAC(isac, ISACX_ISTAD); + pr_debug("%s: ISACX ISTAD %x\n", isac->name, val); + val = ReadISAC(isac, ISACX_ISTA); + pr_debug("%s: ISACX ISTA %x\n", isac->name, val); + /* clear LDD */ + WriteISAC(isac, ISACX_TR_CONF0, 0x00); + /* enable transmitter */ + WriteISAC(isac, ISACX_TR_CONF2, 0x00); + /* transparent mode 0, RAC, stop/go */ + WriteISAC(isac, ISACX_MODED, 0xc9); + /* all HDLC IRQ unmasked */ + val = ReadISAC(isac, ISACX_ID); + if (isac->dch.debug & DEBUG_HW) + pr_notice("%s: ISACX Design ID %x\n", + isac->name, val & 0x3f); + val = ReadISAC(isac, ISACX_CIR0); + pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val); + isac->state = val >> 4; + isac_ph_state_change(isac); + ph_command(isac, ISAC_CMD_RS); + WriteISAC(isac, ISACX_MASK, IPACX__ON); + WriteISAC(isac, ISACX_MASKD, 0x00); + } else { /* old isac */ + WriteISAC(isac, ISAC_MASK, 0xff); + val = ReadISAC(isac, ISAC_STAR); + pr_debug("%s: ISAC STAR %x\n", isac->name, val); + val = ReadISAC(isac, ISAC_MODE); + pr_debug("%s: ISAC MODE %x\n", isac->name, val); + val = ReadISAC(isac, ISAC_ADF2); + pr_debug("%s: ISAC ADF2 %x\n", isac->name, val); + val = ReadISAC(isac, ISAC_ISTA); + pr_debug("%s: ISAC ISTA %x\n", isac->name, val); + if (val & 0x01) { + val = ReadISAC(isac, ISAC_EXIR); + pr_debug("%s: ISAC EXIR %x\n", isac->name, val); + } + val = ReadISAC(isac, ISAC_RBCH); + if (isac->dch.debug & DEBUG_HW) + pr_notice("%s: ISAC version (%x): %s\n", isac->name, + val, ISACVer[(val >> 5) & 3]); + isac->type |= ((val >> 5) & 3); + if (!isac->adf2) + isac->adf2 = 0x80; + if (!(isac->adf2 & 0x80)) { /* only IOM 2 Mode */ + pr_info("%s: only support IOM2 mode but adf2=%02x\n", + isac->name, isac->adf2); + isac_release(isac); + return -EINVAL; + } + WriteISAC(isac, ISAC_ADF2, isac->adf2); + WriteISAC(isac, ISAC_SQXR, 0x2f); + WriteISAC(isac, ISAC_SPCR, 0x00); + WriteISAC(isac, ISAC_STCR, 0x70); + WriteISAC(isac, ISAC_MODE, 0xc9); + WriteISAC(isac, ISAC_TIMR, 0x00); + WriteISAC(isac, ISAC_ADF1, 0x00); + val = ReadISAC(isac, ISAC_CIR0); + pr_debug("%s: ISAC CIR0 %x\n", isac->name, val); + isac->state = (val >> 2) & 0xf; + isac_ph_state_change(isac); + ph_command(isac, ISAC_CMD_RS); + WriteISAC(isac, ISAC_MASK, 0); + } + return err; +} + +int +mISDNisac_init(struct isac_hw *isac, void *hw) +{ + mISDN_initdchannel(&isac->dch, MAX_DFRAME_LEN_L1, isac_ph_state_bh); + isac->dch.hw = hw; + isac->dch.dev.D.send = isac_l1hw; + isac->init = isac_init; + isac->release = isac_release; + isac->ctrl = isac_ctrl; + isac->open = open_dchannel; + isac->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0); + isac->dch.dev.nrbchan = 2; + return 0; +} +EXPORT_SYMBOL(mISDNisac_init); + +static void +waitforCEC(struct hscx_hw *hx) +{ + u8 starb, to = 50; + + while (to) { + starb = ReadHSCX(hx, IPAC_STARB); + if (!(starb & 0x04)) + break; + udelay(1); + to--; + } + if (to < 50) + pr_debug("%s: B%1d CEC %d us\n", hx->ip->name, hx->bch.nr, + 50 - to); + if (!to) + pr_info("%s: B%1d CEC timeout\n", hx->ip->name, hx->bch.nr); +} + + +static void +waitforXFW(struct hscx_hw *hx) +{ + u8 starb, to = 50; + + while (to) { + starb = ReadHSCX(hx, IPAC_STARB); + if ((starb & 0x44) == 0x40) + break; + udelay(1); + to--; + } + if (to < 50) + pr_debug("%s: B%1d XFW %d us\n", hx->ip->name, hx->bch.nr, + 50 - to); + if (!to) + pr_info("%s: B%1d XFW timeout\n", hx->ip->name, hx->bch.nr); +} + +static void +hscx_cmdr(struct hscx_hw *hx, u8 cmd) +{ + if (hx->ip->type & IPAC_TYPE_IPACX) + WriteHSCX(hx, IPACX_CMDRB, cmd); + else { + waitforCEC(hx); + WriteHSCX(hx, IPAC_CMDRB, cmd); + } +} + +static void +hscx_empty_fifo(struct hscx_hw *hscx, u8 count) +{ + u8 *p; + + pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count); + if (!hscx->bch.rx_skb) { + hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC); + if (!hscx->bch.rx_skb) { + pr_info("%s: B receive out of memory\n", + hscx->ip->name); + hscx_cmdr(hscx, 0x80); /* RMC */ + return; + } + } + if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) { + pr_debug("%s: overrun %d\n", hscx->ip->name, + hscx->bch.rx_skb->len + count); + skb_trim(hscx->bch.rx_skb, 0); + hscx_cmdr(hscx, 0x80); /* RMC */ + return; + } + p = skb_put(hscx->bch.rx_skb, count); + + if (hscx->ip->type & IPAC_TYPE_IPACX) + hscx->ip->read_fifo(hscx->ip->hw, + hscx->off + IPACX_RFIFOB, p, count); + else + hscx->ip->read_fifo(hscx->ip->hw, + hscx->off, p, count); + + hscx_cmdr(hscx, 0x80); /* RMC */ + + if (hscx->bch.debug & DEBUG_HW_BFIFO) { + snprintf(hscx->log, 64, "B%1d-recv %s %d ", + hscx->bch.nr, hscx->ip->name, count); + print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); + } +} + +static void +hscx_fill_fifo(struct hscx_hw *hscx) +{ + int count, more; + u8 *p; + + if (!hscx->bch.tx_skb) + return; + count = hscx->bch.tx_skb->len - hscx->bch.tx_idx; + if (count <= 0) + return; + p = hscx->bch.tx_skb->data + hscx->bch.tx_idx; + + more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0; + if (count > hscx->fifo_size) { + count = hscx->fifo_size; + more = 1; + } + pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, count, + hscx->bch.tx_idx, hscx->bch.tx_skb->len); + hscx->bch.tx_idx += count; + + if (hscx->ip->type & IPAC_TYPE_IPACX) + hscx->ip->write_fifo(hscx->ip->hw, + hscx->off + IPACX_XFIFOB, p, count); + else { + waitforXFW(hscx); + hscx->ip->write_fifo(hscx->ip->hw, + hscx->off, p, count); + } + hscx_cmdr(hscx, more ? 0x08 : 0x0a); + + if (hscx->bch.debug & DEBUG_HW_BFIFO) { + snprintf(hscx->log, 64, "B%1d-send %s %d ", + hscx->bch.nr, hscx->ip->name, count); + print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); + } +} + +static void +hscx_xpr(struct hscx_hw *hx) +{ + if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) + hscx_fill_fifo(hx); + else { + if (hx->bch.tx_skb) { + /* send confirm, on trans, free on hdlc. */ + if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) + confirm_Bsend(&hx->bch); + dev_kfree_skb(hx->bch.tx_skb); + } + if (get_next_bframe(&hx->bch)) + hscx_fill_fifo(hx); + } +} + +static void +ipac_rme(struct hscx_hw *hx) +{ + int count; + u8 rstab; + + if (hx->ip->type & IPAC_TYPE_IPACX) + rstab = ReadHSCX(hx, IPACX_RSTAB); + else + rstab = ReadHSCX(hx, IPAC_RSTAB); + pr_debug("%s: B%1d RSTAB %02x\n", hx->ip->name, hx->bch.nr, rstab); + if ((rstab & 0xf0) != 0xa0) { + /* !(VFR && !RDO && CRC && !RAB) */ + if (!(rstab & 0x80)) { + if (hx->bch.debug & DEBUG_HW_BCHANNEL) + pr_notice("%s: B%1d invalid frame\n", + hx->ip->name, hx->bch.nr); + } + if (rstab & 0x40) { + if (hx->bch.debug & DEBUG_HW_BCHANNEL) + pr_notice("%s: B%1d RDO proto=%x\n", + hx->ip->name, hx->bch.nr, + hx->bch.state); + } + if (!(rstab & 0x20)) { + if (hx->bch.debug & DEBUG_HW_BCHANNEL) + pr_notice("%s: B%1d CRC error\n", + hx->ip->name, hx->bch.nr); + } + hscx_cmdr(hx, 0x80); /* Do RMC */ + return; + } + if (hx->ip->type & IPAC_TYPE_IPACX) + count = ReadHSCX(hx, IPACX_RBCLB); + else + count = ReadHSCX(hx, IPAC_RBCLB); + count &= (hx->fifo_size - 1); + if (count == 0) + count = hx->fifo_size; + hscx_empty_fifo(hx, count); + if (!hx->bch.rx_skb) + return; + if (hx->bch.rx_skb->len < 2) { + pr_debug("%s: B%1d frame to short %d\n", + hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len); + skb_trim(hx->bch.rx_skb, 0); + } else { + skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1); + recv_Bchannel(&hx->bch, 0); + } +} + +static void +ipac_irq(struct hscx_hw *hx, u8 ista) +{ + u8 istab, m, exirb = 0; + + if (hx->ip->type & IPAC_TYPE_IPACX) + istab = ReadHSCX(hx, IPACX_ISTAB); + else if (hx->ip->type & IPAC_TYPE_IPAC) { + istab = ReadHSCX(hx, IPAC_ISTAB); + m = (hx->bch.nr & 1) ? IPAC__EXA : IPAC__EXB; + if (m & ista) { + exirb = ReadHSCX(hx, IPAC_EXIRB); + pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, + hx->bch.nr, exirb); + } + } else if (hx->bch.nr & 2) { /* HSCX B */ + if (ista & (HSCX__EXA | HSCX__ICA)) + ipac_irq(&hx->ip->hscx[0], ista); + if (ista & HSCX__EXB) { + exirb = ReadHSCX(hx, IPAC_EXIRB); + pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, + hx->bch.nr, exirb); + } + istab = ista & 0xF8; + } else { /* HSCX A */ + istab = ReadHSCX(hx, IPAC_ISTAB); + if (ista & HSCX__EXA) { + exirb = ReadHSCX(hx, IPAC_EXIRB); + pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, + hx->bch.nr, exirb); + } + istab = istab & 0xF8; + } + if (exirb & IPAC_B_XDU) + istab |= IPACX_B_XDU; + if (exirb & IPAC_B_RFO) + istab |= IPACX_B_RFO; + pr_debug("%s: B%1d ISTAB %02x\n", hx->ip->name, hx->bch.nr, istab); + + if (!test_bit(FLG_ACTIVE, &hx->bch.Flags)) + return; + + if (istab & IPACX_B_RME) + ipac_rme(hx); + + if (istab & IPACX_B_RPF) { + hscx_empty_fifo(hx, hx->fifo_size); + if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { + /* receive transparent audio data */ + if (hx->bch.rx_skb) + recv_Bchannel(&hx->bch, 0); + } + } + + if (istab & IPACX_B_RFO) { + pr_debug("%s: B%1d RFO error\n", hx->ip->name, hx->bch.nr); + hscx_cmdr(hx, 0x40); /* RRES */ + } + + if (istab & IPACX_B_XPR) + hscx_xpr(hx); + + if (istab & IPACX_B_XDU) { + if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { + hscx_fill_fifo(hx); + return; + } + pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name, + hx->bch.nr, hx->bch.tx_idx); + hx->bch.tx_idx = 0; + hscx_cmdr(hx, 0x01); /* XRES */ + } +} + +irqreturn_t +mISDNipac_irq(struct ipac_hw *ipac, int maxloop) +{ + int cnt = maxloop + 1; + u8 ista, istad; + struct isac_hw *isac = &ipac->isac; + + if (ipac->type & IPAC_TYPE_IPACX) { + ista = ReadIPAC(ipac, ISACX_ISTA); + while (ista && cnt--) { + pr_debug("%s: ISTA %02x\n", ipac->name, ista); + if (ista & IPACX__ICA) + ipac_irq(&ipac->hscx[0], ista); + if (ista & IPACX__ICB) + ipac_irq(&ipac->hscx[1], ista); + if (ista & (ISACX__ICD | ISACX__CIC)) + mISDNisac_irq(&ipac->isac, ista); + ista = ReadIPAC(ipac, ISACX_ISTA); + } + } else if (ipac->type & IPAC_TYPE_IPAC) { + ista = ReadIPAC(ipac, IPAC_ISTA); + while (ista && cnt--) { + pr_debug("%s: ISTA %02x\n", ipac->name, ista); + if (ista & (IPAC__ICD | IPAC__EXD)) { + istad = ReadISAC(isac, ISAC_ISTA); + pr_debug("%s: ISTAD %02x\n", ipac->name, istad); + if (istad & IPAC_D_TIN2) + pr_debug("%s TIN2 irq\n", ipac->name); + if (ista & IPAC__EXD) + istad |= 1; /* ISAC EXI */ + mISDNisac_irq(isac, istad); + } + if (ista & (IPAC__ICA | IPAC__EXA)) + ipac_irq(&ipac->hscx[0], ista); + if (ista & (IPAC__ICB | IPAC__EXB)) + ipac_irq(&ipac->hscx[1], ista); + ista = ReadIPAC(ipac, IPAC_ISTA); + } + } else if (ipac->type & IPAC_TYPE_HSCX) { + while (cnt) { + ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off); + pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista); + if (ista) + ipac_irq(&ipac->hscx[1], ista); + istad = ReadISAC(isac, ISAC_ISTA); + pr_debug("%s: ISTAD %02x\n", ipac->name, istad); + if (istad) + mISDNisac_irq(isac, istad); + if (0 == (ista | istad)) + break; + cnt--; + } + } + if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */ + return IRQ_NONE; + if (cnt < maxloop) + pr_debug("%s: %d irqloops cpu%d\n", ipac->name, + maxloop - cnt, smp_processor_id()); + if (maxloop && !cnt) + pr_notice("%s: %d IRQ LOOP cpu%d\n", ipac->name, + maxloop, smp_processor_id()); + return IRQ_HANDLED; +} +EXPORT_SYMBOL(mISDNipac_irq); + +static int +hscx_mode(struct hscx_hw *hscx, u32 bprotocol) +{ + pr_debug("%s: HSCX %c protocol %x-->%x ch %d\n", hscx->ip->name, + '@' + hscx->bch.nr, hscx->bch.state, bprotocol, hscx->bch.nr); + if (hscx->ip->type & IPAC_TYPE_IPACX) { + if (hscx->bch.nr & 1) { /* B1 and ICA */ + WriteIPAC(hscx->ip, ISACX_BCHA_TSDP_BC1, 0x80); + WriteIPAC(hscx->ip, ISACX_BCHA_CR, 0x88); + } else { /* B2 and ICB */ + WriteIPAC(hscx->ip, ISACX_BCHB_TSDP_BC1, 0x81); + WriteIPAC(hscx->ip, ISACX_BCHB_CR, 0x88); + } + switch (bprotocol) { + case ISDN_P_NONE: /* init */ + WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* rec off */ + WriteHSCX(hscx, IPACX_EXMB, 0x30); /* std adj. */ + WriteHSCX(hscx, IPACX_MASKB, 0xFF); /* ints off */ + hscx_cmdr(hscx, 0x41); + test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_RAW: + WriteHSCX(hscx, IPACX_MODEB, 0x88); /* ex trans */ + WriteHSCX(hscx, IPACX_EXMB, 0x00); /* trans */ + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON); + test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_HDLC: + WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* trans */ + WriteHSCX(hscx, IPACX_EXMB, 0x00); /* hdlc,crc */ + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON); + test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); + break; + default: + pr_info("%s: protocol not known %x\n", hscx->ip->name, + bprotocol); + return -ENOPROTOOPT; + } + } else if (hscx->ip->type & IPAC_TYPE_IPAC) { /* IPAC */ + WriteHSCX(hscx, IPAC_CCR1, 0x82); + WriteHSCX(hscx, IPAC_CCR2, 0x30); + WriteHSCX(hscx, IPAC_XCCR, 0x07); + WriteHSCX(hscx, IPAC_RCCR, 0x07); + WriteHSCX(hscx, IPAC_TSAX, hscx->slot); + WriteHSCX(hscx, IPAC_TSAR, hscx->slot); + switch (bprotocol) { + case ISDN_P_NONE: + WriteHSCX(hscx, IPAC_TSAX, 0x1F); + WriteHSCX(hscx, IPAC_TSAR, 0x1F); + WriteHSCX(hscx, IPAC_MODEB, 0x84); + WriteHSCX(hscx, IPAC_CCR1, 0x82); + WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */ + test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_RAW: + WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */ + WriteHSCX(hscx, IPAC_CCR1, 0x82); + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPAC_MASKB, 0); + test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_HDLC: + WriteHSCX(hscx, IPAC_MODEB, 0x8c); + WriteHSCX(hscx, IPAC_CCR1, 0x8a); + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPAC_MASKB, 0); + test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); + break; + default: + pr_info("%s: protocol not known %x\n", hscx->ip->name, + bprotocol); + return -ENOPROTOOPT; + } + } else if (hscx->ip->type & IPAC_TYPE_HSCX) { /* HSCX */ + WriteHSCX(hscx, IPAC_CCR1, 0x85); + WriteHSCX(hscx, IPAC_CCR2, 0x30); + WriteHSCX(hscx, IPAC_XCCR, 0x07); + WriteHSCX(hscx, IPAC_RCCR, 0x07); + WriteHSCX(hscx, IPAC_TSAX, hscx->slot); + WriteHSCX(hscx, IPAC_TSAR, hscx->slot); + switch (bprotocol) { + case ISDN_P_NONE: + WriteHSCX(hscx, IPAC_TSAX, 0x1F); + WriteHSCX(hscx, IPAC_TSAR, 0x1F); + WriteHSCX(hscx, IPAC_MODEB, 0x84); + WriteHSCX(hscx, IPAC_CCR1, 0x85); + WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */ + test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_RAW: + WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */ + WriteHSCX(hscx, IPAC_CCR1, 0x85); + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPAC_MASKB, 0); + test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_HDLC: + WriteHSCX(hscx, IPAC_MODEB, 0x8c); + WriteHSCX(hscx, IPAC_CCR1, 0x8d); + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPAC_MASKB, 0); + test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); + break; + default: + pr_info("%s: protocol not known %x\n", hscx->ip->name, + bprotocol); + return -ENOPROTOOPT; + } + } else + return -EINVAL; + hscx->bch.state = bprotocol; + return 0; +} + +static int +hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch); + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(hx->ip->hwlock, flags); + ret = bchannel_senddata(bch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + ret = 0; + hscx_fill_fifo(hx); + spin_unlock_irqrestore(hx->ip->hwlock, flags); + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(hx->ip->hwlock, flags); + return ret; + case PH_ACTIVATE_REQ: + spin_lock_irqsave(hx->ip->hwlock, flags); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) + ret = hscx_mode(hx, ch->protocol); + else + ret = 0; + spin_unlock_irqrestore(hx->ip->hwlock, flags); + if (!ret) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + break; + case PH_DEACTIVATE_REQ: + spin_lock_irqsave(hx->ip->hwlock, flags); + mISDN_clear_bchannel(bch); + hscx_mode(hx, ISDN_P_NONE); + spin_unlock_irqrestore(hx->ip->hwlock, flags); + _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + ret = 0; + break; + default: + pr_info("%s: %s unknown prim(%x,%x)\n", + hx->ip->name, __func__, hh->prim, hh->id); + ret = -EINVAL; + } + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + /* Nothing implemented yet */ + case MISDN_CTRL_FILL_EMPTY: + default: + pr_info("%s: unknown Op %x\n", __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch); + int ret = -EINVAL; + u_long flags; + + pr_debug("%s: %s cmd:%x %p\n", hx->ip->name, __func__, cmd, arg); + switch (cmd) { + case CLOSE_CHANNEL: + test_and_clear_bit(FLG_OPEN, &bch->Flags); + if (test_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(hx->ip->hwlock, flags); + mISDN_freebchannel(bch); + hscx_mode(hx, ISDN_P_NONE); + spin_unlock_irqrestore(hx->ip->hwlock, flags); + } else { + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; + } + ch->protocol = ISDN_P_NONE; + ch->peer = NULL; + module_put(hx->ip->owner); + ret = 0; + break; + case CONTROL_CHANNEL: + ret = channel_bctrl(bch, arg); + break; + default: + pr_info("%s: %s unknown prim(%x)\n", + hx->ip->name, __func__, cmd); + } + return ret; +} + +static void +free_ipac(struct ipac_hw *ipac) +{ + isac_release(&ipac->isac); +} + +static const char *HSCXVer[] = +{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7", + "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"}; + + + +static void +hscx_init(struct hscx_hw *hx) +{ + u8 val; + + WriteHSCX(hx, IPAC_RAH2, 0xFF); + WriteHSCX(hx, IPAC_XBCH, 0x00); + WriteHSCX(hx, IPAC_RLCR, 0x00); + + if (hx->ip->type & IPAC_TYPE_HSCX) { + WriteHSCX(hx, IPAC_CCR1, 0x85); + val = ReadHSCX(hx, HSCX_VSTR); + pr_debug("%s: HSCX VSTR %02x\n", hx->ip->name, val); + if (hx->bch.debug & DEBUG_HW) + pr_notice("%s: HSCX version %s\n", hx->ip->name, + HSCXVer[val & 0x0f]); + } else + WriteHSCX(hx, IPAC_CCR1, 0x82); + WriteHSCX(hx, IPAC_CCR2, 0x30); + WriteHSCX(hx, IPAC_XCCR, 0x07); + WriteHSCX(hx, IPAC_RCCR, 0x07); +} + +static int +ipac_init(struct ipac_hw *ipac) +{ + u8 val; + + if (ipac->type & IPAC_TYPE_HSCX) { + hscx_init(&ipac->hscx[0]); + hscx_init(&ipac->hscx[1]); + val = ReadIPAC(ipac, IPAC_ID); + } else if (ipac->type & IPAC_TYPE_IPAC) { + hscx_init(&ipac->hscx[0]); + hscx_init(&ipac->hscx[1]); + WriteIPAC(ipac, IPAC_MASK, IPAC__ON); + val = ReadIPAC(ipac, IPAC_CONF); + /* conf is default 0, but can be overwritten by card setup */ + pr_debug("%s: IPAC CONF %02x/%02x\n", ipac->name, + val, ipac->conf); + WriteIPAC(ipac, IPAC_CONF, ipac->conf); + val = ReadIPAC(ipac, IPAC_ID); + if (ipac->hscx[0].bch.debug & DEBUG_HW) + pr_notice("%s: IPAC Design ID %02x\n", ipac->name, val); + } + /* nothing special for IPACX to do here */ + return isac_init(&ipac->isac); +} + +static int +open_bchannel(struct ipac_hw *ipac, struct channel_req *rq) +{ + struct bchannel *bch; + + if (rq->adr.channel > 2) + return -EINVAL; + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + bch = &ipac->hscx[rq->adr.channel - 1].bch; + if (test_and_set_bit(FLG_OPEN, &bch->Flags)) + return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + bch->ch.protocol = rq->protocol; + rq->ch = &bch->ch; + return 0; +} + +static int +channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_LOOP; + break; + case MISDN_CTRL_LOOP: + /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ + if (cq->channel < 0 || cq->channel > 3) { + ret = -EINVAL; + break; + } + ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel); + break; + default: + pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct isac_hw *isac = container_of(dch, struct isac_hw, dch); + struct ipac_hw *ipac = container_of(isac, struct ipac_hw, isac); + struct channel_req *rq; + int err = 0; + + pr_debug("%s: DCTRL: %x %p\n", ipac->name, cmd, arg); + switch (cmd) { + case OPEN_CHANNEL: + rq = arg; + if (rq->protocol == ISDN_P_TE_S0) + err = open_dchannel(isac, rq); + else + err = open_bchannel(ipac, rq); + if (err) + break; + if (!try_module_get(ipac->owner)) + pr_info("%s: cannot get module\n", ipac->name); + break; + case CLOSE_CHANNEL: + pr_debug("%s: dev(%d) close from %p\n", ipac->name, + dch->dev.id, __builtin_return_address(0)); + module_put(ipac->owner); + break; + case CONTROL_CHANNEL: + err = channel_ctrl(ipac, arg); + break; + default: + pr_debug("%s: unknown DCTRL command %x\n", ipac->name, cmd); + return -EINVAL; + } + return err; +} + +u32 +mISDNipac_init(struct ipac_hw *ipac, void *hw) +{ + u32 ret; + u8 i; + + ipac->hw = hw; + if (ipac->isac.dch.debug & DEBUG_HW) + pr_notice("%s: ipac type %x\n", ipac->name, ipac->type); + if (ipac->type & IPAC_TYPE_HSCX) { + ipac->isac.type = IPAC_TYPE_ISAC; + ipac->hscx[0].off = 0; + ipac->hscx[1].off = 0x40; + ipac->hscx[0].fifo_size = 32; + ipac->hscx[1].fifo_size = 32; + } else if (ipac->type & IPAC_TYPE_IPAC) { + ipac->isac.type = IPAC_TYPE_IPAC | IPAC_TYPE_ISAC; + ipac->hscx[0].off = 0; + ipac->hscx[1].off = 0x40; + ipac->hscx[0].fifo_size = 64; + ipac->hscx[1].fifo_size = 64; + } else if (ipac->type & IPAC_TYPE_IPACX) { + ipac->isac.type = IPAC_TYPE_IPACX | IPAC_TYPE_ISACX; + ipac->hscx[0].off = IPACX_OFF_ICA; + ipac->hscx[1].off = IPACX_OFF_ICB; + ipac->hscx[0].fifo_size = 64; + ipac->hscx[1].fifo_size = 64; + } else + return 0; + + mISDNisac_init(&ipac->isac, hw); + + ipac->isac.dch.dev.D.ctrl = ipac_dctrl; + + for (i = 0; i < 2; i++) { + ipac->hscx[i].bch.nr = i + 1; + set_channelmap(i + 1, ipac->isac.dch.dev.channelmap); + list_add(&ipac->hscx[i].bch.ch.list, + &ipac->isac.dch.dev.bchannels); + mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM); + ipac->hscx[i].bch.ch.nr = i + 1; + ipac->hscx[i].bch.ch.send = &hscx_l2l1; + ipac->hscx[i].bch.ch.ctrl = hscx_bctrl; + ipac->hscx[i].bch.hw = hw; + ipac->hscx[i].ip = ipac; + /* default values for IOM time slots + * can be overwriten by card */ + ipac->hscx[i].slot = (i == 0) ? 0x2f : 0x03; + } + + ipac->init = ipac_init; + ipac->release = free_ipac; + + ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + return ret; +} +EXPORT_SYMBOL(mISDNipac_init); + +static int __init +isac_mod_init(void) +{ + pr_notice("mISDNipac module version %s\n", ISAC_REV); + return 0; +} + +static void __exit +isac_mod_cleanup(void) +{ + pr_notice("mISDNipac module unloaded\n"); +} +module_init(isac_mod_init); +module_exit(isac_mod_cleanup); -- cgit v0.10.2 From 6115d2f3fcaebed5b88fa9cefd178bb5b07461ff Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 22 Jul 2009 19:52:24 +0200 Subject: mISDN: Driver for AVM Fritz!CARD PCI Add mISDN driver for AVM FRITZ!CARD PCI (all versions). Signed-off-by: Karsten Keil diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index a8542b8..212dee6 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -39,6 +39,14 @@ config MISDN_HFCUSB Enable support for USB ISDN TAs with Cologne Chip AG's HFC-S USB ISDN Controller +config MISDN_AVMFRITZ + tristate "Support for AVM FRITZ!CARD PCI" + depends on MISDN + depends on PCI + select MISDN_IPAC + help + Enable support for AVMs FRITZ!CARD PCI cards + config MISDN_INFINEON tristate "Support for cards with Infineon chipset" depends on MISDN diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 2863455..8204d84 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o +obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o # chip modules obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c new file mode 100644 index 0000000..81ac541 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -0,0 +1,1152 @@ +/* + * avm_fritz.c low level stuff for AVM FRITZ!CARD PCI ISDN cards + * Thanks to AVM, Berlin for informations + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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 "ipac.h" + + +#define AVMFRITZ_REV "2.1" + +static int AVM_cnt; +static int debug; + +enum { + AVM_FRITZ_PCI, + AVM_FRITZ_PCIV2, +}; + +#define HDLC_FIFO 0x0 +#define HDLC_STATUS 0x4 +#define CHIP_WINDOW 0x10 + +#define CHIP_INDEX 0x4 +#define AVM_HDLC_1 0x00 +#define AVM_HDLC_2 0x01 +#define AVM_ISAC_FIFO 0x02 +#define AVM_ISAC_REG_LOW 0x04 +#define AVM_ISAC_REG_HIGH 0x06 + +#define AVM_STATUS0_IRQ_ISAC 0x01 +#define AVM_STATUS0_IRQ_HDLC 0x02 +#define AVM_STATUS0_IRQ_TIMER 0x04 +#define AVM_STATUS0_IRQ_MASK 0x07 + +#define AVM_STATUS0_RESET 0x01 +#define AVM_STATUS0_DIS_TIMER 0x02 +#define AVM_STATUS0_RES_TIMER 0x04 +#define AVM_STATUS0_ENA_IRQ 0x08 +#define AVM_STATUS0_TESTBIT 0x10 + +#define AVM_STATUS1_INT_SEL 0x0f +#define AVM_STATUS1_ENA_IOM 0x80 + +#define HDLC_MODE_ITF_FLG 0x01 +#define HDLC_MODE_TRANS 0x02 +#define HDLC_MODE_CCR_7 0x04 +#define HDLC_MODE_CCR_16 0x08 +#define HDLC_MODE_TESTLOOP 0x80 + +#define HDLC_INT_XPR 0x80 +#define HDLC_INT_XDU 0x40 +#define HDLC_INT_RPR 0x20 +#define HDLC_INT_MASK 0xE0 + +#define HDLC_STAT_RME 0x01 +#define HDLC_STAT_RDO 0x10 +#define HDLC_STAT_CRCVFRRAB 0x0E +#define HDLC_STAT_CRCVFR 0x06 +#define HDLC_STAT_RML_MASK 0x3f00 + +#define HDLC_CMD_XRS 0x80 +#define HDLC_CMD_XME 0x01 +#define HDLC_CMD_RRS 0x20 +#define HDLC_CMD_XML_MASK 0x3f00 +#define HDLC_FIFO_SIZE 32 + +/* Fritz PCI v2.0 */ + +#define AVM_HDLC_FIFO_1 0x10 +#define AVM_HDLC_FIFO_2 0x18 + +#define AVM_HDLC_STATUS_1 0x14 +#define AVM_HDLC_STATUS_2 0x1c + +#define AVM_ISACX_INDEX 0x04 +#define AVM_ISACX_DATA 0x08 + +/* data struct */ +#define LOG_SIZE 63 + +struct hdlc_stat_reg { +#ifdef __BIG_ENDIAN + u8 fill; + u8 mode; + u8 xml; + u8 cmd; +#else + u8 cmd; + u8 xml; + u8 mode; + u8 fill; +#endif +} __attribute__((packed)); + +struct hdlc_hw { + union { + u32 ctrl; + struct hdlc_stat_reg sr; + } ctrl; + u32 stat; +}; + +struct fritzcard { + struct list_head list; + struct pci_dev *pdev; + char name[MISDN_MAX_IDLEN]; + u8 type; + u8 ctrlreg; + u16 irq; + u32 irqcnt; + u32 addr; + spinlock_t lock; /* hw lock */ + struct isac_hw isac; + struct hdlc_hw hdlc[2]; + struct bchannel bch[2]; + char log[LOG_SIZE + 1]; +}; + +static LIST_HEAD(Cards); +static DEFINE_RWLOCK(card_lock); /* protect Cards */ + +static void +_set_debug(struct fritzcard *card) +{ + card->isac.dch.debug = debug; + card->bch[0].debug = debug; + card->bch[1].debug = debug; +} + +static int +set_debug(const char *val, struct kernel_param *kp) +{ + int ret; + struct fritzcard *card; + + ret = param_set_uint(val, kp); + if (!ret) { + read_lock(&card_lock); + list_for_each_entry(card, &Cards, list) + _set_debug(card); + read_unlock(&card_lock); + } + return ret; +} + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(AVMFRITZ_REV); +module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "avmfritz debug mask"); + +/* Interface functions */ + +static u8 +ReadISAC_V1(void *p, u8 offset) +{ + struct fritzcard *fc = p; + u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; + + outb(idx, fc->addr + CHIP_INDEX); + return inb(fc->addr + CHIP_WINDOW + (offset & 0xf)); +} + +static void +WriteISAC_V1(void *p, u8 offset, u8 value) +{ + struct fritzcard *fc = p; + u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; + + outb(idx, fc->addr + CHIP_INDEX); + outb(value, fc->addr + CHIP_WINDOW + (offset & 0xf)); +} + +static void +ReadFiFoISAC_V1(void *p, u8 off, u8 *data, int size) +{ + struct fritzcard *fc = p; + + outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); + insb(fc->addr + CHIP_WINDOW, data, size); +} + +static void +WriteFiFoISAC_V1(void *p, u8 off, u8 *data, int size) +{ + struct fritzcard *fc = p; + + outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); + outsb(fc->addr + CHIP_WINDOW, data, size); +} + +static u8 +ReadISAC_V2(void *p, u8 offset) +{ + struct fritzcard *fc = p; + + outl(offset, fc->addr + AVM_ISACX_INDEX); + return 0xff & inl(fc->addr + AVM_ISACX_DATA); +} + +static void +WriteISAC_V2(void *p, u8 offset, u8 value) +{ + struct fritzcard *fc = p; + + outl(offset, fc->addr + AVM_ISACX_INDEX); + outl(value, fc->addr + AVM_ISACX_DATA); +} + +static void +ReadFiFoISAC_V2(void *p, u8 off, u8 *data, int size) +{ + struct fritzcard *fc = p; + int i; + + outl(off, fc->addr + AVM_ISACX_INDEX); + for (i = 0; i < size; i++) + data[i] = 0xff & inl(fc->addr + AVM_ISACX_DATA); +} + +static void +WriteFiFoISAC_V2(void *p, u8 off, u8 *data, int size) +{ + struct fritzcard *fc = p; + int i; + + outl(off, fc->addr + AVM_ISACX_INDEX); + for (i = 0; i < size; i++) + outl(data[i], fc->addr + AVM_ISACX_DATA); +} + +static struct bchannel * +Sel_BCS(struct fritzcard *fc, u32 channel) +{ + if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) && + (fc->bch[0].nr & channel)) + return &fc->bch[0]; + else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) && + (fc->bch[1].nr & channel)) + return &fc->bch[1]; + else + return NULL; +} + +static inline void +__write_ctrl_pci(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { + u32 idx = channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1; + + outl(idx, fc->addr + CHIP_INDEX); + outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS); +} + +static inline void +__write_ctrl_pciv2(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { + outl(hdlc->ctrl.ctrl, fc->addr + (channel == 2 ? AVM_HDLC_STATUS_2 : + AVM_HDLC_STATUS_1)); +} + +void +write_ctrl(struct bchannel *bch, int which) { + struct fritzcard *fc = bch->hw; + struct hdlc_hw *hdlc; + + hdlc = &fc->hdlc[(bch->nr - 1) & 1]; + pr_debug("%s: hdlc %c wr%x ctrl %x\n", fc->name, '@' + bch->nr, + which, hdlc->ctrl.ctrl); + switch (fc->type) { + case AVM_FRITZ_PCIV2: + __write_ctrl_pciv2(fc, hdlc, bch->nr); + break; + case AVM_FRITZ_PCI: + __write_ctrl_pci(fc, hdlc, bch->nr); + break; + } +} + + +static inline u32 +__read_status_pci(u_long addr, u32 channel) +{ + outl(channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX); + return inl(addr + CHIP_WINDOW + HDLC_STATUS); +} + +static inline u32 +__read_status_pciv2(u_long addr, u32 channel) +{ + return inl(addr + (channel == 2 ? AVM_HDLC_STATUS_2 : + AVM_HDLC_STATUS_1)); +} + + +static u32 +read_status(struct fritzcard *fc, u32 channel) +{ + switch (fc->type) { + case AVM_FRITZ_PCIV2: + return __read_status_pciv2(fc->addr, channel); + case AVM_FRITZ_PCI: + return __read_status_pci(fc->addr, channel); + } + /* dummy */ + return 0; +} + +static void +enable_hwirq(struct fritzcard *fc) +{ + fc->ctrlreg |= AVM_STATUS0_ENA_IRQ; + outb(fc->ctrlreg, fc->addr + 2); +} + +static void +disable_hwirq(struct fritzcard *fc) +{ + fc->ctrlreg &= ~AVM_STATUS0_ENA_IRQ; + outb(fc->ctrlreg, fc->addr + 2); +} + +static int +modehdlc(struct bchannel *bch, int protocol) +{ + struct fritzcard *fc = bch->hw; + struct hdlc_hw *hdlc; + + hdlc = &fc->hdlc[(bch->nr - 1) & 1]; + pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name, + '@' + bch->nr, bch->state, protocol, bch->nr); + hdlc->ctrl.ctrl = 0; + switch (protocol) { + case -1: /* used for init */ + bch->state = -1; + case ISDN_P_NONE: + if (bch->state == ISDN_P_NONE) + break; + hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; + hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; + write_ctrl(bch, 5); + bch->state = ISDN_P_NONE; + test_and_clear_bit(FLG_HDLC, &bch->Flags); + test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); + break; + case ISDN_P_B_RAW: + bch->state = protocol; + hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; + hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; + write_ctrl(bch, 5); + hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; + write_ctrl(bch, 1); + hdlc->ctrl.sr.cmd = 0; + test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); + break; + case ISDN_P_B_HDLC: + bch->state = protocol; + hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; + hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG; + write_ctrl(bch, 5); + hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; + write_ctrl(bch, 1); + hdlc->ctrl.sr.cmd = 0; + test_and_set_bit(FLG_HDLC, &bch->Flags); + break; + default: + pr_info("%s: protocol not known %x\n", fc->name, protocol); + return -ENOPROTOOPT; + } + return 0; +} + +static void +hdlc_empty_fifo(struct bchannel *bch, int count) +{ + u32 *ptr; + u8 *p; + u32 val, addr; + int cnt = 0; + struct fritzcard *fc = bch->hw; + + pr_debug("%s: %s %d\n", fc->name, __func__, count); + if (!bch->rx_skb) { + bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC); + if (!bch->rx_skb) { + pr_info("%s: B receive out of memory\n", + fc->name); + return; + } + } + if ((bch->rx_skb->len + count) > bch->maxlen) { + pr_debug("%s: overrun %d\n", fc->name, + bch->rx_skb->len + count); + return; + } + p = skb_put(bch->rx_skb, count); + ptr = (u32 *)p; + if (AVM_FRITZ_PCIV2 == fc->type) + addr = fc->addr + (bch->nr == 2 ? + AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); + else { + addr = fc->addr + CHIP_WINDOW; + outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr); + } + while (cnt < count) { + val = le32_to_cpu(inl(addr)); + put_unaligned(val, ptr); + ptr++; + cnt += 4; + } + if (debug & DEBUG_HW_BFIFO) { + snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ", + bch->nr, fc->name, count); + print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); + } +} + +static void +hdlc_fill_fifo(struct bchannel *bch) +{ + struct fritzcard *fc = bch->hw; + struct hdlc_hw *hdlc; + int count, cnt = 0; + u8 *p; + u32 *ptr, val, addr; + + hdlc = &fc->hdlc[(bch->nr - 1) & 1]; + if (!bch->tx_skb) + return; + count = bch->tx_skb->len - bch->tx_idx; + if (count <= 0) + return; + p = bch->tx_skb->data + bch->tx_idx; + hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME; + if (count > HDLC_FIFO_SIZE) { + count = HDLC_FIFO_SIZE; + } else { + if (test_bit(FLG_HDLC, &bch->Flags)) + hdlc->ctrl.sr.cmd |= HDLC_CMD_XME; + } + pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count, + bch->tx_idx, bch->tx_skb->len); + ptr = (u32 *)p; + bch->tx_idx += count; + hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count); + if (AVM_FRITZ_PCIV2 == fc->type) { + __write_ctrl_pciv2(fc, hdlc, bch->nr); + addr = fc->addr + (bch->nr == 2 ? + AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); + } else { + __write_ctrl_pci(fc, hdlc, bch->nr); + addr = fc->addr + CHIP_WINDOW; + } + while (cnt < count) { + val = get_unaligned(ptr); + outl(cpu_to_le32(val), addr); + ptr++; + cnt += 4; + } + if (debug & DEBUG_HW_BFIFO) { + snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ", + bch->nr, fc->name, count); + print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); + } +} + +static void +HDLC_irq_xpr(struct bchannel *bch) +{ + if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) + hdlc_fill_fifo(bch); + else { + if (bch->tx_skb) { + /* send confirm, on trans, free on hdlc. */ + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) + confirm_Bsend(bch); + dev_kfree_skb(bch->tx_skb); + } + if (get_next_bframe(bch)) + hdlc_fill_fifo(bch); + } +} + +static void +HDLC_irq(struct bchannel *bch, u32 stat) +{ + struct fritzcard *fc = bch->hw; + int len; + struct hdlc_hw *hdlc; + + hdlc = &fc->hdlc[(bch->nr - 1) & 1]; + pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat); + if (stat & HDLC_INT_RPR) { + if (stat & HDLC_STAT_RDO) { + hdlc->ctrl.sr.xml = 0; + hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS; + write_ctrl(bch, 1); + hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS; + write_ctrl(bch, 1); + if (bch->rx_skb) + skb_trim(bch->rx_skb, 0); + } else { + len = (stat & HDLC_STAT_RML_MASK) >> 8; + if (!len) + len = 32; + hdlc_empty_fifo(bch, len); + if (!bch->rx_skb) + goto handle_tx; + if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT, + &bch->Flags)) { + if (((stat & HDLC_STAT_CRCVFRRAB) == + HDLC_STAT_CRCVFR) || + test_bit(FLG_TRANSPARENT, &bch->Flags)) { + recv_Bchannel(bch, 0); + } else { + pr_debug("%s: got invalid frame\n", + fc->name); + skb_trim(bch->rx_skb, 0); + } + } + } + } +handle_tx: + if (stat & HDLC_INT_XDU) { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame on HDLC + * in transparent mode we send the next data + */ + if (bch->tx_skb) + pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n", + fc->name, bch->nr, bch->tx_skb->len, + bch->tx_idx, bch->Flags); + else + pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n", + fc->name, bch->nr, bch->Flags); + if (bch->tx_skb && bch->tx_skb->len) { + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + bch->tx_idx = 0; + } + hdlc->ctrl.sr.xml = 0; + hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS; + write_ctrl(bch, 1); + hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS; + HDLC_irq_xpr(bch); + return; + } else if (stat & HDLC_INT_XPR) + HDLC_irq_xpr(bch); +} + +static inline void +HDLC_irq_main(struct fritzcard *fc) +{ + u32 stat; + struct bchannel *bch; + + stat = read_status(fc, 1); + if (stat & HDLC_INT_MASK) { + bch = Sel_BCS(fc, 1); + if (bch) + HDLC_irq(bch, stat); + else + pr_debug("%s: spurious ch1 IRQ\n", fc->name); + } + stat = read_status(fc, 2); + if (stat & HDLC_INT_MASK) { + bch = Sel_BCS(fc, 2); + if (bch) + HDLC_irq(bch, stat); + else + pr_debug("%s: spurious ch2 IRQ\n", fc->name); + } +} + +static irqreturn_t +avm_fritz_interrupt(int intno, void *dev_id) +{ + struct fritzcard *fc = dev_id; + u8 val; + u8 sval; + + spin_lock(&fc->lock); + sval = inb(fc->addr + 2); + pr_debug("%s: irq stat0 %x\n", fc->name, sval); + if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) { + /* shared IRQ from other HW */ + spin_unlock(&fc->lock); + return IRQ_NONE; + } + fc->irqcnt++; + + if (!(sval & AVM_STATUS0_IRQ_ISAC)) { + val = ReadISAC_V1(fc, ISAC_ISTA); + mISDNisac_irq(&fc->isac, val); + } + if (!(sval & AVM_STATUS0_IRQ_HDLC)) + HDLC_irq_main(fc); + spin_unlock(&fc->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +avm_fritzv2_interrupt(int intno, void *dev_id) +{ + struct fritzcard *fc = dev_id; + u8 val; + u8 sval; + + spin_lock(&fc->lock); + sval = inb(fc->addr + 2); + pr_debug("%s: irq stat0 %x\n", fc->name, sval); + if (!(sval & AVM_STATUS0_IRQ_MASK)) { + /* shared IRQ from other HW */ + spin_unlock(&fc->lock); + return IRQ_NONE; + } + fc->irqcnt++; + + if (sval & AVM_STATUS0_IRQ_HDLC) + HDLC_irq_main(fc); + if (sval & AVM_STATUS0_IRQ_ISAC) { + val = ReadISAC_V2(fc, ISACX_ISTA); + mISDNisac_irq(&fc->isac, val); + } + if (sval & AVM_STATUS0_IRQ_TIMER) { + pr_debug("%s: timer irq\n", fc->name); + outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2); + udelay(1); + outb(fc->ctrlreg, fc->addr + 2); + } + spin_unlock(&fc->lock); + return IRQ_HANDLED; +} + +static int +avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct fritzcard *fc = bch->hw; + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(&fc->lock, flags); + ret = bchannel_senddata(bch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + hdlc_fill_fifo(bch); + ret = 0; + spin_unlock_irqrestore(&fc->lock, flags); + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(&fc->lock, flags); + return ret; + case PH_ACTIVATE_REQ: + spin_lock_irqsave(&fc->lock, flags); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) + ret = modehdlc(bch, ch->protocol); + else + ret = 0; + spin_unlock_irqrestore(&fc->lock, flags); + if (!ret) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + break; + case PH_DEACTIVATE_REQ: + spin_lock_irqsave(&fc->lock, flags); + mISDN_clear_bchannel(bch); + modehdlc(bch, ISDN_P_NONE); + spin_unlock_irqrestore(&fc->lock, flags); + _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + ret = 0; + break; + } + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static void +inithdlc(struct fritzcard *fc) +{ + modehdlc(&fc->bch[0], -1); + modehdlc(&fc->bch[1], -1); +} + +void +clear_pending_hdlc_ints(struct fritzcard *fc) +{ + u32 val; + + val = read_status(fc, 1); + pr_debug("%s: HDLC 1 STA %x\n", fc->name, val); + val = read_status(fc, 2); + pr_debug("%s: HDLC 2 STA %x\n", fc->name, val); +} + +static void +reset_avm(struct fritzcard *fc) +{ + switch (fc->type) { + case AVM_FRITZ_PCI: + fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER; + break; + case AVM_FRITZ_PCIV2: + fc->ctrlreg = AVM_STATUS0_RESET; + break; + } + if (debug & DEBUG_HW) + pr_notice("%s: reset\n", fc->name); + disable_hwirq(fc); + mdelay(5); + switch (fc->type) { + case AVM_FRITZ_PCI: + fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER; + disable_hwirq(fc); + outb(AVM_STATUS1_ENA_IOM, fc->addr + 3); + break; + case AVM_FRITZ_PCIV2: + fc->ctrlreg = 0; + disable_hwirq(fc); + break; + } + mdelay(1); + if (debug & DEBUG_HW) + pr_notice("%s: S0/S1 %x/%x\n", fc->name, + inb(fc->addr + 2), inb(fc->addr + 3)); +} + +static int +init_card(struct fritzcard *fc) +{ + int ret, cnt = 3; + u_long flags; + + reset_avm(fc); /* disable IRQ */ + if (fc->type == AVM_FRITZ_PCIV2) + ret = request_irq(fc->irq, avm_fritzv2_interrupt, + IRQF_SHARED, fc->name, fc); + else + ret = request_irq(fc->irq, avm_fritz_interrupt, + IRQF_SHARED, fc->name, fc); + if (ret) { + pr_info("%s: couldn't get interrupt %d\n", + fc->name, fc->irq); + return ret; + } + while (cnt--) { + spin_lock_irqsave(&fc->lock, flags); + ret = fc->isac.init(&fc->isac); + if (ret) { + spin_unlock_irqrestore(&fc->lock, flags); + pr_info("%s: ISAC init failed with %d\n", + fc->name, ret); + break; + } + clear_pending_hdlc_ints(fc); + inithdlc(fc); + enable_hwirq(fc); + /* RESET Receiver and Transmitter */ + if (AVM_FRITZ_PCIV2 == fc->type) { + WriteISAC_V2(fc, ISACX_MASK, 0); + WriteISAC_V2(fc, ISACX_CMDRD, 0x41); + } else { + WriteISAC_V1(fc, ISAC_MASK, 0); + WriteISAC_V1(fc, ISAC_CMDR, 0x41); + } + spin_unlock_irqrestore(&fc->lock, flags); + /* Timeout 10ms */ + msleep_interruptible(10); + if (debug & DEBUG_HW) + pr_notice("%s: IRQ %d count %d\n", fc->name, + fc->irq, fc->irqcnt); + if (!fc->irqcnt) { + pr_info("%s: IRQ(%d) getting no IRQs during init %d\n", + fc->name, fc->irq, 3 - cnt); + reset_avm(fc); + } else + return 0; + } + free_irq(fc->irq, fc); + return -EIO; +} + +static int +channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + struct fritzcard *fc = bch->hw; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + /* Nothing implemented yet */ + case MISDN_CTRL_FILL_EMPTY: + default: + pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct fritzcard *fc = bch->hw; + int ret = -EINVAL; + u_long flags; + + pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); + switch (cmd) { + case CLOSE_CHANNEL: + test_and_clear_bit(FLG_OPEN, &bch->Flags); + if (test_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(&fc->lock, flags); + mISDN_freebchannel(bch); + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); + test_and_clear_bit(FLG_ACTIVE, &bch->Flags); + modehdlc(bch, ISDN_P_NONE); + spin_unlock_irqrestore(&fc->lock, flags); + } + ch->protocol = ISDN_P_NONE; + ch->peer = NULL; + module_put(THIS_MODULE); + ret = 0; + break; + case CONTROL_CHANNEL: + ret = channel_bctrl(bch, arg); + break; + default: + pr_info("%s: %s unknown prim(%x)\n", fc->name, __func__, cmd); + } + return ret; +} + +static int +channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_LOOP; + break; + case MISDN_CTRL_LOOP: + /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ + if (cq->channel < 0 || cq->channel > 3) { + ret = -EINVAL; + break; + } + ret = fc->isac.ctrl(&fc->isac, HW_TESTLOOP, cq->channel); + break; + default: + pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +open_bchannel(struct fritzcard *fc, struct channel_req *rq) +{ + struct bchannel *bch; + + if (rq->adr.channel > 2) + return -EINVAL; + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + bch = &fc->bch[rq->adr.channel - 1]; + if (test_and_set_bit(FLG_OPEN, &bch->Flags)) + return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + bch->ch.protocol = rq->protocol; + rq->ch = &bch->ch; + return 0; +} + +/* + * device control function + */ +static int +avm_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct fritzcard *fc = dch->hw; + struct channel_req *rq; + int err = 0; + + pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); + switch (cmd) { + case OPEN_CHANNEL: + rq = arg; + if (rq->protocol == ISDN_P_TE_S0) + err = fc->isac.open(&fc->isac, rq); + else + err = open_bchannel(fc, rq); + if (err) + break; + if (!try_module_get(THIS_MODULE)) + pr_info("%s: cannot get module\n", fc->name); + break; + case CLOSE_CHANNEL: + pr_debug("%s: dev(%d) close from %p\n", fc->name, dch->dev.id, + __builtin_return_address(0)); + module_put(THIS_MODULE); + break; + case CONTROL_CHANNEL: + err = channel_ctrl(fc, arg); + break; + default: + pr_debug("%s: %s unknown command %x\n", + fc->name, __func__, cmd); + return -EINVAL; + } + return err; +} + +int +setup_fritz(struct fritzcard *fc) +{ + u32 val, ver; + + if (!request_region(fc->addr, 32, fc->name)) { + pr_info("%s: AVM config port %x-%x already in use\n", + fc->name, fc->addr, fc->addr + 31); + return -EIO; + } + switch (fc->type) { + case AVM_FRITZ_PCI: + val = inl(fc->addr); + outl(AVM_HDLC_1, fc->addr + CHIP_INDEX); + ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24; + if (debug & DEBUG_HW) { + pr_notice("%s: PCI stat %#x\n", fc->name, val); + pr_notice("%s: PCI Class %X Rev %d\n", fc->name, + val & 0xff, (val >> 8) & 0xff); + pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); + } + ASSIGN_FUNC(V1, ISAC, fc->isac); + fc->isac.type = IPAC_TYPE_ISAC; + break; + case AVM_FRITZ_PCIV2: + val = inl(fc->addr); + ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24; + if (debug & DEBUG_HW) { + pr_notice("%s: PCI V2 stat %#x\n", fc->name, val); + pr_notice("%s: PCI V2 Class %X Rev %d\n", fc->name, + val & 0xff, (val>>8) & 0xff); + pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); + } + ASSIGN_FUNC(V2, ISAC, fc->isac); + fc->isac.type = IPAC_TYPE_ISACX; + break; + default: + release_region(fc->addr, 32); + pr_info("%s: AVM unknown type %d\n", fc->name, fc->type); + return -ENODEV; + } + pr_notice("%s: %s config irq:%d base:0x%X\n", fc->name, + (fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!CARD PCI" : + "AVM Fritz!CARD PCIv2", fc->irq, fc->addr); + return 0; +} + +static void +release_card(struct fritzcard *card) +{ + u_long flags; + + disable_hwirq(card); + spin_lock_irqsave(&card->lock, flags); + modehdlc(&card->bch[0], ISDN_P_NONE); + modehdlc(&card->bch[1], ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); + card->isac.release(&card->isac); + free_irq(card->irq, card); + mISDN_freebchannel(&card->bch[1]); + mISDN_freebchannel(&card->bch[0]); + mISDN_unregister_device(&card->isac.dch.dev); + release_region(card->addr, 32); + pci_disable_device(card->pdev); + pci_set_drvdata(card->pdev, NULL); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + kfree(card); + AVM_cnt--; +} + +static int __devinit +setup_instance(struct fritzcard *card) +{ + int i, err; + u_long flags; + + snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1); + write_lock_irqsave(&card_lock, flags); + list_add_tail(&card->list, &Cards); + write_unlock_irqrestore(&card_lock, flags); + + _set_debug(card); + card->isac.name = card->name; + spin_lock_init(&card->lock); + card->isac.hwlock = &card->lock; + mISDNisac_init(&card->isac, card); + + card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + card->isac.dch.dev.D.ctrl = avm_dctrl; + for (i = 0; i < 2; i++) { + card->bch[i].nr = i + 1; + set_channelmap(i + 1, card->isac.dch.dev.channelmap); + mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); + card->bch[i].hw = card; + card->bch[i].ch.send = avm_l2l1B; + card->bch[i].ch.ctrl = avm_bctrl; + card->bch[i].ch.nr = i + 1; + list_add(&card->bch[i].ch.list, &card->isac.dch.dev.bchannels); + } + err = setup_fritz(card); + if (err) + goto error; + err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev, + card->name); + if (err) + goto error_reg; + err = init_card(card); + if (!err) { + AVM_cnt++; + pr_notice("AVM %d cards installed DEBUG\n", AVM_cnt); + return 0; + } + mISDN_unregister_device(&card->isac.dch.dev); +error_reg: + release_region(card->addr, 32); +error: + card->isac.release(&card->isac); + mISDN_freebchannel(&card->bch[1]); + mISDN_freebchannel(&card->bch[0]); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + kfree(card); + return err; +} + +static int __devinit +fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = -ENOMEM; + struct fritzcard *card; + + card = kzalloc(sizeof(struct fritzcard), GFP_KERNEL); + if (!card) { + pr_info("No kmem for fritzcard\n"); + return err; + } + if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) + card->type = AVM_FRITZ_PCIV2; + else + card->type = AVM_FRITZ_PCI; + card->pdev = pdev; + err = pci_enable_device(pdev); + if (err) { + kfree(card); + return err; + } + + pr_notice("mISDN: found adapter %s at %s\n", + (char *) ent->driver_data, pci_name(pdev)); + + card->addr = pci_resource_start(pdev, 1); + card->irq = pdev->irq; + pci_set_drvdata(pdev, card); + err = setup_instance(card); + if (err) + pci_set_drvdata(pdev, NULL); + return err; +} + +static void __devexit +fritz_remove_pci(struct pci_dev *pdev) +{ + struct fritzcard *card = pci_get_drvdata(pdev); + + if (card) + release_card(card); + else + if (debug) + pr_info("%s: drvdata allready removed\n", __func__); +} + +static struct pci_device_id fcpci_ids[] __devinitdata = { + { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, (unsigned long) "Fritz!Card PCI"}, + { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, (unsigned long) "Fritz!Card PCI v2" }, + { } +}; +MODULE_DEVICE_TABLE(pci, fcpci_ids); + +static struct pci_driver fcpci_driver = { + .name = "fcpci", + .probe = fritzpci_probe, + .remove = __devexit_p(fritz_remove_pci), + .id_table = fcpci_ids, +}; + +static int __init AVM_init(void) +{ + int err; + + pr_notice("AVM Fritz PCI driver Rev. %s\n", AVMFRITZ_REV); + err = pci_register_driver(&fcpci_driver); + return err; +} + +static void __exit AVM_cleanup(void) +{ + pci_unregister_driver(&fcpci_driver); +} + +module_init(AVM_init); +module_exit(AVM_cleanup); -- cgit v0.10.2 From da2272c91ae81b41ae6fa6ebdc767a6cef73b770 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 22 Jul 2009 20:01:59 +0200 Subject: mISDN: Add support for Speedfax+ cards Add support for the Siemens ISAR DSP chip and cards based on it, including analog modem protocols. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index 212dee6..2600534 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -47,6 +47,15 @@ config MISDN_AVMFRITZ help Enable support for AVMs FRITZ!CARD PCI cards +config MISDN_SPEEDFAX + tristate "Support for Sedlbauer Speedfax+" + depends on MISDN + depends on PCI + select MISDN_IPAC + select MISDN_ISAR + help + Enable support for Sedlbauer Speedfax+. + config MISDN_INFINEON tristate "Support for cards with Infineon chipset" depends on MISDN @@ -61,3 +70,7 @@ config MISDN_IPAC tristate depends on MISDN +config MISDN_ISAR + tristate + depends on MISDN + diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 8204d84..e18f964 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o +obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o # chip modules obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o +obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h new file mode 100644 index 0000000..092351a --- /dev/null +++ b/drivers/isdn/hardware/mISDN/isar.h @@ -0,0 +1,269 @@ +/* + * + * isar.h ISAR (Siemens PSB 7110) specific defines + * + * Author Karsten Keil (keil@isdn4linux.de) + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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 "iohelper.h" + +struct isar_hw; + +struct isar_ch { + struct bchannel bch; + struct isar_hw *is; + struct timer_list ftimer; + u8 nr; + u8 dpath; + u8 mml; + u8 state; + u8 cmd; + u8 mod; + u8 newcmd; + u8 newmod; + u8 try_mod; + u8 conmsg[16]; +}; + +struct isar_hw { + struct isar_ch ch[2]; + void *hw; + spinlock_t *hwlock; /* lock HW acccess */ + char *name; + struct module *owner; + read_reg_t *read_reg; + write_reg_t *write_reg; + fifo_func_t *read_fifo; + fifo_func_t *write_fifo; + int (*ctrl)(void *, u32, u_long); + void (*release)(struct isar_hw *); + int (*init)(struct isar_hw *); + int (*open)(struct isar_hw *, struct channel_req *); + int (*firmware)(struct isar_hw *, const u8 *, int); + unsigned long Flags; + int version; + u8 bstat; + u8 iis; + u8 cmsb; + u8 clsb; + u8 buf[256]; + u8 log[256]; +}; + +#define ISAR_IRQMSK 0x04 +#define ISAR_IRQSTA 0x04 +#define ISAR_IRQBIT 0x75 +#define ISAR_CTRL_H 0x61 +#define ISAR_CTRL_L 0x60 +#define ISAR_IIS 0x58 +#define ISAR_IIA 0x58 +#define ISAR_HIS 0x50 +#define ISAR_HIA 0x50 +#define ISAR_MBOX 0x4c +#define ISAR_WADR 0x4a +#define ISAR_RADR 0x48 + +#define ISAR_HIS_VNR 0x14 +#define ISAR_HIS_DKEY 0x02 +#define ISAR_HIS_FIRM 0x1e +#define ISAR_HIS_STDSP 0x08 +#define ISAR_HIS_DIAG 0x05 +#define ISAR_HIS_P0CFG 0x3c +#define ISAR_HIS_P12CFG 0x24 +#define ISAR_HIS_SARTCFG 0x25 +#define ISAR_HIS_PUMPCFG 0x26 +#define ISAR_HIS_PUMPCTRL 0x2a +#define ISAR_HIS_IOM2CFG 0x27 +#define ISAR_HIS_IOM2REQ 0x07 +#define ISAR_HIS_IOM2CTRL 0x2b +#define ISAR_HIS_BSTREQ 0x0c +#define ISAR_HIS_PSTREQ 0x0e +#define ISAR_HIS_SDATA 0x20 +#define ISAR_HIS_DPS1 0x40 +#define ISAR_HIS_DPS2 0x80 +#define SET_DPS(x) ((x<<6) & 0xc0) + +#define ISAR_IIS_MSCMSD 0x3f +#define ISAR_IIS_VNR 0x15 +#define ISAR_IIS_DKEY 0x03 +#define ISAR_IIS_FIRM 0x1f +#define ISAR_IIS_STDSP 0x09 +#define ISAR_IIS_DIAG 0x25 +#define ISAR_IIS_GSTEV 0x00 +#define ISAR_IIS_BSTEV 0x28 +#define ISAR_IIS_BSTRSP 0x2c +#define ISAR_IIS_PSTRSP 0x2e +#define ISAR_IIS_PSTEV 0x2a +#define ISAR_IIS_IOM2RSP 0x27 +#define ISAR_IIS_RDATA 0x20 +#define ISAR_IIS_INVMSG 0x3f + +#define ISAR_CTRL_SWVER 0x10 +#define ISAR_CTRL_STST 0x40 + +#define ISAR_MSG_HWVER 0x20 + +#define ISAR_DP1_USE 1 +#define ISAR_DP2_USE 2 +#define ISAR_RATE_REQ 3 + +#define PMOD_DISABLE 0 +#define PMOD_FAX 1 +#define PMOD_DATAMODEM 2 +#define PMOD_HALFDUPLEX 3 +#define PMOD_V110 4 +#define PMOD_DTMF 5 +#define PMOD_DTMF_TRANS 6 +#define PMOD_BYPASS 7 + +#define PCTRL_ORIG 0x80 +#define PV32P2_V23R 0x40 +#define PV32P2_V22A 0x20 +#define PV32P2_V22B 0x10 +#define PV32P2_V22C 0x08 +#define PV32P2_V21 0x02 +#define PV32P2_BEL 0x01 + +/* LSB MSB in ISAR doc wrong !!! Arghhh */ +#define PV32P3_AMOD 0x80 +#define PV32P3_V32B 0x02 +#define PV32P3_V23B 0x01 +#define PV32P4_48 0x11 +#define PV32P5_48 0x05 +#define PV32P4_UT48 0x11 +#define PV32P5_UT48 0x0d +#define PV32P4_96 0x11 +#define PV32P5_96 0x03 +#define PV32P4_UT96 0x11 +#define PV32P5_UT96 0x0f +#define PV32P4_B96 0x91 +#define PV32P5_B96 0x0b +#define PV32P4_UTB96 0xd1 +#define PV32P5_UTB96 0x0f +#define PV32P4_120 0xb1 +#define PV32P5_120 0x09 +#define PV32P4_UT120 0xf1 +#define PV32P5_UT120 0x0f +#define PV32P4_144 0x99 +#define PV32P5_144 0x09 +#define PV32P4_UT144 0xf9 +#define PV32P5_UT144 0x0f +#define PV32P6_CTN 0x01 +#define PV32P6_ATN 0x02 + +#define PFAXP2_CTN 0x01 +#define PFAXP2_ATN 0x04 + +#define PSEV_10MS_TIMER 0x02 +#define PSEV_CON_ON 0x18 +#define PSEV_CON_OFF 0x19 +#define PSEV_V24_OFF 0x20 +#define PSEV_CTS_ON 0x21 +#define PSEV_CTS_OFF 0x22 +#define PSEV_DCD_ON 0x23 +#define PSEV_DCD_OFF 0x24 +#define PSEV_DSR_ON 0x25 +#define PSEV_DSR_OFF 0x26 +#define PSEV_REM_RET 0xcc +#define PSEV_REM_REN 0xcd +#define PSEV_GSTN_CLR 0xd4 + +#define PSEV_RSP_READY 0xbc +#define PSEV_LINE_TX_H 0xb3 +#define PSEV_LINE_TX_B 0xb2 +#define PSEV_LINE_RX_H 0xb1 +#define PSEV_LINE_RX_B 0xb0 +#define PSEV_RSP_CONN 0xb5 +#define PSEV_RSP_DISC 0xb7 +#define PSEV_RSP_FCERR 0xb9 +#define PSEV_RSP_SILDET 0xbe +#define PSEV_RSP_SILOFF 0xab +#define PSEV_FLAGS_DET 0xba + +#define PCTRL_CMD_TDTMF 0x5a + +#define PCTRL_CMD_FTH 0xa7 +#define PCTRL_CMD_FRH 0xa5 +#define PCTRL_CMD_FTM 0xa8 +#define PCTRL_CMD_FRM 0xa6 +#define PCTRL_CMD_SILON 0xac +#define PCTRL_CMD_CONT 0xa2 +#define PCTRL_CMD_ESC 0xa4 +#define PCTRL_CMD_SILOFF 0xab +#define PCTRL_CMD_HALT 0xa9 + +#define PCTRL_LOC_RET 0xcf +#define PCTRL_LOC_REN 0xce + +#define SMODE_DISABLE 0 +#define SMODE_V14 2 +#define SMODE_HDLC 3 +#define SMODE_BINARY 4 +#define SMODE_FSK_V14 5 + +#define SCTRL_HDMC_BOTH 0x00 +#define SCTRL_HDMC_DTX 0x80 +#define SCTRL_HDMC_DRX 0x40 +#define S_P1_OVSP 0x40 +#define S_P1_SNP 0x20 +#define S_P1_EOP 0x10 +#define S_P1_EDP 0x08 +#define S_P1_NSB 0x04 +#define S_P1_CHS_8 0x03 +#define S_P1_CHS_7 0x02 +#define S_P1_CHS_6 0x01 +#define S_P1_CHS_5 0x00 + +#define S_P2_BFT_DEF 0x10 + +#define IOM_CTRL_ENA 0x80 +#define IOM_CTRL_NOPCM 0x00 +#define IOM_CTRL_ALAW 0x02 +#define IOM_CTRL_ULAW 0x04 +#define IOM_CTRL_RCV 0x01 + +#define IOM_P1_TXD 0x10 + +#define HDLC_FED 0x40 +#define HDLC_FSD 0x20 +#define HDLC_FST 0x20 +#define HDLC_ERROR 0x1c +#define HDLC_ERR_FAD 0x10 +#define HDLC_ERR_RER 0x08 +#define HDLC_ERR_CER 0x04 +#define SART_NMD 0x01 + +#define BSTAT_RDM0 0x1 +#define BSTAT_RDM1 0x2 +#define BSTAT_RDM2 0x4 +#define BSTAT_RDM3 0x8 +#define BSTEV_TBO 0x1f +#define BSTEV_RBO 0x2f + +/* FAX State Machine */ +#define STFAX_NULL 0 +#define STFAX_READY 1 +#define STFAX_LINE 2 +#define STFAX_CONT 3 +#define STFAX_ACTIV 4 +#define STFAX_ESCAPE 5 +#define STFAX_SILDET 6 + +extern u32 mISDNisar_init(struct isar_hw *, void *); +extern void mISDNisar_irq(struct isar_hw *); diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c new file mode 100644 index 0000000..de352a1 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -0,0 +1,1726 @@ +/* + * mISDNisar.c ISAR (Siemens PSB 7110) specific functions + * + * Author Karsten Keil (keil@isdn4linux.de) + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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. + * + */ + +/* define this to enable static debug messages, if you kernel supports + * dynamic debugging, you should use debugfs for this + */ +/* #define DEBUG */ + +#include +#include +#include +#include "isar.h" + +#define ISAR_REV "2.1" + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(ISAR_REV); + +#define DEBUG_HW_FIRMWARE_FIFO 0x10000 + +static const u8 faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146"; +static const u8 faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121, + 122, 145, 146}; +#define FAXMODCNT 13 + +static void isar_setup(struct isar_hw *); + +static inline int +waitforHIA(struct isar_hw *isar, int timeout) +{ + int t = timeout; + u8 val = isar->read_reg(isar->hw, ISAR_HIA); + + while ((val & 1) && t) { + udelay(1); + t--; + val = isar->read_reg(isar->hw, ISAR_HIA); + } + pr_debug("%s: HIA after %dus\n", isar->name, timeout - t); + return timeout; +} + +/* + * send msg to ISAR mailbox + * if msg is NULL use isar->buf + */ +static int +send_mbox(struct isar_hw *isar, u8 his, u8 creg, u8 len, u8 *msg) +{ + if (!waitforHIA(isar, 1000)) + return 0; + pr_debug("send_mbox(%02x,%02x,%d)\n", his, creg, len); + isar->write_reg(isar->hw, ISAR_CTRL_H, creg); + isar->write_reg(isar->hw, ISAR_CTRL_L, len); + isar->write_reg(isar->hw, ISAR_WADR, 0); + if (!msg) + msg = isar->buf; + if (msg && len) { + isar->write_fifo(isar->hw, ISAR_MBOX, msg, len); + if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { + int l = 0; + + while (l < (int)len) { + hex_dump_to_buffer(msg + l, len - l, 32, 1, + isar->log, 256, 1); + pr_debug("%s: %s %02x: %s\n", isar->name, + __func__, l, isar->log); + l += 32; + } + } + } + isar->write_reg(isar->hw, ISAR_HIS, his); + waitforHIA(isar, 1000); + return 1; +} + +/* + * receive message from ISAR mailbox + * if msg is NULL use isar->buf + */ +static void +rcv_mbox(struct isar_hw *isar, u8 *msg) +{ + if (!msg) + msg = isar->buf; + isar->write_reg(isar->hw, ISAR_RADR, 0); + if (msg && isar->clsb) { + isar->read_fifo(isar->hw, ISAR_MBOX, msg, isar->clsb); + if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { + int l = 0; + + while (l < (int)isar->clsb) { + hex_dump_to_buffer(msg + l, isar->clsb - l, 32, + 1, isar->log, 256, 1); + pr_debug("%s: %s %02x: %s\n", isar->name, + __func__, l, isar->log); + l += 32; + } + } + } + isar->write_reg(isar->hw, ISAR_IIA, 0); +} + +static inline void +get_irq_infos(struct isar_hw *isar) +{ + isar->iis = isar->read_reg(isar->hw, ISAR_IIS); + isar->cmsb = isar->read_reg(isar->hw, ISAR_CTRL_H); + isar->clsb = isar->read_reg(isar->hw, ISAR_CTRL_L); + pr_debug("%s: rcv_mbox(%02x,%02x,%d)\n", isar->name, + isar->iis, isar->cmsb, isar->clsb); +} + +/* + * poll answer message from ISAR mailbox + * should be used only with ISAR IRQs disabled before DSP was started + * + */ +static int +poll_mbox(struct isar_hw *isar, int maxdelay) +{ + int t = maxdelay; + u8 irq; + + irq = isar->read_reg(isar->hw, ISAR_IRQBIT); + while (t && !(irq & ISAR_IRQSTA)) { + udelay(1); + t--; + } + if (t) { + get_irq_infos(isar); + rcv_mbox(isar, NULL); + } + pr_debug("%s: pulled %d bytes after %d us\n", + isar->name, isar->clsb, maxdelay - t); + return t; +} + +static int +ISARVersion(struct isar_hw *isar) +{ + int ver; + + /* disable ISAR IRQ */ + isar->write_reg(isar->hw, ISAR_IRQBIT, 0); + isar->buf[0] = ISAR_MSG_HWVER; + isar->buf[1] = 0; + isar->buf[2] = 1; + if (!send_mbox(isar, ISAR_HIS_VNR, 0, 3, NULL)) + return -1; + if (!poll_mbox(isar, 1000)) + return -2; + if (isar->iis == ISAR_IIS_VNR) { + if (isar->clsb == 1) { + ver = isar->buf[0] & 0xf; + return ver; + } + return -3; + } + return -4; +} + +static int +load_firmware(struct isar_hw *isar, const u8 *buf, int size) +{ + u32 saved_debug = isar->ch[0].bch.debug; + int ret, cnt; + u8 nom, noc; + u16 left, val, *sp = (u16 *)buf; + u8 *mp; + u_long flags; + + struct { + u16 sadr; + u16 len; + u16 d_key; + } blk_head; + + if (1 != isar->version) { + pr_err("%s: ISAR wrong version %d firmware download aborted\n", + isar->name, isar->version); + return -EINVAL; + } + if (!(saved_debug & DEBUG_HW_FIRMWARE_FIFO)) + isar->ch[0].bch.debug &= ~DEBUG_HW_BFIFO; + pr_debug("%s: load firmware %d words (%d bytes)\n", + isar->name, size/2, size); + cnt = 0; + size /= 2; + /* disable ISAR IRQ */ + spin_lock_irqsave(isar->hwlock, flags); + isar->write_reg(isar->hw, ISAR_IRQBIT, 0); + spin_unlock_irqrestore(isar->hwlock, flags); + while (cnt < size) { + blk_head.sadr = le16_to_cpu(*sp++); + blk_head.len = le16_to_cpu(*sp++); + blk_head.d_key = le16_to_cpu(*sp++); + cnt += 3; + pr_debug("ISAR firmware block (%#x,%d,%#x)\n", + blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); + left = blk_head.len; + if (cnt + left > size) { + pr_info("%s: firmware error have %d need %d words\n", + isar->name, size, cnt + left); + ret = -EINVAL; + goto reterrflg; + } + spin_lock_irqsave(isar->hwlock, flags); + if (!send_mbox(isar, ISAR_HIS_DKEY, blk_head.d_key & 0xff, + 0, NULL)) { + pr_info("ISAR send_mbox dkey failed\n"); + ret = -ETIME; + goto reterror; + } + if (!poll_mbox(isar, 1000)) { + pr_warning("ISAR poll_mbox dkey failed\n"); + ret = -ETIME; + goto reterror; + } + spin_unlock_irqrestore(isar->hwlock, flags); + if ((isar->iis != ISAR_IIS_DKEY) || isar->cmsb || isar->clsb) { + pr_info("ISAR wrong dkey response (%x,%x,%x)\n", + isar->iis, isar->cmsb, isar->clsb); + ret = 1; + goto reterrflg; + } + while (left > 0) { + if (left > 126) + noc = 126; + else + noc = left; + nom = (2 * noc) + 3; + mp = isar->buf; + /* the ISAR is big endian */ + *mp++ = blk_head.sadr >> 8; + *mp++ = blk_head.sadr & 0xFF; + left -= noc; + cnt += noc; + *mp++ = noc; + pr_debug("%s: load %3d words at %04x\n", isar->name, + noc, blk_head.sadr); + blk_head.sadr += noc; + while (noc) { + val = le16_to_cpu(*sp++); + *mp++ = val >> 8; + *mp++ = val & 0xFF;; + noc--; + } + spin_lock_irqsave(isar->hwlock, flags); + if (!send_mbox(isar, ISAR_HIS_FIRM, 0, nom, NULL)) { + pr_info("ISAR send_mbox prog failed\n"); + ret = -ETIME; + goto reterror; + } + if (!poll_mbox(isar, 1000)) { + pr_info("ISAR poll_mbox prog failed\n"); + ret = -ETIME; + goto reterror; + } + spin_unlock_irqrestore(isar->hwlock, flags); + if ((isar->iis != ISAR_IIS_FIRM) || + isar->cmsb || isar->clsb) { + pr_info("ISAR wrong prog response (%x,%x,%x)\n", + isar->iis, isar->cmsb, isar->clsb); + ret = -EIO; + goto reterrflg; + } + } + pr_debug("%s: ISAR firmware block %d words loaded\n", + isar->name, blk_head.len); + } + isar->ch[0].bch.debug = saved_debug; + /* 10ms delay */ + cnt = 10; + while (cnt--) + mdelay(1); + isar->buf[0] = 0xff; + isar->buf[1] = 0xfe; + isar->bstat = 0; + spin_lock_irqsave(isar->hwlock, flags); + if (!send_mbox(isar, ISAR_HIS_STDSP, 0, 2, NULL)) { + pr_info("ISAR send_mbox start dsp failed\n"); + ret = -ETIME; + goto reterror; + } + if (!poll_mbox(isar, 1000)) { + pr_info("ISAR poll_mbox start dsp failed\n"); + ret = -ETIME; + goto reterror; + } + if ((isar->iis != ISAR_IIS_STDSP) || isar->cmsb || isar->clsb) { + pr_info("ISAR wrong start dsp response (%x,%x,%x)\n", + isar->iis, isar->cmsb, isar->clsb); + ret = -EIO; + goto reterror; + } else + pr_debug("%s: ISAR start dsp success\n", isar->name); + + /* NORMAL mode entered */ + /* Enable IRQs of ISAR */ + isar->write_reg(isar->hw, ISAR_IRQBIT, ISAR_IRQSTA); + spin_unlock_irqrestore(isar->hwlock, flags); + cnt = 1000; /* max 1s */ + while ((!isar->bstat) && cnt) { + mdelay(1); + cnt--; + } + if (!cnt) { + pr_info("ISAR no general status event received\n"); + ret = -ETIME; + goto reterrflg; + } else + pr_debug("%s: ISAR general status event %x\n", + isar->name, isar->bstat); + /* 10ms delay */ + cnt = 10; + while (cnt--) + mdelay(1); + isar->iis = 0; + spin_lock_irqsave(isar->hwlock, flags); + if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { + pr_info("ISAR send_mbox self tst failed\n"); + ret = -ETIME; + goto reterror; + } + spin_unlock_irqrestore(isar->hwlock, flags); + cnt = 10000; /* max 100 ms */ + while ((isar->iis != ISAR_IIS_DIAG) && cnt) { + udelay(10); + cnt--; + } + mdelay(1); + if (!cnt) { + pr_info("ISAR no self tst response\n"); + ret = -ETIME; + goto reterrflg; + } + if ((isar->cmsb == ISAR_CTRL_STST) && (isar->clsb == 1) + && (isar->buf[0] == 0)) + pr_debug("%s: ISAR selftest OK\n", isar->name); + else { + pr_info("ISAR selftest not OK %x/%x/%x\n", + isar->cmsb, isar->clsb, isar->buf[0]); + ret = -EIO; + goto reterrflg; + } + spin_lock_irqsave(isar->hwlock, flags); + isar->iis = 0; + if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { + pr_info("ISAR RQST SVN failed\n"); + ret = -ETIME; + goto reterror; + } + spin_unlock_irqrestore(isar->hwlock, flags); + cnt = 30000; /* max 300 ms */ + while ((isar->iis != ISAR_IIS_DIAG) && cnt) { + udelay(10); + cnt--; + } + mdelay(1); + if (!cnt) { + pr_info("ISAR no SVN response\n"); + ret = -ETIME; + goto reterrflg; + } else { + if ((isar->cmsb == ISAR_CTRL_SWVER) && (isar->clsb == 1)) { + pr_notice("%s: ISAR software version %#x\n", + isar->name, isar->buf[0]); + } else { + pr_info("%s: ISAR wrong swver response (%x,%x)" + " cnt(%d)\n", isar->name, isar->cmsb, + isar->clsb, cnt); + ret = -EIO; + goto reterrflg; + } + } + spin_lock_irqsave(isar->hwlock, flags); + isar_setup(isar); + spin_unlock_irqrestore(isar->hwlock, flags); + ret = 0; +reterrflg: + spin_lock_irqsave(isar->hwlock, flags); +reterror: + isar->ch[0].bch.debug = saved_debug; + if (ret) + /* disable ISAR IRQ */ + isar->write_reg(isar->hw, ISAR_IRQBIT, 0); + spin_unlock_irqrestore(isar->hwlock, flags); + return ret; +} + +static inline void +deliver_status(struct isar_ch *ch, int status) +{ + pr_debug("%s: HL->LL FAXIND %x\n", ch->is->name, status); + _queue_data(&ch->bch.ch, PH_CONTROL_IND, status, 0, NULL, GFP_ATOMIC); +} + +static inline void +isar_rcv_frame(struct isar_ch *ch) +{ + u8 *ptr; + + if (!ch->is->clsb) { + pr_debug("%s; ISAR zero len frame\n", ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + return; + } + switch (ch->bch.state) { + case ISDN_P_NONE: + pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n", + ch->is->name, ch->is->iis, ch->is->cmsb, ch->is->clsb); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + case ISDN_P_B_RAW: + case ISDN_P_B_L2DTMF: + case ISDN_P_B_MODEM_ASYNC: + if (!ch->bch.rx_skb) { + ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, + GFP_ATOMIC); + if (unlikely(!ch->bch.rx_skb)) { + pr_info("%s: B receive out of memory\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } + } + rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); + recv_Bchannel(&ch->bch, 0); + break; + case ISDN_P_B_HDLC: + if (!ch->bch.rx_skb) { + ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, + GFP_ATOMIC); + if (unlikely(!ch->bch.rx_skb)) { + pr_info("%s: B receive out of memory\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } + } + if ((ch->bch.rx_skb->len + ch->is->clsb) > + (ch->bch.maxlen + 2)) { + pr_debug("%s: incoming packet too large\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + skb_trim(ch->bch.rx_skb, 0); + break; + } + if (ch->is->cmsb & HDLC_ERROR) { + pr_debug("%s: ISAR frame error %x len %d\n", + ch->is->name, ch->is->cmsb, ch->is->clsb); +#ifdef ERROR_STATISTIC + if (ch->is->cmsb & HDLC_ERR_RER) + ch->bch.err_inv++; + if (ch->is->cmsb & HDLC_ERR_CER) + ch->bch.err_crc++; +#endif + skb_trim(ch->bch.rx_skb, 0); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } + if (ch->is->cmsb & HDLC_FSD) + skb_trim(ch->bch.rx_skb, 0); + ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); + rcv_mbox(ch->is, ptr); + if (ch->is->cmsb & HDLC_FED) { + if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ + pr_debug("%s: ISAR frame to short %d\n", + ch->is->name, ch->bch.rx_skb->len); + skb_trim(ch->bch.rx_skb, 0); + break; + } + skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); + recv_Bchannel(&ch->bch, 0); + } + break; + case ISDN_P_B_T30_FAX: + if (ch->state != STFAX_ACTIV) { + pr_debug("%s: isar_rcv_frame: not ACTIV\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + if (ch->bch.rx_skb) + skb_trim(ch->bch.rx_skb, 0); + break; + } + if (!ch->bch.rx_skb) { + ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, + GFP_ATOMIC); + if (unlikely(!ch->bch.rx_skb)) { + pr_info("%s: B receive out of memory\n", + __func__); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } + } + if (ch->cmd == PCTRL_CMD_FRM) { + rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); + pr_debug("%s: isar_rcv_frame: %d\n", + ch->is->name, ch->bch.rx_skb->len); + if (ch->is->cmsb & SART_NMD) { /* ABORT */ + pr_debug("%s: isar_rcv_frame: no more data\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + send_mbox(ch->is, SET_DPS(ch->dpath) | + ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, + 0, NULL); + ch->state = STFAX_ESCAPE; + /* set_skb_flag(skb, DF_NOMOREDATA); */ + } + recv_Bchannel(&ch->bch, 0); + if (ch->is->cmsb & SART_NMD) + deliver_status(ch, HW_MOD_NOCARR); + break; + } + if (ch->cmd != PCTRL_CMD_FRH) { + pr_debug("%s: isar_rcv_frame: unknown fax mode %x\n", + ch->is->name, ch->cmd); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + if (ch->bch.rx_skb) + skb_trim(ch->bch.rx_skb, 0); + break; + } + /* PCTRL_CMD_FRH */ + if ((ch->bch.rx_skb->len + ch->is->clsb) > + (ch->bch.maxlen + 2)) { + pr_info("%s: %s incoming packet too large\n", + ch->is->name, __func__); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + skb_trim(ch->bch.rx_skb, 0); + break; + } else if (ch->is->cmsb & HDLC_ERROR) { + pr_info("%s: ISAR frame error %x len %d\n", + ch->is->name, ch->is->cmsb, ch->is->clsb); + skb_trim(ch->bch.rx_skb, 0); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } + if (ch->is->cmsb & HDLC_FSD) + skb_trim(ch->bch.rx_skb, 0); + ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); + rcv_mbox(ch->is, ptr); + if (ch->is->cmsb & HDLC_FED) { + if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ + pr_info("%s: ISAR frame to short %d\n", + ch->is->name, ch->bch.rx_skb->len); + skb_trim(ch->bch.rx_skb, 0); + break; + } + skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); + recv_Bchannel(&ch->bch, 0); + } + if (ch->is->cmsb & SART_NMD) { /* ABORT */ + pr_debug("%s: isar_rcv_frame: no more data\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + if (ch->bch.rx_skb) + skb_trim(ch->bch.rx_skb, 0); + send_mbox(ch->is, SET_DPS(ch->dpath) | + ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); + ch->state = STFAX_ESCAPE; + deliver_status(ch, HW_MOD_NOCARR); + } + break; + default: + pr_info("isar_rcv_frame protocol (%x)error\n", ch->bch.state); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } +} + +static void +isar_fill_fifo(struct isar_ch *ch) +{ + int count; + u8 msb; + u8 *ptr; + + pr_debug("%s: ch%d tx_skb %p tx_idx %d\n", + ch->is->name, ch->bch.nr, ch->bch.tx_skb, ch->bch.tx_idx); + if (!ch->bch.tx_skb) + return; + count = ch->bch.tx_skb->len - ch->bch.tx_idx; + if (count <= 0) + return; + if (!(ch->is->bstat & + (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) + return; + if (count > ch->mml) { + msb = 0; + count = ch->mml; + } else { + msb = HDLC_FED; + } + ptr = ch->bch.tx_skb->data + ch->bch.tx_idx; + if (!ch->bch.tx_idx) { + pr_debug("%s: frame start\n", ch->is->name); + if ((ch->bch.state == ISDN_P_B_T30_FAX) && + (ch->cmd == PCTRL_CMD_FTH)) { + if (count > 1) { + if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) { + /* last frame */ + test_and_set_bit(FLG_LASTDATA, + &ch->bch.Flags); + pr_debug("%s: set LASTDATA\n", + ch->is->name); + if (msb == HDLC_FED) + test_and_set_bit(FLG_DLEETX, + &ch->bch.Flags); + } + } + } + msb |= HDLC_FST; + } + ch->bch.tx_idx += count; + switch (ch->bch.state) { + case ISDN_P_NONE: + pr_info("%s: wrong protocol 0\n", __func__); + break; + case ISDN_P_B_RAW: + case ISDN_P_B_L2DTMF: + case ISDN_P_B_MODEM_ASYNC: + send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, + 0, count, ptr); + break; + case ISDN_P_B_HDLC: + send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, + msb, count, ptr); + break; + case ISDN_P_B_T30_FAX: + if (ch->state != STFAX_ACTIV) + pr_debug("%s: not ACTIV\n", ch->is->name); + else if (ch->cmd == PCTRL_CMD_FTH) + send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, + msb, count, ptr); + else if (ch->cmd == PCTRL_CMD_FTM) + send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, + 0, count, ptr); + else + pr_debug("%s: not FTH/FTM\n", ch->is->name); + break; + default: + pr_info("%s: protocol(%x) error\n", + __func__, ch->bch.state); + break; + } +} + +static inline struct isar_ch * +sel_bch_isar(struct isar_hw *isar, u8 dpath) +{ + struct isar_ch *base = &isar->ch[0]; + + if ((!dpath) || (dpath > 2)) + return NULL; + if (base->dpath == dpath) + return base; + base++; + if (base->dpath == dpath) + return base; + return NULL; +} + +static void +send_next(struct isar_ch *ch) +{ + pr_debug("%s: %s ch%d tx_skb %p tx_idx %d\n", + ch->is->name, __func__, ch->bch.nr, + ch->bch.tx_skb, ch->bch.tx_idx); + if (ch->bch.state == ISDN_P_B_T30_FAX) { + if (ch->cmd == PCTRL_CMD_FTH) { + if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) { + pr_debug("set NMD_DATA\n"); + test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); + } + } else if (ch->cmd == PCTRL_CMD_FTM) { + if (test_bit(FLG_DLEETX, &ch->bch.Flags)) { + test_and_set_bit(FLG_LASTDATA, &ch->bch.Flags); + test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); + } + } + } + if (ch->bch.tx_skb) { + /* send confirm, on trans, free on hdlc. */ + if (test_bit(FLG_TRANSPARENT, &ch->bch.Flags)) + confirm_Bsend(&ch->bch); + dev_kfree_skb(ch->bch.tx_skb); + } + if (get_next_bframe(&ch->bch)) + isar_fill_fifo(ch); + else { + if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) { + if (test_and_clear_bit(FLG_LASTDATA, + &ch->bch.Flags)) { + if (test_and_clear_bit(FLG_NMD_DATA, + &ch->bch.Flags)) { + u8 zd = 0; + send_mbox(ch->is, SET_DPS(ch->dpath) | + ISAR_HIS_SDATA, 0x01, 1, &zd); + } + test_and_set_bit(FLG_LL_OK, &ch->bch.Flags); + } else { + deliver_status(ch, HW_MOD_CONNECT); + } + } + } +} + +static void +check_send(struct isar_hw *isar, u8 rdm) +{ + struct isar_ch *ch; + + pr_debug("%s: rdm %x\n", isar->name, rdm); + if (rdm & BSTAT_RDM1) { + ch = sel_bch_isar(isar, 1); + if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { + if (ch->bch.tx_skb && (ch->bch.tx_skb->len > + ch->bch.tx_idx)) + isar_fill_fifo(ch); + else + send_next(ch); + } + } + if (rdm & BSTAT_RDM2) { + ch = sel_bch_isar(isar, 2); + if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { + if (ch->bch.tx_skb && (ch->bch.tx_skb->len > + ch->bch.tx_idx)) + isar_fill_fifo(ch); + else + send_next(ch); + } + } +} + +const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4", + "300", "600", "1200", "2400", "4800", "7200", + "9600nt", "9600t", "12000", "14400", "WRONG"}; +const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", + "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"}; + +static void +isar_pump_status_rsp(struct isar_ch *ch) { + u8 ril = ch->is->buf[0]; + u8 rim; + + if (!test_and_clear_bit(ISAR_RATE_REQ, &ch->is->Flags)) + return; + if (ril > 14) { + pr_info("%s: wrong pstrsp ril=%d\n", ch->is->name, ril); + ril = 15; + } + switch (ch->is->buf[1]) { + case 0: + rim = 0; + break; + case 0x20: + rim = 2; + break; + case 0x40: + rim = 3; + break; + case 0x41: + rim = 4; + break; + case 0x51: + rim = 5; + break; + case 0x61: + rim = 6; + break; + case 0x71: + rim = 7; + break; + case 0x82: + rim = 8; + break; + case 0x92: + rim = 9; + break; + case 0xa2: + rim = 10; + break; + default: + rim = 1; + break; + } + sprintf(ch->conmsg, "%s %s", dmril[ril], dmrim[rim]); + pr_debug("%s: pump strsp %s\n", ch->is->name, ch->conmsg); +} + +static void +isar_pump_statev_modem(struct isar_ch *ch, u8 devt) { + u8 dps = SET_DPS(ch->dpath); + + switch (devt) { + case PSEV_10MS_TIMER: + pr_debug("%s: pump stev TIMER\n", ch->is->name); + break; + case PSEV_CON_ON: + pr_debug("%s: pump stev CONNECT\n", ch->is->name); + deliver_status(ch, HW_MOD_CONNECT); + break; + case PSEV_CON_OFF: + pr_debug("%s: pump stev NO CONNECT\n", ch->is->name); + send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + deliver_status(ch, HW_MOD_NOCARR); + break; + case PSEV_V24_OFF: + pr_debug("%s: pump stev V24 OFF\n", ch->is->name); + break; + case PSEV_CTS_ON: + pr_debug("%s: pump stev CTS ON\n", ch->is->name); + break; + case PSEV_CTS_OFF: + pr_debug("%s pump stev CTS OFF\n", ch->is->name); + break; + case PSEV_DCD_ON: + pr_debug("%s: pump stev CARRIER ON\n", ch->is->name); + test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); + send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + break; + case PSEV_DCD_OFF: + pr_debug("%s: pump stev CARRIER OFF\n", ch->is->name); + break; + case PSEV_DSR_ON: + pr_debug("%s: pump stev DSR ON\n", ch->is->name); + break; + case PSEV_DSR_OFF: + pr_debug("%s: pump stev DSR_OFF\n", ch->is->name); + break; + case PSEV_REM_RET: + pr_debug("%s: pump stev REMOTE RETRAIN\n", ch->is->name); + break; + case PSEV_REM_REN: + pr_debug("%s: pump stev REMOTE RENEGOTIATE\n", ch->is->name); + break; + case PSEV_GSTN_CLR: + pr_debug("%s: pump stev GSTN CLEAR\n", ch->is->name); + break; + default: + pr_info("u%s: nknown pump stev %x\n", ch->is->name, devt); + break; + } +} + +static void +isar_pump_statev_fax(struct isar_ch *ch, u8 devt) { + u8 dps = SET_DPS(ch->dpath); + u8 p1; + + switch (devt) { + case PSEV_10MS_TIMER: + pr_debug("%s: pump stev TIMER\n", ch->is->name); + break; + case PSEV_RSP_READY: + pr_debug("%s: pump stev RSP_READY\n", ch->is->name); + ch->state = STFAX_READY; + deliver_status(ch, HW_MOD_READY); +#ifdef AUTOCON + if (test_bit(BC_FLG_ORIG, &ch->bch.Flags)) + isar_pump_cmd(bch, HW_MOD_FRH, 3); + else + isar_pump_cmd(bch, HW_MOD_FTH, 3); +#endif + break; + case PSEV_LINE_TX_H: + if (ch->state == STFAX_LINE) { + pr_debug("%s: pump stev LINE_TX_H\n", ch->is->name); + ch->state = STFAX_CONT; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_CONT, 0, NULL); + } else { + pr_debug("%s: pump stev LINE_TX_H wrong st %x\n", + ch->is->name, ch->state); + } + break; + case PSEV_LINE_RX_H: + if (ch->state == STFAX_LINE) { + pr_debug("%s: pump stev LINE_RX_H\n", ch->is->name); + ch->state = STFAX_CONT; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_CONT, 0, NULL); + } else { + pr_debug("%s: pump stev LINE_RX_H wrong st %x\n", + ch->is->name, ch->state); + } + break; + case PSEV_LINE_TX_B: + if (ch->state == STFAX_LINE) { + pr_debug("%s: pump stev LINE_TX_B\n", ch->is->name); + ch->state = STFAX_CONT; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_CONT, 0, NULL); + } else { + pr_debug("%s: pump stev LINE_TX_B wrong st %x\n", + ch->is->name, ch->state); + } + break; + case PSEV_LINE_RX_B: + if (ch->state == STFAX_LINE) { + pr_debug("%s: pump stev LINE_RX_B\n", ch->is->name); + ch->state = STFAX_CONT; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_CONT, 0, NULL); + } else { + pr_debug("%s: pump stev LINE_RX_B wrong st %x\n", + ch->is->name, ch->state); + } + break; + case PSEV_RSP_CONN: + if (ch->state == STFAX_CONT) { + pr_debug("%s: pump stev RSP_CONN\n", ch->is->name); + ch->state = STFAX_ACTIV; + test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); + send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + if (ch->cmd == PCTRL_CMD_FTH) { + int delay = (ch->mod == 3) ? 1000 : 200; + /* 1s (200 ms) Flags before data */ + if (test_and_set_bit(FLG_FTI_RUN, + &ch->bch.Flags)) + del_timer(&ch->ftimer); + ch->ftimer.expires = + jiffies + ((delay * HZ)/1000); + test_and_set_bit(FLG_LL_CONN, + &ch->bch.Flags); + add_timer(&ch->ftimer); + } else { + deliver_status(ch, HW_MOD_CONNECT); + } + } else { + pr_debug("%s: pump stev RSP_CONN wrong st %x\n", + ch->is->name, ch->state); + } + break; + case PSEV_FLAGS_DET: + pr_debug("%s: pump stev FLAGS_DET\n", ch->is->name); + break; + case PSEV_RSP_DISC: + pr_debug("%s: pump stev RSP_DISC state(%d)\n", + ch->is->name, ch->state); + if (ch->state == STFAX_ESCAPE) { + p1 = 5; + switch (ch->newcmd) { + case 0: + ch->state = STFAX_READY; + break; + case PCTRL_CMD_FTM: + p1 = 2; + case PCTRL_CMD_FTH: + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_SILON, 1, &p1); + ch->state = STFAX_SILDET; + break; + case PCTRL_CMD_FRH: + case PCTRL_CMD_FRM: + ch->mod = ch->newmod; + p1 = ch->newmod; + ch->newmod = 0; + ch->cmd = ch->newcmd; + ch->newcmd = 0; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + ch->cmd, 1, &p1); + ch->state = STFAX_LINE; + ch->try_mod = 3; + break; + default: + pr_debug("%s: RSP_DISC unknown newcmd %x\n", + ch->is->name, ch->newcmd); + break; + } + } else if (ch->state == STFAX_ACTIV) { + if (test_and_clear_bit(FLG_LL_OK, &ch->bch.Flags)) + deliver_status(ch, HW_MOD_OK); + else if (ch->cmd == PCTRL_CMD_FRM) + deliver_status(ch, HW_MOD_NOCARR); + else + deliver_status(ch, HW_MOD_FCERROR); + ch->state = STFAX_READY; + } else if (ch->state != STFAX_SILDET) { + /* ignore in STFAX_SILDET */ + ch->state = STFAX_READY; + deliver_status(ch, HW_MOD_FCERROR); + } + break; + case PSEV_RSP_SILDET: + pr_debug("%s: pump stev RSP_SILDET\n", ch->is->name); + if (ch->state == STFAX_SILDET) { + ch->mod = ch->newmod; + p1 = ch->newmod; + ch->newmod = 0; + ch->cmd = ch->newcmd; + ch->newcmd = 0; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + ch->cmd, 1, &p1); + ch->state = STFAX_LINE; + ch->try_mod = 3; + } + break; + case PSEV_RSP_SILOFF: + pr_debug("%s: pump stev RSP_SILOFF\n", ch->is->name); + break; + case PSEV_RSP_FCERR: + if (ch->state == STFAX_LINE) { + pr_debug("%s: pump stev RSP_FCERR try %d\n", + ch->is->name, ch->try_mod); + if (ch->try_mod--) { + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + ch->cmd, 1, &ch->mod); + break; + } + } + pr_debug("%s: pump stev RSP_FCERR\n", ch->is->name); + ch->state = STFAX_ESCAPE; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, + 0, NULL); + deliver_status(ch, HW_MOD_FCERROR); + break; + default: + break; + } +} + +void +mISDNisar_irq(struct isar_hw *isar) +{ + struct isar_ch *ch; + + get_irq_infos(isar); + switch (isar->iis & ISAR_IIS_MSCMSD) { + case ISAR_IIS_RDATA: + ch = sel_bch_isar(isar, isar->iis >> 6); + if (ch) + isar_rcv_frame(ch); + else { + pr_debug("%s: ISAR spurious IIS_RDATA %x/%x/%x\n", + isar->name, isar->iis, isar->cmsb, + isar->clsb); + isar->write_reg(isar->hw, ISAR_IIA, 0); + } + break; + case ISAR_IIS_GSTEV: + isar->write_reg(isar->hw, ISAR_IIA, 0); + isar->bstat |= isar->cmsb; + check_send(isar, isar->cmsb); + break; + case ISAR_IIS_BSTEV: +#ifdef ERROR_STATISTIC + ch = sel_bch_isar(isar, isar->iis >> 6); + if (ch) { + if (isar->cmsb == BSTEV_TBO) + ch->bch.err_tx++; + if (isar->cmsb == BSTEV_RBO) + ch->bch.err_rdo++; + } +#endif + pr_debug("%s: Buffer STEV dpath%d msb(%x)\n", + isar->name, isar->iis>>6, isar->cmsb); + isar->write_reg(isar->hw, ISAR_IIA, 0); + break; + case ISAR_IIS_PSTEV: + ch = sel_bch_isar(isar, isar->iis >> 6); + if (ch) { + rcv_mbox(isar, NULL); + if (ch->bch.state == ISDN_P_B_MODEM_ASYNC) + isar_pump_statev_modem(ch, isar->cmsb); + else if (ch->bch.state == ISDN_P_B_T30_FAX) + isar_pump_statev_fax(ch, isar->cmsb); + else if (ch->bch.state == ISDN_P_B_RAW) { + int tt; + tt = isar->cmsb | 0x30; + if (tt == 0x3e) + tt = '*'; + else if (tt == 0x3f) + tt = '#'; + else if (tt > '9') + tt += 7; + tt |= DTMF_TONE_VAL; + _queue_data(&ch->bch.ch, PH_CONTROL_IND, + MISDN_ID_ANY, sizeof(tt), &tt, + GFP_ATOMIC); + } else + pr_debug("%s: ISAR IIS_PSTEV pm %d sta %x\n", + isar->name, ch->bch.state, + isar->cmsb); + } else { + pr_debug("%s: ISAR spurious IIS_PSTEV %x/%x/%x\n", + isar->name, isar->iis, isar->cmsb, + isar->clsb); + isar->write_reg(isar->hw, ISAR_IIA, 0); + } + break; + case ISAR_IIS_PSTRSP: + ch = sel_bch_isar(isar, isar->iis >> 6); + if (ch) { + rcv_mbox(isar, NULL); + isar_pump_status_rsp(ch); + } else { + pr_debug("%s: ISAR spurious IIS_PSTRSP %x/%x/%x\n", + isar->name, isar->iis, isar->cmsb, + isar->clsb); + isar->write_reg(isar->hw, ISAR_IIA, 0); + } + break; + case ISAR_IIS_DIAG: + case ISAR_IIS_BSTRSP: + case ISAR_IIS_IOM2RSP: + rcv_mbox(isar, NULL); + break; + case ISAR_IIS_INVMSG: + rcv_mbox(isar, NULL); + pr_debug("%s: invalid msg his:%x\n", isar->name, isar->cmsb); + break; + default: + rcv_mbox(isar, NULL); + pr_debug("%s: unhandled msg iis(%x) ctrl(%x/%x)\n", + isar->name, isar->iis, isar->cmsb, isar->clsb); + break; + } +} +EXPORT_SYMBOL(mISDNisar_irq); + +static void +ftimer_handler(unsigned long data) +{ + struct isar_ch *ch = (struct isar_ch *)data; + + pr_debug("%s: ftimer flags %lx\n", ch->is->name, ch->bch.Flags); + test_and_clear_bit(FLG_FTI_RUN, &ch->bch.Flags); + if (test_and_clear_bit(FLG_LL_CONN, &ch->bch.Flags)) + deliver_status(ch, HW_MOD_CONNECT); +} + +static void +setup_pump(struct isar_ch *ch) { + u8 dps = SET_DPS(ch->dpath); + u8 ctrl, param[6]; + + switch (ch->bch.state) { + case ISDN_P_NONE: + case ISDN_P_B_RAW: + case ISDN_P_B_HDLC: + send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); + break; + case ISDN_P_B_L2DTMF: + if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) { + param[0] = 5; /* TOA 5 db */ + send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, + PMOD_DTMF_TRANS, 1, param); + } else { + param[0] = 40; /* REL -46 dbm */ + send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, + PMOD_DTMF, 1, param); + } + case ISDN_P_B_MODEM_ASYNC: + ctrl = PMOD_DATAMODEM; + if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { + ctrl |= PCTRL_ORIG; + param[5] = PV32P6_CTN; + } else { + param[5] = PV32P6_ATN; + } + param[0] = 6; /* 6 db */ + param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | + PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; + param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; + param[3] = PV32P4_UT144; + param[4] = PV32P5_UT144; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param); + break; + case ISDN_P_B_T30_FAX: + ctrl = PMOD_FAX; + if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { + ctrl |= PCTRL_ORIG; + param[1] = PFAXP2_CTN; + } else { + param[1] = PFAXP2_ATN; + } + param[0] = 6; /* 6 db */ + send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); + ch->state = STFAX_NULL; + ch->newcmd = 0; + ch->newmod = 0; + test_and_set_bit(FLG_FTI_RUN, &ch->bch.Flags); + break; + } + udelay(1000); + send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + udelay(1000); +} + +static void +setup_sart(struct isar_ch *ch) { + u8 dps = SET_DPS(ch->dpath); + u8 ctrl, param[2] = {0, 0}; + + switch (ch->bch.state) { + case ISDN_P_NONE: + send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, + 0, NULL); + break; + case ISDN_P_B_RAW: + case ISDN_P_B_L2DTMF: + send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, + 2, param); + break; + case ISDN_P_B_HDLC: + case ISDN_P_B_T30_FAX: + send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, + 1, param); + break; + case ISDN_P_B_MODEM_ASYNC: + ctrl = SMODE_V14 | SCTRL_HDMC_BOTH; + param[0] = S_P1_CHS_8; + param[1] = S_P2_BFT_DEF; + send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, ctrl, 2, param); + break; + } + udelay(1000); + send_mbox(ch->is, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); + udelay(1000); +} + +static void +setup_iom2(struct isar_ch *ch) { + u8 dps = SET_DPS(ch->dpath); + u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0}; + + if (ch->bch.nr == 2) { + msg[1] = 1; + msg[3] = 1; + } + switch (ch->bch.state) { + case ISDN_P_NONE: + cmsb = 0; + /* dummy slot */ + msg[1] = ch->dpath + 2; + msg[3] = ch->dpath + 2; + break; + case ISDN_P_B_RAW: + case ISDN_P_B_HDLC: + break; + case ISDN_P_B_MODEM_ASYNC: + case ISDN_P_B_T30_FAX: + cmsb |= IOM_CTRL_RCV; + case ISDN_P_B_L2DTMF: + if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) + cmsb |= IOM_CTRL_RCV; + cmsb |= IOM_CTRL_ALAW; + break; + } + send_mbox(ch->is, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg); + udelay(1000); + send_mbox(ch->is, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL); + udelay(1000); +} + +static int +modeisar(struct isar_ch *ch, u32 bprotocol) +{ + /* Here we are selecting the best datapath for requested protocol */ + if (ch->bch.state == ISDN_P_NONE) { /* New Setup */ + switch (bprotocol) { + case ISDN_P_NONE: /* init */ + if (!ch->dpath) + /* no init for dpath 0 */ + return 0; + test_and_clear_bit(FLG_HDLC, &ch->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &ch->bch.Flags); + break; + case ISDN_P_B_RAW: + case ISDN_P_B_HDLC: + /* best is datapath 2 */ + if (!test_and_set_bit(ISAR_DP2_USE, &ch->is->Flags)) + ch->dpath = 2; + else if (!test_and_set_bit(ISAR_DP1_USE, + &ch->is->Flags)) + ch->dpath = 1; + else { + pr_info("modeisar both pathes in use\n"); + return -EBUSY; + } + if (bprotocol == ISDN_P_B_HDLC) + test_and_set_bit(FLG_HDLC, &ch->bch.Flags); + else + test_and_set_bit(FLG_TRANSPARENT, + &ch->bch.Flags); + break; + case ISDN_P_B_MODEM_ASYNC: + case ISDN_P_B_T30_FAX: + case ISDN_P_B_L2DTMF: + /* only datapath 1 */ + if (!test_and_set_bit(ISAR_DP1_USE, &ch->is->Flags)) + ch->dpath = 1; + else { + pr_info("%s: ISAR modeisar analog functions" + "only with DP1\n", ch->is->name); + return -EBUSY; + } + break; + default: + pr_info("%s: protocol not known %x\n", ch->is->name, + bprotocol); + return -ENOPROTOOPT; + } + } + pr_debug("%s: ISAR ch%d dp%d protocol %x->%x\n", ch->is->name, + ch->bch.nr, ch->dpath, ch->bch.state, bprotocol); + ch->bch.state = bprotocol; + setup_pump(ch); + setup_iom2(ch); + setup_sart(ch); + if (ch->bch.state == ISDN_P_NONE) { + /* Clear resources */ + if (ch->dpath == 1) + test_and_clear_bit(ISAR_DP1_USE, &ch->is->Flags); + else if (ch->dpath == 2) + test_and_clear_bit(ISAR_DP2_USE, &ch->is->Flags); + ch->dpath = 0; + ch->is->ctrl(ch->is->hw, HW_DEACT_IND, ch->bch.nr); + } else + ch->is->ctrl(ch->is->hw, HW_ACTIVATE_IND, ch->bch.nr); + return 0; +} + +static void +isar_pump_cmd(struct isar_ch *ch, u32 cmd, u8 para) +{ + u8 dps = SET_DPS(ch->dpath); + u8 ctrl = 0, nom = 0, p1 = 0; + + pr_debug("%s: isar_pump_cmd %x/%x state(%x)\n", + ch->is->name, cmd, para, ch->bch.state); + switch (cmd) { + case HW_MOD_FTM: + if (ch->state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FTM; + nom = 1; + ch->state = STFAX_LINE; + ch->cmd = ctrl; + ch->mod = para; + ch->newmod = 0; + ch->newcmd = 0; + ch->try_mod = 3; + } else if ((ch->state == STFAX_ACTIV) && + (ch->cmd == PCTRL_CMD_FTM) && (ch->mod == para)) + deliver_status(ch, HW_MOD_CONNECT); + else { + ch->newmod = para; + ch->newcmd = PCTRL_CMD_FTM; + nom = 0; + ctrl = PCTRL_CMD_ESC; + ch->state = STFAX_ESCAPE; + } + break; + case HW_MOD_FTH: + if (ch->state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FTH; + nom = 1; + ch->state = STFAX_LINE; + ch->cmd = ctrl; + ch->mod = para; + ch->newmod = 0; + ch->newcmd = 0; + ch->try_mod = 3; + } else if ((ch->state == STFAX_ACTIV) && + (ch->cmd == PCTRL_CMD_FTH) && (ch->mod == para)) + deliver_status(ch, HW_MOD_CONNECT); + else { + ch->newmod = para; + ch->newcmd = PCTRL_CMD_FTH; + nom = 0; + ctrl = PCTRL_CMD_ESC; + ch->state = STFAX_ESCAPE; + } + break; + case HW_MOD_FRM: + if (ch->state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FRM; + nom = 1; + ch->state = STFAX_LINE; + ch->cmd = ctrl; + ch->mod = para; + ch->newmod = 0; + ch->newcmd = 0; + ch->try_mod = 3; + } else if ((ch->state == STFAX_ACTIV) && + (ch->cmd == PCTRL_CMD_FRM) && (ch->mod == para)) + deliver_status(ch, HW_MOD_CONNECT); + else { + ch->newmod = para; + ch->newcmd = PCTRL_CMD_FRM; + nom = 0; + ctrl = PCTRL_CMD_ESC; + ch->state = STFAX_ESCAPE; + } + break; + case HW_MOD_FRH: + if (ch->state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FRH; + nom = 1; + ch->state = STFAX_LINE; + ch->cmd = ctrl; + ch->mod = para; + ch->newmod = 0; + ch->newcmd = 0; + ch->try_mod = 3; + } else if ((ch->state == STFAX_ACTIV) && + (ch->cmd == PCTRL_CMD_FRH) && (ch->mod == para)) + deliver_status(ch, HW_MOD_CONNECT); + else { + ch->newmod = para; + ch->newcmd = PCTRL_CMD_FRH; + nom = 0; + ctrl = PCTRL_CMD_ESC; + ch->state = STFAX_ESCAPE; + } + break; + case PCTRL_CMD_TDTMF: + p1 = para; + nom = 1; + ctrl = PCTRL_CMD_TDTMF; + break; + } + if (ctrl) + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); +} + +static void +isar_setup(struct isar_hw *isar) +{ + u8 msg; + int i; + + /* Dpath 1, 2 */ + msg = 61; + for (i = 0; i < 2; i++) { + /* Buffer Config */ + send_mbox(isar, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | + ISAR_HIS_P12CFG, 4, 1, &msg); + isar->ch[i].mml = msg; + isar->ch[i].bch.state = 0; + isar->ch[i].dpath = i + 1; + modeisar(&isar->ch[i], ISDN_P_NONE); + } +} + +static int +isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct isar_ch *ich = container_of(bch, struct isar_ch, bch); + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id, *val; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(ich->is->hwlock, flags); + ret = bchannel_senddata(bch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + ret = 0; + isar_fill_fifo(ich); + spin_unlock_irqrestore(ich->is->hwlock, flags); + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(ich->is->hwlock, flags); + return ret; + case PH_ACTIVATE_REQ: + spin_lock_irqsave(ich->is->hwlock, flags); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) + ret = modeisar(ich, ch->protocol); + else + ret = 0; + spin_unlock_irqrestore(ich->is->hwlock, flags); + if (!ret) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + break; + case PH_DEACTIVATE_REQ: + spin_lock_irqsave(ich->is->hwlock, flags); + mISDN_clear_bchannel(bch); + modeisar(ich, ISDN_P_NONE); + spin_unlock_irqrestore(ich->is->hwlock, flags); + _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + ret = 0; + break; + case PH_CONTROL_REQ: + val = (u32 *)skb->data; + pr_debug("%s: PH_CONTROL | REQUEST %x/%x\n", ich->is->name, + hh->id, *val); + if ((hh->id == 0) && ((*val & ~DTMF_TONE_MASK) == + DTMF_TONE_VAL)) { + if (bch->state == ISDN_P_B_L2DTMF) { + char tt = *val & DTMF_TONE_MASK; + + if (tt == '*') + tt = 0x1e; + else if (tt == '#') + tt = 0x1f; + else if (tt > '9') + tt -= 7; + tt &= 0x1f; + spin_lock_irqsave(ich->is->hwlock, flags); + isar_pump_cmd(ich, PCTRL_CMD_TDTMF, tt); + spin_unlock_irqrestore(ich->is->hwlock, flags); + } else { + pr_info("%s: DTMF send wrong protocol %x\n", + __func__, bch->state); + return -EINVAL; + } + } else if ((hh->id == HW_MOD_FRM) || (hh->id == HW_MOD_FRH) || + (hh->id == HW_MOD_FTM) || (hh->id == HW_MOD_FTH)) { + for (id = 0; id < FAXMODCNT; id++) + if (faxmodulation[id] == *val) + break; + if ((FAXMODCNT > id) && + test_bit(FLG_INITIALIZED, &bch->Flags)) { + pr_debug("%s: isar: new mod\n", ich->is->name); + isar_pump_cmd(ich, hh->id, *val); + ret = 0; + } else { + pr_info("%s: wrong modulation\n", + ich->is->name); + ret = -EINVAL; + } + } else if (hh->id == HW_MOD_LASTDATA) + test_and_set_bit(FLG_DLEETX, &bch->Flags); + else { + pr_info("%s: unknown PH_CONTROL_REQ %x\n", + ich->is->name, hh->id); + ret = -EINVAL; + } + default: + pr_info("%s: %s unknown prim(%x,%x)\n", + ich->is->name, __func__, hh->prim, hh->id); + ret = -EINVAL; + } + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + /* Nothing implemented yet */ + case MISDN_CTRL_FILL_EMPTY: + default: + pr_info("%s: unknown Op %x\n", __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct isar_ch *ich = container_of(bch, struct isar_ch, bch); + int ret = -EINVAL; + u_long flags; + + pr_debug("%s: %s cmd:%x %p\n", ich->is->name, __func__, cmd, arg); + switch (cmd) { + case CLOSE_CHANNEL: + test_and_clear_bit(FLG_OPEN, &bch->Flags); + if (test_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(ich->is->hwlock, flags); + mISDN_freebchannel(bch); + modeisar(ich, ISDN_P_NONE); + spin_unlock_irqrestore(ich->is->hwlock, flags); + } else { + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; + } + ch->protocol = ISDN_P_NONE; + ch->peer = NULL; + module_put(ich->is->owner); + ret = 0; + break; + case CONTROL_CHANNEL: + ret = channel_bctrl(bch, arg); + break; + default: + pr_info("%s: %s unknown prim(%x)\n", + ich->is->name, __func__, cmd); + } + return ret; +} + +static void +free_isar(struct isar_hw *isar) +{ + modeisar(&isar->ch[0], ISDN_P_NONE); + modeisar(&isar->ch[1], ISDN_P_NONE); + del_timer(&isar->ch[0].ftimer); + del_timer(&isar->ch[1].ftimer); + test_and_clear_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); + test_and_clear_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); +} + +static int +init_isar(struct isar_hw *isar) +{ + int cnt = 3; + + while (cnt--) { + isar->version = ISARVersion(isar); + if (isar->ch[0].bch.debug & DEBUG_HW) + pr_notice("%s: Testing version %d (%d time)\n", + isar->name, isar->version, 3 - cnt); + if (isar->version == 1) + break; + isar->ctrl(isar->hw, HW_RESET_REQ, 0); + } + if (isar->version != 1) + return -EINVAL; + isar->ch[0].ftimer.function = &ftimer_handler; + isar->ch[0].ftimer.data = (long)&isar->ch[0]; + init_timer(&isar->ch[0].ftimer); + test_and_set_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); + isar->ch[1].ftimer.function = &ftimer_handler; + isar->ch[1].ftimer.data = (long)&isar->ch[1]; + init_timer(&isar->ch[1].ftimer); + test_and_set_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); + return 0; +} + +static int +isar_open(struct isar_hw *isar, struct channel_req *rq) +{ + struct bchannel *bch; + + if (rq->adr.channel > 2) + return -EINVAL; + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + bch = &isar->ch[rq->adr.channel - 1].bch; + if (test_and_set_bit(FLG_OPEN, &bch->Flags)) + return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + bch->ch.protocol = rq->protocol; + rq->ch = &bch->ch; + return 0; +} + +u32 +mISDNisar_init(struct isar_hw *isar, void *hw) +{ + u32 ret, i; + + isar->hw = hw; + for (i = 0; i < 2; i++) { + isar->ch[i].bch.nr = i + 1; + mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM); + isar->ch[i].bch.ch.nr = i + 1; + isar->ch[i].bch.ch.send = &isar_l2l1; + isar->ch[i].bch.ch.ctrl = isar_bctrl; + isar->ch[i].bch.hw = hw; + isar->ch[i].is = isar; + } + + isar->init = &init_isar; + isar->release = &free_isar; + isar->firmware = &load_firmware; + isar->open = &isar_open; + + ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_L2DTMF & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_MODEM_ASYNC & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_T30_FAX & ISDN_P_B_MASK)); + + return ret; +} +EXPORT_SYMBOL(mISDNisar_init); + +static int isar_mod_init(void) +{ + pr_notice("mISDN: ISAR driver Rev. %s\n", ISAR_REV); + return 0; +} + +static void isar_mod_cleanup(void) +{ + pr_notice("mISDN: ISAR module unloaded\n"); +} +module_init(isar_mod_init); +module_exit(isar_mod_cleanup); diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c new file mode 100644 index 0000000..ff3a4e2 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/speedfax.c @@ -0,0 +1,526 @@ +/* + * speedfax.c low level stuff for Sedlbauer Speedfax+ cards + * based on the ISAR DSP + * Thanks to Sedlbauer AG for informations and HW + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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 "ipac.h" +#include "isar.h" + +#define SPEEDFAX_REV "2.0" + +#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 +#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 +#define PCI_SUB_ID_SEDLBAUER 0x01 + +#define SFAX_PCI_ADDR 0xc8 +#define SFAX_PCI_ISAC 0xd0 +#define SFAX_PCI_ISAR 0xe0 + +/* TIGER 100 Registers */ + +#define TIGER_RESET_ADDR 0x00 +#define TIGER_EXTERN_RESET_ON 0x01 +#define TIGER_EXTERN_RESET_OFF 0x00 +#define TIGER_AUX_CTRL 0x02 +#define TIGER_AUX_DATA 0x03 +#define TIGER_AUX_IRQMASK 0x05 +#define TIGER_AUX_STATUS 0x07 + +/* Tiger AUX BITs */ +#define SFAX_AUX_IOMASK 0xdd /* 1 and 5 are inputs */ +#define SFAX_ISAR_RESET_BIT_OFF 0x00 +#define SFAX_ISAR_RESET_BIT_ON 0x01 +#define SFAX_TIGER_IRQ_BIT 0x02 +#define SFAX_LED1_BIT 0x08 +#define SFAX_LED2_BIT 0x10 + +#define SFAX_PCI_RESET_ON (SFAX_ISAR_RESET_BIT_ON) +#define SFAX_PCI_RESET_OFF (SFAX_LED1_BIT | SFAX_LED2_BIT) + +static int sfax_cnt; +static u32 debug; +static u32 irqloops = 4; + +struct sfax_hw { + struct list_head list; + struct pci_dev *pdev; + char name[MISDN_MAX_IDLEN]; + u32 irq; + u32 irqcnt; + u32 cfg; + struct _ioport p_isac; + struct _ioport p_isar; + u8 aux_data; + spinlock_t lock; /* HW access lock */ + struct isac_hw isac; + struct isar_hw isar; +}; + +static LIST_HEAD(Cards); +static DEFINE_RWLOCK(card_lock); /* protect Cards */ + +static void +_set_debug(struct sfax_hw *card) +{ + card->isac.dch.debug = debug; + card->isar.ch[0].bch.debug = debug; + card->isar.ch[1].bch.debug = debug; +} + +static int +set_debug(const char *val, struct kernel_param *kp) +{ + int ret; + struct sfax_hw *card; + + ret = param_set_uint(val, kp); + if (!ret) { + read_lock(&card_lock); + list_for_each_entry(card, &Cards, list) + _set_debug(card); + read_unlock(&card_lock); + } + return ret; +} + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(SPEEDFAX_REV); +module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Speedfax debug mask"); +module_param(irqloops, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)"); + +IOFUNC_IND(ISAC, sfax_hw, p_isac) +IOFUNC_IND(ISAR, sfax_hw, p_isar) + +static irqreturn_t +speedfax_irq(int intno, void *dev_id) +{ + struct sfax_hw *sf = dev_id; + u8 val; + int cnt = irqloops; + + spin_lock(&sf->lock); + val = inb(sf->cfg + TIGER_AUX_STATUS); + if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */ + spin_unlock(&sf->lock); + return IRQ_NONE; /* shared */ + } + sf->irqcnt++; + val = ReadISAR_IND(sf, ISAR_IRQBIT); +Start_ISAR: + if (val & ISAR_IRQSTA) + mISDNisar_irq(&sf->isar); + val = ReadISAC_IND(sf, ISAC_ISTA); + if (val) + mISDNisac_irq(&sf->isac, val); + val = ReadISAR_IND(sf, ISAR_IRQBIT); + if ((val & ISAR_IRQSTA) && cnt--) + goto Start_ISAR; + if (cnt < irqloops) + pr_debug("%s: %d irqloops cpu%d\n", sf->name, + irqloops - cnt, smp_processor_id()); + if (irqloops && !cnt) + pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name, + irqloops, smp_processor_id()); + spin_unlock(&sf->lock); + return IRQ_HANDLED; +} + +static void +enable_hwirq(struct sfax_hw *sf) +{ + WriteISAC_IND(sf, ISAC_MASK, 0); + WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK); + outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK); +} + +static void +disable_hwirq(struct sfax_hw *sf) +{ + WriteISAC_IND(sf, ISAC_MASK, 0xFF); + WriteISAR_IND(sf, ISAR_IRQBIT, 0); + outb(0, sf->cfg + TIGER_AUX_IRQMASK); +} + +static void +reset_speedfax(struct sfax_hw *sf) +{ + + pr_debug("%s: resetting card\n", sf->name); + outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR); + outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA); + mdelay(1); + outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR); + sf->aux_data = SFAX_PCI_RESET_OFF; + outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); + mdelay(1); +} + +static int +sfax_ctrl(struct sfax_hw *sf, u32 cmd, u_long arg) +{ + int ret = 0; + + switch (cmd) { + case HW_RESET_REQ: + reset_speedfax(sf); + break; + case HW_ACTIVATE_IND: + if (arg & 1) + sf->aux_data &= ~SFAX_LED1_BIT; + if (arg & 2) + sf->aux_data &= ~SFAX_LED2_BIT; + outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); + break; + case HW_DEACT_IND: + if (arg & 1) + sf->aux_data |= SFAX_LED1_BIT; + if (arg & 2) + sf->aux_data |= SFAX_LED2_BIT; + outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); + break; + default: + pr_info("%s: %s unknown command %x %lx\n", + sf->name, __func__, cmd, arg); + ret = -EINVAL; + break; + } + return ret; +} + +static int +channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_LOOP; + break; + case MISDN_CTRL_LOOP: + /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ + if (cq->channel < 0 || cq->channel > 3) { + ret = -EINVAL; + break; + } + ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel); + break; + default: + pr_info("%s: unknown Op %x\n", sf->name, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct sfax_hw *sf = dch->hw; + struct channel_req *rq; + int err = 0; + + pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg); + switch (cmd) { + case OPEN_CHANNEL: + rq = arg; + if (rq->protocol == ISDN_P_TE_S0) + err = sf->isac.open(&sf->isac, rq); + else + err = sf->isar.open(&sf->isar, rq); + if (err) + break; + if (!try_module_get(THIS_MODULE)) + pr_info("%s: cannot get module\n", sf->name); + break; + case CLOSE_CHANNEL: + pr_debug("%s: dev(%d) close from %p\n", sf->name, + dch->dev.id, __builtin_return_address(0)); + module_put(THIS_MODULE); + break; + case CONTROL_CHANNEL: + err = channel_ctrl(sf, arg); + break; + default: + pr_debug("%s: unknown command %x\n", sf->name, cmd); + return -EINVAL; + } + return err; +} + +static int __devinit +init_card(struct sfax_hw *sf) +{ + int ret, cnt = 3; + u_long flags; + + ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf); + if (ret) { + pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq); + return ret; + } + while (cnt--) { + spin_lock_irqsave(&sf->lock, flags); + ret = sf->isac.init(&sf->isac); + if (ret) { + spin_unlock_irqrestore(&sf->lock, flags); + pr_info("%s: ISAC init failed with %d\n", + sf->name, ret); + break; + } + enable_hwirq(sf); + /* RESET Receiver and Transmitter */ + WriteISAC_IND(sf, ISAC_CMDR, 0x41); + spin_unlock_irqrestore(&sf->lock, flags); + msleep_interruptible(10); + if (debug & DEBUG_HW) + pr_notice("%s: IRQ %d count %d\n", sf->name, + sf->irq, sf->irqcnt); + if (!sf->irqcnt) { + pr_info("%s: IRQ(%d) got no requests during init %d\n", + sf->name, sf->irq, 3 - cnt); + } else + return 0; + } + free_irq(sf->irq, sf); + return -EIO; +} + + +static int __devinit +setup_speedfax(struct sfax_hw *sf) +{ + u_long flags; + + if (!request_region(sf->cfg, 256, sf->name)) { + pr_info("mISDN: %s config port %x-%x already in use\n", + sf->name, sf->cfg, sf->cfg + 255); + return -EIO; + } + outb(0xff, sf->cfg); + outb(0, sf->cfg); + outb(0xdd, sf->cfg + TIGER_AUX_CTRL); + outb(0, sf->cfg + TIGER_AUX_IRQMASK); + + sf->isac.type = IPAC_TYPE_ISAC; + sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR; + sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC; + sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR; + sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR; + ASSIGN_FUNC(IND, ISAC, sf->isac); + ASSIGN_FUNC(IND, ISAR, sf->isar); + spin_lock_irqsave(&sf->lock, flags); + reset_speedfax(sf); + disable_hwirq(sf); + spin_unlock_irqrestore(&sf->lock, flags); + return 0; +} + +static void +release_card(struct sfax_hw *card) { + u_long flags; + + spin_lock_irqsave(&card->lock, flags); + disable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); + card->isac.release(&card->isac); + free_irq(card->irq, card); + card->isar.release(&card->isar); + mISDN_unregister_device(&card->isac.dch.dev); + release_region(card->cfg, 256); + pci_disable_device(card->pdev); + pci_set_drvdata(card->pdev, NULL); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + kfree(card); + sfax_cnt--; +} + +static int __devinit +setup_instance(struct sfax_hw *card) +{ + const struct firmware *firmware; + int i, err; + u_long flags; + + snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1); + write_lock_irqsave(&card_lock, flags); + list_add_tail(&card->list, &Cards); + write_unlock_irqrestore(&card_lock, flags); + _set_debug(card); + spin_lock_init(&card->lock); + card->isac.hwlock = &card->lock; + card->isar.hwlock = &card->lock; + card->isar.ctrl = (void *)&sfax_ctrl; + card->isac.name = card->name; + card->isar.name = card->name; + card->isar.owner = THIS_MODULE; + + err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev); + if (err < 0) { + pr_info("%s: firmware request failed %d\n", + card->name, err); + goto error_fw; + } + if (debug & DEBUG_HW) + pr_notice("%s: got firmware %zu bytes\n", + card->name, firmware->size); + + mISDNisac_init(&card->isac, card); + + card->isac.dch.dev.D.ctrl = sfax_dctrl; + card->isac.dch.dev.Bprotocols = + mISDNisar_init(&card->isar, card); + for (i = 0; i < 2; i++) { + set_channelmap(i + 1, card->isac.dch.dev.channelmap); + list_add(&card->isar.ch[i].bch.ch.list, + &card->isac.dch.dev.bchannels); + } + + err = setup_speedfax(card); + if (err) + goto error_setup; + err = card->isar.init(&card->isar); + if (err) + goto error; + err = mISDN_register_device(&card->isac.dch.dev, + &card->pdev->dev, card->name); + if (err) + goto error; + err = init_card(card); + if (err) + goto error_init; + err = card->isar.firmware(&card->isar, firmware->data, firmware->size); + if (!err) { + release_firmware(firmware); + sfax_cnt++; + pr_notice("SpeedFax %d cards installed\n", sfax_cnt); + return 0; + } + disable_hwirq(card); + free_irq(card->irq, card); +error_init: + mISDN_unregister_device(&card->isac.dch.dev); +error: + release_region(card->cfg, 256); +error_setup: + card->isac.release(&card->isac); + card->isar.release(&card->isar); + release_firmware(firmware); +error_fw: + pci_disable_device(card->pdev); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + kfree(card); + return err; +} + +static int __devinit +sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = -ENOMEM; + struct sfax_hw *card = kzalloc(sizeof(struct sfax_hw), GFP_KERNEL); + + if (!card) { + pr_info("No memory for Speedfax+ PCI\n"); + return err; + } + card->pdev = pdev; + err = pci_enable_device(pdev); + if (err) { + kfree(card); + return err; + } + + pr_notice("mISDN: Speedfax found adapter %s at %s\n", + (char *)ent->driver_data, pci_name(pdev)); + + card->cfg = pci_resource_start(pdev, 0); + card->irq = pdev->irq; + pci_set_drvdata(pdev, card); + err = setup_instance(card); + if (err) + pci_set_drvdata(pdev, NULL); + return err; +} + +static void __devexit +sfax_remove_pci(struct pci_dev *pdev) +{ + struct sfax_hw *card = pci_get_drvdata(pdev); + + if (card) + release_card(card); + else + pr_debug("%s: drvdata allready removed\n", __func__); +} + +static struct pci_device_id sfaxpci_ids[] __devinitdata = { + { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, + PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER, + 0, 0, (unsigned long) "Pyramid Speedfax + PCI" + }, + { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, + PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER, + 0, 0, (unsigned long) "Sedlbauer Speedfax + PCI" + }, + { } +}; +MODULE_DEVICE_TABLE(pci, sfaxpci_ids); + +static struct pci_driver sfaxpci_driver = { + .name = "speedfax+ pci", + .probe = sfaxpci_probe, + .remove = __devexit_p(sfax_remove_pci), + .id_table = sfaxpci_ids, +}; + +static int __init +Speedfax_init(void) +{ + int err; + + pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n", + SPEEDFAX_REV); + err = pci_register_driver(&sfaxpci_driver); + return err; +} + +static void __exit +Speedfax_cleanup(void) +{ + pci_unregister_driver(&sfaxpci_driver); +} + +module_init(Speedfax_init); +module_exit(Speedfax_cleanup); diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index 45100b3..536ca12 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h @@ -37,7 +37,7 @@ */ #define MISDN_MAJOR_VERSION 1 #define MISDN_MINOR_VERSION 1 -#define MISDN_RELEASE 20 +#define MISDN_RELEASE 21 /* primitives for information exchange * generell format @@ -153,6 +153,18 @@ #define HFC_VOL_CHANGE_RX 0x2602 #define HFC_SPL_LOOP_ON 0x2603 #define HFC_SPL_LOOP_OFF 0x2604 +/* for T30 FAX and analog modem */ +#define HW_MOD_FRM 0x4000 +#define HW_MOD_FRH 0x4001 +#define HW_MOD_FTM 0x4002 +#define HW_MOD_FTH 0x4003 +#define HW_MOD_FTS 0x4004 +#define HW_MOD_CONNECT 0x4010 +#define HW_MOD_OK 0x4011 +#define HW_MOD_NOCARR 0x4012 +#define HW_MOD_FCERROR 0x4013 +#define HW_MOD_READY 0x4014 +#define HW_MOD_LASTDATA 0x4015 /* DSP_TONE_PATT_ON parameter */ #define TONE_OFF 0x0000 @@ -224,6 +236,8 @@ #define ISDN_P_B_L2DTMF 0x24 #define ISDN_P_B_L2DSP 0x25 #define ISDN_P_B_L2DSPHDLC 0x26 +#define ISDN_P_B_T30_FAX 0x27 +#define ISDN_P_B_MODEM_ASYNC 0x28 #define OPTION_L2_PMX 1 #define OPTION_L2_PTP 2 -- cgit v0.10.2 From 707b2ce6c1f4f1261788f2ff09ad82c35e0e6240 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 22 Jul 2009 20:06:05 +0200 Subject: mISDN: Add driver for Winbond cards Add driver for Winbond W6692 based PCI cards. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index 2600534..d72586e 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -65,6 +65,13 @@ config MISDN_INFINEON Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX chip from Infineon (former manufacturer Siemens). +config MISDN_W6692 + tristate "Support for cards with Winbond 6692" + depends on MISDN + depends on PCI + help + Enable support for Winbond 6692 PCI chip based cards. + config MISDN_IPAC tristate diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index e18f964..61dd5a5 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o +obj-$(CONFIG_MISDN_W6692) += w6692.o # chip modules obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c new file mode 100644 index 0000000..1b9008f --- /dev/null +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -0,0 +1,1440 @@ +/* + * w6692.c mISDN driver for Winbond w6692 based cards + * + * Author Karsten Keil + * based on the w6692 I4L driver from Petr Novak + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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 "w6692.h" + +#define W6692_REV "2.0" + +#define DBUSY_TIMER_VALUE 80 + +enum { + W6692_ASUS, + W6692_WINBOND, + W6692_USR +}; + +/* private data in the PCI devices list */ +struct w6692map { + u_int subtype; + char *name; +}; + +static const struct w6692map w6692_map[] = +{ + {W6692_ASUS, "Dynalink/AsusCom IS64PH"}, + {W6692_WINBOND, "Winbond W6692"}, + {W6692_USR, "USR W6692"} +}; + +#ifndef PCI_VENDOR_ID_USR +#define PCI_VENDOR_ID_USR 0x16ec +#define PCI_DEVICE_ID_USR_6692 0x3409 +#endif + +struct w6692_ch { + struct bchannel bch; + u32 addr; + struct timer_list timer; + u8 b_mode; +}; + +struct w6692_hw { + struct list_head list; + struct pci_dev *pdev; + char name[MISDN_MAX_IDLEN]; + u32 irq; + u32 irqcnt; + u32 addr; + u32 fmask; /* feature mask - bit set per card nr */ + int subtype; + spinlock_t lock; /* hw lock */ + u8 imask; + u8 pctl; + u8 xaddr; + u8 xdata; + u8 state; + struct w6692_ch bc[2]; + struct dchannel dch; + char log[64]; +}; + +static LIST_HEAD(Cards); +static DEFINE_RWLOCK(card_lock); /* protect Cards */ + +static int w6692_cnt; +static int debug; +static u32 led; +static u32 pots; + +static void +_set_debug(struct w6692_hw *card) +{ + card->dch.debug = debug; + card->bc[0].bch.debug = debug; + card->bc[1].bch.debug = debug; +} + +static int +set_debug(const char *val, struct kernel_param *kp) +{ + int ret; + struct w6692_hw *card; + + ret = param_set_uint(val, kp); + if (!ret) { + read_lock(&card_lock); + list_for_each_entry(card, &Cards, list) + _set_debug(card); + read_unlock(&card_lock); + } + return ret; +} + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(W6692_REV); +module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "W6692 debug mask"); +module_param(led, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(led, "W6692 LED support bitmask (one bit per card)"); +module_param(pots, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(pots, "W6692 POTS support bitmask (one bit per card)"); + +static inline u8 +ReadW6692(struct w6692_hw *card, u8 offset) +{ + return inb(card->addr + offset); +} + +static inline void +WriteW6692(struct w6692_hw *card, u8 offset, u8 value) +{ + outb(value, card->addr + offset); +} + +static inline u8 +ReadW6692B(struct w6692_ch *bc, u8 offset) +{ + return inb(bc->addr + offset); +} + +static inline void +WriteW6692B(struct w6692_ch *bc, u8 offset, u8 value) +{ + outb(value, bc->addr + offset); +} + +static void +enable_hwirq(struct w6692_hw *card) +{ + WriteW6692(card, W_IMASK, card->imask); +} + +static void +disable_hwirq(struct w6692_hw *card) +{ + WriteW6692(card, W_IMASK, 0xff); +} + +static const char *W6692Ver[] = {"V00", "V01", "V10", "V11"}; + +static void +W6692Version(struct w6692_hw *card) +{ + int val; + + val = ReadW6692(card, W_D_RBCH); + pr_notice("%s: Winbond W6692 version: %s\n", card->name, + W6692Ver[(val >> 6) & 3]); +} + +static void +w6692_led_handler(struct w6692_hw *card, int on) +{ + if ((!(card->fmask & led)) || card->subtype == W6692_USR) + return; + if (on) { + card->xdata &= 0xfb; /* LED ON */ + WriteW6692(card, W_XDATA, card->xdata); + } else { + card->xdata |= 0x04; /* LED OFF */ + WriteW6692(card, W_XDATA, card->xdata); + } +} + +static void +ph_command(struct w6692_hw *card, u8 cmd) +{ + pr_debug("%s: ph_command %x\n", card->name, cmd); + WriteW6692(card, W_CIX, cmd); +} + +static void +W6692_new_ph(struct w6692_hw *card) +{ + if (card->state == W_L1CMD_RST) + ph_command(card, W_L1CMD_DRC); + schedule_event(&card->dch, FLG_PHCHANGE); +} + +static void +W6692_ph_bh(struct dchannel *dch) +{ + struct w6692_hw *card = dch->hw; + + switch (card->state) { + case W_L1CMD_RST: + dch->state = 0; + l1_event(dch->l1, HW_RESET_IND); + break; + case W_L1IND_CD: + dch->state = 3; + l1_event(dch->l1, HW_DEACT_CNF); + break; + case W_L1IND_DRD: + dch->state = 3; + l1_event(dch->l1, HW_DEACT_IND); + break; + case W_L1IND_CE: + dch->state = 4; + l1_event(dch->l1, HW_POWERUP_IND); + break; + case W_L1IND_LD: + if (dch->state <= 5) { + dch->state = 5; + l1_event(dch->l1, ANYSIGNAL); + } else { + dch->state = 8; + l1_event(dch->l1, LOSTFRAMING); + } + break; + case W_L1IND_ARD: + dch->state = 6; + l1_event(dch->l1, INFO2); + break; + case W_L1IND_AI8: + dch->state = 7; + l1_event(dch->l1, INFO4_P8); + break; + case W_L1IND_AI10: + dch->state = 7; + l1_event(dch->l1, INFO4_P10); + break; + default: + pr_debug("%s: TE unknown state %02x dch state %02x\n", + card->name, card->state, dch->state); + break; + } + pr_debug("%s: TE newstate %02x\n", card->name, dch->state); +} + +static void +W6692_empty_Dfifo(struct w6692_hw *card, int count) +{ + struct dchannel *dch = &card->dch; + u8 *ptr; + + pr_debug("%s: empty_Dfifo %d\n", card->name, count); + if (!dch->rx_skb) { + dch->rx_skb = mI_alloc_skb(card->dch.maxlen, GFP_ATOMIC); + if (!dch->rx_skb) { + pr_info("%s: D receive out of memory\n", card->name); + WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); + return; + } + } + if ((dch->rx_skb->len + count) >= dch->maxlen) { + pr_debug("%s: empty_Dfifo overrun %d\n", card->name, + dch->rx_skb->len + count); + WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); + return; + } + ptr = skb_put(dch->rx_skb, count); + insb(card->addr + W_D_RFIFO, ptr, count); + WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); + if (debug & DEBUG_HW_DFIFO) { + snprintf(card->log, 63, "D-recv %s %d ", + card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static void +W6692_fill_Dfifo(struct w6692_hw *card) +{ + struct dchannel *dch = &card->dch; + int count; + u8 *ptr; + u8 cmd = W_D_CMDR_XMS; + + pr_debug("%s: fill_Dfifo\n", card->name); + if (!dch->tx_skb) + return; + count = dch->tx_skb->len - dch->tx_idx; + if (count <= 0) + return; + if (count > W_D_FIFO_THRESH) + count = W_D_FIFO_THRESH; + else + cmd |= W_D_CMDR_XME; + ptr = dch->tx_skb->data + dch->tx_idx; + dch->tx_idx += count; + outsb(card->addr + W_D_XFIFO, ptr, count); + WriteW6692(card, W_D_CMDR, cmd); + if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) { + pr_debug("%s: fill_Dfifo dbusytimer running\n", card->name); + del_timer(&dch->timer); + } + init_timer(&dch->timer); + dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); + add_timer(&dch->timer); + if (debug & DEBUG_HW_DFIFO) { + snprintf(card->log, 63, "D-send %s %d ", + card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static void +d_retransmit(struct w6692_hw *card) +{ + struct dchannel *dch = &card->dch; + + if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) + del_timer(&dch->timer); +#ifdef FIXME + if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) + dchannel_sched_event(dch, D_CLEARBUSY); +#endif + if (test_bit(FLG_TX_BUSY, &dch->Flags)) { + /* Restart frame */ + dch->tx_idx = 0; + W6692_fill_Dfifo(card); + } else if (dch->tx_skb) { /* should not happen */ + pr_info("%s: %s without TX_BUSY\n", card->name, __func__); + test_and_set_bit(FLG_TX_BUSY, &dch->Flags); + dch->tx_idx = 0; + W6692_fill_Dfifo(card); + } else { + pr_info("%s: XDU no TX_BUSY\n", card->name); + if (get_next_dframe(dch)) + W6692_fill_Dfifo(card); + } +} + +static void +handle_rxD(struct w6692_hw *card) { + u8 stat; + int count; + + stat = ReadW6692(card, W_D_RSTA); + if (stat & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) { + if (stat & W_D_RSTA_RDOV) { + pr_debug("%s: D-channel RDOV\n", card->name); +#ifdef ERROR_STATISTIC + card->dch.err_rx++; +#endif + } + if (stat & W_D_RSTA_CRCE) { + pr_debug("%s: D-channel CRC error\n", card->name); +#ifdef ERROR_STATISTIC + card->dch.err_crc++; +#endif + } + if (stat & W_D_RSTA_RMB) { + pr_debug("%s: D-channel ABORT\n", card->name); +#ifdef ERROR_STATISTIC + card->dch.err_rx++; +#endif + } + if (card->dch.rx_skb) + dev_kfree_skb(card->dch.rx_skb); + card->dch.rx_skb = NULL; + WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); + } else { + count = ReadW6692(card, W_D_RBCL) & (W_D_FIFO_THRESH - 1); + if (count == 0) + count = W_D_FIFO_THRESH; + W6692_empty_Dfifo(card, count); + recv_Dchannel(&card->dch); + } +} + +static void +handle_txD(struct w6692_hw *card) { + if (test_and_clear_bit(FLG_BUSY_TIMER, &card->dch.Flags)) + del_timer(&card->dch.timer); + if (card->dch.tx_skb && card->dch.tx_idx < card->dch.tx_skb->len) { + W6692_fill_Dfifo(card); + } else { + if (card->dch.tx_skb) + dev_kfree_skb(card->dch.tx_skb); + if (get_next_dframe(&card->dch)) + W6692_fill_Dfifo(card); + } +} + +static void +handle_statusD(struct w6692_hw *card) +{ + struct dchannel *dch = &card->dch; + u8 exval, v1, cir; + + exval = ReadW6692(card, W_D_EXIR); + + pr_debug("%s: D_EXIR %02x\n", card->name, exval); + if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { + /* Transmit underrun/collision */ + pr_debug("%s: D-channel underrun/collision\n", card->name); +#ifdef ERROR_STATISTIC + dch->err_tx++; +#endif + d_retransmit(card); + } + if (exval & W_D_EXI_RDOV) { /* RDOV */ + pr_debug("%s: D-channel RDOV\n", card->name); + WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST); + } + if (exval & W_D_EXI_TIN2) /* TIN2 - never */ + pr_debug("%s: spurious TIN2 interrupt\n", card->name); + if (exval & W_D_EXI_MOC) { /* MOC - not supported */ + v1 = ReadW6692(card, W_MOSR); + pr_debug("%s: spurious MOC interrupt MOSR %02x\n", + card->name, v1); + } + if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */ + cir = ReadW6692(card, W_CIR); + pr_debug("%s: ISC CIR %02X\n", card->name, cir); + if (cir & W_CIR_ICC) { + v1 = cir & W_CIR_COD_MASK; + pr_debug("%s: ph_state_change %x -> %x\n", card->name, + dch->state, v1); + card->state = v1; + if (card->fmask & led) { + switch (v1) { + case W_L1IND_AI8: + case W_L1IND_AI10: + w6692_led_handler(card, 1); + break; + default: + w6692_led_handler(card, 0); + break; + } + } + W6692_new_ph(card); + } + if (cir & W_CIR_SCC) { + v1 = ReadW6692(card, W_SQR); + pr_debug("%s: SCC SQR %02X\n", card->name, v1); + } + } + if (exval & W_D_EXI_WEXP) + pr_debug("%s: spurious WEXP interrupt!\n", card->name); + if (exval & W_D_EXI_TEXP) + pr_debug("%s: spurious TEXP interrupt!\n", card->name); +} + +static void +W6692_empty_Bfifo(struct w6692_ch *wch, int count) +{ + struct w6692_hw *card = wch->bch.hw; + u8 *ptr; + + pr_debug("%s: empty_Bfifo %d\n", card->name, count); + if (unlikely(wch->bch.state == ISDN_P_NONE)) { + pr_debug("%s: empty_Bfifo ISDN_P_NONE\n", card->name); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + if (wch->bch.rx_skb) + skb_trim(wch->bch.rx_skb, 0); + return; + } + if (!wch->bch.rx_skb) { + wch->bch.rx_skb = mI_alloc_skb(wch->bch.maxlen, GFP_ATOMIC); + if (unlikely(!wch->bch.rx_skb)) { + pr_info("%s: B receive out of memory\n", card->name); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | + W_B_CMDR_RACT); + return; + } + } + if (wch->bch.rx_skb->len + count > wch->bch.maxlen) { + pr_debug("%s: empty_Bfifo incoming packet too large\n", + card->name); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + skb_trim(wch->bch.rx_skb, 0); + return; + } + ptr = skb_put(wch->bch.rx_skb, count); + insb(wch->addr + W_B_RFIFO, ptr, count); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + if (debug & DEBUG_HW_DFIFO) { + snprintf(card->log, 63, "B%1d-recv %s %d ", + wch->bch.nr, card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static void +W6692_fill_Bfifo(struct w6692_ch *wch) +{ + struct w6692_hw *card = wch->bch.hw; + int count; + u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS; + + pr_debug("%s: fill Bfifo\n", card->name); + if (!wch->bch.tx_skb) + return; + count = wch->bch.tx_skb->len - wch->bch.tx_idx; + if (count <= 0) + return; + ptr = wch->bch.tx_skb->data + wch->bch.tx_idx; + if (count > W_B_FIFO_THRESH) + count = W_B_FIFO_THRESH; + else if (test_bit(FLG_HDLC, &wch->bch.Flags)) + cmd |= W_B_CMDR_XME; + + pr_debug("%s: fill Bfifo%d/%d\n", card->name, + count, wch->bch.tx_idx); + wch->bch.tx_idx += count; + outsb(wch->addr + W_B_XFIFO, ptr, count); + WriteW6692B(wch, W_B_CMDR, cmd); + if (debug & DEBUG_HW_DFIFO) { + snprintf(card->log, 63, "B%1d-send %s %d ", + wch->bch.nr, card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static int +setvolume(struct w6692_ch *wch, int mic, struct sk_buff *skb) +{ + struct w6692_hw *card = wch->bch.hw; + u16 *vol = (u16 *)skb->data; + u8 val; + + if ((!(card->fmask & pots)) || + !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + return -ENODEV; + if (skb->len < 2) + return -EINVAL; + if (*vol > 7) + return -EINVAL; + val = *vol & 7; + val = 7 - val; + if (mic) { + val <<= 3; + card->xaddr &= 0xc7; + } else { + card->xaddr &= 0xf8; + } + card->xaddr |= val; + WriteW6692(card, W_XADDR, card->xaddr); + return 0; +} + +static int +enable_pots(struct w6692_ch *wch) +{ + struct w6692_hw *card = wch->bch.hw; + + if ((!(card->fmask & pots)) || + !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + return -ENODEV; + wch->b_mode |= W_B_MODE_EPCM | W_B_MODE_BSW0; + WriteW6692B(wch, W_B_MODE, wch->b_mode); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); + card->pctl |= ((wch->bch.nr & 2) ? W_PCTL_PCX : 0); + WriteW6692(card, W_PCTL, card->pctl); + return 0; +} + +static int +disable_pots(struct w6692_ch *wch) +{ + struct w6692_hw *card = wch->bch.hw; + + if (!(card->fmask & pots)) + return -ENODEV; + wch->b_mode &= ~(W_B_MODE_EPCM | W_B_MODE_BSW0); + WriteW6692B(wch, W_B_MODE, wch->b_mode); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | + W_B_CMDR_XRST); + return 0; +} + +static int +w6692_mode(struct w6692_ch *wch, u32 pr) +{ + struct w6692_hw *card; + + card = wch->bch.hw; + pr_debug("%s: B%d protocol %x-->%x\n", card->name, + wch->bch.nr, wch->bch.state, pr); + switch (pr) { + case ISDN_P_NONE: + if ((card->fmask & pots) && (wch->b_mode & W_B_MODE_EPCM)) + disable_pots(wch); + wch->b_mode = 0; + mISDN_clear_bchannel(&wch->bch); + WriteW6692B(wch, W_B_MODE, wch->b_mode); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); + test_and_clear_bit(FLG_HDLC, &wch->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &wch->bch.Flags); + break; + case ISDN_P_B_RAW: + wch->b_mode = W_B_MODE_MMS; + WriteW6692B(wch, W_B_MODE, wch->b_mode); + WriteW6692B(wch, W_B_EXIM, 0); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | + W_B_CMDR_XRST); + test_and_set_bit(FLG_TRANSPARENT, &wch->bch.Flags); + break; + case ISDN_P_B_HDLC: + wch->b_mode = W_B_MODE_ITF; + WriteW6692B(wch, W_B_MODE, wch->b_mode); + WriteW6692B(wch, W_B_ADM1, 0xff); + WriteW6692B(wch, W_B_ADM2, 0xff); + WriteW6692B(wch, W_B_EXIM, 0); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | + W_B_CMDR_XRST); + test_and_set_bit(FLG_HDLC, &wch->bch.Flags); + break; + default: + pr_info("%s: protocol %x not known\n", card->name, pr); + return -ENOPROTOOPT; + } + wch->bch.state = pr; + return 0; +} + +static void +send_next(struct w6692_ch *wch) +{ + if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len) + W6692_fill_Bfifo(wch); + else { + if (wch->bch.tx_skb) { + /* send confirm, on trans, free on hdlc. */ + if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + confirm_Bsend(&wch->bch); + dev_kfree_skb(wch->bch.tx_skb); + } + if (get_next_bframe(&wch->bch)) + W6692_fill_Bfifo(wch); + } +} + +static void +W6692B_interrupt(struct w6692_hw *card, int ch) +{ + struct w6692_ch *wch = &card->bc[ch]; + int count; + u8 stat, star = 0; + + stat = ReadW6692B(wch, W_B_EXIR); + pr_debug("%s: B%d EXIR %02x\n", card->name, wch->bch.nr, stat); + if (stat & W_B_EXI_RME) { + star = ReadW6692B(wch, W_B_STAR); + if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { + if ((star & W_B_STAR_RDOV) && + test_bit(FLG_ACTIVE, &wch->bch.Flags)) { + pr_debug("%s: B%d RDOV proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); +#ifdef ERROR_STATISTIC + wch->bch.err_rdo++; +#endif + } + if (test_bit(FLG_HDLC, &wch->bch.Flags)) { + if (star & W_B_STAR_CRCE) { + pr_debug("%s: B%d CRC error\n", + card->name, wch->bch.nr); +#ifdef ERROR_STATISTIC + wch->bch.err_crc++; +#endif + } + if (star & W_B_STAR_RMB) { + pr_debug("%s: B%d message abort\n", + card->name, wch->bch.nr); +#ifdef ERROR_STATISTIC + wch->bch.err_inv++; +#endif + } + } + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | + W_B_CMDR_RRST | W_B_CMDR_RACT); + if (wch->bch.rx_skb) + skb_trim(wch->bch.rx_skb, 0); + } else { + count = ReadW6692B(wch, W_B_RBCL) & + (W_B_FIFO_THRESH - 1); + if (count == 0) + count = W_B_FIFO_THRESH; + W6692_empty_Bfifo(wch, count); + recv_Bchannel(&wch->bch, 0); + } + } + if (stat & W_B_EXI_RMR) { + if (!(stat & W_B_EXI_RME)) + star = ReadW6692B(wch, W_B_STAR); + if (star & W_B_STAR_RDOV) { + pr_debug("%s: B%d RDOV proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); +#ifdef ERROR_STATISTIC + wch->bch.err_rdo++; +#endif + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | + W_B_CMDR_RRST | W_B_CMDR_RACT); + } else { + W6692_empty_Bfifo(wch, W_B_FIFO_THRESH); + if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags) && + wch->bch.rx_skb && (wch->bch.rx_skb->len > 0)) + recv_Bchannel(&wch->bch, 0); + } + } + if (stat & W_B_EXI_RDOV) { + /* only if it is not handled yet */ + if (!(star & W_B_STAR_RDOV)) { + pr_debug("%s: B%d RDOV IRQ proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); +#ifdef ERROR_STATISTIC + wch->bch.err_rdo++; +#endif + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | + W_B_CMDR_RRST | W_B_CMDR_RACT); + } + } + if (stat & W_B_EXI_XFR) { + if (!(stat & (W_B_EXI_RME | W_B_EXI_RMR))) { + star = ReadW6692B(wch, W_B_STAR); + pr_debug("%s: B%d star %02x\n", card->name, + wch->bch.nr, star); + } + if (star & W_B_STAR_XDOW) { + pr_debug("%s: B%d XDOW proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); +#ifdef ERROR_STATISTIC + wch->bch.err_xdu++; +#endif + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | + W_B_CMDR_RACT); + /* resend */ + if (wch->bch.tx_skb) { + if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + wch->bch.tx_idx = 0; + } + } + send_next(wch); + if (stat & W_B_EXI_XDUN) + return; /* handle XDOW only once */ + } + if (stat & W_B_EXI_XDUN) { + pr_debug("%s: B%d XDUN proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); +#ifdef ERROR_STATISTIC + wch->bch.err_xdu++; +#endif + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); + /* resend */ + if (wch->bch.tx_skb) { + if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + wch->bch.tx_idx = 0; + } + send_next(wch); + } +} + +static irqreturn_t +w6692_irq(int intno, void *dev_id) +{ + struct w6692_hw *card = dev_id; + u8 ista; + + spin_lock(&card->lock); + ista = ReadW6692(card, W_ISTA); + if ((ista | card->imask) == card->imask) { + /* possible a shared IRQ reqest */ + spin_unlock(&card->lock); + return IRQ_NONE; + } + card->irqcnt++; + pr_debug("%s: ista %02x\n", card->name, ista); + ista &= ~card->imask; + if (ista & W_INT_B1_EXI) + W6692B_interrupt(card, 0); + if (ista & W_INT_B2_EXI) + W6692B_interrupt(card, 1); + if (ista & W_INT_D_RME) + handle_rxD(card); + if (ista & W_INT_D_RMR) + W6692_empty_Dfifo(card, W_D_FIFO_THRESH); + if (ista & W_INT_D_XFR) + handle_txD(card); + if (ista & W_INT_D_EXI) + handle_statusD(card); + if (ista & (W_INT_XINT0 | W_INT_XINT1)) /* XINT0/1 - never */ + pr_debug("%s: W6692 spurious XINT!\n", card->name); +/* End IRQ Handler */ + spin_unlock(&card->lock); + return IRQ_HANDLED; +} + +static void +dbusy_timer_handler(struct dchannel *dch) +{ + struct w6692_hw *card = dch->hw; + int rbch, star; + u_long flags; + + if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) { + spin_lock_irqsave(&card->lock, flags); + rbch = ReadW6692(card, W_D_RBCH); + star = ReadW6692(card, W_D_STAR); + pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n", + card->name, rbch, star); + if (star & W_D_STAR_XBZ) /* D-Channel Busy */ + test_and_set_bit(FLG_L1_BUSY, &dch->Flags); + else { + /* discard frame; reset transceiver */ + test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags); + if (dch->tx_idx) + dch->tx_idx = 0; + else + pr_info("%s: W6692 D-Channel Busy no tx_idx\n", + card->name); + /* Transmitter reset */ + WriteW6692(card, W_D_CMDR, W_D_CMDR_XRST); + } + spin_unlock_irqrestore(&card->lock, flags); + } +} + +void initW6692(struct w6692_hw *card) +{ + u8 val; + + card->dch.timer.function = (void *)dbusy_timer_handler; + card->dch.timer.data = (u_long)&card->dch; + init_timer(&card->dch.timer); + w6692_mode(&card->bc[0], ISDN_P_NONE); + w6692_mode(&card->bc[1], ISDN_P_NONE); + WriteW6692(card, W_D_CTL, 0x00); + disable_hwirq(card); + WriteW6692(card, W_D_SAM, 0xff); + WriteW6692(card, W_D_TAM, 0xff); + WriteW6692(card, W_D_MODE, W_D_MODE_RACT); + card->state = W_L1CMD_RST; + ph_command(card, W_L1CMD_RST); + ph_command(card, W_L1CMD_ECK); + /* enable all IRQ but extern */ + card->imask = 0x18; + WriteW6692(card, W_D_EXIM, 0x00); + WriteW6692B(&card->bc[0], W_B_EXIM, 0); + WriteW6692B(&card->bc[1], W_B_EXIM, 0); + /* Reset D-chan receiver and transmitter */ + WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST); + /* Reset B-chan receiver and transmitter */ + WriteW6692B(&card->bc[0], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); + WriteW6692B(&card->bc[1], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); + /* enable peripheral */ + if (card->subtype == W6692_USR) { + /* seems that USR implemented some power control features + * Pin 79 is connected to the oscilator circuit so we + * have to handle it here + */ + card->pctl = 0x80; + card->xdata = 0; + WriteW6692(card, W_PCTL, card->pctl); + WriteW6692(card, W_XDATA, card->xdata); + } else { + card->pctl = W_PCTL_OE5 | W_PCTL_OE4 | W_PCTL_OE2 | + W_PCTL_OE1 | W_PCTL_OE0; + card->xaddr = 0x00;/* all sw off */ + if (card->fmask & pots) + card->xdata |= 0x06; /* POWER UP/ LED OFF / ALAW */ + if (card->fmask & led) + card->xdata |= 0x04; /* LED OFF */ + if ((card->fmask & pots) || (card->fmask & led)) { + WriteW6692(card, W_PCTL, card->pctl); + WriteW6692(card, W_XADDR, card->xaddr); + WriteW6692(card, W_XDATA, card->xdata); + val = ReadW6692(card, W_XADDR); + if (debug & DEBUG_HW) + pr_notice("%s: W_XADDR=%02x\n", + card->name, val); + } + } +} + +static void +reset_w6692(struct w6692_hw *card) +{ + WriteW6692(card, W_D_CTL, W_D_CTL_SRST); + mdelay(10); + WriteW6692(card, W_D_CTL, 0); +} + +static int +init_card(struct w6692_hw *card) +{ + int cnt = 3; + u_long flags; + + spin_lock_irqsave(&card->lock, flags); + disable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); + if (request_irq(card->irq, w6692_irq, IRQF_SHARED, card->name, card)) { + pr_info("%s: couldn't get interrupt %d\n", card->name, + card->irq); + return -EIO; + } + while (cnt--) { + spin_lock_irqsave(&card->lock, flags); + initW6692(card); + enable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); + /* Timeout 10ms */ + msleep_interruptible(10); + if (debug & DEBUG_HW) + pr_notice("%s: IRQ %d count %d\n", card->name, + card->irq, card->irqcnt); + if (!card->irqcnt) { + pr_info("%s: IRQ(%d) getting no IRQs during init %d\n", + card->name, card->irq, 3 - cnt); + reset_w6692(card); + } else + return 0; + } + free_irq(card->irq, card); + return -EIO; +} + +static int +w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch); + struct w6692_hw *card = bch->hw; + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(&card->lock, flags); + ret = bchannel_senddata(bch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + ret = 0; + W6692_fill_Bfifo(bc); + spin_unlock_irqrestore(&card->lock, flags); + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(&card->lock, flags); + return ret; + case PH_ACTIVATE_REQ: + spin_lock_irqsave(&card->lock, flags); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) + ret = w6692_mode(bc, ch->protocol); + else + ret = 0; + spin_unlock_irqrestore(&card->lock, flags); + if (!ret) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + break; + case PH_DEACTIVATE_REQ: + spin_lock_irqsave(&card->lock, flags); + mISDN_clear_bchannel(bch); + w6692_mode(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); + _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + ret = 0; + break; + default: + pr_info("%s: %s unknown prim(%x,%x)\n", + card->name, __func__, hh->prim, hh->id); + ret = -EINVAL; + } + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + /* Nothing implemented yet */ + case MISDN_CTRL_FILL_EMPTY: + default: + pr_info("%s: unknown Op %x\n", __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +open_bchannel(struct w6692_hw *card, struct channel_req *rq) +{ + struct bchannel *bch; + + if (rq->adr.channel > 2) + return -EINVAL; + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + bch = &card->bc[rq->adr.channel - 1].bch; + if (test_and_set_bit(FLG_OPEN, &bch->Flags)) + return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + bch->ch.protocol = rq->protocol; + rq->ch = &bch->ch; + return 0; +} + +static int +channel_ctrl(struct w6692_hw *card, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + default: + pr_info("%s: unknown CTRL OP %x\n", card->name, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch); + struct w6692_hw *card = bch->hw; + int ret = -EINVAL; + u_long flags; + + pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); + switch (cmd) { + case CLOSE_CHANNEL: + test_and_clear_bit(FLG_OPEN, &bch->Flags); + if (test_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(&card->lock, flags); + mISDN_freebchannel(bch); + w6692_mode(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); + } else { + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; + } + ch->protocol = ISDN_P_NONE; + ch->peer = NULL; + module_put(THIS_MODULE); + ret = 0; + break; + case CONTROL_CHANNEL: + ret = channel_bctrl(bch, arg); + break; + default: + pr_info("%s: %s unknown prim(%x)\n", + card->name, __func__, cmd); + } + return ret; +} + +static int +w6692_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(&card->lock, flags); + ret = dchannel_senddata(dch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + W6692_fill_Dfifo(card); + ret = 0; + spin_unlock_irqrestore(&card->lock, flags); + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(&card->lock, flags); + return ret; + case PH_ACTIVATE_REQ: + ret = l1_event(dch->l1, hh->prim); + break; + case PH_DEACTIVATE_REQ: + test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); + ret = l1_event(dch->l1, hh->prim); + break; + } + + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +w6692_l1callback(struct dchannel *dch, u32 cmd) +{ + struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); + u_long flags; + + pr_debug("%s: cmd(%x) state(%02x)\n", card->name, cmd, card->state); + switch (cmd) { + case INFO3_P8: + spin_lock_irqsave(&card->lock, flags); + ph_command(card, W_L1CMD_AR8); + spin_unlock_irqrestore(&card->lock, flags); + break; + case INFO3_P10: + spin_lock_irqsave(&card->lock, flags); + ph_command(card, W_L1CMD_AR10); + spin_unlock_irqrestore(&card->lock, flags); + break; + case HW_RESET_REQ: + spin_lock_irqsave(&card->lock, flags); + if (card->state != W_L1IND_DRD) + ph_command(card, W_L1CMD_RST); + ph_command(card, W_L1CMD_ECK); + spin_unlock_irqrestore(&card->lock, flags); + break; + case HW_DEACT_REQ: + skb_queue_purge(&dch->squeue); + if (dch->tx_skb) { + dev_kfree_skb(dch->tx_skb); + dch->tx_skb = NULL; + } + dch->tx_idx = 0; + if (dch->rx_skb) { + dev_kfree_skb(dch->rx_skb); + dch->rx_skb = NULL; + } + test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); + if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) + del_timer(&dch->timer); + break; + case HW_POWERUP_REQ: + spin_lock_irqsave(&card->lock, flags); + ph_command(card, W_L1CMD_ECK); + spin_unlock_irqrestore(&card->lock, flags); + break; + case PH_ACTIVATE_IND: + test_and_set_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, + GFP_ATOMIC); + break; + case PH_DEACTIVATE_IND: + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, + GFP_ATOMIC); + break; + default: + pr_debug("%s: %s unknown command %x\n", card->name, + __func__, cmd); + return -1; + } + return 0; +} + +static int +open_dchannel(struct w6692_hw *card, struct channel_req *rq) +{ + pr_debug("%s: %s dev(%d) open from %p\n", card->name, __func__, + card->dch.dev.id, __builtin_return_address(1)); + if (rq->protocol != ISDN_P_TE_S0) + return -EINVAL; + if (rq->adr.channel == 1) + /* E-Channel not supported */ + return -EINVAL; + rq->ch = &card->dch.dev.D; + rq->ch->protocol = rq->protocol; + if (card->dch.state == 7) + _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY, + 0, NULL, GFP_KERNEL); + return 0; +} + +static int +w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); + struct channel_req *rq; + int err = 0; + + pr_debug("%s: DCTRL: %x %p\n", card->name, cmd, arg); + switch (cmd) { + case OPEN_CHANNEL: + rq = arg; + if (rq->protocol == ISDN_P_TE_S0) + err = open_dchannel(card, rq); + else + err = open_bchannel(card, rq); + if (err) + break; + if (!try_module_get(THIS_MODULE)) + pr_info("%s: cannot get module\n", card->name); + break; + case CLOSE_CHANNEL: + pr_debug("%s: dev(%d) close from %p\n", card->name, + dch->dev.id, __builtin_return_address(0)); + module_put(THIS_MODULE); + break; + case CONTROL_CHANNEL: + err = channel_ctrl(card, arg); + break; + default: + pr_debug("%s: unknown DCTRL command %x\n", card->name, cmd); + return -EINVAL; + } + return err; +} + +int +setup_w6692(struct w6692_hw *card) +{ + u32 val; + + if (!request_region(card->addr, 256, card->name)) { + pr_info("%s: config port %x-%x already in use\n", card->name, + card->addr, card->addr + 255); + return -EIO; + } + W6692Version(card); + card->bc[0].addr = card->addr; + card->bc[1].addr = card->addr + 0x40; + val = ReadW6692(card, W_ISTA); + if (debug & DEBUG_HW) + pr_notice("%s ISTA=%02x\n", card->name, val); + val = ReadW6692(card, W_IMASK); + if (debug & DEBUG_HW) + pr_notice("%s IMASK=%02x\n", card->name, val); + val = ReadW6692(card, W_D_EXIR); + if (debug & DEBUG_HW) + pr_notice("%s D_EXIR=%02x\n", card->name, val); + val = ReadW6692(card, W_D_EXIM); + if (debug & DEBUG_HW) + pr_notice("%s D_EXIM=%02x\n", card->name, val); + val = ReadW6692(card, W_D_RSTA); + if (debug & DEBUG_HW) + pr_notice("%s D_RSTA=%02x\n", card->name, val); + return 0; +} + +static void +release_card(struct w6692_hw *card) +{ + u_long flags; + + spin_lock_irqsave(&card->lock, flags); + disable_hwirq(card); + w6692_mode(&card->bc[0], ISDN_P_NONE); + w6692_mode(&card->bc[1], ISDN_P_NONE); + if ((card->fmask & led) || card->subtype == W6692_USR) { + card->xdata |= 0x04; /* LED OFF */ + WriteW6692(card, W_XDATA, card->xdata); + } + spin_unlock_irqrestore(&card->lock, flags); + free_irq(card->irq, card); + l1_event(card->dch.l1, CLOSE_CHANNEL); + mISDN_unregister_device(&card->dch.dev); + release_region(card->addr, 256); + mISDN_freebchannel(&card->bc[1].bch); + mISDN_freebchannel(&card->bc[0].bch); + mISDN_freedchannel(&card->dch); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + pci_disable_device(card->pdev); + pci_set_drvdata(card->pdev, NULL); + kfree(card); +} + +static int +setup_instance(struct w6692_hw *card) +{ + int i, err; + u_long flags; + + snprintf(card->name, MISDN_MAX_IDLEN - 1, "w6692.%d", w6692_cnt + 1); + write_lock_irqsave(&card_lock, flags); + list_add_tail(&card->list, &Cards); + write_unlock_irqrestore(&card_lock, flags); + card->fmask = (1 << w6692_cnt); + _set_debug(card); + spin_lock_init(&card->lock); + mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, W6692_ph_bh); + card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0); + card->dch.dev.D.send = w6692_l2l1D; + card->dch.dev.D.ctrl = w6692_dctrl; + card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + card->dch.hw = card; + card->dch.dev.nrbchan = 2; + for (i = 0; i < 2; i++) { + mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM); + card->bc[i].bch.hw = card; + card->bc[i].bch.nr = i + 1; + card->bc[i].bch.ch.nr = i + 1; + card->bc[i].bch.ch.send = w6692_l2l1B; + card->bc[i].bch.ch.ctrl = w6692_bctrl; + set_channelmap(i + 1, card->dch.dev.channelmap); + list_add(&card->bc[i].bch.ch.list, &card->dch.dev.bchannels); + } + err = setup_w6692(card); + if (err) + goto error_setup; + err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, + card->name); + if (err) + goto error_reg; + err = init_card(card); + if (err) + goto error_init; + err = create_l1(&card->dch, w6692_l1callback); + if (!err) { + w6692_cnt++; + pr_notice("W6692 %d cards installed\n", w6692_cnt); + return 0; + } + + free_irq(card->irq, card); +error_init: + mISDN_unregister_device(&card->dch.dev); +error_reg: + release_region(card->addr, 256); +error_setup: + mISDN_freebchannel(&card->bc[1].bch); + mISDN_freebchannel(&card->bc[0].bch); + mISDN_freedchannel(&card->dch); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + kfree(card); + return err; +} + +static int __devinit +w6692_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = -ENOMEM; + struct w6692_hw *card; + struct w6692map *m = (struct w6692map *)ent->driver_data; + + card = kzalloc(sizeof(struct w6692_hw), GFP_KERNEL); + if (!card) { + pr_info("No kmem for w6692 card\n"); + return err; + } + card->pdev = pdev; + card->subtype = m->subtype; + err = pci_enable_device(pdev); + if (err) { + kfree(card); + return err; + } + + printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n", + m->name, pci_name(pdev)); + + card->addr = pci_resource_start(pdev, 1); + card->irq = pdev->irq; + pci_set_drvdata(pdev, card); + err = setup_instance(card); + if (err) + pci_set_drvdata(pdev, NULL); + return err; +} + +static void __devexit +w6692_remove_pci(struct pci_dev *pdev) +{ + struct w6692_hw *card = pci_get_drvdata(pdev); + + if (card) + release_card(card); + else + if (debug) + pr_notice("%s: drvdata allready removed\n", __func__); +} + +static struct pci_device_id w6692_ids[] = { + { PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[0]}, + { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, + PCI_VENDOR_ID_USR, PCI_DEVICE_ID_USR_6692, 0, 0, + (ulong)&w6692_map[2]}, + { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[1]}, + { } +}; +MODULE_DEVICE_TABLE(pci, w6692_ids); + +static struct pci_driver w6692_driver = { + .name = "w6692", + .probe = w6692_probe, + .remove = __devexit_p(w6692_remove_pci), + .id_table = w6692_ids, +}; + +static int __init w6692_init(void) +{ + int err; + + pr_notice("Winbond W6692 PCI driver Rev. %s\n", W6692_REV); + + err = pci_register_driver(&w6692_driver); + return err; +} + +static void __exit w6692_cleanup(void) +{ + pci_unregister_driver(&w6692_driver); +} + +module_init(w6692_init); +module_exit(w6692_cleanup); diff --git a/drivers/isdn/hardware/mISDN/w6692.h b/drivers/isdn/hardware/mISDN/w6692.h new file mode 100644 index 0000000..f956977 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/w6692.h @@ -0,0 +1,190 @@ +/* + * Winbond W6692 specific defines + * + * Author Karsten Keil + * based on the w6692 I4L driver from Petr Novak + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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. + * + */ + +/* Specifications of W6692 registers */ + +#define W_D_RFIFO 0x00 /* R */ +#define W_D_XFIFO 0x04 /* W */ +#define W_D_CMDR 0x08 /* W */ +#define W_D_MODE 0x0c /* R/W */ +#define W_D_TIMR 0x10 /* R/W */ +#define W_ISTA 0x14 /* R_clr */ +#define W_IMASK 0x18 /* R/W */ +#define W_D_EXIR 0x1c /* R_clr */ +#define W_D_EXIM 0x20 /* R/W */ +#define W_D_STAR 0x24 /* R */ +#define W_D_RSTA 0x28 /* R */ +#define W_D_SAM 0x2c /* R/W */ +#define W_D_SAP1 0x30 /* R/W */ +#define W_D_SAP2 0x34 /* R/W */ +#define W_D_TAM 0x38 /* R/W */ +#define W_D_TEI1 0x3c /* R/W */ +#define W_D_TEI2 0x40 /* R/W */ +#define W_D_RBCH 0x44 /* R */ +#define W_D_RBCL 0x48 /* R */ +#define W_TIMR2 0x4c /* W */ +#define W_L1_RC 0x50 /* R/W */ +#define W_D_CTL 0x54 /* R/W */ +#define W_CIR 0x58 /* R */ +#define W_CIX 0x5c /* W */ +#define W_SQR 0x60 /* R */ +#define W_SQX 0x64 /* W */ +#define W_PCTL 0x68 /* R/W */ +#define W_MOR 0x6c /* R */ +#define W_MOX 0x70 /* R/W */ +#define W_MOSR 0x74 /* R_clr */ +#define W_MOCR 0x78 /* R/W */ +#define W_GCR 0x7c /* R/W */ + +#define W_B_RFIFO 0x80 /* R */ +#define W_B_XFIFO 0x84 /* W */ +#define W_B_CMDR 0x88 /* W */ +#define W_B_MODE 0x8c /* R/W */ +#define W_B_EXIR 0x90 /* R_clr */ +#define W_B_EXIM 0x94 /* R/W */ +#define W_B_STAR 0x98 /* R */ +#define W_B_ADM1 0x9c /* R/W */ +#define W_B_ADM2 0xa0 /* R/W */ +#define W_B_ADR1 0xa4 /* R/W */ +#define W_B_ADR2 0xa8 /* R/W */ +#define W_B_RBCL 0xac /* R */ +#define W_B_RBCH 0xb0 /* R */ + +#define W_XADDR 0xf4 /* R/W */ +#define W_XDATA 0xf8 /* R/W */ +#define W_EPCTL 0xfc /* W */ + +/* W6692 register bits */ + +#define W_D_CMDR_XRST 0x01 +#define W_D_CMDR_XME 0x02 +#define W_D_CMDR_XMS 0x08 +#define W_D_CMDR_STT 0x10 +#define W_D_CMDR_RRST 0x40 +#define W_D_CMDR_RACK 0x80 + +#define W_D_MODE_RLP 0x01 +#define W_D_MODE_DLP 0x02 +#define W_D_MODE_MFD 0x04 +#define W_D_MODE_TEE 0x08 +#define W_D_MODE_TMS 0x10 +#define W_D_MODE_RACT 0x40 +#define W_D_MODE_MMS 0x80 + +#define W_INT_B2_EXI 0x01 +#define W_INT_B1_EXI 0x02 +#define W_INT_D_EXI 0x04 +#define W_INT_XINT0 0x08 +#define W_INT_XINT1 0x10 +#define W_INT_D_XFR 0x20 +#define W_INT_D_RME 0x40 +#define W_INT_D_RMR 0x80 + +#define W_D_EXI_WEXP 0x01 +#define W_D_EXI_TEXP 0x02 +#define W_D_EXI_ISC 0x04 +#define W_D_EXI_MOC 0x08 +#define W_D_EXI_TIN2 0x10 +#define W_D_EXI_XCOL 0x20 +#define W_D_EXI_XDUN 0x40 +#define W_D_EXI_RDOV 0x80 + +#define W_D_STAR_DRDY 0x10 +#define W_D_STAR_XBZ 0x20 +#define W_D_STAR_XDOW 0x80 + +#define W_D_RSTA_RMB 0x10 +#define W_D_RSTA_CRCE 0x20 +#define W_D_RSTA_RDOV 0x40 + +#define W_D_CTL_SRST 0x20 + +#define W_CIR_SCC 0x80 +#define W_CIR_ICC 0x40 +#define W_CIR_COD_MASK 0x0f + +#define W_PCTL_PCX 0x01 +#define W_PCTL_XMODE 0x02 +#define W_PCTL_OE0 0x04 +#define W_PCTL_OE1 0x08 +#define W_PCTL_OE2 0x10 +#define W_PCTL_OE3 0x20 +#define W_PCTL_OE4 0x40 +#define W_PCTL_OE5 0x80 + +#define W_B_CMDR_XRST 0x01 +#define W_B_CMDR_XME 0x02 +#define W_B_CMDR_XMS 0x04 +#define W_B_CMDR_RACT 0x20 +#define W_B_CMDR_RRST 0x40 +#define W_B_CMDR_RACK 0x80 + +#define W_B_MODE_FTS0 0x01 +#define W_B_MODE_FTS1 0x02 +#define W_B_MODE_SW56 0x04 +#define W_B_MODE_BSW0 0x08 +#define W_B_MODE_BSW1 0x10 +#define W_B_MODE_EPCM 0x20 +#define W_B_MODE_ITF 0x40 +#define W_B_MODE_MMS 0x80 + +#define W_B_EXI_XDUN 0x01 +#define W_B_EXI_XFR 0x02 +#define W_B_EXI_RDOV 0x10 +#define W_B_EXI_RME 0x20 +#define W_B_EXI_RMR 0x40 + +#define W_B_STAR_XBZ 0x01 +#define W_B_STAR_XDOW 0x04 +#define W_B_STAR_RMB 0x10 +#define W_B_STAR_CRCE 0x20 +#define W_B_STAR_RDOV 0x40 + +#define W_B_RBCH_LOV 0x20 + +/* W6692 Layer1 commands */ + +#define W_L1CMD_ECK 0x00 +#define W_L1CMD_RST 0x01 +#define W_L1CMD_SCP 0x04 +#define W_L1CMD_SSP 0x02 +#define W_L1CMD_AR8 0x08 +#define W_L1CMD_AR10 0x09 +#define W_L1CMD_EAL 0x0a +#define W_L1CMD_DRC 0x0f + +/* W6692 Layer1 indications */ + +#define W_L1IND_CE 0x07 +#define W_L1IND_DRD 0x00 +#define W_L1IND_LD 0x04 +#define W_L1IND_ARD 0x08 +#define W_L1IND_TI 0x0a +#define W_L1IND_ATI 0x0b +#define W_L1IND_AI8 0x0c +#define W_L1IND_AI10 0x0d +#define W_L1IND_CD 0x0f + +/* FIFO thresholds */ +#define W_D_FIFO_THRESH 64 +#define W_B_FIFO_THRESH 64 -- cgit v0.10.2 From a900845e56617edc005fd8f35bfd5a407aaf96c8 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Thu, 23 Jul 2009 10:03:05 +0200 Subject: mISDN: Add support for Traverse Technologies NETJet PCI cards Add support for cards based on the Tiger 300 and Tiger 320 ISDN PCI chip. Currently only the ISAC ISDN line interface is supported. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index d72586e..bde55d7 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -72,6 +72,15 @@ config MISDN_W6692 help Enable support for Winbond 6692 PCI chip based cards. +config MISDN_NETJET + tristate "Support for NETJet cards" + depends on MISDN + depends on PCI + select MISDN_IPAC + select ISDN_HDLC + help + Enable support for Traverse Technologies NETJet PCI cards. + config MISDN_IPAC tristate diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 61dd5a5..2987d99 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o obj-$(CONFIG_MISDN_W6692) += w6692.o +obj-$(CONFIG_MISDN_NETJET) += netjet.o # chip modules obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c new file mode 100644 index 0000000..6c1b164 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -0,0 +1,1156 @@ +/* + * NETJet mISDN driver + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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 "ipac.h" +#include "iohelper.h" +#include "netjet.h" +#include + +#define NETJET_REV "2.0" + +enum nj_types { + NETJET_S_TJ300, + NETJET_S_TJ320, + ENTERNOW__TJ320, +}; + +struct tiger_dma { + size_t size; + u32 *start; + int idx; + u32 dmastart; + u32 dmairq; + u32 dmaend; + u32 dmacur; +}; + +struct tiger_hw; + +struct tiger_ch { + struct bchannel bch; + struct tiger_hw *nj; + int idx; + int free; + int lastrx; + u16 rxstate; + u16 txstate; + struct isdnhdlc_vars hsend; + struct isdnhdlc_vars hrecv; + u8 *hsbuf; + u8 *hrbuf; +}; + +#define TX_INIT 0x0001 +#define TX_IDLE 0x0002 +#define TX_RUN 0x0004 +#define TX_UNDERRUN 0x0100 +#define RX_OVERRUN 0x0100 + +#define LOG_SIZE 64 + +struct tiger_hw { + struct list_head list; + struct pci_dev *pdev; + char name[MISDN_MAX_IDLEN]; + enum nj_types typ; + int irq; + u32 irqcnt; + u32 base; + size_t base_s; + dma_addr_t dma; + void *dma_p; + spinlock_t lock; /* lock HW */ + struct isac_hw isac; + struct tiger_dma send; + struct tiger_dma recv; + struct tiger_ch bc[2]; + u8 ctrlreg; + u8 dmactrl; + u8 auxd; + u8 last_is0; + u8 irqmask0; + char log[LOG_SIZE]; +}; + +static LIST_HEAD(Cards); +static DEFINE_RWLOCK(card_lock); /* protect Cards */ +static u32 debug; +static int nj_cnt; + +static void +_set_debug(struct tiger_hw *card) +{ + card->isac.dch.debug = debug; + card->bc[0].bch.debug = debug; + card->bc[1].bch.debug = debug; +} + +static int +set_debug(const char *val, struct kernel_param *kp) +{ + int ret; + struct tiger_hw *card; + + ret = param_set_uint(val, kp); + if (!ret) { + read_lock(&card_lock); + list_for_each_entry(card, &Cards, list) + _set_debug(card); + read_unlock(&card_lock); + } + return ret; +} + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(NETJET_REV); +module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Netjet debug mask"); + +static void +nj_disable_hwirq(struct tiger_hw *card) +{ + outb(0, card->base + NJ_IRQMASK0); + outb(0, card->base + NJ_IRQMASK1); +} + + +static u8 +ReadISAC_nj(void *p, u8 offset) +{ + struct tiger_hw *card = p; + u8 ret; + + card->auxd &= 0xfc; + card->auxd |= (offset >> 4) & 3; + outb(card->auxd, card->base + NJ_AUXDATA); + ret = inb(card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2)); + return ret; +} + +static void +WriteISAC_nj(void *p, u8 offset, u8 value) +{ + struct tiger_hw *card = p; + + card->auxd &= 0xfc; + card->auxd |= (offset >> 4) & 3; + outb(card->auxd, card->base + NJ_AUXDATA); + outb(value, card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2)); +} + +static void +ReadFiFoISAC_nj(void *p, u8 offset, u8 *data, int size) +{ + struct tiger_hw *card = p; + + card->auxd &= 0xfc; + outb(card->auxd, card->base + NJ_AUXDATA); + insb(card->base + NJ_ISAC_OFF, data, size); +} + +static void +WriteFiFoISAC_nj(void *p, u8 offset, u8 *data, int size) +{ + struct tiger_hw *card = p; + + card->auxd &= 0xfc; + outb(card->auxd, card->base + NJ_AUXDATA); + outsb(card->base + NJ_ISAC_OFF, data, size); +} + +static void +fill_mem(struct tiger_ch *bc, u32 idx, u32 cnt, u32 fill) +{ + struct tiger_hw *card = bc->bch.hw; + u32 mask = 0xff, val; + + pr_debug("%s: B%1d fill %02x len %d idx %d/%d\n", card->name, + bc->bch.nr, fill, cnt, idx, card->send.idx); + if (bc->bch.nr & 2) { + fill <<= 8; + mask <<= 8; + } + mask ^= 0xffffffff; + while (cnt--) { + val = card->send.start[idx]; + val &= mask; + val |= fill; + card->send.start[idx++] = val; + if (idx >= card->send.size) + idx = 0; + } +} + +static int +mode_tiger(struct tiger_ch *bc, u32 protocol) +{ + struct tiger_hw *card = bc->bch.hw; + + pr_debug("%s: B%1d protocol %x-->%x\n", card->name, + bc->bch.nr, bc->bch.state, protocol); + switch (protocol) { + case ISDN_P_NONE: + if (bc->bch.state == ISDN_P_NONE) + break; + fill_mem(bc, 0, card->send.size, 0xff); + bc->bch.state = protocol; + /* only stop dma and interrupts if both channels NULL */ + if ((card->bc[0].bch.state == ISDN_P_NONE) && + (card->bc[1].bch.state == ISDN_P_NONE)) { + card->dmactrl = 0; + outb(card->dmactrl, card->base + NJ_DMACTRL); + outb(0, card->base + NJ_IRQMASK0); + } + test_and_clear_bit(FLG_HDLC, &bc->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &bc->bch.Flags); + bc->txstate = 0; + bc->rxstate = 0; + bc->lastrx = -1; + break; + case ISDN_P_B_RAW: + test_and_set_bit(FLG_TRANSPARENT, &bc->bch.Flags); + bc->bch.state = protocol; + bc->idx = 0; + bc->free = card->send.size/2; + bc->rxstate = 0; + bc->txstate = TX_INIT | TX_IDLE; + bc->lastrx = -1; + if (!card->dmactrl) { + card->dmactrl = 1; + outb(card->dmactrl, card->base + NJ_DMACTRL); + outb(0x0f, card->base + NJ_IRQMASK0); + } + break; + case ISDN_P_B_HDLC: + test_and_set_bit(FLG_HDLC, &bc->bch.Flags); + bc->bch.state = protocol; + bc->idx = 0; + bc->free = card->send.size/2; + bc->rxstate = 0; + bc->txstate = TX_INIT | TX_IDLE; + isdnhdlc_rcv_init(&bc->hrecv, 0); + isdnhdlc_out_init(&bc->hsend, 0); + bc->lastrx = -1; + if (!card->dmactrl) { + card->dmactrl = 1; + outb(card->dmactrl, card->base + NJ_DMACTRL); + outb(0x0f, card->base + NJ_IRQMASK0); + } + break; + default: + pr_info("%s: %s protocol %x not handled\n", card->name, + __func__, protocol); + return -ENOPROTOOPT; + } + card->send.dmacur = inl(card->base + NJ_DMA_READ_ADR); + card->recv.dmacur = inl(card->base + NJ_DMA_WRITE_ADR); + card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; + card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2; + pr_debug("%s: %s ctrl %x irq %02x/%02x idx %d/%d\n", + card->name, __func__, + inb(card->base + NJ_DMACTRL), + inb(card->base + NJ_IRQMASK0), + inb(card->base + NJ_IRQSTAT0), + card->send.idx, + card->recv.idx); + return 0; +} + +static void +nj_reset(struct tiger_hw *card) +{ + outb(0xff, card->base + NJ_CTRL); /* Reset On */ + mdelay(1); + + /* now edge triggered for TJ320 GE 13/07/00 */ + /* see comment in IRQ function */ + if (card->typ == NETJET_S_TJ320) /* TJ320 */ + card->ctrlreg = 0x40; /* Reset Off and status read clear */ + else + card->ctrlreg = 0x00; /* Reset Off and status read clear */ + outb(card->ctrlreg, card->base + NJ_CTRL); + mdelay(10); + + /* configure AUX pins (all output except ISAC IRQ pin) */ + card->auxd = 0; + card->dmactrl = 0; + outb(~NJ_ISACIRQ, card->base + NJ_AUXCTRL); + outb(NJ_ISACIRQ, card->base + NJ_IRQMASK1); + outb(card->auxd, card->base + NJ_AUXDATA); +} + +static int +inittiger(struct tiger_hw *card) +{ + int i; + + card->dma_p = pci_alloc_consistent(card->pdev, NJ_DMA_SIZE, + &card->dma); + if (!card->dma_p) { + pr_info("%s: No DMA memory\n", card->name); + return -ENOMEM; + } + if ((u64)card->dma > 0xffffffff) { + pr_info("%s: DMA outside 32 bit\n", card->name); + return -ENOMEM; + } + for (i = 0; i < 2; i++) { + card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_KERNEL); + if (!card->bc[i].hsbuf) { + pr_info("%s: no B%d send buffer\n", card->name, i + 1); + return -ENOMEM; + } + card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_KERNEL); + if (!card->bc[i].hrbuf) { + pr_info("%s: no B%d recv buffer\n", card->name, i + 1); + return -ENOMEM; + } + } + memset(card->dma_p, 0xff, NJ_DMA_SIZE); + + card->send.start = card->dma_p; + card->send.dmastart = (u32)card->dma; + card->send.dmaend = card->send.dmastart + + (4 * (NJ_DMA_TXSIZE - 1)); + card->send.dmairq = card->send.dmastart + + (4 * ((NJ_DMA_TXSIZE / 2) - 1)); + card->send.size = NJ_DMA_TXSIZE; + + if (debug & DEBUG_HW) + pr_notice("%s: send buffer phy %#x - %#x - %#x virt %p" + " size %zu u32\n", card->name, + card->send.dmastart, card->send.dmairq, + card->send.dmaend, card->send.start, card->send.size); + + outl(card->send.dmastart, card->base + NJ_DMA_READ_START); + outl(card->send.dmairq, card->base + NJ_DMA_READ_IRQ); + outl(card->send.dmaend, card->base + NJ_DMA_READ_END); + + card->recv.start = card->dma_p + (NJ_DMA_SIZE / 2); + card->recv.dmastart = (u32)card->dma + (NJ_DMA_SIZE / 2); + card->recv.dmaend = card->recv.dmastart + + (4 * (NJ_DMA_RXSIZE - 1)); + card->recv.dmairq = card->recv.dmastart + + (4 * ((NJ_DMA_RXSIZE / 2) - 1)); + card->recv.size = NJ_DMA_RXSIZE; + + if (debug & DEBUG_HW) + pr_notice("%s: recv buffer phy %#x - %#x - %#x virt %p" + " size %zu u32\n", card->name, + card->recv.dmastart, card->recv.dmairq, + card->recv.dmaend, card->recv.start, card->recv.size); + + outl(card->recv.dmastart, card->base + NJ_DMA_WRITE_START); + outl(card->recv.dmairq, card->base + NJ_DMA_WRITE_IRQ); + outl(card->recv.dmaend, card->base + NJ_DMA_WRITE_END); + return 0; +} + +static void +read_dma(struct tiger_ch *bc, u32 idx, int cnt) +{ + struct tiger_hw *card = bc->bch.hw; + int i, stat; + u32 val; + u8 *p, *pn; + + if (bc->lastrx == idx) { + bc->rxstate |= RX_OVERRUN; + pr_info("%s: B%1d overrun at idx %d\n", card->name, + bc->bch.nr, idx); + } + bc->lastrx = idx; + if (!bc->bch.rx_skb) { + bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC); + if (!bc->bch.rx_skb) { + pr_info("%s: B%1d receive out of memory\n", + card->name, bc->bch.nr); + return; + } + } + + if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) { + if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) { + pr_debug("%s: B%1d overrun %d\n", card->name, + bc->bch.nr, bc->bch.rx_skb->len + cnt); + skb_trim(bc->bch.rx_skb, 0); + return; + } + p = skb_put(bc->bch.rx_skb, cnt); + } else + p = bc->hrbuf; + + for (i = 0; i < cnt; i++) { + val = card->recv.start[idx++]; + if (bc->bch.nr & 2) + val >>= 8; + if (idx >= card->recv.size) + idx = 0; + p[i] = val & 0xff; + } + pn = bc->hrbuf; +next_frame: + if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i, + bc->bch.rx_skb->data, bc->bch.maxlen); + if (stat > 0) /* valid frame received */ + p = skb_put(bc->bch.rx_skb, stat); + else if (stat == -HDLC_CRC_ERROR) + pr_info("%s: B%1d receive frame CRC error\n", + card->name, bc->bch.nr); + else if (stat == -HDLC_FRAMING_ERROR) + pr_info("%s: B%1d receive framing error\n", + card->name, bc->bch.nr); + else if (stat == -HDLC_LENGTH_ERROR) + pr_info("%s: B%1d receive frame too long (> %d)\n", + card->name, bc->bch.nr, bc->bch.maxlen); + } else + stat = cnt; + + if (stat > 0) { + if (debug & DEBUG_HW_BFIFO) { + snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ", + bc->bch.nr, card->name, stat); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, + p, stat); + } + recv_Bchannel(&bc->bch, 0); + } + if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + pn += i; + cnt -= i; + if (!bc->bch.rx_skb) { + bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, + GFP_ATOMIC); + if (!bc->bch.rx_skb) { + pr_info("%s: B%1d receive out of memory\n", + card->name, bc->bch.nr); + return; + } + } + if (cnt > 0) + goto next_frame; + } +} + +static void +recv_tiger(struct tiger_hw *card, u8 irq_stat) +{ + u32 idx; + int cnt = card->recv.size / 2; + + /* Note receive is via the WRITE DMA channel */ + card->last_is0 &= ~NJ_IRQM0_WR_MASK; + card->last_is0 |= (irq_stat & NJ_IRQM0_WR_MASK); + + if (irq_stat & NJ_IRQM0_WR_END) + idx = cnt - 1; + else + idx = card->recv.size - 1; + + if (test_bit(FLG_ACTIVE, &card->bc[0].bch.Flags)) + read_dma(&card->bc[0], idx, cnt); + if (test_bit(FLG_ACTIVE, &card->bc[1].bch.Flags)) + read_dma(&card->bc[1], idx, cnt); +} + +/* sync with current DMA address at start or after exception */ +static void +resync(struct tiger_ch *bc, struct tiger_hw *card) +{ + card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR); + card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; + if (bc->free > card->send.size / 2) + bc->free = card->send.size / 2; + /* currently we simple sync to the next complete free area + * this hast the advantage that we have always maximum time to + * handle TX irq + */ + if (card->send.idx < ((card->send.size / 2) - 1)) + bc->idx = (card->recv.size / 2) - 1; + else + bc->idx = card->recv.size - 1; + bc->txstate = TX_RUN; + pr_debug("%s: %s B%1d free %d idx %d/%d\n", card->name, + __func__, bc->bch.nr, bc->free, bc->idx, card->send.idx); +} + +static int bc_next_frame(struct tiger_ch *); + +static void +fill_hdlc_flag(struct tiger_ch *bc) +{ + struct tiger_hw *card = bc->bch.hw; + int count, i; + u32 m, v; + u8 *p; + + if (bc->free == 0) + return; + pr_debug("%s: %s B%1d %d state %x idx %d/%d\n", card->name, + __func__, bc->bch.nr, bc->free, bc->txstate, + bc->idx, card->send.idx); + if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN)) + resync(bc, card); + count = isdnhdlc_encode(&bc->hsend, NULL, 0, &i, + bc->hsbuf, bc->free); + pr_debug("%s: B%1d hdlc encoded %d flags\n", card->name, + bc->bch.nr, count); + bc->free -= count; + p = bc->hsbuf; + m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff; + for (i = 0; i < count; i++) { + if (bc->idx >= card->send.size) + bc->idx = 0; + v = card->send.start[bc->idx]; + v &= m; + v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8; + card->send.start[bc->idx++] = v; + } + if (debug & DEBUG_HW_BFIFO) { + snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ", + bc->bch.nr, card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count); + } +} + +static void +fill_dma(struct tiger_ch *bc) +{ + struct tiger_hw *card = bc->bch.hw; + int count, i; + u32 m, v; + u8 *p; + + if (bc->free == 0) + return; + count = bc->bch.tx_skb->len - bc->bch.tx_idx; + if (count <= 0) + return; + pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", card->name, + __func__, bc->bch.nr, count, bc->free, bc->bch.tx_idx, + bc->bch.tx_skb->len, bc->txstate, bc->idx, card->send.idx); + if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN)) + resync(bc, card); + p = bc->bch.tx_skb->data + bc->bch.tx_idx; + if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + count = isdnhdlc_encode(&bc->hsend, p, count, &i, + bc->hsbuf, bc->free); + pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name, + bc->bch.nr, i, count); + bc->bch.tx_idx += i; + bc->free -= count; + p = bc->hsbuf; + } else { + if (count > bc->free) + count = bc->free; + bc->bch.tx_idx += count; + bc->free -= count; + } + m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff; + for (i = 0; i < count; i++) { + if (bc->idx >= card->send.size) + bc->idx = 0; + v = card->send.start[bc->idx]; + v &= m; + v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8; + card->send.start[bc->idx++] = v; + } + if (debug & DEBUG_HW_BFIFO) { + snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ", + bc->bch.nr, card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count); + } + if (bc->free) + bc_next_frame(bc); +} + + +static int +bc_next_frame(struct tiger_ch *bc) +{ + if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len) + fill_dma(bc); + else { + if (bc->bch.tx_skb) { + /* send confirm, on trans, free on hdlc. */ + if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) + confirm_Bsend(&bc->bch); + dev_kfree_skb(bc->bch.tx_skb); + } + if (get_next_bframe(&bc->bch)) + fill_dma(bc); + else + return 0; + } + return 1; +} + +static void +send_tiger_bc(struct tiger_hw *card, struct tiger_ch *bc) +{ + int ret; + + bc->free += card->send.size / 2; + if (bc->free >= card->send.size) { + if (!(bc->txstate & (TX_UNDERRUN | TX_INIT))) { + pr_info("%s: B%1d TX underrun state %x\n", card->name, + bc->bch.nr, bc->txstate); + bc->txstate |= TX_UNDERRUN; + } + bc->free = card->send.size; + } + ret = bc_next_frame(bc); + if (!ret) { + if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + fill_hdlc_flag(bc); + return; + } + pr_debug("%s: B%1d TX no data free %d idx %d/%d\n", card->name, + bc->bch.nr, bc->free, bc->idx, card->send.idx); + if (!(bc->txstate & (TX_IDLE | TX_INIT))) { + fill_mem(bc, bc->idx, bc->free, 0xff); + if (bc->free == card->send.size) + bc->txstate |= TX_IDLE; + } + } +} + +static void +send_tiger(struct tiger_hw *card, u8 irq_stat) +{ + int i; + + /* Note send is via the READ DMA channel */ + if ((irq_stat & card->last_is0) & NJ_IRQM0_RD_MASK) { + pr_info("%s: tiger warn write double dma %x/%x\n", + card->name, irq_stat, card->last_is0); + return; + } else { + card->last_is0 &= ~NJ_IRQM0_RD_MASK; + card->last_is0 |= (irq_stat & NJ_IRQM0_RD_MASK); + } + for (i = 0; i < 2; i++) { + if (test_bit(FLG_ACTIVE, &card->bc[i].bch.Flags)) + send_tiger_bc(card, &card->bc[i]); + } +} + +static irqreturn_t +nj_irq(int intno, void *dev_id) +{ + struct tiger_hw *card = dev_id; + u8 val, s1val, s0val; + + spin_lock(&card->lock); + s0val = inb(card->base | NJ_IRQSTAT0); + s1val = inb(card->base | NJ_IRQSTAT1); + if ((s1val & NJ_ISACIRQ) && (s0val == 0)) { + /* shared IRQ */ + spin_unlock(&card->lock); + return IRQ_NONE; + } + pr_debug("%s: IRQSTAT0 %02x IRQSTAT1 %02x\n", card->name, s0val, s1val); + card->irqcnt++; + if (!(s1val & NJ_ISACIRQ)) { + val = ReadISAC_nj(card, ISAC_ISTA); + if (val) + mISDNisac_irq(&card->isac, val); + } + + if (s0val) + /* write to clear */ + outb(s0val, card->base | NJ_IRQSTAT0); + else + goto end; + s1val = s0val; + /* set bits in sval to indicate which page is free */ + card->recv.dmacur = inl(card->base | NJ_DMA_WRITE_ADR); + card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2; + if (card->recv.dmacur < card->recv.dmairq) + s0val = 0x08; /* the 2nd write area is free */ + else + s0val = 0x04; /* the 1st write area is free */ + + card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR); + card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; + if (card->send.dmacur < card->send.dmairq) + s0val |= 0x02; /* the 2nd read area is free */ + else + s0val |= 0x01; /* the 1st read area is free */ + + pr_debug("%s: DMA Status %02x/%02x/%02x %d/%d\n", card->name, + s1val, s0val, card->last_is0, + card->recv.idx, card->send.idx); + /* test if we have a DMA interrupt */ + if (s0val != card->last_is0) { + if ((s0val & NJ_IRQM0_RD_MASK) != + (card->last_is0 & NJ_IRQM0_RD_MASK)) + /* got a write dma int */ + send_tiger(card, s0val); + if ((s0val & NJ_IRQM0_WR_MASK) != + (card->last_is0 & NJ_IRQM0_WR_MASK)) + /* got a read dma int */ + recv_tiger(card, s0val); + } +end: + spin_unlock(&card->lock); + return IRQ_HANDLED; +} + +static int +nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) +{ + int ret = -EINVAL; + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch); + struct tiger_hw *card = bch->hw; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(&card->lock, flags); + ret = bchannel_senddata(bch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + fill_dma(bc); + ret = 0; + spin_unlock_irqrestore(&card->lock, flags); + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(&card->lock, flags); + return ret; + case PH_ACTIVATE_REQ: + spin_lock_irqsave(&card->lock, flags); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) + ret = mode_tiger(bc, ch->protocol); + else + ret = 0; + spin_unlock_irqrestore(&card->lock, flags); + if (!ret) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + break; + case PH_DEACTIVATE_REQ: + spin_lock_irqsave(&card->lock, flags); + mISDN_clear_bchannel(bch); + mode_tiger(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); + _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + ret = 0; + break; + } + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +channel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + struct tiger_hw *card = bc->bch.hw; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + /* Nothing implemented yet */ + case MISDN_CTRL_FILL_EMPTY: + default: + pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch); + struct tiger_hw *card = bch->hw; + int ret = -EINVAL; + u_long flags; + + pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); + switch (cmd) { + case CLOSE_CHANNEL: + test_and_clear_bit(FLG_OPEN, &bch->Flags); + if (test_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(&card->lock, flags); + mISDN_freebchannel(bch); + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); + test_and_clear_bit(FLG_ACTIVE, &bch->Flags); + mode_tiger(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); + } + ch->protocol = ISDN_P_NONE; + ch->peer = NULL; + module_put(THIS_MODULE); + ret = 0; + break; + case CONTROL_CHANNEL: + ret = channel_bctrl(bc, arg); + break; + default: + pr_info("%s: %s unknown prim(%x)\n", card->name, __func__, cmd); + } + return ret; +} + +static int +channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_LOOP; + break; + case MISDN_CTRL_LOOP: + /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ + if (cq->channel < 0 || cq->channel > 3) { + ret = -EINVAL; + break; + } + ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel); + break; + default: + pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +open_bchannel(struct tiger_hw *card, struct channel_req *rq) +{ + struct bchannel *bch; + + if (rq->adr.channel > 2) + return -EINVAL; + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + bch = &card->bc[rq->adr.channel - 1].bch; + if (test_and_set_bit(FLG_OPEN, &bch->Flags)) + return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + bch->ch.protocol = rq->protocol; + rq->ch = &bch->ch; + return 0; +} + +/* + * device control function + */ +static int +nj_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct tiger_hw *card = dch->hw; + struct channel_req *rq; + int err = 0; + + pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); + switch (cmd) { + case OPEN_CHANNEL: + rq = arg; + if (rq->protocol == ISDN_P_TE_S0) + err = card->isac.open(&card->isac, rq); + else + err = open_bchannel(card, rq); + if (err) + break; + if (!try_module_get(THIS_MODULE)) + pr_info("%s: cannot get module\n", card->name); + break; + case CLOSE_CHANNEL: + pr_debug("%s: dev(%d) close from %p\n", card->name, dch->dev.id, + __builtin_return_address(0)); + module_put(THIS_MODULE); + break; + case CONTROL_CHANNEL: + err = channel_ctrl(card, arg); + break; + default: + pr_debug("%s: %s unknown command %x\n", + card->name, __func__, cmd); + return -EINVAL; + } + return err; +} + +static int +nj_init_card(struct tiger_hw *card) +{ + u_long flags; + int ret; + + spin_lock_irqsave(&card->lock, flags); + nj_disable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); + + card->irq = card->pdev->irq; + if (request_irq(card->irq, nj_irq, IRQF_SHARED, card->name, card)) { + pr_info("%s: couldn't get interrupt %d\n", + card->name, card->irq); + card->irq = -1; + return -EIO; + } + + spin_lock_irqsave(&card->lock, flags); + nj_reset(card); + ret = card->isac.init(&card->isac); + if (ret) + goto error; + ret = inittiger(card); + if (ret) + goto error; + mode_tiger(&card->bc[0], ISDN_P_NONE); + mode_tiger(&card->bc[1], ISDN_P_NONE); +error: + spin_unlock_irqrestore(&card->lock, flags); + return ret; +} + + +static void +nj_release(struct tiger_hw *card) +{ + u_long flags; + int i; + + if (card->base_s) { + spin_lock_irqsave(&card->lock, flags); + nj_disable_hwirq(card); + mode_tiger(&card->bc[0], ISDN_P_NONE); + mode_tiger(&card->bc[1], ISDN_P_NONE); + card->isac.release(&card->isac); + spin_unlock_irqrestore(&card->lock, flags); + release_region(card->base, card->base_s); + card->base_s = 0; + } + if (card->irq > 0) + free_irq(card->irq, card); + if (card->isac.dch.dev.dev.class) + mISDN_unregister_device(&card->isac.dch.dev); + + for (i = 0; i < 2; i++) { + mISDN_freebchannel(&card->bc[i].bch); + kfree(card->bc[i].hsbuf); + kfree(card->bc[i].hrbuf); + } + if (card->dma_p) + pci_free_consistent(card->pdev, NJ_DMA_SIZE, + card->dma_p, card->dma); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + pci_clear_master(card->pdev); + pci_disable_device(card->pdev); + pci_set_drvdata(card->pdev, NULL); + kfree(card); +} + + +static int +nj_setup(struct tiger_hw *card) +{ + card->base = pci_resource_start(card->pdev, 0); + card->base_s = pci_resource_len(card->pdev, 0); + if (!request_region(card->base, card->base_s, card->name)) { + pr_info("%s: NETjet config port %#x-%#x already in use\n", + card->name, card->base, + (u32)(card->base + card->base_s - 1)); + card->base_s = 0; + return -EIO; + } + ASSIGN_FUNC(nj, ISAC, card->isac); + return 0; +} + + +static int __devinit +setup_instance(struct tiger_hw *card) +{ + int i, err; + u_long flags; + + snprintf(card->name, MISDN_MAX_IDLEN - 1, "netjet.%d", nj_cnt + 1); + write_lock_irqsave(&card_lock, flags); + list_add_tail(&card->list, &Cards); + write_unlock_irqrestore(&card_lock, flags); + + _set_debug(card); + card->isac.name = card->name; + spin_lock_init(&card->lock); + card->isac.hwlock = &card->lock; + mISDNisac_init(&card->isac, card); + + card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + card->isac.dch.dev.D.ctrl = nj_dctrl; + for (i = 0; i < 2; i++) { + card->bc[i].bch.nr = i + 1; + set_channelmap(i + 1, card->isac.dch.dev.channelmap); + mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM); + card->bc[i].bch.hw = card; + card->bc[i].bch.ch.send = nj_l2l1B; + card->bc[i].bch.ch.ctrl = nj_bctrl; + card->bc[i].bch.ch.nr = i + 1; + list_add(&card->bc[i].bch.ch.list, + &card->isac.dch.dev.bchannels); + card->bc[i].bch.hw = card; + } + err = nj_setup(card); + if (err) + goto error; + err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev, + card->name); + if (err) + goto error; + err = nj_init_card(card); + if (!err) { + nj_cnt++; + pr_notice("Netjet %d cards installed\n", nj_cnt); + return 0; + } +error: + nj_release(card); + return err; +} + +static int __devinit +nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = -ENOMEM; + int cfg; + struct tiger_hw *card; + + if (pdev->subsystem_vendor == 0x8086 && + pdev->subsystem_device == 0x0003) { + pr_notice("Netjet: Digium X100P/X101P not handled\n"); + return -ENODEV; + } + + if (pdev->subsystem_vendor == 0x55 && + pdev->subsystem_device == 0x02) { + pr_notice("Netjet: Enter!Now not handled yet\n"); + return -ENODEV; + } + + card = kzalloc(sizeof(struct tiger_hw), GFP_ATOMIC); + if (!card) { + pr_info("No kmem for Netjet\n"); + return err; + } + + card->pdev = pdev; + + err = pci_enable_device(pdev); + if (err) { + kfree(card); + return err; + } + + printk(KERN_INFO "nj_probe(mISDN): found adapter at %s\n", + pci_name(pdev)); + + pci_set_master(pdev); + + /* the TJ300 and TJ320 must be detected, the IRQ handling is different + * unfortunately the chips use the same device ID, but the TJ320 has + * the bit20 in status PCI cfg register set + */ + pci_read_config_dword(pdev, 0x04, &cfg); + if (cfg & 0x00100000) + card->typ = NETJET_S_TJ320; + else + card->typ = NETJET_S_TJ300; + + card->base = pci_resource_start(pdev, 0); + card->irq = pdev->irq; + pci_set_drvdata(pdev, card); + err = setup_instance(card); + if (err) + pci_set_drvdata(pdev, NULL); + + return err; +} + + +static void __devexit nj_remove(struct pci_dev *pdev) +{ + struct tiger_hw *card = pci_get_drvdata(pdev); + + if (card) + nj_release(card); + else + pr_info("%s drvdata already removed\n", __func__); +} + +/* We cannot select cards with PCI_SUB... IDs, since here are cards with + * SUB IDs set to PCI_ANY_ID, so we need to match all and reject + * known other cards which not work with this driver - see probe function */ +static struct pci_device_id nj_pci_ids[] __devinitdata = { + { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; +MODULE_DEVICE_TABLE(pci, nj_pci_ids); + +static struct pci_driver nj_driver = { + .name = "netjet", + .probe = nj_probe, + .remove = __devexit_p(nj_remove), + .id_table = nj_pci_ids, +}; + +static int __init nj_init(void) +{ + int err; + + pr_notice("Netjet PCI driver Rev. %s\n", NETJET_REV); + err = pci_register_driver(&nj_driver); + return err; +} + +static void __exit nj_cleanup(void) +{ + pci_unregister_driver(&nj_driver); +} + +module_init(nj_init); +module_exit(nj_cleanup); diff --git a/drivers/isdn/hardware/mISDN/netjet.h b/drivers/isdn/hardware/mISDN/netjet.h new file mode 100644 index 0000000..d061ff9 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/netjet.h @@ -0,0 +1,58 @@ +/* + * NETjet common header file + * + * Author Karsten Keil + * based on work of Matt Henderson and Daniel Potts, + * Traverse Technologies P/L www.traverse.com.au + * + * Copyright 2009 by Karsten Keil + * + * 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 + * published by the Free Software Foundation. + * + * 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. + * + */ + +#define NJ_CTRL 0x00 +#define NJ_DMACTRL 0x01 +#define NJ_AUXCTRL 0x02 +#define NJ_AUXDATA 0x03 +#define NJ_IRQMASK0 0x04 +#define NJ_IRQMASK1 0x05 +#define NJ_IRQSTAT0 0x06 +#define NJ_IRQSTAT1 0x07 +#define NJ_DMA_READ_START 0x08 +#define NJ_DMA_READ_IRQ 0x0c +#define NJ_DMA_READ_END 0x10 +#define NJ_DMA_READ_ADR 0x14 +#define NJ_DMA_WRITE_START 0x18 +#define NJ_DMA_WRITE_IRQ 0x1c +#define NJ_DMA_WRITE_END 0x20 +#define NJ_DMA_WRITE_ADR 0x24 +#define NJ_PULSE_CNT 0x28 + +#define NJ_ISAC_OFF 0xc0 +#define NJ_ISACIRQ 0x10 + +#define NJ_IRQM0_RD_MASK 0x03 +#define NJ_IRQM0_RD_IRQ 0x01 +#define NJ_IRQM0_RD_END 0x02 +#define NJ_IRQM0_WR_MASK 0x0c +#define NJ_IRQM0_WR_IRQ 0x04 +#define NJ_IRQM0_WR_END 0x08 + +/* one page here is no need to be smaller */ +#define NJ_DMA_SIZE 4096 +/* 2 * 64 byte is a compromise between IRQ count and latency */ +#define NJ_DMA_RXSIZE 128 /* 2 * 64 */ +#define NJ_DMA_TXSIZE 128 /* 2 * 64 */ + -- cgit v0.10.2 From 3cad3da3ed9ece03704f7d67e038b8ae710fa312 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 12 Jul 2009 22:05:03 +0200 Subject: drivers/isdn: Drop unnecessary NULL test The result of container_of should not be NULL. In particular, in this case the argument to the enclosing function has passed though INIT_WORK, which dereferences it, implying that its container cannot be NULL. A simplified version of the semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ identifier fn,work,x,fld; type T; expression E1,E2; statement S; @@ static fn(struct work_struct *work) { ... when != work = E1 x = container_of(work,T,fld) ... when != x = E2 - if (x == NULL) S ... } // Signed-off-by: Julia Lawall Signed-off-by: Karsten Keil diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index 341faf5..bf526a7 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c @@ -238,8 +238,6 @@ Amd7930_bh(struct work_struct *work) container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; - if (!cs) - return; if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { if (cs->debug) debugl1(cs, "Amd7930: bh, D-Channel Busy cleared"); diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 3d337d9..d110a77 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1506,8 +1506,6 @@ hfcpci_bh(struct work_struct *work) u_long flags; // struct PStack *stptr; - if (!cs) - return; if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { if (!cs->hw.hfcpci.nt_mode) switch (cs->dc.hfcpci.ph_state) { diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index d92e8d6..419f87c 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -1255,8 +1255,6 @@ hfcsx_bh(struct work_struct *work) container_of(work, struct IsdnCardState, tqueue); u_long flags; - if (!cs) - return; if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { if (!cs->hw.hfcsx.nt_mode) switch (cs->dc.hfcsx.ph_state) { diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index 682cac3..9aba646 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -83,8 +83,6 @@ icc_bh(struct work_struct *work) container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; - if (!cs) - return; if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { if (cs->debug) debugl1(cs, "D-Channel Busy cleared"); diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index 07b1673..a19354d 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -86,8 +86,6 @@ isac_bh(struct work_struct *work) container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; - if (!cs) - return; if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { if (cs->debug) debugl1(cs, "D-Channel Busy cleared"); diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index bb1c8dd..c4d862c 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -105,8 +105,6 @@ W6692_bh(struct work_struct *work) container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; - if (!cs) - return; if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { if (cs->debug) debugl1(cs, "D-Channel Busy cleared"); -- cgit v0.10.2 From ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 24 Jul 2009 18:26:08 +0200 Subject: ISDN: ARRAY_SIZE changes These changes were a direct result of using a semantic patch More information can be found at http://www.emn.fr/x-info/coccinelle/ Modified some of the changes to avoid the extra define. Signed-off-by: Stoyan Gaydarov Signed-off-by: Karsten Keil diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c index 946c38c..1f0a949 100644 --- a/drivers/isdn/act2000/capi.c +++ b/drivers/isdn/act2000/capi.c @@ -78,7 +78,6 @@ static actcapi_msgdsc valid_msg[] = { #endif {{ 0x00, 0x00}, NULL}, }; -#define num_valid_msg (sizeof(valid_msg)/sizeof(actcapi_msgdsc)) #define num_valid_imsg 27 /* MANUFACTURER_IND */ /* @@ -1025,7 +1024,7 @@ actcapi_debug_msg(struct sk_buff *skb, int direction) #ifdef DEBUG_DUMP_SKB dump_skb(skb); #endif - for (i = 0; i < num_valid_msg; i++) + for (i = 0; i < ARRAY_SIZE(valid_msg); i++) if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) && (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) { descr = valid_msg[i].description; diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c index 8325022..f774e12 100644 --- a/drivers/isdn/act2000/module.c +++ b/drivers/isdn/act2000/module.c @@ -23,7 +23,6 @@ static unsigned short act2000_isa_ports[] = 0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380, 0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60, }; -#define ISA_NRPORTS (sizeof(act2000_isa_ports)/sizeof(unsigned short)) static act2000_card *cards = (act2000_card *) NULL; @@ -686,21 +685,21 @@ act2000_addcard(int bus, int port, int irq, char *id) * This may result in more than one card detected. */ switch (bus) { - case ACT2000_BUS_ISA: - for (i = 0; i < ISA_NRPORTS; i++) - if (act2000_isa_detect(act2000_isa_ports[i])) { - printk(KERN_INFO - "act2000: Detected ISA card at port 0x%x\n", - act2000_isa_ports[i]); - act2000_alloccard(bus, act2000_isa_ports[i], irq, id); - } - break; - case ACT2000_BUS_MCA: - case ACT2000_BUS_PCMCIA: - default: - printk(KERN_WARNING - "act2000: addcard: Invalid BUS type %d\n", - bus); + case ACT2000_BUS_ISA: + for (i = 0; i < ARRAY_SIZE(act2000_isa_ports); i++) + if (act2000_isa_detect(act2000_isa_ports[i])) { + printk(KERN_INFO "act2000: Detected " + "ISA card at port 0x%x\n", + act2000_isa_ports[i]); + act2000_alloccard(bus, + act2000_isa_ports[i], irq, id); + } + break; + case ACT2000_BUS_MCA: + case ACT2000_BUS_PCMCIA: + default: + printk(KERN_WARNING + "act2000: addcard: Invalid BUS type %d\n", bus); } } if (!cards) diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 31f91c1..27d5dd6 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -551,9 +551,7 @@ word api_put(APPL * appl, CAPI_MSG * msg) dbug(1,dprintf("com=%x",msg->header.command)); for(j=0;jheader.command) { /* break loop if the message is correct, otherwise continue scan */ diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c index c964b8d..cb7616c 100644 --- a/drivers/isdn/hardware/eicon/os_4bri.c +++ b/drivers/isdn/hardware/eicon/os_4bri.c @@ -149,8 +149,7 @@ int diva_4bri_init_card(diva_os_xdi_adapter_t * a) diva_os_xdi_adapter_t *diva_current; diva_os_xdi_adapter_t *adapter_list[4]; PISDN_ADAPTER Slave; - unsigned long bar_length[sizeof(_4bri_bar_length) / - sizeof(_4bri_bar_length[0])]; + unsigned long bar_length[ARRAY_SIZE(_4bri_bar_length)]; int v2 = _4bri_is_rev_2_card(a->CardOrdinal); int tasks = _4bri_is_rev_2_bri_card(a->CardOrdinal) ? 1 : MQ_INSTANCE_COUNT; int factor = (tasks == 1) ? 1 : 2; diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index 025a20d..475b1a0 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c @@ -833,8 +833,6 @@ static struct FsmNode fnlist[] __initdata = }; /* *INDENT-ON* */ -#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) - int __init CallcNew(void) { @@ -842,7 +840,7 @@ CallcNew(void) callcfsm.event_count = EVENT_COUNT; callcfsm.strEvent = strEvent; callcfsm.strState = strState; - return FsmNew(&callcfsm, fnlist, FNCOUNT); + return FsmNew(&callcfsm, fnlist, ARRAY_SIZE(fnlist)); } void diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index 317f16f..9ce6abe 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -647,8 +647,6 @@ static struct FsmNode L1SFnList[] __initdata = {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, }; -#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode)) - #ifdef HISAX_UINTERFACE static void l1_deact_req_u(struct FsmInst *fi, int event, void *arg) @@ -706,8 +704,6 @@ static struct FsmNode L1UFnList[] __initdata = {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact}, }; -#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode)) - #endif static void @@ -754,8 +750,6 @@ static struct FsmNode L1BFnList[] __initdata = {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact}, }; -#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode)) - int __init Isdnl1New(void) { @@ -765,7 +759,7 @@ Isdnl1New(void) l1fsm_s.event_count = L1_EVENT_COUNT; l1fsm_s.strEvent = strL1Event; l1fsm_s.strState = strL1SState; - retval = FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT); + retval = FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList)); if (retval) return retval; @@ -773,7 +767,7 @@ Isdnl1New(void) l1fsm_b.event_count = L1_EVENT_COUNT; l1fsm_b.strEvent = strL1Event; l1fsm_b.strState = strL1BState; - retval = FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT); + retval = FsmNew(&l1fsm_b, L1BFnList, ARRAY_SIZE(L1BFnList)); if (retval) { FsmFree(&l1fsm_s); return retval; @@ -783,7 +777,7 @@ Isdnl1New(void) l1fsm_u.event_count = L1_EVENT_COUNT; l1fsm_u.strEvent = strL1Event; l1fsm_u.strState = strL1UState; - retval = FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT); + retval = FsmNew(&l1fsm_u, L1UFnList, ARRAY_SIZE(L1UFnList)); if (retval) { FsmFree(&l1fsm_s); FsmFree(&l1fsm_b); diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index 3446f24..7b9496a 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c @@ -1623,8 +1623,6 @@ static struct FsmNode L2FnList[] __initdata = {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da}, }; -#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) - static void isdnl2_l1l2(struct PStack *st, int pr, void *arg) { @@ -1836,7 +1834,7 @@ Isdnl2New(void) l2fsm.event_count = L2_EVENT_COUNT; l2fsm.strEvent = strL2Event; l2fsm.strState = strL2State; - return FsmNew(&l2fsm, L2FnList, L2_FN_COUNT); + return FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList)); } void diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index 935f233..0676602 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c @@ -543,8 +543,6 @@ static struct FsmNode L3FnList[] __initdata = }; /* *INDENT-ON* */ -#define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode)) - void l3_msg(struct PStack *st, int pr, void *arg) { @@ -587,7 +585,7 @@ Isdnl3New(void) l3fsm.event_count = L3_EVENT_COUNT; l3fsm.strEvent = strL3Event; l3fsm.strState = strL3State; - return FsmNew(&l3fsm, L3FnList, L3_FN_COUNT); + return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList)); } void diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c index c5c36ee..b0554f8 100644 --- a/drivers/isdn/hisax/l3_1tr6.c +++ b/drivers/isdn/hisax/l3_1tr6.c @@ -698,9 +698,6 @@ static struct stateentry downstl[] = CC_T308_2, l3_1tr6_t308_2}, }; -#define DOWNSTL_LEN \ - (sizeof(downstl) / sizeof(struct stateentry)) - static struct stateentry datastln1[] = { {SBIT(0), @@ -735,9 +732,6 @@ static struct stateentry datastln1[] = MT_N1_REL_ACK, l3_1tr6_rel_ack} }; -#define DATASTLN1_LEN \ - (sizeof(datastln1) / sizeof(struct stateentry)) - static struct stateentry manstatelist[] = { {SBIT(2), @@ -746,8 +740,6 @@ static struct stateentry manstatelist[] = DL_RELEASE | INDICATION, l3_1tr6_dl_release}, }; -#define MANSLLEN \ - (sizeof(manstatelist) / sizeof(struct stateentry)) /* *INDENT-ON* */ static void @@ -840,11 +832,11 @@ up1tr6(struct PStack *st, int pr, void *arg) mt = MT_N1_INVALID; } } - for (i = 0; i < DATASTLN1_LEN; i++) + for (i = 0; i < ARRAY_SIZE(datastln1); i++) if ((mt == datastln1[i].primitive) && ((1 << proc->state) & datastln1[i].state)) break; - if (i == DATASTLN1_LEN) { + if (i == ARRAY_SIZE(datastln1)) { dev_kfree_skb(skb); if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "up1tr6%sstate %d mt %x unhandled", @@ -892,11 +884,11 @@ down1tr6(struct PStack *st, int pr, void *arg) proc = arg; } - for (i = 0; i < DOWNSTL_LEN; i++) + for (i = 0; i < ARRAY_SIZE(downstl); i++) if ((pr == downstl[i].primitive) && ((1 << proc->state) & downstl[i].state)) break; - if (i == DOWNSTL_LEN) { + if (i == ARRAY_SIZE(downstl)) { if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "down1tr6 state %d prim %d unhandled", proc->state, pr); @@ -922,11 +914,11 @@ man1tr6(struct PStack *st, int pr, void *arg) printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr); return; } - for (i = 0; i < MANSLLEN; i++) + for (i = 0; i < ARRAY_SIZE(manstatelist); i++) if ((pr == manstatelist[i].primitive) && ((1 << proc->state) & manstatelist[i].state)) break; - if (i == MANSLLEN) { + if (i == ARRAY_SIZE(manstatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled", proc->callref & 0x7f, proc->state, pr); diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index 99feae8..a12fa4d 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -2820,9 +2820,6 @@ static struct stateentry downstatelist[] = CC_T309, l3dss1_dl_release}, }; -#define DOWNSLLEN \ - (sizeof(downstatelist) / sizeof(struct stateentry)) - static struct stateentry datastatelist[] = { {ALL_STATES, @@ -2875,9 +2872,6 @@ static struct stateentry datastatelist[] = MT_RESUME_REJECT, l3dss1_resume_rej}, }; -#define DATASLLEN \ - (sizeof(datastatelist) / sizeof(struct stateentry)) - static struct stateentry globalmes_list[] = { {ALL_STATES, @@ -2888,8 +2882,6 @@ static struct stateentry globalmes_list[] = MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack}, */ }; -#define GLOBALM_LEN \ - (sizeof(globalmes_list) / sizeof(struct stateentry)) static struct stateentry manstatelist[] = { @@ -2903,8 +2895,6 @@ static struct stateentry manstatelist[] = DL_RELEASE | INDICATION, l3dss1_dl_release}, }; -#define MANSLLEN \ - (sizeof(manstatelist) / sizeof(struct stateentry)) /* *INDENT-ON* */ @@ -2918,11 +2908,11 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) struct l3_process *proc = st->l3.global; proc->callref = skb->data[2]; /* cr flag */ - for (i = 0; i < GLOBALM_LEN; i++) + for (i = 0; i < ARRAY_SIZE(globalmes_list); i++) if ((mt == globalmes_list[i].primitive) && ((1 << proc->state) & globalmes_list[i].state)) break; - if (i == GLOBALM_LEN) { + if (i == ARRAY_SIZE(globalmes_list)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1 global state %d mt %x unhandled", proc->state, mt); @@ -3097,11 +3087,11 @@ dss1up(struct PStack *st, int pr, void *arg) } if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) l3dss1_deliver_display(proc, pr, p); /* Display IE included */ - for (i = 0; i < DATASLLEN; i++) + for (i = 0; i < ARRAY_SIZE(datastatelist); i++) if ((mt == datastatelist[i].primitive) && ((1 << proc->state) & datastatelist[i].state)) break; - if (i == DATASLLEN) { + if (i == ARRAY_SIZE(datastatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1up%sstate %d mt %#x unhandled", (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", @@ -3156,11 +3146,11 @@ dss1down(struct PStack *st, int pr, void *arg) return; } - for (i = 0; i < DOWNSLLEN; i++) + for (i = 0; i < ARRAY_SIZE(downstatelist); i++) if ((pr == downstatelist[i].primitive) && ((1 << proc->state) & downstatelist[i].state)) break; - if (i == DOWNSLLEN) { + if (i == ARRAY_SIZE(downstatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1down state %d prim %#x unhandled", proc->state, pr); @@ -3184,11 +3174,11 @@ dss1man(struct PStack *st, int pr, void *arg) printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr); return; } - for (i = 0; i < MANSLLEN; i++) + for (i = 0; i < ARRAY_SIZE(manstatelist); i++) if ((pr == manstatelist[i].primitive) && ((1 << proc->state) & manstatelist[i].state)) break; - if (i == MANSLLEN) { + if (i == ARRAY_SIZE(manstatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "cr %d dss1man state %d prim %#x unhandled", proc->callref & 0x7f, proc->state, pr); diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c index f7041d5..4622d43 100644 --- a/drivers/isdn/hisax/l3ni1.c +++ b/drivers/isdn/hisax/l3ni1.c @@ -2755,9 +2755,6 @@ static struct stateentry downstatelist[] = CC_TSPID, l3ni1_spid_tout }, }; -#define DOWNSLLEN \ - (sizeof(downstatelist) / sizeof(struct stateentry)) - static struct stateentry datastatelist[] = { {ALL_STATES, @@ -2810,9 +2807,6 @@ static struct stateentry datastatelist[] = MT_RESUME_REJECT, l3ni1_resume_rej}, }; -#define DATASLLEN \ - (sizeof(datastatelist) / sizeof(struct stateentry)) - static struct stateentry globalmes_list[] = { {ALL_STATES, @@ -2825,8 +2819,6 @@ static struct stateentry globalmes_list[] = { SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send }, { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid }, }; -#define GLOBALM_LEN \ - (sizeof(globalmes_list) / sizeof(struct stateentry)) static struct stateentry manstatelist[] = { @@ -2840,8 +2832,6 @@ static struct stateentry manstatelist[] = DL_RELEASE | INDICATION, l3ni1_dl_release}, }; -#define MANSLLEN \ - (sizeof(manstatelist) / sizeof(struct stateentry)) /* *INDENT-ON* */ @@ -2858,11 +2848,11 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) proc->callref = skb->data[2]; /* cr flag */ else proc->callref = 0; - for (i = 0; i < GLOBALM_LEN; i++) + for (i = 0; i < ARRAY_SIZE(globalmes_list); i++) if ((mt == globalmes_list[i].primitive) && ((1 << proc->state) & globalmes_list[i].state)) break; - if (i == GLOBALM_LEN) { + if (i == ARRAY_SIZE(globalmes_list)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "ni1 global state %d mt %x unhandled", proc->state, mt); @@ -3049,11 +3039,11 @@ ni1up(struct PStack *st, int pr, void *arg) } if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) l3ni1_deliver_display(proc, pr, p); /* Display IE included */ - for (i = 0; i < DATASLLEN; i++) + for (i = 0; i < ARRAY_SIZE(datastatelist); i++) if ((mt == datastatelist[i].primitive) && ((1 << proc->state) & datastatelist[i].state)) break; - if (i == DATASLLEN) { + if (i == ARRAY_SIZE(datastatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "ni1up%sstate %d mt %#x unhandled", (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", @@ -3108,11 +3098,11 @@ ni1down(struct PStack *st, int pr, void *arg) return; } - for (i = 0; i < DOWNSLLEN; i++) + for (i = 0; i < ARRAY_SIZE(downstatelist); i++) if ((pr == downstatelist[i].primitive) && ((1 << proc->state) & downstatelist[i].state)) break; - if (i == DOWNSLLEN) { + if (i == ARRAY_SIZE(downstatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "ni1down state %d prim %#x unhandled", proc->state, pr); @@ -3136,11 +3126,11 @@ ni1man(struct PStack *st, int pr, void *arg) printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr); return; } - for (i = 0; i < MANSLLEN; i++) + for (i = 0; i < ARRAY_SIZE(manstatelist); i++) if ((pr == manstatelist[i].primitive) && ((1 << proc->state) & manstatelist[i].state)) break; - if (i == MANSLLEN) { + if (i == ARRAY_SIZE(manstatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "cr %d ni1man state %d prim %#x unhandled", proc->callref & 0x7f, proc->state, pr); diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index aacbf0d..8b853d5 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c @@ -140,7 +140,7 @@ struct MessageType { } }; -#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType) +#define MTSIZE ARRAY_SIZE(mtlist) static struct MessageType mt_n0[] = @@ -157,7 +157,7 @@ struct MessageType mt_n0[] = {MT_N0_CLO_ACK, "CLOse ACKnowledge"} }; -#define MT_N0_LEN (sizeof(mt_n0) / sizeof(struct MessageType)) +#define MT_N0_LEN ARRAY_SIZE(mt_n0) static struct MessageType mt_n1[] = @@ -194,7 +194,7 @@ struct MessageType mt_n1[] = {MT_N1_STAT, "STATus"} }; -#define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType)) +#define MT_N1_LEN ARRAY_SIZE(mt_n1) static int @@ -438,7 +438,7 @@ struct CauseValue { }, }; -#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue) +#define CVSIZE ARRAY_SIZE(cvlist) static int @@ -516,7 +516,7 @@ struct MessageType cause_1tr6[] = {CAUSE_UserInfoDiscarded, "User Info Discarded"} }; -static int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); +static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6); static int prcause_1tr6(char *dest, u_char * p) @@ -865,7 +865,7 @@ struct DTag { /* Display tags */ { 0x96, "Redirection name" }, { 0x9e, "Text" }, }; -#define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag) +#define DTAGSIZE ARRAY_SIZE(dtaglist) static int disptext_ni1(char *dest, u_char * p) @@ -1074,7 +1074,7 @@ struct InformationElement { }; -#define IESIZE sizeof(ielist)/sizeof(struct InformationElement) +#define IESIZE ARRAY_SIZE(ielist) static struct InformationElement ielist_ni1[] = { @@ -1102,7 +1102,7 @@ struct InformationElement ielist_ni1[] = { }; -#define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement) +#define IESIZE_NI1 ARRAY_SIZE(ielist_ni1) static struct InformationElement ielist_ni1_cs5[] = { @@ -1110,14 +1110,14 @@ struct InformationElement ielist_ni1_cs5[] = { { 0x2a, "Display text", disptext_ni1 }, }; -#define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement) +#define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5) static struct InformationElement ielist_ni1_cs6[] = { { 0x7b, "Call appearance", general_ni1 }, }; -#define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement) +#define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6) static struct InformationElement we_0[] = { @@ -1133,7 +1133,7 @@ static struct InformationElement we_0[] = {WE0_userInfo, "User Info", general} }; -#define WE_0_LEN (sizeof(we_0) / sizeof(struct InformationElement)) +#define WE_0_LEN ARRAY_SIZE(we_0) static struct InformationElement we_6[] = { @@ -1145,7 +1145,7 @@ static struct InformationElement we_6[] = {WE6_statusCalled, "Status Called", general}, {WE6_addTransAttr, "Additional Transmission Attributes", general} }; -#define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement)) +#define WE_6_LEN ARRAY_SIZE(we_6) int QuickHex(char *txt, u_char * p, int cnt) diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c index ceb0df9..6e65424 100644 --- a/drivers/isdn/hisax/tei.c +++ b/drivers/isdn/hisax/tei.c @@ -447,8 +447,6 @@ static struct FsmNode TeiFnList[] __initdata = {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, }; -#define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode)) - int __init TeiNew(void) { @@ -456,7 +454,7 @@ TeiNew(void) teifsm.event_count = TEI_EVENT_COUNT; teifsm.strEvent = strTeiEvent; teifsm.strState = strTeiState; - return FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT); + return FsmNew(&teifsm, TeiFnList, ARRAY_SIZE(TeiFnList)); } void diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index 9c2589e..e17f004 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -1832,8 +1832,6 @@ static struct FsmNode L2FnList[] = {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, }; -#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) - static int ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) { -- cgit v0.10.2 From f70e75e11069edfbe55be06960854c46860da0a3 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 24 Jul 2009 18:41:23 +0200 Subject: mISDN: hfcmulti display real PCI ids for not supported cards In the PCI probe function struct pci_device_id points to the matched entry of the ID table, but for devices which are matched with PCI_ANY_ID sub IDs we want display the IDs of the device itself. Signed-off-by: Karsten Keil diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index fd77bb1..faed794 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -5370,9 +5370,10 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ent->device == PCI_DEVICE_ID_CCD_HFC8S || ent->device == PCI_DEVICE_ID_CCD_HFCE1)) { printk(KERN_ERR - "Unknown HFC multiport controller (vendor:%x device:%x " - "subvendor:%x subdevice:%x)\n", ent->vendor, ent->device, - ent->subvendor, ent->subdevice); + "Unknown HFC multiport controller (vendor:%04x device:%04x " + "subvendor:%04x subdevice:%04x)\n", pdev->vendor, + pdev->device, pdev->subsystem_vendor, + pdev->subsystem_device); printk(KERN_ERR "Please contact the driver maintainer for support.\n"); return -ENODEV; -- cgit v0.10.2 From dcc3ae9a5252ea4ffe65b43cdc09ec2654b48000 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:07:20 +0000 Subject: igb: remove media type fiber as it is misleading The current igb driver only supports copper and serdes. The fiber media type is a holdover from earlier NICs as the current nics supported by igb all use serdes when communicating over a fiber connection. As a result we can remove media type fiber without losing any functionality. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index ac28dd5..bd3efdb 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -867,8 +867,7 @@ void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw) u32 reg; if (hw->mac.type != e1000_82576 || - (hw->phy.media_type != e1000_media_type_fiber && - hw->phy.media_type != e1000_media_type_internal_serdes)) + hw->phy.media_type != e1000_media_type_internal_serdes) return; /* if the management interface is not enabled, then power down */ diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 68aac20..f096ddd 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -61,8 +61,7 @@ enum e1000_mac_type { enum e1000_media_type { e1000_media_type_unknown = 0, e1000_media_type_copper = 1, - e1000_media_type_fiber = 2, - e1000_media_type_internal_serdes = 3, + e1000_media_type_internal_serdes = 2, e1000_num_media_types }; diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 472f3f1..37706d9 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -713,8 +713,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) * configuration of the MAC to match the "fc" parameter. */ if (mac->autoneg_failed) { - if (hw->phy.media_type == e1000_media_type_fiber || - hw->phy.media_type == e1000_media_type_internal_serdes) + if (hw->phy.media_type == e1000_media_type_internal_serdes) ret_val = igb_force_mac_fc(hw); } else { if (hw->phy.media_type == e1000_media_type_copper) @@ -1161,22 +1160,16 @@ s32 igb_blink_led(struct e1000_hw *hw) u32 ledctl_blink = 0; u32 i; - if (hw->phy.media_type == e1000_media_type_fiber) { - /* always blink LED0 for PCI-E fiber */ - ledctl_blink = E1000_LEDCTL_LED0_BLINK | - (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); - } else { - /* - * set the blink bit for each LED that's "on" (0x0E) - * in ledctl_mode2 - */ - ledctl_blink = hw->mac.ledctl_mode2; - for (i = 0; i < 4; i++) - if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == - E1000_LEDCTL_MODE_LED_ON) - ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << - (i * 8)); - } + /* + * set the blink bit for each LED that's "on" (0x0E) + * in ledctl_mode2 + */ + ledctl_blink = hw->mac.ledctl_mode2; + for (i = 0; i < 4; i++) + if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == + E1000_LEDCTL_MODE_LED_ON) + ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << + (i * 8)); wr32(E1000_LEDCTL, ledctl_blink); @@ -1191,15 +1184,7 @@ s32 igb_blink_led(struct e1000_hw *hw) **/ s32 igb_led_off(struct e1000_hw *hw) { - u32 ctrl; - switch (hw->phy.media_type) { - case e1000_media_type_fiber: - ctrl = rd32(E1000_CTRL); - ctrl |= E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - wr32(E1000_CTRL, ctrl); - break; case e1000_media_type_copper: wr32(E1000_LEDCTL, hw->mac.ledctl_mode1); break; diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 9598ac0..a9c37cb 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -168,8 +168,7 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->duplex = -1; } - ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || - hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + ecmd->autoneg = hw->mac.autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; return 0; } @@ -191,23 +190,18 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; - if (hw->phy.media_type == e1000_media_type_fiber) - hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | - ADVERTISED_FIBRE | - ADVERTISED_Autoneg; - else - hw->phy.autoneg_advertised = ecmd->advertising | - ADVERTISED_TP | - ADVERTISED_Autoneg; + hw->phy.autoneg_advertised = ecmd->advertising | + ADVERTISED_TP | + ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; - } else + } else { if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { clear_bit(__IGB_RESETTING, &adapter->state); return -EINVAL; } + } /* reset the link */ - if (netif_running(adapter->netdev)) { igb_down(adapter); igb_up(adapter); @@ -267,8 +261,8 @@ static int igb_set_pauseparam(struct net_device *netdev, } else igb_reset(adapter); } else - retval = ((hw->phy.media_type == e1000_media_type_fiber) ? - igb_setup_link(hw) : igb_force_mac_fc(hw)); + retval = ((hw->phy.media_type == e1000_media_type_copper) ? + igb_force_mac_fc(hw) : igb_setup_link(hw)); clear_bit(__IGB_RESETTING, &adapter->state); return retval; @@ -1483,8 +1477,7 @@ static int igb_setup_loopback_test(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 reg; - if (hw->phy.media_type == e1000_media_type_fiber || - hw->phy.media_type == e1000_media_type_internal_serdes) { + if (hw->phy.media_type == e1000_media_type_internal_serdes) { reg = rd32(E1000_RCTL); reg |= E1000_RCTL_LBM_TCVR; wr32(E1000_RCTL, reg); diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index adb09d3..39b3b6a 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -2618,10 +2618,6 @@ static bool igb_has_link(struct igb_adapter *adapter) link_active = true; } break; - case e1000_media_type_fiber: - ret_val = hw->mac.ops.check_for_link(hw); - link_active = !!(rd32(E1000_STATUS) & E1000_STATUS_LU); - break; case e1000_media_type_internal_serdes: ret_val = hw->mac.ops.check_for_link(hw); link_active = hw->mac.serdes_has_link; @@ -5136,14 +5132,6 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx) mac->autoneg = 0; - /* Fiber NICs only allow 1000 gbps Full duplex */ - if ((adapter->hw.phy.media_type == e1000_media_type_fiber) && - spddplx != (SPEED_1000 + DUPLEX_FULL)) { - dev_err(&adapter->pdev->dev, - "Unsupported Speed/Duplex configuration\n"); - return -EINVAL; - } - switch (spddplx) { case SPEED_10 + DUPLEX_HALF: mac->forced_speed_duplex = ADVERTISE_10_HALF; -- cgit v0.10.2 From 099e1cb700da6359b784ac7fb65099091b7b961e Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:07:40 +0000 Subject: igb: make serdes power down available for 82575 in addition to 82576 parts There was a serdes power down workaround that was originally added for 82576 fiber. However it has also been found that this workaround is needed for serdes connections as well. In addition it is also needed for 82575 serdes so we we need to remove the checks restricting it to 82576. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index bd3efdb..fa4a762 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -866,8 +866,7 @@ void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw) { u32 reg; - if (hw->mac.type != e1000_82576 || - hw->phy.media_type != e1000_media_type_internal_serdes) + if (hw->phy.media_type != e1000_media_type_internal_serdes) return; /* if the management interface is not enabled, then power down */ @@ -1228,10 +1227,6 @@ out: static bool igb_sgmii_active_82575(struct e1000_hw *hw) { struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575; - - if (hw->mac.type != e1000_82575 && hw->mac.type != e1000_82576) - return false; - return dev_spec->sgmii_active; } diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index 0f16aba..b674417 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -32,6 +32,11 @@ void igb_update_mc_addr_list(struct e1000_hw*, u8*, u32, u32, u32); extern void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw); extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw); +#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \ + (ID_LED_DEF1_DEF2 << 8) | \ + (ID_LED_DEF1_DEF2 << 4) | \ + (ID_LED_OFF1_ON2)) + #define E1000_RAR_ENTRIES_82575 16 #define E1000_RAR_ENTRIES_82576 24 diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 37706d9..34f1a37 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -1064,9 +1064,17 @@ static s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data) goto out; } - if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) - *data = ID_LED_DEFAULT; - + if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) { + switch(hw->phy.media_type) { + case e1000_media_type_internal_serdes: + *data = ID_LED_DEFAULT_82575_SERDES; + break; + case e1000_media_type_copper: + default: + *data = ID_LED_DEFAULT; + break; + } + } out: return ret_val; } -- cgit v0.10.2 From f3e7841ca3608db6e0207cd8af5561f065882517 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:07:58 +0000 Subject: igb: change configure_pcs_link to void since it always returns 0 Since igb_configure_pcs_link always returns 0 there isn't really much point to checking for the result so it is best just to change this to a void so we can properly ignore the return result. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index fa4a762..f946bed 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -53,7 +53,7 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *); static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16); static void igb_clear_hw_cntrs_82575(struct e1000_hw *); static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *, u16); -static s32 igb_configure_pcs_link_82575(struct e1000_hw *); +static void igb_configure_pcs_link_82575(struct e1000_hw *); static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *, u16 *, u16 *); static s32 igb_get_phy_id_82575(struct e1000_hw *); @@ -1050,9 +1050,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) } } - ret_val = igb_configure_pcs_link_82575(hw); - if (ret_val) - goto out; + igb_configure_pcs_link_82575(hw); /* * Check link status. Wait up to 100 microseconds for link to become @@ -1161,14 +1159,14 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw) * independent interface (sgmii) is being used. Configures the link * for auto-negotiation or forces speed/duplex. **/ -static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw) +static void igb_configure_pcs_link_82575(struct e1000_hw *hw) { struct e1000_mac_info *mac = &hw->mac; u32 reg = 0; if (hw->phy.media_type != e1000_media_type_copper || !(igb_sgmii_active_82575(hw))) - goto out; + return; /* For SGMII, we need to issue a PCS autoneg restart */ reg = rd32(E1000_PCS_LCTL); @@ -1211,9 +1209,6 @@ static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw) reg); } wr32(E1000_PCS_LCTL, reg); - -out: - return 0; } /** -- cgit v0.10.2 From 12645a196eccb9209f88915f56a686086dea1a16 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:08:16 +0000 Subject: igb: do not overwrite EEPROM LED settings The igb driver was overwritting the LED settings that were configured via EEPROM. This is not correct behavior as the LED settings are meant to be configured by EEPROM and not changed. This change removes the code that was setting the LED behavior on the interface. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index f946bed..606c25c 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -1000,7 +1000,7 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw) **/ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) { - u32 ctrl, led_ctrl; + u32 ctrl; s32 ret_val; bool link; @@ -1015,11 +1015,6 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) break; case e1000_phy_igp_3: ret_val = igb_copper_link_setup_igp(hw); - /* Setup activity LED */ - led_ctrl = rd32(E1000_LEDCTL); - led_ctrl &= IGP_ACTIVITY_LED_MASK; - led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); - wr32(E1000_LEDCTL, led_ctrl); break; default: ret_val = -E1000_ERR_PHY; -- cgit v0.10.2 From 009bc06e5311b48c77b7708d9e226ae0f110373a Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:08:35 +0000 Subject: igb: add completion timeout workaround for 82575/82576 The 82575 and 82576 hardware can both experience data corruption issues if a pci-e completion arrives after the timeout value. In order to avoid this we need to increase the timeout value while pci-e master is disabled. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 606c25c..c4506bf 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -61,6 +61,7 @@ static void igb_release_swfw_sync_82575(struct e1000_hw *, u16); static bool igb_sgmii_active_82575(struct e1000_hw *); static s32 igb_reset_init_script_82575(struct e1000_hw *); static s32 igb_read_mac_addr_82575(struct e1000_hw *); +static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw); static s32 igb_get_invariants_82575(struct e1000_hw *hw) { @@ -909,6 +910,12 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw) if (ret_val) hw_dbg("PCI-E Master disable polling has failed.\n"); + /* set the completion timeout for interface */ + ret_val = igb_set_pcie_completion_timeout(hw); + if (ret_val) { + hw_dbg("PCI-E Set completion timeout has failed.\n"); + } + hw_dbg("Masking off all interrupts\n"); wr32(E1000_IMC, 0xffffffff); @@ -1408,6 +1415,57 @@ void igb_rx_fifo_flush_82575(struct e1000_hw *hw) } /** + * igb_set_pcie_completion_timeout - set pci-e completion timeout + * @hw: pointer to the HW structure + * + * The defaults for 82575 and 82576 should be in the range of 50us to 50ms, + * however the hardware default for these parts is 500us to 1ms which is less + * than the 10ms recommended by the pci-e spec. To address this we need to + * increase the value to either 10ms to 200ms for capability version 1 config, + * or 16ms to 55ms for version 2. + **/ +static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw) +{ + u32 gcr = rd32(E1000_GCR); + s32 ret_val = 0; + u16 pcie_devctl2; + + /* only take action if timeout value is defaulted to 0 */ + if (gcr & E1000_GCR_CMPL_TMOUT_MASK) + goto out; + + /* + * if capababilities version is type 1 we can write the + * timeout of 10ms to 200ms through the GCR register + */ + if (!(gcr & E1000_GCR_CAP_VER2)) { + gcr |= E1000_GCR_CMPL_TMOUT_10ms; + goto out; + } + + /* + * for version 2 capabilities we need to write the config space + * directly in order to set the completion timeout value for + * 16ms to 55ms + */ + ret_val = igb_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2, + &pcie_devctl2); + if (ret_val) + goto out; + + pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms; + + ret_val = igb_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2, + &pcie_devctl2); +out: + /* disable completion timeout resend */ + gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND; + + wr32(E1000_GCR, gcr); + return ret_val; +} + +/** * igb_vmdq_set_loopback_pf - enable or disable vmdq loopback * @hw: pointer to the hardware struct * @enable: state to enter, either enabled or disabled diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h index 3bda3db..c858293 100644 --- a/drivers/net/igb/e1000_defines.h +++ b/drivers/net/igb/e1000_defines.h @@ -435,6 +435,12 @@ /* Flow Control */ #define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ +/* PCI Express Control */ +#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000 +#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000 +#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000 +#define E1000_GCR_CAP_VER2 0x00040000 + /* PHY Control Register */ #define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ #define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ @@ -569,9 +575,11 @@ /* PCI/PCI-X/PCI-EX Config space */ #define PCIE_LINK_STATUS 0x12 +#define PCIE_DEVICE_CONTROL2 0x28 #define PCIE_LINK_WIDTH_MASK 0x3F0 #define PCIE_LINK_WIDTH_SHIFT 4 +#define PCIE_DEVICE_CONTROL2_16ms 0x0005 #define PHY_REVISION_MASK 0xFFFFFFF0 #define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index f096ddd..eb41f3b 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -494,5 +494,7 @@ extern char *igb_get_hw_dev_name(struct e1000_hw *hw); #else #define hw_dbg(format, arg...) #endif - #endif +/* These functions must be implemented by drivers */ +s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); +s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 34f1a37..60343b5 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -37,20 +37,6 @@ static s32 igb_set_default_fc(struct e1000_hw *hw); static s32 igb_set_fc_watermarks(struct e1000_hw *hw); -static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) -{ - struct igb_adapter *adapter = hw->back; - u16 cap_offset; - - cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); - if (!cap_offset) - return -E1000_ERR_CONFIG; - - pci_read_config_word(adapter->pdev, cap_offset + reg, value); - - return 0; -} - /** * igb_get_bus_info_pcie - Get PCIe bus information * @hw: pointer to the HW structure diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h index 6e59245..345d144 100644 --- a/drivers/net/igb/e1000_regs.h +++ b/drivers/net/igb/e1000_regs.h @@ -305,6 +305,7 @@ enum { #define E1000_CCMCTL 0x05B48 /* CCM Control Register */ #define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */ #define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */ +#define E1000_GCR 0x05B00 /* PCI-Ex Control */ #define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ #define E1000_SWSM 0x05B50 /* SW Semaphore */ #define E1000_FWSM 0x05B54 /* FW Semaphore */ diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 39b3b6a..2cb5460 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -5029,6 +5029,34 @@ static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } } +s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) +{ + struct igb_adapter *adapter = hw->back; + u16 cap_offset; + + cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (!cap_offset) + return -E1000_ERR_CONFIG; + + pci_read_config_word(adapter->pdev, cap_offset + reg, value); + + return 0; +} + +s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) +{ + struct igb_adapter *adapter = hw->back; + u16 cap_offset; + + cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (!cap_offset) + return -E1000_ERR_CONFIG; + + pci_write_config_word(adapter->pdev, cap_offset + reg, *value); + + return 0; +} + static void igb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) { -- cgit v0.10.2 From 28fc06f58b1fe567bb86c7d0e3d93137e5c0126e Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:08:54 +0000 Subject: igb: move all multicast addresses into multicast table array This patch moves all of the multicast addresses out of the free Receive address registers and instead programs them all into the multicast table array. As a result the multicast filtering may not be as precise, but it also greatly reduces the overhead for multicast addresses. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index c4506bf..5d2c2fb 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -798,65 +798,6 @@ static void igb_init_rx_addrs_82575(struct e1000_hw *hw, u16 rar_count) } /** - * igb_update_mc_addr_list - Update Multicast addresses - * @hw: pointer to the HW structure - * @mc_addr_list: array of multicast addresses to program - * @mc_addr_count: number of multicast addresses to program - * @rar_used_count: the first RAR register free to program - * @rar_count: total number of supported Receive Address Registers - * - * Updates the Receive Address Registers and Multicast Table Array. - * The caller must have a packed mc_addr_list of multicast addresses. - * The parameter rar_count will usually be hw->mac.rar_entry_count - * unless there are workarounds that change this. - **/ -void igb_update_mc_addr_list(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count, - u32 rar_used_count, u32 rar_count) -{ - u32 hash_value; - u32 i; - u8 addr[6] = {0,0,0,0,0,0}; - /* - * This function is essentially the same as that of - * igb_update_mc_addr_list_generic. However it also takes care - * of the special case where the register offset of the - * second set of RARs begins elsewhere. This is implicitly taken care by - * function e1000_rar_set_generic. - */ - - /* - * Load the first set of multicast addresses into the exact - * filters (RAR). If there are not enough to fill the RAR - * array, clear the filters. - */ - for (i = rar_used_count; i < rar_count; i++) { - if (mc_addr_count) { - igb_rar_set(hw, mc_addr_list, i); - mc_addr_count--; - mc_addr_list += ETH_ALEN; - } else { - igb_rar_set(hw, addr, i); - } - } - - /* Clear the old settings from the MTA */ - hw_dbg("Clearing MTA\n"); - for (i = 0; i < hw->mac.mta_reg_count; i++) { - array_wr32(E1000_MTA, i, 0); - wrfl(); - } - - /* Load any remaining multicast addresses into the hash table. */ - for (; mc_addr_count > 0; mc_addr_count--) { - hash_value = igb_hash_mc_addr(hw, mc_addr_list); - hw_dbg("Hash value = 0x%03X\n", hash_value); - igb_mta_set(hw, hash_value); - mc_addr_list += ETH_ALEN; - } -} - -/** * igb_shutdown_fiber_serdes_link_82575 - Remove link during power down * @hw: pointer to the HW structure * diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index b674417..8a1e659 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -28,7 +28,6 @@ #ifndef _E1000_82575_H_ #define _E1000_82575_H_ -void igb_update_mc_addr_list(struct e1000_hw*, u8*, u32, u32, u32); extern void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw); extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw); diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index eb41f3b..83f9b4f 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -338,6 +338,10 @@ struct e1000_mac_info { u16 ifs_ratio; u16 ifs_step_size; u16 mta_reg_count; + + /* Maximum size of the MTA register table in all supported adapters */ + #define MAX_MTA_REG 128 + u32 mta_shadow[MAX_MTA_REG]; u16 rar_entry_count; u8 forced_speed_duplex; diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 60343b5..46e27e9 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -261,6 +261,41 @@ void igb_mta_set(struct e1000_hw *hw, u32 hash_value) } /** + * igb_update_mc_addr_list - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * + * Updates entire Multicast Table Array. + * The caller must have a packed mc_addr_list of multicast addresses. + **/ +void igb_update_mc_addr_list(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count) +{ + u32 hash_value, hash_bit, hash_reg; + int i; + + /* clear mta_shadow */ + memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); + + /* update mta_shadow from mc_addr_list */ + for (i = 0; (u32) i < mc_addr_count; i++) { + hash_value = igb_hash_mc_addr(hw, mc_addr_list); + + hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); + hash_bit = hash_value & 0x1F; + + hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit); + mc_addr_list += (ETH_ALEN); + } + + /* replace the entire MTA table */ + for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) + array_wr32(E1000_MTA, i, hw->mac.mta_shadow[i]); + wrfl(); +} + +/** * igb_hash_mc_addr - Generate a multicast hash value * @hw: pointer to the HW structure * @mc_addr: pointer to a multicast address diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h index 1d690b4..f9ebfb3 100644 --- a/drivers/net/igb/e1000_mac.h +++ b/drivers/net/igb/e1000_mac.h @@ -51,6 +51,8 @@ s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex); s32 igb_id_led_init(struct e1000_hw *hw); s32 igb_led_off(struct e1000_hw *hw); +void igb_update_mc_addr_list(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count); s32 igb_setup_link(struct e1000_hw *hw); s32 igb_validate_mdi_setting(struct e1000_hw *hw); s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 2cb5460..e4f4526 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -127,7 +127,7 @@ static void igb_restore_vlan(struct igb_adapter *); static void igb_ping_all_vfs(struct igb_adapter *); static void igb_msg_task(struct igb_adapter *); static int igb_rcv_msg_from_vf(struct igb_adapter *, u32); -static void igb_set_mc_list_pools(struct igb_adapter *, int, u16); +static inline void igb_set_rah_pool(struct e1000_hw *, int , int); static void igb_vmm_control(struct igb_adapter *); static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *); static void igb_restore_vf_multicasts(struct igb_adapter *adapter); @@ -2535,7 +2535,6 @@ static void igb_set_multi(struct net_device *netdev) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct e1000_mac_info *mac = &hw->mac; struct dev_mc_list *mc_ptr; u8 *mta_list = NULL; u32 rctl; @@ -2558,13 +2557,18 @@ static void igb_set_multi(struct net_device *netdev) } wr32(E1000_RCTL, rctl); - if (netdev->mc_count) { - mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC); - if (!mta_list) { - dev_err(&adapter->pdev->dev, - "failed to allocate multicast filter list\n"); - return; - } + if (!netdev->mc_count) { + /* nothing to program, so clear mc list */ + igb_update_mc_addr_list(hw, NULL, 0); + igb_restore_vf_multicasts(adapter); + return; + } + + mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC); + if (!mta_list) { + dev_err(&adapter->pdev->dev, + "failed to allocate multicast filter list\n"); + return; } /* The shared function expects a packed array of only addresses. */ @@ -2576,14 +2580,9 @@ static void igb_set_multi(struct net_device *netdev) memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN); mc_ptr = mc_ptr->next; } - igb_update_mc_addr_list(hw, mta_list, i, - adapter->vfs_allocated_count + 1, - mac->rar_entry_count); - - igb_set_mc_list_pools(adapter, i, mac->rar_entry_count); - igb_restore_vf_multicasts(adapter); - + igb_update_mc_addr_list(hw, mta_list, i); kfree(mta_list); + igb_restore_vf_multicasts(adapter); } /* Need to wait a few seconds after link up to get diagnostic information from @@ -5468,19 +5467,6 @@ static void igb_io_resume(struct pci_dev *pdev) igb_get_hw_control(adapter); } -static void igb_set_mc_list_pools(struct igb_adapter *adapter, - int entry_count, u16 total_rar_filters) -{ - struct e1000_hw *hw = &adapter->hw; - int i = adapter->vfs_allocated_count + 1; - - if ((i + entry_count) < total_rar_filters) - total_rar_filters = i + entry_count; - - for (; i < total_rar_filters; i++) - igb_set_rah_pool(hw, adapter->vfs_allocated_count, i); -} - static int igb_set_vf_mac(struct igb_adapter *adapter, int vf, unsigned char *mac_addr) { -- cgit v0.10.2 From 5ac1665906559768029c398d9ede8e7cdd73004e Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:09:12 +0000 Subject: igb: cleanup receive address register initialization This update cleans up the receive address register initialization. The main purpose of this is to clean out some redundancy that was introduced due to having multiple ways of setting the receive address registers. Instead of having a specialized function to set one register and one to set all of them it makes more sense to just go through the list calling the function that is needed to set the individual registers. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 5d2c2fb..95360dc 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -765,39 +765,6 @@ static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed, } /** - * igb_init_rx_addrs_82575 - Initialize receive address's - * @hw: pointer to the HW structure - * @rar_count: receive address registers - * - * Setups the receive address registers by setting the base receive address - * register to the devices MAC address and clearing all the other receive - * address registers to 0. - **/ -static void igb_init_rx_addrs_82575(struct e1000_hw *hw, u16 rar_count) -{ - u32 i; - u8 addr[6] = {0,0,0,0,0,0}; - /* - * This function is essentially the same as that of - * e1000_init_rx_addrs_generic. However it also takes care - * of the special case where the register offset of the - * second set of RARs begins elsewhere. This is implicitly taken care by - * function e1000_rar_set_generic. - */ - - hw_dbg("e1000_init_rx_addrs_82575"); - - /* Setup the receive address */ - hw_dbg("Programming MAC Address into RAR[0]\n"); - hw->mac.ops.rar_set(hw, hw->mac.addr, 0); - - /* Zero out the other (rar_entry_count - 1) receive addresses */ - hw_dbg("Clearing RAR[1-%u]\n", rar_count-1); - for (i = 1; i < rar_count; i++) - hw->mac.ops.rar_set(hw, addr, i); -} - -/** * igb_shutdown_fiber_serdes_link_82575 - Remove link during power down * @hw: pointer to the HW structure * @@ -889,7 +856,8 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw) wr32(E1000_IMC, 0xffffffff); icr = rd32(E1000_ICR); - igb_check_alt_mac_addr(hw); + /* Install any alternate MAC address into RAR0 */ + ret_val = igb_check_alt_mac_addr(hw); return ret_val; } @@ -918,7 +886,8 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw) igb_clear_vfta(hw); /* Setup the receive address */ - igb_init_rx_addrs_82575(hw, rar_count); + igb_init_rx_addrs(hw, rar_count); + /* Zero out the Multicast HASH table */ hw_dbg("Zeroing the MTA\n"); for (i = 0; i < mac->mta_reg_count; i++) diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 46e27e9..a1e3da7 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -104,6 +104,31 @@ static void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) } /** + * igb_init_rx_addrs - Initialize receive address's + * @hw: pointer to the HW structure + * @rar_count: receive address registers + * + * Setups the receive address registers by setting the base receive address + * register to the devices MAC address and clearing all the other receive + * address registers to 0. + **/ +void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count) +{ + u32 i; + u8 mac_addr[ETH_ALEN] = {0}; + + /* Setup the receive address */ + hw_dbg("Programming MAC Address into RAR[0]\n"); + + hw->mac.ops.rar_set(hw, hw->mac.addr, 0); + + /* Zero out the other (rar_entry_count - 1) receive addresses */ + hw_dbg("Clearing RAR[1-%u]\n", rar_count-1); + for (i = 1; i < rar_count; i++) + hw->mac.ops.rar_set(hw, mac_addr, i); +} + +/** * igb_vfta_set - enable or disable vlan in VLAN filter table * @hw: pointer to the HW structure * @vid: VLAN id to add or remove diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h index f9ebfb3..7518af8 100644 --- a/drivers/net/igb/e1000_mac.h +++ b/drivers/net/igb/e1000_mac.h @@ -62,6 +62,7 @@ void igb_clear_hw_cntrs_base(struct e1000_hw *hw); void igb_clear_vfta(struct e1000_hw *hw); s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add); void igb_config_collision_dist(struct e1000_hw *hw); +void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); void igb_mta_set(struct e1000_hw *hw, u32 hash_value); void igb_put_hw_semaphore(struct e1000_hw *hw); void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); -- cgit v0.10.2 From 08a72b5dced32889594e08008cca0d0582f2d3d8 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:09:30 +0000 Subject: igb: remove unused switch statement from igb_set_wol There is a switch statement in igb_set_wol that defaults to break and doesn't actually do anything. As such it should be removed. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index a9c37cb..df2d234 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -1836,7 +1836,6 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct igb_adapter *adapter = netdev_priv(netdev); - struct e1000_hw *hw = &adapter->hw; if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) return -EOPNOTSUPP; @@ -1845,11 +1844,6 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) !device_can_wakeup(&adapter->pdev->dev)) return wol->wolopts ? -EOPNOTSUPP : 0; - switch (hw->device_id) { - default: - break; - } - /* these settings will always override what we currently have */ adapter->wol = 0; -- cgit v0.10.2 From 4703bf73bd5b0d43c3eb5b547398d4f62dc5d4e1 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:09:48 +0000 Subject: igb: add support for 82576 mezzanine card This patch adds support for a new 82576 mezzanine adapter. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 95360dc..dbbd72f 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -85,6 +85,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) case E1000_DEV_ID_82576_FIBER: case E1000_DEV_ID_82576_SERDES: case E1000_DEV_ID_82576_QUAD_COPPER: + case E1000_DEV_ID_82576_SERDES_QUAD: mac->type = e1000_82576; break; default: diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 83f9b4f..0469e2e 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -42,6 +42,7 @@ struct e1000_hw; #define E1000_DEV_ID_82576_SERDES 0x10E7 #define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8 #define E1000_DEV_ID_82576_NS 0x150A +#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D #define E1000_DEV_ID_82575EB_COPPER 0x10A7 #define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9 #define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6 diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index e4f4526..2ffb51d 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -65,6 +65,7 @@ static struct pci_device_id igb_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 }, -- cgit v0.10.2 From 2d94d8ab76ea6c858c6e2eb0ab0403b00b031039 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:10:06 +0000 Subject: igb: use buffer_info->dma instead of shinfo->nr_frags to determine unmap This change makes it so that we use buffer_info->dma instead of shinfo->nr_frags to determine if we need to unmap a received skb. By doing this we can avoid a cache miss on small packets since the buffer_info structure should already be prefetched. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 2ffb51d..12d8683 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -4538,6 +4538,20 @@ static inline void igb_rx_checksum_adv(struct igb_adapter *adapter, adapter->hw_csum_good++; } +static inline u16 igb_get_hlen(struct igb_adapter *adapter, + union e1000_adv_rx_desc *rx_desc) +{ + /* HW will not DMA in data larger than the given buffer, even if it + * parses the (NFS, of course) header to be larger. In that case, it + * fills the header buffer and spills the rest into the page. + */ + u16 hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) & + E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT; + if (hlen > adapter->rx_ps_hdr_size) + hlen = adapter->rx_ps_hdr_size; + return hlen; +} + static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, int *work_done, int budget) { @@ -4552,7 +4566,8 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, int cleaned_count = 0; unsigned int total_bytes = 0, total_packets = 0; unsigned int i; - u32 length, hlen, staterr; + u32 staterr; + u16 length; i = rx_ring->next_to_clean; buffer_info = &rx_ring->buffer_info[i]; @@ -4589,17 +4604,8 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, goto send_up; } - /* HW will not DMA in data larger than the given buffer, even - * if it parses the (NFS, of course) header to be larger. In - * that case, it fills the header buffer and spills the rest - * into the page. - */ - hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) & - E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT; - if (hlen > adapter->rx_ps_hdr_size) - hlen = adapter->rx_ps_hdr_size; - - if (!skb_shinfo(skb)->nr_frags) { + if (buffer_info->dma) { + u16 hlen = igb_get_hlen(adapter, rx_desc); pci_unmap_single(pdev, buffer_info->dma, adapter->rx_ps_hdr_size, PCI_DMA_FROMDEVICE); -- cgit v0.10.2 From 0cce119aa977dba00467985c0ae93fe43d28740a Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:10:24 +0000 Subject: igb: cleanup flow control configuration to make requested/current more clear This patch cleans up the flow control configuration for igb to make it a bit more readable in regards to what the requested and current modes are. This should help with the maintainability of the current igb driver in regards to flow control. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 0469e2e..119869b 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -137,7 +137,7 @@ enum e1000_rev_polarity { e1000_rev_polarity_undefined = 0xFF }; -enum e1000_fc_type { +enum e1000_fc_mode { e1000_fc_none = 0, e1000_fc_rx_pause, e1000_fc_tx_pause, @@ -429,8 +429,8 @@ struct e1000_fc_info { u16 pause_time; /* Flow control pause timer */ bool send_xon; /* Flow control send XON */ bool strict_ieee; /* Strict IEEE mode */ - enum e1000_fc_type type; /* Type of flow control */ - enum e1000_fc_type original_type; + enum e1000_fc_mode current_mode; /* Type of flow control */ + enum e1000_fc_mode requested_mode; }; struct e1000_mbx_operations { diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index a1e3da7..a0231cd 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -536,18 +536,24 @@ s32 igb_setup_link(struct e1000_hw *hw) if (igb_check_reset_block(hw)) goto out; - ret_val = igb_set_default_fc(hw); - if (ret_val) - goto out; + /* + * If requested flow control is set to default, set flow control + * based on the EEPROM flow control settings. + */ + if (hw->fc.requested_mode == e1000_fc_default) { + ret_val = igb_set_default_fc(hw); + if (ret_val) + goto out; + } /* * We want to save off the original Flow Control configuration just * in case we get disconnected and then reconnected into a different * hub or switch with different Flow Control capabilities. */ - hw->fc.original_type = hw->fc.type; + hw->fc.current_mode = hw->fc.requested_mode; - hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.type); + hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode); /* Call the necessary media_type subroutine to configure the link. */ ret_val = hw->mac.ops.setup_physical_interface(hw); @@ -614,7 +620,7 @@ static s32 igb_set_fc_watermarks(struct e1000_hw *hw) * ability to transmit pause frames is not enabled, then these * registers will be set to 0. */ - if (hw->fc.type & e1000_fc_tx_pause) { + if (hw->fc.current_mode & e1000_fc_tx_pause) { /* * We need to set up the Receive Threshold high and low water * marks as well as (optionally) enabling the transmission of @@ -661,12 +667,12 @@ static s32 igb_set_default_fc(struct e1000_hw *hw) } if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) - hw->fc.type = e1000_fc_none; + hw->fc.requested_mode = e1000_fc_none; else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == NVM_WORD0F_ASM_DIR) - hw->fc.type = e1000_fc_tx_pause; + hw->fc.requested_mode = e1000_fc_tx_pause; else - hw->fc.type = e1000_fc_full; + hw->fc.requested_mode = e1000_fc_full; out: return ret_val; @@ -696,7 +702,7 @@ s32 igb_force_mac_fc(struct e1000_hw *hw) * receive flow control. * * The "Case" statement below enables/disable flow control - * according to the "hw->fc.type" parameter. + * according to the "hw->fc.current_mode" parameter. * * The possible values of the "fc" parameter are: * 0: Flow control is completely disabled @@ -707,9 +713,9 @@ s32 igb_force_mac_fc(struct e1000_hw *hw) * 3: Both Rx and TX flow control (symmetric) is enabled. * other: No other values should be possible at this point. */ - hw_dbg("hw->fc.type = %u\n", hw->fc.type); + hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode); - switch (hw->fc.type) { + switch (hw->fc.current_mode) { case e1000_fc_none: ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); break; @@ -857,11 +863,11 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) * ONLY. Hence, we must now check to see if we need to * turn OFF the TRANSMISSION of PAUSE frames. */ - if (hw->fc.original_type == e1000_fc_full) { - hw->fc.type = e1000_fc_full; + if (hw->fc.requested_mode == e1000_fc_full) { + hw->fc.current_mode = e1000_fc_full; hw_dbg("Flow Control = FULL.\r\n"); } else { - hw->fc.type = e1000_fc_rx_pause; + hw->fc.current_mode = e1000_fc_rx_pause; hw_dbg("Flow Control = " "RX PAUSE frames only.\r\n"); } @@ -878,7 +884,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.type = e1000_fc_tx_pause; + hw->fc.current_mode = e1000_fc_tx_pause; hw_dbg("Flow Control = TX PAUSE frames only.\r\n"); } /* @@ -893,7 +899,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.type = e1000_fc_rx_pause; + hw->fc.current_mode = e1000_fc_rx_pause; hw_dbg("Flow Control = RX PAUSE frames only.\r\n"); } /* @@ -917,13 +923,13 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) * be asked to delay transmission of packets than asking * our link partner to pause transmission of frames. */ - else if ((hw->fc.original_type == e1000_fc_none || - hw->fc.original_type == e1000_fc_tx_pause) || + else if ((hw->fc.requested_mode == e1000_fc_none || + hw->fc.requested_mode == e1000_fc_tx_pause) || hw->fc.strict_ieee) { - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; hw_dbg("Flow Control = NONE.\r\n"); } else { - hw->fc.type = e1000_fc_rx_pause; + hw->fc.current_mode = e1000_fc_rx_pause; hw_dbg("Flow Control = RX PAUSE frames only.\r\n"); } @@ -939,7 +945,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) } if (duplex == HALF_DUPLEX) - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; /* * Now we call a subroutine to actually force the MAC diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c index f50fac2..c1f4da6 100644 --- a/drivers/net/igb/e1000_phy.c +++ b/drivers/net/igb/e1000_phy.c @@ -735,7 +735,7 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw) * other: No software override. The flow control configuration * in the EEPROM is used. */ - switch (hw->fc.type) { + switch (hw->fc.current_mode) { case e1000_fc_none: /* * Flow control (RX & TX) is completely disabled by a @@ -992,7 +992,7 @@ static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, u32 ctrl; /* Turn off flow control when forcing speed/duplex */ - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; /* Force speed/duplex on the mac */ ctrl = rd32(E1000_CTRL); diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index df2d234..114ccab 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -194,6 +194,8 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ADVERTISED_TP | ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; + if (adapter->fc_autoneg) + hw->fc.requested_mode = e1000_fc_default; } else { if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { clear_bit(__IGB_RESETTING, &adapter->state); @@ -221,11 +223,11 @@ static void igb_get_pauseparam(struct net_device *netdev, pause->autoneg = (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); - if (hw->fc.type == e1000_fc_rx_pause) + if (hw->fc.current_mode == e1000_fc_rx_pause) pause->rx_pause = 1; - else if (hw->fc.type == e1000_fc_tx_pause) + else if (hw->fc.current_mode == e1000_fc_tx_pause) pause->tx_pause = 1; - else if (hw->fc.type == e1000_fc_full) { + else if (hw->fc.current_mode == e1000_fc_full) { pause->rx_pause = 1; pause->tx_pause = 1; } @@ -243,26 +245,28 @@ static int igb_set_pauseparam(struct net_device *netdev, while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) msleep(1); - if (pause->rx_pause && pause->tx_pause) - hw->fc.type = e1000_fc_full; - else if (pause->rx_pause && !pause->tx_pause) - hw->fc.type = e1000_fc_rx_pause; - else if (!pause->rx_pause && pause->tx_pause) - hw->fc.type = e1000_fc_tx_pause; - else if (!pause->rx_pause && !pause->tx_pause) - hw->fc.type = e1000_fc_none; - - hw->fc.original_type = hw->fc.type; - if (adapter->fc_autoneg == AUTONEG_ENABLE) { + hw->fc.requested_mode = e1000_fc_default; if (netif_running(adapter->netdev)) { igb_down(adapter); igb_up(adapter); } else igb_reset(adapter); - } else + } else { + if (pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = e1000_fc_full; + else if (pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = e1000_fc_rx_pause; + else if (!pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = e1000_fc_tx_pause; + else if (!pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = e1000_fc_none; + + hw->fc.current_mode = hw->fc.requested_mode; + retval = ((hw->phy.media_type == e1000_media_type_copper) ? igb_force_mac_fc(hw) : igb_setup_link(hw)); + } clear_bit(__IGB_RESETTING, &adapter->state); return retval; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 12d8683..fb32735 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1130,7 +1130,7 @@ void igb_reset(struct igb_adapter *adapter) } fc->pause_time = 0xFFFF; fc->send_xon = 1; - fc->type = fc->original_type; + fc->current_mode = fc->requested_mode; /* disable receive for all VFs and wait one second */ if (adapter->vfs_allocated_count) { @@ -1427,8 +1427,8 @@ static int __devinit igb_probe(struct pci_dev *pdev, hw->mac.autoneg = true; hw->phy.autoneg_advertised = 0x2f; - hw->fc.original_type = e1000_fc_default; - hw->fc.type = e1000_fc_default; + hw->fc.requested_mode = e1000_fc_default; + hw->fc.current_mode = e1000_fc_default; adapter->itr_setting = IGB_DEFAULT_ITR; adapter->itr = IGB_START_ITR; -- cgit v0.10.2 From a0c98605d7237fc4bf26a345db5f950f46e69834 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:10:43 +0000 Subject: igb: initialize mailbox function pointers prior to phy init The igb driver is currently initializing the mailbox function pointers after the phy. This causes issues as the phy init will return from the function early if there is no phy present. To resolve this I have moved the function pointer init to a location prior to the phy initialization so that serdes based adapters can also make use of SR-IOV. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index dbbd72f..6158c0f 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -172,6 +172,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) size = 14; nvm->word_size = 1 << size; + /* if 82576 then initialize mailbox parameters */ + if (mac->type == e1000_82576) + igb_init_mbx_params_pf(hw); + /* setup PHY parameters */ if (phy->media_type != e1000_media_type_copper) { phy->type = e1000_phy_none; @@ -221,10 +225,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) return -E1000_ERR_PHY; } - /* if 82576 then initialize mailbox parameters */ - if (mac->type == e1000_82576) - igb_init_mbx_params_pf(hw); - return 0; } -- cgit v0.10.2 From 92d947b77436437f4fe6f9b7b7cd35f1a294fa9d Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:11:01 +0000 Subject: igbvf: resolve "frees DMA memory with different size" warnings This change resolves some warnings seen with DMA debugging enabled in which we were mapping skb->data with size + NET_IP_ALIGN and unmapping it with just size. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 2bc9d63..926c31b 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -149,7 +149,6 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring, bufsz = adapter->rx_ps_hdr_size; else bufsz = adapter->rx_buffer_len; - bufsz += NET_IP_ALIGN; while (cleaned_count--) { rx_desc = IGBVF_RX_DESC_ADV(*rx_ring, i); @@ -173,7 +172,7 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring, } if (!buffer_info->skb) { - skb = netdev_alloc_skb(netdev, bufsz); + skb = netdev_alloc_skb(netdev, bufsz + NET_IP_ALIGN); if (!skb) { adapter->alloc_rx_buff_failed++; goto no_buffers; @@ -286,7 +285,7 @@ static bool igbvf_clean_rx_irq(struct igbvf_adapter *adapter, if (!skb_shinfo(skb)->nr_frags) { pci_unmap_single(pdev, buffer_info->dma, - adapter->rx_ps_hdr_size + NET_IP_ALIGN, + adapter->rx_ps_hdr_size, PCI_DMA_FROMDEVICE); skb_put(skb, hlen); } -- cgit v0.10.2 From 421d20a3dccb3670d4b2e8d3e4cef6327530f30d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 26 Jul 2009 13:39:10 -0700 Subject: phonet: Fix build. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As reported by Oliver Hartkopp: net/phonet/pn_dev.c: In function ‘phonet_init_net’: net/phonet/pn_dev.c:221: error: implicit declaration of function ‘proc_net_fops_create’ net/phonet/pn_dev.c: In function ‘phonet_exit_net’: net/phonet/pn_dev.c:242: error: implicit declaration of function ‘proc_net_remove’ Signed-off-by: David S. Miller diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 5107b79..6b30cc1 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From c409c34bc472cc62da6c619acf786120b56c2dc2 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Tue, 21 Jul 2009 14:51:20 +0000 Subject: sky2: remove unnecessary assignment Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3550c5d..661abd0 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -4117,7 +4117,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v) seq_printf(seq, "\nRx ring hw get=%d put=%d last=%d\n", sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_GET_IDX)), - last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)), + sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)), sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX))); sky2_read32(hw, B0_Y2_SP_LISR); -- cgit v0.10.2 From b5eb0589937eae2d58fca17fa45ed44152e772ed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Jul 2009 05:23:23 +0000 Subject: net: deprecate print_mac We've had %pM for long enough now, time to deprecate print_mac() and remove the __maybe_unused attribute from DECLARE_MAC_BUF so that variables declared with that can be found and removed. Otherwise people are putting in new users of print_mac(). Signed-off-by: Johannes Berg Signed-off-by: David S. Miller diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 70fdba2..580b600 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -139,10 +139,10 @@ extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len); /* * Display a 6 byte device address (MAC) in a readable format. */ -extern char *print_mac(char *buf, const unsigned char *addr); +extern char *print_mac(char *buf, const unsigned char *addr) __deprecated; #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" #define MAC_BUF_SIZE 18 -#define DECLARE_MAC_BUF(var) char var[MAC_BUF_SIZE] __maybe_unused +#define DECLARE_MAC_BUF(var) char var[MAC_BUF_SIZE] #endif -- cgit v0.10.2 From 7d073c68a49b23b5ba2bc23c3bb5b3bcaa0b4f20 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 23 Jul 2009 21:21:19 +0000 Subject: bnx2x: Dont update vlan_features in bnx2x_set_tso() Patrick said : "vlan_features doesn't need to be updated, the resulting dev->features of the VLAN device is computed as the intersection of dev->features and dev->vlan_features." Signed-off-by: Eric Dumazet Acked-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index c4c42b3..a2de0cd 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -9349,17 +9349,9 @@ static int bnx2x_set_tso(struct net_device *dev, u32 data) if (data) { dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); dev->features |= NETIF_F_TSO6; -#ifdef BCM_VLAN - dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->vlan_features |= NETIF_F_TSO6; -#endif } else { dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); dev->features &= ~NETIF_F_TSO6; -#ifdef BCM_VLAN - dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->vlan_features &= ~NETIF_F_TSO6; -#endif } return 0; -- cgit v0.10.2 From 1896e61ff7cc1c9dd0d8b1cf4a9426a0f7217a20 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Wed, 22 Jul 2009 13:38:22 +0000 Subject: ethtool: device independent rx_csum and get_flags routines This helps avoid error messages with ethtool -k on devices that don't provide device specific routines. Signed-off-by: Sridhar Samudrala ------------------------------------------------------------------ Signed-off-by: David S. Miller diff --git a/net/core/ethtool.c b/net/core/ethtool.c index d9d5160..cf36ff4 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -30,6 +30,11 @@ u32 ethtool_op_get_link(struct net_device *dev) return netif_carrier_ok(dev) ? 1 : 0; } +u32 ethtool_op_get_rx_csum(struct net_device *dev) +{ + return (dev->features & NETIF_F_ALL_CSUM) != 0; +} + u32 ethtool_op_get_tx_csum(struct net_device *dev) { return (dev->features & NETIF_F_ALL_CSUM) != 0; @@ -1004,7 +1009,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) break; case ETHTOOL_GRXCSUM: rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_rx_csum); + (dev->ethtool_ops->get_rx_csum ? + dev->ethtool_ops->get_rx_csum : + ethtool_op_get_rx_csum)); break; case ETHTOOL_SRXCSUM: rc = ethtool_set_rx_csum(dev, useraddr); @@ -1068,7 +1075,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) break; case ETHTOOL_GFLAGS: rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_flags); + (dev->ethtool_ops->get_flags ? + dev->ethtool_ops->get_flags : + ethtool_op_get_flags)); break; case ETHTOOL_SFLAGS: rc = ethtool_set_value(dev, useraddr, -- cgit v0.10.2 From 51def0bea92629dff02ff1de40603eb90c609c55 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 22 Jul 2009 14:06:56 +0000 Subject: imwc3200: move iwmc3200 SDIO ids to sdio_ids.h 1. add intel's sdio vendor id to sdio_ids.h 2. move iwmc3200 sdio devices' ids to sdio_ids.h Signed-off-by: Tomas Winkler Signed-off-by: David S. Miller diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 2538825..ea7b290 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -58,6 +58,7 @@ */ #include +#include #include #include #include "i2400m-sdio.h" @@ -501,15 +502,12 @@ void i2400ms_remove(struct sdio_func *func) d_fnend(3, dev, "SDIO func %p\n", func); } -enum { - I2400MS_INTEL_VID = 0x89, -}; - static const struct sdio_device_id i2400ms_sdio_ids[] = { - /* Intel: i2400m WiMAX over SDIO */ - { SDIO_DEVICE(I2400MS_INTEL_VID, 0x1402) }, - { }, /* end: all zeroes */ + /* Intel: i2400m WiMAX (iwmc3200) over SDIO */ + { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, + SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX) }, + { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, i2400ms_sdio_ids); diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index b93f620..8b1de84 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -492,7 +493,8 @@ static void iwm_sdio_remove(struct sdio_func *func) } static const struct sdio_device_id iwm_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, + SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) }, { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h index b3c156b..aab6b68 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.h +++ b/drivers/net/wireless/iwmc3200wifi/sdio.h @@ -39,9 +39,6 @@ #ifndef __IWM_SDIO_H__ #define __IWM_SDIO_H__ -#define SDIO_VENDOR_ID_INTEL 0x89 -#define SDIO_DEVICE_ID_IWM 0x1403 - #define IWM_SDIO_DATA_ADDR 0x0 #define IWM_SDIO_INTR_ENABLE_ADDR 0x14 #define IWM_SDIO_INTR_STATUS_ADDR 0x13 diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 39751c8..2dbfb5a 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -22,6 +22,12 @@ /* * Vendors and devices. Sort key: vendor first, device next. */ +#define SDIO_VENDOR_ID_INTEL 0x0089 +#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402 +#define SDIO_DEVICE_ID_INTEL_IWMC3200WIFI 0x1403 +#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404 +#define SDIO_DEVICE_ID_INTEL_IWMC3200GPS 0x1405 +#define SDIO_DEVICE_ID_INTEL_IWMC3200BT 0x1406 #define SDIO_VENDOR_ID_MARVELL 0x02df #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103 -- cgit v0.10.2 From 72dccb01e8632aa5ffe58070003d0fa19d007116 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 23 Jul 2009 02:01:38 +0000 Subject: bnx2: Update vlan_features [PATCH net-next-2.6] bnx2: Update vlan_features In order to get full use of some advanced features of BNX2, we now need to fill dev->vlan_features. Patch successfully tested with vlan devices built on top of bonding. (bond0 : one bnx2 slave, one tg3 slave (not yet vlan_features enabled) Signed-off-by: Eric Dumazet Acked-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index b70cc99..cec1b17 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -8023,6 +8023,13 @@ static const struct net_device_ops bnx2_netdev_ops = { #endif }; +static void inline vlan_features_add(struct net_device *dev, unsigned long flags) +{ +#ifdef BCM_VLAN + dev->vlan_features |= flags; +#endif +} + static int __devinit bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -8064,16 +8071,20 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) memcpy(dev->perm_addr, bp->mac_addr, 6); dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - if (CHIP_NUM(bp) == CHIP_NUM_5709) + vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG); + if (CHIP_NUM(bp) == CHIP_NUM_5709) { dev->features |= NETIF_F_IPV6_CSUM; - + vlan_features_add(dev, NETIF_F_IPV6_CSUM); + } #ifdef BCM_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; #endif dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - if (CHIP_NUM(bp) == CHIP_NUM_5709) + vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN); + if (CHIP_NUM(bp) == CHIP_NUM_5709) { dev->features |= NETIF_F_TSO6; - + vlan_features_add(dev, NETIF_F_TSO6); + } if ((rc = register_netdev(dev))) { dev_err(&pdev->dev, "Cannot register net device\n"); goto error; -- cgit v0.10.2 From a22d543a95e82e5ad0ee1a44aad54fd6b6bf52a8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 27 Jul 2009 12:54:26 +0200 Subject: ALSA: hda - Introduce get_wcaps_type() macro Add a helper macro to retrieve the widget type from wiget cap bits. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index aa55407..b8c656c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -748,8 +748,7 @@ static int read_pin_defaults(struct hda_codec *codec) for (i = 0; i < codec->num_nodes; i++, nid++) { struct hda_pincfg *pin; unsigned int wcaps = get_wcaps(codec, nid); - unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> - AC_WCAP_TYPE_SHIFT; + unsigned int wid_type = get_wcaps_type(wcaps); if (wid_type != AC_WID_PIN) continue; pin = snd_array_new(&codec->init_pins); @@ -2386,8 +2385,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, for (i = 0; i < codec->num_nodes; i++, nid++) { unsigned int wcaps = get_wcaps(codec, nid); if (wcaps & AC_WCAP_POWER) { - unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> - AC_WCAP_TYPE_SHIFT; + unsigned int wid_type = get_wcaps_type(wcaps); if (power_state == AC_PWRST_D3 && wid_type == AC_WID_PIN) { unsigned int pincap; @@ -3678,8 +3676,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, end_nid = codec->start_nid + codec->num_nodes; for (nid = codec->start_nid; nid < end_nid; nid++) { unsigned int wid_caps = get_wcaps(codec, nid); - unsigned int wid_type = - (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + unsigned int wid_type = get_wcaps_type(wid_caps); unsigned int def_conf; short assoc, loc; diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index bccb62a..b36f6c5 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -122,7 +122,7 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid return -ENOMEM; node->nid = nid; node->wid_caps = get_wcaps(codec, nid); - node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + node->type = get_wcaps_type(node->wid_caps); if (node->wid_caps & AC_WCAP_CONN_LIST) { nconns = snd_hda_get_connections(codec, nid, conn_list, HDA_MAX_CONNECTIONS); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 75aa378..fa57cb9 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -407,6 +407,9 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) return codec->wcaps[nid - codec->start_nid]; } +/* get the widget type from widget capability bits */ +#define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT) + u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 418c5d1..a721eb0 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -508,8 +508,7 @@ static void print_codec_info(struct snd_info_entry *entry, unsigned int wid_caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); - unsigned int wid_type = - (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + unsigned int wid_type = get_wcaps_type(wid_caps); hda_nid_t conn[HDA_MAX_CONNECTIONS]; int conn_len = 0; diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index 019ca7c..d08353d 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -459,8 +459,7 @@ static void parse_input(struct hda_codec *codec) nid = codec->start_nid; for (i = 0; i < codec->num_nodes; i++, nid++) { unsigned int wcaps = get_wcaps(codec, nid); - unsigned int type = (wcaps & AC_WCAP_TYPE) >> - AC_WCAP_TYPE_SHIFT; + unsigned int type = get_wcaps_type(wcaps); if (type != AC_WID_AUD_IN) continue; if (snd_hda_get_connections(codec, nid, &pin, 1) != 1) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e1563f4..df87c01 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -415,7 +415,7 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; imux = &spec->input_mux[mux_idx]; - type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_AUD_MIX) { /* Matrix-mixer style (e.g. ALC882) */ unsigned int *cur_val = &spec->cur_mux[adc_idx]; @@ -4623,7 +4623,7 @@ static int patch_alc880(struct hda_codec *codec) /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]); /* get type */ - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + wcap = get_wcaps_type(wcap); if (wcap != AC_WID_AUD_IN) { spec->adc_nids = alc880_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); @@ -6266,7 +6266,7 @@ static int patch_alc260(struct hda_codec *codec) if (!spec->adc_nids && spec->input_mux) { /* check whether NID 0x04 is valid */ unsigned int wcap = get_wcaps(codec, 0x04); - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + wcap = get_wcaps_type(wcap); /* get type */ if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { spec->adc_nids = alc260_adc_nids_alt; @@ -9460,7 +9460,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec) 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; + wcap = get_wcaps_type(wcap); if (wcap == AC_WID_AUD_IN) add_verb(spec, alc882_adc1_init_verbs); @@ -9577,7 +9577,7 @@ static int patch_alc882(struct hda_codec *codec) 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; + wcap = get_wcaps_type(wcap); if (wcap != AC_WID_AUD_IN) continue; spec->private_adc_nids[spec->num_adc_nids] = nid; @@ -11460,7 +11460,7 @@ static int patch_alc262(struct hda_codec *codec) unsigned int wcap = get_wcaps(codec, 0x07); /* get type */ - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + wcap = get_wcaps_type(wcap); if (wcap != AC_WID_AUD_IN) { spec->adc_nids = alc262_adc_nids_alt; spec->num_adc_nids = @@ -12536,7 +12536,7 @@ static int patch_alc268(struct hda_codec *codec) int i; /* get type */ - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + wcap = get_wcaps_type(wcap); if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { spec->adc_nids = alc268_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt); @@ -13991,8 +13991,7 @@ static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin) return 0; for (i = 0; i < num; i++) { unsigned int type; - type = (get_wcaps(codec, srcs[i]) & AC_WCAP_TYPE) - >> AC_WCAP_TYPE_SHIFT; + type = get_wcaps_type(get_wcaps(codec, srcs[i])); if (type != AC_WID_AUD_OUT) continue; for (j = 0; j < spec->multiout.num_dacs; j++) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 8c48f86..9de97f3 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3058,7 +3058,7 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid) HDA_MAX_CONNECTIONS); for (j = 0; j < conn_len; j++) { wcaps = get_wcaps(codec, conn[j]); - wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + wtype = get_wcaps_type(wcaps); /* we check only analog outputs */ if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL)) continue; @@ -3746,8 +3746,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out conn_list, 1) > 0) { int wcaps = get_wcaps(codec, conn_list[0]); - int wid_type = (wcaps & AC_WCAP_TYPE) - >> AC_WCAP_TYPE_SHIFT; + int wid_type = get_wcaps_type(wcaps); /* LR swap check, some stac925x have a mux that * changes the DACs output path instead of the * mono-mux path. @@ -4753,8 +4752,7 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) nid = codec->start_nid; for (i = 0; i < codec->num_nodes; i++, nid++) { unsigned int wcaps = get_wcaps(codec, nid); - unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> - AC_WCAP_TYPE_SHIFT; + unsigned int wid_type = get_wcaps_type(wcaps); if (wid_type == AC_WID_PIN) snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 9008b4b..ab90abb 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1339,8 +1339,7 @@ static int get_mux_nids(struct hda_codec *codec) for (i = 0; i < spec->num_adc_nids; i++) { nid = spec->adc_nids[i]; while (nid) { - type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) - >> AC_WCAP_TYPE_SHIFT; + type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_PIN) break; n = snd_hda_get_connections(codec, nid, conn, -- cgit v0.10.2 From 1ba7a7c650bd8ee567e25d9b68e9081d131c70f6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 27 Jul 2009 12:56:26 +0200 Subject: ALSA: hda - Add exception for volume-knob in snd_hda_get_connections() Volume-knob widgets may have connections even if they have no CONN_LIST cap bit. Allow the query exceptionally in snd_hda_get_connections(). Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index b8c656c..3a603cd 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -301,12 +301,15 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, unsigned int parm; int i, conn_len, conns; unsigned int shift, num_elems, mask; + unsigned int wcaps; hda_nid_t prev_nid; if (snd_BUG_ON(!conn_list || max_conns <= 0)) return -EINVAL; - if ((get_wcaps(codec, nid) & AC_WCAP_CONN_LIST) == 0) { + wcaps = get_wcaps(codec, nid); + if (!(wcaps & AC_WCAP_CONN_LIST) && + get_wcaps_type(wcaps) != AC_WID_VOL_KNB) { snd_printk(KERN_WARNING "hda_codec: " "connection list not available for 0x%x\n", nid); return -EINVAL; -- cgit v0.10.2 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 diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index 1634c6dc..50189bf 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 a0280ad..1d4ed66 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 v0.10.2 From 59e57f4417507b1e71f6e5af3eb7e68e6477ac94 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 27 Jul 2009 08:03:18 -0700 Subject: phonet: phonet_device_get() fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/phonet/pn_dev.c: In function `phonet_device_get': net/phonet/pn_dev.c:99: warning: 'dev' might be used uninitialized in this function Signed-off-by: Eric Dumazet Acked-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 6b30cc1..5ae4c01 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -97,7 +97,7 @@ struct net_device *phonet_device_get(struct net *net) { struct phonet_device_list *pndevs = phonet_device_list(net); struct phonet_device *pnd; - struct net_device *dev; + struct net_device *dev = NULL; spin_lock_bh(&pndevs->lock); list_for_each_entry(pnd, &pndevs->list, list) { -- cgit v0.10.2 From 70034918930d2e5b68c09bced637228c50d9561a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 27 Jul 2009 08:05:52 -0700 Subject: net: fix multiple definitions of setup_w6692 Signed-off-by: Stephen Rothwell Acked-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 1b9008f..d3f1077 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -1234,7 +1234,7 @@ w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) return err; } -int +static int setup_w6692(struct w6692_hw *card) { u32 val; -- cgit v0.10.2 From 663a31ce5bbef2d14fa325023e48bf02b4249f27 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Mon, 27 Jul 2009 08:20:55 -0700 Subject: mISDN: Fix wrong struct name in macro and clarifications Based on comments from Joe Perches . Thanks. Fix IOFUNC_MEMIO macro. WriteFiFo##name##_MIO use the wrong struct name, this was missed because the macro was only called with this name. Clarify with _func that the defined types are functions. Add names to the parameters for better understanding the purpose. Signed-off-by: Karsten Keil Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/iohelper.h b/drivers/isdn/hardware/mISDN/iohelper.h index c16a217..b438981 100644 --- a/drivers/isdn/hardware/mISDN/iohelper.h +++ b/drivers/isdn/hardware/mISDN/iohelper.h @@ -26,9 +26,9 @@ #ifndef _IOHELPER_H #define _IOHELPER_H -typedef u8 (read_reg_t)(void *, u8); -typedef void (write_reg_t)(void *, u8, u8); -typedef void (fifo_func_t)(void *, u8, u8 *, int); +typedef u8 (read_reg_func)(void *hwp, u8 offset); +typedef void (write_reg_func)(void *hwp, u8 offset, u8 value); +typedef void (fifo_func)(void *hwp, u8 offset, u8 *datap, int size); struct _ioport { u32 port; @@ -90,7 +90,7 @@ struct _ioport { *dp++ = readb(((typ *)hw->adr) + off);\ } \ static void WriteFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\ - struct inf_hw *hw = p;\ + struct hws *hw = p;\ while (size--)\ writeb(*dp++, ((typ *)hw->adr) + off);\ } @@ -106,4 +106,4 @@ struct _ioport { ASSIGN_FUNC(typ, IPAC, target);\ } while (0) -#endif \ No newline at end of file +#endif diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h index f9601d5..74a6ccf 100644 --- a/drivers/isdn/hardware/mISDN/ipac.h +++ b/drivers/isdn/hardware/mISDN/ipac.h @@ -30,10 +30,10 @@ struct isac_hw { u32 off; /* offset to isac regs */ char *name; spinlock_t *hwlock; /* lock HW acccess */ - read_reg_t *read_reg; - write_reg_t *write_reg; - fifo_func_t *read_fifo; - fifo_func_t *write_fifo; + read_reg_func *read_reg; + write_reg_func *write_reg; + fifo_func *read_fifo; + fifo_func *write_fifo; int (*monitor)(void *, u32, u8 *, int); void (*release)(struct isac_hw *); int (*init)(struct isac_hw *); @@ -73,10 +73,10 @@ struct ipac_hw { spinlock_t *hwlock; /* lock HW acccess */ struct module *owner; u32 type; - read_reg_t *read_reg; - write_reg_t *write_reg; - fifo_func_t *read_fifo; - fifo_func_t *write_fifo; + read_reg_func *read_reg; + write_reg_func *write_reg; + fifo_func *read_fifo; + fifo_func *write_fifo; void (*release)(struct ipac_hw *); int (*init)(struct ipac_hw *); int (*ctrl)(struct ipac_hw *, u32, u_long); diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h index 092351a..4a134ac 100644 --- a/drivers/isdn/hardware/mISDN/isar.h +++ b/drivers/isdn/hardware/mISDN/isar.h @@ -47,10 +47,10 @@ struct isar_hw { spinlock_t *hwlock; /* lock HW acccess */ char *name; struct module *owner; - read_reg_t *read_reg; - write_reg_t *write_reg; - fifo_func_t *read_fifo; - fifo_func_t *write_fifo; + read_reg_func *read_reg; + write_reg_func *write_reg; + fifo_func *read_fifo; + fifo_func *write_fifo; int (*ctrl)(void *, u32, u_long); void (*release)(struct isar_hw *); int (*init)(struct isar_hw *); -- cgit v0.10.2 From 68b3cae0824b98d1f469a80cc65dcaab81771f45 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:36 +0000 Subject: netxen: refresh firmware info after reset o move dma mask update to netxen_start_firmware() so that if firmware changes across suspend (e.g. file -> flash) it reflects right dma mask. o re-read firmware capabilities after firmware reset. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index b9123d4..3c614c3 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -2047,6 +2047,9 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) dev_info(&pdev->dev, "firmware running in %s mode\n", adapter->ahw.cut_through ? "cut-through" : "legacy"); } + + if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) + adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); } int diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 5d3343e..847f78b 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1083,10 +1083,6 @@ int netxen_init_firmware(struct netxen_adapter *adapter) NXWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE); NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); - if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) { - adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); - } - return err; } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 637ac8b..4c7e4c2 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -764,6 +764,10 @@ wait_init: return err; } + nx_update_dma_mask(adapter); + + netxen_nic_get_firmware_info(adapter); + return 0; } @@ -1071,11 +1075,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = netxen_start_firmware(adapter, 1); if (err) goto err_out_iounmap; - - nx_update_dma_mask(adapter); - - netxen_nic_get_firmware_info(adapter); - /* * See if the firmware gave us a virtual-physical port mapping. */ -- cgit v0.10.2 From 6598b169b856793f8f9b80a3f3c5a48f5eaf40e3 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:37 +0000 Subject: netxen: enable ip addr hashing NX3031 hardware requires local IP addresses for packet accumulation (LRO). IP address hashing is required to distinguish a local TCP flow from others (forwarded or guest). This patch adds listener for IP and netdev events and configures IP address in the firmware. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index f86e050..6b9e759 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -380,6 +380,7 @@ struct rcv_desc { }; /* opcode field in status_desc */ +#define NETXEN_NIC_SYN_OFFLOAD 0x03 #define NETXEN_NIC_RXPKT_DESC 0x04 #define NETXEN_OLD_RXPKT_DESC 0x3f #define NETXEN_NIC_RESPONSE_DESC 0x05 @@ -1078,6 +1079,9 @@ typedef struct { #define NX_MAC_EVENT 0x1 +#define NX_IP_UP 2 +#define NX_IP_DOWN 3 + /* * Driver --> Firmware */ @@ -1443,6 +1447,7 @@ void netxen_p3_free_mac_list(struct netxen_adapter *adapter); int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32); int netxen_config_intr_coalesce(struct netxen_adapter *adapter); int netxen_config_rss(struct netxen_adapter *adapter, int enable); +int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd); int netxen_linkevent_request(struct netxen_adapter *adapter, int enable); void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup); diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 3c614c3..088611b 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -706,6 +706,30 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable) return rv; } +int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd) +{ + nx_nic_req_t req; + u64 word; + int rv; + + memset(&req, 0, sizeof(nx_nic_req_t)); + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); + + word = NX_NIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(cmd); + req.words[1] = cpu_to_le64(ip); + + rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) { + printk(KERN_ERR "%s: could not notify %s IP 0x%x reuqest\n", + adapter->netdev->name, + (cmd == NX_IP_UP) ? "Add" : "Remove", ip); + } + return rv; +} + int netxen_linkevent_request(struct netxen_adapter *adapter, int enable) { nx_nic_req_t req; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 847f78b..5d7a2c4 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -880,22 +880,10 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname) return 0; } -void netxen_request_firmware(struct netxen_adapter *adapter) +static int +netxen_p3_has_mn(struct netxen_adapter *adapter) { u32 capability, flashed_ver; - u8 fw_type; - struct pci_dev *pdev = adapter->pdev; - int rc = 0; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - fw_type = NX_P2_MN_ROMIMAGE; - goto request_fw; - } else { - fw_type = NX_P3_CT_ROMIMAGE; - goto request_fw; - } - -request_mn: capability = 0; netxen_rom_fast_read(adapter, @@ -903,23 +891,35 @@ request_mn: flashed_ver = NETXEN_DECODE_VERSION(flashed_ver); if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) { + capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY); - if (capability & NX_PEG_TUNE_MN_PRESENT) { - fw_type = NX_P3_MN_ROMIMAGE; - goto request_fw; - } + if (capability & NX_PEG_TUNE_MN_PRESENT) + return 1; + } + return 0; +} + +void netxen_request_firmware(struct netxen_adapter *adapter) +{ + u8 fw_type; + struct pci_dev *pdev = adapter->pdev; + int rc = 0; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + fw_type = NX_P2_MN_ROMIMAGE; + goto request_fw; } - fw_type = NX_FLASH_ROMIMAGE; - adapter->fw = NULL; - goto done; + fw_type = netxen_p3_has_mn(adapter) ? + NX_P3_MN_ROMIMAGE : NX_P3_CT_ROMIMAGE; request_fw: rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev); if (rc != 0) { - if (fw_type == NX_P3_CT_ROMIMAGE) { + if (fw_type == NX_P3_MN_ROMIMAGE) { msleep(1); - goto request_mn; + fw_type = NX_P3_CT_ROMIMAGE; + goto request_fw; } fw_type = NX_FLASH_ROMIMAGE; @@ -931,9 +931,10 @@ request_fw: if (rc != 0) { release_firmware(adapter->fw); - if (fw_type == NX_P3_CT_ROMIMAGE) { + if (fw_type == NX_P3_MN_ROMIMAGE) { msleep(1); - goto request_mn; + fw_type = NX_P3_CT_ROMIMAGE; + goto request_fw; } fw_type = NX_FLASH_ROMIMAGE; @@ -1292,6 +1293,7 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) switch (opcode) { case NETXEN_NIC_RXPKT_DESC: case NETXEN_OLD_RXPKT_DESC: + case NETXEN_NIC_SYN_OFFLOAD: break; case NETXEN_NIC_RESPONSE_DESC: netxen_handle_fw_message(desc_cnt, consumer, sds_ring); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 4c7e4c2..b368326 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -39,6 +39,7 @@ #include #include #include +#include MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver"); MODULE_LICENSE("GPL"); @@ -1780,6 +1781,125 @@ static void netxen_nic_poll_controller(struct net_device *netdev) } #endif +#define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops) + +static int +netxen_destip_supported(struct netxen_adapter *adapter) +{ + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + return 0; + + if (adapter->ahw.cut_through) + return 0; + + return 1; +} + +static int netxen_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct netxen_adapter *adapter; + struct net_device *dev = (struct net_device *)ptr; + struct in_device *indev; + +recheck: + if (dev == NULL) + goto done; + + if (dev->priv_flags & IFF_802_1Q_VLAN) { + dev = vlan_dev_real_dev(dev); + goto recheck; + } + + if (!is_netxen_netdev(dev)) + goto done; + + adapter = netdev_priv(dev); + + if (!adapter || !netxen_destip_supported(adapter)) + goto done; + + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + goto done; + + indev = in_dev_get(dev); + if (!indev) + goto done; + + for_ifa(indev) { + switch (event) { + case NETDEV_UP: + netxen_config_ipaddr(adapter, + ifa->ifa_address, NX_IP_UP); + break; + case NETDEV_DOWN: + netxen_config_ipaddr(adapter, + ifa->ifa_address, NX_IP_DOWN); + break; + default: + break; + } + } endfor_ifa(indev); + + in_dev_put(indev); +done: + return NOTIFY_DONE; +} + +static int +netxen_inetaddr_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct netxen_adapter *adapter; + struct net_device *dev; + + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + + dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL; + +recheck: + if (dev == NULL || !netif_running(dev)) + goto done; + + if (dev->priv_flags & IFF_802_1Q_VLAN) { + dev = vlan_dev_real_dev(dev); + goto recheck; + } + + if (!is_netxen_netdev(dev)) + goto done; + + adapter = netdev_priv(dev); + + if (!adapter || !netxen_destip_supported(adapter)) + goto done; + + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + goto done; + + switch (event) { + case NETDEV_UP: + netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP); + break; + case NETDEV_DOWN: + netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_DOWN); + break; + default: + break; + } + +done: + return NOTIFY_DONE; +} + +static struct notifier_block netxen_netdev_cb = { + .notifier_call = netxen_netdev_event, +}; + +static struct notifier_block netxen_inetaddr_cb = { + .notifier_call = netxen_inetaddr_event, +}; + static struct pci_driver netxen_driver = { .name = netxen_nic_driver_name, .id_table = netxen_pci_tbl, @@ -1800,6 +1920,9 @@ static int __init netxen_init_module(void) if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL) return -ENOMEM; + register_netdevice_notifier(&netxen_netdev_cb); + register_inetaddr_notifier(&netxen_inetaddr_cb); + return pci_register_driver(&netxen_driver); } @@ -1808,6 +1931,9 @@ module_init(netxen_init_module); static void __exit netxen_exit_module(void) { pci_unregister_driver(&netxen_driver); + + unregister_inetaddr_notifier(&netxen_inetaddr_cb); + unregister_netdevice_notifier(&netxen_netdev_cb); destroy_workqueue(netxen_workq); } -- cgit v0.10.2 From ca2ef330b5eb30e3bc7047f99fd4be9f1bad22be Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:38 +0000 Subject: netxen: configure interrupt coalesce defaults Initialize and configure interrupt coalesing defaults in the firmware, so that these also reflect in "ethool -c". Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index b368326..76bdd5c 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -819,6 +819,20 @@ netxen_nic_free_irq(struct netxen_adapter *adapter) } } +static void +netxen_nic_init_coalesce_defaults(struct netxen_adapter *adapter) +{ + adapter->coal.flags = NETXEN_NIC_INTR_DEFAULT; + adapter->coal.normal.data.rx_time_us = + NETXEN_DEFAULT_INTR_COALESCE_RX_TIME_US; + adapter->coal.normal.data.rx_packets = + NETXEN_DEFAULT_INTR_COALESCE_RX_PACKETS; + adapter->coal.normal.data.tx_time_us = + NETXEN_DEFAULT_INTR_COALESCE_TX_TIME_US; + adapter->coal.normal.data.tx_packets = + NETXEN_DEFAULT_INTR_COALESCE_TX_PACKETS; +} + static int netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) { @@ -841,6 +855,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) if (adapter->max_sds_rings > 1) netxen_config_rss(adapter, 1); + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netxen_config_intr_coalesce(adapter); + netxen_napi_enable(adapter); if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION) @@ -936,6 +953,9 @@ netxen_nic_attach(struct netxen_adapter *adapter) goto err_out_free_rxbuf; } + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netxen_nic_init_coalesce_defaults(adapter); + adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; return 0; -- cgit v0.10.2 From 83ac51fa747c3a74372417629fcad4b110857b77 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:39 +0000 Subject: netxen: annotate dma watchdog setup o remove superfluous code to setup PCI dma watchdog for NX2031. o disable dma watchdog completely for NX3031 (not required). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 6b9e759..3368af0 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1324,24 +1324,6 @@ struct netxen_adapter { const struct firmware *fw; }; -/* - * NetXen dma watchdog control structure - * - * Bit 0 : enabled => R/O: 1 watchdog active, 0 inactive - * Bit 1 : disable_request => 1 req disable dma watchdog - * Bit 2 : enable_request => 1 req enable dma watchdog - * Bit 3-31 : unused - */ - -#define netxen_set_dma_watchdog_disable_req(config_word) \ - _netxen_set_bits(config_word, 1, 1, 1) -#define netxen_set_dma_watchdog_enable_req(config_word) \ - _netxen_set_bits(config_word, 2, 1, 1) -#define netxen_get_dma_watchdog_enabled(config_word) \ - ((config_word) & 0x1) -#define netxen_get_dma_watchdog_disabled(config_word) \ - (((config_word) >> 1) & 0x1) - int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter); @@ -1402,8 +1384,9 @@ unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, unsigned long long addr); /* Functions from netxen_nic_init.c */ -void netxen_free_adapter_offload(struct netxen_adapter *adapter); -int netxen_initialize_adapter_offload(struct netxen_adapter *adapter); +int netxen_init_dummy_dma(struct netxen_adapter *adapter); +void netxen_free_dummy_dma(struct netxen_adapter *adapter); + int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val); int netxen_load_firmware(struct netxen_adapter *adapter); int netxen_need_fw_reset(struct netxen_adapter *adapter); @@ -1510,56 +1493,6 @@ static inline void get_brd_name_by_type(u32 type, char *name) name = "Unknown"; } -static inline int -dma_watchdog_shutdown_request(struct netxen_adapter *adapter) -{ - u32 ctrl; - - /* check if already inactive */ - ctrl = adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); - - if (netxen_get_dma_watchdog_enabled(ctrl) == 0) - return 1; - - /* Send the disable request */ - netxen_set_dma_watchdog_disable_req(ctrl); - NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); - - return 0; -} - -static inline int -dma_watchdog_shutdown_poll_result(struct netxen_adapter *adapter) -{ - u32 ctrl; - - ctrl = adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); - - return (netxen_get_dma_watchdog_enabled(ctrl) == 0); -} - -static inline int -dma_watchdog_wakeup(struct netxen_adapter *adapter) -{ - u32 ctrl; - - ctrl = adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); - - if (netxen_get_dma_watchdog_enabled(ctrl)) - return 1; - - /* send the wakeup request */ - netxen_set_dma_watchdog_enable_req(ctrl); - - NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); - - return 0; -} - - static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring) { smp_mb(); diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index 8241036..a732858 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -852,7 +852,7 @@ enum { #define NX_PEG_TUNE_MN_PRESENT 0x1 #define NX_PEG_TUNE_CAPABILITY (NETXEN_CAM_RAM(0x02c)) -#define NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL (0x14) +#define NETXEN_DMA_WATCHDOG_CTRL (NETXEN_CAM_RAM(0x14)) #define NETXEN_PEG_ALIVE_COUNTER (NETXEN_CAM_RAM(0xb0)) #define ISR_MSI_INT_TRIGGER(FUNC) (NETXEN_PCIX_PS_REG(PCIX_MSI_F(FUNC))) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 5d7a2c4..9135845 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -954,19 +954,20 @@ netxen_release_firmware(struct netxen_adapter *adapter) release_firmware(adapter->fw); } -int netxen_initialize_adapter_offload(struct netxen_adapter *adapter) +int netxen_init_dummy_dma(struct netxen_adapter *adapter) { - uint64_t addr; - uint32_t hi; - uint32_t lo; + u64 addr; + u32 hi, lo; - adapter->dummy_dma.addr = - pci_alloc_consistent(adapter->pdev, + if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) + return 0; + + adapter->dummy_dma.addr = pci_alloc_consistent(adapter->pdev, NETXEN_HOST_DUMMY_DMA_SIZE, &adapter->dummy_dma.phys_addr); if (adapter->dummy_dma.addr == NULL) { - printk("%s: ERROR: Could not allocate dummy DMA memory\n", - __func__); + dev_err(&adapter->pdev->dev, + "ERROR: Could not allocate dummy DMA memory\n"); return -ENOMEM; } @@ -977,29 +978,41 @@ int netxen_initialize_adapter_offload(struct netxen_adapter *adapter) NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi); NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo); - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - uint32_t temp = 0; - NXWR32(adapter, CRB_HOST_DUMMY_BUF, temp); - } - return 0; } -void netxen_free_adapter_offload(struct netxen_adapter *adapter) +/* + * NetXen DMA watchdog control: + * + * Bit 0 : enabled => R/O: 1 watchdog active, 0 inactive + * Bit 1 : disable_request => 1 req disable dma watchdog + * Bit 2 : enable_request => 1 req enable dma watchdog + * Bit 3-31 : unused + */ +void netxen_free_dummy_dma(struct netxen_adapter *adapter) { int i = 100; + u32 ctrl; + + if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) + return; if (!adapter->dummy_dma.addr) return; - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - do { - if (dma_watchdog_shutdown_request(adapter) == 1) - break; + ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL); + if ((ctrl & 0x1) != 0) { + NXWR32(adapter, NETXEN_DMA_WATCHDOG_CTRL, (ctrl | 0x2)); + + while ((ctrl & 0x1) != 0) { + msleep(50); - if (dma_watchdog_shutdown_poll_result(adapter) == 1) + + ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL); + + if (--i == 0) break; - } while (--i); + }; } if (i) { @@ -1008,10 +1021,8 @@ void netxen_free_adapter_offload(struct netxen_adapter *adapter) adapter->dummy_dma.addr, adapter->dummy_dma.phys_addr); adapter->dummy_dma.addr = NULL; - } else { - printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n", - adapter->netdev->name); - } + } else + dev_err(&adapter->pdev->dev, "dma_watchdog_shutdown failed\n"); } int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 76bdd5c..fb976cb 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -745,7 +745,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) } - err = netxen_initialize_adapter_offload(adapter); + err = netxen_init_dummy_dma(adapter); if (err) return err; @@ -761,7 +761,7 @@ wait_init: /* Handshake with the card before we register the devices. */ err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); if (err) { - netxen_free_adapter_offload(adapter); + netxen_free_dummy_dma(adapter); return err; } @@ -1154,7 +1154,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_out_disable_msi: netxen_teardown_intr(adapter); - netxen_free_adapter_offload(adapter); + netxen_free_dummy_dma(adapter); err_out_iounmap: netxen_cleanup_pci_map(adapter); @@ -1189,7 +1189,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) } if (adapter->portnum == 0) - netxen_free_adapter_offload(adapter); + netxen_free_dummy_dma(adapter); netxen_teardown_intr(adapter); netxen_free_sds_rings(&adapter->recv_ctx); -- cgit v0.10.2 From 1bcfd790c49341fcbdce9526a007c4e2b9d54c7c Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:40 +0000 Subject: netxen: refactor tso code o move all tso / checksum offload code into netxen_tso_check(). o optimize the tso header copy into simple loop. o clean up unnecessary unions from cmd_desc_type0 struct. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 3368af0..3a4cbd5 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -316,56 +316,29 @@ struct netxen_ring_ctx { cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7)) #define netxen_set_tx_frags_len(_desc, _frags, _len) \ - (_desc)->num_of_buffers_total_length = \ + (_desc)->nfrags__length = \ cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8)) struct cmd_desc_type0 { u8 tcp_hdr_offset; /* For LSO only */ u8 ip_hdr_offset; /* For LSO only */ - /* Bit pattern: 0-6 flags, 7-12 opcode, 13-15 unused */ - __le16 flags_opcode; - /* Bit pattern: 0-7 total number of segments, - 8-31 Total size of the packet */ - __le32 num_of_buffers_total_length; - union { - struct { - __le32 addr_low_part2; - __le32 addr_high_part2; - }; - __le64 addr_buffer2; - }; + __le16 flags_opcode; /* 15:13 unused, 12:7 opcode, 6:0 flags */ + __le32 nfrags__length; /* 31:8 total len, 7:0 frag count */ + + __le64 addr_buffer2; - __le16 reference_handle; /* changed to u16 to add mss */ - __le16 mss; /* passed by NDIS_PACKET for LSO */ - /* Bit pattern 0-3 port, 0-3 ctx id */ - u8 port_ctxid; + __le16 reference_handle; + __le16 mss; + u8 port_ctxid; /* 7:4 ctxid 3:0 port */ u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */ __le16 conn_id; /* IPSec offoad only */ - union { - struct { - __le32 addr_low_part3; - __le32 addr_high_part3; - }; - __le64 addr_buffer3; - }; - union { - struct { - __le32 addr_low_part1; - __le32 addr_high_part1; - }; - __le64 addr_buffer1; - }; + __le64 addr_buffer3; + __le64 addr_buffer1; __le16 buffer_length[4]; - union { - struct { - __le32 addr_low_part4; - __le32 addr_high_part4; - }; - __le64 addr_buffer4; - }; + __le64 addr_buffer4; __le64 unused; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index fb976cb..381bd8f 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1310,13 +1310,18 @@ static int netxen_nic_close(struct net_device *netdev) return 0; } -static bool netxen_tso_check(struct net_device *netdev, - struct cmd_desc_type0 *desc, struct sk_buff *skb) +static void +netxen_tso_check(struct net_device *netdev, + struct nx_host_tx_ring *tx_ring, + struct cmd_desc_type0 *first_desc, + struct sk_buff *skb) { - bool tso = false; u8 opcode = TX_ETHER_PKT; __be16 protocol = skb->protocol; u16 flags = 0; + u32 producer; + int copied, offset, copy_len, hdr_len = 0, tso = 0; + struct cmd_desc_type0 *hwdesc; if (protocol == cpu_to_be16(ETH_P_8021Q)) { struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data; @@ -1327,13 +1332,14 @@ static bool netxen_tso_check(struct net_device *netdev, if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && skb_shinfo(skb)->gso_size > 0) { - desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); - desc->total_hdr_length = - skb_transport_offset(skb) + tcp_hdrlen(skb); + hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + + first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); + first_desc->total_hdr_length = hdr_len; opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ? TX_TCP_LSO6 : TX_TCP_LSO; - tso = true; + tso = 1; } else if (skb->ip_summed == CHECKSUM_PARTIAL) { u8 l4proto; @@ -1354,10 +1360,39 @@ static bool netxen_tso_check(struct net_device *netdev, opcode = TX_UDPV6_PKT; } } - desc->tcp_hdr_offset = skb_transport_offset(skb); - desc->ip_hdr_offset = skb_network_offset(skb); - netxen_set_tx_flags_opcode(desc, flags, opcode); - return tso; + first_desc->tcp_hdr_offset = skb_transport_offset(skb); + first_desc->ip_hdr_offset = skb_network_offset(skb); + netxen_set_tx_flags_opcode(first_desc, flags, opcode); + + if (!tso) + return; + + /* For LSO, we need to copy the MAC/IP/TCP headers into + * the descriptor ring + */ + producer = tx_ring->producer; + copied = 0; + offset = 2; + + while (copied < hdr_len) { + + copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, + (hdr_len - copied)); + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + skb_copy_from_linear_data_offset(skb, copied, + (char *)hwdesc + offset, copy_len); + + copied += copy_len; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); + } + + tx_ring->producer = producer; + barrier(); } static void @@ -1381,9 +1416,8 @@ netxen_clean_tx_dma_mapping(struct pci_dev *pdev, static inline void netxen_clear_cmddesc(u64 *desc) { - int i; - for (i = 0; i < 8; i++) - desc[i] = 0ULL; + desc[0] = 0ULL; + desc[2] = 0ULL; } static int @@ -1391,18 +1425,18 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); struct nx_host_tx_ring *tx_ring = adapter->tx_ring; - unsigned int first_seg_len = skb->len - skb->data_len; + struct skb_frag_struct *frag; struct netxen_cmd_buffer *pbuf; struct netxen_skb_frag *buffrag; - struct cmd_desc_type0 *hwdesc; - struct pci_dev *pdev = adapter->pdev; + struct cmd_desc_type0 *hwdesc, *first_desc; + struct pci_dev *pdev; dma_addr_t temp_dma; int i, k; + unsigned long offset; u32 producer; - int frag_count, no_of_desc; + int len, frag_count, no_of_desc; u32 num_txd = tx_ring->num_desc; - bool is_tso = false; frag_count = skb_shinfo(skb)->nr_frags + 1; @@ -1416,32 +1450,30 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) producer = tx_ring->producer; - hwdesc = &tx_ring->desc_head[producer]; - netxen_clear_cmddesc((u64 *)hwdesc); - pbuf = &tx_ring->cmd_buf_arr[producer]; + pdev = adapter->pdev; + len = skb->len - skb->data_len; - is_tso = netxen_tso_check(netdev, hwdesc, skb); + temp_dma = pci_map_single(pdev, skb->data, len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, temp_dma)) + goto drop_packet; + pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = skb; pbuf->frag_count = frag_count; - buffrag = &pbuf->frag_array[0]; - temp_dma = pci_map_single(pdev, skb->data, first_seg_len, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(pdev, temp_dma)) - goto drop_packet; + buffrag = &pbuf->frag_array[0]; buffrag->dma = temp_dma; - buffrag->length = first_seg_len; + buffrag->length = len; + + first_desc = hwdesc = &tx_ring->desc_head[producer]; + netxen_clear_cmddesc((u64 *)hwdesc); netxen_set_tx_frags_len(hwdesc, frag_count, skb->len); netxen_set_tx_port(hwdesc, adapter->portnum); - hwdesc->buffer_length[0] = cpu_to_le16(first_seg_len); - hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); + hwdesc->buffer_length[0] = cpu_to_le16(len); + hwdesc->addr_buffer1 = cpu_to_le64(temp_dma); for (i = 1, k = 1; i < frag_count; i++, k++) { - struct skb_frag_struct *frag; - int len, temp_len; - unsigned long offset; /* move to next desc. if there is a need */ if ((i & 0x3) == 0) { @@ -1452,11 +1484,11 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = NULL; } + buffrag = &pbuf->frag_array[i]; frag = &skb_shinfo(skb)->frags[i - 1]; len = frag->size; offset = frag->page_offset; - temp_len = len; temp_dma = pci_map_page(pdev, frag->page, offset, len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(pdev, temp_dma)) { @@ -1464,11 +1496,10 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) goto drop_packet; } - buffrag++; buffrag->dma = temp_dma; - buffrag->length = temp_len; + buffrag->length = len; - hwdesc->buffer_length[k] = cpu_to_le16(temp_len); + hwdesc->buffer_length[k] = cpu_to_le16(len); switch (k) { case 0: hwdesc->addr_buffer1 = cpu_to_le64(temp_dma); @@ -1483,53 +1514,14 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) hwdesc->addr_buffer4 = cpu_to_le64(temp_dma); break; } - frag++; } - producer = get_next_index(producer, num_txd); + tx_ring->producer = get_next_index(producer, num_txd); - /* For LSO, we need to copy the MAC/IP/TCP headers into - * the descriptor ring - */ - if (is_tso) { - int hdr_len, first_hdr_len, more_hdr; - hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); - if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) { - first_hdr_len = sizeof(struct cmd_desc_type0) - 2; - more_hdr = 1; - } else { - first_hdr_len = hdr_len; - more_hdr = 0; - } - /* copy the MAC/IP/TCP headers to the cmd descriptor list */ - hwdesc = &tx_ring->desc_head[producer]; - pbuf = &tx_ring->cmd_buf_arr[producer]; - pbuf->skb = NULL; - - /* copy the first 64 bytes */ - memcpy(((void *)hwdesc) + 2, - (void *)(skb->data), first_hdr_len); - producer = get_next_index(producer, num_txd); - - if (more_hdr) { - hwdesc = &tx_ring->desc_head[producer]; - pbuf = &tx_ring->cmd_buf_arr[producer]; - pbuf->skb = NULL; - /* copy the next 64 bytes - should be enough except - * for pathological case - */ - skb_copy_from_linear_data_offset(skb, first_hdr_len, - hwdesc, - (hdr_len - - first_hdr_len)); - producer = get_next_index(producer, num_txd); - } - } - - tx_ring->producer = producer; - adapter->stats.txbytes += skb->len; + netxen_tso_check(netdev, tx_ring, first_desc, skb); netxen_nic_update_cmd_producer(adapter, tx_ring); + adapter->stats.txbytes += skb->len; adapter->stats.xmitcalled++; return NETDEV_TX_OK; -- cgit v0.10.2 From 24767ab16913bc27ba7a85698e5c0f591368647d Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Mon, 27 Jul 2009 11:08:00 -0700 Subject: netxen: Add default and limit macros for ring sizes. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 3a4cbd5..e017827 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -200,13 +200,20 @@ #define RCV_RING_JUMBO 1 #define RCV_RING_LRO 2 -#define MAX_CMD_DESCRIPTORS 4096 -#define MAX_RCV_DESCRIPTORS 16384 -#define MAX_CMD_DESCRIPTORS_HOST 1024 -#define MAX_RCV_DESCRIPTORS_1G 2048 -#define MAX_RCV_DESCRIPTORS_10G 4096 -#define MAX_JUMBO_RCV_DESCRIPTORS 1024 +#define MIN_CMD_DESCRIPTORS 64 +#define MIN_RCV_DESCRIPTORS 64 +#define MIN_JUMBO_DESCRIPTORS 32 + +#define MAX_CMD_DESCRIPTORS 1024 +#define MAX_RCV_DESCRIPTORS_1G 4096 +#define MAX_RCV_DESCRIPTORS_10G 8192 +#define MAX_JUMBO_RCV_DESCRIPTORS_1G 512 +#define MAX_JUMBO_RCV_DESCRIPTORS_10G 1024 #define MAX_LRO_RCV_DESCRIPTORS 8 + +#define DEFAULT_RCV_DESCRIPTORS_1G 2048 +#define DEFAULT_RCV_DESCRIPTORS_10G 4096 + #define NETXEN_CTX_SIGNATURE 0xdee0 #define NETXEN_CTX_SIGNATURE_V2 0x0002dee0 #define NETXEN_CTX_RESET 0xbad0 diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index e16ea46..80d286d 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -494,20 +494,21 @@ netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) { struct netxen_adapter *adapter = netdev_priv(dev); - ring->rx_pending = 0; - ring->rx_jumbo_pending = 0; - ring->rx_pending += adapter->recv_ctx. - rds_rings[RCV_RING_NORMAL].num_desc; - ring->rx_jumbo_pending += adapter->recv_ctx. - rds_rings[RCV_RING_JUMBO].num_desc; + ring->rx_pending = adapter->num_rxd; + ring->rx_jumbo_pending = adapter->num_jumbo_rxd; + ring->rx_jumbo_pending += adapter->num_lro_rxd; ring->tx_pending = adapter->num_txd; - if (adapter->ahw.port_type == NETXEN_NIC_GBE) + if (adapter->ahw.port_type == NETXEN_NIC_GBE) { ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G; - else + ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G; + } else { ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G; - ring->tx_max_pending = MAX_CMD_DESCRIPTORS_HOST; - ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS; + ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } + + ring->tx_max_pending = MAX_CMD_DESCRIPTORS; + ring->rx_mini_max_pending = 0; ring->rx_mini_pending = 0; } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 381bd8f..1aa850a 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -283,12 +283,16 @@ nx_update_dma_mask(struct netxen_adapter *adapter) return 0; } -static void netxen_check_options(struct netxen_adapter *adapter) +static void +netxen_check_options(struct netxen_adapter *adapter) { - if (adapter->ahw.port_type == NETXEN_NIC_XGBE) - adapter->num_rxd = MAX_RCV_DESCRIPTORS_10G; - else if (adapter->ahw.port_type == NETXEN_NIC_GBE) - adapter->num_rxd = MAX_RCV_DESCRIPTORS_1G; + if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } else if (adapter->ahw.port_type == NETXEN_NIC_GBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; + } adapter->msix_supported = 0; if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { @@ -306,11 +310,15 @@ static void netxen_check_options(struct netxen_adapter *adapter) } } - adapter->num_txd = MAX_CMD_DESCRIPTORS_HOST; - adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS; - adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS; + adapter->num_txd = MAX_CMD_DESCRIPTORS; - return; + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS; + adapter->max_rds_rings = 3; + } else { + adapter->num_lro_rxd = 0; + adapter->max_rds_rings = 2; + } } static int @@ -908,11 +916,6 @@ netxen_nic_attach(struct netxen_adapter *adapter) return -EIO; } - if (adapter->fw_major < 4) - adapter->max_rds_rings = 3; - else - adapter->max_rds_rings = 2; - err = netxen_alloc_sw_resources(adapter); if (err) { printk(KERN_ERR "%s: Error in setting sw resources\n", @@ -1923,8 +1926,6 @@ static struct pci_driver netxen_driver = { #endif }; -/* Driver Registration on NetXen card */ - static int __init netxen_init_module(void) { printk(KERN_INFO "%s\n", netxen_nic_driver_string); -- cgit v0.10.2 From 4f96b988e8d404b8b32aefed27503b4538949a3c Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:42 +0000 Subject: netxen: clean up firmware version checks NX2031 firmware version will never be > 4.0.0, so replace (adapter->fw_major < 4) checks with pci revision ID check. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index e017827..b58d0b2 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1299,7 +1299,7 @@ struct netxen_adapter { nx_nic_intr_coalesce_t coal; - u32 fw_major; + u32 resv5; u32 fw_version; const struct firmware *fw; }; diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 9f8ae47..9e04696 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -647,7 +647,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) } rds_ring->desc_head = (struct rcv_desc *)addr; - if (adapter->fw_major < 4) + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) rds_ring->crb_rcv_producer = recv_crb_registers[port].crb_rcv_producer[ring]; } @@ -675,7 +675,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) } - if (adapter->fw_major >= 4) { + if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { err = nx_fw_cmd_create_rx_ctx(adapter); if (err) goto err_out_free; @@ -705,7 +705,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) int port = adapter->portnum; - if (adapter->fw_major >= 4) { + if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { nx_fw_cmd_destroy_rx_ctx(adapter); nx_fw_cmd_destroy_tx_ctx(adapter); } else { diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 088611b..ddb9deb 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -2045,7 +2045,6 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); - adapter->fw_major = fw_major; adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build); if (adapter->portnum == 0) { diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 9135845..ef7f1b1 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1477,7 +1477,7 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, NXWR32(adapter, rds_ring->crb_rcv_producer, (producer-1) & (rds_ring->num_desc-1)); - if (adapter->fw_major < 4) { + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { /* * Write a doorbell msg to tell phanmon of change in * receive ring producer diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 1aa850a..5d52630 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -932,7 +932,7 @@ netxen_nic_attach(struct netxen_adapter *adapter) goto err_out_free_sw; } - if (adapter->fw_major < 4) { + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { tx_ring = adapter->tx_ring; tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum]; tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum]; @@ -1103,7 +1103,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * See if the firmware gave us a virtual-physical port mapping. */ adapter->physical_port = adapter->portnum; - if (adapter->fw_major < 4) { + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { i = NXRD32(adapter, CRB_V2P(adapter->portnum)); if (i != 0x55555555) adapter->physical_port = i; @@ -1727,7 +1727,7 @@ static irqreturn_t netxen_intr(int irq, void *data) } /* clear interrupt */ - if (adapter->fw_major < 4) + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) netxen_nic_disable_int(sds_ring); adapter->pci_write_immediate(adapter, -- cgit v0.10.2 From f17443f4b01659a5c44d5fc6f5c502c39c293959 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:43 +0000 Subject: netxen: refactor net_device setup code Move all net_device initialization into one function netxen_setup_netdev(). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 5d52630..43a99f6 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -66,7 +66,7 @@ static int netxen_nic_open(struct net_device *netdev); static int netxen_nic_close(struct net_device *netdev); static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); static void netxen_tx_timeout(struct net_device *netdev); -static void netxen_tx_timeout_task(struct work_struct *work); +static void netxen_reset_task(struct work_struct *work); static void netxen_watchdog(unsigned long); static int netxen_nic_poll(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER @@ -182,7 +182,7 @@ netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev) struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; if (netxen_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) - return 1; + return -ENOMEM; for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; @@ -981,6 +981,68 @@ netxen_nic_detach(struct netxen_adapter *adapter) adapter->is_up = 0; } +static int +netxen_setup_netdev(struct netxen_adapter *adapter, + struct net_device *netdev) +{ + int err = 0; + struct pci_dev *pdev = adapter->pdev; + + adapter->rx_csum = 1; + adapter->mc_enabled = 0; + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + adapter->max_mc_count = 38; + else + adapter->max_mc_count = 16; + + netdev->netdev_ops = &netxen_netdev_ops; + netdev->watchdog_timeo = 2*HZ; + + netxen_nic_change_mtu(netdev, netdev->mtu); + + SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); + + netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + netdev->features |= (NETIF_F_GRO); + netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); + netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); + } + + if (adapter->pci_using_dac) { + netdev->features |= NETIF_F_HIGHDMA; + netdev->vlan_features |= NETIF_F_HIGHDMA; + } + + netdev->irq = adapter->msix_entries[0].vector; + + err = netxen_napi_add(adapter, netdev); + if (err) + return err; + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &netxen_watchdog; + adapter->watchdog_timer.data = (unsigned long)adapter; + INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task); + INIT_WORK(&adapter->tx_timeout_task, netxen_reset_task); + + if (netxen_read_mac_addr(adapter)) + dev_warn(&pdev->dev, "failed to read mac addr\n"); + + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + err = register_netdev(netdev); + if (err) { + dev_err(&pdev->dev, "failed to register net device\n"); + return err; + } + + return 0; +} + static int __devinit netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1018,9 +1080,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev = alloc_etherdev(sizeof(struct netxen_adapter)); if(!netdev) { - printk(KERN_ERR"%s: Failed to allocate memory for the " - "device block.Check system memory resource" - " usage.\n", netxen_nic_driver_name); + dev_err(&pdev->dev, "failed to allocate net_device\n"); + err = -ENOMEM; goto err_out_free_res; } @@ -1048,38 +1109,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* This will be reset for mezz cards */ adapter->portnum = pci_func_id; - adapter->rx_csum = 1; - adapter->mc_enabled = 0; - if (NX_IS_REVISION_P3(revision_id)) - adapter->max_mc_count = 38; - else - adapter->max_mc_count = 16; - - netdev->netdev_ops = &netxen_netdev_ops; - netdev->watchdog_timeo = 2*HZ; - - netxen_nic_change_mtu(netdev, netdev->mtu); - - SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); - - netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); - netdev->features |= (NETIF_F_GRO); - netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); - - if (NX_IS_REVISION_P3(revision_id)) { - netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - } - - if (adapter->pci_using_dac) { - netdev->features |= NETIF_F_HIGHDMA; - netdev->vlan_features |= NETIF_F_HIGHDMA; - } - if (netxen_nic_get_board_info(adapter) != 0) { - printk("%s: Error getting board config info.\n", - netxen_nic_driver_name); - err = -EIO; + err = netxen_nic_get_board_info(adapter); + if (err) { + dev_err(&pdev->dev, "Error getting board config info.\n"); goto err_out_iounmap; } @@ -1099,6 +1132,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = netxen_start_firmware(adapter, 1); if (err) goto err_out_iounmap; + /* * See if the firmware gave us a virtual-physical port mapping. */ @@ -1113,31 +1147,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netxen_setup_intr(adapter); - netdev->irq = adapter->msix_entries[0].vector; - - if (netxen_napi_add(adapter, netdev)) - goto err_out_disable_msi; - - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = &netxen_watchdog; - adapter->watchdog_timer.data = (unsigned long)adapter; - INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task); - INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task); - - err = netxen_read_mac_addr(adapter); + err = netxen_setup_netdev(adapter, netdev); if (err) - dev_warn(&pdev->dev, "failed to read mac addr\n"); - - netif_carrier_off(netdev); - netif_stop_queue(netdev); - - if ((err = register_netdev(netdev))) { - printk(KERN_ERR "%s: register_netdev failed port #%d" - " aborting\n", netxen_nic_driver_name, - adapter->portnum); - err = -EIO; goto err_out_disable_msi; - } pci_set_drvdata(pdev, adapter); @@ -1656,10 +1668,13 @@ static void netxen_tx_timeout(struct net_device *netdev) { struct netxen_adapter *adapter = (struct netxen_adapter *) netdev_priv(netdev); + + dev_err(&netdev->dev, "transmit timeout, resetting.\n"); + SCHEDULE_WORK(&adapter->tx_timeout_task); } -static void netxen_tx_timeout_task(struct work_struct *work) +static void netxen_reset_task(struct work_struct *work) { struct netxen_adapter *adapter = container_of(work, struct netxen_adapter, tx_timeout_task); @@ -1667,9 +1682,6 @@ static void netxen_tx_timeout_task(struct work_struct *work) if (!netif_running(adapter->netdev)) return; - printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", - netxen_nic_driver_name, adapter->netdev->name); - netxen_napi_disable(adapter); adapter->netdev->trans_start = jiffies; -- cgit v0.10.2 From 9b08beba2d1bf7e4598deba2800a9ea5e5c3a282 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:44 +0000 Subject: netxen: fix skb alloc size for legacy firmware Request 1532 bytes skb data size for NX3031. NX2031 firmware needs 1760 sized buffers. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index b58d0b2..e7702f6 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -143,18 +143,13 @@ #define NX_ETHERMTU 1500 #define NX_MAX_ETHERHDR 32 /* This contains some padding */ -#define NX_RX_NORMAL_BUF_MAX_LEN (NX_MAX_ETHERHDR + NX_ETHERMTU) +#define NX_P2_RX_BUF_MAX_LEN 1760 +#define NX_P3_RX_BUF_MAX_LEN (NX_MAX_ETHERHDR + NX_ETHERMTU) #define NX_P2_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P2_MAX_MTU) #define NX_P3_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P3_MAX_MTU) #define NX_CT_DEFAULT_RX_BUF_LEN 2048 -#define MAX_RX_BUFFER_LENGTH 1760 -#define MAX_RX_JUMBO_BUFFER_LENGTH 8062 -#define MAX_RX_LRO_BUFFER_LENGTH (8062) -#define RX_DMA_MAP_LEN (MAX_RX_BUFFER_LENGTH - 2) -#define RX_JUMBO_DMA_MAP_LEN \ - (MAX_RX_JUMBO_BUFFER_LENGTH - 2) -#define RX_LRO_DMA_MAP_LEN (MAX_RX_LRO_BUFFER_LENGTH - 2) +#define NX_RX_LRO_BUFFER_LENGTH (8060) /* * Maximum number of ring contexts diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index ef7f1b1..a6b244a 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -247,9 +247,14 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) rds_ring->skb_size = NX_CT_DEFAULT_RX_BUF_LEN; } else { - rds_ring->dma_size = RX_DMA_MAP_LEN; + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + rds_ring->dma_size = + NX_P3_RX_BUF_MAX_LEN; + else + rds_ring->dma_size = + NX_P2_RX_BUF_MAX_LEN; rds_ring->skb_size = - MAX_RX_BUFFER_LENGTH; + rds_ring->dma_size + NET_IP_ALIGN; } break; @@ -267,8 +272,8 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) case RCV_RING_LRO: rds_ring->num_desc = adapter->num_lro_rxd; - rds_ring->dma_size = RX_LRO_DMA_MAP_LEN; - rds_ring->skb_size = MAX_RX_LRO_BUFFER_LENGTH; + rds_ring->dma_size = NX_RX_LRO_BUFFER_LENGTH; + rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN; break; } -- cgit v0.10.2 From 028afe719855a157e32450c36b7a12e1f9e85abe Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:45 +0000 Subject: netxen: add vlan tx acceleration support Enable vlan tx acceleration for NX3031 if firmware advertises capability. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index e7702f6..d01cc09 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -304,6 +304,10 @@ struct netxen_ring_ctx { #define FLAGS_IPSEC_SA_ADD 0x04 #define FLAGS_IPSEC_SA_DELETE 0x08 #define FLAGS_VLAN_TAGGED 0x10 +#define FLAGS_VLAN_OOB 0x40 + +#define netxen_set_tx_vlan_tci(cmd_desc, v) \ + (cmd_desc)->vlan_TCI = cpu_to_le16(v); #define netxen_set_cmd_desc_port(cmd_desc, var) \ ((cmd_desc)->port_ctxid |= ((var) & 0x0F)) @@ -342,7 +346,9 @@ struct cmd_desc_type0 { __le64 addr_buffer4; - __le64 unused; + __le16 vlan_TCI; + __le16 reserved; + __le32 reserved2; } __attribute__ ((aligned(64))); @@ -1111,6 +1117,9 @@ typedef struct { #define NX_FW_CAPABILITY_LINK_NOTIFICATION (1 << 5) #define NX_FW_CAPABILITY_SWITCHING (1 << 6) +#define NX_FW_CAPABILITY_PEXQ (1 << 7) +#define NX_FW_CAPABILITY_BDG (1 << 8) +#define NX_FW_CAPABILITY_FVLANTX (1 << 9) /* module types */ #define LINKEVENT_MODULE_NOT_PRESENT 1 diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 43a99f6..ff7ee9c 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1016,6 +1016,9 @@ netxen_setup_netdev(struct netxen_adapter *adapter, netdev->vlan_features |= NETIF_F_HIGHDMA; } + if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX) + netdev->features |= (NETIF_F_HW_VLAN_TX); + netdev->irq = adapter->msix_entries[0].vector; err = netxen_napi_add(adapter, netdev); @@ -1333,15 +1336,24 @@ netxen_tso_check(struct net_device *netdev, { u8 opcode = TX_ETHER_PKT; __be16 protocol = skb->protocol; - u16 flags = 0; + u16 flags = 0, vid = 0; u32 producer; - int copied, offset, copy_len, hdr_len = 0, tso = 0; + int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0; struct cmd_desc_type0 *hwdesc; + struct vlan_ethhdr *vh; if (protocol == cpu_to_be16(ETH_P_8021Q)) { - struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data; + + vh = (struct vlan_ethhdr *)skb->data; protocol = vh->h_vlan_encapsulated_proto; flags = FLAGS_VLAN_TAGGED; + + } else if (vlan_tx_tag_present(skb)) { + + flags = FLAGS_VLAN_OOB; + vid = vlan_tx_tag_get(skb); + netxen_set_tx_vlan_tci(first_desc, vid); + vlan_oob = 1; } if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && @@ -1351,6 +1363,13 @@ netxen_tso_check(struct net_device *netdev, first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); first_desc->total_hdr_length = hdr_len; + if (vlan_oob) { + first_desc->total_hdr_length += VLAN_HLEN; + first_desc->tcp_hdr_offset = VLAN_HLEN; + first_desc->ip_hdr_offset = VLAN_HLEN; + /* Only in case of TSO on vlan device */ + flags |= FLAGS_VLAN_TAGGED; + } opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ? TX_TCP_LSO6 : TX_TCP_LSO; @@ -1375,8 +1394,9 @@ netxen_tso_check(struct net_device *netdev, opcode = TX_UDPV6_PKT; } } - first_desc->tcp_hdr_offset = skb_transport_offset(skb); - first_desc->ip_hdr_offset = skb_network_offset(skb); + + first_desc->tcp_hdr_offset += skb_transport_offset(skb); + first_desc->ip_hdr_offset += skb_network_offset(skb); netxen_set_tx_flags_opcode(first_desc, flags, opcode); if (!tso) @@ -1389,6 +1409,28 @@ netxen_tso_check(struct net_device *netdev, copied = 0; offset = 2; + if (vlan_oob) { + /* Create a TSO vlan header template for firmware */ + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, + hdr_len + VLAN_HLEN); + + vh = (struct vlan_ethhdr *)((char *)hwdesc + 2); + skb_copy_from_linear_data(skb, vh, 12); + vh->h_vlan_proto = htons(ETH_P_8021Q); + vh->h_vlan_TCI = htons(vid); + skb_copy_from_linear_data_offset(skb, 12, + (char *)vh + 16, copy_len - 16); + + copied = copy_len; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); + } + while (copied < hdr_len) { copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, -- cgit v0.10.2 From 7042cd8f148345bfca6c336f009c96a416674f5e Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 27 Jul 2009 11:15:54 -0700 Subject: netxen: support for ethtool set ringparam Add support for ethtool -G to tune rx and tx ring sizes per interface basis. This is only supported for NX3031 based cards. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index d01cc09..b68a70d 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1427,6 +1427,9 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev); void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, struct nx_host_tx_ring *tx_ring); +/* Functions from netxen_nic_main.c */ +int netxen_nic_reset_context(struct netxen_adapter *); + /* * NetXen Board information */ diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 80d286d..39a308c 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -490,7 +490,8 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, } static void -netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) +netxen_nic_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) { struct netxen_adapter *adapter = netdev_priv(dev); @@ -513,6 +514,62 @@ netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) ring->rx_mini_pending = 0; } +static u32 +netxen_validate_ringparam(u32 val, u32 min, u32 max, char *r_name) +{ + u32 num_desc; + num_desc = max(val, min); + num_desc = min(num_desc, max); + num_desc = roundup_pow_of_two(num_desc); + + if (val != num_desc) { + printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n", + netxen_nic_driver_name, r_name, num_desc, val); + } + + return num_desc; +} + +static int +netxen_nic_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct netxen_adapter *adapter = netdev_priv(dev); + u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G; + u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G; + u16 num_rxd, num_jumbo_rxd, num_txd; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + return -EOPNOTSUPP; + + if (ring->rx_mini_pending) + return -EOPNOTSUPP; + + if (adapter->ahw.port_type == NETXEN_NIC_GBE) { + max_rcv_desc = MAX_RCV_DESCRIPTORS_1G; + max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } + + num_rxd = netxen_validate_ringparam(ring->rx_pending, + MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx"); + + num_jumbo_rxd = netxen_validate_ringparam(ring->rx_jumbo_pending, + MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo"); + + num_txd = netxen_validate_ringparam(ring->tx_pending, + MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx"); + + if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd && + num_jumbo_rxd == adapter->num_jumbo_rxd) + return 0; + + adapter->num_rxd = num_rxd; + adapter->num_jumbo_rxd = num_jumbo_rxd; + adapter->num_txd = num_txd; + + return netxen_nic_reset_context(adapter); +} + static void netxen_nic_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause) @@ -894,6 +951,7 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .get_eeprom_len = netxen_nic_get_eeprom_len, .get_eeprom = netxen_nic_get_eeprom, .get_ringparam = netxen_nic_get_ringparam, + .set_ringparam = netxen_nic_set_ringparam, .get_pauseparam = netxen_nic_get_pauseparam, .set_pauseparam = netxen_nic_set_pauseparam, .set_tx_csum = ethtool_op_set_tx_csum, diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index ff7ee9c..2bbefa6 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -910,6 +910,9 @@ netxen_nic_attach(struct netxen_adapter *adapter) struct nx_host_rds_ring *rds_ring; struct nx_host_tx_ring *tx_ring; + if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) + return 0; + err = netxen_init_firmware(adapter); if (err != 0) { printk(KERN_ERR "Failed to init firmware\n"); @@ -973,6 +976,9 @@ err_out_free_sw: static void netxen_nic_detach(struct netxen_adapter *adapter) { + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + return; + netxen_free_hw_resources(adapter); netxen_release_rx_buffers(adapter); netxen_nic_free_irq(adapter); @@ -981,6 +987,30 @@ netxen_nic_detach(struct netxen_adapter *adapter) adapter->is_up = 0; } +int +netxen_nic_reset_context(struct netxen_adapter *adapter) +{ + int err = 0; + struct net_device *netdev = adapter->netdev; + + if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) { + + if (netif_running(netdev)) + netxen_nic_down(adapter, netdev); + + netxen_nic_detach(adapter); + + err = netxen_nic_attach(adapter); + if (err) + goto done; + + if (netif_running(netdev)) + err = netxen_nic_up(adapter, netdev); + } +done: + return err; +} + static int netxen_setup_netdev(struct netxen_adapter *adapter, struct net_device *netdev) @@ -1202,9 +1232,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) unregister_netdev(netdev); - if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) { - netxen_nic_detach(adapter); - } + netxen_nic_detach(adapter); if (adapter->portnum == 0) netxen_free_dummy_dma(adapter); @@ -1236,8 +1264,7 @@ netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) if (netif_running(netdev)) netxen_nic_down(adapter, netdev); - if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) - netxen_nic_detach(adapter); + netxen_nic_detach(adapter); pci_save_state(pdev); @@ -1298,11 +1325,9 @@ static int netxen_nic_open(struct net_device *netdev) if (adapter->driver_mismatch) return -EIO; - if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) { - err = netxen_nic_attach(adapter); - if (err) - return err; - } + err = netxen_nic_attach(adapter); + if (err) + return err; err = netxen_nic_up(adapter, netdev); if (err) -- cgit v0.10.2 From c685bfc6c6bcb9bcc42d1345a3650d3ce5185c52 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:47 +0000 Subject: netxen: update version to 4.0.41 Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index b68a70d..e22d086 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -57,8 +57,8 @@ #define _NETXEN_NIC_LINUX_MAJOR 4 #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 30 -#define NETXEN_NIC_LINUX_VERSIONID "4.0.30" +#define _NETXEN_NIC_LINUX_SUBVERSION 41 +#define NETXEN_NIC_LINUX_VERSIONID "4.0.41" #define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) #define _major(v) (((v) >> 24) & 0xff) -- cgit v0.10.2 From 463889e27e6f4f097374a6c9de5611f520766dad Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 27 Jul 2009 06:13:30 +0000 Subject: drivers/net: Correct redundant test res has already been tested. It seems that this test should be on the recently returned value mmio. A simplified version of the semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; expression E; @@ if (x == NULL || ...) { ... when forall return ...; } ... when != \(x=E\|x--\|x++\|--x\|++x\|x-=E\|x+=E\|x|=E\|x&=E\|&x\) ( *x == NULL | *x != NULL ) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index ceb6a9c..4dbe5f1 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -894,7 +894,7 @@ static int ethoc_probe(struct platform_device *pdev) mmio = devm_request_mem_region(&pdev->dev, res->start, res->end - res->start + 1, res->name); - if (!res) { + if (!mmio) { dev_err(&pdev->dev, "cannot request I/O memory space\n"); ret = -ENXIO; goto free; -- cgit v0.10.2 From 479432344420bc9a868088e346fecb6765e2b674 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 27 Jul 2009 06:15:43 +0000 Subject: net/netlabel: Correct redundant test entry was tested for NULL near the beginning of the function, followed by a return, and there is no intervening modification of its value. A simplified version of the semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; expression E; position p1,p2; @@ if (x == NULL || ...) { ... when forall return ...; } ... when != \(x=E\|x--\|x++\|--x\|++x\|x-=E\|x+=E\|x|=E\|x&=E\|&x\) ( *x == NULL | *x != NULL ) // Signed-off-by: Julia Lawall Acked-by: Paul Moore Signed-off-by: David S. Miller diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index b0e582f..3ff6f32 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -185,8 +185,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain, return 0; cfg_unlbl_map_add_failure: - if (entry != NULL) - kfree(entry->domain); + kfree(entry->domain); kfree(entry); kfree(addrmap); kfree(map4); @@ -385,8 +384,7 @@ int netlbl_cfg_cipsov4_map_add(u32 doi, cfg_cipsov4_map_add_failure: cipso_v4_doi_putdef(doi_def); - if (entry != NULL) - kfree(entry->domain); + kfree(entry->domain); kfree(entry); kfree(addrmap); kfree(addrinfo); -- cgit v0.10.2 From 8a729fce76f7af50d8b622f2fb26adce9c8df743 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 26 Jul 2009 23:18:11 +0000 Subject: net: ethtool_op_get_rx_csum() should be public and exported Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 9b660bd..90c4a36 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -368,6 +368,7 @@ struct net_device; /* Some generic methods drivers may use in their ethtool_ops */ u32 ethtool_op_get_link(struct net_device *dev); +u32 ethtool_op_get_rx_csum(struct net_device *dev); u32 ethtool_op_get_tx_csum(struct net_device *dev); int ethtool_op_set_tx_csum(struct net_device *dev, u32 data); int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index cf36ff4..44e5711 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -34,11 +34,13 @@ u32 ethtool_op_get_rx_csum(struct net_device *dev) { return (dev->features & NETIF_F_ALL_CSUM) != 0; } +EXPORT_SYMBOL(ethtool_op_get_rx_csum); u32 ethtool_op_get_tx_csum(struct net_device *dev) { return (dev->features & NETIF_F_ALL_CSUM) != 0; } +EXPORT_SYMBOL(ethtool_op_get_tx_csum); int ethtool_op_set_tx_csum(struct net_device *dev, u32 data) { @@ -1125,7 +1127,6 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) EXPORT_SYMBOL(ethtool_op_get_link); EXPORT_SYMBOL(ethtool_op_get_sg); EXPORT_SYMBOL(ethtool_op_get_tso); -EXPORT_SYMBOL(ethtool_op_get_tx_csum); EXPORT_SYMBOL(ethtool_op_set_sg); EXPORT_SYMBOL(ethtool_op_set_tso); EXPORT_SYMBOL(ethtool_op_set_tx_csum); -- cgit v0.10.2 From a44a4a006b860476881ec0098c36584036e1cb91 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 27 Jul 2009 08:22:46 +0000 Subject: xfrm: export xfrm garbage collector thresholds via sysctl Export garbage collector thresholds for xfrm[4|6]_dst_ops Had a problem reported to me recently in which a high volume of ipsec connections on a system began reporting ENOBUFS for new connections eventually. It seemed that after about 2000 connections we started being unable to create more. A quick look revealed that the xfrm code used a dst_ops structure that limited the gc_thresh value to 1024, and always dropped route cache entries after 2x the gc_thresh. It seems the most direct solution is to export the gc_thresh values in the xfrm[4|6] dst_ops as sysctls, like the main routing table does, so that higher volumes of connections can be supported. This patch has been tested and allows the reporter to increase their ipsec connection volume successfully. Reported-by: Joe Nall Signed-off-by: Neil Horman ipv4/xfrm4_policy.c | 18 ++++++++++++++++++ ipv6/xfrm6_policy.c | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) Signed-off-by: David S. Miller diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 0071ee6..26496ba 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -264,6 +264,20 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { .fill_dst = xfrm4_fill_dst, }; +static struct ctl_table xfrm4_policy_table[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "xfrm4_gc_thresh", + .data = &xfrm4_dst_ops.gc_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { } +}; + +static struct ctl_table_header *sysctl_hdr; + static void __init xfrm4_policy_init(void) { xfrm_policy_register_afinfo(&xfrm4_policy_afinfo); @@ -271,6 +285,8 @@ static void __init xfrm4_policy_init(void) static void __exit xfrm4_policy_fini(void) { + if (sysctl_hdr) + unregister_net_sysctl_table(sysctl_hdr); xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo); } @@ -278,5 +294,7 @@ void __init xfrm4_init(void) { xfrm4_state_init(); xfrm4_policy_init(); + sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv4_ctl_path, + xfrm4_policy_table); } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 3a3c677..4acc308 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -306,6 +306,20 @@ static void xfrm6_policy_fini(void) xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo); } +static struct ctl_table xfrm6_policy_table[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "xfrm6_gc_thresh", + .data = &xfrm6_dst_ops.gc_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { } +}; + +static struct ctl_table_header *sysctl_hdr; + int __init xfrm6_init(void) { int ret; @@ -317,6 +331,8 @@ int __init xfrm6_init(void) ret = xfrm6_state_init(); if (ret) goto out_policy; + sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv6_ctl_path, + xfrm6_policy_table); out: return ret; out_policy: @@ -326,6 +342,8 @@ out_policy: void xfrm6_fini(void) { + if (sysctl_hdr) + unregister_net_sysctl_table(sysctl_hdr); //xfrm6_input_fini(); xfrm6_policy_fini(); xfrm6_state_fini(); -- cgit v0.10.2 From 6cf5767c7107c606644503f3e95bc1855386a70f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 27 Jul 2009 11:38:52 -0700 Subject: drivers/atm: Correct redundant test str has already been tested. It seems that this test should be on the recently returned value snr. A simplified version of the semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; expression E; @@ if (x == NULL || ...) { ... when forall return ...; } ... when != \(x=E\|x--\|x++\|--x\|++x\|x-=E\|x+=E\|x|=E\|x&=E\|&x\) ( *x == NULL | *x != NULL ) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 9359613..307321b 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -372,7 +372,7 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb } snr = next_string(skb); - if (!str) + if (!snr) return -EIO; attn = next_string(skb); if (!attn) -- cgit v0.10.2 From 5061b0c2b9066de426fbc63f1278d2210e789412 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Jul 2009 00:33:34 +0200 Subject: mac80211: cooperate more with network namespaces There are still two places in mac80211 that hardcode the initial net namespace (init_net). One of them is mandated by cfg80211 and will be removed by a separate patch, the other one is used for finding the network device of a pending packet via its ifindex. Remove the latter use by keeping track of the device pointer itself, via the vif pointer, and avoid it going stale by dropping pending frames for a given interface when the interface is removed. To keep track of the vif pointer for the correct interface, change the info->control.vif pointer's internal use to always be the correct vif, and only move it to the vif the driver expects (or NULL for monitor interfaces and injected packets) right before giving the packet to the driver. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2f797a8..559d698 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -335,7 +335,10 @@ static int ieee80211_stop(struct net_device *dev) struct ieee80211_local *local = sdata->local; struct ieee80211_if_init_conf conf; struct sta_info *sta; + unsigned long flags; + struct sk_buff *skb, *tmp; u32 hw_reconf_flags = 0; + int i; /* * Stop TX on this interface first. @@ -551,6 +554,18 @@ static int ieee80211_stop(struct net_device *dev) if (hw_reconf_flags) ieee80211_hw_config(local, hw_reconf_flags); + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { + skb_queue_walk_safe(&local->pending[i], skb, tmp) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + if (info->control.vif == &sdata->vif) { + __skb_unlink(skb, &local->pending[i]); + dev_kfree_skb_irq(skb); + } + } + } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + return 0; } @@ -788,7 +803,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); - ndev->features |= NETIF_F_NETNS_LOCAL; /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ sdata = netdev_priv(ndev); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 66c797c..d9df819 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1539,7 +1539,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) info = IEEE80211_SKB_CB(fwd_skb); memset(info, 0, sizeof(*info)); info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; - fwd_skb->iif = rx->dev->ifindex; + info->control.vif = &rx->sdata->vif; ieee80211_select_queue(local, fwd_skb); if (is_multicast_ether_addr(fwd_hdr->addr3)) memcpy(fwd_hdr->addr1, fwd_hdr->addr3, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2572509..ffd3b10 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta_info_set_tim_bit(sta); info->control.jiffies = jiffies; + info->control.vif = &tx->sdata->vif; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; skb_queue_tail(&sta->ps_tx_buf, tx->skb); return TX_QUEUED; @@ -696,7 +697,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) * number, if we have no matching interface then we * neither assign one ourselves nor ask the driver to. */ - if (unlikely(!info->control.vif)) + if (unlikely(info->control.vif->type == NL80211_IFTYPE_MONITOR)) return TX_CONTINUE; if (unlikely(ieee80211_is_ctl(hdr->frame_control))) @@ -1092,6 +1093,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, } else if (*state != HT_AGG_STATE_IDLE) { /* in progress */ queued = true; + info->control.vif = &sdata->vif; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; __skb_queue_tail(&tid_tx->pending, skb); } @@ -1143,6 +1145,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, { struct sk_buff *skb = *skbp, *next; struct ieee80211_tx_info *info; + struct ieee80211_sub_if_data *sdata; unsigned long flags; int ret, len; bool fragm = false; @@ -1167,7 +1170,24 @@ static int __ieee80211_tx(struct ieee80211_local *local, next = skb->next; len = skb->len; + + sdata = vif_to_sdata(info->control.vif); + + switch (sdata->vif.type) { + case NL80211_IFTYPE_MONITOR: + info->control.vif = NULL; + break; + case NL80211_IFTYPE_AP_VLAN: + info->control.vif = &container_of(sdata->bss, + struct ieee80211_sub_if_data, u.ap)->vif; + break; + default: + /* keep */ + break; + } + ret = drv_tx(local, skb); + info->control.vif = &sdata->vif; if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { dev_kfree_skb(skb); ret = NETDEV_TX_OK; @@ -1386,11 +1406,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *tmp_sdata; int headroom; bool may_encrypt; - enum { - NOT_MONITOR, - FOUND_SDATA, - UNKNOWN_ADDRESS, - } monitor_iface = NOT_MONITOR; dev_hold(sdata->dev); @@ -1424,7 +1439,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, u16 len_rthdr; info->flags |= IEEE80211_TX_CTL_INJECTED; - monitor_iface = UNKNOWN_ADDRESS; len_rthdr = ieee80211_get_radiotap_len(skb->data); hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); @@ -1454,7 +1468,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, dev_hold(tmp_sdata->dev); dev_put(sdata->dev); sdata = tmp_sdata; - monitor_iface = FOUND_SDATA; break; } } @@ -1476,13 +1489,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, return; } - tmp_sdata = sdata; - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - tmp_sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - if (likely(monitor_iface != UNKNOWN_ADDRESS)) - info->control.vif = &tmp_sdata->vif; + info->control.vif = &sdata->vif; ieee80211_select_queue(local, skb); ieee80211_tx(sdata, skb, false); @@ -1534,9 +1541,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, if (unlikely(skb->len < len_rthdr)) goto fail; /* skb too short for claimed rt header extent */ - /* needed because we set skb device to master */ - skb->iif = dev->ifindex; - /* * fix up the pointers accounting for the radiotap * header still being in there. We are being given @@ -1810,8 +1814,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, nh_pos += hdrlen; h_pos += hdrlen; - skb->iif = dev->ifindex; - dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; @@ -1856,32 +1858,13 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata; struct sta_info *sta; struct ieee80211_hdr *hdr; - struct net_device *dev; int ret; bool result = true; - /* does interface still exist? */ - dev = dev_get_by_index(&init_net, skb->iif); - if (!dev) { - dev_kfree_skb(skb); - return true; - } - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - - if (unlikely(info->control.vif && info->control.vif != &sdata->vif)) { - dev_kfree_skb(skb); - result = true; - goto out; - } + sdata = vif_to_sdata(info->control.vif); if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { - /* do not use sdata, it may have been changed above */ - ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true); + ieee80211_tx(sdata, skb, true); } else { hdr = (struct ieee80211_hdr *)skb->data; sta = sta_info_get(local, hdr->addr1); @@ -1891,9 +1874,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, result = false; } - out: - dev_put(dev); - return result; } @@ -1921,10 +1901,16 @@ void ieee80211_tx_pending(unsigned long data) while (!skb_queue_empty(&local->pending[i])) { struct sk_buff *skb = __skb_dequeue(&local->pending[i]); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sub_if_data *sdata; + + sdata = vif_to_sdata(info->control.vif); + dev_hold(sdata->dev); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); txok = ieee80211_tx_pending_skb(local, skb); + dev_put(sdata->dev); if (!txok) __skb_queue_head(&local->pending[i], skb); spin_lock_irqsave(&local->queue_stop_reason_lock, @@ -2234,7 +2220,6 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, skb_set_network_header(skb, 0); skb_set_transport_header(skb, 0); - skb->iif = sdata->dev->ifindex; if (!encrypt) info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; -- cgit v0.10.2 From 463d018323851a608eef52a9427b0585005c647f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Jul 2009 00:33:35 +0200 Subject: cfg80211: make aware of net namespaces In order to make cfg80211/nl80211 aware of network namespaces, we have to do the following things: * del_virtual_intf method takes an interface index rather than a netdev pointer - simply change this * nl80211 uses init_net a lot, it changes to use the sender's network namespace * scan requests use the interface index, hold a netdev pointer and reference instead * we want a wiphy and its associated virtual interfaces to be in one netns together, so - we need to be able to change ns for a given interface, so export dev_change_net_namespace() - for each virtual interface set the NETIF_F_NETNS_LOCAL flag, and clear that flag only when the wiphy changes ns, to disallow breaking this invariant * when a network namespace goes away, we need to reparent the wiphy to init_net * cfg80211 users that support creating virtual interfaces must create them in the wiphy's namespace, currently this affects only mac80211 The end result is that you can now switch an entire wiphy into a different network namespace with the new command iw phy# set netns and all virtual interfaces will follow (or the operation fails). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 962e223..cb3dc60 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -262,6 +262,9 @@ * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and * %NL80211_ATTR_REASON_CODE attributes are used. * + * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices + * associated with this wiphy must be down and will follow. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -336,6 +339,8 @@ enum nl80211_commands { NL80211_CMD_ROAM, NL80211_CMD_DISCONNECT, + NL80211_CMD_SET_WIPHY_NETNS, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -573,6 +578,8 @@ enum nl80211_commands { * and join_ibss(), key information is in a nested attribute each * with %NL80211_KEY_* sub-attributes * + * @NL80211_ATTR_PID: Process ID of a network namespace. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -701,6 +708,8 @@ enum nl80211_attrs { NL80211_ATTR_KEY, NL80211_ATTR_KEYS, + NL80211_ATTR_PID, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a981ca8..0d27877 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -542,7 +542,7 @@ struct cfg80211_ssid { * @ie: optional information element(s) to add into Probe Request or %NULL * @ie_len: length of ie in octets * @wiphy: the wiphy this was for - * @ifidx: the interface index + * @dev: the interface */ struct cfg80211_scan_request { struct cfg80211_ssid *ssids; @@ -554,7 +554,7 @@ struct cfg80211_scan_request { /* internal */ struct wiphy *wiphy; - int ifidx; + struct net_device *dev; bool aborted; }; @@ -845,7 +845,8 @@ struct cfg80211_bitrate_mask { * @resume: wiphy device needs to be resumed * * @add_virtual_intf: create a new virtual interface with the given name, - * must set the struct wireless_dev's iftype. + * must set the struct wireless_dev's iftype. Beware: You must create + * the new netdev in the wiphy's network namespace! * * @del_virtual_intf: remove the virtual interface determined by ifindex. * @@ -937,7 +938,7 @@ struct cfg80211_ops { int (*add_virtual_intf)(struct wiphy *wiphy, char *name, enum nl80211_iftype type, u32 *flags, struct vif_params *params); - int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); + int (*del_virtual_intf)(struct wiphy *wiphy, struct net_device *dev); int (*change_virtual_intf)(struct wiphy *wiphy, struct net_device *dev, enum nl80211_iftype type, u32 *flags, @@ -1088,6 +1089,9 @@ struct cfg80211_ops { * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold); * -1 = fragmentation disabled, only odd values >= 256 used * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled + * @net: the network namespace this wiphy currently lives in + * @netnsok: if set to false, do not allow changing the netns of this + * wiphy at all */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -1101,6 +1105,8 @@ struct wiphy { bool custom_regulatory; bool strict_regulatory; + bool netnsok; + enum cfg80211_signal_type signal_type; int bss_priv_size; @@ -1139,9 +1145,35 @@ struct wiphy { /* dir in debugfs: ieee80211/ */ struct dentry *debugfsdir; +#ifdef CONFIG_NET_NS + /* the network namespace this phy lives in currently */ + struct net *_net; +#endif + char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; +#ifdef CONFIG_NET_NS +static inline struct net *wiphy_net(struct wiphy *wiphy) +{ + return wiphy->_net; +} + +static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net) +{ + wiphy->_net = net; +} +#else +static inline struct net *wiphy_net(struct wiphy *wiphy) +{ + return &init_net; +} + +static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net) +{ +} +#endif + /** * wiphy_priv - return priv from wiphy * diff --git a/net/core/dev.c b/net/core/dev.c index d6c657e..7134766 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5344,6 +5344,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char out: return err; } +EXPORT_SYMBOL_GPL(dev_change_net_namespace); static int dev_cpu_callback(struct notifier_block *nfb, unsigned long action, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 52928ad..4bbf500 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -57,19 +57,9 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, return 0; } -static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) +static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) { - struct net_device *dev; - struct ieee80211_sub_if_data *sdata; - - /* we're under RTNL */ - dev = __dev_get_by_index(&init_net, ifindex); - if (!dev) - return -ENODEV; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - ieee80211_if_remove(sdata); + ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev)); return 0; } diff --git a/net/wireless/core.c b/net/wireless/core.c index 6891cd0..442c9f3 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -106,7 +106,7 @@ __cfg80211_rdev_from_info(struct genl_info *info) if (info->attrs[NL80211_ATTR_IFINDEX]) { ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); - dev = dev_get_by_index(&init_net, ifindex); + dev = dev_get_by_index(genl_info_net(info), ifindex); if (dev) { if (dev->ieee80211_ptr) byifidx = @@ -151,13 +151,13 @@ cfg80211_get_dev_from_info(struct genl_info *info) } struct cfg80211_registered_device * -cfg80211_get_dev_from_ifindex(int ifindex) +cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) { struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV); struct net_device *dev; mutex_lock(&cfg80211_mutex); - dev = dev_get_by_index(&init_net, ifindex); + dev = dev_get_by_index(net, ifindex); if (!dev) goto out; if (dev->ieee80211_ptr) { @@ -222,6 +222,42 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, return 0; } +int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, + struct net *net) +{ + struct wireless_dev *wdev; + int err = 0; + + if (!rdev->wiphy.netnsok) + return -EOPNOTSUPP; + + list_for_each_entry(wdev, &rdev->netdev_list, list) { + wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; + err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); + if (err) + break; + wdev->netdev->features |= NETIF_F_NETNS_LOCAL; + } + + if (err) { + /* failed -- clean up to old netns */ + net = wiphy_net(&rdev->wiphy); + + list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list, + list) { + wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; + err = dev_change_net_namespace(wdev->netdev, net, + "wlan%d"); + WARN_ON(err); + wdev->netdev->features |= NETIF_F_NETNS_LOCAL; + } + } + + wiphy_net_set(&rdev->wiphy, net); + + return err; +} + static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) { struct cfg80211_registered_device *rdev = data; @@ -375,6 +411,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) rdev->wiphy.dev.class = &ieee80211_class; rdev->wiphy.dev.platform_data = rdev; + wiphy_net_set(&rdev->wiphy, &init_net); + rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev), &rdev->wiphy.dev, RFKILL_TYPE_WLAN, @@ -615,6 +653,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, spin_lock_init(&wdev->event_lock); mutex_lock(&rdev->devlist_mtx); list_add(&wdev->list, &rdev->netdev_list); + /* can only change netns with wiphy */ + dev->features |= NETIF_F_NETNS_LOCAL; + if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, "phy80211")) { printk(KERN_ERR "wireless: failed to add phy80211 " @@ -705,10 +746,32 @@ static struct notifier_block cfg80211_netdev_notifier = { .notifier_call = cfg80211_netdev_notifier_call, }; -static int cfg80211_init(void) +static void __net_exit cfg80211_pernet_exit(struct net *net) +{ + struct cfg80211_registered_device *rdev; + + rtnl_lock(); + mutex_lock(&cfg80211_mutex); + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + if (net_eq(wiphy_net(&rdev->wiphy), net)) + WARN_ON(cfg80211_switch_netns(rdev, &init_net)); + } + mutex_unlock(&cfg80211_mutex); + rtnl_unlock(); +} + +static struct pernet_operations cfg80211_pernet_ops = { + .exit = cfg80211_pernet_exit, +}; + +static int __init cfg80211_init(void) { int err; + err = register_pernet_device(&cfg80211_pernet_ops); + if (err) + goto out_fail_pernet; + err = wiphy_sysfs_init(); if (err) goto out_fail_sysfs; @@ -736,9 +799,10 @@ out_fail_nl80211: out_fail_notifier: wiphy_sysfs_exit(); out_fail_sysfs: + unregister_pernet_device(&cfg80211_pernet_ops); +out_fail_pernet: return err; } - subsys_initcall(cfg80211_init); static void cfg80211_exit(void) @@ -748,5 +812,6 @@ static void cfg80211_exit(void) unregister_netdevice_notifier(&cfg80211_netdev_notifier); wiphy_sysfs_exit(); regulatory_exit(); + unregister_pernet_device(&cfg80211_pernet_ops); } module_exit(cfg80211_exit); diff --git a/net/wireless/core.h b/net/wireless/core.h index 2ec8ddb..4276b70 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -170,7 +170,10 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ extern struct cfg80211_registered_device * -cfg80211_get_dev_from_ifindex(int ifindex); +cfg80211_get_dev_from_ifindex(struct net *net, int ifindex); + +int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, + struct net *net); static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index da450ef..7880a9c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -14,8 +14,10 @@ #include #include #include +#include #include #include +#include #include "core.h" #include "nl80211.h" #include "reg.h" @@ -27,24 +29,26 @@ static struct genl_family nl80211_fam = { .hdrsize = 0, /* no private header */ .version = 1, /* no particular meaning now */ .maxattr = NL80211_ATTR_MAX, + .netnsok = true, }; /* internal helper: get rdev and dev */ -static int get_rdev_dev_by_info_ifindex(struct nlattr **attrs, +static int get_rdev_dev_by_info_ifindex(struct genl_info *info, struct cfg80211_registered_device **rdev, struct net_device **dev) { + struct nlattr **attrs = info->attrs; int ifindex; if (!attrs[NL80211_ATTR_IFINDEX]) return -EINVAL; ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); - *dev = dev_get_by_index(&init_net, ifindex); + *dev = dev_get_by_index(genl_info_net(info), ifindex); if (!*dev) return -ENODEV; - *rdev = cfg80211_get_dev_from_ifindex(ifindex); + *rdev = cfg80211_get_dev_from_ifindex(genl_info_net(info), ifindex); if (IS_ERR(*rdev)) { dev_put(*dev); return PTR_ERR(*rdev); @@ -133,6 +137,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, + [NL80211_ATTR_PID] = { .type = NLA_U32 }, }; /* policy for the attributes */ @@ -532,6 +537,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(deauth, DEAUTHENTICATE); CMD(disassoc, DISASSOCIATE); CMD(join_ibss, JOIN_IBSS); + if (dev->wiphy.netnsok) { + i++; + NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); + } #undef CMD @@ -562,6 +571,8 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) mutex_lock(&cfg80211_mutex); list_for_each_entry(dev, &cfg80211_rdev_list, list) { + if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) + continue; if (++idx <= start) continue; if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, @@ -867,6 +878,8 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * mutex_lock(&cfg80211_mutex); list_for_each_entry(dev, &cfg80211_rdev_list, list) { + if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) + continue; if (wp_idx < wp_start) { wp_idx++; continue; @@ -907,7 +920,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) struct net_device *netdev; int err; - err = get_rdev_dev_by_info_ifindex(info->attrs, &dev, &netdev); + err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); if (err) return err; @@ -975,7 +988,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1098,26 +1111,25 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; - int ifindex, err; + int err; struct net_device *dev; rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; - ifindex = dev->ifindex; - dev_put(dev); if (!rdev->ops->del_virtual_intf) { err = -EOPNOTSUPP; goto out; } - err = rdev->ops->del_virtual_intf(&rdev->wiphy, ifindex); + err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); out: cfg80211_unlock_rdev(rdev); + dev_put(dev); unlock_rtnl: rtnl_unlock(); return err; @@ -1195,7 +1207,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1274,7 +1286,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1333,7 +1345,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1380,7 +1392,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1429,7 +1441,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1516,7 +1528,7 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -1726,13 +1738,13 @@ static int nl80211_dump_station(struct sk_buff *skb, rtnl_lock(); - netdev = __dev_get_by_index(&init_net, ifidx); + netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); if (!netdev) { err = -ENODEV; goto out_rtnl; } - dev = cfg80211_get_dev_from_ifindex(ifidx); + dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); if (IS_ERR(dev)) { err = PTR_ERR(dev); goto out_rtnl; @@ -1791,7 +1803,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -1829,14 +1841,16 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) /* * Get vlan interface making sure it is on the right wiphy. */ -static int get_vlan(struct nlattr *vlanattr, +static int get_vlan(struct genl_info *info, struct cfg80211_registered_device *rdev, struct net_device **vlan) { + struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN]; *vlan = NULL; if (vlanattr) { - *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr)); + *vlan = dev_get_by_index(genl_info_net(info), + nla_get_u32(vlanattr)); if (!*vlan) return -ENODEV; if (!(*vlan)->ieee80211_ptr) @@ -1891,11 +1905,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; - err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan); + err = get_vlan(info, rdev, ¶ms.vlan); if (err) goto out; @@ -2004,11 +2018,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; - err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, ¶ms.vlan); + err = get_vlan(info, rdev, ¶ms.vlan); if (err) goto out; @@ -2079,7 +2093,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2185,13 +2199,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb, rtnl_lock(); - netdev = __dev_get_by_index(&init_net, ifidx); + netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); if (!netdev) { err = -ENODEV; goto out_rtnl; } - dev = cfg80211_get_dev_from_ifindex(ifidx); + dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); if (IS_ERR(dev)) { err = PTR_ERR(dev); goto out_rtnl; @@ -2255,7 +2269,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2314,7 +2328,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2362,7 +2376,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2404,7 +2418,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2455,7 +2469,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2574,7 +2588,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, rtnl_lock(); /* Look up our device */ - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2691,7 +2705,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -2947,7 +2961,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto out_rtnl; @@ -3069,14 +3083,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request->ie_len); } - request->ifidx = dev->ifindex; + request->dev = dev; request->wiphy = &rdev->wiphy; rdev->scan_req = request; err = rdev->ops->scan(&rdev->wiphy, dev, request); - if (!err) + if (!err) { nl80211_send_scan_start(rdev, dev); + dev_hold(dev); + } out_free: if (err) { @@ -3198,11 +3214,11 @@ static int nl80211_dump_scan(struct sk_buff *skb, cb->args[0] = ifidx; } - dev = dev_get_by_index(&init_net, ifidx); + dev = dev_get_by_index(sock_net(skb->sk), ifidx); if (!dev) return -ENODEV; - rdev = cfg80211_get_dev_from_ifindex(ifidx); + rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); if (IS_ERR(rdev)) { err = PTR_ERR(rdev); goto out_put_netdev; @@ -3312,7 +3328,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3448,7 +3464,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3531,7 +3547,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3593,7 +3609,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3666,7 +3682,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3739,7 +3755,7 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -3924,7 +3940,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) return err; rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -4000,7 +4016,7 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) rtnl_lock(); - err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) goto unlock_rtnl; @@ -4024,6 +4040,47 @@ unlock_rtnl: return err; } +static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct net *net; + int err; + u32 pid; + + if (!info->attrs[NL80211_ATTR_PID]) + return -EINVAL; + + pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); + + rtnl_lock(); + + rdev = cfg80211_get_dev_from_info(info); + if (IS_ERR(rdev)) { + err = PTR_ERR(rdev); + goto out; + } + + net = get_net_ns_by_pid(pid); + if (IS_ERR(net)) { + err = PTR_ERR(net); + goto out; + } + + err = 0; + + /* check if anything to do */ + if (net_eq(wiphy_net(&rdev->wiphy), net)) + goto out_put_net; + + err = cfg80211_switch_netns(rdev, net); + out_put_net: + put_net(net); + out: + cfg80211_unlock_rdev(rdev); + rtnl_unlock(); + return err; +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -4257,6 +4314,12 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_SET_WIPHY_NETNS, + .doit = nl80211_wiphy_netns, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { .name = "mlme", @@ -4288,7 +4351,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) return; } - genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_config_mcgrp.id, GFP_KERNEL); } static int nl80211_add_scan_req(struct sk_buff *msg, @@ -4365,7 +4429,8 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); } void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, @@ -4383,7 +4448,8 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); } void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, @@ -4401,7 +4467,8 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); } /* @@ -4450,7 +4517,10 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) return; } - genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL); + rtnl_lock(); + genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, + GFP_KERNEL); + rtnl_unlock(); return; @@ -4486,7 +4556,8 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4553,7 +4624,8 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4611,7 +4683,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4651,7 +4724,8 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4691,7 +4765,8 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, GFP_KERNEL); return; nla_put_failure: @@ -4726,7 +4801,8 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4766,7 +4842,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: @@ -4819,7 +4896,10 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, return; } - genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC); + rcu_read_lock(); + genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, + GFP_ATOMIC); + rcu_read_unlock(); return; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index decc59f..1b578b8 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -32,9 +32,7 @@ void __cfg80211_scan_done(struct work_struct *wk) mutex_lock(&rdev->mtx); request = rdev->scan_req; - dev = dev_get_by_index(&init_net, request->ifidx); - if (!dev) - goto out; + dev = request->dev; /* * This must be before sending the other events! @@ -58,7 +56,6 @@ void __cfg80211_scan_done(struct work_struct *wk) dev_put(dev); - out: cfg80211_unlock_rdev(rdev); wiphy_to_dev(request->wiphy)->scan_req = NULL; kfree(request); @@ -66,17 +63,10 @@ void __cfg80211_scan_done(struct work_struct *wk) void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) { - struct net_device *dev = dev_get_by_index(&init_net, request->ifidx); - if (WARN_ON(!dev)) { - kfree(request); - return; - } - WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); request->aborted = aborted; schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk); - dev_put(dev); } EXPORT_SYMBOL(cfg80211_scan_done); @@ -592,7 +582,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, if (!netif_running(dev)) return -ENETDOWN; - rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); + rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); if (IS_ERR(rdev)) return PTR_ERR(rdev); @@ -617,7 +607,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, } creq->wiphy = wiphy; - creq->ifidx = dev->ifindex; + creq->dev = dev; creq->ssids = (void *)(creq + 1); creq->channels = (void *)(creq->ssids + 1); creq->n_channels = n_channels; @@ -654,8 +644,10 @@ int cfg80211_wext_siwscan(struct net_device *dev, if (err) { rdev->scan_req = NULL; kfree(creq); - } else + } else { nl80211_send_scan_start(rdev, dev); + dev_hold(dev); + } out: cfg80211_unlock_rdev(rdev); return err; @@ -948,7 +940,7 @@ int cfg80211_wext_giwscan(struct net_device *dev, if (!netif_running(dev)) return -ENETDOWN; - rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); + rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); if (IS_ERR(rdev)) return PTR_ERR(rdev); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 82de2d9..a197410 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -86,7 +86,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) wdev->conn->params.ssid_len); request->ssids[0].ssid_len = wdev->conn->params.ssid_len; - request->ifidx = wdev->netdev->ifindex; + request->dev = wdev->netdev; request->wiphy = &rdev->wiphy; rdev->scan_req = request; @@ -95,6 +95,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) if (!err) { wdev->conn->state = CFG80211_CONN_SCANNING; nl80211_send_scan_start(rdev, wdev->netdev); + dev_hold(wdev->netdev); } else { rdev->scan_req = NULL; kfree(request); -- cgit v0.10.2 From a272a720660059c30fa038113b77fa2a096437d9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Jul 2009 00:33:36 +0200 Subject: mac80211: allow using network namespaces This finally opens up the ability to put mac80211 devices into different network namespaces. As long as you don't have sysfs, that is. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 559d698..0cb29df 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -787,6 +787,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, name, ieee80211_if_setup); if (!ndev) return -ENOMEM; + dev_net_set(ndev, wiphy_net(local->hw.wiphy)); ndev->needed_headroom = local->tx_headroom + 4*6 /* four MAC addresses */ diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 3234f37..02cabbf 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -620,6 +620,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, if (!wiphy) return NULL; + wiphy->netnsok = true; wiphy->privid = mac80211_wiphy_privid; /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ -- cgit v0.10.2 From eb87eaac52e916e28bcf3bd5974f3b581f6c0ae9 Mon Sep 17 00:00:00 2001 From: Lars Ericsson Date: Sat, 18 Jul 2009 20:21:52 +0200 Subject: rt2x00: Don't alter rt2x00dev->default_ant rt2x00dev->default_ant should be initialized once by the driver, and should not be changed afterwards. Because rt2x00lib_config_antenna() was using a reference to the struct antenna_setup it actually had the oppurtunity to change the default antenna setting and it actually did that during the validation. Instead of passing a pointer to antenna_setup the entire structure should be copied. Signed-off-by: Lars Ericsson Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index c6e0bcf..3845316 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -124,7 +124,7 @@ enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, } void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) + struct antenna_setup ant) { struct antenna_setup *def = &rt2x00dev->default_ant; struct antenna_setup *active = &rt2x00dev->link.ant.active; @@ -138,10 +138,10 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * might have caused that we restore back to the already * active setting. If that has happened we can quit. */ - ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx); - ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx); + ant.rx = rt2x00lib_config_antenna_check(ant.rx, def->rx); + ant.tx = rt2x00lib_config_antenna_check(ant.tx, def->tx); - if (ant->rx == active->rx && ant->tx == active->tx) + if (ant.rx == active->rx && ant.tx == active->tx) return; /* @@ -156,11 +156,11 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * The latter is required since we need to recalibrate the * noise-sensitivity ratio for the new setup. */ - rt2x00dev->ops->lib->config_ant(rt2x00dev, ant); + rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant); rt2x00link_reset_tuner(rt2x00dev, true); - memcpy(active, ant, sizeof(*ant)); + memcpy(active, &ant, sizeof(ant)); if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 512fa2b..eeb2881 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -88,7 +88,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, struct ieee80211_bss_conf *conf); void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant); + struct antenna_setup ant); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const unsigned int changed_flags); diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 3257075..7991568 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -173,7 +173,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) if (ant->flags & ANTENNA_TX_DIVERSITY) new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; - rt2x00lib_config_antenna(rt2x00dev, &new_ant); + rt2x00lib_config_antenna(rt2x00dev, new_ant); } static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) @@ -213,7 +213,7 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) if (ant->flags & ANTENNA_TX_DIVERSITY) new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; - rt2x00lib_config_antenna(rt2x00dev, &new_ant); + rt2x00lib_config_antenna(rt2x00dev, new_ant); } static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 9d31c23..7de1a2c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -378,7 +378,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) */ if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) rt2x00lib_config_antenna(rt2x00dev, - &rt2x00dev->default_ant); + rt2x00dev->default_ant); /* Turn RX back on */ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); -- cgit v0.10.2 From 58d30d14a1e5fbc3db6351e5af178ba71e2710f0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 22 Jul 2009 10:41:14 -0700 Subject: ath: map TH to FCC3_WORLD TH gets 5 GHz. Cc: David Quan Cc: Michael Green Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 4d0e298..ad6d938 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -450,7 +450,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, {CTRY_SYRIA, NULL1_WORLD, "SY"}, {CTRY_TAIWAN, APL3_FCCA, "TW"}, - {CTRY_THAILAND, NULL1_WORLD, "TH"}, + {CTRY_THAILAND, FCC3_WORLD, "TH"}, {CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, {CTRY_TURKEY, ETSI3_WORLD, "TR"}, -- cgit v0.10.2 From d9db5fa2c5cada8d8c20219ad4bab254e866409d Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Thu, 23 Jul 2009 12:01:50 +0530 Subject: ath9k: Add init values for AR9287 based chipsets. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index f67a2a9..af4a1ba 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -4849,3 +4849,1519 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { {0x00004040, 0x00043007 }, {0x00004044, 0x00000000 }, }; + +/* AR9287 Revision 10 */ +static const u_int32_t ar9287Modes_9287_1_0[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 }, + { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a }, + { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e }, + { 0x00009828, 0x00000000, 0x00000000, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 }, + { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 }, + { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e }, + { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 }, + { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 }, + { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce }, + { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c }, + { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 }, + { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, + { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const u_int32_t ar9287Common_9287_1_0[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000033 }, + { 0x00007020, 0x00000000 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x18487320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d4, 0x00000000 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x000000ff }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00008344, 0x01c81043 }, + { 0x00008360, 0xffffffff }, + { 0x00008364, 0xffffffff }, + { 0x00008368, 0x00000000 }, + { 0x00008370, 0x00000000 }, + { 0x00008374, 0x000000ff }, + { 0x00008378, 0x00000000 }, + { 0x0000837c, 0x00000000 }, + { 0x00008380, 0xffffffff }, + { 0x00008384, 0xffffffff }, + { 0x00008390, 0x0fffffff }, + { 0x00008394, 0x0fffffff }, + { 0x00008398, 0x00000000 }, + { 0x0000839c, 0x00000000 }, + { 0x000083a0, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x0000a84c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x10002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x0000a920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009930, 0x00000000 }, + { 0x0000a930, 0x00000000 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x0108ecff }, + { 0x00009940, 0x14750604 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x00009970, 0x990bb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x0c6f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099c4, 0x06336f77 }, + { 0x000099c8, 0x6af65329 }, + { 0x000099cc, 0x08f186c8 }, + { 0x000099d0, 0x00046384 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x000099fc, 0x00001042 }, + { 0x0000a1f4, 0x00fffeff }, + { 0x0000a1f8, 0x00f5f9ff }, + { 0x0000a1fc, 0xb79f6427 }, + { 0x0000a208, 0x803e4788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x40206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x233f7180 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cdbd380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a264, 0x00418a11 }, + { 0x0000b264, 0x00418a11 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0e79e5c6 }, + { 0x0000b26c, 0x0e79e5c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000b398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x0000a3f0, 0x01036a1e }, + { 0x0000a3f4, 0x00000000 }, + { 0x0000b3f4, 0x00000000 }, + { 0x0000a7d8, 0x00000001 }, + { 0x00007800, 0x00000800 }, + { 0x00007804, 0x6c35ffb0 }, + { 0x00007808, 0x6db6c000 }, + { 0x0000780c, 0x6db6cb30 }, + { 0x00007810, 0x6db6cb6c }, + { 0x00007814, 0x0501e200 }, + { 0x00007818, 0x0094128d }, + { 0x0000781c, 0x976ee392 }, + { 0x00007820, 0xf75ff6fc }, + { 0x00007824, 0x00040000 }, + { 0x00007828, 0xdb003012 }, + { 0x0000782c, 0x04924914 }, + { 0x00007830, 0x21084210 }, + { 0x00007834, 0x00140000 }, + { 0x00007838, 0x0e4548d8 }, + { 0x0000783c, 0x54214514 }, + { 0x00007840, 0x02025820 }, + { 0x00007844, 0x71c0d388 }, + { 0x00007848, 0x934934a8 }, + { 0x00007850, 0x00000000 }, + { 0x00007854, 0x00000800 }, + { 0x00007858, 0x6c35ffb0 }, + { 0x0000785c, 0x6db6c000 }, + { 0x00007860, 0x6db6cb2c }, + { 0x00007864, 0x6db6cb6c }, + { 0x00007868, 0x0501e200 }, + { 0x0000786c, 0x0094128d }, + { 0x00007870, 0x976ee392 }, + { 0x00007874, 0xf75ff6fc }, + { 0x00007878, 0x00040000 }, + { 0x0000787c, 0xdb003012 }, + { 0x00007880, 0x04924914 }, + { 0x00007884, 0x21084210 }, + { 0x00007888, 0x001b6db0 }, + { 0x0000788c, 0x00376b63 }, + { 0x00007890, 0x06db6db6 }, + { 0x00007894, 0x006d8000 }, + { 0x00007898, 0x48100000 }, + { 0x0000789c, 0x00000000 }, + { 0x000078a0, 0x08000000 }, + { 0x000078a4, 0x0007ffd8 }, + { 0x000078a8, 0x0007ffd8 }, + { 0x000078ac, 0x001c0020 }, + { 0x000078b0, 0x000611eb }, + { 0x000078b4, 0x40008080 }, + { 0x000078b8, 0x2a850160 }, +}; + +static const u_int32_t ar9287Modes_tx_gain_9287_1_0[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b }, + { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a }, + { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a }, + { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c }, + { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc }, + { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 }, + { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc }, + { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede }, + { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e }, + { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e }, + { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e }, + { 0x0000a780, 0x00000000, 0x00000000, 0x00000060, 0x00000060, 0x00000060 }, + { 0x0000a784, 0x00000000, 0x00000000, 0x00004062, 0x00004062, 0x00004062 }, + { 0x0000a788, 0x00000000, 0x00000000, 0x00008064, 0x00008064, 0x00008064 }, + { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0a4, 0x0000c0a4, 0x0000c0a4 }, + { 0x0000a790, 0x00000000, 0x00000000, 0x000100b0, 0x000100b0, 0x000100b0 }, + { 0x0000a794, 0x00000000, 0x00000000, 0x000140b2, 0x000140b2, 0x000140b2 }, + { 0x0000a798, 0x00000000, 0x00000000, 0x000180b4, 0x000180b4, 0x000180b4 }, + { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c0f4, 0x0001c0f4, 0x0001c0f4 }, + { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020134, 0x00020134, 0x00020134 }, + { 0x0000a7a4, 0x00000000, 0x00000000, 0x000240fe, 0x000240fe, 0x000240fe }, + { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002813e, 0x0002813e, 0x0002813e }, + { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c17e, 0x0002c17e, 0x0002c17e }, + { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301be, 0x000301be, 0x000301be }, + { 0x0000a7b4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7b8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7bc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7c0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7c4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7c8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7cc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7d0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7d4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 }, +}; + + +static const u_int32_t ar9287Modes_rx_gain_9287_1_0[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c }, + { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c }, + { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac }, + { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c }, + { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c }, + { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c }, + { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c }, + { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c }, + { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac }, + { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd }, + { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca }, + { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda }, + { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb }, + { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf }, + { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 }, + { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 }, +}; + +static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +/* AR9287 Revision 11 */ + +static const u_int32_t ar9287Modes_9287_1_1[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 }, + { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a }, + { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e }, + { 0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001, 0x3a020001 }, + { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 }, + { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 }, + { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e }, + { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 }, + { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 }, + { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce }, + { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c }, + { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 }, + { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, + { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const u_int32_t ar9287Common_9287_1_1[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000033 }, + { 0x00007020, 0x00000000 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x18487320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d4, 0x00000000 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0x88a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x000000ff }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00008344, 0x01c81043 }, + { 0x00008360, 0xffffffff }, + { 0x00008364, 0xffffffff }, + { 0x00008368, 0x00000000 }, + { 0x00008370, 0x00000000 }, + { 0x00008374, 0x000000ff }, + { 0x00008378, 0x00000000 }, + { 0x0000837c, 0x00000000 }, + { 0x00008380, 0xffffffff }, + { 0x00008384, 0xffffffff }, + { 0x00008390, 0x0fffffff }, + { 0x00008394, 0x0fffffff }, + { 0x00008398, 0x00000000 }, + { 0x0000839c, 0x00000000 }, + { 0x000083a0, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x0000a84c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x10002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x0000a920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009930, 0x00000000 }, + { 0x0000a930, 0x00000000 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x0108ecff }, + { 0x00009940, 0x14750604 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x00009970, 0x990bb514 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x0c6f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099c4, 0x06336f77 }, + { 0x000099c8, 0x6af6532f }, + { 0x000099cc, 0x08f186c8 }, + { 0x000099d0, 0x00046384 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x000099fc, 0x00001042 }, + { 0x0000a1f4, 0x00fffeff }, + { 0x0000a1f8, 0x00f5f9ff }, + { 0x0000a1fc, 0xb79f6427 }, + { 0x0000a208, 0x803e4788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x40206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x233f7180 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cdbd380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a264, 0x00418a11 }, + { 0x0000b264, 0x00418a11 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0e79e5c6 }, + { 0x0000b26c, 0x0e79e5c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000b398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x0000a3f0, 0x01036a1e }, + { 0x0000a3f4, 0x00000000 }, + { 0x0000b3f4, 0x00000000 }, + { 0x0000a7d8, 0x000003f1 }, + { 0x00007800, 0x00000800 }, + { 0x00007804, 0x6c35ffc2 }, + { 0x00007808, 0x6db6c000 }, + { 0x0000780c, 0x6db6cb30 }, + { 0x00007810, 0x6db6cb6c }, + { 0x00007814, 0x0501e200 }, + { 0x00007818, 0x0094128d }, + { 0x0000781c, 0x976ee392 }, + { 0x00007820, 0xf75ff6fc }, + { 0x00007824, 0x00040000 }, + { 0x00007828, 0xdb003012 }, + { 0x0000782c, 0x04924914 }, + { 0x00007830, 0x21084210 }, + { 0x00007834, 0x00140000 }, + { 0x00007838, 0x0e4548d8 }, + { 0x0000783c, 0x54214514 }, + { 0x00007840, 0x02025830 }, + { 0x00007844, 0x71c0d388 }, + { 0x00007848, 0x934934a8 }, + { 0x00007850, 0x00000000 }, + { 0x00007854, 0x00000800 }, + { 0x00007858, 0x6c35ffc2 }, + { 0x0000785c, 0x6db6c000 }, + { 0x00007860, 0x6db6cb30 }, + { 0x00007864, 0x6db6cb6c }, + { 0x00007868, 0x0501e200 }, + { 0x0000786c, 0x0094128d }, + { 0x00007870, 0x976ee392 }, + { 0x00007874, 0xf75ff6fc }, + { 0x00007878, 0x00040000 }, + { 0x0000787c, 0xdb003012 }, + { 0x00007880, 0x04924914 }, + { 0x00007884, 0x21084210 }, + { 0x00007888, 0x001b6db0 }, + { 0x0000788c, 0x00376b63 }, + { 0x00007890, 0x06db6db6 }, + { 0x00007894, 0x006d8000 }, + { 0x00007898, 0x48100000 }, + { 0x0000789c, 0x00000000 }, + { 0x000078a0, 0x08000000 }, + { 0x000078a4, 0x0007ffd8 }, + { 0x000078a8, 0x0007ffd8 }, + { 0x000078ac, 0x001c0020 }, + { 0x000078b0, 0x00060aeb }, + { 0x000078b4, 0x40008080 }, + { 0x000078b8, 0x2a850160 }, +}; + +static const u_int32_t ar9287Modes_tx_gain_9287_1_1[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b }, + { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a }, + { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a }, + { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c }, + { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc }, + { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 }, + { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc }, + { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede }, + { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e }, + { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e }, + { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e }, + { 0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062, 0x00000062 }, + { 0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064, 0x00004064 }, + { 0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4, 0x000080a4 }, + { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa, 0x0000c0aa }, + { 0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac, 0x000100ac }, + { 0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4, 0x000140b4 }, + { 0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4, 0x000180f4 }, + { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134, 0x0001c134 }, + { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174, 0x00020174 }, + { 0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c, 0x0002417c }, + { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e, 0x0002817e }, + { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be, 0x0002c1be }, + { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 }, +}; + +static const u_int32_t ar9287Modes_rx_gain_9287_1_1[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c }, + { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c }, + { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac }, + { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c }, + { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c }, + { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c }, + { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c }, + { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c }, + { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac }, + { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd }, + { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca }, + { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda }, + { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb }, + { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf }, + { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 }, + { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 }, +}; + +static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + + -- cgit v0.10.2 From d1eba248469272ae0618288bccf65b24d017f1d2 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Jul 2009 15:31:31 +0530 Subject: mac80211: Add a few 802.11n defines for AMPDU parameters Signed-off-by: Sujith Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 23343ab..21556a2 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -802,6 +802,31 @@ struct ieee80211_ht_cap { #define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03 #define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C +/* + * Maximum length of AMPDU that the STA can receive. + * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) + */ +enum ieee80211_max_ampdu_length_exp { + IEEE80211_HT_MAX_AMPDU_8K = 0, + IEEE80211_HT_MAX_AMPDU_16K = 1, + IEEE80211_HT_MAX_AMPDU_32K = 2, + IEEE80211_HT_MAX_AMPDU_64K = 3 +}; + +#define IEEE80211_HT_MAX_AMPDU_FACTOR 13 + +/* Minimum MPDU start spacing */ +enum ieee80211_min_mpdu_spacing { + IEEE80211_HT_MPDU_DENSITY_NONE = 0, /* No restriction */ + IEEE80211_HT_MPDU_DENSITY_0_25 = 1, /* 1/4 usec */ + IEEE80211_HT_MPDU_DENSITY_0_5 = 2, /* 1/2 usec */ + IEEE80211_HT_MPDU_DENSITY_1 = 3, /* 1 usec */ + IEEE80211_HT_MPDU_DENSITY_2 = 4, /* 2 usec */ + IEEE80211_HT_MPDU_DENSITY_4 = 5, /* 4 usec */ + IEEE80211_HT_MPDU_DENSITY_8 = 6, /* 8 usec */ + IEEE80211_HT_MPDU_DENSITY_16 = 7 /* 16 usec */ +}; + /** * struct ieee80211_ht_info - HT information * -- cgit v0.10.2 From c49fd520d10eb277d94c570f2fdb35d2974a30ee Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Jul 2009 15:32:25 +0530 Subject: ath9k: Trivial fix in Kconfig Update filename for debug information. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 2d79610..0f4a6d8 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -18,6 +18,6 @@ config ATH9K_DEBUG Say Y, if you need ath9k to display debug messages. Pass the debug mask as a module parameter: - modprobe ath9k debug=0x00002000 + modprobe ath9k debug=0x00000200 - Look in ath9k/core.h for possible debug masks + Look in ath9k/debug.h for possible debug masks -- cgit v0.10.2 From 305fe47fb8ac1279f01284c1ba5875fa9a355d22 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Jul 2009 15:32:29 +0530 Subject: ath9k: Fix a sparse warning Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 4ff155e..c039d0a 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2037,7 +2037,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } } -void ath_tx_complete_poll_work(struct work_struct *work) +static void ath_tx_complete_poll_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, tx_complete_work.work); -- cgit v0.10.2 From 9e98ac65a39df54fb0520cd86d1e7373319df00f Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Jul 2009 15:32:34 +0530 Subject: ath9k: Remove redundant HT macros These can be obtained from mac80211. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 751885a..ebcf78b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -194,8 +194,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_MAX 4096 -#define IEEE80211_MIN_AMPDU_BUF 0x8 -#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 #define IEEE80211_WEP_IVLEN 3 #define IEEE80211_WEP_KIDLEN 1 #define IEEE80211_WEP_CRCLEN 4 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3436295..3834678 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -462,7 +462,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) if (sc->sc_flags & SC_OP_TXAGGR) { ath_tx_node_init(sc, an); - an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor); an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); an->last_rssi = ATH_RSSI_DUMMY_MARKER; @@ -888,8 +888,6 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) static void setup_ht_cap(struct ath_softc *sc, struct ieee80211_sta_ht_cap *ht_info) { -#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ -#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ u8 tx_streams, rx_streams; ht_info->ht_supported = true; @@ -898,8 +896,8 @@ static void setup_ht_cap(struct ath_softc *sc, IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_DSSSCCK40; - ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; - ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); -- cgit v0.10.2 From f83da96564b2a2f4ae75ea971b357458e5240b61 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Jul 2009 15:32:37 +0530 Subject: ath9k: Cleanup return values Cleanup aggregation start/stop function interfaces. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index ebcf78b..d816c9d 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -363,9 +363,9 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, void ath_tx_tasklet(struct ath_softc *sc); void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb); bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); -int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tid, u16 *ssn); -int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); +void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn); +void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); /********/ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3834678..b3e07e7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2669,19 +2669,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: - ret = ath_tx_aggr_start(sc, sta, tid, ssn); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to start TX aggregation\n"); - else - ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ath_tx_aggr_start(sc, sta, tid, ssn); + ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: - ret = ath_tx_aggr_stop(sc, sta, tid); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to stop TX aggregation\n"); - + ath_tx_aggr_stop(sc, sta, tid); ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index c039d0a..2c01fda 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -695,25 +695,20 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, status != ATH_AGGR_BAW_CLOSED); } -int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tid, u16 *ssn) +void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn) { struct ath_atx_tid *txtid; struct ath_node *an; an = (struct ath_node *)sta->drv_priv; - - if (sc->sc_flags & SC_OP_TXAGGR) { - txtid = ATH_AN_2_TID(an, tid); - txtid->state |= AGGR_ADDBA_PROGRESS; - ath_tx_pause_tid(sc, txtid); - *ssn = txtid->seq_start; - } - - return 0; + txtid = ATH_AN_2_TID(an, tid); + txtid->state |= AGGR_ADDBA_PROGRESS; + ath_tx_pause_tid(sc, txtid); + *ssn = txtid->seq_start; } -int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) +void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); @@ -723,11 +718,11 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) INIT_LIST_HEAD(&bf_head); if (txtid->state & AGGR_CLEANUP) - return 0; + return; if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { txtid->state &= ~AGGR_ADDBA_PROGRESS; - return 0; + return; } ath_tx_pause_tid(sc, txtid); @@ -756,8 +751,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) txtid->state &= ~AGGR_ADDBA_COMPLETE; ath_tx_flush_tid(sc, txtid); } - - return 0; } void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) -- cgit v0.10.2 From 4ef7084173e22cfdd4bb3aa3858ba8dd5d76f22f Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Jul 2009 15:32:41 +0530 Subject: ath9k: Remove a few redundant variables/macros Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index d816c9d..e2ebf1a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -190,7 +190,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_AGGR_MIN_QDEPTH 2 #define ATH_AMPDU_SUBFRAME_DEFAULT 32 #define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) -#define ATH_AMPDU_LIMIT_DEFAULT ATH_AMPDU_LIMIT_MAX #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_MAX 4096 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2c01fda..6eb2927 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -455,7 +455,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ieee80211_tx_rate *rates; struct ath_tx_info_priv *tx_info_priv; u32 max_4ms_framelen, frmlen; - u16 aggr_limit, legacy = 0, maxampdu; + u16 aggr_limit, legacy = 0; int i; skb = bf->bf_mpdu; @@ -490,16 +490,15 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) return 0; - aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_DEFAULT); + aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX); /* * h/w can accept aggregates upto 16 bit lengths (65535). * The IE, however can hold upto 65536, which shows up here * as zero. Ignore 65536 since we are constrained by hw. */ - maxampdu = tid->an->maxampdu; - if (maxampdu) - aggr_limit = min(aggr_limit, maxampdu); + if (tid->an->maxampdu) + aggr_limit = min(aggr_limit, tid->an->maxampdu); return aggr_limit; } @@ -507,7 +506,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, /* * Returns the number of delimiters to be added to * meet the minimum required mpdudensity. - * caller should make sure that the rate is HT rate . */ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, struct ath_buf *bf, u16 frmlen) @@ -515,7 +513,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, const struct ath_rate_table *rt = sc->cur_rate_table; struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - u32 nsymbits, nsymbols, mpdudensity; + u32 nsymbits, nsymbols; u16 minlen; u8 rc, flags, rix; int width, half_gi, ndelim, mindelim; @@ -537,14 +535,12 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, * on highest rate in rate series (i.e. first rate) to determine * required minimum length for subframe. Take into account * whether high rate is 20 or 40Mhz and half or full GI. - */ - mpdudensity = tid->an->mpdudensity; - - /* + * * If there is no mpdu density restriction, no further calculation * is needed. */ - if (mpdudensity == 0) + + if (tid->an->mpdudensity == 0) return ndelim; rix = tx_info->control.rates[0].idx; @@ -554,9 +550,9 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; if (half_gi) - nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); + nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity); else - nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity); + nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity); if (nsymbols == 0) nsymbols = 1; -- cgit v0.10.2 From 7d3be3cc489176bc7bd23e673b0b4aef597af2b3 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 12:13:41 +0200 Subject: mac80211: refactor the scan code Move the processing of each scan state into its own functions for better readability. This patch does not introduce functional changes. Signed-off-by: Helmut Schaa Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 7482065..71500f1 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -474,13 +474,87 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, return rc; } +static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, + unsigned long *next_delay) +{ + int skip; + struct ieee80211_channel *chan; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + + /* if no more bands/channels left, complete scan */ + if (local->scan_channel_idx >= local->scan_req->n_channels) { + ieee80211_scan_completed(&local->hw, false); + return 1; + } + skip = 0; + chan = local->scan_req->channels[local->scan_channel_idx]; + + if (chan->flags & IEEE80211_CHAN_DISABLED || + (sdata->vif.type == NL80211_IFTYPE_ADHOC && + chan->flags & IEEE80211_CHAN_NO_IBSS)) + skip = 1; + + if (!skip) { + local->scan_channel = chan; + if (ieee80211_hw_config(local, + IEEE80211_CONF_CHANGE_CHANNEL)) + skip = 1; + } + + /* advance state machine to next channel/band */ + local->scan_channel_idx++; + + if (skip) + return 0; + + /* + * Probe delay is used to update the NAV, cf. 11.1.3.2.2 + * (which unfortunately doesn't say _why_ step a) is done, + * but it waits for the probe delay or until a frame is + * received - and the received frame would update the NAV). + * For now, we do not support waiting until a frame is + * received. + * + * In any case, it is not necessary for a passive scan. + */ + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || + !local->scan_req->n_ssids) { + *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + return 0; + } + + *next_delay = IEEE80211_PROBE_DELAY; + local->scan_state = SCAN_SEND_PROBE; + + return 0; +} + +static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, + unsigned long *next_delay) +{ + int i; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + + for (i = 0; i < local->scan_req->n_ssids; i++) + ieee80211_send_probe_req( + sdata, NULL, + local->scan_req->ssids[i].ssid, + local->scan_req->ssids[i].ssid_len, + local->scan_req->ie, local->scan_req->ie_len); + + /* + * After sending probe requests, wait for probe responses + * on the channel. + */ + *next_delay = IEEE80211_CHANNEL_TIME; + local->scan_state = SCAN_SET_CHANNEL; +} + void ieee80211_scan_work(struct work_struct *work) { struct ieee80211_local *local = container_of(work, struct ieee80211_local, scan_work.work); struct ieee80211_sub_if_data *sdata = local->scan_sdata; - struct ieee80211_channel *chan; - int skip, i; unsigned long next_delay = 0; mutex_lock(&local->scan_mtx); @@ -515,65 +589,11 @@ void ieee80211_scan_work(struct work_struct *work) switch (local->scan_state) { case SCAN_SET_CHANNEL: - /* if no more bands/channels left, complete scan */ - if (local->scan_channel_idx >= local->scan_req->n_channels) { - ieee80211_scan_completed(&local->hw, false); + if (ieee80211_scan_state_set_channel(local, &next_delay)) return; - } - skip = 0; - chan = local->scan_req->channels[local->scan_channel_idx]; - - if (chan->flags & IEEE80211_CHAN_DISABLED || - (sdata->vif.type == NL80211_IFTYPE_ADHOC && - chan->flags & IEEE80211_CHAN_NO_IBSS)) - skip = 1; - - if (!skip) { - local->scan_channel = chan; - if (ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_CHANNEL)) - skip = 1; - } - - /* advance state machine to next channel/band */ - local->scan_channel_idx++; - - if (skip) - break; - - /* - * Probe delay is used to update the NAV, cf. 11.1.3.2.2 - * (which unfortunately doesn't say _why_ step a) is done, - * but it waits for the probe delay or until a frame is - * received - and the received frame would update the NAV). - * For now, we do not support waiting until a frame is - * received. - * - * In any case, it is not necessary for a passive scan. - */ - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || - !local->scan_req->n_ssids) { - next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; - break; - } - - next_delay = IEEE80211_PROBE_DELAY; - local->scan_state = SCAN_SEND_PROBE; break; case SCAN_SEND_PROBE: - for (i = 0; i < local->scan_req->n_ssids; i++) - ieee80211_send_probe_req( - sdata, NULL, - local->scan_req->ssids[i].ssid, - local->scan_req->ssids[i].ssid_len, - local->scan_req->ie, local->scan_req->ie_len); - - /* - * After sending probe requests, wait for probe responses - * on the channel. - */ - next_delay = IEEE80211_CHANNEL_TIME; - local->scan_state = SCAN_SET_CHANNEL; + ieee80211_scan_state_send_probe(local, &next_delay); break; } -- cgit v0.10.2 From f502d09b750437a4ec9c63333acf1070fe7958af Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 12:13:48 +0200 Subject: mac80211: advance the state machine immediately if no delay is needed Instead of queueing the scan work again without delay just process the next state immediately. Signed-off-by: Helmut Schaa Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 71500f1..db122e4 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -587,15 +587,21 @@ void ieee80211_scan_work(struct work_struct *work) return; } - switch (local->scan_state) { - case SCAN_SET_CHANNEL: - if (ieee80211_scan_state_set_channel(local, &next_delay)) - return; - break; - case SCAN_SEND_PROBE: - ieee80211_scan_state_send_probe(local, &next_delay); - break; - } + /* + * as long as no delay is required advance immediately + * without scheduling a new work + */ + do { + switch (local->scan_state) { + case SCAN_SET_CHANNEL: + if (ieee80211_scan_state_set_channel(local, &next_delay)) + return; + break; + case SCAN_SEND_PROBE: + ieee80211_scan_state_send_probe(local, &next_delay); + break; + } + } while (next_delay == 0); queue_delayed_work(local->hw.workqueue, &local->scan_work, next_delay); -- cgit v0.10.2 From 2fb3f028a9a46bd344329766257699b4acb36525 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 12:13:56 +0200 Subject: mac80211: introduce a new scan state "decision" Introduce a new scan state "decision" which is entered after every completed scan operation and decides about the next steps. At first the decision is in any case to scan the next channel. This shouldn't introduce any functional changes. Signed-off-by: Helmut Schaa Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6a01771..4166418 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -678,7 +678,7 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; + enum { SCAN_DECISION, SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; struct delayed_work scan_work; struct ieee80211_sub_if_data *scan_sdata; enum nl80211_channel_type oper_channel_type; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index db122e4..48f910a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -376,7 +376,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) } mutex_unlock(&local->iflist_mtx); - local->scan_state = SCAN_SET_CHANNEL; + local->scan_state = SCAN_DECISION; local->scan_channel_idx = 0; spin_lock_bh(&local->filter_lock); @@ -474,18 +474,27 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, return rc; } -static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, - unsigned long *next_delay) +static int ieee80211_scan_state_decision(struct ieee80211_local *local, + unsigned long *next_delay) { - int skip; - struct ieee80211_channel *chan; - struct ieee80211_sub_if_data *sdata = local->scan_sdata; - /* if no more bands/channels left, complete scan */ if (local->scan_channel_idx >= local->scan_req->n_channels) { ieee80211_scan_completed(&local->hw, false); return 1; } + + *next_delay = 0; + local->scan_state = SCAN_SET_CHANNEL; + return 0; +} + +static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, + unsigned long *next_delay) +{ + int skip; + struct ieee80211_channel *chan; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + skip = 0; chan = local->scan_req->channels[local->scan_channel_idx]; @@ -505,7 +514,7 @@ static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, local->scan_channel_idx++; if (skip) - return 0; + return; /* * Probe delay is used to update the NAV, cf. 11.1.3.2.2 @@ -520,13 +529,13 @@ static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || !local->scan_req->n_ssids) { *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; - return 0; + local->scan_state = SCAN_DECISION; + return; } + /* active scan, send probes */ *next_delay = IEEE80211_PROBE_DELAY; local->scan_state = SCAN_SEND_PROBE; - - return 0; } static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, @@ -547,7 +556,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, * on the channel. */ *next_delay = IEEE80211_CHANNEL_TIME; - local->scan_state = SCAN_SET_CHANNEL; + local->scan_state = SCAN_DECISION; } void ieee80211_scan_work(struct work_struct *work) @@ -593,10 +602,13 @@ void ieee80211_scan_work(struct work_struct *work) */ do { switch (local->scan_state) { - case SCAN_SET_CHANNEL: - if (ieee80211_scan_state_set_channel(local, &next_delay)) + case SCAN_DECISION: + if (ieee80211_scan_state_decision(local, &next_delay)) return; break; + case SCAN_SET_CHANNEL: + ieee80211_scan_state_set_channel(local, &next_delay); + break; case SCAN_SEND_PROBE: ieee80211_scan_state_send_probe(local, &next_delay); break; -- cgit v0.10.2 From fbe9c429f195111bbf7f1630efa19aee295fd8e7 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 12:14:04 +0200 Subject: mac80211: Replace {sw, hw}_scanning variables with a bitfield Use a bitfield to store the current scan mode instead of two boolean variables {sw,hw}_scanning. This patch does not introduce functional changes but allows us to enhance the scan flags later (for example for background scanning). Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 8e22200..6e3cca6 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -742,7 +742,7 @@ static void ieee80211_ibss_work(struct work_struct *work) if (!netif_running(sdata->dev)) return; - if (local->sw_scanning || local->hw_scanning) + if (local->scanning) return; if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC)) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4166418..783a125 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -570,6 +570,11 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_SKB_ADD, }; +enum { + SCAN_SW_SCANNING, + SCAN_HW_SCANNING +}; + struct ieee80211_local { /* embed the driver visible part. * don't cast (use the static inlines below), but we keep @@ -668,7 +673,7 @@ struct ieee80211_local { /* Scanning and BSS list */ struct mutex scan_mtx; - bool sw_scanning, hw_scanning; + unsigned long scanning; struct cfg80211_ssid scan_ssid; struct cfg80211_scan_request int_scan_req; struct cfg80211_scan_request *scan_req; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 0cb29df..d79a211 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -518,7 +518,7 @@ static int ieee80211_stop(struct net_device *dev) * the scan_sdata is NULL already don't send out a * scan event to userspace -- the scan is incomplete. */ - if (local->sw_scanning) + if (test_bit(SCAN_SW_SCANNING, &local->scanning)) ieee80211_scan_completed(&local->hw, true); } @@ -920,7 +920,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) struct ieee80211_sub_if_data *sdata; int count = 0; - if (local->hw_scanning || local->sw_scanning) + if (local->scanning) return ieee80211_idle_off(local, "scanning"); list_for_each_entry(sdata, &local->interfaces, list) { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 02cabbf..c1a7991 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -198,7 +198,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (local->sw_scanning) { + if (test_bit(SCAN_SW_SCANNING, &local->scanning)) { sdata->vif.bss_conf.enable_beacon = false; } else { /* diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 8a97b14..9a38269 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -597,7 +597,7 @@ static void ieee80211_mesh_work(struct work_struct *work) if (!netif_running(sdata->dev)) return; - if (local->sw_scanning || local->hw_scanning) + if (local->scanning) return; while ((skb = skb_dequeue(&ifmsh->skb_queue))) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 523c0d9..52b6f83 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -581,7 +581,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, if (!ifmgd->associated) return; - if (sdata->local->sw_scanning || sdata->local->hw_scanning) + if (sdata->local->scanning) return; /* Disregard subsequent beacons if we are already running a timer @@ -639,7 +639,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local, * If we are scanning right now then the parameters will * take effect when scan finishes. */ - if (local->hw_scanning || local->sw_scanning) + if (local->scanning) return; if (conf->dynamic_ps_timeout > 0 && @@ -2038,7 +2038,7 @@ static void ieee80211_sta_work(struct work_struct *work) if (!netif_running(sdata->dev)) return; - if (local->sw_scanning || local->hw_scanning) + if (local->scanning) return; if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) @@ -2213,7 +2213,7 @@ static void ieee80211_sta_monitor_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.monitor_work); - if (sdata->local->sw_scanning || sdata->local->hw_scanning) + if (sdata->local->scanning) return; ieee80211_mgd_probe_ap(sdata, false); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d9df819..9c1679d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -418,10 +418,10 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) struct ieee80211_local *local = rx->local; struct sk_buff *skb = rx->skb; - if (unlikely(local->hw_scanning)) + if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning))) return ieee80211_scan_rx(rx->sdata, skb); - if (unlikely(local->sw_scanning)) { + if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) { /* drop all the other packets during a software scan anyway */ if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) dev_kfree_skb(skb); @@ -2136,7 +2136,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, return; } - if (unlikely(local->sw_scanning || local->hw_scanning)) + if (unlikely(local->scanning)) rx.flags |= IEEE80211_RX_IN_SCAN; ieee80211_parse_qos(&rx); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 48f910a..4233c3d 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -265,7 +265,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) mutex_lock(&local->scan_mtx); - if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) { + if (WARN_ON(!local->scanning)) { mutex_unlock(&local->scan_mtx); return; } @@ -275,16 +275,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) return; } - if (local->hw_scanning) + if (test_bit(SCAN_HW_SCANNING, &local->scanning)) ieee80211_restore_scan_ies(local); if (local->scan_req != &local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; - was_hw_scan = local->hw_scanning; - local->hw_scanning = false; - local->sw_scanning = false; + was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); + local->scanning = 0; local->scan_channel = NULL; /* we only have to protect scan_req and hw/sw scan */ @@ -434,9 +433,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, } if (local->ops->hw_scan) - local->hw_scanning = true; + __set_bit(SCAN_HW_SCANNING, &local->scanning); else - local->sw_scanning = true; + __set_bit(SCAN_SW_SCANNING, &local->scanning); /* * Kicking off the scan need not be protected, * only the scan variable stuff, since now @@ -459,11 +458,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->scan_mtx); if (rc) { - if (local->ops->hw_scan) { - local->hw_scanning = false; + if (local->ops->hw_scan) ieee80211_restore_scan_ies(local); - } else - local->sw_scanning = false; + local->scanning = 0; ieee80211_recalc_idle(local); @@ -572,7 +569,7 @@ void ieee80211_scan_work(struct work_struct *work) return; } - if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) { + if (local->scan_req && !local->scanning) { struct cfg80211_scan_request *req = local->scan_req; int rc; @@ -663,7 +660,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) * queued -- mostly at suspend under RTNL. */ mutex_lock(&local->scan_mtx); - swscan = local->sw_scanning; + swscan = test_bit(SCAN_SW_SCANNING, &local->scanning); mutex_unlock(&local->scan_mtx); if (swscan) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ffd3b10..d7491dc 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -192,7 +192,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) return TX_CONTINUE; - if (unlikely(tx->local->sw_scanning) && + if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) && !ieee80211_is_probe_req(hdr->frame_control) && !ieee80211_is_nullfunc(hdr->frame_control)) /* @@ -552,7 +552,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) * Lets not bother rate control if we're associated and cannot * talk to the sta. This should not happen. */ - if (WARN((tx->local->sw_scanning) && + if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && (sta_flags & WLAN_STA_ASSOC) && !rate_usable_index_exists(sband, &tx->sta->sta), "%s: Dropped data frame as no usable bitrate found while " @@ -1411,7 +1411,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && local->hw.conf.dynamic_ps_timeout > 0 && - !local->sw_scanning && !local->hw_scanning && local->ps_sdata) { + !(local->scanning) && local->ps_sdata) { if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_QUEUE_STOP_REASON_PS); -- cgit v0.10.2 From 142b9f5074dc0d09dc0025739ad437723d7bf527 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 13:18:01 +0200 Subject: mac80211: implement basic background scanning Introduce a new scan flag "SCAN_OFF_CHANNEL" which basically tells us that we are currently on a different channel for scanning and cannot RX/TX. "SCAN_SW_SCANNING" tells us that we are currently running a software scan but we might as well be on the operating channel to RX/TX. While "SCAN_SW_SCANNING" is set during the whole scan "SCAN_OFF_CHANNEL" is set when leaving the operating channel and unset when coming back. Introduce two new scan states "SCAN_LEAVE_OPER_CHANNEL" and "SCAN_ENTER_OPER_CHANNEL" which basically implement the functionality we need to leave the operating channel (send a nullfunc to the AP and stop the queues) and enter it again (send a nullfunc to the AP and start the queues again). Enhance the scan state "SCAN_DECISION" to switch back to the operating channel after each scanned channel. In the future it sould be simple to enhance the decision state to scan as much channels in a row as the qos latency allows us. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 783a125..efda19e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -570,9 +570,41 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_SKB_ADD, }; +/** + * mac80211 scan flags - currently active scan mode + * + * @SCAN_SW_SCANNING: We're currently in the process of scanning but may as + * well be on the operating channel + * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to + * determine if we are on the operating channel or not + * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning, + * gets only set in conjunction with SCAN_SW_SCANNING + */ enum { SCAN_SW_SCANNING, - SCAN_HW_SCANNING + SCAN_HW_SCANNING, + SCAN_OFF_CHANNEL, +}; + +/** + * enum mac80211_scan_state - scan state machine states + * + * @SCAN_DECISION: Main entry point to the scan state machine, this state + * determines if we should keep on scanning or switch back to the + * operating channel + * @SCAN_SET_CHANNEL: Set the next channel to be scanned + * @SCAN_SEND_PROBE: Send probe requests and wait for probe responses + * @SCAN_LEAVE_OPER_CHANNEL: Leave the operating channel, notify the AP + * about us leaving the channel and stop all associated STA interfaces + * @SCAN_ENTER_OPER_CHANNEL: Enter the operating channel again, notify the + * AP about us being back and restart all associated STA interfaces + */ +enum mac80211_scan_state { + SCAN_DECISION, + SCAN_SET_CHANNEL, + SCAN_SEND_PROBE, + SCAN_LEAVE_OPER_CHANNEL, + SCAN_ENTER_OPER_CHANNEL, }; struct ieee80211_local { @@ -683,7 +715,7 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - enum { SCAN_DECISION, SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; + enum mac80211_scan_state scan_state; struct delayed_work scan_work; struct ieee80211_sub_if_data *scan_sdata; enum nl80211_channel_type oper_channel_type; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9c1679d..cb95a31 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -421,7 +421,8 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning))) return ieee80211_scan_rx(rx->sdata, skb); - if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) { + if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) && + (rx->flags & IEEE80211_RX_IN_SCAN))) { /* drop all the other packets during a software scan anyway */ if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) dev_kfree_skb(skb); @@ -2136,7 +2137,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, return; } - if (unlikely(local->scanning)) + if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || + test_bit(SCAN_OFF_CHANNEL, &local->scanning))) rx.flags |= IEEE80211_RX_IN_SCAN; ieee80211_parse_qos(&rx); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 4233c3d..d56b9da 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -365,12 +365,11 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) ieee80211_bss_info_change_notify( sdata, BSS_CHANGED_BEACON_ENABLED); - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.associated) { - netif_tx_stop_all_queues(sdata->dev); - ieee80211_scan_ps_enable(sdata); - } - } else + /* + * only handle non-STA interfaces here, STA interfaces + * are handled in the scan state machine + */ + if (sdata->vif.type != NL80211_IFTYPE_STATION) netif_tx_stop_all_queues(sdata->dev); } mutex_unlock(&local->iflist_mtx); @@ -474,17 +473,113 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, static int ieee80211_scan_state_decision(struct ieee80211_local *local, unsigned long *next_delay) { - /* if no more bands/channels left, complete scan */ + bool associated = false; + struct ieee80211_sub_if_data *sdata; + + /* if no more bands/channels left, complete scan and advance to the idle state */ if (local->scan_channel_idx >= local->scan_req->n_channels) { ieee80211_scan_completed(&local->hw, false); return 1; } + /* check if at least one STA interface is associated */ + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + if (sdata->u.mgd.associated) { + associated = true; + break; + } + } + } + mutex_unlock(&local->iflist_mtx); + + if (local->scan_channel) { + /* + * we're currently scanning a different channel, let's + * switch back to the operating channel now if at least + * one interface is associated. Otherwise just scan the + * next channel + */ + if (associated) + local->scan_state = SCAN_ENTER_OPER_CHANNEL; + else + local->scan_state = SCAN_SET_CHANNEL; + } else { + /* + * we're on the operating channel currently, let's + * leave that channel now to scan another one + */ + local->scan_state = SCAN_LEAVE_OPER_CHANNEL; + } + *next_delay = 0; - local->scan_state = SCAN_SET_CHANNEL; return 0; } +static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, + unsigned long *next_delay) +{ + struct ieee80211_sub_if_data *sdata; + + /* + * notify the AP about us leaving the channel and stop all STA interfaces + */ + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + netif_tx_stop_all_queues(sdata->dev); + if (sdata->u.mgd.associated) + ieee80211_scan_ps_enable(sdata); + } + } + mutex_unlock(&local->iflist_mtx); + + __set_bit(SCAN_OFF_CHANNEL, &local->scanning); + + /* advance to the next channel to be scanned */ + *next_delay = HZ / 10; + local->scan_state = SCAN_SET_CHANNEL; +} + +static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, + unsigned long *next_delay) +{ + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + + /* switch back to the operating channel */ + local->scan_channel = NULL; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + + /* + * notify the AP about us being back and restart all STA interfaces + */ + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + /* Tell AP we're back */ + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + if (sdata->u.mgd.associated) + ieee80211_scan_ps_disable(sdata); + netif_tx_wake_all_queues(sdata->dev); + } + } + mutex_unlock(&local->iflist_mtx); + + __clear_bit(SCAN_OFF_CHANNEL, &local->scanning); + + *next_delay = HZ / 5; + local->scan_state = SCAN_DECISION; +} + static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, unsigned long *next_delay) { @@ -609,6 +704,12 @@ void ieee80211_scan_work(struct work_struct *work) case SCAN_SEND_PROBE: ieee80211_scan_state_send_probe(local, &next_delay); break; + case SCAN_LEAVE_OPER_CHANNEL: + ieee80211_scan_state_leave_oper_channel(local, &next_delay); + break; + case SCAN_ENTER_OPER_CHANNEL: + ieee80211_scan_state_enter_oper_channel(local, &next_delay); + break; } } while (next_delay == 0); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d7491dc..70ff4f0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -192,7 +192,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) return TX_CONTINUE; - if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) && + if (unlikely(test_bit(SCAN_OFF_CHANNEL, &tx->local->scanning)) && !ieee80211_is_probe_req(hdr->frame_control) && !ieee80211_is_nullfunc(hdr->frame_control)) /* -- cgit v0.10.2 From 977923b00c79185c11b4b47664f5ffa4c3820438 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 12:14:20 +0200 Subject: mac80211: rename scan_state to next_scan_state Rename scan_state to next_scan_state to better reflect what it is used for. Signed-off-by: Helmut Schaa Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index efda19e..c6b25cb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -715,7 +715,7 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - enum mac80211_scan_state scan_state; + enum mac80211_scan_state next_scan_state; struct delayed_work scan_work; struct ieee80211_sub_if_data *scan_sdata; enum nl80211_channel_type oper_channel_type; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index d56b9da..b376775 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -374,7 +374,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) } mutex_unlock(&local->iflist_mtx); - local->scan_state = SCAN_DECISION; + local->next_scan_state = SCAN_DECISION; local->scan_channel_idx = 0; spin_lock_bh(&local->filter_lock); @@ -505,15 +505,15 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, * next channel */ if (associated) - local->scan_state = SCAN_ENTER_OPER_CHANNEL; + local->next_scan_state = SCAN_ENTER_OPER_CHANNEL; else - local->scan_state = SCAN_SET_CHANNEL; + local->next_scan_state = SCAN_SET_CHANNEL; } else { /* * we're on the operating channel currently, let's * leave that channel now to scan another one */ - local->scan_state = SCAN_LEAVE_OPER_CHANNEL; + local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL; } *next_delay = 0; @@ -545,7 +545,7 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca /* advance to the next channel to be scanned */ *next_delay = HZ / 10; - local->scan_state = SCAN_SET_CHANNEL; + local->next_scan_state = SCAN_SET_CHANNEL; } static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, @@ -577,7 +577,7 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca __clear_bit(SCAN_OFF_CHANNEL, &local->scanning); *next_delay = HZ / 5; - local->scan_state = SCAN_DECISION; + local->next_scan_state = SCAN_DECISION; } static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, @@ -621,13 +621,13 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || !local->scan_req->n_ssids) { *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; - local->scan_state = SCAN_DECISION; + local->next_scan_state = SCAN_DECISION; return; } /* active scan, send probes */ *next_delay = IEEE80211_PROBE_DELAY; - local->scan_state = SCAN_SEND_PROBE; + local->next_scan_state = SCAN_SEND_PROBE; } static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, @@ -648,7 +648,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, * on the channel. */ *next_delay = IEEE80211_CHANNEL_TIME; - local->scan_state = SCAN_DECISION; + local->next_scan_state = SCAN_DECISION; } void ieee80211_scan_work(struct work_struct *work) @@ -693,7 +693,7 @@ void ieee80211_scan_work(struct work_struct *work) * without scheduling a new work */ do { - switch (local->scan_state) { + switch (local->next_scan_state) { case SCAN_DECISION: if (ieee80211_scan_state_decision(local, &next_delay)) return; -- cgit v0.10.2 From 09f97e0fc4ae81f151bd76b97e28d2af429c1427 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 12:14:29 +0200 Subject: cfg80211: increase scan result expire time Using background scanning in mac80211 the time a scan needs to finish can exceed 10 seconds. Hence, increase the scan results expire time to 15 seconds which should be sufficient. Signed-off-by: Helmut Schaa Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 1b578b8..2a2683f 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -15,7 +15,7 @@ #include "core.h" #include "nl80211.h" -#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) +#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) void __cfg80211_scan_done(struct work_struct *wk) { -- cgit v0.10.2 From 485318471e85c1ddb5e3056fa30fdbbc46d759c6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Jul 2009 16:50:16 +0200 Subject: mac80211: fix mlme timeouts When a new MLME work is created, its timeout is initialised to 0. This is wrong, it could then be thought of as having an actual timeout in the future (time_is_after_jiffies() can return true). Instead, it should be initialised to jiffies so that it will run right away as soon as the mlme work is executed. Signed-off-by: Johannes Berg Reported-by: Luciano Roth Coelho Reported-by: Alban Browaeys Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 52b6f83..807ab89 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2377,6 +2377,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, wk->state = IEEE80211_MGD_STATE_PROBE; wk->auth_alg = auth_alg; + wk->timeout = jiffies; /* run right away */ /* * XXX: if still associated need to tell AP that we're going @@ -2448,6 +2449,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, wk->state = IEEE80211_MGD_STATE_ASSOC; wk->tries = 0; + wk->timeout = jiffies; /* run right away */ if (req->use_mfp) { ifmgd->mfp = IEEE80211_MFP_REQUIRED; -- cgit v0.10.2 From 91a3bd76155085d41520cf41ede39e8b7f01aeff Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 23 Jul 2009 16:37:47 -0700 Subject: mac80211: fix MLME issuing of probe requests while scanning We were issuing probe requests to the associated AP on the wrong band by having our beacon timer loss trigger while we are scanning. When we would scan the timer could hit and force us to send a probe request to the AP but with a chance we'd be on the wrong band. This leads to finding no usable bitrate but we should not get so far on the xmit path. We should not be trying to send these probe request frames so prevent ieee80211_mgd_probe_ap() from sending these. As it turns out all callers of ieee80211_mgd_probe_ap() need this check so we just move the scan check there. This means we can remove the recenlty added check during ieee80211_sta_monitor_work(). Additionally we now fix a race condition added by the patch "mac80211: do not monitor the connection while scanning" which had the same check in ieee80211_sta_conn_mon_timer(). The race happens because the timer routine *does* a valid check for scanning but after it queues work into the mac80211 workqueue the work callback can kick off with scanning enabled and cause the same issue we were trying to avoid. The more appropriate solution would be to disable the respective timers during scan and re-enable them after scan but requires more complex code and testing. Cc: Christian Lamparter Cc: Larry Finger Reported-by: Fabio Rossi Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 807ab89..76c03da 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1166,6 +1166,9 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, if (!netif_running(sdata->dev)) return; + if (sdata->local->scanning) + return; + mutex_lock(&ifmgd->mtx); if (!ifmgd->associated) @@ -2213,9 +2216,6 @@ static void ieee80211_sta_monitor_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.monitor_work); - if (sdata->local->scanning) - return; - ieee80211_mgd_probe_ap(sdata, false); } -- cgit v0.10.2 From 3fa52056f3a8e755708241d5795e6d3e6f55ad85 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jul 2009 13:23:09 +0200 Subject: mac80211: fix PS-poll response, race When a station queries us for a PS-poll response, we wrongly queue the frame on the virtual interface's queue rather than the pending queue. Additionally, fix a race condition where we could potentially send multiple frames to the sleeping station due to using a station flag rather than a packet flag. When converting to a packet flag, we can also convert p54 and remove the filter clearing we added for it. (Also remove a now dead function) Signed-off-by: Johannes Berg Reported-by: Bob Copeland Tested-by: Bob Copeland Cc: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 0d589d6..c32a0d2 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -614,7 +614,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; - if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) + if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE) *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7dd67a1..d4e09a0 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -243,6 +243,9 @@ struct ieee80211_bss_conf { * used to indicate that a frame was already retried due to PS * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, * used to indicate frame should not be encrypted + * @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?) + * This frame is a response to a PS-poll frame and should be sent + * although the station is in powersave mode. */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), @@ -262,6 +265,7 @@ enum mac80211_tx_control_flags { IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), IEEE80211_TX_INTFL_RETRIED = BIT(15), IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), + IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17), }; /** diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index cb95a31..f195705 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -783,7 +783,7 @@ static void ap_sta_ps_start(struct sta_info *sta) struct ieee80211_local *local = sdata->local; atomic_inc(&sdata->bss->num_sta_ps); - set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); + set_sta_flags(sta, WLAN_STA_PS); drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", @@ -799,7 +799,7 @@ static int ap_sta_ps_end(struct sta_info *sta) atomic_dec(&sdata->bss->num_sta_ps); - clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); + clear_sta_flags(sta, WLAN_STA_PS); drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); if (!skb_queue_empty(&sta->ps_tx_buf)) @@ -1117,14 +1117,15 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) skb_queue_empty(&rx->sta->ps_tx_buf); if (skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; /* - * Tell TX path to send one frame even though the STA may + * Tell TX path to send this frame even though the STA may * still remain is PS mode after this frame exchange. */ - set_sta_flags(rx->sta, WLAN_STA_PSPOLL); + info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", @@ -1139,7 +1140,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) else hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - dev_queue_xmit(skb); + ieee80211_add_pending_skb(rx->local, skb); if (no_pending_pkts) sta_info_clear_tim_bit(rx->sta); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4ecf10a..ccc3adf 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -30,7 +30,6 @@ * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP. * @WLAN_STA_WME: Station is a QoS-STA. * @WLAN_STA_WDS: Station is one of our WDS peers. - * @WLAN_STA_PSPOLL: Station has just PS-polled us. * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next * frame to this station is transmitted. @@ -47,7 +46,6 @@ enum ieee80211_sta_info_flags { WLAN_STA_ASSOC_AP = 1<<5, WLAN_STA_WME = 1<<6, WLAN_STA_WDS = 1<<7, - WLAN_STA_PSPOLL = 1<<8, WLAN_STA_CLEAR_PS_FILT = 1<<9, WLAN_STA_MFP = 1<<10, WLAN_STA_SUSPEND = 1<<11 @@ -359,17 +357,6 @@ static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) spin_unlock_irqrestore(&sta->flaglock, irqfl); } -static inline void set_and_clear_sta_flags(struct sta_info *sta, - const u32 set, const u32 clear) -{ - unsigned long irqfl; - - spin_lock_irqsave(&sta->flaglock, irqfl); - sta->flags |= set; - sta->flags &= ~clear; - spin_unlock_irqrestore(&sta->flaglock, irqfl); -} - static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) { u32 ret; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 70ff4f0..edacad1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -373,7 +373,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) staflags = get_sta_flags(sta); if (unlikely((staflags & WLAN_STA_PS) && - !(staflags & WLAN_STA_PSPOLL))) { + !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries " "before %d)\n", @@ -412,24 +412,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta->sta.addr); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) { - /* - * The sleeping station with pending data is now snoozing. - * It queried us for its buffered frames and will go back - * to deep sleep once it got everything. - * - * inform the driver, in case the hardware does powersave - * frame filtering and keeps a station blacklist on its own - * (e.g: p54), so that frames can be delivered unimpeded. - * - * Note: It should be safe to disable the filter now. - * As, it is really unlikely that we still have any pending - * frame for this station in the hw's buffers/fifos left, - * that is not rejected with a unsuccessful tx_status yet. - */ - info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; - } return TX_CONTINUE; } -- cgit v0.10.2 From ac88b6ecdfa629fd1261dab1504d78a56fd4cabf Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Thu, 23 Jul 2009 10:59:57 +0530 Subject: ath9k: Add support for AR9287 based chipsets. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 1f0c5fe..d1bbb02 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -116,7 +116,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, "NF calibrated [ctl] [chain 1] is %d\n", nf); nfarray[1] = nf; - if (!AR_SREV_9280(ah)) { + if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) { nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR); if (nf & 0x100) @@ -154,7 +154,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, "NF calibrated [ext] [chain 1] is %d\n", nf); nfarray[4] = nf; - if (!AR_SREV_9280(ah)) { + if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) { nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR); if (nf & 0x100) @@ -613,7 +613,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) if (AR_SREV_9285(ah)) chainmask = 0x9; - else if (AR_SREV_9280(ah)) + else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) chainmask = 0x1B; else chainmask = 0x3F; @@ -873,7 +873,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9285_11_OR_LATER(ah)) ath9k_hw_9285_pa_cal(ah); - if (OLC_FOR_AR9280_20_LATER) + if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER) ath9k_olc_temp_compensation(ah); ath9k_hw_getnf(ah, chan); ath9k_hw_loadnf(ah, ah->curchan); @@ -929,8 +929,11 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) return false; } else { if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + if (!AR_SREV_9287_10_OR_LATER(ah)) + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, + AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); } /* Calibrate the AGC */ @@ -948,8 +951,11 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) } if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + if (!AR_SREV_9287_10_OR_LATER(ah)) + REG_SET_BIT(ah, AR_PHY_ADC_CTL, + AR_PHY_ADC_CTL_OFF_PWDADC); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); } } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index df41ed5..9b1d960 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -2781,11 +2781,1210 @@ static struct eeprom_ops eep_def_ops = { .get_spur_channel = ath9k_hw_def_get_spur_channel }; + +static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) +{ + return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; +} + +static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) +{ + return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; +} + +static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) +{ + struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + u16 *eep_data; + int addr, eep_start_loc = AR9287_EEP_START_LOC; + eep_data = (u16 *)eep; + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + for (addr = 0; addr < sizeof(struct ar9287_eeprom_t) / sizeof(u16); + addr++) { + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); + return false; + } + eep_data++; + } + return true; +} +static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) +{ +#define SIZE_EEPROM_87 (sizeof(struct ar9287_eeprom_t) / sizeof(u16)) + u32 sum = 0, el, integer; + u16 temp, word, magic, magic2, *eepdata; + int i, addr; + bool need_swap = false; + struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + + if (!ath9k_hw_use_flash(ah)) { + if (!ath9k_hw_nvram_read + (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Reading Magic # failed\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + if (magic != AR5416_EEPROM_MAGIC) { + + + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + need_swap = true; + eepdata = (u16 *)(&ah->eeprom); + + for (addr = 0; addr < SIZE_EEPROM_87; addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; } + } + } + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? + "True" : "False"); + + if (need_swap) + el = swab16(ah->eeprom.map9287.baseEepHeader.length); + else + el = ah->eeprom.map9287.baseEepHeader.length; + + eepdata = (u16 *)(&ah->eeprom); + for (i = 0; i < min(el, SIZE_EEPROM_87); i++) + sum ^= *eepdata++; + + if (need_swap) { + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + integer = swab32(eep->modalHeader.antCtrlCommon); + eep->modalHeader.antCtrlCommon = integer; + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + integer = swab32(eep->modalHeader.antCtrlChain[i]); + eep->modalHeader.antCtrlChain[i] = integer; + } + + for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) { + word = swab16(eep->modalHeader.spurChans[i].spurChan); + eep->modalHeader.spurChans[i].spurChan = word; + } + } + + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER + || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); + return -EINVAL; + } + + return 0; +#undef SIZE_EEPROM_87 +} + +static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) +{ + struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; + u16 ver_minor; + + ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; + switch (param) { + case EEP_NFTHRESH_2: + return pModal->noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_MINOR_REV: + return ver_minor; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_DEV_TYPE: + return pBase->deviceType; + case EEP_OL_PWRCTRL: + return pBase->openLoopPwrCntl; + case EEP_TEMPSENSE_SLOPE: + if (ver_minor >= AR9287_EEP_MINOR_VER_2) + return pBase->tempSensSlope; + else + return 0; + case EEP_TEMPSENSE_SLOPE_PAL_ON: + if (ver_minor >= AR9287_EEP_MINOR_VER_3) + return pBase->tempSensSlopePalOn; + else + return 0; + default: + return 0; + } +} + + +static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq_ar9287 *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ +#define TMP_VAL_VPD_TABLE \ + ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR9287_NUM_PD_GAINS]; + u8 maxPwrT4[AR9287_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; + static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR9287_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), bChans, numPiers, + &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR9287_PD_GAIN_ICEPTS, vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1], + pPwrR[AR9287_PD_GAIN_ICEPTS - 1]); + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR9287_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR9287_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. synth_center, + IS_CHAN_2GHZ(chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = (u16)((maxPwrT4[i] + + minPwrT4[i+1]) / 4); + + pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER, + pPdGainBoundaries[i]); + + + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else + minDelta = 0; + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else + ss = (int16_t)((pPdGainBoundaries[i-1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + + tPdGainOverlap - (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1))) + pPDADCValues[k++] = vpdTableI[i][ss++]; + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR9287_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t) TMP_VAL_VPD_TABLE; + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR9287_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; + i++; + } + + while (k < AR9287_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k-1]; + k++; + } + +#undef TMP_VAL_VPD_TABLE +} + +static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, + u8 *pCalChans, u16 availPiers, + int8_t *pPwr) +{ + u8 pcdac, i = 0; + u16 idxL = 0, idxR = 0, numPiers; + bool match; + struct chan_centers centers; + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + pCalChans, numPiers, + &idxL, &idxR); + + if (match) { + pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; + *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; + } else { + pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; + *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + + pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; + } + + while ((pcdac > ah->originalGain[i]) && + (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) + i++; +} + +static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, + int32_t txPower, u16 chain) +{ + u32 tmpVal; + u32 a; + + tmpVal = REG_READ(ah, 0xa270); + tmpVal = tmpVal & 0xFCFFFFFF; + tmpVal = tmpVal | (0x3 << 24); + REG_WRITE(ah, 0xa270, tmpVal); + + tmpVal = REG_READ(ah, 0xb270); + tmpVal = tmpVal & 0xFCFFFFFF; + tmpVal = tmpVal | (0x3 << 24); + REG_WRITE(ah, 0xb270, tmpVal); + + if (chain == 0) { + tmpVal = REG_READ(ah, 0xa398); + tmpVal = tmpVal & 0xff00ffff; + a = (txPower)&0xff; + tmpVal = tmpVal | (a << 16); + REG_WRITE(ah, 0xa398, tmpVal); + } + + if (chain == 1) { + tmpVal = REG_READ(ah, 0xb398); + tmpVal = tmpVal & 0xff00ffff; + a = (txPower)&0xff; + tmpVal = tmpVal | (a << 16); + REG_WRITE(ah, 0xb398, tmpVal); + } +} + + +static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, + struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) +{ + struct cal_data_per_freq_ar9287 *pRawDataset; + struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + u8 pdadcValues[AR9287_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK]; + u16 numPiers = 0, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0}; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx, diff = 0; + struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader.xpdGain; + if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= + AR9287_EEP_MINOR_VER_2) + pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; + else + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR9287_NUM_2G_CAL_PIERS; + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + pRawDatasetOpenLoop = + (struct cal_data_op_loop_ar9287 *) + pEepData->calPierData2G[0]; + ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; + } + } + + numXpdGain = 0; + for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR9287_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR9287_PD_GAINS_IN_MASK-i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + regChainOffset = i * 0x1000; + if (pEepData->baseEepHeader.txMask & (1 << i)) { + pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *) + pEepData->calPierData2G[i]; + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + int8_t txPower; + ar9287_eeprom_get_tx_gain_index(ah, chan, + pRawDatasetOpenLoop, + pCalBChans, numPiers, + &txPower); + ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i); + } else { + pRawDataset = + (struct cal_data_per_freq_ar9287 *) + pEepData->calPierData2G[i]; + ath9k_hw_get_AR9287_gain_boundaries_pdadcs( + ah, chan, pRawDataset, + pCalBChans, numPiers, + pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + } + + if (i == 0) { + if (!ath9k_hw_AR9287_get_eeprom( + ah, EEP_OL_PWRCTRL)) { + REG_WRITE(ah, AR_PHY_TPCRG5 + + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + } + + if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB != + pEepData->baseEepHeader.pwrTableOffset) { + diff = (u16) + (pEepData->baseEepHeader.pwrTableOffset + - (int32_t)AR9287_PWR_TABLE_OFFSET_DB); + diff *= 2; + + for (j = 0; + j < ((u16)AR9287_NUM_PDADC_VALUES-diff); + j++) + pdadcValues[j] = pdadcValues[j+diff]; + + for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff); + j < AR9287_NUM_PDADC_VALUES; j++) + pdadcValues[j] = + pdadcValues[ + AR9287_NUM_PDADC_VALUES-diff]; + } + if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + regOffset = AR_PHY_BASE + (672 << 2) + + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4*j + 0] + & 0xFF) << 0) | + ((pdadcValues[4*j + 1] + & 0xFF) << 8) | + ((pdadcValues[4*j + 2] + & 0xFF) << 16) | + ((pdadcValues[4*j + 3] + & 0xFF) << 24) ; + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, + pdadcValues[4 * j + 1], + 4 * j + 2, + pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + } + + *pTxPowerIndexOffset = 0; +} + + +static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, + struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, + u16 AntennaReduction, u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ +#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 +#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 + + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, + AR5416_MAX_RATE_POWER }; + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data_ar9287 *rep; + struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, + targetPowerCck = {0, {0, 0, 0, 0} }; + struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} }, + targetPowerCckExt = {0, {0, 0, 0, 0} }; + struct cal_target_power_ht targetPowerHt20, + targetPowerHt40 = {0, {0, 0, 0, 0} }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11g[] = {CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, + CTL_11G_EXT, CTL_2GHT40}; + u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + tx_chainmask = ah->txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], + pEepData->modalHeader.antennaGainCh[1]); + + twiceLargestAntenna = (int16_t)min((AntennaReduction) - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + + scaledPower = min(powerLimit, maxRegAllowedPower); + + switch (ar5416_get_ntxchains(tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + break; + case 3: + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + break; + } + scaledPower = max((u16)0, scaledPower); + + if (IS_CHAN_2GHZ(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - + SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR9287_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d," + "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, + isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); + for (i = 0; (i < AR9287_NUM_CTLS) + && pEepData->ctlIndex[i]; i++) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "LOOP-Ctlidx %d: cfgCtl 0x%2.2x" + "pCtlMode 0x%2.2x ctlIndex 0x%2.2x" + "chan %d chanctl=xxxx\n", + i, cfgCtl, pCtlMode[ctlMode], + pEepData->ctlIndex[i], chan->channel); + + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & + CTL_MODE_M) | SD_NO_CTL))) { + + rep = &(pEepData->ctlData[i]); + twiceMinEdgePower = ath9k_hw_get_max_edge_power( + freq, + rep->ctlEdges[ar5416_get_ntxchains( + tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "MATCH-EE_IDX %d: ch %d is2 %d" + "2xMinEdge %d chainmask %d chains %d\n", + i, freq, IS_CHAN_2GHZ(chan), + twiceMinEdgePower, tx_chainmask, + ar5416_get_ntxchains(tx_chainmask)); + + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) + twiceMaxEdgePower = min( + twiceMaxEdgePower, + twiceMinEdgePower); + else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d" + "sP %d minCtlPwr %d\n", + ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, + scaledPower, minCtlPower); + + + switch (pCtlMode[ctlMode]) { + + case CTL_11B: + for (i = 0; + i < ARRAY_SIZE(targetPowerCck.tPow2x); + i++) { + targetPowerCck.tPow2x[i] = (u8)min( + (u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; + i < ARRAY_SIZE(targetPowerOfdm.tPow2x); + i++) { + targetPowerOfdm.tPow2x[i] = (u8)min( + (u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; + i < ARRAY_SIZE(targetPowerHt20.tPow2x); + i++) { + targetPowerHt20.tPow2x[i] = (u8)min( + (u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = (u8)min( + (u16)targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = (u8)min( + (u16)targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; + i < ARRAY_SIZE(targetPowerHt40.tPow2x); + i++) { + targetPowerHt40.tPow2x[i] = (u8)min( + (u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = + targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = + targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = + targetPowerCck.tPow2x[3]; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) + ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; + + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } +#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN +#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN +} + +static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, u16 cfgCtl, + u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ +#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 +#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 + struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= + AR9287_EEP_MINOR_VER_2) + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + + ath9k_hw_set_AR9287_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); + + + ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset); + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR9287_MAX_RATE_POWER) + ratesArray[i] = AR9287_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; + } + + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0) + ); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0) + ); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0) + ); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0) + ); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0) + ); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0) + ); + + if (IS_CHAN_HT40(chan)) { + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0], 0) + ); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4], 0) + ); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0) + ); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0) + ); + + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0) + ); + } + + + if (IS_CHAN_2GHZ(chan)) + i = rate1l; + else + i = rate6mb; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->regulatory.max_power_level = + ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; + else + ah->regulatory.max_power_level = ratesArray[i]; + + switch (ar5416_get_ntxchains(ah->txchainmask)) { + case 1: + break; + case 2: + ah->regulatory.max_power_level += + INCREASE_MAXPOW_BY_TWO_CHAIN; + break; + case 3: + ah->regulatory.max_power_level += + INCREASE_MAXPOW_BY_THREE_CHAIN; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); + break; + } +} + +static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return; +} + +static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + + u16 antWrites[AR9287_ANT_16S]; + u32 regChainOffset; + u8 txRxAttenLocal; + int i, j, offset_num; + + pModal = &eep->modalHeader; + + antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); + antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); + antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); + antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); + antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); + antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); + antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); + antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); + + offset_num = 8; + + for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); + antWrites[j++] = 0; + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); + antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); + } + + + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + regChainOffset = i * 0x1000; + + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[i]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) + & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + txRxAttenLocal = pModal->txRxAttenCh[i]; + + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, + pModal->bswAtten[i]); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, + txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, + pModal->rxTxMarginCh[i]); + } + + + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); + else + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, pModal->switchSettling); + + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, + AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); + + REG_RMW_FIELD(ah, AR_PHY_CCA, + AR9280_PHY_CCA_THRESH62, pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, + AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1, + AR9287_AN_RF2G3_DB1_S, pModal->db1); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2, + AR9287_AN_RF2G3_DB2_S, pModal->db2); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_CCK, + AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_PSK, + AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_QAM, + AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_PAL_OFF, + AR9287_AN_RF2G3_OB_PAL_OFF_S, + pModal->ob_pal_off); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S, + pModal->db1); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2, + AR9287_AN_RF2G3_DB2_S, pModal->db2); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_CCK, + AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_PSK, + AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_QAM, + AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_PAL_OFF, + AR9287_AN_RF2G3_OB_PAL_OFF_S, + pModal->ob_pal_off); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2, + AR9287_AN_TOP2_XPABIAS_LVL, + AR9287_AN_TOP2_XPABIAS_LVL_S, + pModal->xpaBiasLvl); +} + +static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + + + + +static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + return pModal->antCtrlCommon & 0xFFFF; +} + + +static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, + u16 i, bool is2GHz) +{ +#define EEP_MAP9287_SPURCHAN \ + (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); + + switch (ah->config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = EEP_MAP9287_SPURCHAN; + break; + } + + return spur_val; + +#undef EEP_MAP9287_SPURCHAN +} + +static struct eeprom_ops eep_AR9287_ops = { + .check_eeprom = ath9k_hw_AR9287_check_eeprom, + .get_eeprom = ath9k_hw_AR9287_get_eeprom, + .fill_eeprom = ath9k_hw_AR9287_fill_eeprom, + .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_AR9287_set_board_values, + .set_addac = ath9k_hw_AR9287_set_addac, + .set_txpower = ath9k_hw_AR9287_set_txpower, + .get_spur_channel = ath9k_hw_AR9287_get_spur_channel +}; + + int ath9k_hw_eeprom_attach(struct ath_hw *ah) { int status; - - if (AR_SREV_9285(ah)) { + if (AR_SREV_9287(ah)) { + ah->eep_map = EEP_MAP_AR9287; + ah->eep_ops = &eep_AR9287_ops; + } else if (AR_SREV_9285(ah)) { ah->eep_map = EEP_MAP_4KBITS; ah->eep_ops = &eep_4k_ops; } else { diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 67b8bd12..7ddd016 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -100,6 +100,8 @@ #define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) #define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) +#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_10_OR_LATER(ah) && \ + ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) #define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c #define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 @@ -176,6 +178,57 @@ #define AR9280_TX_GAIN_TABLE_SIZE 22 +#define AR9287_EEP_VER 0xE +#define AR9287_EEP_VER_MINOR_MASK 0xFFF +#define AR9287_EEP_MINOR_VER_1 0x1 +#define AR9287_EEP_MINOR_VER_2 0x2 +#define AR9287_EEP_MINOR_VER_3 0x3 +#define AR9287_EEP_MINOR_VER AR9287_EEP_MINOR_VER_3 +#define AR9287_EEP_MINOR_VER_b AR9287_EEP_MINOR_VER +#define AR9287_EEP_NO_BACK_VER AR9287_EEP_MINOR_VER_1 + +#define AR9287_EEP_START_LOC 128 +#define AR9287_NUM_2G_CAL_PIERS 3 +#define AR9287_NUM_2G_CCK_TARGET_POWERS 3 +#define AR9287_NUM_2G_20_TARGET_POWERS 3 +#define AR9287_NUM_2G_40_TARGET_POWERS 3 +#define AR9287_NUM_CTLS 12 +#define AR9287_NUM_BAND_EDGES 4 +#define AR9287_NUM_PD_GAINS 4 +#define AR9287_PD_GAINS_IN_MASK 4 +#define AR9287_PD_GAIN_ICEPTS 1 +#define AR9287_EEPROM_MODAL_SPURS 5 +#define AR9287_MAX_RATE_POWER 63 +#define AR9287_NUM_PDADC_VALUES 128 +#define AR9287_NUM_RATES 16 +#define AR9287_BCHAN_UNUSED 0xFF +#define AR9287_MAX_PWR_RANGE_IN_HALF_DB 64 +#define AR9287_OPFLAGS_11A 0x01 +#define AR9287_OPFLAGS_11G 0x02 +#define AR9287_OPFLAGS_2G_HT40 0x08 +#define AR9287_OPFLAGS_2G_HT20 0x20 +#define AR9287_OPFLAGS_5G_HT40 0x04 +#define AR9287_OPFLAGS_5G_HT20 0x10 +#define AR9287_EEPMISC_BIG_ENDIAN 0x01 +#define AR9287_EEPMISC_WOW 0x02 +#define AR9287_MAX_CHAINS 2 +#define AR9287_ANT_16S 32 +#define AR9287_custdatasize 20 + +#define AR9287_NUM_ANT_CHAIN_FIELDS 6 +#define AR9287_NUM_ANT_COMMON_FIELDS 4 +#define AR9287_SIZE_ANT_CHAIN_FIELD 2 +#define AR9287_SIZE_ANT_COMMON_FIELD 4 +#define AR9287_ANT_CHAIN_MASK 0x3 +#define AR9287_ANT_COMMON_MASK 0xf +#define AR9287_CHAIN_0_IDX 0 +#define AR9287_CHAIN_1_IDX 1 +#define AR9287_DATA_SZ 32 + +#define AR9287_PWR_TABLE_OFFSET_DB -5 + +#define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1) + enum eeprom_param { EEP_NFTHRESH_5, EEP_NFTHRESH_2, @@ -199,7 +252,11 @@ enum eeprom_param { EEP_OL_PWRCTRL, EEP_RC_CHAIN_MASK, EEP_DAC_HPWR_5G, - EEP_FRAC_N_5G + EEP_FRAC_N_5G, + EEP_DEV_TYPE, + EEP_TEMPSENSE_SLOPE, + EEP_TEMPSENSE_SLOPE_PAL_ON, + EEP_PWR_TABLE_OFFSET }; enum ar5416_rates { @@ -368,6 +425,65 @@ struct modal_eep_4k_header { struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; } __packed; +struct base_eep_ar9287_header { + u16 length; + u16 checksum; + u16 version; + u8 opCapFlags; + u8 eepMisc; + u16 regDmn[2]; + u8 macAddr[6]; + u8 rxMask; + u8 txMask; + u16 rfSilent; + u16 blueToothOptions; + u16 deviceCap; + u32 binBuildNumber; + u8 deviceType; + u8 openLoopPwrCntl; + int8_t pwrTableOffset; + int8_t tempSensSlope; + int8_t tempSensSlopePalOn; + u8 futureBase[29]; +} __packed; + +struct modal_eep_ar9287_header { + u32 antCtrlChain[AR9287_MAX_CHAINS]; + u32 antCtrlCommon; + int8_t antennaGainCh[AR9287_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR9287_MAX_CHAINS]; + u8 rxTxMarginCh[AR9287_MAX_CHAINS]; + int8_t adcDesiredSize; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + int8_t iqCalICh[AR9287_MAX_CHAINS]; + int8_t iqCalQCh[AR9287_MAX_CHAINS]; + u8 pdGainOverlap; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR9287_MAX_CHAINS]; + u8 bswMargin[AR9287_MAX_CHAINS]; + u8 swSettleHt40; + u8 version; + u8 db1; + u8 db2; + u8 ob_cck; + u8 ob_psk; + u8 ob_qam; + u8 ob_pal_off; + u8 futureModal[30]; + struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS]; +} __packed; + + struct cal_data_per_freq { u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; @@ -402,6 +518,29 @@ struct cal_ctl_edges { } __packed; #endif +struct cal_data_op_loop_ar9287 { + u8 pwrPdg[2][5]; + u8 vpdPdg[2][5]; + u8 pcdac[2][5]; + u8 empty[2][5]; +} __packed; + + +struct cal_data_per_freq_ar9287 { + u8 pwrPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; + u8 vpdPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; +} __packed; + +union cal_data_per_freq_ar9287_u { + struct cal_data_op_loop_ar9287 calDataOpen; + struct cal_data_per_freq_ar9287 calDataClose; +} __packed; + +struct cal_ctl_data_ar9287 { + struct cal_ctl_edges + ctlEdges[AR9287_MAX_CHAINS][AR9287_NUM_BAND_EDGES]; +} __packed; + struct cal_ctl_data { struct cal_ctl_edges ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; @@ -461,6 +600,27 @@ struct ar5416_eeprom_4k { u8 padding; } __packed; +struct ar9287_eeprom_t { + struct base_eep_ar9287_header baseEepHeader; + u8 custData[AR9287_DATA_SZ]; + struct modal_eep_ar9287_header modalHeader; + u8 calFreqPier2G[AR9287_NUM_2G_CAL_PIERS]; + union cal_data_per_freq_ar9287_u + calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS]; + struct cal_target_power_leg + calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS]; + struct cal_target_power_leg + calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS]; + u8 ctlIndex[AR9287_NUM_CTLS]; + struct cal_ctl_data_ar9287 ctlData[AR9287_NUM_CTLS]; + u8 padding; +} __packed; + + enum reg_ext_bitmap { REG_EXT_JAPAN_MIDBAND = 1, REG_EXT_FCC_DFS_HT40 = 2, @@ -480,6 +640,7 @@ struct ath9k_country_entry { enum ath9k_eep_map { EEP_MAP_DEFAULT = 0x0, EEP_MAP_4KBITS, + EEP_MAP_AR9287, EEP_MAP_MAX }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 605803a..da32269 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -380,6 +380,9 @@ static const char *ath9k_hw_devname(u16 devid) return "Atheros 9280"; case AR9285_DEVID_PCIE: return "Atheros 9285"; + case AR5416_DEVID_AR9287_PCI: + case AR5416_DEVID_AR9287_PCIE: + return "Atheros 9287"; } return NULL; @@ -660,7 +663,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) && (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && (ah->hw_version.macVersion != AR_SREV_VERSION_9160) && - (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) { + (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && + (!AR_SREV_9285(ah)) && (!AR_SREV_9287(ah))) { DPRINTF(sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, @@ -700,8 +704,37 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, ah->ani_function = ATH9K_ANI_ALL; if (AR_SREV_9280_10_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; + if (AR_SREV_9287_11_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, + ARRAY_SIZE(ar9287Modes_9287_1_1), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1, + ARRAY_SIZE(ar9287Common_9287_1_1), 2); + if (ah->config.pcie_clock_req) + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_off_L1_9287_1_1, + ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2); + else + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_always_on_L1_9287_1_1, + ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1), + 2); + } else if (AR_SREV_9287_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0, + ARRAY_SIZE(ar9287Modes_9287_1_0), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0, + ARRAY_SIZE(ar9287Common_9287_1_0), 2); + + if (ah->config.pcie_clock_req) + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_off_L1_9287_1_0, + ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2); + else + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_always_on_L1_9287_1_0, + ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0), + 2); + } else if (AR_SREV_9285_12_OR_LATER(ah)) { - if (AR_SREV_9285_12_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, ARRAY_SIZE(ar9285Modes_9285_1_2), 6); @@ -842,7 +875,28 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if (ecode != 0) goto bad; - if (AR_SREV_9285_12_OR_LATER(ah)) { + if (AR_SREV_9287_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9287Modes_rx_gain_9287_1_1, + ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6); + else if (AR_SREV_9287_10(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9287Modes_rx_gain_9287_1_0, + ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6); + else if (AR_SREV_9280_20(ah)) + ath9k_hw_init_rxgain_ini(ah); + + if (AR_SREV_9287_11(ah)) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9287Modes_tx_gain_9287_1_1, + ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6); + } else if (AR_SREV_9287_10(ah)) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9287Modes_tx_gain_9287_1_0, + ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6); + } else if (AR_SREV_9280_20(ah)) { + ath9k_hw_init_txgain_ini(ah); + } else if (AR_SREV_9285_12_OR_LATER(ah)) { u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); /* txgain table */ @@ -858,14 +912,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, } - /* rxgain table */ - if (AR_SREV_9280_20(ah)) - ath9k_hw_init_rxgain_ini(ah); - - /* txgain table */ - if (AR_SREV_9280_20(ah)) - ath9k_hw_init_txgain_ini(ah); - ath9k_hw_fill_cap_info(ah); if ((ah->hw_version.devid == AR9280_DEVID_PCI) && @@ -1165,6 +1211,8 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error) case AR9280_DEVID_PCI: case AR9280_DEVID_PCIE: case AR9285_DEVID_PCIE: + case AR5416_DEVID_AR9287_PCI: + case AR5416_DEVID_AR9287_PCIE: ah = ath9k_hw_do_attach(devid, sc, error); break; default: @@ -1341,10 +1389,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, DO_DELAY(regWrites); } - if (AR_SREV_9280(ah)) + if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah)) REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); - if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah)) + if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) || + AR_SREV_9287_10_OR_LATER(ah)) REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); for (i = 0; i < ah->iniCommon.ia_rows; i++) { @@ -2254,6 +2303,16 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9280_10_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); + if (AR_SREV_9287_10_OR_LATER(ah)) { + /* Enable ASYNC FIFO */ + REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, + AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL); + REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO); + REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, + AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET); + REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, + AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET); + } r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width); if (r) return r; @@ -2330,6 +2389,27 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_init_user_settings(ah); + if (AR_SREV_9287_10_OR_LATER(ah)) { + REG_WRITE(ah, AR_D_GBL_IFS_SIFS, + AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR); + REG_WRITE(ah, AR_D_GBL_IFS_SLOT, + AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR); + REG_WRITE(ah, AR_D_GBL_IFS_EIFS, + AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR); + + REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR); + REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR); + + REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER, + AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768); + REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN, + AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL); + } + if (AR_SREV_9287_10_OR_LATER(ah)) { + REG_SET_BIT(ah, AR_PCU_MISC_MODE2, + AR_PCU_MISC_MODE2_ENABLE_AGGWEP); + } + REG_WRITE(ah, AR_STA_ID1, REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); @@ -3644,7 +3724,9 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) if (gpio >= ah->caps.num_gpio_pins) return 0xffffffff; - if (AR_SREV_9285_10_OR_LATER(ah)) + if (AR_SREV_9287_10_OR_LATER(ah)) + return MS_REG_READ(AR9287, gpio) != 0; + else if (AR_SREV_9285_10_OR_LATER(ah)) return MS_REG_READ(AR9285, gpio) != 0; else if (AR_SREV_9280_10_OR_LATER(ah)) return MS_REG_READ(AR928X, gpio) != 0; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 28bffdb..37f7d3d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -42,6 +42,9 @@ #define AR_SUBVENDOR_ID_NEW_A 0x7065 #define AR5416_MAGIC 0x19641014 +#define AR5416_DEVID_AR9287_PCI 0x002D +#define AR5416_DEVID_AR9287_PCIE 0x002E + /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) #define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) @@ -400,6 +403,7 @@ struct ath_hw { union { struct ar5416_eeprom_def def; struct ar5416_eeprom_4k map4k; + struct ar9287_eeprom_t map9287; } eeprom; const struct eeprom_ops *eep_ops; enum ath9k_eep_map eep_map; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b3e07e7..1c648db 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2751,7 +2751,8 @@ static struct { { AR_SREV_VERSION_9100, "9100" }, { AR_SREV_VERSION_9160, "9160" }, { AR_SREV_VERSION_9280, "9280" }, - { AR_SREV_VERSION_9285, "9285" } + { AR_SREV_VERSION_9285, "9285" }, + { AR_SREV_VERSION_9287, "9287" } }; static struct { diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 170c5b3..cd4841b 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -25,6 +25,8 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ + { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ { 0 } }; diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index c70f530..de4fada 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -375,6 +375,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_CHAN_INFO_GAIN 0x9CFC #define AR_PHY_MODE 0xA200 +#define AR_PHY_MODE_ASYNCFIFO 0x80 #define AR_PHY_MODE_AR2133 0x08 #define AR_PHY_MODE_AR5111 0x00 #define AR_PHY_MODE_AR5112 0x08 -- cgit v0.10.2 From 21f5fc75deca63bc41c9d13007d35981d4485622 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 24 Jul 2009 19:57:25 -0400 Subject: mac80211: fix oops due to missing private data This was caused by patch: "mac80211: cooperate more with network namespaces" The version of the patch applied doesn't match Johannes' latest: http://johannes.sipsolutions.net/patches/kernel/all/LATEST/NNN-mac80211-netns.patch The skb->cb virtual interface data wasn't being reset for reuse so ath9k pooped out when trying to dereference the private rate control info from the skb. BUG: unable to handle kernel NULL pointer dereference RIP: 0010:[] ath_tx_rc_status+0x33/0x150 [ath9k] <-- snip etc --> Reported-by: Davide Pesavento Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index edacad1..9e5dff1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1170,13 +1170,15 @@ static int __ieee80211_tx(struct ieee80211_local *local, } ret = drv_tx(local, skb); - info->control.vif = &sdata->vif; if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { dev_kfree_skb(skb); ret = NETDEV_TX_OK; } - if (ret != NETDEV_TX_OK) + if (ret != NETDEV_TX_OK) { + info->control.vif = &sdata->vif; return IEEE80211_TX_AGAIN; + } + *skbp = skb = next; ieee80211_led_tx(local, 1); fragm = true; -- cgit v0.10.2 From e3139fe741b25a0f8a27fd2cdf2ad11734c3d4d3 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:00 -0700 Subject: iwlwifi: revert to active table when rate is not valid When performing rate scaling, if detected that the new rate index is invalid, clear the search_better_tbl flag so it will not be stuck in the loop. Since the search table is already set up in uCode, we need to empty out the the search table; revert back to the "active" rate and throughput info. Also pass the "active" table setup to uCode to make sure the rate scale is functioning correctly. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 6328041..40207dac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2003,6 +2003,25 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta) } /* + * setup rate table in uCode + * return rate_n_flags as used in the table + */ +static u32 rs_update_rate_tbl(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct iwl_scale_tbl_info *tbl, + int index, u8 is_green) +{ + u32 rate; + + /* Update uCode's rate table. */ + rate = rate_n_flags_from_tbl(priv, tbl, index, is_green); + rs_fill_link_cmd(priv, lq_sta, rate); + iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); + + return rate; +} + +/* * Do rate scaling and search for new modulation mode. */ static void rs_rate_scale_perform(struct iwl_priv *priv, @@ -2098,6 +2117,16 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (!((1 << index) & rate_scale_index_msk)) { IWL_ERR(priv, "Current Rate is not valid\n"); + if (lq_sta->search_better_tbl) { + /* revert to active table if search table is not valid*/ + tbl->lq_type = LQ_NONE; + lq_sta->search_better_tbl = 0; + tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + /* get "active" rate info */ + index = iwl_hwrate_to_plcp_idx(tbl->current_rate); + rate = rs_update_rate_tbl(priv, lq_sta, + tbl, index, is_green); + } return; } @@ -2308,11 +2337,9 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, lq_update: /* Replace uCode's rate table for the destination station. */ - if (update_lq) { - rate = rate_n_flags_from_tbl(priv, tbl, index, is_green); - rs_fill_link_cmd(priv, lq_sta, rate); - iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); - } + if (update_lq) + rate = rs_update_rate_tbl(priv, lq_sta, + tbl, index, is_green); /* Should we stay with this modulation mode, or search for a new one? */ rs_stay_in_table(lq_sta); -- cgit v0.10.2 From 672639de13c4db92ed6a47e68043a4317e219902 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:01 -0700 Subject: iwlwifi: critical temperature enter/exit condition If advance thermal throttling is used the driver need to pass both "enter" and "exit" temperature to uCode. Using different critical temperature threshold for legacy and advance thermal throttling management based on the type of thermal throttling method is used except 1000. For 1000, it use advance thermal throttling critical temperature threshold, but with legacy thermal management implementation until ucode has the necessary implementations in place. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index a899be9..80a2818 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -55,13 +55,87 @@ #define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" #define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api) + +/* + * For 1000, use advance thermal throttling critical temperature threshold, + * but legacy thermal management implementation for now. + * This is for the reason of 1000 uCode using advance thermal throttling API + * but not implement ct_kill_exit based on ct_kill exit temperature + * so the thermal throttling will still based on legacy thermal throttling + * management. + * The code here need to be modified once 1000 uCode has the advanced thermal + * throttling algorithm in place + */ +static void iwl1000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; + priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; +} + +static struct iwl_lib_ops iwl1000_lib = { + .set_hw_params = iwl5000_hw_set_hw_params, + .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwl5000_txq_set_sched, + .txq_agg_enable = iwl5000_txq_agg_enable, + .txq_agg_disable = iwl5000_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwl5000_rx_handler_setup, + .setup_deferred_work = iwl5000_setup_deferred_work, + .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, + .load_ucode = iwl5000_load_ucode, + .init_alive_start = iwl5000_init_alive_start, + .alive_notify = iwl5000_alive_notify, + .send_tx_power = iwl5000_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .apm_ops = { + .init = iwl5000_apm_init, + .reset = iwl5000_apm_reset, + .stop = iwl5000_apm_stop, + .config = iwl5000_nic_config, + .set_pwr_src = iwl_set_pwr_src, + }, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_5000_REG_BAND_1_CHANNELS, + EEPROM_5000_REG_BAND_2_CHANNELS, + EEPROM_5000_REG_BAND_3_CHANNELS, + EEPROM_5000_REG_BAND_4_CHANNELS, + EEPROM_5000_REG_BAND_5_CHANNELS, + EEPROM_5000_REG_BAND_24_FAT_CHANNELS, + EEPROM_5000_REG_BAND_52_FAT_CHANNELS + }, + .verify_signature = iwlcore_eeprom_verify_signature, + .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, + .release_semaphore = iwlcore_eeprom_release_semaphore, + .calib_version = iwl5000_eeprom_calib_version, + .query_addr = iwl5000_eeprom_query_addr, + }, + .post_associate = iwl_post_associate, + .isr = iwl_isr_ict, + .config_ap = iwl_config_ap, + .temp_ops = { + .temperature = iwl5000_temperature, + .set_ct_kill = iwl1000_set_ct_threshold, + }, +}; + +static struct iwl_ops iwl1000_ops = { + .lib = &iwl1000_lib, + .hcmd = &iwl5000_hcmd, + .utils = &iwl5000_hcmd_utils, +}; + struct iwl_cfg iwl1000_bgn_cfg = { .name = "1000 Series BGN", .fw_name_pre = IWL1000_FW_PRE, .ucode_api_max = IWL1000_UCODE_API_MAX, .ucode_api_min = IWL1000_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, - .ops = &iwl5000_ops, + .ops = &iwl1000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index c30a1b9..23925bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -776,7 +776,8 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = { static void iwl4965_set_ct_threshold(struct iwl_priv *priv) { /* want Kelvin */ - priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); + priv->hw_params.ct_kill_threshold = + CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY); } /** diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 702db07..076acb1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -91,7 +91,7 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv) } -static int iwl5000_apm_init(struct iwl_priv *priv) +int iwl5000_apm_init(struct iwl_priv *priv) { int ret = 0; @@ -137,7 +137,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv) } /* FIXME: this is identical to 4965 */ -static void iwl5000_apm_stop(struct iwl_priv *priv) +void iwl5000_apm_stop(struct iwl_priv *priv) { unsigned long flags; @@ -156,7 +156,7 @@ static void iwl5000_apm_stop(struct iwl_priv *priv) } -static int iwl5000_apm_reset(struct iwl_priv *priv) +int iwl5000_apm_reset(struct iwl_priv *priv) { int ret = 0; @@ -198,7 +198,7 @@ out: } -static void iwl5000_nic_config(struct iwl_priv *priv) +void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; u16 radio_cfg; @@ -290,7 +290,7 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) return (address & ADDRESS_MSK) + (offset << 1); } -static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv) +u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv) { struct iwl_eeprom_calib_hdr { u8 version; @@ -436,7 +436,7 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = { .nrg_th_ofdm = 95, }; -static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, +const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) { u32 address = eeprom_indirect_address(priv, offset); @@ -447,7 +447,7 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, static void iwl5150_set_ct_threshold(struct iwl_priv *priv) { const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; - s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - + s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) - iwl_temp_calib_to_offset(priv); priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef; @@ -456,7 +456,7 @@ static void iwl5150_set_ct_threshold(struct iwl_priv *priv) static void iwl5000_set_ct_threshold(struct iwl_priv *priv) { /* want Celsius */ - priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; } /* @@ -631,7 +631,7 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv, return ret; } -static int iwl5000_load_ucode(struct iwl_priv *priv) +int iwl5000_load_ucode(struct iwl_priv *priv) { int ret = 0; @@ -658,7 +658,7 @@ static int iwl5000_load_ucode(struct iwl_priv *priv) return ret; } -static void iwl5000_init_alive_start(struct iwl_priv *priv) +void iwl5000_init_alive_start(struct iwl_priv *priv) { int ret = 0; @@ -734,7 +734,7 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv) sizeof(coex_cmd), &coex_cmd); } -static int iwl5000_alive_notify(struct iwl_priv *priv) +int iwl5000_alive_notify(struct iwl_priv *priv) { u32 a; unsigned long flags; @@ -821,7 +821,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) return 0; } -static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) +int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { @@ -892,7 +892,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) /** * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ -static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, +void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt) { @@ -932,7 +932,7 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } -static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, +void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq) { struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; @@ -987,7 +987,7 @@ static void iwl5000_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id) (1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); } -static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, +int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, int tx_fifo, int sta_id, int tid, u16 ssn_idx) { unsigned long flags; @@ -1048,7 +1048,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, return 0; } -static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, +int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || @@ -1091,7 +1091,7 @@ u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask * must be called under priv->lock and mac access */ -static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) +void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) { iwl_write_prph(priv, IWL50_SCD_TXFACT, mask); } @@ -1312,13 +1312,13 @@ u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) return len; } -static void iwl5000_setup_deferred_work(struct iwl_priv *priv) +void iwl5000_setup_deferred_work(struct iwl_priv *priv) { /* in 5000 the tx power calibration is done in uCode */ priv->disable_tx_power_cal = 1; } -static void iwl5000_rx_handler_setup(struct iwl_priv *priv) +void iwl5000_rx_handler_setup(struct iwl_priv *priv) { /* init calibration handlers */ priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = @@ -1329,7 +1329,7 @@ static void iwl5000_rx_handler_setup(struct iwl_priv *priv) } -static int iwl5000_hw_valid_rtc_data_addr(u32 addr) +int iwl5000_hw_valid_rtc_data_addr(u32 addr) { return (addr >= IWL50_RTC_DATA_LOWER_BOUND) && (addr < IWL50_RTC_DATA_UPPER_BOUND); @@ -1381,7 +1381,7 @@ static int iwl5000_send_rxon_assoc(struct iwl_priv *priv) return ret; } -static int iwl5000_send_tx_power(struct iwl_priv *priv) +int iwl5000_send_tx_power(struct iwl_priv *priv) { struct iwl5000_tx_power_dbm_cmd tx_power_cmd; u8 tx_ant_cfg_cmd; @@ -1401,7 +1401,7 @@ static int iwl5000_send_tx_power(struct iwl_priv *priv) NULL); } -static void iwl5000_temperature(struct iwl_priv *priv) +void iwl5000_temperature(struct iwl_priv *priv) { /* store temperature from statistics (in Celsius) */ priv->temperature = le32_to_cpu(priv->statistics.general.temperature); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 26c5d4a..59ff735 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -61,6 +61,63 @@ #define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" #define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api) +static void iwl6000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; + priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; +} + +static struct iwl_lib_ops iwl6000_lib = { + .set_hw_params = iwl5000_hw_set_hw_params, + .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwl5000_txq_set_sched, + .txq_agg_enable = iwl5000_txq_agg_enable, + .txq_agg_disable = iwl5000_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwl5000_rx_handler_setup, + .setup_deferred_work = iwl5000_setup_deferred_work, + .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, + .load_ucode = iwl5000_load_ucode, + .init_alive_start = iwl5000_init_alive_start, + .alive_notify = iwl5000_alive_notify, + .send_tx_power = iwl5000_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .apm_ops = { + .init = iwl5000_apm_init, + .reset = iwl5000_apm_reset, + .stop = iwl5000_apm_stop, + .config = iwl5000_nic_config, + .set_pwr_src = iwl_set_pwr_src, + }, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_5000_REG_BAND_1_CHANNELS, + EEPROM_5000_REG_BAND_2_CHANNELS, + EEPROM_5000_REG_BAND_3_CHANNELS, + EEPROM_5000_REG_BAND_4_CHANNELS, + EEPROM_5000_REG_BAND_5_CHANNELS, + EEPROM_5000_REG_BAND_24_FAT_CHANNELS, + EEPROM_5000_REG_BAND_52_FAT_CHANNELS + }, + .verify_signature = iwlcore_eeprom_verify_signature, + .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, + .release_semaphore = iwlcore_eeprom_release_semaphore, + .calib_version = iwl5000_eeprom_calib_version, + .query_addr = iwl5000_eeprom_query_addr, + }, + .post_associate = iwl_post_associate, + .isr = iwl_isr_ict, + .config_ap = iwl_config_ap, + .temp_ops = { + .temperature = iwl5000_temperature, + .set_ct_kill = iwl6000_set_ct_threshold, + }, +}; + static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = { .get_hcmd_size = iwl5000_get_hcmd_size, .build_addsta_hcmd = iwl5000_build_addsta_hcmd, @@ -70,7 +127,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = { static struct iwl_ops iwl6000_ops = { .ucode = &iwl5000_ucode, - .lib = &iwl5000_lib, + .lib = &iwl6000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl6000_hcmd_utils, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index ebb2fbc..39ede57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2413,6 +2413,13 @@ struct iwl_ct_kill_config { __le32 critical_temperature_R; } __attribute__ ((packed)); +/* 1000, and 6x00 */ +struct iwl_ct_kill_throttling_config { + __le32 critical_temperature_exit; + __le32 reserved; + __le32 critical_temperature_enter; +} __attribute__ ((packed)); + /****************************************************************************** * (8) * Scan Commands, Responses, Notifications: diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6aea026..5ef3c37 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2224,6 +2224,7 @@ EXPORT_SYMBOL(iwl_verify_ucode); void iwl_rf_kill_ct_config(struct iwl_priv *priv) { struct iwl_ct_kill_config cmd; + struct iwl_ct_kill_throttling_config adv_cmd; unsigned long flags; int ret = 0; @@ -2232,9 +2233,26 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); - cmd.critical_temperature_R = - cpu_to_le32(priv->hw_params.ct_kill_threshold); + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_1000: + case CSR_HW_REV_TYPE_6x00: + case CSR_HW_REV_TYPE_6x50: + adv_cmd.critical_temperature_enter = + cpu_to_le32(priv->hw_params.ct_kill_threshold); + adv_cmd.critical_temperature_exit = + cpu_to_le32(priv->hw_params.ct_kill_exit_threshold); + + ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, + sizeof(adv_cmd), &adv_cmd); + break; + default: + cmd.critical_temperature_R = + cpu_to_le32(priv->hw_params.ct_kill_threshold); + ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, + sizeof(cmd), &cmd); + break; + } ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); if (ret) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0751891..cddf173 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -63,6 +63,8 @@ extern struct iwl_cfg iwl6050_2agn_cfg; extern struct iwl_cfg iwl6050_3agn_cfg; extern struct iwl_cfg iwl1000_bgn_cfg; +struct iwl_tx_queue; + /* shared structures from iwl-5000.c */ extern struct iwl_mod_params iwl50_mod_params; extern struct iwl_ops iwl5000_ops; @@ -79,9 +81,37 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags); extern int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp); +extern int iwl5000_apm_init(struct iwl_priv *priv); +extern void iwl5000_apm_stop(struct iwl_priv *priv); +extern int iwl5000_apm_reset(struct iwl_priv *priv); +extern void iwl5000_nic_config(struct iwl_priv *priv); +extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv); +extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, + size_t offset); +extern void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + u16 byte_cnt); +extern void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq); +extern int iwl5000_load_ucode(struct iwl_priv *priv); +extern void iwl5000_init_alive_start(struct iwl_priv *priv); +extern int iwl5000_alive_notify(struct iwl_priv *priv); +extern int iwl5000_hw_set_hw_params(struct iwl_priv *priv); +extern int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, + int tx_fifo, int sta_id, int tid, u16 ssn_idx); +extern int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, + u16 ssn_idx, u8 tx_fifo); +extern void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask); +extern void iwl5000_setup_deferred_work(struct iwl_priv *priv); +extern void iwl5000_rx_handler_setup(struct iwl_priv *priv); +extern int iwl5000_hw_valid_rtc_data_addr(u32 addr); +extern int iwl5000_send_tx_power(struct iwl_priv *priv); +extern void iwl5000_temperature(struct iwl_priv *priv); /* CT-KILL constants */ -#define CT_KILL_THRESHOLD 110 /* in Celsius */ +#define CT_KILL_THRESHOLD_LEGACY 110 /* in Celsius */ +#define CT_KILL_THRESHOLD 114 /* in Celsius */ +#define CT_KILL_EXIT_THRESHOLD 95 /* in Celsius */ /* Default noise level to report when noise measurement is not available. * This may be because we're: @@ -630,6 +660,8 @@ struct iwl_hw_params { u32 max_data_size; u32 max_bsm_size; u32 ct_kill_threshold; /* value in hw-dependent units */ + u32 ct_kill_exit_threshold; /* value in hw-dependent units */ + /* for 1000, 6000 series and up */ u32 calib_init_cfg; const struct iwl_sensitivity_ranges *sens; }; -- cgit v0.10.2 From 39b73fb15e4704fd4d1e33688135810637f5f3fb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:02 -0700 Subject: iwlwifi: Thermal Throttling Management - Part 1 Part 1 of Thermal Throttling Management - Thermal Throttling feature is used to put NIC into low power state when driver detect the Radio temperature reach pre-defined threshold Two Thermal Throttling Management Methods; this patch introduce the Legacy Thermal Management: IWL_TI_0: normal temperature, system power state IWL_TI_1: high temperature detect, low power state IWL_TI_2: higher temperature detected, lower power state IWL_TI_CT_KILL: critical temperature detected, lowest power state Once get into CT_KILL state, uCode go into sleep, driver will stop all the active queues, then move to IWL_TI_CT_KILL state; also set up 5 seconds timer to toggle CSR flag, uCode wake up upon CSR flag change, then measure the temperature. If temperature is above CT_KILL exit threshold, uCode go backto sleep; if temperature is below CT_KILL exit threshold, uCode send Card State Notification response with appropriate CT_KILL status flag, and uCode remain awake, Driver receive Card State Notification Response and update the card temperature to the CT_KILL exit threshold. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 23925bd..6702148 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1797,6 +1797,7 @@ static void iwl4965_temperature_calib(struct iwl_priv *priv) } priv->temperature = temp; + iwl_tt_handler(priv); set_bit(STATUS_TEMPERATURE, &priv->status); if (!priv->disable_tx_power_cal && diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 076acb1..ddd64fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1405,6 +1405,7 @@ void iwl5000_temperature(struct iwl_priv *priv) { /* store temperature from statistics (in Celsius) */ priv->temperature = le32_to_cpu(priv->statistics.general.temperature); + iwl_tt_handler(priv); } static void iwl5150_temperature(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 44c7f23..23ae991 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -637,7 +637,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; - unsigned long reg_flags; IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", (flags & HW_CARD_DISABLED) ? "Kill" : "On", @@ -657,19 +656,12 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); iwl_write_direct32(priv, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - - } - - if (flags & RF_CARD_DISABLED) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - iwl_read32(priv, CSR_UCODE_DRV_GP1); - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } + if (flags & RF_CARD_DISABLED) + iwl_tt_enter_ct_kill(priv); } + if (!(flags & RF_CARD_DISABLED)) + iwl_tt_exit_ct_kill(priv); if (flags & HW_CARD_DISABLED) set_bit(STATUS_RF_KILL_HW, &priv->status); @@ -3015,6 +3007,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) test_bit(STATUS_RF_KILL_HW, &priv->status)); iwl_power_initialize(priv); + iwl_tt_initialize(priv); return 0; out_remove_sysfs: @@ -3067,6 +3060,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_down(priv); } + iwl_tt_exit(priv); + /* make sure we flush any pending irq or * tasklet for the driver */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5ef3c37..d8aeb24 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2232,6 +2232,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); + priv->power_data.ct_kill_toggle = false; switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_1000: diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index f2ea3f0..d7fdb58 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -36,6 +36,7 @@ #include "iwl-eeprom.h" #include "iwl-dev.h" #include "iwl-core.h" +#include "iwl-io.h" #include "iwl-commands.h" #include "iwl-debug.h" #include "iwl-power.h" @@ -211,6 +212,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) { struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; + struct iwl_tt_mgmt *tt = &priv->power_data.tt; u16 uninitialized_var(final_mode); bool update_chains; @@ -223,6 +225,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) if (setting->power_disabled) final_mode = IWL_POWER_MODE_CAM; + if (tt->state >= IWL_TI_1) { + /* TT power setting overwrite user & system power setting */ + final_mode = tt->tt_power_mode; + } if (iwl_is_ready_rf(priv) && ((setting->power_mode != final_mode) || force)) { struct iwl_powertable_cmd cmd; @@ -267,6 +273,249 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) } EXPORT_SYMBOL(iwl_power_set_user_mode); +#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ + +/* + * toggle the bit to wake up uCode and check the temperature + * if the temperature is below CT, uCode will stay awake and send card + * state notification with CT_KILL bit clear to inform Thermal Throttling + * Management to change state. Otherwise, uCode will go back to sleep + * without doing anything, driver should continue the 5 seconds timer + * to wake up uCode for temperature check until temperature drop below CT + */ +static void iwl_tt_check_exit_ct_kill(unsigned long data) +{ + struct iwl_priv *priv = (struct iwl_priv *)data; + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + unsigned long flags; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (tt->state == IWL_TI_CT_KILL) { + if (priv->power_data.ct_kill_toggle) { + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + priv->power_data.ct_kill_toggle = false; + } else { + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + priv->power_data.ct_kill_toggle = true; + } + iwl_read32(priv, CSR_UCODE_DRV_GP1); + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + + /* Reschedule the ct_kill timer to occur in + * CT_KILL_EXIT_DURATION seconds to ensure we get a + * thermal update */ + mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + + CT_KILL_EXIT_DURATION * HZ); + } +} + +static void iwl_perform_ct_kill_task(struct iwl_priv *priv, + bool stop) +{ + if (stop) { + IWL_DEBUG_POWER(priv, "Stop all queues\n"); + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + IWL_DEBUG_POWER(priv, + "Schedule 5 seconds CT_KILL Timer\n"); + mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + + CT_KILL_EXIT_DURATION * HZ); + } else { + IWL_DEBUG_POWER(priv, "Wake all queues\n"); + if (priv->mac80211_registered) + ieee80211_wake_queues(priv->hw); + } +} + +#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY) +#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100) +#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90) + +/* + * Legacy thermal throttling + * 1) Avoid NIC destruction due to high temperatures + * Chip will identify dangerously high temperatures that can + * harm the device and will power down + * 2) Avoid the NIC power down due to high temperature + * Throttle early enough to lower the power consumption before + * drastic steps are needed + */ +static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + enum iwl_tt_state new_state; + struct iwl_power_mgr *setting = &priv->power_data; + +#ifdef CONFIG_IWLWIFI_DEBUG + if ((tt->tt_previous_temp) && + (temp > tt->tt_previous_temp) && + ((temp - tt->tt_previous_temp) > + IWL_TT_INCREASE_MARGIN)) { + IWL_DEBUG_POWER(priv, + "Temperature increase %d degree Celsius\n", + (temp - tt->tt_previous_temp)); + } +#endif + /* in Celsius */ + if (temp >= IWL_MINIMAL_POWER_THRESHOLD) + new_state = IWL_TI_CT_KILL; + else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2) + new_state = IWL_TI_2; + else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1) + new_state = IWL_TI_1; + else + new_state = IWL_TI_0; + +#ifdef CONFIG_IWLWIFI_DEBUG + tt->tt_previous_temp = temp; +#endif + if (tt->state != new_state) { + if (tt->state == IWL_TI_0) { + tt->sys_power_mode = setting->power_mode; + IWL_DEBUG_POWER(priv, "current power mode: %u\n", + setting->power_mode); + } + switch (new_state) { + case IWL_TI_0: + /* when system ready to go back to IWL_TI_0 state + * using system power mode instead of TT power mode + * revert back to the orginal power mode which was saved + * before enter Thermal Throttling state + * update priv->power_data.user_power_setting to the + * required power mode to make sure + * iwl_power_update_mode() will update power correctly. + */ + priv->power_data.user_power_setting = + tt->sys_power_mode; + tt->tt_power_mode = tt->sys_power_mode; + break; + case IWL_TI_1: + tt->tt_power_mode = IWL_POWER_INDEX_3; + break; + case IWL_TI_2: + tt->tt_power_mode = IWL_POWER_INDEX_4; + break; + default: + tt->tt_power_mode = IWL_POWER_INDEX_5; + break; + } + if (iwl_power_update_mode(priv, true)) { + /* TT state not updated + * try again during next temperature read + */ + IWL_ERR(priv, "Cannot update power mode, " + "TT state not updated\n"); + } else { + if (new_state == IWL_TI_CT_KILL) + iwl_perform_ct_kill_task(priv, true); + else if (tt->state == IWL_TI_CT_KILL && + new_state != IWL_TI_CT_KILL) + iwl_perform_ct_kill_task(priv, false); + tt->state = new_state; + IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", + tt->state); + IWL_DEBUG_POWER(priv, "Power Index change to %u\n", + tt->tt_power_mode); + } + } +} + +/* Card State Notification indicated reach critical temperature + * if PSP not enable, no Thermal Throttling function will be performed + * just set the GP1 bit to acknowledge the event + * otherwise, go into IWL_TI_CT_KILL state + * since Card State Notification will not provide any temperature reading + * so just pass the CT_KILL temperature to iwl_legacy_tt_handler() + */ +void iwl_tt_enter_ct_kill(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (tt->state != IWL_TI_CT_KILL) { + IWL_ERR(priv, "Device reached critical temperature " + "- ucode going to sleep!\n"); + iwl_legacy_tt_handler(priv, IWL_MINIMAL_POWER_THRESHOLD); + } +} +EXPORT_SYMBOL(iwl_tt_enter_ct_kill); + +/* Card State Notification indicated out of critical temperature + * since Card State Notification will not provide any temperature reading + * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature + * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state + */ +void iwl_tt_exit_ct_kill(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + /* stop ct_kill_exit_tm timer */ + del_timer_sync(&priv->power_data.ct_kill_exit_tm); + + if (tt->state == IWL_TI_CT_KILL) { + IWL_ERR(priv, + "Device temperature below critical" + "- ucode awake!\n"); + iwl_legacy_tt_handler(priv, + IWL_REDUCED_PERFORMANCE_THRESHOLD_2); + } +} +EXPORT_SYMBOL(iwl_tt_exit_ct_kill); + +void iwl_tt_handler(struct iwl_priv *priv) +{ + s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) + temp = KELVIN_TO_CELSIUS(priv->temperature); + + iwl_legacy_tt_handler(priv, temp); +} +EXPORT_SYMBOL(iwl_tt_handler); + +/* Thermal throttling initialization + */ +void iwl_tt_initialize(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_power_mgr *setting = &priv->power_data; + + IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n"); + + memset(tt, 0, sizeof(struct iwl_tt_mgmt)); + + tt->state = IWL_TI_0; + tt->sys_power_mode = setting->power_mode; + tt->tt_power_mode = tt->sys_power_mode; + init_timer(&priv->power_data.ct_kill_exit_tm); + priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; + priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; +} +EXPORT_SYMBOL(iwl_tt_initialize); + +/* cleanup thermal throttling management related memory and timer */ +void iwl_tt_exit(struct iwl_priv *priv) +{ + /* stop ct_kill_exit_tm timer if activated */ + del_timer_sync(&priv->power_data.ct_kill_exit_tm); +} +EXPORT_SYMBOL(iwl_tt_exit); + /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 37ba3bb..7bb10d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -33,6 +33,38 @@ struct iwl_priv; +#define IWL_TT_INCREASE_MARGIN 5 + +/* Thermal Throttling State Machine states */ +enum iwl_tt_state { + IWL_TI_0, /* normal temperature, system power state */ + IWL_TI_1, /* high temperature detect, low power state */ + IWL_TI_2, /* higher temperature detected, lower power state */ + IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */ + IWL_TI_STATE_MAX +}; + +/** + * struct iwl_tt_mgnt - Thermal Throttling Management structure + * @state: current Thermal Throttling state + * @tt_power_mode: Thermal Throttling power mode index + * being used to set power level when + * when thermal throttling state != IWL_TI_0 + * the tt_power_mode should set to different + * power mode based on the current tt state + * @sys_power_mode: previous system power mode + * before transition into TT state + * @tt_previous_temperature: last measured temperature + */ +struct iwl_tt_mgmt { + enum iwl_tt_state state; + u8 tt_power_mode; + u8 sys_power_mode; +#ifdef CONFIG_IWLWIFI_DEBUG + s32 tt_previous_temp; +#endif +}; + enum { IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */ IWL_POWER_INDEX_1, @@ -59,10 +91,20 @@ struct iwl_power_mgr { u8 power_mode; u8 user_power_setting; /* set by user through sysfs */ u8 power_disabled; /* set by mac80211's CONF_PS */ + struct iwl_tt_mgmt tt; /* Thermal Throttling Management */ + bool ct_kill_toggle; /* use to toggle the CSR bit when + * checking uCode temperature + */ + struct timer_list ct_kill_exit_tm; }; int iwl_power_update_mode(struct iwl_priv *priv, bool force); int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); +void iwl_tt_enter_ct_kill(struct iwl_priv *priv); +void iwl_tt_exit_ct_kill(struct iwl_priv *priv); +void iwl_tt_handler(struct iwl_priv *priv); +void iwl_tt_initialize(struct iwl_priv *priv); +void iwl_tt_exit(struct iwl_priv *priv); void iwl_power_initialize(struct iwl_priv *priv); #endif /* __iwl_power_setting_h__ */ -- cgit v0.10.2 From 46f9381aa3fb62f6a141bfd41dcbeda1ec5fa26e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:03 -0700 Subject: iwlwifi: Thermal Throttling Management - part 2 Part 2 of Thermal Throttling Management - Thermal Throttling feature is used to put NIC into low power state when driver detect the Radio temperature reach pre-defined threshold Two Thermal Throttling Management Methods; this patch introduce the Advance Thermal Throttling: TI-0: system power index, no tx/rx restriction, HT enabled TI-1: power index 5, 1 spatial stream Tx, multiple spatial stream Rx, HT enabled TI-2: power index 5: 1 spatial stream Tx, 1 spatial stream Rx, HT disabled TI-CT-KILL: power index 5, no Tx, no Rx, HT disabled For advance Thermal Throttling, CT_KILL_ENTER threshold and CT_KILL_EXIT threshold are different; uCode will not stay awake until reach CT_KILL_EXIT threshold. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 40207dac..52a4810 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -177,7 +177,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, struct sk_buff *skb, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta); -static void rs_fill_link_cmd(const struct iwl_priv *priv, +static void rs_fill_link_cmd(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, u32 rate_n_flags); @@ -1398,6 +1398,12 @@ static int rs_move_legacy_other(struct iwl_priv *priv, int ret = 0; u8 update_search_tbl_counter = 0; + if (!iwl_ht_enabled(priv)) + /* stay in Legacy */ + tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; + else if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && + tbl->action > IWL_LEGACY_SWITCH_SISO) + tbl->action = IWL_LEGACY_SWITCH_SISO; for (; ;) { lq_sta->action_counter++; switch (tbl->action) { @@ -1529,6 +1535,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, u8 update_search_tbl_counter = 0; int ret; + if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && + tbl->action > IWL_SISO_SWITCH_ANTENNA2) { + /* stay in SISO */ + tbl->action = IWL_SISO_SWITCH_ANTENNA1; + } for (;;) { lq_sta->action_counter++; switch (tbl->action) { @@ -1663,6 +1674,12 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, u8 update_search_tbl_counter = 0; int ret; + if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && + (tbl->action < IWL_MIMO2_SWITCH_SISO_A || + tbl->action > IWL_MIMO2_SWITCH_SISO_C)) { + /* switch in SISO */ + tbl->action = IWL_MIMO2_SWITCH_SISO_A; + } for (;;) { lq_sta->action_counter++; switch (tbl->action) { @@ -1799,6 +1816,12 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, int ret; u8 update_search_tbl_counter = 0; + if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && + (tbl->action < IWL_MIMO3_SWITCH_SISO_A || + tbl->action > IWL_MIMO3_SWITCH_SISO_C)) { + /* switch in SISO */ + tbl->action = IWL_MIMO3_SWITCH_SISO_A; + } for (;;) { lq_sta->action_counter++; switch (tbl->action) { @@ -2178,8 +2201,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, tbl->expected_tpt[index] + 64) / 128)); /* If we are searching for better modulation mode, check success. */ - if (lq_sta->search_better_tbl) { - + if (lq_sta->search_better_tbl && + (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI)) { /* If good success, continue using the "search" mode; * no need to send new link quality command, since we're * continuing to use the setup that we've been trying. */ @@ -2307,7 +2330,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, ((sr > IWL_RATE_HIGH_TH) || (current_tpt > (100 * tbl->expected_tpt[low])))) scale_action = 0; - + if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type)) + scale_action = -1; + if (iwl_tx_ant_restriction(priv) != IWL_TX_MULTI && + (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) + scale_action = -1; switch (scale_action) { case -1: /* Decrease starting rate, update uCode's rate table */ @@ -2341,9 +2368,11 @@ lq_update: rate = rs_update_rate_tbl(priv, lq_sta, tbl, index, is_green); - /* Should we stay with this modulation mode, or search for a new one? */ - rs_stay_in_table(lq_sta); - + if (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI) { + /* Should we stay with this modulation mode, + * or search for a new one? */ + rs_stay_in_table(lq_sta); + } /* * Search for new modulation mode if we're: * 1) Not changing rates right now @@ -2400,7 +2429,8 @@ lq_update: * have been tried and compared, stay in this best modulation * mode for a while before next round of mode comparisons. */ if (lq_sta->enable_counter && - (lq_sta->action_counter >= tbl1->max_search)) { + (lq_sta->action_counter >= tbl1->max_search) && + iwl_ht_enabled(priv)) { if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && (lq_sta->tx_agg_tid_en & (1 << tid)) && (tid != MAX_TID_COUNT)) { @@ -2686,7 +2716,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, rs_initialize_lq(priv, conf, sta, lq_sta); } -static void rs_fill_link_cmd(const struct iwl_priv *priv, +static void rs_fill_link_cmd(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, u32 new_rate) { struct iwl_scale_tbl_info tbl_type; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index d7fdb58..00937b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -98,6 +98,45 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} }; +/* default Thermal Throttling transaction table + * Current state | Throttling Down | Throttling Up + *============================================================================= + * Condition Nxt State Condition Nxt State Condition Nxt State + *----------------------------------------------------------------------------- + * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A + * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 + * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 + * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 + *============================================================================= + */ +static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = { + {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104}, + {IWL_TI_1, 105, CT_KILL_THRESHOLD}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} +}; +static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = { + {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95}, + {IWL_TI_2, 110, CT_KILL_THRESHOLD}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} +}; +static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = { + {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} +}; +static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = { + {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD}, + {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}, + {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX} +}; + +/* Advance Thermal Throttling default restriction table */ +static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { + {IWL_TX_MULTI, true, IWL_RX_MULTI}, + {IWL_TX_SINGLE, true, IWL_RX_MULTI}, + {IWL_TX_SINGLE, false, IWL_RX_SINGLE}, + {IWL_TX_NONE, false, IWL_RX_NONE} +}; /* set card power command */ static int iwl_set_power(struct iwl_priv *priv, void *cmd) @@ -273,6 +312,42 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) } EXPORT_SYMBOL(iwl_power_set_user_mode); +bool iwl_ht_enabled(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_restriction *restriction; + + if (!priv->power_data.adv_tt) + return true; + restriction = tt->restriction + tt->state; + return restriction->is_ht; +} +EXPORT_SYMBOL(iwl_ht_enabled); + +u8 iwl_tx_ant_restriction(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_restriction *restriction; + + if (!priv->power_data.adv_tt) + return IWL_TX_MULTI; + restriction = tt->restriction + tt->state; + return restriction->tx_stream; +} +EXPORT_SYMBOL(iwl_tx_ant_restriction); + +u8 iwl_rx_ant_restriction(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_restriction *restriction; + + if (!priv->power_data.adv_tt) + return IWL_RX_MULTI; + restriction = tt->restriction + tt->state; + return restriction->rx_stream; +} +EXPORT_SYMBOL(iwl_rx_ant_restriction); + #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ /* @@ -427,12 +502,147 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) } } +/* + * Advance thermal throttling + * 1) Avoid NIC destruction due to high temperatures + * Chip will identify dangerously high temperatures that can + * harm the device and will power down + * 2) Avoid the NIC power down due to high temperature + * Throttle early enough to lower the power consumption before + * drastic steps are needed + * Actions include relaxing the power down sleep thresholds and + * decreasing the number of TX streams + * 3) Avoid throughput performance impact as much as possible + * + *============================================================================= + * Condition Nxt State Condition Nxt State Condition Nxt State + *----------------------------------------------------------------------------- + * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A + * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 + * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 + * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 + *============================================================================= + */ +static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + int i; + bool changed = false; + enum iwl_tt_state old_state; + struct iwl_tt_trans *transaction; + + old_state = tt->state; + for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) { + /* based on the current TT state, + * find the curresponding transaction table + * each table has (IWL_TI_STATE_MAX - 1) entries + * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1)) + * will advance to the correct table. + * then based on the current temperature + * find the next state need to transaction to + * go through all the possible (IWL_TI_STATE_MAX - 1) entries + * in the current table to see if transaction is needed + */ + transaction = tt->transaction + + ((old_state * (IWL_TI_STATE_MAX - 1)) + i); + if (temp >= transaction->tt_low && + temp <= transaction->tt_high) { +#ifdef CONFIG_IWLWIFI_DEBUG + if ((tt->tt_previous_temp) && + (temp > tt->tt_previous_temp) && + ((temp - tt->tt_previous_temp) > + IWL_TT_INCREASE_MARGIN)) { + IWL_DEBUG_POWER(priv, + "Temperature increase %d " + "degree Celsius\n", + (temp - tt->tt_previous_temp)); + } + tt->tt_previous_temp = temp; +#endif + if (old_state != + transaction->next_state) { + changed = true; + tt->state = + transaction->next_state; + } + break; + } + } + if (changed) { + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl_power_mgr *setting = &priv->power_data; + + if (tt->state >= IWL_TI_1) { + /* if switching from IWL_TI_0 to other TT state + * save previous power setting in tt->sys_power_mode */ + if (old_state == IWL_TI_0) + tt->sys_power_mode = setting->power_mode; + /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */ + tt->tt_power_mode = IWL_POWER_INDEX_5; + if (!iwl_ht_enabled(priv)) + /* disable HT */ + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | + RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | + RXON_FLG_FAT_PROT_MSK | + RXON_FLG_HT_PROT_MSK); + else { + /* check HT capability and set + * according to the system HT capability + * in case get disabled before */ + iwl_set_rxon_ht(priv, &priv->current_ht_config); + } + + } else { + /* restore system power setting */ + /* the previous power mode was saved in + * tt->sys_power_mode when system move into + * Thermal Throttling state + * set power_data.user_power_setting to the previous + * system power mode to make sure power will get + * updated correctly + */ + priv->power_data.user_power_setting = + tt->sys_power_mode; + tt->tt_power_mode = tt->sys_power_mode; + /* check HT capability and set + * according to the system HT capability + * in case get disabled before */ + iwl_set_rxon_ht(priv, &priv->current_ht_config); + } + if (iwl_power_update_mode(priv, true)) { + /* TT state not updated + * try again during next temperature read + */ + IWL_ERR(priv, "Cannot update power mode, " + "TT state not updated\n"); + tt->state = old_state; + } else { + IWL_DEBUG_POWER(priv, + "Thermal Throttling to new state: %u\n", + tt->state); + if (old_state != IWL_TI_CT_KILL && + tt->state == IWL_TI_CT_KILL) { + IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n"); + iwl_perform_ct_kill_task(priv, true); + + } else if (old_state == IWL_TI_CT_KILL && + tt->state != IWL_TI_CT_KILL) { + IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n"); + iwl_perform_ct_kill_task(priv, false); + } + } + } +} + /* Card State Notification indicated reach critical temperature * if PSP not enable, no Thermal Throttling function will be performed * just set the GP1 bit to acknowledge the event * otherwise, go into IWL_TI_CT_KILL state * since Card State Notification will not provide any temperature reading + * for Legacy mode * so just pass the CT_KILL temperature to iwl_legacy_tt_handler() + * for advance mode + * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state */ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) { @@ -444,7 +654,12 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) if (tt->state != IWL_TI_CT_KILL) { IWL_ERR(priv, "Device reached critical temperature " "- ucode going to sleep!\n"); - iwl_legacy_tt_handler(priv, IWL_MINIMAL_POWER_THRESHOLD); + if (!priv->power_data.adv_tt) + iwl_legacy_tt_handler(priv, + IWL_MINIMAL_POWER_THRESHOLD); + else + iwl_advance_tt_handler(priv, + CT_KILL_THRESHOLD + 1); } } EXPORT_SYMBOL(iwl_tt_enter_ct_kill); @@ -468,8 +683,11 @@ void iwl_tt_exit_ct_kill(struct iwl_priv *priv) IWL_ERR(priv, "Device temperature below critical" "- ucode awake!\n"); - iwl_legacy_tt_handler(priv, - IWL_REDUCED_PERFORMANCE_THRESHOLD_2); + if (!priv->power_data.adv_tt) + iwl_legacy_tt_handler(priv, + IWL_REDUCED_PERFORMANCE_THRESHOLD_2); + else + iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); } } EXPORT_SYMBOL(iwl_tt_exit_ct_kill); @@ -484,16 +702,24 @@ void iwl_tt_handler(struct iwl_priv *priv) if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) temp = KELVIN_TO_CELSIUS(priv->temperature); - iwl_legacy_tt_handler(priv, temp); + if (!priv->power_data.adv_tt) + iwl_legacy_tt_handler(priv, temp); + else + iwl_advance_tt_handler(priv, temp); } EXPORT_SYMBOL(iwl_tt_handler); /* Thermal throttling initialization + * For advance thermal throttling: + * Initialize Thermal Index and temperature threshold table + * Initialize thermal throttling restriction table */ void iwl_tt_initialize(struct iwl_priv *priv) { struct iwl_tt_mgmt *tt = &priv->power_data.tt; struct iwl_power_mgr *setting = &priv->power_data; + int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); + struct iwl_tt_trans *transaction; IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n"); @@ -505,14 +731,65 @@ void iwl_tt_initialize(struct iwl_priv *priv) init_timer(&priv->power_data.ct_kill_exit_tm); priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_6x00: + case CSR_HW_REV_TYPE_6x50: + IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n"); + tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) * + IWL_TI_STATE_MAX, GFP_KERNEL); + tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) * + IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1), + GFP_KERNEL); + if (!tt->restriction || !tt->transaction) { + IWL_ERR(priv, "Fallback to Legacy Throttling\n"); + priv->power_data.adv_tt = false; + kfree(tt->restriction); + tt->restriction = NULL; + kfree(tt->transaction); + tt->transaction = NULL; + } else { + transaction = tt->transaction + + (IWL_TI_0 * (IWL_TI_STATE_MAX - 1)); + memcpy(transaction, &tt_range_0[0], size); + transaction = tt->transaction + + (IWL_TI_1 * (IWL_TI_STATE_MAX - 1)); + memcpy(transaction, &tt_range_1[0], size); + transaction = tt->transaction + + (IWL_TI_2 * (IWL_TI_STATE_MAX - 1)); + memcpy(transaction, &tt_range_2[0], size); + transaction = tt->transaction + + (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1)); + memcpy(transaction, &tt_range_3[0], size); + size = sizeof(struct iwl_tt_restriction) * + IWL_TI_STATE_MAX; + memcpy(tt->restriction, + &restriction_range[0], size); + priv->power_data.adv_tt = true; + } + break; + default: + IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); + priv->power_data.adv_tt = false; + break; + } } EXPORT_SYMBOL(iwl_tt_initialize); /* cleanup thermal throttling management related memory and timer */ void iwl_tt_exit(struct iwl_priv *priv) { + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + /* stop ct_kill_exit_tm timer if activated */ del_timer_sync(&priv->power_data.ct_kill_exit_tm); + + if (priv->power_data.adv_tt) { + /* free advance thermal throttling memory */ + kfree(tt->restriction); + tt->restriction = NULL; + kfree(tt->transaction); + tt->transaction = NULL; + } } EXPORT_SYMBOL(iwl_tt_exit); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 7bb10d4..3d49b7a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -33,8 +33,18 @@ struct iwl_priv; +#define IWL_ABSOLUTE_ZERO 0 +#define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 +/* Tx/Rx restrictions */ +#define IWL_TX_MULTI 0x02 +#define IWL_TX_SINGLE 0x01 +#define IWL_TX_NONE 0x00 +#define IWL_RX_MULTI 0x02 +#define IWL_RX_SINGLE 0x01 +#define IWL_RX_NONE 0x00 + /* Thermal Throttling State Machine states */ enum iwl_tt_state { IWL_TI_0, /* normal temperature, system power state */ @@ -45,6 +55,35 @@ enum iwl_tt_state { }; /** + * struct iwl_tt_restriction - Thermal Throttling restriction table used + * by advance thermal throttling management + * based on the current thermal throttling state, determine + * number of tx/rx streams; and the status of HT operation + * @tx_stream: number of tx stream allowed + * @is_ht: ht enable/disable + * @rx_stream: number of rx stream allowed + */ +struct iwl_tt_restriction { + u8 tx_stream; + bool is_ht; + u8 rx_stream; +}; + +/** + * struct iwl_tt_trans - Thermal Throttling transaction table; used by + * advance thermal throttling algorithm to determine next + * thermal state to go based on the current temperature + * @next_state: next thermal throttling mode + * @tt_low: low temperature threshold to change state + * @tt_high: high temperature threshold to change state + */ +struct iwl_tt_trans { + enum iwl_tt_state next_state; + u32 tt_low; + u32 tt_high; +}; + +/** * struct iwl_tt_mgnt - Thermal Throttling Management structure * @state: current Thermal Throttling state * @tt_power_mode: Thermal Throttling power mode index @@ -55,6 +94,11 @@ enum iwl_tt_state { * @sys_power_mode: previous system power mode * before transition into TT state * @tt_previous_temperature: last measured temperature + * @iwl_tt_restriction: ptr to restriction tbl, used by advance + * thermal throttling to determine how many tx/rx streams + * should be used in tt state; and can HT be enabled or not + * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling + * state transaction */ struct iwl_tt_mgmt { enum iwl_tt_state state; @@ -63,6 +107,8 @@ struct iwl_tt_mgmt { #ifdef CONFIG_IWLWIFI_DEBUG s32 tt_previous_temp; #endif + struct iwl_tt_restriction *restriction; + struct iwl_tt_trans *transaction; }; enum { @@ -92,6 +138,8 @@ struct iwl_power_mgr { u8 user_power_setting; /* set by user through sysfs */ u8 power_disabled; /* set by mac80211's CONF_PS */ struct iwl_tt_mgmt tt; /* Thermal Throttling Management */ + bool adv_tt; /* false: legacy mode */ + /* true: advance mode */ bool ct_kill_toggle; /* use to toggle the CSR bit when * checking uCode temperature */ @@ -100,6 +148,9 @@ struct iwl_power_mgr { int iwl_power_update_mode(struct iwl_priv *priv, bool force); int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); +bool iwl_ht_enabled(struct iwl_priv *priv); +u8 iwl_tx_ant_restriction(struct iwl_priv *priv); +u8 iwl_rx_ant_restriction(struct iwl_priv *priv); void iwl_tt_enter_ct_kill(struct iwl_priv *priv); void iwl_tt_exit_ct_kill(struct iwl_priv *priv); void iwl_tt_handler(struct iwl_priv *priv); -- cgit v0.10.2 From fbf3a2af3834e8e93e9c2876de62c5b49988e352 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:04 -0700 Subject: iwlwifi: Thermal Throttling debugfs function Add debugfs function to display current thermal throttling status for both Legacy and Advance Thermal Throttling Management Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 9faf0c2..609a681 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -84,6 +84,7 @@ struct iwl_debugfs { struct dentry *file_status; struct dentry *file_interrupt; struct dentry *file_qos; + struct dentry *file_thermal_throttling; #ifdef CONFIG_IWLWIFI_LEDS struct dentry *file_led; #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 0ab3463..748dc31 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -618,6 +618,41 @@ static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, } #endif +static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_restriction *restriction; + char buf[100]; + int pos = 0; + const size_t bufsz = sizeof(buf); + ssize_t ret; + + pos += scnprintf(buf + pos, bufsz - pos, + "Thermal Throttling Mode: %s\n", + (priv->power_data.adv_tt) + ? "Advance" : "Legacy"); + pos += scnprintf(buf + pos, bufsz - pos, + "Thermal Throttling State: %d\n", + tt->state); + if (priv->power_data.adv_tt) { + restriction = tt->restriction + tt->state; + pos += scnprintf(buf + pos, bufsz - pos, + "Tx mode: %d\n", + restriction->tx_stream); + pos += scnprintf(buf + pos, bufsz - pos, + "Rx mode: %d\n", + restriction->rx_stream); + pos += scnprintf(buf + pos, bufsz - pos, + "HT mode: %d\n", + restriction->is_ht); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); @@ -631,6 +666,7 @@ DEBUGFS_READ_FILE_OPS(qos); #ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_READ_FILE_OPS(led); #endif +DEBUGFS_READ_FILE_OPS(thermal_throttling); /* * Create the debugfs files and directories @@ -671,6 +707,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) #ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_ADD_FILE(led, data); #endif + DEBUGFS_ADD_FILE(thermal_throttling, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -709,6 +746,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) #ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led); #endif + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); -- cgit v0.10.2 From c2acea8e9b86ba5a5469ff477445676a223af4e2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jul 2009 11:13:05 -0700 Subject: iwlwifi: fix up command sending The current command sending in iwlwifi is a bit of a mess: 1) there is a struct, iwl_cmd, that contains both driver and device data in a single packed structure -- this is very confusing 2) the on-stack data and the command metadata share a structure by embedding the latter in the former, which is also rather confusing because it leads to weird unions and similarly odd constructs 3) each txq always has enough space for 256 commands, even if only 32 end up being used This patch fixes these things: 1) rename iwl_cmd to iwl_device_cmd and keep track of command metadata and device command separately, in two arrays in each tx queue 2) remove the 'meta' member from iwl_host_cmd and only put in the required members 3) allocate the cmd/meta arrays separately instead of embedding them into the txq structure Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index 225e5f8..b379382 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -80,7 +80,7 @@ static const struct { #define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) static int iwl3945_led_cmd_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, + struct iwl_device_cmd *cmd, struct sk_buff *skb) { return 1; @@ -99,8 +99,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, .id = REPLY_LEDS_CMD, .len = sizeof(struct iwl_led_cmd), .data = led_cmd, - .meta.flags = CMD_ASYNC, - .meta.u.callback = iwl3945_led_cmd_callback, + .flags = CMD_ASYNC, + .callback = iwl3945_led_cmd_callback, }; return iwl_send_cmd(priv, &cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8ee403c..e1b0ef3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -749,8 +749,8 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) /* Unmap tx_cmd */ if (counter) pci_unmap_single(dev, - pci_unmap_addr(&txq->cmd[index]->meta, mapping), - pci_unmap_len(&txq->cmd[index]->meta, len), + pci_unmap_addr(&txq->meta[index], mapping), + pci_unmap_len(&txq->meta[index], len), PCI_DMA_TODEVICE); /* unmap chunks if any */ @@ -774,9 +774,11 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: * */ -void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, - struct ieee80211_tx_info *info, - struct ieee80211_hdr *hdr, int sta_id, int tx_id) +void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, + int sta_id, int tx_id) { u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value; u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); @@ -1858,7 +1860,7 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) struct iwl_host_cmd cmd = { .id = REPLY_RXON_ASSOC, .len = sizeof(rxon_assoc), - .meta.flags = CMD_WANT_SKB, + .flags = CMD_WANT_SKB, .data = &rxon_assoc, }; const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; @@ -1882,14 +1884,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.reply_skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); rc = -EIO; } priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); + dev_kfree_skb_any(cmd.reply_skb); return rc; } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index f2ffc48..f240369 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -254,10 +254,11 @@ extern int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq); extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl3945_frame *frame, u8 rate); -void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, - struct ieee80211_tx_info *info, - struct ieee80211_hdr *hdr, - int sta_id, int tx_id); +void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, + int sta_id, int tx_id); extern int iwl3945_hw_reg_send_txpower(struct iwl_priv *priv); extern int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 23ae991..4cb1a1b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -442,8 +442,8 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) /* Unmap tx_cmd */ if (num_tbs) pci_unmap_single(dev, - pci_unmap_addr(&txq->cmd[index]->meta, mapping), - pci_unmap_len(&txq->cmd[index]->meta, len), + pci_unmap_addr(&txq->meta[index], mapping), + pci_unmap_len(&txq->meta[index], len), PCI_DMA_BIDIRECTIONAL); /* Unmap chunks, if any. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index f8bf592..13180d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -86,7 +86,7 @@ int iwl_send_calib_results(struct iwl_priv *priv) struct iwl_host_cmd hcmd = { .id = REPLY_PHY_CALIBRATION_CMD, - .meta.flags = CMD_SIZE_HUGE, + .flags = CMD_SIZE_HUGE, }; for (i = 0; i < IWL_CALIB_MAX; i++) { @@ -419,7 +419,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv) struct iwl_host_cmd cmd_out = { .id = SENSITIVITY_CMD, .len = sizeof(struct iwl_sensitivity_cmd), - .meta.flags = CMD_ASYNC, + .flags = CMD_ASYNC, .data = &cmd, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d8aeb24..710dd41 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2089,7 +2089,7 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) u32 stat_flags = 0; struct iwl_host_cmd cmd = { .id = REPLY_STATISTICS_CMD, - .meta.flags = flags, + .flags = flags, .len = sizeof(stat_flags), .data = (u8 *) &stat_flags, }; @@ -2282,7 +2282,7 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) .id = REPLY_CARD_STATE_CMD, .len = sizeof(u32), .data = &flags, - .meta.flags = meta_flag, + .flags = meta_flag, }; return iwl_send_cmd(priv, &cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 614ec7c..4156deb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -447,7 +447,7 @@ int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, int (*callback)(struct iwl_priv *priv, - struct iwl_cmd *cmd, + struct iwl_device_cmd *cmd, struct sk_buff *skb)); int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cddf173..ce765f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -150,6 +150,31 @@ struct iwl_rx_mem_buffer { struct list_head list; }; +/* defined below */ +struct iwl_device_cmd; + +struct iwl_cmd_meta { + /* only for SYNC commands, iff the reply skb is wanted */ + struct iwl_host_cmd *source; + /* + * only for ASYNC commands + * (which is somewhat stupid -- look at iwl-sta.c for instance + * which duplicates a bunch of code because the callback isn't + * invoked for SYNC commands, if it were and its result passed + * through it would be simpler...) + */ + int (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb); + + /* The CMD_SIZE_HUGE flag bit indicates that the command + * structure is stored at the end of the shared queue memory. */ + u32 flags; + + DECLARE_PCI_UNMAP_ADDR(mapping) + DECLARE_PCI_UNMAP_LEN(len) +}; + /* * Generic queue structure * @@ -177,7 +202,8 @@ struct iwl_tx_info { * struct iwl_tx_queue - Tx Queue for DMA * @q: generic Rx/Tx queue descriptor * @bd: base of circular buffer of TFDs - * @cmd: array of command/Tx buffers + * @cmd: array of command/TX buffer pointers + * @meta: array of meta data for each command/tx buffer * @dma_addr_cmd: physical address of cmd/tx buffer array * @txb: array of per-TFD driver data * @need_update: indicates need to update read/write index @@ -192,7 +218,8 @@ struct iwl_tx_info { struct iwl_tx_queue { struct iwl_queue q; void *tfds; - struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS]; + struct iwl_device_cmd **cmd; + struct iwl_cmd_meta *meta; struct iwl_tx_info *txb; u8 need_update; u8 sched_retry; @@ -329,35 +356,16 @@ enum { CMD_WANT_SKB = (1 << 2), }; -struct iwl_cmd; -struct iwl_priv; - -struct iwl_cmd_meta { - struct iwl_cmd_meta *source; - union { - struct sk_buff *skb; - int (*callback)(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb); - } __attribute__ ((packed)) u; - - /* The CMD_SIZE_HUGE flag bit indicates that the command - * structure is stored at the end of the shared queue memory. */ - u32 flags; - DECLARE_PCI_UNMAP_ADDR(mapping) - DECLARE_PCI_UNMAP_LEN(len) -} __attribute__ ((packed)); - #define IWL_CMD_MAX_PAYLOAD 320 /** - * struct iwl_cmd + * struct iwl_device_cmd * * For allocation of the command and tx queues, this establishes the overall * size of the largest command we send to uCode, except for a scan command * (which is relatively huge; space is allocated separately). */ -struct iwl_cmd { - struct iwl_cmd_meta meta; /* driver data */ +struct iwl_device_cmd { struct iwl_cmd_header hdr; /* uCode API */ union { u32 flags; @@ -369,17 +377,20 @@ struct iwl_cmd { } __attribute__ ((packed)) cmd; } __attribute__ ((packed)); +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) + struct iwl_host_cmd { - u8 id; - u16 len; - struct iwl_cmd_meta meta; const void *data; + struct sk_buff *reply_skb; + int (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb); + u32 flags; + u16 len; + u8 id; }; -#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ - sizeof(struct iwl_cmd_meta)) - /* * RX related structures and functions */ diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 17d61ac..d8a3eac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -104,7 +104,8 @@ EXPORT_SYMBOL(get_cmd_string); #define HOST_COMPLETE_TIMEOUT (HZ / 2) static int iwl_generic_cmd_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *pkt = NULL; @@ -142,14 +143,14 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { int ret; - BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); + BUG_ON(!(cmd->flags & CMD_ASYNC)); /* An asynchronous command can not expect an SKB to be set. */ - BUG_ON(cmd->meta.flags & CMD_WANT_SKB); + BUG_ON(cmd->flags & CMD_WANT_SKB); /* Assign a generic callback if one is not provided */ - if (!cmd->meta.u.callback) - cmd->meta.u.callback = iwl_generic_cmd_callback; + if (!cmd->callback) + cmd->callback = iwl_generic_cmd_callback; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EBUSY; @@ -168,10 +169,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int cmd_idx; int ret; - BUG_ON(cmd->meta.flags & CMD_ASYNC); + BUG_ON(cmd->flags & CMD_ASYNC); /* A synchronous command can not have a callback set. */ - BUG_ON(cmd->meta.u.callback != NULL); + BUG_ON(cmd->callback); if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) { IWL_ERR(priv, @@ -183,9 +184,6 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) set_bit(STATUS_HCMD_ACTIVE, &priv->status); - if (cmd->meta.flags & CMD_WANT_SKB) - cmd->meta.source = &cmd->meta; - cmd_idx = iwl_enqueue_hcmd(priv, cmd); if (cmd_idx < 0) { ret = cmd_idx; @@ -222,7 +220,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ret = -EIO; goto fail; } - if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { + if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) { IWL_ERR(priv, "Error: Response NULL in '%s'\n", get_cmd_string(cmd->id)); ret = -EIO; @@ -233,20 +231,20 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) goto out; cancel: - if (cmd->meta.flags & CMD_WANT_SKB) { - struct iwl_cmd *qcmd; - - /* Cancel the CMD_WANT_SKB flag for the cmd in the + if (cmd->flags & CMD_WANT_SKB) { + /* + * Cancel the CMD_WANT_SKB flag for the cmd in the * TX cmd queue. Otherwise in case the cmd comes * in later, it will possibly set an invalid - * address (cmd->meta.source). */ - qcmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; - qcmd->meta.flags &= ~CMD_WANT_SKB; + * address (cmd->meta.source). + */ + priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_idx].flags &= + ~CMD_WANT_SKB; } fail: - if (cmd->meta.u.skb) { - dev_kfree_skb_any(cmd->meta.u.skb); - cmd->meta.u.skb = NULL; + if (cmd->reply_skb) { + dev_kfree_skb_any(cmd->reply_skb); + cmd->reply_skb = NULL; } out: clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status); @@ -256,7 +254,7 @@ EXPORT_SYMBOL(iwl_send_cmd_sync); int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { - if (cmd->meta.flags & CMD_ASYNC) + if (cmd->flags & CMD_ASYNC) return iwl_send_cmd_async(priv, cmd); return iwl_send_cmd_sync(priv, cmd); @@ -278,7 +276,7 @@ EXPORT_SYMBOL(iwl_send_cmd_pdu); int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, int (*callback)(struct iwl_priv *priv, - struct iwl_cmd *cmd, + struct iwl_device_cmd *cmd, struct sk_buff *skb)) { struct iwl_host_cmd cmd = { @@ -287,8 +285,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, .data = data, }; - cmd.meta.flags |= CMD_ASYNC; - cmd.meta.u.callback = callback; + cmd.flags |= CMD_ASYNC; + cmd.callback = callback; return iwl_send_cmd_async(priv, &cmd); } diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 8c81152..7cce8f8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -91,8 +91,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) .id = REPLY_LEDS_CMD, .len = sizeof(struct iwl_led_cmd), .data = led_cmd, - .meta.flags = CMD_ASYNC, - .meta.u.callback = NULL, + .flags = CMD_ASYNC, + .callback = NULL, }; u32 reg; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 00398d9..c4c916d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -115,7 +115,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) struct iwl_rx_packet *res; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, - .meta.flags = CMD_WANT_SKB, + .flags = CMD_WANT_SKB, }; /* If there isn't a scan actively going on in the hardware @@ -132,7 +132,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) return ret; } - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.reply_skb->data; if (res->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be @@ -146,7 +146,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) } priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); + dev_kfree_skb_any(cmd.reply_skb); return ret; } @@ -567,7 +567,7 @@ static void iwl_bg_request_scan(struct work_struct *data) struct iwl_host_cmd cmd = { .id = REPLY_SCAN_CMD, .len = sizeof(struct iwl_scan_cmd), - .meta.flags = CMD_SIZE_HUGE, + .flags = CMD_SIZE_HUGE, }; struct iwl_scan_cmd *scan; struct ieee80211_conf *conf = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index cbe4e26..1571ace 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -98,7 +98,8 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) } static int iwl_add_sta_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; struct iwl_addsta_cmd *addsta = @@ -139,14 +140,14 @@ int iwl_send_add_sta(struct iwl_priv *priv, u8 data[sizeof(*sta)]; struct iwl_host_cmd cmd = { .id = REPLY_ADD_STA, - .meta.flags = flags, + .flags = flags, .data = data, }; if (flags & CMD_ASYNC) - cmd.meta.u.callback = iwl_add_sta_callback; + cmd.callback = iwl_add_sta_callback; else - cmd.meta.flags |= CMD_WANT_SKB; + cmd.flags |= CMD_WANT_SKB; cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); ret = iwl_send_cmd(priv, &cmd); @@ -154,7 +155,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, if (ret || (flags & CMD_ASYNC)) return ret; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.reply_skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", res->hdr.flags); @@ -175,7 +176,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, } priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); + dev_kfree_skb_any(cmd.reply_skb); return ret; } @@ -325,7 +326,8 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) } static int iwl_remove_sta_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; struct iwl_rem_sta_cmd *rm_sta = @@ -368,7 +370,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, struct iwl_host_cmd cmd = { .id = REPLY_REMOVE_STA, .len = sizeof(struct iwl_rem_sta_cmd), - .meta.flags = flags, + .flags = flags, .data = &rm_sta_cmd, }; @@ -377,15 +379,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN); if (flags & CMD_ASYNC) - cmd.meta.u.callback = iwl_remove_sta_callback; + cmd.callback = iwl_remove_sta_callback; else - cmd.meta.flags |= CMD_WANT_SKB; + cmd.flags |= CMD_WANT_SKB; ret = iwl_send_cmd(priv, &cmd); if (ret || (flags & CMD_ASYNC)) return ret; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.reply_skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", res->hdr.flags); @@ -406,7 +408,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, } priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); + dev_kfree_skb_any(cmd.reply_skb); return ret; } @@ -525,7 +527,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) struct iwl_host_cmd cmd = { .id = REPLY_WEPKEY, .data = wep_cmd, - .meta.flags = CMD_ASYNC, + .flags = CMD_ASYNC, }; memset(wep_cmd, 0, cmd_size + @@ -930,7 +932,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_host_cmd cmd = { .id = REPLY_TX_LINK_QUALITY_CMD, .len = sizeof(struct iwl_link_quality_cmd), - .meta.flags = flags, + .flags = flags, .data = lq, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 0912987..51ddbab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -141,7 +141,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) priv->cfg->ops->lib->txq_free_tfd(priv, txq); - len = sizeof(struct iwl_cmd) * q->n_window; + len = sizeof(struct iwl_device_cmd) * q->n_window; /* De-alloc array of command/tx buffers */ for (i = 0; i < TFD_TX_CMD_SLOTS; i++) @@ -156,6 +156,12 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) kfree(txq->txb); txq->txb = NULL; + /* deallocate arrays */ + kfree(txq->cmd); + kfree(txq->meta); + txq->cmd = NULL; + txq->meta = NULL; + /* 0-fill queue descriptor structure */ memset(txq, 0, sizeof(*txq)); } @@ -179,7 +185,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) if (q->n_bd == 0) return; - len = sizeof(struct iwl_cmd) * q->n_window; + len = sizeof(struct iwl_device_cmd) * q->n_window; len += IWL_MAX_SCAN_SIZE; /* De-alloc array of command/tx buffers */ @@ -318,6 +324,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, { int i, len; int ret; + int actual_slots = slots_num; /* * Alloc buffer array for commands (Tx or other types of commands). @@ -327,14 +334,22 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, * For normal Tx queues (all other queues), no super-size command * space is needed. */ - len = sizeof(struct iwl_cmd); - for (i = 0; i <= slots_num; i++) { - if (i == slots_num) { - if (txq_id == IWL_CMD_QUEUE_NUM) - len += IWL_MAX_SCAN_SIZE; - else - continue; - } + if (txq_id == IWL_CMD_QUEUE_NUM) + actual_slots++; + + txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots, + GFP_KERNEL); + txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots, + GFP_KERNEL); + + if (!txq->meta || !txq->cmd) + goto out_free_arrays; + + len = sizeof(struct iwl_device_cmd); + for (i = 0; i < actual_slots; i++) { + /* only happens for cmd queue */ + if (i == slots_num) + len += IWL_MAX_SCAN_SIZE; txq->cmd[i] = kmalloc(len, GFP_KERNEL); if (!txq->cmd[i]) @@ -364,15 +379,12 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, return 0; err: - for (i = 0; i < slots_num; i++) { + for (i = 0; i < actual_slots; i++) kfree(txq->cmd[i]); - txq->cmd[i] = NULL; - } +out_free_arrays: + kfree(txq->meta); + kfree(txq->cmd); - if (txq_id == IWL_CMD_QUEUE_NUM) { - kfree(txq->cmd[slots_num]); - txq->cmd[slots_num] = NULL; - } return -ENOMEM; } EXPORT_SYMBOL(iwl_tx_queue_init); @@ -673,7 +685,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_tx_queue *txq; struct iwl_queue *q; - struct iwl_cmd *out_cmd; + struct iwl_device_cmd *out_cmd; + struct iwl_cmd_meta *out_meta; struct iwl_tx_cmd *tx_cmd; int swq_id, txq_id; dma_addr_t phys_addr; @@ -766,6 +779,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_cmd = txq->cmd[q->write_ptr]; + out_meta = &txq->meta[q->write_ptr]; tx_cmd = &out_cmd->cmd.tx; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); @@ -828,8 +842,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txcmd_phys = pci_map_single(priv->pci_dev, &out_cmd->hdr, len, PCI_DMA_BIDIRECTIONAL); - pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); - pci_unmap_len_set(&out_cmd->meta, len, len); + pci_unmap_addr_set(out_meta, mapping, txcmd_phys); + pci_unmap_len_set(out_meta, len, len); /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, @@ -923,7 +937,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_queue *q = &txq->q; - struct iwl_cmd *out_cmd; + struct iwl_device_cmd *out_cmd; + struct iwl_cmd_meta *out_meta; dma_addr_t phys_addr; unsigned long flags; int len, ret; @@ -937,25 +952,31 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then * we will need to increase the size of the TFD entries */ BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && - !(cmd->meta.flags & CMD_SIZE_HUGE)); + !(cmd->flags & CMD_SIZE_HUGE)); if (iwl_is_rfkill(priv)) { IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n"); return -EIO; } - if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERR(priv, "No space for Tx\n"); return -ENOSPC; } spin_lock_irqsave(&priv->hcmd_lock, flags); - idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); + idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); out_cmd = txq->cmd[idx]; + out_meta = &txq->meta[idx]; + + out_meta->flags = cmd->flags; + if (cmd->flags & CMD_WANT_SKB) + out_meta->source = cmd; + if (cmd->flags & CMD_ASYNC) + out_meta->callback = cmd->callback; out_cmd->hdr.cmd = cmd->id; - memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); /* At this point, the out_cmd now has all of the incoming cmd @@ -964,9 +985,9 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) out_cmd->hdr.flags = 0; out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | INDEX_TO_SEQ(q->write_ptr)); - if (out_cmd->meta.flags & CMD_SIZE_HUGE) + if (cmd->flags & CMD_SIZE_HUGE) out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; - len = sizeof(struct iwl_cmd) - sizeof(struct iwl_cmd_meta); + len = sizeof(struct iwl_device_cmd); len += (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : 0; @@ -998,8 +1019,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr, fix_size, PCI_DMA_BIDIRECTIONAL); - pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr); - pci_unmap_len_set(&out_cmd->meta, len, fix_size); + pci_unmap_addr_set(out_meta, mapping, phys_addr); + pci_unmap_len_set(out_meta, len, fix_size); priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, phys_addr, fix_size, 1, @@ -1068,8 +1089,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, } pci_unmap_single(priv->pci_dev, - pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping), - pci_unmap_len(&txq->cmd[cmd_idx]->meta, len), + pci_unmap_addr(&txq->meta[cmd_idx], mapping), + pci_unmap_len(&txq->meta[cmd_idx], len), PCI_DMA_BIDIRECTIONAL); for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; @@ -1100,7 +1121,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) int index = SEQ_TO_INDEX(sequence); int cmd_index; bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME); - struct iwl_cmd *cmd; + struct iwl_device_cmd *cmd; + struct iwl_cmd_meta *meta; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -1116,18 +1138,18 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; + meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index]; /* Input error checking is done when commands are added to queue. */ - if (cmd->meta.flags & CMD_WANT_SKB) { - cmd->meta.source->u.skb = rxb->skb; + if (meta->flags & CMD_WANT_SKB) { + meta->source->reply_skb = rxb->skb; rxb->skb = NULL; - } else if (cmd->meta.u.callback && - !cmd->meta.u.callback(priv, cmd, rxb->skb)) + } else if (meta->callback && !meta->callback(priv, cmd, rxb->skb)) rxb->skb = NULL; iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); - if (!(cmd->meta.flags & CMD_ASYNC)) { + if (!(meta->flags & CMD_ASYNC)) { clear_bit(STATUS_HCMD_ACTIVE, &priv->status); wake_up_interruptible(&priv->wait_command_queue); } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2cc7e30..5ded898 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -363,7 +363,7 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv) static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct ieee80211_tx_info *info, - struct iwl_cmd *cmd, + struct iwl_device_cmd *cmd, struct sk_buff *skb_frag, int sta_id) { @@ -403,7 +403,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, * handle build REPLY_TX command notification. */ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, - struct iwl_cmd *cmd, + struct iwl_device_cmd *cmd, struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, u8 std_id) { @@ -476,7 +476,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct iwl3945_tx_cmd *tx; struct iwl_tx_queue *txq = NULL; struct iwl_queue *q = NULL; - struct iwl_cmd *out_cmd = NULL; + struct iwl_device_cmd *out_cmd; + struct iwl_cmd_meta *out_meta; dma_addr_t phys_addr; dma_addr_t txcmd_phys; int txq_id = skb_get_queue_mapping(skb); @@ -565,6 +566,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Init first empty entry in queue's array of Tx/cmd buffers */ out_cmd = txq->cmd[idx]; + out_meta = &txq->meta[idx]; tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(tx, 0, sizeof(*tx)); @@ -642,8 +644,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) len, PCI_DMA_TODEVICE); /* we do not map meta data ... so we can safely access address to * provide to unmap command*/ - pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); - pci_unmap_len_set(&out_cmd->meta, len, len); + pci_unmap_addr_set(out_meta, mapping, txcmd_phys); + pci_unmap_len_set(out_meta, len, len); /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ @@ -753,7 +755,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, struct iwl_host_cmd cmd = { .id = REPLY_SPECTRUM_MEASUREMENT_CMD, .data = (void *)&spectrum, - .meta.flags = CMD_WANT_SKB, + .flags = CMD_WANT_SKB, }; u32 add_time = le64_to_cpu(params->start_time); int rc; @@ -794,7 +796,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.reply_skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n"); rc = -EIO; @@ -817,7 +819,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, break; } - dev_kfree_skb_any(cmd.meta.u.skb); + dev_kfree_skb_any(cmd.reply_skb); return rc; } @@ -2717,7 +2719,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) struct iwl_host_cmd cmd = { .id = REPLY_SCAN_CMD, .len = sizeof(struct iwl3945_scan_cmd), - .meta.flags = CMD_SIZE_HUGE, + .flags = CMD_SIZE_HUGE, }; int rc = 0; struct iwl3945_scan_cmd *scan; -- cgit v0.10.2 From 5696aea6f243e40013d2b00cd140fd006ec20b9c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jul 2009 11:13:06 -0700 Subject: iwlwifi: remove command callback return value No existing callbacks use anything other than the return value 1, which means that the caller should free the reply skb, so it seems safer in terms of not introducing memory leaks to simply remove the return value and let the caller always free the skb. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index b379382..8c29ded 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -79,11 +79,10 @@ static const struct { #define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/ #define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) -static int iwl3945_led_cmd_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb) +static void iwl3945_led_cmd_callback(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { - return 1; } static inline int iwl3945_brightness_to_idx(enum led_brightness brightness) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4156deb..febcf76 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -446,9 +446,9 @@ int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data); int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, - int (*callback)(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb)); + void (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb)); int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ce765f7..3ca188a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -163,9 +163,9 @@ struct iwl_cmd_meta { * invoked for SYNC commands, if it were and its result passed * through it would be simpler...) */ - int (*callback)(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb); + void (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb); /* The CMD_SIZE_HUGE flag bit indicates that the command * structure is stored at the end of the shared queue memory. */ @@ -383,9 +383,9 @@ struct iwl_device_cmd { struct iwl_host_cmd { const void *data; struct sk_buff *reply_skb; - int (*callback)(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb); + void (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb); u32 flags; u16 len; u8 id; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index d8a3eac..b82ad15 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -103,23 +103,23 @@ EXPORT_SYMBOL(get_cmd_string); #define HOST_COMPLETE_TIMEOUT (HZ / 2) -static int iwl_generic_cmd_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb) +static void iwl_generic_cmd_callback(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *pkt = NULL; if (!skb) { IWL_ERR(priv, "Error: Response NULL in %s.\n", get_cmd_string(cmd->hdr.cmd)); - return 1; + return; } pkt = (struct iwl_rx_packet *)skb->data; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); - return 1; + return; } #ifdef CONFIG_IWLWIFI_DEBUG @@ -128,15 +128,12 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv, case SENSITIVITY_CMD: IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); - break; + break; default: IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); } #endif - - /* Let iwl_tx_complete free the response skb */ - return 1; } static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) @@ -275,9 +272,9 @@ EXPORT_SYMBOL(iwl_send_cmd_pdu); int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, - int (*callback)(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb)) + void (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb)) { struct iwl_host_cmd cmd = { .id = id, diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 1571ace..79ea5cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -97,9 +97,9 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) spin_unlock_irqrestore(&priv->sta_lock, flags); } -static int iwl_add_sta_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb) +static void iwl_add_sta_callback(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; struct iwl_addsta_cmd *addsta = @@ -108,14 +108,14 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, if (!skb) { IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n"); - return 1; + return; } res = (struct iwl_rx_packet *)skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", res->hdr.flags); - return 1; + return; } switch (res->u.add_sta.status) { @@ -127,9 +127,6 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, res->u.add_sta.status); break; } - - /* We didn't cache the SKB; let the caller free it */ - return 1; } int iwl_send_add_sta(struct iwl_priv *priv, @@ -325,9 +322,9 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) spin_unlock_irqrestore(&priv->sta_lock, flags); } -static int iwl_remove_sta_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb) +static void iwl_remove_sta_callback(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; struct iwl_rem_sta_cmd *rm_sta = @@ -336,14 +333,14 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv, if (!skb) { IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n"); - return 1; + return; } res = (struct iwl_rx_packet *)skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", res->hdr.flags); - return 1; + return; } switch (res->u.rem_sta.status) { @@ -354,9 +351,6 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv, IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); break; } - - /* We didn't cache the SKB; let the caller free it */ - return 1; } static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 51ddbab..e1558db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1144,8 +1144,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) if (meta->flags & CMD_WANT_SKB) { meta->source->reply_skb = rxb->skb; rxb->skb = NULL; - } else if (meta->callback && !meta->callback(priv, cmd, rxb->skb)) - rxb->skb = NULL; + } else if (meta->callback) + meta->callback(priv, cmd, rxb->skb); iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); -- cgit v0.10.2 From ec74116487278adf6c3db9c3bbdc81c6409c1cbb Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 24 Jul 2009 11:13:08 -0700 Subject: iwlwifi: print packet contents in error case This data is more useful to debugging that the receive buffer contents. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index e1558db..660d1a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1132,7 +1132,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) txq_id, sequence, priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr, priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) { - iwl_print_hex_error(priv, rxb, 32); + iwl_print_hex_error(priv, pkt, 32); return; } -- cgit v0.10.2 From bcc693a14ddf46170752c185e415ff8609b9f82f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:09 -0700 Subject: iwlwifi: Name fix for MPDU density for TX aggregation Fix incorrect name for HT MPDU Density. default set to 4 uSec Reported-by: Sujith Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 3ca188a..facbc3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -491,8 +491,16 @@ union iwl_ht_rate_supp { }; #define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) -#define CFG_HT_MPDU_DENSITY_2USEC (0x5) -#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC + +/* + * Maximal MPDU density for TX aggregation + * 4 - 2us density + * 5 - 4us density + * 6 - 8us density + * 7 - 16us density + */ +#define CFG_HT_MPDU_DENSITY_4USEC (0x5) +#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC struct iwl_ht_info { /* self configuration data */ -- cgit v0.10.2 From 1da46bebb1bb01a77333e6509e74e12b85df5729 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Fri, 24 Jul 2009 11:13:10 -0700 Subject: iwlwifi: fix LED config option IWLWIFI_LEDS option should certainly have help comment, and should default to y. Signed-off-by: Pavel Machek Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index e092af0..99310c0 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -9,6 +9,9 @@ config IWLWIFI config IWLWIFI_LEDS bool "Enable LED support in iwlagn and iwl3945 drivers" depends on IWLWIFI + default y + ---help--- + Select this if you want LED support. config IWLWIFI_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwlagn driver" -- cgit v0.10.2 From 3885123da8335dc6b67387e5e626acbffc56f664 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:04:50 +0900 Subject: swiotlb: remove unused swiotlb_alloc_boot() Nobody uses swiotlb_alloc_boot(). Signed-off-by: FUJITA Tomonori Acked-by: Becky Bruce diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index 6af96ee..0ac7cd5 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -13,11 +13,6 @@ int swiotlb __read_mostly; -void * __init swiotlb_alloc_boot(size_t size, unsigned long nslabs) -{ - return alloc_bootmem_low_pages(size); -} - void *swiotlb_alloc(unsigned order, unsigned long nslabs) { return (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, order); diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index cb1a663..94db704 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -14,7 +14,6 @@ struct scatterlist; */ #define IO_TLB_SEGSIZE 128 - /* * log of the size of each IO TLB slab. The number of slabs is command line * controllable. @@ -24,7 +23,6 @@ struct scatterlist; extern void swiotlb_init(void); -extern void *swiotlb_alloc_boot(size_t bytes, unsigned long nslabs); extern void *swiotlb_alloc(unsigned order, unsigned long nslabs); extern dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, diff --git a/lib/swiotlb.c b/lib/swiotlb.c index bffe6d7..9edfdd4 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -114,11 +114,6 @@ setup_io_tlb_npages(char *str) __setup("swiotlb=", setup_io_tlb_npages); /* make io_tlb_overflow tunable too? */ -void * __weak __init swiotlb_alloc_boot(size_t size, unsigned long nslabs) -{ - return alloc_bootmem_low_pages(size); -} - void * __weak swiotlb_alloc(unsigned order, unsigned long nslabs) { return (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, order); @@ -189,7 +184,7 @@ swiotlb_init_with_default_size(size_t default_size) /* * Get IO TLB memory from the low pages */ - io_tlb_start = swiotlb_alloc_boot(bytes, io_tlb_nslabs); + io_tlb_start = alloc_bootmem_low_pages(bytes); if (!io_tlb_start) panic("Cannot allocate SWIOTLB buffer"); io_tlb_end = io_tlb_start + bytes; -- cgit v0.10.2 From bb52196be37ce154ddc50b1f39496146d181cbe7 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:04:51 +0900 Subject: swiotlb: remove unused swiotlb_alloc() Nobody uses swiotlb_alloc(). Signed-off-by: FUJITA Tomonori Acked-by: Becky Bruce diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index 0ac7cd5..ea675cf 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -13,11 +13,6 @@ int swiotlb __read_mostly; -void *swiotlb_alloc(unsigned order, unsigned long nslabs) -{ - return (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, order); -} - dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr) { return paddr; diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 94db704..6bc5094 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -23,8 +23,6 @@ struct scatterlist; extern void swiotlb_init(void); -extern void *swiotlb_alloc(unsigned order, unsigned long nslabs); - extern dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t address); extern phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 9edfdd4..3c4c21c 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -114,11 +114,6 @@ setup_io_tlb_npages(char *str) __setup("swiotlb=", setup_io_tlb_npages); /* make io_tlb_overflow tunable too? */ -void * __weak swiotlb_alloc(unsigned order, unsigned long nslabs) -{ - return (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, order); -} - dma_addr_t __weak swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr) { return paddr; @@ -240,7 +235,8 @@ swiotlb_late_init_with_default_size(size_t default_size) bytes = io_tlb_nslabs << IO_TLB_SHIFT; while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) { - io_tlb_start = swiotlb_alloc(order, io_tlb_nslabs); + io_tlb_start = (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, + order); if (io_tlb_start) break; order--; -- cgit v0.10.2 From cf56e3f2e8a8d5b7bc719980869b0e7985c256f3 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:04:52 +0900 Subject: swiotlb: remove swiotlb_arch_range_needs_mapping Nobody uses swiotlb_arch_range_needs_mapping(). Signed-off-by: FUJITA Tomonori Acked-by: Becky Bruce diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index ea675cf..165bd7f 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -23,11 +23,6 @@ phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr) return baddr; } -int __weak swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size) -{ - return 0; -} - static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t flags) { diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 6bc5094..a977da2 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -28,8 +28,6 @@ extern dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, extern phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t address); -extern int swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size); - extern void *swiotlb_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t flags); diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 3c4c21c..dc1cd1f 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -141,11 +141,6 @@ int __weak swiotlb_arch_address_needs_mapping(struct device *hwdev, return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size); } -int __weak swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size) -{ - return 0; -} - static void swiotlb_print_info(unsigned long bytes) { phys_addr_t pstart, pend; @@ -312,11 +307,6 @@ address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t size) return swiotlb_arch_address_needs_mapping(hwdev, addr, size); } -static inline int range_needs_mapping(phys_addr_t paddr, size_t size) -{ - return swiotlb_force || swiotlb_arch_range_needs_mapping(paddr, size); -} - static int is_swiotlb_buffer(char *addr) { return addr >= io_tlb_start && addr < io_tlb_end; @@ -646,8 +636,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page, * we can safely return the device addr and not worry about bounce * buffering it. */ - if (!address_needs_mapping(dev, dev_addr, size) && - !range_needs_mapping(phys, size)) + if (!address_needs_mapping(dev, dev_addr, size) && !swiotlb_force) return dev_addr; /* @@ -810,7 +799,7 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems, phys_addr_t paddr = sg_phys(sg); dma_addr_t dev_addr = swiotlb_phys_to_bus(hwdev, paddr); - if (range_needs_mapping(paddr, sg->length) || + if (swiotlb_force || address_needs_mapping(hwdev, dev_addr, sg->length)) { void *map = map_single(hwdev, sg_phys(sg), sg->length, dir); -- cgit v0.10.2 From 02ca646e73f3cb9be69e339841b94edae675e248 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 23 Jul 2009 11:18:49 +0900 Subject: swiotlb: remove unnecessary swiotlb_bus_to_virt swiotlb_bus_to_virt is unncessary; we can use swiotlb_bus_to_phys and phys_to_virt instead. Signed-off-by: FUJITA Tomonori Acked-by: Becky Bruce diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c index 68ccf11..41534ae 100644 --- a/arch/powerpc/kernel/dma-swiotlb.c +++ b/arch/powerpc/kernel/dma-swiotlb.c @@ -24,16 +24,6 @@ int swiotlb __read_mostly; unsigned int ppc_swiotlb_enable; -void *swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t addr) -{ - unsigned long pfn = PFN_DOWN(swiotlb_bus_to_phys(hwdev, addr)); - void *pageaddr = page_address(pfn_to_page(pfn)); - - if (pageaddr != NULL) - return pageaddr + (addr % PAGE_SIZE); - return NULL; -} - dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr) { return paddr + get_dma_direct_offset(hwdev); diff --git a/lib/swiotlb.c b/lib/swiotlb.c index dc1cd1f..cba3db8 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -124,17 +124,13 @@ phys_addr_t __weak swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr) return baddr; } +/* Note that this doesn't work with highmem page */ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev, volatile void *address) { return swiotlb_phys_to_bus(hwdev, virt_to_phys(address)); } -void * __weak swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address) -{ - return phys_to_virt(swiotlb_bus_to_phys(hwdev, address)); -} - int __weak swiotlb_arch_address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t size) { @@ -307,9 +303,10 @@ address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t size) return swiotlb_arch_address_needs_mapping(hwdev, addr, size); } -static int is_swiotlb_buffer(char *addr) +static int is_swiotlb_buffer(phys_addr_t paddr) { - return addr >= io_tlb_start && addr < io_tlb_end; + return paddr >= virt_to_phys(io_tlb_start) && + paddr < virt_to_phys(io_tlb_end); } /* @@ -582,11 +579,13 @@ EXPORT_SYMBOL(swiotlb_alloc_coherent); void swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, - dma_addr_t dma_handle) + dma_addr_t dev_addr) { + phys_addr_t paddr = swiotlb_bus_to_phys(hwdev, dev_addr); + WARN_ON(irqs_disabled()); - if (!is_swiotlb_buffer(vaddr)) - free_pages((unsigned long) vaddr, get_order(size)); + if (!is_swiotlb_buffer(paddr)) + free_pages((unsigned long)vaddr, get_order(size)); else /* DMA_TO_DEVICE to avoid memcpy in unmap_single */ do_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE); @@ -671,19 +670,25 @@ EXPORT_SYMBOL_GPL(swiotlb_map_page); static void unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir) { - char *dma_addr = swiotlb_bus_to_virt(hwdev, dev_addr); + phys_addr_t paddr = swiotlb_bus_to_phys(hwdev, dev_addr); BUG_ON(dir == DMA_NONE); - if (is_swiotlb_buffer(dma_addr)) { - do_unmap_single(hwdev, dma_addr, size, dir); + if (is_swiotlb_buffer(paddr)) { + do_unmap_single(hwdev, phys_to_virt(paddr), size, dir); return; } if (dir != DMA_FROM_DEVICE) return; - dma_mark_clean(dma_addr, size); + /* + * phys_to_virt doesn't work with hihgmem page but we could + * call dma_mark_clean() with hihgmem page here. However, we + * are fine since dma_mark_clean() is null on POWERPC. We can + * make dma_mark_clean() take a physical address if necessary. + */ + dma_mark_clean(phys_to_virt(paddr), size); } void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr, @@ -708,19 +713,19 @@ static void swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir, int target) { - char *dma_addr = swiotlb_bus_to_virt(hwdev, dev_addr); + phys_addr_t paddr = swiotlb_bus_to_phys(hwdev, dev_addr); BUG_ON(dir == DMA_NONE); - if (is_swiotlb_buffer(dma_addr)) { - sync_single(hwdev, dma_addr, size, dir, target); + if (is_swiotlb_buffer(paddr)) { + sync_single(hwdev, phys_to_virt(paddr), size, dir, target); return; } if (dir != DMA_FROM_DEVICE) return; - dma_mark_clean(dma_addr, size); + dma_mark_clean(phys_to_virt(paddr), size); } void -- cgit v0.10.2 From 99becaca86d184a4433e9fde879ff97303d7669f Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:04:54 +0900 Subject: x86: add dma_capable() to replace is_buffer_dma_capable() dma_capable() eventually replaces is_buffer_dma_capable(), which tells if a memory area is dma-capable or not. The problem of is_buffer_dma_capable() is that it doesn't take a pointer to struct device so it doesn't work for POWERPC. Signed-off-by: FUJITA Tomonori diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 1c3f943..adac59c 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -55,6 +55,14 @@ extern int dma_set_mask(struct device *dev, u64 mask); extern void *dma_generic_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, gfp_t flag); +static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +{ + if (!dev->dma_mask) + return 0; + + return addr + size <= *dev->dma_mask; +} + static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction dir) -- cgit v0.10.2 From a4c2baa6e148adfb27beaf16b6fb6d465b5b3acb Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:04:55 +0900 Subject: x86: replace is_buffer_dma_capable() with dma_capable Signed-off-by: FUJITA Tomonori diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 1a041bc..3c945c0 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -147,7 +147,7 @@ again: return NULL; addr = page_to_phys(page); - if (!is_buffer_dma_capable(dma_mask, addr, size)) { + if (addr + size > dma_mask) { __free_pages(page, get_order(size)); if (dma_mask < DMA_BIT_MASK(32) && !(flag & GFP_DMA)) { diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index d2e56b8..98a827e 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -190,14 +190,13 @@ static void iommu_full(struct device *dev, size_t size, int dir) static inline int need_iommu(struct device *dev, unsigned long addr, size_t size) { - return force_iommu || - !is_buffer_dma_capable(*dev->dma_mask, addr, size); + return force_iommu || !dma_capable(dev, addr, size); } static inline int nonforced_iommu(struct device *dev, unsigned long addr, size_t size) { - return !is_buffer_dma_capable(*dev->dma_mask, addr, size); + return !dma_capable(dev, addr, size); } /* Map a single continuous physical area into the IOMMU. diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c index 71d412a..c0a4222 100644 --- a/arch/x86/kernel/pci-nommu.c +++ b/arch/x86/kernel/pci-nommu.c @@ -14,7 +14,7 @@ static int check_addr(char *name, struct device *hwdev, dma_addr_t bus, size_t size) { - if (hwdev && !is_buffer_dma_capable(*hwdev->dma_mask, bus, size)) { + if (hwdev && !dma_capable(hwdev, bus, size)) { if (*hwdev->dma_mask >= DMA_BIT_MASK(32)) printk(KERN_ERR "nommu_%s: overflow %Lx+%zu of device mask %Lx\n", -- cgit v0.10.2 From a0b00ca84b3ecb9eebd62ad34880d8cc0d988c8a Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:04:56 +0900 Subject: ia64: add dma_capable() to replace is_buffer_dma_capable() dma_capable() eventually replaces is_buffer_dma_capable(), which tells if a memory area is dma-capable or not. The problem of is_buffer_dma_capable() is that it doesn't take a pointer to struct device so it doesn't work for POWERPC. Signed-off-by: FUJITA Tomonori diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index 5a61b5c..88d0f86 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -69,6 +69,14 @@ dma_set_mask (struct device *dev, u64 mask) return 0; } +static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +{ + if (!dev->dma_mask) + return 0; + + return addr + size <= *dev->dma_mask; +} + extern int dma_get_cache_alignment(void); static inline void -- cgit v0.10.2 From 9a937c91eea31c4b594ea49a2a23c57003e04987 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:04:57 +0900 Subject: powerpc: add dma_capable() to replace is_buffer_dma_capable() dma_capable() eventually replaces is_buffer_dma_capable(), which tells if a memory area is dma-capable or not. The problem of is_buffer_dma_capable() is that it doesn't take a pointer to struct device so it doesn't work for POWERPC. Signed-off-by: FUJITA Tomonori Acked-by: Becky Bruce diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index b44aaab..6ff1f85 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -424,6 +424,19 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) #endif } +static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +{ + struct dma_mapping_ops *ops = get_dma_ops(dev); + + if (ops->addr_needs_map && ops->addr_needs_map(dev, addr, size)) + return 0; + + if (!dev->dma_mask) + return 0; + + return addr + size <= *dev->dma_mask; +} + #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) #ifdef CONFIG_NOT_COHERENT_CACHE -- cgit v0.10.2 From b9394647ac88faad9db0f9e92eac4db434faded6 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:04:58 +0900 Subject: swiotlb: use dma_capable() This converts swiotlb to use dma_capable() instead of swiotlb_arch_address_needs_mapping() and is_buffer_dma_capable(). Signed-off-by: FUJITA Tomonori Acked-by: Becky Bruce diff --git a/lib/swiotlb.c b/lib/swiotlb.c index cba3db8..a012d93 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -131,12 +131,6 @@ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev, return swiotlb_phys_to_bus(hwdev, virt_to_phys(address)); } -int __weak swiotlb_arch_address_needs_mapping(struct device *hwdev, - dma_addr_t addr, size_t size) -{ - return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size); -} - static void swiotlb_print_info(unsigned long bytes) { phys_addr_t pstart, pend; @@ -297,12 +291,6 @@ cleanup1: return -ENOMEM; } -static inline int -address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t size) -{ - return swiotlb_arch_address_needs_mapping(hwdev, addr, size); -} - static int is_swiotlb_buffer(phys_addr_t paddr) { return paddr >= virt_to_phys(io_tlb_start) && @@ -539,9 +527,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, dma_mask = hwdev->coherent_dma_mask; ret = (void *)__get_free_pages(flags, order); - if (ret && - !is_buffer_dma_capable(dma_mask, swiotlb_virt_to_bus(hwdev, ret), - size)) { + if (ret && swiotlb_virt_to_bus(hwdev, ret) + size > dma_mask) { /* * The allocated memory isn't reachable by the device. */ @@ -563,7 +549,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, dev_addr = swiotlb_virt_to_bus(hwdev, ret); /* Confirm address can be DMA'd by device */ - if (!is_buffer_dma_capable(dma_mask, dev_addr, size)) { + if (dev_addr + size > dma_mask) { printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n", (unsigned long long)dma_mask, (unsigned long long)dev_addr); @@ -635,7 +621,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page, * we can safely return the device addr and not worry about bounce * buffering it. */ - if (!address_needs_mapping(dev, dev_addr, size) && !swiotlb_force) + if (dma_capable(dev, dev_addr, size) && !swiotlb_force) return dev_addr; /* @@ -652,7 +638,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page, /* * Ensure that the address returned is DMA'ble */ - if (address_needs_mapping(dev, dev_addr, size)) + if (!dma_capable(dev, dev_addr, size)) panic("map_single: bounce buffer is not DMA'ble"); return dev_addr; @@ -805,7 +791,7 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems, dma_addr_t dev_addr = swiotlb_phys_to_bus(hwdev, paddr); if (swiotlb_force || - address_needs_mapping(hwdev, dev_addr, sg->length)) { + !dma_capable(hwdev, dev_addr, sg->length)) { void *map = map_single(hwdev, sg_phys(sg), sg->length, dir); if (!map) { -- cgit v0.10.2 From 30945fdf6a08f52370dab3bc162e96c4b4e36082 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:04:59 +0900 Subject: powerpc: remove unncesary swiotlb_arch_address_needs_mapping swiotlb doesn't use swiotlb_arch_address_needs_mapping(); it uses dma_capalbe(). We can remove unnecessary swiotlb_arch_address_needs_mapping(). We can remove swiotlb_addr_needs_map() and is_buffer_dma_capable() in swiotlb_pci_addr_needs_map() too; dma_capable() handles the features that both provide. Signed-off-by: FUJITA Tomonori Acked-by: Becky Bruce diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c index 41534ae..a3bbe02 100644 --- a/arch/powerpc/kernel/dma-swiotlb.c +++ b/arch/powerpc/kernel/dma-swiotlb.c @@ -36,28 +36,11 @@ phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr) } /* - * Determine if an address needs bounce buffering via swiotlb. - * Going forward I expect the swiotlb code to generalize on using - * a dma_ops->addr_needs_map, and this function will move from here to the - * generic swiotlb code. - */ -int -swiotlb_arch_address_needs_mapping(struct device *hwdev, dma_addr_t addr, - size_t size) -{ - struct dma_mapping_ops *dma_ops = get_dma_ops(hwdev); - - BUG_ON(!dma_ops); - return dma_ops->addr_needs_map(hwdev, addr, size); -} - -/* * Determine if an address is reachable by a pci device, or if we must bounce. */ static int swiotlb_pci_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size) { - u64 mask = dma_get_mask(hwdev); dma_addr_t max; struct pci_controller *hose; struct pci_dev *pdev = to_pci_dev(hwdev); @@ -69,16 +52,9 @@ swiotlb_pci_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size) if ((addr + size > max) | (addr < hose->dma_window_base_cur)) return 1; - return !is_buffer_dma_capable(mask, addr, size); -} - -static int -swiotlb_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size) -{ - return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size); + return 0; } - /* * At the moment, all platforms that use this code only require * swiotlb to be used if we're operating on HIGHMEM. Since @@ -94,7 +70,6 @@ struct dma_mapping_ops swiotlb_dma_ops = { .dma_supported = swiotlb_dma_supported, .map_page = swiotlb_map_page, .unmap_page = swiotlb_unmap_page, - .addr_needs_map = swiotlb_addr_needs_map, .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu, .sync_single_range_for_device = swiotlb_sync_single_range_for_device, .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu, -- cgit v0.10.2 From 8f2502fd8157632909ff335a3c628e7caeec5e03 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:05:00 +0900 Subject: remove is_buffer_dma_capable() is_buffer_dma_capable() was replaced with dma_capable(). is_buffer_dma_capable() tells if a buffer is dma-capable or not. However, it doesn't take a pointer to struct device so it doesn't work for POWERPC. Signed-off-by: FUJITA Tomonori Acked-by: Becky Bruce diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 07dfd46..c0f6c3c 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -98,11 +98,6 @@ static inline int is_device_dma_capable(struct device *dev) return dev->dma_mask != NULL && *dev->dma_mask != DMA_MASK_NONE; } -static inline int is_buffer_dma_capable(u64 mask, dma_addr_t addr, size_t size) -{ - return addr + size <= mask; -} - #ifdef CONFIG_HAS_DMA #include #else -- cgit v0.10.2 From 8d4f5339d1ee4027c07e6b2a1cfa9dc41b0d383b Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:05:01 +0900 Subject: x86, IA64, powerpc: add phys_to_dma() and dma_to_phys() This adds two functions, phys_to_dma() and dma_to_phys() to x86, IA64 and powerpc. swiotlb uses them. phys_to_dma() converts a physical address to a dma address. dma_to_phys() does the opposite. Signed-off-by: FUJITA Tomonori Acked-by: Becky Bruce diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index 88d0f86..f91829d 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -77,6 +77,16 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) return addr + size <= *dev->dma_mask; } +static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) +{ + return paddr; +} + +static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) +{ + return daddr; +} + extern int dma_get_cache_alignment(void); static inline void diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index 6ff1f85..0c34371 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -437,6 +437,16 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) return addr + size <= *dev->dma_mask; } +static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) +{ + return paddr + get_dma_direct_offset(dev); +} + +static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) +{ + return daddr - get_dma_direct_offset(dev); +} + #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) #ifdef CONFIG_NOT_COHERENT_CACHE diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index adac59c..0ee770d 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -63,6 +63,16 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) return addr + size <= *dev->dma_mask; } +static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) +{ + return paddr; +} + +static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) +{ + return daddr; +} + static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction dir) -- cgit v0.10.2 From 862d196b27bd30a5ab8109d5cdb37980d81b1fe9 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:05:02 +0900 Subject: swiotlb: use phys_to_dma and dma_to_phys This converts swiotlb to use phys_to_dma and dma_to_phys instead of swiotlb_phys_to_bus() and swiotlb_bus_to_phys(). swiotlb_phys_to_bus() and swiotlb_bus_to_phys() are not necessary so this patch also removes them. Signed-off-by: FUJITA Tomonori Acked-by: Becky Bruce diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index a977da2..73b1f1c 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -23,11 +23,6 @@ struct scatterlist; extern void swiotlb_init(void); -extern dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, - phys_addr_t address); -extern phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, - dma_addr_t address); - extern void *swiotlb_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t flags); diff --git a/lib/swiotlb.c b/lib/swiotlb.c index a012d93..9e2fe3e 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -114,21 +114,11 @@ setup_io_tlb_npages(char *str) __setup("swiotlb=", setup_io_tlb_npages); /* make io_tlb_overflow tunable too? */ -dma_addr_t __weak swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr) -{ - return paddr; -} - -phys_addr_t __weak swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr) -{ - return baddr; -} - /* Note that this doesn't work with highmem page */ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev, volatile void *address) { - return swiotlb_phys_to_bus(hwdev, virt_to_phys(address)); + return phys_to_dma(hwdev, virt_to_phys(address)); } static void swiotlb_print_info(unsigned long bytes) @@ -567,7 +557,7 @@ void swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dev_addr) { - phys_addr_t paddr = swiotlb_bus_to_phys(hwdev, dev_addr); + phys_addr_t paddr = dma_to_phys(hwdev, dev_addr); WARN_ON(irqs_disabled()); if (!is_swiotlb_buffer(paddr)) @@ -612,7 +602,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page, struct dma_attrs *attrs) { phys_addr_t phys = page_to_phys(page) + offset; - dma_addr_t dev_addr = swiotlb_phys_to_bus(dev, phys); + dma_addr_t dev_addr = phys_to_dma(dev, phys); void *map; BUG_ON(dir == DMA_NONE); @@ -656,7 +646,7 @@ EXPORT_SYMBOL_GPL(swiotlb_map_page); static void unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir) { - phys_addr_t paddr = swiotlb_bus_to_phys(hwdev, dev_addr); + phys_addr_t paddr = dma_to_phys(hwdev, dev_addr); BUG_ON(dir == DMA_NONE); @@ -699,7 +689,7 @@ static void swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir, int target) { - phys_addr_t paddr = swiotlb_bus_to_phys(hwdev, dev_addr); + phys_addr_t paddr = dma_to_phys(hwdev, dev_addr); BUG_ON(dir == DMA_NONE); @@ -788,7 +778,7 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems, for_each_sg(sgl, sg, nelems, i) { phys_addr_t paddr = sg_phys(sg); - dma_addr_t dev_addr = swiotlb_phys_to_bus(hwdev, paddr); + dma_addr_t dev_addr = phys_to_dma(hwdev, paddr); if (swiotlb_force || !dma_capable(hwdev, dev_addr, sg->length)) { -- cgit v0.10.2 From 8ab7ff42c9dd9231706a4ba7120eed22ff52a93b Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:05:03 +0900 Subject: powerpc: remove unused swiotlb_phys_to_bus() and swiotlb_bus_to_phys() phys_to_dma() and dma_to_phys() are used instead of swiotlb_phys_to_bus() and swiotlb_bus_to_phys(). Signed-off-by: FUJITA Tomonori Acked-by: Becky Bruce diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c index a3bbe02..e8a57de 100644 --- a/arch/powerpc/kernel/dma-swiotlb.c +++ b/arch/powerpc/kernel/dma-swiotlb.c @@ -24,17 +24,6 @@ int swiotlb __read_mostly; unsigned int ppc_swiotlb_enable; -dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr) -{ - return paddr + get_dma_direct_offset(hwdev); -} - -phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr) - -{ - return baddr - get_dma_direct_offset(hwdev); -} - /* * Determine if an address is reachable by a pci device, or if we must bounce. */ -- cgit v0.10.2 From b683d42693c4e92b838117f5c6f7b90bfa1525c9 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 10 Jul 2009 10:05:04 +0900 Subject: x86: remove unused swiotlb_phys_to_bus() and swiotlb_bus_to_phys() phys_to_dma() and dma_to_phys() are used instead of swiotlb_phys_to_bus() and swiotlb_bus_to_phys(). Signed-off-by: FUJITA Tomonori diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index 165bd7f..e8a3501 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -13,16 +13,6 @@ int swiotlb __read_mostly; -dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr) -{ - return paddr; -} - -phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr) -{ - return baddr; -} - static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t flags) { -- cgit v0.10.2 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 diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 0b5b480..7b8a5f9 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -139,6 +139,10 @@ 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... ------------------------------------------------------------------------ Even if you see such a message, DON'T PANIC. Take a deep breath and diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 3da85ca..ab3bcb7 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 c921264..780e1a7 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 df87c01..6794d02 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 9de97f3..c6dc625 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 v0.10.2 From 4417932315d185b59c0089091de7fa509c59fd5a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Jul 2009 17:03:49 +0200 Subject: ALSA: hda - Don't create unneeded digital input source for IDT 92HD71x The current driver creates always the digital input source mixer elements for IDT 92HD71x codecs no matter whether digital mics are present. This patch adds the proper check to avoid the creation of these controls if unnecessary. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c6dc625..4e3531b 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5355,7 +5355,6 @@ again: /* no output amps */ spec->num_pwrs = 0; spec->mixer = stac92hd71bxx_analog_mixer; - spec->dinput_mux = &spec->private_dimux; /* disable VSW */ spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; @@ -5366,8 +5365,11 @@ again: spec->num_dmics = stac92hd71bxx_connected_ports(codec, stac92hd71bxx_dmic_nids, STAC92HD71BXX_NUM_DMICS - 1); - spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); - ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 2; + if (spec->num_dmics) { + spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); + spec->dinput_mux = &spec->private_dimux; + ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 2; + } break; case 0x111d7603: /* 6 Port with Analog Mixer */ if ((codec->revision_id & 0xf) == 1) @@ -5379,15 +5381,17 @@ again: default: memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer, sizeof(stac92hd71bxx_dmux_amixer)); - spec->dinput_mux = &spec->private_dimux; spec->mixer = stac92hd71bxx_analog_mixer; spec->init = stac92hd71bxx_analog_core_init; codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; spec->num_dmics = stac92hd71bxx_connected_ports(codec, stac92hd71bxx_dmic_nids, STAC92HD71BXX_NUM_DMICS); - spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); - ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1; + if (spec->num_dmics) { + spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); + spec->dinput_mux = &spec->private_dimux; + ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1; + } } if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) -- cgit v0.10.2 From 6479c63188290beae83ade3243b9d6eb47d394b6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Jul 2009 18:20:25 +0200 Subject: ALSA: hda - Create Capture controls dynamically Instead of static snd_kcontrol_new arrays, create "Capture Volume" and "Capture Switch" controls dynamically based on the mixer attr values (made via HDA_COMPOSE_AMP_VAL()). This reduces the code size and gives more flexibility to change the number of controls later. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 4e3531b..be6cf2c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -238,6 +238,11 @@ struct sigmatel_spec { unsigned int num_dmuxes; hda_nid_t *smux_nids; unsigned int num_smuxes; + + unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */ + unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ + unsigned int num_caps; /* number of capture volume/switch elements */ + const char **spdif_labels; hda_nid_t dig_in_nid; @@ -334,6 +339,13 @@ static hda_nid_t stac92hd73xx_smux_nids[2] = { 0x22, 0x23, }; +#define STAC92HD73XX_NUM_CAPS 2 +static unsigned long stac92hd73xx_capvols[] = { + HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), +}; +#define stac92hd73xx_capsws stac92hd73xx_capvols + #define STAC92HD83XXX_NUM_DMICS 2 static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { 0x11, 0x12, 0 @@ -365,6 +377,13 @@ static hda_nid_t stac92hd83xxx_amp_nids[1] = { 0xc, }; +#define STAC92HD83XXX_NUM_CAPS 2 +static unsigned long stac92hd83xxx_capvols[] = { + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_OUTPUT), +}; +#define stac92hd83xxx_capsws stac92hd83xxx_capvols + static hda_nid_t stac92hd71bxx_pwr_nids[3] = { 0x0a, 0x0d, 0x0f }; @@ -394,6 +413,13 @@ static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = { 0x22, 0 }; +#define STAC92HD71BXX_NUM_CAPS 2 +static unsigned long stac92hd71bxx_capvols[] = { + HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), +}; +#define stac92hd71bxx_capsws stac92hd71bxx_capvols + static hda_nid_t stac925x_adc_nids[1] = { 0x03, }; @@ -415,6 +441,13 @@ static hda_nid_t stac925x_dmux_nids[1] = { 0x14, }; +static unsigned long stac925x_capvols[] = { + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), +}; +static unsigned long stac925x_capsws[] = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), +}; + static hda_nid_t stac922x_adc_nids[2] = { 0x06, 0x07, }; @@ -423,6 +456,13 @@ static hda_nid_t stac922x_mux_nids[2] = { 0x12, 0x13, }; +#define STAC922X_NUM_CAPS 2 +static unsigned long stac922x_capvols[] = { + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), +}; +#define stac922x_capsws stac922x_capvols + static hda_nid_t stac927x_slave_dig_outs[2] = { 0x1f, 0, }; @@ -452,6 +492,18 @@ static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = { 0x13, 0x14, 0 }; +#define STAC927X_NUM_CAPS 3 +static unsigned long stac927x_capvols[] = { + HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT), +}; +static unsigned long stac927x_capsws[] = { + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), +}; + static const char *stac927x_spdif_labels[5] = { "Digital Playback", "ADAT", "Analog Mux 1", "Analog Mux 2", "Analog Mux 3" @@ -478,6 +530,16 @@ static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { 0x17, 0x18, 0 }; +#define STAC9205_NUM_CAPS 2 +static unsigned long stac9205_capvols[] = { + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT), +}; +static unsigned long stac9205_capsws[] = { + HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT), +}; + static hda_nid_t stac9200_pin_nids[8] = { 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, @@ -1069,12 +1131,6 @@ static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = { HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), - { } /* end */ }; @@ -1094,12 +1150,6 @@ static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = { }; static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = { - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), @@ -1118,12 +1168,6 @@ static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = { }; static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = { - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), @@ -1143,12 +1187,6 @@ static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = { static struct snd_kcontrol_new stac92hd83xxx_mixer[] = { - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT), HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT), @@ -1169,17 +1207,6 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = { }; static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), - /* analog pc-beep replaced with digital beep support */ - /* - HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT), - */ - HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT), @@ -1198,29 +1225,9 @@ static struct snd_kcontrol_new stac92hd71bxx_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2) }; -static struct snd_kcontrol_new stac92hd71bxx_mixer[] = { - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), - { } /* end */ -}; - static struct snd_kcontrol_new stac925x_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new stac9205_mixer[] = { - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT), { } /* end */ }; @@ -1229,29 +1236,6 @@ static struct snd_kcontrol_new stac9205_loopback[] = { {} }; -/* This needs to be generated dynamically based on sequence */ -static struct snd_kcontrol_new stac922x_mixer[] = { - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT), - { } /* end */ -}; - - -static struct snd_kcontrol_new stac927x_mixer[] = { - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT), - { } /* end */ -}; - static struct snd_kcontrol_new stac927x_loopback[] = { STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1), {} @@ -1309,9 +1293,11 @@ static int stac92xx_build_controls(struct hda_codec *codec) int err; int i; - err = snd_hda_add_new_ctls(codec, spec->mixer); - if (err < 0) - return err; + if (spec->mixer) { + err = snd_hda_add_new_ctls(codec, spec->mixer); + if (err < 0) + return err; + } for (i = 0; i < spec->num_mixers; i++) { err = snd_hda_add_new_ctls(codec, spec->mixers[i]); @@ -3317,6 +3303,21 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, return 0; } +static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol, + unsigned long sw, int idx) +{ + int err; + err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, + "Captuer Volume", vol); + if (err < 0) + return err; + err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx, + "Captuer Switch", sw); + if (err < 0) + return err; + return 0; +} + /* add playback controls from the parsed DAC table */ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) @@ -3703,7 +3704,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out { struct sigmatel_spec *spec = codec->spec; int hp_swap = 0; - int err; + int i, err; if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, @@ -3837,6 +3838,13 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out spec->autocfg.line_outs = 0; } + for (i = 0; i < spec->num_caps; i++) { + err = stac92xx_add_capvol_ctls(codec, spec->capvols[i], + spec->capsws[i], i); + if (err < 0) + return err; + } + err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -4898,6 +4906,9 @@ static int patch_stac925x(struct hda_codec *codec) spec->init = stac925x_core_init; spec->mixer = stac925x_mixer; + spec->num_caps = 1; + spec->capvols = stac925x_capvols; + spec->capsws = stac925x_capsws; err = stac92xx_parse_auto_config(codec, 0x8, 0x7); if (!err) { @@ -5001,6 +5012,10 @@ again: memcpy(&spec->private_dimux, &stac92hd73xx_dmux, sizeof(stac92hd73xx_dmux)); + spec->num_caps = STAC92HD73XX_NUM_CAPS; + spec->capvols = stac92hd73xx_capvols; + spec->capsws = stac92hd73xx_capsws; + switch (spec->board_config) { case STAC_DELL_EQ: spec->init = dell_eq_core_init; @@ -5120,6 +5135,10 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->num_dmics = STAC92HD83XXX_NUM_DMICS; spec->dinput_mux = &stac92hd83xxx_dmux; spec->pin_nids = stac92hd83xxx_pin_nids; + spec->num_caps = STAC92HD83XXX_NUM_CAPS; + spec->capvols = stac92hd83xxx_capvols; + spec->capsws = stac92hd83xxx_capsws; + spec->board_config = snd_hda_check_board_config(codec, STAC_92HD83XXX_MODELS, stac92hd83xxx_models, @@ -5308,6 +5327,10 @@ again: spec->dmic_nids = stac92hd71bxx_dmic_nids; spec->dmux_nids = stac92hd71bxx_dmux_nids; + spec->num_caps = STAC92HD71BXX_NUM_CAPS; + spec->capvols = stac92hd71bxx_capvols; + spec->capsws = stac92hd71bxx_capsws; + switch (codec->vendor_id) { case 0x111d76b6: /* 4 Port without Analog Mixer */ case 0x111d76b7: @@ -5317,7 +5340,6 @@ again: case 0x111d76b5: memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_nomixer, sizeof(stac92hd71bxx_dmux_nomixer)); - spec->mixer = stac92hd71bxx_mixer; spec->init = stac92hd71bxx_core_init; codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; spec->num_dmics = stac92hd71bxx_connected_ports(codec, @@ -5566,7 +5588,10 @@ static int patch_stac922x(struct hda_codec *codec) spec->num_pwrs = 0; spec->init = stac922x_core_init; - spec->mixer = stac922x_mixer; + + spec->num_caps = STAC922X_NUM_CAPS; + spec->capvols = stac922x_capvols; + spec->capsws = stac922x_capsws; spec->multiout.dac_nids = spec->dac_nids; @@ -5641,7 +5666,6 @@ static int patch_stac927x(struct hda_codec *codec) spec->num_dmics = 0; spec->init = d965_core_init; - spec->mixer = stac927x_mixer; break; case STAC_DELL_BIOS: switch (codec->subsystem_id) { @@ -5666,7 +5690,6 @@ static int patch_stac927x(struct hda_codec *codec) spec->num_dmics = STAC927X_NUM_DMICS; spec->init = d965_core_init; - spec->mixer = stac927x_mixer; spec->dmux_nids = stac927x_dmux_nids; spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids); break; @@ -5679,9 +5702,12 @@ static int patch_stac927x(struct hda_codec *codec) spec->num_dmics = 0; spec->init = stac927x_core_init; - spec->mixer = stac927x_mixer; } + spec->num_caps = STAC927X_NUM_CAPS; + spec->capvols = stac927x_capvols; + spec->capsws = stac927x_capsws; + spec->num_pwrs = 0; spec->aloopback_ctl = stac927x_loopback; spec->aloopback_mask = 0x40; @@ -5763,9 +5789,12 @@ static int patch_stac9205(struct hda_codec *codec) spec->num_pwrs = 0; spec->init = stac9205_core_init; - spec->mixer = stac9205_mixer; spec->aloopback_ctl = stac9205_loopback; + spec->num_caps = STAC9205_NUM_CAPS; + spec->capvols = stac9205_capvols; + spec->capsws = stac9205_capsws; + spec->aloopback_mask = 0x40; spec->aloopback_shift = 0; /* Turn on/off EAPD per HP plugging */ @@ -5840,12 +5869,6 @@ static struct hda_verb stac9872_core_init[] = { {} }; -static struct snd_kcontrol_new stac9872_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), - { } /* end */ -}; - static hda_nid_t stac9872_pin_nids[] = { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x13, 0x14, @@ -5859,6 +5882,11 @@ static hda_nid_t stac9872_mux_nids[] = { 0x15 }; +static unsigned long stac9872_capvols[] = { + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), +}; +#define stac9872_capsws stac9872_capvols + static unsigned int stac9872_vaio_pin_configs[9] = { 0x03211020, 0x411111f0, 0x411111f0, 0x03a15030, 0x411111f0, 0x90170110, 0x411111f0, 0x411111f0, @@ -5907,8 +5935,10 @@ static int patch_stac9872(struct hda_codec *codec) spec->adc_nids = stac9872_adc_nids; spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids); spec->mux_nids = stac9872_mux_nids; - spec->mixer = stac9872_mixer; spec->init = stac9872_core_init; + spec->num_caps = 1; + spec->capvols = stac9872_capvols; + spec->capsws = stac9872_capsws; err = stac92xx_parse_auto_config(codec, 0x10, 0x12); if (err < 0) { -- cgit v0.10.2 From 50c62f068ee67b5a0178855f502f4ea2ee931eed Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Jul 2009 18:25:29 +0200 Subject: ALSA: hda - Don't create analog mixer for IDT92HD71bxx The analog mixer unit on IDT 92HD71Bxx codecs is almost useless since we use only the direct connections from DAC to pin. Remove the controls to avoid unneeded confusion as default now. This can be still back via "analog_mixer = 1" hint. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index be6cf2c..66b1f3c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5376,7 +5376,8 @@ again: /* no output amps */ spec->num_pwrs = 0; - spec->mixer = stac92hd71bxx_analog_mixer; + if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) + spec->mixer = stac92hd71bxx_analog_mixer; /* disable VSW */ spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; @@ -5403,7 +5404,8 @@ again: default: memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer, sizeof(stac92hd71bxx_dmux_amixer)); - spec->mixer = stac92hd71bxx_analog_mixer; + if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) + spec->mixer = stac92hd71bxx_analog_mixer; spec->init = stac92hd71bxx_analog_core_init; codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; spec->num_dmics = stac92hd71bxx_connected_ports(codec, -- cgit v0.10.2 From b84eab08a67913581515a1184f1deedf1d54dc5d Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Tue, 28 Jul 2009 20:24:12 +0200 Subject: ASoC: CX20442: fix issues pointed out by subsystem maintainer The patch fixes some checkpatch identified issues and adds a comment about line discipline interaction to my driver code, as requested by Mark on my inital submission (thank you Mark for applying my imperfect patch anyway). It also fixes MODULE_ALIAS mismatch as used in my machine driver. Signed-off-by: Janusz Krzysztofik Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index f64483c..7bbb77b 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -132,7 +132,7 @@ enum v253_vls { static int cx20442_pm_to_v253_vls(u8 value) { - switch(value & ~(1 << CX20442_AGC)) { + switch (value & ~(1 << CX20442_AGC)) { case 0: return V253_VLS_T; case (1 << CX20442_SPKOUT): @@ -152,7 +152,7 @@ static int cx20442_pm_to_v253_vls(u8 value) } static int cx20442_pm_to_v253_vsp(u8 value) { - switch(value & ~(1 << CX20442_AGC)) { + switch (value & ~(1 << CX20442_AGC)) { case (1 << CX20442_SPKOUT): case (1 << CX20442_MIC): case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC): @@ -171,6 +171,9 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, if (reg >= codec->reg_cache_size) return -EINVAL; + /* hw_write and control_data pointers required for talking to the modem + * are expected to be set by the machine driver's line discipline + * initialization code */ if (!codec->hw_write || !codec->control_data) return -EIO; @@ -182,7 +185,7 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, return vls; vsp = cx20442_pm_to_v253_vsp(value); - if (vsp < 0 ) + if (vsp < 0) return vsp; if ((vls == V253_VLS_T) || @@ -232,7 +235,7 @@ static int cx20442_codec_probe(struct platform_device *pdev) struct snd_soc_codec *codec; int ret; - if(!cx20442_codec) { + if (!cx20442_codec) { dev_err(&pdev->dev, "cx20442 not yet discovered\n"); return -ENODEV; } @@ -310,13 +313,13 @@ static int cx20442_register(struct cx20442_priv *cx20442) ret = snd_soc_register_codec(codec); if (ret != 0) { - //dev_err(&dev->dev, "Failed to register codec: %d\n", ret); + dev_err(&codec->dev, "Failed to register codec: %d\n", ret); goto err; } ret = snd_soc_register_dai(&cx20442_dai); if (ret != 0) { - //dev_err(&dev->dev, "Failed to register DAI: %d\n", ret); + dev_err(&codec->dev, "Failed to register DAI: %d\n", ret); goto err_codec; } @@ -392,4 +395,4 @@ module_exit(cx20442_exit); MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver"); MODULE_AUTHOR("Janusz Krzysztofik"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:cx20442-codec"); +MODULE_ALIAS("platform:cx20442"); -- cgit v0.10.2 From 01e2ab207ca5a8edac622ab112b581d41b5eb36e Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Mon, 27 Jul 2009 18:06:39 +0800 Subject: ASoC: blackfin I2S(TDM mode) CPU DAI driver The I2S DAI driver for blackfin SPORT, but works in TDM mode. I2S is not a special case of TDM with only left and right two slots for SPORT interface. I2S coordinates with TDM in SPORT, but not a part of TDM. TDM require different hardware configuration with I2S, not only different slot number. One is "Stereo Serial Operation" mode of SPORT, the other one is "Multichannel Operation" mode. They are incompatible at the same time. Hardware and DMA description and data transfer flow are much different for I2S and TDM. Merging them as a whole will be very ugly and difficult to maintain. So we don't define a new DAI type, but give two DAI instances for standard I2S and TDM, both in I2S-family DAI type. The TDM instance still uses the I2S-family DAI type. Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mark Brown diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 811596f..2ab6d2f 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -7,6 +7,15 @@ config SND_BF5XX_I2S mode (supports single stereo In/Out). You will also need to select the audio interfaces to support below. +config SND_BF5XX_TDM + tristate "SoC I2S(TDM mode) Audio for the ADI BF5xx chip" + depends on (BLACKFIN && SND_SOC) + help + Say Y or M if you want to add support for codecs attached to + the Blackfin SPORT (synchronous serial ports) interface in TDM + mode. + You will also need to select the audio interfaces to support below. + config SND_BF5XX_SOC_SSM2602 tristate "SoC SSM2602 Audio support for BF52x ezkit" depends on SND_BF5XX_I2S @@ -69,6 +78,10 @@ config SND_BF5XX_SOC_I2S tristate select SND_BF5XX_SOC_SPORT +config SND_BF5XX_SOC_TDM + tristate + select SND_BF5XX_SOC_SPORT + config SND_BF5XX_SOC_AC97 tristate select AC97_BUS @@ -85,7 +98,7 @@ config SND_BF5XX_SOC_AD1980 config SND_BF5XX_SPORT_NUM int "Set a SPORT for Sound chip" - depends on (SND_BF5XX_I2S || SND_BF5XX_AC97) + depends on (SND_BF5XX_I2S || SND_BF5XX_AC97 || SND_BF5XX_TDM) range 0 3 if BF54x range 0 1 if !BF54x default 0 diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile index 97bb37a..f8619262 100644 --- a/sound/soc/blackfin/Makefile +++ b/sound/soc/blackfin/Makefile @@ -1,15 +1,19 @@ # Blackfin Platform Support snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o +snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o snd-soc-bf5xx-sport-objs := bf5xx-sport.o snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o +snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o +obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o +obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o # Blackfin Machine Support snd-ad1980-objs := bf5xx-ad1980.o diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c new file mode 100644 index 0000000..af7fa8d --- /dev/null +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c @@ -0,0 +1,330 @@ +/* + * File: sound/soc/blackfin/bf5xx-tdm-pcm.c + * Author: Barry Song + * + * Created: Tue June 06 2009 + * Description: DMA driver for tdm codec + * + * Modified: + * Copyright 2009 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or 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 "bf5xx-tdm-pcm.h" +#include "bf5xx-tdm.h" +#include "bf5xx-sport.h" + +#define PCM_BUFFER_MAX 0x10000 +#define FRAGMENT_SIZE_MIN (4*1024) +#define FRAGMENTS_MIN 2 +#define FRAGMENTS_MAX 32 + +static void bf5xx_dma_irq(void *data) +{ + struct snd_pcm_substream *pcm = data; + snd_pcm_period_elapsed(pcm); +} + +static const struct snd_pcm_hardware bf5xx_pcm_hardware = { + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_RESUME), + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rates = SNDRV_PCM_RATE_48000, + .channels_min = 2, + .channels_max = 8, + .buffer_bytes_max = PCM_BUFFER_MAX, + .period_bytes_min = FRAGMENT_SIZE_MIN, + .period_bytes_max = PCM_BUFFER_MAX/2, + .periods_min = FRAGMENTS_MIN, + .periods_max = FRAGMENTS_MAX, +}; + +static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + size_t size = bf5xx_pcm_hardware.buffer_bytes_max; + snd_pcm_lib_malloc_pages(substream, size * 4); + + return 0; +} + +static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_lib_free_pages(substream); + + return 0; +} + +static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sport_device *sport = runtime->private_data; + int fragsize_bytes = frames_to_bytes(runtime, runtime->period_size); + + fragsize_bytes /= runtime->channels; + /* inflate the fragsize to match the dma width of SPORT */ + fragsize_bytes *= 8; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + sport_set_tx_callback(sport, bf5xx_dma_irq, substream); + sport_config_tx_dma(sport, runtime->dma_area, + runtime->periods, fragsize_bytes); + } else { + sport_set_rx_callback(sport, bf5xx_dma_irq, substream); + sport_config_rx_dma(sport, runtime->dma_area, + runtime->periods, fragsize_bytes); + } + + return 0; +} + +static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sport_device *sport = runtime->private_data; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + sport_tx_start(sport); + else + sport_rx_start(sport); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + sport_tx_stop(sport); + else + sport_rx_stop(sport); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sport_device *sport = runtime->private_data; + unsigned int diff; + snd_pcm_uframes_t frames; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + diff = sport_curr_offset_tx(sport); + frames = diff / (8*4); /* 32 bytes per frame */ + } else { + diff = sport_curr_offset_rx(sport); + frames = diff / (8*4); + } + return frames; +} + +static int bf5xx_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + if (sport_handle != NULL) + runtime->private_data = sport_handle; + else { + pr_err("sport_handle is NULL\n"); + ret = -ENODEV; + } +out: + return ret; +} + +static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, + snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count) +{ + unsigned int *src; + unsigned int *dst; + int i; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + src = buf; + dst = (unsigned int *)substream->runtime->dma_area; + + dst += pos * 8; + while (count--) { + for (i = 0; i < substream->runtime->channels; i++) + *(dst + i) = *src++; + dst += 8; + } + } else { + src = (unsigned int *)substream->runtime->dma_area; + dst = buf; + + src += pos * 8; + while (count--) { + for (i = 0; i < substream->runtime->channels; i++) + *dst++ = *(src+i); + src += 8; + } + } + + return 0; +} + +static int bf5xx_pcm_silence(struct snd_pcm_substream *substream, + int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count) +{ + unsigned char *buf = substream->runtime->dma_area; + buf += pos * 8 * 4; + memset(buf, '\0', count * 8 * 4); + + return 0; +} + + +struct snd_pcm_ops bf5xx_pcm_tdm_ops = { + .open = bf5xx_pcm_open, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = bf5xx_pcm_hw_params, + .hw_free = bf5xx_pcm_hw_free, + .prepare = bf5xx_pcm_prepare, + .trigger = bf5xx_pcm_trigger, + .pointer = bf5xx_pcm_pointer, + .copy = bf5xx_pcm_copy, + .silence = bf5xx_pcm_silence, +}; + +static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = bf5xx_pcm_hardware.buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_coherent(pcm->card->dev, size * 4, + &buf->addr, GFP_KERNEL); + if (!buf->area) { + pr_err("Failed to allocate dma memory \ + Please increase uncached DMA memory region\n"); + return -ENOMEM; + } + buf->bytes = size; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + sport_handle->tx_buf = buf->area; + else + sport_handle->rx_buf = buf->area; + + return 0; +} + +static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + dma_free_coherent(NULL, buf->bytes, buf->area, 0); + buf->area = NULL; + } + if (sport_handle) + sport_done(sport_handle); +} + +static u64 bf5xx_pcm_dmamask = DMA_32BIT_MASK; + +static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &bf5xx_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_32BIT_MASK; + + if (dai->playback.channels_min) { + ret = bf5xx_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = bf5xx_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } +out: + return ret; +} + +struct snd_soc_platform bf5xx_tdm_soc_platform = { + .name = "bf5xx-audio", + .pcm_ops = &bf5xx_pcm_tdm_ops, + .pcm_new = bf5xx_pcm_tdm_new, + .pcm_free = bf5xx_pcm_free_dma_buffers, +}; +EXPORT_SYMBOL_GPL(bf5xx_tdm_soc_platform); + +static int __init bfin_pcm_tdm_init(void) +{ + return snd_soc_register_platform(&bf5xx_tdm_soc_platform); +} +module_init(bfin_pcm_tdm_init); + +static void __exit bfin_pcm_tdm_exit(void) +{ + snd_soc_unregister_platform(&bf5xx_tdm_soc_platform); +} +module_exit(bfin_pcm_tdm_exit); + +MODULE_AUTHOR("Barry Song"); +MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.h b/sound/soc/blackfin/bf5xx-tdm-pcm.h new file mode 100644 index 0000000..9e8473d --- /dev/null +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.h @@ -0,0 +1,21 @@ +/* + * linux/sound/arm/bf5xx-tdm-pcm.h -- ALSA PCM interface for the Blackfin + * + * Copyright 2009 Analog Device Inc. + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef _BF5XX_TDM_PCM_H +#define _BF5XX_TDM_PCM_H + +struct bf5xx_pcm_dma_params { + char *name; /* stream identifier */ +}; + +/* platform data */ +extern struct snd_soc_platform bf5xx_tdm_soc_platform; + +#endif diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c new file mode 100644 index 0000000..3096bad --- /dev/null +++ b/sound/soc/blackfin/bf5xx-tdm.c @@ -0,0 +1,343 @@ +/* + * File: sound/soc/blackfin/bf5xx-tdm.c + * Author: Barry Song + * + * Created: Thurs June 04 2009 + * Description: Blackfin I2S(TDM) CPU DAI driver + * Even though TDM mode can be as part of I2S DAI, but there + * are so much difference in configuration and data flow, + * it's very ugly to integrate I2S and TDM into a module + * + * Modified: + * Copyright 2009 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or 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 "bf5xx-sport.h" +#include "bf5xx-tdm.h" + +struct bf5xx_tdm_port { + u16 tcr1; + u16 rcr1; + u16 tcr2; + u16 rcr2; + int configured; +}; + +static struct bf5xx_tdm_port bf5xx_tdm; +static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; + +static struct sport_param sport_params[2] = { + { + .dma_rx_chan = CH_SPORT0_RX, + .dma_tx_chan = CH_SPORT0_TX, + .err_irq = IRQ_SPORT0_ERROR, + .regs = (struct sport_register *)SPORT0_TCR1, + }, + { + .dma_rx_chan = CH_SPORT1_RX, + .dma_tx_chan = CH_SPORT1_TX, + .err_irq = IRQ_SPORT1_ERROR, + .regs = (struct sport_register *)SPORT1_TCR1, + } +}; + +/* + * Setting the TFS pin selector for SPORT 0 based on whether the selected + * port id F or G. If the port is F then no conflict should exist for the + * TFS. When Port G is selected and EMAC then there is a conflict between + * the PHY interrupt line and TFS. Current settings prevent the conflict + * by ignoring the TFS pin when Port G is selected. This allows both + * ssm2602 using Port G and EMAC concurrently. + */ +#ifdef CONFIG_BF527_SPORT0_PORTF +#define LOCAL_SPORT0_TFS (P_SPORT0_TFS) +#else +#define LOCAL_SPORT0_TFS (0) +#endif + +static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, + P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0}, + {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI, + P_SPORT1_RSCLK, P_SPORT1_TFS, 0} }; + +static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + int ret = 0; + + /* interface format:support TDM,slave mode */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + break; + default: + printk(KERN_ERR "%s: Unknown DAI format type\n", __func__); + ret = -EINVAL; + break; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + break; + case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBS_CFM: + ret = -EINVAL; + break; + default: + printk(KERN_ERR "%s: Unknown DAI master type\n", __func__); + ret = -EINVAL; + break; + } + + return ret; +} + +static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int ret = 0; + + bf5xx_tdm.tcr2 &= ~0x1f; + bf5xx_tdm.rcr2 &= ~0x1f; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S32_LE: + bf5xx_tdm.tcr2 |= 31; + bf5xx_tdm.rcr2 |= 31; + sport_handle->wdsize = 4; + break; + /* at present, we only support 32bit transfer */ + default: + pr_err("not supported PCM format yet\n"); + return -EINVAL; + break; + } + + if (!bf5xx_tdm.configured) { + /* + * TX and RX are not independent,they are enabled at the + * same time, even if only one side is running. So, we + * need to configure both of them at the time when the first + * stream is opened. + * + * CPU DAI:slave mode. + */ + ret = sport_config_rx(sport_handle, bf5xx_tdm.rcr1, + bf5xx_tdm.rcr2, 0, 0); + if (ret) { + pr_err("SPORT is busy!\n"); + return -EBUSY; + } + + ret = sport_config_tx(sport_handle, bf5xx_tdm.tcr1, + bf5xx_tdm.tcr2, 0, 0); + if (ret) { + pr_err("SPORT is busy!\n"); + return -EBUSY; + } + + bf5xx_tdm.configured = 1; + } + + return 0; +} + +static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + /* No active stream, SPORT is allowed to be configured again. */ + if (!dai->active) + bf5xx_tdm.configured = 0; +} + +#ifdef CONFIG_PM +static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) +{ + struct sport_device *sport = + (struct sport_device *)dai->private_data; + + if (!dai->active) + return 0; + if (dai->capture.active) + sport_rx_stop(sport); + if (dai->playback.active) + sport_tx_stop(sport); + return 0; +} + +static int bf5xx_tdm_resume(struct snd_soc_dai *dai) +{ + int ret; + struct sport_device *sport = + (struct sport_device *)dai->private_data; + + if (!dai->active) + return 0; + + ret = sport_set_multichannel(sport, 8, 0xFF, 1); + if (ret) { + pr_err("SPORT is busy!\n"); + ret = -EBUSY; + } + + ret = sport_config_rx(sport, IRFS, 0x1F, 0, 0); + if (ret) { + pr_err("SPORT is busy!\n"); + ret = -EBUSY; + } + + ret = sport_config_tx(sport, ITFS, 0x1F, 0, 0); + if (ret) { + pr_err("SPORT is busy!\n"); + ret = -EBUSY; + } + + return 0; +} + +#else +#define bf5xx_tdm_suspend NULL +#define bf5xx_tdm_resume NULL +#endif + +static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = { + .hw_params = bf5xx_tdm_hw_params, + .set_fmt = bf5xx_tdm_set_dai_fmt, + .shutdown = bf5xx_tdm_shutdown, +}; + +struct snd_soc_dai bf5xx_tdm_dai = { + .name = "bf5xx-tdm", + .id = 0, + .suspend = bf5xx_tdm_suspend, + .resume = bf5xx_tdm_resume, + .playback = { + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE,}, + .capture = { + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE,}, + .ops = &bf5xx_tdm_dai_ops, +}; +EXPORT_SYMBOL_GPL(bf5xx_tdm_dai); + +static int __devinit bfin_tdm_probe(struct platform_device *pdev) +{ + int ret = 0; + + if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { + pr_err("Requesting Peripherals failed\n"); + return -EFAULT; + } + + /* request DMA for SPORT */ + sport_handle = sport_init(&sport_params[sport_num], 4, \ + 8 * sizeof(u32), NULL); + if (!sport_handle) { + peripheral_free_list(&sport_req[sport_num][0]); + return -ENODEV; + } + + /* SPORT works in TDM mode */ + ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1); + if (ret) { + pr_err("SPORT is busy!\n"); + ret = -EBUSY; + goto sport_config_err; + } + + ret = sport_config_rx(sport_handle, IRFS, 0x1F, 0, 0); + if (ret) { + pr_err("SPORT is busy!\n"); + ret = -EBUSY; + goto sport_config_err; + } + + ret = sport_config_tx(sport_handle, ITFS, 0x1F, 0, 0); + if (ret) { + pr_err("SPORT is busy!\n"); + ret = -EBUSY; + goto sport_config_err; + } + + ret = snd_soc_register_dai(&bf5xx_tdm_dai); + if (ret) { + pr_err("Failed to register DAI: %d\n", ret); + goto sport_config_err; + } + return 0; + +sport_config_err: + peripheral_free_list(&sport_req[sport_num][0]); + return ret; +} + +static int __devexit bfin_tdm_remove(struct platform_device *pdev) +{ + peripheral_free_list(&sport_req[sport_num][0]); + snd_soc_unregister_dai(&bf5xx_tdm_dai); + + return 0; +} + +static struct platform_driver bfin_tdm_driver = { + .probe = bfin_tdm_probe, + .remove = __devexit_p(bfin_tdm_remove), + .driver = { + .name = "bfin-tdm", + .owner = THIS_MODULE, + }, +}; + +static int __init bfin_tdm_init(void) +{ + return platform_driver_register(&bfin_tdm_driver); +} +module_init(bfin_tdm_init); + +static void __exit bfin_tdm_exit(void) +{ + platform_driver_unregister(&bfin_tdm_driver); +} +module_exit(bfin_tdm_exit); + +/* Module information */ +MODULE_AUTHOR("Barry Song"); +MODULE_DESCRIPTION("TDM driver for ADI Blackfin"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h new file mode 100644 index 0000000..e5157cd --- /dev/null +++ b/sound/soc/blackfin/bf5xx-tdm.h @@ -0,0 +1,14 @@ +/* + * linux/sound/arm/bf5xx-i2s.h + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef _BF5XX_TDM_H +#define _BF5XX_TDM_H + +extern struct snd_soc_dai bf5xx_tdm_dai; + +#endif -- cgit v0.10.2 From c8489c3ed319677f23e5387fec09c844365566e8 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Thu, 23 Jul 2009 02:10:34 +0800 Subject: ASoC: board driver to connect bf5xx with ad1938 Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mark Brown diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 2ab6d2f..8a4de4d 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -96,6 +96,14 @@ config SND_BF5XX_SOC_AD1980 help Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT. +config SND_BF5XX_SOC_AD1938 + tristate "SoC AD1938 Audio support for Blackfin" + depends on SND_BF5XX_TDM + select SND_BF5XX_SOC_TDM + select SND_SOC_AD1938 + help + Say Y if you want to add support for AD1938 codec on Blackfin. + config SND_BF5XX_SPORT_NUM int "Set a SPORT for Sound chip" depends on (SND_BF5XX_I2S || SND_BF5XX_AC97 || SND_BF5XX_TDM) diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile index f8619262..f4d7607 100644 --- a/sound/soc/blackfin/Makefile +++ b/sound/soc/blackfin/Makefile @@ -19,7 +19,9 @@ obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o snd-ad1980-objs := bf5xx-ad1980.o snd-ssm2602-objs := bf5xx-ssm2602.o snd-ad73311-objs := bf5xx-ad73311.o +snd-ad1938-objs := bf5xx-ad1938.o obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o +obj-$(CONFIG_SND_BF5XX_SOC_AD1938) += snd-ad1938.o diff --git a/sound/soc/blackfin/bf5xx-ad1938.c b/sound/soc/blackfin/bf5xx-ad1938.c new file mode 100644 index 0000000..08269e9 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-ad1938.c @@ -0,0 +1,142 @@ +/* + * File: sound/soc/blackfin/bf5xx-ad1938.c + * Author: Barry Song + * + * Created: Thur June 4 2009 + * Description: Board driver for ad1938 sound chip + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or 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 "../codecs/ad1938.h" +#include "bf5xx-sport.h" + +#include "bf5xx-tdm-pcm.h" +#include "bf5xx-tdm.h" + +static struct snd_soc_card bf5xx_ad1938; + +static int bf5xx_ad1938_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + cpu_dai->private_data = sport_handle; + return 0; +} + +static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + int ret = 0; + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + /* set codec DAI slots, 8 channels, all channels are enabled */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 8); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops bf5xx_ad1938_ops = { + .startup = bf5xx_ad1938_startup, + .hw_params = bf5xx_ad1938_hw_params, +}; + +static struct snd_soc_dai_link bf5xx_ad1938_dai = { + .name = "ad1938", + .stream_name = "AD1938", + .cpu_dai = &bf5xx_tdm_dai, + .codec_dai = &ad1938_dai, + .ops = &bf5xx_ad1938_ops, +}; + +static struct snd_soc_card bf5xx_ad1938 = { + .name = "bf5xx_ad1938", + .platform = &bf5xx_tdm_soc_platform, + .dai_link = &bf5xx_ad1938_dai, + .num_links = 1, +}; + +static struct snd_soc_device bf5xx_ad1938_snd_devdata = { + .card = &bf5xx_ad1938, + .codec_dev = &soc_codec_dev_ad1938, +}; + +static struct platform_device *bfxx_ad1938_snd_device; + +static int __init bf5xx_ad1938_init(void) +{ + int ret; + + bfxx_ad1938_snd_device = platform_device_alloc("soc-audio", -1); + if (!bfxx_ad1938_snd_device) + return -ENOMEM; + + platform_set_drvdata(bfxx_ad1938_snd_device, &bf5xx_ad1938_snd_devdata); + bf5xx_ad1938_snd_devdata.dev = &bfxx_ad1938_snd_device->dev; + ret = platform_device_add(bfxx_ad1938_snd_device); + + if (ret) + platform_device_put(bfxx_ad1938_snd_device); + + return ret; +} + +static void __exit bf5xx_ad1938_exit(void) +{ + platform_device_unregister(bfxx_ad1938_snd_device); +} + +module_init(bf5xx_ad1938_init); +module_exit(bf5xx_ad1938_exit); + +/* Module information */ +MODULE_AUTHOR("Barry Song"); +MODULE_DESCRIPTION("ALSA SoC AD1938 board driver"); +MODULE_LICENSE("GPL"); + -- cgit v0.10.2 From 62558ce15759ee93223132258588320967e1e521 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Jul 2009 14:23:09 +0200 Subject: ALSA: hda - Avoid overwrite of jack events with STAC/IDT Since only one event can be associated to a (pin) widget, it's safer to avoid the multiple mapping. This patch fixes the behavior of the STAC/IDT codec driver. Now stac_get_event() doesn't take the type argument but simply returns the first hit element. Then enable_pin_detect() checks the validity of the type, and returns non-zero only if a valid entry. The caller can call stac_issue_unsol_event() after checking the return value. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 66b1f3c..307e86c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2620,8 +2620,7 @@ static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol, return 0; } -static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, - unsigned char type); +static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid); static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2635,7 +2634,7 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, /* check to be sure that the ports are upto date with * switch changes */ - stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); + stac_issue_unsol_event(codec, nid); return 1; } @@ -2768,7 +2767,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ * appropriately according to the pin direction */ if (spec->hp_detect) - stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); + stac_issue_unsol_event(codec, nid); return 1; } @@ -4107,14 +4106,14 @@ static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid, } static struct sigmatel_event *stac_get_event(struct hda_codec *codec, - hda_nid_t nid, unsigned char type) + hda_nid_t nid) { struct sigmatel_spec *spec = codec->spec; struct sigmatel_event *event = spec->events.list; int i; for (i = 0; i < spec->events.used; i++, event++) { - if (event->nid == nid && event->type == type) + if (event->nid == nid) return event; } return NULL; @@ -4134,24 +4133,32 @@ static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec, return NULL; } -static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, - unsigned int type) +/* check if given nid is a valid pin and no other events are assigned + * to it. If OK, assign the event, set the unsol flag, and returns 1. + * Otherwise, returns zero. + */ +static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, + unsigned int type) { struct sigmatel_event *event; int tag; if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) - return; - event = stac_get_event(codec, nid, type); - if (event) + return 0; + event = stac_get_event(codec, nid); + if (event) { + if (event->type != type) + return 0; tag = event->tag; - else + } else { tag = stac_add_event(codec->spec, nid, type, 0); - if (tag < 0) - return; + if (tag < 0) + return 0; + } snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | tag); + return 1; } static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) @@ -4250,8 +4257,7 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], AC_PINCTL_OUT_EN); /* fake event to set up pins */ - stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], - STAC_HP_EVENT); + stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]); } else { stac92xx_auto_init_multi_out(codec); stac92xx_auto_init_hp_out(codec); @@ -4284,10 +4290,9 @@ static int stac92xx_init(struct hda_codec *codec) } conf = snd_hda_codec_get_pincfg(codec, nid); if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) { - enable_pin_detect(codec, nid, - STAC_INSERT_EVENT); - stac_issue_unsol_event(codec, nid, - STAC_INSERT_EVENT); + if (enable_pin_detect(codec, nid, + STAC_INSERT_EVENT)) + stac_issue_unsol_event(codec, nid); } } } @@ -4332,10 +4337,8 @@ static int stac92xx_init(struct hda_codec *codec) stac_toggle_power_map(codec, nid, 1); continue; } - if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) { - enable_pin_detect(codec, nid, STAC_PWR_EVENT); - stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); - } + if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) + stac_issue_unsol_event(codec, nid); } if (spec->dac_list) stac92xx_power_down(codec); @@ -4598,10 +4601,9 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) } } -static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, - unsigned char type) +static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid) { - struct sigmatel_event *event = stac_get_event(codec, nid, type); + struct sigmatel_event *event = stac_get_event(codec, nid); if (!event) return; codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26); @@ -4712,8 +4714,7 @@ static int stac92xx_resume(struct hda_codec *codec) snd_hda_codec_resume_cache(codec); /* fake event to set up pins again to override cached values */ if (spec->hp_detect) - stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], - STAC_HP_EVENT); + stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]); return 0; } -- cgit v0.10.2 From 3d21d3f7e7032619f5c5b47d3ee23bbe45de5993 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Jul 2009 14:32:56 +0200 Subject: ALSA: hda - Support auto-mic switching with IDT/STAC codec Support the automatic mic-switching with some devices with IDT/STAC codecs. The condition is that the device has only two inputs, one for an external mic and one for an internal mic. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 307e86c..f39dc98 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -40,6 +40,7 @@ enum { STAC_INSERT_EVENT, STAC_PWR_EVENT, STAC_HP_EVENT, + STAC_MIC_EVENT, }; enum { @@ -176,6 +177,12 @@ struct sigmatel_jack { struct snd_jack *jack; }; +struct sigmatel_mic_route { + hda_nid_t pin; + unsigned char mux_idx; + unsigned char dmux_idx; +}; + struct sigmatel_spec { struct snd_kcontrol_new *mixers[4]; unsigned int num_mixers; @@ -187,6 +194,7 @@ struct sigmatel_spec { unsigned int hp_detect: 1; unsigned int spdif_mute: 1; unsigned int check_volume_offset:1; + unsigned int auto_mic:1; /* gpio lines */ unsigned int eapd_mask; @@ -243,6 +251,9 @@ struct sigmatel_spec { unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ unsigned int num_caps; /* number of capture volume/switch elements */ + struct sigmatel_mic_route ext_mic; + struct sigmatel_mic_route int_mic; + const char **spdif_labels; hda_nid_t dig_in_nid; @@ -1304,7 +1315,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) if (err < 0) return err; } - if (spec->num_dmuxes > 0) { + if (!spec->auto_mic && spec->num_dmuxes > 0) { stac_dmux_mixer.count = spec->num_dmuxes; err = snd_hda_ctl_add(codec, snd_ctl_new1(&stac_dmux_mixer, codec)); @@ -2950,6 +2961,8 @@ static int stac92xx_add_input_source(struct sigmatel_spec *spec) struct snd_kcontrol_new *knew; struct hda_input_mux *imux = &spec->private_imux; + if (spec->auto_mic) + return 0; /* no need for input source */ if (!spec->num_adcs || imux->num_items <= 1) return 0; /* no need for input source control */ knew = stac_control_new(spec, &stac_input_src_temp, @@ -3557,14 +3570,26 @@ static const char *stac92xx_dmic_labels[5] = { "Digital Mic 3", "Digital Mic 4" }; +static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t nid) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int i, nums; + + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + for (i = 0; i < nums; i++) + if (conn[i] == nid) + return i; + return -1; +} + /* create playback/capture controls for input pins on dmic capable codecs */ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; struct hda_input_mux *dimux = &spec->private_dimux; - hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; - int err, i, j; + int err, i; char name[32]; dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; @@ -3574,7 +3599,6 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, for (i = 0; i < spec->num_dmics; i++) { hda_nid_t nid; int index; - int num_cons; unsigned int wcaps; unsigned int def_conf; @@ -3583,17 +3607,10 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, continue; nid = spec->dmic_nids[i]; - num_cons = snd_hda_get_connections(codec, - spec->dmux_nids[0], - con_lst, - HDA_MAX_NUM_INPUTS); - for (j = 0; j < num_cons; j++) - if (con_lst[j] == nid) { - index = j; - goto found; - } - continue; -found: + index = get_connection_index(codec, spec->dmux_nids[0], nid); + if (index < 0) + continue; + wcaps = get_wcaps(codec, nid) & (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); @@ -3620,6 +3637,88 @@ found: return 0; } +static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *fixed, hda_nid_t *ext) +{ + unsigned int cfg; + + if (!nid) + return 0; + cfg = snd_hda_codec_get_pincfg(codec, nid); + switch (get_defcfg_connect(cfg)) { + case AC_JACK_PORT_FIXED: + if (*fixed) + return 1; /* already occupied */ + *fixed = nid; + break; + case AC_JACK_PORT_COMPLEX: + if (*ext) + return 1; /* already occupied */ + *ext = nid; + break; + } + return 0; +} + +static int set_mic_route(struct hda_codec *codec, + struct sigmatel_mic_route *mic, + hda_nid_t pin) +{ + struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + mic->pin = pin; + for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) + if (pin == cfg->input_pins[i]) + break; + if (i <= AUTO_PIN_FRONT_MIC) { + /* analog pin */ + mic->dmux_idx = 0; + i = get_connection_index(codec, spec->mux_nids[0], pin); + if (i < 0) + return -1; + mic->mux_idx = i; + } else { + /* digital pin */ + mic->mux_idx = 0; + i = get_connection_index(codec, spec->dmux_nids[0], pin); + if (i < 0) + return -1; + mic->dmux_idx = i; + } + return 0; +} + +/* return non-zero if the device is for automatic mic switch */ +static int stac_check_auto_mic(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t fixed, ext; + int i; + + for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) { + if (cfg->input_pins[i]) + return 0; /* must be exclusively mics */ + } + fixed = ext = 0; + for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) + if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext)) + return 0; + for (i = 0; i < spec->num_dmics; i++) + if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext)) + return 0; + if (!fixed || !ext) + return 0; + if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP)) + return 0; /* no unsol support */ + if (set_mic_route(codec, &spec->ext_mic, ext) || + set_mic_route(codec, &spec->int_mic, fixed)) + return 0; /* something is wrong */ + return 1; +} + /* create playback/capture controls for input pins */ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { @@ -3837,6 +3936,14 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out spec->autocfg.line_outs = 0; } + if (stac_check_auto_mic(codec)) { + spec->auto_mic = 1; + /* only one capture for auto-mic */ + spec->num_adcs = 1; + spec->num_caps = 1; + spec->num_muxes = 1; + } + for (i = 0; i < spec->num_caps; i++) { err = stac92xx_add_capvol_ctls(codec, spec->capvols[i], spec->capsws[i], i); @@ -4264,6 +4371,10 @@ static int stac92xx_init(struct hda_codec *codec) for (i = 0; i < cfg->hp_outs; i++) stac_toggle_power_map(codec, cfg->hp_pins[i], 1); } + if (spec->auto_mic) { + if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT)) + stac_issue_unsol_event(codec, spec->ext_mic.pin); + } for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = cfg->input_pins[i]; if (nid) { @@ -4601,6 +4712,25 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) } } +static void stac92xx_mic_detect(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + struct sigmatel_mic_route *mic; + + if (get_pin_presence(codec, spec->ext_mic.pin)) + mic = &spec->ext_mic; + else + mic = &spec->int_mic; + if (mic->dmux_idx) + snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, + AC_VERB_SET_CONNECT_SEL, + mic->dmux_idx); + else + snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0, + AC_VERB_SET_CONNECT_SEL, + mic->mux_idx); +} + static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid) { struct sigmatel_event *event = stac_get_event(codec, nid); @@ -4623,7 +4753,15 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) switch (event->type) { case STAC_HP_EVENT: stac92xx_hp_detect(codec); - /* fallthru */ + break; + case STAC_MIC_EVENT: + stac92xx_mic_detect(codec); + break; + } + + switch (event->type) { + case STAC_HP_EVENT: + case STAC_MIC_EVENT: case STAC_INSERT_EVENT: case STAC_PWR_EVENT: if (spec->num_pwrs > 0) -- cgit v0.10.2 From 26a2798053519d766ddae1ca1b03c8295fddf1a8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Jul 2009 16:28:09 +0200 Subject: ALSA: hda - Remove static connection in IDT 92HD71bxx We don't need any more static connection to the port F (which is often used for docking stations) since its connection is done dynamically via DAC assignment now. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f39dc98..abc44db 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -997,19 +997,6 @@ static struct hda_verb stac92hd71bxx_core_init[] = { {} }; -#define HD_DISABLE_PORTF 1 -static struct hda_verb stac92hd71bxx_analog_core_init[] = { - /* start of config #1 */ - - /* connect port 0f to audio mixer */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, - /* start of config #2 */ - - /* set master volume and direct control */ - { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - {} -}; - static struct hda_verb stac92hd71bxx_unmute_core_init[] = { /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */ { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -5519,7 +5506,7 @@ again: spec->mixer = stac92hd71bxx_analog_mixer; /* disable VSW */ - spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; + spec->init = stac92hd71bxx_core_init; unmute_init++; snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0); snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3); @@ -5545,7 +5532,7 @@ again: sizeof(stac92hd71bxx_dmux_amixer)); if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) spec->mixer = stac92hd71bxx_analog_mixer; - spec->init = stac92hd71bxx_analog_core_init; + spec->init = stac92hd71bxx_core_init; codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; spec->num_dmics = stac92hd71bxx_connected_ports(codec, stac92hd71bxx_dmic_nids, -- cgit v0.10.2 From 15b4f296fce683497ecc815b2f9b6f121fb3fef8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Jul 2009 16:32:55 +0200 Subject: ALSA: hda - Add missing DMUX initialization for auto-mic with STAC/IDT Added the missing initialization of DMUX connection (to analog input) for auto-mic mode with STAC/IDT codecs. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index abc44db..2405f841 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4359,6 +4359,9 @@ static int stac92xx_init(struct hda_codec *codec) stac_toggle_power_map(codec, cfg->hp_pins[i], 1); } if (spec->auto_mic) { + /* initialize connection to analog input */ + snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, + AC_VERB_SET_CONNECT_SEL, 0); if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT)) stac_issue_unsol_event(codec, spec->ext_mic.pin); } -- cgit v0.10.2 From 71443b0b745f7d2c775c8a228e09ef2dc98d42f3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Jul 2009 18:41:29 +0200 Subject: ALSA: hda - No analog mix input source as default for IDT92HD71bxx The analog mix is disabled now as default (unless "analog_mixer" hint is given), so it shoudn't appear in the digital input source as well. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 2405f841..883e2aa 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5481,8 +5481,6 @@ again: } break; case 0x111d7608: /* 5 Port with Analog Mixer */ - memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer, - sizeof(stac92hd71bxx_dmux_amixer)); spec->private_dimux.num_items--; switch (spec->board_config) { case STAC_HP_M4: @@ -5505,9 +5503,15 @@ again: /* no output amps */ spec->num_pwrs = 0; - if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) + if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) { spec->mixer = stac92hd71bxx_analog_mixer; - + memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer, + sizeof(stac92hd71bxx_dmux_amixer)); + } else { + memcpy(&spec->private_dimux, + &stac92hd71bxx_dmux_nomixer, + sizeof(stac92hd71bxx_dmux_nomixer)); + } /* disable VSW */ spec->init = stac92hd71bxx_core_init; unmute_init++; @@ -5531,10 +5535,15 @@ again: spec->num_pwrs = 0; /* fallthru */ default: - memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer, - sizeof(stac92hd71bxx_dmux_amixer)); - if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) + if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) { spec->mixer = stac92hd71bxx_analog_mixer; + memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer, + sizeof(stac92hd71bxx_dmux_amixer)); + } else { + memcpy(&spec->private_dimux, + &stac92hd71bxx_dmux_nomixer, + sizeof(stac92hd71bxx_dmux_nomixer)); + } spec->init = stac92hd71bxx_core_init; codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; spec->num_dmics = stac92hd71bxx_connected_ports(codec, -- cgit v0.10.2 From f7ea097d9b4e61a816c041c92548aad7c7ed7915 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 24 Jul 2009 11:13:12 -0700 Subject: iwlagn: fix null pointer access during ucode load on 1000 Commit "iwlwifi: Handle new firmware file with ucode build number in header" introduced new ucode header parsing routines, but neglected to initialize these routines for 1000. The system thus goes into infinite loop trying to load ucode, failing every time with a null pointer exception as it tries to parse the header. Signed-off-by: Reinette Chatre Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 80a2818..5f7c520 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -124,6 +124,7 @@ static struct iwl_lib_ops iwl1000_lib = { }; static struct iwl_ops iwl1000_ops = { + .ucode = &iwl5000_ucode, .lib = &iwl1000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, -- cgit v0.10.2 From 6686d17e161dcd0dc6801bcde9e397020bf9edf7 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 24 Jul 2009 11:13:13 -0700 Subject: iwlagn: fix sparse warning when compiling without debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C [M] drivers/net/wireless/iwlwifi/iwl-core.o drivers/net/wireless/iwlwifi/iwl-core.c:1341: warning: ‘iwl_dump_nic_error_log’ defined but not used Reported-by: Luis R. Rodriguez Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 710dd41..aafa9fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1291,7 +1291,6 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } -#endif static const char *desc_lookup_text[] = { "OK", @@ -1496,6 +1495,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) iwl_print_event_log(priv, 0, next_entry, mode); } +#endif /** * iwl_irq_handle_error - called for HW or SW error interrupt from card */ -- cgit v0.10.2 From bc43b28c10855aa56f6d0bd64ec6a6d8edbcf11b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Jul 2009 10:54:13 +0200 Subject: cfg80211: fix circular lock dependency (1) Luis reported this lockdep complaint, that he had also reported earlier but when trying to analyse I had been locking at the wrong code, and never saw the problem: (slightly abridged) ======================================================= [ INFO: possible circular locking dependency detected ] 2.6.31-rc4-wl #6 ------------------------------------------------------- wpa_supplicant/3799 is trying to acquire lock: (cfg80211_mutex){+.+.+.}, at: [] cfg80211_get_dev_from_ifindex+0x1a/0x90 [cfg80211] but task is already holding lock: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x12/0x20 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (rtnl_mutex){+.+.+.}: [] __lock_acquire+0xd76/0x12b0 [] lock_acquire+0xe3/0x120 [] mutex_lock_nested+0x44/0x350 [] rtnl_lock+0x12/0x20 [] nl80211_send_reg_change_event+0x1f5/0x2a0 [cfg80211] [] set_regdom+0x28e/0x4c0 [cfg80211] -> #0 (cfg80211_mutex){+.+.+.}: [] __lock_acquire+0xe3b/0x12b0 [] lock_acquire+0xe3/0x120 [] mutex_lock_nested+0x44/0x350 [] cfg80211_get_dev_from_ifindex+0x1a/0x90 [cfg80211] [] get_rdev_dev_by_info_ifindex+0x6f/0xa0 [cfg80211] [] nl80211_set_interface+0x3b/0x260 [cfg80211] When looking at the correct code, the problem is quite obvious. I'm not entirely sure which code paths lead here, so until I can analyse it better let's just use RCU to avoid the problem. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7880a9c..283f1a8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4517,10 +4517,10 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) return; } - rtnl_lock(); + rcu_read_lock(); genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, - GFP_KERNEL); - rtnl_unlock(); + GFP_ATOMIC); + rcu_read_unlock(); return; -- cgit v0.10.2 From 8d8b261a5c11bd043b9b0e0c7e6c49d57611e3ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Jul 2009 11:58:36 +0200 Subject: mac80211: fix receiving deauth Marcel reported a warning, which quite obviously comes from an oversight in the code handling deauth frames, and which resulted in multiple follow-up warnings due to this missing handling. This patch adds the missing deauth handling (telling cfg80211 about it) and also removes the follow-up warnings since they could happen due to races even if nothing is wrong. I've explained the races in the comments. Signed-off-by: Johannes Berg Reported-by: Marcel Holtmann Tested-by: Marcel Holtmann Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 76c03da..f60a831 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2003,6 +2003,9 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, case RX_MGMT_CFG80211_ASSOC: cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); break; + case RX_MGMT_CFG80211_DEAUTH: + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, NULL); + break; default: WARN(1, "unexpected: %d", rma); } @@ -2498,8 +2501,13 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, } } - /* cfg80211 should catch this... */ - if (WARN_ON(!bssid)) { + /* + * cfg80211 should catch this ... but it's racy since + * we can receive a deauth frame, process it, hand it + * to cfg80211 while that's in a locked section already + * trying to tell us that the user wants to disconnect. + */ + if (!bssid) { mutex_unlock(&ifmgd->mtx); return -ENOLINK; } @@ -2524,8 +2532,13 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, mutex_lock(&ifmgd->mtx); - /* cfg80211 should catch that */ - if (WARN_ON(&ifmgd->associated->cbss != req->bss)) { + /* + * cfg80211 should catch this ... but it's racy since + * we can receive a disassoc frame, process it, hand it + * to cfg80211 while that's in a locked section already + * trying to tell us that the user wants to disconnect. + */ + if (&ifmgd->associated->cbss != req->bss) { mutex_unlock(&ifmgd->mtx); return -ENOLINK; } -- cgit v0.10.2 From 11866efa9b5d6f321a2625b7f6837ba55c4c2e4b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 27 Jul 2009 10:56:41 -0400 Subject: ray_cs: remove bogus NULL check at head of ray_get_wireless_stats Reported-by: Johannes Berg Cc: Martin Ettl Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 64e574c..2be7820 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1511,9 +1511,6 @@ static iw_stats *ray_get_wireless_stats(struct net_device *dev) struct pcmcia_device *link = local->finder; struct status __iomem *p = local->sram + STATUS_BASE; - if (local == (ray_dev_t *) NULL) - return (iw_stats *) NULL; - local->wstats.status = local->card_status; #ifdef WIRELESS_SPY if ((local->spy_data.spy_number > 0) -- cgit v0.10.2 From ff8365ca889cb86ba5bd40fe3047d047bc632f4c Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Fri, 24 Jul 2009 11:55:44 +0400 Subject: ar9170: fix build error when !CONFIG_AR9170_LEDS Fix this build error when CONFIG_AR9170_LEDS is not set drivers/net/wireless/ath/ar9170/main.c:1296: error: 'struct ar9170' has no member named 'led_work' Signed-off-by: Alexander Beregalov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index c7287a8..85a1452 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1293,7 +1293,9 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) flush_workqueue(ar->hw->workqueue); cancel_delayed_work_sync(&ar->tx_janitor); +#ifdef CONFIG_AR9170_LEDS cancel_delayed_work_sync(&ar->led_work); +#endif cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); mutex_lock(&ar->mutex); -- cgit v0.10.2 From 96148326c4b54db5c384def1a5ab285c359d1395 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 24 Jul 2009 17:27:21 +0200 Subject: ath9k: fix race with IEEE80211_CONF_PS checks There is a small window where the mac80211 changes the IEEE80211_CONF_PS flag, and then informs the driver about the change. We have a race condition if we are checking the flag in the same time. Avoid it by introducing a local variable, and using that instead of checking the IEEE80211_CONF_PS flag directly. This fix the problem reported by Luis: http://article.gmane.org/gmane.linux.kernel.wireless.general/34363 Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e2ebf1a..3a978bf 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -573,6 +573,7 @@ struct ath_softc { u32 keymax; DECLARE_BITMAP(keymap, ATH_KEYMAX); u8 splitmic; + bool ps_enabled; unsigned long ps_usecount; enum ath9k_int imask; enum ath9k_ht_extprotspacing ht_extprotspacing; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index da32269..e6e52f4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2863,10 +2863,8 @@ void ath9k_ps_wakeup(struct ath_softc *sc) if (++sc->ps_usecount != 1) goto unlock; - if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { - sc->sc_ah->restore_mode = sc->sc_ah->power_mode; + if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); - } unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); @@ -2880,13 +2878,12 @@ void ath9k_ps_restore(struct ath_softc *sc) if (--sc->ps_usecount != 0) goto unlock; - if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && - !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA | - SC_OP_WAIT_FOR_TX_ACK))) - ath9k_hw_setpower_nolock(sc->sc_ah, - sc->sc_ah->restore_mode); + if (sc->ps_enabled && + !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK))) + ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 37f7d3d..2e196df 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -421,7 +421,6 @@ struct ath_hw { enum nl80211_iftype opmode; enum ath9k_power_mode power_mode; - enum ath9k_power_mode restore_mode; struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; struct ar5416Stats stats; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1c648db..87f9971 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -499,8 +499,7 @@ static void ath9k_tasklet(unsigned long data) if (status & ATH9K_INT_TX) ath_tx_tasklet(sc); - if ((status & ATH9K_INT_TSFOOR) && - (sc->hw->conf.flags & IEEE80211_CONF_PS)) { + if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { /* * TSF sync does not look correct; remain awake to sync with * the next Beacon. @@ -2001,7 +2000,7 @@ static int ath9k_tx(struct ieee80211_hw *hw, goto exit; } - if (sc->hw->conf.flags & IEEE80211_CONF_PS) { + if (sc->ps_enabled) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; /* * mac80211 does not set PM field for normal data frames, so we @@ -2289,8 +2288,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } ath9k_hw_setrxabort(sc->sc_ah, 1); } - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); + sc->ps_enabled = true; } else { + sc->ps_enabled = false; ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { -- cgit v0.10.2 From cbdec9758736c30ecbb03651b0c2915c442a5895 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 24 Jul 2009 17:27:22 +0200 Subject: ath9k: get rid of unnecessary setpower calls We are using setpower routines regardless of the current power mode. Don't bother the hardware, if it is not necessary. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e6e52f4..431854c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -478,6 +478,8 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, ah->gbeacon_rate = 0; + ah->power_mode = ATH9K_PM_UNDEFINED; + return ah; } @@ -2819,6 +2821,9 @@ static bool ath9k_hw_setpower_nolock(struct ath_hw *ah, "UNDEFINED" }; + if (ah->power_mode == mode) + return status; + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n", modes[ah->power_mode], modes[mode]); @@ -2863,8 +2868,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc) if (++sc->ps_usecount != 1) goto unlock; - if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) - ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); + ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); -- cgit v0.10.2 From c0b2bbd833a5a26b5a9425cb9a7eb66bbe736dd1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Jul 2009 16:54:36 +0200 Subject: nl80211: add missing parameter clearing Jouni and Maxim reported an oops when using wpa_supplicant -Dnl80211, which seems to be due to random data being contained in the crypto settings for the assoc() command. This seems to be due to the missing memset here, so add it -- it's certainly missing but I'm not 100% certain that it will fix the problem. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 283f1a8..c951eb2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3385,6 +3385,8 @@ static int nl80211_crypto_settings(struct genl_info *info, struct cfg80211_crypto_settings *settings, int cipher_limit) { + memset(settings, 0, sizeof(*settings)); + settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { -- cgit v0.10.2 From 0ee9c13c7c92581ab005d80795cf65897213b249 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 25 Jul 2009 17:25:51 +0200 Subject: mac80211: fix an oops in ieee80211_scan_state_set_channel Fix an oops in ieee80211_scan_state_set_channel which was triggered if the last scanned channel was skipped (for example due to regulatory restrictions) by returning to the decision state after each skipped channel. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index b376775..147772a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -605,8 +605,11 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, /* advance state machine to next channel/band */ local->scan_channel_idx++; - if (skip) + if (skip) { + /* if we skip this channel return to the decision state */ + local->next_scan_state = SCAN_DECISION; return; + } /* * Probe delay is used to update the NAV, cf. 11.1.3.2.2 -- cgit v0.10.2 From fec247c0d5bfbaa0861774ce31d515bbd48f7fce Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 27 Jul 2009 12:08:16 +0530 Subject: ath9k: Add debug counters for TX Location: ath9k/phy#/xmit Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3a978bf..bda0f30 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -237,7 +237,6 @@ struct ath_txq { spinlock_t axq_lock; u32 axq_depth; u8 axq_aggr_depth; - u32 axq_totalqueued; bool stopped; bool axq_tx_inprogress; struct ath_buf *axq_linkbuf; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 9f99f00..9e36920 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -486,6 +486,83 @@ static const struct file_operations fops_wiphy = { .owner = THIS_MODULE }; +#define PR(str, elem) \ + do { \ + len += snprintf(buf + len, size - len, \ + "%s%13u%11u%10u%10u\n", str, \ + sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BE]].elem, \ + sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BK]].elem, \ + sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VI]].elem, \ + sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VO]].elem); \ +} while(0) + +static ssize_t read_file_xmit(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char *buf; + unsigned int len = 0, size = 2048; + ssize_t retval = 0; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return 0; + + len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO"); + + PR("MPDUs Queued: ", queued); + PR("MPDUs Completed: ", completed); + PR("Aggregates: ", a_aggr); + PR("AMPDUs Queued: ", a_queued); + PR("AMPDUs Completed:", a_completed); + PR("AMPDUs Retried: ", a_retries); + PR("AMPDUs XRetried: ", a_xretries); + PR("FIFO Underrun: ", fifo_underrun); + PR("TXOP Exceeded: ", xtxop); + PR("TXTIMER Expiry: ", timer_exp); + PR("DESC CFG Error: ", desc_cfg_err); + PR("DATA Underrun: ", data_underrun); + PR("DELIM Underrun: ", delim_underrun); + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, + struct ath_buf *bf) +{ + struct ath_desc *ds = bf->bf_desc; + + if (bf_isampdu(bf)) { + if (bf_isxretried(bf)) + TX_STAT_INC(txq->axq_qnum, a_xretries); + else + TX_STAT_INC(txq->axq_qnum, a_completed); + } else { + TX_STAT_INC(txq->axq_qnum, completed); + } + + if (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO) + TX_STAT_INC(txq->axq_qnum, fifo_underrun); + if (ds->ds_txstat.ts_status & ATH9K_TXERR_XTXOP) + TX_STAT_INC(txq->axq_qnum, xtxop); + if (ds->ds_txstat.ts_status & ATH9K_TXERR_TIMER_EXPIRED) + TX_STAT_INC(txq->axq_qnum, timer_exp); + if (ds->ds_txstat.ts_flags & ATH9K_TX_DESC_CFG_ERR) + TX_STAT_INC(txq->axq_qnum, desc_cfg_err); + if (ds->ds_txstat.ts_flags & ATH9K_TX_DATA_UNDERRUN) + TX_STAT_INC(txq->axq_qnum, data_underrun); + if (ds->ds_txstat.ts_flags & ATH9K_TX_DELIM_UNDERRUN) + TX_STAT_INC(txq->axq_qnum, delim_underrun); +} + +static const struct file_operations fops_xmit = { + .read = read_file_xmit, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; int ath9k_init_debug(struct ath_softc *sc) { @@ -529,6 +606,13 @@ int ath9k_init_debug(struct ath_softc *sc) if (!sc->debug.debugfs_wiphy) goto err; + sc->debug.debugfs_xmit = debugfs_create_file("xmit", + S_IRUSR, + sc->debug.debugfs_phy, + sc, &fops_xmit); + if (!sc->debug.debugfs_xmit) + goto err; + return 0; err: ath9k_exit_debug(sc); @@ -537,6 +621,7 @@ err: void ath9k_exit_debug(struct ath_softc *sc) { + debugfs_remove(sc->debug.debugfs_xmit); debugfs_remove(sc->debug.debugfs_wiphy); debugfs_remove(sc->debug.debugfs_rcstat); debugfs_remove(sc->debug.debugfs_interrupt); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index edda15b..5e56b79 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -35,6 +35,15 @@ enum ATH_DEBUG { #define DBG_DEFAULT (ATH_DBG_FATAL) +struct ath_txq; +struct ath_buf; + +#ifdef CONFIG_ATH9K_DEBUG +#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ +#else +#define TX_STAT_INC(q, c) do { } while (0) +#endif + #ifdef CONFIG_ATH9K_DEBUG /** @@ -87,9 +96,45 @@ struct ath_rc_stats { u8 per; }; +/** + * struct ath_tx_stats - Statistics about TX + * @queued: Total MPDUs (non-aggr) queued + * @completed: Total MPDUs (non-aggr) completed + * @a_aggr: Total no. of aggregates queued + * @a_queued: Total AMPDUs queued + * @a_completed: Total AMPDUs completed + * @a_retries: No. of AMPDUs retried (SW) + * @a_xretries: No. of AMPDUs dropped due to xretries + * @fifo_underrun: FIFO underrun occurrences + Valid only for: + - non-aggregate condition. + - first packet of aggregate. + * @xtxop: No. of frames filtered because of TXOP limit + * @timer_exp: Transmit timer expiry + * @desc_cfg_err: Descriptor configuration errors + * @data_urn: TX data underrun errors + * @delim_urn: TX delimiter underrun errors + */ +struct ath_tx_stats { + u32 queued; + u32 completed; + u32 a_aggr; + u32 a_queued; + u32 a_completed; + u32 a_retries; + u32 a_xretries; + u32 fifo_underrun; + u32 xtxop; + u32 timer_exp; + u32 desc_cfg_err; + u32 data_underrun; + u32 delim_underrun; +}; + struct ath_stats { struct ath_interrupt_stats istats; struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; + struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; }; struct ath9k_debug { @@ -100,6 +145,7 @@ struct ath9k_debug { struct dentry *debugfs_interrupt; struct dentry *debugfs_rcstat; struct dentry *debugfs_wiphy; + struct dentry *debugfs_xmit; struct ath_stats stats; }; @@ -110,6 +156,8 @@ int ath9k_debug_create_root(void); void ath9k_debug_remove_root(void); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb); +void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, + struct ath_buf *bf); void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per); @@ -148,6 +196,12 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc, { } +static inline void ath_debug_stat_tx(struct ath_softc *sc, + struct ath_txq *txq, + struct ath_buf *bf) +{ +} + static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per) { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 6eb2927..b7806e2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -59,6 +59,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_head); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, + struct ath_txq *txq, struct list_head *bf_q, int txok, int sendbar); static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, @@ -212,7 +213,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, ath_tx_update_baw(sc, tid, bf->bf_seqno); spin_unlock(&txq->axq_lock); - ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0); spin_lock(&txq->axq_lock); } @@ -220,13 +221,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, tid->baw_tail = tid->baw_head; } -static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) +static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, + struct ath_buf *bf) { struct sk_buff *skb; struct ieee80211_hdr *hdr; bf->bf_state.bf_type |= BUF_RETRY; bf->bf_retries++; + TX_STAT_INC(txq->axq_qnum, a_retries); skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; @@ -328,7 +331,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (!(tid->state & AGGR_CLEANUP) && ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { if (bf->bf_retries < ATH_MAX_SW_RETRIES) { - ath_tx_set_retry(sc, bf); + ath_tx_set_retry(sc, txq, bf); txpending = 1; } else { bf->bf_state.bf_type |= BUF_XRETRY; @@ -375,7 +378,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ath_tx_rc_status(bf, ds, nbad, txok, false); } - ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar); + ath_tx_complete_buf(sc, bf, txq, &bf_head, !txfail, sendbar); } else { /* retry the un-acked ones */ if (bf->bf_next == NULL && bf_last->bf_stale) { @@ -395,8 +398,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, bf->bf_state.bf_type |= BUF_XRETRY; ath_tx_rc_status(bf, ds, nbad, 0, false); - ath_tx_complete_buf(sc, bf, &bf_head, - 0, 0); + ath_tx_complete_buf(sc, bf, txq, + &bf_head, 0, 0); break; } @@ -569,6 +572,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, } static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, + struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_q) { @@ -633,6 +637,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, bf_prev->bf_desc->ds_link = bf->bf_daddr; } bf_prev = bf; + } while (!list_empty(&tid->buf_q)); bf_first->bf_al = al; @@ -655,7 +660,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&bf_q); - status = ath_tx_form_aggr(sc, tid, &bf_q); + status = ath_tx_form_aggr(sc, txq, tid, &bf_q); /* * no frames picked up to be aggregated; @@ -686,6 +691,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, txq->axq_aggr_depth++; ath_tx_txqaddbuf(sc, txq, &bf_q); + TX_STAT_INC(txq->axq_qnum, a_aggr); } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH && status != ATH_AGGR_BAW_CLOSED); @@ -737,7 +743,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) } list_move_tail(&bf->list, &bf_head); ath_tx_update_baw(sc, txtid, bf->bf_seqno); - ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0); } spin_unlock_bh(&txq->axq_lock); @@ -859,7 +865,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) spin_lock_init(&txq->axq_lock); txq->axq_depth = 0; txq->axq_aggr_depth = 0; - txq->axq_totalqueued = 0; txq->axq_linkbuf = NULL; txq->axq_tx_inprogress = false; sc->tx.txqsetup |= 1<axq_lock); @@ -1176,7 +1181,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, list_splice_tail_init(head, &txq->axq_q); txq->axq_depth++; - txq->axq_totalqueued++; txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); DPRINTF(sc, ATH_DBG_QUEUE, @@ -1224,6 +1228,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, bf = list_first_entry(bf_head, struct ath_buf, list); bf->bf_state.bf_type |= BUF_AMPDU; + TX_STAT_INC(txctl->txq->axq_qnum, a_queued); /* * Do not queue to h/w when any of the following conditions is true: @@ -1270,6 +1275,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, bf->bf_lastbf = bf; ath_buf_set_rate(sc, bf); ath_tx_txqaddbuf(sc, txq, bf_head); + TX_STAT_INC(txq->axq_qnum, queued); } static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, @@ -1283,6 +1289,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, bf->bf_nframes = 1; ath_buf_set_rate(sc, bf); ath_tx_txqaddbuf(sc, txq, bf_head); + TX_STAT_INC(txq->axq_qnum, queued); } static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) @@ -1808,6 +1815,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, } static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, + struct ath_txq *txq, struct list_head *bf_q, int txok, int sendbar) { @@ -1815,7 +1823,6 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, unsigned long flags; int tx_flags = 0; - if (sendbar) tx_flags = ATH_TX_BAR; @@ -1828,6 +1835,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); ath_tx_complete(sc, skb, tx_flags); + ath_debug_stat_tx(sc, txq, bf); /* * Return the list of ath_buf of this mpdu to free queue @@ -2015,7 +2023,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok); else - ath_tx_complete_buf(sc, bf, &bf_head, txok, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, txok, 0); ath_wake_mac80211_queue(sc, txq); -- cgit v0.10.2 From f9d6b402603a63b5e5b56bd7a79fa72a818be55b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 10:22:28 +0200 Subject: cfg80211: fix disassoc while not associated When trying to disassociate while not associated, the kernel would crash rather than refusing the operation, fix this; Reported-by: Maxim Levitsky Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 5b9b221..30058a8 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -545,6 +545,12 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); + if (wdev->sme_state != CFG80211_SME_CONNECTED) + return -ENOTCONN; + + if (WARN_ON(!wdev->current_bss)) + return -ENOTCONN; + memset(&req, 0, sizeof(req)); req.reason_code = reason; req.ie = ie; -- cgit v0.10.2 From a7bc376c858e0e724b8cb2db09b6874562d377ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 10:33:31 +0200 Subject: mac80211: verify info->control.vif is not NULL When enqueuing packets on the internal packet queue, we need to ensure that we have a valid vif pointer since that is required since the net namespace work. Add some assertions to verify this, but also don't crash is for some reason we don't end up with a vif pointer -- warn and drop the packet in all these cases. Since this code touches a number of hotpaths, it is intended to be temporary, or maybe configurable in the future, at least the bit that is in the path that gets hit for every packet, ieee80211_tx_pending(). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9e5dff1..4e1b2ba 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1889,6 +1889,11 @@ void ieee80211_tx_pending(unsigned long data) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_sub_if_data *sdata; + if (WARN_ON(!info->control.vif)) { + kfree_skb(skb); + continue; + } + sdata = vif_to_sdata(info->control.vif); dev_hold(sdata->dev); spin_unlock_irqrestore(&local->queue_stop_reason_lock, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7fc5584..8502936 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -336,6 +336,12 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, struct ieee80211_hw *hw = &local->hw; unsigned long flags; int queue = skb_get_queue_mapping(skb); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if (WARN_ON(!info->control.vif)) { + kfree(skb); + return; + } spin_lock_irqsave(&local->queue_stop_reason_lock, flags); __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); @@ -358,6 +364,13 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); while ((skb = skb_dequeue(skbs))) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if (WARN_ON(!info->control.vif)) { + kfree(skb); + continue; + } + ret++; queue = skb_get_queue_mapping(skb); __skb_queue_tail(&local->pending[queue], skb); -- cgit v0.10.2 From 0e82ffe3b90bcad72cfe80e4379946b8fb0691ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:50 +0200 Subject: cfg80211: combine iwfreq implementations Until now we implemented iwfreq for managed mode, we needed to keep the implementations separate, but now that we have all versions implemented we can combine them and export just one handler. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index c3c90d5..8058e99 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -27,36 +27,6 @@ #include "iwm.h" #include "commands.h" -static int iwm_wext_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); - default: - return -EOPNOTSUPP; - } -} - -static int iwm_wext_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); - case UMAC_MODE_BSS: - return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); - default: - return -EOPNOTSUPP; - } -} - static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { @@ -125,8 +95,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ (iw_handler) NULL, /* SIOCSIWNWID */ (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */ + (iw_handler) cfg80211_wext_siwfreq, /* SIOCSIWFREQ */ + (iw_handler) cfg80211_wext_giwfreq, /* SIOCGIWFREQ */ (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ (iw_handler) NULL, /* SIOCSIWSENS */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0d27877..5d249c4 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1595,12 +1595,6 @@ int cfg80211_wext_siwmlme(struct net_device *dev, int cfg80211_wext_giwrange(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra); -int cfg80211_ibss_wext_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra); -int cfg80211_ibss_wext_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra); int cfg80211_ibss_wext_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid); @@ -1614,12 +1608,6 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra); -int cfg80211_mgd_wext_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra); -int cfg80211_mgd_wext_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra); int cfg80211_mgd_wext_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid); @@ -1642,8 +1630,12 @@ int cfg80211_wext_giwauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *data, char *extra); -struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, - struct iw_freq *freq); +int cfg80211_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); int cfg80211_wext_siwrate(struct net_device *dev, struct iw_request_info *info, diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 5acb814..7cd9aa7 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -27,75 +27,6 @@ #include "aes_ccm.h" -static int ieee80211_ioctl_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; - struct ieee80211_channel *chan; - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra); - - /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ - if (freq->e == 0) { - if (freq->m < 0) - return -EINVAL; - else - chan = ieee80211_get_channel(local->hw.wiphy, - ieee80211_channel_to_frequency(freq->m)); - } else { - int i, div = 1000000; - for (i = 0; i < freq->e; i++) - div /= 10; - if (div <= 0) - return -EINVAL; - chan = ieee80211_get_channel(local->hw.wiphy, freq->m / div); - } - - if (!chan) - return -EINVAL; - - if (chan->flags & IEEE80211_CHAN_DISABLED) - return -EINVAL; - - /* - * no change except maybe auto -> fixed, ignore the HT - * setting so you can fix a channel you're on already - */ - if (local->oper_channel == chan) - return 0; - - local->oper_channel = chan; - local->oper_channel_type = NL80211_CHAN_NO_HT; - ieee80211_hw_config(local, 0); - - return 0; -} - - -static int ieee80211_ioctl_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); - - freq->m = local->oper_channel->center_freq; - freq->e = 6; - - return 0; -} - - static int ieee80211_ioctl_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) @@ -173,8 +104,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ (iw_handler) NULL, /* SIOCSIWNWID */ (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */ + (iw_handler) cfg80211_wext_siwfreq, /* SIOCSIWFREQ */ + (iw_handler) cfg80211_wext_giwfreq, /* SIOCGIWFREQ */ (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ (iw_handler) NULL, /* SIOCSIWSENS */ diff --git a/net/wireless/core.h b/net/wireless/core.h index 4276b70..6d903c1 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -66,6 +66,9 @@ struct cfg80211_registered_device { struct work_struct conn_work; struct work_struct event_work; + /* current channel */ + struct ieee80211_channel *channel; + #ifdef CONFIG_CFG80211_DEBUGFS /* Debugfs entries */ struct wiphy_debugfsdentries { diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 8b65e21..de9ac49 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -7,6 +7,7 @@ #include #include #include +#include "wext-compat.h" #include "nl80211.h" @@ -312,8 +313,6 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq); int cfg80211_ibss_wext_giwfreq(struct net_device *dev, struct iw_request_info *info, @@ -342,8 +341,6 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, /* no channel if not joining */ return -EINVAL; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq); int cfg80211_ibss_wext_siwessid(struct net_device *dev, struct iw_request_info *info, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c951eb2..0cd5482 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -757,6 +757,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) channel_type); if (result) goto bad_res; + + rdev->channel = chan; } changed = 0; diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index c7351a9..fc2e776 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -14,6 +14,7 @@ #include #include #include +#include "wext-compat.h" #include "core.h" int cfg80211_wext_giwname(struct net_device *dev, @@ -300,7 +301,6 @@ struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, return ERR_PTR(-EINVAL); return chan; } -EXPORT_SYMBOL_GPL(cfg80211_wext_freq); int cfg80211_wext_siwrts(struct net_device *dev, struct iw_request_info *info, @@ -759,6 +759,58 @@ int cfg80211_wext_giwencode(struct net_device *dev, } EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); +int cfg80211_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct ieee80211_channel *chan; + int err; + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra); + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); + default: + chan = cfg80211_wext_freq(wdev->wiphy, freq); + if (!chan) + return -EINVAL; + if (IS_ERR(chan)) + return PTR_ERR(chan); + err = rdev->ops->set_channel(wdev->wiphy, chan, + NL80211_CHAN_NO_HT); + if (err) + return err; + rdev->channel = chan; + return 0; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); + +int cfg80211_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); + default: + if (!rdev->channel) + return -EINVAL; + freq->m = rdev->channel->center_freq; + freq->e = 6; + return 0; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwfreq); + int cfg80211_wext_siwtxpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *data, char *extra) diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h new file mode 100644 index 0000000..23a6b5a --- /dev/null +++ b/net/wireless/wext-compat.h @@ -0,0 +1,21 @@ +#ifndef __WEXT_COMPAT +#define __WEXT_COMPAT + +int cfg80211_ibss_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_ibss_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); + +int cfg80211_mgd_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); +int cfg80211_mgd_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra); + +struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, + struct iw_freq *freq); + +#endif /* __WEXT_COMPAT */ diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 4c689fd..509279a 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -8,6 +8,7 @@ #include #include #include +#include "wext-compat.h" #include "nl80211.h" int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, @@ -108,8 +109,6 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, cfg80211_unlock_rdev(rdev); return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq); int cfg80211_mgd_wext_giwfreq(struct net_device *dev, struct iw_request_info *info, @@ -138,8 +137,6 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev, /* no channel if not joining */ return -EINVAL; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwfreq); int cfg80211_mgd_wext_siwessid(struct net_device *dev, struct iw_request_info *info, -- cgit v0.10.2 From 562e482265ac4d660d9f0114419591d62f44361d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:51 +0200 Subject: cfg80211: combine IWAP handlers Since we now have IWAP handlers for all modes, we can combine them into one. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 8058e99..5319b16 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -27,36 +27,6 @@ #include "iwm.h" #include "commands.h" -static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - case UMAC_MODE_BSS: - return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); - default: - return -EOPNOTSUPP; - } -} - -static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); - case UMAC_MODE_BSS: - return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); - default: - return -EOPNOTSUPP; - } -} - static int iwm_wext_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) @@ -111,8 +81,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* SIOCGIWSPY */ (iw_handler) NULL, /* SIOCSIWTHRSPY */ (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */ - (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */ + (iw_handler) cfg80211_wext_siwap, /* SIOCSIWAP */ + (iw_handler) cfg80211_wext_giwap, /* SIOCGIWAP */ (iw_handler) NULL, /* SIOCSIWMLME */ (iw_handler) NULL, /* SIOCGIWAPLIST */ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5d249c4..3348c16 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1601,12 +1601,6 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, int cfg80211_ibss_wext_giwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid); -int cfg80211_ibss_wext_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra); -int cfg80211_ibss_wext_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra); int cfg80211_mgd_wext_siwessid(struct net_device *dev, struct iw_request_info *info, @@ -1614,12 +1608,6 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, int cfg80211_mgd_wext_giwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid); -int cfg80211_mgd_wext_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra); -int cfg80211_mgd_wext_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra); int cfg80211_wext_siwgenie(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra); @@ -1686,12 +1674,12 @@ int cfg80211_wext_giwpower(struct net_device *dev, struct iw_request_info *info, struct iw_param *wrq, char *extra); -int cfg80211_wds_wext_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *addr, char *extra); -int cfg80211_wds_wext_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *addr, char *extra); +int cfg80211_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); /* * callbacks for asynchronous cfg80211 methods, notification diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 7cd9aa7..72866c8 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -59,43 +59,6 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, } -static int ieee80211_ioctl_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_WDS) - return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra); - return -EOPNOTSUPP; -} - - -static int ieee80211_ioctl_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_WDS) - return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra); - - return -EOPNOTSUPP; -} - - /* Structures to export the Wireless Handlers */ static const iw_handler ieee80211_handler[] = @@ -120,8 +83,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* SIOCGIWSPY */ (iw_handler) NULL, /* SIOCSIWTHRSPY */ (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */ - (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ + (iw_handler) cfg80211_wext_siwap, /* SIOCSIWAP */ + (iw_handler) cfg80211_wext_giwap, /* SIOCGIWAP */ (iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */ (iw_handler) NULL, /* SIOCGIWAPLIST */ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index de9ac49..f955225 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -466,8 +466,6 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap); int cfg80211_ibss_wext_giwap(struct net_device *dev, struct iw_request_info *info, @@ -493,6 +491,4 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, return 0; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap); #endif diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index fc2e776..c27774b 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1149,9 +1149,9 @@ int cfg80211_wext_giwpower(struct net_device *dev, } EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower); -int cfg80211_wds_wext_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *addr, char *extra) +static int cfg80211_wds_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *addr, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); @@ -1177,11 +1177,10 @@ int cfg80211_wds_wext_siwap(struct net_device *dev, return 0; } -EXPORT_SYMBOL_GPL(cfg80211_wds_wext_siwap); -int cfg80211_wds_wext_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *addr, char *extra) +static int cfg80211_wds_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *addr, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -1193,7 +1192,6 @@ int cfg80211_wds_wext_giwap(struct net_device *dev, return 0; } -EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap); int cfg80211_wext_siwrate(struct net_device *dev, struct iw_request_info *info, @@ -1327,3 +1325,41 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) return &wstats; } EXPORT_SYMBOL_GPL(cfg80211_wireless_stats); + +int cfg80211_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_WDS: + return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwap); + +int cfg80211_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); + case NL80211_IFTYPE_WDS: + return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwap); diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h index 23a6b5a..51028eb 100644 --- a/net/wireless/wext-compat.h +++ b/net/wireless/wext-compat.h @@ -7,6 +7,12 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, int cfg80211_ibss_wext_giwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra); +int cfg80211_ibss_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_ibss_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); int cfg80211_mgd_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, @@ -14,6 +20,12 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, int cfg80211_mgd_wext_giwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra); +int cfg80211_mgd_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); +int cfg80211_mgd_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra); struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 509279a..1aa31cc 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -273,8 +273,6 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap); int cfg80211_mgd_wext_giwap(struct net_device *dev, struct iw_request_info *info, @@ -299,8 +297,6 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev, return 0; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwap); int cfg80211_wext_siwgenie(struct net_device *dev, struct iw_request_info *info, -- cgit v0.10.2 From 1f9298f96082692bdfe73af6fc2167f627f21647 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:52 +0200 Subject: cfg80211: combine IWESSID handlers Since we now have handlers IWESSID for all modes, we can combine them into one. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 5319b16..9196024a2 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -27,38 +27,6 @@ #include "iwm.h" #include "commands.h" -static int iwm_wext_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); - case UMAC_MODE_BSS: - return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); - default: - return -EOPNOTSUPP; - } -} - -static int iwm_wext_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); - case UMAC_MODE_BSS: - return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); - default: - return -EOPNOTSUPP; - } -} - static const iw_handler iwm_handlers[] = { (iw_handler) NULL, /* SIOCSIWCOMMIT */ @@ -87,8 +55,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* SIOCGIWAPLIST */ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ - (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */ - (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */ + (iw_handler) cfg80211_wext_siwessid, /* SIOCSIWESSID */ + (iw_handler) cfg80211_wext_giwessid, /* SIOCGIWESSID */ (iw_handler) NULL, /* SIOCSIWNICKN */ (iw_handler) NULL, /* SIOCGIWNICKN */ (iw_handler) NULL, /* -- hole -- */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3348c16..e1b9235 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1595,19 +1595,6 @@ int cfg80211_wext_siwmlme(struct net_device *dev, int cfg80211_wext_giwrange(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra); -int cfg80211_ibss_wext_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid); -int cfg80211_ibss_wext_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid); - -int cfg80211_mgd_wext_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid); -int cfg80211_mgd_wext_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid); int cfg80211_wext_siwgenie(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra); @@ -1624,7 +1611,12 @@ int cfg80211_wext_siwfreq(struct net_device *dev, int cfg80211_wext_giwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra); - +int cfg80211_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); int cfg80211_wext_siwrate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rate, char *extra); diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 72866c8..aa250c3 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -27,37 +27,6 @@ #include "aes_ccm.h" -static int ieee80211_ioctl_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); - - return -EOPNOTSUPP; -} - - -static int ieee80211_ioctl_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); - - return -EOPNOTSUPP; -} - /* Structures to export the Wireless Handlers */ @@ -89,8 +58,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* SIOCGIWAPLIST */ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ - (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */ - (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */ + (iw_handler) cfg80211_wext_siwessid, /* SIOCSIWESSID */ + (iw_handler) cfg80211_wext_giwessid, /* SIOCGIWESSID */ (iw_handler) NULL, /* SIOCSIWNICKN */ (iw_handler) NULL, /* SIOCGIWNICKN */ (iw_handler) NULL, /* -- hole -- */ diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index f955225..4d7a084 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -381,8 +381,6 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid); int cfg80211_ibss_wext_giwessid(struct net_device *dev, struct iw_request_info *info, @@ -410,8 +408,6 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev, return 0; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid); int cfg80211_ibss_wext_siwap(struct net_device *dev, struct iw_request_info *info, diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index c27774b..083e4c3 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1363,3 +1363,37 @@ int cfg80211_wext_giwap(struct net_device *dev, } } EXPORT_SYMBOL_GPL(cfg80211_wext_giwap); + +int cfg80211_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwessid); + +int cfg80211_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); + case NL80211_IFTYPE_STATION: + return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid); diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h index 51028eb..c0310d9 100644 --- a/net/wireless/wext-compat.h +++ b/net/wireless/wext-compat.h @@ -13,6 +13,12 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, int cfg80211_ibss_wext_giwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra); +int cfg80211_ibss_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_ibss_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); int cfg80211_mgd_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, @@ -26,6 +32,12 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, int cfg80211_mgd_wext_giwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra); +int cfg80211_mgd_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); +int cfg80211_mgd_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid); struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 1aa31cc..7bacbd1 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -192,8 +192,6 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); return err; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid); int cfg80211_mgd_wext_giwessid(struct net_device *dev, struct iw_request_info *info, @@ -218,8 +216,6 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, return 0; } -/* temporary symbol - mark GPL - in the future the handler won't be */ -EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwessid); int cfg80211_mgd_wext_siwap(struct net_device *dev, struct iw_request_info *info, -- cgit v0.10.2 From a9a11622c5c742c115fad371c0397ae86dd3bb67 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:53 +0200 Subject: cfg80211: self-contained wext handling where possible Finally! This is what you've all been waiting for! This patch makes cfg80211 take care of wext emulation _completely_ by itself, drivers that don't need things cfg80211 doesn't do yet don't even need to be aware of wireless extensions. This means we can also clean up mac80211's and iwm's Kconfig and make it possible to build them w/o wext now! RIP wext. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig index 030401d..c62da43 100644 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -2,7 +2,6 @@ config IWM tristate "Intel Wireless Multicomm 3200 WiFi driver" depends on MMC && WLAN_80211 && EXPERIMENTAL depends on CFG80211 - select WIRELESS_EXT select FW_LOADER help The Intel Wireless Multicomm 3200 hardware is a combo diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile index 927f022..d34291b 100644 --- a/drivers/net/wireless/iwmc3200wifi/Makefile +++ b/drivers/net/wireless/iwmc3200wifi/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_IWM) := iwmc3200wifi.o iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o -iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o +iwmc3200wifi-objs += commands.o cfg80211.o eeprom.o iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 2175a48..7a51bc3 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -306,8 +306,6 @@ static inline void *iwm_private(struct iwm_priv *iwm) #define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb)) #define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb) -extern const struct iw_handler_def iwm_iw_handler_def; - void *iwm_if_alloc(int sizeof_bus, struct device *dev, struct iwm_if_ops *if_ops); void iwm_if_free(struct iwm_priv *iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index 092d28a..30116d1 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -123,7 +123,6 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev, } ndev->netdev_ops = &iwm_netdev_ops; - ndev->wireless_handlers = &iwm_iw_handler_def; ndev->ieee80211_ptr = wdev; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c deleted file mode 100644 index 9196024a2..0000000 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation - * Samuel Ortiz - * Zhu Yi - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include -#include - -#include "iwm.h" -#include "commands.h" - -static const iw_handler iwm_handlers[] = -{ - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) cfg80211_wext_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) cfg80211_wext_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ - (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ - (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ - (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ - (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) cfg80211_wext_siwap, /* SIOCSIWAP */ - (iw_handler) cfg80211_wext_giwap, /* SIOCGIWAP */ - (iw_handler) NULL, /* SIOCSIWMLME */ - (iw_handler) NULL, /* SIOCGIWAPLIST */ - (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ - (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ - (iw_handler) cfg80211_wext_siwessid, /* SIOCSIWESSID */ - (iw_handler) cfg80211_wext_giwessid, /* SIOCGIWESSID */ - (iw_handler) NULL, /* SIOCSIWNICKN */ - (iw_handler) NULL, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* SIOCSIWRATE */ - (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */ - (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ - (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ - (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ - (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ - (iw_handler) NULL, /* SIOCSIWRETRY */ - (iw_handler) NULL, /* SIOCGIWRETRY */ - (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ - (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ - (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */ - (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */ - (iw_handler) NULL, /* SIOCGIWGENIE */ - (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */ - (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */ - (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) NULL, /* SIOCGIWENCODEEXT */ - (iw_handler) NULL, /* SIOCSIWPMKSA */ - (iw_handler) NULL, /* -- hole -- */ -}; - -const struct iw_handler_def iwm_iw_handler_def = { - .num_standard = ARRAY_SIZE(iwm_handlers), - .standard = (iw_handler *) iwm_handlers, - .get_wireless_stats = cfg80211_wireless_stats, -}; - diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 19a4c66..7dd77b6 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -6,7 +6,6 @@ config MAC80211 select CRYPTO_ARC4 select CRYPTO_AES select CRC32 - select WIRELESS_EXT ---help--- This option enables the hardware independent IEEE 802.11 networking stack. diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 91284a7..9f3cf71 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -3,7 +3,6 @@ obj-$(CONFIG_MAC80211) += mac80211.o # mac80211 objects mac80211-y := \ main.o \ - wext.o \ sta_info.o \ wep.o \ wpa.o \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c6b25cb..aec6853 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -24,7 +24,6 @@ #include #include #include -#include #include #include "key.h" #include "sta_info.h" @@ -951,9 +950,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, void ieee80211_configure_filter(struct ieee80211_local *local); u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); -/* wireless extensions */ -extern const struct iw_handler_def ieee80211_iw_handler_def; - /* STA code */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d79a211..6c655b6 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -684,7 +684,6 @@ static void ieee80211_if_setup(struct net_device *dev) { ether_setup(dev); dev->netdev_ops = &ieee80211_dataif_ops; - dev->wireless_handlers = &ieee80211_iw_handler_def; dev->destructor = free_netdev; } diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 147772a..4573100 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "ieee80211_i.h" #include "driver-ops.h" diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c deleted file mode 100644 index aa250c3..0000000 --- a/net/mac80211/wext.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * - * 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 - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "ieee80211_i.h" -#include "led.h" -#include "rate.h" -#include "wpa.h" -#include "aes_ccm.h" - - - -/* Structures to export the Wireless Handlers */ - -static const iw_handler ieee80211_handler[] = -{ - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) cfg80211_wext_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) cfg80211_wext_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ - (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ - (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ - (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ - (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) cfg80211_wext_siwap, /* SIOCSIWAP */ - (iw_handler) cfg80211_wext_giwap, /* SIOCGIWAP */ - (iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */ - (iw_handler) NULL, /* SIOCGIWAPLIST */ - (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ - (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ - (iw_handler) cfg80211_wext_siwessid, /* SIOCSIWESSID */ - (iw_handler) cfg80211_wext_giwessid, /* SIOCGIWESSID */ - (iw_handler) NULL, /* SIOCSIWNICKN */ - (iw_handler) NULL, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) cfg80211_wext_siwrate, /* SIOCSIWRATE */ - (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */ - (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ - (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ - (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ - (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ - (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ - (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ - (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ - (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ - (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */ - (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */ - (iw_handler) NULL, /* SIOCGIWGENIE */ - (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */ - (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */ - (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) NULL, /* SIOCGIWENCODEEXT */ - (iw_handler) NULL, /* SIOCSIWPMKSA */ - (iw_handler) NULL, /* -- hole -- */ -}; - -const struct iw_handler_def ieee80211_iw_handler_def = -{ - .num_standard = ARRAY_SIZE(ieee80211_handler), - .standard = (iw_handler *) ieee80211_handler, - .get_wireless_stats = cfg80211_wireless_stats, -}; diff --git a/net/wireless/core.c b/net/wireless/core.c index 442c9f3..f9fee65 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -19,6 +19,7 @@ #include "core.h" #include "sysfs.h" #include "debugfs.h" +#include "wext-compat.h" /* name for sysfs, %d is appended */ #define PHY_NAME "phy" @@ -665,6 +666,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev->sme_state = CFG80211_SME_IDLE; mutex_unlock(&rdev->devlist_mtx); #ifdef CONFIG_WIRELESS_EXT + if (!dev->wireless_handlers) + dev->wireless_handlers = &cfg80211_wext_handler; wdev->wext.default_key = -1; wdev->wext.default_mgmt_key = -1; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 30058a8..097a87d 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -8,7 +8,9 @@ #include #include #include +#include #include +#include #include "core.h" #include "nl80211.h" diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 2a2683f..67714d7 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -14,6 +14,7 @@ #include #include "core.h" #include "nl80211.h" +#include "wext-compat.h" #define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index a197410..d2b5d4c 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include "nl80211.h" diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 083e4c3..e4e90e2 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1397,3 +1397,43 @@ int cfg80211_wext_giwessid(struct net_device *dev, } } EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid); + +static const iw_handler cfg80211_handlers[] = { + [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, + [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, + [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq, + [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode, + [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode, + [IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange, + [IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap, + [IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap, + [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme, + [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan, + [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan, + [IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid, + [IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid, + [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate, + [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate, + [IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts, + [IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts, + [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag, + [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag, + [IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower, + [IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower, + [IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry, + [IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry, + [IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode, + [IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode, + [IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower, + [IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower, + [IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie, + [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, + [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, + [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, +}; + +const struct iw_handler_def cfg80211_wext_handler = { + .num_standard = ARRAY_SIZE(cfg80211_handlers), + .standard = cfg80211_handlers, + .get_wireless_stats = cfg80211_wireless_stats, +}; diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h index c0310d9..9a37747 100644 --- a/net/wireless/wext-compat.h +++ b/net/wireless/wext-compat.h @@ -1,6 +1,9 @@ #ifndef __WEXT_COMPAT #define __WEXT_COMPAT +#include +#include + int cfg80211_ibss_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra); @@ -42,4 +45,6 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); + +extern const struct iw_handler_def cfg80211_wext_handler; #endif /* __WEXT_COMPAT */ -- cgit v0.10.2 From 35a1e70dfe74aafa350325f79687153b9852c3f1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 08:30:00 -0700 Subject: ath9k: remove unused ATH_PCI_VERSION Our version goes by the kernel release. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 87f9971..75ddb2a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -17,8 +17,6 @@ #include #include "ath9k.h" -#define ATH_PCI_VERSION "0.1" - static char *dev_info = "ath9k"; MODULE_AUTHOR("Atheros Communications"); -- cgit v0.10.2 From 1e4247d457c6a42e4a05cb7dfa4e6ea1fa65c112 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 27 Jul 2009 13:50:15 -0700 Subject: iwlwifi: debugFs to enable/disable HT40 support Add debugfs file to enable/disable HT40(40MHz) channel support. By default, 40MHz is supported if AP can support the function. By echo "1" to "disable_ht40" file, iwlwifi driver will disable the 40MHz support and only allow 20MHz channel. Because the information exchange happen during association time, so enable/disable ht40 channel only can be performed when it is not associated with AP. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index aafa9fd..8570d56 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -632,6 +632,10 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, if (!sta_ht_inf->ht_supported) return 0; } +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->disable_ht40) + return 0; +#endif return iwl_is_channel_extension(priv, priv->band, le16_to_cpu(priv->staging_rxon.channel), iwl_ht_conf->extension_chan_offset); diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 609a681..fbe1776 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -88,6 +88,7 @@ struct iwl_debugfs { #ifdef CONFIG_IWLWIFI_LEDS struct dentry *file_led; #endif + struct dentry *file_disable_ht40; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 748dc31..7707a26 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -653,6 +653,49 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int ht40; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &ht40) != 1) + return -EFAULT; + if (!iwl_is_associated(priv)) + priv->disable_ht40 = ht40 ? true : false; + else { + IWL_ERR(priv, "Sta associated with AP - " + "Change to 40MHz channel support is not allowed\n"); + return -EINVAL; + } + + return count; +} + +static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[100]; + int pos = 0; + const size_t bufsz = sizeof(buf); + ssize_t ret; + + pos += scnprintf(buf + pos, bufsz - pos, + "11n 40MHz Mode: %s\n", + priv->disable_ht40 ? "Disabled" : "Enabled"); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); @@ -667,6 +710,7 @@ DEBUGFS_READ_FILE_OPS(qos); DEBUGFS_READ_FILE_OPS(led); #endif DEBUGFS_READ_FILE_OPS(thermal_throttling); +DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); /* * Create the debugfs files and directories @@ -708,6 +752,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(led, data); #endif DEBUGFS_ADD_FILE(thermal_throttling, data); + DEBUGFS_ADD_FILE(disable_ht40, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -747,6 +792,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led); #endif DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index facbc3d..0ee3ad2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1164,6 +1164,7 @@ struct iwl_priv { /* debugging info */ u32 framecnt_to_us; atomic_t restrict_refcnt; + bool disable_ht40; #ifdef CONFIG_IWLWIFI_DEBUGFS /* debugfs */ struct iwl_debugfs *dbgfs; -- cgit v0.10.2 From 69331fbdeede932b64a0eaea6d196beaa9c40e0f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 29 Jul 2009 16:40:18 +0200 Subject: ASoC: neo1973_gta02_wm8753: Replace snd_soc_cnew with snd_soc_add_controls. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 1358f6f..75ee63d 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c @@ -338,7 +338,7 @@ static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = { */ static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) { - int i, err; + int err; /* set up NC codec pins */ snd_soc_dapm_nc_pin(codec, "OUT3"); @@ -351,13 +351,11 @@ static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) ARRAY_SIZE(wm8753_dapm_widgets)); /* add neo1973 gta02 specific controls */ - for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_gta02_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&wm8753_neo1973_gta02_controls[i], - codec, NULL)); - if (err < 0) - return err; - } + err = snd_soc_add_controls(codec, wm8753_neo1973_gta02_controls, + ARRAY_SIZE(wm8753_neo1973_gta02_controls)); + + if (err < 0) + return err; /* set up neo1973 gta02 specific audio path audio_map */ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); -- cgit v0.10.2 From 82c4362ee3d8a0b8797ba77222b25c7671696e2b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 29 Jul 2009 16:40:19 +0200 Subject: ASoC: neo1973_gta02_wm8753: Replace deprecated s3c_gpio calls with gpiolib With the s3c platform has implementing gpiolib support the s3c_gpio api has been deprecated. This patch gets rid of all s3c_gpio calls and replaces them by using gpiolib. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 75ee63d..0c52e36 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c @@ -1,5 +1,5 @@ /* - * neo1973_gta02_wm8753.c -- SoC audio for Neo1973 + * neo1973_gta02_wm8753.c -- SoC audio for Openmoko Freerunner(GTA02) * * Copyright 2007 Openmoko Inc * Author: Graeme Gregory @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -28,10 +29,7 @@ #include #include -#include -#include #include -#include #include #include "../codecs/wm8753.h" #include "s3c24xx-pcm.h" @@ -243,10 +241,10 @@ static int lm4853_set_spk(struct snd_kcontrol *kcontrol, if (val) { lm4853_state |= LM4853_SPK; - s3c2410_gpio_setpin(GTA02_GPIO_HP_IN, 0); + gpio_set_value(GTA02_GPIO_HP_IN, 0); } else { lm4853_state &= ~LM4853_SPK; - s3c2410_gpio_setpin(GTA02_GPIO_HP_IN, 1); + gpio_set_value(GTA02_GPIO_HP_IN, 1); } return 0; @@ -264,11 +262,7 @@ static int lm4853_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - if (SND_SOC_DAPM_EVENT_ON(event)) - s3c2410_gpio_setpin(GTA02_GPIO_AMP_SHUT, 0); - - if (SND_SOC_DAPM_EVENT_OFF(event)) - s3c2410_gpio_setpin(GTA02_GPIO_AMP_SHUT, 1); + gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(value)); return 0; } @@ -453,15 +447,38 @@ static int __init neo1973_gta02_init(void) } /* Initialise GPIOs used by amp */ - s3c2410_gpio_cfgpin(GTA02_GPIO_HP_IN, S3C2410_GPIO_OUTPUT); - s3c2410_gpio_cfgpin(GTA02_GPIO_AMP_SHUT, S3C2410_GPIO_OUTPUT); + ret = gpio_request(GTA02_GPIO_HP_IN, "GTA02_HP_IN"); + if (ret) { + pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_HP_IN); + goto err_unregister_device; + } - /* Amp off by default */ - s3c2410_gpio_setpin(GTA02_GPIO_AMP_SHUT, 1); + ret = gpio_direction_output(GTA02_GPIO_AMP_HP_IN, 1); + if (ret) { + pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN); + goto err_free_gpio_hp_in; + } - /* Speaker off by default */ - s3c2410_gpio_setpin(GTA02_GPIO_HP_IN, 1); + ret = gpio_request(GTA02_GPIO_AMP_SHUT, "GTA02_AMP_SHUT"); + if (ret) { + pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_AMP_SHUT); + goto err_free_gpio_hp_in; + } + ret = gpio_direction_output(GTA02_GPIO_AMP_SHUT, 1); + if (ret) { + pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_AMP_SHUT); + goto err_free_gpio_amp_shut; + } + + return 0; + +err_free_gpio_amp_shut: + gpio_free(GTA02_GPIO_AMP_SHUT); +err_free_gpio_hp_in: + gpio_free(GTA02_GPIO_HP_IN); +err_unregister_device: + platform_device_unregister(neo1973_gta02_snd_device); return ret; } module_init(neo1973_gta02_init); @@ -470,6 +487,8 @@ static void __exit neo1973_gta02_exit(void) { snd_soc_unregister_dai(&bt_dai); platform_device_unregister(neo1973_gta02_snd_device); + gpio_free(GTA02_GPIO_HP_IN); + gpio_free(GTA02_GPIO_AMP_SHUT); } module_exit(neo1973_gta02_exit); -- cgit v0.10.2 From 3a39f832a5699d50a6785de97c551033cc09d0ec Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Wed, 29 Jul 2009 15:03:16 +0800 Subject: ASoC: Fix checkpatch issues and typos of ad1938 codec and bf5xx-tdm dai MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. fix "line over 80 characters" checkpatch warnings 2. ‘DMA_nnBIT_MASK’ is deprecated, use DMA_BIT_MASK instead 3. fix typos Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mark Brown diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c index af7fa8d..ccb5e82 100644 --- a/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c @@ -276,7 +276,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) sport_done(sport_handle); } -static u64 bf5xx_pcm_dmamask = DMA_32BIT_MASK; +static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) @@ -286,7 +286,7 @@ static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai, if (!card->dev->dma_mask) card->dev->dma_mask = &bf5xx_pcm_dmamask; if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = DMA_32BIT_MASK; + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); if (dai->playback.channels_min) { ret = bf5xx_pcm_preallocate_dma_buffer(pcm, diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.h b/sound/soc/blackfin/bf5xx-tdm-pcm.h index 9e8473d..ddc5047 100644 --- a/sound/soc/blackfin/bf5xx-tdm-pcm.h +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.h @@ -1,5 +1,5 @@ /* - * linux/sound/arm/bf5xx-tdm-pcm.h -- ALSA PCM interface for the Blackfin + * sound/soc/blackfin/bf5xx-tdm-pcm.h -- ALSA PCM interface for the Blackfin * * Copyright 2009 Analog Device Inc. * diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h index e5157cd..618ec3d 100644 --- a/sound/soc/blackfin/bf5xx-tdm.h +++ b/sound/soc/blackfin/bf5xx-tdm.h @@ -1,5 +1,5 @@ /* - * linux/sound/arm/bf5xx-i2s.h + * sound/soc/blackfin/bf5xx-tdm.h * * 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/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index ffc97c9..aafda74 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -72,14 +72,20 @@ static const struct snd_kcontrol_new ad1938_snd_controls[] = { AD1938_DAC_R4_VOL, 0, 0xFF, 1), /* ADC switch control */ - SOC_DOUBLE("ADC1 Switch", AD1938_ADC_CTRL0, AD1938_ADCL1_MUTE, AD1938_ADCR1_MUTE, 1, 1), - SOC_DOUBLE("ADC2 Switch", AD1938_ADC_CTRL0, AD1938_ADCL2_MUTE, AD1938_ADCR2_MUTE, 1, 1), + SOC_DOUBLE("ADC1 Switch", AD1938_ADC_CTRL0, AD1938_ADCL1_MUTE, + AD1938_ADCR1_MUTE, 1, 1), + SOC_DOUBLE("ADC2 Switch", AD1938_ADC_CTRL0, AD1938_ADCL2_MUTE, + AD1938_ADCR2_MUTE, 1, 1), /* DAC switch control */ - SOC_DOUBLE("DAC1 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL1_MUTE, AD1938_DACR1_MUTE, 1, 1), - SOC_DOUBLE("DAC2 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL2_MUTE, AD1938_DACR2_MUTE, 1, 1), - SOC_DOUBLE("DAC3 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL3_MUTE, AD1938_DACR3_MUTE, 1, 1), - SOC_DOUBLE("DAC4 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL4_MUTE, AD1938_DACR4_MUTE, 1, 1), + SOC_DOUBLE("DAC1 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL1_MUTE, + AD1938_DACR1_MUTE, 1, 1), + SOC_DOUBLE("DAC2 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL2_MUTE, + AD1938_DACR2_MUTE, 1, 1), + SOC_DOUBLE("DAC3 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL3_MUTE, + AD1938_DACR3_MUTE, 1, 1), + SOC_DOUBLE("DAC4 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL4_MUTE, + AD1938_DACR4_MUTE, 1, 1), /* ADC high-pass filter */ SOC_SINGLE("ADC High Pass Filter Switch", AD1938_ADC_CTRL0, @@ -110,7 +116,8 @@ static int ad1938_mute(struct snd_soc_dai *dai, int mute) int reg; reg = codec->read(codec, AD1938_DAC_CTRL2); - reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg & (~AD1938_DAC_MASTER_MUTE); + reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg & + (~AD1938_DAC_MASTER_MUTE); codec->write(codec, AD1938_DAC_CTRL2, reg); return 0; @@ -119,7 +126,8 @@ static int ad1938_mute(struct snd_soc_dai *dai, int mute) static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd) { int reg = codec->read(codec, AD1938_PLL_CLK_CTRL0); - reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg | AD1938_PLL_POWERDOWN; + reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg | + AD1938_PLL_POWERDOWN; codec->write(codec, AD1938_PLL_CLK_CTRL0, reg); return 0; @@ -171,8 +179,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai, adc_reg = codec->read(codec, AD1938_ADC_CTRL2); dac_reg = codec->read(codec, AD1938_DAC_CTRL1); - /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S with TDM) - * and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) + /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S + * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -363,7 +371,8 @@ static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec, * read from the ad1938 register space */ -static unsigned int ad1938_read_reg(struct snd_soc_codec *codec, unsigned int reg) +static unsigned int ad1938_read_reg(struct snd_soc_codec *codec, + unsigned int reg) { char w_buf[AD1938_SPI_BUFLEN]; char r_buf[AD1938_SPI_BUFLEN]; @@ -502,12 +511,19 @@ static int ad1938_register(struct ad1938_priv *ad1938) ad1938_codec = codec; /* default setting for ad1938 */ - codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0); /* unmute dac channels */ - codec->write(codec, AD1938_DAC_CTRL2, 0x1A); /* de-emphasis: 48kHz, powedown dac */ - codec->write(codec, AD1938_DAC_CTRL0, 0x21); /* powerdown dac, dac tdm mode */ - codec->write(codec, AD1938_ADC_CTRL0, 0x3); /* high-pass filter enable */ - codec->write(codec, AD1938_ADC_CTRL1, 0x43); /* sata delay=1, adc aux mode */ - codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); /* pll input:mclki/xi */ + + /* unmute dac channels */ + codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0); + /* de-emphasis: 48kHz, powedown dac */ + codec->write(codec, AD1938_DAC_CTRL2, 0x1A); + /* powerdown dac, dac in tdm mode */ + codec->write(codec, AD1938_DAC_CTRL0, 0x41); + /* high-pass filter enable */ + codec->write(codec, AD1938_ADC_CTRL0, 0x3); + /* sata delay=1, adc aux mode */ + codec->write(codec, AD1938_ADC_CTRL1, 0x43); + /* pll input: mclki/xi */ + codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); codec->write(codec, AD1938_PLL_CLK_CTRL1, 0x04); ad1938_fill_cache(codec); -- cgit v0.10.2 From 044824d96208c8ec4863f9c54a529e00a1f1d37c Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 28 Jul 2009 09:10:03 +0000 Subject: netxen: fix CONFIG_INET=n build Wrap dest IP hashing code with #ifdef CONFIG_INET, this feature makes no sense without INET, but other driver can still work. Signed-off-by: Dhananjay Phadke Acked-by: Randy Dunlap Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 2bbefa6..40549a0 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1875,6 +1875,8 @@ static void netxen_nic_poll_controller(struct net_device *netdev) } #endif +#ifdef CONFIG_INET + #define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops) static int @@ -1993,6 +1995,7 @@ static struct notifier_block netxen_netdev_cb = { static struct notifier_block netxen_inetaddr_cb = { .notifier_call = netxen_inetaddr_event, }; +#endif static struct pci_driver netxen_driver = { .name = netxen_nic_driver_name, @@ -2012,8 +2015,10 @@ static int __init netxen_init_module(void) if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL) return -ENOMEM; +#ifdef CONFIG_INET register_netdevice_notifier(&netxen_netdev_cb); register_inetaddr_notifier(&netxen_inetaddr_cb); +#endif return pci_register_driver(&netxen_driver); } @@ -2024,8 +2029,10 @@ static void __exit netxen_exit_module(void) { pci_unregister_driver(&netxen_driver); +#ifdef CONFIG_INET unregister_inetaddr_notifier(&netxen_inetaddr_cb); unregister_netdevice_notifier(&netxen_netdev_cb); +#endif destroy_workqueue(netxen_workq); } -- cgit v0.10.2 From dd7714c92248943b778e8199c7dec7ef859dcac2 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Thu, 30 Jul 2009 14:36:35 +0800 Subject: ALSA: hda: add 2-channel mode to Intel ALC889/ALC889A models This 2-channel mode is useful in that it will broadcast a 2-channel audio stream to all front/side/... ports. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6794d02..8c5d342 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6681,18 +6681,27 @@ static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { }; /* + * 2ch mode + */ +static struct hda_verb alc889_ch2_intel_init[] = { + { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* * 6ch mode */ static struct hda_verb alc889_ch6_intel_init[] = { - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { } /* end */ }; @@ -6701,21 +6710,18 @@ static struct hda_verb alc889_ch6_intel_init[] = { * 8ch mode */ static struct hda_verb alc889_ch8_intel_init[] = { - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 }, { 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, 0x03 }, { } /* end */ }; -static struct hda_channel_mode alc889_8ch_intel_modes[2] = { +static struct hda_channel_mode alc889_8ch_intel_modes[3] = { + { 2, alc889_ch2_intel_init }, { 6, alc889_ch6_intel_init }, { 8, alc889_ch8_intel_init }, }; -- cgit v0.10.2 From 6732bd0d15893d20359396309adc238e0af10b58 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Thu, 30 Jul 2009 09:19:14 +0200 Subject: ALSA: hda: add HP automute support to Intel ALC889/ALC889A models It auto mutes all 8-channel outputs at rear panel when the front panel headphone is connected. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8c5d342..587d94f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1436,6 +1436,25 @@ static void alc_automute_amp_unsol_event(struct hda_codec *codec, alc_automute_amp(codec); } +static void alc889_automute_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x17; + spec->autocfg.speaker_pins[3] = 0x19; + spec->autocfg.speaker_pins[4] = 0x1a; + alc_automute_amp(codec); +} + +static void alc889_intel_init_hook(struct hda_codec *codec) +{ + alc889_coef_init(codec); + alc889_automute_init(codec); +} + static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -6993,6 +7012,11 @@ static struct hda_verb alc889_eapd_verbs[] = { { } }; +static struct hda_verb alc_hp15_unsol_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {} +}; static struct hda_verb alc885_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ @@ -7018,7 +7042,7 @@ static struct hda_verb alc885_init_verbs[] = { {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* Front HP Pin: output 0 (0x0c) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front Pin: output 0 (0x0c) */ @@ -8860,7 +8884,8 @@ static struct alc_config_preset alc882_presets[] = { }, [ALC889A_INTEL] = { .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, - .init_verbs = { alc885_init_verbs, alc885_init_input_verbs }, + .init_verbs = { alc885_init_verbs, alc885_init_input_verbs, + alc_hp15_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), @@ -8872,12 +8897,14 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc889_8ch_intel_modes, .capsrc_nids = alc889_capsrc_nids, .input_mux = &alc889_capture_source, + .init_hook = alc889_automute_init, + .unsol_event = alc_automute_amp_unsol_event, .need_dac_fix = 1, }, [ALC889_INTEL] = { .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer }, .init_verbs = { alc885_init_verbs, alc889_init_input_verbs, - alc889_eapd_verbs }, + alc889_eapd_verbs, alc_hp15_unsol_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), @@ -8889,7 +8916,8 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc889_8ch_intel_modes, .capsrc_nids = alc889_capsrc_nids, .input_mux = &alc889_capture_source, - .init_hook = alc889_coef_init, + .init_hook = alc889_intel_init_hook, + .unsol_event = alc_automute_amp_unsol_event, .need_dac_fix = 1, }, [ALC883_6ST_DIG] = { @@ -10121,12 +10149,6 @@ static struct hda_verb alc262_eapd_verbs[] = { { } }; -static struct hda_verb alc262_hippo_unsol_verbs[] = { - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {} -}; - static struct hda_verb alc262_hippo1_unsol_verbs[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -11168,7 +11190,7 @@ static struct alc_config_preset alc262_presets[] = { }, [ALC262_HIPPO] = { .mixers = { alc262_hippo_mixer }, - .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs}, + .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs}, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, .hp_nid = 0x03, @@ -11288,7 +11310,8 @@ static struct alc_config_preset alc262_presets[] = { }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, - .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs }, + .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, + alc_hp15_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, .hp_nid = 0x03, -- cgit v0.10.2 From bf677bd8fbd5dc06ead5511cf9fa76d090856c6a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Jul 2009 09:24:29 +0200 Subject: ALSA: hda - Fix typos of Capture controls. The commit 6479c63188290beae83ade3243b9d6eb47d394b6 ALSA: hda - Create Capture controls dynamically introduced typos of "Capture". Fixed now. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 883e2aa..9e19252 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3307,11 +3307,11 @@ static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol, { int err; err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, - "Captuer Volume", vol); + "Capture Volume", vol); if (err < 0) return err; err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx, - "Captuer Switch", sw); + "Capture Switch", sw); if (err < 0) return err; return 0; -- cgit v0.10.2 From 5207e10ed49c515e7432d0b1a7561ccc7b71f9df Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Jul 2009 13:09:08 +0200 Subject: ALSA: hda - Integrate Digital Input Source to Input Source STAC/IDT codecs provide both "Input Source" and "Digital Input Source" controls to choose the analog input source and the digital input source. But this is far user-unfriendly. This patch merges the input source selections into one "Input Source" control. To have separate digital and analog input source controls, you can pass "separate_dmux = 1 " hint string. At the same time, this patch gets rid of analog mixer stuff that was already disabled in previous patches. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 883e2aa..3457f61 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -246,6 +246,7 @@ struct sigmatel_spec { unsigned int num_dmuxes; hda_nid_t *smux_nids; unsigned int num_smuxes; + unsigned int num_analog_muxes; unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */ unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ @@ -765,9 +766,35 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); + const struct hda_input_mux *imux = spec->input_mux; + unsigned int idx, prev_idx; + + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + prev_idx = spec->cur_mux[adc_idx]; + if (prev_idx == idx) + return 0; + if (idx < spec->num_analog_muxes) { + snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[idx].index); + if (prev_idx >= spec->num_analog_muxes) { + imux = spec->dinput_mux; + /* 0 = analog */ + snd_hda_codec_write_cache(codec, + spec->dmux_nids[adc_idx], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[0].index); + } + } else { + imux = spec->dinput_mux; + snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[idx - 1].index); + } + spec->cur_mux[adc_idx] = idx; + return 1; } static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol, @@ -1204,21 +1231,6 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { - HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT), - - HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT), - - HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT), - - HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT), - { } /* end */ -}; - static struct snd_kcontrol_new stac92hd71bxx_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2) }; @@ -1302,7 +1314,8 @@ static int stac92xx_build_controls(struct hda_codec *codec) if (err < 0) return err; } - if (!spec->auto_mic && spec->num_dmuxes > 0) { + if (!spec->auto_mic && spec->num_dmuxes > 0 && + snd_hda_get_bool_hint(codec, "separate_dmux") == 1) { stac_dmux_mixer.count = spec->num_dmuxes; err = snd_hda_ctl_add(codec, snd_ctl_new1(&stac_dmux_mixer, codec)); @@ -3575,19 +3588,28 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->private_imux; struct hda_input_mux *dimux = &spec->private_dimux; - int err, i; + int err, i, active_mics; + unsigned int def_conf; char name[32]; dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; dimux->items[dimux->num_items].index = 0; dimux->num_items++; + active_mics = 0; + for (i = 0; i < spec->num_dmics; i++) { + def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); + if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) + active_mics++; + } + for (i = 0; i < spec->num_dmics; i++) { hda_nid_t nid; int index; unsigned int wcaps; - unsigned int def_conf; + const char *label; def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) @@ -3598,12 +3620,16 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, if (index < 0) continue; + if (active_mics == 1) + label = "Digital Mic"; + else + label = stac92xx_dmic_labels[dimux->num_items]; + wcaps = get_wcaps(codec, nid) & (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); if (wcaps) { - sprintf(name, "%s Capture Volume", - stac92xx_dmic_labels[dimux->num_items]); + sprintf(name, "%s Capture Volume", label); err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, @@ -3615,10 +3641,14 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, return err; } - dimux->items[dimux->num_items].label = - stac92xx_dmic_labels[dimux->num_items]; + dimux->items[dimux->num_items].label = label; dimux->items[dimux->num_items].index = index; dimux->num_items++; + if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) { + imux->items[imux->num_items].label = label; + imux->items[imux->num_items].index = index; + imux->num_items++; + } } return 0; @@ -3738,6 +3768,7 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const imux->items[imux->num_items].index = index; imux->num_items++; } + spec->num_analog_muxes = imux->num_items; if (imux->num_items) { /* @@ -5059,16 +5090,6 @@ static int patch_stac925x(struct hda_codec *codec) return 0; } -static struct hda_input_mux stac92hd73xx_dmux = { - .num_items = 4, - .items = { - { "Analog Inputs", 0x0b }, - { "Digital Mic 1", 0x09 }, - { "Digital Mic 2", 0x0a }, - { "CD", 0x08 }, - } -}; - static int patch_stac92hd73xx(struct hda_codec *codec) { struct sigmatel_spec *spec; @@ -5138,8 +5159,6 @@ again: spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids); spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids); spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids); - memcpy(&spec->private_dimux, &stac92hd73xx_dmux, - sizeof(stac92hd73xx_dmux)); spec->num_caps = STAC92HD73XX_NUM_CAPS; spec->capvols = stac92hd73xx_capvols; @@ -5164,18 +5183,15 @@ again: case STAC_DELL_M6_AMIC: /* Analog Mics */ snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); spec->num_dmics = 0; - spec->private_dimux.num_items = 1; break; case STAC_DELL_M6_DMIC: /* Digital Mics */ snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); spec->num_dmics = 1; - spec->private_dimux.num_items = 2; break; case STAC_DELL_M6_BOTH: /* Both */ snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); spec->num_dmics = 1; - spec->private_dimux.num_items = 2; break; } break; @@ -5183,13 +5199,13 @@ again: spec->num_dmics = STAC92HD73XX_NUM_DMICS; spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); spec->eapd_switch = 1; + break; } if (spec->board_config > STAC_92HD73XX_REF) { /* GPIO0 High = Enable EAPD */ spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; spec->gpio_data = 0x01; } - spec->dinput_mux = &spec->private_dimux; spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); spec->pwr_nids = stac92hd73xx_pwr_nids; @@ -5221,15 +5237,6 @@ again: return 0; } -static struct hda_input_mux stac92hd83xxx_dmux = { - .num_items = 3, - .items = { - { "Analog Inputs", 0x03 }, - { "Digital Mic 1", 0x04 }, - { "Digital Mic 2", 0x05 }, - } -}; - static int patch_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; @@ -5262,7 +5269,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids); spec->num_dmics = STAC92HD83XXX_NUM_DMICS; - spec->dinput_mux = &stac92hd83xxx_dmux; spec->pin_nids = stac92hd83xxx_pin_nids; spec->num_caps = STAC92HD83XXX_NUM_CAPS; spec->capvols = stac92hd83xxx_capvols; @@ -5332,25 +5338,6 @@ again: return 0; } -static struct hda_input_mux stac92hd71bxx_dmux_nomixer = { - .num_items = 3, - .items = { - { "Analog Inputs", 0x00 }, - { "Digital Mic 1", 0x02 }, - { "Digital Mic 2", 0x03 }, - } -}; - -static struct hda_input_mux stac92hd71bxx_dmux_amixer = { - .num_items = 4, - .items = { - { "Analog Inputs", 0x00 }, - { "Mixer", 0x01 }, - { "Digital Mic 1", 0x02 }, - { "Digital Mic 2", 0x03 }, - } -}; - /* get the pin connection (fixed, none, etc) */ static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) { @@ -5411,7 +5398,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) struct sigmatel_spec *spec; struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; int err = 0; - unsigned int ndmic_nids = 0; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -5467,21 +5453,13 @@ again: /* fallthru */ case 0x111d76b4: /* 6 Port without Analog Mixer */ case 0x111d76b5: - memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_nomixer, - sizeof(stac92hd71bxx_dmux_nomixer)); spec->init = stac92hd71bxx_core_init; codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; spec->num_dmics = stac92hd71bxx_connected_ports(codec, stac92hd71bxx_dmic_nids, STAC92HD71BXX_NUM_DMICS); - if (spec->num_dmics) { - spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); - spec->dinput_mux = &spec->private_dimux; - ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1; - } break; case 0x111d7608: /* 5 Port with Analog Mixer */ - spec->private_dimux.num_items--; switch (spec->board_config) { case STAC_HP_M4: /* Enable VREF power saving on GPIO1 detect */ @@ -5503,15 +5481,6 @@ again: /* no output amps */ spec->num_pwrs = 0; - if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) { - spec->mixer = stac92hd71bxx_analog_mixer; - memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer, - sizeof(stac92hd71bxx_dmux_amixer)); - } else { - memcpy(&spec->private_dimux, - &stac92hd71bxx_dmux_nomixer, - sizeof(stac92hd71bxx_dmux_nomixer)); - } /* disable VSW */ spec->init = stac92hd71bxx_core_init; unmute_init++; @@ -5521,11 +5490,6 @@ again: spec->num_dmics = stac92hd71bxx_connected_ports(codec, stac92hd71bxx_dmic_nids, STAC92HD71BXX_NUM_DMICS - 1); - if (spec->num_dmics) { - spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); - spec->dinput_mux = &spec->private_dimux; - ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 2; - } break; case 0x111d7603: /* 6 Port with Analog Mixer */ if ((codec->revision_id & 0xf) == 1) @@ -5535,25 +5499,12 @@ again: spec->num_pwrs = 0; /* fallthru */ default: - if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) { - spec->mixer = stac92hd71bxx_analog_mixer; - memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer, - sizeof(stac92hd71bxx_dmux_amixer)); - } else { - memcpy(&spec->private_dimux, - &stac92hd71bxx_dmux_nomixer, - sizeof(stac92hd71bxx_dmux_nomixer)); - } spec->init = stac92hd71bxx_core_init; codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; spec->num_dmics = stac92hd71bxx_connected_ports(codec, stac92hd71bxx_dmic_nids, STAC92HD71BXX_NUM_DMICS); - if (spec->num_dmics) { - spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); - spec->dinput_mux = &spec->private_dimux; - ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1; - } + break; } if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) @@ -5581,6 +5532,7 @@ again: spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); + spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e); switch (spec->board_config) { @@ -5635,8 +5587,6 @@ again: #endif spec->multiout.dac_nids = spec->dac_nids; - if (spec->dinput_mux) - spec->private_dimux.num_items += spec->num_dmics - ndmic_nids; err = stac92xx_parse_auto_config(codec, 0x21, 0); if (!err) { -- cgit v0.10.2 From 3a38516750e176a18f76d605b401fbab2c72d648 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Thu, 30 Jul 2009 14:44:27 +0200 Subject: ALSA: hda - Enable HP output with Macbook Pro 5, 5 The patch below, to be applied on the latest sound-unstable-2.6.git, enables headphones output on my MacBookPro 5,5, together with the automuting feature. Here is the exact soundcard id: Vendor Id: 0x10134206 Subsystem Id: 0x106b4d00 Revision Id: 0x100301 Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index f552738..8ba3068 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -832,6 +832,11 @@ static void cs_automute(struct hda_codec *codec) AC_VERB_SET_PIN_WIDGET_CONTROL, hp_present ? 0 : PIN_OUT); } + if (spec->board_config == CS420X_MBP55) { + unsigned int gpio = hp_present ? 0x02 : 0x08; + snd_hda_codec_write(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, gpio); + } } static void cs_automic(struct hda_codec *codec) @@ -1133,10 +1138,10 @@ static int patch_cs420x(struct hda_codec *codec) switch (spec->board_config) { case CS420X_MBP55: - /* GPIO3 = EAPD? */ - spec->gpio_mask = 0x08; - spec->gpio_dir = 0x08; - spec->gpio_data = 0x08; + /* GPIO1 = headphones */ + /* GPIO3 = speakers */ + spec->gpio_mask = 0x0a; + spec->gpio_dir = 0x0a; break; } -- cgit v0.10.2 From fefd67f31ee7f5259344e36a237d59b47e8715cf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Jul 2009 18:03:05 +0200 Subject: ALSA: hda - Add line-out jack detection on IDT/STAC codecs Add the automatic mute of speakers via line-out jack plugging on STAC/IDT codecs. The feature is enabled when the HP detect is present. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 9e19252..c7e5de6 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -40,6 +40,7 @@ enum { STAC_INSERT_EVENT, STAC_PWR_EVENT, STAC_HP_EVENT, + STAC_LO_EVENT, STAC_MIC_EVENT, }; @@ -4345,6 +4346,14 @@ static int stac92xx_init(struct hda_codec *codec) hda_nid_t nid = cfg->hp_pins[i]; enable_pin_detect(codec, nid, STAC_HP_EVENT); } + if (cfg->line_out_type == AUTO_PIN_LINE_OUT) { + /* enable pin-detect for line-outs as well */ + for (i = 0; i < cfg->hp_outs; i++) { + hda_nid_t nid = cfg->hp_pins[i]; + enable_pin_detect(codec, nid, STAC_LO_EVENT); + } + } + /* force to enable the first line-out; the others are set up * in unsol_event */ @@ -4543,6 +4552,48 @@ static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) return 0; } +static void stac92xx_line_out_detect(struct hda_codec *codec, + int presence) +{ + struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->line_outs; i++) { + if (presence) + break; + presence = get_pin_presence(codec, cfg->line_out_pins[i]); + if (presence) { + unsigned int pinctl; + pinctl = snd_hda_codec_read(codec, + cfg->line_out_pins[i], 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (pinctl & AC_PINCTL_IN_EN) + presence = 0; /* mic- or line-input */ + } + } + + if (presence) { + /* disable speakers */ + for (i = 0; i < cfg->speaker_outs; i++) + stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], + AC_PINCTL_OUT_EN); + if (spec->eapd_mask && spec->eapd_switch) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data & + ~spec->eapd_mask); + } else { + /* enable speakers */ + for (i = 0; i < cfg->speaker_outs; i++) + stac92xx_set_pinctl(codec, cfg->speaker_pins[i], + AC_PINCTL_OUT_EN); + if (spec->eapd_mask && spec->eapd_switch) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data | + spec->eapd_mask); + } +} + /* return non-zero if the hp-pin of the given array index isn't * a jack-detection target */ @@ -4595,13 +4646,6 @@ static void stac92xx_hp_detect(struct hda_codec *codec) for (i = 0; i < cfg->line_outs; i++) stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], AC_PINCTL_OUT_EN); - for (i = 0; i < cfg->speaker_outs; i++) - stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], - AC_PINCTL_OUT_EN); - if (spec->eapd_mask && spec->eapd_switch) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data & - ~spec->eapd_mask); } else { /* enable lineouts */ if (spec->hp_switch) @@ -4610,14 +4654,8 @@ static void stac92xx_hp_detect(struct hda_codec *codec) for (i = 0; i < cfg->line_outs; i++) stac92xx_set_pinctl(codec, cfg->line_out_pins[i], AC_PINCTL_OUT_EN); - for (i = 0; i < cfg->speaker_outs; i++) - stac92xx_set_pinctl(codec, cfg->speaker_pins[i], - AC_PINCTL_OUT_EN); - if (spec->eapd_mask && spec->eapd_switch) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data | - spec->eapd_mask); } + stac92xx_line_out_detect(codec, presence); /* toggle hp outs */ for (i = 0; i < cfg->hp_outs; i++) { unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; @@ -4744,6 +4782,9 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) case STAC_HP_EVENT: stac92xx_hp_detect(codec); break; + case STAC_LO_EVENT: + stac92xx_line_out_detect(codec, 0); + break; case STAC_MIC_EVENT: stac92xx_mic_detect(codec); break; @@ -4751,6 +4792,7 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) switch (event->type) { case STAC_HP_EVENT: + case STAC_LO_EVENT: case STAC_MIC_EVENT: case STAC_INSERT_EVENT: case STAC_PWR_EVENT: -- cgit v0.10.2 From 581ce43d269bb9f9ea85d8f6e6acf68bad129740 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 29 Jul 2009 00:20:04 +0000 Subject: bnx2x: Receive traffic that maches management filtering rules Due to lack of configuration, if the BMC configures the chip to pass all broadcast/multicast traffic to it, the host will not receive it. On top of fixing it, also make sure that in promiscuous mode, the host will receive the management traffic as well. Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index a2de0cd..5273988 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -4831,7 +4831,14 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp) int mode = bp->rx_mode; int mask = (1 << BP_L_ID(bp)); int func = BP_FUNC(bp); + int port = BP_PORT(bp); int i; + /* All but management unicast packets should pass to the host as well */ + u32 llh_mask = + NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST | + NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST | + NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN | + NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN; DP(NETIF_MSG_IFUP, "rx mode %d mask 0x%x\n", mode, mask); @@ -4855,6 +4862,8 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp) tstorm_mac_filter.ucast_accept_all = mask; tstorm_mac_filter.mcast_accept_all = mask; tstorm_mac_filter.bcast_accept_all = mask; + /* pass management unicast packets as well */ + llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST; break; default: @@ -4862,6 +4871,10 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp) break; } + REG_WR(bp, + (port ? NIG_REG_LLH1_BRB1_DRV_MASK : NIG_REG_LLH0_BRB1_DRV_MASK), + llh_mask); + for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) { REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_MAC_FILTER_CONFIG_OFFSET(func) + i * 4, diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index d771168..8e9e7a2 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -1616,6 +1616,11 @@ /* [RW 1] Set by the MCP to remember if one or more of the drivers is/are loaded; 0-prepare; -unprepare */ #define MISC_REG_UNPREPARED 0xa424 +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST (0x1<<0) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST (0x1<<1) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN (0x1<<4) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST (0x1<<2) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN (0x1<<3) #define NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT (0x1<<0) #define NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS (0x1<<9) #define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G (0x1<<15) -- cgit v0.10.2 From c1f1a06f926acc267c62a26d5d7435a3b5c7e429 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 29 Jul 2009 00:20:08 +0000 Subject: bnx2x: Self-test kills management traffic Self test used to play with the management FIFO possibly while management was running... Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 5273988..b47b531 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -9415,10 +9415,9 @@ static int bnx2x_test_registers(struct bnx2x *bp) { XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 }, { XCM_REG_WU_DA_CNT_CMD00, 4, 0x00000003 }, { XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 4, 0x000000ff }, - { NIG_REG_EGRESS_MNG0_FIFO, 20, 0xffffffff }, { NIG_REG_LLH0_T_BIT, 4, 0x00000001 }, -/* 20 */ { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 }, - { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 }, + { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 }, +/* 20 */ { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 }, { NIG_REG_XCM0_OUT_EN, 4, 0x00000001 }, { NIG_REG_BRB0_OUT_EN, 4, 0x00000001 }, { NIG_REG_LLH0_XCM_MASK, 4, 0x00000007 }, @@ -9427,8 +9426,8 @@ static int bnx2x_test_registers(struct bnx2x *bp) { NIG_REG_LLH0_DEST_MAC_0_0, 160, 0xffffffff }, { NIG_REG_LLH0_DEST_IP_0_1, 160, 0xffffffff }, { NIG_REG_LLH0_IPV4_IPV6_0, 160, 0x00000001 }, -/* 30 */ { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff }, - { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff }, + { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff }, +/* 30 */ { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff }, { NIG_REG_LLH0_VLAN_ID_0, 160, 0x00000fff }, { NIG_REG_XGXS_SERDES0_MODE_SEL, 4, 0x00000001 }, { NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001 }, -- cgit v0.10.2 From 7d0446c2349da54f2967fb34d984db572fbfc6ac Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 29 Jul 2009 00:20:10 +0000 Subject: bnx2x: WoL only with current MAC address In some cases with 57711E, depending on the functions unload sequence, other functions MAC address could have been used to wake the system as well. Make sure to block all but the current function if WoL is required by changing the mode to single function WoL. Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index b47b531..4245412 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -7354,17 +7354,17 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) for (i = 0; i < MC_HASH_SIZE; i++) REG_WR(bp, MC_HASH_OFFSET(bp, i), 0); + + REG_WR(bp, MISC_REG_E1HMF_MODE, 0); } if (unload_mode == UNLOAD_NORMAL) reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; - else if (bp->flags & NO_WOL_FLAG) { + else if (bp->flags & NO_WOL_FLAG) reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP; - if (CHIP_IS_E1H(bp)) - REG_WR(bp, MISC_REG_E1HMF_MODE, 0); - } else if (bp->wol) { + else if (bp->wol) { u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; u8 *mac_addr = bp->dev->dev_addr; u32 val; -- cgit v0.10.2 From 573dd788ccd919f90c78f971c0da124ffa4b8bff Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 29 Jul 2009 00:20:11 +0000 Subject: bnx2x: Version 1.48.114-1 Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 4245412..2d035d7 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -56,8 +56,8 @@ #include "bnx2x_init_ops.h" #include "bnx2x_dump.h" -#define DRV_MODULE_VERSION "1.48.113-1" -#define DRV_MODULE_RELDATE "2009/07/21" +#define DRV_MODULE_VERSION "1.48.114-1" +#define DRV_MODULE_RELDATE "2009/07/29" #define BNX2X_BC_VER 0x040200 #include -- cgit v0.10.2 From b4076d1715b8a38138db0805a85932b3b650d583 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 30 Jul 2009 13:16:45 -0700 Subject: vlan: allow creating vlan when real device is not up There is no reason for the arbitrary restriction that device must be up to create a vlan. This patch was added to Vyatta kernel to resolve startup ordering issues where vlan's are created but real device was disabled. Note: the vlan already correctly inherits the operstate from real device; so if vlan is created and real device is marked down, the vlan is marked down. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 6d37b7e..a1f1630 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -225,12 +225,6 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) return -EOPNOTSUPP; } - /* The real device must be up and operating in order to - * assosciate a VLAN device with it. - */ - if (!(real_dev->flags & IFF_UP)) - return -ENETDOWN; - if (__find_vlan_dev(real_dev, vlan_id) != NULL) return -EEXIST; -- cgit v0.10.2 From 9aada7ac047f789ffb27540cc1695989897b2dfe Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Thu, 30 Jul 2009 14:29:44 -0700 Subject: IPVS: use pr_fmt While being at it cleanup whitespace. Signed-off-by: Hannes Eder Signed-off-by: David S. Miller diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index bbae1e8..9108203 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -99,47 +99,47 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len, return &buf[*idx - len]; } -#define IP_VS_DBG_BUF(level, msg...) \ - do { \ - char ip_vs_dbg_buf[160]; \ - int ip_vs_dbg_idx = 0; \ - if (level <= ip_vs_get_debug_level()) \ - printk(KERN_DEBUG "IPVS: " msg); \ - } while (0) -#define IP_VS_ERR_BUF(msg...) \ - do { \ - char ip_vs_dbg_buf[160]; \ - int ip_vs_dbg_idx = 0; \ - printk(KERN_ERR "IPVS: " msg); \ - } while (0) +#define IP_VS_DBG_BUF(level, msg, ...) \ + do { \ + char ip_vs_dbg_buf[160]; \ + int ip_vs_dbg_idx = 0; \ + if (level <= ip_vs_get_debug_level()) \ + printk(KERN_DEBUG pr_fmt(msg), ##__VA_ARGS__); \ + } while (0) +#define IP_VS_ERR_BUF(msg...) \ + do { \ + char ip_vs_dbg_buf[160]; \ + int ip_vs_dbg_idx = 0; \ + pr_err(msg); \ + } while (0) /* Only use from within IP_VS_DBG_BUF() or IP_VS_ERR_BUF macros */ -#define IP_VS_DBG_ADDR(af, addr) \ - ip_vs_dbg_addr(af, ip_vs_dbg_buf, \ - sizeof(ip_vs_dbg_buf), addr, \ - &ip_vs_dbg_idx) - -#define IP_VS_DBG(level, msg...) \ - do { \ - if (level <= ip_vs_get_debug_level()) \ - printk(KERN_DEBUG "IPVS: " msg); \ - } while (0) -#define IP_VS_DBG_RL(msg...) \ - do { \ - if (net_ratelimit()) \ - printk(KERN_DEBUG "IPVS: " msg); \ - } while (0) -#define IP_VS_DBG_PKT(level, pp, skb, ofs, msg) \ - do { \ - if (level <= ip_vs_get_debug_level()) \ - pp->debug_packet(pp, skb, ofs, msg); \ - } while (0) -#define IP_VS_DBG_RL_PKT(level, pp, skb, ofs, msg) \ - do { \ - if (level <= ip_vs_get_debug_level() && \ - net_ratelimit()) \ - pp->debug_packet(pp, skb, ofs, msg); \ - } while (0) +#define IP_VS_DBG_ADDR(af, addr) \ + ip_vs_dbg_addr(af, ip_vs_dbg_buf, \ + sizeof(ip_vs_dbg_buf), addr, \ + &ip_vs_dbg_idx) + +#define IP_VS_DBG(level, msg, ...) \ + do { \ + if (level <= ip_vs_get_debug_level()) \ + printk(KERN_DEBUG pr_fmt(msg), ##__VA_ARGS__); \ + } while (0) +#define IP_VS_DBG_RL(msg, ...) \ + do { \ + if (net_ratelimit()) \ + printk(KERN_DEBUG pr_fmt(msg), ##__VA_ARGS__); \ + } while (0) +#define IP_VS_DBG_PKT(level, pp, skb, ofs, msg) \ + do { \ + if (level <= ip_vs_get_debug_level()) \ + pp->debug_packet(pp, skb, ofs, msg); \ + } while (0) +#define IP_VS_DBG_RL_PKT(level, pp, skb, ofs, msg) \ + do { \ + if (level <= ip_vs_get_debug_level() && \ + net_ratelimit()) \ + pp->debug_packet(pp, skb, ofs, msg); \ + } while (0) #else /* NO DEBUGGING at ALL */ #define IP_VS_DBG_BUF(level, msg...) do {} while (0) #define IP_VS_ERR_BUF(msg...) do {} while (0) @@ -150,29 +150,30 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len, #endif #define IP_VS_BUG() BUG() -#define IP_VS_ERR(msg...) printk(KERN_ERR "IPVS: " msg) -#define IP_VS_INFO(msg...) printk(KERN_INFO "IPVS: " msg) -#define IP_VS_WARNING(msg...) \ - printk(KERN_WARNING "IPVS: " msg) -#define IP_VS_ERR_RL(msg...) \ - do { \ - if (net_ratelimit()) \ - printk(KERN_ERR "IPVS: " msg); \ - } while (0) +#define IP_VS_ERR(msg...) pr_err(msg) +#define IP_VS_INFO(msg...) pr_info(msg) +#define IP_VS_WARNING(msg...) pr_warning(msg) +#define IP_VS_ERR_RL(msg...) \ + do { \ + if (net_ratelimit()) \ + pr_err(msg); \ + } while (0) #ifdef CONFIG_IP_VS_DEBUG #define EnterFunction(level) \ - do { \ - if (level <= ip_vs_get_debug_level()) \ - printk(KERN_DEBUG "Enter: %s, %s line %i\n", \ - __func__, __FILE__, __LINE__); \ - } while (0) -#define LeaveFunction(level) \ - do { \ - if (level <= ip_vs_get_debug_level()) \ - printk(KERN_DEBUG "Leave: %s, %s line %i\n", \ - __func__, __FILE__, __LINE__); \ - } while (0) + do { \ + if (level <= ip_vs_get_debug_level()) \ + printk(KERN_DEBUG \ + pr_fmt("Enter: %s, %s line %i\n"), \ + __func__, __FILE__, __LINE__); \ + } while (0) +#define LeaveFunction(level) \ + do { \ + if (level <= ip_vs_get_debug_level()) \ + printk(KERN_DEBUG \ + pr_fmt("Leave: %s, %s line %i\n"), \ + __func__, __FILE__, __LINE__); \ + } while (0) #else #define EnterFunction(level) do {} while (0) #define LeaveFunction(level) do {} while (0) diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c index 201b8ea..c1781f8 100644 --- a/net/netfilter/ipvs/ip_vs_app.c +++ b/net/netfilter/ipvs/ip_vs_app.c @@ -18,6 +18,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index 77bfdfe..4173d7b 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -22,6 +22,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 8dddb17..6811dca 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -24,6 +24,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 2d24d81..e6133ea 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -18,6 +18,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c index a9dac74..d0c0594 100644 --- a/net/netfilter/ipvs/ip_vs_dh.c +++ b/net/netfilter/ipvs/ip_vs_dh.c @@ -35,6 +35,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c index 2eb2860..702b53c 100644 --- a/net/netfilter/ipvs/ip_vs_est.c +++ b/net/netfilter/ipvs/ip_vs_est.c @@ -11,6 +11,10 @@ * Changes: * */ + +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 428edbf..9c16a3f 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c @@ -22,6 +22,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c index 3eb5e26..98fb185 100644 --- a/net/netfilter/ipvs/ip_vs_lblc.c +++ b/net/netfilter/ipvs/ip_vs_lblc.c @@ -39,6 +39,9 @@ * me to write this module. */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c index c04ce56..5f5e5f4 100644 --- a/net/netfilter/ipvs/ip_vs_lblcr.c +++ b/net/netfilter/ipvs/ip_vs_lblcr.c @@ -37,6 +37,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_lc.c b/net/netfilter/ipvs/ip_vs_lc.c index d0dadc8..4ecd5e1 100644 --- a/net/netfilter/ipvs/ip_vs_lc.c +++ b/net/netfilter/ipvs/ip_vs_lc.c @@ -14,6 +14,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include diff --git a/net/netfilter/ipvs/ip_vs_nq.c b/net/netfilter/ipvs/ip_vs_nq.c index 694952d..2224478 100644 --- a/net/netfilter/ipvs/ip_vs_nq.c +++ b/net/netfilter/ipvs/ip_vs_nq.c @@ -31,6 +31,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c index a01520e..a95bc40 100644 --- a/net/netfilter/ipvs/ip_vs_proto.c +++ b/net/netfilter/ipvs/ip_vs_proto.c @@ -13,6 +13,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -181,7 +184,7 @@ ip_vs_tcpudp_debug_packet_v4(struct ip_vs_protocol *pp, &ih->daddr, ntohs(pptr[1])); } - printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); + pr_debug("%s: %s\n", msg, buf); } #ifdef CONFIG_IP_VS_IPV6 @@ -215,7 +218,7 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp, &ih->daddr, ntohs(pptr[1])); } - printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); + pr_debug("%s: %s\n", msg, buf); } #endif diff --git a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c index 79f56c1..c30b43c 100644 --- a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c +++ b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c @@ -10,6 +10,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -138,7 +141,7 @@ ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb, sprintf(buf, "%s %pI4->%pI4", pp->name, &ih->saddr, &ih->daddr); - printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); + pr_debug("%s: %s\n", msg, buf); } #ifdef CONFIG_IP_VS_IPV6 @@ -156,7 +159,7 @@ ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb, sprintf(buf, "%s %pI6->%pI6", pp->name, &ih->saddr, &ih->daddr); - printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); + pr_debug("%s: %s\n", msg, buf); } #endif diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index 8cba418..c36c80d 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c @@ -13,6 +13,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include /* for tcphdr */ diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index d2930a7..96ebe40 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c @@ -13,6 +13,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_rr.c b/net/netfilter/ipvs/ip_vs_rr.c index 2d16ab7..b01007e 100644 --- a/net/netfilter/ipvs/ip_vs_rr.c +++ b/net/netfilter/ipvs/ip_vs_rr.c @@ -19,6 +19,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c index a46ad9e..87bc5ea 100644 --- a/net/netfilter/ipvs/ip_vs_sched.c +++ b/net/netfilter/ipvs/ip_vs_sched.c @@ -17,6 +17,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_sed.c b/net/netfilter/ipvs/ip_vs_sed.c index 20e4657..4f745dd 100644 --- a/net/netfilter/ipvs/ip_vs_sed.c +++ b/net/netfilter/ipvs/ip_vs_sed.c @@ -35,6 +35,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c index 75709eb..fb4d2d2 100644 --- a/net/netfilter/ipvs/ip_vs_sh.c +++ b/net/netfilter/ipvs/ip_vs_sh.c @@ -32,6 +32,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 5c48378..cc04c99 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -17,6 +17,9 @@ * Justin Ossevoort : Fix endian problem on sync message size. */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_wlc.c b/net/netfilter/ipvs/ip_vs_wlc.c index 8e94256..bbddfdb 100644 --- a/net/netfilter/ipvs/ip_vs_wlc.c +++ b/net/netfilter/ipvs/ip_vs_wlc.c @@ -19,6 +19,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c index f7d74ef..c39ebb6 100644 --- a/net/netfilter/ipvs/ip_vs_wrr.c +++ b/net/netfilter/ipvs/ip_vs_wrr.c @@ -18,6 +18,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 5874657..061e76d 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -13,6 +13,9 @@ * */ +#define KMSG_COMPONENT "IPVS" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include /* for tcphdr */ #include -- cgit v0.10.2 From a33bc5c15154c835aae26f16e6a3a7d9ad4acb45 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 30 Jul 2009 18:52:15 -0700 Subject: xfrm: select sane defaults for xfrm[4|6] gc_thresh Choose saner defaults for xfrm[4|6] gc_thresh values on init Currently, the xfrm[4|6] code has hard-coded initial gc_thresh values (set to 1024). Given that the ipv4 and ipv6 routing caches are sized dynamically at boot time, the static selections can be non-sensical. This patch dynamically selects an appropriate gc threshold based on the corresponding main routing table size, using the assumption that we should in the worst case be able to handle as many connections as the routing table can. For ipv4, the maximum route cache size is 16 * the number of hash buckets in the route cache. Given that xfrm4 starts garbage collection at the gc_thresh and prevents new allocations at 2 * gc_thresh, we set gc_thresh to half the maximum route cache size. For ipv6, its a bit trickier. there is no maximum route cache size, but the ipv6 dst_ops gc_thresh is statically set to 1024. It seems sane to select a simmilar gc_thresh for the xfrm6 code that is half the number of hash buckets in the v6 route cache times 16 (like the v4 code does). Signed-off-by: Neil Horman Signed-off-by: David S. Miller diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 7c5c0f7..15b492a 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -22,6 +22,12 @@ #include #include +#ifdef CONFIG_IPV6_MULTIPLE_TABLES +#define FIB6_TABLE_HASHSZ 256 +#else +#define FIB6_TABLE_HASHSZ 1 +#endif + struct rt6_info; struct fib6_config diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 9e3a3f4..223e90a 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1280,7 +1280,7 @@ struct xfrm6_tunnel { }; extern void xfrm_init(void); -extern void xfrm4_init(void); +extern void xfrm4_init(int rt_hash_size); extern int xfrm_state_init(struct net *net); extern void xfrm_state_fini(struct net *net); extern void xfrm4_state_init(void); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 278f46f..fafbe16 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -3442,7 +3442,7 @@ int __init ip_rt_init(void) printk(KERN_ERR "Unable to create route proc files\n"); #ifdef CONFIG_XFRM xfrm_init(); - xfrm4_init(); + xfrm4_init(ip_rt_max_size); #endif rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 26496ba..1ba4474 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -290,10 +290,21 @@ static void __exit xfrm4_policy_fini(void) xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo); } -void __init xfrm4_init(void) +void __init xfrm4_init(int rt_max_size) { xfrm4_state_init(); xfrm4_policy_init(); + /* + * Select a default value for the gc_thresh based on the main route + * table hash size. It seems to me the worst case scenario is when + * we have ipsec operating in transport mode, in which we create a + * dst_entry per socket. The xfrm gc algorithm starts trying to remove + * entries at gc_thresh, and prevents new allocations as 2*gc_thresh + * so lets set an initial xfrm gc_thresh value at the rt_max_size/2. + * That will let us store an ipsec connection per route table entry, + * and start cleaning when were 1/2 full + */ + xfrm4_dst_ops.gc_thresh = rt_max_size/2; sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv4_ctl_path, xfrm4_policy_table); } diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 52ee1dc..0e93ca5 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -164,12 +164,6 @@ static __inline__ void rt6_release(struct rt6_info *rt) dst_free(&rt->u.dst); } -#ifdef CONFIG_IPV6_MULTIPLE_TABLES -#define FIB_TABLE_HASHSZ 256 -#else -#define FIB_TABLE_HASHSZ 1 -#endif - static void fib6_link_table(struct net *net, struct fib6_table *tb) { unsigned int h; @@ -180,7 +174,7 @@ static void fib6_link_table(struct net *net, struct fib6_table *tb) */ rwlock_init(&tb->tb6_lock); - h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1); + h = tb->tb6_id & (FIB6_TABLE_HASHSZ - 1); /* * No protection necessary, this is the only list mutatation @@ -231,7 +225,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id) if (id == 0) id = RT6_TABLE_MAIN; - h = id & (FIB_TABLE_HASHSZ - 1); + h = id & (FIB6_TABLE_HASHSZ - 1); rcu_read_lock(); head = &net->ipv6.fib_table_hash[h]; hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) { @@ -382,7 +376,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) arg.net = net; w->args = &arg; - for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { + for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { e = 0; head = &net->ipv6.fib_table_hash[h]; hlist_for_each_entry(tb, node, head, tb6_hlist) { @@ -1368,7 +1362,7 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), unsigned int h; rcu_read_lock(); - for (h = 0; h < FIB_TABLE_HASHSZ; h++) { + for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { head = &net->ipv6.fib_table_hash[h]; hlist_for_each_entry_rcu(table, node, head, tb6_hlist) { write_lock_bh(&table->tb6_lock); @@ -1483,7 +1477,7 @@ static int fib6_net_init(struct net *net) if (!net->ipv6.rt6_stats) goto out_timer; - net->ipv6.fib_table_hash = kcalloc(FIB_TABLE_HASHSZ, + net->ipv6.fib_table_hash = kcalloc(FIB6_TABLE_HASHSZ, sizeof(*net->ipv6.fib_table_hash), GFP_KERNEL); if (!net->ipv6.fib_table_hash) diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 4acc308..611cffc 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -323,6 +323,7 @@ static struct ctl_table_header *sysctl_hdr; int __init xfrm6_init(void) { int ret; + unsigned int gc_thresh; ret = xfrm6_policy_init(); if (ret) @@ -331,6 +332,20 @@ int __init xfrm6_init(void) ret = xfrm6_state_init(); if (ret) goto out_policy; + /* + * We need a good default value for the xfrm6 gc threshold. + * In ipv4 we set it to the route hash table size * 8, which + * is half the size of the maximaum route cache for ipv4. It + * would be good to do the same thing for v6, except the table is + * constructed differently here. Here each table for a net namespace + * can have FIB_TABLE_HASHSZ entries, so lets go with the same + * computation that we used for ipv4 here. Also, lets keep the initial + * gc_thresh to a minimum of 1024, since, the ipv6 route cache defaults + * to that as a minimum as well + */ + gc_thresh = FIB6_TABLE_HASHSZ * 8; + xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh; + sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv6_ctl_path, xfrm6_policy_table); out: -- cgit v0.10.2 From 77ee09c67e051a5ebd19a53ba3945dbdc8d21b3c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 31 Jul 2009 18:26:51 +0100 Subject: ASoC: Allow CODECs to flag invalid registers This helps CODECs with sparse register maps work better with the register cache display interface. Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 756fb59..55b3309 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -385,6 +385,7 @@ struct snd_soc_codec { int (*display_register)(struct snd_soc_codec *, char *, size_t, unsigned int); int (*volatile_register)(unsigned int); + int (*readable_register)(unsigned int); hw_write_t hw_write; hw_read_t hw_read; void *reg_cache; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5eabb71..fb8d7a7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1156,6 +1156,9 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) count += sprintf(buf, "%s registers\n", codec->name); for (i = 0; i < codec->reg_cache_size; i += step) { + if (codec->readable_register && !codec->readable_register(i)) + continue; + count += sprintf(buf + count, "%2x: ", i); if (count >= PAGE_SIZE - 1) break; -- cgit v0.10.2 From b8e22c1fe375a8c3b3e4fd7c569cb8932607bef3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 31 Jul 2009 21:15:25 +0200 Subject: ASoC: jack: Fix race in snd_soc_jack_add_gpios The irq can fire as soon as it has been requested, thus all fields accessed from within the irq handler must be initialized prior to requesting the irq. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 4aa7d8f..1d455ab 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -221,6 +221,9 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, if (ret) goto err; + INIT_WORK(&gpios[i].work, gpio_work); + gpios[i].jack = jack; + ret = request_irq(gpio_to_irq(gpios[i].gpio), gpio_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, @@ -234,9 +237,6 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, gpio_export(gpios[i].gpio, false); #endif - INIT_WORK(&gpios[i].work, gpio_work); - gpios[i].jack = jack; - /* Update initial jack status */ snd_soc_jack_gpio_detect(&gpios[i]); } -- cgit v0.10.2 From 78ed73e84d132e2d556eda90e5b76620f4390ff2 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 22 Jul 2009 05:22:37 +0200 Subject: TTY: Add definition of a new line discipline required by Amstrad E3 (Delta) ASoC driver This patch adds new line discipline name an number to include/linux/tty.h. The line discipline will be used by the Amstrad E3 (Delta) sound driver that will come next in this series of patches. Created against linux-2.6.31-rc3. Applies to linux-omap-2.6 commit 7c5cb7862d32cb344be7831d466535d5255e35ac as well. Signed-off-by: Janusz Krzysztofik Acked-by: Alan Cox Signed-off-by: Mark Brown diff --git a/include/linux/tty.h b/include/linux/tty.h index 1488d8c..26af981 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -23,7 +23,7 @@ */ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ -#define NR_LDISCS 19 +#define NR_LDISCS 20 /* line disciplines */ #define N_TTY 0 @@ -47,6 +47,8 @@ #define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */ #define N_PPS 18 /* Pulse per Second */ +#define N_AMSDELTA 19 /* codec control over modem, board specific */ + /* * This character is the same as _POSIX_VDISABLE: it cannot be used as * a c_cc[] character, but indicates that a particular special character -- cgit v0.10.2 From ad120dae127f5cb14b4c4ed0b98313fb13b9c846 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 29 Jul 2009 12:24:46 +0200 Subject: ASoC: CX20442: push down machine independent line discipline bits This corrected patch adds machine independent line discipline code, prevoiusly exsiting inside my Amstrad Delta ASoC machine dirver, to the Conexant CX20442 codec driver. The code can be used as a standalone line discipline, or as a set of codec specific functions called from machine's line discipline callbacks. Anyway, the line discipline itself must be registered by a machine driver. Applies on top of the followup to my initial driver version: http://mailman.alsa-project.org/pipermail/alsa-devel/2009-July/019757.html Suggested by ASoC manintainer Mark Brown Signed-off-by: Janusz Krzysztofik Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 7bbb77b..f332455 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -13,6 +13,8 @@ * option) any later version. */ +#include + #include #include #include @@ -172,8 +174,7 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, return -EINVAL; /* hw_write and control_data pointers required for talking to the modem - * are expected to be set by the machine driver's line discipline - * initialization code */ + * are expected to be set by the line discipline initialization code */ if (!codec->hw_write || !codec->control_data) return -EIO; @@ -208,6 +209,111 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, return 0; } + +/* Moved up here as line discipline referres it during initialization */ +static struct snd_soc_codec *cx20442_codec; + + +/* + * Line discpline related code + * + * Any of the callback functions below can be used in two ways: + * 1) registerd by a machine driver as one of line discipline operations, + * 2) called from a machine's provided line discipline callback function + * in case when extra machine specific code must be run as well. + */ + +/* Modem init: echo off, digital speaker off, quiet off, voice mode */ +static const char *v253_init = "ate0m0q0+fclass=8\r"; + +/* Line discipline .open() */ +static int v253_open(struct tty_struct *tty) +{ + struct snd_soc_codec *codec = cx20442_codec; + int ret, len = strlen(v253_init); + + /* Doesn't make sense without write callback */ + if (!tty->ops->write) + return -EINVAL; + + /* Pass the codec structure address for use by other ldisc callbacks */ + tty->disc_data = codec; + + if (tty->ops->write(tty, v253_init, len) != len) { + ret = -EIO; + goto err; + } + /* Actual setup will be performed after the modem responds. */ + return 0; +err: + tty->disc_data = NULL; + return ret; +} + +/* Line discipline .close() */ +static void v253_close(struct tty_struct *tty) +{ + struct snd_soc_codec *codec = tty->disc_data; + + tty->disc_data = NULL; + + if (!codec) + return; + + /* Prevent the codec driver from further accessing the modem */ + codec->hw_write = NULL; + codec->control_data = NULL; + codec->pop_time = 0; +} + +/* Line discipline .hangup() */ +static int v253_hangup(struct tty_struct *tty) +{ + v253_close(tty); + return 0; +} + +/* Line discipline .receive_buf() */ +static void v253_receive(struct tty_struct *tty, + const unsigned char *cp, char *fp, int count) +{ + struct snd_soc_codec *codec = tty->disc_data; + + if (!codec) + return; + + if (!codec->control_data) { + /* First modem response, complete setup procedure */ + + /* Set up codec driver access to modem controls */ + codec->control_data = tty; + codec->hw_write = (hw_write_t)tty->ops->write; + codec->pop_time = 1; + } +} + +/* Line discipline .write_wakeup() */ +static void v253_wakeup(struct tty_struct *tty) +{ +} + +struct tty_ldisc_ops v253_ops = { + .magic = TTY_LDISC_MAGIC, + .name = "cx20442", + .owner = THIS_MODULE, + .open = v253_open, + .close = v253_close, + .hangup = v253_hangup, + .receive_buf = v253_receive, + .write_wakeup = v253_wakeup, +}; +EXPORT_SYMBOL_GPL(v253_ops); + + +/* + * Codec DAI + */ + struct snd_soc_dai cx20442_dai = { .name = "CX20442", .playback = { @@ -227,8 +333,6 @@ struct snd_soc_dai cx20442_dai = { }; EXPORT_SYMBOL_GPL(cx20442_dai); -static struct snd_soc_codec *cx20442_codec; - static int cx20442_codec_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); @@ -313,13 +417,13 @@ static int cx20442_register(struct cx20442_priv *cx20442) ret = snd_soc_register_codec(codec); if (ret != 0) { - dev_err(&codec->dev, "Failed to register codec: %d\n", ret); + dev_err(codec->dev, "Failed to register codec: %d\n", ret); goto err; } ret = snd_soc_register_dai(&cx20442_dai); if (ret != 0) { - dev_err(&codec->dev, "Failed to register DAI: %d\n", ret); + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); goto err_codec; } diff --git a/sound/soc/codecs/cx20442.h b/sound/soc/codecs/cx20442.h index d0a4f29..688a5eb 100644 --- a/sound/soc/codecs/cx20442.h +++ b/sound/soc/codecs/cx20442.h @@ -15,5 +15,6 @@ extern struct snd_soc_dai cx20442_dai; extern struct snd_soc_codec_device cx20442_codec_dev; +extern struct tty_ldisc_ops v253_ops; #endif -- cgit v0.10.2 From 6d7f68a1eab3d5b3c0a6a5cf9434c77cd3a8c6ac Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 29 Jul 2009 13:18:53 +0200 Subject: ASoC: add support for Amstrad E3 (Delta) machine This patch adds machine support for Amstrad E3 (Delta) videophone to ASoC. Created and tested against linux-2.6.31-rc3. Applies and works with linux-omap-2.6 commit 7c5cb7862d32cb344be7831d466535d5255e35ac as well. Depends on: 1) latest version of the CX20442 codec driver that exposes v253_ops structure[1], 2) patch 2/3 form this series: TTY: Add definition of a new line discipline required by Amstrad E3 (Delta) ASoC driver[2]. CPU DAI parameters best matching the codec DAI has been selected out empirically for best user experience. Board specific audio function control (with related DAPM widgets) has been modeled after empirically discovered codec capabilities. Unlike other ASoC machine drivers, this one makes use of a codec provided line discipline that is required for talking to a modem chip that can control the codec behavoiur. As the line discipline operations must call board specific bits as well, the machine driver registers its own line discipline ops, not the codec provided, and then calls those codec provided from inside its own callbacks. If some kind of a glue, like a bus over a tty, exsited that could help in runtime detection of a modem (bus adapter) over a more generic line discipline (bus driver)[3], the line discipline code could be probably designed in a more generic way. In order to work at all, this driver requires a working McBSP1. On OMAP1510 based machines (not sure if other OMAP1 variants as well), where McBSP1 is a DSP public peripheral, that means the kernel must provide basic DSP support, ie. omap_dsp_init(), in order to power up the DSP. This used to be included in linux-omap-2.6 tree up to commit 2512fd29db4eb09e82d182596304c7aaf76d2c5c. Without that, the driver would not work, ie. not shift in/out any bits over the CPU DAI[4]. This limitation is not board, but CPU specific, and may apply to other code that makes use of McBSP1/McBSP3 on affected machines. I provide an extra patch (4/3) as a temporary solution. To work correctly in playback mode, this driver requires my prevoiusly submitted patch that corrects pcm pointer calculation for OMAP1510 based machines[5] (already included in linux-2.6.31-rc3). To support codec controls, this driver requires my previously submitted patch that adds support for modem found on Amstrad Delta[6]. [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2009-July/019780.html [2] http://www.spinics.net/lists/linux-serial/msg01862.html [3] http://www.spinics.net/lists/linux-serial/msg01856.html [4] http://www.spinics.net/lists/linux-omap/msg15114.html [5] http://mailman.alsa-project.org/pipermail/alsa-devel/2009-June/018950.html [6] http://www.spinics.net/lists/linux-omap/msg15432.html Credits to: Mark Underwood - for his initial, omap-alsa based sound driver for this machine, Mark Brown - for his help, patience and excellent subsytem maintainer support. Signed-off-by: Janusz Krzysztofik Signed-off-by: Mark Brown diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index a5a90e5..2dee983 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -15,6 +15,14 @@ config SND_OMAP_SOC_N810 help Say Y if you want to add support for SoC audio on Nokia N810. +config SND_OMAP_SOC_AMS_DELTA + tristate "SoC Audio support for Amstrad E3 (Delta) videophone" + depends on SND_OMAP_SOC && MACH_AMS_DELTA + select SND_OMAP_SOC_MCBSP + select SND_SOC_CX20442 + help + Say Y if you want to add support for SoC audio on Amstrad Delta. + config SND_OMAP_SOC_OSK5912 tristate "SoC Audio support for omap osk5912" depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index fefc48f..02d6947 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o # OMAP Machine Support snd-soc-n810-objs := n810.o +snd-soc-ams-delta-objs := ams-delta.o snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o snd-soc-omap2evm-objs := omap2evm.o @@ -17,6 +18,7 @@ snd-soc-omap3beagle-objs := omap3beagle.o snd-soc-zoom2-objs := zoom2.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o +obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c new file mode 100644 index 0000000..4f35b1f --- /dev/null +++ b/sound/soc/omap/ams-delta.c @@ -0,0 +1,646 @@ +/* + * ams-delta.c -- SoC audio for Amstrad E3 (Delta) videophone + * + * Copyright (C) 2009 Janusz Krzysztofik + * + * Initially based on sound/soc/omap/osk5912.x + * Copyright (C) 2008 Mistral Solutions + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/cx20442.h" + + +/* Board specific DAPM widgets */ + const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = { + /* Handset */ + SND_SOC_DAPM_MIC("Mouthpiece", NULL), + SND_SOC_DAPM_HP("Earpiece", NULL), + /* Handsfree/Speakerphone */ + SND_SOC_DAPM_MIC("Microphone", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +/* How they are connected to codec pins */ +static const struct snd_soc_dapm_route ams_delta_audio_map[] = { + {"TELIN", NULL, "Mouthpiece"}, + {"Earpiece", NULL, "TELOUT"}, + + {"MIC", NULL, "Microphone"}, + {"Speaker", NULL, "SPKOUT"}, +}; + +/* + * Controls, functional after the modem line discipline is activated. + */ + +/* Virtual switch: audio input/output constellations */ +static const char *ams_delta_audio_mode[] = + {"Mixed", "Handset", "Handsfree", "Speakerphone"}; + +/* Selection <-> pin translation */ +#define AMS_DELTA_MOUTHPIECE 0 +#define AMS_DELTA_EARPIECE 1 +#define AMS_DELTA_MICROPHONE 2 +#define AMS_DELTA_SPEAKER 3 +#define AMS_DELTA_AGC 4 + +#define AMS_DELTA_MIXED ((1 << AMS_DELTA_EARPIECE) | \ + (1 << AMS_DELTA_MICROPHONE)) +#define AMS_DELTA_HANDSET ((1 << AMS_DELTA_MOUTHPIECE) | \ + (1 << AMS_DELTA_EARPIECE)) +#define AMS_DELTA_HANDSFREE ((1 << AMS_DELTA_MICROPHONE) | \ + (1 << AMS_DELTA_SPEAKER)) +#define AMS_DELTA_SPEAKERPHONE (AMS_DELTA_HANDSFREE | (1 << AMS_DELTA_AGC)) + +unsigned short ams_delta_audio_mode_pins[] = { + AMS_DELTA_MIXED, + AMS_DELTA_HANDSET, + AMS_DELTA_HANDSFREE, + AMS_DELTA_SPEAKERPHONE, +}; + +static unsigned short ams_delta_audio_agc; + +static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_enum *control = (struct soc_enum *)kcontrol->private_value; + unsigned short pins; + int pin, changed = 0; + + /* Refuse any mode changes if we are not able to control the codec. */ + if (!codec->control_data) + return -EUNATCH; + + if (ucontrol->value.enumerated.item[0] >= control->max) + return -EINVAL; + + mutex_lock(&codec->mutex); + + /* Translate selection to bitmap */ + pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]]; + + /* Setup pins after corresponding bits if changed */ + pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE)); + if (pin != snd_soc_dapm_get_pin_status(codec, "Mouthpiece")) { + changed = 1; + if (pin) + snd_soc_dapm_enable_pin(codec, "Mouthpiece"); + else + snd_soc_dapm_disable_pin(codec, "Mouthpiece"); + } + pin = !!(pins & (1 << AMS_DELTA_EARPIECE)); + if (pin != snd_soc_dapm_get_pin_status(codec, "Earpiece")) { + changed = 1; + if (pin) + snd_soc_dapm_enable_pin(codec, "Earpiece"); + else + snd_soc_dapm_disable_pin(codec, "Earpiece"); + } + pin = !!(pins & (1 << AMS_DELTA_MICROPHONE)); + if (pin != snd_soc_dapm_get_pin_status(codec, "Microphone")) { + changed = 1; + if (pin) + snd_soc_dapm_enable_pin(codec, "Microphone"); + else + snd_soc_dapm_disable_pin(codec, "Microphone"); + } + pin = !!(pins & (1 << AMS_DELTA_SPEAKER)); + if (pin != snd_soc_dapm_get_pin_status(codec, "Speaker")) { + changed = 1; + if (pin) + snd_soc_dapm_enable_pin(codec, "Speaker"); + else + snd_soc_dapm_disable_pin(codec, "Speaker"); + } + pin = !!(pins & (1 << AMS_DELTA_AGC)); + if (pin != ams_delta_audio_agc) { + ams_delta_audio_agc = pin; + changed = 1; + if (pin) + snd_soc_dapm_enable_pin(codec, "AGCIN"); + else + snd_soc_dapm_disable_pin(codec, "AGCIN"); + } + if (changed) + snd_soc_dapm_sync(codec); + + mutex_unlock(&codec->mutex); + + return changed; +} + +static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned short pins, mode; + + pins = ((snd_soc_dapm_get_pin_status(codec, "Mouthpiece") << + AMS_DELTA_MOUTHPIECE) | + (snd_soc_dapm_get_pin_status(codec, "Earpiece") << + AMS_DELTA_EARPIECE)); + if (pins) + pins |= (snd_soc_dapm_get_pin_status(codec, "Microphone") << + AMS_DELTA_MICROPHONE); + else + pins = ((snd_soc_dapm_get_pin_status(codec, "Microphone") << + AMS_DELTA_MICROPHONE) | + (snd_soc_dapm_get_pin_status(codec, "Speaker") << + AMS_DELTA_SPEAKER) | + (ams_delta_audio_agc << AMS_DELTA_AGC)); + + for (mode = 0; mode < ARRAY_SIZE(ams_delta_audio_mode); mode++) + if (pins == ams_delta_audio_mode_pins[mode]) + break; + + if (mode >= ARRAY_SIZE(ams_delta_audio_mode)) + return -EINVAL; + + ucontrol->value.enumerated.item[0] = mode; + + return 0; +} + +static const struct soc_enum ams_delta_audio_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ams_delta_audio_mode), + ams_delta_audio_mode), +}; + +static const struct snd_kcontrol_new ams_delta_audio_controls[] = { + SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum[0], + ams_delta_get_audio_mode, ams_delta_set_audio_mode), +}; + +/* Hook switch */ +static struct snd_soc_jack ams_delta_hook_switch; +static struct snd_soc_jack_gpio ams_delta_hook_switch_gpios[] = { + { + .gpio = 4, + .name = "hook_switch", + .report = SND_JACK_HEADSET, + .invert = 1, + .debounce_time = 150, + } +}; + +/* After we are able to control the codec over the modem, + * the hook switch can be used for dynamic DAPM reconfiguration. */ +static struct snd_soc_jack_pin ams_delta_hook_switch_pins[] = { + /* Handset */ + { + .pin = "Mouthpiece", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Earpiece", + .mask = SND_JACK_HEADPHONE, + }, + /* Handsfree */ + { + .pin = "Microphone", + .mask = SND_JACK_MICROPHONE, + .invert = 1, + }, + { + .pin = "Speaker", + .mask = SND_JACK_HEADPHONE, + .invert = 1, + }, +}; + + +/* + * Modem line discipline, required for making above controls functional. + * Activated from userspace with ldattach, possibly invoked from udev rule. + */ + +/* To actually apply any modem controlled configuration changes to the codec, + * we must connect codec DAI pins to the modem for a moment. Be carefull not + * to interfere with our digital mute function that shares the same hardware. */ +static struct timer_list cx81801_timer; +static bool cx81801_cmd_pending; +static bool ams_delta_muted; +static DEFINE_SPINLOCK(ams_delta_lock); + +static void cx81801_timeout(unsigned long data) +{ + int muted; + + spin_lock(&ams_delta_lock); + cx81801_cmd_pending = 0; + muted = ams_delta_muted; + spin_unlock(&ams_delta_lock); + + /* Reconnect the codec DAI back from the modem to the CPU DAI + * only if digital mute still off */ + if (!muted) + ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0); +} + +/* Line discipline .open() */ +static int cx81801_open(struct tty_struct *tty) +{ + return v253_ops.open(tty); +} + +/* Line discipline .close() */ +static void cx81801_close(struct tty_struct *tty) +{ + struct snd_soc_codec *codec = tty->disc_data; + + del_timer_sync(&cx81801_timer); + + v253_ops.close(tty); + + /* Prevent the hook switch from further changing the DAPM pins */ + INIT_LIST_HEAD(&ams_delta_hook_switch.pins); + + /* Revert back to default audio input/output constellation */ + snd_soc_dapm_disable_pin(codec, "Mouthpiece"); + snd_soc_dapm_enable_pin(codec, "Earpiece"); + snd_soc_dapm_enable_pin(codec, "Microphone"); + snd_soc_dapm_disable_pin(codec, "Speaker"); + snd_soc_dapm_disable_pin(codec, "AGCIN"); + snd_soc_dapm_sync(codec); +} + +/* Line discipline .hangup() */ +static int cx81801_hangup(struct tty_struct *tty) +{ + cx81801_close(tty); + return 0; +} + +/* Line discipline .recieve_buf() */ +static void cx81801_receive(struct tty_struct *tty, + const unsigned char *cp, char *fp, int count) +{ + struct snd_soc_codec *codec = tty->disc_data; + const unsigned char *c; + int apply, ret; + + if (!codec->control_data) { + /* First modem response, complete setup procedure */ + + /* Initialize timer used for config pulse generation */ + setup_timer(&cx81801_timer, cx81801_timeout, 0); + + v253_ops.receive_buf(tty, cp, fp, count); + + /* Link hook switch to DAPM pins */ + ret = snd_soc_jack_add_pins(&ams_delta_hook_switch, + ARRAY_SIZE(ams_delta_hook_switch_pins), + ams_delta_hook_switch_pins); + if (ret) + dev_warn(codec->socdev->card->dev, + "Failed to link hook switch to DAPM pins, " + "will continue with hook switch unlinked.\n"); + + return; + } + + v253_ops.receive_buf(tty, cp, fp, count); + + for (c = &cp[count - 1]; c >= cp; c--) { + if (*c != '\r') + continue; + /* Complete modem response received, apply config to codec */ + + spin_lock_bh(&ams_delta_lock); + mod_timer(&cx81801_timer, jiffies + msecs_to_jiffies(150)); + apply = !ams_delta_muted && !cx81801_cmd_pending; + cx81801_cmd_pending = 1; + spin_unlock_bh(&ams_delta_lock); + + /* Apply config pulse by connecting the codec to the modem + * if not already done */ + if (apply) + ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, + AMS_DELTA_LATCH2_MODEM_CODEC); + break; + } +} + +/* Line discipline .write_wakeup() */ +static void cx81801_wakeup(struct tty_struct *tty) +{ + v253_ops.write_wakeup(tty); +} + +static struct tty_ldisc_ops cx81801_ops = { + .magic = TTY_LDISC_MAGIC, + .name = "cx81801", + .owner = THIS_MODULE, + .open = cx81801_open, + .close = cx81801_close, + .hangup = cx81801_hangup, + .receive_buf = cx81801_receive, + .write_wakeup = cx81801_wakeup, +}; + + +/* + * Even if not very usefull, the sound card can still work without any of the + * above functonality activated. You can still control its audio input/output + * constellation and speakerphone gain from userspace by issueing AT commands + * over the modem port. + */ + +static int ams_delta_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* Set cpu DAI configuration */ + return snd_soc_dai_set_fmt(rtd->dai->cpu_dai, + SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); +} + +static struct snd_soc_ops ams_delta_ops = { + .hw_params = ams_delta_hw_params, +}; + + +/* Board specific codec bias level control */ +static int ams_delta_set_bias_level(struct snd_soc_card *card, + enum snd_soc_bias_level level) +{ + struct snd_soc_codec *codec = card->codec; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) + ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET, + AMS_DELTA_LATCH2_MODEM_NRESET); + break; + case SND_SOC_BIAS_OFF: + if (codec->bias_level != SND_SOC_BIAS_OFF) + ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET, + 0); + } + codec->bias_level = level; + + return 0; +} + +/* Digital mute implemented using modem/CPU multiplexer. + * Shares hardware with codec config pulse generation */ +static bool ams_delta_muted = 1; + +static int ams_delta_digital_mute(struct snd_soc_dai *dai, int mute) +{ + int apply; + + if (ams_delta_muted == mute) + return 0; + + spin_lock_bh(&ams_delta_lock); + ams_delta_muted = mute; + apply = !cx81801_cmd_pending; + spin_unlock_bh(&ams_delta_lock); + + if (apply) + ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, + mute ? AMS_DELTA_LATCH2_MODEM_CODEC : 0); + return 0; +} + +/* Our codec DAI probably doesn't have its own .ops structure */ +static struct snd_soc_dai_ops ams_delta_dai_ops = { + .digital_mute = ams_delta_digital_mute, +}; + +/* Will be used if the codec ever has its own digital_mute function */ +static int ams_delta_startup(struct snd_pcm_substream *substream) +{ + return ams_delta_digital_mute(NULL, 0); +} + +static void ams_delta_shutdown(struct snd_pcm_substream *substream) +{ + ams_delta_digital_mute(NULL, 1); +} + + +/* + * Card initialization + */ + +static int ams_delta_cx20442_init(struct snd_soc_codec *codec) +{ + struct snd_soc_dai *codec_dai = codec->dai; + struct snd_soc_card *card = codec->socdev->card; + int ret; + /* Codec is ready, now add/activate board specific controls */ + + /* Set up digital mute if not provided by the codec */ + if (!codec_dai->ops) { + codec_dai->ops = &ams_delta_dai_ops; + } else if (!codec_dai->ops->digital_mute) { + codec_dai->ops->digital_mute = ams_delta_digital_mute; + } else { + ams_delta_ops.startup = ams_delta_startup; + ams_delta_ops.shutdown = ams_delta_shutdown; + } + + /* Set codec bias level */ + ams_delta_set_bias_level(card, SND_SOC_BIAS_STANDBY); + + /* Add hook switch - can be used to control the codec from userspace + * even if line discipline fails */ + ret = snd_soc_jack_new(card, "hook_switch", + SND_JACK_HEADSET, &ams_delta_hook_switch); + if (ret) + dev_warn(card->dev, + "Failed to allocate resources for hook switch, " + "will continue without one.\n"); + else { + ret = snd_soc_jack_add_gpios(&ams_delta_hook_switch, + ARRAY_SIZE(ams_delta_hook_switch_gpios), + ams_delta_hook_switch_gpios); + if (ret) + dev_warn(card->dev, + "Failed to set up hook switch GPIO line, " + "will continue with hook switch inactive.\n"); + } + + /* Register optional line discipline for over the modem control */ + ret = tty_register_ldisc(N_AMSDELTA, &cx81801_ops); + if (ret) { + dev_warn(card->dev, + "Failed to register line discipline, " + "will continue without any controls.\n"); + return 0; + } + + /* Add board specific DAPM widgets and routes */ + ret = snd_soc_dapm_new_controls(codec, ams_delta_dapm_widgets, + ARRAY_SIZE(ams_delta_dapm_widgets)); + if (ret) { + dev_warn(card->dev, + "Failed to register DAPM controls, " + "will continue without any.\n"); + return 0; + } + + ret = snd_soc_dapm_add_routes(codec, ams_delta_audio_map, + ARRAY_SIZE(ams_delta_audio_map)); + if (ret) { + dev_warn(card->dev, + "Failed to set up DAPM routes, " + "will continue with codec default map.\n"); + return 0; + } + + /* Set up initial pin constellation */ + snd_soc_dapm_disable_pin(codec, "Mouthpiece"); + snd_soc_dapm_enable_pin(codec, "Earpiece"); + snd_soc_dapm_enable_pin(codec, "Microphone"); + snd_soc_dapm_disable_pin(codec, "Speaker"); + snd_soc_dapm_disable_pin(codec, "AGCIN"); + snd_soc_dapm_disable_pin(codec, "AGCOUT"); + snd_soc_dapm_sync(codec); + + /* Add virtual switch */ + ret = snd_soc_add_controls(codec, ams_delta_audio_controls, + ARRAY_SIZE(ams_delta_audio_controls)); + if (ret) + dev_warn(card->dev, + "Failed to register audio mode control, " + "will continue without it.\n"); + + return 0; +} + +/* DAI glue - connects codec <--> CPU */ +static struct snd_soc_dai_link ams_delta_dai_link = { + .name = "CX20442", + .stream_name = "CX20442", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &cx20442_dai, + .init = ams_delta_cx20442_init, + .ops = &ams_delta_ops, +}; + +/* Audio card driver */ +static struct snd_soc_card ams_delta_audio_card = { + .name = "AMS_DELTA", + .platform = &omap_soc_platform, + .dai_link = &ams_delta_dai_link, + .num_links = 1, + .set_bias_level = ams_delta_set_bias_level, +}; + +/* Audio subsystem */ +static struct snd_soc_device ams_delta_snd_soc_device = { + .card = &ams_delta_audio_card, + .codec_dev = &cx20442_codec_dev, +}; + +/* Module init/exit */ +static struct platform_device *ams_delta_audio_platform_device; +static struct platform_device *cx20442_platform_device; + +static int __init ams_delta_module_init(void) +{ + int ret; + + if (!(machine_is_ams_delta())) + return -ENODEV; + + ams_delta_audio_platform_device = + platform_device_alloc("soc-audio", -1); + if (!ams_delta_audio_platform_device) + return -ENOMEM; + + platform_set_drvdata(ams_delta_audio_platform_device, + &ams_delta_snd_soc_device); + ams_delta_snd_soc_device.dev = &ams_delta_audio_platform_device->dev; + *(unsigned int *)ams_delta_dai_link.cpu_dai->private_data = OMAP_MCBSP1; + + ret = platform_device_add(ams_delta_audio_platform_device); + if (ret) + goto err; + + /* + * Codec platform device could be registered from elsewhere (board?), + * but I do it here as it makes sense only if used with the card. + */ + cx20442_platform_device = platform_device_register_simple("cx20442", + -1, NULL, 0); + return 0; +err: + platform_device_put(ams_delta_audio_platform_device); + return ret; +} +module_init(ams_delta_module_init); + +static void __exit ams_delta_module_exit(void) +{ + struct snd_soc_codec *codec; + struct tty_struct *tty; + + if (ams_delta_audio_card.codec) { + codec = ams_delta_audio_card.codec; + + if (codec->control_data) { + tty = codec->control_data; + + tty_hangup(tty); + } + } + + if (tty_unregister_ldisc(N_AMSDELTA) != 0) + dev_warn(&ams_delta_audio_platform_device->dev, + "failed to unregister AMSDELTA line discipline\n"); + + snd_soc_jack_free_gpios(&ams_delta_hook_switch, + ARRAY_SIZE(ams_delta_hook_switch_gpios), + ams_delta_hook_switch_gpios); + + /* Keep modem power on */ + ams_delta_set_bias_level(&ams_delta_audio_card, SND_SOC_BIAS_STANDBY); + + platform_device_unregister(cx20442_platform_device); + platform_device_unregister(ams_delta_audio_platform_device); +} +module_exit(ams_delta_module_exit); + +MODULE_AUTHOR("Janusz Krzysztofik "); +MODULE_DESCRIPTION("ALSA SoC driver for Amstrad E3 (Delta) videophone"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 8788fdc2a53cf012a43808877eaa6ac7e3c923b4 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 27 Jul 2009 22:52:03 +0000 Subject: be2net: get rid of be_ctrl_info struct/abstraction Currently only the be_ctrl_info struct ptr (instead of adapter) is passed to all the routines in be_cmds.c. Instead pass be_adapter ptr to allow access to all its fields. Merge the contents of struct be_ctrl_info into be_adapter. The resulting code is simpler. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 41cddbe..d8a157f 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -71,6 +71,8 @@ static inline char *nic_name(struct pci_dev *pdev) #define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST) +#define FW_VER_LEN 32 + struct be_dma_mem { void *va; dma_addr_t dma; @@ -123,7 +125,6 @@ static inline void queue_tail_inc(struct be_queue_info *q) index_inc(&q->tail, q->len); } - struct be_eq_obj { struct be_queue_info q; char desc[32]; @@ -142,31 +143,6 @@ struct be_mcc_obj { struct be_queue_info cq; }; -struct be_ctrl_info { - u8 __iomem *csr; - u8 __iomem *db; /* Door Bell */ - u8 __iomem *pcicfg; /* PCI config space */ - int pci_func; - - /* Mbox used for cmd request/response */ - spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */ - struct be_dma_mem mbox_mem; - /* Mbox mem is adjusted to align to 16 bytes. The allocated addr - * is stored for freeing purpose */ - struct be_dma_mem mbox_mem_alloced; - - /* MCC Rings */ - struct be_mcc_obj mcc_obj; - spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ - spinlock_t mcc_cq_lock; - - /* MCC Async callback */ - void (*async_cb)(void *adapter, bool link_up); - void *adapter_ctxt; -}; - -#include "be_cmds.h" - struct be_drvr_stats { u32 be_tx_reqs; /* number of TX requests initiated */ u32 be_tx_stops; /* number of times TX Q was stopped */ @@ -234,8 +210,20 @@ struct be_adapter { struct pci_dev *pdev; struct net_device *netdev; - /* Mbox, pci config, csr address information */ - struct be_ctrl_info ctrl; + u8 __iomem *csr; + u8 __iomem *db; /* Door Bell */ + u8 __iomem *pcicfg; /* PCI config space */ + int pci_func; + + spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */ + struct be_dma_mem mbox_mem; + /* Mbox mem is adjusted to align to 16 bytes. The allocated addr + * is stored for freeing purpose */ + struct be_dma_mem mbox_mem_alloced; + + struct be_mcc_obj mcc_obj; + spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ + spinlock_t mcc_cq_lock; struct msix_entry msix_entries[BE_NUM_MSIX_VECTORS]; bool msix_enabled; @@ -366,6 +354,7 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) return val; } -extern void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm, +extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); +extern void be_link_status_update(struct be_adapter *adapter, bool link_up); #endif /* BE_H */ diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 583517ed..20278b9 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -16,15 +16,16 @@ */ #include "be.h" +#include "be_cmds.h" -static void be_mcc_notify(struct be_ctrl_info *ctrl) +static void be_mcc_notify(struct be_adapter *adapter) { - struct be_queue_info *mccq = &ctrl->mcc_obj.q; + struct be_queue_info *mccq = &adapter->mcc_obj.q; u32 val = 0; val |= mccq->id & DB_MCCQ_RING_ID_MASK; val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; - iowrite32(val, ctrl->db + DB_MCCQ_OFFSET); + iowrite32(val, adapter->db + DB_MCCQ_OFFSET); } /* To check if valid bit is set, check the entire word as we don't know @@ -47,7 +48,7 @@ static inline void be_mcc_compl_use(struct be_mcc_cq_entry *compl) compl->flags = 0; } -static int be_mcc_compl_process(struct be_ctrl_info *ctrl, +static int be_mcc_compl_process(struct be_adapter *adapter, struct be_mcc_cq_entry *compl) { u16 compl_status, extd_status; @@ -70,11 +71,11 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl, } /* Link state evt is a string of bytes; no need for endian swapping */ -static void be_async_link_state_process(struct be_ctrl_info *ctrl, +static void be_async_link_state_process(struct be_adapter *adapter, struct be_async_event_link_state *evt) { - ctrl->async_cb(ctrl->adapter_ctxt, - evt->port_link_status == ASYNC_EVENT_LINK_UP ? true : false); + be_link_status_update(adapter, + evt->port_link_status == ASYNC_EVENT_LINK_UP); } static inline bool is_link_state_evt(u32 trailer) @@ -84,9 +85,9 @@ static inline bool is_link_state_evt(u32 trailer) ASYNC_EVENT_CODE_LINK_STATE); } -static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_ctrl_info *ctrl) +static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_adapter *adapter) { - struct be_queue_info *mcc_cq = &ctrl->mcc_obj.cq; + struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq; struct be_mcc_cq_entry *compl = queue_tail_node(mcc_cq); if (be_mcc_compl_is_new(compl)) { @@ -96,40 +97,40 @@ static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_ctrl_info *ctrl) return NULL; } -void be_process_mcc(struct be_ctrl_info *ctrl) +void be_process_mcc(struct be_adapter *adapter) { struct be_mcc_cq_entry *compl; int num = 0; - spin_lock_bh(&ctrl->mcc_cq_lock); - while ((compl = be_mcc_compl_get(ctrl))) { + spin_lock_bh(&adapter->mcc_cq_lock); + while ((compl = be_mcc_compl_get(adapter))) { if (compl->flags & CQE_FLAGS_ASYNC_MASK) { /* Interpret flags as an async trailer */ BUG_ON(!is_link_state_evt(compl->flags)); /* Interpret compl as a async link evt */ - be_async_link_state_process(ctrl, + be_async_link_state_process(adapter, (struct be_async_event_link_state *) compl); } else { - be_mcc_compl_process(ctrl, compl); - atomic_dec(&ctrl->mcc_obj.q.used); + be_mcc_compl_process(adapter, compl); + atomic_dec(&adapter->mcc_obj.q.used); } be_mcc_compl_use(compl); num++; } if (num) - be_cq_notify(ctrl, ctrl->mcc_obj.cq.id, true, num); - spin_unlock_bh(&ctrl->mcc_cq_lock); + be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, num); + spin_unlock_bh(&adapter->mcc_cq_lock); } /* Wait till no more pending mcc requests are present */ -static void be_mcc_wait_compl(struct be_ctrl_info *ctrl) +static void be_mcc_wait_compl(struct be_adapter *adapter) { #define mcc_timeout 50000 /* 5s timeout */ int i; for (i = 0; i < mcc_timeout; i++) { - be_process_mcc(ctrl); - if (atomic_read(&ctrl->mcc_obj.q.used) == 0) + be_process_mcc(adapter); + if (atomic_read(&adapter->mcc_obj.q.used) == 0) break; udelay(100); } @@ -138,10 +139,10 @@ static void be_mcc_wait_compl(struct be_ctrl_info *ctrl) } /* Notify MCC requests and wait for completion */ -static void be_mcc_notify_wait(struct be_ctrl_info *ctrl) +static void be_mcc_notify_wait(struct be_adapter *adapter) { - be_mcc_notify(ctrl); - be_mcc_wait_compl(ctrl); + be_mcc_notify(adapter); + be_mcc_wait_compl(adapter); } static int be_mbox_db_ready_wait(void __iomem *db) @@ -173,12 +174,12 @@ static int be_mbox_db_ready_wait(void __iomem *db) * Insert the mailbox address into the doorbell in two steps * Polls on the mbox doorbell till a command completion (or a timeout) occurs */ -static int be_mbox_db_ring(struct be_ctrl_info *ctrl) +static int be_mbox_db_ring(struct be_adapter *adapter) { int status; u32 val = 0; - void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET; - struct be_dma_mem *mbox_mem = &ctrl->mbox_mem; + void __iomem *db = adapter->db + MPU_MAILBOX_DB_OFFSET; + struct be_dma_mem *mbox_mem = &adapter->mbox_mem; struct be_mcc_mailbox *mbox = mbox_mem->va; struct be_mcc_cq_entry *cqe = &mbox->cqe; @@ -208,7 +209,7 @@ static int be_mbox_db_ring(struct be_ctrl_info *ctrl) /* A cq entry has been made now */ if (be_mcc_compl_is_new(cqe)) { - status = be_mcc_compl_process(ctrl, &mbox->cqe); + status = be_mcc_compl_process(adapter, &mbox->cqe); be_mcc_compl_use(cqe); if (status) return status; @@ -219,9 +220,9 @@ static int be_mbox_db_ring(struct be_ctrl_info *ctrl) return 0; } -static int be_POST_stage_get(struct be_ctrl_info *ctrl, u16 *stage) +static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage) { - u32 sem = ioread32(ctrl->csr + MPU_EP_SEMAPHORE_OFFSET); + u32 sem = ioread32(adapter->csr + MPU_EP_SEMAPHORE_OFFSET); *stage = sem & EP_SEMAPHORE_POST_STAGE_MASK; if ((sem >> EP_SEMAPHORE_POST_ERR_SHIFT) & EP_SEMAPHORE_POST_ERR_MASK) @@ -230,11 +231,11 @@ static int be_POST_stage_get(struct be_ctrl_info *ctrl, u16 *stage) return 0; } -static int be_POST_stage_poll(struct be_ctrl_info *ctrl, u16 poll_stage) +static int be_POST_stage_poll(struct be_adapter *adapter, u16 poll_stage) { u16 stage, cnt, error; for (cnt = 0; cnt < 5000; cnt++) { - error = be_POST_stage_get(ctrl, &stage); + error = be_POST_stage_get(adapter, &stage); if (error) return -1; @@ -248,11 +249,11 @@ static int be_POST_stage_poll(struct be_ctrl_info *ctrl, u16 poll_stage) } -int be_cmd_POST(struct be_ctrl_info *ctrl) +int be_cmd_POST(struct be_adapter *adapter) { u16 stage, error; - error = be_POST_stage_get(ctrl, &stage); + error = be_POST_stage_get(adapter, &stage); if (error) goto err; @@ -263,14 +264,14 @@ int be_cmd_POST(struct be_ctrl_info *ctrl) goto err; /* On awaiting host rdy, reset and again poll on awaiting host rdy */ - iowrite32(POST_STAGE_BE_RESET, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET); - error = be_POST_stage_poll(ctrl, POST_STAGE_AWAITING_HOST_RDY); + iowrite32(POST_STAGE_BE_RESET, adapter->csr + MPU_EP_SEMAPHORE_OFFSET); + error = be_POST_stage_poll(adapter, POST_STAGE_AWAITING_HOST_RDY); if (error) goto err; /* Now kickoff POST and poll on armfw ready */ - iowrite32(POST_STAGE_HOST_RDY, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET); - error = be_POST_stage_poll(ctrl, POST_STAGE_ARMFW_RDY); + iowrite32(POST_STAGE_HOST_RDY, adapter->csr + MPU_EP_SEMAPHORE_OFFSET); + error = be_POST_stage_poll(adapter, POST_STAGE_ARMFW_RDY); if (error) goto err; @@ -367,16 +368,16 @@ static inline struct be_mcc_wrb *wrb_from_mcc(struct be_queue_info *mccq) return wrb; } -int be_cmd_eq_create(struct be_ctrl_info *ctrl, +int be_cmd_eq_create(struct be_adapter *adapter, struct be_queue_info *eq, int eq_delay) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_eq_create *req = embedded_payload(wrb); struct be_cmd_resp_eq_create *resp = embedded_payload(wrb); struct be_dma_mem *q_mem = &eq->dma_mem; int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -387,7 +388,7 @@ int be_cmd_eq_create(struct be_ctrl_info *ctrl, req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); AMAP_SET_BITS(struct amap_eq_context, func, req->context, - ctrl->pci_func); + adapter->pci_func); AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); /* 4byte eqe*/ AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); @@ -399,24 +400,24 @@ int be_cmd_eq_create(struct be_ctrl_info *ctrl, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { eq->id = le16_to_cpu(resp->eq_id); eq->created = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr, +int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, u8 type, bool permanent, u32 if_handle) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_mac_query *req = embedded_payload(wrb); struct be_cmd_resp_mac_query *resp = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -432,22 +433,22 @@ int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr, req->permanent = 0; } - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) memcpy(mac_addr, resp->mac.addr, ETH_ALEN); - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr, +int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, u32 if_id, u32 *pmac_id) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_pmac_add *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -458,23 +459,23 @@ int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr, req->if_id = cpu_to_le32(if_id); memcpy(req->mac_address, mac_addr, ETH_ALEN); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_pmac_add *resp = embedded_payload(wrb); *pmac_id = le32_to_cpu(resp->pmac_id); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id) +int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_pmac_del *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -485,24 +486,24 @@ int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id) req->if_id = cpu_to_le32(if_id); req->pmac_id = cpu_to_le32(pmac_id); - status = be_mbox_db_ring(ctrl); - spin_unlock(&ctrl->mbox_lock); + status = be_mbox_db_ring(adapter); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_cq_create(struct be_ctrl_info *ctrl, +int be_cmd_cq_create(struct be_adapter *adapter, struct be_queue_info *cq, struct be_queue_info *eq, bool sol_evts, bool no_delay, int coalesce_wm) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_cq_create *req = embedded_payload(wrb); struct be_cmd_resp_cq_create *resp = embedded_payload(wrb); struct be_dma_mem *q_mem = &cq->dma_mem; void *ctxt = &req->context; int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -521,17 +522,17 @@ int be_cmd_cq_create(struct be_ctrl_info *ctrl, AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1); AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id); AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1); - AMAP_SET_BITS(struct amap_cq_context, func, ctxt, ctrl->pci_func); + AMAP_SET_BITS(struct amap_cq_context, func, ctxt, adapter->pci_func); be_dws_cpu_to_le(ctxt, sizeof(req->context)); be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { cq->id = le16_to_cpu(resp->cq_id); cq->created = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } @@ -544,17 +545,17 @@ static u32 be_encoded_q_len(int q_len) return len_encoded; } -int be_cmd_mccq_create(struct be_ctrl_info *ctrl, +int be_cmd_mccq_create(struct be_adapter *adapter, struct be_queue_info *mccq, struct be_queue_info *cq) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_mcc_create *req = embedded_payload(wrb); struct be_dma_mem *q_mem = &mccq->dma_mem; void *ctxt = &req->context; int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -564,7 +565,7 @@ int be_cmd_mccq_create(struct be_ctrl_info *ctrl, req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); - AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, ctrl->pci_func); + AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, adapter->pci_func); AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1); AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt, be_encoded_q_len(mccq->len)); @@ -574,29 +575,29 @@ int be_cmd_mccq_create(struct be_ctrl_info *ctrl, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); mccq->id = le16_to_cpu(resp->id); mccq->created = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_txq_create(struct be_ctrl_info *ctrl, +int be_cmd_txq_create(struct be_adapter *adapter, struct be_queue_info *txq, struct be_queue_info *cq) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_eth_tx_create *req = embedded_payload(wrb); struct be_dma_mem *q_mem = &txq->dma_mem; void *ctxt = &req->context; int status; u32 len_encoded; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -613,7 +614,7 @@ int be_cmd_txq_create(struct be_ctrl_info *ctrl, len_encoded = 0; AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt, len_encoded); AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt, - ctrl->pci_func); + adapter->pci_func); AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1); AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id); @@ -621,27 +622,27 @@ int be_cmd_txq_create(struct be_ctrl_info *ctrl, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb); txq->id = le16_to_cpu(resp->cid); txq->created = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_rxq_create(struct be_ctrl_info *ctrl, +int be_cmd_rxq_create(struct be_adapter *adapter, struct be_queue_info *rxq, u16 cq_id, u16 frag_size, u16 max_frame_size, u32 if_id, u32 rss) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_eth_rx_create *req = embedded_payload(wrb); struct be_dma_mem *q_mem = &rxq->dma_mem; int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -657,27 +658,27 @@ int be_cmd_rxq_create(struct be_ctrl_info *ctrl, req->max_frame_size = cpu_to_le16(max_frame_size); req->rss_queue = cpu_to_le32(rss); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb); rxq->id = le16_to_cpu(resp->id); rxq->created = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } /* Generic destroyer function for all types of queues */ -int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, +int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, int queue_type) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_q_destroy *req = embedded_payload(wrb); u8 subsys = 0, opcode = 0; int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -711,22 +712,22 @@ int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); req->id = cpu_to_le16(q->id); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); err: - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } /* Create an rx filtering policy configuration on an i/f */ -int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac, +int be_cmd_if_create(struct be_adapter *adapter, u32 flags, u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_if_create *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -739,7 +740,7 @@ int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac, if (!pmac_invalid) memcpy(req->mac_addr, mac, ETH_ALEN); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_if_create *resp = embedded_payload(wrb); *if_handle = le32_to_cpu(resp->interface_id); @@ -747,17 +748,17 @@ int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac, *pmac_id = le32_to_cpu(resp->pmac_id); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id) +int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_if_destroy *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -766,9 +767,9 @@ int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id) OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req)); req->interface_id = cpu_to_le32(interface_id); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } @@ -776,14 +777,14 @@ int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id) /* Get stats is a non embedded command: the request is not embedded inside * WRB but is a separate dma memory block */ -int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd) +int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_get_stats *req = nonemb_cmd->va; struct be_sge *sge = nonembedded_sgl(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); memset(req, 0, sizeof(*req)); @@ -796,24 +797,24 @@ int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd) sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); sge->len = cpu_to_le32(nonemb_cmd->size); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_get_stats *resp = nonemb_cmd->va; be_dws_le_to_cpu(&resp->hw_stats, sizeof(resp->hw_stats)); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_link_status_query(struct be_ctrl_info *ctrl, +int be_cmd_link_status_query(struct be_adapter *adapter, bool *link_up) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_link_status *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); *link_up = false; memset(wrb, 0, sizeof(*wrb)); @@ -823,24 +824,24 @@ int be_cmd_link_status_query(struct be_ctrl_info *ctrl, be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req)); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_link_status *resp = embedded_payload(wrb); if (resp->mac_speed != PHY_LINK_SPEED_ZERO) *link_up = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver) +int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_get_fw_version *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -848,24 +849,24 @@ int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_FW_VERSION, sizeof(*req)); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb); strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } /* set the EQ delay interval of an EQ to specified value */ -int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd) +int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_modify_eq_delay *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -878,20 +879,20 @@ int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd) req->delay[0].phase = 0; req->delay[0].delay_multiplier = cpu_to_le32(eqd); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, u16 *vtag_array, +int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, u32 num, bool untagged, bool promiscuous) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_vlan_config *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -908,21 +909,21 @@ int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, u16 *vtag_array, req->num_vlan * sizeof(vtag_array[0])); } - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } /* Use MCC for this command as it may be called in BH context */ -int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) +int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en) { struct be_mcc_wrb *wrb; struct be_cmd_req_promiscuous_config *req; - spin_lock_bh(&ctrl->mcc_lock); + spin_lock_bh(&adapter->mcc_lock); - wrb = wrb_from_mcc(&ctrl->mcc_obj.q); + wrb = wrb_from_mcc(&adapter->mcc_obj.q); BUG_ON(!wrb); req = embedded_payload(wrb); @@ -937,9 +938,9 @@ int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) else req->port0_promiscuous = en; - be_mcc_notify_wait(ctrl); + be_mcc_notify_wait(adapter); - spin_unlock_bh(&ctrl->mcc_lock); + spin_unlock_bh(&adapter->mcc_lock); return 0; } @@ -947,16 +948,16 @@ int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) * Use MCC for this command as it may be called in BH context * (mc == NULL) => multicast promiscous */ -int be_cmd_multicast_set(struct be_ctrl_info *ctrl, u32 if_id, +int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id, struct dev_mc_list *mc_list, u32 mc_count) { #define BE_MAX_MC 32 /* set mcast promisc if > 32 */ struct be_mcc_wrb *wrb; struct be_cmd_req_mcast_mac_config *req; - spin_lock_bh(&ctrl->mcc_lock); + spin_lock_bh(&adapter->mcc_lock); - wrb = wrb_from_mcc(&ctrl->mcc_obj.q); + wrb = wrb_from_mcc(&adapter->mcc_obj.q); BUG_ON(!wrb); req = embedded_payload(wrb); @@ -979,20 +980,20 @@ int be_cmd_multicast_set(struct be_ctrl_info *ctrl, u32 if_id, req->promiscuous = 1; } - be_mcc_notify_wait(ctrl); + be_mcc_notify_wait(adapter); - spin_unlock_bh(&ctrl->mcc_lock); + spin_unlock_bh(&adapter->mcc_lock); return 0; } -int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc) +int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_set_flow_control *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); @@ -1004,19 +1005,19 @@ int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc) req->tx_flow_control = cpu_to_le16((u16)tx_fc); req->rx_flow_control = cpu_to_le16((u16)rx_fc); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc) +int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_get_flow_control *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); @@ -1025,7 +1026,7 @@ int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req)); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_get_flow_control *resp = embedded_payload(wrb); @@ -1033,17 +1034,17 @@ int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc) *rx_fc = le16_to_cpu(resp->rx_flow_control); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num) +int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_query_fw_cfg *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); @@ -1052,12 +1053,12 @@ int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req)); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb); *port_num = le32_to_cpu(resp->phys_port); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 747626d..164ab92 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -634,7 +634,6 @@ struct be_cmd_resp_link_status { } __packed; /******************** Get FW Version *******************/ -#define FW_VER_LEN 32 struct be_cmd_req_get_fw_version { struct be_cmd_req_hdr hdr; u8 rsvd0[FW_VER_LEN]; @@ -697,52 +696,52 @@ struct be_cmd_resp_query_fw_cfg { u32 rsvd[26]; }; -extern int be_pci_fnum_get(struct be_ctrl_info *ctrl); -extern int be_cmd_POST(struct be_ctrl_info *ctrl); -extern int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr, +extern int be_pci_fnum_get(struct be_adapter *adapter); +extern int be_cmd_POST(struct be_adapter *adapter); +extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, u8 type, bool permanent, u32 if_handle); -extern int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr, +extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, u32 if_id, u32 *pmac_id); -extern int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id); -extern int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 if_flags, u8 *mac, +extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id); +extern int be_cmd_if_create(struct be_adapter *adapter, u32 if_flags, u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id); -extern int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 if_handle); -extern int be_cmd_eq_create(struct be_ctrl_info *ctrl, +extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle); +extern int be_cmd_eq_create(struct be_adapter *adapter, struct be_queue_info *eq, int eq_delay); -extern int be_cmd_cq_create(struct be_ctrl_info *ctrl, +extern int be_cmd_cq_create(struct be_adapter *adapter, struct be_queue_info *cq, struct be_queue_info *eq, bool sol_evts, bool no_delay, int num_cqe_dma_coalesce); -extern int be_cmd_mccq_create(struct be_ctrl_info *ctrl, +extern int be_cmd_mccq_create(struct be_adapter *adapter, struct be_queue_info *mccq, struct be_queue_info *cq); -extern int be_cmd_txq_create(struct be_ctrl_info *ctrl, +extern int be_cmd_txq_create(struct be_adapter *adapter, struct be_queue_info *txq, struct be_queue_info *cq); -extern int be_cmd_rxq_create(struct be_ctrl_info *ctrl, +extern int be_cmd_rxq_create(struct be_adapter *adapter, struct be_queue_info *rxq, u16 cq_id, u16 frag_size, u16 max_frame_size, u32 if_id, u32 rss); -extern int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, +extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, int type); -extern int be_cmd_link_status_query(struct be_ctrl_info *ctrl, +extern int be_cmd_link_status_query(struct be_adapter *adapter, bool *link_up); -extern int be_cmd_reset(struct be_ctrl_info *ctrl); -extern int be_cmd_get_stats(struct be_ctrl_info *ctrl, +extern int be_cmd_reset(struct be_adapter *adapter); +extern int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd); -extern int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver); +extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver); -extern int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd); -extern int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, +extern int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd); +extern int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, u32 num, bool untagged, bool promiscuous); -extern int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, +extern int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en); -extern int be_cmd_multicast_set(struct be_ctrl_info *ctrl, u32 if_id, +extern int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id, struct dev_mc_list *mc_list, u32 mc_count); -extern int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, +extern int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc); -extern int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, +extern int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc); -extern int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num); -extern void be_process_mcc(struct be_ctrl_info *ctrl); +extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num); +extern void be_process_mcc(struct be_adapter *adapter); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index f3f0f91..c480c19 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -16,6 +16,7 @@ */ #include "be.h" +#include "be_cmds.h" #include struct be_ethtool_stat { @@ -148,7 +149,6 @@ static int be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; u32 tx_max, tx_min, tx_cur; @@ -176,7 +176,7 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) if (tx_cur > BE_MAX_EQD) tx_cur = BE_MAX_EQD; if (tx_eq->cur_eqd != tx_cur) { - status = be_cmd_modify_eqd(ctrl, tx_eq->q.id, tx_cur); + status = be_cmd_modify_eqd(adapter, tx_eq->q.id, tx_cur); if (!status) tx_eq->cur_eqd = tx_cur; } @@ -196,7 +196,8 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) if (rx_cur > BE_MAX_EQD) rx_cur = BE_MAX_EQD; if (rx_eq->cur_eqd != rx_cur) { - status = be_cmd_modify_eqd(ctrl, rx_eq->q.id, rx_cur); + status = be_cmd_modify_eqd(adapter, rx_eq->q.id, + rx_cur); if (!status) rx_eq->cur_eqd = rx_cur; } @@ -310,8 +311,7 @@ be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) { struct be_adapter *adapter = netdev_priv(netdev); - be_cmd_get_flow_control(&adapter->ctrl, &ecmd->tx_pause, - &ecmd->rx_pause); + be_cmd_get_flow_control(adapter, &ecmd->tx_pause, &ecmd->rx_pause); ecmd->autoneg = 0; } @@ -324,7 +324,7 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) if (ecmd->autoneg != 0) return -EINVAL; - status = be_cmd_set_flow_control(&adapter->ctrl, ecmd->tx_pause, + status = be_cmd_set_flow_control(adapter, ecmd->tx_pause, ecmd->rx_pause); if (!status) dev_warn(&adapter->pdev->dev, "Pause param set failed.\n"); diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index c56487e..da5341f 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -16,6 +16,7 @@ */ #include "be.h" +#include "be_cmds.h" #include MODULE_VERSION(DRV_VER); @@ -60,9 +61,9 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, return 0; } -static void be_intr_set(struct be_ctrl_info *ctrl, bool enable) +static void be_intr_set(struct be_adapter *adapter, bool enable) { - u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; + u8 __iomem *addr = adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; u32 reg = ioread32(addr); u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; if (!enabled && enable) { @@ -77,23 +78,23 @@ static void be_intr_set(struct be_ctrl_info *ctrl, bool enable) iowrite32(reg, addr); } -static void be_rxq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted) +static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted) { u32 val = 0; val |= qid & DB_RQ_RING_ID_MASK; val |= posted << DB_RQ_NUM_POSTED_SHIFT; - iowrite32(val, ctrl->db + DB_RQ_OFFSET); + iowrite32(val, adapter->db + DB_RQ_OFFSET); } -static void be_txq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted) +static void be_txq_notify(struct be_adapter *adapter, u16 qid, u16 posted) { u32 val = 0; val |= qid & DB_TXULP_RING_ID_MASK; val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT; - iowrite32(val, ctrl->db + DB_TXULP1_OFFSET); + iowrite32(val, adapter->db + DB_TXULP1_OFFSET); } -static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid, +static void be_eq_notify(struct be_adapter *adapter, u16 qid, bool arm, bool clear_int, u16 num_popped) { u32 val = 0; @@ -104,18 +105,17 @@ static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid, val |= 1 << DB_EQ_CLR_SHIFT; val |= 1 << DB_EQ_EVNT_SHIFT; val |= num_popped << DB_EQ_NUM_POPPED_SHIFT; - iowrite32(val, ctrl->db + DB_EQ_OFFSET); + iowrite32(val, adapter->db + DB_EQ_OFFSET); } -void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, - bool arm, u16 num_popped) +void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped) { u32 val = 0; val |= qid & DB_CQ_RING_ID_MASK; if (arm) val |= 1 << DB_CQ_REARM_SHIFT; val |= num_popped << DB_CQ_NUM_POPPED_SHIFT; - iowrite32(val, ctrl->db + DB_CQ_OFFSET); + iowrite32(val, adapter->db + DB_CQ_OFFSET); } @@ -126,12 +126,12 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) int status = 0; if (netif_running(netdev)) { - status = be_cmd_pmac_del(&adapter->ctrl, adapter->if_handle, + status = be_cmd_pmac_del(adapter, adapter->if_handle, adapter->pmac_id); if (status) return status; - status = be_cmd_pmac_add(&adapter->ctrl, (u8 *)addr->sa_data, + status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, adapter->if_handle, &adapter->pmac_id); } @@ -214,9 +214,8 @@ static void netdev_stats_update(struct be_adapter *adapter) dev_stats->tx_window_errors = 0; } -void be_link_status_update(void *ctxt, bool link_up) +void be_link_status_update(struct be_adapter *adapter, bool link_up) { - struct be_adapter *adapter = ctxt; struct net_device *netdev = adapter->netdev; /* If link came up or went down */ @@ -237,7 +236,6 @@ void be_link_status_update(void *ctxt, bool link_up) /* Update the EQ delay n BE based on the RX frags consumed / sec */ static void be_rx_eqd_update(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_drvr_stats *stats = &adapter->stats.drvr_stats; ulong now = jiffies; @@ -270,7 +268,7 @@ static void be_rx_eqd_update(struct be_adapter *adapter) if (eqd < 10) eqd = 0; if (eqd != rx_eq->cur_eqd) - be_cmd_modify_eqd(ctrl, rx_eq->q.id, eqd); + be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd); rx_eq->cur_eqd = eqd; } @@ -412,8 +410,8 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; busaddr = pci_map_page(pdev, frag->page, - frag->page_offset, - frag->size, PCI_DMA_TODEVICE); + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); wrb = queue_head_node(txq); wrb_fill(wrb, busaddr, frag->size); be_dws_cpu_to_le(wrb, sizeof(*wrb)); @@ -461,7 +459,7 @@ static int be_xmit(struct sk_buff *skb, struct net_device *netdev) stopped = true; } - be_txq_notify(&adapter->ctrl, txq->id, wrb_cnt); + be_txq_notify(adapter, txq->id, wrb_cnt); be_tx_stats_update(adapter, wrb_cnt, copied, stopped); return NETDEV_TX_OK; @@ -502,10 +500,10 @@ static void be_vid_config(struct net_device *netdev) ntags++; } } - be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle, + be_cmd_vlan_config(adapter, adapter->if_handle, vtag, ntags, 1, 0); } else { - be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle, + be_cmd_vlan_config(adapter, adapter->if_handle, NULL, 0, 1, 1); } } @@ -515,13 +513,12 @@ static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp) struct be_adapter *adapter = netdev_priv(netdev); struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; - struct be_ctrl_info *ctrl = &adapter->ctrl; - be_eq_notify(ctrl, rx_eq->q.id, false, false, 0); - be_eq_notify(ctrl, tx_eq->q.id, false, false, 0); + be_eq_notify(adapter, rx_eq->q.id, false, false, 0); + be_eq_notify(adapter, tx_eq->q.id, false, false, 0); adapter->vlan_grp = grp; - be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); - be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); + be_eq_notify(adapter, rx_eq->q.id, true, false, 0); + be_eq_notify(adapter, tx_eq->q.id, true, false, 0); } static void be_vlan_add_vid(struct net_device *netdev, u16 vid) @@ -548,10 +545,9 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) static void be_set_multicast_list(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_ctrl_info *ctrl = &adapter->ctrl; if (netdev->flags & IFF_PROMISC) { - be_cmd_promiscuous_config(ctrl, adapter->port_num, 1); + be_cmd_promiscuous_config(adapter, adapter->port_num, 1); adapter->promiscuous = true; goto done; } @@ -559,15 +555,15 @@ static void be_set_multicast_list(struct net_device *netdev) /* BE was previously in promiscous mode; disable it */ if (adapter->promiscuous) { adapter->promiscuous = false; - be_cmd_promiscuous_config(ctrl, adapter->port_num, 0); + be_cmd_promiscuous_config(adapter, adapter->port_num, 0); } if (netdev->flags & IFF_ALLMULTI) { - be_cmd_multicast_set(ctrl, adapter->if_handle, NULL, 0); + be_cmd_multicast_set(adapter, adapter->if_handle, NULL, 0); goto done; } - be_cmd_multicast_set(ctrl, adapter->if_handle, netdev->mc_list, + be_cmd_multicast_set(adapter, adapter->if_handle, netdev->mc_list, netdev->mc_count); done: return; @@ -942,7 +938,7 @@ static void be_post_rx_frags(struct be_adapter *adapter) if (posted) { atomic_add(posted, &rxq->used); - be_rxq_notify(&adapter->ctrl, rxq->id, posted); + be_rxq_notify(adapter, rxq->id, posted); } else if (atomic_read(&rxq->used) == 0) { /* Let be_worker replenish when memory is available */ adapter->rx_post_starved = true; @@ -1010,7 +1006,7 @@ static void be_rx_q_clean(struct be_adapter *adapter) while ((rxcp = be_rx_compl_get(adapter)) != NULL) { be_rx_compl_discard(adapter, rxcp); be_rx_compl_reset(rxcp); - be_cq_notify(&adapter->ctrl, rx_cq->id, true, 1); + be_cq_notify(adapter, rx_cq->id, true, 1); } /* Then free posted rx buffer that were not used */ @@ -1043,16 +1039,15 @@ static void be_tx_q_clean(struct be_adapter *adapter) static void be_mcc_queues_destroy(struct be_adapter *adapter) { struct be_queue_info *q; - struct be_ctrl_info *ctrl = &adapter->ctrl; - q = &ctrl->mcc_obj.q; + q = &adapter->mcc_obj.q; if (q->created) - be_cmd_q_destroy(ctrl, q, QTYPE_MCCQ); + be_cmd_q_destroy(adapter, q, QTYPE_MCCQ); be_queue_free(adapter, q); - q = &ctrl->mcc_obj.cq; + q = &adapter->mcc_obj.cq; if (q->created) - be_cmd_q_destroy(ctrl, q, QTYPE_CQ); + be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); } @@ -1060,25 +1055,24 @@ static void be_mcc_queues_destroy(struct be_adapter *adapter) static int be_mcc_queues_create(struct be_adapter *adapter) { struct be_queue_info *q, *cq; - struct be_ctrl_info *ctrl = &adapter->ctrl; /* Alloc MCC compl queue */ - cq = &ctrl->mcc_obj.cq; + cq = &adapter->mcc_obj.cq; if (be_queue_alloc(adapter, cq, MCC_CQ_LEN, sizeof(struct be_mcc_cq_entry))) goto err; /* Ask BE to create MCC compl queue; share TX's eq */ - if (be_cmd_cq_create(ctrl, cq, &adapter->tx_eq.q, false, true, 0)) + if (be_cmd_cq_create(adapter, cq, &adapter->tx_eq.q, false, true, 0)) goto mcc_cq_free; /* Alloc MCC queue */ - q = &ctrl->mcc_obj.q; + q = &adapter->mcc_obj.q; if (be_queue_alloc(adapter, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb))) goto mcc_cq_destroy; /* Ask BE to create MCC queue */ - if (be_cmd_mccq_create(ctrl, q, cq)) + if (be_cmd_mccq_create(adapter, q, cq)) goto mcc_q_free; return 0; @@ -1086,7 +1080,7 @@ static int be_mcc_queues_create(struct be_adapter *adapter) mcc_q_free: be_queue_free(adapter, q); mcc_cq_destroy: - be_cmd_q_destroy(ctrl, cq, QTYPE_CQ); + be_cmd_q_destroy(adapter, cq, QTYPE_CQ); mcc_cq_free: be_queue_free(adapter, cq); err: @@ -1099,7 +1093,7 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) q = &adapter->tx_obj.q; if (q->created) { - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_TXQ); + be_cmd_q_destroy(adapter, q, QTYPE_TXQ); /* No more tx completions can be rcvd now; clean up if there * are any pending completions or pending tx requests */ @@ -1109,12 +1103,12 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) q = &adapter->tx_obj.cq; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); + be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); q = &adapter->tx_eq.q; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); + be_cmd_q_destroy(adapter, q, QTYPE_EQ); be_queue_free(adapter, q); } @@ -1132,7 +1126,7 @@ static int be_tx_queues_create(struct be_adapter *adapter) return -1; /* Ask BE to create Tx Event queue */ - if (be_cmd_eq_create(&adapter->ctrl, eq, adapter->tx_eq.cur_eqd)) + if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd)) goto tx_eq_free; /* Alloc TX eth compl queue */ cq = &adapter->tx_obj.cq; @@ -1141,7 +1135,7 @@ static int be_tx_queues_create(struct be_adapter *adapter) goto tx_eq_destroy; /* Ask BE to create Tx eth compl queue */ - if (be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3)) + if (be_cmd_cq_create(adapter, cq, eq, false, false, 3)) goto tx_cq_free; /* Alloc TX eth queue */ @@ -1150,18 +1144,18 @@ static int be_tx_queues_create(struct be_adapter *adapter) goto tx_cq_destroy; /* Ask BE to create Tx eth queue */ - if (be_cmd_txq_create(&adapter->ctrl, q, cq)) + if (be_cmd_txq_create(adapter, q, cq)) goto tx_q_free; return 0; tx_q_free: be_queue_free(adapter, q); tx_cq_destroy: - be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ); + be_cmd_q_destroy(adapter, cq, QTYPE_CQ); tx_cq_free: be_queue_free(adapter, cq); tx_eq_destroy: - be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ); + be_cmd_q_destroy(adapter, eq, QTYPE_EQ); tx_eq_free: be_queue_free(adapter, eq); return -1; @@ -1173,19 +1167,19 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) q = &adapter->rx_obj.q; if (q->created) { - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_RXQ); + be_cmd_q_destroy(adapter, q, QTYPE_RXQ); be_rx_q_clean(adapter); } be_queue_free(adapter, q); q = &adapter->rx_obj.cq; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); + be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); q = &adapter->rx_eq.q; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); + be_cmd_q_destroy(adapter, q, QTYPE_EQ); be_queue_free(adapter, q); } @@ -1208,7 +1202,7 @@ static int be_rx_queues_create(struct be_adapter *adapter) return rc; /* Ask BE to create Rx Event queue */ - rc = be_cmd_eq_create(&adapter->ctrl, eq, adapter->rx_eq.cur_eqd); + rc = be_cmd_eq_create(adapter, eq, adapter->rx_eq.cur_eqd); if (rc) goto rx_eq_free; @@ -1220,7 +1214,7 @@ static int be_rx_queues_create(struct be_adapter *adapter) goto rx_eq_destroy; /* Ask BE to create Rx eth compl queue */ - rc = be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3); + rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3); if (rc) goto rx_cq_free; @@ -1231,7 +1225,7 @@ static int be_rx_queues_create(struct be_adapter *adapter) goto rx_cq_destroy; /* Ask BE to create Rx eth queue */ - rc = be_cmd_rxq_create(&adapter->ctrl, q, cq->id, rx_frag_size, + rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size, BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, false); if (rc) goto rx_q_free; @@ -1240,11 +1234,11 @@ static int be_rx_queues_create(struct be_adapter *adapter) rx_q_free: be_queue_free(adapter, q); rx_cq_destroy: - be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ); + be_cmd_q_destroy(adapter, cq, QTYPE_CQ); rx_cq_free: be_queue_free(adapter, cq); rx_eq_destroy: - be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ); + be_cmd_q_destroy(adapter, eq, QTYPE_EQ); rx_eq_free: be_queue_free(adapter, eq); return rc; @@ -1264,8 +1258,7 @@ static bool event_get(struct be_eq_obj *eq_obj, u16 *rid) return true; } -static int event_handle(struct be_ctrl_info *ctrl, - struct be_eq_obj *eq_obj) +static int event_handle(struct be_adapter *adapter, struct be_eq_obj *eq_obj) { u16 rid = 0, num = 0; @@ -1273,7 +1266,7 @@ static int event_handle(struct be_ctrl_info *ctrl, num++; /* We can see an interrupt and no event */ - be_eq_notify(ctrl, eq_obj->q.id, true, true, num); + be_eq_notify(adapter, eq_obj->q.id, true, true, num); if (num) napi_schedule(&eq_obj->napi); @@ -1283,25 +1276,24 @@ static int event_handle(struct be_ctrl_info *ctrl, static irqreturn_t be_intx(int irq, void *dev) { struct be_adapter *adapter = dev; - struct be_ctrl_info *ctrl = &adapter->ctrl; - int isr; + int isr; - isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET + - ctrl->pci_func * CEV_ISR_SIZE); + isr = ioread32(adapter->csr + CEV_ISR0_OFFSET + + adapter->pci_func * CEV_ISR_SIZE); if (!isr) - return IRQ_NONE; + return IRQ_NONE; - event_handle(ctrl, &adapter->tx_eq); - event_handle(ctrl, &adapter->rx_eq); + event_handle(adapter, &adapter->tx_eq); + event_handle(adapter, &adapter->rx_eq); - return IRQ_HANDLED; + return IRQ_HANDLED; } static irqreturn_t be_msix_rx(int irq, void *dev) { struct be_adapter *adapter = dev; - event_handle(&adapter->ctrl, &adapter->rx_eq); + event_handle(adapter, &adapter->rx_eq); return IRQ_HANDLED; } @@ -1310,7 +1302,7 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev) { struct be_adapter *adapter = dev; - event_handle(&adapter->ctrl, &adapter->tx_eq); + event_handle(adapter, &adapter->tx_eq); return IRQ_HANDLED; } @@ -1356,10 +1348,10 @@ int be_poll_rx(struct napi_struct *napi, int budget) /* All consumed */ if (work_done < budget) { napi_complete(napi); - be_cq_notify(&adapter->ctrl, rx_cq->id, true, work_done); + be_cq_notify(adapter, rx_cq->id, true, work_done); } else { /* More to be consumed; continue with interrupts disabled */ - be_cq_notify(&adapter->ctrl, rx_cq->id, false, work_done); + be_cq_notify(adapter, rx_cq->id, false, work_done); } return work_done; } @@ -1380,7 +1372,7 @@ void be_process_tx(struct be_adapter *adapter) } if (num_cmpl) { - be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl); + be_cq_notify(adapter, tx_cq->id, true, num_cmpl); /* As Tx wrbs have been freed up, wake up netdev queue if * it was stopped due to lack of tx wrbs. @@ -1408,7 +1400,7 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) be_process_tx(adapter); - be_process_mcc(&adapter->ctrl); + be_process_mcc(adapter); return 1; } @@ -1420,7 +1412,7 @@ static void be_worker(struct work_struct *work) int status; /* Get Stats */ - status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd); + status = be_cmd_get_stats(adapter, &adapter->stats.cmd); if (!status) netdev_stats_update(adapter); @@ -1454,8 +1446,7 @@ static void be_msix_enable(struct be_adapter *adapter) static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id) { - return adapter->msix_entries[eq_id - - 8 * adapter->ctrl.pci_func].vector; + return adapter->msix_entries[eq_id - 8 * adapter->pci_func].vector; } static int be_msix_register(struct be_adapter *adapter) @@ -1540,7 +1531,6 @@ done: static int be_open(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; bool link_up; @@ -1554,16 +1544,16 @@ static int be_open(struct net_device *netdev) be_irq_register(adapter); - be_intr_set(ctrl, true); + be_intr_set(adapter, true); /* The evt queues are created in unarmed state; arm them */ - be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); - be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); + be_eq_notify(adapter, rx_eq->q.id, true, false, 0); + be_eq_notify(adapter, tx_eq->q.id, true, false, 0); /* Rx compl queue may be in unarmed state; rearm it */ - be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0); + be_cq_notify(adapter, adapter->rx_obj.cq.id, true, 0); - status = be_cmd_link_status_query(ctrl, &link_up); + status = be_cmd_link_status_query(adapter, &link_up); if (status) return status; be_link_status_update(adapter, link_up); @@ -1574,7 +1564,6 @@ static int be_open(struct net_device *netdev) static int be_setup(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; struct net_device *netdev = adapter->netdev; u32 if_flags; int status; @@ -1582,7 +1571,7 @@ static int be_setup(struct be_adapter *adapter) if_flags = BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PROMISCUOUS | BE_IF_FLAGS_MCAST_PROMISCUOUS | BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_PASS_L3L4_ERRORS; - status = be_cmd_if_create(ctrl, if_flags, netdev->dev_addr, + status = be_cmd_if_create(adapter, if_flags, netdev->dev_addr, false/* pmac_invalid */, &adapter->if_handle, &adapter->pmac_id); if (status != 0) @@ -1590,7 +1579,7 @@ static int be_setup(struct be_adapter *adapter) be_vid_config(netdev); - status = be_cmd_set_flow_control(ctrl, true, true); + status = be_cmd_set_flow_control(adapter, true, true); if (status != 0) goto if_destroy; @@ -1613,19 +1602,17 @@ rx_qs_destroy: tx_qs_destroy: be_tx_queues_destroy(adapter); if_destroy: - be_cmd_if_destroy(ctrl, adapter->if_handle); + be_cmd_if_destroy(adapter, adapter->if_handle); do_none: return status; } static int be_clear(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; - be_rx_queues_destroy(adapter); be_tx_queues_destroy(adapter); - be_cmd_if_destroy(ctrl, adapter->if_handle); + be_cmd_if_destroy(adapter, adapter->if_handle); be_mcc_queues_destroy(adapter); return 0; @@ -1634,7 +1621,6 @@ static int be_clear(struct be_adapter *adapter) static int be_close(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; int vec; @@ -1645,7 +1631,7 @@ static int be_close(struct net_device *netdev) netif_carrier_off(netdev); adapter->link_up = false; - be_intr_set(ctrl, false); + be_intr_set(adapter, false); if (adapter->msix_enabled) { vec = be_msix_vec_get(adapter, tx_eq->q.id); @@ -1704,13 +1690,12 @@ static void be_netdev_init(struct net_device *netdev) static void be_unmap_pci_bars(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; - if (ctrl->csr) - iounmap(ctrl->csr); - if (ctrl->db) - iounmap(ctrl->db); - if (ctrl->pcicfg) - iounmap(ctrl->pcicfg); + if (adapter->csr) + iounmap(adapter->csr); + if (adapter->db) + iounmap(adapter->db); + if (adapter->pcicfg) + iounmap(adapter->pcicfg); } static int be_map_pci_bars(struct be_adapter *adapter) @@ -1721,19 +1706,19 @@ static int be_map_pci_bars(struct be_adapter *adapter) pci_resource_len(adapter->pdev, 2)); if (addr == NULL) return -ENOMEM; - adapter->ctrl.csr = addr; + adapter->csr = addr; addr = ioremap_nocache(pci_resource_start(adapter->pdev, 4), 128 * 1024); if (addr == NULL) goto pci_map_err; - adapter->ctrl.db = addr; + adapter->db = addr; addr = ioremap_nocache(pci_resource_start(adapter->pdev, 1), pci_resource_len(adapter->pdev, 1)); if (addr == NULL) goto pci_map_err; - adapter->ctrl.pcicfg = addr; + adapter->pcicfg = addr; return 0; pci_map_err: @@ -1744,7 +1729,7 @@ pci_map_err: static void be_ctrl_cleanup(struct be_adapter *adapter) { - struct be_dma_mem *mem = &adapter->ctrl.mbox_mem_alloced; + struct be_dma_mem *mem = &adapter->mbox_mem_alloced; be_unmap_pci_bars(adapter); @@ -1753,12 +1738,10 @@ static void be_ctrl_cleanup(struct be_adapter *adapter) mem->va, mem->dma); } -/* Initialize the mbox required to send cmds to BE */ static int be_ctrl_init(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; - struct be_dma_mem *mbox_mem_alloc = &ctrl->mbox_mem_alloced; - struct be_dma_mem *mbox_mem_align = &ctrl->mbox_mem; + struct be_dma_mem *mbox_mem_alloc = &adapter->mbox_mem_alloced; + struct be_dma_mem *mbox_mem_align = &adapter->mbox_mem; int status; u32 val; @@ -1777,15 +1760,12 @@ static int be_ctrl_init(struct be_adapter *adapter) mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16); mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); - spin_lock_init(&ctrl->mbox_lock); - spin_lock_init(&ctrl->mcc_lock); - spin_lock_init(&ctrl->mcc_cq_lock); - - ctrl->async_cb = be_link_status_update; - ctrl->adapter_ctxt = adapter; + spin_lock_init(&adapter->mbox_lock); + spin_lock_init(&adapter->mcc_lock); + spin_lock_init(&adapter->mcc_cq_lock); - val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); - ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & + val = ioread32(adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); + adapter->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & MEMBAR_CTRL_INT_CTRL_PFUNC_MASK; return 0; } @@ -1840,18 +1820,17 @@ static void __devexit be_remove(struct pci_dev *pdev) static int be_hw_up(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; int status; - status = be_cmd_POST(ctrl); + status = be_cmd_POST(adapter); if (status) return status; - status = be_cmd_get_fw_ver(ctrl, adapter->fw_ver); + status = be_cmd_get_fw_ver(adapter, adapter->fw_ver); if (status) return status; - status = be_cmd_query_fw_cfg(ctrl, &adapter->port_num); + status = be_cmd_query_fw_cfg(adapter, &adapter->port_num); return status; } @@ -1861,7 +1840,6 @@ static int __devinit be_probe(struct pci_dev *pdev, int status = 0; struct be_adapter *adapter; struct net_device *netdev; - struct be_ctrl_info *ctrl; u8 mac[ETH_ALEN]; status = pci_enable_device(pdev); @@ -1896,7 +1874,6 @@ static int __devinit be_probe(struct pci_dev *pdev, } } - ctrl = &adapter->ctrl; status = be_ctrl_init(adapter); if (status) goto free_netdev; @@ -1909,7 +1886,7 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status) goto stats_clean; - status = be_cmd_mac_addr_query(ctrl, mac, MAC_ADDRESS_TYPE_NETWORK, + status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK, true /* permanent */, 0); if (status) goto stats_clean; -- cgit v0.10.2 From eec368fb3ce3ee9e7bb042bbafb03f297d96e55e Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 27 Jul 2009 22:52:23 +0000 Subject: be2net: remove pci_func field from be_adapter struct pci function is available as PCI_FUNC(pdev->devfn); no need for a separate field. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index d8a157f..beb1313 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -213,7 +213,6 @@ struct be_adapter { u8 __iomem *csr; u8 __iomem *db; /* Door Bell */ u8 __iomem *pcicfg; /* PCI config space */ - int pci_func; spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */ struct be_dma_mem mbox_mem; @@ -264,6 +263,11 @@ extern struct ethtool_ops be_ethtool_ops; #define drvr_stats(adapter) (&adapter->stats.drvr_stats) +static inline unsigned int be_pci_func(struct be_adapter *adapter) +{ + return PCI_FUNC(adapter->pdev->devfn); +} + #define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops) #define PAGE_SHIFT_4K 12 diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 20278b9..daa2fe8 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -388,7 +388,7 @@ int be_cmd_eq_create(struct be_adapter *adapter, req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); AMAP_SET_BITS(struct amap_eq_context, func, req->context, - adapter->pci_func); + be_pci_func(adapter)); AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); /* 4byte eqe*/ AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); @@ -522,7 +522,7 @@ int be_cmd_cq_create(struct be_adapter *adapter, AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1); AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id); AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1); - AMAP_SET_BITS(struct amap_cq_context, func, ctxt, adapter->pci_func); + AMAP_SET_BITS(struct amap_cq_context, func, ctxt, be_pci_func(adapter)); be_dws_cpu_to_le(ctxt, sizeof(req->context)); be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); @@ -565,7 +565,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter, req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); - AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, adapter->pci_func); + AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, be_pci_func(adapter)); AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1); AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt, be_encoded_q_len(mccq->len)); @@ -614,7 +614,7 @@ int be_cmd_txq_create(struct be_adapter *adapter, len_encoded = 0; AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt, len_encoded); AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt, - adapter->pci_func); + be_pci_func(adapter)); AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1); AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id); diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index 29c33c7..d28f0c6 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -51,9 +51,6 @@ * with the OS. */ #define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */ -/* PCI physical function number */ -#define MEMBAR_CTRL_INT_CTRL_PFUNC_MASK 0x7 /* bits 26 - 28 */ -#define MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT 26 /********* ISR0 Register offset **********/ #define CEV_ISR0_OFFSET 0xC18 diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index da5341f..9c8654d 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1279,7 +1279,7 @@ static irqreturn_t be_intx(int irq, void *dev) int isr; isr = ioread32(adapter->csr + CEV_ISR0_OFFSET + - adapter->pci_func * CEV_ISR_SIZE); + be_pci_func(adapter) * CEV_ISR_SIZE); if (!isr) return IRQ_NONE; @@ -1446,7 +1446,7 @@ static void be_msix_enable(struct be_adapter *adapter) static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id) { - return adapter->msix_entries[eq_id - 8 * adapter->pci_func].vector; + return adapter->msix_entries[eq_id - 8 * be_pci_func(adapter)].vector; } static int be_msix_register(struct be_adapter *adapter) @@ -1743,7 +1743,6 @@ static int be_ctrl_init(struct be_adapter *adapter) struct be_dma_mem *mbox_mem_alloc = &adapter->mbox_mem_alloced; struct be_dma_mem *mbox_mem_align = &adapter->mbox_mem; int status; - u32 val; status = be_map_pci_bars(adapter); if (status) @@ -1764,9 +1763,6 @@ static int be_ctrl_init(struct be_adapter *adapter) spin_lock_init(&adapter->mcc_lock); spin_lock_init(&adapter->mcc_cq_lock); - val = ioread32(adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); - adapter->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & - MEMBAR_CTRL_INT_CTRL_PFUNC_MASK; return 0; } -- cgit v0.10.2 From 5f0b849eb35d09cd2f332d5031051c1a8976c30b Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 27 Jul 2009 22:52:56 +0000 Subject: be2net: replace some printks with dev_err()/dev_warn() And get rid of some unnecessary printks. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index daa2fe8..7c1724e 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -62,8 +62,8 @@ static int be_mcc_compl_process(struct be_adapter *adapter, if (compl_status != MCC_STATUS_SUCCESS) { extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & CQE_STATUS_EXTD_MASK; - printk(KERN_WARNING DRV_NAME - " error in cmd completion: status(compl/extd)=%d/%d\n", + dev_warn(&adapter->pdev->dev, + "Error in cmd completion: status(compl/extd)=%d/%d\n", compl_status, extd_status); return -1; } @@ -135,7 +135,7 @@ static void be_mcc_wait_compl(struct be_adapter *adapter) udelay(100); } if (i == mcc_timeout) - printk(KERN_WARNING DRV_NAME "mcc poll timed out\n"); + dev_err(&adapter->pdev->dev, "mccq poll timed out\n"); } /* Notify MCC requests and wait for completion */ @@ -145,7 +145,7 @@ static void be_mcc_notify_wait(struct be_adapter *adapter) be_mcc_wait_compl(adapter); } -static int be_mbox_db_ready_wait(void __iomem *db) +static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) { int cnt = 0, wait = 5; u32 ready; @@ -156,8 +156,7 @@ static int be_mbox_db_ready_wait(void __iomem *db) break; if (cnt > 200000) { - printk(KERN_WARNING DRV_NAME - ": mbox_db poll timed out\n"); + dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); return -1; } @@ -185,25 +184,22 @@ static int be_mbox_db_ring(struct be_adapter *adapter) memset(cqe, 0, sizeof(*cqe)); - val &= ~MPU_MAILBOX_DB_RDY_MASK; val |= MPU_MAILBOX_DB_HI_MASK; /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; iowrite32(val, db); /* wait for ready to be set */ - status = be_mbox_db_ready_wait(db); + status = be_mbox_db_ready_wait(adapter, db); if (status != 0) return status; val = 0; - val &= ~MPU_MAILBOX_DB_RDY_MASK; - val &= ~MPU_MAILBOX_DB_HI_MASK; /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */ val |= (u32)(mbox_mem->dma >> 4) << 2; iowrite32(val, db); - status = be_mbox_db_ready_wait(db); + status = be_mbox_db_ready_wait(adapter, db); if (status != 0) return status; @@ -214,7 +210,7 @@ static int be_mbox_db_ring(struct be_adapter *adapter) if (status) return status; } else { - printk(KERN_WARNING DRV_NAME "invalid mailbox completion\n"); + dev_err(&adapter->pdev->dev, "invalid mailbox completion\n"); return -1; } return 0; @@ -705,15 +701,13 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, opcode = OPCODE_COMMON_MCC_DESTROY; break; default: - printk(KERN_WARNING DRV_NAME ":bad Q type in Q destroy cmd\n"); - status = -1; - goto err; + BUG(); } be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); req->id = cpu_to_le16(q->id); status = be_mbox_db_ring(adapter); -err: + spin_unlock(&adapter->mbox_lock); return status; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 9c8654d..ab5fcc0 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -66,15 +66,14 @@ static void be_intr_set(struct be_adapter *adapter, bool enable) u8 __iomem *addr = adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; u32 reg = ioread32(addr); u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - if (!enabled && enable) { + + if (!enabled && enable) reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - } else if (enabled && !enable) { + else if (enabled && !enable) reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - } else { - printk(KERN_WARNING DRV_NAME - ": bad value in membar_int_ctrl reg=0x%x\n", reg); + else return; - } + iowrite32(reg, addr); } @@ -1981,12 +1980,6 @@ static int __init be_init_module(void) " Using 2048\n"); rx_frag_size = 2048; } - /* Ensure rx_frag_size is aligned to chache line */ - if (SKB_DATA_ALIGN(rx_frag_size) != rx_frag_size) { - printk(KERN_WARNING DRV_NAME - " : Bad module param rx_frag_size. Using 2048\n"); - rx_frag_size = 2048; - } return pci_register_driver(&be_driver); } -- cgit v0.10.2 From efd2e40a8cc891e8f90e0bdde000006bd6201530 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 27 Jul 2009 22:53:10 +0000 Subject: be2net: some name changes for consistency be_mbox_db_ring() has been changed to be_mbox_notify() (to be consistent with be_mcc_notify()) and struct be_mcc_cq_entry changed to be_mcc_compl to be consistent with rx/tx_compl. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 7c1724e..ebf65c7 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -31,7 +31,7 @@ static void be_mcc_notify(struct be_adapter *adapter) /* To check if valid bit is set, check the entire word as we don't know * the endianness of the data (old entry is host endian while a new entry is * little endian) */ -static inline bool be_mcc_compl_is_new(struct be_mcc_cq_entry *compl) +static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) { if (compl->flags != 0) { compl->flags = le32_to_cpu(compl->flags); @@ -43,13 +43,13 @@ static inline bool be_mcc_compl_is_new(struct be_mcc_cq_entry *compl) } /* Need to reset the entire word that houses the valid bit */ -static inline void be_mcc_compl_use(struct be_mcc_cq_entry *compl) +static inline void be_mcc_compl_use(struct be_mcc_compl *compl) { compl->flags = 0; } static int be_mcc_compl_process(struct be_adapter *adapter, - struct be_mcc_cq_entry *compl) + struct be_mcc_compl *compl) { u16 compl_status, extd_status; @@ -85,10 +85,10 @@ static inline bool is_link_state_evt(u32 trailer) ASYNC_EVENT_CODE_LINK_STATE); } -static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_adapter *adapter) +static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) { struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq; - struct be_mcc_cq_entry *compl = queue_tail_node(mcc_cq); + struct be_mcc_compl *compl = queue_tail_node(mcc_cq); if (be_mcc_compl_is_new(compl)) { queue_tail_inc(mcc_cq); @@ -99,7 +99,7 @@ static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_adapter *adapter) void be_process_mcc(struct be_adapter *adapter) { - struct be_mcc_cq_entry *compl; + struct be_mcc_compl *compl; int num = 0; spin_lock_bh(&adapter->mcc_cq_lock); @@ -173,16 +173,16 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) * Insert the mailbox address into the doorbell in two steps * Polls on the mbox doorbell till a command completion (or a timeout) occurs */ -static int be_mbox_db_ring(struct be_adapter *adapter) +static int be_mbox_notify(struct be_adapter *adapter) { int status; u32 val = 0; void __iomem *db = adapter->db + MPU_MAILBOX_DB_OFFSET; struct be_dma_mem *mbox_mem = &adapter->mbox_mem; struct be_mcc_mailbox *mbox = mbox_mem->va; - struct be_mcc_cq_entry *cqe = &mbox->cqe; + struct be_mcc_compl *compl = &mbox->compl; - memset(cqe, 0, sizeof(*cqe)); + memset(compl, 0, sizeof(*compl)); val |= MPU_MAILBOX_DB_HI_MASK; /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ @@ -204,9 +204,9 @@ static int be_mbox_db_ring(struct be_adapter *adapter) return status; /* A cq entry has been made now */ - if (be_mcc_compl_is_new(cqe)) { - status = be_mcc_compl_process(adapter, &mbox->cqe); - be_mcc_compl_use(cqe); + if (be_mcc_compl_is_new(compl)) { + status = be_mcc_compl_process(adapter, &mbox->compl); + be_mcc_compl_use(compl); if (status) return status; } else { @@ -396,7 +396,7 @@ int be_cmd_eq_create(struct be_adapter *adapter, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { eq->id = le16_to_cpu(resp->eq_id); eq->created = true; @@ -429,7 +429,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, req->permanent = 0; } - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) memcpy(mac_addr, resp->mac.addr, ETH_ALEN); @@ -455,7 +455,7 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, req->if_id = cpu_to_le32(if_id); memcpy(req->mac_address, mac_addr, ETH_ALEN); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_pmac_add *resp = embedded_payload(wrb); *pmac_id = le32_to_cpu(resp->pmac_id); @@ -482,7 +482,7 @@ int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id) req->if_id = cpu_to_le32(if_id); req->pmac_id = cpu_to_le32(pmac_id); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); return status; @@ -523,7 +523,7 @@ int be_cmd_cq_create(struct be_adapter *adapter, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { cq->id = le16_to_cpu(resp->cq_id); cq->created = true; @@ -571,7 +571,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); mccq->id = le16_to_cpu(resp->id); @@ -618,7 +618,7 @@ int be_cmd_txq_create(struct be_adapter *adapter, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb); txq->id = le16_to_cpu(resp->cid); @@ -654,7 +654,7 @@ int be_cmd_rxq_create(struct be_adapter *adapter, req->max_frame_size = cpu_to_le16(max_frame_size); req->rss_queue = cpu_to_le32(rss); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb); rxq->id = le16_to_cpu(resp->id); @@ -706,7 +706,7 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); req->id = cpu_to_le16(q->id); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); @@ -734,7 +734,7 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 flags, u8 *mac, if (!pmac_invalid) memcpy(req->mac_addr, mac, ETH_ALEN); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_if_create *resp = embedded_payload(wrb); *if_handle = le32_to_cpu(resp->interface_id); @@ -761,7 +761,7 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req)); req->interface_id = cpu_to_le32(interface_id); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); @@ -791,7 +791,7 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); sge->len = cpu_to_le32(nonemb_cmd->size); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_get_stats *resp = nonemb_cmd->va; be_dws_le_to_cpu(&resp->hw_stats, sizeof(resp->hw_stats)); @@ -818,7 +818,7 @@ int be_cmd_link_status_query(struct be_adapter *adapter, be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req)); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_link_status *resp = embedded_payload(wrb); if (resp->mac_speed != PHY_LINK_SPEED_ZERO) @@ -843,7 +843,7 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_FW_VERSION, sizeof(*req)); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb); strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN); @@ -873,7 +873,7 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd) req->delay[0].phase = 0; req->delay[0].delay_multiplier = cpu_to_le32(eqd); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); return status; @@ -903,7 +903,7 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, req->num_vlan * sizeof(vtag_array[0])); } - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); return status; @@ -999,7 +999,7 @@ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) req->tx_flow_control = cpu_to_le16((u16)tx_fc); req->rx_flow_control = cpu_to_le16((u16)rx_fc); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); return status; @@ -1020,7 +1020,7 @@ int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req)); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_get_flow_control *resp = embedded_payload(wrb); @@ -1047,7 +1047,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req)); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb); *port_num = le32_to_cpu(resp->phys_port); diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 164ab92..5c5de35 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -69,7 +69,7 @@ enum { #define CQE_STATUS_EXTD_MASK 0xFFFF #define CQE_STATUS_EXTD_SHIFT 0 /* bits 0 - 15 */ -struct be_mcc_cq_entry { +struct be_mcc_compl { u32 status; /* dword 0 */ u32 tag0; /* dword 1 */ u32 tag1; /* dword 2 */ @@ -106,7 +106,7 @@ struct be_async_event_link_state { struct be_mcc_mailbox { struct be_mcc_wrb wrb; - struct be_mcc_cq_entry cqe; + struct be_mcc_compl compl; }; #define CMD_SUBSYSTEM_COMMON 0x1 diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index ab5fcc0..ef82a52 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1058,7 +1058,7 @@ static int be_mcc_queues_create(struct be_adapter *adapter) /* Alloc MCC compl queue */ cq = &adapter->mcc_obj.cq; if (be_queue_alloc(adapter, cq, MCC_CQ_LEN, - sizeof(struct be_mcc_cq_entry))) + sizeof(struct be_mcc_compl))) goto err; /* Ask BE to create MCC compl queue; share TX's eq */ -- cgit v0.10.2 From d9509ac1295ce2ec121333d29b8a85a9e564f817 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 27 Jul 2009 22:53:30 +0000 Subject: be2net: delete unnecessary code from be_cmd_POST() When the driver loads the POST stage of the card is expected to be POST_STAGE_ARMFW_RDY. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index ebf65c7..de10773 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -227,54 +227,17 @@ static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage) return 0; } -static int be_POST_stage_poll(struct be_adapter *adapter, u16 poll_stage) -{ - u16 stage, cnt, error; - for (cnt = 0; cnt < 5000; cnt++) { - error = be_POST_stage_get(adapter, &stage); - if (error) - return -1; - - if (stage == poll_stage) - break; - udelay(1000); - } - if (stage != poll_stage) - return -1; - return 0; -} - - int be_cmd_POST(struct be_adapter *adapter) { u16 stage, error; error = be_POST_stage_get(adapter, &stage); - if (error) - goto err; - - if (stage == POST_STAGE_ARMFW_RDY) - return 0; - - if (stage != POST_STAGE_AWAITING_HOST_RDY) - goto err; - - /* On awaiting host rdy, reset and again poll on awaiting host rdy */ - iowrite32(POST_STAGE_BE_RESET, adapter->csr + MPU_EP_SEMAPHORE_OFFSET); - error = be_POST_stage_poll(adapter, POST_STAGE_AWAITING_HOST_RDY); - if (error) - goto err; - - /* Now kickoff POST and poll on armfw ready */ - iowrite32(POST_STAGE_HOST_RDY, adapter->csr + MPU_EP_SEMAPHORE_OFFSET); - error = be_POST_stage_poll(adapter, POST_STAGE_ARMFW_RDY); - if (error) - goto err; + if (error || stage != POST_STAGE_ARMFW_RDY) { + dev_err(&adapter->pdev->dev, "POST failed.\n"); + return -1; + } return 0; -err: - printk(KERN_WARNING DRV_NAME ": ERROR, stage=%d\n", stage); - return -1; } static inline void *embedded_payload(struct be_mcc_wrb *wrb) -- cgit v0.10.2 From 005fb4f0330afb2916ddc3f3c4c70e4555d64758 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:02 +0000 Subject: atl1c: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for atl1c. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index a383122..1d601ce 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -2678,6 +2678,9 @@ static pci_ers_result_t atl1c_io_error_detected(struct pci_dev *pdev, netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) atl1c_down(adapter); -- cgit v0.10.2 From 0d6ab58da0465c42f34d9d4e7d91510278183c80 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:10 +0000 Subject: atl1e: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for atl1e. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 9fc6d6d..4570749 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -2497,6 +2497,9 @@ atl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) atl1e_down(adapter); -- cgit v0.10.2 From 2ec3de26d2dc666159b79a8b9394fa00b6f414ae Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:18 +0000 Subject: bnx2: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for bnx2. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index cec1b17..756d4b4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -8199,6 +8199,11 @@ static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev, rtnl_lock(); netif_device_detach(dev); + if (state == pci_channel_io_perm_failure) { + rtnl_unlock(); + return PCI_ERS_RESULT_DISCONNECT; + } + if (netif_running(dev)) { bnx2_netif_stop(bp); del_timer_sync(&bp->timer); -- cgit v0.10.2 From 07ce50e434b62c4de05207109ecd3d615b3cce42 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:25 +0000 Subject: bnx2x: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for bnx2x. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 2d035d7..c92d1a4 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11690,6 +11690,11 @@ static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev, netif_device_detach(dev); + if (state == pci_channel_io_perm_failure) { + rtnl_unlock(); + return PCI_ERS_RESULT_DISCONNECT; + } + if (netif_running(dev)) bnx2x_eeh_nic_unload(bp); -- cgit v0.10.2 From c06c430dedf71a0e9180d673191b9c9368aeaa65 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:33 +0000 Subject: igbvf: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for igbvf. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 926c31b..3f03c42 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2511,6 +2511,9 @@ static pci_ers_result_t igbvf_io_error_detected(struct pci_dev *pdev, netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) igbvf_down(adapter); pci_disable_device(pdev); -- cgit v0.10.2 From d6a1f83b63e6999ee9374330ea2d7924e775aff7 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:40 +0000 Subject: ixgb: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for ixgb. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index eb917f1..fad08ce 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -2227,6 +2227,11 @@ static pci_ers_result_t ixgb_io_error_detected(struct pci_dev *pdev, struct net_device *netdev = pci_get_drvdata(pdev); struct ixgb_adapter *adapter = netdev_priv(netdev); + netif_device_detach(netdev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) ixgb_down(adapter, true); -- cgit v0.10.2 From fbc663ceeb7a48481a3b0290040528fbfd207282 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:48 +0000 Subject: qlge: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for qlge. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 5768af1..3a271af 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4076,6 +4076,11 @@ static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev, struct net_device *ndev = pci_get_drvdata(pdev); struct ql_adapter *qdev = netdev_priv(ndev); + netif_device_detach(ndev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(ndev)) ql_adapter_down(qdev); -- cgit v0.10.2 From 1e3c8bd63854a620680323681f28e60a44e26f0e Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:56 +0000 Subject: s2io: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for s2io. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index d4df933..bd6d713 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -8636,6 +8636,9 @@ static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) { /* Bring down the card, while avoiding PCI I/O */ do_s2io_card_down(sp, 0); -- cgit v0.10.2 From e33b992d1504f21a8c2173245aeca4fc2ad632ab Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:14:03 +0000 Subject: vxge: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for vxge. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 7b5402b..335140d 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -3956,6 +3956,9 @@ static pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev, netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) { /* Bring down the card, while avoiding PCI I/O */ do_vxge_close(netdev, 0); -- cgit v0.10.2 From c1dc0b9c0c8979ce4d411caadff5c0d79dee58bc Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 2 Aug 2009 11:28:21 +0200 Subject: debug lockups: Improve lockup detection When debugging a recent lockup bug i found various deficiencies in how our current lockup detection helpers work: - SysRq-L is not very efficient as it uses a workqueue, hence it cannot punch through hard lockups and cannot see through most soft lockups either. - The SysRq-L code depends on the NMI watchdog - which is off by default. - We dont print backtraces from the RCU code's built-in 'RCU state machine is stuck' debug code. This debug code tends to be one of the first (and only) mechanisms that show that a lockup has occured. This patch changes the code so taht we: - Trigger the NMI backtrace code from SysRq-L instead of using a workqueue (which cannot punch through hard lockups) - Trigger print-all-CPU-backtraces from the RCU lockup detection code Also decouple the backtrace printing code from the NMI watchdog: - Dont use variable size cpumasks (it might not be initialized and they are a bit more fragile anyway) - Trigger an NMI immediately via an IPI, instead of waiting for the NMI tick to occur. This is a lot faster and can produce more relevant backtraces. It will also work if the NMI watchdog is disabled. - Dont print the 'dazed and confused' message when we print a backtrace from the NMI - Do a show_regs() plus a dump_stack() to get maximum info out of the dump. Worst-case we get two stacktraces - which is not a big deal. Sometimes, if register content is corrupted, the precise stack walker in show_regs() wont give us a full backtrace - in this case dump_stack() will do it. Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Andrew Morton Cc: Linus Torvalds LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/nmi.c b/arch/x86/kernel/apic/nmi.c index b3025b4..1bb1ac2 100644 --- a/arch/x86/kernel/apic/nmi.c +++ b/arch/x86/kernel/apic/nmi.c @@ -39,7 +39,7 @@ int unknown_nmi_panic; int nmi_watchdog_enabled; -static cpumask_var_t backtrace_mask; +static cpumask_t backtrace_mask __read_mostly; /* nmi_active: * >0: the lapic NMI watchdog is active, but can be disabled @@ -138,7 +138,6 @@ int __init check_nmi_watchdog(void) if (!prev_nmi_count) goto error; - alloc_cpumask_var(&backtrace_mask, GFP_KERNEL|__GFP_ZERO); printk(KERN_INFO "Testing NMI watchdog ... "); #ifdef CONFIG_SMP @@ -415,14 +414,17 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason) } /* We can be called before check_nmi_watchdog, hence NULL check. */ - if (backtrace_mask != NULL && cpumask_test_cpu(cpu, backtrace_mask)) { + if (cpumask_test_cpu(cpu, &backtrace_mask)) { static DEFINE_SPINLOCK(lock); /* Serialise the printks */ spin_lock(&lock); printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu); + show_regs(regs); dump_stack(); spin_unlock(&lock); - cpumask_clear_cpu(cpu, backtrace_mask); + cpumask_clear_cpu(cpu, &backtrace_mask); + + rc = 1; } /* Could check oops_in_progress here too, but it's safer not to */ @@ -556,10 +558,14 @@ void __trigger_all_cpu_backtrace(void) { int i; - cpumask_copy(backtrace_mask, cpu_online_mask); + cpumask_copy(&backtrace_mask, cpu_online_mask); + + printk(KERN_INFO "sending NMI to all CPUs:\n"); + apic->send_IPI_all(NMI_VECTOR); + /* Wait for up to 10 seconds for all CPUs to do the backtrace */ for (i = 0; i < 10 * 1000; i++) { - if (cpumask_empty(backtrace_mask)) + if (cpumask_empty(&backtrace_mask)) break; mdelay(1); } diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 5d7a02f..165f307 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -222,12 +223,7 @@ static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus); static void sysrq_handle_showallcpus(int key, struct tty_struct *tty) { - struct pt_regs *regs = get_irq_regs(); - if (regs) { - printk(KERN_INFO "CPU%d:\n", smp_processor_id()); - show_regs(regs); - } - schedule_work(&sysrq_showallcpus); + trigger_all_cpu_backtrace(); } static struct sysrq_key_op sysrq_showallcpus_op = { diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 7717b95..9c5fa9f 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -469,6 +470,8 @@ static void print_other_cpu_stall(struct rcu_state *rsp) } printk(" (detected by %d, t=%ld jiffies)\n", smp_processor_id(), (long)(jiffies - rsp->gp_start)); + trigger_all_cpu_backtrace(); + force_quiescent_state(rsp, 0); /* Kick them all. */ } @@ -479,12 +482,14 @@ static void print_cpu_stall(struct rcu_state *rsp) printk(KERN_ERR "INFO: RCU detected CPU %d stall (t=%lu jiffies)\n", smp_processor_id(), jiffies - rsp->gp_start); - dump_stack(); + trigger_all_cpu_backtrace(); + spin_lock_irqsave(&rnp->lock, flags); if ((long)(jiffies - rsp->jiffies_stall) >= 0) rsp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_RECHECK; spin_unlock_irqrestore(&rnp->lock, flags); + set_need_resched(); /* kick ourselves to get things going. */ } -- cgit v0.10.2 From 716a42348cdaf04534b15fbdc9c83e25baebfed5 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 24 Jul 2009 20:05:23 +0200 Subject: sched: Fix cond_resched_lock() in !CONFIG_PREEMPT The might_sleep() test inside cond_resched_lock() assumes the spinlock is held and then preemption is disabled. This is true with CONFIG_PREEMPT but the preempt_count() doesn't change otherwise. Check by starting from the appropriate preempt offset depending on the config. Reported-by: Li Zefan Signed-off-by: Frederic Weisbecker Signed-off-by: Peter Zijlstra LKML-Reference: <1248458723-12146-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index cbbfca6..c472414 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2293,8 +2293,14 @@ extern int _cond_resched(void); extern int __cond_resched_lock(spinlock_t *lock); +#ifdef CONFIG_PREEMPT +#define PREEMPT_LOCK_OFFSET PREEMPT_OFFSET +#else +#define PREEMPT_LOCK_OFFSET 0 +#endif + #define cond_resched_lock(lock) ({ \ - __might_sleep(__FILE__, __LINE__, PREEMPT_OFFSET); \ + __might_sleep(__FILE__, __LINE__, PREEMPT_LOCK_OFFSET); \ __cond_resched_lock(lock); \ }) -- cgit v0.10.2 From a5004278f0525dcb9aa43703ef77bf371ea837cd Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 27 Jul 2009 14:04:49 +0200 Subject: sched: Fix cgroup smp fairness Commit ec4e0e2fe018992d980910db901637c814575914 ("fix inconsistency when redistribute per-cpu tg->cfs_rq shares") broke cgroup smp fairness. In order to avoid starvation of newly placed tasks, we never quite set the share of an empty cpu group-task to 0, but instead we set it as if there's a single NICE-0 task present. If however we actually set this in cfs_rq[cpu]->shares, that means the total shares for that group will be slightly inflated every time we balance, causing the observed unfairness. Fix this by setting cfs_rq[cpu]->shares to 0 but actually setting the effective weight of the related se to the inflated number. Signed-off-by: Peter Zijlstra LKML-Reference: <1248696557.6987.1615.camel@twins> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index ce1056e..26976cd 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1523,13 +1523,18 @@ static void update_group_shares_cpu(struct task_group *tg, int cpu, unsigned long sd_shares, unsigned long sd_rq_weight) { - unsigned long shares; unsigned long rq_weight; + unsigned long shares; + int boost = 0; if (!tg->se[cpu]) return; rq_weight = tg->cfs_rq[cpu]->rq_weight; + if (!rq_weight) { + boost = 1; + rq_weight = NICE_0_LOAD; + } /* * \Sum shares * rq_weight @@ -1546,8 +1551,7 @@ update_group_shares_cpu(struct task_group *tg, int cpu, unsigned long flags; spin_lock_irqsave(&rq->lock, flags); - tg->cfs_rq[cpu]->shares = shares; - + tg->cfs_rq[cpu]->shares = boost ? 0 : shares; __set_se_shares(tg->se[cpu], shares); spin_unlock_irqrestore(&rq->lock, flags); } @@ -1560,7 +1564,7 @@ update_group_shares_cpu(struct task_group *tg, int cpu, */ static int tg_shares_up(struct task_group *tg, void *data) { - unsigned long weight, rq_weight = 0; + unsigned long weight, rq_weight = 0, eff_weight = 0; unsigned long shares = 0; struct sched_domain *sd = data; int i; @@ -1572,11 +1576,13 @@ static int tg_shares_up(struct task_group *tg, void *data) * run here it will not get delayed by group starvation. */ weight = tg->cfs_rq[i]->load.weight; + tg->cfs_rq[i]->rq_weight = weight; + rq_weight += weight; + if (!weight) weight = NICE_0_LOAD; - tg->cfs_rq[i]->rq_weight = weight; - rq_weight += weight; + eff_weight += weight; shares += tg->cfs_rq[i]->shares; } @@ -1586,8 +1592,14 @@ static int tg_shares_up(struct task_group *tg, void *data) if (!sd->parent || !(sd->parent->flags & SD_LOAD_BALANCE)) shares = tg->shares; - for_each_cpu(i, sched_domain_span(sd)) - update_group_shares_cpu(tg, i, shares, rq_weight); + for_each_cpu(i, sched_domain_span(sd)) { + unsigned long sd_rq_weight = rq_weight; + + if (!tg->cfs_rq[i]->rq_weight) + sd_rq_weight = eff_weight; + + update_group_shares_cpu(tg, i, shares, sd_rq_weight); + } return 0; } -- cgit v0.10.2 From e709715915d69b6a929d77e7652c9c3fea61c317 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 3 Jun 2009 15:41:20 +0200 Subject: sched: Optimize unused cgroup configuration When cgroup group scheduling is built in, skip some code paths if we don't have any (but the root) cgroups configured. Signed-off-by: Peter Zijlstra Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 26976cd..ca1f76b 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1629,8 +1629,14 @@ static int tg_load_down(struct task_group *tg, void *data) static void update_shares(struct sched_domain *sd) { - u64 now = cpu_clock(raw_smp_processor_id()); - s64 elapsed = now - sd->last_update; + s64 elapsed; + u64 now; + + if (root_task_group_empty()) + return; + + now = cpu_clock(raw_smp_processor_id()); + elapsed = now - sd->last_update; if (elapsed >= (s64)(u64)sysctl_sched_shares_ratelimit) { sd->last_update = now; @@ -1640,6 +1646,9 @@ static void update_shares(struct sched_domain *sd) static void update_shares_locked(struct rq *rq, struct sched_domain *sd) { + if (root_task_group_empty()) + return; + spin_unlock(&rq->lock); update_shares(sd); spin_lock(&rq->lock); @@ -1647,6 +1656,9 @@ static void update_shares_locked(struct rq *rq, struct sched_domain *sd) static void update_h_load(long cpu) { + if (root_task_group_empty()) + return; + walk_tg_tree(tg_load_down, tg_nop, (void *)cpu); } -- cgit v0.10.2 From da19ab510343c6496fe8b8f890091296032025c9 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 29 Jul 2009 00:21:22 -0400 Subject: sched: Check for pushing rt tasks after all scheduling The current method for pushing RT tasks after scheduling only happens after a context switch. But we found cases where a task is set up on a run queue to be pushed but the push never happens because the schedule chooses the same task. This bug was found with the help of Gregory Haskins and the use of ftrace (trace_printk). It tooks several days for both of us analyzing the code and the trace output to find this. Signed-off-by: Steven Rostedt Signed-off-by: Peter Zijlstra LKML-Reference: <20090729042526.205923666@goodmis.org> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index ca1f76b..a030d45 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2839,14 +2839,14 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev, * with the lock held can cause deadlocks; see schedule() for * details.) */ -static void finish_task_switch(struct rq *rq, struct task_struct *prev) +static int finish_task_switch(struct rq *rq, struct task_struct *prev) __releases(rq->lock) { struct mm_struct *mm = rq->prev_mm; long prev_state; -#ifdef CONFIG_SMP int post_schedule = 0; +#ifdef CONFIG_SMP if (current->sched_class->needs_post_schedule) post_schedule = current->sched_class->needs_post_schedule(rq); #endif @@ -2868,10 +2868,6 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) finish_arch_switch(prev); perf_counter_task_sched_in(current, cpu_of(rq)); finish_lock_switch(rq, prev); -#ifdef CONFIG_SMP - if (post_schedule) - current->sched_class->post_schedule(rq); -#endif fire_sched_in_preempt_notifiers(current); if (mm) @@ -2884,6 +2880,8 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) kprobe_flush_task(prev); put_task_struct(prev); } + + return post_schedule; } /** @@ -2894,8 +2892,15 @@ asmlinkage void schedule_tail(struct task_struct *prev) __releases(rq->lock) { struct rq *rq = this_rq(); + int post_schedule; + + post_schedule = finish_task_switch(rq, prev); + +#ifdef CONFIG_SMP + if (post_schedule) + current->sched_class->post_schedule(rq); +#endif - finish_task_switch(rq, prev); #ifdef __ARCH_WANT_UNLOCKED_CTXSW /* In this case, finish_task_switch does not reenable preemption */ preempt_enable(); @@ -2908,7 +2913,7 @@ asmlinkage void schedule_tail(struct task_struct *prev) * context_switch - switch to the new MM and the new * thread's register state. */ -static inline void +static inline int context_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next) { @@ -2955,7 +2960,7 @@ context_switch(struct rq *rq, struct task_struct *prev, * CPUs since it called schedule(), thus the 'rq' on its stack * frame will be invalid. */ - finish_task_switch(this_rq(), prev); + return finish_task_switch(this_rq(), prev); } /* @@ -5366,6 +5371,7 @@ asmlinkage void __sched schedule(void) { struct task_struct *prev, *next; unsigned long *switch_count; + int post_schedule = 0; struct rq *rq; int cpu; @@ -5416,15 +5422,25 @@ need_resched_nonpreemptible: rq->curr = next; ++*switch_count; - context_switch(rq, prev, next); /* unlocks the rq */ + post_schedule = context_switch(rq, prev, next); /* unlocks the rq */ /* * the context switch might have flipped the stack from under * us, hence refresh the local variables. */ cpu = smp_processor_id(); rq = cpu_rq(cpu); - } else + } else { +#ifdef CONFIG_SMP + if (current->sched_class->needs_post_schedule) + post_schedule = current->sched_class->needs_post_schedule(rq); +#endif spin_unlock_irq(&rq->lock); + } + +#ifdef CONFIG_SMP + if (post_schedule) + current->sched_class->post_schedule(rq); +#endif if (unlikely(reacquire_kernel_lock(current) < 0)) goto need_resched_nonpreemptible; -- cgit v0.10.2 From c3a2ae3d93c0f10d29c071f599764d00b8de00cb Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 29 Jul 2009 00:21:23 -0400 Subject: sched: Add new prio to cpupri before removing old prio We need to add the new prio to the cpupri accounting before removing the old prio. This is because removing the old prio first will open a race window where the cpu will be removed from pri_active. In this case the cpu will not be visible for RT push and pulls. This could cause a RT task to not migrate appropriately, and create a very large latency. This bug was found with the use of ftrace sched events and trace_printk. Signed-off-by: Steven Rostedt Signed-off-by: Peter Zijlstra LKML-Reference: <20090729042526.438281019@goodmis.org> Signed-off-by: Ingo Molnar diff --git a/kernel/sched_cpupri.c b/kernel/sched_cpupri.c index d014efb..0f052fc 100644 --- a/kernel/sched_cpupri.c +++ b/kernel/sched_cpupri.c @@ -127,21 +127,11 @@ void cpupri_set(struct cpupri *cp, int cpu, int newpri) /* * If the cpu was currently mapped to a different value, we - * first need to unmap the old value + * need to map it to the new value then remove the old value. + * Note, we must add the new value first, otherwise we risk the + * cpu being cleared from pri_active, and this cpu could be + * missed for a push or pull. */ - if (likely(oldpri != CPUPRI_INVALID)) { - struct cpupri_vec *vec = &cp->pri_to_cpu[oldpri]; - - spin_lock_irqsave(&vec->lock, flags); - - vec->count--; - if (!vec->count) - clear_bit(oldpri, cp->pri_active); - cpumask_clear_cpu(cpu, vec->mask); - - spin_unlock_irqrestore(&vec->lock, flags); - } - if (likely(newpri != CPUPRI_INVALID)) { struct cpupri_vec *vec = &cp->pri_to_cpu[newpri]; @@ -154,6 +144,18 @@ void cpupri_set(struct cpupri *cp, int cpu, int newpri) spin_unlock_irqrestore(&vec->lock, flags); } + if (likely(oldpri != CPUPRI_INVALID)) { + struct cpupri_vec *vec = &cp->pri_to_cpu[oldpri]; + + spin_lock_irqsave(&vec->lock, flags); + + vec->count--; + if (!vec->count) + clear_bit(oldpri, cp->pri_active); + cpumask_clear_cpu(cpu, vec->mask); + + spin_unlock_irqrestore(&vec->lock, flags); + } *currpri = newpri; } -- cgit v0.10.2 From 3f029d3c6d62068d59301d90c18dbde8ee402107 Mon Sep 17 00:00:00 2001 From: Gregory Haskins Date: Wed, 29 Jul 2009 11:08:47 -0400 Subject: sched: Enhance the pre/post scheduling logic We currently have an explicit "needs_post" vtable method which returns a stack variable for whether we should later run post-schedule. This leads to an awkward exchange of the variable as it bubbles back up out of the context switch. Peter Zijlstra observed that this information could be stored in the run-queue itself instead of handled on the stack. Therefore, we revert to the method of having context_switch return void, and update an internal rq->post_schedule variable when we require further processing. In addition, we fix a race condition where we try to access current->sched_class without holding the rq->lock. This is technically racy, as the sched-class could change out from under us. Instead, we reference the per-rq post_schedule variable with the runqueue unlocked, but with preemption disabled to see if we need to reacquire the rq->lock. Finally, we clean the code up slightly by removing the #ifdef CONFIG_SMP conditionals from the schedule() call, and implement some inline helper functions instead. This patch passes checkpatch, and rt-migrate. Signed-off-by: Gregory Haskins Signed-off-by: Peter Zijlstra LKML-Reference: <20090729150422.17691.55590.stgit@dev.haskins.net> Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 2c35bc2..195d72d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1047,7 +1047,6 @@ struct sched_class { struct rq *busiest, struct sched_domain *sd, enum cpu_idle_type idle); void (*pre_schedule) (struct rq *this_rq, struct task_struct *task); - int (*needs_post_schedule) (struct rq *this_rq); void (*post_schedule) (struct rq *this_rq); void (*task_wake_up) (struct rq *this_rq, struct task_struct *task); diff --git a/kernel/sched.c b/kernel/sched.c index a030d45..613fee5 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -616,6 +616,7 @@ struct rq { unsigned char idle_at_tick; /* For active balancing */ + int post_schedule; int active_balance; int push_cpu; /* cpu of this runqueue: */ @@ -2839,17 +2840,11 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev, * with the lock held can cause deadlocks; see schedule() for * details.) */ -static int finish_task_switch(struct rq *rq, struct task_struct *prev) +static void finish_task_switch(struct rq *rq, struct task_struct *prev) __releases(rq->lock) { struct mm_struct *mm = rq->prev_mm; long prev_state; - int post_schedule = 0; - -#ifdef CONFIG_SMP - if (current->sched_class->needs_post_schedule) - post_schedule = current->sched_class->needs_post_schedule(rq); -#endif rq->prev_mm = NULL; @@ -2880,10 +2875,44 @@ static int finish_task_switch(struct rq *rq, struct task_struct *prev) kprobe_flush_task(prev); put_task_struct(prev); } +} + +#ifdef CONFIG_SMP + +/* assumes rq->lock is held */ +static inline void pre_schedule(struct rq *rq, struct task_struct *prev) +{ + if (prev->sched_class->pre_schedule) + prev->sched_class->pre_schedule(rq, prev); +} + +/* rq->lock is NOT held, but preemption is disabled */ +static inline void post_schedule(struct rq *rq) +{ + if (rq->post_schedule) { + unsigned long flags; + + spin_lock_irqsave(&rq->lock, flags); + if (rq->curr->sched_class->post_schedule) + rq->curr->sched_class->post_schedule(rq); + spin_unlock_irqrestore(&rq->lock, flags); + + rq->post_schedule = 0; + } +} + +#else - return post_schedule; +static inline void pre_schedule(struct rq *rq, struct task_struct *p) +{ +} + +static inline void post_schedule(struct rq *rq) +{ } +#endif + /** * schedule_tail - first thing a freshly forked thread must call. * @prev: the thread we just switched away from. @@ -2892,14 +2921,14 @@ asmlinkage void schedule_tail(struct task_struct *prev) __releases(rq->lock) { struct rq *rq = this_rq(); - int post_schedule; - post_schedule = finish_task_switch(rq, prev); + finish_task_switch(rq, prev); -#ifdef CONFIG_SMP - if (post_schedule) - current->sched_class->post_schedule(rq); -#endif + /* + * FIXME: do we need to worry about rq being invalidated by the + * task_switch? + */ + post_schedule(rq); #ifdef __ARCH_WANT_UNLOCKED_CTXSW /* In this case, finish_task_switch does not reenable preemption */ @@ -2913,7 +2942,7 @@ asmlinkage void schedule_tail(struct task_struct *prev) * context_switch - switch to the new MM and the new * thread's register state. */ -static inline int +static inline void context_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next) { @@ -2960,7 +2989,7 @@ context_switch(struct rq *rq, struct task_struct *prev, * CPUs since it called schedule(), thus the 'rq' on its stack * frame will be invalid. */ - return finish_task_switch(this_rq(), prev); + finish_task_switch(this_rq(), prev); } /* @@ -5371,7 +5400,6 @@ asmlinkage void __sched schedule(void) { struct task_struct *prev, *next; unsigned long *switch_count; - int post_schedule = 0; struct rq *rq; int cpu; @@ -5403,10 +5431,7 @@ need_resched_nonpreemptible: switch_count = &prev->nvcsw; } -#ifdef CONFIG_SMP - if (prev->sched_class->pre_schedule) - prev->sched_class->pre_schedule(rq, prev); -#endif + pre_schedule(rq, prev); if (unlikely(!rq->nr_running)) idle_balance(cpu, rq); @@ -5422,25 +5447,17 @@ need_resched_nonpreemptible: rq->curr = next; ++*switch_count; - post_schedule = context_switch(rq, prev, next); /* unlocks the rq */ + context_switch(rq, prev, next); /* unlocks the rq */ /* * the context switch might have flipped the stack from under * us, hence refresh the local variables. */ cpu = smp_processor_id(); rq = cpu_rq(cpu); - } else { -#ifdef CONFIG_SMP - if (current->sched_class->needs_post_schedule) - post_schedule = current->sched_class->needs_post_schedule(rq); -#endif + } else spin_unlock_irq(&rq->lock); - } -#ifdef CONFIG_SMP - if (post_schedule) - current->sched_class->post_schedule(rq); -#endif + post_schedule(rq); if (unlikely(reacquire_kernel_lock(current) < 0)) goto need_resched_nonpreemptible; @@ -9403,6 +9420,7 @@ void __init sched_init(void) #ifdef CONFIG_SMP rq->sd = NULL; rq->rd = NULL; + rq->post_schedule = 0; rq->active_balance = 0; rq->next_balance = jiffies; rq->push_cpu = 0; diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index 3918e01..a8f89bc 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -1056,6 +1056,11 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq) return p; } +static inline int has_pushable_tasks(struct rq *rq) +{ + return !plist_head_empty(&rq->rt.pushable_tasks); +} + static struct task_struct *pick_next_task_rt(struct rq *rq) { struct task_struct *p = _pick_next_task_rt(rq); @@ -1064,6 +1069,12 @@ static struct task_struct *pick_next_task_rt(struct rq *rq) if (p) dequeue_pushable_task(rq, p); + /* + * We detect this state here so that we can avoid taking the RQ + * lock again later if there is no need to push + */ + rq->post_schedule = has_pushable_tasks(rq); + return p; } @@ -1262,11 +1273,6 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq) return lowest_rq; } -static inline int has_pushable_tasks(struct rq *rq) -{ - return !plist_head_empty(&rq->rt.pushable_tasks); -} - static struct task_struct *pick_next_pushable_task(struct rq *rq) { struct task_struct *p; @@ -1466,23 +1472,9 @@ static void pre_schedule_rt(struct rq *rq, struct task_struct *prev) pull_rt_task(rq); } -/* - * assumes rq->lock is held - */ -static int needs_post_schedule_rt(struct rq *rq) -{ - return has_pushable_tasks(rq); -} - static void post_schedule_rt(struct rq *rq) { - /* - * This is only called if needs_post_schedule_rt() indicates that - * we need to push tasks away - */ - spin_lock_irq(&rq->lock); push_rt_tasks(rq); - spin_unlock_irq(&rq->lock); } /* @@ -1758,7 +1750,6 @@ static const struct sched_class rt_sched_class = { .rq_online = rq_online_rt, .rq_offline = rq_offline_rt, .pre_schedule = pre_schedule_rt, - .needs_post_schedule = needs_post_schedule_rt, .post_schedule = post_schedule_rt, .task_wake_up = task_wake_up_rt, .switched_from = switched_from_rt, -- cgit v0.10.2 From 00aec93d10a051ea64f83eff75d4065a19508ea6 Mon Sep 17 00:00:00 2001 From: Gregory Haskins Date: Thu, 30 Jul 2009 10:57:23 -0400 Subject: sched: Fully integrate cpus_active_map and root-domain code Reflect "active" cpus in the rq->rd->online field, instead of the online_map. The motivation is that things that use the root-domain code (such as cpupri) only care about cpus classified as "active" anyway. By synchronizing the root-domain state with the active map, we allow several optimizations. For instance, we can remove an extra cpumask_and from the scheduler hotpath by utilizing rq->rd->online (since it is now a cached version of cpu_active_map & rq->rd->span). Signed-off-by: Gregory Haskins Acked-by: Peter Zijlstra Acked-by: Max Krasnyansky Signed-off-by: Peter Zijlstra LKML-Reference: <20090730145723.25226.24493.stgit@dev.haskins.net> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 613fee5..475138c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -7927,7 +7927,7 @@ static void rq_attach_root(struct rq *rq, struct root_domain *rd) rq->rd = rd; cpumask_set_cpu(rq->cpu, rd->span); - if (cpumask_test_cpu(rq->cpu, cpu_online_mask)) + if (cpumask_test_cpu(rq->cpu, cpu_active_mask)) set_rq_online(rq); spin_unlock_irqrestore(&rq->lock, flags); diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 652e8bd..4934729 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1046,17 +1046,21 @@ static void yield_task_fair(struct rq *rq) * search starts with cpus closest then further out as needed, * so we always favor a closer, idle cpu. * Domains may include CPUs that are not usable for migration, - * hence we need to mask them out (cpu_active_mask) + * hence we need to mask them out (rq->rd->online) * * Returns the CPU we should wake onto. */ #if defined(ARCH_HAS_SCHED_WAKE_IDLE) + +#define cpu_rd_active(cpu, rq) cpumask_test_cpu(cpu, rq->rd->online) + static int wake_idle(int cpu, struct task_struct *p) { struct sched_domain *sd; int i; unsigned int chosen_wakeup_cpu; int this_cpu; + struct rq *task_rq = task_rq(p); /* * At POWERSAVINGS_BALANCE_WAKEUP level, if both this_cpu and prev_cpu @@ -1089,10 +1093,10 @@ static int wake_idle(int cpu, struct task_struct *p) for_each_domain(cpu, sd) { if ((sd->flags & SD_WAKE_IDLE) || ((sd->flags & SD_WAKE_IDLE_FAR) - && !task_hot(p, task_rq(p)->clock, sd))) { + && !task_hot(p, task_rq->clock, sd))) { for_each_cpu_and(i, sched_domain_span(sd), &p->cpus_allowed) { - if (cpu_active(i) && idle_cpu(i)) { + if (cpu_rd_active(i, task_rq) && idle_cpu(i)) { if (i != task_cpu(p)) { schedstat_inc(p, se.nr_wakeups_idle); diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index a8f89bc..13f728e 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -1173,13 +1173,6 @@ static int find_lowest_rq(struct task_struct *task) return -1; /* No targets found */ /* - * Only consider CPUs that are usable for migration. - * I guess we might want to change cpupri_find() to ignore those - * in the first place. - */ - cpumask_and(lowest_mask, lowest_mask, cpu_active_mask); - - /* * At this point we have built a mask of cpus representing the * lowest priority tasks in the system. Now we want to elect * the best one based on our affinity and topology. -- cgit v0.10.2 From 8f48894fcc89ddec62e1762f73a0825793e59e91 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 24 Jul 2009 12:25:30 +0200 Subject: sched: Add debug check to task_of() A frequent mistake appears to be to call task_of() on a scheduler entity that is not actually a task, which can result in a wild pointer. Add a check to catch these mistakes. Suggested-by: Ingo Molnar Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 4934729..342000b 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -79,11 +79,6 @@ static const struct sched_class fair_sched_class; * CFS operations on generic schedulable entities: */ -static inline struct task_struct *task_of(struct sched_entity *se) -{ - return container_of(se, struct task_struct, se); -} - #ifdef CONFIG_FAIR_GROUP_SCHED /* cpu runqueue to which this cfs_rq is attached */ @@ -95,6 +90,14 @@ static inline struct rq *rq_of(struct cfs_rq *cfs_rq) /* An entity is a task if it doesn't "own" a runqueue */ #define entity_is_task(se) (!se->my_q) +static inline struct task_struct *task_of(struct sched_entity *se) +{ +#ifdef CONFIG_SCHED_DEBUG + WARN_ON_ONCE(!entity_is_task(se)); +#endif + return container_of(se, struct task_struct, se); +} + /* Walk up scheduling entities hierarchy */ #define for_each_sched_entity(se) \ for (; se; se = se->parent) @@ -186,7 +189,12 @@ find_matching_se(struct sched_entity **se, struct sched_entity **pse) } } -#else /* CONFIG_FAIR_GROUP_SCHED */ +#else /* !CONFIG_FAIR_GROUP_SCHED */ + +static inline struct task_struct *task_of(struct sched_entity *se) +{ + return container_of(se, struct task_struct, se); +} static inline struct rq *rq_of(struct cfs_rq *cfs_rq) { diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index 13f728e..f365e66 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -3,15 +3,18 @@ * policies) */ +#ifdef CONFIG_RT_GROUP_SCHED + +#define rt_entity_is_task(rt_se) (!(rt_se)->my_q) + static inline struct task_struct *rt_task_of(struct sched_rt_entity *rt_se) { +#ifdef CONFIG_SCHED_DEBUG + WARN_ON_ONCE(!rt_entity_is_task(rt_se)); +#endif return container_of(rt_se, struct task_struct, rt); } -#ifdef CONFIG_RT_GROUP_SCHED - -#define rt_entity_is_task(rt_se) (!(rt_se)->my_q) - static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq) { return rt_rq->rq; @@ -26,6 +29,11 @@ static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se) #define rt_entity_is_task(rt_se) (1) +static inline struct task_struct *rt_task_of(struct sched_rt_entity *rt_se) +{ + return container_of(rt_se, struct task_struct, rt); +} + static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq) { return container_of(rt_rq, struct rq, rt); -- cgit v0.10.2 From 693525e3bea25cf2ee6cf2b862ba7c148e891df2 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 21 Jul 2009 13:56:38 +0200 Subject: sched: Ensure the migration task doesn't go away during use Like sched_migrate_task(), set_cpus_allowed_ptr() should hold onto the migration thread too. Signed-off-by: Peter Zijlstra Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 475138c..7f83be3 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -7078,8 +7078,12 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) if (migrate_task(p, cpumask_any_and(cpu_online_mask, new_mask), &req)) { /* Need help from migration thread: drop lock and wait. */ + struct task_struct *mt = rq->migration_thread; + + get_task_struct(mt); task_rq_unlock(rq, &flags); wake_up_process(rq->migration_thread); + put_task_struct(mt); wait_for_completion(&req.done); tlb_migrate_finish(p->mm); return 0; -- cgit v0.10.2 From bbfa26229a8143889e95e0df4a9d69067ee836cd Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 2 Aug 2009 14:44:24 +0200 Subject: lockdep: Fix BFS build Fix: kernel/built-in.o: In function `lockdep_stats_show': lockdep_proc.c:(.text+0x48202): undefined reference to `max_bfs_queue_depth' As max_bfs_queue_depth is only available under CONFIG_PROVE_LOCKING=y. Cc: Ming Lei Cc: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index 9a1bf34..fba81f1 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c @@ -411,8 +411,10 @@ static int lockdep_stats_show(struct seq_file *m, void *v) max_lockdep_depth); seq_printf(m, " max recursion depth: %11u\n", max_recursion_depth); +#ifdef CONFIG_PROVE_LOCKING seq_printf(m, " max bfs queue depth: %11u\n", max_bfs_queue_depth); +#endif lockdep_stats_debug_show(m); seq_printf(m, " debug_locks: %11u\n", debug_locks); -- cgit v0.10.2 From bcf08df3b23b3d13bf8c4ad6bd744a6ad30015fb Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sat, 19 Apr 2008 12:11:10 +0200 Subject: sched: Fix cpupri build on !CONFIG_SMP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This build bug: In file included from kernel/sched.c:1765: kernel/sched_rt.c: In function ‘has_pushable_tasks’: kernel/sched_rt.c:1069: error: ‘struct rt_rq’ has no member named ‘pushable_tasks’ kernel/sched_rt.c: In function ‘pick_next_task_rt’: kernel/sched_rt.c:1084: error: ‘struct rq’ has no member named ‘post_schedule’ Triggers because both pushable_tasks and post_schedule are SMP-only fields. Move pushable_tasks() to the SMP section and #ifdef the post_schedule use. Cc: Gregory Haskins Cc: Peter Zijlstra LKML-Reference: <20090729150422.17691.55590.stgit@dev.haskins.net> Signed-off-by: Ingo Molnar diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index f365e66..3d4020a 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -136,6 +136,11 @@ static void dequeue_pushable_task(struct rq *rq, struct task_struct *p) plist_del(&p->pushable_tasks, &rq->rt.pushable_tasks); } +static inline int has_pushable_tasks(struct rq *rq) +{ + return !plist_head_empty(&rq->rt.pushable_tasks); +} + #else static inline void enqueue_pushable_task(struct rq *rq, struct task_struct *p) @@ -1064,11 +1069,6 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq) return p; } -static inline int has_pushable_tasks(struct rq *rq) -{ - return !plist_head_empty(&rq->rt.pushable_tasks); -} - static struct task_struct *pick_next_task_rt(struct rq *rq) { struct task_struct *p = _pick_next_task_rt(rq); @@ -1077,11 +1077,13 @@ static struct task_struct *pick_next_task_rt(struct rq *rq) if (p) dequeue_pushable_task(rq, p); +#ifdef CONFIG_SMP /* * We detect this state here so that we can avoid taking the RQ * lock again later if there is no need to push */ rq->post_schedule = has_pushable_tasks(rq); +#endif return p; } -- cgit v0.10.2 From 4f84f4330a11b9eb828bf5af557f4c79c64614a3 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 20 Jul 2009 15:27:04 +0200 Subject: lockdep: Fix backtraces Truncate stupid -1 entries in backtraces. Signed-off-by: Peter Zijlstra LKML-Reference: <1248096665.15751.8816.camel@twins> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 1cedb00..2f09702 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -367,11 +367,21 @@ static int save_trace(struct stack_trace *trace) save_stack_trace(trace); + /* + * Some daft arches put -1 at the end to indicate its a full trace. + * + * this is buggy anyway, since it takes a whole extra entry so a + * complete trace that maxes out the entries provided will be reported + * as incomplete, friggin useless + */ + if (trace->entries[trace->nr_entries-1] == ULONG_MAX) + trace->nr_entries--; + trace->max_entries = trace->nr_entries; nr_stack_trace_entries += trace->nr_entries; - if (nr_stack_trace_entries == MAX_STACK_TRACE_ENTRIES) { + if (nr_stack_trace_entries >= MAX_STACK_TRACE_ENTRIES-1) { if (!debug_locks_off_graph_unlock()) return 0; -- cgit v0.10.2 From 98c33eddaf41d225d99b40f9eedbd0fac4c08c05 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 21 Jul 2009 13:19:07 +0200 Subject: lockdep: Fix style nits fixes a few comments and whitespaces that annoyed me. Signed-off-by: Peter Zijlstra Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 2f09702..4b6cebe 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -843,15 +843,18 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, return 1; } -/*For good efficiency of modular, we use power of 2*/ +/* + * For good efficiency of modular, we use power of 2 + */ #define MAX_CIRCULAR_QUEUE_SIZE 4096UL #define CQ_MASK (MAX_CIRCULAR_QUEUE_SIZE-1) -/* The circular_queue and helpers is used to implement the +/* + * The circular_queue and helpers is used to implement the * breadth-first search(BFS)algorithem, by which we can build * the shortest path from the next lock to be acquired to the * previous held lock if there is a circular between them. - * */ + */ struct circular_queue { unsigned long element[MAX_CIRCULAR_QUEUE_SIZE]; unsigned int front, rear; @@ -907,6 +910,7 @@ static inline void mark_lock_accessed(struct lock_list *lock, struct lock_list *parent) { unsigned long nr; + nr = lock - list_entries; WARN_ON(nr >= nr_list_entries); lock->parent = parent; @@ -916,6 +920,7 @@ static inline void mark_lock_accessed(struct lock_list *lock, static inline unsigned long lock_accessed(struct lock_list *lock) { unsigned long nr; + nr = lock - list_entries; WARN_ON(nr >= nr_list_entries); return test_bit(nr, bfs_accessed); -- cgit v0.10.2 From f607c6685774811b8112e124f10a053d77015485 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 20 Jul 2009 19:16:29 +0200 Subject: lockdep: Introduce lockdep_assert_held() Add a lockdep helper to validate that we indeed are the owner of a lock. Signed-off-by: Peter Zijlstra Signed-off-by: Ingo Molnar diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 12aabfc..a6d5e5e 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -296,6 +296,10 @@ extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass, extern void lock_release(struct lockdep_map *lock, int nested, unsigned long ip); +#define lockdep_is_held(lock) lock_is_held(&(lock)->dep_map) + +extern int lock_is_held(struct lockdep_map *lock); + extern void lock_set_class(struct lockdep_map *lock, const char *name, struct lock_class_key *key, unsigned int subclass, unsigned long ip); @@ -314,6 +318,8 @@ extern void lockdep_trace_alloc(gfp_t mask); #define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) +#define lockdep_assert_held(l) WARN_ON(debug_locks && !lockdep_is_held(l)) + #else /* !LOCKDEP */ static inline void lockdep_off(void) @@ -358,6 +364,8 @@ struct lock_class_key { }; #define lockdep_depth(tsk) (0) +#define lockdep_assert_held(l) do { } while (0) + #endif /* !LOCKDEP */ #ifdef CONFIG_LOCK_STAT diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 4b6cebe..28914a5 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -3059,6 +3059,19 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip) check_chain_key(curr); } +static int __lock_is_held(struct lockdep_map *lock) +{ + struct task_struct *curr = current; + int i; + + for (i = 0; i < curr->lockdep_depth; i++) { + if (curr->held_locks[i].instance == lock) + return 1; + } + + return 0; +} + /* * Check whether we follow the irq-flags state precisely: */ @@ -3160,6 +3173,26 @@ void lock_release(struct lockdep_map *lock, int nested, } EXPORT_SYMBOL_GPL(lock_release); +int lock_is_held(struct lockdep_map *lock) +{ + unsigned long flags; + int ret = 0; + + if (unlikely(current->lockdep_recursion)) + return ret; + + raw_local_irq_save(flags); + check_flags(flags); + + current->lockdep_recursion = 1; + ret = __lock_is_held(lock); + current->lockdep_recursion = 0; + raw_local_irq_restore(flags); + + return ret; +} +EXPORT_SYMBOL_GPL(lock_is_held); + void lockdep_set_current_reclaim_state(gfp_t gfp_mask) { current->lockdep_reclaim_gfp = gfp_mask; diff --git a/kernel/sched.c b/kernel/sched.c index 1b59e26..2c75f7d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6609,6 +6609,8 @@ int cond_resched_lock(spinlock_t *lock) int resched = should_resched(); int ret = 0; + lockdep_assert_held(lock); + if (spin_needbreak(lock) || resched) { spin_unlock(lock); if (resched) -- cgit v0.10.2 From bb97a91e2549a7f2df9c21d32542582f549ab3ec Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 20 Jul 2009 19:15:35 +0200 Subject: lockdep: Deal with many similar locks spin_lock_nest_lock() allows to take many instances of the same class, this can easily lead to overflow of MAX_LOCK_DEPTH. To avoid this overflow, we'll stop accounting instances but start reference counting the class in the held_lock structure. [ We could maintain a list of instances, if we'd move the hlock stuff into __lock_acquired(), but that would require significant modifications to the current code. ] We restrict this mode to spin_lock_nest_lock() only, because it degrades the lockdep quality due to lost of instance. For lockstat this means we don't track lock statistics for any but the first lock in the series. Currently nesting is limited to 11 bits because that was the spare space available in held_lock. This yields a 2048 instances maximium. Signed-off-by: Peter Zijlstra Cc: Marcelo Tosatti Cc: Linus Torvalds Signed-off-by: Ingo Molnar diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index a6d5e5e..47d42ef 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -213,10 +213,12 @@ struct held_lock { * interrupt context: */ unsigned int irq_context:2; /* bit 0 - soft, bit 1 - hard */ - unsigned int trylock:1; + unsigned int trylock:1; /* 16 bits */ + unsigned int read:2; /* see lock_acquire() comment */ unsigned int check:2; /* see lock_acquire() comment */ unsigned int hardirqs_off:1; + unsigned int references:11; /* 32 bits */ }; /* diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 28914a5..0bb246e 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -2708,13 +2708,15 @@ EXPORT_SYMBOL_GPL(lockdep_init_map); */ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, int trylock, int read, int check, int hardirqs_off, - struct lockdep_map *nest_lock, unsigned long ip) + struct lockdep_map *nest_lock, unsigned long ip, + int references) { struct task_struct *curr = current; struct lock_class *class = NULL; struct held_lock *hlock; unsigned int depth, id; int chain_head = 0; + int class_idx; u64 chain_key; if (!prove_locking) @@ -2762,10 +2764,24 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, if (DEBUG_LOCKS_WARN_ON(depth >= MAX_LOCK_DEPTH)) return 0; + class_idx = class - lock_classes + 1; + + if (depth) { + hlock = curr->held_locks + depth - 1; + if (hlock->class_idx == class_idx && nest_lock) { + if (hlock->references) + hlock->references++; + else + hlock->references = 2; + + return 1; + } + } + hlock = curr->held_locks + depth; if (DEBUG_LOCKS_WARN_ON(!class)) return 0; - hlock->class_idx = class - lock_classes + 1; + hlock->class_idx = class_idx; hlock->acquire_ip = ip; hlock->instance = lock; hlock->nest_lock = nest_lock; @@ -2773,6 +2789,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, hlock->read = read; hlock->check = check; hlock->hardirqs_off = !!hardirqs_off; + hlock->references = references; #ifdef CONFIG_LOCK_STAT hlock->waittime_stamp = 0; hlock->holdtime_stamp = sched_clock(); @@ -2881,6 +2898,30 @@ static int check_unlock(struct task_struct *curr, struct lockdep_map *lock, return 1; } +static int match_held_lock(struct held_lock *hlock, struct lockdep_map *lock) +{ + if (hlock->instance == lock) + return 1; + + if (hlock->references) { + struct lock_class *class = lock->class_cache; + + if (!class) + class = look_up_lock_class(lock, 0); + + if (DEBUG_LOCKS_WARN_ON(!class)) + return 0; + + if (DEBUG_LOCKS_WARN_ON(!hlock->nest_lock)) + return 0; + + if (hlock->class_idx == class - lock_classes + 1) + return 1; + } + + return 0; +} + static int __lock_set_class(struct lockdep_map *lock, const char *name, struct lock_class_key *key, unsigned int subclass, @@ -2904,7 +2945,7 @@ __lock_set_class(struct lockdep_map *lock, const char *name, */ if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) break; - if (hlock->instance == lock) + if (match_held_lock(hlock, lock)) goto found_it; prev_hlock = hlock; } @@ -2923,7 +2964,8 @@ found_it: if (!__lock_acquire(hlock->instance, hlock_class(hlock)->subclass, hlock->trylock, hlock->read, hlock->check, hlock->hardirqs_off, - hlock->nest_lock, hlock->acquire_ip)) + hlock->nest_lock, hlock->acquire_ip, + hlock->references)) return 0; } @@ -2962,20 +3004,34 @@ lock_release_non_nested(struct task_struct *curr, */ if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) break; - if (hlock->instance == lock) + if (match_held_lock(hlock, lock)) goto found_it; prev_hlock = hlock; } return print_unlock_inbalance_bug(curr, lock, ip); found_it: - lock_release_holdtime(hlock); + if (hlock->instance == lock) + lock_release_holdtime(hlock); + + if (hlock->references) { + hlock->references--; + if (hlock->references) { + /* + * We had, and after removing one, still have + * references, the current lock stack is still + * valid. We're done! + */ + return 1; + } + } /* * We have the right lock to unlock, 'hlock' points to it. * Now we remove it from the stack, and add back the other * entries (if any), recalculating the hash along the way: */ + curr->lockdep_depth = i; curr->curr_chain_key = hlock->prev_chain_key; @@ -2984,7 +3040,8 @@ found_it: if (!__lock_acquire(hlock->instance, hlock_class(hlock)->subclass, hlock->trylock, hlock->read, hlock->check, hlock->hardirqs_off, - hlock->nest_lock, hlock->acquire_ip)) + hlock->nest_lock, hlock->acquire_ip, + hlock->references)) return 0; } @@ -3014,7 +3071,7 @@ static int lock_release_nested(struct task_struct *curr, /* * Is the unlock non-nested: */ - if (hlock->instance != lock) + if (hlock->instance != lock || hlock->references) return lock_release_non_nested(curr, lock, ip); curr->lockdep_depth--; @@ -3065,7 +3122,9 @@ static int __lock_is_held(struct lockdep_map *lock) int i; for (i = 0; i < curr->lockdep_depth; i++) { - if (curr->held_locks[i].instance == lock) + struct held_lock *hlock = curr->held_locks + i; + + if (match_held_lock(hlock, lock)) return 1; } @@ -3148,7 +3207,7 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass, current->lockdep_recursion = 1; __lock_acquire(lock, subclass, trylock, read, check, - irqs_disabled_flags(flags), nest_lock, ip); + irqs_disabled_flags(flags), nest_lock, ip, 0); current->lockdep_recursion = 0; raw_local_irq_restore(flags); } @@ -3252,7 +3311,7 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip) */ if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) break; - if (hlock->instance == lock) + if (match_held_lock(hlock, lock)) goto found_it; prev_hlock = hlock; } @@ -3260,6 +3319,9 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip) return; found_it: + if (hlock->instance != lock) + return; + hlock->waittime_stamp = sched_clock(); contention_point = lock_point(hlock_class(hlock)->contention_point, ip); @@ -3299,7 +3361,7 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip) */ if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) break; - if (hlock->instance == lock) + if (match_held_lock(hlock, lock)) goto found_it; prev_hlock = hlock; } @@ -3307,6 +3369,9 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip) return; found_it: + if (hlock->instance != lock) + return; + cpu = smp_processor_id(); if (hlock->waittime_stamp) { now = sched_clock(); -- cgit v0.10.2 From e351b660fddd4df76cc4635f896d311ed0ff3752 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 22 Jul 2009 22:48:09 +0800 Subject: lockdep: Reintroduce generation count to make BFS faster We still can apply DaveM's generation count optimization to BFS, based on the following idea: - before doing each BFS, increase the global generation id by 1 - if one node in the graph has been visited, mark it as visited by storing the current global generation id into the node's dep_gen_id field - so we can decide if one node has been visited already, by comparing the node's dep_gen_id with the global generation id. By applying DaveM's generation count optimization to current implementation of BFS, we gain the following advantages: - we save MAX_LOCKDEP_ENTRIES/8 bytes memory; - we remove the bitmap_zero(bfs_accessed, MAX_LOCKDEP_ENTRIES); in each BFS, which is very time-consuming since MAX_LOCKDEP_ENTRIES may be very large.(16384UL) Signed-off-by: Ming Lei Signed-off-by: Peter Zijlstra Cc: "David S. Miller" LKML-Reference: <1248274089-6358-1-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 47d42ef..9ccf0e2 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -58,6 +58,7 @@ struct lock_class { struct lockdep_subclass_key *key; unsigned int subclass; + unsigned int dep_gen_id; /* * IRQ/softirq usage tracking bits: diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 0bb246e..2b443b5 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -861,14 +861,15 @@ struct circular_queue { }; static struct circular_queue lock_cq; -static unsigned long bfs_accessed[BITS_TO_LONGS(MAX_LOCKDEP_ENTRIES)]; unsigned int max_bfs_queue_depth; +static unsigned int lockdep_dependency_gen_id; + static inline void __cq_init(struct circular_queue *cq) { cq->front = cq->rear = 0; - bitmap_zero(bfs_accessed, MAX_LOCKDEP_ENTRIES); + lockdep_dependency_gen_id++; } static inline int __cq_empty(struct circular_queue *cq) @@ -914,7 +915,7 @@ static inline void mark_lock_accessed(struct lock_list *lock, nr = lock - list_entries; WARN_ON(nr >= nr_list_entries); lock->parent = parent; - set_bit(nr, bfs_accessed); + lock->class->dep_gen_id = lockdep_dependency_gen_id; } static inline unsigned long lock_accessed(struct lock_list *lock) @@ -923,7 +924,7 @@ static inline unsigned long lock_accessed(struct lock_list *lock) nr = lock - list_entries; WARN_ON(nr >= nr_list_entries); - return test_bit(nr, bfs_accessed); + return lock->class->dep_gen_id == lockdep_dependency_gen_id; } static inline struct lock_list *get_lock_parent(struct lock_list *child) @@ -3604,7 +3605,7 @@ void __init lockdep_info(void) sizeof(struct lock_chain) * MAX_LOCKDEP_CHAINS + sizeof(struct list_head) * CHAINHASH_SIZE) / 1024 #ifdef CONFIG_PROVE_LOCKING - + sizeof(struct circular_queue) + sizeof(bfs_accessed) + + sizeof(struct circular_queue) #endif ); -- cgit v0.10.2 From 90629209a020859b67423a6326f3765f220c7f5c Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sun, 2 Aug 2009 21:43:36 +0800 Subject: lockdep: Fix memory usage info of BFS The unit is KB, so sizeof(struct circular_queue) should be divided by 1024. Signed-off-by: Ming Lei Cc: akpm@linux-foundation.org Cc: torvalds@linux-foundation.org Cc: davem@davemloft.net Cc: Ming Lei Cc: a.p.zijlstra@chello.nl LKML-Reference: <1249220616-7190-1-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 2b443b5..0843584 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -3603,10 +3603,11 @@ void __init lockdep_info(void) sizeof(struct list_head) * CLASSHASH_SIZE + sizeof(struct lock_list) * MAX_LOCKDEP_ENTRIES + sizeof(struct lock_chain) * MAX_LOCKDEP_CHAINS + - sizeof(struct list_head) * CHAINHASH_SIZE) / 1024 + sizeof(struct list_head) * CHAINHASH_SIZE #ifdef CONFIG_PROVE_LOCKING + sizeof(struct circular_queue) #endif + ) / 1024 ); printk(" per task-struct memory footprint: %lu bytes\n", -- cgit v0.10.2 From 9450526ac7bd74edf1ee030841d8078c6db6ca0b Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Thu, 30 Jul 2009 21:23:34 +0000 Subject: cxgb3: fix EDC filename string Fix a cut'n paste error in the AEL2020 twinax EDC file name Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index ec05149..8b3e76c 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -993,7 +993,7 @@ static int bind_qsets(struct adapter *adap) #define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin" #define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin" #define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" -#define AEL2020_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" +#define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin" static inline const char *get_edc_fw_name(int edc_idx) { -- cgit v0.10.2 From 88e7b76ef7cf939a0cf23a1902030211b20837fe Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Thu, 30 Jul 2009 21:23:39 +0000 Subject: cxgb3: fix Gen2 pci default settings Modify control register settings to accommodate the bridge's max read requset size. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index e78d341..526e144 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -3465,7 +3465,7 @@ static void config_pcie(struct adapter *adap) {201, 321, 258, 450, 834, 1602} }; - u16 val; + u16 val, devid; unsigned int log2_width, pldsize; unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt; @@ -3473,6 +3473,17 @@ static void config_pcie(struct adapter *adap) adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL, &val); pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5; + + pci_read_config_word(adap->pdev, 0x2, &devid); + if (devid == 0x37) { + pci_write_config_word(adap->pdev, + adap->params.pci.pcie_cap_addr + + PCI_EXP_DEVCTL, + val & ~PCI_EXP_DEVCTL_READRQ & + ~PCI_EXP_DEVCTL_PAYLOAD); + pldsize = 0; + } + pci_read_config_word(adap->pdev, adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL, &val); -- cgit v0.10.2 From 25f6e89bedd29cc49bfa0d55497e91a671b9ae6e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 30 Jul 2009 23:21:18 +0200 Subject: x86: Remove superfluous NULL pointer check in destroy_irq() This takes care of the following entry from Dan's list: arch/x86/kernel/apic/io_apic.c +3241 destroy_irq(11) warning: variable derefenced before check 'desc' Reported-by: Dan Carpenter Signed-off-by: Bartlomiej Zolnierkiewicz Cc: Jonathan Corbet Cc: Eugene Teo Cc: Julia Lawall LKML-Reference: <200907302321.19086.bzolnier@gmail.com> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index cf51b0b..7e92a92 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -3185,8 +3185,7 @@ void destroy_irq(unsigned int irq) cfg = desc->chip_data; dynamic_irq_cleanup(irq); /* connect back irq_cfg */ - if (desc) - desc->chip_data = cfg; + desc->chip_data = cfg; free_irte(irq); spin_lock_irqsave(&vector_lock, flags); -- cgit v0.10.2 From 39506a552b4b302540e1f9c6c93a122df353e57d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 1 Aug 2009 09:51:06 +0000 Subject: drivers/net: Use DIV_ROUND_CLOSEST The kernel.h macro DIV_ROUND_CLOSEST performs the computation (x + d/2)/d but is perhaps more readable. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @haskernel@ @@ #include @depends on haskernel@ expression x,__divisor; @@ - (((x) + ((__divisor) / 2)) / (__divisor)) + DIV_ROUND_CLOSEST(x,__divisor) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 1f7f015..07c92f3 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1297,7 +1297,8 @@ static void b44_chip_reset(struct b44 *bp, int reset_kind) switch (sdev->bus->bustype) { case SSB_BUSTYPE_SSB: bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | - (((ssb_clockspeed(sdev->bus) + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO) + (DIV_ROUND_CLOSEST(ssb_clockspeed(sdev->bus), + B44_MDC_RATIO) & MDIO_CTRL_MAXF_MASK))); break; case SSB_BUSTYPE_PCI: -- cgit v0.10.2 From 8b97c7c283c5ba8f9f4dabd418fd7dcfcc8a387e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 1 Aug 2009 22:48:45 +0000 Subject: drivers/atm: Use DIV_ROUND_CLOSEST The kernel.h macro DIV_ROUND_CLOSEST performs the computation (x + d/2)/d but is perhaps more readable. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @haskernel@ @@ #include @depends on haskernel@ expression x,__divisor; @@ - (((x) + ((__divisor) / 2)) / (__divisor)) + DIV_ROUND_CLOSEST(x,__divisor) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 6b969f8..01ce241 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -641,7 +641,7 @@ static int make_rate (const hrz_dev * dev, u32 c, rounding r, pre = 1; break; case round_nearest: - pre = (br+(c< Date: Tue, 28 Jul 2009 09:48:07 +0000 Subject: inet6: functions shadow global variable This renames away a variable clash: * ipv6_table[] is declared as a static global table; * ipv6_sysctl_net_init() uses ipv6_table to refer/destroy dynamic memory; * ipv6_sysctl_net_exit() also uses ipv6_table for the same purpose; * both the two last functions call kfree() on ipv6_table. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index a031034..0dc6a4e 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -40,7 +40,7 @@ static ctl_table ipv6_table_template[] = { { .ctl_name = 0 } }; -static ctl_table ipv6_table[] = { +static ctl_table ipv6_rotable[] = { { .ctl_name = NET_IPV6_MLD_MAX_MSF, .procname = "mld_max_msf", @@ -130,7 +130,7 @@ int ipv6_sysctl_register(void) { int err = -ENOMEM; - ip6_header = register_net_sysctl_rotable(net_ipv6_ctl_path, ipv6_table); + ip6_header = register_net_sysctl_rotable(net_ipv6_ctl_path, ipv6_rotable); if (ip6_header == NULL) goto out; -- cgit v0.10.2 From bcd218be5aebed94951a750b1d477aea86fb68ea Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Tue, 28 Jul 2009 02:37:58 +0000 Subject: smsc95xx: remove EEPROM loaded check The eeprom read & write commands currently check the E2P_CMD_LOADED_ bit is set before allowing any operations. This prevents any reading or writing unless a correctly programmed EEPROM is installed. This patch removes the check, so it is possible to program blank EEPROMS via ethtool. Signed-off-by: Steve Glendinning Signed-off-by: David S. Miller diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index fe04589..09bd635 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -220,11 +220,6 @@ static int smsc95xx_eeprom_confirm_not_busy(struct usbnet *dev) do { smsc95xx_read_reg(dev, E2P_CMD, &val); - if (!(val & E2P_CMD_LOADED_)) { - devwarn(dev, "No EEPROM present"); - return -EIO; - } - if (!(val & E2P_CMD_BUSY_)) return 0; -- cgit v0.10.2 From 1e3e238e9c4bf9987b19185235cd0cdc21ea038c Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Sun, 2 Aug 2009 11:05:41 +0000 Subject: IPVS: use pr_err and friends instead of IP_VS_ERR and friends Since pr_err and friends are used instead of printk there is no point in keeping IP_VS_ERR and friends. Furthermore make use of '__func__' instead of hard coded function names. Signed-off-by: Hannes Eder Acked-by: Simon Horman Signed-off-by: David S. Miller diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 9108203..1c8ee1b 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -150,13 +150,10 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len, #endif #define IP_VS_BUG() BUG() -#define IP_VS_ERR(msg...) pr_err(msg) -#define IP_VS_INFO(msg...) pr_info(msg) -#define IP_VS_WARNING(msg...) pr_warning(msg) -#define IP_VS_ERR_RL(msg...) \ +#define IP_VS_ERR_RL(msg, ...) \ do { \ if (net_ratelimit()) \ - pr_err(msg); \ + pr_err(msg, ##__VA_ARGS__); \ } while (0) #ifdef CONFIG_IP_VS_DEBUG diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c index c1781f8..3c7e427 100644 --- a/net/netfilter/ipvs/ip_vs_app.c +++ b/net/netfilter/ipvs/ip_vs_app.c @@ -265,12 +265,12 @@ static inline void vs_fix_seq(const struct ip_vs_seq *vseq, struct tcphdr *th) if (vseq->delta || vseq->previous_delta) { if(after(seq, vseq->init_seq)) { th->seq = htonl(seq + vseq->delta); - IP_VS_DBG(9, "vs_fix_seq(): added delta (%d) to seq\n", - vseq->delta); + IP_VS_DBG(9, "%s(): added delta (%d) to seq\n", + __func__, vseq->delta); } else { th->seq = htonl(seq + vseq->previous_delta); - IP_VS_DBG(9, "vs_fix_seq(): added previous_delta " - "(%d) to seq\n", vseq->previous_delta); + IP_VS_DBG(9, "%s(): added previous_delta (%d) to seq\n", + __func__, vseq->previous_delta); } } } @@ -294,14 +294,14 @@ vs_fix_ack_seq(const struct ip_vs_seq *vseq, struct tcphdr *th) to receive next, so compare it with init_seq+delta */ if(after(ack_seq, vseq->init_seq+vseq->delta)) { th->ack_seq = htonl(ack_seq - vseq->delta); - IP_VS_DBG(9, "vs_fix_ack_seq(): subtracted delta " - "(%d) from ack_seq\n", vseq->delta); + IP_VS_DBG(9, "%s(): subtracted delta " + "(%d) from ack_seq\n", __func__, vseq->delta); } else { th->ack_seq = htonl(ack_seq - vseq->previous_delta); - IP_VS_DBG(9, "vs_fix_ack_seq(): subtracted " + IP_VS_DBG(9, "%s(): subtracted " "previous_delta (%d) from ack_seq\n", - vseq->previous_delta); + __func__, vseq->previous_delta); } } } diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index 4173d7b..27c30cf 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -153,8 +153,8 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp) atomic_inc(&cp->refcnt); ret = 1; } else { - IP_VS_ERR("ip_vs_conn_hash(): request for already hashed, " - "called from %p\n", __builtin_return_address(0)); + pr_err("%s(): request for already hashed, called from %pF\n", + __func__, __builtin_return_address(0)); ret = 0; } @@ -692,7 +692,7 @@ ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport, cp = kmem_cache_zalloc(ip_vs_conn_cachep, GFP_ATOMIC); if (cp == NULL) { - IP_VS_ERR_RL("ip_vs_conn_new: no memory available.\n"); + IP_VS_ERR_RL("%s(): no memory\n", __func__); return NULL; } @@ -1076,10 +1076,10 @@ int __init ip_vs_conn_init(void) return -ENOMEM; } - IP_VS_INFO("Connection hash table configured " - "(size=%d, memory=%ldKbytes)\n", - IP_VS_CONN_TAB_SIZE, - (long)(IP_VS_CONN_TAB_SIZE*sizeof(struct list_head))/1024); + pr_info("Connection hash table configured " + "(size=%d, memory=%ldKbytes)\n", + IP_VS_CONN_TAB_SIZE, + (long)(IP_VS_CONN_TAB_SIZE*sizeof(struct list_head))/1024); IP_VS_DBG(0, "Each connection entry needs %Zd bytes at least\n", sizeof(struct ip_vs_conn)); diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 6811dca..b227750 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -391,9 +391,9 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) */ if (!svc->fwmark && pptr[1] != svc->port) { if (!svc->port) - IP_VS_ERR("Schedule: port zero only supported " - "in persistent services, " - "check your ipvs configuration\n"); + pr_err("Schedule: port zero only supported " + "in persistent services, " + "check your ipvs configuration\n"); return NULL; } @@ -465,7 +465,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, ip_vs_service_put(svc); /* create a new connection entry */ - IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n"); + IP_VS_DBG(6, "%s(): create a cache_bypass entry\n", __func__); cp = ip_vs_conn_new(svc->af, iph.protocol, &iph.saddr, pptr[0], &iph.daddr, pptr[1], @@ -667,8 +667,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb, unsigned int verdict = NF_DROP; if (IP_VS_FWD_METHOD(cp) != 0) { - IP_VS_ERR("shouldn't reach here, because the box is on the " - "half connection in the tun/dr module.\n"); + pr_err("shouldn't reach here, because the box is on the " + "half connection in the tun/dr module.\n"); } /* Ensure the checksum is correct */ @@ -1490,7 +1490,7 @@ static int __init ip_vs_init(void) ret = ip_vs_control_init(); if (ret < 0) { - IP_VS_ERR("can't setup control.\n"); + pr_err("can't setup control.\n"); goto cleanup_estimator; } @@ -1498,23 +1498,23 @@ static int __init ip_vs_init(void) ret = ip_vs_app_init(); if (ret < 0) { - IP_VS_ERR("can't setup application helper.\n"); + pr_err("can't setup application helper.\n"); goto cleanup_protocol; } ret = ip_vs_conn_init(); if (ret < 0) { - IP_VS_ERR("can't setup connection table.\n"); + pr_err("can't setup connection table.\n"); goto cleanup_app; } ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops)); if (ret < 0) { - IP_VS_ERR("can't register hooks.\n"); + pr_err("can't register hooks.\n"); goto cleanup_conn; } - IP_VS_INFO("ipvs loaded.\n"); + pr_info("ipvs loaded.\n"); return ret; cleanup_conn: @@ -1537,7 +1537,7 @@ static void __exit ip_vs_cleanup(void) ip_vs_protocol_cleanup(); ip_vs_control_cleanup(); ip_vs_estimator_cleanup(); - IP_VS_INFO("ipvs unloaded.\n"); + pr_info("ipvs unloaded.\n"); } module_init(ip_vs_init); diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index e6133ea..fba2892 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -343,8 +343,8 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc) unsigned hash; if (svc->flags & IP_VS_SVC_F_HASHED) { - IP_VS_ERR("ip_vs_svc_hash(): request for already hashed, " - "called from %p\n", __builtin_return_address(0)); + pr_err("%s(): request for already hashed, called from %pF\n", + __func__, __builtin_return_address(0)); return 0; } @@ -377,8 +377,8 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc) static int ip_vs_svc_unhash(struct ip_vs_service *svc) { if (!(svc->flags & IP_VS_SVC_F_HASHED)) { - IP_VS_ERR("ip_vs_svc_unhash(): request for unhash flagged, " - "called from %p\n", __builtin_return_address(0)); + pr_err("%s(): request for unhash flagged, called from %pF\n", + __func__, __builtin_return_address(0)); return 0; } @@ -844,7 +844,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest, dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC); if (dest == NULL) { - IP_VS_ERR("ip_vs_new_dest: kmalloc failed.\n"); + pr_err("%s(): no memory.\n", __func__); return -ENOMEM; } @@ -888,13 +888,13 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) EnterFunction(2); if (udest->weight < 0) { - IP_VS_ERR("ip_vs_add_dest(): server weight less than zero\n"); + pr_err("%s(): server weight less than zero\n", __func__); return -ERANGE; } if (udest->l_threshold > udest->u_threshold) { - IP_VS_ERR("ip_vs_add_dest(): lower threshold is higher than " - "upper threshold\n"); + pr_err("%s(): lower threshold is higher than upper threshold\n", + __func__); return -ERANGE; } @@ -906,7 +906,7 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) dest = ip_vs_lookup_dest(svc, &daddr, dport); if (dest != NULL) { - IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n"); + IP_VS_DBG(1, "%s(): dest already exists\n", __func__); return -EEXIST; } @@ -1000,13 +1000,13 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) EnterFunction(2); if (udest->weight < 0) { - IP_VS_ERR("ip_vs_edit_dest(): server weight less than zero\n"); + pr_err("%s(): server weight less than zero\n", __func__); return -ERANGE; } if (udest->l_threshold > udest->u_threshold) { - IP_VS_ERR("ip_vs_edit_dest(): lower threshold is higher than " - "upper threshold\n"); + pr_err("%s(): lower threshold is higher than upper threshold\n", + __func__); return -ERANGE; } @@ -1018,7 +1018,7 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) dest = ip_vs_lookup_dest(svc, &daddr, dport); if (dest == NULL) { - IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n"); + IP_VS_DBG(1, "%s(): dest doesn't exist\n", __func__); return -ENOENT; } @@ -1118,7 +1118,7 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) dest = ip_vs_lookup_dest(svc, &udest->addr, dport); if (dest == NULL) { - IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n"); + IP_VS_DBG(1, "%s(): destination not found!\n", __func__); return -ENOENT; } @@ -1164,8 +1164,7 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u, /* Lookup the scheduler by 'u->sched_name' */ sched = ip_vs_scheduler_get(u->sched_name); if (sched == NULL) { - IP_VS_INFO("Scheduler module ip_vs_%s not found\n", - u->sched_name); + pr_info("Scheduler module ip_vs_%s not found\n", u->sched_name); ret = -ENOENT; goto out_mod_dec; } @@ -1179,7 +1178,7 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u, svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC); if (svc == NULL) { - IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n"); + IP_VS_DBG(1, "%s(): no memory\n", __func__); ret = -ENOMEM; goto out_err; } @@ -1262,8 +1261,7 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) */ sched = ip_vs_scheduler_get(u->sched_name); if (sched == NULL) { - IP_VS_INFO("Scheduler module ip_vs_%s not found\n", - u->sched_name); + pr_info("Scheduler module ip_vs_%s not found\n", u->sched_name); return -ENOENT; } old_sched = sched; @@ -2080,8 +2078,8 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) return -EPERM; if (len != set_arglen[SET_CMDID(cmd)]) { - IP_VS_ERR("set_ctl: len %u != %u\n", - len, set_arglen[SET_CMDID(cmd)]); + pr_err("set_ctl: len %u != %u\n", + len, set_arglen[SET_CMDID(cmd)]); return -EINVAL; } @@ -2132,9 +2130,9 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) /* Check for valid protocol: TCP or UDP, even for fwmark!=0 */ if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP) { - IP_VS_ERR("set_ctl: invalid protocol: %d %pI4:%d %s\n", - usvc.protocol, &usvc.addr.ip, - ntohs(usvc.port), usvc.sched_name); + pr_err("set_ctl: invalid protocol: %d %pI4:%d %s\n", + usvc.protocol, &usvc.addr.ip, + ntohs(usvc.port), usvc.sched_name); ret = -EFAULT; goto out_unlock; } @@ -2359,8 +2357,8 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) return -EPERM; if (*len < get_arglen[GET_CMDID(cmd)]) { - IP_VS_ERR("get_ctl: len %u < %u\n", - *len, get_arglen[GET_CMDID(cmd)]); + pr_err("get_ctl: len %u < %u\n", + *len, get_arglen[GET_CMDID(cmd)]); return -EINVAL; } @@ -2405,7 +2403,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) size = sizeof(*get) + sizeof(struct ip_vs_service_entry) * get->num_services; if (*len != size) { - IP_VS_ERR("length: %u != %u\n", *len, size); + pr_err("length: %u != %u\n", *len, size); ret = -EINVAL; goto out; } @@ -2445,7 +2443,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) size = sizeof(*get) + sizeof(struct ip_vs_dest_entry) * get->num_dests; if (*len != size) { - IP_VS_ERR("length: %u != %u\n", *len, size); + pr_err("length: %u != %u\n", *len, size); ret = -EINVAL; goto out; } @@ -3173,7 +3171,7 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info) else if (cmd == IPVS_CMD_GET_CONFIG) reply_cmd = IPVS_CMD_SET_CONFIG; else { - IP_VS_ERR("unknown Generic Netlink command\n"); + pr_err("unknown Generic Netlink command\n"); return -EINVAL; } @@ -3238,7 +3236,7 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info) goto out; nla_put_failure: - IP_VS_ERR("not enough space in Netlink message\n"); + pr_err("not enough space in Netlink message\n"); ret = -EMSGSIZE; out_err: @@ -3369,13 +3367,13 @@ int __init ip_vs_control_init(void) ret = nf_register_sockopt(&ip_vs_sockopts); if (ret) { - IP_VS_ERR("cannot register sockopt.\n"); + pr_err("cannot register sockopt.\n"); return ret; } ret = ip_vs_genl_register(); if (ret) { - IP_VS_ERR("cannot register Generic Netlink interface.\n"); + pr_err("cannot register Generic Netlink interface.\n"); nf_unregister_sockopt(&ip_vs_sockopts); return ret; } diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c index d0c0594..fe3e188 100644 --- a/net/netfilter/ipvs/ip_vs_dh.c +++ b/net/netfilter/ipvs/ip_vs_dh.c @@ -150,7 +150,7 @@ static int ip_vs_dh_init_svc(struct ip_vs_service *svc) tbl = kmalloc(sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE, GFP_ATOMIC); if (tbl == NULL) { - IP_VS_ERR("ip_vs_dh_init_svc(): no memory\n"); + pr_err("%s(): no memory\n", __func__); return -ENOMEM; } svc->sched_data = tbl; @@ -217,7 +217,7 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); - IP_VS_DBG(6, "ip_vs_dh_schedule(): Scheduling...\n"); + IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); tbl = (struct ip_vs_dh_bucket *)svc->sched_data; dest = ip_vs_dh_get(svc->af, tbl, &iph.daddr); diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 9c16a3f..33e2c79 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c @@ -385,8 +385,8 @@ static int __init ip_vs_ftp_init(void) ret = register_ip_vs_app_inc(app, app->protocol, ports[i]); if (ret) break; - IP_VS_INFO("%s: loaded support on port[%d] = %d\n", - app->name, i, ports[i]); + pr_info("%s: loaded support on port[%d] = %d\n", + app->name, i, ports[i]); } if (ret) diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c index 98fb185..c1757f3 100644 --- a/net/netfilter/ipvs/ip_vs_lblc.c +++ b/net/netfilter/ipvs/ip_vs_lblc.c @@ -202,7 +202,7 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr, if (!en) { en = kmalloc(sizeof(*en), GFP_ATOMIC); if (!en) { - IP_VS_ERR("ip_vs_lblc_new(): no memory\n"); + pr_err("%s(): no memory\n", __func__); return NULL; } @@ -335,7 +335,7 @@ static int ip_vs_lblc_init_svc(struct ip_vs_service *svc) */ tbl = kmalloc(sizeof(*tbl), GFP_ATOMIC); if (tbl == NULL) { - IP_VS_ERR("ip_vs_lblc_init_svc(): no memory\n"); + pr_err("%s(): no memory\n", __func__); return -ENOMEM; } svc->sched_data = tbl; @@ -480,7 +480,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); - IP_VS_DBG(6, "ip_vs_lblc_schedule(): Scheduling...\n"); + IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); /* First look in our cache */ read_lock(&svc->sched_lock); diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c index 5f5e5f4..715b57f 100644 --- a/net/netfilter/ipvs/ip_vs_lblcr.c +++ b/net/netfilter/ipvs/ip_vs_lblcr.c @@ -111,7 +111,7 @@ ip_vs_dest_set_insert(struct ip_vs_dest_set *set, struct ip_vs_dest *dest) e = kmalloc(sizeof(*e), GFP_ATOMIC); if (e == NULL) { - IP_VS_ERR("ip_vs_dest_set_insert(): no memory\n"); + pr_err("%s(): no memory\n", __func__); return NULL; } @@ -205,8 +205,9 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set) } } - IP_VS_DBG_BUF(6, "ip_vs_dest_set_min: server %s:%d " + IP_VS_DBG_BUF(6, "%s(): server %s:%d " "activeconns %d refcnt %d weight %d overhead %d\n", + __func__, IP_VS_DBG_ADDR(least->af, &least->addr), ntohs(least->port), atomic_read(&least->activeconns), @@ -252,8 +253,9 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set) } } - IP_VS_DBG_BUF(6, "ip_vs_dest_set_max: server %s:%d " + IP_VS_DBG_BUF(6, "%s(): server %s:%d " "activeconns %d refcnt %d weight %d overhead %d\n", + __func__, IP_VS_DBG_ADDR(most->af, &most->addr), ntohs(most->port), atomic_read(&most->activeconns), atomic_read(&most->refcnt), @@ -377,7 +379,7 @@ ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr, if (!en) { en = kmalloc(sizeof(*en), GFP_ATOMIC); if (!en) { - IP_VS_ERR("ip_vs_lblcr_new(): no memory\n"); + pr_err("%s(): no memory\n", __func__); return NULL; } @@ -511,7 +513,7 @@ static int ip_vs_lblcr_init_svc(struct ip_vs_service *svc) */ tbl = kmalloc(sizeof(*tbl), GFP_ATOMIC); if (tbl == NULL) { - IP_VS_ERR("ip_vs_lblcr_init_svc(): no memory\n"); + pr_err("%s(): no memory\n", __func__); return -ENOMEM; } svc->sched_data = tbl; @@ -657,7 +659,7 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); - IP_VS_DBG(6, "ip_vs_lblcr_schedule(): Scheduling...\n"); + IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); /* First look in our cache */ read_lock(&svc->sched_lock); diff --git a/net/netfilter/ipvs/ip_vs_lc.c b/net/netfilter/ipvs/ip_vs_lc.c index 4ecd5e1..4f69db1 100644 --- a/net/netfilter/ipvs/ip_vs_lc.c +++ b/net/netfilter/ipvs/ip_vs_lc.c @@ -47,7 +47,7 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) struct ip_vs_dest *dest, *least = NULL; unsigned int loh = 0, doh; - IP_VS_DBG(6, "ip_vs_lc_schedule(): Scheduling...\n"); + IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); /* * Simply select the server with the least number of diff --git a/net/netfilter/ipvs/ip_vs_nq.c b/net/netfilter/ipvs/ip_vs_nq.c index 2224478..c413e18 100644 --- a/net/netfilter/ipvs/ip_vs_nq.c +++ b/net/netfilter/ipvs/ip_vs_nq.c @@ -60,7 +60,7 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) struct ip_vs_dest *dest, *least = NULL; unsigned int loh = 0, doh; - IP_VS_DBG(6, "ip_vs_nq_schedule(): Scheduling...\n"); + IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); /* * We calculate the load of each dest server as follows: diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c index a95bc40..85c8892 100644 --- a/net/netfilter/ipvs/ip_vs_proto.c +++ b/net/netfilter/ipvs/ip_vs_proto.c @@ -262,7 +262,7 @@ int __init ip_vs_protocol_init(void) #ifdef CONFIG_IP_VS_PROTO_ESP REGISTER_PROTOCOL(&ip_vs_protocol_esp); #endif - IP_VS_INFO("Registered protocols (%s)\n", &protocols[2]); + pr_info("Registered protocols (%s)\n", &protocols[2]); return 0; } diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index c36c80d..2278e14 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c @@ -664,7 +664,7 @@ tcp_app_conn_bind(struct ip_vs_conn *cp) break; spin_unlock(&tcp_app_lock); - IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->" + IP_VS_DBG_BUF(9, "%s(): Binding conn %s:%u->" "%s:%u to app %s on port %u\n", __func__, IP_VS_DBG_ADDR(cp->af, &cp->caddr), diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index 96ebe40..33a05d3 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c @@ -445,7 +445,7 @@ static int udp_app_conn_bind(struct ip_vs_conn *cp) break; spin_unlock(&udp_app_lock); - IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->" + IP_VS_DBG_BUF(9, "%s(): Binding conn %s:%u->" "%s:%u to app %s on port %u\n", __func__, IP_VS_DBG_ADDR(cp->af, &cp->caddr), diff --git a/net/netfilter/ipvs/ip_vs_rr.c b/net/netfilter/ipvs/ip_vs_rr.c index b01007e..e210f37 100644 --- a/net/netfilter/ipvs/ip_vs_rr.c +++ b/net/netfilter/ipvs/ip_vs_rr.c @@ -51,7 +51,7 @@ ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) struct list_head *p, *q; struct ip_vs_dest *dest; - IP_VS_DBG(6, "ip_vs_rr_schedule(): Scheduling...\n"); + IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); write_lock(&svc->sched_lock); p = (struct list_head *)svc->sched_data; diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c index 87bc5ea..bbc1ac7 100644 --- a/net/netfilter/ipvs/ip_vs_sched.c +++ b/net/netfilter/ipvs/ip_vs_sched.c @@ -47,11 +47,11 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc, int ret; if (svc == NULL) { - IP_VS_ERR("ip_vs_bind_scheduler(): svc arg NULL\n"); + pr_err("%s(): svc arg NULL\n", __func__); return -EINVAL; } if (scheduler == NULL) { - IP_VS_ERR("ip_vs_bind_scheduler(): scheduler arg NULL\n"); + pr_err("%s(): scheduler arg NULL\n", __func__); return -EINVAL; } @@ -60,7 +60,7 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc, if (scheduler->init_service) { ret = scheduler->init_service(svc); if (ret) { - IP_VS_ERR("ip_vs_bind_scheduler(): init error\n"); + pr_err("%s(): init error\n", __func__); return ret; } } @@ -77,19 +77,19 @@ int ip_vs_unbind_scheduler(struct ip_vs_service *svc) struct ip_vs_scheduler *sched; if (svc == NULL) { - IP_VS_ERR("ip_vs_unbind_scheduler(): svc arg NULL\n"); + pr_err("%s(): svc arg NULL\n", __func__); return -EINVAL; } sched = svc->scheduler; if (sched == NULL) { - IP_VS_ERR("ip_vs_unbind_scheduler(): svc isn't bound\n"); + pr_err("%s(): svc isn't bound\n", __func__); return -EINVAL; } if (sched->done_service) { if (sched->done_service(svc) != 0) { - IP_VS_ERR("ip_vs_unbind_scheduler(): done error\n"); + pr_err("%s(): done error\n", __func__); return -EINVAL; } } @@ -106,8 +106,7 @@ static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name) { struct ip_vs_scheduler *sched; - IP_VS_DBG(2, "ip_vs_sched_getbyname(): sched_name \"%s\"\n", - sched_name); + IP_VS_DBG(2, "%s(): sched_name \"%s\"\n", __func__, sched_name); read_lock_bh(&__ip_vs_sched_lock); @@ -173,12 +172,12 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler) struct ip_vs_scheduler *sched; if (!scheduler) { - IP_VS_ERR("register_ip_vs_scheduler(): NULL arg\n"); + pr_err("%s(): NULL arg\n", __func__); return -EINVAL; } if (!scheduler->name) { - IP_VS_ERR("register_ip_vs_scheduler(): NULL scheduler_name\n"); + pr_err("%s(): NULL scheduler_name\n", __func__); return -EINVAL; } @@ -190,8 +189,8 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler) if (!list_empty(&scheduler->n_list)) { write_unlock_bh(&__ip_vs_sched_lock); ip_vs_use_count_dec(); - IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler " - "already linked\n", scheduler->name); + pr_err("%s(): [%s] scheduler already linked\n", + __func__, scheduler->name); return -EINVAL; } @@ -203,9 +202,8 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler) if (strcmp(scheduler->name, sched->name) == 0) { write_unlock_bh(&__ip_vs_sched_lock); ip_vs_use_count_dec(); - IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler " - "already existed in the system\n", - scheduler->name); + pr_err("%s(): [%s] scheduler already existed " + "in the system\n", __func__, scheduler->name); return -EINVAL; } } @@ -215,7 +213,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler) list_add(&scheduler->n_list, &ip_vs_schedulers); write_unlock_bh(&__ip_vs_sched_lock); - IP_VS_INFO("[%s] scheduler registered.\n", scheduler->name); + pr_info("[%s] scheduler registered.\n", scheduler->name); return 0; } @@ -227,15 +225,15 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler) int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler) { if (!scheduler) { - IP_VS_ERR( "unregister_ip_vs_scheduler(): NULL arg\n"); + pr_err("%s(): NULL arg\n", __func__); return -EINVAL; } write_lock_bh(&__ip_vs_sched_lock); if (list_empty(&scheduler->n_list)) { write_unlock_bh(&__ip_vs_sched_lock); - IP_VS_ERR("unregister_ip_vs_scheduler(): [%s] scheduler " - "is not in the list. failed\n", scheduler->name); + pr_err("%s(): [%s] scheduler is not in the list. failed\n", + __func__, scheduler->name); return -EINVAL; } @@ -248,7 +246,7 @@ int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler) /* decrease the module use count */ ip_vs_use_count_dec(); - IP_VS_INFO("[%s] scheduler unregistered.\n", scheduler->name); + pr_info("[%s] scheduler unregistered.\n", scheduler->name); return 0; } diff --git a/net/netfilter/ipvs/ip_vs_sed.c b/net/netfilter/ipvs/ip_vs_sed.c index 4f745dd..1ab75a9 100644 --- a/net/netfilter/ipvs/ip_vs_sed.c +++ b/net/netfilter/ipvs/ip_vs_sed.c @@ -64,7 +64,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) struct ip_vs_dest *dest, *least; unsigned int loh, doh; - IP_VS_DBG(6, "ip_vs_sed_schedule(): Scheduling...\n"); + IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); /* * We calculate the load of each dest server as follows: diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c index fb4d2d2..8e6cfd3 100644 --- a/net/netfilter/ipvs/ip_vs_sh.c +++ b/net/netfilter/ipvs/ip_vs_sh.c @@ -147,7 +147,7 @@ static int ip_vs_sh_init_svc(struct ip_vs_service *svc) tbl = kmalloc(sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE, GFP_ATOMIC); if (tbl == NULL) { - IP_VS_ERR("ip_vs_sh_init_svc(): no memory\n"); + pr_err("%s(): no memory\n", __func__); return -ENOMEM; } svc->sched_data = tbl; diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index cc04c99..e177f0d 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -246,7 +246,7 @@ void ip_vs_sync_conn(struct ip_vs_conn *cp) if (!curr_sb) { if (!(curr_sb=ip_vs_sync_buff_create())) { spin_unlock(&curr_sb_lock); - IP_VS_ERR("ip_vs_sync_buff_create failed.\n"); + pr_err("ip_vs_sync_buff_create failed.\n"); return; } } @@ -412,7 +412,7 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen) if (dest) atomic_dec(&dest->refcnt); if (!cp) { - IP_VS_ERR("ip_vs_conn_new failed\n"); + pr_err("ip_vs_conn_new failed\n"); return; } } else if (!cp->dest) { @@ -580,8 +580,8 @@ static int bind_mcastif_addr(struct socket *sock, char *ifname) addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); if (!addr) - IP_VS_ERR("You probably need to specify IP address on " - "multicast interface.\n"); + pr_err("You probably need to specify IP address on " + "multicast interface.\n"); IP_VS_DBG(7, "binding socket with (%s) %pI4\n", ifname, &addr); @@ -605,13 +605,13 @@ static struct socket * make_send_sock(void) /* First create a socket */ result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); if (result < 0) { - IP_VS_ERR("Error during creation of socket; terminating\n"); + pr_err("Error during creation of socket; terminating\n"); return ERR_PTR(result); } result = set_mcast_if(sock->sk, ip_vs_master_mcast_ifn); if (result < 0) { - IP_VS_ERR("Error setting outbound mcast interface\n"); + pr_err("Error setting outbound mcast interface\n"); goto error; } @@ -620,14 +620,14 @@ static struct socket * make_send_sock(void) result = bind_mcastif_addr(sock, ip_vs_master_mcast_ifn); if (result < 0) { - IP_VS_ERR("Error binding address of the mcast interface\n"); + pr_err("Error binding address of the mcast interface\n"); goto error; } result = sock->ops->connect(sock, (struct sockaddr *) &mcast_addr, sizeof(struct sockaddr), 0); if (result < 0) { - IP_VS_ERR("Error connecting to the multicast addr\n"); + pr_err("Error connecting to the multicast addr\n"); goto error; } @@ -650,7 +650,7 @@ static struct socket * make_receive_sock(void) /* First create a socket */ result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); if (result < 0) { - IP_VS_ERR("Error during creation of socket; terminating\n"); + pr_err("Error during creation of socket; terminating\n"); return ERR_PTR(result); } @@ -660,7 +660,7 @@ static struct socket * make_receive_sock(void) result = sock->ops->bind(sock, (struct sockaddr *) &mcast_addr, sizeof(struct sockaddr)); if (result < 0) { - IP_VS_ERR("Error binding to the multicast addr\n"); + pr_err("Error binding to the multicast addr\n"); goto error; } @@ -669,7 +669,7 @@ static struct socket * make_receive_sock(void) (struct in_addr *) &mcast_addr.sin_addr, ip_vs_backup_mcast_ifn); if (result < 0) { - IP_VS_ERR("Error joining to the multicast group\n"); + pr_err("Error joining to the multicast group\n"); goto error; } @@ -709,7 +709,7 @@ ip_vs_send_sync_msg(struct socket *sock, struct ip_vs_sync_mesg *msg) msg->size = htons(msg->size); if (ip_vs_send_async(sock, (char *)msg, msize) != msize) - IP_VS_ERR("ip_vs_send_async error\n"); + pr_err("ip_vs_send_async error\n"); } static int @@ -740,9 +740,9 @@ static int sync_thread_master(void *data) struct ip_vs_sync_thread_data *tinfo = data; struct ip_vs_sync_buff *sb; - IP_VS_INFO("sync thread started: state = MASTER, mcast_ifn = %s, " - "syncid = %d\n", - ip_vs_master_mcast_ifn, ip_vs_master_syncid); + pr_info("sync thread started: state = MASTER, mcast_ifn = %s, " + "syncid = %d\n", + ip_vs_master_mcast_ifn, ip_vs_master_syncid); while (!kthread_should_stop()) { while ((sb = sb_dequeue())) { @@ -783,9 +783,9 @@ static int sync_thread_backup(void *data) struct ip_vs_sync_thread_data *tinfo = data; int len; - IP_VS_INFO("sync thread started: state = BACKUP, mcast_ifn = %s, " - "syncid = %d\n", - ip_vs_backup_mcast_ifn, ip_vs_backup_syncid); + pr_info("sync thread started: state = BACKUP, mcast_ifn = %s, " + "syncid = %d\n", + ip_vs_backup_mcast_ifn, ip_vs_backup_syncid); while (!kthread_should_stop()) { wait_event_interruptible(*tinfo->sock->sk->sk_sleep, @@ -797,7 +797,7 @@ static int sync_thread_backup(void *data) len = ip_vs_receive(tinfo->sock, tinfo->buf, sync_recv_mesg_maxlen); if (len <= 0) { - IP_VS_ERR("receiving message error\n"); + pr_err("receiving message error\n"); break; } @@ -827,7 +827,7 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid) int (*threadfn)(void *data); int result = -ENOMEM; - IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current)); + IP_VS_DBG(7, "%s(): pid %d\n", __func__, task_pid_nr(current)); IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %Zd bytes\n", sizeof(struct ip_vs_sync_conn)); @@ -904,14 +904,14 @@ out: int stop_sync_thread(int state) { - IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current)); + IP_VS_DBG(7, "%s(): pid %d\n", __func__, task_pid_nr(current)); if (state == IP_VS_STATE_MASTER) { if (!sync_master_thread) return -ESRCH; - IP_VS_INFO("stopping master sync thread %d ...\n", - task_pid_nr(sync_master_thread)); + pr_info("stopping master sync thread %d ...\n", + task_pid_nr(sync_master_thread)); /* * The lock synchronizes with sb_queue_tail(), so that we don't @@ -928,8 +928,8 @@ int stop_sync_thread(int state) if (!sync_backup_thread) return -ESRCH; - IP_VS_INFO("stopping backup sync thread %d ...\n", - task_pid_nr(sync_backup_thread)); + pr_info("stopping backup sync thread %d ...\n", + task_pid_nr(sync_backup_thread)); ip_vs_sync_state &= ~IP_VS_STATE_BACKUP; kthread_stop(sync_backup_thread); diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c index c39ebb6..70ff82cd 100644 --- a/net/netfilter/ipvs/ip_vs_wrr.c +++ b/net/netfilter/ipvs/ip_vs_wrr.c @@ -97,7 +97,7 @@ static int ip_vs_wrr_init_svc(struct ip_vs_service *svc) */ mark = kmalloc(sizeof(struct ip_vs_wrr_mark), GFP_ATOMIC); if (mark == NULL) { - IP_VS_ERR("ip_vs_wrr_init_svc(): no memory\n"); + pr_err("%s(): no memory\n", __func__); return -ENOMEM; } mark->cl = &svc->destinations; @@ -144,7 +144,7 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) struct ip_vs_wrr_mark *mark = svc->sched_data; struct list_head *p; - IP_VS_DBG(6, "ip_vs_wrr_schedule(): Scheduling...\n"); + IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); /* * This loop will always terminate, because mark->cw in (0, max_weight] diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 061e76d..30b3189 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -238,8 +238,8 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, EnterFunction(10); if (ip_route_output_key(&init_net, &rt, &fl)) { - IP_VS_DBG_RL("ip_vs_bypass_xmit(): ip_route_output error, dest: %pI4\n", - &iph->daddr); + IP_VS_DBG_RL("%s(): ip_route_output error, dest: %pI4\n", + __func__, &iph->daddr); goto tx_error_icmp; } @@ -248,7 +248,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) { ip_rt_put(rt); icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); - IP_VS_DBG_RL("ip_vs_bypass_xmit(): frag needed\n"); + IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error; } @@ -302,8 +302,8 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl); if (!rt) { - IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): ip6_route_output error, dest: %pI6\n", - &iph->daddr); + IP_VS_DBG_RL("%s(): ip6_route_output error, dest: %pI6\n", + __func__, &iph->daddr); goto tx_error_icmp; } @@ -312,7 +312,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, if (skb->len > mtu) { dst_release(&rt->u.dst); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); - IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): frag needed\n"); + IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error; } @@ -539,9 +539,9 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, EnterFunction(10); if (skb->protocol != htons(ETH_P_IP)) { - IP_VS_DBG_RL("ip_vs_tunnel_xmit(): protocol error, " + IP_VS_DBG_RL("%s(): protocol error, " "ETH_P_IP: %d, skb protocol: %d\n", - htons(ETH_P_IP), skb->protocol); + __func__, htons(ETH_P_IP), skb->protocol); goto tx_error; } @@ -553,7 +553,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr); if (mtu < 68) { ip_rt_put(rt); - IP_VS_DBG_RL("ip_vs_tunnel_xmit(): mtu less than 68\n"); + IP_VS_DBG_RL("%s(): mtu less than 68\n", __func__); goto tx_error; } if (skb_dst(skb)) @@ -565,7 +565,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, && mtu < ntohs(old_iph->tot_len)) { icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); ip_rt_put(rt); - IP_VS_DBG_RL("ip_vs_tunnel_xmit(): frag needed\n"); + IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error; } @@ -581,7 +581,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, if (!new_skb) { ip_rt_put(rt); kfree_skb(skb); - IP_VS_ERR_RL("ip_vs_tunnel_xmit(): no memory\n"); + IP_VS_ERR_RL("%s(): no memory\n", __func__); return NF_STOLEN; } kfree_skb(skb); @@ -649,9 +649,9 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, EnterFunction(10); if (skb->protocol != htons(ETH_P_IPV6)) { - IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): protocol error, " + IP_VS_DBG_RL("%s(): protocol error, " "ETH_P_IPV6: %d, skb protocol: %d\n", - htons(ETH_P_IPV6), skb->protocol); + __func__, htons(ETH_P_IPV6), skb->protocol); goto tx_error; } @@ -665,7 +665,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, /* TODO IPv6: do we need this check in IPv6? */ if (mtu < 1280) { dst_release(&rt->u.dst); - IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): mtu less than 1280\n"); + IP_VS_DBG_RL("%s(): mtu less than 1280\n", __func__); goto tx_error; } if (skb_dst(skb)) @@ -674,7 +674,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); dst_release(&rt->u.dst); - IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): frag needed\n"); + IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error; } @@ -690,7 +690,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, if (!new_skb) { dst_release(&rt->u.dst); kfree_skb(skb); - IP_VS_ERR_RL("ip_vs_tunnel_xmit_v6(): no memory\n"); + IP_VS_ERR_RL("%s(): no memory\n", __func__); return NF_STOLEN; } kfree_skb(skb); @@ -763,7 +763,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu) { icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); ip_rt_put(rt); - IP_VS_DBG_RL("ip_vs_dr_xmit(): frag needed\n"); + IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error; } @@ -816,7 +816,7 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, if (skb->len > mtu) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); dst_release(&rt->u.dst); - IP_VS_DBG_RL("ip_vs_dr_xmit_v6(): frag needed\n"); + IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error; } @@ -891,7 +891,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF))) { ip_rt_put(rt); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); - IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n"); + IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error; } @@ -966,7 +966,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, if (skb->len > mtu) { dst_release(&rt->u.dst); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); - IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n"); + IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error; } -- cgit v0.10.2 From e4c4e448cf557921ffbbbd6d6ddac81fdceacb4f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 30 Jul 2009 03:15:07 +0000 Subject: neigh: Convert garbage collection from softirq to workqueue Current neigh_periodic_timer() function is fired by timer IRQ, and scans one hash bucket each round (very litle work in fact) As we are supposed to scan whole hash table in 15 seconds, this means neigh_periodic_timer() can be fired very often. (depending on the number of concurrent hash entries we stored in this table) Converting this to a workqueue permits scanning whole table, minimizing icache pollution, and firing this work every 15 seconds, independantly of hash table size. This 15 seconds delay is not a hard number, as work is a deferrable one. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/net/neighbour.h b/include/net/neighbour.h index d8d790e..18b69b6 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -24,6 +24,7 @@ #include #include +#include #include /* @@ -167,7 +168,7 @@ struct neigh_table int gc_thresh2; int gc_thresh3; unsigned long last_flush; - struct timer_list gc_timer; + struct delayed_work gc_work; struct timer_list proxy_timer; struct sk_buff_head proxy_queue; atomic_t entries; @@ -178,7 +179,6 @@ struct neigh_table struct neighbour **hash_buckets; unsigned int hash_mask; __u32 hash_rnd; - unsigned int hash_chain_gc; struct pneigh_entry **phash_buckets; }; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index c6f9ad8..e587e68 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -692,75 +692,74 @@ static void neigh_connect(struct neighbour *neigh) hh->hh_output = neigh->ops->hh_output; } -static void neigh_periodic_timer(unsigned long arg) +static void neigh_periodic_work(struct work_struct *work) { - struct neigh_table *tbl = (struct neigh_table *)arg; + struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work); struct neighbour *n, **np; - unsigned long expire, now = jiffies; + unsigned int i; NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs); - write_lock(&tbl->lock); + write_lock_bh(&tbl->lock); /* * periodically recompute ReachableTime from random function */ - if (time_after(now, tbl->last_rand + 300 * HZ)) { + if (time_after(jiffies, tbl->last_rand + 300 * HZ)) { struct neigh_parms *p; - tbl->last_rand = now; + tbl->last_rand = jiffies; for (p = &tbl->parms; p; p = p->next) p->reachable_time = neigh_rand_reach_time(p->base_reachable_time); } - np = &tbl->hash_buckets[tbl->hash_chain_gc]; - tbl->hash_chain_gc = ((tbl->hash_chain_gc + 1) & tbl->hash_mask); + for (i = 0 ; i <= tbl->hash_mask; i++) { + np = &tbl->hash_buckets[i]; - while ((n = *np) != NULL) { - unsigned int state; + while ((n = *np) != NULL) { + unsigned int state; - write_lock(&n->lock); + write_lock(&n->lock); - state = n->nud_state; - if (state & (NUD_PERMANENT | NUD_IN_TIMER)) { - write_unlock(&n->lock); - goto next_elt; - } + state = n->nud_state; + if (state & (NUD_PERMANENT | NUD_IN_TIMER)) { + write_unlock(&n->lock); + goto next_elt; + } - if (time_before(n->used, n->confirmed)) - n->used = n->confirmed; + if (time_before(n->used, n->confirmed)) + n->used = n->confirmed; - if (atomic_read(&n->refcnt) == 1 && - (state == NUD_FAILED || - time_after(now, n->used + n->parms->gc_staletime))) { - *np = n->next; - n->dead = 1; + if (atomic_read(&n->refcnt) == 1 && + (state == NUD_FAILED || + time_after(jiffies, n->used + n->parms->gc_staletime))) { + *np = n->next; + n->dead = 1; + write_unlock(&n->lock); + neigh_cleanup_and_release(n); + continue; + } write_unlock(&n->lock); - neigh_cleanup_and_release(n); - continue; - } - write_unlock(&n->lock); next_elt: - np = &n->next; + np = &n->next; + } + /* + * It's fine to release lock here, even if hash table + * grows while we are preempted. + */ + write_unlock_bh(&tbl->lock); + cond_resched(); + write_lock_bh(&tbl->lock); } - /* Cycle through all hash buckets every base_reachable_time/2 ticks. * ARP entry timeouts range from 1/2 base_reachable_time to 3/2 * base_reachable_time. */ - expire = tbl->parms.base_reachable_time >> 1; - expire /= (tbl->hash_mask + 1); - if (!expire) - expire = 1; - - if (expire>HZ) - mod_timer(&tbl->gc_timer, round_jiffies(now + expire)); - else - mod_timer(&tbl->gc_timer, now + expire); - - write_unlock(&tbl->lock); + schedule_delayed_work(&tbl->gc_work, + tbl->parms.base_reachable_time >> 1); + write_unlock_bh(&tbl->lock); } static __inline__ int neigh_max_probes(struct neighbour *n) @@ -1442,10 +1441,8 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd)); rwlock_init(&tbl->lock); - setup_timer(&tbl->gc_timer, neigh_periodic_timer, (unsigned long)tbl); - tbl->gc_timer.expires = now + 1; - add_timer(&tbl->gc_timer); - + INIT_DELAYED_WORK_DEFERRABLE(&tbl->gc_work, neigh_periodic_work); + schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time); setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl); skb_queue_head_init_class(&tbl->proxy_queue, &neigh_table_proxy_queue_class); @@ -1482,7 +1479,8 @@ int neigh_table_clear(struct neigh_table *tbl) struct neigh_table **tp; /* It is not clean... Fix it to unload IPv6 module safely */ - del_timer_sync(&tbl->gc_timer); + cancel_delayed_work(&tbl->gc_work); + flush_scheduled_work(); del_timer_sync(&tbl->proxy_timer); pneigh_queue_purge(&tbl->proxy_queue); neigh_ifdown(tbl, NULL); @@ -1752,7 +1750,6 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, .ndtc_last_rand = jiffies_to_msecs(rand_delta), .ndtc_hash_rnd = tbl->hash_rnd, .ndtc_hash_mask = tbl->hash_mask, - .ndtc_hash_chain_gc = tbl->hash_chain_gc, .ndtc_proxy_qlen = tbl->proxy_queue.qlen, }; -- cgit v0.10.2 From 559059b27f1768e89adc204f3ba2cb82882c15ca Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sun, 2 Aug 2009 16:48:55 +0800 Subject: ALSA: hda: add IbexPeak/Clarkdale HDMI model with static cvt/pin number The new IbexPeak HDMI codec has 3 pin nodes and 2 converter nodes. Here we assume only the first ones will be used. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 032850e..01a18ed 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -33,8 +33,8 @@ #include "hda_codec.h" #include "hda_local.h" -#define CVT_NID 0x02 /* audio converter */ -#define PIN_NID 0x03 /* HDMI output pin */ +static hda_nid_t cvt_nid; /* audio converter */ +static hda_nid_t pin_nid; /* HDMI output pin */ #define INTEL_HDMI_EVENT_TAG 0x08 @@ -44,30 +44,6 @@ struct intel_hdmi_spec { struct hdmi_eld sink_eld; }; -static struct hda_verb pinout_enable_verb[] = { - {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {} /* terminator */ -}; - -static struct hda_verb unsolicited_response_verb[] = { - {PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | - INTEL_HDMI_EVENT_TAG}, - {} -}; - -static struct hda_verb def_chan_map[] = { - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77}, - {} -}; - - struct hdmi_audio_infoframe { u8 type; /* 0x84 */ u8 ver; /* 0x01 */ @@ -244,11 +220,12 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, static void hdmi_enable_output(struct hda_codec *codec) { /* Unmute */ - if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, PIN_NID, 0, + if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); /* Enable pin out */ - snd_hda_sequence_write(codec, pinout_enable_verb); + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); } /* @@ -256,8 +233,8 @@ static void hdmi_enable_output(struct hda_codec *codec) */ static void hdmi_start_infoframe_trans(struct hda_codec *codec) { - hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); - snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, + hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); + snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); } @@ -266,20 +243,20 @@ static void hdmi_start_infoframe_trans(struct hda_codec *codec) */ static void hdmi_stop_infoframe_trans(struct hda_codec *codec) { - hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); - snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, + hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); + snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); } static int hdmi_get_channel_count(struct hda_codec *codec) { - return 1 + snd_hda_codec_read(codec, CVT_NID, 0, + return 1 + snd_hda_codec_read(codec, cvt_nid, 0, AC_VERB_GET_CVT_CHAN_COUNT, 0); } static void hdmi_set_channel_count(struct hda_codec *codec, int chs) { - snd_hda_codec_write(codec, CVT_NID, 0, + snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); if (chs != hdmi_get_channel_count(codec)) @@ -294,7 +271,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec) int slot; for (i = 0; i < 8; i++) { - slot = snd_hda_codec_read(codec, CVT_NID, 0, + slot = snd_hda_codec_read(codec, cvt_nid, 0, AC_VERB_GET_HDMI_CHAN_SLOT, i); printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", slot >> 4, slot & 0x7); @@ -307,7 +284,7 @@ static void hdmi_parse_eld(struct hda_codec *codec) struct intel_hdmi_spec *spec = codec->spec; struct hdmi_eld *eld = &spec->sink_eld; - if (!snd_hdmi_get_eld(eld, codec, PIN_NID)) + if (!snd_hdmi_get_eld(eld, codec, pin_nid)) snd_hdmi_show_eld(eld); } @@ -322,11 +299,11 @@ static void hdmi_debug_dip_size(struct hda_codec *codec) int i; int size; - size = snd_hdmi_get_eld_size(codec, PIN_NID); + size = snd_hdmi_get_eld_size(codec, pin_nid); printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); for (i = 0; i < 8; i++) { - size = snd_hda_codec_read(codec, PIN_NID, 0, + size = snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, i); printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); } @@ -340,15 +317,15 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec) int size; int pi, bi; for (i = 0; i < 8; i++) { - size = snd_hda_codec_read(codec, PIN_NID, 0, + size = snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, i); if (size == 0) continue; - hdmi_set_dip_index(codec, PIN_NID, i, 0x0); + hdmi_set_dip_index(codec, pin_nid, i, 0x0); for (j = 1; j < 1000; j++) { - hdmi_write_dip_byte(codec, PIN_NID, 0x0); - hdmi_get_dip_index(codec, PIN_NID, &pi, &bi); + hdmi_write_dip_byte(codec, pin_nid, 0x0); + hdmi_get_dip_index(codec, pin_nid, &pi, &bi); if (pi != i) snd_printd(KERN_INFO "dip index %d: %d != %d\n", bi, pi, i); @@ -376,9 +353,9 @@ static void hdmi_fill_audio_infoframe(struct hda_codec *codec, sum += params[i]; ai->checksum = - sum; - hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); + hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); for (i = 0; i < sizeof(ai); i++) - hdmi_write_dip_byte(codec, PIN_NID, params[i]); + hdmi_write_dip_byte(codec, pin_nid, params[i]); } /* @@ -465,6 +442,8 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, static void hdmi_setup_channel_mapping(struct hda_codec *codec, struct hdmi_audio_infoframe *ai) { + int i; + if (!ai->CA) return; @@ -473,7 +452,11 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, * ALSA sequence is front/surr/clfe/side? */ - snd_hda_sequence_write(codec, def_chan_map); + for (i = 0; i < 8; i++) + snd_hda_codec_write(codec, cvt_nid, 0, + AC_VERB_SET_HDMI_CHAN_SLOT, + (i << 4) | i); + hdmi_debug_channel_mapping(codec); } @@ -597,7 +580,6 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, - .nid = CVT_NID, /* NID to query formats and rates and setup streams */ .ops = { .open = intel_hdmi_playback_pcm_open, .close = intel_hdmi_playback_pcm_close, @@ -613,6 +595,9 @@ static int intel_hdmi_build_pcms(struct hda_codec *codec) codec->num_pcms = 1; codec->pcm_info = info; + /* NID to query formats and rates and setup streams */ + intel_hdmi_pcm_playback.nid = cvt_nid; + info->name = "INTEL HDMI"; info->pcm_type = HDA_PCM_TYPE_HDMI; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; @@ -636,8 +621,9 @@ static int intel_hdmi_init(struct hda_codec *codec) { hdmi_enable_output(codec); - snd_hda_sequence_write(codec, unsolicited_response_verb); - + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | INTEL_HDMI_EVENT_TAG); return 0; } @@ -657,7 +643,7 @@ static struct hda_codec_ops intel_hdmi_patch_ops = { .unsol_event = intel_hdmi_unsol_event, }; -static int patch_intel_hdmi(struct hda_codec *codec) +static int do_patch_intel_hdmi(struct hda_codec *codec) { struct intel_hdmi_spec *spec; @@ -667,7 +653,7 @@ static int patch_intel_hdmi(struct hda_codec *codec) spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 8; - spec->multiout.dig_out_nid = CVT_NID; + spec->multiout.dig_out_nid = cvt_nid; codec->spec = spec; codec->patch_ops = intel_hdmi_patch_ops; @@ -679,13 +665,27 @@ static int patch_intel_hdmi(struct hda_codec *codec) return 0; } +static int patch_intel_hdmi(struct hda_codec *codec) +{ + cvt_nid = 0x02; + pin_nid = 0x03; + return do_patch_intel_hdmi(codec); +} + +static int patch_intel_hdmi_ibexpeak(struct hda_codec *codec) +{ + cvt_nid = 0x02; + pin_nid = 0x04; + return do_patch_intel_hdmi(codec); +} + static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, - { .id = 0x80860054, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, + { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; -- cgit v0.10.2 From 51840409b6c928eead140157d4e9fc267f50caf9 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sun, 2 Aug 2009 18:14:44 +0200 Subject: ALSA: pcm - Tell user that stream to be rewound is suspended Return STRPIPE instead of EBADF when userspace attempts to rewind of forward a stream that was suspended in meanwhile, so that it can be recovered by snd_pcm_recover(). This was causing Pulseaudio to unload the ALSA sink module under a race condition when it attempted to rewind the stream right after resume from suspend, before writing to the stream which would cause it to revive the stream otherwise. Tested to work with Pulseaudio patched to attempt to snd_pcm_recover() upon receiving an error from snd_pcm_rewind(). Signed-off-by: Lubomir Rintel Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ac2150e..d89c816 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2208,6 +2208,9 @@ static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *subst case SNDRV_PCM_STATE_XRUN: ret = -EPIPE; goto __end; + case SNDRV_PCM_STATE_SUSPENDED: + ret = -ESTRPIPE; + goto __end; default: ret = -EBADFD; goto __end; @@ -2253,6 +2256,9 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substr case SNDRV_PCM_STATE_XRUN: ret = -EPIPE; goto __end; + case SNDRV_PCM_STATE_SUSPENDED: + ret = -ESTRPIPE; + goto __end; default: ret = -EBADFD; goto __end; @@ -2299,6 +2305,9 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs case SNDRV_PCM_STATE_XRUN: ret = -EPIPE; goto __end; + case SNDRV_PCM_STATE_SUSPENDED: + ret = -ESTRPIPE; + goto __end; default: ret = -EBADFD; goto __end; @@ -2345,6 +2354,9 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst case SNDRV_PCM_STATE_XRUN: ret = -EPIPE; goto __end; + case SNDRV_PCM_STATE_SUSPENDED: + ret = -ESTRPIPE; + goto __end; default: ret = -EBADFD; goto __end; -- cgit v0.10.2 From 47cab6a722d44c71c4f8224017ef548522243cf4 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 3 Aug 2009 09:31:54 +0200 Subject: debug lockups: Improve lockup detection, fix generic arch fallback As Andrew noted, my previous patch ("debug lockups: Improve lockup detection") broke/removed SysRq-L support from architecture that do not provide a __trigger_all_cpu_backtrace implementation. Restore a fallback path and clean up the SysRq-L machinery a bit: - Rename the arch method to arch_trigger_all_cpu_backtrace() - Simplify the define - Document the method a bit - in the hope of more architectures adding support for it. [ The patch touches Sparc code for the rename. ] Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Andrew Morton Cc: Linus Torvalds Cc: "David S. Miller" LKML-Reference: <20090802140809.7ec4bb6b.akpm@linux-foundation.org> Signed-off-by: Ingo Molnar diff --git a/arch/sparc/include/asm/irq_64.h b/arch/sparc/include/asm/irq_64.h index 1934f2c..a0b443c 100644 --- a/arch/sparc/include/asm/irq_64.h +++ b/arch/sparc/include/asm/irq_64.h @@ -89,8 +89,8 @@ static inline unsigned long get_softint(void) return retval; } -void __trigger_all_cpu_backtrace(void); -#define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace() +void arch_trigger_all_cpu_backtrace(void); +#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace extern void *hardirq_stack[NR_CPUS]; extern void *softirq_stack[NR_CPUS]; diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 4041f94..18d6785 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -251,7 +251,7 @@ static void __global_reg_poll(struct global_reg_snapshot *gp) } } -void __trigger_all_cpu_backtrace(void) +void arch_trigger_all_cpu_backtrace(void) { struct thread_info *tp = current_thread_info(); struct pt_regs *regs = get_irq_regs(); @@ -304,7 +304,7 @@ void __trigger_all_cpu_backtrace(void) static void sysrq_handle_globreg(int key, struct tty_struct *tty) { - __trigger_all_cpu_backtrace(); + arch_trigger_all_cpu_backtrace(); } static struct sysrq_key_op sparc_globalreg_op = { diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h index c86e5ed4..e63cf7d 100644 --- a/arch/x86/include/asm/nmi.h +++ b/arch/x86/include/asm/nmi.h @@ -45,8 +45,8 @@ extern int proc_nmi_enabled(struct ctl_table *, int , struct file *, void __user *, size_t *, loff_t *); extern int unknown_nmi_panic; -void __trigger_all_cpu_backtrace(void); -#define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace() +void arch_trigger_all_cpu_backtrace(void); +#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace static inline void localise_nmi_watchdog(void) { diff --git a/arch/x86/kernel/apic/nmi.c b/arch/x86/kernel/apic/nmi.c index 1bb1ac2..db72202 100644 --- a/arch/x86/kernel/apic/nmi.c +++ b/arch/x86/kernel/apic/nmi.c @@ -554,7 +554,7 @@ int do_nmi_callback(struct pt_regs *regs, int cpu) return 0; } -void __trigger_all_cpu_backtrace(void) +void arch_trigger_all_cpu_backtrace(void) { int i; diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 165f307..50eecfe 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -223,7 +223,20 @@ static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus); static void sysrq_handle_showallcpus(int key, struct tty_struct *tty) { - trigger_all_cpu_backtrace(); + /* + * Fall back to the workqueue based printing if the + * backtrace printing did not succeed or the + * architecture has no support for it: + */ + if (!trigger_all_cpu_backtrace()) { + struct pt_regs *regs = get_irq_regs(); + + if (regs) { + printk(KERN_INFO "CPU%d:\n", smp_processor_id()); + show_regs(regs); + } + schedule_work(&sysrq_showallcpus); + } } static struct sysrq_key_op sysrq_showallcpus_op = { diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 29af2d5..b752e80 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -28,8 +28,23 @@ static inline void acpi_nmi_disable(void) { } static inline void acpi_nmi_enable(void) { } #endif -#ifndef trigger_all_cpu_backtrace -#define trigger_all_cpu_backtrace() do { } while (0) +/* + * Create trigger_all_cpu_backtrace() out of the arch-provided + * base function. Return whether such support was available, + * to allow calling code to fall back to some other mechanism: + */ +#ifdef arch_trigger_all_cpu_backtrace +static inline bool trigger_all_cpu_backtrace(void) +{ + arch_trigger_all_cpu_backtrace(); + + return true; +} +#else +static inline bool trigger_all_cpu_backtrace(void) +{ + return false; +} #endif #endif -- cgit v0.10.2 From 15cfa2b3db8b64d4e66d36fb88d21bae9ea3dfba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 3 Aug 2009 14:23:33 +0200 Subject: ALSA: hda - Fix line-out jack detection The commit fefd67f31ee7f5259344e36a237d59b47e8715cf ALSA: hda - Add line-out jack detection on IDT/STAC codecs enabled wrong pins for jack detections. Fixed to the correct ones. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index b3c53f7..9961fe1 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4350,8 +4350,8 @@ static int stac92xx_init(struct hda_codec *codec) } if (cfg->line_out_type == AUTO_PIN_LINE_OUT) { /* enable pin-detect for line-outs as well */ - for (i = 0; i < cfg->hp_outs; i++) { - hda_nid_t nid = cfg->hp_pins[i]; + for (i = 0; i < cfg->line_outs; i++) { + hda_nid_t nid = cfg->line_out_pins[i]; enable_pin_detect(codec, nid, STAC_LO_EVENT); } } -- cgit v0.10.2 From 7084a42b965d972079201414d19a399e65b26099 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 10 Jul 2009 22:24:27 +0100 Subject: ASoC: Add I/O control bus information to factored out cache setup While writes tend to be able to use a fairly bus independant format to do the writes reads are all bus specific. To allow us to factor out this code include the bus type as a parameter when setting up the cache. Initially just use this to factor out hw_write_t for I2C. Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 27409dd..d0b29a5 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -187,13 +187,20 @@ typedef int (*hw_read_t)(void *,char* ,int); extern struct snd_ac97_bus_ops soc_ac97_ops; +enum snd_soc_control_type { + SND_SOC_CUSTOM, + SND_SOC_I2C, + SND_SOC_SPI, +}; + int snd_soc_register_platform(struct snd_soc_platform *platform); void snd_soc_unregister_platform(struct snd_soc_platform *platform); int snd_soc_register_codec(struct snd_soc_codec *codec); void snd_soc_unregister_codec(struct snd_soc_codec *codec); int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg); int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, - int addr_bits, int data_bits); + int addr_bits, int data_bits, + enum snd_soc_control_type control); #ifdef CONFIG_PM int snd_soc_suspend_device(struct device *dev); diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 7a169bf..4ca724f 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -564,7 +564,8 @@ static int wm8510_resume(struct platform_device *pdev) * initialise the WM8510 driver * register the mixer and dsp interfaces with the kernel */ -static int wm8510_init(struct snd_soc_device *socdev) +static int wm8510_init(struct snd_soc_device *socdev, + enum snd_soc_control_type control) { struct snd_soc_codec *codec = socdev->card->codec; int ret = 0; @@ -580,7 +581,7 @@ static int wm8510_init(struct snd_soc_device *socdev) if (codec->reg_cache == NULL) return -ENOMEM; - ret = snd_soc_codec_set_cache_io(codec, 7, 9); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); if (ret < 0) { printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret); @@ -635,7 +636,7 @@ static int wm8510_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = wm8510_init(socdev); + ret = wm8510_init(socdev, SND_SOC_I2C); if (ret < 0) pr_err("failed to initialise WM8510\n"); @@ -715,7 +716,7 @@ static int __devinit wm8510_spi_probe(struct spi_device *spi) codec->control_data = spi; - ret = wm8510_init(socdev); + ret = wm8510_init(socdev, SND_SOC_SPI); if (ret < 0) dev_err(&spi->dev, "failed to initialise WM8510\n"); @@ -784,7 +785,6 @@ static int wm8510_probe(struct platform_device *pdev) wm8510_socdev = socdev; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { - codec->hw_write = (hw_write_t)i2c_master_send; ret = wm8510_add_i2c_device(pdev, setup); } #endif diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 2250ade..d547347 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -832,7 +832,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8580 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); -static int wm8580_register(struct wm8580_priv *wm8580) +static int wm8580_register(struct wm8580_priv *wm8580, + enum snd_soc_control_type control) { int ret, i; struct snd_soc_codec *codec = &wm8580->codec; @@ -859,7 +860,7 @@ static int wm8580_register(struct wm8580_priv *wm8580) memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg)); - ret = snd_soc_codec_set_cache_io(codec, 7, 9); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); goto err; @@ -944,14 +945,13 @@ static int wm8580_i2c_probe(struct i2c_client *i2c, return -ENOMEM; codec = &wm8580->codec; - codec->hw_write = (hw_write_t)i2c_master_send; i2c_set_clientdata(i2c, wm8580); codec->control_data = i2c; codec->dev = &i2c->dev; - return wm8580_register(wm8580); + return wm8580_register(wm8580, SND_SOC_I2C); } static int wm8580_i2c_remove(struct i2c_client *client) diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 66da44b..a28630d 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -248,7 +248,8 @@ static int wm8728_resume(struct platform_device *pdev) * initialise the WM8728 driver * register the mixer and dsp interfaces with the kernel */ -static int wm8728_init(struct snd_soc_device *socdev) +static int wm8728_init(struct snd_soc_device *socdev, + enum snd_soc_control_type control) { struct snd_soc_codec *codec = socdev->card->codec; int ret = 0; @@ -266,7 +267,7 @@ static int wm8728_init(struct snd_soc_device *socdev) if (codec->reg_cache == NULL) return -ENOMEM; - ret = snd_soc_codec_set_cache_io(codec, 7, 9); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); if (ret < 0) { printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n", ret); @@ -323,7 +324,7 @@ static int wm8728_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = wm8728_init(socdev); + ret = wm8728_init(socdev, SND_SOC_I2C); if (ret < 0) pr_err("failed to initialise WM8728\n"); @@ -403,7 +404,7 @@ static int __devinit wm8728_spi_probe(struct spi_device *spi) codec->control_data = spi; - ret = wm8728_init(socdev); + ret = wm8728_init(socdev, SND_SOC_SPI); if (ret < 0) dev_err(&spi->dev, "failed to initialise WM8728\n"); @@ -472,7 +473,6 @@ static int wm8728_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { - codec->hw_write = (hw_write_t)i2c_master_send; ret = wm8728_add_i2c_device(pdev, setup); } #endif diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 4eb84ff..27fc942 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -504,7 +504,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8731 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); -static int wm8731_register(struct wm8731_priv *wm8731) +static int wm8731_register(struct wm8731_priv *wm8731, + enum snd_soc_control_type control) { int ret; struct snd_soc_codec *codec = &wm8731->codec; @@ -531,7 +532,7 @@ static int wm8731_register(struct wm8731_priv *wm8731) memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg)); - ret = snd_soc_codec_set_cache_io(codec, 7, 9); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); goto err; @@ -630,7 +631,7 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi) dev_set_drvdata(&spi->dev, wm8731); - return wm8731_register(wm8731); + return wm8731_register(wm8731, SND_SOC_SPI); } static int __devexit wm8731_spi_remove(struct spi_device *spi) @@ -682,14 +683,13 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c, return -ENOMEM; codec = &wm8731->codec; - codec->hw_write = (hw_write_t)i2c_master_send; i2c_set_clientdata(i2c, wm8731); codec->control_data = i2c; codec->dev = &i2c->dev; - return wm8731_register(wm8731); + return wm8731_register(wm8731, SND_SOC_I2C); } static __devexit int wm8731_i2c_remove(struct i2c_client *client) diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index ed09043..e6422b1 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -711,7 +711,8 @@ static int wm8750_resume(struct platform_device *pdev) * initialise the WM8750 driver * register the mixer and dsp interfaces with the kernel */ -static int wm8750_init(struct snd_soc_device *socdev) +static int wm8750_init(struct snd_soc_device *socdev, + enum snd_soc_control_type control) { struct snd_soc_codec *codec = socdev->card->codec; int reg, ret = 0; @@ -726,7 +727,7 @@ static int wm8750_init(struct snd_soc_device *socdev) if (codec->reg_cache == NULL) return -ENOMEM; - ret = snd_soc_codec_set_cache_io(codec, 7, 9); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); if (ret < 0) { printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret); goto err; @@ -809,7 +810,7 @@ static int wm8750_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = wm8750_init(socdev); + ret = wm8750_init(socdev, SND_SOC_I2C); if (ret < 0) pr_err("failed to initialise WM8750\n"); @@ -889,7 +890,7 @@ static int __devinit wm8750_spi_probe(struct spi_device *spi) codec->control_data = spi; - ret = wm8750_init(socdev); + ret = wm8750_init(socdev, SND_SOC_SPI); if (ret < 0) dev_err(&spi->dev, "failed to initialise WM8750\n"); @@ -967,7 +968,6 @@ static int wm8750_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { - codec->hw_write = (hw_write_t)i2c_master_send; ret = wm8750_add_i2c_device(pdev, setup); } #endif diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index c529ffc..f59703b 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -747,7 +747,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8960 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960); -static int wm8960_register(struct wm8960_priv *wm8960) +static int wm8960_register(struct wm8960_priv *wm8960, + enum snd_soc_control_type control) { struct wm8960_data *pdata = wm8960->codec.dev->platform_data; struct snd_soc_codec *codec = &wm8960->codec; @@ -785,7 +786,7 @@ static int wm8960_register(struct wm8960_priv *wm8960) memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg)); - ret = snd_soc_codec_set_cache_io(codec, 7, 9); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); goto err; @@ -866,14 +867,13 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c, return -ENOMEM; codec = &wm8960->codec; - codec->hw_write = (hw_write_t)i2c_master_send; i2c_set_clientdata(i2c, wm8960); codec->control_data = i2c; codec->dev = &i2c->dev; - return wm8960_register(wm8960); + return wm8960_register(wm8960, SND_SOC_I2C); } static __devexit int wm8960_i2c_remove(struct i2c_client *client) diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 53f3bc9..d66efb0 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -640,7 +640,8 @@ static int wm8971_resume(struct platform_device *pdev) return 0; } -static int wm8971_init(struct snd_soc_device *socdev) +static int wm8971_init(struct snd_soc_device *socdev, + enum snd_soc_control_type control) { struct snd_soc_codec *codec = socdev->card->codec; int reg, ret = 0; @@ -656,7 +657,7 @@ static int wm8971_init(struct snd_soc_device *socdev) if (codec->reg_cache == NULL) return -ENOMEM; - ret = snd_soc_codec_set_cache_io(codec, 7, 9); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); if (ret < 0) { printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret); goto err; @@ -734,7 +735,7 @@ static int wm8971_i2c_probe(struct i2c_client *i2c, codec->control_data = i2c; - ret = wm8971_init(socdev); + ret = wm8971_init(socdev, SND_SOC_I2C); if (ret < 0) pr_err("failed to initialise WM8971\n"); @@ -844,7 +845,6 @@ static int wm8971_probe(struct platform_device *pdev) #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) if (setup->i2c_address) { - codec->hw_write = (hw_write_t)i2c_master_send; ret = wm8971_add_i2c_device(pdev, setup); } #endif diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 7d5b807..7486d3e 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -825,7 +825,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8988 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988); -static int wm8988_register(struct wm8988_priv *wm8988) +static int wm8988_register(struct wm8988_priv *wm8988, + enum snd_soc_control_type control) { struct snd_soc_codec *codec = &wm8988->codec; int ret; @@ -854,7 +855,7 @@ static int wm8988_register(struct wm8988_priv *wm8988) memcpy(codec->reg_cache, wm8988_reg, sizeof(wm8988_reg)); - ret = snd_soc_codec_set_cache_io(codec, 7, 9); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); goto err; @@ -927,14 +928,13 @@ static int wm8988_i2c_probe(struct i2c_client *i2c, return -ENOMEM; codec = &wm8988->codec; - codec->hw_write = (hw_write_t)i2c_master_send; i2c_set_clientdata(i2c, wm8988); codec->control_data = i2c; codec->dev = &i2c->dev; - return wm8988_register(wm8988); + return wm8988_register(wm8988, SND_SOC_I2C); } static int wm8988_i2c_remove(struct i2c_client *client) @@ -1019,7 +1019,7 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi) spi->dev.driver_data = wm8988; - return wm8988_register(wm8988); + return wm8988_register(wm8988, SND_SOC_SPI); } static int __devexit wm8988_spi_remove(struct spi_device *spi) diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 4eb4333..8b12668 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -11,6 +11,7 @@ * option) any later version. */ +#include #include static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, @@ -62,6 +63,7 @@ static struct { * @type: Type of cache. * @addr_bits: Number of bits of register address data. * @data_bits: Number of bits of data per register. + * @control: Control bus used. * * Register formats are frequently shared between many I2C and SPI * devices. In order to promote code reuse the ASoC core provides @@ -75,7 +77,8 @@ static struct { * volatile registers. */ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, - int addr_bits, int data_bits) + int addr_bits, int data_bits, + enum snd_soc_control_type control) { int i; @@ -100,6 +103,20 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, codec->write = io_types[i].write; codec->read = io_types[i].read; + switch (control) { + case SND_SOC_CUSTOM: + break; + + case SND_SOC_I2C: +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + codec->hw_write = (hw_write_t)i2c_master_send; +#endif + break; + + case SND_SOC_SPI: + break; + } + return 0; } EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); -- cgit v0.10.2 From afa2f1066e7288a9e4f8e3fda277da245219dffc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 10 Jul 2009 23:11:24 +0100 Subject: ASoC: Factor out I2C 8 bit address 16 bit data I/O As part of this refactoring the type of the CODEC hw_read operation is changed to match the regular read operation. Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index d0b29a5..4a5846e 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -373,7 +373,7 @@ struct snd_soc_codec { size_t, unsigned int); int (*volatile_register)(unsigned int); hw_write_t hw_write; - hw_read_t hw_read; + unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int); void *reg_cache; short reg_cache_size; short reg_cache_step; diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 8b12668..ab058b8 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -46,14 +46,82 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, return -EIO; } +static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 *reg_cache = codec->reg_cache; + u8 data[3]; + + data[0] = reg; + data[1] = (value >> 8) & 0xff; + data[2] = value & 0xff; + + if (!snd_soc_codec_volatile_register(codec, reg)) + reg_cache[reg] = value; + + if (codec->hw_write(codec->control_data, data, 3) == 3) + return 0; + else + return -EIO; +} + +static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + + if (reg >= codec->reg_cache_size || + snd_soc_codec_volatile_register(codec, reg)) + return codec->hw_read(codec, reg); + else + return cache[reg]; +} + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, + unsigned int r) +{ + struct i2c_msg xfer[2]; + u8 reg = r; + u16 data; + int ret; + struct i2c_client *client = codec->control_data; + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = ® + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (u8 *)&data; + + ret = i2c_transfer(client->adapter, xfer, 2); + if (ret != 2) { + dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + return 0; + } + + return (data >> 8) | ((data & 0xff) << 8); +} +#else +#define snd_soc_8_16_read_i2c NULL +#endif static struct { int addr_bits; int data_bits; - int (*write)(struct snd_soc_codec *, unsigned int, unsigned int); + int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); unsigned int (*read)(struct snd_soc_codec *, unsigned int); + unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); } io_types[] = { { 7, 9, snd_soc_7_9_write, snd_soc_7_9_read }, + { 8, 16, + snd_soc_8_16_write, snd_soc_8_16_read, + snd_soc_8_16_read_i2c }, }; /** @@ -82,13 +150,6 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, { int i; - /* We don't support volatile registers yet - refactoring of - * the hw_read operation will be required to do so. */ - if (codec->volatile_register) { - printk(KERN_ERR "Volatile registers not yet supported\n"); - return -EINVAL; - } - for (i = 0; i < ARRAY_SIZE(io_types); i++) if (io_types[i].addr_bits == addr_bits && io_types[i].data_bits == data_bits) @@ -111,6 +172,8 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) codec->hw_write = (hw_write_t)i2c_master_send; #endif + if (io_types[i].i2c_read) + codec->hw_read = io_types[i].i2c_read; break; case SND_SOC_SPI: -- cgit v0.10.2 From 8d50e447d19fec64adebeef55f2b60d695435412 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 10 Jul 2009 23:12:01 +0100 Subject: ASoC: Factor out I/O for Wolfson 8 bit data 16 bit register CODECs Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 3b499ae..25870a4 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -62,7 +62,7 @@ static const u16 wm8523_reg[WM8523_REGISTER_COUNT] = { 0x0000, /* R8 - ZERO_DETECT */ }; -static int wm8523_volatile(unsigned int reg) +static int wm8523_volatile_register(unsigned int reg) { switch (reg) { case WM8523_DEVICE_ID: @@ -73,71 +73,9 @@ static int wm8523_volatile(unsigned int reg) } } -static int wm8523_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - struct wm8523_priv *wm8523 = codec->private_data; - u8 data[3]; - - BUG_ON(reg > WM8523_MAX_REGISTER); - - data[0] = reg; - data[1] = (value >> 8) & 0x00ff; - data[2] = value & 0x00ff; - - if (!wm8523_volatile(reg)) - wm8523->reg_cache[reg] = value; - if (codec->hw_write(codec->control_data, data, 3) == 3) - return 0; - else - return -EIO; -} - static int wm8523_reset(struct snd_soc_codec *codec) { - return wm8523_write(codec, WM8523_DEVICE_ID, 0); -} - -static unsigned int wm8523_read_hw(struct snd_soc_codec *codec, u8 reg) -{ - struct i2c_msg xfer[2]; - u16 data; - int ret; - struct i2c_client *i2c = codec->control_data; - - /* Write register */ - xfer[0].addr = i2c->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® - - /* Read data */ - xfer[1].addr = i2c->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(i2c->adapter, xfer, 2); - if (ret != 2) { - dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret); - return 0; - } - - return (data >> 8) | ((data & 0xff) << 8); -} - - -static unsigned int wm8523_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *reg_cache = codec->reg_cache; - - BUG_ON(reg > WM8523_MAX_REGISTER); - - if (wm8523_volatile(reg)) - return wm8523_read_hw(codec, reg); - else - return reg_cache[reg]; + return snd_soc_write(codec, WM8523_DEVICE_ID, 0); } static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0); @@ -228,8 +166,8 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = socdev->card->codec; struct wm8523_priv *wm8523 = codec->private_data; int i; - u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1); - u16 aifctrl2 = wm8523_read(codec, WM8523_AIF_CTRL2); + u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1); + u16 aifctrl2 = snd_soc_read(codec, WM8523_AIF_CTRL2); /* Find a supported LRCLK ratio */ for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { @@ -263,8 +201,8 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream, break; } - wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1); - wm8523_write(codec, WM8523_AIF_CTRL2, aifctrl2); + snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1); + snd_soc_write(codec, WM8523_AIF_CTRL2, aifctrl2); return 0; } @@ -322,7 +260,7 @@ static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1); + u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1); aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK | WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK); @@ -372,7 +310,7 @@ static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1); + snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1); return 0; } @@ -411,7 +349,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec, /* Sync back default/cached values */ for (i = WM8523_AIF_CTRL1; i < WM8523_MAX_REGISTER; i++) - wm8523_write(codec, i, wm8523->reg_cache[i]); + snd_soc_write(codec, i, wm8523->reg_cache[i]); msleep(100); @@ -543,7 +481,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8523 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523); -static int wm8523_register(struct wm8523_priv *wm8523) +static int wm8523_register(struct wm8523_priv *wm8523, + enum snd_soc_control_type control) { int ret; struct snd_soc_codec *codec = &wm8523->codec; @@ -561,14 +500,13 @@ static int wm8523_register(struct wm8523_priv *wm8523) codec->private_data = wm8523; codec->name = "WM8523"; codec->owner = THIS_MODULE; - codec->read = wm8523_read; - codec->write = wm8523_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8523_set_bias_level; codec->dai = &wm8523_dai; codec->num_dai = 1; codec->reg_cache_size = WM8523_REGISTER_COUNT; codec->reg_cache = &wm8523->reg_cache; + codec->volatile_register = wm8523_volatile_register; wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0]; wm8523->rate_constraint.count = @@ -576,6 +514,12 @@ static int wm8523_register(struct wm8523_priv *wm8523) memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg)); + ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++) wm8523->supplies[i].supply = wm8523_supply_names[i]; @@ -593,7 +537,7 @@ static int wm8523_register(struct wm8523_priv *wm8523) goto err_get; } - ret = wm8523_read(codec, WM8523_DEVICE_ID); + ret = snd_soc_read(codec, WM8523_DEVICE_ID); if (ret < 0) { dev_err(codec->dev, "Failed to read ID register\n"); goto err_enable; @@ -604,7 +548,7 @@ static int wm8523_register(struct wm8523_priv *wm8523) goto err_enable; } - ret = wm8523_read(codec, WM8523_REVISION); + ret = snd_soc_read(codec, WM8523_REVISION); if (ret < 0) { dev_err(codec->dev, "Failed to read revision register\n"); goto err_enable; @@ -684,7 +628,7 @@ static __devinit int wm8523_i2c_probe(struct i2c_client *i2c, codec->dev = &i2c->dev; - return wm8523_register(wm8523); + return wm8523_register(wm8523, SND_SOC_I2C); } static __devexit int wm8523_i2c_remove(struct i2c_client *client) diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index ac30899..5e9c855 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -183,111 +183,20 @@ static const u16 wm8900_reg_defaults[WM8900_MAXREG] = { /* Remaining registers all zero */ }; -/* - * read wm8900 register cache - */ -static inline unsigned int wm8900_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - - BUG_ON(reg >= WM8900_MAXREG); - - if (reg == WM8900_REG_ID) - return 0; - - return cache[reg]; -} - -/* - * write wm8900 register cache - */ -static inline void wm8900_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - - BUG_ON(reg >= WM8900_MAXREG); - - cache[reg] = value; -} - -/* - * write to the WM8900 register space - */ -static int wm8900_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[3]; - - if (value == wm8900_read_reg_cache(codec, reg)) - return 0; - - /* data is - * D15..D9 WM8900 register offset - * D8...D0 register data - */ - data[0] = reg; - data[1] = value >> 8; - data[2] = value & 0x00ff; - - wm8900_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 3) == 3) - return 0; - else - return -EIO; -} - -/* - * Read from the wm8900. - */ -static unsigned int wm8900_chip_read(struct snd_soc_codec *codec, u8 reg) -{ - struct i2c_msg xfer[2]; - u16 data; - int ret; - struct i2c_client *client = codec->control_data; - - BUG_ON(reg != WM8900_REG_ID && reg != WM8900_REG_POWER1); - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - printk(KERN_CRIT "i2c_transfer returned %d\n", ret); - return 0; - } - - return (data >> 8) | ((data & 0xff) << 8); -} - -/* - * Read from the WM8900 register space. Most registers can't be read - * and are therefore supplied from cache. - */ -static unsigned int wm8900_read(struct snd_soc_codec *codec, unsigned int reg) +static int wm8900_volatile_register(unsigned int reg) { switch (reg) { case WM8900_REG_ID: - return wm8900_chip_read(codec, reg); + case WM8900_REG_POWER1: + return 1; default: - return wm8900_read_reg_cache(codec, reg); + return 0; } } static void wm8900_reset(struct snd_soc_codec *codec) { - wm8900_write(codec, WM8900_REG_RESET, 0); + snd_soc_write(codec, WM8900_REG_RESET, 0); memcpy(codec->reg_cache, wm8900_reg_defaults, sizeof(codec->reg_cache)); @@ -297,14 +206,14 @@ static int wm8900_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - u16 hpctl1 = wm8900_read(codec, WM8900_REG_HPCTL1); + u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1); switch (event) { case SND_SOC_DAPM_PRE_PMU: /* Clamp headphone outputs */ hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP | WM8900_REG_HPCTL1_HP_CLAMP_OP; - wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); + snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); break; case SND_SOC_DAPM_POST_PMU: @@ -313,41 +222,41 @@ static int wm8900_hp_event(struct snd_soc_dapm_widget *w, hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT | WM8900_REG_HPCTL1_HP_SHORT2 | WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; - wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); + snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); msleep(400); /* Enable the output stage */ hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP; hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; - wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); + snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); /* Remove the shorts */ hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2; - wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); + snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT; - wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); + snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); break; case SND_SOC_DAPM_PRE_PMD: /* Short the output */ hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT; - wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); + snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); /* Disable the output stage */ hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; - wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); + snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); /* Clamp the outputs and power down input */ hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP | WM8900_REG_HPCTL1_HP_CLAMP_OP; hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; - wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); + snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); break; case SND_SOC_DAPM_POST_PMD: /* Disable everything */ - wm8900_write(codec, WM8900_REG_HPCTL1, 0); + snd_soc_write(codec, WM8900_REG_HPCTL1, 0); break; default: @@ -723,7 +632,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = socdev->card->codec; u16 reg; - reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60; + reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -741,17 +650,17 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - wm8900_write(codec, WM8900_REG_AUDIO1, reg); + snd_soc_write(codec, WM8900_REG_AUDIO1, reg); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - reg = wm8900_read(codec, WM8900_REG_DACCTRL); + reg = snd_soc_read(codec, WM8900_REG_DACCTRL); if (params_rate(params) <= 24000) reg |= WM8900_REG_DACCTRL_DAC_SB_FILT; else reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT; - wm8900_write(codec, WM8900_REG_DACCTRL, reg); + snd_soc_write(codec, WM8900_REG_DACCTRL, reg); } return 0; @@ -845,18 +754,18 @@ static int wm8900_set_fll(struct snd_soc_codec *codec, return 0; /* The digital side should be disabled during any change. */ - reg = wm8900_read(codec, WM8900_REG_POWER1); - wm8900_write(codec, WM8900_REG_POWER1, + reg = snd_soc_read(codec, WM8900_REG_POWER1); + snd_soc_write(codec, WM8900_REG_POWER1, reg & (~WM8900_REG_POWER1_FLL_ENA)); /* Disable the FLL? */ if (!freq_in || !freq_out) { - reg = wm8900_read(codec, WM8900_REG_CLOCKING1); - wm8900_write(codec, WM8900_REG_CLOCKING1, + reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); + snd_soc_write(codec, WM8900_REG_CLOCKING1, reg & (~WM8900_REG_CLOCKING1_MCLK_SRC)); - reg = wm8900_read(codec, WM8900_REG_FLLCTL1); - wm8900_write(codec, WM8900_REG_FLLCTL1, + reg = snd_soc_read(codec, WM8900_REG_FLLCTL1); + snd_soc_write(codec, WM8900_REG_FLLCTL1, reg & (~WM8900_REG_FLLCTL1_OSC_ENA)); wm8900->fll_in = freq_in; @@ -873,33 +782,33 @@ static int wm8900_set_fll(struct snd_soc_codec *codec, /* The osclilator *MUST* be enabled before we enable the * digital circuit. */ - wm8900_write(codec, WM8900_REG_FLLCTL1, + snd_soc_write(codec, WM8900_REG_FLLCTL1, fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA); - wm8900_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5); - wm8900_write(codec, WM8900_REG_FLLCTL5, + snd_soc_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5); + snd_soc_write(codec, WM8900_REG_FLLCTL5, (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f)); if (fll_div.k) { - wm8900_write(codec, WM8900_REG_FLLCTL2, + snd_soc_write(codec, WM8900_REG_FLLCTL2, (fll_div.k >> 8) | 0x100); - wm8900_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff); + snd_soc_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff); } else - wm8900_write(codec, WM8900_REG_FLLCTL2, 0); + snd_soc_write(codec, WM8900_REG_FLLCTL2, 0); if (fll_div.fll_slow_lock_ref) - wm8900_write(codec, WM8900_REG_FLLCTL6, + snd_soc_write(codec, WM8900_REG_FLLCTL6, WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF); else - wm8900_write(codec, WM8900_REG_FLLCTL6, 0); + snd_soc_write(codec, WM8900_REG_FLLCTL6, 0); - reg = wm8900_read(codec, WM8900_REG_POWER1); - wm8900_write(codec, WM8900_REG_POWER1, + reg = snd_soc_read(codec, WM8900_REG_POWER1); + snd_soc_write(codec, WM8900_REG_POWER1, reg | WM8900_REG_POWER1_FLL_ENA); reenable: - reg = wm8900_read(codec, WM8900_REG_CLOCKING1); - wm8900_write(codec, WM8900_REG_CLOCKING1, + reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); + snd_soc_write(codec, WM8900_REG_CLOCKING1, reg | WM8900_REG_CLOCKING1_MCLK_SRC); return 0; @@ -919,38 +828,38 @@ static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8900_BCLK_DIV: - reg = wm8900_read(codec, WM8900_REG_CLOCKING1); - wm8900_write(codec, WM8900_REG_CLOCKING1, + reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); + snd_soc_write(codec, WM8900_REG_CLOCKING1, div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK)); break; case WM8900_OPCLK_DIV: - reg = wm8900_read(codec, WM8900_REG_CLOCKING1); - wm8900_write(codec, WM8900_REG_CLOCKING1, + reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); + snd_soc_write(codec, WM8900_REG_CLOCKING1, div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK)); break; case WM8900_DAC_LRCLK: - reg = wm8900_read(codec, WM8900_REG_AUDIO4); - wm8900_write(codec, WM8900_REG_AUDIO4, + reg = snd_soc_read(codec, WM8900_REG_AUDIO4); + snd_soc_write(codec, WM8900_REG_AUDIO4, div | (reg & WM8900_LRC_MASK)); break; case WM8900_ADC_LRCLK: - reg = wm8900_read(codec, WM8900_REG_AUDIO3); - wm8900_write(codec, WM8900_REG_AUDIO3, + reg = snd_soc_read(codec, WM8900_REG_AUDIO3); + snd_soc_write(codec, WM8900_REG_AUDIO3, div | (reg & WM8900_LRC_MASK)); break; case WM8900_DAC_CLKDIV: - reg = wm8900_read(codec, WM8900_REG_CLOCKING2); - wm8900_write(codec, WM8900_REG_CLOCKING2, + reg = snd_soc_read(codec, WM8900_REG_CLOCKING2); + snd_soc_write(codec, WM8900_REG_CLOCKING2, div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV)); break; case WM8900_ADC_CLKDIV: - reg = wm8900_read(codec, WM8900_REG_CLOCKING2); - wm8900_write(codec, WM8900_REG_CLOCKING2, + reg = snd_soc_read(codec, WM8900_REG_CLOCKING2); + snd_soc_write(codec, WM8900_REG_CLOCKING2, div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV)); break; case WM8900_LRCLK_MODE: - reg = wm8900_read(codec, WM8900_REG_DACCTRL); - wm8900_write(codec, WM8900_REG_DACCTRL, + reg = snd_soc_read(codec, WM8900_REG_DACCTRL); + snd_soc_write(codec, WM8900_REG_DACCTRL, div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE)); break; default: @@ -967,10 +876,10 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; unsigned int clocking1, aif1, aif3, aif4; - clocking1 = wm8900_read(codec, WM8900_REG_CLOCKING1); - aif1 = wm8900_read(codec, WM8900_REG_AUDIO1); - aif3 = wm8900_read(codec, WM8900_REG_AUDIO3); - aif4 = wm8900_read(codec, WM8900_REG_AUDIO4); + clocking1 = snd_soc_read(codec, WM8900_REG_CLOCKING1); + aif1 = snd_soc_read(codec, WM8900_REG_AUDIO1); + aif3 = snd_soc_read(codec, WM8900_REG_AUDIO3); + aif4 = snd_soc_read(codec, WM8900_REG_AUDIO4); /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -1066,10 +975,10 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8900_write(codec, WM8900_REG_CLOCKING1, clocking1); - wm8900_write(codec, WM8900_REG_AUDIO1, aif1); - wm8900_write(codec, WM8900_REG_AUDIO3, aif3); - wm8900_write(codec, WM8900_REG_AUDIO4, aif4); + snd_soc_write(codec, WM8900_REG_CLOCKING1, clocking1); + snd_soc_write(codec, WM8900_REG_AUDIO1, aif1); + snd_soc_write(codec, WM8900_REG_AUDIO3, aif3); + snd_soc_write(codec, WM8900_REG_AUDIO4, aif4); return 0; } @@ -1079,14 +988,14 @@ static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute) struct snd_soc_codec *codec = codec_dai->codec; u16 reg; - reg = wm8900_read(codec, WM8900_REG_DACCTRL); + reg = snd_soc_read(codec, WM8900_REG_DACCTRL); if (mute) reg |= WM8900_REG_DACCTRL_MUTE; else reg &= ~WM8900_REG_DACCTRL_MUTE; - wm8900_write(codec, WM8900_REG_DACCTRL, reg); + snd_soc_write(codec, WM8900_REG_DACCTRL, reg); return 0; } @@ -1135,11 +1044,11 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: /* Enable thermal shutdown */ - reg = wm8900_read(codec, WM8900_REG_GPIO); - wm8900_write(codec, WM8900_REG_GPIO, + reg = snd_soc_read(codec, WM8900_REG_GPIO); + snd_soc_write(codec, WM8900_REG_GPIO, reg | WM8900_REG_GPIO_TEMP_ENA); - reg = wm8900_read(codec, WM8900_REG_ADDCTL); - wm8900_write(codec, WM8900_REG_ADDCTL, + reg = snd_soc_read(codec, WM8900_REG_ADDCTL); + snd_soc_write(codec, WM8900_REG_ADDCTL, reg | WM8900_REG_ADDCTL_TEMP_SD); break; @@ -1150,69 +1059,69 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec, /* Charge capacitors if initial power up */ if (codec->bias_level == SND_SOC_BIAS_OFF) { /* STARTUP_BIAS_ENA on */ - wm8900_write(codec, WM8900_REG_POWER1, + snd_soc_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_STARTUP_BIAS_ENA); /* Startup bias mode */ - wm8900_write(codec, WM8900_REG_ADDCTL, + snd_soc_write(codec, WM8900_REG_ADDCTL, WM8900_REG_ADDCTL_BIAS_SRC | WM8900_REG_ADDCTL_VMID_SOFTST); /* VMID 2x50k */ - wm8900_write(codec, WM8900_REG_POWER1, + snd_soc_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1); /* Allow capacitors to charge */ schedule_timeout_interruptible(msecs_to_jiffies(400)); /* Enable bias */ - wm8900_write(codec, WM8900_REG_POWER1, + snd_soc_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_STARTUP_BIAS_ENA | WM8900_REG_POWER1_BIAS_ENA | 0x1); - wm8900_write(codec, WM8900_REG_ADDCTL, 0); + snd_soc_write(codec, WM8900_REG_ADDCTL, 0); - wm8900_write(codec, WM8900_REG_POWER1, + snd_soc_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_BIAS_ENA | 0x1); } - reg = wm8900_read(codec, WM8900_REG_POWER1); - wm8900_write(codec, WM8900_REG_POWER1, + reg = snd_soc_read(codec, WM8900_REG_POWER1); + snd_soc_write(codec, WM8900_REG_POWER1, (reg & WM8900_REG_POWER1_FLL_ENA) | WM8900_REG_POWER1_BIAS_ENA | 0x1); - wm8900_write(codec, WM8900_REG_POWER2, + snd_soc_write(codec, WM8900_REG_POWER2, WM8900_REG_POWER2_SYSCLK_ENA); - wm8900_write(codec, WM8900_REG_POWER3, 0); + snd_soc_write(codec, WM8900_REG_POWER3, 0); break; case SND_SOC_BIAS_OFF: /* Startup bias enable */ - reg = wm8900_read(codec, WM8900_REG_POWER1); - wm8900_write(codec, WM8900_REG_POWER1, + reg = snd_soc_read(codec, WM8900_REG_POWER1); + snd_soc_write(codec, WM8900_REG_POWER1, reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA); - wm8900_write(codec, WM8900_REG_ADDCTL, + snd_soc_write(codec, WM8900_REG_ADDCTL, WM8900_REG_ADDCTL_BIAS_SRC | WM8900_REG_ADDCTL_VMID_SOFTST); /* Discharge caps */ - wm8900_write(codec, WM8900_REG_POWER1, + snd_soc_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_STARTUP_BIAS_ENA); schedule_timeout_interruptible(msecs_to_jiffies(500)); /* Remove clamp */ - wm8900_write(codec, WM8900_REG_HPCTL1, 0); + snd_soc_write(codec, WM8900_REG_HPCTL1, 0); /* Power down */ - wm8900_write(codec, WM8900_REG_ADDCTL, 0); - wm8900_write(codec, WM8900_REG_POWER1, 0); - wm8900_write(codec, WM8900_REG_POWER2, 0); - wm8900_write(codec, WM8900_REG_POWER3, 0); + snd_soc_write(codec, WM8900_REG_ADDCTL, 0); + snd_soc_write(codec, WM8900_REG_POWER1, 0); + snd_soc_write(codec, WM8900_REG_POWER2, 0); + snd_soc_write(codec, WM8900_REG_POWER3, 0); /* Need to let things settle before stopping the clock * to ensure that restart works, see "Stopping the * master clock" in the datasheet. */ schedule_timeout_interruptible(msecs_to_jiffies(1)); - wm8900_write(codec, WM8900_REG_POWER2, + snd_soc_write(codec, WM8900_REG_POWER2, WM8900_REG_POWER2_SYSCLK_ENA); break; } @@ -1275,7 +1184,7 @@ static int wm8900_resume(struct platform_device *pdev) if (cache) { for (i = 0; i < WM8900_MAXREG; i++) - wm8900_write(codec, i, cache[i]); + snd_soc_write(codec, i, cache[i]); kfree(cache); } else dev_err(&pdev->dev, "Unable to allocate register cache\n"); @@ -1308,16 +1217,20 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c, codec->name = "WM8900"; codec->owner = THIS_MODULE; - codec->read = wm8900_read; - codec->write = wm8900_write; codec->dai = &wm8900_dai; codec->num_dai = 1; - codec->hw_write = (hw_write_t)i2c_master_send; codec->control_data = i2c; codec->set_bias_level = wm8900_set_bias_level; + codec->volatile_register = wm8900_volatile_register; codec->dev = &i2c->dev; - reg = wm8900_read(codec, WM8900_REG_ID); + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + + reg = snd_soc_read(codec, WM8900_REG_ID); if (reg != 0x8900) { dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg); ret = -ENODEV; @@ -1325,7 +1238,7 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c, } /* Read back from the chip */ - reg = wm8900_chip_read(codec, WM8900_REG_POWER1); + reg = snd_soc_read(codec, WM8900_REG_POWER1); reg = (reg >> 12) & 0xf; dev_info(&i2c->dev, "WM8900 revision %d\n", reg); @@ -1335,29 +1248,29 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c, wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Latch the volume update bits */ - wm8900_write(codec, WM8900_REG_LINVOL, - wm8900_read(codec, WM8900_REG_LINVOL) | 0x100); - wm8900_write(codec, WM8900_REG_RINVOL, - wm8900_read(codec, WM8900_REG_RINVOL) | 0x100); - wm8900_write(codec, WM8900_REG_LOUT1CTL, - wm8900_read(codec, WM8900_REG_LOUT1CTL) | 0x100); - wm8900_write(codec, WM8900_REG_ROUT1CTL, - wm8900_read(codec, WM8900_REG_ROUT1CTL) | 0x100); - wm8900_write(codec, WM8900_REG_LOUT2CTL, - wm8900_read(codec, WM8900_REG_LOUT2CTL) | 0x100); - wm8900_write(codec, WM8900_REG_ROUT2CTL, - wm8900_read(codec, WM8900_REG_ROUT2CTL) | 0x100); - wm8900_write(codec, WM8900_REG_LDAC_DV, - wm8900_read(codec, WM8900_REG_LDAC_DV) | 0x100); - wm8900_write(codec, WM8900_REG_RDAC_DV, - wm8900_read(codec, WM8900_REG_RDAC_DV) | 0x100); - wm8900_write(codec, WM8900_REG_LADC_DV, - wm8900_read(codec, WM8900_REG_LADC_DV) | 0x100); - wm8900_write(codec, WM8900_REG_RADC_DV, - wm8900_read(codec, WM8900_REG_RADC_DV) | 0x100); + snd_soc_write(codec, WM8900_REG_LINVOL, + snd_soc_read(codec, WM8900_REG_LINVOL) | 0x100); + snd_soc_write(codec, WM8900_REG_RINVOL, + snd_soc_read(codec, WM8900_REG_RINVOL) | 0x100); + snd_soc_write(codec, WM8900_REG_LOUT1CTL, + snd_soc_read(codec, WM8900_REG_LOUT1CTL) | 0x100); + snd_soc_write(codec, WM8900_REG_ROUT1CTL, + snd_soc_read(codec, WM8900_REG_ROUT1CTL) | 0x100); + snd_soc_write(codec, WM8900_REG_LOUT2CTL, + snd_soc_read(codec, WM8900_REG_LOUT2CTL) | 0x100); + snd_soc_write(codec, WM8900_REG_ROUT2CTL, + snd_soc_read(codec, WM8900_REG_ROUT2CTL) | 0x100); + snd_soc_write(codec, WM8900_REG_LDAC_DV, + snd_soc_read(codec, WM8900_REG_LDAC_DV) | 0x100); + snd_soc_write(codec, WM8900_REG_RDAC_DV, + snd_soc_read(codec, WM8900_REG_RDAC_DV) | 0x100); + snd_soc_write(codec, WM8900_REG_LADC_DV, + snd_soc_read(codec, WM8900_REG_LADC_DV) | 0x100); + snd_soc_write(codec, WM8900_REG_RADC_DV, + snd_soc_read(codec, WM8900_REG_RADC_DV) | 0x100); /* Set the DAC and mixer output bias */ - wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81); + snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81); wm8900_dai.dev = &i2c->dev; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index c9baeae..fe1307b 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -225,94 +225,18 @@ struct wm8903_priv { struct snd_pcm_substream *slave_substream; }; - -static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - - BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults)); - - return cache[reg]; -} - -static unsigned int wm8903_hw_read(struct snd_soc_codec *codec, u8 reg) -{ - struct i2c_msg xfer[2]; - u16 data; - int ret; - struct i2c_client *client = codec->control_data; - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - pr_err("i2c_transfer returned %d\n", ret); - return 0; - } - - return (data >> 8) | ((data & 0xff) << 8); -} - -static unsigned int wm8903_read(struct snd_soc_codec *codec, - unsigned int reg) +static int wm8903_volatile_register(unsigned int reg) { switch (reg) { case WM8903_SW_RESET_AND_ID: case WM8903_REVISION_NUMBER: case WM8903_INTERRUPT_STATUS_1: case WM8903_WRITE_SEQUENCER_4: - return wm8903_hw_read(codec, reg); + return 1; default: - return wm8903_read_reg_cache(codec, reg); - } -} - -static void wm8903_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - - BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults)); - - switch (reg) { - case WM8903_SW_RESET_AND_ID: - case WM8903_REVISION_NUMBER: - break; - - default: - cache[reg] = value; - break; - } -} - -static int wm8903_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[3]; - - wm8903_write_reg_cache(codec, reg, value); - - /* Data format is 1 byte of address followed by 2 bytes of data */ - data[0] = reg; - data[1] = (value >> 8) & 0xff; - data[2] = value & 0xff; - - if (codec->hw_write(codec->control_data, data, 3) == 2) return 0; - else - return -EIO; + } } static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start) @@ -323,13 +247,13 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start) BUG_ON(start > 48); /* Enable the sequencer */ - reg[0] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_0); + reg[0] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_0); reg[0] |= WM8903_WSEQ_ENA; - wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]); + snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]); dev_dbg(&i2c->dev, "Starting sequence at %d\n", start); - wm8903_write(codec, WM8903_WRITE_SEQUENCER_3, + snd_soc_write(codec, WM8903_WRITE_SEQUENCER_3, start | WM8903_WSEQ_START); /* Wait for it to complete. If we have the interrupt wired up then @@ -339,13 +263,13 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start) do { msleep(10); - reg[4] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_4); + reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4); } while (reg[4] & WM8903_WSEQ_BUSY); dev_dbg(&i2c->dev, "Sequence complete\n"); /* Disable the sequencer again */ - wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, + snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0] & ~WM8903_WSEQ_ENA); return 0; @@ -357,12 +281,12 @@ static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache) /* There really ought to be something better we can do here :/ */ for (i = 0; i < ARRAY_SIZE(wm8903_reg_defaults); i++) - cache[i] = wm8903_hw_read(codec, i); + cache[i] = codec->hw_read(codec, i); } static void wm8903_reset(struct snd_soc_codec *codec) { - wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0); + snd_soc_write(codec, WM8903_SW_RESET_AND_ID, 0); memcpy(codec->reg_cache, wm8903_reg_defaults, sizeof(wm8903_reg_defaults)); } @@ -423,52 +347,52 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, } if (event & SND_SOC_DAPM_PRE_PMU) { - val = wm8903_read(codec, reg); + val = snd_soc_read(codec, reg); /* Short the output */ val &= ~(WM8903_OUTPUT_SHORT << shift); - wm8903_write(codec, reg, val); + snd_soc_write(codec, reg, val); } if (event & SND_SOC_DAPM_POST_PMU) { - val = wm8903_read(codec, reg); + val = snd_soc_read(codec, reg); val |= (WM8903_OUTPUT_IN << shift); - wm8903_write(codec, reg, val); + snd_soc_write(codec, reg, val); val |= (WM8903_OUTPUT_INT << shift); - wm8903_write(codec, reg, val); + snd_soc_write(codec, reg, val); /* Turn on the output ENA_OUTP */ val |= (WM8903_OUTPUT_OUT << shift); - wm8903_write(codec, reg, val); + snd_soc_write(codec, reg, val); /* Enable the DC servo */ - dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0); + dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0); dcs_reg |= dcs_bit; - wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg); + snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg); /* Remove the short */ val |= (WM8903_OUTPUT_SHORT << shift); - wm8903_write(codec, reg, val); + snd_soc_write(codec, reg, val); } if (event & SND_SOC_DAPM_PRE_PMD) { - val = wm8903_read(codec, reg); + val = snd_soc_read(codec, reg); /* Short the output */ val &= ~(WM8903_OUTPUT_SHORT << shift); - wm8903_write(codec, reg, val); + snd_soc_write(codec, reg, val); /* Disable the DC servo */ - dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0); + dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0); dcs_reg &= ~dcs_bit; - wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg); + snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg); /* Then disable the intermediate and output stages */ val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT | WM8903_OUTPUT_IN) << shift); - wm8903_write(codec, reg, val); + snd_soc_write(codec, reg, val); } return 0; @@ -492,13 +416,13 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, u16 reg; int ret; - reg = wm8903_read(codec, WM8903_CLASS_W_0); + reg = snd_soc_read(codec, WM8903_CLASS_W_0); /* Turn it off if we're about to enable bypass */ if (ucontrol->value.integer.value[0]) { if (wm8903->class_w_users == 0) { dev_dbg(&i2c->dev, "Disabling Class W\n"); - wm8903_write(codec, WM8903_CLASS_W_0, reg & + snd_soc_write(codec, WM8903_CLASS_W_0, reg & ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V)); } wm8903->class_w_users++; @@ -511,7 +435,7 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, if (!ucontrol->value.integer.value[0]) { if (wm8903->class_w_users == 1) { dev_dbg(&i2c->dev, "Enabling Class W\n"); - wm8903_write(codec, WM8903_CLASS_W_0, reg | + snd_soc_write(codec, WM8903_CLASS_W_0, reg | WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V); } wm8903->class_w_users--; @@ -1009,55 +933,55 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: case SND_SOC_BIAS_PREPARE: - reg = wm8903_read(codec, WM8903_VMID_CONTROL_0); + reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0); reg &= ~(WM8903_VMID_RES_MASK); reg |= WM8903_VMID_RES_50K; - wm8903_write(codec, WM8903_VMID_CONTROL_0, reg); + snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg); break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { - wm8903_write(codec, WM8903_CLOCK_RATES_2, + snd_soc_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); /* Change DC servo dither level in startup sequence */ - wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11); - wm8903_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257); - wm8903_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2); + snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11); + snd_soc_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257); + snd_soc_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2); wm8903_run_sequence(codec, 0); wm8903_sync_reg_cache(codec, codec->reg_cache); /* Enable low impedence charge pump output */ - reg = wm8903_read(codec, + reg = snd_soc_read(codec, WM8903_CONTROL_INTERFACE_TEST_1); - wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, + snd_soc_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, reg | WM8903_TEST_KEY); - reg2 = wm8903_read(codec, WM8903_CHARGE_PUMP_TEST_1); - wm8903_write(codec, WM8903_CHARGE_PUMP_TEST_1, + reg2 = snd_soc_read(codec, WM8903_CHARGE_PUMP_TEST_1); + snd_soc_write(codec, WM8903_CHARGE_PUMP_TEST_1, reg2 | WM8903_CP_SW_KELVIN_MODE_MASK); - wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, + snd_soc_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, reg); /* By default no bypass paths are enabled so * enable Class W support. */ dev_dbg(&i2c->dev, "Enabling Class W\n"); - wm8903_write(codec, WM8903_CLASS_W_0, reg | + snd_soc_write(codec, WM8903_CLASS_W_0, reg | WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V); } - reg = wm8903_read(codec, WM8903_VMID_CONTROL_0); + reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0); reg &= ~(WM8903_VMID_RES_MASK); reg |= WM8903_VMID_RES_250K; - wm8903_write(codec, WM8903_VMID_CONTROL_0, reg); + snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg); break; case SND_SOC_BIAS_OFF: wm8903_run_sequence(codec, 32); - reg = wm8903_read(codec, WM8903_CLOCK_RATES_2); + reg = snd_soc_read(codec, WM8903_CLOCK_RATES_2); reg &= ~WM8903_CLK_SYS_ENA; - wm8903_write(codec, WM8903_CLOCK_RATES_2, reg); + snd_soc_write(codec, WM8903_CLOCK_RATES_2, reg); break; } @@ -1081,7 +1005,7 @@ static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1); + u16 aif1 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_1); aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK | WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV); @@ -1159,7 +1083,7 @@ static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); + snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); return 0; } @@ -1169,14 +1093,14 @@ static int wm8903_digital_mute(struct snd_soc_dai *codec_dai, int mute) struct snd_soc_codec *codec = codec_dai->codec; u16 reg; - reg = wm8903_read(codec, WM8903_DAC_DIGITAL_1); + reg = snd_soc_read(codec, WM8903_DAC_DIGITAL_1); if (mute) reg |= WM8903_DAC_MUTE; else reg &= ~WM8903_DAC_MUTE; - wm8903_write(codec, WM8903_DAC_DIGITAL_1, reg); + snd_soc_write(codec, WM8903_DAC_DIGITAL_1, reg); return 0; } @@ -1366,12 +1290,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream, int cur_val; int clk_sys; - u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1); - u16 aif2 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_2); - u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3); - u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0); - u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1); - u16 dac_digital1 = wm8903_read(codec, WM8903_DAC_DIGITAL_1); + u16 aif1 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_1); + u16 aif2 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_2); + u16 aif3 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_3); + u16 clock0 = snd_soc_read(codec, WM8903_CLOCK_RATES_0); + u16 clock1 = snd_soc_read(codec, WM8903_CLOCK_RATES_1); + u16 dac_digital1 = snd_soc_read(codec, WM8903_DAC_DIGITAL_1); if (substream == wm8903->slave_substream) { dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); @@ -1503,12 +1427,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream, aif2 |= bclk_divs[bclk_div].div; aif3 |= bclk / fs; - wm8903_write(codec, WM8903_CLOCK_RATES_0, clock0); - wm8903_write(codec, WM8903_CLOCK_RATES_1, clock1); - wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); - wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2); - wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3); - wm8903_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1); + snd_soc_write(codec, WM8903_CLOCK_RATES_0, clock0); + snd_soc_write(codec, WM8903_CLOCK_RATES_1, clock1); + snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); + snd_soc_write(codec, WM8903_AUDIO_INTERFACE_2, aif2); + snd_soc_write(codec, WM8903_AUDIO_INTERFACE_3, aif3); + snd_soc_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1); return 0; } @@ -1593,7 +1517,7 @@ static int wm8903_resume(struct platform_device *pdev) if (tmp_cache) { for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++) if (tmp_cache[i] != reg_cache[i]) - wm8903_write(codec, i, tmp_cache[i]); + snd_soc_write(codec, i, tmp_cache[i]); } else { dev_err(&i2c->dev, "Failed to allocate temporary cache\n"); } @@ -1624,9 +1548,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, codec->dev = &i2c->dev; codec->name = "WM8903"; codec->owner = THIS_MODULE; - codec->read = wm8903_read; - codec->write = wm8903_write; - codec->hw_write = (hw_write_t)i2c_master_send; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8903_set_bias_level; codec->dai = &wm8903_dai; @@ -1634,18 +1555,25 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache); codec->reg_cache = &wm8903->reg_cache[0]; codec->private_data = wm8903; + codec->volatile_register = wm8903_volatile_register; i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + + val = snd_soc_read(codec, WM8903_SW_RESET_AND_ID); if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { dev_err(&i2c->dev, "Device with ID register %x is not a WM8903\n", val); return -ENODEV; } - val = wm8903_read(codec, WM8903_REVISION_NUMBER); + val = snd_soc_read(codec, WM8903_REVISION_NUMBER); dev_info(&i2c->dev, "WM8903 revision %d\n", val & WM8903_CHIP_REV_MASK); @@ -1655,35 +1583,35 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Latch volume update bits */ - val = wm8903_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT); + val = snd_soc_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT); val |= WM8903_ADCVU; - wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val); - wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val); + snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val); + snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val); - val = wm8903_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT); + val = snd_soc_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT); val |= WM8903_DACVU; - wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val); - wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val); + snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val); + snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val); - val = wm8903_read(codec, WM8903_ANALOGUE_OUT1_LEFT); + val = snd_soc_read(codec, WM8903_ANALOGUE_OUT1_LEFT); val |= WM8903_HPOUTVU; - wm8903_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val); - wm8903_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val); + snd_soc_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val); + snd_soc_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val); - val = wm8903_read(codec, WM8903_ANALOGUE_OUT2_LEFT); + val = snd_soc_read(codec, WM8903_ANALOGUE_OUT2_LEFT); val |= WM8903_LINEOUTVU; - wm8903_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val); - wm8903_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val); + snd_soc_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val); + snd_soc_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val); - val = wm8903_read(codec, WM8903_ANALOGUE_OUT3_LEFT); + val = snd_soc_read(codec, WM8903_ANALOGUE_OUT3_LEFT); val |= WM8903_SPKVU; - wm8903_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val); - wm8903_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val); + snd_soc_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val); + snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val); /* Enable DAC soft mute by default */ - val = wm8903_read(codec, WM8903_DAC_DIGITAL_1); + val = snd_soc_read(codec, WM8903_DAC_DIGITAL_1); val |= WM8903_DAC_MUTEMODE; - wm8903_write(codec, WM8903_DAC_DIGITAL_1, val); + snd_soc_write(codec, WM8903_DAC_DIGITAL_1, val); wm8903_dai.dev = &i2c->dev; wm8903_codec = codec; diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index b69210a..da97aae 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -106,50 +106,6 @@ static u16 wm8940_reg_defaults[] = { 0x0000, /* Mono Mixer Control */ }; -static inline unsigned int wm8940_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - - if (reg >= ARRAY_SIZE(wm8940_reg_defaults)) - return -1; - - return cache[reg]; -} - -static inline int wm8940_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - - if (reg >= ARRAY_SIZE(wm8940_reg_defaults)) - return -1; - - cache[reg] = value; - - return 0; -} - -static int wm8940_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - int ret; - u8 data[3] = { reg, - (value & 0xff00) >> 8, - (value & 0x00ff) - }; - - wm8940_write_reg_cache(codec, reg, value); - - ret = codec->hw_write(codec->control_data, data, 3); - - if (ret < 0) - return ret; - else if (ret != 3) - return -EIO; - return 0; -} - static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" }; static const struct soc_enum wm8940_adc_companding_enum = SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding); @@ -348,14 +304,14 @@ error_ret: return ret; } -#define wm8940_reset(c) wm8940_write(c, WM8940_SOFTRESET, 0); +#define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0); static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFE67; - u16 clk = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0x1fe; + u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFE67; + u16 clk = snd_soc_read(codec, WM8940_CLOCK) & 0x1fe; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: @@ -366,7 +322,7 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - wm8940_write(codec, WM8940_CLOCK, clk); + snd_soc_write(codec, WM8940_CLOCK, clk); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -399,7 +355,7 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, break; } - wm8940_write(codec, WM8940_IFACE, iface); + snd_soc_write(codec, WM8940_IFACE, iface); return 0; } @@ -411,9 +367,9 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFD9F; - u16 addcntrl = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFF1; - u16 companding = wm8940_read_reg_cache(codec, + u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F; + u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1; + u16 companding = snd_soc_read(codec, WM8940_COMPANDINGCTL) & 0xFFDF; int ret; @@ -442,7 +398,7 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_RATE_48000: break; } - ret = wm8940_write(codec, WM8940_ADDCNTRL, addcntrl); + ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl); if (ret) goto error_ret; @@ -462,10 +418,10 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, iface |= (3 << 5); break; } - ret = wm8940_write(codec, WM8940_COMPANDINGCTL, companding); + ret = snd_soc_write(codec, WM8940_COMPANDINGCTL, companding); if (ret) goto error_ret; - ret = wm8940_write(codec, WM8940_IFACE, iface); + ret = snd_soc_write(codec, WM8940_IFACE, iface); error_ret: return ret; @@ -474,19 +430,19 @@ error_ret: static int wm8940_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8940_read_reg_cache(codec, WM8940_DAC) & 0xffbf; + u16 mute_reg = snd_soc_read(codec, WM8940_DAC) & 0xffbf; if (mute) mute_reg |= 0x40; - return wm8940_write(codec, WM8940_DAC, mute_reg); + return snd_soc_write(codec, WM8940_DAC, mute_reg); } static int wm8940_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { u16 val; - u16 pwr_reg = wm8940_read_reg_cache(codec, WM8940_POWER1) & 0x1F0; + u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0; int ret = 0; switch (level) { @@ -494,26 +450,26 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec, /* ensure bufioen and biasen */ pwr_reg |= (1 << 2) | (1 << 3); /* Enable thermal shutdown */ - val = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); - ret = wm8940_write(codec, WM8940_OUTPUTCTL, val | 0x2); + val = snd_soc_read(codec, WM8940_OUTPUTCTL); + ret = snd_soc_write(codec, WM8940_OUTPUTCTL, val | 0x2); if (ret) break; /* set vmid to 75k */ - ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); + ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); break; case SND_SOC_BIAS_PREPARE: /* ensure bufioen and biasen */ pwr_reg |= (1 << 2) | (1 << 3); - ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); + ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); break; case SND_SOC_BIAS_STANDBY: /* ensure bufioen and biasen */ pwr_reg |= (1 << 2) | (1 << 3); /* set vmid to 300k for standby */ - ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x2); + ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x2); break; case SND_SOC_BIAS_OFF: - ret = wm8940_write(codec, WM8940_POWER1, pwr_reg); + ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg); break; } @@ -587,36 +543,36 @@ static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, u16 reg; /* Turn off PLL */ - reg = wm8940_read_reg_cache(codec, WM8940_POWER1); - wm8940_write(codec, WM8940_POWER1, reg & 0x1df); + reg = snd_soc_read(codec, WM8940_POWER1); + snd_soc_write(codec, WM8940_POWER1, reg & 0x1df); if (freq_in == 0 || freq_out == 0) { /* Clock CODEC directly from MCLK */ - reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); - wm8940_write(codec, WM8940_CLOCK, reg & 0x0ff); + reg = snd_soc_read(codec, WM8940_CLOCK); + snd_soc_write(codec, WM8940_CLOCK, reg & 0x0ff); /* Pll power down */ - wm8940_write(codec, WM8940_PLLN, (1 << 7)); + snd_soc_write(codec, WM8940_PLLN, (1 << 7)); return 0; } /* Pll is followed by a frequency divide by 4 */ pll_factors(freq_out*4, freq_in); if (pll_div.k) - wm8940_write(codec, WM8940_PLLN, + snd_soc_write(codec, WM8940_PLLN, (pll_div.pre_scale << 4) | pll_div.n | (1 << 6)); else /* No factional component */ - wm8940_write(codec, WM8940_PLLN, + snd_soc_write(codec, WM8940_PLLN, (pll_div.pre_scale << 4) | pll_div.n); - wm8940_write(codec, WM8940_PLLK1, pll_div.k >> 18); - wm8940_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff); - wm8940_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff); + snd_soc_write(codec, WM8940_PLLK1, pll_div.k >> 18); + snd_soc_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff); + snd_soc_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff); /* Enable the PLL */ - reg = wm8940_read_reg_cache(codec, WM8940_POWER1); - wm8940_write(codec, WM8940_POWER1, reg | 0x020); + reg = snd_soc_read(codec, WM8940_POWER1); + snd_soc_write(codec, WM8940_POWER1, reg | 0x020); /* Run CODEC from PLL instead of MCLK */ - reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); - wm8940_write(codec, WM8940_CLOCK, reg | 0x100); + reg = snd_soc_read(codec, WM8940_CLOCK); + snd_soc_write(codec, WM8940_CLOCK, reg | 0x100); return 0; } @@ -648,16 +604,16 @@ static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8940_BCLKDIV: - reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFFEF3; - ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 2)); + reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFEF3; + ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2)); break; case WM8940_MCLKDIV: - reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFF1F; - ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 5)); + reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFF1F; + ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 5)); break; case WM8940_OPCLKDIV: - reg = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFCF; - ret = wm8940_write(codec, WM8940_ADDCNTRL, reg | (div << 4)); + reg = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFCF; + ret = snd_soc_write(codec, WM8940_ADDCNTRL, reg | (div << 4)); break; } return ret; @@ -808,7 +764,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8940 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940); -static int wm8940_register(struct wm8940_priv *wm8940) +static int wm8940_register(struct wm8940_priv *wm8940, + enum snd_soc_control_type control) { struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data; struct snd_soc_codec *codec = &wm8940->codec; @@ -825,8 +782,6 @@ static int wm8940_register(struct wm8940_priv *wm8940) codec->private_data = wm8940; codec->name = "WM8940"; codec->owner = THIS_MODULE; - codec->read = wm8940_read_reg_cache; - codec->write = wm8940_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8940_set_bias_level; codec->dai = &wm8940_dai; @@ -834,6 +789,12 @@ static int wm8940_register(struct wm8940_priv *wm8940) codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults); codec->reg_cache = &wm8940->reg_cache; + ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); + if (ret == 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + memcpy(codec->reg_cache, wm8940_reg_defaults, sizeof(wm8940_reg_defaults)); @@ -847,15 +808,15 @@ static int wm8940_register(struct wm8940_priv *wm8940) wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ret = wm8940_write(codec, WM8940_POWER1, 0x180); + ret = snd_soc_write(codec, WM8940_POWER1, 0x180); if (ret < 0) return ret; if (!pdata) dev_warn(codec->dev, "No platform data supplied\n"); else { - reg = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); - ret = wm8940_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi); + reg = snd_soc_read(codec, WM8940_OUTPUTCTL); + ret = snd_soc_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi); if (ret < 0) return ret; } @@ -904,7 +865,7 @@ static int wm8940_i2c_probe(struct i2c_client *i2c, codec->control_data = i2c; codec->dev = &i2c->dev; - return wm8940_register(wm8940); + return wm8940_register(wm8940, SND_SOC_I2C); } static int __devexit wm8940_i2c_remove(struct i2c_client *client) diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index bd1af92..5030320 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -292,9 +292,10 @@ struct wm8961_priv { u16 reg_cache[WM8961_MAX_REGISTER]; }; -static int wm8961_reg_is_volatile(int reg) +static int wm8961_volatile_register(unsigned int reg) { switch (reg) { + case WM8961_SOFTWARE_RESET: case WM8961_WRITE_SEQUENCER_7: case WM8961_DC_SERVO_1: return 1; @@ -304,76 +305,9 @@ static int wm8961_reg_is_volatile(int reg) } } -static unsigned int wm8961_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg > WM8961_MAX_REGISTER); - return cache[reg]; -} - -static unsigned int wm8961_read_hw(struct snd_soc_codec *codec, u8 reg) -{ - struct i2c_msg xfer[2]; - u16 data; - int ret; - struct i2c_client *client = codec->control_data; - - BUG_ON(reg > WM8961_MAX_REGISTER); - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); - return 0; - } - - return (data >> 8) | ((data & 0xff) << 8); -} - -static unsigned int wm8961_read(struct snd_soc_codec *codec, unsigned int reg) -{ - if (wm8961_reg_is_volatile(reg)) - return wm8961_read_hw(codec, reg); - else - return wm8961_read_reg_cache(codec, reg); -} - -static int wm8961_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 *cache = codec->reg_cache; - u8 data[3]; - - BUG_ON(reg > WM8961_MAX_REGISTER); - - if (!wm8961_reg_is_volatile(reg)) - cache[reg] = value; - - data[0] = reg; - data[1] = value >> 8; - data[2] = value & 0x00ff; - - if (codec->hw_write(codec->control_data, data, 3) == 3) - return 0; - else - return -EIO; -} - static int wm8961_reset(struct snd_soc_codec *codec) { - return wm8961_write(codec, WM8961_SOFTWARE_RESET, 0); + return snd_soc_write(codec, WM8961_SOFTWARE_RESET, 0); } /* @@ -384,33 +318,33 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - u16 hp_reg = wm8961_read(codec, WM8961_ANALOGUE_HP_0); - u16 cp_reg = wm8961_read(codec, WM8961_CHARGE_PUMP_1); - u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2); - u16 dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1); + u16 hp_reg = snd_soc_read(codec, WM8961_ANALOGUE_HP_0); + u16 cp_reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_1); + u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2); + u16 dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1); int timeout = 500; if (event & SND_SOC_DAPM_POST_PMU) { /* Make sure the output is shorted */ hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT); - wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Enable the charge pump */ cp_reg |= WM8961_CP_ENA; - wm8961_write(codec, WM8961_CHARGE_PUMP_1, cp_reg); + snd_soc_write(codec, WM8961_CHARGE_PUMP_1, cp_reg); mdelay(5); /* Enable the PGA */ pwr_reg |= WM8961_LOUT1_PGA | WM8961_ROUT1_PGA; - wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg); /* Enable the amplifier */ hp_reg |= WM8961_HPR_ENA | WM8961_HPL_ENA; - wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Second stage enable */ hp_reg |= WM8961_HPR_ENA_DLY | WM8961_HPL_ENA_DLY; - wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Enable the DC servo & trigger startup */ dcs_reg |= @@ -418,10 +352,10 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w, WM8961_DCS_ENA_CHAN_HPL | WM8961_DCS_TRIG_STARTUP_HPL; dev_dbg(codec->dev, "Enabling DC servo\n"); - wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg); + snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg); do { msleep(1); - dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1); + dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1); } while (--timeout && dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR | WM8961_DCS_TRIG_STARTUP_HPL)); @@ -433,39 +367,39 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w, /* Enable the output stage */ hp_reg |= WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP; - wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Remove the short on the output stage */ hp_reg |= WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT; - wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); } if (event & SND_SOC_DAPM_PRE_PMD) { /* Short the output */ hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT); - wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Disable the output stage */ hp_reg &= ~(WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP); - wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Disable DC offset cancellation */ dcs_reg &= ~(WM8961_DCS_ENA_CHAN_HPR | WM8961_DCS_ENA_CHAN_HPL); - wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg); + snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg); /* Finish up */ hp_reg &= ~(WM8961_HPR_ENA_DLY | WM8961_HPR_ENA | WM8961_HPL_ENA_DLY | WM8961_HPL_ENA); - wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Disable the PGA */ pwr_reg &= ~(WM8961_LOUT1_PGA | WM8961_ROUT1_PGA); - wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg); /* Disable the charge pump */ dev_dbg(codec->dev, "Disabling charge pump\n"); - wm8961_write(codec, WM8961_CHARGE_PUMP_1, + snd_soc_write(codec, WM8961_CHARGE_PUMP_1, cp_reg & ~WM8961_CP_ENA); } @@ -476,27 +410,27 @@ static int wm8961_spk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2); - u16 spk_reg = wm8961_read(codec, WM8961_CLASS_D_CONTROL_1); + u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2); + u16 spk_reg = snd_soc_read(codec, WM8961_CLASS_D_CONTROL_1); if (event & SND_SOC_DAPM_POST_PMU) { /* Enable the PGA */ pwr_reg |= WM8961_SPKL_PGA | WM8961_SPKR_PGA; - wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg); /* Enable the amplifier */ spk_reg |= WM8961_SPKL_ENA | WM8961_SPKR_ENA; - wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); + snd_soc_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); } if (event & SND_SOC_DAPM_PRE_PMD) { /* Enable the amplifier */ spk_reg &= ~(WM8961_SPKL_ENA | WM8961_SPKR_ENA); - wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); + snd_soc_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); /* Enable the PGA */ pwr_reg &= ~(WM8961_SPKL_PGA | WM8961_SPKR_PGA); - wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg); } return 0; @@ -714,10 +648,10 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream, abs(wm8961_srate[best].rate - fs)) best = i; } - reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_3); + reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_3); reg &= ~WM8961_SAMPLE_RATE_MASK; reg |= wm8961_srate[best].val; - wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg); + snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg); dev_dbg(codec->dev, "Selected SRATE %dHz for %dHz\n", wm8961_srate[best].rate, fs); @@ -747,12 +681,12 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream, wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs, wm8961->sysclk / fs); - reg = wm8961_read(codec, WM8961_CLOCKING_4); + reg = snd_soc_read(codec, WM8961_CLOCKING_4); reg &= ~WM8961_CLK_SYS_RATE_MASK; reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT; - wm8961_write(codec, WM8961_CLOCKING_4, reg); + snd_soc_write(codec, WM8961_CLOCKING_4, reg); - reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0); + reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0); reg &= ~WM8961_WL_MASK; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -769,15 +703,15 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream, default: return -EINVAL; } - wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, reg); + snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, reg); /* Sloping stop-band filter is recommended for <= 24kHz */ - reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2); + reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2); if (fs <= 24000) reg |= WM8961_DACSLOPE; else reg &= WM8961_DACSLOPE; - wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); + snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); return 0; } @@ -788,7 +722,7 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id, { struct snd_soc_codec *codec = dai->codec; struct wm8961_priv *wm8961 = codec->private_data; - u16 reg = wm8961_read(codec, WM8961_CLOCKING1); + u16 reg = snd_soc_read(codec, WM8961_CLOCKING1); if (freq > 33000000) { dev_err(codec->dev, "MCLK must be <33MHz\n"); @@ -804,7 +738,7 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id, reg &= WM8961_MCLKDIV; } - wm8961_write(codec, WM8961_CLOCKING1, reg); + snd_soc_write(codec, WM8961_CLOCKING1, reg); wm8961->sysclk = freq; @@ -814,7 +748,7 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id, static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_codec *codec = dai->codec; - u16 aif = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0); + u16 aif = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0); aif &= ~(WM8961_BCLKINV | WM8961_LRP | WM8961_MS | WM8961_FORMAT_MASK); @@ -874,26 +808,26 @@ static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - return wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, aif); + return snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, aif); } static int wm8961_set_tristate(struct snd_soc_dai *dai, int tristate) { struct snd_soc_codec *codec = dai->codec; - u16 reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_2); + u16 reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_2); if (tristate) reg |= WM8961_TRIS; else reg &= ~WM8961_TRIS; - return wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg); + return snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg); } static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_1); + u16 reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_1); if (mute) reg |= WM8961_DACMU; @@ -902,7 +836,7 @@ static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute) msleep(17); - return wm8961_write(codec, WM8961_ADC_DAC_CONTROL_1, reg); + return snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_1, reg); } static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) @@ -912,17 +846,17 @@ static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) switch (div_id) { case WM8961_BCLK: - reg = wm8961_read(codec, WM8961_CLOCKING2); + reg = snd_soc_read(codec, WM8961_CLOCKING2); reg &= ~WM8961_BCLKDIV_MASK; reg |= div; - wm8961_write(codec, WM8961_CLOCKING2, reg); + snd_soc_write(codec, WM8961_CLOCKING2, reg); break; case WM8961_LRCLK: - reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_2); + reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_2); reg &= ~WM8961_LRCLK_RATE_MASK; reg |= div; - wm8961_write(codec, WM8961_AUDIO_INTERFACE_2, reg); + snd_soc_write(codec, WM8961_AUDIO_INTERFACE_2, reg); break; default: @@ -949,34 +883,34 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: if (codec->bias_level == SND_SOC_BIAS_STANDBY) { /* Enable bias generation */ - reg = wm8961_read(codec, WM8961_ANTI_POP); + reg = snd_soc_read(codec, WM8961_ANTI_POP); reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN; - wm8961_write(codec, WM8961_ANTI_POP, reg); + snd_soc_write(codec, WM8961_ANTI_POP, reg); /* VMID=2*50k, VREF */ - reg = wm8961_read(codec, WM8961_PWR_MGMT_1); + reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); reg &= ~WM8961_VMIDSEL_MASK; reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF; - wm8961_write(codec, WM8961_PWR_MGMT_1, reg); + snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); } break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_PREPARE) { /* VREF off */ - reg = wm8961_read(codec, WM8961_PWR_MGMT_1); + reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); reg &= ~WM8961_VREF; - wm8961_write(codec, WM8961_PWR_MGMT_1, reg); + snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); /* Bias generation off */ - reg = wm8961_read(codec, WM8961_ANTI_POP); + reg = snd_soc_read(codec, WM8961_ANTI_POP); reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN); - wm8961_write(codec, WM8961_ANTI_POP, reg); + snd_soc_write(codec, WM8961_ANTI_POP, reg); /* VMID off */ - reg = wm8961_read(codec, WM8961_PWR_MGMT_1); + reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); reg &= ~WM8961_VMIDSEL_MASK; - wm8961_write(codec, WM8961_PWR_MGMT_1, reg); + snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); } break; @@ -1101,7 +1035,7 @@ static int wm8961_resume(struct platform_device *pdev) if (i == WM8961_SOFTWARE_RESET) continue; - wm8961_write(codec, i, reg_cache[i]); + snd_soc_write(codec, i, reg_cache[i]); } wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1140,26 +1074,32 @@ static int wm8961_register(struct wm8961_priv *wm8961) codec->private_data = wm8961; codec->name = "WM8961"; codec->owner = THIS_MODULE; - codec->read = wm8961_read; - codec->write = wm8961_write; codec->dai = &wm8961_dai; codec->num_dai = 1; codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache); codec->reg_cache = &wm8961->reg_cache; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8961_set_bias_level; + codec->volatile_register = wm8961_volatile_register; memcpy(codec->reg_cache, wm8961_reg_defaults, sizeof(wm8961_reg_defaults)); - reg = wm8961_read_hw(codec, WM8961_SOFTWARE_RESET); + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + + reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET); if (reg != 0x1801) { dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg); ret = -EINVAL; goto err; } - reg = wm8961_read_hw(codec, WM8961_RIGHT_INPUT_VOLUME); + /* This isn't volatile - readback doesn't correspond to write */ + reg = codec->hw_read(codec, WM8961_RIGHT_INPUT_VOLUME); dev_info(codec->dev, "WM8961 family %d revision %c\n", (reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT, ((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT) @@ -1172,37 +1112,37 @@ static int wm8961_register(struct wm8961_priv *wm8961) } /* Enable class W */ - reg = wm8961_read(codec, WM8961_CHARGE_PUMP_B); + reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_B); reg |= WM8961_CP_DYN_PWR_MASK; - wm8961_write(codec, WM8961_CHARGE_PUMP_B, reg); + snd_soc_write(codec, WM8961_CHARGE_PUMP_B, reg); /* Latch volume update bits (right channel only, we always * write both out) and default ZC on. */ - reg = wm8961_read(codec, WM8961_ROUT1_VOLUME); - wm8961_write(codec, WM8961_ROUT1_VOLUME, + reg = snd_soc_read(codec, WM8961_ROUT1_VOLUME); + snd_soc_write(codec, WM8961_ROUT1_VOLUME, reg | WM8961_LO1ZC | WM8961_OUT1VU); - wm8961_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC); - reg = wm8961_read(codec, WM8961_ROUT2_VOLUME); - wm8961_write(codec, WM8961_ROUT2_VOLUME, + snd_soc_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC); + reg = snd_soc_read(codec, WM8961_ROUT2_VOLUME); + snd_soc_write(codec, WM8961_ROUT2_VOLUME, reg | WM8961_SPKRZC | WM8961_SPKVU); - wm8961_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC); + snd_soc_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC); - reg = wm8961_read(codec, WM8961_RIGHT_ADC_VOLUME); - wm8961_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU); - reg = wm8961_read(codec, WM8961_RIGHT_INPUT_VOLUME); - wm8961_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU); + reg = snd_soc_read(codec, WM8961_RIGHT_ADC_VOLUME); + snd_soc_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU); + reg = snd_soc_read(codec, WM8961_RIGHT_INPUT_VOLUME); + snd_soc_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU); /* Use soft mute by default */ - reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2); + reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2); reg |= WM8961_DACSMM; - wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); + snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); /* Use automatic clocking mode by default; for now this is all * we support. */ - reg = wm8961_read(codec, WM8961_CLOCKING_3); + reg = snd_soc_read(codec, WM8961_CLOCKING_3); reg &= ~WM8961_MANUAL_MODE; - wm8961_write(codec, WM8961_CLOCKING_3, reg); + snd_soc_write(codec, WM8961_CLOCKING_3, reg); wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1250,7 +1190,6 @@ static __devinit int wm8961_i2c_probe(struct i2c_client *i2c, return -ENOMEM; codec = &wm8961->codec; - codec->hw_write = (hw_write_t)i2c_master_send; i2c_set_clientdata(i2c, wm8961); codec->control_data = i2c; diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index d029818..2d702db 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -108,53 +108,7 @@ static const u16 wm8990_reg[] = { 0x0000, /* R63 - Driver internal */ }; -/* - * read wm8990 register cache - */ -static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg >= ARRAY_SIZE(wm8990_reg)); - return cache[reg]; -} - -/* - * write wm8990 register cache - */ -static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - - /* Reset register and reserved registers are uncached */ - if (reg == 0 || reg >= ARRAY_SIZE(wm8990_reg)) - return; - - cache[reg] = value; -} - -/* - * write to the wm8990 register space - */ -static int wm8990_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[3]; - - data[0] = reg & 0xFF; - data[1] = (value >> 8) & 0xFF; - data[2] = value & 0xFF; - - wm8990_write_reg_cache(codec, reg, value); - - if (codec->hw_write(codec->control_data, data, 3) == 2) - return 0; - else - return -EIO; -} - -#define wm8990_reset(c) wm8990_write(c, WM8990_RESET, 0) +#define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0) static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); @@ -187,8 +141,8 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, return ret; /* now hit the volume update bits (always bit 8) */ - val = wm8990_read_reg_cache(codec, reg); - return wm8990_write(codec, reg, val | 0x0100); + val = snd_soc_read(codec, reg); + return snd_soc_write(codec, reg, val | 0x0100); } #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ @@ -427,8 +381,8 @@ static int inmixer_event(struct snd_soc_dapm_widget *w, { u16 reg, fakepower; - reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2); - fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS); + reg = snd_soc_read(w->codec, WM8990_POWER_MANAGEMENT_2); + fakepower = snd_soc_read(w->codec, WM8990_INTDRIVBITS); if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) | (1 << WM8990_AINLMUX_PWR_BIT))) { @@ -443,7 +397,7 @@ static int inmixer_event(struct snd_soc_dapm_widget *w, } else { reg &= ~WM8990_AINL_ENA; } - wm8990_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); + snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); return 0; } @@ -457,7 +411,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, switch (reg_shift) { case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) : - reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER1); + reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER1); if (reg & WM8990_LDLO) { printk(KERN_WARNING "Cannot set as Output Mixer 1 LDLO Set\n"); @@ -465,7 +419,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8): - reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER2); + reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER2); if (reg & WM8990_RDRO) { printk(KERN_WARNING "Cannot set as Output Mixer 2 RDRO Set\n"); @@ -473,7 +427,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8): - reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); + reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER); if (reg & WM8990_LDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer LDSPK Set\n"); @@ -481,7 +435,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8): - reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); + reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER); if (reg & WM8990_RDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer RDSPK Set\n"); @@ -1029,24 +983,24 @@ static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, pll_factors(&pll_div, freq_out * 4, freq_in); /* Turn on PLL */ - reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); + reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2); reg |= WM8990_PLL_ENA; - wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg); /* sysclk comes from PLL */ - reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2); - wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); + reg = snd_soc_read(codec, WM8990_CLOCKING_2); + snd_soc_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); /* set up N , fractional mode and pre-divisor if neccessary */ - wm8990_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | + snd_soc_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | (pll_div.div2?WM8990_PRESCALE:0)); - wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); - wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); + snd_soc_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); + snd_soc_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); } else { /* Turn on PLL */ - reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); + reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2); reg &= ~WM8990_PLL_ENA; - wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg); } return 0; } @@ -1073,8 +1027,8 @@ static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; u16 audio1, audio3; - audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); - audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3); + audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1); + audio3 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_3); /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -1115,8 +1069,8 @@ static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); - wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); + snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); + snd_soc_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); return 0; } @@ -1128,24 +1082,24 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8990_MCLK_DIV: - reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & + reg = snd_soc_read(codec, WM8990_CLOCKING_2) & ~WM8990_MCLK_DIV_MASK; - wm8990_write(codec, WM8990_CLOCKING_2, reg | div); + snd_soc_write(codec, WM8990_CLOCKING_2, reg | div); break; case WM8990_DACCLK_DIV: - reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & + reg = snd_soc_read(codec, WM8990_CLOCKING_2) & ~WM8990_DAC_CLKDIV_MASK; - wm8990_write(codec, WM8990_CLOCKING_2, reg | div); + snd_soc_write(codec, WM8990_CLOCKING_2, reg | div); break; case WM8990_ADCCLK_DIV: - reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & + reg = snd_soc_read(codec, WM8990_CLOCKING_2) & ~WM8990_ADC_CLKDIV_MASK; - wm8990_write(codec, WM8990_CLOCKING_2, reg | div); + snd_soc_write(codec, WM8990_CLOCKING_2, reg | div); break; case WM8990_BCLK_DIV: - reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_1) & + reg = snd_soc_read(codec, WM8990_CLOCKING_1) & ~WM8990_BCLK_DIV_MASK; - wm8990_write(codec, WM8990_CLOCKING_1, reg | div); + snd_soc_write(codec, WM8990_CLOCKING_1, reg | div); break; default: return -EINVAL; @@ -1164,7 +1118,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); + u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1); audio1 &= ~WM8990_AIF_WL_MASK; /* bit size */ @@ -1182,7 +1136,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream, break; } - wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); + snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); return 0; } @@ -1191,12 +1145,12 @@ static int wm8990_mute(struct snd_soc_dai *dai, int mute) struct snd_soc_codec *codec = dai->codec; u16 val; - val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; + val = snd_soc_read(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; if (mute) - wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); + snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); else - wm8990_write(codec, WM8990_DAC_CTRL, val); + snd_soc_write(codec, WM8990_DAC_CTRL, val); return 0; } @@ -1212,21 +1166,21 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: /* VMID=2*50k */ - val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & + val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) & ~WM8990_VMID_MODE_MASK; - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2); break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Enable all output discharge bits */ - wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | + snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | WM8990_DIS_ROUT); /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_VMIDTOG); @@ -1234,83 +1188,83 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, msleep(msecs_to_jiffies(300)); /* Disable VMIDTOG */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL); /* disable all output discharge bits */ - wm8990_write(codec, WM8990_ANTIPOP1, 0); + snd_soc_write(codec, WM8990_ANTIPOP1, 0); /* Enable outputs */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); msleep(msecs_to_jiffies(50)); /* Enable VMID at 2x50k */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); msleep(msecs_to_jiffies(100)); /* Enable VREF */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); msleep(msecs_to_jiffies(600)); /* Enable BUFIOEN */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_BUFIOEN); /* Disable outputs */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); + snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); /* Enable workaround for ADC clocking issue. */ - wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2); - wm8990_write(codec, WM8990_EXT_CTL1, 0xa003); - wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0); + snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0x2); + snd_soc_write(codec, WM8990_EXT_CTL1, 0xa003); + snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0); } /* VMID=2*250k */ - val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & + val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) & ~WM8990_VMID_MODE_MASK; - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4); break; case SND_SOC_BIAS_OFF: /* Enable POBCTRL and SOFT_ST */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_POBCTRL | WM8990_BUFIOEN); /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ - wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_BUFIOEN); /* mute DAC */ - val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL); - wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); + val = snd_soc_read(codec, WM8990_DAC_CTRL); + snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); /* Enable any disabled outputs */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); /* Disable VMID */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); msleep(msecs_to_jiffies(300)); /* Enable all output discharge bits */ - wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | + snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | WM8990_DIS_ROUT); /* Disable VREF */ - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ - wm8990_write(codec, WM8990_ANTIPOP2, 0x0); + snd_soc_write(codec, WM8990_ANTIPOP2, 0x0); break; } @@ -1411,8 +1365,6 @@ static int wm8990_init(struct snd_soc_device *socdev) codec->name = "WM8990"; codec->owner = THIS_MODULE; - codec->read = wm8990_read_reg_cache; - codec->write = wm8990_write; codec->set_bias_level = wm8990_set_bias_level; codec->dai = &wm8990_dai; codec->num_dai = 2; @@ -1422,6 +1374,12 @@ static int wm8990_init(struct snd_soc_device *socdev) if (codec->reg_cache == NULL) return -ENOMEM; + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); + if (ret < 0) { + printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret); + goto pcm_err; + } + wm8990_reset(codec); /* register pcms */ @@ -1435,18 +1393,18 @@ static int wm8990_init(struct snd_soc_device *socdev) codec->bias_level = SND_SOC_BIAS_OFF; wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4); - wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); + reg = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_4); + snd_soc_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); - reg = wm8990_read_reg_cache(codec, WM8990_GPIO1_GPIO2) & + reg = snd_soc_read(codec, WM8990_GPIO1_GPIO2) & ~WM8990_GPIO1_SEL_MASK; - wm8990_write(codec, WM8990_GPIO1_GPIO2, reg | 1); + snd_soc_write(codec, WM8990_GPIO1_GPIO2, reg | 1); - reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); - wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); + reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2); + snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); - wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); - wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); + snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); + snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_add_controls(codec, wm8990_snd_controls, ARRAY_SIZE(wm8990_snd_controls)); diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index dbe2059..dc383c2 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -168,84 +168,19 @@ struct wm9081_priv { struct wm9081_retune_mobile_config *retune; }; -static int wm9081_reg_is_volatile(int reg) +static int wm9081_volatile_register(unsigned int reg) { switch (reg) { + case WM9081_SOFTWARE_RESET: + return 1; default: return 0; } } -static unsigned int wm9081_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg > WM9081_MAX_REGISTER); - return cache[reg]; -} - -static unsigned int wm9081_read_hw(struct snd_soc_codec *codec, u8 reg) -{ - struct i2c_msg xfer[2]; - u16 data; - int ret; - struct i2c_client *client = codec->control_data; - - BUG_ON(reg > WM9081_MAX_REGISTER); - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); - return 0; - } - - return (data >> 8) | ((data & 0xff) << 8); -} - -static unsigned int wm9081_read(struct snd_soc_codec *codec, unsigned int reg) -{ - if (wm9081_reg_is_volatile(reg)) - return wm9081_read_hw(codec, reg); - else - return wm9081_read_reg_cache(codec, reg); -} - -static int wm9081_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 *cache = codec->reg_cache; - u8 data[3]; - - BUG_ON(reg > WM9081_MAX_REGISTER); - - if (!wm9081_reg_is_volatile(reg)) - cache[reg] = value; - - data[0] = reg; - data[1] = value >> 8; - data[2] = value & 0x00ff; - - if (codec->hw_write(codec->control_data, data, 3) == 3) - return 0; - else - return -EIO; -} - static int wm9081_reset(struct snd_soc_codec *codec) { - return wm9081_write(codec, WM9081_SOFTWARE_RESET, 0); + return snd_soc_write(codec, WM9081_SOFTWARE_RESET, 0); } static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0); @@ -356,7 +291,7 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg; - reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2); + reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2); if (reg & WM9081_SPK_MODE) ucontrol->value.integer.value[0] = 1; else @@ -375,8 +310,8 @@ static int speaker_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg_pwr = wm9081_read(codec, WM9081_POWER_MANAGEMENT); - unsigned int reg2 = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2); + unsigned int reg_pwr = snd_soc_read(codec, WM9081_POWER_MANAGEMENT); + unsigned int reg2 = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2); /* Are we changing anything? */ if (ucontrol->value.integer.value[0] == @@ -397,7 +332,7 @@ static int speaker_mode_put(struct snd_kcontrol *kcontrol, reg2 &= ~WM9081_SPK_MODE; } - wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2); + snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2); return 0; } @@ -456,7 +391,7 @@ static int speaker_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - unsigned int reg = wm9081_read(codec, WM9081_POWER_MANAGEMENT); + unsigned int reg = snd_soc_read(codec, WM9081_POWER_MANAGEMENT); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -468,7 +403,7 @@ static int speaker_event(struct snd_soc_dapm_widget *w, break; } - wm9081_write(codec, WM9081_POWER_MANAGEMENT, reg); + snd_soc_write(codec, WM9081_POWER_MANAGEMENT, reg); return 0; } @@ -607,7 +542,7 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id, if (ret != 0) return ret; - reg5 = wm9081_read(codec, WM9081_FLL_CONTROL_5); + reg5 = snd_soc_read(codec, WM9081_FLL_CONTROL_5); reg5 &= ~WM9081_FLL_CLK_SRC_MASK; switch (fll_id) { @@ -621,44 +556,44 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id, } /* Disable CLK_SYS while we reconfigure */ - clk_sys_reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3); + clk_sys_reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3); if (clk_sys_reg & WM9081_CLK_SYS_ENA) - wm9081_write(codec, WM9081_CLOCK_CONTROL_3, + snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg & ~WM9081_CLK_SYS_ENA); /* Any FLL configuration change requires that the FLL be * disabled first. */ - reg1 = wm9081_read(codec, WM9081_FLL_CONTROL_1); + reg1 = snd_soc_read(codec, WM9081_FLL_CONTROL_1); reg1 &= ~WM9081_FLL_ENA; - wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1); + snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1); /* Apply the configuration */ if (fll_div.k) reg1 |= WM9081_FLL_FRAC_MASK; else reg1 &= ~WM9081_FLL_FRAC_MASK; - wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1); + snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1); - wm9081_write(codec, WM9081_FLL_CONTROL_2, + snd_soc_write(codec, WM9081_FLL_CONTROL_2, (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) | (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT)); - wm9081_write(codec, WM9081_FLL_CONTROL_3, fll_div.k); + snd_soc_write(codec, WM9081_FLL_CONTROL_3, fll_div.k); - reg4 = wm9081_read(codec, WM9081_FLL_CONTROL_4); + reg4 = snd_soc_read(codec, WM9081_FLL_CONTROL_4); reg4 &= ~WM9081_FLL_N_MASK; reg4 |= fll_div.n << WM9081_FLL_N_SHIFT; - wm9081_write(codec, WM9081_FLL_CONTROL_4, reg4); + snd_soc_write(codec, WM9081_FLL_CONTROL_4, reg4); reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK; reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT; - wm9081_write(codec, WM9081_FLL_CONTROL_5, reg5); + snd_soc_write(codec, WM9081_FLL_CONTROL_5, reg5); /* Enable the FLL */ - wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA); + snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA); /* Then bring CLK_SYS up again if it was disabled */ if (clk_sys_reg & WM9081_CLK_SYS_ENA) - wm9081_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg); + snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg); dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); @@ -734,19 +669,19 @@ static int configure_clock(struct snd_soc_codec *codec) return -EINVAL; } - reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_1); + reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_1); if (mclkdiv) reg |= WM9081_MCLKDIV2; else reg &= ~WM9081_MCLKDIV2; - wm9081_write(codec, WM9081_CLOCK_CONTROL_1, reg); + snd_soc_write(codec, WM9081_CLOCK_CONTROL_1, reg); - reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3); + reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3); if (fll) reg |= WM9081_CLK_SRC_SEL; else reg &= ~WM9081_CLK_SRC_SEL; - wm9081_write(codec, WM9081_CLOCK_CONTROL_3, reg); + snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, reg); dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate); @@ -846,76 +781,76 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: /* VMID=2*40k */ - reg = wm9081_read(codec, WM9081_VMID_CONTROL); + reg = snd_soc_read(codec, WM9081_VMID_CONTROL); reg &= ~WM9081_VMID_SEL_MASK; reg |= 0x2; - wm9081_write(codec, WM9081_VMID_CONTROL, reg); + snd_soc_write(codec, WM9081_VMID_CONTROL, reg); /* Normal bias current */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); reg &= ~WM9081_STBY_BIAS_ENA; - wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); + snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); break; case SND_SOC_BIAS_STANDBY: /* Initial cold start */ if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Disable LINEOUT discharge */ - reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL); + reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL); reg &= ~WM9081_LINEOUT_DISCH; - wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg); + snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg); /* Select startup bias source */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA; - wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); + snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); /* VMID 2*4k; Soft VMID ramp enable */ - reg = wm9081_read(codec, WM9081_VMID_CONTROL); + reg = snd_soc_read(codec, WM9081_VMID_CONTROL); reg |= WM9081_VMID_RAMP | 0x6; - wm9081_write(codec, WM9081_VMID_CONTROL, reg); + snd_soc_write(codec, WM9081_VMID_CONTROL, reg); mdelay(100); /* Normal bias enable & soft start off */ reg |= WM9081_BIAS_ENA; reg &= ~WM9081_VMID_RAMP; - wm9081_write(codec, WM9081_VMID_CONTROL, reg); + snd_soc_write(codec, WM9081_VMID_CONTROL, reg); /* Standard bias source */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); reg &= ~WM9081_BIAS_SRC; - wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); + snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); } /* VMID 2*240k */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); reg &= ~WM9081_VMID_SEL_MASK; reg |= 0x40; - wm9081_write(codec, WM9081_VMID_CONTROL, reg); + snd_soc_write(codec, WM9081_VMID_CONTROL, reg); /* Standby bias current on */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); reg |= WM9081_STBY_BIAS_ENA; - wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); + snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); break; case SND_SOC_BIAS_OFF: /* Startup bias source */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); reg |= WM9081_BIAS_SRC; - wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); + snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); /* Disable VMID and biases with soft ramping */ - reg = wm9081_read(codec, WM9081_VMID_CONTROL); + reg = snd_soc_read(codec, WM9081_VMID_CONTROL); reg &= ~(WM9081_VMID_SEL_MASK | WM9081_BIAS_ENA); reg |= WM9081_VMID_RAMP; - wm9081_write(codec, WM9081_VMID_CONTROL, reg); + snd_soc_write(codec, WM9081_VMID_CONTROL, reg); /* Actively discharge LINEOUT */ - reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL); + reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL); reg |= WM9081_LINEOUT_DISCH; - wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg); + snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg); break; } @@ -929,7 +864,7 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai, { struct snd_soc_codec *codec = dai->codec; struct wm9081_priv *wm9081 = codec->private_data; - unsigned int aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2); + unsigned int aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2); aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV | WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK); @@ -1010,7 +945,7 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai, return -EINVAL; } - wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); + snd_soc_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); return 0; } @@ -1024,18 +959,18 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream, int ret, i, best, best_val, cur_val; unsigned int clk_ctrl2, aif1, aif2, aif3, aif4; - clk_ctrl2 = wm9081_read(codec, WM9081_CLOCK_CONTROL_2); + clk_ctrl2 = snd_soc_read(codec, WM9081_CLOCK_CONTROL_2); clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK); - aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); + aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1); - aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2); + aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2); aif2 &= ~WM9081_AIF_WL_MASK; - aif3 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_3); + aif3 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_3); aif3 &= ~WM9081_BCLK_DIV_MASK; - aif4 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_4); + aif4 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_4); aif4 &= ~WM9081_LRCLK_RATE_MASK; /* What BCLK do we need? */ @@ -1149,22 +1084,22 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream, s->name, s->rate); /* If the EQ is enabled then disable it while we write out */ - eq1 = wm9081_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA; + eq1 = snd_soc_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA; if (eq1 & WM9081_EQ_ENA) - wm9081_write(codec, WM9081_EQ_1, 0); + snd_soc_write(codec, WM9081_EQ_1, 0); /* Write out the other values */ for (i = 1; i < ARRAY_SIZE(s->config); i++) - wm9081_write(codec, WM9081_EQ_1 + i, s->config[i]); + snd_soc_write(codec, WM9081_EQ_1 + i, s->config[i]); eq1 |= (s->config[0] & ~WM9081_EQ_ENA); - wm9081_write(codec, WM9081_EQ_1, eq1); + snd_soc_write(codec, WM9081_EQ_1, eq1); } - wm9081_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2); - wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); - wm9081_write(codec, WM9081_AUDIO_INTERFACE_3, aif3); - wm9081_write(codec, WM9081_AUDIO_INTERFACE_4, aif4); + snd_soc_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2); + snd_soc_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); + snd_soc_write(codec, WM9081_AUDIO_INTERFACE_3, aif3); + snd_soc_write(codec, WM9081_AUDIO_INTERFACE_4, aif4); return 0; } @@ -1174,14 +1109,14 @@ static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute) struct snd_soc_codec *codec = codec_dai->codec; unsigned int reg; - reg = wm9081_read(codec, WM9081_DAC_DIGITAL_2); + reg = snd_soc_read(codec, WM9081_DAC_DIGITAL_2); if (mute) reg |= WM9081_DAC_MUTE; else reg &= ~WM9081_DAC_MUTE; - wm9081_write(codec, WM9081_DAC_DIGITAL_2, reg); + snd_soc_write(codec, WM9081_DAC_DIGITAL_2, reg); return 0; } @@ -1210,7 +1145,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, unsigned int mask, int slots) { struct snd_soc_codec *codec = dai->codec; - unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); + unsigned int aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1); aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK); @@ -1235,7 +1170,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, return -EINVAL; } - wm9081_write(codec, WM9081_AUDIO_INTERFACE_1, aif1); + snd_soc_write(codec, WM9081_AUDIO_INTERFACE_1, aif1); return 0; } @@ -1357,7 +1292,7 @@ static int wm9081_resume(struct platform_device *pdev) if (i == WM9081_SOFTWARE_RESET) continue; - wm9081_write(codec, i, reg_cache[i]); + snd_soc_write(codec, i, reg_cache[i]); } wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1377,7 +1312,8 @@ struct snd_soc_codec_device soc_codec_dev_wm9081 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081); -static int wm9081_register(struct wm9081_priv *wm9081) +static int wm9081_register(struct wm9081_priv *wm9081, + enum snd_soc_control_type control) { struct snd_soc_codec *codec = &wm9081->codec; int ret; @@ -1396,19 +1332,24 @@ static int wm9081_register(struct wm9081_priv *wm9081) codec->private_data = wm9081; codec->name = "WM9081"; codec->owner = THIS_MODULE; - codec->read = wm9081_read; - codec->write = wm9081_write; codec->dai = &wm9081_dai; codec->num_dai = 1; codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache); codec->reg_cache = &wm9081->reg_cache; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm9081_set_bias_level; + codec->volatile_register = wm9081_volatile_register; memcpy(codec->reg_cache, wm9081_reg_defaults, sizeof(wm9081_reg_defaults)); - reg = wm9081_read_hw(codec, WM9081_SOFTWARE_RESET); + ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + + reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET); if (reg != 0x9081) { dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg); ret = -EINVAL; @@ -1424,10 +1365,10 @@ static int wm9081_register(struct wm9081_priv *wm9081) wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Enable zero cross by default */ - reg = wm9081_read(codec, WM9081_ANALOGUE_LINEOUT); - wm9081_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC); - reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_PGA); - wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_PGA, + reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT); + snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC); + reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA); + snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA, reg | WM9081_SPKPGAZC); wm9081_dai.dev = codec->dev; @@ -1482,7 +1423,7 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c, codec->dev = &i2c->dev; - return wm9081_register(wm9081); + return wm9081_register(wm9081, SND_SOC_I2C); } static __devexit int wm9081_i2c_remove(struct i2c_client *client) -- cgit v0.10.2 From 27ded041f03026e8c6be9efc626e11ddfb4620c1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 10 Jul 2009 23:28:16 +0100 Subject: ASoC: Factor out 7 bit register 9 bit data SPI write This converts all the Wolfson drivers using this format (the only devices that do) except WM8753 to use it. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 4ca724f..bcd6a40 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -737,30 +737,6 @@ static struct spi_driver wm8510_spi_driver = { .probe = wm8510_spi_probe, .remove = __devexit_p(wm8510_spi_remove), }; - -static int wm8510_spi_write(struct spi_device *spi, const char *data, int len) -{ - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} #endif /* CONFIG_SPI_MASTER */ static int wm8510_probe(struct platform_device *pdev) @@ -790,7 +766,6 @@ static int wm8510_probe(struct platform_device *pdev) #endif #if defined(CONFIG_SPI_MASTER) if (setup->spi) { - codec->hw_write = (hw_write_t)wm8510_spi_write; ret = spi_register_driver(&wm8510_spi_driver); if (ret != 0) printk(KERN_ERR "can't add spi driver"); diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index a28630d..16e969a 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -425,30 +425,6 @@ static struct spi_driver wm8728_spi_driver = { .probe = wm8728_spi_probe, .remove = __devexit_p(wm8728_spi_remove), }; - -static int wm8728_spi_write(struct spi_device *spi, const char *data, int len) -{ - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} #endif /* CONFIG_SPI_MASTER */ static int wm8728_probe(struct platform_device *pdev) @@ -478,7 +454,6 @@ static int wm8728_probe(struct platform_device *pdev) #endif #if defined(CONFIG_SPI_MASTER) if (setup->spi) { - codec->hw_write = (hw_write_t)wm8728_spi_write; ret = spi_register_driver(&wm8728_spi_driver); if (ret != 0) printk(KERN_ERR "can't add spi driver"); diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 27fc942..6232afd 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -591,30 +591,6 @@ static void wm8731_unregister(struct wm8731_priv *wm8731) } #if defined(CONFIG_SPI_MASTER) -static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) -{ - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} - static int __devinit wm8731_spi_probe(struct spi_device *spi) { struct snd_soc_codec *codec; @@ -626,7 +602,6 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi) codec = &wm8731->codec; codec->control_data = spi; - codec->hw_write = (hw_write_t)wm8731_spi_write; codec->dev = &spi->dev; dev_set_drvdata(&spi->dev, wm8731); diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index e6422b1..4ba1e7e 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -911,30 +911,6 @@ static struct spi_driver wm8750_spi_driver = { .probe = wm8750_spi_probe, .remove = __devexit_p(wm8750_spi_remove), }; - -static int wm8750_spi_write(struct spi_device *spi, const char *data, int len) -{ - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} #endif static int wm8750_probe(struct platform_device *pdev) @@ -973,7 +949,6 @@ static int wm8750_probe(struct platform_device *pdev) #endif #if defined(CONFIG_SPI_MASTER) if (setup->spi) { - codec->hw_write = (hw_write_t)wm8750_spi_write; ret = spi_register_driver(&wm8750_spi_driver); if (ret != 0) printk(KERN_ERR "can't add spi driver"); diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 7486d3e..1c86535 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -979,30 +979,6 @@ static struct i2c_driver wm8988_i2c_driver = { #endif #if defined(CONFIG_SPI_MASTER) -static int wm8988_spi_write(struct spi_device *spi, const char *data, int len) -{ - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} - static int __devinit wm8988_spi_probe(struct spi_device *spi) { struct wm8988_priv *wm8988; @@ -1013,7 +989,6 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi) return -ENOMEM; codec = &wm8988->codec; - codec->hw_write = (hw_write_t)wm8988_spi_write; codec->control_data = spi; codec->dev = &spi->dev; diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index ab058b8..56ec3f2 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -12,6 +12,7 @@ */ #include +#include #include static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, @@ -46,6 +47,36 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, return -EIO; } +#if defined(CONFIG_SPI_MASTER) +static int snd_soc_7_9_spi_write(void *control_data, const char *data, + int len) +{ + struct spi_device *spi = control_data; + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} +#else +#define snd_soc_7_9_spi_write NULL +#endif + static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { @@ -115,12 +146,12 @@ static struct { int addr_bits; int data_bits; int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); + int (*spi_write)(void *, const char *, int); unsigned int (*read)(struct snd_soc_codec *, unsigned int); unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); } io_types[] = { - { 7, 9, snd_soc_7_9_write, snd_soc_7_9_read }, - { 8, 16, - snd_soc_8_16_write, snd_soc_8_16_read, + { 7, 9, snd_soc_7_9_write, snd_soc_7_9_spi_write, snd_soc_7_9_read }, + { 8, 16, snd_soc_8_16_write, NULL, snd_soc_8_16_read, snd_soc_8_16_read_i2c }, }; @@ -177,6 +208,8 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, break; case SND_SOC_SPI: + if (io_types[i].spi_write) + codec->hw_write = io_types[i].spi_write; break; } -- cgit v0.10.2 From ed8d9adf357ec331603fa1049510399812cea7e5 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 3 Aug 2009 14:08:48 +0900 Subject: x86, percpu: Add 'percpu_read_stable()' interface for cacheable accesses This is very useful for some common things like 'get_current()' and 'get_thread_info()', which can be used multiple times in a function, and where the result is cacheable. tj: Added the magical undocumented "P" modifier to UP __percpu_arg() to force gcc to dereference the pointer value passed in via the "p" input constraint. Without this, percpu_read_stable() returns the address of the percpu variable. Also added comment explaining the difference between percpu_read() and percpu_read_stable(). Signed-off-by: Linus Torvalds Signed-off-by: Tejun Heo Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/current.h b/arch/x86/include/asm/current.h index c68c361..4d447b7 100644 --- a/arch/x86/include/asm/current.h +++ b/arch/x86/include/asm/current.h @@ -11,7 +11,7 @@ DECLARE_PER_CPU(struct task_struct *, current_task); static __always_inline struct task_struct *get_current(void) { - return percpu_read(current_task); + return percpu_read_stable(current_task); } #define current get_current() diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index 103f1dd..04eacef 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -49,7 +49,7 @@ #define __percpu_arg(x) "%%"__stringify(__percpu_seg)":%P" #x #define __my_cpu_offset percpu_read(this_cpu_off) #else -#define __percpu_arg(x) "%" #x +#define __percpu_arg(x) "%P" #x #endif /* @@ -104,36 +104,48 @@ do { \ } \ } while (0) -#define percpu_from_op(op, var) \ +#define percpu_from_op(op, var, constraint) \ ({ \ typeof(var) ret__; \ switch (sizeof(var)) { \ case 1: \ asm(op "b "__percpu_arg(1)",%0" \ : "=q" (ret__) \ - : "m" (var)); \ + : constraint); \ break; \ case 2: \ asm(op "w "__percpu_arg(1)",%0" \ : "=r" (ret__) \ - : "m" (var)); \ + : constraint); \ break; \ case 4: \ asm(op "l "__percpu_arg(1)",%0" \ : "=r" (ret__) \ - : "m" (var)); \ + : constraint); \ break; \ case 8: \ asm(op "q "__percpu_arg(1)",%0" \ : "=r" (ret__) \ - : "m" (var)); \ + : constraint); \ break; \ default: __bad_percpu_size(); \ } \ ret__; \ }) -#define percpu_read(var) percpu_from_op("mov", per_cpu__##var) +/* + * percpu_read() makes gcc load the percpu variable every time it is + * accessed while percpu_read_stable() allows the value to be cached. + * percpu_read_stable() is more efficient and can be used if its value + * is guaranteed to be valid across cpus. The current users include + * get_current() and get_thread_info() both of which are actually + * per-thread variables implemented as per-cpu variables and thus + * stable for the duration of the respective task. + */ +#define percpu_read(var) percpu_from_op("mov", per_cpu__##var, \ + "m" (per_cpu__##var)) +#define percpu_read_stable(var) percpu_from_op("mov", per_cpu__##var, \ + "p" (&per_cpu__##var)) #define percpu_write(var, val) percpu_to_op("mov", per_cpu__##var, val) #define percpu_add(var, val) percpu_to_op("add", per_cpu__##var, val) #define percpu_sub(var, val) percpu_to_op("sub", per_cpu__##var, val) diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index fad7d40..a1bb5a11 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -213,7 +213,7 @@ DECLARE_PER_CPU(unsigned long, kernel_stack); static inline struct thread_info *current_thread_info(void) { struct thread_info *ti; - ti = (void *)(percpu_read(kernel_stack) + + ti = (void *)(percpu_read_stable(kernel_stack) + KERNEL_STACK_OFFSET - THREAD_SIZE); return ti; } -- cgit v0.10.2 From 3e352aa8ee2bd48f1a19c7742810b3a4a7ba605e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Aug 2009 14:10:11 +0900 Subject: x86, percpu: Fix DECLARE/DEFINE_PER_CPU_PAGE_ALIGNED() DECLARE/DEFINE_PER_CPU_PAGE_ALIGNED() put percpu variables in .page_aligned section without adding any alignment restrictions. Currently, this doesn't cause any problem because all users of the macros have explicit page alignment and page-sized but it's much safer to enforce page alignment from the macros. After all, it's what they claim to do. Add __aligned(PAGE_SIZE) to DECLARE/DEFINE_PER_CPU_PAGE_ALIGNED() and drop explicit alignment from it users. Signed-off-by: Tejun Heo Cc: Ingo Molnar Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index f1961c0..12493c5 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1008,8 +1008,7 @@ static const unsigned int exception_stack_sizes[N_EXCEPTION_STACKS] = { }; static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks - [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]) - __aligned(PAGE_SIZE); + [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]); /* May not be marked __init: used by software suspend */ void syscall_init(void) diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h index 68438e1..afd5f8b 100644 --- a/include/linux/percpu-defs.h +++ b/include/linux/percpu-defs.h @@ -69,11 +69,13 @@ /* * Declaration/definition used for per-CPU variables that must be page aligned. */ -#define DECLARE_PER_CPU_PAGE_ALIGNED(type, name) \ - DECLARE_PER_CPU_SECTION(type, name, ".page_aligned") +#define DECLARE_PER_CPU_PAGE_ALIGNED(type, name) \ + DECLARE_PER_CPU_SECTION(type, name, ".page_aligned") \ + __aligned(PAGE_SIZE) #define DEFINE_PER_CPU_PAGE_ALIGNED(type, name) \ - DEFINE_PER_CPU_SECTION(type, name, ".page_aligned") + DEFINE_PER_CPU_SECTION(type, name, ".page_aligned") \ + __aligned(PAGE_SIZE) /* * Intermodule exports for per-CPU variables. -- cgit v0.10.2 From bdf977b37418cdf8a2252504779a7e12a09b7575 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Aug 2009 14:12:19 +0900 Subject: x86, percpu: Collect hot percpu variables into one cacheline On x86_64, percpu variables current_task and kernel_stack are used for get_current() and current_thread_info() respectively and thus are often used close to each other. Move definition of current_task to kernel/cpu/common.c right above kernel_stack definition and align it to cacheline so that they always fall into the same cacheline. Two percpu variables defined there together - irq_stack_ptr and irq_count - are also pretty hot and will benefit from sharing the cacheline. For consistency, current_task definition for x86_32 is also moved to kernel/cpu/common.c. Putting current_task and kernel_stack into the same cacheline was suggested by Linus Torvalds. Signed-off-by: Tejun Heo Cc: Linus Torvalds Cc: Ingo Molnar Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 12493c5..1bd88ed 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -987,13 +987,21 @@ struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; DEFINE_PER_CPU_FIRST(union irq_stack_union, irq_stack_union) __aligned(PAGE_SIZE); -DEFINE_PER_CPU(char *, irq_stack_ptr) = - init_per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64; +/* + * The following four percpu variables are hot. Align current_task to + * cacheline size such that all four fall in the same cacheline. + */ +DEFINE_PER_CPU(struct task_struct *, current_task) ____cacheline_aligned = + &init_task; +EXPORT_PER_CPU_SYMBOL(current_task); DEFINE_PER_CPU(unsigned long, kernel_stack) = (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE; EXPORT_PER_CPU_SYMBOL(kernel_stack); +DEFINE_PER_CPU(char *, irq_stack_ptr) = + init_per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64; + DEFINE_PER_CPU(unsigned int, irq_count) = -1; /* @@ -1041,6 +1049,9 @@ DEFINE_PER_CPU(struct orig_ist, orig_ist); #else /* CONFIG_X86_64 */ +DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; +EXPORT_PER_CPU_SYMBOL(current_task); + #ifdef CONFIG_CC_STACKPROTECTOR DEFINE_PER_CPU(unsigned long, stack_canary); #endif diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 59f4524..daa4107 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -61,9 +61,6 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); -DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; -EXPORT_PER_CPU_SYMBOL(current_task); - /* * Return saved PC of a blocked thread. */ diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index ebefb54..c4c675d 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -55,9 +55,6 @@ asmlinkage extern void ret_from_fork(void); -DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; -EXPORT_PER_CPU_SYMBOL(current_task); - DEFINE_PER_CPU(unsigned long, old_rsp); static DEFINE_PER_CPU(unsigned char, is_idle); -- cgit v0.10.2 From 16ffe32c773dab387cfc5e6bdf181367ff944376 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Aug 2009 13:40:54 +0200 Subject: ALSA: hda - Fix line-out jack handling with STAC/IDT codec When the line-out jack is plugged/unplugged, the driver needs to check the headphone plug, not only the line-out jack itself. Otherwise the headphone or the speaker may be wrongly muted/unmuted. As a result, both STAC_HP_EVENT and STAC_LO_EVENT need to call the same function, stac92xx_hp_detect(). Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 9961fe1..edeeb56 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4782,10 +4782,8 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) switch (event->type) { case STAC_HP_EVENT: - stac92xx_hp_detect(codec); - break; case STAC_LO_EVENT: - stac92xx_line_out_detect(codec, 0); + stac92xx_hp_detect(codec); break; case STAC_MIC_EVENT: stac92xx_mic_detect(codec); -- cgit v0.10.2 From c7bd0414d681706a32105895cae20fb9090db52e Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Thu, 23 Jul 2009 20:56:27 +0200 Subject: x86: Simplify the Makefile in a minor way through use of cc-ifversion Signed-off-by: Frans Pop Acked-by: Sam Ravnborg Reviewed-by: WANG Cong LKML-Reference: <200907232056.28635.elendil@planet.nl> Signed-off-by: Ingo Molnar diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 1b68659..1f3851a 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -32,8 +32,8 @@ ifeq ($(CONFIG_X86_32),y) # Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use # a lot more stack due to the lack of sharing of stacklots: - KBUILD_CFLAGS += $(shell if [ $(call cc-version) -lt 0400 ] ; then \ - echo $(call cc-option,-fno-unit-at-a-time); fi ;) + KBUILD_CFLAGS += $(call cc-ifversion, -lt, 0400, \ + $(call cc-option,-fno-unit-at-a-time)) # CPU-specific tuning. Anything which can be shared with UML should go here. include $(srctree)/arch/x86/Makefile_32.cpu -- cgit v0.10.2 From 5b0f437df0a3e374d26ad533eb78fe64744f55a8 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 30 Jul 2009 19:00:53 +0200 Subject: workqueues: Improve schedule_work() documentation Two important aspects of the schedule_work() function are not yet documented: - that it is allowed to pass a struct work_struct * to this function that is already on the kernel-global workqueue; - the meaning of its return value. The patch below documents both aspects. Signed-off-by: Bart Van Assche Cc: "Greg Kroah-Hartman" Cc: Andrew Morton LKML-Reference: <200907301900.54202.bart.vanassche@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 0668795..3c44b56 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -600,7 +600,12 @@ static struct workqueue_struct *keventd_wq __read_mostly; * schedule_work - put work task in global workqueue * @work: job to be done * - * This puts a job in the kernel-global workqueue. + * Returns zero if @work was already on the kernel-global workqueue and + * non-zero otherwise. + * + * This puts a job in the kernel-global workqueue if it was not already + * queued and leaves it in the same position on the kernel-global + * workqueue otherwise. */ int schedule_work(struct work_struct *work) { -- cgit v0.10.2 From 54a0bf3c2cad3fd118ea725f26a493aece6ea01d Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 4 Aug 2009 15:52:38 +0200 Subject: Revert "x86: oprofile/op_model_amd.c set return values for op_amd_handle_ibs()" This reverts commit 21e70878215f620fe99ea7d7c74bc641aeec932f. Instead Andrew's patch will be applied he posted at the same time. Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 827beec..37d19c7 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -195,7 +195,7 @@ op_amd_handle_ibs(struct pt_regs * const regs, struct op_entry entry; if (!has_ibs) - return 0; + return 1; if (ibs_config.fetch_enabled) { rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl); @@ -277,10 +277,7 @@ static void op_amd_stop_ibs(void) #else static inline int op_amd_handle_ibs(struct pt_regs * const regs, - struct op_msrs const * const msrs) -{ - return 0; -} + struct op_msrs const * const msrs) { } static inline void op_amd_start_ibs(void) { } static inline void op_amd_stop_ibs(void) { } -- cgit v0.10.2 From cc6db4e60116c1f76577b6850a35ae7de69a95b6 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Fri, 31 Jul 2009 16:20:10 -0700 Subject: futex: Correct futex_wait_requeue_pi() commentary The state machine described in the comments wasn't updated with a follow-on fix. Address that and cleanup the corresponding commentary in the function. Signed-off-by: Darren Hart Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Thomas Gleixner LKML-Reference: <4A737C2A.9090001@us.ibm.com> Signed-off-by: Ingo Molnar diff --git a/kernel/futex.c b/kernel/futex.c index 0672ff8..d077201 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2102,11 +2102,11 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, * We call schedule in futex_wait_queue_me() when we enqueue and return there * via the following: * 1) wakeup on uaddr2 after an atomic lock acquisition by futex_requeue() - * 2) wakeup on uaddr2 after a requeue and subsequent unlock - * 3) signal (before or after requeue) - * 4) timeout (before or after requeue) + * 2) wakeup on uaddr2 after a requeue + * 3) signal + * 4) timeout * - * If 3, we setup a restart_block with futex_wait_requeue_pi() as the function. + * If 3, cleanup and return -ERESTARTNOINTR. * * If 2, we may then block on trying to take the rt_mutex and return via: * 5) successful lock @@ -2114,7 +2114,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, * 7) timeout * 8) other lock acquisition failure * - * If 6, we setup a restart_block with futex_lock_pi() as the function. + * If 6, return -EWOULDBLOCK (restarting the syscall would do the same). * * If 4 or 7, we cleanup and return with -ETIMEDOUT. * @@ -2232,14 +2232,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, rt_mutex_unlock(pi_mutex); } else if (ret == -EINTR) { /* - * We've already been requeued, but we have no way to - * restart by calling futex_lock_pi() directly. We - * could restart the syscall, but that will look at - * the user space value and return right away. So we - * drop back with EWOULDBLOCK to tell user space that - * "val" has been changed. That's the same what the - * restart of the syscall would do in - * futex_wait_setup(). + * We've already been requeued, but cannot restart by calling + * futex_lock_pi() directly. We could restart this syscall, but + * it would detect that the user space "val" changed and return + * -EWOULDBLOCK. Save the overhead of the restart and return + * -EWOULDBLOCK directly. */ ret = -EWOULDBLOCK; } -- cgit v0.10.2 From 4680e64a88c4ce2c4e736dade99233e3def13fa7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 23 Jun 2009 12:36:08 -0700 Subject: arch/x86/oprofile/op_model_amd.c: fix op_amd_handle_ibs() return type arch/x86/oprofile/op_model_amd.c: In function 'op_amd_handle_ibs': arch/x86/oprofile/op_model_amd.c:217: warning: no return statement in function returning non-void Fix this by making op_amd_handle_ibs() return void. Cc: Robert Richter Signed-off-by: Andrew Morton Signed-off-by: Robert Richter diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 37d19c7..39686c2 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -187,7 +187,7 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, #ifdef CONFIG_OPROFILE_IBS -static inline int +static inline void op_amd_handle_ibs(struct pt_regs * const regs, struct op_msrs const * const msrs) { @@ -195,7 +195,7 @@ op_amd_handle_ibs(struct pt_regs * const regs, struct op_entry entry; if (!has_ibs) - return 1; + return; if (ibs_config.fetch_enabled) { rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl); @@ -241,8 +241,6 @@ op_amd_handle_ibs(struct pt_regs * const regs, wrmsrl(MSR_AMD64_IBSOPCTL, ctl); } } - - return 1; } static inline void op_amd_start_ibs(void) @@ -276,7 +274,7 @@ static void op_amd_stop_ibs(void) #else -static inline int op_amd_handle_ibs(struct pt_regs * const regs, +static inline void op_amd_handle_ibs(struct pt_regs * const regs, struct op_msrs const * const msrs) { } static inline void op_amd_start_ibs(void) { } static inline void op_amd_stop_ibs(void) { } -- cgit v0.10.2 From 990a55eb25d9698d61352264cc43f3a9c04cce90 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 31 Jul 2009 00:02:06 +0200 Subject: irq: Clean up by removing irqfixup MODULE_PARM_DESC() It's wrong (the parm takes no arguments) and compile-time wiped away anyway (due to !MODULE). Signed-off-by: Jiri Slaby LKML-Reference: <1248991326-26267-1-git-send-email-jirislaby@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index 4d56829..114e704 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -297,7 +297,6 @@ static int __init irqfixup_setup(char *str) __setup("irqfixup", irqfixup_setup); module_param(irqfixup, int, 0644); -MODULE_PARM_DESC("irqfixup", "0: No fixup, 1: irqfixup mode, 2: irqpoll mode"); static int __init irqpoll_setup(char *str) { -- cgit v0.10.2 From 4da163ab0a224590f3cae67c1d54ae8c428f6223 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 20:28:40 +0200 Subject: mac80211: disable software retry for now Pavel Roskin reported a problem that seems to be due to software retry of already transmitted frames. It turns out that we've never done that correctly, but due to some recent changes it now crashes in the TX code. I've added a comment in the patch that explains the problem better and also points to possible solutions -- which I can't implement right now. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c1a7991..9dd8d25 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -310,6 +310,31 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + /* + * XXX: This is temporary! + * + * The problem here is that when we get here, the driver will + * quite likely have pretty much overwritten info->control by + * using info->driver_data or info->rate_driver_data. Thus, + * when passing out the frame to the driver again, we would be + * passing completely bogus data since the driver would then + * expect a properly filled info->control. In mac80211 itself + * the same problem occurs, since we need info->control.vif + * internally. + * + * To fix this, we should send the frame through TX processing + * again. However, it's not that simple, since the frame will + * have been software-encrypted (if applicable) already, and + * encrypting it again doesn't do much good. So to properly do + * that, we not only have to skip the actual 'raw' encryption + * (key selection etc. still has to be done!) but also the + * sequence number assignment since that impacts the crypto + * encapsulation, of course. + * + * Hence, for now, fix the bug by just dropping the frame. + */ + goto drop; + sta->tx_filtered_count++; /* @@ -363,6 +388,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, return; } + drop: #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped TX filtered frame, " -- cgit v0.10.2 From 9851bad7a3ab601b8b5b156119a7d0fd15b47fa3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 11:53:02 -0700 Subject: ath9k: re-order cancelling of work on mac80211 workqueue ath9k uses the mac80211 workqueue for 4 different types of work: * Led blink work * TX hang monitoring work * internal wiphy schedular work * channel change work done for internal wiphy schedular Since the internal wiphy schedular can end up kicking off some channel channel change work we should first cancel the wiphy schedular work and then the channel change work. The TX hang work can be cancelled second since we're going down anyway. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 75ddb2a..49f2764 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1252,9 +1252,9 @@ void ath_detach(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); ath_deinit_leds(sc); - cancel_work_sync(&sc->chan_work); - cancel_delayed_work_sync(&sc->wiphy_work); cancel_delayed_work_sync(&sc->tx_complete_work); + cancel_delayed_work_sync(&sc->wiphy_work); + cancel_work_sync(&sc->chan_work); for (i = 0; i < sc->num_sec_wiphy; i++) { struct ath_wiphy *aphy = sc->sec_wiphy[i]; -- cgit v0.10.2 From 35c95ab9b5ea3a2bf69d049d5437bb831e9bddf3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 11:53:03 -0700 Subject: ath9k: move cancel_delayed_work_sync() out of ath_deinit_leds() We do this as we'll be moving the cancel elsewhere later. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 49f2764..7437b42 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1056,7 +1056,6 @@ static void ath_unregister_led(struct ath_led *led) static void ath_deinit_leds(struct ath_softc *sc) { - cancel_delayed_work_sync(&sc->ath_led_blink_work); ath_unregister_led(&sc->assoc_led); sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; ath_unregister_led(&sc->tx_led); @@ -1113,6 +1112,7 @@ static void ath_init_leds(struct ath_softc *sc) return; fail: + cancel_delayed_work_sync(&sc->ath_led_blink_work); ath_deinit_leds(sc); } @@ -1251,11 +1251,13 @@ void ath_detach(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); - ath_deinit_leds(sc); + cancel_delayed_work_sync(&sc->ath_led_blink_work); cancel_delayed_work_sync(&sc->tx_complete_work); cancel_delayed_work_sync(&sc->wiphy_work); cancel_work_sync(&sc->chan_work); + ath_deinit_leds(sc); + for (i = 0; i < sc->num_sec_wiphy; i++) { struct ath_wiphy *aphy = sc->sec_wiphy[i]; if (aphy == NULL) -- cgit v0.10.2 From c94dbff7996b861fb0ff730bdf6eac4e2b288402 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 11:53:04 -0700 Subject: ath9k: move workqueue cancels to stop callback We should be cancelling our work at the stop callback since we are borrowing the mac80211 workqueue for our work. As it stands mac80211 expects this for suspend purposes. The ath9k specific virtual wiphy stuff need only be cancelled only when the we have no secondary virtual wiphys. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7437b42..cf44623 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1251,11 +1251,6 @@ void ath_detach(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); - cancel_delayed_work_sync(&sc->ath_led_blink_work); - cancel_delayed_work_sync(&sc->tx_complete_work); - cancel_delayed_work_sync(&sc->wiphy_work); - cancel_work_sync(&sc->chan_work); - ath_deinit_leds(sc); for (i = 0; i < sc->num_sec_wiphy; i++) { @@ -2091,6 +2086,14 @@ static void ath9k_stop(struct ieee80211_hw *hw) aphy->state = ATH_WIPHY_INACTIVE; + cancel_delayed_work_sync(&sc->ath_led_blink_work); + cancel_delayed_work_sync(&sc->tx_complete_work); + + if (!sc->num_sec_wiphy) { + cancel_delayed_work_sync(&sc->wiphy_work); + cancel_work_sync(&sc->chan_work); + } + if (sc->sc_flags & SC_OP_INVALID) { DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); return; -- cgit v0.10.2 From ebc8ab17d69cbaec6bb345a48a2cb87047643f63 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 11:56:23 -0700 Subject: ar76c50x-usb: cancel promisc work during mac80211 stop We weren't ever cancelling this. Signed-off-by: Luis R. Rodriguez Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 13303fa..bbf5277 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1773,6 +1773,8 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw) at76_dbg(DBG_MAC80211, "%s()", __func__); + cancel_work_sync(&priv->work_set_promisc); + mutex_lock(&priv->mtx); if (!priv->device_unplugged) { -- cgit v0.10.2 From 9ed21d390166ceb89e011d3dbd277475ff2f33c4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 11:56:24 -0700 Subject: at76c50x-usb: cancel scan work at stop callback This should fix suspend as mac80211 expects all work queued to the mac80211 workqueue to be canceled at driver stop(). Signed-off-by: Luis R. Rodriguez Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index bbf5277..f46e2b3 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1773,6 +1773,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw) at76_dbg(DBG_MAC80211, "%s()", __func__); + cancel_delayed_work(&priv->dwork_hw_scan); cancel_work_sync(&priv->work_set_promisc); mutex_lock(&priv->mtx); @@ -2298,7 +2299,6 @@ static void at76_delete_device(struct at76_priv *priv) tasklet_kill(&priv->rx_tasklet); if (priv->mac80211_registered) { - cancel_delayed_work(&priv->dwork_hw_scan); flush_workqueue(priv->hw->workqueue); ieee80211_unregister_hw(priv->hw); } -- cgit v0.10.2 From e351cfbf4e6ccd8bf32555748a49dba5bc93fcb0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 12:51:37 -0700 Subject: ar9170: remove unneeded flush_workqueue() cancel_delayed_work_sync() and cancel_work_sync() are already being used therefore already waiting for all pending work by the driver to have been completed, no need to flush the mac80211 workqueue. Cc: Christian Lamparter Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 85a1452..099ed3c 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1290,14 +1290,13 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) if (IS_STARTED(ar)) ar->state = AR9170_IDLE; - flush_workqueue(ar->hw->workqueue); - cancel_delayed_work_sync(&ar->tx_janitor); #ifdef CONFIG_AR9170_LEDS cancel_delayed_work_sync(&ar->led_work); #endif cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); + mutex_lock(&ar->mutex); if (IS_ACCEPTING_CMD(ar)) { -- cgit v0.10.2 From dd21dcdc65a182222666199ec4cea188a11cb5d2 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:10:22 -0700 Subject: wext: remove extra return on wireless_nlevent_init() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 3fe3c2c..5b4a0ce 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -1291,7 +1291,6 @@ static struct pernet_operations wext_pernet_ops = { static int __init wireless_nlevent_init(void) { return register_pernet_subsys(&wext_pernet_ops); - return 0; } subsys_initcall(wireless_nlevent_init); -- cgit v0.10.2 From d17734aee6383ff5e1720b3f01c014c0a9db40d5 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:52:06 -0700 Subject: ath: depend on cfg80211 The ath.ko module itself depends on cfg80211 Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index eb0337c..6bed009 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,6 +1,7 @@ config ATH_COMMON tristate "Atheros Wireless Cards" depends on WLAN_80211 + depends on CFG80211 depends on ATH5K || ATH9K || AR9170_USB source "drivers/net/wireless/ath/ath5k/Kconfig" -- cgit v0.10.2 From b820b3bcb02a97091b969faf2b5f19f1218953f9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:52:07 -0700 Subject: ath: simplify kconfig dependency and add documentation Make atheros wireless drivers visible when you select "Atheros wirless drivers". Adds links to ath.ko page, and Atheros drivers page on the wiki. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 6bed009..f27f3a7 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -2,9 +2,23 @@ config ATH_COMMON tristate "Atheros Wireless Cards" depends on WLAN_80211 depends on CFG80211 - depends on ATH5K || ATH9K || AR9170_USB + ---help--- + This will enable the support for the Atheros wireless drivers. + ath5k, ath9k and ar9170 drivers share some common code, this option + enables the common ath.ko module which currently shares just common + regulatory EEPROM helpers but will likely be extended later to share + more between modules. + For more information and documentation on this module you can visit: + + http://wireless.kernel.org/en/users/Drivers/ath + + For information on all Atheros wireless drivers visit: + + http://wireless.kernel.org/en/users/Drivers/Atheros + +if ATH_COMMON source "drivers/net/wireless/ath/ath5k/Kconfig" source "drivers/net/wireless/ath/ath9k/Kconfig" source "drivers/net/wireless/ath/ar9170/Kconfig" - +endif diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig index b99e326..de4281f 100644 --- a/drivers/net/wireless/ath/ar9170/Kconfig +++ b/drivers/net/wireless/ath/ar9170/Kconfig @@ -2,7 +2,6 @@ config AR9170_USB tristate "Atheros AR9170 802.11n USB support" depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER - select ATH_COMMON help This is a driver for the Atheros "otus" 802.11n USB devices. diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index daf0c83..9b07eef 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -1,7 +1,6 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL - select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 0f4a6d8..2cb72f8 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -1,7 +1,6 @@ config ATH9K tristate "Atheros 802.11n wireless cards support" depends on PCI && MAC80211 && WLAN_80211 - select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS -- cgit v0.10.2 From 44b7dd6dde1b80a94e5c0d01ecbc8097f52aa2dc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:52:08 -0700 Subject: ath: use menuconfig to put ath stuff in its own page Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index f27f3a7..253b95a 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,4 +1,4 @@ -config ATH_COMMON +menuconfig ATH_COMMON tristate "Atheros Wireless Cards" depends on WLAN_80211 depends on CFG80211 -- cgit v0.10.2 From 75323fa3dec54abb0bcba8ce6b4994020af210ca Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:52:09 -0700 Subject: ath5k: remove EXPERIMENTAL marker Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 9b07eef..06d0066 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -1,6 +1,6 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" - depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on PCI && MAC80211 && WLAN_80211 select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS -- cgit v0.10.2 From 3e6404528c95e3439f478e1d28353e77f6d9c188 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:56:15 -0700 Subject: wireless: use menuconfig for WLAN_PRE80211 and WLAN_80211 This should make it very clear which are pre-802.11 or not Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index ca7a8a3..dda7cc2 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -5,7 +5,7 @@ menu "Wireless LAN" depends on !S390 -config WLAN_PRE80211 +menuconfig WLAN_PRE80211 bool "Wireless LAN (pre-802.11)" depends on NETDEVICES ---help--- @@ -101,7 +101,7 @@ config PCMCIA_NETWAVE called netwave_cs. If unsure, say N. -config WLAN_80211 +menuconfig WLAN_80211 bool "Wireless LAN (IEEE 802.11)" depends on NETDEVICES ---help--- -- cgit v0.10.2 From 33172899a9d922b04081e12dced3ae474d46d620 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 28 Jul 2009 08:03:42 -0700 Subject: rt2x00: move experimental on kconfig only to rt2800usb These drivers have been around for a while, if there are issues they should be reported. rt2800usb is still a bit flaky though. Signed-off-by: Luis R. Rodriguez Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index f970aa2..ed1f997 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -1,8 +1,8 @@ menuconfig RT2X00 tristate "Ralink driver support" - depends on MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && WLAN_80211 ---help--- - This will enable the experimental support for the Ralink drivers, + This will enable the support for the Ralink drivers, developed in the rt2x00 project . These drivers make use of the mac80211 stack. @@ -79,14 +79,14 @@ config RT73USB config RT2800USB tristate "Ralink rt2800 (USB) support" - depends on USB + depends on USB && EXPERIMENTAL select RT2X00_LIB_USB select RT2X00_LIB_HT select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO select CRC_CCITT ---help--- - This adds support for rt2800 wireless chipset family. + This adds experimental support for rt2800 wireless chipset family. Supported chips: RT2770, RT2870 & RT3070. When compiled as a module, this driver will be called "rt2800usb.ko". -- cgit v0.10.2 From ad2f34b41fd6e2b84c896ccf321d5de0a7c7cd52 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 28 Jul 2009 18:58:54 +0200 Subject: rt2x00: Fix build error when crypto support is disabled When only rt2400pci or rt2500pci is compiled without any of the other rt2x00 modules, then CONFIG_RT2X00_LIB_CRYPTO will not be enabled. However rt2x00mac_set_tim() implemented within #ifdef CONFIG_RT2X00_LIB_CRYPTO statements while the declaration is placed outside the definition. This results in linking errors as reporte by Ken. rt2x00_set_tim() has nothing to do with crypto, and thus should be moved outside of the #ifdef statements. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 7de1a2c..e92c8f9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -435,6 +435,16 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); +int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt2x00lib_beacondone(rt2x00dev); + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_set_tim); + #ifdef CONFIG_RT2X00_LIB_CRYPTO static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len) { @@ -454,16 +464,6 @@ static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len) sizeof(crypto->rx_mic)); } -int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, - bool set) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - - rt2x00lib_beacondone(rt2x00dev); - return 0; -} -EXPORT_SYMBOL_GPL(rt2x00mac_set_tim); - int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) -- cgit v0.10.2 From 97af743207466ff8b477e14bfb7af0ba2c93375b Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 29 Jul 2009 10:13:03 +0200 Subject: mac80211: disable beacons before removing the associated interface When downing interfaces, it's a good idea to tell the driver to stop sending beacons; that way the driver doesn't need special code in ops->remove_interface() when it should already handle the case in bss_info_changed(). This fixes a potential crash with at least ath5k since the vif pointer will be nullified while beacon interrupts are still active. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6c655b6..6614d4f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -522,6 +522,16 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_scan_completed(&local->hw, true); } + /* + * Disable beaconing for AP and mesh, IBSS can't + * still be joined to a network at this point. + */ + if (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_MESH_POINT) { + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_BEACON_ENABLED); + } + conf.vif = &sdata->vif; conf.type = sdata->vif.type; conf.mac_addr = dev->dev_addr; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9dd8d25..5e76dd1 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -198,7 +198,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (test_bit(SCAN_SW_SCANNING, &local->scanning)) { + if (local->quiescing || !netif_running(sdata->dev) || + test_bit(SCAN_SW_SCANNING, &local->scanning)) { sdata->vif.bss_conf.enable_beacon = false; } else { /* diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 5e3d476..3320f7d 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -96,6 +96,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) if (!netif_running(sdata->dev)) continue; + /* disable beaconing */ + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_BEACON_ENABLED); + conf.vif = &sdata->vif; conf.type = sdata->vif.type; conf.mac_addr = sdata->dev->dev_addr; -- cgit v0.10.2 From df7fc0f9735085bb617fff774bfd71465edb448c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Jul 2009 11:23:49 +0200 Subject: cfg80211: keep track of current_bss for userspace SME When a userspace SME is active, we're currently not keeping track of the BSS properly for reporting the current link and for internal use. Additionally, it looks like there is a possible BSS leak in that the BSS never gets removed from auth_bsses[]. To fix it, pass the BSS struct to __cfg80211_connect_result in this case. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index f9fee65..755cdf1 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -314,7 +314,8 @@ static void cfg80211_process_events(struct wireless_dev *wdev) ev->cr.req_ie, ev->cr.req_ie_len, ev->cr.resp_ie, ev->cr.resp_ie_len, ev->cr.status, - ev->cr.status == WLAN_STATUS_SUCCESS); + ev->cr.status == WLAN_STATUS_SUCCESS, + NULL); break; case EVENT_ROAMED: __cfg80211_roamed(wdev, ev->rm.bssid, diff --git a/net/wireless/core.h b/net/wireless/core.h index 6d903c1..325c17e 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -127,6 +127,11 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu return container_of(pub, struct cfg80211_internal_bss, pub); } +static inline void cfg80211_ref_bss(struct cfg80211_internal_bss *bss) +{ + kref_get(&bss->ref); +} + static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) { atomic_inc(&bss->hold); @@ -323,7 +328,8 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, const u8 *req_ie, size_t req_ie_len, const u8 *resp_ie, size_t resp_ie_len, - u16 status, bool wextev); + u16 status, bool wextev, + struct cfg80211_bss *bss); /* SME */ int __cfg80211_connect(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 097a87d..525e8e2 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -61,7 +61,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; u8 *ie = mgmt->u.assoc_resp.variable; int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); - bool done; + struct cfg80211_internal_bss *bss = NULL; wdev_lock(wdev); @@ -69,22 +69,32 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); - __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, - status_code, - status_code == WLAN_STATUS_SUCCESS); - if (status_code == WLAN_STATUS_SUCCESS) { - for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) { - if (wdev->auth_bsses[i] == wdev->current_bss) { - cfg80211_unhold_bss(wdev->auth_bsses[i]); - cfg80211_put_bss(&wdev->auth_bsses[i]->pub); + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (!wdev->auth_bsses[i]) + continue; + if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid, + ETH_ALEN) == 0) { + bss = wdev->auth_bsses[i]; wdev->auth_bsses[i] = NULL; - done = true; + /* additional reference to drop hold */ + cfg80211_ref_bss(bss); break; } } - WARN_ON(!done); + WARN_ON(!bss); + } + + /* this consumes one bss reference (unless bss is NULL) */ + __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, + status_code, + status_code == WLAN_STATUS_SUCCESS, + bss ? &bss->pub : NULL); + /* drop hold now, and also reference acquired above */ + if (bss) { + cfg80211_unhold_bss(bss); + cfg80211_put_bss(&bss->pub); } wdev_unlock(wdev); @@ -144,7 +154,7 @@ static void __cfg80211_send_deauth(struct net_device *dev, } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, - false); + false, NULL); } } @@ -241,7 +251,7 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) if (wdev->sme_state == CFG80211_SME_CONNECTING) __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, - false); + false, NULL); for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { if (wdev->authtry_bsses[i] && @@ -275,7 +285,7 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) if (wdev->sme_state == CFG80211_SME_CONNECTING) __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, - false); + false, NULL); for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { if (wdev->auth_bsses[i] && diff --git a/net/wireless/sme.c b/net/wireless/sme.c index d2b5d4c..3728d2b 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -182,7 +182,7 @@ void cfg80211_conn_work(struct work_struct *work) wdev->conn->params.bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, - false); + false, NULL); wdev_unlock(wdev); } @@ -247,7 +247,7 @@ static void __cfg80211_sme_scan_done(struct net_device *dev) wdev->conn->params.bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, - false); + false, NULL); } } @@ -305,7 +305,7 @@ void cfg80211_sme_rx_auth(struct net_device *dev, schedule_work(&rdev->conn_work); } else if (status_code != WLAN_STATUS_SUCCESS) { __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, - status_code, false); + status_code, false, NULL); } else if (wdev->sme_state == CFG80211_SME_CONNECTING && wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; @@ -316,10 +316,10 @@ void cfg80211_sme_rx_auth(struct net_device *dev, void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, const u8 *req_ie, size_t req_ie_len, const u8 *resp_ie, size_t resp_ie_len, - u16 status, bool wextev) + u16 status, bool wextev, + struct cfg80211_bss *bss) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_bss *bss; #ifdef CONFIG_WIRELESS_EXT union iwreq_data wrqu; #endif @@ -361,6 +361,12 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, } #endif + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(&wdev->current_bss->pub); + wdev->current_bss = NULL; + } + if (status == WLAN_STATUS_SUCCESS && wdev->sme_state == CFG80211_SME_IDLE) goto success; @@ -368,12 +374,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (wdev->sme_state != CFG80211_SME_CONNECTING) return; - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(&wdev->current_bss->pub); - wdev->current_bss = NULL; - } - if (wdev->conn) wdev->conn->state = CFG80211_CONN_IDLE; @@ -386,10 +386,12 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, return; } - bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, - wdev->ssid, wdev->ssid_len, - WLAN_CAPABILITY_ESS, - WLAN_CAPABILITY_ESS); + success: + if (!bss) + bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, + wdev->ssid, wdev->ssid_len, + WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); if (WARN_ON(!bss)) return; @@ -397,7 +399,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, cfg80211_hold_bss(bss_from_pub(bss)); wdev->current_bss = bss_from_pub(bss); - success: wdev->sme_state = CFG80211_SME_CONNECTED; cfg80211_upload_connect_keys(wdev); } @@ -788,7 +789,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, else if (wdev->sme_state == CFG80211_SME_CONNECTING) __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, - wextev); + wextev, NULL); return 0; } -- cgit v0.10.2 From 42e8856092be1db40bd4ae01406d2aaddf4e66fc Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Jul 2009 15:05:21 +0530 Subject: ath9k: Update rate control for 11NA HT40 mode Now the lowest rate in 11na ht40 mode is 13.5Mbps this shortens the range when compared to 11na ht20 mode where the lowest rate is 6.5Mbps. To improve the range, make 6.5Mbps as the lowest rate in 11na ht40 mode, this improves the range by approximately 2dB. 11ng ht40 does not have this issue as it also has basic rates (1, 2, 5.5 and 11). Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a07efa2..59ad47c 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -44,7 +44,7 @@ static const struct ath_rate_table ar5416_11na_ratetable = { { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, 4, 7, 7, 7, 7, 0 }, - { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ + { VALID_2040, VALID_2040, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, 0, 8, 24, 8, 24, 3216 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ @@ -463,8 +463,6 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) if (!ignore_cw && WLAN_RC_PHY_HT(phy)) if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) return 0; - if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG)) - return 0; return 1; } -- cgit v0.10.2 From 3fc0fbf407967fa8def04d019316553c9ca133e2 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Jul 2009 15:05:22 +0530 Subject: ath9k: Maintain monotonicity of PER while going across different phy Monotonicity of packet error rate should be kept when moving from one phy to another (legacy to ht, ht single stream to dual, etc). Current code skips updating per for other phys. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 59ad47c..16a2717 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1041,9 +1041,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Monotonicity is kept only for rates below the current rate. */ if (ath_rc_priv->per[tx_rate] < last_per) { for (rate = tx_rate - 1; rate >= 0; rate--) { - if (rate_table->info[rate].phy != - rate_table->info[tx_rate].phy) - break; if (ath_rc_priv->per[rate] > ath_rc_priv->per[rate+1]) { -- cgit v0.10.2 From 0b3acfa71a50a1fa1fcee528aa15404ea4ea0877 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Jul 2009 15:05:23 +0530 Subject: ath9k: Remove unused ath9k_hw_intrget() Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 431854c..7a0a6ae 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3152,11 +3152,6 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) return true; } -enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah) -{ - return ah->mask_reg; -} - enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) { u32 omask = ah->mask_reg; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 2e196df..93a8930 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -612,7 +612,6 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore); /* Interrupt Handling */ bool ath9k_hw_intrpend(struct ath_hw *ah); bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); -enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); void ath9k_hw_btcoex_enable(struct ath_hw *ah); -- cgit v0.10.2 From 57c9fff3d0c5d77bc7910717faeca4e8a018b1ee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Jul 2009 15:46:21 +0200 Subject: mac80211: fix sparse warnings/errors sparse complains about a shadowed variable, which we can just rename, and lots of stuff if the API tracer is enabled, so kick out the tracer code in a sparse run -- the macros just confuse it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c index 6da6f79..8ed8711 100644 --- a/net/mac80211/driver-trace.c +++ b/net/mac80211/driver-trace.c @@ -1,6 +1,9 @@ /* bug in tracepoint.h, it should include this */ #include +/* sparse isn't too happy with all macros... */ +#ifndef __CHECKER__ #include "driver-ops.h" #define CREATE_TRACE_POINTS #include "driver-trace.h" +#endif diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6614d4f..a83087f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -401,7 +401,7 @@ static int ieee80211_stop(struct net_device *dev) /* APs need special treatment */ if (sdata->vif.type == NL80211_IFTYPE_AP) { - struct ieee80211_sub_if_data *vlan, *tmp; + struct ieee80211_sub_if_data *vlan, *tmpsdata; struct beacon_data *old_beacon = sdata->u.ap.beacon; /* remove beacon */ @@ -410,7 +410,7 @@ static int ieee80211_stop(struct net_device *dev) kfree(old_beacon); /* down all dependent devices, that is VLANs */ - list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans, + list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, u.vlan.list) dev_close(vlan->dev); WARN_ON(!list_empty(&sdata->u.ap.vlans)); -- cgit v0.10.2 From ae6f53f25f9803212d1985b5eb5a03111f439c24 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 29 Jul 2009 10:29:03 -0400 Subject: ath5k: update PCU opmode whenever a new interface is added Previously, we would store the operating mode at interface up time, but only update the PCU registers when the next reset happened. The result is that if beacon configuration (ops->bss_info_changed) happens before ops->config, we will program the wrong things into the timer registers. Consequently, beacons won't work in AP mode until after a reset (channel change, scan etc.). This is fragile anyway so just program the opmode as soon as mac80211 gives it to us. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 7db32ce..55ee976 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1117,6 +1117,8 @@ ath5k_mode_setup(struct ath5k_softc *sc) struct ath5k_hw *ah = sc->ah; u32 rfilt; + ah->ah_op_mode = sc->opmode; + /* configure rx filter */ rfilt = sc->filter_flags; ath5k_hw_set_rx_filter(ah, rfilt); @@ -2768,6 +2770,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, } ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); + ath5k_mode_setup(sc); ret = 0; end: -- cgit v0.10.2 From 18c6951091eca7645005a71b556106cc99a6f4b1 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 29 Jul 2009 10:54:06 -0500 Subject: b43: Work around mac80211 race condition As shown in http://thread.gmane.org/gmane.linux.kernel.wireless.general/36497, mac80211 has a bug that allows a call to the TX routine after the queues have been stopped. This situation will only occur under extreme stress. Although b43 does not crash when this condition occurs, it does generate a WARN_ON and also logs a queue overrun message. This patch recognizes b43 is not at fault and logs a message only when the most verbose debugging mode is enabled. In the unlikely event that the queue is not stopped when the DMA queue becomes full, then a warning is issued. During testing of this patch with one output stream running repeated tcpperf writes and a second running a flood ping, this routine was entered with the DMA ring stopped about once per hour. The condition where the DMA queue is full but the ring has not been stopped has never been seen by me. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 7964cc3..41a0e9c 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1334,13 +1334,22 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) spin_lock_irqsave(&ring->lock, flags); B43_WARN_ON(!ring->tx); - /* Check if the queue was stopped in mac80211, - * but we got called nevertheless. - * That would be a mac80211 bug. */ - B43_WARN_ON(ring->stopped); - if (unlikely(free_slots(ring) < TX_SLOTS_PER_FRAME)) { - b43warn(dev->wl, "DMA queue overflow\n"); + if (unlikely(ring->stopped)) { + /* We get here only because of a bug in mac80211. + * Because of a race, one packet may be queued after + * the queue is stopped, thus we got called when we shouldn't. + * For now, just refuse the transmit. */ + if (b43_debug(dev, B43_DBG_DMAVERBOSE)) + b43err(dev->wl, "Packet after queue stopped\n"); + err = -ENOSPC; + goto out_unlock; + } + + if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) { + /* If we get here, we have a real error with the queue + * full, but queues not stopped. */ + b43err(dev->wl, "DMA queue overflow\n"); err = -ENOSPC; goto out_unlock; } -- cgit v0.10.2 From 91b092d73435489d7336f94e927d96224b26c9a8 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:52:10 -0700 Subject: ar9170: remove EXPERIMENTAL marker Cc: Christian Lamparter Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig index de4281f..05918f1 100644 --- a/drivers/net/wireless/ath/ar9170/Kconfig +++ b/drivers/net/wireless/ath/ar9170/Kconfig @@ -1,12 +1,13 @@ config AR9170_USB tristate "Atheros AR9170 802.11n USB support" - depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on USB && MAC80211 && WLAN_80211 select FW_LOADER help This is a driver for the Atheros "otus" 802.11n USB devices. These devices require additional firmware (2 files). For now, these files can be downloaded from here: + http://wireless.kernel.org/en/users/Drivers/ar9170 If you choose to build a module, it'll be called ar9170usb. -- cgit v0.10.2 From 7e2ce646fc0acc99837f73d39528493e146d1dcc Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 28 Jul 2009 16:34:26 +0200 Subject: orinoco: enable cfg80211 "set_channel" operation Signed-off-by: Holger Schurig Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 1a87d3a..27f2d33 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -156,7 +156,48 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, return err; } +static int orinoco_set_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + int err = 0; + unsigned long flags; + int channel; + + if (!chan) + return -EINVAL; + + if (channel_type != NL80211_CHAN_NO_HT) + return -EINVAL; + + if (chan->band != IEEE80211_BAND_2GHZ) + return -EINVAL; + + channel = ieee80211_freq_to_dsss_chan(chan->center_freq); + + if ((channel < 1) || (channel > NUM_CHANNELS) || + !(priv->channel_mask & (1 << (channel-1)))) + return -EINVAL; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + priv->channel = channel; + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { + /* Fast channel change - no commit if successful */ + hermes_t *hw = &priv->hw; + err = hermes_docmd_wait(hw, HERMES_CMD_TEST | + HERMES_TEST_SET_CHANNEL, + channel, NULL); + } + orinoco_unlock(priv, &flags); + + return err; +} + const struct cfg80211_ops orinoco_cfg_ops = { .change_virtual_intf = orinoco_change_vif, + .set_channel = orinoco_set_channel, .scan = orinoco_scan, }; -- cgit v0.10.2 From 8784d2ee92fc835bf18dd5096f00ec9a48dc0590 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 29 Jul 2009 17:32:28 -0400 Subject: ath5k: fix CAB queue operation We need to process tx descriptors for all queues (currently main tx queue and cabq) which may have triggered the TX completion interrupt. Otherwise, the queues can get stuck after sending a few frames. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 55ee976..3a1c156d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2000,9 +2000,12 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) static void ath5k_tasklet_tx(unsigned long data) { + int i; struct ath5k_softc *sc = (void *)data; - ath5k_tx_processq(sc, sc->txq); + for (i=0; i < AR5K_NUM_TX_QUEUES; i++) + if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i))) + ath5k_tx_processq(sc, &sc->txqs[i]); } -- cgit v0.10.2 From 64344d78228f6346a0462ba2d5fc03494aef4e6b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 29 Jul 2009 14:20:41 -0700 Subject: at76c50x-usb: remove unneeded flush_workqueue() at usb disconnect This driver only uses the mac80211 workqueue and mac80211 requires us to cancel all work at driver stop. Since we now have the cancels in the right places at stop() we really don't need to flush the mac80211 workqueue so remove it. Signed-off-by: Luis R. Rodriguez Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index f46e2b3..aff09a1 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -2298,10 +2298,8 @@ static void at76_delete_device(struct at76_priv *priv) tasklet_kill(&priv->rx_tasklet); - if (priv->mac80211_registered) { - flush_workqueue(priv->hw->workqueue); + if (priv->mac80211_registered) ieee80211_unregister_hw(priv->hw); - } if (priv->tx_urb) { usb_kill_urb(priv->tx_urb); -- cgit v0.10.2 From 42935ecaf4e784d0815afa9a7e5fe7e141157ca3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 29 Jul 2009 20:08:07 -0400 Subject: mac80211: redefine usage of the mac80211 workqueue The mac80211 workqueue exists to enable mac80211 and drivers to queue their own work on a single threaded workqueue. mac80211 takes care to flush the workqueue during suspend but we never really had requirements on drivers for how they should use the workqueue in consideration for suspend. We extend mac80211 to document how the mac80211 workqueue should be used, how it should not be used and finally move raw access to the workqueue to mac80211 only. Drivers and mac80211 use helpers to queue work onto the mac80211 workqueue: * ieee80211_queue_work() * ieee80211_queue_delayed_work() These helpers will now warn if mac80211 already completed its suspend cycle and someone is trying to queue work. mac80211 flushes the mac80211 workqueue prior to suspend a few times, but we haven't taken the care to ensure drivers won't add more work after suspend. To help with this we add a warning when someone tries to add work and mac80211 already completed the suspend cycle. Drivers should ensure they cancel any work or delayed work in the mac80211 stop() callback. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index aff09a1..7218dba 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1875,8 +1875,8 @@ static void at76_dwork_hw_scan(struct work_struct *work) /* FIXME: add maximum time for scan to complete */ if (ret != CMD_STATUS_COMPLETE) { - queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan, - SCAN_POLL_INTERVAL); + ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan, + SCAN_POLL_INTERVAL); mutex_unlock(&priv->mtx); return; } @@ -1937,8 +1937,8 @@ static int at76_hw_scan(struct ieee80211_hw *hw, goto exit; } - queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan, - SCAN_POLL_INTERVAL); + ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan, + SCAN_POLL_INTERVAL); exit: mutex_unlock(&priv->mtx); @@ -2027,7 +2027,7 @@ static void at76_configure_filter(struct ieee80211_hw *hw, } else return; - queue_work(hw->workqueue, &priv->work_set_promisc); + ieee80211_queue_work(hw, &priv->work_set_promisc); } static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c index 63fda6c..86c4e79 100644 --- a/drivers/net/wireless/ath/ar9170/led.c +++ b/drivers/net/wireless/ath/ar9170/led.c @@ -90,9 +90,12 @@ static void ar9170_update_leds(struct work_struct *work) ar9170_set_leds_state(ar, led_val); mutex_unlock(&ar->mutex); - if (rerun) - queue_delayed_work(ar->hw->workqueue, &ar->led_work, - msecs_to_jiffies(blink_delay)); + if (!rerun) + return; + + ieee80211_queue_delayed_work(ar->hw, + &ar->led_work, + msecs_to_jiffies(blink_delay)); } static void ar9170_led_brightness_set(struct led_classdev *led, @@ -110,7 +113,7 @@ static void ar9170_led_brightness_set(struct led_classdev *led, } if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) - queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10); + ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10); } static int ar9170_register_led(struct ar9170 *ar, int i, char *name, diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 099ed3c..4fc389a 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -595,10 +595,12 @@ static void ar9170_tx_janitor(struct work_struct *work) ar9170_tx_fake_ampdu_status(ar); - if (resched) - queue_delayed_work(ar->hw->workqueue, - &ar->tx_janitor, - msecs_to_jiffies(AR9170_JANITOR_DELAY)); + if (!resched) + return; + + ieee80211_queue_delayed_work(ar->hw, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); } void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) @@ -648,7 +650,7 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) * pre-TBTT event */ if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP) - queue_work(ar->hw->workqueue, &ar->beacon_work); + ieee80211_queue_work(ar->hw, &ar->beacon_work); break; case 0xc2: @@ -1825,10 +1827,12 @@ static void ar9170_tx(struct ar9170 *ar) } } - if (schedule_garbagecollector) - queue_delayed_work(ar->hw->workqueue, - &ar->tx_janitor, - msecs_to_jiffies(AR9170_JANITOR_DELAY)); + if (!schedule_garbagecollector) + return; + + ieee80211_queue_delayed_work(ar->hw, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); } static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb) @@ -2157,7 +2161,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, } if (likely(IS_STARTED(ar))) - queue_work(ar->hw->workqueue, &ar->filter_config_work); + ieee80211_queue_work(ar->hw, &ar->filter_config_work); } static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, @@ -2415,7 +2419,7 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, } if (IS_STARTED(ar) && ar->filter_changed) - queue_work(ar->hw->workqueue, &ar->filter_config_work); + ieee80211_queue_work(ar->hw, &ar->filter_config_work); } static int ar9170_get_stats(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cf44623..292ac2b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -973,10 +973,11 @@ static void ath_led_blink_work(struct work_struct *work) ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); - queue_delayed_work(sc->hw->workqueue, &sc->ath_led_blink_work, - (sc->sc_flags & SC_OP_LED_ON) ? - msecs_to_jiffies(sc->led_off_duration) : - msecs_to_jiffies(sc->led_on_duration)); + ieee80211_queue_delayed_work(sc->hw, + &sc->ath_led_blink_work, + (sc->sc_flags & SC_OP_LED_ON) ? + msecs_to_jiffies(sc->led_off_duration) : + msecs_to_jiffies(sc->led_on_duration)); sc->led_on_duration = sc->led_on_cnt ? max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : @@ -1013,8 +1014,8 @@ static void ath_led_brightness(struct led_classdev *led_cdev, case LED_FULL: if (led->led_type == ATH_LED_ASSOC) { sc->sc_flags |= SC_OP_LED_ASSOCIATED; - queue_delayed_work(sc->hw->workqueue, - &sc->ath_led_blink_work, 0); + ieee80211_queue_delayed_work(sc->hw, + &sc->ath_led_blink_work, 0); } else if (led->led_type == ATH_LED_RADIO) { ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); sc->sc_flags |= SC_OP_LED_ON; @@ -1972,7 +1973,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_wake_queues(hw); - queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0); + ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); mutex_unlock: mutex_unlock(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index e1d419e..19b88f8 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -351,7 +351,7 @@ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) * Drop from tasklet to work to allow mutex for channel * change. */ - queue_work(aphy->sc->hw->workqueue, + ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work); } } @@ -367,7 +367,7 @@ static void ath9k_mark_paused(struct ath_wiphy *aphy) struct ath_softc *sc = aphy->sc; aphy->state = ATH_WIPHY_PAUSED; if (!__ath9k_wiphy_pausing(sc)) - queue_work(sc->hw->workqueue, &sc->chan_work); + ieee80211_queue_work(sc->hw, &sc->chan_work); } static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) @@ -521,7 +521,7 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy) spin_unlock_bh(&sc->wiphy_lock); ath_radio_disable(sc); ath_radio_enable(sc); - queue_work(aphy->sc->hw->workqueue, + ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work); return -EBUSY; /* previous select still in progress */ } @@ -541,7 +541,7 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy) if (now) { /* Ready to request channel change immediately */ - queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work); + ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work); } /* @@ -648,8 +648,9 @@ try_again: "change\n"); } - queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, - sc->wiphy_scheduler_int); + ieee80211_queue_delayed_work(sc->hw, + &sc->wiphy_work, + sc->wiphy_scheduler_int); } void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) @@ -657,8 +658,8 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) cancel_delayed_work_sync(&sc->wiphy_work); sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int); if (sc->wiphy_scheduler_int) - queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, - sc->wiphy_scheduler_int); + ieee80211_queue_delayed_work(sc->hw, &sc->wiphy_work, + sc->wiphy_scheduler_int); } /* caller must hold wiphy_lock */ diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index b7806e2..87762da 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2063,7 +2063,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work) ath_reset(sc, false); } - queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, + ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT)); } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 3f4360a..f985938 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1654,7 +1654,7 @@ static void b43_update_templates(struct b43_wl *wl) wl->current_beacon = beacon; wl->beacon0_uploaded = 0; wl->beacon1_uploaded = 0; - queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); + ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger); } static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) @@ -2914,7 +2914,7 @@ out_requeue: delay = msecs_to_jiffies(50); else delay = round_jiffies_relative(HZ * 15); - queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay); + ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay); out: mutex_unlock(&wl->mutex); } @@ -2925,7 +2925,7 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev) dev->periodic_state = 0; INIT_DELAYED_WORK(work, b43_periodic_work_handler); - queue_delayed_work(dev->wl->hw->workqueue, work, 0); + ieee80211_queue_delayed_work(dev->wl->hw, work, 0); } /* Check if communication with the device works correctly. */ @@ -4871,7 +4871,7 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason) if (b43_status(dev) < B43_STAT_INITIALIZED) return; b43info(dev->wl, "Controller RESET (%s) ...\n", reason); - queue_work(dev->wl->hw->workqueue, &dev->restart_work); + ieee80211_queue_work(dev->wl->hw, &dev->restart_work); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 6d24162..f537bfe 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -352,7 +352,7 @@ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) /* We must adjust the transmission power in hardware. * Schedule b43_phy_txpower_adjust_work(). */ - queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work); + ieee80211_queue_work(dev->wl->hw, &dev->wl->txpower_adjust_work); } int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset) diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 69138e8..73c047d 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -783,7 +783,7 @@ void b43_pio_rx(struct b43_pio_rxqueue *q) { /* Due to latency issues we must run the RX path in * a workqueue to be able to schedule between packets. */ - queue_work(q->dev->wl->hw->workqueue, &q->rx_work); + ieee80211_queue_work(q->dev->wl->hw, &q->rx_work); } static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index c4973c1..b143559 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1252,7 +1252,7 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl) wl->current_beacon = beacon; wl->beacon0_uploaded = 0; wl->beacon1_uploaded = 0; - queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); + ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger); } static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, @@ -2300,7 +2300,7 @@ out_requeue: delay = msecs_to_jiffies(50); else delay = round_jiffies_relative(HZ * 15); - queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay); + ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay); out: mutex_unlock(&wl->mutex); } @@ -2311,7 +2311,7 @@ static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev) dev->periodic_state = 0; INIT_DELAYED_WORK(work, b43legacy_periodic_work_handler); - queue_delayed_work(dev->wl->hw->workqueue, work, 0); + ieee80211_queue_delayed_work(dev->wl->hw, work, 0); } /* Validate access to the chip (SHM) */ @@ -3885,7 +3885,7 @@ void b43legacy_controller_restart(struct b43legacy_wldev *dev, if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) return; b43legacyinfo(dev->wl, "Controller RESET (%s) ...\n", reason); - queue_work(dev->wl->hw->workqueue, &dev->restart_work); + ieee80211_queue_work(dev->wl->hw, &dev->restart_work); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c index c00115b..9575ac0 100644 --- a/drivers/net/wireless/p54/led.c +++ b/drivers/net/wireless/p54/led.c @@ -61,7 +61,7 @@ static void p54_update_leds(struct work_struct *work) wiphy_name(priv->hw->wiphy), err); if (rerun) - queue_delayed_work(priv->hw->workqueue, &priv->led_work, + ieee80211_queue_delayed_work(priv->hw, &priv->led_work, msecs_to_jiffies(blink_delay)); } @@ -78,8 +78,7 @@ static void p54_led_brightness_set(struct led_classdev *led_dev, if ((brightness) && (led->registered)) { led->toggled++; - queue_delayed_work(priv->hw->workqueue, &priv->led_work, - HZ/10); + ieee80211_queue_delayed_work(priv->hw, &priv->led_work, HZ/10); } } diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 955f6d7..a0d0e72 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -180,7 +180,7 @@ static int p54_start(struct ieee80211_hw *dev) goto out; } - queue_delayed_work(dev->workqueue, &priv->work, 0); + ieee80211_queue_delayed_work(dev, &priv->work, 0); priv->softled_state = 0; err = p54_set_leds(priv); diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index eef5329..05458d9 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -391,7 +391,7 @@ static irqreturn_t p54spi_interrupt(int irq, void *config) struct spi_device *spi = config; struct p54s_priv *priv = dev_get_drvdata(&spi->dev); - queue_work(priv->hw->workqueue, &priv->work); + ieee80211_queue_work(priv->hw, &priv->work); return IRQ_HANDLED; } @@ -479,7 +479,7 @@ static void p54spi_op_tx(struct ieee80211_hw *dev, struct sk_buff *skb) list_add_tail(&di->tx_list, &priv->tx_pending); spin_unlock_irqrestore(&priv->tx_lock, flags); - queue_work(priv->hw->workqueue, &priv->work); + ieee80211_queue_work(priv->hw, &priv->work); } static void p54spi_work(struct work_struct *work) diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index c32a0d2..704685f 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -380,7 +380,7 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb) ieee80211_rx_irqsafe(priv->hw, skb); - queue_delayed_work(priv->hw->workqueue, &priv->work, + ieee80211_queue_delayed_work(priv->hw, &priv->work, msecs_to_jiffies(P54_STATISTICS_UPDATE)); return -1; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 658a63b..b717afb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -215,7 +215,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) rt2x00lib_beacondone_iter, rt2x00dev); - queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work); + ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work); } EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 7991568..9178316 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -351,8 +351,8 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) rt2x00link_reset_tuner(rt2x00dev, false); - queue_delayed_work(rt2x00dev->hw->workqueue, - &link->work, LINK_TUNE_INTERVAL); + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->work, LINK_TUNE_INTERVAL); } void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev) @@ -461,8 +461,8 @@ static void rt2x00link_tuner(struct work_struct *work) * Increase tuner counter, and reschedule the next link tuner run. */ link->count++; - queue_delayed_work(rt2x00dev->hw->workqueue, - &link->work, LINK_TUNE_INTERVAL); + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->work, LINK_TUNE_INTERVAL); } void rt2x00link_register(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index e92c8f9..81febdf 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -431,7 +431,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); else - queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); + ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->filter_work); } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index c9b9dbe..53f57dc 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -220,7 +220,7 @@ static void rtl8187_tx_cb(struct urb *urb) * reading a register in the device. We are in interrupt mode * here, thus queue the skb and finish on a work queue. */ skb_queue_tail(&priv->b_tx_status.queue, skb); - queue_delayed_work(hw->workqueue, &priv->work, 0); + ieee80211_queue_delayed_work(hw, &priv->work, 0); } } diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c index cf9f899..a6cfb7e 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_leds.c +++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c @@ -108,11 +108,11 @@ static void rtl8187_led_brightness_set(struct led_classdev *led_dev, struct rtl8187_priv *priv = hw->priv; if (brightness == LED_OFF) { - queue_delayed_work(hw->workqueue, &priv->led_off, 0); + ieee80211_queue_delayed_work(hw, &priv->led_off, 0); /* The LED is off for 1/20 sec so that it just blinks. */ - queue_delayed_work(hw->workqueue, &priv->led_on, HZ / 20); + ieee80211_queue_delayed_work(hw, &priv->led_on, HZ / 20); } else - queue_delayed_work(hw->workqueue, &priv->led_on, 0); + ieee80211_queue_delayed_work(hw, &priv->led_on, 0); } static int rtl8187_register_led(struct ieee80211_hw *dev, @@ -193,7 +193,7 @@ void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid) err = rtl8187_register_led(dev, &priv->led_rx, name, ieee80211_get_rx_led_name(dev), ledpin); if (!err) { - queue_delayed_work(dev->workqueue, &priv->led_on, 0); + ieee80211_queue_delayed_work(dev, &priv->led_on, 0); return; } /* registration of RX LED failed - unregister TX */ @@ -209,7 +209,7 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev) struct rtl8187_priv *priv = dev->priv; /* turn the LED off before exiting */ - queue_delayed_work(dev->workqueue, &priv->led_off, 0); + ieee80211_queue_delayed_work(dev, &priv->led_off, 0); cancel_delayed_work_sync(&priv->led_off); cancel_delayed_work_sync(&priv->led_on); rtl8187_unregister_led(&priv->led_rx); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 9600b72..54abdd0c 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -698,7 +698,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) && !mac->pass_ctrl) return 0; - fc = *(__le16 *)buffer; + fc = get_unaligned((__le16*)buffer); need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc); skb = dev_alloc_skb(length + (need_padding ? 2 : 0)); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d4e09a0..5ed93f4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -73,6 +73,21 @@ */ /** + * DOC: mac80211 workqueue + * + * mac80211 provides its own workqueue for drivers and internal mac80211 use. + * The workqueue is a single threaded workqueue and can only be accessed by + * helpers for sanity checking. Drivers must ensure all work added onto the + * mac80211 workqueue should be cancelled on the driver stop() callback. + * + * mac80211 will flushed the workqueue upon interface removal and during + * suspend. + * + * All work performed on the mac80211 workqueue must not acquire the RTNL lock. + * + */ + +/** * enum ieee80211_max_queues - maximum number of queues * * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues. @@ -913,12 +928,6 @@ enum ieee80211_hw_flags { * * @conf: &struct ieee80211_conf, device configuration, don't use. * - * @workqueue: single threaded workqueue available for driver use, - * allocated by mac80211 on registration and flushed when an - * interface is removed. - * NOTICE: All work performed on this workqueue must not - * acquire the RTNL lock. - * * @priv: pointer to private area that was allocated for driver use * along with this structure. * @@ -954,7 +963,6 @@ enum ieee80211_hw_flags { struct ieee80211_hw { struct ieee80211_conf conf; struct wiphy *wiphy; - struct workqueue_struct *workqueue; const char *rate_control_algorithm; void *priv; u32 flags; @@ -1301,7 +1309,8 @@ enum ieee80211_ampdu_mlme_action { * is disabled. This should turn off the hardware (at least * it must turn off frame reception.) * May be called right after add_interface if that rejects - * an interface. + * an interface. If you added any work onto the mac80211 workqueue + * you should ensure to cancel it on this callback. * Must be implemented. * * @add_interface: Called when a netdevice attached to the hardware is @@ -1928,6 +1937,31 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, void *data); /** + * ieee80211_queue_work - add work onto the mac80211 workqueue + * + * Drivers and mac80211 use this to add work onto the mac80211 workqueue. + * This helper ensures drivers are not queueing work when they should not be. + * + * @hw: the hardware struct for the interface we are adding work for + * @work: the work we want to add onto the mac80211 workqueue + */ +void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work); + +/** + * ieee80211_queue_delayed_work - add work onto the mac80211 workqueue + * + * Drivers and mac80211 use this to queue delayed work onto the mac80211 + * workqueue. + * + * @hw: the hardware struct for the interface we are adding work for + * @dwork: delayable work to queue onto the mac80211 workqueue + * @delay: number of jiffies to wait before queueing + */ +void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, + struct delayed_work *dwork, + unsigned long delay); + +/** * ieee80211_start_tx_ba_session - Start a tx Block Ack session. * @hw: pointer as obtained from ieee80211_alloc_hw(). * @ra: receiver address of the BA session recipient diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 6e3cca6..920ec87 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -781,7 +781,7 @@ static void ieee80211_ibss_timer(unsigned long data) } set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); - queue_work(local->hw.workqueue, &ifibss->work); + ieee80211_queue_work(&local->hw, &ifibss->work); } #ifdef CONFIG_PM @@ -853,7 +853,7 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) case IEEE80211_STYPE_PROBE_REQ: case IEEE80211_STYPE_AUTH: skb_queue_tail(&sdata->u.ibss.skb_queue, skb); - queue_work(local->hw.workqueue, &sdata->u.ibss.work); + ieee80211_queue_work(&local->hw, &sdata->u.ibss.work); return RX_QUEUED; } @@ -912,7 +912,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_idle(sdata->local); set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); - queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work); + ieee80211_queue_work(&sdata->local->hw, &sdata->u.ibss.work); return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index aec6853..316825b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -614,6 +614,12 @@ struct ieee80211_local { const struct ieee80211_ops *ops; + /* + * private workqueue to mac80211. mac80211 makes this accessible + * via ieee80211_queue_work() + */ + struct workqueue_struct *workqueue; + unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ spinlock_t queue_stop_reason_lock; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index a83087f..8c1284d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -312,7 +312,7 @@ static int ieee80211_open(struct net_device *dev) * to fix this. */ if (sdata->vif.type == NL80211_IFTYPE_STATION) - queue_work(local->hw.workqueue, &sdata->u.mgd.work); + ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); netif_tx_start_all_queues(dev); @@ -551,7 +551,7 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_led_radio(local, false); - flush_workqueue(local->hw.workqueue); + flush_workqueue(local->workqueue); tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5e76dd1..22e0738 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -821,9 +821,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (hw->queues > IEEE80211_MAX_QUEUES) hw->queues = IEEE80211_MAX_QUEUES; - local->hw.workqueue = + local->workqueue = create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); - if (!local->hw.workqueue) { + if (!local->workqueue) { result = -ENOMEM; goto fail_workqueue; } @@ -913,7 +913,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) sta_info_stop(local); fail_sta_info: debugfs_hw_del(local); - destroy_workqueue(local->hw.workqueue); + destroy_workqueue(local->workqueue); fail_workqueue: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: @@ -955,7 +955,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) skb_queue_purge(&local->skb_queue); skb_queue_purge(&local->skb_queue_unreliable); - destroy_workqueue(local->hw.workqueue); + destroy_workqueue(local->workqueue); wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); ieee80211_led_exit(local); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9a38269..2f4f518 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -54,7 +54,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) return; } - queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); } /** @@ -357,7 +357,7 @@ static void ieee80211_mesh_path_timer(unsigned long data) return; } - queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); } struct mesh_table *mesh_table_grow(struct mesh_table *tbl) @@ -471,7 +471,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; ifmsh->housekeeping = true; - queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED); } @@ -619,7 +619,7 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) if (ieee80211_vif_is_mesh(&sdata->vif)) - queue_work(local->hw.workqueue, &sdata->u.mesh.work); + ieee80211_queue_work(local->hw.workqueue, &sdata->u.mesh.work); rcu_read_unlock(); } @@ -692,7 +692,7 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: skb_queue_tail(&ifmsh->skb_queue, skb); - queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); return RX_QUEUED; } diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index e93c37e..11ab71a 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -660,14 +660,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) spin_unlock(&ifmsh->mesh_preq_queue_lock); if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) - queue_work(sdata->local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); else if (time_before(jiffies, ifmsh->last_preq)) { /* avoid long wait if did not send preqs for a long time * and jiffies wrapped around */ ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; - queue_work(sdata->local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); } else mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + min_preq_int_jiff(sdata)); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ee83125..0779ba1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -565,7 +565,7 @@ static void ieee80211_chswitch_timer(unsigned long data) return; } - queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); + ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); } void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, @@ -597,7 +597,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, sdata->local->csa_channel = new_ch; if (sw_elem->count <= 1) { - queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); + ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); } else { ieee80211_stop_queues_by_reason(&sdata->local->hw, IEEE80211_QUEUE_STOP_REASON_CSA); @@ -763,7 +763,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data) if (local->quiescing || local->suspended) return; - queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); + ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work); } /* MLME */ @@ -950,7 +950,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, * due to work needing to be done. Hence, queue the STAs work * again for that. */ - queue_work(local->hw.workqueue, &ifmgd->work); + ieee80211_queue_work(&local->hw, &ifmgd->work); return RX_MGMT_CFG80211_AUTH_TO; } @@ -995,7 +995,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, * due to work needing to be done. Hence, queue the STAs work * again for that. */ - queue_work(local->hw.workqueue, &ifmgd->work); + ieee80211_queue_work(&local->hw, &ifmgd->work); return RX_MGMT_CFG80211_AUTH_TO; } @@ -1124,7 +1124,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata, * due to work needing to be done. Hence, queue the STAs work * again for that. */ - queue_work(local->hw.workqueue, &ifmgd->work); + ieee80211_queue_work(&local->hw, &ifmgd->work); return RX_MGMT_CFG80211_ASSOC_TO; } @@ -1232,8 +1232,7 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); - queue_work(sdata->local->hw.workqueue, - &sdata->u.mgd.beacon_loss_work); + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); } EXPORT_SYMBOL(ieee80211_beacon_loss); @@ -1888,7 +1887,7 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, case IEEE80211_STYPE_DISASSOC: case IEEE80211_STYPE_ACTION: skb_queue_tail(&sdata->u.mgd.skb_queue, skb); - queue_work(local->hw.workqueue, &sdata->u.mgd.work); + ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); return RX_QUEUED; } @@ -2026,7 +2025,7 @@ static void ieee80211_sta_timer(unsigned long data) return; } - queue_work(local->hw.workqueue, &ifmgd->work); + ieee80211_queue_work(&local->hw, &ifmgd->work); } static void ieee80211_sta_work(struct work_struct *work) @@ -2051,13 +2050,11 @@ static void ieee80211_sta_work(struct work_struct *work) return; /* - * Nothing should have been stuffed into the workqueue during - * the suspend->resume cycle. If this WARN is seen then there - * is a bug with either the driver suspend or something in - * mac80211 stuffing into the workqueue which we haven't yet - * cleared during mac80211's suspend cycle. + * ieee80211_queue_work() should have picked up most cases, + * here we'll pick the the rest. */ - if (WARN_ON(local->suspended)) + if (WARN(local->suspended, "STA MLME work scheduled while " + "going to suspend\n")) return; ifmgd = &sdata->u.mgd; @@ -2113,9 +2110,9 @@ static void ieee80211_sta_work(struct work_struct *work) mutex_unlock(&ifmgd->mtx); if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) - queue_delayed_work(local->hw.workqueue, - &local->scan_work, - round_jiffies_relative(0)); + ieee80211_queue_delayed_work(&local->hw, + &local->scan_work, + round_jiffies_relative(0)); return; } @@ -2196,8 +2193,7 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) if (local->quiescing) return; - queue_work(sdata->local->hw.workqueue, - &sdata->u.mgd.beacon_loss_work); + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); } static void ieee80211_sta_conn_mon_timer(unsigned long data) @@ -2210,7 +2206,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data) if (local->quiescing) return; - queue_work(local->hw.workqueue, &ifmgd->monitor_work); + ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); } static void ieee80211_sta_monitor_work(struct work_struct *work) @@ -2229,10 +2225,10 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) IEEE80211_STA_CONNECTION_POLL); /* let's probe the connection once */ - queue_work(sdata->local->hw.workqueue, + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.monitor_work); /* and do all the other regular work too */ - queue_work(sdata->local->hw.workqueue, + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); } } @@ -2393,7 +2389,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, list_add(&wk->list, &sdata->u.mgd.work_list); mutex_unlock(&ifmgd->mtx); - queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); return 0; } @@ -2467,7 +2463,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, else ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; - queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); err = 0; diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 3320f7d..a5d2f1f 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -26,7 +26,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) /* make quiescing visible to timers everywhere */ mb(); - flush_workqueue(local->hw.workqueue); + flush_workqueue(local->workqueue); /* Don't try to run timers while suspended. */ del_timer_sync(&local->sta_cleanup); @@ -117,7 +117,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) * shouldn't be doing (or cancel everything in the * stop callback) that but better safe than sorry. */ - flush_workqueue(local->hw.workqueue); + flush_workqueue(local->workqueue); local->suspended = true; /* need suspended to be visible before quiescing is false */ diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 4573100..244f53f 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -385,8 +385,9 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) spin_unlock_bh(&local->filter_lock); /* TODO: start scan as soon as all nullfunc frames are ACKed */ - queue_delayed_work(local->hw.workqueue, &local->scan_work, - IEEE80211_CHANNEL_TIME); + ieee80211_queue_delayed_work(&local->hw, + &local->scan_work, + IEEE80211_CHANNEL_TIME); return 0; } @@ -715,8 +716,7 @@ void ieee80211_scan_work(struct work_struct *work) } } while (next_delay == 0); - queue_delayed_work(local->hw.workqueue, &local->scan_work, - next_delay); + ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); } int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 4e1b2ba..7cffaa0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1400,7 +1400,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_QUEUE_STOP_REASON_PS); - queue_work(local->hw.workqueue, + ieee80211_queue_work(&local->hw, &local->dynamic_ps_disable_work); } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 8502936..e55d57f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -511,6 +511,46 @@ void ieee80211_iterate_active_interfaces_atomic( } EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); +/* + * Nothing should have been stuffed into the workqueue during + * the suspend->resume cycle. If this WARN is seen then there + * is a bug with either the driver suspend or something in + * mac80211 stuffing into the workqueue which we haven't yet + * cleared during mac80211's suspend cycle. + */ +static bool ieee80211_can_queue_work(struct ieee80211_local *local) +{ + if (WARN(local->suspended, "queueing ieee80211 work while " + "going to suspend\n")) + return false; + + return true; +} + +void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (!ieee80211_can_queue_work(local)) + return; + + queue_work(local->workqueue, work); +} +EXPORT_SYMBOL(ieee80211_queue_work); + +void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, + struct delayed_work *dwork, + unsigned long delay) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (!ieee80211_can_queue_work(local)) + return; + + queue_delayed_work(local->workqueue, dwork, delay); +} +EXPORT_SYMBOL(ieee80211_queue_delayed_work); + void ieee802_11_parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems) { @@ -1114,3 +1154,4 @@ int ieee80211_reconfig(struct ieee80211_local *local) #endif return 0; } + -- cgit v0.10.2 From e46ab7f0886143846d8da2ca06c2b0e245f34dc6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Jul 2009 11:58:16 +0200 Subject: iwlwifi: don't export symbols not needed in other modules Even with the split into iwlcore/agn/3945 not all symbols that cross file boundaries are needed in other modules, a few are only used within iwlcore, for example. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8570d56..1b5180f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1140,7 +1140,6 @@ void iwl_set_flags_for_band(struct iwl_priv *priv, priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; } } -EXPORT_SYMBOL(iwl_set_flags_for_band); /* * initialize rxon structure with default values from eeprom @@ -2291,7 +2290,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) return iwl_send_cmd(priv, &cmd); } -EXPORT_SYMBOL(iwl_send_card_state); void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) @@ -2335,7 +2333,6 @@ void iwl_clear_isr_stats(struct iwl_priv *priv) { memset(&priv->isr_stats, 0, sizeof(priv->isr_stats)); } -EXPORT_SYMBOL(iwl_clear_isr_stats); int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 7cce8f8..3d61cb4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -335,7 +335,6 @@ void iwl_leds_background(struct iwl_priv *priv) priv->last_blink_time = jiffies; priv->last_blink_rate = blink_idx; } -EXPORT_SYMBOL(iwl_leds_background); /* Register all led handler */ int iwl_leds_register(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 5d5f215..e002c8b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -406,7 +406,6 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) rxq->free_count = 0; spin_unlock_irqrestore(&rxq->lock, flags); } -EXPORT_SYMBOL(iwl_rx_queue_reset); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 79ea5cc..efcae0d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -464,7 +464,6 @@ out: spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; } -EXPORT_SYMBOL(iwl_remove_station); /** * iwl_clear_stations_table - Clear the driver's station table -- cgit v0.10.2 From e40cbdac0629402a4cb0c3bca0cc19ab7a00e00d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Jul 2009 14:04:01 +0200 Subject: cfg80211: fix NETDEV_UNREGISTER notifier It's possible to get the NETDEV_UNREGISTER callback multiple times (see net/core/dev.c:netdev_wait_allrefs) and this will completely mess up our cleanup code. To avoid that, clean up only when the interface is still on the wiphy interface list from which it's removed on the first NETDEV_UNREGISTER call. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 755cdf1..1493285 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -725,15 +725,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; case NETDEV_UNREGISTER: mutex_lock(&rdev->devlist_mtx); + /* + * It is possible to get NETDEV_UNREGISTER + * multiple times. To detect that, check + * that the interface is still on the list + * of registered interfaces, and only then + * remove and clean it up. + */ if (!list_empty(&wdev->list)) { sysfs_remove_link(&dev->dev.kobj, "phy80211"); list_del_init(&wdev->list); - } - mutex_unlock(&rdev->devlist_mtx); - mutex_destroy(&wdev->mtx); + mutex_destroy(&wdev->mtx); #ifdef CONFIG_WIRELESS_EXT - kfree(wdev->wext.keys); + kfree(wdev->wext.keys); #endif + } + mutex_unlock(&rdev->devlist_mtx); break; case NETDEV_PRE_UP: if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) -- cgit v0.10.2 From 1487cd5e76337555737cbc55d7d83f41460d198f Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:20 +0300 Subject: usbnet: allow "minidriver" to prevent urb unlinking on usbnet_stop rndis_wlan devices freeze after running usbnet_stop several times. It appears that firmware freezes in state where it does not respond to any RNDIS commands and device have to be physically unplugged/replugged. This patch lets minidrivers to disable unlink_urbs on usbnet_stop through new info flag. Signed-off-by: Jussi Kivilinna Cc: David Brownell Signed-off-by: John W. Linville diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 25e435c..af1fe46 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -601,21 +601,25 @@ int usbnet_stop (struct net_device *net) info->description); } - // ensure there are no more active urbs - add_wait_queue (&unlink_wakeup, &wait); - dev->wait = &unlink_wakeup; - temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq); - - // maybe wait for deletions to finish. - while (!skb_queue_empty(&dev->rxq) - && !skb_queue_empty(&dev->txq) - && !skb_queue_empty(&dev->done)) { - msleep(UNLINK_TIMEOUT_MS); - if (netif_msg_ifdown (dev)) - devdbg (dev, "waited for %d urb completions", temp); + if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { + /* ensure there are no more active urbs */ + add_wait_queue(&unlink_wakeup, &wait); + dev->wait = &unlink_wakeup; + temp = unlink_urbs(dev, &dev->txq) + + unlink_urbs(dev, &dev->rxq); + + /* maybe wait for deletions to finish. */ + while (!skb_queue_empty(&dev->rxq) + && !skb_queue_empty(&dev->txq) + && !skb_queue_empty(&dev->done)) { + msleep(UNLINK_TIMEOUT_MS); + if (netif_msg_ifdown(dev)) + devdbg(dev, "waited for %d urb completions", + temp); + } + dev->wait = NULL; + remove_wait_queue(&unlink_wakeup, &wait); } - dev->wait = NULL; - remove_wait_queue (&unlink_wakeup, &wait); usb_kill_urb(dev->interrupt); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 09c0702..76c5ec6 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2513,7 +2513,8 @@ static int rndis_wlan_stop(struct usbnet *usbdev) static const struct driver_info bcm4320b_info = { .description = "Wireless RNDIS device, BCM4320b based", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | + FLAG_AVOID_UNLINK_URBS, .bind = rndis_wlan_bind, .unbind = rndis_wlan_unbind, .status = rndis_status, @@ -2527,7 +2528,8 @@ static const struct driver_info bcm4320b_info = { static const struct driver_info bcm4320a_info = { .description = "Wireless RNDIS device, BCM4320a based", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | + FLAG_AVOID_UNLINK_URBS, .bind = rndis_wlan_bind, .unbind = rndis_wlan_unbind, .status = rndis_status, @@ -2541,7 +2543,8 @@ static const struct driver_info bcm4320a_info = { static const struct driver_info rndis_wlan_info = { .description = "Wireless RNDIS device", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | + FLAG_AVOID_UNLINK_URBS, .bind = rndis_wlan_bind, .unbind = rndis_wlan_unbind, .status = rndis_status, diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 7c17b2e..c642f78 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -86,6 +86,7 @@ struct driver_info { #define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ #define FLAG_WLAN 0x0080 /* use "wlan%d" names */ +#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */ /* init device ... can sleep, or cause probe() failure */ -- cgit v0.10.2 From 110736de938b5bfdd63c86166e355d3f16115f6a Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:26 +0300 Subject: rndis_wlan: stop workers on rndis_wlan_stop() and restore on rndis_wlan_reset() Driver doesn't need to poll statistics/link status when stopped. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 76c5ec6..3c7c620 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2457,9 +2457,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) disassociate(usbdev, 1); netif_carrier_off(usbdev->net); - queue_delayed_work(priv->workqueue, &priv->stats_work, - round_jiffies_relative(STATS_UPDATE_JIFFIES)); - return 0; fail: @@ -2499,15 +2496,33 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) static int rndis_wlan_reset(struct usbnet *usbdev) { + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + devdbg(usbdev, "rndis_wlan_reset"); + + queue_delayed_work(priv->workqueue, &priv->stats_work, + round_jiffies_relative(STATS_UPDATE_JIFFIES)); + return deauthenticate(usbdev); } static int rndis_wlan_stop(struct usbnet *usbdev) { + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + int retval; + devdbg(usbdev, "rndis_wlan_stop"); - return disassociate(usbdev, 0); + + retval = disassociate(usbdev, 0); + + priv->work_pending = 0; + cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->scan_work); + cancel_work_sync(&priv->work); + flush_workqueue(priv->workqueue); + + return retval; } -- cgit v0.10.2 From 005ba2f17e68b4da6a2c2c01c826294beac50415 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:31 +0300 Subject: rndis_wlan: clear cfg80211 scan on rndis_wlan_stop() Scanning gets stuck if device is stopped when scan is active. Fix by clearing/aborting cfg80211 scan on rndis_wlan_stop(). Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 3c7c620..dee0551 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1484,6 +1484,9 @@ static void rndis_get_scan_results(struct work_struct *work) devdbg(usbdev, "get_scan_results"); + if (!priv->scan_request) + return; + ret = rndis_check_bssid_list(usbdev); cfg80211_scan_done(priv->scan_request, ret < 0); @@ -2522,6 +2525,11 @@ static int rndis_wlan_stop(struct usbnet *usbdev) cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); + if (priv->scan_request) { + cfg80211_scan_done(priv->scan_request, true); + priv->scan_request = NULL; + } + return retval; } -- cgit v0.10.2 From 7eaab7086c3a313d76c217f98bc610c523d9bc2c Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:37 +0300 Subject: rndis_wlan: reset device and restore multicast list on rndis_wlan_reset() Reset device properly with RNDIS_MSG_RESET in rndis_wlan_reset() and restore multicast list afterwards. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index dee0551..bfb9861 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -594,6 +594,28 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) } +static int rndis_reset(struct usbnet *usbdev) +{ + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct rndis_reset *reset; + int ret; + + mutex_lock(&priv->command_lock); + + reset = (void *)priv->command_buffer; + memset(reset, 0, sizeof(*reset)); + reset->msg_type = RNDIS_MSG_RESET; + reset->msg_len = cpu_to_le32(sizeof(*reset)); + ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE); + + mutex_unlock(&priv->command_lock); + + if (ret < 0) + return ret; + return 0; +} + + /* * Specs say that we can only set config parameters only soon after device * initialization. @@ -2500,9 +2522,17 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) static int rndis_wlan_reset(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + int retval; devdbg(usbdev, "rndis_wlan_reset"); + retval = rndis_reset(usbdev); + if (retval) + devwarn(usbdev, "rndis_reset() failed: %d", retval); + + /* rndis_reset cleared multicast list, so restore here. */ + set_multicast_list(usbdev); + queue_delayed_work(priv->workqueue, &priv->stats_work, round_jiffies_relative(STATS_UPDATE_JIFFIES)); -- cgit v0.10.2 From e5a11a822e1758b05b987e3a5041ef1029aa6cec Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:42 +0300 Subject: rndis_wlan: set current packet filter to zero on stop Set current packet filter to zero to block receiving data packets from device. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index bfb9861..974f724 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2530,7 +2530,8 @@ static int rndis_wlan_reset(struct usbnet *usbdev) if (retval) devwarn(usbdev, "rndis_reset() failed: %d", retval); - /* rndis_reset cleared multicast list, so restore here. */ + /* rndis_reset cleared multicast list, so restore here. + (set_multicast_list() also turns on current packet filter) */ set_multicast_list(usbdev); queue_delayed_work(priv->workqueue, &priv->stats_work, @@ -2544,6 +2545,7 @@ static int rndis_wlan_stop(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int retval; + __le32 filter; devdbg(usbdev, "rndis_wlan_stop"); @@ -2560,6 +2562,12 @@ static int rndis_wlan_stop(struct usbnet *usbdev) priv->scan_request = NULL; } + /* Set current packet filter zero to block receiving data packets from + device. */ + filter = 0; + rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter, + sizeof(filter)); + return retval; } -- cgit v0.10.2 From 27b7b5c131a1df6701a96e10d1056de8e3b15aa9 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:47 +0300 Subject: rndis_wlan: add rndis_set/query_oid debugging Add better debugging for failed OID queries. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 974f724..f6dcbb1 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -100,7 +100,6 @@ MODULE_PARM_DESC(workaround_interval, #define OID_GEN_RCV_ERROR cpu_to_le32(0x00020104) #define OID_GEN_RCV_NO_BUFFER cpu_to_le32(0x00020105) -#define OID_802_3_PERMANENT_ADDRESS cpu_to_le32(0x01010101) #define OID_802_3_CURRENT_ADDRESS cpu_to_le32(0x01010102) #define OID_802_3_MULTICAST_LIST cpu_to_le32(0x01010103) #define OID_802_3_MAXIMUM_LIST_SIZE cpu_to_le32(0x01010104) @@ -478,6 +477,68 @@ static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) } +#ifdef DEBUG +static const char *oid_to_string(__le32 oid) +{ + switch (oid) { +#define OID_STR(oid) case oid: return(#oid) + /* from rndis_host.h */ + OID_STR(OID_802_3_PERMANENT_ADDRESS); + OID_STR(OID_GEN_MAXIMUM_FRAME_SIZE); + OID_STR(OID_GEN_CURRENT_PACKET_FILTER); + OID_STR(OID_GEN_PHYSICAL_MEDIUM); + + /* from rndis_wlan.c */ + OID_STR(OID_GEN_LINK_SPEED); + OID_STR(OID_GEN_RNDIS_CONFIG_PARAMETER); + + OID_STR(OID_GEN_XMIT_OK); + OID_STR(OID_GEN_RCV_OK); + OID_STR(OID_GEN_XMIT_ERROR); + OID_STR(OID_GEN_RCV_ERROR); + OID_STR(OID_GEN_RCV_NO_BUFFER); + + OID_STR(OID_802_3_CURRENT_ADDRESS); + OID_STR(OID_802_3_MULTICAST_LIST); + OID_STR(OID_802_3_MAXIMUM_LIST_SIZE); + + OID_STR(OID_802_11_BSSID); + OID_STR(OID_802_11_SSID); + OID_STR(OID_802_11_INFRASTRUCTURE_MODE); + OID_STR(OID_802_11_ADD_WEP); + OID_STR(OID_802_11_REMOVE_WEP); + OID_STR(OID_802_11_DISASSOCIATE); + OID_STR(OID_802_11_AUTHENTICATION_MODE); + OID_STR(OID_802_11_PRIVACY_FILTER); + OID_STR(OID_802_11_BSSID_LIST_SCAN); + OID_STR(OID_802_11_ENCRYPTION_STATUS); + OID_STR(OID_802_11_ADD_KEY); + OID_STR(OID_802_11_REMOVE_KEY); + OID_STR(OID_802_11_ASSOCIATION_INFORMATION); + OID_STR(OID_802_11_PMKID); + OID_STR(OID_802_11_NETWORK_TYPES_SUPPORTED); + OID_STR(OID_802_11_NETWORK_TYPE_IN_USE); + OID_STR(OID_802_11_TX_POWER_LEVEL); + OID_STR(OID_802_11_RSSI); + OID_STR(OID_802_11_RSSI_TRIGGER); + OID_STR(OID_802_11_FRAGMENTATION_THRESHOLD); + OID_STR(OID_802_11_RTS_THRESHOLD); + OID_STR(OID_802_11_SUPPORTED_RATES); + OID_STR(OID_802_11_CONFIGURATION); + OID_STR(OID_802_11_BSSID_LIST); +#undef OID_STR + } + + return "?"; +} +#else +static const char *oid_to_string(__le32 oid) +{ + return "?"; +} +#endif + + /* translate error code */ static int rndis_error_status(__le32 rndis_status) { @@ -533,11 +594,21 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) u.get->oid = oid; ret = rndis_command(dev, u.header, buflen); + if (ret < 0) + devdbg(dev, "rndis_query_oid(%s): rndis_command() failed, %d " + "(%08x)", oid_to_string(oid), ret, + le32_to_cpu(u.get_c->status)); + if (ret == 0) { ret = le32_to_cpu(u.get_c->len); *len = (*len > ret) ? ret : *len; memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len); ret = rndis_error_status(u.get_c->status); + + if (ret < 0) + devdbg(dev, "rndis_query_oid(%s): device returned " + "error, 0x%08x (%d)", oid_to_string(oid), + le32_to_cpu(u.get_c->status), ret); } mutex_unlock(&priv->command_lock); @@ -583,9 +654,20 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) memcpy(u.buf + sizeof(*u.set), data, len); ret = rndis_command(dev, u.header, buflen); - if (ret == 0) + if (ret < 0) + devdbg(dev, "rndis_set_oid(%s): rndis_command() failed, %d " + "(%08x)", oid_to_string(oid), ret, + le32_to_cpu(u.set_c->status)); + + if (ret == 0) { ret = rndis_error_status(u.set_c->status); + if (ret < 0) + devdbg(dev, "rndis_set_oid(%s): device returned error, " + "0x%08x (%d)", oid_to_string(oid), + le32_to_cpu(u.set_c->status), ret); + } + mutex_unlock(&priv->command_lock); if (u.buf != priv->command_buffer) -- cgit v0.10.2 From 2a4901bcbe9c122bd56e1f6c337fcb4ad75fafb7 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:52 +0300 Subject: rndis_host: allow rndis_wlan to see all indications Allow rndis_wlan to see all indications. Currently rndis_host lets rndis_wlan to know about link state changes only, but there is whole set of other 802.11-specific indications that rndis_wlan should handle properly. So rename link_change() to indication() and convert rndis_wlan to use it. Signed-off-by: Jussi Kivilinna Cc: David Brownell Signed-off-by: John W. Linville diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 2232232..d032bba 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -65,6 +65,32 @@ void rndis_status(struct usbnet *dev, struct urb *urb) EXPORT_SYMBOL_GPL(rndis_status); /* + * RNDIS indicate messages. + */ +static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, + int buflen) +{ + struct cdc_state *info = (void *)&dev->data; + struct device *udev = &info->control->dev; + + if (dev->driver_info->indication) { + dev->driver_info->indication(dev, msg, buflen); + } else { + switch (msg->status) { + case RNDIS_STATUS_MEDIA_CONNECT: + dev_info(udev, "rndis media connect\n"); + break; + case RNDIS_STATUS_MEDIA_DISCONNECT: + dev_info(udev, "rndis media disconnect\n"); + break; + default: + dev_info(udev, "rndis indication: 0x%08x\n", + le32_to_cpu(msg->status)); + } + } +} + +/* * RPC done RNDIS-style. Caller guarantees: * - message is properly byteswapped * - there's no other request pending @@ -143,27 +169,9 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) request_id, xid); /* then likely retry */ } else switch (buf->msg_type) { - case RNDIS_MSG_INDICATE: { /* fault/event */ - struct rndis_indicate *msg = (void *)buf; - int state = 0; - - switch (msg->status) { - case RNDIS_STATUS_MEDIA_CONNECT: - state = 1; - case RNDIS_STATUS_MEDIA_DISCONNECT: - dev_info(&info->control->dev, - "rndis media %sconnect\n", - !state?"dis":""); - if (dev->driver_info->link_change) - dev->driver_info->link_change( - dev, state); - break; - default: - dev_info(&info->control->dev, - "rndis indication: 0x%08x\n", - le32_to_cpu(msg->status)); - } - } + case RNDIS_MSG_INDICATE: /* fault/event */ + rndis_msg_indicate(dev, (void *)buf, buflen); + break; case RNDIS_MSG_KEEPALIVE: { /* ping */ struct rndis_keepalive_c *msg = (void *)buf; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index f6dcbb1..6b6452b 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2211,13 +2211,32 @@ static void rndis_wlan_set_multicast_list(struct net_device *dev) queue_work(priv->workqueue, &priv->work); } -static void rndis_wlan_link_change(struct usbnet *usbdev, int state) +static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct rndis_indicate *msg = ind; /* queue work to avoid recursive calls into rndis_command */ - set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); + switch (msg->status) { + case RNDIS_STATUS_MEDIA_CONNECT: + devinfo(usbdev, "media connect"); + + set_bit(WORK_LINK_UP, &priv->work_pending); + queue_work(priv->workqueue, &priv->work); + break; + + case RNDIS_STATUS_MEDIA_DISCONNECT: + devinfo(usbdev, "media disconnect"); + + set_bit(WORK_LINK_DOWN, &priv->work_pending); + queue_work(priv->workqueue, &priv->work); + break; + + default: + devinfo(usbdev, "indication: 0x%08x", + le32_to_cpu(msg->status)); + break; + } } @@ -2666,7 +2685,7 @@ static const struct driver_info bcm4320b_info = { .reset = rndis_wlan_reset, .stop = rndis_wlan_stop, .early_init = bcm4320b_early_init, - .link_change = rndis_wlan_link_change, + .indication = rndis_wlan_indication, }; static const struct driver_info bcm4320a_info = { @@ -2681,7 +2700,7 @@ static const struct driver_info bcm4320a_info = { .reset = rndis_wlan_reset, .stop = rndis_wlan_stop, .early_init = bcm4320a_early_init, - .link_change = rndis_wlan_link_change, + .indication = rndis_wlan_indication, }; static const struct driver_info rndis_wlan_info = { @@ -2696,7 +2715,7 @@ static const struct driver_info rndis_wlan_info = { .reset = rndis_wlan_reset, .stop = rndis_wlan_stop, .early_init = bcm4320a_early_init, - .link_change = rndis_wlan_link_change, + .indication = rndis_wlan_indication, }; /*-------------------------------------------------------------------------*/ diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index c642f78..de8b4b1 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -122,9 +122,8 @@ struct driver_info { * right after minidriver have initialized hardware. */ int (*early_init)(struct usbnet *dev); - /* called by minidriver when link state changes, state: 0=disconnect, - * 1=connect */ - void (*link_change)(struct usbnet *dev, int state); + /* called by minidriver when receiving indication */ + void (*indication)(struct usbnet *dev, void *ind, int indlen); /* for new devices, use the descriptor-reading code instead */ int in; /* rx endpoint */ -- cgit v0.10.2 From 030645aceb3d9f10b1c3d2231c50f5a8bb3a9667 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:58 +0300 Subject: rndis_wlan: handle 802.11 indications from device Add handling for 802.11 specific rndis indications. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 6b6452b..7a50cfa 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -201,6 +201,24 @@ enum ndis_80211_priv_filter { NDIS_80211_PRIV_8021X_WEP }; +enum ndis_80211_status_type { + NDIS_80211_STATUSTYPE_AUTHENTICATION, + NDIS_80211_STATUSTYPE_MEDIASTREAMMODE, + NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST, + NDIS_80211_STATUSTYPE_RADIOSTATE, +}; + +enum ndis_80211_media_stream_mode { + NDIS_80211_MEDIA_STREAM_OFF, + NDIS_80211_MEDIA_STREAM_ON +}; + +enum ndis_80211_radio_status { + NDIS_80211_RADIO_STATUS_ON, + NDIS_80211_RADIO_STATUS_HARDWARE_OFF, + NDIS_80211_RADIO_STATUS_SOFTWARE_OFF, +}; + enum ndis_80211_addkey_bits { NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28), NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29), @@ -213,6 +231,35 @@ enum ndis_80211_addwep_bits { NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31) }; +struct ndis_80211_auth_request { + __le32 length; + u8 bssid[6]; + u8 padding[2]; + __le32 flags; +} __attribute__((packed)); + +struct ndis_80211_pmkid_candidate { + u8 bssid[6]; + u8 padding[2]; + __le32 flags; +} __attribute__((packed)); + +struct ndis_80211_pmkid_cand_list { + __le32 version; + __le32 num_candidates; + struct ndis_80211_pmkid_candidate candidate_list[0]; +} __attribute__((packed)); + +struct ndis_80211_status_indication { + __le32 status_type; + union { + enum ndis_80211_media_stream_mode media_stream_mode; + enum ndis_80211_radio_status radio_status; + struct ndis_80211_auth_request auth_request[0]; + struct ndis_80211_pmkid_cand_list cand_list; + } u; +} __attribute__((packed)); + struct ndis_80211_ssid { __le32 length; u8 essid[NDIS_802_11_LENGTH_SSID]; @@ -2211,16 +2258,195 @@ static void rndis_wlan_set_multicast_list(struct net_device *dev) queue_work(priv->workqueue, &priv->work); } + +static void rndis_wlan_auth_indication(struct usbnet *usbdev, + struct ndis_80211_status_indication *indication, + int len) +{ + u8 *buf; + const char *type; + int flags, buflen; + bool pairwise_error, group_error; + struct ndis_80211_auth_request *auth_req; + + /* must have at least one array entry */ + if (len < offsetof(struct ndis_80211_status_indication, u) + + sizeof(struct ndis_80211_auth_request)) { + devinfo(usbdev, "authentication indication: " + "too short message (%i)", len); + return; + } + + buf = (void *)&indication->u.auth_request[0]; + buflen = len - offsetof(struct ndis_80211_status_indication, u); + + while (buflen >= sizeof(*auth_req)) { + auth_req = (void *)buf; + type = "unknown"; + flags = le32_to_cpu(auth_req->flags); + pairwise_error = false; + group_error = false; + + if (flags & 0x1) + type = "reauth request"; + if (flags & 0x2) + type = "key update request"; + if (flags & 0x6) { + pairwise_error = true; + type = "pairwise_error"; + } + if (flags & 0xe) { + group_error = true; + type = "group_error"; + } + + devinfo(usbdev, "authentication indication: %s (0x%08x)", type, + le32_to_cpu(auth_req->flags)); + + if (pairwise_error || group_error) { + union iwreq_data wrqu; + struct iw_michaelmicfailure micfailure; + + memset(&micfailure, 0, sizeof(micfailure)); + if (pairwise_error) + micfailure.flags |= IW_MICFAILURE_PAIRWISE; + if (group_error) + micfailure.flags |= IW_MICFAILURE_GROUP; + + memcpy(micfailure.src_addr.sa_data, auth_req->bssid, + ETH_ALEN); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(micfailure); + wireless_send_event(usbdev->net, IWEVMICHAELMICFAILURE, + &wrqu, (u8 *)&micfailure); + } + + buflen -= le32_to_cpu(auth_req->length); + buf += le32_to_cpu(auth_req->length); + } +} + +static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, + struct ndis_80211_status_indication *indication, + int len) +{ + struct ndis_80211_pmkid_cand_list *cand_list; + int list_len, expected_len, i; + + if (len < offsetof(struct ndis_80211_status_indication, u) + + sizeof(struct ndis_80211_pmkid_cand_list)) { + devinfo(usbdev, "pmkid candidate list indication: " + "too short message (%i)", len); + return; + } + + list_len = le32_to_cpu(indication->u.cand_list.num_candidates) * + sizeof(struct ndis_80211_pmkid_candidate); + expected_len = sizeof(struct ndis_80211_pmkid_cand_list) + list_len + + offsetof(struct ndis_80211_status_indication, u); + + if (len < expected_len) { + devinfo(usbdev, "pmkid candidate list indication: " + "list larger than buffer (%i < %i)", + len, expected_len); + return; + } + + cand_list = &indication->u.cand_list; + + devinfo(usbdev, "pmkid candidate list indication: " + "version %i, candidates %i", + le32_to_cpu(cand_list->version), + le32_to_cpu(cand_list->num_candidates)); + + if (le32_to_cpu(cand_list->version) != 1) + return; + + for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) { + struct iw_pmkid_cand pcand; + union iwreq_data wrqu; + struct ndis_80211_pmkid_candidate *cand = + &cand_list->candidate_list[i]; + + devdbg(usbdev, "cand[%i]: flags: 0x%08x, bssid: %pM", + i, le32_to_cpu(cand->flags), cand->bssid); + + memset(&pcand, 0, sizeof(pcand)); + if (le32_to_cpu(cand->flags) & 0x01) + pcand.flags |= IW_PMKID_CAND_PREAUTH; + pcand.index = i; + memcpy(pcand.bssid.sa_data, cand->bssid, ETH_ALEN); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(pcand); + wireless_send_event(usbdev->net, IWEVPMKIDCAND, &wrqu, + (u8 *)&pcand); + } +} + +static void rndis_wlan_media_specific_indication(struct usbnet *usbdev, + struct rndis_indicate *msg, int buflen) +{ + struct ndis_80211_status_indication *indication; + int len, offset; + + offset = offsetof(struct rndis_indicate, status) + + le32_to_cpu(msg->offset); + len = le32_to_cpu(msg->length); + + if (len < 8) { + devinfo(usbdev, "media specific indication, " + "ignore too short message (%i < 8)", len); + return; + } + + if (offset + len > buflen) { + devinfo(usbdev, "media specific indication, " + "too large to fit to buffer (%i > %i)", + offset + len, buflen); + return; + } + + indication = (void *)((u8 *)msg + offset); + + switch (le32_to_cpu(indication->status_type)) { + case NDIS_80211_STATUSTYPE_RADIOSTATE: + devinfo(usbdev, "radio state indication: %i", + le32_to_cpu(indication->u.radio_status)); + return; + + case NDIS_80211_STATUSTYPE_MEDIASTREAMMODE: + devinfo(usbdev, "media stream mode indication: %i", + le32_to_cpu(indication->u.media_stream_mode)); + return; + + case NDIS_80211_STATUSTYPE_AUTHENTICATION: + rndis_wlan_auth_indication(usbdev, indication, len); + return; + + case NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST: + rndis_wlan_pmkid_cand_list_indication(usbdev, indication, len); + return; + + default: + devinfo(usbdev, "media specific indication: " + "unknown status type 0x%08x", + le32_to_cpu(indication->status_type)); + } +} + + static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct rndis_indicate *msg = ind; - /* queue work to avoid recursive calls into rndis_command */ switch (msg->status) { case RNDIS_STATUS_MEDIA_CONNECT: devinfo(usbdev, "media connect"); + /* queue work to avoid recursive calls into rndis_command */ set_bit(WORK_LINK_UP, &priv->work_pending); queue_work(priv->workqueue, &priv->work); break; @@ -2228,10 +2454,15 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) case RNDIS_STATUS_MEDIA_DISCONNECT: devinfo(usbdev, "media disconnect"); + /* queue work to avoid recursive calls into rndis_command */ set_bit(WORK_LINK_DOWN, &priv->work_pending); queue_work(priv->workqueue, &priv->work); break; + case RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION: + rndis_wlan_media_specific_indication(usbdev, msg, buflen); + break; + default: devinfo(usbdev, "indication: 0x%08x", le32_to_cpu(msg->status)); diff --git a/include/linux/usb/rndis_host.h b/include/linux/usb/rndis_host.h index 37836b9..1ef1ebc 100644 --- a/include/linux/usb/rndis_host.h +++ b/include/linux/usb/rndis_host.h @@ -70,12 +70,13 @@ struct rndis_msg_hdr { #define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION) /* codes for "status" field of completion messages */ -#define RNDIS_STATUS_SUCCESS cpu_to_le32(0x00000000) -#define RNDIS_STATUS_FAILURE cpu_to_le32(0xc0000001) -#define RNDIS_STATUS_INVALID_DATA cpu_to_le32(0xc0010015) -#define RNDIS_STATUS_NOT_SUPPORTED cpu_to_le32(0xc00000bb) -#define RNDIS_STATUS_MEDIA_CONNECT cpu_to_le32(0x4001000b) -#define RNDIS_STATUS_MEDIA_DISCONNECT cpu_to_le32(0x4001000c) +#define RNDIS_STATUS_SUCCESS cpu_to_le32(0x00000000) +#define RNDIS_STATUS_FAILURE cpu_to_le32(0xc0000001) +#define RNDIS_STATUS_INVALID_DATA cpu_to_le32(0xc0010015) +#define RNDIS_STATUS_NOT_SUPPORTED cpu_to_le32(0xc00000bb) +#define RNDIS_STATUS_MEDIA_CONNECT cpu_to_le32(0x4001000b) +#define RNDIS_STATUS_MEDIA_DISCONNECT cpu_to_le32(0x4001000c) +#define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION cpu_to_le32(0x40010012) /* codes for OID_GEN_PHYSICAL_MEDIUM */ #define RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED cpu_to_le32(0x00000000) -- cgit v0.10.2 From 9d40934e5e28314731d4b32acd2fdf5fb805a3ed Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:42:03 +0300 Subject: rndis_wlan: add missing padding to struct rndis_80211_remove_key OID_802_11_REMOVE_KEY failed with invalid length error, add missing padding to structure fix this. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 7a50cfa..3d92b77 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -327,6 +327,7 @@ struct ndis_80211_remove_key { __le32 size; __le32 index; u8 bssid[6]; + u8 padding[2]; } __attribute__((packed)); struct ndis_config_param { -- cgit v0.10.2 From b7cfc5b35eed2fe8a5c45793e6e52ef0edddc824 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:42:08 +0300 Subject: rndis_wlan: rework key handling Organize key data in private structure better and store WPA keys, so they can be restored as WEP keys. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 3d92b77..828dc18 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -413,6 +413,15 @@ static const struct ieee80211_rate rndis_rates[] = { { .bitrate = 540 } }; +struct rndis_wlan_encr_key { + int len; + int cipher; + u8 material[32]; + u8 bssid[ETH_ALEN]; + bool pairwise; + bool tx_key; +}; + /* RNDIS device private data */ struct rndis_wlan_private { struct usbnet *usbdev; @@ -456,9 +465,7 @@ struct rndis_wlan_private { /* encryption stuff */ int encr_tx_key_index; - char encr_keys[4][32]; - int encr_key_len[4]; - char encr_key_wpa[4]; + struct rndis_wlan_encr_key encr_keys[4]; int wpa_version; int wpa_keymgmt; int wpa_authalg; @@ -525,6 +532,15 @@ static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) } +static bool is_wpa_key(struct rndis_wlan_private *priv, int idx) +{ + int cipher = priv->encr_keys[idx].cipher; + + return (cipher == WLAN_CIPHER_SUITE_CCMP || + cipher == WLAN_CIPHER_SUITE_TKIP); +} + + #ifdef DEBUG static const char *oid_to_string(__le32 oid) { @@ -895,8 +911,7 @@ static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig) /* * common functions */ -static int -add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index); +static void restore_keys(struct usbnet *usbdev); static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { @@ -1115,7 +1130,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; - int ret, i; + int ret; devdbg(usbdev, "set_infra_mode: infra_mode=0x%x", priv->infra_mode); @@ -1130,14 +1145,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) /* NDIS drivers clear keys when infrastructure mode is * changed. But Linux tools assume otherwise. So set the * keys */ - if (priv->wpa_keymgmt == 0 || - priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) { - for (i = 0; i < 4; i++) { - if (priv->encr_key_len[i] > 0 && !priv->encr_key_wpa[i]) - add_wep_key(usbdev, priv->encr_keys[i], - priv->encr_key_len[i], i); - } - } + restore_keys(usbdev); priv->infra_mode = mode; return 0; @@ -1204,11 +1212,16 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_wep_key ndis_key; - int ret; + int cipher, ret; - if (key_len <= 0 || key_len > 32 || index < 0 || index >= 4) + if ((key_len != 5 || key_len != 13) || index < 0 || index > 3) return -EINVAL; + if (key_len == 5) + cipher = WLAN_CIPHER_SUITE_WEP40; + else + cipher = WLAN_CIPHER_SUITE_WEP104; + memset(&ndis_key, 0, sizeof(ndis_key)); ndis_key.size = cpu_to_le32(sizeof(ndis_key)); @@ -1233,30 +1246,44 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) return ret; } - priv->encr_key_len[index] = key_len; - priv->encr_key_wpa[index] = 0; - memcpy(&priv->encr_keys[index], key, key_len); + priv->encr_keys[index].len = key_len; + priv->encr_keys[index].cipher = cipher; + memcpy(&priv->encr_keys[index].material, key, key_len); + memset(&priv->encr_keys[index].bssid, 0xff, ETH_ALEN); return 0; } static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, - int index, const struct sockaddr *addr, - const u8 *rx_seq, int alg, int flags) + int index, const u8 *addr, const u8 *rx_seq, int cipher, + int flags) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_key ndis_key; + bool is_addr_ok; int ret; - if (index < 0 || index >= 4) + if (index < 0 || index >= 4) { + devdbg(usbdev, "add_wpa_key: index out of range (%i)", index); return -EINVAL; - if (key_len > sizeof(ndis_key.material) || key_len < 0) + } + if (key_len > sizeof(ndis_key.material) || key_len < 0) { + devdbg(usbdev, "add_wpa_key: key length out of range (%i)", + key_len); return -EINVAL; - if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) + } + if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) { + devdbg(usbdev, "add_wpa_key: recv seq flag without buffer"); return -EINVAL; - if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !addr) + } + is_addr_ok = addr && memcmp(addr, zero_bssid, ETH_ALEN) != 0 && + memcmp(addr, ffff_bssid, ETH_ALEN) != 0; + if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) { + devdbg(usbdev, "add_wpa_key: pairwise but bssid invalid (%pM)", + addr); return -EINVAL; + } devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index, !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY), @@ -1270,7 +1297,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, ndis_key.length = cpu_to_le32(key_len); ndis_key.index = cpu_to_le32(index) | flags; - if (alg == IW_ENCODE_ALG_TKIP && key_len == 32) { + if (cipher == WLAN_CIPHER_SUITE_TKIP && key_len == 32) { /* wpa_supplicant gives us the Michael MIC RX/TX keys in * different order than NDIS spec, so swap the order here. */ memcpy(ndis_key.material, key, 16); @@ -1284,7 +1311,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) { /* pairwise key */ - memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN); + memcpy(ndis_key.bssid, addr, ETH_ALEN); } else { /* group key */ if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) @@ -1299,8 +1326,14 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, if (ret != 0) return ret; - priv->encr_key_len[index] = key_len; - priv->encr_key_wpa[index] = 1; + memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); + priv->encr_keys[index].len = key_len; + priv->encr_keys[index].cipher = cipher; + memcpy(&priv->encr_keys[index].material, key, key_len); + if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) + memcpy(&priv->encr_keys[index].bssid, ndis_key.bssid, ETH_ALEN); + else + memset(&priv->encr_keys[index].bssid, 0xff, ETH_ALEN); if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY) priv->encr_tx_key_index = index; @@ -1309,25 +1342,74 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, } +static int restore_key(struct usbnet *usbdev, int key_idx) +{ + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct rndis_wlan_encr_key key; + int flags; + + key = priv->encr_keys[key_idx]; + + devdbg(usbdev, "restore_key: %i:%s:%i", key_idx, + is_wpa_key(priv, key_idx) ? "wpa" : "wep", + key.len); + + if (key.len == 0) + return 0; + + if (is_wpa_key(priv, key_idx)) { + flags = 0; + + /*if (priv->encr_tx_key_index == key_idx) + flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;*/ + + if (memcmp(key.bssid, zero_bssid, ETH_ALEN) != 0 && + memcmp(key.bssid, ffff_bssid, ETH_ALEN) != 0) + flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; + + return add_wpa_key(usbdev, key.material, key.len, key_idx, + key.bssid, NULL, key.cipher, flags); + } + + return add_wep_key(usbdev, key.material, key.len, key_idx); +} + + +static void restore_keys(struct usbnet *usbdev) +{ + int i; + + for (i = 0; i < 4; i++) + restore_key(usbdev, i); +} + + +static void clear_key(struct rndis_wlan_private *priv, int idx) +{ + memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx])); +} + + /* remove_key is for both wep and wpa */ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_remove_key remove_key; __le32 keyindex; + bool is_wpa; int ret; - if (priv->encr_key_len[index] == 0) + if (priv->encr_keys[index].len == 0) return 0; - priv->encr_key_len[index] = 0; - priv->encr_key_wpa[index] = 0; - memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); + is_wpa = is_wpa_key(priv, index); - if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP || - priv->wpa_cipher_pair == IW_AUTH_CIPHER_CCMP || - priv->wpa_cipher_group == IW_AUTH_CIPHER_TKIP || - priv->wpa_cipher_group == IW_AUTH_CIPHER_CCMP) { + devdbg(usbdev, "remove_key: %i:%s:%i", index, is_wpa ? "wpa" : "wep", + priv->encr_keys[index].len); + + clear_key(priv, index); + + if (is_wpa) { remove_key.size = cpu_to_le32(sizeof(remove_key)); remove_key.index = cpu_to_le32(index); if (bssid) { @@ -1871,8 +1953,9 @@ static int rndis_iw_set_encode(struct net_device *dev, { struct usbnet *usbdev = netdev_priv(dev); struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct rndis_wlan_encr_key key; int ret, index, key_len; - u8 *key; + u8 *keybuf; index = (wrqu->encoding.flags & IW_ENCODE_INDEX); @@ -1907,17 +1990,18 @@ static int rndis_iw_set_encode(struct net_device *dev, if (wrqu->data.length > 0) { key_len = wrqu->data.length; - key = extra; + keybuf = extra; } else { /* must be set as tx key */ - if (priv->encr_key_len[index] == 0) + if (priv->encr_keys[index].len == 0) return -EINVAL; - key_len = priv->encr_key_len[index]; key = priv->encr_keys[index]; + key_len = key.len; + keybuf = key.material; priv->encr_tx_key_index = index; } - if (add_wep_key(usbdev, key, key_len, index) != 0) + if (add_wep_key(usbdev, keybuf, key_len, index) != 0) return -EINVAL; if (index == priv->encr_tx_key_index) @@ -1934,7 +2018,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct usbnet *usbdev = netdev_priv(dev); struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int keyidx, flags; + int keyidx, flags, cipher; keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; @@ -1944,8 +2028,10 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, else keyidx = priv->encr_tx_key_index; - if (keyidx < 0 || keyidx >= 4) + if (keyidx < 0 || keyidx >= 4) { + devwarn(usbdev, "encryption index out of range (%u)", keyidx); return -EINVAL; + } if (ext->alg == WPA_ALG_WEP) { if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) @@ -1953,10 +2039,19 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, return add_wep_key(usbdev, ext->key, ext->key_len, keyidx); } + cipher = -1; + if (ext->alg == IW_ENCODE_ALG_TKIP) + cipher = WLAN_CIPHER_SUITE_TKIP; + else if (ext->alg == IW_ENCODE_ALG_CCMP) + cipher = WLAN_CIPHER_SUITE_CCMP; + if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) return remove_key(usbdev, keyidx, NULL); + if (cipher == -1) + return -EOPNOTSUPP; + flags = 0; if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; @@ -1965,8 +2060,9 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY; - return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr, - ext->rx_seq, ext->alg, flags); + return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, + (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher, + flags); } -- cgit v0.10.2 From 056508dcb6890586745aa937e779f00fde05531b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Jul 2009 21:43:55 +0200 Subject: mac80211: fix powersave Some of the recent MLME rework I did broke powersave because the ps_sdata isn't assigned at the right time, and the work item wasn't removed from the list before calling ieee80211_recalc_ps(). To be more specific, this broke the case where you'd enabled PS before associating, either automatically or with iwconfig. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0779ba1..2d5edfd 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -916,12 +916,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_bss_info_change_notify(sdata, bss_info_changed); - /* will be same as sdata */ - if (local->ps_sdata) { - mutex_lock(&local->iflist_mtx); - ieee80211_recalc_ps(local, -1); - mutex_unlock(&local->iflist_mtx); - } + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); netif_tx_start_all_queues(sdata->dev); netif_carrier_on(sdata->dev); @@ -1569,6 +1566,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, wk->bss->cbss.bssid, ap_ht_cap_flags); + /* delete work item -- must be before set_associated for PS */ + list_del(&wk->list); + /* set AID and assoc capability, * ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; @@ -1582,7 +1582,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); mod_beacon_timer(sdata); - list_del(&wk->list); kfree(wk); return RX_MGMT_CFG80211_ASSOC; } -- cgit v0.10.2 From 9828b0170eef541c3fa583caa0134dadbb1d3ea6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 30 Jul 2009 17:38:06 -0700 Subject: cfg80211: use goto out on country IE reg hint failure This has no functional changes. Acked-by: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index fb40428..2d1d183 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1774,10 +1774,8 @@ void regulatory_hint_11d(struct wiphy *wiphy, mutex_lock(&cfg80211_mutex); - if (unlikely(!last_request)) { - mutex_unlock(&cfg80211_mutex); - return; - } + if (unlikely(!last_request)) + goto out; /* IE len must be evenly divisible by 2 */ if (country_ie_len & 0x01) -- cgit v0.10.2 From 4b44c8bc4d077f1a7a9e5e946a1400c3cbcadee7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 30 Jul 2009 17:38:07 -0700 Subject: cfg80211: do not iterate over rdev list on country IE hint Simplify the country IE hint code by just bailing out if a previous country IE has been issued. We currently just trust the first AP we connect to on any card. The idea was to perform conflict resolution within this routine but since we can no longer iterate over the registered device list here we leave conflict resolution to be dealt with at a later time on the workqueue. This code has no functional changes other than saving us an interation over the registered device list when a second card is connected, or you unplug and connect the same one, and a country IE is received. This would have been done upon every beacon received. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2d1d183..f386981 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1762,6 +1762,10 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, return false; } +/* + * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and + * therefore cannot iterate over the rdev list here. + */ void regulatory_hint_11d(struct wiphy *wiphy, u8 *country_ie, u8 country_ie_len) @@ -1804,51 +1808,14 @@ void regulatory_hint_11d(struct wiphy *wiphy, * We will run this for *every* beacon processed for the BSSID, so * we optimize an early check to exit out early if we don't have to * do anything + * + * We leave conflict resolution to the workqueue, where can hold + * cfg80211_mutex. */ if (likely(last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && - wiphy_idx_valid(last_request->wiphy_idx))) { - struct cfg80211_registered_device *rdev_last_ie; - - rdev_last_ie = - cfg80211_rdev_by_wiphy_idx(last_request->wiphy_idx); - - /* - * Lets keep this simple -- we trust the first AP - * after we intersect with CRDA - */ - if (likely(&rdev_last_ie->wiphy == wiphy)) { - /* - * Ignore IEs coming in on this wiphy with - * the same alpha2 and environment cap - */ - if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2, - alpha2) && - env == rdev_last_ie->env)) { - goto out; - } - /* - * the wiphy moved on to another BSSID or the AP - * was reconfigured. XXX: We need to deal with the - * case where the user suspends and goes to goes - * to another country, and then gets IEs from an - * AP with different settings - */ - goto out; - } else { - /* - * Ignore IEs coming in on two separate wiphys with - * the same alpha2 and environment cap - */ - if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2, - alpha2) && - env == rdev_last_ie->env)) { - goto out; - } - /* We could potentially intersect though */ - goto out; - } - } + wiphy_idx_valid(last_request->wiphy_idx))) + goto out; rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); if (!rd) -- cgit v0.10.2 From abc7381bcca6ce9dc101f112a13e14957bfbda7e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 30 Jul 2009 17:38:08 -0700 Subject: cfg80211: decouple regulatory variables from cfg80211_mutex We change regulatory code to be protected by its own regulatory mutex and alleviate cfg80211_mutex to only be used to protect cfg80211_rdev_list, the registered device list. By doing this we will be able to work on regulatory core components without having to have hog up the cfg80211_mutex. An example here is we no longer need to use the cfg80211_mutex during driver specific wiphy_apply_custom_regulatory(). We also no longer need it for the the country IE regulatory hint; by doing so we end up curing this new lockdep warning: ======================================================= [ INFO: possible circular locking dependency detected ] 2.6.31-rc4-wl #12 ------------------------------------------------------- phy1/1709 is trying to acquire lock: (cfg80211_mutex){+.+.+.}, at: [] regulatory_hint_11d+0x32/0x3f0 [cfg80211] but task is already holding lock: (&ifmgd->mtx){+.+.+.}, at: [] ieee80211_sta_work+0x108/0x10f0 [mac80211] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #3 (&ifmgd->mtx){+.+.+.}: [] __lock_acquire+0xd76/0x12b0 [] lock_acquire+0xe3/0x120 [] mutex_lock_nested+0x44/0x350 [] ieee80211_mgd_auth+0x108/0x1f0 [mac80211] [] ieee80211_auth+0x13/0x20 [mac80211] [] __cfg80211_mlme_auth+0x1b1/0x2a0 [cfg80211] [] cfg80211_mlme_auth+0x86/0xc0 [cfg80211] [] nl80211_authenticate+0x21d/0x230 [cfg80211] [] genl_rcv_msg+0x1b6/0x1f0 [] netlink_rcv_skb+0x89/0xb0 [] genl_rcv+0x29/0x40 [] netlink_unicast+0x29d/0x2b0 [] netlink_sendmsg+0x214/0x300 [] sock_sendmsg+0x107/0x130 [] sys_sendmsg+0x189/0x320 [] system_call_fastpath+0x16/0x1b [] 0xffffffffffffffff -> #2 (&wdev->mtx){+.+.+.}: [] __lock_acquire+0xd76/0x12b0 [] lock_acquire+0xe3/0x120 [] mutex_lock_nested+0x44/0x350 [] cfg80211_netdev_notifier_call+0x1a4/0x390 [cfg80211] [] notifier_call_chain+0x3f/0x80 [] raw_notifier_call_chain+0x11/0x20 [] dev_open+0x10a/0x120 [] dev_change_flags+0x9d/0x1e0 [] devinet_ioctl+0x6fe/0x760 [] inet_ioctl+0x94/0xc0 [] sock_ioctl+0x6a/0x290 [] vfs_ioctl+0x31/0xa0 [] do_vfs_ioctl+0x8a/0x5c0 [] sys_ioctl+0x99/0xa0 [] system_call_fastpath+0x16/0x1b [] 0xffffffffffffffff -> #1 (&rdev->mtx){+.+.+.}: [] __lock_acquire+0xd76/0x12b0 [] lock_acquire+0xe3/0x120 [] mutex_lock_nested+0x44/0x350 [] cfg80211_get_dev_from_ifindex+0x60/0x90 [cfg80211] [] get_rdev_dev_by_info_ifindex+0x6f/0xa0 [cfg80211] [] nl80211_set_interface+0x3b/0x260 [cfg80211] [] genl_rcv_msg+0x1b6/0x1f0 [] netlink_rcv_skb+0x89/0xb0 [] genl_rcv+0x29/0x40 [] netlink_unicast+0x29d/0x2b0 [] netlink_sendmsg+0x214/0x300 [] sock_sendmsg+0x107/0x130 [] sys_sendmsg+0x189/0x320 [] system_call_fastpath+0x16/0x1b [] 0xffffffffffffffff other info that might help us debug this: 3 locks held by phy1/1709: #0: ((wiphy_name(local->hw.wiphy))){+.+.+.}, at: [] worker_thread+0x19d/0x340 #1: (&ifmgd->work){+.+.+.}, at: [] worker_thread+0x19d/0x340 #2: (&ifmgd->mtx){+.+.+.}, at: [] ieee80211_sta_work+0x108/0x10f0 [mac80211] Reported-by: Reinette Chatre Acked-by: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 1493285..cd7dff9 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -34,9 +34,7 @@ MODULE_DESCRIPTION("wireless configuration support"); LIST_HEAD(cfg80211_rdev_list); /* - * This is used to protect the cfg80211_rdev_list, cfg80211_regdomain, - * country_ie_regdomain, the reg_beacon_list and the the last regulatory - * request receipt (last_request). + * This is used to protect the cfg80211_rdev_list */ DEFINE_MUTEX(cfg80211_mutex); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f386981..6ab56f0 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -62,6 +62,16 @@ const struct ieee80211_regdomain *cfg80211_regdomain; */ static const struct ieee80211_regdomain *country_ie_regdomain; +/* + * Protects static reg.c components: + * - cfg80211_world_regdom + * - cfg80211_regdom + * - country_ie_regdomain + * - last_request + */ +DEFINE_MUTEX(reg_mutex); +#define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) + /* Used to queue up regulatory hints */ static LIST_HEAD(reg_requests_list); static spinlock_t reg_requests_lock; @@ -1293,7 +1303,7 @@ static void handle_channel_custom(struct wiphy *wiphy, struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; - assert_cfg80211_lock(); + assert_reg_lock(); sband = wiphy->bands[band]; BUG_ON(chan_idx >= sband->n_channels); @@ -1342,14 +1352,14 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, enum ieee80211_band band; unsigned int bands_set = 0; - mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (!wiphy->bands[band]) continue; handle_band_custom(wiphy, band, regd); bands_set++; } - mutex_unlock(&cfg80211_mutex); + mutex_unlock(®_mutex); /* * no point in calling this if it won't have any effect @@ -1495,7 +1505,7 @@ static int ignore_request(struct wiphy *wiphy, * Returns zero if all went fine, %-EALREADY if a regulatory domain had * already been set or other standard error codes. * - * Caller must hold &cfg80211_mutex + * Caller must hold &cfg80211_mutex and ®_mutex */ static int __regulatory_hint(struct wiphy *wiphy, struct regulatory_request *pending_request) @@ -1570,6 +1580,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) BUG_ON(!reg_request->alpha2); mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); if (wiphy_idx_valid(reg_request->wiphy_idx)) wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); @@ -1585,6 +1596,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) if (r == -EALREADY && wiphy && wiphy->strict_regulatory) wiphy_update_regulatory(wiphy, reg_request->initiator); out: + mutex_unlock(®_mutex); mutex_unlock(&cfg80211_mutex); } @@ -1613,6 +1625,10 @@ static void reg_process_pending_beacon_hints(void) struct cfg80211_registered_device *rdev; struct reg_beacon *pending_beacon, *tmp; + /* + * No need to hold the reg_mutex here as we just touch wiphys + * and do not read or access regulatory variables. + */ mutex_lock(&cfg80211_mutex); /* This goes through the _pending_ beacon list */ @@ -1734,12 +1750,13 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) } EXPORT_SYMBOL(regulatory_hint); +/* Caller must hold reg_mutex */ static bool reg_same_country_ie_hint(struct wiphy *wiphy, u32 country_ie_checksum) { struct wiphy *request_wiphy; - assert_cfg80211_lock(); + assert_reg_lock(); if (unlikely(last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) @@ -1776,7 +1793,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, enum environment_cap env = ENVIRON_ANY; struct regulatory_request *request; - mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); if (unlikely(!last_request)) goto out; @@ -1850,7 +1867,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, request->country_ie_checksum = checksum; request->country_ie_env = env; - mutex_unlock(&cfg80211_mutex); + mutex_unlock(®_mutex); queue_regulatory_request(request); @@ -1859,7 +1876,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, free_rd_out: kfree(rd); out: - mutex_unlock(&cfg80211_mutex); + mutex_unlock(®_mutex); } EXPORT_SYMBOL(regulatory_hint_11d); @@ -2192,10 +2209,13 @@ int set_regdom(const struct ieee80211_regdomain *rd) assert_cfg80211_lock(); + mutex_lock(®_mutex); + /* Note that this doesn't update the wiphys, this is done below */ r = __set_regdom(rd); if (r) { kfree(rd); + mutex_unlock(®_mutex); return r; } @@ -2210,6 +2230,8 @@ int set_regdom(const struct ieee80211_regdomain *rd) nl80211_send_reg_change_event(last_request); + mutex_unlock(®_mutex); + return r; } @@ -2220,16 +2242,20 @@ void reg_device_remove(struct wiphy *wiphy) assert_cfg80211_lock(); + mutex_lock(®_mutex); + kfree(wiphy->regd); if (last_request) request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); if (!request_wiphy || request_wiphy != wiphy) - return; + goto out; last_request->wiphy_idx = WIPHY_IDX_STALE; last_request->country_ie_env = ENVIRON_ANY; +out: + mutex_unlock(®_mutex); } int regulatory_init(void) @@ -2290,6 +2316,7 @@ void regulatory_exit(void) cancel_work_sync(®_work); mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); reset_regdomains(); @@ -2328,5 +2355,6 @@ void regulatory_exit(void) } spin_unlock(®_requests_lock); + mutex_unlock(®_mutex); mutex_unlock(&cfg80211_mutex); } -- cgit v0.10.2 From 8b19e6ca3bac7e04e93fb73f561d670e77c5fae6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 30 Jul 2009 17:38:09 -0700 Subject: cfg80211: enable country IE support to all cfg80211 drivers Since the bss is always set now once we are connected, if the bss has its own information element we refer to it and pass that instead of relying on mac80211's parsing. Now all cfg80211 drivers get country IE support, automatically and we reduce the call overhead that we had on mac80211 which called this upon every beacon and instead now call this only upon a successfull connection by a STA on cfg80211. Acked-by: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e1b9235..fa72997 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1514,20 +1514,6 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb); extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2); /** - * regulatory_hint_11d - hints a country IE as a regulatory domain - * @wiphy: the wireless device giving the hint (used only for reporting - * conflicts) - * @country_ie: pointer to the country IE - * @country_ie_len: length of the country IE - * - * We will intersect the rd with the what CRDA tells us should apply - * for the alpha2 this country IE belongs to, this prevents APs from - * sending us incorrect or outdated information against a country. - */ -extern void regulatory_hint_11d(struct wiphy *wiphy, - u8 *country_ie, - u8 country_ie_len); -/** * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain * @wiphy: the wireless device we want to process the regulatory domain on * @regd: the custom regulatory domain to use for this wiphy diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2d5edfd..c9e4091 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1845,12 +1845,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, bssid, ap_ht_cap_flags); } + /* Note: country IE parsing is done for us by cfg80211 */ if (elems.country_elem) { - /* Note we are only reviewing this on beacons - * for the BSSID we are associated to */ - regulatory_hint_11d(local->hw.wiphy, - elems.country_elem, elems.country_elem_len); - /* TODO: IBSS also needs this */ if (elems.pwr_constr_elem) ieee80211_handle_pwr_constr(sdata, diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 6ab56f0..b3ac0aa 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1822,10 +1822,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, env = ENVIRON_OUTDOOR; /* - * We will run this for *every* beacon processed for the BSSID, so - * we optimize an early check to exit out early if we don't have to - * do anything - * + * We will run this only upon a successful connection on cfg80211. * We leave conflict resolution to the workqueue, where can hold * cfg80211_mutex. */ @@ -1878,7 +1875,6 @@ free_rd_out: out: mutex_unlock(®_mutex); } -EXPORT_SYMBOL(regulatory_hint_11d); static bool freq_is_chan_12_13_14(u16 freq) { diff --git a/net/wireless/reg.h b/net/wireless/reg.h index e37829a..662a9da 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -36,4 +36,19 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, struct ieee80211_channel *beacon_chan, gfp_t gfp); +/** + * regulatory_hint_11d - hints a country IE as a regulatory domain + * @wiphy: the wireless device giving the hint (used only for reporting + * conflicts) + * @country_ie: pointer to the country IE + * @country_ie_len: length of the country IE + * + * We will intersect the rd with the what CRDA tells us should apply + * for the alpha2 this country IE belongs to, this prevents APs from + * sending us incorrect or outdated information against a country. + */ +void regulatory_hint_11d(struct wiphy *wiphy, + u8 *country_ie, + u8 country_ie_len); + #endif /* __NET_WIRELESS_REG_H */ diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 3728d2b..af91192 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -13,6 +13,7 @@ #include #include #include "nl80211.h" +#include "reg.h" struct cfg80211_conn { struct cfg80211_connect_params params; @@ -320,6 +321,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, struct cfg80211_bss *bss) { struct wireless_dev *wdev = dev->ieee80211_ptr; + u8 *country_ie; #ifdef CONFIG_WIRELESS_EXT union iwreq_data wrqu; #endif @@ -401,6 +403,20 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, wdev->sme_state = CFG80211_SME_CONNECTED; cfg80211_upload_connect_keys(wdev); + + country_ie = (u8 *) ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); + + if (!country_ie) + return; + + /* + * ieee80211_bss_get_ie() ensures we can access: + * - country_ie + 2, the start of the country ie data, and + * - and country_ie[1] which is the IE length + */ + regulatory_hint_11d(wdev->wiphy, + country_ie + 2, + country_ie[1]); } void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, -- cgit v0.10.2 From 97cad51e191919b43aabdc85b83241b66c3fcf2c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 30 Jul 2009 21:37:27 -0400 Subject: iwlwifi: remove usage of orig_flags This is a private flag, internal to cfg80211. cfg80211 will set orig_* stuff internally upon wiphy registration, drivers do not need to muck with it. Signed-off-by: Luis R. Rodriguez Acked-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1b5180f..6797076 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -548,9 +548,6 @@ int iwlcore_init_geos(struct iwl_priv *priv) geo_ch->flags |= IEEE80211_CHAN_DISABLED; } - /* Save flags for reg domain usage */ - geo_ch->orig_flags = geo_ch->flags; - IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n", ch->channel, geo_ch->center_freq, is_channel_a_band(ch) ? "5.2" : "2.4", -- cgit v0.10.2 From 75e6c3b72b3ab01c47629f3fbd0fed4e6550bf3a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Jul 2009 11:18:13 +0200 Subject: cfg80211: lower dynamic PS timeout to 100ms The default of 500ms is pretty high, and leads to the device being awake at least 50% of the time under such light traffic conditions as a simple 1 second interval ping. Reduce to just 100ms -- it should have a similar effect while providing a better sleep time. Signed-off-by: Johannes Berg Reviewed-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index cd7dff9..1e18930 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -671,7 +671,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev->wext.default_mgmt_key = -1; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE; - wdev->wext.ps_timeout = 500; + wdev->wext.ps_timeout = 100; if (rdev->ops->set_power_mgmt) if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->wext.ps, -- cgit v0.10.2 From a43abf293965230c93a4b74e5d10b9d60b153ab4 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Fri, 31 Jul 2009 18:54:12 +0300 Subject: mac80211: Retry probe request few times Retry 5 times (chosen arbitary ), before assuming that station is out of range. Fixes frequent disassociations while connected to weak, and sometimes even strong access points. Signed-off-by: Maxim Levitky Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 316825b..8d790e4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -280,6 +280,7 @@ struct ieee80211_if_managed { struct work_struct beacon_loss_work; unsigned long probe_timeout; + int probe_send_count; struct mutex mtx; struct ieee80211_bss *associated; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c9e4091..ccd5c7a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -31,6 +31,7 @@ #define IEEE80211_AUTH_MAX_TRIES 3 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_ASSOC_MAX_TRIES 3 +#define IEEE80211_MAX_PROBE_TRIES 5 /* * beacon loss detection timeout @@ -1153,11 +1154,24 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); } +static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + const u8 *ssid; + + ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); + ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, + ssid + 2, ssid[1], NULL, 0); + + ifmgd->probe_send_count++; + ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; + run_again(ifmgd, ifmgd->probe_timeout); +} + static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, bool beacon) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - const u8 *ssid; bool already = false; if (!netif_running(sdata->dev)) @@ -1200,18 +1214,12 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, if (already) goto out; - ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; - mutex_lock(&sdata->local->iflist_mtx); ieee80211_recalc_ps(sdata->local, -1); mutex_unlock(&sdata->local->iflist_mtx); - ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); - ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, - ssid + 2, ssid[1], NULL, 0); - - run_again(ifmgd, ifmgd->probe_timeout); - + ifmgd->probe_send_count = 0; + ieee80211_mgd_probe_ap_send(sdata); out: mutex_unlock(&ifmgd->mtx); } @@ -2064,17 +2072,27 @@ static void ieee80211_sta_work(struct work_struct *work) if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL) && ifmgd->associated) { + u8 bssid[ETH_ALEN]; + + memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); if (time_is_after_jiffies(ifmgd->probe_timeout)) run_again(ifmgd, ifmgd->probe_timeout); - else { - u8 bssid[ETH_ALEN]; + + else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "No probe response from AP %pM" + " after %dms, try %d\n", bssid, + (1000 * IEEE80211_PROBE_WAIT)/HZ, + ifmgd->probe_send_count); +#endif + ieee80211_mgd_probe_ap_send(sdata); + } else { /* * We actually lost the connection ... or did we? * Let's make sure! */ ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | IEEE80211_STA_BEACON_POLL); - memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); printk(KERN_DEBUG "No probe response from AP %pM" " after %dms, disconnecting.\n", bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); -- cgit v0.10.2 From d1c5091f23fed5195271e2849f89017d3a126521 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Fri, 31 Jul 2009 18:54:23 +0300 Subject: mac80211: Increase timeouts for station polling Do a probe request every 30 seconds, and wait for probe response, half a second This should lower the traffic that card sends, thus save power Wainting longer for response makes probe more robust against 'slow' access points Signed-off-by: Maxim Levitsky Acked-by: Johannes Berg Tested-by: Marcel Holtmann Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ccd5c7a..6d5a1ee 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -42,13 +42,13 @@ * Time the connection can be idle before we probe * it to see if we can still talk to the AP. */ -#define IEEE80211_CONNECTION_IDLE_TIME (2 * HZ) +#define IEEE80211_CONNECTION_IDLE_TIME (30 * HZ) /* * Time we wait for a probe response after sending * a probe request because of beacon loss or for * checking the connection still works. */ -#define IEEE80211_PROBE_WAIT (HZ / 5) +#define IEEE80211_PROBE_WAIT (HZ / 2) #define TMR_RUNNING_TIMER 0 #define TMR_RUNNING_CHANSW 1 -- cgit v0.10.2 From 88d89526a671ba008f59456161b0c513cdfb5d5a Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Fri, 31 Jul 2009 11:35:19 -0700 Subject: libertas: check valid bits in SPI bus mode reg The SPI driver writes to the bus mode register and performs a sanity check by reading back what we wrote, however only the lower four bits of that register are defined. In some cases, the device side seems to set the higher bits, causing us to fail the sanity check unnecessarily. Check only the lower four bits instead. Thanks to John Goyette from Schick Technologies for pointing out the problem. Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 963c201..446e327 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -376,7 +376,7 @@ static int spu_set_bus_mode(struct if_spi_card *card, u16 mode) err = spu_read_u16(card, IF_SPI_SPU_BUS_MODE_REG, &rval); if (err) return err; - if (rval != mode) { + if ((rval & 0xF) != mode) { lbs_pr_err("Can't read bus mode register.\n"); return -EIO; } -- cgit v0.10.2 From f62ae6cd887a184d6923037d588b5b2466aa2a97 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 31 Jul 2009 20:51:41 +0200 Subject: b43: Fix unaligned 32bit SHM-shared access This fixes unaligned 32bit SHM-shared read/write access. The low and high 16 bits were swapped. It also adds a testcase for this to the chipaccess validation. (Thanks to Albert Herranz for tracking down this bug.) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index f985938..a048de5 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -395,9 +395,8 @@ u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); - ret <<= 16; b43_shm_control_word(dev, routing, (offset >> 2) + 1); - ret |= b43_read16(dev, B43_MMIO_SHM_DATA); + ret |= ((u32)b43_read16(dev, B43_MMIO_SHM_DATA)) << 16; goto out; } @@ -464,9 +463,10 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, - (value >> 16) & 0xffff); + value & 0xFFFF); b43_shm_control_word(dev, routing, (offset >> 2) + 1); - b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); + b43_write16(dev, B43_MMIO_SHM_DATA, + (value >> 16) & 0xFFFF); return; } offset >>= 2; @@ -2931,9 +2931,10 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev) /* Check if communication with the device works correctly. */ static int b43_validate_chipaccess(struct b43_wldev *dev) { - u32 v, backup; + u32 v, backup0, backup4; - backup = b43_shm_read32(dev, B43_SHM_SHARED, 0); + backup0 = b43_shm_read32(dev, B43_SHM_SHARED, 0); + backup4 = b43_shm_read32(dev, B43_SHM_SHARED, 4); /* Check for read/write and endianness problems. */ b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55); @@ -2943,7 +2944,23 @@ static int b43_validate_chipaccess(struct b43_wldev *dev) if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA) goto error; - b43_shm_write32(dev, B43_SHM_SHARED, 0, backup); + /* Check if unaligned 32bit SHM_SHARED access works properly. + * However, don't bail out on failure, because it's noncritical. */ + b43_shm_write16(dev, B43_SHM_SHARED, 0, 0x1122); + b43_shm_write16(dev, B43_SHM_SHARED, 2, 0x3344); + b43_shm_write16(dev, B43_SHM_SHARED, 4, 0x5566); + b43_shm_write16(dev, B43_SHM_SHARED, 6, 0x7788); + if (b43_shm_read32(dev, B43_SHM_SHARED, 2) != 0x55663344) + b43warn(dev->wl, "Unaligned 32bit SHM read access is broken\n"); + b43_shm_write32(dev, B43_SHM_SHARED, 2, 0xAABBCCDD); + if (b43_shm_read16(dev, B43_SHM_SHARED, 0) != 0x1122 || + b43_shm_read16(dev, B43_SHM_SHARED, 2) != 0xCCDD || + b43_shm_read16(dev, B43_SHM_SHARED, 4) != 0xAABB || + b43_shm_read16(dev, B43_SHM_SHARED, 6) != 0x7788) + b43warn(dev->wl, "Unaligned 32bit SHM write access is broken\n"); + + b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0); + b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4); if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) { /* The 32bit register shadows the two 16bit registers -- cgit v0.10.2 From 92ca8d437fdbb482752534885d86af264897da85 Mon Sep 17 00:00:00 2001 From: gregor kowski Date: Fri, 31 Jul 2009 22:35:49 +0200 Subject: b43: remove wrong probe_resp_plcp write The tkip hw support uncovered a bug in b43_write_probe_resp_template : it is writing at the wrong shm offset, it is in the B43_SHM_SH_TKIPTSCTTAK zone. This patch comments these writes. Signed-off-by: Gregor Kowski Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a048de5..925f346 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1524,10 +1524,13 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev, /* Looks like PLCP headers plus packet timings are stored for * all possible basic rates */ + /* FIXME this is the wrong offset : it goes in tkip rx phase1 shm */ +#if 0 b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]); b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]); b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]); b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]); +#endif size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6)); b43_write_template_common(dev, probe_resp_data, -- cgit v0.10.2 From 8ce73f3abd064081706cc337c771378fc4431ef3 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 31 Jul 2009 14:28:06 -0700 Subject: iwlwifi: clear iwl_cmd_meta structure before use Resolve an issue in which out-dated fields in iwl_cmd_meta could be used for later hardware commands. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 6bb9602..288b871 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -970,6 +970,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) out_cmd = txq->cmd[idx]; out_meta = &txq->meta[idx]; + memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ out_meta->flags = cmd->flags; if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; -- cgit v0.10.2 From 65b7998a9be418482493e9448bb83ff2914ed050 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 31 Jul 2009 14:28:07 -0700 Subject: iwlwifi: Distinguish power amplifier for 6000 series For 6x00 2x2 NIC, two types of Power Amplifier are available. In order for uCode to apply correct tx power, driver needs to program the CSR_GP_DRIVER_REG register and let uCode know the type of PA. If driver do not program CSR_GP_DRIVER_REG register (default to 0), then it is uCode's decision for tx power 2x2 Hybrid card: use both internal and external PA 2x2 IPA(Internal Power Amplifier) card: internal PA only Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 5f7c520..cf3fbc6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -73,6 +73,18 @@ static void iwl1000_set_ct_threshold(struct iwl_priv *priv) priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; } +/* NIC configuration for 1000 series */ +static void iwl1000_nic_config(struct iwl_priv *priv) +{ + iwl5000_nic_config(priv); + + /* Setting digital SVR for 1000 card to 1.32V */ + /* locking is acquired in iwl_set_bits_mask_prph() function */ + iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG, + APMG_SVR_DIGITAL_VOLTAGE_1_32, + ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); +} + static struct iwl_lib_ops iwl1000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, @@ -95,7 +107,7 @@ static struct iwl_lib_ops iwl1000_lib = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, .stop = iwl5000_apm_stop, - .config = iwl5000_nic_config, + .config = iwl1000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ddd64fe..87957c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -198,6 +198,7 @@ out: } +/* NIC configuration for 5000 series and up */ void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; @@ -239,18 +240,11 @@ void iwl5000_nic_config(struct iwl_priv *priv) APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); - if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) { - /* Setting digital SVR for 1000 card to 1.32V */ - iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG, - APMG_SVR_DIGITAL_VOLTAGE_1_32, - ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); - } spin_unlock_irqrestore(&priv->lock, flags); } - /* * EEPROM */ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 59ff735..052a704 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -68,6 +68,24 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; } +/* NIC configuration for 6000 series */ +static void iwl6000_nic_config(struct iwl_priv *priv) +{ + iwl5000_nic_config(priv); + + /* no locking required for register write */ + if (priv->cfg->pa_type == IWL_PA_HYBRID) { + /* 2x2 hybrid phy type */ + iwl_write32(priv, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB); + } else if (priv->cfg->pa_type == IWL_PA_INTERNAL) { + /* 2x2 IPA phy type */ + iwl_write32(priv, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); + } + /* else do nothing, uCode configured */ +} + static struct iwl_lib_ops iwl6000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, @@ -90,7 +108,7 @@ static struct iwl_lib_ops iwl6000_lib = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, .stop = iwl5000_apm_stop, - .config = iwl5000_nic_config, + .config = iwl6000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { @@ -146,9 +164,13 @@ struct iwl_cfg iwl6000_2ag_cfg = { .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, .need_pll_cfg = false, + .pa_type = IWL_PA_SYSTEM, }; -struct iwl_cfg iwl6000_2agn_cfg = { +/* + * "h": Hybrid configuration, use both internal and external Power Amplifier + */ +struct iwl_cfg iwl6000h_2agn_cfg = { .name = "6000 Series 2x2 AGN", .fw_name_pre = IWL6000_FW_PRE, .ucode_api_max = IWL6000_UCODE_API_MAX, @@ -162,6 +184,27 @@ struct iwl_cfg iwl6000_2agn_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .need_pll_cfg = false, + .pa_type = IWL_PA_HYBRID, +}; + +/* + * "i": Internal configuration, use internal Power Amplifier + */ +struct iwl_cfg iwl6000i_2agn_cfg = { + .name = "6000 Series 2x2 AGN", + .fw_name_pre = IWL6000_FW_PRE, + .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_min = IWL6000_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl6000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_BC, + .valid_rx_ant = ANT_BC, + .need_pll_cfg = false, + .pa_type = IWL_PA_INTERNAL, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -178,6 +221,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .need_pll_cfg = false, + .pa_type = IWL_PA_SYSTEM, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -194,6 +238,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, + .pa_type = IWL_PA_SYSTEM, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -210,6 +255,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, + .pa_type = IWL_PA_SYSTEM, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4cb1a1b..a54330b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3142,11 +3142,13 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x0082, 0x1102, iwl6000_2ag_cfg)}, {IWL_PCI_DEVICE(0x0085, 0x1112, iwl6000_2ag_cfg)}, {IWL_PCI_DEVICE(0x0082, 0x1122, iwl6000_2ag_cfg)}, + {IWL_PCI_DEVICE(0x008D, PCI_ANY_ID, iwl6000h_2agn_cfg)}, + {IWL_PCI_DEVICE(0x008E, PCI_ANY_ID, iwl6000h_2agn_cfg)}, {IWL_PCI_DEVICE(0x422B, PCI_ANY_ID, iwl6000_3agn_cfg)}, - {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000_2agn_cfg)}, + {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000i_2agn_cfg)}, {IWL_PCI_DEVICE(0x4238, PCI_ANY_ID, iwl6000_3agn_cfg)}, - {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0082, PCI_ANY_ID, iwl6000_2agn_cfg)}, + {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000i_2agn_cfg)}, + {IWL_PCI_DEVICE(0x0082, PCI_ANY_ID, iwl6000h_2agn_cfg)}, {IWL_PCI_DEVICE(0x0085, PCI_ANY_ID, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x0086, PCI_ANY_ID, iwl6050_3agn_cfg)}, {IWL_PCI_DEVICE(0x0087, PCI_ANY_ID, iwl6050_2agn_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index febcf76..10ddcdd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -206,6 +206,7 @@ struct iwl_mod_params { * filename is constructed as fw_name_pre.ucode. * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. + * @pa_type: used by 6000 series only to identify the type of Power Amplifier * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -226,6 +227,7 @@ struct iwl_mod_params { * iwl_hcmd_utils_ops etc. we accommodate different command structures * and flows between hardware versions (4965/5000) as well as their API * versions. + * */ struct iwl_cfg { const char *name; @@ -242,6 +244,7 @@ struct iwl_cfg { u8 valid_rx_ant; bool need_pll_cfg; bool use_isr_legacy; + enum iwl_pa_type pa_type; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index f03dae1..06437d1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -91,7 +91,8 @@ #define CSR_EEPROM_GP (CSR_BASE+0x030) #define CSR_OTP_GP_REG (CSR_BASE+0x034) #define CSR_GIO_REG (CSR_BASE+0x03C) -#define CSR_GP_UCODE (CSR_BASE+0x044) +#define CSR_GP_UCODE_REG (CSR_BASE+0x048) +#define CSR_GP_DRIVER_REG (CSR_BASE+0x050) #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) #define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) @@ -245,6 +246,13 @@ #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) #define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) +/* GP Driver */ +#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_MSK (0x00000003) +#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB (0x00000000) +#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB (0x00000001) +#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002) + + /* GI Chicken Bits */ #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0ee3ad2..335a8f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -57,7 +57,8 @@ extern struct iwl_cfg iwl5100_bg_cfg; extern struct iwl_cfg iwl5100_abg_cfg; extern struct iwl_cfg iwl5150_agn_cfg; extern struct iwl_cfg iwl6000_2ag_cfg; -extern struct iwl_cfg iwl6000_2agn_cfg; +extern struct iwl_cfg iwl6000h_2agn_cfg; +extern struct iwl_cfg iwl6000i_2agn_cfg; extern struct iwl_cfg iwl6000_3agn_cfg; extern struct iwl_cfg iwl6050_2agn_cfg; extern struct iwl_cfg iwl6050_3agn_cfg; @@ -888,6 +889,19 @@ enum iwl_nvm_type { NVM_DEVICE_TYPE_OTP, }; + +/** + * enum iwl_pa_type - Power Amplifier type + * @IWL_PA_SYSTEM: based on uCode configuration + * @IWL_PA_HYBRID: use both Internal and external PA + * @IWL_PA_INTERNAL: use Internal only + */ +enum iwl_pa_type { + IWL_PA_SYSTEM = 0, + IWL_PA_HYBRID = 1, + IWL_PA_INTERNAL = 2, +}; + /* interrupt statistics */ struct isr_statistics { u32 hw; -- cgit v0.10.2 From a11c4d000b84f7f49ebefc018c24bbfa3c9c0f3b Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 31 Jul 2009 14:28:08 -0700 Subject: iwlwifi: remove deprecated 6000 series adapters Remove the support for deprecated devices. These devices are engineering samples and no longer supported by the uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 052a704..4450943 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -150,22 +150,6 @@ static struct iwl_ops iwl6000_ops = { .utils = &iwl6000_hcmd_utils, }; -struct iwl_cfg iwl6000_2ag_cfg = { - .name = "6000 Series 2x2 AG", - .fw_name_pre = IWL6000_FW_PRE, - .ucode_api_max = IWL6000_UCODE_API_MAX, - .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .mod_params = &iwl50_mod_params, - .valid_tx_ant = ANT_BC, - .valid_rx_ant = ANT_BC, - .need_pll_cfg = false, - .pa_type = IWL_PA_SYSTEM, -}; /* * "h": Hybrid configuration, use both internal and external Power Amplifier diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a54330b..467c861 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3139,17 +3139,12 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)}, {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, /* 6000/6050 Series */ - {IWL_PCI_DEVICE(0x0082, 0x1102, iwl6000_2ag_cfg)}, - {IWL_PCI_DEVICE(0x0085, 0x1112, iwl6000_2ag_cfg)}, - {IWL_PCI_DEVICE(0x0082, 0x1122, iwl6000_2ag_cfg)}, {IWL_PCI_DEVICE(0x008D, PCI_ANY_ID, iwl6000h_2agn_cfg)}, {IWL_PCI_DEVICE(0x008E, PCI_ANY_ID, iwl6000h_2agn_cfg)}, {IWL_PCI_DEVICE(0x422B, PCI_ANY_ID, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000i_2agn_cfg)}, {IWL_PCI_DEVICE(0x4238, PCI_ANY_ID, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000i_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0082, PCI_ANY_ID, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0085, PCI_ANY_ID, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x0086, PCI_ANY_ID, iwl6050_3agn_cfg)}, {IWL_PCI_DEVICE(0x0087, PCI_ANY_ID, iwl6050_2agn_cfg)}, {IWL_PCI_DEVICE(0x0088, PCI_ANY_ID, iwl6050_3agn_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 335a8f3..cab6255 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -56,7 +56,6 @@ extern struct iwl_cfg iwl5350_agn_cfg; extern struct iwl_cfg iwl5100_bg_cfg; extern struct iwl_cfg iwl5100_abg_cfg; extern struct iwl_cfg iwl5150_agn_cfg; -extern struct iwl_cfg iwl6000_2ag_cfg; extern struct iwl_cfg iwl6000h_2agn_cfg; extern struct iwl_cfg iwl6000i_2agn_cfg; extern struct iwl_cfg iwl6000_3agn_cfg; -- cgit v0.10.2 From abdc2d62be335b85091e8f74081336563277a163 Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Fri, 31 Jul 2009 14:28:09 -0700 Subject: iwlwifi: remove duplicated version info from sysfs version info in sysfs had been determined to be unnecessary as it is already provided in syslog info. nvm version is added to syslog version info as a debug level message to provide all info that was in the version sysfs data. Signed-off-by: Jay Sternberg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 467c861..db580cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1291,6 +1291,7 @@ static int iwl_read_ucode(struct iwl_priv *priv) size_t len; u32 api_ver, build; u32 inst_size, data_size, init_size, init_data_size, boot_size; + u16 eeprom_ver; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ @@ -1368,6 +1369,11 @@ static int iwl_read_ucode(struct iwl_priv *priv) if (build) IWL_DEBUG_INFO(priv, "Build %u\n", build); + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + IWL_DEBUG_INFO(priv, "NVM Type: %s, version: 0x%x\n", + (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + ? "OTP" : "EEPROM", eeprom_ver); + IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", priv->ucode_ver); IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n", @@ -2483,39 +2489,6 @@ static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, #endif /* CONFIG_IWLWIFI_DEBUG */ -static ssize_t show_version(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct iwl_alive_resp *palive = &priv->card_alive; - ssize_t pos = 0; - u16 eeprom_ver; - - if (palive->is_valid) - pos += sprintf(buf + pos, - "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n" - "fw type: 0x%01X 0x%01X\n", - palive->ucode_major, palive->ucode_minor, - palive->sw_rev[0], palive->sw_rev[1], - palive->ver_type, palive->ver_subtype); - else - pos += sprintf(buf + pos, "fw not loaded\n"); - - if (priv->eeprom) { - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - pos += sprintf(buf + pos, "NVM Type: %s, version: 0x%x\n", - (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) - ? "OTP" : "EEPROM", eeprom_ver); - - } else { - pos += sprintf(buf + pos, "EEPROM not initialzed\n"); - } - - return pos; -} - -static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL); - static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { @@ -2779,7 +2752,6 @@ static struct attribute *iwl_sysfs_entries[] = { #ifdef CONFIG_IWLWIFI_DEBUG &dev_attr_debug_level.attr, #endif - &dev_attr_version.attr, NULL }; -- cgit v0.10.2 From 2c8d51048f6a54aabe2e15278210cb07288e17bb Mon Sep 17 00:00:00 2001 From: Maithili Hinge Date: Fri, 31 Jul 2009 20:02:19 -0700 Subject: libertas: Fix WEP association failure with open source wpa_supplicant 0.5.10 Add code to handle IW_AUTH_PRIVACY_INVOKED and IW_AUTH_RX_UNENCRYPTED_EAPOL cases in lbs_set_auth() function in libertas code. Signed-off-by: Maithili Hinge Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index e96451c..be837a0 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1728,6 +1728,8 @@ static int lbs_set_auth(struct net_device *dev, } switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_PRIVACY_INVOKED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: case IW_AUTH_TKIP_COUNTERMEASURES: case IW_AUTH_CIPHER_PAIRWISE: case IW_AUTH_CIPHER_GROUP: -- cgit v0.10.2 From 87cdb9894b9367237f25e5a4c381eb8e594e782b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 1 Aug 2009 21:50:31 +0200 Subject: drivers/net/wireless: Use DIV_ROUND_CLOSEST The kernel.h macro DIV_ROUND_CLOSEST performs the computation (x + d/2)/d but is perhaps more readable. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @haskernel@ @@ #include @depends on haskernel@ expression x,__divisor; @@ - (((x) + ((__divisor) / 2)) / (__divisor)) + DIV_ROUND_CLOSEST(x,__divisor) // Signed-off-by: Julia Lawall Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 73300c2..ef2cb20 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1550,9 +1550,12 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev) if (time_after(jiffies, strip_info->pps_timer + HZ)) { unsigned long t = jiffies - strip_info->pps_timer; - unsigned long rx_pps_count = (strip_info->rx_pps_count * HZ * 8 + t / 2) / t; - unsigned long tx_pps_count = (strip_info->tx_pps_count * HZ * 8 + t / 2) / t; - unsigned long sx_pps_count = (strip_info->sx_pps_count * HZ * 8 + t / 2) / t; + unsigned long rx_pps_count = + DIV_ROUND_CLOSEST(strip_info->rx_pps_count*HZ*8, t); + unsigned long tx_pps_count = + DIV_ROUND_CLOSEST(strip_info->tx_pps_count*HZ*8, t); + unsigned long sx_pps_count = + DIV_ROUND_CLOSEST(strip_info->sx_pps_count*HZ*8, t); strip_info->pps_timer = jiffies; strip_info->rx_pps_count = 0; -- cgit v0.10.2 From 3ad201496badddd8e1cda87ee6d29e8b3b8e1279 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 2 Aug 2009 02:36:49 +0300 Subject: rfkill: add the GPS radio type Althoug GPS is a technology w/o transmitting radio and thus not a primary candidate for rfkill switch, rfkill gives unified interface point for devices with wireless technology. The input key is not supplied as it is too be deprecated. Cc: johannes@sipsolutions.net Signed-off-by: Tomas Winkler Acked-by: Marcel Holtmann Signed-off-by: John W. Linville diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 1020290..21ca51b 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -47,6 +47,7 @@ enum rfkill_type { RFKILL_TYPE_UWB, RFKILL_TYPE_WIMAX, RFKILL_TYPE_WWAN, + RFKILL_TYPE_GPS, NUM_RFKILL_TYPES, }; diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 044de1c..dbeaf29 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -589,11 +589,13 @@ static const char *rfkill_get_type_str(enum rfkill_type type) return "wimax"; case RFKILL_TYPE_WWAN: return "wwan"; + case RFKILL_TYPE_GPS: + return "gps"; default: BUG(); } - BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_WWAN + 1); + BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_GPS + 1); } static ssize_t rfkill_type_show(struct device *dev, -- cgit v0.10.2 From c1be5152860218dffea6a47cff5ea31a56c6cff5 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 1 Aug 2009 22:32:48 -0500 Subject: b43legacy: Work around mac80211 race condition As shown in http://thread.gmane.org/gmane.linux.kernel.wireless.general/36497, mac80211 has a bug that allows a call to the TX routine after the queues have been stopped. This situation will only occur under extreme stress. Although b43legacy does not crash when this condition occurs, it does generate a WARN_ON and also logs a queue overrun message. This patch recognizes b43legacy is not at fault and logs a message only when the most verbose debugging mode is enabled. In the unlikely event that the queue is not stopped when the DMA queue becomes full, then a warning is issued. This patch is based on the one used by b43. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index 2f90fb9..8664034 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1366,15 +1366,25 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); - if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { - b43legacywarn(dev->wl, "DMA queue overflow\n"); + + if (unlikely(ring->stopped)) { + /* We get here only because of a bug in mac80211. + * Because of a race, one packet may be queued after + * the queue is stopped, thus we got called when we shouldn't. + * For now, just refuse the transmit. */ + if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) + b43legacyerr(dev->wl, "Packet after queue stopped\n"); + err = -ENOSPC; + goto out_unlock; + } + + if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) { + /* If we get here, we have a real error with the queue + * full, but queues not stopped. */ + b43legacyerr(dev->wl, "DMA queue overflow\n"); err = -ENOSPC; goto out_unlock; } - /* Check if the queue was stopped in mac80211, - * but we got called nevertheless. - * That would be a mac80211 bug. */ - B43legacy_BUG_ON(ring->stopped); err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { -- cgit v0.10.2 From 117839bd1251dc654938c529c95c7611ac260351 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Sun, 2 Aug 2009 14:30:02 -0400 Subject: rt61pci: fix module reloading Unloading rt61pci can leave the device in such state that reloading rt61pci would fail to reinitialize it. Bogus data would be read from the EEPROM and the RF version won't be recognized. It appears that unloading rt61pci with power saving enabled would have such effect. To initialize the device properly, SOFT_RESET_CSR should be set to the same value as rt61pci_config_ps() uses to wake up the device. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index fb95b8c..e20dd74 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2601,6 +2601,11 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) int retval; /* + * Disable power saving. + */ + rt2x00pci_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000007); + + /* * Allocate eeprom data. */ retval = rt61pci_validate_eeprom(rt2x00dev); -- cgit v0.10.2 From d8cc8926e9b4dc2ce513ee3325bf16b4ea6d94e8 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Sun, 2 Aug 2009 14:30:15 -0400 Subject: rt2x00: cancel all work on disconnect Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b717afb..db54fcc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -893,6 +893,12 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) rt2x00lib_disable_radio(rt2x00dev); /* + * Stop all work. + */ + cancel_work_sync(&rt2x00dev->filter_work); + cancel_work_sync(&rt2x00dev->intf_work); + + /* * Uninitialize device. */ rt2x00lib_uninitialize(rt2x00dev); -- cgit v0.10.2 From 738f0f4301587ad09b58651390b122205086b484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Mon, 3 Aug 2009 01:28:12 +0200 Subject: b43: implement baseband init for LP-PHY <= rev1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement baseband init for rev.0 and rev.1 LP PHYs. Convert boardflags_hi values to defines. Implement b43_phy_copy for easier copying between registers, as needed by LP-PHY init. Signed-off-by: Gábor Stefanik Cc: Michael Buesch Cc: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 4044806..b6811cf 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -142,6 +142,17 @@ #define B43_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */ #define B43_BFL_ALTIQ 0x8000 /* alternate I/Q settings */ +/* SPROM boardflags_hi values */ +#define B43_BFH_NOPA 0x0001 /* has no PA */ +#define B43_BFH_RSSIINV 0x0002 /* RSSI uses positive slope (not TSSI) */ +#define B43_BFH_PAREF 0x0004 /* uses the PARef LDO */ +#define B43_BFH_3TSWITCH 0x0008 /* uses a triple throw switch shared + * with bluetooth */ +#define B43_BFH_PHASESHIFT 0x0010 /* can support phase shifter */ +#define B43_BFH_BUCKBOOST 0x0020 /* has buck/booster */ +#define B43_BFH_FEM_BT 0x0040 /* has FEM and switch to share antenna + * with bluetooth */ + /* GPIO register offset, in both ChipCommon and PCI core. */ #define B43_GPIO_CONTROL 0x6c diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index f537bfe..51686ec 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -240,6 +240,13 @@ void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) dev->phy.ops->phy_write(dev, reg, value); } +void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg) +{ + assert_mac_suspended(dev); + dev->phy.ops->phy_write(dev, destreg, + dev->phy.ops->phy_read(dev, srcreg)); +} + void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) { b43_phy_write(dev, offset, diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 44cc918..9f9f23c 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -291,6 +291,11 @@ u16 b43_phy_read(struct b43_wldev *dev, u16 reg); void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value); /** + * b43_phy_copy - copy contents of 16bit PHY register to another + */ +void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg); + +/** * b43_phy_mask - Mask a PHY register with a mask */ void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask); diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index ea0d3a3..aa1486a 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -66,7 +66,99 @@ static void lpphy_table_init(struct b43_wldev *dev) static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) { - B43_WARN_ON(1);//TODO rev < 2 not supported, yet. + struct ssb_bus *bus = dev->dev->bus; + u16 tmp, tmp2; + + if (dev->phy.rev == 1 && + (bus->sprom.boardflags_hi & B43_BFH_FEM_BT)) { + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0x3F00, 0x0900); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0400); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0B00); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xC0FF, 0x0900); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xC0FF, 0x0B00); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xC0FF, 0x0900); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00); + } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ || + (bus->boardinfo.type == 0x048A) || ((dev->phy.rev == 0) && + (bus->sprom.boardflags_lo & B43_BFL_FEM))) { + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0500); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0800); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0A00); + } else if (dev->phy.rev == 1 || + (bus->sprom.boardflags_lo & B43_BFL_FEM)) { + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0004); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0800); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0004); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0C00); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0100); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0300); + } else { + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0900); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0006); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0500); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700); + } + if (dev->phy.rev == 1) { + b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1); + b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2); + b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3); + b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_8, B43_LPPHY_TR_LOOKUP_4); + } + if ((bus->sprom.boardflags_hi & B43_BFH_FEM_BT) && + (bus->chip_id == 0x5354) && + (bus->chip_package == SSB_CHIPPACK_BCM4712S)) { + b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006); + b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005); + b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF); + b43_hf_write(dev, b43_hf_read(dev) | 0x0800ULL << 32); + } + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000); + b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0040); + b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0xA400); + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0x0B00); + b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x0007); + b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFF8, 0x0003); + b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFC7, 0x0020); + b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF); + } else { /* 5GHz */ + b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0x7FFF); + b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFBF); + } + if (dev->phy.rev == 1) { + tmp = b43_phy_read(dev, B43_LPPHY_CLIPCTRTHRESH); + tmp2 = (tmp & 0x03E0) >> 5; + tmp2 |= tmp << 5; + b43_phy_write(dev, B43_LPPHY_4C3, tmp2); + tmp = b43_phy_read(dev, B43_LPPHY_OFDMSYNCTHRESH0); + tmp2 = (tmp & 0x1F00) >> 8; + tmp2 |= tmp << 5; + b43_phy_write(dev, B43_LPPHY_4C4, tmp2); + tmp = b43_phy_read(dev, B43_LPPHY_VERYLOWGAINDB); + tmp2 = tmp & 0x00FF; + tmp2 |= tmp << 8; + b43_phy_write(dev, B43_LPPHY_4C5, tmp2); + } } static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 18370b4..829b2bb 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -273,12 +273,19 @@ #define B43_LPPHY_AFE_DDFS_POINTER_INIT B43_PHY_OFDM(0xB8) /* AFE DDFS pointer init */ #define B43_LPPHY_AFE_DDFS_INCR_INIT B43_PHY_OFDM(0xB9) /* AFE DDFS incr init */ #define B43_LPPHY_MRCNOISEREDUCTION B43_PHY_OFDM(0xBA) /* mrcNoiseReduction */ -#define B43_LPPHY_TRLOOKUP3 B43_PHY_OFDM(0xBB) /* TRLookup3 */ -#define B43_LPPHY_TRLOOKUP4 B43_PHY_OFDM(0xBC) /* TRLookup4 */ +#define B43_LPPHY_TR_LOOKUP_3 B43_PHY_OFDM(0xBB) /* TR Lookup 3 */ +#define B43_LPPHY_TR_LOOKUP_4 B43_PHY_OFDM(0xBC) /* TR Lookup 4 */ #define B43_LPPHY_RADAR_FIFO_STAT B43_PHY_OFDM(0xBD) /* Radar FIFO Status */ #define B43_LPPHY_GPIO_OUTEN B43_PHY_OFDM(0xBE) /* GPIO Out enable */ #define B43_LPPHY_GPIO_SELECT B43_PHY_OFDM(0xBF) /* GPIO Select */ #define B43_LPPHY_GPIO_OUT B43_PHY_OFDM(0xC0) /* GPIO Out */ +#define B43_LPPHY_4C3 B43_PHY_OFDM(0xC3) /* unknown, used during BB init */ +#define B43_LPPHY_4C4 B43_PHY_OFDM(0xC4) /* unknown, used during BB init */ +#define B43_LPPHY_4C5 B43_PHY_OFDM(0xC5) /* unknown, used during BB init */ +#define B43_LPPHY_TR_LOOKUP_5 B43_PHY_OFDM(0xC7) /* TR Lookup 5 */ +#define B43_LPPHY_TR_LOOKUP_6 B43_PHY_OFDM(0xC8) /* TR Lookup 6 */ +#define B43_LPPHY_TR_LOOKUP_7 B43_PHY_OFDM(0xC9) /* TR Lookup 7 */ +#define B43_LPPHY_TR_LOOKUP_8 B43_PHY_OFDM(0xCA) /* TR Lookup 8 */ diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index be7b560..992318a 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -137,7 +137,8 @@ static void b43_radio_init2055_post(struct b43_wldev *dev) b43_radio_mask(dev, B2055_MASTER1, 0xFFF3); msleep(1); - if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) { + if ((sprom->revision != 4) || + !(sprom->boardflags_hi & B43_BFH_RSSIINV)) { if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) || (binfo->type != 0x46D) || (binfo->rev < 0x41)) { -- cgit v0.10.2 From 554503f8c9e11cbea92b7cf1e31f7e4d93ad4492 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 3 Aug 2009 14:37:01 +0800 Subject: iwmc3200wifi: fix set_wpa_version and set_auth_type order iwm->umac_profile->sec.flags is set by iwm_set_wpa_version and checked by iwm_set_auth_type. The patch changes the order to make the flag used correctly. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 3f5a08f..a6e852f 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -484,6 +484,8 @@ static int iwm_set_auth_type(struct iwm_priv *iwm, static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version) { + IWM_DBG_WEXT(iwm, DBG, "wpa_version: %d\n", wpa_version); + if (!wpa_version) { iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; return 0; @@ -508,6 +510,9 @@ static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast) return 0; } + IWM_DBG_WEXT(iwm, DBG, "%ccast cipher is 0x%x\n", ucast ? 'u' : 'm', + cipher); + switch (cipher) { case IW_AUTH_CIPHER_NONE: *profile_cipher = UMAC_CIPHER_TYPE_NONE; @@ -584,11 +589,11 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, iwm->umac_profile->bss_num = 0; } - ret = iwm_set_auth_type(iwm, sme->auth_type); + ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions); if (ret < 0) return ret; - ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions); + ret = iwm_set_auth_type(iwm, sme->auth_type); if (ret < 0) return ret; -- cgit v0.10.2 From beda278d987cf7091302cf730c5b226d88e01c5b Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 3 Aug 2009 14:37:02 +0800 Subject: iwmc3200wifi: set WEP key static flag correctly We should only set the static_key flag for open and legacy authentication types. It should not be set for 802.1X and TKIP. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 0d66370..6b36260 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -596,6 +596,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) key_idx = key->hdr.key_idx; if (!remove) { + u8 auth_type = iwm->umac_profile->sec.auth_type; + IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx); IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", @@ -618,7 +620,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) memcpy(&wep40->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(wep40->key, key_data, key_len); - wep40->static_key = 1; + wep40->static_key = + !!((auth_type != UMAC_AUTH_TYPE_8021X) && + (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); cmd_size = sizeof(struct iwm_umac_key_wep40); break; @@ -632,7 +636,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) memcpy(&wep104->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(wep104->key, key_data, key_len); - wep104->static_key = 1; + wep104->static_key = + !!((auth_type != UMAC_AUTH_TYPE_8021X) && + (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); cmd_size = sizeof(struct iwm_umac_key_wep104); break; -- cgit v0.10.2 From 847c1e130092240c225a7be08607a7bf4e296fbd Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 3 Aug 2009 14:37:03 +0800 Subject: iwmc3200wifi: avoid setting default key for 802.1X and RSNA UMAC only allows us to set default key for WEP and auth type is not 802.1X or RSNA. This patch fixes iwmc3200wifi for 802.1X with WEP104. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 6b36260..f0c8acd 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -526,19 +526,6 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) return 0; } -int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) -{ - struct iwm_umac_tx_key_id tx_key_id; - - tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; - tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - - sizeof(struct iwm_umac_wifi_if)); - - tx_key_id.key_idx = key_idx; - - return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); -} - static int iwm_check_profile(struct iwm_priv *iwm) { if (!iwm->umac_profile_active) @@ -572,6 +559,32 @@ static int iwm_check_profile(struct iwm_priv *iwm) return 0; } +int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) +{ + struct iwm_umac_tx_key_id tx_key_id; + int ret; + + ret = iwm_check_profile(iwm); + if (ret < 0) + return ret; + + /* UMAC only allows to set default key for WEP and auth type is + * NOT 802.1X or RSNA. */ + if ((iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && + iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104) || + iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_8021X || + iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_RSNA_PSK) + return 0; + + tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; + tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - + sizeof(struct iwm_umac_wifi_if)); + + tx_key_id.key_idx = key_idx; + + return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); +} + int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) { int ret = 0; -- cgit v0.10.2 From 8dadadb7e977a91b46ed3549f9d2f22a629e5043 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Aug 2009 09:32:23 +0200 Subject: cfg80211: clear SSID on disconnect/no connection The SME state machine in cfg80211 uses the SSID stored in struct wireless_dev internally, but fails to clear it in multiple places (when giving up on a connection attempt and when disconnecting). This doesn't matter to the SME state machine, but does matter for IBSS. Thus, in those cases, clear the SSID to avoid messing up the IBSS state machine. Reported-by: Joerg Albert Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/sme.c b/net/wireless/sme.c index af91192..8a7dcbf 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -385,6 +385,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, wdev->conn = NULL; kfree(wdev->connect_keys); wdev->connect_keys = NULL; + wdev->ssid_len = 0; return; } @@ -566,6 +567,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, wdev->current_bss = NULL; wdev->sme_state = CFG80211_SME_IDLE; + wdev->ssid_len = 0; if (wdev->conn) { kfree(wdev->conn->ie); @@ -721,6 +723,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, wdev->conn = NULL; wdev->sme_state = CFG80211_SME_IDLE; wdev->connect_keys = NULL; + wdev->ssid_len = 0; } return err; @@ -785,6 +788,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, wdev->sme_state = CFG80211_SME_IDLE; kfree(wdev->conn); wdev->conn = NULL; + wdev->ssid_len = 0; return 0; } -- cgit v0.10.2 From ed459c18517881890193b3414a25dbfe83d2ae7f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:33 -0700 Subject: ath9k: remove usage of AR_SREV_*() wrapper to detect supported hw We will clean this up next to just use a switch. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7a0a6ae..e0bc4c5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -665,8 +665,10 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) && (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && (ah->hw_version.macVersion != AR_SREV_VERSION_9160) && - (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && - (!AR_SREV_9285(ah)) && (!AR_SREV_9287(ah))) { + (ah->hw_version.macVersion != AR_SREV_VERSION_9100) && + (ah->hw_version.macVersion != AR_SREV_VERSION_9280) && + (ah->hw_version.macVersion != AR_SREV_VERSION_9285) && + (ah->hw_version.macVersion != AR_SREV_VERSION_9287)) { DPRINTF(sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, -- cgit v0.10.2 From fbf54660d1b48fba8527aae5c628ba72feee8f83 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:34 -0700 Subject: ath9k: use a switch for revising supported hw mac revisions This makes adding new hw revisions a one line change here. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e0bc4c5..8228f41 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -662,13 +662,16 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n", ah->config.serialize_regmode); - if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) && - (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && - (ah->hw_version.macVersion != AR_SREV_VERSION_9160) && - (ah->hw_version.macVersion != AR_SREV_VERSION_9100) && - (ah->hw_version.macVersion != AR_SREV_VERSION_9280) && - (ah->hw_version.macVersion != AR_SREV_VERSION_9285) && - (ah->hw_version.macVersion != AR_SREV_VERSION_9287)) { + switch (ah->hw_version.macVersion) { + case AR_SREV_VERSION_5416_PCI: + case AR_SREV_VERSION_5416_PCIE: + case AR_SREV_VERSION_9160: + case AR_SREV_VERSION_9100: + case AR_SREV_VERSION_9280: + case AR_SREV_VERSION_9285: + case AR_SREV_VERSION_9287: + break; + default: DPRINTF(sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, -- cgit v0.10.2 From 7819ac84b689b61340f29af6233fa1d15b76a6ef Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:35 -0700 Subject: ath9k: propagate hw initialization errors We were never propagating hw initialization errors, lets do that now and also use -EOPNOTSUPP when device revision is not supported yet. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8228f41..2e09204 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1223,7 +1223,7 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error) ah = ath9k_hw_do_attach(devid, sc, error); break; default: - *error = -ENXIO; + *error = -EOPNOTSUPP; break; } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 292ac2b..ada5fef 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1295,7 +1295,6 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, static int ath_init(u16 devid, struct ath_softc *sc) { struct ath_hw *ah = NULL; - int status; int error = 0, i; int csz = 0; @@ -1323,11 +1322,11 @@ static int ath_init(u16 devid, struct ath_softc *sc) /* XXX assert csz is non-zero */ sc->cachelsz = csz << 2; /* convert to bytes */ - ah = ath9k_hw_attach(devid, sc, &status); + ah = ath9k_hw_attach(devid, sc, &error); if (ah == NULL) { DPRINTF(sc, ATH_DBG_FATAL, - "Unable to attach hardware; HAL status %d\n", status); - error = -ENXIO; + "Unable to attach hardware; " + "initialization status: %d\n", error); goto bad; } sc->sc_ah = ah; -- cgit v0.10.2 From 4f3acf81f2a47244f7403353784f528c92e98a6c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:36 -0700 Subject: ath9k: move memory allocation of ath_hw to ath_init() This lets us simplify attach code and arguments passed. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2e09204..fcefea8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -437,20 +437,9 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.serialize_regmode = SER_REG_MODE_AUTO; } -static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, - int *status) +static void ath9k_hw_newstate(u16 devid, + struct ath_hw *ah) { - struct ath_hw *ah; - - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); - if (ah == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "Cannot allocate memory for state block\n"); - *status = -ENOMEM; - return NULL; - } - - ah->ah_sc = sc; ah->hw_version.magic = AR5416_MAGIC; ah->regulatory.country_code = CTRY_DEFAULT; ah->hw_version.devid = devid; @@ -479,8 +468,6 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, ah->gbeacon_rate = 0; ah->power_mode = ATH9K_PM_UNDEFINED; - - return ah; } static int ath9k_hw_rfattach(struct ath_hw *ah) @@ -623,28 +610,25 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) return 0; } -static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, - int *status) +static int ath9k_hw_do_attach(struct ath_hw *ah, + u16 devid, + struct ath_softc *sc) { - struct ath_hw *ah; - int ecode; + int r; u32 i, j; - ah = ath9k_hw_newstate(devid, sc, status); - if (ah == NULL) - return NULL; - + ath9k_hw_newstate(devid, ah); ath9k_hw_set_defaults(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); - ecode = -EIO; + r = -EIO; goto bad; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); - ecode = -EIO; + r = -EIO; goto bad; } @@ -676,7 +660,7 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, ah->hw_version.macRev); - ecode = -EOPNOTSUPP; + r = -EOPNOTSUPP; goto bad; } @@ -878,8 +862,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, else ath9k_hw_disablepcie(ah); - ecode = ath9k_hw_post_attach(ah); - if (ecode != 0) + r = ath9k_hw_post_attach(ah); + if (r) goto bad; if (AR_SREV_9287_11(ah)) @@ -939,8 +923,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, } } - ecode = ath9k_hw_init_macaddr(ah); - if (ecode != 0) { + r = ath9k_hw_init_macaddr(ah); + if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Failed to initialize MAC address\n"); goto bad; @@ -953,14 +937,10 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, ath9k_init_nfcal_hist_buffer(ah); - return ah; + return 0; bad: - if (ah) - ath9k_hw_detach(ah); - if (status) - *status = ecode; - - return NULL; + ath9k_hw_detach(ah); + return r; } static void ath9k_hw_init_bb(struct ath_hw *ah, @@ -1206,10 +1186,8 @@ void ath9k_hw_detach(struct ath_hw *ah) kfree(ah); } -struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error) +int ath9k_hw_attach(struct ath_hw *ah, u16 devid, struct ath_softc *sc) { - struct ath_hw *ah = NULL; - switch (devid) { case AR5416_DEVID_PCI: case AR5416_DEVID_PCIE: @@ -1220,14 +1198,11 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error) case AR9285_DEVID_PCIE: case AR5416_DEVID_AR9287_PCI: case AR5416_DEVID_AR9287_PCIE: - ah = ath9k_hw_do_attach(devid, sc, error); - break; + return ath9k_hw_do_attach(ah, devid, sc); default: - *error = -EOPNOTSUPP; break; } - - return ah; + return -EOPNOTSUPP; } /*******/ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 93a8930..4a0d5f2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -544,7 +544,7 @@ struct ath_hw { /* Attach, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); -struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error); +int ath9k_hw_attach(struct ath_hw *ah, u16 devid, struct ath_softc *sc); void ath9k_hw_rfdetach(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ada5fef..c2b9974 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1295,7 +1295,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, static int ath_init(u16 devid, struct ath_softc *sc) { struct ath_hw *ah = NULL; - int error = 0, i; + int r = 0, i; int csz = 0; /* XXX: hardware will not be ready until ath_open() being called */ @@ -1322,11 +1322,21 @@ static int ath_init(u16 devid, struct ath_softc *sc) /* XXX assert csz is non-zero */ sc->cachelsz = csz << 2; /* convert to bytes */ - ah = ath9k_hw_attach(devid, sc, &error); - if (ah == NULL) { + ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); + if (!ah) { + DPRINTF(sc, ATH_DBG_FATAL, + "Cannot allocate memory for state block\n"); + r = -ENOMEM; + goto bad_no_ah; + } + + ah->ah_sc = sc; + + r = ath9k_hw_attach(ah, devid, sc); + if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to attach hardware; " - "initialization status: %d\n", error); + "initialization status: %d\n", r); goto bad; } sc->sc_ah = ah; @@ -1347,7 +1357,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) for (i = 0; i < sc->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - if (error) + if (r) goto bad; /* default to MONITOR mode */ @@ -1369,14 +1379,14 @@ static int ath_init(u16 devid, struct ath_softc *sc) if (sc->beacon.beaconq == -1) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup a beacon xmit queue\n"); - error = -EIO; + r = -EIO; goto bad2; } sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); if (sc->beacon.cabq == NULL) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup CAB xmit queue\n"); - error = -EIO; + r = -EIO; goto bad2; } @@ -1391,26 +1401,26 @@ static int ath_init(u16 devid, struct ath_softc *sc) if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup xmit queue for BK traffic\n"); - error = -EIO; + r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup xmit queue for BE traffic\n"); - error = -EIO; + r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup xmit queue for VI traffic\n"); - error = -EIO; + r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup xmit queue for VO traffic\n"); - error = -EIO; + r = -EIO; goto bad2; } @@ -1506,9 +1516,10 @@ bad2: bad: if (ah) ath9k_hw_detach(ah); +bad_no_ah: ath9k_exit_debug(sc); - return error; + return r; } void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) -- cgit v0.10.2 From 8df5d1b77395271dd9b75ed2b9aa9235f7589a0d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:37 -0700 Subject: ath9k: move devid cache setting to ath_init() This lets us trim one argument off of hw initializer routines. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index fcefea8..ff2875b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -437,16 +437,14 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.serialize_regmode = SER_REG_MODE_AUTO; } -static void ath9k_hw_newstate(u16 devid, - struct ath_hw *ah) +static void ath9k_hw_newstate(struct ath_hw *ah) { ah->hw_version.magic = AR5416_MAGIC; ah->regulatory.country_code = CTRY_DEFAULT; - ah->hw_version.devid = devid; ah->hw_version.subvendorid = 0; ah->ah_flags = 0; - if ((devid == AR5416_AR9100_DEVID)) + if (ah->hw_version.devid == AR5416_AR9100_DEVID) ah->hw_version.macVersion = AR_SREV_VERSION_9100; if (!AR_SREV_9100(ah)) ah->ah_flags = AH_USE_EEPROM; @@ -611,13 +609,12 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) } static int ath9k_hw_do_attach(struct ath_hw *ah, - u16 devid, struct ath_softc *sc) { int r; u32 i, j; - ath9k_hw_newstate(devid, ah); + ath9k_hw_newstate(ah); ath9k_hw_set_defaults(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { @@ -1186,9 +1183,9 @@ void ath9k_hw_detach(struct ath_hw *ah) kfree(ah); } -int ath9k_hw_attach(struct ath_hw *ah, u16 devid, struct ath_softc *sc) +int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) { - switch (devid) { + switch (ah->hw_version.devid) { case AR5416_DEVID_PCI: case AR5416_DEVID_PCIE: case AR5416_AR9100_DEVID: @@ -1198,7 +1195,7 @@ int ath9k_hw_attach(struct ath_hw *ah, u16 devid, struct ath_softc *sc) case AR9285_DEVID_PCIE: case AR5416_DEVID_AR9287_PCI: case AR5416_DEVID_AR9287_PCIE: - return ath9k_hw_do_attach(ah, devid, sc); + return ath9k_hw_do_attach(ah, sc); default: break; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4a0d5f2..c769dd6 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -544,7 +544,7 @@ struct ath_hw { /* Attach, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); -int ath9k_hw_attach(struct ath_hw *ah, u16 devid, struct ath_softc *sc); +int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc); void ath9k_hw_rfdetach(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c2b9974..fa2c230 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1331,8 +1331,9 @@ static int ath_init(u16 devid, struct ath_softc *sc) } ah->ah_sc = sc; + ah->hw_version.devid = devid; - r = ath9k_hw_attach(ah, devid, sc); + r = ath9k_hw_attach(ah, sc); if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to attach hardware; " -- cgit v0.10.2 From e1e2f93ffacab692823209e00a124e802039aa9a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:38 -0700 Subject: ath9k: move cache setting of softc ah prior to attach We do this in case attach and friends try to get back to ah from the softc somehow. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index fa2c230..605d328 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1332,6 +1332,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) ah->ah_sc = sc; ah->hw_version.devid = devid; + sc->sc_ah = ah; r = ath9k_hw_attach(ah, sc); if (r) { @@ -1340,7 +1341,6 @@ static int ath_init(u16 devid, struct ath_softc *sc) "initialization status: %d\n", r); goto bad; } - sc->sc_ah = ah; /* Get the hardware key cache size. */ sc->keymax = ah->caps.keycache_size; -- cgit v0.10.2 From ee2bb460e28b757f097efb9e5947a6e47e2477e1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:39 -0700 Subject: ath9k: call hw initializer directly ath9k_hw_attach() was going first through some device id verifier, and then calling some other helper which was doing the real hardware initialization. Lets just do the devid checks within the real worker by calling a helper ath9k_hw_devid_supported(). Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ff2875b..d8ae289 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -608,12 +608,35 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) return 0; } -static int ath9k_hw_do_attach(struct ath_hw *ah, - struct ath_softc *sc) +static bool ath9k_hw_devid_supported(u16 devid) +{ + switch (devid) { + case AR5416_DEVID_PCI: + case AR5416_DEVID_PCIE: + case AR5416_AR9100_DEVID: + case AR9160_DEVID_PCI: + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + case AR9285_DEVID_PCIE: + case AR5416_DEVID_AR9287_PCI: + case AR5416_DEVID_AR9287_PCIE: + return true; + default: + break; + } + return false; +} + +int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) { int r; u32 i, j; + if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { + r = -EOPNOTSUPP; + goto bad; + } + ath9k_hw_newstate(ah); ath9k_hw_set_defaults(ah); @@ -1183,25 +1206,6 @@ void ath9k_hw_detach(struct ath_hw *ah) kfree(ah); } -int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) -{ - switch (ah->hw_version.devid) { - case AR5416_DEVID_PCI: - case AR5416_DEVID_PCIE: - case AR5416_AR9100_DEVID: - case AR9160_DEVID_PCI: - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - case AR9285_DEVID_PCIE: - case AR5416_DEVID_AR9287_PCI: - case AR5416_DEVID_AR9287_PCIE: - return ath9k_hw_do_attach(ah, sc); - default: - break; - } - return -EOPNOTSUPP; -} - /*******/ /* INI */ /*******/ @@ -2898,7 +2902,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) /* * AR9280 2.0 or later chips use SerDes values from the * initvals.h initialized depending on chipset during - * ath9k_hw_do_attach() + * ath9k_hw_attach() */ for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) { REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0), -- cgit v0.10.2 From 07c10c6177bdd199fead127c2a4c43acb415a5be Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:40 -0700 Subject: ath9k: pass only one argument to hw attach The softc is cached and set within the ath_hw struct. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index d8ae289..301ef04 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -627,7 +627,7 @@ static bool ath9k_hw_devid_supported(u16 devid) return false; } -int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) +int ath9k_hw_attach(struct ath_hw *ah) { int r; u32 i, j; @@ -641,13 +641,13 @@ int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) ath9k_hw_set_defaults(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); r = -EIO; goto bad; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); r = -EIO; goto bad; } @@ -663,7 +663,7 @@ int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) } } - DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n", + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n", ah->config.serialize_regmode); switch (ah->hw_version.macVersion) { @@ -676,7 +676,7 @@ int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) case AR_SREV_VERSION_9287: break; default: - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, ah->hw_version.macRev); @@ -945,7 +945,7 @@ int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) r = ath9k_hw_init_macaddr(ah); if (r) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Failed to initialize MAC address\n"); goto bad; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c769dd6..35cf9f8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -544,7 +544,7 @@ struct ath_hw { /* Attach, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); -int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc); +int ath9k_hw_attach(struct ath_hw *ah); void ath9k_hw_rfdetach(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 605d328..6242950 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1334,7 +1334,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) ah->hw_version.devid = devid; sc->sc_ah = ah; - r = ath9k_hw_attach(ah, sc); + r = ath9k_hw_attach(ah); if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to attach hardware; " -- cgit v0.10.2 From f9d4a668035b0bf65d1c8d5eba680201112f7c3d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:41 -0700 Subject: ath9k: move hw macrevision checker to helper Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 301ef04..4f3d7bf 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -627,6 +627,23 @@ static bool ath9k_hw_devid_supported(u16 devid) return false; } +static bool ath9k_hw_macversion_supported(u32 macversion) +{ + switch (macversion) { + case AR_SREV_VERSION_5416_PCI: + case AR_SREV_VERSION_5416_PCIE: + case AR_SREV_VERSION_9160: + case AR_SREV_VERSION_9100: + case AR_SREV_VERSION_9280: + case AR_SREV_VERSION_9285: + case AR_SREV_VERSION_9287: + return true; + default: + break; + } + return false; +} + int ath9k_hw_attach(struct ath_hw *ah) { int r; @@ -666,16 +683,7 @@ int ath9k_hw_attach(struct ath_hw *ah) DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n", ah->config.serialize_regmode); - switch (ah->hw_version.macVersion) { - case AR_SREV_VERSION_5416_PCI: - case AR_SREV_VERSION_5416_PCIE: - case AR_SREV_VERSION_9160: - case AR_SREV_VERSION_9100: - case AR_SREV_VERSION_9280: - case AR_SREV_VERSION_9285: - case AR_SREV_VERSION_9287: - break; - default: + if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, -- cgit v0.10.2 From 50aca25b5824f29fa94417abadf82ee7f0c7f816 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:42 -0700 Subject: ath9k: rename ath9k_hw_newstate() to ath9k_hw_init_defaults() This reflects better what we are actually doing there. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4f3d7bf..6aee570 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -437,7 +437,7 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.serialize_regmode = SER_REG_MODE_AUTO; } -static void ath9k_hw_newstate(struct ath_hw *ah) +static void ath9k_hw_init_defaults(struct ath_hw *ah) { ah->hw_version.magic = AR5416_MAGIC; ah->regulatory.country_code = CTRY_DEFAULT; @@ -654,7 +654,7 @@ int ath9k_hw_attach(struct ath_hw *ah) goto bad; } - ath9k_hw_newstate(ah); + ath9k_hw_init_defaults(ah); ath9k_hw_set_defaults(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { -- cgit v0.10.2 From b8b0f377c762558b3773e27f73c7bbcd0fa40171 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:43 -0700 Subject: ath9k: rename ath9k_hw_set_defaults() to ath9k_hw_init_config() This reflects better what we are actually doing there. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6aee570..31ec83d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -388,7 +388,7 @@ static const char *ath9k_hw_devname(u16 devid) return NULL; } -static void ath9k_hw_set_defaults(struct ath_hw *ah) +static void ath9k_hw_init_config(struct ath_hw *ah) { int i; @@ -655,7 +655,7 @@ int ath9k_hw_attach(struct ath_hw *ah) } ath9k_hw_init_defaults(ah); - ath9k_hw_set_defaults(ah); + ath9k_hw_init_config(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); -- cgit v0.10.2 From 08e0403a1472d9fa3662369a36ccaf24c796a33e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:44 -0700 Subject: ath9k: remove debug message for no memoery on ath_init() We're now propagating the -ENOMEM error so there is no need to keep a debug message there now. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6242950..230dedb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1324,8 +1324,6 @@ static int ath_init(u16 devid, struct ath_softc *sc) ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); if (!ah) { - DPRINTF(sc, ATH_DBG_FATAL, - "Cannot allocate memory for state block\n"); r = -ENOMEM; goto bad_no_ah; } -- cgit v0.10.2 From aa4058aea24efe7aef736cbfb2d9b07de920ca27 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:45 -0700 Subject: ath9k: break up hw initialization into a few more helpers This makes reading the hardware initialization process easier to understand. The new helpers added are: ath9k_hw_init_cal_settings() ath9k_hw_init_mode_regs() ath9k_hw_init_mode_gain_regs() ath9k_hw_init_11a_eeprom_fix() This patch has no functional changes. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 31ec83d..f280eef 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -644,61 +644,8 @@ static bool ath9k_hw_macversion_supported(u32 macversion) return false; } -int ath9k_hw_attach(struct ath_hw *ah) +static void ath9k_hw_init_cal_settings(struct ath_hw *ah) { - int r; - u32 i, j; - - if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { - r = -EOPNOTSUPP; - goto bad; - } - - ath9k_hw_init_defaults(ah); - ath9k_hw_init_config(ah); - - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); - r = -EIO; - goto bad; - } - - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); - r = -EIO; - goto bad; - } - - if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { - if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || - (AR_SREV_9280(ah) && !ah->is_pciexpress)) { - ah->config.serialize_regmode = - SER_REG_MODE_ON; - } else { - ah->config.serialize_regmode = - SER_REG_MODE_OFF; - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n", - ah->config.serialize_regmode); - - if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Mac Chip Rev 0x%02x.%x is not supported by " - "this driver\n", ah->hw_version.macVersion, - ah->hw_version.macRev); - r = -EOPNOTSUPP; - goto bad; - } - - if (AR_SREV_9100(ah)) { - ah->iq_caldata.calData = &iq_cal_multi_sample; - ah->supp_cals = IQ_MISMATCH_CAL; - ah->is_pciexpress = false; - } - ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); - if (AR_SREV_9160_10_OR_LATER(ah)) { if (AR_SREV_9280_10_OR_LATER(ah)) { ah->iq_caldata.calData = &iq_cal_single_sample; @@ -719,10 +666,10 @@ int ath9k_hw_attach(struct ath_hw *ah) } ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; } +} - ah->ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; +static void ath9k_hw_init_mode_regs(struct ath_hw *ah) +{ if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, ARRAY_SIZE(ar9287Modes_9287_1_1), 6); @@ -884,16 +831,10 @@ int ath9k_hw_attach(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, ARRAY_SIZE(ar5416Addac), 2); } +} - if (ah->is_pciexpress) - ath9k_hw_configpcipowersave(ah, 0); - else - ath9k_hw_disablepcie(ah); - - r = ath9k_hw_post_attach(ah); - if (r) - goto bad; - +static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) +{ if (AR_SREV_9287_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9287Modes_rx_gain_9287_1_1, @@ -930,8 +871,11 @@ int ath9k_hw_attach(struct ath_hw *ah) } } +} - ath9k_hw_fill_cap_info(ah); +static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah) +{ + u32 i, j; if ((ah->hw_version.devid == AR9280_DEVID_PCI) && test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) { @@ -950,6 +894,82 @@ int ath9k_hw_attach(struct ath_hw *ah) } } } +} + +int ath9k_hw_attach(struct ath_hw *ah) +{ + int r; + + if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { + r = -EOPNOTSUPP; + goto bad; + } + + ath9k_hw_init_defaults(ah); + ath9k_hw_init_config(ah); + + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); + r = -EIO; + goto bad; + } + + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); + r = -EIO; + goto bad; + } + + if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { + if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || + (AR_SREV_9280(ah) && !ah->is_pciexpress)) { + ah->config.serialize_regmode = + SER_REG_MODE_ON; + } else { + ah->config.serialize_regmode = + SER_REG_MODE_OFF; + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n", + ah->config.serialize_regmode); + + if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Mac Chip Rev 0x%02x.%x is not supported by " + "this driver\n", ah->hw_version.macVersion, + ah->hw_version.macRev); + r = -EOPNOTSUPP; + goto bad; + } + + if (AR_SREV_9100(ah)) { + ah->iq_caldata.calData = &iq_cal_multi_sample; + ah->supp_cals = IQ_MISMATCH_CAL; + ah->is_pciexpress = false; + } + ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); + + ath9k_hw_init_cal_settings(ah); + + ah->ani_function = ATH9K_ANI_ALL; + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; + + ath9k_hw_init_mode_regs(ah); + + if (ah->is_pciexpress) + ath9k_hw_configpcipowersave(ah, 0); + else + ath9k_hw_disablepcie(ah); + + r = ath9k_hw_post_attach(ah); + if (r) + goto bad; + + ath9k_hw_init_mode_gain_regs(ah); + ath9k_hw_fill_cap_info(ah); + ath9k_hw_init_11a_eeprom_fix(ah); r = ath9k_hw_init_macaddr(ah); if (r) { -- cgit v0.10.2 From f637cfd6bbacbaeab329f9dfc56e9855cc15849d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:46 -0700 Subject: ath9k: describe hw initialization better During initialization ath9k tends to use "attach" to when we initialize hardware due to the fact we used to attach a "HAL". The notion of a HAL is long gone, so lets just be clear on what we are doing. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index aad259b..a613cf4 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -777,7 +777,7 @@ void ath9k_hw_ani_setup(struct ath_hw *ah) } } -void ath9k_hw_ani_attach(struct ath_hw *ah) +void ath9k_hw_ani_init(struct ath_hw *ah) { int i; diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 08b4e7e..803669f 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -132,7 +132,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, void ath9k_hw_procmibevent(struct ath_hw *ah, const struct ath9k_node_stats *stats); void ath9k_hw_ani_setup(struct ath_hw *ah); -void ath9k_hw_ani_attach(struct ath_hw *ah); +void ath9k_hw_ani_init(struct ath_hw *ah); void ath9k_hw_ani_detach(struct ath_hw *ah); #endif /* ANI_H */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 6fb1a80..e8ccec0 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -3978,7 +3978,7 @@ static struct eeprom_ops eep_AR9287_ops = { }; -int ath9k_hw_eeprom_attach(struct ath_hw *ah) +int ath9k_hw_eeprom_init(struct ath_hw *ah) { int status; if (AR_SREV_9287(ah)) { diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 7ddd016..335098d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -665,6 +665,6 @@ struct eeprom_ops { (((_txchainmask >> 2) & 1) + \ ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) -int ath9k_hw_eeprom_attach(struct ath_hw *ah); +int ath9k_hw_eeprom_init(struct ath_hw *ah); #endif /* EEPROM_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f280eef..65d2e7d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -578,7 +578,7 @@ static void ath9k_hw_init_txgain_ini(struct ath_hw *ah) } } -static int ath9k_hw_post_attach(struct ath_hw *ah) +static int ath9k_hw_post_init(struct ath_hw *ah) { int ecode; @@ -589,7 +589,7 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) if (ecode != 0) return ecode; - ecode = ath9k_hw_eeprom_attach(ah); + ecode = ath9k_hw_eeprom_init(ah); if (ecode != 0) return ecode; @@ -602,7 +602,7 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) if (!AR_SREV_9100(ah)) { ath9k_hw_ani_setup(ah); - ath9k_hw_ani_attach(ah); + ath9k_hw_ani_init(ah); } return 0; @@ -896,7 +896,7 @@ static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah) } } -int ath9k_hw_attach(struct ath_hw *ah) +int ath9k_hw_init(struct ath_hw *ah) { int r; @@ -963,7 +963,7 @@ int ath9k_hw_attach(struct ath_hw *ah) else ath9k_hw_disablepcie(ah); - r = ath9k_hw_post_attach(ah); + r = ath9k_hw_post_init(ah); if (r) goto bad; @@ -2930,7 +2930,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) /* * AR9280 2.0 or later chips use SerDes values from the * initvals.h initialized depending on chipset during - * ath9k_hw_attach() + * ath9k_hw_init() */ for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) { REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0), diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 35cf9f8..4c78e8c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -541,10 +541,10 @@ struct ath_hw { struct ar5416IniArray iniModesTxGain; }; -/* Attach, Detach, Reset */ +/* Initialization, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); -int ath9k_hw_attach(struct ath_hw *ah); +int ath9k_hw_init(struct ath_hw *ah); void ath9k_hw_rfdetach(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 230dedb..751d803 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1332,10 +1332,10 @@ static int ath_init(u16 devid, struct ath_softc *sc) ah->hw_version.devid = devid; sc->sc_ah = ah; - r = ath9k_hw_attach(ah); + r = ath9k_hw_init(ah); if (r) { DPRINTF(sc, ATH_DBG_FATAL, - "Unable to attach hardware; " + "Unable to initialize hardware; " "initialization status: %d\n", r); goto bad; } -- cgit v0.10.2 From 1e40bcfa91429edb665af9ffefb2658350913d35 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:47 -0700 Subject: ath9k: distinguish between device initialization and ath_softc init We re-label the device driver initialization routines from the ath_softc, the "Software Carrier" fillers. This should make it clearer what each of these do. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 0e65c51..5618fc2 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -119,7 +119,7 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->bus_ops = &ath_ahb_bus_ops; sc->irq = irq; - ret = ath_attach(AR5416_AR9100_DEVID, sc); + ret = ath_init_device(AR5416_AR9100_DEVID, sc); if (ret != 0) { dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); ret = -ENODEV; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index bda0f30..7a5a157 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -642,7 +642,7 @@ extern struct ieee80211_ops ath9k_ops; irqreturn_t ath_isr(int irq, void *dev); void ath_cleanup(struct ath_softc *sc); -int ath_attach(u16 devid, struct ath_softc *sc); +int ath_init_device(u16 devid, struct ath_softc *sc); void ath_detach(struct ath_softc *sc); const char *ath_mac_bb_name(u32 mac_bb_version); const char *ath_rf_name(u16 rf_version); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 751d803..91bffc9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1292,7 +1292,13 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, return ath_reg_notifier_apply(wiphy, request, reg); } -static int ath_init(u16 devid, struct ath_softc *sc) +/* + * Initialize and fill ath_softc, ath_sofct is the + * "Software Carrier" struct. Historically it has existed + * to allow the separation between hardware specific + * variables (now in ath_hw) and driver specific variables. + */ +static int ath_init_softc(u16 devid, struct ath_softc *sc) { struct ath_hw *ah = NULL; int r = 0, i; @@ -1558,7 +1564,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) &sc->sbands[IEEE80211_BAND_5GHZ]; } -int ath_attach(u16 devid, struct ath_softc *sc) +/* Device driver core initialization */ +int ath_init_device(u16 devid, struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; int error = 0, i; @@ -1566,7 +1573,7 @@ int ath_attach(u16 devid, struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); - error = ath_init(devid, sc); + error = ath_init_softc(devid, sc); if (error != 0) return error; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index cd4841b..3546504 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -178,7 +178,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = mem; sc->bus_ops = &ath_pci_bus_ops; - if (ath_attach(id->device, sc) != 0) { + if (ath_init_device(id->device, sc) != 0) { ret = -ENODEV; goto bad3; } -- cgit v0.10.2 From 39a21951efc99e040a7d66449f63910e439b97e9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:48 -0700 Subject: ath9k: remove !NULL check before kfree() kfree(NULL) works so remove all those branches which check for it before kfree()'ing on ath9k_hw_rfdetach(). Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index aaa9415..06fd057 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -266,42 +266,32 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, void ath9k_hw_rfdetach(struct ath_hw *ah) { - if (ah->analogBank0Data != NULL) { - kfree(ah->analogBank0Data); - ah->analogBank0Data = NULL; - } - if (ah->analogBank1Data != NULL) { - kfree(ah->analogBank1Data); - ah->analogBank1Data = NULL; - } - if (ah->analogBank2Data != NULL) { - kfree(ah->analogBank2Data); - ah->analogBank2Data = NULL; - } - if (ah->analogBank3Data != NULL) { - kfree(ah->analogBank3Data); - ah->analogBank3Data = NULL; - } - if (ah->analogBank6Data != NULL) { - kfree(ah->analogBank6Data); - ah->analogBank6Data = NULL; - } - if (ah->analogBank6TPCData != NULL) { - kfree(ah->analogBank6TPCData); - ah->analogBank6TPCData = NULL; - } - if (ah->analogBank7Data != NULL) { - kfree(ah->analogBank7Data); - ah->analogBank7Data = NULL; - } - if (ah->addac5416_21 != NULL) { - kfree(ah->addac5416_21); - ah->addac5416_21 = NULL; - } - if (ah->bank6Temp != NULL) { - kfree(ah->bank6Temp); - ah->bank6Temp = NULL; - } + kfree(ah->analogBank0Data); + ah->analogBank0Data = NULL; + + kfree(ah->analogBank1Data); + ah->analogBank1Data = NULL; + + kfree(ah->analogBank2Data); + ah->analogBank2Data = NULL; + + kfree(ah->analogBank3Data); + ah->analogBank3Data = NULL; + + kfree(ah->analogBank6Data); + ah->analogBank6Data = NULL; + + kfree(ah->analogBank6TPCData); + ah->analogBank6TPCData = NULL; + + kfree(ah->analogBank7Data); + ah->analogBank7Data = NULL; + + kfree(ah->addac5416_21); + ah->addac5416_21 = NULL; + + kfree(ah->bank6Temp); + ah->bank6Temp = NULL; } bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) -- cgit v0.10.2 From 6b827529058d6d479f31b281a9ec630f7b6841e1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:49 -0700 Subject: ath9k: use helper macro to kfree and nullify on ath9k_hw_rfdetach() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 06fd057..98b1b56 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -266,32 +266,21 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, void ath9k_hw_rfdetach(struct ath_hw *ah) { - kfree(ah->analogBank0Data); - ah->analogBank0Data = NULL; - - kfree(ah->analogBank1Data); - ah->analogBank1Data = NULL; - - kfree(ah->analogBank2Data); - ah->analogBank2Data = NULL; - - kfree(ah->analogBank3Data); - ah->analogBank3Data = NULL; - - kfree(ah->analogBank6Data); - ah->analogBank6Data = NULL; - - kfree(ah->analogBank6TPCData); - ah->analogBank6TPCData = NULL; - - kfree(ah->analogBank7Data); - ah->analogBank7Data = NULL; - - kfree(ah->addac5416_21); - ah->addac5416_21 = NULL; - - kfree(ah->bank6Temp); - ah->bank6Temp = NULL; +#define ATH_FREE_BANK(bank) do { \ + kfree(bank); \ + bank = NULL; \ + } while (0); + + ATH_FREE_BANK(ah->analogBank0Data); + ATH_FREE_BANK(ah->analogBank1Data); + ATH_FREE_BANK(ah->analogBank2Data); + ATH_FREE_BANK(ah->analogBank3Data); + ATH_FREE_BANK(ah->analogBank6Data); + ATH_FREE_BANK(ah->analogBank6TPCData); + ATH_FREE_BANK(ah->analogBank7Data); + ATH_FREE_BANK(ah->addac5416_21); + ATH_FREE_BANK(ah->bank6Temp); +#undef ATH_FREE_BANK } bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) -- cgit v0.10.2 From 081b35ab2e98a2f76d0378219e91cd1c90aed55f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:50 -0700 Subject: ath9k: rename ath9k_hw_rfdetach() to ath9k_hw_rf_free() This makes it clear what this does. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 65d2e7d..73dee19 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1229,7 +1229,7 @@ void ath9k_hw_detach(struct ath_hw *ah) if (!AR_SREV_9100(ah)) ath9k_hw_ani_detach(ah); - ath9k_hw_rfdetach(ah); + ath9k_hw_rf_free(ah); ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); kfree(ah); } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4c78e8c..4e717cc 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -545,7 +545,7 @@ struct ath_hw { const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); int ath9k_hw_init(struct ath_hw *ah); -void ath9k_hw_rfdetach(struct ath_hw *ah); +void ath9k_hw_rf_free(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); void ath9k_hw_fill_cap_info(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 98b1b56..59bb3ce 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -264,7 +264,7 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, } void -ath9k_hw_rfdetach(struct ath_hw *ah) +ath9k_hw_rf_free(struct ath_hw *ah) { #define ATH_FREE_BANK(bank) do { \ kfree(bank); \ -- cgit v0.10.2 From e70c0cfdbf98384d9ce0b7a7332b6e60ec22ad54 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:51 -0700 Subject: ath9k: rename ath9k_hw_ani_detach() to ath9k_hw_ani_disable() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index a613cf4..b709312 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -822,9 +822,9 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ah->proc_phyerr |= HAL_PROCESS_ANI; } -void ath9k_hw_ani_detach(struct ath_hw *ah) +void ath9k_hw_ani_disable(struct ath_hw *ah) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n"); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n"); if (ah->has_hw_phycounters) { ath9k_hw_disable_mib_counters(ah); diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 803669f..a36b7bb 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -133,6 +133,6 @@ void ath9k_hw_procmibevent(struct ath_hw *ah, const struct ath9k_node_stats *stats); void ath9k_hw_ani_setup(struct ath_hw *ah); void ath9k_hw_ani_init(struct ath_hw *ah); -void ath9k_hw_ani_detach(struct ath_hw *ah); +void ath9k_hw_ani_disable(struct ath_hw *ah); #endif /* ANI_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 73dee19..6641fbe 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1227,7 +1227,7 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid) void ath9k_hw_detach(struct ath_hw *ah) { if (!AR_SREV_9100(ah)) - ath9k_hw_ani_detach(ah); + ath9k_hw_ani_disable(ah); ath9k_hw_rf_free(ah); ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); -- cgit v0.10.2 From 9db6b6a25fd829a0d29480785ac0770a1e76f9a4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:52 -0700 Subject: ath9k: set ah to null after freeing Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6641fbe..633fe8b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1232,6 +1232,7 @@ void ath9k_hw_detach(struct ath_hw *ah) ath9k_hw_rf_free(ah); ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); kfree(ah); + ah = NULL; } /*******/ -- cgit v0.10.2 From 3ce1b1a949ae849fb73556867e60977a65ca3141 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:53 -0700 Subject: ath9k: set sc->sc_ah to NULL after freeing it Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 91bffc9..d3d2cb6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1278,6 +1278,7 @@ void ath_detach(struct ath_softc *sc) ath_tx_cleanupq(sc, &sc->tx.txq[i]); ath9k_hw_detach(sc->sc_ah); + sc->sc_ah = NULL; ath9k_exit_debug(sc); } @@ -1521,6 +1522,7 @@ bad2: bad: if (ah) ath9k_hw_detach(ah); + sc->sc_ah = NULL; bad_no_ah: ath9k_exit_debug(sc); @@ -1631,6 +1633,7 @@ error_attach: ath_tx_cleanupq(sc, &sc->tx.txq[i]); ath9k_hw_detach(sc->sc_ah); + sc->sc_ah = NULL; ath9k_exit_debug(sc); return error; -- cgit v0.10.2 From 95fafca26dc317b7ea0667c57576b0b5389f5bef Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:54 -0700 Subject: ath9k: call ath9k_hw_detach() once upon hw init failure If hw initialization fails (ath9k_hw_init()) on ath_init_softc() we bail out and call ath9k_hw_detach(). The call ath9k_hw_detach() is conditional though as ath9k_hw_init() could itself have called ath9k_hw_detach(). Just describing this is itself a brain twister. Avoid this nonsense by removing ath9k_hw_detach() from ath9k_hw_init(). Upon hw initialization failure we expect the callers to take care of the cleanup. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 633fe8b..0871529 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -898,26 +898,22 @@ static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah) int ath9k_hw_init(struct ath_hw *ah) { - int r; + int r = 0; - if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { - r = -EOPNOTSUPP; - goto bad; - } + if (!ath9k_hw_devid_supported(ah->hw_version.devid)) + return -EOPNOTSUPP; ath9k_hw_init_defaults(ah); ath9k_hw_init_config(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); - r = -EIO; - goto bad; + return -EIO; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); - r = -EIO; - goto bad; + return -EIO; } if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { @@ -939,8 +935,7 @@ int ath9k_hw_init(struct ath_hw *ah) "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, ah->hw_version.macRev); - r = -EOPNOTSUPP; - goto bad; + return -EOPNOTSUPP; } if (AR_SREV_9100(ah)) { @@ -965,7 +960,7 @@ int ath9k_hw_init(struct ath_hw *ah) r = ath9k_hw_post_init(ah); if (r) - goto bad; + return r; ath9k_hw_init_mode_gain_regs(ah); ath9k_hw_fill_cap_info(ah); @@ -975,7 +970,7 @@ int ath9k_hw_init(struct ath_hw *ah) if (r) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Failed to initialize MAC address\n"); - goto bad; + return r; } if (AR_SREV_9285(ah)) @@ -986,9 +981,6 @@ int ath9k_hw_init(struct ath_hw *ah) ath9k_init_nfcal_hist_buffer(ah); return 0; -bad: - ath9k_hw_detach(ah); - return r; } static void ath9k_hw_init_bb(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d3d2cb6..a5475b7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1520,8 +1520,7 @@ bad2: if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); bad: - if (ah) - ath9k_hw_detach(ah); + ath9k_hw_detach(ah); sc->sc_ah = NULL; bad_no_ah: ath9k_exit_debug(sc); -- cgit v0.10.2 From 2f69ffacb303bba274b126eabd3a3ed011b2d35d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:55 -0700 Subject: ath9k: remove dangling error check on keycache reset on hw init The keycache reset will not fail as right above we ensure to set the sc->keymax to be <= ah->caps.keycache_size. Just remove this dangling check. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a5475b7..7f412dd 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1363,9 +1363,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) for (i = 0; i < sc->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - if (r) - goto bad; - /* default to MONITOR mode */ sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; -- cgit v0.10.2 From 39068d1c2810077377fc2ffcfbe380bfbed696cb Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:56 -0700 Subject: ath9k: remove spurious check for channel on keycache reset ath9k_hw_keyreset() has a spurious check for ah->curchan.. remove it. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0871529..0d60b35 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2496,9 +2496,6 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry) } - if (ah->curchan == NULL) - return true; - return true; } -- cgit v0.10.2 From 475f5989d4dc359046521cdfe9869cabf8c9fce9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 17:31:25 -0400 Subject: ath9k: Remove _t postfix for ar9287_eeprom structure We don't use typdefs on ath9k, remove that _t. Cc: Vivek Natarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index e8ccec0..80ece01 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -2794,7 +2794,7 @@ static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) { - struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; u16 *eep_data; int addr, eep_start_loc = AR9287_EEP_START_LOC; eep_data = (u16 *)eep; @@ -2803,7 +2803,7 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) "Reading from EEPROM, not flash\n"); } - for (addr = 0; addr < sizeof(struct ar9287_eeprom_t) / sizeof(u16); + for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); addr++) { if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, @@ -2816,12 +2816,12 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) } static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) { -#define SIZE_EEPROM_87 (sizeof(struct ar9287_eeprom_t) / sizeof(u16)) +#define SIZE_EEPROM_87 (sizeof(struct ar9287_eeprom) / sizeof(u16)) u32 sum = 0, el, integer; u16 temp, word, magic, magic2, *eepdata; int i, addr; bool need_swap = false; - struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; if (!ath9k_hw_use_flash(ah)) { if (!ath9k_hw_nvram_read @@ -2920,7 +2920,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, enum eeprom_param param) { - struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; u16 ver_minor; @@ -3210,7 +3210,7 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0}; u32 reg32, regOffset, regChainOffset; int16_t modalIdx, diff = 0; - struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; xpdMask = pEepData->modalHeader.xpdGain; if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= @@ -3380,7 +3380,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, struct chan_centers centers; int tx_chainmask; u16 twiceMinEdgePower; - struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; tx_chainmask = ah->txchainmask; ath9k_hw_get_channel_centers(ah, chan, ¢ers); @@ -3613,7 +3613,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, { #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 - struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; int16_t txPowerIndexOffset = 0; @@ -3776,7 +3776,7 @@ static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; u16 antWrites[AR9287_ANT_16S]; @@ -3928,7 +3928,7 @@ static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; return pModal->antCtrlCommon & 0xFFFF; } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 335098d..db77e90 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -600,7 +600,7 @@ struct ar5416_eeprom_4k { u8 padding; } __packed; -struct ar9287_eeprom_t { +struct ar9287_eeprom { struct base_eep_ar9287_header baseEepHeader; u8 custData[AR9287_DATA_SZ]; struct modal_eep_ar9287_header modalHeader; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4e717cc..9c23db1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -403,7 +403,7 @@ struct ath_hw { union { struct ar5416_eeprom_def def; struct ar5416_eeprom_4k map4k; - struct ar9287_eeprom_t map9287; + struct ar9287_eeprom map9287; } eeprom; const struct eeprom_ops *eep_ops; enum ath9k_eep_map eep_map; -- cgit v0.10.2 From edb1f9152f1f346381336554674f5d443fc5f473 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 23:14:10 -0400 Subject: ath9k: add ar9271 revision and subrevision ID helpers These will be used later to add support for ar9271. Cc: Stephen Chen Cc: Zhifeng Cai Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 8302aeb..37cbf03 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -744,6 +744,9 @@ #define AR_SREV_VERSION_9287 0x180 #define AR_SREV_REVISION_9287_10 0 #define AR_SREV_REVISION_9287_11 1 +#define AR_SREV_VERSION_9271 0x140 +#define AR_SREV_REVISION_9271_10 0 +#define AR_SREV_REVISION_9271_11 1 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -815,6 +818,15 @@ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11))) +#define AR_SREV_9271(_ah) \ + (((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271) +#define AR_SREV_9271_10(_ah) \ + (AR_SREV_9271(_ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_10)) +#define AR_SREV_9271_11(_ah) \ + (AR_SREV_9271(_ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11)) + #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 #define AR_RAD2133_SREV_MAJOR 0xd0 -- cgit v0.10.2 From 670388c5f56383e1d5b9f4f7fc835a280487754e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 23:14:11 -0400 Subject: ath9k: add initvals and registry definitions for AR9271 Cc: Stephen Chen Cc: Zhifeng Cai Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index af4a1ba..27a86bb 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -6365,3 +6365,669 @@ static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = { }; +/* AR9271 initialization values automaticaly created: 03/23/09 */ +static const u_int32_t ar9271Modes_9271_1_0[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e }, + { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18 }, + { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, + { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c }, + { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 }, + { 0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 }, + { 0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, + { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, + { 0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 }, + { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 }, + { 0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 }, + { 0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 }, + { 0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 }, + { 0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, + { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 }, + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 }, + { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, +}; + +static const u_int32_t ar9271Common_9271_1_0[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020045 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x02000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080b0, 0x00000000 }, + { 0x000080b4, 0x00000000 }, + { 0x000080b8, 0x00000000 }, + { 0x000080bc, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04814 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081d0, 0x0000320a }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000001 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x00010380 }, + { 0x00008344, 0x00581043 }, + { 0x00007010, 0x00000030 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00007800, 0x00140000 }, + { 0x00007804, 0x0e4548d8 }, + { 0x00007808, 0x54214514 }, + { 0x0000780c, 0x02025820 }, + { 0x00007810, 0x71c0d388 }, + { 0x00007814, 0x924934a8 }, + { 0x0000781c, 0x00000000 }, + { 0x00007820, 0x00000c04 }, + { 0x00007824, 0x00d86bff }, + { 0x00007828, 0x66964300 }, + { 0x0000782c, 0x8db6d961 }, + { 0x00007830, 0x8db6d96c }, + { 0x00007834, 0x6140008b }, + { 0x00007838, 0x00000029 }, + { 0x0000783c, 0x72ee0a72 }, + { 0x00007840, 0xbbfffffc }, + { 0x00007844, 0x000c0db6 }, + { 0x00007848, 0x6db61b6f }, + { 0x0000784c, 0x6d9b66db }, + { 0x00007850, 0x6d8c6dba }, + { 0x00007854, 0x00040000 }, + { 0x00007858, 0xdb003012 }, + { 0x0000785c, 0x04924914 }, + { 0x00007860, 0x21084210 }, + { 0x00007864, 0xf7d7ffde }, + { 0x00007868, 0xc2034080 }, + { 0x0000786c, 0x48609eb4 }, + { 0x00007870, 0x10142c00 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x30002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009940, 0x14750604 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x0108ecff }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x192bb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x2def0400 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x0000a1f4, 0x00000000 }, + { 0x0000a1f8, 0x71733d01 }, + { 0x0000a1fc, 0xd0ad5c12 }, + { 0x0000a208, 0x803e68c8 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x00206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0ccb5380 }, + { 0x0000a25c, 0x15151501 }, + { 0x0000a260, 0xdfa90f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9e6 }, + { 0x0000a278, 0x3bdef7bd }, + { 0x0000a27c, 0x050e83bd }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x3bdef7bd }, + { 0x0000a398, 0x000003bd }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x3bdef7bd }, + { 0x0000a3e0, 0x000003bd }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x0000a3f0, 0x01036a2f }, + { 0x0000a3f4, 0x00000000 }, + { 0x0000d270, 0x0d820820 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, +}; diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index de4fada..27bd93c 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -185,6 +185,9 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_PLL_CTL_44_2133 0xeb #define AR_PHY_PLL_CTL_40_2133 0xea +#define AR_PHY_SPECTRAL_SCAN 0x9912 +#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x1 + #define AR_PHY_RX_DELAY 0x9914 #define AR_PHY_SEARCH_START_DELAY 0x9918 #define AR_PHY_RX_DELAY_DELAY 0x00003FFF diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 37cbf03..13fd658 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1154,12 +1154,32 @@ enum { #define AR9285_AN_RF2G4_DB2_4 0x00003800 #define AR9285_AN_RF2G4_DB2_4_S 11 +/* AR9271 : 0x7828, 0x782c different setting from AR9285 */ +#define AR9271_AN_RF2G3_OB_cck 0x001C0000 +#define AR9271_AN_RF2G3_OB_cck_S 18 +#define AR9271_AN_RF2G3_OB_psk 0x00038000 +#define AR9271_AN_RF2G3_OB_psk_S 15 +#define AR9271_AN_RF2G3_OB_qam 0x00007000 +#define AR9271_AN_RF2G3_OB_qam_S 12 + +#define AR9271_AN_RF2G3_DB_1 0x00E00000 +#define AR9271_AN_RF2G3_DB_1_S 21 + +#define AR9271_AN_RF2G3_CCOMP 0xFFF +#define AR9271_AN_RF2G3_CCOMP_S 0 + +#define AR9271_AN_RF2G4_DB_2 0xE0000000 +#define AR9271_AN_RF2G4_DB_2_S 29 + #define AR9285_AN_RF2G6 0x7834 #define AR9285_AN_RF2G6_CCOMP 0x00007800 #define AR9285_AN_RF2G6_CCOMP_S 11 #define AR9285_AN_RF2G6_OFFS 0x03f00000 #define AR9285_AN_RF2G6_OFFS_S 20 +#define AR9271_AN_RF2G6_OFFS 0x07f00000 +#define AR9271_AN_RF2G6_OFFS_S 20 + #define AR9285_AN_RF2G7 0x7838 #define AR9285_AN_RF2G7_PWDDB 0x00000002 #define AR9285_AN_RF2G7_PWDDB_S 1 @@ -1220,6 +1240,11 @@ enum { #define AR9287_AN_TOP2_XPABIAS_LVL 0xC0000000 #define AR9287_AN_TOP2_XPABIAS_LVL_S 30 +/* AR9271 specific stuff */ +#define AR9271_RESET_POWER_DOWN_CONTROL 0x50044 +#define AR9271_RADIO_RF_RST 0x20 +#define AR9271_GATE_MAC_CTL 0x4000 + #define AR_STA_ID0 0x8000 #define AR_STA_ID1 0x8004 #define AR_STA_ID1_SADH_MASK 0x0000FFFF -- cgit v0.10.2 From d7e7d229c7d1395283e1e1fda8727af60ca6f4ad Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 23:14:12 -0400 Subject: ath9k: add initial hardware support for ar9271 We will finalize this after some driver core changes, for now we leave this unsupported. Cc: Stephen Chen Cc: Zhifeng Cai Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index d1bbb02..26d8752 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -753,6 +753,98 @@ static void ath9k_olc_temp_compensation(struct ath_hw *ah) } } +static void ath9k_hw_9271_pa_cal(struct ath_hw *ah) +{ + u32 regVal; + unsigned int i; + u32 regList [][2] = { + { 0x786c, 0 }, + { 0x7854, 0 }, + { 0x7820, 0 }, + { 0x7824, 0 }, + { 0x7868, 0 }, + { 0x783c, 0 }, + { 0x7838, 0 } , + { 0x7828, 0 } , + }; + + for (i = 0; i < ARRAY_SIZE(regList); i++) + regList[i][1] = REG_READ(ah, regList[i][0]); + + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1)); + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal |= (0x1 << 27); + REG_WRITE(ah, 0x9808, regVal); + + /* 786c,b23,1, pwddac=1 */ + REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); + /* 7854, b5,1, pdrxtxbb=1 */ + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); + /* 7854, b7,1, pdv2i=1 */ + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); + /* 7854, b8,1, pddacinterface=1 */ + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); + /* 7824,b12,0, offcal=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); + /* 7838, b1,0, pwddb=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); + /* 7820,b11,0, enpacal=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); + /* 7820,b25,1, pdpadrv1=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); + /* 7820,b24,0, pdpadrv2=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1,AR9285_AN_RF2G1_PDPADRV2,0); + /* 7820,b23,0, pdpaout=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); + /* 783c,b14-16,7, padrvgn2tab_0=7 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G8,AR9285_AN_RF2G8_PADRVGN2TAB0, 7); + /* + * 7838,b29-31,0, padrvgn1tab_0=0 + * does not matter since we turn it off + */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G7,AR9285_AN_RF2G7_PADRVGN2TAB0, 0); + + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff); + + /* Set: + * localmode=1,bmode=1,bmoderxtx=1,synthon=1, + * txon=1,paon=1,oscon=1,synthon_force=1 + */ + REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); + udelay(30); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0); + + /* find off_6_1; */ + for (i = 6; i >= 0; i--) { + regVal = REG_READ(ah, 0x7834); + regVal |= (1 << (20 + i)); + REG_WRITE(ah, 0x7834, regVal); + udelay(1); + //regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1 << (20 + i))); + regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9) + << (20 + i)); + REG_WRITE(ah, 0x7834, regVal); + } + + /* Empirical offset correction */ +#if 0 + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0x20); +#endif + + regVal = REG_READ(ah, 0x7834); + regVal |= 0x1; + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal &= (~(0x1 << 27)); + REG_WRITE(ah, 0x9808, regVal); + + for (i = 0; i < ARRAY_SIZE(regList); i++) + REG_WRITE(ah, regList[i][0], regList[i][1]); +} + static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) { @@ -869,14 +961,26 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, } } + /* Do NF cal only at longer intervals */ if (longcal) { - if (AR_SREV_9285_11_OR_LATER(ah)) + /* Do periodic PAOffset Cal */ + if (AR_SREV_9271(ah)) + ath9k_hw_9271_pa_cal(ah); + else if (AR_SREV_9285_11_OR_LATER(ah)) ath9k_hw_9285_pa_cal(ah); if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER) ath9k_olc_temp_compensation(ah); + + /* Get the value from the previous NF cal and update history buffer */ ath9k_hw_getnf(ah, chan); + + /* + * Load the NF from history buffer of the current channel. + * NF is slow time-variant, so it is OK to use a historical value. + */ ath9k_hw_loadnf(ah, ah->curchan); + ath9k_hw_start_nfcal(ah); } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 80ece01..9a09cc8 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -1237,6 +1237,10 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); } +/* + * Read EEPROM header info and program the device for correct operation + * given the channel value. + */ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -1313,38 +1317,110 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, } } - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]); - - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]); - - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]); + if (AR_SREV_9271(ah)) { + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_cck, + AR9271_AN_RF2G3_OB_cck_S, + ob[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_psk, + AR9271_AN_RF2G3_OB_psk_S, + ob[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_qam, + AR9271_AN_RF2G3_OB_qam_S, + ob[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_DB_1, + AR9271_AN_RF2G3_DB_1_S, + db1[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9271_AN_RF2G4_DB_2, + AR9271_AN_RF2G4_DB_2_S, + db2[0]); + } else { + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_0, + AR9285_AN_RF2G3_OB_0_S, + ob[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_1, + AR9285_AN_RF2G3_OB_1_S, + ob[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_2, + AR9285_AN_RF2G3_OB_2_S, + ob[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_3, + AR9285_AN_RF2G3_OB_3_S, + ob[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_4, + AR9285_AN_RF2G3_OB_4_S, + ob[4]); + + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_0, + AR9285_AN_RF2G3_DB1_0_S, + db1[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_1, + AR9285_AN_RF2G3_DB1_1_S, + db1[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_2, + AR9285_AN_RF2G3_DB1_2_S, + db1[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_3, + AR9285_AN_RF2G4_DB1_3_S, + db1[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_4, + AR9285_AN_RF2G4_DB1_4_S, db1[4]); + + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_0, + AR9285_AN_RF2G4_DB2_0_S, + db2[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_1, + AR9285_AN_RF2G4_DB2_1_S, + db2[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_2, + AR9285_AN_RF2G4_DB2_2_S, + db2[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_3, + AR9285_AN_RF2G4_DB2_3_S, + db2[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_4, + AR9285_AN_RF2G4_DB2_4_S, + db2[4]); + } if (AR_SREV_9285_11(ah)) @@ -3984,7 +4060,7 @@ int ath9k_hw_eeprom_init(struct ath_hw *ah) if (AR_SREV_9287(ah)) { ah->eep_map = EEP_MAP_AR9287; ah->eep_ops = &eep_AR9287_ops; - } else if (AR_SREV_9285(ah)) { + } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) { ah->eep_map = EEP_MAP_4KBITS; ah->eep_ops = &eep_4k_ops; } else { diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0d60b35..71a3bcc 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -638,6 +638,8 @@ static bool ath9k_hw_macversion_supported(u32 macversion) case AR_SREV_VERSION_9285: case AR_SREV_VERSION_9287: return true; + /* Not yet */ + case AR_SREV_VERSION_9271: default: break; } @@ -670,6 +672,14 @@ static void ath9k_hw_init_cal_settings(struct ath_hw *ah) static void ath9k_hw_init_mode_regs(struct ath_hw *ah) { + if (AR_SREV_9271(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271_1_0, + ARRAY_SIZE(ar9271Modes_9271_1_0), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271_1_0, + ARRAY_SIZE(ar9271Common_9271_1_0), 2); + return; + } + if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, ARRAY_SIZE(ar9287Modes_9287_1_1), 6); @@ -943,6 +953,10 @@ int ath9k_hw_init(struct ath_hw *ah) ah->supp_cals = IQ_MISMATCH_CAL; ah->is_pciexpress = false; } + + if (AR_SREV_9271(ah)) + ah->is_pciexpress = false; + ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); ath9k_hw_init_cal_settings(ah); @@ -973,7 +987,7 @@ int ath9k_hw_init(struct ath_hw *ah) return r; } - if (AR_SREV_9285(ah)) + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S); else ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); @@ -1234,6 +1248,27 @@ void ath9k_hw_detach(struct ath_hw *ah) static void ath9k_hw_override_ini(struct ath_hw *ah, struct ath9k_channel *chan) { + u32 val; + + if (AR_SREV_9271(ah)) { + /* + * Enable spectral scan to solution for issues with stuck + * beacons on AR9271 1.0. The beacon stuck issue is not seeon on + * AR9271 1.1 + */ + if (AR_SREV_9271_10(ah)) { + val = REG_READ(ah, AR_PHY_SPECTRAL_SCAN) | AR_PHY_SPECTRAL_SCAN_ENABLE; + REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val); + } + else if (AR_SREV_9271_11(ah)) + /* + * change AR_PHY_RF_CTL3 setting to fix MAC issue + * present on AR9271 1.1 + */ + REG_WRITE(ah, AR_PHY_RF_CTL3, 0x3a020001); + return; + } + /* * Set the RX_ABORT and RX_DIS and clear if off only after * RXE is set for MAC. This prevents frames with corrupted @@ -1245,7 +1280,10 @@ static void ath9k_hw_override_ini(struct ath_hw *ah, if (!AR_SREV_5416_20_OR_LATER(ah) || AR_SREV_9280_10_OR_LATER(ah)) return; - + /* + * Disable BB clock gating + * Necessary to avoid issues on AR5416 2.0 + */ REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); } @@ -1477,23 +1515,48 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) { u32 regval; + /* + * set AHB_MODE not to do cacheline prefetches + */ regval = REG_READ(ah, AR_AHB_MODE); REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); + /* + * let mac dma reads be in 128 byte chunks + */ regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + /* + * Restore TX Trigger Level to its pre-reset value. + * The initial value depends on whether aggregation is enabled, and is + * adjusted whenever underruns are detected. + */ REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level); + /* + * let mac dma writes be in 128 byte chunks + */ regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + /* + * Setup receive FIFO threshold to hold off TX activities + */ REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + /* + * reduce the number of usable entries in PCU TXBUF to avoid + * wrap around issues. + */ if (AR_SREV_9285(ah)) { + /* For AR9285 the number of Fifos are reduced to half. + * So set the usable tx buf size also to half to + * avoid data/delimiter underruns + */ REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); - } else { + } else if (!AR_SREV_9271(ah)) { REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE); } @@ -2299,11 +2362,26 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_mark_phy_inactive(ah); + if (AR_SREV_9271(ah) && ah->htc_reset_init) { + REG_WRITE(ah, + AR9271_RESET_POWER_DOWN_CONTROL, + AR9271_RADIO_RF_RST); + udelay(50); + } + if (!ath9k_hw_chip_reset(ah, chan)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n"); return -EINVAL; } + if (AR_SREV_9271(ah) && ah->htc_reset_init) { + ah->htc_reset_init = false; + REG_WRITE(ah, + AR9271_RESET_POWER_DOWN_CONTROL, + AR9271_GATE_MAC_CTL); + udelay(50); + } + if (AR_SREV_9280_10_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); @@ -2439,6 +2517,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ); + /* + * For big endian systems turn on swapping for descriptors + */ if (AR_SREV_9100(ah)) { u32 mask; mask = REG_READ(ah, AR_CFG); @@ -2453,8 +2534,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, "Setting CFG 0x%x\n", REG_READ(ah, AR_CFG)); } } else { + /* Configure AR9271 target WLAN */ + if (AR_SREV_9271(ah)) + REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB); #ifdef __BIG_ENDIAN - REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); + else + REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); #endif } @@ -2981,7 +3066,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) if (ah->config.pcie_waen) { REG_WRITE(ah, AR_WA, ah->config.pcie_waen); } else { - if (AR_SREV_9285(ah)) + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); /* * On AR9280 chips bit 22 of 0x4004 needs to be set to @@ -3445,10 +3530,17 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) } pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); + /* + * For AR9271 we will temporarilly uses the rx chainmax as read from + * the EEPROM. + */ if ((ah->hw_version.devid == AR5416_DEVID_PCI) && - !(eeval & AR5416_OPFLAGS_11A)) + !(eeval & AR5416_OPFLAGS_11A) && + !(AR_SREV_9271(ah))) + /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */ pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; else + /* Use rx_chainmask from EEPROM. */ pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0))) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 9c23db1..d4aaf4f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -419,6 +419,8 @@ struct ath_hw { u32 wlanactive_gpio; u32 ah_flags; + bool htc_reset_init; + enum nl80211_iftype opmode; enum ath9k_power_mode power_mode; -- cgit v0.10.2 From e48e3a2f17f189deb086ff221e489e7fd8ec4302 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 24 Jul 2009 20:47:33 -0400 Subject: ath9k: cancel xmit poll work at stop() callback We forgot to cancel this work at the stop() callback. ------------[ cut here ]------------ WARNING: at net/mac80211/util.c:511 ieee80211_queue_delayed_work+0x3a/0x40 [mac80211]() Hardware name: 6460DWU queueing ieee80211 work while going to suspend Modules linked in: <-- snip --> Pid: 5124, comm: phy0 Tainted: G W 2.6.31-rc3-wl #4 Call Trace: [] ? ieee80211_queue_delayed_work+0x3a/0x40 [mac80211] [] warn_slowpath_common+0x78/0xd0 [] warn_slowpath_fmt+0x64/0x70 [] ? thread_return+0x3e/0x635 [] ieee80211_queue_delayed_work+0x3a/0x40 [mac80211] [] ath_tx_complete_poll_work+0xc0/0x100 [ath9k] [] ? ath_tx_complete_poll_work+0x0/0x100 [ath9k] [] worker_thread+0x178/0x260 [] ? autoremove_wake_function+0x0/0x40 [] ? worker_thread+0x0/0x260 [] kthread+0x9e/0xb0 [] child_rip+0xa/0x20 [] ? kthread+0x0/0xb0 [] ? child_rip+0x0/0x20 Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7f412dd..a9e43f7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2117,6 +2117,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); + cancel_delayed_work_sync(&sc->tx_complete_work); + if (ath9k_wiphy_started(sc)) { mutex_unlock(&sc->mutex); return; /* another wiphy still in use */ -- cgit v0.10.2 From e3b90ca28412fb9dcc8c5ca38e179e78fec07eee Mon Sep 17 00:00:00 2001 From: Igor Perminov Date: Tue, 4 Aug 2009 16:48:51 +0400 Subject: mac80211: FIF_PSPOLL filter flag When an interface is configured in the AP mode, the mac80211 implementation doesn't inform the driver to receive PS Poll frames. It leads to inability to communicate with power-saving stations reliably. The FIF_CONTROL flag isn't passed by mac80211 to ieee80211_ops.configure_filter when an interface is in the AP mode. And it's ok, because we don't want to receive ACK frames and other control ones, but only PS Poll ones. This patch introduces the FIF_PSPOLL filter flag in addition to FIF_CONTROL, which means for the driver "pass PS Poll frames". This flag is passed to the driver: A) When an interface is configured in the AP mode. B) In all cases, when the FIF_CONTROL flag was passed earlier (in addition to it). Signed-off-by: Igor Perminov Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5ed93f4..e2fb576 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1244,10 +1244,13 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * mac80211 needs to do and the amount of CPU wakeups, so you should * honour this flag if possible. * - * @FIF_CONTROL: pass control frames, if PROMISC_IN_BSS is not set then - * only those addressed to this station + * @FIF_CONTROL: pass control frames (except for PS Poll), if PROMISC_IN_BSS + * is not set then only those addressed to this station. * * @FIF_OTHER_BSS: pass frames destined to other BSSes + * + * @FIF_PSPOLL: pass PS Poll frames, if PROMISC_IN_BSS is not set then only + * those addressed to this station. */ enum ieee80211_filter_flags { FIF_PROMISC_IN_BSS = 1<<0, @@ -1257,6 +1260,7 @@ enum ieee80211_filter_flags { FIF_BCN_PRBRESP_PROMISC = 1<<4, FIF_CONTROL = 1<<5, FIF_OTHER_BSS = 1<<6, + FIF_PSPOLL = 1<<7, }; /** diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8d790e4..630a438 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -628,7 +628,7 @@ struct ieee80211_local { int open_count; int monitors, cooked_mntrs; /* number of interfaces with corresponding FIF_ flags */ - int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; + int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll; unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8c1284d..e8fb03b 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -220,8 +220,10 @@ static int ieee80211_open(struct net_device *dev) local->fif_fcsfail++; if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) local->fif_plcpfail++; - if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { local->fif_control++; + local->fif_pspoll++; + } if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss++; @@ -244,7 +246,14 @@ static int ieee80211_open(struct net_device *dev) spin_unlock_bh(&local->filter_lock); ieee80211_start_mesh(sdata); + } else if (sdata->vif.type == NL80211_IFTYPE_AP) { + local->fif_pspoll++; + + spin_lock_bh(&local->filter_lock); + ieee80211_configure_filter(local); + spin_unlock_bh(&local->filter_lock); } + changed |= ieee80211_reset_erp_info(sdata); ieee80211_bss_info_change_notify(sdata, changed); ieee80211_enable_keys(sdata); @@ -388,6 +397,9 @@ static int ieee80211_stop(struct net_device *dev) if (sdata->flags & IEEE80211_SDATA_PROMISC) atomic_dec(&local->iff_promiscs); + if (sdata->vif.type == NL80211_IFTYPE_AP) + local->fif_pspoll--; + netif_addr_lock_bh(dev); spin_lock_bh(&local->filter_lock); __dev_addr_unsync(&local->mc_list, &local->mc_count, @@ -439,8 +451,10 @@ static int ieee80211_stop(struct net_device *dev) local->fif_fcsfail--; if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) local->fif_plcpfail--; - if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { + local->fif_pspoll--; local->fif_control--; + } if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss--; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 22e0738..0c4f8e1 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -77,6 +77,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (local->fif_other_bss) new_flags |= FIF_OTHER_BSS; + if (local->fif_pspoll) + new_flags |= FIF_PSPOLL; + changed_flags = local->filter_flags ^ new_flags; /* be a bit nasty */ -- cgit v0.10.2 From 6b4f645a491ac29c7dced415d034eea7736155a6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 13:51:49 -0700 Subject: ath9k: fix compile warning on ath9k_hw_AR9287_check_eeprom() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/ath/ath9k/eeprom.o drivers/net/wireless/ath/ath9k/eeprom.c: In function ‘ath9k_hw_AR9287_check_eeprom’: drivers/net/wireless/ath/ath9k/eeprom.c:2866: warning: comparison of distinct pointer types lacks a cast Cc: Vivek Natarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 9a09cc8..4cb64a0 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -2892,7 +2892,6 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) } static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) { -#define SIZE_EEPROM_87 (sizeof(struct ar9287_eeprom) / sizeof(u16)) u32 sum = 0, el, integer; u16 temp, word, magic, magic2, *eepdata; int i, addr; @@ -2918,7 +2917,9 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) need_swap = true; eepdata = (u16 *)(&ah->eeprom); - for (addr = 0; addr < SIZE_EEPROM_87; addr++) { + for (addr = 0; + addr < sizeof(struct ar9287_eeprom) / sizeof(u16); + addr++) { temp = swab16(*eepdata); *eepdata = temp; eepdata++; @@ -2938,8 +2939,13 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) else el = ah->eeprom.map9287.baseEepHeader.length; + if (el > sizeof(struct ar9287_eeprom)) + el = sizeof(struct ar9287_eeprom) / sizeof(u16); + else + el = el / sizeof(u16); + eepdata = (u16 *)(&ah->eeprom); - for (i = 0; i < min(el, SIZE_EEPROM_87); i++) + for (i = 0; i < el; i++) sum ^= *eepdata++; if (need_swap) { @@ -2990,7 +2996,6 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) } return 0; -#undef SIZE_EEPROM_87 } static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, -- cgit v0.10.2 From f816700aa9ef1b1e2f984f638cb211e79dcab495 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 4 Aug 2009 20:18:33 -0700 Subject: xfrm4: fix build when SYSCTLs are disabled Fix build errors when SYSCTLs are not enabled: (.init.text+0x5154): undefined reference to `net_ipv4_ctl_path' (.init.text+0x5176): undefined reference to `register_net_sysctl_table' xfrm4_policy.c:(.exit.text+0x573): undefined reference to `unregister_net_sysctl_table Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 1ba4474..74fb2eb 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -264,6 +264,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { .fill_dst = xfrm4_fill_dst, }; +#ifdef CONFIG_SYSCTL static struct ctl_table xfrm4_policy_table[] = { { .ctl_name = CTL_UNNUMBERED, @@ -277,6 +278,7 @@ static struct ctl_table xfrm4_policy_table[] = { }; static struct ctl_table_header *sysctl_hdr; +#endif static void __init xfrm4_policy_init(void) { @@ -285,8 +287,10 @@ static void __init xfrm4_policy_init(void) static void __exit xfrm4_policy_fini(void) { +#ifdef CONFIG_SYSCTL if (sysctl_hdr) unregister_net_sysctl_table(sysctl_hdr); +#endif xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo); } @@ -305,7 +309,9 @@ void __init xfrm4_init(int rt_max_size) * and start cleaning when were 1/2 full */ xfrm4_dst_ops.gc_thresh = rt_max_size/2; +#ifdef CONFIG_SYSCTL sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv4_ctl_path, xfrm4_policy_table); +#endif } -- cgit v0.10.2 From db71789c01ae7b641f83c5aa64e7df25122f4b28 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 4 Aug 2009 20:32:16 -0700 Subject: xfrm6: Fix xfrm6_policy.c build when SYSCTL disabled. Same as how Randy Dunlap fixed the ipv4 side of things. Signed-off-by: David S. Miller diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 611cffc..8ec3d45 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -306,6 +306,7 @@ static void xfrm6_policy_fini(void) xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo); } +#ifdef CONFIG_SYSCTL static struct ctl_table xfrm6_policy_table[] = { { .ctl_name = CTL_UNNUMBERED, @@ -319,6 +320,7 @@ static struct ctl_table xfrm6_policy_table[] = { }; static struct ctl_table_header *sysctl_hdr; +#endif int __init xfrm6_init(void) { @@ -345,9 +347,10 @@ int __init xfrm6_init(void) */ gc_thresh = FIB6_TABLE_HASHSZ * 8; xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh; - +#ifdef CONFIG_SYSCTL sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv6_ctl_path, xfrm6_policy_table); +#endif out: return ret; out_policy: @@ -357,8 +360,10 @@ out_policy: void xfrm6_fini(void) { +#ifdef CONFIG_SYSCTL if (sysctl_hdr) unregister_net_sysctl_table(sysctl_hdr); +#endif //xfrm6_input_fini(); xfrm6_policy_fini(); xfrm6_state_fini(); -- cgit v0.10.2 From 2977fb3ffc8493a2f4f0a362e8660a6cde9f1bb9 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 1 Aug 2009 11:47:59 +0400 Subject: x86, ioapic: Introduce for_each_irq_pin() helper This allow us to save a few lines of code. Signed-off-by: Cyrill Gorcunov Cc: yinghai@kernel.org LKML-Reference: <20090801075435.597863129@openvz.org> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 7e92a92..ffd8fdf 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -66,6 +66,8 @@ #include #define __apicdebuginit(type) static type __init +#define for_each_irq_pin(entry, head) \ + for (entry = head; entry; entry = entry->next) /* * Is the SiS APIC rmw bug present ? @@ -410,7 +412,7 @@ static bool io_apic_level_ack_pending(struct irq_cfg *cfg) unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); - for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) { + for_each_irq_pin(entry, cfg->irq_2_pin) { unsigned int reg; int pin; @@ -490,22 +492,21 @@ static void ioapic_mask_entry(int apic, int pin) */ static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin) { - struct irq_pin_list **entryp, *entry; + struct irq_pin_list **last, *entry; - for (entryp = &cfg->irq_2_pin; - *entryp != NULL; - entryp = &(*entryp)->next) { - entry = *entryp; - /* not again, please */ + /* don't allow duplicates */ + last = &cfg->irq_2_pin; + for_each_irq_pin(entry, cfg->irq_2_pin) { if (entry->apic == apic && entry->pin == pin) return; + last = &entry->next; } entry = get_one_free_irq_2_pin(node); entry->apic = apic; entry->pin = pin; - *entryp = entry; + *last = entry; } /* @@ -517,7 +518,7 @@ static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node, { struct irq_pin_list *entry; - for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) { + for_each_irq_pin(entry, cfg->irq_2_pin) { if (entry->apic == oldapic && entry->pin == oldpin) { entry->apic = newapic; entry->pin = newpin; @@ -537,7 +538,7 @@ static void io_apic_modify_irq(struct irq_cfg *cfg, int pin; struct irq_pin_list *entry; - for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) { + for_each_irq_pin(entry, cfg->irq_2_pin) { unsigned int reg; pin = entry->pin; reg = io_apic_read(entry->apic, 0x10 + pin * 2); @@ -1669,12 +1670,8 @@ __apicdebuginit(void) print_IO_APIC(void) if (!entry) continue; printk(KERN_DEBUG "IRQ%d ", irq); - for (;;) { + for_each_irq_pin(entry, cfg->irq_2_pin) printk("-> %d:%d", entry->apic, entry->pin); - if (!entry->next) - break; - entry = entry->next; - } printk("\n"); } @@ -2227,7 +2224,7 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq struct irq_pin_list *entry; u8 vector = cfg->vector; - for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) { + for_each_irq_pin(entry, cfg->irq_2_pin) { unsigned int reg; apic = entry->apic; @@ -2556,20 +2553,10 @@ static void ack_apic_level(unsigned int irq) #ifdef CONFIG_INTR_REMAP static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg) { - int apic, pin; struct irq_pin_list *entry; - entry = cfg->irq_2_pin; - for (;;) { - - if (!entry) - break; - - apic = entry->apic; - pin = entry->pin; - io_apic_eoi(apic, pin); - entry = entry->next; - } + for_each_irq_pin(entry, cfg->irq_2_pin) + io_apic_eoi(entry->apic, entry->pin); } static void -- cgit v0.10.2 From a7428cd2ef77734465e36bceb43290e37e2a97c6 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sat, 1 Aug 2009 11:48:00 +0400 Subject: x86, ioapic: Throw BUG instead of NULL dereference Instead of plain NULL deref we better throw error message with a backtrace. Actually we need more gracious error handling here. Meanwhile leave it as is. Signed-off-by: Cyrill Gorcunov Cc: yinghai@kernel.org LKML-Reference: <20090801075435.769301745@openvz.org> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index ffd8fdf..2a145d3 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -503,6 +503,10 @@ static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin } entry = get_one_free_irq_2_pin(node); + if (!entry) { + printk(KERN_ERR "can not alloc irq_pin_list\n"); + BUG_ON(1); + } entry->apic = apic; entry->pin = pin; -- cgit v0.10.2 From 9910887af84e33ba98fd6792029470ae80166208 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 23 Jul 2009 00:52:59 +0400 Subject: x86, apic: Drop redundant bit assignment cpu_has_apic has already investigated boot_cpu_data X86_FEATURE_APIC bit for being clear if condition is triggered. So there is no need to clear this bit second time. Signed-off-by: Cyrill Gorcuno v Cc: "Maciej W. Rozycki" LKML-Reference: <20090722205259.GE15805@lenovo> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 0a1c283..0b021c5 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1651,7 +1651,6 @@ int __init APIC_init_uniprocessor(void) APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { pr_err("BIOS bug, local APIC 0x%x not detected!...\n", boot_cpu_physical_apicid); - clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); return -1; } #endif -- cgit v0.10.2 From cbdcf80d8b9486ddb699a044c6f87f25821708cb Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Wed, 5 Aug 2009 19:35:34 +1000 Subject: crypto: authenc - Convert to ahash This patch converts authenc to the new ahash interface. Signed-off-by: Steffen Klassert Signed-off-by: Herbert Xu diff --git a/crypto/authenc.c b/crypto/authenc.c index 2e16ce0..4d6f49a 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -23,24 +23,36 @@ #include #include +typedef u8 *(*authenc_ahash_t)(struct aead_request *req, unsigned int flags); + struct authenc_instance_ctx { - struct crypto_spawn auth; + struct crypto_ahash_spawn auth; struct crypto_skcipher_spawn enc; }; struct crypto_authenc_ctx { - spinlock_t auth_lock; - struct crypto_hash *auth; + unsigned int reqoff; + struct crypto_ahash *auth; struct crypto_ablkcipher *enc; }; +struct authenc_request_ctx { + unsigned int cryptlen; + struct scatterlist *sg; + struct scatterlist asg[2]; + struct scatterlist cipher[2]; + crypto_completion_t complete; + crypto_completion_t update_complete; + char tail[]; +}; + static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, unsigned int keylen) { unsigned int authkeylen; unsigned int enckeylen; struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); - struct crypto_hash *auth = ctx->auth; + struct crypto_ahash *auth = ctx->auth; struct crypto_ablkcipher *enc = ctx->enc; struct rtattr *rta = (void *)key; struct crypto_authenc_key_param *param; @@ -64,11 +76,11 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, authkeylen = keylen - enckeylen; - crypto_hash_clear_flags(auth, CRYPTO_TFM_REQ_MASK); - crypto_hash_set_flags(auth, crypto_aead_get_flags(authenc) & + crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK); + crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc) & CRYPTO_TFM_REQ_MASK); - err = crypto_hash_setkey(auth, key, authkeylen); - crypto_aead_set_flags(authenc, crypto_hash_get_flags(auth) & + err = crypto_ahash_setkey(auth, key, authkeylen); + crypto_aead_set_flags(authenc, crypto_ahash_get_flags(auth) & CRYPTO_TFM_RES_MASK); if (err) @@ -103,40 +115,198 @@ static void authenc_chain(struct scatterlist *head, struct scatterlist *sg, sg_mark_end(head); } -static u8 *crypto_authenc_hash(struct aead_request *req, unsigned int flags, - struct scatterlist *cipher, - unsigned int cryptlen) +static void authenc_geniv_ahash_update_done(struct crypto_async_request *areq, + int err) +{ + struct aead_request *req = areq->data; + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); + struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); + + if (err) + goto out; + + ahash_request_set_crypt(ahreq, areq_ctx->sg, ahreq->result, + areq_ctx->cryptlen); + ahash_request_set_callback(ahreq, aead_request_flags(req) & + CRYPTO_TFM_REQ_MAY_SLEEP, + areq_ctx->complete, req); + + err = crypto_ahash_finup(ahreq); + if (err) + goto out; + + scatterwalk_map_and_copy(ahreq->result, areq_ctx->sg, + areq_ctx->cryptlen, + crypto_aead_authsize(authenc), 1); + +out: + aead_request_complete(req, err); +} + +static void authenc_geniv_ahash_done(struct crypto_async_request *areq, int err) +{ + struct aead_request *req = areq->data; + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); + struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); + + if (err) + goto out; + + scatterwalk_map_and_copy(ahreq->result, areq_ctx->sg, + areq_ctx->cryptlen, + crypto_aead_authsize(authenc), 1); + +out: + aead_request_complete(req, err); +} + +static void authenc_verify_ahash_update_done(struct crypto_async_request *areq, + int err) { + u8 *ihash; + unsigned int authsize; + struct ablkcipher_request *abreq; + struct aead_request *req = areq->data; struct crypto_aead *authenc = crypto_aead_reqtfm(req); struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); - struct crypto_hash *auth = ctx->auth; - struct hash_desc desc = { - .tfm = auth, - .flags = aead_request_flags(req) & flags, - }; - u8 *hash = aead_request_ctx(req); + struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); + struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); + + if (err) + goto out; + + ahash_request_set_crypt(ahreq, areq_ctx->sg, ahreq->result, + areq_ctx->cryptlen); + ahash_request_set_callback(ahreq, aead_request_flags(req) & + CRYPTO_TFM_REQ_MAY_SLEEP, + areq_ctx->complete, req); + + err = crypto_ahash_finup(ahreq); + if (err) + goto out; + + authsize = crypto_aead_authsize(authenc); + ihash = ahreq->result + authsize; + scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, + authsize, 0); + + err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG: 0; + if (err) + goto out; + + abreq = aead_request_ctx(req); + ablkcipher_request_set_tfm(abreq, ctx->enc); + ablkcipher_request_set_callback(abreq, aead_request_flags(req), + req->base.complete, req->base.data); + ablkcipher_request_set_crypt(abreq, req->src, req->dst, + req->cryptlen, req->iv); + + err = crypto_ablkcipher_decrypt(abreq); + +out: + aead_request_complete(req, err); +} + +static void authenc_verify_ahash_done(struct crypto_async_request *areq, + int err) +{ + u8 *ihash; + unsigned int authsize; + struct ablkcipher_request *abreq; + struct aead_request *req = areq->data; + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); + struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); + + if (err) + goto out; + + authsize = crypto_aead_authsize(authenc); + ihash = ahreq->result + authsize; + scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, + authsize, 0); + + err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG: 0; + if (err) + goto out; + + abreq = aead_request_ctx(req); + ablkcipher_request_set_tfm(abreq, ctx->enc); + ablkcipher_request_set_callback(abreq, aead_request_flags(req), + req->base.complete, req->base.data); + ablkcipher_request_set_crypt(abreq, req->src, req->dst, + req->cryptlen, req->iv); + + err = crypto_ablkcipher_decrypt(abreq); + +out: + aead_request_complete(req, err); +} + +static u8 *crypto_authenc_ahash_fb(struct aead_request *req, unsigned int flags) +{ + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + struct crypto_ahash *auth = ctx->auth; + struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); + struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); + u8 *hash = areq_ctx->tail; int err; - hash = (u8 *)ALIGN((unsigned long)hash + crypto_hash_alignmask(auth), - crypto_hash_alignmask(auth) + 1); + hash = (u8 *)ALIGN((unsigned long)hash + crypto_ahash_alignmask(auth), + crypto_ahash_alignmask(auth) + 1); + + ahash_request_set_tfm(ahreq, auth); - spin_lock_bh(&ctx->auth_lock); - err = crypto_hash_init(&desc); + err = crypto_ahash_init(ahreq); if (err) - goto auth_unlock; + return ERR_PTR(err); + + ahash_request_set_crypt(ahreq, req->assoc, hash, req->assoclen); + ahash_request_set_callback(ahreq, aead_request_flags(req) & flags, + areq_ctx->update_complete, req); - err = crypto_hash_update(&desc, req->assoc, req->assoclen); + err = crypto_ahash_update(ahreq); if (err) - goto auth_unlock; + return ERR_PTR(err); + + ahash_request_set_crypt(ahreq, areq_ctx->sg, hash, + areq_ctx->cryptlen); + ahash_request_set_callback(ahreq, aead_request_flags(req) & flags, + areq_ctx->complete, req); - err = crypto_hash_update(&desc, cipher, cryptlen); + err = crypto_ahash_finup(ahreq); if (err) - goto auth_unlock; + return ERR_PTR(err); - err = crypto_hash_final(&desc, hash); -auth_unlock: - spin_unlock_bh(&ctx->auth_lock); + return hash; +} + +static u8 *crypto_authenc_ahash(struct aead_request *req, unsigned int flags) +{ + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + struct crypto_ahash *auth = ctx->auth; + struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); + struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); + u8 *hash = areq_ctx->tail; + int err; + hash = (u8 *)ALIGN((unsigned long)hash + crypto_ahash_alignmask(auth), + crypto_ahash_alignmask(auth) + 1); + + ahash_request_set_tfm(ahreq, auth); + ahash_request_set_crypt(ahreq, areq_ctx->sg, hash, + areq_ctx->cryptlen); + ahash_request_set_callback(ahreq, aead_request_flags(req) & flags, + areq_ctx->complete, req); + + err = crypto_ahash_digest(ahreq); if (err) return ERR_PTR(err); @@ -147,11 +317,15 @@ static int crypto_authenc_genicv(struct aead_request *req, u8 *iv, unsigned int flags) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); struct scatterlist *dst = req->dst; - struct scatterlist cipher[2]; - struct page *dstp; + struct scatterlist *assoc = req->assoc; + struct scatterlist *cipher = areq_ctx->cipher; + struct scatterlist *asg = areq_ctx->asg; unsigned int ivsize = crypto_aead_ivsize(authenc); - unsigned int cryptlen; + unsigned int cryptlen = req->cryptlen; + authenc_ahash_t authenc_ahash_fn = crypto_authenc_ahash_fb; + struct page *dstp; u8 *vdst; u8 *hash; @@ -163,10 +337,25 @@ static int crypto_authenc_genicv(struct aead_request *req, u8 *iv, sg_set_buf(cipher, iv, ivsize); authenc_chain(cipher, dst, vdst == iv + ivsize); dst = cipher; + cryptlen += ivsize; } - cryptlen = req->cryptlen + ivsize; - hash = crypto_authenc_hash(req, flags, dst, cryptlen); + if (sg_is_last(assoc)) { + authenc_ahash_fn = crypto_authenc_ahash; + sg_init_table(asg, 2); + sg_set_page(asg, sg_page(assoc), assoc->length, assoc->offset); + authenc_chain(asg, dst, 0); + dst = asg; + cryptlen += req->assoclen; + } + + areq_ctx->cryptlen = cryptlen; + areq_ctx->sg = dst; + + areq_ctx->complete = authenc_geniv_ahash_done; + areq_ctx->update_complete = authenc_geniv_ahash_update_done; + + hash = authenc_ahash_fn(req, flags); if (IS_ERR(hash)) return PTR_ERR(hash); @@ -256,22 +445,25 @@ static int crypto_authenc_givencrypt(struct aead_givcrypt_request *req) } static int crypto_authenc_verify(struct aead_request *req, - struct scatterlist *cipher, - unsigned int cryptlen) + authenc_ahash_t authenc_ahash_fn) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); u8 *ohash; u8 *ihash; unsigned int authsize; - ohash = crypto_authenc_hash(req, CRYPTO_TFM_REQ_MAY_SLEEP, cipher, - cryptlen); + areq_ctx->complete = authenc_verify_ahash_done; + areq_ctx->complete = authenc_verify_ahash_update_done; + + ohash = authenc_ahash_fn(req, CRYPTO_TFM_REQ_MAY_SLEEP); if (IS_ERR(ohash)) return PTR_ERR(ohash); authsize = crypto_aead_authsize(authenc); ihash = ohash + authsize; - scatterwalk_map_and_copy(ihash, cipher, cryptlen, authsize, 0); + scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen, + authsize, 0); return memcmp(ihash, ohash, authsize) ? -EBADMSG: 0; } @@ -279,10 +471,14 @@ static int crypto_authenc_iverify(struct aead_request *req, u8 *iv, unsigned int cryptlen) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); struct scatterlist *src = req->src; - struct scatterlist cipher[2]; - struct page *srcp; + struct scatterlist *assoc = req->assoc; + struct scatterlist *cipher = areq_ctx->cipher; + struct scatterlist *asg = areq_ctx->asg; unsigned int ivsize = crypto_aead_ivsize(authenc); + authenc_ahash_t authenc_ahash_fn = crypto_authenc_ahash_fb; + struct page *srcp; u8 *vsrc; srcp = sg_page(src); @@ -293,9 +489,22 @@ static int crypto_authenc_iverify(struct aead_request *req, u8 *iv, sg_set_buf(cipher, iv, ivsize); authenc_chain(cipher, src, vsrc == iv + ivsize); src = cipher; + cryptlen += ivsize; + } + + if (sg_is_last(assoc)) { + authenc_ahash_fn = crypto_authenc_ahash; + sg_init_table(asg, 2); + sg_set_page(asg, sg_page(assoc), assoc->length, assoc->offset); + authenc_chain(asg, src, 0); + src = asg; + cryptlen += req->assoclen; } - return crypto_authenc_verify(req, src, cryptlen + ivsize); + areq_ctx->cryptlen = cryptlen; + areq_ctx->sg = src; + + return crypto_authenc_verify(req, authenc_ahash_fn); } static int crypto_authenc_decrypt(struct aead_request *req) @@ -326,38 +535,41 @@ static int crypto_authenc_decrypt(struct aead_request *req) static int crypto_authenc_init_tfm(struct crypto_tfm *tfm) { - struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); struct authenc_instance_ctx *ictx = crypto_instance_ctx(inst); struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm); - struct crypto_hash *auth; + struct crypto_ahash *auth; struct crypto_ablkcipher *enc; int err; - auth = crypto_spawn_hash(&ictx->auth); + auth = crypto_spawn_ahash(&ictx->auth); if (IS_ERR(auth)) return PTR_ERR(auth); + ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth) + + crypto_ahash_alignmask(auth), + crypto_ahash_alignmask(auth) + 1); + enc = crypto_spawn_skcipher(&ictx->enc); err = PTR_ERR(enc); if (IS_ERR(enc)) - goto err_free_hash; + goto err_free_ahash; ctx->auth = auth; ctx->enc = enc; + tfm->crt_aead.reqsize = max_t(unsigned int, - (crypto_hash_alignmask(auth) & - ~(crypto_tfm_ctx_alignment() - 1)) + - crypto_hash_digestsize(auth) * 2, - sizeof(struct skcipher_givcrypt_request) + - crypto_ablkcipher_reqsize(enc) + - crypto_ablkcipher_ivsize(enc)); - - spin_lock_init(&ctx->auth_lock); + crypto_ahash_reqsize(auth) + ctx->reqoff + + sizeof(struct authenc_request_ctx) + + sizeof(struct ahash_request), + sizeof(struct skcipher_givcrypt_request) + + crypto_ablkcipher_reqsize(enc) + + crypto_ablkcipher_ivsize(enc)); return 0; -err_free_hash: - crypto_free_hash(auth); +err_free_ahash: + crypto_free_ahash(auth); return err; } @@ -365,7 +577,7 @@ static void crypto_authenc_exit_tfm(struct crypto_tfm *tfm) { struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm); - crypto_free_hash(ctx->auth); + crypto_free_ahash(ctx->auth); crypto_free_ablkcipher(ctx->enc); } @@ -373,7 +585,8 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) { struct crypto_attr_type *algt; struct crypto_instance *inst; - struct crypto_alg *auth; + struct hash_alg_common *auth; + struct crypto_alg *auth_base; struct crypto_alg *enc; struct authenc_instance_ctx *ctx; const char *enc_name; @@ -387,11 +600,13 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) return ERR_PTR(-EINVAL); - auth = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH, - CRYPTO_ALG_TYPE_HASH_MASK); + auth = ahash_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH, + CRYPTO_ALG_TYPE_AHASH_MASK); if (IS_ERR(auth)) return ERR_PTR(PTR_ERR(auth)); + auth_base = &auth->base; + enc_name = crypto_attr_alg_name(tb[2]); err = PTR_ERR(enc_name); if (IS_ERR(enc_name)) @@ -404,7 +619,7 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) ctx = crypto_instance_ctx(inst); - err = crypto_init_spawn(&ctx->auth, auth, inst, CRYPTO_ALG_TYPE_MASK); + err = crypto_init_ahash_spawn(&ctx->auth, auth, inst); if (err) goto err_free_inst; @@ -419,24 +634,25 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) err = -ENAMETOOLONG; if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, - "authenc(%s,%s)", auth->cra_name, enc->cra_name) >= + "authenc(%s,%s)", auth_base->cra_name, enc->cra_name) >= CRYPTO_MAX_ALG_NAME) goto err_drop_enc; if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, - "authenc(%s,%s)", auth->cra_driver_name, + "authenc(%s,%s)", auth_base->cra_driver_name, enc->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) goto err_drop_enc; inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD; inst->alg.cra_flags |= enc->cra_flags & CRYPTO_ALG_ASYNC; - inst->alg.cra_priority = enc->cra_priority * 10 + auth->cra_priority; + inst->alg.cra_priority = enc->cra_priority * + 10 + auth_base->cra_priority; inst->alg.cra_blocksize = enc->cra_blocksize; - inst->alg.cra_alignmask = auth->cra_alignmask | enc->cra_alignmask; + inst->alg.cra_alignmask = auth_base->cra_alignmask | enc->cra_alignmask; inst->alg.cra_type = &crypto_aead_type; inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize; - inst->alg.cra_aead.maxauthsize = __crypto_shash_alg(auth)->digestsize; + inst->alg.cra_aead.maxauthsize = auth->digestsize; inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx); @@ -449,13 +665,13 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) inst->alg.cra_aead.givencrypt = crypto_authenc_givencrypt; out: - crypto_mod_put(auth); + crypto_mod_put(auth_base); return inst; err_drop_enc: crypto_drop_skcipher(&ctx->enc); err_drop_auth: - crypto_drop_spawn(&ctx->auth); + crypto_drop_ahash(&ctx->auth); err_free_inst: kfree(inst); out_put_auth: @@ -468,7 +684,7 @@ static void crypto_authenc_free(struct crypto_instance *inst) struct authenc_instance_ctx *ctx = crypto_instance_ctx(inst); crypto_drop_skcipher(&ctx->enc); - crypto_drop_spawn(&ctx->auth); + crypto_drop_ahash(&ctx->auth); kfree(inst); } -- cgit v0.10.2 From ce69a784504222c3ab6f1b3c357d09ec5772127a Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Mon, 20 Jul 2009 15:24:17 +0300 Subject: x86/apic: Enable x2APIC without interrupt remapping under KVM KVM would like to provide x2APIC interface to a guest without emulating interrupt remapping device. The reason KVM prefers guest to use x2APIC is that x2APIC interface is better virtualizable and provides better performance than mmio xAPIC interface: - msr exits are faster than mmio (no page table walk, emulation) - no need to read back ICR to look at the busy bit - one 64 bit ICR write instead of two 32 bit writes - shared code with the Hyper-V paravirt interface Included patch changes x2APIC enabling logic to enable it even if IR initialization failed, but kernel runs under KVM and no apic id is greater than 255 (if there is one spec requires BIOS to move to x2apic mode before starting an OS). -v2: fix build -v3: fix bug causing compiler warning Signed-off-by: Gleb Natapov Acked-by: Suresh Siddha Cc: Sheng Yang Cc: "avi@redhat.com" LKML-Reference: <20090720122417.GR5638@redhat.com> Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index bb7d479..586b7ad 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -183,6 +183,10 @@ static inline int x2apic_enabled(void) } #define x2apic_supported() (cpu_has_x2apic) +static inline void x2apic_force_phys(void) +{ + x2apic_phys = 1; +} #else static inline void check_x2apic(void) { @@ -194,6 +198,9 @@ static inline int x2apic_enabled(void) { return 0; } +static inline void x2apic_force_phys(void) +{ +} #define x2apic_preenabled 0 #define x2apic_supported() 0 diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 0b021c5..de039fc 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -49,6 +49,7 @@ #include #include #include +#include unsigned int num_processors; @@ -1361,52 +1362,76 @@ void enable_x2apic(void) } #endif /* CONFIG_X86_X2APIC */ -void __init enable_IR_x2apic(void) +int __init enable_IR(void) { #ifdef CONFIG_INTR_REMAP int ret; - unsigned long flags; - struct IO_APIC_route_entry **ioapic_entries = NULL; ret = dmar_table_init(); if (ret) { pr_debug("dmar_table_init() failed with %d:\n", ret); - goto ir_failed; + return 0; } if (!intr_remapping_supported()) { pr_debug("intr-remapping not supported\n"); - goto ir_failed; + return 0; } - if (!x2apic_preenabled && skip_ioapic_setup) { pr_info("Skipped enabling intr-remap because of skipping " "io-apic setup\n"); - return; + return 0; } + if (enable_intr_remapping(x2apic_supported())) + return 0; + + pr_info("Enabled Interrupt-remapping\n"); + + return 1; + +#endif + return 0; +} + +void __init enable_IR_x2apic(void) +{ + unsigned long flags; + struct IO_APIC_route_entry **ioapic_entries = NULL; + int ret, x2apic_enabled = 0; + ioapic_entries = alloc_ioapic_entries(); if (!ioapic_entries) { - pr_info("Allocate ioapic_entries failed: %d\n", ret); - goto end; + pr_err("Allocate ioapic_entries failed\n"); + goto out; } ret = save_IO_APIC_setup(ioapic_entries); if (ret) { pr_info("Saving IO-APIC state failed: %d\n", ret); - goto end; + goto out; } local_irq_save(flags); - mask_IO_APIC_setup(ioapic_entries); mask_8259A(); + mask_IO_APIC_setup(ioapic_entries); - ret = enable_intr_remapping(x2apic_supported()); - if (ret) - goto end_restore; + ret = enable_IR(); + if (!ret) { + /* IR is required if there is APIC ID > 255 even when running + * under KVM + */ + if (max_physical_apicid > 255 || !kvm_para_available()) + goto nox2apic; + /* + * without IR all CPUs can be addressed by IOAPIC/MSI + * only in physical mode + */ + x2apic_force_phys(); + } - pr_info("Enabled Interrupt-remapping\n"); + x2apic_enabled = 1; if (x2apic_supported() && !x2apic_mode) { x2apic_mode = 1; @@ -1414,41 +1439,25 @@ void __init enable_IR_x2apic(void) pr_info("Enabled x2apic\n"); } -end_restore: - if (ret) - /* - * IR enabling failed - */ +nox2apic: + if (!ret) /* IR enabling failed */ restore_IO_APIC_setup(ioapic_entries); - unmask_8259A(); local_irq_restore(flags); -end: +out: if (ioapic_entries) free_ioapic_entries(ioapic_entries); - if (!ret) + if (x2apic_enabled) return; -ir_failed: if (x2apic_preenabled) - panic("x2apic enabled by bios. But IR enabling failed"); + panic("x2apic: enabled by BIOS but kernel init failed."); else if (cpu_has_x2apic) - pr_info("Not enabling x2apic,Intr-remapping\n"); -#else - if (!cpu_has_x2apic) - return; - - if (x2apic_preenabled) - panic("x2apic enabled prior OS handover," - " enable CONFIG_X86_X2APIC, CONFIG_INTR_REMAP"); -#endif - - return; + pr_info("Not enabling x2apic, Intr-remapping init failed.\n"); } - #ifdef CONFIG_X86_64 /* * Detect and enable local APICs on non-SMP boards. diff --git a/arch/x86/kernel/apic/probe_64.c b/arch/x86/kernel/apic/probe_64.c index bc3e880..f3b1037 100644 --- a/arch/x86/kernel/apic/probe_64.c +++ b/arch/x86/kernel/apic/probe_64.c @@ -50,11 +50,11 @@ static struct apic *apic_probe[] __initdata = { void __init default_setup_apic_routing(void) { #ifdef CONFIG_X86_X2APIC - if (x2apic_mode && (apic != &apic_x2apic_phys && + if (x2apic_mode #ifdef CONFIG_X86_UV - apic != &apic_x2apic_uv_x && + && apic != &apic_x2apic_uv_x #endif - apic != &apic_x2apic_cluster)) { + ) { if (x2apic_phys) apic = &apic_x2apic_phys; else -- cgit v0.10.2 From 4bc4c9a5f5206d795e9ee1af8b0b074d126354af Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 4 Aug 2009 11:38:42 +0100 Subject: ASoC: Existing S3C24xx AC97 drivers should depend on S3C24xx Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index d1ed0f5..808de5c 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -66,7 +66,7 @@ config SND_S3C24XX_SOC_SMDK2443_WM9710 config SND_S3C24XX_SOC_LN2440SBC_ALC650 tristate "SoC AC97 Audio support for LN2440SBC - ALC650" - depends on SND_S3C24XX_SOC + depends on SND_S3C24XX_SOC && ARCH_S3C2410 select SND_S3C2443_SOC_AC97 select SND_SOC_AC97_CODEC help @@ -75,7 +75,7 @@ config SND_S3C24XX_SOC_LN2440SBC_ALC650 config SND_S3C24XX_SOC_S3C24XX_UDA134X tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" - depends on SND_S3C24XX_SOC + depends on SND_S3C24XX_SOC && ARCH_S3C2410 select SND_S3C24XX_SOC_I2S select SND_SOC_L3 select SND_SOC_UDA134X -- cgit v0.10.2 From 36cbd3dcc10384f813ec0814255f576c84f2bcd4 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 5 Aug 2009 10:42:58 -0700 Subject: net: mark read-only arrays as const String literals are constant, and usually, we can also tag the array of pointers const too, moving it to the .rodata section. Signed-off-by: Jan Engelhardt Signed-off-by: David S. Miller diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 1c8ee1b..98978e7 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -738,7 +738,8 @@ extern void ip_vs_protocol_cleanup(void); extern void ip_vs_protocol_timeout_change(int flags); extern int *ip_vs_create_timeout_table(int *table, int size); extern int -ip_vs_set_state_timeout(int *table, int num, char **names, char *name, int to); +ip_vs_set_state_timeout(int *table, int num, const char *const *names, + const char *name, int to); extern void ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb, int offset, const char *msg); diff --git a/include/net/irda/ircomm_event.h b/include/net/irda/ircomm_event.h index c290447..bc0c6f3 100644 --- a/include/net/irda/ircomm_event.h +++ b/include/net/irda/ircomm_event.h @@ -74,7 +74,7 @@ struct ircomm_info { struct qos_info *qos; }; -extern char *ircomm_state[]; +extern const char *const ircomm_state[]; struct ircomm_cb; /* Forward decl. */ diff --git a/include/net/irda/ircomm_tty_attach.h b/include/net/irda/ircomm_tty_attach.h index f91a569..0a63bbb 100644 --- a/include/net/irda/ircomm_tty_attach.h +++ b/include/net/irda/ircomm_tty_attach.h @@ -66,8 +66,8 @@ struct ircomm_tty_info { __u8 dlsap_sel; }; -extern char *ircomm_state[]; -extern char *ircomm_tty_state[]; +extern const char *const ircomm_state[]; +extern const char *const ircomm_tty_state[]; int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event, struct sk_buff *skb, struct ircomm_tty_info *info); diff --git a/include/net/irda/irlap_event.h b/include/net/irda/irlap_event.h index 2ae2e119..4c90824 100644 --- a/include/net/irda/irlap_event.h +++ b/include/net/irda/irlap_event.h @@ -120,7 +120,7 @@ typedef enum { /* FIXME check the two first reason codes */ LAP_PRIMARY_CONFLICT, } LAP_REASON; -extern const char *irlap_state[]; +extern const char *const irlap_state[]; void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, struct sk_buff *skb, struct irlap_info *info); diff --git a/include/net/irda/irlmp_event.h b/include/net/irda/irlmp_event.h index e03ae4a..9e4ec17 100644 --- a/include/net/irda/irlmp_event.h +++ b/include/net/irda/irlmp_event.h @@ -79,8 +79,8 @@ typedef enum { LM_LAP_IDLE_TIMEOUT, } IRLMP_EVENT; -extern const char *irlmp_state[]; -extern const char *irlsap_state[]; +extern const char *const irlmp_state[]; +extern const char *const irlsap_state[]; void irlmp_watchdog_timer_expired(void *data); void irlmp_discovery_timer_expired(void *data); diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index b05b055..8bc25f7 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -241,7 +241,9 @@ const char *sctp_tname(const sctp_subtype_t); /* timeouts */ const char *sctp_pname(const sctp_subtype_t); /* primitives */ /* This is a table of printable names of sctp_state_t's. */ -extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[]; +extern const char *const sctp_state_tbl[]; +extern const char *const sctp_evttype_tbl[]; +extern const char *const sctp_status_tbl[]; /* Maximum chunk length considering padding requirements. */ enum { SCTP_MAX_CHUNK_LEN = ((1<<16) - sizeof(__u32)) }; diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index b55a091..6262c33 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -107,7 +107,7 @@ static const struct file_operations vlandev_fops = { */ /* Strings */ -static const char *vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = { +static const char *const vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = { [VLAN_NAME_TYPE_RAW_PLUS_VID] = "VLAN_NAME_TYPE_RAW_PLUS_VID", [VLAN_NAME_TYPE_PLUS_VID_NO_PAD] = "VLAN_NAME_TYPE_PLUS_VID_NO_PAD", [VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD] = "VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD", diff --git a/net/atm/lec.c b/net/atm/lec.c index c463868..8e723c2 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -935,9 +935,9 @@ static int lecd_attach(struct atm_vcc *vcc, int arg) } #ifdef CONFIG_PROC_FS -static char *lec_arp_get_status_string(unsigned char status) +static const char *lec_arp_get_status_string(unsigned char status) { - static char *lec_arp_status_string[] = { + static const char *const lec_arp_status_string[] = { "ESI_UNKNOWN ", "ESI_ARP_PENDING ", "ESI_VC_PENDING ", @@ -1121,7 +1121,8 @@ static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos) static int lec_seq_show(struct seq_file *seq, void *v) { - static char lec_banner[] = "Itf MAC ATM destination" + static const char lec_banner[] = + "Itf MAC ATM destination" " Status Flags " "VPI/VCI Recv VPI/VCI\n"; @@ -1505,7 +1506,7 @@ lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove) } #if DEBUG_ARP_TABLE -static char *get_status_string(unsigned char st) +static const char *get_status_string(unsigned char st) { switch (st) { case ESI_UNKNOWN: diff --git a/net/atm/proc.c b/net/atm/proc.c index 38de5ff..ab8419a 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -151,8 +151,9 @@ static void *vcc_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc) { - static const char *class_name[] = { "off","UBR","CBR","VBR","ABR" }; - static const char *aal_name[] = { + static const char *const class_name[] = + {"off","UBR","CBR","VBR","ABR"}; + static const char *const aal_name[] = { "---", "1", "2", "3/4", /* 0- 3 */ "???", "5", "???", "???", /* 4- 7 */ "???", "???", "???", "???", /* 8-11 */ @@ -178,7 +179,7 @@ static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc) static const char *vcc_state(struct atm_vcc *vcc) { - static const char *map[] = { ATM_VS2TXT_MAP }; + static const char *const map[] = { ATM_VS2TXT_MAP }; return map[ATM_VF2VS(vcc->flags)]; } @@ -335,7 +336,7 @@ static const struct file_operations vcc_seq_fops = { static int svc_seq_show(struct seq_file *seq, void *v) { - static char atm_svc_banner[] = + static const char atm_svc_banner[] = "Itf VPI VCI State Remote\n"; if (v == SEQ_START_TOKEN) diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 0250e06..8cfb5a8 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -49,7 +49,7 @@ static struct net_proto_family *bt_proto[BT_MAX_PROTO]; static DEFINE_RWLOCK(bt_proto_lock); static struct lock_class_key bt_lock_key[BT_MAX_PROTO]; -static const char *bt_key_strings[BT_MAX_PROTO] = { +static const char *const bt_key_strings[BT_MAX_PROTO] = { "sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP", "sk_lock-AF_BLUETOOTH-BTPROTO_HCI", "sk_lock-AF_BLUETOOTH-BTPROTO_SCO", @@ -61,7 +61,7 @@ static const char *bt_key_strings[BT_MAX_PROTO] = { }; static struct lock_class_key bt_slock_key[BT_MAX_PROTO]; -static const char *bt_slock_key_strings[BT_MAX_PROTO] = { +static const char *const bt_slock_key_strings[BT_MAX_PROTO] = { "slock-AF_BLUETOOTH-BTPROTO_L2CAP", "slock-AF_BLUETOOTH-BTPROTO_HCI", "slock-AF_BLUETOOTH-BTPROTO_SCO", diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 0660515..fd3f8d6 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -21,7 +21,7 @@ */ #define MESSAGE_AGE_INCR ((HZ < 256) ? 1 : (HZ/256)) -static const char *br_port_state_names[] = { +static const char *const br_port_state_names[] = { [BR_STATE_DISABLED] = "disabled", [BR_STATE_LISTENING] = "listening", [BR_STATE_LEARNING] = "learning", diff --git a/net/core/dev.c b/net/core/dev.c index 7134766..f01a9c4 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -272,7 +272,7 @@ static const unsigned short netdev_lock_type[] = ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154, ARPHRD_IEEE802154_PHY, ARPHRD_VOID, ARPHRD_NONE}; -static const char *netdev_lock_name[] = +static const char *const netdev_lock_name[] = {"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25", "_xmit_PRONET", "_xmit_CHAOS", "_xmit_IEEE802", "_xmit_ARCNET", "_xmit_APPLETLK", "_xmit_DLCI", "_xmit_ATM", "_xmit_METRICOM", diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 3994680..ad91e9e 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -141,7 +141,7 @@ static ssize_t show_dormant(struct device *dev, return -EINVAL; } -static const char *operstates[] = { +static const char *const operstates[] = { "unknown", "notpresent", /* currently unused */ "down", diff --git a/net/core/sock.c b/net/core/sock.c index bbb25be..a324a80 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -142,7 +142,7 @@ static struct lock_class_key af_family_slock_keys[AF_MAX]; * strings build-time, so that runtime initialization of socket * locks is fast): */ -static const char *af_family_key_strings[AF_MAX+1] = { +static const char *const af_family_key_strings[AF_MAX+1] = { "sk_lock-AF_UNSPEC", "sk_lock-AF_UNIX" , "sk_lock-AF_INET" , "sk_lock-AF_AX25" , "sk_lock-AF_IPX" , "sk_lock-AF_APPLETALK", "sk_lock-AF_NETROM", "sk_lock-AF_BRIDGE" , "sk_lock-AF_ATMPVC" , @@ -158,7 +158,7 @@ static const char *af_family_key_strings[AF_MAX+1] = { "sk_lock-AF_IEEE802154", "sk_lock-AF_MAX" }; -static const char *af_family_slock_key_strings[AF_MAX+1] = { +static const char *const af_family_slock_key_strings[AF_MAX+1] = { "slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" , "slock-AF_AX25" , "slock-AF_IPX" , "slock-AF_APPLETALK", "slock-AF_NETROM", "slock-AF_BRIDGE" , "slock-AF_ATMPVC" , @@ -174,7 +174,7 @@ static const char *af_family_slock_key_strings[AF_MAX+1] = { "slock-AF_IEEE802154", "slock-AF_MAX" }; -static const char *af_family_clock_key_strings[AF_MAX+1] = { +static const char *const af_family_clock_key_strings[AF_MAX+1] = { "clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" , "clock-AF_AX25" , "clock-AF_IPX" , "clock-AF_APPLETALK", "clock-AF_NETROM", "clock-AF_BRIDGE" , "clock-AF_ATMPVC" , diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index a27b7f4..f596ce1 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -52,7 +52,7 @@ static int ccid3_debug; #ifdef CONFIG_IP_DCCP_CCID3_DEBUG static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state) { - static char *ccid3_state_names[] = { + static const char *const ccid3_state_names[] = { [TFRC_SSTATE_NO_SENT] = "NO_SENT", [TFRC_SSTATE_NO_FBACK] = "NO_FBACK", [TFRC_SSTATE_FBACK] = "FBACK", @@ -646,7 +646,7 @@ enum ccid3_fback_type { #ifdef CONFIG_IP_DCCP_CCID3_DEBUG static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state) { - static char *ccid3_rx_state_names[] = { + static const char *const ccid3_rx_state_names[] = { [TFRC_RSTATE_NO_DATA] = "NO_DATA", [TFRC_RSTATE_DATA] = "DATA", [TFRC_RSTATE_TERM] = "TERM", diff --git a/net/dccp/feat.c b/net/dccp/feat.c index b04160a..972b8dc 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -213,7 +213,7 @@ static int dccp_feat_default_value(u8 feat_num) */ static const char *dccp_feat_fname(const u8 feat) { - static const char *feature_names[] = { + static const char *const feature_names[] = { [DCCPF_RESERVED] = "Reserved", [DCCPF_CCID] = "CCID", [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos", @@ -236,8 +236,9 @@ static const char *dccp_feat_fname(const u8 feat) return feature_names[feat]; } -static const char *dccp_feat_sname[] = { "DEFAULT", "INITIALISING", "CHANGING", - "UNSTABLE", "STABLE" }; +static const char *const dccp_feat_sname[] = { + "DEFAULT", "INITIALISING", "CHANGING", "UNSTABLE", "STABLE", +}; #ifdef CONFIG_IP_DCCP_DEBUG static const char *dccp_feat_oname(const u8 opt) diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 94ca8ea..37b3b42 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -124,7 +124,7 @@ EXPORT_SYMBOL_GPL(dccp_done); const char *dccp_packet_name(const int type) { - static const char *dccp_packet_names[] = { + static const char *const dccp_packet_names[] = { [DCCP_PKT_REQUEST] = "REQUEST", [DCCP_PKT_RESPONSE] = "RESPONSE", [DCCP_PKT_DATA] = "DATA", @@ -147,7 +147,7 @@ EXPORT_SYMBOL_GPL(dccp_packet_name); const char *dccp_state_name(const int state) { - static char *dccp_state_names[] = { + static const char *const dccp_state_names[] = { [DCCP_OPEN] = "OPEN", [DCCP_REQUESTING] = "REQUESTING", [DCCP_PARTOPEN] = "PARTOPEN", diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index d58b491..fe3c846 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2421,7 +2421,7 @@ static inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s) } } -static const char *rtn_type_names[__RTN_MAX] = { +static const char *const rtn_type_names[__RTN_MAX] = { [RTN_UNSPEC] = "UNSPEC", [RTN_UNICAST] = "UNICAST", [RTN_LOCAL] = "LOCAL", diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 590ddef..c9605c3 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -101,7 +101,7 @@ static struct snmp_mib snmp6_icmp6_list[] = { }; /* RFC 4293 v6 ICMPMsgStatsTable; named items for RFC 2466 compatibility */ -static char *icmp6type2name[256] = { +static const char *const icmp6type2name[256] = { [ICMPV6_DEST_UNREACH] = "DestUnreachs", [ICMPV6_PKT_TOOBIG] = "PktTooBigs", [ICMPV6_TIME_EXCEED] = "TimeExcds", @@ -144,7 +144,7 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib) /* print by name -- deprecated items */ for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { int icmptype; - char *p; + const char *p; icmptype = i & 0xff; p = icmp6type2name[icmptype]; diff --git a/net/irda/ircomm/ircomm_event.c b/net/irda/ircomm/ircomm_event.c index c35b3ef..d78554f 100644 --- a/net/irda/ircomm/ircomm_event.c +++ b/net/irda/ircomm/ircomm_event.c @@ -49,7 +49,7 @@ static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, struct sk_buff *skb, struct ircomm_info *info); -char *ircomm_state[] = { +const char *const ircomm_state[] = { "IRCOMM_IDLE", "IRCOMM_WAITI", "IRCOMM_WAITR", @@ -57,7 +57,7 @@ char *ircomm_state[] = { }; #ifdef CONFIG_IRDA_DEBUG -static char *ircomm_event[] = { +static const char *const ircomm_event[] = { "IRCOMM_CONNECT_REQUEST", "IRCOMM_CONNECT_RESPONSE", "IRCOMM_TTP_CONNECT_INDICATION", diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index 9032a1d..eafc010 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -80,7 +80,7 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, struct sk_buff *skb, struct ircomm_tty_info *info); -char *ircomm_tty_state[] = { +const char *const ircomm_tty_state[] = { "IRCOMM_TTY_IDLE", "IRCOMM_TTY_SEARCH", "IRCOMM_TTY_QUERY_PARAMETERS", @@ -91,7 +91,7 @@ char *ircomm_tty_state[] = { }; #ifdef CONFIG_IRDA_DEBUG -static char *ircomm_tty_event[] = { +static const char *const ircomm_tty_event[] = { "IRCOMM_TTY_ATTACH_CABLE", "IRCOMM_TTY_DETACH_CABLE", "IRCOMM_TTY_DATA_REQUEST", diff --git a/net/irda/iriap.c b/net/irda/iriap.c index 4a105dc..294e34d 100644 --- a/net/irda/iriap.c +++ b/net/irda/iriap.c @@ -44,7 +44,7 @@ #ifdef CONFIG_IRDA_DEBUG /* FIXME: This one should go in irlmp.c */ -static const char *ias_charset_types[] = { +static const char *const ias_charset_types[] = { "CS_ASCII", "CS_ISO_8859_1", "CS_ISO_8859_2", @@ -966,7 +966,7 @@ static void iriap_watchdog_timer_expired(void *data) #ifdef CONFIG_PROC_FS -static const char *ias_value_types[] = { +static const char *const ias_value_types[] = { "IAS_MISSING", "IAS_INTEGER", "IAS_OCT_SEQ", diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 774d73a..6211682 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c @@ -69,14 +69,14 @@ static int eth; /* Use "eth" or "irlan" name for devices */ static int access = ACCESS_PEER; /* PEER, DIRECT or HOSTED */ #ifdef CONFIG_PROC_FS -static const char *irlan_access[] = { +static const char *const irlan_access[] = { "UNKNOWN", "DIRECT", "PEER", "HOSTED" }; -static const char *irlan_media[] = { +static const char *const irlan_media[] = { "UNKNOWN", "802.3", "802.5" diff --git a/net/irda/irlap.c b/net/irda/irlap.c index e4965b7..356e65b 100644 --- a/net/irda/irlap.c +++ b/net/irda/irlap.c @@ -63,7 +63,7 @@ static void irlap_init_qos_capabilities(struct irlap_cb *self, struct qos_info *qos_user); #ifdef CONFIG_IRDA_DEBUG -static char *lap_reasons[] = { +static const char *const lap_reasons[] = { "ERROR, NOT USED", "LAP_DISC_INDICATION", "LAP_NO_RESPONSE", diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c index 16c4ef0..c5c5195 100644 --- a/net/irda/irlap_event.c +++ b/net/irda/irlap_event.c @@ -78,7 +78,7 @@ static int irlap_state_reset_check(struct irlap_cb *, IRLAP_EVENT event, struct sk_buff *, struct irlap_info *); #ifdef CONFIG_IRDA_DEBUG -static const char *irlap_event[] = { +static const char *const irlap_event[] = { "DISCOVERY_REQUEST", "CONNECT_REQUEST", "CONNECT_RESPONSE", @@ -120,7 +120,7 @@ static const char *irlap_event[] = { }; #endif /* CONFIG_IRDA_DEBUG */ -const char *irlap_state[] = { +const char *const irlap_state[] = { "LAP_NDM", "LAP_QUERY", "LAP_REPLY", diff --git a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c index 78cce0c..c1fb5db 100644 --- a/net/irda/irlmp_event.c +++ b/net/irda/irlmp_event.c @@ -33,13 +33,13 @@ #include #include -const char *irlmp_state[] = { +const char *const irlmp_state[] = { "LAP_STANDBY", "LAP_U_CONNECT", "LAP_ACTIVE", }; -const char *irlsap_state[] = { +const char *const irlsap_state[] = { "LSAP_DISCONNECTED", "LSAP_CONNECT", "LSAP_CONNECT_PEND", @@ -49,7 +49,7 @@ const char *irlsap_state[] = { }; #ifdef CONFIG_IRDA_DEBUG -static const char *irlmp_event[] = { +static const char *const irlmp_event[] = { "LM_CONNECT_REQUEST", "LM_CONNECT_CONFIRM", "LM_CONNECT_RESPONSE", diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index f97be47..be47ac427 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -143,7 +143,7 @@ out: return 0; } -static char *llc_conn_state_names[] = { +static const char *const llc_conn_state_names[] = { [LLC_CONN_STATE_ADM] = "adm", [LLC_CONN_STATE_SETUP] = "setup", [LLC_CONN_STATE_NORMAL] = "normal", diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c index 85c8892..3e76716 100644 --- a/net/netfilter/ipvs/ip_vs_proto.c +++ b/net/netfilter/ipvs/ip_vs_proto.c @@ -127,7 +127,8 @@ ip_vs_create_timeout_table(int *table, int size) * Set timeout value for state specified by name */ int -ip_vs_set_state_timeout(int *table, int num, char **names, char *name, int to) +ip_vs_set_state_timeout(int *table, int num, const char *const *names, + const char *name, int to) { int i; diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index 2278e14..91d28e0 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c @@ -377,7 +377,7 @@ static int tcp_timeouts[IP_VS_TCP_S_LAST+1] = { [IP_VS_TCP_S_LAST] = 2*HZ, }; -static char * tcp_state_name_table[IP_VS_TCP_S_LAST+1] = { +static const char *const tcp_state_name_table[IP_VS_TCP_S_LAST+1] = { [IP_VS_TCP_S_NONE] = "NONE", [IP_VS_TCP_S_ESTABLISHED] = "ESTABLISHED", [IP_VS_TCP_S_SYN_SENT] = "SYN_SENT", diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index 33a05d3..e7a6885 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c @@ -472,7 +472,7 @@ static int udp_timeouts[IP_VS_UDP_S_LAST+1] = { [IP_VS_UDP_S_LAST] = 2*HZ, }; -static char * udp_state_name_table[IP_VS_UDP_S_LAST+1] = { +static const char *const udp_state_name_table[IP_VS_UDP_S_LAST+1] = { [IP_VS_UDP_S_NORMAL] = "UDP", [IP_VS_UDP_S_LAST] = "BUG!", }; diff --git a/net/rds/ib_stats.c b/net/rds/ib_stats.c index 02e3e3d..8d84883 100644 --- a/net/rds/ib_stats.c +++ b/net/rds/ib_stats.c @@ -39,7 +39,7 @@ DEFINE_PER_CPU(struct rds_ib_statistics, rds_ib_stats) ____cacheline_aligned; -static char *rds_ib_stat_names[] = { +static const char *const rds_ib_stat_names[] = { "ib_connect_raced", "ib_listen_closed_stale", "ib_tx_cq_call", diff --git a/net/rds/iw_stats.c b/net/rds/iw_stats.c index ccc7e8f..d33ea79 100644 --- a/net/rds/iw_stats.c +++ b/net/rds/iw_stats.c @@ -39,7 +39,7 @@ DEFINE_PER_CPU(struct rds_iw_statistics, rds_iw_stats) ____cacheline_aligned; -static char *rds_iw_stat_names[] = { +static const char *const rds_iw_stat_names[] = { "iw_connect_raced", "iw_listen_closed_stale", "iw_tx_cq_call", diff --git a/net/rds/rds.h b/net/rds/rds.h index dbe1112..290566c 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -652,7 +652,8 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct rds_statistics, rds_stats); int __init rds_stats_init(void); void rds_stats_exit(void); void rds_stats_info_copy(struct rds_info_iterator *iter, - uint64_t *values, char **names, size_t nr); + uint64_t *values, const char *const *names, + size_t nr); /* sysctl.c */ int __init rds_sysctl_init(void); diff --git a/net/rds/stats.c b/net/rds/stats.c index 6371468..91d8c58 100644 --- a/net/rds/stats.c +++ b/net/rds/stats.c @@ -40,7 +40,7 @@ DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_statistics, rds_stats); /* :.,$s/unsigned long\>.*\ Date: Tue, 4 Aug 2009 10:52:41 +0000 Subject: cpmac: fix wrong MDIO bus identifier This patch fixes the wrong MDIO bus identifier which was set to 0 unconditionaly, suitable for external switches while it is actually 1 for PHYs different than external switches which are autodetected. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index fd5e32c..c951dd4 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -1109,7 +1109,7 @@ static int external_switch; static int __devinit cpmac_probe(struct platform_device *pdev) { int rc, phy_id; - char *mdio_bus_id = "0"; + char mdio_bus_id[BUS_ID_SIZE]; struct resource *mem; struct cpmac_priv *priv; struct net_device *dev; @@ -1127,7 +1127,7 @@ static int __devinit cpmac_probe(struct platform_device *pdev) if (phy_id == PHY_MAX_ADDR) { if (external_switch || dumb_switch) { - mdio_bus_id = 0; /* fixed phys bus */ + strncpy(mdio_bus_id, "0", BUS_ID_SIZE); /* fixed phys bus */ phy_id = pdev->id; } else { dev_err(&pdev->dev, "no PHY present\n"); @@ -1254,7 +1254,7 @@ int __devinit cpmac_init(void) } cpmac_mii->phy_mask = ~(mask | 0x80000000); - snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "0"); + snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "1"); res = mdiobus_register(cpmac_mii); if (res) -- cgit v0.10.2 From 1e2c8d830a74c24ccb25601bd89dcd0dbcb4e9f5 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 4 Aug 2009 10:52:47 +0000 Subject: ar7: add fixed PHY support for the two on-board cpmac This patch adds fixed PHY support for the two on-chip cpmac Ethernet adapters. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c index 5422449..c4737ce 100644 --- a/arch/mips/ar7/platform.c +++ b/arch/mips/ar7/platform.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -209,6 +211,12 @@ static struct physmap_flash_data physmap_flash_data = { .width = 2, }; +static struct fixed_phy_status fixed_phy_status __initdata = { + .link = 1, + .speed = 100, + .duplex = 1, +}; + static struct plat_cpmac_data cpmac_low_data = { .reset_bit = 17, .power_bit = 20, @@ -530,6 +538,9 @@ static int __init ar7_register_devices(void) } if (ar7_has_high_cpmac()) { + res = fixed_phy_add(PHY_POLL, cpmac_high.id, &fixed_phy_status); + if (res && res != -ENODEV) + return res; cpmac_get_mac(1, cpmac_high_data.dev_addr); res = platform_device_register(&cpmac_high); if (res) @@ -538,6 +549,10 @@ static int __init ar7_register_devices(void) cpmac_low_data.phy_mask = 0xffffffff; } + res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status); + if (res && res != -ENODEV) + return res; + cpmac_get_mac(0, cpmac_low_data.dev_addr); res = platform_device_register(&cpmac_low); if (res) -- cgit v0.10.2 From 76e61eaa55e33ea51205fad633393d1ae10311c5 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 4 Aug 2009 10:52:52 +0000 Subject: cpmac: add support for fixed PHY This patch adds support for fixed PHY connected in MII mode to cpmac. We allow external and dumb_switch module parameters to override the PHY detection process since they are always connected with MDIO bus identifier 0. This lets fixed PHYs to be detected correctly and be connected to the their corresponding MDIO bus identifier. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index c951dd4..7b311c6 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -1117,22 +1117,23 @@ static int __devinit cpmac_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; - for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) { - if (!(pdata->phy_mask & (1 << phy_id))) - continue; - if (!cpmac_mii->phy_map[phy_id]) - continue; - break; + if (external_switch || dumb_switch) { + strncpy(mdio_bus_id, "0", BUS_ID_SIZE); /* fixed phys bus */ + phy_id = pdev->id; + } else { + for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) { + if (!(pdata->phy_mask & (1 << phy_id))) + continue; + if (!cpmac_mii->phy_map[phy_id]) + continue; + strncpy(mdio_bus_id, cpmac_mii->id, BUS_ID_SIZE); + break; + } } if (phy_id == PHY_MAX_ADDR) { - if (external_switch || dumb_switch) { - strncpy(mdio_bus_id, "0", BUS_ID_SIZE); /* fixed phys bus */ - phy_id = pdev->id; - } else { - dev_err(&pdev->dev, "no PHY present\n"); - return -ENODEV; - } + dev_err(&pdev->dev, "no PHY present\n"); + return -ENODEV; } dev = alloc_etherdev_mq(sizeof(*priv), CPMAC_QUEUES); @@ -1166,8 +1167,11 @@ static int __devinit cpmac_probe(struct platform_device *pdev) priv->msg_enable = netif_msg_init(debug_level, 0xff); memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr)); - priv->phy = phy_connect(dev, dev_name(&cpmac_mii->phy_map[phy_id]->dev), - &cpmac_adjust_link, 0, PHY_INTERFACE_MODE_MII); + snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id); + + priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0, + PHY_INTERFACE_MODE_MII); + if (IS_ERR(priv->phy)) { if (netif_msg_drv(priv)) printk(KERN_ERR "%s: Could not attach to PHY\n", -- cgit v0.10.2 From e4540aa94f9b3e75528d9091524e7d82a0650f10 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 4 Aug 2009 10:52:57 +0000 Subject: cpmac: wait longer after MDIO reset This patch slows down the MDIO_ALIVE busy waiting to let switches and PHY come up after reset. Previous loop was too quick for IC+175C and ADM6996C/L switches to come up. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 7b311c6..645e644 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -1245,11 +1245,11 @@ int __devinit cpmac_init(void) cpmac_mii->reset(cpmac_mii); - for (i = 0; i < 300000; i++) + for (i = 0; i < 300; i++) if ((mask = cpmac_read(cpmac_mii->priv, CPMAC_MDIO_ALIVE))) break; else - cpu_relax(); + msleep(10); mask &= 0x7fffffff; if (mask & (mask - 1)) { -- cgit v0.10.2 From 4e43af323a669a977fcb35f1127c57480ebf7265 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 4 Aug 2009 10:53:00 +0000 Subject: cpmac: bump version to 0.5.1 Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 645e644..3e3fab8 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -54,7 +54,7 @@ module_param(dumb_switch, int, 0444); MODULE_PARM_DESC(debug_level, "Number of NETIF_MSG bits to enable"); MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus"); -#define CPMAC_VERSION "0.5.0" +#define CPMAC_VERSION "0.5.1" /* frame size + 802.1q tag */ #define CPMAC_SKB_SIZE (ETH_FRAME_LEN + 4) #define CPMAC_QUEUES 8 -- cgit v0.10.2 From 839b04c4aba91dd175f60f45712680126fdc88f7 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 4 Aug 2009 11:17:49 +0000 Subject: cpmac: unmark as broken Starting with version 0.5.1, cpmac is no longer broken. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5f6509a..9948fa2 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1774,7 +1774,7 @@ config SC92031 config CPMAC tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)" - depends on NET_ETHERNET && EXPERIMENTAL && AR7 && BROKEN + depends on NET_ETHERNET && EXPERIMENTAL && AR7 select PHYLIB help TI AR7 CPMAC Ethernet support -- cgit v0.10.2 From 545eb370087494dcf267e6285fe3aa20e5617c33 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Wed, 5 Aug 2009 07:34:07 +0000 Subject: netxen: fix vlan tso case Fix the calculation of remaining header length in TSO over vlan device case. This was inadvertently missed out in patch 028afe719855a157e32450c ("netxen: add vlan tx acceleration support"). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 40549a0..c91e022 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1450,7 +1450,7 @@ netxen_tso_check(struct net_device *netdev, skb_copy_from_linear_data_offset(skb, 12, (char *)vh + 16, copy_len - 16); - copied = copy_len; + copied = copy_len - VLAN_HLEN; offset = 0; producer = get_next_index(producer, tx_ring->num_desc); -- cgit v0.10.2 From 06db58c0cd92e157a4ccf2b6836c9f4b931c7cda Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Wed, 5 Aug 2009 07:34:08 +0000 Subject: netxen: remove unnecessary structures Remove unnecessary offsetof calulations on these structures: netxen_board_info, netxen_user_old_info, netxen_new_user_info. The offsets into the flash are fixed, don't need to be calculated. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index e22d086..bb4aa4f 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -441,154 +441,6 @@ struct status_desc { #define NETXEN_BRDTYPE_P3_10G_XFP 0x0032 #define NETXEN_BRDTYPE_P3_10G_TP 0x0080 -struct netxen_board_info { - u32 header_version; - - u32 board_mfg; - u32 board_type; - u32 board_num; - u32 chip_id; - u32 chip_minor; - u32 chip_major; - u32 chip_pkg; - u32 chip_lot; - - u32 port_mask; /* available niu ports */ - u32 peg_mask; /* available pegs */ - u32 icache_ok; /* can we run with icache? */ - u32 dcache_ok; /* can we run with dcache? */ - u32 casper_ok; - - u32 mac_addr_lo_0; - u32 mac_addr_lo_1; - u32 mac_addr_lo_2; - u32 mac_addr_lo_3; - - /* MN-related config */ - u32 mn_sync_mode; /* enable/ sync shift cclk/ sync shift mclk */ - u32 mn_sync_shift_cclk; - u32 mn_sync_shift_mclk; - u32 mn_wb_en; - u32 mn_crystal_freq; /* in MHz */ - u32 mn_speed; /* in MHz */ - u32 mn_org; - u32 mn_depth; - u32 mn_ranks_0; /* ranks per slot */ - u32 mn_ranks_1; /* ranks per slot */ - u32 mn_rd_latency_0; - u32 mn_rd_latency_1; - u32 mn_rd_latency_2; - u32 mn_rd_latency_3; - u32 mn_rd_latency_4; - u32 mn_rd_latency_5; - u32 mn_rd_latency_6; - u32 mn_rd_latency_7; - u32 mn_rd_latency_8; - u32 mn_dll_val[18]; - u32 mn_mode_reg; /* MIU DDR Mode Register */ - u32 mn_ext_mode_reg; /* MIU DDR Extended Mode Register */ - u32 mn_timing_0; /* MIU Memory Control Timing Rgister */ - u32 mn_timing_1; /* MIU Extended Memory Ctrl Timing Register */ - u32 mn_timing_2; /* MIU Extended Memory Ctrl Timing2 Register */ - - /* SN-related config */ - u32 sn_sync_mode; /* enable/ sync shift cclk / sync shift mclk */ - u32 sn_pt_mode; /* pass through mode */ - u32 sn_ecc_en; - u32 sn_wb_en; - u32 sn_crystal_freq; - u32 sn_speed; - u32 sn_org; - u32 sn_depth; - u32 sn_dll_tap; - u32 sn_rd_latency; - - u32 mac_addr_hi_0; - u32 mac_addr_hi_1; - u32 mac_addr_hi_2; - u32 mac_addr_hi_3; - - u32 magic; /* indicates flash has been initialized */ - - u32 mn_rdimm; - u32 mn_dll_override; - -}; - -#define FLASH_NUM_PORTS (4) - -struct netxen_flash_mac_addr { - u32 flash_addr[32]; -}; - -struct netxen_user_old_info { - u8 flash_md5[16]; - u8 crbinit_md5[16]; - u8 brdcfg_md5[16]; - /* bootloader */ - u32 bootld_version; - u32 bootld_size; - u8 bootld_md5[16]; - /* image */ - u32 image_version; - u32 image_size; - u8 image_md5[16]; - /* primary image status */ - u32 primary_status; - u32 secondary_present; - - /* MAC address , 4 ports */ - struct netxen_flash_mac_addr mac_addr[FLASH_NUM_PORTS]; -}; -#define FLASH_NUM_MAC_PER_PORT 32 -struct netxen_user_info { - u8 flash_md5[16 * 64]; - /* bootloader */ - u32 bootld_version; - u32 bootld_size; - /* image */ - u32 image_version; - u32 image_size; - /* primary image status */ - u32 primary_status; - u32 secondary_present; - - /* MAC address , 4 ports, 32 address per port */ - u64 mac_addr[FLASH_NUM_PORTS * FLASH_NUM_MAC_PER_PORT]; - u32 sub_sys_id; - u8 serial_num[32]; - - /* Any user defined data */ -}; - -/* - * Flash Layout - new format. - */ -struct netxen_new_user_info { - u8 flash_md5[16 * 64]; - /* bootloader */ - u32 bootld_version; - u32 bootld_size; - /* image */ - u32 image_version; - u32 image_size; - /* primary image status */ - u32 primary_status; - u32 secondary_present; - - /* MAC address , 4 ports, 32 address per port */ - u64 mac_addr[FLASH_NUM_PORTS * FLASH_NUM_MAC_PER_PORT]; - u32 sub_sys_id; - u8 serial_num[32]; - - /* Any user defined data */ -}; - -#define SECONDARY_IMAGE_PRESENT 0xb3b4b5b6 -#define SECONDARY_IMAGE_ABSENT 0xffffffff -#define PRIMARY_IMAGE_GOOD 0x5a5a5a5a -#define PRIMARY_IMAGE_BAD 0xffffffff - /* Flash memory map */ #define NETXEN_CRBINIT_START 0 /* crbinit section */ #define NETXEN_BRDCFG_START 0x4000 /* board config */ @@ -599,28 +451,25 @@ struct netxen_new_user_info { #define NETXEN_PXE_START 0x3E0000 /* PXE boot rom */ #define NETXEN_USER_START 0x3E8000 /* Firmare info */ #define NETXEN_FIXED_START 0x3F0000 /* backup of crbinit */ +#define NETXEN_USER_START_OLD NETXEN_PXE_START /* very old flash */ +#define NX_OLD_MAC_ADDR_OFFSET (NETXEN_USER_START) #define NX_FW_VERSION_OFFSET (NETXEN_USER_START+0x408) #define NX_FW_SIZE_OFFSET (NETXEN_USER_START+0x40c) +#define NX_FW_MAC_ADDR_OFFSET (NETXEN_USER_START+0x418) +#define NX_FW_SERIAL_NUM_OFFSET (NETXEN_USER_START+0x81c) #define NX_BIOS_VERSION_OFFSET (NETXEN_USER_START+0x83c) + +#define NX_HDR_VERSION_OFFSET (NETXEN_BRDCFG_START) +#define NX_BRDTYPE_OFFSET (NETXEN_BRDCFG_START+0x8) #define NX_FW_MAGIC_OFFSET (NETXEN_BRDCFG_START+0x128) + #define NX_FW_MIN_SIZE (0x3fffff) #define NX_P2_MN_ROMIMAGE 0 #define NX_P3_CT_ROMIMAGE 1 #define NX_P3_MN_ROMIMAGE 2 #define NX_FLASH_ROMIMAGE 3 -#define NETXEN_USER_START_OLD NETXEN_PXE_START /* for backward compatibility */ - -#define NETXEN_FLASH_START (NETXEN_CRBINIT_START) -#define NETXEN_INIT_SECTOR (0) -#define NETXEN_PRIMARY_START (NETXEN_BOOTLD_START) -#define NETXEN_FLASH_CRBINIT_SIZE (0x4000) -#define NETXEN_FLASH_BRDCFG_SIZE (sizeof(struct netxen_board_info)) -#define NETXEN_FLASH_USER_SIZE (sizeof(struct netxen_user_info)/sizeof(u32)) -#define NETXEN_FLASH_SECONDARY_SIZE (NETXEN_USER_START-NETXEN_SECONDARY_START) -#define NETXEN_NUM_PRIMARY_SECTORS (0x20) -#define NETXEN_NUM_CONFIG_SECTORS (1) extern char netxen_nic_driver_name[]; /* Number of status descriptors to handle per interrupt */ diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index ddb9deb..673dcf5 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -816,18 +816,15 @@ int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac) __le32 *pmac = (__le32 *) mac; u32 offset; - offset = NETXEN_USER_START + - offsetof(struct netxen_new_user_info, mac_addr) + - adapter->portnum * sizeof(u64); + offset = NX_FW_MAC_ADDR_OFFSET + (adapter->portnum * sizeof(u64)); if (netxen_get_flash_block(adapter, offset, sizeof(u64), pmac) == -1) return -1; if (*mac == cpu_to_le64(~0ULL)) { - offset = NETXEN_USER_START_OLD + - offsetof(struct netxen_user_old_info, mac_addr) + - adapter->portnum * sizeof(u64); + offset = NX_OLD_MAC_ADDR_OFFSET + + (adapter->portnum * sizeof(u64)); if (netxen_get_flash_block(adapter, offset, sizeof(u64), pmac) == -1) @@ -1857,13 +1854,11 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter) int offset, board_type, magic, header_version; struct pci_dev *pdev = adapter->pdev; - offset = NETXEN_BRDCFG_START + - offsetof(struct netxen_board_info, magic); + offset = NX_FW_MAGIC_OFFSET; if (netxen_rom_fast_read(adapter, offset, &magic)) return -EIO; - offset = NETXEN_BRDCFG_START + - offsetof(struct netxen_board_info, header_version); + offset = NX_HDR_VERSION_OFFSET; if (netxen_rom_fast_read(adapter, offset, &header_version)) return -EIO; @@ -1875,8 +1870,7 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter) return -EIO; } - offset = NETXEN_BRDCFG_START + - offsetof(struct netxen_board_info, board_type); + offset = NX_BRDTYPE_OFFSET; if (netxen_rom_fast_read(adapter, offset, &board_type)) return -EIO; @@ -2022,23 +2016,22 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) u32 fw_major, fw_minor, fw_build; char brd_name[NETXEN_MAX_SHORT_NAME]; char serial_num[32]; - int i, addr, val; + int i, offset, val; int *ptr32; struct pci_dev *pdev = adapter->pdev; adapter->driver_mismatch = 0; ptr32 = (int *)&serial_num; - addr = NETXEN_USER_START + - offsetof(struct netxen_new_user_info, serial_num); + offset = NX_FW_SERIAL_NUM_OFFSET; for (i = 0; i < 8; i++) { - if (netxen_rom_fast_read(adapter, addr, &val) == -1) { + if (netxen_rom_fast_read(adapter, offset, &val) == -1) { dev_err(&pdev->dev, "error reading board info\n"); adapter->driver_mismatch = 1; return; } ptr32[i] = cpu_to_le32(val); - addr += sizeof(u32); + offset += sizeof(u32); } fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); -- cgit v0.10.2 From c1c00ab8626298ac784ea344bf10e94b5bd9bcb5 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Wed, 5 Aug 2009 07:34:09 +0000 Subject: netxen: add hardware LRO support Add support to handle aggregate packets from firmware. Local TCP flows are automatically identified by firmware based on the dest IP hash added by driver for local IP addresses. The packets are sent down on the jumbo rx ring. Signed-off-by: Narender Kumar Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index bb4aa4f..ae81f70 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -365,6 +365,7 @@ struct rcv_desc { #define NETXEN_NIC_RXPKT_DESC 0x04 #define NETXEN_OLD_RXPKT_DESC 0x3f #define NETXEN_NIC_RESPONSE_DESC 0x05 +#define NETXEN_NIC_LRO_DESC 0x12 /* for status field in status_desc */ #define STATUS_NEED_CKSUM (1) @@ -398,6 +399,24 @@ struct rcv_desc { #define netxen_get_sts_opcode(sts_data) \ (((sts_data) >> 58) & 0x03F) +#define netxen_get_lro_sts_refhandle(sts_data) \ + ((sts_data) & 0x0FFFF) +#define netxen_get_lro_sts_length(sts_data) \ + (((sts_data) >> 16) & 0x0FFFF) +#define netxen_get_lro_sts_l2_hdr_offset(sts_data) \ + (((sts_data) >> 32) & 0x0FF) +#define netxen_get_lro_sts_l4_hdr_offset(sts_data) \ + (((sts_data) >> 40) & 0x0FF) +#define netxen_get_lro_sts_timestamp(sts_data) \ + (((sts_data) >> 48) & 0x1) +#define netxen_get_lro_sts_type(sts_data) \ + (((sts_data) >> 49) & 0x7) +#define netxen_get_lro_sts_push_flag(sts_data) \ + (((sts_data) >> 52) & 0x1) +#define netxen_get_lro_sts_seq_number(sts_data) \ + ((sts_data) & 0x0FFFFFFFF) + + struct status_desc { __le64 status_desc_data[2]; } __attribute__ ((aligned(16))); @@ -712,6 +731,7 @@ struct netxen_recv_context { #define NX_CAP0_LSO NX_CAP_BIT(0, 6) #define NX_CAP0_JUMBO_CONTIGUOUS NX_CAP_BIT(0, 7) #define NX_CAP0_LRO_CONTIGUOUS NX_CAP_BIT(0, 8) +#define NX_CAP0_HW_LRO NX_CAP_BIT(0, 10) /* * Context state @@ -969,6 +989,7 @@ typedef struct { #define NX_FW_CAPABILITY_PEXQ (1 << 7) #define NX_FW_CAPABILITY_BDG (1 << 8) #define NX_FW_CAPABILITY_FVLANTX (1 << 9) +#define NX_FW_CAPABILITY_HW_LRO (1 << 10) /* module types */ #define LINKEVENT_MODULE_NOT_PRESENT 1 diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 9e04696..412d658 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -203,6 +203,8 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter) cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN); cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS); + if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) + cap |= NX_CAP0_HW_LRO; prq->capabilities[0] = cpu_to_le32(cap); prq->host_int_crb_mode = diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 81253ab..5828287 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1242,20 +1242,31 @@ no_skb: static struct netxen_rx_buffer * netxen_process_rcv(struct netxen_adapter *adapter, - int ring, int index, int length, int cksum, int pkt_offset, - struct nx_host_sds_ring *sds_ring) + struct nx_host_sds_ring *sds_ring, + int ring, u64 sts_data0) { struct net_device *netdev = adapter->netdev; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; struct netxen_rx_buffer *buffer; struct sk_buff *skb; - struct nx_host_rds_ring *rds_ring = &recv_ctx->rds_rings[ring]; + struct nx_host_rds_ring *rds_ring; + int index, length, cksum, pkt_offset; - if (unlikely(index > rds_ring->num_desc)) + if (unlikely(ring >= adapter->max_rds_rings)) + return NULL; + + rds_ring = &recv_ctx->rds_rings[ring]; + + index = netxen_get_sts_refhandle(sts_data0); + if (unlikely(index >= rds_ring->num_desc)) return NULL; buffer = &rds_ring->rx_buf_arr[index]; + length = netxen_get_sts_totallength(sts_data0); + cksum = netxen_get_sts_status(sts_data0); + pkt_offset = netxen_get_sts_pkt_offset(sts_data0); + skb = netxen_process_rxbuf(adapter, rds_ring, index, cksum); if (!skb) return buffer; @@ -1279,6 +1290,78 @@ netxen_process_rcv(struct netxen_adapter *adapter, return buffer; } +#define TCP_HDR_SIZE 20 +#define TCP_TS_OPTION_SIZE 12 +#define TCP_TS_HDR_SIZE (TCP_HDR_SIZE + TCP_TS_OPTION_SIZE) + +static struct netxen_rx_buffer * +netxen_process_lro(struct netxen_adapter *adapter, + struct nx_host_sds_ring *sds_ring, + int ring, u64 sts_data0, u64 sts_data1) +{ + struct net_device *netdev = adapter->netdev; + struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; + struct netxen_rx_buffer *buffer; + struct sk_buff *skb; + struct nx_host_rds_ring *rds_ring; + struct iphdr *iph; + struct tcphdr *th; + bool push, timestamp; + int l2_hdr_offset, l4_hdr_offset; + int index; + u16 lro_length, length, data_offset; + u32 seq_number; + + if (unlikely(ring > adapter->max_rds_rings)) + return NULL; + + rds_ring = &recv_ctx->rds_rings[ring]; + + index = netxen_get_lro_sts_refhandle(sts_data0); + if (unlikely(index > rds_ring->num_desc)) + return NULL; + + buffer = &rds_ring->rx_buf_arr[index]; + + timestamp = netxen_get_lro_sts_timestamp(sts_data0); + lro_length = netxen_get_lro_sts_length(sts_data0); + l2_hdr_offset = netxen_get_lro_sts_l2_hdr_offset(sts_data0); + l4_hdr_offset = netxen_get_lro_sts_l4_hdr_offset(sts_data0); + push = netxen_get_lro_sts_push_flag(sts_data0); + seq_number = netxen_get_lro_sts_seq_number(sts_data1); + + skb = netxen_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK); + if (!skb) + return buffer; + + if (timestamp) + data_offset = l4_hdr_offset + TCP_TS_HDR_SIZE; + else + data_offset = l4_hdr_offset + TCP_HDR_SIZE; + + skb_put(skb, lro_length + data_offset); + + skb->truesize = (skb->len + sizeof(struct sk_buff) + + ((unsigned long)skb->data - (unsigned long)skb->head)); + + skb_pull(skb, l2_hdr_offset); + skb->protocol = eth_type_trans(skb, netdev); + + iph = (struct iphdr *)skb->data; + th = (struct tcphdr *)(skb->data + (iph->ihl << 2)); + + length = (iph->ihl << 2) + (th->doff << 2) + lro_length; + iph->tot_len = htons(length); + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + th->psh = push; + th->seq = htonl(seq_number); + + netif_receive_skb(skb); + + return buffer; +} + #define netxen_merge_rx_buffers(list, head) \ do { list_splice_tail_init(list, head); } while (0); @@ -1295,28 +1378,33 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) u32 consumer = sds_ring->consumer; int count = 0; - u64 sts_data; - int opcode, ring, index, length, cksum, pkt_offset, desc_cnt; + u64 sts_data0, sts_data1; + int opcode, ring = 0, desc_cnt; while (count < max) { desc = &sds_ring->desc_head[consumer]; - sts_data = le64_to_cpu(desc->status_desc_data[0]); + sts_data0 = le64_to_cpu(desc->status_desc_data[0]); - if (!(sts_data & STATUS_OWNER_HOST)) + if (!(sts_data0 & STATUS_OWNER_HOST)) break; - desc_cnt = netxen_get_sts_desc_cnt(sts_data); - ring = netxen_get_sts_type(sts_data); + desc_cnt = netxen_get_sts_desc_cnt(sts_data0); - if (ring > RCV_RING_JUMBO) - goto skip; - - opcode = netxen_get_sts_opcode(sts_data); + opcode = netxen_get_sts_opcode(sts_data0); switch (opcode) { case NETXEN_NIC_RXPKT_DESC: case NETXEN_OLD_RXPKT_DESC: case NETXEN_NIC_SYN_OFFLOAD: + ring = netxen_get_sts_type(sts_data0); + rxbuf = netxen_process_rcv(adapter, sds_ring, + ring, sts_data0); + break; + case NETXEN_NIC_LRO_DESC: + ring = netxen_get_lro_sts_type(sts_data0); + sts_data1 = le64_to_cpu(desc->status_desc_data[1]); + rxbuf = netxen_process_lro(adapter, sds_ring, + ring, sts_data0, sts_data1); break; case NETXEN_NIC_RESPONSE_DESC: netxen_handle_fw_message(desc_cnt, consumer, sds_ring); @@ -1326,14 +1414,6 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) WARN_ON(desc_cnt > 1); - index = netxen_get_sts_refhandle(sts_data); - length = netxen_get_sts_totallength(sts_data); - cksum = netxen_get_sts_status(sts_data); - pkt_offset = netxen_get_sts_pkt_offset(sts_data); - - rxbuf = netxen_process_rcv(adapter, ring, index, - length, cksum, pkt_offset, sds_ring); - if (rxbuf) list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); -- cgit v0.10.2 From 49c794e94649020248e37b78db16cd25bad38b4f Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 4 Aug 2009 07:28:28 +0000 Subject: net: implement a SO_PROTOCOL getsockoption Similar to SO_TYPE returning the socket type, SO_PROTOCOL allows to retrieve the protocol used with a given socket. I am not quite sure why we have that-many copies of socket.h, and why the values are not the same on all arches either, but for where hex numbers dominate, I use 0x1029 for SO_PROTOCOL as that seems to be the next free unused number across a bunch of operating systems, or so Google results make me want to believe. SO_PROTOCOL for others just uses the next free Linux number, 38. Signed-off-by: Jan Engelhardt Signed-off-by: David S. Miller diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h index 3641ec1..2f8b4d3 100644 --- a/arch/alpha/include/asm/socket.h +++ b/arch/alpha/include/asm/socket.h @@ -32,6 +32,7 @@ #define SO_RCVTIMEO 0x1012 #define SO_SNDTIMEO 0x1013 #define SO_ACCEPTCONN 0x1014 +#define SO_PROTOCOL 0x1028 /* linux-specific, might as well be the same as on i386 */ #define SO_NO_CHECK 11 diff --git a/arch/arm/include/asm/socket.h b/arch/arm/include/asm/socket.h index 537de4e..7f47454 100644 --- a/arch/arm/include/asm/socket.h +++ b/arch/arm/include/asm/socket.h @@ -57,4 +57,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/avr32/include/asm/socket.h b/arch/avr32/include/asm/socket.h index 04c8606..6af2866 100644 --- a/arch/avr32/include/asm/socket.h +++ b/arch/avr32/include/asm/socket.h @@ -57,4 +57,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* __ASM_AVR32_SOCKET_H */ diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h index d5cf740..f3859fb 100644 --- a/arch/cris/include/asm/socket.h +++ b/arch/cris/include/asm/socket.h @@ -59,6 +59,8 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/include/asm/socket.h b/arch/frv/include/asm/socket.h index 57c3d40..8dab348 100644 --- a/arch/frv/include/asm/socket.h +++ b/arch/frv/include/asm/socket.h @@ -57,5 +57,7 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h index 602518a..ba770d0 100644 --- a/arch/h8300/include/asm/socket.h +++ b/arch/h8300/include/asm/socket.h @@ -57,4 +57,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/ia64/include/asm/socket.h b/arch/ia64/include/asm/socket.h index 7454212..091cd9d 100644 --- a/arch/ia64/include/asm/socket.h +++ b/arch/ia64/include/asm/socket.h @@ -66,4 +66,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_IA64_SOCKET_H */ diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h index be7ed58..d36f592 100644 --- a/arch/m32r/include/asm/socket.h +++ b/arch/m32r/include/asm/socket.h @@ -57,4 +57,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_M32R_SOCKET_H */ diff --git a/arch/m68k/include/asm/socket.h b/arch/m68k/include/asm/socket.h index ca87f93..060cb7e 100644 --- a/arch/m68k/include/asm/socket.h +++ b/arch/m68k/include/asm/socket.h @@ -57,4 +57,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/microblaze/include/asm/socket.h b/arch/microblaze/include/asm/socket.h index 8259368..96bf8bf 100644 --- a/arch/microblaze/include/asm/socket.h +++ b/arch/microblaze/include/asm/socket.h @@ -66,4 +66,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_MICROBLAZE_SOCKET_H */ diff --git a/arch/mips/include/asm/socket.h b/arch/mips/include/asm/socket.h index 2abca17..289ce5f 100644 --- a/arch/mips/include/asm/socket.h +++ b/arch/mips/include/asm/socket.h @@ -42,6 +42,7 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SO_SNDTIMEO 0x1005 /* send timeout */ #define SO_RCVTIMEO 0x1006 /* receive timeout */ #define SO_ACCEPTCONN 0x1009 +#define SO_PROTOCOL 0x1028 /* protocol type */ /* linux-specific, might as well be the same as on i386 */ #define SO_NO_CHECK 11 diff --git a/arch/mn10300/include/asm/socket.h b/arch/mn10300/include/asm/socket.h index fb5daf4..19d7cf7 100644 --- a/arch/mn10300/include/asm/socket.h +++ b/arch/mn10300/include/asm/socket.h @@ -57,4 +57,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h index 885472b..a658b09 100644 --- a/arch/parisc/include/asm/socket.h +++ b/arch/parisc/include/asm/socket.h @@ -24,6 +24,7 @@ #define SO_RCVTIMEO 0x1006 #define SO_ERROR 0x1007 #define SO_TYPE 0x1008 +#define SO_PROTOCOL 0x1028 #define SO_PEERNAME 0x2000 #define SO_NO_CHECK 0x400b diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h index 1e5cfad..609049d 100644 --- a/arch/powerpc/include/asm/socket.h +++ b/arch/powerpc/include/asm/socket.h @@ -64,4 +64,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/arch/s390/include/asm/socket.h b/arch/s390/include/asm/socket.h index 02330c5..65baa9a 100644 --- a/arch/s390/include/asm/socket.h +++ b/arch/s390/include/asm/socket.h @@ -65,4 +65,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/sparc/include/asm/socket.h b/arch/sparc/include/asm/socket.h index 982a12f..9cbbfaf 100644 --- a/arch/sparc/include/asm/socket.h +++ b/arch/sparc/include/asm/socket.h @@ -29,6 +29,8 @@ #define SO_RCVBUFFORCE 0x100b #define SO_ERROR 0x1007 #define SO_TYPE 0x1008 +#define SO_PROTOCOL 0x1028 + /* Linux specific, keep the same. */ #define SO_NO_CHECK 0x000b diff --git a/arch/x86/include/asm/socket.h b/arch/x86/include/asm/socket.h index ca8bf2c..1077d25 100644 --- a/arch/x86/include/asm/socket.h +++ b/arch/x86/include/asm/socket.h @@ -57,4 +57,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _ASM_X86_SOCKET_H */ diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h index dd1a7a4..e47f172 100644 --- a/arch/xtensa/include/asm/socket.h +++ b/arch/xtensa/include/asm/socket.h @@ -68,4 +68,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* _XTENSA_SOCKET_H */ diff --git a/include/asm-generic/socket.h b/include/asm-generic/socket.h index 5d79e40..7e24d18 100644 --- a/include/asm-generic/socket.h +++ b/include/asm-generic/socket.h @@ -60,4 +60,6 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_PROTOCOL 38 + #endif /* __ASM_GENERIC_SOCKET_H */ diff --git a/net/core/sock.c b/net/core/sock.c index a324a80..ebce661 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -482,6 +482,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname, sk->sk_reuse = valbool; break; case SO_TYPE: + case SO_PROTOCOL: case SO_ERROR: ret = -ENOPROTOOPT; break; @@ -764,6 +765,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = sk->sk_type; break; + case SO_PROTOCOL: + v.val = sk->sk_protocol; + break; + case SO_ERROR: v.val = -sock_error(sk); if (v.val == 0) -- cgit v0.10.2 From 0d6038ee76f2e06b79d0465807f67e86bf4025de Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 4 Aug 2009 07:28:29 +0000 Subject: net: implement a SO_DOMAIN getsockoption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This sockopt goes in line with SO_TYPE and SO_PROTOCOL. It makes it possible for userspace programs to pass around file descriptors — I am referring to arguments-to-functions, but it may even work for the fd passing over UNIX sockets — without needing to also pass the auxiliary information (PF_INET6/IPPROTO_TCP). Signed-off-by: Jan Engelhardt Signed-off-by: David S. Miller diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h index 2f8b4d3..26773e3 100644 --- a/arch/alpha/include/asm/socket.h +++ b/arch/alpha/include/asm/socket.h @@ -33,6 +33,7 @@ #define SO_SNDTIMEO 0x1013 #define SO_ACCEPTCONN 0x1014 #define SO_PROTOCOL 0x1028 +#define SO_DOMAIN 0x1029 /* linux-specific, might as well be the same as on i386 */ #define SO_NO_CHECK 11 diff --git a/arch/arm/include/asm/socket.h b/arch/arm/include/asm/socket.h index 7f47454..92ac61d 100644 --- a/arch/arm/include/asm/socket.h +++ b/arch/arm/include/asm/socket.h @@ -58,5 +58,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_SOCKET_H */ diff --git a/arch/avr32/include/asm/socket.h b/arch/avr32/include/asm/socket.h index 6af2866..fe863f9 100644 --- a/arch/avr32/include/asm/socket.h +++ b/arch/avr32/include/asm/socket.h @@ -58,5 +58,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* __ASM_AVR32_SOCKET_H */ diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h index f3859fb..45ec49b 100644 --- a/arch/cris/include/asm/socket.h +++ b/arch/cris/include/asm/socket.h @@ -60,6 +60,7 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/include/asm/socket.h b/arch/frv/include/asm/socket.h index 8dab348..2dea726 100644 --- a/arch/frv/include/asm/socket.h +++ b/arch/frv/include/asm/socket.h @@ -58,6 +58,7 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_SOCKET_H */ diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h index ba770d0..1547f01 100644 --- a/arch/h8300/include/asm/socket.h +++ b/arch/h8300/include/asm/socket.h @@ -58,5 +58,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_SOCKET_H */ diff --git a/arch/ia64/include/asm/socket.h b/arch/ia64/include/asm/socket.h index 091cd9d..0b0d5ff 100644 --- a/arch/ia64/include/asm/socket.h +++ b/arch/ia64/include/asm/socket.h @@ -67,5 +67,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_IA64_SOCKET_H */ diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h index d36f592..3390a86 100644 --- a/arch/m32r/include/asm/socket.h +++ b/arch/m32r/include/asm/socket.h @@ -58,5 +58,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_M32R_SOCKET_H */ diff --git a/arch/m68k/include/asm/socket.h b/arch/m68k/include/asm/socket.h index 060cb7e..eee01cc 100644 --- a/arch/m68k/include/asm/socket.h +++ b/arch/m68k/include/asm/socket.h @@ -58,5 +58,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_SOCKET_H */ diff --git a/arch/microblaze/include/asm/socket.h b/arch/microblaze/include/asm/socket.h index 96bf8bf..7361ae7 100644 --- a/arch/microblaze/include/asm/socket.h +++ b/arch/microblaze/include/asm/socket.h @@ -67,5 +67,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_MICROBLAZE_SOCKET_H */ diff --git a/arch/mips/include/asm/socket.h b/arch/mips/include/asm/socket.h index 289ce5f..ae05acc 100644 --- a/arch/mips/include/asm/socket.h +++ b/arch/mips/include/asm/socket.h @@ -43,6 +43,7 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SO_RCVTIMEO 0x1006 /* receive timeout */ #define SO_ACCEPTCONN 0x1009 #define SO_PROTOCOL 0x1028 /* protocol type */ +#define SO_DOMAIN 0x1029 /* domain/socket family */ /* linux-specific, might as well be the same as on i386 */ #define SO_NO_CHECK 11 diff --git a/arch/mn10300/include/asm/socket.h b/arch/mn10300/include/asm/socket.h index 19d7cf7..4df75af 100644 --- a/arch/mn10300/include/asm/socket.h +++ b/arch/mn10300/include/asm/socket.h @@ -58,5 +58,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_SOCKET_H */ diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h index a658b09..960b1e5 100644 --- a/arch/parisc/include/asm/socket.h +++ b/arch/parisc/include/asm/socket.h @@ -25,6 +25,7 @@ #define SO_ERROR 0x1007 #define SO_TYPE 0x1008 #define SO_PROTOCOL 0x1028 +#define SO_DOMAIN 0x1029 #define SO_PEERNAME 0x2000 #define SO_NO_CHECK 0x400b diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h index 609049d..3ab8b3e 100644 --- a/arch/powerpc/include/asm/socket.h +++ b/arch/powerpc/include/asm/socket.h @@ -65,5 +65,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/arch/s390/include/asm/socket.h b/arch/s390/include/asm/socket.h index 65baa9a..e42df89 100644 --- a/arch/s390/include/asm/socket.h +++ b/arch/s390/include/asm/socket.h @@ -66,5 +66,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_SOCKET_H */ diff --git a/arch/sparc/include/asm/socket.h b/arch/sparc/include/asm/socket.h index 9cbbfaf..3a5ae3d 100644 --- a/arch/sparc/include/asm/socket.h +++ b/arch/sparc/include/asm/socket.h @@ -30,6 +30,7 @@ #define SO_ERROR 0x1007 #define SO_TYPE 0x1008 #define SO_PROTOCOL 0x1028 +#define SO_DOMAIN 0x1029 /* Linux specific, keep the same. */ diff --git a/arch/x86/include/asm/socket.h b/arch/x86/include/asm/socket.h index 1077d25..b2a8c74 100644 --- a/arch/x86/include/asm/socket.h +++ b/arch/x86/include/asm/socket.h @@ -58,5 +58,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _ASM_X86_SOCKET_H */ diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h index e47f172..beb3a6b 100644 --- a/arch/xtensa/include/asm/socket.h +++ b/arch/xtensa/include/asm/socket.h @@ -69,5 +69,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* _XTENSA_SOCKET_H */ diff --git a/include/asm-generic/socket.h b/include/asm-generic/socket.h index 7e24d18..538991c 100644 --- a/include/asm-generic/socket.h +++ b/include/asm-generic/socket.h @@ -61,5 +61,6 @@ #define SCM_TIMESTAMPING SO_TIMESTAMPING #define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #endif /* __ASM_GENERIC_SOCKET_H */ diff --git a/net/core/sock.c b/net/core/sock.c index ebce661..3ac34ea 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -483,6 +483,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname, break; case SO_TYPE: case SO_PROTOCOL: + case SO_DOMAIN: case SO_ERROR: ret = -ENOPROTOOPT; break; @@ -769,6 +770,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = sk->sk_protocol; break; + case SO_DOMAIN: + v.val = sk->sk_family; + break; + case SO_ERROR: v.val = -sock_error(sk); if (v.val == 0) -- cgit v0.10.2 From 14074eab8dcaa7f66d8f52612b2dcec51222bb5f Mon Sep 17 00:00:00 2001 From: sarveshwarb Date: Wed, 5 Aug 2009 13:05:24 -0700 Subject: be2net: Patch to perform function reset at initialization This patch is a bug fix to avoid system going into a bad state when driver is loaded in context of kdump kernel. The patch fixes the issue by performing a soft reset of pci function at probe time. Signed-off-by: sarveshwarb Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index de10773..2547ee2 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1019,3 +1019,24 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num) spin_unlock(&adapter->mbox_lock); return status; } + +int be_cmd_reset_function(struct be_adapter *adapter) +{ + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); + struct be_cmd_req_hdr *req = embedded_payload(wrb); + int status; + + spin_lock(&adapter->mbox_lock); + + memset(wrb, 0, sizeof(*wrb)); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + + be_cmd_hdr_prepare(req, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_FUNCTION_RESET, sizeof(*req)); + + status = be_mbox_notify(adapter); + + spin_unlock(&adapter->mbox_lock); + return status; +} diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 5c5de35..7061806 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -135,6 +135,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58 #define OPCODE_COMMON_NTWK_PMAC_ADD 59 #define OPCODE_COMMON_NTWK_PMAC_DEL 60 +#define OPCODE_COMMON_FUNCTION_RESET 61 #define OPCODE_ETH_ACPI_CONFIG 2 #define OPCODE_ETH_PROMISCUOUS 3 @@ -744,4 +745,5 @@ extern int be_cmd_set_flow_control(struct be_adapter *adapter, extern int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc); extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num); +extern int be_cmd_reset_function(struct be_adapter *adapter); extern void be_process_mcc(struct be_adapter *adapter); diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index ef82a52..d20235b 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1873,6 +1873,10 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status) goto free_netdev; + status = be_cmd_reset_function(adapter); + if (status) + goto ctrl_clean; + status = be_stats_init(adapter); if (status) goto ctrl_clean; -- cgit v0.10.2 From 36e89d73e54c8db79d0fd1636cab9236eea7aae9 Mon Sep 17 00:00:00 2001 From: Lucy Liu Date: Wed, 5 Aug 2009 13:06:34 -0700 Subject: ixgbe: allow vlan egress priority mapping in DCB mode The skb priority to vlan-qos egress mapping that can be configured using set_egress_map with vconfig is overriden by the DCB code in the driver. This patch allows this existing mechanism to work and will increase the configuration flexibility of DCB mode on Linux. A hierarchy of configuration is: 1. Modifies the ixgbe_select_queue() routine for DCB mode to return the priority value from the VLAN tag. It will normally be zero, unless the egress priority map has modified it. This will get packets into the correct queue and result in the queue_mapping field being set correctly. 2. Any tc filter which modifies queue_mapping will be honored, as the filters are handled after the vlan egress map is handled. Signed-off-by: Lucy Liu Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 44adc98..52d7f19 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5126,7 +5126,7 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) return smp_processor_id(); if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) - return 0; /* All traffic should default to class 0 */ + return (skb->vlan_tci & IXGBE_TX_FLAGS_VLAN_PRIO_MASK) >> 13; return skb_tx_hash(dev, skb); } -- cgit v0.10.2 From 4403b371888d5947ed08200ee6351441a188a5c7 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:20:44 +0000 Subject: vxge: don't drop frame on tx queue full The vxge driver will drop a packet in its transmit function if the number of TxDs available hits 0. Instead of doing that, simply stop the transmit queue when transmitting a packet with the last available TxD. Signed-off-by: Benjamin LaHaise Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 335140d..beee4ab 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -895,6 +895,12 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) goto _exit2; } + /* Last TXD? Stop tx queue to avoid dropping packets. TX + * completion will resume the queue. + */ + if (avail == 1) + vxge_stop_tx_queue(fifo); + status = vxge_hw_fifo_txdl_reserve(fifo_hw, &dtr, &dtr_priv); if (unlikely(status != VXGE_HW_OK)) { vxge_debug_tx(VXGE_ERR, -- cgit v0.10.2 From ff67df55f6bde9de5e508bf1f09509c843accd54 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:21:03 +0000 Subject: vxge: fix pktgen hangs (don't abuse skb->cb[]) This patch fixes a case in the transmit completion code which was resulting in pktgen hanging at the end of a run. The cause is due to the fact that the ->cb[] area of an skb cannot be used in a network driver's transmit path, as that area belongs to the network protocol. Pktgen hangs, as it sends out the same packet multiple times, and vxge's use of this area of the skb for a temporary list can only add the packet to the temporary list once (while it may be on the queue many times). The fix is to remove this abuse of skb->cb[]. Instead, skb pointers are placed into a temporary stack array, and then free outside of the tx lock. This retains the smp optimization of doing dev_kfree_skb() outside of the tx lock. Signed-off-by: Benjamin LaHaise Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index 224acea..62779a5 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -978,7 +978,9 @@ struct __vxge_hw_fifo { void *txdlh, enum vxge_hw_fifo_tcode t_code, void *userdata, - void **skb_ptr); + struct sk_buff ***skb_ptr, + int nr_skb, + int *more); void (*txdl_term)( void *txdlh, @@ -1779,7 +1781,8 @@ struct vxge_hw_fifo_attr { void *txdlh, enum vxge_hw_fifo_tcode t_code, void *userdata, - void **skb_ptr); + struct sk_buff ***skb_ptr, + int nr_skb, int *more); void (*txdl_term)( void *txdlh, diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index beee4ab..4b22513 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -87,22 +87,25 @@ static inline int is_vxge_card_up(struct vxgedev *vdev) static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo) { unsigned long flags = 0; - struct sk_buff *skb_ptr = NULL; - struct sk_buff **temp, *head, *skb; - - if (spin_trylock_irqsave(&fifo->tx_lock, flags)) { - vxge_hw_vpath_poll_tx(fifo->handle, (void **)&skb_ptr); - spin_unlock_irqrestore(&fifo->tx_lock, flags); - } - /* free SKBs */ - head = skb_ptr; - while (head) { - skb = head; - temp = (struct sk_buff **)&skb->cb; - head = *temp; - *temp = NULL; - dev_kfree_skb_irq(skb); - } + struct sk_buff **skb_ptr = NULL; + struct sk_buff **temp; +#define NR_SKB_COMPLETED 128 + struct sk_buff *completed[NR_SKB_COMPLETED]; + int more; + + do { + more = 0; + skb_ptr = completed; + + if (spin_trylock_irqsave(&fifo->tx_lock, flags)) { + vxge_hw_vpath_poll_tx(fifo->handle, &skb_ptr, + NR_SKB_COMPLETED, &more); + spin_unlock_irqrestore(&fifo->tx_lock, flags); + } + /* free SKBs */ + for (temp = completed; temp != skb_ptr; temp++) + dev_kfree_skb_irq(*temp); + } while (more) ; } static inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev) @@ -600,11 +603,10 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, enum vxge_hw_status vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, enum vxge_hw_fifo_tcode t_code, void *userdata, - void **skb_ptr) + struct sk_buff ***skb_ptr, int nr_skb, int *more) { struct vxge_fifo *fifo = (struct vxge_fifo *)userdata; - struct sk_buff *skb, *head = NULL; - struct sk_buff **temp; + struct sk_buff *skb, **done_skb = *skb_ptr; int pkt_cnt = 0; vxge_debug_entryexit(VXGE_TRACE, @@ -657,9 +659,12 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, fifo->stats.tx_frms++; fifo->stats.tx_bytes += skb->len; - temp = (struct sk_buff **)&skb->cb; - *temp = head; - head = skb; + *done_skb++ = skb; + + if (--nr_skb <= 0) { + *more = 1; + break; + } pkt_cnt++; if (pkt_cnt > fifo->indicate_max_pkts) @@ -668,11 +673,9 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, } while (vxge_hw_fifo_txdl_next_completed(fifo_hw, &dtr, &t_code) == VXGE_HW_OK); + *skb_ptr = done_skb; vxge_wake_tx_queue(fifo, skb); - if (skb_ptr) - *skb_ptr = (void *) head; - vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", fifo->ndev->name, __func__, __LINE__); diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 18d824c..8b3989b 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -428,7 +428,8 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, enum vxge_hw_status vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, - enum vxge_hw_fifo_tcode t_code, void *userdata, void **skb_ptr); + enum vxge_hw_fifo_tcode t_code, void *userdata, + struct sk_buff ***skb_ptr, int nr_skbs, int *more); int vxge_close(struct net_device *dev); diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index 370f55c..c249cd2 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -2508,7 +2508,8 @@ enum vxge_hw_status vxge_hw_vpath_poll_rx(struct __vxge_hw_ring *ring) * See also: vxge_hw_vpath_poll_tx(). */ enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo, - void **skb_ptr) + struct sk_buff ***skb_ptr, int nr_skb, + int *more) { enum vxge_hw_fifo_tcode t_code; void *first_txdlh; @@ -2520,8 +2521,8 @@ enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo, status = vxge_hw_fifo_txdl_next_completed(fifo, &first_txdlh, &t_code); if (status == VXGE_HW_OK) - if (fifo->callback(fifo, first_txdlh, - t_code, channel->userdata, skb_ptr) != VXGE_HW_OK) + if (fifo->callback(fifo, first_txdlh, t_code, + channel->userdata, skb_ptr, nr_skb, more) != VXGE_HW_OK) status = VXGE_HW_COMPLETIONS_REMAIN; return status; diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 8260b91..461742b 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -2326,7 +2326,7 @@ enum vxge_hw_status vxge_hw_vpath_poll_rx( enum vxge_hw_status vxge_hw_vpath_poll_tx( struct __vxge_hw_fifo *fifoh, - void **skb_ptr); + struct sk_buff ***skb_ptr, int nr_skb, int *more); enum vxge_hw_status vxge_hw_vpath_alarm_process( struct __vxge_hw_vpath_handle *vpath_handle, -- cgit v0.10.2 From ff1b974cf30b282f90993ab658e59b73c152c0b8 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:21:21 +0000 Subject: vxge: improve tx performance by using mmiowb() instead of wmb() wmb() is extremely heavy on x86. The semantics required in the driver are provided by mmiowb(), so use that and improve tx performance on P4 Xeons by 5-10%. Signed-off-by: Benjamin LaHaise Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index c249cd2..0efb769 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -1070,11 +1070,11 @@ static void __vxge_hw_non_offload_db_post(struct __vxge_hw_fifo *fifo, VXGE_HW_NODBW_GET_NO_SNOOP(no_snoop), &fifo->nofl_db->control_0); - wmb(); + mmiowb(); writeq(txdl_ptr, &fifo->nofl_db->txdl_ptr); - wmb(); + mmiowb(); } /** -- cgit v0.10.2 From 3f23e436d241ac1cf50a659228a5a0e1e6572c1a Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:21:39 +0000 Subject: vxge: prefetch RxD descriptors This patch prefetches RxD descriptors which helps to lower the latency of a cache miss in vxge_hw_ring_rxd_next_completed. This lowers the % of CPU time used by vxge_hw_ring_rxd_next_completed() where the descriptor is accessed in profiling netperf on a P4 Xeon from 1.5% to 1.0%. Signed-off-by: Benjamin LaHaise Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 4b22513..e93651c 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -445,6 +445,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, vxge_hw_ring_replenish(ringh, 0); do { + prefetch((char *)dtr + L1_CACHE_BYTES); rx_priv = vxge_hw_ring_rxd_private_get(dtr); skb = rx_priv->skb; data_size = rx_priv->data_size; diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index 0efb769..fe3ae51 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -731,6 +731,7 @@ vxge_hw_channel_dtr_try_complete(struct __vxge_hw_channel *channel, void **dtrh) vxge_assert(channel->compl_index < channel->length); *dtrh = channel->work_arr[channel->compl_index]; + prefetch(*dtrh); } /* -- cgit v0.10.2 From ea11bbe0c94b045fdefc05476b69a2eef999a9c4 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:21:57 +0000 Subject: vxge: prefetch skb->data This patch implements prefetching of skb->data from a copy of the pointer in the descriptor (which is already in the L1 cache at this point). This improves netperf rx performance (netperf -L 0,0 -c -H 192.168.254.2 -- -M 131072 -m 131072) by 4.9% on a P4 Xeon host. Signed-off-by: Benjamin LaHaise Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index e93651c..094d155 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -286,6 +286,7 @@ vxge_rx_alloc(void *dtrh, struct vxge_ring *ring, const int skb_size) skb_reserve(skb, VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN); rx_priv->skb = skb; + rx_priv->skb_data = NULL; rx_priv->data_size = skb_size; vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); @@ -305,7 +306,8 @@ static int vxge_rx_map(void *dtrh, struct vxge_ring *ring) ring->ndev->name, __func__, __LINE__); rx_priv = vxge_hw_ring_rxd_private_get(dtrh); - dma_addr = pci_map_single(ring->pdev, rx_priv->skb->data, + rx_priv->skb_data = rx_priv->skb->data; + dma_addr = pci_map_single(ring->pdev, rx_priv->skb_data, rx_priv->data_size, PCI_DMA_FROMDEVICE); if (dma_addr == 0) { @@ -450,6 +452,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, skb = rx_priv->skb; data_size = rx_priv->data_size; data_dma = rx_priv->data_dma; + prefetch(rx_priv->skb_data); vxge_debug_rx(VXGE_TRACE, "%s: %s:%d skb = 0x%p", @@ -1056,6 +1059,7 @@ vxge_rx_term(void *dtrh, enum vxge_hw_rxd_state state, void *userdata) rx_priv->data_size, PCI_DMA_FROMDEVICE); dev_kfree_skb(rx_priv->skb); + rx_priv->skb_data = NULL; vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 8b3989b..9c36b3a 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -378,6 +378,7 @@ struct vxgedev { struct vxge_rx_priv { struct sk_buff *skb; + unsigned char *skb_data; dma_addr_t data_dma; dma_addr_t data_size; }; -- cgit v0.10.2 From cc104e52b4f61dbfe1a815f775ffb2fbbb4b785d Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:22:19 +0000 Subject: vxge: Version update Update the driver version number for any bug reports from end users. Signed-off-by: Benjamin LaHaise Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index 580c6eb..8fbce75 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -17,7 +17,7 @@ #define VXGE_VERSION_MAJOR "2" #define VXGE_VERSION_MINOR "0" -#define VXGE_VERSION_FIX "4" -#define VXGE_VERSION_BUILD "17899" +#define VXGE_VERSION_FIX "5" +#define VXGE_VERSION_BUILD "18053" #define VXGE_VERSION_FOR "k" #endif -- cgit v0.10.2 From b0a2712ffdde139f95d3e78c359877b23709509a Mon Sep 17 00:00:00 2001 From: John Bonesio Date: Wed, 29 Jul 2009 08:38:55 -0700 Subject: ASoC: MPC5200: Support for buffer wrap around The code in psc_dma_bcom_enqueue_tx() didn't account for the fact that s->runtime->control->appl_ptr can wrap around to the beginning of the buffer. This change fixes this problem. Signed-off-by: John Bonesio Acked-by: Grant Likely Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index f0a2d40..9ff62e3 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -69,6 +69,23 @@ static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s) static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s) { + if (s->appl_ptr > s->runtime->control->appl_ptr) { + /* + * In this case s->runtime->control->appl_ptr has wrapped around. + * Play the data to the end of the boundary, then wrap our own + * appl_ptr back around. + */ + while (s->appl_ptr < s->runtime->boundary) { + if (bcom_queue_full(s->bcom_task)) + return; + + s->appl_ptr += s->period_size; + + psc_dma_bcom_enqueue_next_buffer(s); + } + s->appl_ptr -= s->runtime->boundary; + } + while (s->appl_ptr < s->runtime->control->appl_ptr) { if (bcom_queue_full(s->bcom_task)) -- cgit v0.10.2 From 15b5bdaeeb15e0c18cca3ce7449188ca46516721 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 5 Aug 2009 20:50:43 +0200 Subject: ALSA: ASoC: cs4270: move power management hooks to snd_soc_codec_device Power management for the cs4270 codec is currently implemented as part of the i2c_driver struct. The disadvantage of doing it this way is that the callbacks registered in the snd_soc_card struct are called _before_ the codec's callbacks. That doesn't work, because the snd_soc_card callbacks will most likely switch down the codec's power domains or pull the reset GPIOs, and hence make the i2c communication bail out. Fix this by binding the suspend and resume code to the snd_soc_codec_device driver model and let the I2C functions only call the SoC core function for resume and suspend, which do nothing currently but will do later. Signed-off-by: Daniel Mack Cc: Timur Tabi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index a32b822..ca1e24a 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -806,15 +806,30 @@ static int cs4270_i2c_suspend(struct i2c_client *client, pm_message_t mesg) { struct cs4270_private *cs4270 = i2c_get_clientdata(client); struct snd_soc_codec *codec = &cs4270->codec; - int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; - return snd_soc_write(codec, CS4270_PWRCTL, reg); + return snd_soc_suspend_device(codec->dev); } static int cs4270_i2c_resume(struct i2c_client *client) { struct cs4270_private *cs4270 = i2c_get_clientdata(client); struct snd_soc_codec *codec = &cs4270->codec; + + return snd_soc_resume_device(codec->dev); +} + +static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + struct snd_soc_codec *codec = cs4270_codec; + int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; + + return snd_soc_write(codec, CS4270_PWRCTL, reg); +} + +static int cs4270_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_codec *codec = cs4270_codec; + struct i2c_client *i2c_client = codec->control_data; int reg; /* In case the device was put to hard reset during sleep, we need to @@ -825,7 +840,7 @@ static int cs4270_i2c_resume(struct i2c_client *client) for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) { u8 val = snd_soc_read(codec, reg); - if (i2c_smbus_write_byte_data(client, reg, val)) { + if (i2c_smbus_write_byte_data(i2c_client, reg, val)) { dev_err(codec->dev, "i2c write failed\n"); return -EIO; } @@ -840,6 +855,8 @@ static int cs4270_i2c_resume(struct i2c_client *client) #else #define cs4270_i2c_suspend NULL #define cs4270_i2c_resume NULL +#define cs4270_soc_suspend NULL +#define cs4270_soc_resume NULL #endif /* CONFIG_PM */ /* @@ -868,7 +885,9 @@ static struct i2c_driver cs4270_i2c_driver = { */ struct snd_soc_codec_device soc_codec_device_cs4270 = { .probe = cs4270_probe, - .remove = cs4270_remove + .remove = cs4270_remove, + .suspend = cs4270_soc_suspend, + .resume = cs4270_soc_resume, }; EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); -- cgit v0.10.2 From fd6a6394d7d6142afb3d4c87beb3c2c1d25c69bd Mon Sep 17 00:00:00 2001 From: javier Martin Date: Tue, 4 Aug 2009 17:17:52 +0200 Subject: ASoC: add DMA platform driver for MX1x and MX2x This adds support for DMA platform valid for i.MX1 and i.MX2 platforms. This is not valid for i.MX3 since it doesn't share the same DMA interface than i.MX1 and i.MX2. It has been tested on i.MX27 board. Signed-off-by: Javier Martin Signed-off-by: Mark Brown diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 0237879..8120b52 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_SND_SOC) += omap/ obj-$(CONFIG_SND_SOC) += pxa/ obj-$(CONFIG_SND_SOC) += s3c24xx/ obj-$(CONFIG_SND_SOC) += sh/ +obj-$(CONFIG_SND_SOC) += imx/ diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig new file mode 100644 index 0000000..a1bf053 --- /dev/null +++ b/sound/soc/imx/Kconfig @@ -0,0 +1,11 @@ +config SND_MX1_MX2_SOC + tristate "SoC Audio for Freecale i.MX1x i.MX2x CPUs" + depends on (ARCH_MX2 || ARCH_MX1) && SND + select SND_PCM + help + Say Y or M if you want to add support for codecs attached to + the MX1 or MX2 SSI interface. + + + + diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile new file mode 100644 index 0000000..c390f0f --- /dev/null +++ b/sound/soc/imx/Makefile @@ -0,0 +1,4 @@ +# i.MX Platform Support +snd-soc-mx1_mx2-objs := mx1_mx2-pcm.o + +obj-$(CONFIG_SND_MX1_MX2_SOC) += snd-soc-mx1_mx2.o diff --git a/sound/soc/imx/mx1_mx2-pcm.c b/sound/soc/imx/mx1_mx2-pcm.c new file mode 100644 index 0000000..94807f8 --- /dev/null +++ b/sound/soc/imx/mx1_mx2-pcm.c @@ -0,0 +1,487 @@ +/* + * mx1_mx2-pcm.c -- ALSA SoC interface for Freescale i.MX1x, i.MX2x CPUs + * + * Copyright 2009 Vista Silicon S.L. + * Author: Javier Martin + * javier.martin@vista-silicon.com + * + * Based on mxc-pcm.c by Liam Girdwood. + * + * 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 + * published by the Free Software Foundation. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mx1_mx2-pcm.h" + + +static const struct snd_pcm_hardware mx1_mx2_pcm_hardware = { + .info = (SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .buffer_bytes_max = 32 * 1024, + .period_bytes_min = 64, + .period_bytes_max = 8 * 1024, + .periods_min = 2, + .periods_max = 255, + .fifo_size = 0, +}; + +struct mx1_mx2_runtime_data { + int dma_ch; + int active; + unsigned int period; + unsigned int periods; + int tx_spin; + spinlock_t dma_lock; + struct mx1_mx2_pcm_dma_params *dma_params; +}; + + +/** + * This function stops the current dma transfer for playback + * and clears the dma pointers. + * + * @param substream pointer to the structure of the current stream. + * + */ +static int audio_stop_dma(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mx1_mx2_runtime_data *prtd = runtime->private_data; + unsigned long flags; + + spin_lock_irqsave(&prtd->dma_lock, flags); + + pr_debug("%s\n", __func__); + + prtd->active = 0; + prtd->period = 0; + prtd->periods = 0; + + /* this stops the dma channel and clears the buffer ptrs */ + + imx_dma_disable(prtd->dma_ch); + + spin_unlock_irqrestore(&prtd->dma_lock, flags); + + return 0; +} + +/** + * This function is called whenever a new audio block needs to be + * transferred to the codec. The function receives the address and the size + * of the new block and start a new DMA transfer. + * + * @param substream pointer to the structure of the current stream. + * + */ +static int dma_new_period(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mx1_mx2_runtime_data *prtd = runtime->private_data; + unsigned int dma_size; + unsigned int offset; + int ret = 0; + dma_addr_t mem_addr; + unsigned int dev_addr; + + if (prtd->active) { + dma_size = frames_to_bytes(runtime, runtime->period_size); + offset = dma_size * prtd->period; + + pr_debug("%s: period (%d) out of (%d)\n", __func__, + prtd->period, + runtime->periods); + pr_debug("period_size %d frames\n offset %d bytes\n", + (unsigned int)runtime->period_size, + offset); + pr_debug("dma_size %d bytes\n", dma_size); + + snd_BUG_ON(dma_size > mx1_mx2_pcm_hardware.period_bytes_max); + + mem_addr = (dma_addr_t)(runtime->dma_addr + offset); + dev_addr = prtd->dma_params->per_address; + pr_debug("%s: mem_addr is %x\n dev_addr is %x\n", + __func__, mem_addr, dev_addr); + + ret = imx_dma_setup_single(prtd->dma_ch, mem_addr, + dma_size, dev_addr, + prtd->dma_params->transfer_type); + if (ret < 0) { + printk(KERN_ERR "Error configuring DMA\n"); + return ret; + } + imx_dma_enable(prtd->dma_ch); + + pr_debug("%s: transfer enabled\nmem_addr = %x\n", + __func__, (unsigned int) mem_addr); + pr_debug("dev_addr = %x\ndma_size = %d\n", + (unsigned int) dev_addr, dma_size); + + prtd->tx_spin = 1; /* FGA little trick to retrieve DMA pos */ + prtd->period++; + prtd->period %= runtime->periods; + } + return ret; +} + + +/** + * This is a callback which will be called + * when a TX transfer finishes. The call occurs + * in interrupt context. + * + * @param dat pointer to the structure of the current stream. + * + */ +static void audio_dma_irq(int channel, void *data) +{ + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + struct mx1_mx2_runtime_data *prtd; + unsigned int dma_size; + unsigned int previous_period; + unsigned int offset; + + substream = data; + runtime = substream->runtime; + prtd = runtime->private_data; + previous_period = prtd->periods; + dma_size = frames_to_bytes(runtime, runtime->period_size); + offset = dma_size * previous_period; + + prtd->tx_spin = 0; + prtd->periods++; + prtd->periods %= runtime->periods; + + pr_debug("%s: irq per %d offset %x\n", __func__, prtd->periods, offset); + + /* + * If we are getting a callback for an active stream then we inform + * the PCM middle layer we've finished a period + */ + if (prtd->active) + snd_pcm_period_elapsed(substream); + + /* + * Trig next DMA transfer + */ + dma_new_period(substream); +} + +/** + * This function configures the hardware to allow audio + * playback operations. It is called by ALSA framework. + * + * @param substream pointer to the structure of the current stream. + * + * @return 0 on success, -1 otherwise. + */ +static int +snd_mx1_mx2_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mx1_mx2_runtime_data *prtd = runtime->private_data; + + prtd->period = 0; + prtd->periods = 0; + + return 0; +} + +static int mx1_mx2_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int ret; + + ret = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + if (ret < 0) { + printk(KERN_ERR "%s: failed to malloc pcm pages\n", __func__); + return ret; + } + + pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_addr 0x(%x)\n", + __func__, (unsigned int)runtime->dma_addr); + pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_area 0x(%x)\n", + __func__, (unsigned int)runtime->dma_area); + pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_bytes 0x(%x)\n", + __func__, (unsigned int)runtime->dma_bytes); + + return ret; +} + +static int mx1_mx2_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mx1_mx2_runtime_data *prtd = runtime->private_data; + + imx_dma_free(prtd->dma_ch); + + snd_pcm_lib_free_pages(substream); + + return 0; +} + +static int mx1_mx2_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct mx1_mx2_runtime_data *prtd = substream->runtime->private_data; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->tx_spin = 0; + /* requested stream startup */ + prtd->active = 1; + pr_debug("%s: starting dma_new_period\n", __func__); + ret = dma_new_period(substream); + break; + case SNDRV_PCM_TRIGGER_STOP: + /* requested stream shutdown */ + pr_debug("%s: stopping dma transfer\n", __func__); + ret = audio_stop_dma(substream); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static snd_pcm_uframes_t +mx1_mx2_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mx1_mx2_runtime_data *prtd = runtime->private_data; + unsigned int offset = 0; + + /* tx_spin value is used here to check if a transfer is active */ + if (prtd->tx_spin) { + offset = (runtime->period_size * (prtd->periods)) + + (runtime->period_size >> 1); + if (offset >= runtime->buffer_size) + offset = runtime->period_size >> 1; + } else { + offset = (runtime->period_size * (prtd->periods)); + if (offset >= runtime->buffer_size) + offset = 0; + } + pr_debug("%s: pointer offset %x\n", __func__, offset); + + return offset; +} + +static int mx1_mx2_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mx1_mx2_runtime_data *prtd; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mx1_mx2_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data; + int ret; + + snd_soc_set_runtime_hwparams(substream, &mx1_mx2_pcm_hardware); + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + prtd = kzalloc(sizeof(struct mx1_mx2_runtime_data), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + + runtime->private_data = prtd; + + if (!dma_data) + return -ENODEV; + + prtd->dma_params = dma_data; + + pr_debug("%s: Requesting dma channel (%s)\n", __func__, + prtd->dma_params->name); + prtd->dma_ch = imx_dma_request_by_prio(prtd->dma_params->name, + DMA_PRIO_HIGH); + if (prtd->dma_ch < 0) { + printk(KERN_ERR "Error requesting dma channel\n"); + return ret; + } + imx_dma_config_burstlen(prtd->dma_ch, + prtd->dma_params->watermark_level); + + ret = imx_dma_config_channel(prtd->dma_ch, + prtd->dma_params->per_config, + prtd->dma_params->mem_config, + prtd->dma_params->event_id, 0); + + if (ret) { + pr_debug(KERN_ERR "Error configuring dma channel %d\n", + prtd->dma_ch); + return ret; + } + + pr_debug("%s: Setting tx dma callback function\n", __func__); + ret = imx_dma_setup_handlers(prtd->dma_ch, + audio_dma_irq, NULL, + (void *)substream); + if (ret < 0) { + printk(KERN_ERR "Error setting dma callback function\n"); + return ret; + } + return 0; + + out: + return ret; +} + +static int mx1_mx2_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mx1_mx2_runtime_data *prtd = runtime->private_data; + + kfree(prtd); + + return 0; +} + +static int mx1_mx2_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +struct snd_pcm_ops mx1_mx2_pcm_ops = { + .open = mx1_mx2_pcm_open, + .close = mx1_mx2_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = mx1_mx2_pcm_hw_params, + .hw_free = mx1_mx2_pcm_hw_free, + .prepare = snd_mx1_mx2_prepare, + .trigger = mx1_mx2_pcm_trigger, + .pointer = mx1_mx2_pcm_pointer, + .mmap = mx1_mx2_pcm_mmap, +}; + +static u64 mx1_mx2_pcm_dmamask = 0xffffffff; + +static int mx1_mx2_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = mx1_mx2_pcm_hardware.buffer_bytes_max; + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + + /* Reserve uncached-buffered memory area for DMA */ + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + + pr_debug("%s: preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", + __func__, (void *) buf->area, (void *) buf->addr, size); + + if (!buf->area) + return -ENOMEM; + + buf->bytes = size; + return 0; +} + +static void mx1_mx2_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +int mx1_mx2_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &mx1_mx2_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = mx1_mx2_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + pr_debug("%s: preallocate playback buffer\n", __func__); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = mx1_mx2_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + pr_debug("%s: preallocate capture buffer\n", __func__); + if (ret) + goto out; + } + out: + return ret; +} + +struct snd_soc_platform mx1_mx2_soc_platform = { + .name = "mx1_mx2-audio", + .pcm_ops = &mx1_mx2_pcm_ops, + .pcm_new = mx1_mx2_pcm_new, + .pcm_free = mx1_mx2_pcm_free_dma_buffers, +}; +EXPORT_SYMBOL_GPL(mx1_mx2_soc_platform); + +static int __init mx1_mx2_soc_platform_init(void) +{ + return snd_soc_register_platform(&mx1_mx2_soc_platform); +} +module_init(mx1_mx2_soc_platform_init); + +static void __exit mx1_mx2_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&mx1_mx2_soc_platform); +} +module_exit(mx1_mx2_soc_platform_exit); + +MODULE_AUTHOR("Javier Martin, javier.martin@vista-silicon.com"); +MODULE_DESCRIPTION("Freescale i.MX2x, i.MX1x PCM DMA module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/imx/mx1_mx2-pcm.h b/sound/soc/imx/mx1_mx2-pcm.h new file mode 100644 index 0000000..e1e3a3f --- /dev/null +++ b/sound/soc/imx/mx1_mx2-pcm.h @@ -0,0 +1,48 @@ +/* + * mx1_mx2-pcm.h :- ASoC platform header for Freescale i.MX1x, i.MX2x + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef _MXC_PCM_H +#define _MXC_PCM_H + +/* AUDMUX register definitions */ +#define AUDMUX_IO_BASE_ADDR IO_ADDRESS(AUDMUX_BASE_ADDR) + +#define DAM_HPCR1 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x00))) +#define DAM_HPCR2 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x04))) +#define DAM_HPCR3 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x08))) +#define DAM_PPCR1 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x10))) +#define DAM_PPCR2 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x14))) +#define DAM_PPCR3 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x1C))) + +#define AUDMUX_HPCR_TFSDIR (1 << 31) +#define AUDMUX_HPCR_TCLKDIR (1 << 30) +#define AUDMUX_HPCR_TFCSEL(x) (((x) & 0xff) << 26) +#define AUDMUX_HPCR_RXDSEL(x) (((x) & 0x7) << 13) +#define AUDMUX_HPCR_SYN (1 << 12) + +#define AUDMUX_PPCR_TFSDIR (1 << 31) +#define AUDMUX_PPCR_TCLKDIR (1 << 30) +#define AUDMUX_PPCR_TFCSEL(x) (((x) & 0xff) << 26) +#define AUDMUX_PPCR_RXDSEL(x) (((x) & 0x7) << 13) +#define AUDMUX_PPCR_SYN (1 << 12) + +/* DMA information for mx1_mx2 platforms */ +struct mx1_mx2_pcm_dma_params { + char *name; /* stream identifier */ + unsigned int transfer_type; /* READ or WRITE DMA transfer */ + dma_addr_t per_address; /* physical address of SSI fifo */ + int event_id; /* fixed DMA number for SSI fifo */ + int watermark_level; /* SSI fifo watermark level */ + int per_config; /* DMA Config flags for peripheral */ + int mem_config; /* DMA Config flags for RAM */ + }; + +/* platform data */ +extern struct snd_soc_platform mx1_mx2_soc_platform; + +#endif -- cgit v0.10.2 From 9d8bc2968cb0b50ffa76ed806591974e34fc296a Mon Sep 17 00:00:00 2001 From: javier Martin Date: Wed, 5 Aug 2009 08:47:48 +0200 Subject: ASoC: add DAI platform ssi driver for MXC This adds support for DAI platform for the SSI present in MXC platforms. It currently does not support i.MX3, the only thing necessary to do this is to export DMA data for i.MX3 interface which I haven't done because I don't have a i.MX3 based board available. It has been tested on i.MX27 board. Signed-off-by: Mark Brown diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index a1bf053..886dadd 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -6,6 +6,8 @@ config SND_MX1_MX2_SOC Say Y or M if you want to add support for codecs attached to the MX1 or MX2 SSI interface. +config SND_MXC_SOC_SSI + tristate diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index c390f0f..6552cb2 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile @@ -1,4 +1,6 @@ # i.MX Platform Support snd-soc-mx1_mx2-objs := mx1_mx2-pcm.o +snd-soc-mxc-ssi-objs := mxc-ssi.o obj-$(CONFIG_SND_MX1_MX2_SOC) += snd-soc-mx1_mx2.o +obj-$(CONFIG_SND_MXC_SOC_SSI) += snd-soc-mxc-ssi.o diff --git a/sound/soc/imx/mxc-ssi.c b/sound/soc/imx/mxc-ssi.c new file mode 100644 index 0000000..3806ff2 --- /dev/null +++ b/sound/soc/imx/mxc-ssi.c @@ -0,0 +1,868 @@ +/* + * mxc-ssi.c -- SSI driver for Freescale IMX + * + * Copyright 2006 Wolfson Microelectronics PLC. + * Author: Liam Girdwood + * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com + * + * Based on mxc-alsa-mc13783 (C) 2006 Freescale. + * + * 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. + * + * TODO: + * Need to rework SSI register defs when new defs go into mainline. + * Add support for TDM and FIFO 1. + * Add support for i.mx3x DMA interface. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mxc-ssi.h" +#include "mx1_mx2-pcm.h" + +#define SSI1_PORT 0 +#define SSI2_PORT 1 + +static int ssi_active[2] = {0, 0}; + +/* DMA information for mx1_mx2 platforms */ +static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out0 = { + .name = "SSI1 PCM Stereo out 0", + .transfer_type = DMA_MODE_WRITE, + .per_address = SSI1_BASE_ADDR + STX0, + .event_id = DMA_REQ_SSI1_TX0, + .watermark_level = TXFIFO_WATERMARK, + .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, + .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, +}; + +static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out1 = { + .name = "SSI1 PCM Stereo out 1", + .transfer_type = DMA_MODE_WRITE, + .per_address = SSI1_BASE_ADDR + STX1, + .event_id = DMA_REQ_SSI1_TX1, + .watermark_level = TXFIFO_WATERMARK, + .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, + .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, +}; + +static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in0 = { + .name = "SSI1 PCM Stereo in 0", + .transfer_type = DMA_MODE_READ, + .per_address = SSI1_BASE_ADDR + SRX0, + .event_id = DMA_REQ_SSI1_RX0, + .watermark_level = RXFIFO_WATERMARK, + .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, + .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, +}; + +static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in1 = { + .name = "SSI1 PCM Stereo in 1", + .transfer_type = DMA_MODE_READ, + .per_address = SSI1_BASE_ADDR + SRX1, + .event_id = DMA_REQ_SSI1_RX1, + .watermark_level = RXFIFO_WATERMARK, + .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, + .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, +}; + +static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out0 = { + .name = "SSI2 PCM Stereo out 0", + .transfer_type = DMA_MODE_WRITE, + .per_address = SSI2_BASE_ADDR + STX0, + .event_id = DMA_REQ_SSI2_TX0, + .watermark_level = TXFIFO_WATERMARK, + .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, + .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, +}; + +static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out1 = { + .name = "SSI2 PCM Stereo out 1", + .transfer_type = DMA_MODE_WRITE, + .per_address = SSI2_BASE_ADDR + STX1, + .event_id = DMA_REQ_SSI2_TX1, + .watermark_level = TXFIFO_WATERMARK, + .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, + .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, +}; + +static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in0 = { + .name = "SSI2 PCM Stereo in 0", + .transfer_type = DMA_MODE_READ, + .per_address = SSI2_BASE_ADDR + SRX0, + .event_id = DMA_REQ_SSI2_RX0, + .watermark_level = RXFIFO_WATERMARK, + .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, + .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, +}; + +static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in1 = { + .name = "SSI2 PCM Stereo in 1", + .transfer_type = DMA_MODE_READ, + .per_address = SSI2_BASE_ADDR + SRX1, + .event_id = DMA_REQ_SSI2_RX1, + .watermark_level = RXFIFO_WATERMARK, + .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, + .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, +}; + +static struct clk *ssi_clk0, *ssi_clk1; + +int get_ssi_clk(int ssi, struct device *dev) +{ + switch (ssi) { + case 0: + ssi_clk0 = clk_get(dev, "ssi1"); + if (IS_ERR(ssi_clk0)) + return PTR_ERR(ssi_clk0); + return 0; + case 1: + ssi_clk1 = clk_get(dev, "ssi2"); + if (IS_ERR(ssi_clk1)) + return PTR_ERR(ssi_clk1); + return 0; + default: + return -EINVAL; + } +} +EXPORT_SYMBOL(get_ssi_clk); + +void put_ssi_clk(int ssi) +{ + switch (ssi) { + case 0: + clk_put(ssi_clk0); + ssi_clk0 = NULL; + break; + case 1: + clk_put(ssi_clk1); + ssi_clk1 = NULL; + break; + } +} +EXPORT_SYMBOL(put_ssi_clk); + +/* + * SSI system clock configuration. + * Should only be called when port is inactive (i.e. SSIEN = 0). + */ +static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + u32 scr; + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + scr = SSI1_SCR; + pr_debug("%s: SCR for SSI1 is %x\n", __func__, scr); + } else { + scr = SSI2_SCR; + pr_debug("%s: SCR for SSI2 is %x\n", __func__, scr); + } + + if (scr & SSI_SCR_SSIEN) { + printk(KERN_WARNING "Warning ssi already enabled\n"); + return 0; + } + + switch (clk_id) { + case IMX_SSP_SYS_CLK: + if (dir == SND_SOC_CLOCK_OUT) { + scr |= SSI_SCR_SYS_CLK_EN; + pr_debug("%s: clk of is output\n", __func__); + } else { + scr &= ~SSI_SCR_SYS_CLK_EN; + pr_debug("%s: clk of is input\n", __func__); + } + break; + default: + return -EINVAL; + } + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + pr_debug("%s: writeback of SSI1_SCR\n", __func__); + SSI1_SCR = scr; + } else { + pr_debug("%s: writeback of SSI2_SCR\n", __func__); + SSI2_SCR = scr; + } + + return 0; +} + +/* + * SSI Clock dividers + * Should only be called when port is inactive (i.e. SSIEN = 0). + */ +static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + u32 stccr, srccr; + + pr_debug("%s\n", __func__); + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + if (SSI1_SCR & SSI_SCR_SSIEN) + return 0; + srccr = SSI1_STCCR; + stccr = SSI1_STCCR; + } else { + if (SSI2_SCR & SSI_SCR_SSIEN) + return 0; + srccr = SSI2_STCCR; + stccr = SSI2_STCCR; + } + + switch (div_id) { + case IMX_SSI_TX_DIV_2: + stccr &= ~SSI_STCCR_DIV2; + stccr |= div; + break; + case IMX_SSI_TX_DIV_PSR: + stccr &= ~SSI_STCCR_PSR; + stccr |= div; + break; + case IMX_SSI_TX_DIV_PM: + stccr &= ~0xff; + stccr |= SSI_STCCR_PM(div); + break; + case IMX_SSI_RX_DIV_2: + stccr &= ~SSI_STCCR_DIV2; + stccr |= div; + break; + case IMX_SSI_RX_DIV_PSR: + stccr &= ~SSI_STCCR_PSR; + stccr |= div; + break; + case IMX_SSI_RX_DIV_PM: + stccr &= ~0xff; + stccr |= SSI_STCCR_PM(div); + break; + default: + return -EINVAL; + } + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + SSI1_STCCR = stccr; + SSI1_SRCCR = srccr; + } else { + SSI2_STCCR = stccr; + SSI2_SRCCR = srccr; + } + return 0; +} + +/* + * SSI Network Mode or TDM slots configuration. + * Should only be called when port is inactive (i.e. SSIEN = 0). + */ +static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, + unsigned int mask, int slots) +{ + u32 stmsk, srmsk, stccr; + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + if (SSI1_SCR & SSI_SCR_SSIEN) { + printk(KERN_WARNING "Warning ssi already enabled\n"); + return 0; + } + stccr = SSI1_STCCR; + } else { + if (SSI2_SCR & SSI_SCR_SSIEN) { + printk(KERN_WARNING "Warning ssi already enabled\n"); + return 0; + } + stccr = SSI2_STCCR; + } + + stmsk = srmsk = mask; + stccr &= ~SSI_STCCR_DC_MASK; + stccr |= SSI_STCCR_DC(slots - 1); + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + SSI1_STMSK = stmsk; + SSI1_SRMSK = srmsk; + SSI1_SRCCR = SSI1_STCCR = stccr; + } else { + SSI2_STMSK = stmsk; + SSI2_SRMSK = srmsk; + SSI2_SRCCR = SSI2_STCCR = stccr; + } + + return 0; +} + +/* + * SSI DAI format configuration. + * Should only be called when port is inactive (i.e. SSIEN = 0). + * Note: We don't use the I2S modes but instead manually configure the + * SSI for I2S. + */ +static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + u32 stcr = 0, srcr = 0, scr; + + /* + * This is done to avoid this function to modify + * previous set values in stcr + */ + stcr = SSI1_STCR; + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) + scr = SSI1_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET); + else + scr = SSI2_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET); + + if (scr & SSI_SCR_SSIEN) { + printk(KERN_WARNING "Warning ssi already enabled\n"); + return 0; + } + + /* DAI mode */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + /* data on rising edge of bclk, frame low 1clk before data */ + stcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0; + srcr |= SSI_SRCR_RFSI | SSI_SRCR_REFS | SSI_SRCR_RXBIT0; + break; + case SND_SOC_DAIFMT_LEFT_J: + /* data on rising edge of bclk, frame high with data */ + stcr |= SSI_STCR_TXBIT0; + srcr |= SSI_SRCR_RXBIT0; + break; + case SND_SOC_DAIFMT_DSP_B: + /* data on rising edge of bclk, frame high with data */ + stcr |= SSI_STCR_TFSL; + srcr |= SSI_SRCR_RFSL; + break; + case SND_SOC_DAIFMT_DSP_A: + /* data on rising edge of bclk, frame high 1clk before data */ + stcr |= SSI_STCR_TFSL | SSI_STCR_TEFS; + srcr |= SSI_SRCR_RFSL | SSI_SRCR_REFS; + break; + } + + /* DAI clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + stcr |= SSI_STCR_TFSI; + stcr &= ~SSI_STCR_TSCKP; + srcr |= SSI_SRCR_RFSI; + srcr &= ~SSI_SRCR_RSCKP; + break; + case SND_SOC_DAIFMT_IB_NF: + stcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI); + srcr &= ~(SSI_SRCR_RSCKP | SSI_SRCR_RFSI); + break; + case SND_SOC_DAIFMT_NB_IF: + stcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP; + srcr |= SSI_SRCR_RFSI | SSI_SRCR_RSCKP; + break; + case SND_SOC_DAIFMT_NB_NF: + stcr &= ~SSI_STCR_TFSI; + stcr |= SSI_STCR_TSCKP; + srcr &= ~SSI_SRCR_RFSI; + srcr |= SSI_SRCR_RSCKP; + break; + } + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + stcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR; + srcr |= SSI_SRCR_RFDIR | SSI_SRCR_RXDIR; + break; + case SND_SOC_DAIFMT_CBM_CFS: + stcr |= SSI_STCR_TFDIR; + srcr |= SSI_SRCR_RFDIR; + break; + case SND_SOC_DAIFMT_CBS_CFM: + stcr |= SSI_STCR_TXDIR; + srcr |= SSI_SRCR_RXDIR; + break; + } + + /* sync */ + if (!(fmt & SND_SOC_DAIFMT_ASYNC)) + scr |= SSI_SCR_SYN; + + /* tdm - only for stereo atm */ + if (fmt & SND_SOC_DAIFMT_TDM) + scr |= SSI_SCR_NET; + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + SSI1_STCR = stcr; + SSI1_SRCR = srcr; + SSI1_SCR = scr; + } else { + SSI2_STCR = stcr; + SSI2_SRCR = srcr; + SSI2_SCR = scr; + } + + return 0; +} + +static int imx_ssi_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* set up TX DMA params */ + switch (cpu_dai->id) { + case IMX_DAI_SSI0: + cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out0; + break; + case IMX_DAI_SSI1: + cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out1; + break; + case IMX_DAI_SSI2: + cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out0; + break; + case IMX_DAI_SSI3: + cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out1; + } + pr_debug("%s: (playback)\n", __func__); + } else { + /* set up RX DMA params */ + switch (cpu_dai->id) { + case IMX_DAI_SSI0: + cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in0; + break; + case IMX_DAI_SSI1: + cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in1; + break; + case IMX_DAI_SSI2: + cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in0; + break; + case IMX_DAI_SSI3: + cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in1; + } + pr_debug("%s: (capture)\n", __func__); + } + + /* + * we cant really change any SSI values after SSI is enabled + * need to fix in software for max flexibility - lrg + */ + if (cpu_dai->active) { + printk(KERN_WARNING "Warning ssi already enabled\n"); + return 0; + } + + /* reset the SSI port - Sect 45.4.4 */ + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + + if (!ssi_clk0) + return -EINVAL; + + if (ssi_active[SSI1_PORT]++) { + pr_debug("%s: exit before reset\n", __func__); + return 0; + } + + /* SSI1 Reset */ + SSI1_SCR = 0; + + SSI1_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) | + SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) | + SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) | + SSI_SFCSR_TFWM0(TXFIFO_WATERMARK); + } else { + + if (!ssi_clk1) + return -EINVAL; + + if (ssi_active[SSI2_PORT]++) { + pr_debug("%s: exit before reset\n", __func__); + return 0; + } + + /* SSI2 Reset */ + SSI2_SCR = 0; + + SSI2_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) | + SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) | + SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) | + SSI_SFCSR_TFWM0(TXFIFO_WATERMARK); + } + + return 0; +} + +int imx_ssi_hw_tx_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + u32 stccr, stcr, sier; + + pr_debug("%s\n", __func__); + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + stccr = SSI1_STCCR & ~SSI_STCCR_WL_MASK; + stcr = SSI1_STCR; + sier = SSI1_SIER; + } else { + stccr = SSI2_STCCR & ~SSI_STCCR_WL_MASK; + stcr = SSI2_STCR; + sier = SSI2_SIER; + } + + /* DAI data (word) size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + stccr |= SSI_STCCR_WL(16); + break; + case SNDRV_PCM_FORMAT_S20_3LE: + stccr |= SSI_STCCR_WL(20); + break; + case SNDRV_PCM_FORMAT_S24_LE: + stccr |= SSI_STCCR_WL(24); + break; + } + + /* enable interrupts */ + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) + stcr |= SSI_STCR_TFEN0; + else + stcr |= SSI_STCR_TFEN1; + sier |= SSI_SIER_TDMAE; + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + SSI1_STCR = stcr; + SSI1_STCCR = stccr; + SSI1_SIER = sier; + } else { + SSI2_STCR = stcr; + SSI2_STCCR = stccr; + SSI2_SIER = sier; + } + + return 0; +} + +int imx_ssi_hw_rx_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + u32 srccr, srcr, sier; + + pr_debug("%s\n", __func__); + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + srccr = SSI1_SRCCR & ~SSI_SRCCR_WL_MASK; + srcr = SSI1_SRCR; + sier = SSI1_SIER; + } else { + srccr = SSI2_SRCCR & ~SSI_SRCCR_WL_MASK; + srcr = SSI2_SRCR; + sier = SSI2_SIER; + } + + /* DAI data (word) size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + srccr |= SSI_SRCCR_WL(16); + break; + case SNDRV_PCM_FORMAT_S20_3LE: + srccr |= SSI_SRCCR_WL(20); + break; + case SNDRV_PCM_FORMAT_S24_LE: + srccr |= SSI_SRCCR_WL(24); + break; + } + + /* enable interrupts */ + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) + srcr |= SSI_SRCR_RFEN0; + else + srcr |= SSI_SRCR_RFEN1; + sier |= SSI_SIER_RDMAE; + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + SSI1_SRCR = srcr; + SSI1_SRCCR = srccr; + SSI1_SIER = sier; + } else { + SSI2_SRCR = srcr; + SSI2_SRCCR = srccr; + SSI2_SIER = sier; + } + + return 0; +} + +/* + * Should only be called when port is inactive (i.e. SSIEN = 0), + * although can be called multiple times by upper layers. + */ +int imx_ssi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + int ret; + + /* cant change any parameters when SSI is running */ + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + if (SSI1_SCR & SSI_SCR_SSIEN) { + printk(KERN_WARNING "Warning ssi already enabled\n"); + return 0; + } + } else { + if (SSI2_SCR & SSI_SCR_SSIEN) { + printk(KERN_WARNING "Warning ssi already enabled\n"); + return 0; + } + } + + /* + * Configure both tx and rx params with the same settings. This is + * really a harware restriction because SSI must be disabled until + * we can change those values. If there is an active audio stream in + * one direction, enabling the other direction with different + * settings would mean disturbing the running one. + */ + ret = imx_ssi_hw_tx_params(substream, params); + if (ret < 0) + return ret; + return imx_ssi_hw_rx_params(substream, params); +} + +int imx_ssi_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + pr_debug("%s\n", __func__); + + /* Enable clks here to follow SSI recommended init sequence */ + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) { + ret = clk_enable(ssi_clk0); + if (ret < 0) + printk(KERN_ERR "Unable to enable ssi_clk0\n"); + } else { + ret = clk_enable(ssi_clk1); + if (ret < 0) + printk(KERN_ERR "Unable to enable ssi_clk1\n"); + } + + return 0; +} + +static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + u32 scr; + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) + scr = SSI1_SCR; + else + scr = SSI2_SCR; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + scr |= SSI_SCR_TE | SSI_SCR_SSIEN; + else + scr |= SSI_SCR_RE | SSI_SCR_SSIEN; + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + scr &= ~SSI_SCR_TE; + else + scr &= ~SSI_SCR_RE; + break; + default: + return -EINVAL; + } + + if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) + SSI1_SCR = scr; + else + SSI2_SCR = scr; + + return 0; +} + +static void imx_ssi_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + /* shutdown SSI if neither Tx or Rx is active */ + if (!cpu_dai->active) { + + if (cpu_dai->id == IMX_DAI_SSI0 || + cpu_dai->id == IMX_DAI_SSI2) { + + if (--ssi_active[SSI1_PORT] > 1) + return; + + SSI1_SCR = 0; + clk_disable(ssi_clk0); + } else { + if (--ssi_active[SSI2_PORT]) + return; + SSI2_SCR = 0; + clk_disable(ssi_clk1); + } + } +} + +#ifdef CONFIG_PM +static int imx_ssi_suspend(struct platform_device *dev, + struct snd_soc_dai *dai) +{ + return 0; +} + +static int imx_ssi_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + return 0; +} + +#else +#define imx_ssi_suspend NULL +#define imx_ssi_resume NULL +#endif + +#define IMX_SSI_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000) + +#define IMX_SSI_BITS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = { + .startup = imx_ssi_startup, + .shutdown = imx_ssi_shutdown, + .trigger = imx_ssi_trigger, + .prepare = imx_ssi_prepare, + .hw_params = imx_ssi_hw_params, + .set_sysclk = imx_ssi_set_dai_sysclk, + .set_clkdiv = imx_ssi_set_dai_clkdiv, + .set_fmt = imx_ssi_set_dai_fmt, + .set_tdm_slot = imx_ssi_set_dai_tdm_slot, +}; + +struct snd_soc_dai imx_ssi_pcm_dai[] = { +{ + .name = "imx-i2s-1-0", + .id = IMX_DAI_SSI0, + .suspend = imx_ssi_suspend, + .resume = imx_ssi_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .formats = IMX_SSI_BITS, + .rates = IMX_SSI_RATES,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .formats = IMX_SSI_BITS, + .rates = IMX_SSI_RATES,}, + .ops = &imx_ssi_pcm_dai_ops, +}, +{ + .name = "imx-i2s-2-0", + .id = IMX_DAI_SSI1, + .playback = { + .channels_min = 1, + .channels_max = 2, + .formats = IMX_SSI_BITS, + .rates = IMX_SSI_RATES,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .formats = IMX_SSI_BITS, + .rates = IMX_SSI_RATES,}, + .ops = &imx_ssi_pcm_dai_ops, +}, +{ + .name = "imx-i2s-1-1", + .id = IMX_DAI_SSI2, + .suspend = imx_ssi_suspend, + .resume = imx_ssi_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .formats = IMX_SSI_BITS, + .rates = IMX_SSI_RATES,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .formats = IMX_SSI_BITS, + .rates = IMX_SSI_RATES,}, + .ops = &imx_ssi_pcm_dai_ops, +}, +{ + .name = "imx-i2s-2-1", + .id = IMX_DAI_SSI3, + .playback = { + .channels_min = 1, + .channels_max = 2, + .formats = IMX_SSI_BITS, + .rates = IMX_SSI_RATES,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .formats = IMX_SSI_BITS, + .rates = IMX_SSI_RATES,}, + .ops = &imx_ssi_pcm_dai_ops, +}, +}; +EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai); + +static int __init imx_ssi_init(void) +{ + return snd_soc_register_dais(imx_ssi_pcm_dai, + ARRAY_SIZE(imx_ssi_pcm_dai)); +} + +static void __exit imx_ssi_exit(void) +{ + snd_soc_unregister_dais(imx_ssi_pcm_dai, + ARRAY_SIZE(imx_ssi_pcm_dai)); +} + +module_init(imx_ssi_init); +module_exit(imx_ssi_exit); +MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com"); +MODULE_DESCRIPTION("i.MX ASoC I2S driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/imx/mxc-ssi.h b/sound/soc/imx/mxc-ssi.h new file mode 100644 index 0000000..12bbdc9 --- /dev/null +++ b/sound/soc/imx/mxc-ssi.h @@ -0,0 +1,238 @@ +/* + * 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 + * published by the Free Software Foundation. + */ + +#ifndef _IMX_SSI_H +#define _IMX_SSI_H + +#include + +/* SSI regs definition - MOVE to /arch/arm/plat-mxc/include/mach/ when stable */ +#define SSI1_IO_BASE_ADDR IO_ADDRESS(SSI1_BASE_ADDR) +#define SSI2_IO_BASE_ADDR IO_ADDRESS(SSI2_BASE_ADDR) + +#define STX0 0x00 +#define STX1 0x04 +#define SRX0 0x08 +#define SRX1 0x0c +#define SCR 0x10 +#define SISR 0x14 +#define SIER 0x18 +#define STCR 0x1c +#define SRCR 0x20 +#define STCCR 0x24 +#define SRCCR 0x28 +#define SFCSR 0x2c +#define STR 0x30 +#define SOR 0x34 +#define SACNT 0x38 +#define SACADD 0x3c +#define SACDAT 0x40 +#define SATAG 0x44 +#define STMSK 0x48 +#define SRMSK 0x4c + +#define SSI1_STX0 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STX0))) +#define SSI1_STX1 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STX1))) +#define SSI1_SRX0 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRX0))) +#define SSI1_SRX1 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRX1))) +#define SSI1_SCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SCR))) +#define SSI1_SISR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SISR))) +#define SSI1_SIER (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SIER))) +#define SSI1_STCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STCR))) +#define SSI1_SRCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRCR))) +#define SSI1_STCCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STCCR))) +#define SSI1_SRCCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRCCR))) +#define SSI1_SFCSR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SFCSR))) +#define SSI1_STR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STR))) +#define SSI1_SOR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SOR))) +#define SSI1_SACNT (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACNT))) +#define SSI1_SACADD (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACADD))) +#define SSI1_SACDAT (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACDAT))) +#define SSI1_SATAG (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SATAG))) +#define SSI1_STMSK (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STMSK))) +#define SSI1_SRMSK (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRMSK))) + + +#define SSI2_STX0 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STX0))) +#define SSI2_STX1 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STX1))) +#define SSI2_SRX0 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRX0))) +#define SSI2_SRX1 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRX1))) +#define SSI2_SCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SCR))) +#define SSI2_SISR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SISR))) +#define SSI2_SIER (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SIER))) +#define SSI2_STCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STCR))) +#define SSI2_SRCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRCR))) +#define SSI2_STCCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STCCR))) +#define SSI2_SRCCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRCCR))) +#define SSI2_SFCSR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SFCSR))) +#define SSI2_STR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STR))) +#define SSI2_SOR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SOR))) +#define SSI2_SACNT (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACNT))) +#define SSI2_SACADD (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACADD))) +#define SSI2_SACDAT (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACDAT))) +#define SSI2_SATAG (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SATAG))) +#define SSI2_STMSK (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STMSK))) +#define SSI2_SRMSK (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRMSK))) + +#define SSI_SCR_CLK_IST (1 << 9) +#define SSI_SCR_TCH_EN (1 << 8) +#define SSI_SCR_SYS_CLK_EN (1 << 7) +#define SSI_SCR_I2S_MODE_NORM (0 << 5) +#define SSI_SCR_I2S_MODE_MSTR (1 << 5) +#define SSI_SCR_I2S_MODE_SLAVE (2 << 5) +#define SSI_SCR_SYN (1 << 4) +#define SSI_SCR_NET (1 << 3) +#define SSI_SCR_RE (1 << 2) +#define SSI_SCR_TE (1 << 1) +#define SSI_SCR_SSIEN (1 << 0) + +#define SSI_SISR_CMDAU (1 << 18) +#define SSI_SISR_CMDDU (1 << 17) +#define SSI_SISR_RXT (1 << 16) +#define SSI_SISR_RDR1 (1 << 15) +#define SSI_SISR_RDR0 (1 << 14) +#define SSI_SISR_TDE1 (1 << 13) +#define SSI_SISR_TDE0 (1 << 12) +#define SSI_SISR_ROE1 (1 << 11) +#define SSI_SISR_ROE0 (1 << 10) +#define SSI_SISR_TUE1 (1 << 9) +#define SSI_SISR_TUE0 (1 << 8) +#define SSI_SISR_TFS (1 << 7) +#define SSI_SISR_RFS (1 << 6) +#define SSI_SISR_TLS (1 << 5) +#define SSI_SISR_RLS (1 << 4) +#define SSI_SISR_RFF1 (1 << 3) +#define SSI_SISR_RFF0 (1 << 2) +#define SSI_SISR_TFE1 (1 << 1) +#define SSI_SISR_TFE0 (1 << 0) + +#define SSI_SIER_RDMAE (1 << 22) +#define SSI_SIER_RIE (1 << 21) +#define SSI_SIER_TDMAE (1 << 20) +#define SSI_SIER_TIE (1 << 19) +#define SSI_SIER_CMDAU_EN (1 << 18) +#define SSI_SIER_CMDDU_EN (1 << 17) +#define SSI_SIER_RXT_EN (1 << 16) +#define SSI_SIER_RDR1_EN (1 << 15) +#define SSI_SIER_RDR0_EN (1 << 14) +#define SSI_SIER_TDE1_EN (1 << 13) +#define SSI_SIER_TDE0_EN (1 << 12) +#define SSI_SIER_ROE1_EN (1 << 11) +#define SSI_SIER_ROE0_EN (1 << 10) +#define SSI_SIER_TUE1_EN (1 << 9) +#define SSI_SIER_TUE0_EN (1 << 8) +#define SSI_SIER_TFS_EN (1 << 7) +#define SSI_SIER_RFS_EN (1 << 6) +#define SSI_SIER_TLS_EN (1 << 5) +#define SSI_SIER_RLS_EN (1 << 4) +#define SSI_SIER_RFF1_EN (1 << 3) +#define SSI_SIER_RFF0_EN (1 << 2) +#define SSI_SIER_TFE1_EN (1 << 1) +#define SSI_SIER_TFE0_EN (1 << 0) + +#define SSI_STCR_TXBIT0 (1 << 9) +#define SSI_STCR_TFEN1 (1 << 8) +#define SSI_STCR_TFEN0 (1 << 7) +#define SSI_STCR_TFDIR (1 << 6) +#define SSI_STCR_TXDIR (1 << 5) +#define SSI_STCR_TSHFD (1 << 4) +#define SSI_STCR_TSCKP (1 << 3) +#define SSI_STCR_TFSI (1 << 2) +#define SSI_STCR_TFSL (1 << 1) +#define SSI_STCR_TEFS (1 << 0) + +#define SSI_SRCR_RXBIT0 (1 << 9) +#define SSI_SRCR_RFEN1 (1 << 8) +#define SSI_SRCR_RFEN0 (1 << 7) +#define SSI_SRCR_RFDIR (1 << 6) +#define SSI_SRCR_RXDIR (1 << 5) +#define SSI_SRCR_RSHFD (1 << 4) +#define SSI_SRCR_RSCKP (1 << 3) +#define SSI_SRCR_RFSI (1 << 2) +#define SSI_SRCR_RFSL (1 << 1) +#define SSI_SRCR_REFS (1 << 0) + +#define SSI_STCCR_DIV2 (1 << 18) +#define SSI_STCCR_PSR (1 << 15) +#define SSI_STCCR_WL(x) ((((x) - 2) >> 1) << 13) +#define SSI_STCCR_DC(x) (((x) & 0x1f) << 8) +#define SSI_STCCR_PM(x) (((x) & 0xff) << 0) +#define SSI_STCCR_WL_MASK (0xf << 13) +#define SSI_STCCR_DC_MASK (0x1f << 8) +#define SSI_STCCR_PM_MASK (0xff << 0) + +#define SSI_SRCCR_DIV2 (1 << 18) +#define SSI_SRCCR_PSR (1 << 15) +#define SSI_SRCCR_WL(x) ((((x) - 2) >> 1) << 13) +#define SSI_SRCCR_DC(x) (((x) & 0x1f) << 8) +#define SSI_SRCCR_PM(x) (((x) & 0xff) << 0) +#define SSI_SRCCR_WL_MASK (0xf << 13) +#define SSI_SRCCR_DC_MASK (0x1f << 8) +#define SSI_SRCCR_PM_MASK (0xff << 0) + + +#define SSI_SFCSR_RFCNT1(x) (((x) & 0xf) << 28) +#define SSI_SFCSR_TFCNT1(x) (((x) & 0xf) << 24) +#define SSI_SFCSR_RFWM1(x) (((x) & 0xf) << 20) +#define SSI_SFCSR_TFWM1(x) (((x) & 0xf) << 16) +#define SSI_SFCSR_RFCNT0(x) (((x) & 0xf) << 12) +#define SSI_SFCSR_TFCNT0(x) (((x) & 0xf) << 8) +#define SSI_SFCSR_RFWM0(x) (((x) & 0xf) << 4) +#define SSI_SFCSR_TFWM0(x) (((x) & 0xf) << 0) + +#define SSI_STR_TEST (1 << 15) +#define SSI_STR_RCK2TCK (1 << 14) +#define SSI_STR_RFS2TFS (1 << 13) +#define SSI_STR_RXSTATE(x) (((x) & 0xf) << 8) +#define SSI_STR_TXD2RXD (1 << 7) +#define SSI_STR_TCK2RCK (1 << 6) +#define SSI_STR_TFS2RFS (1 << 5) +#define SSI_STR_TXSTATE(x) (((x) & 0xf) << 0) + +#define SSI_SOR_CLKOFF (1 << 6) +#define SSI_SOR_RX_CLR (1 << 5) +#define SSI_SOR_TX_CLR (1 << 4) +#define SSI_SOR_INIT (1 << 3) +#define SSI_SOR_WAIT(x) (((x) & 0x3) << 1) +#define SSI_SOR_SYNRST (1 << 0) + +#define SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5) +#define SSI_SACNT_WR (x << 4) +#define SSI_SACNT_RD (x << 3) +#define SSI_SACNT_TIF (x << 2) +#define SSI_SACNT_FV (x << 1) +#define SSI_SACNT_AC97EN (x << 0) + +/* Watermarks for FIFO's */ +#define TXFIFO_WATERMARK 0x4 +#define RXFIFO_WATERMARK 0x4 + +/* i.MX DAI SSP ID's */ +#define IMX_DAI_SSI0 0 /* SSI1 FIFO 0 */ +#define IMX_DAI_SSI1 1 /* SSI1 FIFO 1 */ +#define IMX_DAI_SSI2 2 /* SSI2 FIFO 0 */ +#define IMX_DAI_SSI3 3 /* SSI2 FIFO 1 */ + +/* SSI clock sources */ +#define IMX_SSP_SYS_CLK 0 + +/* SSI audio dividers */ +#define IMX_SSI_TX_DIV_2 0 +#define IMX_SSI_TX_DIV_PSR 1 +#define IMX_SSI_TX_DIV_PM 2 +#define IMX_SSI_RX_DIV_2 3 +#define IMX_SSI_RX_DIV_PSR 4 +#define IMX_SSI_RX_DIV_PM 5 + + +/* SSI Div 2 */ +#define IMX_SSI_DIV_2_OFF (~SSI_STCCR_DIV2) +#define IMX_SSI_DIV_2_ON SSI_STCCR_DIV2 + +extern struct snd_soc_dai imx_ssi_pcm_dai[4]; +extern int get_ssi_clk(int ssi, struct device *dev); +extern void put_ssi_clk(int ssi); +#endif -- cgit v0.10.2 From 2ccafed43a75b836a15bd36ef0acf466ba36604d Mon Sep 17 00:00:00 2001 From: javier Martin Date: Tue, 4 Aug 2009 17:18:02 +0200 Subject: ASoC: add machine driver for i.mx27_visstrim_m10 board This adds support for i.mx27_visstrim_sm10 board machine driver which uses an i.mx27 processor plus a wm8974 codec. It has been tested on a visstrim_sm10 board. Signed-off-by: Javier Martin Signed-off-by: Mark Brown diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index 886dadd..565e327 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -9,5 +9,13 @@ config SND_MX1_MX2_SOC config SND_MXC_SOC_SSI tristate +config SND_SOC_MX27VIS_WM8974 + tristate "SoC Audio support for MX27 - WM8974 Visstrim_sm10 board" + depends on SND_MX1_MX2_SOC && MACH_MX27 && MACH_IMX27_VISSTRIM_M10 + select SND_MXC_SOC_SSI + select SND_SOC_WM8974 + help + Say Y if you want to add support for SoC audio on Visstrim SM10 + board with WM8974. diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index 6552cb2..c2ffd2c 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile @@ -4,3 +4,7 @@ snd-soc-mxc-ssi-objs := mxc-ssi.o obj-$(CONFIG_SND_MX1_MX2_SOC) += snd-soc-mx1_mx2.o obj-$(CONFIG_SND_MXC_SOC_SSI) += snd-soc-mxc-ssi.o + +# i.MX Machine Support +snd-soc-mx27vis-wm8974-objs := mx27vis_wm8974.o +obj-$(CONFIG_SND_SOC_MX27VIS_WM8974) += snd-soc-mx27vis-wm8974.o diff --git a/sound/soc/imx/mx27vis_wm8974.c b/sound/soc/imx/mx27vis_wm8974.c new file mode 100644 index 0000000..e4dcb53 --- /dev/null +++ b/sound/soc/imx/mx27vis_wm8974.c @@ -0,0 +1,317 @@ +/* + * mx27vis_wm8974.c -- SoC audio for mx27vis + * + * Copyright 2009 Vista Silicon S.L. + * Author: Javier Martin + * javier.martin@vista-silicon.com + * + * 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 +#include +#include +#include +#include +#include +#include +#include + + +#include "../codecs/wm8974.h" +#include "mx1_mx2-pcm.h" +#include "mxc-ssi.h" +#include +#include + +#define IGNORED_ARG 0 + + +static struct snd_soc_card mx27vis; + +/** + * This function connects SSI1 (HPCR1) as slave to + * SSI1 external signals (PPCR1) + * As slave, HPCR1 must set TFSDIR and TCLKDIR as inputs from + * port 4 + */ +void audmux_connect_1_4(void) +{ + pr_debug("AUDMUX: normal operation mode\n"); + /* Reset HPCR1 and PPCR1 */ + + DAM_HPCR1 = 0x00000000; + DAM_PPCR1 = 0x00000000; + + /* set to synchronous */ + DAM_HPCR1 |= AUDMUX_HPCR_SYN; + DAM_PPCR1 |= AUDMUX_PPCR_SYN; + + + /* set Rx sources 1 <--> 4 */ + DAM_HPCR1 |= AUDMUX_HPCR_RXDSEL(3); /* port 4 */ + DAM_PPCR1 |= AUDMUX_PPCR_RXDSEL(0); /* port 1 */ + + /* set Tx frame and Clock direction and source 4 --> 1 output */ + DAM_HPCR1 |= AUDMUX_HPCR_TFSDIR | AUDMUX_HPCR_TCLKDIR; + DAM_HPCR1 |= AUDMUX_HPCR_TFCSEL(3); /* TxDS and TxCclk from port 4 */ + + return; +} + +static int mx27vis_hifi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int pll_out = 0, bclk = 0, fmt = 0, mclk = 0; + int ret = 0; + + /* + * The WM8974 is better at generating accurate audio clocks than the + * MX27 SSI controller, so we will use it as master when we can. + */ + switch (params_rate(params)) { + case 8000: + fmt = SND_SOC_DAIFMT_CBM_CFM; + mclk = WM8974_MCLKDIV_12; + pll_out = 24576000; + break; + case 16000: + fmt = SND_SOC_DAIFMT_CBM_CFM; + pll_out = 12288000; + break; + case 48000: + fmt = SND_SOC_DAIFMT_CBM_CFM; + bclk = WM8974_BCLKDIV_4; + pll_out = 12288000; + break; + case 96000: + fmt = SND_SOC_DAIFMT_CBM_CFM; + bclk = WM8974_BCLKDIV_2; + pll_out = 12288000; + break; + case 11025: + fmt = SND_SOC_DAIFMT_CBM_CFM; + bclk = WM8974_BCLKDIV_16; + pll_out = 11289600; + break; + case 22050: + fmt = SND_SOC_DAIFMT_CBM_CFM; + bclk = WM8974_BCLKDIV_8; + pll_out = 11289600; + break; + case 44100: + fmt = SND_SOC_DAIFMT_CBM_CFM; + bclk = WM8974_BCLKDIV_4; + mclk = WM8974_MCLKDIV_2; + pll_out = 11289600; + break; + case 88200: + fmt = SND_SOC_DAIFMT_CBM_CFM; + bclk = WM8974_BCLKDIV_2; + pll_out = 11289600; + break; + } + + /* set codec DAI configuration */ + ret = codec_dai->ops->set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_SYNC | fmt); + if (ret < 0) { + printk(KERN_ERR "Error from codec DAI configuration\n"); + return ret; + } + + /* set cpu DAI configuration */ + ret = cpu_dai->ops->set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_SYNC | fmt); + if (ret < 0) { + printk(KERN_ERR "Error from cpu DAI configuration\n"); + return ret; + } + + /* Put DC field of STCCR to 1 (not zero) */ + ret = cpu_dai->ops->set_tdm_slot(cpu_dai, 0, 2); + + /* set the SSI system clock as input */ + ret = cpu_dai->ops->set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "Error when setting system SSI clk\n"); + return ret; + } + + /* set codec BCLK division for sample rate */ + ret = codec_dai->ops->set_clkdiv(codec_dai, WM8974_BCLKDIV, bclk); + if (ret < 0) { + printk(KERN_ERR "Error when setting BCLK division\n"); + return ret; + } + + + /* codec PLL input is 25 MHz */ + ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, + 25000000, pll_out); + if (ret < 0) { + printk(KERN_ERR "Error when setting PLL input\n"); + return ret; + } + + /*set codec MCLK division for sample rate */ + ret = codec_dai->ops->set_clkdiv(codec_dai, WM8974_MCLKDIV, mclk); + if (ret < 0) { + printk(KERN_ERR "Error when setting MCLK division\n"); + return ret; + } + + return 0; +} + +static int mx27vis_hifi_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + + /* disable the PLL */ + return codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, 0, 0); +} + +/* + * mx27vis WM8974 HiFi DAI opserations. + */ +static struct snd_soc_ops mx27vis_hifi_ops = { + .hw_params = mx27vis_hifi_hw_params, + .hw_free = mx27vis_hifi_hw_free, +}; + + +static int mx27vis_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static int mx27vis_resume(struct platform_device *pdev) +{ + return 0; +} + +static int mx27vis_probe(struct platform_device *pdev) +{ + int ret = 0; + + ret = get_ssi_clk(0, &pdev->dev); + + if (ret < 0) { + printk(KERN_ERR "%s: cant get ssi clock\n", __func__); + return ret; + } + + + return 0; +} + +static int mx27vis_remove(struct platform_device *pdev) +{ + put_ssi_clk(0); + return 0; +} + +static struct snd_soc_dai_link mx27vis_dai[] = { +{ /* Hifi Playback*/ + .name = "WM8974", + .stream_name = "WM8974 HiFi", + .cpu_dai = &imx_ssi_pcm_dai[0], + .codec_dai = &wm8974_dai, + .ops = &mx27vis_hifi_ops, +}, +}; + +static struct snd_soc_card mx27vis = { + .name = "mx27vis", + .platform = &mx1_mx2_soc_platform, + .probe = mx27vis_probe, + .remove = mx27vis_remove, + .suspend_pre = mx27vis_suspend, + .resume_post = mx27vis_resume, + .dai_link = mx27vis_dai, + .num_links = ARRAY_SIZE(mx27vis_dai), +}; + +static struct snd_soc_device mx27vis_snd_devdata = { + .card = &mx27vis, + .codec_dev = &soc_codec_dev_wm8974, +}; + +static struct platform_device *mx27vis_snd_device; + +/* Temporal definition of board specific behaviour */ +void gpio_ssi_active(int ssi_num) +{ + int ret = 0; + + unsigned int ssi1_pins[] = { + PC20_PF_SSI1_FS, + PC21_PF_SSI1_RXD, + PC22_PF_SSI1_TXD, + PC23_PF_SSI1_CLK, + }; + unsigned int ssi2_pins[] = { + PC24_PF_SSI2_FS, + PC25_PF_SSI2_RXD, + PC26_PF_SSI2_TXD, + PC27_PF_SSI2_CLK, + }; + if (ssi_num == 0) + ret = mxc_gpio_setup_multiple_pins(ssi1_pins, + ARRAY_SIZE(ssi1_pins), "USB OTG"); + else + ret = mxc_gpio_setup_multiple_pins(ssi2_pins, + ARRAY_SIZE(ssi2_pins), "USB OTG"); + if (ret) + printk(KERN_ERR "Error requesting ssi %x pins\n", ssi_num); +} + + +static int __init mx27vis_init(void) +{ + int ret; + + mx27vis_snd_device = platform_device_alloc("soc-audio", -1); + if (!mx27vis_snd_device) + return -ENOMEM; + + platform_set_drvdata(mx27vis_snd_device, &mx27vis_snd_devdata); + mx27vis_snd_devdata.dev = &mx27vis_snd_device->dev; + ret = platform_device_add(mx27vis_snd_device); + + if (ret) { + printk(KERN_ERR "ASoC: Platform device allocation failed\n"); + platform_device_put(mx27vis_snd_device); + } + + /* WM8974 uses SSI1 (HPCR1) via AUDMUX port 4 for audio (PPCR1) */ + gpio_ssi_active(0); + audmux_connect_1_4(); + + return ret; +} + +static void __exit mx27vis_exit(void) +{ + /* We should call some "ssi_gpio_inactive()" properly */ +} + +module_init(mx27vis_init); +module_exit(mx27vis_exit); + + +MODULE_AUTHOR("Javier Martin, javier.martin@vista-silicon.com"); +MODULE_DESCRIPTION("ALSA SoC WM8974 mx27vis"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From fbb474dedab871c7382858c374acd287dad4ab38 Mon Sep 17 00:00:00 2001 From: javier Martin Date: Wed, 5 Aug 2009 22:29:39 +0100 Subject: ASoC: Fix review issues in i.MX2x PCM driver Signed-off-by: javier Martin Signed-off-by: Mark Brown diff --git a/sound/soc/imx/mx1_mx2-pcm.c b/sound/soc/imx/mx1_mx2-pcm.c index 94807f8..16efd8a 100644 --- a/sound/soc/imx/mx1_mx2-pcm.c +++ b/sound/soc/imx/mx1_mx2-pcm.c @@ -126,7 +126,7 @@ static int dma_new_period(struct snd_pcm_substream *substream) dma_size, dev_addr, prtd->dma_params->transfer_type); if (ret < 0) { - printk(KERN_ERR "Error configuring DMA\n"); + printk(KERN_ERR "Error %d configuring DMA\n", ret); return ret; } imx_dma_enable(prtd->dma_ch); @@ -216,7 +216,8 @@ static int mx1_mx2_pcm_hw_params(struct snd_pcm_substream *substream, ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (ret < 0) { - printk(KERN_ERR "%s: failed to malloc pcm pages\n", __func__); + printk(KERN_ERR "%s: Error %d failed to malloc pcm pages \n", + __func__, ret); return ret; } @@ -324,7 +325,7 @@ static int mx1_mx2_pcm_open(struct snd_pcm_substream *substream) prtd->dma_ch = imx_dma_request_by_prio(prtd->dma_params->name, DMA_PRIO_HIGH); if (prtd->dma_ch < 0) { - printk(KERN_ERR "Error requesting dma channel\n"); + printk(KERN_ERR "Error %d requesting dma channel\n", ret); return ret; } imx_dma_config_burstlen(prtd->dma_ch, @@ -336,8 +337,8 @@ static int mx1_mx2_pcm_open(struct snd_pcm_substream *substream) prtd->dma_params->event_id, 0); if (ret) { - pr_debug(KERN_ERR "Error configuring dma channel %d\n", - prtd->dma_ch); + pr_debug(KERN_ERR "Error %d configuring dma channel %d\n", + ret, prtd->dma_ch); return ret; } @@ -346,7 +347,7 @@ static int mx1_mx2_pcm_open(struct snd_pcm_substream *substream) audio_dma_irq, NULL, (void *)substream); if (ret < 0) { - printk(KERN_ERR "Error setting dma callback function\n"); + printk(KERN_ERR "Error %d setting dma callback function\n", ret); return ret; } return 0; diff --git a/sound/soc/imx/mx1_mx2-pcm.h b/sound/soc/imx/mx1_mx2-pcm.h index e1e3a3f..2e52810 100644 --- a/sound/soc/imx/mx1_mx2-pcm.h +++ b/sound/soc/imx/mx1_mx2-pcm.h @@ -6,30 +6,8 @@ * published by the Free Software Foundation. */ -#ifndef _MXC_PCM_H -#define _MXC_PCM_H - -/* AUDMUX register definitions */ -#define AUDMUX_IO_BASE_ADDR IO_ADDRESS(AUDMUX_BASE_ADDR) - -#define DAM_HPCR1 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x00))) -#define DAM_HPCR2 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x04))) -#define DAM_HPCR3 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x08))) -#define DAM_PPCR1 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x10))) -#define DAM_PPCR2 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x14))) -#define DAM_PPCR3 (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x1C))) - -#define AUDMUX_HPCR_TFSDIR (1 << 31) -#define AUDMUX_HPCR_TCLKDIR (1 << 30) -#define AUDMUX_HPCR_TFCSEL(x) (((x) & 0xff) << 26) -#define AUDMUX_HPCR_RXDSEL(x) (((x) & 0x7) << 13) -#define AUDMUX_HPCR_SYN (1 << 12) - -#define AUDMUX_PPCR_TFSDIR (1 << 31) -#define AUDMUX_PPCR_TCLKDIR (1 << 30) -#define AUDMUX_PPCR_TFCSEL(x) (((x) & 0xff) << 26) -#define AUDMUX_PPCR_RXDSEL(x) (((x) & 0x7) << 13) -#define AUDMUX_PPCR_SYN (1 << 12) +#ifndef _MX1_MX2_PCM_H +#define _MX1_MX2_PCM_H /* DMA information for mx1_mx2 platforms */ struct mx1_mx2_pcm_dma_params { -- cgit v0.10.2 From da34d4248bd2013ee64ce51e63ec0ebd1f32b46c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 5 Aug 2009 14:34:55 +0200 Subject: security/smack: Use AF_INET for sin_family field Elsewhere the sin_family field holds a value with a name of the form AF_..., so it seems reasonable to do so here as well. Also the values of PF_INET and AF_INET are the same. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ struct sockaddr_in sip; @@ ( sip.sin_family == - PF_INET + AF_INET | sip.sin_family != - PF_INET + AF_INET | sip.sin_family = - PF_INET + AF_INET ) // Signed-off-by: Julia Lawall Acked-by: Casey Schaufler Signed-off-by: James Morris diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 1c9bdbc..c243a2b 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2464,7 +2464,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, /* * Perfectly reasonable for this to be NULL */ - if (sip == NULL || sip->sin_family != PF_INET) + if (sip == NULL || sip->sin_family != AF_INET) return 0; return smack_netlabel_send(sock->sk, sip); -- cgit v0.10.2 From 7c73875e7dda627040b12c19b01db634fa7f0fd1 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 31 Jul 2009 12:53:58 -0400 Subject: Capabilities: move cap_file_mmap to commoncap.c Currently we duplicate the mmap_min_addr test in cap_file_mmap and in security_file_mmap if !CONFIG_SECURITY. This patch moves cap_file_mmap into commoncap.c and then calls that function directly from security_file_mmap ifndef CONFIG_SECURITY like all of the other capability checks are done. Signed-off-by: Eric Paris Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/include/linux/security.h b/include/linux/security.h index 1459091..963a48f 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -66,6 +66,9 @@ extern int cap_inode_setxattr(struct dentry *dentry, const char *name, extern int cap_inode_removexattr(struct dentry *dentry, const char *name); extern int cap_inode_need_killpriv(struct dentry *dentry); extern int cap_inode_killpriv(struct dentry *dentry); +extern int cap_file_mmap(struct file *file, unsigned long reqprot, + unsigned long prot, unsigned long flags, + unsigned long addr, unsigned long addr_only); extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags); extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); @@ -2197,9 +2200,7 @@ static inline int security_file_mmap(struct file *file, unsigned long reqprot, unsigned long addr, unsigned long addr_only) { - if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) - return -EACCES; - return 0; + return cap_file_mmap(file, reqprot, prot, flags, addr, addr_only); } static inline int security_file_mprotect(struct vm_area_struct *vma, diff --git a/security/capability.c b/security/capability.c index f218dd3..ec05730 100644 --- a/security/capability.c +++ b/security/capability.c @@ -330,15 +330,6 @@ static int cap_file_ioctl(struct file *file, unsigned int command, return 0; } -static int cap_file_mmap(struct file *file, unsigned long reqprot, - unsigned long prot, unsigned long flags, - unsigned long addr, unsigned long addr_only) -{ - if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) - return -EACCES; - return 0; -} - static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot) { diff --git a/security/commoncap.c b/security/commoncap.c index aa97704..3852e94 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -984,3 +984,33 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) cap_sys_admin = 1; return __vm_enough_memory(mm, pages, cap_sys_admin); } + +/* + * cap_file_mmap - check if able to map given addr + * @file: unused + * @reqprot: unused + * @prot: unused + * @flags: unused + * @addr: address attempting to be mapped + * @addr_only: unused + * + * If the process is attempting to map memory below mmap_min_addr they need + * CAP_SYS_RAWIO. The other parameters to this function are unused by the + * capability security module. Returns 0 if this mapping should be allowed + * -EPERM if not. + */ +int cap_file_mmap(struct file *file, unsigned long reqprot, + unsigned long prot, unsigned long flags, + unsigned long addr, unsigned long addr_only) +{ + int ret = 0; + + if (addr < mmap_min_addr) { + ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO, + SECURITY_CAP_AUDIT); + /* set PF_SUPERPRIV if it turns out we allow the low mmap */ + if (ret == 0) + current->flags |= PF_SUPERPRIV; + } + return ret; +} -- cgit v0.10.2 From 84336d1a77ccd2c06a730ddd38e695c2324a7386 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 31 Jul 2009 12:54:05 -0400 Subject: SELinux: call cap_file_mmap in selinux_file_mmap Currently SELinux does not check CAP_SYS_RAWIO in the file_mmap hook. This means there is no DAC check on the ability to mmap low addresses in the memory space. This function adds the DAC check for CAP_SYS_RAWIO while maintaining the selinux check on mmap_zero. This means that processes which need to mmap low memory will need CAP_SYS_RAWIO and mmap_zero but will NOT need the SELinux sys_rawio capability. Signed-off-by: Eric Paris Signed-off-by: James Morris diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e65677d..8a78f58 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3034,9 +3034,21 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot, int rc = 0; u32 sid = current_sid(); - if (addr < mmap_min_addr) + /* + * notice that we are intentionally putting the SELinux check before + * the secondary cap_file_mmap check. This is such a likely attempt + * at bad behaviour/exploit that we always want to get the AVC, even + * if DAC would have also denied the operation. + */ + if (addr < mmap_min_addr) { rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, NULL); + if (rc) + return rc; + } + + /* do DAC check on address space usage */ + rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only); if (rc || addr_only) return rc; -- cgit v0.10.2 From a2551df7ec568d87793d2eea4ca744e86318f205 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 31 Jul 2009 12:54:11 -0400 Subject: Security/SELinux: seperate lsm specific mmap_min_addr Currently SELinux enforcement of controls on the ability to map low memory is determined by the mmap_min_addr tunable. This patch causes SELinux to ignore the tunable and instead use a seperate Kconfig option specific to how much space the LSM should protect. The tunable will now only control the need for CAP_SYS_RAWIO and SELinux permissions will always protect the amount of low memory designated by CONFIG_LSM_MMAP_MIN_ADDR. This allows users who need to disable the mmap_min_addr controls (usual reason being they run WINE as a non-root user) to do so and still have SELinux controls preventing confined domains (like a web server) from being able to map some area of low memory. Signed-off-by: Eric Paris Signed-off-by: James Morris diff --git a/include/linux/mm.h b/include/linux/mm.h index ba3a7cb..9a72cc7 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -34,8 +34,6 @@ extern int sysctl_legacy_va_layout; #define sysctl_legacy_va_layout 0 #endif -extern unsigned long mmap_min_addr; - #include #include #include @@ -575,19 +573,6 @@ static inline void set_page_links(struct page *page, enum zone_type zone, } /* - * If a hint addr is less than mmap_min_addr change hint to be as - * low as possible but still greater than mmap_min_addr - */ -static inline unsigned long round_hint_to_min(unsigned long hint) -{ - hint &= PAGE_MASK; - if (((void *)hint != NULL) && - (hint < mmap_min_addr)) - return PAGE_ALIGN(mmap_min_addr); - return hint; -} - -/* * Some inline functions in vmstat.h depend on page_zone() */ #include diff --git a/include/linux/security.h b/include/linux/security.h index 963a48f..7b43115 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -28,6 +28,7 @@ #include #include #include +#include /* PAGE_ALIGN */ #include #include #include @@ -95,6 +96,7 @@ extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); extern int cap_netlink_recv(struct sk_buff *skb, int cap); extern unsigned long mmap_min_addr; +extern unsigned long dac_mmap_min_addr; /* * Values used in the task_security_ops calls */ @@ -147,6 +149,21 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) opts->num_mnt_opts = 0; } +/* + * If a hint addr is less than mmap_min_addr change hint to be as + * low as possible but still greater than mmap_min_addr + */ +static inline unsigned long round_hint_to_min(unsigned long hint) +{ + hint &= PAGE_MASK; + if (((void *)hint != NULL) && + (hint < mmap_min_addr)) + return PAGE_ALIGN(mmap_min_addr); + return hint; +} + +extern int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos); /** * struct security_operations - main security structure * diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 98e0232..58be760 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -1306,10 +1307,10 @@ static struct ctl_table vm_table[] = { { .ctl_name = CTL_UNNUMBERED, .procname = "mmap_min_addr", - .data = &mmap_min_addr, - .maxlen = sizeof(unsigned long), + .data = &dac_mmap_min_addr, + .maxlen = sizeof(unsigned long), .mode = 0644, - .proc_handler = &proc_doulongvec_minmax, + .proc_handler = &mmap_min_addr_handler, }, #ifdef CONFIG_NUMA { diff --git a/mm/Kconfig b/mm/Kconfig index c948d4c..fe5f674 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -225,9 +225,9 @@ config DEFAULT_MMAP_MIN_ADDR For most ia64, ppc64 and x86 users with lots of address space a value of 65536 is reasonable and should cause no problems. On arm and other archs it should not be higher than 32768. - Programs which use vm86 functionality would either need additional - permissions from either the LSM or the capabilities module or have - this protection disabled. + Programs which use vm86 functionality or have some need to map + this low address space will need CAP_SYS_RAWIO or disable this + protection by setting the value to 0. This value can be changed after boot using the /proc/sys/vm/mmap_min_addr tunable. diff --git a/mm/mmap.c b/mm/mmap.c index 34579b2..8101de4 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -88,9 +88,6 @@ int sysctl_overcommit_ratio = 50; /* default is 50% */ int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; struct percpu_counter vm_committed_as; -/* amount of vm to protect from userspace access */ -unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; - /* * Check that a process has enough memory to allocate a new virtual * mapping. 0 means there is enough memory for the allocation to diff --git a/mm/nommu.c b/mm/nommu.c index 53cab10..28754c4 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -69,9 +69,6 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT; int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS; int heap_stack_gap = 0; -/* amount of vm to protect from userspace access */ -unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; - atomic_long_t mmap_pages_allocated; EXPORT_SYMBOL(mem_map); diff --git a/security/Kconfig b/security/Kconfig index d23c839..9c60c34 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -113,6 +113,22 @@ config SECURITY_ROOTPLUG If you are unsure how to answer this question, answer N. +config LSM_MMAP_MIN_ADDR + int "Low address space for LSM to from user allocation" + depends on SECURITY && SECURITY_SELINUX + default 65535 + help + This is the portion of low virtual memory which should be protected + from userspace allocation. Keeping a user from writing to low pages + can help reduce the impact of kernel NULL pointer bugs. + + For most ia64, ppc64 and x86 users with lots of address space + a value of 65536 is reasonable and should cause no problems. + On arm and other archs it should not be higher than 32768. + Programs which use vm86 functionality or have some need to map + this low address space will need the permission specific to the + systems running LSM. + source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig diff --git a/security/Makefile b/security/Makefile index c67557c..b56e7f9 100644 --- a/security/Makefile +++ b/security/Makefile @@ -8,7 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK) += smack subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo # always enable default capabilities -obj-y += commoncap.o +obj-y += commoncap.o min_addr.o # Object file lists obj-$(CONFIG_SECURITY) += security.o capability.o diff --git a/security/commoncap.c b/security/commoncap.c index 3852e94..fe30751 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -1005,7 +1005,7 @@ int cap_file_mmap(struct file *file, unsigned long reqprot, { int ret = 0; - if (addr < mmap_min_addr) { + if (addr < dac_mmap_min_addr) { ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO, SECURITY_CAP_AUDIT); /* set PF_SUPERPRIV if it turns out we allow the low mmap */ diff --git a/security/min_addr.c b/security/min_addr.c new file mode 100644 index 0000000..14cc7b3 --- /dev/null +++ b/security/min_addr.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +/* amount of vm to protect from userspace access by both DAC and the LSM*/ +unsigned long mmap_min_addr; +/* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */ +unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; +/* amount of vm to protect from userspace using the LSM = CONFIG_LSM_MMAP_MIN_ADDR */ + +/* + * Update mmap_min_addr = max(dac_mmap_min_addr, CONFIG_LSM_MMAP_MIN_ADDR) + */ +static void update_mmap_min_addr(void) +{ +#ifdef CONFIG_LSM_MMAP_MIN_ADDR + if (dac_mmap_min_addr > CONFIG_LSM_MMAP_MIN_ADDR) + mmap_min_addr = dac_mmap_min_addr; + else + mmap_min_addr = CONFIG_LSM_MMAP_MIN_ADDR; +#else + mmap_min_addr = dac_mmap_min_addr; +#endif +} + +/* + * sysctl handler which just sets dac_mmap_min_addr = the new value and then + * calls update_mmap_min_addr() so non MAP_FIXED hints get rounded properly + */ +int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int ret; + + ret = proc_doulongvec_minmax(table, write, filp, buffer, lenp, ppos); + + update_mmap_min_addr(); + + return ret; +} + +int __init init_mmap_min_addr(void) +{ + update_mmap_min_addr(); + + return 0; +} +pure_initcall(init_mmap_min_addr); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 8a78f58..5dee883 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3040,7 +3040,7 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot, * at bad behaviour/exploit that we always want to get the AVC, even * if DAC would have also denied the operation. */ - if (addr < mmap_min_addr) { + if (addr < CONFIG_LSM_MMAP_MIN_ADDR) { rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, NULL); if (rc) -- cgit v0.10.2 From 9073e3a32bb249293edc01ecff575bb87380c068 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Aug 2009 20:28:27 -0700 Subject: cxgb3: fix 2 ports 1G regression commit 88045b3cf0f8981129cb489c7b6bc36c21dd33a7 cxgb3: fix mac index mapping Override the mac index computation for the gen2 adapter, as each port is expected to use index 0. introduces a regression on 2 port 1G adapter as its xauicfg vpd value is null. Add a check on the device id. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 526e144..032cfe0 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -3692,8 +3692,12 @@ static void mc7_prep(struct adapter *adapter, struct mc7 *mc7, void mac_prep(struct cmac *mac, struct adapter *adapter, int index) { + u16 devid; + mac->adapter = adapter; - if (!adapter->params.vpd.xauicfg[1]) + pci_read_config_word(adapter->pdev, 0x2, &devid); + + if (devid == 0x37 && !adapter->params.vpd.xauicfg[1]) index = 0; mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; mac->nucast = 1; -- cgit v0.10.2 From 3d7ddd540b4c2d24c6a3e7a52c083a0c31e6151c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 5 Aug 2009 20:30:13 -0700 Subject: net/rds: Use AF_INET for sin_family field Elsewhere the sin_family field holds a value with a name of the form AF_..., so it seems reasonable to do so here as well. Also the values of PF_INET and AF_INET are the same. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ struct sockaddr_in sip; @@ ( sip.sin_family == - PF_INET + AF_INET | sip.sin_family != - PF_INET + AF_INET | sip.sin_family = - PF_INET + AF_INET ) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/net/rds/rdma_transport.c b/net/rds/rdma_transport.c index 981a5e6..7a6c748 100644 --- a/net/rds/rdma_transport.c +++ b/net/rds/rdma_transport.c @@ -137,7 +137,7 @@ static int __init rds_rdma_listen_init(void) goto out; } - sin.sin_family = PF_INET, + sin.sin_family = AF_INET, sin.sin_addr.s_addr = (__force u32)htonl(INADDR_ANY); sin.sin_port = (__force u16)htons(RDS_PORT); -- cgit v0.10.2 From 0c9e6f639aed490202bbc79214f4495cf4bfde58 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 28 Jul 2009 20:26:06 +0800 Subject: tracing: Simplify print_graph_cpu() print_graph_cpu() is little over-designed. And "log10_all" may be wrong when there are holes in cpu_online_mask: the max online cpu id > cpumask_weight(cpu_online_mask) So change it by using a static column length for the cpu matching nr_cpu_ids number of decimal characters. Signed-off-by: Lai Jiangshan Cc: Steven Rostedt LKML-Reference: <4A6EEE5E.2000001@cn.fujitsu.com> Signed-off-by: Frederic Weisbecker diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index abf7c4a..e30472d 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -183,43 +183,19 @@ static void graph_trace_reset(struct trace_array *tr) unregister_ftrace_graph(); } -static inline int log10_cpu(int nb) -{ - if (nb / 100) - return 3; - if (nb / 10) - return 2; - return 1; -} +static int max_bytes_for_cpu; static enum print_line_t print_graph_cpu(struct trace_seq *s, int cpu) { - int i; int ret; - int log10_this = log10_cpu(cpu); - int log10_all = log10_cpu(cpumask_weight(cpu_online_mask)); - /* * Start with a space character - to make it stand out * to the right a bit when trace output is pasted into * email: */ - ret = trace_seq_printf(s, " "); - - /* - * Tricky - we space the CPU field according to the max - * number of online CPUs. On a 2-cpu system it would take - * a maximum of 1 digit - on a 128 cpu system it would - * take up to 3 digits: - */ - for (i = 0; i < log10_all - log10_this; i++) { - ret = trace_seq_printf(s, " "); - if (!ret) - return TRACE_TYPE_PARTIAL_LINE; - } - ret = trace_seq_printf(s, "%d) ", cpu); + ret = trace_seq_printf(s, " %*d) ", max_bytes_for_cpu, cpu); if (!ret) return TRACE_TYPE_PARTIAL_LINE; @@ -919,6 +895,8 @@ static struct tracer graph_trace __read_mostly = { static __init int init_graph_trace(void) { + max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1); + return register_tracer(&graph_trace); } -- cgit v0.10.2 From 07868b086cca784f4b532fc2ab574ec3a73b468a Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 29 Jul 2009 03:33:51 +0200 Subject: tracing/function-graph-tracer: Drop the useless nmi protection The function graph tracer used to have a protection against NMI while entering a function entry tracing. But this is useless now, this tracer is reentrant and the ring buffer supports the NMI tracing. We can then drop this protection. Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index d94e1ea..8e96634 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -417,10 +417,6 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, unsigned long return_hooker = (unsigned long) &return_to_handler; - /* Nmi's are currently unsupported */ - if (unlikely(in_nmi())) - return; - if (unlikely(atomic_read(¤t->tracing_graph_pause))) return; -- cgit v0.10.2 From 5e5bf483986ad86ad25f25eec5299c86eb2d1c57 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 29 Jul 2009 17:11:12 +0200 Subject: tracing/core: Turn ftrace_cpu_disabled into a global var In order to prepare the moving of the function graph tracer insertion helpers from trace.c to trace_functions_graph.c, we need to export the ftrace_cpu_disabled variable. Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 38a4a3e..b6211d6 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -89,7 +89,7 @@ static int dummy_set_flag(u32 old_flags, u32 bit, int set) */ static int tracing_disabled = 1; -static DEFINE_PER_CPU(local_t, ftrace_cpu_disabled); +DEFINE_PER_CPU(local_t, ftrace_cpu_disabled); static inline void ftrace_disable_cpu(void) { diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 758b0db..c7e9273 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -519,6 +519,7 @@ extern int DYN_FTRACE_TEST_NAME(void); extern int ring_buffer_expanded; extern bool tracing_selftest_disabled; +DECLARE_PER_CPU(local_t, ftrace_cpu_disabled); #ifdef CONFIG_FTRACE_STARTUP_TEST extern int trace_selftest_startup_function(struct tracer *trace, -- cgit v0.10.2 From c0a0d0d3f65284c71115a9bb1ed801ee33eeb552 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 29 Jul 2009 17:51:13 +0200 Subject: tracing/core: Make the stack entry helpers global Make the stacktrace event insertion helpers globals. This has two effects: - Prepare for moving the sched events insertion helpers to the sched switch tracer file. - Move some ifdef outside function definitions Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index b6211d6..d6059a4 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -866,10 +866,6 @@ struct ring_buffer_event *trace_buffer_lock_reserve(struct trace_array *tr, return event; } -static void ftrace_trace_stack(struct trace_array *tr, - unsigned long flags, int skip, int pc); -static void ftrace_trace_userstack(struct trace_array *tr, - unsigned long flags, int pc); static inline void __trace_buffer_unlock_commit(struct trace_array *tr, struct ring_buffer_event *event, @@ -1003,11 +999,11 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data, trace_function(tr, ip, parent_ip, flags, pc); } +#ifdef CONFIG_STACKTRACE static void __ftrace_trace_stack(struct trace_array *tr, unsigned long flags, int skip, int pc) { -#ifdef CONFIG_STACKTRACE struct ftrace_event_call *call = &event_kernel_stack; struct ring_buffer_event *event; struct stack_entry *entry; @@ -1028,12 +1024,10 @@ static void __ftrace_trace_stack(struct trace_array *tr, save_stack_trace(&trace); if (!filter_check_discard(call, entry, tr->buffer, event)) ring_buffer_unlock_commit(tr->buffer, event); -#endif } -static void ftrace_trace_stack(struct trace_array *tr, - unsigned long flags, - int skip, int pc) +void ftrace_trace_stack(struct trace_array *tr, unsigned long flags, int skip, + int pc) { if (!(trace_flags & TRACE_ITER_STACKTRACE)) return; @@ -1041,17 +1035,14 @@ static void ftrace_trace_stack(struct trace_array *tr, __ftrace_trace_stack(tr, flags, skip, pc); } -void __trace_stack(struct trace_array *tr, - unsigned long flags, - int skip, int pc) +void __trace_stack(struct trace_array *tr, unsigned long flags, int skip, + int pc) { __ftrace_trace_stack(tr, flags, skip, pc); } -static void ftrace_trace_userstack(struct trace_array *tr, - unsigned long flags, int pc) +void ftrace_trace_userstack(struct trace_array *tr, unsigned long flags, int pc) { -#ifdef CONFIG_STACKTRACE struct ftrace_event_call *call = &event_user_stack; struct ring_buffer_event *event; struct userstack_entry *entry; @@ -1076,7 +1067,6 @@ static void ftrace_trace_userstack(struct trace_array *tr, save_stack_trace_user(&trace); if (!filter_check_discard(call, entry, tr->buffer, event)) ring_buffer_unlock_commit(tr->buffer, event); -#endif } #ifdef UNUSED @@ -1086,6 +1076,8 @@ static void __trace_userstack(struct trace_array *tr, unsigned long flags) } #endif /* UNUSED */ +#endif /* CONFIG_STACKTRACE */ + static void ftrace_trace_special(void *__tr, unsigned long arg1, unsigned long arg2, unsigned long arg3, diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index c7e9273..116524d 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -489,9 +489,31 @@ void update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu); void update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu); -void __trace_stack(struct trace_array *tr, - unsigned long flags, - int skip, int pc); +#ifdef CONFIG_STACKTRACE +void ftrace_trace_stack(struct trace_array *tr, unsigned long flags, + int skip, int pc); + +void ftrace_trace_userstack(struct trace_array *tr, unsigned long flags, + int pc); + +void __trace_stack(struct trace_array *tr, unsigned long flags, int skip, + int pc); +#else +static inline void ftrace_trace_stack(struct trace_array *tr, + unsigned long flags, int skip, int pc) +{ +} + +static inline void ftrace_trace_userstack(struct trace_array *tr, + unsigned long flags, int pc) +{ +} + +static inline void __trace_stack(struct trace_array *tr, unsigned long flags, + int skip, int pc) +{ +} +#endif /* CONFIG_STACKTRACE */ extern cycle_t ftrace_now(int cpu); -- cgit v0.10.2 From 82e04af498a85ba425efe77580b7ba08234411df Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 29 Jul 2009 18:00:29 +0200 Subject: tracing: Move sched event insertion helpers in the sched switch tracer file The sched events helpers which insert the sched switch and wakeup events into the ring buffer currently reside in trace.c But this file is quite overloaded and the right place for these helpers is in the sched switch tracer file. Then move them to trace_functions.c Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index d6059a4..1b73acb 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1106,62 +1106,6 @@ __trace_special(void *__tr, void *__data, } void -tracing_sched_switch_trace(struct trace_array *tr, - struct task_struct *prev, - struct task_struct *next, - unsigned long flags, int pc) -{ - struct ftrace_event_call *call = &event_context_switch; - struct ring_buffer_event *event; - struct ctx_switch_entry *entry; - - event = trace_buffer_lock_reserve(tr, TRACE_CTX, - sizeof(*entry), flags, pc); - if (!event) - return; - entry = ring_buffer_event_data(event); - entry->prev_pid = prev->pid; - entry->prev_prio = prev->prio; - entry->prev_state = prev->state; - entry->next_pid = next->pid; - entry->next_prio = next->prio; - entry->next_state = next->state; - entry->next_cpu = task_cpu(next); - - if (!filter_check_discard(call, entry, tr->buffer, event)) - trace_buffer_unlock_commit(tr, event, flags, pc); -} - -void -tracing_sched_wakeup_trace(struct trace_array *tr, - struct task_struct *wakee, - struct task_struct *curr, - unsigned long flags, int pc) -{ - struct ftrace_event_call *call = &event_wakeup; - struct ring_buffer_event *event; - struct ctx_switch_entry *entry; - - event = trace_buffer_lock_reserve(tr, TRACE_WAKE, - sizeof(*entry), flags, pc); - if (!event) - return; - entry = ring_buffer_event_data(event); - entry->prev_pid = curr->pid; - entry->prev_prio = curr->prio; - entry->prev_state = curr->state; - entry->next_pid = wakee->pid; - entry->next_prio = wakee->prio; - entry->next_state = wakee->state; - entry->next_cpu = task_cpu(wakee); - - if (!filter_check_discard(call, entry, tr->buffer, event)) - ring_buffer_unlock_commit(tr->buffer, event); - ftrace_trace_stack(tr, flags, 6, pc); - ftrace_trace_userstack(tr, flags, pc); -} - -void ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { struct trace_array *tr = &global_trace; diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c index a98106d..e1285d7 100644 --- a/kernel/trace/trace_sched_switch.c +++ b/kernel/trace/trace_sched_switch.c @@ -20,6 +20,34 @@ static int sched_ref; static DEFINE_MUTEX(sched_register_mutex); static int sched_stopped; + +void +tracing_sched_switch_trace(struct trace_array *tr, + struct task_struct *prev, + struct task_struct *next, + unsigned long flags, int pc) +{ + struct ftrace_event_call *call = &event_context_switch; + struct ring_buffer_event *event; + struct ctx_switch_entry *entry; + + event = trace_buffer_lock_reserve(tr, TRACE_CTX, + sizeof(*entry), flags, pc); + if (!event) + return; + entry = ring_buffer_event_data(event); + entry->prev_pid = prev->pid; + entry->prev_prio = prev->prio; + entry->prev_state = prev->state; + entry->next_pid = next->pid; + entry->next_prio = next->prio; + entry->next_state = next->state; + entry->next_cpu = task_cpu(next); + + if (!filter_check_discard(call, entry, tr->buffer, event)) + trace_buffer_unlock_commit(tr, event, flags, pc); +} + static void probe_sched_switch(struct rq *__rq, struct task_struct *prev, struct task_struct *next) @@ -49,6 +77,35 @@ probe_sched_switch(struct rq *__rq, struct task_struct *prev, local_irq_restore(flags); } +void +tracing_sched_wakeup_trace(struct trace_array *tr, + struct task_struct *wakee, + struct task_struct *curr, + unsigned long flags, int pc) +{ + struct ftrace_event_call *call = &event_wakeup; + struct ring_buffer_event *event; + struct ctx_switch_entry *entry; + + event = trace_buffer_lock_reserve(tr, TRACE_WAKE, + sizeof(*entry), flags, pc); + if (!event) + return; + entry = ring_buffer_event_data(event); + entry->prev_pid = curr->pid; + entry->prev_prio = curr->prio; + entry->prev_state = curr->state; + entry->next_pid = wakee->pid; + entry->next_prio = wakee->prio; + entry->next_state = wakee->state; + entry->next_cpu = task_cpu(wakee); + + if (!filter_check_discard(call, entry, tr->buffer, event)) + ring_buffer_unlock_commit(tr->buffer, event); + ftrace_trace_stack(tr, flags, 6, pc); + ftrace_trace_userstack(tr, flags, pc); +} + static void probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee, int success) { -- cgit v0.10.2 From 1a0799a8fef5acc6503f9c5e79b2cd003317826c Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 29 Jul 2009 18:59:58 +0200 Subject: tracing/function-graph-tracer: Move graph event insertion helpers in the graph tracer file The function graph events helpers which insert the function entry and return events into the ring buffer currently reside in trace.c But this file is quite overloaded and the right place for these helpers is in the function graph tracer file. Then move them to trace_functions_graph.c Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 1b73acb..0cfd1a6 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -942,54 +942,6 @@ trace_function(struct trace_array *tr, ring_buffer_unlock_commit(tr->buffer, event); } -#ifdef CONFIG_FUNCTION_GRAPH_TRACER -static int __trace_graph_entry(struct trace_array *tr, - struct ftrace_graph_ent *trace, - unsigned long flags, - int pc) -{ - struct ftrace_event_call *call = &event_funcgraph_entry; - struct ring_buffer_event *event; - struct ftrace_graph_ent_entry *entry; - - if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled)))) - return 0; - - event = trace_buffer_lock_reserve(&global_trace, TRACE_GRAPH_ENT, - sizeof(*entry), flags, pc); - if (!event) - return 0; - entry = ring_buffer_event_data(event); - entry->graph_ent = *trace; - if (!filter_current_check_discard(call, entry, event)) - ring_buffer_unlock_commit(global_trace.buffer, event); - - return 1; -} - -static void __trace_graph_return(struct trace_array *tr, - struct ftrace_graph_ret *trace, - unsigned long flags, - int pc) -{ - struct ftrace_event_call *call = &event_funcgraph_exit; - struct ring_buffer_event *event; - struct ftrace_graph_ret_entry *entry; - - if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled)))) - return; - - event = trace_buffer_lock_reserve(&global_trace, TRACE_GRAPH_RET, - sizeof(*entry), flags, pc); - if (!event) - return; - entry = ring_buffer_event_data(event); - entry->ret = *trace; - if (!filter_current_check_discard(call, entry, event)) - ring_buffer_unlock_commit(global_trace.buffer, event); -} -#endif - void ftrace(struct trace_array *tr, struct trace_array_cpu *data, unsigned long ip, unsigned long parent_ip, unsigned long flags, @@ -1129,68 +1081,6 @@ ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) local_irq_restore(flags); } -#ifdef CONFIG_FUNCTION_GRAPH_TRACER -int trace_graph_entry(struct ftrace_graph_ent *trace) -{ - struct trace_array *tr = &global_trace; - struct trace_array_cpu *data; - unsigned long flags; - long disabled; - int ret; - int cpu; - int pc; - - if (!ftrace_trace_task(current)) - return 0; - - if (!ftrace_graph_addr(trace->func)) - return 0; - - local_irq_save(flags); - cpu = raw_smp_processor_id(); - data = tr->data[cpu]; - disabled = atomic_inc_return(&data->disabled); - if (likely(disabled == 1)) { - pc = preempt_count(); - ret = __trace_graph_entry(tr, trace, flags, pc); - } else { - ret = 0; - } - /* Only do the atomic if it is not already set */ - if (!test_tsk_trace_graph(current)) - set_tsk_trace_graph(current); - - atomic_dec(&data->disabled); - local_irq_restore(flags); - - return ret; -} - -void trace_graph_return(struct ftrace_graph_ret *trace) -{ - struct trace_array *tr = &global_trace; - struct trace_array_cpu *data; - unsigned long flags; - long disabled; - int cpu; - int pc; - - local_irq_save(flags); - cpu = raw_smp_processor_id(); - data = tr->data[cpu]; - disabled = atomic_inc_return(&data->disabled); - if (likely(disabled == 1)) { - pc = preempt_count(); - __trace_graph_return(tr, trace, flags, pc); - } - if (!trace->depth) - clear_tsk_trace_graph(current); - atomic_dec(&data->disabled); - local_irq_restore(flags); -} -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ - - /** * trace_vbprintk - write binary msg to tracing buffer * diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 116524d..9301f12 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -471,6 +471,7 @@ void trace_function(struct trace_array *tr, void trace_graph_return(struct ftrace_graph_ret *trace); int trace_graph_entry(struct ftrace_graph_ent *trace); +void set_graph_array(struct trace_array *tr); void tracing_start_cmdline_record(void); void tracing_stop_cmdline_record(void); diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index e30472d..f97244a 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -52,7 +52,7 @@ static struct tracer_flags tracer_flags = { .opts = trace_opts }; -/* pid on the last trace processed */ +static struct trace_array *graph_array; /* Add a function return address to the trace stack on thread info.*/ @@ -166,10 +166,121 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer) return ret; } +static int __trace_graph_entry(struct trace_array *tr, + struct ftrace_graph_ent *trace, + unsigned long flags, + int pc) +{ + struct ftrace_event_call *call = &event_funcgraph_entry; + struct ring_buffer_event *event; + struct ftrace_graph_ent_entry *entry; + + if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled)))) + return 0; + + event = trace_buffer_lock_reserve(tr, TRACE_GRAPH_ENT, + sizeof(*entry), flags, pc); + if (!event) + return 0; + entry = ring_buffer_event_data(event); + entry->graph_ent = *trace; + if (!filter_current_check_discard(call, entry, event)) + ring_buffer_unlock_commit(tr->buffer, event); + + return 1; +} + +int trace_graph_entry(struct ftrace_graph_ent *trace) +{ + struct trace_array *tr = graph_array; + struct trace_array_cpu *data; + unsigned long flags; + long disabled; + int ret; + int cpu; + int pc; + + if (unlikely(!tr)) + return 0; + + if (!ftrace_trace_task(current)) + return 0; + + if (!ftrace_graph_addr(trace->func)) + return 0; + + local_irq_save(flags); + cpu = raw_smp_processor_id(); + data = tr->data[cpu]; + disabled = atomic_inc_return(&data->disabled); + if (likely(disabled == 1)) { + pc = preempt_count(); + ret = __trace_graph_entry(tr, trace, flags, pc); + } else { + ret = 0; + } + /* Only do the atomic if it is not already set */ + if (!test_tsk_trace_graph(current)) + set_tsk_trace_graph(current); + + atomic_dec(&data->disabled); + local_irq_restore(flags); + + return ret; +} + +static void __trace_graph_return(struct trace_array *tr, + struct ftrace_graph_ret *trace, + unsigned long flags, + int pc) +{ + struct ftrace_event_call *call = &event_funcgraph_exit; + struct ring_buffer_event *event; + struct ftrace_graph_ret_entry *entry; + + if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled)))) + return; + + event = trace_buffer_lock_reserve(tr, TRACE_GRAPH_RET, + sizeof(*entry), flags, pc); + if (!event) + return; + entry = ring_buffer_event_data(event); + entry->ret = *trace; + if (!filter_current_check_discard(call, entry, event)) + ring_buffer_unlock_commit(tr->buffer, event); +} + +void trace_graph_return(struct ftrace_graph_ret *trace) +{ + struct trace_array *tr = graph_array; + struct trace_array_cpu *data; + unsigned long flags; + long disabled; + int cpu; + int pc; + + local_irq_save(flags); + cpu = raw_smp_processor_id(); + data = tr->data[cpu]; + disabled = atomic_inc_return(&data->disabled); + if (likely(disabled == 1)) { + pc = preempt_count(); + __trace_graph_return(tr, trace, flags, pc); + } + if (!trace->depth) + clear_tsk_trace_graph(current); + atomic_dec(&data->disabled); + local_irq_restore(flags); +} + static int graph_trace_init(struct trace_array *tr) { - int ret = register_ftrace_graph(&trace_graph_return, - &trace_graph_entry); + int ret; + + graph_array = tr; + ret = register_ftrace_graph(&trace_graph_return, + &trace_graph_entry); if (ret) return ret; tracing_start_cmdline_record(); @@ -177,6 +288,11 @@ static int graph_trace_init(struct trace_array *tr) return 0; } +void set_graph_array(struct trace_array *tr) +{ + graph_array = tr; +} + static void graph_trace_reset(struct trace_array *tr) { tracing_stop_cmdline_record(); diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 00dd648..d2cdbab 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c @@ -288,6 +288,7 @@ trace_selftest_startup_function_graph(struct tracer *trace, * to detect and recover from possible hangs */ tracing_reset_online_cpus(tr); + set_graph_array(tr); ret = register_ftrace_graph(&trace_graph_return, &trace_graph_entry_watchdog); if (ret) { -- cgit v0.10.2 From a2ca5e03b6a5a1d401062f0a7f78888cf9e5e3b0 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 6 Aug 2009 07:32:21 +0200 Subject: tracing/events: Only define remove_subsystem_dir() if CONFIG_MODULES MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we disable modules, we get the following warning in ftrace events file: kernel/trace/trace_events.c:912: attention : ‘remove_subsystem_dir’ defined but not used remove_subystem_dir() is useless if !CONFIG_MODULES, then move it to the appropriate #ifdef section of trace_events.c Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 90cf936..70ecb76 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -908,32 +908,6 @@ event_subsystem_dir(const char *name, struct dentry *d_events) return system->entry; } -static void remove_subsystem_dir(const char *name) -{ - struct event_subsystem *system; - - if (strcmp(name, TRACE_SYSTEM) == 0) - return; - - list_for_each_entry(system, &event_subsystems, list) { - if (strcmp(system->name, name) == 0) { - if (!--system->nr_events) { - struct event_filter *filter = system->filter; - - debugfs_remove_recursive(system->entry); - list_del(&system->list); - if (filter) { - kfree(filter->filter_string); - kfree(filter); - } - kfree(system->name); - kfree(system); - } - break; - } - } -} - static int event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, const struct file_operations *id, @@ -1018,6 +992,32 @@ struct ftrace_module_file_ops { struct file_operations filter; }; +static void remove_subsystem_dir(const char *name) +{ + struct event_subsystem *system; + + if (strcmp(name, TRACE_SYSTEM) == 0) + return; + + list_for_each_entry(system, &event_subsystems, list) { + if (strcmp(system->name, name) == 0) { + if (!--system->nr_events) { + struct event_filter *filter = system->filter; + + debugfs_remove_recursive(system->entry); + list_del(&system->list); + if (filter) { + kfree(filter->filter_string); + kfree(filter); + } + kfree(system->name); + kfree(system); + } + break; + } + } +} + static struct ftrace_module_file_ops * trace_create_file_ops(struct module *mod) { -- cgit v0.10.2 From 2cdc6899a88e2b9c6cb82ebd547bf58932d534df Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Thu, 6 Aug 2009 15:32:38 +1000 Subject: crypto: ghash - Add GHASH digest algorithm for GCM GHASH is implemented as a shash algorithm. The actual implementation is copied from gcm.c. This makes it possible to add architecture/hardware accelerated GHASH implementation. Signed-off-by: Huang Ying Signed-off-by: Herbert Xu diff --git a/crypto/Kconfig b/crypto/Kconfig index f2002d8..0ae170e 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -290,6 +290,13 @@ config CRYPTO_CRC32C_INTEL gain performance compared with software implementation. Module will be crc32c-intel. +config CRYPTO_GHASH + tristate "GHASH digest algorithm" + select CRYPTO_SHASH + select CRYPTO_GF128MUL + help + GHASH is message digest algorithm for GCM (Galois/Counter Mode). + config CRYPTO_MD4 tristate "MD4 digest algorithm" select CRYPTO_HASH diff --git a/crypto/Makefile b/crypto/Makefile index 3c961b4..c2ca721 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_CRYPTO_RNG2) += rng.o obj-$(CONFIG_CRYPTO_RNG2) += krng.o obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o +obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o # # generic algorithms and the async_tx api diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c new file mode 100644 index 0000000..be44256 --- /dev/null +++ b/crypto/ghash-generic.c @@ -0,0 +1,170 @@ +/* + * GHASH: digest algorithm for GCM (Galois/Counter Mode). + * + * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen + * Copyright (c) 2009 Intel Corp. + * Author: Huang Ying + * + * The algorithm implementation is copied from gcm.c. + * + * 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 published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define GHASH_BLOCK_SIZE 16 +#define GHASH_DIGEST_SIZE 16 + +struct ghash_ctx { + struct gf128mul_4k *gf128; +}; + +struct ghash_desc_ctx { + u8 buffer[GHASH_BLOCK_SIZE]; + u32 bytes; +}; + +static int ghash_init(struct shash_desc *desc) +{ + struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); + + memset(dctx, 0, sizeof(*dctx)); + + return 0; +} + +static int ghash_setkey(struct crypto_shash *tfm, + const u8 *key, unsigned int keylen) +{ + struct ghash_ctx *ctx = crypto_shash_ctx(tfm); + + if (keylen != GHASH_BLOCK_SIZE) { + crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + if (ctx->gf128) + gf128mul_free_4k(ctx->gf128); + ctx->gf128 = gf128mul_init_4k_lle((be128 *)key); + if (!ctx->gf128) + return -ENOMEM; + + return 0; +} + +static int ghash_update(struct shash_desc *desc, + const u8 *src, unsigned int srclen) +{ + struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); + struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); + u8 *dst = dctx->buffer; + + if (dctx->bytes) { + int n = min(srclen, dctx->bytes); + u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes); + + dctx->bytes -= n; + srclen -= n; + + while (n--) + *pos++ ^= *src++; + + if (!dctx->bytes) + gf128mul_4k_lle((be128 *)dst, ctx->gf128); + } + + while (srclen >= GHASH_BLOCK_SIZE) { + crypto_xor(dst, src, GHASH_BLOCK_SIZE); + gf128mul_4k_lle((be128 *)dst, ctx->gf128); + src += GHASH_BLOCK_SIZE; + srclen -= GHASH_BLOCK_SIZE; + } + + if (srclen) { + dctx->bytes = GHASH_BLOCK_SIZE - srclen; + while (srclen--) + *dst++ ^= *src++; + } + + return 0; +} + +static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx) +{ + u8 *dst = dctx->buffer; + + if (dctx->bytes) { + u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes); + + while (dctx->bytes--) + *tmp++ ^= 0; + + gf128mul_4k_lle((be128 *)dst, ctx->gf128); + } + + dctx->bytes = 0; +} + +static int ghash_final(struct shash_desc *desc, u8 *dst) +{ + struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); + struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); + u8 *buf = dctx->buffer; + + ghash_flush(ctx, dctx); + memcpy(dst, buf, GHASH_BLOCK_SIZE); + + return 0; +} + +static void ghash_exit_tfm(struct crypto_tfm *tfm) +{ + struct ghash_ctx *ctx = crypto_tfm_ctx(tfm); + if (ctx->gf128) + gf128mul_free_4k(ctx->gf128); +} + +static struct shash_alg ghash_alg = { + .digestsize = GHASH_DIGEST_SIZE, + .init = ghash_init, + .update = ghash_update, + .final = ghash_final, + .setkey = ghash_setkey, + .descsize = sizeof(struct ghash_desc_ctx), + .base = { + .cra_name = "ghash", + .cra_driver_name = "ghash-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = GHASH_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ghash_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list), + .cra_exit = ghash_exit_tfm, + }, +}; + +static int __init ghash_mod_init(void) +{ + return crypto_register_shash(&ghash_alg); +} + +static void __exit ghash_mod_exit(void) +{ + crypto_unregister_shash(&ghash_alg); +} + +module_init(ghash_mod_init); +module_exit(ghash_mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GHASH Message Digest Algorithm"); +MODULE_ALIAS("ghash"); -- cgit v0.10.2 From 9382d97af586a47dad312765e35c61aa7ad7fcdd Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Thu, 6 Aug 2009 15:34:26 +1000 Subject: crypto: gcm - Use GHASH digest algorithm Remove the dedicated GHASH implementation in GCM, and uses the GHASH digest algorithm instead. This will make GCM uses hardware accelerated GHASH implementation automatically if available. ahash instead of shash interface is used, because some hardware accelerated GHASH implementation needs asynchronous interface. Signed-off-by: Huang Ying Signed-off-by: Herbert Xu diff --git a/crypto/Kconfig b/crypto/Kconfig index 0ae170e..5105cf1 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -157,7 +157,7 @@ config CRYPTO_GCM tristate "GCM/GMAC support" select CRYPTO_CTR select CRYPTO_AEAD - select CRYPTO_GF128MUL + select CRYPTO_GHASH help Support for Galois/Counter Mode (GCM) and Galois Message Authentication Code (GMAC). Required for IPSec. diff --git a/crypto/gcm.c b/crypto/gcm.c index e70afd0..5fc3292 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c @@ -11,7 +11,10 @@ #include #include #include +#include #include +#include +#include "internal.h" #include #include #include @@ -21,11 +24,12 @@ struct gcm_instance_ctx { struct crypto_skcipher_spawn ctr; + struct crypto_ahash_spawn ghash; }; struct crypto_gcm_ctx { struct crypto_ablkcipher *ctr; - struct gf128mul_4k *gf128; + struct crypto_ahash *ghash; }; struct crypto_rfc4106_ctx { @@ -34,10 +38,9 @@ struct crypto_rfc4106_ctx { }; struct crypto_gcm_ghash_ctx { - u32 bytes; - u32 flags; - struct gf128mul_4k *gf128; - u8 buffer[16]; + unsigned int cryptlen; + struct scatterlist *src; + crypto_completion_t complete; }; struct crypto_gcm_req_priv_ctx { @@ -45,8 +48,11 @@ struct crypto_gcm_req_priv_ctx { u8 iauth_tag[16]; struct scatterlist src[2]; struct scatterlist dst[2]; - struct crypto_gcm_ghash_ctx ghash; - struct ablkcipher_request abreq; + struct crypto_gcm_ghash_ctx ghash_ctx; + union { + struct ahash_request ahreq; + struct ablkcipher_request abreq; + } u; }; struct crypto_gcm_setkey_result { @@ -54,6 +60,8 @@ struct crypto_gcm_setkey_result { struct completion completion; }; +static void *gcm_zeroes; + static inline struct crypto_gcm_req_priv_ctx *crypto_gcm_reqctx( struct aead_request *req) { @@ -62,113 +70,6 @@ static inline struct crypto_gcm_req_priv_ctx *crypto_gcm_reqctx( return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1); } -static void crypto_gcm_ghash_init(struct crypto_gcm_ghash_ctx *ctx, u32 flags, - struct gf128mul_4k *gf128) -{ - ctx->bytes = 0; - ctx->flags = flags; - ctx->gf128 = gf128; - memset(ctx->buffer, 0, 16); -} - -static void crypto_gcm_ghash_update(struct crypto_gcm_ghash_ctx *ctx, - const u8 *src, unsigned int srclen) -{ - u8 *dst = ctx->buffer; - - if (ctx->bytes) { - int n = min(srclen, ctx->bytes); - u8 *pos = dst + (16 - ctx->bytes); - - ctx->bytes -= n; - srclen -= n; - - while (n--) - *pos++ ^= *src++; - - if (!ctx->bytes) - gf128mul_4k_lle((be128 *)dst, ctx->gf128); - } - - while (srclen >= 16) { - crypto_xor(dst, src, 16); - gf128mul_4k_lle((be128 *)dst, ctx->gf128); - src += 16; - srclen -= 16; - } - - if (srclen) { - ctx->bytes = 16 - srclen; - while (srclen--) - *dst++ ^= *src++; - } -} - -static void crypto_gcm_ghash_update_sg(struct crypto_gcm_ghash_ctx *ctx, - struct scatterlist *sg, int len) -{ - struct scatter_walk walk; - u8 *src; - int n; - - if (!len) - return; - - scatterwalk_start(&walk, sg); - - while (len) { - n = scatterwalk_clamp(&walk, len); - - if (!n) { - scatterwalk_start(&walk, scatterwalk_sg_next(walk.sg)); - n = scatterwalk_clamp(&walk, len); - } - - src = scatterwalk_map(&walk, 0); - - crypto_gcm_ghash_update(ctx, src, n); - len -= n; - - scatterwalk_unmap(src, 0); - scatterwalk_advance(&walk, n); - scatterwalk_done(&walk, 0, len); - if (len) - crypto_yield(ctx->flags); - } -} - -static void crypto_gcm_ghash_flush(struct crypto_gcm_ghash_ctx *ctx) -{ - u8 *dst = ctx->buffer; - - if (ctx->bytes) { - u8 *tmp = dst + (16 - ctx->bytes); - - while (ctx->bytes--) - *tmp++ ^= 0; - - gf128mul_4k_lle((be128 *)dst, ctx->gf128); - } - - ctx->bytes = 0; -} - -static void crypto_gcm_ghash_final_xor(struct crypto_gcm_ghash_ctx *ctx, - unsigned int authlen, - unsigned int cryptlen, u8 *dst) -{ - u8 *buf = ctx->buffer; - u128 lengths; - - lengths.a = cpu_to_be64(authlen * 8); - lengths.b = cpu_to_be64(cryptlen * 8); - - crypto_gcm_ghash_flush(ctx); - crypto_xor(buf, (u8 *)&lengths, 16); - gf128mul_4k_lle((be128 *)buf, ctx->gf128); - crypto_xor(dst, buf, 16); -} - static void crypto_gcm_setkey_done(struct crypto_async_request *req, int err) { struct crypto_gcm_setkey_result *result = req->data; @@ -184,6 +85,7 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key, unsigned int keylen) { struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead); + struct crypto_ahash *ghash = ctx->ghash; struct crypto_ablkcipher *ctr = ctx->ctr; struct { be128 hash; @@ -233,13 +135,12 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key, if (err) goto out; - if (ctx->gf128 != NULL) - gf128mul_free_4k(ctx->gf128); - - ctx->gf128 = gf128mul_init_4k_lle(&data->hash); - - if (ctx->gf128 == NULL) - err = -ENOMEM; + crypto_ahash_clear_flags(ghash, CRYPTO_TFM_REQ_MASK); + crypto_ahash_set_flags(ghash, crypto_aead_get_flags(aead) & + CRYPTO_TFM_REQ_MASK); + err = crypto_ahash_setkey(ghash, (u8 *)&data->hash, sizeof(be128)); + crypto_aead_set_flags(aead, crypto_ahash_get_flags(ghash) & + CRYPTO_TFM_RES_MASK); out: kfree(data); @@ -272,8 +173,6 @@ static void crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req, struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead); struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); - u32 flags = req->base.tfm->crt_flags; - struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; struct scatterlist *dst; __be32 counter = cpu_to_be32(1); @@ -296,108 +195,398 @@ static void crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req, ablkcipher_request_set_crypt(ablk_req, pctx->src, dst, cryptlen + sizeof(pctx->auth_tag), req->iv); +} + +static inline unsigned int gcm_remain(unsigned int len) +{ + len &= 0xfU; + return len ? 16 - len : 0; +} + +static void gcm_hash_len_done(struct crypto_async_request *areq, int err); +static void gcm_hash_final_done(struct crypto_async_request *areq, int err); - crypto_gcm_ghash_init(ghash, flags, ctx->gf128); +static int gcm_hash_update(struct aead_request *req, + struct crypto_gcm_req_priv_ctx *pctx, + crypto_completion_t complete, + struct scatterlist *src, + unsigned int len) +{ + struct ahash_request *ahreq = &pctx->u.ahreq; - crypto_gcm_ghash_update_sg(ghash, req->assoc, req->assoclen); - crypto_gcm_ghash_flush(ghash); + ahash_request_set_callback(ahreq, aead_request_flags(req), + complete, req); + ahash_request_set_crypt(ahreq, src, NULL, len); + + return crypto_ahash_update(ahreq); } -static int crypto_gcm_hash(struct aead_request *req) +static int gcm_hash_remain(struct aead_request *req, + struct crypto_gcm_req_priv_ctx *pctx, + unsigned int remain, + crypto_completion_t complete) { - struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct ahash_request *ahreq = &pctx->u.ahreq; + + ahash_request_set_callback(ahreq, aead_request_flags(req), + complete, req); + sg_init_one(pctx->src, gcm_zeroes, remain); + ahash_request_set_crypt(ahreq, pctx->src, NULL, remain); + + return crypto_ahash_update(ahreq); +} + +static int gcm_hash_len(struct aead_request *req, + struct crypto_gcm_req_priv_ctx *pctx) +{ + struct ahash_request *ahreq = &pctx->u.ahreq; + struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; + u128 lengths; + + lengths.a = cpu_to_be64(req->assoclen * 8); + lengths.b = cpu_to_be64(gctx->cryptlen * 8); + memcpy(pctx->iauth_tag, &lengths, 16); + sg_init_one(pctx->src, pctx->iauth_tag, 16); + ahash_request_set_callback(ahreq, aead_request_flags(req), + gcm_hash_len_done, req); + ahash_request_set_crypt(ahreq, pctx->src, + NULL, sizeof(lengths)); + + return crypto_ahash_update(ahreq); +} + +static int gcm_hash_final(struct aead_request *req, + struct crypto_gcm_req_priv_ctx *pctx) +{ + struct ahash_request *ahreq = &pctx->u.ahreq; + + ahash_request_set_callback(ahreq, aead_request_flags(req), + gcm_hash_final_done, req); + ahash_request_set_crypt(ahreq, NULL, pctx->iauth_tag, 0); + + return crypto_ahash_final(ahreq); +} + +static void gcm_hash_final_done(struct crypto_async_request *areq, + int err) +{ + struct aead_request *req = areq->data; struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); - u8 *auth_tag = pctx->auth_tag; - struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; + struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; + + if (!err) + crypto_xor(pctx->auth_tag, pctx->iauth_tag, 16); - crypto_gcm_ghash_update_sg(ghash, req->dst, req->cryptlen); - crypto_gcm_ghash_final_xor(ghash, req->assoclen, req->cryptlen, - auth_tag); + gctx->complete(areq, err); +} + +static void gcm_hash_len_done(struct crypto_async_request *areq, + int err) +{ + struct aead_request *req = areq->data; + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + + if (!err) { + err = gcm_hash_final(req, pctx); + if (err == -EINPROGRESS || err == -EBUSY) + return; + } + + gcm_hash_final_done(areq, err); +} + +static void gcm_hash_crypt_remain_done(struct crypto_async_request *areq, + int err) +{ + struct aead_request *req = areq->data; + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + + if (!err) { + err = gcm_hash_len(req, pctx); + if (err == -EINPROGRESS || err == -EBUSY) + return; + } + + gcm_hash_len_done(areq, err); +} + +static void gcm_hash_crypt_done(struct crypto_async_request *areq, + int err) +{ + struct aead_request *req = areq->data; + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; + unsigned int remain; + + if (!err) { + remain = gcm_remain(gctx->cryptlen); + BUG_ON(!remain); + err = gcm_hash_remain(req, pctx, remain, + gcm_hash_crypt_remain_done); + if (err == -EINPROGRESS || err == -EBUSY) + return; + } + + gcm_hash_crypt_remain_done(areq, err); +} + +static void gcm_hash_assoc_remain_done(struct crypto_async_request *areq, + int err) +{ + struct aead_request *req = areq->data; + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; + crypto_completion_t complete; + unsigned int remain = 0; + + if (!err && gctx->cryptlen) { + remain = gcm_remain(gctx->cryptlen); + complete = remain ? gcm_hash_crypt_done : + gcm_hash_crypt_remain_done; + err = gcm_hash_update(req, pctx, complete, + gctx->src, gctx->cryptlen); + if (err == -EINPROGRESS || err == -EBUSY) + return; + } + + if (remain) + gcm_hash_crypt_done(areq, err); + else + gcm_hash_crypt_remain_done(areq, err); +} + +static void gcm_hash_assoc_done(struct crypto_async_request *areq, + int err) +{ + struct aead_request *req = areq->data; + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + unsigned int remain; + + if (!err) { + remain = gcm_remain(req->assoclen); + BUG_ON(!remain); + err = gcm_hash_remain(req, pctx, remain, + gcm_hash_assoc_remain_done); + if (err == -EINPROGRESS || err == -EBUSY) + return; + } + + gcm_hash_assoc_remain_done(areq, err); +} + +static void gcm_hash_init_done(struct crypto_async_request *areq, + int err) +{ + struct aead_request *req = areq->data; + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + crypto_completion_t complete; + unsigned int remain = 0; + + if (!err && req->assoclen) { + remain = gcm_remain(req->assoclen); + complete = remain ? gcm_hash_assoc_done : + gcm_hash_assoc_remain_done; + err = gcm_hash_update(req, pctx, complete, + req->assoc, req->assoclen); + if (err == -EINPROGRESS || err == -EBUSY) + return; + } + + if (remain) + gcm_hash_assoc_done(areq, err); + else + gcm_hash_assoc_remain_done(areq, err); +} + +static int gcm_hash(struct aead_request *req, + struct crypto_gcm_req_priv_ctx *pctx) +{ + struct ahash_request *ahreq = &pctx->u.ahreq; + struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; + struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + unsigned int remain; + crypto_completion_t complete; + int err; + + ahash_request_set_tfm(ahreq, ctx->ghash); + + ahash_request_set_callback(ahreq, aead_request_flags(req), + gcm_hash_init_done, req); + err = crypto_ahash_init(ahreq); + if (err) + return err; + remain = gcm_remain(req->assoclen); + complete = remain ? gcm_hash_assoc_done : gcm_hash_assoc_remain_done; + err = gcm_hash_update(req, pctx, complete, req->assoc, req->assoclen); + if (err) + return err; + if (remain) { + err = gcm_hash_remain(req, pctx, remain, + gcm_hash_assoc_remain_done); + if (err) + return err; + } + remain = gcm_remain(gctx->cryptlen); + complete = remain ? gcm_hash_crypt_done : gcm_hash_crypt_remain_done; + err = gcm_hash_update(req, pctx, complete, gctx->src, gctx->cryptlen); + if (err) + return err; + if (remain) { + err = gcm_hash_remain(req, pctx, remain, + gcm_hash_crypt_remain_done); + if (err) + return err; + } + err = gcm_hash_len(req, pctx); + if (err) + return err; + err = gcm_hash_final(req, pctx); + if (err) + return err; + + return 0; +} + +static void gcm_enc_copy_hash(struct aead_request *req, + struct crypto_gcm_req_priv_ctx *pctx) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + u8 *auth_tag = pctx->auth_tag; scatterwalk_map_and_copy(auth_tag, req->dst, req->cryptlen, crypto_aead_authsize(aead), 1); - return 0; } -static void crypto_gcm_encrypt_done(struct crypto_async_request *areq, int err) +static void gcm_enc_hash_done(struct crypto_async_request *areq, + int err) { struct aead_request *req = areq->data; + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); if (!err) - err = crypto_gcm_hash(req); + gcm_enc_copy_hash(req, pctx); aead_request_complete(req, err); } +static void gcm_encrypt_done(struct crypto_async_request *areq, + int err) +{ + struct aead_request *req = areq->data; + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + + if (!err) { + err = gcm_hash(req, pctx); + if (err == -EINPROGRESS || err == -EBUSY) + return; + } + + gcm_enc_hash_done(areq, err); +} + static int crypto_gcm_encrypt(struct aead_request *req) { struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); - struct ablkcipher_request *abreq = &pctx->abreq; + struct ablkcipher_request *abreq = &pctx->u.abreq; + struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; int err; crypto_gcm_init_crypt(abreq, req, req->cryptlen); ablkcipher_request_set_callback(abreq, aead_request_flags(req), - crypto_gcm_encrypt_done, req); + gcm_encrypt_done, req); + + gctx->src = req->dst; + gctx->cryptlen = req->cryptlen; + gctx->complete = gcm_enc_hash_done; err = crypto_ablkcipher_encrypt(abreq); if (err) return err; - return crypto_gcm_hash(req); + err = gcm_hash(req, pctx); + if (err) + return err; + + crypto_xor(pctx->auth_tag, pctx->iauth_tag, 16); + gcm_enc_copy_hash(req, pctx); + + return 0; } -static int crypto_gcm_verify(struct aead_request *req) +static int crypto_gcm_verify(struct aead_request *req, + struct crypto_gcm_req_priv_ctx *pctx) { struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); - struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; u8 *auth_tag = pctx->auth_tag; u8 *iauth_tag = pctx->iauth_tag; unsigned int authsize = crypto_aead_authsize(aead); unsigned int cryptlen = req->cryptlen - authsize; - crypto_gcm_ghash_final_xor(ghash, req->assoclen, cryptlen, auth_tag); - - authsize = crypto_aead_authsize(aead); + crypto_xor(auth_tag, iauth_tag, 16); scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0); return memcmp(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0; } -static void crypto_gcm_decrypt_done(struct crypto_async_request *areq, int err) +static void gcm_decrypt_done(struct crypto_async_request *areq, int err) { struct aead_request *req = areq->data; + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); if (!err) - err = crypto_gcm_verify(req); + err = crypto_gcm_verify(req, pctx); aead_request_complete(req, err); } +static void gcm_dec_hash_done(struct crypto_async_request *areq, int err) +{ + struct aead_request *req = areq->data; + struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); + struct ablkcipher_request *abreq = &pctx->u.abreq; + struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; + + if (!err) { + ablkcipher_request_set_callback(abreq, aead_request_flags(req), + gcm_decrypt_done, req); + crypto_gcm_init_crypt(abreq, req, gctx->cryptlen); + err = crypto_ablkcipher_decrypt(abreq); + if (err == -EINPROGRESS || err == -EBUSY) + return; + } + + gcm_decrypt_done(areq, err); +} + static int crypto_gcm_decrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); - struct ablkcipher_request *abreq = &pctx->abreq; - struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; - unsigned int cryptlen = req->cryptlen; + struct ablkcipher_request *abreq = &pctx->u.abreq; + struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; unsigned int authsize = crypto_aead_authsize(aead); + unsigned int cryptlen = req->cryptlen; int err; if (cryptlen < authsize) return -EINVAL; cryptlen -= authsize; - crypto_gcm_init_crypt(abreq, req, cryptlen); - ablkcipher_request_set_callback(abreq, aead_request_flags(req), - crypto_gcm_decrypt_done, req); + gctx->src = req->src; + gctx->cryptlen = cryptlen; + gctx->complete = gcm_dec_hash_done; - crypto_gcm_ghash_update_sg(ghash, req->src, cryptlen); + err = gcm_hash(req, pctx); + if (err) + return err; + ablkcipher_request_set_callback(abreq, aead_request_flags(req), + gcm_decrypt_done, req); + crypto_gcm_init_crypt(abreq, req, cryptlen); err = crypto_ablkcipher_decrypt(abreq); if (err) return err; - return crypto_gcm_verify(req); + return crypto_gcm_verify(req, pctx); } static int crypto_gcm_init_tfm(struct crypto_tfm *tfm) @@ -406,43 +595,56 @@ static int crypto_gcm_init_tfm(struct crypto_tfm *tfm) struct gcm_instance_ctx *ictx = crypto_instance_ctx(inst); struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm); struct crypto_ablkcipher *ctr; + struct crypto_ahash *ghash; unsigned long align; int err; + ghash = crypto_spawn_ahash(&ictx->ghash); + if (IS_ERR(ghash)) + return PTR_ERR(ghash); + ctr = crypto_spawn_skcipher(&ictx->ctr); err = PTR_ERR(ctr); if (IS_ERR(ctr)) - return err; + goto err_free_hash; ctx->ctr = ctr; - ctx->gf128 = NULL; + ctx->ghash = ghash; align = crypto_tfm_alg_alignmask(tfm); align &= ~(crypto_tfm_ctx_alignment() - 1); tfm->crt_aead.reqsize = align + - sizeof(struct crypto_gcm_req_priv_ctx) + - crypto_ablkcipher_reqsize(ctr); + offsetof(struct crypto_gcm_req_priv_ctx, u) + + max(sizeof(struct ablkcipher_request) + + crypto_ablkcipher_reqsize(ctr), + sizeof(struct ahash_request) + + crypto_ahash_reqsize(ghash)); return 0; + +err_free_hash: + crypto_free_ahash(ghash); + return err; } static void crypto_gcm_exit_tfm(struct crypto_tfm *tfm) { struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm); - if (ctx->gf128 != NULL) - gf128mul_free_4k(ctx->gf128); - + crypto_free_ahash(ctx->ghash); crypto_free_ablkcipher(ctx->ctr); } static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb, const char *full_name, - const char *ctr_name) + const char *ctr_name, + const char *ghash_name) { struct crypto_attr_type *algt; struct crypto_instance *inst; struct crypto_alg *ctr; + struct crypto_alg *ghash_alg; + struct ahash_alg *ghash_ahash_alg; struct gcm_instance_ctx *ctx; int err; @@ -454,17 +656,31 @@ static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb, if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) return ERR_PTR(-EINVAL); + ghash_alg = crypto_find_alg(ghash_name, &crypto_ahash_type, + CRYPTO_ALG_TYPE_HASH, + CRYPTO_ALG_TYPE_AHASH_MASK); + err = PTR_ERR(ghash_alg); + if (IS_ERR(ghash_alg)) + return ERR_PTR(err); + + err = -ENOMEM; inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); if (!inst) - return ERR_PTR(-ENOMEM); + goto out_put_ghash; ctx = crypto_instance_ctx(inst); + ghash_ahash_alg = container_of(ghash_alg, struct ahash_alg, halg.base); + err = crypto_init_ahash_spawn(&ctx->ghash, &ghash_ahash_alg->halg, + inst); + if (err) + goto err_free_inst; + crypto_set_skcipher_spawn(&ctx->ctr, inst); err = crypto_grab_skcipher(&ctx->ctr, ctr_name, 0, crypto_requires_sync(algt->type, algt->mask)); if (err) - goto err_free_inst; + goto err_drop_ghash; ctr = crypto_skcipher_spawn_alg(&ctx->ctr); @@ -479,7 +695,8 @@ static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb, err = -ENAMETOOLONG; if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, - "gcm_base(%s)", ctr->cra_driver_name) >= + "gcm_base(%s,%s)", ctr->cra_driver_name, + ghash_alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) goto out_put_ctr; @@ -502,12 +719,16 @@ static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb, inst->alg.cra_aead.decrypt = crypto_gcm_decrypt; out: + crypto_mod_put(ghash_alg); return inst; out_put_ctr: crypto_drop_skcipher(&ctx->ctr); +err_drop_ghash: + crypto_drop_ahash(&ctx->ghash); err_free_inst: kfree(inst); +out_put_ghash: inst = ERR_PTR(err); goto out; } @@ -532,7 +753,7 @@ static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb) CRYPTO_MAX_ALG_NAME) return ERR_PTR(-ENAMETOOLONG); - return crypto_gcm_alloc_common(tb, full_name, ctr_name); + return crypto_gcm_alloc_common(tb, full_name, ctr_name, "ghash"); } static void crypto_gcm_free(struct crypto_instance *inst) @@ -540,6 +761,7 @@ static void crypto_gcm_free(struct crypto_instance *inst) struct gcm_instance_ctx *ctx = crypto_instance_ctx(inst); crypto_drop_skcipher(&ctx->ctr); + crypto_drop_ahash(&ctx->ghash); kfree(inst); } @@ -554,6 +776,7 @@ static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb) { int err; const char *ctr_name; + const char *ghash_name; char full_name[CRYPTO_MAX_ALG_NAME]; ctr_name = crypto_attr_alg_name(tb[1]); @@ -561,11 +784,16 @@ static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb) if (IS_ERR(ctr_name)) return ERR_PTR(err); - if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s)", - ctr_name) >= CRYPTO_MAX_ALG_NAME) + ghash_name = crypto_attr_alg_name(tb[2]); + err = PTR_ERR(ghash_name); + if (IS_ERR(ghash_name)) + return ERR_PTR(err); + + if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s,%s)", + ctr_name, ghash_name) >= CRYPTO_MAX_ALG_NAME) return ERR_PTR(-ENAMETOOLONG); - return crypto_gcm_alloc_common(tb, full_name, ctr_name); + return crypto_gcm_alloc_common(tb, full_name, ctr_name, ghash_name); } static struct crypto_template crypto_gcm_base_tmpl = { @@ -784,6 +1012,10 @@ static int __init crypto_gcm_module_init(void) { int err; + gcm_zeroes = kzalloc(16, GFP_KERNEL); + if (!gcm_zeroes) + return -ENOMEM; + err = crypto_register_template(&crypto_gcm_base_tmpl); if (err) goto out; @@ -796,18 +1028,20 @@ static int __init crypto_gcm_module_init(void) if (err) goto out_undo_gcm; -out: - return err; + return 0; out_undo_gcm: crypto_unregister_template(&crypto_gcm_tmpl); out_undo_base: crypto_unregister_template(&crypto_gcm_base_tmpl); - goto out; +out: + kfree(gcm_zeroes); + return err; } static void __exit crypto_gcm_module_exit(void) { + kfree(gcm_zeroes); crypto_unregister_template(&crypto_rfc4106_tmpl); crypto_unregister_template(&crypto_gcm_tmpl); crypto_unregister_template(&crypto_gcm_base_tmpl); -- cgit v0.10.2 From ace1366369841c9c3a9788f79baa4d73f1c53107 Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Thu, 6 Aug 2009 15:35:20 +1000 Subject: crypto: cryptd - Add support to access underlaying shash cryptd_alloc_ahash() will allocate a cryptd-ed ahash for specified algorithm name. The new allocated one is guaranteed to be cryptd-ed ahash, so the shash underlying can be gotten via cryptd_ahash_child(). Signed-off-by: Huang Ying Signed-off-by: Herbert Xu diff --git a/crypto/cryptd.c b/crypto/cryptd.c index 2eb7058..3533582 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -682,6 +682,41 @@ void cryptd_free_ablkcipher(struct cryptd_ablkcipher *tfm) } EXPORT_SYMBOL_GPL(cryptd_free_ablkcipher); +struct cryptd_ahash *cryptd_alloc_ahash(const char *alg_name, + u32 type, u32 mask) +{ + char cryptd_alg_name[CRYPTO_MAX_ALG_NAME]; + struct crypto_ahash *tfm; + + if (snprintf(cryptd_alg_name, CRYPTO_MAX_ALG_NAME, + "cryptd(%s)", alg_name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-EINVAL); + tfm = crypto_alloc_ahash(cryptd_alg_name, type, mask); + if (IS_ERR(tfm)) + return ERR_CAST(tfm); + if (tfm->base.__crt_alg->cra_module != THIS_MODULE) { + crypto_free_ahash(tfm); + return ERR_PTR(-EINVAL); + } + + return __cryptd_ahash_cast(tfm); +} +EXPORT_SYMBOL_GPL(cryptd_alloc_ahash); + +struct crypto_shash *cryptd_ahash_child(struct cryptd_ahash *tfm) +{ + struct cryptd_hash_ctx *ctx = crypto_ahash_ctx(&tfm->base); + + return ctx->child; +} +EXPORT_SYMBOL_GPL(cryptd_ahash_child); + +void cryptd_free_ahash(struct cryptd_ahash *tfm) +{ + crypto_free_ahash(&tfm->base); +} +EXPORT_SYMBOL_GPL(cryptd_free_ahash); + static int __init cryptd_init(void) { int err; diff --git a/include/crypto/cryptd.h b/include/crypto/cryptd.h index 55fa7bb..2f65a6e 100644 --- a/include/crypto/cryptd.h +++ b/include/crypto/cryptd.h @@ -7,6 +7,7 @@ #include #include +#include struct cryptd_ablkcipher { struct crypto_ablkcipher base; @@ -24,4 +25,20 @@ struct cryptd_ablkcipher *cryptd_alloc_ablkcipher(const char *alg_name, struct crypto_blkcipher *cryptd_ablkcipher_child(struct cryptd_ablkcipher *tfm); void cryptd_free_ablkcipher(struct cryptd_ablkcipher *tfm); +struct cryptd_ahash { + struct crypto_ahash base; +}; + +static inline struct cryptd_ahash *__cryptd_ahash_cast( + struct crypto_ahash *tfm) +{ + return (struct cryptd_ahash *)tfm; +} + +/* alg_name should be algorithm to be cryptd-ed */ +struct cryptd_ahash *cryptd_alloc_ahash(const char *alg_name, + u32 type, u32 mask); +struct crypto_shash *cryptd_ahash_child(struct cryptd_ahash *tfm); +void cryptd_free_ahash(struct cryptd_ahash *tfm); + #endif -- cgit v0.10.2 From 1972d02504b142a6f1442bd987a8831146031d3d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Aug 2009 08:44:43 +0200 Subject: ALSA: hda - Add quirks for some HP laptops The new HP laptops have PCI SSID 103c:701x and requires model=hp-dv5. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index edeeb56..163aad5 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1906,6 +1906,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "HP mini 1000", STAC_HP_M4), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361b, "HP HDX", STAC_HP_HDX), /* HDX16 */ + SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010, + "HP", STAC_HP_DV5), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, "unknown Dell", STAC_DELL_M4_1), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234, -- cgit v0.10.2 From 924914ee953f2ccf3a2d49bda08c9ce1046a0c58 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 4 Aug 2009 23:50:16 +0100 Subject: ASoC: Add WM8776 CODEC driver The WM8776 is a high performance, stereo audio CODEC with five channel input selector. The WM8776 is ideal for surround sound processing applications for home hi-fi, DVD-RW and other audio visual equipment. This driver implements support for most WM8776 features - currently the ADC automatic level control/limiter functionality is omitted. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index fdfc502..31a6d21 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -38,6 +38,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8900 if I2C select SND_SOC_WM8903 if I2C select SND_SOC_WM8940 if I2C @@ -158,6 +159,9 @@ config SND_SOC_WM8750 config SND_SOC_WM8753 tristate +config SND_SOC_WM8776 + tristate + config SND_SOC_WM8900 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1131d6d..78dce5d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -26,6 +26,7 @@ snd-soc-wm8728-objs := wm8728.o snd-soc-wm8731-objs := wm8731.o snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o +snd-soc-wm8776-objs := wm8776.o snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o snd-soc-wm8940-objs := wm8940.o @@ -71,6 +72,7 @@ obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o +obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c new file mode 100644 index 0000000..ee12bf8 --- /dev/null +++ b/sound/soc/codecs/wm8776.c @@ -0,0 +1,781 @@ +/* + * wm8776.c -- WM8776 ALSA SoC Audio driver + * + * Copyright 2009 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * 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 + * published by the Free Software Foundation. + * + * TODO: Input ALC/limiter support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8776.h" + +static struct snd_soc_codec *wm8776_codec; +struct snd_soc_codec_device soc_codec_dev_wm8776; + +/* codec private data */ +struct wm8776_priv { + struct snd_soc_codec codec; + u16 reg_cache[WM8776_CACHEREGNUM]; + int sysclk[2]; +}; + +#ifdef CONFIG_SPI_MASTER +static int wm8776_spi_write(struct spi_device *spi, const char *data, int len); +#endif + +static const u16 wm8776_reg[WM8776_CACHEREGNUM] = { + 0x79, 0x79, 0x79, 0xff, 0xff, /* 4 */ + 0xff, 0x00, 0x90, 0x00, 0x00, /* 9 */ + 0x22, 0x22, 0x22, 0x08, 0xcf, /* 14 */ + 0xcf, 0x7b, 0x00, 0x32, 0x00, /* 19 */ + 0xa6, 0x01, 0x01 +}; + +/* + * read wm8776 register cache + */ +static inline unsigned int wm8776_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8776_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8776 register cache + */ +static inline void wm8776_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8776_CACHEREGNUM) + return; + cache[reg] = value; +} + +/* + * write to the WM8776 register space + */ +static int wm8776_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8776_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +static int wm8776_reset(struct snd_soc_codec *codec) +{ + return wm8776_write(codec, WM8776_RESET, 0); +} + +static const DECLARE_TLV_DB_SCALE(hp_tlv, -12100, 100, 1); +static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(adc_tlv, -10350, 50, 1); + +static const struct snd_kcontrol_new wm8776_snd_controls[] = { +SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8776_HPLVOL, WM8776_HPRVOL, + 0, 127, 0, hp_tlv), +SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8776_DACLVOL, WM8776_DACRVOL, + 0, 255, 0, dac_tlv), +SOC_SINGLE("Digital Playback ZC Switch", WM8776_DACCTRL1, 0, 1, 0), + +SOC_SINGLE("Deemphasis Switch", WM8776_DACCTRL2, 0, 1, 0), + +SOC_DOUBLE_R_TLV("Capture Volume", WM8776_ADCLVOL, WM8776_ADCRVOL, + 0, 255, 0, adc_tlv), +SOC_DOUBLE("Capture Switch", WM8776_ADCMUX, 7, 6, 1, 1), +SOC_DOUBLE_R("Capture ZC Switch", WM8776_ADCLVOL, WM8776_ADCRVOL, 8, 1, 0), +SOC_SINGLE("Capture HPF Switch", WM8776_ADCIFCTRL, 8, 1, 1), +}; + +static const struct snd_kcontrol_new inmix_controls[] = { +SOC_DAPM_SINGLE("AIN1 Switch", WM8776_ADCMUX, 0, 1, 0), +SOC_DAPM_SINGLE("AIN2 Switch", WM8776_ADCMUX, 1, 1, 0), +SOC_DAPM_SINGLE("AIN3 Switch", WM8776_ADCMUX, 2, 1, 0), +SOC_DAPM_SINGLE("AIN4 Switch", WM8776_ADCMUX, 3, 1, 0), +SOC_DAPM_SINGLE("AIN5 Switch", WM8776_ADCMUX, 4, 1, 0), +}; + +static const struct snd_kcontrol_new outmix_controls[] = { +SOC_DAPM_SINGLE("DAC Switch", WM8776_OUTMUX, 0, 1, 0), +SOC_DAPM_SINGLE("AUX Switch", WM8776_OUTMUX, 1, 1, 0), +SOC_DAPM_SINGLE("Bypass Switch", WM8776_OUTMUX, 2, 1, 0), +}; + +static const struct snd_soc_dapm_widget wm8776_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("AUX"), +SND_SOC_DAPM_INPUT("AUX"), + +SND_SOC_DAPM_INPUT("AIN1"), +SND_SOC_DAPM_INPUT("AIN2"), +SND_SOC_DAPM_INPUT("AIN3"), +SND_SOC_DAPM_INPUT("AIN4"), +SND_SOC_DAPM_INPUT("AIN5"), + +SND_SOC_DAPM_MIXER("Input Mixer", WM8776_PWRDOWN, 6, 1, + inmix_controls, ARRAY_SIZE(inmix_controls)), + +SND_SOC_DAPM_ADC("ADC", "Capture", WM8776_PWRDOWN, 1, 1), +SND_SOC_DAPM_DAC("DAC", "Playback", WM8776_PWRDOWN, 2, 1), + +SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, + outmix_controls, ARRAY_SIZE(outmix_controls)), + +SND_SOC_DAPM_PGA("Headphone PGA", WM8776_PWRDOWN, 3, 1, NULL, 0), + +SND_SOC_DAPM_OUTPUT("VOUT"), + +SND_SOC_DAPM_OUTPUT("HPOUTL"), +SND_SOC_DAPM_OUTPUT("HPOUTR"), +}; + +static const struct snd_soc_dapm_route routes[] = { + { "Input Mixer", "AIN1 Switch", "AIN1" }, + { "Input Mixer", "AIN2 Switch", "AIN2" }, + { "Input Mixer", "AIN3 Switch", "AIN3" }, + { "Input Mixer", "AIN4 Switch", "AIN4" }, + { "Input Mixer", "AIN5 Switch", "AIN5" }, + + { "ADC", NULL, "Input Mixer" }, + + { "Output Mixer", "DAC Switch", "DAC" }, + { "Output Mixer", "AUX Switch", "AUX" }, + { "Output Mixer", "Bypass Switch", "Input Mixer" }, + + { "VOUT", NULL, "Output Mixer" }, + + { "Headphone PGA", NULL, "Output Mixer" }, + + { "HPOUTL", NULL, "Headphone PGA" }, + { "HPOUTR", NULL, "Headphone PGA" }, +}; + +static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + int reg, iface, master; + + switch (dai->id) { + case WM8776_DAI_DAC: + reg = WM8776_DACIFCTRL; + master = 0x80; + break; + case WM8776_DAI_ADC: + reg = WM8776_ADCIFCTRL; + master = 0x100; + break; + default: + return -EINVAL; + } + + iface = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + break; + case SND_SOC_DAIFMT_CBS_CFS: + master = 0; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0001; + break; + /* FIXME: CHECK A/B */ + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0003; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x0007; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x00c; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x008; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x004; + break; + default: + return -EINVAL; + } + + /* Finally, write out the values */ + snd_soc_update_bits(codec, reg, 0xf, iface); + snd_soc_update_bits(codec, WM8776_MSTRCTRL, 0x180, master); + + return 0; +} + +static int mclk_ratios[] = { + 128, + 192, + 256, + 384, + 512, + 768, +}; + +static int wm8776_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8776_priv *wm8776 = codec->private_data; + int iface_reg, iface; + int ratio_shift, master; + int i; + + iface = 0; + + switch (dai->id) { + case WM8776_DAI_DAC: + iface_reg = WM8776_DACIFCTRL; + master = 0x80; + ratio_shift = 4; + break; + case WM8776_DAI_ADC: + iface_reg = WM8776_ADCIFCTRL; + master = 0x100; + ratio_shift = 0; + break; + default: + return -EINVAL; + } + + + /* Set word length */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x10; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x20; + break; + case SNDRV_PCM_FORMAT_S32_LE: + iface |= 0x30; + break; + } + + /* Only need to set MCLK/LRCLK ratio if we're master */ + if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) { + for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) { + if (wm8776->sysclk[dai->id] / params_rate(params) + == mclk_ratios[i]) + break; + } + + if (i == ARRAY_SIZE(mclk_ratios)) { + dev_err(codec->dev, + "Unable to configure MCLK ratio %d/%d\n", + wm8776->sysclk[dai->id], params_rate(params)); + return -EINVAL; + } + + dev_dbg(codec->dev, "MCLK is %dfs\n", mclk_ratios[i]); + + snd_soc_update_bits(codec, WM8776_MSTRCTRL, + 0x7 << ratio_shift, i << ratio_shift); + } else { + dev_dbg(codec->dev, "DAI in slave mode\n"); + } + + snd_soc_update_bits(codec, iface_reg, 0x30, iface); + + return 0; +} + +static int wm8776_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + + return snd_soc_write(codec, WM8776_DACMUTE, !!mute); +} + +static int wm8776_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8776_priv *wm8776 = codec->private_data; + + BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk)); + + wm8776->sysclk[dai->id] = freq; + + return 0; +} + +static int wm8776_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* Disable the global powerdown; DAPM does the rest */ + snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 0); + } + + break; + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 1); + break; + } + + codec->bias_level = level; + return 0; +} + +#define WM8776_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000) + + +#define WM8776_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops wm8776_dac_ops = { + .digital_mute = wm8776_mute, + .hw_params = wm8776_hw_params, + .set_fmt = wm8776_set_fmt, + .set_sysclk = wm8776_set_sysclk, +}; + +static struct snd_soc_dai_ops wm8776_adc_ops = { + .hw_params = wm8776_hw_params, + .set_fmt = wm8776_set_fmt, + .set_sysclk = wm8776_set_sysclk, +}; + +struct snd_soc_dai wm8776_dai[] = { + { + .name = "WM8776 Playback", + .id = WM8776_DAI_DAC, + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = WM8776_RATES, + .formats = WM8776_FORMATS, + }, + .ops = &wm8776_dac_ops, + }, + { + .name = "WM8776 Capture", + .id = WM8776_DAI_ADC, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = WM8776_RATES, + .formats = WM8776_FORMATS, + }, + .ops = &wm8776_adc_ops, + }, +}; +EXPORT_SYMBOL_GPL(wm8776_dai); + +#ifdef CONFIG_PM +static int wm8776_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int wm8776_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int i; + u8 data[2]; + u16 *cache = codec->reg_cache; + + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) { + data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); + data[1] = cache[i] & 0x00ff; + codec->hw_write(codec->control_data, data, 2); + } + + wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} +#else +#define wm8776_suspend NULL +#define wm8776_resume NULL +#endif + +static int wm8776_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (wm8776_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = wm8776_codec; + codec = wm8776_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, wm8776_snd_controls, + ARRAY_SIZE(wm8776_snd_controls)); + snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets, + ARRAY_SIZE(wm8776_dapm_widgets)); + snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes)); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +/* power down chip */ +static int wm8776_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8776 = { + .probe = wm8776_probe, + .remove = wm8776_remove, + .suspend = wm8776_suspend, + .resume = wm8776_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776); + +static int wm8776_register(struct wm8776_priv *wm8776) +{ + int ret, i; + struct snd_soc_codec *codec = &wm8776->codec; + + if (wm8776_codec) { + dev_err(codec->dev, "Another WM8776 is registered\n"); + ret = -EINVAL; + goto err; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = wm8776; + codec->name = "WM8776"; + codec->owner = THIS_MODULE; + codec->read = wm8776_read_reg_cache; + codec->write = wm8776_write; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8776_set_bias_level; + codec->dai = wm8776_dai; + codec->num_dai = ARRAY_SIZE(wm8776_dai); + codec->reg_cache_size = WM8776_CACHEREGNUM; + codec->reg_cache = &wm8776->reg_cache; + + memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg)); + + for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++) + wm8776_dai[i].dev = codec->dev; + + ret = wm8776_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset: %d\n", ret); + goto err; + } + + wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* Latch the update bits; right channel only since we always + * update both. */ + snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100); + snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100); + + wm8776_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai)); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); + goto err_codec; + } + + return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(wm8776); + return ret; +} + +static void wm8776_unregister(struct wm8776_priv *wm8776) +{ + wm8776_set_bias_level(&wm8776->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai)); + snd_soc_unregister_codec(&wm8776->codec); + kfree(wm8776); + wm8776_codec = NULL; +} + +#if defined(CONFIG_SPI_MASTER) +static int wm8776_spi_write(struct spi_device *spi, const char *data, int len) +{ + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} + +static int __devinit wm8776_spi_probe(struct spi_device *spi) +{ + struct snd_soc_codec *codec; + struct wm8776_priv *wm8776; + + wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL); + if (wm8776 == NULL) + return -ENOMEM; + + codec = &wm8776->codec; + codec->control_data = spi; + codec->hw_write = (hw_write_t)wm8776_spi_write; + codec->dev = &spi->dev; + + dev_set_drvdata(&spi->dev, wm8776); + + return wm8776_register(wm8776); +} + +static int __devexit wm8776_spi_remove(struct spi_device *spi) +{ + struct wm8776_priv *wm8776 = dev_get_drvdata(&spi->dev); + + wm8776_unregister(wm8776); + + return 0; +} + +#ifdef CONFIG_PM +static int wm8776_spi_suspend(struct spi_device *spi, pm_message_t msg) +{ + return snd_soc_suspend_device(&spi->dev); +} + +static int wm8776_spi_resume(struct spi_device *spi) +{ + return snd_soc_resume_device(&spi->dev); +} +#else +#define wm8776_spi_suspend NULL +#define wm8776_spi_resume NULL +#endif + +static struct spi_driver wm8776_spi_driver = { + .driver = { + .name = "wm8776", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm8776_spi_probe, + .suspend = wm8776_spi_suspend, + .resume = wm8776_spi_resume, + .remove = __devexit_p(wm8776_spi_remove), +}; +#endif /* CONFIG_SPI_MASTER */ + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static __devinit int wm8776_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8776_priv *wm8776; + struct snd_soc_codec *codec; + + wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL); + if (wm8776 == NULL) + return -ENOMEM; + + codec = &wm8776->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + + i2c_set_clientdata(i2c, wm8776); + codec->control_data = i2c; + + codec->dev = &i2c->dev; + + return wm8776_register(wm8776); +} + +static __devexit int wm8776_i2c_remove(struct i2c_client *client) +{ + struct wm8776_priv *wm8776 = i2c_get_clientdata(client); + wm8776_unregister(wm8776); + return 0; +} + +#ifdef CONFIG_PM +static int wm8776_i2c_suspend(struct i2c_client *i2c, pm_message_t msg) +{ + return snd_soc_suspend_device(&i2c->dev); +} + +static int wm8776_i2c_resume(struct i2c_client *i2c) +{ + return snd_soc_resume_device(&i2c->dev); +} +#else +#define wm8776_i2c_suspend NULL +#define wm8776_i2c_resume NULL +#endif + +static const struct i2c_device_id wm8776_i2c_id[] = { + { "wm8776", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id); + +static struct i2c_driver wm8776_i2c_driver = { + .driver = { + .name = "wm8776", + .owner = THIS_MODULE, + }, + .probe = wm8776_i2c_probe, + .remove = __devexit_p(wm8776_i2c_remove), + .suspend = wm8776_i2c_suspend, + .resume = wm8776_i2c_resume, + .id_table = wm8776_i2c_id, +}; +#endif + +static int __init wm8776_modinit(void) +{ + int ret; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&wm8776_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register WM8776 I2C driver: %d\n", + ret); + } +#endif +#if defined(CONFIG_SPI_MASTER) + ret = spi_register_driver(&wm8776_spi_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register WM8776 SPI driver: %d\n", + ret); + } +#endif + return 0; +} +module_init(wm8776_modinit); + +static void __exit wm8776_exit(void) +{ +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&wm8776_i2c_driver); +#endif +#if defined(CONFIG_SPI_MASTER) + spi_unregister_driver(&wm8776_spi_driver); +#endif +} +module_exit(wm8776_exit); + +MODULE_DESCRIPTION("ASoC WM8776 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8776.h b/sound/soc/codecs/wm8776.h new file mode 100644 index 0000000..6606d25 --- /dev/null +++ b/sound/soc/codecs/wm8776.h @@ -0,0 +1,51 @@ +/* + * wm8776.h -- WM8776 ASoC driver + * + * Copyright 2009 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef _WM8776_H +#define _WM8776_H + +/* Registers */ + +#define WM8776_HPLVOL 0x00 +#define WM8776_HPRVOL 0x01 +#define WM8776_HPMASTER 0x02 +#define WM8776_DACLVOL 0x03 +#define WM8776_DACRVOL 0x04 +#define WM8776_DACMASTER 0x05 +#define WM8776_PHASESWAP 0x06 +#define WM8776_DACCTRL1 0x07 +#define WM8776_DACMUTE 0x08 +#define WM8776_DACCTRL2 0x09 +#define WM8776_DACIFCTRL 0x0a +#define WM8776_ADCIFCTRL 0x0b +#define WM8776_MSTRCTRL 0x0c +#define WM8776_PWRDOWN 0x0d +#define WM8776_ADCLVOL 0x0e +#define WM8776_ADCRVOL 0x0f +#define WM8776_ALCCTRL1 0x10 +#define WM8776_ALCCTRL2 0x11 +#define WM8776_ALCCTRL3 0x12 +#define WM8776_NOISEGATE 0x13 +#define WM8776_LIMITER 0x14 +#define WM8776_ADCMUX 0x15 +#define WM8776_OUTMUX 0x16 +#define WM8776_RESET 0x17 + +#define WM8776_CACHEREGNUM 0x17 + +#define WM8776_DAI_DAC 0 +#define WM8776_DAI_ADC 1 + +extern struct snd_soc_dai wm8776_dai[]; +extern struct snd_soc_codec_device soc_codec_dev_wm8776; + +#endif -- cgit v0.10.2 From 4977b03e3dc3b76182903cda2df9dc2ef8f566a0 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Thu, 6 Aug 2009 12:24:54 +0200 Subject: ASoC: CX20442: add some debugging This patch adds debugging statement that can help in tracing how the driver is trying to control the codec device. Signed-off-by: Janusz Krzysztofik Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index f332455..0e54adc 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -203,6 +203,7 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, if (unlikely(len > (ARRAY_SIZE(buf) - 1))) return -ENOMEM; + dev_dbg(codec->dev, "%s: %s\n", __func__, buf); if (codec->hw_write(codec->control_data, buf, len) != len) return -EIO; -- cgit v0.10.2 From 9029bb316bb99ccc7f0518c4d3e0d6adc0729c4f Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Thu, 6 Aug 2009 12:25:00 +0200 Subject: ASoC: CX20442: simplify codec controller usage This patch is a workaround for the problem of several subsequent control statements not being applied correctly to the codec controller (modem). In order to follow the hook switch state change from handset to handsfree while in full duplex mode, two consecutive +VLS control commands were sent to the modem. The first one was M1 (microphone only), the seconds one was M1S1 (both microphone and speaker). As there was no real modem handshaking procedure implemented, neither in the codec nor in the machine driver part of the line discipline, the modem was having the second command missed. Since a possibility to switch to microphone only mode (and speaker only mode as well) seams of no value, I have modified the code to issue single M1S1 command only for any of those cases. Tested on my Amstrad Delta. Signed-off-by: Janusz Krzysztofik Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 0e54adc..38eac9c 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -138,9 +138,7 @@ static int cx20442_pm_to_v253_vls(u8 value) case 0: return V253_VLS_T; case (1 << CX20442_SPKOUT): - return V253_VLS_S1; case (1 << CX20442_MIC): - return V253_VLS_M1; case (1 << CX20442_SPKOUT) | (1 << CX20442_MIC): return V253_VLS_M1S1; case (1 << CX20442_TELOUT): -- cgit v0.10.2 From a5479e389e989acfeca9c32eeb0083d086202280 Mon Sep 17 00:00:00 2001 From: Daniel Ribeiro Date: Mon, 15 Jun 2009 21:44:31 -0300 Subject: ASoC: change set_tdm_slot api to allow slot_width override. Extend set_tdm_slot to allow the user to arbitrarily set the frame width and active TX/RX slots. Updates magician.c and wm9081.c for the new set_tdm_slot(). wm9081.c still doesn't handle the slot_width override. While being there, correct an incorrect use of SlotsPerFrm(7) use in bitmask on pxa-ssp.c (SSCR0_SlotsPerFrm(x) is (((x) - 1) << 24)) ). (this series is meant for Mark's for-2.6.32 branch) Signed-off-by: Daniel Ribeiro Signed-off-by: Mark Brown diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 25d62ac..2d3fa29 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -106,7 +106,7 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots); + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); @@ -140,7 +140,8 @@ struct snd_soc_dai_ops { */ int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); int (*set_tdm_slot)(struct snd_soc_dai *dai, - unsigned int mask, int slots); + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width); int (*set_tristate)(struct snd_soc_dai *dai, int tristate); /* diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 156f2a4..c965323 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1214,8 +1214,9 @@ static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai, return 0; } +/* FIXME: Needs to handle slot_width */ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots) + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct snd_soc_codec *codec = dai->codec; unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); @@ -1227,7 +1228,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT; - switch (mask) { + switch (rx_mask) { case 1: break; case 2: diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 8889cd3..9f7c61e 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -190,7 +190,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1); + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 0, 1, width); if (ret < 0) return ret; diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index e22c5ce..5b9ed64 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -375,21 +375,34 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, * Set the active slots in TDM/Network mode */ static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, - unsigned int mask, int slots) + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct ssp_priv *priv = cpu_dai->private_data; struct ssp_device *ssp = priv->dev.ssp; u32 sscr0; - sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7); + sscr0 = ssp_read_reg(ssp, SSCR0); + sscr0 &= ~(SSCR0_MOD | SSCR0_SlotsPerFrm(8) | SSCR0_EDSS | SSCR0_DSS); + + /* set slot width */ + if (slot_width > 16) + sscr0 |= SSCR0_EDSS | SSCR0_DataSize(slot_width - 16); + else + sscr0 |= SSCR0_DataSize(slot_width); - /* set number of active slots */ - sscr0 |= SSCR0_SlotsPerFrm(slots); + if (slots > 1) { + /* enable network mode */ + sscr0 |= SSCR0_MOD; + + /* set number of active slots */ + sscr0 |= SSCR0_SlotsPerFrm(slots); + + /* set active slot mask */ + ssp_write_reg(ssp, SSTSA, tx_mask); + ssp_write_reg(ssp, SSRSA, rx_mask); + } ssp_write_reg(ssp, SSCR0, sscr0); - /* set active slot mask */ - ssp_write_reg(ssp, SSTSA, mask); - ssp_write_reg(ssp, SSRSA, mask); return 0; } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fb8d7a7..e984a17 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2223,17 +2223,20 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); /** * snd_soc_dai_set_tdm_slot - configure DAI TDM. * @dai: DAI - * @mask: DAI specific mask representing used slots. + * @tx_mask: bitmask representing active TX slots. + * @rx_mask: bitmask representing active RX slots. * @slots: Number of slots in use. + * @slot_width: Width in bits for each slot. * * Configures a DAI for TDM operation. Both mask and slots are codec and DAI * specific. */ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots) + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { if (dai->ops && dai->ops->set_tdm_slot) - return dai->ops->set_tdm_slot(dai, mask, slots); + return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask, + slots, slot_width); else return -EINVAL; } -- cgit v0.10.2 From 297713decac17527d3583fcd4d18564568cac759 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 6 Aug 2009 04:41:45 +0000 Subject: tc35815: Disable StripCRC It seems Rx_StripCRC cause trouble on recovering from the BLEx (Buffer List Exhaust) or FDAEx (Free Descriptor Area Exhaust) condition. Do not use it. Also bump version number up. Reported-by: Ralf Roesch Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 1ce2da1..a758163 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -23,9 +23,9 @@ */ #ifdef TC35815_NAPI -#define DRV_VERSION "1.37-NAPI" +#define DRV_VERSION "1.38-NAPI" #else -#define DRV_VERSION "1.37" +#define DRV_VERSION "1.38" #endif static const char *version = "tc35815.c:v" DRV_VERSION "\n"; #define MODNAME "tc35815" @@ -341,8 +341,9 @@ struct BDesc { Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \ Tx_En) /* maybe 0x7b01 */ #endif +/* Do not use Rx_StripCRC -- it causes trouble on BLEx/FDAEx condition */ #define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \ - | Rx_EnCRCErr | Rx_EnAlign | Rx_StripCRC | Rx_RxEn) /* maybe 0x6f11 */ + | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */ #define INT_EN_CMD (Int_NRAbtEn | \ Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \ Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \ -- cgit v0.10.2 From db30f5ef6e4471fd55671382b8870fdd61e35814 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 6 Aug 2009 04:41:46 +0000 Subject: tc35815: Improve BLEx / FDAEx handling Clear Int_BLEx / Int_FDAEx after (not before) processing Rx interrupt. This will reduce number of unnecessary interrupts. Also print rx error messages only if netif_msg_rx_err() enabled. Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index a758163..62965d6 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -1541,8 +1541,6 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status) #endif { struct tc35815_local *lp = netdev_priv(dev); - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; int ret = -1; /* Fatal errors... */ @@ -1552,27 +1550,26 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status) } /* recoverable errors */ if (status & Int_IntFDAEx) { - /* disable FDAEx int. (until we make rooms...) */ - tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En); - printk(KERN_WARNING - "%s: Free Descriptor Area Exhausted (%#x).\n", - dev->name, status); + if (netif_msg_rx_err(lp)) + dev_warn(&dev->dev, + "Free Descriptor Area Exhausted (%#x).\n", + status); dev->stats.rx_dropped++; ret = 0; } if (status & Int_IntBLEx) { - /* disable BLEx int. (until we make rooms...) */ - tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En); - printk(KERN_WARNING - "%s: Buffer List Exhausted (%#x).\n", - dev->name, status); + if (netif_msg_rx_err(lp)) + dev_warn(&dev->dev, + "Buffer List Exhausted (%#x).\n", + status); dev->stats.rx_dropped++; ret = 0; } if (status & Int_IntExBD) { - printk(KERN_WARNING - "%s: Excessive Buffer Descriptiors (%#x).\n", - dev->name, status); + if (netif_msg_rx_err(lp)) + dev_warn(&dev->dev, + "Excessive Buffer Descriptiors (%#x).\n", + status); dev->stats.rx_length_errors++; ret = 0; } @@ -1631,8 +1628,12 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) spin_lock(&lp->lock); status = tc_readl(&tr->Int_Src); - tc_writel(status, &tr->Int_Src); /* write to clear */ + /* BLEx, FDAEx will be cleared later */ + tc_writel(status & ~(Int_BLEx | Int_FDAEx), + &tr->Int_Src); /* write to clear */ handled = tc35815_do_interrupt(dev, status); + if (status & (Int_BLEx | Int_FDAEx)) + tc_writel(status & (Int_BLEx | Int_FDAEx), &tr->Int_Src); (void)tc_readl(&tr->Int_Src); /* flush */ spin_unlock(&lp->lock); return IRQ_RETVAL(handled >= 0); @@ -1660,8 +1661,6 @@ tc35815_rx(struct net_device *dev) struct tc35815_local *lp = netdev_priv(dev); unsigned int fdctl; int i; - int buf_free_count = 0; - int fd_free_count = 0; #ifdef TC35815_NAPI int received = 0; #endif @@ -1770,8 +1769,9 @@ tc35815_rx(struct net_device *dev) dev->stats.rx_bytes += pkt_len; } else { dev->stats.rx_errors++; - printk(KERN_DEBUG "%s: Rx error (status %x)\n", - dev->name, status & Rx_Stat_Mask); + if (netif_msg_rx_err(lp)) + dev_info(&dev->dev, "Rx error (status %x)\n", + status & Rx_Stat_Mask); /* WORKAROUND: LongErr and CRCErr means Overflow. */ if ((status & Rx_LongErr) && (status & Rx_CRCErr)) { status &= ~(Rx_LongErr|Rx_CRCErr); @@ -1849,7 +1849,6 @@ tc35815_rx(struct net_device *dev) #else lp->fbl_count++; #endif - buf_free_count++; } } @@ -1871,7 +1870,6 @@ tc35815_rx(struct net_device *dev) #endif lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD); lp->rfd_cur++; - fd_free_count++; } if (lp->rfd_cur > lp->rfd_limit) lp->rfd_cur = lp->rfd_base; @@ -1882,17 +1880,6 @@ tc35815_rx(struct net_device *dev) #endif } - /* re-enable BL/FDA Exhaust interrupts. */ - if (fd_free_count) { - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - u32 en, en_old = tc_readl(&tr->Int_En); - en = en_old | Int_FDAExEn; - if (buf_free_count) - en |= Int_BLExEn; - if (en != en_old) - tc_writel(en, &tr->Int_En); - } #ifdef TC35815_NAPI return received; #endif @@ -1911,9 +1898,14 @@ static int tc35815_poll(struct napi_struct *napi, int budget) spin_lock(&lp->lock); status = tc_readl(&tr->Int_Src); do { - tc_writel(status, &tr->Int_Src); /* write to clear */ + /* BLEx, FDAEx will be cleared later */ + tc_writel(status & ~(Int_BLEx | Int_FDAEx), + &tr->Int_Src); /* write to clear */ handled = tc35815_do_interrupt(dev, status, budget - received); + if (status & (Int_BLEx | Int_FDAEx)) + tc_writel(status & (Int_BLEx | Int_FDAEx), + &tr->Int_Src); if (handled >= 0) { received += handled; if (received >= budget) -- cgit v0.10.2 From c60a5cf7af0a94cf8b09ca22796affa5f5f0669a Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 6 Aug 2009 04:41:47 +0000 Subject: tc35815: Increase timeout for mdio The current timeout value is too short for very high-load condition which jiffies might jump up in busy-loop. Also add minimum delay before checking completion of MDIO. Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 62965d6..f42aaf7 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -594,9 +594,10 @@ static int tc_mdio_read(struct mii_bus *bus, int mii_id, int regnum) struct net_device *dev = bus->priv; struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; - unsigned long timeout = jiffies + 10; + unsigned long timeout = jiffies + HZ; tc_writel(MD_CA_Busy | (mii_id << 5) | (regnum & 0x1f), &tr->MD_CA); + udelay(12); /* it takes 32 x 400ns at least */ while (tc_readl(&tr->MD_CA) & MD_CA_Busy) { if (time_after(jiffies, timeout)) return -EIO; @@ -610,11 +611,12 @@ static int tc_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 val) struct net_device *dev = bus->priv; struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; - unsigned long timeout = jiffies + 10; + unsigned long timeout = jiffies + HZ; tc_writel(val, &tr->MD_Data); tc_writel(MD_CA_Busy | MD_CA_Wr | (mii_id << 5) | (regnum & 0x1f), &tr->MD_CA); + udelay(12); /* it takes 32 x 400ns at least */ while (tc_readl(&tr->MD_CA) & MD_CA_Busy) { if (time_after(jiffies, timeout)) return -EIO; -- cgit v0.10.2 From 7bb82e834cc9cc95512287a9bf637719557674a0 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 6 Aug 2009 04:41:48 +0000 Subject: tc35815: Fix rx_missed_errors count The Miss_Cnt register is cleared by reading. Accumulate its value to rx_missed_errors count. Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index f42aaf7..411cc0e5 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -2139,7 +2139,7 @@ static struct net_device_stats *tc35815_get_stats(struct net_device *dev) (struct tc35815_regs __iomem *)dev->base_addr; if (netif_running(dev)) /* Update the statistics from the device registers. */ - dev->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt); + dev->stats.rx_missed_errors += tc_readl(&tr->Miss_Cnt); return &dev->stats; } -- cgit v0.10.2 From a48ec346fcb095f6a0e74a57165f9a9a3b23b95a Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 6 Aug 2009 04:41:49 +0000 Subject: tc35815: Use 0 RxFragSize.MinFrag value for non-packing mode The datasheet say "When not enabling packing, the MinFrag value must remain at 0". Do not set value to RxFragSize register if TC35815_USE_PACKEDBUFFER disabled. This is not a bugfix. No real problem reported on this. Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 411cc0e5..d1298e5 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -2394,8 +2394,6 @@ static void tc35815_chip_init(struct net_device *dev) tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl); #ifdef TC35815_USE_PACKEDBUFFER tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */ -#else - tc_writel(ETH_ZLEN, &tr->RxFragSize); #endif tc_writel(0, &tr->TxPollCtr); /* Batch mode */ tc_writel(TX_THRESHOLD, &tr->TxThrsh); -- cgit v0.10.2 From 6cb87823627699b0267234a210d8199b681c70e3 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 5 Aug 2009 08:29:31 +0000 Subject: net: smsc911x: switch to new dev_pm_ops Hibernation is unsupported for now, which meets the actual implementation in the driver. For free/thaw, the chip's D2 state should be entered. Signed-off-by: Daniel Mack Acked-by: Signed-off-by: David S. Miller diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 94b6d26..c266785 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -50,6 +50,7 @@ #include #include #include +#include #include "smsc911x.h" #define SMSC_CHIPNAME "smsc911x" @@ -2114,10 +2115,12 @@ out_0: /* This implementation assumes the devices remains powered on its VDDVARIO * pins during suspend. */ -static int smsc911x_suspend(struct platform_device *pdev, pm_message_t state) +/* TODO: implement freeze/thaw callbacks for hibernation.*/ + +static int smsc911x_suspend(struct device *dev) { - struct net_device *dev = platform_get_drvdata(pdev); - struct smsc911x_data *pdata = netdev_priv(dev); + struct net_device *ndev = dev_get_drvdata(dev); + struct smsc911x_data *pdata = netdev_priv(ndev); /* enable wake on LAN, energy detection and the external PME * signal. */ @@ -2128,10 +2131,10 @@ static int smsc911x_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int smsc911x_resume(struct platform_device *pdev) +static int smsc911x_resume(struct device *dev) { - struct net_device *dev = platform_get_drvdata(pdev); - struct smsc911x_data *pdata = netdev_priv(dev); + struct net_device *ndev = dev_get_drvdata(dev); + struct smsc911x_data *pdata = netdev_priv(ndev); unsigned int to = 100; /* Note 3.11 from the datasheet: @@ -2149,19 +2152,25 @@ static int smsc911x_resume(struct platform_device *pdev) return (to == 0) ? -EIO : 0; } +static struct dev_pm_ops smsc911x_pm_ops = { + .suspend = smsc911x_suspend, + .resume = smsc911x_resume, +}; + +#define SMSC911X_PM_OPS (&smsc911x_pm_ops) + #else -#define smsc911x_suspend NULL -#define smsc911x_resume NULL +#define SMSC911X_PM_OPS NULL #endif static struct platform_driver smsc911x_driver = { .probe = smsc911x_drv_probe, .remove = __devexit_p(smsc911x_drv_remove), .driver = { - .name = SMSC_CHIPNAME, + .name = SMSC_CHIPNAME, + .owner = THIS_MODULE, + .pm = SMSC911X_PM_OPS, }, - .suspend = smsc911x_suspend, - .resume = smsc911x_resume, }; /* Entry point for loading the module */ -- cgit v0.10.2 From a35ee541a66d11d26da30d3f6046dbddd073334e Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Thu, 6 Aug 2009 19:27:28 -0700 Subject: mlx4_en: Adaptive moderation policy change If the net device is identified as "sender" (number of sent packets is higher then the number of received packets and the incoming packets are small), set the moderation time to its low limit. We do it because the incoming packets are acks, and we don't want to delay them Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 93f4abd..c8a24dc 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -414,6 +414,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) unsigned long avg_pkt_size; unsigned long rx_packets; unsigned long rx_bytes; + unsigned long rx_byte_diff; unsigned long tx_packets; unsigned long tx_pkt_diff; unsigned long rx_pkt_diff; @@ -437,6 +438,8 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) rx_pkt_diff = ((unsigned long) (rx_packets - priv->last_moder_packets)); packets = max(tx_pkt_diff, rx_pkt_diff); + rx_byte_diff = rx_bytes - priv->last_moder_bytes; + rx_byte_diff = rx_byte_diff ? rx_byte_diff : 1; rate = packets * HZ / period; avg_pkt_size = packets ? ((unsigned long) (rx_bytes - priv->last_moder_bytes)) / packets : 0; @@ -447,10 +450,13 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) /* If tx and rx packet rates are not balanced, assume that * traffic is mainly BW bound and apply maximum moderation. * Otherwise, moderate according to packet rate */ - if (2 * tx_pkt_diff > 3 * rx_pkt_diff || - 2 * rx_pkt_diff > 3 * tx_pkt_diff) { + if (2 * tx_pkt_diff > 3 * rx_pkt_diff && + rx_pkt_diff / rx_byte_diff < + MLX4_EN_SMALL_PKT_SIZE) + moder_time = priv->rx_usecs_low; + else if (2 * rx_pkt_diff > 3 * tx_pkt_diff) moder_time = priv->rx_usecs_high; - } else { + else { if (rate < priv->pkt_rate_low) moder_time = priv->rx_usecs_low; else if (rate > priv->pkt_rate_high) -- cgit v0.10.2 From b6b912e0804dc1b3e856da3cc82fbe78b50e968c Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Thu, 6 Aug 2009 19:27:51 -0700 Subject: mlx4_en: Using real number of rings as RSS map size There is no point in using more QPs then actual number of receive rings. If the RSS function for two streams gives the same result modulo number of rings, they will arrive to the same RX ring anyway. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 9ed4a15..507e11f 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -218,8 +218,9 @@ static void *mlx4_en_add(struct mlx4_dev *dev) mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { mlx4_info(mdev, "Using %d tx rings for port:%d\n", mdev->profile.prof[i].tx_ring_num, i); - mdev->profile.prof[i].rx_ring_num = - min_t(int, dev->caps.num_comp_vectors, MAX_RX_RINGS); + mdev->profile.prof[i].rx_ring_num = min_t(int, + roundup_pow_of_two(dev->caps.num_comp_vectors), + MAX_RX_RINGS); mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n", mdev->profile.prof[i].rx_ring_num, i); } diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index c8a24dc..f8bbc5a 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -1011,9 +1011,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, if (err) goto out; - /* Populate Rx default RSS mappings */ - mlx4_en_set_default_rss_map(priv, &priv->rss_map, priv->rx_ring_num * - RSS_FACTOR, priv->rx_ring_num); /* Allocate page for receive rings */ err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 91bdfdf..47b178e 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -835,23 +835,6 @@ void mlx4_en_calc_rx_buf(struct net_device *dev) /* RSS related functions */ -/* Calculate rss size and map each entry in rss table to rx ring */ -void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, - struct mlx4_en_rss_map *rss_map, - int num_entries, int num_rings) -{ - int i; - - rss_map->size = roundup_pow_of_two(num_entries); - en_dbg(DRV, priv, "Setting default RSS map of %d entires\n", - rss_map->size); - - for (i = 0; i < rss_map->size; i++) { - rss_map->map[i] = i % num_rings; - en_dbg(DRV, priv, "Entry %d ---> ring %d\n", i, rss_map->map[i]); - } -} - static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, int srqn, int cqn, enum mlx4_qp_state *state, @@ -902,16 +885,17 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) int good_qps = 0; en_dbg(DRV, priv, "Configuring rss steering\n"); - err = mlx4_qp_reserve_range(mdev->dev, rss_map->size, - rss_map->size, &rss_map->base_qpn); + err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num, + priv->rx_ring_num, + &rss_map->base_qpn); if (err) { - en_err(priv, "Failed reserving %d qps\n", rss_map->size); + en_err(priv, "Failed reserving %d qps\n", priv->rx_ring_num); return err; } - for (i = 0; i < rss_map->size; i++) { - cqn = priv->rx_ring[rss_map->map[i]].cqn; - srqn = priv->rx_ring[rss_map->map[i]].srq.srqn; + for (i = 0; i < priv->rx_ring_num; i++) { + cqn = priv->rx_ring[i].cqn; + srqn = priv->rx_ring[i].srq.srqn; qpn = rss_map->base_qpn + i; err = mlx4_en_config_rss_qp(priv, qpn, srqn, cqn, &rss_map->state[i], @@ -940,7 +924,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) ptr = ((void *) &context) + 0x3c; rss_context = (struct mlx4_en_rss_context *) ptr; - rss_context->base_qpn = cpu_to_be32(ilog2(rss_map->size) << 24 | + rss_context->base_qpn = cpu_to_be32(ilog2(priv->rx_ring_num) << 24 | (rss_map->base_qpn)); rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn); rss_context->hash_fn = rss_xor & 0x3; @@ -967,7 +951,7 @@ rss_err: mlx4_qp_remove(mdev->dev, &rss_map->qps[i]); mlx4_qp_free(mdev->dev, &rss_map->qps[i]); } - mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, rss_map->size); + mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, priv->rx_ring_num); return err; } @@ -983,13 +967,13 @@ void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv) mlx4_qp_free(mdev->dev, &rss_map->indir_qp); mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); - for (i = 0; i < rss_map->size; i++) { + for (i = 0; i < priv->rx_ring_num; i++) { mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->qps[i]); mlx4_qp_remove(mdev->dev, &rss_map->qps[i]); mlx4_qp_free(mdev->dev, &rss_map->qps[i]); } - mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, rss_map->size); + mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, priv->rx_ring_num); } diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index c7c5e86..2d76ff4 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -95,8 +95,6 @@ #define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) #define MAX_TX_RINGS 16 #define MAX_RX_RINGS 16 -#define MAX_RSS_MAP_SIZE 64 -#define RSS_FACTOR 2 #define TXBB_SIZE 64 #define HEADROOM (2048 / TXBB_SIZE + 1) #define STAMP_STRIDE 64 @@ -377,11 +375,9 @@ struct mlx4_en_dev { struct mlx4_en_rss_map { - int size; int base_qpn; - u16 map[MAX_RSS_MAP_SIZE]; - struct mlx4_qp qps[MAX_RSS_MAP_SIZE]; - enum mlx4_qp_state state[MAX_RSS_MAP_SIZE]; + struct mlx4_qp qps[MAX_RX_RINGS]; + enum mlx4_qp_state state[MAX_RX_RINGS]; struct mlx4_qp indir_qp; enum mlx4_qp_state indir_state; }; @@ -555,9 +551,6 @@ int mlx4_en_map_buffer(struct mlx4_buf *buf); void mlx4_en_unmap_buffer(struct mlx4_buf *buf); void mlx4_en_calc_rx_buf(struct net_device *dev); -void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, - struct mlx4_en_rss_map *rss_map, - int num_entries, int num_rings); int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv); void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv); int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring); -- cgit v0.10.2 From 9f519f68cfffba022978634f724944a0b971fec1 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Thu, 6 Aug 2009 19:28:18 -0700 Subject: mlx4_en: Not using Shared Receive Queues We use 1:1 mapping between QPs and SRQs on receive side, so additional indirection level not required. Allocated the receive buffers for the RSS QPs. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index f8bbc5a..c48b0f4b 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -622,8 +622,7 @@ int mlx4_en_start_port(struct net_device *dev) /* Configure ring */ tx_ring = &priv->tx_ring[i]; - err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn, - priv->rx_ring[0].srq.srqn); + err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn); if (err) { en_err(priv, "Failed allocating Tx ring\n"); mlx4_en_deactivate_cq(priv, cq); diff --git a/drivers/net/mlx4/en_resources.c b/drivers/net/mlx4/en_resources.c index 65ca706..1625678 100644 --- a/drivers/net/mlx4/en_resources.c +++ b/drivers/net/mlx4/en_resources.c @@ -37,7 +37,7 @@ #include "mlx4_en.h" void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, - int is_tx, int rss, int qpn, int cqn, int srqn, + int is_tx, int rss, int qpn, int cqn, struct mlx4_qp_context *context) { struct mlx4_en_dev *mdev = priv->mdev; @@ -46,11 +46,12 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, context->flags = cpu_to_be32(7 << 16 | rss << 13); context->pd = cpu_to_be32(mdev->priv_pdn); context->mtu_msgmax = 0xff; - context->rq_size_stride = 0; + if (!is_tx && !rss) + context->rq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); if (is_tx) context->sq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); else - context->sq_size_stride = 1; + context->sq_size_stride = ilog2(TXBB_SIZE) - 4; context->usr_page = cpu_to_be32(mdev->priv_uar.index); context->local_qpn = cpu_to_be32(qpn); context->pri_path.ackto = 1 & 0x07; @@ -59,8 +60,6 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, context->cqn_send = cpu_to_be32(cqn); context->cqn_recv = cpu_to_be32(cqn); context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2); - if (!rss) - context->srqn = cpu_to_be32(MLX4_EN_USE_SRQ | srqn); } diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 47b178e..cd084de 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -40,16 +40,6 @@ #include "mlx4_en.h" -static void *get_wqe(struct mlx4_en_rx_ring *ring, int n) -{ - int offset = n << ring->srq.wqe_shift; - return ring->buf + offset; -} - -static void mlx4_en_srq_event(struct mlx4_srq *srq, enum mlx4_event type) -{ - return; -} static int mlx4_en_get_frag_header(struct skb_frag_struct *frags, void **mac_hdr, void **ip_hdr, void **tcpudp_hdr, @@ -154,9 +144,6 @@ static void mlx4_en_init_rx_desc(struct mlx4_en_priv *priv, int possible_frags; int i; - /* Pre-link descriptor */ - rx_desc->next.next_wqe_index = cpu_to_be16((index + 1) & ring->size_mask); - /* Set size and memtype fields */ for (i = 0; i < priv->num_frags; i++) { skb_frags[i].size = priv->frag_info[i].frag_size; @@ -294,9 +281,6 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, int err; int tmp; - /* Sanity check SRQ size before proceeding */ - if (size >= mdev->dev->caps.max_srq_wqes) - return -EINVAL; ring->prod = 0; ring->cons = 0; @@ -304,7 +288,7 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, ring->size_mask = size - 1; ring->stride = stride; ring->log_stride = ffs(ring->stride) - 1; - ring->buf_size = ring->size * ring->stride; + ring->buf_size = ring->size * ring->stride + TXBB_SIZE; tmp = size * roundup_pow_of_two(MLX4_EN_MAX_RX_FRAGS * sizeof(struct skb_frag_struct)); @@ -360,15 +344,12 @@ err_ring: int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) { - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_wqe_srq_next_seg *next; struct mlx4_en_rx_ring *ring; int i; int ring_ind; int err; int stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + DS_SIZE * priv->num_frags); - int max_gs = (stride - sizeof(struct mlx4_wqe_srq_next_seg)) / DS_SIZE; for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { ring = &priv->rx_ring[ring_ind]; @@ -379,6 +360,9 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) ring->cqn = priv->rx_cq[ring_ind].mcq.cqn; ring->stride = stride; + if (ring->stride <= TXBB_SIZE) + ring->buf += TXBB_SIZE; + ring->log_stride = ffs(ring->stride) - 1; ring->buf_size = ring->size * ring->stride; @@ -405,37 +389,10 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) ring = &priv->rx_ring[ring_ind]; mlx4_en_update_rx_prod_db(ring); - - /* Configure SRQ representing the ring */ - ring->srq.max = ring->actual_size; - ring->srq.max_gs = max_gs; - ring->srq.wqe_shift = ilog2(ring->stride); - - for (i = 0; i < ring->srq.max; ++i) { - next = get_wqe(ring, i); - next->next_wqe_index = - cpu_to_be16((i + 1) & (ring->srq.max - 1)); - } - - err = mlx4_srq_alloc(mdev->dev, mdev->priv_pdn, &ring->wqres.mtt, - ring->wqres.db.dma, &ring->srq); - if (err){ - en_err(priv, "Failed to allocate srq\n"); - ring_ind--; - goto err_srq; - } - ring->srq.event = mlx4_en_srq_event; } return 0; -err_srq: - while (ring_ind >= 0) { - ring = &priv->rx_ring[ring_ind]; - mlx4_srq_free(mdev->dev, &ring->srq); - ring_ind--; - } - err_buffers: for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) mlx4_en_free_rx_buf(priv, &priv->rx_ring[ring_ind]); @@ -456,7 +413,7 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, kfree(ring->lro.lro_arr); mlx4_en_unmap_buffer(&ring->wqres.buf); - mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); + mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size + TXBB_SIZE); vfree(ring->rx_info); ring->rx_info = NULL; } @@ -464,10 +421,9 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring) { - struct mlx4_en_dev *mdev = priv->mdev; - - mlx4_srq_free(mdev->dev, &ring->srq); mlx4_en_free_rx_buf(priv, ring); + if (ring->stride <= TXBB_SIZE) + ring->buf -= TXBB_SIZE; mlx4_en_destroy_allocator(priv, ring); } @@ -835,8 +791,8 @@ void mlx4_en_calc_rx_buf(struct net_device *dev) /* RSS related functions */ -static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, - int qpn, int srqn, int cqn, +static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, + struct mlx4_en_rx_ring *ring, enum mlx4_qp_state *state, struct mlx4_qp *qp) { @@ -858,13 +814,16 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, qp->event = mlx4_en_sqp_event; memset(context, 0, sizeof *context); - mlx4_en_fill_qp_context(priv, 0, 0, 0, 0, qpn, cqn, srqn, context); + mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 0, 0, + qpn, ring->cqn, context); + context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma); - err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, context, qp, state); + err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, context, qp, state); if (err) { mlx4_qp_remove(mdev->dev, qp); mlx4_qp_free(mdev->dev, qp); } + mlx4_en_update_rx_prod_db(ring); out: kfree(context); return err; @@ -880,7 +839,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) void *ptr; int rss_xor = mdev->profile.rss_xor; u8 rss_mask = mdev->profile.rss_mask; - int i, srqn, qpn, cqn; + int i, qpn; int err = 0; int good_qps = 0; @@ -894,10 +853,8 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) } for (i = 0; i < priv->rx_ring_num; i++) { - cqn = priv->rx_ring[i].cqn; - srqn = priv->rx_ring[i].srq.srqn; qpn = rss_map->base_qpn + i; - err = mlx4_en_config_rss_qp(priv, qpn, srqn, cqn, + err = mlx4_en_config_rss_qp(priv, qpn, &priv->rx_ring[i], &rss_map->state[i], &rss_map->qps[i]); if (err) @@ -920,7 +877,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) } rss_map->indir_qp.event = mlx4_en_sqp_event; mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, - priv->rx_ring[0].cqn, 0, &context); + priv->rx_ring[0].cqn, &context); ptr = ((void *) &context) + 0x3c; rss_context = (struct mlx4_en_rss_context *) ptr; diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index d5c18c6..cbc8ab0 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -150,7 +150,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - int cq, int srqn) + int cq) { struct mlx4_en_dev *mdev = priv->mdev; int err; @@ -168,7 +168,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, ring->doorbell_qpn = swab32(ring->qp.qpn << 8); mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, - ring->cqn, srqn, &ring->context); + ring->cqn, &ring->context); err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context, &ring->qp, &ring->qp_state); diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 2d76ff4..4513fb4 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -274,13 +274,11 @@ struct mlx4_en_tx_ring { }; struct mlx4_en_rx_desc { - struct mlx4_wqe_srq_next_seg next; /* actual number of entries depends on rx ring stride */ struct mlx4_wqe_data_seg data[0]; }; struct mlx4_en_rx_ring { - struct mlx4_srq srq; struct mlx4_hwq_resources wqres; struct mlx4_en_rx_alloc page_alloc[MLX4_EN_MAX_RX_FRAGS]; struct net_lro_mgr lro; @@ -527,7 +525,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ri void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - int cq, int srqn); + int cq); void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); @@ -544,7 +542,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, int budget); int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget); void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, - int is_tx, int rss, int qpn, int cqn, int srqn, + int is_tx, int rss, int qpn, int cqn, struct mlx4_qp_context *context); void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event); int mlx4_en_map_buffer(struct mlx4_buf *buf); -- cgit v0.10.2 From bbd8a0d3a3b65d341437f8b99c828fa5cc29c739 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Thu, 6 Aug 2009 01:44:21 +0000 Subject: net: Avoid enqueuing skb for default qdiscs dev_queue_xmit enqueue's a skb and calls qdisc_run which dequeue's the skb and xmits it. In most cases, the skb that is enqueue'd is the same one that is dequeue'd (unless the queue gets stopped or multiple cpu's write to the same queue and ends in a race with qdisc_run). For default qdiscs, we can remove the redundant enqueue/dequeue and simply xmit the skb since the default qdisc is work-conserving. The patch uses a new flag - TCQ_F_CAN_BYPASS to identify the default fast queue. The controversial part of the patch is incrementing qlen when a skb is requeued - this is to avoid checks like the second line below: + } else if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) && >> !q->gso_skb && + !test_and_set_bit(__QDISC_STATE_RUNNING, &q->state)) { Results of a 2 hour testing for multiple netperf sessions (1, 2, 4, 8, 12 sessions on a 4 cpu system-X). The BW numbers are aggregate Mb/s across iterations tested with this version on System-X boxes with Chelsio 10gbps cards: ---------------------------------- Size | ORG BW NEW BW | ---------------------------------- 128K | 156964 159381 | 256K | 158650 162042 | ---------------------------------- Changes from ver1: 1. Move sch_direct_xmit declaration from sch_generic.h to pkt_sched.h 2. Update qdisc basic statistics for direct xmit path. 3. Set qlen to zero in qdisc_reset. 4. Changed some function names to more meaningful ones. Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 82a3191..f911ec7 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -87,6 +87,9 @@ extern struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, extern void qdisc_put_rtab(struct qdisc_rate_table *tab); extern void qdisc_put_stab(struct qdisc_size_table *tab); extern void qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc); +extern int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, + struct net_device *dev, struct netdev_queue *txq, + spinlock_t *root_lock); extern void __qdisc_run(struct Qdisc *q); diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 964ffa0..84b3fc2 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -45,6 +45,7 @@ struct Qdisc #define TCQ_F_BUILTIN 1 #define TCQ_F_THROTTLED 2 #define TCQ_F_INGRESS 4 +#define TCQ_F_CAN_BYPASS 8 #define TCQ_F_WARN_NONWC (1 << 16) int padded; struct Qdisc_ops *ops; @@ -182,6 +183,11 @@ struct qdisc_skb_cb { char data[]; }; +static inline int qdisc_qlen(struct Qdisc *q) +{ + return q->q.qlen; +} + static inline struct qdisc_skb_cb *qdisc_skb_cb(struct sk_buff *skb) { return (struct qdisc_skb_cb *)skb->cb; @@ -387,13 +393,18 @@ static inline int qdisc_enqueue_root(struct sk_buff *skb, struct Qdisc *sch) return qdisc_enqueue(skb, sch) & NET_XMIT_MASK; } +static inline void __qdisc_update_bstats(struct Qdisc *sch, unsigned int len) +{ + sch->bstats.bytes += len; + sch->bstats.packets++; +} + static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff_head *list) { __skb_queue_tail(list, skb); sch->qstats.backlog += qdisc_pkt_len(skb); - sch->bstats.bytes += qdisc_pkt_len(skb); - sch->bstats.packets++; + __qdisc_update_bstats(sch, qdisc_pkt_len(skb)); return NET_XMIT_SUCCESS; } diff --git a/net/core/dev.c b/net/core/dev.c index f01a9c4..a0bc087 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1786,6 +1786,40 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev, return netdev_get_tx_queue(dev, queue_index); } +static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, + struct net_device *dev, + struct netdev_queue *txq) +{ + spinlock_t *root_lock = qdisc_lock(q); + int rc; + + spin_lock(root_lock); + if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) { + kfree_skb(skb); + rc = NET_XMIT_DROP; + } else if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) && + !test_and_set_bit(__QDISC_STATE_RUNNING, &q->state)) { + /* + * This is a work-conserving queue; there are no old skbs + * waiting to be sent out; and the qdisc is not running - + * xmit the skb directly. + */ + __qdisc_update_bstats(q, skb->len); + if (sch_direct_xmit(skb, q, dev, txq, root_lock)) + __qdisc_run(q); + else + clear_bit(__QDISC_STATE_RUNNING, &q->state); + + rc = NET_XMIT_SUCCESS; + } else { + rc = qdisc_enqueue_root(skb, q); + qdisc_run(q); + } + spin_unlock(root_lock); + + return rc; +} + /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit @@ -1859,19 +1893,7 @@ gso: skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS); #endif if (q->enqueue) { - spinlock_t *root_lock = qdisc_lock(q); - - spin_lock(root_lock); - - if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) { - kfree_skb(skb); - rc = NET_XMIT_DROP; - } else { - rc = qdisc_enqueue_root(skb, q); - qdisc_run(q); - } - spin_unlock(root_lock); - + rc = __dev_xmit_skb(skb, q, dev, txq); goto out; } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 27d0381..693df7a 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -37,15 +37,11 @@ * - updates to tree and tree walking are only done under the rtnl mutex. */ -static inline int qdisc_qlen(struct Qdisc *q) -{ - return q->q.qlen; -} - static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) { q->gso_skb = skb; q->qstats.requeues++; + q->q.qlen++; /* it's still part of the queue */ __netif_schedule(q); return 0; @@ -61,9 +57,11 @@ static inline struct sk_buff *dequeue_skb(struct Qdisc *q) /* check the reason of requeuing without tx lock first */ txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); - if (!netif_tx_queue_stopped(txq) && !netif_tx_queue_frozen(txq)) + if (!netif_tx_queue_stopped(txq) && + !netif_tx_queue_frozen(txq)) { q->gso_skb = NULL; - else + q->q.qlen--; + } else skb = NULL; } else { skb = q->dequeue(q); @@ -103,44 +101,23 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb, } /* - * NOTE: Called under qdisc_lock(q) with locally disabled BH. - * - * __QDISC_STATE_RUNNING guarantees only one CPU can process - * this qdisc at a time. qdisc_lock(q) serializes queue accesses for - * this queue. - * - * netif_tx_lock serializes accesses to device driver. - * - * qdisc_lock(q) and netif_tx_lock are mutually exclusive, - * if one is grabbed, another must be free. - * - * Note, that this procedure can be called by a watchdog timer + * Transmit one skb, and handle the return status as required. Holding the + * __QDISC_STATE_RUNNING bit guarantees that only one CPU can execute this + * function. * * Returns to the caller: * 0 - queue is empty or throttled. * >0 - queue is not empty. - * */ -static inline int qdisc_restart(struct Qdisc *q) +int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, + struct net_device *dev, struct netdev_queue *txq, + spinlock_t *root_lock) { - struct netdev_queue *txq; int ret = NETDEV_TX_BUSY; - struct net_device *dev; - spinlock_t *root_lock; - struct sk_buff *skb; - - /* Dequeue packet */ - if (unlikely((skb = dequeue_skb(q)) == NULL)) - return 0; - - root_lock = qdisc_lock(q); /* And release qdisc */ spin_unlock(root_lock); - dev = qdisc_dev(q); - txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); - HARD_TX_LOCK(dev, txq, smp_processor_id()); if (!netif_tx_queue_stopped(txq) && !netif_tx_queue_frozen(txq)) @@ -177,6 +154,44 @@ static inline int qdisc_restart(struct Qdisc *q) return ret; } +/* + * NOTE: Called under qdisc_lock(q) with locally disabled BH. + * + * __QDISC_STATE_RUNNING guarantees only one CPU can process + * this qdisc at a time. qdisc_lock(q) serializes queue accesses for + * this queue. + * + * netif_tx_lock serializes accesses to device driver. + * + * qdisc_lock(q) and netif_tx_lock are mutually exclusive, + * if one is grabbed, another must be free. + * + * Note, that this procedure can be called by a watchdog timer + * + * Returns to the caller: + * 0 - queue is empty or throttled. + * >0 - queue is not empty. + * + */ +static inline int qdisc_restart(struct Qdisc *q) +{ + struct netdev_queue *txq; + struct net_device *dev; + spinlock_t *root_lock; + struct sk_buff *skb; + + /* Dequeue packet */ + skb = dequeue_skb(q); + if (unlikely(!skb)) + return 0; + + root_lock = qdisc_lock(q); + dev = qdisc_dev(q); + txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); + + return sch_direct_xmit(skb, q, dev, txq, root_lock); +} + void __qdisc_run(struct Qdisc *q) { unsigned long start_time = jiffies; @@ -547,8 +562,11 @@ void qdisc_reset(struct Qdisc *qdisc) if (ops->reset) ops->reset(qdisc); - kfree_skb(qdisc->gso_skb); - qdisc->gso_skb = NULL; + if (qdisc->gso_skb) { + kfree_skb(qdisc->gso_skb); + qdisc->gso_skb = NULL; + qdisc->q.qlen = 0; + } } EXPORT_SYMBOL(qdisc_reset); @@ -605,6 +623,9 @@ static void attach_one_default_qdisc(struct net_device *dev, printk(KERN_INFO "%s: activation failed\n", dev->name); return; } + + /* Can by-pass the queue discipline for default qdisc */ + qdisc->flags |= TCQ_F_CAN_BYPASS; } else { qdisc = &noqueue_qdisc; } -- cgit v0.10.2 From c12abc012e18b362204345c323536f228d65c4db Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 7 Aug 2009 09:59:47 +0300 Subject: ARM: OMAP: McBSP: Fix ASoC on OMAP1510 by fixing API of omap_mcbsp_start/stop Simultaneous audio playback and capture on OMAP1510 can cause that second stream is stalled if there is enough delay between startup of the audio streams. Current implementation of the omap_mcbsp_start is starting both transmitter and receiver at the same time and it is called only for firstly started audio stream from the OMAP McBSP based ASoC DAI driver. Since DMA request lines on OMAP1510 are edge sensitive, the DMA request is missed if there is no DMA transfer set up at that time when the first word after McBSP startup is transmitted. The problem hasn't noted before since later OMAPs are using level sensitive DMA request lines. Fix the problem by changing API of omap_mcbsp_start and omap_mcbsp_stop by allowing to start and stop individually McBSP transmitter and receiver logics. Then call those functions individually for both audio playback and capture streams. This ensures that DMA transfer is setup before transmitter or receiver is started. Thanks to Janusz Krzysztofik for detailed problem analysis and Peter Ujfalusi for info about DMA request line behavior differences between the OMAP generations. Reported-and-tested-by: Janusz Krzysztofik Signed-off-by: Jarkko Nikula Acked-by: Tony Lindgren Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index bb154ea..57249bb 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -387,8 +387,8 @@ void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config, void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config); int omap_mcbsp_request(unsigned int id); void omap_mcbsp_free(unsigned int id); -void omap_mcbsp_start(unsigned int id); -void omap_mcbsp_stop(unsigned int id); +void omap_mcbsp_start(unsigned int id, int tx, int rx); +void omap_mcbsp_stop(unsigned int id, int tx, int rx); void omap_mcbsp_xmit_word(unsigned int id, u32 word); u32 omap_mcbsp_recv_word(unsigned int id); diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index efa0e01..a3d2313 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -328,14 +328,15 @@ void omap_mcbsp_free(unsigned int id) EXPORT_SYMBOL(omap_mcbsp_free); /* - * Here we start the McBSP, by enabling the sample - * generator, both transmitter and receivers, - * and the frame sync. + * Here we start the McBSP, by enabling transmitter, receiver or both. + * If no transmitter or receiver is active prior calling, then sample-rate + * generator and frame sync are started. */ -void omap_mcbsp_start(unsigned int id) +void omap_mcbsp_start(unsigned int id, int tx, int rx) { struct omap_mcbsp *mcbsp; void __iomem *io_base; + int idle; u16 w; if (!omap_mcbsp_check_valid_id(id)) { @@ -348,32 +349,40 @@ void omap_mcbsp_start(unsigned int id) mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7; mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7; - /* Start the sample generator */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); + idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | + OMAP_MCBSP_READ(io_base, SPCR1)) & 1); + + if (idle) { + /* Start the sample generator */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); + } /* Enable transmitter and receiver */ w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | (tx & 1)); w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1); + OMAP_MCBSP_WRITE(io_base, SPCR1, w | (rx & 1)); udelay(100); - /* Start frame sync */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); + if (idle) { + /* Start frame sync */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); + } /* Dump McBSP Regs */ omap_mcbsp_dump_reg(id); } EXPORT_SYMBOL(omap_mcbsp_start); -void omap_mcbsp_stop(unsigned int id) +void omap_mcbsp_stop(unsigned int id, int tx, int rx) { struct omap_mcbsp *mcbsp; void __iomem *io_base; + int idle; u16 w; if (!omap_mcbsp_check_valid_id(id)) { @@ -386,15 +395,20 @@ void omap_mcbsp_stop(unsigned int id) /* Reset transmitter */ w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1)); + OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(tx & 1)); /* Reset receiver */ w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1)); + OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(rx & 1)); - /* Reset the sample rate generator */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); + idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | + OMAP_MCBSP_READ(io_base, SPCR1)) & 1); + + if (idle) { + /* Reset the sample rate generator */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); + } } EXPORT_SYMBOL(omap_mcbsp_stop); diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index a5d46a7..6a837ff 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -183,21 +183,21 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); - int err = 0; + int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (!mcbsp_data->active++) - omap_mcbsp_start(mcbsp_data->bus_id); + mcbsp_data->active++; + omap_mcbsp_start(mcbsp_data->bus_id, play, !play); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (!--mcbsp_data->active) - omap_mcbsp_stop(mcbsp_data->bus_id); + omap_mcbsp_stop(mcbsp_data->bus_id, play, !play); + mcbsp_data->active--; break; default: err = -EINVAL; -- cgit v0.10.2 From 9bb74150561bb337b49192a8f8e8f812057b88ea Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 6 Aug 2009 16:55:31 -0700 Subject: ASoC: DaVinci: i2s: don't bounce through rtd to get dai dai is a parameter to the functions, so use it instead of looking it up. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index e5cd97b..2a56fb7 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -353,9 +353,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; - struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; + struct davinci_pcm_dma_params *dma_params = dai->dma_data; + struct davinci_mcbsp_dev *dev = dai->private_data; struct snd_interval *i = NULL; int mcbsp_word_length; unsigned int rcr, xcr, srgr; @@ -425,8 +424,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, static int davinci_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; + struct davinci_mcbsp_dev *dev = dai->private_data; int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); davinci_mcbsp_stop(dev, playback); if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) { @@ -439,8 +437,7 @@ static int davinci_i2s_prepare(struct snd_pcm_substream *substream, static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; + struct davinci_mcbsp_dev *dev = dai->private_data; int ret = 0; int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) @@ -466,8 +463,7 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; + struct davinci_mcbsp_dev *dev = dai->private_data; int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); davinci_mcbsp_stop(dev, playback); } -- cgit v0.10.2 From 6a90d536feeccb2c84a2831252b1ed4642684da3 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 6 Aug 2009 16:55:32 -0700 Subject: ASoC: DaVinci: pcm, constrain buffer size to multiple of period The dma setup code assumes that the buffer size is a multiple of the period size. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 8fd0c3c..ab43a53 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -244,6 +244,11 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream) int ret = 0; snd_soc_set_runtime_hwparams(substream, &davinci_pcm_hardware); + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL); if (prtd == NULL) -- cgit v0.10.2 From b7b8f9bf0cd73b90561e8123fd5ec28f4539c419 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Thu, 6 Aug 2009 13:07:32 +0200 Subject: TTY/ASoC: Rename N_AMSDELTA line discipline to N_V253 The patch changes the line discipline name registered in include/linux/tty.h and updates the ams-delta machine driver to use it. Signed-off-by: Janusz Krzysztofik Signed-off-by: Mark Brown diff --git a/include/linux/tty.h b/include/linux/tty.h index 26af981..15bd3b0 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -47,7 +47,7 @@ #define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */ #define N_PPS 18 /* Pulse per Second */ -#define N_AMSDELTA 19 /* codec control over modem, board specific */ +#define N_V253 19 /* Codec control over voice modem */ /* * This character is the same as _POSIX_VDISABLE: it cannot be used as diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 4f35b1f..5a5166a 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -500,7 +500,7 @@ static int ams_delta_cx20442_init(struct snd_soc_codec *codec) } /* Register optional line discipline for over the modem control */ - ret = tty_register_ldisc(N_AMSDELTA, &cx81801_ops); + ret = tty_register_ldisc(N_V253, &cx81801_ops); if (ret) { dev_warn(card->dev, "Failed to register line discipline, " @@ -625,9 +625,9 @@ static void __exit ams_delta_module_exit(void) } } - if (tty_unregister_ldisc(N_AMSDELTA) != 0) + if (tty_unregister_ldisc(N_V253) != 0) dev_warn(&ams_delta_audio_platform_device->dev, - "failed to unregister AMSDELTA line discipline\n"); + "failed to unregister V253 line discipline\n"); snd_soc_jack_free_gpios(&ams_delta_hook_switch, ARRAY_SIZE(ams_delta_hook_switch_gpios), -- cgit v0.10.2 From dbe9ea6e79d38cd5f2069405864ff06606cf9ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 7 Aug 2009 22:42:37 +0200 Subject: ASoC: s3c2443-ac97: convert semaphore to mutex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a build failure for 2.6.31-rc4-rt1 (ARCH=arm, s3c2410_defconfig): CC [M] sound/soc/s3c24xx/s3c2443-ac97.o sound/soc/s3c24xx/s3c2443-ac97.c:50: warning: type defaults to 'int' in declaration of 'DECLARE_MUTEX' sound/soc/s3c24xx/s3c2443-ac97.c:50: warning: parameter names (without types) in function declaration sound/soc/s3c24xx/s3c2443-ac97.c: In function 's3c2443_ac97_read': sound/soc/s3c24xx/s3c2443-ac97.c:59: error: 'ac97_mutex' undeclared (first use in this function) sound/soc/s3c24xx/s3c2443-ac97.c:59: error: (Each undeclared identifier is reported only once sound/soc/s3c24xx/s3c2443-ac97.c:59: error: for each function it appears in.) sound/soc/s3c24xx/s3c2443-ac97.c: In function 's3c2443_ac97_write': sound/soc/s3c24xx/s3c2443-ac97.c:93: error: 'ac97_mutex' undeclared (first use in this function) Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 3f03d5d..bf16f20 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -47,7 +47,7 @@ static struct s3c24xx_ac97_info s3c24xx_ac97; static DECLARE_COMPLETION(ac97_completion); static u32 codec_ready; -static DECLARE_MUTEX(ac97_mutex); +static DEFINE_MUTEX(ac97_mutex); static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, unsigned short reg) @@ -56,7 +56,7 @@ static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, u32 ac_codec_cmd; u32 stat, addr, data; - down(&ac97_mutex); + mutex_lock(&ac97_mutex); codec_ready = S3C_AC97_GLBSTAT_CODECREADY; ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); @@ -79,7 +79,7 @@ static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, printk(KERN_ERR "s3c24xx-ac97: req addr = %02x," " rep addr = %02x\n", reg, addr); - up(&ac97_mutex); + mutex_unlock(&ac97_mutex); return (unsigned short)data; } @@ -90,7 +90,7 @@ static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg, u32 ac_glbctrl; u32 ac_codec_cmd; - down(&ac97_mutex); + mutex_lock(&ac97_mutex); codec_ready = S3C_AC97_GLBSTAT_CODECREADY; ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); @@ -109,7 +109,7 @@ static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg, ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); - up(&ac97_mutex); + mutex_unlock(&ac97_mutex); } -- cgit v0.10.2 From 7ae5945f0cacdfa30ed3257892dbea75bc959a28 Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Fri, 7 Aug 2009 10:07:51 -0400 Subject: ASoC: DaVinci: Support Audio on DA830 EVM Add support for audio on DA830 EVM- here McASP1 is interfaced to TLV320AIC3106 codec. Signed-off-by: Chaithrika U S Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 6802dd5..677a538 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -41,3 +41,14 @@ config SND_DAVINCI_SOC_SFFSDR help Say Y if you want to add support for SoC audio on Lyrtech SFFSDR board. + +config SND_DA830_SOC_EVM + tristate "SoC Audio support for DA830/OMAPL137 EVM" + depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM + select SND_DAVINCI_SOC_MCASP + select SND_SOC_TLV320AIC3X + + help + Say Y if you want to add support for SoC audio on TI + DA830/OMAPL137 EVM + diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index 67be54f..5e2195f 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -13,4 +13,5 @@ snd-soc-sffsdr-objs := davinci-sffsdr.o obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o +obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index f3bb6f6..a5a9212 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -54,6 +54,9 @@ static int evm_hw_params(struct snd_pcm_substream *substream, else if (machine_is_davinci_evm()) sysclk = 12288000; + else if (machine_is_davinci_da830_evm()) + sysclk = 24576000; + else return -EINVAL; @@ -162,6 +165,14 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = { .ops = &evm_ops, }, }; +static struct snd_soc_dai_link da830_evm_dai = { + .name = "TLV320AIC3X", + .stream_name = "AIC3X", + .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI], + .codec_dai = &aic3x_dai, + .init = evm_aic3x_init, + .ops = &evm_ops, +}; /* davinci-evm audio machine driver */ static struct snd_soc_card snd_soc_card_evm = { @@ -179,6 +190,13 @@ static struct snd_soc_card dm6467_snd_soc_card_evm = { .num_links = ARRAY_SIZE(dm6467_evm_dai), }; +static struct snd_soc_card da830_snd_soc_card = { + .name = "DA830 EVM", + .dai_link = &da830_evm_dai, + .platform = &davinci_soc_platform, + .num_links = 1, +}; + /* evm audio private data */ static struct aic3x_setup_data evm_aic3x_setup = { .i2c_bus = 1, @@ -191,6 +209,11 @@ static struct aic3x_setup_data dm6467_evm_aic3x_setup = { .i2c_address = 0x18, }; +static struct aic3x_setup_data da830_evm_aic3x_setup = { + .i2c_bus = 1, + .i2c_address = 0x18, +}; + /* evm audio subsystem */ static struct snd_soc_device evm_snd_devdata = { .card = &snd_soc_card_evm, @@ -205,6 +228,13 @@ static struct snd_soc_device dm6467_evm_snd_devdata = { .codec_data = &dm6467_evm_aic3x_setup, }; +/* evm audio subsystem */ +static struct snd_soc_device da830_evm_snd_devdata = { + .card = &da830_snd_soc_card, + .codec_dev = &soc_codec_dev_aic3x, + .codec_data = &da830_evm_aic3x_setup, +}; + static struct platform_device *evm_snd_device; static int __init evm_init(void) @@ -222,6 +252,9 @@ static int __init evm_init(void) } else if (machine_is_davinci_dm6467_evm()) { evm_snd_dev_data = &dm6467_evm_snd_devdata; index = 0; + } else if (machine_is_davinci_da830_evm()) { + evm_snd_dev_data = &da830_evm_snd_devdata; + index = 1; } else return -EINVAL; -- cgit v0.10.2 From 35b1207b34975d7ff2ea014171229c02bdb066f1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 8 Aug 2009 10:37:33 +0100 Subject: ASoC: Convert WM8776 to use factored out register cache code Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index ee12bf8..a9829aa 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -52,51 +52,9 @@ static const u16 wm8776_reg[WM8776_CACHEREGNUM] = { 0xa6, 0x01, 0x01 }; -/* - * read wm8776 register cache - */ -static inline unsigned int wm8776_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg >= WM8776_CACHEREGNUM) - return -1; - return cache[reg]; -} - -/* - * write wm8776 register cache - */ -static inline void wm8776_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg >= WM8776_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * write to the WM8776 register space - */ -static int wm8776_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8776_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - static int wm8776_reset(struct snd_soc_codec *codec) { - return wm8776_write(codec, WM8776_RESET, 0); + return snd_soc_write(codec, WM8776_RESET, 0); } static const DECLARE_TLV_DB_SCALE(hp_tlv, -12100, 100, 1); @@ -523,7 +481,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8776 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776); -static int wm8776_register(struct wm8776_priv *wm8776) +static int wm8776_register(struct wm8776_priv *wm8776, + enum snd_soc_control_type control) { int ret, i; struct snd_soc_codec *codec = &wm8776->codec; @@ -541,8 +500,6 @@ static int wm8776_register(struct wm8776_priv *wm8776) codec->private_data = wm8776; codec->name = "WM8776"; codec->owner = THIS_MODULE; - codec->read = wm8776_read_reg_cache; - codec->write = wm8776_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8776_set_bias_level; codec->dai = wm8776_dai; @@ -552,6 +509,12 @@ static int wm8776_register(struct wm8776_priv *wm8776) memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg)); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++) wm8776_dai[i].dev = codec->dev; @@ -641,7 +604,7 @@ static int __devinit wm8776_spi_probe(struct spi_device *spi) dev_set_drvdata(&spi->dev, wm8776); - return wm8776_register(wm8776); + return wm8776_register(wm8776, SND_SOC_SPI); } static int __devexit wm8776_spi_remove(struct spi_device *spi) @@ -700,7 +663,7 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c, codec->dev = &i2c->dev; - return wm8776_register(wm8776); + return wm8776_register(wm8776, SND_SOC_I2C); } static __devexit int wm8776_i2c_remove(struct i2c_client *client) -- cgit v0.10.2 From f3d1915a8623b9248572d3ee44e19a80b7a3520b Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 6 Aug 2009 00:09:31 +0400 Subject: x86, ioapic: Panic on irq-pin binding only if needed Though the most time we are to panic on irq-pin allocation fails, for PCI interrupts it's not the case and we could continue operate even if irq-pin allocation failed. Signed-off-by: Cyrill Gorcunov Cc: Yinghai Lu LKML-Reference: <20090805200931.GB5319@lenovo> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 2a145d3..2999f3d 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -490,7 +490,8 @@ static void ioapic_mask_entry(int apic, int pin) * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */ -static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin) +static int +add_pin_to_irq_node_nopanic(struct irq_cfg *cfg, int node, int apic, int pin) { struct irq_pin_list **last, *entry; @@ -498,19 +499,27 @@ static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin last = &cfg->irq_2_pin; for_each_irq_pin(entry, cfg->irq_2_pin) { if (entry->apic == apic && entry->pin == pin) - return; + return 0; last = &entry->next; } entry = get_one_free_irq_2_pin(node); if (!entry) { - printk(KERN_ERR "can not alloc irq_pin_list\n"); - BUG_ON(1); + printk(KERN_ERR "can not alloc irq_pin_list (%d,%d,%d)\n", + node, apic, pin); + return -ENOMEM; } entry->apic = apic; entry->pin = pin; *last = entry; + return 0; +} + +static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin) +{ + if (add_pin_to_irq_node_nopanic(cfg, node, apic, pin)) + panic("IO-APIC: failed to add irq-pin. Can not proceed\n"); } /* @@ -3843,7 +3852,11 @@ static int __io_apic_set_pci_routing(struct device *dev, int irq, */ if (irq >= NR_IRQS_LEGACY) { cfg = desc->chip_data; - add_pin_to_irq_node(cfg, node, ioapic, pin); + if (add_pin_to_irq_node_nopanic(cfg, node, ioapic, pin)) { + printk(KERN_INFO "can not add pin %d for irq %d\n", + pin, irq); + return 0; + } } setup_IO_APIC_irq(ioapic, pin, irq, desc, trigger, polarity); -- cgit v0.10.2 From 1e5de18278e6862f4198412b5059a03770fa816a Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 19 Jul 2009 00:12:20 +0900 Subject: x86: Introduce GDT_ENTRY_INIT() GDT_ENTRY_INIT is static initializer of desc_struct. We already have similar macro GDT_ENTRY() but it's static initializer for u64 and it cannot be used for desc_struct. Signed-off-by: Akinobu Mita LKML-Reference: <20090718151219.GD11294@localhost.localdomain> Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/desc_defs.h b/arch/x86/include/asm/desc_defs.h index a6adefa..9d66848 100644 --- a/arch/x86/include/asm/desc_defs.h +++ b/arch/x86/include/asm/desc_defs.h @@ -34,6 +34,12 @@ struct desc_struct { }; } __attribute__((packed)); +#define GDT_ENTRY_INIT(flags, base, limit) { { { \ + .a = ((limit) & 0xffff) | (((base) & 0xffff) << 16), \ + .b = (((base) & 0xff0000) >> 16) | (((flags) & 0xf0ff) << 8) | \ + ((limit) & 0xf0000) | ((base) & 0xff000000), \ + } } } + enum { GATE_INTERRUPT = 0xE, GATE_TRAP = 0xF, diff --git a/arch/x86/include/asm/lguest.h b/arch/x86/include/asm/lguest.h index 313389c..94cd698 100644 --- a/arch/x86/include/asm/lguest.h +++ b/arch/x86/include/asm/lguest.h @@ -91,8 +91,9 @@ static inline void lguest_set_ts(void) } /* Full 4G segment descriptors, suitable for CS and DS. */ -#define FULL_EXEC_SEGMENT ((struct desc_struct){ { {0x0000ffff, 0x00cf9b00} } }) -#define FULL_SEGMENT ((struct desc_struct){ { {0x0000ffff, 0x00cf9300} } }) +#define FULL_EXEC_SEGMENT \ + ((struct desc_struct)GDT_ENTRY_INIT(0xc09b, 0, 0xfffff)) +#define FULL_SEGMENT ((struct desc_struct)GDT_ENTRY_INIT(0xc093, 0, 0xfffff)) #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h index cdc5e0b..44efdff 100644 --- a/arch/x86/include/asm/stackprotector.h +++ b/arch/x86/include/asm/stackprotector.h @@ -48,7 +48,7 @@ * head_32 for boot CPU and setup_per_cpu_areas() for others. */ #define GDT_STACK_CANARY_INIT \ - [GDT_ENTRY_STACK_CANARY] = { { { 0x00000018, 0x00409000 } } }, + [GDT_ENTRY_STACK_CANARY] = GDT_ENTRY_INIT(0x4090, 0, 0x18), /* * Initialize the stackprotector canary value. diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index b5e841b..febb2da 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -403,7 +403,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); static struct apm_user *user_list; static DEFINE_SPINLOCK(user_list_lock); -static struct desc_struct bad_bios_desc = { { { 0, 0x00409200 } } }; +static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, 0, 0); static const char driver_version[] = "1.16ac"; /* no spaces */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index f1961c0..8c9bc28 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -71,45 +71,45 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { * TLS descriptors are currently at a different place compared to i386. * Hopefully nobody expects them at a fixed place (Wine?) */ - [GDT_ENTRY_KERNEL32_CS] = { { { 0x0000ffff, 0x00cf9b00 } } }, - [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00af9b00 } } }, - [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9300 } } }, - [GDT_ENTRY_DEFAULT_USER32_CS] = { { { 0x0000ffff, 0x00cffb00 } } }, - [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff300 } } }, - [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00affb00 } } }, + [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff), + [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff), + [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc093, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER32_CS] = GDT_ENTRY_INIT(0xc0fb, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_DS] = GDT_ENTRY_INIT(0xc0f3, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_CS] = GDT_ENTRY_INIT(0xa0fb, 0, 0xfffff), #else - [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00cf9a00 } } }, - [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9200 } } }, - [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00cffa00 } } }, - [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff200 } } }, + [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xc09a, 0, 0xfffff), + [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_CS] = GDT_ENTRY_INIT(0xc0fa, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_DS] = GDT_ENTRY_INIT(0xc0f2, 0, 0xfffff), /* * Segments used for calling PnP BIOS have byte granularity. * They code segments and data segments have fixed 64k limits, * the transfer segment sizes are set at run time. */ /* 32-bit code */ - [GDT_ENTRY_PNPBIOS_CS32] = { { { 0x0000ffff, 0x00409a00 } } }, + [GDT_ENTRY_PNPBIOS_CS32] = GDT_ENTRY_INIT(0x409a, 0, 0xffff), /* 16-bit code */ - [GDT_ENTRY_PNPBIOS_CS16] = { { { 0x0000ffff, 0x00009a00 } } }, + [GDT_ENTRY_PNPBIOS_CS16] = GDT_ENTRY_INIT(0x009a, 0, 0xffff), /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_DS] = { { { 0x0000ffff, 0x00009200 } } }, + [GDT_ENTRY_PNPBIOS_DS] = GDT_ENTRY_INIT(0x0092, 0, 0xffff), /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS1] = { { { 0x00000000, 0x00009200 } } }, + [GDT_ENTRY_PNPBIOS_TS1] = GDT_ENTRY_INIT(0x0092, 0, 0), /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS2] = { { { 0x00000000, 0x00009200 } } }, + [GDT_ENTRY_PNPBIOS_TS2] = GDT_ENTRY_INIT(0x0092, 0, 0), /* * The APM segments have byte granularity and their bases * are set at run time. All have 64k limits. */ /* 32-bit code */ - [GDT_ENTRY_APMBIOS_BASE] = { { { 0x0000ffff, 0x00409a00 } } }, + [GDT_ENTRY_APMBIOS_BASE] = GDT_ENTRY_INIT(0x409a, 0, 0xffff), /* 16-bit code */ - [GDT_ENTRY_APMBIOS_BASE+1] = { { { 0x0000ffff, 0x00009a00 } } }, + [GDT_ENTRY_APMBIOS_BASE+1] = GDT_ENTRY_INIT(0x009a, 0, 0xffff), /* data */ - [GDT_ENTRY_APMBIOS_BASE+2] = { { { 0x0000ffff, 0x00409200 } } }, + [GDT_ENTRY_APMBIOS_BASE+2] = GDT_ENTRY_INIT(0x409a, 0, 0xffff), - [GDT_ENTRY_ESPFIX_SS] = { { { 0x0000ffff, 0x00cf9200 } } }, - [GDT_ENTRY_PERCPU] = { { { 0x0000ffff, 0x00cf9200 } } }, + [GDT_ENTRY_ESPFIX_SS] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), + [GDT_ENTRY_PERCPU] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), GDT_STACK_CANARY_INIT #endif } }; diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index 45ad3e9..bd035e3 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -60,7 +60,7 @@ do { \ set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \ } while(0) -static struct desc_struct bad_bios_desc; +static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, 0, 0); /* * At some point we want to use this stack frame pointer to unwind @@ -476,9 +476,6 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) pnp_bios_callpoint.offset = header->fields.pm16offset; pnp_bios_callpoint.segment = PNP_CS16; - bad_bios_desc.a = 0; - bad_bios_desc.b = 0x00409200; - set_desc_base(&bad_bios_desc, (unsigned long)__va(0x40UL << 4)); set_desc_limit(&bad_bios_desc, 4095 - (0x40 << 4)); for_each_possible_cpu(i) { -- cgit v0.10.2 From 72c4d8530244264317a662de9a55cc47e6c8e9df Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 3 Aug 2009 08:47:07 +0200 Subject: x86: Introduce GDT_ENTRY_INIT(), fix APM This crash: [ 0.891983] calling cache_sysfs_init+0x0/0x1ee @ 1 [ 0.897251] initcall cache_sysfs_init+0x0/0x1ee returned 0 after 405 usecs [ 0.904019] calling mce_init_device+0x0/0x242 @ 1 [ 0.909124] initcall mce_init_device+0x0/0x242 returned 0 after 347 usecs [ 0.915815] calling apm_init+0x0/0x38d @ 1 [ 0.919967] apm: BIOS version 1.2 Flags 0x07 (Driver version 1.16ac) [ 0.926813] general protection fault: 0000 [#1] [ 0.927269] last sysfs file: [ 0.927269] Modules linked in: [ 0.927269] [ 0.927269] Pid: 271, comm: kapmd Not tainted (2.6.31-rc3-00100-gd520da1-dirty #311) System Product Name [ 0.927269] EIP: 00c0:[<000082b2>] EFLAGS: 00010002 CPU: 0 [ 0.927269] EIP is at 0x82b2 [ 0.927269] EAX: 0000530e EBX: 00000000 ECX: 00000102 EDX: 00000000 [ 0.927269] ESI: 00000000 EDI: f6a4bf44 EBP: 67890000 ESP: f6a4beec [ 0.927269] DS: 00c8 ES: 0000 FS: 0000 GS: 0000 SS: 0068 [ 0.927269] Process kapmd (pid: 271, ti=f6a4a000 task=f7142280 task.ti=f6a4a000) [ 0.927269] Stack: [ 0.927269] 0000828d 02160000 00b88092 f6a4bf3c c102a63d 00000060 f6a4bf3c f6a4bf44 [ 0.927269] <0> 0000007b 0000007b 00000000 00000000 00000000 00000000 560aae9e 00000000 [ 0.927269] <0> 00000200 f705fd74 00000000 c102af70 f6a4bf60 c102a6ec 0000530e 00000000 [ 0.927269] Call Trace: [ 0.927269] [] ? __apm_bios_call_simple+0x7d/0x110 [ 0.927269] [] ? apm+0x0/0x6a0 [ 0.927269] [] ? apm_bios_call_simple+0x1c/0x50 [ 0.927269] [] ? apm+0x485/0x6a0 [ 0.927269] [] ? finish_task_switch+0x2a/0xb0 [ 0.927269] [] ? schedule+0x31e/0x480 [ 0.927269] [] ? apm+0x0/0x6a0 [ 0.927269] [] ? apm+0x0/0x6a0 [ 0.927269] [] ? kthread+0x74/0x80 [ 0.927269] [] ? kthread+0x0/0x80 [ 0.927269] [] ? kernel_thread_helper+0x7/0x10 [ 0.927269] Code: Bad EIP value. [ 0.927269] EIP: [<000082b2>] 0x82b2 SS:ESP 0068:f6a4beec [ 0.927269] ---[ end trace a7919e7f17c0a725 ]--- [ 0.927269] Kernel panic - not syncing: Fatal exception [ 0.927269] Pid: 271, comm: kapmd Tainted: G D 2.6.31-rc3-00100-gd520da1-dirty #311 Is caused by an incorrect GDT_ENTRY_INIT() conversion in the apm code, as noticed by hpa. Reported-by: Ingo Molnar Noticed-by: "H. Peter Anvin" Signed-off-by: Akinobu Mita LKML-Reference: <20090808094905.GA2954@localhost.localdomain> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 8c9bc28..b5764a2 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -106,7 +106,7 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { /* 16-bit code */ [GDT_ENTRY_APMBIOS_BASE+1] = GDT_ENTRY_INIT(0x009a, 0, 0xffff), /* data */ - [GDT_ENTRY_APMBIOS_BASE+2] = GDT_ENTRY_INIT(0x409a, 0, 0xffff), + [GDT_ENTRY_APMBIOS_BASE+2] = GDT_ENTRY_INIT(0x4092, 0, 0xffff), [GDT_ENTRY_ESPFIX_SS] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), [GDT_ENTRY_PERCPU] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), -- cgit v0.10.2 From fb82ad719831db58e9baa4c67015aae3fe27e7e3 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sat, 8 Aug 2009 10:49:36 -0500 Subject: tracing/filters: Don't use pred on alloc failure Dan Carpenter sent me a fix to prevent pred from being used if it couldn't be allocated. This updates his patch for the same problem in the tracing tree (which has changed this code quite substantially). Reported-by: Dan Carpenter Signed-off-by: Tom Zanussi Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Li Zefan LKML-Reference: <1249746576.6453.30.camel@tropicana> Signed-off-by: Ingo Molnar The original report: create_logical_pred() could sometimes return NULL. It's a static checker complaining rather than problems at runtime... diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 27c2dbe..490337a 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -1050,6 +1050,8 @@ static int replace_preds(struct event_subsystem *system, pred = create_pred(elt->op, operand1, operand2); add_pred: + if (!pred) + return -ENOMEM; if (call) err = filter_add_pred(ps, call, pred, false); else -- cgit v0.10.2 From 4c711576b90cc36c13b94816a953a8de6a53d03c Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Thu, 6 Aug 2009 15:58:12 -0700 Subject: x86, 32-bit: Use generic sys_pipe() As suggested by Al, it's better to use the generic sys_pipe() for ia32. Signed-off-by: WANG Cong Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index e590261..ba331bf 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -537,7 +537,7 @@ ia32_sys_call_table: .quad sys_mkdir .quad sys_rmdir /* 40 */ .quad sys_dup - .quad sys32_pipe + .quad sys_pipe .quad compat_sys_times .quad quiet_ni_syscall /* old prof syscall holder */ .quad sys_brk /* 45 */ diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c index 085a8c3..9f55271 100644 --- a/arch/x86/ia32/sys_ia32.c +++ b/arch/x86/ia32/sys_ia32.c @@ -189,20 +189,6 @@ asmlinkage long sys32_mprotect(unsigned long start, size_t len, return sys_mprotect(start, len, prot); } -asmlinkage long sys32_pipe(int __user *fd) -{ - int retval; - int fds[2]; - - retval = do_pipe_flags(fds, 0); - if (retval) - goto out; - if (copy_to_user(fd, fds, sizeof(fds))) - retval = -EFAULT; -out: - return retval; -} - asmlinkage long sys32_rt_sigaction(int sig, struct sigaction32 __user *act, struct sigaction32 __user *oact, unsigned int sigsetsize) -- cgit v0.10.2 From 42c2c8c854a716b05882a122632ddcd6dbe108f1 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 6 Aug 2009 15:58:11 -0700 Subject: printk: Fix "printk: Enable the use of more than one CON_BOOT (early console)" Don't return when we find the first bootconsole - it can leave other bootconsoles still installed, and they can be used and cause problems later (if they are in the init section, and eventually released), and cause problems. Make sure we remove all of them. Signed-off-by: Sonic Zhang Signed-off-by: Robin Getz Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar diff --git a/kernel/printk.c b/kernel/printk.c index e0daaf5..e10d193 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -1352,7 +1352,7 @@ static int __init disable_boot_consoles(void) if (con->flags & CON_BOOT) { printk(KERN_INFO "turn off boot console %s%d\n", con->name, con->index); - return unregister_console(con); + unregister_console(con); } } return 0; -- cgit v0.10.2 From c36ba80ea01d0aecb652c26799a912e760ce8981 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 6 Aug 2009 21:46:03 +0200 Subject: irq: Remove superfluous NULL pointer check in check_irq_resend() This takes care of the following entry from Dan's list: kernel/irq/resend.c +73 check_irq_resend(17) warning: variable derefenced before check 'desc->chip' Reported-by: Dan Carpenter Signed-off-by: Bartlomiej Zolnierkiewicz Cc: Jonathan Corbet Cc: Eugene Teo Cc: Julia Lawall LKML-Reference: <200908062146.03638.bzolnier@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 89c7117..090c376 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -70,8 +70,7 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq) if ((status & (IRQ_LEVEL | IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { desc->status = (status & ~IRQ_PENDING) | IRQ_REPLAY; - if (!desc->chip || !desc->chip->retrigger || - !desc->chip->retrigger(irq)) { + if (!desc->chip->retrigger || !desc->chip->retrigger(irq)) { #ifdef CONFIG_HARDIRQS_SW_RESEND /* Set it pending and activate the softirq: */ set_bit(irq, irqs_resend); -- cgit v0.10.2 From 30dd568c912602b7dbd609a45d053e01b13422bb Mon Sep 17 00:00:00 2001 From: Markus Metzger Date: Tue, 21 Jul 2009 15:56:48 +0200 Subject: x86, perf_counter, bts: Add BTS support to perfcounters Implement a performance counter with: attr.type = PERF_TYPE_HARDWARE attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS attr.sample_period = 1 Using branch trace store (BTS) on x86 hardware, if available. The from and to address for each branch can be sampled using: PERF_SAMPLE_IP for the from address PERF_SAMPLE_ADDR for the to address [ v2: address review feedback, fix bugs ] Signed-off-by: Markus Metzger Acked-by: Peter Zijlstra Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/perf_counter.h b/arch/x86/include/asm/perf_counter.h index fa64e40..e7b7c93 100644 --- a/arch/x86/include/asm/perf_counter.h +++ b/arch/x86/include/asm/perf_counter.h @@ -84,6 +84,16 @@ union cpuid10_edx { #define MSR_ARCH_PERFMON_FIXED_CTR2 0x30b #define X86_PMC_IDX_FIXED_BUS_CYCLES (X86_PMC_IDX_FIXED + 2) +/* + * We model BTS tracing as another fixed-mode PMC. + * + * We choose a value in the middle of the fixed counter range, since lower + * values are used by actual fixed counters and higher values are used + * to indicate other overflow conditions in the PERF_GLOBAL_STATUS msr. + */ +#define X86_PMC_IDX_FIXED_BTS (X86_PMC_IDX_FIXED + 16) + + #ifdef CONFIG_PERF_COUNTERS extern void init_hw_perf_counters(void); extern void perf_counters_lapic_init(void); diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c index a7aa8f9..b237c18 100644 --- a/arch/x86/kernel/cpu/perf_counter.c +++ b/arch/x86/kernel/cpu/perf_counter.c @@ -6,6 +6,7 @@ * Copyright (C) 2009 Jaswinder Singh Rajput * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2009 Intel Corporation, * * For licencing details see kernel-base/COPYING */ @@ -20,6 +21,7 @@ #include #include #include +#include #include #include @@ -27,12 +29,52 @@ static u64 perf_counter_mask __read_mostly; +/* The maximal number of PEBS counters: */ +#define MAX_PEBS_COUNTERS 4 + +/* The size of a BTS record in bytes: */ +#define BTS_RECORD_SIZE 24 + +/* The size of a per-cpu BTS buffer in bytes: */ +#define BTS_BUFFER_SIZE (BTS_RECORD_SIZE * 1024) + +/* The BTS overflow threshold in bytes from the end of the buffer: */ +#define BTS_OVFL_TH (BTS_RECORD_SIZE * 64) + + +/* + * Bits in the debugctlmsr controlling branch tracing. + */ +#define X86_DEBUGCTL_TR (1 << 6) +#define X86_DEBUGCTL_BTS (1 << 7) +#define X86_DEBUGCTL_BTINT (1 << 8) +#define X86_DEBUGCTL_BTS_OFF_OS (1 << 9) +#define X86_DEBUGCTL_BTS_OFF_USR (1 << 10) + +/* + * A debug store configuration. + * + * We only support architectures that use 64bit fields. + */ +struct debug_store { + u64 bts_buffer_base; + u64 bts_index; + u64 bts_absolute_maximum; + u64 bts_interrupt_threshold; + u64 pebs_buffer_base; + u64 pebs_index; + u64 pebs_absolute_maximum; + u64 pebs_interrupt_threshold; + u64 pebs_counter_reset[MAX_PEBS_COUNTERS]; +}; + struct cpu_hw_counters { struct perf_counter *counters[X86_PMC_IDX_MAX]; unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; unsigned long active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; unsigned long interrupts; int enabled; + struct debug_store *ds; }; /* @@ -57,6 +99,8 @@ struct x86_pmu { u64 counter_mask; u64 max_period; u64 intel_ctrl; + void (*enable_bts)(u64 config); + void (*disable_bts)(void); }; static struct x86_pmu x86_pmu __read_mostly; @@ -576,6 +620,9 @@ x86_perf_counter_update(struct perf_counter *counter, u64 prev_raw_count, new_raw_count; s64 delta; + if (idx == X86_PMC_IDX_FIXED_BTS) + return 0; + /* * Careful: an NMI might modify the previous counter value. * @@ -659,10 +706,109 @@ static void release_pmc_hardware(void) enable_lapic_nmi_watchdog(); } +static inline bool bts_available(void) +{ + return x86_pmu.enable_bts != NULL; +} + +static inline void init_debug_store_on_cpu(int cpu) +{ + struct debug_store *ds = per_cpu(cpu_hw_counters, cpu).ds; + + if (!ds) + return; + + wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, + (u32)((u64)(long)ds), (u32)((u64)(long)ds >> 32)); +} + +static inline void fini_debug_store_on_cpu(int cpu) +{ + if (!per_cpu(cpu_hw_counters, cpu).ds) + return; + + wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0); +} + +static void release_bts_hardware(void) +{ + int cpu; + + if (!bts_available()) + return; + + get_online_cpus(); + + for_each_online_cpu(cpu) + fini_debug_store_on_cpu(cpu); + + for_each_possible_cpu(cpu) { + struct debug_store *ds = per_cpu(cpu_hw_counters, cpu).ds; + + if (!ds) + continue; + + per_cpu(cpu_hw_counters, cpu).ds = NULL; + + kfree((void *)(long)ds->bts_buffer_base); + kfree(ds); + } + + put_online_cpus(); +} + +static int reserve_bts_hardware(void) +{ + int cpu, err = 0; + + if (!bts_available()) + return -EOPNOTSUPP; + + get_online_cpus(); + + for_each_possible_cpu(cpu) { + struct debug_store *ds; + void *buffer; + + err = -ENOMEM; + buffer = kzalloc(BTS_BUFFER_SIZE, GFP_KERNEL); + if (unlikely(!buffer)) + break; + + ds = kzalloc(sizeof(*ds), GFP_KERNEL); + if (unlikely(!ds)) { + kfree(buffer); + break; + } + + ds->bts_buffer_base = (u64)(long)buffer; + ds->bts_index = ds->bts_buffer_base; + ds->bts_absolute_maximum = + ds->bts_buffer_base + BTS_BUFFER_SIZE; + ds->bts_interrupt_threshold = + ds->bts_absolute_maximum - BTS_OVFL_TH; + + per_cpu(cpu_hw_counters, cpu).ds = ds; + err = 0; + } + + if (err) + release_bts_hardware(); + else { + for_each_online_cpu(cpu) + init_debug_store_on_cpu(cpu); + } + + put_online_cpus(); + + return err; +} + static void hw_perf_counter_destroy(struct perf_counter *counter) { if (atomic_dec_and_mutex_lock(&active_counters, &pmc_reserve_mutex)) { release_pmc_hardware(); + release_bts_hardware(); mutex_unlock(&pmc_reserve_mutex); } } @@ -705,6 +851,42 @@ set_ext_hw_attr(struct hw_perf_counter *hwc, struct perf_counter_attr *attr) return 0; } +static void intel_pmu_enable_bts(u64 config) +{ + unsigned long debugctlmsr; + + debugctlmsr = get_debugctlmsr(); + + debugctlmsr |= X86_DEBUGCTL_TR; + debugctlmsr |= X86_DEBUGCTL_BTS; + debugctlmsr |= X86_DEBUGCTL_BTINT; + + if (!(config & ARCH_PERFMON_EVENTSEL_OS)) + debugctlmsr |= X86_DEBUGCTL_BTS_OFF_OS; + + if (!(config & ARCH_PERFMON_EVENTSEL_USR)) + debugctlmsr |= X86_DEBUGCTL_BTS_OFF_USR; + + update_debugctlmsr(debugctlmsr); +} + +static void intel_pmu_disable_bts(void) +{ + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + unsigned long debugctlmsr; + + if (!cpuc->ds) + return; + + debugctlmsr = get_debugctlmsr(); + + debugctlmsr &= + ~(X86_DEBUGCTL_TR | X86_DEBUGCTL_BTS | X86_DEBUGCTL_BTINT | + X86_DEBUGCTL_BTS_OFF_OS | X86_DEBUGCTL_BTS_OFF_USR); + + update_debugctlmsr(debugctlmsr); +} + /* * Setup the hardware configuration for a given attr_type */ @@ -721,9 +903,13 @@ static int __hw_perf_counter_init(struct perf_counter *counter) err = 0; if (!atomic_inc_not_zero(&active_counters)) { mutex_lock(&pmc_reserve_mutex); - if (atomic_read(&active_counters) == 0 && !reserve_pmc_hardware()) - err = -EBUSY; - else + if (atomic_read(&active_counters) == 0) { + if (!reserve_pmc_hardware()) + err = -EBUSY; + else + reserve_bts_hardware(); + } + if (!err) atomic_inc(&active_counters); mutex_unlock(&pmc_reserve_mutex); } @@ -801,7 +987,18 @@ static void p6_pmu_disable_all(void) static void intel_pmu_disable_all(void) { + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + + if (!cpuc->enabled) + return; + + cpuc->enabled = 0; + barrier(); + wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0); + + if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask)) + intel_pmu_disable_bts(); } static void amd_pmu_disable_all(void) @@ -859,7 +1056,25 @@ static void p6_pmu_enable_all(void) static void intel_pmu_enable_all(void) { + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + + if (cpuc->enabled) + return; + + cpuc->enabled = 1; + barrier(); + wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl); + + if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask)) { + struct perf_counter *counter = + cpuc->counters[X86_PMC_IDX_FIXED_BTS]; + + if (WARN_ON_ONCE(!counter)) + return; + + intel_pmu_enable_bts(counter->hw.config); + } } static void amd_pmu_enable_all(void) @@ -946,6 +1161,11 @@ p6_pmu_disable_counter(struct hw_perf_counter *hwc, int idx) static inline void intel_pmu_disable_counter(struct hw_perf_counter *hwc, int idx) { + if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) { + intel_pmu_disable_bts(); + return; + } + if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) { intel_pmu_disable_fixed(hwc, idx); return; @@ -974,6 +1194,9 @@ x86_perf_counter_set_period(struct perf_counter *counter, s64 period = hwc->sample_period; int err, ret = 0; + if (idx == X86_PMC_IDX_FIXED_BTS) + return 0; + /* * If we are way outside a reasoable range then just skip forward: */ @@ -1056,6 +1279,14 @@ static void p6_pmu_enable_counter(struct hw_perf_counter *hwc, int idx) static void intel_pmu_enable_counter(struct hw_perf_counter *hwc, int idx) { + if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) { + if (!__get_cpu_var(cpu_hw_counters).enabled) + return; + + intel_pmu_enable_bts(hwc->config); + return; + } + if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) { intel_pmu_enable_fixed(hwc, idx); return; @@ -1077,11 +1308,16 @@ fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc) { unsigned int event; + event = hwc->config & ARCH_PERFMON_EVENT_MASK; + + if (unlikely((event == + x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) && + (hwc->sample_period == 1))) + return X86_PMC_IDX_FIXED_BTS; + if (!x86_pmu.num_counters_fixed) return -1; - event = hwc->config & ARCH_PERFMON_EVENT_MASK; - if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS))) return X86_PMC_IDX_FIXED_INSTRUCTIONS; if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES))) @@ -1102,7 +1338,25 @@ static int x86_pmu_enable(struct perf_counter *counter) int idx; idx = fixed_mode_idx(counter, hwc); - if (idx >= 0) { + if (idx == X86_PMC_IDX_FIXED_BTS) { + /* + * Try to use BTS for branch tracing. If that is not + * available, try to get a generic counter. + */ + if (unlikely(!cpuc->ds)) + goto try_generic; + + /* + * Try to get the fixed counter, if that is already taken + * then try to get a generic counter: + */ + if (test_and_set_bit(idx, cpuc->used_mask)) + goto try_generic; + + hwc->config_base = 0; + hwc->counter_base = 0; + hwc->idx = idx; + } else if (idx >= 0) { /* * Try to get the fixed counter, if that is already taken * then try to get a generic counter: @@ -1213,6 +1467,45 @@ void perf_counter_print_debug(void) local_irq_restore(flags); } +static void intel_pmu_drain_bts_buffer(struct cpu_hw_counters *cpuc, + struct perf_sample_data *data) +{ + struct debug_store *ds = cpuc->ds; + struct bts_record { + u64 from; + u64 to; + u64 flags; + }; + struct perf_counter *counter = cpuc->counters[X86_PMC_IDX_FIXED_BTS]; + unsigned long orig_ip = data->regs->ip; + u64 at; + + if (!counter) + return; + + if (!ds) + return; + + for (at = ds->bts_buffer_base; + at < ds->bts_index; + at += sizeof(struct bts_record)) { + struct bts_record *rec = (struct bts_record *)(long)at; + + data->regs->ip = rec->from; + data->addr = rec->to; + + perf_counter_output(counter, 1, data); + } + + ds->bts_index = ds->bts_buffer_base; + + data->regs->ip = orig_ip; + data->addr = 0; + + /* There's new data available. */ + counter->pending_kill = POLL_IN; +} + static void x86_pmu_disable(struct perf_counter *counter) { struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); @@ -1237,6 +1530,15 @@ static void x86_pmu_disable(struct perf_counter *counter) * that we are disabling: */ x86_perf_counter_update(counter, hwc, idx); + + /* Drain the remaining BTS records. */ + if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) { + struct perf_sample_data data; + struct pt_regs regs; + + data.regs = ®s; + intel_pmu_drain_bts_buffer(cpuc, &data); + } cpuc->counters[idx] = NULL; clear_bit(idx, cpuc->used_mask); @@ -1264,6 +1566,7 @@ static int intel_pmu_save_and_restart(struct perf_counter *counter) static void intel_pmu_reset(void) { + struct debug_store *ds = __get_cpu_var(cpu_hw_counters).ds; unsigned long flags; int idx; @@ -1281,6 +1584,8 @@ static void intel_pmu_reset(void) for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) { checking_wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull); } + if (ds) + ds->bts_index = ds->bts_buffer_base; local_irq_restore(flags); } @@ -1346,6 +1651,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) cpuc = &__get_cpu_var(cpu_hw_counters); perf_disable(); + intel_pmu_drain_bts_buffer(cpuc, &data); status = intel_pmu_get_status(); if (!status) { perf_enable(); @@ -1547,6 +1853,8 @@ static struct x86_pmu intel_pmu = { * the generic counter period: */ .max_period = (1ULL << 31) - 1, + .enable_bts = intel_pmu_enable_bts, + .disable_bts = intel_pmu_disable_bts, }; static struct x86_pmu amd_pmu = { @@ -1936,3 +2244,8 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) return entry; } + +void hw_perf_counter_setup_online(int cpu) +{ + init_debug_store_on_cpu(cpu); +} diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index 2aabe43..0a6f320 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h @@ -692,6 +692,8 @@ struct perf_sample_data { extern int perf_counter_overflow(struct perf_counter *counter, int nmi, struct perf_sample_data *data); +extern void perf_counter_output(struct perf_counter *counter, int nmi, + struct perf_sample_data *data); /* * Return 1 for a software counter, 0 for a hardware counter diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 546e62d..bf8110b 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -88,6 +88,7 @@ void __weak hw_perf_disable(void) { barrier(); } void __weak hw_perf_enable(void) { barrier(); } void __weak hw_perf_counter_setup(int cpu) { barrier(); } +void __weak hw_perf_counter_setup_online(int cpu) { barrier(); } int __weak hw_perf_group_sched_in(struct perf_counter *group_leader, @@ -2630,7 +2631,7 @@ static u32 perf_counter_tid(struct perf_counter *counter, struct task_struct *p) return task_pid_nr_ns(p, counter->ns); } -static void perf_counter_output(struct perf_counter *counter, int nmi, +void perf_counter_output(struct perf_counter *counter, int nmi, struct perf_sample_data *data) { int ret; @@ -4566,6 +4567,11 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) perf_counter_init_cpu(cpu); break; + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + hw_perf_counter_setup_online(cpu); + break; + case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: perf_counter_exit_cpu(cpu); @@ -4590,6 +4596,8 @@ void __init perf_counter_init(void) { perf_cpu_notify(&perf_cpu_nb, (unsigned long)CPU_UP_PREPARE, (void *)(long)smp_processor_id()); + perf_cpu_notify(&perf_cpu_nb, (unsigned long)CPU_ONLINE, + (void *)(long)smp_processor_id()); register_cpu_notifier(&perf_cpu_nb); } -- cgit v0.10.2 From 8d51327090ac025d7f4ce6c059786b5e93513321 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Fri, 7 Aug 2009 13:55:24 +0200 Subject: perf report: Fix and improve the displaying of per-thread event counters Improve and fix the handling of per-thread counter stats recorded via perf record -s. Previously we only displayed it in debug printouts (-D) and even that output was hard to disambiguate. I moved everything to utils/values.[ch] so that we may reuse it in perf stat. We get something like this now: # PID TID cache-misses cache-references 4658 4659 495581 3238779 4658 4662 498246 3236823 4658 4663 499531 3243162 Then it'll be easy to add --pretty=raw to display a single line per thread/event. By the way, -S was also used for --symbol... So I used -T/--thread here. perf report: Add -T/--threads to display per-thread counter values We get something like this now: # PID TID cache-misses cache-references 4658 4659 495581 3238779 4658 4662 498246 3236823 4658 4663 499531 3243162 Per-thread arrays of counter values are managed in utils/values.[ch] Signed-off-by: Brice Goglin Cc: Peter Zijlstra Cc: paulus@samba.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index e72e931..370344a 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -27,6 +27,9 @@ OPTIONS -n --show-nr-samples Show the number of samples for each symbol +-T +--threads + Show per-thread event counters -C:: --comms=:: Only consider symbols in these comms. CSV that understands diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 60411e9..de7beac 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -310,6 +310,7 @@ LIB_H += util/sigchain.h LIB_H += util/symbol.h LIB_H += util/module.h LIB_H += util/color.h +LIB_H += util/values.h LIB_OBJS += util/abspath.o LIB_OBJS += util/alias.o @@ -337,6 +338,7 @@ LIB_OBJS += util/color.o LIB_OBJS += util/pager.o LIB_OBJS += util/header.o LIB_OBJS += util/callchain.o +LIB_OBJS += util/values.o BUILTIN_OBJS += builtin-annotate.o BUILTIN_OBJS += builtin-help.o diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 99274ce..4163918 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -17,6 +17,7 @@ #include "util/string.h" #include "util/callchain.h" #include "util/strlist.h" +#include "util/values.h" #include "perf.h" #include "util/header.h" @@ -53,6 +54,9 @@ static int modules; static int full_paths; static int show_nr_samples; +static int show_threads; +static struct perf_read_values show_threads_values; + static unsigned long page_size; static unsigned long mmap_window = 32; @@ -1473,6 +1477,9 @@ print_entries: free(rem_sq_bracket); + if (show_threads) + perf_read_values_display(fp, &show_threads_values); + return ret; } @@ -1758,6 +1765,16 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head) { struct perf_counter_attr *attr = perf_header__find_attr(event->read.id); + if (show_threads) { + char *name = attr ? __event_name(attr->type, attr->config) + : "unknown"; + perf_read_values_add_value(&show_threads_values, + event->read.pid, event->read.tid, + event->read.id, + name, + event->read.value); + } + dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -1839,6 +1856,9 @@ static int __cmd_report(void) register_idle_thread(); + if (show_threads) + perf_read_values_init(&show_threads_values); + input = open(input_name, O_RDONLY); if (input < 0) { fprintf(stderr, " failed to open file: %s", input_name); @@ -1993,6 +2013,9 @@ done: output__resort(total); output__fprintf(stdout, total); + if (show_threads) + perf_read_values_destroy(&show_threads_values); + return rc; } @@ -2066,6 +2089,8 @@ static const struct option options[] = { "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, "Show a column with the number of samples"), + OPT_BOOLEAN('T', "threads", &show_threads, + "Show per-thread event counters"), OPT_STRING('s', "sort", &sort_order, "key[,key2...]", "sort by key(s): pid, comm, dso, symbol, parent"), OPT_BOOLEAN('P', "full-paths", &full_paths, diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c new file mode 100644 index 0000000..8551c0b --- /dev/null +++ b/tools/perf/util/values.c @@ -0,0 +1,171 @@ +#include + +#include "util.h" +#include "values.h" + +void perf_read_values_init(struct perf_read_values *values) +{ + values->threads_max = 16; + values->pid = malloc(values->threads_max * sizeof(*values->pid)); + values->tid = malloc(values->threads_max * sizeof(*values->tid)); + values->value = malloc(values->threads_max * sizeof(*values->value)); + if (!values->pid || !values->tid || !values->value) + die("failed to allocate read_values threads arrays"); + values->threads = 0; + + values->counters_max = 16; + values->counterrawid = malloc(values->counters_max + * sizeof(*values->counterrawid)); + values->countername = malloc(values->counters_max + * sizeof(*values->countername)); + if (!values->counterrawid || !values->countername) + die("failed to allocate read_values counters arrays"); + values->counters = 0; +} + +void perf_read_values_destroy(struct perf_read_values *values) +{ + int i; + + if (!values->threads_max || !values->counters_max) + return; + + for (i = 0; i < values->threads; i++) + free(values->value[i]); + free(values->pid); + free(values->tid); + free(values->counterrawid); + for (i = 0; i < values->counters; i++) + free(values->countername[i]); + free(values->countername); +} + +static void perf_read_values__enlarge_threads(struct perf_read_values *values) +{ + values->threads_max *= 2; + values->pid = realloc(values->pid, + values->threads_max * sizeof(*values->pid)); + values->tid = realloc(values->tid, + values->threads_max * sizeof(*values->tid)); + values->value = realloc(values->value, + values->threads_max * sizeof(*values->value)); + if (!values->pid || !values->tid || !values->value) + die("failed to enlarge read_values threads arrays"); +} + +static int perf_read_values__findnew_thread(struct perf_read_values *values, + u32 pid, u32 tid) +{ + int i; + + for (i = 0; i < values->threads; i++) + if (values->pid[i] == pid && values->tid[i] == tid) + return i; + + if (values->threads == values->threads_max) + perf_read_values__enlarge_threads(values); + + i = values->threads++; + values->pid[i] = pid; + values->tid[i] = tid; + values->value[i] = malloc(values->counters_max * sizeof(**values->value)); + if (!values->value[i]) + die("failed to allocate read_values counters array"); + + return i; +} + +static void perf_read_values__enlarge_counters(struct perf_read_values *values) +{ + int i; + + values->counters_max *= 2; + values->counterrawid = realloc(values->counterrawid, + values->counters_max * sizeof(*values->counterrawid)); + values->countername = realloc(values->countername, + values->counters_max * sizeof(*values->countername)); + if (!values->counterrawid || !values->countername) + die("failed to enlarge read_values counters arrays"); + + for (i = 0; i < values->threads; i++) { + values->value[i] = realloc(values->value[i], + values->counters_max * sizeof(**values->value)); + if (!values->value[i]) + die("failed to enlarge read_values counters arrays"); + } +} + +static int perf_read_values__findnew_counter(struct perf_read_values *values, + u64 rawid, char *name) +{ + int i; + + for (i = 0; i < values->counters; i++) + if (values->counterrawid[i] == rawid) + return i; + + if (values->counters == values->counters_max) + perf_read_values__enlarge_counters(values); + + i = values->counters++; + values->counterrawid[i] = rawid; + values->countername[i] = strdup(name); + + return i; +} + +void perf_read_values_add_value(struct perf_read_values *values, + u32 pid, u32 tid, + u64 rawid, char *name, u64 value) +{ + int tindex, cindex; + + tindex = perf_read_values__findnew_thread(values, pid, tid); + cindex = perf_read_values__findnew_counter(values, rawid, name); + + values->value[tindex][cindex] = value; +} + +void perf_read_values_display(FILE *fp, struct perf_read_values *values) +{ + int i, j; + int pidwidth, tidwidth; + int *counterwidth; + + counterwidth = malloc(values->counters * sizeof(*counterwidth)); + if (!counterwidth) + die("failed to allocate counterwidth array"); + tidwidth = 3; + pidwidth = 3; + for (j = 0; j < values->counters; j++) + counterwidth[j] = strlen(values->countername[j]); + for (i = 0; i < values->threads; i++) { + int width; + + width = snprintf(NULL, 0, "%d", values->pid[i]); + if (width > pidwidth) + pidwidth = width; + width = snprintf(NULL, 0, "%d", values->tid[i]); + if (width > tidwidth) + tidwidth = width; + for (j = 0; j < values->counters; j++) { + width = snprintf(NULL, 0, "%Lu", values->value[i][j]); + if (width > counterwidth[j]) + counterwidth[j] = width; + } + } + + fprintf(fp, "# %*s %*s", pidwidth, "PID", tidwidth, "TID"); + for (j = 0; j < values->counters; j++) + fprintf(fp, " %*s", counterwidth[j], values->countername[j]); + fprintf(fp, "\n"); + + for (i = 0; i < values->threads; i++) { + fprintf(fp, " %*d %*d", pidwidth, values->pid[i], + tidwidth, values->tid[i]); + for (j = 0; j < values->counters; j++) + fprintf(fp, " %*Lu", + counterwidth[j], values->value[i][j]); + fprintf(fp, "\n"); + } +} diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h new file mode 100644 index 0000000..e41be5e --- /dev/null +++ b/tools/perf/util/values.h @@ -0,0 +1,26 @@ +#ifndef _PERF_VALUES_H +#define _PERF_VALUES_H + +#include "types.h" + +struct perf_read_values { + int threads; + int threads_max; + u32 *pid, *tid; + int counters; + int counters_max; + u64 *counterrawid; + char **countername; + u64 **value; +}; + +void perf_read_values_init(struct perf_read_values *values); +void perf_read_values_destroy(struct perf_read_values *values); + +void perf_read_values_add_value(struct perf_read_values *values, + u32 pid, u32 tid, + u64 rawid, char *name, u64 value); + +void perf_read_values_display(FILE *fp, struct perf_read_values *values); + +#endif /* _PERF_VALUES_H */ -- cgit v0.10.2 From 8e5b59a2d728e6963b35dba8bb36e0b70267462e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 6 Aug 2009 16:02:50 -0700 Subject: sched: Add default defines for PREEMPT_ACTIVE The PREEMPT_ACTIVE setting doesn't actually need to be arch-specific, so set up a sane default for all arches to (hopefully) migrate to. > if we look at linux/hardirq.h, it makes this claim: > * - bit 28 is the PREEMPT_ACTIVE flag > if that's true, then why are we letting any arch set this define ? a > quick survey shows that half the arches (11) are using 0x10000000 (bit > 28) while the other half (10) are using 0x4000000 (bit 26). and then > there is the ia64 oddity which uses bit 30. the exact value here > shouldnt really matter across arches though should it ? actually alpha, arm and avr32 also use bit 30 (0x40000000), there are only five (or eight, depending on how you count) architectures (blackfin, h8300, m68k, s390 and sparc) using bit 26. Signed-off-by: Arnd Bergmann Signed-off-by: Mike Frysinger Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 8246c69..0d885fd 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -64,6 +64,12 @@ #define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT) #define NMI_OFFSET (1UL << NMI_SHIFT) +#ifndef PREEMPT_ACTIVE +#define PREEMPT_ACTIVE_BITS 1 +#define PREEMPT_ACTIVE_SHIFT (NMI_SHIFT + NMI_BITS) +#define PREEMPT_ACTIVE (__IRQ_MASK(PREEMPT_ACTIVE_BITS) << PREEMPT_ACTIVE_SHIFT) +#endif + #if PREEMPT_ACTIVE < (1 << (NMI_SHIFT + NMI_BITS)) #error PREEMPT_ACTIVE is too low! #endif -- cgit v0.10.2 From dd8ac1da4190139de70da18823ff8f5992a649ae Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sun, 9 Aug 2009 15:06:19 -0400 Subject: nfs: Keep index within mnt_errtbl[] Ensure that index i remains within array mnt_errtbl[] and mnt3_errtbl[]. Signed-off-by: Roel Kluin Signed-off-by: Trond Myklebust diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 38ef9ea..8b9affc 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -258,7 +258,7 @@ static int decode_status(struct xdr_stream *xdr, struct mountres *res) return -EIO; status = ntohl(*p); - for (i = 0; i <= ARRAY_SIZE(mnt_errtbl); i++) { + for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) { if (mnt_errtbl[i].status == status) { res->errno = mnt_errtbl[i].errno; return 0; @@ -309,7 +309,7 @@ static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res) return -EIO; status = ntohl(*p); - for (i = 0; i <= ARRAY_SIZE(mnt3_errtbl); i++) { + for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) { if (mnt3_errtbl[i].status == status) { res->errno = mnt3_errtbl[i].errno; return 0; -- cgit v0.10.2 From a78cb57a106fceeba26da2907db9d8886700e1dc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:06:19 -0400 Subject: NFSv4: Don't loop forever on state recovery failure... If the server is broken, then retrying forever won't fix it. We should just give up after a while, and return an error to the user. We set the number of retries to 10 for now... Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6917311..d95f7f9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -61,6 +61,8 @@ #define NFS4_POLL_RETRY_MIN (HZ/10) #define NFS4_POLL_RETRY_MAX (15*HZ) +#define NFS4_MAX_LOOP_ON_RECOVER (10) + struct nfs4_opendata; static int _nfs4_proc_open(struct nfs4_opendata *data); static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); @@ -426,17 +428,19 @@ out: static int nfs4_recover_session(struct nfs4_session *session) { struct nfs_client *clp = session->clp; + unsigned int loop; int ret; - for (;;) { + for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) { ret = nfs4_wait_clnt_recover(clp); if (ret != 0) - return ret; + break; if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) break; nfs4_schedule_state_manager(clp); + ret = -EIO; } - return 0; + return ret; } static int nfs41_setup_sequence(struct nfs4_session *session, @@ -1444,18 +1448,20 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) static int nfs4_recover_expired_lease(struct nfs_server *server) { struct nfs_client *clp = server->nfs_client; + unsigned int loop; int ret; - for (;;) { + for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) { ret = nfs4_wait_clnt_recover(clp); if (ret != 0) - return ret; + break; if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state)) break; nfs4_schedule_state_recovery(clp); + ret = -EIO; } - return 0; + return ret; } /* -- cgit v0.10.2 From 62ab460cf5e450e1d207a98a9c6cf2e4a6a78fd1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:06:19 -0400 Subject: NFSv4: Add 'server capability' flags for NFSv4 recommended attributes If the NFSv4 server doesn't support a POSIX attribute, the generic NFS code needs to know that, so that it don't keep trying to poll for it. However, by the same count, if the NFSv4 server does support that attribute, then we should ensure that the inode metadata is appropriately labelled as being untrusted. For instance, if we don't know the correct value of the file's uid, we should certainly not be caching ACLs or ACCESS results. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 8d25ccb..8f34fd8 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -809,6 +809,9 @@ static int nfs_init_server(struct nfs_server *server, /* Initialise the client representation from the mount data */ server->flags = data->flags; server->options = data->options; + server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID| + NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP| + NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME; if (data->rsize) server->rsize = nfs_block_size(data->rsize, NULL); @@ -1274,7 +1277,7 @@ static int nfs4_init_server(struct nfs_server *server, /* Initialise the client representation from the mount data */ server->flags = data->flags; - server->caps |= NFS_CAP_ATOMIC_OPEN; + server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; server->options = data->options; /* Get a client record */ @@ -1400,7 +1403,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, /* Initialise the client representation from the parent server */ nfs_server_copy_userdata(server, parent_server); - server->caps |= NFS_CAP_ATOMIC_OPEN; + server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; /* Get a client representation. * Note: NFSv4 always uses TCP, */ diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index bd7938e..fe5a8b4 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -286,6 +286,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) /* We can't support update_atime(), since the server will reset it */ inode->i_flags |= S_NOATIME|S_NOCMTIME; inode->i_mode = fattr->mode; + if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0 + && nfs_server_capable(inode, NFS_CAP_MODE)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL; /* Why so? Because we want revalidate for devices/FIFOs, and * that's precisely what we have in nfs_file_inode_operations. */ @@ -330,20 +335,46 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) nfsi->attr_gencount = fattr->gencount; if (fattr->valid & NFS_ATTR_FATTR_ATIME) inode->i_atime = fattr->atime; + else if (nfs_server_capable(inode, NFS_CAP_ATIME)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR; if (fattr->valid & NFS_ATTR_FATTR_MTIME) inode->i_mtime = fattr->mtime; + else if (nfs_server_capable(inode, NFS_CAP_MTIME)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_DATA; if (fattr->valid & NFS_ATTR_FATTR_CTIME) inode->i_ctime = fattr->ctime; + else if (nfs_server_capable(inode, NFS_CAP_CTIME)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL; if (fattr->valid & NFS_ATTR_FATTR_CHANGE) nfsi->change_attr = fattr->change_attr; + else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_DATA; if (fattr->valid & NFS_ATTR_FATTR_SIZE) inode->i_size = nfs_size_to_loff_t(fattr->size); + else + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_DATA + | NFS_INO_REVAL_PAGECACHE; if (fattr->valid & NFS_ATTR_FATTR_NLINK) inode->i_nlink = fattr->nlink; + else if (nfs_server_capable(inode, NFS_CAP_NLINK)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR; if (fattr->valid & NFS_ATTR_FATTR_OWNER) inode->i_uid = fattr->uid; + else if (nfs_server_capable(inode, NFS_CAP_OWNER)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL; if (fattr->valid & NFS_ATTR_FATTR_GROUP) inode->i_gid = fattr->gid; + else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP)) + nfsi->cache_validity |= NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL; if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) inode->i_blocks = fattr->du.nfs2.blocks; if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { @@ -1145,6 +1176,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) loff_t cur_isize, new_isize; unsigned long invalid = 0; unsigned long now = jiffies; + unsigned long save_cache_validity; dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", __func__, inode->i_sb->s_id, inode->i_ino, @@ -1171,10 +1203,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) */ nfsi->read_cache_jiffies = fattr->time_start; - if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) || (fattr->valid & (NFS_ATTR_FATTR_MTIME|NFS_ATTR_FATTR_CTIME))) - nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR - | NFS_INO_INVALID_ATIME - | NFS_INO_REVAL_PAGECACHE); + save_cache_validity = nfsi->cache_validity; + nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ATIME + | NFS_INO_REVAL_FORCED + | NFS_INO_REVAL_PAGECACHE); /* Do atomic weak cache consistency updates */ nfs_wcc_update_inode(inode, fattr); @@ -1189,7 +1222,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) nfs_force_lookup_revalidate(inode); nfsi->change_attr = fattr->change_attr; } - } + } else if (server->caps & NFS_CAP_CHANGE_ATTR) + invalid |= save_cache_validity; if (fattr->valid & NFS_ATTR_FATTR_MTIME) { /* NFSv2/v3: Check if the mtime agrees */ @@ -1201,7 +1235,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) nfs_force_lookup_revalidate(inode); memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); } - } + } else if (server->caps & NFS_CAP_MTIME) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_DATA + | NFS_INO_REVAL_PAGECACHE + | NFS_INO_REVAL_FORCED); + if (fattr->valid & NFS_ATTR_FATTR_CTIME) { /* If ctime has changed we should definitely clear access+acl caches */ if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { @@ -1215,7 +1254,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) } memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); } - } + } else if (server->caps & NFS_CAP_CTIME) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL + | NFS_INO_REVAL_FORCED); /* Check if our cached file size is stale */ if (fattr->valid & NFS_ATTR_FATTR_SIZE) { @@ -1231,30 +1274,50 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) dprintk("NFS: isize change on server for file %s/%ld\n", inode->i_sb->s_id, inode->i_ino); } - } + } else + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_REVAL_PAGECACHE + | NFS_INO_REVAL_FORCED); if (fattr->valid & NFS_ATTR_FATTR_ATIME) memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); + else if (server->caps & NFS_CAP_ATIME) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATIME + | NFS_INO_REVAL_FORCED); if (fattr->valid & NFS_ATTR_FATTR_MODE) { if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; inode->i_mode = fattr->mode; } - } + } else if (server->caps & NFS_CAP_MODE) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL + | NFS_INO_REVAL_FORCED); + if (fattr->valid & NFS_ATTR_FATTR_OWNER) { if (inode->i_uid != fattr->uid) { invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; inode->i_uid = fattr->uid; } - } + } else if (server->caps & NFS_CAP_OWNER) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL + | NFS_INO_REVAL_FORCED); + if (fattr->valid & NFS_ATTR_FATTR_GROUP) { if (inode->i_gid != fattr->gid) { invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; inode->i_gid = fattr->gid; } - } + } else if (server->caps & NFS_CAP_OWNER_GROUP) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_INVALID_ACCESS + | NFS_INO_INVALID_ACL + | NFS_INO_REVAL_FORCED); if (fattr->valid & NFS_ATTR_FATTR_NLINK) { if (inode->i_nlink != fattr->nlink) { @@ -1263,7 +1326,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) invalid |= NFS_INO_INVALID_DATA; inode->i_nlink = fattr->nlink; } - } + } else if (server->caps & NFS_CAP_NLINK) + invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR + | NFS_INO_REVAL_FORCED); if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { /* @@ -1293,9 +1358,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) || S_ISLNK(inode->i_mode))) invalid &= ~NFS_INO_INVALID_DATA; if (!nfs_have_delegation(inode, FMODE_READ) || - (nfsi->cache_validity & NFS_INO_REVAL_FORCED)) + (save_cache_validity & NFS_INO_REVAL_FORCED)) nfsi->cache_validity |= invalid; - nfsi->cache_validity &= ~NFS_INO_REVAL_FORCED; return 0; out_changed: diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d95f7f9..be6544a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2003,12 +2003,34 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f status = nfs4_call_sync(server, &msg, &args, &res, 0); if (status == 0) { memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); + server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS| + NFS_CAP_SYMLINKS|NFS_CAP_FILEID| + NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER| + NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME| + NFS_CAP_CTIME|NFS_CAP_MTIME); if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) server->caps |= NFS_CAP_ACLS; if (res.has_links != 0) server->caps |= NFS_CAP_HARDLINKS; if (res.has_symlinks != 0) server->caps |= NFS_CAP_SYMLINKS; + if (res.attr_bitmask[0] & FATTR4_WORD0_FILEID) + server->caps |= NFS_CAP_FILEID; + if (res.attr_bitmask[1] & FATTR4_WORD1_MODE) + server->caps |= NFS_CAP_MODE; + if (res.attr_bitmask[1] & FATTR4_WORD1_NUMLINKS) + server->caps |= NFS_CAP_NLINK; + if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER) + server->caps |= NFS_CAP_OWNER; + if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER_GROUP) + server->caps |= NFS_CAP_OWNER_GROUP; + if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_ACCESS) + server->caps |= NFS_CAP_ATIME; + if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_METADATA) + server->caps |= NFS_CAP_CTIME; + if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY) + server->caps |= NFS_CAP_MTIME; + memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask)); server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 19fe15d..320569e 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -167,6 +167,15 @@ struct nfs_server { #define NFS_CAP_SYMLINKS (1U << 2) #define NFS_CAP_ACLS (1U << 3) #define NFS_CAP_ATOMIC_OPEN (1U << 4) +#define NFS_CAP_CHANGE_ATTR (1U << 5) +#define NFS_CAP_FILEID (1U << 6) +#define NFS_CAP_MODE (1U << 7) +#define NFS_CAP_NLINK (1U << 8) +#define NFS_CAP_OWNER (1U << 9) +#define NFS_CAP_OWNER_GROUP (1U << 10) +#define NFS_CAP_ATIME (1U << 11) +#define NFS_CAP_CTIME (1U << 12) +#define NFS_CAP_MTIME (1U << 13) /* maximum number of slots to use */ -- cgit v0.10.2 From 80e52aced138bb41b045a8595a87510f27d8d8c5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:06:19 -0400 Subject: NFSv4: Don't do idmapper upcalls for asynchronous RPC calls We don't want to cause rpciod to hang... Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 617273e..e65cc2e 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -3075,7 +3075,8 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t return ret; } -static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *uid) +static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, + struct nfs_client *clp, uint32_t *uid, int may_sleep) { uint32_t len; __be32 *p; @@ -3088,7 +3089,9 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf READ_BUF(4); READ32(len); READ_BUF(len); - if (len < XDR_MAX_NETOBJ) { + if (!may_sleep) { + /* do nothing */ + } else if (len < XDR_MAX_NETOBJ) { if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0) ret = NFS_ATTR_FATTR_OWNER; else @@ -3103,7 +3106,8 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf return ret; } -static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *gid) +static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, + struct nfs_client *clp, uint32_t *gid, int may_sleep) { uint32_t len; __be32 *p; @@ -3116,7 +3120,9 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf READ_BUF(4); READ32(len); READ_BUF(len); - if (len < XDR_MAX_NETOBJ) { + if (!may_sleep) { + /* do nothing */ + } else if (len < XDR_MAX_NETOBJ) { if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0) ret = NFS_ATTR_FATTR_GROUP; else @@ -3466,7 +3472,8 @@ xdr_error: return status; } -static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server) +static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, + const struct nfs_server *server, int may_sleep) { __be32 *savep; uint32_t attrlen, @@ -3538,12 +3545,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons goto xdr_error; fattr->valid |= status; - status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid); + status = decode_attr_owner(xdr, bitmap, server->nfs_client, + &fattr->uid, may_sleep); if (status < 0) goto xdr_error; fattr->valid |= status; - status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid); + status = decode_attr_group(xdr, bitmap, server->nfs_client, + &fattr->gid, may_sleep); if (status < 0) goto xdr_error; fattr->valid |= status; @@ -4370,7 +4379,8 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct status = decode_open_downgrade(&xdr, res); if (status != 0) goto out; - decode_getfattr(&xdr, res->fattr, res->server); + decode_getfattr(&xdr, res->fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4397,7 +4407,8 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac status = decode_access(&xdr, res); if (status != 0) goto out; - decode_getfattr(&xdr, res->fattr, res->server); + decode_getfattr(&xdr, res->fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4424,7 +4435,8 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo goto out; if ((status = decode_getfh(&xdr, res->fh)) != 0) goto out; - status = decode_getfattr(&xdr, res->fattr, res->server); + status = decode_getfattr(&xdr, res->fattr, res->server + ,!RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4448,7 +4460,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf if ((status = decode_putrootfh(&xdr)) != 0) goto out; if ((status = decode_getfh(&xdr, res->fh)) == 0) - status = decode_getfattr(&xdr, res->fattr, res->server); + status = decode_getfattr(&xdr, res->fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4473,7 +4486,8 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem goto out; if ((status = decode_remove(&xdr, &res->cinfo)) != 0) goto out; - decode_getfattr(&xdr, &res->dir_attr, res->server); + decode_getfattr(&xdr, &res->dir_attr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4503,11 +4517,13 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0) goto out; /* Current FH is target directory */ - if (decode_getfattr(&xdr, res->new_fattr, res->server) != 0) + if (decode_getfattr(&xdr, res->new_fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)) != 0) goto out; if ((status = decode_restorefh(&xdr)) != 0) goto out; - decode_getfattr(&xdr, res->old_fattr, res->server); + decode_getfattr(&xdr, res->old_fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4540,11 +4556,13 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link * Note order: OP_LINK leaves the directory as the current * filehandle. */ - if (decode_getfattr(&xdr, res->dir_attr, res->server) != 0) + if (decode_getfattr(&xdr, res->dir_attr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)) != 0) goto out; if ((status = decode_restorefh(&xdr)) != 0) goto out; - decode_getfattr(&xdr, res->fattr, res->server); + decode_getfattr(&xdr, res->fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4573,11 +4591,13 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr goto out; if ((status = decode_getfh(&xdr, res->fh)) != 0) goto out; - if (decode_getfattr(&xdr, res->fattr, res->server) != 0) + if (decode_getfattr(&xdr, res->fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)) != 0) goto out; if ((status = decode_restorefh(&xdr)) != 0) goto out; - decode_getfattr(&xdr, res->dir_fattr, res->server); + decode_getfattr(&xdr, res->dir_fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4609,7 +4629,8 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g status = decode_putfh(&xdr); if (status) goto out; - status = decode_getfattr(&xdr, res->fattr, res->server); + status = decode_getfattr(&xdr, res->fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4716,7 +4737,8 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos * an ESTALE error. Shouldn't be a problem, * though, since fattr->valid will remain unset. */ - decode_getfattr(&xdr, res->fattr, res->server); + decode_getfattr(&xdr, res->fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4748,11 +4770,13 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr goto out; if (decode_getfh(&xdr, &res->fh) != 0) goto out; - if (decode_getfattr(&xdr, res->f_attr, res->server) != 0) + if (decode_getfattr(&xdr, res->f_attr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)) != 0) goto out; if (decode_restorefh(&xdr) != 0) goto out; - decode_getfattr(&xdr, res->dir_attr, res->server); + decode_getfattr(&xdr, res->dir_attr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4800,7 +4824,8 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nf status = decode_open(&xdr, res); if (status) goto out; - decode_getfattr(&xdr, res->f_attr, res->server); + decode_getfattr(&xdr, res->f_attr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -4827,7 +4852,8 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se status = decode_setattr(&xdr); if (status) goto out; - decode_getfattr(&xdr, res->fattr, res->server); + decode_getfattr(&xdr, res->fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -5001,7 +5027,8 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writ status = decode_write(&xdr, res); if (status) goto out; - decode_getfattr(&xdr, res->fattr, res->server); + decode_getfattr(&xdr, res->fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); if (!status) status = res->count; out: @@ -5030,7 +5057,8 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri status = decode_commit(&xdr, res); if (status) goto out; - decode_getfattr(&xdr, res->fattr, res->server); + decode_getfattr(&xdr, res->fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -5194,7 +5222,8 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf if (status != 0) goto out; status = decode_delegreturn(&xdr); - decode_getfattr(&xdr, res->fattr, res->server); + decode_getfattr(&xdr, res->fattr, res->server, + !RPC_IS_ASYNC(rqstp->rq_task)); out: return status; } @@ -5222,7 +5251,8 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, goto out; xdr_enter_page(&xdr, PAGE_SIZE); status = decode_getfattr(&xdr, &res->fs_locations->fattr, - res->fs_locations->server); + res->fs_locations->server, + !RPC_IS_ASYNC(req->rq_task)); out: return status; } -- cgit v0.10.2 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 diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index dd1a6d4..2f18206 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 83c73c4..585a864 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 v0.10.2 From c140aa91357c415c91269884518fa1d6fdebc20d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:06:19 -0400 Subject: NFSv4: Clean up the nfs.callback_tcpport option Tighten up the validity checking in param_set_port: check for NULL pointers. Ensure that the option shows up on 'modinfo' output. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 7f604c7..293fa05 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -43,21 +43,29 @@ static struct svc_program nfs4_callback_program; unsigned int nfs_callback_set_tcpport; unsigned short nfs_callback_tcpport; unsigned short nfs_callback_tcpport6; -static const int nfs_set_port_min = 0; -static const int nfs_set_port_max = 65535; +#define NFS_CALLBACK_MAXPORTNR (65535U) -static int param_set_port(const char *val, struct kernel_param *kp) +static int param_set_portnr(const char *val, struct kernel_param *kp) { - char *endp; - int num = simple_strtol(val, &endp, 0); - if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max) + unsigned long num; + int ret; + + if (!val) + return -EINVAL; + ret = strict_strtoul(val, 0, &num); + if (ret == -EINVAL || num > NFS_CALLBACK_MAXPORTNR) return -EINVAL; - *((int *)kp->arg) = num; + *((unsigned int *)kp->arg) = num; return 0; } -module_param_call(callback_tcpport, param_set_port, param_get_int, - &nfs_callback_set_tcpport, 0644); +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(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644); /* * This is the NFSv4 callback kernel thread. -- cgit v0.10.2 From 8f738d58425625faf0c1a6dbfdd4458545338551 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 9 Aug 2009 20:08:31 +0100 Subject: ASoC: Define more formats for the AC97 CODECs Signed-off-by: Mark Brown diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 25d62ac..50c6a0e 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -78,7 +78,13 @@ struct snd_pcm_substream; #define SND_SOC_CLOCK_IN 0 #define SND_SOC_CLOCK_OUT 1 -#define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S16_LE |\ +#define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S8 |\ + SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S16_BE |\ + SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S20_3BE |\ + SNDRV_PCM_FMTBIT_S24_3LE |\ + SNDRV_PCM_FMTBIT_S24_3BE |\ SNDRV_PCM_FMTBIT_S32_LE |\ SNDRV_PCM_FMTBIT_S32_BE) -- cgit v0.10.2 From f3f4f4ed26b116f621596f74d42d2b736171e968 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:29 -0400 Subject: NFS: Fix up new minorversion= option The new minorversion= mount option (commit 3fd5be9e) was merged at the same time as the recent sloppy parser fixes (commit a5a16bae), so minorversion= still uses the old value parsing logic. If the minorversion= option specifies a bogus value, it should fail with "bad value" not "bad option." Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0b4cbdc..83a3107 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -158,7 +158,7 @@ static const match_table_t nfs_mount_option_tokens = { { Opt_mountvers, "mountvers=%s" }, { Opt_nfsvers, "nfsvers=%s" }, { Opt_nfsvers, "vers=%s" }, - { Opt_minorversion, "minorversion=%u" }, + { Opt_minorversion, "minorversion=%s" }, { Opt_sec, "sec=%s" }, { Opt_proto, "proto=%s" }, @@ -1001,7 +1001,6 @@ static int nfs_parse_mount_options(char *raw, while ((p = strsep(&raw, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; unsigned long option; - int int_option; int token; if (!*p) @@ -1273,11 +1272,16 @@ static int nfs_parse_mount_options(char *raw, } break; case Opt_minorversion: - if (match_int(args, &int_option)) - return 0; - if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION) - return 0; - mnt->minorversion = int_option; + string = match_strdup(args); + if (string == NULL) + goto out_nomem; + rc = strict_strtoul(string, 10, &option); + kfree(string); + if (rc != 0) + goto out_invalid_value; + if (option > NFS4_MAX_MINOR_VERSION) + goto out_invalid_value; + mnt->minorversion = option; break; /* -- cgit v0.10.2 From 0b524123c93893391ec9e6c9b04998a45235f9c8 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:30 -0400 Subject: NFS: Add ability to send MOUNTPROC_UMNT to the kernel's mountd client After certain failure modes of an NFS mount, an NFS client should send a MOUNTPROC_UMNT request to remove the just-added mount entry from the server's mount table. While no-one should rely on the accuracy of the server's mount table, sending a UMNT is simply being a good internet neighbor. Since NFS mount processing is handled in the kernel now, we will need a function in the kernel's mountd client that can post a MOUNTRPC_UMNT request, in order to handle these failure modes. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 7dd90a6..8d2b71d 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -102,6 +102,7 @@ struct nfs_mount_request { }; extern int nfs_mount(struct nfs_mount_request *info); +extern void nfs_umount(const struct nfs_mount_request *info); /* client.c */ extern struct rpc_program nfs_program; diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 38ef9ea..72dd8b6 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -209,6 +209,71 @@ out_mnt_err: goto out; } +/** + * nfs_umount - Notify a server that we have unmounted this export + * @info: pointer to umount request arguments + * + * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always + * use UDP. + */ +void nfs_umount(const struct nfs_mount_request *info) +{ + static const struct rpc_timeout nfs_umnt_timeout = { + .to_initval = 1 * HZ, + .to_maxval = 3 * HZ, + .to_retries = 2, + }; + struct rpc_create_args args = { + .protocol = IPPROTO_UDP, + .address = info->sap, + .addrsize = info->salen, + .timeout = &nfs_umnt_timeout, + .servername = info->hostname, + .program = &mnt_program, + .version = info->version, + .authflavor = RPC_AUTH_UNIX, + .flags = RPC_CLNT_CREATE_NOPING, + }; + struct mountres result; + struct rpc_message msg = { + .rpc_argp = info->dirpath, + .rpc_resp = &result, + }; + struct rpc_clnt *clnt; + int status; + + if (info->noresvport) + args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; + + clnt = rpc_create(&args); + if (unlikely(IS_ERR(clnt))) + goto out_clnt_err; + + dprintk("NFS: sending UMNT request for %s:%s\n", + (info->hostname ? info->hostname : "server"), info->dirpath); + + if (info->version == NFS_MNT3_VERSION) + msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT]; + else + msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT]; + + status = rpc_call_sync(clnt, &msg, 0); + rpc_shutdown_client(clnt); + + if (unlikely(status < 0)) + goto out_call_err; + + return; + +out_clnt_err: + dprintk("NFS: failed to create UMNT RPC client, status=%ld\n", + PTR_ERR(clnt)); + return; + +out_call_err: + dprintk("NFS: UMNT request failed, status=%d\n", status); +} + /* * XDR encode/decode functions for MOUNT */ @@ -407,6 +472,13 @@ static struct rpc_procinfo mnt_procedures[] = { .p_statidx = MOUNTPROC_MNT, .p_name = "MOUNT", }, + [MOUNTPROC_UMNT] = { + .p_proc = MOUNTPROC_UMNT, + .p_encode = (kxdrproc_t)mnt_enc_dirpath, + .p_arglen = MNT_enc_dirpath_sz, + .p_statidx = MOUNTPROC_UMNT, + .p_name = "UMOUNT", + }, }; static struct rpc_procinfo mnt3_procedures[] = { @@ -419,6 +491,13 @@ static struct rpc_procinfo mnt3_procedures[] = { .p_statidx = MOUNTPROC3_MNT, .p_name = "MOUNT", }, + [MOUNTPROC3_UMNT] = { + .p_proc = MOUNTPROC3_UMNT, + .p_encode = (kxdrproc_t)mnt_enc_dirpath, + .p_arglen = MNT_enc_dirpath_sz, + .p_statidx = MOUNTPROC3_UMNT, + .p_name = "UMOUNT", + }, }; -- cgit v0.10.2 From 059f90b323c0f5d34656ab7e0548d7d033c2a51a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:31 -0400 Subject: NFS: Fix auth flavor len accounting Previous logic in the NFS mount parsing code path assumed auth_flavor_len was set to zero for simple authentication flavors (like AUTH_UNIX), and 1 for compound flavors (like AUTH_GSS). At some earlier point (maybe even before the option parsers were merged?) specific checks for auth_flavor_len being zero were removed from the functions that validate the mount option that sets the mount point's authentication flavor. Since we are populating an array for authentication flavors, the auth_flavor_len should always be set to the number of flavors. Let's eliminate some cleverness here, and prepare for new logic that needs to know the number of flavors in the auth_flavors[] array. (auth_flavors[] is an array because at some point we want to allow a list of acceptable authentication flavors to be specified via the sec= mount option. For now it remains a single element array). Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 83a3107..a33e608 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -904,8 +904,6 @@ static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt) /* * Parse the value of the 'sec=' option. - * - * The flavor_len setting is for v4 mounts. */ static int nfs_parse_security_flavors(char *value, struct nfs_parsed_mount_data *mnt) @@ -916,53 +914,43 @@ static int nfs_parse_security_flavors(char *value, switch (match_token(value, nfs_secflavor_tokens, args)) { case Opt_sec_none: - mnt->auth_flavor_len = 0; mnt->auth_flavors[0] = RPC_AUTH_NULL; break; case Opt_sec_sys: - mnt->auth_flavor_len = 0; mnt->auth_flavors[0] = RPC_AUTH_UNIX; break; case Opt_sec_krb5: - mnt->auth_flavor_len = 1; mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; break; case Opt_sec_krb5i: - mnt->auth_flavor_len = 1; mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; break; case Opt_sec_krb5p: - mnt->auth_flavor_len = 1; mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; break; case Opt_sec_lkey: - mnt->auth_flavor_len = 1; mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; break; case Opt_sec_lkeyi: - mnt->auth_flavor_len = 1; mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; break; case Opt_sec_lkeyp: - mnt->auth_flavor_len = 1; mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; break; case Opt_sec_spkm: - mnt->auth_flavor_len = 1; mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; break; case Opt_sec_spkmi: - mnt->auth_flavor_len = 1; mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; break; case Opt_sec_spkmp: - mnt->auth_flavor_len = 1; mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; break; default: return 0; } + mnt->auth_flavor_len = 1; return 1; } @@ -1680,6 +1668,7 @@ static int nfs_validate_mount_data(void *options, args->nfs_server.port = 0; /* autobind unless user sets port */ args->nfs_server.protocol = XPRT_TRANSPORT_TCP; args->auth_flavors[0] = RPC_AUTH_UNIX; + args->auth_flavor_len = 1; switch (data->version) { case 1: @@ -2343,7 +2332,7 @@ static int nfs4_validate_mount_data(void *options, args->acdirmax = NFS_DEF_ACDIRMAX; args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ args->auth_flavors[0] = RPC_AUTH_UNIX; - args->auth_flavor_len = 0; + args->auth_flavor_len = 1; args->minorversion = 0; switch (data->version) { -- cgit v0.10.2 From ec88f28d1eb77346f19ca324ceec76e645cdd9da Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:32 -0400 Subject: NFS: Use the authentication flavor list returned by mountd Commit a14017db added support in the kernel's NFS mount client to decode the authentication flavor list returned by mountd. The NFS client can now use this list to determine whether the authentication flavor requested by the user is actually supported by the server. Note we don't actually negotiate the security flavor if none was specified by the user. Instead, we try to use AUTH_SYS, and fail if the server does not support it. This prevents us from negotiating an inappropriate security flavor (some servers list AUTH_NULL first). If the server does not support AUTH_SYS, the user must provide an appropriate security flavor by specifying the "sec=" mount option. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfs/super.c b/fs/nfs/super.c index a33e608..8526008 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1437,13 +1437,50 @@ out_security_failure: } /* + * Match the requested auth flavors with the list returned by + * the server. Returns zero and sets the mount's authentication + * flavor on success; returns -EACCES if server does not support + * the requested flavor. + */ +static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, + struct nfs_mount_request *request) +{ + unsigned int i, j, server_authlist_len = *(request->auth_flav_len); + + /* + * We avoid sophisticated negotiating here, as there are + * plenty of cases where we can get it wrong, providing + * either too little or too much security. + * + * RFC 2623, section 2.7 suggests we SHOULD prefer the + * flavor listed first. However, some servers list + * AUTH_NULL first. Our caller plants AUTH_SYS, the + * preferred default, in args->auth_flavors[0] if user + * didn't specify sec= mount option. + */ + for (i = 0; i < args->auth_flavor_len; i++) + for (j = 0; j < server_authlist_len; j++) + if (args->auth_flavors[i] == request->auth_flavs[j]) { + dfprintk(MOUNT, "NFS: using auth flavor %d\n", + request->auth_flavs[j]); + args->auth_flavors[0] = request->auth_flavs[j]; + return 0; + } + + dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n"); + nfs_umount(request); + return -EACCES; +} + +/* * Use the remote server's MOUNT service to request the NFS file handle * corresponding to the provided path. */ static int nfs_try_mount(struct nfs_parsed_mount_data *args, struct nfs_fh *root_fh) { - unsigned int auth_flavor_len = 0; + rpc_authflavor_t server_authlist[NFS_MAX_SECFLAVORS]; + unsigned int server_authlist_len = ARRAY_SIZE(server_authlist); struct nfs_mount_request request = { .sap = (struct sockaddr *) &args->mount_server.address, @@ -1451,7 +1488,8 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, .protocol = args->mount_server.protocol, .fh = root_fh, .noresvport = args->flags & NFS_MOUNT_NORESVPORT, - .auth_flav_len = &auth_flavor_len, + .auth_flav_len = &server_authlist_len, + .auth_flavs = server_authlist, }; int status; @@ -1488,12 +1526,18 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, * to a file handle. */ status = nfs_mount(&request); - if (status == 0) - return 0; + if (status != 0) { + dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", + request.hostname, status); + return status; + } - dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", - request.hostname, status); - return status; + /* + * MNTv1 (NFSv2) does not support auth flavor negotiation. + */ + if (args->mount_server.version != NFS_MNT3_VERSION) + return 0; + return nfs_walk_authlist(args, &request); } static int nfs_parse_simple_hostname(const char *dev_name, -- cgit v0.10.2 From 169026a61e6f436dfc12c9d10d95455c4e9f945b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:32 -0400 Subject: SUNRPC: Clean up RPCBIND_MAXUADDRLEN definitions Clean up: Replace the single-integer definition of RPCBIND_MAXUADDRLEN with a definition that is based on previously defined address string sizes, and document the way this maximum is calculated. Also provide a separate macro for the size of the port number extension. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h index 70df4f1..77e6248 100644 --- a/include/linux/sunrpc/msg_prot.h +++ b/include/linux/sunrpc/msg_prot.h @@ -189,7 +189,22 @@ typedef __be32 rpc_fraghdr; * Additionally, the two alternative forms specified in Section 2.2 of * [RFC2373] are also acceptable. */ -#define RPCBIND_MAXUADDRLEN (56u) + +#include + +/* Maximum size of the port number part of a universal address */ +#define RPCBIND_MAXUADDRPLEN sizeof(".255.255") + +/* Maximum size of an IPv4 universal address */ +#define RPCBIND_MAXUADDR4LEN \ + (INET_ADDRSTRLEN + RPCBIND_MAXUADDRPLEN) + +/* Maximum size of an IPv6 universal address */ +#define RPCBIND_MAXUADDR6LEN \ + (INET6_ADDRSTRLEN + RPCBIND_MAXUADDRPLEN) + +/* Assume INET6_ADDRSTRLEN will always be larger than INET_ADDRSTRLEN... */ +#define RPCBIND_MAXUADDRLEN RPCBIND_MAXUADDR6LEN #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_MSGPROT_H_ */ -- cgit v0.10.2 From 0b10bf5e14d856d1d27a2117d07af2bebee81b75 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:33 -0400 Subject: SUNRPC: Move XDR data type size macros Clean up: To make subsequent patches cleaner, move the XDR data type size macros to the top of the file (similar to nfs4xdr.c) first. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index beee6da..ad1d731 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -75,6 +75,37 @@ enum { #define RPCB_OWNER_STRING "0" #define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING) +/* + * XDR data type sizes + */ +#define RPCB_program_sz (1) +#define RPCB_version_sz (1) +#define RPCB_protocol_sz (1) +#define RPCB_port_sz (1) +#define RPCB_boolean_sz (1) + +#define RPCB_netid_sz (1 + XDR_QUADLEN(RPCBIND_MAXNETIDLEN)) +#define RPCB_addr_sz (1 + XDR_QUADLEN(RPCBIND_MAXUADDRLEN)) +#define RPCB_ownerstring_sz (1 + XDR_QUADLEN(RPCB_MAXOWNERLEN)) + +/* + * XDR argument and result sizes + */ +#define RPCB_mappingargs_sz (RPCB_program_sz + RPCB_version_sz + \ + RPCB_protocol_sz + RPCB_port_sz) +#define RPCB_getaddrargs_sz (RPCB_program_sz + RPCB_version_sz + \ + RPCB_netid_sz + RPCB_addr_sz + \ + RPCB_ownerstring_sz) + +#define RPCB_getportres_sz RPCB_port_sz +#define RPCB_setres_sz RPCB_boolean_sz + +/* + * Note that RFC 1833 does not put any size restrictions on the + * address string returned by the remote rpcbind database. + */ +#define RPCB_getaddrres_sz RPCB_addr_sz + static void rpcb_getport_done(struct rpc_task *, void *); static void rpcb_map_release(void *data); static struct rpc_program rpcb_program; @@ -768,31 +799,6 @@ out_err: return -EIO; } -#define RPCB_program_sz (1u) -#define RPCB_version_sz (1u) -#define RPCB_protocol_sz (1u) -#define RPCB_port_sz (1u) -#define RPCB_boolean_sz (1u) - -#define RPCB_netid_sz (1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN)) -#define RPCB_addr_sz (1+XDR_QUADLEN(RPCBIND_MAXUADDRLEN)) -#define RPCB_ownerstring_sz (1+XDR_QUADLEN(RPCB_MAXOWNERLEN)) - -#define RPCB_mappingargs_sz RPCB_program_sz+RPCB_version_sz+ \ - RPCB_protocol_sz+RPCB_port_sz -#define RPCB_getaddrargs_sz RPCB_program_sz+RPCB_version_sz+ \ - RPCB_netid_sz+RPCB_addr_sz+ \ - RPCB_ownerstring_sz - -#define RPCB_setres_sz RPCB_boolean_sz -#define RPCB_getportres_sz RPCB_port_sz - -/* - * Note that RFC 1833 does not put any size restrictions on the - * address string returned by the remote rpcbind database. - */ -#define RPCB_getaddrres_sz RPCB_addr_sz - #define PROC(proc, argtype, restype) \ [RPCBPROC_##proc] = { \ .p_proc = RPCBPROC_##proc, \ -- cgit v0.10.2 From a02d692611348f11ee1bc37431a883c3ff2de23e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:34 -0400 Subject: SUNRPC: Provide functions for managing universal addresses Introduce a set of functions in the kernel's RPC implementation for converting between a socket address and either a standard presentation address string or an RPC universal address. The universal address functions will be used to encode and decode RPCB_FOO and NFSv4 SETCLIENTID arguments. The other functions are part of a previous promise to deliver shared functions that can be used by upper-layer protocols to display and manipulate IP addresses. The kernel's current address printf formatters were designed specifically for kernel to user-space APIs that require a particular string format for socket addresses, thus are somewhat limited for the purposes of sunrpc.ko. The formatter for IPv6 addresses, %pI6, does not support short-handing or scope IDs. Also, these printf formatters are unique per address family, so a separate formatter string is required for printing AF_INET and AF_INET6 addresses. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 8d2b71d..ff68397 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -370,8 +370,6 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len) PAGE_SIZE - 1) >> PAGE_SHIFT; } -#define IPV6_SCOPE_DELIMITER '%' - /* * Set the port number in an address. Be agnostic about the address * family. diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 37881f1a..2636e8a 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -9,6 +9,10 @@ #ifndef _LINUX_SUNRPC_CLNT_H #define _LINUX_SUNRPC_CLNT_H +#include +#include +#include + #include #include #include @@ -151,5 +155,39 @@ void rpc_force_rebind(struct rpc_clnt *); size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); +size_t rpc_ntop(const struct sockaddr *, char *, const size_t); +size_t rpc_pton(const char *, const size_t, + struct sockaddr *, const size_t); +char * rpc_sockaddr2uaddr(const struct sockaddr *); +size_t rpc_uaddr2sockaddr(const char *, const size_t, + struct sockaddr *, const size_t); + +static inline unsigned short rpc_get_port(const struct sockaddr *sap) +{ + switch (sap->sa_family) { + case AF_INET: + return ntohs(((struct sockaddr_in *)sap)->sin_port); + case AF_INET6: + return ntohs(((struct sockaddr_in6 *)sap)->sin6_port); + } + return 0; +} + +static inline void rpc_set_port(struct sockaddr *sap, + const unsigned short port) +{ + switch (sap->sa_family) { + case AF_INET: + ((struct sockaddr_in *)sap)->sin_port = htons(port); + break; + case AF_INET6: + ((struct sockaddr_in6 *)sap)->sin6_port = htons(port); + break; + } +} + +#define IPV6_SCOPE_DELIMITER '%' +#define IPV6_SCOPE_ID_LEN sizeof("%nnnnnnnnnn") + #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_CLNT_H */ diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile index db73fd2..9d2fca5 100644 --- a/net/sunrpc/Makefile +++ b/net/sunrpc/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma/ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ auth.o auth_null.o auth_unix.o auth_generic.o \ svc.o svcsock.o svcauth.o svcauth_unix.o \ - rpcb_clnt.o timer.o xdr.o \ + addr.o rpcb_clnt.o timer.o xdr.o \ sunrpc_syms.o cache.o rpc_pipe.o \ svc_xprt.o sunrpc-$(CONFIG_NFS_V4_1) += backchannel_rqst.o bc_svc.o diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c new file mode 100644 index 0000000..22e8fd8 --- /dev/null +++ b/net/sunrpc/addr.c @@ -0,0 +1,364 @@ +/* + * Copyright 2009, Oracle. All rights reserved. + * + * Convert socket addresses to presentation addresses and universal + * addresses, and vice versa. + * + * Universal addresses are introduced by RFC 1833 and further refined by + * recent RFCs describing NFSv4. The universal address format is part + * of the external (network) interface provided by rpcbind version 3 + * and 4, and by NFSv4. Such an address is a string containing a + * presentation format IP address followed by a port number in + * "hibyte.lobyte" format. + * + * IPv6 addresses can also include a scope ID, typically denoted by + * a '%' followed by a device name or a non-negative integer. Refer to + * RFC 4291, Section 2.2 for details on IPv6 presentation formats. + */ + +#include +#include + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap, + char *buf, const int buflen) +{ + const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; + const struct in6_addr *addr = &sin6->sin6_addr; + + /* + * RFC 4291, Section 2.2.2 + * + * Shorthanded ANY address + */ + if (ipv6_addr_any(addr)) + return snprintf(buf, buflen, "::"); + + /* + * RFC 4291, Section 2.2.2 + * + * Shorthanded loopback address + */ + if (ipv6_addr_loopback(addr)) + return snprintf(buf, buflen, "::1"); + + /* + * RFC 4291, Section 2.2.3 + * + * Special presentation address format for mapped v4 + * addresses. + */ + if (ipv6_addr_v4mapped(addr)) + return snprintf(buf, buflen, "::ffff:%pI4", + &addr->s6_addr32[3]); + + /* + * RFC 4291, Section 2.2.1 + * + * To keep the result as short as possible, especially + * since we don't shorthand, we don't want leading zeros + * in each halfword, so avoid %pI6. + */ + return snprintf(buf, buflen, "%x:%x:%x:%x:%x:%x:%x:%x", + ntohs(addr->s6_addr16[0]), ntohs(addr->s6_addr16[1]), + ntohs(addr->s6_addr16[2]), ntohs(addr->s6_addr16[3]), + ntohs(addr->s6_addr16[4]), ntohs(addr->s6_addr16[5]), + ntohs(addr->s6_addr16[6]), ntohs(addr->s6_addr16[7])); +} + +static size_t rpc_ntop6(const struct sockaddr *sap, + char *buf, const size_t buflen) +{ + const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; + char scopebuf[IPV6_SCOPE_ID_LEN]; + size_t len; + int rc; + + len = rpc_ntop6_noscopeid(sap, buf, buflen); + if (unlikely(len == 0)) + return len; + + if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) && + !(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_SITELOCAL)) + return len; + + rc = snprintf(scopebuf, sizeof(scopebuf), "%c%u", + IPV6_SCOPE_DELIMITER, sin6->sin6_scope_id); + if (unlikely((size_t)rc > sizeof(scopebuf))) + return 0; + + len += rc; + if (unlikely(len > buflen)) + return 0; + + strcat(buf, scopebuf); + return len; +} + +#else /* !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) */ + +static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap, + char *buf, const int buflen) +{ + return 0; +} + +static size_t rpc_ntop6(const struct sockaddr *sap, + char *buf, const size_t buflen) +{ + return 0; +} + +#endif /* !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) */ + +static int rpc_ntop4(const struct sockaddr *sap, + char *buf, const size_t buflen) +{ + const struct sockaddr_in *sin = (struct sockaddr_in *)sap; + + return snprintf(buf, buflen, "%pI4", &sin->sin_addr); +} + +/** + * rpc_ntop - construct a presentation address in @buf + * @sap: socket address + * @buf: construction area + * @buflen: size of @buf, in bytes + * + * Plants a %NUL-terminated string in @buf and returns the length + * of the string, excluding the %NUL. Otherwise zero is returned. + */ +size_t rpc_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) +{ + switch (sap->sa_family) { + case AF_INET: + return rpc_ntop4(sap, buf, buflen); + case AF_INET6: + return rpc_ntop6(sap, buf, buflen); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rpc_ntop); + +static size_t rpc_pton4(const char *buf, const size_t buflen, + struct sockaddr *sap, const size_t salen) +{ + struct sockaddr_in *sin = (struct sockaddr_in *)sap; + u8 *addr = (u8 *)&sin->sin_addr.s_addr; + + if (buflen > INET_ADDRSTRLEN || salen < sizeof(struct sockaddr_in)) + return 0; + + memset(sap, 0, sizeof(struct sockaddr_in)); + + if (in4_pton(buf, buflen, addr, '\0', NULL) == 0) + return 0; + + sin->sin_family = AF_INET; + return sizeof(struct sockaddr_in);; +} + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +static int rpc_parse_scope_id(const char *buf, const size_t buflen, + const char *delim, struct sockaddr_in6 *sin6) +{ + char *p; + size_t len; + + if ((buf + buflen) == delim) + return 1; + + if (*delim != IPV6_SCOPE_DELIMITER) + return 0; + + if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) && + !(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_SITELOCAL)) + return 0; + + len = (buf + buflen) - delim - 1; + p = kstrndup(delim + 1, len, GFP_KERNEL); + if (p) { + unsigned long scope_id = 0; + struct net_device *dev; + + dev = dev_get_by_name(&init_net, p); + if (dev != NULL) { + scope_id = dev->ifindex; + dev_put(dev); + } else { + if (strict_strtoul(p, 10, &scope_id) == 0) { + kfree(p); + return 0; + } + } + + kfree(p); + + sin6->sin6_scope_id = scope_id; + return 1; + } + + return 0; +} + +static size_t rpc_pton6(const char *buf, const size_t buflen, + struct sockaddr *sap, const size_t salen) +{ + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; + u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; + const char *delim; + + if (buflen > (INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN) || + salen < sizeof(struct sockaddr_in6)) + return 0; + + memset(sap, 0, sizeof(struct sockaddr_in6)); + + if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0) + return 0; + + if (!rpc_parse_scope_id(buf, buflen, delim, sin6)) + return 0; + + sin6->sin6_family = AF_INET6; + return sizeof(struct sockaddr_in6); +} +#else +static size_t rpc_pton6(const char *buf, const size_t buflen, + struct sockaddr *sap, const size_t salen) +{ + return 0; +} +#endif + +/** + * rpc_pton - Construct a sockaddr in @sap + * @buf: C string containing presentation format IP address + * @buflen: length of presentation address in bytes + * @sap: buffer into which to plant socket address + * @salen: size of buffer in bytes + * + * Returns the size of the socket address if successful; otherwise + * zero is returned. + * + * Plants a socket address in @sap and returns the size of the + * socket address, if successful. Returns zero if an error + * occurred. + */ +size_t rpc_pton(const char *buf, const size_t buflen, + struct sockaddr *sap, const size_t salen) +{ + unsigned int i; + + for (i = 0; i < buflen; i++) + if (buf[i] == ':') + return rpc_pton6(buf, buflen, sap, salen); + return rpc_pton4(buf, buflen, sap, salen); +} +EXPORT_SYMBOL_GPL(rpc_pton); + +/** + * rpc_sockaddr2uaddr - Construct a universal address string from @sap. + * @sap: socket address + * + * Returns a %NUL-terminated string in dynamically allocated memory; + * otherwise NULL is returned if an error occurred. Caller must + * free the returned string. + */ +char *rpc_sockaddr2uaddr(const struct sockaddr *sap) +{ + char portbuf[RPCBIND_MAXUADDRPLEN]; + char addrbuf[RPCBIND_MAXUADDRLEN]; + unsigned short port; + + switch (sap->sa_family) { + case AF_INET: + if (rpc_ntop4(sap, addrbuf, sizeof(addrbuf)) == 0) + return NULL; + port = ntohs(((struct sockaddr_in *)sap)->sin_port); + break; + case AF_INET6: + if (rpc_ntop6_noscopeid(sap, addrbuf, sizeof(addrbuf)) == 0) + return NULL; + port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port); + break; + default: + return NULL; + } + + if (snprintf(portbuf, sizeof(portbuf), + ".%u.%u", port >> 8, port & 0xff) > (int)sizeof(portbuf)) + return NULL; + + if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf)) + return NULL; + + return kstrdup(addrbuf, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(rpc_sockaddr2uaddr); + +/** + * rpc_uaddr2sockaddr - convert a universal address to a socket address. + * @uaddr: C string containing universal address to convert + * @uaddr_len: length of universal address string + * @sap: buffer into which to plant socket address + * @salen: size of buffer + * + * Returns the size of the socket address if successful; otherwise + * zero is returned. + */ +size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, + struct sockaddr *sap, const size_t salen) +{ + char *c, buf[RPCBIND_MAXUADDRLEN]; + unsigned long portlo, porthi; + unsigned short port; + + if (uaddr_len > sizeof(buf)) + return 0; + + memcpy(buf, uaddr, uaddr_len); + + buf[uaddr_len] = '\n'; + buf[uaddr_len + 1] = '\0'; + + c = strrchr(buf, '.'); + if (unlikely(c == NULL)) + return 0; + if (unlikely(strict_strtoul(c + 1, 10, &portlo) != 0)) + return 0; + if (unlikely(portlo > 255)) + return 0; + + c[0] = '\n'; + c[1] = '\0'; + + c = strrchr(buf, '.'); + if (unlikely(c == NULL)) + return 0; + if (unlikely(strict_strtoul(c + 1, 10, &porthi) != 0)) + return 0; + if (unlikely(porthi > 255)) + return 0; + + port = (unsigned short)((porthi << 8) | portlo); + + c[0] = '\0'; + + if (rpc_pton(buf, strlen(buf), sap, salen) == 0) + return 0; + + switch (sap->sa_family) { + case AF_INET: + ((struct sockaddr_in *)sap)->sin_port = htons(port); + return sizeof(struct sockaddr_in); + case AF_INET6: + ((struct sockaddr_in6 *)sap)->sin6_port = htons(port); + return sizeof(struct sockaddr_in6); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rpc_uaddr2sockaddr); -- cgit v0.10.2 From ba809130bc260fce04141aca01ef9e068d32af2a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:35 -0400 Subject: SUNRPC: Remove duplicate universal address generation RPC universal address generation is currently done in several places: rpcb_clnt.c, nfs4proc.c xprtsock.c, and xprtrdma.c. Remove the redundant cases that convert a socket address to a universal address. The nfs4proc.c case takes a pre-formatted presentation address string, not a socket address, so we'll leave that one. Because the new uaddr constructor uses the recently introduced rpc_ntop(), it now supports proper "::" shorthanding for IPv6 addresses. This allows the kernel to register properly formed universal addresses with the local rpcbind service, in _all_ cases. The kernel can now also send properly formed universal addresses in RPCB_GETADDR requests, and support link-local properly when encoding and decoding IPv6 addresses. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 1175d58..65fad95 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -41,7 +41,6 @@ enum rpc_display_format_t { RPC_DISPLAY_ALL, RPC_DISPLAY_HEX_ADDR, RPC_DISPLAY_HEX_PORT, - RPC_DISPLAY_UNIVERSAL_ADDR, RPC_DISPLAY_NETID, RPC_DISPLAY_MAX, }; diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index ad1d731..1fb1c07 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -153,6 +153,7 @@ static void rpcb_map_release(void *data) rpcb_wake_rpcbind_waiters(map->r_xprt, map->r_status); xprt_put(map->r_xprt); + kfree(map->r_addr); kfree(map); } @@ -299,12 +300,9 @@ static int rpcb_register_inet4(const struct sockaddr *sap, const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; struct rpcbind_args *map = msg->rpc_argp; unsigned short port = ntohs(sin->sin_port); - char buf[32]; + int result; - /* Construct AF_INET universal address */ - snprintf(buf, sizeof(buf), "%pI4.%u.%u", - &sin->sin_addr.s_addr, port >> 8, port & 0xff); - map->r_addr = buf; + map->r_addr = rpc_sockaddr2uaddr(sap); dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " "local rpcbind\n", (port ? "" : "un"), @@ -315,7 +313,9 @@ static int rpcb_register_inet4(const struct sockaddr *sap, if (port) msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; - return rpcb_register_call(RPCBVERS_4, msg); + result = rpcb_register_call(RPCBVERS_4, msg); + kfree(map->r_addr); + return result; } /* @@ -327,16 +327,9 @@ static int rpcb_register_inet6(const struct sockaddr *sap, const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; struct rpcbind_args *map = msg->rpc_argp; unsigned short port = ntohs(sin6->sin6_port); - char buf[64]; + int result; - /* Construct AF_INET6 universal address */ - if (ipv6_addr_any(&sin6->sin6_addr)) - snprintf(buf, sizeof(buf), "::.%u.%u", - port >> 8, port & 0xff); - else - snprintf(buf, sizeof(buf), "%pI6.%u.%u", - &sin6->sin6_addr, port >> 8, port & 0xff); - map->r_addr = buf; + map->r_addr = rpc_sockaddr2uaddr(sap); dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " "local rpcbind\n", (port ? "" : "un"), @@ -347,7 +340,9 @@ static int rpcb_register_inet6(const struct sockaddr *sap, if (port) msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; - return rpcb_register_call(RPCBVERS_4, msg); + result = rpcb_register_call(RPCBVERS_4, msg); + kfree(map->r_addr); + return result; } static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) @@ -570,6 +565,7 @@ void rpcb_getport_async(struct rpc_task *task) goto bailout_nofree; } + /* Parent transport's destination address */ salen = rpc_peeraddr(clnt, sap, sizeof(addr)); /* Don't ever use rpcbind v2 for AF_INET6 requests */ @@ -620,11 +616,22 @@ void rpcb_getport_async(struct rpc_task *task) map->r_prot = xprt->prot; map->r_port = 0; map->r_xprt = xprt_get(xprt); - map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); - map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR); - map->r_owner = ""; map->r_status = -EIO; + switch (bind_version) { + case RPCBVERS_4: + case RPCBVERS_3: + map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); + map->r_addr = rpc_sockaddr2uaddr(sap); + map->r_owner = ""; + break; + case RPCBVERS_2: + map->r_addr = NULL; + break; + default: + BUG(); + } + child = rpcb_call_async(rpcb_clnt, map, proc); rpc_release_client(rpcb_clnt); if (IS_ERR(child)) { @@ -722,6 +729,9 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p, static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p, struct rpcbind_args *rpcb) { + if (rpcb->r_addr == NULL) + return -EIO; + dprintk("RPC: encoding rpcb request (%u, %u, %s)\n", rpcb->r_prog, rpcb->r_vers, rpcb->r_addr); *p++ = htonl(rpcb->r_prog); diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 1dd6123..537c210 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -202,14 +202,6 @@ xprt_rdma_format_addresses(struct rpc_xprt *xprt) snprintf(buf, 8, "%4hx", ntohs(addr->sin_port)); xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf; - buf = kzalloc(30, GFP_KERNEL); - if (buf) - snprintf(buf, 30, "%pI4.%u.%u", - &addr->sin_addr.s_addr, - ntohs(addr->sin_port) >> 8, - ntohs(addr->sin_port) & 0xff); - xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; - /* netid */ xprt->address_strings[RPC_DISPLAY_NETID] = "rdma"; } diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 83c73c4..a42c2ad 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -341,15 +341,6 @@ static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt, } xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf; - buf = kzalloc(30, GFP_KERNEL); - if (buf) { - snprintf(buf, 30, "%pI4.%u.%u", - &addr->sin_addr.s_addr, - ntohs(addr->sin_port) >> 8, - ntohs(addr->sin_port) & 0xff); - } - xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; - xprt->address_strings[RPC_DISPLAY_NETID] = netid; } @@ -397,15 +388,6 @@ static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt, } xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf; - buf = kzalloc(50, GFP_KERNEL); - if (buf) { - snprintf(buf, 50, "%pI6.%u.%u", - &addr->sin6_addr, - ntohs(addr->sin6_port) >> 8, - ntohs(addr->sin6_port) & 0xff); - } - xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; - xprt->address_strings[RPC_DISPLAY_NETID] = netid; } -- cgit v0.10.2 From c877b849d302d1275452af80b7221a2555dc02e1 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:36 -0400 Subject: SUNRPC: Use rpc_ntop() for constructing transport address strings Clean up: In addition to using the new generic rpc_ntop() and rpc_get_port() functions, have the RPC client compute the presentation address buffer sizes dynamically using kstrdup(). Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 537c210..5f9b867 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -168,39 +168,30 @@ static struct rpc_xprt_ops xprt_rdma_procs; /* forward reference */ static void xprt_rdma_format_addresses(struct rpc_xprt *xprt) { - struct sockaddr_in *addr = (struct sockaddr_in *) + struct sockaddr *sap = (struct sockaddr *) &rpcx_to_rdmad(xprt).addr; - char *buf; + struct sockaddr_in *sin = (struct sockaddr_in *)sap; + char buf[64]; - buf = kzalloc(20, GFP_KERNEL); - if (buf) - snprintf(buf, 20, "%pI4", &addr->sin_addr.s_addr); - xprt->address_strings[RPC_DISPLAY_ADDR] = buf; + (void)rpc_ntop(sap, buf, sizeof(buf)); + xprt->address_strings[RPC_DISPLAY_ADDR] = kstrdup(buf, GFP_KERNEL); - buf = kzalloc(8, GFP_KERNEL); - if (buf) - snprintf(buf, 8, "%u", ntohs(addr->sin_port)); - xprt->address_strings[RPC_DISPLAY_PORT] = buf; + (void)snprintf(buf, sizeof(buf), "%u", rpc_get_port(sap)); + xprt->address_strings[RPC_DISPLAY_PORT] = kstrdup(buf, GFP_KERNEL); xprt->address_strings[RPC_DISPLAY_PROTO] = "rdma"; - buf = kzalloc(48, GFP_KERNEL); - if (buf) - snprintf(buf, 48, "addr=%pI4 port=%u proto=%s", - &addr->sin_addr.s_addr, - ntohs(addr->sin_port), "rdma"); - xprt->address_strings[RPC_DISPLAY_ALL] = buf; - - buf = kzalloc(10, GFP_KERNEL); - if (buf) - snprintf(buf, 10, "%02x%02x%02x%02x", - NIPQUAD(addr->sin_addr.s_addr)); - xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf; - - buf = kzalloc(8, GFP_KERNEL); - if (buf) - snprintf(buf, 8, "%4hx", ntohs(addr->sin_port)); - xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf; + (void)snprintf(buf, sizeof(buf), "addr=%s port=%s proto=rdma", + xprt->address_strings[RPC_DISPLAY_ADDR], + xprt->address_strings[RPC_DISPLAY_PORT]); + xprt->address_strings[RPC_DISPLAY_ALL] = kstrdup(buf, GFP_KERNEL); + + (void)snprintf(buf, sizeof(buf), "%02x%02x%02x%02x", + NIPQUAD(sin->sin_addr.s_addr)); + xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL); + + (void)snprintf(buf, sizeof(buf), "%4hx", rpc_get_port(sap)); + xprt->address_strings[RPC_DISPLAY_HEX_PORT] = kstrdup(buf, GFP_KERNEL); /* netid */ xprt->address_strings[RPC_DISPLAY_NETID] = "rdma"; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index a42c2ad..302a409 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -296,99 +296,58 @@ static inline struct sockaddr_in6 *xs_addr_in6(struct rpc_xprt *xprt) return (struct sockaddr_in6 *) &xprt->addr; } -static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt, - const char *protocol, - const char *netid) +static void xs_format_common_peer_addresses(struct rpc_xprt *xprt) { - struct sockaddr_in *addr = xs_addr_in(xprt); - char *buf; - - buf = kzalloc(20, GFP_KERNEL); - if (buf) { - snprintf(buf, 20, "%pI4", &addr->sin_addr.s_addr); - } - xprt->address_strings[RPC_DISPLAY_ADDR] = buf; + struct sockaddr *sap = xs_addr(xprt); + char buf[128]; - buf = kzalloc(8, GFP_KERNEL); - if (buf) { - snprintf(buf, 8, "%u", - ntohs(addr->sin_port)); - } - xprt->address_strings[RPC_DISPLAY_PORT] = buf; + (void)rpc_ntop(sap, buf, sizeof(buf)); + xprt->address_strings[RPC_DISPLAY_ADDR] = kstrdup(buf, GFP_KERNEL); - xprt->address_strings[RPC_DISPLAY_PROTO] = protocol; + (void)snprintf(buf, sizeof(buf), "%u", rpc_get_port(sap)); + xprt->address_strings[RPC_DISPLAY_PORT] = kstrdup(buf, GFP_KERNEL); - buf = kzalloc(48, GFP_KERNEL); - if (buf) { - snprintf(buf, 48, "addr=%pI4 port=%u proto=%s", - &addr->sin_addr.s_addr, - ntohs(addr->sin_port), - protocol); - } - xprt->address_strings[RPC_DISPLAY_ALL] = buf; + (void)snprintf(buf, sizeof(buf), "addr=%s port=%s proto=%s", + xprt->address_strings[RPC_DISPLAY_ADDR], + xprt->address_strings[RPC_DISPLAY_PORT], + xprt->address_strings[RPC_DISPLAY_PROTO]); + xprt->address_strings[RPC_DISPLAY_ALL] = kstrdup(buf, GFP_KERNEL); - buf = kzalloc(10, GFP_KERNEL); - if (buf) { - snprintf(buf, 10, "%02x%02x%02x%02x", - NIPQUAD(addr->sin_addr.s_addr)); - } - xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf; + (void)snprintf(buf, sizeof(buf), "%4hx", rpc_get_port(sap)); + xprt->address_strings[RPC_DISPLAY_HEX_PORT] = kstrdup(buf, GFP_KERNEL); +} - buf = kzalloc(8, GFP_KERNEL); - if (buf) { - snprintf(buf, 8, "%4hx", - ntohs(addr->sin_port)); - } - xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf; +static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt, + const char *protocol, + const char *netid) +{ + struct sockaddr_in *sin = xs_addr_in(xprt); + char buf[16]; + xprt->address_strings[RPC_DISPLAY_PROTO] = protocol; xprt->address_strings[RPC_DISPLAY_NETID] = netid; + + (void)snprintf(buf, sizeof(buf), "%02x%02x%02x%02x", + NIPQUAD(sin->sin_addr.s_addr)); + xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL); + + xs_format_common_peer_addresses(xprt); } static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt, const char *protocol, const char *netid) { - struct sockaddr_in6 *addr = xs_addr_in6(xprt); - char *buf; - - buf = kzalloc(40, GFP_KERNEL); - if (buf) { - snprintf(buf, 40, "%pI6",&addr->sin6_addr); - } - xprt->address_strings[RPC_DISPLAY_ADDR] = buf; - - buf = kzalloc(8, GFP_KERNEL); - if (buf) { - snprintf(buf, 8, "%u", - ntohs(addr->sin6_port)); - } - xprt->address_strings[RPC_DISPLAY_PORT] = buf; + struct sockaddr_in6 *sin6 = xs_addr_in6(xprt); + char buf[48]; xprt->address_strings[RPC_DISPLAY_PROTO] = protocol; + xprt->address_strings[RPC_DISPLAY_NETID] = netid; - buf = kzalloc(64, GFP_KERNEL); - if (buf) { - snprintf(buf, 64, "addr=%pI6 port=%u proto=%s", - &addr->sin6_addr, - ntohs(addr->sin6_port), - protocol); - } - xprt->address_strings[RPC_DISPLAY_ALL] = buf; - - buf = kzalloc(36, GFP_KERNEL); - if (buf) - snprintf(buf, 36, "%pi6", &addr->sin6_addr); - - xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf; - - buf = kzalloc(8, GFP_KERNEL); - if (buf) { - snprintf(buf, 8, "%4hx", - ntohs(addr->sin6_port)); - } - xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf; + (void)snprintf(buf, sizeof(buf), "%pi6", &sin6->sin6_addr); + xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL); - xprt->address_strings[RPC_DISPLAY_NETID] = netid; + xs_format_common_peer_addresses(xprt); } static void xs_free_peer_addresses(struct rpc_xprt *xprt) -- cgit v0.10.2 From 53a0b9c4c99ab0085a06421f71592722e5b3fd5f Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:36 -0400 Subject: NFS: Replace nfs_parse_ip_address() with rpc_pton() Clean up: Use the common routine now provided in sunrpc.ko for parsing mount addresses. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index ff68397..cf1da3e 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -214,7 +214,6 @@ void nfs_zap_acl_cache(struct inode *inode); extern int nfs_wait_bit_killable(void *word); /* super.c */ -void nfs_parse_ip_address(char *, size_t, struct sockaddr *, size_t *); extern struct file_system_type nfs_xdev_fs_type; #ifdef CONFIG_NFS_V4 extern struct file_system_type nfs4_xdev_fs_type; diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 2a2a0a7..43c86b7 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -121,9 +121,9 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) continue; - nfs_parse_ip_address(buf->data, buf->len, - mountdata->addr, &mountdata->addrlen); - if (mountdata->addr->sa_family == AF_UNSPEC) + mountdata->addrlen = rpc_pton(buf->data, buf->len, + mountdata->addr, mountdata->addrlen); + if (mountdata->addrlen == 0) continue; nfs_set_port(mountdata->addr, NFS_PORT); diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 8526008..1eeba8e 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -742,129 +742,10 @@ static int nfs_verify_server_address(struct sockaddr *addr) } } + dfprintk(MOUNT, "NFS: Invalid IP address specified\n"); return 0; } -static void nfs_parse_ipv4_address(char *string, size_t str_len, - struct sockaddr *sap, size_t *addr_len) -{ - struct sockaddr_in *sin = (struct sockaddr_in *)sap; - u8 *addr = (u8 *)&sin->sin_addr.s_addr; - - if (str_len <= INET_ADDRSTRLEN) { - dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n", - (int)str_len, string); - - sin->sin_family = AF_INET; - *addr_len = sizeof(*sin); - if (in4_pton(string, str_len, addr, '\0', NULL)) - return; - } - - sap->sa_family = AF_UNSPEC; - *addr_len = 0; -} - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len, - const char *delim, - struct sockaddr_in6 *sin6) -{ - char *p; - size_t len; - - if ((string + str_len) == delim) - return 1; - - if (*delim != IPV6_SCOPE_DELIMITER) - return 0; - - if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) - return 0; - - len = (string + str_len) - delim - 1; - p = kstrndup(delim + 1, len, GFP_KERNEL); - if (p) { - unsigned long scope_id = 0; - struct net_device *dev; - - dev = dev_get_by_name(&init_net, p); - if (dev != NULL) { - scope_id = dev->ifindex; - dev_put(dev); - } else { - if (strict_strtoul(p, 10, &scope_id) == 0) { - kfree(p); - return 0; - } - } - - kfree(p); - - sin6->sin6_scope_id = scope_id; - dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id); - return 1; - } - - return 0; -} - -static void nfs_parse_ipv6_address(char *string, size_t str_len, - struct sockaddr *sap, size_t *addr_len) -{ - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; - u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; - const char *delim; - - if (str_len <= INET6_ADDRSTRLEN) { - dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n", - (int)str_len, string); - - sin6->sin6_family = AF_INET6; - *addr_len = sizeof(*sin6); - if (in6_pton(string, str_len, addr, - IPV6_SCOPE_DELIMITER, &delim) != 0) { - if (nfs_parse_ipv6_scope_id(string, str_len, - delim, sin6) != 0) - return; - } - } - - sap->sa_family = AF_UNSPEC; - *addr_len = 0; -} -#else -static void nfs_parse_ipv6_address(char *string, size_t str_len, - struct sockaddr *sap, size_t *addr_len) -{ - sap->sa_family = AF_UNSPEC; - *addr_len = 0; -} -#endif - -/* - * Construct a sockaddr based on the contents of a string that contains - * an IP address in presentation format. - * - * If there is a problem constructing the new sockaddr, set the address - * family to AF_UNSPEC. - */ -void nfs_parse_ip_address(char *string, size_t str_len, - struct sockaddr *sap, size_t *addr_len) -{ - unsigned int i, colons; - - colons = 0; - for (i = 0; i < str_len; i++) - if (string[i] == ':') - colons++; - - if (colons >= 2) - nfs_parse_ipv6_address(string, str_len, sap, addr_len); - else - nfs_parse_ipv4_address(string, str_len, sap, addr_len); -} - /* * Sanity check the NFS transport protocol. * @@ -1344,11 +1225,14 @@ static int nfs_parse_mount_options(char *raw, string = match_strdup(args); if (string == NULL) goto out_nomem; - nfs_parse_ip_address(string, strlen(string), - (struct sockaddr *) - &mnt->nfs_server.address, - &mnt->nfs_server.addrlen); + mnt->nfs_server.addrlen = + rpc_pton(string, strlen(string), + (struct sockaddr *) + &mnt->nfs_server.address, + sizeof(mnt->nfs_server.address)); kfree(string); + if (mnt->nfs_server.addrlen == 0) + goto out_invalid_address; break; case Opt_clientaddr: string = match_strdup(args); @@ -1368,11 +1252,14 @@ static int nfs_parse_mount_options(char *raw, string = match_strdup(args); if (string == NULL) goto out_nomem; - nfs_parse_ip_address(string, strlen(string), - (struct sockaddr *) - &mnt->mount_server.address, - &mnt->mount_server.addrlen); + mnt->mount_server.addrlen = + rpc_pton(string, strlen(string), + (struct sockaddr *) + &mnt->mount_server.address, + sizeof(mnt->mount_server.address)); kfree(string); + if (mnt->mount_server.addrlen == 0) + goto out_invalid_address; break; case Opt_lookupcache: string = match_strdup(args); @@ -1424,8 +1311,11 @@ static int nfs_parse_mount_options(char *raw, return 1; +out_invalid_address: + printk(KERN_INFO "NFS: bad IP address specified: %s\n", p); + return 0; out_invalid_value: - printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p); + printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p); return 0; out_nomem: printk(KERN_INFO "NFS: not enough memory to parse option\n"); -- cgit v0.10.2 From ec6ee61250acfccbc5578dd4014735fb2cbe53b5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:37 -0400 Subject: NFS: Replace nfs_set_port() with rpc_set_port() Clean up. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index cf1da3e..c2f171a 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -368,22 +368,3 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len) return ((unsigned long)len + (unsigned long)base + PAGE_SIZE - 1) >> PAGE_SHIFT; } - -/* - * Set the port number in an address. Be agnostic about the address - * family. - */ -static inline void nfs_set_port(struct sockaddr *sap, unsigned short port) -{ - struct sockaddr_in *ap = (struct sockaddr_in *)sap; - struct sockaddr_in6 *ap6 = (struct sockaddr_in6 *)sap; - - switch (sap->sa_family) { - case AF_INET: - ap->sin_port = htons(port); - break; - case AF_INET6: - ap6->sin6_port = htons(port); - break; - } -} diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 43c86b7..ef22ee8 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -125,7 +125,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, mountdata->addr, mountdata->addrlen); if (mountdata->addrlen == 0) continue; - nfs_set_port(mountdata->addr, NFS_PORT); + rpc_set_port(mountdata->addr, NFS_PORT); memcpy(page2, buf->data, buf->len); page2[buf->len] = '\0'; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 1eeba8e..9c85cdb 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1409,7 +1409,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, /* * autobind will be used if mount_server.port == 0 */ - nfs_set_port(request.sap, args->mount_server.port); + rpc_set_port(request.sap, args->mount_server.port); /* * Now ask the mount server to map our export path @@ -1703,7 +1703,7 @@ static int nfs_validate_mount_data(void *options, &args->nfs_server.address)) goto out_no_address; - nfs_set_port((struct sockaddr *)&args->nfs_server.address, + rpc_set_port((struct sockaddr *)&args->nfs_server.address, args->nfs_server.port); nfs_set_mount_transport_protocol(args); @@ -2336,7 +2336,7 @@ static int nfs4_validate_mount_data(void *options, &args->nfs_server.address)) return -EINVAL; - nfs_set_port((struct sockaddr *)&args->nfs_server.address, + rpc_set_port((struct sockaddr *)&args->nfs_server.address, args->nfs_server.port); nfs_validate_transport_protocol(args); -- cgit v0.10.2 From b97a56747ea3f6c1a27dd0719bf1424959f1ebae Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:38 -0400 Subject: lockd: Replace nlm_clear_port() Clean up: Use shared rpc_set_port() function instead of nlm_clear_port(). Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 99d737b..7cb076a 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -87,18 +87,6 @@ static unsigned int nlm_hash_address(const struct sockaddr *sap) return hash & (NLM_HOST_NRHASH - 1); } -static void nlm_clear_port(struct sockaddr *sap) -{ - switch (sap->sa_family) { - case AF_INET: - ((struct sockaddr_in *)sap)->sin_port = 0; - break; - case AF_INET6: - ((struct sockaddr_in6 *)sap)->sin6_port = 0; - break; - } -} - /* * Common host lookup routine for server & client */ @@ -177,7 +165,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) host->h_addrbuf = nsm->sm_addrbuf; memcpy(nlm_addr(host), ni->sap, ni->salen); host->h_addrlen = ni->salen; - nlm_clear_port(nlm_addr(host)); + rpc_set_port(nlm_addr(host), 0); memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len); host->h_version = ni->version; host->h_proto = ni->protocol; -- cgit v0.10.2 From c15128c5e428af1e8ada1476484a74c970665edd Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:39 -0400 Subject: lockd: Replace nsm_display_address() with rpc_ntop() Clean up. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 7fce1b5..30c9331 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -61,43 +61,6 @@ static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) return (struct sockaddr *)&nsm->sm_addr; } -static void nsm_display_ipv4_address(const struct sockaddr *sap, char *buf, - const size_t len) -{ - const struct sockaddr_in *sin = (struct sockaddr_in *)sap; - snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr); -} - -static void nsm_display_ipv6_address(const struct sockaddr *sap, char *buf, - const size_t len) -{ - const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; - - if (ipv6_addr_v4mapped(&sin6->sin6_addr)) - snprintf(buf, len, "%pI4", &sin6->sin6_addr.s6_addr32[3]); - else if (sin6->sin6_scope_id != 0) - snprintf(buf, len, "%pI6%%%u", &sin6->sin6_addr, - sin6->sin6_scope_id); - else - snprintf(buf, len, "%pI6", &sin6->sin6_addr); -} - -static void nsm_display_address(const struct sockaddr *sap, - char *buf, const size_t len) -{ - switch (sap->sa_family) { - case AF_INET: - nsm_display_ipv4_address(sap, buf, len); - break; - case AF_INET6: - nsm_display_ipv6_address(sap, buf, len); - break; - default: - snprintf(buf, len, "unsupported address family"); - break; - } -} - static struct rpc_clnt *nsm_create(void) { struct sockaddr_in sin = { @@ -307,8 +270,11 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, memcpy(nsm_addr(new), sap, salen); new->sm_addrlen = salen; nsm_init_private(new); - nsm_display_address((const struct sockaddr *)&new->sm_addr, - new->sm_addrbuf, sizeof(new->sm_addrbuf)); + + if (rpc_ntop(nsm_addr(new), new->sm_addrbuf, + sizeof(new->sm_addrbuf)) == 0) + (void)snprintf(new->sm_addrbuf, sizeof(new->sm_addrbuf), + "unsupported address family"); memcpy(new->sm_name, hostname, hostname_len); new->sm_name[hostname_len] = '\0'; -- cgit v0.10.2 From 4116092b92f859e5e9a90c99d740933e651ee8c0 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:40 -0400 Subject: NFSD: Support IPv6 addresses in write_failover_ip() In write_failover_ip(), replace the sscanf() with a call to the common sunrpc.ko presentation address parser. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 6d08475..7e906c5 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -490,22 +491,18 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size) * * Input: * buf: '\n'-terminated C string containing a - * presentation format IPv4 address + * presentation format IP address * size: length of C string in @buf * Output: * On success: returns zero if all specified locks were released; * returns one if one or more locks were not released * On error: return code is negative errno value - * - * Note: Only AF_INET client addresses are passed in */ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size) { - struct sockaddr_in sin = { - .sin_family = AF_INET, - }; - int b1, b2, b3, b4; - char c; + struct sockaddr_storage address; + struct sockaddr *sap = (struct sockaddr *)&address; + size_t salen = sizeof(address); char *fo_path; /* sanity check */ @@ -519,14 +516,10 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size) if (qword_get(&buf, fo_path, size) < 0) return -EINVAL; - /* get ipv4 address */ - if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) - return -EINVAL; - if (b1 > 255 || b2 > 255 || b3 > 255 || b4 > 255) + if (rpc_pton(fo_path, size, sap, salen) == 0) return -EINVAL; - sin.sin_addr.s_addr = htonl((b1 << 24) | (b2 << 16) | (b3 << 8) | b4); - return nlmsvc_unlock_all_by_ip((struct sockaddr *)&sin); + return nlmsvc_unlock_all_by_ip(sap); } /** -- cgit v0.10.2 From 6f2c2db7a46243bd86e3d7ff5f9ff982f26a9fe8 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:40 -0400 Subject: SUNRPC: Introduce new xdr_stream-based encoders to rpcb_clnt.c Replace the open-coded encode logic for rpcbind arguments with an xdr_stream-based implementation, similar to what NFSv4 uses, to better protect against buffer overflows. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 1fb1c07..823d20d 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -708,6 +708,30 @@ static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p, return 0; } +static int rpcb_enc_mapping(struct rpc_rqst *req, __be32 *p, + const struct rpcbind_args *rpcb) +{ + struct rpc_task *task = req->rq_task; + struct xdr_stream xdr; + + dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n", + task->tk_pid, task->tk_msg.rpc_proc->p_name, + rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port); + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + + p = xdr_reserve_space(&xdr, sizeof(__be32) * RPCB_mappingargs_sz); + if (unlikely(p == NULL)) + return -EIO; + + *p++ = htonl(rpcb->r_prog); + *p++ = htonl(rpcb->r_vers); + *p++ = htonl(rpcb->r_prot); + *p = htonl(rpcb->r_port); + + return 0; +} + static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p, unsigned short *portp) { @@ -746,6 +770,56 @@ static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p, return 0; } +static int encode_rpcb_string(struct xdr_stream *xdr, const char *string, + const u32 maxstrlen) +{ + u32 len; + __be32 *p; + + if (unlikely(string == NULL)) + return -EIO; + len = strlen(string); + if (unlikely(len > maxstrlen)) + return -EIO; + + p = xdr_reserve_space(xdr, sizeof(__be32) + len); + if (unlikely(p == NULL)) + return -EIO; + xdr_encode_opaque(p, string, len); + + return 0; +} + +static int rpcb_enc_getaddr(struct rpc_rqst *req, __be32 *p, + const struct rpcbind_args *rpcb) +{ + struct rpc_task *task = req->rq_task; + struct xdr_stream xdr; + + dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n", + task->tk_pid, task->tk_msg.rpc_proc->p_name, + rpcb->r_prog, rpcb->r_vers, + rpcb->r_netid, rpcb->r_addr); + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + + p = xdr_reserve_space(&xdr, + sizeof(__be32) * (RPCB_program_sz + RPCB_version_sz)); + if (unlikely(p == NULL)) + return -EIO; + *p++ = htonl(rpcb->r_prog); + *p = htonl(rpcb->r_vers); + + if (encode_rpcb_string(&xdr, rpcb->r_netid, RPCBIND_MAXNETIDLEN)) + return -EIO; + if (encode_rpcb_string(&xdr, rpcb->r_addr, RPCBIND_MAXUADDRLEN)) + return -EIO; + if (encode_rpcb_string(&xdr, rpcb->r_owner, RPCB_MAXOWNERLEN)) + return -EIO; + + return 0; +} + static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, unsigned short *portp) { @@ -812,7 +886,7 @@ out_err: #define PROC(proc, argtype, restype) \ [RPCBPROC_##proc] = { \ .p_proc = RPCBPROC_##proc, \ - .p_encode = (kxdrproc_t) rpcb_encode_##argtype, \ + .p_encode = (kxdrproc_t) rpcb_enc_##argtype, \ .p_decode = (kxdrproc_t) rpcb_decode_##restype, \ .p_arglen = RPCB_##argtype##args_sz, \ .p_replen = RPCB_##restype##res_sz, \ -- cgit v0.10.2 From 0d36c4f7574d5a33bedd8f0e3c793490d45d83c6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:41 -0400 Subject: SUNRPC: Clean up: Remove unused XDR encoder functions from rpcb_clnt.c Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 823d20d..e0d7b31 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -694,20 +694,6 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) * XDR functions for rpcbind */ -static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p, - struct rpcbind_args *rpcb) -{ - dprintk("RPC: encoding rpcb request (%u, %u, %d, %u)\n", - rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port); - *p++ = htonl(rpcb->r_prog); - *p++ = htonl(rpcb->r_vers); - *p++ = htonl(rpcb->r_prot); - *p++ = htonl(rpcb->r_port); - - req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); - return 0; -} - static int rpcb_enc_mapping(struct rpc_rqst *req, __be32 *p, const struct rpcbind_args *rpcb) { @@ -750,26 +736,6 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p, return 0; } -static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p, - struct rpcbind_args *rpcb) -{ - if (rpcb->r_addr == NULL) - return -EIO; - - dprintk("RPC: encoding rpcb request (%u, %u, %s)\n", - rpcb->r_prog, rpcb->r_vers, rpcb->r_addr); - *p++ = htonl(rpcb->r_prog); - *p++ = htonl(rpcb->r_vers); - - p = xdr_encode_string(p, rpcb->r_netid); - p = xdr_encode_string(p, rpcb->r_addr); - p = xdr_encode_string(p, rpcb->r_owner); - - req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); - - return 0; -} - static int encode_rpcb_string(struct xdr_stream *xdr, const char *string, const u32 maxstrlen) { -- cgit v0.10.2 From 7ed0ff983c8ad30bf4e2b9fdbb299a3e3ec08d08 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:42 -0400 Subject: SUNRPC: Introduce xdr_stream-based decoders for RPCB_UNSET Replace the open-coded decode logic for rpcbind UNSET results with an xdr_stream-based implementation, similar to what NFSv4 uses, to protect against buffer overflows. The new function is unused for the moment. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index e0d7b31..fe183af 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -736,6 +736,28 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p, return 0; } +static int rpcb_dec_set(struct rpc_rqst *req, __be32 *p, + unsigned int *boolp) +{ + struct rpc_task *task = req->rq_task; + struct xdr_stream xdr; + + xdr_init_decode(&xdr, &req->rq_rcv_buf, p); + + p = xdr_inline_decode(&xdr, sizeof(__be32)); + if (unlikely(p == NULL)) + return -EIO; + + *boolp = 0; + if (*p) + *boolp = 1; + + dprintk("RPC: %5u RPCB_%s call %s\n", + task->tk_pid, task->tk_msg.rpc_proc->p_name, + (*boolp ? "succeeded" : "failed")); + return 0; +} + static int encode_rpcb_string(struct xdr_stream *xdr, const char *string, const u32 maxstrlen) { -- cgit v0.10.2 From c0c077df009f2f329875051ac5283df235288689 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:43 -0400 Subject: SUNRPC: Introduce new xdr_stream-based decoders to rpcb_clnt.c Replace the open-coded decode logic for PMAP_GETPORT/RPCB_GETADDR with an xdr_stream-based implementation, similar to what NFSv4 uses, to protect against buffer overflows. The new implementation also checks that the incoming port number is reasonable. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index fe183af..88de754e 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -454,7 +454,7 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot) struct rpc_message msg = { .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT], .rpc_argp = &map, - .rpc_resp = &map.r_port, + .rpc_resp = &map, }; struct rpc_clnt *rpcb_clnt; int status; @@ -484,7 +484,7 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi struct rpc_message msg = { .rpc_proc = proc, .rpc_argp = map, - .rpc_resp = &map->r_port, + .rpc_resp = map, }; struct rpc_task_setup task_setup_data = { .rpc_client = rpcb_clnt, @@ -727,6 +727,31 @@ static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p, return 0; } +static int rpcb_dec_getport(struct rpc_rqst *req, __be32 *p, + struct rpcbind_args *rpcb) +{ + struct rpc_task *task = req->rq_task; + struct xdr_stream xdr; + unsigned long port; + + xdr_init_decode(&xdr, &req->rq_rcv_buf, p); + + rpcb->r_port = 0; + + p = xdr_inline_decode(&xdr, sizeof(__be32)); + if (unlikely(p == NULL)) + return -EIO; + + port = ntohl(*p); + dprintk("RPC: %5u PMAP_%s result: %lu\n", task->tk_pid, + task->tk_msg.rpc_proc->p_name, port); + if (unlikely(port > USHORT_MAX)) + return -EIO; + + rpcb->r_port = port; + return 0; +} + static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p, unsigned int *boolp) { @@ -871,11 +896,60 @@ out_err: return -EIO; } +static int rpcb_dec_getaddr(struct rpc_rqst *req, __be32 *p, + struct rpcbind_args *rpcb) +{ + struct sockaddr_storage address; + struct sockaddr *sap = (struct sockaddr *)&address; + struct rpc_task *task = req->rq_task; + struct xdr_stream xdr; + u32 len; + + rpcb->r_port = 0; + + xdr_init_decode(&xdr, &req->rq_rcv_buf, p); + + p = xdr_inline_decode(&xdr, sizeof(__be32)); + if (unlikely(p == NULL)) + goto out_fail; + len = ntohl(*p); + + /* + * If the returned universal address is a null string, + * the requested RPC service was not registered. + */ + if (len == 0) { + dprintk("RPC: %5u RPCB reply: program not registered\n", + task->tk_pid); + return 0; + } + + if (unlikely(len > RPCBIND_MAXUADDRLEN)) + goto out_fail; + + p = xdr_inline_decode(&xdr, len); + if (unlikely(p == NULL)) + goto out_fail; + dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid, + task->tk_msg.rpc_proc->p_name, (char *)p); + + if (rpc_uaddr2sockaddr((char *)p, len, sap, sizeof(address)) == 0) + goto out_fail; + rpcb->r_port = rpc_get_port(sap); + + return 0; + +out_fail: + dprintk("RPC: %5u malformed RPCB_%s reply\n", + task->tk_pid, task->tk_msg.rpc_proc->p_name); + return -EIO; +} + #define PROC(proc, argtype, restype) \ [RPCBPROC_##proc] = { \ .p_proc = RPCBPROC_##proc, \ .p_encode = (kxdrproc_t) rpcb_enc_##argtype, \ - .p_decode = (kxdrproc_t) rpcb_decode_##restype, \ + .p_decode = (kxdrproc_t) rpcb_dec_##restype, \ .p_arglen = RPCB_##argtype##args_sz, \ .p_replen = RPCB_##restype##res_sz, \ .p_statidx = RPCBPROC_##proc, \ -- cgit v0.10.2 From 0e47f0d665efcf1b45f293422d21d8383f07d122 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:43 -0400 Subject: SUNRPC: Clean up: Remove unused XDR decoder functions from rpcb_clnt.c Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 88de754e..c4b716c 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -718,15 +718,6 @@ static int rpcb_enc_mapping(struct rpc_rqst *req, __be32 *p, return 0; } -static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p, - unsigned short *portp) -{ - *portp = (unsigned short) ntohl(*p++); - dprintk("RPC: rpcb getport result: %u\n", - *portp); - return 0; -} - static int rpcb_dec_getport(struct rpc_rqst *req, __be32 *p, struct rpcbind_args *rpcb) { @@ -752,15 +743,6 @@ static int rpcb_dec_getport(struct rpc_rqst *req, __be32 *p, return 0; } -static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p, - unsigned int *boolp) -{ - *boolp = (unsigned int) ntohl(*p++); - dprintk("RPC: rpcb set/unset call %s\n", - (*boolp ? "succeeded" : "failed")); - return 0; -} - static int rpcb_dec_set(struct rpc_rqst *req, __be32 *p, unsigned int *boolp) { @@ -833,69 +815,6 @@ static int rpcb_enc_getaddr(struct rpc_rqst *req, __be32 *p, return 0; } -static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, - unsigned short *portp) -{ - char *addr; - u32 addr_len; - int c, i, f, first, val; - - *portp = 0; - addr_len = ntohl(*p++); - - if (addr_len == 0) { - dprintk("RPC: rpcb_decode_getaddr: " - "service is not registered\n"); - return 0; - } - - /* - * Simple sanity check. - */ - if (addr_len > RPCBIND_MAXUADDRLEN) - goto out_err; - - /* - * Start at the end and walk backwards until the first dot - * is encountered. When the second dot is found, we have - * both parts of the port number. - */ - addr = (char *)p; - val = 0; - first = 1; - f = 1; - for (i = addr_len - 1; i > 0; i--) { - c = addr[i]; - if (c >= '0' && c <= '9') { - val += (c - '0') * f; - f *= 10; - } else if (c == '.') { - if (first) { - *portp = val; - val = first = 0; - f = 1; - } else { - *portp |= (val << 8); - break; - } - } - } - - /* - * Simple sanity check. If we never saw a dot in the reply, - * then this was probably just garbage. - */ - if (first) - goto out_err; - - dprintk("RPC: rpcb_decode_getaddr port=%u\n", *portp); - return 0; - -out_err: - dprintk("RPC: rpcbind server returned malformed reply\n"); - return -EIO; -} - static int rpcb_dec_getaddr(struct rpc_rqst *req, __be32 *p, struct rpcbind_args *rpcb) { -- cgit v0.10.2 From f8b761eff1e49fde43dd940ac32b38cf7cee2a95 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:44 -0400 Subject: SUNRPC: Eliminate PROC macro from rpcb_clnt Clean up: Replace PROC macro with open coded C99 structure initializers to improve readability. The rpcbind v4 GETVERSADDR procedure is never sent by the current implementation, so it is not copied to the new structures. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index c4b716c..830faf4 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -864,39 +864,108 @@ out_fail: return -EIO; } -#define PROC(proc, argtype, restype) \ - [RPCBPROC_##proc] = { \ - .p_proc = RPCBPROC_##proc, \ - .p_encode = (kxdrproc_t) rpcb_enc_##argtype, \ - .p_decode = (kxdrproc_t) rpcb_dec_##restype, \ - .p_arglen = RPCB_##argtype##args_sz, \ - .p_replen = RPCB_##restype##res_sz, \ - .p_statidx = RPCBPROC_##proc, \ - .p_timer = 0, \ - .p_name = #proc, \ - } - /* * Not all rpcbind procedures described in RFC 1833 are implemented * since the Linux kernel RPC code requires only these. */ + static struct rpc_procinfo rpcb_procedures2[] = { - PROC(SET, mapping, set), - PROC(UNSET, mapping, set), - PROC(GETPORT, mapping, getport), + [RPCBPROC_SET] = { + .p_proc = RPCBPROC_SET, + .p_encode = (kxdrproc_t)rpcb_enc_mapping, + .p_decode = (kxdrproc_t)rpcb_dec_set, + .p_arglen = RPCB_mappingargs_sz, + .p_replen = RPCB_setres_sz, + .p_statidx = RPCBPROC_SET, + .p_timer = 0, + .p_name = "SET", + }, + [RPCBPROC_UNSET] = { + .p_proc = RPCBPROC_UNSET, + .p_encode = (kxdrproc_t)rpcb_enc_mapping, + .p_decode = (kxdrproc_t)rpcb_dec_set, + .p_arglen = RPCB_mappingargs_sz, + .p_replen = RPCB_setres_sz, + .p_statidx = RPCBPROC_UNSET, + .p_timer = 0, + .p_name = "UNSET", + }, + [RPCBPROC_GETPORT] = { + .p_proc = RPCBPROC_GETPORT, + .p_encode = (kxdrproc_t)rpcb_enc_mapping, + .p_decode = (kxdrproc_t)rpcb_dec_getport, + .p_arglen = RPCB_mappingargs_sz, + .p_replen = RPCB_getportres_sz, + .p_statidx = RPCBPROC_GETPORT, + .p_timer = 0, + .p_name = "GETPORT", + }, }; static struct rpc_procinfo rpcb_procedures3[] = { - PROC(SET, getaddr, set), - PROC(UNSET, getaddr, set), - PROC(GETADDR, getaddr, getaddr), + [RPCBPROC_SET] = { + .p_proc = RPCBPROC_SET, + .p_encode = (kxdrproc_t)rpcb_enc_getaddr, + .p_decode = (kxdrproc_t)rpcb_dec_set, + .p_arglen = RPCB_getaddrargs_sz, + .p_replen = RPCB_setres_sz, + .p_statidx = RPCBPROC_SET, + .p_timer = 0, + .p_name = "SET", + }, + [RPCBPROC_UNSET] = { + .p_proc = RPCBPROC_UNSET, + .p_encode = (kxdrproc_t)rpcb_enc_getaddr, + .p_decode = (kxdrproc_t)rpcb_dec_set, + .p_arglen = RPCB_getaddrargs_sz, + .p_replen = RPCB_setres_sz, + .p_statidx = RPCBPROC_UNSET, + .p_timer = 0, + .p_name = "UNSET", + }, + [RPCBPROC_GETADDR] = { + .p_proc = RPCBPROC_GETADDR, + .p_encode = (kxdrproc_t)rpcb_enc_getaddr, + .p_decode = (kxdrproc_t)rpcb_dec_getaddr, + .p_arglen = RPCB_getaddrargs_sz, + .p_replen = RPCB_getaddrres_sz, + .p_statidx = RPCBPROC_GETADDR, + .p_timer = 0, + .p_name = "GETADDR", + }, }; static struct rpc_procinfo rpcb_procedures4[] = { - PROC(SET, getaddr, set), - PROC(UNSET, getaddr, set), - PROC(GETADDR, getaddr, getaddr), - PROC(GETVERSADDR, getaddr, getaddr), + [RPCBPROC_SET] = { + .p_proc = RPCBPROC_SET, + .p_encode = (kxdrproc_t)rpcb_enc_getaddr, + .p_decode = (kxdrproc_t)rpcb_dec_set, + .p_arglen = RPCB_getaddrargs_sz, + .p_replen = RPCB_setres_sz, + .p_statidx = RPCBPROC_SET, + .p_timer = 0, + .p_name = "SET", + }, + [RPCBPROC_UNSET] = { + .p_proc = RPCBPROC_UNSET, + .p_encode = (kxdrproc_t)rpcb_enc_getaddr, + .p_decode = (kxdrproc_t)rpcb_dec_set, + .p_arglen = RPCB_getaddrargs_sz, + .p_replen = RPCB_setres_sz, + .p_statidx = RPCBPROC_UNSET, + .p_timer = 0, + .p_name = "UNSET", + }, + [RPCBPROC_GETADDR] = { + .p_proc = RPCBPROC_GETADDR, + .p_encode = (kxdrproc_t)rpcb_enc_getaddr, + .p_decode = (kxdrproc_t)rpcb_dec_getaddr, + .p_arglen = RPCB_getaddrargs_sz, + .p_replen = RPCB_getaddrres_sz, + .p_statidx = RPCBPROC_GETADDR, + .p_timer = 0, + .p_name = "GETADDR", + }, }; static struct rpcb_info rpcb_next_version[] = { -- cgit v0.10.2 From fbfffbd5e74c5fa8c9165e110cb5899ec21e6364 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:46 -0400 Subject: SUNRPC: Rename sock_xprt.addr as sock_xprt.srcaddr Clean up: Give the "addr" and "port" field less ambiguous names. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 302a409..7bc3c17 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -248,8 +248,8 @@ struct sock_xprt { * Connection of transports */ struct delayed_work connect_worker; - struct sockaddr_storage addr; - unsigned short port; + struct sockaddr_storage srcaddr; + unsigned short srcport; /* * UDP socket buffer size parameters @@ -1546,7 +1546,7 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket *sock) { - unsigned short port = transport->port; + unsigned short port = transport->srcport; if (port == 0 && transport->xprt.resvport) port = xs_get_random_port(); @@ -1555,8 +1555,8 @@ static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket static unsigned short xs_next_srcport(struct sock_xprt *transport, struct socket *sock, unsigned short port) { - if (transport->port != 0) - transport->port = 0; + if (transport->srcport != 0) + transport->srcport = 0; if (!transport->xprt.resvport) return 0; if (port <= xprt_min_resvport || port > xprt_max_resvport) @@ -1574,7 +1574,7 @@ static int xs_bind4(struct sock_xprt *transport, struct socket *sock) unsigned short port = xs_get_srcport(transport, sock); unsigned short last; - sa = (struct sockaddr_in *)&transport->addr; + sa = (struct sockaddr_in *)&transport->srcaddr; myaddr.sin_addr = sa->sin_addr; do { myaddr.sin_port = htons(port); @@ -1583,7 +1583,7 @@ static int xs_bind4(struct sock_xprt *transport, struct socket *sock) if (port == 0) break; if (err == 0) { - transport->port = port; + transport->srcport = port; break; } last = port; @@ -1607,7 +1607,7 @@ static int xs_bind6(struct sock_xprt *transport, struct socket *sock) unsigned short port = xs_get_srcport(transport, sock); unsigned short last; - sa = (struct sockaddr_in6 *)&transport->addr; + sa = (struct sockaddr_in6 *)&transport->srcaddr; myaddr.sin6_addr = sa->sin6_addr; do { myaddr.sin6_port = htons(port); @@ -1616,7 +1616,7 @@ static int xs_bind6(struct sock_xprt *transport, struct socket *sock) if (port == 0) break; if (err == 0) { - transport->port = port; + transport->srcport = port; break; } last = port; @@ -2061,7 +2061,7 @@ static void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %Lu %Lu\n", - transport->port, + transport->srcport, xprt->stat.bind_count, xprt->stat.sends, xprt->stat.recvs, @@ -2085,7 +2085,7 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) idle_time = (long)(jiffies - xprt->last_used) / HZ; seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu\n", - transport->port, + transport->srcport, xprt->stat.bind_count, xprt->stat.connect_count, xprt->stat.connect_time, @@ -2164,7 +2164,7 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, memcpy(&xprt->addr, args->dstaddr, args->addrlen); xprt->addrlen = args->addrlen; if (args->srcaddr) - memcpy(&new->addr, args->srcaddr, args->addrlen); + memcpy(&new->srcaddr, args->srcaddr, args->addrlen); return xprt; } -- cgit v0.10.2 From c740eff84bcfd63c0497ef880e80171931cb8222 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:46 -0400 Subject: SUNRPC: Kill RPC_DISPLAY_ALL At some point, I recall that rpc_pipe_fs used RPC_DISPLAY_ALL. Currently there are no uses of RPC_DISPLAY_ALL outside the transport modules themselves, so we can safely get rid of it. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 65fad95..c090df4 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -38,7 +38,6 @@ enum rpc_display_format_t { RPC_DISPLAY_ADDR = 0, RPC_DISPLAY_PORT, RPC_DISPLAY_PROTO, - RPC_DISPLAY_ALL, RPC_DISPLAY_HEX_ADDR, RPC_DISPLAY_HEX_PORT, RPC_DISPLAY_NETID, diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 5f9b867..9a63f66 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -181,11 +181,6 @@ xprt_rdma_format_addresses(struct rpc_xprt *xprt) xprt->address_strings[RPC_DISPLAY_PROTO] = "rdma"; - (void)snprintf(buf, sizeof(buf), "addr=%s port=%s proto=rdma", - xprt->address_strings[RPC_DISPLAY_ADDR], - xprt->address_strings[RPC_DISPLAY_PORT]); - xprt->address_strings[RPC_DISPLAY_ALL] = kstrdup(buf, GFP_KERNEL); - (void)snprintf(buf, sizeof(buf), "%02x%02x%02x%02x", NIPQUAD(sin->sin_addr.s_addr)); xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 7bc3c17..eee5ac9 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -307,12 +307,6 @@ static void xs_format_common_peer_addresses(struct rpc_xprt *xprt) (void)snprintf(buf, sizeof(buf), "%u", rpc_get_port(sap)); xprt->address_strings[RPC_DISPLAY_PORT] = kstrdup(buf, GFP_KERNEL); - (void)snprintf(buf, sizeof(buf), "addr=%s port=%s proto=%s", - xprt->address_strings[RPC_DISPLAY_ADDR], - xprt->address_strings[RPC_DISPLAY_PORT], - xprt->address_strings[RPC_DISPLAY_PROTO]); - xprt->address_strings[RPC_DISPLAY_ALL] = kstrdup(buf, GFP_KERNEL); - (void)snprintf(buf, sizeof(buf), "%4hx", rpc_get_port(sap)); xprt->address_strings[RPC_DISPLAY_HEX_PORT] = kstrdup(buf, GFP_KERNEL); } @@ -1721,8 +1715,11 @@ static void xs_udp_connect_worker4(struct work_struct *work) goto out; } - dprintk("RPC: worker connecting xprt %p to address: %s\n", - xprt, xprt->address_strings[RPC_DISPLAY_ALL]); + dprintk("RPC: worker connecting xprt %p via %s to " + "%s (port %s)\n", xprt, + xprt->address_strings[RPC_DISPLAY_PROTO], + xprt->address_strings[RPC_DISPLAY_ADDR], + xprt->address_strings[RPC_DISPLAY_PORT]); xs_udp_finish_connecting(xprt, sock); status = 0; @@ -1763,8 +1760,11 @@ static void xs_udp_connect_worker6(struct work_struct *work) goto out; } - dprintk("RPC: worker connecting xprt %p to address: %s\n", - xprt, xprt->address_strings[RPC_DISPLAY_ALL]); + dprintk("RPC: worker connecting xprt %p via %s to " + "%s (port %s)\n", xprt, + xprt->address_strings[RPC_DISPLAY_PROTO], + xprt->address_strings[RPC_DISPLAY_ADDR], + xprt->address_strings[RPC_DISPLAY_PORT]); xs_udp_finish_connecting(xprt, sock); status = 0; @@ -1889,8 +1889,11 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt, goto out_eagain; } - dprintk("RPC: worker connecting xprt %p to address: %s\n", - xprt, xprt->address_strings[RPC_DISPLAY_ALL]); + dprintk("RPC: worker connecting xprt %p via %s to " + "%s (port %s)\n", xprt, + xprt->address_strings[RPC_DISPLAY_PROTO], + xprt->address_strings[RPC_DISPLAY_ADDR], + xprt->address_strings[RPC_DISPLAY_PORT]); status = xs_tcp_finish_connecting(xprt, sock); dprintk("RPC: %p connect status %d connected %d sock state %d\n", @@ -2228,8 +2231,15 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args) return ERR_PTR(-EAFNOSUPPORT); } - dprintk("RPC: set up transport to address %s\n", - xprt->address_strings[RPC_DISPLAY_ALL]); + if (xprt_bound(xprt)) + dprintk("RPC: set up xprt to %s (port %s) via %s\n", + xprt->address_strings[RPC_DISPLAY_ADDR], + xprt->address_strings[RPC_DISPLAY_PORT], + xprt->address_strings[RPC_DISPLAY_PROTO]); + else + dprintk("RPC: set up xprt to %s (autobind) via %s\n", + xprt->address_strings[RPC_DISPLAY_ADDR], + xprt->address_strings[RPC_DISPLAY_PROTO]); if (try_module_get(THIS_MODULE)) return xprt; @@ -2293,8 +2303,16 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) return ERR_PTR(-EAFNOSUPPORT); } - dprintk("RPC: set up transport to address %s\n", - xprt->address_strings[RPC_DISPLAY_ALL]); + if (xprt_bound(xprt)) + dprintk("RPC: set up xprt to %s (port %s) via %s\n", + xprt->address_strings[RPC_DISPLAY_ADDR], + xprt->address_strings[RPC_DISPLAY_PORT], + xprt->address_strings[RPC_DISPLAY_PROTO]); + else + dprintk("RPC: set up xprt to %s (autobind) via %s\n", + xprt->address_strings[RPC_DISPLAY_ADDR], + xprt->address_strings[RPC_DISPLAY_PROTO]); + if (try_module_get(THIS_MODULE)) return xprt; -- cgit v0.10.2 From 9dc3b095b78347bfb02c324b5ee2e558f7267396 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:46 -0400 Subject: SUNRPC: Update xprt address strings after an rpcbind completes After a bind completes, update the transport instance's address strings so debugging messages display the current port the transport is connected to. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index eee5ac9..8aaf900 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -299,11 +299,34 @@ static inline struct sockaddr_in6 *xs_addr_in6(struct rpc_xprt *xprt) static void xs_format_common_peer_addresses(struct rpc_xprt *xprt) { struct sockaddr *sap = xs_addr(xprt); + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; char buf[128]; (void)rpc_ntop(sap, buf, sizeof(buf)); xprt->address_strings[RPC_DISPLAY_ADDR] = kstrdup(buf, GFP_KERNEL); + switch (sap->sa_family) { + case AF_INET: + sin = xs_addr_in(xprt); + (void)snprintf(buf, sizeof(buf), "%02x%02x%02x%02x", + NIPQUAD(sin->sin_addr.s_addr)); + break; + case AF_INET6: + sin6 = xs_addr_in6(xprt); + (void)snprintf(buf, sizeof(buf), "%pi6", &sin6->sin6_addr); + break; + default: + BUG(); + } + xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL); +} + +static void xs_format_common_peer_ports(struct rpc_xprt *xprt) +{ + struct sockaddr *sap = xs_addr(xprt); + char buf[128]; + (void)snprintf(buf, sizeof(buf), "%u", rpc_get_port(sap)); xprt->address_strings[RPC_DISPLAY_PORT] = kstrdup(buf, GFP_KERNEL); @@ -311,37 +334,22 @@ static void xs_format_common_peer_addresses(struct rpc_xprt *xprt) xprt->address_strings[RPC_DISPLAY_HEX_PORT] = kstrdup(buf, GFP_KERNEL); } -static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt, - const char *protocol, - const char *netid) +static void xs_format_peer_addresses(struct rpc_xprt *xprt, + const char *protocol, + const char *netid) { - struct sockaddr_in *sin = xs_addr_in(xprt); - char buf[16]; - xprt->address_strings[RPC_DISPLAY_PROTO] = protocol; xprt->address_strings[RPC_DISPLAY_NETID] = netid; - - (void)snprintf(buf, sizeof(buf), "%02x%02x%02x%02x", - NIPQUAD(sin->sin_addr.s_addr)); - xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL); - xs_format_common_peer_addresses(xprt); + xs_format_common_peer_ports(xprt); } -static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt, - const char *protocol, - const char *netid) +static void xs_update_peer_port(struct rpc_xprt *xprt) { - struct sockaddr_in6 *sin6 = xs_addr_in6(xprt); - char buf[48]; + kfree(xprt->address_strings[RPC_DISPLAY_HEX_PORT]); + kfree(xprt->address_strings[RPC_DISPLAY_PORT]); - xprt->address_strings[RPC_DISPLAY_PROTO] = protocol; - xprt->address_strings[RPC_DISPLAY_NETID] = netid; - - (void)snprintf(buf, sizeof(buf), "%pi6", &sin6->sin6_addr); - xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL); - - xs_format_common_peer_addresses(xprt); + xs_format_common_peer_ports(xprt); } static void xs_free_peer_addresses(struct rpc_xprt *xprt) @@ -1522,20 +1530,10 @@ static unsigned short xs_get_random_port(void) */ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) { - struct sockaddr *addr = xs_addr(xprt); - dprintk("RPC: setting port for xprt %p to %u\n", xprt, port); - switch (addr->sa_family) { - case AF_INET: - ((struct sockaddr_in *)addr)->sin_port = htons(port); - break; - case AF_INET6: - ((struct sockaddr_in6 *)addr)->sin6_port = htons(port); - break; - default: - BUG(); - } + rpc_set_port(xs_addr(xprt), port); + xs_update_peer_port(xprt); } static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket *sock) @@ -2216,7 +2214,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args) INIT_DELAYED_WORK(&transport->connect_worker, xs_udp_connect_worker4); - xs_format_ipv4_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP); + xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP); break; case AF_INET6: if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0)) @@ -2224,7 +2222,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args) INIT_DELAYED_WORK(&transport->connect_worker, xs_udp_connect_worker6); - xs_format_ipv6_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6); + xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6); break; default: kfree(xprt); @@ -2288,15 +2286,17 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) if (((struct sockaddr_in *)addr)->sin_port != htons(0)) xprt_set_bound(xprt); - INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker4); - xs_format_ipv4_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP); + INIT_DELAYED_WORK(&transport->connect_worker, + xs_tcp_connect_worker4); + xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP); break; case AF_INET6: if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0)) xprt_set_bound(xprt); - INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker6); - xs_format_ipv6_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6); + INIT_DELAYED_WORK(&transport->connect_worker, + xs_tcp_connect_worker6); + xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6); break; default: kfree(xprt); -- cgit v0.10.2 From c05988cdb06237738d361ef82fbf4df1020aa3db Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 9 Aug 2009 15:09:47 -0400 Subject: SUNRPC: Add documenting comments in net/sunrpc/timer.c Clean up: provide documenting comments for the functions in net/sunrpc/timer.c. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/timer.c b/net/sunrpc/timer.c index 31becbf..dd82434 100644 --- a/net/sunrpc/timer.c +++ b/net/sunrpc/timer.c @@ -25,8 +25,13 @@ #define RPC_RTO_INIT (HZ/5) #define RPC_RTO_MIN (HZ/10) -void -rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo) +/** + * rpc_init_rtt - Initialize an RPC RTT estimator context + * @rt: context to initialize + * @timeo: initial timeout value, in jiffies + * + */ +void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo) { unsigned long init = 0; unsigned i; @@ -43,12 +48,16 @@ rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo) } EXPORT_SYMBOL_GPL(rpc_init_rtt); -/* +/** + * rpc_update_rtt - Update an RPC RTT estimator context + * @rt: context to update + * @timer: timer array index (request type) + * @m: recent actual RTT, in jiffies + * * NB: When computing the smoothed RTT and standard deviation, * be careful not to produce negative intermediate results. */ -void -rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m) +void rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m) { long *srtt, *sdrtt; @@ -79,21 +88,25 @@ rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m) } EXPORT_SYMBOL_GPL(rpc_update_rtt); -/* - * Estimate rto for an nfs rpc sent via. an unreliable datagram. - * Use the mean and mean deviation of rtt for the appropriate type of rpc - * for the frequent rpcs and a default for the others. - * The justification for doing "other" this way is that these rpcs - * happen so infrequently that timer est. would probably be stale. - * Also, since many of these rpcs are - * non-idempotent, a conservative timeout is desired. +/** + * rpc_calc_rto - Provide an estimated timeout value + * @rt: context to use for calculation + * @timer: timer array index (request type) + * + * Estimate RTO for an NFS RPC sent via an unreliable datagram. Use + * the mean and mean deviation of RTT for the appropriate type of RPC + * for frequently issued RPCs, and a fixed default for the others. + * + * The justification for doing "other" this way is that these RPCs + * happen so infrequently that timer estimation would probably be + * stale. Also, since many of these RPCs are non-idempotent, a + * conservative timeout is desired. + * * getattr, lookup, * read, write, commit - A+4D * other - timeo */ - -unsigned long -rpc_calc_rto(struct rpc_rtt *rt, unsigned timer) +unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned timer) { unsigned long res; -- cgit v0.10.2 From b693ba4a338da15db1db4b5ebaa36e4ab9781c82 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:15 -0400 Subject: SUNRPC: Constify rpc_pipe_ops... Signed-off-by: Trond Myklebust diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 86147b0..fae0d3e 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -101,7 +101,7 @@ static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); static unsigned int fnvhash32(const void *, size_t); -static struct rpc_pipe_ops idmap_upcall_ops = { +static const struct rpc_pipe_ops idmap_upcall_ops = { .upcall = idmap_pipe_upcall, .downcall = idmap_pipe_downcall, .destroy_msg = idmap_pipe_destroy_msg, diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index cea764c..91f5b13 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -32,8 +32,8 @@ struct rpc_inode { wait_queue_head_t waitq; #define RPC_PIPE_WAIT_FOR_OPEN 1 int flags; - struct rpc_pipe_ops *ops; struct delayed_work queue_timeout; + const struct rpc_pipe_ops *ops; }; static inline struct rpc_inode * @@ -46,7 +46,8 @@ extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); extern int rpc_rmdir(struct dentry *); -extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, struct rpc_pipe_ops *, int flags); +extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, + const struct rpc_pipe_ops *, int flags); extern int rpc_unlink(struct dentry *); extern struct vfsmount *rpc_get_mount(void); extern void rpc_put_mount(void); diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 66d458f..23eb386 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -89,8 +89,8 @@ static struct rpc_wait_queue pipe_version_rpc_waitqueue; static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); static void gss_free_ctx(struct gss_cl_ctx *); -static struct rpc_pipe_ops gss_upcall_ops_v0; -static struct rpc_pipe_ops gss_upcall_ops_v1; +static const struct rpc_pipe_ops gss_upcall_ops_v0; +static const struct rpc_pipe_ops gss_upcall_ops_v1; static inline struct gss_cl_ctx * gss_get_ctx(struct gss_cl_ctx *ctx) @@ -1507,7 +1507,7 @@ static const struct rpc_credops gss_nullops = { .crunwrap_resp = gss_unwrap_resp, }; -static struct rpc_pipe_ops gss_upcall_ops_v0 = { +static const struct rpc_pipe_ops gss_upcall_ops_v0 = { .upcall = gss_pipe_upcall, .downcall = gss_pipe_downcall, .destroy_msg = gss_pipe_destroy_msg, @@ -1515,7 +1515,7 @@ static struct rpc_pipe_ops gss_upcall_ops_v0 = { .release_pipe = gss_pipe_release, }; -static struct rpc_pipe_ops gss_upcall_ops_v1 = { +static const struct rpc_pipe_ops gss_upcall_ops_v1 = { .upcall = gss_pipe_upcall, .downcall = gss_pipe_downcall, .destroy_msg = gss_pipe_destroy_msg, diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 9ced062..f6f60f6 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -125,7 +125,7 @@ static void rpc_close_pipes(struct inode *inode) { struct rpc_inode *rpci = RPC_I(inode); - struct rpc_pipe_ops *ops; + const struct rpc_pipe_ops *ops; int need_release; mutex_lock(&inode->i_mutex); @@ -776,8 +776,9 @@ rpc_rmdir(struct dentry *dentry) * The @private argument passed here will be available to all these methods * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. */ -struct dentry * -rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags) +struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, + void *private, const struct rpc_pipe_ops *ops, + int flags) { struct dentry *dentry; struct inode *dir, *inode; -- cgit v0.10.2 From 7364af6a2d5e708b5c6fee3cce08d1bd7b27c9f1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:16 -0400 Subject: SUNRPC: Allow rpc_pipefs_ops to have null values for upcall and downcall Also ensure that we use the umode_t type when appropriate... Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index f6f60f6..8fa7182 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -417,7 +417,7 @@ enum { struct rpc_filelist { char *name; const struct file_operations *i_fop; - int mode; + umode_t mode; }; static struct rpc_filelist files[] = { @@ -516,7 +516,7 @@ rpc_release_path(struct nameidata *nd) } static struct inode * -rpc_get_inode(struct super_block *sb, int mode) +rpc_get_inode(struct super_block *sb, umode_t mode) { struct inode *inode = new_inode(sb); if (!inode) @@ -589,7 +589,8 @@ rpc_populate(struct dentry *parent, struct inode *inode, *dir = parent->d_inode; void *private = RPC_I(dir)->private; struct dentry *dentry; - int mode, i; + umode_t mode; + int i; mutex_lock(&dir->i_mutex); for (i = start; i < eof; i++) { @@ -783,6 +784,12 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, struct dentry *dentry; struct inode *dir, *inode; struct rpc_inode *rpci; + umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR; + + if (ops->upcall == NULL) + umode &= ~S_IRUGO; + if (ops->downcall == NULL) + umode &= ~S_IWUGO; dentry = rpc_lookup_create(parent, name, strlen(name), 0); if (IS_ERR(dentry)) @@ -799,7 +806,7 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, rpci->nkern_readwriters++; goto out; } - inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR); + inode = rpc_get_inode(dir->i_sb, umode); if (!inode) goto err_dput; inode->i_ino = iunique(dir->i_sb, 100); -- cgit v0.10.2 From b5bb61da2efe7519eedd6a8f3830ab33ab774b83 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:17 -0400 Subject: SUNRPC: Clean up rpc_pipefs lookup code... Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 8fa7182..2940b92 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -484,12 +484,12 @@ static const struct dentry_operations rpc_dentry_operations = { .d_delete = rpc_delete_dentry, }; -static int -rpc_lookup_parent(char *path, struct nameidata *nd) +static int __rpc_lookup_path(const char *pathname, unsigned flags, + struct nameidata *nd) { struct vfsmount *mnt; - if (path[0] == '\0') + if (pathname[0] == '\0') return -ENOENT; mnt = rpc_get_mount(); @@ -499,15 +499,20 @@ rpc_lookup_parent(char *path, struct nameidata *nd) return PTR_ERR(mnt); } - if (vfs_path_lookup(mnt->mnt_root, mnt, path, LOOKUP_PARENT, nd)) { + if (vfs_path_lookup(mnt->mnt_root, mnt, pathname, flags, nd)) { printk(KERN_WARNING "%s: %s failed to find path %s\n", - __FILE__, __func__, path); + __FILE__, __func__, pathname); rpc_put_mount(); return -ENOENT; } return 0; } +static int rpc_lookup_parent(const char *pathname, struct nameidata *nd) +{ + return __rpc_lookup_path(pathname, LOOKUP_PARENT, nd); +} + static void rpc_release_path(struct nameidata *nd) { -- cgit v0.10.2 From 7589806e961a16449003b636b369edec537c2726 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:17 -0400 Subject: SUNRPC: Clean up file creation code in rpc_pipefs Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 2940b92..d8c7815 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -539,6 +539,68 @@ rpc_get_inode(struct super_block *sb, umode_t mode) return inode; } +static int __rpc_create_common(struct inode *dir, struct dentry *dentry, + umode_t mode, + const struct file_operations *i_fop, + void *private) +{ + struct inode *inode; + + BUG_ON(!d_unhashed(dentry)); + inode = rpc_get_inode(dir->i_sb, mode); + if (!inode) + goto out_err; + inode->i_ino = iunique(dir->i_sb, 100); + if (i_fop) + inode->i_fop = i_fop; + if (private) + rpc_inode_setowner(inode, private); + d_add(dentry, inode); + return 0; +out_err: + printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", + __FILE__, __func__, dentry->d_name.name); + dput(dentry); + return -ENOMEM; +} + +static int __rpc_mkdir(struct inode *dir, struct dentry *dentry, + umode_t mode, + const struct file_operations *i_fop, + void *private) +{ + int err; + + err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private); + if (err) + return err; + inc_nlink(dir); + fsnotify_mkdir(dir, dentry); + return 0; +} + +static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, + umode_t mode, + const struct file_operations *i_fop, + void *private, + const struct rpc_pipe_ops *ops, + int flags) +{ + struct rpc_inode *rpci; + int err; + + err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private); + if (err) + return err; + rpci = RPC_I(dentry->d_inode); + rpci->nkern_readwriters = 1; + rpci->private = private; + rpci->flags = flags; + rpci->ops = ops; + fsnotify_create(dir, dentry); + return 0; +} + /* * FIXME: This probably has races. */ @@ -629,25 +691,6 @@ out_bad: } static int -__rpc_mkdir(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode; - - inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); - if (!inode) - goto out_err; - inode->i_ino = iunique(dir->i_sb, 100); - d_instantiate(dentry, inode); - inc_nlink(dir); - fsnotify_mkdir(dir, dentry); - return 0; -out_err: - printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", - __FILE__, __func__, dentry->d_name.name); - return -ENOMEM; -} - -static int __rpc_rmdir(struct inode *dir, struct dentry *dentry) { int error; @@ -717,9 +760,9 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client) if (IS_ERR(dentry)) return dentry; dir = nd.path.dentry->d_inode; - if ((error = __rpc_mkdir(dir, dentry)) != 0) - goto err_dput; - RPC_I(dentry->d_inode)->private = rpc_client; + error = __rpc_mkdir(dir, dentry, S_IRUGO | S_IXUGO, NULL, rpc_client); + if (error != 0) + goto out_err; error = rpc_populate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF); if (error) @@ -732,8 +775,7 @@ out: err_depopulate: rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); __rpc_rmdir(dir, dentry); -err_dput: - dput(dentry); +out_err: printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n", __FILE__, __func__, path, error); dentry = ERR_PTR(error); @@ -787,9 +829,9 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, int flags) { struct dentry *dentry; - struct inode *dir, *inode; - struct rpc_inode *rpci; + struct inode *dir = parent->d_inode; umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR; + int err; if (ops->upcall == NULL) umode &= ~S_IRUGO; @@ -801,7 +843,7 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, return dentry; dir = parent->d_inode; if (dentry->d_inode) { - rpci = RPC_I(dentry->d_inode); + struct rpc_inode *rpci = RPC_I(dentry->d_inode); if (rpci->private != private || rpci->ops != ops || rpci->flags != flags) { @@ -811,28 +853,20 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, rpci->nkern_readwriters++; goto out; } - inode = rpc_get_inode(dir->i_sb, umode); - if (!inode) - goto err_dput; - inode->i_ino = iunique(dir->i_sb, 100); - inode->i_fop = &rpc_pipe_fops; - d_instantiate(dentry, inode); - rpci = RPC_I(inode); - rpci->private = private; - rpci->flags = flags; - rpci->ops = ops; - rpci->nkern_readwriters = 1; - fsnotify_create(dir, dentry); + + err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops, + private, ops, flags); + if (err) + goto out_err; dget(dentry); out: mutex_unlock(&dir->i_mutex); return dentry; -err_dput: - dput(dentry); - dentry = ERR_PTR(-ENOMEM); +out_err: + dentry = ERR_PTR(err); printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n", __FILE__, __func__, parent->d_name.name, name, - -ENOMEM); + err); goto out; } EXPORT_SYMBOL_GPL(rpc_mkpipe); -- cgit v0.10.2 From 810d90bc2a76ff54295cfb3aa9b165160faa47ef Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:18 -0400 Subject: SUNRPC: Clean up rpc_unlink() Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index d8c7815..cf30bf5 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -601,6 +601,29 @@ static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, return 0; } +static int __rpc_unlink(struct inode *dir, struct dentry *dentry) +{ + int ret; + + dget(dentry); + ret = simple_unlink(dir, dentry); + d_delete(dentry); + dput(dentry); + return ret; +} + +static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct rpc_inode *rpci = RPC_I(inode); + + rpci->nkern_readwriters--; + if (rpci->nkern_readwriters != 0) + return 0; + rpc_close_pipes(inode); + return __rpc_unlink(dir, dentry); +} + /* * FIXME: This probably has races. */ @@ -848,14 +871,15 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, rpci->ops != ops || rpci->flags != flags) { dput (dentry); - dentry = ERR_PTR(-EBUSY); + err = -EBUSY; + goto out_err; } rpci->nkern_readwriters++; goto out; } err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops, - private, ops, flags); + private, ops, flags); if (err) goto out_err; dget(dentry); @@ -889,12 +913,7 @@ rpc_unlink(struct dentry *dentry) parent = dget_parent(dentry); dir = parent->d_inode; mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); - if (--RPC_I(dentry->d_inode)->nkern_readwriters == 0) { - rpc_close_pipes(dentry->d_inode); - error = simple_unlink(dir, dentry); - if (!error) - d_delete(dentry); - } + error = __rpc_rmpipe(dir, dentry); dput(dentry); mutex_unlock(&dir->i_mutex); dput(parent); -- cgit v0.10.2 From cfeaa4a3caaf590c1fdb7a83fcd5326e7cdc70c3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:20 -0400 Subject: SUNRPC: Clean up rpc_lookup_create Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index cf30bf5..3633851 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -624,6 +624,57 @@ static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry) return __rpc_unlink(dir, dentry); } +static struct dentry *__rpc_lookup_create(struct dentry *parent, + struct qstr *name) +{ + struct dentry *dentry; + + dentry = d_lookup(parent, name); + if (!dentry) { + dentry = d_alloc(parent, name); + if (!dentry) { + dentry = ERR_PTR(-ENOMEM); + goto out_err; + } + } + if (!dentry->d_inode) + dentry->d_op = &rpc_dentry_operations; +out_err: + return dentry; +} + +static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, + struct qstr *name) +{ + struct dentry *dentry; + + dentry = __rpc_lookup_create(parent, name); + if (dentry->d_inode == NULL) + return dentry; + dput(dentry); + return ERR_PTR(-EEXIST); +} + +static struct dentry *rpc_lookup_negative(const char *path, + struct nameidata *nd) +{ + struct inode *dir; + struct dentry *dentry; + int error; + + error = rpc_lookup_parent(path, nd); + if (error != 0) + return ERR_PTR(error); + dir = nd->path.dentry->d_inode; + mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); + dentry = __rpc_lookup_create_exclusive(nd->path.dentry, &nd->last); + if (IS_ERR(dentry)) { + mutex_unlock(&dir->i_mutex); + rpc_release_path(nd); + } + return dentry; +} + /* * FIXME: This probably has races. */ @@ -723,44 +774,6 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry) return error; } -static struct dentry * -rpc_lookup_create(struct dentry *parent, const char *name, int len, int exclusive) -{ - struct inode *dir = parent->d_inode; - struct dentry *dentry; - - mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); - dentry = lookup_one_len(name, parent, len); - if (IS_ERR(dentry)) - goto out_err; - if (!dentry->d_inode) - dentry->d_op = &rpc_dentry_operations; - else if (exclusive) { - dput(dentry); - dentry = ERR_PTR(-EEXIST); - goto out_err; - } - return dentry; -out_err: - mutex_unlock(&dir->i_mutex); - return dentry; -} - -static struct dentry * -rpc_lookup_negative(char *path, struct nameidata *nd) -{ - struct dentry *dentry; - int error; - - if ((error = rpc_lookup_parent(path, nd)) != 0) - return ERR_PTR(error); - dentry = rpc_lookup_create(nd->path.dentry, nd->last.name, nd->last.len, - 1); - if (IS_ERR(dentry)) - rpc_release_path(nd); - return dentry; -} - /** * rpc_mkdir - Create a new directory in rpc_pipefs * @path: path from the rpc_pipefs root to the new directory @@ -854,6 +867,7 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, struct dentry *dentry; struct inode *dir = parent->d_inode; umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR; + struct qstr q; int err; if (ops->upcall == NULL) @@ -861,10 +875,14 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, if (ops->downcall == NULL) umode &= ~S_IWUGO; - dentry = rpc_lookup_create(parent, name, strlen(name), 0); + q.name = name; + q.len = strlen(name); + q.hash = full_name_hash(q.name, q.len), + + mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); + dentry = __rpc_lookup_create(parent, &q); if (IS_ERR(dentry)) - return dentry; - dir = parent->d_inode; + goto out; if (dentry->d_inode) { struct rpc_inode *rpci = RPC_I(dentry->d_inode); if (rpci->private != private || -- cgit v0.10.2 From ac6fecee3121a6825a01c8fda2f5cbf1ad6a3ebd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:20 -0400 Subject: SUNRPC: Clean up rpc_populate/depopulate Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 3633851..e5f37de 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -401,7 +401,6 @@ static const struct file_operations rpc_info_operations = { * We have a single directory with 1 node in it. */ enum { - RPCAUTH_Root = 1, RPCAUTH_lockd, RPCAUTH_mount, RPCAUTH_nfs, @@ -415,12 +414,12 @@ enum { * Description of fs contents. */ struct rpc_filelist { - char *name; + const char *name; const struct file_operations *i_fop; umode_t mode; }; -static struct rpc_filelist files[] = { +static const struct rpc_filelist files[] = { [RPCAUTH_lockd] = { .name = "lockd", .mode = S_IFDIR | S_IRUGO | S_IXUGO, @@ -448,11 +447,11 @@ static struct rpc_filelist files[] = { }; enum { - RPCAUTH_info = 2, + RPCAUTH_info, RPCAUTH_EOF }; -static struct rpc_filelist authfiles[] = { +static const struct rpc_filelist authfiles[] = { [RPCAUTH_info] = { .name = "info", .i_fop = &rpc_info_operations, @@ -564,6 +563,20 @@ out_err: return -ENOMEM; } +static int __rpc_create(struct inode *dir, struct dentry *dentry, + umode_t mode, + const struct file_operations *i_fop, + void *private) +{ + int err; + + err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private); + if (err) + return err; + fsnotify_create(dir, dentry); + return 0; +} + static int __rpc_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode, const struct file_operations *i_fop, @@ -601,6 +614,17 @@ static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, return 0; } +static int __rpc_rmdir(struct inode *dir, struct dentry *dentry) +{ + int ret; + + dget(dentry); + ret = simple_rmdir(dir, dentry); + d_delete(dentry); + dput(dentry); + return ret; +} + static int __rpc_unlink(struct inode *dir, struct dentry *dentry) { int ret; @@ -678,100 +702,96 @@ static struct dentry *rpc_lookup_negative(const char *path, /* * FIXME: This probably has races. */ -static void rpc_depopulate(struct dentry *parent, - unsigned long start, unsigned long eof) +static void __rpc_depopulate(struct dentry *parent, + const struct rpc_filelist *files, + int start, int eof) { struct inode *dir = parent->d_inode; - struct list_head *pos, *next; - struct dentry *dentry, *dvec[10]; - int n = 0; + struct dentry *dentry; + struct qstr name; + int i; - mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD); -repeat: - spin_lock(&dcache_lock); - list_for_each_safe(pos, next, &parent->d_subdirs) { - dentry = list_entry(pos, struct dentry, d_u.d_child); - if (!dentry->d_inode || - dentry->d_inode->i_ino < start || - dentry->d_inode->i_ino >= eof) + for (i = start; i < eof; i++) { + name.name = files[i].name; + name.len = strlen(files[i].name); + name.hash = full_name_hash(name.name, name.len); + dentry = d_lookup(parent, &name); + + if (dentry == NULL) continue; - spin_lock(&dentry->d_lock); - if (!d_unhashed(dentry)) { - dget_locked(dentry); - __d_drop(dentry); - spin_unlock(&dentry->d_lock); - dvec[n++] = dentry; - if (n == ARRAY_SIZE(dvec)) + if (dentry->d_inode == NULL) + goto next; + switch (dentry->d_inode->i_mode & S_IFMT) { + default: + BUG(); + case S_IFREG: + __rpc_unlink(dir, dentry); break; - } else - spin_unlock(&dentry->d_lock); - } - spin_unlock(&dcache_lock); - if (n) { - do { - dentry = dvec[--n]; - if (S_ISREG(dentry->d_inode->i_mode)) - simple_unlink(dir, dentry); - else if (S_ISDIR(dentry->d_inode->i_mode)) - simple_rmdir(dir, dentry); - d_delete(dentry); - dput(dentry); - } while (n); - goto repeat; + case S_IFDIR: + __rpc_rmdir(dir, dentry); + } +next: + dput(dentry); } +} + +static void rpc_depopulate(struct dentry *parent, + const struct rpc_filelist *files, + int start, int eof) +{ + struct inode *dir = parent->d_inode; + + mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD); + __rpc_depopulate(parent, files, start, eof); mutex_unlock(&dir->i_mutex); } -static int -rpc_populate(struct dentry *parent, - struct rpc_filelist *files, - int start, int eof) +static int rpc_populate(struct dentry *parent, + const struct rpc_filelist *files, + int start, int eof, + void *private) { - struct inode *inode, *dir = parent->d_inode; - void *private = RPC_I(dir)->private; + struct inode *dir = parent->d_inode; struct dentry *dentry; - umode_t mode; - int i; + int i, err; mutex_lock(&dir->i_mutex); for (i = start; i < eof; i++) { - dentry = d_alloc_name(parent, files[i].name); - if (!dentry) - goto out_bad; - dentry->d_op = &rpc_dentry_operations; - mode = files[i].mode; - inode = rpc_get_inode(dir->i_sb, mode); - if (!inode) { - dput(dentry); + struct qstr q; + + q.name = files[i].name; + q.len = strlen(files[i].name); + q.hash = full_name_hash(q.name, q.len); + dentry = __rpc_lookup_create_exclusive(parent, &q); + err = PTR_ERR(dentry); + if (IS_ERR(dentry)) goto out_bad; + switch (files[i].mode & S_IFMT) { + default: + BUG(); + case S_IFREG: + err = __rpc_create(dir, dentry, + files[i].mode, + files[i].i_fop, + private); + break; + case S_IFDIR: + err = __rpc_mkdir(dir, dentry, + files[i].mode, + NULL, + private); } - inode->i_ino = i; - if (files[i].i_fop) - inode->i_fop = files[i].i_fop; - if (private) - rpc_inode_setowner(inode, private); - if (S_ISDIR(mode)) - inc_nlink(dir); - d_add(dentry, inode); - fsnotify_create(dir, dentry); + if (err != 0) + goto out_bad; } mutex_unlock(&dir->i_mutex); return 0; out_bad: + __rpc_depopulate(parent, files, start, eof); mutex_unlock(&dir->i_mutex); printk(KERN_WARNING "%s: %s failed to populate directory %s\n", __FILE__, __func__, parent->d_name.name); - return -ENOMEM; -} - -static int -__rpc_rmdir(struct inode *dir, struct dentry *dentry) -{ - int error; - error = simple_rmdir(dir, dentry); - if (!error) - d_delete(dentry); - return error; + return err; } /** @@ -800,16 +820,14 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client) if (error != 0) goto out_err; error = rpc_populate(dentry, authfiles, - RPCAUTH_info, RPCAUTH_EOF); + RPCAUTH_info, RPCAUTH_EOF, rpc_client); if (error) - goto err_depopulate; - dget(dentry); + goto err_rmdir; out: mutex_unlock(&dir->i_mutex); rpc_release_path(&nd); return dentry; -err_depopulate: - rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); +err_rmdir: __rpc_rmdir(dir, dentry); out_err: printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n", @@ -832,9 +850,8 @@ rpc_rmdir(struct dentry *dentry) parent = dget_parent(dentry); dir = parent->d_inode; mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); - rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); + rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF); error = __rpc_rmdir(dir, dentry); - dput(dentry); mutex_unlock(&dir->i_mutex); dput(parent); return error; @@ -900,7 +917,6 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, private, ops, flags); if (err) goto out_err; - dget(dentry); out: mutex_unlock(&dir->i_mutex); return dentry; @@ -932,7 +948,6 @@ rpc_unlink(struct dentry *dentry) dir = parent->d_inode; mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); error = __rpc_rmpipe(dir, dentry); - dput(dentry); mutex_unlock(&dir->i_mutex); dput(parent); return error; @@ -970,7 +985,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) iput(inode); return -ENOMEM; } - if (rpc_populate(root, files, RPCAUTH_Root + 1, RPCAUTH_RootEOF)) + if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) goto out; sb->s_root = root; return 0; -- cgit v0.10.2 From bb1567491e43df4113ec8b088ff0ebc22f568bc5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:21 -0400 Subject: SUNRPC: rpc_pipefs cleanup Move the files[] array closer to rpc_fill_super() Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index e5f37de..2a4e6eb 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -398,19 +398,6 @@ static const struct file_operations rpc_info_operations = { /* - * We have a single directory with 1 node in it. - */ -enum { - RPCAUTH_lockd, - RPCAUTH_mount, - RPCAUTH_nfs, - RPCAUTH_portmap, - RPCAUTH_statd, - RPCAUTH_nfsd4_cb, - RPCAUTH_RootEOF -}; - -/* * Description of fs contents. */ struct rpc_filelist { @@ -419,33 +406,6 @@ struct rpc_filelist { umode_t mode; }; -static const struct rpc_filelist files[] = { - [RPCAUTH_lockd] = { - .name = "lockd", - .mode = S_IFDIR | S_IRUGO | S_IXUGO, - }, - [RPCAUTH_mount] = { - .name = "mount", - .mode = S_IFDIR | S_IRUGO | S_IXUGO, - }, - [RPCAUTH_nfs] = { - .name = "nfs", - .mode = S_IFDIR | S_IRUGO | S_IXUGO, - }, - [RPCAUTH_portmap] = { - .name = "portmap", - .mode = S_IFDIR | S_IRUGO | S_IXUGO, - }, - [RPCAUTH_statd] = { - .name = "statd", - .mode = S_IFDIR | S_IRUGO | S_IXUGO, - }, - [RPCAUTH_nfsd4_cb] = { - .name = "nfsd4_cb", - .mode = S_IFDIR | S_IRUGO | S_IXUGO, - }, -}; - enum { RPCAUTH_info, RPCAUTH_EOF @@ -965,6 +925,46 @@ static struct super_operations s_ops = { #define RPCAUTH_GSSMAGIC 0x67596969 +/* + * We have a single directory with 1 node in it. + */ +enum { + RPCAUTH_lockd, + RPCAUTH_mount, + RPCAUTH_nfs, + RPCAUTH_portmap, + RPCAUTH_statd, + RPCAUTH_nfsd4_cb, + RPCAUTH_RootEOF +}; + +static const struct rpc_filelist files[] = { + [RPCAUTH_lockd] = { + .name = "lockd", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, + [RPCAUTH_mount] = { + .name = "mount", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, + [RPCAUTH_nfs] = { + .name = "nfs", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, + [RPCAUTH_portmap] = { + .name = "portmap", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, + [RPCAUTH_statd] = { + .name = "statd", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, + [RPCAUTH_nfsd4_cb] = { + .name = "nfsd4_cb", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, +}; + static int rpc_fill_super(struct super_block *sb, void *data, int silent) { -- cgit v0.10.2 From 458adb8ba9b26bfc66593866013adbb62a1a3d2e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:22 -0400 Subject: SUNRPC: Rename rpc_mkdir to rpc_create_client_dir() This reflects the fact that rpc_mkdir() as it stands today, can only create a RPC client type directory. Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 91f5b13..8de0ac2 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -44,8 +44,9 @@ RPC_I(struct inode *inode) extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); -extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); -extern int rpc_rmdir(struct dentry *); +struct rpc_clnt; +extern struct dentry *rpc_create_client_dir(const char *, struct rpc_clnt *); +extern int rpc_remove_client_dir(struct dentry *); extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, const struct rpc_pipe_ops *, int flags); extern int rpc_unlink(struct dentry *); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index ebfcf9b..6ec3770 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -113,7 +113,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) "%s/clnt%x", dir_name, (unsigned int)clntid++); clnt->cl_pathname[sizeof(clnt->cl_pathname) - 1] = '\0'; - clnt->cl_dentry = rpc_mkdir(clnt->cl_pathname, clnt); + clnt->cl_dentry = rpc_create_client_dir(clnt->cl_pathname, clnt); if (!IS_ERR(clnt->cl_dentry)) return 0; error = PTR_ERR(clnt->cl_dentry); @@ -232,7 +232,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru out_no_auth: if (!IS_ERR(clnt->cl_dentry)) { - rpc_rmdir(clnt->cl_dentry); + rpc_remove_client_dir(clnt->cl_dentry); rpc_put_mount(); } out_no_path: @@ -424,7 +424,7 @@ rpc_free_client(struct kref *kref) dprintk("RPC: destroying %s client for %s\n", clnt->cl_protname, clnt->cl_server); if (!IS_ERR(clnt->cl_dentry)) { - rpc_rmdir(clnt->cl_dentry); + rpc_remove_client_dir(clnt->cl_dentry); rpc_put_mount(); } if (clnt->cl_parent != clnt) { diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 2a4e6eb..08580be 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -755,7 +755,7 @@ out_bad: } /** - * rpc_mkdir - Create a new directory in rpc_pipefs + * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs * @path: path from the rpc_pipefs root to the new directory * @rpc_client: rpc client to associate with this directory * @@ -764,8 +764,8 @@ out_bad: * information about the client, together with any "pipes" that may * later be created using rpc_mkpipe(). */ -struct dentry * -rpc_mkdir(char *path, struct rpc_clnt *rpc_client) +struct dentry *rpc_create_client_dir(const char *path, + struct rpc_clnt *rpc_client) { struct nameidata nd; struct dentry *dentry; @@ -797,11 +797,10 @@ out_err: } /** - * rpc_rmdir - Remove a directory created with rpc_mkdir() + * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() * @dentry: directory to remove */ -int -rpc_rmdir(struct dentry *dentry) +int rpc_remove_client_dir(struct dentry *dentry) { struct dentry *parent; struct inode *dir; -- cgit v0.10.2 From 7d59d1e86531a53d7648726ab8a6a670ecbd8f06 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:23 -0400 Subject: SUNRPC: Clean up rpc_create_client_dir() Factor out the code that does lookups from the code that actually creates the directory. Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 08580be..6d152f6 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -639,26 +639,6 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, return ERR_PTR(-EEXIST); } -static struct dentry *rpc_lookup_negative(const char *path, - struct nameidata *nd) -{ - struct inode *dir; - struct dentry *dentry; - int error; - - error = rpc_lookup_parent(path, nd); - if (error != 0) - return ERR_PTR(error); - dir = nd->path.dentry->d_inode; - mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); - dentry = __rpc_lookup_create_exclusive(nd->path.dentry, &nd->last); - if (IS_ERR(dentry)) { - mutex_unlock(&dir->i_mutex); - rpc_release_path(nd); - } - return dentry; -} - /* * FIXME: This probably has races. */ @@ -754,44 +734,30 @@ out_bad: return err; } -/** - * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs - * @path: path from the rpc_pipefs root to the new directory - * @rpc_client: rpc client to associate with this directory - * - * This creates a directory at the given @path associated with - * @rpc_clnt, which will contain a file named "info" with some basic - * information about the client, together with any "pipes" that may - * later be created using rpc_mkpipe(). - */ -struct dentry *rpc_create_client_dir(const char *path, - struct rpc_clnt *rpc_client) +struct dentry *rpc_mkdir_populate(struct dentry *parent, + struct qstr *name, umode_t mode, void *private) { - struct nameidata nd; struct dentry *dentry; - struct inode *dir; + struct inode *dir = parent->d_inode; int error; - dentry = rpc_lookup_negative(path, &nd); + mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); + dentry = __rpc_lookup_create_exclusive(parent, name); if (IS_ERR(dentry)) - return dentry; - dir = nd.path.dentry->d_inode; - error = __rpc_mkdir(dir, dentry, S_IRUGO | S_IXUGO, NULL, rpc_client); + goto out; + error = __rpc_mkdir(dir, dentry, mode, NULL, private); if (error != 0) goto out_err; error = rpc_populate(dentry, authfiles, - RPCAUTH_info, RPCAUTH_EOF, rpc_client); + RPCAUTH_info, RPCAUTH_EOF, private); if (error) goto err_rmdir; out: mutex_unlock(&dir->i_mutex); - rpc_release_path(&nd); return dentry; err_rmdir: __rpc_rmdir(dir, dentry); out_err: - printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n", - __FILE__, __func__, path, error); dentry = ERR_PTR(error); goto out; } @@ -913,6 +879,39 @@ rpc_unlink(struct dentry *dentry) } EXPORT_SYMBOL_GPL(rpc_unlink); +/** + * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs + * @path: path from the rpc_pipefs root to the new directory + * @rpc_client: rpc client to associate with this directory + * + * This creates a directory at the given @path associated with + * @rpc_clnt, which will contain a file named "info" with some basic + * information about the client, together with any "pipes" that may + * later be created using rpc_mkpipe(). + */ +struct dentry *rpc_create_client_dir(const char *path, + struct rpc_clnt *rpc_client) +{ + struct nameidata nd; + struct dentry *ret; + struct inode *dir; + + ret = ERR_PTR(rpc_lookup_parent(path, &nd)); + if (IS_ERR(ret)) + goto out_err; + dir = nd.path.dentry->d_inode; + + ret = rpc_mkdir_populate(nd.path.dentry, &nd.last, + S_IRUGO | S_IXUGO, rpc_client); + rpc_release_path(&nd); + if (!IS_ERR(ret)) + return ret; +out_err: + printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %ld)\n", + __FILE__, __func__, path, PTR_ERR(ret)); + return ret; +} + /* * populate the filesystem */ -- cgit v0.10.2 From 7d217caca5d704e48aa5e59aba0b3ad4c7af4fd2 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:24 -0400 Subject: SUNRPC: Replace rpc_client->cl_dentry and cl_mnt, with a cl_path Signed-off-by: Trond Myklebust diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index fae0d3e..21a84d45 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -119,8 +119,8 @@ nfs_idmap_new(struct nfs_client *clp) if (idmap == NULL) return -ENOMEM; - idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap", - idmap, &idmap_upcall_ops, 0); + idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry, + "idmap", idmap, &idmap_upcall_ops, 0); if (IS_ERR(idmap->idmap_dentry)) { error = PTR_ERR(idmap->idmap_dentry); kfree(idmap); diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 37881f1a..38ad162 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -17,6 +17,7 @@ #include #include #include +#include struct rpc_inode; @@ -51,8 +52,7 @@ struct rpc_clnt { int cl_nodelen; /* nodename length */ char cl_nodename[UNX_MAXNODENAME]; char cl_pathname[30];/* Path in rpc_pipe_fs */ - struct vfsmount * cl_vfsmnt; - struct dentry * cl_dentry; /* inode */ + struct path cl_path; struct rpc_clnt * cl_parent; /* Points to parent of clones */ struct rpc_rtt cl_rtt_default; struct rpc_timeout cl_timeout_default; diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 23eb386..fc6a43c 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -777,7 +777,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) * that we supported only the old pipe. So we instead create * the new pipe first. */ - gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_dentry, + gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_path.dentry, "gssd", clnt, &gss_upcall_ops_v1, RPC_PIPE_WAIT_FOR_OPEN); @@ -786,7 +786,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) goto err_put_mech; } - gss_auth->dentry[0] = rpc_mkpipe(clnt->cl_dentry, + gss_auth->dentry[0] = rpc_mkpipe(clnt->cl_path.dentry, gss_auth->mech->gm_name, clnt, &gss_upcall_ops_v0, RPC_PIPE_WAIT_FOR_OPEN); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 6ec3770..b3f8633 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -99,24 +99,24 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) static uint32_t clntid; int error; - clnt->cl_vfsmnt = ERR_PTR(-ENOENT); - clnt->cl_dentry = ERR_PTR(-ENOENT); + clnt->cl_path.mnt = ERR_PTR(-ENOENT); + clnt->cl_path.dentry = ERR_PTR(-ENOENT); if (dir_name == NULL) return 0; - clnt->cl_vfsmnt = rpc_get_mount(); - if (IS_ERR(clnt->cl_vfsmnt)) - return PTR_ERR(clnt->cl_vfsmnt); + clnt->cl_path.mnt = rpc_get_mount(); + if (IS_ERR(clnt->cl_path.mnt)) + return PTR_ERR(clnt->cl_path.mnt); for (;;) { snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname), "%s/clnt%x", dir_name, (unsigned int)clntid++); clnt->cl_pathname[sizeof(clnt->cl_pathname) - 1] = '\0'; - clnt->cl_dentry = rpc_create_client_dir(clnt->cl_pathname, clnt); - if (!IS_ERR(clnt->cl_dentry)) + clnt->cl_path.dentry = rpc_create_client_dir(clnt->cl_pathname, clnt); + if (!IS_ERR(clnt->cl_path.dentry)) return 0; - error = PTR_ERR(clnt->cl_dentry); + error = PTR_ERR(clnt->cl_path.dentry); if (error != -EEXIST) { printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", clnt->cl_pathname, error); @@ -231,8 +231,8 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru return clnt; out_no_auth: - if (!IS_ERR(clnt->cl_dentry)) { - rpc_remove_client_dir(clnt->cl_dentry); + if (!IS_ERR(clnt->cl_path.dentry)) { + rpc_remove_client_dir(clnt->cl_path.dentry); rpc_put_mount(); } out_no_path: @@ -423,8 +423,8 @@ rpc_free_client(struct kref *kref) dprintk("RPC: destroying %s client for %s\n", clnt->cl_protname, clnt->cl_server); - if (!IS_ERR(clnt->cl_dentry)) { - rpc_remove_client_dir(clnt->cl_dentry); + if (!IS_ERR(clnt->cl_path.dentry)) { + rpc_remove_client_dir(clnt->cl_path.dentry); rpc_put_mount(); } if (clnt->cl_parent != clnt) { -- cgit v0.10.2 From 23ac6581702ac6d029643328a7e6ea3baf834c5e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:25 -0400 Subject: SUNRPC: clean up rpc_setup_pipedir() There is still a little wart or two there: Since we've already got a vfsmount, we might as well pass that in to rpc_create_client_dir. Another point is that if we open code __rpc_lookup_path() here, then we can avoid looking up the entire parent directory path over and over again: it doesn't change. Also get rid of rpc_clnt->cl_pathname, since it has no users... Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 38ad162..1848d44 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -51,7 +51,6 @@ struct rpc_clnt { int cl_nodelen; /* nodename length */ char cl_nodename[UNX_MAXNODENAME]; - char cl_pathname[30];/* Path in rpc_pipe_fs */ struct path cl_path; struct rpc_clnt * cl_parent; /* Points to parent of clones */ struct rpc_rtt cl_rtt_default; diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 8de0ac2..88332ef 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -45,7 +45,7 @@ RPC_I(struct inode *inode) extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); struct rpc_clnt; -extern struct dentry *rpc_create_client_dir(const char *, struct rpc_clnt *); +extern struct dentry *rpc_create_client_dir(struct dentry *, struct qstr *, struct rpc_clnt *); extern int rpc_remove_client_dir(struct dentry *); extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, const struct rpc_pipe_ops *, int flags); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index b3f8633..c1e467e 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -97,6 +99,12 @@ static int rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) { static uint32_t clntid; + struct nameidata nd; + struct path path; + char name[15]; + struct qstr q = { + .name = name, + }; int error; clnt->cl_path.mnt = ERR_PTR(-ENOENT); @@ -104,26 +112,36 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) if (dir_name == NULL) return 0; - clnt->cl_path.mnt = rpc_get_mount(); - if (IS_ERR(clnt->cl_path.mnt)) - return PTR_ERR(clnt->cl_path.mnt); + path.mnt = rpc_get_mount(); + if (IS_ERR(path.mnt)) + return PTR_ERR(path.mnt); + error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &nd); + if (error) + goto err; for (;;) { - snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname), - "%s/clnt%x", dir_name, - (unsigned int)clntid++); - clnt->cl_pathname[sizeof(clnt->cl_pathname) - 1] = '\0'; - clnt->cl_path.dentry = rpc_create_client_dir(clnt->cl_pathname, clnt); - if (!IS_ERR(clnt->cl_path.dentry)) - return 0; - error = PTR_ERR(clnt->cl_path.dentry); + q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++); + name[sizeof(name) - 1] = '\0'; + q.hash = full_name_hash(q.name, q.len); + path.dentry = rpc_create_client_dir(nd.path.dentry, &q, clnt); + if (!IS_ERR(path.dentry)) + break; + error = PTR_ERR(path.dentry); if (error != -EEXIST) { - printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", - clnt->cl_pathname, error); - rpc_put_mount(); - return error; + printk(KERN_INFO "RPC: Couldn't create pipefs entry" + " %s/%s, error %d\n", + dir_name, name, error); + goto err_path_put; } } + path_put(&nd.path); + clnt->cl_path = path; + return 0; +err_path_put: + path_put(&nd.path); +err: + rpc_put_mount(); + return error; } static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 6d152f6..1613d85 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -443,42 +443,6 @@ static const struct dentry_operations rpc_dentry_operations = { .d_delete = rpc_delete_dentry, }; -static int __rpc_lookup_path(const char *pathname, unsigned flags, - struct nameidata *nd) -{ - struct vfsmount *mnt; - - if (pathname[0] == '\0') - return -ENOENT; - - mnt = rpc_get_mount(); - if (IS_ERR(mnt)) { - printk(KERN_WARNING "%s: %s failed to mount " - "pseudofilesystem \n", __FILE__, __func__); - return PTR_ERR(mnt); - } - - if (vfs_path_lookup(mnt->mnt_root, mnt, pathname, flags, nd)) { - printk(KERN_WARNING "%s: %s failed to find path %s\n", - __FILE__, __func__, pathname); - rpc_put_mount(); - return -ENOENT; - } - return 0; -} - -static int rpc_lookup_parent(const char *pathname, struct nameidata *nd) -{ - return __rpc_lookup_path(pathname, LOOKUP_PARENT, nd); -} - -static void -rpc_release_path(struct nameidata *nd) -{ - path_put(&nd->path); - rpc_put_mount(); -} - static struct inode * rpc_get_inode(struct super_block *sb, umode_t mode) { @@ -889,27 +853,11 @@ EXPORT_SYMBOL_GPL(rpc_unlink); * information about the client, together with any "pipes" that may * later be created using rpc_mkpipe(). */ -struct dentry *rpc_create_client_dir(const char *path, +struct dentry *rpc_create_client_dir(struct dentry *dentry, + struct qstr *name, struct rpc_clnt *rpc_client) { - struct nameidata nd; - struct dentry *ret; - struct inode *dir; - - ret = ERR_PTR(rpc_lookup_parent(path, &nd)); - if (IS_ERR(ret)) - goto out_err; - dir = nd.path.dentry->d_inode; - - ret = rpc_mkdir_populate(nd.path.dentry, &nd.last, - S_IRUGO | S_IXUGO, rpc_client); - rpc_release_path(&nd); - if (!IS_ERR(ret)) - return ret; -out_err: - printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %ld)\n", - __FILE__, __func__, path, PTR_ERR(ret)); - return ret; + return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, rpc_client); } /* -- cgit v0.10.2 From e57aed77ad48d28ac617ba157ad2f665f5301b30 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:26 -0400 Subject: SUNRPC: One more clean up for rpc_create_client_dir() In order to allow rpc_pipefs to create directories with different types of subtrees, it is useful to allow the caller to customise the subtree filling process. In order to do so, we separate out the parts which are specific to making an RPC client directory, and put them in a separate helper, then we convert the process of filling the directory contents into a callback. Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 1613d85..57e9cd3 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -406,19 +406,6 @@ struct rpc_filelist { umode_t mode; }; -enum { - RPCAUTH_info, - RPCAUTH_EOF -}; - -static const struct rpc_filelist authfiles[] = { - [RPCAUTH_info] = { - .name = "info", - .i_fop = &rpc_info_operations, - .mode = S_IFREG | S_IRUSR, - }, -}; - struct vfsmount *rpc_get_mount(void) { int err; @@ -698,8 +685,9 @@ out_bad: return err; } -struct dentry *rpc_mkdir_populate(struct dentry *parent, - struct qstr *name, umode_t mode, void *private) +static struct dentry *rpc_mkdir_populate(struct dentry *parent, + struct qstr *name, umode_t mode, void *private, + int (*populate)(struct dentry *, void *), void *args_populate) { struct dentry *dentry; struct inode *dir = parent->d_inode; @@ -712,10 +700,11 @@ struct dentry *rpc_mkdir_populate(struct dentry *parent, error = __rpc_mkdir(dir, dentry, mode, NULL, private); if (error != 0) goto out_err; - error = rpc_populate(dentry, authfiles, - RPCAUTH_info, RPCAUTH_EOF, private); - if (error) - goto err_rmdir; + if (populate != NULL) { + error = populate(dentry, args_populate); + if (error) + goto err_rmdir; + } out: mutex_unlock(&dir->i_mutex); return dentry; @@ -726,11 +715,8 @@ out_err: goto out; } -/** - * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() - * @dentry: directory to remove - */ -int rpc_remove_client_dir(struct dentry *dentry) +static int rpc_rmdir_depopulate(struct dentry *dentry, + void (*depopulate)(struct dentry *)) { struct dentry *parent; struct inode *dir; @@ -739,7 +725,8 @@ int rpc_remove_client_dir(struct dentry *dentry) parent = dget_parent(dentry); dir = parent->d_inode; mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); - rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF); + if (depopulate != NULL) + depopulate(dentry); error = __rpc_rmdir(dir, dentry); mutex_unlock(&dir->i_mutex); dput(parent); @@ -843,6 +830,31 @@ rpc_unlink(struct dentry *dentry) } EXPORT_SYMBOL_GPL(rpc_unlink); +enum { + RPCAUTH_info, + RPCAUTH_EOF +}; + +static const struct rpc_filelist authfiles[] = { + [RPCAUTH_info] = { + .name = "info", + .i_fop = &rpc_info_operations, + .mode = S_IFREG | S_IRUSR, + }, +}; + +static int rpc_clntdir_populate(struct dentry *dentry, void *private) +{ + return rpc_populate(dentry, + authfiles, RPCAUTH_info, RPCAUTH_EOF, + private); +} + +static void rpc_clntdir_depopulate(struct dentry *dentry) +{ + rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF); +} + /** * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs * @path: path from the rpc_pipefs root to the new directory @@ -854,10 +866,20 @@ EXPORT_SYMBOL_GPL(rpc_unlink); * later be created using rpc_mkpipe(). */ struct dentry *rpc_create_client_dir(struct dentry *dentry, - struct qstr *name, - struct rpc_clnt *rpc_client) + struct qstr *name, + struct rpc_clnt *rpc_client) +{ + return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL, + rpc_clntdir_populate, rpc_client); +} + +/** + * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() + * @dentry: directory to remove + */ +int rpc_remove_client_dir(struct dentry *dentry) { - return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, rpc_client); + return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate); } /* -- cgit v0.10.2 From 2da8ca26c6bfad685bfddf39728eac1c83906aa9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:26 -0400 Subject: NFSD: Clean up the idmapper warning... What part of 'internal use' is so hard to understand? Signed-off-by: Trond Myklebust diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 5b39842..e9012ad 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -175,10 +175,10 @@ idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) } static void -warn_no_idmapd(struct cache_detail *detail) +warn_no_idmapd(struct cache_detail *detail, int has_died) { printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n", - detail->last_close? "died" : "not been started"); + has_died ? "died" : "not been started"); } diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 2d8b211..3d1fad2 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -79,6 +79,8 @@ struct cache_detail { int (*cache_show)(struct seq_file *m, struct cache_detail *cd, struct cache_head *h); + void (*warn_no_listener)(struct cache_detail *cd, + int has_died); struct cache_head * (*alloc)(void); int (*match)(struct cache_head *orig, struct cache_head *new); @@ -102,7 +104,6 @@ struct cache_detail { atomic_t readers; /* how many time is /chennel open */ time_t last_close; /* if no readers, when did last close */ time_t last_warn; /* when we last warned about no readers */ - void (*warn_no_listener)(struct cache_detail *cd); }; diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index ff0c230..8ede4a6 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1020,7 +1020,7 @@ static void warn_no_listener(struct cache_detail *detail) if (detail->last_warn != detail->last_close) { detail->last_warn = detail->last_close; if (detail->warn_no_listener) - detail->warn_no_listener(detail); + detail->warn_no_listener(detail, detail->last_close != 0); } } -- cgit v0.10.2 From 5b7a1b9f9214cb89dd164b43ca3fab7af4058e06 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:27 -0400 Subject: SUNRPC: Ensure we initialise the cache_detail before creating procfs files Also ensure that we destroy those files before we destroy the cache_detail. Otherwise, user processes might attempt to write into uninitialised caches. Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 8ede4a6..062d4f4 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -347,13 +347,8 @@ static int create_cache_proc_entries(struct cache_detail *cd) } #endif -int cache_register(struct cache_detail *cd) +static void sunrpc_init_cache_detail(struct cache_detail *cd) { - int ret; - - ret = create_cache_proc_entries(cd); - if (ret) - return ret; rwlock_init(&cd->hash_lock); INIT_LIST_HEAD(&cd->queue); spin_lock(&cache_list_lock); @@ -367,11 +362,9 @@ int cache_register(struct cache_detail *cd) /* start the cleaning process */ schedule_delayed_work(&cache_cleaner, 0); - return 0; } -EXPORT_SYMBOL_GPL(cache_register); -void cache_unregister(struct cache_detail *cd) +static void sunrpc_destroy_cache_detail(struct cache_detail *cd) { cache_purge(cd); spin_lock(&cache_list_lock); @@ -386,7 +379,6 @@ void cache_unregister(struct cache_detail *cd) list_del_init(&cd->others); write_unlock(&cd->hash_lock); spin_unlock(&cache_list_lock); - remove_cache_proc_entries(cd); if (list_empty(&cache_list)) { /* module must be being unloaded so its safe to kill the worker */ cancel_delayed_work_sync(&cache_cleaner); @@ -395,6 +387,24 @@ void cache_unregister(struct cache_detail *cd) out: printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name); } + +int cache_register(struct cache_detail *cd) +{ + int ret; + + sunrpc_init_cache_detail(cd); + ret = create_cache_proc_entries(cd); + if (ret) + sunrpc_destroy_cache_detail(cd); + return ret; +} +EXPORT_SYMBOL_GPL(cache_register); + +void cache_unregister(struct cache_detail *cd) +{ + remove_cache_proc_entries(cd); + sunrpc_destroy_cache_detail(cd); +} EXPORT_SYMBOL_GPL(cache_unregister); /* clean cache tries to find something to clean -- cgit v0.10.2 From da77005f0d64486cd760f43d9b7cc2379262a363 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:28 -0400 Subject: SUNRPC: Remove the global temporary write buffer in net/sunrpc/cache.c While we do want to protect against multiple concurrent readers and writers on each upcall/downcall pipe, we don't want to limit concurrent reading and writing to separate caches. This patch therefore replaces the static buffer 'write_buf', which can only be used by one writer at a time, with use of the page cache as the temporary buffer for downcalls. We still fall back to using the the old global buffer if the downcall is larger than PAGE_CACHE_SIZE, since this is apparently needed by the SPKM security context initialisation. It then replaces the use of the global 'queue_io_mutex' with the inode->i_mutex in cache_read() and cache_write(). Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 062d4f4..c8e7d2d 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -702,13 +703,14 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { struct cache_reader *rp = filp->private_data; struct cache_request *rq; - struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + struct inode *inode = filp->f_path.dentry->d_inode; + struct cache_detail *cd = PDE(inode)->data; int err; if (count == 0) return 0; - mutex_lock(&queue_io_mutex); /* protect against multiple concurrent + mutex_lock(&inode->i_mutex); /* protect against multiple concurrent * readers on this file */ again: spin_lock(&queue_lock); @@ -721,7 +723,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) } if (rp->q.list.next == &cd->queue) { spin_unlock(&queue_lock); - mutex_unlock(&queue_io_mutex); + mutex_unlock(&inode->i_mutex); BUG_ON(rp->offset); return 0; } @@ -768,38 +770,81 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) } if (err == -EAGAIN) goto again; - mutex_unlock(&queue_io_mutex); + mutex_unlock(&inode->i_mutex); return err ? err : count; } -static char write_buf[8192]; /* protected by queue_io_mutex */ +static ssize_t cache_do_downcall(char *kaddr, const char __user *buf, + size_t count, struct cache_detail *cd) +{ + ssize_t ret; -static ssize_t -cache_write(struct file *filp, const char __user *buf, size_t count, - loff_t *ppos) + if (copy_from_user(kaddr, buf, count)) + return -EFAULT; + kaddr[count] = '\0'; + ret = cd->cache_parse(cd, kaddr, count); + if (!ret) + ret = count; + return ret; +} + +static ssize_t cache_slow_downcall(const char __user *buf, + size_t count, struct cache_detail *cd) { - int err; - struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + static char write_buf[8192]; /* protected by queue_io_mutex */ + ssize_t ret = -EINVAL; - if (count == 0) - return 0; if (count >= sizeof(write_buf)) - return -EINVAL; - + goto out; mutex_lock(&queue_io_mutex); + ret = cache_do_downcall(write_buf, buf, count, cd); + mutex_unlock(&queue_io_mutex); +out: + return ret; +} - if (copy_from_user(write_buf, buf, count)) { - mutex_unlock(&queue_io_mutex); - return -EFAULT; - } - write_buf[count] = '\0'; - if (cd->cache_parse) - err = cd->cache_parse(cd, write_buf, count); - else - err = -EINVAL; +static ssize_t cache_downcall(struct address_space *mapping, + const char __user *buf, + size_t count, struct cache_detail *cd) +{ + struct page *page; + char *kaddr; + ssize_t ret = -ENOMEM; + + if (count >= PAGE_CACHE_SIZE) + goto out_slow; + + page = find_or_create_page(mapping, 0, GFP_KERNEL); + if (!page) + goto out_slow; + + kaddr = kmap(page); + ret = cache_do_downcall(kaddr, buf, count, cd); + kunmap(page); + unlock_page(page); + page_cache_release(page); + return ret; +out_slow: + return cache_slow_downcall(buf, count, cd); +} - mutex_unlock(&queue_io_mutex); - return err ? err : count; +static ssize_t +cache_write(struct file *filp, const char __user *buf, size_t count, + loff_t *ppos) +{ + struct address_space *mapping = filp->f_mapping; + struct inode *inode = filp->f_path.dentry->d_inode; + struct cache_detail *cd = PDE(inode)->data; + ssize_t ret = -EINVAL; + + if (!cd->cache_parse) + goto out; + + mutex_lock(&inode->i_mutex); + ret = cache_downcall(mapping, buf, count, cd); + mutex_unlock(&inode->i_mutex); +out: + return ret; } static DECLARE_WAIT_QUEUE_HEAD(queue_wait); -- cgit v0.10.2 From bc74b4f5e63a09fb78e245794a0de1e5a2716bbe Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:29 -0400 Subject: SUNRPC: Allow the cache_detail to specify alternative upcall mechanisms For events that are rare, such as referral DNS lookups, it makes limited sense to have a daemon constantly listening for upcalls on a channel. An alternative in those cases might simply be to run the app that fills the cache using call_usermodehelper_exec() and friends. The following patch allows the cache_detail to specify alternative upcall mechanisms for these particular cases. Signed-off-by: Trond Myklebust diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index b92a276..d946264 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -85,6 +85,11 @@ static void expkey_request(struct cache_detail *cd, (*bpp)[-1] = '\n'; } +static int expkey_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall(cd, h, expkey_request); +} + static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old); static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *); static struct cache_detail svc_expkey_cache; @@ -259,7 +264,7 @@ static struct cache_detail svc_expkey_cache = { .hash_table = expkey_table, .name = "nfsd.fh", .cache_put = expkey_put, - .cache_request = expkey_request, + .cache_upcall = expkey_upcall, .cache_parse = expkey_parse, .cache_show = expkey_show, .match = expkey_match, @@ -355,6 +360,11 @@ static void svc_export_request(struct cache_detail *cd, (*bpp)[-1] = '\n'; } +static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall(cd, h, svc_export_request); +} + static struct svc_export *svc_export_update(struct svc_export *new, struct svc_export *old); static struct svc_export *svc_export_lookup(struct svc_export *); @@ -724,7 +734,7 @@ struct cache_detail svc_export_cache = { .hash_table = export_table, .name = "nfsd.export", .cache_put = svc_export_put, - .cache_request = svc_export_request, + .cache_upcall = svc_export_upcall, .cache_parse = svc_export_parse, .cache_show = svc_export_show, .match = svc_export_match, diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index e9012ad..cdfa86f 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -146,6 +146,12 @@ idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, } static int +idtoname_upcall(struct cache_detail *cd, struct cache_head *ch) +{ + return sunrpc_cache_pipe_upcall(cd, ch, idtoname_request); +} + +static int idtoname_match(struct cache_head *ca, struct cache_head *cb) { struct ent *a = container_of(ca, struct ent, h); @@ -192,7 +198,7 @@ static struct cache_detail idtoname_cache = { .hash_table = idtoname_table, .name = "nfs4.idtoname", .cache_put = ent_put, - .cache_request = idtoname_request, + .cache_upcall = idtoname_upcall, .cache_parse = idtoname_parse, .cache_show = idtoname_show, .warn_no_listener = warn_no_idmapd, @@ -325,6 +331,12 @@ nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, } static int +nametoid_upcall(struct cache_detail *cd, struct cache_head *ch) +{ + return sunrpc_cache_pipe_upcall(cd, ch, nametoid_request); +} + +static int nametoid_match(struct cache_head *ca, struct cache_head *cb) { struct ent *a = container_of(ca, struct ent, h); @@ -363,7 +375,7 @@ static struct cache_detail nametoid_cache = { .hash_table = nametoid_table, .name = "nfs4.nametoid", .cache_put = ent_put, - .cache_request = nametoid_request, + .cache_upcall = nametoid_upcall, .cache_parse = nametoid_parse, .cache_show = nametoid_show, .warn_no_listener = warn_no_idmapd, diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 3d1fad2..23ee259 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -70,9 +70,9 @@ struct cache_detail { char *name; void (*cache_put)(struct kref *); - void (*cache_request)(struct cache_detail *cd, - struct cache_head *h, - char **bpp, int *blen); + int (*cache_upcall)(struct cache_detail *, + struct cache_head *); + int (*cache_parse)(struct cache_detail *, char *buf, int len); @@ -135,6 +135,13 @@ extern struct cache_head * sunrpc_cache_update(struct cache_detail *detail, struct cache_head *new, struct cache_head *old, int hash); +extern int +sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h, + void (*cache_request)(struct cache_detail *, + struct cache_head *, + char **, + int *)); + extern void cache_clean_deferred(void *owner); diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 2278a50..2e6a148 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -181,6 +181,11 @@ static void rsi_request(struct cache_detail *cd, (*bpp)[-1] = '\n'; } +static int rsi_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall(cd, h, rsi_request); +} + static int rsi_parse(struct cache_detail *cd, char *mesg, int mlen) @@ -270,7 +275,7 @@ static struct cache_detail rsi_cache = { .hash_table = rsi_table, .name = "auth.rpcsec.init", .cache_put = rsi_put, - .cache_request = rsi_request, + .cache_upcall = rsi_upcall, .cache_parse = rsi_parse, .match = rsi_match, .init = rsi_init, diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index c8e7d2d..e438352 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -176,7 +176,13 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, } EXPORT_SYMBOL_GPL(sunrpc_cache_update); -static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); +static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) +{ + if (!cd->cache_upcall) + return -EINVAL; + return cd->cache_upcall(cd, h); +} + /* * This is the generic cache management routine for all * the authentication caches. @@ -322,7 +328,7 @@ static int create_cache_proc_entries(struct cache_detail *cd) if (p == NULL) goto out_nomem; - if (cd->cache_request || cd->cache_parse) { + if (cd->cache_upcall || cd->cache_parse) { p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR, cd->proc_ent, &cache_file_operations, cd); cd->channel_ent = p; @@ -1080,10 +1086,16 @@ static void warn_no_listener(struct cache_detail *detail) } /* - * register an upcall request to user-space. + * register an upcall request to user-space and queue it up for read() by the + * upcall daemon. + * * Each request is at most one page long. */ -static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h) +int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h, + void (*cache_request)(struct cache_detail *, + struct cache_head *, + char **, + int *)) { char *buf; @@ -1091,9 +1103,6 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h) char *bp; int len; - if (detail->cache_request == NULL) - return -EINVAL; - if (atomic_read(&detail->readers) == 0 && detail->last_close < get_seconds() - 30) { warn_no_listener(detail); @@ -1112,7 +1121,7 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h) bp = buf; len = PAGE_SIZE; - detail->cache_request(detail, h, &bp, &len); + cache_request(detail, h, &bp, &len); if (len < 0) { kfree(buf); @@ -1130,6 +1139,7 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h) wake_up(&queue_wait); return 0; } +EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall); /* * parse a message from user-space and pass it diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 5c865e2..6caffa3 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -171,6 +171,11 @@ static void ip_map_request(struct cache_detail *cd, (*bpp)[-1] = '\n'; } +static int ip_map_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall(cd, h, ip_map_request); +} + static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr); static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry); @@ -289,7 +294,7 @@ struct cache_detail ip_map_cache = { .hash_table = ip_table, .name = "auth.unix.ip", .cache_put = ip_map_put, - .cache_request = ip_map_request, + .cache_upcall = ip_map_upcall, .cache_parse = ip_map_parse, .cache_show = ip_map_show, .match = ip_map_match, @@ -523,6 +528,11 @@ static void unix_gid_request(struct cache_detail *cd, (*bpp)[-1] = '\n'; } +static int unix_gid_upcall(struct cache_detail *cd, struct cache_head *h) +{ + return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request); +} + static struct unix_gid *unix_gid_lookup(uid_t uid); extern struct cache_detail unix_gid_cache; @@ -622,7 +632,7 @@ struct cache_detail unix_gid_cache = { .hash_table = gid_table, .name = "auth.unix.gid", .cache_put = unix_gid_put, - .cache_request = unix_gid_request, + .cache_upcall = unix_gid_upcall, .cache_parse = unix_gid_parse, .cache_show = unix_gid_show, .match = unix_gid_match, -- cgit v0.10.2 From 173912a6add00f4715774dcecf9ee53274c5924c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:29 -0400 Subject: SUNRPC: Move procfs-specific stuff out of the generic sunrpc cache code Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 23ee259..8e5bf30 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -59,6 +59,11 @@ struct cache_head { #define CACHE_NEW_EXPIRY 120 /* keep new things pending confirmation for 120 seconds */ +struct cache_detail_procfs { + struct proc_dir_entry *proc_ent; + struct proc_dir_entry *flush_ent, *channel_ent, *content_ent; +}; + struct cache_detail { struct module * owner; int hash_size; @@ -98,12 +103,14 @@ struct cache_detail { /* fields for communication over channel */ struct list_head queue; - struct proc_dir_entry *proc_ent; - struct proc_dir_entry *flush_ent, *channel_ent, *content_ent; atomic_t readers; /* how many time is /chennel open */ time_t last_close; /* if no readers, when did last close */ time_t last_warn; /* when we last warned about no readers */ + + union { + struct cache_detail_procfs procfs; + } u; }; diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index e438352..1cd82ed 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -291,69 +291,9 @@ static DEFINE_SPINLOCK(cache_list_lock); static struct cache_detail *current_detail; static int current_index; -static const struct file_operations cache_file_operations; -static const struct file_operations content_file_operations; -static const struct file_operations cache_flush_operations; - static void do_cache_clean(struct work_struct *work); static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean); -static void remove_cache_proc_entries(struct cache_detail *cd) -{ - if (cd->proc_ent == NULL) - return; - if (cd->flush_ent) - remove_proc_entry("flush", cd->proc_ent); - if (cd->channel_ent) - remove_proc_entry("channel", cd->proc_ent); - if (cd->content_ent) - remove_proc_entry("content", cd->proc_ent); - cd->proc_ent = NULL; - remove_proc_entry(cd->name, proc_net_rpc); -} - -#ifdef CONFIG_PROC_FS -static int create_cache_proc_entries(struct cache_detail *cd) -{ - struct proc_dir_entry *p; - - cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc); - if (cd->proc_ent == NULL) - goto out_nomem; - cd->channel_ent = cd->content_ent = NULL; - - p = proc_create_data("flush", S_IFREG|S_IRUSR|S_IWUSR, - cd->proc_ent, &cache_flush_operations, cd); - cd->flush_ent = p; - if (p == NULL) - goto out_nomem; - - if (cd->cache_upcall || cd->cache_parse) { - p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR, - cd->proc_ent, &cache_file_operations, cd); - cd->channel_ent = p; - if (p == NULL) - goto out_nomem; - } - if (cd->cache_show) { - p = proc_create_data("content", S_IFREG|S_IRUSR|S_IWUSR, - cd->proc_ent, &content_file_operations, cd); - cd->content_ent = p; - if (p == NULL) - goto out_nomem; - } - return 0; -out_nomem: - remove_cache_proc_entries(cd); - return -ENOMEM; -} -#else /* CONFIG_PROC_FS */ -static int create_cache_proc_entries(struct cache_detail *cd) -{ - return 0; -} -#endif - static void sunrpc_init_cache_detail(struct cache_detail *cd) { rwlock_init(&cd->hash_lock); @@ -395,25 +335,6 @@ out: printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name); } -int cache_register(struct cache_detail *cd) -{ - int ret; - - sunrpc_init_cache_detail(cd); - ret = create_cache_proc_entries(cd); - if (ret) - sunrpc_destroy_cache_detail(cd); - return ret; -} -EXPORT_SYMBOL_GPL(cache_register); - -void cache_unregister(struct cache_detail *cd) -{ - remove_cache_proc_entries(cd); - sunrpc_destroy_cache_detail(cd); -} -EXPORT_SYMBOL_GPL(cache_unregister); - /* clean cache tries to find something to clean * and cleans it. * It returns 1 if it cleaned something, @@ -704,13 +625,12 @@ struct cache_reader { int offset; /* if non-0, we have a refcnt on next request */ }; -static ssize_t -cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) +static ssize_t cache_read(struct file *filp, char __user *buf, size_t count, + loff_t *ppos, struct cache_detail *cd) { struct cache_reader *rp = filp->private_data; struct cache_request *rq; struct inode *inode = filp->f_path.dentry->d_inode; - struct cache_detail *cd = PDE(inode)->data; int err; if (count == 0) @@ -834,13 +754,12 @@ out_slow: return cache_slow_downcall(buf, count, cd); } -static ssize_t -cache_write(struct file *filp, const char __user *buf, size_t count, - loff_t *ppos) +static ssize_t cache_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos, + struct cache_detail *cd) { struct address_space *mapping = filp->f_mapping; struct inode *inode = filp->f_path.dentry->d_inode; - struct cache_detail *cd = PDE(inode)->data; ssize_t ret = -EINVAL; if (!cd->cache_parse) @@ -855,13 +774,12 @@ out: static DECLARE_WAIT_QUEUE_HEAD(queue_wait); -static unsigned int -cache_poll(struct file *filp, poll_table *wait) +static unsigned int cache_poll(struct file *filp, poll_table *wait, + struct cache_detail *cd) { unsigned int mask; struct cache_reader *rp = filp->private_data; struct cache_queue *cq; - struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; poll_wait(filp, &queue_wait, wait); @@ -883,14 +801,13 @@ cache_poll(struct file *filp, poll_table *wait) return mask; } -static int -cache_ioctl(struct inode *ino, struct file *filp, - unsigned int cmd, unsigned long arg) +static int cache_ioctl(struct inode *ino, struct file *filp, + unsigned int cmd, unsigned long arg, + struct cache_detail *cd) { int len = 0; struct cache_reader *rp = filp->private_data; struct cache_queue *cq; - struct cache_detail *cd = PDE(ino)->data; if (cmd != FIONREAD || !rp) return -EINVAL; @@ -913,15 +830,13 @@ cache_ioctl(struct inode *ino, struct file *filp, return put_user(len, (int __user *)arg); } -static int -cache_open(struct inode *inode, struct file *filp) +static int cache_open(struct inode *inode, struct file *filp, + struct cache_detail *cd) { struct cache_reader *rp = NULL; nonseekable_open(inode, filp); if (filp->f_mode & FMODE_READ) { - struct cache_detail *cd = PDE(inode)->data; - rp = kmalloc(sizeof(*rp), GFP_KERNEL); if (!rp) return -ENOMEM; @@ -936,11 +851,10 @@ cache_open(struct inode *inode, struct file *filp) return 0; } -static int -cache_release(struct inode *inode, struct file *filp) +static int cache_release(struct inode *inode, struct file *filp, + struct cache_detail *cd) { struct cache_reader *rp = filp->private_data; - struct cache_detail *cd = PDE(inode)->data; if (rp) { spin_lock(&queue_lock); @@ -969,18 +883,6 @@ cache_release(struct inode *inode, struct file *filp) -static const struct file_operations cache_file_operations = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cache_read, - .write = cache_write, - .poll = cache_poll, - .ioctl = cache_ioctl, /* for FIONREAD */ - .open = cache_open, - .release = cache_release, -}; - - static void queue_loose(struct cache_detail *detail, struct cache_head *ch) { struct cache_queue *cq; @@ -1307,10 +1209,10 @@ static const struct seq_operations cache_content_op = { .show = c_show, }; -static int content_open(struct inode *inode, struct file *file) +static int content_open(struct inode *inode, struct file *file, + struct cache_detail *cd) { struct handle *han; - struct cache_detail *cd = PDE(inode)->data; han = __seq_open_private(file, &cache_content_op, sizeof(*han)); if (han == NULL) @@ -1320,17 +1222,10 @@ static int content_open(struct inode *inode, struct file *file) return 0; } -static const struct file_operations content_file_operations = { - .open = content_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; - static ssize_t read_flush(struct file *file, char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos, + struct cache_detail *cd) { - struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data; char tbuf[20]; unsigned long p = *ppos; size_t len; @@ -1348,10 +1243,10 @@ static ssize_t read_flush(struct file *file, char __user *buf, return len; } -static ssize_t write_flush(struct file * file, const char __user * buf, - size_t count, loff_t *ppos) +static ssize_t write_flush(struct file *file, const char __user *buf, + size_t count, loff_t *ppos, + struct cache_detail *cd) { - struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data; char tbuf[20]; char *ep; long flushtime; @@ -1372,8 +1267,174 @@ static ssize_t write_flush(struct file * file, const char __user * buf, return count; } -static const struct file_operations cache_flush_operations = { +static ssize_t cache_read_procfs(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + + return cache_read(filp, buf, count, ppos, cd); +} + +static ssize_t cache_write_procfs(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + + return cache_write(filp, buf, count, ppos, cd); +} + +static unsigned int cache_poll_procfs(struct file *filp, poll_table *wait) +{ + struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + + return cache_poll(filp, wait, cd); +} + +static int cache_ioctl_procfs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct cache_detail *cd = PDE(inode)->data; + + return cache_ioctl(inode, filp, cmd, arg, cd); +} + +static int cache_open_procfs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = PDE(inode)->data; + + return cache_open(inode, filp, cd); +} + +static int cache_release_procfs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = PDE(inode)->data; + + return cache_release(inode, filp, cd); +} + +static const struct file_operations cache_file_operations_procfs = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = cache_read_procfs, + .write = cache_write_procfs, + .poll = cache_poll_procfs, + .ioctl = cache_ioctl_procfs, /* for FIONREAD */ + .open = cache_open_procfs, + .release = cache_release_procfs, +}; + +static int content_open_procfs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = PDE(inode)->data; + + return content_open(inode, filp, cd); +} + +static const struct file_operations content_file_operations_procfs = { + .open = content_open_procfs, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + +static ssize_t read_flush_procfs(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + + return read_flush(filp, buf, count, ppos, cd); +} + +static ssize_t write_flush_procfs(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; + + return write_flush(filp, buf, count, ppos, cd); +} + +static const struct file_operations cache_flush_operations_procfs = { .open = nonseekable_open, - .read = read_flush, - .write = write_flush, + .read = read_flush_procfs, + .write = write_flush_procfs, }; + +static void remove_cache_proc_entries(struct cache_detail *cd) +{ + if (cd->u.procfs.proc_ent == NULL) + return; + if (cd->u.procfs.flush_ent) + remove_proc_entry("flush", cd->u.procfs.proc_ent); + if (cd->u.procfs.channel_ent) + remove_proc_entry("channel", cd->u.procfs.proc_ent); + if (cd->u.procfs.content_ent) + remove_proc_entry("content", cd->u.procfs.proc_ent); + cd->u.procfs.proc_ent = NULL; + remove_proc_entry(cd->name, proc_net_rpc); +} + +#ifdef CONFIG_PROC_FS +static int create_cache_proc_entries(struct cache_detail *cd) +{ + struct proc_dir_entry *p; + + cd->u.procfs.proc_ent = proc_mkdir(cd->name, proc_net_rpc); + if (cd->u.procfs.proc_ent == NULL) + goto out_nomem; + cd->u.procfs.channel_ent = NULL; + cd->u.procfs.content_ent = NULL; + + p = proc_create_data("flush", S_IFREG|S_IRUSR|S_IWUSR, + cd->u.procfs.proc_ent, + &cache_flush_operations_procfs, cd); + cd->u.procfs.flush_ent = p; + if (p == NULL) + goto out_nomem; + + if (cd->cache_upcall || cd->cache_parse) { + p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR, + cd->u.procfs.proc_ent, + &cache_file_operations_procfs, cd); + cd->u.procfs.channel_ent = p; + if (p == NULL) + goto out_nomem; + } + if (cd->cache_show) { + p = proc_create_data("content", S_IFREG|S_IRUSR|S_IWUSR, + cd->u.procfs.proc_ent, + &content_file_operations_procfs, cd); + cd->u.procfs.content_ent = p; + if (p == NULL) + goto out_nomem; + } + return 0; +out_nomem: + remove_cache_proc_entries(cd); + return -ENOMEM; +} +#else /* CONFIG_PROC_FS */ +static int create_cache_proc_entries(struct cache_detail *cd) +{ + return 0; +} +#endif + +int cache_register(struct cache_detail *cd) +{ + int ret; + + sunrpc_init_cache_detail(cd); + ret = create_cache_proc_entries(cd); + if (ret) + sunrpc_destroy_cache_detail(cd); + return ret; +} +EXPORT_SYMBOL_GPL(cache_register); + +void cache_unregister(struct cache_detail *cd) +{ + remove_cache_proc_entries(cd); + sunrpc_destroy_cache_detail(cd); +} +EXPORT_SYMBOL_GPL(cache_unregister); -- cgit v0.10.2 From 8854e82d9accc80f43c0bc3ff06b5979ac858185 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:14:30 -0400 Subject: SUNRPC: Add an rpc_pipefs front end for the sunrpc cache code Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 8e5bf30..6f52b4d 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -64,6 +64,10 @@ struct cache_detail_procfs { struct proc_dir_entry *flush_ent, *channel_ent, *content_ent; }; +struct cache_detail_pipefs { + struct dentry *dir; +}; + struct cache_detail { struct module * owner; int hash_size; @@ -110,6 +114,7 @@ struct cache_detail { union { struct cache_detail_procfs procfs; + struct cache_detail_pipefs pipefs; } u; }; @@ -135,6 +140,10 @@ struct cache_deferred_req { }; +extern const struct file_operations cache_file_operations_pipefs; +extern const struct file_operations content_file_operations_pipefs; +extern const struct file_operations cache_flush_operations_pipefs; + extern struct cache_head * sunrpc_cache_lookup(struct cache_detail *detail, struct cache_head *key, int hash); @@ -186,6 +195,10 @@ extern void cache_purge(struct cache_detail *detail); extern int cache_register(struct cache_detail *cd); extern void cache_unregister(struct cache_detail *cd); +extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *, + mode_t, struct cache_detail *); +extern void sunrpc_cache_unregister_pipefs(struct cache_detail *); + extern void qword_add(char **bpp, int *lp, char *str); extern void qword_addhex(char **bpp, int *lp, char *buf, int blen); extern int qword_get(char **bpp, char *dest, int bufsize); diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 88332ef..a92571a 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -47,6 +47,14 @@ extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); struct rpc_clnt; extern struct dentry *rpc_create_client_dir(struct dentry *, struct qstr *, struct rpc_clnt *); extern int rpc_remove_client_dir(struct dentry *); + +struct cache_detail; +extern struct dentry *rpc_create_cache_dir(struct dentry *, + struct qstr *, + mode_t umode, + struct cache_detail *); +extern void rpc_remove_cache_dir(struct dentry *); + extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, const struct rpc_pipe_ops *, int flags); extern int rpc_unlink(struct dentry *); diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 1cd82ed..db7720e 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -32,6 +32,7 @@ #include #include #include +#include #define RPCDBG_FACILITY RPCDBG_CACHE @@ -1438,3 +1439,128 @@ void cache_unregister(struct cache_detail *cd) sunrpc_destroy_cache_detail(cd); } EXPORT_SYMBOL_GPL(cache_unregister); + +static ssize_t cache_read_pipefs(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; + + return cache_read(filp, buf, count, ppos, cd); +} + +static ssize_t cache_write_pipefs(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; + + return cache_write(filp, buf, count, ppos, cd); +} + +static unsigned int cache_poll_pipefs(struct file *filp, poll_table *wait) +{ + struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; + + return cache_poll(filp, wait, cd); +} + +static int cache_ioctl_pipefs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct cache_detail *cd = RPC_I(inode)->private; + + return cache_ioctl(inode, filp, cmd, arg, cd); +} + +static int cache_open_pipefs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = RPC_I(inode)->private; + + return cache_open(inode, filp, cd); +} + +static int cache_release_pipefs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = RPC_I(inode)->private; + + return cache_release(inode, filp, cd); +} + +const struct file_operations cache_file_operations_pipefs = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = cache_read_pipefs, + .write = cache_write_pipefs, + .poll = cache_poll_pipefs, + .ioctl = cache_ioctl_pipefs, /* for FIONREAD */ + .open = cache_open_pipefs, + .release = cache_release_pipefs, +}; + +static int content_open_pipefs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = RPC_I(inode)->private; + + return content_open(inode, filp, cd); +} + +const struct file_operations content_file_operations_pipefs = { + .open = content_open_pipefs, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + +static ssize_t read_flush_pipefs(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; + + return read_flush(filp, buf, count, ppos, cd); +} + +static ssize_t write_flush_pipefs(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; + + return write_flush(filp, buf, count, ppos, cd); +} + +const struct file_operations cache_flush_operations_pipefs = { + .open = nonseekable_open, + .read = read_flush_pipefs, + .write = write_flush_pipefs, +}; + +int sunrpc_cache_register_pipefs(struct dentry *parent, + const char *name, mode_t umode, + struct cache_detail *cd) +{ + struct qstr q; + struct dentry *dir; + int ret = 0; + + sunrpc_init_cache_detail(cd); + q.name = name; + q.len = strlen(name); + q.hash = full_name_hash(q.name, q.len); + dir = rpc_create_cache_dir(parent, &q, umode, cd); + if (!IS_ERR(dir)) + cd->u.pipefs.dir = dir; + else { + sunrpc_destroy_cache_detail(cd); + ret = PTR_ERR(dir); + } + return ret; +} +EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs); + +void sunrpc_cache_unregister_pipefs(struct cache_detail *cd) +{ + rpc_remove_cache_dir(cd->u.pipefs.dir); + cd->u.pipefs.dir = NULL; + sunrpc_destroy_cache_detail(cd); +} +EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs); + diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 57e9cd3..8dd8153 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -26,6 +26,7 @@ #include #include #include +#include static struct vfsmount *rpc_mount __read_mostly; static int rpc_mount_count; @@ -882,6 +883,48 @@ int rpc_remove_client_dir(struct dentry *dentry) return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate); } +static const struct rpc_filelist cache_pipefs_files[3] = { + [0] = { + .name = "channel", + .i_fop = &cache_file_operations_pipefs, + .mode = S_IFIFO|S_IRUSR|S_IWUSR, + }, + [1] = { + .name = "content", + .i_fop = &content_file_operations_pipefs, + .mode = S_IFREG|S_IRUSR, + }, + [2] = { + .name = "flush", + .i_fop = &cache_flush_operations_pipefs, + .mode = S_IFREG|S_IRUSR|S_IWUSR, + }, +}; + +static int rpc_cachedir_populate(struct dentry *dentry, void *private) +{ + return rpc_populate(dentry, + cache_pipefs_files, 0, 3, + private); +} + +static void rpc_cachedir_depopulate(struct dentry *dentry) +{ + rpc_depopulate(dentry, cache_pipefs_files, 0, 3); +} + +struct dentry *rpc_create_cache_dir(struct dentry *parent, struct qstr *name, + mode_t umode, struct cache_detail *cd) +{ + return rpc_mkdir_populate(parent, name, umode, NULL, + rpc_cachedir_populate, cd); +} + +void rpc_remove_cache_dir(struct dentry *dentry) +{ + rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate); +} + /* * populate the filesystem */ -- cgit v0.10.2 From 9f51e24ee8b5a1595b6a5ac0c2be278a16488e75 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 9 Aug 2009 21:54:00 +0200 Subject: x86: Use printk_once() Signed-off-by: Marcin Slusarz Cc: "H. Peter Anvin" LKML-Reference: <1249847649-11631-6-git-send-email-marcin.slusarz@gmail.com> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 3b09634..7d35d0f 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -218,7 +218,6 @@ bool handle_irq(unsigned irq, struct pt_regs *regs) void fixup_irqs(void) { unsigned int irq; - static int warned; struct irq_desc *desc; for_each_irq_desc(irq, desc) { @@ -236,8 +235,8 @@ void fixup_irqs(void) } if (desc->chip->set_affinity) desc->chip->set_affinity(irq, affinity); - else if (desc->action && !(warned++)) - printk("Cannot set affinity for irq %i\n", irq); + else if (desc->action) + printk_once("Cannot set affinity for irq %i\n", irq); } #if 0 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index fe5474a..0572c90 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2261,12 +2261,7 @@ static int emulator_cmpxchg_emulated(unsigned long addr, unsigned int bytes, struct kvm_vcpu *vcpu) { - static int reported; - - if (!reported) { - reported = 1; - printk(KERN_WARNING "kvm: emulating exchange as write\n"); - } + printk_once(KERN_WARNING "kvm: emulating exchange as write\n"); #ifndef CONFIG_X86_64 /* guests cmpxchg8b have to be emulated atomically */ if (bytes == 8) { -- cgit v0.10.2 From 47d439e9fb8a81a90022cfa785bf1c36c4e2aff6 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 7 Aug 2009 14:53:57 -0400 Subject: security: define round_hint_to_min in !CONFIG_SECURITY Fix the header files to define round_hint_to_min() and to define mmap_min_addr_handler() in the !CONFIG_SECURITY case. Built and tested with !CONFIG_SECURITY Signed-off-by: Eric Paris Signed-off-by: James Morris diff --git a/include/linux/security.h b/include/linux/security.h index 7b43115..57ead99 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -121,6 +121,21 @@ struct request_sock; #define LSM_UNSAFE_PTRACE 2 #define LSM_UNSAFE_PTRACE_CAP 4 +/* + * If a hint addr is less than mmap_min_addr change hint to be as + * low as possible but still greater than mmap_min_addr + */ +static inline unsigned long round_hint_to_min(unsigned long hint) +{ + hint &= PAGE_MASK; + if (((void *)hint != NULL) && + (hint < mmap_min_addr)) + return PAGE_ALIGN(mmap_min_addr); + return hint; +} +extern int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos); + #ifdef CONFIG_SECURITY struct security_mnt_opts { @@ -149,21 +164,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) opts->num_mnt_opts = 0; } -/* - * If a hint addr is less than mmap_min_addr change hint to be as - * low as possible but still greater than mmap_min_addr - */ -static inline unsigned long round_hint_to_min(unsigned long hint) -{ - hint &= PAGE_MASK; - if (((void *)hint != NULL) && - (hint < mmap_min_addr)) - return PAGE_ALIGN(mmap_min_addr); - return hint; -} - -extern int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos); /** * struct security_operations - main security structure * -- cgit v0.10.2 From d3c8660233d3f2801e14eaf722937ff4ed49bfb7 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 10 Jul 2009 03:27:38 +0200 Subject: mm_for_maps: shift down_read(mmap_sem) to the caller mm_for_maps() takes ->mmap_sem after security checks, this looks strange and obfuscates the locking rules. Move this lock to its single caller, m_start(). Signed-off-by: Oleg Nesterov Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/fs/proc/base.c b/fs/proc/base.c index 917f338..f3c2e40 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -235,9 +235,8 @@ static int check_mem_permission(struct task_struct *task) struct mm_struct *mm_for_maps(struct task_struct *task) { struct mm_struct *mm = get_task_mm(task); - if (!mm) - return NULL; - if (mm != current->mm) { + + if (mm && mm != current->mm) { /* * task->mm can be changed before security check, * in that case we must notice the change after. @@ -245,10 +244,9 @@ struct mm_struct *mm_for_maps(struct task_struct *task) if (!ptrace_may_access(task, PTRACE_MODE_READ) || mm != task->mm) { mmput(mm); - return NULL; + mm = NULL; } } - down_read(&mm->mmap_sem); return mm; } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 6f61b7c..9bd8be1 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -119,6 +119,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) mm = mm_for_maps(priv->task); if (!mm) return NULL; + down_read(&mm->mmap_sem); tail_vma = get_gate_vma(priv->task); priv->tail_vma = tail_vma; diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 64a72e2..8f5c05d 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -189,6 +189,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) priv->task = NULL; return NULL; } + down_read(&mm->mmap_sem); /* start from the Nth VMA */ for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) -- cgit v0.10.2 From 896a6de40ef3814525632609799af909338f50c3 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 10 Jul 2009 03:27:40 +0200 Subject: mm_for_maps: take ->cred_guard_mutex to fix the race with exec The problem is minor, but without ->cred_guard_mutex held we can race with exec() and get the new ->mm but check old creds. Now we do not need to re-check task->mm after ptrace_may_access(), it can't be changed to the new mm under us. Strictly speaking, this also fixes another very minor problem. Unless security check fails or the task exits mm_for_maps() should never return NULL, the caller should get either old or new ->mm. Signed-off-by: Oleg Nesterov Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/fs/proc/base.c b/fs/proc/base.c index f3c2e40..175db25 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -234,19 +234,19 @@ static int check_mem_permission(struct task_struct *task) struct mm_struct *mm_for_maps(struct task_struct *task) { - struct mm_struct *mm = get_task_mm(task); + struct mm_struct *mm; - if (mm && mm != current->mm) { - /* - * task->mm can be changed before security check, - * in that case we must notice the change after. - */ - if (!ptrace_may_access(task, PTRACE_MODE_READ) || - mm != task->mm) { - mmput(mm); - mm = NULL; - } + if (mutex_lock_killable(&task->cred_guard_mutex)) + return NULL; + + mm = get_task_mm(task); + if (mm && mm != current->mm && + !ptrace_may_access(task, PTRACE_MODE_READ)) { + mmput(mm); + mm = NULL; } + mutex_unlock(&task->cred_guard_mutex); + return mm; } -- cgit v0.10.2 From 85a7f0ac5370901916a21935e1fafbe397b70f80 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 10 Aug 2009 12:50:03 +1000 Subject: crypto: mv_cesa - Add support for Orion5X crypto engine This adds support for Marvell's Cryptographic Engines and Security Accelerator (CESA) which can be found on a few SoC. Tested with dm-crypt. Acked-by: Nicolas Pitre Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Herbert Xu diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 1bb4b7fe..b08403d 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -157,6 +157,19 @@ config S390_PRNG ANSI X9.17 standard. The PRNG is usable via the char device /dev/prandom. +config CRYPTO_DEV_MV_CESA + tristate "Marvell's Cryptographic Engine" + depends on PLAT_ORION + select CRYPTO_ALGAPI + select CRYPTO_AES + select CRYPTO_BLKCIPHER2 + help + This driver allows you to utilize the Cryptographic Engines and + Security Accelerator (CESA) which can be found on the Marvell Orion + and Kirkwood SoCs, such as QNAP's TS-209. + + Currently the driver supports AES in ECB and CBC mode without DMA. + config CRYPTO_DEV_HIFN_795X tristate "Driver HIFN 795x crypto accelerator chips" select CRYPTO_DES diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 9bf4a2b..6ffcb3f 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o +obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/ diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c new file mode 100644 index 0000000..b21ef63 --- /dev/null +++ b/drivers/crypto/mv_cesa.c @@ -0,0 +1,606 @@ +/* + * Support for Marvell's crypto engine which can be found on some Orion5X + * boards. + * + * Author: Sebastian Andrzej Siewior < sebastian at breakpoint dot cc > + * License: GPLv2 + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mv_cesa.h" +/* + * STM: + * /---------------------------------------\ + * | | request complete + * \./ | + * IDLE -> new request -> BUSY -> done -> DEQUEUE + * /°\ | + * | | more scatter entries + * \________________/ + */ +enum engine_status { + ENGINE_IDLE, + ENGINE_BUSY, + ENGINE_W_DEQUEUE, +}; + +/** + * struct req_progress - used for every crypt request + * @src_sg_it: sg iterator for src + * @dst_sg_it: sg iterator for dst + * @sg_src_left: bytes left in src to process (scatter list) + * @src_start: offset to add to src start position (scatter list) + * @crypt_len: length of current crypt process + * @sg_dst_left: bytes left dst to process in this scatter list + * @dst_start: offset to add to dst start position (scatter list) + * @total_req_bytes: total number of bytes processed (request). + * + * sg helper are used to iterate over the scatterlist. Since the size of the + * SRAM may be less than the scatter size, this struct struct is used to keep + * track of progress within current scatterlist. + */ +struct req_progress { + struct sg_mapping_iter src_sg_it; + struct sg_mapping_iter dst_sg_it; + + /* src mostly */ + int sg_src_left; + int src_start; + int crypt_len; + /* dst mostly */ + int sg_dst_left; + int dst_start; + int total_req_bytes; +}; + +struct crypto_priv { + void __iomem *reg; + void __iomem *sram; + int irq; + struct task_struct *queue_th; + + /* the lock protects queue and eng_st */ + spinlock_t lock; + struct crypto_queue queue; + enum engine_status eng_st; + struct ablkcipher_request *cur_req; + struct req_progress p; + int max_req_size; + int sram_size; +}; + +static struct crypto_priv *cpg; + +struct mv_ctx { + u8 aes_enc_key[AES_KEY_LEN]; + u32 aes_dec_key[8]; + int key_len; + u32 need_calc_aes_dkey; +}; + +enum crypto_op { + COP_AES_ECB, + COP_AES_CBC, +}; + +struct mv_req_ctx { + enum crypto_op op; + int decrypt; +}; + +static void compute_aes_dec_key(struct mv_ctx *ctx) +{ + struct crypto_aes_ctx gen_aes_key; + int key_pos; + + if (!ctx->need_calc_aes_dkey) + return; + + crypto_aes_expand_key(&gen_aes_key, ctx->aes_enc_key, ctx->key_len); + + key_pos = ctx->key_len + 24; + memcpy(ctx->aes_dec_key, &gen_aes_key.key_enc[key_pos], 4 * 4); + switch (ctx->key_len) { + case AES_KEYSIZE_256: + key_pos -= 2; + /* fall */ + case AES_KEYSIZE_192: + key_pos -= 2; + memcpy(&ctx->aes_dec_key[4], &gen_aes_key.key_enc[key_pos], + 4 * 4); + break; + } + ctx->need_calc_aes_dkey = 0; +} + +static int mv_setkey_aes(struct crypto_ablkcipher *cipher, const u8 *key, + unsigned int len) +{ + struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); + struct mv_ctx *ctx = crypto_tfm_ctx(tfm); + + switch (len) { + case AES_KEYSIZE_128: + case AES_KEYSIZE_192: + case AES_KEYSIZE_256: + break; + default: + crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + ctx->key_len = len; + ctx->need_calc_aes_dkey = 1; + + memcpy(ctx->aes_enc_key, key, AES_KEY_LEN); + return 0; +} + +static void setup_data_in(struct ablkcipher_request *req) +{ + int ret; + void *buf; + + if (!cpg->p.sg_src_left) { + ret = sg_miter_next(&cpg->p.src_sg_it); + BUG_ON(!ret); + cpg->p.sg_src_left = cpg->p.src_sg_it.length; + cpg->p.src_start = 0; + } + + cpg->p.crypt_len = min(cpg->p.sg_src_left, cpg->max_req_size); + + buf = cpg->p.src_sg_it.addr; + buf += cpg->p.src_start; + + memcpy(cpg->sram + SRAM_DATA_IN_START, buf, cpg->p.crypt_len); + + cpg->p.sg_src_left -= cpg->p.crypt_len; + cpg->p.src_start += cpg->p.crypt_len; +} + +static void mv_process_current_q(int first_block) +{ + struct ablkcipher_request *req = cpg->cur_req; + struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + struct sec_accel_config op; + + switch (req_ctx->op) { + case COP_AES_ECB: + op.config = CFG_OP_CRYPT_ONLY | CFG_ENCM_AES | CFG_ENC_MODE_ECB; + break; + case COP_AES_CBC: + op.config = CFG_OP_CRYPT_ONLY | CFG_ENCM_AES | CFG_ENC_MODE_CBC; + op.enc_iv = ENC_IV_POINT(SRAM_DATA_IV) | + ENC_IV_BUF_POINT(SRAM_DATA_IV_BUF); + if (first_block) + memcpy(cpg->sram + SRAM_DATA_IV, req->info, 16); + break; + } + if (req_ctx->decrypt) { + op.config |= CFG_DIR_DEC; + memcpy(cpg->sram + SRAM_DATA_KEY_P, ctx->aes_dec_key, + AES_KEY_LEN); + } else { + op.config |= CFG_DIR_ENC; + memcpy(cpg->sram + SRAM_DATA_KEY_P, ctx->aes_enc_key, + AES_KEY_LEN); + } + + switch (ctx->key_len) { + case AES_KEYSIZE_128: + op.config |= CFG_AES_LEN_128; + break; + case AES_KEYSIZE_192: + op.config |= CFG_AES_LEN_192; + break; + case AES_KEYSIZE_256: + op.config |= CFG_AES_LEN_256; + break; + } + op.enc_p = ENC_P_SRC(SRAM_DATA_IN_START) | + ENC_P_DST(SRAM_DATA_OUT_START); + op.enc_key_p = SRAM_DATA_KEY_P; + + setup_data_in(req); + op.enc_len = cpg->p.crypt_len; + memcpy(cpg->sram + SRAM_CONFIG, &op, + sizeof(struct sec_accel_config)); + + writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); + /* GO */ + writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD); + + /* + * XXX: add timer if the interrupt does not occur for some mystery + * reason + */ +} + +static void mv_crypto_algo_completion(void) +{ + struct ablkcipher_request *req = cpg->cur_req; + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + + if (req_ctx->op != COP_AES_CBC) + return ; + + memcpy(req->info, cpg->sram + SRAM_DATA_IV_BUF, 16); +} + +static void dequeue_complete_req(void) +{ + struct ablkcipher_request *req = cpg->cur_req; + void *buf; + int ret; + + cpg->p.total_req_bytes += cpg->p.crypt_len; + do { + int dst_copy; + + if (!cpg->p.sg_dst_left) { + ret = sg_miter_next(&cpg->p.dst_sg_it); + BUG_ON(!ret); + cpg->p.sg_dst_left = cpg->p.dst_sg_it.length; + cpg->p.dst_start = 0; + } + + buf = cpg->p.dst_sg_it.addr; + buf += cpg->p.dst_start; + + dst_copy = min(cpg->p.crypt_len, cpg->p.sg_dst_left); + + memcpy(buf, cpg->sram + SRAM_DATA_OUT_START, dst_copy); + + cpg->p.sg_dst_left -= dst_copy; + cpg->p.crypt_len -= dst_copy; + cpg->p.dst_start += dst_copy; + } while (cpg->p.crypt_len > 0); + + BUG_ON(cpg->eng_st != ENGINE_W_DEQUEUE); + if (cpg->p.total_req_bytes < req->nbytes) { + /* process next scatter list entry */ + cpg->eng_st = ENGINE_BUSY; + mv_process_current_q(0); + } else { + sg_miter_stop(&cpg->p.src_sg_it); + sg_miter_stop(&cpg->p.dst_sg_it); + mv_crypto_algo_completion(); + cpg->eng_st = ENGINE_IDLE; + req->base.complete(&req->base, 0); + } +} + +static int count_sgs(struct scatterlist *sl, unsigned int total_bytes) +{ + int i = 0; + + do { + total_bytes -= sl[i].length; + i++; + + } while (total_bytes > 0); + + return i; +} + +static void mv_enqueue_new_req(struct ablkcipher_request *req) +{ + int num_sgs; + + cpg->cur_req = req; + memset(&cpg->p, 0, sizeof(struct req_progress)); + + num_sgs = count_sgs(req->src, req->nbytes); + sg_miter_start(&cpg->p.src_sg_it, req->src, num_sgs, SG_MITER_FROM_SG); + + num_sgs = count_sgs(req->dst, req->nbytes); + sg_miter_start(&cpg->p.dst_sg_it, req->dst, num_sgs, SG_MITER_TO_SG); + mv_process_current_q(1); +} + +static int queue_manag(void *data) +{ + cpg->eng_st = ENGINE_IDLE; + do { + struct ablkcipher_request *req; + struct crypto_async_request *async_req = NULL; + struct crypto_async_request *backlog; + + __set_current_state(TASK_INTERRUPTIBLE); + + if (cpg->eng_st == ENGINE_W_DEQUEUE) + dequeue_complete_req(); + + spin_lock_irq(&cpg->lock); + if (cpg->eng_st == ENGINE_IDLE) { + backlog = crypto_get_backlog(&cpg->queue); + async_req = crypto_dequeue_request(&cpg->queue); + if (async_req) { + BUG_ON(cpg->eng_st != ENGINE_IDLE); + cpg->eng_st = ENGINE_BUSY; + } + } + spin_unlock_irq(&cpg->lock); + + if (backlog) { + backlog->complete(backlog, -EINPROGRESS); + backlog = NULL; + } + + if (async_req) { + req = container_of(async_req, + struct ablkcipher_request, base); + mv_enqueue_new_req(req); + async_req = NULL; + } + + schedule(); + + } while (!kthread_should_stop()); + return 0; +} + +static int mv_handle_req(struct ablkcipher_request *req) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&cpg->lock, flags); + ret = ablkcipher_enqueue_request(&cpg->queue, req); + spin_unlock_irqrestore(&cpg->lock, flags); + wake_up_process(cpg->queue_th); + return ret; +} + +static int mv_enc_aes_ecb(struct ablkcipher_request *req) +{ + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + + req_ctx->op = COP_AES_ECB; + req_ctx->decrypt = 0; + + return mv_handle_req(req); +} + +static int mv_dec_aes_ecb(struct ablkcipher_request *req) +{ + struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + + req_ctx->op = COP_AES_ECB; + req_ctx->decrypt = 1; + + compute_aes_dec_key(ctx); + return mv_handle_req(req); +} + +static int mv_enc_aes_cbc(struct ablkcipher_request *req) +{ + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + + req_ctx->op = COP_AES_CBC; + req_ctx->decrypt = 0; + + return mv_handle_req(req); +} + +static int mv_dec_aes_cbc(struct ablkcipher_request *req) +{ + struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + + req_ctx->op = COP_AES_CBC; + req_ctx->decrypt = 1; + + compute_aes_dec_key(ctx); + return mv_handle_req(req); +} + +static int mv_cra_init(struct crypto_tfm *tfm) +{ + tfm->crt_ablkcipher.reqsize = sizeof(struct mv_req_ctx); + return 0; +} + +irqreturn_t crypto_int(int irq, void *priv) +{ + u32 val; + + val = readl(cpg->reg + SEC_ACCEL_INT_STATUS); + if (!(val & SEC_INT_ACCEL0_DONE)) + return IRQ_NONE; + + val &= ~SEC_INT_ACCEL0_DONE; + writel(val, cpg->reg + FPGA_INT_STATUS); + writel(val, cpg->reg + SEC_ACCEL_INT_STATUS); + BUG_ON(cpg->eng_st != ENGINE_BUSY); + cpg->eng_st = ENGINE_W_DEQUEUE; + wake_up_process(cpg->queue_th); + return IRQ_HANDLED; +} + +struct crypto_alg mv_aes_alg_ecb = { + .cra_name = "ecb(aes)", + .cra_driver_name = "mv-ecb-aes", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = 16, + .cra_ctxsize = sizeof(struct mv_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = mv_cra_init, + .cra_u = { + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = mv_setkey_aes, + .encrypt = mv_enc_aes_ecb, + .decrypt = mv_dec_aes_ecb, + }, + }, +}; + +struct crypto_alg mv_aes_alg_cbc = { + .cra_name = "cbc(aes)", + .cra_driver_name = "mv-cbc-aes", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct mv_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = mv_cra_init, + .cra_u = { + .ablkcipher = { + .ivsize = AES_BLOCK_SIZE, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = mv_setkey_aes, + .encrypt = mv_enc_aes_cbc, + .decrypt = mv_dec_aes_cbc, + }, + }, +}; + +static int mv_probe(struct platform_device *pdev) +{ + struct crypto_priv *cp; + struct resource *res; + int irq; + int ret; + + if (cpg) { + printk(KERN_ERR "Second crypto dev?\n"); + return -EEXIST; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + if (!res) + return -ENXIO; + + cp = kzalloc(sizeof(*cp), GFP_KERNEL); + if (!cp) + return -ENOMEM; + + spin_lock_init(&cp->lock); + crypto_init_queue(&cp->queue, 50); + cp->reg = ioremap(res->start, res->end - res->start + 1); + if (!cp->reg) { + ret = -ENOMEM; + goto err; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); + if (!res) { + ret = -ENXIO; + goto err_unmap_reg; + } + cp->sram_size = res->end - res->start + 1; + cp->max_req_size = cp->sram_size - SRAM_CFG_SPACE; + cp->sram = ioremap(res->start, cp->sram_size); + if (!cp->sram) { + ret = -ENOMEM; + goto err_unmap_reg; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0 || irq == NO_IRQ) { + ret = irq; + goto err_unmap_sram; + } + cp->irq = irq; + + platform_set_drvdata(pdev, cp); + cpg = cp; + + cp->queue_th = kthread_run(queue_manag, cp, "mv_crypto"); + if (IS_ERR(cp->queue_th)) { + ret = PTR_ERR(cp->queue_th); + goto err_thread; + } + + ret = request_irq(irq, crypto_int, IRQF_DISABLED, dev_name(&pdev->dev), + cp); + if (ret) + goto err_unmap_sram; + + writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK); + writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG); + + ret = crypto_register_alg(&mv_aes_alg_ecb); + if (ret) + goto err_reg; + + ret = crypto_register_alg(&mv_aes_alg_cbc); + if (ret) + goto err_unreg_ecb; + return 0; +err_unreg_ecb: + crypto_unregister_alg(&mv_aes_alg_ecb); +err_thread: + free_irq(irq, cp); +err_reg: + kthread_stop(cp->queue_th); +err_unmap_sram: + iounmap(cp->sram); +err_unmap_reg: + iounmap(cp->reg); +err: + kfree(cp); + cpg = NULL; + platform_set_drvdata(pdev, NULL); + return ret; +} + +static int mv_remove(struct platform_device *pdev) +{ + struct crypto_priv *cp = platform_get_drvdata(pdev); + + crypto_unregister_alg(&mv_aes_alg_ecb); + crypto_unregister_alg(&mv_aes_alg_cbc); + kthread_stop(cp->queue_th); + free_irq(cp->irq, cp); + memset(cp->sram, 0, cp->sram_size); + iounmap(cp->sram); + iounmap(cp->reg); + kfree(cp); + cpg = NULL; + return 0; +} + +static struct platform_driver marvell_crypto = { + .probe = mv_probe, + .remove = mv_remove, + .driver = { + .owner = THIS_MODULE, + .name = "mv_crypto", + }, +}; +MODULE_ALIAS("platform:mv_crypto"); + +static int __init mv_crypto_init(void) +{ + return platform_driver_register(&marvell_crypto); +} +module_init(mv_crypto_init); + +static void __exit mv_crypto_exit(void) +{ + platform_driver_unregister(&marvell_crypto); +} +module_exit(mv_crypto_exit); + +MODULE_AUTHOR("Sebastian Andrzej Siewior "); +MODULE_DESCRIPTION("Support for Marvell's cryptographic engine"); +MODULE_LICENSE("GPL"); diff --git a/drivers/crypto/mv_cesa.h b/drivers/crypto/mv_cesa.h new file mode 100644 index 0000000..c3e25d3 --- /dev/null +++ b/drivers/crypto/mv_cesa.h @@ -0,0 +1,119 @@ +#ifndef __MV_CRYPTO_H__ + +#define DIGEST_INITIAL_VAL_A 0xdd00 +#define DES_CMD_REG 0xdd58 + +#define SEC_ACCEL_CMD 0xde00 +#define SEC_CMD_EN_SEC_ACCL0 (1 << 0) +#define SEC_CMD_EN_SEC_ACCL1 (1 << 1) +#define SEC_CMD_DISABLE_SEC (1 << 2) + +#define SEC_ACCEL_DESC_P0 0xde04 +#define SEC_DESC_P0_PTR(x) (x) + +#define SEC_ACCEL_DESC_P1 0xde14 +#define SEC_DESC_P1_PTR(x) (x) + +#define SEC_ACCEL_CFG 0xde08 +#define SEC_CFG_STOP_DIG_ERR (1 << 0) +#define SEC_CFG_CH0_W_IDMA (1 << 7) +#define SEC_CFG_CH1_W_IDMA (1 << 8) +#define SEC_CFG_ACT_CH0_IDMA (1 << 9) +#define SEC_CFG_ACT_CH1_IDMA (1 << 10) + +#define SEC_ACCEL_STATUS 0xde0c +#define SEC_ST_ACT_0 (1 << 0) +#define SEC_ST_ACT_1 (1 << 1) + +/* + * FPGA_INT_STATUS looks like a FPGA leftover and is documented only in Errata + * 4.12. It looks like that it was part of an IRQ-controller in FPGA and + * someone forgot to remove it while switching to the core and moving to + * SEC_ACCEL_INT_STATUS. + */ +#define FPGA_INT_STATUS 0xdd68 +#define SEC_ACCEL_INT_STATUS 0xde20 +#define SEC_INT_AUTH_DONE (1 << 0) +#define SEC_INT_DES_E_DONE (1 << 1) +#define SEC_INT_AES_E_DONE (1 << 2) +#define SEC_INT_AES_D_DONE (1 << 3) +#define SEC_INT_ENC_DONE (1 << 4) +#define SEC_INT_ACCEL0_DONE (1 << 5) +#define SEC_INT_ACCEL1_DONE (1 << 6) +#define SEC_INT_ACC0_IDMA_DONE (1 << 7) +#define SEC_INT_ACC1_IDMA_DONE (1 << 8) + +#define SEC_ACCEL_INT_MASK 0xde24 + +#define AES_KEY_LEN (8 * 4) + +struct sec_accel_config { + + u32 config; +#define CFG_OP_MAC_ONLY 0 +#define CFG_OP_CRYPT_ONLY 1 +#define CFG_OP_MAC_CRYPT 2 +#define CFG_OP_CRYPT_MAC 3 +#define CFG_MACM_MD5 (4 << 4) +#define CFG_MACM_SHA1 (5 << 4) +#define CFG_MACM_HMAC_MD5 (6 << 4) +#define CFG_MACM_HMAC_SHA1 (7 << 4) +#define CFG_ENCM_DES (1 << 8) +#define CFG_ENCM_3DES (2 << 8) +#define CFG_ENCM_AES (3 << 8) +#define CFG_DIR_ENC (0 << 12) +#define CFG_DIR_DEC (1 << 12) +#define CFG_ENC_MODE_ECB (0 << 16) +#define CFG_ENC_MODE_CBC (1 << 16) +#define CFG_3DES_EEE (0 << 20) +#define CFG_3DES_EDE (1 << 20) +#define CFG_AES_LEN_128 (0 << 24) +#define CFG_AES_LEN_192 (1 << 24) +#define CFG_AES_LEN_256 (2 << 24) + + u32 enc_p; +#define ENC_P_SRC(x) (x) +#define ENC_P_DST(x) ((x) << 16) + + u32 enc_len; +#define ENC_LEN(x) (x) + + u32 enc_key_p; +#define ENC_KEY_P(x) (x) + + u32 enc_iv; +#define ENC_IV_POINT(x) ((x) << 0) +#define ENC_IV_BUF_POINT(x) ((x) << 16) + + u32 mac_src_p; +#define MAC_SRC_DATA_P(x) (x) +#define MAC_SRC_TOTAL_LEN(x) ((x) << 16) + + u32 mac_digest; + u32 mac_iv; +}__attribute__ ((packed)); + /* + * /-----------\ 0 + * | ACCEL CFG | 4 * 8 + * |-----------| 0x20 + * | CRYPT KEY | 8 * 4 + * |-----------| 0x40 + * | IV IN | 4 * 4 + * |-----------| 0x40 (inplace) + * | IV BUF | 4 * 4 + * |-----------| 0x50 + * | DATA IN | 16 * x (max ->max_req_size) + * |-----------| 0x50 (inplace operation) + * | DATA OUT | 16 * x (max ->max_req_size) + * \-----------/ SRAM size + */ +#define SRAM_CONFIG 0x00 +#define SRAM_DATA_KEY_P 0x20 +#define SRAM_DATA_IV 0x40 +#define SRAM_DATA_IV_BUF 0x40 +#define SRAM_DATA_IN_START 0x50 +#define SRAM_DATA_OUT_START 0x50 + +#define SRAM_CFG_SPACE 0x50 + +#endif -- cgit v0.10.2 From da2a2aaa8e3dddb41678af7e5295d9e3e6c030a4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Aug 2009 07:44:09 +0200 Subject: ALSA: hda - Fix Oops due to STAC/IDT auto-mic changes The previous auto-mic patch for STAC/IDT codecs causes the Oops on machines without digital mic pins. This patch fixes the problem. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 163aad5..2760730 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3671,7 +3671,7 @@ static int set_mic_route(struct hda_codec *codec, if (i < 0) return -1; mic->mux_idx = i; - } else { + } else if (spec->dmux_nids) { /* digital pin */ mic->mux_idx = 0; i = get_connection_index(codec, spec->dmux_nids[0], pin); @@ -4373,7 +4373,8 @@ static int stac92xx_init(struct hda_codec *codec) } if (spec->auto_mic) { /* initialize connection to analog input */ - snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, + if (spec->dmux_nids) + snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, AC_VERB_SET_CONNECT_SEL, 0); if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT)) stac_issue_unsol_event(codec, spec->ext_mic.pin); -- cgit v0.10.2 From a8ad568dd8ca122aa8048ea067d3599820d1c1b4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 10 Aug 2009 11:53:10 +0900 Subject: dma-ops: Remove flush_write_buffers() in dma-mapping-common.h This moves flush_write_buffers() in asm-generic/dma-mapping-common.h to arch/x86/kernel/pci-nommu.c. The purpose of this patch is that, we can avoid defining NULL flush_write_buffers() on IA64 and SPARC. dma-mapping-common.h is used by X86 and IA64 (and SPARC soon) but only X86 with CONFIG_X86_OOSTORE or CONFIG_X86_PPRO_FENCE actually uses flush_write_buffers(). CONFIG_X86_OOSTORE or CONFIG_X86_PPRO_FENCE is usable with only kernel/pci-nommu.c (that is, not usable with other X86 IOMMU implementations such as SWIOTLB, VT-d, etc) so we can safely move flush_write_buffers() in asm-generic/dma-mapping-common.h to arch/x86/kernel/pci-nommu.c. The further discussion is: http://lkml.org/lkml/2009/6/28/104 Signed-off-by: Arnd Bergmann Acked-by: FUJITA Tomonori Cc: davem@davemloft.net Cc: tony.luck@intel.com Cc: fenghua.yu@intel.com LKML-Reference: <1249872797-1314-2-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c index c0a4222..a3933d4 100644 --- a/arch/x86/kernel/pci-nommu.c +++ b/arch/x86/kernel/pci-nommu.c @@ -79,12 +79,29 @@ static void nommu_free_coherent(struct device *dev, size_t size, void *vaddr, free_pages((unsigned long)vaddr, get_order(size)); } +static void nommu_sync_single_for_device(struct device *dev, + dma_addr_t addr, size_t size, + enum dma_data_direction dir) +{ + flush_write_buffers(); +} + + +static void nommu_sync_sg_for_device(struct device *dev, + struct scatterlist *sg, int nelems, + enum dma_data_direction dir) +{ + flush_write_buffers(); +} + struct dma_map_ops nommu_dma_ops = { - .alloc_coherent = dma_generic_alloc_coherent, - .free_coherent = nommu_free_coherent, - .map_sg = nommu_map_sg, - .map_page = nommu_map_page, - .is_phys = 1, + .alloc_coherent = dma_generic_alloc_coherent, + .free_coherent = nommu_free_coherent, + .map_sg = nommu_map_sg, + .map_page = nommu_map_page, + .sync_single_for_device = nommu_sync_single_for_device, + .sync_sg_for_device = nommu_sync_sg_for_device, + .is_phys = 1, }; void __init no_iommu_init(void) diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h index 5406a60..e694263 100644 --- a/include/asm-generic/dma-mapping-common.h +++ b/include/asm-generic/dma-mapping-common.h @@ -103,7 +103,6 @@ static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, if (ops->sync_single_for_cpu) ops->sync_single_for_cpu(dev, addr, size, dir); debug_dma_sync_single_for_cpu(dev, addr, size, dir); - flush_write_buffers(); } static inline void dma_sync_single_for_device(struct device *dev, @@ -116,7 +115,6 @@ static inline void dma_sync_single_for_device(struct device *dev, if (ops->sync_single_for_device) ops->sync_single_for_device(dev, addr, size, dir); debug_dma_sync_single_for_device(dev, addr, size, dir); - flush_write_buffers(); } static inline void dma_sync_single_range_for_cpu(struct device *dev, @@ -132,7 +130,6 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev, ops->sync_single_range_for_cpu(dev, addr, offset, size, dir); debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir); - flush_write_buffers(); } else dma_sync_single_for_cpu(dev, addr, size, dir); } @@ -150,7 +147,6 @@ static inline void dma_sync_single_range_for_device(struct device *dev, ops->sync_single_range_for_device(dev, addr, offset, size, dir); debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir); - flush_write_buffers(); } else dma_sync_single_for_device(dev, addr, size, dir); } @@ -165,7 +161,6 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, if (ops->sync_sg_for_cpu) ops->sync_sg_for_cpu(dev, sg, nelems, dir); debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir); - flush_write_buffers(); } static inline void @@ -179,7 +174,6 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, ops->sync_sg_for_device(dev, sg, nelems, dir); debug_dma_sync_sg_for_device(dev, sg, nelems, dir); - flush_write_buffers(); } #define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL) -- cgit v0.10.2 From be02ff9940c0106dea1470462401a07c5d52e086 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 10 Aug 2009 11:53:11 +0900 Subject: IA64: Remove NULL flush_write_buffers flush_write_buffers() in dma-mapping-common.h was removed so we can remove NULL flush_write_buffers() in IA64. Signed-off-by: FUJITA Tomonori Cc: tony.luck@intel.com Cc: fenghua.yu@intel.com Cc: davem@davemloft.net LKML-Reference: <1249872797-1314-3-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index f91829d..8d3c79c 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -44,7 +44,6 @@ static inline void dma_free_coherent(struct device *dev, size_t size, #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) #define get_dma_ops(dev) platform_dma_get_ops(dev) -#define flush_write_buffers() #include -- cgit v0.10.2 From bc0a14f154069cc4e42ea903c2c2b9984a94e4b7 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 10 Aug 2009 11:53:12 +0900 Subject: sparc: Use dma_map_ops struct Signed-off-by: FUJITA Tomonori Tested-by: Robert Reif Acked-by: David S. Miller Cc: tony.luck@intel.com Cc: fenghua.yu@intel.com LKML-Reference: <1249872797-1314-4-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 204e4bf..893f3ec 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -13,36 +13,7 @@ extern int dma_set_mask(struct device *dev, u64 dma_mask); #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) #define dma_is_consistent(d, h) (1) -struct dma_ops { - void *(*alloc_coherent)(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag); - void (*free_coherent)(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle); - dma_addr_t (*map_page)(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction); - void (*unmap_page)(struct device *dev, dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction); - int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction); - void (*unmap_sg)(struct device *dev, struct scatterlist *sg, - int nhwentries, - enum dma_data_direction direction); - void (*sync_single_for_cpu)(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction); - void (*sync_single_for_device)(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction); - void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, - int nelems, - enum dma_data_direction direction); - void (*sync_sg_for_device)(struct device *dev, - struct scatterlist *sg, int nents, - enum dma_data_direction dir); -}; -extern const struct dma_ops *dma_ops; +extern const struct dma_map_ops *dma_ops; static inline void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) @@ -62,40 +33,40 @@ static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, { return dma_ops->map_page(dev, virt_to_page(cpu_addr), (unsigned long)cpu_addr & ~PAGE_MASK, size, - direction); + direction, NULL); } static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction direction) { - dma_ops->unmap_page(dev, dma_addr, size, direction); + dma_ops->unmap_page(dev, dma_addr, size, direction, NULL); } static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction direction) { - return dma_ops->map_page(dev, page, offset, size, direction); + return dma_ops->map_page(dev, page, offset, size, direction, NULL); } static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, enum dma_data_direction direction) { - dma_ops->unmap_page(dev, dma_address, size, direction); + dma_ops->unmap_page(dev, dma_address, size, direction, NULL); } static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction) { - return dma_ops->map_sg(dev, sg, nents, direction); + return dma_ops->map_sg(dev, sg, nents, direction, NULL); } static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction) { - dma_ops->unmap_sg(dev, sg, nents, direction); + dma_ops->unmap_sg(dev, sg, nents, direction, NULL); } static inline void dma_sync_single_for_cpu(struct device *dev, diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c index 524c32f..473a3fc 100644 --- a/arch/sparc/kernel/dma.c +++ b/arch/sparc/kernel/dma.c @@ -60,7 +60,8 @@ static void dma32_free_coherent(struct device *dev, size_t size, static dma_addr_t dma32_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) @@ -72,7 +73,8 @@ static dma_addr_t dma32_map_page(struct device *dev, struct page *page, } static void dma32_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, enum dma_data_direction direction) + size_t size, enum dma_data_direction direction, + struct dma_attrs *attrs) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -85,7 +87,8 @@ static void dma32_unmap_page(struct device *dev, dma_addr_t dma_address, } static int dma32_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) @@ -95,7 +98,8 @@ static int dma32_map_sg(struct device *dev, struct scatterlist *sg, } void dma32_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -161,7 +165,7 @@ static void dma32_sync_sg_for_device(struct device *dev, BUG(); } -static const struct dma_ops dma32_dma_ops = { +static const struct dma_map_ops dma32_dma_ops = { .alloc_coherent = dma32_alloc_coherent, .free_coherent = dma32_free_coherent, .map_page = dma32_map_page, @@ -174,5 +178,5 @@ static const struct dma_ops dma32_dma_ops = { .sync_sg_for_device = dma32_sync_sg_for_device, }; -const struct dma_ops *dma_ops = &dma32_dma_ops; +const struct dma_map_ops *dma_ops = &dma32_dma_ops; EXPORT_SYMBOL(dma_ops); diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c index 0aeaefe..a9f0ad9 100644 --- a/arch/sparc/kernel/iommu.c +++ b/arch/sparc/kernel/iommu.c @@ -353,7 +353,8 @@ static void dma_4u_free_coherent(struct device *dev, size_t size, static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page, unsigned long offset, size_t sz, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { struct iommu *iommu; struct strbuf *strbuf; @@ -474,7 +475,8 @@ do_flush_sync: } static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr, - size_t sz, enum dma_data_direction direction) + size_t sz, enum dma_data_direction direction, + struct dma_attrs *attrs) { struct iommu *iommu; struct strbuf *strbuf; @@ -520,7 +522,8 @@ static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr, } static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) + int nelems, enum dma_data_direction direction, + struct dma_attrs *attrs) { struct scatterlist *s, *outs, *segstart; unsigned long flags, handle, prot, ctx; @@ -691,7 +694,8 @@ static unsigned long fetch_sg_ctx(struct iommu *iommu, struct scatterlist *sg) } static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) + int nelems, enum dma_data_direction direction, + struct dma_attrs *attrs) { unsigned long flags, ctx; struct scatterlist *sg; @@ -822,7 +826,7 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev, spin_unlock_irqrestore(&iommu->lock, flags); } -static const struct dma_ops sun4u_dma_ops = { +static const struct dma_map_ops sun4u_dma_ops = { .alloc_coherent = dma_4u_alloc_coherent, .free_coherent = dma_4u_free_coherent, .map_page = dma_4u_map_page, @@ -833,7 +837,7 @@ static const struct dma_ops sun4u_dma_ops = { .sync_sg_for_cpu = dma_4u_sync_sg_for_cpu, }; -const struct dma_ops *dma_ops = &sun4u_dma_ops; +const struct dma_map_ops *dma_ops = &sun4u_dma_ops; EXPORT_SYMBOL(dma_ops); int dma_supported(struct device *dev, u64 device_mask) diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index 2485eaa..c4f7dce 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -232,7 +232,8 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu, static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page, unsigned long offset, size_t sz, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { struct iommu *iommu; unsigned long flags, npages, oaddr; @@ -296,7 +297,8 @@ iommu_map_fail: } static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr, - size_t sz, enum dma_data_direction direction) + size_t sz, enum dma_data_direction direction, + struct dma_attrs *attrs) { struct pci_pbm_info *pbm; struct iommu *iommu; @@ -336,7 +338,8 @@ static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr, } static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) + int nelems, enum dma_data_direction direction, + struct dma_attrs *attrs) { struct scatterlist *s, *outs, *segstart; unsigned long flags, handle, prot; @@ -478,7 +481,8 @@ iommu_map_failed: } static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) + int nelems, enum dma_data_direction direction, + struct dma_attrs *attrs) { struct pci_pbm_info *pbm; struct scatterlist *sg; @@ -535,7 +539,7 @@ static void dma_4v_sync_sg_for_cpu(struct device *dev, /* Nothing to do... */ } -static const struct dma_ops sun4v_dma_ops = { +static const struct dma_map_ops sun4v_dma_ops = { .alloc_coherent = dma_4v_alloc_coherent, .free_coherent = dma_4v_free_coherent, .map_page = dma_4v_map_page, -- cgit v0.10.2 From 02f7a18935eef0e56d9180fc3c35da6aad1ff3bb Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 10 Aug 2009 11:53:13 +0900 Subject: sparc: Use asm-generic/dma-mapping-common.h Signed-off-by: FUJITA Tomonori Tested-by: Robert Reif Acked-by: David S. Miller Cc: tony.luck@intel.com Cc: fenghua.yu@intel.com LKML-Reference: <1249872797-1314-5-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 3f8b6a9..5f2df99 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -25,6 +25,7 @@ config SPARC select ARCH_WANT_OPTIONAL_GPIOLIB select RTC_CLASS select RTC_DRV_M48T59 + select HAVE_DMA_ATTRS config SPARC32 def_bool !64BIT diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 893f3ec..34c9226 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -3,6 +3,7 @@ #include #include +#include #define DMA_ERROR_CODE (~(dma_addr_t)0x0) @@ -13,113 +14,31 @@ extern int dma_set_mask(struct device *dev, u64 dma_mask); #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) #define dma_is_consistent(d, h) (1) -extern const struct dma_map_ops *dma_ops; +extern struct dma_map_ops *dma_ops; -static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) -{ - return dma_ops->alloc_coherent(dev, size, dma_handle, flag); -} - -static inline void dma_free_coherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) -{ - dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); -} - -static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, - size_t size, - enum dma_data_direction direction) +static inline struct dma_map_ops *get_dma_ops(struct device *dev) { - return dma_ops->map_page(dev, virt_to_page(cpu_addr), - (unsigned long)cpu_addr & ~PAGE_MASK, size, - direction, NULL); + return dma_ops; } -static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction) -{ - dma_ops->unmap_page(dev, dma_addr, size, direction, NULL); -} - -static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - return dma_ops->map_page(dev, page, offset, size, direction, NULL); -} +#include -static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, - enum dma_data_direction direction) -{ - dma_ops->unmap_page(dev, dma_address, size, direction, NULL); -} - -static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) -{ - return dma_ops->map_sg(dev, sg, nents, direction, NULL); -} - -static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) -{ - dma_ops->unmap_sg(dev, sg, nents, direction, NULL); -} - -static inline void dma_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - dma_ops->sync_single_for_cpu(dev, dma_handle, size, direction); -} - -static inline void dma_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, - size_t size, - enum dma_data_direction direction) -{ - if (dma_ops->sync_single_for_device) - dma_ops->sync_single_for_device(dev, dma_handle, size, - direction); -} - -static inline void dma_sync_sg_for_cpu(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction) +static inline void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) { - dma_ops->sync_sg_for_cpu(dev, sg, nelems, direction); -} + struct dma_map_ops *ops = get_dma_ops(dev); -static inline void dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - if (dma_ops->sync_sg_for_device) - dma_ops->sync_sg_for_device(dev, sg, nelems, direction); + return ops->alloc_coherent(dev, size, dma_handle, flag); } -static inline void dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - enum dma_data_direction dir) +static inline void dma_free_coherent(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) { - dma_sync_single_for_cpu(dev, dma_handle+offset, size, dir); -} + struct dma_map_ops *ops = get_dma_ops(dev); -static inline void dma_sync_single_range_for_device(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - enum dma_data_direction dir) -{ - dma_sync_single_for_device(dev, dma_handle+offset, size, dir); + ops->free_coherent(dev, size, cpu_addr, dma_handle); } - static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { return (dma_addr == DMA_ERROR_CODE); diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c index 473a3fc..15820a9 100644 --- a/arch/sparc/kernel/dma.c +++ b/arch/sparc/kernel/dma.c @@ -165,7 +165,7 @@ static void dma32_sync_sg_for_device(struct device *dev, BUG(); } -static const struct dma_map_ops dma32_dma_ops = { +static struct dma_map_ops dma32_dma_ops = { .alloc_coherent = dma32_alloc_coherent, .free_coherent = dma32_free_coherent, .map_page = dma32_map_page, @@ -178,5 +178,5 @@ static const struct dma_map_ops dma32_dma_ops = { .sync_sg_for_device = dma32_sync_sg_for_device, }; -const struct dma_map_ops *dma_ops = &dma32_dma_ops; +struct dma_map_ops *dma_ops = &dma32_dma_ops; EXPORT_SYMBOL(dma_ops); diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c index a9f0ad9..74b289c 100644 --- a/arch/sparc/kernel/iommu.c +++ b/arch/sparc/kernel/iommu.c @@ -826,7 +826,7 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev, spin_unlock_irqrestore(&iommu->lock, flags); } -static const struct dma_map_ops sun4u_dma_ops = { +static struct dma_map_ops sun4u_dma_ops = { .alloc_coherent = dma_4u_alloc_coherent, .free_coherent = dma_4u_free_coherent, .map_page = dma_4u_map_page, @@ -837,7 +837,7 @@ static const struct dma_map_ops sun4u_dma_ops = { .sync_sg_for_cpu = dma_4u_sync_sg_for_cpu, }; -const struct dma_map_ops *dma_ops = &sun4u_dma_ops; +struct dma_map_ops *dma_ops = &sun4u_dma_ops; EXPORT_SYMBOL(dma_ops); int dma_supported(struct device *dev, u64 device_mask) diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index c4f7dce..ee800f9 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -539,7 +539,7 @@ static void dma_4v_sync_sg_for_cpu(struct device *dev, /* Nothing to do... */ } -static const struct dma_map_ops sun4v_dma_ops = { +static struct dma_map_ops sun4v_dma_ops = { .alloc_coherent = dma_4v_alloc_coherent, .free_coherent = dma_4v_free_coherent, .map_page = dma_4v_map_page, -- cgit v0.10.2 From 595cc8560783ea31ed1208dc1f97282a2a5606b7 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 10 Aug 2009 11:53:14 +0900 Subject: sparc: Remove no-op dma_4v_sync_single_for_cpu and dma_4v_sync_sg_for_cpu Now sparc uses include/asm-generic/dma-mapping-common.h. pci_sun4v.c doesn't need to have no-op dma_4v_sync_single_for_cpu and dma_4v_sync_sg_for_cpu (dma-mapping-common.h does nothing if sync_{single|sg}_for_cpu hook is not defined). So we can remove them safely. Signed-off-by: FUJITA Tomonori Tested-by: Robert Reif Acked-by: David S. Miller Cc: tony.luck@intel.com Cc: fenghua.yu@intel.com LKML-Reference: <1249872797-1314-6-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index ee800f9..23c33ff 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -525,20 +525,6 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, spin_unlock_irqrestore(&iommu->lock, flags); } -static void dma_4v_sync_single_for_cpu(struct device *dev, - dma_addr_t bus_addr, size_t sz, - enum dma_data_direction direction) -{ - /* Nothing to do... */ -} - -static void dma_4v_sync_sg_for_cpu(struct device *dev, - struct scatterlist *sglist, int nelems, - enum dma_data_direction direction) -{ - /* Nothing to do... */ -} - static struct dma_map_ops sun4v_dma_ops = { .alloc_coherent = dma_4v_alloc_coherent, .free_coherent = dma_4v_free_coherent, @@ -546,8 +532,6 @@ static struct dma_map_ops sun4v_dma_ops = { .unmap_page = dma_4v_unmap_page, .map_sg = dma_4v_map_sg, .unmap_sg = dma_4v_unmap_sg, - .sync_single_for_cpu = dma_4v_sync_single_for_cpu, - .sync_sg_for_cpu = dma_4v_sync_sg_for_cpu, }; static void __devinit pci_sun4v_scan_bus(struct pci_pbm_info *pbm, -- cgit v0.10.2 From c2c07dbd8742a26ab3f1ee8b82237a060a0d9f61 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 10 Aug 2009 11:53:15 +0900 Subject: sparc: Replace sbus_map_single and sbus_unmap_single with sbus_map_page and sbus_unmap_page This is a preparation for using asm-generic/pci-dma-compat.h; SPARC32 has two dma_map_ops structures for pci and sbus (removing arch/sparc/kernel/dma.c, PCI and SBUS DMA accessor). Signed-off-by: FUJITA Tomonori Tested-by: Robert Reif Acked-by: David S. Miller Cc: tony.luck@intel.com Cc: fenghua.yu@intel.com LKML-Reference: <1249872797-1314-7-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c index 15820a9..a5d50da 100644 --- a/arch/sparc/kernel/dma.c +++ b/arch/sparc/kernel/dma.c @@ -68,8 +68,7 @@ static dma_addr_t dma32_map_page(struct device *dev, struct page *page, return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); #endif - return sbus_map_single(dev, page_address(page) + offset, - size, (int)direction); + return sbus_map_page(dev, page, offset, size, (int)direction); } static void dma32_unmap_page(struct device *dev, dma_addr_t dma_address, @@ -83,7 +82,7 @@ static void dma32_unmap_page(struct device *dev, dma_addr_t dma_address, return; } #endif - sbus_unmap_single(dev, dma_address, size, (int)direction); + sbus_unmap_page(dev, dma_address, size, (int)direction); } static int dma32_map_sg(struct device *dev, struct scatterlist *sg, diff --git a/arch/sparc/kernel/dma.h b/arch/sparc/kernel/dma.h index f8d8951..680351e 100644 --- a/arch/sparc/kernel/dma.h +++ b/arch/sparc/kernel/dma.h @@ -1,8 +1,8 @@ void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp); void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba); -dma_addr_t sbus_map_single(struct device *dev, void *va, - size_t len, int direction); -void sbus_unmap_single(struct device *dev, dma_addr_t ba, +dma_addr_t sbus_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t len, int direction); +void sbus_unmap_page(struct device *dev, dma_addr_t ba, size_t n, int direction); int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction); diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 87ea0d0..39ff1e0 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -337,8 +337,11 @@ void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba) * CPU view of this memory may be inconsistent with * a device view and explicit flushing is necessary. */ -dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int direction) +dma_addr_t sbus_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t len, int direction) { + void *va = page_address(page) + offset; + /* XXX why are some lengths signed, others unsigned? */ if (len <= 0) { return 0; @@ -350,7 +353,7 @@ dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int directi return mmu_get_scsi_one(dev, va, len); } -void sbus_unmap_single(struct device *dev, dma_addr_t ba, size_t n, int direction) +void sbus_unmap_page(struct device *dev, dma_addr_t ba, size_t n, int direction) { mmu_release_scsi_one(dev, ba, n); } -- cgit v0.10.2 From ee664a9252d24ef10317d1bba8fc8f4c6495b36c Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 10 Aug 2009 11:53:16 +0900 Subject: sparc: Use asm-generic/pci-dma-compat This converts SPARC to use asm-generic/pci-dma-compat instead of the homegrown mechnism. SPARC32 has two dma_map_ops structures for pci and sbus (removing arch/sparc/kernel/dma.c, PCI and SBUS DMA accessor). The global 'dma_ops' is set to sbus_dma_ops and get_dma_ops() returns pci32_dma_ops for pci devices so we can use the appropriate dma mapping operations. Signed-off-by: FUJITA Tomonori Tested-by: Robert Reif Acked-by: David S. Miller Cc: tony.luck@intel.com Cc: fenghua.yu@intel.com LKML-Reference: <1249872797-1314-8-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 34c9226..2677818 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -14,10 +14,15 @@ extern int dma_set_mask(struct device *dev, u64 dma_mask); #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) #define dma_is_consistent(d, h) (1) -extern struct dma_map_ops *dma_ops; +extern struct dma_map_ops *dma_ops, pci32_dma_ops; +extern struct bus_type pci_bus_type; static inline struct dma_map_ops *get_dma_ops(struct device *dev) { +#if defined(CONFIG_SPARC32) && defined(CONFIG_PCI) + if (dev->bus == &pci_bus_type) + return &pci32_dma_ops; +#endif return dma_ops; } diff --git a/arch/sparc/include/asm/pci.h b/arch/sparc/include/asm/pci.h index 6e14fd1..d9c031f 100644 --- a/arch/sparc/include/asm/pci.h +++ b/arch/sparc/include/asm/pci.h @@ -5,4 +5,7 @@ #else #include #endif + +#include + #endif diff --git a/arch/sparc/include/asm/pci_32.h b/arch/sparc/include/asm/pci_32.h index b41c4c1..ac0e836 100644 --- a/arch/sparc/include/asm/pci_32.h +++ b/arch/sparc/include/asm/pci_32.h @@ -31,42 +31,8 @@ static inline void pcibios_penalize_isa_irq(int irq, int active) */ #define PCI_DMA_BUS_IS_PHYS (0) -#include - struct pci_dev; -/* Allocate and map kernel buffer using consistent mode DMA for a device. - * hwdev should be valid struct pci_dev pointer for PCI devices. - */ -extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle); - -/* Free and unmap a consistent DMA buffer. - * cpu_addr is what was returned from pci_alloc_consistent, - * size must be the same as what as passed into pci_alloc_consistent, - * and likewise dma_addr must be the same as what *dma_addrp was set to. - * - * References to the memory and mappings assosciated with cpu_addr/dma_addr - * past this call are illegal. - */ -extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle); - -/* Map a single buffer of the indicated size for DMA in streaming mode. - * The 32-bit bus address to use is returned. - * - * Once the device is given the dma address, the device owns this memory - * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. - */ -extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction); - -/* Unmap a single streaming mode DMA translation. The dma_addr and size - * must match what was provided for in a previous pci_map_single call. All - * other usages are undefined. - * - * After this call, reads by the cpu to the buffer are guaranteed to see - * whatever the device wrote there. - */ -extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction); - /* pci_unmap_{single,page} is not a nop, thus... */ #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ dma_addr_t ADDR_NAME; @@ -81,69 +47,6 @@ extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t #define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ (((PTR)->LEN_NAME) = (VAL)) -/* - * Same as above, only with pages instead of mapped addresses. - */ -extern dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page, - unsigned long offset, size_t size, int direction); -extern void pci_unmap_page(struct pci_dev *hwdev, - dma_addr_t dma_address, size_t size, int direction); - -/* Map a set of buffers described by scatterlist in streaming - * mode for DMA. This is the scather-gather version of the - * above pci_map_single interface. Here the scatter gather list - * elements are each tagged with the appropriate dma address - * and length. They are obtained via sg_dma_{address,length}(SG). - * - * NOTE: An implementation may be able to use a smaller number of - * DMA address/length pairs than there are SG table elements. - * (for example via virtual mapping capabilities) - * The routine returns the number of addr/length pairs actually - * used, at most nents. - * - * Device ownership issues as mentioned above for pci_map_single are - * the same here. - */ -extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction); - -/* Unmap a set of streaming mode DMA translations. - * Again, cpu read rules concerning calls here are the same as for - * pci_unmap_single() above. - */ -extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction); - -/* Make physical memory consistent for a single - * streaming mode DMA translation after a transfer. - * - * If you perform a pci_map_single() but wish to interrogate the - * buffer using the cpu, yet do not wish to teardown the PCI dma - * mapping, you must call this function before doing so. At the - * next point you give the PCI dma address back to the card, you - * must first perform a pci_dma_sync_for_device, and then the device - * again owns the buffer. - */ -extern void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction); -extern void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction); - -/* Make physical memory consistent for a set of streaming - * mode DMA translations after a transfer. - * - * The same as pci_dma_sync_single_* but for a scatter-gather list, - * same rules and usage. - */ -extern void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); -extern void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); - -/* Return whether the given PCI device DMA address mask can - * be supported properly. For example, if your device can - * only drive the low 24-bits during PCI bus mastering, then - * you would pass 0x00ffffff as the mask to this function. - */ -static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) -{ - return 1; -} - #ifdef CONFIG_PCI static inline void pci_dma_burst_advice(struct pci_dev *pdev, enum pci_dma_burst_strategy *strat, @@ -154,14 +57,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev, } #endif -#define PCI_DMA_ERROR_CODE (~(dma_addr_t)0x0) - -static inline int pci_dma_mapping_error(struct pci_dev *pdev, - dma_addr_t dma_addr) -{ - return (dma_addr == PCI_DMA_ERROR_CODE); -} - struct device_node; extern struct device_node *pci_device_to_OF_node(struct pci_dev *pdev); diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h index 7a1e356..5cc9f6a 100644 --- a/arch/sparc/include/asm/pci_64.h +++ b/arch/sparc/include/asm/pci_64.h @@ -35,37 +35,6 @@ static inline void pcibios_penalize_isa_irq(int irq, int active) */ #define PCI_DMA_BUS_IS_PHYS (0) -static inline void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, - dma_addr_t *dma_handle) -{ - return dma_alloc_coherent(&pdev->dev, size, dma_handle, GFP_ATOMIC); -} - -static inline void pci_free_consistent(struct pci_dev *pdev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - return dma_free_coherent(&pdev->dev, size, vaddr, dma_handle); -} - -static inline dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, - size_t size, int direction) -{ - return dma_map_single(&pdev->dev, ptr, size, - (enum dma_data_direction) direction); -} - -static inline void pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, - size_t size, int direction) -{ - dma_unmap_single(&pdev->dev, dma_addr, size, - (enum dma_data_direction) direction); -} - -#define pci_map_page(dev, page, off, size, dir) \ - pci_map_single(dev, (page_address(page) + (off)), size, dir) -#define pci_unmap_page(dev,addr,sz,dir) \ - pci_unmap_single(dev,addr,sz,dir) - /* pci_unmap_{single,page} is not a nop, thus... */ #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ dma_addr_t ADDR_NAME; @@ -80,57 +49,6 @@ static inline void pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, #define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ (((PTR)->LEN_NAME) = (VAL)) -static inline int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, - int nents, int direction) -{ - return dma_map_sg(&pdev->dev, sg, nents, - (enum dma_data_direction) direction); -} - -static inline void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, - int nents, int direction) -{ - dma_unmap_sg(&pdev->dev, sg, nents, - (enum dma_data_direction) direction); -} - -static inline void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, - dma_addr_t dma_handle, - size_t size, int direction) -{ - dma_sync_single_for_cpu(&pdev->dev, dma_handle, size, - (enum dma_data_direction) direction); -} - -static inline void pci_dma_sync_single_for_device(struct pci_dev *pdev, - dma_addr_t dma_handle, - size_t size, int direction) -{ - /* No flushing needed to sync cpu writes to the device. */ -} - -static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, - struct scatterlist *sg, - int nents, int direction) -{ - dma_sync_sg_for_cpu(&pdev->dev, sg, nents, - (enum dma_data_direction) direction); -} - -static inline void pci_dma_sync_sg_for_device(struct pci_dev *pdev, - struct scatterlist *sg, - int nelems, int direction) -{ - /* No flushing needed to sync cpu writes to the device. */ -} - -/* Return whether the given PCI device DMA address mask can - * be supported properly. For example, if your device can - * only drive the low 24-bits during PCI bus mastering, then - * you would pass 0x00ffffff as the mask to this function. - */ -extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask); - /* PCI IOMMU mapping bypass support. */ /* PCI 64-bit addressing works for all slots on all controller @@ -140,12 +58,6 @@ extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask); #define PCI64_REQUIRED_MASK (~(dma64_addr_t)0) #define PCI64_ADDR_BASE 0xfffc000000000000UL -static inline int pci_dma_mapping_error(struct pci_dev *pdev, - dma_addr_t dma_addr) -{ - return dma_mapping_error(&pdev->dev, dma_addr); -} - #ifdef CONFIG_PCI static inline void pci_dma_burst_advice(struct pci_dev *pdev, enum pci_dma_burst_strategy *strat, diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c index a5d50da..b2fa312 100644 --- a/arch/sparc/kernel/dma.c +++ b/arch/sparc/kernel/dma.c @@ -13,13 +13,17 @@ #include #endif -#include "dma.h" - +/* + * Return whether the given PCI device DMA address mask can be + * supported properly. For example, if your device can only drive the + * low 24-bits during PCI bus mastering, then you would pass + * 0x00ffffff as the mask to this function. + */ int dma_supported(struct device *dev, u64 mask) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) - return pci_dma_supported(to_pci_dev(dev), mask); + return 1; #endif return 0; } @@ -34,148 +38,3 @@ int dma_set_mask(struct device *dev, u64 dma_mask) return -EOPNOTSUPP; } EXPORT_SYMBOL(dma_set_mask); - -static void *dma32_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) - return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle); -#endif - return sbus_alloc_consistent(dev, size, dma_handle); -} - -static void dma32_free_coherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) { - pci_free_consistent(to_pci_dev(dev), size, - cpu_addr, dma_handle); - return; - } -#endif - sbus_free_consistent(dev, size, cpu_addr, dma_handle); -} - -static dma_addr_t dma32_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction, - struct dma_attrs *attrs) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) - return pci_map_page(to_pci_dev(dev), page, offset, - size, (int)direction); -#endif - return sbus_map_page(dev, page, offset, size, (int)direction); -} - -static void dma32_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, enum dma_data_direction direction, - struct dma_attrs *attrs) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) { - pci_unmap_page(to_pci_dev(dev), dma_address, - size, (int)direction); - return; - } -#endif - sbus_unmap_page(dev, dma_address, size, (int)direction); -} - -static int dma32_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction, - struct dma_attrs *attrs) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) - return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); -#endif - return sbus_map_sg(dev, sg, nents, direction); -} - -void dma32_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction, - struct dma_attrs *attrs) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) { - pci_unmap_sg(to_pci_dev(dev), sg, nents, (int)direction); - return; - } -#endif - sbus_unmap_sg(dev, sg, nents, (int)direction); -} - -static void dma32_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, - size_t size, - enum dma_data_direction direction) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) { - pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, - size, (int)direction); - return; - } -#endif - sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction); -} - -static void dma32_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) { - pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, - size, (int)direction); - return; - } -#endif - sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction); -} - -static void dma32_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, - int nelems, enum dma_data_direction direction) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) { - pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, - nelems, (int)direction); - return; - } -#endif - BUG(); -} - -static void dma32_sync_sg_for_device(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) { - pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, - nelems, (int)direction); - return; - } -#endif - BUG(); -} - -static struct dma_map_ops dma32_dma_ops = { - .alloc_coherent = dma32_alloc_coherent, - .free_coherent = dma32_free_coherent, - .map_page = dma32_map_page, - .unmap_page = dma32_unmap_page, - .map_sg = dma32_map_sg, - .unmap_sg = dma32_unmap_sg, - .sync_single_for_cpu = dma32_sync_single_for_cpu, - .sync_single_for_device = dma32_sync_single_for_device, - .sync_sg_for_cpu = dma32_sync_sg_for_cpu, - .sync_sg_for_device = dma32_sync_sg_for_device, -}; - -struct dma_map_ops *dma_ops = &dma32_dma_ops; -EXPORT_SYMBOL(dma_ops); diff --git a/arch/sparc/kernel/dma.h b/arch/sparc/kernel/dma.h deleted file mode 100644 index 680351e..0000000 --- a/arch/sparc/kernel/dma.h +++ /dev/null @@ -1,14 +0,0 @@ -void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp); -void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba); -dma_addr_t sbus_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t len, int direction); -void sbus_unmap_page(struct device *dev, dma_addr_t ba, - size_t n, int direction); -int sbus_map_sg(struct device *dev, struct scatterlist *sg, - int n, int direction); -void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, - int n, int direction); -void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, - size_t size, int direction); -void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, - size_t size, int direction); diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c index 74b289c..7690cc2 100644 --- a/arch/sparc/kernel/iommu.c +++ b/arch/sparc/kernel/iommu.c @@ -840,6 +840,8 @@ static struct dma_map_ops sun4u_dma_ops = { struct dma_map_ops *dma_ops = &sun4u_dma_ops; EXPORT_SYMBOL(dma_ops); +extern int pci64_dma_supported(struct pci_dev *pdev, u64 device_mask); + int dma_supported(struct device *dev, u64 device_mask) { struct iommu *iommu = dev->archdata.iommu; @@ -853,7 +855,7 @@ int dma_supported(struct device *dev, u64 device_mask) #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) - return pci_dma_supported(to_pci_dev(dev), device_mask); + return pci64_dma_supported(to_pci_dev(dev), device_mask); #endif return 0; diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 39ff1e0..1eb6043 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -48,8 +48,6 @@ #include #include -#include "dma.h" - #define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ static struct resource *_sparc_find_resource(struct resource *r, @@ -246,7 +244,8 @@ EXPORT_SYMBOL(sbus_set_sbus64); * Typically devices use them for control blocks. * CPU may access them without any explicit flushing. */ -void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp) +static void *sbus_alloc_coherent(struct device *dev, size_t len, + dma_addr_t *dma_addrp, gfp_t gfp) { struct of_device *op = to_of_device(dev); unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; @@ -299,7 +298,8 @@ err_nopages: return NULL; } -void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba) +static void sbus_free_coherent(struct device *dev, size_t n, void *p, + dma_addr_t ba) { struct resource *res; struct page *pgv; @@ -317,7 +317,7 @@ void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba) n = (n + PAGE_SIZE-1) & PAGE_MASK; if ((res->end-res->start)+1 != n) { - printk("sbus_free_consistent: region 0x%lx asked 0x%lx\n", + printk("sbus_free_consistent: region 0x%lx asked 0x%zx\n", (long)((res->end-res->start)+1), n); return; } @@ -337,8 +337,10 @@ void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba) * CPU view of this memory may be inconsistent with * a device view and explicit flushing is necessary. */ -dma_addr_t sbus_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t len, int direction) +static dma_addr_t sbus_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t len, + enum dma_data_direction dir, + struct dma_attrs *attrs) { void *va = page_address(page) + offset; @@ -353,12 +355,14 @@ dma_addr_t sbus_map_page(struct device *dev, struct page *page, return mmu_get_scsi_one(dev, va, len); } -void sbus_unmap_page(struct device *dev, dma_addr_t ba, size_t n, int direction) +static void sbus_unmap_page(struct device *dev, dma_addr_t ba, size_t n, + enum dma_data_direction dir, struct dma_attrs *attrs) { mmu_release_scsi_one(dev, ba, n); } -int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction) +static int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, + enum dma_data_direction dir, struct dma_attrs *attrs) { mmu_get_scsi_sgl(dev, sg, n); @@ -369,19 +373,38 @@ int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction return n; } -void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, int direction) +static void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, + enum dma_data_direction dir, struct dma_attrs *attrs) { mmu_release_scsi_sgl(dev, sg, n); } -void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, size_t size, int direction) +static void sbus_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, + int n, enum dma_data_direction dir) { + BUG(); } -void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, size_t size, int direction) +static void sbus_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + int n, enum dma_data_direction dir) { + BUG(); } +struct dma_map_ops sbus_dma_ops = { + .alloc_coherent = sbus_alloc_coherent, + .free_coherent = sbus_free_coherent, + .map_page = sbus_map_page, + .unmap_page = sbus_unmap_page, + .map_sg = sbus_map_sg, + .unmap_sg = sbus_unmap_sg, + .sync_sg_for_cpu = sbus_sync_sg_for_cpu, + .sync_sg_for_device = sbus_sync_sg_for_device, +}; + +struct dma_map_ops *dma_ops = &sbus_dma_ops; +EXPORT_SYMBOL(dma_ops); + static int __init sparc_register_ioport(void) { register_proc_sparc_ioport(); @@ -398,7 +421,8 @@ arch_initcall(sparc_register_ioport); /* Allocate and map kernel buffer using consistent mode DMA for a device. * hwdev should be valid struct pci_dev pointer for PCI devices. */ -void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba) +static void *pci32_alloc_coherent(struct device *dev, size_t len, + dma_addr_t *pba, gfp_t gfp) { unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; unsigned long va; @@ -442,7 +466,6 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba) *pba = virt_to_phys(va); /* equals virt_to_bus (R.I.P.) for us. */ return (void *) res->start; } -EXPORT_SYMBOL(pci_alloc_consistent); /* Free and unmap a consistent DMA buffer. * cpu_addr is what was returned from pci_alloc_consistent, @@ -452,7 +475,8 @@ EXPORT_SYMBOL(pci_alloc_consistent); * References to the memory and mappings associated with cpu_addr/dma_addr * past this call are illegal. */ -void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba) +static void pci32_free_coherent(struct device *dev, size_t n, void *p, + dma_addr_t ba) { struct resource *res; unsigned long pgp; @@ -484,60 +508,18 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba) free_pages(pgp, get_order(n)); } -EXPORT_SYMBOL(pci_free_consistent); - -/* Map a single buffer of the indicated size for DMA in streaming mode. - * The 32-bit bus address to use is returned. - * - * Once the device is given the dma address, the device owns this memory - * until either pci_unmap_single or pci_dma_sync_single_* is performed. - */ -dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, - int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); - /* IIep is write-through, not flushing. */ - return virt_to_phys(ptr); -} -EXPORT_SYMBOL(pci_map_single); - -/* Unmap a single streaming mode DMA translation. The dma_addr and size - * must match what was provided for in a previous pci_map_single call. All - * other usages are undefined. - * - * After this call, reads by the cpu to the buffer are guaranteed to see - * whatever the device wrote there. - */ -void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, - int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); - if (direction != PCI_DMA_TODEVICE) { - mmu_inval_dma_area((unsigned long)phys_to_virt(ba), - (size + PAGE_SIZE-1) & PAGE_MASK); - } -} -EXPORT_SYMBOL(pci_unmap_single); /* * Same as pci_map_single, but with pages. */ -dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page, - unsigned long offset, size_t size, int direction) +static dma_addr_t pci32_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs) { - BUG_ON(direction == PCI_DMA_NONE); /* IIep is write-through, not flushing. */ return page_to_phys(page) + offset; } -EXPORT_SYMBOL(pci_map_page); - -void pci_unmap_page(struct pci_dev *hwdev, - dma_addr_t dma_address, size_t size, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); - /* mmu_inval_dma_area XXX */ -} -EXPORT_SYMBOL(pci_unmap_page); /* Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the @@ -554,13 +536,13 @@ EXPORT_SYMBOL(pci_unmap_page); * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, - int direction) +static int pci32_map_sg(struct device *device, struct scatterlist *sgl, + int nents, enum dma_data_direction dir, + struct dma_attrs *attrs) { struct scatterlist *sg; int n; - BUG_ON(direction == PCI_DMA_NONE); /* IIep is write-through, not flushing. */ for_each_sg(sgl, sg, nents, n) { BUG_ON(page_address(sg_page(sg)) == NULL); @@ -569,20 +551,19 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, } return nents; } -EXPORT_SYMBOL(pci_map_sg); /* Unmap a set of streaming mode DMA translations. * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, - int direction) +static void pci32_unmap_sg(struct device *dev, struct scatterlist *sgl, + int nents, enum dma_data_direction dir, + struct dma_attrs *attrs) { struct scatterlist *sg; int n; - BUG_ON(direction == PCI_DMA_NONE); - if (direction != PCI_DMA_TODEVICE) { + if (dir != PCI_DMA_TODEVICE) { for_each_sg(sgl, sg, nents, n) { BUG_ON(page_address(sg_page(sg)) == NULL); mmu_inval_dma_area( @@ -591,7 +572,6 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, } } } -EXPORT_SYMBOL(pci_unmap_sg); /* Make physical memory consistent for a single * streaming mode DMA translation before or after a transfer. @@ -603,25 +583,23 @@ EXPORT_SYMBOL(pci_unmap_sg); * must first perform a pci_dma_sync_for_device, and then the * device again owns the buffer. */ -void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) +static void pci32_sync_single_for_cpu(struct device *dev, dma_addr_t ba, + size_t size, enum dma_data_direction dir) { - BUG_ON(direction == PCI_DMA_NONE); - if (direction != PCI_DMA_TODEVICE) { + if (dir != PCI_DMA_TODEVICE) { mmu_inval_dma_area((unsigned long)phys_to_virt(ba), (size + PAGE_SIZE-1) & PAGE_MASK); } } -EXPORT_SYMBOL(pci_dma_sync_single_for_cpu); -void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) +static void pci32_sync_single_for_device(struct device *dev, dma_addr_t ba, + size_t size, enum dma_data_direction dir) { - BUG_ON(direction == PCI_DMA_NONE); - if (direction != PCI_DMA_TODEVICE) { + if (dir != PCI_DMA_TODEVICE) { mmu_inval_dma_area((unsigned long)phys_to_virt(ba), (size + PAGE_SIZE-1) & PAGE_MASK); } } -EXPORT_SYMBOL(pci_dma_sync_single_for_device); /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. @@ -629,13 +607,13 @@ EXPORT_SYMBOL(pci_dma_sync_single_for_device); * The same as pci_dma_sync_single_* but for a scatter-gather list, * same rules and usage. */ -void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, int direction) +static void pci32_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl, + int nents, enum dma_data_direction dir) { struct scatterlist *sg; int n; - BUG_ON(direction == PCI_DMA_NONE); - if (direction != PCI_DMA_TODEVICE) { + if (dir != PCI_DMA_TODEVICE) { for_each_sg(sgl, sg, nents, n) { BUG_ON(page_address(sg_page(sg)) == NULL); mmu_inval_dma_area( @@ -644,15 +622,14 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sgl, int } } } -EXPORT_SYMBOL(pci_dma_sync_sg_for_cpu); -void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sgl, int nents, int direction) +static void pci32_sync_sg_for_device(struct device *device, struct scatterlist *sgl, + int nents, enum dma_data_direction dir) { struct scatterlist *sg; int n; - BUG_ON(direction == PCI_DMA_NONE); - if (direction != PCI_DMA_TODEVICE) { + if (dir != PCI_DMA_TODEVICE) { for_each_sg(sgl, sg, nents, n) { BUG_ON(page_address(sg_page(sg)) == NULL); mmu_inval_dma_area( @@ -661,7 +638,20 @@ void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sgl, } } } -EXPORT_SYMBOL(pci_dma_sync_sg_for_device); + +struct dma_map_ops pci32_dma_ops = { + .alloc_coherent = pci32_alloc_coherent, + .free_coherent = pci32_free_coherent, + .map_page = pci32_map_page, + .map_sg = pci32_map_sg, + .unmap_sg = pci32_unmap_sg, + .sync_single_for_cpu = pci32_sync_single_for_cpu, + .sync_single_for_device = pci32_sync_single_for_device, + .sync_sg_for_cpu = pci32_sync_sg_for_cpu, + .sync_sg_for_device = pci32_sync_sg_for_device, +}; +EXPORT_SYMBOL(pci32_dma_ops); + #endif /* CONFIG_PCI */ #ifdef CONFIG_PROC_FS diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 57859ad..c686486 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -1039,7 +1039,7 @@ static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit) pci_dev_put(ali_isa_bridge); } -int pci_dma_supported(struct pci_dev *pdev, u64 device_mask) +int pci64_dma_supported(struct pci_dev *pdev, u64 device_mask) { u64 dma_addr_mask; -- cgit v0.10.2 From 451d7400a34cb679369e337d67f0238ed410f484 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 10 Aug 2009 11:53:17 +0900 Subject: sparc: Add CONFIG_DMA_API_DEBUG support All we need to do for CONFIG_DMA_API_DEBUG support is call dma_debug_init() in DMA code common for SPARC32 and SPARC64. Now SPARC32 uses two dma_map_ops structures for pci and sbus so there is not much dma stuff for SPARC32 in kernel/dma.c. kernel/ioport.c also includes dma stuff for SPARC32. So let's put all the dma stuff for SPARC32 in kernel/ioport.c and make kernel/dma.c common for SPARC32 and SPARC64. Signed-off-by: FUJITA Tomonori Tested-by: Robert Reif Acked-by: David S. Miller Cc: tony.luck@intel.com Cc: fenghua.yu@intel.com LKML-Reference: <1249872797-1314-9-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 5f2df99..233cff5 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -26,6 +26,7 @@ config SPARC select RTC_CLASS select RTC_DRV_M48T59 select HAVE_DMA_ATTRS + select HAVE_DMA_API_DEBUG config SPARC32 def_bool !64BIT diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 2677818..5a8c308 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -32,8 +32,11 @@ static inline void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { struct dma_map_ops *ops = get_dma_ops(dev); + void *cpu_addr; - return ops->alloc_coherent(dev, size, dma_handle, flag); + cpu_addr = ops->alloc_coherent(dev, size, dma_handle, flag); + debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr); + return cpu_addr; } static inline void dma_free_coherent(struct device *dev, size_t size, @@ -41,6 +44,7 @@ static inline void dma_free_coherent(struct device *dev, size_t size, { struct dma_map_ops *ops = get_dma_ops(dev); + debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); ops->free_coherent(dev, size, cpu_addr, dma_handle); } diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 475ce46..29b88a5 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -61,7 +61,7 @@ obj-$(CONFIG_SPARC64_SMP) += cpumap.o obj-$(CONFIG_SPARC32) += devres.o devres-y := ../../../kernel/irq/devres.o -obj-$(CONFIG_SPARC32) += dma.o +obj-y += dma.o obj-$(CONFIG_SPARC32_PCI) += pcic.o diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c index b2fa312..e1ba8ee 100644 --- a/arch/sparc/kernel/dma.c +++ b/arch/sparc/kernel/dma.c @@ -1,40 +1,13 @@ -/* dma.c: PCI and SBUS DMA accessors for 32-bit sparc. - * - * Copyright (C) 2008 David S. Miller - */ - #include #include #include -#include -#include +#include -#ifdef CONFIG_PCI -#include -#endif +#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 15) -/* - * Return whether the given PCI device DMA address mask can be - * supported properly. For example, if your device can only drive the - * low 24-bits during PCI bus mastering, then you would pass - * 0x00ffffff as the mask to this function. - */ -int dma_supported(struct device *dev, u64 mask) +static int __init dma_init(void) { -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) - return 1; -#endif + dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); return 0; } -EXPORT_SYMBOL(dma_supported); - -int dma_set_mask(struct device *dev, u64 dma_mask) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) - return pci_set_dma_mask(to_pci_dev(dev), dma_mask); -#endif - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(dma_set_mask); +fs_initcall(dma_init); diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 1eb6043..edbea23 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -654,6 +654,33 @@ EXPORT_SYMBOL(pci32_dma_ops); #endif /* CONFIG_PCI */ +/* + * Return whether the given PCI device DMA address mask can be + * supported properly. For example, if your device can only drive the + * low 24-bits during PCI bus mastering, then you would pass + * 0x00ffffff as the mask to this function. + */ +int dma_supported(struct device *dev, u64 mask) +{ +#ifdef CONFIG_PCI + if (dev->bus == &pci_bus_type) + return 1; +#endif + return 0; +} +EXPORT_SYMBOL(dma_supported); + +int dma_set_mask(struct device *dev, u64 dma_mask) +{ +#ifdef CONFIG_PCI + if (dev->bus == &pci_bus_type) + return pci_set_dma_mask(to_pci_dev(dev), dma_mask); +#endif + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(dma_set_mask); + + #ifdef CONFIG_PROC_FS static int -- cgit v0.10.2 From 549812799c8495451e71ebd9f6a862b33120a35a Mon Sep 17 00:00:00 2001 From: Rafael Laufer Date: Mon, 10 Aug 2009 10:08:27 +0200 Subject: netfilter: nf_conntrack: add SCTP support for SO_ORIGINAL_DST Signed-off-by: Patrick McHardy diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 7d2ead7..05a9bc8 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -256,11 +256,11 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) tuple.dst.u3.ip = inet->daddr; tuple.dst.u.tcp.port = inet->dport; tuple.src.l3num = PF_INET; - tuple.dst.protonum = IPPROTO_TCP; + tuple.dst.protonum = sk->sk_protocol; - /* We only do TCP at the moment: is there a better way? */ - if (strcmp(sk->sk_prot->name, "TCP")) { - pr_debug("SO_ORIGINAL_DST: Not a TCP socket\n"); + /* We only do TCP and SCTP at the moment: is there a better way? */ + if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) { + pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n"); return -ENOPROTOOPT; } -- cgit v0.10.2 From be39ee11cd1f67b51ac8e71d177a981eb34f2ab2 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 10 Aug 2009 10:10:55 +0200 Subject: netfilter: ebtables: Use %pM conversion specifier ebt_log uses its own implementation of print_mac to print MAC addresses. This patch converts it to use the %pM conversion specifier for printk. Signed-off-by: Tobias Klauser Signed-off-by: Patrick McHardy diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index a94f3cc..e4ea3fd 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c @@ -50,14 +50,6 @@ struct arppayload unsigned char ip_dst[4]; }; -static void print_MAC(const unsigned char *p) -{ - int i; - - for (i = 0; i < ETH_ALEN; i++, p++) - printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':'); -} - static void print_ports(const struct sk_buff *skb, uint8_t protocol, int offset) { @@ -88,14 +80,11 @@ ebt_log_packet(u_int8_t pf, unsigned int hooknum, unsigned int bitmask; spin_lock_bh(&ebt_log_lock); - printk("<%c>%s IN=%s OUT=%s MAC source = ", '0' + loginfo->u.log.level, - prefix, in ? in->name : "", out ? out->name : ""); - - print_MAC(eth_hdr(skb)->h_source); - printk("MAC dest = "); - print_MAC(eth_hdr(skb)->h_dest); - - printk("proto = 0x%04x", ntohs(eth_hdr(skb)->h_proto)); + printk("<%c>%s IN=%s OUT=%s MAC source = %pM MAC dest = %pM proto = 0x%04x", + '0' + loginfo->u.log.level, prefix, + in ? in->name : "", out ? out->name : "", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, + ntohs(eth_hdr(skb)->h_proto)); if (loginfo->type == NF_LOG_TYPE_LOG) bitmask = loginfo->u.log.logflags; @@ -171,12 +160,8 @@ ebt_log_packet(u_int8_t pf, unsigned int hooknum, printk(" INCOMPLETE ARP payload"); goto out; } - printk(" ARP MAC SRC="); - print_MAC(ap->mac_src); - printk(" ARP IP SRC=%pI4", ap->ip_src); - printk(" ARP MAC DST="); - print_MAC(ap->mac_dst); - printk(" ARP IP DST=%pI4", ap->ip_dst); + printk(" ARP MAC SRC=%pM ARP IP SRC=%pI4 ARP MAC DST=%pM ARP IP DST=%pI4", + ap->mac_src, ap->ip_src, ap->mac_dst, ap->ip_dst); } } out: -- cgit v0.10.2 From c7425314c755d5f94da7c978205c85a7c6201212 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 9 Aug 2009 17:03:52 +0900 Subject: x86: Introduce GDT_ENTRY_INIT(), initialize bad_bios_desc statically Fully initialize bad_bios_desc statically instead of doing some fields statically and some dynamically. Suggested-by: "H. Peter Anvin" Signed-off-by: Akinobu Mita LKML-Reference: <20090809080350.GA4765@localhost.localdomain> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index febb2da..39a4462 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -403,7 +403,15 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); static struct apm_user *user_list; static DEFINE_SPINLOCK(user_list_lock); -static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, 0, 0); + +/* + * Set up a segment that references the real mode segment 0x40 + * that extends up to the end of page zero (that we have reserved). + * This is for buggy BIOS's that refer to (real mode) segment 0x40 + * even though they are called in protected mode. + */ +static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, + (unsigned long)__va(0x400UL), PAGE_SIZE - 0x400 - 1); static const char driver_version[] = "1.16ac"; /* no spaces */ @@ -2332,15 +2340,6 @@ static int __init apm_init(void) pm_flags |= PM_APM; /* - * Set up a segment that references the real mode segment 0x40 - * that extends up to the end of page zero (that we have reserved). - * This is for buggy BIOS's that refer to (real mode) segment 0x40 - * even though they are called in protected mode. - */ - set_desc_base(&bad_bios_desc, (unsigned long)__va(0x40UL << 4)); - set_desc_limit(&bad_bios_desc, 4095 - (0x40 << 4)); - - /* * Set up the long jump entry point to the APM BIOS, which is called * from inline assembly. */ diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index bd035e3..fc83783c 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -60,7 +60,8 @@ do { \ set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \ } while(0) -static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, 0, 0); +static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, + (unsigned long)__va(0x400UL), PAGE_SIZE - 0x400 - 1); /* * At some point we want to use this stack frame pointer to unwind @@ -476,8 +477,6 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) pnp_bios_callpoint.offset = header->fields.pm16offset; pnp_bios_callpoint.segment = PNP_CS16; - set_desc_base(&bad_bios_desc, (unsigned long)__va(0x40UL << 4)); - set_desc_limit(&bad_bios_desc, 4095 - (0x40 << 4)); for_each_possible_cpu(i) { struct desc_struct *gdt = get_cpu_gdt_table(i); if (!gdt) -- cgit v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index f8cd450..3aa4a77 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 3a7105b..86d81a2 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 6bf9e1f..0000000 --- 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 a21f5df..0000000 --- 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 6a347e7..74ce892 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"); @@ -73,41 +72,6 @@ static bool dscp_tg_check(const struct xt_tgchk_param *par) } 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) { const struct xt_tos_target_info *info = par->targinfo; @@ -168,16 +132,6 @@ static struct xt_target dscp_tg_reg[] __read_mostly = { }, { .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, .family = NFPROTO_IPV4, .table = "mangle", diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c index c3f8085..0280d3a 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; @@ -94,14 +85,6 @@ static struct xt_match dscp_mt_reg[] __read_mostly = { }, { .name = "tos", - .revision = 0, - .family = NFPROTO_IPV4, - .match = tos_mt_v0, - .matchsize = sizeof(struct ipt_tos_info), - .me = THIS_MODULE, - }, - { - .name = "tos", .revision = 1, .family = NFPROTO_IPV4, .match = tos_mt, -- cgit v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 3aa4a77..7eccf94 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 7635c8f..0a85458 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 d6e5ab4..5934570 100644 --- a/net/netfilter/xt_CONNMARK.c +++ b/net/netfilter/xt_CONNMARK.c @@ -36,45 +36,6 @@ MODULE_ALIAS("ip6t_CONNMARK"); #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) { const struct xt_connmark_tginfo1 *info = par->targinfo; @@ -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 v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 7eccf94..121e19c 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 028304b..bc9561b 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 67574bc..225f8d1 100644 --- a/net/netfilter/xt_MARK.c +++ b/net/netfilter/xt_MARK.c @@ -25,39 +25,6 @@ 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) { const struct xt_mark_tginfo2 *info = par->targinfo; @@ -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 v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 121e19c..54f9357 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 571e266..619e47c 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 86cacab..122aa8b 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 v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 54f9357..6746473 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 7ae0533..54f47a2 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 fc58180..6dc4652 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c @@ -19,101 +19,12 @@ 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, const union nf_inet_addr *umask, unsigned int l3proto) @@ -337,73 +248,9 @@ 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, .family = NFPROTO_UNSPEC, .matchsize = sizeof(struct xt_conntrack_mtinfo1), -- cgit v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 6746473..8862b03 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 86d81a2..5e361ef 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 5f1aebd..0000000 --- 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 501f9b6..ffc9638 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) @@ -127,14 +93,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, .family = NFPROTO_IPV4, .match = iprange_mt4, @@ -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 v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 8862b03..5556d23 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 6fa460a..6607c8f 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 10b9e34..1db07d8 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 @@ -23,14 +23,6 @@ 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) { const struct xt_mark_mtinfo1 *info = par->matchinfo; @@ -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 v0.10.2 From 765e8db078e63fdc076fcf6024c15d3b7b955746 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Aug 2009 10:07:35 +0200 Subject: sound: usb-audio: do not make URBs longer than sync packet interval Using more packets in one URB do avoid interrupts does not make sense when we have a sync pipe whose packets generate interrupts more often. Therefore, limit the URB size to the synchronization packet interval. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 44b9cdc..fa3f7a1 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1083,6 +1083,8 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri } else urb_packs = 1; urb_packs *= packs_per_ms; + if (subs->syncpipe) + urb_packs = min(urb_packs, 1 << subs->syncinterval); /* decide how many packets to be used */ if (is_playback) { -- cgit v0.10.2 From 6e2efaacb3579fd9643d0dc59963b58b801c03a1 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Aug 2009 10:06:53 +0200 Subject: sound: ymfpci: increase timer resolution to 96 kHz Allow the interval timer to be programmed with its full 96 kHz precision. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h index 05ead66..444cd6b 100644 --- a/include/sound/ymfpci.h +++ b/include/sound/ymfpci.h @@ -331,6 +331,7 @@ struct snd_ymfpci { struct snd_ac97 *ac97; struct snd_rawmidi *rawmidi; struct snd_timer *timer; + unsigned int timer_ticks; struct pci_dev *pci; struct snd_card *card; diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 2f09252..5518371 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -834,7 +834,7 @@ static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id) status = snd_ymfpci_readw(chip, YDSXGR_INTFLAG); if (status & 1) { if (chip->timer) - snd_timer_interrupt(chip->timer, chip->timer->sticks); + snd_timer_interrupt(chip->timer, chip->timer_ticks); } snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status); @@ -1885,8 +1885,18 @@ static int snd_ymfpci_timer_start(struct snd_timer *timer) unsigned int count; chip = snd_timer_chip(timer); - count = (timer->sticks << 1) - 1; spin_lock_irqsave(&chip->reg_lock, flags); + if (timer->sticks > 1) { + chip->timer_ticks = timer->sticks; + count = timer->sticks - 1; + } else { + /* + * Divisor 1 is not allowed; fake it by using divisor 2 and + * counting two ticks for each interrupt. + */ + chip->timer_ticks = 2; + count = 2 - 1; + } snd_ymfpci_writew(chip, YDSXGR_TIMERCOUNT, count); snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x03); spin_unlock_irqrestore(&chip->reg_lock, flags); @@ -1909,14 +1919,14 @@ static int snd_ymfpci_timer_precise_resolution(struct snd_timer *timer, unsigned long *num, unsigned long *den) { *num = 1; - *den = 48000; + *den = 96000; return 0; } static struct snd_timer_hardware snd_ymfpci_timer_hw = { .flags = SNDRV_TIMER_HW_AUTO, - .resolution = 20833, /* 1/fs = 20.8333...us */ - .ticks = 0x8000, + .resolution = 10417, /* 1 / 96 kHz = 10.41666...us */ + .ticks = 0x10000, .start = snd_ymfpci_timer_start, .stop = snd_ymfpci_timer_stop, .precise_resolution = snd_ymfpci_timer_precise_resolution, -- cgit v0.10.2 From 5e8e7c38533a8f86626e9410fa38f5854a6959df Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Aug 2009 10:05:23 +0200 Subject: sound: fix OSS MIDI output data loss In the 2.1.6 kernel, the output loop in midi_poll() was changed to enable interrupts during the outputc() call. Unfortunately, the check whether the device has accepted the current byte ("ok") was moved behind the code that removes the byte from the output queue, so one byte would be lost every time the hardware FIFO is full. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c index a40be0c..782b3b8 100644 --- a/sound/oss/midibuf.c +++ b/sound/oss/midibuf.c @@ -127,15 +127,16 @@ static void midi_poll(unsigned long dummy) for (dev = 0; dev < num_midis; dev++) if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL) { - int ok = 1; - - while (DATA_AVAIL(midi_out_buf[dev]) && ok) + while (DATA_AVAIL(midi_out_buf[dev])) { + int ok; int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head]; spin_unlock_irqrestore(&lock,flags);/* Give some time to others */ ok = midi_devs[dev]->outputc(dev, c); spin_lock_irqsave(&lock, flags); + if (!ok) + break; midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE; midi_out_buf[dev]->len--; } -- cgit v0.10.2 From 6461caed83412ae3e9a16785ffa64396fb66c6a6 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 12 Jun 2009 19:46:26 +0200 Subject: netfilter: xtables: remove xt_owner v0 Superseded by xt_owner v1 (v2.6.24-2388-g0265ab4). Signed-off-by: Jan Engelhardt diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild index 5e361ef..5413005 100644 --- a/include/linux/netfilter_ipv4/Kbuild +++ b/include/linux/netfilter_ipv4/Kbuild @@ -28,7 +28,6 @@ header-y += ipt_limit.h header-y += ipt_mac.h header-y += ipt_mark.h header-y += ipt_multiport.h -header-y += ipt_owner.h header-y += ipt_physdev.h header-y += ipt_pkttype.h header-y += ipt_policy.h diff --git a/include/linux/netfilter_ipv4/ipt_owner.h b/include/linux/netfilter_ipv4/ipt_owner.h deleted file mode 100644 index a78445b..0000000 --- a/include/linux/netfilter_ipv4/ipt_owner.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _IPT_OWNER_H -#define _IPT_OWNER_H - -/* match and invert flags */ -#define IPT_OWNER_UID 0x01 -#define IPT_OWNER_GID 0x02 -#define IPT_OWNER_PID 0x04 -#define IPT_OWNER_SID 0x08 -#define IPT_OWNER_COMM 0x10 - -struct ipt_owner_info { - __kernel_uid32_t uid; - __kernel_gid32_t gid; - __kernel_pid_t pid; - __kernel_pid_t sid; - char comm[16]; - u_int8_t match, invert; /* flags */ -}; - -#endif /*_IPT_OWNER_H*/ diff --git a/include/linux/netfilter_ipv6/Kbuild b/include/linux/netfilter_ipv6/Kbuild index aca4bd1..4610a16 100644 --- a/include/linux/netfilter_ipv6/Kbuild +++ b/include/linux/netfilter_ipv6/Kbuild @@ -14,7 +14,6 @@ header-y += ip6t_mark.h header-y += ip6t_mh.h header-y += ip6t_multiport.h header-y += ip6t_opts.h -header-y += ip6t_owner.h header-y += ip6t_physdev.h header-y += ip6t_policy.h header-y += ip6t_rt.h diff --git a/include/linux/netfilter_ipv6/ip6t_owner.h b/include/linux/netfilter_ipv6/ip6t_owner.h deleted file mode 100644 index ec5cc7a..0000000 --- a/include/linux/netfilter_ipv6/ip6t_owner.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _IP6T_OWNER_H -#define _IP6T_OWNER_H - -/* match and invert flags */ -#define IP6T_OWNER_UID 0x01 -#define IP6T_OWNER_GID 0x02 -#define IP6T_OWNER_PID 0x04 -#define IP6T_OWNER_SID 0x08 - -struct ip6t_owner_info { - __kernel_uid32_t uid; - __kernel_gid32_t gid; - __kernel_pid_t pid; - __kernel_pid_t sid; - u_int8_t match, invert; /* flags */ -}; - -#endif /*_IPT_OWNER_H*/ diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c index 22b2a5e..d24c76d 100644 --- a/net/netfilter/xt_owner.c +++ b/net/netfilter/xt_owner.c @@ -5,7 +5,6 @@ * (C) 2000 Marc Boucher * * Copyright © CC Computer Consultants GmbH, 2007 - 2008 - * * * 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 @@ -17,60 +16,6 @@ #include #include #include -#include -#include - -static bool -owner_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) -{ - const struct ipt_owner_info *info = par->matchinfo; - const struct file *filp; - - if (skb->sk == NULL || skb->sk->sk_socket == NULL) - return false; - - filp = skb->sk->sk_socket->file; - if (filp == NULL) - return false; - - if (info->match & IPT_OWNER_UID) - if ((filp->f_cred->fsuid != info->uid) ^ - !!(info->invert & IPT_OWNER_UID)) - return false; - - if (info->match & IPT_OWNER_GID) - if ((filp->f_cred->fsgid != info->gid) ^ - !!(info->invert & IPT_OWNER_GID)) - return false; - - return true; -} - -static bool -owner_mt6_v0(const struct sk_buff *skb, const struct xt_match_param *par) -{ - const struct ip6t_owner_info *info = par->matchinfo; - const struct file *filp; - - if (skb->sk == NULL || skb->sk->sk_socket == NULL) - return false; - - filp = skb->sk->sk_socket->file; - if (filp == NULL) - return false; - - if (info->match & IP6T_OWNER_UID) - if ((filp->f_cred->fsuid != info->uid) ^ - !!(info->invert & IP6T_OWNER_UID)) - return false; - - if (info->match & IP6T_OWNER_GID) - if ((filp->f_cred->fsgid != info->gid) ^ - !!(info->invert & IP6T_OWNER_GID)) - return false; - - return true; -} static bool owner_mt(const struct sk_buff *skb, const struct xt_match_param *par) @@ -107,81 +52,30 @@ owner_mt(const struct sk_buff *skb, const struct xt_match_param *par) return true; } -static bool owner_mt_check_v0(const struct xt_mtchk_param *par) -{ - const struct ipt_owner_info *info = par->matchinfo; - - if (info->match & (IPT_OWNER_PID | IPT_OWNER_SID | IPT_OWNER_COMM)) { - printk(KERN_WARNING KBUILD_MODNAME - ": PID, SID and command matching is not " - "supported anymore\n"); - return false; - } - - return true; -} - -static bool owner_mt6_check_v0(const struct xt_mtchk_param *par) -{ - const struct ip6t_owner_info *info = par->matchinfo; - - if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) { - printk(KERN_WARNING KBUILD_MODNAME - ": PID and SID matching is not supported anymore\n"); - return false; - } - - return true; -} - -static struct xt_match owner_mt_reg[] __read_mostly = { - { - .name = "owner", - .revision = 0, - .family = NFPROTO_IPV4, - .match = owner_mt_v0, - .matchsize = sizeof(struct ipt_owner_info), - .checkentry = owner_mt_check_v0, - .hooks = (1 << NF_INET_LOCAL_OUT) | - (1 << NF_INET_POST_ROUTING), - .me = THIS_MODULE, - }, - { - .name = "owner", - .revision = 0, - .family = NFPROTO_IPV6, - .match = owner_mt6_v0, - .matchsize = sizeof(struct ip6t_owner_info), - .checkentry = owner_mt6_check_v0, - .hooks = (1 << NF_INET_LOCAL_OUT) | - (1 << NF_INET_POST_ROUTING), - .me = THIS_MODULE, - }, - { - .name = "owner", - .revision = 1, - .family = NFPROTO_UNSPEC, - .match = owner_mt, - .matchsize = sizeof(struct xt_owner_match_info), - .hooks = (1 << NF_INET_LOCAL_OUT) | - (1 << NF_INET_POST_ROUTING), - .me = THIS_MODULE, - }, +static struct xt_match owner_mt_reg __read_mostly = { + .name = "owner", + .revision = 1, + .family = NFPROTO_UNSPEC, + .match = owner_mt, + .matchsize = sizeof(struct xt_owner_match_info), + .hooks = (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_POST_ROUTING), + .me = THIS_MODULE, }; static int __init owner_mt_init(void) { - return xt_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + return xt_register_match(&owner_mt_reg); } static void __exit owner_mt_exit(void) { - xt_unregister_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + xt_unregister_match(&owner_mt_reg); } module_init(owner_mt_init); module_exit(owner_mt_exit); -MODULE_AUTHOR("Jan Engelhardt "); +MODULE_AUTHOR("Jan Engelhardt "); MODULE_DESCRIPTION("Xtables: socket owner matching"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_owner"); -- cgit v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 5556d23..698e1e8 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 5413005..431b407 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 a46d511..0000000 --- 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 9ecfee0..0000000 --- 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 3491e52..0000000 --- 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 94e0d98..7ca4591 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 697a486..0000000 --- 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 97a2a75..0000000 --- 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 7a850f9..0000000 --- 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 ae2afc2..0000000 --- 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 f63e6ee..0000000 --- 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 c7ba656..0000000 --- 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 cde6762..0000000 --- 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 e70d11e..0000000 --- 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 4b82ca9..0000000 --- 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 1f0d9a4..9945baa 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 78296e7..0000000 --- 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 5662120..0000000 --- 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 80452c2..0000000 --- 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 9b45206..0000000 --- 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 92f5cd0..0000000 --- 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 b186008..0000000 --- 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 bfde67c..0000000 --- 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 55fe85e..0000000 --- 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 2400e71..0000000 --- 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 ff1fbc9..0000000 --- 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 1037fb2..0000000 --- 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 d636cca..0000000 --- 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 80b3dba..0000000 --- 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 a44a99c..0000000 --- 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 c26de30..0000000 --- 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 18bbc8e..0000000 --- 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 4610a16..e864eae 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 7cf629a..0000000 --- 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 f62eaf5..0000000 --- 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 9e9689d..0000000 --- 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 487e5ea..0000000 --- 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 ac58e83..0000000 --- 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 ff20495..0000000 --- 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 042c926..0000000 --- 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 c161c0a..0000000 --- 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 b1c449d..0000000 --- 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 v0.10.2 From 57750a22ed022ed6fcdcc5bc58d16011ccfe575f Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 13 Jun 2009 06:22:18 +0200 Subject: netfilter: conntrack: switch hook PFs to nfproto Simple substitution to indicate that the fields indeed use the NFPROTO_ space. Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 7d2ead7..8905cc7 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -158,28 +158,28 @@ static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = { { .hook = ipv4_conntrack_in, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_CONNTRACK, }, { .hook = ipv4_conntrack_local, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_CONNTRACK, }, { .hook = ipv4_confirm, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_POST_ROUTING, .priority = NF_IP_PRI_CONNTRACK_CONFIRM, }, { .hook = ipv4_confirm, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_CONNTRACK_CONFIRM, }, diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 2a15c2d..a7f4cd6 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -265,42 +265,42 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { { .hook = ipv6_defrag, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, }, { .hook = ipv6_conntrack_in, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP6_PRI_CONNTRACK, }, { .hook = ipv6_conntrack_local, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP6_PRI_CONNTRACK, }, { .hook = ipv6_defrag, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, }, { .hook = ipv6_confirm, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_POST_ROUTING, .priority = NF_IP6_PRI_LAST, }, { .hook = ipv6_confirm, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP6_PRI_LAST-1, }, -- cgit v0.10.2 From 24c232d8e911ef6189e02da411dc2b72cb03bfcf Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 13 Jun 2009 06:20:29 +0200 Subject: netfilter: xtables: switch hook PFs to nfproto Signed-off-by: Jan Engelhardt diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index a5eea72..4b988db 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c @@ -77,21 +77,21 @@ static struct nf_hook_ops ebt_ops_filter[] __read_mostly = { { .hook = ebt_in_hook, .owner = THIS_MODULE, - .pf = PF_BRIDGE, + .pf = NFPROTO_BRIDGE, .hooknum = NF_BR_LOCAL_IN, .priority = NF_BR_PRI_FILTER_BRIDGED, }, { .hook = ebt_in_hook, .owner = THIS_MODULE, - .pf = PF_BRIDGE, + .pf = NFPROTO_BRIDGE, .hooknum = NF_BR_FORWARD, .priority = NF_BR_PRI_FILTER_BRIDGED, }, { .hook = ebt_out_hook, .owner = THIS_MODULE, - .pf = PF_BRIDGE, + .pf = NFPROTO_BRIDGE, .hooknum = NF_BR_LOCAL_OUT, .priority = NF_BR_PRI_FILTER_OTHER, }, diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index 6024c55..4a98804 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c @@ -77,21 +77,21 @@ static struct nf_hook_ops ebt_ops_nat[] __read_mostly = { { .hook = ebt_nat_out, .owner = THIS_MODULE, - .pf = PF_BRIDGE, + .pf = NFPROTO_BRIDGE, .hooknum = NF_BR_LOCAL_OUT, .priority = NF_BR_PRI_NAT_DST_OTHER, }, { .hook = ebt_nat_out, .owner = THIS_MODULE, - .pf = PF_BRIDGE, + .pf = NFPROTO_BRIDGE, .hooknum = NF_BR_POST_ROUTING, .priority = NF_BR_PRI_NAT_SRC, }, { .hook = ebt_nat_in, .owner = THIS_MODULE, - .pf = PF_BRIDGE, + .pf = NFPROTO_BRIDGE, .hooknum = NF_BR_PRE_ROUTING, .priority = NF_BR_PRI_NAT_DST_BRIDGED, }, diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index c30a969..bef326c 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -102,21 +102,21 @@ static struct nf_hook_ops ipt_ops[] __read_mostly = { { .hook = ipt_local_in_hook, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_FILTER, }, { .hook = ipt_hook, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_FORWARD, .priority = NF_IP_PRI_FILTER, }, { .hook = ipt_local_out_hook, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_FILTER, }, diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 4087614..1442df7 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -162,35 +162,35 @@ static struct nf_hook_ops ipt_ops[] __read_mostly = { { .hook = ipt_pre_routing_hook, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_MANGLE, }, { .hook = ipt_local_in_hook, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_MANGLE, }, { .hook = ipt_forward_hook, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_FORWARD, .priority = NF_IP_PRI_MANGLE, }, { .hook = ipt_local_hook, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_MANGLE, }, { .hook = ipt_post_routing_hook, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_POST_ROUTING, .priority = NF_IP_PRI_MANGLE, }, diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index e5356da..1d28df8 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -74,14 +74,14 @@ ipt_local_hook(unsigned int hook, static struct nf_hook_ops ipt_ops[] __read_mostly = { { .hook = ipt_hook, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_RAW, .owner = THIS_MODULE, }, { .hook = ipt_local_hook, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_RAW, .owner = THIS_MODULE, diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index 29ab630..8c5a250 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -105,21 +105,21 @@ static struct nf_hook_ops ipt_ops[] __read_mostly = { { .hook = ipt_local_in_hook, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_SECURITY, }, { .hook = ipt_forward_hook, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_FORWARD, .priority = NF_IP_PRI_SECURITY, }, { .hook = ipt_local_out_hook, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_SECURITY, }, diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index 5567bd0..5f41d01 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -251,7 +251,7 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = { { .hook = nf_nat_in, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_NAT_DST, }, @@ -259,7 +259,7 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = { { .hook = nf_nat_out, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_POST_ROUTING, .priority = NF_IP_PRI_NAT_SRC, }, @@ -267,7 +267,7 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = { { .hook = nf_nat_local_fn, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_NAT_DST, }, @@ -275,7 +275,7 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = { { .hook = nf_nat_fn, .owner = THIS_MODULE, - .pf = PF_INET, + .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_NAT_SRC, }, diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index ef5a0a3..b35c358 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -95,21 +95,21 @@ static struct nf_hook_ops ip6t_ops[] __read_mostly = { { .hook = ip6t_in_hook, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP6_PRI_FILTER, }, { .hook = ip6t_in_hook, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_FORWARD, .priority = NF_IP6_PRI_FILTER, }, { .hook = ip6t_local_out_hook, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP6_PRI_FILTER, }, diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index ab0d398..a98ced1 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -136,35 +136,35 @@ static struct nf_hook_ops ip6t_ops[] __read_mostly = { { .hook = ip6t_in_hook, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP6_PRI_MANGLE, }, { .hook = ip6t_in_hook, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP6_PRI_MANGLE, }, { .hook = ip6t_in_hook, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_FORWARD, .priority = NF_IP6_PRI_MANGLE, }, { .hook = ip6t_local_out_hook, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP6_PRI_MANGLE, }, { .hook = ip6t_post_routing_hook, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_POST_ROUTING, .priority = NF_IP6_PRI_MANGLE, }, diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 4b792b6..ec12540 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -68,14 +68,14 @@ ip6t_local_out_hook(unsigned int hook, static struct nf_hook_ops ip6t_ops[] __read_mostly = { { .hook = ip6t_pre_routing_hook, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP6_PRI_FIRST, .owner = THIS_MODULE, }, { .hook = ip6t_local_out_hook, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP6_PRI_FIRST, .owner = THIS_MODULE, diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index 0ea37ff..d808507 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c @@ -101,21 +101,21 @@ static struct nf_hook_ops ip6t_ops[] __read_mostly = { { .hook = ip6t_local_in_hook, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP6_PRI_SECURITY, }, { .hook = ip6t_forward_hook, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_FORWARD, .priority = NF_IP6_PRI_SECURITY, }, { .hook = ip6t_local_out_hook, .owner = THIS_MODULE, - .pf = PF_INET6, + .pf = NFPROTO_IPV6, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP6_PRI_SECURITY, }, -- cgit v0.10.2 From f88e6a8a50a603f8347343e75d035889784a507c Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 13 Jun 2009 06:25:44 +0200 Subject: netfilter: xtables: switch table AFs to nfproto Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index bef326c..97dbd94 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -57,7 +57,7 @@ static struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, .me = THIS_MODULE, - .af = AF_INET, + .af = NFPROTO_IPV4, }; /* The work comes in here from netfilter.c. */ diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 1442df7..28647f1 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -68,7 +68,7 @@ static struct xt_table packet_mangler = { .name = "mangle", .valid_hooks = MANGLE_VALID_HOOKS, .me = THIS_MODULE, - .af = AF_INET, + .af = NFPROTO_IPV4, }; /* The work comes in here from netfilter.c. */ diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 1d28df8..494784c 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -40,7 +40,7 @@ static struct xt_table packet_raw = { .name = "raw", .valid_hooks = RAW_VALID_HOOKS, .me = THIS_MODULE, - .af = AF_INET, + .af = NFPROTO_IPV4, }; /* The work comes in here from netfilter.c. */ diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index 8c5a250..8804e1a 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -61,7 +61,7 @@ static struct xt_table security_table = { .name = "security", .valid_hooks = SECURITY_VALID_HOOKS, .me = THIS_MODULE, - .af = AF_INET, + .af = NFPROTO_IPV4, }; static unsigned int diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index 6348a79..6448a9b 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -62,7 +62,7 @@ static struct xt_table nat_table = { .name = "nat", .valid_hooks = NAT_VALID_HOOKS, .me = THIS_MODULE, - .af = AF_INET, + .af = NFPROTO_IPV4, }; /* Source NAT */ diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index b35c358..0a3ae48 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -55,7 +55,7 @@ static struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, .me = THIS_MODULE, - .af = AF_INET6, + .af = NFPROTO_IPV6, }; /* The work comes in here from netfilter.c. */ diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index a98ced1..0f49e00 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -61,7 +61,7 @@ static struct xt_table packet_mangler = { .name = "mangle", .valid_hooks = MANGLE_VALID_HOOKS, .me = THIS_MODULE, - .af = AF_INET6, + .af = NFPROTO_IPV6, }; /* The work comes in here from netfilter.c. */ diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index ec12540..679865e 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -39,7 +39,7 @@ static struct xt_table packet_raw = { .name = "raw", .valid_hooks = RAW_VALID_HOOKS, .me = THIS_MODULE, - .af = AF_INET6, + .af = NFPROTO_IPV6, }; /* The work comes in here from netfilter.c. */ diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index d808507..822afab 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c @@ -60,7 +60,7 @@ static struct xt_table security_table = { .name = "security", .valid_hooks = SECURITY_VALID_HOOKS, .me = THIS_MODULE, - .af = AF_INET6, + .af = NFPROTO_IPV6, }; static unsigned int -- cgit v0.10.2 From 98d89b4198cf7273968e9217a62ec7ccfd760171 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 5 Jul 2009 15:55:06 +0200 Subject: netfilter: xtables: realign struct xt_target_param This commit gets rid of a padding hole as reported by pahole(1). Saves 8 bytes on x86_64. Signed-off-by: Jan Engelhardt diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 1030b75..4fa6e4c 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -238,9 +238,9 @@ struct xt_mtdtor_param { */ struct xt_target_param { const struct net_device *in, *out; - unsigned int hooknum; const struct xt_target *target; const void *targinfo; + unsigned int hooknum; u_int8_t family; }; -- cgit v0.10.2 From e5afbba1869a5d9509c61f8962be9bdebf95f7d3 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 8 Jul 2009 12:33:10 +0200 Subject: netfilter: iptables: remove unused datalen variable Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index fdefae6..3856aa3 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -315,7 +315,6 @@ ipt_do_table(struct sk_buff *skb, static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); const struct iphdr *ip; - u_int16_t datalen; bool hotdrop = false; /* Initializing verdict to NF_DROP keeps gcc happy. */ unsigned int verdict = NF_DROP; @@ -328,7 +327,6 @@ ipt_do_table(struct sk_buff *skb, /* Initialization */ ip = ip_hdr(skb); - datalen = skb->len - ip->ihl * 4; indev = in ? in->name : nulldevname; outdev = out ? out->name : nulldevname; /* We handle fragments by dealing with the first fragment as @@ -427,8 +425,6 @@ ipt_do_table(struct sk_buff *skb, #endif /* Target might have changed stuff. */ ip = ip_hdr(skb); - datalen = skb->len - ip->ihl * 4; - if (verdict == IPT_CONTINUE) e = ipt_next_entry(e); else -- cgit v0.10.2 From 47901dc2c4a3f1f9af453486a005d31fe9b393f0 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 9 Jul 2009 23:00:19 +0200 Subject: netfilter: xtables: use memcmp in unconditional check Instead of inspecting each u32/char open-coded, clean up and make use of memcmp. On some arches, memcmp is implemented as assembly or GCC's __builtin_memcmp which can possibly take advantages of known alignment. Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 7505dff..b9f7243 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -341,15 +341,11 @@ unsigned int arpt_do_table(struct sk_buff *skb, } /* All zeroes == unconditional rule. */ -static inline int unconditional(const struct arpt_arp *arp) +static inline bool unconditional(const struct arpt_arp *arp) { - unsigned int i; - - for (i = 0; i < sizeof(*arp)/sizeof(__u32); i++) - if (((__u32 *)arp)[i]) - return 0; + static const struct arpt_arp uncond; - return 1; + return memcmp(arp, &uncond, sizeof(uncond)) == 0; } /* Figures out from what hook each rule can be called: returns 0 if diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 3856aa3..3431a77 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -190,16 +190,11 @@ get_entry(void *base, unsigned int offset) /* All zeroes == unconditional rule. */ /* Mildly perf critical (only if packet tracing is on) */ -static inline int -unconditional(const struct ipt_ip *ip) +static inline bool unconditional(const struct ipt_ip *ip) { - unsigned int i; + static const struct ipt_ip uncond; - for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++) - if (((__u32 *)ip)[i]) - return 0; - - return 1; + return memcmp(ip, &uncond, sizeof(uncond)) == 0; #undef FWINV } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index ced1f2c..1389ad9 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -222,16 +222,11 @@ get_entry(void *base, unsigned int offset) /* All zeroes == unconditional rule. */ /* Mildly perf critical (only if packet tracing is on) */ -static inline int -unconditional(const struct ip6t_ip6 *ipv6) +static inline bool unconditional(const struct ip6t_ip6 *ipv6) { - unsigned int i; - - for (i = 0; i < sizeof(*ipv6); i++) - if (((char *)ipv6)[i]) - break; + static const struct ip6t_ip6 uncond; - return (i == sizeof(*ipv6)); + return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; } #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ -- cgit v0.10.2 From a7d51738e757c1ab94595e7d05594c61f0fb32ce Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 18 Jul 2009 14:52:58 +0200 Subject: netfilter: xtables: ignore unassigned hooks in check_entry_size_and_hooks The "hook_entry" and "underflow" array contains values even for hooks not provided, such as PREROUTING in conjunction with the "filter" table. Usually, the values point to whatever the next rule is. For the upcoming unconditionality and underflow checking patches however, we must not inspect that arbitrary rule. Skipping unassigned hooks seems like a good idea, also because newinfo->hook_entry and newinfo->underflow will then continue to have the poison value for detecting abnormalities. Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index b9f7243..d91f083 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -539,6 +539,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, unsigned char *limit, const unsigned int *hook_entries, const unsigned int *underflows, + unsigned int valid_hooks, unsigned int *i) { unsigned int h; @@ -558,6 +559,8 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, /* Check hooks & underflows */ for (h = 0; h < NF_ARP_NUMHOOKS; h++) { + if (!(valid_hooks & (1 << h))) + continue; if ((unsigned char *)e - base == hook_entries[h]) newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) @@ -626,7 +629,7 @@ static int translate_table(const char *name, newinfo, entry0, entry0 + size, - hook_entries, underflows, &i); + hook_entries, underflows, valid_hooks, &i); duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); if (ret != 0) return ret; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 3431a77..6e7b7e8 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -714,6 +714,7 @@ check_entry_size_and_hooks(struct ipt_entry *e, unsigned char *limit, const unsigned int *hook_entries, const unsigned int *underflows, + unsigned int valid_hooks, unsigned int *i) { unsigned int h; @@ -733,6 +734,8 @@ check_entry_size_and_hooks(struct ipt_entry *e, /* Check hooks & underflows */ for (h = 0; h < NF_INET_NUMHOOKS; h++) { + if (!(valid_hooks & (1 << h))) + continue; if ((unsigned char *)e - base == hook_entries[h]) newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) @@ -804,7 +807,7 @@ translate_table(const char *name, newinfo, entry0, entry0 + size, - hook_entries, underflows, &i); + hook_entries, underflows, valid_hooks, &i); if (ret != 0) return ret; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 1389ad9..8e4921a 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -747,6 +747,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e, unsigned char *limit, const unsigned int *hook_entries, const unsigned int *underflows, + unsigned int valid_hooks, unsigned int *i) { unsigned int h; @@ -766,6 +767,8 @@ check_entry_size_and_hooks(struct ip6t_entry *e, /* Check hooks & underflows */ for (h = 0; h < NF_INET_NUMHOOKS; h++) { + if (!(valid_hooks & (1 << h))) + continue; if ((unsigned char *)e - base == hook_entries[h]) newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) @@ -837,7 +840,7 @@ translate_table(const char *name, newinfo, entry0, entry0 + size, - hook_entries, underflows, &i); + hook_entries, underflows, valid_hooks, &i); if (ret != 0) return ret; -- cgit v0.10.2 From 90e7d4ab5c8b0c4c2e00e4893977f6aeec0f18f1 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 9 Jul 2009 22:54:53 +0200 Subject: netfilter: xtables: check for unconditionality of policies This adds a check that iptables's original author Rusty set forth in a FIXME comment. Underflows in iptables are better known as chain policies, and are required to be unconditional or there would be a stochastical chance for the policy rule to be skipped if it does not match. If that were to happen, rule execution would continue in an unexpected spurious fashion. Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index d91f083..064082d 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -8,7 +8,7 @@ * Copyright (C) 2002 David S. Miller (davem@redhat.com) * */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #include @@ -563,13 +563,15 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, continue; if ((unsigned char *)e - base == hook_entries[h]) newinfo->hook_entry[h] = hook_entries[h]; - if ((unsigned char *)e - base == underflows[h]) + if ((unsigned char *)e - base == underflows[h]) { + if (!unconditional(&e->arp)) { + pr_err("Underflows must be unconditional\n"); + return -EINVAL; + } newinfo->underflow[h] = underflows[h]; + } } - /* FIXME: underflows must be unconditional, standard verdicts - < 0 (not ARPT_RETURN). --RR */ - /* Clear counters and comefrom */ e->counters = ((struct xt_counters) { 0, 0 }); e->comefrom = 0; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 6e7b7e8..6e546d5 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -8,6 +8,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #include @@ -738,13 +739,15 @@ check_entry_size_and_hooks(struct ipt_entry *e, continue; if ((unsigned char *)e - base == hook_entries[h]) newinfo->hook_entry[h] = hook_entries[h]; - if ((unsigned char *)e - base == underflows[h]) + if ((unsigned char *)e - base == underflows[h]) { + if (!unconditional(&e->ip)) { + pr_err("Underflows must be unconditional\n"); + return -EINVAL; + } newinfo->underflow[h] = underflows[h]; + } } - /* FIXME: underflows must be unconditional, standard verdicts - < 0 (not IPT_RETURN). --RR */ - /* Clear counters and comefrom */ e->counters = ((struct xt_counters) { 0, 0 }); e->comefrom = 0; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 8e4921a..b0599b9 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -8,7 +8,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #include @@ -771,13 +771,15 @@ check_entry_size_and_hooks(struct ip6t_entry *e, continue; if ((unsigned char *)e - base == hook_entries[h]) newinfo->hook_entry[h] = hook_entries[h]; - if ((unsigned char *)e - base == underflows[h]) + if ((unsigned char *)e - base == underflows[h]) { + if (!unconditional(&e->ipv6)) { + pr_err("Underflows must be unconditional\n"); + return -EINVAL; + } newinfo->underflow[h] = underflows[h]; + } } - /* FIXME: underflows must be unconditional, standard verdicts - < 0 (not IP6T_RETURN). --RR */ - /* Clear counters and comefrom */ e->counters = ((struct xt_counters) { 0, 0 }); e->comefrom = 0; -- cgit v0.10.2 From e2fe35c17fed62d4ab5038fa9bc489e967ff8416 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 18 Jul 2009 15:22:30 +0200 Subject: netfilter: xtables: check for standard verdicts in policies This adds the second check that Rusty wanted to have a long time ago. :-) Base chain policies must have absolute verdicts that cease processing in the table, otherwise rule execution may continue in an unexpected spurious fashion (e.g. next chain that follows in memory). Signed-off-by: Jan Engelhardt diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 064082d..7bc11ff 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -533,6 +533,21 @@ out: return ret; } +static bool check_underflow(struct arpt_entry *e) +{ + const struct arpt_entry_target *t; + unsigned int verdict; + + if (!unconditional(&e->arp)) + return false; + t = arpt_get_target(e); + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) + return false; + verdict = ((struct arpt_standard_target *)t)->verdict; + verdict = -verdict - 1; + return verdict == NF_DROP || verdict == NF_ACCEPT; +} + static inline int check_entry_size_and_hooks(struct arpt_entry *e, struct xt_table_info *newinfo, unsigned char *base, @@ -564,8 +579,10 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, if ((unsigned char *)e - base == hook_entries[h]) newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) { - if (!unconditional(&e->arp)) { - pr_err("Underflows must be unconditional\n"); + if (!check_underflow(e)) { + pr_err("Underflows must be unconditional and " + "use the STANDARD target with " + "ACCEPT/DROP\n"); return -EINVAL; } newinfo->underflow[h] = underflows[h]; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 6e546d5..0b43fd7 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -708,6 +708,21 @@ find_check_entry(struct ipt_entry *e, const char *name, unsigned int size, return ret; } +static bool check_underflow(struct ipt_entry *e) +{ + const struct ipt_entry_target *t; + unsigned int verdict; + + if (!unconditional(&e->ip)) + return false; + t = ipt_get_target(e); + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) + return false; + verdict = ((struct ipt_standard_target *)t)->verdict; + verdict = -verdict - 1; + return verdict == NF_DROP || verdict == NF_ACCEPT; +} + static int check_entry_size_and_hooks(struct ipt_entry *e, struct xt_table_info *newinfo, @@ -740,8 +755,10 @@ check_entry_size_and_hooks(struct ipt_entry *e, if ((unsigned char *)e - base == hook_entries[h]) newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) { - if (!unconditional(&e->ip)) { - pr_err("Underflows must be unconditional\n"); + if (!check_underflow(e)) { + pr_err("Underflows must be unconditional and " + "use the STANDARD target with " + "ACCEPT/DROP\n"); return -EINVAL; } newinfo->underflow[h] = underflows[h]; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index b0599b9..a5d0c27 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -740,6 +740,21 @@ find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size, return ret; } +static bool check_underflow(struct ip6t_entry *e) +{ + const struct ip6t_entry_target *t; + unsigned int verdict; + + if (!unconditional(&e->ipv6)) + return false; + t = ip6t_get_target(e); + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) + return false; + verdict = ((struct ip6t_standard_target *)t)->verdict; + verdict = -verdict - 1; + return verdict == NF_DROP || verdict == NF_ACCEPT; +} + static int check_entry_size_and_hooks(struct ip6t_entry *e, struct xt_table_info *newinfo, @@ -772,8 +787,10 @@ check_entry_size_and_hooks(struct ip6t_entry *e, if ((unsigned char *)e - base == hook_entries[h]) newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) { - if (!unconditional(&e->ipv6)) { - pr_err("Underflows must be unconditional\n"); + if (!check_underflow(e)) { + pr_err("Underflows must be unconditional and " + "use the STANDARD target with " + "ACCEPT/DROP\n"); return -EINVAL; } newinfo->underflow[h] = underflows[h]; -- cgit v0.10.2 From 1905b1bfc0de6f69a61dc03cac0d86a04b3216bd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 6 Aug 2009 18:13:23 +0900 Subject: chrdev: implement __[un]register_chrdev() [un]register_chrdev() assume minor range 0-255. This patch adds __ prefixed versions which take @minorbase and @count explicitly. Signed-off-by: Tejun Heo Cc: Al Viro Cc: Greg Kroah-Hartman Signed-off-by: Takashi Iwai diff --git a/fs/char_dev.c b/fs/char_dev.c index a173551..2f18c1e 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -237,8 +237,10 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, } /** - * register_chrdev() - Register a major number for character devices. + * __register_chrdev() - create and register a cdev occupying a range of minors * @major: major device number or 0 for dynamic allocation + * @baseminor: first of the requested range of minor numbers + * @count: the number of minor numbers required * @name: name of this range of devices * @fops: file operations associated with this devices * @@ -254,19 +256,17 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, * /dev. It only helps to keep track of the different owners of devices. If * your module name has only one type of devices it's ok to use e.g. the name * of the module here. - * - * This function registers a range of 256 minor numbers. The first minor number - * is 0. */ -int register_chrdev(unsigned int major, const char *name, - const struct file_operations *fops) +int __register_chrdev(unsigned int major, unsigned int baseminor, + unsigned int count, const char *name, + const struct file_operations *fops) { struct char_device_struct *cd; struct cdev *cdev; char *s; int err = -ENOMEM; - cd = __register_chrdev_region(major, 0, 256, name); + cd = __register_chrdev_region(major, baseminor, count, name); if (IS_ERR(cd)) return PTR_ERR(cd); @@ -280,7 +280,7 @@ int register_chrdev(unsigned int major, const char *name, for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/')) *s = '!'; - err = cdev_add(cdev, MKDEV(cd->major, 0), 256); + err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); if (err) goto out; @@ -290,7 +290,7 @@ int register_chrdev(unsigned int major, const char *name, out: kobject_put(&cdev->kobj); out2: - kfree(__unregister_chrdev_region(cd->major, 0, 256)); + kfree(__unregister_chrdev_region(cd->major, baseminor, count)); return err; } @@ -316,10 +316,23 @@ void unregister_chrdev_region(dev_t from, unsigned count) } } -void unregister_chrdev(unsigned int major, const char *name) +/** + * __unregister_chrdev - unregister and destroy a cdev + * @major: major device number + * @baseminor: first of the range of minor numbers + * @count: the number of minor numbers this cdev is occupying + * @name: name of this range of devices + * + * Unregister and destroy the cdev occupying the region described by + * @major, @baseminor and @count. This function undoes what + * __register_chrdev() did. + */ +void __unregister_chrdev(unsigned int major, unsigned int baseminor, + unsigned int count, const char *name) { struct char_device_struct *cd; - cd = __unregister_chrdev_region(major, 0, 256); + + cd = __unregister_chrdev_region(major, baseminor, count); if (cd && cd->cdev) cdev_del(cd->cdev); kfree(cd); @@ -568,6 +581,6 @@ EXPORT_SYMBOL(cdev_alloc); EXPORT_SYMBOL(cdev_del); EXPORT_SYMBOL(cdev_add); EXPORT_SYMBOL(cdev_index); -EXPORT_SYMBOL(register_chrdev); -EXPORT_SYMBOL(unregister_chrdev); +EXPORT_SYMBOL(__register_chrdev); +EXPORT_SYMBOL(__unregister_chrdev); EXPORT_SYMBOL(directly_mappable_cdev_bdi); diff --git a/include/linux/fs.h b/include/linux/fs.h index a36ffa5..6c36ab7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1998,12 +1998,25 @@ extern void bd_release_from_disk(struct block_device *, struct gendisk *); #define CHRDEV_MAJOR_HASH_SIZE 255 extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *); extern int register_chrdev_region(dev_t, unsigned, const char *); -extern int register_chrdev(unsigned int, const char *, - const struct file_operations *); -extern void unregister_chrdev(unsigned int, const char *); +extern int __register_chrdev(unsigned int major, unsigned int baseminor, + unsigned int count, const char *name, + const struct file_operations *fops); +extern void __unregister_chrdev(unsigned int major, unsigned int baseminor, + unsigned int count, const char *name); extern void unregister_chrdev_region(dev_t, unsigned); extern void chrdev_show(struct seq_file *,off_t); +static inline int register_chrdev(unsigned int major, const char *name, + const struct file_operations *fops) +{ + return __register_chrdev(major, 0, 256, name, fops); +} + +static inline void unregister_chrdev(unsigned int major, const char *name) +{ + __unregister_chrdev(major, 0, 256, name); +} + /* fs/block_dev.c */ #define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */ #define BDEVT_SIZE 10 /* Largest string for MAJ:MIN for blkdev */ -- cgit v0.10.2 From 0a848680a82e47854347cdfecbe9adf8842719e6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 6 Aug 2009 18:13:58 +0900 Subject: sound: request char-major-* module aliases for missing OSS devices Till now missing OSS devices emitted sound-slot/service-* module alises instead of the standard char-major-* if a missing device number is opened if soundcore is loaded. The custom module aliases don't have any inherent benefit than backward compatibility. sound-slot/service-* module aliases is scheduled to be removed and to help the transition this patch makes soundcore emit the standard module alises along with the custom ones. Signed-off-by: Tejun Heo Cc: Alan Cox Signed-off-by: Takashi Iwai diff --git a/sound/sound_core.c b/sound/sound_core.c index a41f8b1..786067c 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -541,6 +541,7 @@ static int soundcore_open(struct inode *inode, struct file *file) new_fops = fops_get(s->unit_fops); if (!new_fops) { spin_unlock(&sound_loader_lock); + /* * Please, don't change this order or code. * For ALSA slot means soundcard and OSS emulation code @@ -550,6 +551,17 @@ static int soundcore_open(struct inode *inode, struct file *file) */ request_module("sound-slot-%i", unit>>4); request_module("sound-service-%i-%i", unit>>4, chain); + + /* + * sound-slot/service-* module aliases are scheduled + * for removal in favor of the standard char-major-* + * module aliases. For the time being, generate both + * the legacy and standard module aliases to ease + * transition. + */ + if (request_module("char-major-%d-%d", SOUND_MAJOR, unit) > 0) + request_module("char-major-%d", SOUND_MAJOR); + spin_lock(&sound_loader_lock); s = __look_for_unit(chain, unit); if (s) -- cgit v0.10.2 From e0c48a18f76415d3ec1ac28e5f7a0df10e2f3d8c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 10 Aug 2009 12:59:29 +0100 Subject: ASoC: Drop unneeded declaration of removed wm8731 SPI write function Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 2b980cc..d3fd4f2 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -40,9 +40,6 @@ struct wm8731_priv { unsigned int sysclk; }; -#ifdef CONFIG_SPI_MASTER -static int wm8731_spi_write(struct spi_device *spi, const char *data, int len); -#endif /* * wm8731 register cache -- cgit v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 09e031c..f0690bb 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 1eceb85..439e15c 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 786067c..bb4b88e 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -128,6 +128,46 @@ 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 v0.10.2 From 074cc1deec5dee63fcd5d966b36fa4f3765b50fc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 10 Aug 2009 08:54:13 -0400 Subject: NFS: Add a ->migratepage() aop for NFS Make NFS a bit more friendly to NUMA and memory hot removal... Signed-off-by: Trond Myklebust diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 0506232..dfc8967 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -479,6 +479,7 @@ const struct address_space_operations nfs_file_aops = { .invalidatepage = nfs_invalidate_page, .releasepage = nfs_release_page, .direct_IO = nfs_direct_IO, + .migratepage = nfs_migrate_page, .launder_page = nfs_launder_page, }; diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 7dd90a6..e2ccb4a 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -248,6 +248,12 @@ extern void nfs_read_prepare(struct rpc_task *task, void *calldata); /* write.c */ extern void nfs_write_prepare(struct rpc_task *task, void *calldata); +#ifdef CONFIG_MIGRATION +extern int nfs_migrate_page(struct address_space *, + struct page *, struct page *); +#else +#define nfs_migrate_page NULL +#endif /* nfs4proc.c */ extern int _nfs4_call_sync(struct nfs_server *server, diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 0a0a2ff..6240e64 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,7 @@ #include "internal.h" #include "iostat.h" #include "nfs4_fs.h" +#include "fscache.h" #define NFSDBG_FACILITY NFSDBG_PAGECACHE @@ -220,24 +222,17 @@ static void nfs_end_page_writeback(struct page *page) clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); } -/* - * Find an associated nfs write request, and prepare to flush it out - * May return an error if the user signalled nfs_wait_on_request(). - */ -static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, - struct page *page) +static struct nfs_page *nfs_find_and_lock_request(struct page *page) { struct inode *inode = page->mapping->host; struct nfs_page *req; int ret; spin_lock(&inode->i_lock); - for(;;) { + for (;;) { req = nfs_page_find_request_locked(page); - if (req == NULL) { - spin_unlock(&inode->i_lock); - return 0; - } + if (req == NULL) + break; if (nfs_set_page_tag_locked(req)) break; /* Note: If we hold the page lock, as is the case in nfs_writepage, @@ -249,23 +244,40 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, ret = nfs_wait_on_request(req); nfs_release_request(req); if (ret != 0) - return ret; + return ERR_PTR(ret); spin_lock(&inode->i_lock); } - if (test_bit(PG_CLEAN, &req->wb_flags)) { - spin_unlock(&inode->i_lock); - BUG(); - } - if (nfs_set_page_writeback(page) != 0) { - spin_unlock(&inode->i_lock); - BUG(); - } spin_unlock(&inode->i_lock); + return req; +} + +/* + * Find an associated nfs write request, and prepare to flush it out + * May return an error if the user signalled nfs_wait_on_request(). + */ +static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, + struct page *page) +{ + struct nfs_page *req; + int ret = 0; + + req = nfs_find_and_lock_request(page); + if (!req) + goto out; + ret = PTR_ERR(req); + if (IS_ERR(req)) + goto out; + + ret = nfs_set_page_writeback(page); + BUG_ON(ret != 0); + BUG_ON(test_bit(PG_CLEAN, &req->wb_flags)); + if (!nfs_pageio_add_request(pgio, req)) { nfs_redirty_request(req); - return pgio->pg_error; + ret = pgio->pg_error; } - return 0; +out: + return ret; } static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) @@ -1582,6 +1594,41 @@ int nfs_wb_page(struct inode *inode, struct page* page) return nfs_wb_page_priority(inode, page, FLUSH_STABLE); } +#ifdef CONFIG_MIGRATION +int nfs_migrate_page(struct address_space *mapping, struct page *newpage, + struct page *page) +{ + struct nfs_page *req; + int ret; + + if (PageFsCache(page)) + nfs_fscache_release_page(page, GFP_KERNEL); + + req = nfs_find_and_lock_request(page); + ret = PTR_ERR(req); + if (IS_ERR(req)) + goto out; + + ret = migrate_page(mapping, newpage, page); + if (!req) + goto out; + if (ret) + goto out_unlock; + page_cache_get(newpage); + req->wb_page = newpage; + SetPagePrivate(newpage); + set_page_private(newpage, page_private(page)); + ClearPagePrivate(page); + set_page_private(page, 0); + page_cache_release(page); +out_unlock: + nfs_clear_page_tag_locked(req); + nfs_release_request(req); +out: + return ret; +} +#endif + int __init nfs_init_writepagecache(void) { nfs_wdata_cachep = kmem_cache_create("nfs_write_data", -- cgit v0.10.2 From 38c73044f5f4da2ef4339319b170e5e19f8dec87 Mon Sep 17 00:00:00 2001 From: Peter Staubach Date: Mon, 10 Aug 2009 08:54:16 -0400 Subject: NFS: read-modify-write page updating Hi. I have a proposal for possibly resolving this issue. I believe that this situation occurs due to the way that the Linux NFS client handles writes which modify partial pages. The Linux NFS client handles partial page modifications by allocating a page from the page cache, copying the data from the user level into the page, and then keeping track of the offset and length of the modified portions of the page. The page is not marked as up to date because there are portions of the page which do not contain valid file contents. When a read call comes in for a portion of the page, the contents of the page must be read in the from the server. However, since the page may already contain some modified data, that modified data must be written to the server before the file contents can be read back in the from server. And, since the writing and reading can not be done atomically, the data must be written and committed to stable storage on the server for safety purposes. This means either a FILE_SYNC WRITE or a UNSTABLE WRITE followed by a COMMIT. This has been discussed at length previously. This algorithm could be described as modify-write-read. It is most efficient when the application only updates pages and does not read them. My proposed solution is to add a heuristic to decide whether to do this modify-write-read algorithm or switch to a read- modify-write algorithm when initially allocating the page in the write system call path. The heuristic uses the modes that the file was opened with, the offset in the page to read from, and the size of the region to read. If the file was opened for reading in addition to writing and the page would not be filled completely with data from the user level, then read in the old contents of the page and mark it as Uptodate before copying in the new data. If the page would be completely filled with data from the user level, then there would be no reason to read in the old contents because they would just be copied over. This would optimize for applications which randomly access and update portions of files. The linkage editor for the C compiler is an example of such a thing. I tested the attached patch by using rpmbuild to build the current Fedora rawhide kernel. The kernel without the patch generated about 269,500 WRITE requests. The modified kernel containing the patch generated about 261,000 WRITE requests. Thus, about 8,500 fewer WRITE requests were generated. I suspect that many of these additional WRITE requests were probably FILE_SYNC requests to WRITE a single page, but I didn't test this theory. The difference between this patch and the previous one was to remove the unneeded PageDirty() test. I then retested to ensure that the resulting system continued to behave as desired. Thanx... ps Signed-off-by: Peter Staubach Signed-off-by: Trond Myklebust diff --git a/fs/nfs/file.c b/fs/nfs/file.c index dfc8967..5021b75 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -328,6 +328,42 @@ nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync) } /* + * Decide whether a read/modify/write cycle may be more efficient + * then a modify/write/read cycle when writing to a page in the + * page cache. + * + * The modify/write/read cycle may occur if a page is read before + * being completely filled by the writer. In this situation, the + * page must be completely written to stable storage on the server + * before it can be refilled by reading in the page from the server. + * This can lead to expensive, small, FILE_SYNC mode writes being + * done. + * + * It may be more efficient to read the page first if the file is + * open for reading in addition to writing, the page is not marked + * as Uptodate, it is not dirty or waiting to be committed, + * indicating that it was previously allocated and then modified, + * that there were valid bytes of data in that range of the file, + * and that the new data won't completely replace the old data in + * that range of the file. + */ +static int nfs_want_read_modify_write(struct file *file, struct page *page, + loff_t pos, unsigned len) +{ + unsigned int pglen = nfs_page_length(page); + unsigned int offset = pos & (PAGE_CACHE_SIZE - 1); + unsigned int end = offset + len; + + if ((file->f_mode & FMODE_READ) && /* open for read? */ + !PageUptodate(page) && /* Uptodate? */ + !PagePrivate(page) && /* i/o request already? */ + pglen && /* valid bytes of file? */ + (end < pglen || offset)) /* replace all valid bytes? */ + return 1; + return 0; +} + +/* * This does the "real" work of the write. We must allocate and lock the * page to be sent back to the generic routine, which then copies the * data from user space. @@ -340,15 +376,16 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, struct page **pagep, void **fsdata) { int ret; - pgoff_t index; + pgoff_t index = pos >> PAGE_CACHE_SHIFT; struct page *page; - index = pos >> PAGE_CACHE_SHIFT; + int once_thru = 0; dfprintk(PAGECACHE, "NFS: write_begin(%s/%s(%ld), %u@%lld)\n", file->f_path.dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name, mapping->host->i_ino, len, (long long) pos); +start: /* * Prevent starvation issues if someone is doing a consistency * sync-to-disk @@ -367,6 +404,13 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, if (ret) { unlock_page(page); page_cache_release(page); + } else if (!once_thru && + nfs_want_read_modify_write(file, page, pos, len)) { + once_thru = 1; + ret = nfs_readpage(file, page); + page_cache_release(page); + if (!ret) + goto start; } return ret; } -- cgit v0.10.2 From e576e05a73bc1a00cdf56630942dbada1bf280a1 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Mon, 10 Aug 2009 08:54:16 -0400 Subject: nfs: remove superfluous BUG_ON()s Subject: [PATCH] nfs: remove superfluous BUG_ON()s Remove duplicated BUG_ON()s from nfs[4]_create_server() (we make the same checks earlier in both functions). This takes care of the following entries from Dan's list: fs/nfs/client.c +1078 nfs_create_server(47) warning: variable derefenced before check 'server->nfs_client' fs/nfs/client.c +1079 nfs_create_server(48) warning: variable derefenced before check 'server->nfs_client->rpc_ops' fs/nfs/client.c +1363 nfs4_create_server(43) warning: variable derefenced before check 'server->nfs_client' fs/nfs/client.c +1364 nfs4_create_server(44) warning: variable derefenced before check 'server->nfs_ Reported-by: Dan Carpenter Cc: corbet@lwn.net Cc: eteo@redhat.com Cc: Julia Lawall Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Trond Myklebust diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 8f34fd8..d36925f 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -1077,10 +1077,6 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, (unsigned long long) server->fsid.major, (unsigned long long) server->fsid.minor); - BUG_ON(!server->nfs_client); - BUG_ON(!server->nfs_client->rpc_ops); - BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); - spin_lock(&nfs_client_lock); list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); list_add_tail(&server->master_link, &nfs_volume_list); @@ -1362,10 +1358,6 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) server->namelen = NFS4_MAXNAMLEN; - BUG_ON(!server->nfs_client); - BUG_ON(!server->nfs_client->rpc_ops); - BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); - spin_lock(&nfs_client_lock); list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); list_add_tail(&server->master_link, &nfs_volume_list); -- cgit v0.10.2 From 9f8666971185b86615a074bcac67c90fdf8af8bc Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Mon, 10 Aug 2009 15:26:32 +0200 Subject: perf report: Add raw displaying of per-thread counters If --pretty=raw is given to perf report -T, it now displays one line per-thread per-counter with the raw event id added. We get: # PID TID Name Raw Count 18608 18609 cache-misses 28e 416744 18608 18609 cache-references 28f 6456792 18608 18608 cache-misses 28e 448219 18608 18608 cache-references 28f 7270244 instead of: # PID TID cache-misses cache-references 18608 18609 416744 6456792 18608 18608 448219 7270244 Signed-off-by: Brice Goglin Acked-by: Peter Zijlstra LKML-Reference: <4A802008.5050409@inria.fr> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 4163918..2357c66 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -57,6 +57,9 @@ static int show_nr_samples; static int show_threads; static struct perf_read_values show_threads_values; +static char default_pretty_printing_style[] = "normal"; +static char *pretty_printing_style = default_pretty_printing_style; + static unsigned long page_size; static unsigned long mmap_window = 32; @@ -1401,6 +1404,9 @@ static size_t output__fprintf(FILE *fp, u64 total_samples) size_t ret = 0; unsigned int width; char *col_width = col_width_list_str; + int raw_printing_style; + + raw_printing_style = !strcmp(pretty_printing_style, "raw"); init_rem_hits(); @@ -1478,7 +1484,8 @@ print_entries: free(rem_sq_bracket); if (show_threads) - perf_read_values_display(fp, &show_threads_values); + perf_read_values_display(fp, &show_threads_values, + raw_printing_style); return ret; } @@ -2091,6 +2098,8 @@ static const struct option options[] = { "Show a column with the number of samples"), OPT_BOOLEAN('T', "threads", &show_threads, "Show per-thread event counters"), + OPT_STRING(0, "pretty", &pretty_printing_style, "key", + "pretty printing style key: normal raw"), OPT_STRING('s', "sort", &sort_order, "key[,key2...]", "sort by key(s): pid, comm, dso, symbol, parent"), OPT_BOOLEAN('P', "full-paths", &full_paths, diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c index 8551c0b..614cfaf 100644 --- a/tools/perf/util/values.c +++ b/tools/perf/util/values.c @@ -126,7 +126,8 @@ void perf_read_values_add_value(struct perf_read_values *values, values->value[tindex][cindex] = value; } -void perf_read_values_display(FILE *fp, struct perf_read_values *values) +static void perf_read_values__display_pretty(FILE *fp, + struct perf_read_values *values) { int i, j; int pidwidth, tidwidth; @@ -169,3 +170,62 @@ void perf_read_values_display(FILE *fp, struct perf_read_values *values) fprintf(fp, "\n"); } } + +static void perf_read_values__display_raw(FILE *fp, + struct perf_read_values *values) +{ + int width, pidwidth, tidwidth, namewidth, rawwidth, countwidth; + int i, j; + + tidwidth = 3; /* TID */ + pidwidth = 3; /* PID */ + namewidth = 4; /* "Name" */ + rawwidth = 3; /* "Raw" */ + countwidth = 5; /* "Count" */ + + for (i = 0; i < values->threads; i++) { + width = snprintf(NULL, 0, "%d", values->pid[i]); + if (width > pidwidth) + pidwidth = width; + width = snprintf(NULL, 0, "%d", values->tid[i]); + if (width > tidwidth) + tidwidth = width; + } + for (j = 0; j < values->counters; j++) { + width = strlen(values->countername[j]); + if (width > namewidth) + namewidth = width; + width = snprintf(NULL, 0, "%llx", values->counterrawid[j]); + if (width > rawwidth) + rawwidth = width; + } + for (i = 0; i < values->threads; i++) { + for (j = 0; j < values->counters; j++) { + width = snprintf(NULL, 0, "%Lu", values->value[i][j]); + if (width > countwidth) + countwidth = width; + } + } + + fprintf(fp, "# %*s %*s %*s %*s %*s\n", + pidwidth, "PID", tidwidth, "TID", + namewidth, "Name", rawwidth, "Raw", + countwidth, "Count"); + for (i = 0; i < values->threads; i++) + for (j = 0; j < values->counters; j++) + fprintf(fp, " %*d %*d %*s %*llx %*Lu\n", + pidwidth, values->pid[i], + tidwidth, values->tid[i], + namewidth, values->countername[j], + rawwidth, values->counterrawid[j], + countwidth, values->value[i][j]); +} + +void perf_read_values_display(FILE *fp, struct perf_read_values *values, + int raw) +{ + if (raw) + perf_read_values__display_raw(fp, values); + else + perf_read_values__display_pretty(fp, values); +} diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h index e41be5e..f8960fd 100644 --- a/tools/perf/util/values.h +++ b/tools/perf/util/values.h @@ -21,6 +21,7 @@ void perf_read_values_add_value(struct perf_read_values *values, u32 pid, u32 tid, u64 rawid, char *name, u64 value); -void perf_read_values_display(FILE *fp, struct perf_read_values *values); +void perf_read_values_display(FILE *fp, struct perf_read_values *values, + int raw); #endif /* _PERF_VALUES_H */ -- cgit v0.10.2 From 6c8194922739138f046a4d0924519dd43b48e1f3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Aug 2009 18:47:44 +0200 Subject: ALSA: hda - Add auto-mic support for Realtek codecs Added the support for automatic mic selection via plugging for Realtek codecs (in auto-probing mode). The auto-mic mode is enabled only when one internal mic and one external mic are present. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b0d30fc..678c2d7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -258,6 +258,14 @@ enum { ALC_INIT_GPIO3, }; +struct alc_mic_route { + hda_nid_t pin; + unsigned char mux_idx; + unsigned char amix_idx; +}; + +#define MUX_IDX_UNDEF ((unsigned char)-1) + struct alc_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ @@ -300,6 +308,8 @@ struct alc_spec { unsigned int num_mux_defs; const struct hda_input_mux *input_mux; unsigned int cur_mux[3]; + struct alc_mic_route ext_mic; + struct alc_mic_route int_mic; /* channel model */ const struct hda_channel_mode *channel_mode; @@ -327,6 +337,7 @@ struct alc_spec { unsigned int sense_updated: 1; unsigned int jack_present: 1; unsigned int master_sw: 1; + unsigned int auto_mic:1; /* other flags */ unsigned int no_analog :1; /* digital I/O only */ @@ -963,30 +974,79 @@ static void alc_automute_pin(struct hda_codec *codec) } } -#if 0 /* it's broken in some cases -- temporarily disabled */ +static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t nid) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int i, nums; + + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + for (i = 0; i < nums; i++) + if (conn[i] == nid) + return i; + return -1; +} + +static int set_mic_mux_idx(struct hda_codec *codec, hda_nid_t cap, + struct alc_mic_route *mic) +{ + int idx = get_connection_index(codec, cap, mic->pin); + if (idx < 0) + return 1; /* invalid */ + mic->mux_idx = idx; + return 0; +} + static void alc_mic_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int present; - unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; - unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; - unsigned int mix_nid = spec->capsrc_nids[0]; - unsigned int capsrc_idx_mic, capsrc_idx_fmic; - - capsrc_idx_mic = mic_nid - 0x18; - capsrc_idx_fmic = fmic_nid - 0x18; - present = snd_hda_codec_read(codec, mic_nid, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80)); - snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0)); - snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + struct alc_mic_route *dead, *alive; + unsigned int present, type; + hda_nid_t cap_nid; + + if (!spec->int_mic.pin || !spec->ext_mic.pin) + return; + if (snd_BUG_ON(!spec->adc_nids)) + return; + + cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; + + present = snd_hda_codec_read(codec, spec->ext_mic.pin, 0, + AC_VERB_GET_PIN_SENSE, 0); + present &= AC_PINSENSE_PRESENCE; + if (present) { + alive = &spec->ext_mic; + dead = &spec->int_mic; + } else { + alive = &spec->int_mic; + dead = &spec->ext_mic; + } + + if (alive->mux_idx == MUX_IDX_UNDEF && + set_mic_mux_idx(codec, cap_nid, alive)) + return; + if (dead->mux_idx == MUX_IDX_UNDEF && + set_mic_mux_idx(codec, cap_nid, dead)) + return; + + type = get_wcaps_type(get_wcaps(codec, cap_nid)); + if (type == AC_WID_AUD_MIX) { + /* Matrix-mixer style (e.g. ALC882) */ + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + alive->mux_idx, + HDA_AMP_MUTE, 0); + snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT, + dead->mux_idx, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* MUX style (e.g. ALC880) */ + snd_hda_codec_write_cache(codec, cap_nid, 0, + AC_VERB_SET_CONNECT_SEL, + alive->mux_idx); + } + + /* FIXME: analog mixer */ } -#else -#define alc_mic_automute(codec) do {} while(0) /* NOP */ -#endif /* disabled */ /* unsolicited event for HP jack sensing */ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) @@ -1142,6 +1202,55 @@ static void alc_init_auto_hp(struct hda_codec *codec) spec->unsol_event = alc_sku_unsol_event; } +static void alc_init_auto_mic(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t fixed, ext; + int i; + + /* there must be only two mic inputs exclusively */ + for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) + if (cfg->input_pins[i]) + return; + + fixed = ext = 0; + for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) { + hda_nid_t nid = cfg->input_pins[i]; + unsigned int defcfg; + if (!nid) + return; + defcfg = snd_hda_codec_get_pincfg(codec, nid); + switch (get_defcfg_connect(defcfg)) { + case AC_JACK_PORT_FIXED: + if (fixed) + return; /* already occupied */ + fixed = nid; + break; + case AC_JACK_PORT_COMPLEX: + if (ext) + return; /* already occupied */ + ext = nid; + break; + default: + return; /* invalid entry */ + } + } + if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP)) + return; /* no unsol support */ + snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n", + ext, fixed); + spec->ext_mic.pin = ext; + spec->int_mic.pin = fixed; + spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ + spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */ + spec->auto_mic = 1; + snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_MIC_EVENT); + spec->unsol_event = alc_sku_unsol_event; +} + /* check subsystem ID and set up device-specific initialization; * return 1 if initialized, 0 if invalid SSID */ @@ -1243,6 +1352,7 @@ do_sku: } alc_init_auto_hp(codec); + alc_init_auto_mic(codec); return 1; } @@ -1255,6 +1365,7 @@ static void alc_ssid_check(struct hda_codec *codec, "Enable default setup for auto mode as fallback\n"); spec->init_amp = ALC_INIT_DEFAULT; alc_init_auto_hp(codec); + alc_init_auto_mic(codec); } } @@ -4572,7 +4683,8 @@ static void set_capture_mixer(struct alc_spec *spec) }; if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { int mux; - if (spec->input_mux && spec->input_mux->num_items > 1) + if (spec->input_mux && spec->input_mux->num_items > 1 && + !spec->auto_mic) mux = 1; else mux = 0; @@ -17118,25 +17230,6 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, return 0; } -/* return the index of the src widget from the connection list of the nid. - * return -1 if not found - */ -static int alc662_input_pin_idx(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t src) -{ - hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; - int i, conns; - - conns = snd_hda_get_connections(codec, nid, conn_list, - ARRAY_SIZE(conn_list)); - if (conns < 0) - return -1; - for (i = 0; i < conns; i++) - if (conn_list[i] == src) - return i; - return -1; -} - static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid) { unsigned int pincap = snd_hda_query_pin_caps(codec, nid); @@ -17153,7 +17246,7 @@ static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec, for (i = 0; i < AUTO_PIN_LAST; i++) { if (alc662_is_input_pin(codec, cfg->input_pins[i])) { - idx = alc662_input_pin_idx(codec, 0x0b, + idx = get_connection_index(codec, 0x0b, cfg->input_pins[i]); if (idx >= 0) { err = new_analog_input(spec, cfg->input_pins[i], @@ -17162,7 +17255,7 @@ static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec, if (err < 0) return err; } - idx = alc662_input_pin_idx(codec, 0x22, + idx = get_connection_index(codec, 0x22, cfg->input_pins[i]); if (idx >= 0) { imux->items[imux->num_items].label = -- cgit v0.10.2 From 2a22d3f81283253ab9dae9244f3ca58a5ac66b36 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Aug 2009 18:54:38 +0200 Subject: ALSA: hda - Use only one capture stream for auto-mic When the auto-mic feature is enabled, we should support only one capture stream. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 678c2d7..7ecf929 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4683,8 +4683,10 @@ static void set_capture_mixer(struct alc_spec *spec) }; if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { int mux; - if (spec->input_mux && spec->input_mux->num_items > 1 && - !spec->auto_mic) + if (spec->auto_mic) { + mux = 0; + spec->num_adc_nids = 1; /* support only one ADC */ + } else if (spec->input_mux && spec->input_mux->num_items > 1) mux = 1; else mux = 0; -- cgit v0.10.2 From f1e6d3c5cf86675e54a17a89668aa6685d2ef59d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 11 Aug 2009 08:15:04 +0200 Subject: ALSA: usb-audio - Fix types taken in min() Fix the compile warning due to different integer types used in min(): sound/usb/usbaudio.c: In function 'init_substream_urbs': sound/usb/usbaudio.c:1087: warning: comparison of distinct pointer types lacks a cast Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index fa3f7a1..5149c58 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1084,7 +1084,7 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri urb_packs = 1; urb_packs *= packs_per_ms; if (subs->syncpipe) - urb_packs = min(urb_packs, 1 << subs->syncinterval); + urb_packs = min(urb_packs, 1U << subs->syncinterval); /* decide how many packets to be used */ if (is_playback) { -- cgit v0.10.2 From b59bdf3b0ca11bfc6a539012431d751deaa65b32 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 11 Aug 2009 09:47:30 +0200 Subject: ALSA: hda - Check connectivity for auto-mic of Realtek codecs Some Realtek codecs don't provide the full connections for certain pins from each ADC; e.g. ACL662/ALC272 gives only one of two digital-mic pins for each ADC. Thus, depending on the digital mic pin, the ADC/MUX to be used has to be chosen properly. This patch adds the check of the connectivity of pins at auto-mic mode. If no proper connectivity is found, auto_mic flag is turned off to be sure. Also the mux_idx is determined during this check so it won't be checked in the unsol event any more. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2c348e1..5156c4f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -987,16 +987,6 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, return -1; } -static int set_mic_mux_idx(struct hda_codec *codec, hda_nid_t cap, - struct alc_mic_route *mic) -{ - int idx = get_connection_index(codec, cap, mic->pin); - if (idx < 0) - return 1; /* invalid */ - mic->mux_idx = idx; - return 0; -} - static void alc_mic_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1004,6 +994,8 @@ static void alc_mic_automute(struct hda_codec *codec) unsigned int present, type; hda_nid_t cap_nid; + if (!spec->auto_mic) + return; if (!spec->int_mic.pin || !spec->ext_mic.pin) return; if (snd_BUG_ON(!spec->adc_nids)) @@ -1022,13 +1014,6 @@ static void alc_mic_automute(struct hda_codec *codec) dead = &spec->ext_mic; } - if (alive->mux_idx == MUX_IDX_UNDEF && - set_mic_mux_idx(codec, cap_nid, alive)) - return; - if (dead->mux_idx == MUX_IDX_UNDEF && - set_mic_mux_idx(codec, cap_nid, dead)) - return; - type = get_wcaps_type(get_wcaps(codec, cap_nid)); if (type == AC_WID_AUD_MIX) { /* Matrix-mixer style (e.g. ALC882) */ @@ -4671,8 +4656,42 @@ static void alc880_auto_init(struct hda_codec *codec) alc_inithook(codec); } -static void set_capture_mixer(struct alc_spec *spec) +/* check the ADC/MUX contains all input pins; some ADC/MUX contains only + * one of two digital mic pins, e.g. on ALC272 + */ +static void fixup_automic_adc(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_adc_nids; i++) { + hda_nid_t cap = spec->capsrc_nids ? + spec->capsrc_nids[i] : spec->adc_nids[i]; + int iidx, eidx; + + iidx = get_connection_index(codec, cap, spec->int_mic.pin); + if (iidx < 0) + continue; + eidx = get_connection_index(codec, cap, spec->ext_mic.pin); + if (eidx < 0) + continue; + spec->int_mic.mux_idx = iidx; + spec->ext_mic.mux_idx = eidx; + if (spec->capsrc_nids) + spec->capsrc_nids += i; + spec->adc_nids += i; + spec->num_adc_nids = 1; + return; + } + snd_printd(KERN_INFO "hda_codec: %s: " + "No ADC/MUX containing both 0x%x and 0x%x pins\n", + codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin); + spec->auto_mic = 0; /* disable auto-mic to be sure */ +} + +static void set_capture_mixer(struct hda_codec *codec) { + struct alc_spec *spec = codec->spec; static struct snd_kcontrol_new *caps[2][3] = { { alc_capture_mixer_nosrc1, alc_capture_mixer_nosrc2, @@ -4685,7 +4704,7 @@ static void set_capture_mixer(struct alc_spec *spec) int mux; if (spec->auto_mic) { mux = 0; - spec->num_adc_nids = 1; /* support only one ADC */ + fixup_automic_adc(codec); } else if (spec->input_mux && spec->input_mux->num_items > 1) mux = 1; else @@ -4765,7 +4784,7 @@ static int patch_alc880(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); } } - set_capture_mixer(spec); + set_capture_mixer(codec); set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; @@ -6408,7 +6427,7 @@ static int patch_alc260(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); } } - set_capture_mixer(spec); + set_capture_mixer(codec); set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); spec->vmaster_nid = 0x08; @@ -9737,7 +9756,7 @@ static int patch_alc882(struct hda_codec *codec) spec->capsrc_nids = spec->private_capsrc_nids; } - set_capture_mixer(spec); + set_capture_mixer(codec); set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; @@ -11616,7 +11635,7 @@ static int patch_alc262(struct hda_codec *codec) } } if (!spec->cap_mixer && !spec->no_analog) - set_capture_mixer(spec); + set_capture_mixer(codec); if (!spec->no_analog) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); @@ -13285,7 +13304,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) return err; if (!spec->cap_mixer && !spec->no_analog) - set_capture_mixer(spec); + set_capture_mixer(codec); alc_ssid_check(codec, 0x15, 0x1b, 0x14); @@ -13483,7 +13502,7 @@ static int patch_alc269(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); spec->capsrc_nids = alc269_capsrc_nids; if (!spec->cap_mixer) - set_capture_mixer(spec); + set_capture_mixer(codec); set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); spec->vmaster_nid = 0x02; @@ -14398,7 +14417,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->adc_nids = alc861_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); - set_capture_mixer(spec); + set_capture_mixer(codec); alc_ssid_check(codec, 0x0e, 0x0f, 0x0b); @@ -15561,7 +15580,7 @@ static int patch_alc861vd(struct hda_codec *codec) if (!spec->capsrc_nids) spec->capsrc_nids = alc861vd_capsrc_nids; - set_capture_mixer(spec); + set_capture_mixer(codec); set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x02; @@ -15602,9 +15621,9 @@ static hda_nid_t alc272_dac_nids[2] = { 0x02, 0x03 }; -static hda_nid_t alc662_adc_nids[1] = { +static hda_nid_t alc662_adc_nids[2] = { /* ADC1-2 */ - 0x09, + 0x09, 0x08 }; static hda_nid_t alc272_adc_nids[1] = { @@ -15612,7 +15631,7 @@ static hda_nid_t alc272_adc_nids[1] = { 0x08, }; -static hda_nid_t alc662_capsrc_nids[1] = { 0x22 }; +static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 }; static hda_nid_t alc272_capsrc_nids[1] = { 0x23 }; @@ -17099,7 +17118,7 @@ static struct alc_config_preset alc662_presets[] = { .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .adc_nids = alc662_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc662_adc_nids), + .num_adc_nids = 1, .capsrc_nids = alc662_capsrc_nids, .channel_mode = alc662_3ST_2ch_modes, .input_mux = &alc663_m51va_capture_source, @@ -17465,7 +17484,7 @@ static int patch_alc662(struct hda_codec *codec) spec->capsrc_nids = alc662_capsrc_nids; if (!spec->cap_mixer) - set_capture_mixer(spec); + set_capture_mixer(codec); if (codec->vendor_id == 0x10ec0662) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); else -- cgit v0.10.2 From 17244c24f95ba61a12b6afeab5780a1e3f1a4c57 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 10 Aug 2009 16:04:39 -0700 Subject: ASoC: fix I2C build errors Fix soc build errors when I2C is built as a loadable module: (.text+0x5d26b): undefined reference to `i2c_master_send' soc-cache.c:(.text+0x5d32d): undefined reference to `i2c_transfer' Signed-off-by: Randy Dunlap Signed-off-by: Mark Brown diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 56ec3f2..c8ceddc 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -108,7 +108,7 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, return cache[reg]; } -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, unsigned int r) { @@ -200,7 +200,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, break; case SND_SOC_I2C: -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) codec->hw_write = (hw_write_t)i2c_master_send; #endif if (io_types[i].i2c_read) -- cgit v0.10.2 From 4d8e22e0f6aacb365db2cb9bf69e38310b37f418 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 11 Aug 2009 14:21:26 +0200 Subject: ALSA: hda - Add a white-list for MSI option Created a white-list to enable MSI since some devices require MSI explicitly due to BIOS/ACPI problems. Simply using a quirk list. As the first case, take HP Compaq CQ40. Reference: Novell bnc#529971 https://bugzilla.novell.com/show_bug.cgi?id=529971 Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 754de4f..20a66f8 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2299,6 +2299,30 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) } } +/* + * white-list for enable_msi + */ +static struct snd_pci_quirk msi_white_list[] __devinitdata = { + SND_PCI_QUIRK(0x103c, 0x3607, "HP Compa CQ40", 1), + {} +}; + +static void __devinit check_msi(struct azx *chip) +{ + const struct snd_pci_quirk *q; + + chip->msi = enable_msi; + if (chip->msi) + return; + q = snd_pci_quirk_lookup(chip->pci, msi_white_list); + if (q) { + printk(KERN_INFO + "hda_intel: msi for device %04x:%04x set to %d\n", + q->subvendor, q->subdevice, q->value); + chip->msi = q->value; + } +} + /* * constructor @@ -2333,7 +2357,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->pci = pci; chip->irq = -1; chip->driver_type = driver_type; - chip->msi = enable_msi; + check_msi(chip); chip->dev_index = dev; INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); -- cgit v0.10.2 From e9c364c04f59f7fb250f9689198eaa59872cf8af Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 11 Aug 2009 17:16:13 +0200 Subject: ALSA: hda - Add setup hook to ALC preset struct Added setup hook to ALC preset struct to be called at in the parser but not at each init callback. This can be used for setting up the static pins, etc, while the init hook should be used for updating the status again. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5156c4f..b2e097b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -379,6 +379,7 @@ struct alc_config_preset { unsigned int num_mux_defs; const struct hda_input_mux *input_mux; void (*unsol_event)(struct hda_codec *, unsigned int); + void (*setup)(struct hda_codec *); void (*init_hook)(struct hda_codec *); #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_amp_list *loopbacks; @@ -851,9 +852,10 @@ static void print_realtek_coef(struct snd_info_buffer *buffer, /* * set up from the preset table */ -static void setup_preset(struct alc_spec *spec, +static void setup_preset(struct hda_codec *codec, const struct alc_config_preset *preset) { + struct alc_spec *spec = codec->spec; int i; for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) @@ -895,6 +897,9 @@ static void setup_preset(struct alc_spec *spec, #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = preset->loopbacks; #endif + + if (preset->setup) + preset->setup(codec); } /* Enable GPIO mask and set output */ @@ -4762,7 +4767,7 @@ static int patch_alc880(struct hda_codec *codec) } if (board_config != ALC880_AUTO) - setup_preset(spec, &alc880_presets[board_config]); + setup_preset(codec, &alc880_presets[board_config]); spec->stream_analog_playback = &alc880_pcm_analog_playback; spec->stream_analog_capture = &alc880_pcm_analog_capture; @@ -6406,7 +6411,7 @@ static int patch_alc260(struct hda_codec *codec) } if (board_config != ALC260_AUTO) - setup_preset(spec, &alc260_presets[board_config]); + setup_preset(codec, &alc260_presets[board_config]); spec->stream_analog_playback = &alc260_pcm_analog_playback; spec->stream_analog_capture = &alc260_pcm_analog_capture; @@ -9720,7 +9725,7 @@ static int patch_alc882(struct hda_codec *codec) } if (board_config != ALC882_AUTO) - setup_preset(spec, &alc882_presets[board_config]); + setup_preset(codec, &alc882_presets[board_config]); spec->stream_analog_playback = &alc882_pcm_analog_playback; spec->stream_analog_capture = &alc882_pcm_analog_capture; @@ -11594,7 +11599,7 @@ static int patch_alc262(struct hda_codec *codec) } if (board_config != ALC262_AUTO) - setup_preset(spec, &alc262_presets[board_config]); + setup_preset(codec, &alc262_presets[board_config]); spec->stream_analog_playback = &alc262_pcm_analog_playback; spec->stream_analog_capture = &alc262_pcm_analog_capture; @@ -12659,7 +12664,7 @@ static int patch_alc268(struct hda_codec *codec) } if (board_config != ALC268_AUTO) - setup_preset(spec, &alc268_presets[board_config]); + setup_preset(codec, &alc268_presets[board_config]); spec->stream_analog_playback = &alc268_pcm_analog_playback; spec->stream_analog_capture = &alc268_pcm_analog_capture; @@ -13483,7 +13488,7 @@ static int patch_alc269(struct hda_codec *codec) } if (board_config != ALC269_AUTO) - setup_preset(spec, &alc269_presets[board_config]); + setup_preset(codec, &alc269_presets[board_config]); if (codec->subsystem_id == 0x17aa3bf8) { /* Due to a hardware problem on Lenovo Ideadpad, we need to @@ -14636,7 +14641,7 @@ static int patch_alc861(struct hda_codec *codec) } if (board_config != ALC861_AUTO) - setup_preset(spec, &alc861_presets[board_config]); + setup_preset(codec, &alc861_presets[board_config]); spec->stream_analog_playback = &alc861_pcm_analog_playback; spec->stream_analog_capture = &alc861_pcm_analog_capture; @@ -15560,7 +15565,7 @@ static int patch_alc861vd(struct hda_codec *codec) } if (board_config != ALC861VD_AUTO) - setup_preset(spec, &alc861vd_presets[board_config]); + setup_preset(codec, &alc861vd_presets[board_config]); if (codec->vendor_id == 0x10ec0660) { /* always turn on EAPD */ @@ -17468,7 +17473,7 @@ static int patch_alc662(struct hda_codec *codec) } if (board_config != ALC662_AUTO) - setup_preset(spec, &alc662_presets[board_config]); + setup_preset(codec, &alc662_presets[board_config]); spec->stream_analog_playback = &alc662_pcm_analog_playback; spec->stream_analog_capture = &alc662_pcm_analog_capture; -- cgit v0.10.2 From e0026beac0f1a6253488478b3f022ff243b012b9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 11 Aug 2009 16:28:39 +0100 Subject: ASoC: Update WM9081 for tdm_slot() API change Store the TDM slot width then if it's set use that rather than the sample size to calculate BCLK. Leave imposing constraints to the core (which should do this but doesn't yet) or machine driver. Also allow 0 TDM slots to be configure (for use when disabling TDM). Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index c147f2b..c64e55a 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -165,6 +165,7 @@ struct wm9081_priv { int master; int fll_fref; int fll_fout; + int tdm_width; struct wm9081_retune_mobile_config *retune; }; @@ -981,33 +982,37 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream, aif4 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_4); aif4 &= ~WM9081_LRCLK_RATE_MASK; - /* What BCLK do we need? */ wm9081->fs = params_rate(params); - wm9081->bclk = 2 * wm9081->fs; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - wm9081->bclk *= 16; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - wm9081->bclk *= 20; - aif2 |= 0x4; - break; - case SNDRV_PCM_FORMAT_S24_LE: - wm9081->bclk *= 24; - aif2 |= 0x8; - break; - case SNDRV_PCM_FORMAT_S32_LE: - wm9081->bclk *= 32; - aif2 |= 0xc; - break; - default: - return -EINVAL; - } - if (aif1 & WM9081_AIFDAC_TDM_MODE_MASK) { + if (wm9081->tdm_width) { + /* If TDM is set up then that fixes our BCLK. */ int slots = ((aif1 & WM9081_AIFDAC_TDM_MODE_MASK) >> WM9081_AIFDAC_TDM_MODE_SHIFT) + 1; - wm9081->bclk *= slots; + + wm9081->bclk = wm9081->fs * wm9081->tdm_width * slots; + } else { + /* Otherwise work out a BCLK from the sample size */ + wm9081->bclk = 2 * wm9081->fs; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + wm9081->bclk *= 16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + wm9081->bclk *= 20; + aif2 |= 0x4; + break; + case SNDRV_PCM_FORMAT_S24_LE: + wm9081->bclk *= 24; + aif2 |= 0x8; + break; + case SNDRV_PCM_FORMAT_S32_LE: + wm9081->bclk *= 32; + aif2 |= 0xc; + break; + default: + return -EINVAL; + } } dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm9081->bclk); @@ -1149,18 +1154,23 @@ static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai, return 0; } -/* FIXME: Needs to handle slot_width */ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct snd_soc_codec *codec = dai->codec; + struct wm9081_priv *wm9081 = codec->private_data; unsigned int aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1); aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK); - if (slots < 1 || slots > 4) + if (slots < 0 || slots > 4) return -EINVAL; + wm9081->tdm_width = slot_width; + + if (slots == 0) + slots = 1; + aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT; switch (rx_mask) { -- cgit v0.10.2 From 4f5d17062085ee1c74ff44a37ffb09f94ab4db1c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 11 Aug 2009 18:17:46 +0200 Subject: ALSA: hda - Clean up init and setup hooks for Realtek codecs Move static codes to setup from init_hook for each model. Also, use the common auto-mic selection helper for devices that support auto-mic selection. They just need to set up ext_mic, int_mic and auto_mic flag in the setup section. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b2e097b..ac3207e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1537,7 +1537,7 @@ static void alc_automute_amp_unsol_event(struct hda_codec *codec, alc_automute_amp(codec); } -static void alc889_automute_init(struct hda_codec *codec) +static void alc889_automute_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1547,16 +1547,15 @@ static void alc889_automute_init(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x17; spec->autocfg.speaker_pins[3] = 0x19; spec->autocfg.speaker_pins[4] = 0x1a; - alc_automute_amp(codec); } static void alc889_intel_init_hook(struct hda_codec *codec) { alc889_coef_init(codec); - alc889_automute_init(codec); + alc_automute_amp(codec); } -static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec) +static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1564,7 +1563,6 @@ static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec) spec->autocfg.hp_pins[1] = 0x1b; /* hp */ spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ spec->autocfg.speaker_pins[1] = 0x15; /* bass */ - alc_automute_amp(codec); } /* @@ -1763,16 +1761,15 @@ static struct snd_kcontrol_new alc888_base_mixer[] = { { } /* end */ }; -static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec) +static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); } -static void alc888_acer_aspire_6530g_init_hook(struct hda_codec *codec) +static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1780,10 +1777,9 @@ static void alc888_acer_aspire_6530g_init_hook(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x17; - alc_automute_amp(codec); } -static void alc889_acer_aspire_8930g_init_hook(struct hda_codec *codec) +static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1791,7 +1787,6 @@ static void alc889_acer_aspire_8930g_init_hook(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x1b; - alc_automute_amp(codec); } /* @@ -2771,13 +2766,17 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec) snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); } -static void alc880_uniwill_init_hook(struct hda_codec *codec) +static void alc880_uniwill_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x16; +} + +static void alc880_uniwill_init_hook(struct hda_codec *codec) +{ alc_automute_amp(codec); alc880_uniwill_mic_automute(codec); } @@ -2798,13 +2797,12 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec, } } -static void alc880_uniwill_p53_init_hook(struct hda_codec *codec) +static void alc880_uniwill_p53_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -3067,13 +3065,12 @@ static struct hda_verb alc880_lg_init_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_init_hook(struct hda_codec *codec) +static void alc880_lg_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x17; - alc_automute_amp(codec); } /* @@ -3152,13 +3149,12 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_lw_init_hook(struct hda_codec *codec) +static void alc880_lg_lw_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); } static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { @@ -3224,13 +3220,12 @@ static void alc880_medion_rim_unsol_event(struct hda_codec *codec, alc880_medion_rim_automute(codec); } -static void alc880_medion_rim_init_hook(struct hda_codec *codec) +static void alc880_medion_rim_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; - alc880_medion_rim_automute(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -4097,7 +4092,8 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_f1734_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_init_hook, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_automute_amp, }, [ALC880_ASUS] = { .mixers = { alc880_asus_mixer }, @@ -4174,6 +4170,7 @@ static struct alc_config_preset alc880_presets[] = { .need_dac_fix = 1, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_unsol_event, + .setup = alc880_uniwill_setup, .init_hook = alc880_uniwill_init_hook, }, [ALC880_UNIWILL_P53] = { @@ -4186,7 +4183,8 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_threestack_modes, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_init_hook, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_automute_amp, }, [ALC880_FUJITSU] = { .mixers = { alc880_fujitsu_mixer }, @@ -4200,7 +4198,8 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_init_hook, + .setup = alc880_uniwill_p53_setup, + .init_hook = alc_automute_amp, }, [ALC880_CLEVO] = { .mixers = { alc880_three_stack_mixer }, @@ -4226,7 +4225,8 @@ static struct alc_config_preset alc880_presets[] = { .need_dac_fix = 1, .input_mux = &alc880_lg_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc880_lg_init_hook, + .setup = alc880_lg_setup, + .init_hook = alc_automute_amp, #ifdef CONFIG_SND_HDA_POWER_SAVE .loopbacks = alc880_lg_loopbacks, #endif @@ -4242,7 +4242,8 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_lg_lw_modes, .input_mux = &alc880_lg_lw_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc880_lg_lw_init_hook, + .setup = alc880_lg_lw_setup, + .init_hook = alc_automute_amp, }, [ALC880_MEDION_RIM] = { .mixers = { alc880_medion_rim_mixer }, @@ -4256,7 +4257,8 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_medion_rim_capture_source, .unsol_event = alc880_medion_rim_unsol_event, - .init_hook = alc880_medion_rim_init_hook, + .setup = alc880_medion_rim_setup, + .init_hook = alc880_medion_rim_automute, }, #ifdef CONFIG_SND_DEBUG [ALC880_TEST] = { @@ -7451,23 +7453,21 @@ static struct hda_verb alc885_imac24_init_verbs[] = { }; /* Toggle speaker-output according to the hp-jack state */ -static void alc885_imac24_automute_init_hook(struct hda_codec *codec) +static void alc885_imac24_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x18; spec->autocfg.speaker_pins[1] = 0x1a; - alc_automute_amp(codec); } -static void alc885_mbp3_init_hook(struct hda_codec *codec) +static void alc885_mbp3_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); } @@ -7495,13 +7495,12 @@ static void alc882_targa_automute(struct hda_codec *codec) spec->jack_present ? 1 : 3); } -static void alc882_targa_init_hook(struct hda_codec *codec) +static void alc882_targa_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; - alc882_targa_automute(codec); } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) @@ -7589,7 +7588,7 @@ static void alc885_macpro_init_hook(struct hda_codec *codec) static void alc885_imac24_init_hook(struct hda_codec *codec) { alc885_macpro_init_hook(codec); - alc885_imac24_automute_init_hook(codec); + alc_automute_amp(codec); } /* @@ -8079,14 +8078,13 @@ static struct snd_kcontrol_new alc883_chmode_mixer[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc883_mitac_init_hook(struct hda_codec *codec) +static void alc883_mitac_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x17; - alc_automute_amp(codec); } /* auto-toggle front mic */ @@ -8241,7 +8239,7 @@ static struct hda_verb alc883_vaiott_verbs[] = { { } /* end */ }; -static void alc888_3st_hp_init_hook(struct hda_codec *codec) +static void alc888_3st_hp_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -8249,7 +8247,6 @@ static void alc888_3st_hp_init_hook(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x16; spec->autocfg.speaker_pins[2] = 0x18; - alc_automute_amp(codec); } static struct hda_verb alc888_3st_hp_verbs[] = { @@ -8346,13 +8343,12 @@ static struct hda_verb alc883_medion_md2_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc883_medion_md2_init_hook(struct hda_codec *codec) +static void alc883_medion_md2_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); } /* toggle speaker-output according to the hp-jack state */ @@ -8369,12 +8365,16 @@ static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } -static void alc883_clevo_m720_init_hook(struct hda_codec *codec) +static void alc883_clevo_m720_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; +} + +static void alc883_clevo_m720_init_hook(struct hda_codec *codec) +{ alc_automute_amp(codec); alc883_clevo_m720_mic_automute(codec); } @@ -8393,22 +8393,20 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, } /* toggle speaker-output according to the hp-jack state */ -static void alc883_2ch_fujitsu_pi2515_init_hook(struct hda_codec *codec) +static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); } -static void alc883_haier_w66_init_hook(struct hda_codec *codec) +static void alc883_haier_w66_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); } static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) @@ -8447,14 +8445,13 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, } /* toggle speaker-output according to the hp-jack state */ -static void alc883_acer_aspire_init_hook(struct hda_codec *codec) +static void alc883_acer_aspire_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x15; spec->autocfg.speaker_pins[1] = 0x16; - alc_automute_amp(codec); } static struct hda_verb alc883_acer_eapd_verbs[] = { @@ -8475,7 +8472,7 @@ static struct hda_verb alc883_acer_eapd_verbs[] = { { } }; -static void alc888_6st_dell_init_hook(struct hda_codec *codec) +static void alc888_6st_dell_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -8484,10 +8481,9 @@ static void alc888_6st_dell_init_hook(struct hda_codec *codec) spec->autocfg.speaker_pins[1] = 0x15; spec->autocfg.speaker_pins[2] = 0x16; spec->autocfg.speaker_pins[3] = 0x17; - alc_automute_amp(codec); } -static void alc888_lenovo_sky_init_hook(struct hda_codec *codec) +static void alc888_lenovo_sky_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -8497,17 +8493,15 @@ static void alc888_lenovo_sky_init_hook(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x16; spec->autocfg.speaker_pins[3] = 0x17; spec->autocfg.speaker_pins[4] = 0x1a; - alc_automute_amp(codec); } -static void alc883_vaiott_init_hook(struct hda_codec *codec) +static void alc883_vaiott_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x17; - alc_automute_amp(codec); } static struct hda_verb alc888_asus_m90v_verbs[] = { @@ -8520,19 +8514,7 @@ static struct hda_verb alc888_asus_m90v_verbs[] = { { } /* end */ }; -static void alc883_nb_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); - snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); -} - -static void alc883_M90V_init_hook(struct hda_codec *codec) +static void alc883_mode2_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -8540,26 +8522,11 @@ static void alc883_M90V_init_hook(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x15; spec->autocfg.speaker_pins[2] = 0x16; - alc_automute_pin(codec); -} - -static void alc883_mode2_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_MIC_EVENT: - alc883_nb_mic_automute(codec); - break; - default: - alc_sku_unsol_event(codec, res); - break; - } -} - -static void alc883_mode2_inithook(struct hda_codec *codec) -{ - alc883_M90V_init_hook(codec); - alc883_nb_mic_automute(codec); + spec->ext_mic.pin = 0x18; + spec->int_mic.pin = 0x19; + spec->ext_mic.mux_idx = 0; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } static struct hda_verb alc888_asus_eee1601_verbs[] = { @@ -8890,7 +8857,8 @@ static struct alc_config_preset alc882_presets[] = { .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, + .setup = alc885_mbp3_setup, + .init_hook = alc_automute_amp, }, [ALC885_MB5] = { .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, @@ -8927,6 +8895,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, .unsol_event = alc_automute_amp_unsol_event, + .setup = alc885_imac24_setup, .init_hook = alc885_imac24_init_hook, }, [ALC882_TARGA] = { @@ -8944,7 +8913,8 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc882_capture_source, .unsol_event = alc882_targa_unsol_event, - .init_hook = alc882_targa_init_hook, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, }, [ALC882_ASUS_A7J] = { .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, @@ -9035,7 +9005,8 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc889_8ch_intel_modes, .capsrc_nids = alc889_capsrc_nids, .input_mux = &alc889_capture_source, - .init_hook = alc889_automute_init, + .setup = alc889_automute_setup, + .init_hook = alc_automute_amp, .unsol_event = alc_automute_amp_unsol_event, .need_dac_fix = 1, }, @@ -9054,6 +9025,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc889_8ch_intel_modes, .capsrc_nids = alc889_capsrc_nids, .input_mux = &alc889_capture_source, + .setup = alc889_automute_setup, .init_hook = alc889_intel_init_hook, .unsol_event = alc_automute_amp_unsol_event, .need_dac_fix = 1, @@ -9081,7 +9053,8 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_capture_source, .unsol_event = alc883_targa_unsol_event, - .init_hook = alc883_targa_init_hook, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, }, [ALC883_TARGA_2ch_DIG] = { .mixers = { alc883_targa_2ch_mixer}, @@ -9096,7 +9069,8 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc883_targa_unsol_event, - .init_hook = alc883_targa_init_hook, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, }, [ALC883_TARGA_8ch_DIG] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, @@ -9114,7 +9088,8 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_capture_source, .unsol_event = alc883_targa_unsol_event, - .init_hook = alc883_targa_init_hook, + .setup = alc882_targa_setup, + .init_hook = alc882_targa_automute, }, [ALC883_ACER] = { .mixers = { alc883_base_mixer }, @@ -9140,7 +9115,8 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_acer_aspire_init_hook, + .setup = alc883_acer_aspire_setup, + .init_hook = alc_automute_amp, }, [ALC888_ACER_ASPIRE_4930G] = { .mixers = { alc888_base_mixer, @@ -9160,7 +9136,8 @@ static struct alc_config_preset alc882_presets[] = { ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_acer_aspire_4930g_init_hook, + .setup = alc888_acer_aspire_4930g_setup, + .init_hook = alc_automute_amp, }, [ALC888_ACER_ASPIRE_6530G] = { .mixers = { alc888_acer_aspire_6530_mixer }, @@ -9178,7 +9155,8 @@ static struct alc_config_preset alc882_presets[] = { ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_acer_aspire_6530_sources, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_acer_aspire_6530g_init_hook, + .setup = alc888_acer_aspire_6530g_setup, + .init_hook = alc_automute_amp, }, [ALC888_ACER_ASPIRE_8930G] = { .mixers = { alc888_base_mixer, @@ -9199,7 +9177,8 @@ static struct alc_config_preset alc882_presets[] = { ARRAY_SIZE(alc889_capture_sources), .input_mux = alc889_capture_sources, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc889_acer_aspire_8930g_init_hook, + .setup = alc889_acer_aspire_8930g_setup, + .init_hook = alc_automute_amp, }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, @@ -9224,7 +9203,8 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_medion_md2_init_hook, + .setup = alc883_medion_md2_setup, + .init_hook = alc_automute_amp, }, [ALC883_LAPTOP_EAPD] = { .mixers = { alc883_base_mixer }, @@ -9245,6 +9225,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc883_clevo_m720_unsol_event, + .setup = alc883_clevo_m720_setup, .init_hook = alc883_clevo_m720_init_hook, }, [ALC883_LENOVO_101E_2ch] = { @@ -9270,7 +9251,8 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_lenovo_nb0763_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_medion_md2_init_hook, + .setup = alc883_medion_md2_setup, + .init_hook = alc_automute_amp, }, [ALC888_LENOVO_MS7195_DIG] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9295,7 +9277,8 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_haier_w66_init_hook, + .setup = alc883_haier_w66_setup, + .init_hook = alc_automute_amp, }, [ALC888_3ST_HP] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9307,7 +9290,8 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_3st_hp_init_hook, + .setup = alc888_3st_hp_setup, + .init_hook = alc_automute_amp, }, [ALC888_6ST_DELL] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, @@ -9320,7 +9304,8 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_6st_dell_init_hook, + .setup = alc888_6st_dell_setup, + .init_hook = alc_automute_amp, }, [ALC883_MITAC] = { .mixers = { alc883_mitac_mixer }, @@ -9331,7 +9316,8 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_mitac_init_hook, + .setup = alc883_mitac_setup, + .init_hook = alc_automute_amp, }, [ALC883_FUJITSU_PI2515] = { .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, @@ -9344,7 +9330,8 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_fujitsu_pi2515_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_2ch_fujitsu_pi2515_init_hook, + .setup = alc883_2ch_fujitsu_pi2515_setup, + .init_hook = alc_automute_amp, }, [ALC888_FUJITSU_XA3530] = { .mixers = { alc888_base_mixer, alc883_chmode_mixer }, @@ -9362,7 +9349,8 @@ static struct alc_config_preset alc882_presets[] = { ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_fujitsu_xa3530_init_hook, + .setup = alc888_fujitsu_xa3530_setup, + .init_hook = alc_automute_amp, }, [ALC888_LENOVO_SKY] = { .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, @@ -9375,7 +9363,8 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc883_lenovo_sky_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_lenovo_sky_init_hook, + .setup = alc888_lenovo_sky_setup, + .init_hook = alc_automute_amp, }, [ALC888_ASUS_M90V] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9388,8 +9377,9 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_6ch_modes, .need_dac_fix = 1, .input_mux = &alc883_fujitsu_pi2515_capture_source, - .unsol_event = alc883_mode2_unsol_event, - .init_hook = alc883_mode2_inithook, + .unsol_event = alc_sku_unsol_event, + .setup = alc883_mode2_setup, + .init_hook = alc_inithook, }, [ALC888_ASUS_EEE1601] = { .mixers = { alc883_asus_eee1601_mixer }, @@ -9442,7 +9432,8 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_vaiott_init_hook, + .setup = alc883_vaiott_setup, + .init_hook = alc_automute_amp, }, }; @@ -9954,13 +9945,12 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hp_t5735_init_hook(struct hda_codec *codec) +static void alc262_hp_t5735_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */ - alc_automute_amp(codec); } static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { @@ -10117,22 +10107,20 @@ static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res) alc262_hippo_automute(codec); } -static void alc262_hippo_init_hook(struct hda_codec *codec) +static void alc262_hippo_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - alc262_hippo_automute(codec); } -static void alc262_hippo1_init_hook(struct hda_codec *codec) +static void alc262_hippo1_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; - alc262_hippo_automute(codec); } @@ -10189,13 +10177,12 @@ static struct hda_verb alc262_tyan_verbs[] = { }; /* unsolicited event for HP jack sensing */ -static void alc262_tyan_init_hook(struct hda_codec *codec) +static void alc262_tyan_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); } @@ -10307,14 +10294,6 @@ static struct hda_verb alc262_sony_unsol_verbs[] = { {} }; -static struct hda_input_mux alc262_dmic_capture_source = { - .num_items = 2, - .items = { - { "Int DMic", 0x9 }, - { "Mic", 0x0 }, - }, -}; - static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -10336,35 +10315,17 @@ static struct hda_verb alc262_toshiba_s06_verbs[] = { {} }; -static void alc262_dmic_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_write(codec, 0x22, 0, - AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09); -} - - -/* unsolicited event for HP jack sensing */ -static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_MIC_EVENT) - alc262_dmic_automute(codec); - else - alc_sku_unsol_event(codec, res); -} - -static void alc262_toshiba_s06_init_hook(struct hda_codec *codec) +static void alc262_toshiba_s06_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_pin(codec); - alc262_dmic_automute(codec); + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 9; + spec->auto_mic = 1; } /* @@ -11337,7 +11298,8 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .setup = alc262_hippo_setup, + .init_hook = alc262_hippo_automute, }, [ALC262_HIPPO_1] = { .mixers = { alc262_hippo1_mixer }, @@ -11350,7 +11312,8 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo1_init_hook, + .setup = alc262_hippo1_setup, + .init_hook = alc262_hippo_automute, }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, @@ -11413,7 +11376,8 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc262_hp_t5735_init_hook, + .setup = alc262_hp_t5735_setup, + .init_hook = alc_automute_amp, }, [ALC262_HP_RP5700] = { .mixers = { alc262_hp_rp5700_mixer }, @@ -11444,7 +11408,8 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .setup = alc262_hippo_setup, + .init_hook = alc262_hippo_automute, }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, @@ -11457,7 +11422,8 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .setup = alc262_hippo_setup, + .init_hook = alc262_hippo_automute, }, [ALC262_ULTRA] = { .mixers = { alc262_ultra_mixer }, @@ -11509,9 +11475,9 @@ static struct alc_config_preset alc262_presets[] = { .dig_out_nid = ALC262_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, - .input_mux = &alc262_dmic_capture_source, - .unsol_event = alc262_toshiba_s06_unsol_event, - .init_hook = alc262_toshiba_s06_init_hook, + .unsol_event = alc_sku_unsol_event, + .setup = alc262_toshiba_s06_setup, + .init_hook = alc_inithook, }, [ALC262_TOSHIBA_RX1] = { .mixers = { alc262_toshiba_rx1_mixer }, @@ -11523,7 +11489,8 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .setup = alc262_hippo_setup, + .init_hook = alc262_hippo_automute, }, [ALC262_TYAN] = { .mixers = { alc262_tyan_mixer }, @@ -11536,7 +11503,8 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc262_tyan_init_hook, + .setup = alc262_tyan_setup, + .init_hook = alc_automute_amp, }, }; @@ -11732,14 +11700,6 @@ static struct hda_verb alc268_toshiba_verbs[] = { { } /* end */ }; -static struct hda_input_mux alc268_acer_lc_capture_source = { - .num_items = 2, - .items = { - { "i-Mic", 0x6 }, - { "E-Mic", 0x0 }, - }, -}; - /* Acer specific */ /* bind volumes of both NID 0x02 and 0x03 */ static struct hda_bind_ctls alc268_acer_bind_master_vol = { @@ -11858,7 +11818,8 @@ static struct hda_verb alc268_acer_verbs[] = { /* unsolicited event for HP jack sensing */ #define alc268_toshiba_unsol_event alc262_hippo_unsol_event -#define alc268_toshiba_init_hook alc262_hippo_init_hook +#define alc268_toshiba_setup alc262_hippo_setup +#define alc268_toshiba_automute alc262_hippo_automute static void alc268_acer_unsol_event(struct hda_codec *codec, unsigned int res) @@ -11888,30 +11849,33 @@ static void alc268_aspire_one_speaker_automute(struct hda_codec *codec) AMP_IN_MUTE(0), bits); } - -static void alc268_acer_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL, - present ? 0x0 : 0x6); -} - static void alc268_acer_lc_unsol_event(struct hda_codec *codec, unsigned int res) { - if ((res >> 26) == ALC880_HP_EVENT) + switch (res >> 26) { + case ALC880_HP_EVENT: alc268_aspire_one_speaker_automute(codec); - if ((res >> 26) == ALC880_MIC_EVENT) - alc268_acer_mic_automute(codec); + break; + case ALC880_MIC_EVENT: + alc_mic_automute(codec); + break; + } +} + +static void alc268_acer_lc_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 6; + spec->auto_mic = 1; } static void alc268_acer_lc_init_hook(struct hda_codec *codec) { alc268_aspire_one_speaker_automute(codec); - alc268_acer_mic_automute(codec); + alc_mic_automute(codec); } static struct snd_kcontrol_new alc268_dell_mixer[] = { @@ -11929,17 +11893,22 @@ static struct hda_verb alc268_dell_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, { } }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc268_dell_init_hook(struct hda_codec *codec) +static void alc268_dell_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_pin(codec); + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { @@ -11960,38 +11929,16 @@ static struct hda_verb alc267_quanta_il1_verbs[] = { { } }; -static void alc267_quanta_il1_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, - present ? 0x00 : 0x01); -} - -static void alc267_quanta_il1_init_hook(struct hda_codec *codec) +static void alc267_quanta_il1_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_pin(codec); - alc267_quanta_il1_mic_automute(codec); -} - -static void alc267_quanta_il1_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_MIC_EVENT: - alc267_quanta_il1_mic_automute(codec); - break; - default: - alc_sku_unsol_event(codec, res); - break; - } + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } /* @@ -12490,8 +12437,9 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, - .unsol_event = alc267_quanta_il1_unsol_event, - .init_hook = alc267_quanta_il1_init_hook, + .unsol_event = alc_sku_unsol_event, + .setup = alc267_quanta_il1_setup, + .init_hook = alc_inithook, }, [ALC268_3ST] = { .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, @@ -12523,7 +12471,8 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc268_toshiba_unsol_event, - .init_hook = alc268_toshiba_init_hook, + .setup = alc268_toshiba_setup, + .init_hook = alc268_toshiba_automute, }, [ALC268_ACER] = { .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, @@ -12573,8 +12522,8 @@ static struct alc_config_preset alc268_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, - .input_mux = &alc268_acer_lc_capture_source, .unsol_event = alc268_acer_lc_unsol_event, + .setup = alc268_acer_lc_setup, .init_hook = alc268_acer_lc_init_hook, }, [ALC268_DELL] = { @@ -12587,8 +12536,8 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .unsol_event = alc_sku_unsol_event, - .init_hook = alc268_dell_init_hook, - .input_mux = &alc268_capture_source, + .setup = alc268_dell_setup, + .init_hook = alc_inithook, }, [ALC268_ZEPTO] = { .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, @@ -12605,8 +12554,8 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, - .unsol_event = alc268_toshiba_unsol_event, - .init_hook = alc268_toshiba_init_hook + .setup = alc268_toshiba_setup, + .init_hook = alc268_toshiba_automute, }, #ifdef CONFIG_SND_DEBUG [ALC268_TEST] = { @@ -12750,22 +12699,6 @@ static hda_nid_t alc269_capsrc_nids[1] = { * not a mux! */ -static struct hda_input_mux alc269_eeepc_dmic_capture_source = { - .num_items = 2, - .items = { - { "i-Mic", 0x5 }, - { "e-Mic", 0x0 }, - }, -}; - -static struct hda_input_mux alc269_eeepc_amic_capture_source = { - .num_items = 2, - .items = { - { "i-Mic", 0x1 }, - { "e-Mic", 0x0 }, - }, -}; - #define alc269_modes alc260_modes #define alc269_capture_source alc880_lg_lw_capture_source @@ -12927,16 +12860,6 @@ static void alc269_lifebook_speaker_automute(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x480); } -static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1); -} - static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) { unsigned int present_laptop; @@ -12963,10 +12886,14 @@ static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, unsigned int res) { - if ((res >> 26) == ALC880_HP_EVENT) + switch (res >> 26) { + case ALC880_HP_EVENT: alc269_quanta_fl1_speaker_automute(codec); - if ((res >> 26) == ALC880_MIC_EVENT) - alc269_quanta_fl1_mic_automute(codec); + break; + case ALC880_MIC_EVENT: + alc_mic_automute(codec); + break; + } } static void alc269_lifebook_unsol_event(struct hda_codec *codec, @@ -12978,10 +12905,20 @@ static void alc269_lifebook_unsol_event(struct hda_codec *codec, alc269_lifebook_mic_autoswitch(codec); } +static void alc269_quanta_fl1_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} + static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) { alc269_quanta_fl1_speaker_automute(codec); - alc269_quanta_fl1_mic_automute(codec); + alc_mic_automute(codec); } static void alc269_lifebook_init_hook(struct hda_codec *codec) @@ -13026,60 +12963,44 @@ static void alc269_speaker_automute(struct hda_codec *codec) AMP_IN_MUTE(0), bits); } -static void alc269_eeepc_dmic_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5)); -} - -static void alc269_eeepc_amic_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); - snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); -} - /* unsolicited event for HP jack sensing */ -static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec, +static void alc269_eeepc_unsol_event(struct hda_codec *codec, unsigned int res) { - if ((res >> 26) == ALC880_HP_EVENT) + switch (res >> 26) { + case ALC880_HP_EVENT: alc269_speaker_automute(codec); - - if ((res >> 26) == ALC880_MIC_EVENT) - alc269_eeepc_dmic_automute(codec); + break; + case ALC880_MIC_EVENT: + alc_mic_automute(codec); + break; + } } -static void alc269_eeepc_dmic_inithook(struct hda_codec *codec) +static void alc269_eeepc_dmic_setup(struct hda_codec *codec) { - alc269_speaker_automute(codec); - alc269_eeepc_dmic_automute(codec); + struct alc_spec *spec = codec->spec; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 5; + spec->auto_mic = 1; } -/* unsolicited event for HP jack sensing */ -static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc269_eeepc_amic_setup(struct hda_codec *codec) { - if ((res >> 26) == ALC880_HP_EVENT) - alc269_speaker_automute(codec); - - if ((res >> 26) == ALC880_MIC_EVENT) - alc269_eeepc_amic_automute(codec); + struct alc_spec *spec = codec->spec; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; } -static void alc269_eeepc_amic_inithook(struct hda_codec *codec) +static void alc269_eeepc_inithook(struct hda_codec *codec) { alc269_speaker_automute(codec); - alc269_eeepc_amic_automute(codec); + alc_mic_automute(codec); } /* @@ -13385,6 +13306,7 @@ static struct alc_config_preset alc269_presets[] = { .channel_mode = alc269_modes, .input_mux = &alc269_capture_source, .unsol_event = alc269_quanta_fl1_unsol_event, + .setup = alc269_quanta_fl1_setup, .init_hook = alc269_quanta_fl1_init_hook, }, [ALC269_ASUS_EEEPC_P703] = { @@ -13397,9 +13319,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .input_mux = &alc269_eeepc_amic_capture_source, - .unsol_event = alc269_eeepc_amic_unsol_event, - .init_hook = alc269_eeepc_amic_inithook, + .unsol_event = alc269_eeepc_unsol_event, + .setup = alc269_eeepc_amic_setup, + .init_hook = alc269_eeepc_inithook, }, [ALC269_ASUS_EEEPC_P901] = { .mixers = { alc269_eeepc_mixer }, @@ -13411,9 +13333,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .input_mux = &alc269_eeepc_dmic_capture_source, - .unsol_event = alc269_eeepc_dmic_unsol_event, - .init_hook = alc269_eeepc_dmic_inithook, + .unsol_event = alc269_eeepc_unsol_event, + .setup = alc269_eeepc_dmic_setup, + .init_hook = alc269_eeepc_inithook, }, [ALC269_FUJITSU] = { .mixers = { alc269_fujitsu_mixer }, @@ -13425,9 +13347,9 @@ static struct alc_config_preset alc269_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc269_modes), .channel_mode = alc269_modes, - .input_mux = &alc269_eeepc_dmic_capture_source, - .unsol_event = alc269_eeepc_dmic_unsol_event, - .init_hook = alc269_eeepc_dmic_inithook, + .unsol_event = alc269_eeepc_unsol_event, + .setup = alc269_eeepc_dmic_setup, + .init_hook = alc269_eeepc_inithook, }, [ALC269_LIFEBOOK] = { .mixers = { alc269_lifebook_mixer }, @@ -15044,12 +14966,15 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) HDA_AMP_MUTE, bits); } -static void alc861vd_lenovo_init_hook(struct hda_codec *codec) +static void alc861vd_lenovo_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x1b; spec->autocfg.speaker_pins[0] = 0x14; +} + +static void alc861vd_lenovo_init_hook(struct hda_codec *codec) +{ alc_automute_amp(codec); alc861vd_lenovo_mic_automute(codec); } @@ -15113,13 +15038,12 @@ static struct hda_verb alc861vd_dallas_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc861vd_dallas_init_hook(struct hda_codec *codec) +static void alc861vd_dallas_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -15233,6 +15157,7 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_capture_source, .unsol_event = alc861vd_lenovo_unsol_event, + .setup = alc861vd_lenovo_setup, .init_hook = alc861vd_lenovo_init_hook, }, [ALC861VD_DALLAS] = { @@ -15244,7 +15169,8 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_dallas_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc861vd_dallas_init_hook, + .setup = alc861vd_dallas_setup, + .init_hook = alc_automute_amp, }, [ALC861VD_HP] = { .mixers = { alc861vd_hp_mixer }, @@ -15256,7 +15182,8 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_hp_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc861vd_dallas_init_hook, + .setup = alc861vd_dallas_setup, + .init_hook = alc_automute_amp, }, [ALC660VD_ASUS_V1S] = { .mixers = { alc861vd_lenovo_mixer }, @@ -15271,6 +15198,7 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_capture_source, .unsol_event = alc861vd_lenovo_unsol_event, + .setup = alc861vd_lenovo_setup, .init_hook = alc861vd_lenovo_init_hook, }, }; @@ -15660,14 +15588,6 @@ static struct hda_input_mux alc662_lenovo_101e_capture_source = { }, }; -static struct hda_input_mux alc662_eeepc_capture_source = { - .num_items = 2, - .items = { - { "i-Mic", 0x1 }, - { "e-Mic", 0x0 }, - }, -}; - static struct hda_input_mux alc663_capture_source = { .num_items = 3, .items = { @@ -15677,23 +15597,7 @@ static struct hda_input_mux alc663_capture_source = { }, }; -static struct hda_input_mux alc663_m51va_capture_source = { - .num_items = 2, - .items = { - { "Ext-Mic", 0x0 }, - { "D-Mic", 0x9 }, - }, -}; - -#if 1 /* set to 0 for testing other input sources below */ -static struct hda_input_mux alc272_nc10_capture_source = { - .num_items = 2, - .items = { - { "Autoselect Mic", 0x0 }, - { "Internal Mic", 0x1 }, - }, -}; -#else +#if 0 /* set to 1 for testing other input sources below */ static struct hda_input_mux alc272_nc10_capture_source = { .num_items = 16, .items = { @@ -16362,47 +16266,44 @@ static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, alc662_lenovo_101e_ispeaker_automute(codec); } -static void alc662_eeepc_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); - snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); - snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); - snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); -} - /* unsolicited event for HP jack sensing */ static void alc662_eeepc_unsol_event(struct hda_codec *codec, unsigned int res) { if ((res >> 26) == ALC880_MIC_EVENT) - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); else alc262_hippo_unsol_event(codec, res); } +static void alc662_eeepc_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + alc262_hippo1_setup(codec); + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} + static void alc662_eeepc_inithook(struct hda_codec *codec) { - alc262_hippo1_init_hook(codec); - alc662_eeepc_mic_automute(codec); + alc262_hippo_automute(codec); + alc_mic_automute(codec); } -static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) +static void alc662_eeepc_ep20_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; spec->autocfg.hp_pins[0] = 0x14; spec->autocfg.speaker_pins[0] = 0x1b; - alc262_hippo_master_update(codec); } +#define alc662_eeepc_ep20_inithook alc262_hippo_master_update + static void alc663_m51va_speaker_automute(struct hda_codec *codec) { unsigned int present; @@ -16513,23 +16414,6 @@ static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec) } } -static void alc663_m51va_mic_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); - snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); - snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); - snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, - 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); -} - static void alc663_m51va_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -16538,36 +16422,32 @@ static void alc663_m51va_unsol_event(struct hda_codec *codec, alc663_m51va_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc663_m51va_mic_automute(codec); + alc_mic_automute(codec); break; } } +static void alc663_m51va_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x12; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} + static void alc663_m51va_inithook(struct hda_codec *codec) { alc663_m51va_speaker_automute(codec); - alc663_m51va_mic_automute(codec); + alc_mic_automute(codec); } /* ***************** Mode1 ******************************/ -static void alc663_mode1_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc663_m51va_speaker_automute(codec); - break; - case ALC880_MIC_EVENT: - alc662_eeepc_mic_automute(codec); - break; - } -} +#define alc663_mode1_unsol_event alc663_m51va_unsol_event +#define alc663_mode1_setup alc663_m51va_setup +#define alc663_mode1_inithook alc663_m51va_inithook -static void alc663_mode1_inithook(struct hda_codec *codec) -{ - alc663_m51va_speaker_automute(codec); - alc662_eeepc_mic_automute(codec); -} /* ***************** Mode2 ******************************/ static void alc662_mode2_unsol_event(struct hda_codec *codec, unsigned int res) @@ -16577,15 +16457,17 @@ static void alc662_mode2_unsol_event(struct hda_codec *codec, alc662_f5z_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); break; } } +#define alc662_mode2_setup alc663_m51va_setup + static void alc662_mode2_inithook(struct hda_codec *codec) { alc662_f5z_speaker_automute(codec); - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); } /* ***************** Mode3 ******************************/ static void alc663_mode3_unsol_event(struct hda_codec *codec, @@ -16596,15 +16478,17 @@ static void alc663_mode3_unsol_event(struct hda_codec *codec, alc663_two_hp_m1_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); break; } } +#define alc663_mode3_setup alc663_m51va_setup + static void alc663_mode3_inithook(struct hda_codec *codec) { alc663_two_hp_m1_speaker_automute(codec); - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); } /* ***************** Mode4 ******************************/ static void alc663_mode4_unsol_event(struct hda_codec *codec, @@ -16615,15 +16499,17 @@ static void alc663_mode4_unsol_event(struct hda_codec *codec, alc663_21jd_two_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); break; } } +#define alc663_mode4_setup alc663_m51va_setup + static void alc663_mode4_inithook(struct hda_codec *codec) { alc663_21jd_two_speaker_automute(codec); - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); } /* ***************** Mode5 ******************************/ static void alc663_mode5_unsol_event(struct hda_codec *codec, @@ -16634,15 +16520,17 @@ static void alc663_mode5_unsol_event(struct hda_codec *codec, alc663_15jd_two_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); break; } } +#define alc663_mode5_setup alc663_m51va_setup + static void alc663_mode5_inithook(struct hda_codec *codec) { alc663_15jd_two_speaker_automute(codec); - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); } /* ***************** Mode6 ******************************/ static void alc663_mode6_unsol_event(struct hda_codec *codec, @@ -16653,15 +16541,17 @@ static void alc663_mode6_unsol_event(struct hda_codec *codec, alc663_two_hp_m2_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); break; } } +#define alc663_mode6_setup alc663_m51va_setup + static void alc663_mode6_inithook(struct hda_codec *codec) { alc663_two_hp_m2_speaker_automute(codec); - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); } static void alc663_g71v_hp_automute(struct hda_codec *codec) @@ -16703,16 +16593,18 @@ static void alc663_g71v_unsol_event(struct hda_codec *codec, alc663_g71v_front_automute(codec); break; case ALC880_MIC_EVENT: - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); break; } } +#define alc663_g71v_setup alc663_m51va_setup + static void alc663_g71v_inithook(struct hda_codec *codec) { alc663_g71v_front_automute(codec); alc663_g71v_hp_automute(codec); - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); } static void alc663_g50v_unsol_event(struct hda_codec *codec, @@ -16723,15 +16615,17 @@ static void alc663_g50v_unsol_event(struct hda_codec *codec, alc663_m51va_speaker_automute(codec); break; case ALC880_MIC_EVENT: - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); break; } } +#define alc663_g50v_setup alc663_m51va_setup + static void alc663_g50v_inithook(struct hda_codec *codec) { alc663_m51va_speaker_automute(codec); - alc662_eeepc_mic_automute(codec); + alc_mic_automute(codec); } static struct snd_kcontrol_new alc662_ecs_mixer[] = { @@ -16935,8 +16829,8 @@ static struct alc_config_preset alc662_presets[] = { .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc662_eeepc_unsol_event, + .setup = alc662_eeepc_setup, .init_hook = alc662_eeepc_inithook, }, [ALC662_ASUS_EEEPC_EP20] = { @@ -16950,6 +16844,7 @@ static struct alc_config_preset alc662_presets[] = { .channel_mode = alc662_3ST_6ch_modes, .input_mux = &alc662_lenovo_101e_capture_source, .unsol_event = alc662_eeepc_unsol_event, + .setup = alc662_eeepc_ep20_setup, .init_hook = alc662_eeepc_ep20_inithook, }, [ALC662_ECS] = { @@ -16960,8 +16855,8 @@ static struct alc_config_preset alc662_presets[] = { .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc662_eeepc_unsol_event, + .setup = alc662_eeepc_setup, .init_hook = alc662_eeepc_inithook, }, [ALC663_ASUS_M51VA] = { @@ -16972,8 +16867,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc663_m51va_capture_source, .unsol_event = alc663_m51va_unsol_event, + .setup = alc663_m51va_setup, .init_hook = alc663_m51va_inithook, }, [ALC663_ASUS_G71V] = { @@ -16984,8 +16879,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_g71v_unsol_event, + .setup = alc663_g71v_setup, .init_hook = alc663_g71v_inithook, }, [ALC663_ASUS_H13] = { @@ -16995,7 +16890,6 @@ static struct alc_config_preset alc662_presets[] = { .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc663_m51va_capture_source, .unsol_event = alc663_m51va_unsol_event, .init_hook = alc663_m51va_inithook, }, @@ -17009,6 +16903,7 @@ static struct alc_config_preset alc662_presets[] = { .channel_mode = alc662_3ST_6ch_modes, .input_mux = &alc663_capture_source, .unsol_event = alc663_g50v_unsol_event, + .setup = alc663_g50v_setup, .init_hook = alc663_g50v_inithook, }, [ALC663_ASUS_MODE1] = { @@ -17022,8 +16917,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_mode1_unsol_event, + .setup = alc663_mode1_setup, .init_hook = alc663_mode1_inithook, }, [ALC662_ASUS_MODE2] = { @@ -17036,8 +16931,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc662_mode2_unsol_event, + .setup = alc662_mode2_setup, .init_hook = alc662_mode2_inithook, }, [ALC663_ASUS_MODE3] = { @@ -17051,8 +16946,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_mode3_unsol_event, + .setup = alc663_mode3_setup, .init_hook = alc663_mode3_inithook, }, [ALC663_ASUS_MODE4] = { @@ -17066,8 +16961,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_mode4_unsol_event, + .setup = alc663_mode4_setup, .init_hook = alc663_mode4_inithook, }, [ALC663_ASUS_MODE5] = { @@ -17081,8 +16976,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_mode5_unsol_event, + .setup = alc663_mode5_setup, .init_hook = alc663_mode5_inithook, }, [ALC663_ASUS_MODE6] = { @@ -17096,8 +16991,8 @@ static struct alc_config_preset alc662_presets[] = { .dig_out_nid = ALC662_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc662_eeepc_capture_source, .unsol_event = alc663_mode6_unsol_event, + .setup = alc663_mode6_setup, .init_hook = alc663_mode6_inithook, }, [ALC272_DELL] = { @@ -17111,8 +17006,8 @@ static struct alc_config_preset alc662_presets[] = { .num_adc_nids = ARRAY_SIZE(alc272_adc_nids), .capsrc_nids = alc272_capsrc_nids, .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc663_m51va_capture_source, .unsol_event = alc663_m51va_unsol_event, + .setup = alc663_m51va_setup, .init_hook = alc663_m51va_inithook, }, [ALC272_DELL_ZM1] = { @@ -17126,8 +17021,8 @@ static struct alc_config_preset alc662_presets[] = { .num_adc_nids = 1, .capsrc_nids = alc662_capsrc_nids, .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc663_m51va_capture_source, .unsol_event = alc663_m51va_unsol_event, + .setup = alc663_m51va_setup, .init_hook = alc663_m51va_inithook, }, [ALC272_SAMSUNG_NC10] = { @@ -17138,8 +17033,9 @@ static struct alc_config_preset alc662_presets[] = { .dac_nids = alc272_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc272_nc10_capture_source, + /*.input_mux = &alc272_nc10_capture_source,*/ .unsol_event = alc663_mode4_unsol_event, + .setup = alc663_mode4_setup, .init_hook = alc663_mode4_inithook, }, }; -- cgit v0.10.2 From 7770841e63730d62928b0879498064e9614b2ce0 Mon Sep 17 00:00:00 2001 From: Zhaolei Date: Fri, 7 Aug 2009 18:53:21 +0800 Subject: tracing: Rename set_tracer_flags()'s local variable trace_flags set_tracer_flags() have a local variable named trace_flags which has the same name than a global one in the same scope. This leads to confusion, using tracer_flags should be better by its meaning. Changelog: v1->v2: Simplified another patch in this patchset, no change in this patch. Signed-off-by: Zhao Lei Cc: Steven Rostedt Cc: Li Zefan Signed-off-by: Frederic Weisbecker diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index e793cda..8ac2043 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -2118,23 +2118,23 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf, /* Try to assign a tracer specific option */ static int set_tracer_option(struct tracer *trace, char *cmp, int neg) { - struct tracer_flags *trace_flags = trace->flags; + struct tracer_flags *tracer_flags = trace->flags; struct tracer_opt *opts = NULL; int ret = 0, i = 0; int len; - for (i = 0; trace_flags->opts[i].name; i++) { - opts = &trace_flags->opts[i]; + for (i = 0; tracer_flags->opts[i].name; i++) { + opts = &tracer_flags->opts[i]; len = strlen(opts->name); if (strncmp(cmp, opts->name, len) == 0) { - ret = trace->set_flag(trace_flags->val, + ret = trace->set_flag(tracer_flags->val, opts->bit, !neg); break; } } /* Not found */ - if (!trace_flags->opts[i].name) + if (!tracer_flags->opts[i].name) return -EINVAL; /* Refused to handle */ @@ -2142,9 +2142,9 @@ static int set_tracer_option(struct tracer *trace, char *cmp, int neg) return ret; if (neg) - trace_flags->val &= ~opts->bit; + tracer_flags->val &= ~opts->bit; else - trace_flags->val |= opts->bit; + tracer_flags->val |= opts->bit; return 0; } -- cgit v0.10.2 From eeac19a7efa150231e4a6bb110d6f27500bcc8ce Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:52:13 -0400 Subject: tracing: Map syscall name to number Add a new function to support translating a syscall name to number at runtime. This allows the syscall event tracer to map syscall names to number. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 8e96634..afb31d7 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -500,6 +500,22 @@ struct syscall_metadata *syscall_nr_to_meta(int nr) return syscalls_metadata[nr]; } +int syscall_name_to_nr(char *name) +{ + int i; + + if (!syscalls_metadata) + return -1; + + for (i = 0; i < FTRACE_SYSCALL_MAX; i++) { + if (syscalls_metadata[i]) { + if (!strcmp(syscalls_metadata[i]->name, name)) + return i; + } + } + return -1; +} + void arch_init_ftrace_syscalls(void) { int i; -- cgit v0.10.2 From 066e0378c23f0a3db730893f6a041e4a3922a385 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:52:23 -0400 Subject: tracing: Call arch_init_ftrace_syscalls at boot Call arch_init_ftrace_syscalls at boot, so we can determine early the set of syscalls for the syscall trace events. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index afb31d7..0d93d40 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -516,31 +516,24 @@ int syscall_name_to_nr(char *name) return -1; } -void arch_init_ftrace_syscalls(void) +static int __init arch_init_ftrace_syscalls(void) { int i; struct syscall_metadata *meta; unsigned long **psys_syscall_table = &sys_call_table; - static atomic_t refs; - - if (atomic_inc_return(&refs) != 1) - goto end; syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * FTRACE_SYSCALL_MAX, GFP_KERNEL); if (!syscalls_metadata) { WARN_ON(1); - return; + return -ENOMEM; } for (i = 0; i < FTRACE_SYSCALL_MAX; i++) { meta = find_syscall_meta(psys_syscall_table[i]); syscalls_metadata[i] = meta; } - return; - - /* Paranoid: avoid overflow */ -end: - atomic_dec(&refs); + return 0; } +arch_initcall(arch_init_ftrace_syscalls); #endif diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 8cfe515..c55fcce 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -19,7 +19,6 @@ struct syscall_metadata { }; #ifdef CONFIG_FTRACE_SYSCALLS -extern void arch_init_ftrace_syscalls(void); extern struct syscall_metadata *syscall_nr_to_meta(int nr); extern void start_ftrace_syscalls(void); extern void stop_ftrace_syscalls(void); diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 5e57964..08aed43 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -106,7 +106,6 @@ void start_ftrace_syscalls(void) if (++refcount != 1) goto unlock; - arch_init_ftrace_syscalls(); read_lock_irqsave(&tasklist_lock, flags); do_each_thread(g, t) { -- cgit v0.10.2 From 63fbdab3157b72467013fe4dcf88c85e45280ef7 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:52:27 -0400 Subject: tracing: Add DECLARE_TRACE_WITH_CALLBACK() macro Introduce a new 'DECLARE_TRACE_WITH_CALLBACK()' macro, so that tracepoints can associate an external register/unregister function. This prepares for the syscalls tracer conversion to trace events. We will need to perform arch level operations once a syscall event is turned on/off, such as TIF flags setting, hence the need of such specific callbacks. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index b9dc4ca..5984ed0 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -60,8 +60,10 @@ struct tracepoint { * Make sure the alignment of the structure in the __tracepoints section will * not add unwanted padding between the beginning of the section and the * structure. Force alignment to the same alignment as the section start. + * An optional set of (un)registration functions can be passed to perform any + * additional (un)registration work. */ -#define DECLARE_TRACE(name, proto, args) \ +#define DECLARE_TRACE_WITH_CALLBACK(name, proto, args, reg, unreg) \ extern struct tracepoint __tracepoint_##name; \ static inline void trace_##name(proto) \ { \ @@ -71,13 +73,30 @@ struct tracepoint { } \ static inline int register_trace_##name(void (*probe)(proto)) \ { \ - return tracepoint_probe_register(#name, (void *)probe); \ + int ret; \ + void (*func)(void) = reg; \ + \ + ret = tracepoint_probe_register(#name, (void *)probe); \ + if (func && !ret) \ + func(); \ + return ret; \ } \ static inline int unregister_trace_##name(void (*probe)(proto)) \ { \ - return tracepoint_probe_unregister(#name, (void *)probe);\ + int ret; \ + void (*func)(void) = unreg; \ + \ + ret = tracepoint_probe_unregister(#name, (void *)probe);\ + if (func && !ret) \ + func(); \ + return ret; \ } + +#define DECLARE_TRACE(name, proto, args) \ + DECLARE_TRACE_WITH_CALLBACK(name, TP_PROTO(proto), TP_ARGS(args),\ + NULL, NULL); + #define DEFINE_TRACE(name) \ static const char __tpstrtab_##name[] \ __attribute__((section("__tracepoints_strings"))) = #name; \ @@ -94,7 +113,7 @@ extern void tracepoint_update_probe_range(struct tracepoint *begin, struct tracepoint *end); #else /* !CONFIG_TRACEPOINTS */ -#define DECLARE_TRACE(name, proto, args) \ +#define DECLARE_TRACE_WITH_CALLBACK(name, proto, args, reg, unreg) \ static inline void _do_trace_##name(struct tracepoint *tp, proto) \ { } \ static inline void trace_##name(proto) \ @@ -108,6 +127,10 @@ extern void tracepoint_update_probe_range(struct tracepoint *begin, return -ENOSYS; \ } +#define DECLARE_TRACE(name, proto, args) \ + DECLARE_TRACE_WITH_CALLBACK(name, TP_PROTO(proto), TP_ARGS(args),\ + NULL, NULL); + #define DEFINE_TRACE(name) #define EXPORT_TRACEPOINT_SYMBOL_GPL(name) #define EXPORT_TRACEPOINT_SYMBOL(name) -- cgit v0.10.2 From a871bd33a6c0bc86fb47cd02ea2650dd43d3d95f Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:52:31 -0400 Subject: tracing: Add syscall tracepoints add two tracepoints in syscall exit and entry path, conditioned on TIF_SYSCALL_FTRACE. Supports the syscall trace event code. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 09ecbde..34dd6f1 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -37,6 +37,9 @@ #include +DEFINE_TRACE(syscall_enter); +DEFINE_TRACE(syscall_exit); + #include "tls.h" enum x86_regset { @@ -1498,7 +1501,7 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs) ret = -1L; if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) - ftrace_syscall_enter(regs); + trace_syscall_enter(regs, regs->orig_ax); if (unlikely(current->audit_context)) { if (IS_IA32) @@ -1524,7 +1527,7 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs) audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) - ftrace_syscall_exit(regs); + trace_syscall_exit(regs, regs->ax); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, 0); diff --git a/include/trace/syscall.h b/include/trace/syscall.h index c55fcce..3951d77 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -1,8 +1,28 @@ #ifndef _TRACE_SYSCALL_H #define _TRACE_SYSCALL_H +#include + #include + +extern void syscall_regfunc(void); +extern void syscall_unregfunc(void); + +DECLARE_TRACE_WITH_CALLBACK(syscall_enter, + TP_PROTO(struct pt_regs *regs, long id), + TP_ARGS(regs, id), + syscall_regfunc, + syscall_unregfunc +); + +DECLARE_TRACE_WITH_CALLBACK(syscall_exit, + TP_PROTO(struct pt_regs *regs, long ret), + TP_ARGS(regs, ret), + syscall_regfunc, + syscall_unregfunc +); + /* * A syscall entry in the ftrace syscalls array. * diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 1ef5d3a..070a42b 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -24,6 +24,7 @@ #include #include #include +#include extern struct tracepoint __start___tracepoints[]; extern struct tracepoint __stop___tracepoints[]; @@ -577,3 +578,40 @@ static int init_tracepoints(void) __initcall(init_tracepoints); #endif /* CONFIG_MODULES */ + +static DEFINE_MUTEX(regfunc_mutex); +static int sys_tracepoint_refcount; + +void syscall_regfunc(void) +{ + unsigned long flags; + struct task_struct *g, *t; + + mutex_lock(®func_mutex); + if (!sys_tracepoint_refcount) { + read_lock_irqsave(&tasklist_lock, flags); + do_each_thread(g, t) { + set_tsk_thread_flag(t, TIF_SYSCALL_FTRACE); + } while_each_thread(g, t); + read_unlock_irqrestore(&tasklist_lock, flags); + } + sys_tracepoint_refcount++; + mutex_unlock(®func_mutex); +} + +void syscall_unregfunc(void) +{ + unsigned long flags; + struct task_struct *g, *t; + + mutex_lock(®func_mutex); + sys_tracepoint_refcount--; + if (!sys_tracepoint_refcount) { + read_lock_irqsave(&tasklist_lock, flags); + do_each_thread(g, t) { + clear_tsk_thread_flag(t, TIF_SYSCALL_FTRACE); + } while_each_thread(g, t); + read_unlock_irqrestore(&tasklist_lock, flags); + } + mutex_unlock(®func_mutex); +} -- cgit v0.10.2 From 9daa77e2e9a6b8b859660d5e24d0f8cd77c2af39 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:52:35 -0400 Subject: tracing: Update FTRACE_SYSCALL_MAX update FTRACE_SYSCALL_MAX to the current number of syscalls FTRACE_SYSCALL_MAX is a temporary solution to get the number of syscalls supported by the arch until we find a more dynamic way to get this number. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h index bd2c651..7113654 100644 --- a/arch/x86/include/asm/ftrace.h +++ b/arch/x86/include/asm/ftrace.h @@ -30,9 +30,9 @@ /* FIXME: I don't want to stay hardcoded */ #ifdef CONFIG_X86_64 -# define FTRACE_SYSCALL_MAX 296 +# define FTRACE_SYSCALL_MAX 299 #else -# define FTRACE_SYSCALL_MAX 333 +# define FTRACE_SYSCALL_MAX 337 #endif #ifdef CONFIG_FUNCTION_TRACER -- cgit v0.10.2 From f744bd576a827c5b02e756b81fc2578edf8179b8 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:52:39 -0400 Subject: tracing: Raw_init() bailout in trace event register fail case Allow the return value of raw_init() trace event callback to bail us out of creating a trace event file, in case we fail to register our event. Also, we plan to return -ENOSYS for syscall events that don't match any syscalls listed in our arch tracing syscall table, we don't want to warn in that case, we just want this event to be invisible in debugfs and ignored. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index e0cbede..f95f847 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -925,15 +925,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, if (strcmp(call->system, TRACE_SYSTEM) != 0) d_events = event_subsystem_dir(call->system, d_events); - if (call->raw_init) { - ret = call->raw_init(); - if (ret < 0) { - pr_warning("Could not initialize trace point" - " events/%s\n", call->name); - return ret; - } - } - call->dir = debugfs_create_dir(call->name, d_events); if (!call->dir) { pr_warning("Could not create debugfs " @@ -1058,6 +1049,7 @@ static void trace_module_add_events(struct module *mod) struct ftrace_module_file_ops *file_ops = NULL; struct ftrace_event_call *call, *start, *end; struct dentry *d_events; + int ret; start = mod->trace_events; end = mod->trace_events + mod->num_trace_events; @@ -1073,7 +1065,15 @@ static void trace_module_add_events(struct module *mod) /* The linker may leave blanks */ if (!call->name) continue; - + if (call->raw_init) { + ret = call->raw_init(); + if (ret < 0) { + if (ret != -ENOSYS) + pr_warning("Could not initialize trace " + "point events/%s\n", call->name); + continue; + } + } /* * This module has events, create file ops for this module * if not already done. @@ -1225,6 +1225,15 @@ static __init int event_trace_init(void) /* The linker may leave blanks */ if (!call->name) continue; + if (call->raw_init) { + ret = call->raw_init(); + if (ret < 0) { + if (ret != -ENOSYS) + pr_warning("Could not initialize trace " + "point events/%s\n", call->name); + continue; + } + } list_add(&call->list, &ftrace_events); event_create_dir(call, d_events, &ftrace_event_id_fops, &ftrace_enable_fops, &ftrace_event_filter_fops, -- cgit v0.10.2 From 69fd4f0eb2ececbf8ade55e31a933e174965745e Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:52:44 -0400 Subject: tracing: Add ftrace_event_call void * 'data' field add an optional void * pointer to 'ftrace_event_call' that is passed in for regfunc and unregfunc. This prepares for syscall tracepoints creation by passing the name of the syscall we want to trace and then retrieve its number through our arch syscall table. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index ac8c6f8..8544f12 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -112,8 +112,8 @@ struct ftrace_event_call { struct dentry *dir; struct trace_event *event; int enabled; - int (*regfunc)(void); - void (*unregfunc)(void); + int (*regfunc)(void *); + void (*unregfunc)(void *); int id; int (*raw_init)(void); int (*show_format)(struct trace_seq *s); @@ -122,6 +122,7 @@ struct ftrace_event_call { int filter_active; struct event_filter *filter; void *mod; + void *data; atomic_t profile_count; int (*profile_enable)(struct ftrace_event_call *); diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 25d3b02..46d81b5 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -568,7 +568,7 @@ static void ftrace_raw_event_##call(proto) \ trace_nowake_buffer_unlock_commit(event, irq_flags, pc); \ } \ \ -static int ftrace_raw_reg_event_##call(void) \ +static int ftrace_raw_reg_event_##call(void *ptr) \ { \ int ret; \ \ @@ -579,7 +579,7 @@ static int ftrace_raw_reg_event_##call(void) \ return ret; \ } \ \ -static void ftrace_raw_unreg_event_##call(void) \ +static void ftrace_raw_unreg_event_##call(void *ptr) \ { \ unregister_trace_##call(ftrace_raw_event_##call); \ } \ diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index f95f847..1d289e2 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -86,14 +86,14 @@ static void ftrace_event_enable_disable(struct ftrace_event_call *call, if (call->enabled) { call->enabled = 0; tracing_stop_cmdline_record(); - call->unregfunc(); + call->unregfunc(call->data); } break; case 1: if (!call->enabled) { call->enabled = 1; tracing_start_cmdline_record(); - call->regfunc(); + call->regfunc(call->data); } break; } -- cgit v0.10.2 From fb34a08c3469b2be9eae626ccb96476b4687b810 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:52:47 -0400 Subject: tracing: Add trace events for each syscall entry/exit Layer Frederic's syscall tracer on tracepoints. We create trace events via hooking into the SYSCALL_DEFINE macros. This allows us to individually toggle syscall entry and exit points on/off. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 80de700..5e5b4d3 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -64,6 +64,7 @@ struct perf_counter_attr; #include #include #include +#include #include #include #include @@ -112,6 +113,59 @@ struct perf_counter_attr; #define __SC_STR_TDECL5(t, a, ...) #t, __SC_STR_TDECL4(__VA_ARGS__) #define __SC_STR_TDECL6(t, a, ...) #t, __SC_STR_TDECL5(__VA_ARGS__) + +#define SYSCALL_TRACE_ENTER_EVENT(sname) \ + static struct ftrace_event_call event_enter_##sname; \ + static int init_enter_##sname(void) \ + { \ + int num; \ + num = syscall_name_to_nr("sys"#sname); \ + if (num < 0) \ + return -ENOSYS; \ + register_ftrace_event(&event_syscall_enter); \ + INIT_LIST_HEAD(&event_enter_##sname.fields); \ + init_preds(&event_enter_##sname); \ + return 0; \ + } \ + static struct ftrace_event_call __used \ + __attribute__((__aligned__(4))) \ + __attribute__((section("_ftrace_events"))) \ + event_enter_##sname = { \ + .name = "sys_enter"#sname, \ + .system = "syscalls", \ + .event = &event_syscall_enter, \ + .raw_init = init_enter_##sname, \ + .regfunc = reg_event_syscall_enter, \ + .unregfunc = unreg_event_syscall_enter, \ + .data = "sys"#sname, \ + } + +#define SYSCALL_TRACE_EXIT_EVENT(sname) \ + static struct ftrace_event_call event_exit_##sname; \ + static int init_exit_##sname(void) \ + { \ + int num; \ + num = syscall_name_to_nr("sys"#sname); \ + if (num < 0) \ + return -ENOSYS; \ + register_ftrace_event(&event_syscall_exit); \ + INIT_LIST_HEAD(&event_exit_##sname.fields); \ + init_preds(&event_exit_##sname); \ + return 0; \ + } \ + static struct ftrace_event_call __used \ + __attribute__((__aligned__(4))) \ + __attribute__((section("_ftrace_events"))) \ + event_exit_##sname = { \ + .name = "sys_exit"#sname, \ + .system = "syscalls", \ + .event = &event_syscall_exit, \ + .raw_init = init_exit_##sname, \ + .regfunc = reg_event_syscall_exit, \ + .unregfunc = unreg_event_syscall_exit, \ + .data = "sys"#sname, \ + } + #define SYSCALL_METADATA(sname, nb) \ static const struct syscall_metadata __used \ __attribute__((__aligned__(4))) \ @@ -121,7 +175,9 @@ struct perf_counter_attr; .nb_args = nb, \ .types = types_##sname, \ .args = args_##sname, \ - } + }; \ + SYSCALL_TRACE_ENTER_EVENT(sname); \ + SYSCALL_TRACE_EXIT_EVENT(sname); #define SYSCALL_DEFINE0(sname) \ static const struct syscall_metadata __used \ @@ -131,8 +187,9 @@ struct perf_counter_attr; .name = "sys_"#sname, \ .nb_args = 0, \ }; \ + SYSCALL_TRACE_ENTER_EVENT(_##sname); \ + SYSCALL_TRACE_EXIT_EVENT(_##sname); \ asmlinkage long sys_##sname(void) - #else #define SYSCALL_DEFINE0(name) asmlinkage long sys_##name(void) #endif diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 3951d77..73fb8b4 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -2,6 +2,8 @@ #define _TRACE_SYSCALL_H #include +#include +#include #include @@ -40,15 +42,13 @@ struct syscall_metadata { #ifdef CONFIG_FTRACE_SYSCALLS extern struct syscall_metadata *syscall_nr_to_meta(int nr); -extern void start_ftrace_syscalls(void); -extern void stop_ftrace_syscalls(void); -extern void ftrace_syscall_enter(struct pt_regs *regs); -extern void ftrace_syscall_exit(struct pt_regs *regs); -#else -static inline void start_ftrace_syscalls(void) { } -static inline void stop_ftrace_syscalls(void) { } -static inline void ftrace_syscall_enter(struct pt_regs *regs) { } -static inline void ftrace_syscall_exit(struct pt_regs *regs) { } +extern int syscall_name_to_nr(char *name); +extern struct trace_event event_syscall_enter; +extern struct trace_event event_syscall_exit; +extern int reg_event_syscall_enter(void *ptr); +extern void unreg_event_syscall_enter(void *ptr); +extern int reg_event_syscall_exit(void *ptr); +extern void unreg_event_syscall_exit(void *ptr); #endif #endif /* _TRACE_SYSCALL_H */ diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 08aed43..c7ae25e 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -1,15 +1,16 @@ #include #include +#include #include #include "trace_output.h" #include "trace.h" -/* Keep a counter of the syscall tracing users */ -static int refcount; - -/* Prevent from races on thread flags toggling */ static DEFINE_MUTEX(syscall_trace_lock); +static int sys_refcount_enter; +static int sys_refcount_exit; +static DECLARE_BITMAP(enabled_enter_syscalls, FTRACE_SYSCALL_MAX); +static DECLARE_BITMAP(enabled_exit_syscalls, FTRACE_SYSCALL_MAX); /* Option to display the parameters types */ enum { @@ -95,53 +96,7 @@ print_syscall_exit(struct trace_iterator *iter, int flags) return TRACE_TYPE_HANDLED; } -void start_ftrace_syscalls(void) -{ - unsigned long flags; - struct task_struct *g, *t; - - mutex_lock(&syscall_trace_lock); - - /* Don't enable the flag on the tasks twice */ - if (++refcount != 1) - goto unlock; - - read_lock_irqsave(&tasklist_lock, flags); - - do_each_thread(g, t) { - set_tsk_thread_flag(t, TIF_SYSCALL_FTRACE); - } while_each_thread(g, t); - - read_unlock_irqrestore(&tasklist_lock, flags); - -unlock: - mutex_unlock(&syscall_trace_lock); -} - -void stop_ftrace_syscalls(void) -{ - unsigned long flags; - struct task_struct *g, *t; - - mutex_lock(&syscall_trace_lock); - - /* There are perhaps still some users */ - if (--refcount) - goto unlock; - - read_lock_irqsave(&tasklist_lock, flags); - - do_each_thread(g, t) { - clear_tsk_thread_flag(t, TIF_SYSCALL_FTRACE); - } while_each_thread(g, t); - - read_unlock_irqrestore(&tasklist_lock, flags); - -unlock: - mutex_unlock(&syscall_trace_lock); -} - -void ftrace_syscall_enter(struct pt_regs *regs) +void ftrace_syscall_enter(struct pt_regs *regs, long id) { struct syscall_trace_enter *entry; struct syscall_metadata *sys_data; @@ -150,6 +105,8 @@ void ftrace_syscall_enter(struct pt_regs *regs) int syscall_nr; syscall_nr = syscall_get_nr(current, regs); + if (!test_bit(syscall_nr, enabled_enter_syscalls)) + return; sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) @@ -170,7 +127,7 @@ void ftrace_syscall_enter(struct pt_regs *regs) trace_wake_up(); } -void ftrace_syscall_exit(struct pt_regs *regs) +void ftrace_syscall_exit(struct pt_regs *regs, long ret) { struct syscall_trace_exit *entry; struct syscall_metadata *sys_data; @@ -178,6 +135,8 @@ void ftrace_syscall_exit(struct pt_regs *regs) int syscall_nr; syscall_nr = syscall_get_nr(current, regs); + if (!test_bit(syscall_nr, enabled_exit_syscalls)) + return; sys_data = syscall_nr_to_meta(syscall_nr); if (!sys_data) @@ -196,54 +155,94 @@ void ftrace_syscall_exit(struct pt_regs *regs) trace_wake_up(); } -static int init_syscall_tracer(struct trace_array *tr) +int reg_event_syscall_enter(void *ptr) { - start_ftrace_syscalls(); - - return 0; + int ret = 0; + int num; + char *name; + + name = (char *)ptr; + num = syscall_name_to_nr(name); + if (num < 0 || num >= FTRACE_SYSCALL_MAX) + return -ENOSYS; + mutex_lock(&syscall_trace_lock); + if (!sys_refcount_enter) + ret = register_trace_syscall_enter(ftrace_syscall_enter); + if (ret) { + pr_info("event trace: Could not activate" + "syscall entry trace point"); + } else { + set_bit(num, enabled_enter_syscalls); + sys_refcount_enter++; + } + mutex_unlock(&syscall_trace_lock); + return ret; } -static void reset_syscall_tracer(struct trace_array *tr) +void unreg_event_syscall_enter(void *ptr) { - stop_ftrace_syscalls(); - tracing_reset_online_cpus(tr); -} - -static struct trace_event syscall_enter_event = { - .type = TRACE_SYSCALL_ENTER, - .trace = print_syscall_enter, -}; - -static struct trace_event syscall_exit_event = { - .type = TRACE_SYSCALL_EXIT, - .trace = print_syscall_exit, -}; + int num; + char *name; -static struct tracer syscall_tracer __read_mostly = { - .name = "syscall", - .init = init_syscall_tracer, - .reset = reset_syscall_tracer, - .flags = &syscalls_flags, -}; + name = (char *)ptr; + num = syscall_name_to_nr(name); + if (num < 0 || num >= FTRACE_SYSCALL_MAX) + return; + mutex_lock(&syscall_trace_lock); + sys_refcount_enter--; + clear_bit(num, enabled_enter_syscalls); + if (!sys_refcount_enter) + unregister_trace_syscall_enter(ftrace_syscall_enter); + mutex_unlock(&syscall_trace_lock); +} -__init int register_ftrace_syscalls(void) +int reg_event_syscall_exit(void *ptr) { - int ret; - - ret = register_ftrace_event(&syscall_enter_event); - if (!ret) { - printk(KERN_WARNING "event %d failed to register\n", - syscall_enter_event.type); - WARN_ON_ONCE(1); + int ret = 0; + int num; + char *name; + + name = (char *)ptr; + num = syscall_name_to_nr(name); + if (num < 0 || num >= FTRACE_SYSCALL_MAX) + return -ENOSYS; + mutex_lock(&syscall_trace_lock); + if (!sys_refcount_exit) + ret = register_trace_syscall_exit(ftrace_syscall_exit); + if (ret) { + pr_info("event trace: Could not activate" + "syscall exit trace point"); + } else { + set_bit(num, enabled_exit_syscalls); + sys_refcount_exit++; } + mutex_unlock(&syscall_trace_lock); + return ret; +} - ret = register_ftrace_event(&syscall_exit_event); - if (!ret) { - printk(KERN_WARNING "event %d failed to register\n", - syscall_exit_event.type); - WARN_ON_ONCE(1); - } +void unreg_event_syscall_exit(void *ptr) +{ + int num; + char *name; - return register_tracer(&syscall_tracer); + name = (char *)ptr; + num = syscall_name_to_nr(name); + if (num < 0 || num >= FTRACE_SYSCALL_MAX) + return; + mutex_lock(&syscall_trace_lock); + sys_refcount_exit--; + clear_bit(num, enabled_exit_syscalls); + if (!sys_refcount_exit) + unregister_trace_syscall_exit(ftrace_syscall_exit); + mutex_unlock(&syscall_trace_lock); } -device_initcall(register_ftrace_syscalls); + +struct trace_event event_syscall_enter = { + .trace = print_syscall_enter, + .type = TRACE_SYSCALL_ENTER +}; + +struct trace_event event_syscall_exit = { + .trace = print_syscall_exit, + .type = TRACE_SYSCALL_EXIT +}; -- cgit v0.10.2 From 64c12e0444fcc6b75eb49144ba46d43dbdc6bc8f Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:52:53 -0400 Subject: tracing: Add individual syscalls tracepoint id support The current state of syscalls tracepoints generates only one event id for every syscall events. This patch associates an id with each syscall trace event, so that we can identify each syscall trace event using the 'perf' tool. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 0d93d40..3cff121 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -516,6 +516,16 @@ int syscall_name_to_nr(char *name) return -1; } +void set_syscall_enter_id(int num, int id) +{ + syscalls_metadata[num]->enter_id = id; +} + +void set_syscall_exit_id(int num, int id) +{ + syscalls_metadata[num]->exit_id = id; +} + static int __init arch_init_ftrace_syscalls(void) { int i; diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 5e5b4d3..ce4b01c 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -116,13 +116,20 @@ struct perf_counter_attr; #define SYSCALL_TRACE_ENTER_EVENT(sname) \ static struct ftrace_event_call event_enter_##sname; \ + struct trace_event enter_syscall_print_##sname = { \ + .trace = print_syscall_enter, \ + }; \ static int init_enter_##sname(void) \ { \ - int num; \ + int num, id; \ num = syscall_name_to_nr("sys"#sname); \ if (num < 0) \ return -ENOSYS; \ - register_ftrace_event(&event_syscall_enter); \ + id = register_ftrace_event(&enter_syscall_print_##sname);\ + if (!id) \ + return -ENODEV; \ + event_enter_##sname.id = id; \ + set_syscall_enter_id(num, id); \ INIT_LIST_HEAD(&event_enter_##sname.fields); \ init_preds(&event_enter_##sname); \ return 0; \ @@ -142,13 +149,20 @@ struct perf_counter_attr; #define SYSCALL_TRACE_EXIT_EVENT(sname) \ static struct ftrace_event_call event_exit_##sname; \ + struct trace_event exit_syscall_print_##sname = { \ + .trace = print_syscall_exit, \ + }; \ static int init_exit_##sname(void) \ { \ - int num; \ + int num, id; \ num = syscall_name_to_nr("sys"#sname); \ if (num < 0) \ return -ENOSYS; \ - register_ftrace_event(&event_syscall_exit); \ + id = register_ftrace_event(&exit_syscall_print_##sname);\ + if (!id) \ + return -ENODEV; \ + event_exit_##sname.id = id; \ + set_syscall_exit_id(num, id); \ INIT_LIST_HEAD(&event_exit_##sname.fields); \ init_preds(&event_exit_##sname); \ return 0; \ diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 73fb8b4..df62840 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -32,23 +32,31 @@ DECLARE_TRACE_WITH_CALLBACK(syscall_exit, * @nb_args: number of parameters it takes * @types: list of types as strings * @args: list of args as strings (args[i] matches types[i]) + * @enter_id: associated ftrace enter event id + * @exit_id: associated ftrace exit event id */ struct syscall_metadata { const char *name; int nb_args; const char **types; const char **args; + int enter_id; + int exit_id; }; #ifdef CONFIG_FTRACE_SYSCALLS extern struct syscall_metadata *syscall_nr_to_meta(int nr); extern int syscall_name_to_nr(char *name); +void set_syscall_enter_id(int num, int id); +void set_syscall_exit_id(int num, int id); extern struct trace_event event_syscall_enter; extern struct trace_event event_syscall_exit; extern int reg_event_syscall_enter(void *ptr); extern void unreg_event_syscall_enter(void *ptr); extern int reg_event_syscall_exit(void *ptr); extern void unreg_event_syscall_exit(void *ptr); +enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags); +enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags); #endif #endif /* _TRACE_SYSCALL_H */ diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index d682357..300ef78 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -34,8 +34,6 @@ enum trace_type { TRACE_GRAPH_ENT, TRACE_USER_STACK, TRACE_HW_BRANCHES, - TRACE_SYSCALL_ENTER, - TRACE_SYSCALL_EXIT, TRACE_KMEM_ALLOC, TRACE_KMEM_FREE, TRACE_POWER, @@ -319,10 +317,6 @@ extern void __ftrace_bad_type(void); TRACE_KMEM_ALLOC); \ IF_ASSIGN(var, ent, struct kmemtrace_free_entry, \ TRACE_KMEM_FREE); \ - IF_ASSIGN(var, ent, struct syscall_trace_enter, \ - TRACE_SYSCALL_ENTER); \ - IF_ASSIGN(var, ent, struct syscall_trace_exit, \ - TRACE_SYSCALL_EXIT); \ __ftrace_bad_type(); \ } while (0) diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index c7ae25e..e58a9c1 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -36,14 +36,18 @@ print_syscall_enter(struct trace_iterator *iter, int flags) struct syscall_metadata *entry; int i, ret, syscall; - trace_assign_type(trace, ent); - + trace = (typeof(trace))ent; syscall = trace->nr; - entry = syscall_nr_to_meta(syscall); + if (!entry) goto end; + if (entry->enter_id != ent->type) { + WARN_ON_ONCE(1); + goto end; + } + ret = trace_seq_printf(s, "%s(", entry->name); if (!ret) return TRACE_TYPE_PARTIAL_LINE; @@ -78,16 +82,20 @@ print_syscall_exit(struct trace_iterator *iter, int flags) struct syscall_metadata *entry; int ret; - trace_assign_type(trace, ent); - + trace = (typeof(trace))ent; syscall = trace->nr; - entry = syscall_nr_to_meta(syscall); + if (!entry) { trace_seq_printf(s, "\n"); return TRACE_TYPE_HANDLED; } + if (entry->exit_id != ent->type) { + WARN_ON_ONCE(1); + return TRACE_TYPE_UNHANDLED; + } + ret = trace_seq_printf(s, "%s -> 0x%lx\n", entry->name, trace->ret); if (!ret) @@ -114,7 +122,7 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id) size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args; - event = trace_current_buffer_lock_reserve(TRACE_SYSCALL_ENTER, size, + event = trace_current_buffer_lock_reserve(sys_data->enter_id, size, 0, 0); if (!event) return; @@ -142,7 +150,7 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret) if (!sys_data) return; - event = trace_current_buffer_lock_reserve(TRACE_SYSCALL_EXIT, + event = trace_current_buffer_lock_reserve(sys_data->exit_id, sizeof(*entry), 0, 0); if (!event) return; @@ -239,10 +247,8 @@ void unreg_event_syscall_exit(void *ptr) struct trace_event event_syscall_enter = { .trace = print_syscall_enter, - .type = TRACE_SYSCALL_ENTER }; struct trace_event event_syscall_exit = { .trace = print_syscall_exit, - .type = TRACE_SYSCALL_EXIT }; -- cgit v0.10.2 From f4b5ffccc83c82947f5d9f15d6f1b6edb1b71cd7 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:53:02 -0400 Subject: tracing: Add perf counter support for syscalls tracing The perf counter support is automated for usual trace events. But we have to define specific callbacks for this to handle syscalls trace events Make 'perf stat -e syscalls:sys_enter_blah' work with syscall style tracepoints. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index a9d823a..8e6460f 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h @@ -734,6 +734,8 @@ extern int sysctl_perf_counter_mlock; extern int sysctl_perf_counter_sample_rate; extern void perf_counter_init(void); +extern void perf_tpcounter_event(int event_id, u64 addr, u64 count, + void *record, int entry_size); #ifndef perf_misc_flags #define perf_misc_flags(regs) (user_mode(regs) ? PERF_EVENT_MISC_USER : \ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index ce4b01c..5541e75 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -98,6 +98,53 @@ struct perf_counter_attr; #define __SC_TEST5(t5, a5, ...) __SC_TEST(t5); __SC_TEST4(__VA_ARGS__) #define __SC_TEST6(t6, a6, ...) __SC_TEST(t6); __SC_TEST5(__VA_ARGS__) +#ifdef CONFIG_EVENT_PROFILE +#define TRACE_SYS_ENTER_PROFILE(sname) \ +static int prof_sysenter_enable_##sname(struct ftrace_event_call *event_call) \ +{ \ + int ret = 0; \ + if (!atomic_inc_return(&event_enter_##sname.profile_count)) \ + ret = reg_prof_syscall_enter("sys"#sname); \ + return ret; \ +} \ + \ +static void prof_sysenter_disable_##sname(struct ftrace_event_call *event_call)\ +{ \ + if (atomic_add_negative(-1, &event_enter_##sname.profile_count)) \ + unreg_prof_syscall_enter("sys"#sname); \ +} + +#define TRACE_SYS_EXIT_PROFILE(sname) \ +static int prof_sysexit_enable_##sname(struct ftrace_event_call *event_call) \ +{ \ + int ret = 0; \ + if (!atomic_inc_return(&event_exit_##sname.profile_count)) \ + ret = reg_prof_syscall_exit("sys"#sname); \ + return ret; \ +} \ + \ +static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \ +{ \ + if (atomic_add_negative(-1, &event_exit_##sname.profile_count)) \ + unreg_prof_syscall_exit("sys"#sname); \ +} + +#define TRACE_SYS_ENTER_PROFILE_INIT(sname) \ + .profile_count = ATOMIC_INIT(-1), \ + .profile_enable = prof_sysenter_enable_##sname, \ + .profile_disable = prof_sysenter_disable_##sname, + +#define TRACE_SYS_EXIT_PROFILE_INIT(sname) \ + .profile_count = ATOMIC_INIT(-1), \ + .profile_enable = prof_sysexit_enable_##sname, \ + .profile_disable = prof_sysexit_disable_##sname, +#else +#define TRACE_SYS_ENTER_PROFILE(sname) +#define TRACE_SYS_ENTER_PROFILE_INIT(sname) +#define TRACE_SYS_EXIT_PROFILE(sname) +#define TRACE_SYS_EXIT_PROFILE_INIT(sname) +#endif + #ifdef CONFIG_FTRACE_SYSCALLS #define __SC_STR_ADECL1(t, a) #a #define __SC_STR_ADECL2(t, a, ...) #a, __SC_STR_ADECL1(__VA_ARGS__) @@ -113,7 +160,6 @@ struct perf_counter_attr; #define __SC_STR_TDECL5(t, a, ...) #t, __SC_STR_TDECL4(__VA_ARGS__) #define __SC_STR_TDECL6(t, a, ...) #t, __SC_STR_TDECL5(__VA_ARGS__) - #define SYSCALL_TRACE_ENTER_EVENT(sname) \ static struct ftrace_event_call event_enter_##sname; \ struct trace_event enter_syscall_print_##sname = { \ @@ -134,6 +180,7 @@ struct perf_counter_attr; init_preds(&event_enter_##sname); \ return 0; \ } \ + TRACE_SYS_ENTER_PROFILE(sname); \ static struct ftrace_event_call __used \ __attribute__((__aligned__(4))) \ __attribute__((section("_ftrace_events"))) \ @@ -145,6 +192,7 @@ struct perf_counter_attr; .regfunc = reg_event_syscall_enter, \ .unregfunc = unreg_event_syscall_enter, \ .data = "sys"#sname, \ + TRACE_SYS_ENTER_PROFILE_INIT(sname) \ } #define SYSCALL_TRACE_EXIT_EVENT(sname) \ @@ -167,6 +215,7 @@ struct perf_counter_attr; init_preds(&event_exit_##sname); \ return 0; \ } \ + TRACE_SYS_EXIT_PROFILE(sname); \ static struct ftrace_event_call __used \ __attribute__((__aligned__(4))) \ __attribute__((section("_ftrace_events"))) \ @@ -178,6 +227,7 @@ struct perf_counter_attr; .regfunc = reg_event_syscall_exit, \ .unregfunc = unreg_event_syscall_exit, \ .data = "sys"#sname, \ + TRACE_SYS_EXIT_PROFILE_INIT(sname) \ } #define SYSCALL_METADATA(sname, nb) \ diff --git a/include/trace/syscall.h b/include/trace/syscall.h index df62840..3ab6dd1 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -58,5 +58,12 @@ extern void unreg_event_syscall_exit(void *ptr); enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags); enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags); #endif +#ifdef CONFIG_EVENT_PROFILE +int reg_prof_syscall_enter(char *name); +void unreg_prof_syscall_enter(char *name); +int reg_prof_syscall_exit(char *name); +void unreg_prof_syscall_exit(char *name); + +#endif #endif /* _TRACE_SYSCALL_H */ diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index e58a9c1..f4eaec3 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "trace_output.h" @@ -252,3 +253,123 @@ struct trace_event event_syscall_enter = { struct trace_event event_syscall_exit = { .trace = print_syscall_exit, }; + +#ifdef CONFIG_EVENT_PROFILE +static DECLARE_BITMAP(enabled_prof_enter_syscalls, FTRACE_SYSCALL_MAX); +static DECLARE_BITMAP(enabled_prof_exit_syscalls, FTRACE_SYSCALL_MAX); +static int sys_prof_refcount_enter; +static int sys_prof_refcount_exit; + +static void prof_syscall_enter(struct pt_regs *regs, long id) +{ + struct syscall_metadata *sys_data; + int syscall_nr; + + syscall_nr = syscall_get_nr(current, regs); + if (!test_bit(syscall_nr, enabled_prof_enter_syscalls)) + return; + + sys_data = syscall_nr_to_meta(syscall_nr); + if (!sys_data) + return; + + perf_tpcounter_event(sys_data->enter_id, 0, 1, NULL, 0); +} + +int reg_prof_syscall_enter(char *name) +{ + int ret = 0; + int num; + + num = syscall_name_to_nr(name); + if (num < 0 || num >= FTRACE_SYSCALL_MAX) + return -ENOSYS; + + mutex_lock(&syscall_trace_lock); + if (!sys_prof_refcount_enter) + ret = register_trace_syscall_enter(prof_syscall_enter); + if (ret) { + pr_info("event trace: Could not activate" + "syscall entry trace point"); + } else { + set_bit(num, enabled_prof_enter_syscalls); + sys_prof_refcount_enter++; + } + mutex_unlock(&syscall_trace_lock); + return ret; +} + +void unreg_prof_syscall_enter(char *name) +{ + int num; + + num = syscall_name_to_nr(name); + if (num < 0 || num >= FTRACE_SYSCALL_MAX) + return; + + mutex_lock(&syscall_trace_lock); + sys_prof_refcount_enter--; + clear_bit(num, enabled_prof_enter_syscalls); + if (!sys_prof_refcount_enter) + unregister_trace_syscall_enter(prof_syscall_enter); + mutex_unlock(&syscall_trace_lock); +} + +static void prof_syscall_exit(struct pt_regs *regs, long ret) +{ + struct syscall_metadata *sys_data; + int syscall_nr; + + syscall_nr = syscall_get_nr(current, regs); + if (!test_bit(syscall_nr, enabled_prof_exit_syscalls)) + return; + + sys_data = syscall_nr_to_meta(syscall_nr); + if (!sys_data) + return; + + perf_tpcounter_event(sys_data->exit_id, 0, 1, NULL, 0); +} + +int reg_prof_syscall_exit(char *name) +{ + int ret = 0; + int num; + + num = syscall_name_to_nr(name); + if (num < 0 || num >= FTRACE_SYSCALL_MAX) + return -ENOSYS; + + mutex_lock(&syscall_trace_lock); + if (!sys_prof_refcount_exit) + ret = register_trace_syscall_exit(prof_syscall_exit); + if (ret) { + pr_info("event trace: Could not activate" + "syscall entry trace point"); + } else { + set_bit(num, enabled_prof_exit_syscalls); + sys_prof_refcount_exit++; + } + mutex_unlock(&syscall_trace_lock); + return ret; +} + +void unreg_prof_syscall_exit(char *name) +{ + int num; + + num = syscall_name_to_nr(name); + if (num < 0 || num >= FTRACE_SYSCALL_MAX) + return; + + mutex_lock(&syscall_trace_lock); + sys_prof_refcount_exit--; + clear_bit(num, enabled_prof_exit_syscalls); + if (!sys_prof_refcount_exit) + unregister_trace_syscall_exit(prof_syscall_exit); + mutex_unlock(&syscall_trace_lock); +} + +#endif + + -- cgit v0.10.2 From 48c2e17f1f668fe6691bad965beb2b0b25239c5f Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:53:06 -0400 Subject: tracing: Add more namespace area to 'perf list' output The new syscall tracepoints names can be too long for the 'perf list' output. Add a few more characters. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4858d83..a5d661b 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -606,7 +606,7 @@ static void print_tracepoint_events(void) evt_path, st) { snprintf(evt_path, MAXPATHLEN, "%s:%s", sys_dirent.d_name, evt_dirent.d_name); - fprintf(stderr, " %-40s [%s]\n", evt_path, + fprintf(stderr, " %-42s [%s]\n", evt_path, event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); } closedir(evt_dir); @@ -640,7 +640,7 @@ void print_events(void) sprintf(name, "%s OR %s", syms->symbol, syms->alias); else strcpy(name, syms->symbol); - fprintf(stderr, " %-40s [%s]\n", name, + fprintf(stderr, " %-42s [%s]\n", name, event_type_descriptors[type]); prev_type = type; @@ -654,7 +654,7 @@ void print_events(void) continue; for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { - fprintf(stderr, " %-40s [%s]\n", + fprintf(stderr, " %-42s [%s]\n", event_cache_name(type, op, i), event_type_descriptors[4]); } @@ -662,7 +662,7 @@ void print_events(void) } fprintf(stderr, "\n"); - fprintf(stderr, " %-40s [raw hardware event descriptor]\n", + fprintf(stderr, " %-42s [raw hardware event descriptor]\n", "rNNN"); fprintf(stderr, "\n"); -- cgit v0.10.2 From 0ac676fb50f5f8a22e5e80afc40bf38e31b77c00 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 10 Aug 2009 16:53:11 -0400 Subject: tracing: Convert x86_64 mmap and uname to use DEFINE_SYSCALL A number of syscalls are not using 'DEFINE_SYSCALL'. I'm not sure why. Convert x86_64 uname and mmap to use DEFINE_SYSCALL. Signed-off-by: Jason Baron Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 6bc211a..45e00eb 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -18,9 +18,9 @@ #include #include -asmlinkage long sys_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long off) +SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, + unsigned long, prot, unsigned long, flags, + unsigned long, fd, unsigned long, off) { long error; struct file *file; @@ -226,7 +226,7 @@ bottomup: } -asmlinkage long sys_uname(struct new_utsname __user *name) +SYSCALL_DEFINE1(uname, struct new_utsname __user *, name) { int err; down_read(&uts_sem); -- cgit v0.10.2 From e8f9f4d79a677f55c8ec3acbe87b33a87e2df0de Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Tue, 11 Aug 2009 17:42:52 +0200 Subject: tracing: Add ftrace event call parameter to its field descriptor handler Add the struct ftrace_event_call as a parameter of its show_format() callback. This way we can use it from the syscall trace events to retrieve the syscall name from the ftrace event call parameter and describe its fields using the syscalls metadata. Signed-off-by: Frederic Weisbecker Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Cc: Jason Baron diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 8544f12..189806b 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -116,7 +116,8 @@ struct ftrace_event_call { void (*unregfunc)(void *); int id; int (*raw_init)(void); - int (*show_format)(struct trace_seq *s); + int (*show_format)(struct ftrace_event_call *call, + struct trace_seq *s); int (*define_fields)(void); struct list_head fields; int filter_active; diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 46d81b5..b250b06 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -151,7 +151,8 @@ #undef TRACE_EVENT #define TRACE_EVENT(call, proto, args, tstruct, func, print) \ static int \ -ftrace_format_##call(struct trace_seq *s) \ +ftrace_format_##call(struct ftrace_event_call *unused, \ + struct trace_seq *s) \ { \ struct ftrace_raw_##call field __attribute__((unused)); \ int ret = 0; \ diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 1d289e2..b568ade 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -576,7 +576,7 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt, trace_seq_printf(s, "format:\n"); trace_write_header(s); - r = call->show_format(s); + r = call->show_format(call, s); if (!r) { /* * ug! The format output is bigger than a PAGE!! diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index d06cf89..956d4bc 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c @@ -60,7 +60,8 @@ extern void __bad_type_size(void); #undef TRACE_EVENT_FORMAT #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ static int \ -ftrace_format_##call(struct trace_seq *s) \ +ftrace_format_##call(struct ftrace_event_call *unused, \ + struct trace_seq *s) \ { \ struct args field; \ int ret; \ @@ -76,7 +77,8 @@ ftrace_format_##call(struct trace_seq *s) \ #define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct, \ tpfmt) \ static int \ -ftrace_format_##call(struct trace_seq *s) \ +ftrace_format_##call(struct ftrace_event_call *unused, \ + struct trace_seq *s) \ { \ struct args field; \ int ret; \ -- cgit v0.10.2 From dc4ddb4c0b7348f1c9759ae8a9e7d734dc1cda82 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Tue, 11 Aug 2009 19:03:54 +0200 Subject: tracing: Add fields format definition for syscall events Define the format of the syscall trace fields to parse the binary values from a raw trace using the syscall events "format" file. This is defined dynamically using the syscalls metadata. It prepares the export of syscall event raw records to perf counters. Example: $ cat /debug/tracing/events/syscalls/sys_enter_sched_getparam/format name: sys_enter_sched_getparam ID: 39 format: field:unsigned short common_type; offset:0; size:2; field:unsigned char common_flags; offset:2; size:1; field:unsigned char common_preempt_count; offset:3; size:1; field:int common_pid; offset:4; size:4; field:int common_tgid; offset:8; size:4; field:pid_t pid; offset:12; size:8; field:struct sched_param * param; offset:20; size:8; print fmt: "pid: 0x%08lx, param: 0x%08lx", ((unsigned long)(REC->pid)), ((unsigned long)(REC->param)) Signed-off-by: Frederic Weisbecker Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Masami Hiramatsu Cc: Jason Baron diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 5541e75..87d06c1 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -189,6 +189,7 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \ .system = "syscalls", \ .event = &event_syscall_enter, \ .raw_init = init_enter_##sname, \ + .show_format = ftrace_format_syscall, \ .regfunc = reg_event_syscall_enter, \ .unregfunc = unreg_event_syscall_enter, \ .data = "sys"#sname, \ diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 3ab6dd1..0cb0362 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -55,6 +55,8 @@ extern int reg_event_syscall_enter(void *ptr); extern void unreg_event_syscall_enter(void *ptr); extern int reg_event_syscall_exit(void *ptr); extern void unreg_event_syscall_exit(void *ptr); +extern int +ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s); enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags); enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags); #endif diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index f4eaec3..9ee6386 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -105,6 +105,52 @@ print_syscall_exit(struct trace_iterator *iter, int flags) return TRACE_TYPE_HANDLED; } +int ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s) +{ + int i; + int nr; + int ret = 0; + struct syscall_metadata *entry; + int offset = sizeof(struct trace_entry); + + nr = syscall_name_to_nr((char *)call->data); + entry = syscall_nr_to_meta(nr); + + if (!entry) + return ret; + + for (i = 0; i < entry->nb_args; i++) { + ret = trace_seq_printf(s, "\tfield:%s %s;", entry->types[i], + entry->args[i]); + if (!ret) + return 0; + ret = trace_seq_printf(s, "\toffset:%d;\tsize:%lu;\n", offset, + sizeof(unsigned long)); + if (!ret) + return 0; + offset += sizeof(unsigned long); + } + + trace_seq_printf(s, "\nprint fmt: \""); + for (i = 0; i < entry->nb_args; i++) { + ret = trace_seq_printf(s, "%s: 0x%%0%lulx%s", entry->args[i], + sizeof(unsigned long), + i == entry->nb_args - 1 ? "\", " : ", "); + if (!ret) + return 0; + } + + for (i = 0; i < entry->nb_args; i++) { + ret = trace_seq_printf(s, "((unsigned long)(REC->%s))%s", + entry->args[i], + i == entry->nb_args - 1 ? "\n" : ", "); + if (!ret) + return 0; + } + + return ret; +} + void ftrace_syscall_enter(struct pt_regs *regs, long id) { struct syscall_trace_enter *entry; -- cgit v0.10.2 From 19007a67a64f9b3cbbd7024f972654ebf14daade Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Tue, 11 Aug 2009 20:22:53 +0200 Subject: tracing: Support for syscall events raw records in perfcounters This bring the support for raw syscall events in perfcounters. The arguments or exit value are saved as a raw sample using the PERF_SAMPLE_RAW attribute in a perf counter. Example (for now you must explicitly set the PERF_SAMPLE_RAW flag in perf record): perf record -e syscalls:sys_enter_open -f -F 1 -a perf report -D 0x2cbb8 [0x50]: event: 9 . . ... raw event: size 80 bytes . 0000: 09 00 00 00 02 00 50 00 20 e9 39 ab 0a 7f 00 00 ......P. .9.... . 0010: bc 14 00 00 bc 14 00 00 01 00 00 00 00 00 00 00 ............... . 0020: 2c 00 00 00 15 01 01 00 bc 14 00 00 bc 14 00 00 ,.............. ^ ^ ^ ^ ^ ^ ^ .......................... Event Size struct trace_entry . 0030: 00 00 00 00 46 98 43 02 00 00 00 00 80 08 00 00 ....F.C........ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ptr to file name open flags . 0040: 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 ............... ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . open mode padding 0x2cbb8 [0x50]: PERF_EVENT_SAMPLE (IP, 2): 5308: 0x7f0aab39e920 period: 1 Signed-off-by: Frederic Weisbecker Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Jason Baron Cc: Masami Hiramatsu diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 9ee6386..f837ccc 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -301,6 +301,17 @@ struct trace_event event_syscall_exit = { }; #ifdef CONFIG_EVENT_PROFILE + +struct syscall_enter_record { + struct trace_entry entry; + unsigned long args[0]; +}; + +struct syscall_exit_record { + struct trace_entry entry; + unsigned long ret; +}; + static DECLARE_BITMAP(enabled_prof_enter_syscalls, FTRACE_SYSCALL_MAX); static DECLARE_BITMAP(enabled_prof_exit_syscalls, FTRACE_SYSCALL_MAX); static int sys_prof_refcount_enter; @@ -308,8 +319,10 @@ static int sys_prof_refcount_exit; static void prof_syscall_enter(struct pt_regs *regs, long id) { + struct syscall_enter_record *rec; struct syscall_metadata *sys_data; int syscall_nr; + int size; syscall_nr = syscall_get_nr(current, regs); if (!test_bit(syscall_nr, enabled_prof_enter_syscalls)) @@ -319,7 +332,24 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) if (!sys_data) return; - perf_tpcounter_event(sys_data->enter_id, 0, 1, NULL, 0); + /* get the size after alignment with the u32 buffer size field */ + size = sizeof(unsigned long) * sys_data->nb_args + sizeof(*rec); + size = ALIGN(size + sizeof(u32), sizeof(u64)); + size -= sizeof(u32); + + do { + char raw_data[size]; + + /* zero the dead bytes from align to not leak stack to user */ + *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; + + rec = (struct syscall_enter_record *) raw_data; + tracing_generic_entry_update(&rec->entry, 0, 0); + rec->entry.type = sys_data->enter_id; + syscall_get_arguments(current, regs, 0, sys_data->nb_args, + (unsigned long *)&rec->args); + perf_tpcounter_event(sys_data->enter_id, 0, 1, rec, size); + } while(0); } int reg_prof_syscall_enter(char *name) @@ -364,6 +394,7 @@ void unreg_prof_syscall_enter(char *name) static void prof_syscall_exit(struct pt_regs *regs, long ret) { struct syscall_metadata *sys_data; + struct syscall_exit_record rec; int syscall_nr; syscall_nr = syscall_get_nr(current, regs); @@ -374,7 +405,11 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) if (!sys_data) return; - perf_tpcounter_event(sys_data->exit_id, 0, 1, NULL, 0); + tracing_generic_entry_update(&rec.entry, 0, 0); + rec.entry.type = sys_data->exit_id; + rec.ret = syscall_get_return_value(current, regs); + + perf_tpcounter_event(sys_data->exit_id, 0, 1, &rec, sizeof(rec)); } int reg_prof_syscall_exit(char *name) -- cgit v0.10.2 From 5908589f318835f515bf94829650d36dcb2d9024 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Tue, 11 Aug 2009 22:33:09 -0300 Subject: ALSA: hda - fix noise issue when recording from digital mic with alc268 With auto config model of alc268 realtek codec, it allows to select any of possible available digital microphone inputs when only one is available. For example, when only digital mic in nid 0x12 is available, on second input source it will allow you to select unavailable digital mic in nid 0x13. The problem is that selecting unavailable digital mic creates a source of noise when recording (I'm not sure if this happens on all machines with alc268 and only one digital mic input, but testing on a quanta uw1 netbook a lot of noise is introduced in recording from digital mic 0x12/first input source, when you select the unavailable digital mic 0x13 for capture source 0x24 in the second input source in mixer). Then to avoid noise when recording from digital mic with auto model in this case, prevent a digital mic input source to be selected if microphone is not available. Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ac3207e..7ff2934 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -12232,32 +12232,40 @@ static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { struct hda_input_mux *imux = &spec->private_imux[0]; - int i, idx1; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - switch(cfg->input_pins[i]) { - case 0x18: - idx1 = 0; /* Mic 1 */ - break; - case 0x19: - idx1 = 1; /* Mic 2 */ - break; - case 0x1a: - idx1 = 2; /* Line In */ - break; - case 0x1c: - idx1 = 3; /* CD */ - break; - case 0x12: - case 0x13: - idx1 = 6; /* digital mics */ - break; - default: - continue; + int i, idx1, dmic_nid; + + dmic_nid = 0x12; + while (dmic_nid <= 0x13) { + for (i = 0; i < AUTO_PIN_LAST; i++) { + switch (cfg->input_pins[i]) { + case 0x18: + idx1 = 0; /* Mic 1 */ + break; + case 0x19: + idx1 = 1; /* Mic 2 */ + break; + case 0x1a: + idx1 = 2; /* Line In */ + break; + case 0x1c: + idx1 = 3; /* CD */ + break; + case 0x12: + case 0x13: + if (cfg->input_pins[i] != dmic_nid) + continue; + idx1 = 6; /* digital mics */ + break; + default: + continue; + } + imux->items[imux->num_items].label = + auto_pin_cfg_labels[i]; + imux->items[imux->num_items].index = idx1; + imux->num_items++; } - imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = idx1; - imux->num_items++; + imux++; + dmic_nid++; } return 0; } @@ -12355,7 +12363,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) add_mixer(spec, alc268_beep_mixer); add_verb(spec, alc268_volume_init_verbs); - spec->num_mux_defs = 1; + spec->num_mux_defs = 2; spec->input_mux = &spec->private_imux[0]; err = alc_auto_add_mic_boost(codec); @@ -12665,6 +12673,8 @@ static int patch_alc268(struct hda_codec *codec) for (i = 0; i < spec->num_adc_nids; i++) snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i], 0, AC_VERB_SET_CONNECT_SEL, + i < spec->num_mux_defs ? + spec->input_mux[i].items[0].index : spec->input_mux->items[0].index); } -- cgit v0.10.2 From cd84c2ac6d6425dd4d1b80a2231e534b9b03df18 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 12 Aug 2009 10:03:49 +0200 Subject: perf tools: Factorize high level dso helpers Factorize multiple definitions of high level dso helpers into the symbol source file. The side effect is a general export of the verbose and eprintf debugging helpers into a new file dedicated to debugging purposes. Signed-off-by: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Brice Goglin diff --git a/tools/perf/Makefile b/tools/perf/Makefile index de7beac..2aee21b 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -339,6 +339,7 @@ LIB_OBJS += util/pager.o LIB_OBJS += util/header.o LIB_OBJS += util/callchain.o LIB_OBJS += util/values.o +LIB_OBJS += util/debug.o BUILTIN_OBJS += builtin-annotate.o BUILTIN_OBJS += builtin-help.o diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 1dba568..1a79299 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -26,7 +26,6 @@ #define SHOW_HV 4 static char const *input_name = "perf.data"; -static char *vmlinux = "vmlinux"; static char default_sort_order[] = "comm,symbol"; static char *sort_order = default_sort_order; @@ -37,9 +36,6 @@ static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; static int dump_trace = 0; #define dprintf(x...) do { if (dump_trace) printf(x); } while (0) -static int verbose; - -static int modules; static int full_paths; @@ -89,98 +85,6 @@ struct sym_ext { char *path; }; -static LIST_HEAD(dsos); -static struct dso *kernel_dso; -static struct dso *vdso; - - -static void dsos__add(struct dso *dso) -{ - list_add_tail(&dso->node, &dsos); -} - -static struct dso *dsos__find(const char *name) -{ - struct dso *pos; - - list_for_each_entry(pos, &dsos, node) - if (strcmp(pos->name, name) == 0) - return pos; - return NULL; -} - -static struct dso *dsos__findnew(const char *name) -{ - struct dso *dso = dsos__find(name); - int nr; - - if (dso) - return dso; - - dso = dso__new(name, 0); - if (!dso) - goto out_delete_dso; - - nr = dso__load(dso, NULL, verbose); - if (nr < 0) { - if (verbose) - fprintf(stderr, "Failed to open: %s\n", name); - goto out_delete_dso; - } - if (!nr && verbose) { - fprintf(stderr, - "No symbols found in: %s, maybe install a debug package?\n", - name); - } - - dsos__add(dso); - - return dso; - -out_delete_dso: - dso__delete(dso); - return NULL; -} - -static void dsos__fprintf(FILE *fp) -{ - struct dso *pos; - - list_for_each_entry(pos, &dsos, node) - dso__fprintf(pos, fp); -} - -static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) -{ - return dso__find_symbol(dso, ip); -} - -static int load_kernel(void) -{ - int err; - - kernel_dso = dso__new("[kernel]", 0); - if (!kernel_dso) - return -1; - - err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules); - if (err <= 0) { - dso__delete(kernel_dso); - kernel_dso = NULL; - } else - dsos__add(kernel_dso); - - vdso = dso__new("[vdso]", 0); - if (!vdso) - return -1; - - vdso->find_symbol = vdso__find_symbol; - - dsos__add(vdso); - - return err; -} - struct map { struct list_head node; u64 start; diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0345aad..afae387 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -40,7 +40,6 @@ static int inherit = 1; static int force = 0; static int append_file = 0; static int call_graph = 0; -static int verbose = 0; static int inherit_stat = 0; static int no_samples = 0; static int sample_address = 0; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 2357c66..827eab2 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -30,7 +30,6 @@ #define SHOW_HV 4 static char const *input_name = "perf.data"; -static char *vmlinux = NULL; static char default_sort_order[] = "comm,dso,symbol"; static char *sort_order = default_sort_order; @@ -46,11 +45,6 @@ static int dump_trace = 0; #define dprintf(x...) do { if (dump_trace) printf(x); } while (0) #define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0) -static int verbose; -#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0) - -static int modules; - static int full_paths; static int show_nr_samples; @@ -161,98 +155,7 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...) return n; } -static LIST_HEAD(dsos); -static struct dso *kernel_dso; -static struct dso *vdso; -static struct dso *hypervisor_dso; - -static void dsos__add(struct dso *dso) -{ - list_add_tail(&dso->node, &dsos); -} - -static struct dso *dsos__find(const char *name) -{ - struct dso *pos; - - list_for_each_entry(pos, &dsos, node) - if (strcmp(pos->name, name) == 0) - return pos; - return NULL; -} - -static struct dso *dsos__findnew(const char *name) -{ - struct dso *dso = dsos__find(name); - int nr; - - if (dso) - return dso; - - dso = dso__new(name, 0); - if (!dso) - goto out_delete_dso; - - nr = dso__load(dso, NULL, verbose); - if (nr < 0) { - eprintf("Failed to open: %s\n", name); - goto out_delete_dso; - } - if (!nr) - eprintf("No symbols found in: %s, maybe install a debug package?\n", name); - - dsos__add(dso); - - return dso; - -out_delete_dso: - dso__delete(dso); - return NULL; -} - -static void dsos__fprintf(FILE *fp) -{ - struct dso *pos; - - list_for_each_entry(pos, &dsos, node) - dso__fprintf(pos, fp); -} - -static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) -{ - return dso__find_symbol(dso, ip); -} - -static int load_kernel(void) -{ - int err; - - kernel_dso = dso__new("[kernel]", 0); - if (!kernel_dso) - return -1; - - err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules); - if (err <= 0) { - dso__delete(kernel_dso); - kernel_dso = NULL; - } else - dsos__add(kernel_dso); - - vdso = dso__new("[vdso]", 0); - if (!vdso) - return -1; - vdso->find_symbol = vdso__find_symbol; - - dsos__add(vdso); - - hypervisor_dso = dso__new("[hypervisor]", 0); - if (!hypervisor_dso) - return -1; - dsos__add(hypervisor_dso); - - return err; -} static char __cwd[PATH_MAX]; static char *cwd = __cwd; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index b4b06c7..4b9dd4a 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -63,7 +63,6 @@ static struct perf_counter_attr default_attrs[] = { #define MAX_RUN 100 static int system_wide = 0; -static int verbose = 0; static unsigned int nr_cpus = 0; static int run_idx = 0; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7de28ce..0aa5673 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -68,8 +68,6 @@ static int group = 0; static unsigned int page_size; static unsigned int mmap_pages = 16; static int freq = 0; -static int verbose = 0; -static char *vmlinux = NULL; static int delay_secs = 2; static int zero; @@ -338,8 +336,6 @@ static void show_details(struct sym_entry *syme) printf("%d lines not displayed, maybe increase display entries [e]\n", more); } -struct dso *kernel_dso; - /* * Symbols will be added here in record_ip and will get out * after decayed. diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index 51d1682..3a63e41 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h @@ -22,5 +22,6 @@ extern int cmd_stat(int argc, const char **argv, const char *prefix); extern int cmd_top(int argc, const char **argv, const char *prefix); extern int cmd_version(int argc, const char **argv, const char *prefix); extern int cmd_list(int argc, const char **argv, const char *prefix); +extern int cmd_trace(int argc, const char **argv, const char *prefix); #endif diff --git a/tools/perf/perf.h b/tools/perf/perf.h index e5148e2..f550921 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -48,6 +48,7 @@ #include "../../include/linux/perf_counter.h" #include "util/types.h" +#include "util/debug.h" /* * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c new file mode 100644 index 0000000..7cb8464 --- /dev/null +++ b/tools/perf/util/debug.c @@ -0,0 +1,22 @@ +/* For general debugging purposes */ + +#include "../perf.h" +#include +#include +#include + +int verbose = 0; + +int eprintf(const char *fmt, ...) +{ + va_list args; + int ret = 0; + + if (verbose) { + va_start(args, fmt); + ret = vfprintf(stderr, fmt, args); + va_end(args); + } + + return ret; +} diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h new file mode 100644 index 0000000..2ae9090 --- /dev/null +++ b/tools/perf/util/debug.h @@ -0,0 +1,5 @@ +/* For debugging general purposes */ + +extern int verbose; + +int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index f1dcede..e9b13b4 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -937,6 +937,103 @@ int dso__load_kernel(struct dso *self, const char *vmlinux, return err; } +LIST_HEAD(dsos); +struct dso *kernel_dso; +struct dso *vdso; +struct dso *hypervisor_dso; + +char *vmlinux = "vmlinux"; +int modules; + +static void dsos__add(struct dso *dso) +{ + list_add_tail(&dso->node, &dsos); +} + +static struct dso *dsos__find(const char *name) +{ + struct dso *pos; + + list_for_each_entry(pos, &dsos, node) + if (strcmp(pos->name, name) == 0) + return pos; + return NULL; +} + +struct dso *dsos__findnew(const char *name) +{ + struct dso *dso = dsos__find(name); + int nr; + + if (dso) + return dso; + + dso = dso__new(name, 0); + if (!dso) + goto out_delete_dso; + + nr = dso__load(dso, NULL, verbose); + if (nr < 0) { + eprintf("Failed to open: %s\n", name); + goto out_delete_dso; + } + if (!nr) + eprintf("No symbols found in: %s, maybe install a debug package?\n", name); + + dsos__add(dso); + + return dso; + +out_delete_dso: + dso__delete(dso); + return NULL; +} + +void dsos__fprintf(FILE *fp) +{ + struct dso *pos; + + list_for_each_entry(pos, &dsos, node) + dso__fprintf(pos, fp); +} + +static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) +{ + return dso__find_symbol(dso, ip); +} + +int load_kernel(void) +{ + int err; + + kernel_dso = dso__new("[kernel]", 0); + if (!kernel_dso) + return -1; + + err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules); + if (err <= 0) { + dso__delete(kernel_dso); + kernel_dso = NULL; + } else + dsos__add(kernel_dso); + + vdso = dso__new("[vdso]", 0); + if (!vdso) + return -1; + + vdso->find_symbol = vdso__find_symbol; + + dsos__add(vdso); + + hypervisor_dso = dso__new("[hypervisor]", 0); + if (!hypervisor_dso) + return -1; + dsos__add(hypervisor_dso); + + return err; +} + + void symbol__init(void) { elf_version(EV_CURRENT); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 1e003ec..f3490fc 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -48,9 +48,20 @@ int dso__load_kernel(struct dso *self, const char *vmlinux, symbol_filter_t filter, int verbose, int modules); int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); int dso__load(struct dso *self, symbol_filter_t filter, int verbose); +struct dso *dsos__findnew(const char *name); +void dsos__fprintf(FILE *fp); size_t dso__fprintf(struct dso *self, FILE *fp); char dso__symtab_origin(const struct dso *self); +int load_kernel(void); + void symbol__init(void); + +extern struct list_head dsos; +extern struct dso *kernel_dso; +extern struct dso *vdso; +extern struct dso *hypervisor_dso; +extern char *vmlinux; +extern int modules; #endif /* _PERF_SYMBOL_ */ -- cgit v0.10.2 From 1fe2c1066ce6a30bda7b27785ee3d9b8e62ffbbd Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 12 Aug 2009 10:19:53 +0200 Subject: perf tools: Factorize the event structure definitions in a single file Factorize the multiple definition of the events structures into a single util/event.h file. Signed-off-by: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Brice Goglin diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 1a79299..fee663a 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -44,40 +44,6 @@ static int print_line; static unsigned long page_size; static unsigned long mmap_window = 32; -struct ip_event { - struct perf_event_header header; - u64 ip; - u32 pid, tid; -}; - -struct mmap_event { - struct perf_event_header header; - u32 pid, tid; - u64 start; - u64 len; - u64 pgoff; - char filename[PATH_MAX]; -}; - -struct comm_event { - struct perf_event_header header; - u32 pid, tid; - char comm[16]; -}; - -struct fork_event { - struct perf_event_header header; - u32 pid, ppid; -}; - -typedef union event_union { - struct perf_event_header header; - struct ip_event ip; - struct mmap_event mmap; - struct comm_event comm; - struct fork_event fork; -} event_t; - struct sym_ext { struct rb_node node; diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index afae387..718b8f7 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -59,24 +59,6 @@ static int file_new = 1; struct perf_header *header; -struct mmap_event { - struct perf_event_header header; - u32 pid; - u32 tid; - u64 start; - u64 len; - u64 pgoff; - char filename[PATH_MAX]; -}; - -struct comm_event { - struct perf_event_header header; - u32 pid; - u32 tid; - char comm[16]; -}; - - struct mmap_data { int counter; void *base; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 827eab2..1efefcc 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -75,59 +75,6 @@ struct callchain_param callchain_param = { static u64 sample_type; -struct ip_event { - struct perf_event_header header; - u64 ip; - u32 pid, tid; - unsigned char __more_data[]; -}; - -struct mmap_event { - struct perf_event_header header; - u32 pid, tid; - u64 start; - u64 len; - u64 pgoff; - char filename[PATH_MAX]; -}; - -struct comm_event { - struct perf_event_header header; - u32 pid, tid; - char comm[16]; -}; - -struct fork_event { - struct perf_event_header header; - u32 pid, ppid; - u32 tid, ptid; -}; - -struct lost_event { - struct perf_event_header header; - u64 id; - u64 lost; -}; - -struct read_event { - struct perf_event_header header; - u32 pid,tid; - u64 value; - u64 time_enabled; - u64 time_running; - u64 id; -}; - -typedef union event_union { - struct perf_event_header header; - struct ip_event ip; - struct mmap_event mmap; - struct comm_event comm; - struct fork_event fork; - struct lost_event lost; - struct read_event read; -} event_t; - static int repsep_fprintf(FILE *fp, const char *fmt, ...) { int n; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 0aa5673..9a6dbbf 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -933,26 +933,6 @@ static void mmap_read_counter(struct mmap_data *md) last_read = this_read; for (; old != head;) { - struct ip_event { - struct perf_event_header header; - u64 ip; - u32 pid, target_pid; - }; - struct mmap_event { - struct perf_event_header header; - u32 pid, target_pid; - u64 start; - u64 len; - u64 pgoff; - char filename[PATH_MAX]; - }; - - typedef union event_union { - struct perf_event_header header; - struct ip_event ip; - struct mmap_event mmap; - } event_t; - event_t *event = (event_t *)&data[old & md->mask]; event_t event_copy; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h new file mode 100644 index 0000000..91e2fe5 --- /dev/null +++ b/tools/perf/util/event.h @@ -0,0 +1,54 @@ +#include "../perf.h" + +struct ip_event { + struct perf_event_header header; + u64 ip; + u32 pid, tid; + unsigned char __more_data[]; +}; + +struct mmap_event { + struct perf_event_header header; + u32 pid, tid; + u64 start; + u64 len; + u64 pgoff; + char filename[PATH_MAX]; +}; + +struct comm_event { + struct perf_event_header header; + u32 pid, tid; + char comm[16]; +}; + +struct fork_event { + struct perf_event_header header; + u32 pid, ppid; + u32 tid, ptid; +}; + +struct lost_event { + struct perf_event_header header; + u64 id; + u64 lost; +}; + +struct read_event { + struct perf_event_header header; + u32 pid,tid; + u64 value; + u64 time_enabled; + u64 time_running; + u64 id; +}; + +typedef union event_union { + struct perf_event_header header; + struct ip_event ip; + struct mmap_event mmap; + struct comm_event comm; + struct fork_event fork; + struct lost_event lost; + struct read_event read; +} event_t; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 68fe157..be4b52c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -83,6 +83,8 @@ #include #include "../../../include/linux/magic.h" +#include "event.h" + #ifndef NO_ICONV #include #endif -- cgit v0.10.2 From 66e274f3b8d7fc89d38997e85b900e188f8d5cc0 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 12 Aug 2009 11:07:25 +0200 Subject: perf tools: Factorize the map helpers Factorize the dso mapping helpers into a single purpose common file "util/map.c" Signed-off-by: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Brice Goglin diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 2aee21b..cb9033d 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -340,6 +340,7 @@ LIB_OBJS += util/header.o LIB_OBJS += util/callchain.o LIB_OBJS += util/values.o LIB_OBJS += util/debug.o +LIB_OBJS += util/map.o BUILTIN_OBJS += builtin-annotate.o BUILTIN_OBJS += builtin-help.o diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index fee663a..543c452 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -51,83 +51,6 @@ struct sym_ext { char *path; }; -struct map { - struct list_head node; - u64 start; - u64 end; - u64 pgoff; - u64 (*map_ip)(struct map *, u64); - struct dso *dso; -}; - -static u64 map__map_ip(struct map *map, u64 ip) -{ - return ip - map->start + map->pgoff; -} - -static u64 vdso__map_ip(struct map *map __used, u64 ip) -{ - return ip; -} - -static struct map *map__new(struct mmap_event *event) -{ - struct map *self = malloc(sizeof(*self)); - - if (self != NULL) { - const char *filename = event->filename; - - self->start = event->start; - self->end = event->start + event->len; - self->pgoff = event->pgoff; - - self->dso = dsos__findnew(filename); - if (self->dso == NULL) - goto out_delete; - - if (self->dso == vdso) - self->map_ip = vdso__map_ip; - else - self->map_ip = map__map_ip; - } - return self; -out_delete: - free(self); - return NULL; -} - -static struct map *map__clone(struct map *self) -{ - struct map *map = malloc(sizeof(*self)); - - if (!map) - return NULL; - - memcpy(map, self, sizeof(*self)); - - return map; -} - -static int map__overlap(struct map *l, struct map *r) -{ - if (l->start > r->start) { - struct map *t = l; - l = r; - r = t; - } - - if (l->end > r->start) - return 1; - - return 0; -} - -static size_t map__fprintf(struct map *self, FILE *fp) -{ - return fprintf(fp, " %Lx-%Lx %Lx %s\n", - self->start, self->end, self->pgoff, self->dso->name); -} - struct thread { struct rb_node rb_node; @@ -797,7 +720,7 @@ static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { struct thread *thread = threads__findnew(event->mmap.pid); - struct map *map = map__new(&event->mmap); + struct map *map = map__new(&event->mmap, NULL, 0); dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 718b8f7..106c6ab 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -15,6 +15,7 @@ #include "util/string.h" #include "util/header.h" +#include "util/event.h" #include #include diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1efefcc..93945ec 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -67,6 +67,10 @@ static char callchain_default_opt[] = "fractal,0.5"; static int callchain; +static char __cwd[PATH_MAX]; +static char *cwd = __cwd; +static int cwdlen; + static struct callchain_param callchain_param = { .mode = CHAIN_GRAPH_REL, @@ -102,124 +106,6 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...) return n; } - - -static char __cwd[PATH_MAX]; -static char *cwd = __cwd; -static int cwdlen; - -static int strcommon(const char *pathname) -{ - int n = 0; - - while (n < cwdlen && pathname[n] == cwd[n]) - ++n; - - return n; -} - -struct map { - struct list_head node; - u64 start; - u64 end; - u64 pgoff; - u64 (*map_ip)(struct map *, u64); - struct dso *dso; -}; - -static u64 map__map_ip(struct map *map, u64 ip) -{ - return ip - map->start + map->pgoff; -} - -static u64 vdso__map_ip(struct map *map __used, u64 ip) -{ - return ip; -} - -static inline int is_anon_memory(const char *filename) -{ - return strcmp(filename, "//anon") == 0; -} - -static struct map *map__new(struct mmap_event *event) -{ - struct map *self = malloc(sizeof(*self)); - - if (self != NULL) { - const char *filename = event->filename; - char newfilename[PATH_MAX]; - int anon; - - if (cwd) { - int n = strcommon(filename); - - if (n == cwdlen) { - snprintf(newfilename, sizeof(newfilename), - ".%s", filename + n); - filename = newfilename; - } - } - - anon = is_anon_memory(filename); - - if (anon) { - snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid); - filename = newfilename; - } - - self->start = event->start; - self->end = event->start + event->len; - self->pgoff = event->pgoff; - - self->dso = dsos__findnew(filename); - if (self->dso == NULL) - goto out_delete; - - if (self->dso == vdso || anon) - self->map_ip = vdso__map_ip; - else - self->map_ip = map__map_ip; - } - return self; -out_delete: - free(self); - return NULL; -} - -static struct map *map__clone(struct map *self) -{ - struct map *map = malloc(sizeof(*self)); - - if (!map) - return NULL; - - memcpy(map, self, sizeof(*self)); - - return map; -} - -static int map__overlap(struct map *l, struct map *r) -{ - if (l->start > r->start) { - struct map *t = l; - l = r; - r = t; - } - - if (l->end > r->start) - return 1; - - return 0; -} - -static size_t map__fprintf(struct map *self, FILE *fp) -{ - return fprintf(fp, " %Lx-%Lx %Lx %s\n", - self->start, self->end, self->pgoff, self->dso->name); -} - - struct thread { struct rb_node rb_node; struct list_head maps; @@ -1474,7 +1360,7 @@ static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { struct thread *thread = threads__findnew(event->mmap.pid); - struct map *map = map__new(&event->mmap); + struct map *map = map__new(&event->mmap, cwd, cwdlen); dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index a926ae4..43cf3ea 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -4,6 +4,7 @@ #include "../perf.h" #include #include +#include "util.h" #include "symbol.h" enum chain_mode { diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 91e2fe5..d26dc88 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -1,4 +1,8 @@ +#ifndef __PERF_EVENT_H +#define __PERF_EVENT_H #include "../perf.h" +#include "util.h" +#include struct ip_event { struct perf_event_header header; @@ -52,3 +56,29 @@ typedef union event_union { struct lost_event lost; struct read_event read; } event_t; + +struct map { + struct list_head node; + u64 start; + u64 end; + u64 pgoff; + u64 (*map_ip)(struct map *, u64); + struct dso *dso; +}; + +static inline u64 map__map_ip(struct map *map, u64 ip) +{ + return ip - map->start + map->pgoff; +} + +static inline u64 vdso__map_ip(struct map *map __used, u64 ip) +{ + return ip; +} + +struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); +struct map *map__clone(struct map *self); +int map__overlap(struct map *l, struct map *r); +size_t map__fprintf(struct map *self, FILE *fp); + +#endif diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c new file mode 100644 index 0000000..804e023 --- /dev/null +++ b/tools/perf/util/map.c @@ -0,0 +1,97 @@ +#include "event.h" +#include "symbol.h" +#include +#include +#include + +static inline int is_anon_memory(const char *filename) +{ + return strcmp(filename, "//anon") == 0; +} + +static int strcommon(const char *pathname, char *cwd, int cwdlen) +{ + int n = 0; + + while (n < cwdlen && pathname[n] == cwd[n]) + ++n; + + return n; +} + + struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen) +{ + struct map *self = malloc(sizeof(*self)); + + if (self != NULL) { + const char *filename = event->filename; + char newfilename[PATH_MAX]; + int anon; + + if (cwd) { + int n = strcommon(filename, cwd, cwdlen); + + if (n == cwdlen) { + snprintf(newfilename, sizeof(newfilename), + ".%s", filename + n); + filename = newfilename; + } + } + + anon = is_anon_memory(filename); + + if (anon) { + snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid); + filename = newfilename; + } + + self->start = event->start; + self->end = event->start + event->len; + self->pgoff = event->pgoff; + + self->dso = dsos__findnew(filename); + if (self->dso == NULL) + goto out_delete; + + if (self->dso == vdso || anon) + self->map_ip = vdso__map_ip; + else + self->map_ip = map__map_ip; + } + return self; +out_delete: + free(self); + return NULL; +} + +struct map *map__clone(struct map *self) +{ + struct map *map = malloc(sizeof(*self)); + + if (!map) + return NULL; + + memcpy(map, self, sizeof(*self)); + + return map; +} + +int map__overlap(struct map *l, struct map *r) +{ + if (l->start > r->start) { + struct map *t = l; + l = r; + r = t; + } + + if (l->end > r->start) + return 1; + + return 0; +} + +size_t map__fprintf(struct map *self, FILE *fp) +{ + return fprintf(fp, " %Lx-%Lx %Lx %s\n", + self->start, self->end, self->pgoff, self->dso->name); +} diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index f3490fc..50f7235 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -6,6 +6,7 @@ #include #include #include "module.h" +#include "event.h" struct symbol { struct rb_node rb_node; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index be4b52c..d61a6f0 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -83,7 +83,6 @@ #include #include "../../../include/linux/magic.h" -#include "event.h" #ifndef NO_ICONV #include -- cgit v0.10.2 From d2a382143b35a486b8089861790d6b3ec4e46932 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Aug 2009 14:30:33 +0100 Subject: ASoC: Update AD1938 for new TDM slot API It's only actually paying attention to the slot count anyway. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index aafda74..2ffb1af 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -133,8 +133,8 @@ static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd) return 0; } -static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots) +static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int mask, int slots, int width) { struct snd_soc_codec *codec = dai->codec; int dac_reg = codec->read(codec, AD1938_DAC_CTRL1); -- cgit v0.10.2 From c18bc9b927c98d7324ebd7fce0bbb924696ce7fe Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Wed, 12 Aug 2009 18:21:30 +0200 Subject: ALSA: hdsp - allow proc reporting with disconnected io box the hdsp driver refuses to report any information via the proc interface, if the io box is not connected. with this patch, the content of the control and status registers is printed before the iobox check. Signed-off-by: Tim Blechmann Signed-off-by: Takashi Iwai diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 3da5c02..7bb827c 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3294,15 +3294,33 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) char *clock_source; int x; - if (hdsp_check_for_iobox (hdsp)) { - snd_iprintf(buffer, "No I/O box connected.\nPlease connect one and upload firmware.\n"); + status = hdsp_read(hdsp, HDSP_statusRegister); + status2 = hdsp_read(hdsp, HDSP_status2Register); + + snd_iprintf(buffer, "%s (Card #%d)\n", hdsp->card_name, + hdsp->card->number + 1); + snd_iprintf(buffer, "Buffers: capture %p playback %p\n", + hdsp->capture_buffer, hdsp->playback_buffer); + snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", + hdsp->irq, hdsp->port, (unsigned long)hdsp->iobase); + snd_iprintf(buffer, "Control register: 0x%x\n", hdsp->control_register); + snd_iprintf(buffer, "Control2 register: 0x%x\n", + hdsp->control2_register); + snd_iprintf(buffer, "Status register: 0x%x\n", status); + snd_iprintf(buffer, "Status2 register: 0x%x\n", status2); + + if (hdsp_check_for_iobox(hdsp)) { + snd_iprintf(buffer, "No I/O box connected.\n" + "Please connect one and upload firmware.\n"); return; - } + } if (hdsp_check_for_firmware(hdsp, 0)) { if (hdsp->state & HDSP_FirmwareCached) { if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) { - snd_iprintf(buffer, "Firmware loading from cache failed, please upload manually.\n"); + snd_iprintf(buffer, "Firmware loading from " + "cache failed, " + "please upload manually.\n"); return; } } else { @@ -3319,18 +3337,6 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) } } - status = hdsp_read(hdsp, HDSP_statusRegister); - status2 = hdsp_read(hdsp, HDSP_status2Register); - - snd_iprintf(buffer, "%s (Card #%d)\n", hdsp->card_name, hdsp->card->number + 1); - snd_iprintf(buffer, "Buffers: capture %p playback %p\n", - hdsp->capture_buffer, hdsp->playback_buffer); - snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", - hdsp->irq, hdsp->port, (unsigned long)hdsp->iobase); - snd_iprintf(buffer, "Control register: 0x%x\n", hdsp->control_register); - snd_iprintf(buffer, "Control2 register: 0x%x\n", hdsp->control2_register); - snd_iprintf(buffer, "Status register: 0x%x\n", status); - snd_iprintf(buffer, "Status2 register: 0x%x\n", status2); snd_iprintf(buffer, "FIFO status: %d\n", hdsp_read(hdsp, HDSP_fifoStatus) & 0xff); snd_iprintf(buffer, "MIDI1 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut0)); snd_iprintf(buffer, "MIDI1 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn0)); @@ -3351,7 +3357,6 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) snd_iprintf(buffer, "\n"); - switch (hdsp_clock_source(hdsp)) { case HDSP_CLOCK_SOURCE_AUTOSYNC: clock_source = "AutoSync"; -- cgit v0.10.2 From 07f6642ee9418e962e54cbc07471cfe2e559c568 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 12 Aug 2009 16:39:16 -0700 Subject: net,pppoe: fixup module init/exit subsequent calls pernet data should allocated first and freed last on module init/exit routines otherwise it's possible to have unserialized calls to packet handling routines. Signed-off-by: Cyrill Gorcunov Signed-off-by: David S. Miller diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 5f20902..7cbf6f9 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -1185,17 +1185,17 @@ static int __init pppoe_init(void) { int err; - err = proto_register(&pppoe_sk_proto, 0); + err = register_pernet_gen_device(&pppoe_net_id, &pppoe_net_ops); if (err) goto out; - err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); + err = proto_register(&pppoe_sk_proto, 0); if (err) - goto out_unregister_pppoe_proto; + goto out_unregister_net_ops; - err = register_pernet_gen_device(&pppoe_net_id, &pppoe_net_ops); + err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); if (err) - goto out_unregister_pppox_proto; + goto out_unregister_pppoe_proto; dev_add_pack(&pppoes_ptype); dev_add_pack(&pppoed_ptype); @@ -1203,22 +1203,22 @@ static int __init pppoe_init(void) return 0; -out_unregister_pppox_proto: - unregister_pppox_proto(PX_PROTO_OE); out_unregister_pppoe_proto: proto_unregister(&pppoe_sk_proto); +out_unregister_net_ops: + unregister_pernet_gen_device(pppoe_net_id, &pppoe_net_ops); out: return err; } static void __exit pppoe_exit(void) { - unregister_pppox_proto(PX_PROTO_OE); - dev_remove_pack(&pppoes_ptype); - dev_remove_pack(&pppoed_ptype); unregister_netdevice_notifier(&pppoe_notifier); - unregister_pernet_gen_device(pppoe_net_id, &pppoe_net_ops); + dev_remove_pack(&pppoed_ptype); + dev_remove_pack(&pppoes_ptype); + unregister_pppox_proto(PX_PROTO_OE); proto_unregister(&pppoe_sk_proto); + unregister_pernet_gen_device(pppoe_net_id, &pppoe_net_ops); } module_init(pppoe_init); -- cgit v0.10.2 From e41256f139b9148cfa12d2d057fec39e3d181ff0 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Thu, 13 Aug 2009 11:49:06 +1000 Subject: crypto: talitos - simplify hmac data size calculation don't do request->src vs. assoc pointer math - it's the same as adding assoclen and ivsize (just with more effort). Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index c70775f..b1a651c 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -970,7 +970,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, struct talitos_desc *desc = &edesc->desc; unsigned int cryptlen = areq->cryptlen; unsigned int authsize = ctx->authsize; - unsigned int ivsize; + unsigned int ivsize = crypto_aead_ivsize(aead); int sg_count, ret; int sg_link_tbl_len; @@ -978,11 +978,9 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key, 0, DMA_TO_DEVICE); /* hmac data */ - map_single_talitos_ptr(dev, &desc->ptr[1], sg_virt(areq->src) - - sg_virt(areq->assoc), sg_virt(areq->assoc), 0, - DMA_TO_DEVICE); + map_single_talitos_ptr(dev, &desc->ptr[1], areq->assoclen + ivsize, + sg_virt(areq->assoc), 0, DMA_TO_DEVICE); /* cipher iv */ - ivsize = crypto_aead_ivsize(aead); map_single_talitos_ptr(dev, &desc->ptr[2], ivsize, giv ?: areq->iv, 0, DMA_TO_DEVICE); -- cgit v0.10.2 From 4b992628812137e30cda3510510cf3c052345b30 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Thu, 13 Aug 2009 11:50:38 +1000 Subject: crypto: talitos - align locks on cache lines align channel access locks onto separate cache lines (for performance reasons). This is done by placing per-channel variables into their own private struct, and using the cacheline_aligned attribute within that struct. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index b1a651c..5013a2d 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -86,6 +86,25 @@ struct talitos_request { void *context; }; +/* per-channel fifo management */ +struct talitos_channel { + /* request fifo */ + struct talitos_request *fifo; + + /* number of requests pending in channel h/w fifo */ + atomic_t submit_count ____cacheline_aligned; + + /* request submission (head) lock */ + spinlock_t head_lock ____cacheline_aligned; + /* index to next free descriptor request */ + int head; + + /* request release (tail) lock */ + spinlock_t tail_lock ____cacheline_aligned; + /* index to next in-progress/done descriptor request */ + int tail; +}; + struct talitos_private { struct device *dev; struct of_device *ofdev; @@ -101,15 +120,6 @@ struct talitos_private { /* SEC Compatibility info */ unsigned long features; - /* next channel to be assigned next incoming descriptor */ - atomic_t last_chan; - - /* per-channel number of requests pending in channel h/w fifo */ - atomic_t *submit_count; - - /* per-channel request fifo */ - struct talitos_request **fifo; - /* * length of the request fifo * fifo_len is chfifo_len rounded up to next power of 2 @@ -117,15 +127,10 @@ struct talitos_private { */ unsigned int fifo_len; - /* per-channel index to next free descriptor request */ - int *head; - - /* per-channel index to next in-progress/done descriptor request */ - int *tail; + struct talitos_channel *chan; - /* per-channel request submission (head) and release (tail) locks */ - spinlock_t *head_lock; - spinlock_t *tail_lock; + /* next channel to be assigned next incoming descriptor */ + atomic_t last_chan ____cacheline_aligned; /* request callback tasklet */ struct tasklet_struct done_task; @@ -282,16 +287,16 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, /* emulate SEC's round-robin channel fifo polling scheme */ ch = atomic_inc_return(&priv->last_chan) & (priv->num_channels - 1); - spin_lock_irqsave(&priv->head_lock[ch], flags); + spin_lock_irqsave(&priv->chan[ch].head_lock, flags); - if (!atomic_inc_not_zero(&priv->submit_count[ch])) { + if (!atomic_inc_not_zero(&priv->chan[ch].submit_count)) { /* h/w fifo is full */ - spin_unlock_irqrestore(&priv->head_lock[ch], flags); + spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); return -EAGAIN; } - head = priv->head[ch]; - request = &priv->fifo[ch][head]; + head = priv->chan[ch].head; + request = &priv->chan[ch].fifo[head]; /* map descriptor and save caller data */ request->dma_desc = dma_map_single(dev, desc, sizeof(*desc), @@ -300,7 +305,7 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, request->context = context; /* increment fifo head */ - priv->head[ch] = (priv->head[ch] + 1) & (priv->fifo_len - 1); + priv->chan[ch].head = (priv->chan[ch].head + 1) & (priv->fifo_len - 1); smp_wmb(); request->desc = desc; @@ -309,7 +314,7 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, wmb(); out_be32(priv->reg + TALITOS_FF_LO(ch), request->dma_desc); - spin_unlock_irqrestore(&priv->head_lock[ch], flags); + spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); return -EINPROGRESS; } @@ -324,11 +329,11 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) unsigned long flags; int tail, status; - spin_lock_irqsave(&priv->tail_lock[ch], flags); + spin_lock_irqsave(&priv->chan[ch].tail_lock, flags); - tail = priv->tail[ch]; - while (priv->fifo[ch][tail].desc) { - request = &priv->fifo[ch][tail]; + tail = priv->chan[ch].tail; + while (priv->chan[ch].fifo[tail].desc) { + request = &priv->chan[ch].fifo[tail]; /* descriptors with their done bits set don't get the error */ rmb(); @@ -354,22 +359,22 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) request->desc = NULL; /* increment fifo tail */ - priv->tail[ch] = (tail + 1) & (priv->fifo_len - 1); + priv->chan[ch].tail = (tail + 1) & (priv->fifo_len - 1); - spin_unlock_irqrestore(&priv->tail_lock[ch], flags); + spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags); - atomic_dec(&priv->submit_count[ch]); + atomic_dec(&priv->chan[ch].submit_count); saved_req.callback(dev, saved_req.desc, saved_req.context, status); /* channel may resume processing in single desc error case */ if (error && !reset_ch && status == error) return; - spin_lock_irqsave(&priv->tail_lock[ch], flags); - tail = priv->tail[ch]; + spin_lock_irqsave(&priv->chan[ch].tail_lock, flags); + tail = priv->chan[ch].tail; } - spin_unlock_irqrestore(&priv->tail_lock[ch], flags); + spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags); } /* @@ -397,20 +402,20 @@ static void talitos_done(unsigned long data) static struct talitos_desc *current_desc(struct device *dev, int ch) { struct talitos_private *priv = dev_get_drvdata(dev); - int tail = priv->tail[ch]; + int tail = priv->chan[ch].tail; dma_addr_t cur_desc; cur_desc = in_be32(priv->reg + TALITOS_CDPR_LO(ch)); - while (priv->fifo[ch][tail].dma_desc != cur_desc) { + while (priv->chan[ch].fifo[tail].dma_desc != cur_desc) { tail = (tail + 1) & (priv->fifo_len - 1); - if (tail == priv->tail[ch]) { + if (tail == priv->chan[ch].tail) { dev_err(dev, "couldn't locate current descriptor\n"); return NULL; } } - return priv->fifo[ch][tail].desc; + return priv->chan[ch].fifo[tail].desc; } /* @@ -1740,17 +1745,11 @@ static int talitos_remove(struct of_device *ofdev) if (hw_supports(dev, DESC_HDR_SEL0_RNG)) talitos_unregister_rng(dev); - kfree(priv->submit_count); - kfree(priv->tail); - kfree(priv->head); - - if (priv->fifo) - for (i = 0; i < priv->num_channels; i++) - kfree(priv->fifo[i]); + for (i = 0; i < priv->num_channels; i++) + if (priv->chan[i].fifo) + kfree(priv->chan[i].fifo); - kfree(priv->fifo); - kfree(priv->head_lock); - kfree(priv->tail_lock); + kfree(priv->chan); if (priv->irq != NO_IRQ) { free_irq(priv->irq, dev); @@ -1870,58 +1869,34 @@ static int talitos_probe(struct of_device *ofdev, if (of_device_is_compatible(np, "fsl,sec2.1")) priv->features |= TALITOS_FTR_HW_AUTH_CHECK; - priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, - GFP_KERNEL); - priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, - GFP_KERNEL); - if (!priv->head_lock || !priv->tail_lock) { - dev_err(dev, "failed to allocate fifo locks\n"); + priv->chan = kzalloc(sizeof(struct talitos_channel) * + priv->num_channels, GFP_KERNEL); + if (!priv->chan) { + dev_err(dev, "failed to allocate channel management space\n"); err = -ENOMEM; goto err_out; } for (i = 0; i < priv->num_channels; i++) { - spin_lock_init(&priv->head_lock[i]); - spin_lock_init(&priv->tail_lock[i]); - } - - priv->fifo = kmalloc(sizeof(struct talitos_request *) * - priv->num_channels, GFP_KERNEL); - if (!priv->fifo) { - dev_err(dev, "failed to allocate request fifo\n"); - err = -ENOMEM; - goto err_out; + spin_lock_init(&priv->chan[i].head_lock); + spin_lock_init(&priv->chan[i].tail_lock); } priv->fifo_len = roundup_pow_of_two(priv->chfifo_len); for (i = 0; i < priv->num_channels; i++) { - priv->fifo[i] = kzalloc(sizeof(struct talitos_request) * - priv->fifo_len, GFP_KERNEL); - if (!priv->fifo[i]) { + priv->chan[i].fifo = kzalloc(sizeof(struct talitos_request) * + priv->fifo_len, GFP_KERNEL); + if (!priv->chan[i].fifo) { dev_err(dev, "failed to allocate request fifo %d\n", i); err = -ENOMEM; goto err_out; } } - priv->submit_count = kmalloc(sizeof(atomic_t) * priv->num_channels, - GFP_KERNEL); - if (!priv->submit_count) { - dev_err(dev, "failed to allocate fifo submit count space\n"); - err = -ENOMEM; - goto err_out; - } for (i = 0; i < priv->num_channels; i++) - atomic_set(&priv->submit_count[i], -(priv->chfifo_len - 1)); - - priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); - priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); - if (!priv->head || !priv->tail) { - dev_err(dev, "failed to allocate request index space\n"); - err = -ENOMEM; - goto err_out; - } + atomic_set(&priv->chan[i].submit_count, + -(priv->chfifo_len - 1)); /* reset and initialize the h/w */ err = init_device(dev); -- cgit v0.10.2 From 81eb024c7e63f53b871797f6e2defccfd008dcd4 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Thu, 13 Aug 2009 11:51:51 +1000 Subject: crypto: talitos - add support for 36 bit addressing Enabling extended addressing in the h/w requires we always assign the extended address component (eptr) of the talitos h/w pointer. This is for e500 based platforms with large memories. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 5013a2d..c47ffe8 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -146,6 +146,12 @@ struct talitos_private { #define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001 #define TALITOS_FTR_HW_AUTH_CHECK 0x00000002 +static void to_talitos_ptr(struct talitos_ptr *talitos_ptr, dma_addr_t dma_addr) +{ + talitos_ptr->ptr = cpu_to_be32(lower_32_bits(dma_addr)); + talitos_ptr->eptr = cpu_to_be32(upper_32_bits(dma_addr)); +} + /* * map virtual single (contiguous) pointer to h/w descriptor pointer */ @@ -155,8 +161,10 @@ static void map_single_talitos_ptr(struct device *dev, unsigned char extent, enum dma_data_direction dir) { + dma_addr_t dma_addr = dma_map_single(dev, data, len, dir); + talitos_ptr->len = cpu_to_be16(len); - talitos_ptr->ptr = cpu_to_be32(dma_map_single(dev, data, len, dir)); + to_talitos_ptr(talitos_ptr, dma_addr); talitos_ptr->j_extent = extent; } @@ -187,9 +195,9 @@ static int reset_channel(struct device *dev, int ch) return -EIO; } - /* set done writeback and IRQ */ - setbits32(priv->reg + TALITOS_CCCR_LO(ch), TALITOS_CCCR_LO_CDWE | - TALITOS_CCCR_LO_CDIE); + /* set 36-bit addressing, done writeback enable and done IRQ enable */ + setbits32(priv->reg + TALITOS_CCCR_LO(ch), TALITOS_CCCR_LO_EAE | + TALITOS_CCCR_LO_CDWE | TALITOS_CCCR_LO_CDIE); /* and ICCR writeback, if available */ if (priv->features & TALITOS_FTR_HW_AUTH_CHECK) @@ -312,7 +320,10 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, /* GO! */ wmb(); - out_be32(priv->reg + TALITOS_FF_LO(ch), request->dma_desc); + out_be32(priv->reg + TALITOS_FF(ch), + cpu_to_be32(upper_32_bits(request->dma_desc))); + out_be32(priv->reg + TALITOS_FF_LO(ch), + cpu_to_be32(lower_32_bits(request->dma_desc))); spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); @@ -934,7 +945,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count, int n_sg = sg_count; while (n_sg--) { - link_tbl_ptr->ptr = cpu_to_be32(sg_dma_address(sg)); + to_talitos_ptr(link_tbl_ptr, sg_dma_address(sg)); link_tbl_ptr->len = cpu_to_be16(sg_dma_len(sg)); link_tbl_ptr->j_extent = 0; link_tbl_ptr++; @@ -1009,7 +1020,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, edesc->src_is_chained); if (sg_count == 1) { - desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src)); + to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src)); } else { sg_link_tbl_len = cryptlen; @@ -1020,14 +1031,14 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, &edesc->link_tbl[0]); if (sg_count > 1) { desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; - desc->ptr[4].ptr = cpu_to_be32(edesc->dma_link_tbl); + to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl); dma_sync_single_for_device(dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); } else { /* Only one segment now, so no link tbl needed */ - desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq-> - src)); + to_talitos_ptr(&desc->ptr[4], + sg_dma_address(areq->src)); } } @@ -1042,14 +1053,14 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, edesc->dst_is_chained); if (sg_count == 1) { - desc->ptr[5].ptr = cpu_to_be32(sg_dma_address(areq->dst)); + to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst)); } else { struct talitos_ptr *link_tbl_ptr = &edesc->link_tbl[edesc->src_nents + 1]; - desc->ptr[5].ptr = cpu_to_be32((struct talitos_ptr *) - edesc->dma_link_tbl + - edesc->src_nents + 1); + to_talitos_ptr(&desc->ptr[5], edesc->dma_link_tbl + + (edesc->src_nents + 1) * + sizeof(struct talitos_ptr)); sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen, link_tbl_ptr); @@ -1062,11 +1073,9 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, link_tbl_ptr->len = cpu_to_be16(authsize); /* icv data follows link tables */ - link_tbl_ptr->ptr = cpu_to_be32((struct talitos_ptr *) - edesc->dma_link_tbl + - edesc->src_nents + - edesc->dst_nents + 2); - + to_talitos_ptr(link_tbl_ptr, edesc->dma_link_tbl + + (edesc->src_nents + edesc->dst_nents + 2) * + sizeof(struct talitos_ptr)); desc->ptr[5].j_extent |= DESC_PTR_LNKTBL_JUMP; dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); @@ -1341,7 +1350,7 @@ static int common_nonsnoop(struct talitos_edesc *edesc, /* first DWORD empty */ desc->ptr[0].len = 0; - desc->ptr[0].ptr = 0; + to_talitos_ptr(&desc->ptr[0], 0); desc->ptr[0].j_extent = 0; /* cipher iv */ @@ -1365,20 +1374,20 @@ static int common_nonsnoop(struct talitos_edesc *edesc, edesc->src_is_chained); if (sg_count == 1) { - desc->ptr[3].ptr = cpu_to_be32(sg_dma_address(areq->src)); + to_talitos_ptr(&desc->ptr[3], sg_dma_address(areq->src)); } else { sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen, &edesc->link_tbl[0]); if (sg_count > 1) { + to_talitos_ptr(&desc->ptr[3], edesc->dma_link_tbl); desc->ptr[3].j_extent |= DESC_PTR_LNKTBL_JUMP; - desc->ptr[3].ptr = cpu_to_be32(edesc->dma_link_tbl); dma_sync_single_for_device(dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); } else { /* Only one segment now, so no link tbl needed */ - desc->ptr[3].ptr = cpu_to_be32(sg_dma_address(areq-> - src)); + to_talitos_ptr(&desc->ptr[3], + sg_dma_address(areq->src)); } } @@ -1393,15 +1402,15 @@ static int common_nonsnoop(struct talitos_edesc *edesc, edesc->dst_is_chained); if (sg_count == 1) { - desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->dst)); + to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->dst)); } else { struct talitos_ptr *link_tbl_ptr = &edesc->link_tbl[edesc->src_nents + 1]; + to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl + + (edesc->src_nents + 1) * + sizeof(struct talitos_ptr)); desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; - desc->ptr[4].ptr = cpu_to_be32((struct talitos_ptr *) - edesc->dma_link_tbl + - edesc->src_nents + 1); sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen, link_tbl_ptr); dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, @@ -1414,7 +1423,7 @@ static int common_nonsnoop(struct talitos_edesc *edesc, /* last DWORD empty */ desc->ptr[6].len = 0; - desc->ptr[6].ptr = 0; + to_talitos_ptr(&desc->ptr[6], 0); desc->ptr[6].j_extent = 0; ret = talitos_submit(dev, desc, callback, areq); @@ -1898,6 +1907,8 @@ static int talitos_probe(struct of_device *ofdev, atomic_set(&priv->chan[i].submit_count, -(priv->chfifo_len - 1)); + dma_set_mask(dev, DMA_BIT_MASK(36)); + /* reset and initialize the h/w */ err = init_device(dev); if (err) { diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h index 575981f..ff5a145 100644 --- a/drivers/crypto/talitos.h +++ b/drivers/crypto/talitos.h @@ -57,6 +57,7 @@ #define TALITOS_CCCR_RESET 0x1 /* channel reset */ #define TALITOS_CCCR_LO(ch) (ch * TALITOS_CH_STRIDE + 0x110c) #define TALITOS_CCCR_LO_IWSE 0x80 /* chan. ICCR writeback enab. */ +#define TALITOS_CCCR_LO_EAE 0x20 /* extended address enable */ #define TALITOS_CCCR_LO_CDWE 0x10 /* chan. done writeback enab. */ #define TALITOS_CCCR_LO_NT 0x4 /* notification type */ #define TALITOS_CCCR_LO_CDIE 0x2 /* channel done IRQ enable */ -- cgit v0.10.2 From a8ccc393ddcdff2e0288dc459f03d561ae27b51d Mon Sep 17 00:00:00 2001 From: Christian Kujau Date: Thu, 13 Aug 2009 11:53:56 +1000 Subject: crypto: rng - Fix typo Correct a typo in crypto/rng.c Signed-off-by: Christian Kujau Acked-by: Neil Horman Signed-off-by: Herbert Xu diff --git a/crypto/rng.c b/crypto/rng.c index 6e94bc7..ba05e73 100644 --- a/crypto/rng.c +++ b/crypto/rng.c @@ -123,4 +123,4 @@ void crypto_put_default_rng(void) EXPORT_SYMBOL_GPL(crypto_put_default_rng); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Random Number Genertor"); +MODULE_DESCRIPTION("Random Number Generator"); -- cgit v0.10.2 From 5da63cc4b2258e1c06ee41637492717481025143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Thu, 6 Aug 2009 21:56:43 +0000 Subject: f_phonet: lock-less MTU change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the current driver, the MTU is purely indicative, so there is no need to synchronize with the receive path. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index d17f108..f4eff7c 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -261,20 +261,10 @@ out: static int pn_net_mtu(struct net_device *dev, int new_mtu) { - struct phonet_port *port = netdev_priv(dev); - unsigned long flags; - int err = -EBUSY; - if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU)) return -EINVAL; - - spin_lock_irqsave(&port->lock, flags); - if (!netif_carrier_ok(dev)) { - dev->mtu = new_mtu; - err = 0; - } - spin_unlock_irqrestore(&port->lock, flags); - return err; + dev->mtu = new_mtu; + return 0; } static const struct net_device_ops pn_netdev_ops = { -- cgit v0.10.2 From b91cd1440870f7a0649e570498b7b93caf9f781c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Thu, 6 Aug 2009 21:56:44 +0000 Subject: f_phonet: use page-sized rather than MTU-sized RX buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of a large (physically) linear buffer, we generate a set of paged sk_buff, so no extra memory copy is involved. This removes high-order allocations and saves quite a bit of memory. Phonet MTU is 65541 bytes, so the two buffers were padded to 128 kilo-bytes each. Now, we create 17 page buffers, almost a 75% memory use reduction. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index f4eff7c..d2de10b 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -35,6 +35,10 @@ #include "u_phonet.h" #define PN_MEDIA_USB 0x1B +#define MAXPACKET 512 +#if (PAGE_SIZE % MAXPACKET) +#error MAXPACKET must divide PAGE_SIZE! +#endif /*-------------------------------------------------------------------------*/ @@ -45,6 +49,10 @@ struct phonet_port { struct f_phonet { struct usb_function function; + struct { + struct sk_buff *skb; + spinlock_t lock; + } rx; struct net_device *dev; struct usb_ep *in_ep, *out_ep; @@ -52,7 +60,7 @@ struct f_phonet { struct usb_request *out_reqv[0]; }; -static int phonet_rxq_size = 2; +static int phonet_rxq_size = 17; static inline struct f_phonet *func_to_pn(struct usb_function *f) { @@ -138,7 +146,7 @@ pn_hs_sink_desc = { .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), + .wMaxPacketSize = cpu_to_le16(MAXPACKET), }; static struct usb_endpoint_descriptor @@ -298,21 +306,21 @@ static void pn_net_setup(struct net_device *dev) static int pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags) { - struct sk_buff *skb; - const size_t size = fp->dev->mtu; + struct net_device *dev = fp->dev; + struct page *page; int err; - skb = alloc_skb(size, gfp_flags); - if (!skb) + page = __netdev_alloc_page(dev, gfp_flags); + if (!page) return -ENOMEM; - req->buf = skb->data; - req->length = size; - req->context = skb; + req->buf = page_address(page); + req->length = PAGE_SIZE; + req->context = page; err = usb_ep_queue(fp->out_ep, req, gfp_flags); if (unlikely(err)) - dev_kfree_skb_any(skb); + netdev_free_page(dev, page); return err; } @@ -320,25 +328,37 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) { struct f_phonet *fp = ep->driver_data; struct net_device *dev = fp->dev; - struct sk_buff *skb = req->context; + struct page *page = req->context; + struct sk_buff *skb; + unsigned long flags; int status = req->status; switch (status) { case 0: - if (unlikely(!netif_running(dev))) - break; - if (unlikely(req->actual < 1)) + spin_lock_irqsave(&fp->rx.lock, flags); + skb = fp->rx.skb; + if (!skb) + skb = fp->rx.skb = netdev_alloc_skb(dev, 12); + if (req->actual < req->length) /* Last fragment */ + fp->rx.skb = NULL; + spin_unlock_irqrestore(&fp->rx.lock, flags); + + if (unlikely(!skb)) break; - skb_put(skb, req->actual); - skb->protocol = htons(ETH_P_PHONET); - skb_reset_mac_header(skb); - __skb_pull(skb, 1); - skb->dev = dev; - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - netif_rx(skb); - skb = NULL; + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, 0, + req->actual); + page = NULL; + + if (req->actual < req->length) { /* Last fragment */ + skb->protocol = htons(ETH_P_PHONET); + skb_reset_mac_header(skb); + pskb_pull(skb, 1); + skb->dev = dev; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + netif_rx(skb); + } break; /* Do not resubmit in these cases: */ @@ -356,8 +376,8 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) break; } - if (skb) - dev_kfree_skb_any(skb); + if (page) + netdev_free_page(dev, page); if (req) pn_rx_submit(fp, req, GFP_ATOMIC); } @@ -375,6 +395,10 @@ static void __pn_reset(struct usb_function *f) usb_ep_disable(fp->out_ep); usb_ep_disable(fp->in_ep); + if (fp->rx.skb) { + dev_kfree_skb_irq(fp->rx.skb); + fp->rx.skb = NULL; + } } static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) @@ -573,6 +597,7 @@ int __init phonet_bind_config(struct usb_configuration *c) fp->function.set_alt = pn_set_alt; fp->function.get_alt = pn_get_alt; fp->function.disable = pn_disconnect; + spin_lock_init(&fp->rx.lock); err = usb_add_function(c, &fp->function); if (err) -- cgit v0.10.2 From 6885ffb3a1b4abf731fd0891a2c1544a83c2651d Mon Sep 17 00:00:00 2001 From: Mark Smith Date: Thu, 6 Aug 2009 23:21:22 +0000 Subject: Use correct NET_RX_* returns for atalk_rcv() In all rx'd SKB cases, atalk_rcv() either eventually jumps to or falls through to the label out:, which returns numeric 0. Numeric 0 corresponds to NET_RX_SUCCESS, which is incorrect in failed SKB cases. This patch makes atalk_rcv() provide the correct returns by: o explicitly returning NET_RX_SUCCESS in the two success cases o having the out: label return NET_RX_DROP, instead of numeric 0 o making the failed SKB labels and processing more consistent with other _rcv() routines in the kernel, simplifying validation and removing a backwards goto Signed-off-by: Mark Smith Signed-off-by: David S. Miller diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 875eda5..0d42d5d 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1400,7 +1400,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, __u16 len_hops; if (!net_eq(dev_net(dev), &init_net)) - goto freeit; + goto drop; /* Don't mangle buffer if shared */ if (!(skb = skb_share_check(skb, GFP_ATOMIC))) @@ -1408,7 +1408,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, /* Size check and make sure header is contiguous */ if (!pskb_may_pull(skb, sizeof(*ddp))) - goto freeit; + goto drop; ddp = ddp_hdr(skb); @@ -1426,7 +1426,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, if (skb->len < sizeof(*ddp) || skb->len < (len_hops & 1023)) { pr_debug("AppleTalk: dropping corrupted frame (deh_len=%u, " "skb->len=%u)\n", len_hops & 1023, skb->len); - goto freeit; + goto drop; } /* @@ -1436,7 +1436,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, if (ddp->deh_sum && atalk_checksum(skb, len_hops & 1023) != ddp->deh_sum) /* Not a valid AppleTalk frame - dustbin time */ - goto freeit; + goto drop; /* Check the packet is aimed at us */ if (!ddp->deh_dnet) /* Net 0 is 'this network' */ @@ -1449,7 +1449,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, * AppleTalk iface */ atalk_route_packet(skb, dev, ddp, len_hops, origlen); - goto out; + return NET_RX_SUCCESS; } /* if IP over DDP is not selected this code will be optimized out */ @@ -1465,18 +1465,21 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, sock = atalk_search_socket(&tosat, atif); if (!sock) /* But not one of our sockets */ - goto freeit; + goto drop; /* Queue packet (standard) */ skb->sk = sock; if (sock_queue_rcv_skb(sock, skb) < 0) - goto freeit; -out: - return 0; -freeit: + goto drop; + + return NET_RX_SUCCESS; + +drop: kfree_skb(skb); - goto out; +out: + return NET_RX_DROP; + } /* -- cgit v0.10.2 From 8505091d2a067ad27d4a82df9cff8eae6ee52fca Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 7 Aug 2009 02:58:36 +0000 Subject: af_ieee802154: drop IEEE802154_SIOC_ADD_SLAVE declaration IEEE802154_SIOC_ADD_SLAVE was used to allocate 802.15.4 interfaces on the top of radio. It's not used anymore, drop it. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: David S. Miller diff --git a/include/net/af_ieee802154.h b/include/net/af_ieee802154.h index 0d78605..e9c70ea 100644 --- a/include/net/af_ieee802154.h +++ b/include/net/af_ieee802154.h @@ -54,7 +54,4 @@ struct sockaddr_ieee802154 { struct ieee802154_addr addr; }; -/* master device */ -#define IEEE802154_SIOC_ADD_SLAVE (SIOCDEVPRIVATE + 0) - #endif -- cgit v0.10.2 From 78090a58c49f2f6213d0bb1b3b4c4df73e26865f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 7 Aug 2009 02:58:38 +0000 Subject: nl802154: make ieee802154_policy constant Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: David S. Miller diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h index 2cda00c..266dd96 100644 --- a/include/linux/nl802154.h +++ b/include/linux/nl802154.h @@ -69,7 +69,7 @@ enum { #define IEEE802154_ATTR_MAX (__IEEE802154_ATTR_MAX - 1) -extern struct nla_policy ieee802154_policy[]; +extern const struct nla_policy ieee802154_policy[]; /* commands */ /* REQ should be responded with CONF diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c index c7d71d1..83cb4cc 100644 --- a/net/ieee802154/nl_policy.c +++ b/net/ieee802154/nl_policy.c @@ -24,7 +24,7 @@ #define NLA_HW_ADDR NLA_U64 -struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { +const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { [IEEE802154_ATTR_DEV_NAME] = { .type = NLA_STRING, }, [IEEE802154_ATTR_DEV_INDEX] = { .type = NLA_U32, }, @@ -50,3 +50,4 @@ struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, }, [IEEE802154_ATTR_ED_LIST] = { .len = 27 }, }; + -- cgit v0.10.2 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 diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt index 1d4ed66..1c0c82c 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 v0.10.2 From 8e753dd0a82bd266256c20a20b98dfa48f98d21e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 7 Aug 2009 02:58:40 +0000 Subject: nl802154: add support for dumping WPAN interface information Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: David S. Miller diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h index 266dd96..9a1af5f 100644 --- a/include/linux/nl802154.h +++ b/include/linux/nl802154.h @@ -111,6 +111,8 @@ enum { IEEE802154_RX_ENABLE_REQ, /* Not supported yet */ IEEE802154_RX_ENABLE_CONF, /* Not supported yet */ + IEEE802154_LIST_IFACE, + __IEEE802154_CMD_MAX, }; diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index a615b9d..3fe02b3 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -19,6 +19,7 @@ * Written by: * Sergey Lapin * Dmitry Eremin-Solenikov + * Maxim Osipov */ #include @@ -26,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +75,7 @@ static int ieee802154_nl_finish(struct sk_buff *msg) /* XXX: nlh is right at the start of msg */ void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); - if (!genlmsg_end(msg, hdr)) + if (genlmsg_end(msg, hdr) < 0) goto out; return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, @@ -260,6 +262,35 @@ nla_put_failure: } EXPORT_SYMBOL(ieee802154_nl_scan_confirm); +static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid, + u32 seq, int flags, struct net_device *dev) +{ + void *hdr; + + pr_debug("%s\n", __func__); + + hdr = genlmsg_put(msg, 0, seq, &ieee802154_coordinator_family, flags, + IEEE802154_LIST_IFACE); + if (!hdr) + goto out; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, + ieee802154_mlme_ops(dev)->get_short_addr(dev)); + NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID, + ieee802154_mlme_ops(dev)->get_pan_id(dev)); + return genlmsg_end(msg, hdr); + +nla_put_failure: + genlmsg_cancel(msg, hdr); +out: + return -EMSGSIZE; +} + /* Requests from userspace */ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) { @@ -272,7 +303,7 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) dev = dev_get_by_name(&init_net, name); } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) dev = dev_get_by_index(&init_net, - nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); + nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); else return NULL; @@ -466,6 +497,67 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) return ret; } +static int ieee802154_list_iface(struct sk_buff *skb, + struct genl_info *info) +{ + /* Request for interface name, index, type, IEEE address, + PAN Id, short address */ + struct sk_buff *msg; + struct net_device *dev = NULL; + int rc = -ENOBUFS; + + pr_debug("%s\n", __func__); + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + goto out_dev; + + rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq, + 0, dev); + if (rc < 0) + goto out_free; + + dev_put(dev); + + return genlmsg_unicast(&init_net, msg, info->snd_pid); +out_free: + nlmsg_free(msg); +out_dev: + dev_put(dev); + return rc; + +} + +static int ieee802154_dump_iface(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + int idx; + int s_idx = cb->args[0]; + + pr_debug("%s\n", __func__); + + idx = 0; + for_each_netdev(net, dev) { + if (idx < s_idx || (dev->type != ARPHRD_IEEE802154)) + goto cont; + + if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0) + break; +cont: + idx++; + } + cb->args[0] = idx; + + return skb->len; +} + #define IEEE802154_OP(_cmd, _func) \ { \ .cmd = _cmd, \ @@ -475,12 +567,22 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) .flags = GENL_ADMIN_PERM, \ } +#define IEEE802154_DUMP(_cmd, _func, _dump) \ + { \ + .cmd = _cmd, \ + .policy = ieee802154_policy, \ + .doit = _func, \ + .dumpit = _dump, \ + } + static struct genl_ops ieee802154_coordinator_ops[] = { IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), + IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface, + ieee802154_dump_iface), }; static int __init ieee802154_nl_init(void) -- cgit v0.10.2 From 74eda55db4335383ccdd1fb51a7b014202f89366 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 7 Aug 2009 02:58:42 +0000 Subject: af_ieee802154: minor cleanup in dgram_bind 1) fix ro->bound protection by socket lock 2) make ro->bound bit instead of int Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: David S. Miller diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index d1da6c6..25018a9 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -40,9 +40,10 @@ static DEFINE_RWLOCK(dgram_lock); struct dgram_sock { struct sock sk; - int bound; struct ieee802154_addr src_addr; struct ieee802154_addr dst_addr; + + unsigned bound:1; }; static inline struct dgram_sock *dgram_sk(const struct sock *sk) @@ -86,18 +87,18 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) { struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; struct dgram_sock *ro = dgram_sk(sk); - int err = 0; + int err = -EINVAL; struct net_device *dev; + lock_sock(sk); + ro->bound = 0; if (len < sizeof(*addr)) - return -EINVAL; + goto out; if (addr->family != AF_IEEE802154) - return -EINVAL; - - lock_sock(sk); + goto out; dev = ieee802154_get_dev(sock_net(sk), &addr->addr); if (!dev) { @@ -113,6 +114,7 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr)); ro->bound = 1; + err = 0; out_put: dev_put(dev); out: -- cgit v0.10.2 From 99eb8558642b988055d2b8b16a334475550f78d3 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 7 Aug 2009 02:58:43 +0000 Subject: af_ieee802154: add support for WANT_ACK socket option Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: David S. Miller diff --git a/include/net/af_ieee802154.h b/include/net/af_ieee802154.h index e9c70ea..75e64c7 100644 --- a/include/net/af_ieee802154.h +++ b/include/net/af_ieee802154.h @@ -54,4 +54,9 @@ struct sockaddr_ieee802154 { struct ieee802154_addr addr; }; +/* get/setsockopt */ +#define SOL_IEEE802154 0 + +#define WPAN_WANTACK 0 + #endif diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 25018a9..77ae685 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -44,6 +44,7 @@ struct dgram_sock { struct ieee802154_addr dst_addr; unsigned bound:1; + unsigned want_ack:1; }; static inline struct dgram_sock *dgram_sk(const struct sock *sk) @@ -51,7 +52,6 @@ static inline struct dgram_sock *dgram_sk(const struct sock *sk) return container_of(sk, struct dgram_sock, sk); } - static void dgram_hash(struct sock *sk) { write_lock_bh(&dgram_lock); @@ -74,6 +74,7 @@ static int dgram_init(struct sock *sk) ro->dst_addr.addr_type = IEEE802154_ADDR_LONG; ro->dst_addr.pan_id = 0xffff; + ro->want_ack = 1; memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr)); return 0; } @@ -237,7 +238,10 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, skb_reset_network_header(skb); - mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA | MAC_CB_FLAG_ACKREQ; + mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA; + if (ro->want_ack) + mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ; + mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr, ro->bound ? &ro->src_addr : NULL, size); @@ -382,13 +386,59 @@ int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) static int dgram_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - return -EOPNOTSUPP; + struct dgram_sock *ro = dgram_sk(sk); + + int val, len; + + if (level != SOL_IEEE802154) + return -EOPNOTSUPP; + + if (get_user(len, optlen)) + return -EFAULT; + + len = min_t(unsigned int, len, sizeof(int)); + + switch (optname) { + case WPAN_WANTACK: + val = ro->want_ack; + break; + default: + return -ENOPROTOOPT; + } + + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + return 0; } static int dgram_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user optlen) { - return -EOPNOTSUPP; + struct dgram_sock *ro = dgram_sk(sk); + int val; + int err = 0; + + if (optlen < sizeof(int)) + return -EINVAL; + + if (get_user(val, (int __user *)optval)) + return -EFAULT; + + lock_sock(sk); + + switch (optname) { + case WPAN_WANTACK: + ro->want_ack = !!val; + break; + default: + err = -ENOPROTOOPT; + break; + } + + release_sock(sk); + return err; } struct proto ieee802154_dgram_prot = { -- cgit v0.10.2 From acb8aacda3f0bc3aeb652f4365c078a2b0adb0bf Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 7 Aug 2009 02:58:44 +0000 Subject: nl802154: support START-CONFIRM primitive Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: David S. Miller diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 6096096..e554ecd 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -114,4 +114,13 @@ int ieee802154_nl_scan_confirm(struct net_device *dev, int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, u16 coord_addr); +/** + * ieee802154_nl_start_confirm - Notify userland of completion of start. + * @dev: The device which was instructed to scan. + * @status: The status of the scan operation. + * + * Note: This is in section 7.1.14 of the IEEE 802.15.4 document. + */ +int ieee802154_nl_start_confirm(struct net_device *dev, u8 status); + #endif diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 3fe02b3..cd0567f 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -31,6 +31,7 @@ #include #include #include +#include #include static unsigned int ieee802154_seq_num; @@ -262,6 +263,31 @@ nla_put_failure: } EXPORT_SYMBOL(ieee802154_nl_scan_confirm); +int ieee802154_nl_start_confirm(struct net_device *dev, u8 status) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_START_CONF); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_start_confirm); + static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct net_device *dev) { @@ -462,6 +488,12 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); + if (addr.short_addr == IEEE802154_ADDR_BROADCAST) { + ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS); + dev_put(dev); + return -EINVAL; + } + ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, bcn_ord, sf_ord, pan_coord, blx, coord_realign); -- cgit v0.10.2 From 798c752b815bd80653dc48b6ffb8eb68ede15a66 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 7 Aug 2009 02:58:45 +0000 Subject: fakehard: use START-CONFIRM primitive to report START failure Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: David S. Miller diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index c94d2c2..262536f 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -177,18 +177,14 @@ static int fake_disassoc_req(struct net_device *dev, * * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006 * document, with 7.3.8 describing coordinator realignment. - * - * Note: There is currently no way to notify the coordinator userland - * program of whether or not the PAN has started successfully. As - * such, the coordinator program cannot know when the MAC has - * completed starting the network and will simply have to assume - * completeness based on some form of time delay. */ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 coord_realign) { + /* We don't emulate beacons here at all, so START should fail */ + ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER); return 0; } -- cgit v0.10.2 From 176edd52366d59350717b0bf6865b1d7ece156cc Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 7 Aug 2009 21:53:41 +0000 Subject: drivres/net: Change constant name In this series of tests the constants have the form XRXMAC_STATUS, except in this one case. The values of XRXMAC_STAT_MSK_RXOCTET_CNT_EXP and XRXMAC_STATUS_RXOCTET_CNT_EXP are furthermore the same. Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/drivers/net/niu.c b/drivers/net/niu.c index d2146d4..3ada7ea 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -4015,7 +4015,7 @@ static void niu_xmac_interrupt(struct niu *np) mp->rx_hist_cnt6 += RXMAC_HIST_CNT6_COUNT; if (val & XRXMAC_STATUS_RXHIST7_CNT_EXP) mp->rx_hist_cnt7 += RXMAC_HIST_CNT7_COUNT; - if (val & XRXMAC_STAT_MSK_RXOCTET_CNT_EXP) + if (val & XRXMAC_STATUS_RXOCTET_CNT_EXP) mp->rx_octets += RXMAC_BT_CNT_COUNT; if (val & XRXMAC_STATUS_CVIOLERR_CNT_EXP) mp->rx_code_violations += RXMAC_CD_VIO_CNT_COUNT; -- cgit v0.10.2 From 582b95c2709cd58913ec2a31b0266ba0aa67b03d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 7 Aug 2009 20:47:33 +0000 Subject: drivers/net/tokenring: Use status field rather than state field In general in this file, it is the status field, not the state field, that contains values like OPEN and CLOSED. Indeed, in the first error case, it is the field status that is initialized. I have thus assumed that all of the error handling code should be the same, and moved it to the end of the function to emphasize its commonality. Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 6515894..23e012f 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -3091,11 +3091,7 @@ static int smctr_lobe_media_test(struct net_device *dev) /* Setup the lobe media test. */ smctr_lobe_media_test_cmd(dev); if(smctr_wait_cmd(dev)) - { - smctr_reset_adapter(dev); - tp->status = CLOSED; - return (LOBE_MEDIA_TEST_FAILED); - } + goto err; /* Tx lobe media test frames. */ for(i = 0; i < 1500; ++i) @@ -3103,20 +3099,12 @@ static int smctr_lobe_media_test(struct net_device *dev) if(smctr_send_lobe_media_test(dev)) { if(perror) - { - smctr_reset_adapter(dev); - tp->state = CLOSED; - return (LOBE_MEDIA_TEST_FAILED); - } + goto err; else { perror = 1; if(smctr_lobe_media_test_cmd(dev)) - { - smctr_reset_adapter(dev); - tp->state = CLOSED; - return (LOBE_MEDIA_TEST_FAILED); - } + goto err; } } } @@ -3124,28 +3112,24 @@ static int smctr_lobe_media_test(struct net_device *dev) if(smctr_send_dat(dev)) { if(smctr_send_dat(dev)) - { - smctr_reset_adapter(dev); - tp->state = CLOSED; - return (LOBE_MEDIA_TEST_FAILED); - } + goto err; } /* Check if any frames received during test. */ if((tp->rx_fcb_curr[MAC_QUEUE]->frame_status) || (tp->rx_fcb_curr[NON_MAC_QUEUE]->frame_status)) - { - smctr_reset_adapter(dev); - tp->state = CLOSED; - return (LOBE_MEDIA_TEST_FAILED); - } + goto err; /* Set receive mask to "Promisc" mode. */ tp->receive_mask = saved_rcv_mask; smctr_chg_rx_mask(dev); - return (0); + return 0; +err: + smctr_reset_adapter(dev); + tp->status = CLOSED; + return LOBE_MEDIA_TEST_FAILED; } static int smctr_lobe_media_test_cmd(struct net_device *dev) -- cgit v0.10.2 From ab4c0c77b566bbac25e28c7ae487dc02bdd8f343 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sun, 9 Aug 2009 02:59:56 +0000 Subject: net: cs89x0: includecheck fix for cs89x0.c fix the following 'make includecheck' warning: drivers/net/cs89x0.c: asm/irq.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: David S. Miller diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index ecf88ab..839cac5 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -177,13 +177,10 @@ static unsigned int cs8900_irq_map[] = {1,0,0,0}; #elif defined(CONFIG_MACH_IXDP2351) static unsigned int netcard_portlist[] __used __initdata = {IXDP2351_VIRT_CS8900_BASE, 0}; static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0}; -#include #elif defined(CONFIG_ARCH_IXDP2X01) -#include static unsigned int netcard_portlist[] __used __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0}; static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; #elif defined(CONFIG_ARCH_PNX010X) -#include #include #define CIRRUS_DEFAULT_BASE IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000) /* = Physical address 0x48200000 */ #define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */ -- cgit v0.10.2 From bdf50d7346588b22fd66367ae2890e2cbf574172 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sun, 9 Aug 2009 03:05:25 +0000 Subject: net: pcmcia/axnet_cs: includecheck fix axnet_cs.c fix the following 'make includecheck' warning: drivers/net/pcmcia/axnet_cs.c: linux/etherdevice.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: David S. Miller diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index b5cfac7..1e87d63 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -893,8 +893,6 @@ static const char version_8390[] = KERN_INFO \ #include #include -#include - #define BUG_83C690 /* These are the operational function interfaces to board-specific -- cgit v0.10.2 From c9145a2df072f75d97592ddac1624baeb7bad195 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 8 Aug 2009 21:43:42 +0000 Subject: drivers/net: Correct use of request_region/request_mem_region request_mem_region should be used with release_mem_region, not request_region. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @r2@ expression start; @@ request_mem_region(start,...) @b2@ expression r2.start; @@ request_region(start,...) @depends on !b2@ expression r2.start; expression E; @@ - release_region + release_mem_region (start,E) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index ec337b5..6e5b3f3 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -203,7 +203,7 @@ static int __devinit sonic_probe1(struct net_device *dev) return 0; out: - release_region(dev->base_addr, SONIC_MEM_SIZE); + release_mem_region(dev->base_addr, SONIC_MEM_SIZE); return err; } @@ -247,7 +247,7 @@ static int __devinit jazz_sonic_probe(struct platform_device *pdev) return 0; out1: - release_region(dev->base_addr, SONIC_MEM_SIZE); + release_mem_region(dev->base_addr, SONIC_MEM_SIZE); out: free_netdev(dev); @@ -269,7 +269,7 @@ static int __devexit jazz_sonic_device_remove (struct platform_device *pdev) unregister_netdev(dev); dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), lp->descriptors, lp->descriptors_laddr); - release_region (dev->base_addr, SONIC_MEM_SIZE); + release_mem_region(dev->base_addr, SONIC_MEM_SIZE); free_netdev(dev); return 0; -- cgit v0.10.2 From d02342151c51344034fbdeceff8effcb0a77c573 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Fri, 7 Aug 2009 10:44:22 +0000 Subject: myri10ge: improve parity error detection and recovery Improve myri10ge parity error detection and recovery: 1) Don't restore PCI config space to a rebooted NIC until AFTER the host is quiescent. 2) Let myri10ge_close() know the NIC is dead, so it won't waste time waiting for a dead nic to respond to MXGEFW_CMD_ETHERNET_DOWN 3) When the NIC is quiet (link down, or otherwise idle link) use a pci config space read to detect a rebooted NIC. Otherwise we might never notice that a NIC rebooted Signed-off-by: Andrew Gallatin Signed-off-by: Brice Goglin Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1a34f7e..75deef3 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -75,7 +75,7 @@ #include "myri10ge_mcp.h" #include "myri10ge_mcp_gen_header.h" -#define MYRI10GE_VERSION_STR "1.5.0-1.418" +#define MYRI10GE_VERSION_STR "1.5.0-1.432" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); @@ -188,6 +188,7 @@ struct myri10ge_slice_state { dma_addr_t fw_stats_bus; int watchdog_tx_done; int watchdog_tx_req; + int watchdog_rx_done; #ifdef CONFIG_MYRI10GE_DCA int cached_dca_tag; int cpu; @@ -256,6 +257,7 @@ struct myri10ge_priv { u32 link_changes; u32 msg_enable; unsigned int board_number; + int rebooted; }; static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat"; @@ -2552,17 +2554,22 @@ static int myri10ge_close(struct net_device *dev) netif_carrier_off(dev); netif_tx_stop_all_queues(dev); - old_down_cnt = mgp->down_cnt; - mb(); - status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_DOWN, &cmd, 0); - if (status) - printk(KERN_ERR "myri10ge: %s: Couldn't bring down link\n", - dev->name); - - wait_event_timeout(mgp->down_wq, old_down_cnt != mgp->down_cnt, HZ); - if (old_down_cnt == mgp->down_cnt) - printk(KERN_ERR "myri10ge: %s never got down irq\n", dev->name); + if (mgp->rebooted == 0) { + old_down_cnt = mgp->down_cnt; + mb(); + status = + myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_DOWN, &cmd, 0); + if (status) + printk(KERN_ERR + "myri10ge: %s: Couldn't bring down link\n", + dev->name); + wait_event_timeout(mgp->down_wq, old_down_cnt != mgp->down_cnt, + HZ); + if (old_down_cnt == mgp->down_cnt) + printk(KERN_ERR "myri10ge: %s never got down irq\n", + dev->name); + } netif_tx_disable(dev); myri10ge_free_irq(mgp); for (i = 0; i < mgp->num_slices; i++) @@ -3427,12 +3434,13 @@ static void myri10ge_watchdog(struct work_struct *work) container_of(work, struct myri10ge_priv, watchdog_work); struct myri10ge_tx_buf *tx; u32 reboot; - int status; + int status, rebooted; int i; u16 cmd, vendor; mgp->watchdog_resets++; pci_read_config_word(mgp->pdev, PCI_COMMAND, &cmd); + rebooted = 0; if ((cmd & PCI_COMMAND_MASTER) == 0) { /* Bus master DMA disabled? Check to see * if the card rebooted due to a parity error @@ -3444,9 +3452,12 @@ static void myri10ge_watchdog(struct work_struct *work) myri10ge_reset_recover ? " " : " not"); if (myri10ge_reset_recover == 0) return; - + rtnl_lock(); + mgp->rebooted = 1; + rebooted = 1; + myri10ge_close(mgp->dev); myri10ge_reset_recover--; - + mgp->rebooted = 0; /* * A rebooted nic will come back with config space as * it was after power was applied to PCIe bus. @@ -3494,8 +3505,10 @@ static void myri10ge_watchdog(struct work_struct *work) } } - rtnl_lock(); - myri10ge_close(mgp->dev); + if (!rebooted) { + rtnl_lock(); + myri10ge_close(mgp->dev); + } status = myri10ge_load_firmware(mgp, 1); if (status != 0) printk(KERN_ERR "myri10ge: %s: failed to load firmware\n", @@ -3516,12 +3529,14 @@ static void myri10ge_watchdog_timer(unsigned long arg) { struct myri10ge_priv *mgp; struct myri10ge_slice_state *ss; - int i, reset_needed; + int i, reset_needed, busy_slice_cnt; u32 rx_pause_cnt; + u16 cmd; mgp = (struct myri10ge_priv *)arg; rx_pause_cnt = ntohl(mgp->ss[0].fw_stats->dropped_pause); + busy_slice_cnt = 0; for (i = 0, reset_needed = 0; i < mgp->num_slices && reset_needed == 0; ++i) { @@ -3559,8 +3574,22 @@ static void myri10ge_watchdog_timer(unsigned long arg) reset_needed = 1; } } + if (ss->watchdog_tx_done != ss->tx.done || + ss->watchdog_rx_done != ss->rx_done.cnt) { + busy_slice_cnt++; + } ss->watchdog_tx_done = ss->tx.done; ss->watchdog_tx_req = ss->tx.req; + ss->watchdog_rx_done = ss->rx_done.cnt; + } + /* if we've sent or received no traffic, poll the NIC to + * ensure it is still there. Otherwise, we risk not noticing + * an error in a timely fashion */ + if (busy_slice_cnt == 0) { + pci_read_config_word(mgp->pdev, PCI_COMMAND, &cmd); + if ((cmd & PCI_COMMAND_MASTER) == 0) { + reset_needed = 1; + } } mgp->watchdog_pause = rx_pause_cnt; -- cgit v0.10.2 From aed7df86983ead0af8364fd26d8a9609ef2ed584 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sun, 9 Aug 2009 03:27:18 +0000 Subject: net: include/linux/icmpv6: includecheck fix for icmpv6.h fix the following 'make includecheck' warning: include/linux/icmpv6.h: linux/skbuff.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: David S. Miller diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index b6a8518..c0d8357 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -171,8 +171,6 @@ struct icmp6_filter { #ifdef __KERNEL__ #include -#include - extern void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, -- cgit v0.10.2 From f2341641766af3de18502abb6ac9b98e0e4c6bdb Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sun, 9 Aug 2009 03:12:38 +0000 Subject: net: smc911x: includecheck fix for smc911x.h fix the following 'make includecheck' warning: drivers/net/smc911x.h: mach/dma.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: David S. Miller diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index 8140f7c..05adb6a 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -236,7 +236,6 @@ static inline void SMC_outsl(struct smc911x_local *lp, int reg, * Use a DMA for RX and TX packets. */ #include -#include static dma_addr_t rx_dmabuf, tx_dmabuf; static int rx_dmalen, tx_dmalen; -- cgit v0.10.2 From a8e9179a7de196d37410fd3e9528081f22c70a4e Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 10 Aug 2009 03:42:43 +0000 Subject: be2net: Clear pending tx completions before destroying tx queue Clear pending tx completions in be_close() (ndo.stop method) so that after unregister_netdev() calls be_close(), all tx skbs are freed and there are no more tx completions when txq is destroyed. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index d20235b..acce6a6 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1018,21 +1018,35 @@ static void be_rx_q_clean(struct be_adapter *adapter) BUG_ON(atomic_read(&rxq->used)); } -static void be_tx_q_clean(struct be_adapter *adapter) +static void be_tx_compl_clean(struct be_adapter *adapter) { - struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; - struct sk_buff *sent_skb; + struct be_queue_info *tx_cq = &adapter->tx_obj.cq; struct be_queue_info *txq = &adapter->tx_obj.q; - u16 last_index; - bool dummy_wrb; - - while (atomic_read(&txq->used)) { - sent_skb = sent_skbs[txq->tail]; - last_index = txq->tail; - index_adv(&last_index, - wrb_cnt_for_skb(sent_skb, &dummy_wrb) - 1, txq->len); - be_tx_compl_process(adapter, last_index); - } + struct be_eth_tx_compl *txcp; + u16 end_idx, cmpl = 0, timeo = 0; + + /* Wait for a max of 200ms for all the tx-completions to arrive. */ + do { + while ((txcp = be_tx_compl_get(tx_cq))) { + end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, + wrb_index, txcp); + be_tx_compl_process(adapter, end_idx); + cmpl++; + } + if (cmpl) { + be_cq_notify(adapter, tx_cq->id, false, cmpl); + cmpl = 0; + } + + if (atomic_read(&txq->used) == 0 || ++timeo > 200) + break; + + mdelay(1); + } while (true); + + if (atomic_read(&txq->used)) + dev_err(&adapter->pdev->dev, "%d pending tx-completions\n", + atomic_read(&txq->used)); } static void be_mcc_queues_destroy(struct be_adapter *adapter) @@ -1091,13 +1105,8 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) struct be_queue_info *q; q = &adapter->tx_obj.q; - if (q->created) { + if (q->created) be_cmd_q_destroy(adapter, q, QTYPE_TXQ); - - /* No more tx completions can be rcvd now; clean up if there - * are any pending completions or pending tx requests */ - be_tx_q_clean(adapter); - } be_queue_free(adapter, q); q = &adapter->tx_obj.cq; @@ -1645,6 +1654,11 @@ static int be_close(struct net_device *netdev) napi_disable(&rx_eq->napi); napi_disable(&tx_eq->napi); + /* Wait for all pending tx completions to arrive so that + * all tx skbs are freed. + */ + be_tx_compl_clean(adapter); + return 0; } -- cgit v0.10.2 From cdab23b7017693c00dd69fa28bcdf5b0434b3838 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 10 Aug 2009 03:43:23 +0000 Subject: be2net: fix bad queue traversal in be_rx_q_clean() Using "for(tail != head)" to traverse a queue from tail to head fails in the case of a fully filled queue. Use "for(used != 0)" instead. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index acce6a6..9bbf447 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1010,7 +1010,7 @@ static void be_rx_q_clean(struct be_adapter *adapter) /* Then free posted rx buffer that were not used */ tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len; - for (; tail != rxq->head; index_inc(&tail, rxq->len)) { + for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) { page_info = get_rx_page_info(adapter, tail); put_page(page_info->page); memset(page_info, 0, sizeof(*page_info)); -- cgit v0.10.2 From 859b1e4ec86840b0d0980f82b626d687be682eb9 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 10 Aug 2009 03:43:51 +0000 Subject: be2net: clear & notify residual events before destroying event queues Any events rcvd after interrupts are disabled (in the driver unload path), must be cleared and notified before the event queues are destroyed Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 9bbf447..2db879c 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -993,6 +993,56 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) kfree_skb(sent_skb); } +static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj) +{ + struct be_eq_entry *eqe = queue_tail_node(&eq_obj->q); + + if (!eqe->evt) + return NULL; + + eqe->evt = le32_to_cpu(eqe->evt); + queue_tail_inc(&eq_obj->q); + return eqe; +} + +static int event_handle(struct be_adapter *adapter, + struct be_eq_obj *eq_obj) +{ + struct be_eq_entry *eqe; + u16 num = 0; + + while ((eqe = event_get(eq_obj)) != NULL) { + eqe->evt = 0; + num++; + } + + /* Deal with any spurious interrupts that come + * without events + */ + be_eq_notify(adapter, eq_obj->q.id, true, true, num); + if (num) + napi_schedule(&eq_obj->napi); + + return num; +} + +/* Just read and notify events without processing them. + * Used at the time of destroying event queues */ +static void be_eq_clean(struct be_adapter *adapter, + struct be_eq_obj *eq_obj) +{ + struct be_eq_entry *eqe; + u16 num = 0; + + while ((eqe = event_get(eq_obj)) != NULL) { + eqe->evt = 0; + num++; + } + + if (num) + be_eq_notify(adapter, eq_obj->q.id, false, true, num); +} + static void be_rx_q_clean(struct be_adapter *adapter) { struct be_rx_page_info *page_info; @@ -1114,6 +1164,9 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); + /* Clear any residual events */ + be_eq_clean(adapter, &adapter->tx_eq); + q = &adapter->tx_eq.q; if (q->created) be_cmd_q_destroy(adapter, q, QTYPE_EQ); @@ -1185,6 +1238,9 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); + /* Clear any residual events */ + be_eq_clean(adapter, &adapter->rx_eq); + q = &adapter->rx_eq.q; if (q->created) be_cmd_q_destroy(adapter, q, QTYPE_EQ); @@ -1251,35 +1307,6 @@ rx_eq_free: be_queue_free(adapter, eq); return rc; } -static bool event_get(struct be_eq_obj *eq_obj, u16 *rid) -{ - struct be_eq_entry *entry = queue_tail_node(&eq_obj->q); - u32 evt = entry->evt; - - if (!evt) - return false; - - evt = le32_to_cpu(evt); - *rid = (evt >> EQ_ENTRY_RES_ID_SHIFT) & EQ_ENTRY_RES_ID_MASK; - entry->evt = 0; - queue_tail_inc(&eq_obj->q); - return true; -} - -static int event_handle(struct be_adapter *adapter, struct be_eq_obj *eq_obj) -{ - u16 rid = 0, num = 0; - - while (event_get(eq_obj, &rid)) - num++; - - /* We can see an interrupt and no event */ - be_eq_notify(adapter, eq_obj->q.id, true, true, num); - if (num) - napi_schedule(&eq_obj->napi); - - return num; -} static irqreturn_t be_intx(int irq, void *dev) { -- cgit v0.10.2 From cb7d9e7f9bedee2928fe5ce95e1d5f1f22c1f2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Tue, 11 Aug 2009 03:12:07 +0000 Subject: Phonet: fix /proc/net/phonet with network namespaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit seq_open_net() and seq_release() are needed for seq_file_net(). Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/net/phonet/socket.c b/net/phonet/socket.c index aa1617a..5f26c37 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -498,7 +498,8 @@ static const struct seq_operations pn_sock_seq_ops = { static int pn_sock_open(struct inode *inode, struct file *file) { - return seq_open(file, &pn_sock_seq_ops); + return seq_open_net(inode, file, &pn_sock_seq_ops, + sizeof(struct seq_net_private)); } const struct file_operations pn_sock_seq_fops = { @@ -506,5 +507,5 @@ const struct file_operations pn_sock_seq_fops = { .open = pn_sock_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_net, }; -- cgit v0.10.2 From 5edcc537af1a9810726d1b68ba6c59e5d8d36113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Mon, 10 Aug 2009 19:41:52 +0000 Subject: r8169: fix r8101 quirk dupe Noticed by Vincent Pelletier . Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b82780d..eac882b 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2757,7 +2757,7 @@ static void rtl_hw_start_8168(struct net_device *dev) EnableBist | \ Mac_dbgo_oe | \ Force_half_dup | \ - Force_half_dup | \ + Force_rxflow_en | \ Force_txflow_en | \ Cxpl_dbg_sel | \ ASF | \ -- cgit v0.10.2 From 21d57363201857bd8c5c0ad0ebc795134d632195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Mon, 10 Aug 2009 19:42:37 +0000 Subject: r8169: differentiate close chipsets in the startup identification message The driver displays the same 0x18000000 xid for RTL_GIGA_MAC_VER_06 and RTL_GIGA_MAC_VER_05 whereas the former ought to be identified as 0x98000000. Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index eac882b..6c4b879 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2180,7 +2180,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); if (netif_msg_probe(tp)) { - u32 xid = RTL_R32(TxConfig) & 0x7cf0f8ff; + u32 xid = RTL_R32(TxConfig) & 0x9cf0f8ff; printk(KERN_INFO "%s: %s at 0x%lx, " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " -- cgit v0.10.2 From 8c7006aa94bea415cd7f8c5fa8df9d3f261bd314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Mon, 10 Aug 2009 19:43:29 +0000 Subject: r8169: phy init for the 8169sce Synced with Realtek's 6.011.00 r8169 driver. Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 6c4b879..8672288 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1389,6 +1389,59 @@ static void rtl8169sb_hw_phy_config(void __iomem *ioaddr) rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } +static void rtl8169sce_hw_phy_config(void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x04, 0x0000 }, + { 0x03, 0x00a1 }, + { 0x02, 0x0008 }, + { 0x01, 0x0120 }, + { 0x00, 0x1000 }, + { 0x04, 0x0800 }, + { 0x04, 0x9000 }, + { 0x03, 0x802f }, + { 0x02, 0x4f02 }, + { 0x01, 0x0409 }, + { 0x00, 0xf099 }, + { 0x04, 0x9800 }, + { 0x04, 0xa000 }, + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0xff95 }, + { 0x00, 0xba00 }, + { 0x04, 0xa800 }, + { 0x04, 0xf000 }, + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0x101a }, + { 0x00, 0xa0ff }, + { 0x04, 0xf800 }, + { 0x04, 0x0000 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0001 }, + { 0x0b, 0x8480 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0001 }, + { 0x18, 0x67c7 }, + { 0x04, 0x2000 }, + { 0x03, 0x002f }, + { 0x02, 0x4360 }, + { 0x01, 0x0109 }, + { 0x00, 0x3022 }, + { 0x04, 0x2800 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0001 }, + { 0x17, 0x0cc0 }, + { 0x1f, 0x0000 } + }; + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); +} + static void rtl8168bb_hw_phy_config(void __iomem *ioaddr) { struct phy_reg phy_reg_init[] = { @@ -1628,6 +1681,9 @@ static void rtl_hw_phy_config(struct net_device *dev) case RTL_GIGA_MAC_VER_04: rtl8169sb_hw_phy_config(ioaddr); break; + case RTL_GIGA_MAC_VER_06: + rtl8169sce_hw_phy_config(ioaddr); + break; case RTL_GIGA_MAC_VER_07: case RTL_GIGA_MAC_VER_08: case RTL_GIGA_MAC_VER_09: -- cgit v0.10.2 From 2e955856ff1212bd63dbbf403940c72eca5b4a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Mon, 10 Aug 2009 19:44:19 +0000 Subject: r8169: phy init for the 8169scd Synced with Realtek's 6.011.00 r8169 driver. Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 8672288..4470fef 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1389,6 +1389,71 @@ static void rtl8169sb_hw_phy_config(void __iomem *ioaddr) rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } +static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp, + void __iomem *ioaddr) +{ + struct pci_dev *pdev = tp->pci_dev; + u16 vendor_id, device_id; + + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &vendor_id); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &device_id); + + if ((vendor_id != PCI_VENDOR_ID_GIGABYTE) || (device_id != 0xe000)) + return; + + mdio_write(ioaddr, 0x1f, 0x0001); + mdio_write(ioaddr, 0x10, 0xf01b); + mdio_write(ioaddr, 0x1f, 0x0000); +} + +static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp, + void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x04, 0x0000 }, + { 0x03, 0x00a1 }, + { 0x02, 0x0008 }, + { 0x01, 0x0120 }, + { 0x00, 0x1000 }, + { 0x04, 0x0800 }, + { 0x04, 0x9000 }, + { 0x03, 0x802f }, + { 0x02, 0x4f02 }, + { 0x01, 0x0409 }, + { 0x00, 0xf099 }, + { 0x04, 0x9800 }, + { 0x04, 0xa000 }, + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0xff95 }, + { 0x00, 0xba00 }, + { 0x04, 0xa800 }, + { 0x04, 0xf000 }, + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0x101a }, + { 0x00, 0xa0ff }, + { 0x04, 0xf800 }, + { 0x04, 0x0000 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0001 }, + { 0x10, 0xf41b }, + { 0x14, 0xfb54 }, + { 0x18, 0xf5c7 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0001 }, + { 0x17, 0x0cc0 }, + { 0x1f, 0x0000 } + }; + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + rtl8169scd_hw_phy_config_quirk(tp, ioaddr); +} + static void rtl8169sce_hw_phy_config(void __iomem *ioaddr) { struct phy_reg phy_reg_init[] = { @@ -1681,6 +1746,9 @@ static void rtl_hw_phy_config(struct net_device *dev) case RTL_GIGA_MAC_VER_04: rtl8169sb_hw_phy_config(ioaddr); break; + case RTL_GIGA_MAC_VER_05: + rtl8169scd_hw_phy_config(tp, ioaddr); + break; case RTL_GIGA_MAC_VER_06: rtl8169sce_hw_phy_config(ioaddr); break; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 73b46b6..fdc3110 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1984,6 +1984,8 @@ #define PCI_VENDOR_ID_SAMSUNG 0x144d +#define PCI_VENDOR_ID_GIGABYTE 0x1458 + #define PCI_VENDOR_ID_AMBIT 0x1468 #define PCI_VENDOR_ID_MYRICOM 0x14c1 -- cgit v0.10.2 From 0b9b571d246d1c2621a5e4e5a0fa5cb95e18365d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Mon, 10 Aug 2009 19:44:56 +0000 Subject: r8169: phy init for the 8169s Synced with Realtek's 6.011.00 r8169 driver. Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 4470fef..93a87aa 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1222,17 +1222,6 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_ethtool_stats = rtl8169_get_ethtool_stats, }; -static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, - int bitnum, int bitval) -{ - int val; - - val = mdio_read(ioaddr, reg); - val = (bitval == 1) ? - val | (bitval << bitnum) : val & ~(0x0001 << bitnum); - mdio_write(ioaddr, reg, val & 0xffff); -} - static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *ioaddr) { @@ -1328,54 +1317,69 @@ static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len) static void rtl8169s_hw_phy_config(void __iomem *ioaddr) { - struct { - u16 regs[5]; /* Beware of bit-sign propagation */ - } phy_magic[5] = { { - { 0x0000, //w 4 15 12 0 - 0x00a1, //w 3 15 0 00a1 - 0x0008, //w 2 15 0 0008 - 0x1020, //w 1 15 0 1020 - 0x1000 } },{ //w 0 15 0 1000 - { 0x7000, //w 4 15 12 7 - 0xff41, //w 3 15 0 ff41 - 0xde60, //w 2 15 0 de60 - 0x0140, //w 1 15 0 0140 - 0x0077 } },{ //w 0 15 0 0077 - { 0xa000, //w 4 15 12 a - 0xdf01, //w 3 15 0 df01 - 0xdf20, //w 2 15 0 df20 - 0xff95, //w 1 15 0 ff95 - 0xfa00 } },{ //w 0 15 0 fa00 - { 0xb000, //w 4 15 12 b - 0xff41, //w 3 15 0 ff41 - 0xde20, //w 2 15 0 de20 - 0x0140, //w 1 15 0 0140 - 0x00bb } },{ //w 0 15 0 00bb - { 0xf000, //w 4 15 12 f - 0xdf01, //w 3 15 0 df01 - 0xdf20, //w 2 15 0 df20 - 0xff95, //w 1 15 0 ff95 - 0xbf00 } //w 0 15 0 bf00 - } - }, *p = phy_magic; - unsigned int i; + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x06, 0x006e }, + { 0x08, 0x0708 }, + { 0x15, 0x4000 }, + { 0x18, 0x65c7 }, - mdio_write(ioaddr, 0x1f, 0x0001); //w 31 2 0 1 - mdio_write(ioaddr, 0x15, 0x1000); //w 21 15 0 1000 - mdio_write(ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7 - rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 + { 0x1f, 0x0001 }, + { 0x03, 0x00a1 }, + { 0x02, 0x0008 }, + { 0x01, 0x0120 }, + { 0x00, 0x1000 }, + { 0x04, 0x0800 }, + { 0x04, 0x0000 }, - for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) { - int val, pos = 4; + { 0x03, 0xff41 }, + { 0x02, 0xdf60 }, + { 0x01, 0x0140 }, + { 0x00, 0x0077 }, + { 0x04, 0x7800 }, + { 0x04, 0x7000 }, - val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff); - mdio_write(ioaddr, pos, val); - while (--pos >= 0) - mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff); - rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1 - rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 - } - mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0 + { 0x03, 0x802f }, + { 0x02, 0x4f02 }, + { 0x01, 0x0409 }, + { 0x00, 0xf0f9 }, + { 0x04, 0x9800 }, + { 0x04, 0x9000 }, + + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0xff95 }, + { 0x00, 0xba00 }, + { 0x04, 0xa800 }, + { 0x04, 0xa000 }, + + { 0x03, 0xff41 }, + { 0x02, 0xdf20 }, + { 0x01, 0x0140 }, + { 0x00, 0x00bb }, + { 0x04, 0xb800 }, + { 0x04, 0xb000 }, + + { 0x03, 0xdf41 }, + { 0x02, 0xdc60 }, + { 0x01, 0x6340 }, + { 0x00, 0x007d }, + { 0x04, 0xd800 }, + { 0x04, 0xd000 }, + + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0x100a }, + { 0x00, 0xa0ff }, + { 0x04, 0xf800 }, + { 0x04, 0xf000 }, + + { 0x1f, 0x0000 }, + { 0x0b, 0x0000 }, + { 0x00, 0x9200 } + }; + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } static void rtl8169sb_hw_phy_config(void __iomem *ioaddr) -- cgit v0.10.2 From 85910a8e9f425656bb7202d0fc62800000ffa262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Mon, 10 Aug 2009 19:45:48 +0000 Subject: r8169: phy init for the 8102e Synced with Realtek's 1.013.00 r8101 driver. Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 93a87aa..8cd8530 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1729,6 +1729,7 @@ static void rtl8102e_hw_phy_config(void __iomem *ioaddr) mdio_write(ioaddr, 0x1f, 0x0000); mdio_patch(ioaddr, 0x11, 1 << 12); mdio_patch(ioaddr, 0x19, 1 << 13); + mdio_patch(ioaddr, 0x10, 1 << 15); rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } -- cgit v0.10.2 From 6200f09036ee6f12822a9133dba7ed011b179c69 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 22:52:50 -0700 Subject: bnx2x: New FW files Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/firmware/bnx2x-e1-5.0.21.0.fw.ihex b/firmware/bnx2x-e1-5.0.21.0.fw.ihex new file mode 100644 index 0000000..c51afd4 --- /dev/null +++ b/firmware/bnx2x-e1-5.0.21.0.fw.ihex @@ -0,0 +1,10184 @@ +:10000000000028B0000000600000068800002918E9 +:100010000000161400002FA800000098000045C042 +:100020000000738800004660000000CC0000B9F0BA +:1000300000009A4C0000BAC0000000940001551066 +:10004000000057B8000155A8000000B80001AD68D5 +:100050000000CE1C0001AE280000000400027C4815 +:10006000020400480000000F020400540000004594 +:1000700002040058000000840204005C0000000636 +:100080000204007000000004020400780000000078 +:100090000204007C121700000204008022170000F6 +:1000A00002040084321700000604008800000005E6 +:1000B0000204009C12150000020400A0221500009A +:1000C000020400A432150000060400A80000000489 +:1000D000020400B802100000020400BC001000007E +:1000E000020400C010100000020400C42010000030 +:1000F000020400C830100000060400CC0000000418 +:10010000020400DC00100000020400E012140000F1 +:10011000020400E422140000020400E8321400008B +:10012000060400EC000000040104012400000000AB +:1001300001040128000000000104012C000000005F +:10014000010401300000000002040004000000FF70 +:1001500002040008000000FF0204000C000000FF81 +:1001600002040010000000FF02040014000000FF61 +:1001700002040018000000FF0204001C000000FF41 +:1001800002040020000000FF020400240000003EE2 +:1001900002040028000000000204002C0000003FC0 +:1001A000020400300000003F020400340000003F61 +:1001B00002040038000000000204003C0000003F80 +:1001C000020400400000003F020400440000003F21 +:1001D00002042008000004110204200C00000400A6 +:1001E000020420100000040402042014000004197A +:1001F0000204201C0000FFFF020420200000FFFF7B +:10020000020420240000FFFF020420280000FFFF5A +:1002100006042038000000020204204000000034E0 +:100220000204204400000035060420480000007C41 +:100230000204223807FFFFFF0204223C0000003FB7 +:100240000204224007FFFFFF020422440000000FC7 +:1002500001042248000000000104224C00000000BC +:10026000010422500000000001042254000000009C +:1002700001042258000000000104225C000000007C +:10028000010422600000000001042264000000005C +:1002900001042268000000000104226C000000003C +:1002A000010422700000000001042274000000001C +:1002B00001042278000000000104227C00000000FC +:1002C000020424BC000000010C042000000003E82C +:1002D0000A042000000000010B0420000000000AB6 +:1002E0000205004400000020020500480000003222 +:1002F000020500900215002002050094021500205E +:1003000002050098000000300205009C0810000063 +:10031000020500A000000033020500A40000003028 +:10032000020500A800000031020500AC0000000238 +:10033000020500B000000005020500B40000000640 +:10034000020500B800000002020500BC0000000227 +:10035000020500C000000000020500C40000000506 +:10036000020500C800000002020500CC00000002E7 +:10037000020500D000000002020500D400000001C8 +:1003800002050114000000010205011C000000012B +:100390000205012000000002020502040000000125 +:1003A0000205020C0000004002050210000000409F +:1003B0000205021C000000200205022000000013BC +:1003C0000205022400000020060502400000000A89 +:1003D0000405028000200000020500500000000714 +:1003E0000205005400000007020500580000000844 +:1003F0000205005C00000008060500600000000423 +:10040000020500D800000006020500E00000000D13 +:10041000020500E40000002D020500E800000007CE +:10042000020500EC00000027020500F000000007B4 +:10043000020500F400000027020500F80000000794 +:10044000020500FC00000027020500040000000176 +:1004500002050008000000010205000C0000000178 +:100460000205001000000001020500140000000158 +:1004700002050018000000010205001C0000000138 +:100480000205002000000001020500240000000118 +:1004900002050028000000010205002C00000001F8 +:1004A00002050030000000010205003400000001D8 +:1004B00002050038000000010205003C00000001B8 +:1004C00002050040000000010406100002000020A8 +:1004D000020600DC00000001010600D80000000058 +:1004E0000406020000030220020600DC00000000F7 +:1004F00002060068000000B802060078000001143F +:10050000010600B800000000010600C8000000005D +:100510000206006C000000B80206007C0000011416 +:10052000010600BC00000000010600CC0000000035 +:100530000718040000960000081807600014022342 +:10054000071C000034B80000071C800034E90D2FA0 +:10055000071D000009DD1A6A081D14005D800225D0 +:100560000118000000000000011800040000000055 +:1005700001180008000000000118000C0000000035 +:100580000118001000000000011800140000000015 +:1005900002180020000000010218002400000002E0 +:1005A00002180028000000030218002C00000000C0 +:1005B000021800300000000402180034000000019E +:1005C00002180038000000000218003C0000000182 +:1005D000021800400000000402180044000000005F +:1005E00002180048000000010218004C000000033F +:1005F0000218005000000000021800540000000122 +:1006000002180058000000040218005C00000000FE +:1006100002180060000000010218006400000003DE +:1006200002180068000000000218006C00000001C1 +:10063000021800700000000402180074000000009E +:1006400002180078000000040218007C000000037B +:100650000618008000000002021800A400003FFFFE +:10066000021800A8000003FF021802240000000086 +:1006700002180234000000000218024C00000000C2 +:10068000021802E4000000FF061810000000040039 +:10069000021B8BC000000001021B80000000003420 +:1006A000021B804000000018021B80800000000C2C +:1006B000021B80C0000000200C1B83000007A1204B +:1006C0000A1B8300000001380B1B83000000138805 +:1006D000021B83C0000001F4061A2000000000B2D3 +:1006E000061A23C800000181041A29CC0001022740 +:1006F000061A1020000000C8061A100000000002B0 +:10070000061A1E3800000002061A1E300000000201 +:10071000061A080000000002061A0808000000027D +:10072000061A081000000004041A1FB00005022871 +:10073000041A4CB00008022D061A22C8000000203E +:10074000061A400000000124021A4920000000009F +:10075000061A14000000000A061A145000000006D1 +:10076000061A150000000002041A150800050235DB +:10077000061A151C00000009061A15800000001456 +:10078000061A09C000000048061A0800000000020E +:10079000061A08200000000E041A1FB00002023AD8 +:1007A000061A2C2800000002061A23480000002028 +:1007B000061A449000000124021A49240000000097 +:1007C000061A14280000000A061A14680000000621 +:1007D000061A154000000002041A15480005023CE4 +:1007E000061A155C00000009061A15D00000001456 +:1007F000061A0AE000000048061A08080000000275 +:10080000061A08580000000E041A1FB80002024120 +:10081000061A2C30000000020200A2800000000135 +:100820000200A294071D29110200A29800000000F6 +:100830000200A29C009C04240200A2A00000000070 +:100840000200A2A4000002090200A4FCFF000000B4 +:10085000020100B400000001020100B80000000124 +:10086000020100DC000000010201010000000001A3 +:1008700002010104000000010201007C00300000C0 +:1008800002010084000000280201008C000000002A +:1008900002010130000000040201025C00000001BE +:1008A000020103280000000002010554000000308E +:1008B000020100C400000001020100CC00000001A0 +:1008C000020100F800000001020100F00000000138 +:1008D00002010080003000000201008800000028B2 +:1008E0000201009000000000020101340000000439 +:1008F000020102DC000000010201032C00000000E4 +:100900000201056400000030020100C8000000017F +:10091000020100D000000001020100FC0000000103 +:10092000020100F400000001020C10000000002091 +:10093000020C200800000A11020C200C00000A0022 +:10094000020C201000000A04020C201C0000FFFF13 +:10095000020C20200000FFFF020C20240000FFFFFB +:10096000020C20280000FFFF060C203800000002C7 +:10097000020C204000000034020C2044000000352E +:10098000020C204800000020020C204C0000002136 +:10099000020C205000000022020C20540000002312 +:1009A000020C205800000024020C205C00000025EE +:1009B000020C206000000026020C206400000027CA +:1009C000020C206800000028020C206C00000029A6 +:1009D000020C20700000002A020C20740000002B82 +:1009E000060C207800000056020C21D00000000107 +:1009F000020C21D400000001020C21D800000001EB +:100A0000020C21DC00000001020C21E000000001CA +:100A1000020C21E400000001020C21E800000001AA +:100A2000020C21EC00000001020C21F0000000018A +:100A3000020C21F400000001060C21F80000001057 +:100A4000020C223807FFFFFF020C223C0000003F8F +:100A5000020C224007FFFFFF020C22440000000F9F +:100A6000010C224800000000010C224C0000000094 +:100A7000010C225000000000010C22540000000074 +:100A8000010C225800000000010C225C0000000054 +:100A9000010C226000000000010C22640000000034 +:100AA000010C226800000000010C226C0000000014 +:100AB000010C227000000000010C227400000000F4 +:100AC000010C227800000000010C227C00000000D4 +:100AD000020C24BC000000010C0C2000000003E804 +:100AE0000A0C2000000000010B0C20000000000A8E +:100AF000020C400800000365020C400C0000035487 +:100B0000020C401000000358020C40140000037552 +:100B1000020C401C0000FFFF020C40200000FFFF01 +:100B2000020C40240000FFFF020C40280000FFFFE1 +:100B3000020C403800000046020C403C000000055A +:100B4000060C40400000005E020C41B800000001AD +:100B5000060C41BC0000001F020C423807FFFFFFDB +:100B6000020C423C0000003F020C424007FFFFFF26 +:100B7000020C42440000000F010C4248000000003B +:100B8000010C424C00000000010C4250000000002B +:100B9000010C425400000000010C4258000000000B +:100BA000010C425C00000000010C426000000000EB +:100BB000010C426400000000010C426800000000CB +:100BC000010C426C00000000010C427000000000AB +:100BD000010C427400000000010C4278000000008B +:100BE000010C427C00000000010C4280000000006B +:100BF000020C44C0000000010C0C4000000003E89F +:100C00000A0C4000000000010B0C40000000000A2C +:100C1000020D004400000032020D008C021500207D +:100C2000020D009002150020020D00940810000033 +:100C3000020D009800000033020D009C000000022D +:100C4000020D00A000000000020D00A4000000053D +:100C5000020D00A800000005060D00AC0000000217 +:100C6000020D00B400000002020D00B800000003F5 +:100C7000020D00BC00000002020D00C000000001D7 +:100C8000020D00C800000002020D00CC00000002AE +:100C9000020D010800000001020D015C00000001CE +:100CA000020D016400000001020D01680000000255 +:100CB000020D020400000001020D020C00000020E1 +:100CC000020D021000000040020D0214000000405E +:100CD000020D022000000003020D02240000001893 +:100CE000060D028000000012040D030000240243E0 +:100CF000020D004C00000001020D00500000000237 +:100D0000020D005400000008020D00580000000809 +:100D1000060D005C00000004020D00C40000000489 +:100D2000020D011400000009020D01180000002945 +:100D3000020D011C0000000A020D01200000002A23 +:100D4000020D012400000007020D01280000002709 +:100D5000020D012C00000007020D013000000027E9 +:100D6000020D01340000000C020D01380000002CBF +:100D7000020D013C0000000C020D01400000002C9F +:100D8000020D01440000000C020D01480000002C7F +:100D9000020D000400000001020D00080000000127 +:100DA000020D000C00000001020D00100000000107 +:100DB000020D001400000001020D001800000001E7 +:100DC000020D001C00000001020D002000000001C7 +:100DD000020D002400000001020D002800000001A7 +:100DE000020D002C00000001020D00300000000187 +:100DF000020D003400000001020D00380000000167 +:100E0000020D003C00000001020E004C0000003208 +:100E1000020E009402150020020E00980215002018 +:100E2000020E009C00000030020E00A0081000001E +:100E3000020E00A400000033020E00A800000030E3 +:100E4000020E00AC00000031020E00B000000002F3 +:100E5000020E00B400000004020E00B80000000002 +:100E6000020E00BC00000002020E00C000000002E2 +:100E7000020E00C400000000020E00C800000002C4 +:100E8000020E00CC00000007020E00D0000000029D +:100E9000020E00D400000002020E00D80000000183 +:100EA000020E00E400000001020E014400000001F7 +:100EB000020E014C00000001020E01500000000271 +:100EC000020E020400000001020E020C00000040AD +:100ED000020E021000000040020E021C000000047E +:100EE000020E022000000020020E02240000000E6C +:100EF000020E02280000001B060E03000000001274 +:100F0000040E0280001B0267020E00540000000C59 +:100F1000020E005800000007020E005C0000000FE7 +:100F2000020E006000000010060E006400000004C5 +:100F3000020E00DC00000003020E01100000000F92 +:100F4000020E01140000002F020E01180000000E16 +:100F5000020E011C0000002E020E00040000000121 +:100F6000020E000800000001020E000C000000014B +:100F7000020E001000000001020E0014000000012B +:100F8000020E001800000001020E001C000000010B +:100F9000020E002000000001020E002400000001EB +:100FA000020E002800000001020E002C00000001CB +:100FB000020E003000000001020E003400000001AB +:100FC000020E003800000001020E003C000000018B +:100FD000020E004000000001020E0044000000016B +:100FE0000730040000C900000830076800130282BF +:100FF00007340000341200000734800037B70D05B5 +:10100000073500002E7D1AF308356F405218028410 +:10101000013000000000000001300004000000006A +:1010200001300008000000000130000C000000004A +:10103000013000100000000001300014000000002A +:1010400002300020000000010230002400000002F5 +:1010500002300028000000030230002C00000000D5 +:1010600002300030000000040230003400000001B3 +:1010700002300038000000000230003C0000000197 +:101080000230004000000004023000440000000074 +:1010900002300048000000010230004C0000000354 +:1010A0000230005000000000023000540000000137 +:1010B00002300058000000040230005C0000000014 +:1010C00002300060000000010230006400000003F4 +:1010D00002300068000000000230006C00000001D7 +:1010E00002300070000000040230007400000000B4 +:1010F00002300078000000040230007C0000000391 +:101100000630008000000002023000A400003FFF13 +:10111000023000A8000003FF02300224000000009B +:1011200002300234000000000230024C00000000D7 +:10113000023002E40000FFFF06302000000008003B +:1011400002338BC000000001023380000000001A4F +:10115000023380400000004E023380800000001007 +:10116000023380C0000000200C3383000007A12060 +:101170000A338300000001380B338300000013881A +:10118000023383C0000001F40C3383801DCD650061 +:101190000A3383800004C4B40B338380004C4B407B +:1011A00006321AA0000000C206321020000000C85B +:1011B0000632100000000002063214000000004059 +:1011C00006325098000000040632508000000005EE +:1011D00004325094000102860632500000000020C4 +:1011E00004322830000202870233080001000000A8 +:1011F00004330C00001002890233080000000000D4 +:1012000004330C400010029906321500000000B4AF +:1012100002321DC80000000006324000000000D865 +:10122000063217D0000000B402321DCC00000000CE +:1012300006324360000000D807200400009200003E +:1012400008200780001002A9072400002CCF00000E +:10125000072480002AE50B340824DC6062DA02AB44 +:101260000120000000000000012000040000000038 +:1012700001200008000000000120000C0000000018 +:1012800001200010000000000120001400000000F8 +:1012900002200020000000010220002400000002C3 +:1012A00002200028000000030220002C00000000A3 +:1012B0000220003000000004022000340000000181 +:1012C00002200038000000000220003C0000000165 +:1012D0000220004000000004022000440000000042 +:1012E00002200048000000010220004C0000000322 +:1012F0000220005000000000022000540000000105 +:1013000002200058000000040220005C00000000E1 +:1013100002200060000000010220006400000003C1 +:1013200002200068000000000220006C00000001A4 +:101330000220007000000004022000740000000081 +:1013400002200078000000040220007C000000035E +:101350000620008000000002022000A400003FFFE1 +:10136000022000A8000003FF022002240000000069 +:1013700002200234000000000220024C00000000A5 +:10138000022002E40000FFFF062020000000080009 +:1013900002238BC000000001022380000000001027 +:1013A00002238040000000120223808000000030F1 +:1013B000022380C00000000E022383C0000001F45D +:1013C000062250000000004206221020000000C843 +:1013D000062210000000000206222000000000C0CB +:1013E000062225C00000024004222EC8000802ADDB +:1013F00002230800013FFFFF04230C00001002B588 +:10140000022308000000000004230C40001002C565 +:1014100006223040000000A00622354000000010E7 +:10142000062236C000000030062240000000020004 +:10143000062235C00000002006223840000000309F +:1014400006223000000000080222511800000000AF +:10145000062223000000000E0622241000000030A7 +:10146000062232C0000000A00622358000000010D5 +:1014700006223780000000300622480000000200EB +:10148000062236400000002006223900000000300D +:1014900006223020000000080222511C000000003B +:1014A000062223380000000E062224D0000000305F +:1014B00002161000000000280217000800000002B9 +:1014C0000217002C000000030217003C000000047B +:1014D0000217004400000008021700480000000244 +:1014E0000217004C0000009002170050000000900E +:1014F00002170054008000900217005808140000E2 +:10150000021700600000008A0217006400000080DB +:1015100002170068000000810217006C00000080C4 +:10152000021700700000000602170078000007D0C4 +:101530000217007C0000076C02170038007C1004C2 +:10154000021700040000000F0616402400000002ED +:10155000021640700000001C021642080000000144 +:101560000216421000000001021642200000000195 +:10157000021642280000000102164230000000015D +:10158000021642380000000102164260000000010D +:101590000C16401C0003D0900A16401C0000009C52 +:1015A0000B16401C000009C4021640300000000861 +:1015B000021640340000000C0216403800000010F3 +:1015C0000216404400000020021640000000000106 +:1015D000021640D800000001021640080000000179 +:1015E0000216400C0000000102164010000000012D +:1015F00002164240000000000216424800000000AF +:101600000616427000000002021642500000000060 +:101610000216425800000000061642800000000238 +:1016200002166008000006140216600C0000060096 +:1016300002166010000006040216601C0000FFFF86 +:10164000021660200000FFFF021660240000FFFF6A +:10165000021660280000FFFF02166038000000201C +:101660000216603C000000200216604000000034BA +:101670000216604400000035021660480000002396 +:101680000216604C00000024021660500000002585 +:101690000216605400000026021660580000002761 +:1016A0000216605C00000029021660600000002A3B +:1016B000021660640000002B021660680000002C17 +:1016C0000216606C0000002D0616607000000052CB +:1016D000021661B800000001061661BC0000001F80 +:1016E0000216623807FFFFFF0216623C0000003F4F +:1016F0000216624007FFFFFF021662440000000F5F +:1017000001166248000000000116624C0000000053 +:101710000116625000000000011662540000000033 +:1017200001166258000000000116625C0000000013 +:1017300001166260000000000116626400000000F3 +:1017400001166268000000000116626C00000000D3 +:1017500001166270000000000116627400000000B3 +:1017600001166278000000000116627C0000000093 +:10177000021664BC000000010C166000000003E8C3 +:101780000A166000000000010B1660000000000A4D +:10179000021680400000000602168044000000058A +:1017A000021680480000000A0216804C0000000566 +:1017B0000216805400000002021680CC00000004D3 +:1017C000021680D000000004021680D4000000043D +:1017D000021680D800000004021680DC000000041D +:1017E000021680E000000004021680E400000004FD +:1017F000021680E8000000040216880400000004BD +:10180000021680300000007C021680340000003D8B +:10181000021680380000003F0216803C0000009C49 +:10182000021680F000000007061680F40000000594 +:101830000216880C01010101021681080000000057 +:101840000216810C00000004021681100000000442 +:1018500002168114000000020216881008012004FC +:1018600002168118000000050216811C0000000508 +:1018700002168120000000050216812400000005E8 +:101880000216882C2008100102168128000000088A +:101890000216812C000000060216813000000007AD +:1018A0000216813400000000021688300101012078 +:1018B0000616813800000004021688340101010177 +:1018C0000616814800000004021688380101010153 +:1018D00006168158000000040216883C010101012F +:1018E00006168168000000030216817400000001E2 +:1018F00002168840010101010216817800000001F2 +:101900000216817C000000010216818000000001A7 +:1019100002168184000000010216884401010101C1 +:1019200002168188000000010216818C000000046C +:10193000021681900000000402168194000000024B +:10194000021688480801200402168198000000054C +:101950000216819C00000005021681A0000000050F +:10196000021681A400000005021688142008100148 +:10197000021681A800000008021681AC00000006D3 +:10198000021681B000000007021681B400000001B9 +:101990000216881801010120021681B8000000011A +:1019A000021681BC00000001021681C00000000187 +:1019B000021681C4000000010216881C0101010109 +:1019C000021681C800000001021681CC000000014F +:1019D000021681D000000001021681D4000000012F +:1019E0000216882001010101021681D800000001C1 +:1019F000021681DC00000001021681E000000001F7 +:101A0000021681E400000001021688240101010190 +:101A1000021681E800000001021681EC00000001BE +:101A2000021681F000000001021688280101010160 +:101A300002168240FFFF003F0616824400000002AB +:101A40000216824CFFFF003F021682500000010088 +:101A5000021682540000010006168258000000029F +:101A600002168260000000C002168264000000C0FE +:101A70000216826800001E000216826C00001E0022 +:101A800002168270000040000216827400004000BE +:101A900002168278000080000216827C000080001E +:101AA00002168280000020000216828400002000BE +:101AB0000616828800000007021682A400000001BA +:101AC000061682A80000000A021681F400000C0825 +:101AD000021681F800000040021681FC000001009F +:101AE0000216820000000020021682040000001787 +:101AF00002168208000000800216820C000002001C +:101B0000021682100000000002168218FFFF01FF7B +:101B100002168214FFFF01FF0216823C0000001330 +:101B2000021680900000013F021680600000014014 +:101B30000216806400000140061680680000000262 +:101B400002168070000000C00616807400000007B6 +:101B50000216809C00000048021680A00000004889 +:101B6000061680A400000002021680AC00000048A7 +:101B7000061680B0000000070216823800008000C0 +:101B800002168234000025E40216809400007FFFD4 +:101B900002168220000000070216821C00000007C7 +:101BA000021682280000000002168224FFFFFFFFB9 +:101BB00002168230000000000216822CFFFFFFFF99 +:101BC000021680EC000000FF02140000000000017B +:101BD0000214000C0000000102140040000000018B +:101BE0000214004400007FFF0214000C00000000FB +:101BF00002140000000000000214006C000000004D +:101C00000214000400000001021400300000000172 +:101C100002140004000000000214005C0000000038 +:101C2000021400080000000102140034000000014A +:101C30000214000800000000021400600000000010 +:101C40000202005800000032020200A0031500202A +:101C5000020200A403150020020200A801000030C7 +:101C6000020200AC08100000020200B000000033C5 +:101C7000020200B400000030020200B8000000318F +:101C8000020200BC00000003020200C000000006C7 +:101C9000020200C400000003020200C800000003AA +:101CA000020200CC00000002020200D0000000008E +:101CB000020200D400000002020200DC000000006A +:101CC000020200E000000006020200E4000000043E +:101CD000020200E800000002020200EC0000000224 +:101CE000020200F000000001020200FC00000006F9 +:101CF0000202012000000000020201340000000284 +:101D0000020201B0000000010202020C000000010A +:101D10000202021400000001020202180000000288 +:101D200002020404000000010202040C0000004052 +:101D300002020410000000400202041C0000000423 +:101D4000020204200000002002020424000000021D +:101D5000020204280000001F060205000000001215 +:101D600004020480001F02D5020200600000000F80 +:101D70000202006400000007020200680000000B7D +:101D80000202006C0000000E060200700000000459 +:101D9000020200F40000000402020004000000013E +:101DA00002020008000000010202000C0000000115 +:101DB00002020010000000010202001400000001F5 +:101DC00002020018000000010202001C00000001D5 +:101DD00002020020000000010202002400000001B5 +:101DE00002020028000000010202002C0000000195 +:101DF0000202003000000001020200340000000175 +:101E000002020038000000010202003C0000000154 +:101E10000202004000000001020200440000000134 +:101E200002020048000000010202004C0000000114 +:101E3000020200500000000102020108000000C878 +:101E40000202011800000002020201C400000000AA +:101E5000020201CC00000000020201D400000002D6 +:101E6000020201DC00000002020201E4000000FFA7 +:101E7000020201EC000000FF0202010C000000C899 +:101E80000202011C00000002020201C80000000062 +:101E9000020201D000000000020201D8000000028E +:101EA000020201E000000002020201E8000000FF5F +:101EB000020201F0000000FF0728040000B4000047 +:101EC00008280768001302F4072C000035D700002B +:101ED000072C80003A590D76072D00003B741C0D2D +:101EE000072D8000226C2AEB082DC6F0472202F64F +:101EF000012800000000000001280004000000008C +:101F000001280008000000000128000C000000006B +:101F1000012800100000000001280014000000004B +:101F20000228002000000001022800240000000216 +:101F300002280028000000030228002C00000000F6 +:101F400002280030000000040228003400000001D4 +:101F500002280038000000000228003C00000001B8 +:101F60000228004000000004022800440000000095 +:101F700002280048000000010228004C0000000375 +:101F80000228005000000000022800540000000158 +:101F900002280058000000040228005C0000000035 +:101FA0000228006000000001022800640000000315 +:101FB00002280068000000000228006C00000001F8 +:101FC00002280070000000040228007400000000D5 +:101FD00002280078000000040228007C00000003B2 +:101FE0000628008000000002022800A400003FFF35 +:101FF000022800A8000003FF0228022400000000BD +:1020000002280234000000000228024C00000000F8 +:10201000022802E40000FFFF06282000000008005C +:10202000022B8BC000000001022B8000000000008A +:10203000022B804000000018022B80800000000C62 +:10204000022B80C0000000660C2B83000007A1203B +:102050000A2B8300000001380B2B8300000013883B +:10206000022B83C0000001F40C2B8340000001F41C +:102070000A2B8340000000000B2B8340000000056A +:102080000A2B83800004C4B40C2B83801DCD650013 +:102090000B2B8380004C4B40062A3C400000000480 +:1020A000042A3C50000202F8062A300000000048D2 +:1020B000062A1020000000C8062A100000000002B6 +:1020C000062A31280000008E022A33680000000032 +:1020D000042A3370000202FA042A3A70000402FC57 +:1020E000042A3D0000020300042A15000002030236 +:1020F000062A150800000100022A197000000000DD +:10210000022A197800000000042A19600002030462 +:10211000062A4AC000000002062A4B000000000404 +:10212000042A1F4800020306022B080000000000DA +:10213000042B0C0000100308022B08000100000013 +:10214000042B0C4000080318022B080002000000BA +:10215000042B0C6000080320062A3A8000000014BB +:10216000062A3B2000000024062A14000000000A72 +:10217000062A145000000006062A3378000000D812 +:10218000022A3A3800000000042A3C5800020328C2 +:10219000042A3C680010032A062A5020000000028E +:1021A000062A503000000002062A500000000002FB +:1021B000062A501000000002022A504000000000D1 +:1021C000062A50480000000E022A50B80000000104 +:1021D000042A4AC80002033A062A4B1000000042B3 +:1021E000062A4D2000000004062A3AD00000001400 +:1021F000062A3BB000000024062A14280000000A2A +:10220000062A146800000006062A36D8000000D806 +:10221000022A3A3C00000000042A3C600002033C11 +:10222000042A3CA80010033E062A502800000002A1 +:10223000062A503800000002062A5008000000025A +:10224000062A501800000002022A50440000000034 +:10225000062A50800000000E022A50BC0000000137 +:10226000042A4AD00002034E062A4C1800000042FD +:10227000062A4D3000000004021010080000000182 +:102280000210101000000264021010000003D000C1 +:10229000021010040000003D091018000200035055 +:1022A00009101100002005500610118000000002E6 +:1022B0000910118800060570061011A00000001812 +:1022C000021010100000000006102400000000E0C2 +:1022D0000210201C0000000002102020000000015D +:1022E000021020C0000000010210200400000001C4 +:1022F000021020080000000109103C0000050576CE +:1023000009103C200005057B0910380000050580F8 +:1023100002104028000000100210404400003FFF5F +:102320000210405800280000021040840084924AA5 +:1023300002104058000000000610806800000004F1 +:1023400002108000000010800610802800000002AB +:102350000210803800000010021080400000FFFFD3 +:10236000021080440000FFFF0210805000000000B7 +:102370000210810000000000061081200000000211 +:1023800002108008000002B502108010000000005A +:10239000061082000000004A021081080001FFFFC1 +:1023A00006108140000000020210800000001A8028 +:1023B0000610900000000024061091200000004A42 +:1023C000061093700000004A061095C00000004AF5 +:1023D000021080040000108006108030000000020F +:1023E0000210803C00000010021080480000FFFF37 +:1023F0000210804C0000FFFF02108054000000001B +:102400000210810400000000061081280000000274 +:102410000210800C000002B50210801400000000C1 +:10242000061084000000004A0210810C0001FFFF2A +:1024300006108148000000020210800400001A808B +:102440000610909000000024061092480000004AF8 +:10245000061094980000004A061096E80000004A12 +:102460000212049000E383400212051400003C10A5 +:10247000021205200000000202120494FFFFFFFF79 +:1024800002120498FFFFFFFF0212049CFFFFFFFFF0 +:10249000021204A0FFFFFFFF021204A4FFFFFFFFD0 +:1024A000021204A8FFFFFFFF021204ACFFFFFFFFB0 +:1024B000021204B0FFFFFFFF021204B8FFFFFFFF8C +:1024C000021204BCFFFFFFFF021204C0FFFFFFFF68 +:1024D000021204C4FFFFFFFF021204C8FFFFFFFF48 +:1024E000021204CCFFFFFFFF021204D0FFFFFFFF28 +:1024F000021204DCFFFFFFFF021204E0FFFFFFFFF8 +:10250000021204E4FFFFFFFF021204E8FFFFFFFFD7 +:10251000021204ECFFFFFFFF021204F0FFFFFFFFB7 +:10252000021204F4FFFFFFFF021204F8FFFFFFFF97 +:10253000021204FCFFFFFFFF02120500FFFFFFFF76 +:1025400002120504FFFFFFFF02120508FFFFFFFF55 +:102550000212050CFFFFFFFF02120510FFFFFFFF35 +:10256000021204D4FFFF3330021204D8FFFF3340BD +:10257000021204B4F00030000212039000000008C0 +:102580000212039C00000008061203A000000002D3 +:10259000021203BC00000004021203C40000000485 +:1025A000021203D000000000021203DC0000000051 +:1025B0000212036C00000001021203680000003FD9 +:1025C000021201BC00000040021201C00000180805 +:1025D000021201C400000803021201C8000008032F +:1025E000021201CC00000040021201D000000003E2 +:1025F000021201D400000803021201D800000803EF +:10260000021201DC00000803021201E000010003D5 +:10261000021201E400000803021201E800000803AE +:10262000021201EC00000003021201F0000000039E +:10263000021201F400000003021201F8000000037E +:10264000021201FC0000000302120200000000035D +:10265000021202040000000302120208000000033C +:102660000212020C0000000302120210000000031C +:1026700002120214000000030212021800000003FC +:102680000212021C000000030212022000000003DC +:102690000212022400000003021202280000240398 +:1026A0000212022C0000002F02120230000000096A +:1026B00002120234000000190212023800000184E4 +:1026C0000212023C000001830212024000000306D5 +:1026D0000212024400000019021202480000000623 +:1026E0000212024C00000306021202500000030610 +:1026F00002120254000003060212025800000C8667 +:102700000212025C000003060212026000000306CF +:1027100002120264000000060212026800000006B5 +:102720000212026C00000006021202700000000695 +:102730000212027400000006021202780000000675 +:102740000212027C00000006021202800000000655 +:102750000212028400000006021202880000000635 +:102760000212028C00000006021202900000000615 +:1027700002120294000000060212029800000006F5 +:102780000212029C00000006021202A000000306D2 +:10279000021202A400000013021202A800000006A8 +:1027A000021202B000001004021202B40000100471 +:1027B0000212032400106440021203280010644037 +:1027C000021201B0000000010600A0000000001687 +:1027D0000200A06CBF5C00000200A070FFF51FEFBC +:1027E0000200A0740000FFFF0200A078500003E088 +:1027F0000200A07C000000000200A0800000A000F9 +:102800000600A084000000050200A0980FE0000070 +:102810000600A09C000000140200A0EC555400002B +:102820000200A0F0555555550200A0F40000555582 +:102830000200A0F8000000000200A0FC55540000B7 +:102840000200A100555555550200A1040000555540 +:102850000200A108000000000200A22C00000000FD +:102860000600A230000000030200A0600000000784 +:102870000200A10CBF5C00000200A110FFF51FEFD9 +:102880000200A1140000FFFF0200A118500003E0A5 +:102890000200A11C000000000200A1200000A00016 +:1028A0000600A124000000050200A1380FE000008E +:1028B0000600A13C000000140200A18C5554000049 +:1028C0000200A190555555550200A19400005555A0 +:1028D0000200A198000000000200A19C55540000D5 +:1028E0000200A1A0555555550200A1A40000555560 +:1028F0000200A1A8000000000200A23C00000000AD +:102900000600A240000000030200A06400000007CF +:1029100000000000000000000000002E0000000089 +:1029200000000000000000000000000000000000A7 +:102930000000000000000000000000000000000097 +:102940000000000000000000000000000000000087 +:102950000000000000000000000000000000000077 +:102960000000000000000000000000000000000067 +:10297000002E0050000000000000000000000000D9 +:102980000000000000000000000000000000000047 +:102990000000000000000000000000000050008D5A +:1029A0000000000000000000000000000000000027 +:1029B0000000000000000000000000000000000017 +:1029C0000000000000000000008D009200920096C0 +:1029D0000096009A000000000000000000000000C7 +:1029E00000000000000000000000000000000000E7 +:1029F00000000000009A00DB00DB00E900E900F7BE +:102A000000000000000000000000000000000000C6 +:102A100000000000000000000000000000000000B6 +:102A200000000000000000000000000000000000A6 +:102A30000000000000000000000000000000000096 +:102A40000000000000000000000000000000000086 +:102A50000000000000000000000000000000000076 +:102A60000000000000000000000000000000000066 +:102A70000000000000000000000000000000000056 +:102A80000000000000000000000000000000000046 +:102A90000000000000000000000000000000000036 +:102AA0000000000000000000000000000000000026 +:102AB0000000000000000000000000000000000016 +:102AC0000000000000000000000000000000000006 +:102AD00000F700FE00000000000000000000000001 +:102AE00000000000000000000000000000000000E6 +:102AF00000000000000000000000000000000000D6 +:102B000000000000000000000000000000000000C5 +:102B100000000000000000000000000000000000B5 +:102B2000000000000000000000FE01030103010E90 +:102B3000010E01190000000000000000000000006C +:102B40000000000000000000000000000000000085 +:102B50000000000000000000000000000000000075 +:102B60000000000000000000000000000000000065 +:102B70000000000000000000000000000000000055 +:102B80000119011A00000000000000000000000010 +:102B90000000000000000000000000000000000035 +:102BA000000000000000000000000000011A0152B7 +:102BB0000000000000000000000000000000000015 +:102BC0000000000000000000000000000000000005 +:102BD000000000000000000001520176000000002B +:102BE00000000000000000000000000000000000E5 +:102BF00000000000000000000000000000000000D5 +:102C000000000000017601B5000000000000000097 +:102C100000000000000000000000000000000000B4 +:102C200000000000000000000000000000000000A4 +:102C300001B501F0000000000000000000000000ED +:102C40000000000000000000000000000000000084 +:102C500000000000000000000000000001F002354C +:102C6000023502380238023B00000000000000007C +:102C70000000000000000000000000000000000054 +:102C80000000000000000000023B02760276028095 +:102C90000280028A00000000000000000000000026 +:102CA0000000000000000000000000000000000024 +:102CB00000000000028A028B0000000000000000FB +:102CC0000000000000000000000000000000000004 +:102CD00000000000000000000000000000000000F4 +:102CE000028B029D000000000000000000000000B8 +:102CF00000000000000000000000000000000000D4 +:102D0000000000000000000000000000029D02B270 +:102D100002B202B502B502B80000000000000000D7 +:102D200000000000000000000000000000000000A3 +:102D3000000000000000000002B802E600000000F1 +:102D40000000000000000000000000000000000083 +:102D50000000000000000000000000000000000073 +:102D60000000000002E6036D00000000000000000B +:102D70000000000000000000000000000000000053 +:102D80000000000000000000000000000000000043 +:102D9000036D0374037403780378037C0000000060 +:102DA0000000000000000000000000000000000023 +:102DB000000000000000000000000000037C03BBD6 +:102DC00003BB03C303C303CB0000000000000000EB +:102DD00000000000000000000000000000000000F3 +:102DE000000000000000000003CB041F041F04319A +:102DF0000431044300000000000000000000000057 +:102E000000000000000000000000000000000000C2 +:102E1000000000000443044D00000000000000001A +:102E200000000000000000000000000000000000A2 +:102E30000000000000000000000000000000000092 +:102E4000044D0453000000000000000000000000DA +:102E50000000000000000000000000000000000072 +:102E600000000000000000000000000004530456B1 +:102E70000000000000000000000000000000000052 +:102E80000000000000000000000000000000000042 +:102E900000000000000000000456045B0000000079 +:102EA0000000000000000000000000000000000022 +:102EB0000000000000000000000000000000000012 +:102EC00000000000045B045C045C046E046E04807B +:102ED00000000000000000000000000000000000F2 +:102EE00000000000000000000000000000000000E2 +:102EF000048004ED0000000000000000000000005D +:102F000000000000000000000000000000000000C1 +:102F100000000000000000000000000004ED04EECE +:102F200004EE050205020516000000000000000086 +:102F30000000000000000000000000000000000091 +:102F40000000000000000000000000000000000081 +:102F50000000000000000000000000000000000071 +:102F60000000000000000000000000000000000061 +:102F70000000000000000000000000000000000051 +:102F80000000000000000000000000000000000041 +:102F90000000000000000000000000000000000031 +:102FA000000000000000000000010000000204C05A +:102FB0000003098000040E4000051300000617C03E +:102FC00000071C800008214000092600000A2AC0D2 +:102FD000000B2F80000C3440000D3900000E3DC066 +:102FE000000F42800010474000114C00001250C0FA +:102FF0000013558000145A4000155F00001663C08E +:103000000017688000186D4000197200001A76C021 +:10301000001B7B80001C8040001D8500001E89C0B5 +:10302000001F8E8000209340000020000000400020 +:1030300000006000000080000000A0000000C00050 +:103040000000E0000001000000012000000140003D +:1030500000016000000180000001A0000001C0002C +:103060000001E00000020000000220000002400019 +:1030700000026000000280000002A0000002C00008 +:103080000002E000000300000003200000034000F5 +:1030900000036000000380000003A0000003C000E4 +:1030A0000003E000000400000004200000044000D1 +:1030B00000046000000480000004A0000004C000C0 +:1030C0000004E000000500000005200000054000AD +:1030D00000056000000580000005A0000005C0009C +:1030E0000005E00000060000000620000006400089 +:1030F00000066000000680000006A0000006C00078 +:103100000006E00000070000000720000007400064 +:1031100000076000000780000007A0000007C00053 +:103120000007E00000080000000820000008400040 +:1031300000086000000880000008A0000008C0002F +:103140000008E0000009000000092000000940001C +:1031500000096000000980000009A0000009C0000B +:103160000009E000000A0000000A2000000A4000F8 +:10317000000A6000000A8000000AA000000AC000E7 +:10318000000AE000000B0000000B2000000B4000D4 +:10319000000B6000000B8000000BA000000BC000C3 +:1031A000000BE000000C0000000C2000000C4000B0 +:1031B000000C6000000C8000000CA000000CC0009F +:1031C000000CE000000D0000000D2000000D40008C +:1031D000000D6000000D8000000DA000000DC0007B +:1031E000000DE000000E0000000E2000000E400068 +:1031F000000E6000000E8000000EA000000EC00057 +:10320000000EE000000F0000000F2000000F400043 +:10321000000F6000000F8000000FA000000FC00032 +:10322000000FE0000010000000102000001040001F +:1032300000106000001080000010A0000010C0000E +:103240000010E000001100000011200000114000FB +:1032500000116000001180000011A0000011C000EA +:103260000011E000001200000012200000124000D7 +:1032700000126000001280000012A0000012C000C6 +:103280000012E000001300000013200000134000B3 +:1032900000136000001380000013A0000013C000A2 +:1032A0000013E0000014000000142000001440008F +:1032B00000146000001480000014A0000014C0007E +:1032C0000014E0000015000000152000001540006B +:1032D00000156000001580000015A0000015C0005A +:1032E0000015E00000160000001620000016400047 +:1032F00000166000001680000016A0000016C00036 +:103300000016E00000170000001720000017400022 +:1033100000176000001780000017A0000017C00011 +:103320000017E000001800000018200000184000FE +:1033300000186000001880000018A0000018C000ED +:103340000018E000001900000019200000194000DA +:1033500000196000001980000019A0000019C000C9 +:103360000019E000001A0000001A2000001A4000B6 +:10337000001A6000001A8000001AA000001AC000A5 +:10338000001AE000001B0000001B2000001B400092 +:10339000001B6000001B8000001BA000001BC00081 +:1033A000001BE000001C0000001C2000001C40006E +:1033B000001C6000001C8000001CA000001CC0005D +:1033C000001CE000001D0000001D2000001D40004A +:1033D000001D6000001D8000001DA000001DC00039 +:1033E000001DE000001E0000001E2000001E400026 +:1033F000001E6000001E8000001EA000001EC00015 +:10340000001EE000001F0000001F2000001F400001 +:10341000001F6000001F8000001FA000001FC000F0 +:10342000001FE000002000000020200000204000DD +:1034300000206000002080000020A0000020C000CC +:103440000020E000002100000021200000214000B9 +:1034500000216000002180000021A0000021C000A8 +:103460000021E00000220000002220000022400095 +:1034700000226000002280000022A0000022C00084 +:103480000022E00000230000002320000023400071 +:1034900000236000002380000023A0000023C00060 +:1034A0000023E0000024000000242000002440004D +:1034B00000246000002480000024A0000024C0003C +:1034C0000024E00000250000002520000025400029 +:1034D00000256000002580000025A0000025C00018 +:1034E0000025E00000260000002620000026400005 +:1034F00000266000002680000026A0000026C000F4 +:103500000026E000002700000027200000274000E0 +:1035100000276000002780000027A0000027C000CF +:103520000027E000002800000028200000284000BC +:1035300000286000002880000028A0000028C000AB +:103540000028E00000290000002920000029400098 +:1035500000296000002980000029A0000029C00087 +:103560000029E000002A0000002A2000002A400074 +:10357000002A6000002A8000002AA000002AC00063 +:10358000002AE000002B0000002B2000002B400050 +:10359000002B6000002B8000002BA000002BC0003F +:1035A000002BE000002C0000002C2000002C40002C +:1035B000002C6000002C8000002CA000002CC0001B +:1035C000002CE000002D0000002D2000002D400008 +:1035D000002D6000002D8000002DA000002DC000F7 +:1035E000002DE000002E0000002E2000002E4000E4 +:1035F000002E6000002E8000002EA000002EC000D3 +:10360000002EE000002F0000002F2000002F4000BF +:10361000002F6000002F8000002FA000002FC000AE +:10362000002FE0000030000000302000003040009B +:1036300000306000003080000030A0000030C0008A +:103640000030E00000310000003120000031400077 +:1036500000316000003180000031A0000031C00066 +:103660000031E00000320000003220000032400053 +:1036700000326000003280000032A0000032C00042 +:103680000032E0000033000000332000003340002F +:1036900000336000003380000033A0000033C0001E +:1036A0000033E0000034000000342000003440000B +:1036B00000346000003480000034A0000034C000FA +:1036C0000034E000003500000035200000354000E7 +:1036D00000356000003580000035A0000035C000D6 +:1036E0000035E000003600000036200000364000C3 +:1036F00000366000003680000036A0000036C000B2 +:103700000036E0000037000000372000003740009E +:1037100000376000003780000037A0000037C0008D +:103720000037E0000038000000382000003840007A +:1037300000386000003880000038A0000038C00069 +:103740000038E00000390000003920000039400056 +:1037500000396000003980000039A0000039C00045 +:103760000039E000003A0000003A2000003A400032 +:10377000003A6000003A8000003AA000003AC00021 +:10378000003AE000003B0000003B2000003B40000E +:10379000003B6000003B8000003BA000003BC000FD +:1037A000003BE000003C0000003C2000003C4000EA +:1037B000003C6000003C8000003CA000003CC000D9 +:1037C000003CE000003D0000003D2000003D4000C6 +:1037D000003D6000003D8000003DA000003DC000B5 +:1037E000003DE000003E0000003E2000003E4000A2 +:1037F000003E6000003E8000003EA000003EC00091 +:10380000003EE000003F0000003F2000003F40007D +:10381000003F6000003F8000003FA000003FC0006C +:10382000003FE000003FE00100000000000001FF59 +:103830000000020000007FF800007FF80000026F27 +:1038400000001500000000010000000300BEBC20C5 +:103850000000000300BEBC2000000001FFFFFFFFCE +:10386000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68 +:10387000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 +:1038800000000000FFFFFFFF00000000FFFFFFFF40 +:103890000000000300BEBC20FFFFFFFF000000008F +:1038A000FFFFFFFF00000000FFFFFFFF000000031D +:1038B00000BEBC2000002000000040C0000061806D +:1038C000000082400000A3000000C3C00000E480AC +:1038D0000001054000012600000146C0000167808C +:1038E000000188400001A9000001C9C00001EA8070 +:1038F00000020B4000022C0000024CC000026D8050 +:1039000000028E400002AF000002CFC00002F08033 +:103910000003114000033200000352C00003738013 +:10392000000394400003B5000003D5C00003F680F7 +:103930000004174000043800000458C000047980D7 +:1039400000049A400000800000010380000187000D +:1039500000020A8000028E0000031180000395001F +:103960000004188000049C0000051F800005A300CF +:10397000000626800006AA0000072D800007B1007F +:10398000000834800008B80000093B800009BF002F +:10399000000A4280000AC600000B4980000BCD00DF +:1039A000000C5080000CD400000D5780000DDB008F +:1039B00000007FF800007FF800000174000015008F +:1039C0000000190000000000FFFFFFFF40000000A2 +:1039D00040000000400000004000000040000000E7 +:1039E00040000000400000004000000040000000D7 +:1039F00040000000400000004000000040000000C7 +:103A000040000000400000004000000040000000B6 +:103A100040000000400000004000000040000000A6 +:103A20004000000040000000400000004000000096 +:103A30004000000040000000400000004000000086 +:103A400040000000400000004000000000007FF83F +:103A500000007FF80000050900003500FFFFFFFFB0 +:103A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 +:103A7000FFFFFFFFFFFFFFFFFFFFFFFF4000000012 +:103A80004000000040000000400000004000000036 +:103A90004000000040000000400000004000000026 +:103AA0004000000040000000400000004000000016 +:103AB0004000000040000000400000004000000006 +:103AC00040000000400000004000000040000000F6 +:103AD00040000000400000004000000040000000E6 +:103AE00040000000400000004000000040000000D6 +:103AF00040000000400000004000000000001000F6 +:103B000000002080000031000000418000005200D1 +:103B100000006280000073000000838000009400B9 +:103B20000000A4800000B5000000C5800000D600A1 +:103B30000000E6800000F700000107800001180087 +:103B400000012880000139000001498000015A006D +:103B500000016A8000017B0000018B8000019C0055 +:103B60000001AC800001BD000001CD800001DE003D +:103B70000001EE800001FF0000007FF800007FF8E8 +:103B8000000004480000150010000000000028ADEF +:103B9000000000000001000100150005CCCCCCC1E4 +:103BA000FFFFFFFFFFFFFFFF7058103C0000000009 +:103BB0000000000000000001CCCC0201CCCCCCCC39 +:103BC00000000000FFFFFFFF400000004000000079 +:103BD00040000000400000004000000040000000E5 +:103BE00040000000400000004000000040000000D5 +:103BF00040000000400000004000000040000000C5 +:103C000040000000400000004000000040000000B4 +:103C100040000000400000004000000040000000A4 +:103C20004000000040000000400000004000000094 +:103C30004000000040000000400000004000000084 +:103C40004000000040000000000E01B7011600D641 +:103C50000000FFFF000000000000FFFF0000000068 +:103C60000000FFFF000000000000FFFF0000000058 +:103C70000000FFFF000000000000FFFF0000000048 +:103C80000000FFFF000000000000FFFF0000000038 +:103C90000010000000000000007201BB012300F3CF +:103CA0000000FFFF000000000000FFFF0000000018 +:103CB0000000FFFF000000000000FFFF0000000008 +:103CC0000000FFFF000000000000FFFF00000000F8 +:103CD0000000FFFF000000000000FFFF00000000E8 +:103CE0000010000000000000FFFFFFF3318FFFFF16 +:103CF0000C30C30CC30C30C3CF3CF300F3CF3CF308 +:103D00000000CF3CCDCDCDCDFFFFFFF130EFFFFF69 +:103D10000C30C30CC30C30C3CF3CF300F3CF3CF3E7 +:103D20000001CF3CCDCDCDCDFFFFFFF6305FFFFFD3 +:103D30000C30C30CC30C30C3CF3CF300F3CF3CF3C7 +:103D40000002CF3CCDCDCDCDFFFFF4061CBFFFFF61 +:103D50000C30C305C30C30C3CF300014F3CF3CF399 +:103D60000004CF3CCDCDCDCDFFFFFFF2304FFFFFA4 +:103D70000C30C30CC30C30C3CF3CF300F3CF3CF387 +:103D80000008CF3CCDCDCDCDFFFFFFFA302FFFFF98 +:103D90000C30C30CC30C30C3CF3CF300F3CF3CF367 +:103DA0000010CF3CCDCDCDCDFFFFFFF731EFFFFFB2 +:103DB0000C30C30CC30C30C3CF3CF300F3CF3CF347 +:103DC0000020CF3CCDCDCDCDFFFFFFF5302FFFFF45 +:103DD0000C30C30CC30C30C3CF3CF300F3CF3CF327 +:103DE0000040CF3CCDCDCDCDFFFFFFF3310FFFFF26 +:103DF0000C30C30CC30C30C3CF3CF300F3CF3CF307 +:103E00000000CF3CCDCDCDCDFFFFFFF1310FFFFF47 +:103E10000C30C30CC30C30C3CF3CF300F3CF3CF3E6 +:103E20000001CF3CCDCDCDCDFFFFFFF6305FFFFFD2 +:103E30000C30C30CC30C30C3CF3CF300F3CF3CF3C6 +:103E40000002CF3CCDCDCDCDFFFFF4061CBFFFFF60 +:103E50000C30C305C30C30C3CF300014F3CF3CF398 +:103E60000004CF3CCDCDCDCDFFFFFFF2304FFFFFA3 +:103E70000C30C30CC30C30C3CF3CF300F3CF3CF386 +:103E80000008CF3CCDCDCDCDFFFFFFFA302FFFFF97 +:103E90000C30C30CC30C30C3CF3CF300F3CF3CF366 +:103EA0000010CF3CCDCDCDCDFFFFFFF730EFFFFFB2 +:103EB0000C30C30CC30C30C3CF3CF300F3CF3CF346 +:103EC0000020CF3CCDCDCDCDFFFFFFF5304FFFFF24 +:103ED0000C30C30CC30C30C3CF3CF300F3CF3CF326 +:103EE0000040CF3CCDCDCDCDFFFFFFF331EFFFFF45 +:103EF0000C30C30CC30C30C3CF3CF300F3CF3CF306 +:103F00000000CF3CCDCDCDCDFFFFFFF1310FFFFF46 +:103F10000C30C30CC30C30C3CF3CF300F3CF3CF3E5 +:103F20000001CF3CCDCDCDCDFFFFFFF6305FFFFFD1 +:103F30000C30C30CC30C30C3CF3CF300F3CF3CF3C5 +:103F40000002CF3CCDCDCDCDFFFFF4061CBFFFFF5F +:103F50000C30C305C30C30C3CF300014F3CF3CF397 +:103F60000004CF3CCDCDCDCDFFFFFFF2304FFFFFA2 +:103F70000C30C30CC30C30C3CF3CF300F3CF3CF385 +:103F80000008CF3CCDCDCDCDFFFFFFFA302FFFFF96 +:103F90000C30C30CC30C30C3CF3CF300F3CF3CF365 +:103FA0000010CF3CCDCDCDCDFFFFFF97056FFFFFBC +:103FB0000C30C30CC30C30C3CF3CC000F3CF3CF378 +:103FC0000020CF3CCDCDCDCDFFFFFFF5310FFFFF62 +:103FD0000C30C30CC30C30C3CF3CF300F3CF3CF325 +:103FE0000040CF3CCDCDCDCDFFFFFFF3320FFFFF23 +:103FF0000C30C30CC30C30C3CF3CF300F3CF3CF305 +:104000000000CF3CCDCDCDCDFFFFFFF1310FFFFF45 +:104010000C30C30CC30C30C3CF3CF300F3CF3CF3E4 +:104020000001CF3CCDCDCDCDFFFFFFF6305FFFFFD0 +:104030000C30C30CC30C30C3CF3CF300F3CF3CF3C4 +:104040000002CF3CCDCDCDCDFFFFF4061CBFFFFF5E +:104050000C30C305C30C30C3CF300014F3CF3CF396 +:104060000004CF3CCDCDCDCDFFFFFFF2304FFFFFA1 +:104070000C30C30CC30C30C3CF3CF300F3CF3CF384 +:104080000008CF3CCDCDCDCDFFFFFF8A042FFFFF31 +:104090000C30C30CC30C30C3CF3CC000F3CF3CF397 +:1040A0000010CF3CCDCDCDCDFFFFFF9705CFFFFF5B +:1040B0000C30C30CC30C30C3CF3CC000F3CF3CF377 +:1040C0000020CF3CCDCDCDCDFFFFFFF5310FFFFF61 +:1040D0000C30C30CC30C30C3CF3CF300F3CF3CF324 +:1040E0000040CF3CCDCDCDCDFFFFFFF3300FFFFF24 +:1040F0000C30C30CC30C30C3CF3CF300F3CF3CF304 +:104100000000CF3CCDCDCDCDFFFFFFF1300FFFFF45 +:104110000C30C30CC30C30C3CF3CF300F3CF3CF3E3 +:104120000001CF3CCDCDCDCDFFFFFFF6305FFFFFCF +:104130000C30C30CC30C30C3CF3CF300F3CF3CF3C3 +:104140000002CF3CCDCDCDCDFFFFF4061CBFFFFF5D +:104150000C30C305C30C30C3CF300014F3CF3CF395 +:104160000004CF3CCDCDCDCDFFFFFFF2304FFFFFA0 +:104170000C30C30CC30C30C3CF3CF300F3CF3CF383 +:104180000008CF3CCDCDCDCDFFFFFFFA302FFFFF94 +:104190000C30C30CC30C30C3CF3CF300F3CF3CF363 +:1041A0000010CF3CCDCDCDCDFFFFFF97040FFFFF1B +:1041B0000C30C30CC30C30C3CF3CC000F3CF3CF376 +:1041C0000020CF3CCDCDCDCDFFFFFFF5300FFFFF61 +:1041D0000C30C30CC30C30C3CF3CF300F3CF3CF323 +:1041E0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF57 +:1041F0000C30C30CC30C30C3CF3CF3CCF3CF3CF337 +:104200000000CF3CCDCDCDCDFFFFFFFF30CFFFFF76 +:104210000C30C30CC30C30C3CF3CF3CCF3CF3CF316 +:104220000001CF3CCDCDCDCDFFFFFFFF30CFFFFF55 +:104230000C30C30CC30C30C3CF3CF3CCF3CF3CF3F6 +:104240000002CF3CCDCDCDCDFFFFFFFF30CFFFFF34 +:104250000C30C30CC30C30C3CF3CF3CCF3CF3CF3D6 +:104260000004CF3CCDCDCDCDFFFFFFFF30CFFFFF12 +:104270000C30C30CC30C30C3CF3CF3CCF3CF3CF3B6 +:104280000008CF3CCDCDCDCDFFFFFFFF30CFFFFFEE +:104290000C30C30CC30C30C3CF3CF3CCF3CF3CF396 +:1042A0000010CF3CCDCDCDCDFFFFFFFF30CFFFFFC6 +:1042B0000C30C30CC30C30C3CF3CF3CCF3CF3CF376 +:1042C0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF96 +:1042D0000C30C30CC30C30C3CF3CF3CCF3CF3CF356 +:1042E0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF56 +:1042F0000C30C30CC30C30C3CF3CF3CCF3CF3CF336 +:104300000000CF3CCDCDCDCDFFFFFFFF30CFFFFF75 +:104310000C30C30CC30C30C3CF3CF3CCF3CF3CF315 +:104320000001CF3CCDCDCDCDFFFFFFFF30CFFFFF54 +:104330000C30C30CC30C30C3CF3CF3CCF3CF3CF3F5 +:104340000002CF3CCDCDCDCDFFFFFFFF30CFFFFF33 +:104350000C30C30CC30C30C3CF3CF3CCF3CF3CF3D5 +:104360000004CF3CCDCDCDCDFFFFFFFF30CFFFFF11 +:104370000C30C30CC30C30C3CF3CF3CCF3CF3CF3B5 +:104380000008CF3CCDCDCDCDFFFFFFFF30CFFFFFED +:104390000C30C30CC30C30C3CF3CF3CCF3CF3CF395 +:1043A0000010CF3CCDCDCDCDFFFFFFFF30CFFFFFC5 +:1043B0000C30C30CC30C30C3CF3CF3CCF3CF3CF375 +:1043C0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF95 +:1043D0000C30C30CC30C30C3CF3CF3CCF3CF3CF355 +:1043E0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF55 +:1043F0000C30C30CC30C30C3CF3CF3CCF3CF3CF335 +:104400000000CF3CCDCDCDCDFFFFFFFF30CFFFFF74 +:104410000C30C30CC30C30C3CF3CF3CCF3CF3CF314 +:104420000001CF3CCDCDCDCDFFFFFFFF30CFFFFF53 +:104430000C30C30CC30C30C3CF3CF3CCF3CF3CF3F4 +:104440000002CF3CCDCDCDCDFFFFFFFF30CFFFFF32 +:104450000C30C30CC30C30C3CF3CF3CCF3CF3CF3D4 +:104460000004CF3CCDCDCDCDFFFFFFFF30CFFFFF10 +:104470000C30C30CC30C30C3CF3CF3CCF3CF3CF3B4 +:104480000008CF3CCDCDCDCDFFFFFFFF30CFFFFFEC +:104490000C30C30CC30C30C3CF3CF3CCF3CF3CF394 +:1044A0000010CF3CCDCDCDCDFFFFFFFF30CFFFFFC4 +:1044B0000C30C30CC30C30C3CF3CF3CCF3CF3CF374 +:1044C0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF94 +:1044D0000C30C30CC30C30C3CF3CF3CCF3CF3CF354 +:1044E0000040CF3CCDCDCDCD000C0000000700C07A +:1044F00000028130000B81580002021000010230DE +:10450000000F024000010330000800000008008096 +:1045100000028100000B8128000201E0000102007E +:104520000007021000020280000F0000000800F0E7 +:1045300000028170000B819800020250000102709D +:10454000000B828000080338001000000008010002 +:1045500000028180000B81A80002026000018280BD +:10456000000E82980008038000028000000B802863 +:10457000000200E0000101000000811000000118AD +:10458000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC6B +:1045900000002000CCCCCCCCCCCCCCCCCCCCCCCC6B +:1045A000CCCCCCCC00002000CCCCCCCCCCCCCCCC5B +:1045B000CCCCCCCCCCCCCCCC00002000000000007B +:1045C0001F8B080000000000000BFB51CFC0F00360 +:1045D0008A7BD81818367020F843015F646260B88F +:1045E0000CC45781588099812198918121849178B8 +:1045F000FD49A208F62B210606316106866841A016 +:10460000B9C208F1A3403556220C0C7FA1628D403F +:10461000369B2875DC3FD0789314A6D87A09047BA2 +:1046200033167964BC054D9E4F1295BF9580FE816F +:10463000C68F1551F9620A103A1F2AFE044D5E1CFE +:104640002A7F19EAAFA78AD8CDBD02950700C8E92D +:10465000674460030000000000000000000000004C +:104660001F8B080000000000000BED7D0B7854D577 +:10467000B5F03E73CE9C9949662627214F1E6112E4 +:1046800020828638BC0228BD4E0844AC5C0DF8423E +:104690008B3ABC43DE50B4B4B55F2610224F6FF0A6 +:1046A00047452FD8E161458B3660A4D1021D4010EB +:1046B0007BBDB7C1528BD5FA4554500C24728BD2B6 +:1046C0005B7BFDD75A7BEFCC39930960FFF6FEF791 +:1046D000BFDF1F3FBFC33E673FD65EAFBDD6DA6BBD +:1046E000EFB1B334A60F64EC6BFCBB81B11A1B6352 +:1046F000F0AAFBF9949DDD5FEA662C6FA36FB93BCE +:1047000015DEB7E6EC4AF43196B577BD3211DE67B7 +:104710006D6A5266E747DB8F76C1C731F0BE75BD63 +:104720005204EFB3DE6C5266E1D361636D509F6952 +:10473000BE24864F16602C9DB141E398F80BB8B3A8 +:104740000A19EB8FFF842ECE1B89D01963392B6C8D +:10475000E19002EF8365539997B16D0057560AB403 +:1047600053BF3A60C7BAB5DAC97627634ECDA97D83 +:104770009DCB58F60C6663F01CB894BFC7BFAFE181 +:10478000FF9C90B53C8899CA3958F6A49E8221991D +:104790008779BE56E3C1DBA5970E8FCE533E37D542 +:1047A000F9D2DD5ACFF7F2B978D127FAC3D0FA6936 +:1047B000AC3798B1704CFDAA90AEB16BE1090868B6 +:1047C000CEEFD97E2A2B2A443ADCC726D2B346F351 +:1047D000DD8578A9396A672180BBA6F65409965908 +:1047E000ABC286E4F46C3F9CD9891E454CD14EE1A6 +:1047F0007CBDCC8BF3532B7D4F94009EE726062681 +:1048000061BFEB1283F494EF33674FC90C023CC5D0 +:104810000BF2430CE87E7EA3E27740F3D34A58B70D +:10482000033D2A6EAF2DB811EAFD560FDE8CED2A3E +:1048300067B41D217AB0DA3CC4539BCEF967606B34 +:10484000D1A71AD00D582C9494827461ECA4890ECF +:10485000F87772A828ABBDE3F172CFB9D88F86BDC7 +:104860008469BEF27D4EE8E8A0C131E3B14282879F +:1048700031E471D6AEC4A3EBC0578A8E6A05BD8FF2 +:10488000F7F79F4788CB21E00EE95BE5D1C3CB80EA +:10489000BEC52FDB2337003DAAB6286107946DFB08 +:1048A0005D01A4CFB9ED5006BA443C3AD53F6B3810 +:1048B000A95CE3687BE47A2877BDACB2ADD8EDD0D3 +:1048C000041BCADD29013B1B0D65C0C77C172F5691 +:1048D0006D39701FF657D6EA602EE8BFEA9505B726 +:1048E0005C0FE505C06F58A5EA997ABD2F9417862D +:1048F00095662C774E64C41FA1143DFC0C8CD7E93F +:104900006D4BBF03E4E54C9D93F90094E59EB6F42E +:10491000DB818FCAC3BB4AB05DF94EC58F682F7E5D +:10492000F999235938AFE780AF808F2A7624329FD8 +:10493000C41FFC7F0AA672037C5F0CF344F95FC0BE +:104940009A4A988AE3AFD77D9E28BECED419344EBA +:10495000B73C3D07E340BBEA17153F4EB1DAC682CC +:104960002857E75E71CDD8E6C6F9D5EB791E9CD7FE +:10497000C33AD65B109EB507555679788B5E02DF39 +:10498000CB376DD1E7E723DE40EFE5235C7DAC70EC +:104990006D540388DFC5C9CEAD2AE087B90399D32A +:1049A000E3F0CF993A506379D17239CA37E993B0BD +:1049B0003ECD54BF4449267EADD8A1329F859F3855 +:1049C000FD43C738FD43FB3CE16772A2F45B6C70AA +:1049D0003D29E9B73859D053EB2A8C07CF23480F2C +:1049E00080A709F105CFB5023EEF0456A4015DBCD6 +:1049F000016628ECF2FCD96467B3188CFD169B178E +:104A0000D0C64359678B989F3143AB0A4C82F2570B +:104A1000ACF44D9C0F637E5F29E0B951613370DEC9 +:104A2000871158984F63964EF86B9A5CB84D5504B1 +:104A3000CCA9589EFF93D539D4FE38B5D7A0FDF048 +:104A4000DEDB1B25E32CED8D9232D9FE3DACC79CFD +:104A5000976EDF54729D75FC9272D9FE231ADF7D2A +:104A600069F88D1B2758C7BFB192DAD73838BDBA5D +:104A7000929DE1AD506E70F9031AD24D63117CAF77 +:104A8000A5E46DC57AAAE407D61650A1BD7B67F2EE +:104A9000C8D5CCCC1713FF88E379405ACC7C91342D +:104AA0002EC1C28FC981144B197A324E5D13D54382 +:104AB00001AF93E0D1FBEAA42F8AFA3A09DE07F7A7 +:104AC000BBA8FCE0751CDE07FBBA49CE10069605B4 +:104AD000653D78AD615A8F004E856532764109BAE1 +:104AE0009431E6F73E1BBE4F50592DCE27C1C14829 +:104AF0001F3D9C53B82D64C2CFCA01405F28A72A2E +:104B00003AC7A3C0EBC303E667CE328DD338409FCC +:104B1000B1359FBF9FE3C6F14AD315D4837A579E20 +:104B2000E1EE398E23779C651C6776198D931333DC +:104B30008E23BB2C661CE78CADE2BD1867D0A5C6E2 +:104B40007938F73AEB7CB2CB699C82D8F96497C785 +:104B50008C93C0E703EFC5387EC45FAFF31934C14F +:104B60003A9F819534CEF538CE18D37C0656C68C44 +:104B7000E3A671F03D8E0386948F6500DD1D5DF325 +:104B800089FEBF7491BDA03B82CF62BFEC5D17234D +:104B90007DE283713350AFC0E20CF2AB292934CEF1 +:104BA0001709407FB799CE5C1FD113F4CF3C012287 +:104BB0000B0344A07FAA058FCEDD392DBB1E9FAD10 +:104BC000C599B3D02ED9E0F10F01D139D75AACCF66 +:104BD0008963DFCC6BB29F6AB7F0AFD07B13D9D0BB +:104BE0005A18BF05958DA97C0AF41703BD7512F4F8 +:104BF000173E4F0BFBF423D06F4C37C35B4FF3389A +:104C0000A5713C9EDAC4D7912FD61FB383B187C359 +:104C10001CCF07B8EF14D398D704C69F49CE6A04B7 +:104C20003DBA5E7184B7123D02FD6CC0E76C631F34 +:104C3000C095A80776E61F843D0A7FFD6C60CBDE39 +:104C4000B372D761ACF6B6326BC06298EF8C96F552 +:104C5000F67E503E676FBFCFEF36F533C37E12E767 +:104C6000ED84FFB09FBB83768B7DFA9D326BF9DEBE +:104C7000187BB552C915F410E3FAC276A4D79DE9A2 +:104C80001C9E7BF139123F1B44AFFB0CDE56C25316 +:104C9000F3433B8BD07AD49EC6F2111F696417058B +:104CA000E5BA1203DF7D7667A014E879DFF755C215 +:104CB000632CBCEDFB130336B097DA37FEBB1DED5A +:104CC000EFCBC17FFF52EB7716E2E349BC4A3EB817 +:104CD0006B46519F8F4CF5EE0EDED4E72313BF7C5D +:104CE000A76C9AA57C6FEDDD96FAF72F9D65F93ECE +:104CF0002BB4D0F27DCECA4596F2BCA6EF5BEA2F6C +:104D0000D8586FF9BE30BCCAF2BD62C77A4BB9AA97 +:104D1000F9494BFD9AD62D96EFB6FDC36E45795CE9 +:104D2000FE5B95A17D76C17DEA11B4AF2E189A1F66 +:104D3000EB5423AF811C7E529749FC7DA6CE47CF12 +:104D400073ADA39C688FD724803CC35ABF5FF943DF +:104D500068E504D423501F74F841E5C350089CA7AC +:104D600037141FF1BDBA516711605585A574F375ED +:104D7000971AFDAEB5C3F751BD7F57376A71BF6B48 +:104D8000ED5ADC7E3B95AE3CB4EF42EF3818DA8149 +:104D9000BDD90FF0D70FD78BDEBE77D85859B3499E +:104DA000EF9C526CC407772A134FA17EAED4B9BCD6 +:104DB00057EECE9A88FE60A51EC9AB755F62BC66D1 +:104DC000002603FBC9A5792D0CF78BCA2FD16F9054 +:104DD00045EE97B0E0C7A89F3B0EA8A46759E450E2 +:104DE000F66DC371FCC0297CCF5AD3687D7CBB2E85 +:104DF000D0E723F0E74ED44DA1E7EFEB4AFB7C046C +:104E0000BAE6BDBA19547EBF2E48CFF6BA327A9EA2 +:104E1000ACABA5EF1FD52DA5F2A9BA103D3FA95BFC +:104E200049CF33754DF4BDA36E2395CFD585E9D910 +:104E3000ED07087B94A50AFB4FD8EBB07250F9BC84 +:104E400098830AFFE67EAB3F13E5FABCFB8B3CB4CC +:104E500073CF9F00C3248E7F289FB1FCD63BFD02F9 +:104E6000B4DECF0F03FD47F5FCEE4AE0F471D9D86C +:104E70001406FA67D5109D69307EC22FAF217B19C9 +:104E8000DE6B8CF465D83FCD13A77F9C73C6E5E934 +:104E9000D4CD1F4FFDB910E30F770A7D987048AD50 +:104EA000E574DBE647BA99F0C7EDB297853E8FC14E +:104EB00023D972593DF179364DE2B32D1BE3001B26 +:104EC00094D26136E083F32D0E9AD7F9BD896186BD +:104ED0006D313832FE5278E37054EC701966FD5033 +:104EE000D59C6C58F5459661D617E78F6EF3A2DC1A +:104EF0002FCEB4191F8D42FE0808FEE07C27FBAFC1 +:104F00006ACE31DC967EACE5F34DCA14F48340B929 +:104F100027DD1EC73F90CFC599BAF111C8F7991D7B +:104F20008392705CF0E30C1CA7A3CE30F8B899868E +:104F3000992F2B9726507D095F6FFDFEADE143CB86 +:104F4000E0432723D47F3DE89BFBD94CFB23C5736B +:104F5000D85EFB17B8EE38E0FFAF291EA05159F616 +:104F60005BD3AC861CD7E2FB9D96F1A09D4FFAD097 +:104F7000B85EF54E778D9D32C505AA710CF28F9CF7 +:104F800044E720F49804FD756AEE950A8C33C5E673 +:104F9000A3EF35821FAB9CED7A105E9D6DE1F4E8C6 +:104FA0006D9C3375477D1AE88F32277864304E59EF +:104FB000F3B049A81FCFB62C4F0F02DF56A8E71F4A +:104FC0002C8DD37EA54DE1F084ED5DEDA6F9C838BA +:104FD0000A63D0AF330A3F72FA295339565FCBE7E1 +:104FE000A3D82FF047F5CE6325D703FCD5AD9FEBB3 +:104FF00008C7145BF0515B5A74FE0ACE1FFA29DF12 +:10500000F1818EF3FBC41ECAFBE125F4544F38DD59 +:105010009914B793F085581BDA31B3BBE38ABEBB52 +:10502000DE05D1FCF45FEC6C35C0C1BE825AF0DD08 +:105030002EBECE65A55EC4D7EC960A8A2F7E6A93F3 +:1050400076535321F2C759669B82F33BCBDEF28E37 +:1050500032E1AFC5C6ED7EB692DB3121F80FE1013A +:105060007BD662D72CD8682DCF67D3D3516FCCDFD6 +:1050700060676140D142B48B247FC0BCB7DBB8BD50 +:10508000BB80D536A23DA739B87F30DB605A3F8060 +:10509000ABEAE79B0BD1EEFF85CD46F49171868597 +:1050A000291CEEF2D4B01E80EF1FB68CBAF37AE45E +:1050B0003E47B811D76596C4FCCFB09EF89CB3D2DA +:1050C0000ADFE5E08F8597B165163864BF120E756B +:1050D000871208C7E1BB3724DF093D92A25AEDFCD5 +:1050E0008C98F27B3611BF54998A743E6B3843B664 +:1050F00024FAEE8F607C64B7C3BF1CE8FB80ADB4BC +:105100001DF533D80505CC54EF015B90DE77286F91 +:10511000CE47FB94699102F4EF614DD1901F74C1A9 +:105120000F6A82B700E3B11E06EB27C8A503E1832F +:105130007E1A3D65535901C65F414EA1BF75DE928F +:10514000A30A945DEE1686FD3932ADF16597CF5A0C +:10515000AEC17F201D86328AE3240EB57E87058B83 +:1051600021BF79FCD6F7FFD18DA708F1AD97581A6A +:105170009E4E774485F1D938ADC36C37573B39FC27 +:10518000E49743FD25C29EAF66BE10C58933391F23 +:105190002CB9C946F02CF1F8FC21F8AE680186F272 +:1051A00087B16AF33A56731144AE8FA9AC75E9C85A +:1051B0009735173516067D5F600B7AD43188BF00AE +:1051C000D9B94E40D6D700B2E69E62B17B59FF14E2 +:1051D000B1BEF637CCF2DA1FE93C264A67A917ECD4 +:1051E000422F82BEC850D3500F7695905FC2DA49E5 +:1051F0004FC87A7AB45E7F84A3B77AAE68BD9C78D4 +:10520000FD55FDFC853D21C07FF9CF1EF302F1D98C +:10521000A75A53BA1FDE573EB3C28B7CFC8916F2E5 +:10522000E2BC3F0DAB53E2F1F39DAA22FCB1805BDF +:10523000417F58D0E9CCF36B6E41BC7FF18CDDC06F +:105240002A353B1C110710B1BA6521E7A71D8E0F47 +:1052500078F9E1CF919E35AD56792B7FF6B1748CFC +:10526000770286B8DFC822643F576FFFB804ED911C +:105270001AD6457A22B61D8E7F3185D6AF597A521D +:10528000CFEF72FFA546F07D4DCB9ACF552F96AD4F +:10529000F25D26FC911B554F2AC595C6B2B1483721 +:1052A000890716E6F6F0F2E79E28F800E0E8D8FE57 +:1052B0002F5EC51237E2FAE17CF39C1FBFEAEB5D7B +:1052C000AF9F13FE7CB45D98DAF95AB9FDCEF6F2C1 +:1052D00067A53DE2457FA9728BDD0F92C92A5FD891 +:1052E000F693A790AFDF71509CA1E285C36F5F0773 +:1052F000E58A5DF6D4A97C1A6E253D4A8F1AF87F9F +:10530000E9C828FECB5F3AACFB86F3F70FA544E96A +:1053100050B1EB80CE86F7C45B71F301BDDD1D8714 +:105320001ECD1F94A0BDBDFCB92F7594AB4FF72BBC +:105330002C23A767FBB22D87C99E433C11FD047D3A +:10534000BAE9D5834E915B5E1D4DF50C5CBF7AA327 +:10535000D3D5B8F6A5111FBFF82AC6EF7FEFF0E34B +:10536000FCCB5EFCAE17E7715AABE5FCBC79457A25 +:1053700000C62DB387D20D7AF2F7654F3F407CB659 +:10538000E0D803E9140F60812C1BADA1A12C9CDF98 +:10539000BC4D77D0FCE6B320F15BD966B5348CF117 +:1053A0002C8D4DD915471EDE14F2707AAB03D71E33 +:1053B000761A152CFA876FA9B44FC0D8228A373CC9 +:1053C00020F721D8622A5F70723A6D536D32BEE1C8 +:1053D000B4F0E9F687DB903E67060432303E097888 +:1053E00008097C29A877D4639333387D984F2B1410 +:1053F000ED402F16E37BACDF660FB80A2CEDC43A04 +:10540000C6C75F22C607B813D01E3B9D0EF64D9C43 +:10541000F97DA94ABD0CF68689BF4C72CDE57CFBAF +:105420002A2ED752CEC3D3A6E0F73F1EE7F283ED74 +:10543000705D07B82219F4FDC0ED0AE901078BC4BD +:1054400093E7ED7621CFD6EF727F12E0D6707D8A9A +:10545000F209F49F42F8273B6DFE066867D2CB3510 +:10546000381ED5D3A3EF4DEBFA0221FFAFAB627F1D +:1054700054C83FDBC4E5BE77BB37C4FD037BF827C8 +:105480004FA1BC827CE23A53F982BD14E7FDD9CE2C +:10549000436FDF037CFD59B39453ABDE8C95D3B2DD +:1054A000DD63583C39FDCCED6771E514DEC79553DB +:1054B000773BF1F1DF5B6F4ABC9D8BD19B520FF6BE +:1054C00086BF583DB856F5C5D583F0779C15F6E4F0 +:1054D0003BC96F92CFCA7F5A3590E246921F25BFD3 +:1054E00075F3A3E4B7D8795AF116FBFD15A16F2423 +:1054F0009DEDCB58C883F1D27D2AF9D79D00532367 +:10550000D0B773674E18E3CE2B5C3C7ED1697479BB +:1055100053E0B9229997BBD2F446D40FF27D978B12 +:10552000C7B73B4BBBBCC926BFE283BDAAD707DFC9 +:10553000DBC36C4A3C7F03342FC1D1CE7AFBCEE370 +:10554000C1935577F652F4DB9B54DACF9E5B7F977D +:1055500017F7813BF70EFA27D44FF3DE000313E071 +:10556000ED443B3009A717D0302F618EA0F7272CD0 +:10557000F4F80498DF9CBDDC5F98BB36C6BE772F7D +:10558000D151DF807D7FD21AD7E67C532EFA29DBFA +:1055900064FD5ECED612DDCA63F82828FCC0B19A3D +:1055A000E0A3116C84F0C378FC42E8ABC96AFE3F0B +:1055B000A19DD17994C715CFEF5509FFE7772A61EF +:1055C0008CFB507C773CD2BF4B67267FB903F94DEB +:1055D000EF5D8E3B5EFE43E10FA14AE59E770BFE39 +:1055E000199E1D7BDEC9FB05967FFEBBEC7759CF6C +:1055F000FAC5FBFF44FBC79DFB1D0447E7FED7B37D +:105600007F88E5571D7E84B3739983F6CF42FB3DB7 +:10561000E121F87D00D01BD7CD7D5F16B4D3BAD37E +:1056200040749AADF1FD8EF37BFFFCBE82F9077BDF +:105630001D3E9C47CD7E9E1752F3AA8BE22E9DFB0A +:10564000BE2C0CBAFF76F3A9D65990F8CFC366ECFE +:10565000467E4DE6FB0035BF18BFAD1EF7C35B0E9F +:10566000E8B8BF52FCCBBF14A07EE9DCCDED84735B +:10567000F6F6A7711FB44A1BBCCC8E728F365B5FE7 +:10568000B03BEDF32686F2E3E185E3A113F080F36E +:1056900002BC94A15EEC0D1F0D1AF737FFFBE1E38E +:1056A000F3FB70FCCABD63496EA2785102FCBD27B2 +:1056B000EC5468FEFCFDFE2F0BD0EEF9ACB99ED683 +:1056C000F1CBCD7BDBFFB8792B912B99F7C1FFE6AE +:1056D000FC3F45E3EB52AC1CF4E4F39F3F48E51775 +:1056E0003D7E82F70AE5FFE4FF34BAEF06BA7B2F6E +:1056F0004F77C5FEDF75DE97A3FB1B82EE1E03F31B +:105700000A3AF7FD85E2E572FE979BB7EFFFD17984 +:105710004BFB67B5CDDF940BF5D7B2489B0FE05C30 +:1057200031747A138699C04D288D678F94DAB97FCA +:10573000A42A3C0EC306F0B81013FE04A580F9306D +:105740008E329FEC3ACDDD487626D3FC6D01C0C782 +:10575000EAAB67FB2957838D3C11C472FF097E8A2F +:105760006FC6F8550D0A0B2860EF69577FFB28DAE2 +:10577000F9F6A1B688A3809E1FE0F36111C7B21BA2 +:10578000BAC59F70C7F8032E9FF5BB43F4E76423A7 +:105790009B72314FC1AD196118DF5DD444F3710FB5 +:1057A00061ACC9B40FE860A6F6D05F3E06604DF666 +:1057B000E337C55F7D37FE46B605107FC36C14D74F +:1057C000A2A43EC2873FBC9AFC4CEE3F46F1D9D81A +:1057D0008678D418F87F7C7EE43732E12F6AA20BFA +:1057E0006DA82DE0B2D6137ED165E9C3E9915D299C +:1057F000E8B3D8420F89FF3874B1D043E2F79BD2A7 +:1058000025961EB178BFDDCEE36DB174B2E477A406 +:10581000713F24027EC8EB3BB751BCE3ECF31FDCC5 +:1058200082F52B7EA13227F4736EA78745507EB593 +:10583000B08EFE54798B1A37CE2BEDF28A9F7968A1 +:10584000BCF2DD8EF054685FBEE7C302B29B967572 +:105850001DE9877181E7154EBF507B01EEDB956B2B +:10586000DC3F88ED6F939DC7053A5E499C81F10747 +:105870006507CF572C6FBECBEE30F1DBFFB2F3BC28 +:1058800057A847F21C7A4EA1F5A6277CDC2FE878B2 +:105890004EE1F0B5DAC398F758BE638B1E44BF7271 +:1058A000C7E714C72EFED90BDE76F21755ABFFBC47 +:1058B00043257AC293E817EBC756B754919F50DD42 +:1058C0002CFCC4183FAAE267FBF6840035152F3D77 +:1058D000EBC5F8CB99B667BCE49FEEE0FEA7E6D631 +:1058E000E2FBA797F34B9B57C5F54BCFE03FC09F1B +:1058F00038608FF1E777F4B9B2FDCB172E3C8D718C +:10590000D28EDD9F3D8D7057FEE7BF3F8DF63DDBAC +:10591000EF329E81F9D63CFF5B8A37C976EF0A39B0 +:105920003D378085B2A0DEB9771C943F726EDFE907 +:105930006CF4E7CEEDFA533AFAF54BF64DCEC0795A +:105940002F79B93883C59177F944BE0C5F419C30FB +:10595000960E875A0E911F72F68483FCBEEEF842B3 +:1059600073158FD7F8445C6167FC38ACF487AB5B88 +:105970003E2CE1F131E1175F2E8E701CE878ED15B9 +:10598000D06BA78813C5D0EB2CFE03E8F2650CBDE5 +:105990002EB0E08FB3701FB2A54FAF7184C815E071 +:1059A00049C6778FD803361DE5607762379DA622FA +:1059B0009D5EB8908DF1F04FEC5D64F774ED731857 +:1059C000E8DF97EFFB1DC9C5B9978F51FC94893863 +:1059D000EB39D6FDC7E3628A98DF760F8F3F087CEC +:1059E000637CC2E7A5F7220EC1F955C6277A8B4B17 +:1059F0008CD545DE93883B576D7F576731711E65A7 +:105A00001CD2E9034B7C5CCE3BB63F03F130D61C85 +:105A10005F8B1FF7917E73944E3CAE26E367E7B62B +:105A200088B81BBCEF3F12FD411EC7A8092BBF63FE +:105A300071E450C6D746EA317218BEB2B8DAE5E072 +:105A4000FD6BF13144E7EB83C44BC757F1F5F03FF1 +:105A5000EA5CAEA7D8825375D37EF6FD629F45E21D +:105A60004BC2DB21F2F03A9E57291ED4D87C88F431 +:105A700069AC3C57F7720EE23E9DC75BAB5B0F14FF +:105A8000A0DEE938F80AF15DF5CE0FF410F4736486 +:105A9000C74B3AB727399FA39E0E9BF474C78B0759 +:105AA0000A78DC8FE7DDC6F65F21FAAFD96BEDBF70 +:105AB00066E7E796FE2B42CDB4FF75B971CE6881DB +:105AC000BB70BE67DAEC0CF5DD9966754A389E1D31 +:105AD000A8DB2DFBA08DC7745AAF46BF9540F9B91E +:105AE0004B8E4D793709F7E940CCD0FE6DA9E77CA4 +:105AF000D5F2A3403FA44BCBB17B545C37F6201EBC +:105B00004D7670E1F1DA620FC86BE17BA5A391AD30 +:105B100062F5C0D813360BDC304E06EAE306E80720 +:105B2000F3E9317F08F747556FC9148447356C8610 +:105B30002BEEFAC9FBB3BB4B19DAE576C39AAF9CDF +:105B4000395DC4D122D6BCF54C9D0DC57D70664B28 +:105B5000F0E37EC0E26181118731AF7E5E26C589A8 +:105B6000B36EE3EDCE1AEE90EDDAE8BE6DE245E8F5 +:105B70001FF3606CE1F533A15DA2D6ACE03E003CC2 +:105B800019D2E5015B70AB9E86F574E603D5F8B4D7 +:105B9000AE68947F21CEBDC8FE64BDDEF683E539D4 +:105BA0002455C03F48EC070F60ED0AEE076FF2F096 +:105BB000F34803DDA974DE689BB0DB7CB8EF8AF59F +:105BC0006AADEBF665CF23ADB496538B8B160DF40F +:105BD00033F661E383C51AE883D4BB8A76F5337064 +:105BE0005F7A4331E6DDA73E5B34220BCA77398604 +:105BF0004FA2EFBF2E1A910DE55AE7B849F4BD4206 +:105C0000A1BCC07D7A6771283F2A9F6960DC62BEB3 +:105C100005C8ED4194DBB3A51D8DF8B5EA8E2F7450 +:105C20007E1E8695E2FC078CE3F3EFEF7E6F17CEC6 +:105C300077A0ADBD1EF9EFC7FBBE4CC67A3E66D05D +:105C40003C0DD660E0BE3CBC1AF7F525F27F62F34E +:105C50006024BF6F4B0CFE06E158357BE81325A886 +:105C6000532BFDC447B1FBC4CC4825BACC157441B5 +:105C7000389DA63CE4056A88F25EF04402E5F5B082 +:105C800049068EA7842AD5AFAFF9E6709DD645BEEA +:105C900081380F663A2F7506E15D9718A467EC7995 +:105CA000A9837A6907BECF9A7F311BE721CF4115BF +:105CB0002F70537CE0FC5E1676C49123F9DC5AC742 +:105CC000D2B4C1BD7FFF8D23F81FD87FEE2F7DBBDF +:105CD0008F427FD7CED5FD98C276EDD2D169DA2832 +:105CE000C627847685A05F26D214E5EC41C6CFE7AF +:105CF000389400FA8F9DDF35480FF79F3B95FC8C59 +:105D0000CEC49C66CCA3E8FC21CF0780955E417988 +:105D100018B03729827E10F0F31731FCFC8575BD71 +:105D2000B18EDBF9B5AFB59DFA33447F60F0A4A323 +:105D3000FCF0BF4E95DBDB9D753E8203CCC303B800 +:105D4000AE5EE978590E110F17F401BCF77398F0A5 +:105D50003ED0D12BFD721D9C7EF48CA5DF7C676D3F +:105D600036CA7379697309BAA8BFD5835761BDD3A1 +:105D7000F38F34DAA15ED5CCDA3C64F69E74E5E7A5 +:105D8000B1D2F7CEAAB763BC02E9E2EB49BF6B9789 +:105D9000FAD3B43E167A8E72403FD7EEFDDC8670A1 +:105DA0004B3A3E21F2FC63DBFF834311E356D6DB23 +:105DB000314ED2AA933D1B5B6F0A1EAA1A132D17F0 +:105DC000380B69DC0C1B8F77F4ACCFD7BF68BF4EA4 +:105DD0003A97D51B1F1618BC3FC0FBB7117E89F739 +:105DE0005B1C42DFF6C4FB34AC0778A7E715E0FD87 +:105DF000CE4BE15DDACF15421F54E0FE09F0CDC76E +:105E000081E9E98361DC12D54D7CBFF01995E40D81 +:105E1000EA4FCD4A8FEA8F85E36B0FE03C176E5651 +:105E2000883FE78AF3A59F897CFED83CA8F93342D6 +:105E3000B4AFD3231F2A1CE3CFC5E4B95747F97485 +:105E400020CF4FE3E7B5542107C50BF293D00EDA0C +:105E50006FF7FD9AECEB3754B6350EDE89B9D2A256 +:105E6000E501B5364B7E2C9B9B6CE977D2827CDAC0 +:105E7000EF5EECF15DD29F1AB8D4BA5EE784ACE76E +:105E80008B06ADB49E2F1AD2D4D752FFAA8DB996E5 +:105E9000EFC3C2575BBE5FB363A4A53CBCF93A4BEA +:105EA000FD6B5B275ACA2322DFB6D41F7574BAA5CF +:105EB0003CA6ED1E4BFDB127665BBE8F6F2FB77CF6 +:105EC000BFFE93C596F2B7BA7E60B54F6C8CF421D5 +:105ED0004B50483FBE56372E1BF3B0D9686512E2CF +:105EE000B358E411BEB648B7195E7CE6D90CD0535E +:105EF00007E74DA5F5FEB545E9011F3D0B03E8CFCA +:105F00003075C2E878799A938DF1D9E67CA862A7BA +:105F1000DDA2CF261BD6F2CB926F0672BE79354634 +:105F20009FD96B2744C022647D170ECEC0F140BEBE +:105F3000F609BDB6EF0AF5DA4194C3D3E991462CD0 +:105F40004BF962625D2D127C04CF808EF990933CF8 +:105F5000B4FE06F0A58FDE87349093894E7FFFC391 +:105F6000381F9B3F15996FD28CD2D7786EA5587F7A +:105F7000D950DB37597FA57C67DA44BE5A0ACF5720 +:105F80007B725E5E1233E1F55D874DD8CD4DFC69C5 +:105F90001C7575E7A9E69ADF7F92A099F2E3940554 +:105FA00053293F24B3173DA867E6DEB41DF4AF9E26 +:105FB000E5A3A77CDF38C31637EFEB9CD09BD2BE9E +:105FC0001A16B5AFCE211DCE66BEF538E62555CFE3 +:105FD000EC22FB2AD3D6B4E808CEEB57AA8857FAAE +:105FE000F8792A6117CFBBE9D14547701FFA5F875F +:105FF000905E92E36CAA9B7293663A37DEBF173FBE +:10600000699893AF0F4FD70DBD692EE5691BFC7CD6 +:10601000A8E83F3B54558276F240915FFAB82D7E56 +:106020007E4B8293CF2B03498EF01A6E928FB3F37F +:10603000DFF36A308FA76CC10427EED35EDB56C84E +:10604000FDBC801FCF9D6647EE7D1CEB67676A94A1 +:10605000DF1A3B7EC6CCE0CA1C985F438ACDEFA610 +:10606000729782F51D0F31D607EA37FCA74AF03444 +:106070001C1C4FF91E0E772D43FB55CEEB50CA5317 +:10608000841FB52591D63D26F6C1657CF542E6DC38 +:1060900036B42B2E6CB0D37817608E06F47FA145F2 +:1060A000A57DD6232909111B94D5951E52A9D9681F +:1060B0006B42FDF92D9EB02F278A176DE3043AFF3E +:1060C000E2E8CFE7DF90E20EBB7368DE29386F09A4 +:1060D000A79CF7805EFCCA1B041EB3AEEA3E97C1C4 +:1060E000908F5543A37EE725F37397E1BA71825EE3 +:1060F000D6F934664EBFF56E3C2F745C65980AE2A3 +:106100006B6FA2F9CF87F9637C3716BF677D395F64 +:10611000D85482F3068453DD5842F3A07AD0AEEA15 +:10612000C70A7B2A07F9303885E8DAD746E70063E3 +:10613000E12E71F238EB8D4E1E0FD033F36EDADEA6 +:10614000079F83492E6E76F6BACEDFE2E47A889E08 +:10615000577E9F40C4B2CEAB011BD941B17081DEE6 +:10616000BADB69B26BD4A4870AB0DFDEEDB15D079C +:1061700074B4C7DC8CEC64A92F7BB3C7D00E437E0C +:106180009376D802A755EFC2FCCAC5FCCAE3CD2F4F +:106190008E9EADC17AA7EF89C4B563D2F4F87A6850 +:1061A000B3C07F8DA1338A2BF5120F7FC229EDC1B9 +:1061B000BD0774C42BCC13F19A09FE7109E9197B50 +:1061C000DCBCEFCBF919B96BF2771FC5FEC08E4569 +:1061D000EE39DFE44B4AB9841D615FFA2B97198FC2 +:1061E0008FC4F007E06DBD93DB7FF4EC81B754C042 +:1061F0009BCD82B7C79D97B4FFB8BEED2BCE0F9C49 +:10620000137802BDFB7DECFFEC6DE7EE44DFB0EAF6 +:10621000B6AF845FCBEBA70BFD0C7EEF3F7CECA30E +:10622000FA4B709CA8FFDB5E887ECFF297AF4A42A4 +:10623000FB69D29EBB0D7C9E4F1D4CEBCFD93D8E92 +:10624000008E733685E7D39DDD33F608C6073EAB77 +:106250003B9A6BD6CF675F3C5668877ECEEE3E5644 +:10626000A851FE6ED8628F577DFD9B423C2725F3D7 +:106270009EBBE9ECE47A7D838BC71DD2D2F546CC78 +:10628000E7EE4848A6793F966E7B245E3C05D51D17 +:10629000EDAB7B74DA475C3CCCB7DC8DF1941C83AE +:1062A000F264972B81AC79B80F32CDE9C7387D6A9B +:1062B0002E1B9A9384A1C62073030B395E6BA2E355 +:1062C000A0096DC6013463649C452BE6FAB1EB0E60 +:1062D0009DF2BA1235DF1333A19C3943A3F549C6A9 +:1062E0005DFE9C9042F0C9B84B373C6FD869DD58D1 +:1062F0009C136C2A82768BC7A7503BEFB4B789DE1C +:106300009D3E5BC88EF3D1BA28FEF24F7543D3068B +:10631000031E8D2CDB4D64837C05D832E5E77B358D +:10632000164A027B640DF0EF60E0DF963A27D56FE6 +:10633000043BCE48A17B0CA2F77098F87E779D4174 +:10634000F57E529749ED1EADF3D1B37BDD67BC1DE1 +:1063500095E3E8C3BFD7735D1DBFEF4396FF7D3460 +:10636000D85540EFD4B14055C04BAA381F2EBF3F7F +:1063700055F7C6A049830532009F7D2B8D2DAB2F8D +:10638000016FAA239C8C478007BA58685226E6E121 +:10639000753D52928CE717EA274D1A0678C4FDE73F +:1063A000EBC09570AD6D084D007EA8F4D5635C2EF2 +:1063B000AB5569C6F526AB757D11C6F9A11E9DEBDF +:1063C00093FDBA5C5C3F251E7A52C91D8EC17FBE0B +:1063D0006FCEF62586E39DFF1CEAE27A6AB068B7C5 +:1063E00046EC7B774D73D33D0989875CC42F597B7D +:1063F000AFA1FD37772FFBBEB1FD241EFA13C5698F +:10640000DD4AD301DC4764F3B8BD28F9A9B7765853 +:106410005FBF82FA9D7E8DE2B660A6D2FCCE4EEBC7 +:106420004FF8C6FAE67B3C3AF5F876D46817B753CE +:1064300057D8E3EB6F8D71FB60745B17ED37E2BDEE +:106440004A88EFACE34D0AFAD367159E2FD117F0B7 +:10645000B11BCA59139AE8DEA56DCEE0752E80EF08 +:106460008FC689BC15008E2BFFF7D9D84EE2432D7D +:10647000D09DA84FB2F67EC0CFE1D8DA75CC4FFBE5 +:10648000CEAA17283EA8EAA539BC5CB702E3876903 +:10649000DED22DC8272CF4C2A4D7C0E7794C9C2BA0 +:1064A000C637A8F7D6B84439F47C4300F8648D9D0C +:1064B00097BFB3EAB9063C77BCC65EBA10CF256376 +:1064C000B901FA5F93DC9C6983B2BBFED986A30352 +:1064D000B02CEB3F4B7C76A78B9FEF61EED22CC4A8 +:1064E0007B77D980F2705359E365E6E44F39BFAA50 +:1064F000437F3AD20FF8A57A2FBF87A61B6FADEB6B +:10650000155C4F7E5277D4D7A0093991FA03D6E5AE +:10651000AB3219F9157A5809E72A781FC7CA74737C +:106520003EC9AD898A585FA0BD392E1873EE8C8E96 +:10653000B2E0FADAC0F33662E9FA46425143C218D1 +:106540003C2F1A5CADA21E7CC16E50DE7BBB467A2E +:10655000BB43E6BDD7DAC97EAB14E750EDCB82ABC7 +:1065600087A15CDCABF9310E5091D35484F64BC556 +:106570002B39FE7A16CDA3AD486E4E1FE98EE6D1BB +:10658000CAF2721137CA48AE4D4ECEC7FD92F5D948 +:10659000B89F51CD9AEEFB01C2FBA6CA90DF3F3DEA +:1065A000303E09EF05AA8232C6A9AA5A8EE941A84F +:1065B0005790C0EFA3A96E01BE71F37B6202798C84 +:1065C0006DD18C04D4F33F09D45E8D26EC13AEA3B9 +:1065D000935C40D767730306D2F9A5556F3538BF72 +:1065E0000565DD18C64660F99D06E4B38A1136CA12 +:1065F0008364A1775E0B0C16FBB1507EC89531D930 +:106600001C97CE12EB78CD26379DD78275F971E4B1 +:10661000EFEA8DB610EE6FD99C6D744EE725975C4E +:10662000FFADE79B36285C1F86E6F138E7929B5268 +:10663000BE4DE79B56E41AA14BC45BCB2E26D03946 +:1066400026592E48F051FF655A88F679CA2E7AE904 +:10665000FCD3DF6E3CA7E53C55CFF1DC048F1CAFCB +:10666000323A1ED1F5D0C85F3D3E18E8B66497DDDA +:10667000E630F1DD925D62FFDC15C8C07ED2748E1B +:106680006786FE1BF01ADD41C3CB210DD681755202 +:10669000BE431D0D932620DDA2DF9955FE03E83F82 +:1066A000AF4B90E50BF1EB27C4D4CF95FDFF85EA06 +:1066B000C7C29396102D3BA1BEF617477719E15B31 +:1066C0006F8BE92F4596F51593FA47F9EAA155DE48 +:1066D000C321E0AB75C94D45A8FFBBE6311FDE7392 +:1066E00085FCEA37E9DB875C5CCF965DCCB5D03BB7 +:1066F0008AF73C0B5D4ED7655AF62517CC5C42FBFA +:10670000A70FA1B0603F2CC4CFC16CEAC7C2A6B826 +:10671000CDFF87E3AF85E3BA5EE0F887FF62387CA0 +:1067200096F1A2700CB6C0F7D7C2B1F5CEBC6FE738 +:106730004095C794903317D7851FF1BC35357992B2 +:10674000AF1EF74B7EA451DC7D08E3F928B91A3B54 +:10675000AA8D44F9690A60DC822DE3F60ABC5F6900 +:106760001F49EB10F90B83F63A66615E456E59607E +:10677000213E59FF7CDA8F91FB984CC4F5E4FECBA7 +:10678000108315E1BD7C6F27CCA2752AB77466050E +:10679000C6BF55CFE8045C0F1FB38543385EE85190 +:1067A0003E5E9A2DDCEC447BC93BD8C0F52ECDCBA8 +:1067B000F51F5B9D4FEBDF565BEED58B008E154AC8 +:1067C00051C21B88E7E45C8A63E37BBC0767AB5874 +:1067D000B7D464BF81EBD456B16E2D17FA5DBE4FAE +:1067E0004C299D8576C4F2D545939DE3510F0556FE +:1067F000F681F566D9EAA21599E371BDF1E53A6132 +:106800007D599650B4C20993D95AEFEB6B2447CB0C +:1068100043FE02AB35E989A21568A734B81797A3E0 +:106820009D03DF0FA35FF86C8AD43BFC7BAED4538F +:10683000A897408FA9F5DDE510EAA5DC6EBD5344AD +:106840007A67FBD32A95CB603CB47B601E21BCBF2A +:10685000AB6B8846FE910B604980B26B582EED6B96 +:10686000C1BC5902C6F587F1EF725F421F62A37D7A +:1068700009AC8F787465F1FAFA347E9E59F7B8C97D +:106880006F93FB1CAAD8574B1079248A318DCED92F +:106890003AD78E5C8C7E9473B075FF588FC9375190 +:1068A00063F34FDC11B2BB1A12449CB90FCBA47B2B +:1068B0000DC47BC6FC23F1997E774311DD77E76138 +:1068C00006E63B670623CC6C2FC9A703D6519F4928 +:1068D0006E1C6E168897EF704F22B787DD1735EE66 +:1068E000272A60DFE03AEA1176B8B08FECF21EA2F8 +:1068F000987557DA4B7671DFDD929B2666E0B921F9 +:10690000D51D70A29D73C01849FB292AF3DF5A6474 +:10691000B2771A2237513C5133020CED9CFDC2CEA6 +:10692000510D3F33DB398D75E080C35AB5AD308FE3 +:10693000EE9779CA15710E42FA3E66F3A3DE38343B +:10694000B23CA4603C71292339DD56983E11F7030F +:10695000B668A549F7A2BC1C87F17C9C6E7CFF79C8 +:10696000B982F1EF0BCED224D407EB9299C58F2ACE +:106970004EE4FEC89309DCEE947E4223C013013836 +:10698000B48B57D37D3B43845DAACF9C44F12D4CFF +:10699000D3C178A583D5860C77F43E3947A6CD922E +:1069A0009FA85D2CA0F8DF930936CBFED1C3E23E51 +:1069B000405976B25A1EE7059E8EE7BFCD12703A57 +:1069C000C01EF2917D12B33FDFD33E227B45D2A79A +:1069D000DB4E51F8B9CDDEECA39A8B368B9E8D9EA3 +:1069E00037D7492F9F13E7F9659E865BE8B3C6CC7E +:1069F00060D3F539D1F3FB9AC8D7582BCEEDB34C01 +:106A0000ADCB7C4E3E11E331F0BD41E46D24C69C1C +:106A1000BB77B99790BFE01AAA59CE69395990DA75 +:106A2000397CD6F75A66EC79FE50779E16E5156AE2 +:106A3000EC49850EEF737BB79FC8933A9BF87E2194 +:106A4000CA2FD8BB3F77D23E023FC729E359DFD4D4 +:106A50003EDE8F76D518F40BA78CC07EBF23D6A35D +:106A60002C569AC537079B19E5F524F8DB19BF1397 +:106A70008CEC2D55EAB9D00B0DE847A599ED3B9369 +:106A8000BD3670CD0B0D0DDCEFA0F27756AD263D77 +:106A9000B8C225CB2BA80CEB5504FD1EB6C7E143AD +:106AA0007E82F601941B76671ED9CB6A2EB8B4009D +:106AB000F724BC9F10E3F97B1C5BD19E05BFF64E0B +:106AC00097894FCF7A4E64B3FCB8FD852CFD657F66 +:106AD000B3FE60FC16CC0392DF2779374654DECE36 +:106AE00087ED58FFB6F743D0FF632F3BE8DE107900 +:106AF0000F722CBF162672BB01F58639DF529F3903 +:106B00003780CC29E5D3919960C9D396F2AA5D1C50 +:106B10004AF229DBED4FC8E1F77369018AAB6917C7 +:106B2000F349FE9F14746DAC332E334E4A2FE38C21 +:106B3000A47E7A1FA750E80926F6B334C37CCF4B56 +:106B40006FF21ABB7F17ABDFE453EAB7DDA2FF3B5E +:106B500012ADF1E1F28DCD4790857E600BCE481CE1 +:106B6000837959EF797129AEB4450A50DE1EE8F9F0 +:106B7000BE1A27B7C0C5F727F2762C3A88EC3A3709 +:106B800031D884F6CC7D89226E9F09EB9A8AEB1668 +:106B9000CF2B5A87DF31FE1CF43D3119F5D4B412E6 +:106BA0008A3F6F4B2C7D1DDBAD9A5E48B10209F721 +:106BB0009A3A9E0F27F5A51BF105F51D5A2DE1CD3B +:106BC000E10E44D0BE684CFCF564F4B1548DCB4169 +:106BD000E59ABD24074ECD4F7CE574DB7CB8BE3B07 +:106BE000C1BFC375AFDE6DA378D272BCA73707CF24 +:106BF000034C35505E177B7233D825F4A376315D94 +:106C0000E85FEBBD377FFB7152A97D8FFB750E8D61 +:106C10008F607F9A9F517E0B22E143935E95EB7AC2 +:106C20006CBBD8FE253E257E1D5A90F0AAA3DD1030 +:106C300007AECDDD7119AE0F33A4FE4C7E3B2F02A3 +:106C40006FAB94762FDA27A0173727A25E1CDEF5EC +:106C50006F8A8FF4693AB76742F23E01CBFD453245 +:106C60002EAFBAB95D23E15FFCC6634EF33E512CF3 +:106C7000BCB1EBA53BDF9A47E1EC9F10739F6F3DE2 +:106C80001F472B25BEB14F0838514EEA8D9106DAC9 +:106C90002B0D9AEF7701CAFFB093DD0C76B8657CB7 +:106CA000F95C27EEEF3D2CECA8D8EF1E71DF71ECFC +:106CB000FB8F05FED61DB89BF4706FF4C303CF485D +:106CC0005F4F2E33F0FC8C5DC0EBBD4CBFBDF1D1EE +:106CD0002307785C571BE70CA38B153B9E6A2F0D8F +:106CE000E0792F7504237B571DC0C7075A1A181760 +:106CF000F68E4E61434DEBECAAC1D3F9FDCB69068C +:106D00009DBF533DB6D27876A6C4536BA2CDB23F99 +:106D10009F29F966C8EF693FC9C4371FA17E89E57D +:106D20009B56E4E1340E87999EAB06E766C4A34FF9 +:106D3000542F72BEBA1C5F144EE0FC9E01CF2D3062 +:106D40008F16719F4615E20AFC9DCABBDCCC80758C +:106D5000ED2B4FD117085F61DB419EEFDE9246CEEF +:106D60005FE584F8F2B2C8CDE9B2C8CDE3A84927FF +:106D7000023FC57BC35BDA127C0A7C6A4989AFA7F4 +:106D80000BDC52CE44FE84D65E80F688AC5F38D3EE +:106D90003A9ECFCDD7BF01B25DE8D614B4CBA66280 +:106DA0001780C7417E85E771B42686F17E7AB06A86 +:106DB000B5DB00AF3B84FFB703FCC269D06F7A023A +:106DC0000BE2BCD3FA40399FDA0776B9A3FDBDC9FF +:106DD00051C6260F2ADD8EFD4DCEC81AB13C87B7AD +:106DE000C77E0E27B006E7C828DE6F7500CBA5E08A +:106DF000F750DF45F9D1F7875176A15E7A7A7B812A +:106E000082FB92B6403AAE231F1DFB01E5C12EC0A6 +:106E10007B8C9C78A5844A7E52E18952BAB7EC53A8 +:106E2000FC9885F71D950E738FC1FC30EB3DA46C6B +:106E30003B3F3F23F1D5931FB8FE013843CE140BDF +:106E40009C6C1CC2EDE4ED62F1DBFD147C2CE909C5 +:106E5000E8B9C623E88972DA22EEC5ECE61B71AF09 +:106E60004287B80F6A76A2B817CAE0FE95BCE7A4BD +:106E7000450B24A27D3EBB3B3F2140E78F2A5D812D +:106E8000A4F148B763DC7F3A5DC4EFA73B6D0F24E4 +:106E9000A1BC9E3EA62AF594DFC1F33E655EDD6986 +:106EA000BB6FCDD5F07DCE3FAB817AFA6CF50B3A56 +:106EB0005860D4BFA29FD4AAD23E64CEA3B3D4E17B +:106EC000507F2E380CA88F6617BB4368C7B5FCBE31 +:106ED000F67D5CCFE63CEDF02D83715EDB38EA0B8E +:106EE0002C9F5AEBF13928DE9AABE0FDF14BD6E747 +:106EF00018B40FB9948938F3C4926258839FC7A11C +:106F0000E5FE8593EE9317DFAB1B27C1FCAE4E6BFE +:106F1000B1212AFFB0B6BA11CFB3ADA82FCDC43876 +:106F2000C25AF7E4468C23A4A707DA6E80753DE2C7 +:106F3000BEB104CB2D4FC9FEA63462DCE017B660AB +:106F40008E02DF4FBB679550FEF520D9FF92C60039 +:106F5000AC09B37F7CD51727305F7B5D6309DA0509 +:106F60004057615FAF21F8E64D90E526BD7830B41B +:106F70004F649678AA3D1A97A0786D4BB77DBEA155 +:106F800004E3107326D6166BD07FE1BAA71AF3413B +:106F9000C58E6D2A320250BE7EDDA6125CFF5A58A5 +:106FA000A002ED921BD63D5D8271F9D43ED6FE5310 +:106FB00055119767DB1AB1BFC29981110AB4FF97C7 +:106FC000752F35A21F9286F9B930DE05CF9F1A437F +:106FD000FDA3FAF396E83D5AAB510EAA9CED47305B +:106FE000549BBDB44BE779DB426FF4E7FCDC5D1EDC +:106FF000DACEF3EB653993975B96C5D7438F7AB9B1 +:10700000BFD99210FFFBAB42EF4879493AC1023B2E +:10701000E3C8CD16B7FBFF48EE5AFF6FE9B5E4CBE6 +:10702000E8B564A9D7043EF3AD7A1A8611FAFEEAF0 +:107030005CD40F0B30D9CA642F14B64DA775E47B0E +:107040005E6E3F331F6F9F56CCF39DBA5E49E4F7E7 +:10705000A43ADBF2CCFBA2C7053E8A1F9EFA049D30 +:10706000776FB3333AA7B2ABE89279A69518DF35BC +:10707000F91F955A84FCFA4A8CEF8EC2FEDEA47387 +:10708000A6D80F9E43C17D0C8CCFA62D8F4F7F6954 +:107090004F555E3458A84FCF7537DA7F2A0B8DBA1B +:1070A000FCBCA2FD59E30F3DFBD3C57E50CCFAA832 +:1070B000C787F3CF924F01DF36137FCD13FC26F73E +:1070C00095CFED19B6D5BC8F2FCF87817EFE29FED7 +:1070D0000E4608F43CDA99855AE066AC5FD89642D1 +:1070E000FB4C923F245F48BAB6A4D452DCAEEB49C5 +:1070F00085CEEBC5C265F3703A166EE4F73366CC05 +:107100000CAAE6FBE4A53C40FF2DA2FFD1E3487E9C +:1071100036737900B9B917E517EFDBC179F8DB0BE6 +:10712000CCBF3B21E1AF405E4C233A72FCBFECA2E6 +:10713000FDFED875328AFFBE97A16736D153DA417A +:1071400095BDAE975E9EBF7822E2F561FC08F91FFF +:10715000F549F387747F5C4BABCA141F9F37EAADC8 +:10716000C26E7DFCF5E1891AD963D1F5C3477699E2 +:10717000D49F11A7335ABF6BCDD793719F3955DC7C +:10718000CF9CAAE211EC281C233C5C8F8D0BC68F90 +:107190008716B83D9C0E621E4F2E9DC83E84F97F17 +:1071A0004FACF3E3DA43F4FB4976C4E398283EA4FA +:1071B0003EBBD5D1FEA238F762E14759063BA7DABC +:1071C00036C8F4DDCDF5AE1C0FE06DC0FB98D3E002 +:1071D0008957FF5FF0E4887D77CE9727F7646CA12D +:1071E000DF6D18141881FA46F217AC2762BEB6FBA1 +:1071F000A7BB39FF4F8F4387E982CFE66DE4F36F7A +:10720000F98FE29B910F5ADE4A495E66E2F77AA156 +:107210005764BF529E643BF97D86E8EF5E8F979E70 +:10722000F5027F0847BCFC0AD90EE74BFA7A25D74E +:10723000D730EF10D209E61DC273F8173C4A0C5E36 +:10724000C5FA20F05DA5039E018F3BECA1BE98AF6F +:1072500095A6F27C98CBC92FCC47FC8E8087F44E44 +:107260006CFF6B057F6C11F7E81EB6813CA39CB9DF +:1072700039BCE7F66451BF75A2DEE5F5E195C9CFEB +:107280001691AF02F0533E66D5ABFDB658E1AF178D +:10729000F00797E339C2D427987F3923BC45105FA4 +:1072A000295EBE9EB4E841B2DFBA9E64E4B70E0127 +:1072B0003BC207E59A52F74825272AA779CD0AD17C +:1072C000B17003ACD38837A7C4DB1B3BCDE36EF0B2 +:1072D000782CF710540AFA0F81F5FDA700EF10E89B +:1072E000E745829BC375F2F1E6EB313ED7BDDE0B7D +:1072F000BEE8096744EFC7E1A4BC0AB4777CA3A346 +:107300007062FF94E7E32E5D86FD56FF66773F735C +:10731000BF2F76F73B7BA20BF5D87AD0ABA40E82B9 +:1073200087F01CC9DCBDC906DEF700FE820DFD42F8 +:1073300039EE5C4DFEEE4F7B21DE779ED73D0EE8A9 +:107340004F93FE3BE071F3FACE8303F11E6DA6F17D +:10735000F529ADE9F48F701FA2B775F56FC50F4021 +:10736000479A77D72E98972F8ABF96E659CB5CA875 +:107370002F4F303FEA4B39AF2133DBBD987F53238A +:10738000F428E0C5867C90FACF3EB6DC67D2CF8287 +:107390007E43199737E99F0CC50D1228BFE32910CA +:1073A0007A8B519CE0E4ABFB7ECAEFEDE0F4AA9946 +:1073B000C9E92BE5F52B4F30C58BF6E95D0F4DE4A0 +:1073C00097E146E89EE6CA0D7C1CA8D7CC486EDB48 +:1073D000B26762FE25F2D3989E744B2D6D76517B79 +:1073E000C1FF675F191E463E4CBBBDAB18DF033FB4 +:1073F000103C2DCD9E30FACB642F63FB7D0A5FBF1E +:107400005890F03277A6E137F38984AF9BEE0CE811 +:107410003E3CFA7EC84CDE6F4D2BF4CBFB21F9A924 +:10742000BC9FF1FBA9057D80D5428E9151BD03E53E +:107430008823258A47893FD9BEFA7EFEDB3D182F77 +:10744000403FAF86B553DCB4522DED8FFE1ACB70A2 +:10745000D0395BF07F49FF1C7631CD05ED5F872782 +:10746000AEEF93D545741E6AF22085E41C2449C60C +:10747000CBE8F7C66EBD2191E7BD7DF5DDC1389F34 +:10748000B444CE77D08F53F4E3243B55E8C35F6711 +:10749000833E34F9A5871585FA39FCAD6BB62E57B6 +:1074A000A2F3C4FED06E38AC4CEB4FF6AC886B0048 +:1074B000DE2CF97851FE0D09B8DAB3F1BBD94F4291 +:1074C000BFA6DBCF62490FDF087ED5D829CD11BC1E +:1074D00052BB3E947CE3F760DCC9E067B960FEFD17 +:1074E000918FD12FC809A95E846B8842F7471F4945 +:1074F00008E6F37B88F938E922EE952EF2B4D19EA6 +:10750000C7E7362F5F2F8627F1F5E5A1245E4EF7FA +:10751000C68F933D21BED7887BBB5717C5CF071CAD +:10752000E7B5C6396F15FB3EE06F8DF3A6F1FBE0C2 +:10753000799E32DF2702BB96F05BFCF04CDAF7BC99 +:10754000D0764712BF9F82CBFFC74AE0DFEE52F0F2 +:10755000594AF703867EAB52BEFF4746C08BF9619E +:107560005509F1F3CFEF15705489F99FAEE3F74950 +:10757000CCC3FD48D017B70AFF6C41D36D2548EF47 +:1075800005E0BFE37EA4CC7B90F42DDBA45AF62368 +:10759000E6E17E649FBFC67FF0F7E23F8CB6F80F4E +:1075A00072DC583FE2645DA665DF6476D320718F9C +:1075B00007AF3F87F909EE392BFB59F64FD9CAB40B +:1075C0002BBBE714FC86505CF874D2AFF2FDC93ACD +:1075D000270B99E1F86430E58D8CF3061FF05AE033 +:1075E000486421331C6C02FF5D2F178F5B03DD4362 +:1075F000667B3A16AE55DEBFD64FCBED05CF79FF91 +:10760000257E5AE104AECFF05222CC81193BC96AE3 +:10761000376FF6F27572B337D16237CF9D69ADB768 +:1076200045D4DB22EA5DCEFF37DBCBCA20D41BBCBE +:107630003FF97B3C3967DEA2BCD3F7BCDC0E389E39 +:1076400014D881F2B856E4E96FF9CBA1CC39685F60 +:10765000FCAB9DF2048A362F598E79D4EE66C5A014 +:10766000734AAD563EFAC7A5CD03E7023E5E1274DB +:10767000AAF4F37954FA23FA6037E675F3F1FB378D +:107680001F5034939EE85FC6EBEDF3DA2D71F703DC +:107690005E7E8FC42FBD323E183E70532AD60F68CF +:1076A000B8AEF4C5DFC10178FAD6323A07D57734DF +:1076B000B7C7FE71F416057F974BCE73A56D5ABE02 +:1076C00001ED56A627FA514F671BC1D7719E95EF62 +:1076D000452218BE19FB5E9B86FE92DF081C457E84 +:1076E00095F3F2A9465F5C6F12DFE3F03575C721B1 +:1076F000B89E666C8DF05FB6723B56654719B773DE +:1077000069BF367DD9505A2FE47CD25384BE4D6771 +:10771000C1DD646FB395B4DE39F9FA99BE8CFF8E82 +:107720009EA467347E326C24C64F06AD8D68B3A12B +:10773000DDAB9B6C71EFDD3825F00EF3F800E71739 +:107740004B9F5ED71D51CFDE4B5C4AF27BE294F833 +:10775000FE1E638FD0F7A2CDA9F7905C36E8744F78 +:10776000A2C4BFDF28FD23C2D3B7798B82B83929E1 +:10777000F2194EAEFEA982F6D6771732438DC34F6B +:10778000DDF2BA74F7C0B9267D03FD133DB6C4E43B +:10779000A74BFFC49DC4F5F83CA3544D4AA37C619C +:1077A0008AE32DDCCE7F8FA3577C5C21BE9432EE22 +:1077B000C754CEE0BF475AB459237A5734F0DF2379 +:1077C000ACDCB98BCEE3B187981FE5BDB2799732B7 +:1077D00017C6ADD8B94B9967C25FBFCA30E5755FB0 +:1077E000E59171EA08DD3B16CBD718DFC7F5FD88B8 +:1077F0008BCB7B47913B8471EB0E7BB012EB7564B6 +:1078000025FA717F54E2FBF55D37D2FD079EDD8ED0 +:10781000083E57DAB6663AA1DECAAB753FF291DF91 +:10782000080E45BCA468A52DD83E39D5E3C7B8B726 +:10783000CFC146D23A778578181BC30F631FE27217 +:10784000724F9257DA59946F3531C923ED0ED24FEA +:1078500047EC7C1EBB1987779B373016E16147F9EF +:10786000EF29F4AD8C2898A7123B6E949F02DF4A53 +:10787000FA06FC0DF6928E7ABD42E899A2CDDB9510 +:107880000F4D704F456304F973E71605E32AF09D29 +:10789000F40CD467980FD577278F2755C0F7792632 +:1078A000BD22E71147BFDC86F0B9DF6B7B8DEB971C +:1078B000088F230B7863E9797F12B7DB4A6059A5FB +:1078C000F77A6828FA9B477213A83F29EFB1F2793B +:1078D000BFE0F3BE9BB62B3637C5DBC9FE92F0C9BD +:1078E0007AC79326CE491A837868233C546DD268B0 +:1078F0003E93F5D2C18B4CF2B048F477F0AEF7E985 +:107900005EA00D3F3F46FC58D5A470BBBFE9987EF2 +:1079100007AE2BA1E754DC1FB9992FE5EC71715F1D +:10792000D6CD2D5CFF56B5ECD2F07E49C9A739679C +:107930000ED23D5B55CD0E86FBA5C07FDF43FCC458 +:10794000F2A9C48FD4AFBDD113F4103FA710D24514 +:107950009C3A9833DD13D5CFDBBC627FD4CDDF6F8B +:1079600048E2E528FF04572559F4AB8BE422E7CC25 +:10797000C883980F5AE557E85C656AB1F87D321301 +:107980005CE6F331B1FA11E3E13C7ED29E3DDD7459 +:107990003EAE5BCF8BF64F20BDF9FB087FCF7271F7 +:1079A000BD96F0C7D2EF90B0C7E3F0593829CE3A70 +:1079B00026D7F59CA7776B788F92E49F9B91EE2654 +:1079C000FEF95912BF8FF767491AF5FF7811DFA743 +:1079D0007ADCCED7AFC7EB9D94BFF9FADD3C9FCCE4 +:1079E000738F1EC1E761DBEC4AFC7EB82F8763A56D +:1079F0006D199DF703B96C4E22FEF132AE1FB93EF0 +:107A0000DCF012D767952137DD775A19BC7D2EE55A +:107A1000D9A6BAFC743F68F035FD0E4F4FBEF2EDAB +:107A20003E40BF8B7C7333973F4907D0A7C45F525A +:107A30001E245EA3F8E47897F224E9B14DEE0B0022 +:107A4000BF70FB88FB23F94CA5FD9F3267E0089EC1 +:107A5000CB2C13FBA5F9E2775FE47EE96C4197023A +:107A60005BE9AF719E3DF64BAFD0AEAE58FAAB615D +:107A7000180F29CF3C4A4F29B7E0F759E4FB7D4165 +:107A8000F7C3E2F9B1E09B8AD1CD2497151FD592B7 +:107A90003CBBA770BDE67ECFAA8F195B27E6BB96DD +:107AA000DA4F4E6C2EC1FDC6C93F560CF4877B835E +:107AB00073019E5343FF68D321EF2CC4AFF87D2997 +:107AC000799EE70BA1273A76A8E2F7366BF54BD9FA +:107AD000DF97EB8F458E2B74EF89F0A93A76168FDE +:107AE000FF18FDBA1D49F4FB279FEDBCEDFB1FA756 +:107AF000E2EF8BDCE0473B21757929F14F579ACBB8 +:107B0000BF95C73DA7605CA7BEF99017CFFFFC6F7C +:107B10005968C8A800800000000000001F8B080002 +:107B200000000000000BD57D097854D5D9F0B97359 +:107B3000670B994966267BC832091050499884849E +:107B40007D9924844516270805641BF600D958DA68 +:107B500062A57F068388886D68AD225ABF01C16225 +:107B6000B53560A441020EB208553F470A165BB412 +:107B70002322B284648AADA55FF93EFEF3BEE79C82 +:107B8000CCDC9B09A85FDBE7FFC3E3733CF7DC7B3E +:107B900096F7BCFBFB9E33975FEE5760B01362B65F +:107BA00068084920E4CA6BF21AAF8990877FF1EA2E +:107BB00088A185842CF74A71064248EBEEFFF89FB6 +:107BC000D478422A76D658245AAF7FF94D7D80BEAC +:107BD000A7F16E67CF77C75AE0BDCB2F6C1941FA7A +:107BE000D2F6C67A6CBFF2C276ACBFF58B570FFDEA +:107BF000177DAFD215E380F7AEBC76580FCF2BDDE3 +:107C00005A67232D89FBA87EAA99969E976492486D +:107C1000C878C2FE9EDA73586FCFA5F5463A2AFDA2 +:107C20009E4CD77B7B65D1EF1AF7681798E00D2F34 +:107C3000214574DC5FCC1DEC867A335D444AE8F95B +:107C4000463DF1186DB4EC4648142DAF169B3C52DE +:107C50002C5D5789692394577F15351DD65BAD0F71 +:107C6000E458613E7D8913EADD011E4530CE0A5D90 +:107C7000B509BFC77E3ED41102652EF1908B7DE819 +:107C8000FA09D979AB3F8CF76B841F7D6F50540193 +:107C900021D3667D2AC17CA2FBD6EA96E33C5F66CF +:107CA000ED74D5E1ED0356D3F1E8B8B7E06F64A801 +:107CB0002CB298F07D0A102C539BCAD3ECB0FE78FE +:107CC0008303D62FD6975AE1AE37D3E7F7AE763B8C +:107CD00064BA8F6F5C3A35BA3BADFFA28FD45F8632 +:107CE000D76569AE8BF65FED31E138556B4AC867F1 +:107CF00074BE636017E9F78916123F84AEA74C4B38 +:107D0000E24D5012725A5700FDEFC276BB8138091E +:107D1000C503FB9BD376ADA39F3CA573A714413F3E +:107D20001BFD7A3B943BD9FCE9F7165301F6671922 +:107D300002DF1BC94AF8AE7DDD84F84D12F6EBD7A1 +:107D4000D942F3262498313597F55708701AEB99E4 +:107D50000EEF13BB1ED777055EC17DF4E4CDCE8553 +:107D6000F209365F0D7103BE24EA69897075679563 +:107D700053BC596429765B8A42656237D6AE86EB7E +:107D80004E68A7F0BC6071624976C71132B8F37BC8 +:107D9000A214F07F6B5A9B3E40C77DF2C0A788B704 +:107DA000D580B730BEFB821ED621F076217C42F70B +:107DB000E1A9FD9F22DE2E6C96103ED5CDC5FA05B9 +:107DC000B4BC5AE7249F69699DE3DF53526031E0F8 +:107DD000B5677F94651785539BC0CF864F2FCAF434 +:107DE0007976738A5D82E7FB199E1ED3683C00A7F3 +:107DF000633BEED95E2F85CF731DC247AA2048276B +:107E0000D5B5C46BA0EDC53F5F7D6A1CAD5755105D +:107E100007D079B50A8FB29E3FBF01F0C55A490A13 +:107E2000A3ECB0CE4F4677A7FD57579222A0D3D4EC +:107E300051CEFD5027CD12E905F50AD74218FFDED5 +:107E4000F8A50E99F66F1DE56A82F1EE8D1FEE9092 +:107E5000697F4FA5376E30D2764F19B1EC0238E802 +:107E60001A4AB4B4FE5499DD422149E1B63319DA15 +:107E7000491FBD6317E0B17B6125F4579D3CD301D9 +:107E800078D289FEF7AFEB03F3ADB6777344D1F741 +:107E9000C7374B8857C4632230FF6A0A5FA88FF741 +:107EA0000EF5C27CAE71F80938B6E9FC73607E6DE0 +:107EB000AF1B8887B68F1FC5F0D53AAA11F9C7DB6B +:107EC000FBC79C90F2427869DE67F041DDA6B548B9 +:107ED0000EE04BE47E03CC67019F4F838ECC75D1BF +:107EE000EFAC63593F3D364BC82F7E0DF49400A58F +:107EF00086977A8EE70DACB478F25C141FAEF1FD74 +:107F00004734A1FD2EE7F852B5D087F454F90AEBB7 +:107F10002FDEE0CC5F1586BFF1A504E978771499D0 +:107F20005B4E9FEFB6B2528DAFA7395D673DBF1272 +:107F3000F77D01DD77D8D7D4CDF439C08DE205C007 +:107F40008DEE23E2C1BDF14B70DF166C961EC07D35 +:107F5000F40C20504F8863EB54F77F96F3C5DD5146 +:107F6000AE4289F6174C303B7648301FA7260AEA06 +:107F7000F956C70E02DFBB76C2780949518EFA3036 +:107F80007E4588AB5043C7B9946866FBED7D5F3B87 +:107F90003917E8D18EED0932F111E43F24DB951B4E +:107FA000FAAEAC07EBAF8CF737A1C19347B2193CDF +:107FB000102E1C1EDE75DDA687F3D34F383CBC7730 +:107FC00091E9C0378EE989C908FD5BE838B4BFC4C0 +:107FD0001D435FD884F3ABC77D7BDB62C1B22CCE7F +:107FE00055580B2CB8876B35C045AC530D8F451CCD +:107FF0001E6F4D9B93AF013C9E627200DD3D794048 +:108000009A8F78ED3152A204BC677448E87E005D17 +:1080100010B716F7A3BAD6E58D8CF7E54867D5F10A +:10802000518E2809F1DE89F2CF63F232BC67F22F5C +:108030007A2C9357C027CB733BF303C16740BE0133 +:108040003E0BBAA81E11C881FDFDBA7CA54DC7E83C +:10805000BC8DC201E848D08DF90D462F9BD6D98B37 +:10806000A17D13A5FBF0FD3EAEF720FD1ECFEEE691 +:10807000807E619E2E7388BF67585C362B8577B5EE +:10808000C6B7419B15E2C7D56F3C96E38E807F82D1 +:108090001F1BB58CCF19BDD15ED62F1BCF48C16D2C +:1080A0002EC0D203F2287A0D838FBA9F5E56215FCD +:1080B0008D960B548E4FA29B14DB8390B11A772FB1 +:1080C0002BEDA7CA18384E779664AC09EA611E8971 +:1080D00020BB807E76447B816F252612F7DE08FD6B +:1080E0002659191F10FBD26063749418C3DE2FB693 +:1080F00032FE50686578792F2FC5FC05FEDB35EE22 +:108100004F89DCB51C13DFD17961BB980FFD7E234D +:1081100061F217E79BF870CE8E4D61FB11A2A3BBF5 +:108120000A609F7A6CF669E79B42E30879AADE7FD2 +:10813000983FD00FACA7BC6FD7EF351C66F4A8C62C +:10814000C772CE1763AD84BDA7F3FD15E96A8599A3 +:10815000EC80F96D25CE383AAF9A43BD193D38838E +:1081600039D0FF119BFB15D88F81A3389ED3E7939D +:10817000E9F3E55AE231D03D59BE5BE70D1819CD60 +:10818000DCA2FF95D858FFED66A347A6787EC6E629 +:1081900076037E794A88C30772E907947F00FD1150 +:1081A0005F11F0971A1288013857CBFE1C42F77FF7 +:1081B000B0C9BD08C63BAFF167C073420288AFE7E4 +:1081C000A262F208EDAF49EF4BFF3ECCFBA44C7628 +:1081D000D07EAE13E77858C775BFC6E6A1EBF8B8F6 +:1081E000F977BF3A40BF9A7DE0DAEC87004A9BA25C +:1081F000E73C4BCB59468D51DB3F048F73E6C8FCFF +:10820000F5871C7F12EA99DE155C67F0027CD4EFDB +:108210004DB0B1FDAFB9914A3C71E1CF191FADD15D +:1082200006F5A042D6DCC8201E3AEEC71A52D11875 +:1082300041CF0C5819FF6AA2A81FA9FD738E67BB16 +:108240007524672BCC673BE583003FAD1DF945C521 +:108250004FB31C9B68B5293B781CF488E0CF24E41D +:10826000FFE7748CEFD0BF29C60121F909EA09E8BC +:108270008715168F4F43F946C56AB34FCEC3E7DA69 +:1082800061B0771E8B16F8E07C2E1717D4BEFD77F1 +:108290002986B66B897118FDEE0BD3C218100B8BB3 +:1082A000BFBB2A1194EFA4590D489F848CB2803E25 +:1082B0002E3927C8B7A26FA7CF69516F477CA1FBA2 +:1082C000EBB2B95E80FD9E15CBE03D6B55B4D71384 +:1082D000C6FFA671F8A8F16C37E0289DEF2712932E +:1082E0002BEA715EB595DC07789714E3FA35F6BF93 +:1082F000EA9A829FB54981179F057C5C6176EC62A2 +:10830000DD66B8C2E8E51D31EE0D0DEE5F7BBE3FC8 +:10831000674D16E07D30E3F714CECB5B0C168F1D56 +:10832000DAF58AFD3F5F47195F4EA83EFF52CFD175 +:10833000C404F0776C007C58B0319A78FA84D60186 +:108340000A37E077F50D82FDCC6F79FB2CF0F36AEC +:108350006D00F167BED184FB537D438BF3201B7509 +:10836000AD01F13D95BFFD629C2791BE1E1D66BD0E +:10837000780F7D98449FE3FADDEFC3BA9F8E8E217C +:108380004E462FDEDE74FED78DF6581B85578D9E28 +:10839000E2473FECC6650CD3AF489A59B9FF2D2789 +:1083A000FF0EF3596874EB41DE2F9A5EAB07BA9C5F +:1083B00015EB2BB2F40DDFF761F2AD7BBEFEBE37DD +:1083C000713EF4B19ED245043AFC9CC37F02E02486 +:1083D0005DDFC7A98C7E3ECE20157BA1BC9B96F4A9 +:1083E000BB8FB379BD80D5D5FD44D9183D7F9CC7DF +:1083F000E4956725931FEAF7FEC1C773D99C5F0216 +:108400003CC573A78D3D7FD5E6FC0A9E537EF85F81 +:108410001C5F7D56DADFAC370D88AF647D3007F620 +:10842000B1635D397CBE8991E7956163FC98F62B59 +:10843000D98AF03D27EAED87A2BC60879009943F76 +:10844000033F5E994E801FD371A36CAC5F9F15DF15 +:1084500033E03AC846CAA729DEB617D9715F361588 +:1084600053FC043E71D060013E21F049E0911A7F37 +:10847000126D42FE31397C1FC86119E570A28DC9A9 +:10848000613DD039ED51CFF4C19EB8DF8867F2D796 +:10849000DFEF3D46B68F94DEED3694FBBEDC707A9E +:1084A0001370167CF2E36E4ABCD8CDF9601F0EB78C +:1084B0000E38DBD87BF13D98DC13F6C120BEAE57F9 +:1084C000383F17A5906303C72AF59257B85EF08A24 +:1084D0003546EC4B21AC5FC8BF4EFBFD1CDB6FFA91 +:1084E000DE6058CF2C43704E1C955FDFA17A91BEA1 +:1084F00000BF6B82EF3AF9294631B95BB3D24C40E9 +:108500002F28B55918FC0B8319D01FE913443E34AA +:108510009F507E23DD79FFC02790426964690C93E8 +:108520003B924C07049AE943ECD01F85F7245B513A +:1085300008DEEAF1CE4113D503A7DB242DEE573E2A +:10854000C987FD9AF3C197E6D9B4CB6B16A347430D +:10855000E5C87735EE59D04FEB832751EF3FA7F7AA +:10856000E5349822B4EB7DCF3F2D85DAE7BE247B3E +:10857000F494CF34F95B7F368DE2E57CBFEC80214B +:10858000E7AFFDEB7B03419FF6EB1C60D7527D62AA +:10859000B316E65DCBF4CF731AE5FE5FFD1EDB5F1D +:1085A000517F90E30BD5B3B46440885F093D6129E6 +:1085B000F1F5027D620171EAA13CBF62C90442E1AA +:1085C000B7C8B41AF9D8E595E3507F5E4C3CD8BEE5 +:1085D00060A3EE7CB87C59D4A0AC2FD9AAAC2FF5FF +:1085E0002AEB42FF4A288DAC57BCC8F9D0552A2E39 +:1085F0006EA7576CE1785BFAE884A791FEFD3A62BA +:10860000A0EFAD3E589C4422F42BCA9A1BD9C41B40 +:10861000268742FA470EF1F687FE6EA23FF079AE4A +:108620009F407F60EFAE8E7226815D72B524F2BCF2 +:10863000B7F179D7DCE8A6E8FFF94E7A4E0C8E53F5 +:1086400073C38865E77998F0FBAB8B238FB3BB438B +:108650009FB228E469E8FB7826FFB83D2FF0A1E639 +:1086600046323E1775A16787BE4BC3FEA860B35C58 +:108670008C0EF1235D37360F81FF9F49C49882FE2F +:10868000B12DDC2E71E4819EFB19E851407F63EC33 +:108690008702748A0B1E1A9CA3CD0ED1877A1D14F3 +:1086A0008FAE04C2E4FB219B391EE5B28338605CC7 +:1086B00081DF731E2C8B75D3F9FE696D6992BB6FD8 +:1086C00038DFF4E0F8D57AA1BF9914F298A8E4F560 +:1086D00082E693A89F2D34BA7280C97C7EF041C493 +:1086E000EFC5C4950878DD7EB07786FB7F21A7C5EE +:1086F0007CEEF7CCD3317D9C122DA5B7C97C3EF71B +:10870000B730FD506374EA701C27B15B12D1E46688 +:10871000F3A5CC524BEBC33BE60FCE434286F1F9B7 +:108720004BF03D85EF705E92F9EE6498B701C6A5F7 +:10873000E345116F3294F5831D7628474A2E2D9B11 +:1087400007DBE7D1A4360DDED71803325B279D4146 +:10875000227CDF012FAC9B797DFD94EB7316C173F6 +:108760009319F9869ECFE316F03F23F21323ACDB77 +:1087700060F25D86759979E92961FAB6279B38EA36 +:10878000E96BDD482381714DA66B1E58AC855824DA +:10879000A84759AEFBC0EEB866317934FD902FCAB8 +:1087A00071147EADD2BB8B615F281F667EA8AEDAE6 +:1087B000B53EB477045FB3F1F9D573BE9642181C89 +:1087C000E289EBB093F2859F98174F2031208EDD20 +:1087D00038FE3331634FC07C01F028AFC76ACF87C2 +:1087E000CB8B049756C1B792A62BEB296E65DD485B +:1087F000CE59007F259F2BF9561CDA717DC02FA31F +:10880000E3FC624A37362F813FD9711A853EE1E297 +:10881000767DB54D4FD01F986834927EA85F64C7AF +:1088200031FDE213BAD3D4FE0B221FCE1FE9ECF5C3 +:10883000330AE70D1FC88E87E93E6D30DBD76941EB +:108840006F9B21313D5DDBE8033FCFF63956C726EC +:10885000688F72FEF8BFA1FD039980DE5403FE7598 +:10886000A4774B317CB73DC382EFC59706D12F1A51 +:108870007C8CA05ED4094F6FD2F95378BF00750A83 +:10888000DF9A8596E5AFD0F7535CD10E29AC7D27F2 +:10889000B4D3794A1C2FE0F9C80160C7B2BF1E2DBE +:1088A000F97E27F8299C32CAB59A96FC23263A8F7E +:1088B0001EEE7C07A06DCF161E47893778591C81A4 +:1088C000522D9DC754239B474D4BF17D45B4BDA709 +:1088D000BF3F817842F409FBCC4A68D250FB19BEF5 +:1088E0002B8946FFD569EE47229C1F0C54D1DBD063 +:1088F00010FE637BBEA853F1EF1CC0DC13588F67DA +:1089000074E020E28FD1E71012FA83EF4B43FD2190 +:108910003F1A156A0ED11B5D5A81D1515F49DF3B69 +:10892000563E06F1B006EC27BA1F03B5BEC340DFC2 +:10893000437999CF4B32BF01E1B9699D5306B8170E +:1089400011B7BC85D60719FD71400FC38C8175091D +:10895000B4BFC1D3E72543FD20285945A86779C096 +:108960003F6F3569BCEB7013F31D4037D3A6333F1F +:10897000EBD4E9462FF8EDA76A098B6F69DD59DF63 +:10898000A1EDDF99C5FCBB509F15E63F11F18CD3DB +:10899000D41ED913C19E3C18C7E493F8BE66BD5ED1 +:1089A0001137DA1F67C2F6FF881BBD360EF1DF9D57 +:1089B00005F4F7701CD7ABFA903EC057C2E87E03AF +:1089C000BCD75AFC4E577C41D9CEF9C254E74F75FB +:1089D000A88F73FE20F8B00BE8907EE7979C3A8052 +:1089E000E747250CFEA78A97227F9846DCF89C2251 +:1089F00088CE15EE371A1BA6C7D071A6BA947ACDC9 +:108A0000B4E96A3D87E1AB1877865BD93E59E8A99E +:108A100063957AEAACEFDFB4A2FC4D7AB1EA562650 +:108A2000C649D0DEAFA1FBC4E2245A163759AFF7CE +:108A300082BE53D3BCE25802D0D15AC2E9688FB487 +:108A400010E3387BA44561FA43F74AAF047CBF3793 +:108A50005D931FF73588F1A1D33AEF61889B9C5E47 +:108A60004A574CE77944CFE28F47A38807FCCF02EF +:108A70003FCD9399FF94A231C641D22CD10ED0CBD9 +:108A8000376A0AD0DFBA31C6EC08F76F6E5AE72EA4 +:108A90000BF7B3DA0DA4C0C2F126921D7B8CF3C391 +:108AA000A724E6EFF6CC30A2DD96D0C3A5882F240C +:108AB000C8E42CF80DD7C6D951DE3EC5FD1A109F6B +:108AC000EB4F4BAF4405627CD8F732598F7E461589 +:108AD000FF498873A07F3F213617FDF4D35BF277FF +:108AE00022BF3145397A49A1FEA7BBB76B1781FE7A +:108AF000D4B25DBBD014C2BBB3025FA34934E06BF8 +:108B000087DF6EAF01FD76DFD5B8CE015E56EA7D18 +:108B1000794489CFF8BC2B39B684E38BAEC4356376 +:108B2000119D4FFB7B7AE6C75A4B905E5FDB6F452A +:108B3000BFA376324179B2BE98203EB46F97504FB2 +:108B4000FEC25A81FAFB7AA901E5449B6D34EEDF3F +:108B500032D351B44F2B9ED39D0FD7BB96ED54D635 +:108B600097133FDAC795AF74C267E45F823F563709 +:108B700029BF233D95FC319FF3FD0297E3FE329818 +:108B8000FA74470F661F139F81AEA3E85D3DF7F7A8 +:108B9000CE627293BC2881BED56EBE24333A67FC88 +:108BA000B888F7A79643455C9F1A41F916D89142B9 +:108BB0003FA2EF63FDA8A6454ED684E655C8BF1375 +:108BC0007A99E0DB625F8A07812D4C48463CD76F7B +:108BD000B24936EC2BED1FE9818EEBD1DBB07F0F74 +:108BE000D85F43F97874DF3D20673D1AA317F0681A +:108BF00083548B7CDA4838BF96DCF5F0F16F3C1E6D +:108C0000E4DB8349EDFD13B2805FFBA3011E141F5B +:108C1000B2E3C3F0A49EF832F6480A7CC1F656EBE4 +:108C20003B11F145C817DF474CBF184F570CFD9457 +:108C300041E08696472566CF8D313DA985EFDFD18E +:108C40008C437C184BBC5A985F9945B9CF63929579 +:108C5000F571F64E7820C3B84E0ECFF17D94ED4EEF +:108C6000C1D78892AF65919BB8CFE4B1E3DF05FB34 +:108C70003E7A0DE9037A07D51091DED4FC6054BC2E +:108C800049A11F85C53D46C527748E7BB4733FEE51 +:108C9000101258FC8AD4195FDA8EAD9193C3F04A52 +:108CA000E0F11B3C4F427A93C7570B995F2F24E7A3 +:108CB00019BE0CE0B521806FF4FD45024F32492604 +:108CC000E0C9F0E6289F4CE19ACFFB1902785310D7 +:108CD00092E73E8DC9AECF06FC706C94E5CE7A7BF0 +:108CE000A2CD8E78D25F23E4BB238EA07C6FACD75D +:108CF000C2FCF70FECEE3629F06229E28544F1025E +:108D0000E9AA935C54B6ABF046ECDF09AE2F8F2195 +:108D10009E9E301E656347415FF66531BC29234E38 +:108D2000C493B7B3C7F1F8B35B8BFD10A53C2C35EA +:108D30002AF1408D5774444DF8B86A3CEB0A6F3203 +:108D4000016F843C8CBB33DE3CDE35DE3C7E3BBCBD +:108D500051E38BE0277BA22CA5A097D65448C88767 +:108D6000FBBFD7B31EEABDABB2308F658FD5817A1A +:108D70006B4D2D6B2FF43B65C873E9B19AB767B99A +:108D80004AA15EB386C51B8A4EB33C989E6B597B45 +:108D9000FEC3B547CC20DF3DECFB372E6F906368F8 +:108DA000BB7703FFBEB8A114EA351BD9F75F40BCFF +:108DB00088EEEF80B3DE7A787ED7E62C07333F99D2 +:108DC0003E3B92E3E91E69EF11FCAE817DB7E4B84A +:108DD000B11B413D98E9AD23F83A473EC7D619FF8C +:108DE000D9BD63ED147F17053DA8375DD4540E40FF +:108DF0007ED3859D592C35A44149F106F98CD34881 +:108E0000F13A9BC51377D021DE8E677AA088C341E3 +:108E10005E40781EC0DBF14CDE8BF7126D84C58D91 +:108E2000B799D1AF2BE284BEA7890474066BE4F234 +:108E30003F62DC704C8F5A8C178EC914F1C2807659 +:108E40003E1D37FFD697A323F951FE938F7B89E709 +:108E50003988E715DE2C0DE0C51E4092540052F50E +:108E60006F416FDA037E5426343C6410EC2BAB9FC9 +:108E70008B5FB6692335D297686AB51E103219D454 +:108E8000FEA25D4FF2135F6C4CE7F98FD1121FC841 +:108E900027A265F35F5C4FE5A014E24B5305DB1995 +:108EA000D60BE9740ADFA7CBF15CDFE84FFA03BF0A +:108EB00099CAF7ED3BC65A1D93970D3A15FD5F43CE +:108EC000FA7FA64BBD59D9AEE20F157CDCC55C5FBD +:108ED0005E4A82A8175C94BC585E7A86E9CBCB4D7B +:108EE000A751AF68DFC6F4C44A1240BD43EDF75B3B +:108EF000BE5B59AF6A54D66B9A95F5F65C0F8ED36C +:108F0000FE4CD500F0BF556C7D0FFDBB15824F7830 +:108F1000957C822A488C4F3C7D37FA6D3446CA27AF +:108F20000A015CDD306FA43F71C6013F00217B8BDD +:108F3000D61F834F52685DE38A49403FD6D8B80BAD +:108F4000627C19E3B2EF39EDA17DE9B00B557C22CB +:108F50005FF8637ADAD05F25F8463E617242AD175A +:108F6000F54950DA3942AFC807BD82E2855F63F246 +:108F70006A34E17A8417E98FDA8BE3A3B201655C86 +:108F800032D4FBCF2834F27D27AA7DED9B707B7B0A +:108F900049D9AEDA7761AF0CE0FB3E83B8BBC33E84 +:108FA0004C21AE6320174E7D54A1B0933EFAC368A6 +:108FB000E147417BE99BDB494EF9DBD8491DFB1DAD +:108FC00045F5465A964E1ED7EB6710DF6E8AC2BC37 +:108FD000CD1A89ED6FE28CD319E17EC3537524411C +:108FE0001B46EFF5E30C4688EFD5EB981D3179FC75 +:108FF000C703E687F18B178CC52E80D706C9FFBD46 +:109000003F825D7152269817D39280FB7DBD813ED1 +:10901000A77876FDB97B1C1EFAF8AA8EC50BBF9007 +:109020006A17432A9398C7E235BF8DD252F9752546 +:10903000FA10C683CFE8DDB301EF96BDB30FFD9103 +:1090400095A077F708F5DBB5DFD1837689FE2D266D +:109050000783523707E625104F4E789C685622E367 +:10906000AF676CAEA5307F21E784DFFFDC8A31B1CA +:10907000200AFE429CB1109F94284CBADB3A8F071D +:10908000F900EBC3FCCCE7A294F105517E2F81F9E6 +:10909000BFF7012DD1F1D2ACCEEFC3FA2E717BEF29 +:1090A000128F535D8A6171AB871318FFDDC7BFDB79 +:1090B000CACB4B3CAE75C9A6B413C57BDBF877179A +:1090C000EA8CC6F561FB687FDA50EBC53C289EF759 +:1090D000B19A30BB68BF75FBA6B0F8C1AE84E27D23 +:1090E00030AF841E4E7D0AC06F3F93BB1047867819 +:1090F000EF308BBB01E0556D274E8897127B407F88 +:109100003FC40DC1CE447D81E1497B142BC5BC76A3 +:109110002594EF4338AF0820DFEAA897337EB82BB9 +:10912000C185E3B64F15EDBCFE04AB13EE2F10FE68 +:10913000EBAEE258EAB815CC18F5EA28C6B7D4F178 +:10914000EAD9826FF178F52CCE8766B7307FF81CAC +:1091500023D9D09DB6CF6D4962F6618C274711AFF8 +:10916000F6447FA33C05819FEDE9FE8E38EBB6B057 +:10917000386B158FD35589F53529D77724A1CB388E +:10918000EB9184087156753C7F1FC8F39E2178AE21 +:10919000B4B0F597C995A57AE00F0B09E67FAF3C0F +:1091A000B9A0DE48EB2B1F034F1FF221D44FAB3881 +:1091B000BCBA9A5F824B43EC0ABF7037620FB3832D +:1091C00053DC36451D35DEB0FCC9EE15A98AEFD358 +:1091D0006BB315EF67AEB95BD19EE52950D47B6CBC +:1091E0001CA278BF574389A2DE7BEBBD8AF7F34907 +:1091F000762CFA8F4EC8E01B217779272BDAEFD92E +:10920000FD80E2FB2F48ED53C3E87B4D518CFF13EB +:109210008FD3DF7740285F38B771BEE2FB7AA97140 +:10922000808FBEBFD0CFFCEBFD9A9729FABB1A33D3 +:109230009AD90D3C4E584BFF31FE6D9751FF699600 +:10924000C836A973DCB0A265CB86EE2452FC90C967 +:10925000F56554AE83DEA4D62B0C893C8E944A521D +:109260006F85D155080F4CA8775D7F4E46FF593E5C +:10927000C9797A18C24747BCF6CEFB759D30BFCE80 +:10928000F557CC0EF08F2D39B900F1CF90ACC483D7 +:1092900028BB120FA2FB28F1C0EC50EE7BEC20E5BE +:1092A000BEABE16C752AF140C051C0396EAC122FD3 +:1092B000047C07D17F00DF02123C8EF9D15EC9E148 +:1092C0002311E2B2CDDB711D77D2D3F255F0EC7FE2 +:1092D000D4596F4238B17C29A11719B85EA2F69310 +:1092E00077F85712B9DEC3FB117EED0D9207F59C9E +:1092F0008EF8D5205F862F0BF49D5AC2FC23AEB2A8 +:10930000C4C87E347CDE951F4DC051E831CB418FFF +:10931000A1E32C226EE44B17B81EB3C4F424C6019B +:10932000AFFE81C1B78278915F7FE3B836D50B4934 +:10933000987F510D47A945F299810E38DF4E252DB2 +:10934000826FBB31DF81A29D7180229EA0D43B89B8 +:10935000530AE74F420F15E309780ABE25C633903A +:109360005A3919E840C5C7481F753C43E9E7107EE4 +:10937000111C2C2C6E31B0231EC1ECC2909F8BF9B6 +:1093800035E4CCAC7A02FAB645F831FC33E1B9F0F9 +:1093900063A8EDF93BC541EFF7488167B33AC73F92 +:1093A000453C952EF3B33FD28F8749F674186FF280 +:1093B0001BBD138826921FCE71F600ED47D604E33D +:1093C000C2FD63C25FFDB614C0797F87381F21617B +:1093D000FA4235691C3D330BFC9D546EC540C9FCF7 +:1093E0003CA459AD8FB2F8A186AE04F07B39098B4D +:1093F0000F6685DAB12E77AE8BFC943BC9F75E49D8 +:1094000016712E2587B533FE26ECB5AEEC2311BFC1 +:109410003FA6A7302908E5A33426723F561EC9830C +:10942000FE295D352526803D4EE9500AA7BB8EFCFE +:10943000156CEF4477AAF58BF8BD6C2E443FCB82B8 +:10944000F0F57E0D78083DE2065D1BACF7478976A6 +:109450002CABBA9DFBD009CD857E451E628D9EE565 +:10946000FD9246A5FE7C3651C459999D71273875E9 +:10947000BD0F3C9F8BEFC3D7D587443E9780DF2736 +:10948000820F86E07D5E01CF0E7BAD03DEE723C158 +:109490005BC0E35A91FF45D827D97C3A11E09C1470 +:1094A000E3FA02F862FAD9C04549139A5799DC8A5F +:1094B000799CD79B65B48FAA87B37C9EEAFD18245C +:1094C000276D2D068C0356341F41FDACB58E32D26C +:1094D0009E5DC3A963BD2A787765AF88F5DC52AD80 +:1094E0005FE487407C3FA9E8B67050B67338887C4B +:1094F0009632B96F6C20CC2EF1F17D8FD2BAA29248 +:10950000E8F885BF4B8B01F894C92DC753010EAB0A +:10951000253C6734D2403CE0DF4FE1E7CD06056AE9 +:109520001D160A8FE434139E1BEAFD5DD905F1CBAD +:109530008F57AFB2C1B9A82B7574686A77F49634A7 +:109540002EC437B2F7931F14425C6D16E617CF3660 +:10955000B0787FD6F7A27D3D289F78534F8C406F1F +:10956000BAEC5A3C5711B4CA686FC4CB6414E09784 +:1095700080737C345B87785EFCF39D12E42189E77D +:1095800023EB83FD57D2F273D8F784D03A4796067F +:10959000FBD79A427016F97D441BCC981C461F4796 +:1095A000383CAA13F41B401EB619B91DC8ED416220 +:1095B000D1221F59CDE3EBE77A11E2C77E7C66C862 +:1095C000A7AA8E72C60E04FF16E40FD0E22F16670C +:1095D000AC15D76F47BD7935D7AFDA787EF6EA712B +:1095E0002549604F25D447CE631A9DC4F4FC4A1E1A +:1095F000F716CF2BB53ECC47AA847CE1B0FCA86F10 +:109600009A2F2CF2C4BB8483554BB4140ED512711F +:10961000DDEEBD03FF2347B477AB9234B7CD635B78 +:10962000C8D727F2D3AA213F8D3E5ABDBF388944FF +:10963000E8AF43DEDC18A2C80B13F9CDD53746607E +:109640005E58E9A3AD78BE0FFAB19B4279695DC15E +:10965000F948229B4735E48BF50F7FCEF847A8FFEA +:1096600078DC875F0200C1CFD12CA31FF697273487 +:1096700063774498EF16BEFEBB13B4481FF7F88813 +:10968000737B84F1C57BE2FC07C0B93CB7F3FC9A5D +:109690004A027360FE90771A69BCF549CCCE16F386 +:1096A0006EB20516733CC7F3171D758B721F5FE012 +:1096B000FBD8746F2003CF118D8B9C072FF6FBA670 +:1096C000D9FD26F0DBCA69F465F0B36B6B254B1846 +:1096D0007D75B5DF21386B14F97F9DE1ACC7FD15B1 +:1096E000FD097BE4F25619E3FB974F717A244E9300 +:1096F00044E96A1E975797098B135C6E90D00E99B8 +:10970000EF26640DE52BF3762EC738CDE25DFD37ED +:10971000809882E76B29FF98974CC8085ACE5FAFB4 +:109720008CD32EDCDCC9FF46C2E522553BD1AE5EB0 +:10973000FCA4F2BB0AB2F9CFA0F754A8F49ADEDC7D +:10974000BFB52F89DA09A0D70D200380AFAFDCF5B4 +:10975000A51E526DBBC2F32B949E7B6A81FF59B04C +:109760003C91E43C08FCFDF7496E1F94ED1F303836 +:109770005CAFBCCEF8FD73F128670CC094E9FF1A0A +:1097800066B278EBA3944D409CCD60607A8DD0E7B3 +:109790006479951C43DB077FBEDA06FEBFF897C7E6 +:1097A0008C057D3FE1E56827C06B53B1331FECFFAB +:1097B0004DE526CC5B301A589CD7FBCBC16F81DBC3 +:1097C000BF67E39612B03F2D2D877DE01FD9A8F922 +:1097D000339E1BD93882E5B575E44FB694EF81F915 +:1097E000644C61F262539633DF12D62FE1FA593599 +:1097F0008759FBC1DE3F86F3EACF9E40F598AE2F36 +:109800001BFD707713B69F227F0AC60ED7435BA954 +:10981000DC81243C51BFBB51F2E9E87AAA9AF66098 +:10982000BCA2F2615FE24C902F2F6931DE23E61774 +:10983000FF664A09C475845C992959989F91EBD9B0 +:109840003388F86371A1E91C0F6670FD7A66348372 +:10985000EF7CE2C880EF1E309218F04FCF2C6D2CB9 +:1098600042B9B35C6705792EE21B5DEB0191FD44C3 +:10987000D52F9AD9F9572998039D5CA1760761FEE7 +:10988000A28879BFE6644E67395CDFEB499C104FD4 +:10989000AB3ED47B3BF8030CDD58DC95F21BE3A018 +:1098A00002D4778D60C72C3D10E5637E6A2F3FE7B9 +:1098B000EACC87FC8F9AC9690598877096F20D33B8 +:1098C0009C1F0C64209D527E22519996936C9EA001 +:1098D00085737EA9549FA2F5295B53276829BE573B +:1098E0006707166B687D6D72216BBF3B7011EA1BB9 +:1098F0009247B2F682C06299D6B7274F647530ECB2 +:109900002862FD3A79CA040FEDFF8A95CB694700BA +:10991000CFFD56BFD15B13EEA7DC06C90B143E5733 +:10992000B8BFF54A16993B19E0DD2780E7CAC47B2A +:10993000FF87BF27F27DC53AC577243972FF45FC02 +:10994000BBA5FCBCEEC868B2318AC5A53C3114FE8B +:10995000475B7A635C2D35D9C6FAB7D07E0A43FDE2 +:1099600008388AFEC4B8CB409E029FD5317FA968D3 +:109970002F4966FC9B8EB31EC7E9E964E75027A711 +:10998000E5C3BED1FDD2F2FDD232BB733B9B1FEDCE +:10999000D79A877CBD3FF8BB8FDEA4EF6785E6AD25 +:1099A000C68FFB387E2CAD67F1C4A0B507E2D1C8E5 +:1099B00068A6E79142E53AB62733BEBF2DD9CAF073 +:1099C000A2633F92241CA79EC3318DC23DF79BAF7B +:1099D0007B1E9FCF3F7BDD61FBE584FCBEA3CD7783 +:1099E000ED085F8FC8CF16FD5C59A7FA6E10CB93B8 +:1099F000AAB6F5C0EF1E8D22467C4E76747C9795F4 +:109A0000C7F44BD03BC57D0CC433029D04959C6BC1 +:109A100074DCAFD0C8F3053BD637A190AFCFC2D727 +:109A2000673186DDABD0418FA7831953CC9DF1B749 +:109A300003EE1DFDF52DE0FD29E83A527F401F5D44 +:109A4000EDC74FFFD97828E6A98267079C55F31325 +:109A5000F0047AC6EFFA2AF151CC7343C73EAAE864 +:109A60003AEB5B8E57CCBEAB7A90E7FDDA95F85CAB +:109A7000D594A58178B9F86E2CF8D81342FEB67D3E +:109A8000C9DC6E4B23695DE4BBBD919C10D14F874F +:109A9000CFD5765BBB95E539ABFD06ED090E3F9C56 +:109AA000C3F35C63E7CF87AAF40D88BFEC3585BEAE +:109AB0000BC91365DD90C2F85B673F5010CFCB1622 +:109AC0001A4A5EB33B28BA242F43FE5D185BB22AC4 +:109AD0008BD63F4AAE447E5DD8BDE4CB2CCABFFFD7 +:109AE000985CC5EAF7947C990DF5AD55ECFD91CEE7 +:109AF000D780BF134FD584512921FDE15CB29DE988 +:109B00001FA51A027864905738404E0A7876551689 +:109B10001A34B511CFB576E0018B4F0CE2F2799093 +:109B2000B0CB035A855DDE1EC3CE13B7833CA5EBD5 +:109B30000D26BBAF00FC6BA25BE764D1AE1E8EFEB0 +:109B4000440FFA90E4A4FA06F839EC16320BF2E767 +:109B50005A37B9403F22CB1C462DC293FB9DE8DA11 +:109B60006ED17E0E1C7AE9A1EE6C1817CC6330A77B +:109B7000FF9A437FFF0AE2A235574C0E50FF06B70B +:109B80003CB30AF4ABC12DEFFC9DC95B762E43CCF0 +:109B90007B30F80FE9F341CD069CFFE096BB16C180 +:109BA000FB437FD7D203F063F8395F3DB083F68380 +:109BB000BFE9AE388F41BE90BECD798C0E787C4E19 +:109BC00095A75884872905E17113F3A2DA124E6D27 +:109BD00008A09EA63CF742F5728CAF5E27DD1C10F4 +:109BE0002710E7B4D5FECAB3E5747DF4F9F0209DE3 +:109BF0004198BE3CF206B5EBC3F4EC626255D44B1F +:109C00008D298AF7CB2C598AF631C97729DAC7D939 +:109C1000F315F5F17D062BDE9FE82856D4EF1B34B3 +:109C20004EF17EB9B35C51CFF7352ADEEF7FA259F2 +:109C3000D97EDA8EFBD0FF9CAB14F47887DF5D0F02 +:109C4000E5C0D686D2583BE9E4A72D0C78EBE1F9C4 +:109C5000D09BB5453E12E1BCCA3237FAF73B9D575F +:109C60002966E7D7DB34ECBC86F0CB0E36B98B61C6 +:109C70009FDE9628D829B047188371B05F65739F1F +:109C8000C0FCA8EB41827EAC267DE0474341CECFAD +:109C90009651EF6DE279354DD37331DFFDAC14D8B9 +:109CA00007F179CF6C761E6038D57071DD10D394D2 +:109CB000609FDC8A751793A5AA7D5AA1A897591EA3 +:109CC00054BC3F26799DA27D9CFD31D53E6D51D47B +:109CD000273A9E51EDD376D53EBDA4681F7E215014 +:109CE0000F6434B2D5239BE9FC879C6D28857D19D0 +:109CF0007ACE331BE8A5D0E7AE07765874B4F608E1 +:109D0000943E6A4F817FEAADBA642C8FD6D9D1BF19 +:109D100074BCAE0F9627EA1CF8FCB77583B07CB70D +:109D2000CE89E57FD68DC5D25FE7C2B2B1AE11DF75 +:109D3000DF5BD78C2585603AC88BF8B88E7B13D251 +:109D4000C18E6FD304AA2182FAFD670E225F6CEBED +:109D5000166883FAC3A465C2285A9F0FC614E85731 +:109D600050D2FDF4A43AFF2B05F22952D8739197F3 +:109D7000D0A871E6837EFDF833C7366BD3097964CA +:109D80009D2BD962657523ADE366431F9E639B9D42 +:109D90006984FC0A44C610AC4F807A7B146BDFF0F8 +:109DA000CCB1091E9C1F8B1F4F09C58F1F4F8910F7 +:109DB0003FFED525BB19FC28A76EF636C3BA4E71F7 +:109DC000BF9193E4EBE6D1B2589BAF03B97856A5A7 +:109DD0004788B24653FC24E069A3C63115F380EFEF +:109DE000D511C83B9F2C317BB4430F4C65F2A87D45 +:109DF000A201ED9DD31AE722CC6F9282CF03BC5E05 +:109E000049F910E1D76E0E66001C7E997286D51353 +:109E100082CF4B8EB0BA8EADF38594D35DAD7337E0 +:109E2000CCA7D33A53D87D31C4E74C07F92BEAA726 +:109E3000CB9D5520274E173B7BC17C4EB90C483F2C +:109E40001E97D90BF99544EB2C9A1AE64FE99DAA77 +:109E5000C3EFA6E8199D9107E488E7C4CB52999E09 +:109E600085FB06F6DC8C68D4C34F6B229FF39ECD36 +:109E7000E173B55B64FFCA1CDE5E72BF19FB6B5FEA +:109E80001D85F1DB76576FD483DA6B2994287DB476 +:109E90005FAABDF63AB61B44680BE39433399FFAC8 +:109EA00055CBAABF9EA1EF7FB23ADA813CDC723774 +:109EB000CAA707F8CBB3E38CA8B7CC9E9C5E02720E +:109EC00069268F77CD316B1331ECA5B5EAE10AA095 +:109ED00085A6FC0D20FE17C797EBADB45E91B66268 +:109EE0000394CB7A6ED1C391CFCABE7B3680FA5829 +:109EF0004549AB08EDA5C07B75745E73D7C876661F +:109F00003F897386CBBF517E85C0C3D33C4F86C289 +:109F100017EDC2B9A992C22E999BCAF4866B295C2F +:109F20006FCB25B9B794719C3F033DB4CE7E2FA76C +:109F30000B7FBBB29DEB6D1FEAD9B8EA7B26C4B894 +:109F40006E3E8FD37AE294408F7BC08CF89137FDC0 +:109F5000CB878BE8FAF35A2C1A8CC30B3EEE67F7CB +:109F60007D155D70239F1BD81A78F10C413C6F065C +:109F70003AB9939CBADFB30EE5C3E0BF50F9037C56 +:109F8000F1A6FB9333D81A1FF1FCA5AFAE82F3C73D +:109F90005AE46B47EBD660FD789D07CB13751B39F0 +:109FA0007F6CC0F677EBB672FEE8E5FC71373E6F6A +:109FB000A99B8EE5A13A37964931AEC454A00BA3B4 +:109FC0001BF3318F3D632032C4195A0C88A79402C9 +:109FD0009E7F361EF25F0C163867A7CE8351F3DBE7 +:109FE0008EFD6FEA748F45766A5158DE0BE86799EB +:109FF0005DE3CF296237033F19B22D6522F08F53FD +:10A0000076BB19F4D6A1A9A9ACEEB49B75B43E6C8D +:10A010001BAFBBED6603AD0F4FED3E11F4DE531EDB +:10A02000BB398AD6476CEBCEDABD0483D4A5DBEC12 +:10A030001381FF1413E928D043A9316B14A4C896E7 +:10A04000598A8F021D8C499E370AE8606F8A1DF17C +:10A05000619C7DDD51A88FEFB35D0B476B9CA6FC27 +:10A06000F5F05D497CB916BE1B95B6623D7C37BAEA +:10A07000E7166DF87763FBEE590FF5098EED5AD0B0 +:10A0800007F7A6B0F8A7E847D445BBE0AF224FAB2F +:10A090005F8B0BF9785EB30BF978873F624AF9233F +:10A0A000E0A7AB69962C12CC638AD4117C875CB88C +:10A0B000EA9B945A289F9DBCED1EF33A4A5F3550A7 +:10A0C0001F82F527D645E6BBD35223F0DDDF733A76 +:10A0D00005B909F9CFBFD7B37B387EC3D757D33281 +:10A0E000CF3C0FED19B719E4EBC11426270F73F914 +:10A0F000F8675E7EC59FD7689CF360FF2B5279DCC2 +:10A10000B6335D57C23C28DDAACE0574D1CEE9BA7C +:10A110003A95CB077EDF411561E787EE94AFB53402 +:10A12000DC7ECB82BC9CC6E39027AACE7F10F98D43 +:10A13000EABC5FCA17F15E17D2ACCC1BEDB03FBAD8 +:10A1400031BE07C715C1E87834B54B7EF6F81DD689 +:10A15000FD78A4752F252C9F59BD0EE24E40DA12D2 +:10A16000F9CD9DD71388BC9E4EEB6850DCBF20FC18 +:10A17000EC540F7A16E65336D74CC07F13CE27CE59 +:10A18000DC864FA8F9CE3F8B9FDD86DF34C23CD5FD +:10A19000FC469C6F5697429F837351906F07F7B4AC +:10A1A000809FFEA144F701C0DBF692E0571AB0CFC2 +:10A1B000E20388676956F721782EE959DC5DE4B13E +:10A1C0005ED2787E0D7AD16FB72D423ED406C28121 +:10A1D000D2E35BB40EFED36116D7519817E9C3F0F2 +:10A1E000A7ABFCCC77B81ED2B9647425F214DBB7E8 +:10A1F000FF3D03FD5877C0F7AEE050260F0B40FE41 +:10A20000FFF541D1A8F2B44AC42715409E7522EA51 +:10A2100011ADE97A2D94FF6C3BB1353D07FB57DB5F +:10A220008BAD29838C6CDCD163A16CD6BBB7CE031C +:10A230003B69B001EDA4F7797EDFA4F337E3415E1B +:10A240004D927D897952673BB3F5E4AC127B5E6732 +:10A250007B93AE6F14ACEF4E76A7CBE8B70118D561 +:10A26000F667E59AAF08E4430F5D7393C07D6377AB +:10A27000B647890C6CA2E0ACE3089445179C98861D +:10A2800033E052ED112807FF8599E777CA271A7244 +:10A29000A3F1083B0EDE5779BFC2A07798BDCACBA9 +:10A2A0004EF7B02DF328F3D48A7D45983F210762FD +:10A2B000A0BC2605D0EF256BD8BD0BE2BE056AC752 +:10A2C000A6764F00BB97E54B8D843C233AB9B21F6D +:10A2D0007C34E721A4FB28D47F3AECD8D735981FEB +:10A2E000D0A475C60E073B764D2FC73A5AFF933F51 +:10A2F000E16707685963F98A84DFCF56B9E6BAA2E5 +:10A30000DEBA2E74BF0FE44157FE8F8C72A7929075 +:10A310008DB05F95E42DFDCA3039481AFFDC01F796 +:10A320007E94CF9503E0D0AED24E72D2F7CAB9BDBB +:10A33000413C8FB03AB7B308F97CA293F65B9EC05C +:10A34000DF2733587BBA687F80D57B89FEF64FC400 +:10A350007A8AA8F3FEEE12F52DAC9E25BEDFCBEA7D +:10A36000B962FCF7D97866F67E69F7EF4D02FD43D6 +:10A37000F0F771DD95F7F2507E3FB1FBEDF34994B4 +:10A38000ED5C1E887B78CA7E302EFA3DA0E7460938 +:10A3900073DF2AD7EAD0BF7DD5D698177E1E59E441 +:10A3A0009FB84ACD4ED0F7AAF6F5DE21F37C1CD03B +:10A3B000377EC4E3CA65B209E311D737333EDF9570 +:10A3C000BEB678CD1B8AFDECD4CEEF49C6401D1D2C +:10A3D000EFDA134998DF4E7AFA310EBEBCBB24E2A5 +:10A3E000ED789E55E47BC5F7204EB04FE37F13C553 +:10A3F000EEA1BCE047FEBBF837CCDF5BF5CC119497 +:10A4000073F3653BE2F1F12CF70A804F9B99DD373E +:10A41000B878CD21A4D7B5995C4FB004FB86C3F3BF +:10A42000C1CEF0FFE11DE0FFC37F27FCD57E667142 +:10A430001E7AD937CC4B6B33B338A883EFD3798DE1 +:10A440007D0087D7D340E7D716F973AC32240DFBD4 +:10A450001359BED1BB4560075DAF35E3FD44B3562C +:10A460007D9C177E1E45946AFDFF73A0A38410BCDB +:10A470007675E7FA5E08BE2FDD01BE2FFD3BE19B3E +:10A48000A40DE81D10373DCBEE0B1BE03FAF0FCF07 +:10A490007339D99DC9DDD866162752E76B9DEC6EDE +:10A4A0006678C5E3315593DF1D06F118410F23A3EC +:10A4B0004923F8D7295E3B385E3B00AF05FE86E2B4 +:10A4C00032F4BB08F415C25FC2EC620E277F67BC92 +:10A4D0003D7D07B89EFE77C2B589EABF18C77C3DAF +:10A4E0000AFD276A38FF8DD3BB80B731EDF6703691 +:10A4F000A6FD6BE06C4CB32BF2D204BCBB924FEACE +:10A50000FD11F38E40A745DF864E1F4DE77C4A1BA9 +:10A51000C03C51F5BEC7A675DAF7B8B4DBEFBBB2E5 +:10A52000FD5FBCEF6AB8A9CB4A1EDF543FCF4FD3C3 +:10A53000FC4BE1F8FF9BFF7C76ED6145FBDC3527AA +:10A5400015EDF33C1F28EAC302FE524073E10F1FD2 +:10A55000712988FAE5B7F5AB77E54F9FF4DA120D6C +:10A56000C4DB06F9993FBF2DDDBD01F0EB7D8DB752 +:10A57000DE4CE13AF05C23BBA7AB2207F38756F130 +:10A58000397E39EC6F9F3C44F1E64B62407FA7EF88 +:10A59000F05D5A7B6E673C28BEA121CEB03CB46210 +:10A5A000A355EB447F0D7146C29BC7D318DE61FEF5 +:10A5B0000FA5F7E946A28BA7743E7DBA84F94ED366 +:10A5C00009CB87A6A5CF4DDB2769890FEE352E373E +:10A5D000697D068CF329CF2F1BF8BDC7243E4E7131 +:10A5E0008E5976CA98973675108B0F3E606AC47381 +:10A5F000A4334E3C7CED21DA4ED67B8A58BEB5386A +:10A600007FF607CD3789FB3D9E46989F5DE27164DA +:10A610004987F761A9BF9BCBD73B495E2743BE4B18 +:10A62000F003827AB7A03BBABE13860276BE027EE2 +:10A6300077A29CE87CBDF17CF3965278BFF2B41D02 +:10A64000E15233685D1EEC63CD28E953435EC8AE2A +:10A65000A959F317ECA74C7EA51EDEBF7E96B9C2A2 +:10A6600007B6523BC51EEEAF0CCC01BABC93FD231E +:10A67000E67DAECE87F8F449DD092CDF1FF14E11DF +:10A68000E819813A7F44BFE4B7F50F08BF80F013A3 +:10A69000083E20EEE17B3D8DF305A3D41DEF4FD3A3 +:10A6A000B252F0CB039DF9EB9B77E0AF6FFE3BF925 +:10A6B000EBD7C5F3CA642617D5F8ADC66B81CF704A +:10A6C0005F37FCDEC00354DF03B93A9378722B295D +:10A6D0009F9DBEA4413754FAF678BDCC74218344C3 +:10A6E0003867F2CDF9B91DF74D2E95D13E10F90915 +:10A6F000621FAEA775D233BF4A4BB8EDBE29DBFF50 +:10A70000ED7AFC8539DF4EAE11853E604DEFB4EE3B +:10A7100084F4DBAF5BD9FE2F5E77D8F99739B22688 +:10A7200074DE03F287218FB1DDCBCE33566435E082 +:10A730003DF164503006F4C6A50765C443A2756AAE +:10A7400053C2EE976A25BE0F011F970C5B82E7E0AC +:10A750003ADD0B656AC27371EAFBA144BE7035EF46 +:10A76000477D4F5435CF13AE56E5ED0C49E7E7086A +:10A770000B4801CBAF50EAA5EAB2AD8E28FC926D32 +:10A7800037EBD00F5092BEF7479EB4D03E8CEDBC55 +:10A790006F13EEB06F13FE9DFBA6C657D9BC13CF47 +:10A7A000437D537C2576E73C98B7E0C3B320878B85 +:10A7B0008E3BEB80C10BF7F98B7BADDB2576FF4C35 +:10A7C000FBA704FD4677BA1779F069379EE71CF8B6 +:10A7D000AE536679042CDF40E829426F19DA1A94E7 +:10A7E000D9FDF5FC1C14CF0BFABAFCCBE1B7A09E47 +:10A7F00023FC6FFF2CBFB590737B8C8C3E847FB0A5 +:10A8000030E0423DAE4DE72B827BE83DFBA322EAE0 +:10A81000013F4967FBD4D5BDAD4931EE9FA4433B11 +:10A82000E7EFE2FED63299DDD37CDD2FA3FF6EF594 +:10A830000F7FF7EB67ED77B6EB6B2CD723DA45A2EA +:10A84000ACD1B0731205A576CCDB037B09FC77C2D3 +:10A850009FA77EFF5066C9CE74F42F0DC3FB34AFA3 +:10A860006F65F3E96A5F6AD60471FC2EDBF9F8358F +:10A87000078B2CE1F7607C9E2E097CB65C3486F653 +:10A88000F5EBEEFFF0E074857EF3FFBADD3049A60C +:10A89000AA23958FB99297E9A784E9A9B3881FCB1A +:10A8A000392488A59BB07CFAF9C481E542E2C2D282 +:10A8B00095E9FE281DF35B8289980FB9EF1F7D0192 +:10A8C0006FAE8D18DA00B973FF2A3DAD3DDF8EE320 +:10A8D000B7BFFE8F0CC86BB913FDF78B71B6A647D7 +:10A8E0008827FF67B18CF11392BC12E9A19CDF921B +:10A8F0004046B1B8D88F12B3D83DF51DFC2F69BBC7 +:10A90000E07F106FCDFD54C3F243964A787F6B739E +:10A910004083A495BB28CB0BF7F13437B1F6DC2A82 +:10A92000AB57A2F5DCC151AC7D85D50BE71E669314 +:10A9300000D2E35C38F520C33918C6DFC43DE554C6 +:10A9400063CF063D6B518B91E5EF93404FE0E37988 +:10A950005DD8376333985DDC2F9BF1ED7E254A3F50 +:10A96000444C06E3035599254B3368B92AC3190BA8 +:10A97000653F9B7FD34F0BD12F8FBFA3F2C5E0075D +:10A98000317E28BE7B32B3241EDE7B5562F9E69E03 +:10A9900083FCF706483031FCFE505766696A061D95 +:10A9A0003F2B83303AEA02AEF07B73AE08F69CC8C8 +:10A9B00067EC073615FAC7D93D54AF4AAC5EF0BC18 +:10A9C000EDBEF57DD187EF01BDF6C94CF73D387F6F +:10A9D0003D212698FFCF0DDE1DA87FD666803F72F1 +:10A9E000C9F3060DE8051F51B10AE74AFE5867C4CE +:10A9F000F2636AE742F9276AE742F929B573A1FCD5 +:10AA00008CDAB9502EBAE12084F28FF7329CA3324F +:10AA10008A42F136F57C877378768C7F508FE357C6 +:10AA200065BA11BE1DFBBD9F78211EF2AA35986A3A +:10AA3000BB0DBE75CD673CDCDE8B9C9FD59FEF7B4D +:10AA40005E9316E5785E73206671D87B9333F4D8F5 +:10AA50009EFBFA053C1FDA66E980AF53A24B9EA429 +:10AA600061F5C9CFF741F856653A97C23E52FAFEF2 +:10AA70000E9479CDBFFB099CE7A1FD631E41BB1479 +:10AA80007C0AF57CD53AD47010EB7AD5EADF04DF86 +:10AA9000BFFA7A36AC84F21BC2E806F0488AB4DE0C +:10AAA0007508D7FB0CC14238A772DF2D3962DE7002 +:10AAB000556631C25927F04DC089EFD7B7A5EB8E47 +:10AAC0007836C75322EED700DE690739743306F4AF +:10AAD000BA721EAF6F6EEAF93EACCF734226BDEC80 +:10AAE00088BF0ABA7B8EEF8F28730FEA5DB04FAF35 +:10AAF0001EBCD813EE5BA5FBD213EE5FDD9CD14BE1 +:10AB000091DF943BF8EFDB7E1A8FEFE3EF7CCE20F2 +:10AB1000DBCB209F64A6F1F03158D26CCBA76590B7 +:10AB20004F3237593A0EE53C7BD668C82311F9EE0F +:10AB30000BFA141F07529AE028477DAC18984B98DF +:10AB40003C283546F3CB9F85FC8953D4C7247757DF +:10AB5000BC3FCEDE43D13EBECF3D8A7631EE0447C8 +:10AB60007FC57BFD6CC16CB0BFE83AD87DD7BB64B4 +:10AB7000CCBBCB7DFDF4BDF7D0FAA417A7E2FD7ED8 +:10AB8000AFF2F6497B4BF1F703DB293CF55491BA60 +:10AB900034E8B1A77E0A9DA9F4FBCA832F1C77DA9B +:10ABA0006FA3DFDF41AF17FC75798BB108F8EBD7E6 +:10ABB000D5F3D5FBB23F839F0BE47A7F57F8D241A0 +:10ABC0000F929DE10BBF674B8D2F9059CAF08F9567 +:10ABD000934EB17360DF948F7D0E7C2CEC1C664726 +:10ABE000A9F2B7F5D33BDE5F05FEF7F76482E7EA2B +:10ABF000F8F9BCC5F0FF7208CFC9C2ED8FC07D5215 +:10AC0000F4B907F44F3807EAA4FDFF3983EB4D95FB +:10AC1000871F49290CB593D59F2ADE276BA50D8A7E +:10AC2000FAFA2C657D73F186F0EFBBE2878BB7CE25 +:10AC3000D3BBF1FCA614F1F75AC57CCADE8AC2FC6C +:10AC4000BC899077421F55177EA085F8EAC42EE490 +:10AC5000A7E03B3364521BA9FD6606F3DF4F782B58 +:10AC60000AF359BE69BF1F515862BEE06F98FCFCE1 +:10AC700028D6AF0DDF774326EBFF5AD1961F7E050E +:10AC800071CFFD04F337AF5919DFCF6BFA42A3A19F +:10AC900065BF6E0C5FF22C010DC893F68A680FE455 +:10ACA000E7D72C35635E67BFECE087C67C42623332 +:10ACB00037FFD848F7ED0F7098314C9EB6838D431F +:10ACC000EBC9FFF138F2FBF16F45F934DF623DC9A2 +:10ACD000548742795DC2E87B0EE00D972BE03BAFD5 +:10ACE000798474C819E007B07EA84FCAFCF1FB4F05 +:10ACF000D2716B4E32FA864C39B5DD3E33CC6E27BD +:10AD0000CF31BA34D27FA0CF2D3BDAA0077BEECE75 +:10AD1000F4DD8879335F97AE0B3295F67B043A3ECB +:10AD2000359EEE4BCD7E76BFC4F5965E78AEB52BE4 +:10AD3000F95DB35583F427EA6D2DF258C057F5F944 +:10AD400070014F62C951DCE3B472F8DF26839C5C6A +:10AD50007950CB923DBA1A67A386D8C3C679F590CD +:10AD6000A182FD0E259B7FBB90CF07FF6A2BEECB08 +:10AD7000CA7511E41C95CBBA7890CBE5ECF715CEEB +:10AD80001C4C2A01F89F9188CF8EE7AE589EF1FDAA +:10AD9000AC3B786EC2FB4392FB68C3EF371476E49A +:10ADA000D483537B811EF961D3FC337467C8A2CC72 +:10ADB0001E38DE34E241BDF78CD5950EFE86493C47 +:10ADC000DE7FC61A6C057E7C6678B404F17BDAFF00 +:10ADD0007A12765FDF199D2B9DDD0321F28AEFFE4B +:10ADE00056F7B695C96B8BC743BC7A16B1801D79EF +:10ADF0009FCCF45AF226A34BC1EF6A24BF0DE6E9BB +:10AE0000CA9CFCFD4CFA5DD29A1FA15DD901372D79 +:10AE1000FF9DA6AFA9D776D8AFBB25763F8983E93A +:10AE2000FBD5C3AEFE6C1A9C73A376B644E733BF62 +:10AE3000F930DEC3A3B6AB3BEC9BFFA57FB4B37D7B +:10AE4000E4DA925914F27BABEDA40EBD5CE877BB5B +:10AE5000589EFB91E14FB72DA7F5D5BBA2118E9758 +:10AE60009F3778807F5FDE61407BE7B22D786E157B +:10AE7000D4F7E63A3C385A0E9EEF12F8BD4463FF11 +:10AE80003DC81DF25B1DDEB7F1C5CF0DF87B1E4B33 +:10AE90005FB86B07D84F5FA4DB5F7E05FC7B2F2775 +:10AEA000E07D0024997D3F91D323D0979DEE87FCD0 +:10AEB0000B33EA0D4B5F4B41FE25F6EFD2CFA3F0EB +:10AEC0001CFCE513F7C7821FAC55B387FD8EA46C3D +:10AED000F2001F5EBE230AF53EA277BF06EB2FFDF0 +:10AEE000C5C469FD61FCDF2510584F7BCB6BE87F43 +:10AEF0000CED6F64B97EBDA507E3031D7296E5CD29 +:10AF0000CE0DDDCBBC1FF0A78A887B1059DE6C818B +:10AF10002CB1DF957C22F239F0DF66F238A9F09788 +:10AF2000C4116332D0A19BB07B1F9FE88DF7EA9ECE +:10AF3000CFE4E79749909F7714F876AEFA00FA4B82 +:10AF40000C2C5FAF8B7B2D3FCC64E782171BFFA2DD +:10AF5000F09B54AFB9A1ACF765BFB35C506FEFBFC6 +:10AF60008296AB389CFF91E4FA08D6B7AC71CBBEA1 +:10AF700077112ECF7DEF0F30EE0913FA69C8BB0CA5 +:10AF80007E6AFB65B131C8E30EDB1571F58BCFFC32 +:10AF90001EF3472EBE7E0FFEBED87CD97F11EEC7B2 +:10AFA0006A33FB3F7988967B4F9CC27D51CFB75364 +:10AFB0001C5E627CA512D6D11FF2575CED9948B792 +:10AFC0008CDECF6FCA45F8093F6DFBE5C8F6959852 +:10AFD000A7E85FCC4FF42FDEFBEF4CA6DF5FD3FB7F +:10AFE000F3402EEF843844983E7F2DC69F073F756F +:10AFF000BB339DE5735FB3D17A18DEFC5F8A9C0C8E +:10B00000C3008000000000001F8B0800000000004B +:10B01000000BAD580D6C14D7119EB77BB777C67770 +:10B02000F6818D7FE21FF6CEC4187CF816FFD5B1ED +:10B030004D39FC832842CDF193D44A216C9A4028A3 +:10B04000C4F864438B92AAAC7B95F911515C358AA4 +:10B05000A04DAB83081455541817228A30BD04152F +:10B06000701BD1438914925A68EB36D46D0CE7D229 +:10B07000A42D6A2477E6ED1E77EB9FB4897A966F4C +:10B080003CEFCD9B37F3CDBC99F7DC01F8A906E87E +:10B0900070823D37176907532238D401A0C13C4E56 +:10B0A000632ACE3F5770016C35240C21671EC063A4 +:10B0B000607E72736C500FB091FE9671BCE1B7F771 +:10B0C0005916C01330608732809B42EF1E49041826 +:10B0D0001FF8A15D7591509BE7760500D33E1026C1 +:10B0E0002B0126E9B3623A05B001C9D16752A46FBA +:10B0F0000D603E7EB7404518F5DCF1B834210050B4 +:10B100002A331B972B811292C37925568B74D0A1B9 +:10B1100044D09E3D42C827E3BAE7A4581588A975D4 +:10B120007B04958F8FB3B7B7818FB68B5585DC00C5 +:10B1300089B912B06CA4F3957810F1D03E01E50402 +:10B14000EA49D8A16310F7AD6D15C283DC0FDBA807 +:10B150008EFB0AC0B87DB59538EE07584EE34ED346 +:10B160006E2F8E07ACF2297FACFC0559E0FED5E6C8 +:10B1700008E101FF743C36D07C1D40046222E18A64 +:10B180009F8D4EC4BDC9C41D202802C66597C9EF56 +:10B1900072BA626215DA9DE5D444F4A7E922C605C5 +:10B1A000F9265BEC4DA22C08B017E30BE7EDE30F9B +:10B1B000EC201C0A2A6DA4A7D10C2F435D9B50AE36 +:10B1C0008F8581F675423FA787589CDBF16598E033 +:10B1D00034081E1B51849FD3360871BA0AC29CAE34 +:10B1E000867E4ED7C000A76B21CE292C8945C04B47 +:10B1F0003B7DC7733B13C9579E152691D67E0DC262 +:10B2000003AEE938EC31719A1D078D513E7E5E1C0C +:10B2100056815AC0F54DC5A3B882E7F7543C1C943B +:10B220008F18B70C8816105D0EBA487405252EEAE3 +:10B230005909B28DF8560872BEFD7FC4A141576D01 +:10B24000AA7F063C5A67CE8BEF9A7921128675A9A0 +:10B25000389D9165CE27E305686768E9F43826C70D +:10B260006B335BFE2E7B008E46DB42B642E46B5AAC +:10B270007ACA90FF99BCD1E09B5A7EE143FE54F418 +:10B2800031830FB4D4D81580DEDEC7436D8F00A89C +:10B2900019595510A0C2512E50FEECF618F8ABBD4E +:10B2A0007B140F9E23B5C4A5907F4E076286F88954 +:10B2B000652234206D93D49765B4B37475BCCF40C8 +:10B2C000B825BF03CFEF78DC0E8770FD7EC990777D +:10B2D000E03A6775CA2F1CD732901F1CACEC61BED8 +:10B2E000D9F747FDC748BFDAFBB00664C739A67C6B +:10B2F000D63E3FCE574F923C38CB81E25EE434F4E9 +:10B300008C0F5656525CCE1048349FEBAD21DCFEBC +:10B31000921F3A43F209B7915F672807E7CF4EDFE4 +:10B320009783A7497EEA78E2433400D7BF25ABE78D +:10B3300068BE2BF3D372AA4B7797BDD3A77B537903 +:10B34000CA70FF4DE87724085189D79166CF6DAC5C +:10B35000A3803199C47826B6A21EC4A136A446ECB7 +:10B3600038FCA54D13F558A4486F8CEA5D97A49757 +:10B370002EC3752F6FB8251979566CE499598786B5 +:10B380002E0DBF5064B021483B575D97EEFFE3F7A9 +:10B39000885FD73D9742E2A9F374B407B248C86505 +:10B3A000A91BC973D678DE1113B3885FBC95E496E8 +:10B3B000BF3352467EAD18D1236ED233F45E916115 +:10B3C00087D91782FF645FA42FB48B549C01BACF36 +:10B3D000895107E2D5CDC297DDC4FF9C291ADAFF57 +:10B3E0006727E64736C9075D85E8D776D3AFCEE154 +:10B3F000137D6EA4DB5F7D7A2D54D171B0F3FA2DED +:10B40000E30F9DFF9DAFDB53F59C7F6320D0CF2ED4 +:10B41000487E6212E541E78055AE0B0EFF8DEA4E85 +:10B42000577A9D47BB2664772EC7DBEC57402D0427 +:10B43000F53D6BAE253F5C64F790147530A43FE991 +:10B44000513CC49BE7072E7E0FD2E5E1D51C1EFBC5 +:10B45000E479FAE601B43D278557E0A42348B8070C +:10B460004EE607C9BF80045B421CEF28CFE300E62D +:10B4700006C37C3A3D77C227E03EA7872A14ACA0DA +:10B4800070615F10FEB830655FB7799EDAC553AD65 +:10B4900012E6C1BD67C0834712BA875F8B3891EF50 +:10B4A0003E082401F7E80BF5DC1B13A2A4A771B832 +:10B4B000A680E27DD63C9F8E0201E4349C32E439C2 +:10B4C0002057A4F824BE0E333E9915F32CF36EE5F5 +:10B4D00021CBFAEC069F75BD168CFBEBA91E1BEB6E +:10B4E000E7069758E4F767ADBA4679B93CBE6D2DCB +:10B4F000E192B3BADA325F0F4E7E7FA82B762951E4 +:10B500005C0F1F1BFDBC017F783F80B048FE35E912 +:10B51000003FC278348EDB2C71CFD0311F512EE327 +:10B52000DDB4B8E3AF43B6F2CBBC661E1443717A08 +:10B530001EA470763DC091E7C1300A11CE6E298AF3 +:10B54000578E6938D5C3C26C9AAFBB264294E3DEEE +:10B55000A3C4707C7EC88A777E8715EF42D58A6F38 +:10B56000D1762BBE25612BBE0BF65AF1F46A56FC40 +:10B57000CA0E345AE41FEE6FB1F08B8EACB1C82FF7 +:10B580008EAEB7F095AF3F61915F3AF00DCB7CE0A6 +:10B59000FC0ECB7C32AFA6C67D59ACDB223735EE34 +:10B5A00035D79EB7E84DC659C39FFF679C774D8935 +:10B5B000F3F3681B9DBBEB596387E9187E35D3A86D +:10B5C0004BED62733C48F16EB62B14D3DFC939AD35 +:10B5D0006E3AEF661F0A997D08D43E1EF7909927B0 +:10B5E0004A5CB94C75B4FA66A8350BF95A3D7C999A +:10B5F000CA71FD587F6BB6CCD344F6A03C33717949 +:10B60000B48181CD725E90CF4BE1B641EB15B35161 +:10B61000B8E9D36884974B4A2ADC7FBD39CF1A8CAE +:10B62000BABE2E9801B6343C969BE3007E6E5FB3A3 +:10B6300031051BCCF700DECB41A27BB9E08C46BCC8 +:10B6400033DD27952322BF27A9FCDE7495A976A2B6 +:10B650001B9DF152EA5FC7F2D4235EACF377054538 +:10B66000E6F72CA647C8A90439C69BCE8D50D04F0B +:10B67000F777FCF321ACBBC2F590E6E7E67B74B448 +:10B680005F35ED39E1558F919E51E6E9ABC1B5D7F4 +:10B690001B3F2AA5FEE3101109AC8381ACE06B349B +:10B6A000AFED6F9ECBFB6A3EFA87755417647E7FC1 +:10B6B000D09E67FC3DF011297B24ED9C1EB0F3BEAB +:10B6C00003E6FB68B38957F27DB4C9DC7F14556C7F +:10B6D000C73ABDF9FC558ECBCE8271B0E5F07CE364 +:10B6E000F7A4A78B5DD587C8A7608DB27E298D276B +:10B6F000DF4B45E2E7E98BEDA23F5B9FE1BE98A4FB +:10B700003B0BC6F87BEEC1FA53461F995DBFC6FBE3 +:10B710006CCA6F43FFE8C14CDE5F460F96B4104D14 +:10B72000E9BFCBF56F0EDFB0E4C996BDEF5BF2EF7A +:10B7300029ED0F96793D77C25E84FEEB6F14AEFA69 +:10B740003AE277E79CA39EDE8D18B79BDEBA947E23 +:10B75000FDC5456DB4DF7FF7F3AF1CDF917D71B0A0 +:10B760002D4CF9796BDF4DCEEBFB744EA7FA997C2B +:10B770006726A9F41654D8303E136C8E72DC3B7DDC +:10B780009F2D3EE35D32B232AF85FAEC48896433D7 +:10B7900068B9C11736380D7ED56AA209BBEB00BD6A +:10B7A0003347180419E6C32616FAE953E8F70B796C +:10B7B000EA27947F5D3B26AA6C781EBA02FA930CA6 +:10B7C000E3593C57FD17F9CFF07A57388FDB594EC4 +:10B7D000F78E3141AB62580BAA7D85EB6C1897B19F +:10B7E00039DA5DEAC44B8EE71ABC649C8F46DF24CD +:10B7F0003F0FCD1E55F0A19E0F9918E3F9FC4B1693 +:10B800003DC1F34D97D6BBF979EAA07717BD77E92B +:10B81000BD91C83068868F71FFE64CA10B7D463D17 +:10B820006B3469BB78B89CD1FDE08803E83CE03E0E +:10B830004181F61972444F209F87B6D33DE5D792D8 +:10B84000719FAFFE95234675639BF3631EA7129FFE +:10B8500097EBC92DC3CA85EB725F724423649F1EA8 +:10B860002F5D87F6F5DBF1FE42EFE977711ECFDD44 +:10B870009D17171D3F94168F12330EF00C80319FC9 +:10B880007F8CE63B87476F511DB9E255BDE4FFA8A9 +:10B8900020D7531DE9CC7A53A2FA53E393F93AB473 +:10B8A00097FB8FF5E0FB8CE3ECF4FC09F3750B16CA +:10B8B0009B6C7ABF09EA625ADFE9D425D28719C1A5 +:10B8C000EF7FB3F97F676BFC153FD2BB6EA594F693 +:10B8D00049EE8B76D4909EA4DF493B527A3E3BAF33 +:10B8E000B739272CE7F7F6D1FDE5744E105F95ECDC +:10B8F000AF16D996F533AC7FDC8CDBBFF3432B7DE1 +:10B900004877847FF0C6DB726A3EC1FABFF501C595 +:10B910006BD8C5EBDC6CEBA7FAD9796998E3817E2B +:10B920003E49FEA5F9F928ED93F4F3CED07BAFF8AC +:10B93000E52FEE5FA2242E91DEC4B1FBA532AEEF5F +:10B94000BC78F526E54FA7F9CE87B3D6F7BB630ED3 +:10B95000BE13E7A5D573AA710BF8344BBF3F3992DC +:10B96000EB8B6DD6F578511670BFB3E6FBE13C9DCD +:10B97000DB19DE9967E3026F95670BF07E467D0069 +:10B98000FB2ED5FD64DFDD7D43E0F9B8DB0B7C9E4B +:10B99000ECA2FC67FA15DE0792FF478830EC6F983F +:10B9A00007DD92FA6DCA0F507B785F1017B814CA82 +:10B9B000E3C1DFAC31DF4B469FA933FB4A1DE921D0 +:10B9C000FBFDD9BCDFD49AFBD63BF11EE3A392ADBD +:10B9D00099FF2F31FFAF70F00A7F67FD0774153EA6 +:10B9E000C90014000000000000000000000000007A +:10B9F0001F8B080000000000000BFB51CFC0F003BC +:10BA00008AB7C9333098293130242A33309C01E277 +:10BA10002479841CADB02A0765FA5F303230BC024D +:10BA2000E23740FC8E9174FD3F8510EC87BC0C0C16 +:10BA3000BF80FC8D405A4C8081E12690FD1B88BF61 +:10BA400003F9E27C0C0CCA406C06E4BB00E93C2024 +:10BA5000F607E23F407E1B1F6EF3FF0AE1B7FFAA25 +:10BA6000002A9F571095FF911FBFFE0E41FCF2BCAC +:10BA700004ECC7864FA8911F1F3CEAB44F33D4C4CF +:10BA8000371950F9A7651818EECA323028C843F89C +:10BA9000D790E48D8062676420ECAD620C0C7BE58E +:10BAA00018182E336037771B507E1F50DE0E6A0E3B +:10BAB00000B5BC7B1E680300000000000000000011 +:10BAC0001F8B080000000000000BE57D0B7854D5AB +:10BAD000B5F03E73CE9957662693848484F09824FB +:10BAE000803C020E010248A893071425C008A868EC +:10BAF000110651088F3C44ED976BDBCBF04AD1D255 +:10BB000036D6B6D25ED401E15EA45803448D1A60E5 +:10BB1000806051C106EB03ABD600B6080219A0EA5B +:10BB200048F1F75F6BED7D92732633407BFBDFBFFF +:10BB3000DFFF8FB5DB7DCEDEFBECBDDE6BEDB577D9 +:10BB40005496CE581FC6BEC1DF8D8C3D2031868FE6 +:10BB5000B4127EFFEB9B0CC6A65AE1BF64C6C6CBEF +:10BB60000EC6463036C5C142166833A5081E766338 +:10BB7000ECCD4D5248C63ED02E58C8D822C67F5371 +:10BB800015D6245DCFD885D13BEB867918937C3EC2 +:10BB9000565B00A5C7CD666159B4F72BC9C558F2ED +:10BBA00068136303789F6FE0DF149F9DC6D2EA6934 +:10BBB00013530DF5747F0F43FBEE33730DEFB30298 +:10BBC000830CEFB32B0A0CF55E353718DAF7A92D85 +:10BBD00031D47382371BDAE7AD9966A8F7ABBFD3D0 +:10BBE000D0FEBA75771BDE0F0C2D32BC1FBC65A9C9 +:10BBF000A13EA4E12143FBEB9B5618DE0F0B3F62F5 +:10BC0000783FFCE0CF0CF591ADBF36B41F7574A33F +:10BC1000E1FD98B6AD86F7633FDD61A88F8BBC6C04 +:10BC2000687F63749FA15ECCDE30B42FB5FEC15037 +:10BC30001FEFFEC0D0FEDB99270CEF6FF27C667819 +:10BC4000AFD1C1A401170DCF277BFF66E8A7303F16 +:10BC5000009B3133ABA1D2CAEAA9B4B3062A1DAC0A +:10BC600095CAEFF60EDC49F4F964B08E01DDAD0C37 +:10BC700046FE9406E59BA3F39203F9389A8F31A010 +:10BC8000DB297C6836C5EA08CB4067162B0BDA80C7 +:10BC9000145C51A0B734A0BB28A3D21D057A1B0E9B +:10BCA0007417B552991A4DA5E769513795DDA23D34 +:10BCB000E8797A3493CA8C682E95DDA31E2A33A3C3 +:10BCC00083A8CC8A0EA0B247B480FA6547BD54F66B +:10BCD0008CDE40CF7B454753D93B5A42CFFB447D56 +:10BCE000547AA2375399139D48656E741AB5CB8B5D +:10BCF000FAA9EC1BBD939EF78BCEA4B27FF46E2AFB +:10BD0000AF8B06A81C105D44E5C068059583A24B67 +:10BD1000A9DFE0680D95F9D187E8F990682D954382 +:10BD2000A32BA8BC3E1AA4D21B7D84DA0D8BAEA136 +:10BD3000B220FA337A3E3C5A4FE588E8AFE9F9C8B9 +:10BD4000E83A2A0BA31BA91C150D51393ABA95CA1A +:10BD500031D12D54DE10DD41FDC6461BA82C8ABE14 +:10BD60004CCFC7459BA8FC16D25B1AD25D984A5FA0 +:10BD7000F4757A5E1C3D486549F42D7A5E1A6DA50E +:10BD8000B22CFA477A3E3E7A94CA09D1E3547E3BFC +:10BD9000DA46E5C4E8692A6F8A7E4AE5CDD10BD43C +:10BDA0006F5234426579F4123D9F1C8D52A9C93BF4 +:10BDB000365A3DD3A6D15F2EFEFF2CF75F06835C7B +:10BDC0006201D337503207D0C198CEF6B125483B37 +:10BDD00092932AD05512D0770AC8429487536AA406 +:10BDE000D0B773803EBAB5B5605D1D6DF158A07EC9 +:10BDF000178BA848BF1FB13627CAD3BD634EF66C58 +:10BE0000037A7D333DDC0B881B7F246F559C531ECA +:10BE1000CADB334A1B3C9FD26D5F7AC081FD8137FC +:10BE20000A90BCE1FB48DF408E38CE5D0A0BBA6059 +:10BE3000AA47708431D42E6C81FAAC72E62B80F65E +:10BE400075632C3343F09DBA027F851FCA1FE7F844 +:10BE50006762F93A320FCC7FBF288F3013953FEEDF +:10BE6000EDA672D67DFD383F950110B3AE0E87F476 +:10BE70000CDE8F3922BDFD43AEBD9FC2A0DFC8CE10 +:10BE8000F6CF30FF3BF83C58C206D4383ADBC1F35A +:10BE9000A3D82ECEF30FE23D6F308120007D154CEC +:10BEA000358736A37E629EE45B705E564FF2346740 +:10BEB000E2793DBC2C335FE9AB9F6788E6F7B0C4FD +:10BEC0006636D0F8BECC6943687CC27730D51ADAC2 +:10BED0009C43A830D0CB5F119ED02FDFEE6FA7F52B +:10BEE000413FBF13E1E3BE26B840BF2F089E0AF4CE +:10BEF0001B72EDFD1297F54CCCC343E389E7D516D1 +:10BF00001694004E91CDCED0C61C5C9387E4678515 +:10BF10005B08D06E000CD0EB15290842C65A762774 +:10BF2000854DD0BE68B37323DA01ED25C18CA90815 +:10BF3000878D2ADB0C4D56ECFED1BBFF01F5A20D1F +:10BF40002AB3407DE1C59F1732A0A3EB24897F3F30 +:10BF5000E8DBDB17C60F30EDE79370FC058C8FDF55 +:10BF60002E09B86E4E26BC7D5AB6A96E2C946DBBB8 +:10BF70002ACB19C8F19300D62CA0EF8576A660399C +:10BF8000AB66BB99E834A87ED2A6E917E267A5B3F1 +:10BF90002E77AD2FC0BAC6FFB0EE8521B5B30EFF28 +:10BFA0002EDE62ACEBE0457650E4BC12DA487495C4 +:10BFB000CDE1A3C1CB97CDE127E055765E099ABAD2 +:10BFC00011BC42280792250FC1A1E2BC1296619CC8 +:10BFD0000A8023B260C5AE8733104E8BB7D8DC9F82 +:10BFE000E8BE5BD99062A8573765B93FD1E9D10B5C +:10BFF000079F76E1FA97669ADC9F807C3BB3CC97EB +:10C00000F609A0ECDCB289546AF451D990E37618B1 +:10C01000C631D62FD44B131B487F7A92670C494CFC +:10C02000674B33CDEE4F80554F6FE1FAF6F432ABEC +:10C030001BBF736699DBCDBF9B49A506AF25B576BF +:10C040006AAFCD2FD1B8FFECF931D6C84E58519E0A +:10C05000C3BBBCC4ED13F293F25733F149B3FA05F5 +:10C06000D28D15FEFDC6447444756DDCEA06396850 +:10C07000B91E9F6F337C0FFA79FEA2D32F89F95630 +:10C08000617FD1D1E5FD3800F1A995F01C801193B5 +:10C0900061BC76C5B106EDA8C9827EAAB11DC88370 +:10C0A0004A6B9B39008FCE36727C24FACEE9655BF1 +:10C0B000B251AE5558EBCD28AC2A1A0696213F9DB9 +:10C0C0006D5C9981FA65B17CE1BBFE38FD7FACF116 +:10C0D0006D488D18F56548CC13C635F0197374ACEE +:10C0E0001BEA674CF02947D7711F97B8DEA9DA76AB +:10C0F00064C258987F55D37933CE63B214785C4AC2 +:10C10000EF5CBF84EB8771166D39467CFEA91AEC93 +:10C11000FFBD9C2BC0B3CB3C1D997F49D2CD2F08CE +:10C120008624F0EBDDA305BF32CFED1F007F9E7AA2 +:10C1300043658FC03CD8656805EF7B8BB7F730BF90 +:10C140000BE17577E362923FA750FEA01E66F5856E +:10C15000481F67996922AEEF2C7BCB355C07BF7D0A +:10C160009259C0074C59900716FA14C12D0BF5804F +:10C17000A5A2AE551E8ACF95A0904BD237244F4230 +:10C1800012E9890AFE3CC8ACCB691D6BB83C0AC2F7 +:10C190003F58BFB7DE289F16AC33D6E7B369190AFC +:10C1A000C897F93F576144906F7AF907F07B46E2F0 +:10C1B0007A7701ABA973C3FC9F30039E60FE77BB07 +:10C1C00099920DEBAB7CF189C2B9507F4DE27AECCC +:10C1D000F432987E7F182795AF7F516DC8ECCBEF76 +:10C1E000BABE138DC36F1BCB683C9293C1459AFEB8 +:10C1F000651EA590A42518B989D79FDD28FB6C2E54 +:10C200006C07CF75F279DE1AE3FAAEB6FED8F532D6 +:10C21000F633A2B7455B6E614867DA7A347C69EB26 +:10C2200051B748BE501C3E6813F4AAC9B588809F18 +:10C2300066777C1E53BF1453FF26A6AED1B72AF8EB +:10C240001BE8FE736924F2736402A79336AED744E9 +:10C250003B7367BB4B576A6711FC02EDBEB9523B9B +:10C260005BE7788A29BD6BBBCA179F7D2108F4BDA7 +:10C27000E8B95FB818D0E329A53EC30BCF976C5E31 +:10C28000ED42387DAA045D4837A742F2C478F01A1F +:10C290006392347BC32101DEAB34FA2F5A3E05F59D +:10C2A000FB179B55F7238097EA2D96B005F05DD5D7 +:10C2B000B8B09C0DA5FA315EFFE179A48FEA26F5AE +:10C2C000B81EAF8BFEEB17191E27E121DB84363039 +:10C2D0000B673328AB36FD7902DAD1D52C42F41C3A +:10C2E000DB0FBF8FAE1DC8EBB9E6E4AEEF35BFB1D3 +:10C2F0009A3F62D58D3F3A8F7E6335538EEBE9A826 +:10C30000026919ECBC41266737F417D828360AE5CC +:10C310008A0607164A27B9BCF299C7871E83799CFB +:10C32000D9F4864BD2C1072C2482CB8586791FA7EE +:10C330005D412F9C03FA64FDF5FD42D4CFD3041375 +:10C34000E80ED5665E2E51C3AEB100CF251B542F2B +:10C3500050265BF2ECD3FFF96BE03BF6BEC5DB0F7A +:10C36000E0BDF8D903EFDE00F5C5DBD56EE57C193D +:10C370000E29A3131FD5F02FC66534F82FDA79C024 +:10C38000EC19C29F7F3FB5130F8BB7EF35B3215D1B +:10C39000E156DAB0D7DCE688838F866313D09E59E6 +:10C3A000F9CC9766C4F7A9DD12EB9ED3B57FC5869D +:10C3B0000364BF209C087F023F1DF8EA82A7F09427 +:10C3C0009747503B37CAEB447872A2AE1E4974FCC3 +:10C3D000DB97E1FB157FB47871FD15BFBDDF85EB01 +:10C3E00038A9D4707A7E6275860FBE5BA10633DCF5 +:10C3F00054F2E7154F3E4874B6E0C8836497017D58 +:10C400006499486704B3707DF7AEBF95D6379F0532 +:10C4100088DE2A9E90FD2194030A9BB83D0E3F3C86 +:10C4200027F8E1E4469094B0BE93281FD1CE7D4B0F +:10C4300016F2F13EB2231F146B054B86EA9F5B395F +:10C440009EEA4C262D2E6735D0E9A61F921C3DDDB5 +:10C45000CBD7DD9D4F70D0E426C953F9C8F8EE1C48 +:10C460003F5CFE523FA0BB527C8EED5B559F6DA89A +:10C47000A19F9097FCFB0F88EFC3BCED687F9CCC1D +:10C48000E07A22767D7F3469F211F4AB8EBE747C43 +:10C49000CDF97CD3C39CAF353E0FDD3211DFFFF504 +:10C4A0006DCE3FD80FF50FCC2BDC9DDEEF9D21919B +:10C4B0001CB0B0703C7EDEA40A7E36BE07094DF685 +:10C4C0001BCC5B9192F57402E3A712FCC92E99FF75 +:10C4D00073E8A7B3A7ABF17BD4CEDCF93CA7936F8D +:10C4E0001708FEDF8AFC9FD4C9FF6C7DFA35F96717 +:10C4F0004BD4D07FFE1AF915F833E8417E55FDB8CC +:10C50000EECFB6ED7FF74EA0EBCF1A343E35CACD55 +:10C51000583EADD8F12043FA8CE5D3CF7AD6B0B8E7 +:10C520007C0ACFE3F269CFB6FF11B9A9C1ED480C7F +:10C53000DC400E3EF5B22731FC62E560B5C9135709 +:10C540000EC2EF6D56D895EE347AD3E86CD16F2ACF +:10C55000FBA0BCE9A0478DDE3AE851A3B7D8751A15 +:10C56000E116FB7E3DCA1B9D7DA0AE604127E039F0 +:10C57000B24B263FB1DD1371A5C27757DBD81CB48F +:10C58000B3DBDDA29EC2EB9174731DCA05ED79C4C5 +:10C59000C6E30DEDFE882B45673F1F6B965D1E7849 +:10C5A000DF166213E3D9D52071E9FB6D2CD1FBE5D1 +:10C5B00004BFF1B2A377ED08F4AB642FDA6EF72C69 +:10C5C000BFDD85218BF6E6BCA933E1F9BDAFC91407 +:10C5D000D368B7BB86E2BCC06F57B200BEF3049EFF +:10C5E0003F65C15F16C1BAE63573BBF89EB54678A4 +:10C5F000CC773C60463903F667271DE8E845DB2722 +:10C60000A8586F7CBF88AD257C2D8AA19F80F077CC +:10C61000B264413FC3D830E16F9870BCA5424E8DE3 +:10C6200097F3A7CE04B8B71F949905EA179A6556F1 +:10C6300087EBDC268518F271309DE8B00AE403D35D +:10C64000F9856790CECC89F9F7CCF31F157E0F9A48 +:10C650002C79E183A1FF01E59917DEEFFF0AD65F90 +:10C660007CAFF707AC6BFBD2DD5FCD46F9DEBEDBFE +:10C67000C2284EB2FB77BDBF87F5972D5E8A73AC9B +:10C68000B0F0F8D46E67A81FBEEF05F8467DB9EB91 +:10C69000CBA16DA46F56119ECA64EE475C68FEDBA9 +:10C6A0009FA46E58C2AA508FEE4E22FBBAFA655B69 +:10C6B000089DCEF65D5F16061CFFBCF554995980A7 +:10C6C000E8CFC966EE407A4D01C4C1F7AB5F19F3FC +:10C6D000F472F87E65E35EF33C785FBAE7EBA1287D +:10C6E00057DA7770FBE09CDAF624F3323655FEC554 +:10C6F0007215F0750E6DB51E2097E4778B838E78DA +:10C7000070E170680738E0BA002E15280F13C16376 +:10C71000FEBF2C3CCECFC6EF2F691EC5E41C3D5C8E +:10C72000241F7FEE0C59255A3F7FBEFBCBA12877F3 +:10C730003F6B584EFAFB6AEB5E8DEB4EFF7F69DD77 +:10C7400052F85AD6BDE95F76DD9CFE07C95C1FC56D +:10C75000F241573A7FF1BB54FFADD34BF3BD46FED8 +:10C760006FF9975DFF3F88F71D12EDC75D0DEF274D +:10C77000FE65D77D35BCBF26F0EE7463BCB77DD7B0 +:10C78000D7BD996EFD575BB749F957956F575EB79F +:10C7900066F7B49A6ADC23607EEFB3FA5B73A0FCA1 +:10C7A000BDEF623774478107FCF1FC860285FB0D03 +:10C7B000168C3361C35B252D5ED46AD8C7ED594111 +:10C7C00076C614DF8FC93E604A4D6B31B46F2D9928 +:10C7D000E77D845A141C0D607DC6385137FA536FBB +:10C7E0004ACC27811D3BA564D241B4EFA6FA64B2BE +:10C7F000FFA024BBEF9DDE13F8F3D1463FE28E1875 +:10C800003FE0F699C6F7B78AF16E634BDD23005E11 +:10C81000B7F554DC2100D11DC5352AAEE78EBB2407 +:10C8200056AF8B57DE1A339E4B61224EF28FC1EF0B +:10C830009E0EF82D2578B062D9BB995D03FC188750 +:10C8400077EB8C61218CC330C5CBE1775BA597E298 +:10C85000A0C2CF54457FD5B1A615F9566546FF5203 +:10C86000F31313C19909BF93C6C9ED84BBEA93C9F9 +:10C87000EFD48D47F0D0F0F1F7E241C3DF7F171F0F +:10C8800085888F38FB670BADD65B71FFC23A4022BB +:10C89000BF7DEA5A99F260ACF912C1D13F5AA5FDA9 +:10C8A0009D3F9BFC856838970F1F55F5101FD68B51 +:10C8B000F05928E0389FD590DDC92E7FF34D11EE59 +:10C8C0001B1184E0BD8FB1C9E087CC2F92C276588E +:10C8D000FF028505930B30AE29B1E3FAB866C8585C +:10C8E000C7DFB7323AC7B95AFB44F2E19F5D7E0C0D +:10C8F000F2E8785FF057B054E8F38ADE4F9CD3CC6F +:10C90000E158BD440AE5121D8555BF6E5FE77D41C4 +:10C91000D71F7F7F38C9B9E29F0E4926FFD53788D8 +:10C92000ECFD6A61EF5F087A92315E73A1392F19CD +:10C93000E331170E96BAF472512B8F083FF20FCBEA +:10C94000AC54B69749F532FA5B2C3285F470998D68 +:10C95000A1DC89EDF792A2C55D6ACC1497879F5C34 +:10C960008878E4BF05D035395587B7B5934F29434B +:10C97000BBE2017FC775FB24FF5DF8A2DF8A703D33 +:10C98000626B9BE08FB3DE3704FCCAF77D65C63867 +:10C99000C1B4E61C15E132AD4C36E4DDEC57843F02 +:10C9A000359C0DC77995EFBBC93506F17250F6DAA3 +:10C9B00000BED5CDE7CD8138FB6DB1F0C4F1312E8D +:10C9C0007C42F5CE47789EF8B18D05811F0E8BFD18 +:10C9D0001F78E543F90543F9303EF6B6C2F7150670 +:10C9E000AA3C2E3EBDBC584D87EFE637BA87A18AD8 +:10C9F000E921DA0F543DF43E5BF4D3DAF558C2DB9B +:10CA00001D33BBABE2AD7FB299AF7F01F37E77B44C +:10CA1000F4AF87B7E29F3AC325A8DFCB2492235D0A +:10CA2000E99A117F5C98288550FFA21F4BF5728907 +:10CA3000F4FF612DFF601AD7971ADDC7C25952392A +:10CA40009CB5EFE7A89C9ECD2A878F06670DBEB1E7 +:10CA5000F3D5DA83BCBA511F5F99DA34ECB7689F1B +:10CA600054354B6E0CFD55296D66E4C3EAA6475557 +:10CA7000DC2FB8C3C3C7658A7FA87EBF76A0AAD0C3 +:10CA80007CF6178C25FBF1E25A6E1FFBEE39EF4264 +:10CA90003BE8B0C9FBFBB1C88F6FCA944F90088EBA +:10CAA0001F2CDB32A34CD18F9B43F39CBEA458C5F3 +:10CAB00070D07796EC55BBEBE869A09A4AEFB5E7E2 +:10CAC0003D96780AF0397C8FE611FC8985611E4716 +:10CAD0007E436B4912BCFF4E4D0AA7C38A86BD66D2 +:10CAE000AAE7507BED7BDA7762F969467992A13E3D +:10CAF000AFB4AD27C2A5DC127EC01B874E5B546D60 +:10CB00009FE4EFD4133EA0DBA1FF3FE889F3137C41 +:10CB100071E0F698DA453F748FA71F962EF7744799 +:10CB2000F82FDD95D71D9963E96BE333E2E9877749 +:10CB300096F1FDC0F7409E61D93E03F4C3F53AFD7E +:10CB400030C346F411DBEF07EA35EA070D5FFFC398 +:10CB500072E61DD40F71F8BA5E35EA87DB9AE79268 +:10CB60007EB86D86CC3CBA78DC0F55B1CF95503F7E +:10CB70001467DC4175D59B14876EDE117E09C215E2 +:10CB80004BFC0EEA893D42EEC7EA8B44F27C9A598F +:10CB900012FBD55791E7FF97E0ACC9F3A5E0BFA022 +:10CBA0001DD8950E19C9EBA577803C97901EB93C0E +:10CBB0005F7A97884BC6C8573FCAD7117AF9CAFB24 +:10CBC0005705B83EA86ECA797C16BCBFB35EF55A4D +:10CBD000A1FD9D9DF2B6502F6FF708790B70EEED19 +:10CBE0008E83DF99B39298C728AFFAA29C3A31ECB2 +:10CBF00077F93B91EE0FCBB48FF867A1C70F0DFB10 +:10CC0000DD088C9F77332B443F7F16F2EBDCB2D0EC +:10CC10008C32E0E3D27BB83D5CB94D263854357296 +:10CC20003BAFAAAF3DE481FA8482AF683F70F12E3A +:10CC3000BE1F08802A2FD6E171F1E1B6BA6C7CBF25 +:10CC400041A2FDCCF9DEC514C767EB789CD80AFF7A +:10CC5000F0BC0E1FC5912B05BC16366FA078F3C231 +:10CC600090310E5DD9F7E653E80F68F277F19698A8 +:10CC7000F7DE8769BFA212E3CD3A3F4416F6C3BD83 +:10CC800072387F27E676FE9EFB55B1F8D7DA75AC91 +:10CC9000BFE2BFB9FE23B0FE11FFFCF55FEBBA5552 +:10CCA000B3E0F7023602F9E3CF261FF17BF07558A7 +:10CCB0003F7CE79E47FB75D7E719A509BE3C6C0A88 +:10CCC000D46561BB2A89DA2D58BFFD4006D467358B +:10CCD000B06118A65FB0CEA8173BF470A387F4EC40 +:10CCE000AC9AEDD2DDF9086F56837436AFC012C02E +:10CCF000FDD423B608C92F8DEEC699393D8F15DFB7 +:10CD00003DD12352467E4493E426BE08DBB85F0142 +:10CD1000F0B7417DFF982F270878533CA6BA89E3E6 +:10CD2000A71AF0817C35A159D4B7703BEC3BA06FBA +:10CD3000683FAC79AF8AFD2AA07D1AC99B41867DE8 +:10CD40002EDC9F2BCED0E16DD7314EB79B252F8B9C +:10CD500083B701F04F5CBCFD93E85583C738B3B08F +:10CD6000E705FE8ED85ACB87D33E94E4DD888D9BB1 +:10CD700053681FE593FA3CC2E32441BFB1748DF6BA +:10CD8000BD47174FBA05270EF2954DB4519E1B7D36 +:10CD90003797DB3F7A7912EB3757B356B263264B9E +:10CDA000818F145D5EDB6D22FF44DBA7D5B57B5C14 +:10CDB000BD423B96E936A19CBC5FCBB7C4FCE10CFD +:10CDC000CA5BA2DFFE5E85EFCD82F55E5C237B71E0 +:10CDD000FFE77693E7DD22E4DF4754867479F1902C +:10CDE000EAE3766712C9DDB9874FA8180A990B30B4 +:10CDF000417CCFFD0197AF27703078F647D05B3E7E +:10CE0000DCAB670D23317F788677EF780FE0E5D6CE +:10CE1000114756E33EDCF452F7BBEF227C1F961914 +:10CE2000C2F7F89A52F24FEEBF4F22BA3E0A70C4D0 +:10CE3000FEB7CEC879F75DF8EE5D6BD2695F6D968F +:10CE4000EFC078A4B379539D0EDC5F9B344066013C +:10CE50001D1CEF62ADAB515ECFAAB9EF569C6F05BA +:10CE6000E8018CB356341F19DF1DEBEB25AF07C665 +:10CE7000AF0E06CCDD0185ADEBCE9B31DE311FDA86 +:10CE8000217AAAD7F376D59B24AF0DE9B1F9519257 +:10CE90003BF33749CC8DEDC1DEB3F271435618B781 +:10CEA000753DF487FA02EC8FE36E4AB90DF7D1AA0B +:10CEB0000FC9BCFFE8E5AFA25C9A0FFDE0356BDD62 +:10CEC000741F8DB770BDC43261BC8AD1393F198DD2 +:10CED000E31D52BDF8FEBDBDBF32E3BC67C3F7B270 +:10CEE00060FC7972DB786CCFBE27B93753BC89E719 +:10CEF000C9B60B3E606F6771FE92445DD8819A3E61 +:10CF0000FC833997E8697EEDF23A5C575B303D0768 +:10CF10005DA0EAA6F366B4EB3E013807C06E3B2184 +:10CF2000F2D8F6074F98DB74722A62CEA3FEF7346C +:10CF300015137FDFCBFCB4DF1D58CEF5F0B1D5B6AD +:10CF40009084F687EA263DB97FF575BFC4F59F7BCF +:10CF500056A5FDD173BDDA281E7B72BDCA8230C7CB +:10CF600095EB65921B27B7F13890FC844AF5050FC5 +:10CF70009AA9BE7FFDF409280F4F02FC910E4B9F2A +:10CF8000186FC6FA0290EB9638F263BE67119717D6 +:10CF900031F261C13A23FF7791170F4CE0F23D4621 +:10CFA0001E54F6ACA3385FAC9CA8660E4D3E1460D0 +:10CFB000BD359C45F45B75486568CF5529EED9EBC6 +:10CFC000906E66D970A718F8227C00E5DAC590E467 +:10CFD00009C2FBEFCC796924C2EF2F086FE48BB54F +:10CFE00069B49F3A3F3497E0AAE5132E5867A467C7 +:10CFF0002D7FE98E80CC7C7A3D5091C47CBA76EF4F +:10D00000FD00E812BE37A7490AD924AC1F7BF5C141 +:10D01000115477231D56D50A7DBAD64974FBDEBF5D +:10D020009D5F8D7439FBFB12CD9F050375A857AA30 +:10D03000D6491E8C632EF83EEFBF00FA23BDBCF725 +:10D040002B4E3F40C71EA4F3AAF58FBE4AED3749C9 +:10D050001E1CFFBD0D7349FF56046546EF371D23A7 +:10D06000FB18F400E501ED0FCA1948E755AB2C6E2B +:10D07000C4A3462F1AFD1D53C53901AB77E874E8E8 +:10D08000B7C1ECA175C7D29D3C3387E8AB7A9B4A08 +:10D09000F4511DE4F474EC5999E870FFEADB897EE1 +:10D0A000CE6D9612D05FA9390BE92FC4DF77D0DFA0 +:10D0B0003392A03F4ED7271FE0F4588AEF91FE9E8F +:10D0C00017F629630EBDDDA1D19F464F57A3BB2E96 +:10D0D0007A2901BD816D7C1BCEEBFED5369A77692E +:10D0E000DD4BB7D512DFA8B43F5F5AF76F19C8A759 +:10D0F000F3159E87A1C1B152E1793A5DE6F1F3E5FE +:10D10000E6AC6B994FCC3CF676EAC502D48B9857C7 +:10D110001286EFFC6EDBD394BF7676EB31CA4B5CA4 +:10D12000FC0AE01DDA9FDBE66461B2A743245F16C8 +:10D1300035CA9417CA9470E174DDF9112DDF62F1DC +:10D14000734E82EFA21D965039F45FF4C289A1B4E8 +:10D150001FBE22F22AF24F70ABC4E3F2C1B6A1D3D4 +:10D1600031AF52E1791FB17A778C85C76BCEBC9411 +:10D170003413ED1F69CB5EDA4F5AD470BB6AD1C548 +:10D1800027BD1695BE0BED689F260878C77D449C89 +:10D19000DF2D43F4F35BCEC77B86F3CDA22695EC5F +:10D1A000A2455B36505CAF7ACB79CA7B2D7DEE59B8 +:10D1B00017C2A1BA4936E6436D91C316CAD7928FFA +:10D1C00059B87C32E4255535F27319550D22EF27F5 +:10D1D000262F66F173BB5E08026816EFFC2F17F26C +:10D1E000D1E9D6CD2E84278C47F944534727C83739 +:10D1F000BA5A9E51C3C371F38C4EE37F0081CCB603 +:10D2000018F333D9162EA700EB85FE38F14CCD5E0E +:10D2100059FCECE74F62DEEB991D9F3D89F35EF20E +:10D22000BF2E3E89791B6CB7CD8DF643F5D6772896 +:10D230007F50EB576B11FECF33FF457997E7DEB791 +:10D2400090FD776ED7C9DE681F9CDBFE5506E6535E +:10D250003EB06B3CC51F1E78BEB43B8BE3DF6A2536 +:10D26000D265E81AF23E63F1B0BF510E3B609E6793 +:10D270008F5A88BF3BF2C51A2A79FE9D47E4896D13 +:10D280008B9F57ABE53755354E9F3A0EE55B23D75D +:10D29000E31DF94E57CB0F7B1BF079FD35E06D9BFD +:10D2A000C8FF8BC1DB59FC0FC0CF2F2CC6FCB0CF01 +:10D2B0001BEF7DEAD7F8AE31FE79328D8FAF062FA6 +:10D2C0002D6F779EC517B220DFECF80DE5E121BE8A +:10D2D000CA3DA8E73FEF8D71CB4FD508C50323BBEF +:10D2E0002C6ECCDB5AB4EB3DE28F73CF1FA1BC5840 +:10D2F00026F267CFB18E1FCF77143189EA4D4E9E4B +:10D300005726E08E79671E173D17F9659C6EB5BCF0 +:10D31000B344F966EF5872C5B90B9E1757E96935E2 +:10D3200023FCF57968D268C4D33143FE9EB6EED8AB +:10D33000F1DC088751FABCC944F97CC21EEFC01366 +:10D3400097C3E736883CCA8EFC48C67A1660BE0F83 +:10D35000D777D521E93D16871FB5BCC9D6587E0CB5 +:10D360005D5BBEE4D5E7FB8FC163BF85C79F34B863 +:10D370009CB91C5F1E7F26F81BFC92D316DDB99466 +:10D3800039C22FD1F2C8B4F9D63570BD7B660BB760 +:10D390000B63F9B94AC4DB63BFF395F84E55D3DE8E +:10D3A000A12877CEEC7B49D01BA7E7AA6DC7CC415B +:10D3B000219F437AF98CE3C59127B2958F077E6C44 +:10D3C000DCF1AAB79D8F3BDE69C5773BCEFF742B9E +:10D3D000B7334E37C8134371C63F2BF44FC7BA9DBE +:10D3E00066F2AB64979DE4CF03CED14793BB6169EE +:10D3F000A6FC8595CB45BEC30FBC9908E795CE9B8F +:10D4000019CE6735C247E767AAEE00433B47CDF424 +:10D410008F40FF499BAFF6DEDCCDC4427AFC2BC1C6 +:10D420009E18779D92FBA582FAA57599F15C47AB92 +:10D43000E23E9006E3B596495EB467BBD29971FCB3 +:10D440005B7CB2211E86B1675CD705AF89F0E934F9 +:10D4500085DDD084396DAD99E4C8799847C9A09429 +:10D460006EDADF7E64D9965E78CECAC5BC12BE770E +:10D470007A3BCEB7D078C92C36CF9ABDDDB790892C +:10D4800023C0F8DEBD17E312F6016C009EDF713396 +:10D49000BB17EF57784C9C7B5CEB0C90BE4DC837AC +:10D4A0005E7EEE458B13258F560CE762527CC67A62 +:10D4B0005ACC39484D5ED3113A80FF0471EF43CA0C +:10D4C00078BE7E8C57F5CBE89C6F4A3AF386F1FD27 +:10D4D0006407E5333B1C7C7EDA7C613E240F004C04 +:10D4E0007C3EF96D41B4C3615E317CCCE8DC13CC89 +:10D4F000EF78CCFC0C76DC1D56A11F14A6A01C7185 +:10D50000585B9980F305639E699061DE4172075C08 +:10D51000E13D8C93234DB560DE821BBDE03CFA5E9D +:10D520004CBF9E6EFD79B1EB85DE28CA64F974AEFE +:10D53000B0B91BC9ADDCDA127602EA523DA78FBE44 +:10D540006B19D17DDF88C8635965277B4CBB774059 +:10D550005258502DE8A43780C80A3C17AAAC019A4B +:10D56000817ECD9112D3BD00D4067C05E3DF6BF53F +:10D570003D68857675B704324DC37039C5AB5A8A9C +:10D58000E814EF408C309996FB5A0EF62251C3D81E +:10D590000DF8DED782B45AAFD54120E27D0BF5F607 +:10D5A0008EBACF0A72B23E97D757AEF1AD5A03E3A7 +:10D5B000C94EFF4A2BF2B1D53D88F62FC2D776EE81 +:10D5C0005D9BE7804DE1523B4CE2E6080014F0DF42 +:10D5D0000F7990ECE4563312C96687560F931DED10 +:10D5E0006F3C427E7965C3117A6FC23A947DD2C294 +:10D5F000A5D9B0CE8DD65BCA3207C2788D73334DB4 +:10D6000020A27F63BDA54549D7C3E156031C9415ED +:10D61000D35B0E8ED3C3617A0BEAEB6B85C36FD6F7 +:10D620004C5FB5A6E7B5AF3BCBE6DF8A7899546C83 +:10D63000223935EAA883FC35F8D9283E25C6D99089 +:10D64000E0DCA3668F6BED343A4A442779CC3D8801 +:10D65000EB1723BDD4637E37C6EF02016FD9F04EBE +:10D660003A65EEC0703C9F9E65BB3B6CD5C5F52608 +:10D67000152F9573613E943303CFD36B83B6FE4071 +:10D68000A7E93E13E52367D90207705DAE99913093 +:10D69000E6EA8C6281FBA5BC4E7AD7BE53B78BFB02 +:10D6A000A975734DA115240FDA245C7727DEDB62A0 +:10D6B000F01EE1786F3A4678AF6A3EC6F1DEB4BC40 +:10D6C000C42EF637D00FAC67916188CF0FD6549631 +:10D6D0002940D77D922275480F2A5B5C566E23B88D +:10D6E000BF8FEBE90277313F0DFE89F0567F30F7AF +:10D6F00047F9E8271D32D17E8606AF8E76369E77B3 +:10D70000B7C71EF80B7EA77A74DBAB28DE771C7CCC +:10D710008BF6D55D87A6EDC5FEAE1980094FE7777C +:10D72000EB0FAD2841FAAF8F50580DE44C248876AA +:10D7300047627870BEE88047E331828F09EBF07C66 +:10D74000AB389752D424F950EFF64902BB04CAAF64 +:10D75000ACDC2F74DA645A8FD3C6F57BFAA17D3224 +:10D76000FA1945AB4CD43E1DCB7CFDFA57897E8A15 +:10D7700021CF4CC3A74647403849B7C09CC72407B0 +:10D78000CCB6917ABA494DCA85F7A35AEEBE1FF5B9 +:10D790009BD6EF27CB98F71EDDF972A09F13067A70 +:10D7A0001BA2DA106E5A7BA44B7F9C7B17A05F37BD +:10D7B0005B3AFF0EC655B7B72C95E99CE235E2B54A +:10D7C000D0C26A70FE8549AC6607F42F4C8612EB16 +:10D7D00069A2DE5DD4B345D9473C1FCCEB791F7AF3 +:10D7E0004D9203E3343C6E38D426F67315F720E4EB +:10D7F000A3A1361E1F2FCAB493FCD7F8550170E2BF +:10D800007EA322F61D7323B926C4A3C6BF4AC4143F +:10D8100076821ECC553C26DC7F7E7D19C041492C8A +:10D820005F6E1EC8CF8FC53E1F6B3319CE83FB3A88 +:10D83000CF778E453C555ADB7E320DDE560DBC4807 +:10D84000FB3F2B92AAC65EE91C78EC3C5EBFFCBB9A +:10D8500024A4AFE6A825EE799107C4FA0F2E9B49C0 +:10D86000FD1ED6CE8308BBE55B249AA0ECCBE34734 +:10D870008596A0928AFA2F89C73B0A93B87E64DD09 +:10D8800073E89E8C42EC8BC2FABA4194B752981658 +:10D890002AA7FAE03CC6F33E75F98516D6615F11FA +:10D8A000CA73119F819578AE86C93934FE8DCC68D4 +:10D8B0004F1566D7ECA7F7961CDA8762516EDF68C2 +:10D8C000F6D078B1BF52D8A7BE8CE699CCC72966EE +:10D8D000C6F3C385D70515BCE782E5E5D0BC4AADE4 +:10D8E00031EF07F3FB45B4758CEF6247D57BF19EB2 +:10D8F000914903E67ACBC4F38BF06F1F0B9B734BFC +:10D900007EA77CBFC97387B7CC607FD47B910FDFC4 +:10D91000F85A9E136F1FFCB0E0FB83CBFC5EDC6FFC +:10D920007CCE06F800BFBBC423AD727AAE0EBF58E2 +:10D93000BCC5C2EF5BCDF3C97E8B855BF187DEB2E0 +:10D94000544F5738C5C2653CAB1F40F7D70838C79E +:10D95000C2E5752BA787D7F32D21F42F5E5700CE94 +:10D9600080AFD73D12F91B85E27E0D20724E2F1A33 +:10D97000FD24E5707A4936C23D16BEB1F0D4E4C04C +:10D98000AB082FCA2FF1958FCFE85C7F61F79A968D +:10D99000141DBD68EB2FCC1674BAA73F9F8726379E +:10D9A000AE137244C80FCD5E1E2FC6037B99ECE107 +:10D9B000D27427C5654B2BF938A5FD1C1B31BF81DF +:10D9C000856FA47CD942267E516EDF823DCAE9B3C1 +:10D9D00079C229F4AFFB5802AB9C18879052685F5C +:10D9E00009E07E3C06EEC78D7037DAC9B170780E5B +:10D9F000FF634C577869F4D6621376750FD613ED32 +:10DA0000DEA12F8D4846F9CD9A53E3FAE9A38EFAA9 +:10DA10003BC611744B7429B140C77337D041D380D2 +:10DA2000D58FA13933D65A2F23FD8D65BE34BCCF97 +:10DA3000049364719EDABC864BFE77509E8D699B81 +:10DA400098A6BFDF44FBBE06E77102CEE358702FF5 +:10DA5000C651C631E5AFFA788336DE9F6C22DE9080 +:10DA6000CDB2713D45B83990DE399EB6BE3E792CB7 +:10DA70004CF7DF48563AA707FF0B9A533BBFA7E581 +:10DA80003F4F724EFBD44672B886F13C9F3021B1B5 +:10DA900048BC2F12F78CB18892E85E29F64D52E708 +:10DAA000FCBEB0490ADD9321E677768B3588F946CE +:10DAB0000F49814BF89D33D2A1A1C4AF4AB83FDDD5 +:10DAC0003311F3FE62534B15BE8776F3A99D58D7E9 +:10DAD0006299C77923BB2C749F4F42FBD30AAA4B90 +:10DAE00027078AEC5C8E8CC7785F1EC90B05CBDDDF +:10DAF000E779DE7871538182DF397081E759973099 +:10DB00009F827ED78D51A3BF76553A75C7C66FC425 +:10DB1000BD444AA437C255B3CBF2ED81EE76C0D7EF +:10DB20002A21DF9ACF4FF020BE360E1879F37468A1 +:10DB3000923B70F834342B4CD65615F5DD5D82AE31 +:10DB400046235D4964F56874E5B1A31DBD2686AE24 +:10DB5000DCA9063F6E160BD381C7A21AF592C11F2E +:10DB6000147648AC7DDE6997D7C7F5E7580B38A81F +:10DB7000403FB3057C57A5988328B794FB78BECF68 +:10DB80005D8CF5C63CA0BB6A5483FF393B4521FC44 +:10DB9000CD5E6EA33C4FBC376A2ED403F09CCE35CD +:10DBA0000CE0F74875E0B356D71FE9C09141743BCC +:10DBB0005BEC87FF49E27EF8EC944FD2C9690FAA6B +:10DBC00017F4F419FBFD84E3C6F45B25F178CE2A43 +:10DBD000D597E9D5D91B13EDDC7EBAE02E5B67BA89 +:10DBE000C2FD06016B8F7C45771F505B8A7566BC52 +:10DBF0007B24B4F1347BAF28C0FDF044E3F68D9470 +:10DC0000911D66FA795846FBBA6F84913D5C14F118 +:10DC100099E619EC72EE8F76B1CBF13E03A82F692D +:10DC2000DCCBEDF286E564DF2F01FB1EE5F906DCB7 +:10DC3000F3ECC1F884F2C95EEFF02B31BFA5A84127 +:10DC4000EAF03B15C07B5E3D6FBFEA9171EAC30A03 +:10DC5000FA85814CD58BE18192D556F073EA7298A2 +:10DC60008D819FB3C25E327E2DFAA5A93E89A55053 +:10DC70007DB523EBDAFDD855F6E2D5E8C726F227C5 +:10DC8000ABED1E825F227F5276FA57D975710090F4 +:10DC90008B71ED8F49CE9235D84E93170F9BC27979 +:10DCA0003FED46F941945F7173EDDD64EF4FAEAD2A +:10DCB000F0E2956EEDFB2EF7C7FC8A2281EF5FD86C +:10DCC000B93D599DC4ED48490AFC02F9B375C0D36A +:10DCD0006B0B803F6635F1BC0DDB75977BD37D40C8 +:10DCE000239FFE79018CFF5144A1F842B393C79B57 +:10DCF0003F6212D9AB45472CFE46C0C365905076B3 +:10DD00009DDF729995519DF5CC309C0FFE88EDCD2D +:10DD1000FB297C2758C3F3942ED4E42423DE9B559F +:10DD200063FC77AB9DE7B76D15F4370BEF8D1C8E59 +:10DD3000EDC2D9787FCB2C25AC527E46D4CCEF39BE +:10DD40008479E07C9A6DC67176DAB9DFB5D3CEED11 +:10DD5000F859E2DEC9665BEC380A1F5FDC33170B4B +:10DD6000F7347BE98BB89ECBCCD744780279857A9F +:10DD7000A16844CB51B417AEAE7F7C12EA9FEACBC8 +:10DD800052B80FC6A71B55F2DFCF8873E2671BF7A7 +:10DD900067DC0D65E5F63FB8D0DF7B4DE0E9ACD23E +:10DDA0004AF7BC2C795EA67B0AE0BB19DFA1FEF323 +:10DDB0000AF9392B7E4E48D3CB055FEFCFF6F3E05F +:10DDC000209DFBD1ECCE71D66008E7D7BC5C26B9AC +:10DDD000017ADB70EFCF8DE2DE9F587BF463BB16D8 +:10DDE00067CEA0BC9F07DCFC3B89F8BF289ACA42DB +:10DDF0003AF950A484659C7F5134838500BE670F37 +:10DE0000E63E568EF4CA546F3F1C56612D640F8B4C +:10DE1000FD1BF8B5E0FD74BB45654FE3C5E96389BB +:10DE2000F9DCAB06439B6F8503DDC83EC610686115 +:10DE3000A7DD7763D418578DB5934B9A87AD42937E +:10DE4000F20C3E40FA8BF07B91BAD8CF910971ED7C +:10DE500066C61E2538143C9F3709EF7B2978CDE430 +:10DE6000C6EFEE41BEC6787EE345BA8FA48A856FC1 +:10DE7000C3F7558DB23BCCAE14CF5AF5C68D308F5B +:10DE80003D11C583FCBF27D2621D4A7513C5318A77 +:10DE90000E170D46BE6D8E2814FF2F3ADF92342FD9 +:10DEA000BFD37E69BE6CA2E77B2EEFA3E7DAB8CDC5 +:10DEB00091D4C1A88FB79BB83FDDF2EAA52494A7FF +:10DEC0007B2E5F48E3F70F2DD7EE058AB59B092E11 +:10DED000A54EB923CEACB7D3995CF436E62B8D4F63 +:10DEE00056994C78E0FE6617FBE343B6CAC9BADA26 +:10DEF000212568D7C871EC914E781BECE7FE49C22A +:10DF00007EECC50AF03EB7A6CB698BE95C677392DD +:10DF10007B05C59DB8FDD0DE72FA6793F0F92199B3 +:10DF20009FEBBF2C133FEDDBBDB84F9B430FEF3A88 +:10DF3000C2DF1759E7CFBD02EDBF3860A77839536C +:10DF4000BC83E3C5453AE3C4E11E7C7F2BD883DF65 +:10DF50003FC3E300DFEA8C0314258DE4F737A15AB1 +:10DF6000EABFFE9819E3287BECFE6F2511DF34240D +:10DF7000A19CA8B073B9146425D96024B1E70F9AA5 +:10DF80004A904E462CF710BEB7AA604A215F6CE655 +:10DF90007EFB563C070AE32C6CA837E7E8F0BB5041 +:10DFA000EC377DAA067BA7EA9EFF3E89FBA59F1E54 +:10DFB00058F414E523BC6F61FDE2D89FA1242E071D +:10DFC000779A8393B661BBE3263AE7D1F2EACBAF07 +:10DFD000F600FC2E3CEA1986F27F599287E0D57450 +:10DFE000686B5D0F68D7F4216A4930B937CD954D1C +:10DFF000F0DD579887C7F3DE36D17C3BE29F6007A0 +:10E00000E27A7F20E6F3CA419361FFEA153BD76BC2 +:10E0100095492ABD9F97C4E3693B0E96A461FEE92A +:10E020001E7B603EC2B3FA93B63A97A733FEA7D9D8 +:10E030008163DEDE316908FCE798332637A2CFF32F +:10E04000F64619D7EBF994B114A96B7C0AC6AB411B +:10E050003C68E3BD72868F07F3D887FC1659CEDC87 +:10E060009497C9FC3FCA87FA2BAD4A2AE62D6D1555 +:10E07000FBAA1A1EB4F568F3F03430DF0607B18648 +:10E080006FC795E2CC223F72B8909B5FDB7DC124C5 +:10E090001E07247BFBD30376B2BB768A7835CB9CF4 +:10E0A000DB07E1A7E169BD2863E793E8FB8F2771F0 +:10E0B000BDA1955B554F90E8E179AE6FB73AC3D6F5 +:10E0C0003C947F2FE551DD130C260DC53CA8A67EA0 +:10E0D0005EDCEFC3FCCF24DD3EEB3841E79E868853 +:10E0E00039478787C4728DC3BD837E9406A2ABA6D1 +:10E0F000A38CF86DD196FB787C11E481B8CF89F6BA +:10E100008F912FC43E7296C44B17F2C998E60D2B1F +:10E11000B33D74BE80F66D353878902FA0DC2DF0BD +:10E120008270C1F72F89756BEF5F14F01B2FE72703 +:10E13000EBF31163CB3DCB3229A6A8D55F12F35F79 +:10E14000C81E253B74E1E57AB24F3D35BC5CF80052 +:10E150002FFBAF9F6BC6F8EFC275F1EFAD1B95C4F7 +:10E16000ED97B3820F98C9DE03F3393AF46312D7FF +:10E17000AFA71A1FDB9F4DFA24F02AD2C70D4D8F8F +:10E18000FE12C1A4D1FFA94D2AF5D7E488D6FF0D10 +:10E1900031FEF36F73FE19B3492DC17B8CC6049910 +:10E1A0001BE3E4AF6CDA2CA35C7F05F92387CB0D6E +:10E1B000D4C79F1E7824E921A483632686F1F89DA5 +:10E1C0006656B15D87DF960D2F1AE4C1A22DCB27CD +:10E1D000E138A3DA522594FF9A1CD0F0BDD3ECBDF0 +:10E1E00089E4C994187952C6FB47053C1F13F2E431 +:10E1F000B189204FE051CAA61409C7D9698E7FAFF3 +:10E20000D5671ADF097A1CDB29773FE372B7CD9512 +:10E2100007E3544DBE40F1D78EEF08BA7BAC4CA358 +:10E22000BB1C09E108F6BCA92FAE1BE083F40FF676 +:10E23000FC9C69F9C4A50715DAF711FB48226F8227 +:10E24000384CC7BF9A9CFBDA1EF81BF2496159CDC6 +:10E250004AF433D2CA8344D7A7A4409F54D057A7C7 +:10E2600090AFE3C885E3623D5FA8813EEE38EF3BA7 +:10E27000F988F5403EA8600113AE83AD97DCFAF350 +:10E280000F9EF59CDE521C92217F5CAB6BF0BA9125 +:10E2900075DC3398E248273D65C6BCCAFE21AEA7AF +:10E2A000985442F4C84C37F7407E3BA532A29F53A6 +:10E2B0002017116E0BED463F445B574F07E7AB2F1E +:10E2C00052F83AFE28F88E7CDC91D48EDB59C526B4 +:10E2D000DA8745FA207A9B924A7E0A38460AF17913 +:10E2E000C73E435896B83C90711E6EF4DF280EB4BA +:10E2F00081E7856DDB40749332D14DE7191E53BC25 +:10E30000B6145D1CB765F3E3E437223DE11C12D17E +:10E310006305D2238B438721A043E8973AB186F067 +:10E3200008F81DE5807153CA0232D24D2C7EB5FD2E +:10E33000430D1E3B63F61BBFE7E07C3951949E04FE +:10E3400079279D7AC2286F015FDFE6F8EAA46FC4DF +:10E350009BC66FC31D57A6F39083DF075EF7D13CC2 +:10E36000CAF7D0F699B47D63EDFB77087A49B44FCC +:10E3700094650BCC7418F6A396D27E97C627DADF85 +:10E38000A558BA99E7BD6DC73708F7167B487F5E79 +:10E39000CFAD301FE2B3C29143DFD3F0EBA935B369 +:10E3A000BEE02F7C9133B7055F7DBB35583E04D668 +:10E3B000B1DD1C9C3199EC6EEF4D38FE4DE526F732 +:10E3C0002312E60BB8258C771089235F1CE2DF61EE +:10E3D0001EAF61DE4B05DC353C697048A4AF12E12D +:10E3E0002724E0932EDEC7F275B983F373BEE35A98 +:10E3F000F93A2823DDBB586005DE3FCD8AB81CEA18 +:10E40000E0EB2246FB886BC578DA73AD1E87AFD789 +:10E410003A46EAF87A749B91AFC1C215FA94F82B88 +:10E420007D93CAF368059F7D61E3F3FD9583DB630C +:10E43000E9A83F007FE941BE9FBA54D0195010E5CA +:10E44000E5D56FB230C483C6F7AE19AC44C57D596B +:10E45000D437D86A46E0E838DC8FCD347B707FF85B +:10E46000941A213C9D0207B59EF0E9A73C935307FF +:10E470006EE0F2607287FEF1E17E4FF08F3DF97E33 +:10E480008EDC4C74BD743C23FDD1B27914D141456E +:10E4900079AE8474B6684B8A84EF53CBDC26592757 +:10E4A0001747D59A58DFE144B7CF3974727154B029 +:10E4B0004646B8F4490B64AA29603738E64CD0C701 +:10E4C0007F5E81BA3EFE03F5BABF27FEB37BED5DEA +:10E4D0007518FF694FF235233EB26CFEDDF8FDC2C0 +:10E4E000EC1A99E9E4C5D5ECA66A113FFA70F5EB90 +:10E4F0009BE7C2BA673D1C598D6FE7607C7500E6EB +:10E5000005F0F86A75F3118ABB360B7E1E2EF90FE3 +:10E51000E377EFAAB9C918678D5CDB77BB09BE65E5 +:10E520001F32827F377F8D8CF1084D2E7C807F8F4C +:10E5300081FB8D12EEAB69FC807205ED4F2DBF01A2 +:10E54000E35ECED44EB98CF5649D5E5D5B6E8A7BD6 +:10E550005FED6987C3A0B73439C89AFFF6C243DAC2 +:10E56000BD995C2E9E76E8F4FE63E5C7E93C311365 +:10E57000F7D0DD2F7CC8A756787F7F5DB7CE73ECD0 +:10E58000C32CE620E64F82DBEB71EBF261A5662936 +:10E59000ECC43CCB4BE8B900FE2E99A87CEADFFD29 +:10E5A0001373D08F6F3279C112C03C09A2636F1F01 +:10E5B00046E71E1AC43E6CF17E874F1D81F7E65B6D +:10E5C00049FEB5EFB50791AFDB9D268A1FB7ECB2C8 +:10E5D000105C2FF6B50BBF3A64F0BFB5FD0D9BA5DF +:10E5E000EDAD22E8BFD1C6C7DDF8707FBA4F23D1A9 +:10E5F0007E77516D2EC5F3B4F8626EC463E2496153 +:10E600007C7C25C2685DDAFEF73ACCBF189138FFF2 +:10E61000A297D3ACF94B194EA4C3996DAFE2DC625B +:10E62000FDAF8C43C7F7E23819B53C2CB0EED052A1 +:10E6300009D7B76E567CFF4BA39F7522CEA5CB732F +:10E64000C873EAF5CADCD4A45C9DDCD4FAFD52E4BC +:10E65000398C6AB97B27DA77C0D7694E1D5F4F1AAC +:10E66000B2DA166FBFDD5FFB10C53F13D1BDDFC44B +:10E67000EF5B8A7D3EDE29EC1825D283ECC03D5F3E +:10E68000D83D71F21FFCBB4CF47741B4784CD7EF06 +:10E69000FF3BCDFF4667C7BE5E8F6BD9D78B9D779B +:10E6A000ABCA7AC5D327B17993DAF7E2F4BF4B7FCF +:10E6B000EF81DFCC02DB1D5DFB69F6AE5FE2F74E5A +:10E6C000B18F18E9558D4E00EE7720BE861E9E371D +:10E6D0001C43A9CC5A23A31CB8D8D4928D71AA4448 +:10E6E0007EA1361FF8F58B1767F1E3BD4A71D67727 +:10E6F000BFC0835FE5F6A7547CE03B382FFF79B3BA +:10E70000A43F8731C72919F8498B83369F7F773813 +:10E71000C947359C1D0F7EB1FB96733068C5F51C4B +:10E720008783804B5D312BB174A33801DBE841FF57 +:10E730008FCB494F2D23FEBE5EF2D1BA5738B95D5B +:10E74000B38EB5525EE3C5433C0F79E87D1EFAFBFC +:10E750005CA00F8248B7A35860A74997D7A5D143BB +:10E76000DDB3609F18E2559C7F34BFB59788FBF4FA +:10E77000C47B4274EDBACF0452D5C9FBAC80952955 +:10E78000BAF85A7685DB50EF559369689F190C4BA0 +:10E79000C85799B51EC3F34E39C5D7DB2BC836A071 +:10E7A000DE5FC7DA687DBDC57CAE9702441F170FD8 +:10E7B0009D48C5386448E003D6FB24ADB736705198 +:10E7C0004F1FDA7AAFB6AE0F97C17C80EFFF847E21 +:10E7D0003994773D704CEA4E707753DAEF1CD1AF25 +:10E7E000D7F78F90FFD8ABA695ECF7D9B57B25D49A +:10E7F0005B2037A8DFBA65562A7FBDCC4D3254C3A3 +:10E800006F4F68877947DA7DF089F4D22EE735EBD0 +:10E81000A55DCE387AC9648DBC86FBDB95CDB20789 +:10E82000E960E5F753297FE2A9067E2E717F33CF99 +:10E83000E77BAA8EE76D6BDF3DF77C32EDEF9C1333 +:10E84000FB7CCC7729631AED7B5FCAC0F3451F3B85 +:10E85000026FE8E5E053CD9FDB505F0CD6F26463B6 +:10E86000F40B0A5E3CAF42671F25B47B86AD917105 +:10E870001DB70586634A1BF0F73B9C3EB91EFACDD7 +:10E88000B61293FE9E8E8B4D7F9DBDCFD3B96FA4E4 +:10E89000ED2B69EFB57D27490A7CAC97EBB1FB4ABC +:10E8A000B1FB21B2CB4A79D65ED9EE958D7A95E847 +:10E8B0006E653FAE3757EEB513DC56F673D0FE2DBE +:10E8C000CCF70CCEB705F4169EC3BB78D441EDB49B +:10E8D000F9C37C871ED2CDB7DA1499BD4F8A3BDFCE +:10E8E000CFF570EC3A5F633EB2363FD9A9D0BCDBBE +:10E8F00099DD8B786B30F3FBDB826FDA291EDAEE61 +:10E90000BB64C37B83DBD9251BC6694F3B02920BDB +:10E91000BE23F78AB8D00FD9DF7C7120D27FA27DC9 +:10E92000BE41CE1215DBC33AAD588E72072E6E6310 +:10E930009CCF0257E837C959E2708DFCBBD69FEED9 +:10E94000BA22BE8CEBAFC6BF83A2B3A324216F63F0 +:10E95000E94D6ADEFB15C6F581BF285F34D89B857B +:10E9600056029CEA8608BA9BC1C4DF4132D2C3C7B3 +:10E970000E7F3F5CAFC6975780CF409CF75B0EFF82 +:10E98000606C8FF3C0F33C207786B8B89EDA894775 +:10E990009635FBA94F1E97639114467926B1FBB3B8 +:10E9A000939CD34660BFDC011E13DEE3FE77D0FBF1 +:10E9B000B82BC32F4C792ADA79E24ADC27C4737C5E +:10E9C0008DEA19E3DF4B32C2E1B4C3FF6D1C375847 +:10E9D000D249572B3D5784C72484C35B8EC0142C67 +:10E9E0009D2AD00B0265F45CFAFB555936DF2ADC10 +:10E9F000BFDCBA9CC3A1FD590E87ED2D26A2E30D05 +:10EA00006C10F1DF20D385D9383EC8979938CE886D +:10EA1000D67A13E6F3F50B794C748F536B83C97474 +:10EA200065BA9D25E8768EC0C3FD8887C1DB785C1A +:10EA3000E50A743B4FD0EDB5C27D89EB8A7CDB855E +:10EA4000AE6AF47475ADF9439238071B3B1E636DD3 +:10EA500014BFDFFB9285E477D50E7EEEB76AF749E7 +:10EA60003A2F5AF5B28588B2EC651B3FBFD2C8DF9A +:10EA70009F2B8EBFBFFC6F2EEE5F5536DCE7D5EBCC +:10EA80006BCD0EF8A9EF82BBAFDCB94F9736999FDB +:10EA9000075969D3F241F97E9D4BD0595A2FBF0FC8 +:10EAA000F54EDA781E177239E6D37E5DD7731F9C58 +:10EAB0006FD3453FB7DB43F640EC399074BC179CED +:10EAC000EFBB12BDC826BB17F72DD326C6B4734CB7 +:10EAD000A4FCB9F498FDBC904BD8C166964972D499 +:10EAE00016FFBC9792ACD97376935E9EA09CA7FB51 +:10EAF0007A9C565AF7D27496568EF101A742E73D9A +:10EB000063C7D1CA149FC9709E286DA2DD705F468D +:10EB1000BA3FD550EF3EB387A17D5620D7F03EBB1C +:10EB20006290E17DAF9A0243BD4FED0D86F639400C +:10EB300070FA7ADE9A9B0DEDFBD54F33D4AF5B773D +:10EB4000A7A1FDC0D0DD86F783B72C32BC1FD2B0A1 +:10EB5000D450BFBEE921437B39817DADC159D6EC8C +:10EB60006BE788009D1F735A25BD1D72D8C5EDF057 +:10EB7000629795E0BF5AE8E3D5E2BCD96AA18F5B02 +:10EB8000D20BAFB8BFF28FFA63675DC6B8578988FA +:10EB90007B9DDB673621DD57ED07BAA0BFCB15386B +:10EBA000EBE2F6D794B9B47A7E8EB235413EC79780 +:10EBB0002ECDCF03BF248E7F674AF6C4F5AF40AE9B +:10EBC0005D72E9FD205623A31CD0E452751223BBCD +:10EBD000ADDD15ED8F7C04724A4A4E47F9F458CDED +:10EBE0003E944FCD16924FAF0F38417EF5CDB5F321 +:10EBF000092E875D3C5E2B9BBD1E7ECED4A8770F71 +:10EC0000A9AD94A77D68A4CCF07E948BDE51749E50 +:10EC100039113CDF44BF1964D77E940D23AFEE77E2 +:10EC20001E5A5641F9CC89C63B34CC4671CFF29876 +:10EC30007B7007093A2A4B16F0B470FFF1EC0B4ECB +:10EC4000CA2F3E5BF00EFDFDA2B38D7F181EA4BF40 +:10EC5000D7D57A3FEEBF07FFEAA0B84CF9B0778668 +:10EC60002F27BBD6C7FD37F177C1C6BD78D8857EC3 +:10EC700077F9F6FDDD823AFCC5FA6D65627D4C6977 +:10EC8000EB4F79A1AF9CA2BF1B53FED2816E3C2EED +:10EC900064CC5B89F5D7CB6BAB086F5ABD326A3554 +:10ECA000E4AF542AFCDC6F65D441F92BAE64A33F7A +:10ECB0009F105ED708CFD8E71A3C0F0D3BC5CFAFEA +:10ECC000DBE2D36F4DB2313E1C7BAE2051FEFAED3C +:10ECD000A2DF45EF183A075F6E0EF7BD96F8820681 +:10ECE000A7D72F2FA0F30A2F2438AFE04FE671F7F4 +:10ECF0001706DC4B79C763AC35A5A8BFC788F86594 +:10ED00009CBCE37B9247623EF33F27EFB852C38F30 +:10ED1000C8EB1D837C9CCEBAE41D5FED3CC824BCCF +:10ED20008F3B0E7FDDD401BFF767E0BD4EF73FA1FB +:10ED3000521ED002984310E3261B548A9F1EBE6CBD +:10ED40006118CF3EB95E7D1AF3552A9ED8DFF331A4 +:10ED50008C5F0FB3501EDD820DFC3E1036CC16C208 +:10ED60003C8D8A0D0F66607EE467C0B74B605E0B1A +:10ED70009E48A73C9EC32D8F64209E4E097EAEF810 +:10ED8000FA87B721FCB79BDD838741B9649B64C8D0 +:10ED9000035FB4C966A86B79401AFE98D4991FEE38 +:10EDA0000139FA78B2F17CCBF0CE7D85C793853CF2 +:10EDB0009D0EF3AD1A79D18C78DCFFAA9DE6BDC714 +:10EDC000C1EF570B0FFBF28DEBA15EFAB5A2DDABE5 +:10EDD00063C82B62B80981F79C88FCBFD297948ED8 +:10EDE000FC7CE13738C6EBF2A0C3CB6A886F4A7F60 +:10EDF000C5FDE2521BCFD74D986FC4BAE4330F4024 +:10EE000079DE25CFA8F33C84C12ED1E8A63159E4A0 +:10EE10001B09BEDEFF2ACF2B9A7F48D89357919BC0 +:10EE20006FE2BC15C4D7EBB370DFF1B080C6E1CBA5 +:10EE30002757D13D44A3258CB0B19397E3F38D5967 +:10EE4000939F98BF3FA0133F93BD0B3BEAC89653D7 +:10EE500047DF67385770EDF2E6CAF2A436999FBFD4 +:10EE60008B95EFB174FF7F4ABE970F3BD01BCFC984 +:10EE700043F99F745E7E3B978FB17C1E2BCF6F8AC8 +:10EE800091839D72DC6490E337097DDE29CFCD2428 +:10EE9000CFC13CE3F7B7142AA19512F93D5FA0BE9C +:10EEA000CE7778D28AA1CB2A776E52E0CA7EE82547 +:10EEB000E493765BE06B2CFBFC6610FD5DCFC1DB61 +:10EEC000EA4DC8BFED09EC8FFF0D39A0FC7700803B +:10EED000000000001F8B080000000000000BCD7D2B +:10EEE000097C94D5B5F8FDE69B2DC94C3299EC2BE5 +:10EEF00013761570801010A27E4900A3101C5001DB +:10EF000035E82490842D24205AFA6A5F262460C4B0 +:10EF10006843B58A8A7650F051450D8235B651273F +:10EF20008014AC4BACB6A5AD621044362582FAA76E +:10EF30007D2AEF9C73EFCDCC3799B0F4F97EBF7F7B +:10EF4000FAB397FBDDFDECE7DC6566451B181BC3D8 +:10EF5000D8B32636BBD506A902E930C6CEE2DFD546 +:10EF60008CC5380A66452731B6DF0A29D463CCEA56 +:10EF7000383494B15C6660712A63258A37C601E52E +:10EF8000D5D6AE07CAA074C96FBE354311DB10EDEC +:10EF90004D352632E64B37BB37E504FB93699203C8 +:10EFA0002A41BBFE2B0AD9C104C62C56E68B1AC5D2 +:10EFB0009862643ED3281CC7B5D200ED8D4D8CAD50 +:10EFC00081F6B17646F36443530D2C99B13BAC8C7A +:10EFD000FE7C850C27C37C3BA2FD0D0A63DF332D2D +:10EFE00003E7F303D3321D50FF23A665615E8EDB7A +:10EFF00028D6693430EF565BEF79CD74287C1CE657 +:10F0000019EC81312B0A9937141E322D7018A95E24 +:10F01000C1C337677741F9671DB76433E86FD7AF6E +:10F02000C6C67545A82FD3B575B5EE89D0F4FE3A9E +:10F030002FA5F18C69389F5FD4CDA7BC13F25BA1DB +:10F040007D85D933383EA49F818E788297A3E04F87 +:10F050009E01009743CDAA437141CA0CC5D8FEA0BA +:10F060003FAE78BB6897A86BC7E7A9328DB101B0F6 +:10F070006E9BF15F5D02766719AE9751BF7DAD73F0 +:10F08000A683D38799B9ADD8DEBCE33A2BE25755B6 +:10F090003407E6253D5C0123203DDC839FAE606C98 +:10F0A000B4E2F538A89D9620CBCFE6E0F8C594975A +:10F0B000E3B34C58715ADFF0628A7613E2EF08D35B +:10F0C00066627FAD66769903D6DB1ACDE6479A6F06 +:10F0D000A9C05FBA43D00BB3390E5F26C683F99D32 +:10F0E0008CD16EC77ED2A23C65D86F5E46AD6A8277 +:10F0F00026B3A21DA2BEA67886537925D663A99A07 +:10F100005202F0CEFB04E810B2DBF6142A2E183FB0 +:10F11000B173A2E282F11305FE7ACD5FC0ED25C680 +:10F120008A23CD7356349FE75201FFFD560FF1D766 +:10F13000EA1C6F6A2DF4E76A659A1FDAB5E2944219 +:10F14000E0F396C34CF5374477F954A4FB5B987B06 +:10F1500013D0414ABE4F31429A31B5A50030CE1A84 +:10F160001C4EEADF59EC4D55A05E7AAAD9AD2A179C +:10F17000CE6FC35A35D50BE3E77A0D348F759DBE3C +:10F18000A8C130AFE44E6F8119D2A2F864EA3F857E +:10F19000D5D6233EA03D43BE1CEDE0FFCCF516AA1C +:10F1A000AE10B8E4CDAB6D30C3F7EFA3BD6B43F940 +:10F1B0003163B18FC639AA78FB39819E8EBE193D65 +:10F1C000DB8FFD059C4447B2DE5388D724A487C259 +:10F1D00074960AFD6F34D1BC7237FEEA36E4FFDC68 +:10F1E0008DD718951039F38AC344F58FBEB9B01F77 +:10F1F000AEDFF7370B1B14410EBD28E8E5618187B0 +:10F200006DE6C874F59C1C5FD0FB04A648F9F79C1A +:10F21000907FB103607D4BAA4F91FC6B76B8A8FE3E +:10F22000E3C6D6DDE900D7C7E731B70F3E2DDCBC1A +:10F2300041C1F56E33B75EBB05E7B5C4C0107FBBF7 +:10F2400076FF6E773AE4E7CF738DB4B842DABFFD4C +:10F25000EC6AFCFEF87C3612E19AE65FAB18003EE1 +:10F26000DF46B5D0BABFDD6461F530B5C7373E9231 +:10F270006CC77A5E8303EBF5E22340B32115D3809C +:10F28000C9308EE311E595C49F843BAE1FE5E2AE25 +:10F290004DAFD0BCE57C8050CC08F7A27817C16B8D +:10F2A000E1E6ADD722F1A72F762A6A4E705EE7938A +:10F2B000FB1F0ABEB8503A7C339EF331C8790DC7A4 +:10F2C000F3E51949CE7F62F3FE1DE13ECCE64A2804 +:10F2D0008029353AFAC77861FC7E03D8ED9E08FC98 +:10F2E00078A9BD703FD63F19E53D807CDDEFB94B75 +:10F2F00027B258C62EDBD262407C9C54B85EE8CD63 +:10F30000A7423F0ABD28F5A42C3F29E8E20EA12719 +:10F3100023E8C79391F4A38BB9EE1B06F8626F1B29 +:10F32000887FC3C75D2AE87282E62D427E9E1DE378 +:10F330003D83F3BE629C7FA70AF5C716FB7622BF0A +:10F34000E72AB53BED0017762D9703095DAC0396D0 +:10F35000C5E2F77569B1909F8B7200C61F7F44EBC1 +:10F36000C0F1E23C4CC1F6CF229DC33A5A9CECF668 +:10F37000E911E8FD36B12EC343DD66D46789ED0A95 +:10F38000F15B6FF8707904F232261EE697D70FE42E +:10F39000694E6F791A017FCE786877C996C00EAC36 +:10F3A000352A7E600C343B17FE92E3097F5A0A8EA1 +:10F3B00023F175E959F576CFB0DEF8CA8EE7F3BFD1 +:10F3C000D3AE6561BBCF843EE80B8FC3E339FE8AC1 +:10F3D000E2B99DF3AC5DD48BD2D72B8BE778A988AB +:10F3E000D7CB83107C0F8F8F806F29C7B7ED7949FA +:10F3F00045BCE54D6C69403C005E47E37AC6E7D703 +:10F4000036E0F784A95C1E86E355CAC370FC86E328 +:10F4100095B17A9A1FE0E3AAF808FA4BF613AEC743 +:10F4200042E404AD6B9DA04F1FD227E3FA68832D01 +:10F43000B80EC93FB709784CF07A8BCC9C4E4B7014 +:10F44000DC2B66FB779A904EE7FB769A43E97401D2 +:10F45000A3FEE43C32BA7CB49EB47DDE024CC71FEE +:10F4600009740C837A29B5B01E165C4F56E7870ADB +:10F47000CAABACDA4E85A1FCDCB383E69DD9B98B6F +:10F48000A7A88787F5D6B78CAD1474C8FB79339ECF +:10F49000CBD5D55FCC4D45BA595DC0F5ED2ABB56ED +:10F4A0008EF3BEC3A1CD45FCADB36BF3303F2B9AB9 +:10F4B000EB85E1F15A257ECFEA43DF2F117000B8CA +:10F4C0005763BBC4E5CCA7C03AC6EEB3F9415500BB +:10F4D000E9C3BC614189B53EC50C704DD4981BE5AC +:10F4E00074BF046FBD09EA755FC1DC4F413EAED405 +:10F4F0005180F072CE7777203C577FA1927DBB7A06 +:10F5000029F3AFA47E18FF3F6F7F3FCA57E4DF5057 +:10F510007EF18979F8E2391F80BDF3F378CE9F75CB +:10F52000C49FC2DE917CD997FD12C2D7AB2F92AF98 +:10F53000EFBF48BE5E2BF8FA97949E87AF1F0DF27F +:10F54000F53A9CD7F9F87AB3E0E737057FF7C5D7E6 +:10F550007F10707B27BE4F3F67338ED75B8E73BAA9 +:10F56000937CF1D29E5131E5D0EF4E31CF10F9DDD1 +:10F570008AEB3B9FFCFE37F8FCF7D8EFF9EC54D947 +:10F58000AFC4F7F9F864B8D343F092F668ACDD4144 +:10F59000EB917C0FFCB247F0CB5EC12F6F613A2B31 +:10F5A0009ADB07E1FCD5A3EF3AB93C014F2606E907 +:10F5B000478E7FA437BCFE12095E594CC0AB98CB76 +:10F5C000914CE65363B1DFA90ECA3B4E38EAD155E0 +:10F5D0008C3DD4ED43B87D1BCFFDCC5C857922D921 +:10F5E00075C7049F247616927C01781EC27125BDD2 +:10F5F0002732C714F473A29C5C6E8C1EA7ED44B92D +:10F60000E4D03C2ADA1BB94ECE0F124ED0FE8B4806 +:10F61000F8D88EF818D6DB6F08C7C3A762BE514E64 +:10F620000E8FF0FEA5FCC1FE8753FF2E03F62FDBE5 +:10F63000FF109443DF237EC62EAF55715D894C8B3E +:10F6400041F923E524CB84F6B9BDDB9BC4B8D0DEF9 +:10F65000E484746C2DB41F166C9FC5020AC2C339B2 +:10F660001FE41443FBDD4DF66C9BD5637312BD3074 +:10F670002EAF0A0C240FA6D934E2A748FADF7991FD +:10F68000FADF29F4BFF342F4BF33A8FFB19D723E05 +:10F69000FD2FEA8F709E5B4EB87BF022E304BDF530 +:10F6A000BF3382FEDF6FD5A8DF087C3412D713E3A7 +:10F6B000D046610A7C34DA9914D43BD06E0C7E6F4C +:10F6C00013ED9BA71A86927DCDA2DD91FC9942A7EE +:10F6D0004D37AF2B859FC2DAFFFBB7FF91C7580D9F +:10F6E00016F179163A43FC9607A77E9AEC253F8ED1 +:10F6F000E9E22BBF5EE97E6F088EF7AECA90BF7E4F +:10F70000FD9F5D6684776B74EC0816171CB7E65F87 +:10F71000405860CF9FFC97815289C725EDCA680683 +:10F720000C59B0F33B8A939CECF817C5492EB5975A +:10F73000CFC075ED7A8DC74B4EBF7DD0897424C77D +:10F740005F26FCC849EAB0D600D0D3A9CD6637FA07 +:10F75000212A733D920FF3A9D963627E9283CC8AEA +:10F76000F54D7CBACCB47975A71A8B79A34FC439FF +:10F7700094B3A4EF5C714897A63D2AF9152C919794 +:10F78000D7326BFDD9FE2057C719982B242E12AF04 +:10F79000453357489C22A1D8A9CB338CA7C0B88B3E +:10F7A000189F6792275DD73E65767F5DFD34EFA594 +:10F7B000BAF28CF9A374F9ACDAF1BAFAFDC03F0AD7 +:10F7C000CDE7F8AED3D51FD03443971FD4728BAE9C +:10F7D000FEE7ACF6E17C5CB74FEB1C08F39C27E638 +:10F7E00039645DB9AEDDA586D63CE068362FB070D1 +:10F7F0002A1B01FCE85FA8EBE7F8B3C57B14F8CE41 +:10F800005A4C8738BC6A19C28BD60FF0AC6C53D8EF +:10F8100063D0BE6A1D2F97EDE6B7AF5D9D01E9028B +:10F82000BFFE3B637E33CAFD459BF5DF1F74DA13D1 +:10F83000294E93CED2CFAA91E8C046E39D5AAFFAA3 +:10F840002D803FD537248C0EF4F860FF4BBA700939 +:10F85000BAB0A4EAE922CAA5A78BAABDDBF202AC22 +:10F86000379C63863A23C251C2D9EED6D38B842FFC +:10F87000E8C9FF13F8BE81F08D09C2372DCABB035A +:10F88000F9EF74DB7295E1785EEF686CD797FC9DB9 +:10F89000622FDC8DF2E274DBD7B7ED80F5D5C47052 +:10F8A000FE3FB9E3BBC128DF64BDEB5694BB278E96 +:10F8B00006E02ADEF7B07FF9BD73E8D3CDA3603D43 +:10F8C000A56D2AF1F149A3AD49B99C96E97200DC16 +:10F8D000941EBC713C4ABC29ED3BFFA900DE2C30D4 +:10F8E0004313C61BC7B9AD384F8CF421BD286087C0 +:10F8F0009E8D217DF231CECF57A8318AF7FC89B990 +:10F900001BA056833DEFB2F3C4050E38495F7A1B46 +:10F9100051BE8EEDF49EDE82DD1B3B1D18FF9DE285 +:10F92000F5D27A2EC70982FDC41C00277BB03DB4F6 +:10F930003B8EE34E2970C6A0BDB575D732F2DF58B5 +:10F940007B22D9834832A1764EB89F25ED46B0D3AD +:10F950004FF17978BE7686DAE9C26E93F6765FFD6E +:10F96000807E1D8AF6415FA9B2431D6A04B8742BDC +:10F97000D1EEA722E80D4B82DE9FBD3218DFB22404 +:10F9800084E88925779EDE8DFA03E01D9D00F3B49F +:10F99000DB417F2B17A4BF63B1FE2331B144D7DD18 +:10F9A0007B55FF106870CAEA8A7302BCF2519F5CF3 +:10F9B0004E712096E10CB6ABB5A60F33823EC93F1F +:10F9C00035348E9D23AE9E8FF54607F3ED514C677F +:10F9D00017AC1EC5E7E512EB3C10C5EDACB1225FDC +:10F9E00013168FAA69E2F1D70D6660B5907EC62620 +:10F9F000D879BCC75A3016D7B341C4A157E7286499 +:10FA000027AC5614B21B76DA0AA9FC90B3200FE19A +:10FA100077B918672C8C81FAB9A5BF988FB0C764E5 +:10FA2000FFDDA27EB7B390D2B1090E8117C7A588BA +:10FA3000FF0AAB46FD9A5535229CF313B8FD5313CC +:10FA4000CDA49F46FC3449F0D76421478BEC204776 +:10FA5000B91F387512945F25F94FCDFFD00CA43B28 +:10FA600029CEC4305E7C959057EC8CF15394270ED0 +:10FA7000F81FCA276DA863178CC40A98E9D35039B8 +:10FA800053C83AD3913E8AACFAEF93B64F3E8AF20E +:10FA90006F123306BFE77078C738837C7063428F7C +:10FAA0001EC84439D516DDF5CB29E81FBFA3BA9F80 +:10FAB00062BDD75B91C0EDB066B4A36D042A0DE3BF +:10FAC00097D9621FA5777D0E9F0D7DC4792BAC055C +:10FAD0007311BEAADD538129B0C3A5C8EF6D666F4F +:10FAE00003FA1DDD2F339AC7503FDB81F9E13E1742 +:10FAF0002E17F0EF8B1981743DD2407EBC6B5DCB2D +:10FB0000CE282877AD579C0AE44D46E6B38F0ACA43 +:10FB100093C6841C9A6C7357F90E3B9427AD9FAE25 +:10FB2000F487F9B4B096A258B4B7D6B38871C13A85 +:10FB30004147530A76507C3DA91BE834021DD42569 +:10FB400018A41DFF9FB88EB1DDDED14AFFA03C2274 +:10FB5000518B7ED32E833F529C769AADA811DB0D3C +:10FB6000F7B38871BF9A683E8F26AB670DD2E9F074 +:10FB7000ED01F287AAA45C9F676046A0AB1B841CC2 +:10FB8000BF617DC73FC98EF8EEEC5955DAA18CFAFA +:10FB9000672897AA6EB4FB317E5FD59EE3A379797F +:10FBA00014F720486ADADFF760BE2A37D78171661A +:10FBB000EDEF4C393C944C58C6E59F911D967A96D2 +:10FBC000EC06748A189B21E8B906FDD124D21FCD1A +:10FBD0003100FFAAF5F53BD2A0BF3F3F0D7D40D1DC +:10FBE0003ED5BBEF67D0EF4DA0C4568CC2D4C84AF7 +:10FBF000290E9D4AFDDC28FAF1FD0BC6B506C7BDEE +:10FC0000A97D2FAD679F89F9AC40BFA6423EB4E9FC +:10FC10003FE2FC0D2808999FE86CA6B56512EAD76B +:10FC200093E6EE116EB47F5FFB6B960FE0FFF1CFB2 +:10FC30004FDBD12EFEC4D86DC7EF47EEFEC0AE013C +:10FC4000FC3EBE5B2D4678DF26F48D847787C07B33 +:10FC500042A2A70DF1727BDDF779DE10BCB3154926 +:10FC6000C43F0BFC30C310BB63D1E618B4847AF2F6 +:10FC7000D5AD09BABCD41FD516561B290EF48DE09C +:10FC800097055B3698335C38BEF72D1CFF8891D3FF +:10FC9000CF91ED76BF2F27389FF22D23CD68977C2B +:10FCA000D26E6101D483C64E13B37139A3003D787F +:10FCB00005DEC3E7B9FBF518EAAFE2575C2E95C144 +:10FCC000582B00AEDEF605247FC2D751F1B16B721E +:10FCD0000AC0BBE25E85E1BE0AD6BF1BF0E65D71DD +:10FCE000CF5768E785AFB3CCA79747739BF47929C3 +:10FCF00027AB04BEE7317713DACF152DFA7A55ED2D +:10FD0000F751FF556172EC7882B0AFF2D8D8B3608A +:10FD1000A734D8FAC779CFA1AF4ED4815C1FCCD815 +:10FD2000B13A2BA547EA18A56D092E82F7E2F6F73E +:10FD3000EF42BA59D2B6D58CFD34FA2739C64315ED +:10FD40004BFBCD0CBF5B705F159ACEC17D559827DC +:10FD5000DA3A88FFD18AE77BE44793236C9F55AC5E +:10FD6000AF54C09FD9B85D518AEB1981DF8D5F8791 +:10FD7000AEE7D49ED1561CD79C28E4F15858977A08 +:10FD8000E1EB92EB91EB93E5D52AD05984F692BE44 +:10FD9000DB04BDCDDB387D753A80A2E1B5CFB3BBC6 +:10FDA000B85F4AF6BC51E0C7685B43F6BC9181BDC1 +:10FDB000CED729EC79F621F2ADA4B3703AAA423835 +:10FDC000500087B7B30A3BBF877EDAEF2778483CFD +:10FDD000037FA48A7DB354DC37033A3A144647BA0A +:10FDE0007C458B3EFFA5A92B1BF91BE8E550287C21 +:10FDF000BF0C3B6721D3A4C4FE0487792E6DB203E8 +:10FE0000CA2B986735DF5F6D21B81C31B6ECFE193F +:10FE1000F2DD464EF79F08BCFF32D1332111F59534 +:10FE2000511B81F2BD70659A9A08F5CA9A1507F2BE +:10FE3000D3DCC69193910F47318DFA9B9310D94E25 +:10FE40009B93C8E15F5E6B6266B0EFCB610C946B15 +:10FE5000E5DB55E273A0235B09E061BEC043F5BD5D +:10FE60005BCD6990CEAFADE276829FF30BC095EC8F +:10FE70008485CD1D66A457F04722F29BD403D5ADEF +:10FE8000FAF21AD64C78A8413E93740CE3CF4E1484 +:10FE90007CE6666EA447EF5D76AB1277FEF5B2DEC8 +:10FEA00071058A3B9CDA3388ECCA532E570AD6F385 +:10FEB00002CE3BD15E367AC7E2778013E9A3EEFA31 +:10FEC000183FDACD07CE803F88369CC33B16EDA4A1 +:10FED000AEBF67B1354A903EE57A6AACCD449F35F6 +:10FEE0004CEF6F96816383FB9B659B12FC3E85FA0A +:10FEF0001FD18676C52613D90D3EB62C95019D7966 +:10FF00005699481E96B7C593BF5BDEC8F701CAB7BE +:10FF1000C4FB55EED77F38302F8887038D45E634F4 +:10FF2000C2538E9BE2C36D261D7D4BFC84FB8B0B65 +:10FF30009B3A76A7BA7AFB8B11F073A80FFC1C0AC8 +:10FF4000C54F73187ED8DD095CCE2C7D739015E605 +:10FF500077AA36CAAD46B037A41E6299408079C1EF +:10FF6000F853713AC70733BA93119FA79BC710BEC6 +:10FF7000C2F154FCC35CC207FBBB9DA13D3307FC2F +:10FF80009019F0FD7685F3C79C866B8B515F6F4AA5 +:10FF9000E472E63D904F9A99B1F7413E69209F3E49 +:10FFA00000B985F93FD7A552FEAF752E4AFF5637E7 +:10FFB00094D24362BF54F20D108019EDC2E704BF22 +:10FFC0003C9728E381CB53D17428FEE1833106347A +:10FFD000DD7D33AF9B94C5D8F59A5EDFCDBE51AFC2 +:10FFE000CFBA4C8EC9A9E8B7DEAB90DD57EE99A029 +:10FFF000ABCF8C2EF3740C6C0F1D1DFC4EF69CCBFE +:020000021000EC +:100000003C03F8FDE6A909BAFA339B3274F99D89DD +:100010002E5AF7F4E201BAEFB7945EA6CB979D0192 +:10002000208C466A76121E965B9930169D3C2EE80F +:10003000E075BFAE1D9BF21398EFD76F9BA83C1CD9 +:100040001F12AFF3D6199817A636771DAC0DFA3DDF +:10005000D402788276C7F7D9C9BF58BD65F4BBE32F +:10006000207F608B89E202071A131E40FBE8C096CE +:10007000A45806A977B52AEC08879985C8ABA2C60B +:10008000FADB502E95F92D6EB21776F99E947917FA +:10009000FAA33849E4970F553FC6B7007F3C2EF0CE +:1000A000AC85ECDD2360B7E1D6F8118535628A8A2C +:1000B000250ECABFE94CF2233F17FFA06AA9484F9B +:1000C000CF46517D8A5040F9B1F7073DB586E8CB60 +:1000D000D51A20BEB5903F30B78BAF8F29A3321011 +:1000E000FF47E299160F93A85EF6D7FD46C0D3826C +:1000F000C19D2302D0AE342790340BDA9DD868A27C +:10010000F320D8AF03F2D5CF59367039A2A54C1FD2 +:100110001E0A4FFF085CF71C83E7FF2502FE8E5581 +:10012000FA47903CBB3B89F82A1CEE87CC5E82AF35 +:100130000FF94009CAC7209FF17D1E106A69286720 +:10014000E69ADCC9A89F0E359BC8EE04FD113B9DC5 +:10015000E22B2F111D1F32BA26E3BA0F35E530947A +:100160005772DCF26695FC02A43FAABF56F5828D59 +:10017000C0A49EF235295E96D29B6EEE583A3605A3 +:10018000D7136EDFCAF44BE0556F88BDB0F035D59C +:1001900043E78172BB8C370E0F5D4723E7B754DE10 +:1001A000FF7221D717F7FFC37E9B01E5FA80388CD9 +:1001B000931FFD50253A3BDABF252F1548FF846178 +:1001C00047DE4F207FBCC477D808F9272DDE814950 +:1001D000B0A44586E66CF48F4EB61F7C6002B43B3B +:1001E000F6BCC98DC32E7C76413F8AE708FBBAB7BF +:1001F000DC0AA473FB404B53009E8B5CADA4B75D3F +:100200005B14C6D7EFE7E705841E773CA4A02DC595 +:100210000E8EB1AFC178C75C608F50BBFBA089DB8D +:100220000579495C9E48FDBE5CE4E71A385DB3D7AA +:1002300015FF2661EF84EA0129972725F5A7FA3DE6 +:100240007A99B592BCAAC4731DB0BEC59B2D7E7FA2 +:100250000EB571209F2FE0E861F5492E7EBEC7FCE8 +:10026000FCC3C84355AC93E67DCCE4AFECCCC1F6FF +:100270001B1A9DD4DEE4A6B8ABD027566020944765 +:100280005582EFAA5B147F80F886EBC50AD13F4305 +:100290003D1322BF7AEB15BD3EA9107AB48285C505 +:1002A0006D5BF4FACD1363A7752D8471515F06E77A +:1002B00005F631C0ACD2EBDF3D8DE6ADB8FD11E601 +:1002C00051C5BA03789EAE7A8BE20EB0DEF30A5FB8 +:1002D000C785CEB3D23D7D627C6EC8B861F396F01F +:1002E000A6C06F081E24DC2B7D1C9E95ED0AE1EB59 +:1002F000336197C11FC59B25DEAB98671A9E37A84F +:100300007A08E4654E900E7AF4FE56BF19EDDEE3EE +:10031000AC25D60674BF78DDD6995760BBF5EF9350 +:100320007F51EA0C0C32C4837FE7EB58539CD5DB3A +:100330004E08B70F7E2CF8E0EC8D79A21DC0A362A9 +:10034000A3AA458DD0D5A3F6D23E98EFF399319E5E +:10035000395FC409CF37CF1AAC37EA42E61BD99EC2 +:10036000F9DFCEFB8524E13FF5B2870645F4A37A99 +:10037000ECA0F3E8DF8F4C812CD4BFDD5946D23F8F +:100380005F1BDD7F2D48447D3C88FC82BEE46BA56D +:10039000D0C315A897213DBC6E5B2CFAED9F3DB4F0 +:1003A0008DF6FFCCCF57C4A25D7C78DDDC077CC026 +:1003B0005287B7CC253D5CF598D4C35E73A87E2FD9 +:1003C0005A57F6EB9F237D6E8E725BA0B8729757DB +:1003D000D8DD20EF500EAEE3F28E3DC4E56115EAA4 +:1003E000AB61A4AF8660BDBB2ABD4390CE43BE9334 +:1003F0001EBB6BAE772CB5678E00FA5D203903A863 +:10040000AFA43E957AD668F07E9484FCA3BEFDE747 +:100410009FC2FABF784925F7AE5ADD90EDC0FD8244 +:100420003EE4F6BF0F6F430FBC732E00DEE5086F8E +:10043000B27F38BC3F6DE2703ED8CCE1BE7ACB8053 +:1004400058F46F3F6D1A4076CFA75B0611BCE7AD3D +:10045000017893DDEBD2DB3D4D006FB4F311DE305C +:100460006EF92E9780B79BC3BB49E89D669ECEEB85 +:1004700005571F9D1BBDEB698B1BF5F991A8401219 +:10048000FA2347B6AA0CF7E57BEC2261BF48387F18 +:10049000C35A9E443BAA973DB3D6C21CD0DF829775 +:1004A000ED7E06F9634A410A22E044CB1F6271BC2B +:1004B000E0F83D768C23794C881D7381F859C23C55 +:1004C000747E7D49FB1FF6A11DAF68DCAF5F62B58E +:1004D00005906FC1DF39112ACF1517CA348C93B834 +:1004E000AD56A4834CE6D2EF1B7919EE1B7D3BE899 +:1004F000ABDB96113F770F0EDDD7A9890E9830BE82 +:10050000D4BD55217C572F2F882D60B82F554BF324 +:10051000189ECCF5B1A2691437B400DD44C378EE5F +:100520006417FFEE72F038E27A18D71E9C6FF8F766 +:1005300069487AA8CF6D06D2E7E1EBBF2D99FB2B76 +:10054000D5AA81FC8EC566EE7FC8F30F578AF22BC1 +:100550009379BCB72899EF179C8C62A4374EAE8D67 +:10056000F1D7D3FA26523CB3277E22E1E6307ED97A +:1005700023AF90AF44FC603FB68179CEB388782E2C +:10058000A8586C7FAB687F6BCB3BB42F079ECB1317 +:10059000A877E7ACB0B8D17EF5BD6621BABB279A83 +:1005A000EFA3B0C43823F2D12D42CEDEDA729F071A +:1005B000CF3DCC6989D13085717C4CC44F73711F9C +:1005C00036DD4CF1D3526BD7F3E866DF9E7AF04EFE +:1005D0002B2CADDEC0ED967A27A3F3239783D98E1B +:1005E000F15828DA7E36E15CF4A38F0F2FC638ED80 +:1005F00078C6096B1CC155975F6CE6E5CB93474DF8 +:10060000792893B13F31D770C4F762840DD2435932 +:100610001CC501AEC778B1135323D1D90C23F319EC +:1006200078DA84A135193F9E26D67DD33816888383 +:10063000F506F6EAE3D7B30286C010C0C3F5C6409C +:1006400007D2B5C1EA32A13FE0295646A19FBC7846 +:10065000E585CDF79EE42B69BE8B0D063ECF9F2A24 +:10066000FEA7004EB70293237DDE6664BBD4511C07 +:100670007F487F354E978FEA2DE5F42DE3E6124F44 +:1006800023A1FB50F8DE2AE607FD34C5627B73E444 +:10069000F8D183C9D20FE6F6E622C1AF8B24BD6D37 +:1006A000D1F3E936E4173C9F83762DC0ED5691F6E1 +:1006B00045EFAD82DE5B05BD3F29F2173A5EB58599 +:1006C0000568DDAF59088F72DCEB45FA4232B79B03 +:1006D000E53C243D3311873280E4403A3AD4D2409D +:1006E00076D3FCB038300B8D57A991F23DF2C7702C +:1006F000165373F73C9C8F7255941BE9FA5673EBB3 +:10070000A05A5BEF7A721FB794759AF8BD1B11CF90 +:1007100012FA6A926AA37341A54AB41BEDDF9305EE +:10072000769F210EE32D26426D29D003CAE78FA2C2 +:10073000F8BEFD9CB8BBA6A15D581A6B36627A3B29 +:10074000EBB4E7E404ED92D5052AEEC1C1C0D55360 +:1007500034C837A03CE1F9FBB44C8A0E89FCB23FA7 +:1007600062F98DDF01FE297FC7140DE4C5C9374545 +:10077000395B4EED4FAE1274EC5B3105F7394EFE2E +:100780004A96FF9C97DF2BCBEB79F9FDB27F915F07 +:100790001B565E1F56FE28CF773D5C3FC587701203 +:1007A000FB31A5E31592272E4167A52B0304DF52E9 +:1007B000C30E9E16B28021F7FCF56C291E5732ED50 +:1007C0000B1EB2A3DE4E48D35CC950CF96E43D8EDB +:1007D000DF174E577C6694931FFA070BB91EF15C26 +:1007E000AD4BD06D542AEF4FC21BFAF91AFBBBD8A0 +:1007F0007ED6E1BC9274FD7CFFEFF4332FB5573FFA +:10080000E6947FA39FBD61EB92765159BA9683FD22 +:10081000B14389BAF3658BFED31D877615C3F365A3 +:1008200000FA452B5BB34743FF8B5E7835BB32C480 +:10083000EF5E72C6C034B09F6ACE304A8F77FCCD6F +:10084000EC82F92CD9DE619E0CF56A202D0A99D72D +:1008500062794E9275196784E8F5C12906219FD601 +:10086000D27C17BD70D488F85C64683DFC18C67BE8 +:10087000C62B11F75D6345BBFD7DDCE71A96C2E52B +:100880009E2753BB2C05CF45A0CC407DDC10799F23 +:10089000FE4ED15F6934976F73F3EC5617C079CC75 +:1008A000877C9FB9727DCE288CE35E9E543806FB10 +:1008B000EB3B2EDACDE3A2ED3C2E5AEAEC5C0EC205 +:1008C0009BD5A66CB8CF7A2563531E917C062C0B62 +:1008D0006D8B2D32DF3665623EC5B9287FC3235B41 +:1008E000EF43BED913CDCF4DCC193B3C1AE542574F +:1008F0004E8CC101F2625C62592DE26FCED82B277B +:10090000E3F7028B7D70198FAB135D8C4BF44CC1F8 +:1009100072AC8F710DAF99C7B9BC6FA914E7F28E95 +:1009200088F146DA47BE56C0A136859F73DD03685D +:1009300046BB43CE438E0F86CAF24EE8EFD0CAB410 +:10094000916B5CB8DF515043F424C6FF65A2B73405 +:10095000747C58EE08FC7EA1F3B83985D36F0DE2A4 +:100960000DF198AF322DC45F9C31314697BF716A4B +:1009700002D342E3AD3766E8F2B34B07E8EADF3271 +:10098000EF325D7989A533B7F622ECDF1ABB3D1A49 +:10099000EDB08FDBBFF9CBAD68D76D54DD0AAC6726 +:1009A000C16B9BFE32016A9DC2E397FCFE14C5BD7C +:1009B0008EE17936E43DA3660CDDAFF98275D2B9DC +:1009C000C090FD00DDBECB22C72E3AAFFA63EDD753 +:1009D0003C9022FCDF516C14EABF53B57FA638DB94 +:1009E000121B5FCF17AF1E30E339063C177016E8B5 +:1009F000FB1A6CA8229FFB280E5DD476C08CFE915A +:100A00003B85CBE525994B8D6091B11A48516F4CD0 +:100A100006F91407F4D1D9C1866FC7731339763A32 +:100A2000075E7D66060869A423DFB0A5506F5153A9 +:100A300031E5979C89A67EDF533B27D379E4571491 +:100A4000DA2F28C998B312ED51AC7F078C57F2E228 +:100A500035C5089F25DBF9BDA712F54FB9D8CFE200 +:100A600096626A5FA2B23D0AD807538AB89E2D41AA +:100A7000DD0E7935CFBE06F5AB6A0E0C7E1CE5891E +:100A8000D94EF224EECC2D347ECD192BB5FFAD908E +:100A900017A62E3EAF49673CF45DE2BD3D85EF03EE +:100AA000CABC2969A311EF1598BA18D5BFEECCA519 +:100AB00094CA75BE35F4E9449463A6A4AF276700D1 +:100AC0007DBC95A838C8DC0893B7A76BC7C6B1082A +:100AD000F2A8679C33FCFCAEE50C3FCFDB9EA6FD85 +:100AE00009F96ADADD5D46DCBF6136AB03E1356DDD +:100AF000DC485765081FA93B6E36235E4C0FBD6F5F +:100B0000467D6C81B428A4BC5A9E3B0F93C7FB045E +:100B1000DFC97B0752BF30DF6CB2476F13FEB7E40B +:100B20009337457DD9BE13691CF1F8B285FCA73F08 +:100B3000A7798FA3BCEC2C60B35F22F9D8998DFB09 +:100B4000263FD6FC01CF5685ECFB2E3ACF3E6D9C5E +:100B5000CB80FB01DD3DEBE0FC7ABE757C2CEABF6F +:100B6000A7B215D8EF7B575FDDA9417F1D3F1B3D25 +:100B70001AE5BE1C5749E5F77098A3FB3BF4E76AFA +:100B80005E8F71215F97A073941BB463E13BC3F840 +:100B90005FCDEB96A71428AF89057F16C62F7A2361 +:100BA0002A8074DCF1469411F5437DA657491D83D4 +:100BB000DF874C44FF4D6BB71819D9379A01BFF73F +:100BC00035DFF3C9A7703A937CE96DE2FC5226E861 +:100BD000B45CF09F57F0D1E9DA14E2C3D377C3A431 +:100BE000719FF36E65F876B4075C76F72057902F07 +:100BF0004BD0EF81EF2597C593FF17C277C4878B42 +:100C0000CF38A8BFEA332EC1E74ECA4B7E2B17FC64 +:100C1000621176C43C41DF49E9DE91A930FF9206BA +:100C2000E07718C7BB322D17F928482F6607D21571 +:100C3000D04B6A6508DF3474DCCCD0FEB0247A88EF +:100C40005EE6411A6A7F54F4D81F8EC9C930EF6935 +:100C50008D39BA7B1679A91747F70352C5BEBC2D4B +:100C60003008ED55536D941BEF839D4AE4FB33CB65 +:100C7000EEE5F05B66F214A1FDB0EC51C50D9821D4 +:100C8000BB02E551DEBE5A7368BCF1E63323980B14 +:100C9000E070C39981945E9EE49D88F82F3B3353A6 +:100CA000C06BC4BFB50F3846E3F12593DFE2DE80A9 +:100CB000FB6C515E15F17B248B391E0C892F613C36 +:100CC0000CE362727F50C69B2CB89F1AA227BF31DB +:100CD000B664A3BFD32BEE54A0DF475BDCF1A73C87 +:100CE00003941FCBD128FE34C7E0BD0DF1BA708646 +:100CF000FF0513E417DDBF2D16E3DD129EADC6C060 +:100D000020D493AD00478C83B536ABC57E6ECFC47F +:100D1000F0FD2F4ED7928EC3E97BE199FE444FA799 +:100D20006B2DA4774E03BDB210BD23F58D94EF5209 +:100D3000EF487AAE3672B9556D8BA37315417D338A +:100D4000DD83715C36949F7F0BEA9BA71E188FF49E +:100D50007F3291CE3587D3FF2B75A974CE46EA91A9 +:100D6000707D23E5B994EF525FDD95E65D8B702AC7 +:100D70007CEEBFB7FD1D3E5D67E47AEB3AA39DE8CC +:100D8000E7C2E5E60121370FE8E4E6923EE4FEC360 +:100D90001749FF8DA23ED8AF6417A25C0FEDEFCFCD +:100DA0006985BF41FA7D2195EBD51F6BDE7DC9FBBF +:100DB0001752A51F7161F2FE7151FF7CF2BE43C84C +:100DC000FB70F9CEA03F94EF275FBB84F6A7F73303 +:100DD000D007A8F7DA635C9B84FC27FD101DE73F72 +:100DE00097FCF764CEEDE843FEEFF8DFC87F498F4C +:100DF000925F247F487E08E71FC90F53EE03FF0F61 +:100E0000F1F41EBF5F546DF46DA1FD4357CC48E46F +:100E1000CB1EBB6DBB427CD64B2F08BE09F2895E50 +:100E20004F48BE907C22F9A35AF04345183FEC543A +:100E30005B1F1C0FED6E4EF39E0EE58BC52F85EBF1 +:100E4000853EE90A2386AC22B196215D55431A4AB4 +:100E500057963EF8E14C0F3D5D183F1CBE407A8A24 +:100E6000493353BDFF437A8A494B8A484FB6B41F72 +:100E7000D19E385DFBD75C17CCE7742EC8D99C2077 +:100E8000BD4DF923E3F6C2006EF7EF89E6EBDC63B4 +:100E9000CEA278CE94B3FC5CABA44B8967690754AF +:100EA00088784271BAC78DF395FEC285E2D992D88F +:100EB00069463FA402D250FDDF97BD3B26EDE2F02C +:100EC0003C20EDC2ECC4C902CF3FA29D383D125E6A +:100ED00099C3A98B4380FEBB81ECB780918EC8F487 +:100EE000E957ACE37096F95501A3D4B709A86F810F +:100EF0005E66E078FF2EBD941431110F7C79AA96BE +:100F00000F78FF85C8B357A7227E668E93E5BF6D25 +:100F1000D606A2DC61328E4E7191F75491F7BDF284 +:100F2000F644A83FE541168CB343F9A4FCB89E38BB +:100F30008AC282F5973EBAFDED66C2333FF7C2BC66 +:100F40005D46BECF24F2B990B787E4C785E5D7F3F5 +:100F5000FAB1C62EC6CF29FA39BFAAB8F5C6E9C775 +:100F600013628F002627E3798269DB1507C6416E7D +:100F7000C93F49FBB1C1F5BF41EB5FD2AE88FCCEA2 +:100F8000B771BDB76CE7F9471EFD43B36FA0E82FFB +:100F900099E264F4676A55343CFFB0789CE2EF9FB5 +:100FA000D31BCE8FA4E9FD1BFC33EADB333C7F77F8 +:100FB00031ED11CFD4BE3FB50F582E62FC59F991D7 +:100FC000EF3DFC97AC27E209D43FC0F286D6C8EFCC +:100FD00097BC28F8B113F74D085E1F3523FC3ACDB6 +:100FE000129EFF68C67837DD9F81FCAB8FFE63AA37 +:100FF0006F189FBE16B6FE73CDFFF108EB77E9DBE5 +:1010000007CE05BF0DBDDA0BFA99AFA7A738A367C6 +:10101000D769E8270EFC7FB48B9778A29AD1FE0F90 +:10102000D2C761A28F4E19CFEF45FF9F4F9D682316 +:10103000FB47D43FDA8C7ACC63E8A9CFF941D217C9 +:101040005E05C2B3738CB7FFE0D123CD081FC00F7C +:101050009553DE780E7E680DCBE787F18FA07FE297 +:101060005F94F3009F4111E4CC29019F2FC4B9EA9A +:10107000CE426E2776F6E7A9339DDB85FF12F83660 +:10108000A4F3FA9DD1217008C133FC05D00F095992 +:1010900037C1E9E644B9EEA892A9B0AE4E272FB702 +:1010A000A59BEEF7E507F3E1FDC5A64795205C8219 +:1010B000FD5BDE41B974B3809B33DDFA8E8FCB4389 +:1010C00005F9B29A0804E862BBE253D14F40BA88EE +:1010D000B0EEBFF7A62B5F587BCD748EF65DBDDBFF +:1010E0006B61ED9929F762DA0BBC4D0DC36B71187A +:1010F0005E2786E54B65DEAF937F522E96B7AD5DDA +:10110000959C88714985EE8A06E939A504E97991AB +:1011100043D26F2AC13548CF69EF20FDCE6895F2E2 +:1011200030FD7E0DF0361DE5E1F860FE0694179463 +:10113000CF28D1E242F5452695CF6A92F5B3EE2746 +:1011400079DA28FBCBA6BCC423F3F52B21BCE60A35 +:101150007DE173BD83E50BDB79FB498FE5BC734E05 +:101160007E680983CBFAB0BC2FACFE43E7D12F8D4C +:1011700061EDEF0E2B6F0ECBAF0BCB37E9DB97CDCD +:1011800053880FCB801E1011E7E3CB9BD27BECD4AE +:101190001E7DAAD8C86ED3F1D594069EBFFDB111AD +:1011A000254DB6907CBABB24942FE4BD604B22231E +:1011B000BE30F5212F4BD2F5FE59CF7A8686EB5BF8 +:1011C0005EFE09FE338DF6777476C14E559FEF5063 +:1011D000E5BCAF7A67B92D641F945D5982F195BE65 +:1011E000F75B26944CCC0CB14B7CE34BB49075CAA6 +:1011F000FA93BF3FABE27877A68F2FD988FB39856A +:10120000621FD2C953D06B2AEACD1A118F998CE78D +:1012100063B15E7460D0B2503B84B50EC67576FC87 +:101220008CDF1BF035007E30BEC6DC668CA774C434 +:10123000C5AD7806EAEFFC99BA02F5E8FE15097427 +:101240002EE94FE9DCFFDC19D72FB902F21D31B7C7 +:101250009BF1BD928E7B2651BA43D5567703AF3DA5 +:10126000F8D8B525B64BB03C8EE0F38BF44925F5A4 +:1012700040D7BFC44B3BD0DEEB7424E3BD06B6C6FB +:1012800044FB7A8CB99F24BAB9DF3212FDE7B2FA77 +:10129000CB68DFAAFC57D327D3BD855526DACF808C +:1012A0003F3A7FE25D3389CE3DCD6B14A9EF1A4AF8 +:1012B000DFF8E1E906BC1FD9FD8442F725AEFCBA90 +:1012C000F58F23F0DC63D30037A2E675B0EBF13C79 +:1012D000D2A7EB86D03D898351B574EE13EA33ACC7 +:1012E0005FF59DEBDD69B9585F75E0D18AC3F01DEC +:1012F000EDE1C3F7AA4FE1FDC3B2587B349E973EA0 +:10130000FCBDEB5DB46BA1DCB112BE1F5EB5201954 +:10131000EDACC38A2B16DF1279F1B15925A9697892 +:101320002FDF22F039CB5E067C5E66E8A117D21F64 +:1013300095F13CFF62FAAC924D30FFC38F0EA17362 +:101340005F8333B4D674C0D3E90C6D2BA607C57D7B +:10135000E5377EE0FB85BF3F519E8CF4F47B41C7AF +:10136000AF9F294F2E0FB1772ABF3012DEDF30BB7F +:1013700096E33CDF88CE52E87C366B4DC078F73C74 +:10138000E17F00FDAED816C1EE79385D253C75DCF5 +:1013900097948F780DD27125C94BF21B20FFF6630D +:1013A000E5A4D70E5956B08368378AF38B6C67145F +:1013B000BFEFB825CA1F9583F14F6D32B663A9AD53 +:1013C0008367D843F84ED4FFD8C7CFE77E0CF5D15A +:1013D0007FFBD8F70F7BE83E84AC5F156BF7A1313C +:1013E000F1B9DD6E443CEC37D61DC6737D954F9840 +:1013F00048EE573E91747737CA1BA0178C8F85AF84 +:101400002B35C344F0EA930F7D77944CD4F90777DA +:101410009C930F0F3FB6AC64A3AD6F3EAC127ECA77 +:10142000E4274C744EBD6A8CDD88FB8F854FBCB9B8 +:1014300089EEAD2E8D1A85F713AA9EB010BEBAECB8 +:10144000769F03F74763EDC67848BF167648125E6D +:10145000AEC4B88CCA8CD65194D2BD04B9AF7774DF +:10146000C5830FE331CA63CC3F732CC0EF14220C49 +:10147000E0724ADECB0ADBE7ABDEBBCD5CC0CEB1AF +:10148000CF779EFD3D205F7A47E242F7F96232C492 +:10149000BD9F9E7D3E13BD0B5125F6F98AD6F3F311 +:1014A0005B552BF8FB1D45093CDE7BA8CE878FC41E +:1014B000E27A7D0EBC9FFB10D72F554CF15BE19F6C +:1014C000D7AC5F6AA4FB8FE91C3E65E21DA7835180 +:1014D000EE6CF4D32B9F8822B8563DB9E02F8F4293 +:1014E000BBAEFA92C450BF3847D003F4CFF09EAEE3 +:1014F000ECE7F3FA9F6723DD17FD1AFC5BBCEF17DF +:10150000CF5EB83907F194968DFB91B25ED5CA9F34 +:101510000DE6F5C03F063FB8EC5E95BFBFF6B2855D +:10152000F41DF0782A0BB9CF3CAF71AFD93C2C78C1 +:10153000FFEB53C8E395FB907B60668497BC978470 +:101540007FA979C2DE7691FCA077784B0D0ADD5F2A +:1015500002C945F77EAECFE0F6EBC40C7EDEA92CC7 +:10156000DB4DF75FAA1FB0B857E6F07E7AEE55E381 +:101570003927436725ED3FFED64271919AC6282D43 +:101580002A969F8B7869189D8B369A71DFC4C5E5C2 +:10159000C4F582FE6A5CD3AF417A81F27D463C8716 +:1015A00065E7F2B03A1EE0CEF5B06680714EE2BF5C +:1015B00006F07ED346848CAF88EFD08F2B36D8EFE1 +:1015C0001E036BC2B80BD6BF6404C23161E66C9CCB +:1015D000DFF32AF1312CFE817168DF3DAF8E46BF0B +:1015E000B6ECDE9D93D7617EEB48BCB1C0CA5EF815 +:1015F00080F4C52281FF2E711EAC1CF278DF7F7E45 +:101600000697935E95C77BE60B78493A90E5D5F748 +:10161000F2F350D5AB2C64BF54D7FF95FAADB67733 +:1016200026A3DCAD7ED944F79817897997D767E56B +:10163000EF03BA2A37C5D17BCB8B7D2566CC2F6EC5 +:1016400051281F6C97948D747ABCF19558A49F8390 +:10165000518141A887BA9746B9F11C9E8CB71D6F7E +:101660001CF414C665E6393AED781F69DEF2014EC6 +:1016700094DBFB1D013396EF6FCD31605E7338F262 +:1016800031AF192FA7FC7171EE84FE905E148EE7C6 +:10169000C55B769AFBC3782D822EBE78FE83C1A8E7 +:1016A000A7AAB33B07A33E013A189C81707E56213E +:1016B0003DBC640B3FA72EE96009D201F0DD424139 +:1016C000074BB6BFF213E4872588FF51BDE908E850 +:1016D00074177D7F69C364C6DBEF423A91FA0BF25F +:1016E0008D2627C6DF441EC6C1FC5A014F289FC85D +:1016F000CB7DC3F839B72E3AB75723EE2BF6C8A7E0 +:101700003EF0FC82C06379BD85E4ED0B02CF5DF74E +:10171000BE1C8B78FCE2F99DBB719FA4FA25C5C164 +:10172000F7ABC2F842C0A506E1104BEB20BBA20606 +:10173000D71D1B84430FFD0B7EAC617C9D72DD3594 +:10174000460107592EDABF88EB4C42F80AB86D1FE4 +:10175000C2F94FF01BF233BDCF23D6E775EADFDDC8 +:10176000FE3083EB83D744BA18E802EF6731BC9EA2 +:1017700028E504147DB17503C57D24BEE4BC0F07C4 +:10178000F58816EF0CE2B1CBC0EF2F86EBCB7704D8 +:10179000FC0EAC4AC96E03B81DDF4CCF5412BD1A03 +:1017A00043C6937423C72B7A6EFA75B85EE83F8000 +:1017B000FDCB71F7FB628CD8CF7EC6F903E913E548 +:1017C000A7E4CBA28639D78DC473BFBE2FEC0386A6 +:1017D000E17A39DD1ECEE0E77F34B413A0BDD6A692 +:1017E00050DCF980F0E70FAC7A25B63C044E874414 +:1017F0003B4967F887F12839DF3D4E1EC70D9FB77B +:10180000944372DE45F7CCBA0EBFCBF94B7A95F410 +:1018100029E128E954DE7F0BA757A235A93F559D42 +:10182000BC27FD784DE65766AFADF7F7F0BCB48343 +:101830000E8AF3DBDD498CC7EB1B537785DEF7811E +:101840003F5BA8DE09D127CDC6107D22F57F4DA2D2 +:101850007614F1559CC9CF951C63ADE602E877F18B +:1018600091CEC9F84EA2B43BAFFC3AA0C6611C6A47 +:101870003B3F7F26E1BDF8C42EA2FB6A712FA9EC85 +:10188000DE0F4AC6227DFFC644FB3165AB26D1FD83 +:10189000E3059BE6E621FDE07D0694E747378E19D8 +:1018A000CD9FF37224CFC47B0D1B1F9C790B7C9FB3 +:1018B000D7A6BA49AE433FC8AF65778E66482F07B3 +:1018C000A3BA4AC6A3BDFE53D581F6FA844D63EE92 +:1018D000C6FA13ECFDE2713DDAC604CA6BC638D213 +:1018E0000BD2CE95E7F21A4C9C1E466572FEB9A447 +:1018F0002755C479BC86C1B87FDEBD218ADE412A66 +:10190000358B7B9CAFA5903F5163C62B85742F947C +:10191000ECB0F966664DE3E79DAD69F07DAFA9F3E4 +:101920004ED41F7BEFB48FA473F5EA7779E5DC7EA4 +:10193000E6FB8509FA7787E43C468AF1C3FB93ED21 +:10194000F788F3C607C5FC8F36FE6626EABFA39B61 +:10195000073971DD9FBF1645E7F03F0F7BB7F06297 +:10196000EF6901DD86DD835AC9E545A6FE9C96A494 +:10197000F3F3DE53FA28316C3FE0DCE78B4ED431D1 +:10198000BA4F6D015F98EC9998EFB7E1B9BECA16EE +:101990008B03EFB31C42BAA7F33C2ABF776BE57CFD +:1019A0007068EB483FFA8D951FF1FB45BBD6DE43CF +:1019B000E70A2AC0AEC4A3543D76F2436B67221BEC +:1019C0009C727B57E33B2FA736F37310BDDE2DD8F7 +:1019D000BB6D77E8BB05176B1F5FA85D2CE30A356D +:1019E00099FA7BF112AED23F7A03F03F6E54104E5B +:1019F0005FD6CD27BBF8449D97D293CA8107262096 +:101A0000DDDAE3E8BCFEEFDB1E54F19D95EAED2341 +:101A1000BF43FF76BC2DCE81FCFA65DD0ADAEF3CD0 +:101A200051574B69F05D573FA5576EEFA0765FB6F3 +:101A30008D6EC77BAEAFDBE284BC0FDFD7E178EC05 +:101A4000EBFEAE5CD7B19F727CCA791FDB3C3716C8 +:101A5000D7D5F17842FB1588C7983807DA7755E271 +:101A60009CC7E175DC7E3E628D7B662A9E0F597FA6 +:101A70004332BE8353D171E34CFC5EF99AE240BB22 +:101A8000DFFDDAF4588CA37D66EC8AC57B4D9FADF3 +:101A900093F7A1FCF41EE9F86246FB4EE30346E629 +:101AA000CAE15BCC4827579C30D2BDD3E3B81F8531 +:101AB000718FEFA229EEC1C43E53C5AB3C5ED2E3A9 +:101AC000C70A3F6E8258F75B994EB97F40DF8BC6DD +:101AD000F1EF9FAFDF360DFB3BBAD1E4C0797FB9A0 +:101AE00091BFCFB010FC2FBC9A726433F76F16B65B +:101AF0002AE40F1FDD0CFA19D655BDD4A4F1FB9AC8 +:101B00007AFA2B82723CD728E96FA1E627BA0E7FBA +:101B10003F239EB5D2BDAE1F8B1E03997A3FAD8782 +:101B20000EFBC2BF8013F22DD2A1C4F3C2757CDFBD +:101B3000DCD93AB200E949E25DCA05795FA1C1CCBE +:101B4000F87BA58668FA3D80E936974981F5DF90F4 +:101B5000D83511C5E7B02C6E7FA845060DEFA1B1B1 +:101B6000064BC4F7A8FE26E4E89C2C46E93799DC2E +:101B70005E90F7B1640A0BC9423D3D3DC6F98D0B3D +:101B8000AA1C5EBF749A11E63F7D82F3CE016EC03F +:101B9000DBFA9F4C3302DD4E1FED7CB93FE4BB33D3 +:101BA000EFE2F9CB9D634C90AFAF5F316D22D4B7BC +:101BB0006769873243C691FDC2F7CFF1BB3FC17B56 +:101BC0000CD31A33BF1F7552E91EB1222758FF7D6F +:101BD00085EDFFBD12CC779918BD03F34DA69C7F10 +:101BE000E4744C96763A734CEFEFE58CADA2F3714A +:101BF0003E7EBF05FE3CD664BC7FC4E9A95CDE77AF +:101C000069D2DF77616E7EFF4ADE4392F78C2E0940 +:101C1000DE9F5A7F31F7A74E9A60BD71BDEFB329A1 +:101C2000ED7FA0F7B01A7CAC2B8AF0A0BFBF521D8D +:101C3000C3DFF75BF6F217BB90AC16487B05956DDA +:101C40005EF0FE3E4BE5FBFE770A3AFCBC8E0D1CB7 +:101C500008AC7C7D6767AC0B267B625A6030F2B7BC +:101C6000CBE2CDC8423F7E7D43E6B244BCF769710A +:101C70004F85FA47FCFC5EE562616FB28D4982CF09 +:101C8000D5C0D5506F4FCE25F47EC3A02CEE479C17 +:101C9000C80964E37B3ABE1CEEDF403D3ABF56BC48 +:101CA000F29A24AC7762EB3D032B006F167CBFCD1C +:101CB0004929C3FB4FD742DFE39CF4AE1B53699F16 +:101CC000D64FFD61BD58D4EBAEB9A93C8ECEEFCD59 +:101CD000493C49F8F7C20B4C01ED5183959970FED0 +:101CE00097B0F50EE453891FF9FEE9B29779FC64C9 +:101CF00099D2D59880F9E7153AFFF6B995DFEBE967 +:101D0000ADE7369911D4F3D7CFD5BDCF23DF19FD79 +:101D1000B1E34053B3847C19C94686BEE35A25DA41 +:101D20004E524B5DF8DEDBB2242BBDDBB1EC8901FA +:101D3000A44FD8DB77B0D07A6C7D02D1C7EA1C956E +:101D4000E0BCA08DD1BB3B256DE9745E716A9B93AD +:101D5000D2D833A9F4FDE8337FCCE5F287E3A1E4E0 +:101D6000BF520AE97CD07F0DA194F5F5AEB0CD4A03 +:101D7000F76897EDE57A69D94D2AC52799B81FEE1E +:101D800011D3F1D89A289EE36191DF8FF5C8F763EC +:101D900035D339DF8F95F0B508FC84BF277BD3DEC0 +:101DA000D1A9F41EAB784F76B6A8D729EE6D85BFC2 +:101DB0002B7B4FEC647A5776B65615F15D59A32FFD +:101DC000CA8DF6AD29D3C6DF6BF086BF33DB65C4A1 +:101DD00075CFCCE7EFCCDE343BE45D04F8CF94FF65 +:101DE00015C969537EAFF7814C48DF168FBE7EB3AD +:101DF000C4FF25EC9273BEE39B69A677DE8CF89E48 +:101E000033E4678A777CD18E43FBFC94C6DF95B3BD +:101E10008877A63B596E2AF2FDC5BED3FCFFDBBB1B +:101E2000CCE1EF2F87BFB77CD9E665BAFCF0D6FFCF +:101E3000D0D5BFBC6DA5AE7C64608DAE7CF49E5FDA +:101E4000EAF2633A1FD3D51FBBEF295DF9155DCFC9 +:101E5000EACA271C794997BFB2FB77BAFA579FD9CC +:101E6000A1CB17B03FEAEA17593FD0E52739FEA1C9 +:101E7000AB7F4DEA415DF9B5AEE3BAF229434FEBD2 +:101E8000D763F4FE0DE57C89FBBF75EDA631D72F36 +:101E9000F0FDE75989067AAFE31F59C27F1174F745 +:101EA00057A9B707B26C945F93D4FC00D15D9BC275 +:101EB000DF1F0ED363C6E31E0DE371EC157EFF2B0F +:101EC0000EEC3E63C878F19A151CC2603EA1D8A101 +:101ED000CB27795275F55366BB74E569DEA1BAF27A +:101EE0008CF96E5D3EAB769CAE7EBF159A2E9FE35D +:101EF0002BD6D51FD0E4D1E507B5CCD6D51FB2CEB1 +:101F0000AB2BBFC43F5F577ED9E65A5D7E78EB0AA4 +:101F10005DFDCBDB7CBAF29181265DF9E83D2DBAFF +:101F2000FC98CE75BAFA63F7F975E557746DD695D6 +:101F30004F38D2AACB5FD9DDA6AB7FF599802E5F53 +:101F4000C0F6EAEA1759DFD7E52739FEA6AB7F4D81 +:101F5000EA015DF9B5AEA3BA7269B74C19FA95FEFC +:101F6000BBB0634ADCFFD4B5F7158A77A55F52DCB6 +:101F70000D2E584F767FAEEF418046E1BB883E0F75 +:101F8000C57D9C78B00FE514DEBB76F27331A514E5 +:101F90003F4A243B8754910BCFE9801D108BDE55BF +:101FA0004E0EDAC931417B2CF36CC839B9F3D963D1 +:101FB000D764339AC75DD9DEFCEC24F43FB64EA655 +:101FC00077C1996F35CE43BE73F76ED87BC832BDEB +:101FD000D67A841943ECBFBD512D99A3CEE1BF5FE2 +:101FE0006B3DC1F09DE59E7E45BC4281F52D0BE920 +:101FF000FF01F0178C03196BA903BEC17DE13A07FD +:10200000E51FAA4BA5FCC3752E4AD7D50DA5F4B183 +:102010003A3795AFAF1B47F927EB34CAFBEB8A2958 +:102020007DAACE43DF37D6CDA6FC33E01763BA19BD +:10203000FC644C9F057F17CBB780FF8BF917EA7CB8 +:1020400094B6D635D1F797EA5A28BFBD6E1DE57F05 +:102050005BE7A7B4AD6E33A5BFAB6BA5F2F6BA369E +:10206000CABF5E17A07CA06E0FE577D475527E576D +:10207000DD3ECAEFAEEBA2744FDD114ADFAAEBA63C +:10208000F2B7EBCE50FE9888B72ECF5674F7956412 +:102090005EBEC720EDBF6968BF23718C337DA9B3D5 +:1020A000DFC3ECE8707CC87182EF270C7EAA21C4E4 +:1020B0007FF26573FF4ABEC710FE8E0213F6A97C3D +:1020C000F754BED75029E65525F8610CD2E750A247 +:1020D000CFB72FC65F90FEA02DC9DB42F49965F003 +:1020E000913F6CE3F7892F4FF23E983D06F70B2B9B +:1020F00076D3780E37ED1B96580249B372E99D707E +:102100008ACBF5355E8D38F7DD67F9EB4733D19E25 +:102110002EFE41A577B6DE35D967A3FFFF8CC0C37D +:1021200033D9065DBA2DC9BB09E7F3ADBDF6360359 +:10213000CCFFDBAB963E73474ED04FBE1E5D4DF0DD +:102140006FA6339789CE1532EDCD1CB49BC0B0C2BB +:10215000FC2CE6A3745CA2F705ECE76630B831EF1F +:102160001D6FC98EB4AEF079BD2AF0F56AB64197FD +:102170001E48F2B621FCBEB56B34AF77AFB86630FF +:10218000AE4BCEABBF7877641AEB7E12E7F7ED6B00 +:102190005F1D560604E12FFD71BAD78F726CA9221C +:1021A000DEB5EBF58E009597DEA9907D3607FC191C +:1021B000DC1F92EF069CAA35D13BF2F8CE00EE9FD1 +:1021C0009DAAFDCC86E40CF518EE6F34E0011D28C5 +:1021D0006FF829BF4F5F8AEF628CC2770BACBCDF10 +:1021E000BB15A2BBA4E41C7EFF19EC3DF29F12BB01 +:1021F000E99E1ED0C99F116E0BAF50E9DEF9BB06F8 +:10220000FF6085F6932BCC0ACCAF2A11E8A37FDFC1 +:1022100074B044DC1790DF81BE3E41B87DF9EAD846 +:10222000A1147F7FFD0A17C2ABC1C0EF0FF9DE52C8 +:10223000F9EF2E0911AD4E184E71466674BB315E32 +:102240005422EE9B74A86C45A4F7C4957E9C8EDE48 +:102250004DE5EFE73584EDB3FC53D0D53F05BD9593 +:10226000ECD84BEF082DD9C3DF3B64B95DC342DF27 +:102270009DE959CF8AB72E1918B28E9AB603FC7C05 +:1022800005EB1A167A9E3C5D8C2FE94835DBBD1BA9 +:102290006CA1F3EBA16BD60FE9271EE87A00D1F50C +:1022A00061DC579C6671C5CD82B40B4084EFFB782E +:1022B0007FEDA0F341F29CD03CE6A1B40AC800E94E +:1022C000D8E35B4BEFB92EC45F62C5F778C6CDCDBE +:1022D000C67C0DEB9E980A70BBA9A9FE4D7C0EEF43 +:1022E0008696B59330BE3AC35FF626A6D3372A87C3 +:1022F000D14F05BE88EF87F110A576151EC9BC65C4 +:102300004BC12ADC7A99A6727CB03F727C00DD68F2 +:10231000AAB3F73A810FD2F83A345A871A5BACE382 +:1023200083D2954C531283E7DD7BF862DCA24F70B9 +:102330004B8D19BB69DFBCE6758B13F1BC9071BD89 +:102340001D8C67487DCD88CE17B16837D63B26E80F +:10235000FA581623BA3EA630BAA72EED4896ED4D90 +:102360001D3520A8778F19FC79B103482FBB71BDAB +:10237000BB536F70611C6C51A295DE3F3D16EFCFD1 +:102380000E7BE783DE239271AC074C3CAE143E2FEC +:1023900065DC6EFE7B1866E6C3FD09FCFDE33CE4EC +:1023A000677C3747A177A0BB90EF4D851E57A4FEF1 +:1023B0001B45BF7BBEE7FEAE0FD683F71B7B8DE3CD +:1023C00010E344F371A4FEE8F9BDE564A61B6F7A3F +:1023D0003FCECFEFDA359A7FBD219EE44D9AD5EB03 +:1023E000417CC9B88EF403F7E47C3E90FCF5EF1A0B +:1023F00032D13EA77708D0FEBE8ACBA5774D2E7A84 +:1024000077F7DD821C8ADF4B797BFD381EFFBA5ED1 +:10241000C6BBF2C3E25D61F116961F39FEC598DBBB +:1024200084E35EC23E92F0A138CB8E7C23E15DFE58 +:10243000BED20EE17F9E2A4ECC453AFF5D3F5577D6 +:10244000AE40A66B447CB439ECBDEB35B9CB1C78FF +:102450001EC0F23CDFEFBDBF307A7EE839F42707BB +:10246000F1F329EEC1059B114EC36CFE4252CB9A8B +:10247000D185F356C43A2E73009C0D686F7A449C44 +:10248000D36DE5F1A589A497257E2F542F3F6BF4DA +:10249000AF8CC67526F2DF19B0AFB392DC545BB5D2 +:1024A000001E89FE72D08C5548B7CCE8198AE374B7 +:1024B000E445331BD4FFB6C34CF1A7D70DE5BFC627 +:1024C000F3EADD7FB3303CDFD06ACF30A271DBFAB4 +:1024D0003DFF5DAB56FB84C9FCDD491683EF638E7F +:1024E00074B0A75F44E4887B61AD0ADBC31F69D584 +:1024F00062F07DB756033B7D35CCEB25DBA8072F7B +:102500002712F3A8B8CE67077AD7E13CF2582DE539 +:10251000EF377BE66F8071EF775A892E0A077A1EB4 +:10252000E7F364ABA6C2FCAE2A52E8F7D65689DFC1 +:1025300077B0BBA375EFEC7ACE0C263DF14C3FAEE5 +:10254000571B53B54EBCD0D127DC1CC66EDDFB58E3 +:102550002C93E272128EA1F872E4E9F0E53585E27F +:10256000ABE7776B24BEF8EFD65C28BEEAFA319A67 +:10257000AFA4475FA16BEDC45CAEBF1AA89623174A +:10258000FBDF119D312CF47701243D4AFA8C4097F2 +:102590004B77A2DCCD323830FE79CFD468D263924B +:1025A0004E257D7E9CD343A743FA631CDEE69984C7 +:1025B000B2229C4E31BE154A8FA57DD22D7384F276 +:1025C000E534B013E29C68D71CD9D81A428FA5B560 +:1025D0005F19B99C387B75745E301E372D5F619F23 +:1025E00086E215FEFB74A8581FD93546F2A724FCD5 +:1025F0002E14CEA61BEB87A29DB61AEF0D02BC9A35 +:1026000014B79602FD196B0FDC81DF57897BBBBEC7 +:1026100061666E3F09FE90FD7D39A8F038D2A37D3A +:10262000EC89984AA8F76DB2C185C059E52A7F9117 +:10263000F86D5F0CBD37119BD039FF69E29F210C0B +:10264000F7F3BE5DE0ED87FBEAF7029E3EA5FB399E +:10265000FE14FEEE61570A7F5FD625DEA1F7A6F2D3 +:10266000EF4C94FB297F474E7FE15768A27E17D538 +:10267000BFD7DC628DC67172AC8EA742E8FC6A11CE +:102680001FFF1FC180237D00800000001F8B0800FA +:1026900000000000000BED7D0D7854D5B5E83E3309 +:1026A000677E330927C9240CF98133C92484640265 +:1026B000930410446512020D083AFCD520890C8A57 +:1026C000DEA82493426CA3D77733908001EC2DA22F +:1026D000B568793AD042F1AF3728A5A18D74127E42 +:1026E0002E5A2A83D5165BB581FAACB60582785B83 +:1026F000BC9796BBD6DAE764E64C2680F6BEBEEF02 +:10270000DDF7E65EBBB3CFDE67FFACBDFED7DA8791 +:102710001C59C7580663EC52BB3C3F99B11C59A0E9 +:10272000FAE36D5B7D1FB818DBD016A2327D6E8890 +:10273000F94B19B31605E520F433AF65FE2E1B6384 +:1027400097F1373D5A3EE014199B04ED7D4F311946 +:10275000FAA5BB3C821FFAD9E7C278458C7E97E187 +:10276000BF5B180B8E28877E3B98974D646C9D6CE1 +:102770000D0585A1E3DD925175544C19FA7CB0FD2D +:1027800006819D3647C7C5DF69751E3D8CFF57BD65 +:10279000BFCB8D35878E6532D6827D65C6AAF3E0C4 +:1027A0000F9CB7D5B8DD04F34E965369DF9FDAABC3 +:1027B0004630F7F0F33DD3060B2F642CD466A67297 +:1027C000479BC48246C6BEDBE6A0FAAE3699CADD98 +:1027D0006D45543EDFE6A1F617DBA650FDFB6D5EAE +:1027E000AA77B5D550FDE5361FD5F7B6D5527D5F32 +:1027F0009B9FCAEEB6062A7FD4D64CED3D6DAD54F4 +:102800009F6E62CDB49FA2A063019C47E78346AF51 +:102810000CF06954CEF1A0372FDD6367CC52A4636E +:1028200026E86639B685E17E2C0E9D3704E7B0DEDA +:10283000B185DD05A5617272A73002F6FF92AD5336 +:102840009800EDE2E34C86E7CF08C106E6616C91A3 +:102850003CD6278E62CCE5F84A551AD46F974B3791 +:102860009B9D8C15CAF36BD7C4D4E5E4F2FBF64804 +:10287000D1FA18F776D10AEDCB421336DB05BE0E3E +:1028800096C5D8BD72B96F0DE051388F0511EE03B2 +:102890004E636807B4AFC0F31271FD12ADFF66D688 +:1028A000EED0C1FAC7C8C6722650FF30B35F7BFFB7 +:1028B0004659A6E7F1EF5DA99F6EE235F563FA2B65 +:1028C0008C87EDC215C6310B0BCD1158FB2603FCCE +:1028D0000F3C0F66D8423B015E9D06B6CC0770EFF9 +:1028E000B4F0F28893D3DFB3CEAAF14EA0A3F14E99 +:1028F0007EAE9D96A05485F397EA3C3B109D5B9D70 +:102900003FCF83F9BEFABAC836CA51FCEC403C80CE +:10291000F70AC6247B711EF68FE65001CCF3A53171 +:102920002F75A441BDE03B1E8F1EFA6F621E2BE285 +:1029300049F0511DDB09F51726E6A7CD87EE259353 +:102940007E90E6077C398D7C00C609315683F8B647 +:1029500066DD3D63FAA1FCD309FF1809D6F9B83248 +:10296000CF7643A499CE73928DE1BE19DB9CA473FC +:10297000407F071CD2758CE946F1D268906EC77E05 +:10298000C675461684F518FF729DD907E3B55F3406 +:10299000D5201F612C92A49B02CF2D7E29159E6FFE +:1029A0000EEA882FB4CBB69000E36EB2951F95A1C6 +:1029B0001E94749E0284A35B4770ECB07D39A4879B +:1029C000F144614D03CB87F54A2F9B9DF03CE4D643 +:1029D0004948E721EF821AAC07FDA2A74056180428 +:1029E000B6FBD3421B715C36F0D309D85EC73C08F6 +:1029F000877599FFDE9704F5F6C59247CF7BCBE24A +:102A000064C646E15F3065BBA17F6D12AE6309EF1E +:102A10000F7F79E6031DA698F8F97DA377B6945742 +:102A20008ACFC5603FE74BC2652044D1E0317BA02F +:102A30007DBCADBCC60BA5985C6E96619F1D52B95E +:102A40007939ED9FD918CC93CE387F6A97743521A8 +:102A5000A5FD2EA477911D724D2652A2F60EDB968F +:102A60005E84877837634E19D707F3A97C0FE0613E +:102A7000CEBFE1A80CFBE8BC278DF6210A1EAAB345 +:102A8000BB455A77966C0DB3F1708EC6794719F035 +:102A90008F2CF3FD73B13EAA41FCA03F864F8FF40B +:102AA0006BEB19B5DA7A3A83BA393AEF6F14F91148 +:102AB0000FB778788C923A4EE0FA47F9457A18BF0A +:102AC000FEA7A427522B19AED346EBCCB4DD59098F +:102AD0001082A17D6B10FFFED6758E9716989D30E3 +:102AE000FF78BB0EC1C926B081B538EE2605DF3BA5 +:102AF0009DFC3CA374A557E97224D2E598561D0BA2 +:102B0000C6C81D67D0CA8231F3E577A669EA059B7E +:102B1000B334FDC76ECDD3B48F0B156BDA4B7697FC +:102B20006BEAA55DD76BFA4FE8AED2D4CBC2733453 +:102B3000FD2B8E2ED0D427456ED7F4BFEEE49D9AA0 +:102B4000F6A9FDF769DAA77DB44A53BF71E0214DBC +:102B50007F20E386AE04723255E1571D0E6FC49B91 +:102B6000409EAB2593C481C1F300DE69720066C745 +:102B7000CC97ECB1021247EBA099481F2629759219 +:102B8000EBEDF25AC4E71423E1B388F21CEAAB1E62 +:102B900034864C88FF377964E42F2627E763FB0AE5 +:102BA000BDA39DB0AECA1433C905D1C6FB89B659C1 +:102BB000A4A78CDE0A7CA902EA121B6C4F42FEDC41 +:102BC00016F4B95CD1755BA4CD0CE9B732A586F5D6 +:102BD000DBA2EF8B9297F993713E99EB3F5290FAFB +:102BE0005964783F665F07743A66433EDE0B7202B3 +:102BF000C6EF4ACE1691FEBAFE525C4D65F2B4594C +:102C000088EF6512FBCEBF40FF2E811D65A02775A2 +:102C1000E9D885E9B0EF976DE58F83B806D6E8D39C +:102C200023BF9BCC9AA91CAD63562CB70BFDAB19E7 +:102C3000F473379FA81A09FD9E77F9BDB8EFAF83EB +:102C40000E81FBFAFA78AE67ADCB9C23A35ED6E982 +:102C5000EC3A9A87EBC900B9828420FA3CA857A8BD +:102C6000FBBD4F394F31AFB31FE5DFAA54B38CFA28 +:102C70009268DEECFB00E0F58CA1FFB976A877083E +:102C8000D2CA2EE48B0FDA3C3B19EA8F1C6E72B26B +:102C9000AE622D8CDBB5C62BA6427BD706E6E9409B +:102CA000FAB057AE4D85E70539CB7569480FAE359B +:102CB0006BB1AC73E611FCC6B9B7EBD2A1BD6462CF +:102CC000652D43D92BC17CE9C3E3933E652BC3FD3E +:102CD0003097F821E2954E063E034BAF4C83F386C6 +:102CE000792D78DE02950407CB455BC8827517877E +:102CF0008BC52B8492A06E777905AF1BDFDB4AE78B +:102D00006B096BF5D82A97FF3EA47FFB5CEDB98A6F +:102D1000E627687D9B749C2E3A53E563289F3B9D74 +:102D2000AEB47639BA4E95AF3CA0E86BEA7395AF76 +:102D3000FC0ECF2023AADF009E6FD5E5A37EB699B7 +:102D4000217FB23CBC99215E5BA4A0CC500FFFA7B1 +:102D500020E1B9AADFAE5668A63AAFD68CF2FA8265 +:102D6000BD9CF4594BEB2E3AAF78B859FA75CC7B31 +:102D700005B8A6143E4DF21D18B05C00F0E9CBB4C6 +:102D8000356C4FA0F78F50F4850D40C61192573E19 +:102D900033F26B831EF455926FB06190071724468F +:102DA000F28B7539A9BE3A95D7D5715667948FBC09 +:102DB00092FE6DD96A66FE987D6C8079102EEB2E9E +:102DC000CDAF41B8329188836DFA8B7BFB46A02F43 +:102DD000D5AE19A1E82B39383794A38D8CEC028F2E +:102DE0007D6E0DD29DEF621E09DF83CE346AF7043B +:102DF00099BE99D66D50E592EEF2045AAB6C54E54B +:102E000030A9B65C6EC1FFF75E1690EFC7C8315EA1 +:102E1000905C57E576C1666DFBD8ADDAFAB8D09014 +:102E2000F7DF42B9BF98FF0D7241DBFEB422BF1736 +:102E3000A3FC86922D3290DC33C38A2E73B91B9586 +:102E400083C01772BBC295C846735A62E421A37D42 +:102E500068E463954B26FCF31D150D788EBE8B60E0 +:102E60007C540CE5CBA34D1CDE7DC6E4D05A78EF34 +:102E700051B08BFCD0753DD8437E20B5AF8B9E5FA3 +:102E8000D6A19D7554EF018C1D3CA7F873F5E4A9FC +:102E90007AAFEF2DA403C6FA2B7CC97C3E7FCC7C95 +:102EA0007DD694F10CEC965D85FE5F61BF4F6AECB8 +:102EB00013913F98729801E913E767CAFCCC88FA2E +:102EC000333FEF4D9E379B0FC23A1E396942759CC6 +:102ED000CDD41F3BDA06F555B922F133E9BA95CFC7 +:102EE0005A810F54FD1ADAE19D47647924E9E947D4 +:102EF0000D0CF5F42A058FAB14FBEB9902038DFB47 +:102F000089225FCE3A55BD276845FD172C022BEA72 +:102F1000B325BB81176BCF3389B77B49DF2DED8A92 +:102F20006FF732A4E362055FA06EAB847A9952EF2B +:102F30006242BA04E738A1B6BF0F4D09F76B87ADFF +:102F400088877B2C5C7F7B5EC1874C2678C2B0FE75 +:102F5000CCDD364F08FA25EBD99E08ECC373483C0C +:102F60001D7BEEE37BB475378BA93B711DDAFAA3A9 +:102F700072B3807079B40E7474D8B2352FD9FE61F3 +:102F800009439817227ECDD4DBCAD09E5A55696377 +:102F90000857D3A9B1DF8A20FF38A1672817A424D6 +:102FA000F9B16A785FFA69BA678D1C3DFFE7DB907B +:102FB0007533F6E4650FEB009EFCF52A6B03EABF60 +:102FC0002FC279A21CF93ED8D9D8DE05E78AF59739 +:102FD000C1CEC6722FD8D9F87C1FD8D958EF063B7E +:102FE0001BCB1F819D8DCF7BC0CEC6BAA7B072749C +:102FF0001E9C4FBDCD375340B87A455902BA12A234 +:1030000070661F1661BD5FB80C045227B17E13C0F5 +:10301000F5F81899CED7C47C0CE52BF37BCC8897B8 +:10302000571FC7AB8EE337241A670A8C4376825941 +:1030300042BF481EBC31029E9F79F057BB505ECC08 +:1030400013FC1E5C6FE3A4D346AE3F0F18B1FF36EE +:103050000BE03FF0A11C850E8255004F94BBAFEBF7 +:103060003DEDD0EBA619A7566780FD5D95E79C2F37 +:103070004E85FAFDA72A4643BD73C7A6F968CFDF80 +:10308000F4BD53AF64030F3E9B378FB73F7EEA42D8 +:103090000EB48F605F9B5F0DED29E95C3E6D1358A8 +:1030A0006DAC7E776B1EC7F340EB169273C0DF19D1 +:1030B000C2A13DD347F2F19C7D206539F40F640C29 +:1030C00064DE7905FE1D687D92E4507BCAEF49FFFE +:1030D000681F94171E9217EABCAABCF844C13D555C +:1030E0005EACB2F0EA603F7F3E3D7F5CF1EBB050FA +:1030F00001D5D32DBCFECF55F271B47B003E64E701 +:103100001E4C29FEC60D6857D6881E13D41FB795CE +:103110005B50DEFCA3C27F60DC20DAF1C199E6D00F +:103120004E3C54BB4CF498A68E6F77A1D2C5D29476 +:10313000751CBADE1A463BBFBDDABC03F5C92DB615 +:103140003C1AAF7D8A3188FE15B5BEF6FAEBCDA8E4 +:103150004FA4A6A439B1AEF2A78D80F758C24F8F05 +:10316000E35629DBAD32DBC27AE4E766C31F63F5C1 +:10317000641B8B10FE7874609000BD19F3395E55A6 +:10318000304F2D3E370ACD4144C66DB876DC47B28C +:1031900091FC0C8C65F375ABFBF066F37DA9FB48E5 +:1031A0003606957D909EB4C5A60BA3BEB705F685E1 +:1031B000E305F264824FFCBEE0E7C371674C51D671 +:1031C0002DDDB017D73153E7EDC0F70E7F566707F7 +:1031D000F462B358B388CFF3C1A2FDD04CA2B3E3DD +:1031E000F215F40E14E41FC6C8AD9B7E2BD07ED81A +:1031F000FD463A97CD057CDF4F1B434E46066E6871 +:10320000D482E4E1F1F78521F8EB65484FED695E82 +:103210008EBFD240CA1AC4DFD481CCB5B4AF70C25D +:10322000F388C7E3F8F3D907FF2972408FF0BDDABE +:1032300079AAE7A8E241BCFC32E64BEAF93A689F7A +:10324000DE224E07AA1EC5C0CE491E0ABFF5309E1B +:103250005C18AD1B1D3ED28F0D764F11FA6FDBFF50 +:10326000AA6F48E4BFFD5081D39A142BE9CDED2914 +:103270005C6FEE4D99A3B177AAC1FE11003FF4E94E +:10328000AC0BE9483FE276F27FE947A28684EB8AFD +:10329000D34747CCE5FAA804FA688279D552447D31 +:1032A00034819E3AA88FA6CDE1FA688A91F4D16D57 +:1032B000C9C6DAED09F8CD813CAE5FF7E23E12D81F +:1032C0007B60E7911F52B5F38C929FEC35759F0799 +:1032D000147C57FB9BA466867E31BDD123A3BEA977 +:1032E000B772FDD104DB2C8A91DFEAFCFBF30CF40E +:1032F000FEB70BB91EAF3373FDE4A6E3427322B8E9 +:10330000FF5981FB7078F737E00DF185729BD18B07 +:10331000FA41B9CD5185FAC170EF81A919FC282D68 +:10332000CA573C7F9DAC27F9237A1C88675D86FECF +:10333000578EA31D77D846F246D59BC14EF57AE04D +:10334000E53DFF0114A81B6A9F82DD24E5C3787D5B +:10335000AB3227F2F140BF2B1DAA4FC6FB0106E995 +:103360003C659793BF171A85EF09ABA68C447C8AFE +:10337000A773B5CC75BC9EBB02D6953BEA2895EAEF +:10338000F3FFC9F4E4578BEF3F365F853F97C7E300 +:1033900060B2117A92C36371DD675ADECCF4C05219 +:1033A0009AC4F3248F3F699E32E21199F3D9DD2844 +:1033B0005FBE22129FCDB9B737352DE67C9F6EEBED +:1033C000CE155D182F88E456BBC80EF0265AEF4282 +:1033D00075FEF018E2CB06E5FC657B64F65880B715 +:1033E0006CD379D0150D425743FF95626AB504F34B +:1033F000E7B6318F0DEA4E26911F2BF7B29EF02CC7 +:10340000F7E012C2DF31F60121E88E990759704CBE +:103410003CE4D3E66AA2CBDC9183F61BC50D3EB536 +:1034200087E7235D7FFA045F51EE77B4ED205BC937 +:10343000CF7C4F8B358426E09887251DD6739F154A +:10344000588E13D771D0F908FA697E98447E1AFD18 +:103450005617F9599E15FCD3F2812ECE84E4AFA203 +:103460007D4B3FE8D7F835EB8E8D24BF22B3497EE4 +:103470003DA0633B13F8916ECFE7F6DCD27C4E5F44 +:10348000B98E3772575460798CCEFB5AE9A813F97C +:10349000358CF3C888CD14E70A56B122B4FB3A0D37 +:1034A000805709E8F45FF3957899CA8715F859D0E1 +:1034B0004A817DE80545BFDBFDFCF3CF67A2BC6612 +:1034C000A8DC0DD29B3A4E525117352679BC0CFD23 +:1034D0000D82E4E5FC550A3A8218D7F98B3E215E4D +:1034E0003FA99CDF1AE77A07F6AF76791C4807BD3B +:1034F000CEC98E3B017E369B919962F8AF8A2787B1 +:10350000922793FEA18EB32A39EF8A76B611F8B0CE +:103510007C05F96C447F37EA317D53CD32AC77BD01 +:10352000AD3C827AD67A9BBD9CFCE636E017317EB4 +:10353000249BED08E1A1CDC3FD6B36E4BBE8475207 +:10354000F6DFEB3C42FB57FBAD52F88FCD13E67133 +:1035500047B062B09F45F405D1BEB0D819D99316D3 +:1035600033A7A724380E730C1F51E7BD3F9FDB69BB +:10357000EB73CA2395B43E113D016CBDA3DC4172CF +:1035800010E18C7AE8A8413D94FC25CF297056C7FC +:1035900069EFE5FBF4B53ABCD5E9687FFA9E45BE14 +:1035A000B0DE76A73988F22079E215C77B255FD097 +:1035B000F87BA2E3B5CE50C67B0EC7D327974B3816 +:1035C0009E01F94402FC0B2BEBFAA2FE3080A844CA +:1035D000F61AE37A1560BC2391FEA09666C5AF3556 +:1035E000F43DCE279D8ADD027CF218AEBF31E7F4B0 +:1035F000914AEAC5ED95B4D9629108E7F5099CA016 +:103600005E88DAEFF17A4CA57E80E4992A8754B976 +:10361000F434EA31C6283DA97E97EC061FC96BC178 +:10362000EE23BC01BD4646BAD163BC3701DC24178A +:10363000879B903245467AA9BED49F4D723EF9A32E +:103640006C16E33F53F9E1A1CF7659B0FDD386AABA +:103650002BEA2B6A3C78B83870CA43BFFF4AACBE2D +:10366000325C5CF86AF1E0BE1423F9DD9E11B47C93 +:10367000C9EAE2FCC8E052FD27FEBFE0393C23F86E +:103680003CA42F2A7E947D857EE642BF57A79105F4 +:10369000E13C0F7C36D981F871ADF055FDE6598AD1 +:1036A0001E9565DB25209D66358404F47B673774A1 +:1036B00009DE2BF47B07E93923DADFA08C3F5D1CA0 +:1036C000D0A3BC9AAED071F6459115C5E87F6FE5E1 +:1036D000733DCAA0E8ED297DCF5970BC3E9DAFB3C4 +:1036E00010E5438A4EDE1943EF867BCBCD5531F092 +:1036F00069C7784E82F32B770DEA5B6417A9F2D67F +:10370000A0CA09BBA8911381248EB7AABE13B89E84 +:10371000DB4182E02F41B89EBBFEF7B7E016CF0930 +:103720006183DD79F578C6A05EA30B2D57ED17A454 +:10373000972E83DCDD4FFA558A07FD00AA5E55F609 +:103740003D211FFB79042FD1C924E6A7F23AC6F523 +:1037500040D0AF6E7091BE075B89397786AE88CC5A +:10376000ABEFAF00FDE018271023E44FFDFA2581F1 +:10377000F87B3CDCDA06E13618CFD3F845B315798F +:1037800097ADB4CBE81775627C4AEBB7AC38AAADFD +:103790004F8A68EBD79D8CF38306BD6FBB3279FCF3 +:1037A0001F07DD06F4867C628512B7CC09862A25C0 +:1037B000586F2EEBA2F86076439A06DE37E995BC87 +:1037C00009E61598BA4EF8658BF33EC6F75B5C8345 +:1037D000FE3BD2BFEE51DAFFA17AC5573BD096DE51 +:1037E0006C20FFA819264778FDC3EC0533F1BC8790 +:1037F000F8579BB57ED5ECD87680C33DDB0C9A7626 +:103800009FB78CEC82858ADF7670BFB88E0CBEDFE6 +:10381000ECF2A1F35F7D5EF82F6DE8FCEAB84F0390 +:103820001F42FECA2EC1B94E46B831F440B05C31D9 +:103830002C609C3AAB9979514FCE6E61DE44FEFE0E +:103840005D0ABCE2E1CC82D3097E33946759363DF0 +:10385000D9ED592D3AD20FB3804F207FB86525900E +:1038600011D4B357CAA45FDEDAA063281FD8A536E7 +:10387000CDFBB05CF27FAAE7FE348E87FA65230B9E +:10388000E9703FCDC54467B4AEBC283E00BC4E7362 +:103890007899095EB74E3168FC9CB9E8D78C818B6A +:1038A0008A07D971CFBFE492347401726E978BF09E +:1038B00084CBBF02947FB0A433534FEEEA82F5DD90 +:1038C000B496D17E0752AD219E0F31183FD05F1EB6 +:1038D0000B7CCB3CA308FD2C9B24AB0EF3160EA453 +:1038E000F67F9BA532D60D6A71750E633FB10E94BB +:1038F00008503FE46AD8D27923B45B065E40E7AF54 +:10390000CD16585013534F49695F5083873685C988 +:1039100022C0C78A33C03EADD29CDD7A98DFEAB6BA +:103920009153D2CA06E994F6D371BDFC28E67D74A2 +:1039300014E8487F62B1EDB08FB20249A1036F1164 +:10394000F18F1A1EC78F1D5FB45F61FC3930FEC452 +:10395000CF31BE99AF3F131F81DCC9C4F5A3DF1A75 +:10396000C7C7F345E751ECFCCA78220B6EC7780B4A +:10397000CC6713F87C12E69564326D1EC1E07C12B0 +:10398000CC57FA77D84FEDD0F3305CE93C6EFF7C32 +:10399000E7D1A1F3D27A83E36D64173168D64D463F +:1039A000FB83CF6711D921B19CC3B5637214AEA05C +:1039B00007D2B8D07DCD6505CE0684B36424380F18 +:1039C00007B73E89E7356D90ACA135CEFF03E7E53B +:1039D000E0E7153B1FEA93D73CDFED309FFDDAE7C8 +:1039E00043F822FD0CC217CE646DE6B5C317561519 +:1039F000BC16F8F6C1B8BA18B846F3879E92D02E16 +:103A0000B0187C660FF0DF9B0A5249DEBAED0BCC92 +:103A1000944F90B1C08C797AEBDCB61ACCE75BE7B7 +:103A20005A6436C4C8E975EE3A6A87FE94F7E40E24 +:103A30005BD16DC14A5984FC021B6EA8762C47FCF1 +:103A400069E679546A5E912A0F9912AFA47DC18B01 +:103A5000236EDC3BD007FD37344FA4BCB111A9FF66 +:103A60004EF9529B1A3C1E6CFFB685C71D9F54E24F +:103A70004E88A8E4571B7FFD7730FE5A5EB04AA0FF +:103A800078E3CA2BC71BCBCF47AA30EF8A2DE77943 +:103A9000558E3A314E1E6AE97613C295E73F85048A +:103AA0000E5FCD782D05193C1EEDDAC1D0EE7B05F9 +:103AB000C6D26BE94B877948F1F4281ABD5225EA42 +:103AC000EBAB74B48E6C0CED83882B2F9DEB580EF2 +:103AD000CF73EE163D023C1FE97E98F29140DB2742 +:103AE0007DC3ED3E5685F521FB5CA1DD47FCBEE2C2 +:103AF000D70D828BD6AD9E57F9794F12DA57E5056F +:103B00000B285F8C7E2ABDEBE3F6938E76B1CE6BED +:103B1000198F7641CCBE98A69F62BFFDD7D6EF44E1 +:103B20006442BD303E1EF64F3E5AA78979CC467A94 +:103B3000AF8EEC4835CE9685B483E73E9AF1384592 +:103B4000FCFB93F9FBCCC1E36E262B98A4407FC20B +:103B50007D56F2679A4C5087F3118CCC3C0A9E3FFD +:103B6000ADF803D7084CC47A74BE30C3F9DA05DF68 +:103B7000668F134B6E4719527D946F8861DB587BBB +:103B8000B40FF338A07DD5BDCE91E8CF1B01041151 +:103B9000417B5A8953A9FE9394FCFEA528BF5F2C54 +:103BA000F8688119E5333A9CAE676CFFCED35B822F +:103BB0003951BA345DCC62728C5D63129B299FC30C +:103BC0007471B4C6CF1256EC31B5EEB58BD5385FF3 +:103BD00004ED05CC5F625207BE5709409163FDA614 +:103BE000171D9A71A2E3E768E60D835D1D1B171888 +:103BF0007EFC242617C58E9F37CCF88571E34B09D0 +:103C0000C78F8E9BAE19779DC8F945D06E0D25F2F2 +:103C1000F39D2DA87A1B4979B87CB33305DC0F08D6 +:103C2000FC58A4389482378F389A29FF4C6FE5F1FD +:103C30005283123F3998DCC0F32472B4F967554CB3 +:103C400012B17D5DCAACA302B457D9B47AFAF44B71 +:103C5000A7F5C877A68B5A3DDDCB9A093F6F62DA8C +:103C6000E7861C2D1FD8A8D0872E796284F2D43223 +:103C70006C9477309C5FE1DD3646F95386245F33E0 +:103C8000CA3863E1A5B4750EA88FE0F8652F4C5DC6 +:103C9000887EA277153C5E07748F70AC5B3572BB73 +:103CA0003E66DC3A63B800E5489D8EE7EBD30FE64D +:103CB0007F37238BFCACF1F352C66F8CDFABBE5960 +:103CC000F0B962F6F1AE421783F3ADCEDE8E7AEC38 +:103CD000E07CA6F0249A6F30EF47992FF38BCDF755 +:103CE0009E42CFEA7CF55FD5EEAFDE18A1FDD5EBA5 +:103CF0009892E7CFE77B0FF7E7FC02F329F95B83A4 +:103D0000F37D4DBBBF7A5384F6573F684F2AF36566 +:103D10007EB1F94CC6668ACF3C26F0739DBB6BD44E +:103D2000E3E8A7BF3077958CF8A6DA67B7E00B8099 +:103D300067B728F94DB7E618496F50C7DDDD3685FE +:103D4000798DDC9F8365D10D02E5FB8F9B22783155 +:103D50003EB60DE8DE5B88FE2A89DA436D0E2A77CF +:103D6000B4C9547E17EC412FF9AD3C54FF1F85DCDC +:103D7000CE7F6C94B46405EA0B95569EEF7CC334F9 +:103D8000D044A3F61618607D16CC2BFC322BDB0832 +:103D9000B5C2AD1C1EF6EACC109E93B5EC50A40D36 +:103DA000EAA6A97A19F3B84D4EE64BE48F692DE4E3 +:103DB0007E9E47D4FCF81B051E7F077DA412F6BF2C +:103DC0004C0135D3CF1550AFBAF56BA9A48FD42DC4 +:103DD000EA4F96601D7708656FBB001EBF51F491D6 +:103DE00065A3391DC7DB9376942C13317F4F1F0ACF +:103DF000C19F0B9317923DBA70316369F0FEADF825 +:103E00001EC895E38A3EF346BF89A1BD16ACE67194 +:103E1000E73B1ED6DA918F59C212EA718F95D919F4 +:103E20009E475D8BB6FD11258EB030CEAEBC352ED3 +:103E3000AF06B44C9E1F827B9ECAD80385DABC9A1B +:103E40008A4299F3B91C3B2555A7CD768DC078A43D +:103E5000C998F81E8E3ADE33AA5CB67B090E6A1E3C +:103E60001AD3BF5846EF2BF3A9EF3D2DBC38EA4AD1 +:103E7000FE4ED0DB3EEC2FE2F219F5EB8D71EBBC80 +:103E80003037EF1BD52C11DE0E88E85750D7FFBF17 +:103E90000B5FABD1A70178747CC6A713290EC37240 +:103EA00068DFB7A8F8A3E4572D1CAC8B4C8CC9AFC6 +:103EB000638E01379EF75B3726793612FE29FA4367 +:103EC000F81DDDE5A4CF3FDEE03A1CDE5CEE8FABF3 +:103ED00096283F48196F3838C7E73FA87E1BFAC5B8 +:103EE000E41FB66FE7F98F59F6AA8FF19E143E3F93 +:103EF000ADC12BED7DA8F6DEE704B42FBE8DF7BB78 +:103F0000C4E87CE8BF0D92FEAABDA715BF2EF5FE42 +:103F10008DBA9E76232B227B5407FC01E69B67EB30 +:103F2000170519FDF10322C5CBC7723F11E608F34F +:103F30007B2F5CCFD367EB783EC71899EB7DAE81C2 +:103F4000D1B1F1A28F0AB95C9F97F4668B0CF2EFA6 +:103F5000FDC2C042CC579A37E2CD1627D44F153652 +:103F60002FC47CA679D96F7EEA049DEDB7855FE109 +:103F7000F592373FCD83FAFF2A5CC5EBD31801E5F4 +:103F80007785AB17225FFDA85052FC97911C9C6F60 +:103F90009EC0F1E58B967A932E613CFF7CA1EA4F9F +:103FA00064069CC7D7F3AF27911FF954FFAB571B8B +:103FB0008764D89489F786949F3D85F49939F837BA +:103FC000C0F36631DC8BEFEBCC6182EB58CCA329DC +:103FD000221478E2F215F225E2F14800746D457D75 +:103FE0005996581DE8C7EDADCC6FC98FC173E65522 +:103FF000F09CE7F5A8EB51E71FB22E3852312D7631 +:104000005DDB681C755DE7CA4C41BC5FA6C655D533 +:10401000759D13069E4167C49C929D8BF15CCF25D4 +:104020000F8C16A0FEFCD8B7E99CCF650C3C23781A +:1040300062EA067E8E23C73E4A7A4F8BE01D391610 +:10404000F9A5D146F7D83A153D6F53863FC8B87EDB +:104050004FF98FC15C7E3FA07AA2E08D8DFB3BC7FC +:10406000F2B8494829679A36379F007C0CEC15D87E +:104070001AE81FB874C188F6F8BC9E5346B4BB9BBF +:10408000F69E32A25DDD847518A7699B91F8553CB8 +:10409000BC778ED56BE2EBAA3D7138B7709D1DD60B +:1040A000D3B442F060CAECAAFDA933B1BE6A39EEBE +:1040B00092B1DB6FD83313D1A5DED7BB0ECB65AC85 +:1040C000FF30DE9F5BE2D7EAF94B1BB47A797DB310 +:1040D000569F5EB6194E07E4D7B2D66CCD7B0C3531 +:1040E0006458CF12E53C97381E8DE8C7633DE65E05 +:1040F0008E40644DFE9DA57C07506AFD16F37A0440 +:10410000A2E3A65A33F95F0FE7F27CFAC04A3DE515 +:104110000905101DB0DE2C28FE2C2FF147557ECF4F +:10412000EC3E7F241BDF5F692038B0A037827EFD24 +:104130005A059F96D5D67C8C78562BDFC7E5F89824 +:104140005D06F2AFF8B93E2E2BFEEFBAEEC7AAD34A +:1041500050FF6C11C8BFB1B441ABAFD7E31FA8BFCC +:10416000B50AA1B013E1A46D5FD6AAADDF355691B3 +:104170006325AC04E9A461AC2012DD28F53FE6FE1E +:10418000E28D304CF490E0BB7F2C1CD04A63783C2D +:10419000CAB587043FD5D57678DEC4E50E97F73AE1 +:1041A000A028E2BB06EE5708360A848F4B87C8FF6B +:1041B00018FD403FB4FECC582EDFDA2DBE16B29764 +:1041C0005E1524D447AA45AF98E68EDAB3F1F8F825 +:1041D000AC82DF6FB07E37AEAB10810EF02F5C3853 +:1041E0002284FEB0C29F2CA77CC7C20AC1A3237A37 +:1041F000D6B1D6722C45E20FA86F5AA02CD477D531 +:1042000012BF9E6094783EA183C5F201EF734CC04B +:10421000BC3E5C3ACE7B73CED1CFF01C6FD9FAE8AE +:1042200079E477AE7C6FF963B0BE4D163EFFA6FD14 +:1042300002E9AF4DEE23C41747029AE0BC4D0E854C +:104240003F76037F54F70FE73D12F9155E1099EBA7 +:10425000A67947A9F10135DF365CA5BB0CE73752DB +:10426000997767A94CFBCEBCAF4BC07DE7B2E01A93 +:10427000F413FDF3584670544BD58FBF381AC776E8 +:10428000E279363AFA8DA47F2B71EC04FD4A12F6DE +:10429000F3328D1F61A6FE520AC69B57BD9A7FC599 +:1042A0007C0BBD59A7A1578364D5D0F5CD455A3AAB +:1042B0009FE7D1D2F7AD53F235EDF3BD259AF685E0 +:1042C00035159AFA62DF344DFFDB6A6768ED7DC70A +:1042D0001C4D7F8BBC40534F2ABA5DD33FD973A787 +:1042E00096DFD8BB28AFC0680EF6FB010E9D80ABF1 +:1042F00053D2A2FCBA24C58C49C7CC5A61B161D94A +:1043000059660AE3B97566F138ABE9B5071C6184F3 +:10431000FA8817CD9550BE2084AA305E6456ECBC56 +:10432000E28799869F8F2DE178AE96EF8FF57F5CBF +:1043300004A57BB79CCDF3A723C5783E66742022E5 +:104340001EEF3393DE31214EFFFD5E69E56F51AE06 +:10435000B81FF6CE26BF543793F0FEEC0E23CF7372 +:104360000AEEE3F9B4EEEE7E9D3786DE02455CDEB2 +:104370007FD35745794B4D3D20CD10BFB79E36A218 +:10438000DFAEA9A73705E5C678DF6923EAD7D1E70D +:104390008A3C1107AC18BFFC97AEC4F969638A8CDC +:1043A00034FE1185DFD63FC0F92D20DC5CB48F547C +:1043B000FE59BF87EFAF7EB191E85BE5A3C03F3503 +:1043C000F1B078BEBCF486D03AA45DE0A31AFB65D8 +:1043D000D9A2591FA33DC45898F418E0A3DAF69C5B +:1043E000F544DFCBE2EC9BE422E0A7A8479430F74A +:1043F00065A097933E5DC27DB94BF8F7024EFA6710 +:1044000010BCBF097043BBF19B43E0C4E17735F8B2 +:10441000BCA4F813D5738AEF5756C2F9E84BC3F022 +:10442000CB078A78FB0E21528ECC2CE0B3129E2E45 +:10443000359B1763FEC191DC3FADC77842FD0F0489 +:10444000B465D9AF7B5FCBC47C04E39EC399982746 +:1044500011E83A9CC9004E2B0DF21AD48B010F3C87 +:104460006BE05C9ABAC3B4FEC6AE8A5E7CDED82D21 +:1044700078901506F69E9F45FB64FDEB518FDF316A +:10448000CCBAA615717D785691CCF398FD3027CA29 +:10449000D9BD26B263EBF7001FC275ED17E85EC603 +:1044A0008E0DE6DA44FAC9648437C0E9D00623C326 +:1044B00038CA4A781FF77124F788D18C78B347201F +:1044C0009B30D0756231FAE3032D0686715B757DF2 +:1044D000677223EFE3FEDF596160788FB07D058F4F +:1044E000C7BED3A2A771F4771BA8BEE45E9E377C3B +:1044F00070C56FD767C3B8EFAC1428DF7EC6DDFF89 +:104500007604EB4BEEE57A503CFE0EE26B1C7E2E01 +:10451000F16BF16E089E367C313CBD338AA7E351C6 +:10452000CEC2B9CF1C89F8F320A37B8CB5970E1AA5 +:1045300046C27AF3D64B1E0CED96EA43EB32912F2E +:104540001CE4ED652BB70B9CBFC874BF3DBBD3C843 +:10455000D06E7C4039AF0794F392D98080F96E4CCD +:104560008CE4E1FA9C4A7ED7CB0656BB07FD482275 +:10457000E72FA53F746C8FF523B914BEA2F2BD12CC +:10458000B0F7F7901FBA2B0BEF9DBF64E0FEB1D1DF +:10459000CA7805F903B3E643F9CD22CE07DB94755B +:1045A000A875AF82FFCCBE83E03BCFCCE13EA73500 +:1045B0005C87FBB847F4AF2B82F6B9A37FB1925169 +:1045C0007EE4EB6E3FF9B98A49AE0594F33838F5CD +:1045D00077DB56631EDE382B9DE3FCBEA72278AE48 +:1045E0004D2E91F20F2D051347FAAFE047085C946A +:1045F00035F7F89A7ACECFF226A0EB69CA7A4B95B6 +:10460000FB7AAC87FB0F801F8B53CAA3FDD4FDAB95 +:104610007E0F4BC177E99C567F8595F17BFC8FD14E +:10462000FE97AE3C21E03D95DB0C5E830DE0FC8BFC +:10463000116C31DAC1AFB731BAB7760CEFAF012BDD +:1046400079A34DA27A44B9C7F6669B4CE56D46DF67 +:104650006E84CFE243CD0508AF83B94FFAF0BB0CAF +:10466000E78E29FA2C93F8BD4605F72EF4E8991940 +:10467000DA2FEC1542E43451D67FC7C52CE6077E0D +:10468000F22BE5BE5C63EBCF89CF791ACECF423BEC +:10469000A36CE5A9F5580FB4FEDB2CD41BDE07395B +:1046A00081F815E8169803C6A9BB9846EF37769FA0 +:1046B00030A23DFF926E6016C23F7840A07B5681CB +:1046C000E6F3C43FB729FE958F8A781C31D053A6F4 +:1046D000A3F3F41673FB4439FFDEE27F4F41FE651E +:1046E0006E958F4FC3733CAAA773DC583590222573 +:1046F000389793302EE68FFC4AC9D38B6FAF3506BF +:10470000C92F5BABE06D7CFB070A3E02840D4A9E1D +:104710001213603D750A7ED5E3F761D250CF17C200 +:1047200056A0DBFA9E19E4DFA86FBEF2F75E86C3DF +:10473000B76B2D9B18F76FA875B4BF62F3B8D0FEA6 +:10474000D2DE4B0FD23E4CB9AE91FE2BE87781FE04 +:104750002C8A9F3475328A97345E2CA6F2ECFE4781 +:10476000E81E94D93AF024CA0556A823BDBE31A844 +:10477000D56F8E17733A385ECCE9F95211D8276697 +:1047800036689F801D7219F112EC90943EA6B14FCD +:10479000E29F937D6256FC86A02EF95F4EB0EEB785 +:1047A0008AABC4711948579B09BF19E037E255FC21 +:1047B0003E478CE3EB52E97949DFC746D47703DD06 +:1047C00089E9F937C5952370DC0DC3E4E5BD5DCCFF +:1047D000F95DE35646F00A6C4D23389D615B7D55CB +:1047E000809767601D784FFD9CCF97940AEF9FF3E9 +:1047F000FB92303EA7D27FD3562BBDB7C1B5201D4B +:10480000BFABE11AC7BFEB73B67B8619E17CC75615 +:104810004E77EA7CEF8797A423FD4C320C18D13FEA +:1048200099D3732A05F5BA49FB17A623FD0DB74E98 +:10483000BB721E8DAD598BE91E10FCF440F7F72BAF +:10484000722CB0366C44F8DFDFCA087F7BF7FDBA04 +:1048500009E9F76C4F928472F2CCAB4941E4F7E777 +:104860000E98423A186AA5F23DA43386FE5B487F53 +:10487000DCAFA77C85C0813F3C89F418D867A27B58 +:1048800035F7F73C721EE5DCCA9ED91F8B58BEF87F +:10489000F7A587C6D6D18B63F38EFFD0B63B0BF955 +:1048A000E75991F389FBBB5F217DF6FE4B17C66389 +:1048B000FEE09957FF6332F2B3C04F2E4C463E16CE +:1048C000F8F185C9D81EF861527322FD646609FFAC +:1048D000CE862A1F9D6F891A3FCB39053F9C1D9BB1 +:1048E0006BF0BB05934E2CA23880DA3EA940E7C39B +:1048F000FE93DEAE4EBF3BE6BD8E8848F912134FE5 +:104900005427AD88C1CB0F8A0DAA9FEEDAFC234A4B +:104910001E82EA1FD91011F93DBB067D08F37B9773 +:104920004678FC3DDE6FC298EFE6523CEF7B333CAD +:10493000F8BD1EBCA78E7191730F1684E89E7AD0C5 +:104940007CD815A3072D89E8C226F483F498C2A861 +:104950000F2D8988A74C317E91F7A597D7A11ABF53 +:10496000C4AFF563C4FB41E0972CC6C44FEA5BC2F9 +:1049700006554ECD83F97FB18E4918B719E21FA9AC +:10498000FD12F961E2FD2472E40933BE27BBF8F79A +:1049900075543D13CF6B6F027AB72974A2D2514779 +:1049A0004447E7D011A932BBA03428ED7B416C0607 +:1049B000312FA867E14EB4D33B2EDD9684F0EA7820 +:1049C0006B01C3EF479C93AACC05F8DEA52F99177E +:1049D000BBA3F831847F8CE37265501F1846CE1D4F +:1049E00051F8D6DF4BDEF58DFBEF21EFC0AE7E6DCB +:1049F0001CB7AB9772BF07B7ABE3E584CA7FD5712D +:104A00003F53E03D94FF7E4CFA0BD8BFC47F3F1B61 +:104A100027F3EF34F4CC4F27BBF8AD45E9B26DE88E +:104A2000F8F9A24797E61E3ABEAAAF0582DEC36632 +:104A3000B463BC3CFF34B048A0EF48057C02E9D920 +:104A4000813A4308DBD5F54416F1B8E0628F40DFC8 +:104A50000551F53F553F1C6C9F08EDCEA8BEA8EA56 +:104A600085111FF78B2EF21AA8FD36A37F60DC2478 +:104A7000DC9F859E4F9ACAC7053E7018FD9FB77D83 +:104A800059A0EF76A9FAA28A9FF1FAE4273DF957D7 +:104A9000FC1EDD36052F55FA1A1D4717AA9C7229F0 +:104AA000F06942399D8E72FA3363BF6D78BD1BE4A5 +:104AB000B4584CEF31C2DB896F8BBE4476F7B7C672 +:104AC000717E6C2F56CE2D72A812D79BCB229417D5 +:104AD000359CFCFCB498D3C370EDAE715CCFB91AB1 +:104AE0001D4F2FFEFBD2F1B4E2FF1E743CA8FF194C +:104AF00013EFF3ADE2CA6A3C7FABBE99EE4DB19FB6 +:104B00001AC86F1DDFEF3305FE20CF34787C38D70D +:104B1000A843BB27D0C0EDFECE54F938D927AFF15A +:104B20007BF8F72BF94AF75D94A8ECC40F8561FB7D +:104B3000034EF2DBDCB7FB84C10BEF2F6D11CAD043 +:104B40001FB4B441BB9FCE0CEFEC583F78E7A82EC2 +:104B50008A2B0477E6CB387E3D6E16FD219D5921C8 +:104B60008C3D36A11F67023E8FB98701F3342ACFEF +:104B7000A729FE1D16A707FCB8F71DF2F7605C0811 +:104B8000E9D7D823505E48E028F77734F570BEF0B7 +:104B9000518340FCE423253F23D06A21FFB6AA4776 +:104BA0007CACF4BBF74181F4BD217A85571B776952 +:104BB000FCEEDBC417E3F588B4BD7C1C8CB7A05FAA +:104BC000E670EE6401EB8D60178E447D51966FCDDB +:104BD000E6EB6321E22F5E8D1FE593A3BF253B72B9 +:104BE000E97E81A593DE11177FE99C13177F397247 +:104BF000381BC751F40C09FE0FFD87F17A4653F7B5 +:104C00000903DA05578BB36C2ED6FA05C788DCCFBB +:104C10003AA64790D09F344681D3751BAC04A75960 +:104C2000EFAD48473A57CFE7EC7C7E5E67DFF9B4DB +:104C300012DF9BFC9E2821BFFDF13B2D3FCFE67587 +:104C4000D92CE37B2D4968879C7D6F5512C2F1C733 +:104C500050E2F7927E78524CE83FFC6BF1A0DF788F +:104C60006731CAB78715BFB108F22D39EA7F897F4E +:104C70002FA784F3A94EFC8E11E2DF7E1EDFEE1C0F +:104C8000E59F43F5A7F2781EB1C8F1F5959E54094A +:104C9000F5BD12D82CC661BF6F651D185FE9CCF059 +:104CA000BF4EF4F1948EF017DEE7DFA1D82393BC5A +:104CB000C3D014C63FC683AC31535EA39DE220EA45 +:104CC000776246811DAA7C576111C65D4B9438C836 +:104CD000782B1371FC4D06FFC6711877E9153D6BF3 +:104CE000F01DD1938EDF458A8FC7A8F161352EA3C1 +:104CF000C689878BCB0838CF788E67B1DF3D51E30B +:104D00002FECCB3C7FB37D4A33DD8BDD8E3112E25D +:104D10009F43E2297F463B353E9E22A2FCA1388D6F +:104D2000369EB6B1E865C2B7CF1B479B5E3CDCFC44 +:104D300032B7E7E2E69F98FA4926D92F7FF9730A3E +:104D4000C9B39E0B2477CE0D9894FB9DFDDC4FDDFF +:104D500063207BFD1CD8411931F26CF9380E87BEF7 +:104D60009E19848F7B23D549D8BF53D17336BCB5E8 +:104D70006821EAD3C188C8F3B119B76BF646C449B4 +:104D80005C3F180227A93841DCC96C4D9C071456BA +:104D9000FC056165DF33DEE1F64AA085C70F248597 +:104DA000DE023546E22747723305D58F3C32517C0F +:104DB00061FF00F1D9FA7B797CF79AE30BDDBD0640 +:104DC0009697C06F5B338BF8CDB5FA6B195AC193C8 +:104DD000A3FC39AB44E127A58AFFB698E7F3A735D2 +:104DE0009755E2F7EFC2C39EB77F634982F34ED077 +:104DF0006FABFBDAE281BFBEC6B8616AD1B5F51B05 +:104E000093881E12F49B7E8DE37DF31AFBB55DE360 +:104E1000BC0BC725EAF7FF68FC333EBE191F0F8D98 +:104E20008F739A5EBB3B886D8F088F0E8411BA29F1 +:104E3000FB6A05205531F5BB66E46B73A7F278C0B9 +:104E4000866A7368BB108D8BAAF00A9672BD4B728E +:104E50009F0FE27712477B23D5E940C7E7A632B21E +:104E60001BCE5994EF2389D2A8F9747E127D1FA717 +:104E7000D39238BE3451196F383EF2BDD2CAF548CC +:104E80002FD230DFAFC82DE17680D4CDC85FC344C8 +:104E900079D4029A571E45DFDF3BC49FA78419E5EA +:104EA000F741BB7301E9CFB213D7B745897BA5CDD5 +:104EB0002974A29F2E0DE42DC6451EC3F808F9F5EE +:104EC00025EAA7CE97ECE6F36D313001E358C171C6 +:104ED0003CAF82757C5F13D73866087FB05CA0B8A2 +:104EE000C6765CFFCF7461F70E273F1784AF7BAFA8 +:104EF00044F19637A67EAF88EECB2B718ED512EF9C +:104F00007210ED0C58C7EA572B087F97F64DFD65D8 +:104F10001DEA832E91E03C440F57ECAB938A7DA8A9 +:104F2000DA57FD6827C6D81B3F50F4860474F58312 +:104F3000447C698BC0EDDFE0CFB8FD5B61F4E4C772 +:104F4000E653F52A7192E561EE8755EDDAF1DE90D0 +:104F50002E13E050F1A03E6C02395DB1BED488FC46 +:104F6000BA627DAE95FC4A2BF6E85478273AF79F53 +:104F70002AEBDC707480E212AFC4C52793DD466A69 +:104F80007F48C19F643C5B28571788ED287E47DC2B +:104F900020E913F9C5EB41EFC7F52DEFE4EB55E33D +:104FA00020F5617906CE73EAF0C07A2CCB1B9C33D6 +:104FB000C86FB8F2FC7A949B814B178E4C273F80C8 +:104FC000514E745F604B29F71FBE828A08C26BB6D0 +:104FD0004879BB15B3453AEFB47A0BD9E16906A617 +:104FE000C7EFB0A6CDE772ACBCC63E03EB6C512A4E +:104FF000C9E1F2A372EADDEEA89D9F36BB2503E16D +:1050000074B5F890EA2FB8CDE8FD6349C6E78F0F75 +:10501000351E7B8BF2CCEEE8D7C687D478CF70F103 +:1050200021353E1BA8F954134F0E8803B3D0AF525D +:10503000F1EA298A0F07BA05C9E18CC68D027BCF38 +:105040001B09BE4ABC08FA1BF1BD0A38F65169F8C3 +:105050001D021E3FDA87F9B846FCBE9E4479B73F71 +:10506000C27CDC42FCBE1ECFC73D80F9B846BCFF07 +:10507000C1F371FB94FCDE40CF798A37A5B987E490 +:1050800053513CE221C197E19EA48957503D3E5EB9 +:10509000A1B7723B3470D440DF3F0F1C33139FAD78 +:1050A000EC593E06F531F5BBE44D182F88F12F9DE4 +:1050B000F57A2C78BFE7ACCF63C1384145EFC746DE +:1050C00099F84E381B53989AC48811ED7D8403E5F6 +:1050D000F9F5545A10AE57F5EB77FF7FBFFEE7F1B5 +:1050E000EB7F2B4A97C43FCA7D3ABA575E7ED46B9A +:1050F000B93B863F6CF071FFF006571ED1DF13BE3F +:10510000BCD415B17EFC1A6EBFA5CD7659629FBF87 +:105110005BCAFDF86942E2FB0577B987E5B777B965 +:1051200013EA3B89E3011B6A381F51FDFD43E3038A +:105130009ED75C317EFEB33F33D3BFAFD0BBDF44DD +:10514000F2FC4FAF9A76A0DE5D5EB3624C32D4CBF8 +:105150004F9A9893CB234D5C61698DCE6B4949146E +:1051600047F066D3F743E3E305353AE2EF83F18294 +:105170001AF114D515FDFC8EF3BF4BC64F94BE2219 +:10518000843AD1BE78A551F0F4B2A1F10318389B4E +:105190004D815DD4703BC1536B26BBE06A7185BA0B +:1051A000BD27D6A19FA08C6DEEC4EF5196B97412A5 +:1051B00088A20471059EDF59AEE811F1FE01C40F0B +:1051C00094FBF17EC1AD6E6E9F6F55E47E5E0997D4 +:1051D00033EA38EA7BF1E77EC6AD8D3FC4B7BFA79F +:1051E000B477D4946FC0730BCED531E4FF1D355521 +:1051F0006657CC782FB879DECC168C53D863E3147D +:105200003C1E111F9F50F95345EF67B3F0DC9FE838 +:10521000E1FEA38083FB332B0E54D23D93E83A3951 +:105220007E3EE118BC6798CAF8BE9899FBB9C8AF32 +:10523000503EF7D33EFCF707982F95FE3D83C031D3 +:1052400057BB0DF9C85C719220937F7BD0DF8DFE38 +:10525000A885C71BE6603E70C5E2B213782E8BEBC3 +:105260000C9477B4F0782D7D675C9557158BB7AFAC +:10527000B5627B91E0B1C8D85E5385ED37BF184663 +:10528000CF1E9B87BB077A891C83DE79E4DFFE296A +:10529000DA4515F315BF771D97AB8B7BE61BF847F7 +:1052A000AFB472EE60EE9FC86EBED05341FEEC7498 +:1052B0008CB7BAA372A6E255903FC951F9F3B7CAA9 +:1052C0009D336E9EE73F01E40FAE276D3E8F0BC608 +:1052D0009FFF0B0A3E0D274F86E39F283F745338EC +:1052E000BD088EA8DC95D19EBE2E2A7FA56EA88F04 +:1052F0001C1EFFF215BC4E1D46FF1A5D2A28DF1B3F +:105300001B265FA3FBEFE3F7CE2A55F9E7FFE57E07 +:105310006FC5BE51FDDFAA3DD4A2C0592D1F50F468 +:10532000D9BF395F198562C27CE5B4C4F9CA777404 +:1053300009F41D16255FF9B09155EEB1639E9E727A +:105340002F21E423FDE6F0D3BF5AFF9C1DEF250873 +:10535000128A9DC6AE13249F1B419F213DA8E70FD3 +:10536000DC2FD5C5F34B1BBBB5F71FD4725B29BF30 +:10537000AF500DFB213FB292C7376B2FA7EB80D701 +:1053800018929DE817FAAA18EB170AC8910C353F36 +:1053900030C4E552C23CBE263640F97E4D0D820730 +:1053A000E5C117F61379797EDFB5FA89EA4BB57E48 +:1053B000E6B525DC2F54EB1704D447CD3ADF4ACAB3 +:1053C000EF3D204889F244572BF87EB3E2A7DD6514 +:1053D000E478B0EB7A81F26AF15E0C9EEFAE033CAA +:1053E0007F7E5739CF9F57FDB26A5EFCB8A85F96A3 +:1053F000EEC3A8F9F46A7EBC7A3F74FE566B18F5CA +:105400008B4D862E07D2A19A57E42AE572CEAA7C4C +:10541000773C7E9DCB4A2B5DA518A72BD50DE7E7E2 +:105420006A2B4DA0DFBCAEC8CF75A5C3EAE59DA52C +:105430005ABD9CEAF17AF97F955F76CCF07EE15F08 +:10544000975C9BDFEA96C47ADC907E95A509C66BD3 +:10545000B724FE8EE8EF54FE1BF7EF8FB021F77BE9 +:10546000B87CEB14E45F4EA3389781E25C2A7FE9B5 +:105470004CE6E3EF53F88A5A9E50C61FEE7B93EF3B +:105480002AFD5A04EF0F70DD25BBB57EB2D22EADDA +:105490009F6C42779AA65E16CED2F4AF389AA7696F +:1054A0009F1429D6B45F77B25C539FDA7FBDA6FF05 +:1054B000B48FAA34F51B07B47EB2E91717C4DD3BDD +:1054C000E2F85D091811FBDE0CF35D9A7ED90DDA66 +:1054D0007DE5366BF735A655BB2F755C6750BBBFB6 +:1054E000FC4EEDFED2D07FEFFEE2FEFBDBDD32CDE7 +:1054F000D3D7934FDF03DC52E3A2EF5EABF7FFFE9F +:105500001307AFFB52406F000000000000000000D6 +:105510001F8B080000000000000B53E16760F8518A +:105520000FC15BF918182EF021F8F4C01CCC0C0C3C +:105530009C40ACC8C8C02001C4FC40CC06C49E0C32 +:105540000C0CFF81F81B10BF05E22740EC0CC407D0 +:1055500058B09BE3C6CAC0E001C4DC40B378988968 +:10556000B7DF8917C17ECCC3C0700E889FF1D037DA +:105570000C061B5E27403FBB7E43ED3A2932F0FE0E +:1055800006612131609A1447F0A78AA3CA0B8B21C8 +:10559000D8C9D294D9950FD40F00F19321F080038C +:1055A00000000000000000001F8B08000000000049 +:1055B000000BED7D0B7C94C5B5F87CBBDFBE92DDA6 +:1055C000CD26E44900370960501E4B80C84BDDF002 +:1055D0003252C40411828A2CAF10027914A9A5FF9B +:1055E000DABB0B2804AADE5851A37F6A17041B2DCF +:1055F000DA80D11B6DE02EA208D56A684551AB0D4B +:10560000888808498C8F6AB57ACF3933DF66E7CB53 +:105610002E89B6FE6FFFBF7BC3AF1DE79B99336733 +:10562000CE3973E6CC9999B32696C20C9733F60D12 +:10563000FE416A3331C6C674A5ED4AC77035A7ABC3 +:10564000FC36BF9779CD8CD5F9AD946EF1A733EFC9 +:1056500060F8EE331406ED8CDDEB7751FE17FE4259 +:105660004A6BFD4554EF4E7F09E56FF7FB28DDECF3 +:105670002FA3EF35FE6ACA6FF0AFA17493BA280D5D +:105680005082BFA2C2AC64C6AA9EC9C9DB0CB92DA8 +:10569000B3C627A8A321FF8A9119B300BE4FA5FE68 +:1056A00098EADE347074573D0DCF4DEAA47E08A70A +:1056B0007609C78B59992D46BD2C1CE79D4B043CA0 +:1056C0007B6B4D4E72D47A8311DEED25006F28146A +:1056D000B842D69CE8F02E46789B4B545E2F395842 +:1056E000931D1D9E07EBD5DC20E0A507AC31EA8DAC +:1056F000C17A1B6E10F8F5F3D56445EF773CD6639D +:105700002EF56FAD56467FDF64E3FFDB5DA72E16F7 +:1057100079236693181BD7D54E9F321660384E9565 +:10572000F90A890FEECCAFBFC967EC268409ED03F7 +:105730009358C808FD079258707D96547F26D56F00 +:10574000EDFBF537A952FD80214A7D136B50B0FC6B +:10575000E72847C0F7FBFCB9946E14F273DF5003DF +:1057600063D82EDD1C1C04EDEEF17B485EEEF68F57 +:10577000A5F2BB841CFEBB90B3A090B30751CE2012 +:10578000DD8A7266C6FE7CADA500A77D6F3CDBECB2 +:1057900026F95A4C78AA8CE06FD83B64FB66807F70 +:1057A000DF0DAB4E6F03FAB7350FF318A1DE3D43A3 +:1057B00035F9625E96DC55EF9ED9279C8B8612BD2B +:1057C000CB10CEDD1EC13F15061651EFEE19E17A62 +:1057D0001558EF2E4F185E28B2DFBBA684EBAD2222 +:1057E0003E2BACA4C1DE9D2F3B9842F3110485E80B +:1057F0006B42FAC2BC7C76C0754A2BB44F49CE4B83 +:1058000063D0EE7E9C8F669C776EA28BD61EE9ECF1 +:1058100083EF1916568DF081B2FB8D80AF69B63BD0 +:1058200011E972FBB5454C19C6585F519E1A2852B2 +:10583000B200AE7D4E9182DF4DB3A11CBEBB447958 +:10584000F21A5E7E3B963BBACA13B11CBE27554383 +:1058500039E4ED7379F91D7EE0C4E0AE7A9B80CF28 +:105860003EE2773AFF0E6C45FA9846F354C3FB09C3 +:105870001412A0DF414CC774E1BF69D0BD190BED14 +:105880005DF8DA06D7535EC36FD3E038CA6BF8D839 +:105890002EEC97B110D2BE4BFA326FAE980FAC3BE4 +:1058A0009D13BDD95279A6EA4950814E992F1959B5 +:1058B00000589009E289F0F4ED8A9881F0EC71FECD +:1058C00025F76EFE9986CA74D0D2A3821E1A1D36A1 +:1058D000F697E9601920D361E300990E960BCE4F3D +:1058E000871DCC4D748E450FADDFCD43E47EE32E96 +:1058F00092FBDD7C91DC6FDCC5FF9C7E6BB2E47EAD +:10590000ADD972BF35D972BFD69C7FAC5FA67A6025 +:1059100032A0BED2FE2E94F4DBD5CC7716DBA39E4C +:10592000C3F9A4E93953B28FF9EC5DFC84758AB1EF +:10593000FC48388325BD0A703EC57A00C77B7E3897 +:105940002E1D9C417A385F0B7C58A49EEE06870D75 +:10595000D48FC3A4F076214344FF4CF5B1224764B1 +:105960003B8FAEFF1C7DFF4E458CC370DEFEDD3AE3 +:10597000BA66EBF14913F830C3F9E8C15C3A38591B +:105980007A386E814F48392F1CB77E1C178AFE0368 +:105990008AB47E013D8675B56B07FC689DCAB30469 +:1059A00077827E08EDFBF214AE03E71AAF755BA0B9 +:1059B000FEFE9196D0E5507E2E5810B440F9E427B3 +:1059C0008F3AD18EA978D2A862B9619F8DD697B649 +:1059D0001D0A9557595AEE9C00E51D4F1AD976EAD3 +:1059E0002ED380E33B25740A0BF17CA98D672BB67F +:1059F000EDBF11DB973559980DE0553CBD6CE604C1 +:105A0000C82F3B646258A562E75A735FC82F0F2AFC +:105A10000D98077C699D0AE4D9823BA1FEBA7D5F9F +:105A2000B621FEE71A4D83109F33B04EB8619D78C2 +:105A3000C9D1923A1BE8531EDC3D0DDB97EF523C77 +:105A4000A0E100FF9D073310FF47148F0558B8A24F +:105A50003E9EB923E6CBA946238D77D53625C800CF +:105A6000DE32563B0DE95981C4413C3C96A04DE9DC +:105A70009A6F67FC75D49F96AF7804FA83F6958F7A +:105A80002B1E1C72A581F9701EB73D6D2B79C88E37 +:105A9000E35D6B1EECC0716E3463BD65C1854FD98B +:105AA000DC88E736F334C477EB3673E950A4235B24 +:105AB000503414F1FBBF327E75462F8E77D548CB1C +:105AC0007623E0C1ECA181B31CDDF5EC1958AFDC05 +:105AD00011EB673903BD4FEB77D05C3CACEBFB9728 +:105AE0008644D21F2BEA8DCC6DEDEA47938FC0110F +:105AF000211F7B1D446F8D9FAB5C7C0A68FC5C950D +:105B000028F8AB76E4CF1AD61D9F3B912F644FBB8C +:105B100028FD05AC9B986E81751EE9772FD84F6ED6 +:105B2000B2CB3DF4FD01B09330DD0A7612A60F82B0 +:105B30009DE4167612D6DB0E7612A63BC04EC2EF5F +:105B40000F833D8E693DD8E3F8FD51B0C731DDE5E7 +:105B50000FD0F7C7FD359436F86B29DD837C83B40D +:105B6000D11FA47A4FF9EB296DF237D0F767FC4DBE +:105B700094DE2EE8E89CC80A701D757A990BC99EC0 +:105B800034C35B60827C5211CFA7DE102830433EC5 +:105B9000D50779A04BDF95A1020BE4FB56F3F20188 +:105BA000B7B04956C80F08F0F2ECDBBD936C90CF4C +:105BB000AEE5E583B70626C5417E7090975FB42BAE +:105BC00034291EF21735F0F2E1CD6CB21DF2C34359 +:105BD0003C9FF79277B203F2792D3C9FFFE7C064B8 +:105BE00027E4F35B79FBF16783467794F5778FC9F8 +:105BF000BD1855CE01E56DAF9A0179B3FB265489E6 +:105C0000479553946F3479A9FC7DA5DDABC23ADF8B +:105C100068F652F917CAE7947FCAE4A3F278835270 +:105C20004079B38FCAFB1BE228DF640A50F90843AE +:105C30001F9E3707A8BCC0D0AF00E13F630A52F9EE +:105C40003586413C6F0E52F92FD4E10553A0FEE397 +:105C500006DF5ED477EB155F19DA874C6D48477D18 +:105C6000A5D9953B717068676698691EECF943FE8B +:105C700043340FF02F19F3A50FA35D0A700E121C09 +:105C800013C031F60C27EFE5B1129CBC97CB34382A +:105C9000AF101C5BEFE0EC7979BC8CCFCBE51A9CA4 +:105CA0006304C7D1BB71E5BD3251C6E795951A9C17 +:105CB000E30427B177F8341E95E9D378344C9F3349 +:105CC000B83EAC4FE91D3EA35F93E933FAB5307D92 +:105CD0003E267C327A07A7F135993E8DAF85E9F3F0 +:105CE00015C1E9DFBB718D7E5DA6CFE8D7C3F43166 +:105CF00019104E56EFE03CF5B64C9FA7DE0ED3C709 +:105D00006940FA0CEADDB8F2DF91E993FF4E983E64 +:105D10006984CF90DEC179EA1D993E4FBD13A68FED +:105D20009BF019D6BB71E5FF45A64FFE5FC2F41983 +:105D3000427046F60E9FA6F764FA34BD17A64F1EB2 +:105D4000C119D33B7CC69E92E933F654983E1308A2 +:105D5000CEB8DEC1693A25D3A7E954983E5388CE20 +:105D600097F66E5C63DF97E933F6FD307DAE22383F +:105D700005BE7AC287011C476C38CF9C93E9F3CCEF +:105D8000B9307DE6109CA90027A76738E3DB64FAE9 +:105D90008C6F0BD36701C1B9B277709E6993E9F339 +:105DA0004C5B983E6544E7AB7A37AEF1ED327DC689 +:105DB000B773FA54593C931D68DF2532CF76687269 +:105DC000C9C986034EC89BECCC83605F52423B102E +:105DD0003EAC956417AA1ECD4EF130B4436738DD52 +:105DE0001EF4FB18357B84B5D07EC1BE2B51F20763 +:105DF0007D6998740BE2EB00AB2DD22E49181B275E +:105E0000D94389DE2429DFA7B0AF543FA5285B2AF8 +:105E10004F2BB9482ACFF0E549F9CCB2F152FDFE3B +:105E2000D593A4FC056BA64BF5B302B3A47C4ECD71 +:105E30007552FD41B58BA4F20BEBCAA5F221C155F9 +:105E400052FEE2FAFF23D51FD6B04E2A1FD1B45915 +:105E50002A1F19FA85941F75E801A9FE9896ED523C +:105E6000F925C71E95CAC7B5EE91F2134E3FA3B3ED +:105E700003E5FDFFFA02C6EDC10C33D983218799F2 +:105E8000F2E67D36B2FFF7631EF869EE3B83F2E679 +:105E90006717BB93713F8D0060BD2FE85B7621FAD9 +:105EA0007B6E1EEFBBD005DF6F36FB46B8A2F82332 +:105EB0003CAA6F9F81FC452D0A4BC7D46DC034CEE0 +:105EC00028F6EB162E5F1BB3F21F0A44C8694D7FFC +:105ED000987F903F6C3093FDAAC9F7C6FEA5E90BE9 +:105EE00023FAD9D0DF5CB27D28FFBED88EFD15BD68 +:105EF00088F3ACCADC3118F1D2F763C91E2BF56305 +:105F00001D5046FDBC86FD44F8BD2C03CA74FD58E7 +:105F10004BB68BEFA29F6338AE58FD6CCC1E2F8F13 +:105F2000674039F5F3AEAE9F8D03CA75FDC4F1F13C +:105F3000C077D1CF7BE71D4FCE44793C17ACA47E10 +:105F40003A7474B35CB052D78F9DFAC1EF8BC99F7E +:105F50000BBB8034E0B3A5A394E4E03F6D2C00724A +:105F600061CE2CFF35E6D95B363608FB7143BF5056 +:105F70008FE572FFD1D386241ACF6771C0FF083B2B +:105F8000B56B3F1BA07DF15281220B0246B0BFAD25 +:105F900014B2B96457F1809BDC90361D187837F63F +:105FA000B3C5E11904F9B6A6C9E6C551E46969ADFE +:105FB000E9546BA45F44DBDF4C62B9D5D0FF2E9B64 +:105FC0004BCA6BE94AC5C5843F82F22760DFC260D5 +:105FD0003FF067D8173020D5BB26BE4F7B07F6377A +:105FE000986F85FD0D9633B696DA9D107EDA13B75D +:105FF0002B41A4F7673FF9A189F47880BD9A9E8A66 +:106000007E37FEB7604D3CFAF8C3F82D0CF491F2E0 +:10601000A02E330DE9B42FA4FD6FC7D396E076A46C +:106020006B4D26D054D4CB66EC75D8E4662451363B +:10603000D33096B1D9D5C553D3681629FD57019EE3 +:10604000B31A479AA0056B33B5DEE8B177C1655E38 +:10605000D309A48F15FE219C6B0A211FD1FFB545E2 +:10606000727E2E53BBF2C0EFC1C66CC137D1AFDB1D +:106070006B42BE16A5727CE6629A87C5DCDF51E2F0 +:10608000E26D357CAA169B5888F6A7811486FEE837 +:106090004032D5BB4EDB67EAF02B3159BD4540D7C6 +:1060A000928546A2AB1EDF37F7C57B0DC321ADB984 +:1060B000DB84AECD9EF09FE793CB5919EF4FA3AB96 +:1060C000262FA7047F4F20FF217D1FF90F789F14F3 +:1060D000FCEF9263CEFF2A8B6F26F2BFE37E232371 +:1060E0007E09BECF117C5F5A2BF37D0EFAC9A1FE4B +:1060F0009CD559C1F558BFAE8FC45F18B84C87DA2C +:10610000BBA6825AED86FFDB420EAEABD9FD3CB298 +:10611000F7FA32DDF8041F6E147C98AFA3C71CC1D8 +:10612000B7F9826FCB58E0B60CF21F054DE8179B0C +:1061300057A630D417553FD5F8D62AF1CDA7F14D43 +:1061400087EF8D826F37FE84F34D8F77ABE05B6B0B +:10615000DDC72696DD1D6F3D9E0BD6E8C615D0F334 +:10616000AD569C3BB8CC68EF147B0BFA9C8CA87F97 +:106170004DE1957D4E46E8856B8B8AA5FCDC9279D6 +:1061800052FD79BE8552F9F565CBA5F2F9D53F945C +:10619000F20BD6FC44AABF30B0562A5F5CB3492A42 +:1061A0005F5A7B97945F5677BF547F79709B54BE3C +:1061B000A2FE11A9BCA261B794AF6A7A5AAA6FD89D +:1061C00037E46A94AF978E1A19FACB3EF5BC4FFEAE +:1061D000BA4F3D260FD6A944991B87F2EC26793E8B +:1061E000E5CFA5F4B4DF43F27EC63F96D2B6A60350 +:1061F00076F43F56C581DE4F043BDCF8E6DA9A7E42 +:10620000B8DE40FBF18C351B5BD706207F000FA367 +:1062100060DECCA833B3D02806D2DD372CCF1DC624 +:1062200088F2D61ECAEB5416EAD3BD7C466BF4EF57 +:10623000ED4AC7E00CF413BE61613B23FC75DDCF72 +:106240002B5826DA15B1CACF1A5859E479D6492302 +:106250003F27711A279D3442BAD2CCE7FFCA3D19B5 +:10626000939813F3A1C1D551FC2EE1FE1A00993485 +:10627000E4738E34EF97D55DDC35CF19F6934D720C +:10628000BB3C384AFABEA27E82D42E57F1BD6B8445 +:106290007A67F71B69BD66A10303AE1986F8794FCB +:1062A000E277D6944276578BDFDBE7E440C6FEE820 +:1062B0002FA4F4557F11A5AFF94B283DE6F751FA0D +:1062C000A6BF8CD23FFBAB297DC7BF86D2567F804D +:1062D000D213FE1A4A4FFA6B293DE5AFA3F4B43F3F +:1062E00048E9197F3DA567FD0D94B6F99B28D5F4C3 +:1062F000674FF2775AACAF6750FEA2C899F956B60D +:10630000AE6662979CC5A9967528671A7D67D459B1 +:10631000843CA44AF29088EB30C9590FE5752621D8 +:1063200087B1DA472F4779EBFB3DC81B63EB480E7B +:10633000660AB9FBAEF2C6D01B9F82F294A99327DE +:10634000590E3539D2F440AE52345C1DD325573343 +:106350008DDC4ED2E4EAE7682746B1B76E5015B13E +:10636000FE71FB88F9320C68BFAD127E7FE64EA746 +:106370007CA7E87B3D806BC17A6A3017D791CEDC71 +:10638000BF0D46FF78E7310B433F7CACF1E9E525D3 +:1063900036DDBDB47F280DC2A236AA7BB92D8ED3BF +:1063A000D56660852C0FCF67F38FF9809F71FF79D9 +:1063B000711EEE6BE1BBCAC8AE0A7A8AA3F8DB197C +:1063C000CA785ACFF4D5EA9F7AE0CB7C3C379F2934 +:1063D000E679DC01233FD70E3DE4B926E27C06F6E0 +:1063E000DBE9E877EE18647691FD10EA2BD331D81B +:1063F00057A2E381419F0DC6F38D4D208738BF3AE8 +:10640000070E4E60E7918F9EF47C4FF45C14ECDB3A +:106410004B7A9A199E1B013DB7E3FD97DED2B32755 +:106420003DD9937E3CB199D3D929ECD358746E9F52 +:1064300004F32E8A1CDFA3AAB21CB381FCBC43A3C5 +:106440003FEE4B23E87FA9DD4DF59FDBF7D6805665 +:10645000E8A7B3F1C204C6CF73C8AEEB7852D8ED4B +:10646000EE4C998FAD7D09AE06E7B9275F1F80FB23 +:10647000E4DB3003F3ECC9F8A25FA9295DF07A7B75 +:106480000E1F6B5CBBBFE5FC6C4FD5E667CB009481 +:10649000A7CF841E8839BE9EE414C70770AE52F899 +:1064A000F836188B7E877A263CBED129BD1A5F55F7 +:1064B00082992923003F87D9CC1218DBA1FA0EAAB2 +:1064C000B48FF3B406D04FB12FDEB31E5852E53C63 +:1064D000F372C88DED647FC68A7A9B4BB69F125DBE +:1064E000B2FD94E18AB49F3A0F3DE4F4017EABD251 +:1064F0000DAE93A3709DF38A758EAFAB1A7E150D0A +:10650000592EBB0447CE77D62A850D244FEE84D969 +:1065100051CECBB47455BAD97512D6AB33F539090F +:10652000D8EF19BFD5C5D757978BF79BEE8A5C5F1D +:1065300057AE89A3FA1A7EB1E0FEB3F163AC91BD08 +:106540006BC57511CA7262D78FC94FF513339D4B56 +:10655000379B3E43FBDD96ABD9EF2AE535B8550DA9 +:10656000C68065047EDF25F507EDDCDA1933B68BCE +:106570002D372A3BA5F113F86FC58377DAB75A890F +:10658000CF3E809800F0DA557B0DCAD50995CFE74C +:106590002A21A715D656B3CF4DE46E41795E3496C5 +:1065A000691366EE5BA0A73F78D144F7B4D85700D3 +:1065B0003DBFEBAAC01256E444A7E7A2C61533704C +:1065C000DDFEC0A0ED876BF371DCE798A110F5D27A +:1065D00039F647E7A888F93AC4C4FD31AC86EF73B1 +:1065E00002F00FC7B7B456DEF72CAB93F3A56C5689 +:1065F0002AEADBD22D261604DC97E3BE491B37E8D6 +:10660000DF0C13F76B2C63D51B709F7EAF89FB7B70 +:1066100016B9989A097855FCC72FF3D1EFE3317179 +:10662000BB433B4F5E9EC4F12E9F1D347BA1FEBB3E +:106630008DA3E680C685F6C10D64FF1433CF4ED618 +:106640009DEE8B6B64FC7AC25F8FAF6607753BD79C +:10665000167824D72BDE60143D77994911FB3F3E15 +:106660003F669B647FCE3C93ECF7D1E4C024E4E02A +:1066700084EABBDA3486F31DF9A8A81D665F443DA1 +:106680007357BDD9E7AB67C17A46AA37CF9482F575 +:106690003AA6D1FE98813C0DEDAA67EB827723875D +:1066A00027D7ABF88FC79E0A80BC94FFF61E2783BE +:1066B00075F303B536D503DF57EEBCCDE985F4B4E9 +:1066C0001A70223F3F081A0BA3D1634B981E5EBB82 +:1066D00082FE34219FAC26407E8ACF769A5CE4E726 +:1066E000AFB7842C20A7958DCB67B0E1943FCEF354 +:1066F0001B3F3262BE49E657F9AFEF4975F37B366F +:10670000DC9FC44264E756EE786F1AAE1755AC832F +:10671000E44CDF0EFBFF3C89E6F5427342F772C0A2 +:1067200093FC095562965535FEFC23A313F3B27C06 +:1067300094097B15E984FBFCDB4C8EE453F190BD9E +:10674000845D82F35CA3070B72BB75FD23F70D3FDD +:106750000EF89CDDF1A253191AA91FB89C75362CAE +:10676000FE95D5105B8FB4811C46DA470098DAB9E4 +:106770009B84BDDDCCD395A69013EFB3ACDC66F261 +:106780008004B2958F1919DE03606F5882E8175D97 +:10679000F1D8F3AF8D07BAAFD86D4A9EC187635762 +:1067A00052BBF85205FF5B93D7C587F2279E37BBD4 +:1067B00087F1EFB72475F163C5EEFD6636AC3BFD9E +:1067C0002637EC37B7DAA3F0A5E1F8345C67D73F9A +:1067D000F25733FA133FD8A7B0B4ACEEEDCBB63DC9 +:1067E0004FEB1DD289F828F814E65B377E85663EAC +:1067F000339AEAB9500FC6E2D732A177419E1F7F84 +:1068000006EFFFBC69F1E0F8CB1EBFC989E3785FF2 +:10681000ADE672FDCBDB52717E979902A92E4AF943 +:10682000F7B2077F44F2B6ECC88F52C95E60DE0C47 +:1068300003E9E240068E6FE9D66B697CA5CC47720E +:1068400057F64B6311DE47FC546585BBA3CC8B38F0 +:10685000B342F8BCBF1D0C1918DFFBB8BF447DF66E +:106860004723DD8B62EC87746FEC4762ACB0F2516A +:10687000FE532BE7D371A12771224BF2BA63630B4E +:10688000F2E74C7F6F1A9E73001D02825ECA3700CA +:10689000D778646A1AE70F73ABF9A21DE8F7C9F855 +:1068A0001DEBB798BCB6E1523BA10F79FFAB45FF9A +:1068B00080771CAE57EFA746B7F7C688F1C15F0BCC +:1068C0008B90AF88F9CDE7FB8E4D7C7E6BF33D5806 +:1068D0005C88E59FBCCAE70FB6C3F501F00AA55175 +:1068E000F9FED90AE903D857479BD73B4C625ECBE8 +:1068F000E56029D27A0F78AB4A42A49C00FC24A21E +:106900003FED834BB740BB08FBAB0AFBA37AE6AE77 +:10691000EF11EBC332A1074C6698FF1777CD7FB616 +:1069200095CFFB9EECC995A6E0C30FE07C7DC3E24A +:1069300009B871BE9A8A70DC1FEE3AF0DA7520D77A +:106940001F3668F354D69FFA795AB6670C8B364FC8 +:106950003FB4C3FE2ADA3C85EF51E7A9BD95E4F8C0 +:10696000FBD69F1ADD869A65BD897AF019776CFA95 +:10697000E9F5E0EF4D6EA2A35E0FC2DFAB2CBFBB0B +:10698000DC69F2A6C959F96F2A2E407D1396474D4E +:10699000DEC2F2A8C99B7E9C32DDF4E57F15FAE6E3 +:1069A0007A6BE13568175B3B18ED570A661B83B8B5 +:1069B0004FB67EC268BE4FBA219EF2738DAD4FA016 +:1069C000CDF756C5DC61B88E5FCF02267E6E5E6B5A +:1069D000223BF5AB6FBE9908E3B94ED0F57A20F3B0 +:1069E00055C087125509C5019EF354164848427F89 +:1069F000B1C24E44E0717D999CC7BFCB52BBE0F45D +:106A000054FFDBDAD5DF353DE2E767577FC294F606 +:106A100017603847C85171333FA7A81AAD04B3694E +:106A2000FEB5AA4511FB84C7CCDCCE3832E59A31DD +:106A300048BF82B9C31248BE6B87D03EB04AE8ADAA +:106A4000CE803B01F57967730EEDFB3A0F2D76F89A +:106A5000A2E8AF0342CE9E17E72CED76A5D608F24A +:106A6000DECE3AC86E09D86D51FD6E756683B0777B +:106A700004DFE0CF08FD9708399C074D13F222F898 +:106A800036FBAA0F5467773EE0DF89887DC33F4A13 +:106A90005F946BA4EF015BEBB4A228FE994785BE1F +:106AA000BEECD92FCCB8CE4D692E50918E53EC460A +:106AB000C9DFB15D9BAF43D950C4EBB26797DF31FB +:106AC00006E4B8EA90D16383F155357F64F645D981 +:106AD000BFE9E989F0D17E6C3573FBF8A8A9682974 +:106AE000D2F5E8B5FC3CF74F664F45343C675B395F +:106AF0009EF358D1A7A3957F3DFA16CC7584260145 +:106B00003D3AEDFC7E7277F9E3F3BED3A504D72AB4 +:106B10002887469E4FE6F77FA731DF1D13159AEFB2 +:106B20009747EAAF82A6E2C7F03E4B65B3E2324038 +:106B300079A5DA6A4639AE6ADAADA25DFE03377F1F +:106B400067C1D4EA61B323FC5BAD66EE4F3AF0B7A0 +:106B5000EBE6237D3F9E6D61889777E8474E5CEFBB +:106B60003F6E1E45F320D6B8FEE0F75C3305FDF11D +:106B700066AECFF4F2302D395ECA5F3B99F5C37330 +:106B8000DECB2CAD3779A2F06F9D85CFD35EEB378E +:106B9000EBFF30FD3611F41B976B53A47E9B6EE127 +:106BA000721FA1DFD2A2E9B7556BDD692817ABF6DA +:106BB000E6A4215F571D5E9A124DBFBD20F6B58732 +:106BC000C53DE9F67EA0DF4644E8B77EA0DFA2F827 +:106BD000C1475B34BBB307FD66FDEF997F2FA07EF5 +:106BE0008B32DE2B84DC69FAADB0792DE9B7C27E39 +:106BF00046E93ED2651661C7C5D46F0BEFB996F270 +:106C0000264F7C14F941BAA27E3B2CF41CF6837A01 +:106C1000EE67966FA7E7E65939BE3DEAB9FF263A17 +:106C20006B7A6E557F85EC97EE72C8F5DCAA2CAEB8 +:106C3000E756EDE57A6ED520AEE7F4FA6D5237FDF2 +:106C4000C6DB57E6427BDA2766DD7703DEE72B31CA +:106C500079AC507F865B7B5F503D2652DFFDCC12C6 +:106C600043DF7940DFD97BD677AFA0BE53498F0D84 +:106C7000C479A4978FE903E3A5FB6A47BF38F59B66 +:106C8000DFE27CF98391EE03BD6EE0FBA17D5F9CAA +:106C90001A85F3EE65C407E6CB4E217F6DFEB1A4E5 +:106CA0004F270FE5F3BDE2501CAD13958D0A1FEF82 +:106CB0002D4AD08DEBC0DF3EA77DF2FCBD7C9F3C12 +:106CC000D7C2E9C17E6CE4EF2280040B23E4A1E487 +:106CD000F372F2F395A8CC8AF6EB8243D33F40BB24 +:106CE00075C1E73564EF2EC0EF78BF6277EB864C55 +:106CF000E877FE7285F61B4CDC87D0EE4B5CDFBC80 +:106D00009FEEAFE8EF4168FA7C7EB5FC7D81CEAEA8 +:106D10003F20C609F62CD185BD628CEA9F3BA0A717 +:106D200087878FBF6235B78FC3F400FAB895EEF44A +:106D3000008ECE5898DA35FEF94FC2B892BBC6A580 +:106D4000D1433F3E6D7FB240CC8D58E3D5E8D76D3F +:106D5000BC1A3D75E37EDE22ECA28BD9309C67AF76 +:106D60001B7C778C41B9F83D8C1FF099336F505ADA +:106D7000A41E7E51E8F3AB7CC7A7A4BA915EFCFDCC +:106D8000DD7565BB9F4F85715CEDCDCAC3AB08D780 +:106D9000FECDEC433FC2015B07E9354DAE2EB47228 +:106DA00039FFBB8073B4AF6B0AAD1F4D8A8BE64BC6 +:106DB00048A7B7C4BDB02AA027CEC7AA26B1DE8097 +:106DC000BCE17C9BA6AD3F487FF8CFAB9A39FDABC9 +:106DD000AA15A2FF4CD67110E95B99AC7842006A03 +:106DE0005AD3EEDBF01ED50B36F88EF3B64CF16CB1 +:106DF000E7E4B067A446954B359A5CB2EA21E457C4 +:106E0000D0D6C105582F09DF8BBC9E82F689DEDE05 +:106E1000B8CCD27214F1B8ECC726B68D75B73F3432 +:106E20007EE7C2BF6FA2DDE7E9417E0709FBF205FD +:106E3000A4B71DE9DA6146B9AF0AF175432BAF5229 +:106E4000DD53883E1ABD9B605D18CDE98DEFBEF421 +:106E5000F4BC5ACBA33C63FD66C584EDAF043EF49D +:106E600081A2C9862F0E6AF28BEFC4F474C1FD7F34 +:106E700046C47C47BD1479EE58D97484E8327D3518 +:106E800098551174477D753EFA749B0F4DFBA3DE38 +:106E900083FAB6F3E142AB3C1FF6D93A5E1C81FEA1 +:106EA000ADBD0AE903D69C28EDEFAFB0F27DD3016A +:106EB0009B8FE4B6E3B089EE7BEBF5C658417FDCEF +:106EC0004F44BE839B8C03C1F35D978DBDABE191B5 +:106ED000CDE527525FBF60F3119F62C19F26E0C7D7 +:106EE000B297C2F8627F789EE296FBD3AF179A9F63 +:106EF000A7A7715D23D6FBEF3AAEF0F9246B3133CF +:106F0000EECFDF6D8E38679A23FCFC9A1F2CA2DE31 +:106F10004CCB98D8F5D0DF128271BFB0EB21F2EBE9 +:106F20009E7BF4F84C94DB15BF33322BF0B96D9790 +:106F30008385F83D0A33AEABE58DC6A8E7228CAD5C +:106F400027FC56FCD6417AA57C8F253803DA973F7B +:106F5000F5EE70F44FB5ADE3FA25F0A8908F40EB55 +:106F6000703C2F2F57F979B11EDE8F85BC9C7D3A7E +:106F7000BE04F5A352CFDF759637CC355922F6E51E +:106F80009578E0C6EBD13DE4C0230AF9C1BBE3B775 +:106F900096D77B84EBBDF2265310DF8796D76FA37D +:106FA000FD6C55FD4766B4E326FFF631B223AA9A7D +:106FB0008CB29FB0DE18B2901FD3781C53BDBFAE09 +:106FC000B2B182E6636583F087E9FC452B7EBBF7AF +:106FD000A9009066C513BF76A29E39D3B2D3497E6D +:106FE000B87AEE6753ED6A743F5C4FFEB7864D5139 +:106FF000FD6F67F03F60FE6DB5CAFE3756DFA757DD +:10700000E7E02B1EFBF4413C173ABBE7C30711EF47 +:10701000955F7FFCE04FD13ED96773E17A57F5E881 +:1070200051F2AB6BED9E12F3AAED915F3FFC00CCE9 +:10703000BFB6372C74FFAA6DEFFB03DC30CEB6DD94 +:107040005FA4A2FF72F5DEA9B46F59FDE4E4B4F3C6 +:10705000DD2341B90CF6E23C44CF87038D4686EF31 +:1070600020CF1DB3909D11F6A3365470BFB45BF8CA +:107070004F77453F77D2FC7E958DD75C7D29AE7BDF +:107080008D268F9BBE0B3F604F7ED357819F237A07 +:10709000C1B75DC22FAEE3DB39FC0FE0CF9FACB2CE +:1070A000BFF9D3C6A5BF7A00CB1AFBC4F49B867A7E +:1070B000412FED5C6B9BD5FB8E15E7C39EDF907F68 +:1070C0001AF90536376B7BECD301E86F386DEAB8F7 +:1070D00091EE5FECB5D03DA1F2BDAFD3FC687BF281 +:1070E000089D173171AED4C6C27FFC1C40EC65AA66 +:1070F0007638B8BF55D01DFDB16E277D177E572E4F +:10710000B79A3F36961FB68F4DDC0317E76C153BD9 +:10711000DE32339D5F5B198B7C3A2E9D0B6AE3D682 +:10712000C373211D2E893C4F88E5E7167A34CC279E +:107130007E8ED0B64D9C2F84CF0D18EB9787F7DF4E +:10714000F979775550799D45998FDA7982D3A69B45 +:107150008FC1DE9D23F48CEF77A38762E3FB568D0E +:107160002E67BF8AAE8F87D814F1FEC0976B8B58FD +:10717000771688F5A412E8C5DF93717CCF8AFDDD10 +:10718000D9478D41DC076F6838407A553FAF2B599E +:10719000F4F821E36D5C9F5436ED1F8EFAE7ECB3F3 +:1071A0004F93DC55EE3A6E0E009C83F54F985B874B +:1071B00076C939EAEB6084BE3EFBF8FEE1FC9C83B5 +:1071C000EF23F5F0AF10F0AB9A65F855BB3E92E0B7 +:1071D000AF0834985DF69EFB39A37AE7E278CFB426 +:1071E00098282ECA99066361B47825433190544A91 +:1071F000179D3638F8FB38639299ECC8D58EB1C725 +:1072000012923135BB711FBD7E2DBF0FB9FE679E37 +:1072100074E4CBFAC439740E54ABA3A32BD95580B4 +:10722000FB6BD794A2D128567A3D90E8354878AFC9 +:107230007614A6E17BEE5B853DC2540FBDDF333A89 +:10724000A715E2388C2E83CB16751DE5F04CF6227F +:107250008A176172C9EFE9BEF7F80FEE7E72FC87FC +:1072600040BF7F34FE03A33818FFEFE33F04B09F15 +:107270007F81F80F21F2DB68F11F92BFE7F80F6BF7 +:10728000991CFF41F0331CFF41F0F37FE33FFCFF0B +:1072900015FFC118F7F729189F418BFF9012679EC1 +:1072A0001A19FFE1C2B884A991F11FC6C5A54F8D77 +:1072B0008CFFF083B8ACA991F11FE6C75D3435327D +:1072C000FE4355DCA8A991F11FD6C64DA4BC16FFFC +:1072D000E1EEB8A953E5F80F33A74E817C5B9CEF34 +:1072E000EFB85EC58AFFF01E4E96313DC77F00386D +:1072F000E6B831B1E33FE8E1C48AFF007012084EFE +:107300008CF80FDDF08911FF01E0A4139C18F11F28 +:10731000BAE11323FE03C0C9223831E23FE8E1C4D9 +:107320008AFF00702E8A4B891DFF410F2756FC07EC +:1073300080338AF08911FFA11B3E31E23F009C8916 +:10734000042746FC876EF8C488FF0070A6D2B86296 +:10735000C47FD0C38915FF01E0CC247C62C47FD0F8 +:10736000C38915FF01E0CC257C62C47FE8864F8C81 +:10737000F80F00C747F8C488FFD00D9F18F11F0011 +:10738000CE72821323FE831E4EACF80F006715C128 +:107390008911FF410F2756FC0780F353821323FE08 +:1073A00043377C62C47F0038B7129C18F11FBAE1E2 +:1073B0001323FE03C0B983E0C488FFA087132BFE0C +:1073C00003C0B997E0C488FFA087132BFE03C0F960 +:1073D00015C18911FFA11B3E31E23F009C7A92C387 +:1073E00018F11FBAE1F35DE33FD84203951C8AFF11 +:1073F000407122C3F11F92BF75FC8766C4F77FE31B +:107400003FFCCF8CFF70B3DDF7751CF941BF5BFC0F +:10741000075BFCB78BFF70B3BD283E1EF797DF32CA +:10742000FE436AFCB78BFF00FDA4C78F89DD4FAC1C +:10743000F80F39BA7E7A8AFF00FD0C3AEF7862C401 +:107440007FF0E8E8F67DC57FF822EEFCF11FFEE54F +:10745000E22CC03605CF7F8A4914D9BF4CDC856B3E +:10746000E3FFC97117C858F8578ABBA0BDDF6F305A +:10747000E17AF5A6E0FB6B422EDE12F1178EC58C89 +:10748000BF10BC8AFCA2CBE5F80BD3051FE7F9645B +:107490007998CEF879C3F429593C5E66992EFE425C +:1074A000AE7C7E3DC377640A80635779E4711C111A +:1074B000F230B3E4A3E7903D578F8D1E7F6196E0D5 +:1074C00047B18E2ED305DF8A457A3D3E4901799E2C +:1074D00051764445BACE74B7AAE4D7FE81C63FB709 +:1074E000C4BFD902AE1EDF59827FB3AEE4FCD3E342 +:1074F000FD2AF2CF0969D928E29F1E6F3D9E7AFED0 +:10750000B3487E47C4CD286072DC85C95639EEC2C7 +:1075100054971C77E18A7439EEC2956E39EEC20F2A +:1075200072E5B80B5779E4B80B578F95E32E147BAF +:10753000D7EAE23E6CD2C57DB84B17F7E17E5DDC41 +:10754000876DBAB80F8FE8E23EECD6C57D785A1742 +:10755000F761BF945F5C7358AABFB4F688945F5616 +:10756000F786547F79F0B854BEA2FE03A9BCA2E10D +:1075700023295FD5F48554BFB7711F5E15EF815F76 +:1075800013EF818F89F7C06FC688FBF0D79F7F719B +:107590005BE47BFC2F7FFECD6DF81EDF20DEC1C6D5 +:1075A0008AFB102E8F11F7A1ABFDB78FFB9092FCD9 +:1075B000CF7F879F63E7E79B13E227E5D853BEFBA6 +:1075C0003BFC6B8BE4F7CC734BE4F7CC3976AECF56 +:1075D000E7F9E477CDD797C9EF9ACB6CBE6CC4437B +:1075E0001FF76142BC37C78EFA52BCCF0FE1FB5484 +:1075F000581B9FC5F7A9903E87711F203D88711FBA +:10760000203D84711F20FD3DC67D80F4258CFB004C +:10761000E9CB18F741C5B811011137A246C48DA8AE +:10762000157123EA44DC88A0881B512FE246348878 +:10763000B8114D226E4488E09CF01FA2F4A4BF85CF +:10764000D253FE63949EF6B7527AC67F9AD2B3FEA7 +:107650000E4ADBFC9F53DADBB8119A5CFE19ED068B +:1076600033F6CFE55893D319F6811B22E5B4C87ED3 +:10767000D10694D358F122E6224D5362C78B089766 +:10768000C78817D1D53E76BC88B4D1DF5FBC887F70 +:107690008BE7F2FA8FC68B985F2DC73358B0E6FCA4 +:1076A000F122CA6C45AB512E3579FCB7787E5ED598 +:1076B00053BC886D7645ACD74017B4BB802EB45E02 +:1076C000F7F0DEFE39C7C3B9B89FE8CCBDE8BC719E +:1076D0000EF472119BDE3CAEC175DF739C889EE890 +:1076E000AAD57FB39CC72FF8B7F8F3C72FE81627A2 +:1076F000A2A7F802833E233DD9DB38113DAD0B3DF7 +:10770000D173D6F71C27A227BDDA933EFDE3744E52 +:10771000E709F1E78FC7118E0B676D39488D5D5E04 +:107720009ADAAA78075E30DB45FE93F65DE2DE98D2 +:1077300097B95DA9FC9D3ADA9BED7B1286337ABF3F +:10774000EE625EE04FBCF8AEECDABF1FCFD36F75D0 +:10775000326F6212C583771B73701F36D28AFE9414 +:107760008AC68F5EFE1DC0B5351BE93E593BE0D091 +:1077700042769F3711F916CF6EA77D3A9E717DD361 +:1077800027F23DB3EEF71BB04AC4F9CD54A39DF6E2 +:107790004D9D5BF93D4F23BBE8BE89C9749F9A0597 +:1077A000DDC43FB25357083C3B31C5FA3E2BD98F5D +:1077B000CB0E3F911F62FCBC32D26FD0A750F6D3E4 +:1077C000D4D99CC3F15D250B785BD0FE5E22E0A589 +:1077D00014C9FE9B0F17151EC273FA25BE52BA8735 +:1077E000905622FB739878378EDBB1F07D39C0A7B5 +:1077F000B449610F28DDDF919735DFB501F739CB4B +:10780000837AFB9BE5A29C95B3380FEE7B57D4CBD4 +:10781000E50E87B8CF6167F65ED1AD75F07D134791 +:107820009F976E9E10D6DFE5A0FBB0CB0E2F3623C0 +:10783000B32CE932DD6C6E996EF1B9327DF4F473DC +:107840007864FAE8E9973056F67F69F4D3EE1BAA1C +:107850004CDC170DF27BA4DDDEE1376D233CF5F443 +:10786000D3D36B9443DC93E8A257913595543EE112 +:1078700099A18648BEF5F321D31E52F0BFFB27071E +:10788000D7522B8F4345BD95CE413365096F178F76 +:10789000F301E3CA320FCD07DCD1A37F379EFD5938 +:1078A000C8FDBBEC1B486F2A7EEEF82228DD8AF269 +:1078B0003682FFFE02F9ABB4DF4D601E17EEA31A4D +:1078C000FC56F71215CF05997BC9403C0F74517ACD +:1078D000A778F7DB3E94D1BEBF21F4492A9EA3DDF1 +:1078E00099D73113FD0F554B5911AE5F3F72F277A7 +:1078F000179B443AC2C9FD339B8B0CCC3B1A7F8744 +:10790000C71854D0EFEAF21EBE1CEDD166939BDE81 +:1079100011BB3A5EBE9ECA47D1FBE80C43ED48C49A +:1079200007EAD3FBDAF6E6779D8B23F4705BD3DDB1 +:1079300043F07EF1FD86E8EF7A4B1DDAFB367EBF21 +:107940006344579C8152C7188A47706736F453596D +:10795000DC497CD4E47282A0FF73A5D309BF279BC6 +:107960001537FAEBA6196FF8C130C06FDC5195EBF3 +:107970002F71AF7BB4A8FF34F3A423BEE32E650AB6 +:10798000CE9F716F304F00495C5D4AF7E97EE79CFE +:107990007608F935A519E409F5C859BB07AFCA8FB0 +:1079A0006991EFCB254EF11DC0FB85971C63A4CFD9 +:1079B0002E39A6EAEFC71871BF3FAE55FE3E41B75C +:1079C000FF5CA7C99D93A5A2DC6DF9CA4878B5777D +:1079D00030CF3A80DBBEA42F9DDBB67FC2C84E6C91 +:1079E000FFCA5818ED7EC9DD0EEEF7BADFCC487F2E +:1079F000DF5F6AA7770ECF96965F80F6C5673FF187 +:107A00005D10CD4F1961A725F0F7E7DE043616E5C6 +:107A1000F05685D3BB36A328CABAA5C99D26879A36 +:107A2000FC6594C6F9A2DDD74C7672FB685269AE4C +:107A30006246F9D9A730A46BDB3AC0EB3CEB768009 +:107A4000ADCB447CAA9A3EA67B58D66625EAEFF2D7 +:107A50003CE170F2FB80EB026BF1FEC5CD3089504A +:107A60004F65986BB3A2C10FB02D64973EE070F3E1 +:107A7000770356114748ADCDC0FB086D4D93AFDC81 +:107A800000783E00F301F97BBFC94378072A18A3A9 +:107A9000FBA4C25FD76F26DBB639C2FEDDEB283808 +:107AA0008C727BD8C1EDC63E3E8F82787BFEFE573E +:107AB00027C26FFFDC42FCEB2BEC4DADDD4907A785 +:107AC0004F89D37B00DBB3B264523E1E9FD3BDA46B +:107AD0000FFACD81DE51EC2B6D5D4FF2313A9F48AC +:107AE000B21B82A49CBC5EB74BBAEF1DA079A3CD9C +:107AF00003165218BED7D7F49BD2AC841C20F7A330 +:107B0000ADF610DE3F4B2A837127633C0F2B87D7DE +:107B1000A29E95FD5A208FF968DC337AEF8F8E5440 +:107B200084AFE93D4D5FDE9AC8F5D1AD77A9140F5A +:107B300074ABDA6A437F6A96D73D0943D324A96EB2 +:107B4000BA97D2BF8CCFC3F89C5F2686ED0098E42D +:107B500023BF362E88F69E2903E52905E9E5FBD0EB +:107B600001E9F0431DCFA2B9E0B1B13EFCFE94D0D3 +:107B700013C2AE9926D6BB71EF19F83BCAD0E52CDB +:107B8000F27D915E4F80DCFF097FBFE7FEF7548AEC +:107B9000131AD60FA5D3687D62C6A10750CE26BCA6 +:107BA000C8F87194D00F2EF887F4B9E425DF7A4431 +:107BB000E3BBEA053DBF59C81ACEE34FB38D3A0483 +:107BC000F32D729D758AF55EE8919B8A07AEC7F921 +:107BD000A5C9D105B7788CBE083AEADB87FD948A3F +:107BE00035FCDD9D837AE42523DE0F6B2F007E03B9 +:107BF0005D9EC4F902F44EFC247825F27D4BF3150A +:107C00003694EF5B43935C33A04DA2B5889897C838 +:107C1000BCE4CFC903EA609C88F52414B05F578B9D +:107C2000B29C29788FAB50F2F768BF8B070325BE53 +:107C300084F900721C798F55934FBD3C6AF2BB1ECC +:107C40003758787E871E73488D4A0331C8C2B6BA4A +:107C500050CF6AF6E5FAB03D9748FB8CD5C22E5A54 +:107C60006F9F662535B03F99D6F3D5B83EC1F8571A +:107C7000A7309A07DA38F4F258F5B9810523F607E8 +:107C8000556A07DDE3ABFADCCC827D70DCBE493897 +:107C90006E8D2E23055DF474C8768AFDA6A0476C10 +:107CA0003CF35D787F36D1EA651B09CF4974CFB9C3 +:107CB000219467C5F5F6361D9EBDC06F4E34FC5449 +:107CC0007B0CFC44FCB609CCF7BB5690D7FC9BEA76 +:107CD00032F87AC15E4D8FE09F7EDE8C6DAA3E60E9 +:107CE0008E982F9A5F573F4F4634B36B90EEE34226 +:107CF0002AC3F3D79EE6CB2762BC55F19C5EED7399 +:107D00003A06A37CEE507DD54EB22F5A0D18F7B728 +:107D1000FD6946F3D9B3FFA493E21BB5F4EE7EBA36 +:107D2000664769F693BE9E663F697A57BB1FBEDD04 +:107D3000E9F363FF4A13C8278C7FBD8BEF8BF63ABC +:107D40007CEBF07B3C8C018F92586E288BBF7F952B +:107D5000E53F96BCC7EBE4B901E844BF9305FA7F61 +:107D600090D21D0FADFF29CE447EDE02B319F5502F +:107D7000BF7CC63BAB64747FB2DF70E6C3F5A95F1E +:107D80001EBFF71714EBF636A16FB574AFA3E87EEC +:107D9000C4DFA4B28025EFBBE38DA8E27DECED4EFD +:107DA000EF7D287FD6422F8D23D3C53C687F66AAFE +:107DB0000D0ABE9B4C5AE956F83D6CD6F58E09E08B +:107DC00065CE7017A09C64E23E1AEB37478FA3F58F +:107DD00084D324D9991E168E53F504F60B76E6410A +:107DE00033E0DD678616F74A3BB7F12848A736C768 +:107DF0001C42BAED5385DBE3899C5EFAFD00121E3E +:107E0000F15345FE3633536D49ACEB77380D56B21E +:107E1000E3E399A701F5D2CBCE6C712EEAA9C1FCA0 +:107E2000BFAB1DD6C4A15D727CE7C4591E15AA382C +:107E30002FED1C8E7B2690E7C3886FDBC4CEC1B7C5 +:107E400012313A0670B9F11AA5B8381AFD9B4C12D6 +:107E5000FD6DB8CF8ED4830E33ED23DB94380FCE77 +:107E6000B3B6E50AC753B18AB841AABCFF17FA48AE +:107E7000D3AF9DCE2CC23F9E05681FC0AC1E2BDD2C +:107E80006317F8635C45F2EBEC8D0F6EC7F3285D6A +:107E90001C457D9CC5C98BED74EF62CB5E1BED4B21 +:107EA0003B8BF8F97C67B385F46FAC799A86CAE0AE +:107EB0003CF102816E1D48B734537522EABDB4F916 +:107EC0007CFEEBE9D18E03C5FDCE1F4CC168EFD51A +:107ED000B5343DBD6F31DA65E919E9946ADFEBEC41 +:107EE0006AD47BD8C604458AD337047A14FB1C6352 +:107EF000027C3FE7FBE36B5ED675AFBD2E8ED3AF42 +:107F0000D3373EE161942B1038FA3D01ED5C53EC20 +:107F1000E7B5F8495A3F5BFCD6620CF959B768BA25 +:107F20000DD78114E6BD721E4ECA2D26B693DAE532 +:107F30004AF75DEFF58F2CC6F7C99909FC1EED27AE +:107F40005BA6D27BE654B6CE3618E8505A64F0A051 +:107F50003FE0DCA2379D06909F45992DF928A7099F +:107F6000265F66C218725DD17E6359893918027A1C +:107F700025D78142203A06AE243A2E3444F50F67C5 +:107F800027F07DE75B623D494F1F50BC645464BEDF +:107F90001FD1559323983F194B4677C5C3047E5E86 +:107FA0009410651EB49B5813BE97D0F451B2103391 +:107FB0004D1F6A729C8CF303EDB822D04FD2791F0B +:107FC000544DEDFA3D43A5F9852FD08E755E3A8963 +:107FD000F40DCCDB1A92F35CAE3F6DA8CF22FC56B9 +:107FE000ED7B5FEF8FEF98DEFED9C70E7CD7F217DF +:107FF000B5C381FAEBF42D7F72601CB0B76FE1FB63 +:10800000E41B75F6FF55423E8209455390AE0BFCCA +:108010007FCF8FB4D7D81AEE7F5E1E94DFAFE2FD1C +:10802000EF483F604583FE3E4080C72913BFCFA97C +:10803000E7C33AC187E5BBB69933DDD8BF6F0EF60B +:108040007F5AEC6F4E373AE83D8586CFA25D23CD4F +:1080500068F3FFA5D922DEE9B598B85EF6CEC0F781 +:10806000393E41373D9E07F7C513BCA5F7F0F7AB86 +:108070000BA1AF35A0177DCD3C8E927E1C4BDF76D9 +:108080004F433FFAD24D0AEDE3B0FE2DB04EF8D685 +:108090006CA4773CFA712E0CC8FE1C7DBC466D3F6B +:1080A000B04CF07F09FE1A6F4E94388ECDFC3DDD4A +:1080B000329D7DD17928271EC7BF2641D8D9F9EC3A +:1080C000128CDBB9E7507642B478185A7A569CF78E +:1080D000E3BD7E4C4FFB19A55312DC3C5E57F39178 +:1080E0009B51AE2A9B76537CC47DC1F7FA8C872ABC +:1080F00005CD5F1851A80A843D365FD8637B189779 +:108100001BB0A337A3FC5FFEB9CE8E16E3BC419330 +:10811000FB4349243737E0B886E377F59368E3BA41 +:108120003B417EFFD5DB7169E3D1C6A7955788F740 +:10813000E7FA769A9C4F1172B76447F186BE408A7F +:10814000F57BDF1F20E2C8519C2D4D8EF472B24C9E +:10815000F02D2C0FCD77D0B834BE81BCA78B7749DA +:10816000E9E8CFE8492EF4FC6F33B50EC0F9AAE771 +:108170007F5B8C739FED09FC5C6389DB3B0DFD2B02 +:10818000601E6E7045D80FA7D5DA833FC579B483DA +:10819000CB71E4BA48C6D28B265A675739DC698955 +:1081A00076C1B771F87ED112C07A5A3FA7FC35B3B9 +:1081B00006D27963EDAC8103E9DD06A55A79E9FDC4 +:1081C0001F3BD13E6DCF65E45F6873C8F81EC1C523 +:1081D000660CA69CFE2BD596AFDF421DB4A385E2AC +:1081E000B79EFA4AF827BEB214461BE7D9046E07B9 +:1081F0006AF74F6E14F3E8C666FEDE6ED1D66233C0 +:10820000F901D6C8F7355E525CD332A1A9AF61A49B +:1082100019F9ACE7C752CF15F40EBC1B5FD8EDC4FB +:10822000D7A5FA776DE21ED302211F335D6E61A7D9 +:10823000F9E81DF1923A23D9F7CBDCD5B4BF59A1A7 +:10824000467F8F35C66538EF78F4E358D8A890DEBE +:10825000D3E3BF6CC7DA0D7D198E9F8FAFFB384219 +:10826000FD48CF8871B2D6CBF9BB4CB16EFF174732 +:1082700094BC5700800000001F8B08000000000025 +:10828000000BB57C0D7854D5B5E83E73CEFC243395 +:108290004926FF21413C21111212E2908400017114 +:1082A000F24BC408030182607540518490207A5BD0 +:1082B000EFABB79990682DFA7AA358CB6DEDFD0618 +:1082C0002BAD0A4880A08126E9041403040D820A1C +:1082D00096D68014B1053280B5587D8FB7D6DAFBBB +:1082E00064664E92426F5F87D69D7DCE3EFBACBDED +:1082F000FED7DA6B9F65ECD94B720E630FB7CB8C50 +:10830000E53356FBACEC65A98C2D63CAE9BE0C467F +:10831000BF6BA9F85F67E59204C6EEC53F5568DB01 +:1083200057553278AE5CAE9985CFF56F90995982EA +:10833000EB1EEF53C971D036498E4618C71E379EC3 +:10834000EEB33066817FD746D33C8C25E0FCFCD76A +:1083500023B1A75260FEB38AFFBD0878EE2CC0E1BE +:1083600081799678F873F47EF8FF32C78C2F2478E1 +:10837000DFFDEDF229730E5E5D6D32C0F8A52F4969 +:108380006C1D8CBFFF69DD78B12EFD3A1EDAF0A3BB +:10839000B9E91981710F7B9F0BE9C3DA5456C0D834 +:1083A0007D023EF6EA7F05EE73F84DAE08C632ED6B +:1083B000117167B3A05BC0265D4B63ACCE1A99C345 +:1083C000A2A03533C2233B64F46E02B8D644C08207 +:1083D00001CE355BA3BD1EC4E3EA68C646C0B8F64D +:1083E0008D26B70DE6C4DFED8C9DAB6F9E9B9E0E78 +:1083F000EBAF7F7A6EBAC2D82CBB9DB189408FB6E5 +:10840000E7685CB7E29A6487FE2A4BDF8FEF5683FA +:10841000F03899D363995C696286C07CFA7659B367 +:10842000F1CBBEA0751621FC56F86312C02FFF3D9C +:10843000F8D5C4685B006EFDBC7FAADF1002F74A66 +:1084400085395B6C81F568E326DA0DB41EFDF37A9D +:108450007A30E6A5717ABAAC443A04D117E15400F7 +:10846000AF3D1D56EF5A89F888E0F6748411DC1789 +:1084700093D6CD3D93C7D8617C00E0AE1DF132F5B7 +:108480005F515C6E7B3C5EF48F728DC76762199B97 +:10849000323CDE6046C6607C2ECE0FE3768539F333 +:1084A000988CD75DB1C807D31BFAAA2C40AA3AFB17 +:1084B000A40A05DE33FDB9BEAA30E83F629FCCFBBB +:1084C0009BFA8E5A1C8C35B02915A5F0FC63700FF1 +:1084D000E7BB5E9B6F762D66C0573580534B0CB45F +:1084E000C7C6BC8DF256D35B59214542CB984FCAC3 +:1084F000057E7046FAAC39D4678530AE33CAFD1FAD +:10850000B8BE55579B2EC938EE98C2E5A53B8EF0F4 +:10851000A000EC61F05C53B853B503BE9A622C8E98 +:10852000C654BAEE098BC1BE535583AE6BF4C0E797 +:10853000108E2603734643DB75604C545FF6F0786B +:10854000EBAA57AB14A0FFBEFA0C6AF5F78B4CF6FA +:1085500074073C5F6460EE16DBE0FBAF22BF109D4A +:10856000D414A4736DB789E41C7F12F0FD2AA1878F +:108570006A81405100CFAA63CC171E89E3CABF505D +:10858000B06D95D8E910BE6281BE3C3CDC37DAD6CE +:10859000E27C4A309F703C152BA9554AD07B4B6D2D +:1085A00099217D39D19081EB6172B86313E0574E08 +:1085B00031ACDE01EB976F8616F0A1D81DF2126880 +:1085C0009B4BA6CB4BA16D34B2852DD81AD8F26047 +:1085D0003C750879D2DA4B76D76F90EE17DEEF2D27 +:1085E000B0929E1A6927F916EB6D941C3ED4439EF7 +:1085F0002EE6D804D79A6417E37CDCC2908F7F2FD5 +:10860000E671980D3B55E0D7F7EC0F12FF3AA20C3C +:108610008FA642FFA3E615150AF0AF23C5702515F6 +:1086200078F478F34ADECF325C190DFD4F9A6B78FF +:108630007F2A4C99CCD8C9E655159E6C9C97EB3196 +:10864000B6C59985EF510C12C9A9B2D7E46D843F24 +:108650009B22393F3519812F6370BC4AE39F6A28FA +:10866000DE6C05FE578A9DEA6A1BC735F2C3FFB46C +:10867000D5F0285B0DAB118FD822BECF88756B74F7 +:1086800060ADCEAC39A8175A9C59732310AFEECF0A +:1086900011AF793DBDD3510FB77EF049813B9BD3DC +:1086A0000BE7C9EB612C12D673E1AD9B36CA528041 +:1086B0003E97EC45E7515F4BA0A61F877549AA9DE1 +:1086C000DD0372D7E864AA09D695C85EB2A3FD306F +:1086D000207D4005B532AE5F3AA35C5FE2736CA4C7 +:1086E0008FEC4CB5DDF515BE5FD3CFAC3766483D9A +:1086F000ACD757A69CC765067C1093D2767C29EA36 +:10870000F3DF9A1DB7A8088F933D0E706C33308548 +:10871000C5107B642870DFCAC21DEB50DE1D2CC95A +:1087200003F2856823E0E01707F6D02864485B076A +:108730003C5FCAA09D8470DD4AEB92919F263097E2 +:108740008C7AAB8079ADD8F677BC9584F87A3E8C7C +:10875000DDE782D6F22A737A83F4467EB444F89F2A +:108760001563A436DCD83217F934FC12B3A31FD03A +:10877000FF0B9382F38360DC89D71DFB0D0CE1FCBA +:10878000B5D16B8F82BE3F53515F6681F9FA059D6B +:10879000B5799F37A999D1D0AF8A91082FBF2EE222 +:1087A000F6D8FF85C9FB722AE2C7B2DA1B2457E369 +:1087B000A3F9B8BAB8E2B1D1F07C4B4738C3F74F50 +:1087C000EA0C3720FE376FC90D433ED886B881F5D5 +:1087D000C798ED8FE07C315700DE54BAEE24BC2AF6 +:1087E000EA8428C06BE14C9BBA0EF0FEEBB0969980 +:1087F000C8F7FEAD06F632BC629BC93107FBDB2E23 +:10880000AB76D4B3BF4E6D09A7F56C35D07AB6857B +:10881000FBC7AD01B8D7652815089F62650AEA5FF6 +:10882000C550AC3E02D7A74573FDA8E9E39A689509 +:10883000FACF4BF0FE5C1C5744725326DB48DEFA3D +:10884000FDCC6B86F7C4CFEB95911EE173809590BC +:10885000DF159FCC703E17121A5A9BD1AB929E75B2 +:10886000DA9600DDA70B3D3BFD644D258BC48EE3FE +:10887000D854986F9FCDC8705DB7B13ED902FDDB6B +:10888000AE32870FF9E7AA427E981DFE05FB7B6595 +:10889000629E5F494C898271455FAA0AF257110BAB +:1088A000F5DBCA36947F81F6ADC4A2BB8EFE5C2494 +:1088B000B64AE03ACCB3285AF861A3D8A86BA4CF43 +:1088C00060D6046147555C7FF67FE1BAFA2B4C0E07 +:1088D0005CFF769BF3E3A9A8077B8D6C131B5E8E70 +:1088E0007E550F1A7D0C08C7D570E68D253EB42144 +:1088F000FDC76D68F684C17AC7A5F3F991DF506FA3 +:108900008CFD455C2CEAED8868AE4FB456E32FE44D +:10891000237B14E723FBAD01F9FB5E742A8DD3E4BE +:1089200009F90BE7D963F42E760D6117812FBF8704 +:108930007CB9DDC62A90CF9F19615988F2A4BD6722 +:10894000B7E07B7DFB54C39A2E23AEFB2FA0FF0123 +:10895000EED2E4ABA660FBDD15C7E12D93BF25BFCA +:10896000FA62BB44FE7C423BD7D7C17C316268BE11 +:108970007801F17A3DBED0C7011A5FECB81E5F7472 +:10898000FF637CF18B68E1DF0ECB17DF46E2FA1F55 +:10899000EB2849647FC78F69137C30DCFD2956AE14 +:1089A000D7F4D7DB053E779B9AEFCC41B9BFCBE03C +:1089B00040B906AAA7CC05FBB23B9C3FC794D5693A +:1089C000D8DFAE703DB2BDDD4C7A64BBCDED267B09 +:1089D0009D6461E82730C5DDF77DD47FC916755DDC +:1089E00010DF3E2EF4408BD137E573F47F0F70FA21 +:1089F0004EBE2B5736C1B8110F70B9CE3F67DA287B +:108A0000C33CD53145BE6818DF17CDED62DD1918BE +:108A1000057C597BC644FAEDADCE23E54E1BF937F4 +:108A20004EE4AF497B8E941767E378CE47DDA2D53D +:108A3000FA53704D3164768E25017E5DC24E4C61D5 +:108A40005C0FB9903F72027DE634523CA6F141358D +:108A500063596827E6F639CA908DAA2A42E95BED88 +:108A60009B4971DFFCE3CEB20858D77C97EEBEA0DD +:108A70007FB58EFEE007FF01E564D5E6DE4E1BF212 +:108A8000ADCAED698B697516F77B56A7A1FFAFC913 +:108A900011FD004F2DBFCF78795D901D5763F83AD7 +:108AA0009F752874DFD367F2DE0297FE37E3CFB5F8 +:108AB000087BF3AD90E3DCC7DE588CFC9BB7DCB9D8 +:108AC0000FF1BF284EA6EBFFC97C9634A48F43213B +:108AD000FFABC5A8967C2E05C631C5956183FB7B8F +:108AE000E2C3F3F0FDD531EE6B4827A6F8BBF1B930 +:108AF0004985B9792857B6094DB1687F34B801AEB8 +:108B00008A4DB6001C1A5CE785FEA98E59720DF1DC +:108B100080CFA15E693B75D682CF6B746FE9B8C414 +:108B2000E91D447FA47780FED27DD8D7F06011ADD7 +:108B3000D6FFE7E9EF1B89F41896FE18F747FE8F7A +:108B4000E83F2A6608FA833F958ED7357FAAC50489 +:108B50007E7576A0AFD1BDDA5E44E31C265819FAC3 +:108B60004F9D1057A21CBAA3D1B9613BEDFC5DFD2E +:108B7000BF3F3B0A5C4036292686CB93C93F06FDA2 +:108B80008D093E89FCBE0920F0F7909F3592F49D37 +:108B900043E0879D95A4B319DC05BF9682FE9F2F05 +:108BA00016E56082B9D287FCBEC33A3D05FDB75CCD +:108BB000EBB434E4A737331E3B8426E7CDE4E53B32 +:108BC0005F51037E8EA6D7F68969B5F797C770FA0D +:108BD000DF0E6A16FD3D740D83E1D0F4379205E196 +:108BE000907CD5866B56D2C7ED7D80AFDB110EC071 +:108BF0006B97C45A517F17199C7125E88FC5FB14D8 +:108C0000EED77D3D4A05BEA96C7FF738C25B69B1DE +:108C1000F930DFC21CC6F37D41F912BD9FABF925C7 +:108C20009ADFAFF92D5A7C89FE0DDECFC7EB00BF6E +:108C3000DD0C00A2FDF159BC0DF0FEE72FAB994E03 +:108C400021AF0AACA352AC6336EB25B8D8B7D7AE88 +:108C50004D03FACC12F8A8EC86B83007EF3376173C +:108C6000E0E12E85C78B7739203E0CE2A3D99343F0 +:108C7000FBF89B9E1098E77AE3F5FA7FAAC817FCE9 +:108C8000B371A6D676831D3A0D0C70B09EC734859D +:108C9000A3658F82F1803BD380FC5827EC1A84C9EE +:108CA00043DB2321AF8586BE1C07E0B76BCF37645B +:108CB000FFF6EEF9E623F4E7A67CA130333C5FF83B +:108CC000457E14EA07E60A9DB7EE8FAD56C6AF1390 +:108CD000FFD48AB5EFAFC78C18C267A1F637E79FFC +:108CE0005F8FF37D7946E1BC2DDE5F6E72A7DB6D91 +:108CF000D8F2787FBFC4FD1DEDFE7E23C00DD737AF +:108D0000C568717FAF42F919F89983E87C17C6FBF3 +:108D1000B901BADE75AEE20B2567307DF0F7FF23AF +:108D2000DED7E2FCB744FCC0F69D30A900D78CD654 +:108D30004714F4A36724C9CC19F4DE3B542B730603 +:108D4000C5FB6FC4E8FC907DAFAD9F0576A4AE4730 +:108D50007684A1BCB66F3F9483FD5ED9611D828F7E +:108D6000F4F89DD1FE8882FC9F10CBE5E67AEF2FC8 +:108D70001C077C722BD29D911F77B1402239D2D330 +:108D800077EF9E9FC7F6650F8FEFE1E8AFA7C36F40 +:108D9000CE1747215EAE470F3DDF76C23A3DB03E6B +:108DA0001FACD303FED6DE7A3BF5DFAE4FA2BEC6C4 +:108DB000AF751DBF8C457F4DE3D3B258CE37537688 +:108DC000AF8F65B600BD347C5D1474AB668EF9B3AD +:108DD000E0CF5D922382F48487F5261504EC55F5E7 +:108DE000B172F233347B552D671B51FF6AF60AD3FB +:108DF000C2A8CFF4F6697E7A9111D5AADE2EC102FF +:108E00008DC8BFD50B43AF57F4342B11D433109D0D +:108E10002449E043F8D51A3C1F3217C1ABA7A70677 +:108E20009F1E2ECD9FAE1674837596E1D2E7AA459C +:108E3000B48E417655ACF746EDA9393634CEBA72C8 +:108E4000AEF4FD9C21F87538BED5DFD7F44039BEAD +:108E500020975A0FFA1109B10944AFF2AB26E60484 +:108E60007BC14686B1CF82F3EFAF6492BD7B54D80D +:108E7000DFE1F8A6F6AA81B96303FC636C7BCE8AB6 +:108E8000FCB35B69B662DEF136DB9CC628C053E9F1 +:108E90001F8BE7A15F57D76760989A2A6BBFB40F03 +:108EA000E3F6BAE3CC81FAB0B8BDAB04F9ED6DA539 +:108EB00057A638FA4BC69E0BF20FDBDA1BADE83F24 +:108EC000B5C5C914A7EF8FE6FCA8DD6F89E5FCD70F +:108ED00076E6F22CE710F73F13F74B4FE51AD1482F +:108EE000F6C74750BEA1FC6903ADBF54B25755A2A7 +:108EF000FF718791FC7A885BFEF07DCC37B599B71E +:108F000063AABEACED878FD881102DFFE7B306337F +:108F1000E60FE6488E97615CB9EAEFC27EF9BC5471 +:108F2000DA8799F47F65F25FFD774B94F72807762F +:108F3000C17EF93DA95ECC3FEC9178DFD3C1F3FE51 +:108F4000CCEE899D05EFF9A03276C23AE229AD7FD9 +:108F50004BEE3A261838289E7A6C17DF3F7AAC4CD5 +:108F6000A2FDA3327B0AF304F155F9D340CF3CE0D4 +:108F7000C7F6C462E4DFAA0A997983F87ABECBCA3D +:108F8000BC41E3F7877178FC92D98BF9124D5E678B +:108F90000AFEAE5E181B327E0EE37EE242D66C44C1 +:108FA000F9AE13F0D415013CF0FC4C11A7DEED4EE8 +:108FB00009796F256641606856DC68B28FB3BFECF3 +:108FC00023B33A473E796C31BC876570F9D0E4AC85 +:108FD0004CAE69223E48921C181FCF97C0AB9451EB +:108FE000DF85CAD1ECC9A1FD394EBD7E089577BD9C +:108FF0001ED7E47C7E876CC4387A7E91E46043E8B7 +:1090000003BD3FADD703930C8E7730AE9E7BD54921 +:10901000FC35480F9CACF887F4C05B205B93415E45 +:109020007FA4E9839BD84DA80FCAE42DEB913FFAAA +:10903000C1AE9987E00FCD2E68F17639C827F203CB +:109040003BCFF725CAAE829CC606E2ED01FD007E4D +:109050008363087FE657B16921FB4903FA22C86F91 +:109060003016FCF37E4319F88BA65C846F24F3E47E +:10907000919EA2FC1EB43ECAB3255DA23C4A1DC40B +:10908000F114CFB35F125CA8D7A49800DFEBFD0901 +:109090002D4F3B42E409F4FC3090B79B67F4229FCC +:1090A00069FC506EE772513E4FA6FCB99E3FB4F783 +:1090B0005D8F2F7C12F085F477F842C8D38DF2C50E +:1090C000218D1FD259FA8DF083C6071A5FE8EDC5CE +:1090D000415DDE65387B71F23AF6E29D0C23E9656D +:1090E000BD9DD0ECC28138AE7FC7C7F27D8A999909 +:1090F000F36DE8578C407D80FE9EB0370379A30D59 +:109100009C0FDEE95BAA486837500FA406E15DE4D6 +:109110004D35BEAB7D9A51FEB052E89F8B1D3C9FF2 +:1091200056572A7B2DF06749FB73EB79DF48F9B678 +:1091300022A54BB1C0BCB31D9203F3354E917F9B6A +:1091400075D5E455293F3FF47E7A95E01B8C73700A +:10915000FC6CA7E4851074901EAABACAEDBE5E1F0F +:109160005589FDF22ADD7EB9294ED0F56676F3BF2A +:10917000D2EEC7C72570B919868EDAF31A1D35FAF3 +:109180004DC0B1283FFBBE36A911DC3F46FACDB831 +:10919000AAD03CA3E242FD962FCFE7FE27C574621A +:1091A0007C5DFB25937BFCF0F05FCF2FBD59F3C3B3 +:1091B000855FAEBD7726C8780A3A863AFBA1BDE73F +:1091C000BAF6423CAFA7D3E4B8D07842A387A6470B +:1091D00007E15BE8D9E1E8753D3DABE9B37FB59EBA +:1091E000D5E6D7EC80F65EBDFE1D2E3ED3F4E953E6 +:1091F0001B0D9417B94DC4C1B7893CEB8342CE9780 +:109200000B7DDBFF178B01FDAC6D9DDC1F7198EDB5 +:1092100087D06F08E4F3385D9F8C601EDC2F674AAF +:10922000AF85F62F8B81A4B87F99CCF72FB7283E56 +:1092300017E96987C21A405EFE2AF2164FEEF52C36 +:10924000463DFDE4E93106DA47577CBD18174FCAA1 +:1092500055683F28DAAC52BEF76287D98ECFF5EF5A +:10926000FE5E9711E7F90B7360A8F6768779603F89 +:1092700006F54299DC23635EBEDF0FBE388C9FB6D5 +:10928000D05782F1CE6DACB711E3EA42A4E310F4FB +:109290007B55675FF479FB920EEE279544F0BA9FF9 +:1092A000E980467CEFF43613F985D7CBDB177DC90F +:1092B000C85F1A94AF6FE37A0606119FDC68DEBEC2 +:1092C000107D3DE0E39FE8F40E1B267FBFCDC4F781 +:1092D00073FC478C0CFD5E762E6EC8BCCBF5F2F8A5 +:1092E000BB3BC39D6A24EEBB71FF7C7767B253CD55 +:1092F000197E7C4E9FBF18F395DBB6CC55284E14D3 +:10930000F9CF41FB223AFCED90589315F369ED8EAD +:10931000528C3F86DBE728F63B69DE1BC51B63CD1D +:109320009CCEA27EE9762163DBCE863B91BFB79DC2 +:109330004D76223CBB057F6AFCBEFBCCE570DACFE4 +:10934000343955DC07F6475B1C2F13BF723E6F198B +:1093500031C68BFBADDB853C6C0BF71FCC8A0BDE7B +:10936000CFE0FB179DF59EAA33E9B4DF2D61BE5116 +:10937000DB27F680BC505D4E0C237E32B21686EFA2 +:109380006D74B29F633B7D9A1A85F8BE1CA7ED47AA +:10939000AA519467F8F64A816BFC60BCEFA877513C +:1093A0003D496BFDC22A05607CB3DE4D6D5BFD72ED +:1093B0006AF7D4AFA6FB6B0F453E8E76BFCEB9A041 +:1093C0004A09D21B9FC5F3FC526ED6E912E473F62C +:1093D0000D6318EF4C7FA24F463D71FB555847482F +:1093E000DD887219F14CF9CBB4403F555A12867C96 +:1093F00079FB55E8078D97E2A3391D9A94A65B0A7D +:10940000485A881FC2E29D17E3E0FA0FED2E7F5CF9 +:109410003CF241F5BE0B8CFA97F1FA0EE96EF902B7 +:109420008CCBF31551DE380FF3C6B934ED62C4DFCF +:10943000C42E13ED7B6BF9DB5C31AFF3ABD03C7228 +:109440009EC8DBBEC9FA289F9C6F81C0CA8070711C +:10945000FA39A5F94912E6FBE24D0EAC579898E6A9 +:10946000CAC37C6B573CA3FC695757C24815F0E050 +:1094700054785ED7A9E575D9DFCFEB767F1AE9215D +:109480007D057E0AEAA7EEA3910E1FEDFF59C8FFE6 +:10949000DB810F627D4338AF1760F3E6511EFD7626 +:1094A0000B5F07D89FF878CAFBF9F61D86E77E7B2D +:1094B00099F17DC4DE93B43F5D62C84CEC0338F78C +:1094C0004963A3B07DF1D3C86C6A8F469E47FC7494 +:1094D0001AAC2ABEF7C37A56857567CEF76DB49F6E +:1094E00031FD7D9B82EDE1FA3EAA477BBFFE1CB5B4 +:1094F00047EAFDD41EADBF4AED3B701DF9E7103CB5 +:109500008F6DEEE2087A6EC7A20813C2DB19C9B6E6 +:1095100068EFC17A335FB8AF1593F9EFC57FBECE60 +:109520007213D83BB37BBC3481B113F19FCF54A0ED +:109530007F68C6A87FFF0BDCFFDD4F2EACB3005C5D +:10954000F38EDA5A7BA0FFE94F2EAEB3A19E3D14F5 +:109550000ECA0EF546FF4190749687363D99710507 +:109560003B19FAB1A2EFE99F590A245F50D297C57F +:1095700080B5A6FCC43FD302785C6075FF1BF64D36 +:109580009E976696DE847DE6C17A2EBF64A4F89E1F +:109590008D94E2B07E6599DD7D2C3EC87E3BA53F73 +:1095A000D2FE51815362D1714457DACF62F653B182 +:1095B000C1F2B6CC5E760CE971473CDFBF9A384DFC +:1095C0007206D749E8C74D3CA396229D0ACE95372F +:1095D000613BBB229AFAAE85939A509E4B6DC33D78 +:1095E0005F42CF2F8837127F162B52487D887E5CD2 +:1095F0001E3013FAC7FE03E194179878CCDD887506 +:10960000A36549A9B9B2D0798CFAD11B711F6D62DB +:10961000E587A5B1283F36C981E6A180F535C5C6E5 +:1096200061FD231644E1BA9E2BC1FA9D89AAE4404C +:10963000B41539BB5AF1F9224784A308FDF1636AD6 +:10964000299A9CA3CA84C3F9306E46BAECB0C044D0 +:10965000477D774CBD00FDA28C28CAE31629ABAF2D +:109660001CA67E84A341C5756CFC792DCD63267B39 +:10967000BE6356C97F20FF14BBA228E7576A3B355B +:1096800037B82E0CD64D7017D9656F9884FCFD83C2 +:10969000523BF4778C9218CACF515FE69FE97E77F0 +:1096A000B81A0680EE30D94B71BE1D26C9BE96FA97 +:1096B000AE121CEF196354314F541EF745C8FC33EA +:1096C0004AA5296710FEECA80978AD62E4A590FBD5 +:1096D0003D8BAC64272ADFCF267FA867510AD98B40 +:1096E000CAF7A71563DB63E07E7AE5FB951574DFA7 +:1096F000C0E3DFCAC5DF718A3EC5BB958B5751BF3A +:109700004B4AFC777CDF95ECA85CCCA3CD4CFF7A70 +:10971000AE12ECFFADCE24F9CF1579BC2243E6FAA8 +:109720006900FFA307F83E4465B6145237372BFF94 +:1097300054483DA86BDA1721FDB9A59742EA43E7E3 +:10974000557E1DD25F304FAA0A1E5F7A209FEC6BB8 +:10975000BEA85FD2F24B458285DEA9CFA82A05B903 +:109760003C00ED03A01F8A7A45DE55E1717506FCC9 +:10977000433D586AD3E577994AFBD915DD7CDFBABA +:109780003CCE783AD83E54C84F707F41B7FEDC03D8 +:1097900046B293B9D132E5AB34F82A46863EAFF9EA +:1097A0005F1502CE1D0677530CE5C79CBDE87F68A8 +:1097B000F06BEFD7E0AE90EF29A5EDBFEBC0AF8720 +:1097C000170025FF4D0FC78178118780BF41FE59D3 +:1097D00037AF4B835FDC50765BF3CF2B414F4507B0 +:1097E000EB299B1487F576C3E9296DDEE1FC306D2A +:1097F000DE6576173DEFDCFAD9D14239A89F7A2A87 +:109800003626B8FFDA67EB43EEC79FAA8A0EEE6FE3 +:10981000FAAC0AEF4F57D4461BF0E34126393CC857 +:109820009F3DAA82FBCF25C79C4DD8969D74639916 +:10983000299B71C6D384EDD4F3DE1E33ACEB8E0CC2 +:1098400059C5B85DF33FF4F09A13781C72F0AA6A18 +:10985000C5FDD31D1ED58AFEFB8E27542BFA1F3B58 +:109860009CAC02E331679A6135FAF3CE2C5E6778DF +:1098700055E8E16FE2F9F35A7B5A717F837A11EB75 +:10988000C2D127A8FDDA4F75E007D1AFCA1EEC5749 +:109890001D54BC367CDFC127BCB6E07DC21BF5ABD6 +:1098A000FE8C363A1EF96C4E887C9658EEAE0A96BF +:1098B000EF32FB9290FB9FC6A904FF8CA48743C69E +:1098C000DDA13E12D2077F3103FD914613A33A5921 +:1098D0008F81D7C9EAF1F8A8C0A3C36647378619B4 +:1098E000E354AA6BD38F739470FCE9AFA727F0B849 +:1098F0006823C80CB6F72470F8F475B1FA3EC47C3E +:109900000B713E983909F9DC61355C0157973913C1 +:1099100092EEA47AD93CC3A369D0AF4EC8E2FDA9A8 +:10992000869D581F7B774236EFDF6AC833821FF06F +:109930002B36FE4EAC07AF0D13759D0F24D27E98CB +:1099400016DF2886532F2EC638738F9161FEFE19BD +:1099500013D8BDDCC0BEB9D5CCE352AB89D76D3FBF +:10996000957AF429D41B6A987B7A02F951C52AE2C8 +:10997000EFBCDD42759D8FED2E4B44FADF93C0F3B3 +:109980005C593BA726A17EF917BC7F56C2C4E1DF14 +:109990008F75BE38CFF91D59E47F67DD0CE895025D +:1099A000F887F098AE87419840E725983309F36C23 +:1099B0008DD1269AE79E04CE7F37DA0EAAFB8D3230 +:1099C000ACDE0EEDFD82FE0FE07B095FFE51737091 +:1099D00063CEEE1F35773CEF237D6539D78F7EACA4 +:1099E000FF3B11B4AFC246FA69FFE5E37BB21CE866 +:1099F0009F7E12CEF1B7D03BBAB14FC5FA0DEF4DF5 +:109A0000582F9191E8AE453C2C327B6F21FEB1ADD1 +:109A10008EC0F96FB41E78F07B218004FA544FE1B8 +:109A2000F4D1DE0B38B5A03DF8589C03D1E080F7A7 +:109A3000FF00F9408367000E5D5DB89667AEFBA33B +:109A400081F20C7512E83DE8EF3CC91C1E98E7A2B4 +:109A5000E6AF8BBC266E45E17BA61C5E5A62833660 +:109A6000BF6D258F737B95903CD7A4E38A7EBF831F +:109A7000ECD654ED795D9E71AA886BA7EAE2DA17FD +:109A800013849D4966C9C1798035226EB8DC333AAA +:109A90000AFD4CD45132E0D5A4CA6C724C40CE5B66 +:109AA00021EE674171BFC667E38FD9EF47B8C71F83 +:109AB00063F7915DD7E61DC82F70BC5C3ECEF132D6 +:109AC000A12FE3A7D3A06FEC3632AF1A584F21076E +:109AD000955DC6FFE078BBC98B75CB05077E99E71E +:109AE000834BE624035383F010A6863335482F5A60 +:109AF000336242FAB2866F61CFF3C4FC118EE490F8 +:109B000079F6C49477A37DCFB32D27FB1E357974E6 +:109B1000C83CAC4709B1F3B028DABF9C0840FD0C43 +:109B2000F05A704C09B1E793E23CB86236F9A4A24E +:109B3000B3FFCD32CA41E199D0EB0786A3CB70F8D1 +:109B400063393F45FFEE1FC55FB433147FB115A1E4 +:109B5000F88B7785E22F7161289E46B843F192B267 +:109B60007C5CC8FD9B56E786F46F7EBC30647C2A23 +:109B700018A4E07EDAD33343C6DFD23C37A43F7665 +:109B8000C3A290F199DEA521F7B35E5D7143F41E87 +:109B9000DFB226649C9EDEB7B6FDAF9079357A7B46 +:109BA000E0DFBF82DEE6C4507AA70AFD1AEDE4F5D5 +:109BB00065FD46DBD312E8234C13A15E8B6E7FF765 +:109BC0006BCC43788A55AA9FF3CC64B40FFD82EC2A +:109BD00092500FA5C0148634AA5FA7FABB1F1B0CB6 +:109BE00021FBE28989DCBE2726F27CCDCF4DFCDC4F +:109BF000520AF88F64870C2C102F031E22315EA6A8 +:109C000078FAC7CF60BCDC14DD97A1427C6CC6FE3D +:109C10004D017DB9C8AC36F6013E26C85C1F829E58 +:109C20004C4B84F93F919E30723FC263443F22C542 +:109C3000C23C91B9643F287F1CCDE224ACC78F0A97 +:109C4000E869F51A106BDF8A2C3A07F51E4282FE8E +:109C5000AF2586ECE8DD9A7E5A9E49FAE9B22DD40A +:109C60000FBBFC401A5D3F71AF99F6FB4F883A4439 +:109C70006DFDE784DEFA53BD85DAF3F5F6103DB6E7 +:109C80007CE3FA08F41F4F64707F51BB5E82789BBF +:109C900088AD2CEC9AC58EF9AC7BC0384701BE5715 +:109CA00075F7452E62E43716E3BA6B375EB9F74DA8 +:109CB000E8D719FC09DC3E7878BDCCC78CFCCFEA2C +:109CC0006F5888FF343791C7E973C5FC0BA0B10307 +:109CD0009E1600FEA3B17D775A39F2275CA7F3697F +:109CE000B3BB19D59FCC71A7D23EE351E6F87017EC +:109CF00080F89D4495E09CC75CB45FFFD1BDAB226A +:109D000070DCC07CDA3CC028E86F7C1CED3126603A +:109D1000DC7F1BAF6F80F759F0BAEB9E9427D10E12 +:109D200069EFFB88B92F7C88FBDDCC41F36AF33304 +:109D30001613A29F762C5FF9692CBC6FCD0103E549 +:109D400013D6749829EEEA5FF1D7AD2FC2FDFB520E +:109D5000FA6E42BBFCC98A6FC6203FDCBD01F4101D +:109D6000ACB130CAFD7062509C72E2812B11781F39 +:109D7000ECEBA617D1386E36537DEF272B368F09C3 +:109D8000F6471F4D2CAAC5E7D8E41B3B6F58F27A63 +:109D90006622D563097E7A58F0D39AD7C6921FB54A +:109DA0002662809F787F13AFEFD0D6F1A1E0C71570 +:109DB000AF7F5D107CCE7407F0913A86EF6BA920DF +:109DC000533B7B2EE7E0FD57147713C2D779F57428 +:109DD00024F677BEF737829FCDBB317851063D051B +:109DE00081FD65EDDCE5C2F6D83CA43BC85933CE15 +:109DF000BFE837AF5DF81DE2A763F3A6EFE3981B5A +:109E00003C7FC9847D71083C807DA1F8A09F85F3CB +:109E1000731D428F2AB8839E86E7991C2AF1B3935B +:109E20001DC27D97C62E03C3BA9548DCB409CAB3D8 +:109E300045CA06CD08392D49A09F855E7925F1E4F4 +:109E40009D4DE4E787FA3DF96FAF08F1775CF08F3D +:109E5000FC9D97DC8D9807BAAEDFE3332C3145DDEE +:109E6000B8FF0381B0532A105B38F06B4B14FB2210 +:109E7000420F77A21C61FD3FCE85F97A5F383F67BC +:109E80000CA602F5F80F604DF8B02945B4D2C50C08 +:109E90000BE8C5BD897F78E669D0939674BE5EEC09 +:109EA00037E2DFDD9CDF06FCABB7C7919E62DFC205 +:109EB000DB100F225FA1A7533EC8078B0D9233F131 +:109EC000BC6FFFDF22314FBB35467D1FE9E03F20ED +:109ED000D33E4D98D2678A1E222E7B13F59E89FBB6 +:109EE0004D546FDEC6F38116D5C9300E08B3DB279B +:109EF000049FB36B17FA6ED5FE4F4699800E170C70 +:109F00003D91D9307FCDAE1D91E8C6DF6B747F8A5D +:109F10007CB7F2C40705763ACFB671149D03F08D75 +:109F2000A6BA83F10AF328B983E1A8DB904BC6B83F +:109F3000760325E3D9F8F6BC87501FD5F9F83A71B6 +:109F40006E2CFCCB6C63D4BFD8D61883F3D5FDB68A +:109F50002319E567733C8F135FBF3A8E3FAF30051F +:109F6000C77F99182DF8D96BC03863B3884F2E5E20 +:109F700035D038EDFDE3DB8A643BF043B6AF792F93 +:109F8000C543ED6615E91AF60AE378680F2339AF81 +:109F9000EB9CC1309FDF1FCD1C12DCDF1AEEFF03EC +:109FA0009D33EB30AB981F0DB337B318987FABD808 +:109FB0000FCD048EC2F34ADA75ED7D61ED3FC558D1 +:109FC00002F981F2B4614A33BBCD168CE708C27343 +:109FD0003CF2533CBEC767C0FC88FF16C65E26B87D +:109FE0000270327AAF066726F9735B4DFEB3787E56 +:109FF00005E0B223FD33198793B58F5531BE0FB3FA +:10A000003B691D6176D5E19106C35597C3BC68BF16 +:10A010007FBC960DC82BCA6F5D78A06F0119D83A26 +:10A020009A09F9B63F5B3A2DB80F8A6472E0F9716C +:10A030001B629E6D1A49718347C63816DA88185C10 +:10A04000A7CACF3B636A2897E301F7C5AD167E7FA9 +:10A05000603CF0B70DFB363ECE1165B7CE94484E4E +:10A0600028AF572BE4FD31C977F67690D3BFF8F6C9 +:10A07000E6A8004BCDBB7B884F571ADA5F1C0FF761 +:10A08000375ADCF94980CFB74E1AE81CE99F5E0BBE +:10A09000F35662FCB87B63827308F9D0CFFFC3E349 +:10A0A0006B9F4F41FAEF9654CC9BF61BFDA310DE3D +:10A0B000DAF6CF4D548FD0768AEA938E24B99DF884 +:10A0C0009EC96D0DB46F3C8535D3BE7196387FDD6A +:10A0D00092C4F5C7E563635E6E08C2FF8349DC0F77 +:10A0E000637EF7CD2837ED423E3BD12F817697F046 +:10A0F0008F7675DD9DA606E5FD1AD8DE14C4F75AE5 +:10A10000F636B5DAF57E2F3FCF98F591E53E67102C +:10A11000FFB993B89FE716EFF327B91724A1DC76B0 +:10A120009D3645AA785EA56514DA9116F09FEC433A +:10A13000E065406E757254A7F84D38BEEE1C3F774F +:10A140000A746EC2FAFFCD1FB58D5B02D77701AEE0 +:10A15000B1DED373C24C758FBB8CAE141CDFF0E143 +:10A160005739A8B72A1069F0BFAF3A56DE8C78038A +:10A17000BE2F0E47F9DACE488F69F2998DF209CFDA +:10A180006723DFE7633F93F4F056532F3FF7B98B14 +:10A190009FFB04BE273900BEB7A39F906D0739A06F +:10A1A000E7C7927C6FED35D0F9540FE8F15BA85FFB +:10A1B0005C85FDADBDA576926FCCC3E7A29CFAF697 +:10A1C000D23C2D108320E924E60AF61FDB132389F5 +:10A1D0008F35FD783091EBFF960C350AEBFFADB271 +:10A1E0001C2217417690F7859DECDD50FCEC0BD3DB +:10A1F000D0DE09BB20FC27769CEBF94785AD5AF3EE +:10A200004EE1EC2DB0CE3587E5817A6EF4577D8234 +:10A210004FF60AFF15ED849AC7EB67F0FAC40DBC40 +:10A22000CEB5C0B9BA04CB38265734EFC3B6D0D5B3 +:10A230005282678EA72DECDDC7CF1EF3F3E3AD7B13 +:10A24000EFC8C27DEAFE136686FB24AD7FF3FFE113 +:10A2500075C0C3773B01FF43D825580EF11F58EA5C +:10A26000149634F87EBFA4E98FF995286F175BE543 +:10A27000401FEC612D3038F67F9D54F5AC07004B44 +:10A280001BE17C1D59A230D94D6DFF91BF25A02D3A +:10A29000D8758CFB4DAD266716F24FEBE8D0F3FA7C +:10A2A0005AFB62123FE79C6F6643E6250F09BB37F6 +:10A2B000C6C39E413EAA6D95ED5EA0FB8556D96949 +:10A2C00002FFE6ACD39D806765CE31CF82A968E7F7 +:10A2D00045DCA87D4F6519FA2760A71E7C61501EDA +:10A2E000DF807CF450BBC47E066B5EFED2D0FB0ADE +:10A2F00035629E87DB36EE4F013AAE7825745C8D71 +:10A30000A813ABD1F92F8792447C98C6D2D02F01E5 +:10A31000FE21BD605458B719F8F5C1647707C61B14 +:10A320009BC5770C407F921C7608BEDC2AEA04FCB1 +:10A330005B25DAD7CB7CD52B1BE0F942C52BA39D3F +:10A3400062D0E23EC164A7BB1CF10BEB3E86FB353D +:10A35000CB851E5CAEF9655EBE9F01E696FCB22918 +:10A36000CCDB1889EB7E5572F854FC8EC8A03A5CA1 +:10A370005A779D5877CD8623FB318C5BD5123AAE48 +:10A380004EACBB4EB76E6D5FFBCF49BA73C837B8E2 +:10A390006FF16723F7133E10F368F7CD23B83EAC97 +:10A3A00005F0906E355ED9EBE57E9D0DBFC373BFA2 +:10A3B00080F77E41EF3AE633A5C0B8552FF075B26D +:10A3C0006743EB3F1F6C7DC484F1959E2F966F31E0 +:10A3D000923F0A8833A1BFA8E78B1562DD2B74EB8F +:10A3E000AE754B3AB8B89F3C18AE960548D7555B4A +:10A3F0008C0CEB11F5702D6B59528E7C36985F39B1 +:10A400005D5688F90270AEA6737C370AE7A8118200 +:10A410002FC7B17144978AD81BA28BDE8FDDBE7F18 +:10A420009C15E5FB72F7688ADF35BAEB9F2F177E24 +:10A43000F08C0D8CDA0B6D25D6F118A7F4181C9250 +:10A440004AF156E478C0475E87CC2AA1DFDF9EB68A +:10A45000DE0378CF3D9C5F85F17CDE61039D77DB79 +:10A46000D99D4FFBC07907D263D3281FEDA0EFCD54 +:10A47000C03C643FFB7B72D7E3B980FE9ED27C9CDC +:10A4800057827168E773851D68E8C9B5069FEF2E8E +:10A4900018C1E3F5A7923EFB31FAE133B61BE97C24 +:10A4A000C30CA3FF3DAC9FDAD9ADD0BE75CDE1A5FD +:10A4B0006BC390AEAF49B46FBDBF774DDC62E4AB08 +:10A4C00076A31DF7A1FBDBFF6D2FDEF76C91E87B18 +:10A4D00012751D65595BA19FBB31CF117CDE2B37F7 +:10A4E0005A25F8D8082BC5C3336E32925D3C9F6C59 +:10A4F000FD25FA372B9C1B498ECFEFD969A2FAB9FB +:10A50000AD1243D3BF3F69DF1B888FF36F1E31A1AC +:10A51000935DD27AC4D4F777ECFD052F04FE1407BF +:10A52000379B304E59B551EBF799904E2EE1FFD441 +:10A53000BE728AFA2BDA24D2332B5E92E93CFBBE40 +:10A540008EB74CC8C7B55B2496981A747F8314F2F3 +:10A550001D84A58CF3C152A1675632EF53C9306EEA +:10A560006533AF23604F87D6E5AEDC3287BEDBB400 +:10A57000AC79687DF3B0E0EB87301EBC15BF831467 +:10A580003AEE61EDBB5C3A7E7E5CE3E74C9689FC7B +:10A59000FC55911A950DD7BF3AB2E2E6A1CEB1F7BC +:10A5A000083BACD9C1CB3E03D911FDB88B6D570820 +:10A5B000DEBA9ECB26B483E5ED9708EF95ED5D54AA +:10A5C000C7711773D7209EEE6AB7DA518E2BFBB88E +:10A5D0005E9AD96EF67A25BCDFD284F4ECEFE4758E +:10A5E0008B9E3D12F92F9ABE7A48E0EF2181BF87FA +:10A5F0004041A7E4A21FCBE3DE873336EE8F81FB19 +:10A60000B5E27ACD817D91E8EFCD6497EE457AC0D1 +:10A610007B18BE87BD148AE73B1987E3CE2DBCDECD +:10A62000596FAFFA4764CDA6FC23C49D084FCD9661 +:10A63000503CD7EAE2ED7523B87DDEA4C373A59F35 +:10A6400059B3110E5576786974AF82EFEDCE91282B +:10A65000BFDAADA6450DB5FFA8B5EF09BF59EBCFE1 +:10A6600016E7AB5BECCDB6E038D894CCEDFF8A2989 +:10A67000B207E934103FA4EFCB510D81F801E28617 +:10A68000DF8C88E771041674BC3B5266717181F8E7 +:10A69000E18749EB2B73A15FB785CBF9C5C9301FA3 +:10A6A0007EDF4B61E45FD66D31D339C03AA03BC544 +:10A6B00009EDFC1C83AB5D2A437A83FFFDEE88899C +:10A6C00078AE8619E360DD73DA389FCF29BD447C0C +:10A6D00072209DAFF7B2A2260EE58F6B7E389EC327 +:10A6E0005283CF3F805CE2F8DA765E0FD4BAF7EBA4 +:10A6F00051A9A8D73AFE3A6A09B45746F0F56B7EDD +:10A700009E1FFCBCD1DCCF3986FEE7839ADCD8F9EA +:10A710003EDA83C2CE30A989F8BBD6D8F2760CFADD +:10A720004D5BF9BE3DDB6DC46F9CB1860F5E6F8AD9 +:10A7300081755F7C5DA27A347CFE09E0B38B4B5B54 +:10A740004EA31FFDD5560BF98F0F828F383D77B082 +:10A750003C6A72AB7D77AA81AD257F722D6BA276A4 +:10A7600095E0E38B6D8D26CA9B79839E1F3DD8EFC4 +:10A7700058A5E33B537228BF357C104EFE5FFF01A6 +:10A78000D98EFB2780A7FF4E0EC687F02F5AF7867B +:10A79000113DFB8FD8C85EFC49F0D97991376E988E +:10A7A0002CD3FA0D53789BD5F9D668A41FE21BEB86 +:10A7B000DE3777BE358E9FA7F612DE57BE8A49F187 +:10A7C00020385BAC94DBD3FA0D1F2CA2EFF0D4ED54 +:10A7D00019806B8C292E00D770FC2F493C1E344801 +:10A7E000A1F160DD6ED9155CEF05EBB90FF54F9265 +:10A7F0009003A6F813D02F1999AC92FD6A68E7F47C +:10A800003474F016DEBF80E73B8CF4FE41F78B3DDD +:10A810003578FFAB542BDF4FBEEAA9C4FE7747CB98 +:10A82000544FF9DD0F568C0DD69B0CE1047AD619E6 +:10A83000FD0914371E31107C75472E27A4DB501FED +:10A840006D2CB567A3DEE1FA6EFF68EB72E4630F6F +:10A85000BE373130CF6BC2DE325C6F127A152FF00B +:10A8600079C57AD7B2B9223EE67C942DFC3D882B7F +:10A8700026264F1C1C57DCA83F09F6E0E86209EBCE +:10A8800089140FC6B53B8F737DD0D0F1D0A7C8E730 +:10A89000759F98A9BEEABB9D0F8DA53A5BB7FB5685 +:10A8A000F42BBEEA7CF856CAF3496B092E0FC29707 +:10A8B00084FECB8709580FBAAAE3C304B2AFBB2604 +:10A8C000AEF744A09F927B275E07BF81F80FFC176D +:10A8D000E2BF9D3DF99ABF62C579571D505C889FC4 +:10A8E0005507F20F55A21F71B8381FD5B874389F9D +:10A8F000FC953CF4576C01FF455B4F6532AF77E93F +:10A90000EF0AA33C81C44673FE61E921FC53D3FAEC +:10A910000ED9F59A3639A46E507BCE9DACF07D7E73 +:10A920008D7F5A2427F1C776DED6B4EDA4F5AD3479 +:10A93000B610BD1BB618F9FDADBCD5EAAA3D2CC6B4 +:10A9400083F8388497800E334D5EFA6EC5C154EE9D +:10A95000BFEBE9F15932CF631C3CE1BE19F9E56068 +:10A96000917BAC7D08FBE061C53C3E9504BE5BF984 +:10A970007925FDB853C93C8E8F8C0D3D3F3A605F01 +:10A980009239FFCC340DFD3DBD9F69F2C4D833062A +:10A99000E08BA39546FB3AE1B78F08FA5E42D55D9E +:10A9A00046F20F8E32FB3B5867384BD3AF93B95DFD +:10A9B000D5F2DDAE0D2ADFD7197CAE91F4E47C6DC3 +:10A9C0003EFD7969E1D7CCD7F935EB35FD37868D7A +:10A9D00041FDD722CEB9ADC90CF306E7A3F4ED7E55 +:10A9E000B18F81E775B06DC8FC98F23607BB4EBCDD +:10A9F00041756627C2D8689E97A3FCF5AA61F2D775 +:10AA00000D03F2382F84BF347A5C10DF55D1D3E3C5 +:10AA10000D81776D9F2D5CECB39D56DC6F24535DEB +:10AA2000D67913FF8E9A9FE2AB864CEE1F5D28937A +:10AA3000685F1CE01C650ED2EB1746F0B8EABB0B52 +:10AA400024CA9B76E1788C9F5A24AAAB5EE5EB354D +:10AA5000211F8D695DF224C9AB871D6341DFA99871 +:10AA60006DE17671806EDABA07EC568C87EBE138CF +:10AA70006A713CDAC159C2EEE9CF218D65BDE51896 +:10AA800057563B2507EEDBEBE93D77E18477E2FFA4 +:10AA9000013A9F4B761F21FDD67B7901E63F0F6679 +:10AAA0007E3E0AED65ED307CFB3BC1B7DAF7591C01 +:10AAB00063D546FC3EC98F12DD9F207EFB0DDF462D +:10AAC0008E63F87CDF7FAF91902E8CE8319C9C9C4C +:10AAD00012F39D4A16DF258CE3FB24CBB18FF26A7B +:10AAE000F48EA4FC42F68DED4B35EC7E3707F5D69F +:10AAF000C5AE0339A6203A9E5F03F28EF6A3635FCC +:10AB0000826A0BE63303F1972469FCA608BB18CAD6 +:10AB100077E791EFB2B1FD30321DF5EEF6A391B7B4 +:10AB2000E07CBB783BC09FED328D837867CCFC889E +:10AB300060F89E24F82EB4F07918EB1B53353EF8DC +:10AB40007EE3707C6B4CE1F584217CABADB705BF37 +:10AB50008783FE7DA799BE8783F9E6E820B9484D33 +:10AB6000E1F230497CFF660AF3D0F7002789EFE075 +:10AB70004C51984F89C17D2E9FCCF765F97986029B +:10AB8000C1BF93145F17D6394C11FB3285AC97C601 +:10AB90004D677E6A9DCC4EE7148A9983DAC916DF29 +:10ABA0009D9876C96E69A1FA3F5F82127DD622CE4A +:10ABB000430C41B7C0FA15FAEE0DF1A58CE761869A +:10ABC000FE6E4A650A9773FA3807D2F702A3FC149F +:10ABD0007EDF0C5F325561155877749BC22CE10003 +:10ABE000EFF6B70D24BF9D7DAA17EB401DB1E2B96A +:10ABF0002F18D5BB4E7272F944D3827512DA7AF5EA +:10AC0000782884F9303F364981C892F0E8A3F7DD0F +:10AC1000CEF8398D22A6D207566EC78F27935EF7DE +:10AC2000539C54027112EA7583C543F828C3E4CAE1 +:10AC300044BEBF1109F314364BEC38EE57A4F1F5BE +:10AC40006AF3170223E0B9BD32B15E4C811E8FE179 +:10AC5000FB1E9154385C6AE7DF094AA0EF04DD2847 +:10AC60005EFB13F8772123EFF75FFC7E7E60FFC762 +:10AC700081DF0D8A0C7C8FD281E74C307FE753CE89 +:10AC800007FBCD77A72CAD4E9918A897636EA6A2A7 +:10AC90005FA1AF9743F49D0B3ADFACD57BBCEA9D37 +:10ACA000ABE2B9B98571163A4F9B6B199587762B34 +:10ACB00023D15D9D42751F5B6EA14914EF4457443B +:10ACC00080CFADCC3919F11CA8D7E3DF4F1A38CFAC +:10ACD00094C0E8FC9FD5CCEB199F01B9C0EF178158 +:10ACE00054A958D7C29E28A1FAC7A7A22D0E3C8707 +:10ACF000604678AD01781B2DA2EE475777D96833AF +:10AD0000D0F7381B59389DE79E15E6FE1EAEFFB101 +:10AD100088623A2F9DB56D5A12F983B0DE69DA7AEE +:10AD20000D83EB10B1FE0F9FD3D7FF69EBC2E3EBAE +:10AD3000F85EBBC097B64EBB76DEC7A9849CF7D140 +:10AD4000D6FF4C385FA71177E2D3E85915F5837E1B +:10AD50007D1A3FFC3FDDFB356D605C0000000000AC +:10AD600000000000000000001F8B08000000000031 +:10AD7000000BBB26CBC0F0A31E815964181826F126 +:10AD8000A18AD112CFE066607804C42C3C0C0C85FB +:10AD9000407B23807424101F01E2A340ACC2CBC0CF +:10ADA000100BC471403C07C89F0BC4A5409C05759F +:10ADB000632B0B03433B107702713710EB303330BA +:10ADC000E832136F7FB10803C31309045F5112689F +:10ADD000A734FDFC3FD8F00C7DFADAC76DC0C0B0D7 +:10ADE000D402C11703B29759A0AA596E81DF8C15FE +:10ADF00068F22BD1F8ABF0E8DFA787CAD7D340734E +:10AE00009F160383155298E86BE0770B3ACE04EA5D +:10AE1000CD0262009F3090CD68030000000000006A +:10AE200000000000000000001F8B08000000000070 +:10AE3000000BE57D0B7854D5B5F03E731EF3C8CCFE +:10AE40006412420810C2092FA30D382121058AED92 +:10AE50001020A2458D8F2A54D4098F24E435011F78 +:10AE6000176BDB0C04232068B058A2463B4150F01E +:10AE7000061D6890200107B01A7A7D04AFF5D1F65F +:10AE80007A8352400824E20BBD6DFDF75A7B9FCCBC +:10AE900039273340FFF6FF6FFFFBC7AF3DEC73F67A +:10AEA00063EDF5DA6BADBDF61E990C24D20F08F9EF +:10AEB00016FEE873A644087DD5F774BE4254924846 +:10AEC000487D0E2DA710923E8A84884048410D2D62 +:10AED000E711F2D06D2464CD2464FFEB16FCBECAEA +:10AEE000CFCAB45DD87239FD3E9ABD7F2C8BB6A314 +:10AEF000EF1F3B2762BBE02C12DA4CCB4984F636BD +:10AF000092D021FCF82CF036D8C7D2FA4DB7598828 +:10AF10005525E4513A0C9944888BF8EC84365D351C +:10AF20008AF5F7C82CCB33A2001F2369F36979F5A2 +:10AF3000F492FCD5B4B446667035CE29792648FB28 +:10AF4000F75846E23C68BDC79CB4DEC3EF9792D584 +:10AF5000B4DD86B916A1249BD66B566687B2A3F3DF +:10AF6000D79E7389C4DB05AD9689F0F4F1674481FF +:10AF7000E72FA658709CB5350C1FB49E624923A4D8 +:10AF8000B5F380CD4FFB5B5BD97AB8907E7F709430 +:10AF9000C54B31481EEC3C60BF848E1FCCB3784754 +:10AFA000D3DAE95244F038A3E34D2214F009B49EF9 +:10AFB00077874D75F6AF4FFB9D0AF35E43F12E6622 +:10AFC00046DB8D073869BBB59464613AEE2F65EFB7 +:10AFD0002118F797D7240B4112AD77150009F5E634 +:10AFE0005A4884D62352AF8DD071564F79DB369AAA +:10AFF000D65F5D64814990B55EEDBBD74EA0BF19A9 +:10B00000630E8D02BA5E45BFC33CB21F990DF37E3D +:10B0100078BA4200FFBF14683D8AE2C662E5870045 +:10B020009FAB8678E03D7DFA62E1B54DB0211C64AE +:10B03000CD0642F20980807FAB7DA1952380BFF2CF +:10B040008817CAE95EDADED9BF7D976045BA34CA8F +:10B05000C1C180BF78F41BC5F1B93A6B891DE841C5 +:10B0600048435AD15842D6039E6050C9AF5EEF8A1A +:10B07000D65F2930FCAC93894FA0F34BC85342CB29 +:10B08000289E2DD99E39305FA75F2157D2F22A2101 +:10B09000385804BA8C55C86615F9C23E9A96D75EE0 +:10B0A0009AEC05FEAB17C269127CBF867EA75D1EB7 +:10B0B000281A3F07F8B3C9AB203F53FE3904F85EA6 +:10B0C000EB4F26AB55FCDE89ED9DA33C56C40485B1 +:10B0D00087E26500E525C06BCE75F5578D04FA4C07 +:10B0E000B0788042AB85A9EA7C909F249B07C697E5 +:10B0F00027DC80F49307260B4447EF9F03BD299E6E +:10B100006AD5A29FC3BC9EC8FB286934ADBF26E7A1 +:10B11000C546A0D393F7D8907E4F4EE85C0C72F5ED +:10B12000D8B9DCF7FD28978A7733EDE7A99C6399B6 +:10B13000840EF8C8CC8F92007FC34635DC49DCF41E +:10B1400039ABB7968CA3F09186A20599C827C28D1A +:10B1500014AFC3962A44B5315A7E4BE03BF185B318 +:10B1600059D949E7338CD3B9B5F36D5B31F43797CF +:10B1700044C6B8F1BD2D3539AA6786E591482AED58 +:10B18000FFB185AFA29C3F7959AA97C9791AF24BB2 +:10B1900006EF271DEA53FD926623C104FA1CD6D19F +:10B1A0007B03C0352CEBD85C8073FF1BAF0A40B724 +:10B1B000A7C6A5AAA08F92FC9DA48BD27D58F6BBF2 +:10B1C000F7413D97339456948DF5FF82ED4CF03F57 +:10B1D000A9FA3601DEB6093587803EC11C8B97D1AE +:10B1E0009BE9C13577A586408F0C73FCF17A710419 +:10B1F000F20121A9143E0F4139A91722B691D0EED0 +:10B200005ED66E38090980E76159C1C5A21BEAFB09 +:10B21000852257FF715B4123827C504E077EDDAE55 +:10B2200090F2A21872F03297E77A81CC467E26D24D +:10B230005F816F862731BED1CA4F013C74DCEDAF10 +:10B2400024FF309BC2F3ABA52372440ACF43D02E18 +:10B2500086DCACE572E0E8204181E275FF6F7F6B30 +:10B2600007BC6DB79032A83F352B6CEBE274057AC2 +:10B270002C24ACFFA6EC8D36D4174216F2DDC28921 +:10B280008ACF3E0EE46FB9E0A7EDD33C4C2FBBBC98 +:10B290004A08F4B22B2D2858283C6A36F16CCC644D +:10B2A000DD0529FEE6C13F80D125567FCDDAA4D049 +:10B2B0006AFA7D5E361534C01BC595858EBB80B09D +:10B2C00079CEF3D62F06FA115264017CAEF630FA2D +:10B2D00034C138742A4DE9AC9FB57793D072E0231E +:10B2E0000F6B3F0A9A50BA8DCA7BF15F04DA6F3A4E +:10B2F0006F07720FED12D242360B6DA7D65808C2F7 +:10B3000027450E0940F7B1A92AC0D394E6FDF759A5 +:10B3100000FF6CC9BB917E1E0570D07E9A6A2C3EE0 +:10B32000D417794A33E8E9D53EA6E7357C65F27152 +:10B33000D3BD1181CE9D64523D8978F245EC1E2823 +:10B3400067337832F3D8BCFAE01FAB8496D3C6E9F2 +:10B35000B608817A1A1E4A787F257C1ECEB4D04A60 +:10B3600009E0CE6370D37519E149CF569A410ED2E8 +:10B37000D3587F2AC58F867780CBA1C19547EB83B1 +:10B380001EF62ACDC00A0E0E5F49368367FFEB6FAB +:10B390007708AC3F942B0787D7C1E74F00DE54AE48 +:10B3A000D7697F2D72441069FDD004A26E64A3A9F1 +:10B3B000527EF4FB2335140FB4E0E4E390F5569489 +:10B3C00007FA2AF82DE583F90DB49C15958FD12B3A +:10B3D000AD067971F27993062647946D22D02E93AB +:10B3E000B0B205CA741E25594639235E5D99C2E183 +:10B3F000027EA7FA67D92485F1CFA5CC8E214457C8 +:10B400000FF87C82FAF41AFCAEE0BA9EF153C50044 +:10B41000DFB09AD40211F449C7E3375880AFEE2267 +:10B42000163111F959E8D35F74BC1D4B227698A4EC +:10B43000A3A32819F09651935CA0001E3BFC5876FC +:10B4400074D4F8F0094BD378428610DD3899A05FA8 +:10B450003D152D14AFA4460983BE9EA087937ECFD1 +:10B4600078A5E17AA0D7038B5F1D0CF29B6A6A3F37 +:10B47000CE3202E574D82BB4168E7FEC67507F1560 +:10B48000D7270E80783C3E5F81E73027D5B3544FF5 +:10B490006750042BE3A3FA62F5A5EFE6F89D9C7FC5 +:10B4A00092F11981A759AFE8EA5FCAEB0785F3D695 +:10B4B0003B86F53478CCDFCF0816D4532EB0332931 +:10B4C0007E1F269E39B82E7B2DB82E26F0F761EF11 +:10B4D0008102A4679878854CD0B77FB5EAF9E02758 +:10B4E000F012F4AD14463951321C681F52394E80A7 +:10B4F00075AF49AA2983F7E1740701BD7060C6AB37 +:10B5000002E033BDCD3F1CE450B3730BBCE1347893 +:10B51000FFE021FF25289F71EC46CD4E34CF67E830 +:10B5200015CB511F0CF7F776C07AEFAC94BC5702DD +:10B530007FF9295C4ED4932AF92E85DF1B5C067AAD +:10B5400056F5D3F220FAACE4CF32F67D556D59EEC4 +:10B550005129DAEFAA51D41EA57A717DE77ADB353D +:10B560006067D45854E0DBB5DEB76D3E27940B0618 +:10B57000009E5B8B34BB2F22C078E9EFF8D0CE9BC6 +:10B58000E0513CA0B4C65A23833DBAF5A269C6BBBC +:10B59000E3010E721325E2E0F874A4F3453E8BB785 +:10B5A0009E002C16DD3AB23F6B07AE2F6F904B9189 +:10B5B0002EDABAA2AD23D823D52FF3B91C3DA88625 +:10B5C0006D02EA2B2ABB943EF3B91E7172BD49F598 +:10B5D00030D3737C3D59BB3815D7134D7F826D0D29 +:10B5E0004A623ED7B76B739E49BA86C2E4043D0BEC +:10B5F0007A298D14C0FA3B1AF40CE8272928C07860 +:10B600004D133C6435AE63467D3ABA86E9C107D333 +:10B6100008F2135D879A61BD6B4A0FA7413F4D3514 +:10B620000704BF6EFDD4D63B574D27013D382F8F01 +:10B63000AD73F3B2D978BF07044D60F0825E35AFC9 +:10B640007BBF98B203956502B7B7CCF8172CCC0E28 +:10B650007C78D6DB88C7B50B1EC12769D880FDA5CD +:10B66000D9180D56651DC0F76BFC96996077AF979A +:10B670003A578EA2F0AF9F394F09D2EF6BBCCCEF97 +:10B680005A3D65DE33B0AE592D0A83ABA60CEDD51D +:10B69000040ED706E81BFD4405FDA2BB6FDBB872A4 +:10B6A00004ED278DFA31820A9542362BFDEE049A7D +:10B6B00082FEF64718FC5E524062C0FF1F8283F98B +:10B6C000A1FECE8ED1484F8B07E04DF0F6DAC04F89 +:10B6D00054A91FA6AA00AF6A1F8BF05A3CCBD468AE +:10B6E000FBDF717FE17658F8C1BE9FF3EE4C90AF5F +:10B6F00075B731BFCC0CFFDD53431D161C87A05B13 +:10B70000E78A83D7B9A0C140FF784308972B8BC144 +:10B71000755460F47AB8B3E02AF4938AE87BDAD1FE +:10B72000239D23EC20DFFDECCC840F73D0DE31AD04 +:10B7300033172A0F33E9FBB1D6F0D5C86FDB2CA83D +:10B74000A708617A4E2016F5DB91B08830B890F5E5 +:10B75000A8FE5E2147E62CA0F557EC7412C097C6F0 +:10B760000FE9BCCFD535940F62CCBB4310E3D19D1C +:10B77000D9199CEE9D30DEC00BD39F4AB31DECB6A9 +:10B7800070A87E4839F81F35CCDF0D470EA0FE4962 +:10B790009F7E33FA295B9A53E72C00BECAF27901E7 +:10B7A0001D1A3C609FC4F213AFB6D8CEEBBFC7D30F +:10B7B000C38D952BD0EF6DEC8C3DFF2916E66F877E +:10B7C000A99EF466C71F3FDFC2ECE8240BE7BB1954 +:10B7D000AFA6E9D7336D5DD5D6D96112098ABAF51E +:10B7E000F0268E3FF3BA49A406DB18C6E7E83F36D9 +:10B7F0002E6071880D532C185FD1F89CD64B03BC7A +:10B80000D279A03D47F93004F6DCC3A401E526480F +:10B81000DB6F26FDE1BE8D582E6A7E93F9FCFAC6D9 +:10B82000E3FEF5ED5C5FADCBB9C70E5DD1F1D28023 +:10B830003F026EA627AB5CCC8E9DB6538EFC80C2B9 +:10B8400051D52CA09D65D9674738CF6CA265DA75B4 +:10B85000C4A560FDD31E1B9603D6CE87BE47CBBDC5 +:10B860003B4582766496C302FC7A8CF32BC9A365B0 +:10B87000B087EDAC58D5BCFF76E8AFACCD4AECB4A0 +:10B88000FFAADDA5D77E8F964B3B640255AA362FC3 +:10B890005386D0F2A2901086724F015DA8002FC986 +:10B8A0004A08FCF61E7767EA8FE8BC4FD6DA884A6A +:10B8B00041A97375A6DE44F1511EDA5E08EDCA5B3C +:10B8C00004D088741E9B5F1D0CF3DA2A78C1BFAFC9 +:10B8D000D89260B0078FD1A9FC807E5F42E70972E1 +:10B8E000594A1A0A619DABDABC4E5175F18793B57E +:10B8F0001E1C472B576DA5E3D076D5CF0B5E986203 +:10B90000B585F8410F9DD96D9FFDB413E6B74C196D +:10B91000E382793DA040BDD250F18B7615E06B56A5 +:10B920000AE9F7F2A66605E25B012BB903FCDC8AA3 +:10B930002D038C70358A28AF4B926C1B419F13A747 +:10B940002FED86B1FDE97CB296EAD831D17239E8A3 +:10B9500043E4C39072BDAEFE703109F9B5628B68E5 +:10B96000B4B3F9FA1F3CCCE81FDCEBC2B89F46BF6A +:10B9700025DC5FD6E8B72489D353EACD8F05CF43C2 +:10B98000400F0A4F03E08B3ED770F8DC53C8548851 +:10B99000BBB87DC423C4E06BF3B34126C5C0BAFF76 +:10B9A000BAFCFAA9D260741F1643E4C9B362CED4BC +:10B9B000E9B4FC3B4BD1660BEA0FAF0A72A4F9D98C +:10B9C0004F59985CD60F56107F0D33F29F66F109E0 +:10B9D00082EB5EC38C9267C02EA0EDB759500E6902 +:10B9E000FBB1F1DB7B0A271ADA7B0ACBB4F63BB159 +:10B9F000BDEDFCED1B0A271BC72F2CD7DAEF45F84E +:10BA00009DE787DF73E514E3F8575662FB8095D115 +:10BA1000AB37C98676CD0ABBD727313B2A02EFA5C3 +:10BA2000E4311BA19EA8F103E9F481FDED6C491AF4 +:10BA3000BF9AE8F9A2E00D80C345A545CF17891349 +:10BA40001D067E4CF2251BCAB427CFB1EFF0320C95 +:10BA5000E2B6213CCA1005F5C5D4213684F79E7D97 +:10BA6000762CDF3399C17BCF1027CA19AE2D948E67 +:10BA7000F728FECBF5762BAC4C104A7A53F47F04B2 +:10BA8000F88DBE572DF0DE21921AD4CF5682FAE8F7 +:10BA900081CCFCA7833AFCAC1C46E94BCBA7C1FE8A +:10BAA0001918C5EB03C34AD28A75E3D40F53666FE6 +:10BAB000CC66EFE73B61BCA21EC04340E91D0376A4 +:10BAC000A5791CEB888986716C196538CE37A6710B +:10BAD000AC1965A6716CB337F2F77C9C3FC3BCE22E +:10BAE0008DF3C088C9C6F96494E33856D1349F8C6D +:10BAF00072D3380E361FFA9E8F6317CF379F91533C +:10BB00008CF3195E89E3A4888A216E651D5E691A2B +:10BB1000C789E3C07B1887A433FF46B1F69620FDA2 +:10BB20005FB613B0A715ABFF59E897FCC14E509F05 +:10BB3000A874DC41A0579271BFE03F2CC9389F2FF9 +:10BB40001D94FE4E3D9D839A5D80F6CE420E2209E5 +:10BB5000D5A37F5ECD797441CBF519CBE0D9362DD5 +:10BB6000AD18FCECF52E2FC44FCFB44D53E6C7B043 +:10BB70000B1636C8C7BA0CFCCBF55E01C9AA013F4B +:10BB80008BDB015AF918D55F84EAAD8FA8FE82E7F6 +:10BB90007199EA69FAFE28D56F44D1C3BB0CDB1D4D +:10BBA00093181E8F35B175E4CB7587658CF305C985 +:10BBB0003B59741E37F3692C6C4860BE028723C062 +:10BBC000E9D1BBDB1ADA88F4F00D05BB87340EA08F +:10BBD000B8E2F54600BEA8B824637128D8473F5E96 +:10BBE000B9FD3750ED5DA178D8123ADFD9ADEBE45D +:10BBF000A1B47C46EEBADDEBD4F5335BFE08E66D0E +:10BC0000A3FF413F73FCB4AC1BFFD63263F936226D +:10BC100045CB946E33C4119C1E7C5C352403BD6EF1 +:10BC20004E65F0DC06CFF1F0D983F4BADDC3DA6AF1 +:10BC3000F004EE934904D7A3AE81CCB81D88F5FC7F +:10BC4000DABA6282EF76D9E62BA2F4BCFD5E11F17E +:10BC50006886B76B5F82CF42FDAAAEC6CF64F02F75 +:10BC60002F04FF1D4B8DDF49908DA7E155E3835BCA +:10BC7000664F1D7054576F8EFFAA014775FC726B9B +:10BC8000D9F586F26D35730CF5EF585A6CF85E1CD9 +:10BC90005C64F83E7FE562437961C3BD86FAA58D99 +:10BCA000CB0CDF17855619BE576C59672857851F6F +:10BCB00033D40FB4351BBE5BF65D7A1DC863DDEF70 +:10BCC0004402F6D917CE630F817DF5855342BFAA92 +:10BCD0001A788DCAE189DA34E4EF93B52A3ECFB4FD +:10BCE000E5E2FE58C041E599AEF51BEA0E2D5B3941 +:10BCF00005F408AD4F75F813756F2D0B52DF7D23DA +:10BD000004A929DF8B8D0A890C003F26B98FAF7BF0 +:10BD100045DDF7AE0B7C6FA40B566EFFEF6257EC60 +:10BD2000F73D42EF18B0EF821F5871FF269EFD408D +:10BD3000FF869218FE83F6EC86F8864EEFBC2C3216 +:10BD4000BBFA72B1E065913E2B1526EF953B0617C5 +:10BD500040BCA052898CA9896167F78D17A6C00CD9 +:10BD6000827E98BC2C0A0D8DCA2FD26FA441EEAFF3 +:10BD7000B1F8F7817EEEDE2FB2FD81C8C10CD8A7E5 +:10BD8000B95CF4BD0CEF49DB405C1FDFADF50D384D +:10BD90003A8A90F76B67E2F3F7B54503207EF4C764 +:10BDA000DAD958FEB0D68FCFAEDA327C7E545B83C0 +:10BDB000DF8FD62EC5F2B1DA203E4FD4AEC4E7C92C +:10BDC000DA06FCDE5DDB88E533B5217C6A72A0D93A +:10BDD000A32485DB7FDC5EA72B0796CFF23988F49E +:10BDE000DF9D28D7DE3490EBB3CE2FC7809D7BF646 +:10BDF0007D2B06D1E3E1C9CC6FF1E9E7C3F5BE24A1 +:10BE000044E99FDBFFBBDDC1E863B79099E09FADDC +:10BE10001AAD1088AB3B5EFE0EDACBF4BD44505F2A +:10BE200086BCFA7DC4BEFE61CE832E4C27ADFEB12A +:10BE3000C7FF2B7F5E36D087D1D77150AC61747B42 +:10BE4000DA0B74D3E18FD9653BB93E37E151E27229 +:10BE500067C6E7E9811A3E3B3320DE522516592496 +:10BE6000FAEE6CAB15E775B63D81ED637B522E2A79 +:10BE70009E57B1C5EED1EB87AA7092C7A82F067B5B +:10BE8000F4FAE26CC7D36E90FB256916CFD15CE063 +:10BE90000F1FE70FC6775AFF55E14C8FD3D08FB1F4 +:10BEA0007CB64198C9F615D5C49B62F807DA734988 +:10BEB0009AE2394AF5C2C92D2313615CEAC7796059 +:10BEC0009CEE5A8F878D9BE6D1F365E55207D6D756 +:10BED000E08BD7EF3F1A3ED8F1FBD8C6624D10A7D2 +:10BEE00089573F2E3DA4CF15F00F48BBFC25AC3B36 +:10BEF0008E2C6DDD91B0ACF51B088B41EBE5F0BEEF +:10BF0000C5301E6DA76A3E34B48B4F77891CD3E8C9 +:10BF100049F5E4953C3F843233D2D94F7B4CA4FDA4 +:10BF2000F548CE9510E7CD9454D477011888F25394 +:10BF300095AD4BF1AB88EE4E8C7B4ED4E45EBDE507 +:10BF40000F94E53EF93719E319E4CFB477FA5DE6CB +:10BF50005F179022373819F35A2B66819EFCC4A2D2 +:10BF6000D9030DF930EFD3C482FBF9A7C9DBEE5C2E +:10BF70009D5D5626F1F8E44AB63E07E97F303F6AF8 +:10BF8000A719D6EBD24663B984DC900AF250B25EB0 +:10BF9000861D5BB208D67BDDBEC96CC983F32E2536 +:10BFA00035F560A7AC96D93EEA3C0F918652B8AA07 +:10BFB000763D990FF66C4062FA5EF39F172533B811 +:10BFC000CB53428A8F7EFFB835F7E6EF11681FAA80 +:10BFD00007BD1674116FAC78CCFC9546F82E04BFE3 +:10BFE000195E42961BE0D0FAD5E010B70831F33461 +:10BFF0007E26093CAEC3E463AD64B45F1FE178D034 +:10C00000CA1B4CE526537D8D4F64CE279992FF11B4 +:10C01000D03F55B6DE42B4D308E58FEC683D255AD3 +:10C020006FC3F9EA59A19E88F59AA409F1EBD9A347 +:10C03000FD35C7EAAF6AD7B61783949FCA5F78D435 +:10C040000D41DF4FA48654887F556EBEDF0D783AD0 +:10C050002105DD40EF4F4262CCB8E07B7DF8F2393C +:10C0600005F02390B529DE9F7BF05AD0D75F6E96FE +:10C07000312F26B0C51AB1523EAE6E5D340BE2F7D9 +:10C08000B47C84951FF814F60D036D467A963FFB39 +:10C09000682AC489282699BD4D226877546FFA53BF +:10C0A00021E8F100E9453E34B783F1CF25A3DC1741 +:10C0B0002B89FDBF6BF90A012E6781D6073F85BC2E +:10C0C0008480897FCAFAD6932E05E2081D922B053B +:10C0D000FDF2EF92EF821ED0F04142CC9EA8DBBA77 +:10C0E00061DC110A4FF7A67F730B06BF9BF1E1D904 +:10C0F000F0FC5FBDA4C6D73367B83F146D17C27696 +:10C100006A1BB37F483B7B56CA1137D89B95CDB28B +:10C11000977228A9DCF6F4338F839FF68115FDB45E +:10C120008A6DBF7977322D576C975366B1E93885A0 +:10C13000D4285D02F47F4BC747E950FEEBDF28EAC5 +:10C1400058F6FEA7C9517A546CDFAF90B1FDF137B4 +:10C150002DBC5FE972C6A04BF84821D82B755BBF98 +:10C1600052C0EFFA649F400665F66F5FD6FC1B5C19 +:10C170000F014F48474EA73EBAF5A357E4DA97F2AE +:10C18000B09E07F4643C7A3DC7F572D52E174982FC +:10C19000F8E7EFADA15940C7E7EF74C33C8E4B35CC +:10C1A0008CAF9FBC3F15F6FFCAE460AA079FEC7DE9 +:10C1B000D9537723BF950A35A96C1FD33798C7CBBE +:10C1C00007C3FC1636FD08E75742FCC877654F8A5F +:10C1D00045101FFE422233B7C7908B6B64B6FF74C5 +:10C1E0007CA31592FCC871B0F3C1BE7E5BC4382B32 +:10C1F000218B711FEC6E2D8E4B9660F90BBE2F3587 +:10C200004AB668FEA1CDC0AF9B1EE804FA9C1CE6AE +:10C210001B0470523C0439BE04D8EF170FCF18C46A +:10C22000E8C3F20DB01DD5FFD3E03DD4EF94719F6C +:10C2300050D78EEB4B36FE5D7C7C0AB703D6B3E35A +:10C24000A96CBFD23CBFA57C7EF4AF93E8F84B2726 +:10C25000DF4CDE37AD62F2ADC97BE8FA99F0FDF351 +:10C260007798FC403B583F285C9141F87DFF4D0298 +:10C27000EA032B89C492EB4D32976BE3F700955399 +:10C28000880B50B825C86788F209ED3F19F18F7EF9 +:10C2900049C97ADA4E679F05603CACA744DFEBD60C +:10C2A0008F52AE0766CA46F9274D032FCA5EAC947B +:10C2B00049104CCBCA0FACE877576E938B60DEA762 +:10C2C0005A0EBEFB63CAD7A7C29A9C1AF5A7594E4D +:10C2D000CB766C16803FCD727AAA8CAED6B1E49440 +:10C2E000BE8F29A7655DFF57F4A786B780096F54F5 +:10C2F0000F0E4FB2C4C79F590FBA6435A61EA47F54 +:10C30000EF90FCFE7CA7F19BC667D4421B0EFABBE4 +:10C310008F1F357EEBE3478DDFCCF334E2CDFC7D20 +:10C3200032186A14AEA2DD32FA2595ED6CFF86B69E +:10C330007B75681EE2C787CB17697875688ABE1C53 +:10C340003295C3A6FA3E53B9C854DF6F2AD718EA0C +:10C3500057B61D54589251C450CFBAF471F2710CB3 +:10C36000FB5E5B6702AD9F2A41E087F45E05F49CAB +:10C37000BC9C9A66103FDB2BA2BFD5A3F6BA93E90B +:10C38000FBFBEDCC8FEDF1F072122BF70E54EA416E +:10C39000CF69EF7BED2CCED953D4EB4ED2F9F747D2 +:10C3A000DA4537EC077785583E6A7F78EA506EBAEF +:10C3B00048BCEF2C2E384374662C05FFAD41F48247 +:10C3C0006BB860D92D6ED877EB691F79DD6CFA7E7A +:10C3D000E12111CC67D2E3708F03B848D0270DCE8E +:10C3E000E7F913F4EF0409FE720AE44DB433FB7A63 +:10C3F000C11A933DECBC4BC1FCB2F5BAB8968EFFA6 +:10C40000CB793F654DC6EFE5640DF25FB9491EFC7F +:10C41000DC1F38ACC9430EC961FBDB84F9B15CEFAA +:10C42000CE10B3AF9B4DF1DED32162DEECD9769115 +:10C43000D4C33C5B04DCE724C1812857D5A417F59D +:10C440009D86976E901B25BE3EEADEF91FF9F70127 +:10C450007FBCF887714FD067F78B1F8CD903E55DE0 +:10C46000EF65FC81F4AF3F6DDFD7B88FD8B3CF8ACB +:10C4700071AE9E7DAF65DC07E597AC18E7EA596EB3 +:10C48000C57D94E03E5768347C1FC6FC81BABD5F11 +:10C490008D6379922B904E7F96993F72B6FDBF3E89 +:10C4A00084FC91B3ED74566017EC4B40B909BC6441 +:10C4B00047FFBB67EF57F97EE73F6E3ED50AF12392 +:10C4C000FFB9C8EC1DC0AF492C1E1CD833E969C8A0 +:10C4D0006FAE6ADDAF409C7DDACB7F19077AB26719 +:10C4E00007B377CEC85D4FC17E9855F974B94CF14A +:10C4F0007C06846708214F2BE3A705B363E185E140 +:10C50000A187E201E645F15206FA3D1E3E32947FD4 +:10C51000567C7C7A3BD363DFC53CFB285E041F7BE3 +:10C52000EF0AD9049C3F7BBFEFAB71A0674E8597A4 +:10C53000A13D72A1795FA1B07D96FF39F316221754 +:10C5400033EFB9FFB4F466FCFF11ACAF03FBCB4192 +:10C550007F3EDF750F969F777911DE8B94FF9FFEEC +:10C560004FA3FB0E4A77F785E9FEC43FEDBC2F448D +:10C57000F7439CEE2E0FEC2FF7ECFD0BC64DB5F9F3 +:10C580005F68DE2FFD3F3A6FCD5E7FCDA2BE934345 +:10C59000EB1F220DEF8C11207FF1E0613802562055 +:10C5A00090A258F6C84985C53F0A049627489204C8 +:10C5B000EEDF31BF6828B71386DE558276C6D0F429 +:10C5C000B5681F10495D0FFB71AF65CCF7B27CB049 +:10C5D000F1780EE535CF15BC6CF40F9F10880FF283 +:10C5E000868766FCB003ECD5F47411ED59FA443B30 +:10C5F000F615F74CF6BE5231F84557115D99CEABA2 +:10C6000030C5E8FF4CE7FDCD2023DEC9A1F0CFB057 +:10C61000C99E1045D15553FD12CCE7AAC10269D07D +:10C62000ED074D37F949AF825FAB8B97FDADF84B06 +:10C63000B7323FB24018B1BE08F0374CC478E005BD +:10C64000F14758FED76B9E1C96D72A7919FE92ABFC +:10C65000BC184FE57E338405C05E919CF59D20B7E4 +:10C6600012A17E2F831FFD65CDEF8D8767C2FD6808 +:10C67000890FA9E15D4A17315F55D71FE243A3C770 +:10C68000DF4A078D7E7F2F3DCE98E891FEB94702A5 +:10C69000F99CC6EDFFE99F778A584EF74AB81FC547 +:10C6A000EDFFA9CE2409ECFF2BA4C322C865A9ADD8 +:10C6B000ED6A88D3DBBC02F2F525DD16F46F6C79E8 +:10C6C00002E23DAB51C2F2618B670218DAD77E6F8E +:10C6D000D7A97B09C4877D0A1ADEA488C5E7FFFCB9 +:10C6E000EDB753B4F31AF89D906BA8FFB5A0894439 +:10C6F0001C144F0B25124C4C86F8AE403E32C477CA +:10C700008D65F8FB7E6AB49F0BD58FA747FED1CF0E +:10C710005D546F7D449963373C715F85B284CE3F31 +:10C72000FE6E3BC357E075121A8171059F58A4DB5A +:10C73000377BD0CAF4C7AE3FEEC885B8D8D49EECDC +:10C7400044A64F47A15F10E07EC159A22642FEC118 +:10C75000D9F69189B82FD821BAFC31E2325BB9FF02 +:10C76000FCAF904F419F3D9B48039CC3E821BD18FF +:10C770008F0D6EB2C5DCDFBDC7AAC59B38DDE89F53 +:10C78000A89D3752315F2498A8A75BF7AC4FA471DE +:10C79000FDE9007F1FE9F64BFE5EFC82BF0EF8DD6F +:10C7A0006AEF2A8C751E6C25C7DFB507BEC638E652 +:10C7B00065EDCD16E0DFCB36590CFB8D412BF7BB79 +:10C7C000C693F100D7B507ECAE3CA04B87E885FCDB +:10C7D000C140FBA78A3FC6BE95199FD03FC4C5F78D +:10C7E00059599C7F8F1C9E0F78DD73DA86F939BB0F +:10C7F00095868A58705E62677A6E2109DF392EF35A +:10C800009F0FBF537B9C9102F03337111EC730F34B +:10C810001F413E3EBB85E0F950F04B412F9C6D61BE +:10C82000E780294AD6823F4DE5FD07FAB8CC256D51 +:10C83000DBFF15EC80EA76C103A9B3D5529702F16C +:10C84000D6405B9208EB6E8EAAE5557AC6DEA493BD +:10C850008B7D56966F7C70F29E5B61DCCFBA1502C1 +:10C86000F688EF955E37ACDB9FB5E726C6CA9BD747 +:10C870009EBFAE25574F97A01F827837F343768B24 +:10C88000C350FE9EE81F02F275ADB5EB2E6F0CFA99 +:10C89000F96D8CCF2E5ABF85FE3FD36FEF68FACD6E +:10C8A0002F16E9E428CBD64FBF0D8AA5DF9608EAFC +:10C8B00020C0FB92BD2307015D971C9207C6D26F73 +:10C8C000DB6AD97EDE0B3C1FB6A795EAB7CB75FABB +:10C8D000ADD5867971E676C9360B5F172FA0DF429A +:10C8E000FF3DF2B70DF45B8CF98EB631BDA1E9B70F +:10C8F00071ED4750BF8D6BB518F246D36D17D26FEF +:10C90000C2C09BC01EEE90BD0931F8671BB7BF5F68 +:10C91000E07978300EE8B95B6D6C7FF362F55CB658 +:10C920009DD1FB827AEEBF09CF9A9E5BB2533BE763 +:10C9300068E643A6E796ECA67A4E007E647A6EC956 +:10C940005E768F8359BF65F5D36F04EB574758FB6D +:10C95000405BE686B9B4BFF13ED96BA3F5C747F596 +:10C96000DD04BDBEBBD5C6EE5DE8A7EF3A2E4EDFB7 +:10C97000EDE4FA8EEAB111A05FCDFCE16D37E61D62 +:10C98000EF9974BCE5D7202F6F88B86F78989F4BCC +:10C990007B73D2F13CE0AF161BD3BF759CFFCED4A6 +:10C9A00006B1FF69AFB0F95539593E72752BB30F17 +:10C9B000AB5B84904AFF5938F96B05E05FB45720B0 +:10C9C0008368F97A2BAB4F9ED5F6BDC8AC1C1D3FD2 +:10C9D0002C98588171FB0512B1415CBEC259F8090F +:10C9E000D8BF1513591CBF82BF5F74A8AB1EE2D914 +:10C9F0008B1E1370DF93F07C002DBFB1B47D19C680 +:10CA00006BCD79019A3E5F1432BEAF30E53336F319 +:10CA1000795E2F76215EC85B62CCBC8466333E3A79 +:10CA2000383E3689B86EF6E183E247CDEC8F0F4A87 +:10CA3000D15939A9D1F92F7A83CE2B2F3A2F0D1F37 +:10CA4000E6F96971E70ADE2EDE7C35FCF59BAF86E0 +:10CA50004FD3BC9F06BD010A2187E4425E0CE5036B +:10CA6000D41BC1DF8A787EBF68EAE8417A3DBC9575 +:10CA7000EBF3DC86A9D30613C017A901BE29695CB4 +:10CA8000FCEA603AEF09EFABE36179FCDE64AB1FCF +:10CA9000F647B7DA7B51AF697CF50DE7AB77391E06 +:10CAA000F70CA9C173AA8136C1037645206247FC01 +:10CAB0000528FEE0FC4A809F5F0C50FE02793AF8A0 +:10CAC000D8970C5F7B0515E2E385DAFA03F8A7F542 +:10CAD00073DB19FE032101F19F477A717FA4BA51DC +:10CAE000F04668FDEAB6C598F7A0E95BFAE7D4D34B +:10CAF00043C78F522C7EC44ABAF5AF82D7BBD6DA71 +:10CB0000F02EF0E7B5CFCAA459C79F59F4BF6F63A1 +:10CB1000D049C3E785F8F21CC7D336C0A313F0D5BC +:10CB2000CBECA7C8D7788E46FB1E9082063C4E7B86 +:10CB3000FCDC79F13441C313F029E8A9F66211CA8B +:10CB4000256D021990D97F9EB03FA997DB457B8F59 +:10CB5000B0FE9F14F0DE1233DF6AF3EEC7B771F850 +:10CB600015CEA5815F74B17CFB8D896FDFB4F7BEF4 +:10CB70009E0B7CBB5760F183F624C3FEE2103B5B47 +:10CB8000FFB7DA297FC3BED621D9BB51ED2FDF090C +:10CB90007CFD02BB5F7F2EE9529808E43D6EB161D7 +:10CBA0001E19C23182D9957ABDBACD4E06DE9417D0 +:10CBB000BFFFC1BCFF78768D561E0BE341BE571BED +:10CBC0001D2F2B3A9E59AF6B7EFE85E635E6EF9C16 +:10CBD000575F1E26E9C47DA74CC9FFB0559707775C +:10CBE00033CF33A210A07DA5AB976D3B4F3D92E6AE +:10CBF000C1F34F777A343E63F9EE453C8F7D86383A +:10CC0000E53D583F3FF3B17DBE3C0BF9DD14D0CF7D +:10CC100005329EE3FBEC7519E3B59F4D67799CD710 +:10CC2000BD71508238CD75A09C283EAE9B20A0BF20 +:10CC300002C7B060DF6C17B56F7C63703EB9708E51 +:10CC40002B6753C334387F3C7E4BA80E9EDE69BDF4 +:10CC5000296F021EA78A04F0D8E91B300DEE4FBAE7 +:10CC6000F34F04EF0FA1EB2CB61FDF410642BDC905 +:10CC7000BE81E80E4C6A5D3F0DE2A3D71F743AE116 +:10CC80007E96AC260BF519A2F89B4C4275B0DF3EA0 +:10CC9000E9A8EF4680B78CDA0B10772E6B6FAE7376 +:10CCA00043B949F0AAB4FF40D05FE8A6F3D8D6F85C +:10CCB00069E177401E693DE826D0C4EA0536C1C562 +:10CCC00043F07E1DE6D9946C12F0E0D7B690406C2C +:10CCD000ACDF908DF6BBAD89B6CF837582B6877E0B +:10CCE000377DFACE8D20EFAF8BAC7D0BDBA72EA16D +:10CCF000ED54E0DB4D8BB1BF454D0249A3FD95B529 +:10CD0000B075A0EC75D90BDF5BF73F86EBD82C3AFA +:10CD1000DEE04CD0FB91E95026B98207CFA1548EBA +:10CD200041BAF5703927534633FD21F032F71B34F1 +:10CD3000BBE95D3BCBF72DF12E5306D07EDE9C3850 +:10CD40003013D202026D9FE2FEF3518A673FEDF28B +:10CD500030CFDB3838F163A54BB70E7D6667F75BE4 +:10CD60002D689B8AF90C0B4911E6335C3B89D96B22 +:10CD70006F5D610FC115076FC9BDE9F0FEE0155683 +:10CD8000B47FCF6C93918FCE0CEBC2F8F4F12619DF +:10CD9000CF0DD735B1FBB98EB7B0755C7C92EDEB9A +:10CDA00097BA142C1F6CBAB110D6B7E39BD879C7C9 +:10CDB000694FCE50A05CDA2C78D9FD454C3F6AFE15 +:10CDC0005B8987E52368FAAF8ACFBB5FDEA249DFC4 +:10CDD0005569EB8D49DF55C1BEB21B9EC6F701E216 +:10CDE000647A10EC7EA07BE46BE4DFEAD765027620 +:10CDF000BFF0717721E663ED15309E3FA95DF0C16C +:10CE0000BE7ED9FBD610DAABA1E23B7E027AFC03F0 +:10CE10002B1154C86BA778A7FA61A2B5F78FBFA0F2 +:10CE2000EF3F396C834C18CA27C588672DFF336FD5 +:10CE300033CB63C93BBC3E15CE5B92E90350DF9612 +:10CE4000368AC4AFD31B9F08BE1B7FCCF432DE4FA3 +:10CE5000A1D12F4F692881756CA483E92575B30C86 +:10CE60003922E4108F93507B1ACFDF2EDABD2E5576 +:10CE7000A1F5EA79FEC7A2BDEB5245FABE0ED62F48 +:10CE80005A7F91C2FA5FB44FF034EBFAD7DA6BFDF8 +:10CE900069FD28BB8DFD8CDCCBCB17D98F0687367F +:10CEA0007E3C7B7CE2BF9F5B0FF7C54C7C4BC4A4F0 +:10CEB000E3891FCF1AA9DFEFD09E5AFC35FF1D0B67 +:10CEC000F1E9F036F18F0EE2D3F145EB042ADF945D +:10CED0006ED7B4092100A575C211A52A0FCB1E90EB +:10CEE000E76A1EA7AD9ECEF6AD5A730EAF00F99E4F +:10CEF0009527201F90A05F19908276900AF1F1D2B9 +:10CF00003CD6BE94B607B96B7D8CC921D5072AE8FB +:10CF10008BEAA67585587F93A042FFADCDC5B8DEDC +:10CF2000974D14097EDF7404ED8FB2B6232920AF2C +:10CF3000543ED7C3FA5B3DC58AF7796972A7C9F138 +:10CF40005B32BFAFC9E6190B79FDF7015031E457E9 +:10CF50007C9D303FB54546390B4C6472F9D636118D +:10CF6000E5F9E015B7A01C9ED92CC491E3690A9C91 +:10CF70004B3E1E62DFFBE478ABC0E598E987E34EE9 +:10CF800026D7D3E03BC8F14E81FB83CC1E34CBB116 +:10CF900026971792DF8A2D26798E23B79D52D74D7B +:10CFA00030EE9D57D811EE69DFDFFDEE9DA87F645E +:10CFB000CCFB98F6FD7B5341DF95482C5F49C3635A +:10CFC00095C4F2D9FAC1B17E9932F8A2E031C2F12A +:10CFD00084DD15D51F22F039BB872BB849463E3773 +:10CFE000CBE1DF2B3FFF28793EC4F9478347DCCBF9 +:10CFF000DA43FE5884E2E9B596A7314FF5F473475A +:10D00000AE053C57ECA17C4BE77BA6C5C5EF7B0981 +:10D01000E13A53DE2A621E389122F937BAF472C916 +:10D02000F2902A5E70217F94EF60F9A4E52F7E3C98 +:10D030000EF34496F7627E55F0396E6F06BBC6015B +:10D040005F974B2C1FCA2CE7373998FDD9BD3B6140 +:10D0500036CC43D8C2CEE997876F91810FB57A3F1E +:10D0600074C85A3DDCBF0C52BE85FD75804F7FEE03 +:10D070005CCB83EADECAE4BEBC4D467FA97C4B3361 +:10D08000C6B1035B3EC53CF7692F6CC3F841A04DA8 +:10D0900034E63D6E112356CCCB148F58D93A65C86F +:10D0A0003FAC6EADC2FDB6EA30CFEF33E5BF55BC45 +:10D0B000B0F7C520454DC5AF9F75831E38D9B9D986 +:10D0C0000DF8A4FD61DEE0F73F970C7951F1F37B99 +:10D0D0007DC67CC2F0AA98F98427E11F94C1EF7540 +:10D0E000707ED5F230B70CE079DA91FCA218F1FB32 +:10D0F000BE733BDBBE780AF2DCBB779C7A0AE0AEFB +:10D10000FCEB674F413E13D967C77529F0DCEF3060 +:10D110004F586BF70B07F7F3B73E8BF9D5673EB067 +:10D12000A29F7366EFF10CC85F3BB3FDEB5488C759 +:10D13000DDB57706C62BEFDA396D1089A1DFB5278B +:10D14000F065E822F2BBCD7438D87A10F3AE4EBF4A +:10D150006F457DD697171AAE6279B62ACF076D89CB +:10D160009D47AFE53156B7DE78DD15A09F5B993D51 +:10D17000D797D778A13CD077283D2FBF08BAB5F014 +:10D180003C5F13DD4EC33F287DC226BA7DD1BAF085 +:10D19000578FC3B7D60171F3402317812F2D4FFF4F +:10D1A000E70EDF1E079CFBDB91104C63F40ACD12E7 +:10D1B000C0DEFB2203CE359C907B31DFA377AFD559 +:10D1C00003F98CE57BDF43F938B3F330C65509CF5B +:10D1D000933F43FAFE585EB3C0E7B7C9C5F247397B +:10D1E000DE21BF5475E37B9E47CAF856CB2F8D973F +:10D1F00057DAEB18C1E2D0FCDC4015F593F8BD59C5 +:10D200007DF9A6C244A0D311439EAE366F737F1E34 +:10D21000AE37A3F9D1B1F376B57CC1289DD83AA237 +:10D22000E53F9F69E679D3F47DFA78C88363EB75AF +:10D230002024BC4762C8A3961F7DCA61CA8B0E5DBD +:10D240005C5EF485E0FDDFC5C7870E16AFD6F0D271 +:10D25000FDE7D8FA5849607627F54FE504DC1760FA +:10D26000FEE91DDC3FD5F0A5C15B1F667643F716CE +:10D27000E61F98E5B93ACE7D49297C9CEAB6FDE3E4 +:10D2800040EF741FD8CDF98DF17375CB1196774BA4 +:10D29000F57348AF9FF9FD12E6FE32787F81F6D82C +:10D2A000FD055A3E8DD9DF49C9770BC07FB293D9AE +:10D2B0004927C3E2CC58F7DBD8126443FE40BD8B4C +:10D2C000DD9721BA1D681FDDE59AF87E620A3C15DC +:10D2D000CCEBA95BC6F3807EE6C57B45EB5C5713C0 +:10D2E00080E77EC08F2ECE207BFC04EC3439AD2845 +:10D2F0004F54A3F0F6D123C542427AFA4B9174D031 +:10D30000E71FE61C97A1BFFF34C547FE5322F583F4 +:10D31000285CFF1914BCCBD4F876B556F6FF54340C +:10D32000C433AAADBD1F827D4E5EB6E37EB8B8CFD2 +:10D330001EC4F8D853EC5E8D833BBF7A06EFE5F947 +:10D34000959570BB50007D50CAE314C7777EF5D425 +:10D350007F811D098DE9F8A54FD1FA603FB724A060 +:10D36000BDDFB323711CC4014A5FBEEF5AD017A5BD +:10D37000A0FBC0CE7C6150A88EF6776C202B1FDB03 +:10D38000360CCF0554EC70613EE1C19DBBAA41DF74 +:10D390009F79218180BE3F2D77FD15CA813D89A4EB +:10D3A0005945BB4FD5AFAB8B88A4EAEDB90A281B12 +:10D3B000F25B08E6B760FC8DF273455B229EFFD0FE +:10D3C000D5E3F21C1CC2EF891A027247ED46D598CC +:10D3D000F7CCBE2F4860FA2B60EDBD87DD87C0EA31 +:10D3E0000794DE12566E18C2E4B613EB2FD6F895EA +:10D3F0007FEFDF2FAB1F4860F180683FAC7DB595B4 +:10D40000DDAF61A6EF4F13047E1EF72F97C4BA7FDE +:10D410002206FCEC5E2E8104E1FE55B2DD8EF7F1B2 +:10D42000542A913190AFFEA2C2F63F2ADD9131908D +:10D43000AFBE87EBBF4A072DD3F743381C501FCA36 +:10D44000C4D6F53CDEEBB4CB8EF7E155BDECF2A1D2 +:10D450009FF0E257C79EC8837CB504CC93AE7AF99F +:10D460005F90FE55D6C8EDC0FFBDDBAD783F69F7D4 +:10D47000F64319603774CB918CE4F3ECEB5485AD33 +:10D48000867D6A6D1E276B974E8673BCDA39C3F2B0 +:10D4900038FAE28D0496D7D19CE0FB15D373C6FB16 +:10D4A000654ED6CE36DC9B586E8BADC75A402FE802 +:10D4B000E27862F45C610BF47B9A74D50FA124A925 +:10D4C000127A717FBC7C4B663AF8BB07EC97E0BEE2 +:10D4D000D50159457F109E7A7D7CA2D69B2BE179A0 +:10D4E000FAAC5C89C2D1D3FC69C91002F981F6D9C2 +:10D4F000B1F4D3DE8404E4A7729B35E6F9CDDF7284 +:10D500007EDB06F236818DE7CD8E8E7B400E2900C4 +:10D51000C714A78AF329A77E00BB276A4EAEFEDC9C +:10D52000F622A901EB51F9427C2C22EB953C677F56 +:10D53000BDB268695EAE948B0AEB9B3E7E13A3740A +:10D5400022C114B493244E43B27EB021DF5F928B8C +:10D550006C802F851479241148DD8072EA20617C6B +:10D560003AA919C2D6A11A02F1F1137C7FD62AA9D1 +:10D570000FE37D331D22EAF30BE1EDBD0437C26DED +:10D58000956A8817ED8D591EB0C784A09F7C4BF912 +:10D59000A1AE76662E3B174E7C90EFE6260C3EB78A +:10D5A000E7D5AFC13EA07CC6EEB1FA3E09D5D1F1B8 +:10D5B000E09831C6FF0AD87DF6E6F1FECCE940825C +:10D5C000FB0DF79DC35FAF767F1EF8EB897F9D084B +:10D5D000FB314E0F8980BD94E024918471704F9E81 +:10D5E00074522FBF6EC2CA23283B835EF34C317E38 +:10D5F00037F335F14A9FF7E94511DB7F6E6AFFF992 +:10D60000F9DA6BF808D8367A8FE646F1E2E073086B +:10D610001678CF75013EC6B9BD754047A5F7C3FB67 +:10D62000001FE39CCC1F4C69247A7F2DD7C9F4D509 +:10D630000A7EFF34FD2B72EAFA231E1BC647577180 +:10D64000BCF7D5D7E226FDEADB25C06BBFFAF6783A +:10D65000F51DB1EBBBE2C193101B9EA438FD07631F +:10D66000D7AF7EF9BD37232ABC647A0382F3FCDC92 +:10D6700072AE13FCABC40F538B1957B0FD0013DD12 +:10D680001CC07F941F1CA374EFE1FFB275F41B1143 +:10D6900083FE24827C57CCE1A165E7600ADF8F39E5 +:10D6A000B8D337B1FDCAB977B138D18F6DA5E8EFDE +:10D6B0001EE1F701CD6D647EF5DCA56C1F9194B180 +:10D6C000733E1EFA1F8C771B7442E97D5B83108AC0 +:10D6D00064C2BD3526FBB5EF7E9C450AD42F36C506 +:10D6E0005D347ED2CE23CDE7F67526E7CF85A4D76D +:10D6F00005726F3EF7FE0AD76B9ADE0FAE235970A4 +:10D700006E5FB438BCB03F2AF273A6C4CDEEF323EB +:10D71000BE61EC7E392D8F2B4B4D84F58D84F97BCA +:10D72000BECFB2E42A7590FE9C9674CE81F783D466 +:10D73000C9DE34D083F2396AD751574D393782A8C0 +:10D74000BA7364D49E43E1963DECBE44C953444A47 +:10D75000C10EE4F7039094ABFBECAEB7281E96AC79 +:10D7600053F1DCEA4227B3337FE12ABAD33901EC23 +:10D77000CB895E76CFAD918EC19D6C7E7530BFCC6E +:10D78000FE70D7295E2FDA9D57538B01E3385EFC7C +:10D790007D07D1AABEA7823CFE9BCC7EAFA01F1EF8 +:10D7A00018FDCEA624E3BDEC0BDCAB3F043E5DC30D +:10D7B000EF235C599B85CFD5B5696877D6D77AF1C9 +:10D7C000A9E1C5E66DC07BDF6CA3587F368F9FD97A +:10D7D00015D496817C0AC9531381B22DBD8680BDB4 +:10D7E0006BEFC34F03E247E92BFBB16CF5B0DF8D64 +:10D7F000901B67219E697B524ABF2F71F91F073921 +:10D80000B1AB9719EE91B3A68D37DD3768C29BC6D1 +:10D810001FDB18FED60A8C3FCCF85B2B77AAB0AF83 +:10D82000BCF6AABE7B67107FD4BC67F8FB2DDB6714 +:10D830008B8B3F4F32DAAF0BF2EB6FAFA3AF1EE42F +:10D84000FB8B0FD44E447CADE2F748DE5FEBC3A701 +:10D8500008F8A3F3B3660709DC8FCE7E1B823E9DDA +:10D86000453EB87F167817F0273A193EAD6935B8AE +:10D87000BF6673327C89CE20E24576327C894EC603 +:10D880006F0A2F4B80BF5C6C8FEF29FE0E007FD993 +:10D89000D2271BF0A5A4145C1CFE1EA3F8A370A441 +:10D8A00070F932E3214561F7536A7215CF8E7B948C +:10D8B000CE1FD6ED0DB5049F03E3F88B235C6CDD22 +:10D8C0004CB1D4EC97011FC984AF2741929E4F58A9 +:10D8D000EA21FCA505890A6581C1411A8619EE95E0 +:10D8E000143D92E95E367503F0C1FA43B205EEA32A +:10D8F00013975E6D380F2ACEF625A9884F3FDED3E9 +:10D90000FC60AD8AF45B0774847B40B9FF753FA768 +:10D91000E703FC1ECA555C3ED672797998CB491D47 +:10D92000BF3779CD4C9667959263E1F79545883E70 +:10D930008F29C91B260A850B6D6A159F78CF22791E +:10D94000DF1A1A4DDB2564131FF049D2FBF786D886 +:10D950007D8D4583C10E4AD2EE5F9CA226CDC18348 +:10D96000B01189F91D5415A21FD36989754F559DB2 +:10D97000F7800DE2A1F1E049F0FA32EFA7E3253498 +:10D98000BAD07E1FE02F9AB390969D8D0918FF4B59 +:10D99000E0BFCFE2A47097EAE81DEF1EEA8DAEABC0 +:10D9A000125D949E1E80913E1F691C89BFCBF2A818 +:10D9B0005C84BFE3F2285F4FB57BCEB576DF70FDA8 +:10D9C000E8CEBBCCE0B7AE977DD8CE33C528FFEB11 +:10D9D000B9BE4D9E6EE4734DDF1EEDD3B7FE110050 +:10D9E0004FEAB9E9A8C7526E88AD77EB6405EF2D11 +:10D9F000AF1BCBE43C58ACB0FB4BFBEB018C539F13 +:10DA0000F58FD9087A54E3ABE584E99D20717871EC +:10DA10001DE2F7DB6876F04AB80790EB57788AA3E7 +:10DA2000D8EF0FA4CE65F7F9AEE1F7583D44F98A77 +:10DA3000E0BDA75E7C5EED62FB13CB6DE3F13EB50E +:10DA40003AA705F584F48135042687B47F9207E26E +:10DA50000592ECEDF441BCCF2585E1DEDC3A671E92 +:10DA6000DEFB2E24E57980FE5FBA160C3F5F3E1D7B +:10DA70009D28DE97E94929221F65E36E009E47969F +:10DA80003D3710881B6E48A9B103DE26B9585CBF2C +:10DA9000B1381FF148F17B9D6B60B49F41B3AFEE8D +:10DAA000BB070BBADD10E75CF3AD2E662F91F420B7 +:10DAB00019A593F346ED774ED420C9D2C9FBF2D114 +:10DAC0008504F687FACB791C3DB699E9B115426C0D +:10DAD0003DA6D9999A1E934DFA417BD60F9F69387E +:10DAE000A7A5A4788177E119B478C1BE7BB1FED631 +:10DAF00024C4430DE081A45DDDE7BFFE6004D88F40 +:10DB0000F931F9CDACBF16F4ADE7BE54A0D3095935 +:10DB10001D3407F8E950ECF57CEA23973E0C7CB005 +:10DB2000E0B7A2A0DF4F293DB712D7D3927313F10C +:10DB300059D63813F99E40145CE7871D6FBADB0D88 +:10DB4000701D6FE479004D7208F2338E37DE8DF769 +:10DB500095409EB7A8DBDF27792ADA97DA3D63C7BD +:10DB60004377BAF5FBBB25BFB0FBC06E8DC75F2501 +:10DB70004DB1FD7A5843217E4A01CC027B98DA37B9 +:10DB8000BD11B07F365ABD41122D071FB1C7CC4F12 +:10DB90005CE29AF128E07D89CBF724C83971B27B29 +:10DBA00041E3F3391BF7186C02C37ED3E33C4F53B8 +:10DBB000F2BBF5F7BBF5DDC7C9E324C416E7BB43E9 +:10DBC000FB7D8338DFDD2C9F8378627FD7FC8484E4 +:10DBD000A89FD006F3A86A3C55FF01E289FB091C07 +:10DBE000EE133283FBC43356F63B3726BE38C1F3FF +:10DBF0004716090CAF1A7F9FE8B377FC780F8D9911 +:10DC0000FF848D976E9844FBFDAC43C6385C25E5D8 +:10DC10001FE01B61E324CC5F171E99F430E4257DDF +:10DC2000FEBA88DFCBCFD9F07BF7CFBC1BE6429C96 +:10DC3000E70D19EFEBFEBC6346228BF318E3D00B24 +:10DC4000DD6C9D3FC9E5BEE4DC6AE4CF3EFE68586A +:10DC5000A8805C959C7B08ED99922D02DE13498289 +:10DC6000BDAF4E95381F4E86F6A70B9703BEA7345F +:10DC7000E0FE46E966AB77B5D09FCE275DAAE15EB0 +:10DC8000F5D2AE35D82FA1F6548A6EBFFB04CF0370 +:10DC90002E3DC7EE07249E204903BEE77A27CABF60 +:10DCA000C67B5FBBEDB1E3ECDF707BA6E4DC648395 +:10DCB000DF109DDFF7997CF2F5BCB46B2283AB6F6C +:10DCC0003E1B26C59A4F741E53B07D7752ECF1333C +:10DCD000399E8FD596C1C90D52A6B07A250D772BE6 +:10DCE000A04F4A9A929205DDBC4A1B2B0C7918A5CD +:10DCF0004DC5CA3C5DBF513A385E9B3A2A4A87CC33 +:10DD000087E42B973B61BD2F72B961BC8D8BF27F8D +:10DD1000A2427F4CFF7C223764D4A07EB9D31DEB96 +:10DD20005C43A65B35C4954A1B397DA89D9CA7A37F +:10DD30008F461773FB63CDA5F93F8178F263EC56EC +:10DD400090F87AC744B7CCD8789BDC87B72CCC073F +:10DD5000BA30DEBE63C8FBE987374E5F0D2FDA7B32 +:10DD60006A1FE502BE2643C06920F4C3E87F217C18 +:10DD700045C7E5F49F1A7B1EFEBE792C25416A3FFC +:10DD80002CB8E03CEE2341DB79E6A1D19F5C66A094 +:10DD9000BFFFA1D157821C6AF45E70E031E4DF0559 +:10DDA000541E615FFE78C3DD86F5210A5F1CBA8FC1 +:10DDB0000A92ECFCFF7374FF440E6640DE57701D40 +:10DDC0005B474E6C7C30438FE725AEA90B812E64F8 +:10DDD000D3C08B5A3F8205DE0E15D72519E361BBF0 +:10DDE0005DFE809BBE2FE37EF58AA4C231B1D67D55 +:10DDF000EA174E81F8735DEDCC29106F93B9DD08F9 +:10DE0000BFAC05F6265C811EEB7EAD064ED7FB6BE4 +:10DE10006B307E4D6C41E2D19FF725CC2EFA86B057 +:10DE2000788BD64E91FD1E887F2AFC3CB22CF95788 +:10DE300066E6411C232527A8C3DF436E66D7AD499C +:10DE40003BE0817C522BED1FE231B674E9AC719F4F +:10DE5000929573844932CC474E09138C6766D3F789 +:10DE60003A7C2B2914CEF3F89B92CD8DFB451261A1 +:10DE7000769A367FFA06D7B307F8BAB41CE2B82907 +:10DE8000608759D01F5ACFE394BFAC2DE2789070D1 +:10DE90001DB326B1FA4A2283DB0E716B11D6D50869 +:10DEA000965D70C38E885793E1EF8F2611157FA77B +:10DEB0006F0089D4E33D2653BBEE81F7BE04FF1605 +:10DEC000E0832F07777E28401CBAC87F09ACBF8D3E +:10DED000623047A5F57F25F6E6403DF87DAFF79324 +:10DEE000D97338E42DFB75FB52EC5E4E551FD733CA +:10DEF00097872F954CFB357FBE44FFBD39C1B70BCB +:10DF0000E048F958C07D983A3BBBD7A7CE7573223D +:10DF1000ACDF8739BD90FEC03F1DCC8E392BA9895F +:10DF2000C918DFCCCA7DC530BED75096B8FFB689B8 +:10DF3000F2A3A4BB977594E4B300BF8C6EA0EFF579 +:10DF4000F48B11574B76E2F5B731F76134F8E8B846 +:10DF500004F0279E2B64EBAB890FF6080CFEA08B18 +:10DF6000FB5B2428023DE768F7054B2B5859FBBDA6 +:10DF700008A02285E3036D7F81AC6065BE4F1998D0 +:10DF8000C7F621CDF0CC697FA013E2FA73DA07CF90 +:10DF900087FDA939CE317F82E71EB9F74002D881CB +:10DFA000770B78FEE3C7BF7B454EA0CF9DEF6CC4D7 +:10DFB000F3C6A7B9DCDD4E7AF11E763FF1F07DF2B3 +:10DFC00010BE9F073F3087E5B00C7EFADC48E8477B +:10DFD000D7D0D26DAF84AE01B3EDF68EDEDF801AFE +:10DFE000F0873D85B807A0B56BF3BECACAAC5D1417 +:10DFF0000F366E8FDA705ED179DB100F1FF4E58D6E +:10E0000007911E7D78E2F72A6978E99B77E2CD5780 +:10E01000439C379E3E9BE3CCFA13DBFC607099F186 +:10E02000F4397CA276E4E76E9F3D91EAB78FDD3E3E +:10E03000073C2B6DBD19D20894173794AB45FFF000 +:10E04000548A87D3C3FC970C047C740EB8283DFA1D +:10E05000A19DE901929781F3D1EE7D3F78EF711791 +:10E06000D89DF53BDFCB806795D8B5F6168C6F8AC7 +:10E07000E80F9D6DBDE4BCE7C33E84B8135DFF4669 +:10E08000276A7CC8E677073F5F73476B029EAFB98C +:10E0900063A968B8B7F98EA52CEF8E489DE36E3260 +:10E0A000D8EB2BE2F6037100733FF39716908F07BE +:10E0B000C03EAB672AC6059E62FC357FBA4F847CA2 +:10E0C000E4C92B058CB74C3AAAB675D1F2FC5012B4 +:10E0D000FEDED1FC7B97E4C23D04D59D2CBE3748C3 +:10E0E0005C9CF333889F1C60EB389417837C3B7DEA +:10E0F000AA5317EFEF966B72E0DEBDE06D4E1FF096 +:10E100004FF14DBE0FF0F712791C425B5777351671 +:10E11000631E6BF15C7522D0BD386CC7DF1F2CB657 +:10E1200011C941F558B1446CF01CA410C90E4F0739 +:10E13000B1C1337F39BB27BBA4F17AB40FDC138B99 +:10E1400014B8FFB6B8FDD92FA07DA914D9CFCEB58C +:10E1500030FC14B71FFA1AF867A1AF08F30EBFB36B +:10E160004531F87F63C3C6F2E56DC6724EC458CE22 +:10E17000ED3096B7C21D673A3BE2C05E2BAE131579 +:10E18000A7D839BD9704589B201E6C45799A56D163 +:10E190009E0FFBD1A79E7759E0FB9EBF30BFB7779C +:10E1A000AB1DEF7BDBFF7B0771405EE10BF68DF073 +:10E1B000FD94239C0F71385A9FFDCE5651780CF870 +:10E1C0006F2F5EA6F9E9A17130AF17FFCAF2647A2A +:10E1D000B75AF1F7534EED7EF679D8173BB575284F +:10E1E000DA592F09410BF41B5CC5E86FE6D38A2D81 +:10E1F00046BFF89E44A66F7A0486EF4B1A8DF3BE95 +:10E2000034642CFF3C91F953F388EE7D26ECDFABB0 +:10E21000F569B0AE3E1DFBBEE1FBB95C3CF79CA2CC +:10E22000F1ADC8EF6723AAEEFCD29EE8FEDD5D43A8 +:10E2300021AF02703122FABEC234AED67F5122DB4A +:10E24000874FE1FB33BD6F88889F93A6DF2DECB32A +:10E25000EB6A6B064FD7AD43258DFB538BC13F6AED +:10E26000DA9F3A4FB7BE546E3D987A2BE62549F8AF +:10E27000BB4C95739E7968720ABC17C3002F7C87CC +:10E28000B85777F8376EA847EDDDF1A20EEFA58DF0 +:10E29000770F9EAE93D3BF952F3579AAE4F6C9AE1A +:10E2A000899D8590275ED1C87EBFA922FCA31BE172 +:10E2B000F71749133B679A2F912291CA4FE5F61F32 +:10E2C000FD107E8F2BF0E4042FC043BBB809DE574E +:10E2D000B47C8AE709569B7E47407BEEE3F4A5F5C4 +:10E2E00023165A7FF5CDCE32D04FB4DF57A07C2015 +:10E2F0006B23DE6FE23EC1E2B4F4FDFBF09328270E +:10E300000A826FDE4A9B9E22E177AFC984791BF9AE +:10E310008CF2AD007657EF66017FD7965A5AF937DF +:10E320008049ED5B8679B7F4FB1DB1CE3B2F0A190E +:10E33000FB31D3FFF79C7FE95F969E8FCCF506CC2F +:10E340000AE2B9C4CAA554DFE9ECFCCAA30D789F60 +:10E35000A3791C0CC2E9F20D60BD5451BEEDDC6E18 +:10E3600020822D9FE7CD8E6465BCB710F895324AA8 +:10E37000C56564BA0AF8BE81CC84E74B42E42151FA +:10E38000647A02E340DB12504F747BBA9E7902F844 +:10E39000AB652CC69F86F0F39EDD6A04EF79ECE155 +:10E3A000F1C96E0F2B97B7DB310FE6D46905F5E89D +:10E3B000B2F04137D0A3FB79BB057E97F4D4F601C8 +:10E3C000059027D91D66F7FF9E0C0FC0DF7F8DB724 +:10E3D0006E99F581B64E1E817FC27A9AE8FB06D609 +:10E3E0005BB282E5910E1A509313EBF724B47629B1 +:10E3F0004A4D0EF829FF0BC935400200800000008D +:10E400001F8B080000000000000BDD7D0D7854D547 +:10E4100099F0B973EFFC65669299C9249984FC4C14 +:10E42000420801024E42884851272160C054078AA1 +:10E430001A7F8AC37F80FC89B61B956E26266242AE +:10E4400051C31A1110704051BA6A1B5CD46883CF53 +:10E450008068B1D57EB176BBFEECB223B088562081 +:10E46000A2A5B4DB96EF7DDF73EECCDC49A2747716 +:10E47000BFEEF37CE943AFE79E73CFCFFBBEE7FD72 +:10E480003F6786BE6BF5EECE67F017CC575C8C9D70 +:10E490000BB8BD1BA0BC58825757306671FA8DF679 +:10E4A00034C66CE58CF9E09FF388BC5B86FAE3B276 +:10E4B000F7FBF6B18C2D637E03C36779C0C00AE019 +:10E4C0009B4E689CC9D852858515273C17FA3E900B +:10E4D000A6509931F87EE97629D401DF2FDB6864F4 +:10E4E000CCC4E8EF22FC5BD10BE5E25879150B199F +:10E4F000980CFFB13DAE1DF4BF4A091F9492195B01 +:10E500006D62610BF4BBFA29ED776B5898E6D3F096 +:10E51000DC45637CFFB03EC6606ABF63EABA7C1E1E +:10E52000FB34C65C0628C3BA87DED187100EFF21F4 +:10E53000FB695D6B5880FAB9A5B58A1D4F65ACF9CA +:10E54000EED6CC65F03CDB7A4FE6B2A9508FF38073 +:10E55000F1AD8C7FCF605D7B00666BAA593807E612 +:10E56000B71CD69B5406E501293C19CB26164C2E28 +:10E57000E3EF53CAF87A7D71F3AB673D345EFD7605 +:10E58000ED7BF6EB548267031BA47AF6545C3DC026 +:10E59000A341C0A1E139781F078719CF4941DB6545 +:10E5A000580A75A4C3FC9A4E31B6014A4DFB2F1A86 +:10E5B00035FDB31EC6000E19498C99015F8F4AAC18 +:10E5C000AEAF84BE9B307F32B4C1BFABB1DC4EED89 +:10E5D0008E0AF83D7AC38ACC00B47BD801E52C01C1 +:10E5E000E0E930860E07A772D804E3244D8D96A982 +:10E5F000BEE23E5E9E6F2FAED992CDD8667D20D30F +:10E600000E405C2AFBDFD401FC9E71066E40BC2CE0 +:10E61000D5F972155C2FF315F9611EAC95C3E1B104 +:10E62000B296092D25B179C5E6C7F1BB59EA0BEBC6 +:10E6300080CE82AF48DE3D1EA4DB217DC01A6BD7A1 +:10E640006C97681D2987226F8E41BCBF28B1DDD031 +:10E650006EABF4F19B63E0BBAD733DAC03CA6EC01F +:10E66000935C86EF59A7047029DF3FFF8E3710CFE8 +:10E67000E549DE71F068DC5F29375A69FDB7FB6157 +:10E680003E1996965D3AA8CFB8BDB80CE91BD67D69 +:10E69000FB02787F97DD43E3655A39DEDDF705F34A +:10E6A000D796E0F8FE3BDE80F18626277971FC0CD8 +:10E6B0008095CD49CF2E33B663ED12B67B3499F7F2 +:10E6C0009FA6936F9F8FE5325E76AE937CBB89F8F1 +:10E6D00036D1BA338CAC06E789EF4325B4657CFBB1 +:10E6E000A83EC4F13BABA514FBCB18CB9F2E4338FF +:10E6F0001BFB795BC5F740A68EA5E37CE1BF613EBD +:10E7000077EDABCC70C2F76F7F6E527429F0743323 +:10E710003688ED94B095E1B3B098B73789F6A5B3D4 +:10E72000327033B872B5EDCEEA7D2953012EC17730 +:10E730006586F8F8CAEA4B7140BB6F19F83A12F1D6 +:10E74000B813F103EB69BE00334F8DC35BDD790372 +:10E75000F6D77C4161A1A9B1F79FB79958A828566F +:10E760006EA83F3407DB35B2C1F548578D7D1616CC +:10E770008AA3F76F258D3CAE4ADFCD17742C984ADB +:10E78000E49BEDB7217C86D62FC7F91F90D81E8653 +:10E79000F506168C1BBFF982535B8ECE339DFA892A +:10E7A000B563DA76FDBFA7766C7A2419C739638F13 +:10E7B000243BC5FAF0BB2C99B5205ECE8674413D52 +:10E7C000ECE3331E5E7F96B19A3E6BACBDDADF9907 +:10E7D0003A030B13DC87A85F844B1078DBB6812FDC +:10E7E0000C1E28370C1C24B8A8F4100F9F601CDFE7 +:10E7F00048EF180CEB604FFFDABEAAABC40CA83888 +:10E80000A4EEDF355DBE99502FEB34FBD9521EDDEF +:10E81000DFC4561ED5C9821F347455CF8C2FF3F632 +:10E82000B1EF1B6BAA61FF9797F0EF8FDA9B8EDC3D +:10E83000A7C4F811AC2317E1122D9B12CA56284F1A +:10E840008E2BDB13EA5D09F5EE8472366FFFB92D6E +:10E850009C2B7B19FBD4BEB64601FEF279667891FB +:10E8600004E58D1D77D554039F6B2C1FF4C9C83F59 +:10E870000724AFC462F06BF2325F08E067F5460C24 +:10E880004B4B100E836FE2FE6FE897EC12D0B9B5D8 +:10E890006F5F98CAF89D27EEBB3E89BE6BE8FB9878 +:10E8A000BE1BB5FF621DEDE30DC5C7A81D00C07EF0 +:10E8B00002F0741393580A80345F09FC11F9646301 +:10E8C000DF275CEEB221035F1FE78367327DAF1362 +:10E8D0001F3C20D971DF45E90EFBB5C6E85D6DFF31 +:10E8E000D1E4817FC66E2C777DD1AE40FB7F6BFC7F +:10E8F000641A03547D844DAE40BE1A9A80F2781B90 +:10E900000B4C4039F4DDC6710775D0EEA83EB283DA +:10E9100001BC8A1D1B6A146877D416C99180874C84 +:10E92000DCD4CBCB69911D08CFE0A64709BE477365 +:10E9300022393A284F718479795C6407966FDCF448 +:10E940002C2F4F8EE4C8F07D41F0B99A6A28EFB1C0 +:10E950008FBC5FF31C9C8FABF33B31D697E54843EC +:10E96000B2E37262871E2006FC70D1EACF9EDF03FD +:10E970007058748F85F8D49ECFBF33CF4FEB0FFA0A +:10E98000950AE0879CF4B91C237EAC901E9089B256 +:10E99000CB19C3872D77D0437C7E62CB3E94F71989 +:10E9A0008B4A88CF5F48F1B53BA6C59EBF4BE7CFEA +:10E9B00076879DF36559E7A3F6F7DA48EF79D8CC67 +:10E9C000D703FB86F06B15F82817EB2977E8E89951 +:10E9D0006B9F4DFD7C28F9B69A647CB2A019F1B901 +:10E9E0002A89F48C5B77015F00BEDC2BE6DDBB6916 +:10E9F000422808FDDF2A313FF28D5E872F13F9C3CD +:10EA00004B7F916FC7F5F69642199E3F15FCBE7776 +:10EA1000BE2FD31127177B77F17A95EFF4E6F3EF4A +:10EA2000557993D1C1C7C97878C26E5C8745613E7C +:10EA30002C2FAF2BDADD4E727B01CD97F97C99122A +:10EA4000ACF7C4AA021DEA912A7E9442DF75587F72 +:10EA50000BF66F8DE1491DBF1DD79D867A00C87DDD +:10EA6000586F9B33D08EF8043D600AE981420F68ED +:10EA7000C7F5C6C197299169F8FEFF2338DD89EBF8 +:10EA8000FEEFC269047E11C4711B5B815FE8E2F88E +:10EA90008580DF6629ACCFE0FCC28B720EDF2F00D1 +:10EAA000FE788B3DF000F6AF8EBFE8DE46D2FBD499 +:10EAB0007959FEEEE59A9BD8F07D96A8971DFDD07A +:10EAC000B491811C3B6AE823BE78741EF3B623FF21 +:10EAD000D0B17A84A3AA5756DCB3E66D06FAEC9758 +:10EAE0000E99F0DC2DF932715DDD805713CAE1F922 +:10EAF00086D09EFC985CEC7584B6AE40BCDE50E2DD +:10EB00000D7A483ED27E0BB65AA85DAF23C214AC34 +:10EB1000BFC2638799209E091F43371B42BB25C490 +:10EB200037A797DE5513434189F01EA4EF6FE6F433 +:10EB3000D33B9F917EDF7BB39BE8C6CC42669CCFE4 +:10EB4000687490DEC1888E98E29B32DF1683C32FF3 +:10EB5000C5BEB694475EFC17D423379A498F4499B3 +:10EB6000897617EBC9A0F9023E5F22FA50EDA5475E +:10EB700032431BC83EF356203E1EB0F916D3FC7F2D +:10EB800060F1E0FCB79B5997A90CCD0FD649FC4E1C +:10EB9000CC87F53CC6503FBB5DE867FF5E7FCE8605 +:10EBA0007AC01B0EAE5F21A19880FF2D61BC7EC98B +:10EBB0003ACBC768CF2C5927878D60AFB0AED9BE8E +:10EBC000489C9D411405FD0504BF645B866C483775 +:10EBD00001FC2E19FBFFA3CD63C5327C3F05D10E8E +:10EBE000DF17C7BE7F5FECDB45329F3F6BB378100A +:10EBF000BE897CFD7D757E3D8FF9E2C753C749EC28 +:10EC000017ECB80F903E01EEE114D4E77F20135EBD +:10EC100013E7EB320C3D6886FA456DB2E33E806740 +:10EC2000A0D546EB55E77B7BC6D095645F25F47F86 +:10EC3000D2D254A1E0FA85FDC1D669ED2FC60CB140 +:10EC400032D0C572364476CCB0F7C26E4DB4FB18E4 +:10EC5000FB8B31BE9DBA5F98474A98BFA02B8FA40B +:10EC600020DE0212C79BC130B408F94EE2BC5578D1 +:10EC70001A9D3A01774E1789F0363AB9DC4984B7C4 +:10EC8000CB10C9C17E03AD46825362FFAA5C7CCC27 +:10EC90000CFB07E86E8B2411BD6EB9DB42728E99B6 +:10ECA000389E9B572779907EB719869EA67DF5AA38 +:10ECB0009121DECF9A875E227E55C8FD0A677F29A3 +:10ECC000EFC27667D238DD9F79454FFB8D4F06F452 +:10ECD000A15FCABBA95EE2FD9E69B77870BF36230B +:10ECE000A461FCE6E07FB63180EF711DB7939BFB1A +:10ECF000B5F6F019F8575F16E31B67191F27D8CF31 +:10ED0000F904AC74158D736B12DB00FD36E9241F1A +:10ED1000EA4F4DAB27863A383D99703F3588293503 +:10ED2000E9C02E2C8BEDFF26DDB122B4AB1A4C1BB3 +:10ED300007E564AA3F8CF618437B0ABE5B8D1FE58E +:10ED40000F877FD3C6DFFE19E7DDB45F4B170D31A8 +:10ED5000FA912E4AF87D1C3DE5C7E884F46FE41F64 +:10ED6000D52C344EE27E1A2C5B6A0643E8A769165E +:10ED7000FE8BB4439139483FB6F23EB6049ECDA710 +:10ED8000B8FE316360D7EB68073B6A06737099CDB4 +:10ED9000AD6BA79E981AC3AF3ACF2B0636C968DF72 +:10EDA000A97A4B9C7D3961C1E4F8E77DF41DDAABAB +:10EDB000385E045FE1BE51B8BCDB2CE41DC845E2FF +:10EDC000CBCB7BC6935C44B985FC4DB57791DF21F5 +:10EDD0007F79C659759B13D6E94DADBAC9398D8F68 +:10EDE000437A3E1A49570C8767A2DC51DBA1DDDB71 +:10EDF000621DBD5DD40FB43585F30F45A2F28A5F65 +:10EE0000E8776DA0F929442F6B77E4133F56FD3561 +:10EE10000DC24FB542F8775608FFCECA2D46E68997 +:10EE2000F76785B4E506C10F1A5984FBB9F6427D30 +:10EE3000BC5FA79A856D588FFE1D7CF669BF6F6613 +:10EE4000A1590AE2B7FFA231FE3DEBE5EBBD5DE063 +:10EE50007DAB99FB7566ACDB257367155F6F4A99CF +:10EE60002FFF7E94236FE9C9FFF01F024F2A5C2C0D +:10EE7000CEAAC508EF24B4D7B0DDFD4682CB0990F9 +:10EE8000D7FB84DF6301DAA16D81CCC242048F3DE0 +:10EE900077816D387C37BC6AAE477AE97172BD45BF +:10EEA0007D3FC7A9A732F98310EEED16D2BB01CC86 +:10EEB00053908E2A0A5439CAA6A01FEA633DE8631C +:10EEC000506EBAD11AC0FE22A837407987E05F3B66 +:10EED0009C06EA4F2D47ED3C412F300EF5877E19F9 +:10EEE0007F1C1D3C156DBF49E8939C2F6C5E9544BB +:10EEF000FC2846B73A46745BE237A03FE955C14764 +:10EF00005E0580929DD567E67C44E1FCE9D553130C +:10EF100089EF1DF96C35F195737549CC28517B9FAC +:10EF200084F52F1A43F7417999F0B3BE2A713D3128 +:10EF300078C046FD3418025BD1EFD0F0C2382F60A4 +:10EF40008CBD6408FDE869AC7FCD4C7EAD86643E27 +:10EF5000CF8657C7109FFCA93EF4EC8FC94F6124A0 +:10EF6000FDAD21C99342F53F4F6558DF65098471B6 +:10EF70001F6519B95ED960081739008EC7425C3F1A +:10EF80003E868C06FB1FB091DE03D3CCC4F18F7795 +:10EF900067783778627039FEE024A2FFCD7A8EB7A9 +:10EFA000E02BDCEF794CEF9F9309E5632F967AC154 +:10EFB000B26467FD86B001E6D8FC30D7E796EA3C3C +:10EFC0003B5B9137BD66F16AECD18756D6627DF323 +:10EFD000EA75D7211F1C6D3F233F8FF7E79E6143E2 +:10EFE000B9648FD617F48561DC330313BC243E99D2 +:10EFF0001B900D7462E76D4FE801DE485F07F44433 +:10F00000BF97DA3FAE17ED43942F384E33F0DFA8A9 +:10F010009F99F86F5C591EA9CCF1D9FC6A86D0DFA4 +:10F02000B4F5B7A604CEE1FE6AFA87DF1F6D25F8B6 +:10F030000E11FF633DDC7F7E42EF5B8474EAA80E15 +:10F040001B96C4C9EDA4542ECF971A859EC7C286BD +:10F05000F87DA7D6575469E95C7D9A5339BDDB0624 +:10F06000391F1F5EAF13FBE13B46945BDCB503F633 +:10F07000F629EEEF484AF550FD8C5361C35228E75C +:10F08000AD0B1B568827EE0B8077D804EB3EB1D52D +:10F09000C6F7338001FB59319D91BEB242063DB5A2 +:10F0A0000CDF7BFA238097932F3A387DFD09A0026D +:10F0B000F05ECC443B23E8B5C0B75EEE94C2A8F73F +:10F0C0002FDE62DC6DCEC77DEC936D88CF1D12F113 +:10F0D000ADC59D95455BA1BC7AFF64C27FF2744EBD +:10F0E00097AB430E927F33041F5C6A0C1948CF7EA6 +:10F0F00096FBF1A07FD2971BE0A3CCB2E17040FE5B +:10F10000ADA18790360E31A34FF0D3BD71F1878248 +:10F1100038BEDE97F03DE8795AFA08AA7287F339CB +:10F12000E6C9403EA7F2618BD33F2D95F050988100 +:10F13000F8057C723EB94F22B836B2162E3704BF9E +:10F140008F8E2BE4C54939C8E59271133DE7A5E6DA +:10F1500013DE56A3BC21BF3AB7FF46A38379A93A71 +:10F1600061278C4C07D70A3A6838C5C257C2780D58 +:10F17000EB58B8710A7FDAA6901CE4F2D024E21DA5 +:10F18000261E0FF926B998280787C9BD047997610B +:10F1900010F24DE039DEDF8DF27EC6BA908C7ECF64 +:10F1A0005CBBAF32635A4C7F697EDF64F25C86657C +:10F1B0003F2BB0A2FFA6F25937FA7FC15EC77D652B +:10F1C00001B8EC42F9A2EAB76EBE5EB781D3AF5E7A +:10F1D000F1B3522BE26590ECD9A13466477A54E141 +:10F1E000B9C306DF95E1777CBF45BF37B1CEA4B880 +:10F1F000EFAB5E35135F3DFF8A2D6424BD2390E79E +:10F2000080FED23F32921E7AE6551BC9CF3342FEB2 +:10F21000B954BF005B4FF85927F01A645563D0BF4B +:10F22000CAA479639005AA7A58A363347FB7A8CF9C +:10F230001FBC91D39591ECC9F38EC8F7B10CF36163 +:10F24000A85FDF25F0DCBC7F56E9BDF0BED96FF5C5 +:10F2500072E8074A915E8DF25D37A2DF658EBC6E63 +:10F26000E86E5847638ED56E844FAAF3FEF53737A4 +:10F2700043F9D3FD7A66443CEF9955C70A46E7BF88 +:10F28000AB42FA6391B8FDB266AFB6DCD8A72D37B2 +:10F2900033E558248E1F3F9E6A739D9C44BCC37BFC +:10F2A00011E8DB686C39B50BE66BFCA991E4514BB6 +:10F2B0006A20949A867AF9D09B086763DEE753D078 +:10F2C0008F5195F7278AFB9CFF01F3E2BCCF9B2B64 +:10F2D000497E9FDF6AF604E3F857B3A0FFDEDC5AED +:10F2E000AAEFDD66F448BCBE765A05EA833436FEE2 +:10F2F000997400FFE62D733F25BB09B57628F7A268 +:10F300007E89DFBD2085DA517FDCC2E5DE69D01F52 +:10F310004D309F9308678C7BC803734CF09FBDCE24 +:10F320009A09C85F943F2B7EC4FF03D8559CBE7BCF +:10F3300020CAA7B99FE75AF4F38C253FCF01E41BFD +:10F340008DA688A112FAB9FACF5F115F5ED9BA848F +:10F35000F4FA989E6B243EB2F2EE00BD7F7DEB3551 +:10F36000B4AE93B06E84CFC91DDC9E5B996D0DE188 +:10F37000FCAE7670FD77257C2749C3E19208874F64 +:10F38000B65FE3467C7FC2F878C13EAE277C621F41 +:10F390004C26FEE36949463DAF79CB359F22DF5AC3 +:10F3A000B943F6A21C67076CE41759B963F684E504 +:10F3B00056ECE7CBD44A84DBCED97699DECBFE106F +:10F3C000F7AF0C5E0DEF959D977B709F1CDE61E49F +:10F3D000F373989EC6F95FFD6799E85ED1B100EAC4 +:10F3E000ABBD06DF04DC6F9EED7BE6205C3F999FA2 +:10F3F000A5A3F6CF4BCC8E7070B4A6E3FB9592E23A +:10F40000C7FD55BF65556DBC3ED2952A137E2AF3C4 +:10F41000D6A547AC44EF37A29C6BDCA127BDEEF02C +:10F42000820F7F73B32B46EF2BE59E1B67C4E91B4E +:10F43000CDDBBF2DE8012436C069A58093316F5D17 +:10F44000118EFB4DF4BFF2BE96221EAFF9FA7D106D +:10F45000DDDFDBF97EF833C8FB8BE8EFCB766AF4AF +:10F46000FBD1EC20D51F6DF232DF1E2BC5157D6858 +:10F47000E716B814AA2F400202FA52FEB076EF3B0C +:10F4800030FFFDA9018B0BCA79CC578A78F50CD9CE +:10F49000AB409DC42591FEC3B61BB93EA970BFDC2D +:10F4A000E634F6F486B879E68AFE607FBAB09F3318 +:10F4B0001FFCE94D845F53EEE75378BCED2B8A5F68 +:10F4C0005907785CD3EAF533A48BE681F96C594986 +:10F4D0008C1F367B39BF1EC6575C7ACEBF5C43D4C7 +:10F4E0004F4D1AE767AA3F785B6B12F9FDB6B94238 +:10F4F000666EDF0619F2F3EBCA651E8F117A895F1B +:10F50000F8D14CBED719C66B9857F68E83F2A0EF90 +:10F5100078672A94DF299FED95A16CF53DD9558038 +:10F52000EBF6EA45FD58F227BE3DB392F493EB7C2F +:10F53000328DCBEA93C95E1FF4BDE75A06E35ECF76 +:10F540007CA927608C1A10D688C7411C1BF0655413 +:10F5500002D35D7176D3B7BD73534FC4CB4B1F97A6 +:10F56000FF688FF789B8C24870F0A6565E85F0BD77 +:10F57000FA2A8E87CF9EE7F6C76766EEE756DB7DF1 +:10F5800066E372C6EF52FD847DB9C8E7A3E5DB8A66 +:10F5900035716297A12F17F7D96F256D3FABBB74FB +:10F5A00014BF5DD5C5285EFBD98F5ECE457EFBE9D5 +:10F5B0009E977397C4CD2FF13BF5798B3A9EF04B14 +:10F5C000A97E4A97885B2FF11AB93F70143FA5DADC +:10F5D0009E6DE1F6D859E0EE4877EA7767EB937CC9 +:10F5E000A8579E6526E2674B0684DFD3E72B74A1FC +:10F5F000FDA07E9FD0FF23827EA47E89EC734BC941 +:10F6000010F1D75526FF9B633C98B7E223FCCC450D +:10F610003C4A48AF3E03AE5B11769E51F1DF8178E4 +:10F6200058DEA3C5638E4BC433EC2EC2BBA1C9AA5E +:10F63000A07C48EF10FCFA7B3AB25F0C596E2BF2BB +:10F64000A5AB8B923A312EEF4A4A9E827EF59CAC56 +:10F65000626A1FACE2741D4C67E4B7CA642D12F1F4 +:10F660005B3BF783674F6776CC03F9A98BEB0D6E95 +:10F67000E6DD22933ED827513C40AC5FE5EB482FB6 +:10F68000C8E73E934C442FD28044FA9DACEB5B8498 +:10F69000FD8E463F5B5CAA5DCDE9275AFE1BD1CFAC +:10F6A0006E75BC61F413A038DE12B76964FA117E7E +:10F6B000D74B6E3F5A1CF17B26D50F2DE17A6B4557 +:10F6C0007FB5266B589E42FCE1F3787FEA76D03313 +:10F6D000D11E51E38E633A167BB89E3E1841BBDCC7 +:10F6E00072B989E4DC0F7583F9A8CF27C62101B36D +:10F6F0000EE4F7C863C8AFD85AE53F911A27EF0F59 +:10F7000070BBA1E96E1FBD9F35C0E57B73A181F47D +:10F71000CEE67E2988786EF21B42A67C8ABB2C2618 +:10F72000B9FDA0D9C3E3289E768AA3FCC0C3E32C0D +:10F73000513F6A64E7BD486FF556F23B24C6635EED +:10F74000FA8BCCC71FC768FCDE521EFFE99DEB2178 +:10F75000BF46629C8D7569F7AF1A67396B03C0C0ED +:10F76000784B369A090F593287334B3171F9329CF5 +:10F770000F90BF367DBA408C888744F73590249629 +:10F78000B344BD1ABFB195F8F351C35D94BAFFAD50 +:10F79000A4697F4DBEC33D3FC47C8651F31D82C624 +:10F7A0005AAC37A1F62CEA71DA206FD5B2CFECC192 +:10F7B000F84EAC5E01BDD1D42F89F15EBE7636889D +:10F7C000E0B3923A7EE7069F95E2C99AF1E2E7A795 +:10F7D00024F4AF87FEAD1ED13EF8E3B9B30B296E1A +:10F7E00029EAA50D3E98DFC37A6D7F0452F13D16DC +:10F7F000D4F10E67D4FC70E3CC98DC073DC09A3698 +:10F800002D26FF1FF8B0B6E73218CB62FFD2807208 +:10F810005595E3CD2E9EFF90B85FD3D338BF07FD3B +:10F82000353D8DE40ED76B6B45FC12F4D939B8B574 +:10F830009AD7F919C62F415FC84A237DE1F3930790 +:10F84000117F0B3E237DBEF982C2FD2EA077A07EE4 +:10F850006E1274CEFAF5246F553A582DF84FAF0357 +:10F86000E43DD2EB01695A90E8A225F706C0C1DF5A +:10F87000A7F90A711EAADD9538DF2BD3B87DDC5CB1 +:10F880005CB5B508FB7F4A6228EF37141F4B47BDB4 +:10F89000A479E0E3F4E571DFADEA7F94E0B06AAF0C +:10F8A0007EC4F55F99C6E39D4DAFBC48FEC1CF4213 +:10F8B00012EDE57A25D43D03CAF5F53AD4D058794E +:10F8C00068F1CDE4EFAF33B071B0BEB1288F701ED8 +:10F8D0007BBF139C81F619FC93E0D536FF0A927B1F +:10F8E000DBEA4C568C3B34172FB983E0604FF22192 +:10F8F0001C36145765E2384DF3E7D8294E00FA1547 +:10F90000D637DD7D0BF94DD4796DE8D7D7A0DE551C +:10F91000017AD63FC1BC739CF36ABCB0FFC6C8FB7A +:10F920004AEFB462DC7864FEFB5E3AC767A7E40F77 +:10F930005E5F4E7E4216EFF7CBEBE7FADC0D690611 +:10F940008D5FF8863485E0303338380B69EF352524 +:10F950006241BDB799F9BE40FB92F9AD9E3D842747 +:10F96000CE475C6D1EF21F995C911F5E86F53315C4 +:10F97000B21F98127904C73DD3EDF26E60827EB15A +:10F980007C774908F9E8EB69812588DF0AA13F9E69 +:10F9900079E59A52F4B3A9FA51F72E7308E384DD9E +:10F9A00036CF3FD4201FFC83C2E3E2A6A1C1598811 +:10F9B0008F3F3AA9DF6E73A81BF11FDCA4A7FA578B +:10F9C0006C8146A4CB53F36B8A282FC71A2CC238FC +:10F9D000B0DED5C3504F007381FC0926979F61BCF0 +:10F9E000745670B122219F4FD03B6689FC52629EB3 +:10F9F000F0BE4AB0B1714005274DB4053A2FA6C6F6 +:10FA0000F490237F5AA8E04B553FD199783CABBA8C +:10FA10002E89C948F7EB87DED4A1FFDA3548FA6BA7 +:10FA2000639F44E33416BF40F9626B445E52343F37 +:10FA3000488950BED4FA348BD0033BB91ECD06C9D9 +:10FA40005E66CF717C3216A13CAA981DD14EEDD4D2 +:10FA5000FE0CC2EFDE28FC2E20C1A87E539AAA5FBE +:10FA6000DEA7F5D78B71374B833E19E15A2A69FC23 +:10FA7000C5EA73AFF83EE5D0D01CDCBF43AFA87930 +:10FA80009C3C4F73EBB4895E549D86E571F67F31E3 +:10FA900007E906146DDAAF4DFD9796C7F9BCD86734 +:10FAA000FFE3799C5EC9B71B9E2FA739B4799C5E92 +:10FAB0000E3F35CE9698BF792633ACF07CACC8CEDD +:10FAC0003D489FFD46CAF3AAEDFFD9FB281F6B4DA9 +:10FAD000AC0FE390897A469BFD3B61A4FBB3A74F33 +:10FAE000EEBC9F611EEF4B5ECAE748D01F12ED844B +:10FAF000DDD82473747DEF37517C727D2F5AFE1F41 +:10FB0000D7F7B83E1FDCC3F307547EDE2CECB3B34B +:10FB1000F5E79251CE1C4B53F5CF843C87A7449E0A +:10FB2000C3C0C8790E8AC817027D3D4874B28FC71A +:10FB3000758E3C6D21FE71CEAEEC467DE9B46DE86C +:10FB4000FB082C45E8499D078C1EE417C0EF887F11 +:10FB500007F7E9799C06E33618C7796D8288E38850 +:10FB600078D1AB16D25B1A923D29F8BD1AA7F9A934 +:10FB700090370D493C3ED36509FC3E6D84B8CD2ECF +:10FB8000A17FED82AEECD8DFFB4611C7060681F6F9 +:10FB9000CE83393CEE20E2366745DCE678B12E6C48 +:10FBA000E07E08F25379BA149609F59EF7CD210F3D +:10FBB000F767997420F797AA719BD7B89F6AA988AD +:10FBC000CF1C5F3087F28796637EBC8C7E0CEE671D +:10FBD0008EE6EB33BB0ED7B306D8C5366431418011 +:10FBE000FAE5F05AD249A84F783AA14CCAB2AFA769 +:10FBF00006C65DD2A9237B646997D65F7E7EC31D4E +:10FC00003528BF1FE8E4F1C7609744F27B29F3B9B8 +:10FC100051DF50E9615C7A2AD159B053E7C371AE24 +:10FC20004CE7FE04007D88D6279E9D7AE16717F396 +:10FC30006867BA303E75127F3E60576A4694CBA221 +:10FC4000BF4E7D8BA912F5D81C1DF979CF1B7C7591 +:10FC5000E427751611DE3A6D2D5D35BC9EF6CA7926 +:10FC6000F3909FEAAF54B8A2C73C4EE49363D245E9 +:10FC7000FC2661BDCB7BB4E5C4F8C3AA90B6BC94A6 +:10FC800005C667E23985BDDAF763D239FF3FBF2188 +:10FC90005FF8F9BDE4E7EFD47B7E958F7CAA5B210A +:10FCA0003ED99ECDE1A5CBE1CF0247751DE9070EF8 +:10FCB000D02B68BE7CFE0557BA2494979D0E4E97B4 +:10FCC000FFDD7927CE77767A11D71350B9C37DD46B +:10FCD0002D8538BCF8BC2FD55FB1225D6B6F46CB4C +:10FCE000FFF3F626A7C76E59EC373BF19F2522DEBE +:10FCF000785CF23E1DC6F756D00B60DE4BBBE5329A +:10FD0000D44F667DC74AEB687ACD1C32427DE3BA98 +:10FD1000482EEEA3A6AA4851CB0870C5D92A2ADFDF +:10FD200082764B5C601FE0BEEDD2C6A186C7157D12 +:10FD3000F7A6A7A11D727CDFCF10DFFBCC2497E0D4 +:10FD4000BF0E1AD1DFF14A3EE94B5352021DE9289A +:10FD5000CF93C23B9FC947FD84EB478D03C65DA887 +:10FD6000FF2DE9D49EAB611BB5712ED6E5247F062D +:10FD7000EBD5BEC7F32B9AEF86C5BDB89CDF6C08E8 +:10FD80004C40BDEEEAAB787CFDF42A1D43FC2E9579 +:10FD9000BD2B908F9C366BF5EED3368EAFDDE9AA86 +:10FDA0009CF116219EA3E56178F616219E97EA58EC +:10FDB00020BE9F46C4F354CC4EE7783EFDE2E545B5 +:10FDC00088E7CFF75D5E8478DEACEFF1E1BE79C6FF +:10FDD00019781AE17362B69FF42635AFF252E9B191 +:10FDE0003F811EFBFFDFD1635D7CBE5FA21C3C1C1C +:10FDF0008597560EBA0C9E6CE4874B4CC6AF958720 +:10FE0000F837A23FCD64247FC46B7FFAF221946F50 +:10FE1000C10199F40FB5BFD794C058F417BCF6BE12 +:10FE2000DB1B9446EFBF45E8556E130BA2DF43D5AD +:10FE3000F755BD31911FBF2FE0782ADD578B7AB679 +:10FE4000EA9FAD177D9A425F72FDF42989FCAF26C7 +:10FE50004F1FCFAF3FB0D88EFED95321EE8F6D7AB2 +:10FE6000B194FCB5AB42AF8731FF890D4876B41B26 +:10FE7000563DF57132C6B3C10EFD243D2EBE325B38 +:10FE8000D8A1A742C79331EE0DE3D7A05CB6B886E0 +:10FE90000C48BF4D609F4113D6A40CD1B9A22617C0 +:10FEA00023795FDEAFB5D7D4F8E436BF81F8DDB68D +:10FEB000012984F659BA21909F8DF28965DB4F5A4A +:10FEC00062FBE577E93E17C62D637161DFEF715E76 +:10FED000AA5F27B23585E830A2673ED203B6DA04BE +:10FEE0005FE2F19ADF6D778478FE126FFFBB503EC0 +:10FEF000955579BD429CD35B21CEE921FF0E27F0B9 +:10FF0000EFF87234DEAC9E47037E1E1E29FE1D975D +:10FF1000B714FF7D131B12F979178D9A7EA3F93A56 +:10FF20002DA51E98F79ADBAC740EB119E8BAB52C62 +:10FF300046870D62292A1D3609BF6E73FD31B20353 +:10FF40009AF1FC05EA555E4E870D601F617E67E2FF +:10FF5000BE657DDA7CC6D1F6716986761F47CB7F98 +:10FF6000233FE6CC0CEDFE55D7AFFAC1A3EB1C90B6 +:10FF7000F8FE4A5857A25D99E8BF56EDC24BE56BB3 +:10FF8000DF89CE87C3235AFE1BF3B5DB3346E36B11 +:10FF9000DAF8C05FCDD712E30485DCFF8D71028CE7 +:10FFA000DBFE77E3049F7A7AD2753C4F5F133FED17 +:10FFB000925AAE338DC5B8228F2F37DA8C14874D05 +:10FFC0008CAB367BE68838E2E06FAE40B9B95FCFE4 +:10FFD000509ED75B5752BCB2597ECE80470E87C524 +:10FFE000139583A4B7FFB571F5F5193617F1230FF3 +:10FFF000CBC7B87A625ED1EBD62F530371F8AD2A26 +:020000022000DC +:1000000001857F043A362941167F5EAD3783EBC107 +:10001000AF8BFC17B781E7B13F6C033B0BD6E7D63C +:10002000F1FC9CBF4FF36FCE48433ECEE1F7C42BAB +:1000300037313C77F484BE8FF844B0D1EA457EA7CF +:10004000FA55A2E309FBF352E9FAC709FBFCC77FA3 +:10005000E37DDEAFD2F35F1BEFDA026BD5D03FA3B7 +:10006000B8D6DB18AFC91F4EA7A3F5331ABDFE22C1 +:10007000C3FF6606ED33DF14CABBBD447E62291F91 +:100080003A8EFE1BB6DFE8417BC224CE65B08D9967 +:10009000224FD25B319FF285F9B906F5FCC7687A29 +:1000A000DFC7D1FDCEF5BE8F47E53BFF35BDAFCDF8 +:1000B000E93F8E72F644A5AF08E5E20336983FDAD1 +:1000C000733F328E78CE423D0F00F4C4CF9B3CCFBD +:1000D000E3DC8974F587047EF987FF257EA977FF25 +:1000E0008DF865FD1F93D1AF397A3F419EF75B359F +:1000F000E8137129867121751DCD833CBF2C5DE409 +:100100004DA9EFBF127AECED6E5F861B9E9F7F605C +:1001100032B114507190C650DFF25BC9DFDFD4C733 +:10012000F3409AD6318AEBAAE7289BFAE733D4EB5F +:10013000F6A706F2F1FB073EB406E514F4832F6040 +:10014000A8CF9DF980975B5203E3B0BE795D44135D +:1001500057A8B8F8E57AF457C07CC9FE7719B5E717 +:1001600029E6BB393F539FD7097847D7E5E2F364C7 +:100170007D7208F5408B6790FC444DFBB9725621A7 +:10018000FBC81FCFD638E97C44D3FECA523A6FDE93 +:10019000672E453DB6E2A35A3BFA1F3EBFD24579D2 +:1001A00004B9726415EA51AFA70566E27C6DE5A15A +:1001B000B9A887E6811E8A7AEDE7FBE69606E2FC9F +:1001C000D99BD19F0DFD6EB669FDD5CCC4F3C0EBB4 +:1001D00077F33CDF576C8139D8DF66339F6F7093BC +:1001E000C86B167EECC4FDAFEEFBE839C75B4D145F +:1001F0007756F9C2663D0BA05C53F94989C8830361 +:1002000078F03CBC81F93C9F4394AD2E6D3EE2A951 +:10021000F4D925389F12378F0B2C370D49E8575FDB +:100220002EE2ECD7887C09353FCAA8F8BF8BEDD900 +:10023000BA9A587CBD00BFB78B73BF3C0FC67281A2 +:10024000EBC7057603D18D0DF617F93F806E103F91 +:1002500033870667E179A2C2DEF04C84E76B17743E +:10026000040F65FEDB141F4941B4413F633746BAB2 +:10027000C7A39FC4FEEB2B112F9E1E7B15826E7FA2 +:10028000AABFD14DFEEC9662B41BABFE59CFF3FC76 +:100290000E58C8FEEFCD6DA03CBF331F1A473C1768 +:1002A000A23E83EC3ECAEB2BE87F8FFCF4B6FDD276 +:1002B00088F99A5D6E2B8F1F0507297F8CCD74F10D +:1002C000F384073EA2B8AED2AD9087A253EFD3E13C +:1002D00039A8603B23FFE4B85EBB0EF19227F247DA +:1002E000CEBEF69F53026487A87EF910CFF7D147A0 +:1002F000D6A35DA5B447AE821DCC1AF73B744D253D +:10030000D8DF5013CF5BB730A493BCFEB1F77D0BA1 +:10031000CA795D762621FF79754D1EF943619DE30B +:100320004658E71D6E9E9FA31CB0E8506E299B188F +:10033000E5172A8EF42A9AF7A350867ED608BA517A +:10034000E38D305D37CAA3DBDD811D88EFE8399886 +:10035000D6247E0E469CBBB4B57EF83C9E2FD96950 +:10036000E0E70C0FBD366901F9E5BA1509F170DE59 +:10037000B138CF0EEFF78A7D6B530699DD1A0FFF68 +:1003800043944F597080E79D297A4E274AB76B17DF +:10039000FAFD2EA404286FF4CACEB04CF12AFB89D2 +:1003A000476A3C7176CB162E479AF6727B39D14E4E +:1003B000F926F971D0ADD54BA2E5BF915EF27682F8 +:1003C000DCF8ABED0FA6B5DB12F593443B6D985E00 +:1003D0009DD0DF687A8A9AB751151B87E8E1759B33 +:1003E000AA070535792D555671AECDA4ED7FAF8B9B +:1003F000F30935CF25BDC3D38E79E3433F60E4478E +:1004000053F36D8255DC2E08EA4C74DECDCD7A288C +:10041000CF660C0B4B12E9F7113AD79981F936F0F8 +:10042000DD07EE027E3E8579BB64E2871E09E76D3B +:10043000C63C0DCACB0C6D5D81E3DC60A571CC9828 +:10044000A7311543EDBEADC83F67D5F3384316C895 +:100450005BA4DBAC424E87E63A9EAFA1E663A8F907 +:10046000132A1CAA047CB3C6AFC847FDBF5B0AFCB5 +:10047000483D4F1B7F4E3A7A3E7A55019D27899E13 +:100480008F2B64A2FED2CE4927C253CDDFA8B2077C +:10049000EC9969C3CFCBAAF41187379AD7B6035C1E +:1004A0005FAFAA37D0FCCFAE9A477EC2B3AB740C15 +:1004B000F74DD58091D35BC278DBA2F76084CC7412 +:1004C000DF85C0FB37E9AB80CF62F4C31E6AAB990E +:1004D0007A02607BB8CD4FCFB366A94FBE8CCE2BCE +:1004E0002E42CEF465E6B65ABCA7E0AC6D2817EFF5 +:1004F00039F832EBFE6F53396DE8289693B39EFFBF +:1005000036DE7B7076DCD04EBCF7A0705B25AF4743 +:100510001ACC62ECB2CC8A6F0769DDDCAF342B7683 +:100520003EBB1CE1D3C822EB07C97FC3F3F3319F65 +:100530000FF1E0B61A489F718B3C4A562DF22A31D2 +:10054000C202E58ECC528A475B9967FF20D667F3DB +:100550007340504FF4DB318EFB7D4D02AF2C5BF5C9 +:10056000134582C89F3AF21DF47D948FEE3786B80A +:10057000BF8A8FFFEE8B93297EA4E6873266CF5920 +:100580003899F2493465F57E03A6D873505FE8D0F8 +:100590000BBD5494535302F333E3F4A27767FF5D2A +:1005A00009EE83D32FDD5B887CE91A03E8ED23F0A5 +:1005B000A17FCDE27CE8ACDEDA25819EF65E72E0BA +:1005C00016ECE77DCBA2390E58575D6AA5C181F3C1 +:1005D0000DFE4846BE9826F0ED58C8E7E7A8F64B52 +:1005E000CBA1DF0E33EC5FF83E2DA0F8288F3EB094 +:1005F00050BA01E6DD21717E0B1FA5905D52EC49DA +:10060000C1FCE406711E5216FBFE8ABE4D32EAD3CF +:10061000BF6AEB9FA114C6E53B88F8F17BF9ECF6C5 +:10062000F923F82D5B3339DF5E207B26231DAD9740 +:10063000FADFAECDC4F79C1E6727B796635EF1352F +:10064000969672943FC3DEA7C0FB92B8B291B76B87 +:10065000300DE5E2F9649F25B02E13E33E8B3FA6F3 +:10066000B8E4F7B3DE3D8A7905EFEA7B6625A37C23 +:10067000C917E7FA855FF0CDF1AA5FD0C4CB93B874 +:100680005F309AAF3599E78BD52EE4E7106B453E86 +:10069000C21C3B3FB733A73CDFDB0153BC8E0D29A7 +:1006A000C8F7E6BCEF4F46BB9D2D0C94FB278FAEE1 +:1006B000CF30B7DE13BF5FE77AE2CAF0EFDA626DE0 +:1006C000F9DB5E6DF9FAE97F1E1F5FDE65F16DC52E +:1006D00075FF54E2F98DC12B989DD6E99282A877D7 +:1006E0004C7A394B9CDFE47978FF28ECA297A7334A +:1006F000AA4FDF6BDA8DF9EDAA1F5916F593DCCC02 +:1007000094E7E4F705A0BC1A92443E9F8B6225EC67 +:10071000A53BEC1C7ED0D600FDBCB4D843FB23DD4A +:10072000AA6357E11E2A37911E5231C6948474730E +:1007300048D09D7A1E57A5C30A85F9313F01865ED0 +:1007400088CF77F5F683E83F0E7ECA18C757A542D3 +:10075000F985622CC6DAA9FC98A0EF43624EC11F4E +:1007600028B49FDFB019089FF2CFE55D282730F647 +:10077000827EE1731B27D2FCD4FD03BBBAD0954E19 +:100780002E6BD1AFA2C349140B7D42A56FD480B0AC +:10079000DD18FCCF7CA273E23743D3F8FD09EFE507 +:1007A000737E32B4C929CE7BF178588E29DAAF0F27 +:1007B000FBCD8C8EC3CF13A58B32548575B0EE4F15 +:1007C00032F369D34A033FFB03C965AB3780E318B3 +:1007D000924D740E46DD37F6CEDFBE5D7B05AEB3BF +:1007E000E87BB4CE79363BAEB318C8BACE494F5F7A +:1007F0002AF5C7F78F9CE4F5E03EF94ECD2B3394F4 +:1008000038BA81EF1BF9F716EDF76EF8DE19F77DB0 +:10081000327C5F32FCFBA76CA6B06E0AF653E1890E +:10082000103F0FD362E68975C9E9FCBB7922DFB3BB +:100830003019DAA3BC29D6E663B0E95E13BFAF4333 +:100840009B7F718DB42E13F7D55C53E34004FAFB04 +:1008500099C0DB35BAC057783FDDCF16151DC6FDF0 +:1008600056630A29680F5DCBC2EB1199672B034FC2 +:1008700038C6123FF80BEE8B263930DE09E5D3FA85 +:100880009EC23BF269BF5CCC9C367CBE2A5DA8F35D +:1008900045FA403A8BD247C2BCA378BAAE8F12D584 +:1008A0007680DE834F550F024B9AE7137B7262EB23 +:1008B00002229A636A29443DE467ED41E21BD7387E +:1008C0001EA1BCA5336302AE2CC07FDD655FD0BD29 +:1008D00026CCBD783CEAF730DFB4ACB4FFBDF9AA52 +:1008E000FADEB07CDA4F0D9A7CDAD1F6953A6E33A7 +:1008F000E3F7D3CC1AD845F9B1CD0BAD5E3CE7D0C8 +:100900008CF99DE5143F223D0ECF01D33D2792493E +:10091000E85D979A77CBF7616FA387F4B7281F1725 +:1009200079E3BDA57CDEBD7778D47B4EB87EB798E1 +:10093000F17B52D47B4E96DBA95ECD2FEFDDC5FD5A +:1009400078BD2F8EA7F350A0BF91BEC052747C7E9D +:10095000F9DAFB55F04F4A8FE5436FD6737D739BF1 +:10096000CE5B8170DE86719EAF89EFDE94A5F59B2C +:10097000A8E544BFDE33CEC02D59E80F28F1E54A83 +:10098000403F4B0DDC6F07F4B51DCF4ED4B096A79A +:10099000F0FEC0B9ACE5D7BAB1445F01A2AF495F80 +:1009A000F07B0563F4B598D3579098924A5F51BA9B +:1009B0002A4ECC9F0AACC6F6BD8EBE8F9A504F1DF4 +:1009C00030125ED43CB8C47D1C379F137A3E1F970B +:1009D0002CD37CD68E349F4BA1F378FACA609C9EB0 +:1009E00047A3F70C85056D65317ADF6509B4E3B877 +:1009F00051BA5FCFED9161F396AD441F37DE2CF312 +:100A0000FC700B9757188FC884F1E78BF16FECE6F9 +:100A10007474A3CD4074377FA091F28558358F2B25 +:100A200078E17FDC0EF4117CEBC4770B5DA57A24B2 +:100A3000D985B5DAF8439D558D6FF8F5B81F6F5C11 +:100A4000A83F162FEFEBD8C62F30AFAD0EE314EA58 +:100A50007730EEE359D1F37FE3314E7158D8E9672F +:100A600081BE91FEDF485BB9FD0EA0DBF18F97944C +:100A7000A13F6776FAAAA73641F9996D13A9FC46FA +:100A8000FAAD77BD8BF53B8BA85C8D97B8A0BDD137 +:100A9000C8BF2FAEB8795E3E8C7BD82CFAC57D8559 +:100AA000765F52A0773EB4734F2928C37CC36AC1D6 +:100AB0001FCEDEC1F3DDAFBDCCC65338577AC86F49 +:100AC000549D24EABFCBFB7DBBF45FCA30EFB4BAC0 +:100AD00080DFE3F276D94F2762F9B0F4C5A291E244 +:100AE000DF938AA5F004804FB593B7AF2DFB511665 +:100AF000DAF1D555BC3CC95BD93D16EB75E7168DCF +:100B000074EEF317623F45CF35897DFAB2EF633A51 +:100B1000C7E437495E5CA27FFAC7FC5E22AB64473C +:100B2000FFA3DF97AFA09F74968FE7255699DA331E +:100B3000D1FEBD2E6028C7FC52BBA9F430EA1929AA +:100B4000D32BA7217E6799981EE512D0F9FF213A91 +:100B5000BFFC8BDC64242EAB96CE553A9AAFD2778D +:100B6000B5968E617FFE7356DA37F3D7D1E818C693 +:100B7000FF77E41375DFD2CA95687F09FB2DB1FFBB +:100B8000D1F800FEC5F3B9D83CFA685F6563D6D7E3 +:100B900058DC773DEABE1BC27518748374AE234FD0 +:100BA000F24EA4038DA3C87F757E39C0DB58D9F0FF +:100BB00079E19FA2EA65FCCF85766EB6A887EF7CC7 +:100BC000CC199B178CCFC6A0DC5FCFE7B3436AE19B +:100BD0007C43E8C5AA7DDCA4AEB75FBBDE8A247E79 +:100BE0009ED98DFE0BFCCE553AF1EBE6DD2CE4E60A +:100BF0004293FF4123ACE106C752A2879B58F045C0 +:100C0000D44F8C2901E79834B4BB820722F9E4CF92 +:100C1000A5BC00C077EA9838FD449D57223C9A460F +:100C2000E18789F34E84430C3F83A45FA9E7A3A225 +:100C3000EB4A588F2AFF5D06AD1FC829FC364EE1EE +:100C4000A7410A413958CB92286F61965722395EE5 +:100C5000CB4CC43F6B6BB8DC745AB99C57E5EB685E +:100C6000747DF5559CCFD4363071EE8ACF3F91AE6E +:100C70003258E47BF8AC3579B62EC3FD8AFA80276A +:100C8000B6DF6BADDCAF3B778CF01BB2C834B46F12 +:100C9000A3E5617EC4C834E41B89F745D55EE07ED8 +:100CA00044A7B897B5D6FBF134B4D79D359169C840 +:100CB0007F1E74F8E621DED4FBDC12F9CE8D63745E +:100CC000AA1FF192E82D110F6ADC2835C55F87E372 +:100CD0009C96062BB0F29134E1D767817CA44787BC +:100CE0003DBF12FD01C0DF2E5E44A30AAB005ED300 +:100CF0009D8100D2DB4DCC3F1BCFE2396B027AEEF7 +:100D0000E766B4FEB562FDB385DC3BB75D263F7D8B +:100D1000B5AFF83174A5371FD1B310ED3B1FC9B182 +:100D20003562FEE718C7D3392B977F2BDFFAA70A66 +:100D3000A05C367E8B2E768F01FC9B104AD2DC6342 +:100D40003069AF53539EDC97A5697F597F81A6BE5A +:100D5000343C51533FF54899A63C6D7086A6FDE59D +:100D6000EF5769CA5744E669DA7FEBD4024DF9CAF6 +:100D7000A15B34ED8F0BFB94057D83C5E978CFB77C +:100D8000A0CB0B4B34DFFD3679CE11A4CB651B799C +:100D90009E70254046739F430F97EF2DF03F8E576F +:100DA000BF82F05A017A2FE607AFDCA295FFF50368 +:100DB0009BD6234F4BCC5F58CD5AAAF06AB8C4FCDF +:100DC000856AFB621DD2E1E363449EC2E5EC727169 +:100DD000FFCAD7E2B58815FE97F06A746BF16AF620 +:100DE00068F16A29D6E2D5E6D5E23565BA16AF0EC6 +:100DF0009F16AFA9355ABCA6F9B578CDA8D3E23570 +:100E000033A0C5EB987A2D5E735AB478CD6BD5E2DA +:100E10002F3FB85A8BAF047CABFC6F6CD75A4DBBDD +:100E200028DEFDF5947732AEE71E4DBF2ADE83F053 +:100E30003F8EF716CA0BFF6BF10EDC86FCA089789B +:100E4000FF2001DF20373E44BE00F2FEDFF05937BD +:100E50005EE8D5FE91E5BDCA7FE2E56BBCFD381AC0 +:100E60005F1A264F843D39AA3C49B0273FC0EC1891 +:100E7000D2533692BFE566419F5FE2AB2BD09FF91C +:100E80006392931FC044A6C3BC3EC079C3381F24DD +:100E90004D227BFF5616D6D3FDBB98F1079DDE8E03 +:100EA00009C032DE9BE3A1E7522147970B7F80CF39 +:100EB00012B83886FB01F2D271DCEC417E0FF2DB16 +:100EC000A997741FC031F4872B8C9D407F383CCF8D +:100ED00098393D9C54F9838F795C71705B324B2A51 +:100EE00026BD514EA2BC9C253749244796FC9E3F07 +:100EF000D3B3B9FE99F8EC6855E1C6ED9299D91EC5 +:100F0000E2EBD9AC4FC83B16B08EA57EB8FFFA49CC +:100F10007E0FE8F31253A63BE93812E131C3C4E770 +:100F2000F5BC9E99107ECFB28007E1F243055813BD +:100F3000CF879F88F4B0E4F7EF16A03F49EEB05F8B +:100F400087F73C4FC0F1601EB36F6B91D0BF9AE141 +:100F50006E91D07F33ECFDFE7B243CC7172D33DE32 +:100F60000EFF100EAA9FAC58C7E3C54377703DFF34 +:100F7000A9EF32F2FF74B4062B83182792C120C365 +:100F80007C123D3FF73B339BFBBF32D920DD2FCA9C +:100F9000DE14FA99B897BD44E4979F11F19615BBFA +:100FA0004C0CF3154AF61D74627C6505E07210E581 +:100FB0009912A07B2C4AB6BEE1E4F77DEB1D785E6A +:100FC0004C95A3A3E35B6127E3F2B4018F23DE1703 +:100FD000795B0E97E31D6D3533313EA2CEE7FE36C9 +:100FE000DF4CA40F59F1529E17DE6FE388FBDEE061 +:100FF00082FAB8FDAB586B3465BDD54F9746AC6FE0 +:101000006B213AD38B7B781EC85E6B8FBFBFFFD638 +:101010006CA1479882CC9ECE840A8B4FE524F28740 +:101020003F326E0F1ADDD04F3C5FBB2B97C5FB776D +:10103000BBDAFC34DFF55220809D180B59D89C8C0C +:10104000F90378C611DE6FBDE608E6B3186C6BBD18 +:1010500061CFE87033BA95F3F17CA9215BCB97FEA1 +:10106000A1ED14C1A9A3AD8EC63B83BA1CFA773299 +:10107000B97FA7A36D31BDD7D578889E5EDF3AFED4 +:10108000A007EA8FC23FBC8FC6E8E2F362E5B9244D +:101090009F16093A40DF510ED0CFD1563DD1D99D90 +:1010A00039D6106EC23BDF197710EFD334008CE4D1 +:1010B000BF62DED171049C0C822F013DF971BF1912 +:1010C000B214F2C33AED0B084FFFD5FE54F81ACC18 +:1010D0008CEE7B31E458C97F72A9F3DC922DEC7C55 +:1010E00055CE97E7121FBD53C0E5F5AD3CFFE7E8CD +:1010F0005D8CF4EE3BEFE67EB03BC18EC77DC95AF6 +:10110000E1AF2246372ABF4EC31B37E0654F1B3085 +:101110009A22C61E6A33E1092766417FD5D8181E78 +:101120007B7C8A03DDE29BAA5DF3F1F9D0F4133DE9 +:10113000C8561E9EF9D5203ED1D78CE3DB5B5808FC +:10114000F54C8A89C2F88E7A28C3F8C9A23E39C004 +:10115000CB29A23EA58E97737C2F48D538B18478D1 +:10116000448ED539B710F9DE32C6CFB78AF3ED3BDE +:1011700004DF1D6375CEAFC6FADB18E5BDABF58F96 +:101180008BFA4CEBB1AEB1C897176ABFDF2AE0907B +:10119000613DD6338BE216DA7A35CE90663D7784A0 +:1011A000BE2FD1D63F2ABEB759CF0DCEC2FA42EDDF +:1011B000F80F8A7A8B95F343E6E7F794AAF53F1484 +:1011C000F5662B3FE7053C5953DF2DC6EF9042846F +:1011D0001FBA8B15F74F1AF75BEE6C6357E2FEE907 +:1011E000691BA27DF450DB05C2D339CCF39916DB21 +:1011F00057F65636E2B9EB73829F247B223EDF0816 +:10120000FC4EAD77DAF9B972D96D203A325A05BF82 +:1012100010FB30CA2FA4162F272EEE4FFE267A86FB +:101220000D761EF58B5CF8437ACEBE4BC702717CFF +:101230002BAB218905E2DABB973935E5F4DBB23413 +:10124000ED5D0B0B34F5D6F2899A7AE6CBA1FDB2AF +:1012500056D055524999A65E3DEFCE7A7234FAB314 +:10126000BE7086A6DDB9620FFD8EC7C9B9EAEF7DF3 +:10127000784DC817D6DA0A3250EE3CDB361D956C35 +:10128000F63CEC273CA2F49C83E7F93E87F151A899 +:10129000FFC7361FBDDF03F5A0B9B02761BF79A036 +:1012A000FDAE363B959F6873D373479B879E8FB780 +:1012B0001553FDD6362F951F83FEF1F928F483EFE1 +:1012C0001F69ABA1F2A6363F951F6EABA3F2836DEB +:1012D000017AFEB0AD9EDE77B7B550F981B6567A89 +:1012E000DEDF16A467475B17D5170BF9F69C382F7E +:1012F000F85C253FFF9B88C7C939C28F26E2F8B644 +:10130000581C7F720EC6F1FB229A7BD671DDD49FEA +:1013100099AF3FB1BF2AD1DF4436D86EE1FB98E2E6 +:101320007FE3FABDF75980DEC7B4703CE4F70F5194 +:101330007D663DC74595982F73055976053FEE8923 +:10134000EDCE488355161E0F257F0073C33A2BC47C +:101350003D344476211DCE4B99CEE5A68AD7E8BA16 +:101360001D7C9EB8FE91E6FB6D315FB9BC8FDF330B +:1013700051D31346B24FF2B5D03D13A63A7F187F32 +:1013800047C2E50FD0B9F78917E68071037CE6C242 +:1013900055CC03CFEC06ADDD93B5AC4C635FC817FD +:1013A0001E629EA9D06F89D63E492A5CABF9CE94C5 +:1013B0007D8FA6DEE0BA4F53BF644DFE7A37C2730D +:1013C0000CA3388971633BC3D0DEF2DE4D34AF7BB2 +:1013D000C53ACE481E3A371BDCA7C6C9B97EFE8C7B +:1013E000902BCCB491F6C378072F16A50475281757 +:1013F0003EFFA714E2474F3FA10BA11F74020BE968 +:1014000070FF4F02750FEB27E34DB5325D5D226330 +:10141000B99479642C4F6543649F807E7E27D20BFC +:10142000E8E74F98314E97137886E70F85496E1697 +:10143000097C16A9F6C81625D13F7A770EF93FB474 +:10144000E7863A859EDEEEA8C8C0F8E49951F2BB63 +:101450006CEE1933F0F7AC6C99D3E9A9BE7FD0A339 +:101460001BF13CECC61CD58FC4E97E0210B9A0FB71 +:101470008D388FD3E5BF4A4773AFA97088E8FF8CDA +:10148000E4732F46B8BE25733A1CC8A4752902AE72 +:10149000CABE4AF762809FF2CE586F90C5C679BA2D +:1014A000CD37435162E522919FB8B76DFE8CEAB803 +:1014B000F7FD027FC56CB006E5537189CE1BA29E75 +:1014C000DD1AFE652EECF1E1796EA58C7991BD4DAA +:1014D000603DF7A1AC56FE2253BE8972E80AE601D0 +:1014E000BBC06A0D33CCCFE98FEE6FA6F99DA3AFD9 +:1014F000ECD529742F5F5694EFA14CC4DF351A4404 +:10150000FAF9AA57CFD775485B5F6CE579342B8A17 +:101510000D218F84E1ED1EBA7F4ED9293154FD95FE +:10152000BFCC2238B0972C447F962D53E8EAEAEBE3 +:10153000944008E9E374D8F3926EACA04568D738BC +:10154000C9B01BF5B1F108175C506131C175B958CC +:10155000EFDEB6C504A77704BE3A7312E6C3BC3EFD +:10156000BC9F7145AFEAFFD0AEF3C1F2AAEBF13EEA +:10157000BB8E4159E84A5A786ED00F4EC1DF883B86 +:101580001D8179C934CF7710FFF2960AFA9D231096 +:1015900020B4BEC627C0DECF277E5443727B9A8E0E +:1015A000F24413E9EAD7828F2DCEE1FE3C9BFBAAE1 +:1015B00019F87B6BB1F24CA2CF6775DCCF1AD471EE +:1015C000FB52CDA300C5C183765D41AEEA67EC64F2 +:1015D000F3505E3B74947F27EF4AA27380B243A11D +:1015E0007CDF4E6BB57D35F6635728BE31479E399B +:1015F000887AB3D1A19B8A7AF7E1DDF70C629E87E6 +:101600009CA330F41775DA15AE7764EB282F4A7176 +:10161000549B301E52643D5189F03CB8EBFBE4DF33 +:1016200090BF277235843F492F50D6C95AA8FF6012 +:10163000B622EECDF0D596A60B57BE07ED9F9A4F7A +:10164000D18F72D87ECE8CFA8AC7BA82FC6969B90A +:10165000DC2ED463DC0BCA4FAC3BE740BEF5D6AE04 +:10166000F5CE7CD49F430AE920C57FEEC8A2F3DD06 +:10167000BB0C74FE5C856B5E50D1C4CF725AB565ED +:1016800063421C4D9F70FE2709C7A7FD5EC7C2714C +:10169000EBD1BBB9BDC65C56B277D27225EEE7116D +:1016A000656B2EBF7770AF3E98E505F81CDAB52262 +:1016B0000FD775FE9500E5DB8EA6EF7F94E311F85A +:1016C0000B9A75748F69D88CF9B74FB5B134D4EFD4 +:1016D0004C2185F29FF7087E5668E5F4FFFB5C4ECF +:1016E000E789CFC21EBEEF94E7924216C49BBDAFFE +:1016F0002C087432E9F5B9CC03F2AFD0EE23FF61C8 +:1017000061AB210DE3F8737E62253A39674D223FC4 +:10171000A1D29AE4C5F71DBB2B8AE3CF3585DAEC5D +:1017200069981FB3BBCD94867C2A340A7F1DEBD009 +:1017300051DEB047C7F3DABE25E6F5AD5C0BBF4717 +:101740003997F3992795E0029CE793804FCC573E59 +:10175000B891EBC36BDB4D348FB56F8D25BD6A340B +:10176000B83DDDE64EC37BD8776FD465A1FFA8B244 +:10177000BB7003DE47B0D6C6EF6395532692BF9386 +:10178000FD42CF507FEF489EE15D1AC7DFE5949997 +:10179000C54857B21CCC42BF887F67D5F598B708BB +:1017A000F8DB86E5BADC89D7635EE35E5B300BF37A +:1017B0001C03B95378392DB80DF31CEB73CB783972 +:1017C000279885BFE7D4925BC1BF1F17DC86E5D69B +:1017D000DC19BC1E7D4FC03B83B9575D1F84F13AB5 +:1017E0000CDE7A64C83F86F997C0FCFBC4F33E0167 +:1017F00017B5FE057C0F70DE2F9E89F52F89EFFA55 +:1018000047A97F55D40F8CD2FF6BE2BBF028DF1FB6 +:1018100012DF1D1EE5FB37C5774746A9FFB9A87F34 +:101820007B94FE7F29BE1B1CE5FB5F89EF7E3DCAD2 +:10183000F7BF11DFBD3F4AFD87A2FE5F13FA3F2AC3 +:10184000DA47C4FB02DBC60FC3407705C047902FC1 +:1018500015DB363A719FEFEE2A27FAEFA8E0F11D6B +:1018600095DE0BF07794A0FECB5C7E3FE89782FF7D +:101870006E17FD031D3E8C74B7F61D99F25D3A7428 +:10188000DE5321E4A31B74A40FAC7D8BDBE76BBBA1 +:101890009550FC3988ED09F35F2FE6D729E6DB9BED +:1018A000CBF3A98D6E775A6DBC1FC9AE2D637A1428 +:1018B000F25DE0DF943F5BDC5DD5550CE5314E1DFC +:1018C00069204AA3298CF72228362117ECE53DC56B +:1018D000383FAB42E7C1158712DE8BDFBBCB49BF78 +:1018E00053E7D76955E85E2CD9C6E5C09C9FCCB4B8 +:1018F000A39ED5C902833EFCDEAD90FE7EB0ABCC8C +:101900008E7CCF605B66C7FDBBD6C3F77F75537116 +:1019100012F26BF9411DF1EFC376BEDF77BA75E4C1 +:10192000B700B942E74A805F7B51468C67E1763A5F +:10193000A7F0D04B8BB95F8FD94A2BE8DC861A0F02 +:10194000969438FDFF04C207CF4B0839A2A07C81D2 +:10195000E793E5E2BC4190FB9FF214E61E13776E1D +:10196000F244AECCCF63280823E84BAEA5FB8172CE +:10197000D7291AFF7BF65DDAB221416E280972651C +:101980006C17F0C938B9931FB46BCAEFE50ABF9959 +:101990009779517F9DF3938DC40FCFA17C9346E738 +:1019A0007B51FE2BF8F193E2BE9B2783FCBCEEC17A +:1019B0008D653F477CAFEDD6D1FDCE97CA47B7E7DF +:1019C0003282C3B800C81DD467149685F6D237C1D9 +:1019D000619CDEEFA4FB0BBE011EE31E2D7722BF30 +:1019E0001D175048EE0C931BDF00AFE725EFFB01FE +:1019F000C4A32389EBD576BEEECE7417BFF7479C00 +:101A0000039485BE76BFF0832B29733CF8531C9D4D +:101A10008E162AAF97BC19D742FB07A4801DCB476F +:101A20009C495CEEE424111DEE455D86EE2FCCF45E +:101A3000A37FA42F6450EF030CE3FFEDC33C19F523 +:101A4000BE4137E967A2FCE0F5D5D85EB14F4295BB +:101A5000B328AFE761FD95D0DEC0A2EDF15CD3B352 +:101A60008775A2BFCD0FA3BEBA2F8969EE5BDC8755 +:101A70007E742A6F7D18EF4F84F1AE95C1069BFEF0 +:101A8000C4130F5BAF88CD676AE8A987DB295F9530 +:101A9000DB250EC6EFC33EED8924E37601FBC4933C +:101AA0008776F9AE13E99ADF3F13ED5344FBA68125 +:101AB000A1A6E73CD4BE88DAF70F2597D0FE1AAA74 +:101AC000886F9F2CECFDB8F6255FD7BE589DCF736D +:101AD000BFBAB184B72FC3F6673C9174CA3D499829 +:101AE0004FEAF0FEA77F5DFF1345FBD3E15F51FB9B +:101AF000332C923E399FBEBB3A0FE8F8ECDBBFAA0D +:101B000010EB4E473D19B8A20FDF277B98B877AD91 +:101B100085F4E73E538F1DF535B3BEC78F7CB710F4 +:101B2000EF4F9A1E7BCECA2BE47A55C2FB3E134B75 +:101B3000AD457A6CD591FDD2671A2C2B417DFA65A3 +:101B40002B6B87317479EBBCC807FB236BBD25D0A9 +:101B50006E67F64CB22BF6195AFAE89CED622B9D93 +:101B600003DD69EFB1E3FE313B7AEC184790EFE615 +:101B7000FA93B2C41A780AE929BCB67879DCFE9DDA +:101B8000EAE1BF23D3FD867523DA01DD7A6FCF78D2 +:101B9000D4B36D0AE5812B4B06E6D1B9BD1FEB1816 +:101BA000F177585715943B1B75742F7C9B67C9328E +:101BB000842B53FCFE2AF82E374D91F01CC4FD8A6D +:101BC000DF84F10BA3D0DB767AF9EFAEAAE36EC81F +:101BD000E3F269431EBF1FAA7BF173C56FC2773B57 +:101BE0005BD7F6E178E6092686F95E3BB34F76E3EC +:101BF000B9CDC7DD60F1021CAC0D3AFA5D94C76B3C +:101C0000A14D0AFA330C1A7FC5F3521FB50F36EAFD +:101C1000C84EB0961834FE8DD4069D0FFD8E3B3C09 +:101C2000817B71DE53DF51AEC5F1DCE3143BCAA703 +:101C300007DDBF36E9609EC9E5DA7EED33B5FD38D4 +:101C4000ABB5F5AE5A6D7DFA426DBDFB364382BF32 +:101C5000465BBE888208E1083CC00A72288957B1F9 +:101C600024EB79FA5DAEEEC0F69EF1B01EA32558C6 +:101C7000FA26CC37696212D9FB0FBC91849B0FF80E +:101C80000F23BEF3C06446F9A78772BEEF46799A68 +:101C9000089F9DD9065AAFB510E0998FF6FA29FA38 +:101CA000FD2C2B8B6B978FF0F16DCF9BC6CBEE0A83 +:101CB000F4CF31E283CFABFEE31BF8B9A69DADDCD8 +:101CC0002FFD601DCFCFA31554E0FEE6ED93F1F795 +:101CD000BCA6A0DFBEEB0ECC3B4C846B06E6E3C893 +:101CE00031FA58AF9E23C1538C159C2DE3BE3BEEB9 +:101CF000E174F2933C2EFFF7897B0FA2ED711FA6D2 +:101D0000336ECA427FAFE6A9FE079E97BF598DC7C3 +:101D100088325E1788E57D879DD7E27EDABCD05990 +:101D200086FBE901A197A5641B7C1360BE8F1C3163 +:101D300004A5CBA0ACB0C37A90E7FB9C7C5CC35BF2 +:101D400049413CD7F488BB9CCE497D24E6F542A5A9 +:101D5000F7BD5ADA8F0AE5393DE2F29ACBB8BE8177 +:101D6000774A33FA4954502D0ED696919DFA88CF72 +:101D70006BC6FDFA48B6D78C79C2E64CC58EFBD847 +:101D8000E956E8BEAA474C013BEA2D4E1080F83BCD +:101D90006D869C9EB9743E0860A8ABE0210126F2D6 +:101DA000E9309F2D55C06BA77B991DCF91BB0AF7DA +:101DB000FF1DFAD553B1BF64FE1DC2C921E0743CBA +:101DC000CFC3F38345FFA9CB5EA0F6F8D75911D74F +:101DD0009F97D397612E0BD1EF8D89F1D57EA2FD10 +:101DE000331FF9EDD7FF9CC3AD3D87DFD36358C3E5 +:101DF000C80E7BA132B0F720C2273389ECEC2C77D8 +:101E00005615D247D6916D0BF03CC0FA9F73F96915 +:101E100058CEE34D590A335D85EB4E0BD8118E89B0 +:101E2000FB30F370CF7C2436152F89FB3253615D74 +:101E3000B273F8FECC74BBAA8AA68CB04F13F641DD +:101E4000E691A1EF61FF89FB7587E56829C2E5FF8F +:101E5000029F8BFAF4008000000000001F8B080036 +:101E600000000000000BD57D0B7C94C5D5F73C7BB2 +:101E7000CB26D9249B04424248D8CD8D402E6CC23B +:101E8000C588A84B48102DE2227235E2131220407B +:101E90000201F46B6CA9590C372DD6F0360A5AD4CE +:101EA0008D058A8A362820566C978B8AD56A5AF512 +:101EB0002D554B13A18A728BA17D3FDAFAB6DFFC58 +:101EC000CFCC24FB2C89D27E6F7FBFEF4B7F7598E0 +:101ED000E79967E6CC3967CE9CDBCC3266632E3B54 +:101EE000A3BF7F98F1DFAFAFAFD53AEE1F369A317F +:101EF0007F8AC5B3C3C5585AE87B37FEFBF708D4C1 +:101F0000356672FD2393B151AE78C606E279BDCB3A +:101F100057C0D81E9B73A26300635D2B98E729FE10 +:101F20007DE94B9BE6BEC5EBFF95E67046F056A9F2 +:101F3000C79ADBF3F97376401F86F6DB2CFA93D150 +:101F4000FCFDB6E383985F632C229AD5B7393854E9 +:101F500026A6A3FC07FEAEC738561A6794CBC4D892 +:101F600018C678170153F2BF5EB60D1992E7F4F068 +:101F7000FE0229ED76DE6F9BC59967E1F59CA1CD48 +:101F80000F59AFC53C388CE368DA5E56C2D8B34708 +:101F9000F9B883517DE4A1320B7F1FD5F3DE8FF7B3 +:101FA0007B4C26597FF4A1B2218C0D39DAB6C6E1FB +:101FB000E4F31FDAFA909DE32DF257E2FD045EF799 +:101FC00067012FB5433BF8FC0EA72FA1F937FD2E73 +:101FD0008245F0760566CF56D4D947916C07AFEFAE +:101FE000DA377EB68BB76B8A19EBD2F3192B73698C +:101FF00034FF525986CFCB6CF3E81EC7E5CFC74BF1 +:10200000BC31E639DECAE95BF0631B7B80BFCC05DF +:10201000DCA0576B64E029D0B7790B63498C553B42 +:1020200005CDABF73F907E88972FC74CBBCDC5F150 +:10203000541D53960478522F31A62772BA35DA9977 +:10204000CE71953AE0058D71F8860C383A8139C029 +:1020500037ED6B9C28EBA398AEF807F4BF6461FAE8 +:1020600028F4E7A5FEF0674F02178ABFB5093A5B6F +:10207000C3E1F1735CEF00773AA33AB542FE8FE417 +:10208000326F47AEEC27037CCA66B7F1F12A8107AD +:10209000DE8F8DD3C45ACC4B872518D147FB8512D0 +:1020A0005F66BB23681EC94BE7EBC7A95F87E56C7A +:1020B00087BDB79D3D60217CB05A16C8D6084FFE3B +:1020C00008D4E312A8CEBC5ED78024F03F23E4A658 +:1020D0005AD8D1083E2E712F5F3F292C48E5E31CCA +:1020E0003D8E4C344A8BFF349AE111031F3FC5D813 +:1020F000E450BE56E5C57413CD23ABC134F014C70C +:102100004FDE914882C3B2910522F96059A007A71A +:102110005BD62616B0B8D1CE36F05422BE73D17736 +:102120002EE634311AAF6D04D6D5D6D71D9B581C78 +:10213000D1F74E1F1F6F6B14AB01BED4788CAD214D +:102140007C6C768971B7353A898EEAFD90DAC36185 +:10215000744C30D051B54BBD3498E8D9DB6F80FA60 +:102160004D6DD84BFC907A295DF289EB1BFACFE8D4 +:10217000A7FF64FABEFFFE87D0F88F07DF8F9FCAE4 +:1021800051F1A3AEBDF13E5E465A9B7D9E3EF09C52 +:102190007A57883CE3FF1F7980D7737BEB0A2F9136 +:1021A00056EF80691CFF91779B3CADBCBFAB8E1B8B +:1021B000DB4D767F108FF5D8DB3E38603ADAD78971 +:1021C000F6D79C36B6F74DD817D65EC077FD256397 +:1021D000BB70FA84C3CBE11A382304AE89F608C376 +:1021E000F7B32B2F836BE0AC10B86E4836B6D7D759 +:1021F000F40DD7B77223BE162ED5EE96922B6B1721 +:102200003E8FE99323FAC1BB683F6BF695F57B7B64 +:10221000CDD7B7BBB3217C1CBFDCAFF8DAE2EB381B +:1022200011FFE04B20B1C1E48D8C65CCC9BA18D642 +:10223000D1C9A12E6A97C09CB49EF9C2D7B0AEDEB8 +:10224000C33F53F856E0F69D738D01FEBD150FF3A5 +:10225000A66572BF6253788F57A3735FC1AD0597B0 +:10226000F31F63F7115CAF68BACE689FB57B76F059 +:10227000F59D97CAEC2909FC757220E3D618C6BEF5 +:10228000EA91D75CD470384748DC3D37B86D653C7F +:10229000ADF34002E0F967C7B5BBBD66F798DEF65F +:1022A000E1ED7ADB0B3CD96C6D2B0067579DC38346 +:1022B000FDE17DBCE2DFFD786644D0CCF175C1EA7A +:1022C000D8A87139733C7ADEEB03391EDE8BD5E377 +:1022D000D1FFEC5937AE475D3B9CE85AC9E1BB5092 +:1022E000D9311678F546EB03DDBCDF5ABB3E3489A5 +:1022F0004FF15C9A3E2C0EF8F525125EF93F0A7CF0 +:102300007DC22FE029D304FE13E3F474F453666A0C +:102310007FC2876796F6B1F88E3907127CE76C5C4E +:10232000DEF5B1FE151E4A653F87AC9EAFBAF8FCDC +:102330000E6D8EF3347178AB1367CD5BCE5F2D30AD +:10234000F992826603DCF904B7A372680AE0B64A20 +:10235000B8ED0325DEBD595F077713C6C3BEF63D52 +:102360002DB0C32D6889FA4BFEF8C003BC1E61BABC +:10237000F83EE4475781C9C3F708B68DEB1776BE20 +:10238000AFBC2BF1FD38577FEC09F47C239E274727 +:1023900089EF931F31059AF8F7BED297894E3F5EB9 +:1023A000E6F098F95895CC6503DF5631AF0DF0FF94 +:1023B00071C2DF5EEDE0F3BBC9AD97833E77269A2D +:1023C000D2DF2738F4BC699CDFD87881FF6FE20741 +:1023D000C63699D858C66E95FAC10289C7E9CC6B42 +:1023E000C53833986EC5B8BF396FF332CE1FBFE121 +:1023F000B8621CDE59CC4FCFE7B00095B7B320B51B +:10240000BF837550FDD7D185690D1CBE695B86659C +:10241000633D86E0FD76C92F770E10FCF2D920E0EF +:10242000BD65E015F1EF344DE06FB05BAF76D37A68 +:10243000750DF00026E7C421BE9890F5533650F094 +:102440009FC599FD75EBA7BD3BB6908D2479E048FB +:10245000E178B84192F206EFD229982F2408D6EB02 +:102460002D72BD969B1D6C00A74BBBCB1C88E0B0AA +:102470004C9EB02219F37D630DFBD5284EBF372645 +:10248000985913B5F4D27753657F53874CFA1CFAE9 +:10249000C9DB2C386034FFAEFC927E348EE367AA31 +:1024A00079F75AAE71B3C943AC9F7484C8B51B07A2 +:1024B000ECB130AEBFDC94657C3E259FD743E4EEA3 +:1024C0005466E97DCFE97F08F881DC61CD66F0EFE5 +:1024D0004677CC804FF37875041B21EC034E8D902A +:1024E000F974DBFF6EBBC0BF7BC5AD3F04BAAC8CDB +:1024F0003F3F8FF40E8B98CFB277CCA4577ED2C8D3 +:10250000C079EC14D70FBD398C7DCAF50BD44F3789 +:102510002653F905D707509E6DCCA5F7E71B3D5410 +:10252000FFC4EDDB8A7EE76FFCD2827D6943A4C2E3 +:10253000B7806395E4BB0D6963B7FC95E375C3DBB6 +:102540007C6170786ADA9A2771358BAD4AFBE43E7C +:10255000E8CFAB9ED63C68B7F4A0D7E6E0F02C38C5 +:10256000AAAF079917BDDD311562A20EFA2BD71B52 +:10257000EEB7FA7662BC311F9C4AD27903EFC1CE26 +:10258000D71379FBCF1A4B08AECF1BBD04D799C622 +:10259000C954FECDEDDB8DF65EF6A50DED6FDEDDEB +:1025A0006949E5EDCBBD9A17EBF13A2F0B04383CA6 +:1025B0005BAD42BE6FE5F21DEB7342C1AD8FDF052F +:1025C00071E1D6F7830F6724549527F2E7534B2A1E +:1025D0002D6837EB2B2ED3DCBD7CF8CDEB50E0A380 +:1025E0004ED2E5DCCF35C2D3B9FD79B75CC3FBFB76 +:1025F000F931333373B8BA2F9908AEEEE35101289D +:10260000ADAADDCA7D66D22757A6D902C0DFCA7D32 +:102610007983A04F9DE1746339BDE39D79EEDB2E94 +:102620003D448E9E4968FBAF0F21A77E2FE414D74F +:10263000373F7D0C726CC8600FE87EDECAF57220F1 +:102640009AD547631F5B6693EB8BCB19D4CF44318C +:10265000D247C73E9F5A8AF582F15CB65E3994F341 +:10266000FC968CEFBA7AC7DBD5B6E0C3C778FD5CC1 +:10267000C0E4B7F27DE61C6B3BFF33C8D1ED0E0F13 +:10268000EC830D1A8707FBE88EC154CFD52C510D72 +:10269000C4CF015AAFB99ACBD2C0E54FED0B8F0E24 +:1026A000063FBDC27150C2DFBFB2399AE4D32B5688 +:1026B000CF8906F4F7B8E8EF273FB8E79303281F60 +:1026C000AC2BBE879717DD09D44FF57F2C1E81EF09 +:1026D000F93ECD52787FCFBEA40523F9FA2C683994 +:1026E000745F0A876FE4B64ED3605E166DD79A505A +:1026F000E6A5DD74CCCCDFFFC5ED1276EB6EB73905 +:1027000015CB6A70E0C3EB69FF36EEEBF92D5F96EF +:10271000C2BC54FBFB08ADED8B56D8C3E9C78B7523 +:10272000C25F33C1B1EFE0F4F76E679807D71C00C2 +:1027300077A5CD43FB49C0DF0A3A9FD3733D0F60B5 +:102740004DFBFC8F82BEE7F4240FF697FD267FEC4D +:1027500038B43F61A179BEB4FDD7B1565E8FDB6B53 +:102760006591FC7D5D51D724B4AF4B73911D9EF6EE +:10277000C40D93819F657BF7B5523FB5768F867503 +:10278000B6EFE2EBA9B0876E649E6CF0DD5E51FFA0 +:102790007E99D7037EAB69FDB3A8B7FBA8EE33FBE8 +:1027A000DD16B4AF127ACE16B98FB18E429277C4CD +:1027B000CAAE5E7A7D9FBFC6FBAD6E7F4ABDA37772 +:1027C000FFE3FBD6900CFE3EC526BF774E4FF7FDCC +:1027D00013FB964DEE43AABF2D36E68FE4FDA4F120 +:1027E000E71AF6559BD86F7770F9027E51FB2D1FC3 +:1027F000371FE3F2EFBD9093A97C732DE2F349DD1F +:102800001211A03DFD0AC7577AD2F22821CF94FEBB +:10281000313BB1E9D50E8ED73FC5EA2519BCDD02A3 +:10282000B95F338B2719F33B19EBBD3A83F6BFAE83 +:1028300074CC81EF87D7A2BECCCCF5A7CC10FDC954 +:102840007E65FB61449C7722BEBFD2F6E3A3FA9675 +:10285000BFE3BB4B48FEBE2AE5EFAA3F9B5811AF32 +:10286000AF7A3882E409ED697DE0E555BEDE752E6C +:102870005F7E01BF012FAFFD538799EC8FA3A6DACE +:10288000D7F97E4A4367E03F5D4D71A3A9EE0599F4 +:10289000AFFB93A94FFB50959C4E95A093F72BA3AC +:1028A000BFE1FAAF9C36EADF917045F335F7335F4D +:1028B00073AC98EF41CC97D36ED597C5242F0F5E9C +:1028C000E13CD322BC2B015FF83C38DC0DA047383B +:1028D000DC3DFCDD756570DFAD31BF09EBEC4B5BBA +:1028E00000EBEC200713EBF6E0E2FC00D6F37E9B56 +:1028F000A8FB636DA47F1E8C617EC88F83D3920278 +:102900007EECE7680FF9309089F791F2FB3949F4D2 +:10291000FDE008CEFFBCCE6E8F92FDD7BF5580F78D +:102920006B523D1C02AEDF063666907E6B26BFE121 +:102930007129AF5BE283B79BF9F3962F7318C63901 +:10294000CE82A9CBD1AE268AE4504BBC372581E399 +:1029500071FFDFCDB42FB414F1BA83E434F9775AA0 +:10296000A67953E2797DAEA44B4B6B60C723E86F29 +:102970005AAEC7CFC7196C66F5D4CE2DFAF9D02A56 +:10298000BEFB9DA40B5FC7B4CE8F66CCDF03FCEB10 +:1029900053A32DF08B708CA7681CFEC7AAB319C96E +:1029A0004BE9F79A2D6930B7970FBCF6B1D06BC5DC +:1029B000DF9C053B22218F67D444925FEA78CD7D6E +:1029C000312E3EDE0CDD1C8C80FE775BB9C1EF74CE +:1029D00034C34BE372C342DA09C12AE0F1E75D7602 +:1029E00006B9DC1F3DEBDA26249E0AE1871A9B908C +:1029F0001FA7A53EF4728CFE0BF0CDF20337269E86 +:102A00000AD1F7AA1794E7407F56E37D13DF34819C +:102A10004E2369BDFA4DE08FB648A2FFE45BED445A +:102A2000EF6E87E929F825EF94F2AA0986307FDE58 +:102A3000B42F22701F7FB63C223813F28AD3FFE9ED +:102A40009DA0EBAB9144FF5A9BE0A7DA9FE5117F75 +:102A5000EDB779DDEBD0FFCF2388EEB5B1AE387A94 +:102A6000FFCB4426F98FF486DAA8604E3CC7E7C650 +:102A700068FD43E08DF31DF9836B6DE2F909C957D9 +:102A800027781F80C35F1F43FCC8645DFF6E22D997 +:102A9000535C1F25FED51FCAA3BA6EF3A62CC0FA3D +:102AA00058194DF09D90FEB413B5F1C4DF150F2DEC +:102AB0007D9B717A9EF0EDBC3F87B73B71D0EAC138 +:102AC000BEF471833968E3743DBFFAE4D8ADBCDE6F +:102AD00071DF47E97A881FADE2BEBA29F8AE62C954 +:102AE000EAA9D82FFBC377456D0497B9BD74B266C8 +:102AF0007AFF04FAB933F5FF8D792ECFEF5808B974 +:102B000077DED6FE04EC830FE3F4BFE2FD85973F4A +:102B1000DB49F2D0D29503FD7C9985F301F852EEA2 +:102B20009FCB255F063275963986F047FA78747E1A +:102B3000BB907BABAF4CCE7F7170C77E8D8FB334B3 +:102B4000EAE0322ACD8142F473460BC66A99C01F6F +:102B5000D7E3787F679DC158D0419776D3D25DC6C1 +:102B600079E10F7E95A5F807FF6E699B99FC2A1CF9 +:102B7000421BE05F0A4FAF219E20E40AEFE7295A8B +:102B8000878E8FE77D97E37FC9D3C38BA14F2E8DAF +:102B90003FF0836BA81DFF4EF1B9F9F2BA9ACFE569 +:102BA000F088F99D957C7E96493938DBD66387435A +:102BB0000F3AFFDC2003DF9C7F7A38D5BFD0BAB450 +:102BC000280ED779298F98A76DEC341810DEB6B18E +:102BD000D0671F91CF9726B68D85FC51F288D9DB3F +:102BE0000AC9AECE6D2B843DA9E419F3B5E5D0F347 +:102BF000405B0EBEDF6F127E0AFAC3BC9F4D6D258F +:102C00003CD8C57A5CF26C1EE1458D134EBFF0F9DD +:102C10005E9F29FCDC1CDE3B7DBCFDB0AD36C3FBFA +:102C2000E10163FD06D97E68185D069BBB0E454039 +:102C3000DEFF98D17A0D1F77AAFCEE99677AE860DB +:102C400096F6227329FABB84BE6D05BE7FD783EF4B +:102C5000BB52B93C5D8A3966F4CE7F7F919E0AB93A +:102C60007FDE24FCD4FBE3793D1F7A8EC0A7AA2B1C +:102C70003C86F3D17DBF5B988A78CA3D9926A954DA +:102C80007A0681DF9A202FB9BC68B20A7C7CD158C1 +:102C900033EA9405F6687D4AB5A5773E0BB716D999 +:102CA000B15E166D2BB2CF0FB1779A768D3AE6E210 +:102CB0007439BBCB426E83264BE007D0A39B769939 +:102CC000DBFC8CDEDBBDBCFD59C7E177D06EE1B625 +:102CD000F862E8BDEAFB455BEF4EA90EC177DE2E38 +:102CE00023FE0BDA8C75F8A343EB4DD005C7FCF33C +:102CF000DF15058DF551C78CF5CFDEBF6B26D8F8F3 +:102D0000A512C1EFA7033101C4A96A3E9A740CFB56 +:102D1000DAE9FD2FC5823E4B7F5FFD3AEC96455BBD +:102D20008D7CC6E9A641AFF7EFD4883F1607C2D71E +:102D30009D5CEF97ADC735CAAF991BCA27E1F43C3C +:102D4000C3DA667A393FD536AC1C857848CD14CEC7 +:102D5000B81C9EABDB36DB1037081FAFBF75CF1C2E +:102D60005E17FC559525E2DDB8865276124EDF4D92 +:102D7000BF9E84F556F97D8DF6FFCA17871D85FC29 +:102D8000EEDC33E7262A674E263C28FFD9A2835A79 +:102D90003086D79D25AE031DFCBB05018DF687F956 +:102DA0006B237AE510FF7FF5A630385A42DE73F8C0 +:102DB000171D38F4178DF75FB3CDF8DD628E2FC87D +:102DC000FD25DBFF1111FA5CD97DE30EB69A31EFD8 +:102DD000050A7EFF750CF31221482E3AA4BE720A32 +:102DE000152EEFA3137C8732F9FCC7B588EFB8C066 +:102DF000AAC47CEB1C3617E65B6767C1680EC7B1D7 +:102E0000189BD7C99F5FDC1A43FEA985115C2F2C44 +:102E1000A6924516E33B0FEDD39FBE6B267DA50E14 +:102E200063A39F2735B27FEAE06C44FDC7A2BE983A +:102E300005691EE0176FE8FC02C63A6B167653ADC3 +:102E4000257808F858C23A84DDC3E9E80D89C7D56A +:102E5000F2791E4F803E64FC7E396BA3F6CB0FFCEB +:102E60002322F479889F94EC3965579A6DCC0BFD39 +:102E7000D87C6F14EDF75C1047813FD769DE47EDD2 +:102E80006694625EFECD42FF99DB2AF60BAE9FE6AA +:102E9000003F2D9B877BA0A7CCE57A7624F488C5DC +:102EA00051D4AE259E917FA5654E8ED0B3FFFE62B4 +:102EB00010E3743DAC917FA4A548F4DBF2E0707A96 +:102EC0000F79A8D13811A4B7B44C53EFD3484FFAB7 +:102ED00010A0A540CF95CF07BAE8F960B33707FA3D +:102EE0003AFB6124D9FB4AAFFD4982FE0FECFB6A35 +:102EF000BE4A0F663557A6FFED90FB5DD76611FF02 +:102F00003DA5F95E3785E8A5CE2C21E7C7967A77EF +:102F1000CA761407A8364D7BE07A0E4FF523265764 +:102F200093BB17EFCCEBCDC1FC4F6D8E2C069F8D64 +:102F30002D15FE9E1345426E478F66DE002F5364AB +:102F4000BF29592643991CC5F98FF773AA5CF887E6 +:102F50006346FBC8CFC6753692DFE1F3C896FD54D1 +:102F6000DB7CBFBCB60F787AF8A04CE819A756688E +:102F70004F09B8385D797DEC7F44927FEE94DC5741 +:102F800014FE39DF8CA17D5AC549259F6C06FDB121 +:102F90009F2D1676502F9F18F960AE26F0CA1E148A +:102FA000FA694BBCA82B3EE0F60EFB2BF8A49C1153 +:102FB000DEFBB37BD43C5B5AC57B4EEF6BB3C65C88 +:102FC0006EF7287A334B600CECC6FEE83DBF247EDA +:102FD000AC66A2B8B51F716BEC758497FB2D81FBB5 +:102FE000381C432C02FF6916C15F5C2AFBA38AA927 +:102FF000BDD7C6EB953F5CC4BCBC7D652A237F1062 +:103000006FCFE2D09E7763867F8497F8AE324EF41E +:103010005B3988919D407F5C5E65A1CCA07EBDA69A +:1030200004F17D6C317DEF3789EFBD165E0ECD1456 +:10303000FA7CD7BA88C05390CF1BD272C007534ACC +:103040008D7CD026F94695A9D92E95E7908CF53D33 +:103050007FED70DA2F9A227D75FB40B7E784FE5F23 +:10306000B9FE8E9BC700BEE7133D00EF8BA97B28FE +:10307000DE307FED9CBB3F80DDB02B929E9764EBF2 +:103080004BB3A01F6BAE79FBF883F9338ED892F95E +:10309000F77ADBB4733FE3E554FF9E77A00F4CBD96 +:1030A000CD4CEDA732E11F656BC53837FBBFB424AB +:1030B000F3FE6E1EAF51CE4067A4337D05F2162499 +:1030C000FDBE0DFE851D16C966BFE0005C6939199D +:1030D000FCF9CDD030FB885FED93FCDE3441DB069C +:1030E000BD66E844B1BE547BF4837E5FC9127AD0DA +:1030F0007DB254758E576A5FBD31A2333316A53544 +:10310000380CFB5D4EE97AF0D5940C36692BF07ED5 +:103110008F19B90A1CDEAE4A5AF731392EF0A9CE02 +:103120005890F22302C389AF3B2774756EE0F5CE49 +:10313000D6611EF2F9483B7A01EC2B17DE0B39A65B +:10314000E4CB0967470CF1ABB4ABAB246BFCB161CA +:10315000E22357F1F6550E5B27F683050F4F8F4597 +:103160009E49558B59E4736C32DAD5DCFE0D00DED6 +:10317000703B39DC1E06CF808FAA3769C487439B1A +:103180003CB61492639A13F3AB7604B320DFAB3DE5 +:10319000911EBC3FDBE84D3C958578C4642AD95725 +:1031A0001CEF63E18F6594C4F162B6FE1CF8A1B216 +:1031B000B992ECC5E87C9DE4D3D92CC17753E04F9C +:1031C00084BCB174A4601DCE53CF139C390EE2E7CA +:1031D00048063C745A9D3980AB735DA409FBE694A4 +:1031E000FB045FF37566B7F0EFEFB7B028ACF7EF0D +:1031F000E27B3E5EC51A8BAF95D787D8992526010D +:103200007C55447C9D394CBF0FF09CFE1E2BC1FEAB +:103210005FB56933C1A3F88259DACB12A1DFED7033 +:10322000173FC07AF9287358E951E0AF871F6ED372 +:10323000880F78792893F8E1D637891F4A83592B6C +:10324000F311C7AA655EC411929907FE806ED64538 +:10325000FA4437D72720CF943C517283F3811779F2 +:103260003D8ABE4A7EEC6CE42071BCEE6AB453F930 +:103270004CA39359B80CD8DD984CF5E71B5D54B6B8 +:1032800035E6D2F3171A3D54DFDB5842F5FD8D5E6B +:10329000AA1F689C4CE5CF1A7DF49CE385E49092CC +:1032A0002B4A1E297E5272299C8FE671F45E574C80 +:1032B000DF93DC53F20EF33015F7CA2345DF0CCD54 +:1032C000E74F76438E75CC81BC28379F7DEE25F87D +:1032D000496A1C9E0817F022E45EB7C34E723EDDB9 +:1032E000C60EC05E6F5AE1EDDC10B2AFDE5EA331F8 +:1032F0004B089FDE511FC92C217C7C6743BCA15E1B +:10330000D1F0DE6B8378FF5ABCFEDFA0CB897B3F18 +:103310007DFCB7FCF993F77E910D7A7338766CC11A +:10332000B8ABA37AE048407DAD95F487A151C20EB9 +:10333000C21FE8329F89F5F9E4BD7FA5F5DDD910FC +:10334000E132F376F31B22085F1F824E1CAF1F4B46 +:103350003A55AE3BF9DC4B58E7AB6D24E7E6AF9549 +:10336000EB7223C76788BEF6490A23BD4CF3328649 +:1033700038CC27DFB305F99ECF3ED1EC010DBA0F53 +:1033800037922AF8737DE31B947FA5351C237D5863 +:10339000475E16FC047EAB211F4B6B90795A1D4390 +:1033A0000C7954D1A3BD36C807F034E8363FF73066 +:1033B000C3BA66CD9A135B40B57C5EBD51237DA335 +:1033C000475FC836131D2BB32C54FE026B9CECC513 +:1033D00066DA9F14BF7279E10D605D3417D91686E5 +:1033E000C8E1F9F27955AE894AF5BC32CB46FDFC0D +:1033F000028B91F7FB406E866D01C939970D7240C3 +:10340000B59F9F5BBC3E6334FA99308085ACC7A200 +:103410006C0B7D5F89442FEC5F76E1FFAFED671F9A +:10342000507AC969FCF36A829FECAD25CF3FFB3C23 +:10343000E2634B3E8A203A2D1929FD11F981B1D35F +:10344000499FF13A343ECF6592FE65CFFE3EB6838A +:10345000BF5FBE57F82F79D98972D9EA1AF26B2D5E +:10346000F3F0F59100B96A8C231F7DFEA3D80EB24C +:103470002BFCA9C82FE4DB422A4B46BCE8E424F825 +:10348000C597B3AEF5C8EB0AFF6EB9F655ACF0EFD1 +:103490008B38B98A5F96BFFAE7248263DFC524C8F8 +:1034A000B5E5AFAE4BD2FB98F7F2B0F8B58A9B2BDF +:1034B0003FD872B6E94BC4DDC2DB5565C70C00FFCF +:1034C000B0ABD855E4A7B030CA6358691778E80E96 +:1034D00064C7B13EC6EB19772B17ECDC0EEDB6B81E +:1034E000E23C1CCE0BFDE4F1EDCA16FBF93919479D +:1034F000BDB0DB4C7AE185DD31C4FFCB76FFF0F562 +:103500006B787DD9760DC3B23AD64E785AB6D7CC01 +:10351000ECA1F60DFC3689FDC3B9F4D9987AF0D345 +:10352000E236CDBB231F717957DCC01078D6497EB7 +:103530005A1AD13696E820E1FFAED48F54BBC507A6 +:103540007F6803BD78BBF3A4B7FC341ABA36FFEB2F +:103550007A07709ED9368AE2BA8BDBF62CA37D7F80 +:1035600077B41353FCC26AF4476D96E36DCE167AB6 +:10357000C619E9FF3DF3BC99E40FE0C43AFC4213DD +:103580007E5EF5DD16F9DD1689B7EB10541CD3DB32 +:103590007E715B676C166FFFD981F7A86C95ED178C +:1035A0003BDA0BB15F7EB6377A7280CA1F4D7A85DF +:1035B0008F77AE6DC2002D645D3D9F6DA5FECE6D13 +:1035C000334F06BE5840E519B5D17CCEEC4ED5C878 +:1035D000AE05BE397ECEEC7D31D644EBD66FA0A3CE +:1035E000C92EFCA96E8B4BEA977627F48CB95CAB9D +:1035F0008BE3F2AE6EAFC807087FAEDAD37A4B0129 +:10360000BF77D904FFCBF8BD8C2F214F84E2F13175 +:10361000B600F6D779235DB36E873C7BCB2AE831C1 +:10362000C4B50576D5BC7713C95FB1D2EA1A84FA5E +:103630009FDEB692FF7CDE28B9CE933BC6C03FD951 +:10364000E916FB7AED46BE42F8940773FAFBF9FCE3 +:103650006A0326CAA77C3F3B83E6F7588DC96BA354 +:10366000384730077ECA1336E637434F7E2192F43F +:10367000BBDA0CE1777F0CFCCECBDA84604E22F40F +:103680001D49C7DA5BF9FB107AD63E15CC81DE7294 +:10369000D626FC7878EF44592CDA3549BE413FE80C +:1036A000B7D3ED3C4FFAE5BE18063DDFF4528CF07F +:1036B00027FC2492E20EAADF53D942BF6F92712EEB +:1036C000FF0E011FE082DEBCD8D69C03BD528DBB2D +:1036D00038B699C63B2BC75B1CD52CE207322F0CA2 +:1036E000ED697C2BF3C21EEF7A3A82F4D32F52DAC3 +:1036F000F763FC2F9E1E4E71F04E7760E1017ACF8A +:10370000F5364E8725CF440401EFE74FC7509CF3B1 +:1037100073ABD0833E8F49223DE858CC23F3D05F72 +:10372000F7F6080DFE94CF35664BC6FB1D03295EE8 +:10373000B5A4B181E2044BF872473C9A97931157B4 +:10374000FE7CC770F2B37CFEA699E28BFCF9463C86 +:10375000D759F3BCEF60DDED8A263FDB17CFFC6D58 +:103760007868FC41954BB61BFD498AFEEABD35479A +:10377000D80DD61C81C7C81CB1CFD445B73D9241E6 +:10378000F314EB95D381EC2DBE3E92E09F3ED1F633 +:103790007292E6009E83393F02DE7709BBE68BDD3D +:1037A000568A8B2C7929C64BFE9B0D5799B05F2CFE +:1037B000310BFD77096737510AFFD092D81CF20F01 +:1037C000717C93FDD8B5C32CC711E37EBE334DF891 +:1037D000DF83B2BEBF20003E9F92C0EEBC95F49B3B +:1037E0006D85C0EBC5EDD126F0051FC78BB8FD92E6 +:1037F000EF7C57E0336E21E9E30C79D063112F178A +:10380000F2B26EC33571C88761EF9A1944DF458BF8 +:103810006710E46138BE66E74879B9FF711BE2675B +:10382000B57CBD203F68A98C9B2E7D46237D6EE92B +:10383000FA6BB6901C7CC7CAB2391C67DB7E181BBA +:103840004A8FD21CA157F47EEFA1F64B797BF1FD94 +:103850005BB104CF4EAB07F084D3F18ABF7FC67C47 +:1038600045DFF7F0471BDFD70B2F9FF745D6FEBF8D +:103870003E821CD91DE9F1D3D3368A3B9FB1B62DC8 +:10388000C4BCCF3C1749F2E54CBC58EF9F7179E8B6 +:10389000B7018E6F3D44FE8DDF4C6710DD8B02C695 +:1038A0007ED5B837E488731B75899E38C433EA38EF +:1038B0001DD01FA7CB2DF4FDBB56FA3E7C1E393917 +:1038C000426EF7ACCFE7A2895FCE0C16F438F3FC5A +:1038D00030DA573AE3059F7378D361A79C8917259F +:1038E0008332C2F96089B443CF4C6823BBFB8CB6EA +:1038F00087CA4EABF86E49838CDB72BE4B06DF8005 +:103900002711B7B26F6A871E01FFF4D8622A8311AC +:103910000997FB99C19FD8879E94EB0B6A0DE43AF7 +:10392000C537483F69B3411EEB528FABDD7D79BC93 +:103930008CE2A0BB358AFBDCABFAE1500F50FE7184 +:10394000CE8F4BFD9A17F9464BD7AE580C7E5F5A77 +:10395000BFF976F0BB9AC7520B9B0CFBAA533313EB +:103960003C9D917CDD000FA1E365F4E2F7FE1CAD08 +:10397000270FDA99447A2629D70FE688FD0AF566DB +:10398000DE5FED5A6D138DE356F6A4989FC2134780 +:103990008B0D7E326EE78BF7FDCC5FC1193E7F0544 +:1039A0004F6B8ED01B3ADDAE87C683DEBF3293FFEE +:1039B000F4E257A3E212BE462F83C5D6E32FE6F00A +:1039C0003FCFF76AC0BF42CAB7A5F047733873B696 +:1039D00019E31FB9DB8DF511BB8DF5FCBDC67AE18E +:1039E0004163DD73D4587F04E30EECC513EC5CE453 +:1039F000B5C1CE45093BD79523EC5CD461E7A284E1 +:103A00009D8BE7B07351879D8B3AEC5CD461E7A244 +:103A1000849D8BE77F9078AA957E47D081F2AB5E3C +:103A20008E5471705A2F17E62491FC54F1CC0B8BF5 +:103A3000F3A9DEE3CF9966277F8ECAD3B93D4E7FC7 +:103A40003387E286EDEB5340374B07F97197FF4C14 +:103A5000F8716B8B231DF02F74ACFB6C3DD4A7C2A7 +:103A600038FD1DB4BF60EDDA29F2958224373AD6CD +:103A7000B8DEBD5ED08FFC1C2AEFA612FB5D42FFB4 +:103A8000740C8FA3B04DC6B849781C253C7E12CE6D +:103A9000072A6EF2A4B52B05F2FEE4D3F64D80FFA3 +:103AA000A4F48FB1D94ED2BF945EDDA37F3DA83D73 +:103AB000857DFB428EC8FBEB3EC6F5ED3EF65B55C1 +:103AC000565D2A26BDB1A7BE493351DE48722CEDA2 +:103AD00043AB244CE95A57E706C8BB1813EDE3176C +:103AE0001D26B20B2EBE6F263D6218F4F390F90C22 +:103AF0000F4419F82B6F574258FC6FB0A1FDC80353 +:103B00001961F1BF11C6B8D46D6B0EC1BE9EBE69FE +:103B100094A15DB5EF9A303C4AB8A55EDAB47A6BF1 +:103B20003AE4CFAA986E827FD5BE48CAABADE6F024 +:103B30007A11974385A3A0C6EE9D0AFCD5B459E33C +:103B4000B1CF57C9FD873518F7E31A0BF33B137A4A +:103B5000F9AEC6C9BCF1FCFB7345CD3B4D9C6EE78D +:103B60004CDB1E19EF425CA935DDC9F9EA2EAD2DFB +:103B7000E96ADEDFDF2C7ADA304E8F746BF00715DE +:103B800090977B32D91ADEEEE4A6176349EF967C54 +:103B9000966E754681DEADCD66B20BE0973227F4A6 +:103BA000F2436B73625496A3779EBDF4FF8AE6C717 +:103BB000E9E2C139C56EC7E121ABA0C7B589F9D625 +:103BC0004CD0FCA427CBF9AC94FB0ACB12FDDC252E +:103BD000EBA7A4BDA0E67776F8A14217E2988D077F +:103BE000D2CD90E3A6DD3B717EE0DE28BD64D840F7 +:103BF000E44B66FF763C1F77C907225FF78F2D13D2 +:103C000063AF86FEF99CD53385D73734FFD806BB22 +:103C10007889256083DD59F374ABCDCBCB1B76B5AA +:103C2000D2F385BB2AC9DE5EC4EAC98E3CADF26F11 +:103C3000253E6A4AB56D4E0EF793C384DCA88912FF +:103C4000791BE5E6F1AF212FFDE22EAD08F3BDCDE6 +:103C5000B7C756C99FDF3A4C9E3B095B1FDD6F4FCC +:103C60002F1F087F529B887BF6B71E660473693D41 +:103C70004CBFE4A2F2B64B23C88EFD80F90A484E31 +:103C8000E487D9B36F8B3CE4EE83621DD4D8820302 +:103C9000A6639DFCDC4AEBA48ECBAF9262D8C98CA4 +:103CA0008DE3A56FBCD9C0AFCBCBA20DFC3C9B254F +:103CB00018E2C833716833A47EDB944C43FB59B7D8 +:103CC000E585F17F71EF7B9223E30C792675ABFDDF +:103CD0002E8DF2594A8DCF79B99AF8EC26C3F77533 +:103CE000ECD6DE76B083B7FF9AF0CC58BB0DF65613 +:103CF0008D49E4D5CCD63BE5F30E7ACE27625887C2 +:103D000043333DBF15FBA295FCF2CA2F3D1BFFCEEE +:103D1000EC6B5FE48496E3223F14FE05437E2107AB +:103D200080EC4F26E85027FD3D75B9C2DF53E76FA1 +:103D3000B721FF96E3DF92CA51B2AC59237F1E6FC1 +:103D40006F4F4D10F5D578BED778DE00FD5DC2FB14 +:103D500063E64AAC97F0F7CBF8BCA1672C839F06CB +:103D60007E26D5BFEC57F1E7A2AD46BFD132F8733E +:103D700042E8F8C93017F1F3925D7B5E1FCCF13257 +:103D8000DD175F84F553DB36CD5A997F399F29F9CA +:103D90007EB1C64471EEEEB78F109F75D758889FDD +:103DA000BF091FCBBCC29F19CE7F0BF97C10975D5A +:103DB000B857F30434D10E78190CBE0CC34B6A1FEC +:103DC000F85278EAC15BD8FB45F8C768E40D688112 +:103DD000A0BB2FBC483CAAFEC3F0C44A8C7858A8AC +:103DE000BBDE85BC5978CCCC025730EF45981FC656 +:103DF000E7F3C3F8B75E127E1215379879C942F51A +:103E00001E3EF189FCE9DBA618D7650FDFF8C43A3E +:103E100099712989BEFB9FE69F6FE21B0577787E2B +:103E2000B23ADF737A983CFF32868DA1F57F8579AF +:103E3000C36ABF57781E7A6F09E513753B32487F16 +:103E4000E8D96F9CC6F72B6332288F5897FE392527 +:103E50007775D94E8D53C9DFBB46818F8724C1EF5B +:103E6000BA7E6D667A47885EA2AFB392DF347D4D2D +:103E700022959591CE24EC17956BCC3EEC839FDC7C +:103E80003F28A9047EF875D6015378D79FDC333AD2 +:103E90009D15A05E4EE5C9CD11B343FDD9AA8CCFC7 +:103EA00015FB46DDBDC769FF3A677A3B7636D6D942 +:103EB000BA7DB148A959BAEEBDB14EAE7AB45A74C2 +:103EC000672EC5495B773A8137676B21FCD174F661 +:103ED0007260AF9EB0645DF920F8BF6AFF7EE409AE +:103EE000ECEFFA1A6B12F4CCCFDFE7FB9F46FB171F +:103EF000E907A7917F3C0071AB683ADF765A635EB1 +:103F0000C46F169B0F153A0DFBE9C19980E3E528B4 +:103F1000DD953B06E3077626637C8F9FF225F5351A +:103F2000D9717DF94B54B97CABD0DF762A7FADF4E3 +:103F3000EB426F471D7A3B8242D0DB5187DE8E1207 +:103F40007A3B9E97C25F8FB86A535711EC4E7F2918 +:103F5000CBADA7FDD5910BBD7C9516E581BC59A5D0 +:103F60007906C10FC6B6A7887D358CBEAABCB68BB4 +:103F7000EB5621FC7EFD253B0BCD1F9BC0E20DF5D2 +:103F800089F61443FB72A7DBF0FE86E4E186F7377F +:103F9000BA8A0CF56FE55E6D687FB36782A17E4BD0 +:103FA000C98D86F6D3BCD30CF5E993E718DACFF0C8 +:103FB000551ADECF9ABDD8F07E8EBEC250BFBDE688 +:103FC0001E43FB3BEAD718DE7B99D382FDED20EC44 +:103FD000298EF79FC39EE2E5AA5F653B42E93A7EE0 +:103FE000A2A9BE2F7FFCA25CA1CFDC3FDC3B1FFC63 +:103FF0009126CF81A4C9F31C77E7BA44DE00CEED49 +:10400000933DDB9E02BE096F17FE7E7CF4E18B2E92 +:104010004EC3F6DC5B6EB370F930FEAAC3A33279EF +:10402000DDFC74D36D162E57C65F73F8C50C5E8F1A +:104030007EFA55511F79F822DEAF7E7A83A84F674A +:10404000A45A243E3DEE363F9FC7F8EB33367984C1 +:104050003FA4CF7C4B55020FC85B041E5006397F2E +:10406000A23CCCF913E551CE9FD5598CBDCEF913A6 +:10407000E5316E57E2F92FB95D89F26D6E57A27C7A +:1040800087DB9528DBB95D89F2378DB3A97CBF51F9 +:10409000A7EFFEB3B186CAE38DF5F4FCC3C6062ACA +:1040A0003F6EF4D3F3CDB9CA4F11243F8B8A272D2D +:1040B000431C0F7EB803D6B3A17156150F54F1BF40 +:1040C000A67AD6118D75DA6189FFD4DE1BD7EB5F36 +:1040D000CE5AD8A721FA566BB4775B2EF92F8638C3 +:1040E00029AE239F976AD3D38A79F9854B7F0AEF4C +:1040F000671457AD8B73E31C48BD15FCF281A9EF23 +:1041000073C1774B3EA91AEEFD09BE53716C15477A +:10411000EEC94F0989739B42F262E82F24BF45C55F +:104120009B553ECD7576919FA7E2C92A6F46F557FC +:104130007E8991BCBB76A385F493180B0BA27F9567 +:104140001F73ADBDAD08F902D7D63A280F6D107FA9 +:104150006E2BA6765E332FB7FF99B72FEC8D5F0FCE +:1041600092F0F3F7047FF9259DFCAED7CAF83DBE67 +:10417000B78BF77E7C8FDC29E819BC24BFDAE3C853 +:10418000732AEE8DA7A37DB4681F447F59FFC5C76E +:104190008BED5D3F69096D45C8A74A5BE6A07CAA27 +:1041A0006D1382747E4B77EBEF019FBE08E7EFA3A0 +:1041B00069FD64A6C14F304DEABD5F4387E358AF48 +:1041C0000A3F0ACF8A2E0ABF21794784D7FEE81416 +:1041D0004E9F70BA287A945FEAC533F074391D7A1D +:1041E000E9047FECFF2B74186D69A3F37F11B5769A +:1041F0000FE0FA26BADCD9C526E13C7172867E371B +:10420000E85379C9F53AEA556CC2246C4DEABDFB16 +:104210001BDE4FFE86F70BFB79FF56A4CA47F03A28 +:104220008A385D264AF9B1AA5CE077B2DB4CF89D8A +:1042300098BF88F451E6107A9D8BFF0FF264D25735 +:10424000BEB5E86FD200A37EA8E2C137C9FE2687BB +:10425000C5816F927AE34D617AE1B0E1323EEC665E +:104260006E61F78973EE65729F4E9574CEE4C6FC5D +:1042700078D091E91608ADA338E75E8873E07EAA8E +:10428000DFC802547E8B0569DFBA990B38D46F61A1 +:104290008CF2198F444FAD58CEFB9B386A62169E44 +:1042A000879CEB2B193E86CEF5FDC11972AEEF70DF +:1042B000998BF486C3F64CD263B00EAC217EB43732 +:1042C000B9DC472AC311BE2FA07C8DEF0B599CC9C6 +:1042D000DFE0FB02EA37E5AE61F86E92CB986FA2A1 +:1042E000BEFF96B3945946F52F77BF55F8F210F8F4 +:1042F00057DE8A1F5606BFF35BF1579561BE6FC547 +:104300000F328932C24665C14B597DE9598A0F7B0C +:10431000C79BC42C8997E357E1331C8F0ABFFF0268 +:104320003EE7F785CFBBA53EDA6D7F2F363903F127 +:104330002FB1FEEB5E2A1804F83F0768C84BB60B96 +:10434000BC84FB773E6B6443805FB63D8E9EDF2D61 +:1043500079E8DA8671D4FEBA86129ADF3551FAAA64 +:10436000E13877521CCCE19A03FB6C5B139DBF3D97 +:10437000F7BCD903FDBBD6ECDAE4C15A7F4B9C975E +:10438000635F1D4947BC8D6DEF3B6FB7D6AEF0E65E +:1043900027F88B32BC778BFD4F9C2356FBEF9008A0 +:1043A00091EFAACEB3F6B71F8F8D12726548849035 +:1043B000838A4EFC3BAAA7F27EC672B991FA5014CA +:1043C000E9DF2509DE07804F56C60CFAABB2ABBB5E +:1043D0000798296EBD12F1CB01B06BECE4CFB98E1A +:1043E000E5DC023DB80CF626C743F99B55744F81B6 +:1043F0003A9711916C32DE6FE38A32DCD7129D9BC3 +:1044000060A8C778061BDAC7956418DEC77B471813 +:10441000DE274E2E36D407FAC619DA0F9A5D6AA83F +:10442000A7E83719DAA7D6DC6AA82BF9922A1EB1B9 +:10443000B4FAB986EF8736CC37B477FB9718EF9F7D +:10444000F17BDB73932097C45FE6C69586F73F8ABE +:1044500015E70E263B16D27D12D9CDDF318E6FFEC9 +:10446000CA0CFCA6C669E2BE0097907F7EFE3FD0D4 +:10447000B53CD9280F273A8DF630D7D734ECBFA9F1 +:10448000F516C3F337864BBBB7901592FCFB27E9B3 +:104490001C8E97EE32E609A23DF4155EBF4E1FF169 +:1044A00010FC0E6503AC9E0013FEEED079C1DF1D3B +:1044B0008A07F8BB43EBF0771BEF6D32D21DFEEE9F +:1044C000D0F7A38E19E93EA6DD48F7AB8E1BE9AE07 +:1044D000F8319C3E577718F9219C3ED79C0EE30F8C +:1044E000498FD9FC7FFF10E798895E931C1A7BCC1B +:1044F000FDAFD3E76F61F4E9A187C34EFAE275C15E +:10450000BC38D4CBB1CEA037C8F9DC9057EFC88007 +:104510009CB4E9D611037BF9A72945F04FF7B117F1 +:104520002321F7224618FB3F9FAA47A1FDECC48B2D +:10453000E936F04397B8AF6FBE949F2A9F90DBBBDC +:10454000E23CDD77CC14DF3F616AA6FB920E3BF5BF +:10455000047C7F677EBD86F84132F3ED59C8C79B66 +:10456000F78B088A27CC1B2ACE75B2FC0ECAB3572C +:10457000726E5EAAC863193C42C6273D229F256D14 +:1045800084D00B633C4ECA7BADCC17E708B859907A +:104590003EAF00F8783B12F71676B708FF7D8755D7 +:1045A0009C2FF5733E455C0C7A22F4B834A947354C +:1045B000FDCE6E07FCC3B632C3BE383C6037E45D47 +:1045C000E6ED721AEA056DC986F6230FB80CEF8B7B +:1045D00082B986F7A38E790CF531ED2586F6571D45 +:1045E000F71AEA57774C36B4BFE6B4CF504F655D43 +:1045F0008F02BF4335618FCE1821F278F81AA57863 +:10460000D2BC0DF1E2FCA0B453951EACF27175C999 +:10461000D7E1FAF4509B4EF9BD4D29CC43E700ECAD +:10462000D23E61463D5B97F9B44A1F657E633EAD5D +:10463000CAA3EDD1C7A5FEADF4E1903C5A6F681E48 +:10464000ED3C79CE377CDFAB1C21CFF385C13FD465 +:1046500026E6DB748F8DCE2D28B8C2E1392BF33BD3 +:1046600077D8FB3E3FB27C84B0637F96E95B3482AF +:10467000974F403C65F6359EA7C3CFF9ABE97B3633 +:10468000CF7DAE6F1E6FDE48319F0A93E9CE69F988 +:1046900094B734FB8590F11B257F57E76B7DCE6F78 +:1046A0005E9CC82B62713617F8B7FFF1043E936D1C +:1046B0006C2D9D739179E7776C6A7B102EF20A5B03 +:1046C000B355DC5F16B0821FA69472FDA988DBC9C2 +:1046D000DBFFEB870EAEE73CD160213FC4FA67CA2F +:1046E0006770CDABE71CC1506E5F803FA0ABC02EA2 +:1046F000F94B9EC89BFDC9084665B9F9AB9EFC6F96 +:10470000F2A73326F70761B7F4C16FC4876A1EFFAB +:10471000EE3CF0703C29BB90C9BCBB2C0997C25F32 +:104720008F1D2FF1A7F2F15D2BACBEA71C94D73FD4 +:1047300019F94C8A7E31F9822F7F27F181769047D3 +:10474000FDB52B37E7C7C15FDBCD5C71CEAFF1475D +:10475000FEBBF0A2F0DFDFF99EFEE4C36572A19F0D +:10476000F33EFDF127FDFD13E77E42E483C82F9160 +:10477000F4086499289EBB21C6B88EED79625F78F3 +:104780004EED177E6E4F1AE504837FB9699D59CAB5 +:1047900009B16F63FFC4F305EBACA4CFB006918FF2 +:1047A0005C23653163BEA471A3118FB5D27D56D74A +:1047B0007919E93BF31DB6402B6F5FE90FDFB7BDF9 +:1047C000F43DC56B5CB8B7C4B31EFEF7AA8DC676C0 +:1047D0008B1CE25EAF056176E92269972E0AB34B26 +:1047E000FF3A42DAA51EE621BD4CC69F159C3D7CD2 +:1047F00015C8A4BC60D8A966E12FA17C2585271720 +:10480000E20B21F768727C46E562DF5E6BE9338F6D +:10481000AC079FFDC4C9CF224EEEC2FAEFA6F33F0C +:10482000DD7B23451C4DC52F64FBB3FE8BF41EEDD1 +:10483000D1DBB9A2F642C4917AE21D6171936E8711 +:1048400029B604FDED16F72FA83C80257F0D143AFC +:1048500043E29C7A87C99077115EEA6BF6515E401D +:10486000AB45CFCC433EB2C563C77D91F73B0E2726 +:10487000E1BCF614E9AF0987B747AF1AAF8938A191 +:104880005FE8B9DD9335D273B95C6458472A9E3D21 +:104890008D0507A054F1037D6309E159C50F2A83F3 +:1048A0002504E78CA645565CD9D7F1E8EAF22857EB +:1048B0006F5CA1234DE4A3F4175F987EC943FDDD2F +:1048C00076691CF5539AE716E7F5D73EB8027C34B3 +:1048D0006217B3629E1D61F9D8AA7C214FC89F77E9 +:1048E000F394DC96792E6B34A1C76B4CE5BD90DC5C +:1048F00056F58BCDB25E2EEAABD6897A87BCC768F7 +:10490000A7F437609E28311FD8C5BBA53F02F340EE +:104910008979E039E414EA9053A8434EA10E398511 +:1049200012720ACFE7335F7A9159C441CA42D60D59 +:10493000E22065217A10E220A175C44142DB230EFA +:1049400012FA1E7190D0F7888384D61107096D8FF3 +:104950003848689D95DCD85B875CF34E33D4A773E9 +:104960007DBF2C64DD220E12DA3FE22086FEF415B4 +:1049700086EF6F670D86EF1107096D7F6783668885 +:1049800093DC29CFA5576D4D20FEB8C9ED6BCCE364 +:10499000F4FD43F4DFEFB6C20E341F5C4CF6595DF4 +:1049A0009447D0B979B2A0BB89093A77CD213AAF03 +:1049B000B6897AB9C88BED2BDE509625E20D281109 +:1049C0006F408978034AC41B701F36E20D28116FAF +:1049D000C073C41B5022DE8012F106948837A044B5 +:1049E000BC0125E20DF80EF106948837E039E20D9E +:1049F00028116FC0F313887B64F5C205BD3DCB6001 +:104A00003F723E34D88F4E431D7A7B687BE8EDA120 +:104A1000EFA1B787BE87DE1E5A87DE1EDA1E7A7BBD +:104A200068FDD00817AD33E8EFA1DF417F0FAD1768 +:104A300034FB5F838FE9E66DE78FA2EC88D19ED0CF +:104A4000B82808E67D3C0371A48E482D3D9E2F7941 +:104A5000EB9ACE1965BCAECBFCB242D645F73BEB28 +:104A6000F2DE1A3DC8281FB6E02FC9422EC83824EE +:104A7000FD71BA17ED65640794CAF383EA7B0F737F +:104A80009A51AAF6BDF5BEDB858FAFDA91BC0C81D9 +:104A9000831B8845C883285AED28461EF74E932667 +:104AA000F220EF1379A8E17CF527B96FEF34ED39E7 +:104AB0001C85BC964A8DEE8BCFB1B063B8C7BBA046 +:104AC000B9BE18FAC2C7793DF7CB8F435E8C825BC3 +:104AD000F901B99CA07355E3BB98AD3A1FF7893132 +:104AE000DB02C8779BD013F01DECC73CBFE67D2AE4 +:104AF00084BF3FCD137ABFEE5F31AE9A3FCFDB5D0F +:104B00003F0EE7B5A64489EF7EF2642CE171EA5AC4 +:104B1000ED299C8B1BBF9B7971FEF282843B6FB7A2 +:104B2000D3564DE33AE99C578FBDB22D9DCEA55586 +:104B3000B28EB264F2E56B748FB9C21B9FDF51CCA9 +:104B40008F8BF86356D247C5799128795E449D13BF +:104B5000715B7C7B608FA8F322D78E8E2F47BE16A9 +:104B60003B28EEDDBB7974E5BA81BC7F3D20EEDDEC +:104B7000BBF64FF5AF517DBBB8778FD8602C8D4316 +:104B8000FBDA30BF46F73D4CF5B79A06B8707E7435 +:104B90008D3509ED77330FD49F614C9C8354F0E53C +:104BA000B37613EE1DE75BCC91C4103EE29C7A1BFA +:104BB000E85EE4B1D27D10D32C4E2BE446F83E7E65 +:104BC000793E5D989E10960FD1B4FA78BA3903FEFB +:104BD00024932708B9B52F9AF405A5EF54CA3CA829 +:104BE0008B6B5FA3FBAC2BF708FD40E77200F24F25 +:104BF000E547D46506D24DD01706B7162698C5FEF0 +:104C00009FCFF178C6FFE2CC1217CE31BE46F9FA3B +:104C100095EBC6C489F33A22FE502DF1542DF35F73 +:104C200058BE33097AA7BAC7B4DC3C3E8ECEBB353A +:104C30000B7D4EF9772A7F35EA75D0B9F271791F6D +:104C4000C8C64A3A07149E87A2F44375DFC9E2B585 +:104C500056CA6F591CA6072E957AE0D2303DF09ABD +:104C60007CE99F517AA0BA9F4EB6A9FCD59119A4B0 +:104C7000A7D48BFBF82AD608BD85ED11F7D857AC21 +:104C80009968C2BD1515FBBC1EAD0FFE7857EA2F03 +:104C900053306822F27C065339F3523295B32EE535 +:104CA000921CC0590CD0BFE36546FAF47B525F9961 +:104CB000813C3F9C8FF347C87C3E46FA5211739665 +:104CC000436E8CF06A47E0BE9E62D5D7218F704A52 +:104CD0002BA3F3303743AFE12F6643CF19053E775F +:104CE00097D3B980C91A9DAFB879F40AC9D79CCFB8 +:104CF00019F8DC2FF9D647F59EFD40F2B7EEEFB478 +:104D0000D0BDAC7ECD867BD97469CF2AFE0DE7F38A +:104D100079F2F7269843F8997AFC50001697ABF889 +:104D2000C7CE84BE380FBEC1C1929076D875E2FD61 +:104D3000DDBBC7CE5C8B1CEBFF4BFF4485FA1D0629 +:104D4000AE67419EDE7157916D7E885C292D2C6D7A +:104D50002918D84BF7F93DE7C6F20741FF5F797F85 +:104D6000F6A0AF3BBF58C5F18CF5312FAEE36EDC3A +:104D70008CFB703EF39625E33E66A62E9109225FDA +:104D80006DAEAC1FDE7DE77F6E74107EA8BE39BFAE +:104D90007CA69FD68B9057B7435E9921A7F487F2E4 +:104DA000911F64EF98047A44E777C9F3F0F21C6B23 +:104DB000983FE270BEA043B85FA22A5FC8716671D7 +:104DC000A5DF4EE7545DE4D753F07F62359E1B5458 +:104DD000E5CFA47DFDEFCAB7FF7392FE2CE6F788FE +:104DE000499CDF1E6C6E66D23F247E2743AE1F2691 +:104DF000EF33E8A53F971AA0FFFD9A3394FEFA46D9 +:104E00004D9C9BEEC78FC372BB1EDD013F5EA3F8B6 +:104E10007D8E2773041F3DF91D1BE9DF15B6F6D7FC +:104E2000704F93C2E3470DFF61A5FBFE58301BF79F +:104E30004FCDAD8FA4FB5E4B0B7D8720F7A2F33DDA +:104E4000448F9602C1671D4EDF513CAFDB74E80909 +:104E50009C1F5F7ED04DE71A2B0F14ADC7BD16A562 +:104E600085FA9B986FA5C369C3FEBD6C6D3CED6769 +:104E7000F306C9F385AC8BE2540AFF9DF9621FDD8E +:104E800052C8E43DA732BF9E0BCA69867632AF385E +:104E90006C9D28FF60B89F21FC3E81FED68FF227D3 +:104EA000C07F600BF12F2AFF8435F79339D83F2B51 +:104EB0006CC6F370AA4C289076AEB40317F4EC5F7E +:104EC000F99306415FDEACD1EFD6543B5CB3AEE65E +:104ED000F5EA6356640AB229092E718FC4FDE21EF9 +:104EE00089F97CBD42DE54C8BCA1EAAD25B4DEAA76 +:104EF00003BC4CEC7F5DDEBEF948DACBE09FA097A7 +:104F0000CE89573BBDB68490755FD5AC19CE99ABB1 +:104F1000BAA9C02CD611AE302F86BC70DB70974B6F +:104F200005572B9087965020F8437DC7DB511EC351 +:104F3000940CF6BAB8C787C3ED16E31587F43FBFE4 +:104F4000D9785E9EB7277DC8511023CEA73BF9BC08 +:104F5000E1FF703A094E8E07C253D783BC3F178DCD +:104F600043F4A80A06ACB0B72B903FC1EB739D0188 +:104F70002BC699BF56DC5BA16F12E3E81BE36D05FE +:104F8000D0972C4E5B1AF027EFB5E7F0911CACE6FA +:104F900078C1F91F750E301C3F9512DEEAE678A342 +:104FA0001ED6BCD90A7ACCE9E7FCFC7505826FE70E +:104FB000AF9D40E79FAB2D5ECAAFD7257EFFB822DD +:104FC000F201C407E6B46CB1BA79BDB040C899EB40 +:104FD0000A047F4DC90866D3FD342B223D80738EB1 +:104FE000B399E6D783DF87393E34DC83E223FC7252 +:104FF000BEF0238FACBAC548CF5E7862C43D462D63 +:1050000095B4DE165A749B33148EAD87B271AE67B9 +:105010000E5FDFB8778739753A6FF3E9C3B3D269AA +:105020009E1C4EE035C6E39A84FB66389F101F2B0A +:105030007E51E783D578330BC479C799057DFBD7BB +:105040007BD7A597F49B264E5FF8BDFB5B97361C7C +:1050500034E2E3DAAAC53D60E1EB54AD4FB52ED59D +:105060003A55EBF709AB2F98ACF5CA19BEDFD6BF9E +:10507000D0079E5A0A841C992BE9CAF17A34F45C51 +:10508000D1F7E47AAEC830AE77F447F7064ABA579C +:105090009406B3710E50B557E3562488EFC0F7E07D +:1050A000B7A5723CB45F49ED4D067951D5232F76F3 +:1050B000AF4B82BCD8A391BEBBF2C12369DF861E71 +:1050C000FB9CD063CFD4EE589602BF8125901E7A08 +:1050D0003F537550C887055CFF81BC5828F7E9929B +:1050E0006CFD3B0521EBB7FA87CFE5E842BE042112 +:1050F0005F3E7EEE950FC6B97AF74F05FFFC8DBF78 +:10510000B6563A42F1A5C9FB28BAE9DC5795C3E681 +:10511000429E6DD5DA4A92B72C99DB135A489E54B9 +:10512000181F54AED5E8DEACAA86B101F3FFA05C2F +:10513000AEDA348DEEE6517452F76FA8FD54C1FF1C +:10514000B8847FAEE4E380946B736BDCB685B4EE19 +:10515000DDB62AF0BF7C3FA7DAF8BC874E3D71EC84 +:10516000FCF5C9F21C0BD9259BACC2BFB73B86F43A +:10517000D5332B5F7A67266FF7C523ADE9D04F147F +:105180001C8BA41F6F81F4C72D947A2BA7D34F0BD0 +:1051900042F25B163D29E854F5FCAF7E8FFBA12A55 +:1051A00032A43C7B509C2F9FDFB687E83667E366CE +:1051B000AB9BB7FB4581DB20A7ABEA8B9CF04FCFC5 +:1051C000DDD86A851CF8859437E1FC5E21F3521521 +:1051D0005EB1EF6821F10BD51EF26F0F1FE7AE1520 +:1051E00091B1C87351E39C967C5C551F9F80F1AAD6 +:1051F000EA2B7F00BB47C9FBF075773252AC87F9C9 +:10520000BC3FACCB93133C74CEB642FEBE5478FB8D +:105210003F48BAFDC82AEE114C8D6E7B9AF2169665 +:105220004779201FB2B23A021817FC0CB86D2671EC +:10523000EF60566DC7978083ABC5949F8212F71DB0 +:10524000414D4EE2F5A74CE23C50865994D642C1FE +:105250000F704DE13D1BD041F79F85E4671AF8D5EB +:10526000C6B66FC4FD2BB6018C7EEF45F1A7EA47A9 +:10527000F1A7E2DFFEE6F7DF5738BF936EE987C894 +:10528000F5A4E31CC5BC8786D1FDFCDF344F9BBC75 +:1052900007AF67BE11E2770B2E9B6F968C8FF73BA3 +:1052A000DF96F2A43EE61B3E4FB54E54EE754F5CC2 +:1052B000A159C4154E6A7CFFE2DF9D5C1149795FFC +:1052C0006A5ECAEF7DA5F9F2EEC2049937DC1103DC +:1052D0003DB242FE1E040B8A3A9E4F0B79AEF67D1C +:1052E000756F9892CFA7EAE5BEC83A1EC47A660DDC +:1052F00099744FC689E69331B8BFE3E404019FFA7D +:10530000EE2EAB38F7CA626C2EDC9FC8ED2BFADDAF +:1053100087056B07911D79474326C9853BFCF1C280 +:10532000EF20F5FB85520E46DF55B9FE2AB4DFEAC1 +:10533000766A7C9C050ECFA75BE9FB3C0FF4C1E8C5 +:105340009669B60CD27B851DA0E2407769CC47E711 +:10535000992027B1BE4C87B2B0EF2CDA2AEC802915 +:1053600026B611F1C2A14DBE492990138F8A7B2325 +:10537000D936E3BD4A2F66FBC617026F61F791DD90 +:10538000656DF30E821CE7FA06FC4C0B1C3ED2DB6B +:105390005F9172F2444B27DD4FAEF07AD939159BFD +:1053A0003897DA156322FFDB959E57A996F124C53D +:1053B000372A1EF518FE7335F064A27DADDC5C4122 +:1053C000F7FAAC6F994865F5E6F247FC05380FEB44 +:1053D0004B1A47705BC93F565D37519C1F7D2A228F +:1053E0001EF64DBAD59F1EAA9756B76EA0732AA770 +:1053F0005B23E99C4A99735A59FC00BA6F97CE7D9A +:10540000A976B585623F5F5237D170CE6401EF1344 +:1054100079B07F6E8BA6BC52757EE4DE287D51E1AB +:1054200040718EE46A97383F9242ED5D7DFAC35534 +:10543000F969A3388F10722E66EA1CFE7D6DDD8B34 +:10544000B1E867E9C3EF8DE59881FF6915FAEF3997 +:1054500017B3559C8BB90BF612F4C804DFCC39C0D6 +:10546000FF9B66C27F7FE3D5E0474942EC883B0261 +:1054700071A4B7EA4166433C597732D28B4F9B59AE +:1054800003F400A5BFA8E71B245E4EC735A7833FE2 +:1054900016EFDC928EFDE5F31851AFD839EB9790FB +:1054A00057FAF608A19F5B18E9C3557EA15FB39A2E +:1054B00004752F66E43CCE479B0BA3C53D3DF2FC33 +:1054C0008C824BDDB7FAB945DC17837331E0F78F77 +:1054D0002CC105A0EF475C7F851D5B2BE5D847CD30 +:1054E00066FADD113F5F28D0433E6A7E3106E773DE +:1054F00095BE566EFED88BFB6856EE13E75471AF1F +:1055000039DD5929FD20CBA41F64E5CBD649F8DD50 +:1055100011AE7FD1935A4BD0D617FD9648FDAAA75E +:10552000BE770FD96DB5BB85FE50DBD649FA83D265 +:1055300047D4B9B8A5BB3B499F50DF2DDB2BF052B8 +:10554000B7573CAF44DEBAFCBD502D0BF6B446F560 +:105550007776CF9DB5C6509F43F577F2A5BFDED2D3 +:1055600045FAE003B9BF213BBC6EADEC97D7AD2146 +:10557000E3ED07138D11CF331DF8DE65D01BEAF67E +:10558000C6D3F7C1BAA88DD8E7BDCB1C16944D750C +:105590000EDAF7B7D59B722DA3015C94077ADC4134 +:1055A00099BF3570E97F46C27F90C2BA8EE0DED7E0 +:1055B000C34EFD4DC819F57B96EADCCB85573F1BE2 +:1055C00085FEAF1BDA7111773C58B585B3109FF893 +:1055D00075A19C477EC728F0F5C0C3423E3F6E656B +:1055E0001BE9FE608B8FC16F1F947145FF5F4CE21A +:1055F000F725B4E08F43F52BEB48B19FFA22447CAA +:10560000B1C8AD7F08386ED1AC0545B0A95DE66C78 +:10561000F4AF7E4745E9A9A5523EA749FBCA3638F3 +:10562000D9013ED6BC5E3A87785FFEE12AECCBDF3B +:10563000EFB2D3EFABAA3CBFD2AE28D25BD3064FBA +:10564000A6FD4C7359584531FC2AA620F255BFCF10 +:10565000EC222FC01EA6D79A22291F593BF8C65FFD +:1056600020CF53CD5F1EC1EF94A47E5BA3FB2FE739 +:10567000757FFA387E63A682058AE81EBC78FD2213 +:105680004877A27B72A7CE49F67D679BDD23F6099A +:10569000160AFFC17BFE129B60EA85EB42D7A77416 +:1056A000AFE0852E3BF96B4B0FCAFBF6C2E0B99019 +:1056B000ECA2BC68DE8EF4CC0B0E13DD33567AF010 +:1056C00008DD9B57AAEED5B31BEFD563AEB478F8CF +:1056D00093C987CA9582A42641B7EBE28C7662D241 +:1056E00048A127268DD4E43DA5027FDDF6F36FE9BE +:1056F0005AEF3A5CAEE2F7EAF7A66A22E8F7A6BAF2 +:105700000F667EEDFD09EF417FE07AC1F732BCE91B +:1057100023C7F4EE9F33245ED43E6C96FDCF90F801 +:1057200099E130097C84FDDE86E20F457F05AF3AC2 +:1057300077A4E8C6BED3FE1ACE05717A153CC4889C +:105740004EB918FFC45FDE5E8763FE83CDDE4EDD9B +:10575000FD6FA15310F7E05C319DDAC3E9148C1C96 +:10576000063DE161F1FB5BE1798D2C97D13A9F67B2 +:105770008E223FA02EEF05E7EBFB35AC6FB5AE8771 +:105780004EEE28C0FE78829BDE80ABC3D446CF1796 +:105790008DCCA0753884B5A7C8FC9B31D0CB9AE4DA +:1057A000FDC73DBF63B8D841F78D5C08A8FB8F03E8 +:1057B0008F2EE4E3B6CCC827BFFE0526D77B4DCF9E +:1057C0003DD9E2FEE39E7BB2CD7EF293CC89223FAF +:1057D0004FCF3DD9D9E2BEEB573496837B68FDD3DA +:1057E000EC941F1F7E4F36DF679E463CE3B19A283C +:1057F0008A43A9FB914B9D7AE5C88197DF8FFC888E +:10580000E69BB300FD1538A8BF8E3951CFEF146861 +:105810000EC28F73A22186EE85567CA9FCD743FD6C +:105820009D8F024FEA5CE71F247F29BCAB736D0A92 +:10583000FF8ACFD47DECDA6AC16F3D79B2CB18F91B +:1058400047867010A229EFD1E3029E1F8CD71B0060 +:1058500077D30A2E37C82F2EF2374F988CBFDBAB89 +:10586000CA26B92E99CCFF9F27F7A9792ADFBFC195 +:1058700098EF1F7E7F66629C6F1DC63BA7BD3716E3 +:105880000FDFFE6F739FF9233F90727974B4FE208F +:10589000DAAB730F4A2F7CBBE8B334FA9D91AF8E1D +:1058A000D0EF29CE75FA9AB18E22B3441CE00F29AD +:1058B0001D744EE30F73FE9A467EE4D5E2DECF2BD5 +:1058C00085F3F273B4820F562D107986A9AC9EF839 +:1058D00036B9F77C6624E0F8FFED1C6DEF39D7C9C7 +:1058E000A34E51BE858F7EA7229C1EE3230EBFE8E8 +:1058F000E216CA1B233F9945E74EE30EAF72F3FA57 +:105900003B3FFD54D4530F5F74E35CEA4F3F9B452C +:10591000E74CF30E5FC439D4DFFCF4B4787F0DA3F9 +:1059200038D6FB3FFD7C16CE9DDADDFA07A0EBCC26 +:105930004BF5AF615BFD60CDAD0BDC748E725A5AD6 +:10594000AE3847F916E8392369FEBA38ADF71C6559 +:10595000F748DF07787EE14BC1E76EC4C006FEEB77 +:10596000A53A47AAE46C7FF250ADB77FD73958B556 +:105970007ED94ECF462B98D0FF2F9F4FED12FB992B +:10598000F17CEA6BAFFED685BCC3F1A3EDC4CFE3D7 +:105990001DED2EF80550875CDCFEA538CF87769686 +:1059A000D07603C439BEF1384F01FF41B73867F8EC +:1059B000DAAB6FA440DE8FAFB7519ECF16F9BB00B4 +:1059C00031A643668CF37F00B1492F16008000009A +:1059D000000000001F8B080000000000000BB53C19 +:1059E0000B5894D795F79F7F9E30C08008288A3F38 +:1059F000820413A433BC345BDB8E0A14A54D31DD65 +:105A0000A41A098E9120AF01D4B671B7C9C7188CFA +:105A1000519B74756312638C1950D434B83B463073 +:105A2000A0D84C4CA4C63C96B05BE2B7DBF86162F0 +:105A30008CAF0C48926EFCD6D63DE7DCFB330F20D2 +:105A400026ED2E7EEDCDB9EF7BDEE7DCFB4FC430DB +:105A5000634D1263530C8C19B3188BD733668A616C +:105A6000EC591DC050EE1D665E4D246353631A56FB +:105A7000B31C28CBCCD6A664067F6EC672194B9C8D +:105A8000E09D6484FAC4B57AAA8FD0F4290D66C665 +:105A90007C8DDE45E75319CB0F8BCC64DF8152CF71 +:105AA000D2B5D08F69C2ACADB05E817CA32711E0C6 +:105AB000355D920D9666F986925D2C85B13A2D0082 +:105AC000B1F83F93BB15D7D1F656ED877E7D71892E +:105AD000D62D004E4938C252B3617C7D51069BCE13 +:105AE000D8098B638A7522B4B3AD128E0FCFE0E371 +:105AF0007F5A14DE22C3F8C1E3B7E53AA0EE6E8305 +:105B0000D2C1AC8CA578A29768EF04384AC9952C0D +:105B1000005B63976827011CAF7448D06E74452FF3 +:105B2000C99F84E7335ACEA733F63326B12899B1FB +:105B300064AD231DD771167DA6671A6C1FD297CC52 +:105B4000622CC36A213C4C3C0178827D0E2D8C7006 +:105B5000B7C0F95886928BED49BAA1480BE063F0C3 +:105B600086B6C86DA671917F0FF537F1EF078CED02 +:105B7000EE96A95E85D5D267854960BDFA54F313C8 +:105B800088BFBA04A391CAEE6B850CE7D196A4DE58 +:105B90000DF3D8F56C7949C6E8F103560DED2B7974 +:105BA00023107432AECBEC4C81FF0B632AEC627392 +:105BB000186BFE2554FC1D6F879330FD0C8D806D96 +:105BC0003BF25383FADBB1BFBF9DD98DCC3FFE7E44 +:105BD000EB8C1D1BB4623DA4730573CF802324B2EC +:105BE000068901FE129897E8B3DB1643FBA23FA09B +:105BF000D30BB1A6E62DD02F55662E531695CC02A9 +:105C0000656238AC07ED89AF99DCC8577B4DD00E83 +:105C1000435335BCDCABE1FDF561CC857C3A1560C6 +:105C200006E5319BA3CE3691E6F1D23CF2211BF280 +:105C3000E324E6A1F5E3998BF6A3F69BC27A4D081F +:105C400033ED501AD26BAEAC19139F3ADBBCF5485A +:105C50007F5FA39D7DA20DA05378E4BA40FAD5E101 +:105C60007873E0B8F9344E1DEF5CA7619F4CC0C358 +:105C70007B897F9CA91ABB3B03C7B137A52CACEF2E +:105C8000D59744F8C7F5371AD9274087FF68645479 +:105C90009E69B4D0FAFFD99840E51F1B15AA3FDBD7 +:105CA000984EE540A395EA3F6A9C43E5BDCB22723E +:105CB00090FFEB3BE7B14F8C1CED37E17F4E8FCE71 +:105CC000311000F7CF1B9B8FF60B3EEA4F1EBBDD5A +:105CD0008BEDB8CFEF737A0E3EC8DC2DC9C4971B8D +:105CE0002C31A3E90FE733E1F90623D8120FE0E9DD +:105CF000588E44F30F4EE270B35547F3D9356C0715 +:105D00008E3F96A3E7F34FD75462BB3D86CFDB9F10 +:105D10000630ECA768CEBC17114FF638A8CFF2C3F7 +:105D2000FDB7F376FB645EAFEE576DAFB359685EB7 +:105D300095EE833A583F83F89DE657FB7F96C7E57B +:105D400030B4BF3B5553E41E031F1A1BEF4F7201C3 +:105D5000F870A11C2407C8459D4272A1F2A1CA7F18 +:105D6000BB6D1C8FA906C1E7E12007312407342E43 +:105D7000311EE44022BCD8199C67AF24E425541E90 +:105D8000A0443DAECA832A072ABF27829C4931FE20 +:105D9000737C2F845FD5F29495D3A5372EE21744F8 +:105DA000D76E9D055421F40742C6207C4F8E1DC638 +:105DB000153C6E6E184B7FDDB4FE8D7850F5C13802 +:105DC0007818757E3D2FBFEDF949BFA1DE46BE1D97 +:105DD000435F7D6655F515E75B9DCDFEA915F95529 +:105DE0003269A528284D9C6F42CF7F2C87CB8DCA66 +:105DF0003FBB6D8CDB4B3C67CA687DA79E67E49C0C +:105E0000AB18E9BDD4305E1F4A5FF55C017AEFCF75 +:105E1000B82F159F8C796C1698674AADD9BA25D9D9 +:105E2000CFBFBE89D72BD07E6DB62AB49FE735325F +:105E3000D15FB52723F592BC7C7146909D6116A079 +:105E4000E3D07103C9B757C32A5F8171ADB8D49D40 +:105E5000FE73CF16F41B5E3243B30EF6E5FB93D907 +:105E60008576CB3779E8AC04E37D3B74CC45FE8383 +:105E7000FD47521C630F824D41BB7415F41C4B63EC +:105E80004C7EEECBB312ECBBE239991900753E5053 +:105E9000DB328CAB7F3AC26DE4E3188371B5625C90 +:105EA000D38ECFEF45FEBA00FC6980F64F4C75D318 +:105EB0005926630B9ED3111E2B22F46EAC7F63C751 +:105EC00053A796017CA15D52D0DF2894CDD45EFD0E +:105ED00092ECC6756ACD859724F0737CEDCDCF84A6 +:105EE00041BDF3808E99605C61BB64F5C2FCAB3C44 +:105EF00011881956B15DF7D140BA5F6FFE50D8B125 +:105F0000CABD921B388655EE0A6EAFDE1B0CD73227 +:105F1000AD1F86F9B36C11B117EE006026B3DD44F6 +:105F2000BA6D8F416335A2B743F90ACD36E9C7355B +:105F30005C1F33F645DCDDC097F2F12F933E3273E0 +:105F400078B180CF01FCD9971CFF2ADEEA84CEFF0E +:105F50006C12CBF1C039EB8E9B2C2E38585D974CD0 +:105F6000E7F079A208CFF5610377919C1E952DE8A3 +:105F7000876DEE945DD8EEEC36EDD1C039EB3A2466 +:105F8000A645B8D3E0E678BA5681EDAB3A4D160592 +:105F9000DB8F1A980CE37D403713D271EA00D11FD2 +:105FA000E9EA92680B3F92F2FCF497915EB17E7A37 +:105FB00035EDE0FBB97080D3A7507E584BF46A965C +:105FC000587C009D7FAF7979845ED86FC1737FE87C +:105FD000413A57C0FE0C0AD25D263A5F00FAE0BC97 +:105FE000FAE39F240D98FDF49681DEBF52C743FF6C +:105FF00055B7A07725736D447FEEDBD2395CC83F7F +:10600000F8BD179E47BF37426F453E8C15FEF1C461 +:106010009AFE93B1B06059CC15E76AA89F91F00A37 +:106020004B053F418A763C6483716717BEFB18922B +:10603000A36FD1CB36E48B26DD40EBB350E18A0E63 +:10604000B7A20C0E262FDEF52AAC931F733DE91084 +:10605000CACBEF0C1664A726218FF86704FA3B1908 +:10606000C737D0F11C9EDFD96DF01A008FACBDC0D0 +:106070003EE20F4C477BECD1A39E2AD00F95AD4654 +:106080007F1CE6C37524602394EB9AEEDF9F91603A +:106090009CA4C4B252848D66AF8CF3B4E9AE8E9CDE +:1060A0001BE6912CEF52BF5DB6E9B48F94F8EF294F +:1060B000A87F9A96324758CAD7E979467AFE059D55 +:1060C000D0EFE3F97FE3E87BD5EF63AE29D117602A +:1060D0004EC405971FAE7756CD61E24FC885802B21 +:1060E000D7BB228DD079D51DD6043CFFA7C86791B8 +:1060F000C87FEF6827C0BE6A5B25A25B1DF20F9CBC +:10610000EB24DA37A81FF4083DF2526FFE84582CB6 +:10611000252B482AABEA96AD5E68AFEAE4FC348AE8 +:106120006F84FEA86EE3FA63141FB5011CE0A7D5C7 +:10613000215FA930D0FBA85F7FCCBA09FB7D713607 +:1061400013F4E67AA240CE881A007E19664A942596 +:1061500023C06E49DCDF52F5CA6D3B40D507AC3B2E +:10616000D36D64DA8075EF3860098267791282FA3C +:106170007FA753096AB779D383DAB34F5983E0DC39 +:10618000DE3941FD679FB107C1770E1405F5FFEEBB +:10619000C59220783803CE3396DF21CA1F264841A6 +:1061A000FD172AA6A0F98BD3A383E061B3C08FF0BB +:1061B0000355FFF4A28DFB41A1A58ADF1F5B83D7A6 +:1061C00051E3E29FCC095E6FB13D78BD6F4A977D88 +:1061D000E0F76BC1AF3F00F611CBDF82FFAF05BF29 +:1061E000BE0DFC7F84FF05FC7F2C3DE0FF63FD2B93 +:1061F000E0FF23DC0EFE3FC247205E41B8B3B1880A +:10620000CAA38D25547F2BFCF588754F89754F8B5C +:1062100075FF5A3CA9A5B36886E62B90D3793197D0 +:10622000F4A887ED6B060A310F30F496CC5A504033 +:106230001CEE538DB1688F2630F45B58C9D0DB1A41 +:10624000843B522C5B14B443FFFE1EB6FBDA65059B +:10625000F5F989CE8F23719EAB5F811C66E3B88F01 +:1062600023313EAEBDCE08DE02ED0AC00B0F8162C7 +:10627000207F06F41AF64F5561B79E4159D27648F1 +:106280008FF4A8397088DADFF2E882DB0F3407B5C3 +:106290005BB03F94355A37C5F7973BD5F9BCD4BFAF +:1062A0003655B2A35F7CF9C0BFC75560BFB6F7E3F0 +:1062B000567E0DBE3F3BF27206EA7527D861AFD914 +:1062C0003F8FB34B2760BEEFDAD44385316808DADD +:1062D0002436038AAB6C2B5B07FAAEA6B3B516F572 +:1062E000504DFA321D4B267D24F20DA06DD15FC2B8 +:1062F000E01EF077D5F379E44A98F735CFC9BBECC7 +:1063000048BFEE372271DDC17639289E5994C5FD0C +:10631000D645597AA2E3D5F637221568DFEC7983A2 +:10632000E35BEBA5739F10F0209484E74E99CE5D5C +:10633000F59586F0AFCE774F964CF32DEC9C1181FE +:10634000E7EAF3F0F596672934FFC2D415E5B8FF04 +:10635000D3094B7365F2F34031A35EBDBDB815F3AD +:1063600003351ED93E56BCB55ACCDBA3E37CF856A8 +:10637000EAE19EC9C01FA78B26D848E78B7E5559F6 +:10638000DC1F2FD43B52D12EF4999508E4E3478BC0 +:10639000522290AE27B0C4FAA23D7A0794D5ED7C84 +:1063A000BD3E4B6F24F25B5F7BB68C7E8B3ADF4A3F +:1063B000B1EE085F8FD0CD4574AA74379B711E3F34 +:1063C000FD78FDF22C9E2F3AED7EFF5EF453FAD25B +:1063D000C3AD48971E3DA3F8B606E88AF6A0AF3BCA +:1063E000B119F1A0AEB73C4BC4C9E91AA2ABAF5387 +:1063F00027FA2D6B6541FD78FC7C756FF07E2CEEE5 +:1064000073BF598676E905F0ABA1BA56D71087E776 +:10641000FF7457F0FE2A059E6B75DEB8B8007EAD9E +:10642000ED1A911733F177972A1F0AD153A5635FAD +:106430003AF7DBFA120C6E8C176B0FB5125F8FCE2A +:10644000EFF426A39F9FF89091F286B78A67553F95 +:106450002020EE6118C7E98A527235D3FDF67ED04E +:10646000667F3E6B22C6432514EFF5B1A10A34FEC8 +:106470004EF483A350EFFEF1195C77B81DFC3D5834 +:10648000D769EC5C741EFCAC612B080AEC7B789736 +:10649000CE2DE21333FAA715C23FFD5471E4C96053 +:1064A0005F9DEB3574BEDA8C30EED70A3DF9D9A189 +:1064B000E49F20BFD69E922D46F443216E21B88DD5 +:1064C000FB05759EE47F9A8BFE769B8EFC00D5EFD4 +:1064D000700ABFE382F0672FAC1FD293BF7A5C6271 +:1064E0004FC13E2A3BB7F52442BB336311F9AB4E93 +:1064F000B98DF28FAB7604FB0555EE60B8E64030FF +:10650000EC0CF11BD4B8ED44D688FF3013E38F02B6 +:10651000796E3CCAC107829E6A3CB27696351EE50A +:106520007DB35659A4E603104FF5C70F57E17EDD42 +:10653000B561568A0BD61D257C0E7EC1E38EC10443 +:10654000C6FD23C6F13AD8C9F9BB5E27F13803D896 +:1065500095E6334AEEF5D034E81A8E24BDC45811BE +:10656000CAC39AA53C8EB463CE15CA17845E0AB519 +:1065700097DFD70EC8D101FAE17C16F737F3F5CCD7 +:1065800081766A6D8495ECD63423F7B70B1EF6D866 +:10659000900FA6417C6C08C8674F330F49D86FEF46 +:1065A0002310E266FAE3FBC55A8B2E3AC0EE31B6F1 +:1065B0009EFAABF38326E1E36F35BF05E637FBE7D1 +:1065C000077C4721BE3FCFB1923D4E5ACC582FC9D0 +:1065D0006303C9A37A9EABC067988FC59C09D2ADEF +:1065E00076D7EB940776B25E8A470A23F93E0A71A2 +:1065F0003F0887F19265737CD9B3B9FE589B1D6C37 +:1066000097BBB2ED5236943BB21DBA6CD26716E21C +:10661000CBB58257C04F891F1843EFAE7997C75546 +:106620009F831CA09CDFDF2029A9417E10E7EF7A21 +:106630005EC5AE304FFF5CC483CBDE9B1E877114FA +:1066400097ABE5EB4C4A6A009FD6239F035E2A2D49 +:10665000553F42BFDBB12E4EC17C7F3DF2FD7444FD +:1066600023E7EB58F887F1C5283EF704C3F0B70BD2 +:10667000F9AB8E19AC6847EA3B43DBAD5ACCEBA4CF +:1066800064831C84FBE52049F065B34372A3DE6F8D +:10669000BEA1E579AC5289F256F74025F225FD619D +:1066A000BFCA796E9CFF1E00311E62DB63496EA873 +:1066B00011F4C8DF8BF3DEA3F5BE8E727C52E7497E +:1066C000C67CCA49A7D18AF32F65E070807E296510 +:1066D000BD54F687D775786972D7548C9B3F701874 +:1066E000288FD3BCA12502F56926DB60B9908EC640 +:1066F0009D1DB8993DBE5F018CC42EA874A1BCD06D +:1067000056118772BAEEC8B6CFCBCE1D7F7CCD1F97 +:106710003AEEC290A2E617ADFA78CE36BDE9797EA0 +:10672000FAD5334F3AEE57A5D708FD60CF53000F87 +:106730004BD8501EC6352ADD8CF06F2CBAA9F84C08 +:10674000D20DFD1451067689F44B283D55FCD6B187 +:10675000061DCF7335BCB714FADFB741A3A07F384D +:106760008ABEB7A083D7C49BBC1112C59BE3D14599 +:10677000A5874A9F33D17CDC99FB65CAD3FD5FD3E3 +:10678000A52BDBF1D0D7C963A8FC8D276FCBD785AC +:10679000C86588FCA9F472AC8B243953E958AB3036 +:1067A0008A5B6BBB23AC6EE6A79F19FE21FDF09EB2 +:1067B00082F231ED12DB297D13391CA07B8D50FA5A +:1067C000006FD851AF3F951D6C8754BA8DA77F5489 +:1067D000FDF521F39EB448743FC0E5F3970637DE1C +:1067E0002FAAF703EA3DC061A1F742CB0FC1EFC06A +:1067F0007B972DE97D13D15FEBD7ABF3F0FBC70F90 +:10680000D7F74E5D0DE33F9CC7CB7EF4D302607B90 +:1068100018CFC37D38C9E042BC7D28CD9C8F76FC63 +:1068200043E9A1BB381CAF57105E1A3FDF0270BFAF +:106830004ECDDB3D2AF4B09BEF63E9EC7CEA27B157 +:1068400037111F8AC44A681D498A2982FD7CF88B4A +:1068500019594DCC7FFE966CEECFBA55FDAEE6B120 +:10686000FF41A23CF672300116CCB7CF7FB6683A32 +:10687000D49FFDC7141BDDFFAD095E1FED6832E537 +:1068800007B7D13CDFFF6A48B722C3BFAF11FB9700 +:106890007F8DD797CFA078A252D0D01E3393C7B1A7 +:1068A000EE9428B447AA7D1A3E75D81C98BFBC0444 +:1068B000F68BE903E0994F2605DAB7D7F7FD3A0DD5 +:1068C000E7A9D4BB32AD184F363F9F847E40E5BE6A +:1068D000C7D3C82FDDB7390DE38BCA965FA7D90997 +:1068E0000E77507CA3E5E7BE72F0CE3D5B02FCE084 +:1068F000EA5C99F65F6A7CBD00FDD345777CF618AB +:10690000E6C367FCA34479B1FB59EF636837CBD288 +:10691000B91CB1ED46D2EB301FDD3BB6CEFCF15ECB +:10692000D4E7A7D33FD69543BFEBD95AC24F1973CB +:106930003F118FF9B04D12E5C3FCFDA7D23DE68AA9 +:106940000D923E2116ED61B44D56705C34EDE3813D +:106950004DB61EAC2F7B98D72F32B8DBFB709E67ED +:10696000F5D65605272A995E12702F7C3D9BC75D90 +:10697000CB9F90C81F57D799F14C5C73E039AF0B90 +:10698000FAB31BFF46FAED27822E3F7AF8FD371344 +:1069900014BC4F72DC443DF2DED31752517FE5C781 +:1069A0005CCA403E9FA177ECACC273B718287F98B1 +:1069B000939928C743FFAC9FCF7B0ACBE50FAFD895 +:1069C000598579D01D468AA3D4FDAD91140DC69B7F +:1069D0006F34FFEC01C4DBC5A78DE447AF69BE2D62 +:1069E0009E8D21A76AB91FE8AFA431F652A391CAC0 +:1069F000971B2D4C81231E6C4C20F85F1B152AD948 +:106A000012CE5F6B44BC3ADE7CD910EF2BA0AF7284 +:106A100036C17CE06FDA4CF6C93980AF19B73B5B01 +:106A2000368B73CD80F13657F202C443CEE6D53DA6 +:106A3000E88AEA73787CF476DFA624F2A31F3EB7D7 +:106A4000BB0ADA17E794A4E078E3AE6B14E7BFD192 +:106A5000F57819E5F55B0CFC7CE2DC179F4E8BDFCB +:106A60008979D7B774147FD7EF3AB77B33942B9FCC +:106A700058AD0FE4F76F7ADE64B19F5BC9D57878C3 +:106A8000F8F672F5EB24929F1690AB8CBF5EAEEADF +:106A90001F5E4FF87B28A764510EECFFA2CE9584B1 +:106AA000F27471E6F788CF5DC725C2BFAAC7D5F1DA +:106AB00045E2BC351ACF13E40F0A3DFE25447E881B +:106AC000DFD7BB3E4D437FF8CBCEA55F7BEE238D5A +:106AD00078838E792D2395A1ED797A478A15CE9703 +:106AE000A7E17EF028FF55DCCFA9F7EDF88779E123 +:106AF0005A613F9DB0B1A818B47F92372C13EF397B +:106B00007E78498BF117C4751F05FB97ECA3003BFA +:106B10003EDE7E6F55D6E13C5ABFDE9D7D46C3BC4E +:106B20000176FBCE8130E60D587724EE30224F43BC +:106B30001CDA3589F402D20DEF657C5D335B10BE43 +:106B4000A4E774F41D81F88AE755989CE73FE7A510 +:106B5000AE2B99A86743CF5B77F40AF1476DE7E363 +:106B6000D7243AFFC24BDACC5B9FFFF57D573291B9 +:106B70007E977403791847F9F403994887BA635CE0 +:106B80009F7F5B3CA8F5559BF43CBF2759281E2CE2 +:106B900090AF521CEF3BC5E3F8BAAE3DA44F87BBA4 +:106BA000793EA55ED35B188FF98786733DA8CF86A3 +:106BB00013787C05F3DB116F7353841DD40E252DE0 +:106BC00006BDF6CA083FF0B8EE22CAAF1EE7F1D400 +:106BD000D27BA4CC70867EC5659467A82F5B97BCDA +:106BE00011F9FCA27B226682D8DB99FF5347F9B7E3 +:106BF000D7C22D32F9AD501B40BF9173B865FE70FE +:106C000086A9717A38B307F4ABD72B3FA1F8F834D3 +:106C1000BF27ABBF9DCB133BCAE5C9B9E1757D4228 +:106C2000C07CBB519E68DFDC7F5CF4DAFF905C7651 +:106C3000DBECDD2897E1A80B71BE8428B724897EA0 +:106C400079FE7B4073B788C78B646AAFEF94D92411 +:106C50001C931041F7F5456CAB16FDDD45CC339721 +:106C6000BF9319F8CD77A1BDF835391BDF6381FFDC +:106C70004CF7C785618ED435E81F692481574FCE04 +:106C8000E2407B26DE79CC9525B2634393C2C94F9F +:106C900059B8C4598AFB1DD10F5ADE0FE6213F8B2C +:106CA000B98732F13E93798732F19E53ED77EF6BDE +:106CB000E10D64179927E7DE8075C272B9DDFC1C0F +:106CC000EF9F419FD48BFBCF02F9C6331847AD39F4 +:106CD000CEEF09FB35C91FE07B2D17E019E97A05D6 +:106CE000E86A47FBE360763BCACFAC896E949FFAB3 +:106CF0008312C3776B755D8616CCEBD4E906E29000 +:106D00009F3777FE418FFC5CDFF1BE5E9985E379AA +:106D10001E08FC750DE2B75ED82F67E76D1F60DEB9 +:106D2000CD798A5B51A7F67D8AEB6BDA0F51FC5E59 +:106D3000CBBC14BFD7B605F3CB7002CFB387CA471D +:106D400058AE42FA528517EEE07271AFCC1A28DEC7 +:106D50001779D38509F1E48FF8C7093F51BEF218BE +:106D6000FA2F83D325AB04530D86B936A05FE44ACE +:106D7000E3FECCE0EF5ECEA920BDE2CEF929BE8BCA +:106D800011FEEEC24DDBB472C07E1676F33CE160BC +:106D900018AB3C42F4764C413A446695987373497B +:106DA000AE32E99D8F86E73543CFF1A4C8679EC612 +:106DB0003C4F867FDFC589895C8F3137F14F8F86E5 +:106DC000AFAFBE7B51C7AFC89582E2A53512CF4F9A +:106DD0008DA757F01EA55CDCA3948B7B9472718FFA +:106DE000522EEE51CAC53D4AB9B8472917F728E5D2 +:106DF000E21EA55CDCA3948B7B14AC3F8D5BA5F7F6 +:106E000070CFEF44FBD9833236D90FF7C784C093D4 +:106E100083FBF7C748C1F06489FAE7E43EBFD39526 +:106E200081794C8B906F2502FDAF8B269E5FEA8A9D +:106E300070FC1DE2B97C61D33EFE1ED14EEF59F2CB +:106E4000639696A27C0DC71A18EAA1865CC7BC5C43 +:106E5000A0FBA9530B52B7917E3459F19EBBFFBEE4 +:106E60003BA2282FF796CC6458725E7AF6861C8077 +:106E7000E79925E25BD013DF2951E3499867413751 +:106E8000BFCF28906BCB71FE35934CD9A87787B2D2 +:106E90001CC5B901FC583879552AFA413D3AE50339 +:106EA000CCA7BADED5318CA3D4FC9BDAAF276BDE3E +:106EB000521CB7303D654316EA1B102ED46F763D49 +:106EC0006BC37DD935E15213E92B458BF2BF54F0EA +:106ED000EF7C85FBC35EBDA28DC1B83D6C5EAC4B43 +:106EE000E1F755E5E2BEAA5CDC57217DDEC1BC19A5 +:106EF00094EF413D96BD508F65E87BAE67724A5670 +:106F0000E652BC3D9414F81E6C11CA15D73349C81B +:106F1000CF3B05DF26083DD3935D524DFCCE3C347C +:106F20004F8DC8BF5DD105DFE3A9E3FCE319957779 +:106F30007F87EB6716A5E7EF5DA73017BEA7BDFB00 +:106F4000D549944FF2B9352E5D14C020E3A8BFD8BF +:106F5000AB3CBE65095C5EEE3E1C4FFD9A441ED400 +:106F600019D39B16837657C8950A1FF90B7FE7E361 +:106F7000CC0218CA63123F9FF3EEDEB468807D92A4 +:106F80004983F971670B6FEF1372E79C2EE613E7E5 +:106F900061464F12D263F0F8AB490F00BCC5ECADAF +:106FA000E0FADE9B467A9A79D3F0BDD015C9731604 +:106FB000DFDBAE3A92B50CDFD75ED17976235C7316 +:106FC0002487C3D2A1B396C0F6899E247C8FBBEAE6 +:106FD00048F6327C9F7B65E2A1DDD1D60058F7CA26 +:106FE000596CD73F9AB32C1FE06283FB5423F2CD38 +:106FF000BF72FE321DECB880F8A9E9E2FEFAFC830C +:107000001D575F417BDC1141F7F507729389DE4D17 +:107010005DFB9F407EF31DD2911C6C69FBC3EE5F4C +:10702000513F03A5518A0D9E1C4CB934E4FDC77D28 +:10703000B86E71B8E70B84D7E7FD80F6513C81CB81 +:10704000F3C6BCF9CB503E7D1D077F89F2571C0566 +:107050008E2CEEE76513D1A7FAF0CC7CCC03F82296 +:107060007ACB70FEBADF1AACC8A7D587E3E7635EB8 +:10707000A02397E7A7AB6EDF9A84F65573F4A57D3E +:10708000BFC23CE56F4D743F531FC3FDBB6AB939A6 +:107090006F35D16FCF3E7C37E27BC944F7A45530C2 +:1070A00007AE57B56F06E5D58FFDF9E332A44381EE +:1070B000BC6B1FD67FB1D7A4413CF4E9ED51DF434F +:1070C00039ECD3519C5925E0AAFE097C3FE10385A8 +:1070D00044BFD8AD49685FAB27FCC35DB8EF6279A8 +:1070E000EB6E8C73D87E03DD155C7A09F006E32E17 +:1070F000B5EAE895AAEFA5082DF2CB15696BD94E34 +:107100009CBF95F7BB62DA4AF874B5DEC6703DE8FD +:10711000C7505F5D91B605D55F6ADD9F8971E8E56F +:10712000DF16533CAAF2F9489CB1D710640F4913FB +:10713000C489F71264665DCC0C76B64A80978F3CA2 +:10714000E7DBC9FCE32FB7E9BC7AC05195816DC07C +:10715000F7C1AA3C5427FEB008CF57AD694E437F14 +:10716000A52A7BA00CE5E292891913A0DFDBC25EA1 +:1071700055B7AF5F8C7EEF78FBF98BB03F5F0A3974 +:10718000FCB2D3E40EBC1F0C2DFFD8C8947702DEEE +:107190000DDFDF6020DF5D9DEF6DBDA716E3B3BAA5 +:1071A00018AE3FCE42FF36D0633784DE5BBE2EB8CA +:1071B000FFB5DC18FE2E553F9086764F9DDF97ABCE +:1071C000EAB58134D457A1E38A65A16F5E9648DFA2 +:1071D00054B74BE764C053B5D1E5C6F73BD5184C5F +:1071E000F2736A6F4A7C5C429EC03B8C7D3C2F9957 +:1071F000CE5DDD66B29B605C4DD84024FA43B5118C +:107200000391E8E7F88ECAAC45902B364ED067BAAA +:10721000205940DEB1CAA3B39B32C7A033FA4DF860 +:107220003E07FF1BD6DF95379DD6ABEC0CA7F59834 +:1072300065200FF9B47257F0383C972540FE7C9DCD +:107240007BE202E3F164B1EF41E91CC9C9E09F3F71 +:107250004A42BA576BD806BC47BC2CF1EF1E00A6B9 +:10726000EF1E2E8BFBC8EA3F99C3905F2E7F594BD0 +:1072700072EB930648AFBD7BA484F4814F37407A0C +:10728000ED44DEBDA4C77CD10365A8A7DE3D52C195 +:10729000DB270D9429D0DE8630B64F6564EFFF2BD7 +:1072A000CF49FAA358E6EF1BD81E9D85E78136F536 +:1072B00037525CA15302E3EE3FE6A9F7367AFFB9F5 +:1072C00065BFDCF89872B01DE5B0D24CF91CF09F98 +:1072D000DA5E413F6F699C15F3E295388EF3813E8B +:1072E000F0FE2F36E67A05D2675994A3202F17EFC8 +:1072F0001907287E00AE263FBDEE77068A23077564 +:1073000043FB504F65463916E6017FD5EA7B37A22D +:107310004B7F5537D083F77E8B64AE8FD87ECE57A8 +:10732000BE8C3DFC3B09717FB854E01FEC166B46E8 +:10733000BE90387DDFE83CFC0EEA155F6F0AE9E39A +:1073400050B9B9D4F95424EA873360C75D0171FE9E +:107350009915FBE99E7E09BECB80F2810DC1FC3000 +:107360007CE3A714EFB12702EA910FB707C3A17C12 +:1073700084FCE80DD23B2E92A76773B91F5633BF2A +:10738000B70EF13002DF0DB01C009F088143FAB345 +:1073900012EE273C8BFF8D789CEAEDA7F8FC207F4E +:1073A00017DB04F68BE08E70BA37D61C04FB14CBC7 +:1073B000ED13DA859AC85ECA4BF93A0C743FF2684D +:1073C000D7A7F49E11F890F22F355DAFC661DC7E31 +:1073D00000E3845CB28371F44EA5A32B0EE30DB5DC +:1073E000BE56E34913EFF1C94F57EB9DB2370DF786 +:1073F0005F23F56662FB01B1EF5A0DC032C262DF56 +:10740000129777D625933E0FA5DB0EC1AFA017329A +:10741000E99DC5519E1750F54095D02727B03E8372 +:10742000CBBD45BD5792F0BD5CF898FA213E4FE8C0 +:1074300037D640799BED797CDFEA789A97E795A873 +:10744000BDEED895CCE919384E19790739A2875283 +:10745000FC7A05E53F81E4FF515D1C9CAB7AB76483 +:107460006D423D55BABE10BAB355DAD585942F1387 +:10747000EF3F43F715CA4756D80BE9494D74416CA5 +:10748000C07C97215C4FC8223D43EFE81F8C7DB242 +:1074900010F3133F2BDD46FC3C626F02E51CCFB3BB +:1074A0008BEB71149B9B9AD17CBCAAA17963FC18CD +:1074B000FB08DD6795A3B9304E195DAFEEF7B24911 +:1074C000DDDF7CDDC4403C2C595F3811CA55C6BF96 +:1074D000160FFCBC97BB0C5EB4AB55A5AB37468D05 +:1074E000C137A3ECC1AE00FB351DE9EBA67B8DF1E6 +:1074F000F61F5AD64ADE7ECC133190AB56922F90AF +:107500009700BB30272F24DF50B9621AC69DCCB13B +:10751000621ADA1990AB32EB1871257E59A2A1B725 +:107520001B2E2A43F7733E8FE749E7E47179E9B6EA +:10753000D97DA837C7FBDEE2BFC53EC6FBDE2251C0 +:1075400033FC1ECA5B625C8482F740050BC279BFC4 +:10755000E3260BE66D068F5FA7BCEEE063E625FC35 +:10756000BEC0CC26417B4FC2AC96403BB275365F65 +:10757000273C87FB2DF5E9BAAFCF0B65448CE4853A +:10758000C86FC808A77B125FE7E764B706BB732D17 +:10759000789FE1EB85E810E4A9FECFFF1D87F6D5C3 +:1075A000D7FD09BD07F3DDF894DE896D16EFF44EC3 +:1075B000748A7756BD4A047D1757F47121F6DB2291 +:1075C0004A7F7E80E789D5528DFF03E2DFC9B3C7CA +:1075D0008E7F631CE6C0BC80123F561E25302F9064 +:1075E000AAE579012C312F909ACAF30208635E0054 +:1075F0004BCC0B603DE60510C6BC00C29817401886 +:10760000F30258625E00EBBF10DF3F0C8262E2F9CA +:107610004A33E9F5B5F8BE1DF0B7F638BF775ADB47 +:107620002AD3FD2D7EFF80F66DD4BB9976F16EC610 +:10763000B38DEEF1EA3B642B92A85E377412F338F7 +:10764000F58724EB7AD42B8D4B68FDCDDDB91F94E3 +:10765000627DABCEAA51888F381D9B257AA75FDD4E +:10766000DD4A79A7FCF8E37AAA6F9318E649EF356B +:10767000F038D729436D16DD83921FEC34F452FCA9 +:1076800051734052CA03DF69CCB9467A40BD4FAE50 +:10769000E04DCCE93129E563BC031979772EDE4D45 +:1076A00057E03D33BE17976FD0BB7E2704A41390DD +:1076B0000F77F0F7CF16F847F21EF2AEA9BAFBD05B +:1076C000467C0F157ADF3CF23D5DC8BD73D96C7105 +:1076D000AF6CE3DF57143D5D7EB003D61BDE6A203E +:1076E0007FA321D7F120F2D1499D9DF223278F9BC3 +:1076F000282E3ABFEDB6A0FCC85096A37A36E59B7B +:10770000A650BE628D4E227BBCA028251EF1B8E09B +:10771000948EEC4E4F56492DF65B334BA17C548131 +:1077200081FD82E611EFA5547A1434496E0DC02B09 +:107730009895DED92F073461BE725067DE84EF9AC8 +:107740009633FECE41E59B35DB24E21B4C10203EF8 +:10775000CB043E9777FFFE3ABE635869E07E6BA28A +:1077600086DF5F276EE1EF191E640E3DDAD955C83A +:107770005D32D9C7DF0D40BD237C4A12F7CB957827 +:107780009C7FC5691DBDB72D88FF719A83EC743E3F +:10779000BD6390BCCBE49B778C2F3FA1EF184EEAE2 +:1077A000B85E013C523CD4837C4979190795A71BEC +:1077B0002BA9AC13DF438C7EFF3F7416E3C4C4F8DF +:1077C000082BEAB971BF770BFBFAEFBD768AF76B2E +:1077D000899ABE6C05F1F127B315F1A1BE13ECB681 +:1077E0009534239DEC91CC65A1EFC14003025E0B63 +:1077F000F12012E6B53D76FCEE68E8B864A177C9E1 +:10780000A3F4E3B6C7F09D487DAA649114CC7F6FC2 +:107810002D88837D174E4FA67DD777F2FC286128EF +:107820000EF3E79C5E91598EC3B373FDF5C5426EAE +:107830007CD09FF3C977DDC86FDF206FBA17FBBB21 +:107840009889BEA7A63FD84FF11D53297FAAF2CD34 +:10785000705B7C0BF2CDEF67F338B2B4F47D1DDAC8 +:10786000FF9E6CC709DC4759F9B5C7E2E87C63E7BE +:10787000AFD477EAA1F9AB40FDF9FFF13EFD9DC61B +:10788000062ADF6B5C47656FA38BDA03F4FF7F8EFC +:10789000A3FF43F39FE7B05F68FE93199528B29F5B +:1078A00020DF3CDF1C92EF2C9AF0C026C0DF82ED77 +:1078B0007A2B56A9F94F7C3FBCD64CFAE0F2EC315A +:1078C000F39E2ADECC94271D66A62CC4FFFCF4147C +:1078D000AD06DABF107450F38E281F783E940F2C3B +:1078E000513EB45ABF7CBCA00711CEE176DE45768E +:1078F000DE4474DDB81EF407C02B9925487F5C0D6B +:10790000D11F1070DC47DF55751B18E609D5779439 +:10791000F3A1F82A6B0C7DE2E1FA646A98E725FA94 +:10792000DEBF2E8CDEE79E14EFE14E6EE6EFE1CA7D +:107930005909AD3B865E89447AAC9C3074F679E88F +:10794000BFF2D766F257364EAAC8FB5BF4CAE06CAA +:107950008E8F67F17705B45FF7BB024F48781FBA87 +:10796000E67E66433AABBF2B102FEEB3BFC5EF0ADE +:10797000DC3667E237FF5D81CC39F1A581BF2B9002 +:10798000D93989C3EAEF0AB0F8D2717E57207B4E0D +:10799000EEE8DF15983D87C739E3FDAE00F8937335 +:1079A000707F3A9BFD4E2C13C53E43BFA73D2DEE85 +:1079B000EF7A348E522C0B235D5AAAD7B873B07C61 +:1079C0005BE3F939D6033FE7E33E0A9FB2DD9E0E43 +:1079D00070A2C1437AB227CB5E80F583367B21AE9D +:1079E000139A3747DA627C0FFB5984EDA1EFAE544E +:1079F0007AAE98C3F9FE0151CE6D1AFB7BF207E611 +:107A0000F0EFD56EB56FD8EF7DB82F75FF6CEB8AB0 +:107A10001C92A72CFB32B1DF522C993926E8FBD4FB +:107A2000D17CE612FBE2FC05FAACF83CF707A94C66 +:107A3000D3BAA3D17F9CFC883B1AF73BB979C884A1 +:107A4000DF41BCE81A32A17D7FF1E12113D6BF6886 +:107A5000E7EF9543E77F710EFF4E206DEE108D9F8F +:107A600006FFDD4BFEF95034FA4F6995E737D27DBA +:107A7000CB8199645FA609FB32ED91E99D03C06F4C +:107A8000D39E8BA2FB6C961F4BEDD5462EA7D58FB0 +:107A9000941FE950E8BBADE2F301FECE4C37EC3B5E +:107AA000C8FFD20EF3779700239E0EE808469E4546 +:107AB000FFCAC9F8BBCBC9426FA09F560A7AC15909 +:107AC000F9E675BAF7C7F1381FDED122FF75EA86ED +:107AD000C5F769168C43572D59DF4371E18E917AB2 +:107AE00011671EDA887133F86F41F5D5E5AFF7A05D +:107AF000BDA939105CEF6CB846F12BF86F41F5F772 +:107B0000FFFC9C9EFF7E41703DD07707F29B4ADFD1 +:107B1000933ACF4C8CF34E3AC3ACFCFDBE877EAF9C +:107B2000A4457CFFBCE79FE7E7F0F7A29CDE30DED0 +:107B3000FDCDF8A389FABBE6B37494875B95AA5E82 +:107B40001AF9FD133D73517E6F5104E99D7A115767 +:107B5000D5955BC8CE27D619497F15C8615684478D +:107B60007EFFA448167ACA43F2DF775734E5F1E87E +:107B70000008C7CCA27B9FB8260E0F4D34907E28FC +:107B8000D094D4EE87F24D4DF077EC2FA07E90513B +:107B90007E793EB55EEFE1DF896B955C8C739B244B +:107BA000FB73F8DD639324F2885566BA2F18C4FC82 +:107BB000229C677BB4FBB90A5867FB3D19E41F0F91 +:107BC00032AE4F5D4BF8BDD5F6E892D2D5D8BEF4B3 +:107BD000766A3FF297942773D07FAA0AB3A2FFB4C4 +:107BE000DDC6FDEBED8BD3A9FD98A4ACC773BB1E1E +:107BF00061B4CEF6C5FCDCDB9F9C2ABEBF709B50F7 +:107C00009EB737DB27E17DD47C8BE30CD26BB2B817 +:107C10008FDB9E0CF5503E23952C7D10E799C5F720 +:107C20005B6753885E2797DEFEE43E85CC8817EFBE +:107C300085EA1745501CFCBF93011353F046000022 +:107C4000000000000000000005001500000000001A +:00000001FF diff --git a/firmware/bnx2x-e1h-5.0.21.0.fw.ihex b/firmware/bnx2x-e1h-5.0.21.0.fw.ihex new file mode 100644 index 0000000..e78c863 --- /dev/null +++ b/firmware/bnx2x-e1h-5.0.21.0.fw.ihex @@ -0,0 +1,12855 @@ +:1000000000003BB8000000600000068800003C20B3 +:100010000000192C000042B0000000AC00005BE0C2 +:1000200000008DC400005C90000000E40000EA586D +:100030000000E4140000EB40000000940001CF58E1 +:10004000000058E80001CFF0000000C4000228E0E2 +:100050000000F978000229A800000004000323280A +:10006000020400480000000F020400540000004594 +:1000700002040058000000840204005C0000000636 +:100080000204007000000004020400780000000078 +:100090000204007C121700000204008022170000F6 +:1000A00002040084321700000604008800000005E6 +:1000B0000204009C12150000020400A0221500009A +:1000C000020400A432150000060400A80000000489 +:1000D000020400B802100000020400BC001000007E +:1000E000020400C010100000020400C42010000030 +:1000F000020400C830100000020400CC40100000D0 +:10010000060400D000000003020400DC0010000020 +:10011000020400E012140000020400E422140000B3 +:10012000020400E832140000020400EC4214000053 +:10013000060400F000000003010401240000000098 +:1001400001040128000000000104012C000000004F +:100150000104013000000000020401D00000890603 +:1001600002040004000000FF02040008000000FF79 +:100170000204000C000000FF02040010000000FF59 +:1001800002040014000000FF02040018000000FF39 +:100190000204001C000000FF02040020000000FF19 +:1001A000020400240000003E0204002800000000B9 +:1001B0000204002C0000003F020400300000003F59 +:1001C000020400340000003F020400380000003F39 +:1001D0000204003C0000003F020400400000003F19 +:1001E000020400440000003F020404CC00000001AF +:1001F00002042008000002110204200C000002008A +:10020000020420100000020402042014000002195D +:100210000204201C0000FFFF020420200000FFFF5A +:10022000020420240000FFFF020420280000FFFF3A +:1002300002042038000000200204203C00000000DE +:100240000204204000000034020420440000003575 +:10025000060420480000001C020420B80000000131 +:10026000060420BC0000005F0204223807FFFFFFE5 +:100270000204223C0000003F0204224007FFFFFF6F +:10028000020422440000000F010422480000000084 +:100290000104224C00000000010422500000000074 +:1002A0000104225400000000010422580000000054 +:1002B0000104225C00000000010422600000000034 +:1002C0000104226400000000010422680000000014 +:1002D0000104226C000000000104227000000000F4 +:1002E00001042274000000000104227800000000D4 +:1002F0000104227C000000000C042000000003E840 +:100300000A042000000000010B0420000000000A85 +:1003100002050044000000200205004800000032F1 +:10032000020500900215002002050094021500202D +:1003300002050098000000300205009C0810000033 +:10034000020500A000000033020500A400000030F8 +:10035000020500A800000031020500AC0000000208 +:10036000020500B000000005020500B40000000610 +:10037000020500B800000002020500BC00000002F7 +:10038000020500C000000000020500C400000005D6 +:10039000020500C800000002020500CC00000002B7 +:1003A000020500D000000002020500D40000000198 +:1003B00002050114000000010205011C00000001FB +:1003C00002050120000000020205020400000001F5 +:1003D0000205020C0000004002050210000000406F +:1003E0000205021C0000002002050220000000138C +:1003F0000205022400000020060502400000000A59 +:1004000004050280002000000205005000000007E3 +:100410000205005400000007020500580000000813 +:100420000205005C000000080205006000000001F9 +:100430000605006400000003020500D80000000665 +:100440000205000400000001020500080000000190 +:100450000205000C00000001020500100000000170 +:100460000205001400000001020500180000000150 +:100470000205001C00000001020500200000000130 +:100480000205002400000001020500280000000110 +:100490000205002C000000010205003000000001F0 +:1004A00002050034000000010205003800000001D0 +:1004B0000205003C000000010205004000000001B0 +:1004C000020500E00000000D020500E80000000742 +:1004D000020500F000000007020500F80000000718 +:1004E000020500E40000002D020500EC00000027DA +:1004F000020500F400000027020500FC00000027B0 +:10050000020500E00000001D020500E800000017E1 +:10051000020500F000000017020500F800000017B7 +:10052000020500E40000003D020500EC0000003779 +:10053000020500F400000037020500FC000000374F +:10054000020500E00000004D020500E80000004741 +:10055000020500F000000047020500F80000004717 +:10056000020500E40000006D020500EC00000067D9 +:10057000020500F400000067020500FC00000067AF +:10058000020500E00000005D020500E800000057E1 +:10059000020500F000000057020500F800000057B7 +:1005A000020500E40000007D020500EC0000007779 +:1005B000020500F400000077020500FC000000774F +:1005C0000406100002000020020600DC000000010A +:1005D000010600D80000000004060200000302200B +:1005E000020600DC00000000010600B80000000068 +:1005F000010600C800000000010600BC0000000069 +:10060000010600CC000000000718040000A900004B +:10061000081807C800070223071C00002C2D000043 +:10062000071C800038A20B0C071D000028EF1935AD +:10063000081D681052FE022501180000000000008D +:10064000011800040000000001180008000000006C +:100650000118000C0000000001180010000000004C +:100660000118001400000000021800200000000122 +:1006700002180024000000020218002800000003F5 +:100680000218002C000000000218003000000004D6 +:1006900002180034000000010218003800000000B9 +:1006A0000218003C00000001021800400000000495 +:1006B0000218004400000000021800480000000179 +:1006C0000218004C00000003021800500000000057 +:1006D0000218005400000001021800580000000435 +:1006E0000218005C00000000021800600000000119 +:1006F00002180064000000030218006800000000F7 +:100700000218006C000000010218007000000004D4 +:1007100002180074000000000218007800000004B5 +:100720000218007C00000003061800800000000290 +:10073000021800A400003FFF021800A8000003FFF9 +:100740000218022400000000021802340000000019 +:100750000218024C00000000021802E4000000FF32 +:100760000618100000000400021B8BC000000001EE +:10077000021B800000000034021B804000000018B3 +:10078000021B80800000000C021B80C000000020C3 +:100790000C1B83000007A1200A1B83000000013806 +:1007A0000B1B830000001388021B83C0000001F4B0 +:1007B000021B1480000000010A1B148000000000CE +:1007C000061A1000000003B3041A1ECC0001022711 +:1007D000061AA020000000C8061AA00000000002AF +:1007E000021A1ED000000000061A1ED800000006E3 +:1007F000061A36E800000004061A36E0000000027F +:10080000061A500000000002061A500800000004FA +:10081000061A501800000004061A502800000004B0 +:10082000061A503800000004061A50480000000460 +:10083000061A505800000004061A50680000000410 +:10084000061A507800000002041A404000020228F4 +:10085000061A400000000002061A400800000002CC +:10086000041A62C00020022A061AD1000000000209 +:10087000061A200000000124061AB000000000281B +:10088000061AB1400000000C061A330000000014E4 +:10089000061A33A000000068061A81080000000252 +:1008A000061AD1C800000002061AD1D800000020A4 +:1008B000061A249000000124061AB0A000000028A7 +:1008C000061AB1700000000C061A33500000001424 +:1008D000061A354000000068061A81100000000268 +:1008E000061AD1D000000002061AD25800000020DB +:1008F000021A292000000000061A30000000000241 +:10090000041A30080005024A061A301C00000009CB +:10091000061A320000000008061A5000000000020B +:10092000061A508000000012061A40000000000263 +:10093000061AD0C000000002021A2924000000009C +:10094000061A304000000002041A30480005024F29 +:10095000061A305C00000009061A32200000000868 +:10096000061A501000000002061A50C800000012BB +:10097000061A400800000002061AD0C80000000253 +:10098000021A292800000000061A30800000000228 +:10099000041A308800050254061A309C0000000931 +:1009A000061A324000000008061A5020000000021B +:1009B000061A511000000012041A401000020259D9 +:1009C000061AD0D000000002021A292C00000000F4 +:1009D000061A30C000000002041A30C80005025B8D +:1009E000061A30DC00000009061A32600000000818 +:1009F000061A503000000002061A5158000000127A +:100A0000041A401800020260061AD0D80000000242 +:100A1000021A293000000000061A3100000000020E +:100A2000041A310800050262061A311C0000000990 +:100A3000061A328000000008061A5040000000022A +:100A4000061A51A000000012041A4020000202679A +:100A5000061AD0E000000002021A2934000000004B +:100A6000061A314000000002041A314800050269EC +:100A7000061A315C00000009061A32A000000008C6 +:100A8000061A505000000002061A51E80000001239 +:100A9000041A40280002026E061AD0E80000000284 +:100AA000021A293800000000061A318000000002F6 +:100AB000041A318800050270061A319C00000009F2 +:100AC000061A32C000000008061A5060000000023A +:100AD000061A523000000012041A4030000202755B +:100AE000061AD0F000000002021A293C00000000A3 +:100AF000061A31C000000002041A31C8000502774E +:100B0000061A31DC00000009061A32E00000000875 +:100B1000061A507000000002061A527800000012F7 +:100B2000041A40380002027C061AD0F800000002C5 +:100B30000200A294071D29110200A29800000000E3 +:100B40000200A29C009C04240200A2A0000000005D +:100B50000200A2A4000002090200A270000000002E +:100B60000200A274000000000200A2700000000059 +:100B70000200A274000000000200A2700000000049 +:100B80000200A274000000000200A2700000000039 +:100B90000200A27400000000020100B40000000185 +:100BA000020100B800000001020100DC00000001A9 +:100BB0000201010000000001020101040000000127 +:100BC0000201007C003000000201008400000028C7 +:100BD0000201008C0000000002010130000000044E +:100BE0000201025C00000001020103280000000075 +:100BF0000201607000000007020160800000000137 +:100C00000201055400000030020100C40000000190 +:100C1000020100CC00000001020100F80000000108 +:100C2000020100F00000000102010080003000001D +:100C3000020100880000002802010090000000006E +:100C40000201013400000004020102DC0000000186 +:100C50000201032C00000000020160740000000784 +:100C60000201608400000001020105640000003000 +:100C7000020100C800000001020100D000000001D4 +:100C8000020100FC00000001020100F4000000016C +:100C9000020C100000000020020C200800000211CD +:100CA000020C200C00000200020C201000000204C4 +:100CB000020C201C0000FFFF020C20200000FFFFA0 +:100CC000020C20240000FFFF020C20280000FFFF80 +:100CD000060C203800000002020C20400000003406 +:100CE000020C204400000035020C204800000020C7 +:100CF000020C204C00000021020C205000000022B9 +:100D0000020C205400000023020C20580000002494 +:100D1000020C205C00000025020C20600000002670 +:100D2000020C206400000027020C2068000000284C +:100D3000020C206C00000029020C20700000002A28 +:100D4000020C20740000002B060C207800000056D6 +:100D5000020C21D000000001020C21D4000000018F +:100D6000020C21D800000001020C21DC000000016F +:100D7000020C21E000000001020C21E4000000014F +:100D8000020C21E800000001020C21EC000000012F +:100D9000020C21F000000001020C21F4000000010F +:100DA000060C21F800000010020C223807FFFFFF9C +:100DB000020C223C0000003F020C224007FFFFFF14 +:100DC000020C22440000000F010C22480000000029 +:100DD000010C224C00000000010C22500000000019 +:100DE000010C225400000000010C225800000000F9 +:100DF000010C225C00000000010C226000000000D9 +:100E0000010C226400000000010C226800000000B8 +:100E1000010C226C00000000010C22700000000098 +:100E2000010C227400000000010C22780000000078 +:100E3000010C227C000000000C0C2000000003E8E4 +:100E40000A0C2000000000010B0C20000000000A2A +:100E5000020C400800000411020C400C00000400C9 +:100E6000020C401000000404020C40140000042195 +:100E7000020C401C0000FFFF020C40200000FFFF9E +:100E8000020C40240000FFFF020C40280000FFFF7E +:100E9000020C403800000046020C403C00000005F7 +:100EA000060C404000000002020C40480000000A0E +:100EB000020C404C000000F0060C40500000001FE7 +:100EC000020C40CC00000001060C40D00000003AAB +:100ED000020C41B800000001060C41BC00000003F8 +:100EE000020C41C800000001020C41CC00000001CE +:100EF000060C41D00000001A020C423807FFFFFF29 +:100F0000020C423C0000003F020C424007FFFFFF82 +:100F1000020C42440000000F010C42480000000097 +:100F2000010C424C00000000010C42500000000087 +:100F3000010C425400000000010C42580000000067 +:100F4000010C425C00000000010C42600000000047 +:100F5000010C426400000000010C42680000000027 +:100F6000010C426C00000000010C42700000000007 +:100F7000010C427400000000010C427800000000E7 +:100F8000010C427C00000000010C428000000000C7 +:100F90000C0C4000000003E80A0C400000000001B7 +:100FA0000B0C40000000000A020D0044000000325B +:100FB000020D008C02150020020D00900215002089 +:100FC000020D009408100000020D0098000000338C +:100FD000020D009C00000002020D00A000000000B5 +:100FE000020D00A400000005020D00A8000000058D +:100FF000060D00AC00000002020D00B4000000026B +:10100000020D00B800000003020D00BC0000000249 +:10101000020D00C000000001020D00C80000000227 +:10102000020D00CC00000002020D010800000001CA +:10103000020D015C00000001020D016400000001CE +:10104000020D016800000002020D02040000000110 +:10105000020D020C00000020020D021000000040F2 +:10106000020D021400000040020D022000000003E7 +:10107000020D022400000018060D0280000000127C +:10108000040D03000024027E020D004C000000014C +:10109000020D005000000002020D00540000000884 +:1010A000020D005800000008060D005C000000045E +:1010B000020D00C400000004020D00040000000145 +:1010C000020D000800000001020D000C00000001EC +:1010D000020D001000000001020D001400000001CC +:1010E000020D001800000001020D001C00000001AC +:1010F000020D002000000001020D0024000000018C +:10110000020D002800000001020D002C000000016B +:10111000020D003000000001020D0034000000014B +:10112000020D003800000001020D003C000000012B +:10113000020D011400000009020D011C0000000A4C +:10114000020D012400000007020D012C0000000721 +:10115000020D01340000000C020D013C0000000BE8 +:10116000020D014400000007020D011800000029D3 +:10117000020D01200000002A020D012800000027B6 +:10118000020D013000000027020D01380000002C84 +:10119000020D01400000002B020D01480000002755 +:1011A000020D011400000019020D011C0000001ABC +:1011B000020D012400000017020D012C0000001791 +:1011C000020D01340000001C020D013C0000001B58 +:1011D000020D014400000017020D01180000003943 +:1011E000020D01200000003A020D01280000003726 +:1011F000020D013000000037020D01380000003CF4 +:10120000020D01400000003B020D014800000037C4 +:10121000020D011400000049020D011C0000004AEB +:10122000020D012400000047020D012C00000047C0 +:10123000020D01340000004C020D013C0000004B87 +:10124000020D014400000047020D01180000006972 +:10125000020D01200000006A020D01280000006755 +:10126000020D013000000067020D01380000006C23 +:10127000020D01400000006B020D014800000067F4 +:10128000020D011400000059020D011C0000005A5B +:10129000020D012400000057020D012C0000005730 +:1012A000020D01340000005C020D013C0000005BF7 +:1012B000020D014400000057020D011800000079E2 +:1012C000020D01200000007A020D012800000077C5 +:1012D000020D013000000077020D01380000007C93 +:1012E000020D01400000007B020D01480000007764 +:1012F000020E004C00000032020E00940215002085 +:10130000020E009802150020020E009C0000003022 +:10131000020E00A008100000020E00A4000000331E +:10132000020E00A800000030020E00AC00000031E8 +:10133000020E00B000000002020E00B40000000423 +:10134000020E00B800000000020E00BC0000000207 +:10135000020E00C000000002020E00C400000000E7 +:10136000020E00C800000002020E00CC00000007C0 +:10137000020E00D000000002020E00D400000002A5 +:10138000020E00D800000001020E00E4000000017F +:10139000020E014400000001020E014C0000000199 +:1013A000020E015000000002020E020400000001C3 +:1013B000020E020C00000040020E0210000000406D +:1013C000020E021C00000004020E02200000002099 +:1013D000020E02240000000E020E02280000001B74 +:1013E000060E030000000012040E0280001B02A281 +:1013F000020E00540000000C020E0058000000070E +:10140000020E005C0000000F020E006000000010E1 +:10141000020E00640000000B060E006800000003CE +:10142000020E00DC00000003020E000400000001B8 +:10143000020E000800000001020E000C0000000176 +:10144000020E001000000001020E00140000000156 +:10145000020E001800000001020E001C0000000136 +:10146000020E002000000001020E00240000000116 +:10147000020E002800000001020E002C00000001F6 +:10148000020E003000000001020E003400000001D6 +:10149000020E003800000001020E003C00000001B6 +:1014A000020E004000000001020E00440000000196 +:1014B000020E01100000000F020E01180000000EC5 +:1014C000020E012000000000020E012800000000B2 +:1014D000020E01140000002F020E011C0000002E5D +:1014E000020E012400000000020E012C000000008A +:1014F000020E01100000001F020E01180000001E65 +:10150000020E012000000000020E01280000000071 +:10151000020E01140000003F020E011C0000003EFC +:10152000020E012400000000020E012C0000000049 +:10153000020E01100000004F020E01180000004EC4 +:10154000020E012000000000020E01280000000031 +:10155000020E01140000006F020E011C0000006E5C +:10156000020E012400000000020E012C0000000009 +:10157000020E01100000005F020E01180000005E64 +:10158000020E012000000000020E012800000000F1 +:10159000020E01140000007F020E011C0000007EFC +:1015A000020E012400000000020E012C00000000C9 +:1015B0000730040000E10000083007D8000502BD34 +:1015C000073400002ECA000007348000311A0BB324 +:1015D00007350000368B17FA0735800039C6259D80 +:1015E0000736000013D5340F0836307039F202BFC9 +:1015F0000130000000000000013000040000000085 +:1016000001300008000000000130000C0000000064 +:101610000130001000000000013000140000000044 +:10162000023000200000000102300024000000020F +:1016300002300028000000030230002C00000000EF +:1016400002300030000000040230003400000001CD +:1016500002300038000000000230003C00000001B1 +:10166000023000400000000402300044000000008E +:1016700002300048000000010230004C000000036E +:101680000230005000000000023000540000000151 +:1016900002300058000000040230005C000000002E +:1016A000023000600000000102300064000000030E +:1016B00002300068000000000230006C00000001F1 +:1016C00002300070000000040230007400000000CE +:1016D00002300078000000040230007C00000003AB +:1016E0000630008000000002023000A400003FFF2E +:1016F000023000A8000003FF0230022400000000B6 +:1017000002300234000000000230024C00000000F1 +:10171000023002E40000FFFF063020000000080055 +:1017200002338BC000000001023380000000001A69 +:10173000023380400000004E023380800000001021 +:10174000023380C0000000200C3383000007A1207A +:101750000A338300000001380B3383000000138834 +:10176000023383C0000001F40C3383801DCD65007B +:101770000A3383800004C4B40B338380004C4B4095 +:101780000A331480000000000233148000000001BE +:10179000063220000000010206328020000000C84E +:1017A000063280000000000206323DA8000000045E +:1017B00006323D800000000904323DA4000102C150 +:1017C00006323D00000000200632500000000400F8 +:1017D000063240000000000204324008000102C24C +:1017E0000632400C00000003063240D80000000220 +:1017F00006326B680000000204326B70000202C304 +:1018000006326B1000000002043274C0000202C5F0 +:101810000632DA40000000020632E0000000080054 +:10182000023308000100000004330C00001002C75E +:10183000023308000000000004330C40001002D7FF +:1018400006322450000000B406322AD00000000204 +:1018500006321000000001A002323DB80000000076 +:101860000632500000000020063251000000002027 +:101870000632520000000020063253000000002013 +:1018800006325400000000200632550000000020FF +:1018900006325600000000200632570000000020EB +:1018A00006325800000000200632590000000020D7 +:1018B00006325A000000002006325B0000000020C3 +:1018C00006325C000000002006325D0000000020AF +:1018D00006325E000000002006325F00000000209B +:1018E00006326B780000005206326E080000000CD1 +:1018F0000632DA880000000206322720000000B419 +:1019000006322AD80000000206321680000001A02C +:1019100002323DBC00000000063250800000002072 +:101920000632518000000020063252800000002064 +:101930000632538000000020063254800000002050 +:10194000063255800000002006325680000000203C +:101950000632578000000020063258800000002028 +:10196000063259800000002006325A800000002014 +:1019700006325B800000002006325C800000002000 +:1019800006325D800000002006325E8000000020EC +:1019900006325F800000002006326CC0000000525A +:1019A00006326E380000000C0632DA9000000002A9 +:1019B00002322A3000000000063240180000000207 +:1019C0000632D0000000000602322A340000000077 +:1019D00006324028000000020632D018000000063F +:1019E00002322A38000000000632403800000002AF +:1019F0000632D0300000000602322A3C000000000F +:101A000006324048000000020632D04800000006BE +:101A100002322A4000000000063240580000000256 +:101A20000632D0600000000602322A4400000000A6 +:101A300006324068000000020632D078000000063E +:101A400002322A48000000000632407800000002FE +:101A50000632D0900000000602322A4C000000003E +:101A600006324088000000020632D0A800000006BE +:101A7000072004000093000008200780001002E700 +:101A8000072400002ADF0000072480002E050AB882 +:101A90000824E4A061D202E9012000000000000057 +:101AA00001200004000000000120000800000000E8 +:101AB0000120000C000000000120001000000000C8 +:101AC000012000140000000002200020000000019E +:101AD0000220002400000002022000280000000371 +:101AE0000220002C00000000022000300000000452 +:101AF0000220003400000001022000380000000035 +:101B00000220003C00000001022000400000000410 +:101B100002200044000000000220004800000001F4 +:101B20000220004C000000030220005000000000D2 +:101B300002200054000000010220005800000004B0 +:101B40000220005C00000000022000600000000194 +:101B50000220006400000003022000680000000072 +:101B60000220006C00000001022000700000000450 +:101B70000220007400000000022000780000000431 +:101B80000220007C0000000306200080000000020C +:101B9000022000A400003FFF022000A8000003FF75 +:101BA0000220022400000000022002340000000095 +:101BB0000220024C00000000022002E40000FFFFAF +:101BC000062020000000080002238BC00000000156 +:101BD0000223800000000010022380400000001259 +:101BE0000223808000000030022380C00000000E2D +:101BF000022383C0000001F40223148000000001CE +:101C00000A23148000000000062210000000004299 +:101C100006227020000000C80622700000000002AA +:101C2000022211E80000000006223000000000C07F +:101C3000062240700000008006225280000000044E +:101C40000622670000000100062290000000040048 +:101C500004226B08002002EB02230800013FFFFF73 +:101C600004230C000010030B0223080000000000F6 +:101C700004230C400010031B06228100000000A07A +:101C8000062286000000004006228C000000003C76 +:101C90000622B0000000020006228800000000803A +:101CA00006228DE00000003C0622404000000006B5 +:101CB00006228380000000A006228700000000406A +:101CC00006228CF00000003C0622B8000000020052 +:101CD00006228A000000008006228ED00000003C10 +:101CE000062240580000000606228000000000087E +:101CF000022211480000000006223300000000020A +:101D0000062260400000003006228020000000080B +:101D10000222114C000000000622330800000002DD +:101D2000062261000000003006228040000000080A +:101D300002221150000000000622331000000002B1 +:101D4000062261C00000003006228060000000080A +:101D50000222115400000000062233180000000285 +:101D60000622628000000030062280800000000809 +:101D70000222115800000000062233200000000259 +:101D80000622634000000030062280A00000000808 +:101D90000222115C0000000006223328000000022D +:101DA0000622640000000030062280C00000000807 +:101DB0000222116000000000062233300000000201 +:101DC000062264C000000030062280E00000000807 +:101DD00002221164000000000622333800000002D5 +:101DE0000622658000000030021610000000002866 +:101DF00002170008000000020217002C0000000378 +:101E00000217003C00000004021700440000000814 +:101E100002170048000000020217004C000000906A +:101E2000021700500000009002170054008000903C +:101E30000217005808140000021700600000008A12 +:101E40000217006400000080021700680000008193 +:101E50000217006C000000800217007000000006EE +:101E600002170078000007D00217007C0000076C02 +:101E700002170038007C1004021700040000000F55 +:101E80000616402400000002021640700000001CEC +:101E90000216420800000001021642100000000174 +:101EA0000216422000000001021642280000000134 +:101EB0000216423000000001021642380000000104 +:101EC00002164260000000020C16401C0003D09075 +:101ED0000A16401C0000009C0B16401C000009C4A0 +:101EE0000216403000000008021640340000000CCA +:101EF0000216403800000010021640440000002086 +:101F00000216400000000001021640D80000000147 +:101F100002164008000000010216400C00000001FB +:101F200002164010000000010216424000000000AE +:101F3000021642480000000006164270000000022F +:101F40000216425000000000021642580000000035 +:101F500006164280000000020216600800000424F9 +:101F60000216600C00000410021660100000041439 +:101F70000216601C0000FFFF021660200000FFFF39 +:101F8000021660240000FFFF021660280000FFFF19 +:101F900002166038000000200216603C000000209D +:101FA0000216604000000034021660440000003554 +:101FB00002166048000000230216604C0000002456 +:101FC0000216605000000025021660540000002632 +:101FD00002166058000000270216605C000000290D +:101FE000021660600000002A021660640000002BE8 +:101FF000021660680000002C0216606C0000002DC4 +:102000000616607000000052021661B80000000160 +:10201000061661BC0000001F0216623807FFFFFFB2 +:102020000216623C0000003F0216624007FFFFFFFD +:10203000021662440000000F011662480000000012 +:102040000116624C00000000011662500000000002 +:1020500001166254000000000116625800000000E2 +:102060000116625C000000000116626000000000C2 +:1020700001166264000000000116626800000000A2 +:102080000116626C00000000011662700000000082 +:102090000116627400000000011662780000000062 +:1020A0000116627C000000000C166000000003E8CE +:1020B0000A166000000000010B1660000000000A14 +:1020C0000216804000000006021680440000000551 +:1020D000021680480000000A0216804C000000052D +:1020E0000216805400000002021680CC000000049A +:1020F000021680D000000004021680D40000000404 +:10210000021680D800000004021680DC00000004E3 +:10211000021680E000000004021680E400000004C3 +:10212000021680E800000004021688040000000483 +:10213000021680300000007C021680340000003D52 +:10214000021680380000003F0216803C0000009C10 +:10215000021680F000000007061680F4000000055B +:102160000216880C0101010102168108000000001E +:102170000216810C00000004021681100000000409 +:1021800002168114000000020216881008012004C3 +:1021900002168118000000050216811C00000005CF +:1021A00002168120000000050216812400000005AF +:1021B0000216882C20081001021681280000000851 +:1021C0000216812C00000006021681300000000774 +:1021D000021681340000000002168830010101203F +:1021E000061681380000000402168834010101013E +:1021F00002168148000000000216814C0000000415 +:1022000002168150000000040216815400000002F2 +:1022100002168838080120040216815800000005C3 +:102220000216815C000000050216816000000005B6 +:1022300002168164000000050216883C2008100187 +:1022400002168168000000080216816C000000067A +:102250000216817000000007021681740000000160 +:102260000216884001010120021681780000000159 +:102270000216817C0000000102168180000000012E +:102280000216818400000001021688440101010148 +:1022900002168188000000010216818C00000004F3 +:1022A00002168190000000040216819400000002D2 +:1022B00002168848080120040216819800000005D3 +:1022C0000216819C00000005021681A00000000596 +:1022D000021681A4000000050216881420081001CF +:1022E000021681A800000008021681AC000000065A +:1022F000021681B000000007021681B40000000140 +:102300000216881801010120021681B800000001A0 +:10231000021681BC00000001021681C0000000010D +:10232000021681C4000000010216881C010101018F +:10233000021681C800000001021681CC00000004D2 +:10234000021681D000000004021681D400000002B1 +:102350000216882008012004021681D8000000051A +:10236000021681DC00000005021681E00000000575 +:10237000021681E4000000050216882420081001DE +:10238000021681E800000008021681EC0000000639 +:10239000021681F0000000070216E40C00000000A5 +:1023A00002168828010101200616E410000000042E +:1023B0000216E000010101010216E4200000000005 +:1023C0000216E424000000040216E42800000004C1 +:1023D0000216E42C000000020216E00408012004AA +:1023E0000216E430000000050216E4340000000587 +:1023F0000216E438000000050216E43C0000000567 +:102400000216E008200810010216E440000000084F +:102410000216E444000000060216E448000000072B +:102420000216E44C000000000216E00C010101203D +:102430000616E450000000040216E010010101013C +:102440000216E460000000000216E46400000004CC +:102450000216E468000000040216E46C00000002AA +:102460000216E014080120040216E47000000005C2 +:102470000216E474000000050216E478000000056E +:102480000216E47C000000050216E0182008100186 +:102490000216E480000000080216E4840000000632 +:1024A0000216E488000000070216E48C0000000118 +:1024B0000216E01C010101200216E4900000000158 +:1024C0000216E494000000010216E49800000001E6 +:1024D0000216E49C000000010216E0200101010147 +:1024E0000216E4A0000000010216E4A400000004AB +:1024F0000216E4A8000000040216E4AC000000028A +:102500000216E024080120040216E4B000000005D1 +:102510000216E4B4000000050216E4B8000000054D +:102520000216E4BC000000050216E0282008100195 +:102530000216E4C0000000080216E4C40000000611 +:102540000216E4C8000000070216E4CC00000001F7 +:102550000216E02C010101200216E4D00000000167 +:102560000216E4D4000000010216E4D800000001C5 +:102570000216E4DC000000010216E0300101010156 +:102580000216E4E0000000010216E4E4000000048A +:102590000216E4E8000000040216E4EC0000000269 +:1025A0000216E034080120040216E4F000000005E1 +:1025B0000216E4F4000000050216E4F8000000052D +:1025C0000216E4FC000000050216E03820081001A5 +:1025D0000216E500000000080216E50400000006EF +:1025E0000216E508000000070216E03C0101012088 +:1025F00002168240003F003F0216824400000000A5 +:102600000216E524003F003F0216E5280000000006 +:1026100002168248000000000216824C003F003F74 +:102620000216E52C000000000216E530003F003FD6 +:1026300002168250010001000216825401000100BE +:102640000216E534010001000216E5380100010020 +:1026500006168258000000020216E53C0000000049 +:102660000216E540000000000216826000C000C0B3 +:102670000216826400C000C00216E54400C000C01B +:102680000216E54800C000C0021682681E001E0047 +:102690000216826C1E001E000216E54C1E001E0073 +:1026A0000216E5501E001E00021682704000400017 +:1026B00002168274400040000216E55440004000BB +:1026C0000216E55840004000021682788000800023 +:1026D0000216827C800080000216E55C800080008B +:1026E0000216E56080008000021682802000200033 +:1026F00002168284200020000216E56420002000DB +:102700000216E568200020000616828800000002FC +:102710000216E56C000000000216E57000000000E3 +:102720000216829000000000021682940000000051 +:102730000216E574000000000216E57800000000B3 +:1027400002168298000000000216829C0000000021 +:102750000216E57C000000000216E5800000000083 +:10276000021682A000000000021682A400000001F0 +:10277000061682A80000000A021681F400000C0868 +:10278000021681F800000040021681FC00000100E2 +:1027900002168200000000200216820400000017CA +:1027A00002168208000000800216820C000002005F +:1027B00002168210000000000216821801FF01FFBD +:1027C0000216821401FF01FF0216E51001FF01FF4E +:1027D0000216E50C01FF01FF0216823C0000001307 +:1027E000021680900000013F021680600000014048 +:1027F0000216806400000140061680680000000296 +:1028000002168070000000C00616807400000007E9 +:102810000216809C00000048021680A000000048BC +:10282000061680A400000002021680AC00000048DA +:10283000061680B0000000070216823800008000F3 +:1028400002168234000025E40216809400007FFF07 +:1028500002168220000F000F0216821C000F000FCC +:102860000216E518000F000F0216E514000F000F06 +:10287000021682280000000002168224FFFFFFFFDC +:102880000216E520000000000216E51CFFFFFFFF16 +:102890000216E6BC000000000216E6C000000002BE +:1028A0000216E6C4000000010216E6C8000000039C +:1028B0000216E6CC000000040216E6D00000000676 +:1028C0000216E6D4000000050216E6D80000000754 +:1028D000021680EC000000FF02140000000000015E +:1028E0000214000C0000000102140040000000016E +:1028F0000214004400007FFF0214000C00000000DE +:1029000002140000000000000214006C000000002F +:102910000214000400000001021400300000000155 +:1029200002140004000000000214005C000000001B +:10293000021400080000000102140034000000012D +:1029400002140008000000000214006000000000F3 +:102950000202005800000032020200A0031500200D +:10296000020200A403150020020200A801000030AA +:10297000020200AC08100000020200B000000033A8 +:10298000020200B400000030020200B80000003172 +:10299000020200BC00000003020200C000000006AA +:1029A000020200C400000003020200C8000000038D +:1029B000020200CC00000002020200D00000000071 +:1029C000020200D400000002020200DC000000004D +:1029D000020200E000000006020200E40000000421 +:1029E000020200E800000002020200EC0000000207 +:1029F000020200F000000001020200FC00000006DC +:102A00000202012000000000020201340000000266 +:102A1000020201B0000000010202020C00000001ED +:102A2000020202140000000102020218000000026B +:102A300002020404000000010202040C0000004035 +:102A400002020410000000400202041C0000000406 +:102A50000202042000000020020204240000000200 +:102A600002020428000000200602050000000012F7 +:102A700004020480001F032B020200600000000F0C +:102A80000202006400000007020200680000000B60 +:102A90000202006C0000000E020200700000000E36 +:102AA0000602007400000003020200F400000004AB +:102AB0000202000400000001020200080000000100 +:102AC0000202000C000000010202001000000001E0 +:102AD00002020014000000010202001800000001C0 +:102AE0000202001C000000010202002000000001A0 +:102AF0000202002400000001020200280000000180 +:102B00000202002C0000000102020030000000015F +:102B1000020200340000000102020038000000013F +:102B20000202003C0000000102020040000000011F +:102B300002020044000000010202004800000001FF +:102B40000202004C000000010202005000000001DF +:102B500002020108000000C8020201180000000281 +:102B6000020201C400000000020201CC00000000CB +:102B7000020201D400000002020201DC0000000297 +:102B8000020201E4000000FF020201EC000000FF6D +:102B900002020100000000000202010C000000C857 +:102BA0000202011C00000002020201C80000000035 +:102BB000020201D000000000020201D80000000261 +:102BC000020201E000000002020201E8000000FF32 +:102BD000020201F0000000FF0202010400000000F8 +:102BE00002020108000000C80202011800000002F1 +:102BF000020201C400000000020201CC000000003B +:102C0000020201D400000002020201DC0000000206 +:102C1000020201E4000000FF020201EC000000FFDC +:102C200002020100000000000202010C000000C8C6 +:102C30000202011C00000002020201C800000000A4 +:102C4000020201D000000000020201D800000002D0 +:102C5000020201E000000002020201E8000000FFA1 +:102C6000020201F0000000FF020201040000000067 +:102C700002020108000000C8020201180000000260 +:102C8000020201C400000000020201CC00000000AA +:102C9000020201D400000002020201DC0000000276 +:102CA000020201E4000000FF020201EC000000FF4C +:102CB00002020100000000000202010C000000C836 +:102CC0000202011C00000002020201C80000000014 +:102CD000020201D000000000020201D80000000240 +:102CE000020201E000000002020201E8000000FF11 +:102CF000020201F0000000FF0202010400000000D7 +:102D000002020108000000C80202011800000002CF +:102D1000020201C400000000020201CC0000000019 +:102D2000020201D400000002020201DC00000002E5 +:102D3000020201E4000000FF020201EC000000FFBB +:102D400002020100000000000202010C000000C8A5 +:102D50000202011C00000002020201C80000000083 +:102D6000020201D000000000020201D800000002AF +:102D7000020201E000000002020201E8000000FF80 +:102D8000020201F0000000FF020201040000000046 +:102D90000728040000C00000082807A8000B034A09 +:102DA000072C000032FD0000072C8000357E0CC08F +:102DB000072D00003AE41A20072D800039CF28DAC9 +:102DC000072E00001C3C374E082E3710391E034CCE +:102DD000012800000000000001280004000000009D +:102DE00001280008000000000128000C000000007D +:102DF000012800100000000001280014000000005D +:102E00000228002000000001022800240000000227 +:102E100002280028000000030228002C0000000007 +:102E200002280030000000040228003400000001E5 +:102E300002280038000000000228003C00000001C9 +:102E400002280040000000040228004400000000A6 +:102E500002280048000000010228004C0000000386 +:102E60000228005000000000022800540000000169 +:102E700002280058000000040228005C0000000046 +:102E80000228006000000001022800640000000326 +:102E900002280068000000000228006C0000000109 +:102EA00002280070000000040228007400000000E6 +:102EB00002280078000000040228007C00000003C3 +:102EC0000628008000000002022800A400003FFF46 +:102ED000022800A8000003FF0228022400000000CE +:102EE00002280234000000000228024C000000000A +:102EF000022802E40000FFFF06282000000008006E +:102F0000022B8BC000000001022B8000000000009B +:102F1000022B804000000018022B80800000000C73 +:102F2000022B80C0000000660C2B83000007A1204C +:102F30000A2B8300000001380B2B8300000013884C +:102F4000022B83C0000001F40C2B8340000001F42D +:102F50000A2B8340000000000B2B8340000000057B +:102F60000A2B83800004C4B40C2B83801DCD650024 +:102F70000A2B1480000000000B2B8380004C4B4078 +:102F8000022B148000000001062A29C8000000045A +:102F9000042A29D80002034E062A20800000004897 +:102FA000062A9020000000C8062A900000000002B7 +:102FB000062A21A800000086062A20000000002022 +:102FC000022A23C800000000042A23D00002035074 +:102FD000042A249800040352022A2C500000000006 +:102FE000022A2C1000000000042A2C0800020356BC +:102FF000042A300000020358062A300800000100AD +:10300000062A404000000010042A40000010035A25 +:10301000062A6AC000000002062A6B0000000004B5 +:10302000042A84080002036A022B08000000000042 +:10303000042B0C000010036C022B080001000000A0 +:10304000042B0C400008037C022B08000200000047 +:10305000042B0C6000080384062AC000000000D87E +:10306000062A24A800000014062A2548000000248F +:10307000062A266800000024062A2788000000246B +:10308000062A28A800000024062AA0000000002824 +:10309000062AA1400000000C042A29E00002038C4B +:1030A000062A502000000002062A503000000002CC +:1030B000062A500000000002062A501000000002FC +:1030C000022A520800000001042A6AC80002038E86 +:1030D000062A6B1000000042062A6D200000000442 +:1030E000062ABCD000000002062AC360000000D8F7 +:1030F000062A24F800000014062A25D8000000241F +:10310000062A26F800000024062A281800000024B9 +:10311000062A293800000024062AA0A00000002862 +:10312000062AA1700000000C042A29E8000203907E +:10313000062A502800000002062A5038000000022B +:10314000062A500800000002062A5018000000025B +:10315000022A520C00000001042A6AD000020392E5 +:10316000062A6C1800000042062A6D300000000498 +:10317000062ABCD800000002022AC6C000000000D7 +:10318000042A29F000100394062A50480000000E7B +:10319000062AB00000000006022AC6C40000000093 +:1031A000042A2A30001003A4062A50800000000ED2 +:1031B000062AB01800000006022AC6C80000000057 +:1031C000042A2A70001003B4062A50B80000000E2A +:1031D000062AB03000000006022AC6CC000000001B +:1031E000042A2AB0001003C4062A50F00000000E82 +:1031F000062AB04800000006022AC6D000000000DF +:10320000042A2AF0001003D4062A51280000000ED8 +:10321000062AB06000000006022AC6D400000000A2 +:10322000042A2B30001003E4062A51600000000E2F +:10323000062AB07800000006022AC6D80000000066 +:10324000042A2B70001003F4062A51980000000E87 +:10325000062AB09000000006022AC6DC000000002A +:10326000042A2BB000100404062A51D00000000EDE +:10327000062AB0A800000006021010080000000195 +:103280000210105000000001021010000003D000D6 +:10329000021010040000003D091018000200041480 +:1032A0000910110000280614061011A000000018D3 +:1032B00006102400000000E00210201C00000000A6 +:1032C0000210202000000001021020C000000002B7 +:1032D000021020040000000102102008000000017C +:1032E00009103C000005063C0910380000050641A5 +:1032F000091038200005064606104C0000000100A9 +:1033000002104028000000100210404400003FFF5F +:103310000210405800280000021040840084924AA5 +:1033200002104058000000000210800000001080D1 +:10333000021080AC00000000021080380000001075 +:103340000210810000000000061081200000000231 +:1033500002108008000002B502108010000000007A +:10336000061082000000004A021081080001FFFFE1 +:1033700006108140000000020210800000001A8048 +:103380000610900000000024061091200000004A62 +:10339000061093700000004A061095C00000004A15 +:1033A0000210800400001080021080B000000001B4 +:1033B0000210803C00000010021081040000000098 +:1033C00006108128000000020210800C000002B5E7 +:1033D0000210801400000000061084000000004A63 +:1033E0000210810C0001FFFF06108148000000025E +:1033F0000210800400001A80061090900000002443 +:10340000061092480000004A061094980000004AF6 +:10341000061096E80000004A0210800000001080AC +:10342000021080AC00000002021080380000001082 +:103430000210810000000000061081200000000240 +:1034400002108008000002B5021080100000000089 +:10345000061082000000004A021081080001FFFFF0 +:1034600006108140000000020210800000001A8057 +:103470000610900000000024061091200000004A71 +:10348000061093700000004A061095C00000004A24 +:103490000210800400001080021080B000000003C1 +:1034A0000210803C000000100210810400000000A7 +:1034B00006108128000000020210800C000002B5F6 +:1034C0000210801400000000061084000000004A72 +:1034D0000210810C0001FFFF06108148000000026D +:1034E0000210800400001A80061090900000002452 +:1034F000061092480000004A061094980000004A06 +:10350000061096E80000004A0210800000001080BB +:10351000021080AC0000000402108038000000108F +:10352000021081000000000006108120000000024F +:1035300002108008000002B5021080100000000098 +:10354000061082000000004A021081080001FFFFFF +:1035500006108140000000020210800000001A8066 +:103560000610900000000024061091200000004A80 +:10357000061093700000004A061095C00000004A33 +:103580000210800400001080021080B000000005CE +:103590000210803C000000100210810400000000B6 +:1035A00006108128000000020210800C000002B505 +:1035B0000210801400000000061084000000004A81 +:1035C0000210810C0001FFFF06108148000000027C +:1035D0000210800400001A80061090900000002461 +:1035E000061092480000004A061094980000004A15 +:1035F000061096E80000004A0210800000001080CB +:10360000021080AC0000000602108038000000109C +:10361000021081000000000006108120000000025E +:1036200002108008000002B50210801000000000A7 +:10363000061082000000004A021081080001FFFF0E +:1036400006108140000000020210800000001A8075 +:103650000610900000000024061091200000004A8F +:10366000061093700000004A061095C00000004A42 +:103670000210800400001080021080B000000007DB +:103680000210803C000000100210810400000000C5 +:1036900006108128000000020210800C000002B514 +:1036A0000210801400000000061084000000004A90 +:1036B0000210810C0001FFFF06108148000000028B +:1036C0000210800400001A80061090900000002470 +:1036D000061092480000004A061094980000004A24 +:1036E000061096E80000004A021205B00000000132 +:1036F0000212049000E383400212051400003C1003 +:103700000212066C000000010212067000000000A8 +:1037100002120494FFFFFFFF02120498FFFFFFFF55 +:103720000212049CFFFFFFFF021204A0FFFFFFFF35 +:10373000021204A4FFFFFFFF021204A8FFFFFFFF15 +:10374000021204ACFFFFFFFF021204B0FFFFFFFFF5 +:10375000021204BCFFFFFFFF021204C0FFFFFFFFC5 +:10376000021204C4FFFFFFFF021204C8FFFFFFFFA5 +:10377000021204CCFFFFFFFF021204D0FFFFFFFF85 +:10378000021204D8FFFFFFFF021204DCFFFFFFFF5D +:10379000021204E0FFFFFFFF021204E4FFFFFFFF3D +:1037A000021204E8FFFFFFFF021204ECFFFFFFFF1D +:1037B000021204F0FFFFFFFF021204F4FFFFFFFFFD +:1037C000021204F8FFFFFFFF021204FCFFFFFFFFDD +:1037D00002120500FFFFFFFF02120504FFFFFFFFBB +:1037E00002120508FFFFFFFF0212050CFFFFFFFF9B +:1037F00002120510FFFFFFFF021204D4FF80200019 +:10380000021204B4F0005000021204B8F0001000DC +:1038100002120390000000080212039C000000083E +:10382000021203A000000008021203A4000000021C +:10383000021203BC00000004021203C000000005D5 +:10384000021203C400000004021203D000000000B2 +:103850000212036C00000001021203680000003F26 +:10386000021201BC00000040021201C00000180852 +:10387000021201C400000803021201C8000008037C +:10388000021201CC00000040021201D0000000032F +:10389000021201D400000803021201D8000008033C +:1038A000021201DC00000803021201E00001000323 +:1038B000021201E400000803021201E800000803FC +:1038C000021201EC00000003021201F000000003EC +:1038D000021201F400000003021201F800000003CC +:1038E000021201FC000000030212020000000003AB +:1038F000021202040000000302120208000000038A +:103900000212020C00000003021202100000000369 +:103910000212021400000003021202180000000349 +:103920000212021C00000003021202200000000329 +:1039300002120224000000030212022800002403E5 +:103940000212022C0000002F0212023000000009B7 +:103950000212023400000019021202380000018431 +:103960000212023C00000183021202400000030622 +:103970000212024400000019021202480000000670 +:103980000212024C0000030602120250000003065D +:1039900002120254000003060212025800000C86B4 +:1039A0000212025C0000030602120260000003061D +:1039B0000212026400000006021202680000000603 +:1039C0000212026C000000060212027000000006E3 +:1039D00002120274000000060212027800000006C3 +:1039E0000212027C000000060212028000000006A3 +:1039F0000212028400000006021202880000000683 +:103A00000212028C00000006021202900000000662 +:103A10000212029400000006021202980000000642 +:103A20000212029C00000006021202A0000003061F +:103A3000021202A400000013021202A800000006F5 +:103A4000021202B000001004021202B400001004BE +:103A50000212032400106440021203280010644084 +:103A6000021205B400000001021201B000000001C2 +:103A70000600A000000000160200A0EC5554000053 +:103A80000200A0F0555555550200A0F40000555510 +:103A90000200A0F8F00000000200A0FC5554000055 +:103AA0000200A100555555550200A10400005555CE +:103AB0000200A108F00000000200A18C5554000093 +:103AC0000200A190555555550200A194000055558E +:103AD0000200A198F00000000200A19C000000007C +:103AE0000200A1A0000100000200A1A400005014E7 +:103AF0000200A1A8000000000200A45C00000C006D +:103B00000200A61C000000030200A06CFF5C000085 +:103B10000200A070FFF55FFF0200A0740000FFFF2D +:103B20000200A078F00003E00200A07C000000008A +:103B30000200A0800000A0000600A0840000000594 +:103B40000200A0980FE000000600A09C0000000703 +:103B50000200A0B8000004000600A0BC00000003A2 +:103B60000200A0C8000010000600A0CC0000000366 +:103B70000200A0D8000040000600A0DC0000000306 +:103B80000200A0E8000100000600A22C00000004D2 +:103B90000200A10CFF5C00000200A110FFF55FFF16 +:103BA0000200A1140000FFFF0200A118F00003E0D2 +:103BB0000200A11C000000000200A1200000A000E3 +:103BC0000600A124000000050200A1380FE000005B +:103BD0000600A13C000000070200A15800000800F8 +:103BE0000600A15C000000030200A16800002000A4 +:103BF0000600A16C000000030200A1780000800014 +:103C00000600A17C000000030200A1880002000061 +:103C10000600A23C000000040000000000000000BC +:103C20000000003100000000000000000000000063 +:103C30000000000000000000000000000000000084 +:103C40000000000000000000000000000031003211 +:103C50000000000000000000000000000000000064 +:103C60000000000000000000000000000000000054 +:103C700000000000000000000032005600000000BC +:103C80000000000000000000000000000000000034 +:103C90000000000000000000000000000000000024 +:103CA000000000000056008C000000000000000032 +:103CB000008C009000900094009400980098009C64 +:103CC000009C00A000A000A400A400A800A800ACD4 +:103CD00000AC00B100B100B300B300B500000000BB +:103CE00000000000000000000000000000000000D4 +:103CF00000000000000000000000000000B501020C +:103D00000102010A010A01120112011B011B012417 +:103D10000124012D012D01360136013F013F0148EB +:103D2000014801510151015A00000000000000004B +:103D30000000000000000000000000000000000083 +:103D40000000000000000000000000000000000073 +:103D50000000000000000000000000000000000063 +:103D60000000000000000000000000000000000053 +:103D70000000000000000000000000000000000043 +:103D80000000000000000000000000000000000033 +:103D90000000000000000000000000000000000023 +:103DA0000000000000000000000000000000000013 +:103DB0000000000000000000000000000000000003 +:103DC00000000000000000000000000000000000F3 +:103DD0000000000000000000015A015F0000000028 +:103DE00000000000015F016001600161016101628A +:103DF000016201630163016401640165016501669B +:103E000001660167000000000000000000000000E3 +:103E100000000000000000000000000000000000A2 +:103E20000000000000000000000000000000000092 +:103E30000167016C016C01790179018600000000C5 +:103E40000000000000000000000000000000000072 +:103E50000000000000000000000000000000000062 +:103E60000000000000000000000000000000000052 +:103E70000000000000000000000000000000000042 +:103E80000000000000000000018601870000000023 +:103E90000000000000000000000000000000000022 +:103EA0000000000000000000000000000000000012 +:103EB00000000000018701BE0000000000000000BB +:103EC00000000000000000000000000000000000F2 +:103ED00000000000000000000000000000000000E2 +:103EE00001BE01E900000000000000000000000029 +:103EF00000000000000000000000000000000000C2 +:103F000000000000000000000000000001E9021AAB +:103F10000000000000000000021A02210221022815 +:103F20000228022F022F02360236023D023D0244D1 +:103F30000244024B024B02520252028A000000006D +:103F400000000000028A028E028E02920292029605 +:103F50000296029A029A029E029E02A202A202A661 +:103F600002A602AA02AA02FC02FC03130313032AFC +:103F7000032A032D032D03300330033303330336A9 +:103F8000033603390339033C033C033F033F034239 +:103F9000034203830383038A038A039103910395F6 +:103FA000039503990399039D039D03A103A103A511 +:103FB00003A503A903A903AD03AD03B103B103B284 +:103FC00000000000000000000000000000000000F1 +:103FD00000000000000000000000000000000000E1 +:103FE000000000000000000003B203C40000000055 +:103FF00000000000000000000000000000000000C1 +:1040000000000000000000000000000000000000B0 +:104010000000000003C403D903D903DC03DC03DF81 +:104020000000000000000000000000000000000090 +:104030000000000000000000000000000000000080 +:1040400003DF040C0000000000000000000000007E +:104050000000000000000000000000000000000060 +:10406000000000000000000000000000040C050F2C +:104070000000000000000000000000000000000040 +:104080000000000000000000000000000000000030 +:104090000000000000000000050F05160516051AB7 +:1040A000051A051E000000000000000000000000CE +:1040B0000000000000000000000000000000000000 +:1040C00000000000051E055E00000000000000006A +:1040D000055E056705670570057005790579058238 +:1040E0000582058B058B05940594059D059D05A608 +:1040F00005A605FF05FF0611061106230623062760 +:104100000627062B062B062F062F06330633063707 +:104110000637063B063B063F063F06430643064A74 +:10412000000000000000000000000000000000008F +:10413000000000000000000000000000000000007F +:104140000000000000000000064A065000000000C9 +:10415000000000000000000000000000000000005F +:10416000000000000000000000000000000000004F +:104170000000000006500653000000000000000090 +:10418000000000000000000000000000000000002F +:10419000000000000000000000000000000000001F +:1041A0000653065900000000000000000000000057 +:1041B00000000000000000000000000000000000FF +:1041C00000000000000000000000000000000000EF +:1041D0000000000000000000065906680668067727 +:1041E0000677068606860695069506A406A406B3F7 +:1041F00006B306C206C206D106D10742000000007F +:1042000000000000000000000000000000000000AE +:10421000000000000000000000000000000000009E +:104220000000000007420755075507660766077735 +:10423000000000000000000000000000000000007E +:10424000000000000000000000000000000000006E +:10425000000000000000000000000000000000005E +:10426000000000000000000000000000000000004E +:10427000000000000000000000000000000000003E +:10428000000000000000000000000000000000002E +:10429000000000000000000000000000000000001E +:1042A000000000000000000000000000000000000E +:1042B00000010000000204C00003098000040E4059 +:1042C00000051300000617C000071C8000082140ED +:1042D00000092600000A2AC0000B2F80000C344081 +:1042E000000D3900000E3DC0000F42800010474015 +:1042F00000114C00001250C00013558000145A40A9 +:1043000000155F00001663C00017688000186D403C +:1043100000197200001A76C0001B7B80001C8040D0 +:10432000001D8500001E89C0001F8E800020934064 +:10433000000020000000400000006000000080003D +:104340000000A0000000C0000000E000000100002C +:104350000001200000014000000160000001800019 +:104360000001A0000001C0000001E0000002000008 +:1043700000022000000240000002600000028000F5 +:104380000002A0000002C0000002E00000030000E4 +:1043900000032000000340000003600000038000D1 +:1043A0000003A0000003C0000003E00000040000C0 +:1043B00000042000000440000004600000048000AD +:1043C0000004A0000004C0000004E000000500009C +:1043D0000005200000054000000560000005800089 +:1043E0000005A0000005C0000005E0000006000078 +:1043F0000006200000064000000660000006800065 +:104400000006A0000006C0000006E0000007000053 +:104410000007200000074000000760000007800040 +:104420000007A0000007C0000007E000000800002F +:10443000000820000008400000086000000880001C +:104440000008A0000008C0000008E000000900000B +:1044500000092000000940000009600000098000F8 +:104460000009A0000009C0000009E000000A0000E7 +:10447000000A2000000A4000000A6000000A8000D4 +:10448000000AA000000AC000000AE000000B0000C3 +:10449000000B2000000B4000000B6000000B8000B0 +:1044A000000BA000000BC000000BE000000C00009F +:1044B000000C2000000C4000000C6000000C80008C +:1044C000000CA000000CC000000CE000000D00007B +:1044D000000D2000000D4000000D6000000D800068 +:1044E000000DA000000DC000000DE000000E000057 +:1044F000000E2000000E4000000E6000000E800044 +:10450000000EA000000EC000000EE000000F000032 +:10451000000F2000000F4000000F6000000F80001F +:10452000000FA000000FC000000FE000001000000E +:1045300000102000001040000010600000108000FB +:104540000010A0000010C0000010E00000110000EA +:1045500000112000001140000011600000118000D7 +:104560000011A0000011C0000011E00000120000C6 +:1045700000122000001240000012600000128000B3 +:104580000012A0000012C0000012E00000130000A2 +:10459000001320000013400000136000001380008F +:1045A0000013A0000013C0000013E000001400007E +:1045B000001420000014400000146000001480006B +:1045C0000014A0000014C0000014E000001500005A +:1045D0000015200000154000001560000015800047 +:1045E0000015A0000015C0000015E0000016000036 +:1045F0000016200000164000001660000016800023 +:104600000016A0000016C0000016E0000017000011 +:1046100000172000001740000017600000178000FE +:104620000017A0000017C0000017E00000180000ED +:1046300000182000001840000018600000188000DA +:104640000018A0000018C0000018E00000190000C9 +:1046500000192000001940000019600000198000B6 +:104660000019A0000019C0000019E000001A0000A5 +:10467000001A2000001A4000001A6000001A800092 +:10468000001AA000001AC000001AE000001B000081 +:10469000001B2000001B4000001B6000001B80006E +:1046A000001BA000001BC000001BE000001C00005D +:1046B000001C2000001C4000001C6000001C80004A +:1046C000001CA000001CC000001CE000001D000039 +:1046D000001D2000001D4000001D6000001D800026 +:1046E000001DA000001DC000001DE000001E000015 +:1046F000001E2000001E4000001E6000001E800002 +:10470000001EA000001EC000001EE000001F0000F0 +:10471000001F2000001F4000001F6000001F8000DD +:10472000001FA000001FC000001FE00000200000CC +:1047300000202000002040000020600000208000B9 +:104740000020A0000020C0000020E00000210000A8 +:104750000021200000214000002160000021800095 +:104760000021A0000021C0000021E0000022000084 +:104770000022200000224000002260000022800071 +:104780000022A0000022C0000022E0000023000060 +:10479000002320000023400000236000002380004D +:1047A0000023A0000023C0000023E000002400003C +:1047B0000024200000244000002460000024800029 +:1047C0000024A0000024C0000024E0000025000018 +:1047D0000025200000254000002560000025800005 +:1047E0000025A0000025C0000025E00000260000F4 +:1047F00000262000002640000026600000268000E1 +:104800000026A0000026C0000026E00000270000CF +:1048100000272000002740000027600000278000BC +:104820000027A0000027C0000027E00000280000AB +:104830000028200000284000002860000028800098 +:104840000028A0000028C0000028E0000029000087 +:104850000029200000294000002960000029800074 +:104860000029A0000029C0000029E000002A000063 +:10487000002A2000002A4000002A6000002A800050 +:10488000002AA000002AC000002AE000002B00003F +:10489000002B2000002B4000002B6000002B80002C +:1048A000002BA000002BC000002BE000002C00001B +:1048B000002C2000002C4000002C6000002C800008 +:1048C000002CA000002CC000002CE000002D0000F7 +:1048D000002D2000002D4000002D6000002D8000E4 +:1048E000002DA000002DC000002DE000002E0000D3 +:1048F000002E2000002E4000002E6000002E8000C0 +:10490000002EA000002EC000002EE000002F0000AE +:10491000002F2000002F4000002F6000002F80009B +:10492000002FA000002FC000002FE000003000008A +:104930000030200000304000003060000030800077 +:104940000030A0000030C0000030E0000031000066 +:104950000031200000314000003160000031800053 +:104960000031A0000031C0000031E0000032000042 +:10497000003220000032400000326000003280002F +:104980000032A0000032C0000032E000003300001E +:10499000003320000033400000336000003380000B +:1049A0000033A0000033C0000033E00000340000FA +:1049B00000342000003440000034600000348000E7 +:1049C0000034A0000034C0000034E00000350000D6 +:1049D00000352000003540000035600000358000C3 +:1049E0000035A0000035C0000035E00000360000B2 +:1049F000003620000036400000366000003680009F +:104A00000036A0000036C0000036E000003700008D +:104A1000003720000037400000376000003780007A +:104A20000037A0000037C0000037E0000038000069 +:104A30000038200000384000003860000038800056 +:104A40000038A0000038C0000038E0000039000045 +:104A50000039200000394000003960000039800032 +:104A60000039A0000039C0000039E000003A000021 +:104A7000003A2000003A4000003A6000003A80000E +:104A8000003AA000003AC000003AE000003B0000FD +:104A9000003B2000003B4000003B6000003B8000EA +:104AA000003BA000003BC000003BE000003C0000D9 +:104AB000003C2000003C4000003C6000003C8000C6 +:104AC000003CA000003CC000003CE000003D0000B5 +:104AD000003D2000003D4000003D6000003D8000A2 +:104AE000003DA000003DC000003DE000003E000091 +:104AF000003E2000003E4000003E6000003E80007E +:104B0000003EA000003EC000003EE000003F00006C +:104B1000003F2000003F4000003F6000003F800059 +:104B2000003FA000003FC000003FE000003FE00168 +:104B300000000000000001FF0000020000007FF8FC +:104B400000007FF800000CDF0000150000000001ED +:104B50000000000100000001FFFFFFFFFFFFFFFF5B +:104B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 +:104B7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +:104B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 +:104B9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 +:104BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 +:104BB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 +:104BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 +:104BD000FFFFFFFFFFFFFFFFFFFFFFFF00000000E1 +:104BE000FFFFFFFF00000000FFFFFFFFFFFFFFFFD1 +:104BF00000000000FFFFFFFF00000000FFFFFFFFBD +:104C0000FFFFFFFF00000000FFFFFFFF00000000AC +:104C1000FFFFFFFF0000000300BEBC20FFFFFFFFFF +:104C200000000000FFFFFFFF00000000FFFFFFFF8C +:104C30000000000300BEBC20FFFFFFFF00000000DB +:104C4000FFFFFFFF00000000FFFFFFFF0000000369 +:104C500000BEBC20FFFFFFFF00000000FFFFFFFFC2 +:104C600000000000FFFFFFFF0000000300BEBC20AB +:104C7000FFFFFFFF00000000FFFFFFFF000000003C +:104C8000FFFFFFFF0000000300BEBC20FFFFFFFF8F +:104C900000000000FFFFFFFF00000000FFFFFFFF1C +:104CA0000000000300BEBC2000002000000040C047 +:104CB00000006180000082400000A3000000C3C02B +:104CC0000000E4800001054000012600000146C00C +:104CD00000016780000188400001A9000001C9C0EF +:104CE0000001EA8000020B4000022C0000024CC0D0 +:104CF00000026D8000028E400002AF000002CFC0B3 +:104D00000002F0800003114000033200000352C093 +:104D100000037380000394400003B5000003D5C076 +:104D20000003F6800004174000043800000458C057 +:104D30000004798000049A40000080000001038094 +:104D40000001870000020A8000028E00000311802B +:104D5000000395000004188000049C0000051F80DB +:104D60000005A300000626800006AA0000072D808B +:104D70000007B100000834800008B80000093B803B +:104D80000009BF00000A4280000AC600000B4980EB +:104D9000000BCD00000C5080000CD400000D57809B +:104DA000000DDB0000007FF800007FF80000193CD8 +:104DB000000015000000190000000028001000008D +:104DC0000000000000000000FFFFFFFF40000000A7 +:104DD00040000000400000004000000040000000D3 +:104DE00040000000400000004000000040000000C3 +:104DF00040000000400000004000000040000000B3 +:104E000040000000400000004000000040000000A2 +:104E10004000000040000000400000004000000092 +:104E20004000000040000000400000004000000082 +:104E30004000000040000000400000004000000072 +:104E400040000000400000004000000000007FF82B +:104E500000007FF8000005C700001500FFFFFFFFFE +:104E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +:104E7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +:104E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 +:104E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +:104EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 +:104EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +:104EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 +:104ED000FFFFFFFFFFFFFFFFFFFFFFFF400000009E +:104EE00040000000400000004000000040000000C2 +:104EF00040000000400000004000000040000000B2 +:104F000040000000400000004000000040000000A1 +:104F10004000000040000000400000004000000091 +:104F20004000000040000000400000004000000081 +:104F30004000000040000000400000004000000071 +:104F40004000000040000000400000004000000061 +:104F50004000000040000000400000000000100081 +:104F6000000020800000310000004180000052005D +:104F70000000628000007300000083800000940045 +:104F80000000A4800000B5000000C5800000D6002D +:104F90000000E6800000F700000107800001180013 +:104FA00000012880000139000001498000015A00F9 +:104FB00000016A8000017B0000018B8000019C00E1 +:104FC0000001AC800001BD000001CD800001DE00C9 +:104FD0000001EE800001FF0000007FF800007FF874 +:104FE0000000112E0000350010000000000028AD68 +:104FF000000000000001000100150005CCCCCCC56C +:10500000FFFFFFFFFFFFFFFF7058103C0000000094 +:105010000000000000000001CCCC0201CCCCCCCCC4 +:10502000CCCC0201CCCCCCCCCCCC0201CCCCCCCCEA +:10503000CCCC0201CCCCCCCCCCCC0201CCCCCCCCDA +:10504000CCCC0201CCCCCCCCCCCC0201CCCCCCCCCA +:10505000CCCC0201CCCCCCCC00000000FFFFFFFF89 +:105060004000000040000000400000004000000040 +:105070004000000040000000400000004000000030 +:105080004000000040000000400000004000000020 +:105090004000000040000000400000004000000010 +:1050A0004000000040000000400000004000000000 +:1050B00040000000400000004000000040000000F0 +:1050C00040000000400000004000000040000000E0 +:1050D00040000000400000004000000040000000D0 +:1050E000000E0232011600D6001000000000000081 +:1050F00000720236012300F30010000000000000DF +:105100000000FFFF000000000000FFFF00000000A3 +:105110000000FFFF000000000000FFFF0000000093 +:105120000000FFFF000000000000FFFF0000000083 +:105130000000FFFF000000000000FFFF0000000073 +:105140000000FFFF000000000000FFFF0000000063 +:105150000000FFFF000000000000FFFF0000000053 +:105160000000FFFF000000000000FFFF0000000043 +:105170000000FFFF000000000000FFFF0000000033 +:105180000000FFFF000000000000FFFF0000000023 +:105190000000FFFF000000000000FFFF0000000013 +:1051A0000000FFFF000000000000FFFF0000000003 +:1051B0000000FFFF000000000000FFFF00000000F3 +:1051C0000000FFFF000000000000FFFF00000000E3 +:1051D0000000FFFF000000000000FFFF00000000D3 +:1051E0000000FFFF000000000000FFFF00000000C3 +:1051F0000000FFFF000000000000FFFF00000000B3 +:105200000000FFFF000000000000FFFF00000000A2 +:105210000000FFFF000000000000FFFF0000000092 +:105220000000FFFF000000000000FFFF0000000082 +:105230000000FFFF000000000000FFFF0000000072 +:105240000000FFFF000000000000FFFF0000000062 +:105250000000FFFF000000000000FFFF0000000052 +:105260000000FFFF000000000000FFFF0000000042 +:105270000000FFFF000000000000FFFF0000000032 +:105280000000FFFF000000000000FFFF0000000022 +:105290000000FFFF000000000000FFFF0000000012 +:1052A0000000FFFF000000000000FFFF0000000002 +:1052B0000000FFFF000000000000FFFF00000000F2 +:1052C0000000FFFF000000000000FFFF00000000E2 +:1052D0000000FFFF000000000000FFFF00000000D2 +:1052E0000000FFFF000000000000FFFF00000000C2 +:1052F0000000FFFF000000000000FFFF00000000B2 +:10530000FFFFFFF3318FFFFF0C30C30CC30C30C322 +:10531000CF3CF300F3CF3CF30000CF3CCDCDCDCD5F +:10532000FFFFFFF130EFFFFF0C30C30CC30C30C3A5 +:10533000CF3CF300F3CF3CF30001CF3CCDCDCDCD3E +:10534000FFFFFFF6305FFFFF0C30C30CC30C30C310 +:10535000CF3CF300F3CF3CF30002CF3CCDCDCDCD1D +:10536000FFFFF4061CBFFFFF0C30C305C30C30C3A6 +:10537000CF300014F3CF3CF30004CF3CCDCDCDCDE6 +:10538000FFFFFFF2304FFFFF0C30C30CC30C30C3E4 +:10539000CF3CF300F3CF3CF30008CF3CCDCDCDCDD7 +:1053A000FFFFFFFA302FFFFF0C30C30CC30C30C3DC +:1053B000CF3CF300F3CF3CF30010CF3CCDCDCDCDAF +:1053C000FFFFFFF731EFFFFF0C30C30CC30C30C3FE +:1053D000CF3CF300F3CF3CF30020CF3CCDCDCDCD7F +:1053E000FFFFFFF5302FFFFF0C30C30CC30C30C3A1 +:1053F000CF3CF300F3CF3CF30040CF3CCDCDCDCD3F +:10540000FFFFFFF3310FFFFF0C30C30CC30C30C3A1 +:10541000CF3CF300F3CF3CF30000CF3CCDCDCDCD5E +:10542000FFFFFFF1310FFFFF0C30C30CC30C30C383 +:10543000CF3CF300F3CF3CF30001CF3CCDCDCDCD3D +:10544000FFFFFFF6305FFFFF0C30C30CC30C30C30F +:10545000CF3CF300F3CF3CF30002CF3CCDCDCDCD1C +:10546000FFFFF4061CBFFFFF0C30C305C30C30C3A5 +:10547000CF300014F3CF3CF30004CF3CCDCDCDCDE5 +:10548000FFFFFFF2304FFFFF0C30C30CC30C30C3E3 +:10549000CF3CF300F3CF3CF30008CF3CCDCDCDCDD6 +:1054A000FFFFFFFA302FFFFF0C30C30CC30C30C3DB +:1054B000CF3CF300F3CF3CF30010CF3CCDCDCDCDAE +:1054C000FFFFFFF730EFFFFF0C30C30CC30C30C3FE +:1054D000CF3CF300F3CF3CF30020CF3CCDCDCDCD7E +:1054E000FFFFFFF5304FFFFF0C30C30CC30C30C380 +:1054F000CF3CF300F3CF3CF30040CF3CCDCDCDCD3E +:10550000FFFFFFF331EFFFFF0C30C30CC30C30C3C0 +:10551000CF3CF300F3CF3CF30000CF3CCDCDCDCD5D +:10552000FFFFFFF1310FFFFF0C30C30CC30C30C382 +:10553000CF3CF300F3CF3CF30001CF3CCDCDCDCD3C +:10554000FFFFFFF6305FFFFF0C30C30CC30C30C30E +:10555000CF3CF300F3CF3CF30002CF3CCDCDCDCD1B +:10556000FFFFF4061CBFFFFF0C30C305C30C30C3A4 +:10557000CF300014F3CF3CF30004CF3CCDCDCDCDE4 +:10558000FFFFFFF2304FFFFF0C30C30CC30C30C3E2 +:10559000CF3CF300F3CF3CF30008CF3CCDCDCDCDD5 +:1055A000FFFFFFFA302FFFFF0C30C30CC30C30C3DA +:1055B000CF3CF300F3CF3CF30010CF3CCDCDCDCDAD +:1055C000FFFFFF97056FFFFF0C30C30CC30C30C308 +:1055D000CF3CC000F3CF3CF30020CF3CCDCDCDCDB0 +:1055E000FFFFFFF5310FFFFF0C30C30CC30C30C3BE +:1055F000CF3CF300F3CF3CF30040CF3CCDCDCDCD3D +:10560000FFFFFFF3320FFFFF0C30C30CC30C30C39E +:10561000CF3CF300F3CF3CF30000CF3CCDCDCDCD5C +:10562000FFFFFFF1310FFFFF0C30C30CC30C30C381 +:10563000CF3CF300F3CF3CF30001CF3CCDCDCDCD3B +:10564000FFFFFFF6305FFFFF0C30C30CC30C30C30D +:10565000CF3CF300F3CF3CF30002CF3CCDCDCDCD1A +:10566000FFFFF4061CBFFFFF0C30C305C30C30C3A3 +:10567000CF300014F3CF3CF30004CF3CCDCDCDCDE3 +:10568000FFFFFFF2304FFFFF0C30C30CC30C30C3E1 +:10569000CF3CF300F3CF3CF30008CF3CCDCDCDCDD4 +:1056A000FFFFFF8A042FFFFF0C30C30CC30C30C375 +:1056B000CF3CC000F3CF3CF30010CF3CCDCDCDCDDF +:1056C000FFFFFF9705CFFFFF0C30C30CC30C30C3A7 +:1056D000CF3CC000F3CF3CF30020CF3CCDCDCDCDAF +:1056E000FFFFFFF5310FFFFF0C30C30CC30C30C3BD +:1056F000CF3CF300F3CF3CF30040CF3CCDCDCDCD3C +:10570000FFFFFFF3316FFFFF0C30C30CC30C30C33E +:10571000CF3CF300F3CF3CF30000CF3CCDCDCDCD5B +:10572000FFFFFFF1302FFFFF0C30C30CC30C30C361 +:10573000CF3CF300F3CF3CF30001CF3CCDCDCDCD3A +:10574000FFFFFFF6305FFFFF0C30C30CC30C30C30C +:10575000CF3CF300F3CF3CF30002CF3CCDCDCDCD19 +:10576000FFFFFFF630BFFFFF0C30C30CC30C30C38C +:10577000CF3CF314F3CF3CF30004CF3CCDCDCDCDE3 +:10578000FFFFFFF2304FFFFF0C30C30CC30C30C3E0 +:10579000CF3CF300F3CF3CF30008CF3CCDCDCDCDD3 +:1057A000FFFFFFFA302FFFFF0C30C30CC30C30C3D8 +:1057B000CF3CF300F3CF3CF30010CF3CCDCDCDCDAB +:1057C000FFFFFFF731CFFFFF0C30C30CC30C30C31A +:1057D000CF3CF300F3CF3CF30020CF3CCDCDCDCD7B +:1057E000FFFFFFF0307FFFFF0C30C30CC30C30C352 +:1057F000CF3CF300F3CF3CF30040CF3CCDCDCDCD3B +:10580000FFFFFFFF30CFFFFF0C30C30CC30C30C3D2 +:10581000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD8E +:10582000FFFFFFFF30CFFFFF0C30C30CC30C30C3B2 +:10583000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD6D +:10584000FFFFFFFF30CFFFFF0C30C30CC30C30C392 +:10585000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD4C +:10586000FFFFFFFF30CFFFFF0C30C30CC30C30C372 +:10587000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD2A +:10588000FFFFFFFF30CFFFFF0C30C30CC30C30C352 +:10589000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD06 +:1058A000FFFFFFFF30CFFFFF0C30C30CC30C30C332 +:1058B000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDDE +:1058C000FFFFFFFF30CFFFFF0C30C30CC30C30C312 +:1058D000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDAE +:1058E000FFFFFFFF30CFFFFF0C30C30CC30C30C3F2 +:1058F000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD6E +:10590000FFFFFFFF30CFFFFF0C30C30CC30C30C3D1 +:10591000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD8D +:10592000FFFFFFFF30CFFFFF0C30C30CC30C30C3B1 +:10593000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD6C +:10594000FFFFFFFF30CFFFFF0C30C30CC30C30C391 +:10595000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD4B +:10596000FFFFFFFF30CFFFFF0C30C30CC30C30C371 +:10597000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD29 +:10598000FFFFFFFF30CFFFFF0C30C30CC30C30C351 +:10599000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD05 +:1059A000FFFFFFFF30CFFFFF0C30C30CC30C30C331 +:1059B000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDDD +:1059C000FFFFFFFF30CFFFFF0C30C30CC30C30C311 +:1059D000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDAD +:1059E000FFFFFFFF30CFFFFF0C30C30CC30C30C3F1 +:1059F000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD6D +:105A0000FFFFFFFF30CFFFFF0C30C30CC30C30C3D0 +:105A1000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD8C +:105A2000FFFFFFFF30CFFFFF0C30C30CC30C30C3B0 +:105A3000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD6B +:105A4000FFFFFFFF30CFFFFF0C30C30CC30C30C390 +:105A5000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD4A +:105A6000FFFFFFFF30CFFFFF0C30C30CC30C30C370 +:105A7000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD28 +:105A8000FFFFFFFF30CFFFFF0C30C30CC30C30C350 +:105A9000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD04 +:105AA000FFFFFFFF30CFFFFF0C30C30CC30C30C330 +:105AB000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDDC +:105AC000FFFFFFFF30CFFFFF0C30C30CC30C30C310 +:105AD000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDAC +:105AE000FFFFFFFF30CFFFFF0C30C30CC30C30C3F0 +:105AF000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD6C +:105B0000000C0000000700C000028130000B81582B +:105B10000002021000010230000F024000010330B9 +:105B2000000800000008008000028100000B8128AE +:105B3000000201E0000102000007021000020280E2 +:105B4000000F0000000800F000028170000B819837 +:105B50000002025000010270000B8280000803382E +:105B6000001000000008010000028180000B81A8E5 +:105B70000002026000018280000E8298000803800B +:105B8000000B0000000100B0000280C0000580E8AA +:105B90000002014000010160000E0170000382500C +:105BA000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC35 +:105BB00000002000CCCCCCCCCCCCCCCCCCCCCCCC35 +:105BC000CCCCCCCC00002000CCCCCCCCCCCCCCCC25 +:105BD000CCCCCCCCCCCCCCCC040020000000000041 +:105BE0001F8B080000000000000BFB51CFC0F0032A +:105BF0008A59051918F484117C7A607E4ECAF43BE8 +:105C0000F232303803B12B103700F1616E06862373 +:105C1000DCC4EB3F2B8F6007CA3230D402F17E69BF +:105C200006062B3984B8A10203C312203F0D2AF6C1 +:105C30001A4817CA53E6EEC182555431C51495115E +:105C40006C552CF2C8580D4DBE411995AF4E40FF12 +:105C500040E3641D54FE042D08FD5E1B42A7A0C94D +:105C60004F84CABB42FD95AA83DD5C3722FD9DC6E9 +:105C700082CA4F40E3B730A2F2CD38D0DC0F550FC7 +:105C80000000174B67C80300000000000000000080 +:105C90001F8B080000000000000BED7D0D7854D52F +:105CA000B5E83E3F73E6CCE4CCE4242461C2EF24A3 +:105CB000841034E21022064BEB097F869A7A07AAF9 +:105CC000985AC5012306082452F5E1D37E9948026B +:105CD000011106B53414D4E14F692FB6918B965A51 +:105CE0008A033E2DB6BEEF059FB57AB57DD152FC35 +:105CF000294ACABB52FBAEAD6FAFB5F74ECE39CC19 +:105D000090E04FDBFBDEA59FDDD9E7EC9FB5D7DF49 +:105D10005E6BEDB5CF78483E29B89C904FE01F2DC3 +:105D2000FF9741087DD4577A7412CFBA98909C3C63 +:105D30002BDE534EC8D03C2B452AE973530B7BA571 +:105D4000FE7EA23C9C332B04EDDAF2AD10A163B4CD +:105D5000E5CC2331182BD640480121AA4EF09F688C +:105D6000EF31E7EAA41C1FFDF513F15E21A4DD2C41 +:105D7000CE867EEEF10949127289BD2E1322C6A489 +:105D8000FD7C02DE12FA208F107F959CBCA288C297 +:105D90005D924C41DD0833B80F17BD523386AE63B8 +:105DA0005DB51CF186A1F7AD844C2664058C45EBEE +:105DB000EB2676D78CC983F76A04DECE54F6B66A32 +:105DC000B4BD5142B07D70623CA5613FCB28A4FDBB +:105DD00072180824A76C512D091262CED0FAE1C2C4 +:105DE000FFB770FD066FA79738DF1B64FD1F95098D +:105DF00050EB25D18BE8F8535DEFCB66BD0DE31A70 +:105E0000843E2FE3CFE9BAEE873F0A09F91209E48D +:105E10009DC8A27F5F4A2E053C909A5C42A69C8D4D +:105E2000BF7EBCC591BE8430BA68A4EF1FD241E7E3 +:105E300074B862464FA744D7ED8BC8C44B1FCD52F0 +:105E40005ED48B012F4715C4C3BA3A86E77533E495 +:105E5000645CC275D616D2FEA309C363CEF862890C +:105E60001413B2B185D6C79D8DE7EC928405F4F783 +:105E7000951009F82A9B3E1B42D7953D35857C330A +:105E8000BA8AE193DCCDF011A7FFFBA4B81F9FD91C +:105E9000029F1127BEB2393E736A6CF882E755142F +:105EA0008F13E0BD138F49F883E2AB5EE0319F8C26 +:105EB000453CC67311BF03E1F10A8A832C0ABFFF78 +:105EC000556FD25BD48F57C11702AF26C7EB8699A7 +:105ED000BD3A30C3468BF1392129490EE178925CF5 +:105EE00085EBC3B203F0E6C5FEF85EA7301B7C9ECF +:105EF000309DC75F9640FCEB141D4324E053435292 +:105F000081AF814FD3CCBB4E4FEA126DBF69AA4C13 +:105F1000805EEB2C998469FD74999A5400EEB8D593 +:105F20001DB2F1A901F8A7F8BA8FE3471B213BF096 +:105F3000A9E6F95D7CEE5CC7A6BEF5597C5D6C1DDB +:105F4000A43BD901709C99299375D2C0E30E842794 +:105F500031EE80F0F598BE1298F70525B28EF2DA90 +:105F6000BA70B243A6F8DA3883E1E36CFA7EC6F978 +:105F70007A7BF5924ADB7C915EDD2CFF02E62139CB +:105F8000CE7555993E33ADFE3CBF7988B960743407 +:105F900090991E9F1BFC610ABF0D4F7AD894607CBC +:105FA0007DFC3D3AA8784276E8A017DDF39C05AF6A +:105FB0006B5EF73C6A49B3A562CDA987343341D8FB +:105FC0003C16DBA7087BAE821EA1FAC71F71EA113F +:105FD000B7FED64638EB6A15D3D72AB13D2F02ED6E +:105FE0004EF5CB85A45F4F570E4EBF10AB01E17548 +:105FF000EB93315CAEA7EFEDA95329FD4BB6093DFC +:106000007DF72FCA687D37E8695ADFDD0973D1B2A1 +:10601000CBA9A727F0C1CABFF3920C7A7A47063DF5 +:106020005D9CB0A6819E2E49D08D808E53BC9EE98A +:10603000E9E28E6619E83481EB097280E149A7FF35 +:10604000B3EBE9623ECF986D4E3C15733D5DBEDF0C +:10605000F59CEBE962979EDE087F507C154A1C8F09 +:10606000634929E271EA20F73B8E47F77E570C73AC +:106070008FA1787C90ED7739790C8FED1D3201FD81 +:10608000707A9B8CFA715C51548676424F72D0487C +:10609000195FFF4EAEAF059C636698D5A04C4B8848 +:1060A000590DF4D1D693482A0C7ABA310EF36C4AC2 +:1060B000303D5D922072CC6607691C9E4DA1DCD9F3 +:1060C00020D7A7136A0496B98B8465BDA81FAF7D3E +:1060D0007607C7E3D7A095431E9C74CCE17875E39F +:1060E000675CD2C9DF250FBAE8B1DE59CF71D1E5BF +:1060F0004AC9657F0C921E5E95C4BDB9504FA25D22 +:10610000A7D3B5E6D3BAF22FCF5AC0D746277BA67E +:1061100075C8C922CAB7813656F774A8C96A5ABF6A +:10612000218FF1F5D83849825DA784A204ECCFB164 +:1061300079547FD8F0E9E1F81474833F011F63B804 +:106140007D913D33D707FCBD298FE37B06C33755CF +:10615000803ED07F02DF1E8E6FA3B21BC023B3C36D +:106160004E7C4F3AEAD437D7D60D71D4AF890E3F63 +:10617000277D3C9C8E1E4E27C14767E13FEEB20F44 +:106180002B9D758F8B3E2D924BEF0C923EDA115268 +:10619000067C3B4EF64776149DDD2E21C948373AE2 +:1061A00079F2389D7F0135E3B2E9F8CB48CF28403A +:1061B000D001238CE32C977B0AA07E8AF46E1E39D3 +:1061C000A67FFC512A392051234EA2E85D49411A8D +:1061D000A693545610C18EEA05B874C48B44FFBB15 +:1061E0001EF94495015FC34DF69CC4B355A887883A +:1061F000F817463A79F99F852B9FFFB344F128F1B0 +:1062000052013A8E01FCC4506FEA2481753FE9C205 +:10621000D220DD5806A9A686D224A604652E896060 +:10622000492E483E9142FD79B789FCEEFB1DF924C9 +:10623000AB7F3DF7C29F14AFC348F47109FC273A06 +:106240009EAEF4F3A18FF321B5D3906F7593F1ADAA +:106250005E42F7D372947BF45FDC785ECBF5F28616 +:10626000161DCBF52D262E7268281997297D7CB531 +:106270004C8FE4847A3AC06FF137AB912B68DD6FB5 +:10628000F4BE7A13D87BB76B917B68FDF0CCE74303 +:1062900050EFB8DD60F6611BB353FD1C7B1D637BC3 +:1062A0007B5651B836DCAE47F823873EDA30BEF76E +:1062B0009D9DA0B76EF34700BF9B4247C2AB405EB7 +:1062C0009A3594176A7B22FDD657FCA208EDB58F4C +:1062D00029FC943E2842B4BFFE116D3589B61BD10E +:1062E000DB82767D7377B59287EFE38170FF7A3B2F +:1062F0008A87E1FEDF71642D09D3973995710BF020 +:10630000E52BA3A62CE5435FA529C50D90CAD8EBC4 +:1063100012E53FFF8C18B128FE0221B3157845E73E +:1063200074236A2204F2EBC667C7C87868219D37D8 +:106330003E5E8BEC46B632A57969DAF5E17FE61D63 +:10634000D75969ECA96C5942FE3F327E11FABD5E05 +:10635000120B65814E2AD3C86E0AE7BAF18B46C785 +:10636000D2D87B3639E3F64AFA32533F4D21CD5D20 +:106370003678C6CA32F29F24EB4C6E43948FA85CE9 +:10638000E5988C9FB419C44AA681E3720EBFAEC6CD +:106390008989F6B529819DF545E1EB5D89C1B9563D +:1063A00022755D69DE6F0778F2413EEE4EC1FE98C0 +:1063B0003D93F135FDCFEAA2F0E7A8AC14ED6B38C0 +:1063C000FC7B78BFF3D043050F027F940FCEFEF223 +:1063D000C2BC69E09DF829E6DD48E79565139F0B8F +:1063E000BCBBE9294A49F6E1FACE8CDF1C02FB343A +:1063F000139CE1DB50B79370332D87D2B29697266A +:106400002BDDF39DEF785F96D93ADCE3925DCC9E6D +:10641000F2F3FDEBF094572C85D26D749CF0B88AA2 +:10642000537F8C2E93D15FDDB4876EF845A03F5823 +:10643000FD915D24A950549EBEFB1E19E01A49ED42 +:106440007C683F84C464C05B11094B500A3DB88628 +:10645000EBC10F49F43A391FF47417DA45B595B713 +:106460004E4B1737AAE7F2713EFBD45768B9408FFD +:106470002E82F18DC8318BEEE4447B31BD5CD1EDD1 +:106480002A34D7260F44117CC1E4A99DF33BC8CD23 +:106490001C5A9F777D7A3837CDD48631BBC52C44C2 +:1064A0007F47350BE7DAE471532B952BFA3E09E36E +:1064B000D9E4E0BB7C7DAD5C1ECE871F6B6869466E +:1064C0002C4BA1AF6A92891940B7ABA5D86A998EB7 +:1064D00053D11C7956A575634FB7E567CFD7C2F383 +:1064E0007925CDEDC01286D54D40DF3E72F70A0BFF +:1064F000E8787A045D7A1A3B4194AA253BEC147D36 +:1065000084DF690F0D521E2F8824A601BC65E1634C +:10651000D5B961A0536C1BD069C4D1C86158A251D0 +:10652000772C956FA357D8646523004DE1D7E2948B +:106530006E488F6808E8B198447742FF406594C57B +:106540002B07094726FE0F8798DE0A737E6F8F5050 +:106550007E97FAE5C1CFE5A19DBF3F5D49D0BF68F9 +:10656000CFAB30D3ED1782DF05FF0B7DE86E77F8F8 +:1065700053F0F9785A961213FD9A0F49EC39C0037B +:106580005D3DCA9F16EA42FF4EC8556DE4D88C2186 +:106590001047AD0C5728B6FDFA7DCE770B74EB97FC +:1065A000D07FDEF50BDAF3291EC6DD4D22A066AFE3 +:1065B000BD7E01B1F3FBAFFBDA475F42F9BABB1B0B +:1065C000DDD281FA75F3F55D2D455FB3F3211DE74B +:1065D000751CA7A43B2EDBF44E0EC7B332B38F3F1E +:1065E0004D10CD9ADB122AD0A7A236A248B6755C10 +:1065F0005BE7B4E729BFBF03E3BAF9741E69F690FD +:10660000F3D83F4649B15E80B7B6A4BB0DE0D34294 +:1066100051F4F728DCA7E1F91700F727E782FB1D03 +:10662000887580DE8C545B43C2089FAA5C027E544E +:10663000AA2D3F0C783FA602DE299E35C586E7C10C +:10664000CAF9FD7CBF1848DEDBE00FB49763790A16 +:106650006D3F4467724A7A8E11E67739E397C26ECE +:106660000E8608C659736A7B08F86B171F55D0DE73 +:106670001D5A4B24B0C3845D3BC475DEB001EC668B +:106680002A3FF7B58450882E367A8FC239C08642A9 +:1066900099D9C753CE0C83FE3FAAEE09813F6856B5 +:1066A0009D59775318ECED30B65FDB12E1FB4F15C7 +:1066B0009689DAB7F6ECA4F36F08F9D15EBEB7A5F8 +:1066C0004CC46B11EE2122DE5BCBEC7B11171670F4 +:1066D000D1FE3A0FB63ADA93900D6FC5B6FE61A6B9 +:1066E0006F06EA9F55E9C47B5F7F6B70FD21DE6F0B +:1066F000EF5F6DF51C85F89CC9E3FE42EF05791B41 +:10670000B34A46FF59E0D95BE68CCB25F8FC99F8F3 +:10671000C53D1F09FB1DEB27F106846F05978B4CC8 +:10672000E3B473FD28EA1E92DE6E5BA6F07D929FB5 +:106730004B997CAE1F594E7C5C2CE87790E3CF647C +:10674000F22EFC1A8C0728F6F9D83AB08E719A38D6 +:10675000D3C72EF8457F8DF7CF0487E61EEF381D8F +:1067600067B26D1C179C99E0739F9391779CE364CB +:10677000D65FAE7E27074787B3FA119BDC633DD710 +:10678000551FE66A5FEC7A7F81EB7D85AB7E99AB26 +:10679000FD3457FDABAEF6735DF5EB5CED17BADE7D +:1067A0002F71BD5FE1AAFF5767FBF2C59F0EBFFFC8 +:1067B0009FE149C8D5D978493ACE79DD72554C5216 +:1067C000A352B4DC91F3E22278D5A348EA099847B2 +:1067D000C4B7486A82DD8FFDBD11FB1DEC633B3EF3 +:1067E000B6FC512A57BB122F05617F13CF4F4A6F5A +:1067F00004C787A97DA8A596B3785002E5C64FD4F3 +:10680000B77ACA804A12C6D174A31E51AE97D0E798 +:10681000367DE52551A4B336C2F99C24981C9640D8 +:10682000808A8E17DFA4A1BD171F499263419EF392 +:10683000D8F8D8BEB81FDE492AD34FA168A21A647F +:1068400078585DD76128DD780A4D8F4F7C9EEA65C8 +:10685000F200F3CB77CD74FAD5D7F171E6ABE7ED63 +:10686000A7BE3249E91F7FD7B78D482B6DB20B8089 +:10687000A0F5F8B7F524C4374641BC8E1D2260BC94 +:106880006E24E1FF785C6E04FC4DFB8D348E62FC5F +:106890002DDC601E019DF775B514E17A44EA1D0FE9 +:1068A000F3C9592727B2F3BDBF7E82F1788EAFD0EE +:1068B000BD937BE2104FD9A845C6229E238867EA84 +:1068C0008FB7792B804D187E57C1EECB9EAB815C84 +:1068D0003877E1F400FD4B4B1FF013EC8B2485F56A +:1068E00000E9C17A36B773CBD4225C7F0EF7330947 +:1068F0008948607F84AE4CEF9747A5EA32F592FE57 +:10690000B8A51466F14969FDF37F9620AE5546C2DD +:10691000CC7EE171C2B58AF409C45FCDC1D98BA127 +:106920006F3AE94AD46632C7E65F5EAF0A3F8FE14D +:106930006B4C88AD3FB4516B06BF66D76C271F8880 +:10694000F6EAF9F3C1E60963BE383EC855C764E00C +:1069500083EB4D88574B718AB7ACC1E3CD54AC6F14 +:10696000AAB84E82E3FE40B26EB0D75562DDA8E60B +:10697000F7D77FAD4417C2FBF83452D66CF48F437F +:106980009FDF0CEDD23C6F48D77E1C8FDBD2FD1908 +:10699000F7F152AE03866E3365B0278B3A57F8EDA8 +:1069A000792EA57CBF7EAC739F0FD6BBB5F1DCF60C +:1069B000D17D2DC8FC19DB05A5EE28D0835CA29201 +:1069C000DD69CEB17FCAF9BBAFBDCB3E9CD116AF5E +:1069D00086FEB97532817834DDE7D1BE2BE27EEDDB +:1069E000E6A97149A372F8C0168276726EDB429FE7 +:1069F0007D3D857C3D9B6B0BFC60B76CAF5FF855B4 +:106A0000F413A8FDAFA0DF1B5B07E317D6B0F37E3E +:106A1000377CF7F2F525EA199EDCEFB334124B27E9 +:106A2000873F55F9F9834ADDC782FE73947B0FDFF8 +:106A3000F98BF174BED22A39E20BF7C339AECF6EAF +:106A4000EA417C655DA69AEB400F776A0E7B73FB8B +:106A5000B6FBB7D4C3B91F7D0EEAE0D12F370F8B39 +:106A600052B81EFBDAA2171603DFB7CB04F49180ED +:106A7000C32877DABB47FAE4CC392F1DB71AF15295 +:106A80007F6EFFE9D3E2630B97F34C7CE2DE57DDC8 +:106A90007C703EFBC355CA675FDF7E90433A6E0150 +:106AA000F7FB86D685A51EA35F8E849F22E629E08C +:106AB0007C965B7BBF0FF86C4B5D05CACFE9DA852E +:106AC00012E8934DD0328D9E10F3658227CB93C090 +:106AD0007C892DF5F74BE9F0561863F122F7F36A3C +:106AE0000FA3F37A352141FF4CED467BB8BEE67229 +:106AF00055C8D7159A9A8A02BE0A222AB987E2EBAC +:106B000081DA85D5A5C077540E21BE32A386A0BDFB +:106B10005068B1732293E2EB69BAEF6DAE2791141E +:106B20006DB7D9D2F01CC62D876E7EDC5C7F6EFD02 +:106B3000422C5B7BCAFF1E8FC1CE734B4809D853D2 +:106B40000F0CE0BF0D16BFA17A99C54B67540CA07E +:106B5000CF5BCF378E39EFCBC08F33069907E0D2AA +:106B600017E4D92DB34BF3201E42F50549871FA723 +:106B70007E18081F6EFC5F0CF8BCF08BC3A7FB7D72 +:106B80009E87C70107898FF575C5FF03522633B568 +:106B900077AF47F41379615F21BD0AC8BF051C3A7E +:106BA00006BC8A0896334814CB636A2CEAA1ED67C9 +:106BB0009166ACD79004968B5593D199E7C188F331 +:106BC0006E753AE3FB719792249C3B93A973F9612C +:106BD000B06A9DD00986523F49E35711720F8E3734 +:106BE000DCB51F8B38C5D0C6446D051D77782DCB1D +:106BF000FB1C5EB5CFB18F05B9FC88F1B6560D6EA2 +:106C00007F7ED4B53F3FAAF6E8409F47ABEE69854B +:106C1000ED46CD7D2794AEFFB84E275E377CDCE590 +:106C20008BA681676BFD011FE48D6DAD4A9F17EB4D +:106C30008623D3FB7119CE99BEE265E74C5B73F4F2 +:106C40006FB0649D958EBC04A21845F679B77E4C52 +:106C500072A2E7D4274E79D9E8E1F921011200FEAA +:106C6000CF840F517ED178786C5AF392689AFEA542 +:106C70005E2637ED39240EE7D28FBDA632FEE37AC9 +:106C800078F237C249B017DA414950FDFB5835E375 +:106C9000CFC939FCFD4361CCAF1ADE49E21ADDCF22 +:106CA00086BF5AFF400E6D775F3DF5206DCFEFAB8D +:106CB0007CA903CE899F7A59C6B8EE645FB71EA13E +:106CC000F054F17D706BFD4B989F1CDFA646C6A269 +:106CD0007E97883419BD79A48780F7198FCAE85642 +:106CE00079BF2F0CFB57B8478F50FCDC3EE5253DA4 +:106CF0004CCBFB46A47458E7FAAAFB91CFF7D51703 +:106D00007FBD14D1EACC3B99A54CEDB6E87CEBEB0A +:106D1000D9B95D4E4F4AF7429CB54E255750F8827F +:106D2000065BEF7DED24798F047030FA4A640EFA29 +:106D3000C585AEBCAE0257DE9B5939EB5DC86731E5 +:106D4000E19C1F16A1343E7011E8DB2699B95BAEB9 +:106D5000FC68A3D27A17F2036629077D907FB5A558 +:106D60004D3571FF738DEB5E874962872D09C789A9 +:106D7000831FB8E541B64F9A138D483C0C5D39DC52 +:106D800026857B089DB2CD09B7C0AB7B1E77DEF5AB +:106D9000BB829F8793B1A08744BC59C0EFE6DBBCA0 +:106DA0008AE4FE97281C5B5F3670BFDE5AF5D23747 +:106DB0009B609F2FF362DEC457CFEC69FC112D7FDF +:106DC000F9C70325505E59B8ABB289B60BF07C0900 +:106DD00011CF2B8091D17EE57A8DF30329DFDEE69A +:106DE000C9C347984771DF111FD2ABB04D4EFA802F +:106DF0003E6A8A007FE55D9640BBE9BEEBBA31E9A9 +:106E00002250D725C56D721610F643634C82F3FBF2 +:106E10002BEA12B3810F0D9E47684412681FCD54B0 +:106E20005ED431CECEE966723884DCB9E9525A9F1D +:106E3000D2212F65789B1A0170873736CB202FA57A +:106E4000552C6FB9B4B34BE279C2984F3F8E237182 +:106E50005CB481E5156E63F817F9DFC14627DD4C98 +:106E60009EA749FD0C19FCEEA24ED7FB680DE66308 +:106E7000BAE95AACF1BCA8529E47C8F1309CDBB3CA +:106E8000EB1BF9F99CA127CF65CFEEE3E7734761D0 +:106E9000FDE3CE7E3F2983DEBD0AF42ED5378A9CE2 +:106EA000EA40FFED3219FD37371C1B1A99BEDBA5EE +:106EB000C90EFBFDB3CE7F03D7FB8ADCD301EBFC0D +:106EC0005BCFDFD8B7FEBFCFFC77FD9DE75FF777DD +:106ED000C6FF96BFF3FAF7FC8DD75F532639FCB394 +:106EE0001D909842C7FBB157C4D39C7A5B91D3FBEA +:106EF000D96F69B2239F58E4294EAFB31668783E24 +:106F00002E137BFE8B186FA6F24607E8D32D5C9FED +:106F1000523D4A205F207B8AC89761FAAF86EBBF5B +:106F20001AAEFFF665D0AB15902B96877605DE0777 +:106F3000994412E8C7048FAA9867BC8FD0ED05F476 +:106F40005AD89B362FBB80C3EDD6A7055C9F56BC95 +:106F5000E87ACEF5A87B7F2FEA8B9B128C9BFE777D +:106F60008DEF8F2EBD2AF0B0A58AD9C97973D3DBF6 +:106F700081EB5D74342A9B31FFC04D8FB734E67FBF +:106F80000B7A2CD0ADD7B5FCCCF4EEE1F4BE9CD39B +:106F9000FB571AF33F44BE48267A5779D93C9706E7 +:106FA0008E875A6135D16AA483C2E9A490F5DD18B1 +:106FB000F725B713BB5FB9E1636A7F507A6C358CF4 +:106FC000C83DB47E691E9145D2FDC793FBF3893D50 +:106FD000DD2C7EAAE4692E3FCB6DFFEA9837BED543 +:106FE0009293F122B023766C5D0E76C4CBFE08C47A +:106FF0000BB6E674BE887E5C62920A70087B91F0E4 +:10700000B82C981204ED26F7B993D3DEDFFA715746 +:107010000AEC2EB348C2785F47F8FEBCB4F7F15CC7 +:1070200076BEE10D38E206E48AC1D9EBAB38BDA9E2 +:107030009F98EFB5C5295705664D62E7E6334C3892 +:10704000DF91AC5932C4D1338D0311DE13B6F3A6F0 +:10705000C5AA3512C693C06F2CEBF71B0919C1E204 +:10706000F262FD83BD3FD0B8989D7B73BCE65DD6D0 +:10707000F5B9F88FC2DF17ED0C6AAFA5BBBFE3F619 +:10708000C36B3CD614EF258387FF116038DAFE8589 +:1070900072A5265DDCA087EBD7C0D1AED973E9FA23 +:1070A0002A5FE4717D6AB6D9CFD3EECB53D3F6FF16 +:1070B0003997935FC1E548D4EBA978BE84F92404DD +:1070C000D625E4D13DFF443EEFC4CF38FFCB5CAEC4 +:1070D0002772B9262482E73099E6ADE67A43949F79 +:1070E00076DE1EBEEE6ACDE471DF73CF3B87AF73F1 +:1070F000CE675CEF493EEF9C41AE77019F6FC16761 +:107100009CF7233EEF8241CE7B2BC7EFAD9F11CF83 +:10711000AA2EF1710687E7563E5FEB679CD7E4F332 +:10712000B60E72DE4D1CBF9B3E239E47F07937B9E9 +:10713000F09C497E777CC6F9CA74263FBBB8FCBA7E +:10714000F59A983F502847A1FFD6101DC7A6A7AEB5 +:10715000F4B2F94549529FA0DF3A9C9FE74E597E11 +:10716000C7C27479E1A2BD7B3FCE34CF37799C464C +:1071700094629E203F079D72199D27CDFA44FB899A +:107180007058909F79FC251C9E25E7B90ED1BE5AF8 +:10719000637A36D3F8777238EE74C13FD0F8A2FD27 +:1071A0009C01E0EFE070749C27FCA2FD8201C6FF09 +:1071B0002E87E3BBE709BF687FEB00F87994C3F142 +:1071C000E879C22FDAB70E30FE931C8E27CF137EDC +:1071D000D17ED300F87996C3F1EC79C22FDAEFEAC9 +:1071E0009377A7FC19E2FB06115206F7BC47117F03 +:1071F00004BF6F10E9398CDF3758A985F1FE799704 +:10720000FB5E94ED3E1515F1C37796C6A1FDC38BC9 +:10721000599EF2C31309FA110FE7B3BCFCBE7816EE +:10722000B7071F9E28633CE9E190338FD9E0FED970 +:10723000C3111E2719C1F2988D72719F964E57C0C7 +:107240004DC430E4D3B0FB55C2DE13F7AC56A97C75 +:107250007E8B245B69FF87CB597DEB0C92948B6C02 +:10726000F7AFCA52780F080C5B88C3F6DF1FB3C8AC +:10727000CA0A5B1EC6CA14E619A83C5F8422843879 +:10728000F2315CF7B6C4B9E135116B26A8B9A24A50 +:10729000768E571475FA0F8D70998BB6FF2DD79394 +:1072A0006665FA7B357B75169715F99A57F3F50BDA +:1072B000BC55707A6E98F3C7EEE9749D2F4CF5605B +:1072C000FEE80B47391EA72A49766E4E3CE9EEE3ED +:1072D000648AB3199DCD477C143FD7BC482240C671 +:1072E000C036AB3D8C71B58F91FF30AE46E7BD66C1 +:1072F0005B4205FE9BDD199E0EF1C0AB5F0CAF82B9 +:10730000EF0A8CEB24110BD0FBF1B7709CDC36122A +:10731000493252B59A2CDEE78CCF897BBF3C3E07C1 +:10732000616ABB7F399BAFBBA2CD6C8723BB8A1937 +:107330005E87FD3A9BFB99FF64791D7EE66C7E7F3C +:107340007AB6CBCFECD49DF13AA3333A13E2DCCA40 +:10735000D5C72C1DE08F4A265C4BB921BA498573ED +:10736000E4D9DB9AD9BDDA0CE75AD90FCD0DD8EDA7 +:1073700077718EFDAB6DE7B6D7459C41C41D5EE1CC +:10738000F7F15EE679C57DF9289C3F72AF961C7CCB +:10739000D2A9333DD2097C92FF9F7CF279F3C96F69 +:1073A0007467FCA113DE51792C8DA43F9F6FD0B57B +:1073B000FF94D72F800E415F7A3A90C66C471EB17A +:1073C000C8A772E36D0DC79BA8EB19EEBD8CF0F159 +:1073D0007DD6EDD7BF11AB867589380D2177B9CE33 +:1073E00035A746CE159750C4B98FFC8602EB29F31A +:1073F00071FDA31215C777AD03E5BE00F20D390C80 +:10740000AEF1DA415F78FBD7E529895A12DE1725FC +:1074100078CE07F9EAFBCA617F341DEBB67C6CBFFE +:1074200059C7EF0BAD2B5393592CAFCAF9DDA2927C +:107430001D7A3ABB4294702FD59EE7E186572B897F +:10744000C5EDF0681C1EF7387333C2D3E0887F9D0A +:107450002F3CDEF1847403DFAA948B917FBFE51883 +:107460004F2E4B929E7471283E0EDC55C375B9E8C1 +:1074700092697E7D8433FF49CB73DE4F518D5C571B +:107480007E948BBFFAE242839B4F7CCF6735E783C4 +:10749000367E1FC5DDDFA72648240DDE7D61771E01 +:1074A0004612E9E00D39BF3BE0315D70BBC65F0FAE +:1074B000CFD2E4DFB8EF57AE5593686FC5299890E7 +:1074C000E7D9CEF9523593782FEB3B3E29EDFA49B7 +:1074D00024FD7EAB96A487DF7D2F48CBCB75D221D0 +:1074E000C3FDDBB542EECD5D16F00992260CFFE739 +:1074F00096F3839173EDE759426F49BF513EA14B1B +:10750000DAED737D2F6190F4553F1A029756FBEB2D +:1075100054AF42BC96CA08E6F1BADB1F13F87B638E +:1075200007C22FF474D636914FFBE9D601B906ECA9 +:107530007CDCD93FA31C723DA770BE7E6E80F567D0 +:10754000A2AFBFC49D4F3838FAFA40EE61DF532D29 +:107550007E88EE94FB4CF31193ADF77CE5FED3C22D +:1075600039A42646409F69A11889D17DBE309490E8 +:1075700020CE6048BD71F0C7A84C8581CE1BE1527A +:107580005DBEB3DD34DACF5324C73DD9207F91C32C +:10759000D03E1E225DD07E7D9E5AB3A3BCBF9D21EE +:1075A0009128F0BB91AF46E1B9182F7BAA733C6AD2 +:1075B0002628F67B58EEEF2D78A630FF54A376E808 +:1075C000F674FAC4CFECD0AC677D78AF2F1035924B +:1075D000C092859549CCE32C6C2011F0E74A3BBB67 +:1075E000498C0EBA96C3515899C0FC80C26D093CB3 +:1075F000B7CFF39266D8970B1B13D202DB3C657EA4 +:10760000C6DFD3E6EAB84F7CAB9ADDDBEB0E2D4C40 +:1076100054C37C55ECDC2B90A79261141F8157BD9D +:10762000CCFFACEC816F49B07C11FAFE9D16525133 +:107630003F9690F75A742C4FB698589A1FFFCF1068 +:10764000E4B7B45F32390CF90867020DA361DFF8C3 +:10765000A02584EFEFFB76240C7944CA91D7F03B48 +:1076600012FDFC1E574815E4BFF658403FDBFA7781 +:10767000F86CE7FC7DEBA2EB5D40E7B957926F84B5 +:10768000F9A0BE10F95457B4028EEF30C333D89727 +:107690009E76127DA21CBE6792946E2DB73DF75167 +:1076A000BB0DF6D74B4CA47B3F3E93AD1CDF13C103 +:1076B000DF2D7C91E3756ED539CF4DD6B7A4BA676F +:1076C0008CEDAF1B19EEBBCDF54CBBDC4FE7990938 +:1076D00097D8299F4F9F5B3614F0F5A0C7798F5C30 +:1076E000948A392952026DE38532CA21FFDECA8AA3 +:1076F000F1E1A139B6F16772F895233F41FC669537 +:1077000027C477776A0B6D79FF23620DEC3B7ECD42 +:10771000EC7E8C38871C7D7D4F2B1C498C5EE9BC30 +:1077200037338BDFF32C6A9731EFB5680AEA505292 +:10773000D44A30BF6AA712A900FE7E88BC9C632988 +:10774000B02B1332928A6A51DC39CECE45B5CF4385 +:107750001C40DC1B5DD5C6C61B158E1C0D43FCA44E +:107760005C467B793489E830FE68432670AF680C4C +:10777000B18D43EB239B9DE3BAE12D0AC8F8DD02EE +:1077800001CF28B25FB7F2707C92A4FD4750376FEB +:10779000781AF8DCF38C11ED2EAAA8489134F392F4 +:1077A000DE5638173A6BFE01C66DF1F7E5DF05418D +:1077B0009F6F93D8FAE32F2891DD40D75BF760BC29 +:1077C00066C48A4EDCD73BFDCCBE5B4DED01C303E6 +:1077D000760A2DC766E643C5A488CBC6FD232DFFD8 +:1077E0003DE6AFDEE88778987FDA46E043BF1ABE11 +:1077F00016E8E13FEA21708EE9B712287FA484D908 +:1078000019F796176783BCF99BB5B4FE5A9BDF83C3 +:10781000F06DF34B2AE48352DEC275A98DE1EFCE01 +:10782000A2D5FF966F3D02F3BC9F1FC3523C0F2DA4 +:10783000AC0B037F4EBFA51CE35FA73B258C7FBD30 +:107840002D253548D15E7A75F3842B283EE6E4C4B5 +:107850001E857E8D75DDCFB333DAE652F0EB6A21FB +:10786000CF2F1FA68B337F70C45B1115EE838D5015 +:10787000539E207CCFE7C8ABAC8C5703BFEB7003A3 +:1078800086D2335862BD0B7E5380DF3F52486F5C17 +:1078900002FF682A216FD9E8063E9DBD0E67BAF641 +:1078A0007A26FC0F54D6D3BE6F8D855D3E62496843 +:1078B0001724D97710CCC8048053091D2D28B1EDA9 +:1078C000735EBE3EEFF485FC7B4916F76F22C4EE73 +:1078D000DF7AF9BA4087BF65EBEF0939EB8AF9F92E +:1078E000AE43D8DDD2337F3901745CF5A407E39E43 +:1078F000D39FF4A42EA7F565DB25DC67E4434CAFEA +:107900007FB04B42B94F0534D403EF9B3AD69BBCB2 +:10791000DD1BBE44EBBD4F2A6407A2A50EBF2F7529 +:1079200042ECA707587D117790966D3F3C1FC66BC0 +:1079300038E025B04F2CFBC92D577D89D66FA17C2F +:107940000C4D96ED6ED586D1FAE2A4D405F553D34D +:1079500008F2593C574B425ECBA96077C13506EE21 +:1079600063243C0ECEB7BB0BAEA6FCB824F9C42CE6 +:10797000E8B764AF049154BA8EDDCF1752B8967D44 +:107980005FC2FD71E99E2C12B6E1F3045DCAE5F415 +:10799000FD0ABA4ED087B790C42CA0D7B2DD9B3475 +:1079A000FB3EF75E4B19A67E88FAB2EFD37968BF2B +:1079B000E53F9422B0C4E590EF00FBE54F7C753BBA +:1079C0000D585FAB561A8075ADD1A0DD2DC9054F9E +:1079D000F9C200DF766D167DBF64DB766D5139E04C +:1079E0008DDC08FBEAD23D1792B08DAE273A15F434 +:1079F0001756E4E83BF07BA286159A9B261EF25EA2 +:107A00000B71C0B584EB0DEAF769736CED9FCACAC0 +:107A1000413E5DBA4771CC23E81F3F46D83DB49F35 +:107A200005F01E9AA09FD8AF04FD56880FE5A9BDAA +:107A300093D3C103DFD5027812D4BF81F2FE961032 +:107A4000960FB684914E9B018FE3585E0A3CA77255 +:107A50008BDFF30B5AF0A129B88F625543FE656E98 +:107A600094D50BAE8F49E173D8E9A2DCEC892D00E7 +:107A700023676AD6F766AAD41FDBACC56E8590B5BE +:107A8000A9EE983983EE798D59D1C959B673BFD50E +:107A9000FC3B3217678571FDAB0B35C4F7E61B263F +:107AA000EFE4F127DC2737DFB0E851888FD3FE5FA2 +:107AB000C902FF829FFF65EA5F30BFCAD1BF607E07 +:107AC00083E83F0BFBEBE7EEBF79FE65CEF9E72FCE +:107AD00011FDAF42F88D73C35F70E354E7FC373696 +:107AE00062FF262FA36F6F8E8E79D66DBE48CA03B4 +:107AF0007456097E875ACD2DDD01EDC4BE432D4B52 +:107B00000BF2B68DBD3915EB889D8FA6CD073802D7 +:107B100054BAEC7C945DE577C8558E95EBA80FA917 +:107B200019E6689F1F2D76BC1F5A77818B2F0DBCDD +:107B3000B78875000A0C730AA7364C437D543D8CF8 +:107B4000D9C1771CF261FD8ECBD8FAEE1866A01C65 +:107B500003CCE097DFA1C52EB67F2796AE4B82C33C +:107B60009C9B8DD89DB08EFEE761199EFB79BE93DC +:107B7000DF4B50DFAD299ABC336EC367C748CA0FCD +:107B8000B4DE96A531BC733AAC19B92864B7D7579F +:107B90008FD4EAC0DF80E73719305F7435CCD7A4C3 +:107BA000F59682DDE19EC75B5CE598471FD580F3C3 +:107BB0006CCA62F154318F7754836B1EBD6E077FA0 +:107BC000CEE77900F82CD33C6B8A2F73AE67D412C2 +:107BD0009CE761D73C6B462D71CDE367EBA1CFF9F4 +:107BE0003CC973CDE31D33D5B99ED18D38CF3FBB92 +:107BF000D733BAD1358F81F3C07398871ABE61F835 +:107C00003E96E6ED5D84F47FC687768EE68D3D86F2 +:107C100076CEEB3EB473682B0BBFA355C6FCDBDB03 +:107C2000B272913E67FC94FE869DCE719E7710479E +:107C3000BFF8660E22495288A87E5BCE79B07EEFEF +:107C40009C51AD501E981E5A00FEE883018CE37DC6 +:107C50007060BA76531A7D7473C273A2C7C6CF7DA3 +:107C60007A95C7634359EC1C52D44FF0F8CF5B10A0 +:107C700027A2E5DB1E82FED0711E2FEA87B715FB17 +:107C80009DE0E77A27B6B17DEACCA663ECBB3971FB +:107C9000F272F964F81E0DFB777322CBE18F377116 +:107CA0007AF4FEC49BDC81F4B086E3777F3B8738AF +:107CB000E285BF39F4B5E759DE1D190EDFCBBBAE47 +:107CC000E389E7A0D92BD282912BE87AEBF66FF209 +:107CD0000CA7F50F3C3DF323866D9C3A0FDEBB17D6 +:107CE0007EC837621E87FDFCCD0667FD06973DFD09 +:107CF0004656B1389F65F386931EA0D73C3863A5DE +:107D000024BC014A4CBE33915EF34DD657C0D374A8 +:107D10009787A470BFEBC9C738673C1FE33431B104 +:107D20006FB9E09BEFD1AD28A5E7FC3B15C4A31BC1 +:107D3000DE9E4359964CFD9C9ECEFFED81FB3B039E +:107D4000C17FE34AE77B12F738BE4320F8E0DABA96 +:107D5000EA9DC76DFCF18DD8EC9DC71D789AE3A80C +:107D6000DFD0FC0D47FB1B572E70BC5F105FEC781B +:107D70007F53C7AD8EFACD893B1DED6FE96C75BCA5 +:107D80005F9C5CEB78BF74CF26477D59D71647FBC5 +:107D9000A603DB1DEFE543E3FF09FDC05F2978CFB4 +:107DA000F943E3C406B0DF3E34D977FEDFE1E7777D +:107DB000EFF1EFFD2C07DE9B02F2334907BFA1C9AB +:107DC0004FE599DA12138CFCD51D53418F10FCA49A +:107DD0004685317C759C3ABB53F8BD44A55323A915 +:107DE0002170BCD21F87ED55FADFAB3DF4FDA4CC6A +:107DF000EF954E35ED7BB5474D3BEE29A9B714EC19 +:107E0000C7F86BDEB4F7BFFBE5920C87FD22D3FB0E +:107E1000933269B0FB6FF30C161F7A3E6BDA3C03AA +:107E2000FC218DC97BE3BEC269E037346AA9D274F4 +:107E3000E7367DF37549F89DC079069397C549E704 +:107E4000F76F97EE19E390FB57FDB16B0CDAEEE498 +:107E500061857D2F2FF5ECA8AF5F04F35BF3E0396C +:107E600039908FFBE32B2DD6CEE3D40F78B5A50642 +:107E7000CB7F6D89EE3C4E1DB5375AEAB0FEDB96DE +:107E800018963D2D0D58BED5D28CEF8FB7ACC4FAE5 +:107E900089963896EFB47460F95E4B02DF9F6CE907 +:107EA000C4FA072D492C851C087B9744B93D290E3F +:107EB0004C08AB9FE66B500A441C3382DF8F3A6D4F +:107EC0009C29053BFAF4AB5ECCBBCD842737DF653C +:107ED000A69F85FBFDA2A433CE2C4A9F9FD1C72726 +:107EE000931AC891583B56C3389AFF990BD11EA7D5 +:107EF000CF55C2BEB71CB17F4FA26F7C481E1E3A41 +:107F0000309D44FB13DFFBF7C90BCB813EC58827AF +:107F1000FFB34A33A3DBCEC8D72F1A187F68F315F7 +:107F20009E8D47E999DF8C82F8D4FBF9029FDDA38F +:107F300020B8A51AD12DC087A7F77B715DA70F6662 +:107F4000B17C1408AA0D22FF75E91E5FD2AE1F9600 +:107F500075E5249DFAA23069D717A78FEE0C82DC55 +:107F6000AF0829C9E393803F2CCE1F8CEFC4F8CB18 +:107F7000BA8A9286631C67FD7442AAE9C2B858386F +:107F8000FBEA34FE87285784349CE7BD3D6330FF0D +:107F900080FA89C9E32CDE9964F3869276BE6C5C24 +:107FA00099953C3EA41FBE4CE37EDEF011B29FFCCF +:107FB0004ECF7C0F77A092A8FFA6E1F72D0F7ACEC7 +:107FC000C0BEE3A5FF7D82F9422AD6C5B84D5D4A01 +:107FD000DC0BF778C95EC77CB45F58F8E8F6EFE6CB +:107FE0009C4D77673EF86F819770DF66F7CA6370C4 +:107FF000AF9C8E774A353AA48BFBEF953771BE5C08 +:10800000A6F76831FAE8FDFD63CE990FF25ECB5119 +:10801000531D0B790409FC604443D7F819A01FDFF6 +:10802000DFBFAA00E2694B95D377A4BB2FFB91C1B8 +:10803000E26C24E9E9EDB1AD47C46708A1E3EAFDCC +:10804000F003A79FB0D5DDFA5A947280C5DD97EF93 +:108050003D36EB4B14FEE507FEA8011C078C981C6F +:10806000B0AD5FE2F7EA97EC795383F5BDE389970A +:10807000DE750E3D75369C46C8711E1A27DD20C779 +:108080000BD96F30003F5DFB3A15CD777FE921F0CA +:10809000BB0EE2BC42DC7BA827D120E06BE1FEA551 +:1080A000181F7EF7A92BB93D97980CFCF13E916BF8 +:1080B000607DEF939782936CF82B09303F86743084 +:1080C0003B46DC0BA4F6ACC3AEB9A5D3595F44E67E +:1080D0001680DE58F4A007BEA14A1613DBF797E816 +:1080E000BAF302CCDEBD8534AF067B4EF532FF60BD +:1080F000A149D4E1549F2EFBF14393C1EEBF30C0A0 +:10810000CE1D451C63712EB3F796E42535384FF824 +:10811000DDFE49F3BE04DCE74DAE867D9964A73FE2 +:10812000FFBBA9C309DF40F0BBE115F7DDCF8AA78C +:108130007038943D52DAFCB42901CE775C8FDC13A1 +:1081400070DAF96B5CF5DA008FB32A44013ABF6F3D +:10815000EA71391BDFE3FDDAF83E6F645518BEA7FC +:10816000158D027F51BB6002B1B5FBBD11C3E7277E +:10817000A51717E1FD72353501F3F174A2DA7F8F8F +:1081800041F10727908B214EDA8C4EFD2A5F700754 +:10819000D45707D83DA8269053B83F1D9C7514E2CC +:1081A000FA3A49A4AC2238FF76C6BF7D61673D0B21 +:1081B000E409F4093C007A4408C68BB2CA9CED027B +:1081C00011677D491F9E528AFDDE47503752F87B6A +:1081D0004D55EA49BBDDBC5C67F013F89E2A6D7F04 +:1081E0001BB7E79793701CF316438C0F6E9BCDF271 +:1081F000266E0B84F15EB2A45A783F620D74B5ED21 +:10820000634D1F492469D3EB4D6AAF067CD9F491C5 +:108210008ACF1F3662DF06BC6AC4423B57A7488339 +:10822000F36BD5A871D8BD6404FF2EA02B7F617DB0 +:10823000C074F87B422F78B85EA4FA624D201FF418 +:1082400060EF2C76AEDEA3B1F31DD64EEB6FB71EFA +:10825000E0C8D4CED7DF6E53BA76CB7EFCF853712C +:108260002AEF4B7EF49D201CA6BDAB260A20FFA161 +:1082700071777B10F8F81D351E8475BF9B4C9FF7F6 +:10828000FE73AEEF20DF09EEC92FE7747AEF07F730 +:108290005E05783FB3DB83F7EC9BF678535E4AC408 +:1082A000E5FB17337EDAE37D93D5D7E0EF2E341D5F +:1082B00070CADB92C7BE5310C6C3BD38F31B490A50 +:1082C000EDE7E5BB7E3F0BEC9126D28B7AC2DD0F4A +:1082D000E6FF2817F7AF0570DFDFFD5EE45B357161 +:1082E000BE6FDA7F2FE65535ED9F8D79544D2E39CF +:1082F0006FE07EC88180F37736043E4892D9C5ABE3 +:10830000BEFFDD096F52784EEEFA655072C48F9849 +:108310009E38DD75D3234F8733EBF70FB85FDFDF70 +:108320002F89FDC207981D4F0EB2B2D1930A82DF8A +:10833000D4B8DD13A11A84343EBEF3D1EF017FBF60 +:10834000E6C578C3D2C79F7BE5325A5FFA8427AF70 +:10835000962DC3803C604117B8DB0EF9BA820E4BF4 +:10836000FEE5392D7C117B7E776E3F3D963E715840 +:1083700023179D8DBFE95D8735FC4E909B2E5D6F69 +:10838000CE02BB7BD5F7FFA4817CBD7B4822438B0B +:10839000CEEEDFB0FD39B4EB004F48474EA73EBAF2 +:1083A0009D45AFD4554F57623B13F6B181E8F53D7B +:1083B000E0997CE4EB1F3E0DE705FFEA8D001E1AF5 +:1083C0007EF8AD20ACE76DB599F1F743ED05708E01 +:1083D000DEE089179858B2E70D0FDF8E7C77CBB1BE +:1083E000DB0B581E9455C87F17A010E380DBAEC18D +:1083F000752E2231E4BF868794289C937DA8929A9B +:1084000027D2C8C7E541A6C7DEDEE1C58FDEBD0DB8 +:108410000A17FCC5979424BB6FCBF2126F17E71EA7 +:10842000F0DD465AFF5067F4CA0FCAE27B56BA83A2 +:108430006F77ADE9063ABD37D21A0AF14A8A873812 +:10844000C79B047A4839367328A31309AB93793F45 +:10845000AA27A7C37368DFEDB17C131CFDF8BEC665 +:10846000E6BF8DCF4FE1F6837DF67601B577D2ACCE +:108470006F6950C83FB53F6C7C66937326F7BBD6D7 +:10848000323917729F9C5303EFFFED652647D00FDB +:10849000F6790A576A28BE3F7CB5847AC14B52E907 +:1084A000E47B9787CBB7F33DF5CAD1BE157C42E19B +:1084B0005761DFEAE71776CE4BE980F6DBA2076962 +:1084C0007FBB7D0EF3623BADFFB96DBFBF85EB8314 +:1084D000CB82AEDFDDD9963FA8EFE4357A928F7E6E +:1084E0000FE497CA2BEC3F8D8F7B304FE40F7B9FBF +:1084F0007DE53ACAE77FE81272EBD4A76EB96DD872 +:1085000077094927B77F302224ADDCD2E769E5D669 +:10851000E8417EFE5BE95381BF8541679E93D08F22 +:1085200099F0E8D68F7F0D84D9EF22B8F423FDF7B8 +:1085300032997C361F0AFE137CB7E49F97E1EF83E4 +:10854000F4F1A7E0BF3EFE14FCE75EAF137FEEF749 +:108550001782A122E2C5B4F4DC43E20188A7FE4CF5 +:10856000C178EA290AD36A4AE7537B8BF01E71BBB4 +:108570008FF9E7A7CCDE606E397EFF06EBBDF9DA36 +:108580006AD017E279AF8FC5BF4F457B83F63C9029 +:10859000370F2A4138EFEA49929A74FE08D5C80885 +:1085A000470FC9F49EC58B4F81FD07F3F94725811D +:1085B0006E331563D44AF0F313ECBE7C7DEBB5410A +:1085C000C853387570CC46D05F37BFA010FEBB854E +:1085D0002AE49BDCC4E9FF0E896F9E4AD779D34118 +:1085E000E657D4AF4FCF2F4B78FB45C66D1AE82521 +:1085F000EA17BC658F872FE1BFC7D4B0CDF5FCE08B +:1086000095C8574B5C7C15E37EE3E382AF269289E5 +:10861000DC6F93EDF96C3395F28D60979C3ACAE26A +:1086200090A70F2A488FD37B2596FF04F1E029C03D +:108630000FBD9A3D8FED24F05F9AEF1BF4BD7FF2E2 +:108640003793EFA24D1A9F7A7DC2565A9E7CEAB5A7 +:10865000D29F42FDC7BF1EF53A39BBFDF4437FC62A +:10866000F3EC5387BC08C7A9433F1F7517D49FF687 +:10867000E2776A4EDDE365F99F8702C9B1F07E2497 +:10868000CB175AF5B33F4D60DF7F6943BABD1A641B +:10869000FED8E983FFFE5BC81F3E7DD01B86753484 +:1086A0001DCAC2F3ADA6A77D18A739F5B33F4DB6D5 +:1086B000E7337DD6F52CE7DF413C15207590A77C8C +:1086C0002A879D1B34FD74CA4EB847B46CFF610DF8 +:1086D000CE63A63FF39709A0774EED63F6C4079EDD +:1086E0009E87E19CF577C11BD77820BE0BFBF53048 +:1086F000425AB29357C48D747861783845F100EBD3 +:10870000A27869007D99091FFFE71F161F7F9C0F44 +:10871000F3371EBC14E5A61F2F92C59E079270B5B5 +:1087200089AE9F3D3FF4A709601FFDA1AB15F7F986 +:1087300081D65D98FDFFDABAA5D460D65DF50FBB92 +:108740006EC6FF87826196F7E79283B3F9FCC7771D +:1087500060FD878108C23B48F9AFFB875DFFA7A496 +:10876000FB3E4AF7E0C074FF2FD9EC5CF81F6FDDC9 +:1087700003D1FD054EF780097908A77EF6178CAF67 +:108780008BF50FB4EECDFF41D72DECA175722451BE +:108790005C0479D8A9EEB004BFC3333701612985E1 +:1087A000E75DBBE17A3E9BF9178AC4E23664248B0D +:1087B0001F11EE6FF4FD5EACC1EE57A9C66AF63D1F +:1087C000323582DFD55B77C1C208E676908A57637F +:1087D000501F31157FE7D6ED77B549C492A8FDA7A4 +:1087E0005EF0D5A360FF7BCAE4947702966F42B92E +:1087F00086C7BD3CA6E6F0370C979FE00B3BDF7BBE +:10880000F9783AA948C0EF77EB866A26E9FC463545 +:10881000FBFD68C8ED4CD8CE0DBDC4D69F8EB70306 +:108820007E93C5664F9E2FFEFE94CDFC4F45AAE871 +:1088300086BC58325E66DF3527EC5EF1BA1191E4F2 +:108840003AF443997FD98FCFD5DD80479550FF907B +:10885000AD0FFD4AC2FD49950FA196C996CFD98E9D +:10886000FB4B03D287D1635423A7CF0A073D04FEF5 +:10887000D3D0C5410F81DFF3A58B9B1E6EBCFF22B9 +:108880009BC5E7DC7472E483E433BF24450DE49FA9 +:10889000EFDD897191F77FF0E655D07EE94F150243 +:1088A000BF8BF6C1DE004981FCAA490DFCAC25FB5B +:1088B000158C0BFF5F8242FCFF008000000000006F +:1088C0001F8B080000000000000BED7D7B7C54D561 +:1088D000B5F03E73CE4C6692493249662633793103 +:1088E00049208246980408A82813020842AF038A48 +:1088F000606FD49167304F90B6B4D51F0389313C77 +:108900006C83220F4B7540545AA90D182928DA415F +:108910001E62AD5FA3D25B6CB137E203150829ADCF +:10892000FDE8BDF672D75A7BEFCC399389686F7F2B +:10893000F7FBE7CB3F27FB9C7DF65E7BBDD7DAEBF1 +:10894000ECB97409FEC63376495C196B66CCC55820 +:10895000EDCF5319733276CF9EA4C8F442B8EEFD22 +:108960006038BB9AB19E55BD4773E17EF8A78AFF78 +:1089700029EC1EEE1E7E0BDCBF476377054B63E3DD +:10898000C86BA6C3C4D868C6CEEE4F9913B133A640 +:10899000EC3C78278DDB31DB9CA4C4FAD91C669AA9 +:1089A00017FA05F079F8274A6488D27F3CC656F258 +:1089B000F17EA270F8F6992336846FE7364B08E013 +:1089C00068DCF9274B00E0A8FAF9CFD2BA61BEC63D +:1089D0007D2A8B0E65F47789E173359A349CAEEF6E +:1089E000E395B1805DA960AC01FFF5C1B5B37E3AF6 +:1089F0004B836BC7DA3FA969F8BEF954B735F67EE9 +:108A0000EDCF5FDE1B06D4D43EFF4C9A0FAE9F75B0 +:108A10003D95C64A69BCBB2DE98C6976CDD01FC790 +:108A2000BD98D97F1C98973137DCE7B75863C76A80 +:108A30003E5FE7374E33848FC138126E58DF67F8D8 +:108A40008F97B1B18E54E7C757C1FF63D8984B2AAF +:108A50005C776631764D7F3CC5F015E6F4FCD9E7CE +:108A60008F87013F67F79C791CE1AFFBAF3F3FFE6B +:108A70007DC01F7BC5E6780AD6DDF8D3DFA6217D51 +:108A8000E57B331D0ABDD793CFC25EE8D7F36E52A4 +:108A9000240CB77A5E3E5DE083F5F6ECFE9BDB07C7 +:108AA000FD97BD3C291BD7BFEC85AA6C661F188EAD +:108AB0009E158C4592F47045888EBE7D30683634A4 +:108AC0000F886B1C3D0E751E2A4038CF9D48F2273B +:108AD000219EE0DEF272A40FD069386FDF07F86DD7 +:108AE000D8F5E09FD4E189F01CCE357990AE1F4CCB +:108AF0004638198BE6320FE2B7B7D561EFDFBF8F8B +:108B00005EC7819E23BE02DD76ADE6F37600DDD240 +:108B1000FAD3ED1CFE03F46944BAA5C4E8F6390B98 +:108B20003DE12D86766716D13511BEA25F015F3516 +:108B30000A1FFF7A47E07B0E949F3D297DF49A8EB1 +:108B4000F4FAD9E7050CE8FD89B9F74E368AB1DEAB +:108B500097931CDBE1FE3D2FFF8EE4A4E785B72C45 +:108B60004847F8B32BB0AE1ED6F7D785EB6C50C490 +:108B70003A77A44693D262786F88CC98E24BA3FBF5 +:108B8000EFD3FD08E75FC45F2ED22772F0562501B0 +:108B90003D3A1C45B40E1671D1BAEB77FCC1827C0C +:108BA00023E984F451C622BDDE9F8CF7259DE4BAEB +:108BB000E3C773201EC6E8E8B683CB617FBAF65AD6 +:108BC0005871227A01BCF81EC20BED9E6D499A9233 +:108BD000CEEFE7C13A7ACC6C4E07C211517E97882E +:108BE000BE8CADA2F53C1B2F97627D9793CBCBC17A +:108BF000FD8FE2E5C70E078D2FF173F68BC4FAF9EE +:108C000028CA39C0BFCF1E3A82FCC39835F2218CE6 +:108C1000731753587A710C6F12DEB31A23BD7BF6AB +:108C2000A76A240CEB6FED38447A365EBE615D8135 +:108C30008E04F3FD4ECCD7B0EFE070D443675FDD18 +:108C40004FFCD7B0EB7D4B18C639BAF3794B776937 +:108C50008CDF517F4774FAFBEC73078793BEC5F135 +:108C600013E89B0FC5F88D078CE337EEFA9361FC90 +:108C7000DA7087C561BFFC3C9F6981D9B8DECFBA85 +:108C8000CC0CF5DF671DEA944882795F17F64BE25A +:108C9000A9F52D0BD9B1516F274792004FCBDE9A22 +:108CA000F28774275E2D3E402DEB5CC9F9AAF3FED6 +:108CB000402ED2A5F3AD6FAA684FF6221EAF888D65 +:108CC0005B71BCA92A15E4B6E2647014B255BC3ECF +:108CD0001873C264801BE6C946FDDC02E3F8601C21 +:108CE000A6F93D4118574D9B3C05E1511D26872DA6 +:108CF000A15DE5E399ED411602B8CC60B77D3A7EFF +:108D0000F2CC4C1BCED271795E13EA85A5C05EA869 +:108D10009F3D16365403F89829D9FF148CBB74581C +:108D2000A0EC08B4972EF0F8C3F0DC7B0B7FEF9C2F +:108D3000C31E368DC0764104E528E5A2CA7CA0FAA0 +:108D4000CE2ABF5EC84025A408BECAED48213B9389 +:108D5000A2F93655433BA546F30346D947F6507E64 +:108D6000860BDFB3D07BDE0C45FB18D79DC6D250F7 +:108D7000DEE4F8B29F1C9769D1E1B87E66651A03FC +:108D8000BB92C738DCAA584F31EB5290BF9B67A407 +:108D90006DC7F6D6D41AB2FF05ACF76000E8F664EA +:108DA000DAE463A8C7E05F13F6CB6F32DAF741CBA2 +:108DB0008DEDC2B01627BF3E5310F8AFB8CD78DFA7 +:108DC0005955B964901FE46C7DE7140DF4B77376C0 +:108DD000E5EE5CC0E9B4356FF3F63395655E681F68 +:108DE0005F5F3755033DE2FC4D655901B4CF3FFC51 +:108DF0009DA9F4BC1690742DA8FEF5574F0D97C68B +:108E0000E4D60560A6AB24CF37201ECE05CFB6E250 +:108E1000D3FA597FB5C023FC0B221EF2C7723CE483 +:108E2000D94FEE66D07F90A97B25F2E5132FFFDFA7 +:108E30000CECE7630E5AAF83B5383EB6E2E2D9D800 +:108E40004B23BF4C9F69EC63C9876A4C0E5477E88B +:108E5000E60CE0ABD6B943374D465D5BE727FE82B3 +:108E6000991D640F657F8793E8335FD007E1B402F3 +:108E70009F2DE05DD822356C61346EBB2548F66AC3 +:108E8000A203E753C275EAA5ABBE3E5CF3907F90A8 +:108E90001EA92C15EF6B753E82EFB02BB090F0E65B +:108EA0000AD155DEF7CC9DE30B019E6FC808D6E0D2 +:108EB0007ABC0B2F16E03AA667301AAF6A913D8054 +:108EC000F6F5C201508309E44B5EB7AF607E6DC812 +:108ED000C0CF8399A16FE3BC45BFF4ED3906E38DA4 +:108EE000986FF1DB608A11CB47F9B52CC61784FE69 +:108EF00087A09F07698AF2F76D1641F93B9FA4048A +:108F000002D03E7FAF83F473DEFCE9C7D0AE9D4F45 +:108F100029EC88E2FDEFFB482EC11350502EF20FD2 +:108F2000A4476D69C4D77F8DE3EBBF1AF9D838EF3A +:108F3000F94BBE7DDD349E438C078E113CCF17F478 +:108F40003AAF72FFFCFC0A1FC1016EE441B4BB5F83 +:108F500075BE4733843D15F4B9DF16D8887801FC17 +:108F60006FD6E37FEBC0747C42D0F18944745C68B7 +:108F70006D2A40FD704FB06332686E362323B40310 +:108F8000C73DBDF068AB19D6535FDD54824CDF9FFF +:108F9000BE0AE973F781BB579AA1DD88F4F1F5A702 +:108FA000E388E565442F1D5D3B108E1107FE64428A +:108FB000B8253D3729DC0EC4BFFF528622E6AD5BE3 +:108FC00069063C5ED86721FF37BEDF910C1FF59321 +:108FD000EDE1D60ABF06729A6D62A144E31EE9373D +:108FE000AED59F9400FEBEF11C7C3CC0FB6B7ABCEE +:108FF000BF21F56F7FBCFF1FEC0778A7EB57C0FBC5 +:109000003B5F8677E96FD70ABD50CBD6919FF95168 +:1090100060A67B30CC3B59B513FF2F7E4A25B98320 +:10902000FED3BDEE981E597C4DD3415CE7E21F2B69 +:10903000C4A7F3435CBF9F5938FD28EAF505ED4608 +:10904000BF69E11CD03300DFA2CDC6FB8B23717159 +:1090500020D3E973E08733317E1DC4F58C87ECA4FF +:109060002AE4A16A51693AFA49AF987DBF213FFCD1 +:1090700075956D4F80F7FCCC42B2C37DED264086DE +:10908000CEBEB3F93613EA4939EEC445A5D9E8CFC7 +:109090002C4DF57D69FC3568B9D19E178693994FA3 +:1090A000376E715BA6A13DA43DC7D0FF8ACD458632 +:1090B000E7C322571A9E5FB5B3DCD0BEBAE35A436A +:1090C000FF11FB2618DA65D19B0CFD471E9B6968D2 +:1090D0008FEEFAA6A1FF9813730DCFAFE9BEC7F0CC +:1090E000FCBA4F961ADAD7F77ECFE8BF9818E94551 +:1090F00096AC909E3CBCE2938A0F910147291311D4 +:109100009F556379DFC34B2C26471A5E4B4C0EE00C +:109110008F57174C27FB7F78893BE0A36B4500E313 +:109120001EA68E1B154AE0DF4E727C5AF1A16EDE40 +:109130002AABD9A0D726398CEDF24C11170EE27C60 +:109140003326D328576AD3F4A8059A398B0767E3E7 +:109150007C205FD76672BD46D7AF205FE3B1DFE901 +:10916000B4682BB6A57C31615F2B051FC135602922 +:1091700047864A253B1CC09B3EBA1FD6203E9960BD +:10918000F5E71DC1F598FC4E64BE89738287CD9CBE +:1091900003B91D66434D5FC70E4BF9F6987C61B26B +:1091A0005F998CF2495B1694A4331D5EE764F2FC70 +:1091B00011D87D7E75EC1CA949FC15E9EF4F19AD5E +:1091C0000D8DDD57164DCF4679F30CA0072D9EE28D +:1091D000613B40FF5ABC857495F75BE798A6441243 +:1091E000D0B536531170703F6B58CCCFAA257A7822 +:1091F000DEDE3804F0D550DD4B7E96C7D4BEE428C1 +:10920000AEEB572ACF93812785FA6081F09B174CEC +:109210007D78C951D04B0BDE1C427A49CEB37545DF +:109220007498DE3FC81B208E7A3A93EBF1C757043F +:1092300086CD1F4270915E907E7941B87E32C637EE +:10924000835813C5891B4DAC26D1380F8A71B29152 +:10925000E408AFC34EF2716EE1C9340DD6919C1A89 +:109260007A10D737774457058F0303FE99E07F15AF +:1092700044EFD888FD0B3C1A8B28FDE7CFAE0EB526 +:1092800015C2FA5A324D7E3BB57B15EC9F741F63B5 +:1092900059D0BFE5BF5482A7E5D56B18C66749F61C +:1092A00026867EAC5CD7A1CCC7083F6A670AD93D49 +:1092B000862E28E0EF5B82F69F7BE677A17FF1F9AF +:1092C0000633CDF739ACD101E37FDEA946D0593F53 +:1092D0009A991C35415B6D4B257B5D803E27F45F81 +:1092E000D8991AF115C6F0A26D1EC7A260DF92F2DE +:1092F000F8FA5B32ED117B21ADFB8799A36370CA4D +:1093000075E70F1077BE22E06681A1063A7B210641 +:10931000EBC2B93570F6611C758399E2C205197606 +:109320008233B2223C6CBEB9FFFA5A3D336FBE1D88 +:10933000E0693EAE3215C6F175B7133E16023E2205 +:10934000BEFEF83EE72BFCAB4925B85F417AA99BEE +:1093500027D3BA18FAF1F05EFD130A7BAC10F9328C +:109360003485E89C63624F1526F00F50DE5C883F21 +:109370009E3FB0784AB89C78060FDB01E3FD2A7364 +:10938000407FEBCD4C6EF7E91AAF97C0FE85118E8A +:109390000B9B15A2E76925623103CA6A6F8D1AEC2F +:1093A000BE1A50C9DF88870BF4D8894C9D9FA3A6AD +:1093B000DF371CC71DD83FDB7DD082FE9983917FAC +:1093C00026F5E740FE19FA65C87FD22FFB384E0F0D +:1093D000C3FA3E15EBFB34D1FA12E8DD1ED2BBDF37 +:1093E0008C26F46B5C96C47A29378BEBBB46878559 +:1093F000511E6A80BCBA2B4BFA71DCAF1848CF5DA6 +:109400002EDE285A5B4AFAF642972F3D13AECE0F56 +:1094100094A644E3A8CB9F1D8974596CAB4CCA0237 +:10942000F8EC5946FC6C59DDCF4EA567717CD1B57F +:109430001FBEEC802F93015FCEAC2FF503B9DECDBC +:10944000C1BC14CCD723F003FAF722E9DF5B7A6EB4 +:10945000C358B1FE962F449CCBFBBB859E8638F843 +:10946000868F7CD4FFCF48BF583CDC5D817150F3C0 +:109470000B57A4A31F3571EFED0EBC5E700E26BC1A +:109480009CDB9B14C079CE6582FEB4637BCC51CC4F +:10949000139C59712C538FD773CFBD55618671CEF4 +:1094A000ED79AB42C37C83C8A7C8E7F597DEA9086E +:1094B000C2FBE1096C68935D475F2BD7EF1B6C3CE7 +:1094C0001FE1725B5AD908F06B5D19F4FEA36ED3ED +:1094D0000FF0BE6A7DA7E04394E7B8FCCB06B3AFBC +:1094E000D90E7C0E31961FF3F84B8705BC0B30FF6D +:1094F00032C34379936685EBBDF0021E1F3A8BD8C9 +:10950000D04218CF6C52557CAFD7CBFCDBA14BD2ED +:10951000E1F628AAA9E4AE8E00823F2A3993F07EB4 +:10952000DD598782FEBECCD768557CBCDE5996C813 +:10953000765D9EC63347233B96A27530D4ABB35CB1 +:10954000FC7D99AFA99A39275889703D60A27803AC +:1095500014A582FA2B57ACA3D0BB67B5F4453437BA +:10956000B215C3E40C5B0BFC3B18F09CE6330530F2 +:109570003F9A96173D61063F2CB785B1533A7F2F2E +:1095800005990FD7F3A61AD90EF29FFAC578EB1CEE +:10959000F0675292B9FCA4055B9760DE1AEFFF6B8F +:1095A00039D285BF4FF451318DC4C2E90072EA58F7 +:1095B000E3B8927E9D2BACFEC1C0A87B5638E8FA7A +:1095C000F40A0FC1F5F00A1F5D7FB86228DD1F485D +:1095D000CE2E777D6805CCABE327E718C00AACD761 +:1095E000A93292C7874657A4CF4DA007E4F5B1151D +:1095F000C7DC13870804023D72EA1CDBD614129DF7 +:1096000051686075AFAD0E8C63EC0173600903D6D1 +:109610007A20EB8B8998575AAB98288FD49A75701B +:1096200075380FAF3E4EB743EF32CC477A47B52B74 +:1096300028AFDEBA76E283515D5D2C24EE07A0ED03 +:109640003DCEEF3F60E3785EC7D81484D7AEB0203C +:109650005E7B6CDC9E7C6CE37AED53712DCC0A3D15 +:109660009C05F7FFE23851F20080672BFD7D01EE8B +:1096700047A41CFA1BE56BD5E1162BCA87F7C0FB84 +:10968000B44FA19ABA2D0C4CE8F38FBC4BF92FD5EF +:10969000122CE4ED9FAFC175B8D282DBD0C562E178 +:1096A00077A71EF680DC203F5C4BD808A31CAFB523 +:1096B0008976F8DF080F6BCDBCFDFC23BF5D1DA6CE +:1096C000767031E205DB2D88978C0E8F09DAF695DE +:1096D000EFAC3E763DB665FF77A8FF7359DC3E32AE +:1096E0007BD08BFAA3AFED80F6D5BAB6C6DBCCCA79 +:1096F000AF727DF587FE763417F8B5E180D281A090 +:10970000790FAC57709DDE7DEB09DFF407F281CB5A +:10971000A03CA6354C79AFA7571C73B4009DB5CCBF +:109720003637E2FD0A4F281048A0AF7FEE92FE2A9E +:10973000F4D7E7BF22E6DE6E9DFFEC655C6E580B4A +:10974000E88704FE4091ABF23D27AC6383125AA335 +:10975000A29EF999D9817A8475713D74568CC5227F +:1097600039E48FD4D978D3BC2AB46618EA893B345B +:109770003FC6B9B585ED95688F6BF717FA57B218E4 +:10978000BFD46674B8CB917F328CED669117C9CE89 +:1097900068CAC828C5FD82F50598CF6F60ED777E51 +:1097A0000FE1FDB5CAD0AFFEF4E035E9D741BB1EED +:1097B000DA68E7EB3BDFB2207F3EE8E4FAB3A113BF +:1097C000F807C65907F21500C7639BE64846FDF443 +:1097D00074A0E94A74C97A1FF9CB541B3875CF14A9 +:1097E000051C446FE7A5D5566C5B1CC35819B62DF4 +:1097F0006B90DF6ACB4C5C8E98E557014DEC4F4285 +:10980000FBB78F54DD14B6C7EC8D57D8A7C6ADF69D +:10981000B089DBA7F368D71A369BC2A8BF4CD62EF7 +:109820000BD2D78E7BAF441F07E16D99D4E771FA55 +:109830007AD9D4CC9BB0BDEC812247F84BF28A3563 +:1098400017535844E7CF3CE8E4725CA385699FA3B3 +:10985000E6621A3DFFE7CD676391915F369F9D9E5B +:10986000CBF9EA62F3115D0F95FF6AE360A0DBB20A +:10987000DD6653928EEF96ED16FBC9B640368EE349 +:10988000B2308177F0CF01BF5A615F3BAC819C3F22 +:10989000D427E7DE3513C721DD62CFD958831E08F0 +:1098A000607CF850B2D4038589FB27C7F52F92ED71 +:1098B0002BA97F3C3CAEE458DB0AFDB5BF27F5B5CC +:1098C00011BEF5A6B8F132E5FCE56B26E6C5F8EA6F +:1098D000B759D7FD2A3C189E67B457627D45EF0201 +:1098E000E643BB8CFCEAD7E9FDDF0ABFAFE662B115 +:1098F00081DE31BC9718EE9F5EE131ECCB2DAA5E84 +:1099000046FB87BF157ABE8685290EAAD99ACB2237 +:10991000BABCC4FF87E31F85E3BA01E0B8E17F1951 +:109920008E42837CC6E0186CB8FF8FC2B1FDB69240 +:109930009B0AA1CBA34AD85A8476E17E13E539D499 +:109940008C89BE95B82F70BF467E1EBA24589F5191 +:10995000A4B1635A39CA4F7B00E372B68AE77BE051 +:109960007E9BB99CEC10F9C1C50792EE463FADA8AD +:1099700026B018AF2CAF94F61DE4BE1D13792BB999 +:10998000CF30C4C12A3570DE46B8EE263B5514AC44 +:10999000AE45674E4D1D958CF6F15153248CF385E1 +:1099A0001FE6F3B94C910E2BEADEB4C10EB477AECC +:1099B00034AEFFD89A52B27FDB4D45572E01381E88 +:1099C000502A935F473C6714519E16EF2F85FBDBAF +:1099D00085DD5233FC0EB453DB85DD6A16FA5DDE9D +:1099E0004FC90CDE8DFEC44967C34DD66B500F05C1 +:1099F000DAB2C0DEFCC1D9B0C6730DDA1B5F9115B7 +:109A0000ECCB1F36D4AF417BB37DA52FC791116B33 +:109A10000FF93B586BD213F56BD05F69B12FBD07BF +:109A2000FD1D78FE2B2BACF3994CA177C4F3A23E1D +:109A30003D057A09F498BAB2AF1D46BD54D4A77754 +:109A4000EA49EFEC785CA5F641980FFD3E5847587F +:109A5000C5F50ED1C8AFB7012CC9D0B60D2BA2FDEC +:109A60001B58374B46FF7A187F2EF3EE962126CAF5 +:109A7000BB637FC4A3CDCBFB5B66303FEE3759524F +:109A8000ED1487C83CBE2AF68F92451D85E298C129 +:109A90002EC1FBD675E54B311EB30E36EE935AE25E +:109AA000EA2DD4F8FA0B7B94FCAFF79C22FF9EC5FD +:109AB0003C978A63F719F397E3D57D7B4B25C2BBAF +:109AC00034953954CC8384A2B40F196FD7AC604756 +:109AD0007D3AF9B0DA5920D17EFF8B2EEED7DA2FFE +:109AE0006A14DF6C50C0BF413B9ACAF94CFA476612 +:109AF00087E45BA3DD95FE923983AF65D9D409D99C +:109B0000187FABF68015FD9C838E728AEB55E6BFFD +:109B1000B952E7EFB444A752BE4C7304C80FCFC686 +:109B20003811F33D0E3FD3FB39AD2B20B0BC82B1D1 +:109B3000272B4A26A03C3C668B5A8B91BE8F9A28D5 +:109B4000DE3B547E4F58C17CD9724672FA64857BE5 +:109B500002E6BBB769C1F43B505E8EC37C3E4E3714 +:109B6000BECFDAAC607EF7736B301DF5C143C8F72A +:109B70003ABC3CE9E27EFD0527F73B1F3073B9682C +:109B80000578A2008776F12ACA473DE0E2FAC95279 +:109B90003D91F23516C007E6E3925853D841EBE504 +:109BA000F9B5248FC950B7A75D1C4EEF5F709A0CB2 +:109BB00071751BACD3A7D35F3616A6FC1AE2F8A9C1 +:109BC00004FECB4141372BF8433EF24FE2F6A1FBB6 +:109BD000FB47E4AF48FAF4F9290AF8275F128F35FA +:109BE00042BCACD7F78D5A2FE9DF468887F17E8FCC +:109BF000C34AFEA1AC4BB00B7DD6EA09B55F877CAA +:109C00009E9C361CF3001AEB20A4ACC3BA04D48784 +:109C10001EADB78FFF41E69B6D69DBB15F8BA8532B +:109C200048F11BE52799B54703289F437572C31078 +:109C3000DF611A37C967BCCF5888619CA179E2EB14 +:109C400018C27DF54A546FA7B12DB8AF2CFDDE5C6C +:109C5000512F742EE58F1528C7E0F78ECEA2BC4D8C +:109C60002FC52D325FF375FDE46C1C03E3D1E57F56 +:109C7000AEF810E56CC6E442BC9FA2713E01575C91 +:109C80004B2AC7F06AF2E20C58FF37B238FF39D5D9 +:109C900076AAEB785ED8B1BF38E678298E027C527E +:109CA0003D4CB2BF9BE245E1A7A97DFAF1DDD501AC +:109CB000A3DF19D6FB792B1E7D77754B29C52BD4D5 +:109CC0007EFE9117D7603CF8804DB65FA036D8B9BC +:109CD00028C64B6C6F920FF910DE0FA0BCB1DB4AA7 +:109CE000C8CF568B580EE263629A95F4A6BA3769CC +:109CF0003BFAC110173F97A5CB739E4B3D5180FE99 +:109D00007082F1C286F10ABEDE78307F27D6CBC8DA +:109D1000E713D3364755FE9E0FDF63795D7F0CC393 +:109D2000F88FBE90C4D6000A1F331BE55D5E378AEC +:109D30003813F58DBE5ED1523D3F804C2DE53AC9BA +:109D400093CCA23A7E9272AE5D1CC6A23A39C97615 +:109D50001512BD342D407924ED62293DBFE0E47C2D +:109D6000D0BAC27199793207986724E98F81E7A93F +:109D700010FA85897CA346752F522F0C24E7F1FB3E +:109D80005AF17A515EA55E4CC1B1E1FA82CB984797 +:109D9000BF6773C75164A1CFECA17DAED158BF742A +:109DA000320D4D789D293A1CF9F8A3FEF71B70710E +:109DB00051CC33C0FD929D4B5E45763DEC0A7D8AC9 +:109DC0007ED02B2E919FF5803D54D1DE81BD28E5BC +:109DD000F96B27E66343BE4D9318CAD36D948F5534 +:109DE000DD419F0BF13BB382720E12EEB52B781D55 +:109DF00099D4B3762D44F8B26A617E7584C08633F7 +:109E0000F6B1EBD24D189B691A97A35F3F7A96FC87 +:109E10000A9B1620BEB2394C3EF40B6C1017A2DE22 +:109E20005DE930F1FD168F95F2F5AD0A4488A03753 +:109E30009666147DE93EB6E5A29BEC2D40E2D1EB9F +:109E4000ED7FFE3C4E611F8CF3680EEE37B043DCB5 +:109E50000E23123ED0E963E90FC4BF173FBEC4A76B +:109E6000C4AF15F15A4AF630A1BFF1776137A5FEAC +:109E7000CC96FAD675A2240A77EB95EE34F46B40B3 +:109E80008FFE1DF9A4E1EADE34938FF4AF9BFB4112 +:109E900061F13EB3EBF95AE6A9E5BA24FC4B5F5FEA +:109EA00060D5EF97C4C31B6F67EDA5C6FA029BCFC1 +:109EB000585F20EBF6552D487C631E17B0A29CAC72 +:109EC00074943BD0CF69D17CBF0B505D8499FC6DFD +:109ED000F0DF0DF3CBEB4320FF08C710B7C950F7F5 +:109EE00022AFA9B80F92E0BD496E8EBF870EDE4E3D +:109EF0007A58F3F37DA178FA31D64EFC925AC21CFF +:109F0000943F15F0A65D66DC81F8E807076DE4274D +:109F10006B63AD11ACBB8C9F4F3507030AEADD3292 +:109F2000467EB29ACFE7578730AAD34E1B95C98693 +:109F3000EAF0D8EA9949CF97BA1C0CE9ADA69A8203 +:109F400089F845E2C9E33619F6AD3D926FBCBFA76B +:109F5000FD151DDF4C74BBFAF38DC7CDF521C2A1F1 +:109F6000A76FABA7283B117D627A91F3D5E5F8A2E4 +:109F7000621CF03BDA79B86E8375746A6CCAEE5273 +:109F8000848B515D7BDD6C3B73805DBBC353799BE0 +:109F90001BC6ABE87A95D78B77BA2868AC13EFC7A6 +:109FA000CFFFB69BEBDBB7DD5C3FA69F083C3B1EBB +:109FB000F0DCD995EC53E0516766623DFD03B76272 +:109FC000AC37D0BA87A3FF22FB57541BE70B0BFA21 +:109FD000DF2FDF0BDF9C89FEDC74C665A3D8AFF0F2 +:109FE000FA867D29912168575954BB05F0BA53C4AC +:109FF0008D3B219E9C01E3BA935908D7EDCA827626 +:10A0000029BD1FD86D8F8DF76B8E3236A938B803F6 +:10A01000C79B94ED2D6B2EE4EFE3384792598BB537 +:10A020003C86F79B9380E532F17938674969ECFE0D +:10A030001150EED8CFEDEE1EAE80FCCF3705DC68B8 +:10A04000473E7CEB7B5427BA88059EFC10E87335AD +:10A05000DCC4F8AAE244D0827AE1537C08F87EDCC2 +:10A060001E5C8D7CB2A07DEA93FA3A17B6837F8797 +:10A0700022F1D59F1FB8FE0138C3D64C039C6C2C2F +:10A08000C26DE5EFC5E3575EEF127C2CE909E8B934 +:10A090002A55D0730DA07E6E0AF7973B2D9C4E7DFE +:10A0A000FCE3B2B4E23ECA592B7FCE0243B97F6FC4 +:10A0B000E5F4999B521041BFBA530BA4A07F3FB760 +:10A0C0006FBF3E40DFF5D4D902E9D720FDDEE2F1D3 +:10A0D000D7E94A7B9B02E39C3607D2516E4FBFA55E +:10A0E0002A2BA9FE81D747CABAB3D366DFDA2BE1A0 +:10A0F000F9BC1FA98195F4D818579C6581916F62AE +:10A100009CB54FA57DBBC287EF56AF86FEF321E01D +:10A1100040BD34B7CA1E467FAEF3F74D7F44BB3611 +:10A12000EFF124DF2A98E7F0E6917FC5F6C7EB52FE +:10A130007D4994AF2D52BC98475D5FE8A0FDB7E51F +:10A140004CF8ADF74EAB1ACCD84FF15FB90F026B9C +:10A15000FE98C9E74FAC9D08EBBCD2D569B2034C61 +:10A1600037643FB1D60AF47E6065D0837988731B6B +:10A17000BFB516F3106E77A06BBC1FE0DBF49D69D2 +:10A18000D8EE7C4C8C175EBE16F30E2F9942850AD2 +:10A190003C9FB269FD34AA532E96E33FB53600F6D4 +:10A1A0007FEE1357FCF5048CDF90FD8B69E81F00F0 +:10A1B0007D053C0708BE05E364FB604A15F80ECE3A +:10A1C0001466C8C79A63790DCAF7764A3F9D1D99F0 +:10A1D00086F9D879139AAA34187F53F61B6B4B87EC +:10A1E0003136A6BDD21180F6D6EC37A7A5009F74F4 +:10A1F000B2402DE64D22D9BF9966BD1EC6CF328E24 +:10A20000EF54455E3FFCCE5A1CAFA23A5086FE4C3E +:10A21000A9E7C3B55678DF8575AC30DF6D9B87AD98 +:10A2200043BF5EEAD17F117A14F4E61994877A6B02 +:10A23000F7514CF5162CEFB5F0FA66A13FF2385FF6 +:10A24000F7B58776F37A74D9F6F076E7AAC4FAE818 +:10A250002F1ECEF79DC9899FE76673FD23E526FD76 +:10A26000040BEC4A203FA66CFBFF48FEBCD9FF8FD5 +:10A27000F45BC665F45B86D46F029FA5467D0DD363 +:10A2800008BD7F6511EA89636E9FC15E5774CD2456 +:10A290007BF2AE47E8151F7FDF55C5EB817AF7A744 +:10A2A00050BE8B59BB4A904EF2BDD102EF550F4EB6 +:10A2B000DF84FDEABACC8CBEF3D85DF9A57E651DBE +:10A2C000E6877571489D16A5BC401DE68747E27874 +:10A2D000BFB6A03F84E3E0771CB80F82F95D5773E7 +:10A2E00062FA4BBFAAEE62060B8FEC6F7F63E33B13 +:10A2F000E9F9E5D6151BCF98BFE83F9E45EC27C589 +:10A30000D9494B6238AB259F02BE4D3AFE5A20F820 +:10A310000DB427F9933D7B876D5F53A89F977F5FAF +:10A3200005FAF9D9F1A82F41DFA3BF59A105A6610C +:10A33000FF8AAE4CDAA792FC21F942D2B533B38939 +:10A34000F27EBD5B14F2A7E2E19A27E1DAAC703F3E +:10A35000A43AA4DEAD834FCA038CDF29C61F35960D +:10A36000E4E7C7DC9F06B9B903E517F7BD711DFE29 +:10A37000EEE133AFEE0FFFAF851F0574E4F87FC148 +:10A3800046750AF1F63286FFDCCBD0B3809E4B7F58 +:10A39000A86E40BB9946EF659F88A6F9A05F97E03D +:10A3A000FFCE8E0FD2AE43B9D8A732C5C7D78D7AAC +:10A3B000AB42EAE3F088372668E497C5EC878FFC68 +:10A3C00033A93FA3566BAC7F70E388692DA8BF9378 +:10A3D000B8BC3A55B036E531381ECEE67A6C6C28FA +:10A3E000717CF303772A3D97F8DEB2BC8A7D00EBDF +:10A3F0003B21ECFDD8EEB082745920F0D8E7CF08AD +:10A400007D767352F773E2FB10033FCA36F83B0DBB +:10A41000A662DD733BD7BB723E80B78561C90A5C1B +:10A4200015B8DEE62914E370BE3CB5377B1BEA0F96 +:10A430006771A00CF58DE42FB02762BDA6BB66DA6C +:10A4400039FFCF4C4087E785FE5CB099AFBFF33F43 +:10A45000AAA6211F74BE9D99B14AC7EFA7841F29E0 +:10A46000C795F224DF93CFF78BF15EC94E237C9C16 +:10A4700012F8433812D58BC9F770BDA4AFDBB8BE54 +:10A48000867587914EB0EEB0528EEB560C76A2CF09 +:10A490003E087CD75B00CF80C79DE6700ED631B9F1 +:10A4A000703EFBE5E517D643CF7BF7A792DE891F09 +:10A4B000FF5C368FE7B699789DD51113C833CA99DA +:10A4C0009DC3DBB3D74BE3760B3EBABC3EFC6AF2CE +:10A4D000B3CDC2EB62017EAA4FAC7F31779B11FEF8 +:10A4E0009502FE50337E87E7DCC4FCCD8CF0164528 +:10A4F0007CDDEBF171FD640991FFD6BB8551FC3A1F +:10A5000004FC081FB41B83F672A53026A7251D0A7C +:10A51000D1B16203D869C49B55E2EDF55DFA793F8C +:10A52000CF4E357C4F5827E83F04ECFBB300EF10CB +:10A5300018E739829BC3756A63C77598A7EBB3F7B1 +:10A540009E34C10FF170462DB91C4EAACB407FC777 +:10A55000372A06278E8FF3307B70158EDBF0CE9E68 +:10A560005CFDB8E91ECE6F4E75EE041BEAB1F5A096 +:10A5700057491D840EE17716F30F6438D6308A1BD5 +:10A580004C181FCA79E78B7C2DC865C50C585A49F1 +:10A59000DF3CA03F75FAAFC863E7FDAD5501AA7770 +:10A5A000D3B87D72B59FBE1FF73106B2ABFF2C7ECC +:10A5B000003AD2BA7B77C3BA7C31FC7576DCBDCA6F +:10A5C00086FAF204F3A3BE94EB1A52DD9D86753C25 +:10A5D0008D428F025E4CC807CE1FF958B34FA79F1C +:10A5E00005FD86322E6F323E198A1B2CD0BED63323 +:10A5F0005CEA1BCA179C7AF1E567D7505CC1E9D5C4 +:10A6000058CDE92BE5F50E4FE85E0FCAC1ECFB68AB +:10A610007F07FA55A0BEABDBC0E7817E1D8CE4B698 +:10A62000ABA01AF0F72F9ED4847473063B6CF4BE73 +:10A63000E0FF73FBAF8E201FBA6EEDADC2FBC00F03 +:10A64000044F67476A04E366F297F1FD97156EBF02 +:10A650005888F032BFDAE1D7F38984AF8FEE0CE887 +:10A660007E75ECFE906A3E6EE33E18978F43F25380 +:10A670007717A37CB3A40F801CC6FCBED43B2EFC72 +:10A680002C3E338647893FF97E03BECF78DE00E358 +:10A69000BD46D64DF9D33A359887F11ACB4EA2EF85 +:10A6A00054210E26FD73C4C6341BBCFF1A5CD1BEF8 +:10A6B0004F5297D0F742938A159273D010326F168B +:10A6C000453FF2E6F129A41FD817F70EC6F5B85298 +:10A6D00038DFC13856318E95FC54A10F7F5300FAF4 +:10A6E0005089E9F1238A42E31CB9FEAAED549B2963 +:10A6F000D689E3A1DF7044999147FEACC86F00DEB4 +:10A7000086EBFDB318FF86055CDD05F85C1F27614D +:10A710005CD3176785C7AFBB11E2AC31533AA226B1 +:10A72000074AC384E9DF817927419C6583F5DF8F80 +:10A730007C8CFABE30ACA6215C4360DD70EB6872A5 +:10A74000A8B4C91E9BC72DF25F6E51B78CFE3C5E4C +:10A75000CD5E6E57D67BB9DDE81657703B12E6CB5F +:10A76000FE533CFF773BD7E36B2A13D7376FF118C3 +:10A77000F39D378BFD2288B7B620FF40BC25EA77D2 +:10A78000F9FE12F8B584DFAA07AB69DFF4F3AE591E +:10A79000E9FCBC072EFF0B44FDEC5DF7CFFA21F27C +:10A7A000DD8758570F74FC48ECEF7DE808A4619DE5 +:10A7B000597D72E23AEA5F7AF83AEB051E4EAFE055 +:10A7C000E7332CC07D4DF083777BB8FD5AD47ECB28 +:10A7D00064A4FB2288E3715F53D64F483AD76C5587 +:10A7E0000DFB130B705F33EB1F8923CA06882346CA +:10A7F00019E208396F7C3C716A85C7B08F32B7BDEA +:10A80000589C8FC1FBCF637E827B5E5BAE611F96DF +:10A81000B5B9BED2B906183F8413C26731DC3FB563 +:10A82000C20A02AE83E393C1547FB2C513FA9DC737 +:10A8300000470A0B1BF2C9E31CB4DF6FE3796CA07D +:10A840007F58EF57C7C375C6F38FC66BC503E0B912 +:10A85000E47F255EAB18C7F51A6B57A89666CCC483 +:10A8600038FF59D8CB4B9E14431E607EB5B19FEA8A +:10A87000E5F1BFEA4D31F8CD03E501F47EB3528C2A +:10A88000FA838FD720EC56E1676F531DEB782FF7D3 +:10A8900033C6E60492BD705D27EAD8D7D9F877FEB3 +:10A8A000DBFE7EC8330FFD8D37CD5477C0F671FEC9 +:10A8B000A9FCF1B2663C37C0DEA138F4DFB57E6397 +:10A8C000B912980FF2E0167AA2CECFD753E78F5A7B +:10A8D00006DBB1AE99C391D77150D1747A23AF869C +:10A8E000F7F379CD86FA80C15E7E2E439157E60D4F +:10A8F0002307A73AB17F40433B93D3A1901DCA6978 +:10A9000062F43D4ECE28EE9F7D63D436655E696C61 +:10A91000BD6DA619A50E78AFCD9DE247BDBD2A2716 +:10A9200074A517E13B198D623A67CCC92E0DE3A7D8 +:10A930000D3981AB100F729D3ED59183F627E5242A +:10A9400087AFBD2F2FC1F536636B055CDB797CA823 +:10A95000B2638CFBBDB48FEB5E3594EC875C8F3BB0 +:10A9600053E85F370BED21FF9BB591FDB3727BEA96 +:10A970005E55427EB2A46B2C9F32AC1CF329C5EB12 +:10A98000A2DA5C78EFC5ADA684E7584C15788775D8 +:10A990004CD4AFE372F22EFB9907C85349BE4F99CE +:10A9A0009238FE8308909E57FED8F94D92CF160B31 +:10A9B000C3FCA6C4FF869CE06C8427A7639B82B877 +:10A9C0003925EA234E25F3FCEDA935CF2AE887DDAA +:10A9D000BB9839543630DC75CBD5C07CBD3CB758FC +:10A9E000882E320E88C1C3E396262FD7EBAFE7043B +:10A9F0001721BD1BF6ADA7FCDEE21DEF5BBE74FFA9 +:10AA0000E32BE24DA9E1F14DDD1C2BD55155FE584C +:10AA100023BAD7B65868BFB26ED76EFA8E8DDDC72F +:10AA2000FC28FF751DBB95F9306FEDAEDDCA021D28 +:10AA30001E73EB2254377E45AACC5F472DA8CFE387 +:10AA4000F91BF3FF68F78FDAB8FC9FADB487319F2D +:10AA50007DD61CAAC37E67BD297EDC3F95787F6DBD +:10AA6000F78D747E40EA9EA4285EDB4CDB3D56E801 +:10AA7000D776A5C58FFCB42127B40EE992A9053B72 +:10AA8000F1FD0C67AA1FF3E1BE24564E76EF2BE2D0 +:10AA9000614C1C5F8CB98FCBCB2B42BFC01FD571D3 +:10AAA0003DEDE5712E6E07A0BE3A6AE6EBD8C338DD +:10AAB000BC666FE047C4B7C73269DE9CBAA882752E +:10AAC0001FF1F3C6F82AB0CDEBFA3A70765850CFA2 +:10AAD000D70A7D53F9E31DCA073AB83BBC2AC19790 +:10AAE000B36B9B82F916784EFA06FA33ACB3CAD927 +:10AAF000C5F34CB5F07C814EBFC87524D033BFC0C0 +:10AB0000F5D84F761DE67A26CAF3CB02DE787A1E98 +:10AB1000F2FA68FEC96066E9BE253C14E3D0A3459D +:10AB2000C9349E94FB78393DE4E5FE58CED61D8AA3 +:10AB3000C94E7978F2CB247CB2DFD89C09AF213C96 +:10AB400063A674111EEAB76AB49E4996E0E0253AFE +:10AB500079F8AD909B5767FF91CEDBD9F08BB78822 +:10AB60001FEBDB151E0FB4BF6599857626FC131508 +:10AB7000F74DA671D3CE368AF3A8A675723D5CDF79 +:10AB8000B95B9B678FF169E167AFD23956F51D4913 +:10AB90000CF75381FFFE80F48BE753891FA96707E9 +:10ABA000A227E823FEFD43D822F2D7A1C299A931FA +:10ABB0003D6D167861767EFFA258578C7F42E77014 +:10ABC000FE989EB5915C147E56FE2AD699D6FB154A +:10ABD0003ABFC359C5F1A9876B46C27D32AE273152 +:10ABE0004FCEF32ADD053375DF93F5E97BF1FE7F68 +:10ABF00022BDB9DD88F2FBAC08EDB7843F9E7E57DD +:10AC0000E4703F36019F693909EC99B4F3858FEF01 +:10AC1000D1F07B20C93FD390EE3AFEC9CAB1D0B87B +:10AC200059391AC1B3B192EF5F6D34733BB671A558 +:10AC300095EA425FBB9DD7A9A57ED312C5EB11D380 +:10AC4000DC3A7C7E2487C3D1665A45DFC7815C3AF3 +:10AC5000734623FFA431AE1FB93EDCF03CD76775C5 +:10AC6000617B04CFABA90BDD3A9FEA109C363FD63F +:10AC7000EFB2D061CBACD4FE7CE5DB73D082F04F79 +:10AC8000EBE0F227E900FA94F84BCA83C46B0C9FFF +:10AC900011833C497A98FBFC895021F797789C52A4 +:10ACA000CA54DA17AAB1068EE2778C35623F15EFE7 +:10ACB000639DABDC4F9D2BE8F2B83D3812D7D96FBE +:10ACC0003FF52BFAD9B5CBDFA0B8E61ECFEB7495D4 +:10ACD000720BF1A041BE2708BA0FCBE1F67D6A0ED8 +:10ACE000E79BDA511D2497B51F36913CDBA770BD59 +:10ACF000663F69D4C78C3D24D6BB8EDE9B94D2318F +:10AD000019F721273DA138304E1E08CE45F81D18F1 +:10AD1000C64B5B0FA5DD8DF8FD02BC75DD7742DF0C +:10AD2000CC11E743EE048413BF3759BECC1FBFDC00 +:10AD3000782C7A5CA1F342042ECFEEAABAE623DC8B +:10AD400037D899EEC7EFF3CFECBAE5BB1F01DC674C +:10AD5000778CF7A39FE06C0E12FFF4BA6CFEED3C0B +:10AD60001F3A05F33D2B3B0EA5E177459F3E3BA2E5 +:10AD70001CF5F61201E767CFABCB112FAB9EF9F9AB +:10AD80000DF8BC36A264A1FF7A76E713FF9503E3C2 +:10AD9000D4EC68C413C858F3B3BFA4B8C014D9C660 +:10ADA000EFEF4C273FF7D327D7DF80F86EEE68A68A +:10ADB000E79F3DB98DDAAF3EF3F357FE03F31FC1B2 +:10ADC00034FA3EFAB3E70F125DEA421AD5C50FC452 +:10ADD000D71B771FE4FA12ED3CCAC11CAEC7245F33 +:10ADE0004BFEFDF499BBAED1DB0D79BF4DE441DAEA +:10ADF00092B91D3923E4B67682BD0DAF677E66A396 +:10AE0000733B1B2CDD25181FD79572BE5891C3F5D7 +:10AE1000605DC71273839DDEA771FE0DE41DAF5701 +:10AE2000037F62FD19F4DA7189EAA89EA3FED06F50 +:10AE30002CE6496657BFCFBF2B2D6D32D7129CCF62 +:10AE4000F2E7B06AFDF38A6589F735B6E4D80DF903 +:10AE5000D19CCE19793ED20349FE213AFF37A7266D +:10AE6000D48C7502372D0BF9F13BFA173F797B3201 +:10AE7000E6D39E19AA8C24FAAB0AB773613BCD5373 +:10AE80008FFB0E107F3C2BE4C4ED60CE6B613D93D5 +:10AE900034E6B4E395B1E366D20B4FD1F8E0E79026 +:10AEA000FFE6FBE5ECA7D0EFD9680E7947E3386DF4 +:10AEB000C23EEEE0F0C3FB0E7B398DE7B896FBEBAC +:10AEC0004BF1BDF32BA73BD1BF8771BBCCBA780C3C +:10AED00038B200ED238E370AF134253C87EC94CF4D +:10AEE00042EB93E781C2FA297F2AE5333E4F83FA8A +:10AEF00009F3ADAFE7541ECE71C5AEEE01F21CD61C +:10AF00005CFE7C4A6E80AE5FF57CD15767F7703B84 +:10AF1000FFD2FBC4B70DC8B7387FE843839D97F5D0 +:10AF2000111BF7BF4F7C3B7F1FD7C70DFB2A2D1886 +:10AF30006F9D5911601F80A3DB20F86FA3D2BD90D5 +:10AF4000BE4FDB6FA3EF0E7B247FB6BFFF31EA9FBE +:10AF5000A27D5EAAE7E9D9CFF9F488C944798023B4 +:10AF6000DBAFDAD6ACF4B7ABE06F939C343431E1AD +:10AF70006F2F7B1BFDB3FA1A5E07DF10C747858F63 +:10AF80009F6A457EC900EF18EB32C09F994CDF6D78 +:10AF9000D6B1D128A7391303FB7369FF9BC7E739E3 +:10AFA00035A04FA07D9373B11F4B073226825F8C73 +:10AFB000FCE7BCDE8FF9A68DF91DADE83F87273190 +:10AFC0003A7775A3B97D02C6C11B27F91C8049C019 +:10AFD000DB0EF2AFD9508BB067F3C92F6FF0FCAB2B +:10AFE0009FF2C1F1F2BF7F25F9770DBE643F9E83CA +:10AFF0003B6D9FB294FB337686F037007EB13D2DDA +:10B00000725D04E13927F027F1D863EEA2F3787B73 +:10B010005E48A2F30DA74DE4FC9A31B183F4C76BEF +:10B02000FB6F247B2DF932756F12D9ED4CCDA1F851 +:10B03000295F744B12C2334FC0D32EEA8433841D70 +:10B04000295EC7FDB8CC5C2E4F99B92671B518EBB7 +:10B05000AC1C61CA3B9C13F42736D19DFB543F3F87 +:10B060004AF254B78B8FE74C0A94DDABE35FE95F9C +:10B07000C97A03AC1B989180BFC7E6723B58F8F8B9 +:10B0800052A2FBBC1A713EC43AEE5730E00BC41B0F +:10B09000D091F8E026E722A2DBBC75CA37898EE1A1 +:10B0A0000ACA1B4AFF2C7EFC71627D3B6DC1515860 +:10B0B00067D8EB4AF5E37ED7CE8C8089F2EE65192E +:10B0C00094077165717FD125FCC598DC07479960AD +:10B0D0009E4FDCA99CDE91DF6898179E92EB4BE8AF +:10B0E000E7F58FF3F978D3DBC3C331EE91F5611245 +:10B0F0001F9195C973F4FA7482A04B64189B837AEC +:10B1000003E2093BE5AF1D300FE613B65FF724CF2E +:10B1100027F073A1AFCAE5DF354FCA0A8EA2FDBF83 +:10B12000E2E0326E3FF93AE3F1F1BAB09BAFCEBE46 +:10B13000B30CE3D8865BED7E94BB0D2F297389AFEA +:10B14000C3563C3C08F89ECB21384C540FC5421ADC +:10B15000D1A3A1291849CCF73348CE1AC0EFC33880 +:10B16000601AF2B993F83EC2F99EDB3F996F403DF9 +:10B17000A9F7B7A53E907A06ED1BF2B3948B861B18 +:10B18000BA4B90BE5F55AFF498B99CF7001E508E35 +:10B19000A4DCA4BEC8E565CD4A5F253E5F0372AF5F +:10B1A000A7777C7C867062BC22F5FBAA9CE0B77313 +:10B1B000114E53B495BE7D15FAB8E1C5D52589BEAB +:10B1C0005F92FAD82ACED3B4465222FA7D06DCB377 +:10B1D0004F2DA76B18ED51CAF2C4F998D5B9D2BE5C +:10B1E000F6AB775A9DEBEA5FEFE446DB85F2B33DC1 +:10B1F00085BEA393F9A9F871BF2FF84DD245C62992 +:10B20000B85F80FD9F12F2B359C8E973E2AA8B7F41 +:10B2100088FF7DA6D0FBB8DF3F901D93EFFDB3F212 +:10B2200065721E694FE3E92FF73B703D334A07EE25 +:10B23000D77E50C48171FCF882F0A7EECD65746DA5 +:10B2400037473F27B95A92CA689F6D330B64E17E36 +:10B25000D92B57707908F496E0F857E68732F24612 +:10B26000C7F2C2781FE3935A8D85719FAC76A739D8 +:10B27000A2FF8E67277E4809FDCFA75AC32AF0F99F +:10B28000B8FCD061A4677802FF5E2FFC3D1BEDFF88 +:10B2900080233D1AF54B23EB4E433C37A85D2598A0 +:10B2A000C7DCE20EBD8EFD4F99BA0A78BD05DF9F5F +:10B2B0003A29F2BE2745DEB7D312CDFF8E3376CEC4 +:10B2C000DD05C6EB752E749932310E7C6FDF3B3F86 +:10B2D0007B09DEBEE3A573777C1FB1B526E5CE1FE3 +:10B2E000C1B5DAAA06F5E7FF9C4C4DAC674F093EA5 +:10B2F000EAABA759999430EFBF278FF34163DCFE87 +:10B30000EF9E3C1FBFDFF75D16DFFF7D6F8073B2DE +:10B3100026E771FA748A3A9FF8E7D3C43C3BCDAC78 +:10B320006433C2B32D95F6D799C6CF37AB79A4D085 +:10B330008FFB929D45FCFCFCDE4715B20327CD5CDC +:10B34000FFC0DFADD68A981D453705FDC41A4738C2 +:10B350006A02FD51B32C358AE767C27D6D1CCA5A5B +:10B36000D841F5A673857D9CD7F4DADF30EF51A381 +:10B3700031EB3878EFB47D7E1A9A8785DFBA178F64 +:10B38000C061D9D5EDA22E519CD71698AE5E4AF970 +:10B3900032BFCEF85DCBDEBCA015F9AC3A9DE3BB65 +:10B3A000FA5E7E4EAFECFF9290DB7EFC86BC0AF02C +:10B3B000FE51E1F6257E1E77FE84E751BF2DF7048E +:10B3C000B368FC7BCF19F45A8FD2FDF48F902F977E +:10B3D000A48A73D45881BE5ECA9FC7ED4B2DEE3749 +:10B3E000816A3C5FD655B2BC10F9BFB7E077987759 +:10B3F0003B904475B1B5B8EFA4AB671B68DF69E05B +:10B40000FD269F05F9BCE1A2427C32F7C06B2750B4 +:10B41000AF3768DDC43F73AD76A24FC3458D9EB391 +:10B4200036F359FD777AED9EC0705C5FF8C17119F3 +:10B43000B46F950DF709CF43E99C8FA5A21ED99D46 +:10B440001F1A8DFD36A5A4DD85F1E1052B3F97A9D7 +:10B45000D1C2EB8E99F8FE59F209CB4B35F2C1817E +:10B46000D7FF8670CDB786E81CCB05739AE8DCDC85 +:10B47000EAF4E86847A99EFEE3BED6B9B95EA137F3 +:10B48000DEB3F0FA9CFEFCCFE9B0278FEBAFF7728A +:10B49000B81CBD57C06AF6E0F54AB8C27BEF158903 +:10B4A00076396FC78FD328E4E8BDE1DC7E8597A6A7 +:10B4B000243C97E46E218F7BF302B723BEE4FDA703 +:10B4C000051CEEFC40759E8BF46348F06D3403C69A +:10B4D000ABFE25FF1D03D6D24B75257DEB2A11F05F +:10B4E000BA13C3D5121B77118E07FD02E4C7BF62E2 +:10B4F000A3EFEFD874D0D7A89F97E633D4CF306F9F +:10B50000631E1F379A41FD92681DAC0DF436F0EFB3 +:10B51000F9D13EA2CB9A4AE0D351E25C7E5F8CAF78 +:10B52000243FC5F3D17D79CA40FBE2F7E17CF1FB12 +:10B53000E28C0D267A13BF7D8DEFD8466471BC80F6 +:10B54000DCB7E691FD8D5EAD973B8967A92FDF4B98 +:10B5500036F245AA80F307A25F1F9EC5395ACE6214 +:10B560006E0765BCF0B8E89F21E82FAFD2AEC5EFFB +:10B570000F64887133F2D2245D1E13F4CE4848EF75 +:10B58000AD9CDED0EF09EC579DD47B6716D8B3DBBA +:10B59000C04FC2732FE13D2FDEEF97B798C8ED7013 +:10B5A000E3D254867EC24FF244DE6F542FDFBF1BBE +:10B5B000DA4BFA682E03BDA35C9E7E9823F0823E90 +:10B5C0007C43D40F2958CF93496AC087E301BE3B1F +:10B5D000F35C317CC7CF77121F815FF84A9EF8BEBB +:10B5E000AF8C9521BDEE7CEBCFA977F8F01C74FEF3 +:10B5F0005DF147F6D0AB38CED9EFBE4E71C0494BA6 +:10B60000B4A4DD9EE0B925FAF82625F6FCAE9FA885 +:10B6100061FCDD8BCEAEB38FCE06BE9CDBA5FA718E +:10B62000CAB9F77DFEE618F4AFBBCCB40F05FEC572 +:10B630003A3C179435717FF4A4C948FF33DF36D6FE +:10B6400075740B7995DF3B4B7D25FD86C5CCCFF519 +:10B6500054323F87FDD49245F4BDF37C163C8AE713 +:10B66000B07FBA742AF9D38B58887E8F605E9BF1C5 +:10B670003CDEF8737CE3CFEFC5043FE22FFE1CDF16 +:10B68000BE7C7B55623F23359FF3E1198BA82F18B1 +:10B69000C0CFB828F857D61734CAFA8297BFBCBEB5 +:10B6A000A031AEBE20E68FC8FA822F284F68CEF7B1 +:10B6B000D1F8389EBECEE0CC84C4702BF9D2EF49CD +:10B6C000318C2FC789CD9346CF1BF13C9F84DFABD4 +:10B6D000DBE9FE998589E749CFE7EB6E8CAB67889C +:10B6E000BDCFEB18649C2FF9A2F1A297ECB16CF7D7 +:10B6F000FD0E43DF7B79F43CFEFB7C99A79772F04B +:10B7000081C2AC5ECA9BAD177AD13F1CFDDF0FD062 +:10B71000AF4239BCD1F74A378038EFFBD794684540 +:10B720003139895F07F0D367FAEFE087E48B7379EB +:10B73000FDCC4FDF490A3EBFF3BB93D2719FF5DFCB +:10B74000EFAB327CFFD6F77DBC45FA7376835D663E +:10B7500071767BDEBED7C95F9B6F0DD277781FBD38 +:10B76000FC5DB2D70B59D08DFC7DFEE52B0A42FF64 +:10B77000037B2DE1B9257CB799FBE94EF233660ACC +:10B78000786E39C0FD45933560A67902CCE77053D9 +:10B7900028CEE105A589E7F05DDF077F299DDF3130 +:10B7A0004EC0AFE0FB80DFEBC595CD0D79106E7913 +:10B7B000AE00709307AFCDD7F87D781DAF0435A6E6 +:10B7C000FBDE74326BCAC3FE266BB72ACE3BA3F3F3 +:10B7D000E39362F8A276AA68B7DC7AE1CE0578DF57 +:10B7E000CECF27B6083816E68BEFA8ADCC8AEB4E45 +:10B7F000B2473FA57D40710D4FE0FE77B888D7ED89 +:10B8000026E3790A30AFDD7E2E8C8B7530079D13D1 +:10B8100060735C88621CA2FB1D897BF25DBADF91BC +:10B8200060519E9F1AE879DCEF4C640AF89A857E95 +:10B83000F3E27987C574AE03E9B7875317D239E4C9 +:10B840002EFB32DA9FDE923685F62FDD8878AC53F8 +:10B850009FA23B97019EBB82C6F318B2E718DBDEBE +:10B8600090B16D6527A93E4A89063D97B262E74EC1 +:10B870009A85BEB83599C3756B328FD756E71BBF13 +:10B88000130DCADF7FC9E4E736F4B8AD56ACB7C0D4 +:10B89000F83F9FC7FF7F044A435CC87F1FA66C7CAC +:10B8A00060C8A3A3F0774F54FF2AA0536BAA6FA5DB +:10B8B00086FEDBEDE277C2B40EAA63D8766706D5C2 +:10B8C00089B6DA1C9598F70CE7F37C4FA3A8F70725 +:10B8D0008AD4EE82F7B6CDCCA57ECEAA5ECA97F604 +:10B8E000AE66E41FF5E3D32F80FF01DF4F621BCF6D +:10B8F0009398EFEFC2EF88BD0195EA74E5F31DF868 +:10B900001CE054045FE0FDF115B1DF712A3E507672 +:10B9100008CFC36421C5CFD38F3EE2F759C22F6F42 +:10B920003C5079F36880ABB86B24B1F1E00362BF9F +:10B93000C59924F68DF9F9BDF1FD07637F68A71C51 +:10B94000F3FD6B1D3E32419C8DEF4D48A1751F17D5 +:10B95000F92626F4C39838F9BB2E260FF4BC4CB454 +:10B960001B457D1D9E6111A8E0E90CEAE7E4F2E1C8 +:10B9700067F28FCBEDB52CF687E354C5C6253D3570 +:10B9800031F6382687B0C472ABBFB90EFA1D99C123 +:10B99000F7D7C768D18328EFD7896B99B8B2B9EDCB +:10B9A00084DF352B032AA3128890BA1EDA63AD5DBB +:10B9B00059C8DFE3ACDD2B5D30CE3573EEF660BBEE +:10B9C000A4A098F80DFC2F3A7728C36E8AF0EF28D0 +:10B9D000CBFC2847B3E7F07CECAC3956AA3B9EA5DC +:10B9E000F1F3A198162ABC0D9EDF56CDF3C0D8AE58 +:10B9F000D6E559E4BEC7718853762788374B0AB815 +:10BA00005D94EF378AFA1FF9BC080F8AC63C59C10A +:10BA1000E48FF2C99EF0FDDD3352CF0C6543E37E27 +:10BA20006FE67C3EEE5F56BE31909E303E177A62E6 +:10BA300056E01133F9E9425F48BD1C14754D5DE2D3 +:10BA40005C97772770BCBF5DB998F4C5ADAC89F43D +:10BA5000F96D2C6C467CF7E9FF293ABF06E699158B +:10BA600034FA39B3E7C4FB3D9C5FE5BCB7878CCFA4 +:10BA7000674AFF758AD17FADFECE17196417B39F51 +:10BA8000AEBF342856BFD41857BFD420EA971AF750 +:10BA90002D39E2D2D52F351EE0F54B0DFB2E57BFC9 +:10BAA000D44BFB48C7CD9183B8BF727C318804C0AA +:10BAB0007948D4BB1CC67A97F2185FA6CEE47956B3 +:10BAC000605FDA2FC973A4F8D15F6F3395535EB608 +:10BAD0002D2DD5AFCF83AE59199AA4CFC7CA7AA559 +:10BAE000E303C4B7C30BB8FFBA51E179F1F0ED56E7 +:10BAF0008AE75CC541C33E844B652730BFF811FA25 +:10BB000059A3A93FE53D701F6F245C230AAFB3EF33 +:10BB10007B1FBF3BC27C649C3E7265F9691FC09568 +:10BB20007E35E5F3E71C28DB41FAC66EF3E3EF222E +:10BB3000CAF1E784B6695847D478609B36DF1EE3C4 +:10BB4000BBCA02C1AF292C05F9B52FBFB72789F2AF +:10BB50007B1FD983930AE0FD3A4B743833F233DD0F +:10BB60001FC8AE2D12FC629E10BC7D01C073FE4D3D +:10BB70000BCF73DDC7485E9FDF9F41F9496D2623D8 +:10BB8000FBD252C9F8EFC06CE3DF0B9CCEE0E718A4 +:10BB9000B5CC6064077B322713FD16B3C8513CA7B0 +:10BBA000A866ABD9701ED13D3B8CED3AD641F6A6C6 +:10BBB0006E573F7E26BD25F5633DF3A966DC07E899 +:10BBC00034BECF061BF56399B00723674D6CC67A68 +:10BBD0008D91A6A04AF6F73E7FEE4C8A9FABB91D29 +:10BBE000654FD3F957E7533F51B99C737D3C3AA653 +:10BBF000350D7669B4F0AF6ED0F8EF2A487F69B49E +:10BC0000F89D85C3A6032AFD768F806794784FFA46 +:10BC100069525FF7D1732CE852E0FB07255D8B5822 +:10BC200011D215C627795030C0C9A4F1E9F71AAE70 +:10BC300013F301DDF9F977266B04F9A85569223D64 +:10BC40006D65425F2BA1667CF917E130E9ED6B5819 +:10BC5000D32DF87B9FE3AC5D29E497DA436B0B5C53 +:10BC6000313E6966D182DD8A815FE8F9D98C37126D +:10BC7000F28BB42BD177B9BF318D811F08F3067ECB +:10BC8000CFFDA0C30A8FF3C01F3C8C71DE1BA6A999 +:10BC9000C40F536119D86F92C348E71B3DC6F654D1 +:10BCA0005F3F3E50F5BF5F0112A7213CD3861AFBD0 +:10BCB00005A47E6346FD56C8BEE075E5AB8F7E0BDE +:10BCC000E3FF94E56C28FA31E039FA13FD1EE973BD +:10BCD0000503EE933C5790609FE4BCC8F75ECBBA77 +:10BCE00017EE52FAF34DCF91E5AA47C75F929F5FD7 +:10BCF000147515CA2FC57EEC289EF78BD979CE37DF +:10BD000015A2752DF25D267E7F22F845FCBEC8F592 +:10BD1000FB6C51FCFD9C3231CEB5C83FE531BB1EFA +:10BD200035D97D9622E4137F9BAAF6F7E7DD993E8D +:10BD3000E297912669E7FD598CEC7C47B386F0EFDA +:10BD40001F931BB21BF8E31DAE4F803F282FD5CFAA +:10BD50003E1A9FC7F18FA4E331E147DFC87C144747 +:10BD60004C117E74B490F34F95FD560DDF7FAD8876 +:10BD7000E70926E206227DEF69B48B5556231FC4DE +:10BD8000F317CC68D2CF1BCF6F03F1CD20E41B6932 +:10BD900017B32ECF379F0B3F2301DF7C5E307A60D5 +:10BDA000BE89E717A95776DB1C5578A670638D42CC +:10BDB000FA78E49B839BB17D457D21D5BDECCEF027 +:10BDC0001FA2E74DFCF9A8AE808A7531C5CBC4F33C +:10BDD000C26015B61B97F37D89D1C779DDCCE0FB36 +:10BDE000F8F3B2554D87F0BBB8C6307FFFC54F5B47 +:10BDF000E97BA148AB78BFB2BD0ADB8D6DFCFDD3FA +:10BE0000B8BF3402EBDD22CD787FD8BA423F0F4B6A +:10BE1000B95F3B5EF0E96E65CF217AAF9DBFB7E8B1 +:10BE2000A835997E6750F8AD3788758EDFCAD7E997 +:10BE3000FCE026FADDD105BD61F29F3E36D5559076 +:10BE4000DE1920FEAC54DAF3F07A23EA1315E90781 +:10BE50007C5DC4F71FB7C314658378FE42EEDB61D7 +:10BE60001D81BE6EA06C10B7FBB29F3B937FD7C500 +:10BE70001E4BA5BCAFDC578C6E620ACA19AE51F8D6 +:10BE80000109F7196F2C6EA2FDC51B07C9FDC56E10 +:10BE90000DCF752FBBF4E7C989F22B63C5BC9F8812 +:10BEA000BA0879BF265248BF23B61B9984BEC77E05 +:10BEB000F237D416E79433F11DD8EE42DE9E3CE80B +:10BEC000891FB6E5017E4D4D1A9EEBC60A14FA0E87 +:10BED000EE5FBA58343DAD3FFC376A2C6AE1DFB102 +:10BEE00011FC0B9B2DDBF9F7885C2FCD926A67DC88 +:10BEF0001092D35B059D6E1924F29223D948D43752 +:10BF0000B304DD6EB382DF4A7AADDD1C27FFB307D1 +:10BF1000A1FDD832A0FF6C7C1EA71F6AC4BC0B8594 +:10BF2000DFBC187FAF54C5F3E6B9FFFCC916EE3786 +:10BF3000DFC33A288F78FE31EE2FD6C3F2905FFA36 +:10BF4000FDAED74E63BBBE23FE7764F9EF10F6FB60 +:10BF50009DD6529E9F3DBFA5BE02F373359BDFA4C5 +:10BF60003C708DD41711A3BE000783EB8B4D575245 +:10BF70005EC764E5BFA33912F405D6978CC4BA51E5 +:10BF8000187FB838876735BEC2CFDFF9EE20B237E9 +:10BF900053A8AE94C653693FF7CD802F461F69372B +:10BFA000E2F54599CCD70CCEA47C96D41F658CDBEA +:10BFB0008B78FFE811494F11F7483FA30CFD0CE0C7 +:10BFC0008F2E933D6232E9FD8A08C921C48DD36C5E +:10BFD00045C83ADC9F1A79FB28ABA03F8BA3EF261C +:10BFE000A2EFC0F193F1791CFD65FC5221E87F3B83 +:10BFF0000B505CB457D0FFED77F9EFBDCDB22F23D6 +:10C00000FE7BF7F7DCDF94F1D3D78F9B02EA3F1278 +:10C0100037F5D1DB067E640AFE1EC6D4218FE27E90 +:10C0200078A78DFFAEB5C2E9EBBEFD78813EAFF8D3 +:10C0300036FE7E8BEE77259AA72659711FB0D9CC94 +:10C04000E38A99D3DEAB98ABD31B8559952F0D1A94 +:10C050008DF4E8FAF61F30CE785D9CE37AC045F4A3 +:10C06000BED0C5EF5FD87A953F0CB7CF98C579465B +:10C070004AD3422C8192702C14BFF7F259CA2BB4C8 +:10C080007F3C2323740CE970CF1B7B295F59C7BA0F +:10C09000F8EF028B7107CE4B86497F595EE5F6B00B +:10C0A0005749F6F3EF86C325FAFDA4633EAE67C792 +:10C0B000E5078FE33CD2DEC5D7159C5C72237DD7A4 +:10C0C000F9171648C7FD4C45E3BFDF1C3F2FD611BB +:10C0D000B4E8F2D9276D89BF333D3588E7038A106C +:10C0E000475807911BF800F1F78988033F11FB5A65 +:10C0F0009FA4F17DAE9EBEFEFCAAF9847E16FB6075 +:10C100009F641AE347D9CF22AE1FAEB0065B74F42A +:10C11000F46D4A6A8A501D95A81B59C678BCB43F75 +:10C12000C3700E4186AFB2C887FB14C5010BFEBEBB +:10C1300077EF7E6E8771FF19F7872339A12F10EEF5 +:10C14000061F0BE0FE2AF3755B6EC17D46F17DEBA9 +:10C1500079C12FE76DFC2AE1FA6FC3AFB72E0080DB +:10C16000000000001F8B080000000000000BD57DC0 +:10C17000097854D5D9F0B9732733133213261B84A9 +:10C180002D4E16B2906DB261D8270920B860C25208 +:10C1900051B661DFB209D88FB6F6CF601090475B19 +:10C1A000A8B6C5CFE51910A8562C1183460D1A94D0 +:10C1B00022585B4704454B75A4CA222189602DF69D +:10C1C000A3E57FDFF79C93997B3361FBD5E7FFC83D +:10C1D000F37072EE3DF72CEF79F7F3BE27518E8A9C +:10C1E00024471C63ED77FB4D4C652C4AD62BA09E53 +:10C1F0008CF5F2244711D4A7C8F7A2FE10AFC33FB5 +:10C2000003EBC5D81CFCCD01A5C5DAA2E6C0EFEB57 +:10C21000C25AFDE9F49E5D4A624C51998745432517 +:10C220009D39CA6DF874B8FD442614E1F01EFAA9D0 +:10C230003159D729B9D4BCDC02FDCD10FDB1FE3691 +:10C2400023F63F9D77C566341FFC5689646CA6852E +:10C25000ADE907EF6735F736C10CD8A2484FAA3DC4 +:10C260000B5B8CB69F8071154F847A2902FAC67FCA +:10C27000A3BA968C19D909393F5A8787315CF700E0 +:10C280001FAD6B7D4947C27F1732D6B1C76CDF0245 +:10C29000E35435BF7554817555C9F5356AD797EBA9 +:10C2A00050E87BC62CDECF2D8CDDCE14D613FA6978 +:10C2B000B2BA73115E55163FCD137A349567C368D1 +:10C2C0006B8747D1FA7BC3F7309F17EB5CECEF61CC +:10C2D00001782EB3F3F58F512BCB4CB18C9D9BC7BE +:10C2E000EC6678B4ECE0DC7A0BD4973DC0EC7C745F +:10C2F00097810D86FE05BCBA9B5F5CB981392CA283 +:10C300008EC34EEDC11CE9817A1F77B4A60EFD32B3 +:10C310009CC752D16FBF457D35DF0FA84DD2B4BF4A +:10C3200061E520CDFB444FBEA69EBC6EA8A6FDC015 +:10C330000DA59A7ADAA69B35EDF358524F06F0AF69 +:10C3400039A0322F8036C33B51F33EF3E9BB34DFD3 +:10C350009F64B5BF190EED1AC3237318E0517D78A1 +:10C36000E4162C99C7E5CB02F8CC13EBC86E98A362 +:10C37000E9E74CE4D803B8AFF37C0B6E658057B99E +:10C380004D4B34FD2E552BF9BE6D083BEE87EF6A01 +:10C39000E107E199CF3AF6F783F9557B15670BBCB6 +:10C3A0005EB889BF97DF2D6EDA4CDF2DF66A9F2FBE +:10C3B0007D5A5BF794B2F45A2B63CB1DB658C287F3 +:10C3C000BEACEFA520BA0AE0013482F1CE3DAE7AD0 +:10C3D000CD89089FD4DF0E27F88431AFA3EB7E9D73 +:10C3E00063CCD982ED77D89C1EA82F3C3897E663A2 +:10C3F0008ED7E241B8438B0711E95A3CB039B5FBFF +:10C40000DEB358BBEF7AF846B9065D16BE31E3B429 +:10C410007821E15A0C3FDF255C9FD0C1B3609FAB10 +:10C42000DE4A7062932D83117E7CBE6656AE229FDB +:10C4300063B1C067E0B99377C1CEDAAD1E03E0CF38 +:10C44000730EC578C212E827CFD8B217D7B346F11A +:10C4500030FC2E9C79E3915FD417B724B4C0BEE4BE +:10C460005B6A71E7D817D6F2E791EE2B4D2D39F8BC +:10C470005EF6F785D54DCF5B95771630582F33B6DE +:10C48000E4103FB4301A5FC271700F8EC74B593938 +:10C49000F1E117053E7FFED12282E30256BBDF05A4 +:10C4A000E39DF998C37731F350BBF91BB470E802F0 +:10C4B0003F1DDC006D1C386E8D58F712C6BC86E43B +:10C4C000AEF0549A95165B0E82A159F26DF7A50253 +:10C4D0008E7608CFA1ACF31FF16F095F68A004F35B +:10C4E000271CCFDE2B309E84A7E45B721C33AB5538 +:10C4F000E3910E747C8CA56BF709368E617DB0A834 +:10C50000BD023CD4122D06EB85FDE0E419BB518C35 +:10C51000C3E6B8E3114E16B681F66FBDE25CA7C262 +:10C5200038EA0D89F50CE0596077A9B85F45CC373A +:10C530000D9F175B1AEA8DD0D50DECA2FD04C81330 +:10C54000D67B7BD5A598C03A14B92E8FC28C501FCC +:10C5500021EA933C8AFFB1445CCF5BDFE2B823441D +:10C5600039094BD83F58E6DFFF0A1F0F571C0370ED +:10C57000BC89AFA4C521DEAC516A996E7E475F8548 +:10C580007E5443470CB61BC3DC462E77BD3849F6B4 +:10C5900096E2A779FF88B9EEC752CAB76AD6307655 +:10C5A0001AD4AB1B416E456219DEA242C99A74F0DF +:10C5B00064C6E35837C04A10BF97625DEE7B62E005 +:10C5C0003DD5D5AEF555B0863ED15796EF1B13ED50 +:10C5D000345F907FA9FC3DE76F8B04BC1649B9E539 +:10C5E000D5CEEF18FED287B13F9A0026F9484716FC +:10C5F0008FA127A805894097D82E87E560FF40576F +:10C600008E44E8BF5734D0A1124C77BCBD7CDF8587 +:10C61000EE74EB67B5B0B94300DEB642931B58EE3B +:10C62000DCE0F55E053CA41E310FDB42F92F878369 +:10C63000D65DD5E3D8072E7C5DE84B40F92FF7A9EE +:10C64000C6C4DC0DA8B734C4D1B8F2F9E84483D02D +:10C6500027001FAF024EDDEF430AE943721FAE56BB +:10C660001FCA451C2F0AC0EFE6AEF09E90181704B3 +:10C670004F06F0CCD6C05BFB5EC05BC2E36C916F33 +:10C680003BEE936A3BDC0BE1BC32BE7C12EECF800A +:10C69000A3FE138A2130AF316AEBF6C7508E35A95D +:10C6A0004EA4E5EA119CCF55BFAC12E9B7359BBD4E +:10C6B0000AF4B3A8E94DD2CF5AEB809186750FA743 +:10C6C000CEF5EAE0DD151E7C1FE57A96EAD63FF34B +:10C6D000BDF3B6190E5A67CD15E050130A0E677EEA +:10C6E000CC669567E1FAB27AFAB302E366E1BE037B +:10C6F0001C7E1E597E0FC2A3F0FDFE91089F316A79 +:10C70000F3FEBE0887158AD30CE38E32334F38EC24 +:10C71000739F9565ECEFB057C5FE5AA71DE011DF7A +:10C72000DFEA54011E69F7A8E55EE8F76F2B96472C +:10C73000CF85F2CB3A187A203C570CE5846F6CD742 +:10C74000273F85FED26CD39DEBA136C30CF38171DC +:10C75000127F1CD1920C7CE27513B320BD8525D5C8 +:10C760001E1A0FFD7644A94ED4836355361AF14B39 +:10C77000C2393682AF433E2F7962ABE2B7069E8F55 +:10C78000AAEF285806654522DF77B9CE51651D0509 +:10C79000A8F74838C726F3F6CCD8913031883E72D6 +:10C7A000053C8EA15E07F0AC8E33AD4139D866E111 +:10C7B00075E64A27FD778585D3C7B1F0042FCAC730 +:10C7C00063B0561FF5D76263D620BE18EEEA792310 +:10C7D000AC9BBDA7B26D507C6D77F58C2278D87973 +:10C7E0003F42DF6A636C1CC269C5F8D2DED150C615 +:10C7F000D573F8E8F1A43191EBFD951780F00A02AA +:10C80000CF2B8D2D26BB159F9B34CF8F03DC3CE6B1 +:10C81000407DCEA994B18CF88C730DB69FBB2E824F +:10C820007982F4AB46318FEEE0521D656446804755 +:10C83000B5C2CA2FD7EED5FFA8045FFDFCFF2AF8CA +:10C840004C5C59E8F51D12EB2B5B7BEB6F51FFAC99 +:10C85000F68531333C5AF172496F16A2BF4E385FEC +:10C8600018C6BC314175A39FE0517D61243D2F5B0B +:10C87000DB6A42BCC77E1CF07C45B8ABB7F33270B4 +:10C88000CEC579E07A2F44314F4CF0738E5781FE3C +:10C8900063E9FDEF118080B79E26D5BB0D3EFDFDFF +:10C8A00001C3B82DA1E62BD63F28CE48F492D9C2B9 +:10C8B0005C9B438C2FDBF58A067E6DE570AEC8EE7F +:10C8C0003ABFC652FF4C9CFF8DA3992BD478E74406 +:10C8D0003B39EFC668FF0281F7A915B6A0BA5DBB68 +:10C8E0008F3DC5F88D37FB13B0FFB6F16C6A4388F6 +:10C8F000FEE57ECF88776722DFA9BC031A037E0C92 +:10C9000036D62AF6207AEB6EBF037006BBABE07218 +:10C910007036D17BD9DFE943821E99CBAA001DCDA9 +:10C9200016F26AF6D6A5B702CFECB45F4E6F02FBE3 +:10C93000058638CD6ADFB4617D8342F6C91C37C8ED +:10C9400000E0370BB615AC41B1353B9EB191D1FC3F +:10C95000F9BD58AE0E0BC859FADFC582E5A21C7F9F +:10C96000DE835ABD75117BF02BD47B4E1FE27C0118 +:10C97000D453B2BF173CA2ED6FD1D65B4EE23C1749 +:10C98000E9F49F3454F040FF484B12F6C460361867 +:10C99000F9FFB26DE74D918EEEF1FF4BA0F394815C +:10C9A000C827ED540E4D72E524A17FE13D3ECFF145 +:10C9B00049EEFC24F4A3BCC7E775AEF21C970F8FB9 +:10C9C000C7925C322313875FCDD32CDE7A98C75A87 +:10C9D0006023E1001FB399EB4152FF53D5E56A2470 +:10C9E000BC1FF2C58A6837F2E1676F1A87FDC53D43 +:10C9F0001BE1C2F5AC2F71E5A1BF607D85D5590F54 +:10CA00005D5AE07B941BDEDF0F79A32F6A070D1BB5 +:10CA10004BFB21BA35EF6D417FCA3AC357FBFB414F +:10CA2000FB752399B39E05C6A969AE781EE79330BE +:10CA300099CB97F589AE3C7B50BF4CE873D5027615 +:10CA4000ED7BD27E390CF6F7B103A44EC3FAC09E3B +:10CA500087F90D627C9FD9458013E0098E1DACB724 +:10CA6000B6829C626981FAA006A5250CD653D5F83A +:10CA7000BC01E560E57D2DBDA6A13C7AC6E8DC12CF +:10CA800034BFD8D7FB943A220372689A62273D419B +:10CA9000EAE57732F92F8BF066AAC09B3B853E3ED4 +:10CAA0002D82C3770E7326E077775958A401486921 +:10CAB0005A594311C9A9A5615128FF712DA1F65BEF +:10CAC00096DDF995AAB7DB3C0AEC7B9BD2918A9D57 +:10CAD0007C89BE1EEE5FF26E49ECDA4F5D92A0C318 +:10CAE00054A11FA630970DD65DFD5ADAE6F5F0CABF +:10CAF000DC03F6319FF891A5389FF4630BDA3D8B88 +:10CB00005F0D6F512203706176579E01BEAB99D8BD +:10CB10003F7F3DEAA44781AF0081B585F913888E38 +:10CB200081DF2820F336258DAD3002DE55F705FD77 +:10CB30000BEAFBB74CAA3002DE5727F91718A0DE24 +:10CB40009654C5EB83FC27B07E216925AFE7FB1720 +:10CB5000A8508F495EC3EB6808026239921FAAF0A1 +:10CB600040FF5F4609B9EEF4CF44FCA97E25CDB065 +:10CB70003E68BDD664CEAFBE0CE7EDBE4C64B326B6 +:10CB800022BCD3FDA9384FD9AE2349EAC31BA8BDA7 +:10CB90005CA7FC8EC587EEFF7749BCFFC565421FC9 +:10CBA0008960EB106EB04D9E4880FFBEE6B42DD874 +:10CBB000FEC1A468DEBF1DFA290CF423E128FB9313 +:10CBC000E32E41798B7C380CF870101F6D4CE2F22B +:10CBD00012C6594DE3A400FCB1BF89FDF370DF60BC +:10CBE000BF8C62BF8CDC4EDD4CEDB1DFA81CE2FBDC +:10CBF000054658C7BE8BD03E31306F3D7EEC15F8F0 +:10CC0000B1B81E1821E967C98447A322B85EC80AD3 +:10CC1000B5EB8849E6F0B32647F17576EE476F85A8 +:10CC2000C6A91770EC0F70CFBEF675BF2FE6F35D87 +:10CC3000AF3B68BF5C2ABE6FCAD812BC1EB02C3591 +:10CC4000FD7CB94AF75D311020AE333A99BE5B1BCB +:10CC5000CE2CF49C6DE9FC2E3187EBA3A8A75609D6 +:10CC60007D9A79469253A152708DAA753E9303DF47 +:10CC700037282EAF35787DB7168AF5D9C5FAEC7C02 +:10CC80007D5E0D9EB2C31D09936D5DF1B713EE9DE0 +:10CC9000FD65E58BFE34741DAA3FA48FEEF6232CB0 +:10CCA000F93BDE0F394F1D3C3BE1AC9B9F8427D203 +:10CCB000337D97A5C54739CF0B823EBBD075E27552 +:10CCC0008E57C2BFABFA09EC23EA270E2D3E57352B +:10CCD000261AE66405BE6BC2BD2C0AF8E7D293851E +:10CCE0009DD79FF547FEED29E57E54CF2EB3B3DEE9 +:10CCF000417EBDACE4B8907E3D7AAEB7F3DAA34C8A +:10CD00004C21BD48EB67688F73FA5CA89F9E65CE87 +:10CD10006DD0EF309DDED10EFBB9CB1AF82E204F2F +:10CD2000B4F59F083AE8EA37EA48C0F9159A4B5F2C +:10CD30007038191B9BFC14F1F7C29EA5CB13A17E82 +:10CD40004BF236E2D785FD4ACFA36BE6B6E4EDBCE5 +:10CD50009E597A3E09EB4F6DE7ED47B95E40FECE36 +:10CD60003CDB2B460F09E80F13921D5CFF28333084 +:10CD7000C423B37AB713E5A484677765A1D9501BA0 +:10CD80004A6FBDA3939EF97946B190CFC5D28EF775 +:10CD90001B35767C7BA4C5A3025CDB519EC27AE77F +:10CDA00024BBA723FC6B225A67A20A7C5FC42726F8 +:10CDB000D4871417E81BE81771D8D97498A7D2BA8A +:10CDC000BE9CF4C0254E8B91E029FC54B0F64BD0AC +:10CDD000CFABAF3DF3B37E7C98729CC71041FF355B +:10CDE000AF7DFBCD5F518E7E6975A21B7048F3A3AA +:10CDF000CB51BF1AD2FCA76FB9BCB5D239959CF7FD +:10CE000010F437C2F3E22633CD7F4873C67C6C3F03 +:10CE1000ECFDE664C48F11C75AEA911DB4EF79A9FD +:10CE20009F3BF8DC8A9D542E655EBB7ED1098F2F17 +:10CE30004C0CF54B80C7FFE1F0B8B800FD8A6D716E +:10CE400087D6F8494FEBCFFD98E27BD0CBD391CE7C +:10CE5000CFB11E4E3C5768B7F17EF4FECDA315B09E +:10CE60003E783EA2036610A4378FBA60010612A86E +:10CE700097B0284DBDCCD247D37E8C3D51F3FEA652 +:10CE8000F80CCDFBF18E3C4DFD96F4219AF6B739A6 +:10CE90004B34F5DB8BC76BDA57B82A34F5BC9606F2 +:10CEA0004DFB82034DDAF7871DB40F05C7CACB507F +:10CEB0009F77FADCF558DED8BAA1ACA78375F1EB01 +:10CEC00016FABDF5F87CD8C5DAA216D6D5BFCB9632 +:10CED000B8E93CC08CFBA2069D0F94F8881EDB0CC1 +:10CEE0004E47B01FF7D15EEE17709FDE5200EC0088 +:10CEF000EC91968E18DCAF31B31E5223715F3A1855 +:10CF0000F9BD1A4DFE5F0C43393F4325BDB7D1C86B +:10CF1000487F6C9C9AED45DFDF51C5FFE25F914F82 +:10CF2000CD88207E3202345C5A379E812AB84F6EFB +:10CF3000CDBA4BD862DD3EDDADA98FB1FF44D3FE43 +:10CF4000A6F8559AF7E31D0FE8F669A3A67E9BF3B2 +:10CF500051DD3E6DD6EDD3339AF7233EF7D7231933 +:10CF60008D6AF5A83698FFD0A31BCA705F861DF3A3 +:10CF7000CC407A296C71D7130BD957FB26962D60BC +:10CF800057A13FEB8DBA782AF7D539C81FB5BF2E08 +:10CF90009DCA03754E7AFE765D3195EFD4B9A8FC33 +:10CFA0004BDD382A7D75E55436D43550FB5D754D23 +:10CFB00054020407A0BC888D11F207EA68E7B7198C +:10CFC000FCD578E27AFAA96F884FB6F5F0B761FD23 +:10CFD0003EF68F8AD1503F9CC288BF59A14FA4C74B +:10CFE0007329AECA14A85F48E6CFDBC3ACEB500E82 +:10CFF00034185C79A85FFFFBA9FF6C340E60ECFE6F +:10D0000055E5F1F6285EB7409D361B0D33CF7F36D0 +:10D01000BA8633F61C8A8CA154AFC07A7B387F7FE6 +:10D02000E1A9FF907E2DCF9B2707CE9BFF9D1CE2A1 +:10D03000BCF9B9530E1BFA590E5D4CB3E1BA0E0997 +:10D04000BF928BE585CD86B2C498178672F1A84E43 +:10D050008F90E5A7D612534A1CCEDF3905F508CFCD +:10D06000CD616C1BF08B890AB7473BF5C0142ECFFE +:10D07000DB6F3393BD73D8E09A8F780E7CFA4984C6 +:10D0800057424ACF892857DA6D1D090887FE299132 +:10D09000BC1ED7F1A4E20CAA87F175C6A5D82676E6 +:10D0A000B3CEBE381FFD3A6F4811E70C2DAE0128F4 +:10D0B0007F65FD7085AB0AE5C4E112D7409CCFA126 +:10D0C0007233D18FA7DCE61D884CCEE82A9A12E491 +:10D0D0006F7934258CBE9B6CE274C6EE52BDDB4288 +:10D0E000D8692FA5707D9FF60DEDB93B23480F3F02 +:10D0F0006C608B768580E3BB295CCE9DE911DAFFFD +:10D10000E213F02B9D64A3FEDA5784D3796F7B7909 +:10D110001AE941EDB50025A08FF653B56777D37BAB +:10D12000B33C0AA373CD69824F3DD7BCFC1F47A017 +:10D13000FD272B229CC4C3ED83483EDD251ACF88F2 +:10D14000B190DE3263E28052944BD3C4F9D84C9B49 +:10D15000B1171D9319A34C76E8679E356F0D8AFFB2 +:10D1600005B115A628A82FEA7FF71A2C97A46C34CE +:10D1700045435999F5FC1A541FAB80B48AC85EF236 +:10D18000FFB90EE6356BA5EAE0F693906BAEA5D736 +:10D19000148F21F110E188780AF025BBF03D016F72 +:10D1A000F9DD7B029EB352C4396D36CBBEA43DF788 +:10D1B000998B78D23AE3CFA9DDF8E7B5EF85DEF6B3 +:10D1C00081898FBBF4E9306FB03F498E7B48CCE357 +:10D1D000B089B914D4E3EEB2117EE44C3D7F5F1107 +:10D1E000AC3FA7D96EA0737BC9C77D8CFCF6459F69 +:10D1F000BB89CFDDD8EADF7E84119E37219D5C4953 +:10D200004E4DF2AC22F930E46B903FC8172FBA3F75 +:10D2100039427C7091E083B5C4BFF6D5ADA4FAFE67 +:10D220003A0F9507EAD6093EB881DEBF53B749F0F9 +:10D2300041AFE0834FD3F3E6BAA954BE56E7167C5C +:10D24000909FAB4E14F8B432DEBD0EF9993CBF9CF2 +:10D250006C718721BCFEF8A899A9782ED16C263C68 +:10D26000050A78F2B1588C9731DBD73BBAC6CDE8C6 +:10D27000F96DE7FEEBCE7937C4BB1EC1F13AE3642A +:10D28000503FBBA17BFC39C41C36E4273BB64E247F +:10D29000FE71C8E1B0A1DEFA5CCAA489C8AF0FB9BB +:10D2A0001CB630A8FF61EB24FEDEEDB099A1BE33C1 +:10D2B00065327FEF71D8C2A1DEB055D4BD8C0EB5FA +:10D2C000776FBD93F84F0953F6213D9459124703E8 +:10D2D000BB06F958B20FE9E0A6F8D9A3910E525255 +:10D2E0001C840FE31DABF661FD96F4CDC618077ADA +:10D2F00043F356E377A5B11546FC6E74FFBB57E3C5 +:10D30000776353361A83BF1B97F5FC6AACDFEADC00 +:10D310006C447D3005F9565CA01F5997EF257F4579 +:10D320003B01F134B7B99CF8784E5339F171099744 +:10D33000D2C915F7A39FAEA649B12B388FC94AE7CA +:10D3400061BD023A44F545A016E0B3FBB6CE8B5E54 +:10D3500005DFD5607D28D57FB52A34DF3D981242A0 +:10D36000BE7C28E814E566057CF721D0CF2EA8679F +:10D37000E0FAC87F38DB369BFA73DB50BEE6A67056 +:10D38000395920E4E65C512E12CF3FB5BADE47BAD8 +:10D39000FC3845D8635DE9FA1341B70BF83CBAD0C5 +:10D3A000B5F6BDA06BBF940F851D0958AF621BC8B1 +:10D3B0004F78A5F8AEC5C1F65B22C6493450FC854E +:10D3C0003E4EA292F9787F0DBA380BE637D1796CD0 +:10D3D00053D073E247C2FEE8C1F9DE5464D6809FA1 +:10D3E000DF76CFCFFE8DF0BFCCBAB5EFC5BA17331D +:10D3F0002FC5B5E9D7C1DC71445B4BAD87693FBB35 +:10D40000AEC71F7A3D5DD6C1ED7719C722FDF2A0E8 +:10D4100007D90616211FB431F4DF04F3892397E1FD +:10D42000137A7EF45DF1B9CBF09BA48121F88D8C49 +:10D43000CFD297529F83BA07E3F33CAF85939FFE09 +:10D44000A4C39D8DFDB497767C6340FB2CD64F78AA +:10D45000E6E9E776E273C5C4CFE9E1492AEEDB29C4 +:10D4600083E70FA8170DDFF624F19D36140E408FC9 +:10D47000855047BEE3ED5B3E18BF63E91C7FDA15BC +:10D480002E1725DD833E48E588815C1E752D395DAC +:10D49000C9B8C6F6CDDF26901FEB0AF8DE1D1CC604 +:10D4A000A8C3FD1EE4F7C511A4F2B42AAC4501FDE2 +:10D4B000AFB5A417E911AD034C462CBF6B3BB1755A +:10D4C000402AF5AFB7175BFB145BF8B863C761D9A7 +:10D4D00064726F9A8D76D21033D949EF8A78C00979 +:10D4E000113C7EEA5D3C1F8676138E5F8C45F9A564 +:10D4F000B7375B0F4E2F75E474B53B619DA3719DEB +:10D50000959F19EEC767D76A8756AEFC86196340A8 +:10D510006EAFBCC88C055763973215D945FE51E7ED +:10D520009B58167DEE8BCE71A0FD29F507619F5E9D +:10D53000210EA9B883EB0BA32EB2746321FA997A5A +:10D54000D0F98D52FC276EB78A529E8B0CE7536040 +:10D55000330D56AF29491387146F8472BAEA1F8CB2 +:10D56000F536E6A37312BD3DFB96F043815DFB0BE0 +:10D57000C4DB35223E09762406F177CC4F3F9AF979 +:10D5800033E203E1A40F75DAB5BB0D145FD0687404 +:10D59000F51C8176EDCA81CE5550FFD417F7EB57B5 +:10D5A000A1ACB17F437093F45BB9F23CC153D65B3D +:10D5B00085DF774318C81F282BFFA3921CAA646C31 +:10D5C0001DED1B7BC3B42C482EB286AF3AE19F0BF6 +:10D5D0007CAF02014876D6C8492E685721EC0FE689 +:10D5E000799DD785DD0516C52417F45B1127DAB3BD +:10D5F00087F9FB01F2FD23FCFD40D9DFF989F4BE78 +:10D600008FAC8BFE3264FD4FBC9E28C76BE5F56C7A +:10D61000590FE7FDD978FB9706364CF26405F8FD03 +:10D620009E81423EE6B13C1197B377E0E5E351B409 +:10D63000EF857C98F58CEA31E5E2FE8C8FF833D2E9 +:10D64000778342B17395F78691BFFB4C7443CEF25A +:10D65000207B45C6AF9497D95CA8FF55BD98B645C9 +:10D6600015F13CA87FFCCBC1ED9831AA95CE27CE11 +:10D670003DC8F97E77FADB8295AF6AF6B3CB7B556E +:10D68000E1F6381EDCC178671FEABD99EC8B141FE8 +:10D690009D9B7F2AF85D2FE0ADC5D18178B1D8641C +:10D6A000E6427B35F625E0CFB8C79FFB881F2F7871 +:10D6B00089FB7FAB1E7D93E4DE1CD541FEDCB159B6 +:10D6C000EE2F106FDB6C3EF22B2E58F91ACDEB9B30 +:10D6D0000CA137D83BB282E179B62BFCBFBA02FC71 +:10D6E000BFFA21E1AFF73B2FB1EEA3F52EB9C6B8D3 +:10D6F000B6361B3F17758A7D3A6E700C16F08A4855 +:10D7000045FFF97C5F6A948A41C7BE5E3C5EE99D35 +:10D7100022B48BCED5DA18EEFBF4E57FCB7187F01F +:10D72000FBEAED811938665C005E7D52851E14802F +:10D73000EF001CEF32F0D5BEFF9EE1DBDBE83739AE +:10D74000F11CF528A37E06FB8E9B82E36246A47241 +:10D75000BCECD9C4CF8DF4F15E23526DDCEF2DCE3D +:10D7600067AA26BE331CCF67243D8C8A600DE86F04 +:10D7700007BC760ABC76225E4BFC0D9CD3C0772199 +:10D78000E82B80BF5AB88E4EED82B7E3AE00D7715A +:10D790003F245C1B411FA673CDDDE1E44FD1C3796B +:10D7A000A980AB84F7BD5780F3BDDF139CEF4D75A7 +:10D7B00068FC1112DEDDC927FDFEC87987A0D3A25F +:10D7C000EBA1D34B69DC4E64463FC599EAF7BDBE79 +:10D7D0002B3DADBDC2BEAFFD21F75D0F377D592991 +:10D7E000CE3BF5CFB7A576CBEFBE1338FE6FF3A7D0 +:10D7F000CFA8DDAB793F6BE541CDFBD99EF734F582 +:10D80000E17E5F19A2B9F48F8F3CD5F126D6AFD750 +:10D81000CFDE9D7F7DC20B0B0D78FE56ECE3FEFD47 +:10D8200005E9EE7FA5029CDF3578EB6D00D71B8FF5 +:10D8300035A8741EE6CDA373C0E5628EE787FFF3BB +:10D84000939F01DE9C6766F27FB6ECCD303AB2BBA7 +:10D85000E241C90595B982F4C4124B9411F5A9129D +:10D86000D09443E1CD258137140F04F43ED5C2C2D4 +:10D870006281CEA74E5528FE692AE3F1D450B6B88E +:10D88000E1FD04236B3143BDC26A6C31D3B91FCFB4 +:10D890007798C2A7C9CC46E6C1F72C3686ECE0C91A +:10D8A000F810E6ABBA548A679B52CCCF0BEFB23676 +:10D8B00084A13CBDF3C07D677F06EFD96A4F118F0D +:10D8C000D796F96B1F1BAEE51CF0522AA7F37645DD +:10D8D0009C2B2B614E8C6FD57FF77E2AF7974E508D +:10D8E00057A918FFD2F11E23BD5BD21DACEF8039C2 +:10D8F0009FE7670CC575B2B096B448D49F37966160 +:10D90000FBCAC30E824B4DF1AA1CDCC79AD1CA6771 +:10D91000E69C807D53B3F26BD2D3C7A83BEAB1FD3E +:10D92000B9A3DC357E63AB47457B25E0BFF4CF442C +:10D93000BABC921D24E77DACAE85F0E993BA0354DE +:10D94000BE3BF24F45A867F8EB7C21FD97D7EB2F44 +:10D95000907E02E937907CE0D37BCB7A235E66A48D +:10D96000093DD0A2F443BEC08CBC94FC3237AD8BD1 +:10D970005C2D48BBBC3EA87DFF3DF3D7ABC5F3CAC9 +:10D98000782E17F5F8ADC76B89CFF0599102E3DE19 +:10D9900005FA1ECAD569CC935D097C76EAC20D6191 +:10D9A000C394EBC7EB25D6CF1358883C956BE7E7BC +:10D9B0000EDA47B54C25FB40C62BC87D5890D6459E +:10D9C0002E2EB9C2BE2DF921F7ADAB5CFB7CE6F57E +:10D9D000C935A6C9EBB8BF2BBE3E9076797D40FB1A +:10D9E000FE7B5E7750FECC4CD510C817C178628C98 +:10D9F0006B6CF7F27CC845891B222938B3B8231217 +:10DA0000F5C6C57B54C243667419FB00BE2E14F8DC +:10DA1000DACA5A3E407C5C387C21E5D12D7A3C74D0 +:10DA20005C71B568BFC4DA68C2752ED9AA6D572D6E +:10DA3000E28A2B7768FDA2D5C36F3A89FD56EBE2E7 +:10DA40007976A689F8E17C96CFE32EB4FAA9BE6C6C +:10DA5000AB631A7F65DBC53AF207BCF4BBD6873DE2 +:10DA6000FD83ECFFAE78BBF70AFBB7F787DC3F3DE1 +:10DA7000DEAAB6AD945775AD78FBD341AE0F70DE1C +:10DA8000921F4F47DE04E34E7FD5ECF5E0F9689135 +:10DA900083FB37156F3D9EB7B57FCBC87F3447F802 +:10DAA00039BBCB4B97F106430E7BEB79BC814BC561 +:10DAB0003CD1C107CACBF0B8A2E09D5AD247BA3DCB +:10DAC000B792F955227EE86AF99AF4EB0D3E554B70 +:10DAD0007A96D367277D68E8858637513E7E57FE64 +:10DAE0006E290F736338DC0AFDE5A4E7B585B5142C +:10DAF0007D887AC2CBE121F5841EE95C4F98E499D8 +:10DB00001DC6F30DBB9C07F648C7F340C1FF0D16B9 +:10DB10005718C2698CDAFAEB3B107F7C2AF9F7566A +:10DB2000FCFCFD3F3CE6B8B2DD5F633F4F7A4377D4 +:10DB3000FA7F8D81E75DE4973928CE0FED29F4EF68 +:10DB4000497F9FBE7DF1A0D2FEE971E4AFF6B970C6 +:10DB50003E9BF87CBADB9F9A955F69FC8BDD8D5FFD +:10DB6000B3A7C83E27880E66A42B12CFED272C81C1 +:10DB7000FDBD5A3C18D13155A3FFFCFF6E574C50E8 +:10DB800041B504F999AD78B9FECAB81E3B9DF9A814 +:10DB90009CC93AA874331E7F3F8739A99C27F29805 +:10DBA000DFCE7057A4533C4C472F8A9F7CF17FB245 +:10DBB000106FCE8E1CB60163EDBE2F3DAE3DCF4142 +:10DBC000E3B7EFFE9F048C83B9125FD810EF9A97EA +:10DBD0001EE23CE82F252A9DB7B0538F919CA810D8 +:10DBE000B730B0D1FC1CED5F8E44A29B005FECBD52 +:10DBF00059F2453C9FCDFECCC0E349162BDE81D0C7 +:10DC0000B4C96F20D2CA9E9FE855B1DEC8DF6757FE +:10DC1000457915A8670F09E7EFEF8EF2A21F7D0681 +:10DC2000F3133DCE628CF8DD6CC6F9DE5CE6E2F9FA +:10DC30000EAC2309F5B0F9CD161EEFCFFC29C8DFD5 +:10DC400073BAB17F5A049DE726717E9E5BAAF55395 +:10DC5000AC49E77CFC6446E967484F67D25D6BB12D +:10DC6000CC8DF6AD7FB890FCF60CED8793437E42E9 +:10DC7000E78DF2BBC841A50F62BB9D0A8F4FF7EC41 +:10DC800031537C047CD1AB3C28AEFFED8CB25F619C +:10DC9000BB4711F645DDC315BED3E4CD06E8C9C3C5 +:10DCA000E78F3617F9DFE141318D4BF5DF3F3D61FD +:10DCB000F26A2BF9F83DA8F7460E723F85FB9A6B86 +:10DCC00062CC8AF37FC2ECDD42FA696D02FA2B174F +:10DCD0003E6936A0DEF011885BCC43F96B9D85CAA6 +:10DCE000BF811D8CE5A7600763F919D8C158FE1DD7 +:10DCF000EC602CE75FC80361C1D8D80C5733C7EF7D +:10DD0000D0F959BB053C3BC7DF63A2F14F66B809A8 +:10DD1000BE9DFBFD32F3E2A1CECEA88EBED197C14F +:10DD2000B7EEF98C47D883A1E3B99E15F3C86934DF +:10DD3000927CCF69F2472E086AF776BA89DE67EFE0 +:10DD4000FE9CF24FDBEC9DF07529B0E409065E7F86 +:10DD5000FBE979935767E1FC5D9FE1BA81BEFF82E1 +:10DD6000654ED3FBBFC2FC1FE89FE20EDA958EDF43 +:10DD7000901DA05B871E0E725D3BA37CEBF1FB9DAB +:10DD8000BB937025C06F18A71BC42325D47A57D125 +:10DD90007C6F377714625ECBED97D49071C62733D2 +:10DDA0004A08CE3F97F826E124F6EB7AE9BAF3FC6D +:10DDB0005BE02993F77720EF74A01CBA1889FA5E0C +:10DDC0008538DF6F6A4C7917D7E739A0B2810EC268 +:10DDD0005F0DDDC566F0FD9165F61E5339EED3CEBD +:10DDE0003D2752E659695F52E6437B63C6408DFF8B +:10DDF000317BC8B7FFFD702CB5B7E35077B2CD6368 +:10DE000030FE649A65EF1F714933EC9F8DC1F89322 +:10DE100059F1CA7E2C673B12C762DC898C8F9F9BAD +:10DE20005EB21F49E9566705E96925C85C82E4418D +:10DE30009925020F053BEB63EC319AFA4DF1FD3465 +:10DE4000EDC73B9235EF6F49CFD4BC97E3DEEA2CA8 +:10DE5000D0B4CB8DEE4842FB0CD641F4C0B6A91429 +:10DE6000A797BDFBF0CD99509FB07D8A13D5929DA9 +:10DE7000E2FD845D655EDC8F7680A70914A853C53A +:10DE80000FFCE661EC4CA7FF57EE796ABFCB710D32 +:10DE9000FA7F377ABFE4B34B9B2D45C867AFD60EE8 +:10DEA000D0EF4F7E86D62EE80E6F3AE9427170BCF5 +:10DEB00039A8B26D21F0062352391EF272C2219E9A +:10DEC0003F76ADFCEC0BE4673101FAE82C757EB9C6 +:10DED0005C93F3DDE5E8A7FFB3CA281F4FE4F52DF7 +:10DEE000C0DFD500BEB3799BEFEF134BCF3DA8E762 +:10DEF000627EA90BFA5F9221F4A7CABDF7F7290C3D +:10DF0000BC672B3ED3B467F72A6B34F5D589DAFAB0 +:10DF100083256B82BFEF8E2F2ED834DBE4A6FC4F17 +:10DF2000C5E50DC11FE47CC6BC114E717DB761BC57 +:10DF30000A3CAA2E7CCF88E7B0B775234725FFB9E6 +:10DF40005365B5A1DEDF93C1FDFCB7BE114E713044 +:10DF5000D7DAEF47004B8A337C89CBD18F7AFA8CA2 +:10DF6000C1FBEE11FD9F2DDAF8F36FF07CF46546EE +:10DF7000719F67A338FFCF693C6930A01CECC1F1E9 +:10DF800025C7EE37A05C695F14E1C1B8FE9AC536BB +:10DF90008A07CD4DEAF8C0025BBFEE99038F5800A7 +:10DFA000DF3EC624C820B9DA8E4611D437661C205D +:10DFB000B97ACB1BE12D86EB58CF463C97403958B8 +:10DFC000CAE97C26E28D902FE863AFB99F75CA1B22 +:10DFD000E40BB87EAC1F78E64F871F8179D71CE42D +:10DFE000748E11767AFB7E5A907DCF1EE77469811C +:10DFF0001F1EA7A4A3EF7D1B4CD6CBD27903C5DD92 +:10E000005C2D7DEF407A8EB82C3D1FBA05F6A7E651 +:10E01000657E9FC5B9E6819417DB9D3CAFD9A412FC +:10E020001DCA7A5BB33A0EF1569F7F2EE1CA5C4E51 +:10E03000A24F796FD4B211FF9C887273D91E230F3F +:10E0400012E96E9C752A73048DB3F335F322CA73FB +:10E0500013F36F97F27ACF3FA24BB278B92A84DCE0 +:10E0600003391D168B72BA4221BBF2C89EDEA50889 +:10E07000A7230A6B7150DE168F539EC4BBC3E756AD +:10E08000BAAF243E9DE293A57D29EDCA297BA60C5B +:10E0900044BDF283C6394760E7D8A719C984E7773A +:10E0A000300FE9C147A2CA07A05F6282880F381209 +:10E0B000D5D18A7CF9C8880805CFFBA1FFD5D8BF88 +:10E0C0005CD791B0F201FCDE0919973CE8BAEE8901 +:10E0D0001BA3DE5B720B9E6F4F6776B42B6F57B935 +:10E0E0009ECB5EE7F429F95E8DE28BC679BE9D3149 +:10E0F000F1AB0C3C2F5EF90BE157157033F238C4CD +:10E10000ABD5733BEDD9A7157E1F8A93EBFFD5C323 +:10E11000CFFCFA0ECC9303BB5B81F9CC69DA4BF7E9 +:10E12000FEE8EDEC4E7BE7FFD19FDAD55E2A8F1833 +:10E130005414F093EBEDA64E3D5DEA7BDB789CFC3E +:10E140009B237EDBB614EA2BB645101C4F3F69F6C5 +:10E15000201F3FBDC54CF6CFE9E88E63CBB1BE2B87 +:10E16000DBE9A1D19C9A7BD1161A1C1FA2FC616F1E +:10E1700087D17D1E279F30B7E0F9EEE2A732B6A027 +:10E180003D757280E3D91DE80F7C368EEE19606E06 +:10E19000FEFD6D821E91BE1CA07AA8BFB3911EB178 +:10E1A000F8853EC4C7E4FE9D7A229CF2E84F1F9892 +:10E1B000D413FD65AD86E7298F87A9560FF2E3A535 +:10E1C0005BC2490F5C697767E3FACB7E77DB1D059D +:10E1D00038FEFB710CD7D3DEFC02F92B03FB1B5A74 +:10E1E000BE9F6B4EE67CA053DEF2B8DB5918779BDE +:10E1F0004C71B70583E2305E55DEBBC8E36EF35564 +:10E20000C54579070F85CE231F3D489CAB4AFF4982 +:10E210000CB3C4231DBA19ADB7FDA1B42D68EF4CE2 +:10E220001F24F29F5987C89794F876ACFA55F29F4D +:10E230009879BC5F78E873ECF2413CAF7881E56B8C +:10E240008DFFA67AE5B71ABF4A751623B99B5FEF13 +:10E2500028B81BCAE502CE5549E593107E4B1A3605 +:10E26000BEF80EC1E5F11F7F8CE31EB092DF86BDC4 +:10E27000C3E1A7B7671658BE12F4B459A3079F7835 +:10E28000F4438A3739B13B3307F76D8EEA3B81F7A8 +:10E2900071B5D97C9FFC0CCA5D070ED1BEE8E7DBE7 +:10E2A000E5DC5EE17CA512D71183F12EE58B07D169 +:10E2B000B930A7F7E3EBB3097ED29FDB7E3AB4BD5A +:10E2C00025E729FB97F393FDCB76FF25F6EBACC949 +:10E2D0009783F2B97FBA4393877D36D2971365C58A +:10E2E000E7FC1CEA6C34D483F0E6FB3ADFB94BF868 +:10E2F000798E1A56DD6302FC6B6D7838CC1DCC47E5 +:10E30000AFF15C47CE57C695CA3CDA4D83843F7B5C +:10E31000001BD04DFEEDE38827955DF36FE979771B +:10E32000F9B79DF9B6FFE0F9B632BFB6B0CC501BD5 +:10E330009C672BF96161263CCFC2737FAD7C2FCCEB +:10E34000D5B6EF8E3F0ECEE47E95C298D0F9AE7F63 +:10E350001EC4DFD7B3167EFFA0908BC304DCE5BDDF +:10E360005F524FA9167C5BE6790E6BE6719BC34446 +:10E37000DE0E7001CA73ED72BF5B7C26C955793F12 +:10E380009F027D4D8F0E952FECA3798C641D54BA9E +:10E3900098DD8825809FCAD1AC9CCAB1AC96CA7161 +:10E3A0006C039537B3062A6F653E2AD9A01611EF84 +:10E3B000792FCF331DBFD080F2B5F08ED07A71FBAC +:10E3C00015E1E0A1FB03AF150E6319BFE7AF0B3CEE +:10E3D000FAA7137EEBE1A1CFD71CC1FC7471C92849 +:10E3E00044DC64B4831D14DF5AC65C541F739570FB +:10E3F00028F6BB8D3CBF57078FB2D0787141C06300 +:10E4000015CACEA2C03E65673AE8B9DC2F30C4E237 +:10E4100091FFEBF7513E2F8C283DEFB0E37D30AB01 +:10E42000A6501E7741E9F264A8A766FE6A0AE5795C +:10E430000F2B7D01F3BCD39F7D98BFCF2D2D08738B +:10E44000C2B8AB1E9982F98C6E1137ED16F1D2CCA1 +:10E450009DA7B91FCBBDEA1EBA6FCC3DC0EAC475FB +:10E46000CABC7035999FAFEEB1BB7B66C27C13C648 +:10E47000F9D6704897F69E0A74DCEA0B6318EFBF72 +:10E48000D6C4DBCBFB6CE4FAE43D37BB76652E5794 +:10E4900092AE3C0F1867008EE35E3590F2E3DCBB72 +:10E4A00015E7E5C60B4F722765A2DE8549F14017D7 +:10E4B000FD841C6EDD959989FB949D29E27E621393 +:10E4C0000B108ED392CAB3B17F99179D2DF6A5BBC1 +:10E4D000724AA62B13DBEB9FCBBCEC9199EE3C1C54 +:10E4E000BF26E222E59BB5E5BDBFC69FD8354FBD2F +:10E4F000DEC5BC26E22BDAFCF4F6F926BACFA9B0C9 +:10E50000DC5D8F21CA374EEF188CFA31F43B1CC703 +:10E51000AD31F913F2548C42E6F9EFFA7CEF3DAFDE +:10E520001DD4E4B74B3AEBCC6F3FC7F3DB03F4F5F4 +:10E53000E8721694DF2EE946D2DD50CC6F8FC47A94 +:10E54000C67C6C37E2FD6394DF3EEA985FE4B77FF8 +:10E55000A8CD6F77FDF3BAF2DB4F8AFBDE4E5AF897 +:10E560007D49F23EA965BBF9F9EF3285DF27B5ECAD +:10E57000397E9F94B40B1789F5551DDCB606CFF98B +:10E58000163D3E97EEA362E21E5407FC04DB85F2C3 +:10E590005E527D1E4C0DDA83A437B790DEA5CF877F +:10E5A000A979BC8CECC11A9D1E5D9D29EC4121CF3F +:10E5B00098D0FF168A6F711D56B2CF4CA4772E7B70 +:10E5C00062B9D38E7541576CC70E3A7793EDD9E394 +:10E5D00031840B92CE16AF53487F95F0CBDD6E762B +:10E5E000D13DC6DB7B93DE0AFAB6C863F6727B1BAD +:10E5F0007005E3E177467524A19EBC734FBA1338CA +:10E600002C7BA5DBFBA777E8EE9F7E4A73FFF439EE +:10E61000FC0FF5B453062FF63398A5FF12EF252E05 +:10E620003A65747A1D81FB98AF74EFB084BF59ECE2 +:10E63000D7B5DE43ACBFEF59E63FE8EF235E2BEEE4 +:10E64000231ED1CD7DC466B55925FDE16BA3E65EE1 +:10E65000E21BC53A8B1DCC8BF7FC0E6D356AF6BFFD +:10E66000D8BF81A13E147ED8A8F123981DDA7A8301 +:10E67000C40771BF4857785B3BE1692678A6D03D57 +:10E68000CF45BA7B9E259C3AEF79EE6F25BC1F7A69 +:10E69000F00515F9C1B5DEF7FD43DFEF7DA5FBBC45 +:10E6A000F5F774EBEFE5EEEE9E6FB9EF792DCB3415 +:10E6B000EDF5FB5E70E0A7DA7BA8C57E7BE0E7BBEB +:10E6C000DCEFB64CE1DF15FBFD355E800674F89794 +:10E6D000C8530F22594E88E07CADD3AE1F1E46763C +:10E6E000D6BB8E98321BD2BF9053E5424E8115C7E0 +:10E6F000EB025F9C3E1E47907F94DF5F51E8E7F19D +:10E7000004834F85CE0FBABD58D19CEF76BDB79824 +:10E71000E7190FBBC8E3F4F4E7FE326FA8C215AEE9 +:10E72000BDBFA19B3C22E9C7013D9E99508F37F0A8 +:10E73000FBEC42DC73BC494D0ECE2372937F67B273 +:10E74000C59780F86C4B74C7671505F28D46615EFE +:10E750009142F6A0104A513FC238CF764CB2ED8BB1 +:10E76000F9A3913FC23C1998BEDD3F989BBBF86F5F +:10E7700060963B310BE4C971C5BEA600BEFDCBD08F +:10E780003309289FCC78AE9D4FE7BEC9F85E7F3F26 +:10E79000BFDFE020FDC2F35385EC8733D8D990204A +:10E7A0007A5D1726F21A757FBF40D853F2EF171C17 +:10E7B000872E1601DF9ED1C4F3A897C6B70A3B8CFB +:10E7C000DFDF3AB7BF95EE7F62AE0227B7C3A57D04 +:10E7D000D54FBD16B979A5F8A2A5F1A735762EDBE0 +:10E7E000117355E7898175F3FE8F3F1041F2E6F80A +:10E7F0000303C8CF17E8BF8DECFE19B5DA38E3592B +:10E800002B3FD2E0DF6CCF679AF7FED88EB07EB098 +:10E810007EFF8B7DC64E03F89DDD6D1E8C7406FB5E +:10E8200036352BC80EF63F94369AEB01575AE71946 +:10E830009AC73111272AD7F949DD51AAFBEBFCBA57 +:10E84000781E8FC62E95A5E90D46F7E474283D9CE9 +:10E85000A1FC2C9F6671BDFD98C8833C26F2208FD9 +:10E8600089BCC563224FF198C85394F9A3C714E635 +:10E87000C2788AE94AF993B315CA1FBD07F1AF669A +:10E8800049470EE6DBD5E4FA672A2AE58FAEC4F5E0 +:10E8900087C81FCDC1BCF75D5977FE08F5F8533D19 +:10E8A0003C742FC9EF774CE67513A78F57B246110A +:10E8B0003D78FBBAEFC37EBE50D416C2E797153A37 +:10E8C0004F652EBF69E265F24B1FC8E2E70BEB759F +:10E8D000E5D62CCECF5E11E518F5C154CAFBD9643C +:10E8E000A6BC1F18C765083AFFD7E767E5BF6E6E7D +:10E8F00041BE21FD304F6425F273CF64EE5F89FD88 +:10E90000A599E76DF97D0998E785F13E786F063B9B +:10E91000CC5C3C0F8CDFDF27F7E109B10F74917EEF +:10E9200061204FACEAE0F14F908F8CCD726FC6F54D +:10E93000CBFCA5AAC8BD1437F1429683BE83F9D299 +:10E94000FA811FAC5608CE5DFC70CFE0FEE8F3DF25 +:10E95000BB5BFFD9F9BEDF642506F2A782F2A65E93 +:10E96000C079C875CB7904FAB93C5E4B7F52C0DFE1 +:10E97000B53615E944DE4F9BAF2AB32686F8FE0371 +:10E98000B16F5549E57B711D4B6AB9BFADD31E57B9 +:10E9900036FCF863DCAF8356E273DD7DAF5F67D58D +:10E9A0006B07091EB0CE99B8BEA075BE9B15E417C3 +:10E9B0003CBBE7C3DF20A8AF777DD79AC76CEEC119 +:10E9C000EF43ECEA8F860D0DD2A3CCF2FBFEDA7B8F +:10E9D000C6CCF8F71060BC46617F340AFBA3294C13 +:10E9E000FCBD1A9D3DDAE8E3F13C8DF1268AD76142 +:10E9F000E2EF2B48F9BBE23D1EDFB32291D17B9CB5 +:10EA00001FD281E2DF4FF2A0F3BE2805E41CE0C371 +:10EA100019BBFB02C28FB997937C506FB03A119F1C +:10EA200077BD7DB3B0ABB8BC2912F2A508FBC175A8 +:10EA300064F524B95328C61D6CA925BD7608F308D2 +:10EA40003F8BF0473CB05F638FFD5F0DF62D3910B3 +:10EA500068000000000000001F8B0800000000009C +:10EA6000000BFB51CFC0F0038AD7983330385A31AE +:10EA700030E45933305C07E2307384DC4B71049B23 +:10EA80009AF8A73C65FA374832306C02E22D40BC58 +:10EA90004D9274FDB7B410ECBDAA0C0CB781FC6E9E +:10EAA00020FD5D9D816117907D07882F83F840CC04 +:10EAB000ACC6C0200EE4AB00693F20D607E2BB40E5 +:10EAC0007E9A1A6EF3EF69E1B77F9B062AFF1D1A43 +:10EAD000FF923A7EFD999AF8E5DF1190C7861FDB19 +:10EAE000911F1FEAF6B44927B4C207D0D2F54E13DE +:10EAF00006860BA60C0C22D0B4BF17495E0D28B6B3 +:10EB0000CB04C29EAB074C7B66403E8E7C310F2807 +:10EB1000BF11286F648EDF7E056654BE002FA69A53 +:10EB20006F4C08F6042154B9C3C298EAB9441918C5 +:10EB30000065838486D80300000000000000000008 +:10EB40001F8B080000000000000BE57D0D7854D5F8 +:10EB5000B5F63E73CE9C99644E269310C240024E89 +:10EB60007ED0A8098E1030261372263F242401C3BC +:10EB70004F695A699DA045DA8222DA5E6F2F5F19CC +:10EB80007E1A2245C516ADDADEDE812A4FDBEB7335 +:10EB90009F60A9E586442610100D3F11ADDE7EB6BC +:10EBA000DF8DDA8BA10D38C160E9F760F9F65A7B89 +:10EBB000EFCC9C939904D4EFDEEF071F9F9373CEA5 +:10EBC0003E7BAFBDF65A6BBF6BEDB5F758C944E25B +:10EBD000AA20E40AFCA357DF6442E8A391AB785E65 +:10EBE000692741C72D84A4D9F7F6CEC820649E2694 +:10EBF0007B6B3D844CB2B7F4906242CA89CD63CB43 +:10EC000021A45BFA4DEF0C7A7F34C5EAB511F8F711 +:10EC1000002173085967A77FD2F2472FD22BFDFE40 +:10EC2000E85F2D2122115223371209BEB74BBCBC1D +:10EC3000AE2DC824A49AB07F732F926A5A8C54BB0D +:10EC4000EF6D243308A972D15276F6EE0A2B4F08E5 +:10EC50002D5F4658FDBADDF8BE8C6C1F929D701773 +:10EC6000919B8A687D9755E37B77ED07C409E56240 +:10EC70009E433FE00FCA83EB494AC61907FDFB36A6 +:10EC800072DB15995E950984DC1EE58BF94A481004 +:10EC9000F9D6C1BF5748D30CB827E4456C3F5DF0A7 +:10ECA000B1AE9FB869BF334A88B7967670529DDE81 +:10ECB0000D7C29AB563D367ADF5D336772BF46C89F +:10ECC0000FCFB5679142FA796835F23183F3B1FB22 +:10ECD000DC4BEFDC47BFF7D511AF8DDE1FB07A27D5 +:10ECE00037158EA6C757979E44683D4F341D7260F6 +:10ECF0003D84FCED4A26AF278F90CEA6DCD4409C05 +:10ED0000EFC4F5F10D2E426CD1FB1D3AA96BD7462D +:10ED1000977B0906733654BF1CE92CE3BCFCA14465 +:10ED20009ADBB1DD661CA7039CFE1EFD90A3BF10FD +:10ED3000DE871D16DA8FE090853C4FABE81CAC4CAB +:10ED4000067A37E996303CEF1C5443C00FE26ECF91 +:10ED50005A54349AFE03432B6662BF02AB0DEDFE9C +:10ED60006090F65783FEBDE89847EBB9306871C9EB +:10ED7000745C9FE0CF0F04DA1D2EF86E201DC7F3E0 +:10ED8000F10DF4EF1B12F3E3F1B9DFC80D6850CEBB +:10ED90006EE4C7E085637974DC3A772A5EE8D77859 +:10EDA000FCFC016F47DCA77BC3552E5AAF2FE295C1 +:10EDB000408FD207099990037AD179D809E3DB48CB +:10EDC000502F7C4D9549D3593FBCB207DE1F974168 +:10EDD0003E7CAE30F663841EA0EF06A0D38DD7A78D +:10EDE000797B4FC13862FF36255D4FE9BD50A26087 +:10EDF0003DBBF54D7E05EBBB1C96411E573379CAD2 +:10EE0000F004365A81FFF7106FD003F512ECF74F7C +:10EE100079FF7FC2EB13ED740EA6FB15A0AF9978B6 +:10EE2000414D6AE4F5DDF0BD6F15A37FDAC36B25B4 +:10EE3000E0DF75EBFBF11AE274EE80EF6981ECB56F +:10EE40001109F836F5A1305E776EFC7D37D097BAA0 +:10EE50008524812D78A2DA9206DF3D316F4A12BCFB +:10EE6000773651C5A7F6C0E7753DD043FBB3B35A1B +:10EE7000413A770E52FED372CEA0CB0B7AED0C7ACC +:10EE8000F8D5EB85F207393F0EF076BB381DCEA0E2 +:10EE9000CECBAD2D8472CE6010AF21DE4FE2598310 +:10EEA00072B78ECBDD416BE026E07BC6207113AAE2 +:10EEB000CF07CED74F867645FDE6F27B9EFD9FB30A +:10EEC000E0FDC441F2AE75065CC32DD0DE0DD00F5F +:10EED00027DCF7B54868A742A847FA650B2105511A +:10EEE0003B9571A969FE1D1EB8AB413D1276A06C21 +:10EEF00050B548A9B17A568D7AB093EB41F56018B8 +:10EF0000E584EAD9610BE553F01CD5332A5F079AF3 +:10EF10002C38DECF4554B4C3A4209CB52865B41E5C +:10EF2000750EAD9C09FC16FA34DA7EFCBFA15F3B7E +:10EF3000693F0271EC9A684FE89BF9FDB8FAE60A5E +:10EF4000A2BE75527D0B023F9B2C49F9A07F6D1626 +:10EF5000D41377757B37D397D5A86F19F7307A26F6 +:10EF60002D0FA11E8CA7773B3D2EBF02F537333DF9 +:10EF7000ED1C7C6FA30DC66339E176E27237DCFBD2 +:10EF80001E667A6DD633B31EA6FAFA503F73B644A6 +:10EF9000085C3D9B1B51AE692B49A87F09F4B01357 +:10EFA000F4B0F8FF1F3DAC82799CEA5D9A766B8FD6 +:10EFB0008BF67B7E84303CA43DD103F3784DB68D37 +:10EFC000CDE353DFBEF37E7A7FCCEA40FE1F9B4841 +:10EFD0001F16C3BD8C7AD79DB3357B1D7D3F3F4344 +:10EFE000C2F784AC42FDAE1578091E51FDF1F74B16 +:10EFF000644E3A947B7F4715FDFED501E28557AFFD +:10F0000066CB58DFE141C2F498EB672DEFEF61FE6C +:10F01000FEC2251202FDAC0048429F7F7C3632CDF5 +:10F020004E5F7D68B95C4472E97C2CF8C571460D71 +:10F03000D7FF5733641DECC6E1F529219283F5858E +:10F0400041DE5E7DD81692697B17F2F35E0813C02D +:10F050007F91EBD7D1F73DAE8F5262F57380CBEF46 +:10F060009FB8FC0E723CB1E3E6A64512E5EFABF9A2 +:10F0700079A85F17F23F9A4628ABEFCFFBCB19B8C0 +:10F080001212B6025E32D723BE7FD51DF8B244718C +:10F09000D540E87D278CE7B97D1FCD802B714F408F +:10F0A000DC351E3EF3091C16E9DB0C388454533959 +:10F0B000991395934991BEC3C037DF30C363A46EE3 +:10F0C0000D8E4BB98BF1A5FBE25B59F05D07E75B59 +:10F0D000D7505F16DAC73A633D5DD6FEE54DAC7E8C +:10F0E000FCDEE762E32AE87999F7EB6949220C270D +:10F0F000B2F1F3F1EFE72A7D136EA174CC3D267BCC +:10F1000037D2477307FAAB491C3BB45B4A4379AD2E +:10F11000B86494D7AE8B4765E00BA557067ACB232E +:10F120007D32B3E34CCE7C5CCECA23A70DF65DB432 +:10F13000DF1539DD00ED5F1860F62A115F85FC1CD4 +:10F14000E2E3FCB2D0571272DC42E5E508A57FDBB2 +:10F1500018DFD7B86403DD42FFAAEC0E035EAFB838 +:10F16000946EC2FF467A4B9530F2AB14F8E549CC69 +:10F17000AFF5523AD65F36F0E9F865B62BA2DE2E2F +:10F18000E063E168BA0808B5A05BFE3F9FAF9DF061 +:10F1900007F35F8E829E92FEBD72530ACC271ADA65 +:10F1A00093B26A89E172DECF46F896365527F4CAE3 +:10F1B00023A19F57EF9342B58037BC3F433FF142B5 +:10F1C000B1CD03766892E709A53F46DEEAF9F72359 +:10F1D0007CDCA0633FBB67BF9D05E5BAA66FCC860C +:10F1E0007198EF79DBB18EF2FF28D79B8E0D7558A1 +:10F1F000AEEC1279F45618977CA66773795F7A386B +:10F20000DF0E71BB7190CF9B6F6D08E0F5CD0DAB3C +:10F21000F07A7AC35ABCBE7AE9450DC6AFB7200F63 +:10F22000E7AF3AA55D89E757950E1AE5E6650FC584 +:10F230003BB47CC3E08AEDB7D27E1FBF6441FB7C48 +:10F24000BC206F4CBC22EC8728F78AFB6755C0B7FF +:10F25000C6014A6ECEE8F266792D23523BE0BF32FA +:10F26000EFEB0AA1F67241F12E2D16C71C38975903 +:10F2700004F51E90FEB0649627311D65BE3EECE796 +:10F2800082F0EF144F4AE2722794BEC659E8A732C3 +:10F29000FD2AF3BE5BADD3F66A0B7735A25C0C2B6F +:10F2A00016908BC6C2BD7C7C5D381E0BC47C562C70 +:10F2B000D785809EC10B48676FA13C11E8DB669142 +:10F2C000512E17786C886713B63FAC9030E89712D0 +:10F2D000C6713A4EEB01B93841ED1E7BDEC7EE69CF +:10F2E000BDF0BE3BC7A679819F6E118F5865908F88 +:10F2F000C6FC59C7BD94EE5EB78CF8B2F752A59222 +:10F3000046EF4FC0FCEA89CA671997CF1330EE2049 +:10F31000C72119E73F8197457D5D97721F2DA6EDA7 +:10F320009D0859E37EDF546DD4C73BDC0EC37D7569 +:10F33000F604C3FD89C1996F36417B947EC0732466 +:10F34000B8DA407F17D87B68CF25E1FC7FF472F5EF +:10F35000E0FD502E64A4CB4C47EFA5DC2797D27A72 +:10F360008FEF93514EABDD46BAAA2EBE791CE23820 +:10F370000DD4BE00DF5ED6151DFA7D625F4A68239C +:10F3800095CB970B5F77006EA0FFB405B49D2AC2A2 +:10F39000C6B732C358CFF1C1F7BE0F76EA825D46D9 +:10F3A0003B57F9D7435B005E9D2A7EB007F87C800F +:10F3B00048C8A7F273BB65A86F59C8F8FDD2E546E7 +:10F3C000FEAC593AC164FF8DF1A52A0F8B13CDF520 +:10F3D0000E617DA510FFA1F7959A312E34178C414F +:10F3E0004CBDE5A6B850A987C5854A212E24CAE59B +:10F3F0009051769FDE63FBE679DDACDF09F5DF42F5 +:10F4000056413C8544168F835B36F1F88AD1DE1273 +:10F4100065A704F250CADBEFB0B63B802EDFADCC5F +:10F420007E91487ADC7895D98E10F220CA95E02337 +:10F43000710549C61CE83F2F63B67F9C2F6D743859 +:10F44000AEE03C10E4F8C51357DFCDDF67737D9F56 +:10F450003740ED66068C97EC02BB71FC12D1401F61 +:10F460004F5179672DF75F8995DB868176944B5AEA +:10F470001E469096F7A2FE364D66FADB9D53ABA46E +:10F4800031FB1957DFCD7A3040824F15D3713D9E45 +:10F490009FF7E452FA5DEF3E61072C3AEAD53E86CB +:10F4A0007B4F0CAE4379BD40E515D83E5AEF4F6B0C +:10F4B000B1F3FE7F96BE9BF57C44FF47E93BB35B0F +:10F4C000C7872DD89FAA8B0AD6D37099E03C6ED6F9 +:10F4D000FF13DC7F7B597F53F3C27C58F83EFAC799 +:10F4E000E453EB3BF3430E0C106CBFFCDC7B32EDC2 +:10F4F000F9E7A6EF42CF85DE5EB3BEFF27E9B9F993 +:10F50000F9B72D1CF727D0D3A8FE07B1DCE61452BB +:10F510000071B60E29D9BB2907F49DC57DCCE5271E +:10F52000C8221E6B0FFE91F6AB850A4B2A65F51AB1 +:10F53000D23F0DE461E2640FD6779FA53F13EE3F03 +:10F540002491CC9B65C0CF643FCCBF924EC8C3947E +:10F5500024C9E322CB6712F2B81CB0CBB43E6920B9 +:10F56000FC5789F2993C443C80076F90020E786EFC +:10F57000A37CD26879A29C469C48FD37E4D742AE72 +:10F58000740BED5A18E3F025D6C17EC1779C3F96E7 +:10F59000BBCEDC4CEB2561E9CACDD17EEEB186B2A3 +:10F5A000BC1AF433F4E3FB206EF58CEA7D3E0EDFEB +:10F5B0002D9FB29F607E909F16C6CFA025D9FB7C61 +:10F5C0001CBC35FFDAEB7F2B995ECB808FB78CE6C6 +:10F5D000A33448F9077C50FE7605FCC43237932FDC +:10F5E000F9435587380D91EDA1E971E858C3E978E1 +:10F5F0005CD66FA3C886C855EDC89F0330FE1AF0CD +:10F600002F837C3B46BEE6C92AD2253790B538BF4A +:10F6100090B005ECC878E361558822C338F65D41A7 +:10F62000BBDBCAE9B3D1E7DACCC4E3253778236181 +:10F630003A4EE443364E07E61BE5723DA7FF414EC6 +:10F64000179827A8BF14EAA7FC92FFACAE8D374FDE +:10F650006C17FCE7FC32973FF025D67F517EABCC90 +:10F66000F42978EDE3B66C525EE27113F22E0D1EB2 +:10F670004D347E6B4371F47B8E6CE1FD0D4A57A3D4 +:10F680000FF3B85CCA5574DCA07F35463E6EE6FDCC +:10F690005ACEEBBD4BD2FF1EE4E106A9E91FE04ABA +:10F6A000AAFB50FF40C6A1DCCD44FF6FFCFD06D095 +:10F6B0005352677C4F9F6FC2EF9AFB707D4A3C3F6D +:10F6C0002CE95B64F6BE15BFD38DEFA91CB6C173E0 +:10F6D0002A2F449E09CF193FA99C103BBD6FDD75B1 +:10F6E000F79781AFF4FBC7B07E72DAF0BD150C441A +:10F6F0003ABB4A33D9F559903BEE9F6E6ED691AF27 +:10F700002A59CBFD67369FCDE5F399FDAF6C1EBC42 +:10F71000E05231AEA524E9A130BDA6BBC23AC40374 +:10F720002790BE20F863CB96CA063BDF6C9A5FBE7B +:10F730007C8F71FE5DBE3ACB70FFD587F20CF781EE +:10F74000F5371BEA5BB16596E1FE9EED6586FB959C +:10F750003BAB0CDFAFFA4983E1FD379E5B62B85FDC +:10F76000FDC29D71D737C57CF788E5DDD54DB45F07 +:10F770009BE1550C5E54A2EB971686C78CDF51F1C6 +:10F78000F32873A01CC15084594E15D3FA67FF8823 +:10F79000FEAC33CCB7878239190015F41C4543FC05 +:10F7A0001FD4FBF233A378A0CAB3B231DEFC2BE83E +:10F7B0005178393FE9AF8271D315633985AFD76A84 +:10F7C000DE08C661CCEBB58A671ECEEF667ADF91A4 +:10F7D0005332C02ED1BA3DB84EAB5DDD7C3A6EFFE0 +:10F7E000A825BCAAFEF1F6FCD0CFBCC4FD9A5B1CD8 +:10F7F0009181BCABED57944E23EE11EBE40B5851C5 +:10F80000529AF31CFA630B803E989F8B19DEB1D39A +:10F81000FFD83CCBF8DFC0CB373DE4B2023E6EAA46 +:10F8200036D2D9C07114D54305EC446981E93DD085 +:10F830003903CA19F1520F97474DE1EBE573C81C24 +:10F840001C07AEB78B84DED6B0380771C55F47AFF3 +:10F85000BF440BCDC2F651FEC4F3D70AF292E1BB0E +:10F86000056DC463A3F8E491D91B5D9580F375AB76 +:10F87000B78E96AEF2F278932E239EBDAE80DD3722 +:10F8800056B3F8537DA00FE3808DF78436C275CA56 +:10F89000AAB0827498F8FAAC279486D880F3378B94 +:10F8A000F32B4BF095F351D8F129AB8DE3D8586C7D +:10F8B000E4D742CE4F339F17723E2E34F1B10BFE88 +:10F8C000A07C999D808F0B381EB5CFE6FEDD707A47 +:10F8D0005CBFF1591E1F13F2A398E635613F46E65F +:10F8E000372EBF8F831D079CE7E23885CF7B89F4D5 +:10F8F000C89FDFB2C30FF1D60CAB61FD621EEF6B88 +:10F90000693E5BEF28CD9011F797BADF30C4994B71 +:10F9100047E2A3BA5633272A9F5D03CCFF68759F41 +:10F9200096619C1AF219CEDFC2F923E27F07F8BA7A +:10F930009199AEA3D382D9808F8E5D0C66AF2B8652 +:10F94000F88F8472D279EB03D92C5F80C773797BEF +:10F95000AF0C05D17F3B3630F6FAA2C0F966B92963 +:10F96000F586709DB174A05D86FED645E81C44BB4B +:10F970003E2FFC0BD95384716905E86974AF503090 +:10F980005EE66E5120BE5CE7DE5505FCF091D06668 +:10F9900027C4D53C92370C7C2C64FABB8AFE17AB8B +:10F9A000BF82DEDAC18002FA5EEB31FA353E2E6F9D +:10F9B000356ED3F3FC5A94379F49DE3609399B4E96 +:10F9C000A6C7CA99885BAB43B95C5FE3CB5927E70D +:10F9D000C7BFF338EB1F787CFA1DBEAEF7BB0D1E18 +:10F9E000BCBEB2A1009F1FD9E0C5FBB73794E0FDB4 +:10F9F0006F21CE4BEFDFE071DCD73734E1FDA90D8D +:10FA0000CD78DFCBE3B4428EB7F2F5941AB913E3A5 +:10FA10008B0DDE80DD15234F0D9C6E147DC021857E +:10FA2000F1E3AFB669FB1590AFD3237A42D05E2CD9 +:10FA30006ECCD9BD8DF2C5F65D12005C693BF4AFAA +:10FA4000CAF554FE1BEA72AC2BA1BD60BB320BE4BD +:10FA500031FCAF4A1E3C6FBCD57A779CF6453B899A +:10FA6000DA37DBB72575463FB854C4D1070241E801 +:10FA7000E7A4814018E82B75AB9E7871E1EEC92BA5 +:10FA8000DD204FAD67036E90A7D6C97B64E6AFB3A8 +:10FA900078B8CAE554942F75EF36E8A1CAE9EEA00C +:10FAA000CF81DE8E71F4E000E79B28E753C2B24BB2 +:10FAB0004BDC3F9F295EBE458AEFB7265B19AE75CA +:10FAC000F2F5556A3315D0331051A07F12151BD0B3 +:10FAD0002F4D63710B8737C0EDB2711E4F2B696AD2 +:10FAE00002BBA465106F2D9837ADDF0D722397CC44 +:10FAF0003B0BF32C298CB1DBE0F798FDFFD87B1989 +:10FB0000A7AE604A3A5CCDE5187F352E426DB7321C +:10FB1000FA1EE3710EC15F8DF3B7D473ECDFC0AE94 +:10FB20003EE665F198C732D8BAEC85921588CB4A83 +:10FB3000B95F60233BB07C3269C7EB66AE67174A9A +:10FB40004E13D07B59A1B83903E8B18782F47BA763 +:10FB5000C9BE2B9A91DF12E5C972C0D7038AC1DFF3 +:10FB6000904A989DB783BF0E7E0CC72F513F2F4000 +:10FB7000AE00F3AF124F6DB11AFD31711D502C283C +:10FB80000F2EAB299FEEFF7AFE1DFD5CF927FCC40A +:10FB9000119C77F8EB04D663443EA128FF8A29DE46 +:10FBA000A466B3751873BD775819DF2BAC1C1F0BF7 +:10FBB0003CE133B79314047EAAD49F4A9246D7936C +:10FBC000A83D3230739CB8F5466CFF94E262FE04A7 +:10FBD000CF07A26EB964F04FECBA3B76BD7FE47BF1 +:10FBE000B7C5A0A7A3E966FCF9BCE95D401D52B802 +:10FBF0002E1476B884E1C9451E8A27E99F8B3426E6 +:10FC0000A727FD526813CAA96EF0B7EA4A6ACFA2C5 +:10FC10005DA2FE883A87E3744A7F1BD44BEB797D63 +:10FC2000B2F86EC49E58AEDC32BA9EA66A867B4895 +:10FC3000F097F363E3074D545C0A6642BDEC7B5AD0 +:10FC4000B4FB4A3C3AB8DD6A2A7960A1E6847B5D60 +:10FC50007A1AF05E610C3E00BEE6DB8C7C36D9BFC2 +:10FC6000EA5176CF686FE751F9DD4FDBA993D736BC +:10FC700042C8BBF68915FB5E4572841FE2895BEFC3 +:10FC800071F8E376407F46BC42BC2C8FA32AE8691A +:10FC900044BE6748249403F41BE998976DF2C3327D +:10FCA000CCFDD881E37848A1F3081DAF43741C77DD +:10FCB000A07F1CDF9F127E5E45CE30FA53C2DF2349 +:10FCC000DCDF73D1FF62F158392FEF7FC8A300FE4C +:10FCD000F5DB4D71E691FC6382FE540531D25BCEBB +:10FCE000FDBE7293DF27F4FD25612F855FCBEDE12B +:10FCF0001DC29F2A1F7B7DB9C7944F574D096FBF07 +:10FD0000063D204015AC3791113E19E4AB3BE7FAB4 +:10FD1000F630E5EB1DDE24B6DE42E954843D473E75 +:10FD2000319CBD9097BFC3A3A2FCFB34B67ED138F3 +:10FD30004EDCC257C2D60D4ED925361F04C99B24AE +:10FD4000263FBCCAC3ECB566928B6C4F5335AC03EF +:10FD5000698AE40D91D1F25ACDFD39F87E3D6545B1 +:10FD6000753EF5C967C6CB2FEF83D02A29A7343C4F +:10FD70009B93787C756FA40A86E76AC7979870F69C +:10FD8000A9C87B98D775A150C2759FEE9C8FD13FB3 +:10FD900010EB3B51FE1DC57C145FC947E8AF8CE4F6 +:10FDA0006DF1FA168AFA4A0EE37ACDF75C87314F85 +:10FDB000E424ACE3D2EF4F2A110DFC90F9025F511D +:10FDC0008E86053F73204F82D517E67ED529FB1B13 +:10FDD0000EB09B22EFA4CB27D7C58B7356C82CCE71 +:10FDE0002CAE37A96CDE99A3323C27EEC5F88EC83D +:10FDF000937CBC98F9E1DF318CBBB97E28DF8CF1B4 +:10FE0000C170E158FE68A389CFD3543EEF71BCD1D5 +:10FE100019191BD78A7E9AF960EEA7F93BA7CAE2A7 +:10FE200065F758F59BD5D9D176C47C672EBFC81E1F +:10FE30003F2FC75F628C4F9AF372EEB1064A55CAE4 +:10FE4000CF2A45DA92EA41BB86FA74E8B28638E6F0 +:10FE500042E4D01618D623C32C3E5A4EE4908DCDE2 +:10FE60000B8DB06E27F446C8BF998EF1DA2F1FEEC6 +:10FE7000477FDC7F29520DF27787AF1BEDEA026ADC +:10FE80005727C4B1ABF3E4C12D13407FBD6C7FC7CE +:10FE9000A9DFF755E3BD26613EAC5E9EA74C003955 +:10FEA00070C58F57CDE572327A3D4FD8559702B85D +:10FEB000C11C6F9BCBF56EAE491E02EA080EBAED6F +:10FEC0004ADEF8E394481E2E442E3C182F8E2AAEAC +:10FED0005509C6F73E62E26FA731FE6CAE47C48398 +:10FEE00088DC990DFA2CFC5F73B93695AD7B1C2923 +:10FEF000BA97C4E655097BA096B46B1017EF2D197D +:10FF00007BBE30E70FFA89314FACCA6E5C8F7D4AF9 +:10FF1000D11F01798CE2A416E6AF96B4A0BFBAB0A7 +:10FF200090EF0B2ABA17FD53E157B7DEBE17F3B9AE +:10FF300044BE96F04FCD74F74E7E11F379C6A35BA5 +:10FF4000F8F1C76D325B87A07EBB07FD768AFBE2C6 +:10FF50007CF78A8DF1EB578ABE0BF4758B5577B71A +:10FF6000C03A6391CDFB7C9C7118B031FDEE4DB071 +:10FF7000DEFA0758F8988DFD403E98E71BE1C78AE6 +:10FF80007D4A93DC4C6F1BB81F5B56D882FA98E60B +:10FF9000A67E2BF0CDCBFC563268F453176A7D5900 +:10FFA00030FEE6F94E1EE67EED55FAAD5B93981CE9 +:10FFB000055CC4EEA6EF93140A4DE9FCF7A45C7946 +:10FFC00018F8B1358DA03F70324D0DED8E136F785E +:10FFD0009BCB5B8DBCDA206FE51C97A8D5FD1AC4BE +:10FFE000034E0EB3385EA271DB66C2E9B905C46F79 +:10FFF00073C235E2077ED07BDD86D708E6677FBF18 +:020000021000EC +:1000000068656EBCFA76B72971E7A53FF3715B2C82 +:10001000F2B5EB583CF2BE4215E3C293EADE3D8AEC +:1000200072DAC8E574810DFBDD5BA4E0B8F4DE9EF6 +:10003000D30EEB9ABD4576CC47E92EFACDEF215F82 +:10004000BBBC4432E49708F92D075C0DF5DB59BCC5 +:10005000F33E37B3C3BD1AC72F3C6F640D1FD39354 +:10006000FBDE77C6E68D2C1172DFC8E3E426FC4484 +:10007000CD48DC751C91477CBE91C585EF13FDDD35 +:10008000BF770BE85D03979BEE8B2BDDA89FFB5999 +:100090007E5E6B510BC68BBA27BFA5C2FD1AF7193E +:1000A00015EECDB8428CEB7D25BF62F9917C5CD713 +:1000B000403C9ECAFBCB99375B3DF47E71F8762BB2 +:1000C000C43B457C76D43A145F4FA965DD27B56EF5 +:1000D00086AF8F663A487206F04B0E49C0B7701271 +:1000E0004986FC33B7359444EF1B94FE69805B1C52 +:1000F00026BC78FED77BB341BF8FCCF8408176AF6A +:100100002B79B715FA31A5642FC6FBB3F6EFED498D +:10011000A7F52C2C205EDD339A9E1A3E3FDD97C159 +:10012000F285EEF38682B0EFECDC65B69FA2F2D7E3 +:100130006F54C1B4367A5D46278043C4BA8EE2E676 +:10014000EB227C7D825CBE22C58E5B8312B083FD78 +:100150006D2D79C309F42EE67CCBDD27B7807C5763 +:10016000FF7AD657404EC8ED36D774DAE039D76FEC +:100170009DD76BECFDBDACDEB9015ABEA1706FF628 +:10018000CAA2D1F665447F0AFFB22140E93939FF9E +:1001900037D980DBDEA076D703ED72BB65F697CC4E +:1001A000F3AA392FC6DCEF4C65519D6D368CF78F65 +:1001B000DD39317246EDC00AA07FCDD376CCE34A5B +:1001C000DBFFBA2A837DA3F8BD568ACAD11A2E470F +:1001D0000D1AB37FAD4524B44902F93BD358067AD2 +:1001E000F72ACB379CB4FF5D963F6A9A1F7AF9BC19 +:1001F00021E6E3DEC9EFA1FE9CDFC7F52568916229 +:10020000E3495A4964298C8BE04FA7C9DEF8ECF129 +:10021000E326EFD8185E2DD7D87B8DDA6F58D73606 +:10022000BFAFE4FE54155C63E685076D0CF78AEBFF +:1002300035E4213CF55DAAFFDDDB0FB9EF463BA5B8 +:10024000216E5FB37F6F01ACD964EEDB5BCDED0552 +:10025000FA6532EFE724E2413BB550B3B3F50393BF +:100260009C5B4B7685013E8B791A1C7225336A475D +:10027000E4D838441C3F8C04F537F363F2BEE8FC45 +:100280004EC0AE54B959FCD52C276925D4EEE020D8 +:1002900050EEC5ACFB9AE5B6410BB8613D9BEACF89 +:1002A00059B6FE49E72B884FC88D5E1C4F2E9F160E +:1002B000FA1FCC7F0EAF513EAD05AA01AF98E9F809 +:1002C000A9CD88FFC5FC9CE6EE47FA166AEDD9D0A9 +:1002D000FE24773FFA5BD4BE67C355C899B0D723D5 +:1002E000F257745B3DD877906B58223F59322B19E7 +:1002F000EC60839BE114628AA7F7BAC7F6377A4CA1 +:10030000F278D2C5FCAB861292EC4A057D6771A7E4 +:10031000DE47D3773962E272FF640D74D862E2EB94 +:10032000CEC22FD6BB9C606758FE5629355FD6BC1F +:10033000683C53C44DC57A9F88938E8A671676634E +:100340007E9755E45DF0F5BF51793F09D61DC5553F +:10035000C4336D9BDA152F5F2F413CD6C8E370C3C1 +:1003600033C78987B2F803C567BFB54D1C1F9FED22 +:10037000E17EE600180F7A5D6573E155837C144ACF +:100380006A6F527CDC7690FB6DD7A29FC764F88EB3 +:10039000B5F327937C89E7513CCCF46052C9DE9ECB +:1003A000583C5CDE467943C7496D23D3486A62B93D +:1003B0005B3862F77E6590AF117C3C0E2E16F275AD +:1003C00051D6FF669B98B85C03A723D1FBD6225B6E +:1003D00033E45BD17264522ABBDE40AF3D33F66634 +:1003E0005BE8F3D7007FC5D0D1FBCC7EECC71F54B0 +:1003F000B6CFA6F7E2CA5CC007A7143DD53EF1EA26 +:10040000E5C7AC4FF6D9BA6723D5BFAE6C3BCECFAC +:100410005D6E86435E879231F2B44E0D5C679F8DB0 +:10042000104427E9DCC8093907A3597D75FBC4EEE0 +:1004300072F43FD414333F6C875793619D8FC9CDBD +:10044000236A3FE6E3DC456BB7D1760E6B72E60AB2 +:100450007A3FD3CEE4F170D01A37FF79A69DE1E759 +:10046000756AD34CA093B4AF453D6B91E426D07F21 +:10047000E2BDBAF8DCE68EF879A555D1FAE762FD5F +:10048000FB68FD801BBC3CFE4E5C9971E3EDBCDF5C +:100490006142EA405F1E4B33FA9B3E3B9BF7E646C8 +:1004A000EBAF8FAD1FF3B366E3F30538CE2FB0E7A4 +:1004B0000576A617FE3C96D726F828EA5D1AAD6F9A +:1004C00029D6B79F7D976FE7EB069C6E81F3CDF938 +:1004D0004F35496C3CA2FBFA08DACD528AC3F17C55 +:1004E0008548E830DCFB09DF9729319CDE95C2F6B0 +:1004F00031755987F09C85EE4F3E7E07F66B2A8A50 +:1005000011DFDBB8EC2897F7C850AE34FB8223F636 +:10051000DC8172FEBE7BD8B8AEAA73BC7390F07C4F +:100520000D5E9F3F419C4BE0F80E5E3EBA0ECCF64E +:10053000294E1A60FB122B5CFC9C88B46FA35F2DC4 +:10054000F47CEB276B199E9FCAF7AF65EF9163E9C7 +:1005500051383DA5CAFBDFDC0BFD8F1017C659C310 +:10056000BF73E4D07EEBC7646F129436F9193E8EE8 +:100570006BCB396E4D84EF8F4A81E7C22CBE69C0C8 +:10058000F94733FF59061C5A1A66EB4C151CD7570E +:1005900028A12C981F6AB3593CAAE3625F16E2F9BE +:1005A0008F3371BEB84ED985FD9EA20C619EC43CAE +:1005B00013FECF1A20E837F8A9DFA0C7C12D357286 +:1005C0007635ECCF2DF5B0FDB5A55E56BE8BB61FCA +:1005D000A4E52B2FFEA007E0FA687C6FC429E59EF6 +:1005E000A12A342326DC7FCD783A9BC5A52A4C7EF0 +:1005F000829007CA0FDC37DFA13C68073EE4665BE8 +:10060000987F30D5B21CF846ACCC3FD8EAFA961D9C +:10061000FD03FA1EFC830AEE1F545C8E64817F602A +:10062000EE8F90AFDCCB1FA37FD03DF431F239FCCD +:10063000C99E2CB0CB228F5CE07A513E53F11F0152 +:100640003D2E37E17C9BC0F9C36B09E0FC0AC588ED +:10065000F36D5CCE2A38CEEF80F52E90D7B399C7D4 +:1006600073683F0E0A9C3FEC32E0FC52CE8783A0B9 +:100670008F3138FFE059B6AFB22B3BD780F347FC40 +:10068000C84F89F37D49CCEE081C5FCBF18278FF1F +:1006900021B7E3667C6F7E7FADF89E70FC1EC5C5FA +:1006A00046B9EDDE9E8BEB2AA52E3BCA6DF9406064 +:1006B000F801FA2A7378ED1F9F007EBB1D5EF8CC0F +:1006C000C6C765DCFC4F13DE9F44228753416FF29F +:1006D00059BE515AB60BF5A482EA496D3C7D30E310 +:1006E000FF6C366E554A8BC88B1B13E757682EC4B8 +:1006F000D98A527B5538DFAC5775F9B631FDD2AC8B +:1007000024230EF30BBBA93C1044BBA93C1006FDEF +:10071000F15F66F933DD9F7CDB1D7B9EC3566EFF68 +:10072000853D17FA78F0938F791E8D49AE958F1C11 +:10073000B1FB8A0F66331CF2332582FA7BF0F2CCD0 +:10074000E4D8389519E71FE438BF82E3FC8ACB4C24 +:100750004F0E8EC6F9B725C5E036E7E56588F3AFDD +:10076000369F40F8AFB526FFF55DBBD17F4D24D74E +:10077000FFC1E7F3283F8736239E5586D87CCAF908 +:10078000A9703C6B031C790BCEA3B83F5EE8F1283F +:10079000BE5A3F32CC937E8EEF0E2A578D679B93C5 +:1007A00066272E57310E9EDDFA89DA8CFCE778B683 +:1007B00042E0D9BF45B262F12CD1180E3BF8CC25EE +:1007C000ECC7C1348663CD382C31EE60F77E4DE244 +:1007D000EB30463C21EAE94821D9189F93DE46BE1A +:1007E0007559FF12178F08FC61C61DC4843746EA8D +:1007F000059C027860F88203F6C1761C93F9BEBAB4 +:10080000CF8A4322722CEE10DF75A5E8E8CF0B5C8F +:10081000B2F593338833B60E113C3941E0128A3772 +:100820000E833FA7D3F93BC913A55FE01381374679 +:10083000FAA1B0BCD12E17B7FF09E2A09F373E1135 +:10084000B8C4CC9F8356865B3A2EBEF599F08A19C0 +:100850009F98E99DB76B474F2A2D373F7F08ED5092 +:1008600087B70FF799770DE766001FC6C72D7E5C27 +:10087000871F895372FC71ADB825115E4984330E10 +:10088000028ED1A238C68C5FCCFCCCCD262D10F7C1 +:1008900017B82691DE42B97B9D51BC93A81CB5DBED +:1008A000888312D6733972AD38E84CD298388810E4 +:1008B00026372C3F28113ED9EA7569B1F9AA623E64 +:1008C000E9CEBEF00EEE2B1F50F17C84EEB3CC7E51 +:1008D00026C247874C7A7710EC85169DAF12F265D9 +:1008E000809DF3217054A272578B9FC43CE24B62EF +:1008F000F344A2F5C9AC6486B31EC965FEB2F97DA6 +:1009000034DFC488A3484611CAF3FD7CDF65225C4E +:100910004548C4C9E254417CBE8CFB9B181B9CC358 +:10092000F30D28A94DF9241FE685263B1BAF93B391 +:1009300025F40316C1732A4FFE6AB63E74BA88D9ED +:10094000EB937E1BDAEFE3E7593E62770A8BB39EA7 +:10095000BC35C9BB9B92701EEAA5F3F0E9A4BE6248 +:1009600098F767887EA6B37E2E708457E3FAF8ACBA +:100970009B2DC19CD1FAFD4832A7235DC375B606F5 +:100980008E3F619D306BE6E8FD04CF24E7209F2079 +:100990004F3E8B96DB62E9FB7E2E7D946461EBAA71 +:1009A00066BEFE99D3038CB1C5F0A131DFAE2751ED +:1009B000F94FBA89AD4F7555DB301F270996D269BB +:1009C000BDDB0A7253E2C991E897F9F94F9399FF99 +:1009D0007D7A6A04E7B1533CBF778D22050973B075 +:1009E000B09FCA8429BBB6D1A25F4E66E7D59CFAF8 +:1009F000F5EB18273A91C6F9A04B98C770126C21F5 +:100A0000C4FB5C5A08F665D2EFADCBC6C8FBE8F371 +:100A1000D716B0F53242245847833F7247F37B49DB +:100A20009D8CFD5EE2DAFE00E8E3E9BA371C70FE59 +:100A3000E4C2610B01BD5BE22ABD179E77A7303986 +:100A4000063E036E5A52FDC56FC2F3C646E3781CDC +:100A500049CE65E7C8286C3C60FCB2668E6E97CEC6 +:100A60007E01353386FFBEDFFC9D1433AF88BC1595 +:100A70007B823CBE44FD9662EDAF1C8D3B4E2AD975 +:100A8000B503F6C73415B3732F1A3C2408EBBC0D1D +:100A90005E12CEE1F285F9343DF96C5F10D7AFB448 +:100AA000925D6DB910A71C56D8FAB3693E29A363AD +:100AB000959D0E7173363E2767CBE8D79595305CD0 +:100AC0005FC6717D83DE82EB7A8D8FF66CCF85F702 +:100AD00072768DDFC3D74763F847F6B338DC2293CD +:100AE0009CA798E2FC655E537E20CFEBEB2A78CE84 +:100AF00005F2F3483A979F9912EAD1EB92E7D1DCDD +:100B000098F9A83E59E41F118F35463E46E4818F7F +:100B1000AF99EF89F869E693592ECCFC3E9962E2D1 +:100B20005702FE27E2775989FFBF94BFE7AC362B07 +:100B3000C86DB7F5836CEE0F1139C69E98F9764EE5 +:100B4000F3A4809D383DCCE69B13533D5FC173B049 +:100B5000A81EE3399E5C1FA2E340F5C119ABCF6F1D +:100B60004F037DA67266857A1A75494F02FDDBB781 +:100B7000F501EC37E8A933AA4766FE8FD23FFABFEA +:100B800022E8CD1BAD47E6BCB14FAB7FDF017B0E4A +:100B9000F182640FF24FD8D346E2FA4AEC3E56B1E6 +:100BA0009EDE9DD3DA04FBCF1B062C78DE4FC7F008 +:100BB0008BCA0AD8D75A27E1B4A6913EA4576B63D3 +:100BC0007911D73FFB3081BCF547A7122FD82BAD49 +:100BD0008DE549D0F798272170BD38BF91BED75910 +:100BE0005E88F19CA514AF31CF67F16025AE2FF47C +:100BF000F0738F46FC0B22E4D2B8BFA5159E4C8E35 +:100C0000EE876ABB18C2F84C4782FD2EE26AF617DF +:100C1000CCD723877EF1CDBD905F91AFBA005294BF +:100C20000F87ED50DFF70B0FD5613E5B9DE48275BA +:100C3000B7231FB76F86F38E1617BE1737BFE7C0EF +:100C4000B9A7BCD08F03D61DDE74B00F9BD8BC955E +:100C50007443E1D41563E0A3409DBF2E6746E27C58 +:100C600092D50E1EF7EFFEFAEE47607D7B50F582BF +:100C7000FF52CFFD8E066547F30A3A9E3DF325EFFE +:100C800046FABCE7C627D61E8238EB5915384E7A8D +:100C90002FEEC9063FE3B567ECE87F1EF978CF4F2A +:100CA000309F64509D03FD1DA17FBAC6DE9F7FE982 +:100CB00018D899C5058B8BA19D2485EC0079BA6E57 +:100CC000B8FD1D3817A161409D0DF66771DD2EFB43 +:100CD000D7804F75BFB24F07FF63D85303E3999D89 +:100CE0001CD01D541EB30A73BE9701ED7889574777 +:100CF000BEF611E0ABC84310B85EF8931DF3735213 +:100D0000480C5F4F0FE7A6603CB28EE72BCC979B59 +:100D1000C03F3EED9A9E8271C83A96A760E6D762C0 +:100D2000C0E9A9405FCED49571E6EFDCBABF6C088C +:100D300040DCF7465B733C7E0738BF93FEBC7237DE +:100D4000F437E9C77617C0EBA4047998790E1E8FA3 +:100D5000735F5D7C44E019CA57BB3526EE47F1FE50 +:100D6000D71C3171976B6DFF4EC8D99E0D718AC02B +:100D7000FD504F198F8F94F3F84822BA4AC7895B08 +:100D80005039423E2D86B8C52DEC7A03BDF6D4E726 +:100D90004C35C42D88EE063B7B1AD6E1008F298B9B +:100DA0003638601DEE1C8B5F2492DFC5F97BEE3C6C +:100DB0001463EF7AAD7A36F8B93D37BE8D7ED2FF37 +:100DC0002EF91D91B3BA5FB5C1F959DB0A174F046B +:100DD000FB1723C7CF00FDD72AC766FE75CCCF4BC4 +:100DE000215A549E851C8F964B09FD5121DF89C6DF +:100DF00003CA813F2AE43C51B9D3F36F882BFFD15A +:100E00007A86C6D4832F38187E0938D8FC524E749F +:100E100017D8E17959EFA0DFFA0AB7C7237292D247 +:100E200077E7FDD4EE049FB7E37A79D74515CF591C +:100E3000EF7A6ED5CF60DEE819AE749DC179DCEF34 +:100E40005A42E9BA11FC87421C9F1E25264EF827FC +:100E500087F01F8C79BDFFE2FA63BA9FCDB39A9FEA +:100E6000F2FB163E4FDC94F35C32CCE7B7F07D1317 +:100E7000333AD5B8F3328710A430E3750B40FFC284 +:100E80007DC672DAC83EF4760BAC03DEF482E93D2F +:100E9000DF3F6DCE83FCBDC3B4CFC934DFDA2F8E04 +:100EA000EDF7FE12E6270A255EE079BEFFC2CF0D00 +:100EB0006CE7E706BE08FB59E9751FEC67A5CF5F35 +:100EC00082FDACF47E3FDFCF4AB2AFEE7C7871AEEC +:100ED00093CAF9D036396488878A7DDE1D706E1218 +:100EE000E001B7CACE9B7351B405F9281C2F5A1CD8 +:100EF0003EBB4AC755FD13C17C946F9DED4379D825 +:100F0000CEE759338E11E73A9AE952A37C54204E2A +:100F1000D53535D0DC54C8070CE466F6A45DDB6239 +:100F2000F0B4A631B968E57E5BF022093D2F45CBD0 +:100F30009FB848F66C6371B6A00CB803FEA2225CA1 +:100F40003F4010C7D5176F45FF0B7020E0323C675C +:100F50002C17F6A5BE8478AE7E78CEBD0CB7E8A37C +:100F600070DC08DF64E413C3E7C5AFE3F9CCF50335 +:100F7000F1E52D9AC7D4DC931FB3FFA07138D0C818 +:100F8000F1912BF67C04D52457E67AD28A251C975A +:100F900005053CDEC3D73FC4786E5EDB87F91EBD16 +:100FA000C5360FC417CC38D18CF3D562B65F4CB9B7 +:100FB0009DED5BADBF48303F1E0526337A0E9BCAC0 +:100FC000F3793B5C012FC4311BBC26DCCBCF912ACB +:100FD0002F30E27933DE57075413DE0FB2F9701366 +:100FE0001BCF93E709FA51CFEF64F181036E0F93A2 +:100FF0003F1242BFA7C26DB9759B07D6A9D83ECC98 +:10100000D26182F192D2010FEEABAE1824E1EB6710 +:10101000E079C36D789E90897F1510EA4D877A3C00 +:101020003D13219EA7902D708E4CA6BD45073D50C7 +:10103000DD6B71DF0DE4314C6072648FE5AF9A7C3B +:101040007C33A840058FAB89DFA79864DF8B7210D3 +:10105000337E63AE87A95CEEC4FA969FD7EF1F6418 +:10106000796D663948B30F613CBE7258C3F39ECDAB +:10107000E36E1ED74A2DF2FEE3B03FE362B2771370 +:101080008CB39D8DB3184755EE94611F0751D878E6 +:1010900089F52F73FCB5CCB43FCE4C97381761BDA2 +:1010A00066DA2FC6717C25A7AE2D69AFE17CDA4ADE +:1010B0006E6746E66D7B1E5FC762E7991E181C7B54 +:1010C0001DEB808B9DEF475C8BC7B17B9B98FFCD61 +:1010D000CF11282B21C98073CA060993AF472D2150 +:1010E000474E6CF99061FFB87370593D9EC7E87226 +:1010F00055439CAD8CB0F54A7D80E0FAA54EF6CA0A +:1011000081987E89751095C7C55489F54BF0C94CF7 +:10111000DF5DC3467FE82B41E3BE873B1F36EED33E +:10112000F8D2DA2CC3FBDA557986F7359E9B0DF79A +:101130005F741BCF09FA42C0784ED092E62A43F979 +:10114000454DC67382EEA8339E13D4A0DF69D25FEB +:10115000DD20DF5D52DF0FA1FF16C7EFF3C68A0760 +:10116000978FB76E1C64E706A11F1867BF8B795F66 +:10117000DB079AC00B463DE809FAD9B93A039E9DB0 +:101180007E7A7F8878157470F9F941358495AB7152 +:10119000B3F596EA8CF8FEBCB083E6F50A71FE5F03 +:1011A000D9601FCA41B9E9BCBF52F7BCB8E779BEE4 +:1011B000A771BC20CEBF4870CEC5A8F9FB6AFBC79B +:1011C000D799C6ED1F6FB794F41D76E624EEDFD5F0 +:1011D000F66B248F0BCE1DA4FCE8834793D97B8D3F +:1011E000EADB96B4023CE722C35E29A54C8CC63BE1 +:1011F000893EEBAAF2CEBA791C9FE84BAEEADCD26C +:101200000CBB87E9BFCEF0D116490FC13979E6751D +:101210005395CFA79322ECBC0B1F3FEF22690BD154 +:101220000B298B829504D7F183B9F6D06609F2C6F3 +:10123000D97ED2D61B2D38FFB40EE93BE0772DDAEC +:101240006E54703F638DAC6179359BCD4F3EC8B114 +:10125000877C89D7F466C3391DEE4D2ED013F52750 +:10126000EC7DA2FE744E569BE3F90BC5294CEE4F64 +:10127000294D8529281FBA9BAD4784F0DC33917F27 +:101280009B28EF96024717DA6D22F0011BBFEFC1D2 +:101290007A4A1CFDF5A730BFD8572885AC9047BACD +:1012A0009484AC63F8959D6E4BDC78C64D29DC5F69 +:1012B000BE7C05CFB353C5F97A59EC7CBD6ED3B96A +:1012C0009537F17E1E4AB1E3B53B670FDBA76A3A5B +:1012D0001FBDDEB392C4E25971CE8F1A790FE34C71 +:1012E00027C7395F44AC3F6DE7FB97AB2E5A9AE2B4 +:1012F000D1FF618A82743CAF59E3F6EF5B9CDECE8E +:10130000695E3C57B5F5490B9EA3EF73B74EC1FD1F +:10131000DD295F232CDEC5E8AFE77AEA73873693D1 +:10132000145CA77E1A7E27442DB1412C8F9CBCB142 +:1013300005CF85DD0E797339D1FEA58875EB9D87C4 +:10134000EAF28AD9F9F310EFA91D6079E50B4B7623 +:10135000F13C927EDCAF68FE9D92D2BA800EF3F231 +:10136000C2C6F066C43F5E8F1F7FB7847837E2EF56 +:10137000A88CDA57A921EEEA1C6672DFF9736F3781 +:10138000FE0E885BE046BDB126337A3E58F9D0A107 +:101390002DB004633E1FCC7CBE90F0CB5413AE1432 +:1013A000FE5803091D56A4D171E644FED863291CDA +:1013B0008FDC48FD313AFE77D9583EAD6FBD5402FF +:1013C0004E63D27A6932D8AF1FF1717AB33C80E7AD +:1013D000B4B426D8677769A45C18F73375E604DCE3 +:1013E000DE31CADF9422B37D7997D9F91EAA9DE533 +:1013F000718D5C79FE8B90EB594E1B962F7132BD2F +:10140000A8B8F242D658F367A92F40A03FD4BEC473 +:10141000CD0F7B3185ED4754C3EC9C0AB5EDBDEA99 +:1014200078FA2CF4709DDAB40FECC716696D2809B0 +:10143000EDC0D59F5F798BFCD9EDCD654D3F9C42CA +:10144000FBFF9AF5471ED08FCD01E3EF4B89EB6B85 +:101450005AC08EFC771F7280BF793E39701CE886B7 +:101460007837EC23EC8CBC68477B6AE2BBB99EB54D +:101470004EC677D5C3DE937FD33D8B63E224754E92 +:1014800089CF1FFA5B40D74CABFE36B4F34865FCFE +:1014900075C84CA5F21D785FA935FD01AE9D91DDA3 +:1014A000183F4E4ED6FF077C5FAEE8FF0ECFFFC958 +:1014B000AAF7333B5DED3A5310DDD790689C61E1AC +:1014C000E24C412CBF3E1B9F33EC4D436C9CF5809E +:1014D000768DE3ECA4D72FC1DC429FF797C75F6FEF +:1014E000FF119727AA6798AF20F6BDF8DC448F3725 +:1014F0007F89F274FC6527E6B5079B20AFF3E414FF +:101500000BD91D63E7C47905AD11E6175E7848DA9B +:10151000CDFC4282F73FFF7ACE6E58DF5D3A8DEB0D +:1015200031DF7771F743C6FDD0A2DD39A97CFCC756 +:10153000D1CF365E6E732AD3CF1FA4B278D855EBC5 +:101540006706AB47E8A9AAB0EB5D2E265FEFA7B20E +:10155000AB2D4D12F9EBD3810F540FFB53AE6D7CC5 +:101560009E5A92F7D9E543E883EA35E6E76DE3FA58 +:1015700022EC15A5B3D4C9EC4520F9DAE8CC2CFD52 +:101580001CE458EC3F901D92211EBEC0C9E3955C3F +:101590007F4F29FA42A093EAEF1D285F89F57789EA +:1015A00093E9EF179C46FD5DE664FAFB4527D3DF20 +:1015B00066E767D0DF0FB8FEF8791C9F1C37DA1D8D +:1015C0008A8BEF81FAEB1589EFE7267F9462FC8F17 +:1015D000FA8100D1D964F95C2C6EA0F855C7FD1BC7 +:1015E0006F1AEB7B8B8F17B563F743BD6F41FBB46D +:1015F0003F9BFF3BE31FF0F1C5387A29F828DB5AFF +:10160000DCB0FF35D13CB7C0C9E619BF8DEDAF20C6 +:10161000C768FB4586FE7C17F837D29F20F5ECE2C1 +:10162000F72718B73F7DC6FA62FAF308D42BFA53AE +:1016300071E5F898FAE813FAE80ACB306FFB94F8F2 +:10164000F342AF93CDDB1F3AF427A17EB37C89EB45 +:101650003F727D48B40FE69452F98FC0EF5285D99E +:1016600041A285FBE598FE9516B4887E072CB171E2 +:10167000B681F876F217CE11FBF00B94BF9D6CDFAC +:101680000E95EB5FC2FD5D135CCB709FD747CC6EB0 +:10169000BEF5C97A6B1A6DA739E389EFC1F51D67ED +:1016A0001AD2DB3294EB8461E82F67FB1F5B27B310 +:1016B00073D35A25E3F969EFF0F66EE2F6E91AF40E +:1016C000FBAD5CF9D3EBC767B50B943F2784FD4CAA +:1016D000CABB36BB34FB73687FE93482F8B87597B0 +:1016E0008AE76C09BDB90BC6969D77A0431EC55706 +:1016F000E9BD85DE0F81D30DF62A9B10F74C2C1720 +:1017000054F13C04FD3F983DD2CFC095DAA10FB80B +:101710001D1A802BB543673F8B1D3AEC6476A88D6C +:10172000CA501FC8A11262F9BDDC9FAAE77D2D2D0A +:10173000386C88DB097FAA7360B71684BCC102B617 +:101740001F3551BB61F037207125C1EF5689ABFFC2 +:10175000C91576700236535C077154F13B7A9DD0FF +:10176000BE06ED59F0777E5E2332AEC39BEB6B9DD8 +:10177000CAE7FD142ECF9357A27F65FE1DBD2A77C1 +:1017800068FB4C5A8FEFD8DD6C9FD5E5BBC9B22200 +:10179000C0270102E76DAAF40AF99B82EE69A9D776 +:1017A00093D8DF235689A4CC2B8CDA91AA08095749 +:1017B0001423BEC1FD5C508F87D7132882F93E4D9C +:1017C00081F5BED712FC1ED39372607A6A4CFD7EFF +:1017D00062C42B74FCAF4F9D8DE37F0394A3E35F42 +:1017E00090CAE6A11BE1F95927B37F4FCA4D85F096 +:1017F0003C90C196A069F9225E7E46EAE720279BCD +:1018000009FBFD5D90DFD8F5EADDDC3E744C0C94FD +:10181000433BD53F5FD433857EB2BABD05CF39AEE9 +:10182000B82EF2D129C8BFCD52713DB0F551E33C7D +:10183000F21CFFFE40AA88DF5D1B8EA0F6AF3E15AE +:10184000E963F62FE866BF33DA3239F731061FA9AC +:101850008399193DBFB6DAB508CFE7FAC60B39331D +:10186000E1BC2B95DBE779EE6E75058C6BA43F6EC2 +:10187000BEE95746EC20B5DE86792AFE392FF7A758 +:10188000325C4BF5F8AB7CFCEE023A5F9CA8075249 +:1018900067FFD7D9476187020AB337D46F0A82DF5F +:1018A000B4ECD2DA23304D3593276A607D83CAE5E4 +:1018B000DF019D5FB6EF3DC27E7A303805DAA5F2D2 +:1018C000F8702AB3477F9FCAECD17752993DFA87C7 +:1018D000CF2267F7A69231F1A7C0E1027F533BBF49 +:1018E0002D95E14F8FF3F3993776F2FA02CE6B9C88 +:1018F00037BEF439B44FF1C6CF505F391F12E1DB68 +:101900005F70B9FA65AA88FBE9BF04FE2FB4EBFF4C +:101910009C1A8B370A8FFD11F2E4A278A35BE6785C +:1019200043898D67FB28FEE27975F758E644F54454 +:101930008DC4C721F353477048078EF7768643E678 +:101940008FD0ED1D08811E4EE1FAFE3B668F5BD401 +:10195000FE7BF01CDC7446B794CEC6F128EFC7BB03 +:10196000524ADCF8E6B1687BC7B0BDF5AC3DD97131 +:101970002BFBDD0F6157AC12B623E2C3F3D3D9774B +:10198000A29D79FC2A70AAB99DDF46DBF92DB6F33A +:1019900090D807ACBF05F7BE285FC3B17C05FB62DA +:1019A0009913C34F8EEB12E1B818FEBD8776A08D58 +:1019B000B533C2BF407C3BBBCC250B3919481D4316 +:1019C0003ECE71F9381F958FF35C3E3E4C457CC28C +:1019D000C6E1AE09C6FDE5C35CAF1EE17C12E3655E +:1019E000A6BF95BF1FE187E7D873B1B8D65790B6A9 +:1019F000AC19E2966DB2D7E2192D6FF45F3EE0DDCF +:101A0000FF05CC52B1EF0080000000001F8B0800E2 +:101A100000000000000BE57D0B6014D5B9F0999D26 +:101A2000D9D94DB29B4CDE1B48C226800D1A7009D5 +:101A30002106083A79F20A10111014617985F04AEA +:101A40002262EBF36731213CD5E8556B5BB40B8226 +:101A5000628B3660AA8801372088EFD02A68F5B6F5 +:101A600041ACA0225950EBDADAF29FEF3B67B23378 +:101A70009B5DC0DAF67AFF3FDEDEC339739EDFFB83 +:101A8000FBCE37B34584FDC927BD923B9790B17E0D +:101A9000A27A6D849C83BFAB82A555110849266448 +:101AA000995C655586D20165F5CEAA8184B4977498 +:101AB0002EA90AD3FFB604DA9FF69B9EBEA92CD9A5 +:101AC00049FB7B687B0A21C31DF4DF2221D7D5B4F3 +:101AD0008B6EDDB8E99F7E3C4F0D33CF4F124CB873 +:101AE0006EC30CD721673E9DC661726D253DFB35E7 +:101AF000C7CBB8DEA86CAF1447FBBD7986289B69BD +:101B0000BFEB260BAA979EAB829FCB96C0CE91A52A +:101B100048D85FE5FB1C2577CE0B778E7CFE7CB426 +:101B200093A82D749ED10A517786E95708FB8479D2 +:101B3000A2C3CF338DCF3386B079429FCFE0FB1A5B +:101B400055127EFC083EFF34C78EF20402FBD964B6 +:101B500006F8E599D5610A1DB736021E52A4929186 +:101B600080AF280A3A731E2133E958139D6016E0AE +:101B70009C960F8AEE5278EEA6E070E40125787A02 +:101B8000015E4B6C6A19B44747ABE530FF4849AD7D +:101B900080F297667514E29FF80829206402A79FD7 +:101BA00009569B4F8CA5FF28349FEAB4B2B673D96F +:101BB000F0FF67281F5F4688407CC2B9CBA0EE15B6 +:101BC00061FEE1CE43EF0AB4FF706DDC4929645C2D +:101BD000BAF2710CAF8BB82F84CF6EF34F9D365392 +:101BE000CF736AE56E9BDB0A70381DED9E09FB6CB6 +:101BF000706CB63929BC5F75B7585DB4FD641C4183 +:101C00003876C5A86E7CBE9BD4B4D0763146A86F1A +:101C1000D1C16FBEC2E05DAD30BCBD25A9D570FE9F +:101C2000095675018C9B9C49F144E79D95D8B95C98 +:101C30000FF77A8EA7859C6E67CAAC5FE83EABF95A +:101C4000F32249F0C4C09E6C873E12813F48F75F83 +:101C50003F13AD8F857F51FE293AA94C9D96447163 +:101C6000B6467499685DCE11C2F2E99D7CBF944F6F +:101C7000EF84FD1227E5533BA50F393C7D7CC5FB66 +:101C80009747A0CB3C7E9E32781E66FCA59CAECBCF +:101C900092DA4542C717717E0BED373741C47E0D8E +:101CA0002E323ADC3C0F04E5CB03485F0ADB779E1B +:101CB000B9EA21A8CF500E97C7D3E6E2BB93A6920C +:101CC0002480878958B2104E5642E1247138D16D74 +:101CD00012A82FB3B2BA14BD84C4D132D3E15D3F90 +:101CE00008E0D768763969FDC3931F8A84D2D9D6B4 +:101CF00007CE0A84CA8BDD7E4212B3601E19668449 +:101D00003FD339A1E77CF49953D2D6A3A0B9F224EA +:101D1000512D947EAF2CF44F22B186F1E41C9DCF5F +:101D2000E6EFF008803F2BF1C45C8E64FC76BF14B4 +:101D30009C15E74BA5EBC279E42F8917CEA33ADCBB +:101D400095641021F1FECE5FD461BBCD350ACF453D +:101D50006CC06FC1732E43FED3F625DB3A1FBB97D1 +:101D6000F66FFB2ADA75179CDB5FF109DB0FF1D800 +:101D700081AFC54A17C877422CB83F13FD0FF86CE6 +:101D80006480EE3787EF1716C9D7ED9FF43CCF83F9 +:101D900062D521C0C72C2B5163F3503EBC02F5BE67 +:101DA00066DA81C2B14911BC1EDAAFE981796BB242 +:101DB000405E6F905CFD09D039D925503A1F41D75C +:101DC000BD85CA1DB990D8145A971DECFC4D7727D4 +:101DD0006D8A11E0B94465212DFDBE6F040A875854 +:101DE0004775A542CF21F3F102051C8C179C0A9977 +:101DF000910774DB2112940F0E8487C63FEA8F8807 +:101E0000F0B115550D01FA2A9388C74AFB0B0E361F +:101E1000EF95C42F92BE8007AA086859425C58DE2D +:101E20002BBA3F06BEB1CA14AF74FF5693D5BB524E +:101E300000FC55BD3E1AE15EA67C9C13946791E4BC +:101E40001040EE630DAEE2F7977BE5CBC3F3D5DF31 +:101E5000827CF3372697995E9E9CCDE4CE017BE78A +:101E60000C3DDFAF5298DC59C5C71189F1D9325901 +:101E700035C59F87CFD7F2719782F2017D4CC2F3AF +:101E8000714B3C930793EFF236F5A2F09B9020B88C +:101E9000400F976F9F2DF57606FBA5727DA7A4A82E +:101EA000F1F130DF6ED7496F12681F19F57BD37BD4 +:101EB000641ACC3F9BCBCF009FF72FF16C1FE9BC7E +:101EC0007E4CB04F0B0797CCF86EB864C2B9889BB4 +:101ED000C1458C19ECF7D175486FBE8E59C075DAC3 +:101EE000B3997CCCE6FBD2D6E9C3E51F95FB97C03E +:101EF0003E27677AD3A1DFAB66B6BFD0750706D79A +:101F00001D88EB2E61EB8E05390FFCEF3CF412C8F7 +:101F1000F9224EA763FD6E02760FF0B0A92028EFDC +:101F200065A74FACA7ED4511E4FCF0E03AC3719D05 +:101F30007A86C73D29EA08D827B50B8AA0BD3D5B44 +:101F40004179F9662F13D94CF972765AF63D20364D +:101F5000B57976F273B6673539E6507CC97EE2B260 +:101F6000209DD7A0DC2BE2F2A561B79BC0734F2F59 +:101F70002A3375E365FF1C2BB1E151FE714EEB4F27 +:101F8000F9A8C99F1DE70E8317AD5CBF828922E2C5 +:101F90005C8AE396F171A1FD6C0FEE8B81F93740FD +:101FA000FF1F113291EB1B7A60DCDF58CE3B0DFE38 +:101FB000CD319DB4DFEE9CB986FDE073CA474D3943 +:101FC0008FC580BDD49641F500C8A9574494934D60 +:101FD0007686C7A6B46AA2B7474B1D3EF16398E761 +:101FE000DBB9642AC55F91C34D2EA1F05DC7F751DF +:101FF000E4AAF60849D8FE6C149D6779FC250847C9 +:1020000039C74D2A72012E5E524DC7CB8A4F74D10B +:102010007AA99FF8AECA87FE54CE0B6C3EA75D3FEF +:102020000F698179E45C460FB2BF8500FC769F3C66 +:102030003F1C63724C06F9ADF125B5EB56001D94BB +:10204000295797C5D3F9176DCFCA13E9FC158E76BA +:10205000794E2ECA6D0FD0C7CE647565FCFFA03DCA +:10206000378D78CD80F751994C0F4CA815BC9B2922 +:102070007C9A42EC849FC6333E2C0CCABB9FE1BEC7 +:102080000B353B41FD39D4CF63073F0AF0388F1D34 +:10209000BC059E87B183B7423B85D7E3F1CC0E7E6A +:1020A00002D6A176F0B6EF03B7090A93A3D40EDDEA +:1020B00001F3C6837103F6D11F983D1ABAFFDBF80E +:1020C000F9D7D0B376005D4A5E89D139E3D3E19C7C +:1020D0004FC79EA4FC92DB93FEDB28FD7B28FD9D71 +:1020E000A576939815999E7C17C997C50F32BE6F38 +:1020F00070EC43BE7B91F3451B5FBF2D47AC047C66 +:10210000BE4A4445147ACED794E176805C0FE53F11 +:10211000F55B233D973ABC1BF2806F0ECD75C1B6BF +:1021200042F951A665F5C0E0BE8F031F0ED5C92741 +:102130002248C88F17E04398C73D10EC8C7849CDF2 +:10214000053E62EB7A0E89A82722F111A59B5380E8 +:10215000BF6EB800B075FBA774F3393CA77C76FA64 +:10216000FBD0CB1A4E1FD40FF91AE6EB1FCFE8674E +:102170007604FFE21FF1DD7EC03FA03F99C1F4501D +:1021800066BC938D234932E81755CCC804F942E761 +:102190003525D0F6B7B87F1469DEA8846EFE8B4A69 +:1021A00080F3DCC2E63D0446F6D09EF38E4AA0F6EC +:1021B000479879D2B81CBF2E82BF90C5FD1292DB22 +:1021C0006D9FA4C07A599C6F7627AB8E041DDF14D7 +:1021D00071BBE565C1A89773BAFD7DC63F4909ACDF +:1021E0003F99D73D6F56820E9E9A1D309BCB076D4F +:1021F0009EFE9CFF9C090A1B5FC3C6C7439D8EAB16 +:10220000E0FE13854B2ECC47ACECF985FCA27B1489 +:1022100019C7CFE5FB12E2154DBF215C4747F2BB62 +:1022200082727038E2C1C5FA5FAA100DEF23711FE8 +:10223000956C1F850AC37B68FC20127E34F8276BDF +:10224000E7CD61F3134F37DC46EBE92512DCDE8A7C +:1022500063F6C5280E27D2C8E7099107774B1D56AC +:1022600025CC39AF8D771AF8D9EE32CA8748F19468 +:10227000BC207C66221CF2D9BE23C5570AF87947D8 +:1022800070FB968E9B8F70B5B1FDDEA374B7D7E05F +:102290007CE96CBEFA20BC1763BB83F58FE4F7D7EB +:1022A000F37D5527748F5B86EB24B171A1F104ADEA +:1022B0005CC2F7B73038EE565CAF1F1B971CDCC70B +:1022C0001DD83E9AB57FDFF85B32DFEF4F82EBAE71 +:1022D000C1FDAAECFC81B86EB8ACC7F622B66E247C +:1022E000F9118863E768E270BE12FC623A477C80AD +:1022F000E44849E03545BB46D12EA901D507FAA3EC +:10230000E44BD90972BA5CB479042A8F25A715FD6C +:10231000E42889A8E0D7B67FF56347672ED67DA06D +:10232000D75747155BC1EF5C9325B9401F16DF27D0 +:1023300031FFFA9409E57D85B804E7D9A76876EE00 +:102340008D063FDAA9382BA3601F56913899FF5F9D +:10235000399E3EBF8ACBEB7DD64413CC372283C552 +:102360000BAE7256A3BF4EBE657EB44AFF63F25BEE +:1023700045BD2CF371527A3D11B034FADB32D9707D +:10238000461C847A01EDA8117EA3FF2D3B2B4EC085 +:10239000FC32D18DA3EB3E9F604F427BAA1FE97FA9 +:1023A0008EF28F25472016EA5F944BEE3D808731F1 +:1023B000CE6AA5849EC792EEB6821CEE67F6F586BD +:1023C000784263BAECF2001B3E5066CD027FAB99B7 +:1023D000FAE7080735E1EA81413C598A540274481A +:1023E0007182FCD55DDA589990C8F0F8498205CB26 +:1023F000125ED79E87E27D486234E37F62F57C946B +:102400000372422071940E9792CE4CA0C7E43426FA +:102410009F6A4D9D2950EF22FE94245A36344BA3D7 +:10242000C3F93F1B79FC6CAD29BCBDF44BF3980F8D +:10243000000E12C40D2EC7B880DBD237183FD0EC87 +:10244000552D8E10C96EBD57ACFA18E61114DF3742 +:10245000D0BFA7FDEBC17D48E94C4E6BA5B68F9967 +:10246000898C7F1C895684CFDE3B4AC91C27E2E950 +:102470002CF029C5D3A12B002A59F314C0D32B5912 +:102480000FF583B89435EB8124E0CFD184D9A7E54B +:10249000748C83960FD9DCDF24E8E4E1987EB3D115 +:1024A0006E2ACAAC477B6A7504BFF4C77C1F12A7AB +:1024B00093129BDB943814E25FCBAC305E52AAA23D +:1024C000A1DC1B988425B57BA544DA7F753AAB5F08 +:1024D000080FEF72F91069FFA3402F40BC26BDFB27 +:1024E0001C09303F7DEE91F382E7D0ED2F25DCFE15 +:1024F000CC894C1F69FB92FA71BACC31D2DD784E8F +:102500008F39899ABF78D17477E462E82EF4BC637E +:10251000B2968F1E4082FBD7CEAB9D9F9ED705E71C +:102520002D97D8F9B72A6E15A6A0701E0CED3DCEDA +:10253000650DAFF733124DDFF53C0F25F4BDF8F311 +:102540007C8779A7267E07381D18A93A409E342635 +:1025500053FAA4786A1458A9F58FE6786AE174FAF8 +:102560005DE444FFEF70BE6287F012E8C3ABDCC7E6 +:102570004A6199B2A2C1A076801FE701BD95E4DE51 +:1025800027CDA1F5A63BE6A2FC3C30B21EF7BDDA92 +:102590006EDCAF5626707C1465AAC87F8D9CFFCA7E +:1025A00009F323B57E6DFC5CA1FC113A5F285F3F07 +:1025B00064536F06FA484864FA32E8FF75887AFF78 +:1025C000AF84EBAF91D69B0CF18F91DCFF5BFD6587 +:1025D000B6CD430F7A96EAB57F89FFF70D7D027E6F +:1025E000527A8955EFFF355A4BB17D75863AFAF22A +:1025F00024D0C7A2EB2E82F0437FD02388CAD630E6 +:10260000FEE0EA0CD977157D6E51C8E3B0BF52AA3F +:102610002F21FE62515472C9C09E7EE13E6B29811A +:10262000B8C959853C0BFED885CEF378A2D12F943A +:10263000C02FE4F3A35FA8D4934E8CF79412B06B31 +:10264000A0DD3910E48E4ADC76D023D42FD4C9A77C +:10265000B3D69B90DF43D7A372EB69A0A34685F165 +:1026600071A83F28723ED7E46C283D943B18DD44A6 +:10267000D1AD9B99DC782E31B9275D7C77F934AFE9 +:102680000C5C806BC9CA03E0AA4D09F825707996E5 +:10269000273AB15F956D47233CD7E60FC50F3DB98B +:1026A0000AF174B06758FC86DA6BD48E32537B6DB6 +:1026B0009D105C7F358777247CAC067D1D868FDE80 +:1026C000EE966BA171A29B8CF72F8A872415B0B868 +:1026D0003E09037F91DB496B28BFC0FDCD6AB3CBB8 +:1026E000A1009D6614BDEB067F3E43C6FB0822D5C4 +:1026F0003BAEB6F73CE71A889F85D9DF17890908F2 +:10270000576BBAC9609F1172A7C17E8C746EC2F7F5 +:1027100065E6E712009E397A78869CBB4CC17383CC +:10272000590FF3C69A5CC447F9223693B85060C576 +:102730009A300EABF1B9C2F95C930736858DAB4C7C +:10274000EACBEEF7449B5FA4E75F9F44ED693A4F05 +:1027500083BA0FF5AA363E8E9FDF3692C51B6D7683 +:102760009FA28481C3BD9CCF239DB35995E2CBE842 +:10277000FEEE5598FD2D8D345579311EC5E2B50A12 +:10278000879D589C6F05BB7D54523C8B7BA93B15A4 +:102790007DDC4AE4FB89B1D3FD9C474EAE0DD94F99 +:1027A000544E6719EC5FCA529578DDFE4B9234BDEA +:1027B000D281FC1D69BEBBB99C8FEAE7C2F8ADD5DA +:1027C000E6F2C1BD56945A5D0062313AC745E6EA69 +:1027D000DAA3D58221161D1D3667C861EF236EE787 +:1027E000EBDB25B50AC6D91589C03D999DDBCB9198 +:1027F000E68DB48F0BAD372D89E9D31EEB39C3DBE2 +:10280000157D9218FF49237756819C260325D23FD8 +:102810008C9E484862F22556EE7482BF4EE9D11D67 +:102820006E3E9224737EFE37F187667717B71ECA15 +:10283000A6FB6DB0492E01E457E1C90EA70E3E5428 +:10284000AFCF4AD2C97DD1E646F9263AD9BDFB6859 +:102850000BF3B70F8C34DE93CDE7F8FA80C33192D7 +:102860005C28E2F0F8779DF3BBE2AF2489C97D0DC7 +:102870002ECD001702FC757F6343187949E1D39090 +:1028800094FCDDE1B396C3E5E90BC067D07F183E49 +:1028900017E2EB209F79C9F130706CB0CB69730DF2 +:1028A000FCDF8C7648B87ED5BAF346E2438D3E20F5 +:1028B0007703E1D0AC1AE2027292A783F995371B35 +:1028C000F59CB8C4C5E533F996C22D9EF78FB711B4 +:1028D0005F4C6C707EB9CC184F684BE27181281246 +:1028E00005F039EB9A24409E82C53463B0920D4BBB +:1028F000340BA02752609E4184DCC7E567A81E4CBC +:1029000056999FDC9BD40B4CAFA4E3FE92F83E4259 +:10291000F5601AF56B201E0347047FBA37AD5BC123 +:1029200006212ADE830B1E13FACB0EE21560FE741D +:10293000D289651F4845A0F367910EA11FC5DF7DB1 +:10294000E5D583417EBF13728E0BD9A35AA9D91F37 +:102950006BFF43F0FEF47F2FBC5796EAE02D267FF5 +:102960003F78CFE77227349E5704F1BC2C88E7F9F3 +:10297000F6039FCADF32FBA3FDEF32C6F71AB35846 +:102980003CAF5CAC7C18EF419D32BA1F524EE77AE7 +:10299000C873D2EC4ED4797D83713FEB99FB2588C7 +:1029A000A310E924C209EF869C28CF329351DE3070 +:1029B0003BE22ABE7F396B9E15EEBD83FE934F64CA +:1029C000F606B397644E07458E12F45F1ABF3DBFFB +:1029D000DD71B17ED25EE900DE5F6BFE51837F0E5A +:1029E000FA4BA1E37C92EF7D38BFCF2F3B21DFA4D0 +:1029F0008DDF8BB59D396888D386FA419A5D751550 +:102A0000DF7FA9DF7DE872B8DF52E61016DF647061 +:102A100090F93A8D8EB3780FFEE2B726F4B7CE72F6 +:102A20007FAB08FC2C3BF377AAED3DCF392139BCB5 +:102A3000FF04E320AFAE54F18960CF69FE13B43BCD +:102A4000ED3DFDA7D116FF6BB0BF09AF89981712F6 +:102A500009BEA17E53A8FE999ECCF4CE4DC9DCAE32 +:102A60000B81A716EF0BBD976ED2F84FF2087AFED6 +:102A70000F5D5FDE3706F74F145D3C363B184F1491 +:102A8000540FB9252F183F0C13375C0A74A8C50DD5 +:102A9000353DA6D1B185F6B5E23D73F878625BD6D7 +:102AA000C1BECC2F7C2911F8B35C6171236D7FD43A +:102AB0002FBC2D59878F223FD3DB96FF53DFB9926E +:102AC000C297241017F30FEA9D565AAF5048E23AC6 +:102AD000E4331BE669152509C877922F0AEB15A781 +:102AE0005CDE285AB7EC7B45149360BD39244A0854 +:102AF000D28F96D7D1E8FF703DE0EFEC29C9753E43 +:102B0000BFBB028268063F293A884F946F0986FA54 +:102B10004392FBA164B4177B05C789900F966DC8DB +:102B20003F7B46527F0A709D6A551FC6FE3F3CBCE4 +:102B30006F4FC678F1C17F0AEFC175983E009B8D3B +:102B4000A4E9D6B3D1C661B08E93DD176A71E9E509 +:102B500004EF63B601CE20CEF239F1429CE505F3D5 +:102B6000CB22E8A3263ECF70D2EC94FBB2FD42BF4D +:102B700027B73A36015DFC2E390BD77FC1E6DE3030 +:102B800098B61FDA220D86B84D83F3192BE4CFEEE9 +:102B9000DBDA94DEA9E3BF434FBAFB84F30FB592AF +:102BA000FEC5990AF15CB1AC54459303DB45A8F727 +:102BB000B0CFB6B42AB0CE935BADD3C2C535C41482 +:102BC000C6EFC3B730BB76748EC905E2AD8878A472 +:102BD00004B88F7111978F36C40CDCD9813670968A +:102BE00088F71AB4BE3F96D66386AAE81F0C18B8B9 +:102BF00013C70FF8BCC4C5F2283DB63C5A5F9F53BB +:102C000032741DADA747BB3F06FAA27AA659427D92 +:102C1000DA1203790031032725AFA3B51881548553 +:102C2000B373FF9ACCECEF27CD1A5C25CC83DCB7CD +:102C30005546FE3A9426E2FD1385DB12A8FF252DAA +:102C400086504A2465AAA70CE0584E5A1AC09F2AFB +:102C5000735EFD522CF927E097BF5301FE5F1FC141 +:102C60000EFF1DDF1F0A114A3F07B7345E47C2E45B +:102C7000516B74F85C8C2AA5D0FE6BF9BD2E714C9B +:102C800042FA898CEFBB98BFD9E26B88A6701CBE54 +:102C9000BDB9977EFE2310744DEE896FC87F2697CD +:102CA00043FEAD1BF3691B4E9A107EAFE60A5E81B0 +:102CB000C2E7608E486D36BAAB7E566F7F5ADFC072 +:102CC000E9B872FBE1C65EC0C22949B8EEAB398FE4 +:102CD00059597EEBC5C7AF87503E5804F953141FAE +:102CE000A39468AF93E26B314C41EB2315ABD7470C +:102CF000D76BB77794C6D1255E48165C9B815E7210 +:102D00008802F2035D1013439442EB2032909E92AE +:102D100008E673AD2FC8DD0C71B175E9CE16C83762 +:102D2000DC33D08AF966A1F9C47B84FA97E2212EBC +:102D3000152FA0BC3E98F33BBCA73B986E2140AF3B +:102D400098F04B9F3726303E8DC937DA9FE52959D9 +:102D5000DCCF261E4B41705F31FDAC6A1425A49771 +:102D6000E3D9F843FD042FD0DB2127970FF4BC5B98 +:102D7000C120929AA5A90323E3F595FEA39C9A5D31 +:102D80002C68E734F53CC70B82774D369C63003DD9 +:102D900007ADDB73045CDFAEACBB916059B800EEED +:102DA0003143F7BF2285F9473225BB1C906F2D6B4D +:102DB000C6E8F363E4C21B27D862318F09EDCAD499 +:102DC0001C01CF33E624BBCFED919FAD10B76CC093 +:102DD0000FB53A5282F3C57CF9EC4F20FF775CA126 +:102DE000E08B82FDF0FC66FA7FEDA05FE47EB359D4 +:102DF000FE75CE263CCFD842B30BEE72C6DABCCD00 +:102E000025B4FECA2712C6B3C7F51B85F9D5A1EBB9 +:102E1000AF53886F3485EF2BB912C23BEA92C7706B +:102E20009E37734D286FC6413E36E42FEBF3AA510F +:102E30001F1AF3B9C7891FA8C5D0EC62FC4A244FFA +:102E40002F90EF131C46F8D94F1AEF8B2BF32D86DA +:102E5000FAB85C39440F7B10DE2F6730BA7879807E +:102E6000E0DD9C15A4B3B12713BC4067F02716180A +:102E7000E06838678C5F56017E87063CF15F704FD3 +:102E800012E35C7D23DE8373F86B7412C3F16E4F23 +:102E90007FEE27A0A734F887D2C1C5E3FFEAAA6274 +:102EA000C07FBE767F1F82FF107C630C523B47DFE2 +:102EB0009E78C7F5B37AE25BA3831EE7BEBB754D70 +:102EC00036C5EBAB76FA00F0BC49F6DE2504F174AA +:102ED00041BCF62B46BA59A734DB40EE475D72DCA5 +:102EE00006FE814617446CCBD7DBFBFF2A7C976C30 +:102EF000109833E912BC10D77B0B1E0D0BAEF352AA +:102F00004A77BECC4B20F74915CBE36850F3D87B0A +:102F100057F94C9F86CA873FA4B0F73ADACD2FA75E +:102F20009F2F4FB5D2E626703FD600F976F47CF29B +:102F300086D9F046039127CF46794936082C0FA150 +:102F4000E8F728DFE739BCAB8430EBA12583FB74BD +:102F500032BBBF2811FB93695A5E52D507B8FFC92F +:102F6000AC7EB1FB7AE35FB4AFA3945688CEFF9CEE +:102F7000C8E3F29ADD3DC1C6F20E271489888F3767 +:102F8000B7085ECC8FA4FD3C944E1671B29DC8ED7F +:102F9000C0B385CF340D76823DA81AEC4EA1A81D92 +:102FA000EDBEB842A33F18AF461BF09F383AC15060 +:102FB0004FAEEA65E89F3A2DDB1857705F6A78DEFE +:102FC000BB26CF50CFA81F6EE8DFE79612433DCB5C +:102FD00033D6D0BFEF9A49867AFFE6EB0CFD7FF43B +:102FE000F01CC3F301DE4586E7976D5B66A80F6CA6 +:102FF000B9CDD0FFF25D77199E0FF6AD333C1F724D +:10300000E87E437D68C7CF0DFDAF7877B3E1F9B0B7 +:10301000CE5F199E8F38B9D3501FE9DF6DE87F5519 +:10302000609FA15E4C5E33F42FB5FEDE502F57DE5D +:1030300037F41FE5386E783EC6F999E1B94607E3E3 +:1030400072BE30B48F77FD2DE43D9D2A16E780785F +:10305000405F78D48C65346961F73AA403CB850569 +:10306000EEE254E08F473D4D9090D4E0F1FF11AE79 +:10307000A6DF2CEC1BC7EC2795E8E5A7969F4AFD39 +:10308000164F142585D800A5DB2194EE0202964A3E +:10309000804AD64488F74461991048C4F6C4403C3D +:1030A000964981DED89E1C48C33225D017CBD44028 +:1030B00016968EC06558A6050660D92B3004C7F554 +:1030C0000E0CC6323D3002DB3302C3B0CC0C94622E +:1030D0007B9F403196CEC0382CB30263B0CC0E5CDF +:1030E00083FDFA06AEC6B25FE07A6CEF1F988EE5FC +:1030F0002581B958FE28301BCB9CC0622C070416D2 +:10310000627969E0261C7759E0462C7303B763FBAC +:10311000C0C0AD580E0A34607979602596AEC07A89 +:10312000EC3738B016CBBCC07F61FB90C07D58E651 +:10313000077E81ED43033FC3B220F0189657043653 +:10314000615918F83596C3024F62393CF00C8E1B5A +:1031500011D8816551E0056C1F19781ECB2B03FB3C +:10316000B1FDAA403B966AE0356C2F0EBC826549E2 +:10317000E0F7D85E1A388C6559E07D6C2F0FBC875C +:103180006545E03896A302C7B01C1DF80CCB318111 +:103190004FB01C1BF802C78D0B9CC1B232F0376CCC +:1031A0001F1FF806CB6E7917315FD96D427F96FBF2 +:1031B000A991FD050FCA49337F2F0E72AB31FFBFB6 +:1031C0005EF062BC30A9F325A89B0B2D182FBC81A3 +:1031D000F8F13D81FF269D7690A7EDC34EA443BC38 +:1031E000E9CD645F863EDFC1CCE300E5E22909FC5E +:1031F000D50949FB92419FDE409B21CF88A8E7304B +:103200000F7202CF83BC41A20E16DDEA61986118ED +:10321000F6F359687D462551F368FFA661168CEBDD +:1032200037E5513F88967767B17CD91DA94C5FFE81 +:103230008A97BB52991DEB2960F7FB336EECCFF8F0 +:10324000A92CF1027E1383C3DF07F23C5B9B3F1383 +:10325000F3632F72DC67297C1CEFDF9C5AD5960A3A +:10326000FB282139F5B6603FDAFE6284F67DE1DAAB +:10327000F799183E3C4744EE2754C54D3A8F9FF0CE +:10328000E68A8E4B5FEA1FACBF15C10F256425EEA1 +:103290003776DF2795D7527D38B1507451C9413EFA +:1032A00058B16BE447FDD9BA909FE92911317E31BD +:1032B000A3E8F081445A9FB13C1EF3EEBBF7556280 +:1032C000C6E7131C472E7D891EFD86FAE7477E64FC +:1032D000888BBAD1EEBA89D32851CD7FEDD49E2305 +:1032E000BDB2B8EF4DB0B813E49F19E7ED50CDDE95 +:1032F000F3E5C710D5425403DD3378AD87FD83EF86 +:103300004FAC26583796F7A17045BDEF8995BD0D96 +:103310000238EFCE38A0BB985C3F395F7C19E029BA +:1033200061A242A70DEC9848F04C7030FA8B2B52FA +:103330001D1E8A9FC6BF8B78CFB53FBE4001FABF26 +:10334000C7D62F15F823D9C1E2278DEDEF617C2B6D +:103350002EDF4F3C36767FEEB4401CDF8AE5AA159F +:103360002E2C1B571462B92EFD7E2BC44BC464094E +:1033700032814954C63C8C0769EB9BE3E7588B5D6F +:10338000946C1D722584904488330C87F736E5CA07 +:1033900095FD08F92695E57DBFE9F8C806FCF04DD6 +:1033A000AA13EBA289DD1BC7E4FB54C84B88712923 +:1033B000259233D88E7F49D8BE19FC913749E786CC +:1033C0006B008E2A7B1FA381BF6FDA50DC9FC35531 +:1033D0001B1782F7103C8BB20BEFADC568DA3F3795 +:1033E000325E0738E2719F405F12A52F3FDF3751F1 +:1033F000634C309F86DFB3921FF3A91A84F079974C +:1034000043387E1A155539DF3D0A51A4BFEAE5A9B4 +:103410002D7757083DDB50BE621DF2B9B8BCDA9F6C +:10342000AA0E73D0F9C75CC9F3EBD313500ED0F6D4 +:1034300001C3219FCE44153AC02D41467EA140884C +:10344000833C5F6275C64D3A4F1EC4DA150E553285 +:10345000C3FD80330EE0B5969F0FDE50D6CB817F43 +:1034600057BFA0BCF022DD86F66FD1E4408215E59F +:1034700093C8E1A18D5BE860F2D8945D35D33194B7 +:103480008D033EA27537C08B58697D20D6E7E07367 +:10349000A5BB3E0FEB0ED61F13692E420ED3718BC8 +:1034A000719CD43DCF52ACDBBAD7ADC37593BAEBA8 +:1034B00037623D9DF5BFD875B4B2FBFCBF6372F2B5 +:1034C0004B498D4BA0F43CF696B955A00AC6DFB225 +:1034D000B0AA8CEAEF3FAE785705B9F40195278D75 +:1034E000B41C3B607F22F839E387EE8F71EAE8F580 +:1034F000061ED76CBBC53C1AF45DD1AD62D51684EF +:10350000F74AC3BDCF1A8799C79BD83E664884DC6B +:103510009100F2F7F0A58D06BF93F3A1C2DABAF7D6 +:103520007B9B80FBFDA09EC9DB0F960B286FBBF930 +:10353000349E703FDE970C709AB95C27B74918B873 +:10354000D45B88DB20D723C18790BFD2FA97B67EA1 +:103550001897A5969AB52A8C3ED3E014090F3744E4 +:1035600088FF6A70D2E0ADB5FFE98E210AB3ABBD2A +:103570000638CEBA7328C62B6FE0F17A126FE5FCDD +:10358000C9FACDA0EBECCC457A7202BD433D6C9EEE +:103590000D5F7706FDD71D79178507CC97FFA0FE35 +:1035A00080DDADBBFF0C857B443A8C00EF3A0BC14C +:1035B000F72AFC5BED2C9E94340DE7ADE1EB92A471 +:1035C00019B88F1ABECE4B7B637C26B887DA6ADFC8 +:1035D0000CFE705789276522E06BB319F3DAEEDA37 +:1035E000BBFEC82FE03E789319EF4E167EF14001E6 +:1035F000DCCB76713D4615413B7C47C14DB43F5510 +:1036000080F91710367F97760FB2350EE17AB26CDB +:103610004BD3085A76EE595A09F197137BC71F040A +:10362000FF79613491D2C0DEABDF21233C3CE68FD1 +:103630008C768214AC8B3DEB0BA0AE8B232DF49AD1 +:103640008375FABFC5DB8C753DBC4C7A7839CB8C61 +:10365000F072961BE025BC68F7893A78959D792928 +:1036600011F4FB518713E7AB39D39802F0A9D9B312 +:1036700016CBC5DBA23C1FE9D65DDA126FA8D7EDE9 +:103680004AF3E8F5CBD9438FC5C2F9973944CF4700 +:10369000547E9C5AA136001D9F5E31BA414FCF4BDC +:1036A0005BB23C36C33CC6FAD96601ED14D0339305 +:1036B000CF632F2E73C8B8CEA7DB98DFF9E90AAB2A +:1036C00007D639B542F1B0751D1E664F31782DB958 +:1036D00025C6F3D190E0FE22CDFBAFDE1F21ADE485 +:1036E000B895E0BB3BE7CEA3BF23F28BF4A58CF2E9 +:1036F000BDCDFC17A01B2BFDDF398CA74A58D7E6A0 +:10370000AD6B113D90574CC876C37A749CF3639DA2 +:103710005D10593F18BF373102626228A7D97D88F2 +:103720001BEE43E87C5D926D0DC413B4FB903A58D8 +:1037300088F65D6AED94DDB4E9F3D6BEE77DDF9CE3 +:10374000E2290BF4738DB55906A55BD332A00CF8B2 +:10375000E9F3D68614B067178B677F1CEEBDAF29DF +:10376000699C6FBD66BFD16FF46AFBCC920C7C463E +:103770006CDDE7A6F55311DEF399C5E7ADDD7EB844 +:103780006204DD7FEDAE3332EC2339CD3D2B2D3994 +:10379000787E81DF072DDA760CF9FCA4D973C9EDA8 +:1037A000E7B3F37BECD3E630E41F7A4807F0E79CFD +:1037B00042A231ECB5EF5379F3C96B6602F788E4A6 +:1037C0005BDA8B3ECFE44FE791AA5880D79CD6C5F1 +:1037D000287F3E7976DC419687D45C00F4F139315C +:1037E000E1FBEE9F93DFC50ED1C16F5D9A9647C98D +:1037F000BE73A3E5B9D00DA6619E7A4D5307BC3FB9 +:1038000066219287CB25817DB7C62BA0FD52C3DAF6 +:103810003DC4BA12CFB186C9230FFD0FEAF39B8DC9 +:10382000F269C1C3C67A3599940279DED50F982121 +:1038300093882CD4CB3F0ABF1BD398FFB980D437D1 +:10384000815DF788CCF2BBE72844EA4DF5D1D2E799 +:103850001E29984DEBF7A5317BEC53EE6FC07B8CA6 +:1038600069F4F9A25BBCB29ADBF37CC75B874C1DA1 +:1038700041703EE63F2DD2EC57E284787E6FF857D8 +:1038800076E4F3F76E15F1FEA937B4EBE4F3DC351B +:10389000C6F35DE8FCA1E725E47E3CC7A26D57A313 +:1038A000FFA69D47C397761EF3B6F0EFFB6E4B1352 +:1038B0000C76DC2E0E3FCDFFDE1352DF97C6EC7A7E +:1038C000ADFE72485DA36F33E76F4AF77B80EE97DA +:1038D0005AFD158C4E3A65FDBDA81CECB72F6D68DE +:1038E000E47E16CE2FB4DFCBE7EB17159CEFF57017 +:1038F000EB2E7DEEA967C12F5DF49B0763E152E8D3 +:1039000013A93905DEB758B275552CC0E9A4E4896E +:1039100005BAF9C42B8E0E072F532F0D5EAA4DA0AA +:1039200078AFD5E8BF68E504D0EF7FD96A56C03FCD +:10393000ACDB66F1C177986A5B17E2BD0DAD1F6322 +:10394000F5D5F87E65DD2EF3877ABC2E7AE2C114B8 +:10395000CCF3209EDEEC5EDDD71B3E2154BBE5CFD1 +:1039600015E02FD7113FD273E838583F9080F27A94 +:10397000B61CD7F3B9163FAD634DA4AE75FD1988DB +:103980009FD6B58E39017C5F47A40FF5F4540334FC +:103990004DFD962FD278FEDD15E40A902F1A3C8853 +:1039A0003719E573C3933F1D748CEEE7D496D76245 +:1039B00005BDDFCAEFDDCFB6CCFD53E279F4C369B4 +:1039C0004AA7FAF73234B9EBDC4537904AAB6DAC15 +:1039D0005C62F6C58EA0705DB2C98CEF892E79EA63 +:1039E000B1C77F0EF944EF59F01E64F153078E0CF6 +:1039F000A7F5C53BCC4995EC1836B817D6F0524719 +:103A0000FF07F7141A1E163D734086F768A01DFCC9 +:103A1000040D1F8B77B4CB64604FF895B6B4CB9D83 +:103A2000B6307869395681EF1B3DF9B50C78FF64E3 +:103A3000AF4052B37A8EAFD97400ED188013E29183 +:103A4000E3A91B6F3DF0E59BB03B1FFB2920B72F7F +:103A500084AF77B85EA574FDF46EBA8F9A3F585C58 +:103A600000879AA76F8A85F39C90EA197D3FB22A56 +:103A700005F2DD6ACC9E14054BD65EF3E8CD48779F +:103A80000B0EDF9CC2F20FD5349EE79106E79CBF78 +:103A9000710A9EB39AB891FE6A1E11AB201FE62BE5 +:103AA000898CDE11863F6EE3FC716233452E3DE763 +:103AB0000990973ABF477BBFF9E6EE7808BB8FFCC9 +:103AC0008ADF4756F53219F44B37DD6E598D72F5A2 +:103AD000D30C3515EE29291C34398AF2553C5C9EED +:103AE000CAF0C4E4318EA3F4570AEDD0BFC38CF7FB +:103AF000C3BA715C7EB2F597F3F5E9BEA3C11E3976 +:103B00009112FEBDA0C77B09DAFE3A888ECE747C86 +:103B1000CEF87ECB5AC6E71ADF7BAF1E0DCFBF7C37 +:103B20009BF1118C037D44F7E54BC5E7ED930594BC +:103B30000B16E20BC7DF5BCC9CBF8DCFA9C58EF601 +:103B40009C462774FF127C972C482F749D04C40355 +:103B5000DA2BD50FD0F13A3BBB0ED6C57E72B03D05 +:103B60002BC8C70BB83CB8B91795079705E501D91D +:103B7000987C51F1812566EFE33F07FEA5FCEA71D1 +:103B800002FF9AF1FD9BCFB6EF3F721DA5F3CF5A0E +:103B900034BE35CAD350BEADD97933C60943F9F620 +:103BA000B3F47A12966FD3F9FB73A17C9BDEF91FF5 +:103BB00095A71AFC1E09811F958FBFDCED8C0CC7E1 +:103BC00050F938AC9733AC7CA47F6F93829E74A875 +:103BD000D19F46778B7EBDB40FC8A16EFAD4E8AFF3 +:103BE0009B3E35FA0B3DAF117EA1CFAB21E9496772 +:103BF0003F98EF221E3BC5B77F8F88DF4DEA72FAF0 +:103C000063210EB42A8ACC023BBC4BE1F57856F70F +:103C100027CB4D2027B4767F148BAB7555F963E322 +:103C200075F6F5B1363116E2BC9DDEF0DF79C3CC16 +:103C300044BA7E6784EFC0697189AEE8D841B85E46 +:103C400074A617F0552EDA326F81FCD16611BFE7EA +:103C5000336FE5B5B19027D2D5D677E234DA3EFF9F +:103C600015FE393F8F2AA55138CFE5783F493C0FE3 +:103C700015D1F3CD6D63F6F3BC0DE1E944BB3FAF65 +:103C8000B62D97411E51BBF5437DFC6811FFDE4206 +:103C9000CDC690F6B671484F8B42E8C9CDFDA3134F +:103CA000BDB87E1E4C0673FFC4A4CF0B2917732723 +:103CB000C23B1E5D8744CCBB3EDB26922638E776AE +:103CC000C14B80BF3DC94897B5547EE8E3C0A7808B +:103CD000EECEF33EDDA9DFFE77C1EDB4CB9267DF18 +:103CE0001FF40B5A9E7AF6BD4B5E80FA734733DFA2 +:103CF000273DFB97EEFD6626C8FFAEBD1682719587 +:103D0000BD2F67DE0EF5DD16CC3FEABACBC2E2C1AD +:103D10007BED984FD795C1DE8B69D8F3F520CCDFCA +:103D2000268D88B784DECCEF38DBF6B73FE27BB672 +:103D30006DF454A06FF7C6A03D5EB73BCA0B4E6A48 +:103D4000D79EAF0BF4F718DFF73CB5328BE377D98A +:103D5000C934887F75C5B33C9BBA17863DB692AE11 +:103D6000BFB4B55D86F7774A5FFCFB2090375D3BBB +:103D7000991D71DADCF928711192D1FB8EBBCD143B +:103D80005FA7C1B6A3BCF27CEF3DE3E19EA3275C35 +:103D9000181CBA281CE05C142E35202723C123BF31 +:103DA00037FB4ECF0F0F1E6766C2FA4BDAAEC07BF1 +:103DB00088205C0495B5DBBD5601CFCFDAF77E3D98 +:103DC00008E4F1672D2B51BF5FE8DCD7FC60E9E028 +:103DD0009F3DB7E0BB98732FFBC19E9BD17F00F442 +:103DE00053724F3EE849E7CFFD18EB4FDB5DB8DF7C +:103DF0008BE4FFFBFF5FA3F79D02E6B15C08EF3B9E +:103E0000FED7E2FD158E77BB02F9125D7BFE9E495F +:103E100074E7BFD0B93B7EB0F83EFFB9353BA8C3CD +:103E200054AFE4D3FDBD479AA764D1F22DF58B249E +:103E3000705B2D91EE6BD2995F611158FE3799221C +:103E400068F1A50E43FE537A0DDA1B13D4BBD97764 +:103E50009AA4FA0EC83FED2899EB5A873DF2F0BBC1 +:103E6000021D9347F2BAD1DF7A5320AA40EDDB0955 +:103E700025E30E81BD375115D11EA425DA81EF64EB +:103E800056B0F642A39F313DC43FB8769AF1F9147B +:103E90003EDF54B24CC9A7F09A9A2E295E0AA2E9D5 +:103EA000C5F56638CFF41B04D2AC8B6F4E0999EF81 +:103EB0000308A0E9ECC8EF0ABFBC74E6775A846532 +:103EC000080F522CF2F78D2E003FC2E0DD31793021 +:103ED000CB33965C0C7E5397BA306ECAFD50331FBD +:103EE0006FB6ADE900BE3513A3FFA9F99191E04C7F +:103EF000B85F8AF36407E16E5645F44B75F3213CD5 +:103F0000347C7C573C68F8FBBEF890D289E15E5562 +:103F10002B175A672F867B082BE4BDD379276E6059 +:103F2000EF91587305846355A119DFE3FAB3A9AA89 +:103F3000000CE7CA2157D4DEC6A675017C1672387C +:103F400056937AB43BC9B7E7CE1515E0AD1FDAAD8D +:103F50000B5542C653BFA4BA48F045D3F32F9088FF +:103F6000272E0FE2A002F9501F07F51AEBF0776534 +:103F70004A709E0BF58F241FFED5E59FA83CFA9052 +:103F800022FD1894983F4324BDFF38AB8DC1B16E1C +:103F900089E0CD463AF299F5F7C04F70BAFED31DCD +:103FA0004350CE15DF3B308EF9B5F998D753C7EDA6 +:103FB000FDB31E671CC473CEB6F58D8378CDD9438F +:103FC000A5B1E1F2790E73BFF2F72BAC58769509E3 +:103FD000CD621CBE7F3201F570591401B9133A6EDF +:103FE00075BA1697A997318E4F583E7E353FC70256 +:103FF0003A342E4187B70DE33F9106F5C403FC7DAB +:10400000A8BB57F9BEF0053F16E07A38AAB322DC08 +:10401000770A7FC6E56AE5BE6F64881F4C6ACBC22B +:10402000EF4C4E2A33BE0F785F3AF7CF879021B01E +:10403000AFCA7D636287015E0E89AE280ADFBAB619 +:1040400033B23BCCFD5C283C617E88231F37BBAA82 +:10405000019EC7EF8EC2EF00BCC1EF8B72F9F72152 +:10406000E11342103FDB9CCEEE21BE4E6771F46B34 +:104070002A8BCDC974DDDC566530E497F5E2FDBFCF +:104080004E77E2F3DE7C9CD6AFD712D6EF98ACD455 +:10409000863B7F4626A39F05C4F5E342E18787B7A9 +:1040A000E27BED3E783FEE6C99C0DF9F09A56B8205 +:1040B000FC7176B4E005FD0B7E2CD62B05D4FF6F8A +:1040C0006879159398BED4E83E14CE6F71FAD5D6B0 +:1040D000EFE2707F9BD38706670DBEA1FBD5FA5335 +:1040E0007975953EDE3271D7E0A7C13EA96D1314F4 +:1040F000139DAA56EA94810FEB76DD6786FB85E96E +:10410000FC775A885435487FBFFB75BA84F3EDCFEE +:104110001B81F6E3171B987DACCE3B130B76D01BAF +:1041200026D75B23801FDF140DDF370F2DDF5FA144 +:104130002C2A33EBE7CD627ED29262338487AE5F66 +:10414000D26E4ED5D1D3D7908F3534D8DE6B89134C +:10415000F318E97AB80FCF3D1602F94BB92D1D259A +:1041600031F4F9F5F5F18C0E6B5ADA65ACB3EF0D5D +:104170006BEB69EB84F2D3E4CA18437D6E69673A4E +:10418000C0A5D2E25BEE0A43A7F76774C755BF9B91 +:104190009E5029DD0EFAFF414F9CA908F73DD4D966 +:1041A0001C6E3AFD901A4E3F2C5BE94C05F82FDB54 +:1041B000D337159863D92BE529E1F4C33B2BD8FD00 +:1041C000E1519E7FD93599EA87CB75FA617214D295 +:1041D00047E8B87119DA77552EA01F347CFD87E5C2 +:1041E000CC3BA01FC2F0F5CC0CA37E98DA361BF5B1 +:1041F000C3D4C92271EAE27153322EA41F8A53A696 +:1042000063DDEC8A094337EF70BF04E00A25AC0395 +:104210007AE2EE0C26F743F54524799E7DB1F2FC57 +:104220007F08CE9A3C5F3685BDCFDF930E09CAEB7F +:1042300065D305FC1D93657B983C5F76038F4B86A9 +:10424000C8D72A90AFF97AF9CAC6D7BA993EA8DB7F +:1042500095F5D319F4F975CD669795F6BF2E286FAD +:104260000BF4F2F6EE0C498373A61206BFD366C4B4 +:1042700010A7515EF50339757CF0CBB9CF00DDBFD7 +:10428000C1DE37FB33D7E3AF0F7E391FE2E91FF101 +:10429000795B33185E4EAF208BCA281C4AE7317B0E +:1042A00078E97611E150DBCAECBCDA6D02BED75B6F +:1042B00091F70DDE1B2EDEC3EE0DE1BBBEC53A3C11 +:1042C0002E7EA3B3A9373CDF24E0BD67B56B317BFD +:1042D000FFEF611627B6D2FF205F626D74EC668235 +:1042E000793A2AC69B9772B8555AFC07617CE51348 +:1042F000826B13CA35637C7A69BFB19F807FB078C7 +:104300005B48BB6B2DDE672C85B8B3CE1FF93DE74C +:1043100093F9A22FF719C80F7C4B0CFBBB675ABF50 +:104320006E38D47C4F381CA670C8FFE7E150D776B2 +:104330001FE6DF7CDFF3BF93C1E3ED79241FF8E5CF +:10434000CF2615F9DFF3AA88EF17CFBBAF7FAA3EC0 +:104350004FE93887C31B2677531AF4AB65EF212F3B +:10436000D8B8E300BC223EA3850C86B0FD82878DC1 +:104370007AB25B2FB73A51EFCEA8DF21C077FDE7C5 +:104380008B047F0F6C6E9EC50DF7AF87A3FC28CF03 +:10439000343AB467B2DF8F8BC964EB1EEFE52F436D +:1043A000BF6297A0209FC07735A04EF100DFD5D81F +:1043B0003FECEB0A0E778CCFD4ED6278AAA378019C +:1043C0003EABA0F62EE891EBA9DEC1FBB2B6763388 +:1043D000F4AFA1FD1251EEB8D0DFD5F413DCDF1538 +:1043E000A7E8F0B6E718A3DFAD828B84C15B0EFDB2 +:1043F000EF7C788B842FCD7EB858BC69F0B0671AFB +:10440000F17738AAA37208DE53B1DF03226DF17889 +:10441000AFF251735FC4636F2E6743E91BEC7DA756 +:104420002EBE74356C1C3F601F857972B86E36B332 +:1044300087F4F225D48FAE231D68D724A7B97F9DBA +:10444000AECB8B9BCAF357BAEF7583FDE6679CA78B +:104450001F7194E0FD8F96570BBF2085F960BCBE9D +:104460003FA3E0E80C7ADE2FD688F89EF2B526E767 +:104470009122E0E375660274F9C5EB6695D9A13126 +:10448000288767BF71DC0CA191D9905F40FBCDBE3E +:1044900093C9DBE330196DFB03D5632A7CBF84B479 +:1044A0000C85FCFDC9AEF672C8DF9E927F7815DCE4 +:1044B000D35D53AA1C3902F05D2B1280EF876B4A43 +:1044C000D15FB9E94601E9FADD15F89B5864CAE401 +:1044D000AC2347E8BA37AC49C67BB619EA8172A06B +:1044E000B7B913ED36B8A71B972306F37B09BC0FAA +:1044F000D5B10AE4F78CFA1BA7C07E6BA85E80B822 +:104500006B4DDBE1F254A86F14F0F7D4EA3C6E195E +:104510005E85EA78F88C0CF18F6ADA0FD053B79188 +:10452000F5ABDB22E07B3ED5543EC0F9AAB70804C8 +:104530005E28E9A0F69F95CDEB850F34756CA4E35A +:10454000697D018C8779B7C4E3EFDED5BDCEDE137C +:10455000AA2E5C7910E453351D471F938E2D37E248 +:104560007C0B370A0452836B0AB3EE2984F95E3759 +:10457000E3F7418EB6FF4C867DCFA4EBA5D1F9E7DA +:104580008A9DE5986F7DBBA0E07B4D65B7211F74C8 +:10459000713E2049B7B2FB6681D7B95DA8E9C7C7AC +:1045A00032B391BEAB6F59D904E7EAF42467814B6B +:1045B00054B7EB8C0C76DE472BE00334146F3C0FC2 +:1045C0006EBFE7B8DCA99353BECCBE488FF3761517 +:1045D000239FCF2755782FEE5EC9F4F2B155515E77 +:1045E00001EC11B3827A73FFAA1F3D04E73FFD94EB +:1045F00019EF4B4F6774627CF6C446337E3FA4616B +:10460000A38872E4C4761617121F99529106F0A37C +:104610007200E86EFFC65219E4E109AF80E34B1F58 +:10462000B93985C57D8DF2A3DAB908E5C523514CAA +:104630003E2C7838FCFD6A4479B1BC82C9F7107908 +:10464000B034BD09E37EA172A28ED834F99007F58B +:104650000E5F1AD26FEDEB6602F65DADA4CC7C184E +:10466000E8664614DC2453BEF01D00F9F685577049 +:104670007AE8F3EB673D3F14E0F731C01BF8624383 +:1046800022DEAF567B67235CB57CC4050F1BE9595E +:10469000CB7B9AEE1683EFFBD0FF5D5F1343545D37 +:1046A000BFA37752BAA4EBCDDA2578E13B4847EFB8 +:1046B0003C76F0E67CAC2B4087B5B770BDBAC18EB6 +:1046C000747BF4D633AB802E67DE21E0FE89C7DD34 +:1046D000047AA5F661C10971CD0577B0F10BE878D0 +:1046E000A097A33F63F443E9D809745EBBF1BE838E +:1046F000D87F8BE084F98F6E9A8D7AB8C623127CAE +:10470000BEE518DACB541F60DED07E8F9802745E4F +:10471000DB685100AF1ABD68F4778C7F879A585DCB +:1047200083AEA1E36ECC7486A53B715A16D257DDD9 +:104730007633D24B9D87D1D3B1A744A4C3FDABAE92 +:10474000AD00FA39BD5588407F94BEF283F4253E12 +:1047500062C6F10B9E64F185FD1B195D9F6865F6CD +:1047600069E923FDD1AF59F08699B0F803B1E9EDBD +:104770008F0BD16128DDF5D04B9C0E23D19DDBDC66 +:104780003215F20F663F4DF7EF0CC2ABB4E9568C11 +:104790000394364DC7F36AFC532DB1BC8D79CD2BF4 +:1047A000593EA3C4F27BBEF3BE42F6715F503FE6B2 +:1047B000817E84FC131FDDC7CBDB1F433BE0F35F2F +:1047C0001DC3FCC6C52F50FCD3FEA7B7DB890FED78 +:1047D0006C2FCA9945AD22E69712C957708DEE7DB0 +:1047E0000D2D2F63F16FEC08F7453B2DDE4A3A7E25 +:1047F000D1B3C707E13DF95DCC4EF5FC8A7D6F86EC +:10480000783A075D03F99912CB0F09D5BFD17D58CE +:104810001CE7D4F331F85D26615B3BDE332D6AB9CA +:10482000D66CD1C52D853E66AD1FDEDF7828FEE152 +:104830007E11F6A7FF5D092D2FE4D4938C7F16ED32 +:1048400032A37DB468DB268CF7D56D3B83F9B3A525 +:10485000BF792A16E050B74B34E64F6D137D16CC66 +:10486000F3128F59D8F7390C794CB5ADECFD8EDACF +:10487000169E2714923FB3F8377B9EF550D02C7EBE +:10488000E68958E0A74F3BB6C6023CE97C987F34E6 +:10489000B130427ED285F2925AD6F2BCA4F1F87BB6 +:1048A0001DA179499FC23FA81E77F531E679926D27 +:1048B0004C6E51EC17847B1F49B35F163FF5D5A3AF +:1048C00090477B6AE7678FC2FE97FCE38B4721AF77 +:1048D00083EC8D52C09EA8FBD53B987FA88D1BDB37 +:1048E00087FB474F3E81F99BA7DFB3A05D787ACF66 +:1048F000894CB0174EEFF82605F23297EF29C7F82A +:10490000C4F2DF96E27BA291FC4DA04FEF45E48F0D +:1049100086E2637FABE8B3D17D7EFEAE05F9BF3B97 +:10492000CFAC6529CBDF73F2FCB2EDE1F374B57C5B +:10493000A8DAD66B268E0479D7CAF47A777ED48526 +:10494000F2CADEA678BDFC22F0B79DE70FB68C0F49 +:104950009B57F639FC83E2A9A68F31AFECABD6F9B1 +:10496000BFFC393C6B0DFFBEB6C6D717829B9607BE +:104970003CB48F7A531FE08F9DBFC63C3EC05BA501 +:1049800013F4FF579910DF3C69F663DCD0BFC7A270 +:1049900040BED7A23D47915F4EFFF630E6D9129E4A +:1049A0008F7B9A74FFB1BC491EBBA8DB6267F968B4 +:1049B0001CFE90AFE68CC5769E97C6E858CB578B09 +:1049C00094A7F6649F6C665FF3FCE4A5CE0E59B124 +:1049D00005F105F8110A015FC70CF97FDAB943E761 +:1049E00053000E57E8F32F23E503723BBD07BE9833 +:1049F0005C3EBD89E76376E75912929E07F9414C08 +:104A00001FD67985A3E1F0ABE55F6E09C1AF76BE35 +:104A1000487CA1F1E785F7FDCFC1E5A13EEC7D0023 +:104A20000D3EA7BE0D2FA75FE4FC4EFD96BD7D7425 +:104A3000EFBDCCE27E8B9677A6EDB7A985E9E5536D +:104A4000DB98DD18CADFB5117E57EB0DBE4EEDAE1B +:104A5000F64120874EED7B9ED39D97BF87734CF622 +:104A600070B9EDD5CBED08BF6376B40FF317A9BFCE +:104A70001B76BEBAED67C2CEF7A9A45E0BFBFFB4EE +:104A800083D9219FB688617F0FA1BD8FF17DD52687 +:104A9000BB8C7E97181B8DF268B9BDF05DF8BEDB4C +:104AA00072BB8CF90E0D2B797EC49D2EFC3D8F06BA +:104AB000FB58FC1D8855001F9D1F6A56DCF8FB1330 +:104AC0006647553EF857A1EF77CA4926E2D5E35F1E +:104AD000F2A4E3F7BBB2BF9640EF74AC30BE37D25E +:104AE00021290712E97C1D65820BECDD9E74669C12 +:104AF000FF6A5534C4CF20560DE73AEB62DF45B369 +:104B00009B7C0AED42EC511D0E74F49CEC77ABE1FA +:104B1000E7BAE03E7CDD0A6B3F788FEBFF022FB6F1 +:104B2000D5840080000000001F8B080000000000FA +:104B3000000BB57D097C54D5B9F8B973EF4C26CB81 +:104B400024936560202C37FB1E261012D058261B9C +:104B50000609382255D480376C610B89686D6CFD6D +:104B600097613145E5B5A12E50A5CF01C1C7A3F886 +:104B70001A166BAC510708142DDAD0E293FA571BC2 +:104B8000942A28981194F25A2CFFF37DE79CCCDCF0 +:104B90009B0984BEFEA3FEAEE7DEB37EFBF79DEF6E +:104BA0009C89252E89C884D85C8AB7279BE0DF15AD +:104BB000FA5F1CA1652B2FA7E0E3787A092131EC7D +:104BC00015FD6EDF6F920889CA26D94A3121761207 +:104BD000E59269F98958F761299690F536AD96D036 +:104BE000E715F89BD4FF495CCA2918CF4AFFB99250 +:104BF0004AFB9B40CBD6E0F8F16E7D3991849471ED +:104C00003E6E4286C07BFAA7123259A633A3F388C0 +:104C1000AF36F92224FC5E9B312438DF780771F926 +:104C2000E1FBB4189797D68F8961F313F3A5F3F9D5 +:104C300018E6A3D27F703EF93D5E13C1797D1C3A20 +:104C40000FFA27796C38BF8F0DF3FB38747E05AAF5 +:104C50002DE9D3685A50887285C237C6DA4D389C20 +:104C6000CF87C299102F514A009E02AEF43BED2728 +:104C7000457A52B922015CED1249C3F10CED46D8D8 +:104C8000B17F28D37EC7C09A271252E694DCA7C60C +:104C9000D1FFEF4C22641821A92D95E4135A96DA1E +:104CA00008C2277D3DF145D0F9A5074C58266BA3D6 +:104CB0007C19B46D84957823C7D27A0AF19AC742D9 +:104CC000AF3E42C62370579B6857CA3A421EA3EDB7 +:104CD0003A0315A60514A8EDF089F63F51754F511A +:104CE00069BDD6DB34A7A9089693D7D65546081DCB +:104CF0002E477211625A95DB7D6424214950FF06CC +:104D0000F89EDBED8EC1EFAC4C889FD075B545F5B4 +:104D100095DD56272DA7B2F29DBEDCB675B4BF0F48 +:104D2000D23D77AA0EFACE6ACF05F8137F02AE778E +:104D300040FAA270258EE03CB3B7F92BA3E8246EAD +:104D400009508052FC67D03EBAF3013FDD16209235 +:104D5000ED31A2ECB710FAF4EC3B66E9A1CFC6F650 +:104D600063F8DD0465FA1C9DE8AF4CA6EB7C50BDF2 +:104D7000D1E3CCA1FDEDAB779AEC84AC546FEC564B +:104D80001CA17098A48383B2FA26031C6EBA2E3835 +:104D9000ACF4DD847018ECBACFA99E1F015EA69614 +:104DA0009B8844072D3D11E393181F477A0A82FD23 +:104DB0006C319145ED31E1FA59C5F0CFEB093A1A62 +:104DC000884ED2883D17E8D4482F747D35ED148E77 +:104DD00053B57A4F5562904E895D1B37A300E63973 +:104DE000F74998A718776AF90A3995CEE7498A23CF +:104DF000E8D7D1E28DCCA474EA709B5CC0E7E7549D +:104E0000EDE7503F7656C06FA6554A8976BF941697 +:104E1000EC5FD07DEB6B32D2776BBDC9B71AE54141 +:104E20008F04EB0EE2BDC780F700C37BC749C4FB0C +:104E3000F2CE930CEF1DAB2AA28AA12CD923545891 +:104E40004FA008F0F92BDF9D1E85E2737474A01546 +:104E5000E8C14CBEEBA9CD41B8BF0874DA0FEE7CB7 +:104E60005E02FE03E1ADED48EAE3F9B4AAF7A8C992 +:104E700095A106E125EA1D572D586F63AAF61B1868 +:104E8000A76942CF61BA52B2E7C81F62353ADFD88C +:104E9000A333F643FBD89914136A70DCB6A3AB2B8B +:104EA00080FEDB80FE51CE04BCF698ABC183F14599 +:104EB0001F3CF69D44F898A04CDFEFB430BA29EBC4 +:104EC00090DC3EE08B6872AF873EDF564D38BF9373 +:104ED000AACC9F12C3E3D103B24ADB97AD35617D03 +:104EE000073CF343D7BF16EB9D54152E77183C04AF +:104EF0005E051D51C289BE8DCE797896F63EAC3FD7 +:104F0000483709D1A9F47B69D7DCFB496AB0DD4F8A +:104F10005612CF7C73B01EA59F9775F456608E0411 +:104F2000B8F5D10FA54B902F46FCD076A7193F2599 +:104F300044ABB4FEEEAE15B2963F78BC9644906694 +:104F4000987F493469DE43DB97C4D127941379797C +:104F5000282F27F3E768FE3E8F95D33E7099245A99 +:104F6000DE0270073CA498189C147B2EF0912985D2 +:104F7000C1B9CC198DF25FF0AB42C11997006A88B4 +:104F800078E1991A4835011E05FF2A0193DF46F59D +:104F90005FAAA29A5CF4FD5B2B354F55C6C0F2E5C3 +:104FA000961CD9E30B232FE25218DEA980F69ECA85 +:104FB00006ED2C91382081615A5C0A9D57A3B5E714 +:104FC0002733E8D7E539172C809FD5D1CB6FD4F2A2 +:104FD000071EC7388FB72EFF361AE8ABF352444D81 +:104FE00038795503EBA7E31F59390BDB3D1A155BE5 +:104FF000C8952ADA2DDF41D1449FE94B6A4921E067 +:10500000C3AB2480FE8B965CDB09E285E9C3A12952 +:10501000BEED29801F5F2D96F3D2C87609F0A4ADAE +:10502000B141594EC1FA1472C23E92AE4460DFAA39 +:1050300042ED0D44792AE0B3F9A00D847D04ADAFB3 +:10504000C27BBD3D45E7B7958C017CB7552540BD7A +:1050500038DEEF2566E708BBA83AFD963312CC7719 +:10506000B45701B94AD252703EE5C4ACB38F4AB2CC +:1050700028C8617E59B93EF85E69357CE77454DD15 +:10508000CF8E6A73CDA0F43E359BD23F7F7F81FEE9 +:10509000373A82DC7B5B7E50BE4F51EFF254E9EC35 +:1050A0008F3617F0E1EFBE9591EF8DF8D8CAE9F190 +:1050B000C84A8FA78AF2DFAF22293EE87A2B5469CB +:1050C000AD4DBD36FC8C7833C2EF3B9D0BD17E33AA +:1050D000C2ABFC03575582DA1F3E467808F8D3F579 +:1050E000AD07B85567CBA8AF04BCFBC389D1C3EFEC +:1050F00072683D89D10FC38744905E04FDC4A52129 +:10510000FC4B80F6E07B740A968DF035C293CA01A1 +:1051100037D6E7F83B0C70CB80AFEEDAEA214138A6 +:1051200050BAEA8A0FA12B01877E72238B9739DE52 +:1051300085BD5CCDFBA1F632DAC3950E9B0BC05F3B +:10514000D9C8E65B9911B3D59B82F8DA8AFCE3A74C +:105150001829C17FD9DF2566E752BB94D167E7E400 +:1051600033603F8F8ED0D6027F04A478B29520FCA6 +:105170003F36C05F57AE36D8CB4678FC0AFE676232 +:105180007FB809BAFB790AB5AFF36871381901F62F +:105190006FE12BC57120C7496702CA63233D969E04 +:1051A000F0F4F5C3E917E953225ADF7B3BB5233A04 +:1051B000B21F7902CC9A1BAD6D32D0E18DC4BDE631 +:1051C0009415D62FE33CC5BCFEEEF4EC4CA1F26680 +:1051D000624FCD9A53A17CC1C717F0BE89C3FB268D +:1051E000E2DD2FC7C253F9BACF8E0FE96F6F0AF70E +:1051F00017924932ACC79EA232F9CEFB13EB1B9D2E +:1052000046FC12C2D9EADB2AC1FC89D792101CCF16 +:10521000CCD1949131E3B51494C7CD04ED656A5EA9 +:105220000212CBF8F7326B8C1FE64302CAD93E3C20 +:1052300020DFD5D901AE142EE44A74707EBF4B91A5 +:10524000944FB383F33BB7C3EA95819F8769BF87C8 +:1052500071CE4A470B916F157F26E841E3F70B1D8E +:105260005DCBE13BADB710EBF1752D05A791D25D9C +:10527000E0B508DFD694ABD8A156AAC242E44159A2 +:10528000149327D5242083DDD919C9F8F9F5AF1671 +:10529000213FB8897D6D1EEDEFD0F9C947809F2B66 +:1052A000A978817A932EE9FDB66BD1691509CC8175 +:1052B00076D576B3C10FF4A2BE59CBE59AB0D34CE4 +:1052C000A9DAB9147C3FCA077AA6F3ABC92AE06D04 +:1052D0006BF6F85B6EA7555273C6CD00F7CC64ED44 +:1052E0003683FE9BCDE96B02D097845690A0AF8B9E +:1052F000D04FDA3A037DD913747EDD2DC48FEB2FA6 +:10530000CB36FF4D373F6E9718EDF5A09DDE16D6D4 +:10531000BF235D0AC9A6709EC3E1BC36DEE205B9B3 +:10532000A6DC27F9480ACC978C5A45E739BBD9AC9B +:10533000F347E7C42B88C739AB227D84F9DFCE7AE7 +:105340005AD6E8FBC7A098ED7686DA55A425A43D89 +:10535000D0438C8AF43BC7CEDE7D44FB189600FD1B +:105360009E72A013EF359F0FA553E3F803F66B6809 +:10537000B75622B3C07E5A6B763B5D21F6C7A85460 +:1053800066BF9CB7576D32A50E6C9768D664B7920E +:10539000182CF7C45B67F9C2D831A23F4127651AC0 +:1053A000F3CB07EA373D50857699E949BF0CF6768D +:1053B0007A80A07D5C16709BE6E9EC74E69FF6B3FC +:1053C000D3DBF7A39DBE6CDF7E66A7B7AF427B7FC2 +:1053D00019B5F741BE53BB1164259B503EDAEF7DF2 +:1053E0007E26E52D52D62EF5F9A10A45455A1BAB6E +:1053F0007FF7D6ECF847D3C14FD49C66EAF7DC9D23 +:105400005AB0C14AFD9ED6141249A8DF332BB5E02D +:10541000B6F513283525B825128FE50D311307EFA2 +:10542000D7DE9D9ABF01FCDA81FCCBEA54F5AAFED7 +:10543000E507E99EBB5343E202543E86B54732324C +:105440002AE6403D2137CAA2187F3E6AF2A7FD1422 +:10545000FCADB76402FAF4969679E8074C6B59EC08 +:10546000A9A2F3E93D70399398405E32BC37A63269 +:10547000BBA6299AD9974DD1B41F2A6FDE746A8DC5 +:10548000D07F77F6F3EBC7527EA9EB905DE02F4615 +:10549000665D1E05FC3F6DFCF34F8EA5E37C185046 +:1054A00030FED069A37448DF7F4824B467CB8E45B3 +:1054B00078F651BC7CDF59DE961AE29F7CDF598575 +:1054C00065524B1D2BCA1F2BAC8C2F3F24FBD37E68 +:1054D0004AC7F1364B68079C6F4E89033AE834D3CC +:1054E000F587D0E3EA5405E96F35A7C7BA4B320612 +:1054F000CD3ACDFEE4665ABF4EF19BC10FACBB6402 +:10550000C1F7300F984F67A4BE9FC7793F8FF7F55B +:1055100043E1300EEA19FB51D87B89ADCF8887D3A0 +:1055200029953F85F57CDFE96E43BC51F905FAA268 +:10553000ACB8EB04D811D7D64B6E09F452D365C979 +:105540003F9AC2F3EC3E33FAF767C13FA4E39DDB19 +:105550007770C85CFA6CDCFDC758F007B7707C9DAB +:1055600053BA63617ECB5EA2FE0BDA43FE21F76085 +:10557000FB79258FB161ACA1FA7AECB707933D2C8A +:1055800078A8427C4ED8A53759BD3E985FE72A19C6 +:10559000E508D5E7226E2A81FC9EB44F7647C6F611 +:1055A000B7575F4E350B796B023DF6809D8D33907A +:1055B0003C28BB94487C21F2A24CF1CB30FFB24B8B +:1055C00043F0FDB923A94FD402DD12B30BCD4485BE +:1055D00074A1BD2C11F1D7954ED7F33A2FBCB1EF82 +:1055E000C2ED37223352BD48EB7CC7AF25A1FD0C7D +:1055F00021D292A05D38E9923EEE6AB4A3859EADB9 +:10560000E82C5A9B4C00EEEAED37021D1E51907FAC +:105610008C76767560F200F6F406A4A33DFBD2A268 +:10562000212EB091F379D3BE0B93413E2D27FE3B43 +:105630006E4C82B8836CF793ABC5BBD6FE6E121D61 +:10564000FF8D80A2823C7823D0652DC4B209E31C73 +:10565000656F97E501FF7606941AF05BCBBEEA8A88 +:105660009E971FB46B3A2F9BF0FD1B970FE07BD1E9 +:105670006F6720210FF4F36E13F3B7BB0EFF2D1AE3 +:10568000E4EB1B97CF27A2DF2FEC92FE7635FA01D1 +:105690009536B92F0E1D6ABF13B9ECB815FC8D38BD +:1056A0003391110FCC1FED67977C40D6DA487FFB12 +:1056B00044C01FC812F8A69F5D1D84B7CEBEBE921F +:1056C000CAEDE59164EC15B0732F272E057DDDDB67 +:1056D000196D5F8DF1296657F4767DFEB3A9F0FE52 +:1056E000A88CF1B6DECB32F2D581D7978EEE890940 +:1056F000857B2BE2EFE2B0AFBE7C95D6BF78280A5F +:10570000E3EA4471E5858B9F04E3C9FEE126273C6B +:10571000BDC34D1390ED305EF09D60BCC09186F12D +:1057200082C0645057999B4F5A20DEB231D5333432 +:105730000DDBB747C3BA174531F9E42515C9D4784D +:10574000222F1D315500BD14AF5211EF3BCDD4C4F3 +:1057500002FED8CEFCFB9D54DE825FB4B8BDCD9274 +:105760001282E7C51441B0BED366EFA88490F73B20 +:10577000D2583CE1F4A125CF019CBC7F8A2019615D +:10578000ECD387D2983CDC6BF14EDD05F53E36114B +:1057900018AFEBF06F0E0FA7785E7C422D023D3004 +:1057A0002B4DC57A1D4777B60EA7F53A3E00ED4959 +:1057B0004DF26DF5B2898EFB2A5159DCEFB809E73D +:1057C000DB172725EE4458EF1D694C8EBD7A84D136 +:1057D000AB18FFD528A6EF26A731F95296C6E26E80 +:1057E0007B8E5424CE45BED22601DC9A4EF5B4C63B +:1057F000AAC138A1B00F271EDF33B580FEEFC4B3B6 +:10580000263BA04F3DBE5586F5AAA7098997FAC742 +:10581000B1687F53D21CC1FE5E3DCBFAA3F33800C2 +:105820007C175845EC5B91EA3C8FE7D3F2ABDD4A3D +:10583000C2632AE203F581C083588F9887DA4EDC71 +:105840005B629045DC7BAE168FA67E27F0DB382EA0 +:105850003FDF4D75DF95C6ECAC514077A70F45A1F2 +:105860003DB697C7B589B37E34C04FE0E97BFC698C +:105870009CCF40E337733A10CF9D66D58BF4F0127E +:10588000D3BB3B6D7E6B1AC8BF57D2B0AC7ABDD1CB +:1058900085F47B5347864B56919E9B19DD323ABF68 +:1058A00089D3B9DA1EB0A484E06160F9C6E0DE47AE +:1058B0003F4A3BD255C70982FCB664C77D2C0E49CE +:1058C000FCC98C9FBCC9C05FC0178CCFFCC324F639 +:1058D0008C053E99D8B9654D326DD700749F1F84F1 +:1058E000830A7C017C26D6696376F2CF78597C6F77 +:1058F0004B6371C76A393FAEE72AF1BB37563A8925 +:105900001212BFFB199FFF62B201EDD3C597DBD026 +:105910006E559BD973F103EC99B9B9DE02FA60F1C7 +:1059200026C91DCEAEB673FC9DE37C404C51C389A5 +:1059300033F8DDC1F9E0CCBE270EC23A29BD3E07DF +:10594000F0BFA163C3D3002641FF67B699B1BD90F4 +:1059500023A2FD36DEFF4BC719FF4CDC66AEB89BB9 +:10596000C27BA297D8219EFEEAB6ED32C8F75781D6 +:105970003F5298DC00BD7CFAD063D13F003A3869D1 +:105980002210B7DF6B218B7687E0B76BCBCB3A79F0 +:10599000B064C7AAA9D04F694F82047A40C8018178 +:1059A000EFBD16D7149427D30DF2A48AB53F06F0A5 +:1059B000A4EB7A82CB93276AA83CA1AFE2B7C54B90 +:1059C000D0CF5E1E2736C2AF8BE353D0E38D41B9F3 +:1059D000DBC5E46E4F2C74BD7CDA798CD3F68DC3B5 +:1059E000E9EE892A41772912C091DAF9A67458376D +:1059F000850FD03FB5F3EF9D918F5C7A44C1FD21B7 +:105A0000BEDF44560BFB47C7BF42CEBD9BAA1D87D6 +:105A1000F14BAA9AD780FF9158EB45BA3E2369A370 +:105A200013A8BE3A037C1D462EBCCAE5C845B33652 +:105A3000DA1EE67B908FC870E083454433C13AC8D4 +:105A400066C90E7015DFD5CD8CDE3EE7F011EF3F55 +:105A500037C06B12C02B0DE1F539D753162B9D6F54 +:105A6000A68FE9292255203D12D32DC381DFCE9880 +:105A700009D2CF192A17016E8BA3F4FE8958D737A4 +:105A80009CAF2EC6B375ECE5E3FE097C9EF1580F82 +:105A9000ED0A6FB909F76B813E90DEA627A0DD45C0 +:105AA0001D2605F9BC6F3FC22F4B4C1EC8300F3B63 +:105AB000F8751827DA82FD2EDDB505E926BEC65E2B +:105AC00004FB474F28AEC8F890786FD7F68DE84FA3 +:105AD000023D015F0E448F8B801E49183AF4513A03 +:105AE000A4ED126A9A118F14BFF674DA6F7C9526B2 +:105AF00003DD18F12BF619053CF61AF62567A633D7 +:105B0000F8A4A433FE54B9FC1A584FE8E52DC59704 +:105B10009AEED0D337E04DF05B4C3A934F03D1F976 +:105B200043E976ECB7F5C3794E9017623F4AEC2F04 +:105B30008BF1C7A6337A1C683FE99CAA15A51BF612 +:105B40003BD5FC209F5473FB71C5F608DCA7DF0D25 +:105B50005F00EE5D51B82FD1270715E2067C96A7AE +:105B6000A7E07802BF6A8B85A4D3712FA6D477C52E +:105B7000D04F37777B6B0BE83A765BBC33A7A1DD60 +:105B8000ED9A02FD4FA935D9218E1DEFB64B1007B6 +:105B9000411207BE38CAC621AA4B37EFA91CEE0234 +:105BA0004F020E03E9AB81F0F310878F837F37F24A +:105BB0007506FF6E4E67F47F6DBEF6CA40F7B144BE +:105BC0005B2DC3FCCB981CEAE3EB3282FB8D0BD23E +:105BD000F57C2DCA61F87A417A285F4FE8D1F33518 +:105BE000B570B93E45FE726C33BB993FC9F8EC62A3 +:105BF000249BEF8A74A6871CA03F28FE1C5EB6EF8C +:105C00003A95D319A5A03900EFB66D11B89F20F8C9 +:105C10003E7626A930C3FE2DE81BA835533B7113F1 +:105C2000ECDB3A2D2AEC239F3107104F67A8A3DA4B +:105C300086F8F4603ECA994337307930AD4FFFB8EB +:105C40004D507E7F04EE2754CB9D48D72BAA09EAFE +:105C50008FAEEDA548078B6A5325A0B3253BE225FF +:105C6000F89E506537C92172B1B445467AA274BB1B +:105C70002E3D047EA5DE6619E0323A51739AE3A9FF +:105C80009EDD367546685CE8495A5EEF0CC685684D +:105C9000F96731C3061F17DA987ECBCFD68DA04A9D +:105CA00024CDFD148C7B4EF56C04BC94243763BC6E +:105CB00073B079104D3CAEF4C1236F6DAFA7EBAE5E +:105CC0007B34F0087CBD17E2AED9903FC0E2AE4D08 +:105CD0009DC7301EDBC9F9F9EF4ECF0B30EEECE675 +:105CE00029FAF86B6070E32671BE251F10847F923D +:105CF000A75986B884900BFBD21384FF28C1FE9B62 +:105D0000E007902B607F8A3C088887D9128272193D +:105D1000CA71217A757D2DB583C2F0D9C1F498B0CE +:105D2000729074FEFDD73FA0FE7E137C6272F1601C +:105D30007A88DE7FA2F6E3211A8B7B60BCE97EEED7 +:105D4000433EB7DAF5FB2C9043EFC828FF8B222C9B +:105D50005E09F687DC44B50FE1FD019B744A7E1BAA +:105D6000F53F9BFE261137C4CFFE26E3F3B91F791A +:105D70006A52C09FEF30B9A82500F91448C7AED1C8 +:105D8000C467A5F4D7CEF76BCB0FC6B8CDF47DAF03 +:105D90006445F9D7BB3FCA0B7CDD6B33615CB9EB63 +:105DA000B50884EB85F428EE5FFB747EB8D8FF88D5 +:105DB0008CE8F943196DBF3592F5BB3592C5E9B64C +:105DC0003E9A1907F6E740FBE3652D6918E713F1E2 +:105DD000C7D4806A6249646C1C2540707D62BF7CB8 +:105DE00013E46B140F9CAFF1D7F4BE7C8D00D0533D +:105DF000D3AC9EC33047A31F36E4E8C7FBA19F2165 +:105E00002D2C4CB0E9E80A09D6B9A92EBC1F26E80A +:105E100068138F7B85E4457CABD32FF509D1A9218D +:105E2000F253B47B9AE7459476CDDD0B761EE5EF11 +:105E300073A1FC3DB5E091C870FBF39E961F625CB8 +:105E40007420FAF79888162EEE373A83CB5B25300C +:105E50001CEDC1372E46A961F2253CAF991C0017F5 +:105E6000119FE93FFE8F70FC61197DFB7FC307B373 +:105E7000FF679C77B7998C0CA757049E8DE38569C3 +:105E80003FDB15D2DE6321DAEE98FEED84DDEB9187 +:105E9000F8FEEE8704F5ABA0130AF77119F47BE165 +:105EA000DBF3C64541C2A1B559067970A1A32B19F0 +:105EB000E25603F987623EF42F235CBC858EE70926 +:105EC000878769194CBF7ACCCC0E95CA0FDD03F3D6 +:105ED000F27C65912242E86C22AF67DCC7ECFCEAF9 +:105EE000BFC7A19C34FB93C3C1CFB8BF3911829304 +:105EF0004CDFB171395C5ACB49454412C60BC856C8 +:105F000015FC40262FD516827C3E4672E3BAEB2064 +:105F1000E8E2003AEFC63CC80B4765AC57789FEA09 +:105F200003BF89EA85BB017EA544DB6B4A0BC24BEC +:105F3000D043EB8BD44ED1C5AD18FF08FF75248F2D +:105F4000FF5055E30EC5DFD059945443E4FE30CDE5 +:105F50004A9490385BF222BBAE3CB2D9A9ABEFF4C5 +:105F6000FA25E02B678BAA7B1F94576CBD23BD6479 +:105F70000BE8FF4DA407D7378ACF678CA4217D5C3F +:105F800038FA4902C4257FC0F987AEB705D7DBA22E +:105F90005D08A50FB1DE6BADEB8395743E94EF3FCA +:105FA00002FF9C3E673F70521A8A70B7833AA07A0C +:105FB00091B51BF9F031F423473677A31D3FA76550 +:105FC000BF04FA8BCA0D6CB769A5159FCFACB4A3FB +:105FD0009F2FF03B82D6833C256F05C9867D81814A +:105FE000F4D3C68C41EBA78D1961F493C91A7813C9 +:105FF000F6C11B3B6515E860CDC30998FFF25CBB99 +:1060000084FB2E073B59FEDF73AD51A847C4B85F30 +:10601000BE1487FB3F5FF27D40D2158FF4DD14CFB5 +:1060200071B2361EF7C97BF93E6447BAF61F1921D3 +:10603000F2E0B9CE6F22417FE4893C5B83DE01410F +:106040002CD1F6E013011DB7A614AD93615D7768FE +:10605000E32265E4F7DD8C5E997EFAE5AE0A9316DD +:10606000829F0B1D5FCF39A0F6DF5F12FB50627F6E +:10607000EA4DA7F66A4688BC36EE3B19F74BE45862 +:106080002BE669BBE42897ACD7B748876B32983EBC +:106090005DB33F0AE1B8262306F77BE97C8FC03861 +:1060A0005D360B1946DF5F381183F5C4FCE97C0BC4 +:1060B0008F86996F932930E780A49BEFB1ABCF57C0 +:1060C0009FCF2CE6D7871F1E2F906D0AAEA3974453 +:1060D000B900AFED16D7090DF4EF3B512C7F8AE3E1 +:1060E0006F39E7CD5E8A2F89E2ABB7E34224D0F166 +:1060F000C174ED24CC431E198805FFE560E7851CBB +:10610000E09781F60D958C8ABF00BE20FF0FF166E7 +:10611000D72EEC228C2FB5ABB4CBC8A8380BF5AF7B +:10612000033EDF5C0F7C9A949875A1F697C4E5B3A3 +:10613000911EA5CEFDFF03FB01941F311FD53B8AA5 +:10614000F8D650B8B51670BA9C4954169FD1D34BA7 +:1061500047BAC79CE908F2F155E01309F57E99EEBC +:10616000898627CC23792CCA291B94A95EDB6B492D +:106170000DDA5BA3D398DC0BC413CC5F31EEF7666A +:1061800064CC48CAA4704BCD564DF6FCEBE2879127 +:106190009957859F1FE9A291C3A911F619295CC8D7 +:1061A0003EF3595DBE80010E07D33D590C0E413AB6 +:1061B0005BA35E151E790C1E5A21ACC366A6F402C1 +:1061C000409950EFC4BC18D57D37EC7FEE5CC5E03C +:1061D000D0FB2283C3EE2E13D2F516928BFC996B63 +:1061E0003A3F07FAA7F26702F453DCDD66827CC20D +:1061F0000C9F6A82B8724E77BBC97475BA2DCB44B6 +:106200007DA14DCA64F6C5FD8087BC5D2C1E73154B +:10621000BAADCC1C7F5D70AFCD1C3F783944E9CA64 +:10622000134A5783CD4BA2F4419213FAF747480F14 +:10623000C6FDF7BF1281F27EF91E09E5D3F2D73F02 +:106240009B03F05DFE9B0824CAAADF44E2F7F3FB40 +:10625000D8F72FCBC3EF4FDF9599807AB6B1FD3ECB +:106260004FA87E1776C34FDDE7EDE972709F2F715F +:106270001A3B6FB22652E49BB2FDBE584E6789238B +:106280003D6ED05389D52C9E141BB310F7FBFA9F9B +:106290002B617CEBE0EDEC7615ED07E33913398AE1 +:1062A000E5E539C8FAAF004E8935FAEF8E981ACC79 +:1062B000C77318F6FF04BCBD99DC6EB61027CA5927 +:1062C000C33EBF78FE2593DBEB6BE34DA1F204F4F4 +:1062D00000C07585CD8AEB5EE12089B51057B029E5 +:1062E0002E1CCBD08F78C6BB4D440D3D2F5313458C +:1062F000D410BBC8E149D09587CE1AAEAB3F4C4B0A +:10630000D57D4F5E94ABFB3EB279ACAE3CBAE506B0 +:106310005DFD140A80D072DABA5B74F533DA66E890 +:10632000CA599BEED6D5CFF1CDD57DCFDBB144F7A1 +:10633000BDA07D85AE3CA6E307BAFAF200F6B880B0 +:10634000B32CEC715BB1067425DBAC52A8DDF222F4 +:10635000AF571E6B45F83FC2F5F523360BEAEB4706 +:10636000B8BEEE72945C755FE69FF5DFDE16F4C092 +:10637000EDB50A1E2FFBF280C504F4B8FC20A58BF6 +:106380003168AFBD9DC9ECB5E9F5B8FA8005E45EAA +:10639000F700F920EF65723F43A17E4C187FF09320 +:1063A0004C5517B713FE03956BEF73FDC2FC26D255 +:1063B0002C831C1072A9299AA09DD7146DC73C9FED +:1063C000DED84B99C04F545E7D0CEDBAB39F683E4A +:1063D0000072AA3302E5D45BD99FA03F7E4BCB422B +:1063E0006CFF62A69DE1C5E252ED28A7F4FAF7A87A +:1063F000B9BB16F07074BC4C56811DE42A1D4AAE20 +:1064000002F777C0DFA676F2B62C82FD5ECB5F3D49 +:10641000BA7211E64D0FD4DFD1A2488C9BD6025D33 +:10642000858C1B9DC5E099C19FD41045BFF3DCAF9F +:106430006D3E2FF84B63DF8D2536C893F9E3382F77 +:10644000E823D27D3FECDF7BBF8EC1B84E6DD1BB60 +:10645000E35661BEA89BF97D13D89A6F7AF9ED587F +:10646000F0D76B771F4CF286E0D1E8EF65F0F511BD +:10647000A52713F34E5F3D3344A5CFDA570E25B160 +:10648000B8923EFFC5E8E7D7B62CD7D167E3A54859 +:106490005D1E4CA3D26D017C345E8AC1F7BD99FAB2 +:1064A00038C080F01A243C8DEF053C8F169D1905ED +:1064B00071FA2F23C3D3F16DBC9E281BCF2F0C94F0 +:1064C000273F81B7BBE09A3814E24CB5167FFA60DB +:1064D000E212024E6F5D6EC07311BF1EE05C44514C +:1064E00016DB37F975F602CC6B9E686DAE04FD3D88 +:1064F00091C73FC3E4355767819D7BE25F93D73CEB +:106500003D8BE387E70D0FCF52C3E6355FEBDCC968 +:10651000540B954B61F82BB70F7E7F9A398ED2F1D1 +:10652000FDBF30DB615E0DA0F320DEB2C58CF1D77C +:10653000B72F471088877FB6D9FC3CE4BB2CFAC53F +:10654000C1114F40FCBB2802F3F11AB69859BCB6F2 +:1065500028D2072187455BBE3704F22EBFA07CBB43 +:106560008CCEABE1170ECC077ABBEBB12180A73301 +:106570009C9F177DFBE33B00FEBB2DF6BC22FA5C23 +:10658000B64BD2E5992FD916A92B8B7C22813F22BD +:1065900005F3CF552A4F5BB2F4E768C605F7255AD5 +:1065A000B2B85CBD9DCE77F9F80B16C0E3C1C351FC +:1065B00038EF376264F473FD457FFDDD185AAEFC99 +:1065C00056C1BC7E637E12218874B290E71156BE1C +:1065D000A2F49D0380B27F6533F2096D17531D92BB +:1065E0006F5DF973E64F5746B23CE001F3960CF944 +:1065F0004AE29C45BF3CA5E0390B9D9D22E8E6A9F7 +:106600002C3D5F1F3CCCF292161EE576E535E4E6A4 +:106610003BB08E0CC0D75B75B06FF93687C6DB9781 +:106620003F5B3B8C963F9B2041648E7C76393CDF00 +:106630007C26F4129C0FC80EE2679A6B715F19D822 +:10664000F2D609F7E9CE2D0C5EDE5C5D9EDC956529 +:10665000C1F18DF2DD48F7FFBFE47B6DD1A1515E42 +:106660001B3E5F80E7D9DD4C3E1AF9DC28CF730D65 +:10667000723028C7659D1CCFE5722028CF2DF89D6C +:106680009A69B81E6F89E25B23A1FFF31ED07D7E5D +:106690008C9A584E9BACB5A7466B57F747FF2FD443 +:1066A000EF4AD13ECAA27C34FA97B955608CE7ED27 +:1066B0006A3301FFF60E608714A41AF282787C48D0 +:1066C0007C3F9B555E00F9AA7B54F614FC594C990B +:1066D00090EF2F9FCD62FBCB3F01BB67F97F5E44FC +:1066E000FEDC12A5391558CF708B2B74FF563C2F4A +:1066F000727E1FF87CAD3EDFF9743A6178CFCED65A +:10670000EDCF807F8FF90107A2106ECF3ADD9701A0 +:106710000EED4EF7B730AF32A7FB1F59217859CB9A +:10672000D7A998F4716BF12CCD16F4EF413DBEA0C2 +:1067300022BCFC4DCD6679C1E54FDF350AECCEBFFA +:10674000ECBF7B14C8C7AEA74AAF6A876EE0FCF9FE +:106750006F5CEEC7F3B8E34F816F683901E296B41E +:10676000FD028B27333EA41F73763CDBEF2EFF83A5 +:10677000278DC2E5D47A19E5F7A9181667FC2446D7 +:10678000A9D9C6DB25E9DAB179CA40F7948F951803 +:1067900045775EA21468DA31F03A4BB3991EB51012 +:1067A0009715DA5B0EDC6205FCCA92DBCEF2D219D9 +:1067B0003D4CA423003DFC98CBB1BF3BB5A26C6C13 +:1067C000C7F4ED44AE6F9518837E1D115E9E89E778 +:1067D0004B4E7709F473A7D35D9AED80B817C903C0 +:1067E000BE698F0A9FE77313C7DFDF853D4662D01E +:1067F0006FC6F164DC577567635CCB5301FDC1BEA6 +:10680000AA59023EB0F3FA6E89C52B3C37C377E232 +:10681000744BD328BC4BFE4CF03CC7DE231512EC66 +:10682000FF2675574920C79238FE8CF3E8E170DBEC +:10683000C3F325FAF31DF32B6670F8EF513DC85FE3 +:10684000AD299A13FC55C8CB03BC1AF32C7E99CD05 +:10685000F6D5B644F5E0FEA0F76E82F97743CBBCDF +:1068600012E40F25D7B695538C93F9D9CC9F4FA836 +:10687000D19CE0870F775AF09E8AC1F25B7EBB1BEA +:10688000E325C51A3BAFBCA9DB1B9949E735A45BDF +:106890002BB7D0677ACE105CDF50D2BC8AF909AA38 +:1068A0002EBFA958ABC07D7231EF92F9CD6B2C2A67 +:1068B000E6C3ACC80EF16B929779C3E63B19F7B902 +:1068C000D708BEE4F908C53CFFA078DB53984F50C9 +:1068D000BCED66450A91339BB2CDB8FE3387968CEA +:1068E00086F50F94C7DA96CDF0F0FD6C265F06CAE8 +:1068F0001F5BDF2717FAE58FADCF7684E4D7349E90 +:1069000047F9D798CDE4FCB3905743E1FAEC7C917A +:1069100057B34582F5EEB5B44FD905F35A6EC23C74 +:10692000A6BEBCA2F92CCFADAF3DE417D1F7CF2E58 +:1069300062F945C37C1B705FE26224CBA3B8B83D0B +:1069400082C0B9A467B76D1C02E7109FD54C6807D9 +:106950001AE70F0782785EA419F225018F20AF0491 +:10696000FEFAF28F78FE5ED7F69771DE623E9450A3 +:106970002C00F7F41C36AF253B764F01E21FBE2CEE +:106980004182B89D98D7B5E4FE4B9C2F064B872FCC +:10699000E430FE08A31F5FCDBE3EFDF806E089EAA5 +:1069A000C703D0EEBAF523D78B424F8AEFDD9C2E7A +:1069B00066660FA81FBBB3C3E84715F29E31EFC848 +:1069C000E4DA1E065F3378BF37BAB54AE0E7A2348F +:1069D000ED4FD0CFC409BE8310072DADF11E047E4C +:1069E0002F96F879EB294C0E24F690FD10838B3FFF +:1069F000D1E3863CE5AA6C966F71C36937EEB3C7E5 +:106A0000798804EDC53D066D09ECBCB371FC499C69 +:106A10002F4C4F06301F2EA9337C5E6A412AB3D714 +:106A2000A8BC3C0B702D194DE5694A7F791A067F89 +:106A300017A07ECE2EFF01A835363E3D1ACCAAAB5C +:106A4000E0EFAF0C7FEE4BF014F8CABD22EBE2781A +:106A5000025F57F8FC6FCD70FF03C639CCF97B207D +:106A60003CC6E650FC8D07FA66781479C03B0D767B +:106A70006A450EC3CBE41C7D5C2804DFB139E3FB1F +:106A8000E35BC8F1BD47F6C880B792AAB635800768 +:106A90008AD7A41CDACF0D65FAFC4F235E853C34FF +:106AA000E2D78857910748F1313A278CFE12FD183A +:106AB000F558889CE0FBCE6A5F7E07D8CF224F5CFA +:106AC000AC43F0CF240E8F1B35ADD2C2E8B410C654 +:106AD0009D38CB77D00C74BAC87BD0124AA78B09EB +:106AE000DBAFE2F348EEF1E27A869DD0CAE179C3EA +:106AF000693FDEE331B499AE8704D733B2FB38E6A1 +:106B000063C2BE2CC49BF61E3980F31ED1DDC59E28 +:106B10003C8FC8A86F83F9B7AC9F17B8FC6A3DC714 +:106B2000F2F85ACB99BEBD37C35D99837CECAE8237 +:106B3000F9AFC8705743B92095D14D6C8EFB6628CC +:106B40008F1C40DFDF9AD3B74F3D1DEA253D40BC87 +:106B5000E21E1488C327412410B6F09BBD9285C263 +:106B600035C94DD0EF1C9DA8AD82BCB7C044E282B0 +:106B70007C80B83A7B39C02B61916B3FC0B3F51C68 +:106B8000BFCFE53E82E7BDFAF2ABB454CCA700FE1E +:106B90000DE5977A3E8FFA1CC607D4DE9993C3E6BB +:106BA000A5C1BC84BD23F87220FB2584AF1BA0FDCA +:106BB00075F0F5F29CEBE3EB15398CAFEF8776D7E8 +:106BC000E2EB1FE4F4F1F543D0EE5A7CFD28E7EB4D +:106BD00017AEC1D73B78BFFFC5EB87E1EB47C3F1E9 +:106BE000B5CAE94EF0C59E2363A3215F601BEF2F5A +:106BF000447E6F80F6D792DFFF049F6F867EAF657D +:106C0000A78A7E05BEAFC527B1B91E8483B0474FA2 +:106C1000A733BC0BBEA7FCF29F007FCA2F3B39BF36 +:106C2000FC92F18B8AF58CFCD5A7EFBA4DFC1E11B6 +:106C30007B7468DCFBCD9C7EFAEEE59C30FA6E241A +:106C4000E1F0AA61726404F1CAB1D06FAD1DCBF658 +:106C5000B37674F3634F05BC00B7F77298BD513C2F +:106C6000403CE1779C4F92BA2B50BE50781ECA0927 +:106C7000D16349C43E15FC9CCF73D8BAC64D701F72 +:106C800004B964777B309FDB91CBE022E044DBBF2B +:106C9000134EEEEE037CE4F7F71B8C7838C8E7FB65 +:106CA00039A71F63FF42FE40FF05D8BF6A82FE4539 +:106CB000FB3F07E5D047B08ED2079A65585712714F +:106CC0004783FC1172928CA0ED8BFBB7FF34D8FE8A +:106CD00053584769336D9F1F6C3F92F8315F2761AE +:106CE00011955304EC7717DAB3EB55CFB91C9C27F9 +:106CF00061F2AADC84F2202BDD8D7C174EFF43FD70 +:106D0000EBD1FFB01ED0FF83911357383D81FE8732 +:106D1000713ECEBA86FECF65EB8ECBBDBA9C88CFD6 +:106D200065FD3A7207D6FFB961E4C41ED58DFC1427 +:106D3000868F12721D10677127423BCA4749501651 +:106D40007A87B61B02EFD7AB0C8EEB6B4DD9685F21 +:106D5000932857387F262D3766B0F945697C9ED732 +:106D600095FFFADC8F7A2C006F91A722C635E6BD1D +:106D70000A3C2EEF94C6415CAEFCE0658C93F4EEC9 +:106D8000FF1BC649948CB9E360FCAED758BC44E401 +:106D90009588F157703FB25ACE6F8738EDF91D16BE +:106DA0008C7FCA44DD5846E7D374C44C7C2807D98D +:106DB000F965B14F6BDED1DA0D71793309B9670727 +:106DC000F59D1A0774693EC2EEBB2149EC7B33B1D5 +:106DD000AE62F730EAF769E3DDFA7DDAC41AFD3E08 +:106DE000AD88232E256C9E0E8F7EDF76E82CFDBEAF +:106DF000ED304DBF6F9BBC68AC611F57BF6F3BBA96 +:106E0000A5C2B08FABDFB74D5B37C3B08FABDFB779 +:106E1000FD8C343F5D46D79D2BEEFBF1BABBE15CA8 +:106E2000F47C3EDFAC4DFA7DDD2F76D6E07D21F39C +:106E3000797C3BC7A7DFE75D2A2F433A266DEC9CA0 +:106E40007333FD07E0A690C0E164C83FF0492E3FD0 +:106E5000FDDCB0497F0E7A71C7166CB7D8A77FBF2B +:106E60007487BEFC402EBF0786C7BDFBD3410CCB49 +:106E700063D8CCE2FDB237CB40077A7CFC6FE942A5 +:106E8000E57411E1D4D345A4AAA78B8637F796C041 +:106E9000BA8DF08DCED6D38B11BE36979E5E045C34 +:106EA000A99EE4F9386E5CEFC20E893C23F587EBAE +:106EB000A2CE0DAD700EDD0857427CB8EF6C84AFEA +:106EC000CF00DF73AAF63CF0DF858E07F0BE1FA26D +:106ED00069E3A0DD55F263FE83D51F747E4C3BD47D +:106EE0000FFAC9FAFC985EC8E31A430691C775F019 +:106EF0007F20AF2382CED00CF1C6092E6BF8BC2DBB +:106F0000EDF55CD4336E82F19E3F10D71A5A6B8D2B +:106F1000AD24EF1A718103B9684769789F466937D4 +:106F2000CB73234AB71DE2BFE1EE6F349C6B3A0A84 +:106F3000EDFFD9FBF184DD48EDF43FE632BDFB2ED9 +:106F40003CFBEC746EB7097B7BA07EFAF25C0678A2 +:106F50004A0764CCB30A4851AE70F70D9DCE95C276 +:106F6000EA0DAA274EE73A42E25BDFBB7018F4074E +:106F700085F717F0DE66A3FA5B1A94FEEE05386D0E +:106F80008C8E45BA0EBC29FBB26883F356350ECE03 +:106F90009F1BEF2711794FCD70FF08D52765E7B309 +:106FA000E3AE96675066B89FC6788F47EB589E67EA +:106FB00092C7D6F96B7E8FA0334FD29D9711F1A85F +:106FC000A6752CFE0AF70E7686F4E3CC6387566E20 +:106FD00056CB9D790E8877B178616B8A847642AB07 +:106FE00024A1DDB039BDC29947FB3F945B3E14EA52 +:106FF000D9F9B84E88458FC7F33E381FD5705EEC7F +:1070000018AF7F2CB7029FCE3CE16FD97301FF13FD +:107010005537F66B91C3EFAB8FCC63F64F35F0B4B9 +:1070200023C84FD7734F8325A9FF3D0DC6FBCFDC87 +:10703000D9F62E5007C67DCF17AF754FC3BEF0F7F8 +:107040003400DCA31382FC5092A7BFE7AC23AA074D +:10705000F741036FCBAEADA4FFBA6FE6785CCFCF3C +:10706000853878FEF728BE9FD2BF3E83D39601E2D3 +:10707000BD13D5F26A80F307E99E9B010FE29E9D46 +:107080000E8BB606FC8FC04B04E791ED2307A05C86 +:10709000E055318FBC35C51B8DF7011499D09F5732 +:1070A00037B51D8C4CC273B609921A942766857841 +:1070B0006D94CE16C2655D60DFF5CC3D60A3DF1D2B +:1070C0009B6F93E0FE9636D256190B76D766123632 +:1070D0003E58CFE9696AF9018CB33B02ECBC5FFF13 +:1070E0007A26E1276AB08ED280364E4A0DCA251420 +:1070F000B9E03F75997CE1E2B559E9950BA15D8155 +:107100008F848DFF55F37B66EA54CF32ACB7CF8FB7 +:107110007E518390EFF34D04EE37BC9DCBF3DB370C +:10712000B3BC5C72F9CA15B924787E8AF64F403E2A +:1071300035CCB4E1BDB10D9D2978FF16F14878CF6B +:107140004B53E7310F941B8A8BED106F76BF4F24A2 +:10715000B8970DCFECA11C54C8A742DFA2FD9084C4 +:10716000FBFD33385D8BFB94A81E591F4DE1DEB04B +:1071700079D501C8EB7EF779DA07FD7442D64EFC6B +:1071800090F6FB5DAAC45AC6C2532175188F766269 +:107190003F33793FDEBFD171ADC171BFDBF926AEA0 +:1071A000E7849978AD947ECD156C68F30FE230DFFB +:1071B00058E4AFDC616DAB063DDB6B0914C2F9A985 +:1071C000DED7DE1B09FBD41FFE9F0B36B08FFFAC52 +:1071D000046CF0FEF4C37FB4C1FDC81F3E2CE3BEB7 +:1071E000DE1CAE7704BC9FE7747E31CFF30CD0E792 +:1071F000BD2BBF2D09CDA3272D0EE49FC53E1953EE +:107200001E04DF2DDD110D16515FB9B13D5157162A +:107210007AA411EE6B0D43472738BF2CDEB5C502AB +:10722000F70B5CCCD376C1F8A715463FA7F7D97CFE +:10723000707FA298CFDC5D4516B04FFEDC1941FC93 +:10724000A00F956E333B4FE6AE95283D681CEFC608 +:10725000791E7E3D1AFB5BF014934FF574AC160A51 +:1072600057AD7331CA21E33A167CA84E86731C0BC6 +:107270001E9508ECAF40FD8729DEB4961F639EA8DB +:10728000719DF55EE37D766E948F0D1CBFF3D6E99C +:10729000BF37743E8EFDCC27EA7AB0A717B419BF6A +:1072A0004FF90CEC9F06833C7B278FDB5B25A414F6 +:1072B000EE9D39604D8BBBDABDAF6757DA91383F31 +:1072C0005F69C5E7E995049FCFE4A908F7659DC705 +:1072D0001E04FA59DEB1DB02FD1CF48D4F82E3A3DC +:1072E000533BA72860774DE5FBACB3F9B94E74AAC0 +:1072F000D979CE1EC053558CE13C275F771DC7035B +:10730000B126229DD5C17A0BE1BDF275E87ACE1F78 +:10731000498BC17D3AB1AE52BA2E79F0EB12EB1126 +:10732000EB13DF1B65763FB0B19DA0F36738DDCD71 +:10733000DF765BEB700A8A35AF7D36AA87F9A968DC +:10734000DF5772BC555A1F47FBBE92E8EFA5A27FDC +:10735000C7817F05BD35109702CC6BA42B816712C6 +:1073600063F6F2FBF9D1FEEFA3A7CE7F43B8087C0A +:10737000537E71F2FD3427ECA751BAD2D9DB948E3B +:1073800074E5056DFAF297E69E51C0EF0D86FBA1FC +:10739000BE34E45F88E7A5BC540607D53D19CE0787 +:1073A0002C209E56B6EFCACE1F9D56DA0EFF10F85F +:1073B000701BE3833F73FCB7E47B46E783FE52DC3C +:1073C0008520EF2B560F939368BDFAF5921DF86B4D +:1073D000DEDAA2C9C09763891BFB9B9D18DE7EABDA +:1073E000C8677A646EB39958A8DD3F978E01726EB4 +:1073F000EE3E19F91EF2A6A60D817B26183E1A1F35 +:10740000DD6D19469F8B9A1B98FDE0637C23EEABE4 +:1074100015F427E4FF92F5FBF1DE0DEAB7E8F8ABCF +:1074200009F2BD0B818F0DEF9B6F463C3411F6FBCB +:1074300005027E37E573BBC1455C409FDA83362B7E +:107440009C17B9D6BA49FFB803C625CE1FC940BBA1 +:10745000F3BCAA0E857A1A1DB31BEC48452B85F7A1 +:10746000145EA8A702ABA2F11ECF939764A2427E3E +:107470009B5D2B053BAAE7FD9178CE5DD0AB586FA5 +:1074800093753DD26B13D1FBA3F5D4F181FDCFFAF7 +:10749000ED8998D744FB2FEC007B63BB19ED092FD6 +:1074A00059E184F3F69E47CC2827E776C4A33F3CF6 +:1074B000772DDB2798BB2B1ECF07527F14EF1116B9 +:1074C000F838B9B6D2320CF19582F7F3900E3D9DA3 +:1074D0000B3CF5F7270D785AB7FFB053EDEF5F86F9 +:1074E000E0E9D400783A158AA715F95C8E703C91D2 +:1074F00087B9FCB9EF5006DC5F75BE3912CF83182F +:10750000E950E82932FF06CCBF1271AA9AE10C2F8C +:107510004471619EE285F5E3116F467CD5FC631EE4 +:10752000E285BC6FC3FB8B67A7B17B5BEE9518BF91 +:10753000CC5E33A506F4F9E3F9CCAEF93D955BEEEC +:107540002C6A8F53B9E5A672EB8F549E41F9DD95F5 +:107550004E2CBFB752C5E79F5666E3F314DF5715AD +:107560007C4409C10276E3867C26C736E48BB8E109 +:10757000034E302D6AFEF1C7F1F03B0A0EEF943B4B +:10758000AA471272AB5BAF0F67CDD4EBBB1EB37DC6 +:10759000B213FCDB47D93D4C733D37EAEA1345B5DE +:1075A000C07968923D2EF81EF94DB5C07DE977D5BA +:1075B00026EAEADFB12E5957FECF7C15D77D5B4D09 +:1075C0009AEEFDDD7579BA723DDC9B0874AE4E40D3 +:1075D000BE7980E75552079DE1859F23FCBAB974B7 +:1075E000E8F7E97CBF3E6AC6EF467C08BCCEDF24E4 +:1075F000138DF6376F13955F748AA7DA289E68BBE0 +:107600002F4ED8D00F69DD35EE9D09B47C729719E5 +:10761000E30727D726FE04ECA793BB1CB1843EB535 +:107620005699DB1976BC4F49F45BB976159E87A94C +:10763000F745B8D09EE8F2FEBB28ABE0B7C2248184 +:107640006F8ECB3EBF84F863F1839D11680F9FA6B8 +:10765000761D5C3D7B5A226BE10907E6E3E8F76F94 +:10766000BA1D3EE0EB9A7FC86E27D0D3CE48767F16 +:107670000838C3F4FBE7C732B63E86F4A5B6FB91E3 +:107680007F23D05F98D7C3D647A4B1C980FFD3F179 +:10769000C41D4F27D1B8E2BD8F148AA7C599DD85D7 +:1076A0007EDAAE2EC5EFB893B63BBBCDCCEE97A33A +:1076B000FDDA69B9F197115B983C710FBDAD2014EB +:1076C0009EBE425877D670CF87F9B07FB0D057882A +:1076D00072ED6107F29511EEA72C1AC2D70B7C2030 +:1076E00005E56490CFD87E10156EC340DECC33BB69 +:1076F0008680BE3AB5DE8C7629D527B1B7611C6687 +:107700000FD2F129459D0CEB3EB52E8580DC12E3AE +:10771000CE5D2FF37B42285D42FD0DB2466D072200 +:10772000F496779DA491A1FDE9E6FEFB4A312FDC9A +:1077300068FF8AE7979457B5103B62C96BEC7E7E71 +:1077400052DCA3CC2C085D07FB7D05A24DD0E56B78 +:107750002E4BFDED473126B46BE2209E7EE6B88CC1 +:10776000747626B5ADC44949FFACE940C9F769F95B +:107770008B69DE4F155ABE6FB416554097B4D4B41A +:107780007E14F84FBD9D9FFC04EEDDFBFC45331CD1 +:1077900087274B762E1E8D711F6E7FF7975BE2FE5B +:1077A0003FF730B83F65A9DA8E7A5C854372B87EC0 +:1077B0001FCE53E875FB9312D858E493F1B6C7C0B7 +:1077C0009F9E67389FF28999D909230A989C12FADB +:1077D000FE1E5E9E6762744D5E97300F9CF07BE5E7 +:1077E000853E10F25AC8FDFC02665F08790D997655 +:1077F00020B716C2ED2D749DCB7644F87C29D8D6DF +:107800000E705CCCD0441617A8D86E89E5C5A78148 +:10781000971A4837CEFF73B36F61770AB4DFB23679 +:1078200001DB9B5D18A7E5FA05AEB506B9D4C0F932 +:10783000AFB14DF2F9917F989E5CC0FB27A06742E3 +:10784000E4583FFD62D02B0BB85E5D400C71DE3614 +:10785000BDBEF344DB705D4BE8B8A03F83F3A2F6F6 +:107860003385DD42CD77783ACE5B72F9C2CCA38105 +:1078700004FC907FD7B88BC5BD8DF332AE63B0F3F7 +:107880005CE8BAAD2ABE38645CC3BC05BC31501C90 +:10789000820701F7855E06CF859D12E2EB2FDC5E45 +:1078A000A37F189F36E2BF8178A6439E42C39354BC +:1078B0007EA604E941D0C1E2DD3E0BD8CB5F90B695 +:1078C000D818CA07CB36EDBE63A20AFEF331F443E3 +:1078D000EA12FC19A6784212BD2F3D5D73D3B5E3C1 +:1078E000FCFF2A38C12AE07E5A6C47E1B2609BEC6B +:1078F0008E2CD4D5E379DA5E84D722AFD70271D04B +:10790000453CAE78AD793629EC3CEFB5E7CBE0F8F5 +:10791000AF9EF7D3057A3B36681F6584F5B7FAEC5E +:10792000A26BE8E30FCCFE91A08F032315D4475F31 +:107930002BAEF7CA93403F67A0DF3090BC5DC8F51F +:10794000F202D0D3F4F9E9A6BD786EEC2F4FEEC564 +:107950007D43CB8B0B62C15EFE74D3BC9F40DEFCCB +:10796000A7BBE6A15E6E7846E865CD12AAEF2B377D +:10797000D53FF77F804E7744E20985855D1AB7C70A +:10798000A9FC03B9B889C93FF224938F0DB1ECDE8D +:107990006FAABFB2A0DE830BB52CA0F790F7A8D7D3 +:1079A0001E9CA795627B62F7B37B21ED7ED05F4280 +:1079B000BF0ABD7B7498D655007A413EFAEE4374F7 +:1079C000FDE7F6C818D36994B78C82DF4318488E58 +:1079D000FFF3F036F5C13B6510F09E0BF0467B8857 +:1079E000C1FBE3750CCE9FAC67706FDD95160B7E07 +:1079F000F0C7EBD2D00EFA785706C27BFE6314DED6 +:107A00006807AB7A3B681D8537D8FF006F3AEEDC1C +:107A10002E95C3DBC5E0BD8EEBA1F5EC39BF1F5C35 +:107A2000BD986FFAE0F3112ED0EFA723FD0EF053AF +:107A30004EEF9609ECE7F7D949DC9E1170FE86B44B +:107A4000FD3BD855FDEC9B0D11C44EFB5BFC920D2C +:107A5000CFD57C2E950F05049C6DFB6D2C8C171CCF +:107A6000BFCFAEB954106AD70C123FCB8907F3DEF3 +:107A70009777FEF604D8F570BD0AF8FDCBC539F846 +:107A80000EFD397849059906210A97D50A7430C246 +:107A9000784F8086BF0F7131E3AB392B909F0399EC +:107AA000A1FB414D517E33C4A302BB25C477E30340 +:107AB000E5B1E504F6B39A711E8E42A69F25B71B69 +:107AC000E38C11946EA2E878CE4215E72BA97616C6 +:107AD00077DC4CC7B505E76B7C3F1D0411E8F71850 +:107AE00013EA77E3FA27F3711A6513FA21CB2CCC4A +:107AF0001F11791319FC7B4621F3EBF30AD93E439E +:107B00006F2441FDD1BB21DAB70AD75785F14F85E4 +:107B100030FA5604DCECCA97BA7BCA797C017EBF86 +:107B2000008CEAF9113CFE4B552DB4BF87B7BFA7B7 +:107B3000ED6DDCCFA39ECC2F40FFCE6E8970813DD2 +:107B4000EB85FBAD28DDFD388AEDBF90A43805F844 +:107B5000EA6E2E67EF697BDC03FA68765BB41B9EE6 +:107B6000741C2FE1F1D662D8BF1D6EC1786B9DB534 +:107B7000E74530AFEF757EF23D2B5DDA2A13B35F38 +:107B8000562510CC3B1943CD7888DFD24FFBAE246D +:107B90005E8D7EF4F1E46510D765F7B579519EC826 +:107BA000265D7919FF5D81BAC2CC3B9F1C41C81F7D +:107BB000885A00F85E06B0017AA88FC3F8C0AD10ED +:107BC0005F4E80A782743643215E137BAE8BC173F8 +:107BD000FE2CDE3C9DAFFBBB13883F8EAED7FFA6CD +:107BE0003EDE7DA7DFE4CFA278B855F1EF07BA36C5 +:107BF000595533F8079E1A692CF8CDCB560F6EBE37 +:107C00004D854538DF6526139BE74312DECB700FA9 +:107C10006572A0CF390AE992C732FC01FD3525B063 +:107C20007B8003F731FA16717681A722DA7D287CF2 +:107C3000EFE1F3A3FDAC8B85F696F0F1A51F160AD4 +:107C4000BF98D99D4B39BF2E15F4B64BCFA7CF02A5 +:107C5000BF001F819D4BE1760F7F0E44EF9B38BD27 +:107C60006FE2F4DECACB831DAF3182F8437FAF45AC +:107C70008C7B2B7F3E5D988AFD8979087A263C3E75 +:107C800065A29203E8E854DB1AB49B1619E2C524F6 +:107C9000348E25872BF7C91FD315785A02F3613E1E +:107CA000D277225D40D7F758DA33D8BD12FA7A621C +:107CB000FFB70E6EEEC2F33A44F77B0AD5720CE6BC +:107CC00013D549EC5E99DE729BD744EDC50FF8BD24 +:107CD0000EE79BD9F9D0BA87F8EFA0C43D381DEC68 +:107CE000C3BA588B02CF0FF8FD72F7926E5B4A4A07 +:107CF000D03E692D97F9EF6ECCBDD39D0FF74410A0 +:107D000051DEE81E8151255E6E780FF63B665EA659 +:107D10007480E54577BAA9DCE83DC4BF7B6919F0FA +:107D2000F888A0E746ECAFF729F1FD3E567E547C7B +:107D30007F9095FF4DF4CFCB1B0CDF5719BEFF9CF6 +:107D400095DF2C7CF04E2FD8B57C1FA7EE0609E5F9 +:107D50008A95D35BDD6A3FC2B9CE74803D2B881F04 +:107D6000CED75EABDE37851E6BA103EE37386503D9 +:107D7000FDFDADCB8DE5F3F9DAF1425A7FC96D9285 +:107D8000D702F2F2B82F93CBF7B079B9564EBF179E +:107D9000C6D0FEC607E14DFBF9F09FE96775FF7E8F +:107DA0003E85795D6F3FD35D6C7D21FDF4FE33FD33 +:107DB000EC75E9E723ECA3A963DD5163403E54DD94 +:107DC000A88BFB2DFD912B0EEC2BF20EFB1D93A52A +:107DD000ABDB478DA3FD2FFDAF57462D0CF1C797A9 +:107DE0005F92891BEE47B824E1F38BFD7FB2C0F9A7 +:107DF000FCE5FBF65B26E7C3EF2FECB75486CC6BB4 +:107E000099C8B3243DCA8C10FD1E37C6C4E506FBD5 +:107E10001D87A5FF7546017C2E35B57FFA0CC48100 +:107E20006E90C2EED7FE95AFEFA301CE8339C63078 +:107E3000F95756EC4E82755E041944EB57AE09BFF4 +:107E4000CF3F670C8B27D6F17B95E795D8AC2A8579 +:107E5000F3F8E36C7F7AE1E694B110E77514548C83 +:107E60001A03F31D305E1A60F1D24E162FAD4BE8A7 +:107E70007E00EE31BDEB574F6D847B4DA76E147CB9 +:107E800042F0F7726A2204DFEDBAB3AA0CE35F583E +:107E90002E1BF3C246E09B23FC5EF1D9A5055120C1 +:107EA0001F7A52A24D762A4746E4D7DF05F3985D44 +:107EB0007AD364785F1E61CBAC677177A48B11F9BC +:107EC0009E62F80EF521DEA15958FC4B7B4BC6F89B +:107ED000975618AD85DB7F1ECBE170D718764FF132 +:107EE00011139DE7D8E03CC4F8D46079A09BF677E5 +:107EF0006AF5B022B897BF25BF7C16D2131FBF25E5 +:107F00005FAB86B2189F2EB710DE0F761E159C2E23 +:107F1000668D6178F394517A0BF11B675445EBCA77 +:107F2000336B13893B340E3B3359579E5597A6ABA1 +:107F30007FF7FC3CDDF76911DDC5CDD7610737D987 +:107F40006C51608F7DD8F9CD7FDF03F6DD36D92502 +:107F5000D1F52C7E6DFB7FC3EFA39C871F5C60E790 +:107F6000AF301EF6F911F67B7FD4AE5342F775CED3 +:107F7000916ECC2B0CD92F08BB9F2AF60B96DABB3F +:107F800030FFEF7FBBAFD33286EF178C2563411FE5 +:107F90009E6F7E17E370CB63D8BACEBDC2EF2107C8 +:107FA0003D42E9FC666808F7855D5A85BFEF53C915 +:107FB0007FBF75D81895F90523EE53E0DC77137D64 +:107FC00082FC9F4CE5541CA593EEFDA4601FE45D6C +:107FD000A4D8309FBCF1D2ED18E73E12E5CDBF8F9B +:107FE000D65BBA6E0A96975F8AC67E7F2F774FC69A +:107FF000BCE697D9EF214E4B9EBD1AE60FF5EFA7D1 +:10800000E34DFBD5CD3500A7E5FBD8F9A969F21FF3 +:108010008AA19F656D53B0FD34991C91A8BD10775E +:10802000E91EEC771AE87A5A964B6C8F81FE952DF3 +:10803000FECC6741AE586C28579A2E4562BBA99575 +:108040004C4FFBC6303BC6DCC3E6557DE936FC2E03 +:10805000F0FFC29854DD3D3266C73605CE27987BC7 +:1080600024AC7FCBA53C7C8A75BE95FD3CDE576277 +:10807000767C3D19F23ADF4A92EC687E18E4EE8590 +:10808000E6D23812462EF58D7389E501475C627998 +:10809000C12F14B93B81BFA73FDCA3C0FE0E89B13D +:1080A000DA015ED32714A90B43F8493E709705F017 +:1080B000627EF29805F47E047D56867C6F14F9EB9F +:1080C00006B97C80CB01717E41E819A276E87E5F1B +:1080D0004DF0CBAF38BF8AF6DD40EB80C79722D09A +:1080E0009F7AA3487B17E6DB5DCE7E278328DDA33E +:1080F000605FE55F357F8A67AB84F67E0FE6C54F2C +:108100009FA09A60BFE0FDBE7530BEBDD63A7ECB63 +:10811000EBFF5E262DD0EFEF274DEA76D3FEF6FF7C +:1081200070DC3890FF62DC2FC6B073C3C41EB80C7D +:10813000FE5DD3EBD12AF0F73470968A83762D7DDD +:108140008FF7E535BD1EB155A2DF9B62A97F4BC7F6 +:10815000AF7C23D20F74BCFF8D48057FA7A858FBC6 +:1081600002E465E51B5955E0CFB93B231482768EB6 +:10817000FB2CCAD501E67B2D3965A433C197DA3AC9 +:10818000C62FF59C4EE772FED3381F5D681E8A7CB1 +:1081900078E1613A69D80F7D582AD80776816AC399 +:1081A000FB89055F4E033F88BEFF7F46E48E2C00AF +:1081B000800000001F8B080000000000000BC57D40 +:1081C0000B7854D5B5F03E73CEBC9299C9E44942C0 +:1081D0001E9C400841024C26218410601202A2021B +:1081E0000E501530C88008110909515BACF6CF84D8 +:1081F0002410452D56DB068B74C04751696F406CC7 +:10820000D31661786863F5D368EF6DF1D6DAF8B804 +:10821000888A3582F5A3B728FF5A6BEF9D993349B9 +:1082200010EDBDFF1FE53B5967EFB31F6BADBD5EA2 +:108230007BED9D79E312432D0A63EBCE253296CC7C +:10824000D83C95752B498CD59DCB65AC98B1F5E79D +:1082500092E97DFD393B3D579E1B47EFADE754E664 +:108260000378D53985F900BE6AA633684A60EC42C6 +:108270005120D3930AEDB45C3E87B9180B6CCA2821 +:108280000938189B7F57AF664B618C392CEEC7A11C +:10829000BFF96545E9ABE1FD05FC99C158CB9125D6 +:1082A0004C7742BB297E8B0FDEAF82E7CCA8F29BD6 +:1082B00018F37502CC987B765A097CDF9A6BBA87E3 +:1082C00045CA758F89B14958DE4CCFF9B2BEDEC5BB +:1082D000581A6337B819FFD90883CB60CC29EAAFA5 +:1082E0007484479BA03D7383DDB309C67526459F03 +:1082F000CD006EBC1B004041A3D93FD309E36EDC27 +:10830000AE7882F0F98DA54E1B8379969E68B004F5 +:108310000A23FD2F393781E9808745E7F2E8993A4A +:108320003E3001F1B0E2DCB584AF95508E4FA69798 +:1083300099703CB7D9F0771C10C0A58CDD2AC6F720 +:1083400059C3E461DF81FE3F7BD94CE5937CC11BBF +:10835000703CE690D5B30BC673CA1E50198CE75417 +:1083600036733F08433C65664137D0EBC60E950532 +:10837000A1FD55F00CC0F35422F3257A119F30CFA4 +:1083800002DEF605F8F7776D5B0E1B05F46DFCD386 +:108390005BDA48C66ECEEF991086766B2AC3A9D7F2 +:1083A00041BBA71F337B82D0EFBA23AF979AA0FCC3 +:1083B000C35CDF30A632366678600ECE67EDC2D081 +:1083C0002FCC00DF72DF33AE297A049F9D5A78B438 +:1083D00006DF77021E8330AECE7BD53921A2178B04 +:1083E0005F301E1F803DA83A7B81124C00FCB1EA31 +:1083F000A97CDE363EB6B5E746117ECE3658C71F9D +:108400008076CEEA4E0FBEAF3BB788DEDFD27E0568 +:108410003DCDBD5708BE8CE7FC9AB96C13F2599D4F +:108420000695E1BB3A47422808F399F76FC07F8071 +:10843000F2F50716F82B91EF0A14CF6878ACDB76CB +:1084400085E0F3DDF797035EE77D92E26981F7BF90 +:108450006A4A076445F87FD6B905542FE1DCF5D4A4 +:108460009FE47FABE07733F27F14DFC3778CC17773 +:1084700081A2C09D88A7AAA7FFF9CC7FC2AB2BB56C +:1084800070FE4F52F0E924FE89AC039BFBF15C5A6D +:1084900007FAEA283E528F2EB1E8802FF3436FD3BC +:1084A0003AB0C2736654F97AE4EB42C44CAFB6D02A +:1084B00019791FFC9AFCBF5ED49F6365CBFDD89EE3 +:1084C000D69313DDDEE1A2AA073D50DEE151787BB1 +:1084D000FF43E3063CD910BF307E1FD26B7E996EFE +:1084E000BA2717FB91E3E77CF255E36F13F55F556D +:1084F000D9466CF7D519337A7CD0DE913B8B8B55FE +:108500003DD2EFD31E0BB5370F6887EBA8EF396B61 +:1085100068772E8A11C614A8FFC9736343F7C01485 +:10852000DF627DE7713CC183F13ACEAFFE503CD5AE +:10853000AF8F4B0829505EEFEACBF7C378661EB6C3 +:108540008791AF8E1CB66B0CFAAD28B9F169C4D314 +:10855000CCC363AA15E043DF41ABC6A0DEDF27F83A +:10856000F6221F0C357E39BED8A79CBFE42BB95E1E +:10857000E4FA90EB2176FDC8F570D5564FC277909E +:108580004E8098C771FD68C1BD388F3A3DBE08D78F +:10859000A55C47EB0F28B4CE40E87A46EB917524F2 +:1085A000D74D649D98080FF3849E186A9DD48975F1 +:1085B00071935817723D1C533B1F2C87EF661605AD +:1085C000FE827892EB62DDFE58BD30245F31E4AB71 +:1085D0009B521A18F2551D3CA3F9CA3AC47A78077F +:1085E000F923F5D2D743CF25F2D3DF919F26FDAFF4 +:1085F000F2D3DF916F06E1A7CFFF157E8AE597B32F +:108600000D7F2AD1613C674B40CEE646F8EDAA9734 +:10861000D8F803F09E8D727A907FBAE3F83CBB2DB8 +:10862000D9A116AC778135201EA5FEBF09E99E1C95 +:10863000E153AF3730BC685284FEDD71C1C20D8595 +:10864000974E676B4A8FC55788F4EE31E8FFBA2121 +:10865000E83CA2E8EBD1D929EA7F159D3D455C6E47 +:108660003037D0B184E8A7235D63E98E7445BAD76B +:108670001FB2EEBE185DD79704A6160D2227988F5D +:10868000DB0311BA581721DF9C0D83425386A6AB3A +:10869000B983E35DC26D614DEADB64D4B7C02F15C9 +:1086A000D8DF37E5977933E1D7E1083EB5D89705AC +:1086B00074FFBE80D92F16237DAE2D93E54F77F83A +:1086C000F250EEC0EFE5D4838FD908BF1C0EEE3D0B +:1086D000510DF5AF7AB0BF3C88E5B32A12447BCC8C +:1086E000A7B048FDEBF73D79E25E9AC736AE0F02C0 +:1086F000BD9A7F7C145C02B0330A2E8B8177F0FA2E +:108700002EAD97B9A99D105FAFD0BEE2E5FCE38F17 +:10871000B2478092B313D19E3CA0B8EF01FA2FADBF +:10872000F8C482F48ACCFF00CD7FFD4145C05D27AF +:1087300070BE4B0F70B879DFC18EA026DA033CAF54 +:10874000136836772A3E15DA5D57A68446E60EC4CE +:1087500073739151DFE18F66FC9E5952BEDEF7B80C +:10876000BEE9FB91F47DD8FA35FABFAE82F9428EAC +:1087700081F51E90EBEB3CC0B27DC0E522985FA86E +:108780007060FDEDA2DD1E9349E0EBB50EC45F8F76 +:1087900045E2B3A7C35701F4671C7E745FCFE26064 +:1087A000211FBE2F66FE171B7F5BFFBA8FCC5F3782 +:1087B0007E1FBE18FEB60EC09FE09F5A233F25685D +:1087C000FEE367A19D8414C58D76F17ABFFD5EB48A +:1087D000FF23FCF167E28F1E3BEBE76723FFBFB986 +:1087E00018F97F3D93F5DFEAC0F5E337F5D7E7EBFE +:1087F00041F2177C5F00FC8426327EFFDCBEBF7432 +:10880000041D441F2A2738EF22EBA13306AE8859F6 +:108810003F82FF69FDA29C07FC8C1E44CEBC29F060 +:10882000FBB1C216A39CECA9E27662CF48FE3C5F86 +:10883000C4EDC2F7041E4F8BFA3D715178C88AD03F +:10884000197EC2E88744CD9BF0B42445CEFBCBC54E +:108850007361DE3D49BCFCF3A2FFEE086645E0D83B +:10886000F6CE157D497C1369FFFC09C4EB1281B774 +:10887000F3455F9C107CA5E0BAAC230601BE38A08E +:108880000455F413902F0699F7F1817C158CF9DECD +:1088900067BEC8F7BF1FB82E7D31DF3373C9D7F964 +:1088A0005ED06D6E0C5DE7C4D0B53A06AE9170C86F +:1088B00020FFA45C5CD9F5405B1ACCE3963D0AAA84 +:1088C00099287E762CC1F5798B5BF2AFF30DB4BBA2 +:1088D00022FCEC227861A7948709DB511E2E407997 +:1088E000581E8117A1BC20D8BDC437315A5F24520D +:1088F000F975EDB27E12C14B5B657BC9DB7D5A8495 +:108900008E2C98B204FB5B5222F44530F50DACBFBF +:10891000F620FF7EE2FEB4372EBA1EB6C5E06547EC +:108920000C1C8CA9FFD057E897D698EFEF8A29BF87 +:108930003706EE8881DB8DDFAF58A5D03A5C01FCAD +:108940008084F8AA7539C3DB6FA7F6EB53C541766F +:108950009B615D5DD5C2E12BF68F5AD2EE8882BD58 +:10896000A397041D91756166FCC79AC2685D9887DC +:10897000909793BDB1EB42CCA72056DFF2F2BFE255 +:10898000AF19680733835D704C35C2475439EEE246 +:10899000376E2BC49712F62EC1F8CA553F36CE0B50 +:1089A000FC55017B96545744D925C1894B70FDCBAA +:1089B00079CAFAB3BFB8A0627FCBBD13973C06E576 +:1089C0003555E1D10D30CE9A24FE04BDA6A2DEAC11 +:1089D00017F198D9CFA97ED46B3571E1D18D85512E +:1089E000F3649DF938CF2377AA449F600BD007F03A +:1089F000B492814300AED99184848D4F40FD63775A +:108A0000AA1B518FBEB531390DFD9B835EEE2F1C25 +:108A10004B18917613C047E2975B74A87764CB2C10 +:108A20007A1E557D9BFB60AD7D6FFFF4258EB1589E +:108A30009E40F8B9C35BBEA419F8FA2EAF4EF80CED +:108A400024B9D3BAD07EBEC7CC1ED769FE3B896F8E +:108A5000EEB316A1FFBCA2795C1ADA932B7FB86043 +:108A60007606D45BD966F628548F4DC07107EE990F +:108A700065C1F255ADE219BC9C9E87BF7CB4C505AB +:108A8000F5FB1E513CBBA1FEB4CF3A5F9A00F09AB1 +:108A9000F6511E24CDA17326E6867EDEE918135218 +:108AA000811FDFB537BC309FD767587FCD79FD95E3 +:108AB000F925585F756F82FA27E13DDAC327EF5633 +:108AC000772B382E97334E81299DFC427F05ED5A36 +:108AD00028776F82F727DB6E4E433BEBA4A2BB14D3 +:108AE00098FFF6FD7397A403BFACE9B00A7ACECD28 +:108AF0005801F35F61EAE717D21FAB1339BCDD3BC6 +:108B000077C9E330FE93DBC7B810CF89C5BE87BDF8 +:108B100080E7B78A7D3FF1A6E238B99E3AFCA5BA54 +:108B20001CEDF1DF9E5E9986FCF4B8583F87CEAD10 +:108B30004C5B1965EFACFE5823BA1FB6E8B7E138B5 +:108B40000FC7652BE82F03DD9317C0FA5D25FC0FD7 +:108B5000E0DF8DCF0C62F704BD2AB57B646B6A85BC +:108B60006EE0E3EBDF40BE24BF01E05FEEBF6E3B93 +:108B7000EAB5F7AC1BD9BBB8F8EE828229F03C66A7 +:108B8000A7F89579AF3D64CFC5F8A76F36CA3D9673 +:108B9000DE99BFD019B5EE44FDBF049D54FF2F50A0 +:108BA0001FFDB7BF04FFEC648E8176FC1A973388F3 +:108BB000C6C4FB4EA78674784B6B3A79077CB7FA2C +:108BC0001133C9FDD58FA4DED587F206F805E3631E +:108BD000B1F3528BCD34AF21D761B0D6B80E592D39 +:108BE000C9EBA1D661CFFE35175D876B849F32FB41 +:108BF00011B31FD7D19A494E8D81FEA87AE4F9C7E7 +:108C000091DFD76CB07BAD30F0358F58895EBD4EAB +:108C100067D00DE50197534B84E75B82BEAC98AFFC +:108C20009B992AD36C5E7AB6629CF40C8C2719E06F +:108C30000F363EF8A3C950ED4316BA7632E0EF0C7A +:108C4000120CF072E6804AF143A6F9B479201F6B4A +:108C500019970B752F3E63A9C4D935AC998B7EDD6E +:108C6000CD21F33BBDC267BB20A689F2B49EBF02F3 +:108C7000BD6A2CAF67F77EAA4E2036B6E07AACEB21 +:108C80008C296FB8FC7D8CBFD433ED9D5E19AF8508 +:108C9000717CEE75A69C8C4771C8BC802176A6C1FC +:108CA0009CCF608A6B1CB0AE60BE33772834EE3543 +:108CB0001BD59015EACF4CE671DFF79A80FE63680A +:108CC000DE4137C06B1EE27A660D534236F8F5F28C +:108CD0001D1B345C0FEB857C59A1303FF2F7BB764E +:108CE0004F0EFAEBAB1FB1137ED7ECBCF98FDBE173 +:108CF000BBDEE67929D1FEB143F005B4CF6C4991D2 +:108D000076DE6FFE5E0EF2FFCC9F829F0BF35D93CB +:108D1000C87EB12417E99591A33B22F5D66CBA33EE +:108D20009FD7033F19E6BDE26E95E6C19EB592DE80 +:108D300083B59E4E7259E07355EB8B164B21CAE9F1 +:108D40007B7B54A8FF0EC0AA83F0151478B420BE14 +:108D500096E3B719FC9BF4526177EB24470238BFC6 +:108D60001A93B27C21C9F53E0BAEEBF26285C63395 +:108D7000B198DBB32B723C37501CF97EAB07E5147E +:108D8000FEA8721CE057D5997A56633C97FDD24AEB +:108D9000F191FA56BBCFEE22BFC3B71FC7A731CDA3 +:108DA00002F858A77379512EF8B05E5F7039F20D52 +:108DB000949FD0707FC5C9E5625D22E09DEB639F03 +:108DC00009FAF9047F1BC5DBCD9810D5BF22DE431D +:108DD0003BBA2BD26EB789B5639C05EB8F9D80782B +:108DE0004CBE76318EEFE72AAD6798FCFD6568E7EB +:108DF000FD5C2D46FF76C5DDC7667720BCAFC88D0C +:108E00004DAEF8C51F486FDC22E8DF8BF63EEA1155 +:108E100080F7C1735131D7FB0195C77D16097C4995 +:108E20003E90E575779B79FCBDCD4A764C5DF39F0E +:108E3000A8DD3A674F1ACADFBA67CDA528A7AF15D4 +:108E4000E35ED99C5D7102F86AA539C1ADC0AB750E +:108E5000C1791684D76D53088E7C979A837CFA511A +:108E6000EBAF5CC83FEFDAC3A3511FF56DB07B7663 +:108E7000E30444DCEDA3D6D1BB313EB3CADDE354F9 +:108E8000A07CD56DA392507EBFE50E5BB0FCADCE4D +:108E90005C13C23EB7BB02619F3691E08F40947570 +:108EA0000AFF13F96DBDC2E9BC6EEF31CB48E8EFA4 +:108EB0004E31DF8F7FFE877CD45775393DF9A85737 +:108EC000800FF23311CF4F29A48FD7EF557DF609CC +:108ED000113E588F7C00EB6EADE083F5077EF51DEB +:108EE0005C0FEB91FEDE817C047C7A9CDEEFDF354B +:108EF0009BF1EF8F239F483D0670AB19E369160184 +:108F0000433F08DF85F89C44E5D5BC3C5848F294C3 +:108F1000F55AD0EEACEF32077BA3F67F86A2F3764C +:108F200041C795CD5692BBDBC5BC7BEF7ED6857421 +:108F3000FCF8E7C75EC0FD92BAFDA0ADF541D6854D +:108F4000C04B3DE2C145F320FBA21EE7ED8AE0A144 +:108F50009FFFC57AAC677C9E72DEF59AC0832C17A2 +:108F6000DF3F2CF8661D13783B3086AF3FB1DE70D3 +:108F70003DA35C95F30B24F1EF259F1E2EE67A614D +:108F80008F78AE03BEF01412FFF82C524E40D1C7BA +:108F9000FB7651FC47D24B8EFBB5883EF12526452A +:108FA000E8D86B62B59D83C44DBA04FEDE6E1B9695 +:108FB000D30578FB08FC2CB4A7905FB5A8FE24DF8E +:108FC000C8FE663EBDE04A9C2FB41FC6F665BF6F63 +:108FD00005E3356CE72DC6D707F227CA4FB92E67D0 +:108FE000B62CBBB2C885F53E768E423B46C8B3D799 +:108FF0008ADDF4BD0FED05F8DED7A550FCF96DE173 +:10900000D7BFDDF62BD7CA283CBD2AC62DF90C7F69 +:10901000302E25C7DB9DC4E3B9B1E39672488E7B41 +:10902000E696EBAEC4F772FC925F257F4A3C4A3E5F +:109030006577A5925D13CBAFC46B52AFAA06794F8B +:10904000FAF1F2AC4F2D01C7C0F7B1B0B487DEC55D +:10905000380DCA8F27D510C98FD6F4E379517A1EFF +:109060007E1CD17AA779C3E5EE4ADC7FDDAB78D0F0 +:10907000E489D22FF76A51FA45DA0525252309EF4D +:10908000F529BE0F908EEB4EF5CC76E9113B74DAE4 +:1090900067613501E3520772BDD1FA74DDE9E3C4BB +:1090A000FF75AC6733FA512BEEFEC3BCC9C8E74F5E +:1090B0009A697F6645DB2C0BDAF5373F7E6329F230 +:1090C000D13BEDA348AE7FF0D8A462E22BE64EBBC5 +:1090D00016F87FD5630F5EBB14DEAFEA523D24DF86 +:1090E000A11D5CB72B6E2F66C837EFDA7BE795A31F +:1090F000FD7E87EA46FB7DEAE393EEC2FA539D23A9 +:1091000012711EBEC79209F66909A41FA4DDFB9661 +:1091100090932D66CE1739257C1DA59670B9915A6E +:10912000C2F966664B4B3EEEA7F7ED02F98CFBCA1F +:1091300016BD338CFD3D378CFC8B7A7087D281EE67 +:10914000A7146E97D55A982DC34BEF6D19F0FE45B5 +:1091500073CFEDA8475EBCDD59D48C0350CF97AEDA +:10916000E4F634DF3F4CE6FD4BBCC9716497707E7A +:109170008F6D4F7EDF8D7E04CA5331FE0F5A9FBC28 +:1091800016F5E0077B4627E1BCDF7FCEDE8EF6D406 +:10919000FB662E1765FB60E7BD176DA7815D6780D5 +:1091A000C18E33C0C0BFEF19EDC24D34AE8925600A +:1091B000C78D63FD769CE4F79A0DA313A2F30862B2 +:1091C000ED779617BB6F3339810D226FE4F374137B +:1091D000200A18F52CEE1142BFD5F15F3CD383F67F +:1091E000FE36ABDB0AF37C0FF91FF7A59E5543B89B +:1091F0000F83B639AE87F7F61585D08F5CFD6660B4 +:1092000036B67FFC812D94677013D897C39428BB22 +:10921000F9A107AE45F63FE3096CCE80EFCEECE155 +:10922000791150EC88B1975FC8D0FF757BF952ED8A +:1092300064196FA82911F6B2877910CF12BFD26FC7 +:109240003A0C7C50E68DE0EB6F4DB564279F6E0ABB +:10925000D0F313E5EDFBA722FF3A133CBBE1B3DFEC +:10926000763DA866229D0F149D47BFB7DC91E0C6EE +:1092700075FBB7A68DB4F978BAA9819E92CE32DE7D +:1092800036EDC011FAEE6F5DC507A7C277871C09DE +:109290005CFE0FD8EFE1F48CCD03B975C3E461F83F +:1092A0005ECEEBC33B385DE5B83FDC73A30BE775DF +:1092B000E427C907A7203DE313DC68EFAD11F91FD0 +:1092C000273BB83D7DCA96F0C45CCC1BD9B1288D34 +:1092D000819CBDE9C8B7AEC5F7AB9F53DCE8077802 +:1092E0009E5BE042FFF4BFB45E971B9FF05D18C722 +:1092F000A385549447E57318ED47958735A6E7D2C3 +:10930000562FF1CB94D35A08F3463EC27D2A8C8760 +:109310009C8FA3780813FB4F37FD9AC751FAFD5B6A +:10932000E1DF4D15F3EE2A4992FB0AF47E66197FC0 +:10933000FFFE8E67E6637B1F3C6676E3B8FFF69818 +:1093400099DA5F0B7E9909C67B6A0FF777D6762A82 +:10935000E4277FB007F435CCAB6E83D9674918C8D2 +:109360008733A1BCD711E1C3B5BE10F13713FC6838 +:1093700083FF2E8C1CC88F89AC7333E2E35FE5CB8F +:109380005FC4ACFB7E7E1C8A0F04BE701D233F4A67 +:109390007AAFEDE0FBEA499D4595C85792FE524EE3 +:1093A00004AB5801EAD5160B2BC03C9CA029CE83F8 +:1093B000EB7B8143372B80874529BDD5284E33274A +:1093C0007139ADCE34F94CA85F5AAC240762E5C8B8 +:1093D000EF845C9F8F3C0DFFDE2DE1768499359004 +:1093E0001F229FA077B2517F2F884FFABB0E55FEE8 +:1093F000FD40ED520DC6BF606AD2EDA33C8CBD7935 +:1094000060FD520DF8774171D2B323017EABA48E7B +:10941000C313932699016E6EAE5F5A0DF5FF59E2A4 +:109420007BBD24AA1FD92EBCFF8F1280378D0B9CC9 +:10943000C067BDC54172FA13A56FC2C6DC48FDD72F +:1094400014F6D66F9508DC6B663968DFBD5B22C702 +:109450003FF8336F92EFED9241DEAF64AC0DE32A3B +:109460002B83BF3BA1703FCC6F037A5D2DF86AA5BB +:10947000CD11267FBEDD7CBA9FDEC8479E040DE974 +:109480003A5FF0D1D55AF8087E3F96B5BA4FDAC8A0 +:1094900084DA71217968F90D0B8F9D94ED01BF7C01 +:1094A0006286F9025F2BC09E1B61C92880E41A9076 +:1094B0005FCAC1DFFD03DB6D09B25E3BD1A1C68D82 +:1094C0007CA6B080E9023CEBE25D13306E52179F40 +:1094D0001342BE6F7CF6E3E3C85E374BFB25504674 +:1094E000FC7E9B9BCF8705CA891F6F17FCF87E13F4 +:1094F0006BC883A577754F8F4B87419F9E1FCEC743 +:10950000F5FE694E206E12FAF93B5AB21A817F3E7F +:10951000DE6FF5CC85FAA742CF501C6E9DB047D9BF +:1095200063A962DDABE11950AF3B77EC6ED42F2914 +:1095300093385F9DCE0DE7DC89722397FB3F508FF8 +:10954000F2DCE66CBA3C15EB9DDEB725EF26A09F5A +:1095500055634167123D990BE67D05B45D06B01970 +:109560006095F67343442FACE7427DAFDF98CEE3BE +:10957000EDCC8F7245D24BD261007D600868AF9A06 +:109580006CCC8CE31FCB76B8517F483ABD6F033C5F +:1095900062FCCC067884F53D0B830E25884F1E6F48 +:1095A00069547A5B9311FEB942797303F5E0E316CF +:1095B0004479ED8E1B49FE48B9A3C37F83C99DAF93 +:1095C0001D37DA317350B9336D92D08345ACE80260 +:1095D000371089BE6BC4B7B3D41A5DC371A7DA3C28 +:1095E000184F6B7C6414E91BD6FA07165D8FED48A3 +:1095F000267ED99CAB12DE6FEE5228BF715E5726D5 +:10960000D3A1686E57323D5DE732E8FD074FBC5489 +:10961000C2E512A7CBBC9F0DABA2BCA29F8DA1A798 +:109620001C47A3E0BB596A616718ED08078C03E08B +:10963000C617B9DE6ABC46A5B82643119D86C4E4A8 +:109640003F7E473BC57FFCACDFBE572E509C564F3C +:1096500040BAF8BB5586FC03DE4690E3D9D68C7839 +:10966000B6A69B983E88FD611574B2EB714C8FF2E3 +:109670003BB4E0D8EF57603CF65B664F08CA5BEC42 +:10968000AEDDB89E58D0D783FEC262F15D8F9DF3E8 +:10969000477C4192E1FB2DAED9DDC86F8B7D5CEF3D +:1096A000383DC30DFD5BD57566643216E0F6A2E465 +:1096B00007E24BE8F76ABF42FAF59AC5501ED5AEED +:1096C000B9E25392E3E60AA39D69F51BEB7D6F9225 +:1096D000D03B63D9D868FA47F0EEF0A19D7EC6E78B +:1096E000243E06EDFEE30A80AFED36339CAF358EA7 +:1096F000CFEB0C620AE3A23E3584F1922D88077805 +:109700009F5066C467A2CF88BFE439467CA4FA8D17 +:10971000F31FB678A4A13C237099A13CB3D66B800B +:10972000B31BCA0DF5476CAC32C0B9C12B0DF54760 +:10973000B52F34C0A3B72D35D41FD3B1D2503E3688 +:10974000B4D6503E6E4FA3011EDFF95D43FD895D27 +:109750009B0CE545E17B0CE5C5DD3F30C0937A1EEF +:1097600036D49F7C62B7A17C4AEF5386F2A9A7F654 +:109770001BE0697DBF31D49F71EEA801AE642F1943 +:10978000EACFB4FDC100CF72FFD950FFF2F4770DDC +:10979000E557E81F19CAAF2A386BE4D7382EFFE621 +:1097A00079FE69F84EC90ABC3C096D04F5B4867CA3 +:1097B000DBB24C61C9184FEF5E644339F08A9443C1 +:1097C000820F9F47FD8CF5F3580ECAB3596A4518AE +:1097D000D7ED992E85D67FACBED33EF2FB309EC727 +:1097E0007EA57830CE96006A4B8BEA3FD16703475F +:1097F000320227CF711BE0547FBAA1FEB0C5BAA1D7 +:109800003C23506028CFACF518E0EC863243FD11C4 +:109810001B7D06383738C7507F54BBDF008FDEB65C +:10982000D8507F4C47C0503E36546B281FB7A7C155 +:10983000008FEFDC68A83FB12B68282F0AB71BCA3E +:109840008BBBB719E0493D1D86FA934F840CE55355 +:109850007AF718CAA79EEA34C0D3FABA0CF5679C07 +:109860000B1BE04AF6A2A1FE4CDB6B067896FB0DC3 +:1098700043FDCBD3DF36945FA17F602897F6CD55AB +:10988000059F1ADF0B7B679EE71F86EF83553E8699 +:10989000FC11DCAF785A74C60A4B47927D0172BD49 +:1098A000D7AEA27DE4A7B851122608025F26801029 +:1098B00043BE4257A186E24F2914F725D5A463BEC3 +:1098C0000FD8090024997273D19E8E8FD86D5917C5 +:1098D0008A2FDD6E2B2F65C4E73797062696A6A242 +:1098E000BFB26F36DAED37B3E0661C07E8BD845EC1 +:1098F0005C1F76633C433EAFB0015EA2FA7BD1BEF3 +:109900002DCB7B11BFFF0ADB69AADFDFAE8873288E +:1099100030BFC6A8F6EF07BF4203BB6E5B13AC1B9C +:1099200070187FD0E426F8A1A674827FD4A4D3B3A4 +:10993000A3A9809E0F3779A87C475319C13B9B7C14 +:1099400004879AE6D07377939FDE3FD6B498E027DA +:10995000C08FC6E71EF0ABF1F914F8C758BE17FC6C +:1099600065847FD114A46767533BBDDFDFB48DE00E +:10997000034D1D04FFB22944CFAEA63DF4FC4D5368 +:1099800027951F6CEA22F8505398E0705337C1476F +:109990009B7A083EDE7482E0179A7AE9D9DD748AF0 +:1099A0009EBF6FEAA3F2979BCE11FCA188D7AE2988 +:1099B000E5F12289170933564DFC20EDC3F968E71C +:1099C00023739499FF66B0F363ECED587AC87ECCAC +:1099D00055181384E7F0FCDD2D517ED6ADA2BF2DC6 +:1099E000712C68077E6F3671BFB63989519E351369 +:1099F000F6EB1AC1972C85DBADABC5B8D688F53030 +:109A000009F9B380F8F3E5AFE35748BFF14C61A023 +:109A100085F833DB1424FFD911CA47FB39757C6004 +:109A200073E924DC6FBCE905EACFEDA17DC779D6E7 +:109A300070EA75181F7951A578DE50FDD58BFCF1C1 +:109A400021CB0F7D9085F6F69C2FD500E2E915B36A +:109A50007331C60BB69772FF747BA9C9F0FCC9F8C5 +:109A600040078EE77367C30D2618FFE7D3373C71B5 +:109A70006B6EC49FBE1A5D52F0831630DD4CF989BF +:109A8000CCF77C2E34750D1858085FC782F4CC2AA9 +:109A90000CECC2F92E01431CE140B93567B079C521 +:109AA0008E6BAF18D75E311EF97C717CE0696CEF6C +:109AB00073A78FC6F5CA94CBF3715E725C71137491 +:109AC000719EA16F278EEFF3E73E3DA98C8AE05F80 +:109AD000FAED9B2B455EC90685C7E5A4BD26F2526B +:109AE000A4DF5173BB12427B7D19F83BB8BFF4A6CB +:109AF000B03FDFB473FD7CA6C15C80767D8D12E73C +:109B0000C17DB8330DFFE540771AEA33DC2769C120 +:109B10009C03286FB943A17CEE1A68C704EDD4609A +:109B20002010BFBB4B21FEFB627C2E8DAF06CC3FCD +:109B3000F2B352FA7270BF14F8E545A4C3DA296A89 +:109B4000D002F6F02BA650BE42FBD237591418E7CC +:109B50009A14E0939143F3C37A71FE40BE073EFB33 +:109B600003B6F7B75F4F2EA038FEA1293AE2ADC584 +:109B7000C4CF23057FAF7A78BE0B17D5EAD4F11492 +:109B8000A7649AC78371A679E2FCCA11956DDC3788 +:109B9000881CFDBBA0DB2BE9E639216AD7B85FF34F +:109BA000B1A0E3C7A2DEBCA32F66E3F9ABF5DD6687 +:109BB000B24758496FA1DF39C87C366EFD765E1416 +:109BC0007FD777BDCDF335586F61747EBA6B326F36 +:109BD00057F2936A71067639A2C7D7CFDF9F117FFC +:109BE00027027F8F22FE3E89F6F67CAB9E701D3CDD +:109BF0007B01456178067EEAA67C239977B48AF9D1 +:109C0000E9B906D801F9D91F7CC082F85FCB3AE9DF +:109C1000FDFAB21B7310AE677DD5E9E84FB4373F4C +:109C20009F0EA35CB4ED8159189F5D185AF13C3E1C +:109C3000173CA69C44FF15D6877932C64F9486B64A +:109C4000E1D0DFD2BD956D99F07EBECAE9C15EE27A +:109C5000F400BEF1A94903E709EBC13999E6E1A394 +:109C600079A8AE3986F550B389F9949448FE7CFF03 +:109C7000FA28BBE5AF99E80F697DB4FF5E7FC89A0B +:109C800084745ECBB8FE8EC43FA4DE66C4E7B7B072 +:109C9000380FD6FB50F0F587D98CF8FA43051C3CF9 +:109CA0006FC49E64398174EFA888FEFDD0142A75B4 +:109CB0008D22FD9C87F37D217D918E71B35B526C6B +:109CC0001E15CB1343397C1FB55FCEB30BF191B892 +:109CD000D7FD661E878A1D9752F6C23FD07EB05AC6 +:109CE0005810F737607DB3525CD7C32DB4AE5A100D +:109CF000B5183FABF2EB83B5DF2ADAEDFE82FBC18C +:109D000041980F9E971CD08F5BF413C7FB917A0488 +:109D1000FB233992C60CFDCDC22417A0CB2B4E1FBE +:109D20008DBFD9944872E7E311816AA4978CFF48EC +:109D3000FFB03BF7FD3CF2E3CFB764A19D0EFCCB37 +:109D4000F312A773F9F48A590F22FC4A652EC5FF56 +:109D5000A5DCBDBA8CC7CBAE96F1B18A98F8584C49 +:109D60005C86550C1E2F63CC63C67EC7B237257E3A +:109D7000281E73B44223BA0781EE186F3E2AFCD422 +:109D8000CA78EE9F774E4E267E4ABA226FD07D1556 +:109D9000F9BC47C457EF053B8845C5D5EF2969B4E1 +:109DA000619EC1964285F6BBEEAB8AAB8DCE73DF6A +:109DB0003BCDCCF753A757EE44BC153A4255A4AE61 +:109DC0007D9A8EF350C4BCC6B901EF266CDA2FE23F +:109DD000A41E1B8F4B5593BE96F4BE547DFD941666 +:109DE000DA1487F34E61B4FE9C1D7692A36AA72F06 +:109DF0008C29D75F4E5B7827D151F317603F474AD4 +:109E0000E39803EA7F7EC442FEFD21D3CA9F623EEF +:109E10007CDF1B5686FB9E9DCE4C0DF545E71797C4 +:109E200055D3D3397536E371CE7813088822377B42 +:109E3000F4DF9058E2DC59A7C2BA19C5DB7CF126E1 +:109E4000F0C13A4DECEC0C18D77E87F7C189C4728B +:109E50007E15E7D95511B81FD753296B20F83E8BD3 +:109E6000BF7617F47B5F928DF8C45FE17F808F939C +:109E7000B5CD85F14D9FA9303CC7DB6601B95C8843 +:109E8000719238BE27C5B87DEF3F974FFDEF98CC54 +:109E9000F7F95AD37D3D78606448BCB9B5BEFEB8C9 +:109EA00008F15B16C5F3241EA3E9E52E35D02B601F +:109EB0008EA65719D06B7C34BD7CCAD7A1D7ED983C +:109EC0005C3669207F06ABF407AA4BB85EC314B9B1 +:109ED0004A6B7621DAEB47E2320BA3F7F5245F4AAF +:109EE0003E1D843F371C43F990A5B9317E6A9D170A +:109EF00047FB2D925F259FFE754A3FBF7ACBE1B9A4 +:109F0000CCE19F853224965F311E16CD973543F202 +:109F10002F7347AFD7F9603F2424A1DD73EAB1CE98 +:109F200028BEAC69F854E3F2E3C28CB8D248FC6EA8 +:109F30007E85C2DE89A62FFC7BA740CC8FEC1E8DD0 +:109F4000FC2D89C74BC5B7F95BCD0568C76DC6F356 +:109F50008980AF76C5E31B8671AD86B76FC5F76D97 +:109F6000E27C70B0D0C2ED2BB14E647B5F4EAB7A19 +:109F700007F9D639F974FC6AA8F7799A4947E4B425 +:109F8000E92BFF8DD6DD897886DFB9927B6A1FA524 +:109F9000753486E1FEE0E7370746E07EFDDD40A749 +:109FA0007728993A34CC447B59BDC3701D0172D3D4 +:109FB000F93390CEDF33511E22F83B53460ABFC31C +:109FC00027EAF752FDBB2DDB6C71D84FAECDBD3B00 +:109FD0008ADF6788F83A1E23E7FB672D3ADA657A4D +:109FE00019D7BF0F36ED99F6DE681C4FE7B4F7605E +:109FF0003CC973432C007C1C5710D43105C4F6E5D2 +:10A000004C05CF2FB0CB5827F20DBE6F1E1F69DF56 +:10A010005CC6D7990DED15A09F6D53504F8A927F66 +:10A02000369312182CDFE58E291AFF6E13A372DB0C +:10A03000D1ED749E3F39CFA360DEB36DD33686FB7E +:10A0400031F6307F9F92E7535645B59B3217C61DB8 +:10A05000C517F3F12401C81BDB6E60CC12A4431CAE +:10A06000C51F63FB9D9F5AD5ADB986E693587E63A5 +:10A0700082DF24DFC879D2C994A873F9D523B93D0A +:10A08000DCB6D1B20BEDEDF2B244C2EF672955094F +:10A09000EC227A6527F041D08AFEB18D9EBBC1BF0C +:10A0A0000E8E41FF389DE027C0BFC6E71EF0AFF11E +:10A0B000F914F8D758BE17FC6B847F01FE35C29D9A +:10A0C000E05F23BC1FFC6B840F807F8DF02FC1BF2E +:10A0D000C66717F8D7F8FC0DF8D7587E10FC6B84CC +:10A0E0006758813F703E05C1F48540D7F63B2C3E52 +:10A0F000CC17DC20E87ACC3732D903F4B71798288C +:10A10000F66D7FF9070CE7634F37D1F9AFCDE93F23 +:10A110006037A2DF5AEA24BBA9EDE7DC1EB16B0F62 +:10A1200032943B3B95602DF330B6B86C6C0DEEF37A +:10A13000E5A56FA84A02F886B2893B6CB03EF2F5FD +:10A14000058B9BA360DDE95DBBCF1D814714EED27B +:10A15000C03361377615EDC0A33F380ECC13AE2B5C +:10A160002BA96906160A8F646457F4E55A283F67DD +:10A1700015D26B348E9FC70DAF622DE9B86F39428F +:10A1800007EF47A1FA619672E9F53794E9F43EF6D4 +:10A19000BB8BD533955C523DA65EA43D2C572ED289 +:10A1A0008E4D5964EB81B16F350B3995EA2039D565 +:10A1B0008E711CC07BBB9D3FBBA7F0B8C1AE2955BB +:10A1C000DE29F0F44EE1746DB707DD55D8FF781342 +:10A1D000E52DB08DB97F1809FD7DFBF71AC3BC4F83 +:10A1E000C99FED820F468F70D2F97B76A78DF6ED71 +:10A1F0002F1FF1F3D62480473FEAF1607EC356E675 +:10A2000089433E09DE6BA2FCC6A74B46252D80EA9A +:10A21000E3263D9B8472FDA49037219117D4DCB6D0 +:10A220007A04EAB1CF5FE3F2F0C7423EED32F73491 +:10A23000103D2739C8EE606C1BD917CDE9406CD0B2 +:10A2400091A60CFEB498DD4BB19E050C01CCBFB6B7 +:10A250007C31D9867E5DCB39EB1C9E1FDB43768734 +:10A26000C51E7027C2FB6D4113C98516DD41F96C0F +:10A270005B1DDE6E3CCF1C749B28EF756BA189F0D3 +:10A28000D8EAB83684F6BCA634D7A21E0BB9F7DBE1 +:10A2900072E17DA8D044798C21DFC2390807031A06 +:10A2A000E559D10F960792E81CF756D6F7D2442C01 +:10A2B000AFE176575BDA7F1F8DC738F7356E0FDF5A +:10A2C00056613AE681514A9809FDEBDE4DF1388E30 +:10A2D000254CF8AD41F2535D564EBFEF1FB9C23D5C +:10A2E00092EC8AA8FD2B2BC6E43C360F944F707875 +:10A2F000E7A01FA939BD36CCEF6B757B6D2B68FECF +:10A300003C2F8DF22FA0DD16B789FC592CBFB190E0 +:10A31000D4E1F1BC529172AFE3BC7F7004F1A1DDD6 +:10A32000C458AE8EE3D382D1FB83B65115DD3ACC4F +:10A33000A37D7512CD43533C04B39B341AF7703D93 +:10A340008ECE2F3F6899D78DF6E170DB2DB48F95B7 +:10A3500051AB19F69986058C70EA62239CCCB4C87F +:10A360003E15F4FBAEE09B58BCC5E223C3DDFA1AF0 +:10A370008E3F2340876B078C7FBBFBA1C44A86E3DB +:10A3800074D038D31C2B2BD17E4A65FE66E4BF7F88 +:10A39000759C13DC0B6DB9D0FF84141399471359C6 +:10A3A000DF266C77ABE0F7F65C4ECFC8BA5239BF08 +:10A3B0004FA9CA9C928AFB042670CC22EDE706C105 +:10A3C0004133EC132419E0D1DB861BEA8FE91869CD +:10A3D000281F1BBACC503E6E8FD7008FEF2C37D47E +:10A3E0009FD85565808BC2571AEA17772F34C093D0 +:10A3F0007A961AEA4F3EB1D2503EA577ADA17CEADB +:10A40000A946033CADEFBB86FAD29E8FD58FA953E8 +:10A41000BE991D6F4D1F6EB8C726D64F88B5F36D18 +:10A420005FB6E89B909F5D16E2670DF539EE2BDF76 +:10A43000C1FD21DB748F8EF2255EC8D357A6FB4683 +:10A4400022DD2A5D36D20B9A83D7D31CB3C95EC9ED +:10A45000E9B0D0FD3A9A9BF597C7A37C6E0A4ECB24 +:10A460001B1D19B7DDBD8DEEA9A874CD61987724A9 +:10A47000BFD7DC3E1670627F3AB793DC41AA67D73C +:10A48000E1FBA8791C32999803E538F86D181F197B +:10A49000CA4F93FE99F4CB86F2C7A41F96636271EC +:10A4A000F8DCA5F4DE8A7E7A61C36B55C318F96BBC +:10A4B000D5A847EEC3F3D9E8A74DE076565BDA9509 +:10A4C0003AC66DDA733BBB47E278524D141705BBB1 +:10A4D000D9B330CA5E5C2FE8A98D6CEF45FDD798E3 +:10A4E00068D3D15ED26CBBA6BD07F8DA69EE7D12E7 +:10A4F000E310AD8A7B5D27CAC53B1C94EFF1A0C079 +:10A500009BEE34156F82763B9B7D1A9EC3EFBC9BFE +:10A51000795A717DA4546E4A84F7A3B3569830DCFF +:10A520003326AF79133E03C25E1E5BB8CB940CE5B5 +:10A53000E34A2A17637C4B75437F178937ABAE0E0E +:10A5400086F36179DA49E42BB4EE2FC0D02B936CFB +:10A55000B4FF68477A2BF4243CD8CF39427684F391 +:10A56000385EEC3E2514AF70BB15F3E52A933A88AC +:10A57000BED29E453B17DBF75704D6231FA5CC352B +:10A58000D255B33D46F8D86AE2EBA23D517F19F5AA +:10A59000737B6E5E12EE5BF5CB112157EE10FA5312 +:10A5A000BE9772E523F41D5223F60DF07907C6D944 +:10A5B000ECDA363A7F69BF6B1B43BEB6E36975B20E +:10A5C000F783BA9FF487DF906F563D72B10DF5F5B2 +:10A5D000D9142FD9B3F68DBFA4F1C5E2CDDECBF3EC +:10A5E000CE86C2AB2BFF61D2EF2080753CB77334AF +:10A5F000CD511B1DDF94CF6421F7CD323F083C09BC +:10A60000D4676765FE912F9E8F2F91C3C7F297D2B3 +:10A61000F86E4DF50EBB98BD6D077F331045F7BB47 +:10A6200035BF0DF1D0767EC11C9AB7468B816DFD8A +:10A63000A27017C58D85BF942CF0AB233E018F39D6 +:10A64000167E5EC0933297EE2D93718FE7A724514B +:10A65000B927C8541EAFEBCF4F375D984863D52D4F +:10A6600052EF9229CBF514FC7F04F35246B56BC62A +:10A670007C76A1C7A59E1EBDCD583EA6C3088F0DF2 +:10A680000DF8FEDF51CF5FC37F073D602C7F58E898 +:10A69000EB6B505FE3BED5B7785E880D467481EBF7 +:10A6A000D988DE033990DD19AE44B199759B66C82F +:10A6B00027191EA30FFD153AE1CBDFAD9951CFCA83 +:10A6C000B84CAC1C56EE3CBD01D74B657CBC8EF241 +:10A6D00013E318012BF7CB03E0A7DCA779FE548323 +:10A6E0007E55B74AF952924EB1749D5A2EED5CFFD9 +:10A6F0001FA7907FDC5B8CFE3AF61788EA4FC6579F +:10A700000E4D0FBC89F5649CE5CC1CED79458FC4DA +:10A7100051645CC03B85AF9FAD9ED71B8EC1388E08 +:10A720009DB0520C6496FA727713E643656B24BFB2 +:10A73000DC93D7FD14FDEFAA3F4339CCE398AE0F6D +:10A7400023BBBCDB4C71802AC1C755C2DF92F19696 +:10A75000CF843EE99B22ED9C601CF7EBC37168BF80 +:10A760008EDB03B2D748CF785ECEE36AE33B63CBA0 +:10A770007D94A77499E017CC2FAB4CC3B42E0E7701 +:10A780003225D90D749CB8B8F728BA0E852F3E1F14 +:10A79000877CB8CFCEEDB5A7043FA431C58379F847 +:10A7A000697B1C9E10D473AA6C5F0FCCC3735C339F +:10A7B000E4934D3868840B59149C8BE330C2F7EA5C +:10A7C0000DB8C5CCEEAD019B1CA6EC28177947F956 +:10A7D0002C1FF96B96EA2842FFA9B1D2C110AFD65F +:10A7E000B7C7FCB807E5C56BFC7E2A77BCFE4035D1 +:10A7F0007CEF7E29D9D3AC47E8FF14F8D1A81F7E9F +:10A8000074C1C35ACD51712DA0671EED23BBA9BCE5 +:10A8100013E88AF07EF0ABF3681FB980DEFF12FC0C +:10A820006A84BBC0AFC6E76FC0AFC6F707C1AF460B +:10A83000D837BD722CC6C3DE847AC8177145076C41 +:10A84000A3309EED50E97C4D2C3F6E6978D7711D89 +:10A85000C8AAA91DD97353911F6E53E91CF2D8DF02 +:10A8600064CF45BF353AAE161D578CC4D57A15193D +:10A8700057B3027D5E98ACF3BC45195F0BF0F8DA74 +:10A8800057B7E393ED50BC72403BFD714B5BF0BD9D +:10A89000023C9AA5B00478FFF11DFFF904EA99D4AF +:10A8A0008CC0549C77DDA4772CDCEEE6E7A6B2C41E +:10A8B0003ADA61E779A35922DF27365E397DE6DB94 +:10A8C000B7A602CAE6978F5986FEFFF45BDE2ECE4E +:10A8D00001F887E53F588679BDD37FF6F633998036 +:10A8E000A77FFE66112F7FF0EDB3591ECCBBF8DEBB +:10A8F00032CCF3752573FDB6439C3F92F8BD5EAC38 +:10A90000F7FA8D8F921E073B83213E5AD2FCA45F3B +:10A910003F49E973AD80FAF5A97D692B2FA20FEAB3 +:10A92000373E41DFEF503CA74238EE29369E5F2A82 +:10A93000F4CD19C1BB52DF34DA3928C7C3583ABD48 +:10A940007F50C481982F93BE4BB673F898AB9CF49C +:10A95000D2FD55FAAB3ADF9F24FFF898EBB2EF63D4 +:10A96000FE5CCB1C8DF60D1F7478EDA8B7368B7985 +:10A9700041FB41CA539965A3FD1C96B298D67592C6 +:10A98000EC27A586F20E92C4788E97C785313ED00B +:10A99000526DDB8D72F4078E91D45E4B99258871D0 +:10A9A00019096F2A87F1003E135D49B9D49F90734E +:10A9B000326ECC70F70CDAAD12D3AE92F90C36F3DE +:10A9C000E968FBDAC17A887F3C265D45FB3079AACD +:10A9D0004EF2AB987916E37B8BD2104466C479981B +:10A9E000A2E7A1571BE7A1CF32CC4369B485D12E92 +:10A9F0006C9905F380FAC79DA534DE58BAC9F97C75 +:10AA0000B79CF373EC3C99D83792E704AADC15079E +:10AA1000705CB34CBE561CD7F3FFA849C10B23672B +:10AA2000B3060DDF8F8AE4EDB47E9DBC88E9EF2A82 +:10AA30007C9FEB160BCD6FE7348E87872DA15C3A98 +:10AA4000C0A18532707F77283EEE2AE7723FC2C7E9 +:10AA50003E86EBAB25C9C7F9D8DDE76A463E4EEC2A +:10AA60004BDB44F30A0F4A9F587E8EA5D731BC13A7 +:10AA700081F4625045FC7F157D255D63F7BD24BFE1 +:10AA8000244F754B7AA7D33CC33986FD4068411FDC +:10AA90006C1F7C33B4A747ED9F59D2FD64679B536D +:10AAA0003C05186F6EF9521DF47CE45981A7665776 +:10AAB0001CD9DF2D2E6E7F1F715D69F09BAAC18F9F +:10AAC000C2FD62359975E2BA521396521C4D1D862D +:10AAD0009617B185D1AE4D98CBED5AB7F7A2E7A442 +:10AAE000B45ED5707FDA00BB36E94A6ED7BA2C6403 +:10AAF000D7EE705A16EF1A44EEBC54CEFD9F2338A1 +:10AB00008F41FC46F017299E29FD458B3B407E9FD7 +:10AB10009CE74B82DF657DABBB81617C4DB5787472 +:10AB2000B46355718E15F3970BA2EC02D9FF0BE5B8 +:10AB3000FC1CFE33D339FD641EFBF4579586C1F02F +:10AB4000AE4D9576C9E07CF72FF00DC909AFC3E291 +:10AB500043BBC3EB48A77CEFA1BEC3ADEA53491189 +:10AB600039E3F9B254257DA479287FBFD3DCFBCC2F +:10AB7000ABE80F3EEF20BD23ED71305629FF18FCE6 +:10AB80005E9F071AD9F74F5889A688BF0BFE57F664 +:10AB9000D4A8FDC7A38D2769FF27D64E8D8D27F436 +:10ABA000AF73D713B97C1CA10C5CB74A63D930E4EE +:10ABB000A7D8752E9FD9E9C597AD8271656714D165 +:10ABC00053BE7F84A97306BB1FADA41FFF5C3F8FDC +:10ABD00085CE1254D2CB2553818E1FDFF67A9A4749 +:10ABE000C773B49F927E3ED35096B005F9BC2089BE +:10ABF000E46A96381F26C79375F391C42407E6E9E3 +:10AC0000F58DC5FCB65093FFB26A33F917BEC1C6C5 +:10AC10001B98CAF5110B8F60D1F7FFE8293D578CBF +:10AC2000017CEB0E9347A775E526BD27D77FA59638 +:10AC300058ED06FECE6E621E878E5723BB291E96E8 +:10AC40007D41253ECB3EC6EF6F1E91D2A7E0BD5B96 +:10AC5000FDFD883C26B9AFF2594335ADCBEC618C94 +:10AC6000F550DCD24FFB0F9FA58417E0BAFEEC2114 +:10AC70003EA2EC478DE5A06B295EBDFAB6B8900EFA +:10AC80004D8FB80BC687E3F9A9C2B272711CC772A7 +:10AC9000B760BCE757F114EF513BF2285EB32623AF +:10ACA0003007F9E1E390FE6DD3283159A857F79D9D +:10ACB00038BA2F6087D27305E54BDC6E628F0F12B6 +:10ACC0008F5A3395FB89B582CFB3D34B39BDD34B64 +:10ACD0002E5B957CE9EBE887425E6F4D08D1FE9CC8 +:10ACE000CCFBBAD73C385FBD3ED524E89463C8039B +:10ACF000B3A1F703FCA22AC2DEDBF3D4534FA53184 +:10AD00007E847024DF878CDE2F8ECB0B51619CC735 +:10AD100047724771FBB87C7537A40781BFB77CA128 +:10AD20000EDAFFA3827ECDD9DF4EC7FAD5BA879E51 +:10AD300047B24B4FAC00FC391C16668D92BF924F48 +:10AD400062F57BA373E445FD770BC861FD22F10535 +:10AD50008BC8EFDA7C748A0DEF07DDECF0F6A0DD2E +:10AD6000B5D991E2A5F8BB03E445543CCAE178812A +:10AD7000F8D0E1E1713A07CA5D8C47E1FC0B71FC48 +:10AD80002FD0FC65BD26217F1C9E30ED93DA3DDB84 +:10AD9000A89E4DF3D3F9385B0AA3BC059B9BDF2B20 +:10ADA0001A976762B641E4F0C6A9DCFFDB5CE8ED08 +:10ADB000A9A2F169786C8A6D4EF7A6931E443CC334 +:10ADC000F7C79CA509D1F87956C88396237C7EFEE7 +:10ADD0008D19EEEA62F467FD7B511E6C76ACB4E12E +:10ADE0007D5DAAB3E4A2ED1C12F48AB4B33DAD3A82 +:10ADF00099DA7916F95F757ADDD88E59DC8F3A4089 +:10AE00008F89717CD3381A6090F274082F4498B0FF +:10AE1000812EB14F07C6C39207FB8ECBC55CE1B74D +:10AE2000805CFC138EBFAEF09D17F81AE3FE4AD289 +:10AE3000153C0FE80C7036DE4B159B67116BBF4855 +:10AE4000BD23F510B4A3623B0FA3FD3226B28E647E +:10AE50001C27B3D6CFD74B8A9FF805EC191DD78B8B +:10AE60002AF2F806E8810A8E3FC555A6A3BEA83E81 +:10AE7000DF9B89DF1D729ECAE4F6AB717FF9F83F54 +:10AE80009EB063F967B55517B553E47EF250FBC821 +:10AE9000AEEF7EB821DA4E196A5FF9ABF6938FBA3E +:10AEA0002C14B7DBA918CFBF0FABE0F22F49CC6F42 +:10AEB000D79480BD2215EBF93DFC40338FCBBC32DB +:10AEC0003DE0A8C0385ABB850591EFFE519A1E8817 +:10AED0006AE752F12CE3EFC3851D35DCF18482EB88 +:10AEE00074786D48C1F879666DA7E2BB48BDFF1262 +:10AEF000EB59D6378BF667687D2AEAAB196EAE1729 +:10AF000033CF69AC204AEEF44EE5769459D8EDAED5 +:10AF1000A34FDAB1BDA3267F7B3EEA0797497F3C6A +:10AF20006ABD9B6FF6DAAAA2E6D782FB4283D0D134 +:10AF30005721F56098F4B7D4B766A9275234839E99 +:10AF4000A88FE77C2CED9DFA72EE07D5C7737FFCC6 +:10AF5000C5F4C014C4F327E51FCE1FA5E339D8B04C +:10AF60003925F7ABF747FAED1B536885F46390FF7B +:10AF70003BCD7A572FD9592E3A3F21EDAAA29F29CE +:10AF8000A3B09E47F191FD37096F1A5171AB96DB63 +:10AF90008360675D5991CAAFE48FE6031673AFE033 +:10AFA00050F3F4E27DA6A9180FECA178ED7DE795AA +:10AFB00041CF41DC5721EDA5FEFD4143DC3553E88F +:10AFC000BD4C51AE63DC3517F7BB8C71D1E26E23FB +:10AFD0003CA9C7084F3E1113670DFAFE03CFF96174 +:10AFE0003E0136BA03D61FCA8F55621F342B18AAEA +:10AFF000C4F3E1D9AC93F61B336B930CF89EAE8A85 +:10B000003C0CBCDE588E137E32B5791FE0F79BFAFC +:10B01000E7156486BCFEEA55DFC6AB30D9367EBE86 +:10B02000CF069D23BED65CB17016D27B40FCB6C164 +:10B0300018B7CD8C2E073CACDE613C27E8F71591A4 +:10B040007FB0E85BC6F382321F1DE79BE91DD8FF86 +:10B0500057F70BFF9206F62FDB7D18E412C95D71DE +:10B060008F703616613B5A58C17DEFE10D8CEE139F +:10B07000CEBC8DF906DB3F3820F0158B67169C415E +:10B08000F89B29DE0D77F03CD5E1B799C84E1C0E30 +:10B09000F282FECEC03AF03500CE5CA7939D797562 +:10B0A000AD89A1DE60E79B0CDFC37029BE2AE9FEF3 +:10B0B000B083E7E166D7B19009E7D37019AD331AD1 +:10B0C000D7C8083F00BE0CF7095C5D663CA79B1D16 +:10B0D000733E57F24166CCFB6B2ADC867501FAEFB2 +:10B0E0004005C90FAE1747A35E84217D3CE5C4131C +:10B0F000986F377D13E3F7D924C6F1FB6C22FB135D +:10B10000EA05E0D7A3B6990568C76C75C799300FF3 +:10B11000E25062EF4F5822F88D152C589D85F71C90 +:10B12000F68D53007EBDA27E67FB3428B7F73D8DB8 +:10B13000C16587E3DB37CCC98EC02ED73D04B3325F +:10B14000A6E37D4098738AEB2ECE7DE51EBCE73AE0 +:10B15000AED041C1CA3866BC77A7B55CBF17F3480B +:10B160005A479BC4F9E8A87298C78C696E99FF4644 +:10B17000F9786C0ECF0B886E1FF3B2876CFF4A68AC +:10B18000BFE46BB46FE3E34FC357A07FD270FC18EA +:10B1900017C7F691BE18448AEE5FB4A7B1E02EDC63 +:10B1A000CF81FE1C0AEFCF8D792A69CC9897D0DF2A +:10B1B0009F1BFA1BFFFF603E8B07D2C37C317A2CAA +:10B1C000FD7AF46835F968BCC1090EF28FF0FE2AE9 +:10B1D000BCA7CE2EFAB38BFBBA10AFADA511BC82C3 +:10B1E0007D48ED42F5E60B02CF987798E6B6109EC3 +:10B1F00087C2DB5137CF93BADB1D176ACEFDFF4004 +:10B20000AF744EAFE8FED0CEBCE4FE96427F2997E5 +:10B21000DE1FE217D74F3F7E81269BD22E1DBF3007 +:10B22000AAE0A5E0F728B46B8AC26B241F69BB1B98 +:10B23000FD05BBD96FC3FCCCB9D312697C85290B42 +:10B240006D949F90BA90F28DDB0A1DF4F705DAF247 +:10B25000BE653347E9E9B6C21A2A87FA94475518FA +:10B260008EC3F0051BCF7A283E707745753AFA8B6E +:10B27000C1069E9725F394A43E64623F94E6051FA1 +:10B28000264C3BD07714EADFDD504279680989FF0C +:10B290004DF9575B6B3D1E2CFF899DEF6BFE48EC13 +:10B2A0006B21A3527C6D42F9A3B8BFEB1DDDA8D082 +:10B2B0007EE6BA8BEF677A3FEDA9C23C2EB682E7F5 +:10B2C00069A5D76831FAD0B86EB7225E793E554885 +:10B2D000E1F835B4B7695A2AE1EDEEBCDD0CFFDECA +:10B2E000D033D0966A5C5F26CC6B8A5D8F9AC54757 +:10B2F000F78BB146138D2313530540C579C7CF4D46 +:10B300005F01EFB36ED2E81EDF618577517E13587F +:10B31000FF646F1416BE5C85F08079AE32CE237662 +:10B320005EB1E396F71B4B7A793FF5C4A3DFE51DC9 +:10B33000BD90F2CFE847AE7735663E6027DB534CD1 +:10B34000740F5C5C5ED4BC98A19EF0EBFE67E106D6 +:10B35000D055B48E62F7C9FE0F3F2F64651E9B85E2 +:10B36000BE93E76BF8FEDB705C3B48F71CC6F3C08E +:10B3700063BF2FE5DFB374BE1F678D63363C5FA3E9 +:10B38000AC8DA3B8A6D50A309EBF11F78C3D2CE238 +:10B3900070CD0AD332BCD1FD85298F5EB55D95870E +:10B3A000FEC451DB22379D6B13FE9539D14F798C4A +:10B3B000AC20C9E0A71E15E7D31A6FCE1D8671BD5C +:10B3C0000428EB417F5BF3D890DE329EE21AD57BF6 +:10B3D0003DEAF1DF3EF7C90D36D4DBE81C9733D6E2 +:10B3E0003DEDC39D78BFB05C9FD673FC9E8E7E58AA +:10B3F0006BA03C11EBB91CC3FBB0F0CFFAFD961467 +:10B40000AD9AEE9F127E432573B7E27795801CC3F9 +:10B41000BD00E2DE8F81ED6719DE87C1EF8EDE278A +:10B4200018BAFD78C3FD0256F083066F3F3FA67D34 +:10B43000F7A0ED47DA4D36B4DBA671B9114C890B94 +:10B440000D16F7FB725AD57BB8A487CA63FB629AC4 +:10B45000C8BFB78144C37D29C13F5BD21B28AF4D14 +:10B460008DE3FBA8661023C84FC79CB53C1F23CBB8 +:10B4700098D726EF1569C3FB42A0BCCA61B4D72B8D +:10B4800059DFB1890AFAAF467B7D3A4A52DCAF6296 +:10B49000B1767C03ED9B9AB38C72A143AC1793B346 +:10B4A000A487F2E0521D94E73054DCE1CD2646F942 +:10B4B00059E6787F03EABCB4E9DA88B632801338FB +:10B4C0009FE54DCF588E71DE37053FB7811CA0F345 +:10B4D000A38DC376A951EDD658C2A351AFD498F825 +:10B4E000B900FA81FEDF4C1D4EF1D7D87EE5BD31A3 +:10B4F000125ED6A04CCB8B9ADF9B627DF4F7776B04 +:10B50000E62EB46BFBFBB38627517FFD7946A2BFC5 +:10B51000B46FD6DF5FC4FA96FD2DFBB6717ECB2CDF +:10B520003D34BF65E2BE52D9DF5F707EB9DFA03F18 +:10B53000911FD6DFDF778CF35B66EDA1F92DEBF77A +:10B540002F457F69DFAC3F99FF60B536D4223F0DB0 +:10B55000950721F31F2677641AF21F5830736E6522 +:10B560001E630F289C2F561D1AFD53E48BB3731BCB +:10B570003D64A7087F8FCE0BA9745E88F4E8D55987 +:10B58000DC0E91EDEF692A63BE313C4E84CF820A16 +:10B5900085CE238C2D537CB8EFB603E407DE7FB74E +:10B5A00013D63996879AD2E9B9BB49A7E763E05F1A +:10B5B000FA282EE621F887D379DCE5810CF792553D +:10B5C000687F54C6F17CEC8AA960D946FC37582FB5 +:10B5D00047ED98F7782D2BC27368F91D1C9F29D56C +:10B5E0006974DF7D5CD1F19E2680B794A93AE69913 +:10B5F0006FD1078FF36C9BCEE3BF5B441E6510CF0A +:10B60000499252017F12E6BF5C908AA973E9FCCD92 +:10B61000D5DF4924FBA6E65BBD4E378CE306A5E8E3 +:10B620003FF2001F7F15F6CDF29C2B491EC4FAA7EE +:10B6300029A8A94A30BF500D85E0D745CE45E4DFA3 +:10B640002EBA86B124F8FE6AFC0EF4D4ABC23E7A60 +:10B65000A5D7CAD0FF0B56F3FDEC1BEE32FAA50FAF +:10B66000D8C36EB40B1F284A61488F9ADB8CE55B08 +:10B670002C7CBD2D8AF153AF8EC90392F71F6EC18A +:10B680005FA7003EA78B7B5F441ED055D375AEAF3E +:10B69000B39228E95B9ECFB45AD9A0FB94B2BDBD4A +:10B6A00028B750CEA6F8080F326F8EA97B8BF07B9F +:10B6B000D99FFCEE61656FC6C5E2A960079EEC2DBF +:10B6C000E0FA1EEDF5DDD38DF94A67E78EFC7E3595 +:10B6D0001B8C6FFB348C53C8F1FF6FF16BCD743E44 +:10B6E000DF57677E56C2CFDD65B1E8F376321F6C57 +:10B6F000513FACD17DC2321F90A5F71522BDFF7D11 +:10B700005ABCE71EE23F618F84DF305D88FFFAEDAF +:10B71000F58F23DD976D38BF2ADA1B0ACF43DD375B +:10B72000413F51F9922DCD9E743A5F97CAF7DF865B +:10B73000A7547D80E7B9B0FC1D037F19CF6DB51C00 +:10B74000795241BFE52778DECD1CE917E3C36D0EC2 +:10B750006C37C4E34AE127292E9C551B565A0B230C +:10B76000E78362E562D63AE3F9B3D87B14E7397A26 +:10B770003545C77D803E3AD7983343ECDB208EB108 +:10B780005E2AB727D54C13CF1F19A173FB32AF2FF9 +:10B79000277A1F449DC1ED8679F1AFDFA683E8FDCE +:10B7A000C7A1BB96639ED4BC84D76FCB05F8FCA120 +:10B7B000EF2DC73CAA7999AF7F960BF2F6CB43FFEA +:10B7C00087978F7BFDB39168231E6EE2E5531921A5 +:10B7D000C97438B89CF68766C87B137BE8BC762AA8 +:10B7E0001EAC98F4CD9FAAD534E8BA74CC90714BB6 +:10B7F00046E7B3FD077F7702E5945FC6797DC67D96 +:10B800004F26EE4DBC4AB2578A8BECA52BF177C080 +:10B81000E755E2BE1D932D4C781D13B9CFE4A1AFBF +:10B8200073DF4EE47C3CBF3FA865230B18EF45F463 +:10B8300009FEE77944723CB2FF01E3C27B0193A2A7 +:10B84000C7B583DA91E3FAA4C81A542646F671E51F +:10B85000B83E51FA7662D0A3EED82F5720DD3E7164 +:10B86000F6E5E0DF37393EE31DA2E327A97D3B156E +:10B870004F146CE674F41EDE4EF6544586CF3B231F +:10B8800015EF0FE0F716B40B3B726B6A20887E3D14 +:10B89000F01BE57106B3F9B986EA12E3DF61AB107C +:10B8A000FCF59B197CFF7896755BC36B25788FBA86 +:10B8B000C29AA17EFDF9B316F4FBE71DE47FA775DC +:10B8C000FD81B72DF47719108676D6EFB00CFA7794 +:10B8D000E00ECF5025DD0DFECAF3D9F96D29309E5B +:10B8E000F5ABF8FDD88DBF4E9C8570E30A9C25FE14 +:10B8F0003DBD7DB3F0B365FE236DF85CCE7A9FC786 +:10B90000737F4B02463FE2FA5AA3DDBFACC168AF7A +:10B910002FDF06D401BDB67C6366CC3D7EFC7EC0C5 +:10B9200025829E4BD2EFEDC17B0796B098FB018339 +:10B930003C8E743D9F013C8DF19179F8F7A4701E07 +:10B94000EB548AF33E9FBD59C3F370F50DFC5EB214 +:10B95000595D9F5AA81CEAE17E53DA707E0F9E94CF +:10B960009F52BF5FFFDC2E33C60B62EF095CBE78CF +:10B970000EDD07BE585FCBF5FB883FCE4A82F7B19C +:10B98000F7FFD57471FD5EB35109E17DBBD7D71ABE +:10B99000FD8165ACA70DFD99650DC6F7CB371AE1A2 +:10B9A000EFCD107A6D1C1B87EB63D30C45A373D5C9 +:10B9B000023E9DFDC757C2D07F5586BF6D06F0C9B8 +:10B9C0003A4B7802EAB9AA8C00C1B21CDEAFE77A22 +:10B9D00088EB7F13AC2492BF661EB708D6F17BD9E3 +:10B9E000AE1F600F44D90BEA40B84BCA4FBBFF36BD +:10B9F000F2C39E53E8EF82576B3E2D29CA4F8EE566 +:10BA0000C35F0BBE7E85F516E2B8F291E9802EF990 +:10BA10008BF8DF7DCE3FBC82F22CF38B158F89D65D +:10BA2000B1896DC4FBC4405EA05C40FB13EFC9C884 +:10BA3000573B17939C9E6871F3FB76D259F4FAF743 +:10BA40003DC914C4170E1DFBBD2AAB9BEEDB98DF6E +:10BA500071EFA728E7F246F9BC0FC0F8B68AFBB42D +:10BA6000B7FE5A217B767DE10B240F87015B60BF17 +:10BA7000EBD3855CEC32DE83310CE5141E68995BF8 +:10BA800048FD66C8FD0799E71BAEA27BA586897EA7 +:10BA90007F3F4BA779A7ADED5470DED92CD88C71C0 +:10BAA000A83D280B53234FB94F704D64FFBC02E9EA +:10BAB0005997DE4BF7C2C8FDF341EACD46B933A032 +:10BAC0009E8F19F28066A9E75DB8BFDDF8DCA88B10 +:10BAD000E675A836E3FD9066B7F17EC8AB0A8CEB3D +:10BAE0007B9EC7B8AEAF2E1B65285FE01B67285F43 +:10BAF00034A7D8005FE39F6AA87FDDE299C6384289 +:10BB0000BAF17E48BB6EBC1F32BEC0783FA4D3637F +:10BB1000BC1F92A574525E9AC516EC0DE878BF0062 +:10BB2000BF8756CAE9712E1B5D2A17576C77E0B3A1 +:10BB3000BDC81A46BAB50FE7FBB9D6176F4F0F232A +:10BB4000D613F6DA2AE1F9B412AAC2FD289BF01B3B +:10BB50002FBB8B19E4F89533B91C974FE60BC457EC +:10BB6000625C768F9EC9F3B67B2EBB587EC5A53E20 +:10BB7000FF2FC2784B6B0080000000001F8B080075 +:10BB800000000000000BED5A7D505457963FB7FB64 +:10BB900075D30D880D281F41F4A1A0262069418C82 +:10BBA0004E6636AFBB81693F3269FC986010D3ECBA +:10BBB000E816138126D14C91AADDA255863466FE83 +:10BBC00048AC4CC6A452B5AD153399A9711713569C +:10BBD000DB4DEB362AAEC99AB1DD31194D2A2974F5 +:10BBE000DD4CAC8C0A31E3985D77DD73EE7D8FEE32 +:10BBF000D73C12B23595AA9D5A28EA72DFBB9FE75F +:10BC0000FBFCCEB3A503C022FC3B680BEF2B01B8B5 +:10BC100097E1FF4B01EED0CF0300A7EB5C16A50622 +:10BC2000A0E2AF9565300DDF45C05186E3F65A417D +:10BC3000A17EF0A095CFAB880C9B94CCC4BCE7143C +:10BC40005C683AC04F7DEE65B47E47943900C77595 +:10BC5000ECBE64952BA83F98A5605BE9BB6485CCDE +:10BC6000E4E717ADF4BC431A497760FBF7FD666F54 +:10BC7000B822B1AED6BA142B5FFF6431B6788EE627 +:10BC800027CDE1343A3B282B5D8B011AE95F199FE0 +:10BC90001F18899971FFE676E60CE2A346F9B19583 +:10BCA0009085FFF82D97866D0036FCBD331BCF596C +:10BCB00098B517EEE5F301F2001E05F1F3C892986E +:10BCC000054C004DAD623CFDDCC1BF47D7D45F6180 +:10BCD00095B86E67CAF319BDA3E62C9A2F5D1A9E1C +:10BCE000AF3E27BA2A53A67D5C8E9D72A8B8330753 +:10BCF000E0BCCF6478AF873C12BFD779BF87D3FB56 +:10BD0000A7483733233AA6D249D0EFABE8B31FCFC9 +:10BD10009ECCA7D4716B3C824FFB1934F6678E7FA3 +:10BD2000FF33958F7B59BC0ACC00011F0ACC54A469 +:10BD300087AD65F3E56AA2FFCD5E46F4FF070669AD +:10BD4000B8FE07836FE5C95300AC0786F28671BD64 +:10BD500040FF501E2C0068B3C8DBA4695C0E9CDB5E +:10BD6000902F1D91183F7F7B7FF5203D6F8F30A76F +:10BD70001D8F1A1818ADE7F784E15E4726ED6B7C3E +:10BD8000AE66C5C4CFD5AAC8BC0DF871CF69343F23 +:10BD90002D1C66C4F7612B978BC30C9EC5FEDE3E3F +:10BDA0005B63D8609D75446F94EF137D5690504E41 +:10BDB000DA703EDDE364F149AB8DE4E600DE8BD161 +:10BDC0003DCEAECDA0F5B75A406689F35D2D8E7F8E +:10BDD00044F7BFB0D102417CBE63A399D3FBC256E6 +:10BDE000335FC7BCE9DF7B8BB0BF0EE52F0D8F7AC9 +:10BDF0007CE38D9345B8EE8556ECE37D3D9B2C5C52 +:10BE0000FFD63DCEF8F854F9D5E4F525553ED7F9DF +:10BE1000F5F2962AAFE3E4B4F5EBC9690FC96906F8 +:10BE200097D3CA3B66CEF7BA7C929FA7C0B98FF46E +:10BE3000E7F6714B3E9E7776AFC3B91DFB0BCCE1A5 +:10BE40001FE7915D382EDE2F6CDBC3485FF0F08F6B +:10BE5000D0BD8A4256D8C9488E04BF7EA6F24B8612 +:10BE6000119641FA2AC567FB503E706B85F8FCBA03 +:10BE7000051A0F54D073615F161C2AD8B333496E6C +:10BE8000EB5579B499C0DF8FE3CAADE03F9049E349 +:10BE9000FBEF6AC075F6E37C7A3E535DAF6CCE482B +:10BEA0007D03B687687FE4F31EF51C5AFF0724FF65 +:10BEB000D8C2CB260648F7076D82EECBBB62EBE912 +:10BEC0001E8B66F87F4EF66FE5CCF7DA00ED44681E +:10BED000F6DB157E3A1F384D44F7804AF7E34B7F77 +:10BEE000F7F216BCAFFDEE74CED786632FC689CFAE +:10BEF0001DA51210DFED658BF2FD06F2A7B5815B83 +:10BF000025E0CF4DF43BA2A3F58A815E6F50F57515 +:10BF10008155DC1FA248A4426E8FA525558971DA90 +:10BF2000FD01B6F3FBD9CB5EE17CDAF2382C34F3B9 +:10BF3000133FC7D7696A3BCB5A709D872D8A25135B +:10BF4000E9FCDED4C6CD97CB00DEEE461389173967 +:10BF5000DD6D03FF3C805F773B783FDE5DC0FBFF1C +:10BF6000DA2DF376DE4CDFDB0AAEB3F6446719D187 +:10BF7000EB78F10B3E37EE73FDB485D301C0CDE90C +:10BF8000B44595BD1B5133D8F0FD8D01160696388A +:10BF9000FF865B45E0477BF23EED8713DBBB7EC34C +:10BFA000ED9CB375B45ECE24B9BAD84BFD40D71F13 +:10BFB000EA01DB8FD04F907C05220C0A709DF5B70B +:10BFC00072F9FCF6C859AB4C72601AA927FA078FB0 +:10BFD0003220B90C748E72FBF932DE4BC173A7BBF1 +:10BFE000B2395D02D18526C1CF4526E2FF132AFF73 +:10BFF00007EFF98F2CB25FB62EF9CCFDC4C753669C +:10C00000CEC79DEE912C87015FCEE3BA9026CE4F2E +:10C010006DEAFB466BB0CC89F31A55B94D7D6F754F +:10C0200009B9440A5B7C5304AD18D26DBD2A5FCDBB +:10C030007895A939D88FB0583AEA6D73D47345A270 +:10C04000B693C1259D3D00B8A4E9B37962799B6C94 +:10C05000DB41EB9525D94B3F2E3A3FB15F536B0641 +:10C0600039D1A4FD83FC1E69C5A5F97E837B8EC9E9 +:10C07000FB7011C8C8AF8E100319E5BEFD56396FAD +:10C08000AF1D7E5A263DB1A58FBC407E01E69A1CAD +:10C09000FB90BFED415092FDDCA85BE8EDA85BE8AA +:10C0A000F14C17933EB671BB554EF77617FA4B5CC1 +:10C0B000788EDF17BF97750C1FB759639560FCBC6E +:10C0C00003D01FDB489F70DF72E4CFEB06E7BEE9C9 +:10C0D00076CFA57933E1592EDF80F24D72957ACF74 +:10C0E000852E712E4D9FD71DBB621D26B98D18EB75 +:10C0F00033F3B816D2BA7D005E233FF747F59EEDC5 +:10C10000BB19A75760772EA7D355D8ED73A35C5EF4 +:10C11000C573EC45B9BCEEF36564E3FCEB7E5F46AA +:10C120004E6642FF3B7667F0797DA5AB725BB05FF0 +:10C130004F728FFB5D8B786C44E70DBB85DE69FB2E +:10C140007D145B974BFA536319B13AF1FD8CE8C546 +:10C150002C8AEB6A0EAFCE25FD9BE89C8BDDC22EB0 +:10C16000B5776DD97C3957C88319F569B3EAC70229 +:10C17000DB6356A2FFE62EE0F23B78F0830ED2DFBF +:10C180006BD10C07F9BDAB47328264EFAF1F4D0B8B +:10C19000A32586369277B467572DC3DFE3F1E361B9 +:10C1A000B32388E302473F7D81F4317010B511D786 +:10C1B000DD1C7D7A94FC5B5B74D91589DA5F7DB3F5 +:10C1C000FAD0DEF5237E5FADFF69B74D26FB794DD2 +:10C1D00012766273E40D1ECF6EBE7DA3D25741F777 +:10C1E000FCCFC564CF02FF746331D9B1C09B371651 +:10C1F000D3FBC0A18C4EA3F8A4D563E6FCD7FC63A7 +:10C20000C93949491E97ADFAAF929E67BDB3917E79 +:10C210003567D738CD72E27D4D99C947E36BDEAD06 +:10C22000CDDD9434AF272E79E9F9A2B3B5191B936C +:10C23000E4D2EAB1A87608B51AEDCF3A9586EB0AB2 +:10C240007E123757525F0AAA7104BBC3E36D902573 +:10C25000E47313FD87AAD81797783C136C3587CB06 +:10C26000F07D53DCA4D82BE93DCE4B8A33007C2BE8 +:10C270001610BF7F38DDB953E6FE1EBAA9FF545928 +:10C2800098FC3D046D43A54971D0BAB829968672D1 +:10C29000D3184D8B513CB42E2E5DE47D353EFAC84B +:10C2A000F1FA8F67038F8F2E27C739180F5DD6C716 +:10C2B0004B3085CEABC54BEF515C85F16CF3D69816 +:10C2C00085FC15C649BAF18F367EF70AA338A94B0B +:10C2D000FFBC242E991EC47B96A0B92332F4C59FBF +:10C2E000B7917E687126F16BC040DF2B553DD1F4CC +:10C2F000A8276EE27CE889BB6DA5D8CE53DF0F3846 +:10C300004C10C4F57BA2ABF7318ACB6E3F9C41F455 +:10C31000EA39B70AB693BE3BDCB6329A77FBBBB6B6 +:10C32000B51509F918673F5CAA7D1C8B078CFDDCED +:10C33000272E35AEFA86FCDDE53F177FA7F83F25AF +:10C34000FB5DF19ADC44F121DEE71E8A6753FD8430 +:10C35000667FB5758B543E8FB7BF5778FC82F92F37 +:10C36000B7BF456E998F9B116DC8E579F1B935B9A5 +:10C3700072E6F8F5E7484E534EC5F8F5B5782D103E +:10C3800054866C94C72866AE9F81352CCCA8EF6389 +:10C390003CCE0EACB784E9BD769EF81AC6C7AD7523 +:10C3A000B2B09D25E23F2D3E1C7BBF08DF9724E203 +:10C3B000452D2E8CFB18CF83D62816FE7EDE4C7FB3 +:10C3C0008EBB86EE67E7CF6B968A75D10E0C517ED9 +:10C3D000F4F0F719703BA0C68B9A7CA6C6939F45D4 +:10C3E000E74C852F892B5E56E552D3AF99297AA168 +:10C3F000F9A97AD54F77909FAE263FFD8595F460D9 +:10C40000A2B81BFDF45C379F077CFEA277259F51E5 +:10C41000DE7D585D77B1C6B7F809179DB718E2DB26 +:10C42000285F9CC87FE6794C3ABB90FABE7E927A30 +:10C43000DCA2C60BDF941E37ABF1D7FF753D1E8B18 +:10C44000FFACC6F7BCE976FD15C96FBAB933EE2269 +:10C45000BDFB17D43B79FCB8222D9F9440C79FA108 +:10C4600062AB89F29E40ABC00142D9F2199E9FBCDB +:10C4700065065A67F3AD421EA73D762B9BB7A142D6 +:10C48000107EF4C9128EDB3CF6DA598B82F39BB630 +:10C49000B285840735B5EAEF139AAE709C2D788487 +:10C4A000F1783954D87F92F42AB86F8E4CEB37D399 +:10C4B00065090F69CD0EEF20FC82709C7BE9797ACB +:10C4C000820EB84FBBFAFC7E15DF819438E0CDC1F7 +:10C4D0000B1CEF090C3020FDB546D17E903D39256F +:10C4E000F08E8EA8B00B9F74D9B93DF94412F708AD +:10C4F00074B1F036968823AE449FCB233D1B174F73 +:10C5000028184FE425E289F657DEE5F630357EC877 +:10C510001910FB04DACC61C263868A1733EAB76369 +:10C520003E984F71A22C3F5424CE05616E57141DC6 +:10C530004EB2F72EE1F73F3BF56F3C8F6C3ACC20C3 +:10C5400097C71D4ABC342F11773C1A5ACEFDBF162F +:10C55000673C3AEBE45011ADA7C6190EFC25FC3040 +:10C5600035CEE8889CB5505E302E9E4889235E7794 +:10C57000EB71C15992C05967459983F0A4592A3D7E +:10C58000EFEB4BE77171FD871B7349CF35FE5C6B99 +:10C5900010FCBA76E17317CD5BFCA1E4207BFBE6CF +:10C5A00085ADBF29127DD926D3BCAD1994875CFB1C +:10C5B000F0890CA2E79BD802EAEBA1F392217E2836 +:10C5C000ABF608FDDB3FBB39FE2B17715C4742FF22 +:10C5D000362581BFA4CE7BC023EC4108D30C8E3B13 +:10C5E0001E062EBFA142FF72DE7F7136ECE3B88FCC +:10C5F00090D737A2D90E8AF7CAF1B25D6827FE2E0E +:10C600001D7AEC5524CFFEB7B97EBC68E2F28BF3FD +:10C61000838CFA0764EEEF8864EB717CA515CF522A +:10C62000056233D4B77B54BE15621E4AF9209E665C +:10C63000CD1DA453F98C535F101F2BD341A2F59F3E +:10C64000B1F877DE8D539E19949CDB688EE4CC6D37 +:10C65000C07B3D63174B3D7318E515CF85D2CDCF19 +:10C66000D55171F23CCD67B203D6E3FC8E82CC1873 +:10C67000E16710B1FC7E4C2E510E18ED5329E4ED0C +:10C68000E3F9141B2AEC0E9A9AB7EB646117BEEF1C +:10C6900003CA83762CE904CA3B4FD6811A07D98294 +:10C6A0009771FC5A9C31159F4F2FF417525CD15E45 +:10C6B000306C1571C58895E28AB92E6DBCC0ED4C01 +:10C6C000389EECE5CEF9AF73796BA2E749FA0CC955 +:10C6D000F89E797CBFC53DD1FEB2C8E752F65F94A3 +:10C6E000FD591ECF5FFEEB8F59DC9F456F70BF7306 +:10C6F0007D240DE21CB71B163875D4C2F3F5EB98F8 +:10C70000074D4FF2673B5C820EC7A21E2E8F03F1CE +:10C71000DA0C1AFF4B97D8AFEFDC9AD50F929CC476 +:10C720002567193FA5C86B06E2528D880FC6D1A9AF +:10C73000CA6D704E5BBAB0E7A9F279C92DE4FA125E +:10C74000DD1BCFE1B920F295C056513F70A8FA1613 +:10C75000E864DCAE9C2CCE631A8E9C6F545F383C30 +:10C76000C2ED6CF30F9933284F5C5FD8A5E619A989 +:10C7700076A8237240F02D15B7F5D673BB3359DC7C +:10C7800016281B5E9CB0D3DFF1A8766581C0714F7F +:10C79000B81DFCBE399D0B5DF990B8BF013DF77B1C +:10C7A0006AC6D3D3605CB4D680EE06E3FEF0C0E484 +:10C7B000D6AB5626B79E6B92E35A94C9ED7B68922E +:10C7C000EBED99E47A4F1AE92DB25DC4030E2137DF +:10C7D00075E6DB5924FF4F1C9993FF65F1AC190DE9 +:10C7E000AD9CC47F8B231DE424BFBF627EAEAEFF31 +:10C7F000A0B34837FEA1257374EF1B9472DDFBD5FF +:10C80000DE6A5D7FADEF7EDDF8871B3DBA7E5AC1E3 +:10C8100072DD78BBBC4AD7CF98FF886E7C087566FE +:10C8200009DACF346B6688A1FC4F71FEA56E7C7A65 +:10C83000B53D93F422B4302D46F29EF6D6A620BD27 +:10C840007B9AFD642446D4CD3AD8C85065A5EC57F0 +:10C850006CA4272B978ABA405FAD2DBC87E29CBBA6 +:10C86000B22A69BE46AF7D7522FE72548C06739162 +:10C87000CE3395786D2EEAF3F5A5C0F387EB7651AC +:10C880001F00C951D8C0F9E7285C85763F6437AEF0 +:10C890003335D6A979F104F6E4749DEB17A42F0E75 +:10C8A0008ACB0DF8A8A878BD23021CB701492E5CDD +:10C8B000C5F7950BC9DF4C3D219E67C540D9C3CF55 +:10C8C0002597ACE271B45C42E7DBA5D6BF7296CF88 +:10C8D0002D21BC2E07FD2ED5479EA33A09CF031C60 +:10C8E0007C9CB69FB356ECB7CB028CEA59C1BB19FE +:10C8F0008F53C1315557DF386D895D6E61BCBE7194 +:10C9000082CEFF8E2956B1B744F085E85B31E0E076 +:10C9100075975F2FFDF97C3FDF47D43BB638C49055 +:10C92000E3946FE039B61CA9E6F2DB746CE96FD7CB +:10C93000535C582A713A8F8BC7D53CEBBC9A276A57 +:10C9400079D630E58B4979C7798F6922BB74DE636C +:10C95000A057BB98C88383EF883CB8DAEA9CD39988 +:10C96000C4A7CB6A3CDE121378AC96DF562A61531B +:10C970001ED2A1FA29732C0DFD7575EF022BD9ED8E +:10C98000EADEE2748E2F6D3C60D2E86DC4F76BEA8C +:10C9900039FB4E8DF0FAC41B29754A67AD95BFFF70 +:10C9A0005B551E9DB5C0DB2D65D20E72C353BFED26 +:10C9B000301BE1E3CD18FFD3F95A42E2BC5A3DA443 +:10C9C00039267B689F8B4323BDD456B59678387E35 +:10C9D000D836DA4BFE3370FBC6C907381E6095297E +:10C9E000BE4A5DF7509D99CBC51B149010BD96496A +:10C9F000611A57BD4CE2FCCE69B6F37C3CC702E637 +:10CA00004CEA37087F56E59DE6A13EACC9E6FEB884 +:10CA1000EA949CBDA92291EFE72CDB3A9DE8F455FE +:10CA200075220D37983753994A7EE3EBD689DA4F52 +:10CA30009FB3D2BD370CEBEB445ADD67A23A915657 +:10CA4000A70D783FD7D59503D2483DE12BD5472E8A +:10CA5000F23A7120C21C052589FA516060D4CAE9F6 +:10CA6000ABD68D70BC95E60D748BFAD141DC9FDAA4 +:10CA700008DE57C173FC23DE97DA28DE979E1FED90 +:10CA80009ECFDB58B793B7C7BA97F0B61AC5A63092 +:10CA900087EA4EA3BCEE5453ABAF5B68750977A130 +:10CAA0006F496D8DAE6EC1FBA9750B73BAC8470394 +:10CAB000A72CCEBDF83C70DAC6EDAC2BDA328BE297 +:10CAC000B29B67FDB31CBC0E90CBF3CA31F9559CE9 +:10CAD000F66CCA077C4E3BD50BAA07AF58656E773C +:10CAE00062455040F853DC4A793FD141E1F19CCB9B +:10CAF0004E74FD4A7C3FF2FFF8FED7C1F7A37502E2 +:10CB0000DFD7EC4795CFA4ECA1F69462DF94641FC5 +:10CB1000FA7C0227EE2B9DCDF5EF79DFECEC8DC989 +:10CB200078BE57E47139CB4AEDC9CF59BD45C47DB4 +:10CB30000C7C4676ACB776427BDB6B1CDF19D705E5 +:10CB4000FABCC28E68B8FFF83A81F3ADD224BCFFBC +:10CB5000DA3B28A798B70E1E4EE3FEFCE691B4BD63 +:10CB6000147F577937CE9A82FDAAF3695022FC913F +:10CB7000AEBED0E43529F62CA37A82526442B91DA8 +:10CB80005737F09AB87D1FAB1B78A58BBCAFC6E9B1 +:10CB90001B467F37A58411FDC321CA33DE6867CEEB +:10CBA00041185F47C0858B6009DEC27B8ED7959D9B +:10CBB0009DCC29CB5F5D5FC85371868E48B699E4E2 +:10CBC000BCF904402E33AA337879BC5F05CF866A5E +:10CBD000E97BAC529383FC592A5E407242FE3F15BA +:10CBE000278CAA7C8CD60A7F53E711FEA64A8D4B70 +:10CBF000B479A9FCCF56FDD344B82353E39F1E6FED +:10CC0000551FF12FB8D204E4077ABC6E5B69D27A63 +:10CC1000676AC5774BBBA86E312DB96E21EA13A99F +:10CC2000F50ACD4E550F7E514FFC7F3E2AF0A440B1 +:10CC300081C037AB8FBA4E91DE27CE29EEF73CF29A +:10CC400038CEE3286736887B814DE05E1C67A85AA2 +:10CC5000F9F9B10CA29F0FFD15D9A5D3A53B32C997 +:10CC60009EAC946A98CCF1EE31FC9BF0A9D5675A42 +:10CC70009703F9FFB50BCF12DDD7AEB7F0EF9034C5 +:10CC80007FB5FA4C63BD78BF677B3ABD9FCF9C767A +:10CC9000999E7BDDF47CC5AF6284F4C183747BD440 +:10CCA0009BF8E9CB12E9CBBC99FEEBA43FD50D2A4A +:10CCB0000EBE5EF8D7B5D1060B648EF777C78B6FC3 +:10CCC000F23CFA46B49AE3DBB9547FAD48F88BEAFC +:10CCD00023E887A6FCE9FC50769DC807EF453F4452 +:10CCE000E7C9691075C254FE9F51E3C989FCCA4463 +:10CCF0007694FC886989D01B5690F0BF32E5D7F74F +:10CD000025FCB02382FDFC2FC1BD55B9CE9E200E5F +:10CD100073ABF23BE1F71B916F0607FF8BBA3F8FB6 +:10CD20007A9696E76878B89617BDA8D2596B5F5285 +:10CD3000DB54BC4CC3C9F21580AE2FC1C9F2094700 +:10CD4000CB21B35DC171BB42F50C63B8592CC774DC +:10CD5000A71CC7A9B89D869FE56DE86714671443B3 +:10CD6000701BD997212BB80E4CA3EFF6186C23FD3E +:10CD70000E37F03867E8A5F77B7F41DF1B0E3007E1 +:10CD8000B99FF6FEB3DC4FB7635CC3E3A1E8A7022B +:10CD9000A7EA17DF9BB647986284830EAAFEB956AE +:10CDA000016E37DAD5EFFAEA07845E2770A21F49D1 +:10CDB000C93851408E4FD7BE170C0BFF64F85D5F2A +:10CDC000078CF0EF013B5A993386CF5371A354BCC3 +:10CDD000E859F53BC0097123E5EB7DEFB7BD6EEC7B +:10CDE0007B3F8E3FEFF308BBD0E8678CD6B7997CCA +:10CDF0006DFCBBDFA3CC61F4FDE86E55EE57A8F8DF +:10CE0000EDAB56210FAF7E8B85299E5B0102A77D7E +:10CE1000F5680BC76F5FAD624E13DD53C56B97AB03 +:10CE2000F4B83B81D73E4F78EDF7D09D104EBB4212 +:10CE3000E53F40989FAB61777A8CE28D672CFD05CA +:10CE4000A48FDAF7465E15474D4F834E23FDECA9BC +:10CE50007379EB6A68DC84F1CE2B7506F8CE558FBA +:10CE600058F7977518A7CF07A3387D7FDD745D9CB1 +:10CE7000CEFBA971FA9F0AAFF5D03D8DCFFFDF93AE +:10CE8000C4ED1EAF9DDCB84D7506F1DF0E153F49B0 +:10CE9000A56F66BD66876738B83C8D9D1F443D57BA +:10CEA000C5BD86543F1762F26FEFE7F52F0BAF7FDA +:10CEB0006976263445ACFF816A5FB4F6A6DA862C23 +:10CEC000C6380DAB177EEADB85CAFBC4C7F2D7F4C0 +:10CED000B8D9827E3D6E766F2447D75F18BB4B373B +:10CEE000BEFAD46CDDFB9AF83DBAF7F79DAFD2F5E8 +:10CEF000970E7F4B37FEFE4FDCBAFE7746F4B8D96B +:10CF000003B7F4B89926DF2E9488E4791EDB0F74FA +:10CF1000E38A5AF5F72AEED4DF6B5697FE5EDABA4B +:10CF20002541FDFDE684F4F7CB215CBFE27F8FEB6A +:10CF3000FF4DADCCE97F2C3AC74EF376794BED141B +:10CF4000C74C2F14F2AA8DFB1FAC27E8D970300014 +:10CF500000000000000000001F8B0800000000001F +:10CF6000000BE3146060F8510FC1D3F9191836F3C0 +:10CF700023F8F4C0C79819188E83302303C33E20CA +:10CF8000DE0AC46B80F83D0303C352203D078827A7 +:10CF900003711710BF048AD5B1623787858D8181EF +:10CFA0000D884F02CD3AC54CBCFD8A7C08F6215E47 +:10CFB0000686B5407C9497BE6130D8F00C41FAD912 +:10CFC000F50C6AD76ED181F73708B38A3330304A0F +:10CFD00020F8FD12A8F26CE20876960C65769501B1 +:10CFE000F50300295128158003000000000000000F +:10CFF0001F8B080000000000000BED7D09785445F0 +:10D00000B670DDEE7B7B49BA3B9D90952574802000 +:10D010002A4BCB1201113B2189010306440928D276 +:10D020006C2184249D01661E3EFDFF6E0842C4D122 +:10D03000898A1AFC195F83E004079DE0A0139DC054 +:10D04000348B8833E804C70597795F401E2042126D +:10D05000A338E8F3C9AB73AA6EBAEB763769B7FFAA +:10D06000F97FFF840F8ABA55F7D4A9B3D5A95375B0 +:10D070004F14924292FA1372097E6E20E455851085 +:10D08000FAA8BBEC903A87CB0383ED6BBD2EE2325E +:10D0900012F280D784E57A6F3A715D419F8FD61581 +:10D0A000F92D84DCEFB5E3F3C7BD25583EEA2DC565 +:10D0B000F211AF1BFB3DE42DC7F257DE1A2CEFF542 +:10D0C00016617B9D7715D66F5416A4C1B884B84CF1 +:10D0D00059C984785E1E387203ADADCF1C9F208F76 +:10D0E000A6F5BFEA893E8BBE375A2EF20FA50D7208 +:10D0F0004951D6E8603F15CF1B95BCBE00E7F1B1A2 +:10D100003AD6CF54F35A76E47E59640CC573AC8C8E +:10D11000F8134BC9E4ECE488FD0603BC4786B279FA +:10D1200012BBF3B54191E15D0DF01E1ACAF14BB689 +:10D130004F1E14199E13FAFDCAC9E1A5771E1E18C9 +:10D14000B9DF18E857E7E4F0FAFA4C03228F3B1EE8 +:10D15000FAC5C0278A1321BE16A33F3BEBFBF38B16 +:10D16000B8E85F8A4FC75EF3D60D12F26F1AD06926 +:10D17000AD7DF9992D749CF696614EBD8390CF5C80 +:10D18000CE04BB2526BEDD02F388816FA5304E0C90 +:10D190007C9B1B23DF1640BF18F8B604FAC5C0B746 +:10D1A000CA18F9F6B39F08DFEE053CBE07DF36C4A8 +:10D1B000A86FBF8A916F1B63E4DBA618F5EDC91851 +:10D1C000F9F65428DFD4E76AB9834868176F544AE0 +:10D1D00076403F4F669B6D40D64F827F7BBEA7DE79 +:10D1E000ED8F917FAFC6C8BF23409F18F8773446B4 +:10D1F000FEBD1323FF3E8851EFDA709DB1C85FB5C5 +:10D200000D21F8736900FC6BB19FBA9AD7F580774E +:10D21000122119E172A09694A3280F3271B7B37549 +:10D22000ABE09B4B3984AC30D1FFD2F77D7924A0A1 +:10D23000A7E3FB6CC45F2B09FD3F073C09C9FFE670 +:10D2400052AAD0DFA78BD89FE8A0FD61902BCAFF20 +:10D25000CDDE2158D67339DA5CA44379F0251B5012 +:10D26000BE9EF03AB1BDC13B16CBC7B85C6EE4724E +:10D27000F400C8DD152087A55CAE98DC1152E228C9 +:10D28000A774EDD8134F363850AECC12E02933795D +:10D29000BB77CF955B3750F89B6B74576E0B91B390 +:10D2A000278A54F9A292991CECF744F909DB82A170 +:10D2B000486F1BC06928D6A9FD7CA1FD1ADCDDFDE5 +:10D2C0007A41BFC78AB97CC924103AEE63A5DDFD57 +:10D2D000D2254A977B2552DA6409E7CB1489E929DC +:10D2E0005514E487CCE9BB3FEF2C69A3EFDBEC23BB +:10D2F000D3082D9F04FD44FD7360A9BE5F4FE9EC88 +:10D30000A6F4C834929A26C097B44A0AC5571EEBB1 +:10D310004804397A689C8B485642FA433B1DBFCF7C +:10D32000E8369245CBC4F16D441A06FD683BADA7C3 +:10D33000F0F68CA1B49DC27908DAADC1F654DE9E38 +:10D34000E6E0EF5FC7DA1FF6121C5FED771FE5B36B +:10D350009BE2B78EE28BCF8B890BE8285376FA439A +:10D36000E63F5BD2E3BC2B79A9E27F5FF6A98CF99B +:10D370004383F89A075FCC981F82DF7D83E7605D67 +:10D38000C5C77C4525D6FBAFEA4D3D31AE0F249C89 +:10D39000CEA9330708ED0ED9897E9AE3889EF82836 +:10D3A000BF1C543C23F1E70B2ACE3FA8FEB9183D21 +:10D3B000B4ED776BE8B02E43A483A1B7488775BD61 +:10D3C000453A18FA5C9E0E532407C28F460F75DC4F +:10D3D0000D578AE3C65D258EBBE12A71DCB8AB7FB1 +:10D3E0009871D7F713C735668AE3AECF14C735F601 +:10D3F000FF7EE312D9491F3273411CF0CF3CC1BEFE +:10D400005D20EE8741BFC1CEE99383764EB697107B +:10D41000B725C84F22D3977342E1DC29D8550AE7D4 +:10D42000FF7038AECBC3B16BE0CCD5C2D9C6E190AA +:10D43000503B1D0687DCA19DC76FF97B015DC8F8D5 +:10D44000747D2525D6D0F79C9AF16FD78EBF1BEC43 +:10D4500018CC4377D9F11D1ABACED1E2B387C321D4 +:10D46000BACBD183D83570666BE11CE27002D2650D +:10D47000E1946AE7F1BACA574958BF283D8605DFEB +:10D48000EBC8EB3C857ED08B8A633B6D97FE640DC9 +:10D49000DC40FB1FD922F98DB41ED81B8FEBC7F9D6 +:10D4A0006DD3B1BEEF1A23AE13E79D93FD466A4FCD +:10D4B00026BDF0B60DEC4BD50B7A19EABABD1FDBD1 +:10D4C000DA285E1E63EB83D7D1E79D2FE8C9569417 +:10D4D000C6421DD0FD14974DB28AD5CBCCAC5AB5FF +:10D4E00065DF9D00B7BCD948CC144ED54B4BA65D2B +:10D4F00047EB4B0E2B04BA546D5F6DE84DEB4BFDC3 +:10D500005213D43BF24839E8D39ABDFFD90EEBD180 +:10D51000F9DD4A368C7F96AE130E6A8F8F585B53B7 +:10D5200067523C2AFCBB0AE1BD8A9D92935A388A15 +:10D53000EFF6431980EF0EC969A4F45ED6184F1CAC +:10D54000AABDA37F4FEDD6E3FC97D3F9130A6F0969 +:10D55000A92F047A560171607CA7D16F9682FA7662 +:10D56000D67B18C753EB553BE878F4FDEAE7242750 +:10D570004CB55A47DC8067FB4BE6D2A72C30CFD5A1 +:10D5800086C15698DF7A03F45BE29FFFA2D9017847 +:10D590006E311402BE9BB718CA8602FDC8BC92A1A8 +:10D5A00080DF5F44FC1AF42E98EFF26B8C5BF5C0C1 +:10D5B0004F4B60D00C6BB89D3D4BD72B47C8FA59E9 +:10D5C0004198DD27B2DF307D58F0F94BFA4494835F +:10D5D000658D7AE208B51B5C3E7C4709F363F6581B +:10D5E000FDDBB3827C5C6EE7F2CAF9B83C91F3557F +:10D5F000EECC99312C1C9F07812F46E61F41F93054 +:10D600005D371DE8FF38907E8F51FFC981FE911371 +:10D610009F3F41FD242837533F09CA27A99F04A5EE +:10D620009FFA49D06F2BF593A0DC46FD2478FE3499 +:10D63000F5CFA16CA4FE393C7F86FAE550EEF4FAF2 +:10D64000F0F973DE3A2C9BBCF5583EEF6DC072B713 +:10D65000D78FFD5EF43662D9EC6DC2E72F7B9BB1AC +:10D660006CF106B0DC0B7CA665C0DB8AE57EEF3191 +:10D670002C0F7ADBF0BD43DE3358FE92D3DD3681CA +:10D68000E4CA545E6C2E6207362515BB72C15F4931 +:10D690002A61F5D43B7CB9065A4F75D33AA563EF9E +:10D6A000CA40AE91D67BD7B0F6CC7B489E89D633A4 +:10D6B0007DAC7DC02F5D79665A1F50CFDA076FF6BB +:10D6C000E5C5D1FA603F6BBF6A67202F9ED6AF6A6F +:10D6D00062EDC35BC8240BAD0F0FB0FAC823AE498F +:10D6E000565A1FD9CAEA391FFA26D9683DA78DBDF7 +:10D6F0003FFE5C605202AD8FEF64ED13BF26F976FA +:10D700005A9F4824ACE75972F313693DCFCEEA859E +:10D710007DE7CB8E08EBFB5EA56D2198B49FEB7285 +:10D720007265EA27EC35B4AD0093BB5E7743AE3C3F +:10D730008ED24F218BA07D93AE88D50D6425B4FF8A +:10D7400056371DEBFB1507B6EFD1CD61758303DBB3 +:10D75000FFAA5B88F5838A0BDB8FEB2A59DDE0C2D9 +:10D76000F6CF743FC7F10E296E6C57F4FF9BD50DB1 +:10D770006E6C7F585E9F9B4FFB57EADD1E1D95EB3D +:10D780005AC95D4E0682BC36A5833D5CC7FDD6599D +:10D790003A07CAFDBA0C03EAD9DEFFCA790AF50CCA +:10D7A0007E92A15EF634F8BD14CE2A84A35038FAD6 +:10D7B0009EE14CFC66AC0067E237E52A9CD508C7C1 +:10D7C0001C1B9CBDDF8C17F1F9A64285B34147EDC8 +:10D7D0007DAD35B6794DBC3441C4E752A50AE71199 +:10D7E000C42731367C02CAB5029C80B24485B31985 +:10D7F000E1A4C4868FCB304E80E3322C55E16C47D8 +:10D800003819B1C10918AE13F1312C53E13C87F43A +:10D81000E917DBBC5CC6EB457C8C552A9C3F203E5F +:10D8200059B1C1D96F15E9B3DFDA4D9F00C2C98E76 +:10D830006D5E7936913E79B66EFABC8670AE8C0D0F +:10D84000CE7E9B489FFDB66EFABC897086C536AF0A +:10D85000BC04913E7909DDF4F900E15C131B3E073D +:10D860005344FA1C4CE9A6CF49843326367CF25344 +:10D8700045FAE4A776D3E73CC219171B9C83A9227B +:10D880007D0EA676D3E70B84737D6CF3CA4F13E944 +:10D89000939FD64D9F4B0827D7DD88F8100AC71AEB +:10D8A0001DCEA17E227D0EF5EBA68F490F700A28B2 +:10D8B0009C813DC329CC14E95398D94D9F443DE840 +:10D8C000C5E4D8E01CCA14E97328B39B3EBD119F80 +:10D8D000A9B1CDABB0BF489FC2FE8C3E1E63E7240A +:10D8E0003BF88D89C4B995BE3229F9670761DD51CE +:10D8F0002CC409608F48816D009FAEADE897CA4E79 +:10D90000D50F7212F0738B6D0E27C403F4AABF43B8 +:10D910005A713F62D99928C49B5ED2E70D077CAD4E +:10D92000D42B0CF57B12C6C609FE56A22B49A8F7CC +:10D930002AEA2DF44F291920B4A7955E25B467B8BB +:10D94000470AF53EE5E385FEFD6AF2847AFF55530A +:10D9500084FE59BE19427D60DD1CA17F76FD02A1C7 +:10D96000FD8A860AA1FD4AFF72A17E75E3BF0AFD0A +:10D970008735AD11DA47346F10DAAF093C2CD44744 +:10D980001D7E42E83FA675ABD07EEDB16784F6718F +:10D990006DCF0BF5EBCEBC2CF4BFBE73BF50BFE117 +:10D9A000E29F85FEB9E46F427D92E903A17F81FD8C +:10D9B00023A1FDC6F44F347EAC18BFA8CD25CC9F63 +:10D9C000CD30A03F1BB01AB06ED86B66FB1BA827EA +:10D9D000431CA218EB86FD0B1DC9100F0000D49F3D +:10D9E000C8ED5D7E05C4AB7E31DE7D05C4717F610F +:10D9F000708FB047F083DA65F73D7A8C27B64A24FA +:10DA00001D4A870ECA383D8F271899FCAECFCA79B8 +:10DA1000CA17A20775FDA87F41EBEBF5148F3141C2 +:10DA2000FD59DFAF2C7D7EC838EBFA194AB70E6579 +:10DA3000CF175A60BC92FB603C8FA17330E0A51DEC +:10DA4000C73860AC308E29B31CC7D908E3A404C71B +:10DA50003166966BC631956EE5CFF9388F81DE441D +:10DA60001B67FD80F1E27C322B709C2D9A71D6678A +:10DA70005668C68963F3A1CFF9384F5D6E1CE3C0C9 +:10DA800009E27CFA57E238CF69E7D3BF52338E05FB +:10DA9000C781E7300EE94B77316994CFC6CE329417 +:10DAA000833F99314E66E853F11BA8930FCC241B9A +:10DAB000C671D071693F3224890A3521FFA24F42D5 +:10DAC000FE7C1147F91F124F0BEEC77DB8AF5FCC3C +:10DAD00051247E8A11DD275573D95CB4737AE60A26 +:10DAE000072D9B0F0C7A04C6D9687566D37A7BF331 +:10DAF00024C3C208F2B4B85E39D51622E7DDFBB301 +:10DB00003C32A4868EBF22CE8EF8A875B54CD28941 +:10DB1000CF4FD07D17A1FB930FE93E85D0FDCA47BB +:10DB20000ADB67FE3BDD9F41BD8DEECFA09D90D50A +:10DB3000F8DE091E673EF14BC90FF4FEE2AE9F29E5 +:10DB4000B84EF8C85BE9A9104D603FF356C553269F +:10DB500004F19BEFEB25D4A939EEA34BC77D2DC66D +:10DB60000F3A5F32FAB7025DEBFA509AF27E030881 +:10DB70007977EFD443920DAB7D746309995933BD26 +:10DB8000200DB548EAB79CE23963F7350A7D83B4C6 +:10DB90002B6D773A2D41B8C4A59C00FA98E81F80F8 +:10DBA000734B11AD878C7F6B89589F45E4609DF264 +:10DBB000FBA47E0061F17F3EAEC3A5005F4BE81C75 +:10DBC0003328AB674139129A59BCA6D4CEDE55F141 +:10DBD000F12C544800F7D7BE148863135F32F69BCC +:10DBE000A3EE9335F8952A265709A56BE97C3DD21B +:10DBF000558BEFFB7BE35DBAE1B4AC7B4481D06C29 +:10DC00004FF8CF768BEDA49C8DA7D2559597539C5A +:10DC1000BF2780FFB43C0DFCA7789FE4FC0FCA31FE +:10DC2000E3BFC7E89E06FCEFDCA427C82FCEF7DBD6 +:10DC300038DF17D78B7CBF0DCEE368FFDB5666B1AC +:10DC40007853432F81BF74E2221DEA1F2AA0663554 +:10DC50000CFFBF73399853B7EB1560EFEDE59AF9F8 +:10DC6000713EDCC9F93057438FDB38DFE672BE2DD9 +:10DC700021BE7B33307EE15720AE37BB5C22602F64 +:10DC80003C77AB7C6B13F8E656F9A6C1F74ECEB7DE +:10DC90003BEF627CD3E2DDC6F9D6D6F0994206842A +:10DCA000E3ADC573DE2ACDBC7C5ABED573B9B41BB7 +:10DCB000C09F9AEECA5D7132A4FF2D4593579C0C0C +:10DCC000B10BB7964C17EAB34A670BFD67BBE70B7E +:10DCD000EDB7972F15DAE7D6FC4CA8CF5B7597D038 +:10DCE0007FBE6FB5D0BEB0EE3EA17D71FD43427DDB +:10DCF00049C326A1FF52FF16A17D59E30EA1BDAA7B +:10DD0000699750F734BF24F4D7EDBDF26690AF2386 +:10DD10006FEB09C4FB2E384F639CF1825371429F15 +:10DD2000935E07CAF129EF102CCF789D28E767BDD5 +:10DD300063B1AC06991C0776F68005E2A79E386AA7 +:10DD4000F713E93A2E8F5B533701D61BDA3E9E90CC +:10DD50007F956F58E3EB4BB500E2DE94FEC50D06F0 +:10DD6000121845A874F7EE96E74E7D487B5B0FEDE1 +:10DD70000D3209F40A6F2F6E8BFCBC43EA1C9C0128 +:10DD800071D9F78C647B48BC31FCBC85F401BF229F +:10DD90005AFB391D290F3DEFD92AB3739E23FABCD4 +:10DDA000AD32C5ABD2C0F4BFF2F98C3C62837A606D +:10DDB000708DE532E3355164D280CF0305BD5FD26B +:10DDC000707550CF098CC3ECE952FF28E1F9B2C657 +:10DDD000EB84F7DE90DC5B008F73FBF4B85E93C0DE +:10DDE00081CC5B86017EAEAD32ACA3CD29E877B5A0 +:10DDF0007A5D2B4E2A84BCE92DC2F22D6F0996EF75 +:10DE0000784BB13CE67563F9BEB71CCB0FBD3558F6 +:10DE1000FEBB7715966D5E1F9627BC75589EF4D68F +:10DE20006379CADB80E519AF1FCBB3DE462CCF790F +:10DE30009BB06CF73663A9DACF9EE4EF0C5F5FCF3F +:10DE4000821C1AC3E5ECE0DA796BEAFA06E5ECB07D +:10DE50005C8672A6D2B7B8C1C8E521559087BFC20B +:10DE60003A9C02F2D2437B83C2E530DAFB91DB417C +:10DE7000DE7AFF08F246C81A94030BC8DDF7903724 +:10DE800002A70829204F7D34F224CAA12A47AA9E5E +:10DE9000BF21959C03F952E5CA22337F4895ABFB1D +:10DEA000C14F8CE06FF55624BEFE31FF88047275B9 +:10DEB00040B2E5FCBC82F85C58EFE263D75270AD2B +:10DEC000D04FF60F8175A46BC8578321BEDF758CC8 +:10DED0000A4156F4F969E5253ADD5DB87F28F35328 +:10DEE000E6F70A6F37C731BA9A75A4888C84F3E5D0 +:10DEF0009C636ECACFB83F5D3D12F6CDF4B94C922B +:10DF0000008EDF393DC27901194490CE3DD157EDE5 +:10DF10007FEA89FFCC81737F0BE8399D7BDC017D33 +:10DF20000DD3DFA79CB7849C2F798CCE7488837720 +:10DF3000661BECCC7F9824D2914CC2F303958E07DC +:10DF4000B2BF180CE733F7513904FDEA1A343881AF +:10DF50005C463E7AB2F73DD17301CC37267A1A0877 +:10DF60009C73517A6E85FB8EB1D2B3273BD9937DDA +:10DF70003CB181D1F908F74FA3D1593D0FD3E271DC +:10DF80008B22733E7039267768E85F2AD0BFAFD501 +:10DF900081FD0FEEFD2013CEF1BA765F91408686AB +:10DFA000BE5FC0CE7BBADFCF17F440FAD3DF336158 +:10DFB0007F7CF08577B15C4B981E6EB494CC55C6CF +:10DFC00004E1C57A8F20DABC3C8A24CEAB07FDEC95 +:10DFD0004855F5B33513E46937B70361F3EB413EB8 +:10DFE000D5F91D80F951385341A6E93CF2E592BBC1 +:10DFF00084F98D4EC179F7343F4F82814823287EC2 +:10E0000056838124507954DC6B15DCD739DB7C10C6 +:10E01000A7D81BEFACA52CF1D8CEBE1170C07B6287 +:10E020003C6359A3B946F49F126B44FF29A326D43D +:10E030007FEA3AFC94CD4DF15B9EAEAF39D90BD659 +:10E0400039175FE7D8BAAAE257D594556311E0882B +:10E05000F5AE7AA988DDC37124CC8C70DEA796CB8F +:10E06000D30D38CED9C6810930EE59AFA986ADAFF0 +:10E07000F61A366E7A4DE8FA5AB92ABEE6E4A820B6 +:10E080007ED1E0FED0F85189201F99605DA46D0318 +:10E09000A3F78FCA4FF973039EABB7285F80FF6E5B +:10E0A0001EA2FAEF32D655B89E26BDCF38029EEF9B +:10E0B00014C6A3EF39D4B371782FBADCC8E494CA7C +:10E0C0004F3D9C7711BE3F30219FDD14620285D702 +:10E0D000215BEA40AEFC0AD3670F97D32A539BC15A +:10E0E000ED4072B7825C2F18ABCAB963D607D44E25 +:10E0F0007FFC1705EF9991AF29F49CE0558745A463 +:10E10000C40641D505BB9715C3BAFDF18B37F17D28 +:10E110007A7D0ECCFB3CD115815D3A4FDEB48D0A81 +:10E12000D1D7D30A8B63913AB6CFF1D13F30BFC577 +:10E13000F5E2BE674983582F233352C1DE966D54F2 +:10E14000889FE2BE14F64DEABCA9FD7D57B123724B +:10E150004B48CD3AD8A73FA6B078CF023B91FB50B1 +:10E160007B5DF5875FE740DCA75D61FEAE7A1EBE92 +:10E170003489ED072B66FA0D2EDAFFA3DDA36EA31B +:10E180001697BEEF5F87FECF74E2DC4EC2E9BEB0E9 +:10E190004EC4AF27FCB5F8AA7E50D8B93CC723B906 +:10E1A000518A785FEA6B6EE754FD4832D885B84FE4 +:10E1B0009AA6AECA81C2E5C0AFB8AD8614C677E0F4 +:10E1C000A324771ADC21FD0CC17E498631D1FB19CD +:10E1D000A19F1EFBA5B17E9D85B83F26549E860655 +:10E1E000FB9983F0FAB271C57E557F78F6451F958D +:10E1F000978ADF3D6A2374DDFC58AE4F75D2E795F0 +:10E20000DBEFB5B9687946F6D9809F1FFBF511EFB2 +:10E21000FBDE6250E9E1B248104FE3F249EA7C18B4 +:10E22000A7F862BB62C773844663C048E5B37AF758 +:10E23000D262321CEBC7597DFDA77AA8378BFCAAA6 +:10E24000F8CDA3A90E764F88C5934800FDDCEA6D92 +:10E25000FF5108EB858774A29C69DF83F12F26A10B +:10E260005ECF372484B7E3C5E054789FFD7876DF2E +:10E27000FFA9DE06E5E4D3A0471E8D9C9473BF156D +:10E28000E805FBFD7C833519EDFDB5E45AD07795A3 +:10E290002EC4CFFCD7DA1D8F0F3F4EF13AB7ED2FCA +:10E2A000366968A89D60F2D6D5B4F0DF4CBAE8F6BE +:10E2B000A49DCA63A89F4401E37B8E66EE77B7B046 +:10E2C000B25209D8E03E4EE516C5492591543EAB01 +:10E2D00027703F81BC67F4437C74D9B3AFBC339ED5 +:10E2E000D27FD92E25B9984DC722A506F9E3A17F83 +:10E2F000578D0CF2A3E2F7AF181CC3D8F37B9282C0 +:10E300007C59B66B9F810C0BA7E3A4A67D86364B88 +:10E3100004FE341D2F84F5B676C73F0C1057FC78E9 +:10E32000AF44D2B2C2DF2FDFF20AAE7B4027E42730 +:10E33000E75737FFC2F81698F6F268EC67077BD804 +:10E3400013DFB2613F9782F2FDDCCB708FE97DA3D2 +:10E3500013E850FEDC0A1BCCE7B45CC3E4FCD7F73F +:10E36000A682BE972BBE543B96EC79F9933F47F9B2 +:10E370005B72F4E7A9E83F1057860E6DB32F03E6F2 +:10E38000B978F3AD38CF32E246392CFFB5BE04EE92 +:10E39000995E9049D1AE087AF21703DBBF9CDE4A42 +:10E3A000994BE7791AF003FBF6A6DEBF1DE3E63FC3 +:10E3B000C37B703FE773A62B21D62F9818BFB618E2 +:10E3C000746A3CD424C8EFB6F5ADC0A7B3FD5C6950 +:10E3D00070EE41E9E0E374932E51B8FAA305698C1D +:10E3E0004FC421E7F0F7A8BD9F04CFA17FABE23275 +:10E3F0000F17DEE3F6918DBF928F4FF18E83F5EB11 +:10E40000746A64FFEF1F7C7EF4A79584C85988BEA8 +:10E4100033FDDF761FD37755FFFDD38BA0FDF3B718 +:10E42000981EC17BB05E50BC0269D8BE6FA684F650 +:10E4300081EEB323E9F93685EBB9D84E7738B8FECB +:10E44000AB7242F197A5845079A1E324211F707F1C +:10E450005CB691BE1FE29779605CEC67083E0F598D +:10E46000379670BB7048630FC8E69498FCE84AC5BD +:10E47000FFF413A0BFEF199D3E07E8AF5202F3FF70 +:10E4800064E78177E65039FFA449D55BD1AE6AF5E0 +:10E49000B6FCF9312492DE7E62A1FBAE487A4B9F36 +:10E4A00047D45B4B1BCAF3FF2DBBAAD2AF5D433FE2 +:10E4B000B08F2F3BA2D3516B1F37181C11ED23FDDA +:10E4C000798BE484CBA12A7FAADC55FCB6AA3FD87D +:10E4D000A16EF954E5AF5B3E55F9D3CE57A49FB674 +:10E4E000FD0FA0DF14AFDB4D9BA681FF6CEA241863 +:10E4F00087CF9DA9C77B9AA6CF09BBA771473CD6FA +:10E5000067E9DB7E0F3EE10755B386C13A7F3BF1F9 +:10E5100029ECDCBE5E413FF6EB4B9726D0F9CCE10F +:10E52000F4BD9D927B2AE547A92C05E2289EB365A0 +:10E53000E24B488278B2444E84E0717BB958879FA1 +:10E5400089A941383DF5FFB67EF7772D8F52BE9EE3 +:10E55000C826E46F50E2FE833AD621F234BD859D91 +:10E560006378464BFE01A8876D7249C83EC263645A +:10E57000F6E768FE2D63807EB9B3862530391F8C9F +:10E58000FB450FB7635D3E4702D8F7AE9681B82FC3 +:10E59000EC3ABCD0EA8E60CF0E70397B859FC37495 +:10E5A00058A47A3D95FB0ED2897E8DCF628E189746 +:10E5B0009B6354ED34E71BFDD1D3F14BB91CCEA6C0 +:10E5C000AF268C0CE1DBCCA91FCBB6703EC0CF8947 +:10E5D000907DC5F7A52FC835D0F780B9ADB02442DE +:10E5E000FCA692D36FE2FE2F0DB0EEE5B7E4CA4071 +:10E5F000C77C8B5E88872C32727D1D4A86025E1333 +:10E60000F72F7D600C9563CF61BDD34CE7E769F9C7 +:10E61000D4E08EB0BFD3D213E0837FB9D5C8FCE578 +:10E62000B79592C540D7B76F65E7BD7F3338AB224A +:10E63000E1996E66FEE66C527261B4F4D3A36FEE9C +:10E640002C6B208FD2A3CBC2EE6B87CB1FD3FB2EBC +:10E65000BBE45F2D811CEA593D99DD6F2E24EE0746 +:10E660002648A8EF3784DAAFDCE6E9CFC27D9AEA24 +:10E6700016C9AEA3EDD5729B01E4D8D3BC4B06BF3F +:10E68000FD260771E1FE5AAE19363324FE45973D4B +:10E69000A4D781AFE6CC05FA7E36D348002FD7D079 +:10E6A0004F6DB0FE7FD6320AF520DABC5EF7926974 +:10E6B000F90AC061F64C2B0F85C9F142FDD649A479 +:10E6C0002F9C034F34B6AD7046E05FBE89C959CC6C +:10E6D000F6CDF4FF997D9B40ED1B936B25D4BE597D +:10E6E0004C61F62D2D927D5BBEDA910672B17CCF26 +:10E6F00040FC7E6BF96B8B5322D9B757F9BEF735C7 +:10E700007E0FBCA32FB56F2342EC5B5F6ADF22C490 +:10E71000C9BF88D5BE99FE67F4EF55B06F11E66B9F +:10E720003689F6ADA86535DAB7A2BE7AE1BE1231F8 +:10E7300051FB167F39FB36FFD15BB1AE38E323C8FE +:10E740000FD015ECDB6BDCCEC13860E76E30B1F872 +:10E7500066AC76AE5FAC76EE7F88CEAA9D5BDE4F70 +:10E7600042FF255C0E999D5B9EC5ECDCF23DCCCE54 +:10E770002DCF66764E6BDFF2C2EC1B7BBF7A087D35 +:10E780001FF78F598FDF01F7094B15A789F62F76F1 +:10E79000A8DF4FD48C09B577379864A47398BD73FC +:10E7A0007E8ADFC1F464EFFE0AF62E1BEDD820D07E +:10E7B00023AD7C4C19142FDC677BFBCB53BFFD1DB5 +:10E7C000E8CBEB7ABC2FF4AE8EED8FF67E796A142F +:10E7D000E8DD4326667F9798183FDBBD3EB4A793DC +:10E7E00086327DAFBA87D1AF7AB7C4E6BB52EF7736 +:10E7F000C03AF0D545DC3FCFDDC3F6CFB38CAD29B1 +:10E80000F1702FE95F14C2BEFB20C5F343E4A1F40D +:10E810006205C6019F8FB36D85FD65A94C4CE0C7AD +:10E82000CE3B3CE563F05FE75DAC43BF771E3C87C2 +:10E8300073127E4F42BD4731A779D72B7D48F8FD33 +:10E84000888946C687892B24FF962CB88F20B6CF9F +:10E85000D3F8F5EBF83CA93F8B74217FD5478CDFCB +:10E86000ADD3D2C3C9E65FB5522FD2A3468A480FB3 +:10E87000CAD1E2F9A9C1F9CF7DA16D5D1F685F2AF8 +:10E88000E17E4AA587769E2A7DD4FDCA3CAE239EB2 +:10E89000965D0AF04B3B7F957E61F356E9A9997F1F +:10E8A0009D6A3FAE26C340DFDED5B91F1803F2F1E3 +:10E8B000674A078AD76DB3B3D342EDF183DC2E4D9F +:10E8C000751FCF4F7500DDD8778973CA77BD924A1F +:10E8D000E773B32B6B247C3F7CEB570637C4170ED2 +:10E8E000983BD1BEA9F2F50997F70087F3766F7BC5 +:10E8F0003EAE23CD921DF526A0B15FFCFE98E71E2B +:10E90000A65707A47FACEB331AE90ACB002954D7EA +:10E9100021E003FDEFD416C6070FF081FE771AE958 +:10E920003C0474AE4E969C01E8DFBCEB5E909B57B6 +:10E93000CDF439E86FB9E464DF97114B46EA65E539 +:10E94000538E249F189CC809AE8BF3A05F52B8DF8A +:10E9500031D1D8FA36E03191EAC31612EE87A87C9D +:10E960001F42FF5C8A74EFA70739FE98CBE7AB40E4 +:10E970006F0BD0B5D300FE8C27C0D60FB5DD233B7F +:10E98000F2913E2ABD9BE9FA309AD15B17819E37FE +:10E99000AB754E4F4F8BA4C0FB93E9FEB59704A710 +:10E9A0005B5F1E52E518BE87D3D203E20119217ABC +:10E9B0000FF629F47CB2BAF928D265CA4AEA5E8514 +:10E9C000D01DECD6E5E8134D2FAA9B7F18BDF84467 +:10E9D000A3177BCD9D7F1901F1AF3D12DA07D292CB +:10E9E00028ECF7E3CDCCCF386076A3FC76BEA6E06A +:10E9F000FD73AD1DF99ACB3DEC2F42BFFB9B041379 +:10EA0000013B6737938F543C0630390AB5DFAF9A24 +:10EA1000DDC8AF68F0E3F83A1CCD7F52EB37C2781F +:10EA2000701FD1218E17E65FF0F84F4FF34AE3E3F2 +:10EA30007ED779759F6792560361F1FF15C6907373 +:10EA4000A9DBF8B940779C2CD8CF6EBA4C3F88BF71 +:10EA500004E8BC5FDDF914C67FCF3F737C1AC8EFB2 +:10EA6000B23FEA8989F2B97DA79504D8BD0B03AC02 +:10EA7000B315BBF511CF5108A965DF39FECE8AF673 +:10EA8000A5E279A3BF98BE5FF1E247C3216ED5BE70 +:10EA900086D919DF335C3E7C6DC3E17CBD4266E7FD +:10EAA000C25A78D7717939F7527C29D849A9917D12 +:10EAB000BF5AD1344B3186ECD3479A151C97F6C315 +:10EAC0007BCBBE1D12C6CBC3F15BCDE0ED60F6AFD4 +:10EAD000A259F1C377B0158D5B707FEB69FCD40050 +:10EAE0007EDDA4DF3DCBBEAF6DD68BF1C3467DC0CE +:10EAF00088714EFD71E370A6B792108FAA42BDAC2B +:10EB00006EE271324DFC68D9EFF6BCE8A3A459F669 +:10EB1000FBDFD8C0DE9C6DDD6EC3F85C238BBFC904 +:10EB20001639727CAEA7B85CD37D3C2E37F534190C +:10EB30001E1E973B0BFFA17A38DFCCF5558D6B3647 +:10EB4000F68AE9FC7CD9B3179E84F3A473CF7FF2D5 +:10EB500024E05FF9CD674FDE0DE7127BCD7658FFDD +:10EB60003CCFBC8DF177F5BDBBB99CB7EFF8CDD3E9 +:10EB70004F503D6C7FCF88F7B6DAF79CCE84EF1903 +:10EB8000DB777D990AF1CD957B0A703FB3F2854919 +:10EB90006997BB7F02F2E98FE1FC44CB8F03BBF5A1 +:10EBA00004BEE73C7FCC88FE47779CB5A98AC5AFF9 +:10EBB0001D3CBEBA33F279951A0FACDE7DCBCDD7B2 +:10EBC000C33AB85B713AF0398F0FF614577D8BF268 +:10EBD00075440CFCDBC9E3E74D5323C655CFC37F17 +:10EBE000289F3699C5B8EA85DD8BFFED0968DBDD26 +:10EBF0002B6A5C351003DDD4F3B032B36B9B19F490 +:10EC0000E3F9DF621C1BF8467D72D2FEEC854C886E +:10EC1000479C513AEFC47BCA7B8C78CFA862CFBBAC +:10EC2000A82FED2F1CC57326C2CFA3DA49F70F3BDF +:10EC300037E07B1DCF362B8BC772FA43BCD661C33E +:10EC4000E73C2ECBE4588DD7468BD3BE6F66F7A139 +:10EC5000D4F3B9AA6D1F188826FE2D8D057E1D17C9 +:10EC6000CE15D5796BE1D9810ED7869E3F448B872F +:10EC700073BB1AC62F76EED0BE859F47749F3310A4 +:10EC8000D277249C8FB373738F5F7A37127FD5F35B +:10EC900087B7B5FAE98FEDDCA167BCBF1B5D5E35B8 +:10ECA000B3FDAD4A9F735F47B6D39D5CDFE93AD3AE +:10ECB00061C67363B6CECCE3EB4C35A51BFBEE8D82 +:10ECC000E17B8EEF03CF3DA3F7C37E795DD301B423 +:10ECD000B75A3DAF262CFEA51D4F8A63FE4175F342 +:10ECE000BEE1608FCEED7F09E5AF7AE771838FC219 +:10ECF00039D4F87B43DBD0A0BC831DF787D8F173F0 +:10ED0000CFED1BCECE4522E769B171F89E1611BE3C +:10ED100067E7A702FC65BE2683DDD2F3386765D7B7 +:10ED20002C98EFD95685C07DF6B34DFA227F8471B9 +:10ED30003F83756C4C904EEBACEC3B3E7D9201FDFD +:10ED4000CC95D6B1C7E0FBF195568303F6DBB5ABA6 +:10ED5000D9BDCADAFFE54C07BED426DE86E746F504 +:10ED60001A3ADA93EDB9B00FB7E7978C06B1D2DA59 +:10ED70008344974EC07BA5B528CD6181BC5ECC4F46 +:10ED800021B213BF33D4DB0A8B601E7ABBCE6E8EEA +:10ED9000B8BE32788A85E5CD50ECE2777FDF210F6F +:10EDA00006817C1CDF3A0F46A7260F46F98DFFAF80 +:10EDB000E5C1F0C1383F813C18018CEFA879309251 +:10EDC0007FE43C18105F1A1D9207A353930783F347 +:10EDD000F19F7930FE9907034A350FC63B1BCA0ADB +:10EDE000204F859A07E3CC064F01E4A550F3607CE1 +:10EDF000B56115ABF33C1896FB571784E6C1C8BC48 +:10EE00007F03B6AB79309CF73F52109A0723EFFE91 +:10EE1000CD05A1793066DEBFBD20340F46D9FDCFC8 +:10EE200015087930D6FEA100F260BC1EEF6E8D4B46 +:10EE3000899E07A339CE11531E0C0AE73D84132582 +:10EE40000F86164EB43C1814CE89B831D1F36084C5 +:10EE5000E113250F0685F309C2899207230C9F2829 +:10EE60007930289CCF715E51F26068E144CB8341D8 +:10EE7000E1FC17C2899207430B275A1E0C0AC710E0 +:10EE80009F123D0F46183E51F26050380908274A3C +:10EE90001E8C307CA2E4C1A070D2114E943C185A52 +:10EEA00038D1F26050385908274A1E0C2D9C6879D9 +:10EEB00030289CABE2C744CF8311864F943C181492 +:10EEC000CE28C4274A1E8C307CA2E4C1A070262024 +:10EED0009C287930B470A2E5C1A0700A705E51F22E +:10EEE0006068E144CB8341E14C437CA2E4C108C3A8 +:10EEF000274A1E0C0A6716E213250F46183E51F2E8 +:10EF00006050386EC4274A1E0C2D9C687930289CAE +:10EF1000A508274A1E0C2D9C687930289CE50827F7 +:10EF20004A1E8C307CA2E4C1A070EE463851F260DB +:10EF300084E1F35DF360980383A481980703F37180 +:10EF400076E7C148FED679307E05F8FE330FC63F1E +:10EF5000F360FC1879306EB5BAFF1E8FFBC6EF96D2 +:10EF600007E34CBC266F440F79306EB5969C05794B +:10EF7000FEB679302EC47FBB3C18749C7F5C6E9CBF +:10EF800068793074966F9707838E235BC65C663E04 +:10EF900051F2602458C4FC213F561E8C63F149385D +:10EFA0009F6879307E72F926E8360BF669D35114E2 +:10EFB000C94F26FFC4680B8F1BFE50F92760D2395A +:10EFC0003FA5FC136A1E832605D6C3F739DFDFE1B0 +:10EFD00072F101CF43712C6A1E0AFF548CEF2E157B +:10EFE000F3504CE17C9CED16E5610A61E72853F291 +:10EFF000B3FCB5B05F2FD7E4A118229ED317BB8F07 +:10F00000E6537064AA539CC7512E0FD34A3F3D0864 +:10F01000ECB9796CE43C1433383FA66BE83285F3E5 +:10F020006D3A2F6F874F73A83C17971F9581AED30A +:10F030001C6D32C6E96F52F9E710F83793C3D5E279 +:10F040003B83F36FC664C63F2DDE6F01FF28DE6F82 +:10F05000958F42FE69F1D6E2A9E53F09E57748FEC2 +:10F06000905C22E69F986412F34F14D8C5FC1337C6 +:10F07000A68BF927263BC4FC13370D11F34F4C75B3 +:10F080008AF9276E1E2BE69F98EE5AADC97F719FB5 +:10F0900026FFC5439AFC179B34F92FB668F25FEC44 +:10F0A000D0E4BFD8A5C97FF19226FFC53EA1BEB06E +:10F0B000EE35A1FFE2FAA3427D49C37B42FFA5FEE4 +:10F0C000E342FBB2C68F85F6AAA64F85BAA7F94BD5 +:10F0D000A17F4FF907DEE2DF43BFC3BF873EC6BF54 +:10F0E000877EBF87FC17EF5896AE0BCD7FF1BEC56C +:10F0F000B30EF2121CB738785E81C8F92DBADBA3C3 +:10F10000E4BF08BEFFEDF35FA424FFF0F9087456D6 +:10F11000F63D606F4B9ECE9AF2DDF311DC5A227EF3 +:10F12000D73DAB54FCAE5B6765DF6BCF768BDF778B +:10F13000DF5E2E7EDF3D22CE2D011EDAFC17BD2DB7 +:10F140002E9D15EC25CF531080EF74B321DE56842D +:10F15000E541C87F910DF1B6522C0F43FE0B5AFECC +:10F1600019F25FD0F208E4BFA0E51B90FF221BF26A +:10F1700067F878FE8C3A9E3FA39EE7CF68E0F933AC +:10F18000FC3C7F4623CF9FD1C4F36734F3FC1901C5 +:10F190008473C27B18CB93DE562C4F798F6179C66E +:10F1A000DB86E559EF192CCF793BB16CF75EC432A1 +:10F1B000D6FC19AA5C7E087EC315303E9367554E77 +:10F1C000AF7EE09175A1F933463CB009E5345ADED3 +:10F1D0008C1CF8A62F257ADE8CEEF628793382EF88 +:10F1E00047CF9B9136FAC7CB9B31D7F2C3E4CD987A +:10F1F0005B23E67598B7EAF2793346C495DC82F270 +:10F20000C7E571AE25B6BC193EABC4BFCBA7740130 +:10F21000BF8BD205D7EB1EF20E1CB43E3D04F61395 +:10F220005D43AEBA6CBE07AD5C44A737CBEF30E7A9 +:10F2300047CE97D1135DD5FEEF57B03C0E732DDF4F +:10F24000325F460FF9160E667F817632D67C193D05 +:10F25000AD0F3DD173C68F9C2FA327BBDA933D7DA5 +:10F26000730AA373EF1EE8AC7E2F5D696A3D842F9D +:10F27000DB5DA8DA32FF1E3E77A61DE3331D3BF9A6 +:10F28000BD381771D853D9F7FAE06F763C9F309CA0 +:10F29000E077FC76E2A2FC89E7CFA59DFBF6C1BD35 +:10F2A00080B536E24A4C02678F38F403611F768DD1 +:10F2B00009E23555BB3F7DE38F14AEB9458FF7E5C5 +:10F2C0003A280EADE8F7B912816FF1E497B84F878D +:10F2D00033BA4BBD42BFEBD6FC1E0EE8921A3C7F00 +:10F2E0002AD05B70DFD4B599DD67D593AB1E9F90B4 +:10F2F0008CF7C689DF81FC433F7519C7B38B106754 +:10F3000000FAEFB4E2FDD525AF2D34C0A070DE1AAF +:10F310001A37E85524C6811ACCB6E1706F2F5DBD4F +:10F32000BFE773B5821FBE88C34D2911E3449F2CEC +:10F33000283A0CFEF3227719DEAB482B15E34684FE +:10F340007F470FDB32F03365C2EF75FAD97DCFB05E +:10F35000EFEA9BB7209E4BFD9AFB4B8D625DA5DBD0 +:10F36000392BBF9762219698E8D636F8F109A3BFEA +:10F370003DDD8CE922DDCC0E916EF14344BA68E9A3 +:10F3800066758A74D1D22D61AC185F53E9A6DEA7E9 +:10F39000FCA1E89664E3F73C82F42A31A5A2C947B0 +:10F3A0003C33E400CAB7561FFA5802F01B7E48BF30 +:10F3B00064FF6A7CCB6995C16EA533D0445AC4DE24 +:10F3C0008B077D80FCBDC489FAA0FE3E8A78F221BD +:10F3D00097FB8FC8255AAE987EF0F802DABA19E486 +:10F3E0006D04FB3D1A18AF4A22B89F5388D30EFB19 +:10F3F000A826AFC9B94881734DE25C940DE79976B0 +:10F400002C1FE4DF3B770C25B8EF6F0A7C9E0AF7D0 +:10F41000061E1CD9390DE20F9EC5A404D6AF5909AA +:10F420006C7D5DC64B5B028BCF6C28D111D768F821 +:10F430007D4A7ABF44C76BB7BB5EBB01FCD1167671 +:10F440003F80D83BDFB81DDB47E1F7E119BAFA6B23 +:10F45000001FDA1FBF2BEE68F9C8B630C40EB737ED +:10F460003F7225DC6BDDA48BFC3D73818DFFFE1D9F +:10F470007E3F654430DF42816D0CE6657870001D8B +:10F48000A77A7A17F25195CBEB38FD0F964D41FCD8 +:10F490005E68911C10AF2BD4DF71D3308ADFB8B710 +:10F4A000657EAF97DD5F1FCDFBD79AA9FEA2FDAAAF +:10F4B000FF1BFC9E95974ECA980F71744D19DE1371 +:10F4C000FCA3ADF030F02BC7D5340AE429BF2511D9 +:10F4D000CF713D1F12277E9AD52ADE07CCE1F7B601 +:10F4E00073DA881F84E2DA6362FBB836B17E9D6608 +:10F4F000FF39DFC6F5D4465241EE367EAD9760FD4A +:10F50000E8E824CE3514DF8E45BD71FC8ECF09FAB4 +:10F51000891D5FEB8B22DD8F596E63FCDB642068F5 +:10F52000BF379559F0DEF9FEB28AFEE05F7C719735 +:10F53000BB7FA43865889F96C0BEBB772590B1205D +:10F54000876B2546EFFA8C9208EB962A77AA1CAABD +:10F55000F2975116E78E740FF5339B8472965736E7 +:10F56000443280FCEC9530FCD5BE86E2759975DBA3 +:10F5700047D6F4017C3CCD9FE17D32538BE48A7405 +:10F580004FE7619B8DDD6F5CE35B0DF7467E419538 +:10F5900008EC5486A13E2B127C1FD9887EE95D368B +:10F5A000077BCFC4F320C9F519709FA2BD79D2E4BF +:10F5B0007514CF27A83EC07AB5497122DEBE2A4213 +:10F5C000F09E2C8FD7F59D46B66C08F17F37DB7225 +:10F5D0001B6D145EA38D7D6FD9CBED94006FE77F1B +:10F5E000FDC306F03B2E1A917FBDB9BFA9BE77803F +:10F5F000D3675C826B2BBC4FE0979F51E3E374DBD6 +:10F600009C8B46415C9ED23BC40E06F9E663F951E1 +:10F61000DC04CF3F922C3A9443E27239ECC27D76FF +:10F620001FEA8DAA07242011C853A0DA37A9450A7A +:10F6300058A9DC8F365902708F2EA99CCE3B19F247 +:10F640009A9818BC56F99C18D7A2F29803CE3DC1DF +:10F65000ABF3104805F8AADD53EDE5DA44668FD622 +:10F660003E24635ED4CD729B19E2A9592E471EA495 +:10F67000884C921D78AFA65F3971520C49FCC05F6F +:10F680002776FB0154C9AFF9463F2FD2775B176D40 +:10F69000CCDF1E97E0FE33D06BF8E1CEFDE02E38D4 +:10F6A000CDA417BBFFC5ED04F76B0AF97A37EE3F1F +:10F6B00074EC7BD1C00D24F43B2AAD9DD86466EB7D +:10F6C000FCB8EBD9BA37EEBC05D7BD6E3B515688B6 +:10F6D000EBD4C8965107E09EC5C80F997E126E1FE5 +:10F6E000ECF40FD029E7B04F0FF4F9B67641CB6FA9 +:10F6F000123075D787EAE01C86EA5BC8FB6735766F +:10F7000064C5F441B5185EE672D4FF1EA7DE1D4243 +:10F7100047EDFBDD714AC9D4FDDC3110ECC8113D69 +:10F72000DC0BE9C8A5F3A3F3DFC8F525F173FF648B +:10F7300098D7C6961BCD20DF6B0379F662FA4EA2EE +:10F74000A9049997485C18CF19493D32C88F518B4D +:10F750004241FD41A58424A4C03DB42221DE432CB6 +:10F76000493CFF4B00F9D22DA7548E43EFE5AAF296 +:10F77000A99547557E6BE1A005CE0721624E4BBD92 +:10F78000D484878146B2D90EEBBBEA5FD6727FAED6 +:10F79000D69CE9C7EF977C19E81FADE4FE51ADA5F3 +:10F7A000D084E6605F32AEEB2B217E42E9B0328539 +:10F7B000D979753E5AB9F45CD4137FC83EC123771A +:10F7C000E27D44CF45033E5FA7B807C0FC55FA5C15 +:10F7D000C3E9A3A58794C0F79D9C2E3DE39B638757 +:10F7E0007BC1892617598FF8E6E13DEEA6C0481384 +:10F7F000ACBFF76AF08D01CF6B13C684E3295BA21F +:10F80000E099CCF0BC8EB8FFD846E53767455D6D12 +:10F810003CEA15792B3D275CAFB47AA4EA8D1AE750 +:10F82000BDB6B2FE005EBBED416F3CF18C2E4EA525 +:10F8300004EF5739F7C4A31DD1EAD3E77CFE9E78C5 +:10F8400046BF058A7B06CCCFA3EBCC043919EE204A +:10F85000BD8A2992C39BF5A8E7A435B67BF8AA7F99 +:10F86000A5FA55DA7EAA5FA5DA63F51EFCDA04F77D +:10F870007C9003A999CA2DC5A7D6CEF64B9B6DEEF9 +:10F880004580573CC53D0EF68D430259ECFB5F5158 +:10F890002FA2E941BC46CE9B0232AE0B3EBA2E648B +:10F8A0004BE178A8E30F4A48647CA45A0EEB7DDF55 +:10F8B0001CC206AB269837A7EF70E28675ABEF48FF +:10F8C000769F714D02B3BFB5096CDD52CBCDB692B8 +:10F8D000BB51BF65E2338EFCEE7803AA70DF7C6D0E +:10F8E00082EB2EA087A9C885F3E863274EF04BFB77 +:10F8F000C84D127C379A54E990D83D7312FC7E8B28 +:10F90000C2EB53ECC8057DED03FB6BE8DF1239CF8A +:10F91000D8A309EAFD5EE67F3A49771EAF47139800 +:10F92000FF7908529FF42A56F382A9E7394E09E875 +:10F93000D46EBD0D916EBF20313F3D91D14BBB4F79 +:10F9400000C287FEFEBD7B0D44362791E0EF59D5FE +:10F9500099D0BF8F27CE26B057BB1206F0734C67E5 +:10F960001DD47F25779A128706E55D95E30727CC9E +:10F9700070422A52DBF55DC3614F45E57A27D0BF5F +:10F980007D42D760CC41493A3399FCB8F442BE205D +:10F99000950FCD8AC00733ECC343EDA4D53004FCEA +:10F9A000D17629CE09F72CDA974A0C5FC9C4F3291E +:10F9B000C9C23CD3E3997FDDC1EDD53B0959282766 +:10F9C000AA3DA6F3AB83523B0F8F11EF7490CE3D4F +:10F9D000F1FEAD706EA5C93FA9CD4F3969A105EF04 +:10F9E0007F6CDC63C6FD6B57093BC7EF6A31A27DB4 +:10F9F0008EA6B7696DE688711CB5A4F47B0BE897F9 +:10FA0000A6D424823D4C9B7BD2067CD7D2A543F260 +:10FA10005D7308F645AF2B11BFBB55CBF4F49B12B9 +:10FA200017D1FEE91993B1549F3758E488F7CD4FA9 +:10FA300073BD52E5F14A3A22DF0F9D06793CEF7E15 +:10FA4000F31D1709DEDF6F8863746C886374EC72D2 +:10FA50008F4F781AE4CD9781FAB0583D07E5FB7FC8 +:10FA600035CF943ADE46AF2951A62AD0B0608A1924 +:10FA7000D68914E29A3C1B9475A342E03BA2C7BC12 +:10FA80003B12F3318E6D12EFF9DAD9BDE1CF3716A3 +:10FA9000E077DEA9648D7930A5475989CE09F183D5 +:10FAA000F30BDEB7E9A83C2DE8D39A03F2FBBAE2E8 +:10FAB00026F63118EAC2FDC99252833F40F996DC1E +:10FAC000400D05A5CB7F03F4A15473008000000016 +:10FAD0001F8B080000000000000BB57D0B7854D58B +:10FAE000B5F03E73CE3C92992433794E1EC009E1A5 +:10FAF0009D108724BC1F4E9E448830BC0485EA803C +:10FB000028CF2488D6DFB6DECBC444F4A2B745E9BB +:10FB1000AFF4D6DB7FB0A2A8200182069AA41340DE +:10FB2000E4113408A8A8AD5129620BC908EAC5D66A +:10FB30007BFDD75A7B9FCCCC4922D8DE4E3EBFED11 +:10FB40003E8FBDD75EEFB5F6DA872EC977134B64CB +:10FB5000CCB7D8C0B64A8C7D87BF1B43ADD96E6089 +:10FB60002C89B196383BB54EE70CC7D284F07E8520 +:10FB700063693E63D5D6D85C16876D7F3F8B85F170 +:10FB80008A58EAD202685BACAE5A95B12546AFDD21 +:10FB90000ECF774EBA3CA48EE12FD8DF3392B12E30 +:10FBA000236B94E2B01F606C0C4350F8CFED56ED20 +:10FBB000D097F0FFE1FD448B2D20C3B8CCA35CECC3 +:10FBC000B0F047BE1B281E4D66CC285E939ADEF827 +:10FBD00046CA652C7672116370DFCA5C8FB22CB88E +:10FBE000318CA99E18C6A2D833F6F3D98C19F07DB2 +:10FBF000584757F3BBFD7C00C71FFEE54A0C83FB4B +:10FC00001F29C118570E63171E3C15E3B6C1F5072F +:10FC1000E5723FF46F4740C687F0926F870BA319D8 +:10FC20007BC4EE1981EBBA63DD7F8FF1DA42F7D93D +:10FC300003703195B1157E19E7E6F0C27FABB65976 +:10FC400019B384FA95F509117DC018E1B5D2CCD667 +:10FC5000D4DB7AD26305D203E65DB17D8B295DC525 +:10FC6000F9BD93ECD0BFA0C0AB80EF0B0D317E5F30 +:10FC700066089E25DB4799D2E1D6474D661680750A +:10FC800030A5DDC86C84B50A09F0E61578D3C379D0 +:10FC9000B8C54AE3DDF57F65BF1996BA18E67A2044 +:10FCA0001E9E6F5A51C1727BAEE3AE3FA8652940DC +:10FCB000BCBBFE4D623E953FFF601E3CFFC0235F14 +:10FCC00020DDF4EB5CEC337ED211B16E376300CFF4 +:10FCD0003241EF3B1F8DBCBFACE9311A6729F39A63 +:10FCE000909E776DD4DFBFE933E4BB654C095D07B7 +:10FCF0003C5C3E9265453CDC618F493C0F20038FA4 +:10FD00008DFD0EDEDF7D64609C37A7277EB5F6E2B1 +:10FD10003AE06F33637F5E67A1F6C23A46ED08BBF7 +:10FD20004AF459DD74F27EE4AFAAC65D261CA7C56D +:10FD3000FFA78409F04861D3373232572173DF7B44 +:10FD40000EF0F92326B3EF007FBB19E79FF546CFEE +:10FD50003D48AF1BAF96D37DFDFA1769FC7F249E0B +:10FD6000F86711AE3B17AF2B5FF6B6AE9FE2BA80D5 +:10FD70009FD95858977CFDEBD2D6A3AD4FBB5F29D6 +:10FD800003DFF5F2BEC6EF23843E58FADCACF5691A +:10FD9000808ADAE6CFFA77103FB1D328BF1A3F2D19 +:10FDA0001374D2F38D46C76EFE68FA775A9F463FAA +:10FDB000E07FA7C1896DC06918D7934FF47CA1E794 +:10FDC000834E63477F945F3D1F744A6C416FEBFA2B +:10FDD00037FB405AD752D55D6687FB7731CF7A3BE8 +:10FDE000AD67235DBFA06C3CFC3394ABE7385F7715 +:10FDF000EB3933973776DCE847BDB936464D71D8D5 +:10FE000004FD80CE9DBBCC3E7C4E9BE7FC3AB77B8D +:10FE10009011F15E4EED9FD779DC830687EEDFFD12 +:10FE2000AB2BB12ABCDF358C95A3DC77C644C2BBB3 +:10FE3000CF2E133CFB900EC87F4AFBFF7C803AE933 +:10FE4000B9F631A847CF7FFB5FB11E78BEEB5B737D +:10FE5000796FEB3C2DE807EAE5B413F8EC762167FF +:10FE6000B73755125D963C33CB84FCCC1EE0F8B41A +:10FE7000C01FEAD7B6A8D867711D8B1B24D2237A7E +:10FE80007ADCE59AFA39EADB3BFD85F47E0FFAB0BD +:10FE9000C789BE77213D8685E831D6A1727854F8AE +:10FEA00003BEB943F0CD79658DC9007AE4FC338097 +:10FEB0006F007995C2DCBDE9C1FE0ECE877DAD47EE +:10FEC000BF8EBEE05FF65CCDFA3486EB1F654AEB71 +:10FED00045EF68EBBF8BB96249EF88F5B28E1B49DD +:10FEE0005EAB2D7C5E6D9D2B9AEE9C817C51B5198D +:10FEF000E895D973DDA87717F7026F997CD16881EF +:10FF0000F7BA1E905CA86FFBA283A627EE12F85AE0 +:10FF1000B96DF10C349A8B613E3913F5D1176FC668 +:10FF200024A25C415FFA1E7A35C91F9B711D8CE3C8 +:10FF30007B09E07B8374FDF45BB6B9D03D28ECB956 +:10FF400015FE9BDC83C2F5998EAE6CDBACD0F364FE +:10FF5000B7DD26B4C7F10EA1BF845EEE5BBE60E1E3 +:10FF600000E7DA1D0EB26F6C8D83F46375D3165300 +:10FF7000B8DDD5E44B93B7B10E3BF15955E313F41B +:10FF80001CE85FD501FD4A4BC7CF6F55C3F0394E12 +:10FF9000D051AE30A1FEEE4B7F82BEF9B2236C9DF4 +:10FFA000231CC2AE08FD7B2DFDA0C1AD1F57D3079A +:10FFB0001ADC1ADF6BEBD1F37D5FF0E9E9C2989FA1 +:10FFC000FB0B3AFAAC427A84F5115E05F0DBD66C95 +:10FFD000F53F04F0B6491C7E5F7314C1DFE92C764F +:10FFE0009F033FAF2A7521B527F0C554F4EB3CD3EE +:10FFF000109F9A3FC70A1222FC247DABF93779C2C1 +:020000022000DC +:100000009FDA1BE5CE0713093F4F02F2C3949A8E85 +:10001000391620D9AD8EEDE50A8C3FE5898E395130 +:10002000D05FE8D8C1FB5B3B4E595C8CD5B057CA5A +:100030004BA07F3BA013C7BB565B60F62C44F95D19 +:100040000D7E9205ECD1EAD3430EA1DCAD6EAF2854 +:1000500097C0EEAC068323813DAA74C706ACB9D421 +:100060006713E0B9E7EDDE65C42F57EBC86EAD3E10 +:10007000AD70B9399248EB5700F62878AF2E1AFCCC +:1000800055C0575DBCC5559B49D77D51F1D877AB5D +:100090006AD8758D1EF81EC25167606E07B4AD47F1 +:1000A00087C4757C8FDD6E5DC72A14E08383EB2CDB +:1000B000D4EAEF179AEC83D0EE151A98B7377DF98A +:1000C000A483FB8DC0E4E948E7AA23269277FCA12C +:1000D0001F5829F4511510280EE0A93CCD02D1B1CA +:1000E000F85CD9E70AB60D12FB24C25F61A1BEDC41 +:1000F00037DCD7DB56E17883C3F984E3A948912A3A +:1001000094B0794B6C51117D39C5300CD7C3E4687C +:10011000D756C0AF9C6E58B31BD62F0F8016F0A1D8 +:10012000D85DF2626837164F9197405B6BE476B505 +:10013000D6C09687E3E905811FADFDC0E1D98A7479 +:10014000BFF456FB182BE9AB0C3BC9B9586FADE4B3 +:100150000A50DCD4CA5C5BE15A9DEC619C8FEB19C0 +:10016000F2F11B621C97D9B047057E6D747C40FC90 +:10017000EB8A33DC9B09FDC0131FF17EBAE14A26EE +:10018000F0F781273ACA15900757B6E1CA40E81F31 +:100190007AE2637E7F220C0906EAF0139F94FB6CDF +:1001A000382ED7676CBB3B1BE7510C12C9A972C034 +:1001B000E4AF85FFAD8BE5FC54073C82FCF786B0CD +:1001C000B3EB6B8A5EB602FF2B456E750D8CE3C7F1 +:1001D0008069F4DFDF6A7894AD068A53B0457CBF4E +:1001E00029D6ADD18135B8B367A15EA87767CF8E28 +:1001F00041BC7A4F225EF3DBDAA7A03E6E78FBFDAE +:1002000031E8AF22BD709CFC3688DD603D975EEB27 +:10021000B7450E8B473F7014BEE3003996DCDC9F78 +:1002200094543B5B047257EB66AA09D695A28BEBFC +:100230001A18D72FCFDB3D7FC4F7584680EC4DA16D +:10024000C3FB31CEAF8F57597B7CAF7A59AFB74CD8 +:10025000B90FC8E8E7C4A737BEB704F5FBEFCDAECA +:10026000C12AC2E5660F003C3B0D4C61F1C426C3B8 +:1002700094028C3FA35D1B50EE5DCCE90339C33083 +:100280008D80845FE298B0B855AC07DE2F61D08EC8 +:1002900045F86EA0F5C9C857A3984746FD3586F9BD +:1002A000ADD87635BFE644BC3D19C5EE40BFCFB2F0 +:1002B0008DB9FD61FA63403CF7F726251809EE6811 +:1002C00063FD6CE4D7E82F981DFDAAAEFF342938F2 +:1002D0003E08C874BCEE3A6C6008E70B46BF3D0EA2 +:1002E000FAC1E18AFA2C0B8DD725E8AD8DFBA44924 +:1002F0001DEE407D93C0FB2F1472FB1CFCDCE47FE1 +:100300003613F16359E30F932F673CF75BBD494503 +:10031000F1F1D0D63747339C7F6C4BB401E9F0F252 +:10032000F6BC28E4879D881B587FBCD97E0F8E17AA +:100330007F05E0CDA4EB6EC2ABA28E8A03BC4E98C3 +:1003400066533700DE5F88AA9F86FC1FDC6160CFA2 +:10035000C2143B4DAE59D8DF7959B5A3BE7D21B348 +:100360003E9AD6B3C340EBD9191D1CB116E0DE305E +:100370004C2947F8142B53500F2B8622F51EB83EFC +:10038000349EDB574D2F2F88E7F2F3A404F3E7E107 +:100390007385243FA5B28DE4AE2BC8FC669827690F +:1003A0006EBB8CF4889E05AC847CAF046406FD496A +:1003B0001E46498D4936A35F257DEBB62D06BA4F03 +:1003C00011FA76CA87AB2B78DCE33A3D11C63B685D +:1003D00033325CD764D621A33F38F92A7305907F66 +:1003E000AEF278C60E7FE83F3DAFF3074BC578EE1F +:1003F000A0BD042F17B2483FAE7473D9E712CDA346 +:100400002A68A78B2DBAFBE8E7C5621B193795C58B +:100410000BFFA63FEBFF1DE937E05E98EF3E3B9FE9 +:10042000AF54CEF915AEAFABDCE4423CECB2B9DF71 +:100430009D887AB1DDC8B6B2BEE5E979883FFDE0B6 +:10044000730CBB6A65FE7CE2471BAE67C4E68DBEDB +:100450002858F788417C7CE43BD42343FF333101A7 +:10046000F5F855A15FB456E333E4277B1CE727FB7F +:100470000D2139BC333E939ED3E40AF90CC7D96FE2 +:10048000F42FF4F46227813FEF44FEDC65631447E8 +:100490003D966A598072A5CDF3BCE0637DBBBE6614 +:1004A0006DAB11D7FD15D80380BB24EDAA29DC9EC6 +:1004B000EF49E27C552A7F4BFE766793C4D0CF4F3D +:1004C0006EE2FA3B9C3F527BE78F5F225EAFC51F17 +:1004D0005ABCB0FB87F2C791BF8F3F365C933FBEDB +:1004E0008D453CDCD75C9CC2BEC7BF6914FCD0D72D +:1004F000FDF156AEE7F4D75F1178DD67DA383D17C6 +:10050000F5C0CD0617CA39503F7D36AC635F347FE6 +:100510008F296BB2B0BF4BE17A65579399F4CA2E1D +:100520009BD74B76DC6961E83F30C5DBF133D4877C +:100530006916754318FF2E8DE7FC566F0C8CFF0C67 +:10054000FDE2A39CCEE36ECE934DF05CEA522EE723 +:1005500005174C5B300E2B4D28DC817C7402751620 +:10056000B4D5E7E029407CD53913E9BBD75A4E967C +:10057000617E11FC1E37F2D9D8FD27CB8A72F07943 +:10058000AE4FF78A56EB8FC735C5B3EE78D723EC5D +:10059000C678C6F59207F92437D4676E23C56B1A5F +:1005A0003FD447033F805CCC67AA3116869C73CE4C +:1005B000F330984336A73C92CEF303D3283E9C7B7E +:1005C000BAFD55D0CC6C9E47775FF0C17C1D1F8073 +:1005D0009D3D1E8FFED2F180C980F399D664737F52 +:1005E000684D16F293264FF4033CD5FF61D8B31B38 +:1005F000C2EC7B6C0297A3C75D0ADDF77598FC839C +:10060000E1D2BF33FE5EBDB03F9FA33C63FC70DF11 +:100610002B0BD18EE62F771F44FC4F4F92E9FA2F18 +:1006200058C09285F47129E497D51BD5E2CFA4D0A8 +:10063000734CF10CB3C1FDFD49D1F9387F6982F7E4 +:1006400022D28929C123F8DED80979F9285FB65169 +:100650007509688F34B801AEF2ADB6101C1A5C672C +:10066000055F94262CBE88EBC7F750BF347E7CDE36 +:1006700082EF6B74AF6FFE82D33B8CFE48EF10FDB0 +:10068000A53BB0AFE1E12BA157B4FE3F4A7F2D7FE0 +:10069000704DFA637E20F6EFA2BF352129447FF02A +:1006A000B3E2B1AFF7B3EA4DE077E7F4BC5EE82818 +:1006B000A4E75D265821FA552D1077A23C7A1DB487 +:1006C0002FB0C7CEE7EAFAC3F9FEE022B2C109F1C2 +:1006D00084F76A537008FA21A30212F985A340F047 +:1006E0001791FF95417ACF25F0C4CE4BD2F961DC4A +:1006F00045FF2E1DFDC34002FA51A3CC1501E4F7BE +:10070000DDD629E9E8D7E5592765215FBD3AECBE7A +:10071000E368825E4D5BBEE73935E4FF68FAEDA021 +:1007200018569BBF2081EBA11B41DDA21F882E63C1 +:10073000381C9A3E47F2201C5260BEE13B2BE9E593 +:10074000A60EA0C78D0807E0A155620DA8CF0B0D1E +:10075000EEC462F4D392020AF7F7BEE98FF9C18AB8 +:10076000A637DE43782B703F04E35097F162773E63 +:1007700062604F3F58F357B4B840F367B4F813FDC5 +:100780001EBC3F405CB79B0140B447018BBF06E6EF +:100790007FF2B23ADC2DE4568175548875CC64ED55 +:1007A0000417FBF6BBEF26017D66087C541C81B85C +:1007B0003117EF337633E0E16685C79337BB207E90 +:1007C0000CE3A399E322FBF89B921C1AE75ACFEBA8 +:1007D000EDC044DDFECC3FDA1E017BF409B8CEC784 +:1007E000D6F1B874C240D9A7A0E11C9769407EAC8D +:1007F00016F60DC2E85EEDD24BC22F9E60E8C875BA +:10080000017E5BF7FF8DECE081FD7F7B07FDBCF196 +:100810009F2BCC0CEF4FF8BC200EF5041BA7125FEA +:1008200069E356FFA9C1CAF875E2FF2AB1F6C30011 +:100830008F7B28C267A1F677179FDC84E37D794E12 +:10084000E1BC2DE62F337907611EBBCCC4F30187D1 +:1008500025EEFF68F70F1B016EB8BE2941CB0BB424 +:1008600093DDC79F398CCE37633E202F44D79B2F13 +:10087000947FAEE4F6A40FFEFE37F2015A1E60AB81 +:10088000C01F3B78D6A4025C531BEE51D0BF9EEA3A +:1008900094993B6CDE9B542B7387E5039E49D0F9FA +:1008A00023075FDC3403EC49759BEC8A42796DDAEF +:1008B000753C17FBEDB2CBDA0B1FE9F13BB5E91E36 +:1008C00005F9DF98A8927C5F6BFE0923804F6E408C +:1008D000BA33F2EB3AC74824477AFA1ED8FFEB84C2 +:1008E0008E9CBEF1DD17FDF574F8DDC522DAEFB997 +:1008F000163DF47CDB02EBF4C1FA02B04E1FF85D4A +:1009000007D6D9A97F689D93FA1ABF5637FF3601DB +:10091000FD368D4F4B1338DF8CDFB72981D942F478 +:10092000D2F0F5A1B0577BA3347FC3356F065C3A94 +:1009300005768718D4C7DA9D6342F66BFEE932F27A +:100940003734FB355F5E544A6A53D82F4C23A35E7D +:10095000D3DBA9B9EA6223EBCD3E2D88EC97B76DC6 +:100960005462A867203A4992C087F0B33538CE3038 +:100970000FC1A9A7A706971E1E6D7D9A7F3D5FD068 +:100980006FCEA04C23C2DFC3AE8A75E2409887B811 +:100990005EBBFAB58E9FAF5C28792BB717BEED8B87 +:1009A0007FF5F7357D508613E451EB43BFC298982D +:1009B0004C742BBB6A626EB01B2C238A7D1A66575F +:1009C00058C550E29F7B851DEE8B7FAAAECACC9B9B +:1009D0001FE22363E31356E4A37DCA462BE62727D1 +:1009E000DB66D5C6019E4AFE543417FDBCEA0E03F1 +:1009F000C3145669D3170731AEAF7E8FB9502F1687 +:100A000035B51623DF1D52DA658AB3BF64EC893031 +:100A10007FB1B1A9D68AFE5463A24C71FC6107E78D +:100A20004BEDFE9644AE3F1ACF5D9EE1EEE5FE191A +:100A300071BFE4E33CE2A3B24741AE310E4D8AA15F +:100A4000BC4489649F53817EC84D46F2F3218EF9E0 +:100A500023EE035E6A34EFC2D47E69E323F7D881C4 +:100A600010F5FFFD698D19F30BB324D7B3F05C9932 +:100A70001A6CC57ED9DC4CAA7B18FB3F32F9B3C196 +:100A80005B25CA8B9401BB60BF6C51A61FF313FB9F +:100A900025DEF735F37D0266F725CC8079DEAE489A +:100AA00018B581784AEB0FCEDBC0042387C557F712 +:100AB000ED9549CFDC572AF971BFA9D49ECE7C6150 +:100AC0007C55F6A889D635BB29A508F9784EB9CC4E +:100AD000FC61FC1D107EE13C0FC4E161EF1D8EE264 +:100AE00070051703DC52486EA7093E9FC5B89F38B2 +:100AF0007F4142C47BF0C62D688F6E6D8238157AB7 +:100B0000D344FC7AAB373D625E0FE37ECD09162CF1 +:100B10008983F1FB250D24FE9B11B48F0EA8A877C5 +:100B2000CE24A25E63C3B89C6872572AAFAE237E00 +:100B300070F27DB2791248938CFA2F529E668E8B9A +:100B4000ECCF72F7A83788907FBD5ED7E47E5EB3A6 +:100B50004CFB72F30A2517EB453FE8FDECB1D17D64 +:100B6000E8856FD587E37AD30B1F96FF5D7AE13571 +:100B7000082BC681FCFE3451E8877EAC1FEA875201 +:100B800079FB26E4972EB077E65EF845B3175A3C1A +:100B90005E06F24AF27E91EF67945E4D65BEFC50B0 +:100BA0003CDEAD2FC09F70F5E2E73C9D984572D4C6 +:100BB000AD5F34FD11E64F18C7FCE3FE4429F89100 +:100BC000A63C842F83E02B633C1F5886854398976F +:100BD000737E41F9966A88F329DE67BF25B850CF46 +:100BE00049F12139D0FB195A5ED72AF2087ABEE8BA +:100BF000CEF3CD35521D8CC61765762E1F657365F5 +:100C0000CABBEBF9449B4FCF1F015D5EE69AFC2106 +:100C1000E4EC87F24773A2D8571DC4065D0F5F68E6 +:100C2000FCA0F187DE8E1CD3E567FAB2236FA21D0C +:100C300019DDB71D797D9891F4B5DE7E68F6E2770F +:100C4000495C2F6724F27D8E69C3E7D9D0EFB026C7 +:100C5000F13A0DCD0E75E79736737E78BD63892224 +:100C6000A13D41BD9019867F916FD5F8AFEA5189BA +:100C7000F28D15422F7536F3FC5B7589ECB7C0FF1A +:100C800016373DB189F78D949F2B545A150B8C3B29 +:100C9000D325B930AFE316F9BA196E89E7EB5C9149 +:100CA000FBF42D3AFACE117C349305EBD01FD7EB31 +:100CB000A53957B95FA0D74F73C4BEFB1CDDBEFB7F +:100CC000554DDE07B001FF4C7FC09CF4FDFE80F661 +:100CD000BE46478D7E2AEEC5A11C1DFCC6A4C6706B +:100CE000FF19E937F5AA42E3D893045F0A7FE6CB00 +:100CF0008B79BFA0984F3C5FDDF485C93BB26FF89C +:100D0000AFE5B7C6A29F3E3AE4B76BF34E53184B1C +:100D100047C74C674F6689EB3FD47E0CD7AD43A3E2 +:100D200083A6477BE059E8D9BEE8742D3DABE9B313 +:100D30007FB69ED5C6D7EC8036AF5EFFF615B76995 +:100D4000FA74FD1603E54B268BF878B2C8C3CE4F74 +:100D5000E2F1C1AD493CEEECFACA62407BB9B38521 +:100D6000FB272EB3FD38FA05A17C1FA7E7C331CCC2 +:100D700087FBEC4C69B7D0BE67119012F73DD3F8F2 +:100D8000BEE77625E0213DED52580DC8C9397C0FEC +:100D9000E679F8806F21EAE9873F1962A0FD77259F +:100DA000D08EFEC9D83C85F68F1C6695F2C19DCDCC +:100DB000663BBED7B5EFFFB41A719CAF980B43B832 +:100DC00043CDE6EEFD1BD407A5729B8CF9FBAE204C +:100DD000C8083C3F6941A018E3A0C9ACBD16E57B3B +:100DE00002D2B117FAFD2A498BB37BCFEF173773C5 +:100DF0003FAE3846263F6E8AAFBD18F7ADA62892A3 +:100E0000AB169FD5E5F75FD1C51FA1FCBEAAF0FACE +:100E1000435DFEBE91EB99EBCDEB4F40DD067CBC14 +:100E20005EE373A16F581FF9FD9D26BEEF133C6969 +:100E300064E807B30B89BDE663AE95E7DFD712ED33 +:100E40005663719F8EFBEBFB5AD2DC6A6EDFCFE7F5 +:100E500076048BD03CEEDC3E5BA1FA35911FEDB100 +:100E60007FD2C7FE88BBD17E08D5695FFB21C55FF5 +:100E7000AA94F6B95EBC69750B4CD43FDDC8B49F2B +:100E80009BE474E7F96837F2F9CEF3696E84EB7985 +:100E9000C1A71ADFEF3B77399AF6414D6E15F78FF0 +:100EA000830E8BEB59E25BCEEFF5A943FCB84FFB09 +:100EB0001B21173BA383C7B213C3F73DF83E47CBB3 +:100EC000BA47679F33D27EB984F9486D7FD90772DC +:100ED00043753DF18CE20F23AB67386FAD9BFD1A74 +:100EE000DB2993D438C4FBE5446D1F538DA33CC468 +:100EF000B757A8CE508FFFDDEB9807EB511AD659A4 +:100F00003C0AC8FFABEBECD46F5CE7A476FF3A95E4 +:100F1000DA878EC73E8076BFDA6DF22861FAE39DEC +:100F200064EE77E5657F524CC5DF7F6354873EE50D +:100F3000C10E19F5C58D57611D117527CA65C437D6 +:100F4000E537B342FD4C69710CF66FBC0AFDB0E7A2 +:100F5000AF2439B83DAA53EA462793B4105FFC2D5D +:100F6000C9DD9104D7EF71783EC176B734FFE02533 +:100F700046FD73BC7FAB7C099ECB0F14525E391FBC +:100F8000F3CA7934EC42C4DFE85613ED976BF9DD10 +:100F90003C4DFEBE8ECC33E78BBCEEABAC83F2CDCA +:100FA000051608B40C0817A79F5B9AE794301F98A2 +:100FB000647261BDC3E82C4F3EE6635B9318C5477E +:100FC000ADADC9196A0E720FCFFBBAB5BC2FFBFECF +:100FD000BCEF918F627DA4B7AE9A687FFAC8A9581A +:100FE0005780F60B2DE4FF69F5C82DD1BCCE806586 +:100FF0002CA03CD38DA29ED162F69A93495F050E38 +:101000009E80F77E7F99F17DC7F60F695FBBD83070 +:101010003C05EB7E0F4A43E3B07DEAA3D81C6A4F40 +:10102000C55E44FCB418AC2ACE7B669D5A82756DB1 +:1010300027D6B112AC637B6B9D85DA93EBECD49E23 +:101040005AE7A4F675B88EFC731C9E477E71BF6587 +:10105000A37D92296FD9146CF316C650BBFBB6184A +:1010600013C2DB12CBB66BF360BD5A203AD080C9F5 +:10107000FED6A7BC8F59FA81DD337B474AA3186B94 +:101080007BCA3B5D990CE34EEDFF93AFE0FE9BC93D +:10109000CB1EB3005C734FD91ADAA0FF76F2F2C709 +:1010A0006CA86F8F4783D2C3F5AE38EE1E0474432D +:1010B000A590C605978D837E82D65F31BD6412638D +:1010C000B71477643360ADECE495D32D80C75BAC87 +:1010D000DE1F63DFE44B9A5ED20FFBCC87F56041E5 +:1010E000C948713FCB9012B1FE65A6C3FB4672584A +:1010F000FD9E5BFA13ED338D714BCC41871F8CB491 +:10110000EFC5EC1F2784CBDB4C47E91B488F89C90F +:10111000BC0E78F424C91D5E5FA17F6EF439B5045E +:10112000E934E642591DB633CB1DD4F72C185B8742 +:10113000F25C62EBEBFD627ABF3C99D78D142952C9 +:10114000445D89FEB97C6026F48F8347A3294F3024 +:10115000FAB4B716EB4F4B9D9979B2A6FAA8EFD81F +:1011600082FB6DA32BCE9424A0FCD824179A89313E +:10117000ACA32E01EE17DAB1A00AD7F54431D6FFA1 +:101180008C562517A2ADD0DDDA80EF17BA625C85E8 +:10119000E88F9F564BD0F49C52469D2880E7A60EC0 +:1011A000925D1618E854E0A68997A05F382C8EF25D +:1011B000BC85CA9A2B27A81FE3AA51711D5B7E5DCF +:1011C00045E398C9AEEF9E51FC2FC83F459E38CAF3 +:1011D00009023E4AC2EBCA60DD0477A15DF64749C9 +:1011E000C8DFFF5A6287FEEEFE1296CBC37CC3FFB8 +:1011F00042F78F44AB5100E86E93BD04C7DB6D929C +:10120000EC0F51DF538CCFFB861855CC1F9525462C +:10121000458C3FB5441A7F0EE1CF891B85D7CA3371 +:101220001C11F7DB6EB3929DA8782B87FCA2B6DB6E +:10123000D2C95E54BC35A908DB3603F7D32BDEAA2E +:1012400028A7FB061E07572CFC915BF429EEAD582E +:101250005849FD5629E52738DF959CB83CCCAF4D61 +:101260001B945AA244F8810349FEF3447EAFD03068 +:101270007CD32480FFDEA37C9FA2222733E2F919CE +:1012800005524978FDA8675254447F7689A324BC4F +:101290000E756E456A44FF96B99911FD92A30564D7 +:1012A000BF410F5494801E380AED5260C1025107AD +:1012B000A5E59F0A054B15B68BBCACC2E3EB61F00C +:1012C000877AB0C41669A77747733B5FCED6D0063E +:1012D00049F911BEBF5D9668FC24DC4E94CB1536EF +:1012E0005E97158987BCA346B2977931921FE3FABE +:1012F00092A34BEBD0F4966744BEAFF961E5023E92 +:101300006D5EE673B7A33FA2C1ADCDAFC15F2E2F17 +:101310002AA17CF735D6A18797C17A503FE8E168CA +:101320004A16FE1AF81FE4AF897324F04BECCD7E09 +:101330006BFE7A05E82B47B8BEB2498958B7D797F4 +:10134000BED2C6EDCB2FD3C69DE9F0D0FBEE1D9FDC +:101350009E9A2087F5333F4E880FEFBFF8E9A688A5 +:10136000FB491FCF7184F7B77E3A07EF4F51D45A2C +:101370001BF0E53126B97CC8076DAA1203F4283E9C +:10138000EDAEC3B6F4432F96ABB2A9E77C75D84E49 +:10139000BCE86F33C3BA6E1A26AB18BF6B7E881ECB +:1013A000DEBF26F3BCC3B1ABAA15F75977FB542BAC +:1013B000FAF3BB1F54ADE887EC76F37319EE2C03F8 +:1013C0009D8F7167F37AC5BF24F3BA834EF1BED601 +:1013D000FA8DDE4E841BEBCCD137A8FA264875E592 +:1013E000C7D0BFCAE9E95F1D53FC369CEFD8837EA6 +:1013F0005BF87EE2F5FA577F041E43380A99E40948 +:10140000D723C596284FB8DC96DA1D11FD93C20F7D +:1014100099EA4C8D78EF263533E239F01B87A15FCE +:10142000526B62546FEB33F07A5B3D1E57A4F0F8B9 +:10143000CE65B3A33B83FB66726FE7915CC5865EA6 +:10144000CFB7A5A4707FF03F5218C1352B85C3A735 +:10145000AFAFD5F76BF17C0FE293B99CC8E72EAB29 +:10146000E10AB8BCACE0E927A6535D6DBEE1DE2C15 +:10147000E8573CBD753AAFAB35ECC13ADB194F3F8D +:10148000CFEFDF60C837823FB0CDF7C274AC2BAF6F +:101490008AE2F5095551A23EB46E7444DCA3183EAD +:1014A0007E6A21C69FFB8D0CF3FC8F99C00EE685EA +:1014B000F6D9AD661EAF5A4DBC0E7C7DE6A9F5A8E7 +:1014C0003F3E8BF2E6A5509EB148453C5EB45BA81A +:1014D0003EF4BE7DA529C807B35278DE2B7BCF44EE +:1014E000279D2FFBE7C151FC7D7060FD308E73712D +:1014F0007736F9E5D903189D27D1E801E1335D8FEF +:1015000082F081CE6330B713F36FB50E138D332B9A +:1015100085F3E3F5B63DEA89E30C6B7641BB2085A4 +:10152000C7CDB7E2BC046FB0FF2CDCD0B307FBCF54 +:101530001EC9FB486F59CE0BA27F1BFC510CEDC39B +:10154000BC1FCDF1C63282B46FF3EEA26CD706BADF +:10155000CEF1B8C03FB0B643C5FA0F7F3FACB71865 +:10156000E8F42E457CDC66F60F26BEB2AD89C17963 +:10157000AEB7DEB8EFF921E0047B327F3CA79736A7 +:101580003FE0D882747C579C3BD1E001387E8C7060 +:10159000687075C3A3AB3FEF147E7B278E971BCA81 +:1015A0005357FFC940798A6A09F424F4F77CC85C70 +:1015B0003E95E8437950DCD2C2F9C69F58526C83FD +:1015C000B6A071158F8FDB9588BC9866CF268AE709 +:1015D000C7BEA744D8A38922FE1DAFCB4F4E6C9C3B +:1015E0004EE7F826EAE2E25FA488BC651A4B0BCF0F +:1015F00023AC15F1C6E5B68171E89F2A10E7CA80D1 +:101600006F932AB371F121BDD0B08E459C53D4F8AD +:1016100070E469FB9D38DFC8D3EC0EF207B471BBF0 +:10162000F3131C2F97DFE37819D531ECE949D03754 +:101630001E3132BF1A5AE7040E2A833087E2A4CB48 +:10164000176C645FC61C9D43F5DE66A781A961EB3C +:101650008F52A3991AA62FADC3E223FAB2A04F5D11 +:1016600054A41F902FE68971A5458CB73FBEEC08A6 +:10167000FA05F9B6E5E417C48D1B18311E6B532229 +:10168000FC833CE67163DCE802FAE27ED998D34A37 +:10169000841F302EB091CEA18EFB30F2FA8473916C +:1016A000FD037DD1A52FFCB1DCA7D12FFCA1F873E0 +:1016B000B823F197501E89BF244F24FE521644E2EE +:1016C00027D51B898FF4E52322EEF75B9317D11FF3 +:1016D000F0C08488E733C18085F7B31E9D16F1FC06 +:1016E000E08DB323FA4337DF16F1FC70FF9288FBDD +:1016F000D9DB56FE207A8FAC5F1BF1BC9EDE3734FF +:10170000FE34627C8DDE3EF8FBDFA437730AFF50A7 +:10171000D03B51D859879BD7AD75196D8FE2797C35 +:101720003C3682FACE81E7E963D1FEAB5497E79B62 +:10173000C6685FFB97B24742BD940EA8356451BDA1 +:101740003CD5F5FDDC6088D867B73BB93F6477725C +:101750003DFE6B133F2F950EFE26D929030BC5D9ED +:1017600016AC77648299AC8F639C5DE7E818A63A63 +:10177000306F07FDC921BDAAE9D1DBCC6A6D07E84E +:10178000975132D793A03FFB39619EF7A5078DDCB7 +:10179000FFF019D1FF48B7305F6C1ED919CA433B1F +:1017A00058A284E700E2427A5CFD0E8875706536C7 +:1017B0009DC37A134140BF5975D17ED3AD9A9E5ACD +:1017C0003E9CF4D4655BA4FF767969165D3F7BBBD4 +:1017D00099EA07CE8A3A470D0FFAF3D6DA396CED5B +:1017E000FEF22D9B62D0EF3C2BCEFF6AD7270BFC7D +:1017F0004D76CAC2FE59D6603E6C1118F138C07BD6 +:10180000E5918ED8DB18F99B9370DD555BAEDCFE5D +:101810002AF4AB0DC1646E377CF4DEFC77F9B9EEC7 +:10182000F97F8BFCAE408593C7F91562FC5BA0B1D4 +:10183000039E6E013A38B07D635219F2275CA7F31C +:1018400071338F3023CAF32C6F26D54D9C62AE3393 +:101850007B01C4F94E95E09CCB3C46CC5BBD737BD1 +:10186000650C3ED73D9E360E300CFA25EF3A7CC60D +:1018700064CC1B4CE67513309F05AF7B16A53F8CDF +:1018800076499BEF1DE6BD7406E83B9BB9685C6D2D +:101890007C86E9F9303DB57BF9AA8F1260BEB54769 +:1018A0000D948F58DB6CA678AD6BE57FED780AEE72 +:1018B000DF91DED10FEDF6FB2BFF3604F9E1D6CD3B +:1018C000325381DEAADD7BA7336C5FE5ECD22B318E +:1018D000781FECEED6A7D058BE6CA63AE2F757BEFA +:1018E0003C24DC8FAD74162EC7F7D8B8EB3BEF580D +:1018F000FCD2F014AAF712FCB442F0D3DA178792A4 +:10190000BFB536A69B9F787F2BAF1BD1D67146F013 +:10191000E3CA97BE89F8CEC46EE023D5CCF7C5D410 +:10192000A160EFDB2EE7D2771F8CDE7F75C2BC2D66 +:10193000573F89C5FE9E37FF4AF0B3B9D7072FCA74 +:10194000A26F4C687F5A3BEFB9A029211FE90E72A4 +:10195000B601C7BFED772F5EFA00F1D3FCF2D69F38 +:10196000E133D779FE7397967714F6C625F001F622 +:1019700086E28B2E16CDCF9308FF46C11DF92CFAB7 +:101980009E874A7CED66C7711FA7B6D5407526B104 +:10199000B8091496AF8B950D9A51725B9CA0AF85D8 +:1019A0009EF97FCEDB2AEAA83E20D21F2A38B43225 +:1019B000C20FF2C05FAF7ED033DE5ACC2FE9FDA15B +:1019C000F101C36253DCF7F84587A6F5EA174140F9 +:1019D000ED96C688AD21F835E8F4F37E2157F53849 +:1019E00016E6FF03D1FCFC33980EF47B7F9ACAF510 +:1019F000B72D83F1F36952E7300BE8CB16E7A2C7A6 +:101A00001F856B96417CDDD8AFA53335F9C47FDDEA +:101A10007ED7A111A4B7D8B7301BE243E43DF474DC +:101A20002BC0F3ECF9617227DE0F1CFE6B2CE67DF8 +:101A300077C4AB6F213D824765DAFF89523A4C8EFD +:101A40005EE2BB57510F029FCAA9DC1E581A797E6D +:101A5000D1A2BA19C60F5176FBA8F0737F8D4E1E26 +:101A60004F561E7EBFBF09E871C9D0169B03E3AF76 +:101A7000DEBB3B16DDFF0C93F703E4C35567DF1EA7 +:101A800063A7FCCD96FE180FD607F87730462ACC10 +:101A9000A7E4F584A37A332C2601CFE927503BB283 +:101AA000297F19F2597580AF13C7C642BEE18D1266 +:101AB000F53B1B6BE371BCEADF37A7A13CBD9CC4BF +:101AC000E3CD97AE66F3F715A6E0F341A74310D335 +:101AD0006FC0F8E46511D7745E95E9396DFE918D9C +:101AE00085B21DF82127B0F100C5514D6615E91AE0 +:101AF000F51CE378688A22B9AF6E99CAD0EE7739BF +:101B0000984B82FB3BA2837FA4F36ECD6615F3ADA9 +:101B100051F68D2C1EC6DF21F659870347E179293E +:101B2000EDBA365F54D3D31873203F50DE374AD90D +:101B3000C826DBC2F11C437876A4723EDA111D3050 +:101B4000609E253898B16709AE109C8CE6D5E01CE4 +:101B5000EEC7F3843B4CC1F3786E06E0B223FD87F9 +:101B6000330E276B1AAA629E20CAEEA67544D95579 +:101B7000974FEA0957752EF3A35DFFF943AC5B6EEF +:101B8000518EABA3437D0BC8C08E814CC8F9CF1FCB +:101B90002FC908EF836219177A7FC8AF363E5E37C8 +:101BA00089E2099F8CF12FB431F1B84E95D6A76028 +:101BB0008A298FE301F7DBAD167EBFFB79E06F1B4F +:101BC000F66DFC39579CDD3A4D2239E1F5B8421FDC +:101BD000DC2705CEDF08A4FD2A702057055856BF24 +:101BE000B19FF87495A1E9A99170FFEE28AF2B156C +:101BF000E67BED43039D6BFDF38B51FE0AC0C7B03E +:101C00007D5B92DDBDC8877EFC47DE7BE8C974A49E +:101C1000FF3E49C53C6C973148DF37A96AFACC448E +:101C2000F50D8D1F53DDD39BA9DE4938CFB8C61AF9 +:101C3000DA8F1ECF36D27E74B6380F5EEFE4FAE349 +:101C4000F2E921CFD684E17F492A972F16F40E407E +:101C5000B96912F2D9827E0AB47B85BFB4B7F5D6D2 +:101C60002C352C7F58C30EA423BE1F6287A8D5AE87 +:101C700077F9F9B9CAEC772C77B8C3F86F9190F778 +:101C800045A9224F96EA9D8DF0AE6AFDC414ABE2E1 +:101C90003999FAFE6857EAC19FB2F782976EB9D5B3 +:101CA000C951B51234E1F3D517F8F957A0731D9E49 +:101CB0003778F99DC6118BE1FA5EC035D695FACE1C +:101CC0009AA9BE72AFD1938ECFD79CF93A17F55629 +:101CD000090201F07CDDBC6A00E20DF8BE281AE5BD +:101CE0006B17233DA6C9670ECA27BC9F837C5F8004 +:101CF000FDE1A4877798DAF9F9D3BDFCFC29F03D22 +:101D0000C901F0BD1DFD861C3BC801BD3F94E47BAD +:101D100047BB81CEC9FA408F0FA67ED11CECEF687D +:101D20002FB1937C635E3F0FE5347080C6A987D8DE +:101D3000044927314FB83FD9E88C25BA69FAF1B088 +:101D400093093BA1C6E17903AB2C47C845983DE414 +:101D50007D612F4FFC2AF0F82FD176B8855D10FEFB +:101D600014F3E6939EBF57D8AAB5AF4F98B91DD6C6 +:101D7000B9F684DC5D3F8EFE6B40F0C901E1CFA275 +:101D80009D5013783D0E5E1FBD99D7D58E71AF293A +:101D9000C6B3CFE3CA371EC47682A7BE18CF3E4F64 +:101DA0005AD07E909F81E6E7D91B0EDC948DFBDE36 +:101DB0005D67CD0CF75D1AFE1AFCE34B8087FB5B79 +:101DC00000FFBDD825580EF11F58EC74E6EC79BF22 +:101DD0004BD2F4C7A90AE4C7CE0639D40740AA807B +:101DE000C1B1FFDBD4938FFBA09F95E67E3E15FD2E +:101DF000ED742FB55D27FF9A8CB660EF69EE47351D +:101E000098DCD9C83F0D0323BF1FA0B54FA61A8980 +:101E10000E057D7CBFEB482ACF6F0EF1B1C7908FC6 +:101E2000AA1A64BB1FE87EA941769BC01F3AEFF651 +:101E300026E3D99C0BCC77CB44B4F3228ED4BEF7E7 +:101E40007217FA2960A7EEFE65EFFB0FAB99F65B00 +:101E50006340BE5AD624B1FF001C2C7F26F2F9D570 +:101E6000DAF76A1AB71CC6EF88AD7C4E771FFD15EE +:101E7000FA0E46A41F732455F827592C0BFD13E0C6 +:101E800023D20F46851D3103DFAE48F7EE437BFCBE +:101E9000B2F8BE02E85192C77D4E615744FD4170D1 +:101EA00007AF2B1EBECD2F1BE0FD098A5F467BC509 +:101EB000A0C57D87716E6F197D87C9E73E8DFB3E9A +:101EC000CB853E5CAEF9697EBE3F026637C24FAB42 +:101ED00016AB1FCFFCB5B1B8FE6D12C5CBABB64586 +:101EE000EEA7548BF5AFDE7CF2309ABCCA7ADD7D6A +:101EF000B1FE6ADDFAB57DF3CF5323EBBFAE773F7A +:101F0000E42F46EE37BC2DC6D1EE9BD2B87EAC8214 +:101F10006520DD56FB65BF9FFB7936FC5ED09D6278 +:101F20005D770AFAD33AE1B9CA6D923F803CFE78F8 +:101F3000649DE95DF58BCB90AE7A3E5929D6BD7C88 +:101F4000BB91FC55FCFE0FCA9D9E3F568AF5AFD44F +:101F5000ADBFCA2BE9E0E37E744FF8EA6F413A5710 +:101F60006E37B2DEE0D3E8B552E3EB3EE0D5E0D425 +:101F7000E0FEA1F0F64F13F9AD116C04D1A93CE1DC +:101F8000BAE8A4F773771D1E41DF5BBB7C6420C5F4 +:101F9000FB1A1FE8DF2F137EF2D4CDDC6FBCD458C0 +:101FA0006C1D89F14C9BC125A9149FC58E04BCE40E +:101FB00037CBAC02FA5D4D599BF0FB8379270AE6DB +:101FC00060FC9F7FC240E7EFF61C29A07DE7FCA3E1 +:101FD0008312B228CFEDA2EFE3C038645FBBDAF220 +:101FE00036E1F984AEB692021C5782E7D00FC813CF +:101FF00076A2A62DCF1A7EFE7C4C1A8FEFD73B3FE0 +:10200000FD39FAE9537719E99CC55463F04DACDB0F +:10201000DA7344A17DF2D527963C1485F47D51A254 +:102020007DF2C3ED6B1317229F3519EDB8EFDDD5A7 +:10203000F4E30378DFB75DA2EF5E54379766EF8075 +:102040007EDE967C57F8F9B33C874AF0B1542BC535 +:10205000CF53FB19C96E5E4CB3FE16FD9F95EE2D56 +:1020600024DF17F7EF3151DDDE0E89A1293BEC3C6F +:10207000F80AE2E3E2AB274DE88417379C34757C1D +:102080008F3F70C92FB300C5CD1B4D18C7546ED1FB +:10209000FA1D26A49347F84755CF7D4CFD95E8CF10 +:1020A000C37C2B9F91A97EF760F36B26E4E7AAED32 +:1020B000124BC90CBBBF598AF85EC312C6F96089BE +:1020C000D03FAB987F7D1A3CB76A23AF5B608F46E9 +:1020D000D6016BFCBD42F0F7AAEDB3E8FB533DBE61 +:1020E0005B8871E30DF81CE7EF659B23EFAF107C75 +:1020F000BD42C7D73F4913FA67381B8E7CFD75A1D7 +:102100001A9703D7BF3EB972406FE7ECDB84BDD6A8 +:10211000ECE5E58081EC8DFEB9CEC62B046775DB5E +:102120006513FAA7654D5F10FE2B9A5AA97EE466E7 +:10213000E65D8DF8BAB9C96A47B9AEE8E07A685A7F +:1021400093D9EF97F07E3DD53977B5F0BA49DF7E68 +:1021500089FC1C4D8F69DF775C26F0B80C14787A07 +:102160001EFABB3C6EAE1271F28A615B0EE33E7BDF +:1021700095B8BFFAE8C158F40FA7B12F6E47FAC05F +:102180007C0CE763CF44E27DBAD08BD3B773BDA894 +:10219000B76B5DA9D933298F09712AC2B57A7B241F +:1021A000BEAB74F1F963693C3FF6820EDF15416600 +:1021B000CD413854D9E5A7A7DB159CF7482ED85B4D +:1021C000B4936AD6F77E87F14DE1676BFD99E21C07 +:1021D00078BD7DA32D3C6E8E4AE7FEC2CAF1B20FD8 +:1021E000E9D51D6F0C3A98AB1A42F106C419CD69B6 +:1021F000493CEEC082923732649698188A371E7135 +:102200006EAAC8837EF5762EF79DE3603C3C7FADD9 +:1022100030F247ABB79BE99C6235D09FE28A267EBD +:102220009EC2D3249522DDC15F3F9A86FBB19852AE +:102230008575CF6AE47C3FABE40BE297A383F87A21 +:102240002F2B6A4A6FFEBBE6B7E3F93035CC7FAF80 +:102250000239C5E7AB9A783D52C3816FFA67A29EF7 +:102260006BFEAFFE8BA1FD5AD845CD2F0C825F3897 +:1022700090FB45F4BDC9BB857C2DB3F37DBABB850E +:10228000FD61521DF17995B1FE503CFA593B78BD84 +:1022900000DB871F8503FDF8F64B75F1B0EECE9796 +:1022A00024AA87C3F7F17B949D4BEA3F41BFFBEB28 +:1022B0001D16F237EF06BF654A5E4FB9D4E45BFBEB +:1022C0006E560D7B88FCCF87581DB595829F3B1BB2 +:1022D0006BE9FBA09ABF42EF0FECE98F540ABEAF47 +:1022E000D4F15F547A24DFD5BC1D4D7E63D751D91C +:1022F0008EFB3180AFDFA485E345F8210D07A2886E +:10230000AE5D276D6447FE2CF8EDA2C83FD78C93D5 +:10231000090F86F1BCCD6E796D20D211F18EF5F7E3 +:102320002FB7BC36829FFBF613FE576D9323BE0F6B +:102330005B591FF9FDD79AB76FA3EF0855EFEF86EA +:102340006B88293104575F7220493C8E3448917163 +:1023500064F53ED9135E7706EBB903F551BA9007E1 +:10236000A6049331FF35009D0680AFA689D3D5D052 +:10237000CC5B98FF169E2731D2FC3DEE17F956E351 +:10238000FDAF33AD7CFFFAAAAF02FBF70F94A9AE05 +:10239000F3FEB7570E0DD7A30CE104BA561B83C941 +:1023A000146F9E34107CD5272F270FB2A15EDA520E +:1023B00082DF0F9D2EF4DFE181D6E5C8CF3E9C374A +:1023C0002534CECB69BC7E8FE17A9DE86DFC928F7F +:1023D0002BD6FB109B2DE26ACE4F39697CBD108F46 +:1023E0008C4BEF251EB95EBF13ECC3A98512D63303 +:1023F000293E8C87F7BCC7F5424DF3B28F90DFAB17 +:10240000DF37539DD7FD2DCB8652BDAFD77B03FA67 +:102410001B5FB7ACB881F283D24304970FE173A27C +:102420005F732619EB522B9BCF2493DDDD3B7A9310 +:102430002F06FD97BCE9781DFC09E23FF06B88FF91 +:10244000F6B415687E8C15C7AD3CAA78103F954749 +:102450000B8E57A07F71A2A800D5B974A280FC98FA +:102460007CF4636C21BFA65B4FA6733FA6AB358A95 +:10247000F20B121BC8F9870D8AE09FD50DAF93BDF3 +:102480005FDD2847D42F6AEFDD99AED038CB34FE1C +:10249000A997DCC41FBB78BBBA710FAD6F95B19E15 +:1024A000E85DB3DDC8EFEFE0ADF67D581F8BF72197 +:1024B0003E8EE325A0C334933F03F3D3C732B99FC5 +:1024C000AFA7C7E7E93CFF71ECAC7700F2CBB142B4 +:1024D000EF507B2F76C2C78A785C2B097C37F0736C +:1024E00053FAE73E4B97C4774222CFB76AEDA974FF +:1024F000AE3FA7997AFF2EE06FD2B57309EC314356 +:102500000146C546FB06E1D7A7867DD761CECD46FD +:10251000F2174E31FBEB58EF3843D3B3E3B87DD518 +:10252000E7CBE789F73C9B55BE5FA43B3F334F3B6E +:10253000DFA43BEF364FF83BF374FECED3E9C28FF6 +:102540001FC286A01EAC17E7EFD60E8FF287E7B347 +:10255000F4ED61B12F82E787B0AD19FE2EE57D8ED7 +:10256000B59E7D85EADDCE46B1813CAF47F9EFCA25 +:102570003EF2DF35DD72393782CF34BA5C12DF8349 +:10258000D1D365B7A6AFC4BE5DB4D8B7F31BBDBB8E +:10259000519E2B2D174DBCEE3068427D56339CFB6F +:1025A0004D974A25DA6F0738FB9BC3F4FBA5541EF1 +:1025B0007FDD7F8B4479D7567C1EE3AC7A89EABCF9 +:1025C0002B03ED26E4A7210D8B1F26B9F5B1D32CE3 +:1025D000ECBB1A332DDC4E76D34F5B77B71D8BF7F0 +:1025E000717D9C482D3E8F767186B083FA7351437E +:1025F000597B593AC033DF2DB9B01EA02F3ACF5EB8 +:1026000030EA7544C3F5D2BB33DDFB4E3ACA79FBE1 +:10261000E55B308F7A6CF867FDD18E56F5C1C71F28 +:102620000B3CEBBF2BE31AAAD6E2F7556A9DDE0EF0 +:10263000D29F866F6347301CA7E3376B25A4132313 +:10264000FEEF4B7E3E13E37E96CEBF770FB8A77D9D +:102650009755E9BC4EEB98D19F41798A9CEBDBF70B +:10266000AAD9F7462EEAB3CED6A3B9A630BA5E5C95 +:102670000B7A00ED4AF3C164D516CE7706E23749EE +:10268000D2F84F11F632920F2F221FE6607B26768A +:1026900010EAE35DA76207E3787B79DBCDAF4DFC01 +:1026A0007BF6101F0D9917130EDFC304DFA57A3ECA +:1026B0000E631D43E68C0CBF5FDB171F5B33888FF7 +:1026C0003B22F8585B6F3D7ECF07E38016337DCF0A +:1026D00007F3D78E3039199AC1F5CF58F1FD9EF125 +:1026E000CC47DF391C2BBEE3335E6101251EF7CDDD +:1026F0000232DFF7E5E72DC6087E1EAB045AB18E25 +:1027000062BCD8E799C0DAE9B9292C48AD9BD9E970 +:102710001C451173513BCE12988EEE544E7D3DD523 +:1027200025069215C7798B38AFD10BDD42EB57E800 +:10273000BB3DC49F329ED7E9FDBB2FB333B8DCD37A +:10274000C74590BE9718E5B9F07B6D38C9448595AB +:10275000637DD3648559A201DE5D870C24CF2D1DD6 +:10276000AA1FEB535D09E2BDCF19D5E18E757379D0 +:10277000459383F518DA7AF5789800E3619E6DAC9D +:10278000029128E13140F3DDC8F8399242A652FDAA +:10279000736946A6D0F7418AA38A218E427D6FB025 +:1027A000F8081FD33354BA8FFB25B130CE848D1275 +:1027B0007B0FF73FB2F87AB5F1270023E0F9C2E9C1 +:1027C00019DC9E614AF5BD78BE8F124B05CD25768A +:1027D000FE9DA364FACED1F5E2B52B997FEF32F6D8 +:1027E000CE60E7CF0A42FB492EFCEE516CE83B9BE2 +:1027F0002EEDDF830844FE7B1077642CF911F2A3E1 +:1028000056AFC7BCFCDF7DD0D7EB85D5E7B10B61F8 +:10281000E7B0B5BA926DFED92A9EF35B9068A173BA +:10282000BF7996FEF968C7063ABD34FEFBD2F6C101 +:102830003498E21FED8909F1BB95B9C721BE4375F4 +:1028400083FC3B50DDE7AE92199D57B49A797DE544 +:1028500063201FF81D26902E15EB68D883C5548F72 +:10286000B9DE6171E1790933C26D0DC15D6B11DFB4 +:1028700005B5F07D717D3D68ADCD40DF1DAD65D105 +:10288000740E3D29DABB2E03E0BA2FA688CE7767F7 +:10289000EF9CE444BF317CFD93B4F51B7AD647C26C +:1028A0007A1FC9E8A51E515BA7F6EF76D805FEB4DE +:1028B00075DBB5734A6E25E29C92868FC7A2F9BA82 +:1028C0008DB8F39F45EFAAA837F4EBFDFFDC29BCD8 +:1028D00016A06400000000000000000000000000DE +:1028E0001F8B080000000000000BD3D76660F85172 +:1028F0008FC02E9A0C0C5DD2A862B4C41D120C0CB1 +:102900009780F80B106702EDF5926460F006E26DB7 +:1029100040BC1D88C5A518180280381088FB80FCB3 +:102920007E204E07E224A81BB30519187281381FB8 +:10293000880B815848808141588078FBCB15191845 +:102940005EAB22F85A6A0C0CC91AF4F3FF60C38E0E +:10295000B6F4B5EF14D0BEE56E08BE0490BDC20D4E +:1029600055CD4A37FC66AC42935F8DC65F83477F87 +:10297000A20D2A7F99292A7F9D3903C3432435CB91 +:102980004DF1BB051D0B02FD2784274C9730A2F2A9 +:102990002732A1F2F9A17C00BA0B8074A8030000D1 +:1029A00000000000000000001F8B08000000000075 +:1029B000000BED7D0D7854D599F0B93F73672699DA +:1029C00099DC24433260126E7ED0A001879860B0FB +:1029D000586E20E147A30E082CB440262888166DB7 +:1029E000C49FC6DD500609BF0921E14F70D11D10FB +:1029F0005DEA63FBC5565B75BB7682D646AB356830 +:102A0000D787767765A015BFBA761BD96D976EBB51 +:102A1000F57BDFF79CCBCCBD9900FEECB7BBDFF3B9 +:102A2000C5C7E770EE3D3FEF79CFFB7FDE73C7C5CB +:102A300046B1E058C63EC6BF698C4DCC658CD5A664 +:102A4000CA160F8B65E73096DB213156C3D8CA769C +:102A5000253E0BFE59D8D1F20AD697B7B90D772982 +:102A600063FD0FB8FD35503FBD5D09BBA16BA3E20F +:102A7000A3FAB22E57D86DC0F3AD1FBD9C8FEF37B0 +:102A80004A610675C6EE666C32636B3CF04FA82F48 +:102A9000AB4876E0FB77B748E118BE66A66F12BC7C +:102AA000BF95F1F7CD0F281A93A1BEEFB626369148 +:102AB000B15B7A60160F35641FF3F68C153016E1A2 +:102AC0008F58CB16785F997A1F615D1F29D0AF3977 +:102AD000E678BE6FD6FB2C80EFB5D47358CF31FCAF +:102AE000C714C62E65FEE0E96CF87798853F56A0BE +:102AF0006CC8676C740A5FCE9231807E1463731960 +:102B000073B17218A7F632172B83F559786CE378F6 +:102B10005CD624111E97F918D5DF9D2BC51F2CA557 +:102B20007E6C7A3594F0BC200FCA20330BA18C78D0 +:102B300058221BE09FDB76D97BB8FE0D38D5686A3A +:102B40009F08C0FB052CEA6200DF9FB118958B59E6 +:102B50009CCA2FB304C1B1940D95A850BF4B496CCA +:102B600062304F38149D8EFBFBBBFA63EF4AF0FED8 +:102B7000FE6AA9760A94CC9747EBBED0FAACF95519 +:102B800016B90EC7614C7645FC8C8DB7D67998C5C1 +:102B90002A828CE93D3E4E2F87593F83FAF8064141 +:102BA0002F8DEFCB215877CFF32C8CF5106CE614DA +:102BB000A887BAB2E21BA0DEF378AC1EF172AC05B6 +:102BC000300FFD8F35BAA56815942EDD158132A41E +:102BD00032A6009EEA1BD64B0AB49B1BE5E38C375A +:102BE00035995D09F5C3314915CFB1BFAEC7241D75 +:102BF000EAE3A1FEA084EF751783711A1A725DC90A +:102C00002AC477CF181DCA8AC35A4206FCD69B3AFB +:102C10003D676C11D1D578416B734DDE6FEEE13CB1 +:102C20003FA3F7EC4F1F5BEF01BF9714F17D3B769D +:102C3000B82C07E165517BFF2295C53C79293CEF13 +:102C40005C072FDC29FCEE3A5CB615F176AC4F0D33 +:102C50000B52B68D0FE3F636C0FB335572583190E8 +:102C6000CF8A38FC15BA5FF7A5C6D9B90EDA5F96D8 +:102C700082A35199DA4FF83019F1E3DC1A685F95B5 +:102C80006AFF04B60738F6203CD46FCD512FCE131F +:102C90006134CF48F4F0C23A9DFA0D8A755CF3BFF7 +:102CA000C3B44F731B5A243EAF80AFC10E9F555A19 +:102CB000F08D34FE31019735BE35DF13EB425436CB +:102CC0002A558FDC8BEB3AA2F175CD371EDF8DF8DC +:102CD0003BE209C7A0FEE4757F33E65E18E28AE9AD +:102CE000CF5FFE0CC3F9963F7C3BAEEBB92C5AD7B5 +:102CF000531F9E79ED46367CDEB7041E7E7A6EFE4B +:102D000010D5ADF9E79AD21809E8ACD294122EA0EA +:102D10009763F55F79F85E03EBFD26CA934AF39853 +:102D20002941391186A1FD66EA9F3E06795609DDE3 +:102D3000911F2735482DD8EE891B1FFAD27DF0E868 +:102D4000A72E0EF7157FC9E1BEECFAB54F22BC974E +:102D5000DDB8F6E7CF40FD0A1482C07797DEB47F76 +:102D6000CDDFC13FBFB1F02F97EF61241762D900CB +:102D700047AE2931DCDF65DF77DBE4CAB1E7FD244C +:102D8000570ACDD218F2DFB23E89E4737FA39B05C8 +:102D9000F1FDCFDC7137F2D7039249ED9F75C75132 +:102DA0003E1C733186F278D9716F1CF985AD5A4695 +:102DB000F23A62C96B337FE9BD30DEBB0D963CE76A +:102DC000744AEF617DEF9ABFD87E35F43F63BAC293 +:102DD00028362D79E1C4F3BB02BF91FA72A2836554 +:102DE0006AD215CE400FCD6D8A4D6ED7379C24BA6E +:102DF0005A06254BE3D3B982CF9635FC42F0A74E55 +:102E000072C909CF1BB585C599E8EE94802729E8DA +:102E1000ED5DDCEFCB103EE88574D3A5C495343965 +:102E20000D7FAEC804AAC790A56FD96287D392DB85 +:102E30002DB16C9BBE02F9FB2F28379BDBF26DCFC7 +:102E4000E7E6B0DAA99F4E0EFF81E4705222784087 +:102E5000FFD2FE47E2521CE5A2B53F7788FD8954B8 +:102E6000305ACFAF0E48F118ECEFAF8E88F5ED93E6 +:102E7000E28A44F46A9EF6E0B83067796AFF6F1719 +:102E8000FB9FDA3F8E1F0B5F293D97BB290920B4BA +:102E9000F8222528AF2DFEB1F0DBBFE74725B87F2C +:102EA000856DA5DD7508E70185F8F7C3FA93C5B808 +:102EB0006FEFBA00AFD03F72F8B100F3A5E06F1129 +:102EC00072F0830EA017782E219C9569700AB85D68 +:102ED000588776B737487DC8A7BF14F35AFD7EB42C +:102EE00065C64CC4CF1D3D1243FCDC7EA477D99F40 +:102EF000C3FA57C7B3C338C5AF1A8B0397003C2B2F +:102F00007AECFB796ACBCD01A49B0FFBF20B709C92 +:102F1000DBA72634847375E255CD003A9B65F66ACB +:102F2000C90C74F561DF8600B6FF50EDB9F11A9C4B +:102F3000679F125E0FE3AF3E523AD3E4744AF4BB8C +:102F40005AE0F7A4DA33730CC0D7F28D729207EF10 +:102F5000F529B3E319E4E7D72585E860759B5BC6DF +:102F6000758E442F1F76B85802E7511384CF91DA3B +:102F70007DD0D742EFFB1F28BC01EDB7DBDB5D2422 +:102F80002F6E6F73133DAD6E90E24C4AF1DB0A0178 +:102F9000EFEADD0ABD3F694A243FACFDBA5DD0DBF4 +:102FA000C9C357BD82FAFE0CC81F94BB3336FE500E +:102FB000BB04F0B0620B97472777E72EBD07E58883 +:102FC000D0977788716F8B2B36FE58D99E6DDB8F2B +:102FD0006857BEAD7EFA48FE8D7548D75D0AE9CFC9 +:102FE0005B363EA685483ED9ED4DE4B0490529FB48 +:102FF000F2041B5A708D94A2278B7E6E6D037B3377 +:1030000030DCDE6C3922913D7AD176661BD899137B +:1030100087DB99961C89A07D569E922396DCB84B3F +:10302000898E0D021CBF76452FCB2F27B9F1805416 +:103030008B74A2FF16ED4A16536A51BE5DACBCA05C +:10304000C55A7C047FEF75005D65A0D719485730DD +:10305000CFCC9EFE8CF43C433268BC14DDDC1220E5 +:10306000BEC541018E668FD985705E02137BABA908 +:10307000644A1E2F55A86F4698811E4EAD95E28773 +:103080004A793B1FCA5380EB1A78DEDC75797C9B4A +:10309000847621FCA1FE6CE37637B433FD79F4DC51 +:1030A00094A02C6A2F7D19F7E71210005A356F8F04 +:1030B000F3809D452881F6097735758D05A02C860E +:1030C0007E32EF4FEFB15D80E4789CD68BE3E3383E +:1030D000154A7C0DCA198B8E9709B90372B5520532 +:1030E000FA6A665961D49BCD6DE5E7B55F6E08DB82 +:1030F000E5C74D75763D30D7B4CBFF9B675F626BFC +:10310000BF20526E7BFF678BAEB0BD5F1CBDCA5641 +:10311000FFF2AA2FD8DA2F6D9D61F7937E9A4BEBC1 +:103120005923F87224B85F17F2F2270EFBD42A9BBA +:10313000AE4FD4BC0DFBC4D6B9C38F4371620E5BD6 +:10314000D49726577CB244F8FC0DB009F70FFEF473 +:1031500031E131C4E76DFA0B776B26BAD3443F34C3 +:1031600097D05E72B63FB118E649EBF76F924474A0 +:1031700078AE1FF3F4FC12406E014ECE01D4DFC9CD +:103180009225B86FEE5C83DEDF25270BB0FE1B3681 +:10319000B4371FF7D7972C46FE6956D973520EF6EF +:1031A0000B7BDC301F5843AC0DE8A3A5ED47C7D11E +:1031B0008E938C205B82758F2F81FCCD3A5C1F260D +:1031C0002DBC031FF686A21F4A0087D4DEFF7B09B1 +:1031D000DF7F9F19A88759B22817FD479C2A9D0FAA +:1031E0009B66B056C4D789463BDEBC621D3F9764E0 +:1031F0006AF71C337F8B7C7452D2F9FA04BCDB244F +:10320000F32CCE67C1FD6EAEAEB14F07B722D72209 +:10321000DC3F22B837B4B264B63232DC5730D32D3B +:103220008F1A0ECF596666657A3E0BD835D3F3CB2D +:10323000DDAC12EDD5135256787D299643FFF83553 +:10324000E0ABD8377CE1C78DE1743155CEA5F99B51 +:1032500085BD5BD82E25B2D13E651EB25F59CF43E6 +:10326000A607E59A10712D6DD2495C3FEB68349347 +:103270009ED47A9921B1F476E7F6BDCD4DED2D7946 +:1032800063C92D0B9F965CB1E4978557E7F823C976 +:10329000191C4FCD43F8A393E4743AD1011F1310C6 +:1032A0001EB31AF7CFDA377023639EEA91F7CD92F7 +:1032B00053D08EA1FF3FD27E019EC8AE738519E127 +:1032C000E9DDE0D0D2A760DD036D5C5FBF5BC4C801 +:1032D0003E3CD376D5400EE2C7E3A940FC14F2A9E8 +:1032E000586170681DCA579F9AE847B80A85FEF270 +:1032F00032AEBF0A99B1E36AF4EFDB4F2EC176D646 +:10330000FEE48AFD6986FD417FA4D937548C76920C +:103310001BF51AB47383DC45B95CD8FEFE7FA05E52 +:103320002C74E8458484A5C39155B5E36A237DFCDC +:103330008F36A27D698D4B1DD2F73FA89D44FC16A8 +:10334000B66FBE5B09D8C6973E463C08B98D66D7B6 +:10335000B9794AD15E9513EE408A2E9C7059FD468C +:10336000A213963E4FB9AD4EF684B3EE0E6B36F90E +:10337000FCEE1FCB735A7DE7A137E7784EFA76F261 +:1033800081C0C3A7A0D34D9C4EB95CB0F8F63F8B6B +:103390004EA3D6BEC672EF3882FAB54B0BCF32D0F1 +:1033A0004E18FA21B713DCC621A4B398945509EF3F +:1033B000A31D2AD98D965DD1BFF6AFB794C1F31383 +:1033C000B532F91127D673BADFF300B7472DBD1D0B +:1033D000157A1BED02C42BD80D036E5E7A701CFFAC +:1033E000FA9B4B2580DB630CF5BBB17D9B41F66AF4 +:1033F0004E5D5C6F84325E71C833CE48C9A5642CC3 +:103400003F6F39ECD7B7728D6511B2AFA3A3E7FA5E +:1034100053EF7F2C73FD34AD84E5CD86F1925BE5EF +:10342000F083D03FE9B2EB31AB5CA3707D99F4B28D +:1034300012F483476A37A4587A55D7685FE60F1CA1 +:10344000C77D1A691F6007748A639EA3438E7798AD +:1034500087C64FFAED7AE8A4D04316FC9F40AF2E02 +:103460002C06FAD82B6586FB23315EF4390000F672 +:103470003BAA3233533BE7BAFF41F44BC82ACDB7DE +:10348000A362E76CDCEF584C09A7EF8755FE85C2B5 +:10349000F567CEDC86DC4668C7D6676E9727DA3DCF +:1034A000765FD622F4AF00752AC66B42317DDE6CA2 +:1034B0008C474ECD9B843EF68F51FFC0BCBB23672B +:1034C000F416DF27C247414819191F6FCA32DF4778 +:1034D00007DFEE01770DE56752F250FCA525E6CE39 +:1034E000C8C7969C72CA23A79E934C93B5550F9755 +:1034F0002BD6B89F549F817CC85246A5ECF673FA30 +:10350000EC62E97104395022B3685F06FFF46A8502 +:10351000E3A93FC6E314AA2993DE9AA9343109F03E +:10352000B421C8481EE4E15E23DF36B038A080E550 +:10353000B3F0800FE549506609F25B9D7EA0D98407 +:103540007E609083C6F45165FD85F03C387F259DF3 +:1035500033B00897B73AFCC7F9C8247DE116788DD7 +:10356000C626519C33AFC92EC7DDE807827CD41B29 +:103570001CCFE7CFA4F306374B7B0EEBB84AF1071D +:103580004F8369CFAA590DF267F5FEAB762D86F110 +:103590006B1EB9F96D2C271FBC27FF4B50D63DBEC3 +:1035A000EB662C4B5E8B8ECD144FB54AE01426D7BC +:1035B000017C3E66B873466E67AC57226857C33EBF +:1035C00076203D2463E55948DFAB14CEFFFD0BB4F4 +:1035D00000C667D42D5CAEAAF3017944FFDC4F6FBF +:1035E0004EF9D3E457A8C24F52DA158A2324F53294 +:1035F0008AB71CDA226B58829C8DE13CD6FCBD2236 +:103600004EDD29E2AD4EF87A4B868A510E9E58FF68 +:1036100011D9878A9E159E0DF375F95909C121E2CA +:1036200005CD62FF926BEB3DE9F12245F8391D476C +:10363000E70C184807034AD86B10DF68386E74CB64 +:103640007486F197597A98A13DD129FC1EC567323D +:10365000DCD76C9DCD44BF165E6921EC5FC5C20905 +:10366000ECDFDE8FB885F59AB7231FFCE05A6E8732 +:103670009C28B5CB6D20A12ED85336AB68BD8AB43B +:10368000D9149C7415D2FCEF9502215739BDBE5157 +:103690003BE5B16D4007CFB9CD7B94519F808F1C26 +:1036A00072FD07C026B86F8F4A76796E95079D7CAC +:1036B000D426915DA89A7C9D33950F1B514F6E04C3 +:1036C000BBB1D018CE2F1B5F6764376E04FE8B959D +:1036D00066E29F6A0965C4C5F24F5E7BAE84718C59 +:1036E000CFCA3F7FA988733AC13F406709B4631EC0 +:1036F000958CCE29B0BEEFEC6BFCF11478FDEC811B +:1037000015D9D740F9BDF8C6EBAF81F96F7F7C4F73 +:1037100036EEF3A3AF023F9DC78FB7F8A9196DD856 +:10372000F3C4D98CB5767E32D657103FBDA570FD57 +:10373000D5BFE0776F5CFDFFF9E97CFCF4B602F4DD +:1037400039ED4F678BA3E7916FCD454C437B0BDA87 +:103750009848E7D1A0BDF4A95984EF752E2EC7FC77 +:103760002E2FB73B42FCBD73BCBF513F79FC60417B +:10377000F967E7D3753EF3A3CF83DF41EE90BC3901 +:1037800031CECEF79D2E4E77BF727DE2F5BDF3852B +:10379000CF617D60D7937D779DCA0CF40326BEE090 +:1037A0002161F1EAB88D479025A6C1F3501E7FEF45 +:1037B000CE237919473B6648A9A4FE26E3767C53BD +:1037C000CDE623FC5C62B06211F8CB73E05F688FDA +:1037D0005CE7E37E058CC34230FE6A6FB4581D453A +:1037E000E3917FF9EAF3FB82285F5EF79825F89C66 +:1037F00025D55C3C1FB0EC8E91F95D65A7D3FCAC80 +:10380000A73546709CBA54A378258AB100D4B796E0 +:103810005E4A714A168E1D97B03E4A6728C795606A +:103820006431D9216D6E6316D4B78201150B12DD98 +:1038300092DC54DA7B430194036097E07B3536D702 +:10384000A3A1FF324AC6203473B77D447EF7896254 +:103850002E6F3BA6303AA71978E0DF96CA68EFB41E +:10386000BBE9DC02EC46E2D7A8901BC9E0F4500BA0 +:10387000FA19455A5882FAA6D82F8E7F8DCB13D3CA +:1038800033393D3EC2E31D2D21EEEF3AEDBECD5F53 +:10389000BFEC4D03C7FBE16B5D9743F9FA933F7FA4 +:1038A000FD7278F7C6B75EABC1B8B7BB4EB3C51DE6 +:1038B000DDCC7813ED2DF099121ACAE7D8C925B8D6 +:1038C0009929BF4E8A217EA235FE38AE17791BF1A9 +:1038D000939CA2F0F345F80B017C01015F77F05453 +:1038E00015CD137BFF3F32C97BFA9B2CF408B4DB68 +:1038F0009C777F1CE5486ABE49249FA2209FD08FF9 +:103900008CFA7A96ACA1F9FCE107B1CF1F61572779 +:10391000A7CE0B0F6D99D782789EBBC0A3239DB90C +:10392000639BEF463A77AEF38CEFC14B3134679B24 +:103930001FF8C45DA1995EB27FD961DA0FD1C4824C +:103940005B0705827107E8BF6C05CBD0DF80FEB84E +:103950004E9067686F5BFD808C4D5CEF19DFF44B18 +:1039600029DE2FE21556BF9B62129D13DC540E6CAC +:10397000503E1C4F1B7CF24FBE86E72E3145573818 +:103980001D842AD2F0867FF6B819A78BCBF6D9F51D +:103990002ECCBFB014DFC714A21727BF8C8FDBDB80 +:1039A0006FF09DFF5C7FF87E723C4F14FC66F5B7AC +:1039B000E02378A54CF175FBB9CC4D75F6FADC61C6 +:1039C000F8383F5CD355FBB94D83CF3EDECCA0FD2C +:1039D000FDEC227B7D03C66F3EC9BA1D7CF7F4184F +:1039E000F33BEA67F0EB2DB9FBBE27F2B7348E1A32 +:1039F00066384EFF82BDF3E7011D14EADCEE289C19 +:103A0000BFB021B706E51413792699ED8F42A1EFD7 +:103A100095F697941CF4474DDE3EB9E4AD1939781C +:103A20005E5CC7E83C3DAADE13CB3152F648BF5A74 +:103A30009E8578FEFCED91BBBDE97937297BE48159 +:103A4000578D9A0CF6887A8F64C238B396803D52AF +:103A5000956E8FB44A2883B297803D427647F43DF5 +:103A6000C4D74876C98F2DFBDE9FD9AEFE83CAF539 +:103A70002CE8997FFA2C7A669CD7FC17F573B0076F +:103A8000A695182B2319E8F00395C73B2CFDD918F0 +:103A90004C2878760E7A5375C1F36BEB922FA138D0 +:103AA000EED0770671DDB01E97ABF6D3AFE78CCAC8 +:103AB000E199A8F23C9891FA7D6B047FC5AB7985BA +:103AC000DD62DFEFFE05EFE832FA2FE0C7A0FF92DC +:103AD000F4956DC3B8E099984AF13A75FECADD7362 +:103AE000919EC0CEE6F47C7EFBFADA21D9C6C7D31C +:103AF000CE66D9F8BE9ED9CFE96678ECE7748DBA68 +:103B0000FD9C6E56C87E4E37C7B09FD35D5F693F40 +:103B1000A773DAF73347BBFE7BDAF7A14646FC749E +:103B200001FB1EF8E926A4A791F8E9BA7CE3FE4858 +:103B300086FDAED6B89DBADA1B59807437CDE076D3 +:103B40005D34B69EF201F3A2206F4A296E48712FB0 +:103B50002BAE65C5BDACBC402B9EE58C5F59712F6B +:103B60002B8E25C578DCAAD9135D81F036B79F94DA +:103B7000518EE8CFC13CC808D639DEB0F81C970793 +:103B80002DED99E372CEF8DB88ED3E255F7D0EFAD0 +:103B9000613DAED7D20FC0E70F7E163E07B9B50D17 +:103BA000C7FB17E4F751244FBA69FF2A00D768A76B +:103BB000C33E6818A75F707A3FC6E3D4E36EE2DBCA +:103BC0008BF57F31D141864D8B820F8EF1AC68AC85 +:103BD00094F48BC537169F38FDE361FCF15FCD3F50 +:103BE00017E91F03FF7CCF751E7D04FCF13CE27BCF +:103BF0005A25C7AF931F2CFA07924848D5B8DFD192 +:103C000004B6B7E89DBD183611CE89C2AF39315A16 +:103C100023FFE2C4F3FFCECF619FF784C78935E26B +:103C2000FB89DD05F16DA5293EB3F8A9DD13FDB1D2 +:103C30002B2D0FC4CA773CEC315FC7E721B52F812C +:103C4000FE4A68360B6F3088CF8EF1E79C4F7D615E +:103C500046F1D3CFEC97ED75C5F17CA8451A5ACA49 +:103C6000C86F651AF2AD2AE4C98B59D19388CFE6A3 +:103C7000E991124E4F43E37C00D72F3A14F2D73E1E +:103C80002B3F358F84FF73F8880EB96A87E707A446 +:103C9000CB2D946FA19016DF20659057025F7116AF +:103CA0001E83EB83FDFC77C4635E15936839828FB6 +:103CB0009B3DE61F5C9FCDFE50B4DA141F03DE3C33 +:103CC0001ACAC56AC05BF970BC9D74F1F53BE92F57 +:103CD000A42665A4FF10C8D10D52DA39A9C08BB54E +:103CE0009E91E4B345A769E70D212D7DBDFF8FCAE5 +:103CF000654B5E5EEE894EC67D709B1121FF4CDAEE +:103D00005FA79C196E07C974CE7806EC1EEC76B1DD +:103D1000F275DA592F1E96B0A967152AAF3D4B8769 +:103D200027EC8B67B3A934CFE653597F3697CAE99E +:103D3000672FA172C6D9D154369C0560C0C4693CB6 +:103D40005B4AE5CCB3575039EBEC782A679FBD8AC4 +:103D5000DACD393B89CAEBCE7E81CAEBCF4EA1D2F8 +:103D600069FF18EB5592DF96FCB2E4BB537E5BF221 +:103D7000EFFF9AFC8E355C94FD03FAEFABDA79E441 +:103D8000F748F202F8FA3E2D5D4EA4F4F3FDDA672F +:103D9000E0EBE3824F817FDFC3388C07BC388A5366 +:103DA00085799C2A606806E669ECC326B0A5FED238 +:103DB000C8498C1B342FF0E831807BA05423F9B420 +:103DC0002DA8D1B9DB66491FCDE5413281F4B73367 +:103DD000A4D178DBFEA878317FE1A55105019CA72D +:103DE000DB2FEBD8FE5BB9C97DB7E039FE14163E78 +:103DF00004E3ADD8B3C793EE87EF47E300E00BC40D +:103E00009E660CF87AE3A8DF2DC5F97C5319C563CB +:103E1000A03433E58B7DD32DCEA7D5A110E269ABBD +:103E20004F267DD0AD7B441E6A72A005FDDC3A9919 +:103E30006D8379378C7E670B82AD8E2BDB5106F557 +:103E40009D75655EDCA4A75FF92044F604BC435071 +:103E5000A04C88D2CC81FDE9F4868DF39DB729C6AC +:103E6000D03A2456ECEFAE1EB9DD26FF4008E9A398 +:103E700063D2E4CA5B60FEDE4905A371FEED3547FF +:103E80006DF850747B3C45C18023FAE175498AABDB +:103E90006D908D1D65B0BE80C8B706302B23697943 +:103EA00007161C4A18D6C1E14A287C3DAC009EE7A3 +:103EB000D6256249BE5E13E3AE3E5F3284FEA25257 +:103EC000779AE26D9DFEE422AA3BE0B0C6FFAD66A4 +:103ED000E50570BEF109BE699EF4ED4594475EA507 +:103EE000D1BE75BB8616603DB6D6C51ECF10BFD9F4 +:103EF00020F8795BE5F9E332AACF0E47B7D7EE2F6A +:103F00005AF0BC2F4A271CCDAEA15199F6EFD3CE63 +:103F10007FA1757FDEF3758E903F70B9DBBE0F0118 +:103F200021CF9BA77C3B84E7E2163C9D12EC43CD5E +:103F3000E7BF0FCD53B8BCFEBCD7FB3F6DDCDF6BDA +:103F40003CAE027C3ABB1CE38C632687305EEBB34D +:103F5000E2D1E138E52705301E4DBD0CD243AACE93 +:103F6000C7505496403E94B33F4CE03E29D59AA1A9 +:103F7000909CCDBCEF4A7813E5B539F9D3829BFE0E +:103F8000260BD381CE0FBD567CDA5027F3FB1218D7 +:103F9000FF5598753ECBE3D3567FB542A6783405DE +:103FA000B2D3C651410FE3398E8271EABCE1F37F8F +:103FB00037458FF6F98B787C5C51B91FF89EC4F1B8 +:103FC000117B55A17CCFAEE7B97C63C719C9EFAEB1 +:103FD0005A83CE5576C0FFE83FC46A7D71A45BC5A5 +:103FE000918F77A6727A08E5A81517A7F9F8F90056 +:103FF000C5B9314F91E2E606ABC0F7DD02346B1C68 +:10400000D58ACB57AE9984EDFC06F33C07EBF3D78A +:10401000B1C425006FD0DDBAF5F2D20CF1F0CA358B +:10402000DF7812E6DDFDD4F45F3D09F55D72F8D569 +:104030003A6897FFE53AC2AB331EBEAD523675946F +:104040000F3EDF21DC57B0A1892E6EED9162F83C66 +:10405000DBE73BC8F7BB35A4205E404F225EBCCEF9 +:10406000BCC8747C97211C3B07E6C1BFBD5BE72D34 +:10407000C379116ECCAF5CD15BAFA19E092EB19F0D +:104080005FF89BEC756F951DCEAD62FF2E44FFCEA1 +:104090003CC41E73DE22A4DB33418DA1BCD9B8F62B +:1040A000EA1B49EE6F57D8B8D20CF4EB5857A7E685 +:1040B00022FDDF6DD4EFAD40BDD1A0515E4F77DC66 +:1040C0001BC714EFED75A973139BFD6E68FC1CAB49 +:1040D000464EB833D9F1E27C2C209E31C73958F7CF +:1040E0006C99EC9AEE1E3E8F355E77DD5B1E941365 +:1040F000238DFBF418F3881BEDA968DE45DDBBB802 +:104100006FA38BD3F5142D2E95A23DAA2F5C04F539 +:10411000CDE364B28798F0FFBAAFE5E7890F6B860D +:10412000ED7EC5A6292BC96EB8C9AD0BFE02BB70CA +:1041300042EABEC501AFF9821B9EABCFC148600FFA +:10414000BC971BBE11E9A231F811D951B716C93A73 +:10415000D2D78A3D8DB4AECDBACC1268F7AAAD6481 +:10416000A436B15613CF03305113E96E0EBC91E95A +:104170005E44F25027C039675CE1A46D507317B5F7 +:10418000521E4BA321911F761D6006E5414B7144E1 +:1041900095AAB0DFFC77D0EE9B132C95D1DFBF4EF4 +:1041A000650D5A9A7D0E76F13177DABA4E8CDB13B3 +:1041B00094AB707E9807E75FE4A1FB046EB48FAF09 +:1041C0004CD9C71311916976F2AFD1A8C478465182 +:1041D000E2F794E7FDFDA48CF3B21758F536E993A6 +:1041E000FBD5E05FFE12F733CE8C7E4C35FCAC7114 +:1041F00089AF6B629FC4BD95C39EC86F707C2B1E38 +:104200003051E3F79B37B7B0702C2DAEB2F9F93FC0 +:104210003F8EF6AA157F39977727E0B4E0DE24B108 +:104220002CD2F39EE81FDCE97E314B96CD9DF0F950 +:10423000C19D215FCE570BFC3456F04F5E6D851744 +:10424000E5E658CCF7C17D68E7F2C484FFD2F37D80 +:1042500014C17CC1706BBF6C0C974B8AB837057466 +:104260002DA11DEBCC075230EF67E270B97140D041 +:10427000FF251E91FF33994DE67EB8FDFCCABF9421 +:10428000EB7DD69A97F11EEAF785DE7F51F8950906 +:1042900071AFF1A8B8B7F8F23A83FCBC57D65552C3 +:1042A00039B02E4CCF5F5B574765EA7E159F375F6D +:1042B000D8612A06D5F09CDFC7E206C0EB1FB566C1 +:1042C000A014F9BC8EDFEFEE6E3AB5A59CEC467EED +:1042D0006EB1B9A83A5188FE0BC09A0F7597AFCF4F +:1042E000C3EF79998395055CCD21DEFFABCF2B9C85 +:1042F00074A15BFBEFD86F1F6B6528EF02A67DBF33 +:10430000B3C34EFF86EFBFABE8E2F6BD17FF01FB7C +:10431000F8256BDFAF6657F3EF335C9C3C463EAA53 +:104320001472600CF0D301F0E7DD0ACF57CFE779C4 +:10433000AE6688F39BA9F27A6CBC68EFE224C406EF +:10434000F2785E7B313F4FA07E98578EEF312CF98B +:10435000028F6FB11C91FF3E568CB35A8C3BB19AC1 +:10436000EEEDF2F37FD6A763E96349AAE7021F6087 +:104370001964AD1222730C1B247FBB581AA2BA21F8 +:10438000E959582F93C265DC0F8F93FE2C57CC6FE1 +:104390005710F223328F172517933D097A19E562DA +:1043A0005C8D2C42F9B2A14D0B0326CEE5C9E1FD8F +:1043B000392C37F4D50CE0F9472C2693FC519E6339 +:1043C00059FA9564EF91FEDAB03EEF6036E56B2462 +:1043D00029CF7DBFA7D4A6A726FA165EA7C37E6DF8 +:1043E00014F9742EE8CF32E49F5AF974306E49A65E +:1043F000F756B9D1AF2DCAE4F73FEC91443C2339CD +:104400009AE280625FE353E58CF719F779B85DF3C0 +:104410006869667B9AB10769BCFD1EDD316EB285A5 +:10442000EECFE83CBE91E53229BF66631BBFA76FA4 +:10443000E16F34D8B5680F6FEC9B3F1BF93B56A971 +:1044400052BE39ACDF87F87389BCE48DE38307B3D0 +:10445000795CA214E5743FE2AF360D7FC1954D88BB +:10446000BF8E57797E2FE8731FCB906F68E1CFE541 +:10447000635FCCF4DE2A3B46698B32DD1B3EEAB13A +:10448000ECF46429A7138EBFAC6BD548A6F609815E +:10449000EF9232163D1FFEFA3DBA6D5CEBDC571908 +:1044A00021DE25F91214E79AA8713B63C3628ED707 +:1044B0000DCF5F733C9A760EF14B1C724A2A1E6C2C +:1044C000C58D2DBDD9EE89FEA367544A5FB2EF3387 +:1044D00092BBEC05CF41DCB70CE710A73CB519CE79 +:1044E000217A2EEEFB2E6305DF1EDA72741ECEF3E8 +:1044F00057758CECABC0337CDE5C9DC5E552FC4E41 +:104500008129619CE59A885E8FF69BAB9D99983FC7 +:104510003356C46D0ADBFB14A48B20EC65A184F731 +:104520009A9231FC9EC9D8DD8CFC44B570E6AAF5A0 +:104530008610A569F9510A1BEAA7F5B56BC6E3A574 +:1045400004D64F513F8C11EF03ED337F8572734CCE +:10455000244A79B8D02FE647FB42E0B1C0CBF976C8 +:1045600079435892A07D3098A4F8A453AE8F01FCF3 +:104570005C9266BF05449DADE2725A86FF50CFE75C +:1045800047EC727B9CE35E74C091F792EB15F9EEF9 +:1045900096DC2EE29B3A411D9433F9E529FDEA8031 +:1045A0000F655875AA7FC0AA7F46F88010889E2D97 +:1045B00078F02A25CADD3D2EFD2B4FA17EAED7789F +:1045C0001E99B82F972DF0EE438719DA0D4C79C557 +:1045D000C47DDD11E6DFA53933751EF9A1D975D685 +:1045E0007D3A7E5F19CA18C6E9B2C5FCD6BDBA6C61 +:1045F00066BC590EF4906D26E95E9D6E7D57C164D0 +:1046000009CCC3D17D32E5D1E9BE08C9A79E051EFC +:104610001DBFF3A1897B7A2E717F3CDB3C4DF7EB0C +:10462000B287AD8FDFAFB3E0CECEAA7AB3DCB0CD28 +:10463000B31EE3DBB0F6D119EFD7D5713F29DBE428 +:104640007188B4F1E97EDD8EA965B6FB75340FFA89 +:104650007182FEAC7B764EB8CEF5ABC96CA74D0827 +:10466000DBED880BDDAF7385ECED775C203FEB1362 +:10467000DFAF137818D6CE610FBA2C3B7494CC7090 +:10468000FFCE34C8F41D91DC8F92911912C52548D4 +:10469000DF5B765E1E1FEABF9D9D9767E5F53BECED +:1046A0003CCB7ECB9D6DC7B7D3EE735745A8CFC526 +:1046B000DA79BBF01F402F0F791D765E5366FA70D2 +:1046C000CA8B7C36B8FB4A18E768ED8F14CC57DBF1 +:1046D00095CBBF7FC486F9076FCDA07DF1F1EF1DAB +:1046E000ED9AD2AFE2F76F7EB794919D64C511DC6D +:1046F00002E65D45F27A0ABB773D44F8090A3C348C +:10470000E107C86A0857F171C467A617F316F29B50 +:1047100018352AAC08D3BEE3670964BAB4155351FF +:104720008FD72356D2F034C363FF4E40A39EEFD8F9 +:1047300047FB3E9F3B077F907F4F618E61DF77CBCA +:104740004F427316E7BBBED24E0727A4C8A0025D36 +:104750009ECE2A15F6CFA08EFAB27BAD8BECC68723 +:1047600096946DBD12FDD5A0ACF3E3C8A171681F8E +:10477000351F35BD68E76D8F4CF78E83F70F7528B1 +:1047800061340F9F5AB2E655ACC776BBC80E7AAA01 +:104790006F5EC18A34BEDBBC7BC1C2C5F8BEC345F7 +:1047A000FA7DC59EFB064A83D8DF559BFEBDA996C0 +:1047B0008DF7E9E8B7BD51EBCD68C75C9DC5ED92BB +:1047C0008D5A92E24F1BE7690C5DAE8D25F5A3571C +:1047D000A0FD708D96F13EF95D596E7E9FCFD52A72 +:1047E000A17C2F8C66BE1760B51B5BF35B3AC708D4 +:1047F000CE9619FA71AEEBE7C9587F08F655975275 +:10480000F49427E86963D1BD5B2B707D0399EF1D9C +:104810005AE5DAAC719C4E23763E7715368DC67517 +:10482000BBDC91817A24AE4259C7B888CBDD1AB976 +:1048300019EDD1AB5D48E16C73C70F1B16E1BE8467 +:10484000255D8279826A6415D159308BA13E685802 +:10485000126945BC1482FEC3D05E61D12FE99CA2CF +:10486000B04E635EA87B96F4245CF0DE5311BD0A63 +:10487000F1FED25AFE9D97C2A08FEE051546F8397B +:104880005C61BB9BA1C9B0115C6017F90712C589B7 +:104890009C7C64ADAB792997E3BBD7FE7654A6EF39 +:1048A000CD546495115EBD867DDD1ED4BB30CE54E3 +:1048B000737009E1BBC6CDE2C4BF6EA2EF5DB52E39 +:1048C000826BD794935F41B87EF7FB2CDAEF6B993C +:1048D00029215CF943FC9CD59A27BF6950E1F1700E +:1048E000CE874EBEB3F8C109DFCED9F3E83C6E33B4 +:1048F0001B9C8FF88E9D95898E3617ADF1A6C74506 +:104900005B05FDC13E907C89E98CF65BF957B61ECC +:10491000F361377E315289FCF1B697DF5BBD6FA939 +:1049200046EB7868AE46F1C687FCAD44F7A736BAC9 +:10493000C287101C555F88FBB9BBB8228CF1B6BF8B +:10494000C3C3E734FF60F7A82F55223EBFF8872C7A +:104950003ECE14D51AE76744EFB55E827386D2FE69 +:10496000B31568872E912753EEF4AA2524BF5C4225 +:104970008EBFBC24AF1EFD94C00DCB1997873C4E53 +:1049800011585BCDEF3338E47EA24EDD3D8376894E +:10499000C77FEA85BC1B7BC3F47A5C67BDD00BA6DE +:1049A0009AF9BB8CB9A27DE150044DB261F19F5CD4 +:1049B000A13FC6EE763C177A2177581C7CB0E266A0 +:1049C000903F5FCA1276E408719F5D4BE6113F9CF1 +:1049D000017EA0B874C949A2FF18C809B49BDF9032 +:1049E00092A11569E761D677E67E22E24111B39480 +:1049F000F284DF12F1A09F8AEFCEBD23E241C745CA +:104A00003CE8E7221EF40F180FC2EF87792FA77D2D +:104A10001B57F7513FC67176D62CF01830CE547D17 +:104A2000F02504F28BE6A04FE4DF13BC414B0FCD21 +:104A30003D7F9C2A8170B9312EC5E17C597C8FEE77 +:104A40001501D78080EB350197A507516E209DB1E8 +:104A5000B1AA9E491E06D55609CF7B515EF407497F +:104A60005EF03CF1E01AC998305C4EC078A3D3EDFB +:104A7000748BFE4E8DF2111D3BC77F348BDF3B7C68 +:104A800069EDACFD2C98268F220B5721DDE5C3FE86 +:104A9000A03C8A3671391EC57B176972D58AA7C1B9 +:104AA0008E8449EFDCC0F134927CB9905C2974C8E3 +:104AB00095DD2857A0BE1BE54A305DAEB4F6E3BADB +:104AC000832857584A0F05239F4CAEFCCC5B668B5E +:104AD0009358F2E56A6063B213C3A04FFD9F5E9FD7 +:104AE000BE2DE4C485F4AA95FF113019E9F53D986F +:104AF0001782FECC7846F770147390F28972DB5DF2 +:104B00000CF341B66297D1E8CF2CA47C901DF33D05 +:104B10003AD2C5C3522284F8DC27F578F9BEE8FD05 +:104B2000682F6C9BC0E3243BFE788F17EDEC976EEB +:104B30002F08E0394E6FAE9507A22FBE15EAA71ACF +:104B400019D1C98A3D2B6C790F3FCFCA237CE4C6AB +:104B500040FE003E1EBE9DEB1FDDE079205066CC7E +:104B60000371FB443C488D85903EB649510FC561A9 +:104B70001A65D253BD619EBFD20B7E399E0FF636A9 +:104B8000EC9C83FA79C3AD32A37CF1CA9E7B50CEF4 +:104B9000744C5868205FBA4697BD89E6F8069FECCA +:104BA0004DCF23C5E304AD9A9F1B8AD2CC01903729 +:104BB0007B4DE37CF74755E1F7617FF779F2E03B06 +:104BC0007343A3314ED0DBB83084F3F68E8A84F27F +:104BD000283F650CD9031B476D5A8CF1A78EE51A47 +:104BE0004BB79386CD17B4DBD7569C516DE0F923B4 +:104BF0001D32F72F73C5F934F05525E22D7D9D0840 +:104C0000A76AF2FC115CAFC2D74BDF37CD6D00FF56 +:104C1000B08AAF1FFD57DDA78F46F9A136F0FC9192 +:104C2000CD7E7D31FA8D4E38ACF1AFCD966CFE91D4 +:104C30006EE52DD4AFE1E788453C6FA1D775FEBC8A +:104C4000850E210F2DBF71247CB81CE7D4BD5E7B7F +:104C50001CD082E74A513AE118295FE0D3CE7FA108 +:104C6000757FDEF38D9447B0265BB2DDAFC8B5F239 +:104C7000591AD784504E58F06CBE40FEC8A785AB79 +:104C8000B991B7FFBCD7FB3F6DDCFA6CAE1F814F0B +:104C900007F01E65C7C499219443A978CCD0403948 +:104CA000DA73E23EA3953FE2D2F93F55957FE74E96 +:104CB000CE2EA2EF2CABD379FE08FD65C803D9C474 +:104CC000D86CF4775411BF71F2E985E077E68DDC9A +:104CD000EC137E63D4319FC813618EBC1335C4F3CB +:104CE0004BAC7C922E09D6174CE5838C38AF036F02 +:104CF000E385DC7FCFD17FD8BAC3FC7EA5957F3218 +:104D00002C8F64AABC1FB760581E89C847E9C935F3 +:104D1000E23C4F9CE795A0DAC478DEB03C92A9D380 +:104D200043F84DC96925A2DF0D8CBEBFDBE3E5F575 +:104D3000DE392C8EDF3BEBC53AF2532DA3BC9661D6 +:104D4000F92553D7109E341659C6CF77F879BF8509 +:104D500007677EC905E9ED027924419FF53D8A0880 +:104D6000CDD3E30FFFA48EE093E93CBEE04BC7C375 +:104D7000E9E35FE2E372B247E4E1F5E4DAF3F1EE8E +:104D800013FB5221DA39F7572FE274DD55AF53DCAC +:104D9000DDDDC0E395C3BE035163F7079CF1BC138F +:104DA000425E5F68FDCEB8DEB611EE9B2DF0F13CA1 +:104DB000AE87961CA2BCD833AB40CF02BE1EC67CC9 +:104DC000969A8BCF67793D8BE7B3F41AF50B2F4595 +:104DD0003D16D518CAD35ECC6781F71B1A46C86743 +:104DE00011F1442B3E3A523E4BEEB9F3787B3E4BE9 +:104DF000EFAD3C9FA5B787CF638DD7DB504D76D6FF +:104E000048E33E3DC6947DB8FF1517777E3AAD2442 +:104E1000F26798BFD253AAE90F1A482F9C9EBB1A7B +:104E200035A2EF2E17F76363A3B9DFCCD4786821DE +:104E3000B4D9E24F2CA278B2C8CBE815F7E7FF3E11 +:104E4000CBB0D9C79D8DDF0DA15D0F74F8B2CEF93F +:104E500084C6C9574BD7830DC8DC7A8B893EE540A1 +:104E6000368F23B842C706EAD2E8748BD077881F02 +:104E700019F0932B9DC357542EA0E83EFDAD11F4BD +:104E8000F946369FDFA243A64E0AF3F33F568172DE +:104E9000C4F25F87B5F3F076C3E48F438EF4607E8F +:104EA0001B562C797283254FEC7469C90FE6903339 +:104EB000E7E4C91C6EA79F9327203FF053674E3944 +:104EC000D4EBE5FAC282C78D8219E4C87BAEB02D5F +:104ED0004EE3943B17E2A3CF5BEEBC949D2FEC0F07 +:104EE0002E7782481BC837D9D63922BFF77066EAB9 +:104EF00083240F3D2A5FB727C2E87702B08EF2DC29 +:104F000083E72819E57AB544F106712E922FBE3F4A +:104F1000F8B02B4CF9690F033FA39F37C170DA67D4 +:104F2000E73F57709E273DBCF66BDC3F037CA3DF59 +:104F300075B172C892131F66F3759FA32F93C3694F +:104F4000D1571A3DD3F7052CFAB5C6B5E898218399 +:104F5000169C875E055D63389AE2D431298E711004 +:104F60002B8FCC1AEF0D1FB74746BA5F65B5FB8E86 +:104F7000E5779D8B07EB019DF2C97AE8BE39EBE23C +:104F8000F43787ED56D754513E81CA289F2052826C +:104F9000FECC619FDD2FB6F2C1A69584432827364B +:104FA000083BDDCA23B3F2D20EFB72AD73665B7EA3 +:104FB000DA8611EE67BF790E3F17FFFD13FC6EDB3B +:104FC0006AAFF938CA45C09729BEE7447968D6B8B0 +:104FD000DF15787ADD633EE9FB0CF7275FCCB2E79B +:104FE0005D75FA0C475C80E375A21EABA7FB785198 +:104FF0007EAFCA79AE3ED2FD57E7BDBD73F75FC540 +:10500000F97BB327FA32C1FF22CF7FD3C3D1839D6F +:10501000ECF35BCF01AFF9131CBF53F0F7B420BF23 +:10502000B7F3BE27FA363EBF8E71BFDAB2730E6396 +:105030003BE8EF7F19A436D0CBA65A4EAF45958CEE +:10504000BE3F3EBD95D7772CE5DF35ED7F9DDFFB7D +:10505000D816E5DF33857E7D32E065C778AE0FF781 +:1050600057F17EFBF17E13F26905B7BBF2307AAFE0 +:10507000A0B88E5239BDA6C73B01DE1F582A535C2B +:10508000748FE08B003329CEB1AD92CFB3AB427EAB +:10509000427C8F66D12D50EF9CBD7232DE2FD92E0F +:1050A000E229FB16AF7C02F3FA3E08940BBA4BD010 +:1050B000BDD79EE3B7517CE4A12579D24A58E3BE1F +:1050C0008399F35BAAFCAAE817738B789228131ACA +:1050D000965B4D91B7DACAC4F7D8631AC69F9E197A +:1050E000E479ABDDAB9F393613F571A54C79665D7C +:1050F0008347BD97E1BAEB785E4F919A90D2FD1746 +:10510000AFDFC5EDB49AA31EA36A78FB67068F12C2 +:10511000DD6D07BC2B69FE9F2CE0EC467F02FAEDAB +:1051200075F50CCC84767BC7E5493123D56EB49FE9 +:10513000F35FF712597C879ED1771C3ACD531E94AA +:105140009B9D78FE01EDBB6BACBCD41EBA97B577C6 +:10515000CEE4399827BEED061E2CED0A1F223FB97A +:105160006736B7CBF64AD00EF6655F8B763DDD63CA +:105170006AE571222833C6897A311118F12ACEEDF9 +:1051800028F505E6ED6CE81BC0798AEAF8F72D8A68 +:105190006A32F77F21E0A6FEFB5C318A7F8EB47F06 +:1051A000FFEAE3F8ECACE2E7058CC5292EB55BF825 +:1051B0005D4C8D1AE9DF096D0970FCEC743113E365 +:1051C00065BE3A8DF4BA1C36C80EF583FD88F1B879 +:1051D0006D526C31E687C42669EC71C288E91D877F +:1051E000F1BB097961A4BF4D522284DF558E8DE356 +:1051F000F1EDA3919D74EFEA00D8D1140E6609D2A7 +:1052000053DDD13CBA0F7534523D48FD7D15BADBF4 +:10521000D22898374F1F8A646CD2659BB6A25DD3A3 +:105220003945D6316FB353AA8FE278B15C0FC5917F +:105230005D53E6D1FEB946E549E9FAE8463FD70BAA +:105240002727446EF4C3BA42534EE562DC727BED0D +:105250002BFB70FF1EB9DF4374F448EDE0DD38CF5F +:10526000FEB3571D8F125FF2F3BA476B4F97A2DD63 +:10527000B3ABE9542EE2AF18E373A00F8B2B781C6D +:105280000D3520D9676A0FBB19F058DCA631234DC4 +:105290001F7B193FCFC33FDF64927BF4F7CCE0293B +:1052A0004F0B8EB784252E0DD0730FC6B32C3953F8 +:1052B0005CC71205200FF7AF78278679728F4C2CC8 +:1052C000A07B9445E23D494E18AF448CD7FFC62BD6 +:1052D000EBB1DDA3D50506CA8BE281A179A8248AAA +:1052E000AB4E539C2D64DDFF881AFB6F25FA94E9C1 +:1052F0003B95C5E177FE02D711F0F5919E83F61438 +:105300003773AEE3E309E67D88BF6F4AADAF8E0B1E +:10531000A6FC31FA437EBC97DFCB2ECEFA87B94A82 +:105320005ABE6D89880B6C920667935DFA00B7C30D +:10533000C7B238C9B9E2AAD8DD3CDF364AF9B6CEE1 +:1053400079B7FBCFE95789EE51E737897B25FC77A1 +:105350006C4AC4EFD838E93E14CAAFEAB82A55DF20 +:10536000173D45F4FFB466DC95E97B0FFB845CD800 +:1053700024FC316BFCB1B97C7CABFEA8CEE9F1E931 +:1053800097F3AEAF82F5FC555BD9248C7FEE18C144 +:105390008F5B19E0F4973D00160EE881FED75EF3AF +:1053A000623ECBD3325B8572AABE2AE14956093CE4 +:1053B000C2F8E48BC1F807C2DFF6A05CFA6AA092DB +:1053C000E05A3195C70D3AAB1EA473A090CEF50EEE +:1053D000F227CA775F282661DC7B790DD30F8978A5 +:1053E0004B0CF04F77E76596CAEBDF9E4B7E0EF0D5 +:1053F0000ABF5783B94993C5EF4F94E339D1A6BB90 +:1054000045FEAC8CF8EE14F300DFD23C078AC438BA +:10541000F771FB1FFD0BEC5F2EE629AFFBEED750BB +:105420008F17E99C2E52F0F57908BE5699117C6AC7 +:10543000E255F443B74F2A30906E0E84C26F374165 +:105440007DF92295E2F1E5351C8E03AD32FD1E900B +:10545000BF4E3B48F7C74CD01769F832C4BC45353E +:105460000909CFB58C56BE2E68E745B96884011E80 +:10547000A81B625DE7E09FA411FC459E41CC2D3A3C +:10548000878795381ED0EFCA3ADECF1FEADB8272DB +:105490006C791D871BF43BC15314D60EA2BE2F0A94 +:1054A000F1F196037E0E4929B8B22DB8EA64CABF5D +:1054B0002AAAD10EA21F9C2DE05B19E6F0F4BF7E54 +:1054C0006A40E2E319385EB680375BAC9F12760B18 +:1054D000847E80F19E7225EAF15ECEA929CC38C483 +:1054E00067A37896F57E572BE001F0E317F3B0DD64 +:1054F0006EE2275862EC6399FF7E889116B7A8D8B0 +:10550000ADD9EA7EB17FAC8B3F273F8E5422AFCB23 +:10551000C2AF5B5965EFC76AD2EA6578BF8CD3FB2F +:10552000FA6BF979C78109DC3E42BFE31C7F239DFA +:105530004F311EEB0AE27B8DF45D49BB7DDCE2D688 +:1055400082E9281F8A071E9E27C37A8AEE65B292D7 +:1055500043F42C9D937F30DFB7D724E8FE6CF640F0 +:10556000240FE55D496BDE74FCFE5BF64094EAD9DE +:1055700003AD26CF3F0317260FF3F5D2E6294539B1 +:10558000CDF3E958ABD68772AD361D4E785FF27217 +:10559000CF5CECBFF9EE574623FF1638FA7B72B8A2 +:1055A000FF50FC32B40AE0FCA7D7627B2BBE938D80 +:1055B00010E751F93296C53E90C7509688FC3B4B98 +:1055C0005E744E786752D427E887F2F15822DDCE18 +:1055D0007796D07EBC681F93CEDBEE34B51B29DEF8 +:1055E0003410E0F1A680B0577B98B19FF47B0DCFCB +:1055F000F7F0E173D01F7D3547A7D37EF6B130D2E7 +:105600007371DB9FDCE9F2FAE640A9B8079D20BA86 +:10561000D74AB2E87C0FF898BE6F7A406DA573D672 +:10562000BE227EAE7974CE2B12E2B3E8399EA76D0E +:10563000D9CBD36B12217CDEF56AF432E2CF11ECC8 +:105640004FCBDE74AEE792FA07491E8C8D322F9E47 +:10565000AFF957AB94C75A1205B8AA502E00491794 +:1056600002FC35B1F548374694D78DD5A25C05E5E7 +:10567000D560DFAE1B28FFA52B35EED60AB06BD167 +:105680007E1ADCEDB901ED9556B0460CB4174F7992 +:10569000F07B2ADDADD3F311CFCF442CFB3221E1D7 +:1056A000F8453F35C95EACD5351DE33013DC89D1F3 +:1056B000E9E77407E6BC534DDF139B7F71F9642360 +:1056C000E91384454ED323FD554749BF3CE11F4FA5 +:1056D0007AC8D22B961EA11141BEDC22F8A8CB4875 +:1056E00078249257C0BB00E72D2847808EFD455C8B +:1056F0009E831CE672CED2277773BD6FC9CF0A3165 +:10570000CE2D286FA15F77ED13B937A05C1172D64B +:105710001F3266E2F95C8590AF4C8D4938DF8129F4 +:10572000FC7B9501873CAD68E5E3748518D113E8EF +:10573000A1834837078A12744FFC40EB5129FD9E24 +:10574000A9A5EF02AD4986FB3FAE8ECBC17142AE3B +:105750007EC76F70FAF470B97A4EEF0979BBD53C09 +:10576000CAC4776133E661FDBDD0E73D1587C82F18 +:10577000D876EB29C2A7150F0D89786877D55BF429 +:105780007E7B94DF03D8654E9F43F047966B947FF2 +:105790005A73744E19FA1B4DCB35B4EB4E060AAC56 +:1057A000F32FEF42B4275B5791FDEB13FBF85098B2 +:1057B00009BF53233FEBBEA5DF1EC0FE21F08B24A3 +:1057C000031BF579DC48E7F83D05C47774903AFB94 +:1057D0006A0CFA0E84731DDF0BF0EFD2FAA3C981B5 +:1057E00071B4AF325DE9F1D530F23B97835F87C387 +:1057F000EE56C3DE09F07E7793ACAF67A9FEFF2BB0 +:10580000C0F3D126FAF93D859D8B4F6FC138DFCEAD +:10581000A5E23B670EF8EF6BECF328340FC60428C3 +:105820008F39E3F7F6ABFC59FCFB0B357D0368CFF2 +:1058300007AA385C2F060C8EF7418EC79E884C7CD9 +:10584000B46BB0DA8BFACE69373E92FDEE249ED768 +:1058500062D73717AA173BE4FE0477DF7524EFBE43 +:105860002993BC628CCB3B89C906FEAE464B80D3E4 +:10587000539590D71DAEC47ECC2BE878D6C7D61BE7 +:1058800029BA28126376B6CA197F3FED5040E1FB72 +:105890003F7CDFB9FD20F6FD4981870BED3F86593E +:1058A000D09EEE8B6F1A7307CAF156EE3FF725DED6 +:1058B000A2BCA3A2D90BC9EF3972F052F2078AAA8F +:1058C0004CDBEF6B668FE0B756E478CE1B0F1849C0 +:1058D0001EEF5BDD417EF6BEC1CCF7620A72785ED8 +:1058E0005A1FC84BFCBEC948F3EB399CFFFE292068 +:1058F000E86ECE3BF4BD8C343DFBB2D0B3A46F8BCD +:10590000551653D2F21C2608FC39F52753E39E4B5B +:105910006B88CE097FFBC4F9C543A64C78B7E81C59 +:10592000CF0F10AFB00E53D0219D6FF4B0B807F970 +:1059300026D6C4F33C9C704FF0CB17B5BE600EF773 +:1059400043CECD27FCF5897E0EF7CEDAFBE99E2308 +:10595000CC1742FA907EF01FA7E93ED4B32EFA3D51 +:10596000DB19CFBA1218D3BAF320FFBD45F9452F82 +:10597000C1F9CF87F9F7D5137E6E8FFD5AE7BF5770 +:10598000F455F760F717A03EF4ACC2C89E8C83E2D2 +:10599000027A3D2DE8953DC7EB2BBDBC7AE7C1FEF1 +:1059A0006538DEAAE7781EE69DCFDF76E317A07E96 +:1059B000DB808BEE0CDCF9F87A6D0CD46F8F4B7DAD +:1059C00058FFCD7446BFF719CBD328CEF59BC060E6 +:1059D000C102C0F707EB3CCCB80CE3A48305F3018C +:1059E0000F77C49F9E89FDEE784A0A23DBCE78F6B6 +:1059F000F15746035C777E43A2FCAFAF1CC9B6D912 +:105A000085A76129D3E0FD9A83FC77236F633D333B +:105A1000111F773EDE4BBF7F68E1F3837595CC485D +:105A2000FBDDB03BBFF134FD9EE15DDF92E8F71591 +:105A3000EF92F93DA27F7EDEBBE8311FAE6FBD76EF +:105A4000A91FD7B559C376B7C55BBE8B294D77C49F +:105A50000F6A33E1FD1D070E6A2BD12F73B366D495 +:105A60003F5F3972854DEE9CDEA7907FB026D7430D +:105A7000F7EB99CF0CCD9B307C9F3F58C76C70DD06 +:105A800061C509D4B83637ADBD4BE7FEEF578E2858 +:105A9000B6792C3B20768CEB85D8DFFA297E6EED2B +:105AA000DF1AE1775BFBB7C60AC4AB439333C1D3BC +:105AB0008DFB01F0F4ACD3A9DCB92E44E5EE7506FC +:105AC000EDD35EC423945D02EEC054568FDFE70F22 +:105AD000983CED38AFC9ACC7BB6579115E2F581241 +:105AE000253F64243BC62AF7BAA22DE84376EEE8A8 +:105AF0009FA582DDB3578BDE8D912FBDE3D5590D68 +:105B000050FF9B9CC8C61C92376103F9CEF2CFBFF1 +:105B10009EC3E5EEA6D11AE17BEFD2C98F2996FF8D +:105B20008571BFA52B9F407B02FA6FCF21BE0DD39D +:105B300077BA46EA5FB0ACCED6BF60D92AABFF1EBB +:105B4000EAEF397FFFBDCBAEB1CFBFEC0EABFF2389 +:105B500004BFEFFCF017344FB5CFDFBC9AFA7FD506 +:105B6000CDF77728D743F9F41DDE70C245FE33A385 +:105B7000EF73A879971EA2EF279D8B330D9AA86724 +:105B80007D4FE556A31C4BD1D1F46FE23AFCC05DCA +:105B9000E97494539765E3AB5C33CF56CF9F3DC612 +:105BA000D67E54A4CCF6BE70D1E50EBAF4E99407C3 +:105BB000CBB83E3531CE09706A63F8F79AEAC778F8 +:105BC000687DF7BFE8A5FAFDD7F0F5DD3FC6477C55 +:105BD0004CBA0BF6FD7E2D7A65BA7D0CEB9230E463 +:105BE000F58C1E1DC8A94D7F6EC8F83C4BE1BF6304 +:105BF00097E5E6FA7273E9E4C76269F8DC520CF4DF +:105C000000F5B773345B9C6773F1CA504BDA3C9B69 +:105C10008AB54587AAF8F35BD08ED7237F87F37DBB +:105C2000551BBA14ED57E73CEEB23ADB3C9E925559 +:105C3000344FD2318FBB6495631ECFA243E2B99833 +:105C4000E714D2C948F36C2EBBC6BE9E923B689E39 +:105C50005FE33CB569EB29B9C3314F165F0F3C17C1 +:105C6000F3FCE6BCEB299F6A5FCFD8D534CFBF3BAE +:105C7000E6718F5DED98C747F3E0739C8715713F20 +:105C80004A730FADA4FDFF8197611C487347FF9ACB +:105C90002EA9FCBD97E2C2D0CAC476FF07FE2263DC +:105CA00096008000000000001F8B0800000000002C +:105CB000000BE57D09785445B670DDBE4B7727DDD6 +:105CC0009DCEBE10C20D288B86D88190015CA6594E +:105CD000E4A122065770810E4BF6A4A3E23C1C758A +:105CE000D2104554D446518306A6C1A0E0800626B2 +:105CF0006880800DA883332E719EE3320B368804B2 +:105D000021260DA2E29BC5BFCEA9BAE97B3B1D604F +:105D1000DECCFFBF79EF8FDF4C51B7EAD6AD3AFB4F +:105D20003975AA9A0C4F22641C21FB12683986909F +:105D30006FE33C17396D84FC007F3F26F4CF474862 +:105D40002A2FD3085940F85F60A9408A08A9B5B046 +:105D5000EAFC4D33721643D93629A3A490FE63A5FD +:105D6000DD75BE4A4877DB24655E5E643CAD5CE071 +:105D7000978F8486B3777F2091EFF82692E175F4B0 +:105D8000FB65094E9C8F563F524FEB66420ED51372 +:105D90002C3B6532A7983E3F5C4F27304C3FDFC518 +:105DA000F8DE1189FE3385964D42C027D075ADF8D7 +:105DB000402643F0331F0EA7EBB8912F63813F9E1F +:105DC000104B641E5E3371C37BE1EDE6C03A019E69 +:105DD000BA07983268D1984C8836DFC184FC69F7DD +:105DE000D56F090EAC0E308D25E4E6655BDE846E62 +:105DF0001F092503EFA0EB9DD9BA421E40EBDD72CF +:105E000068B6CBA61B67A67C08D66DA1FFC138B3C8 +:105E10003CB4AEFBFE2DE5C6FA6D448AD47309B9D5 +:105E2000D03998E3837F570DC880AF1BE99A322998 +:105E30000A6F837214343B115FB39DEC5D6D3EDEDF +:105E40007B641284F948A15492072DA9D8CF03FD91 +:105E5000D4BEF39B2D5BDCC5149FB3EF16118ED11E +:105E6000F30DED8E779BF269D9F8B54C069F7DFE58 +:105E7000731619DB898F7D4F83AB460737CD9CF0B6 +:105E8000E4611D7DCCF25CF1E461039C6618EAB725 +:105E9000D5CD32F49FB3A8C4D05EE2AB30B4CF5BB3 +:105EA00076BBA1BEC07FB7A17F59E362437B45E0CB +:105EB00021437BD58615867A4DCB2A437F6FDB5AEB +:105EC00043BB69F7886B088563C3EF4462A670FC27 +:105ED000C676E4B18B53A0945C00F7A3F51948D7BC +:105EE000C7EA552C6B81F6C601FF8CB678289EBC9C +:105EF00071E1529248C87DFE4B962DBB84D615DACF +:105F00003E9E52BB7FE2325F3621CB9C2AD2BDD867 +:105F1000A8902025558124F5D27558D4B587CED2C6 +:105F2000DE2891E0E8BEED6228F6F31E213C348BBA +:105F3000AEC3F7A999AC17FAF279842FC90092D1B0 +:105F40007F7B978994B7E8E4CE7AA709E793EA9C28 +:105F5000B8DE49E9A15A61FC5EBD35732271403D4E +:105F600038B4CE7686EFB5D0C9A4C3388C5F2A0288 +:105F70000322FC8BF81B62E0FB61099E6627FD5E35 +:105F8000D71E7126CC8304F7E55C3712BEEF5E0F97 +:105F9000CF491B1D2493F277BDFBC9C3E713F24918 +:105FA000FD542C7F5F5FFCE46199903FD6CFC4FA2B +:105FB000817A0F96A1FA722C0FD5D761FBE1FA45D1 +:105FC000583F52EFC3F268FD322C8FD5FBB1BDAB09 +:105FD000BE11EBDDF5012C353EA0F2684E31F069C3 +:105FE00071B109F8F40E2BE17FAC7E92AF41A4FFB2 +:105FF000EE40BE7665005F9FB47D3B348BD2DBC93B +:106000004F2831E5F60FA768BAEB1F7F6E13E0AF9C +:1060100034408927B96FBB358EE1C76A2253099591 +:106020003F0F9DAF10897E3FEEF50BD789B9F85C25 +:1060300002D2A18AC335C31E63FCF308E2EB6C787D +:10604000D2FA1F79F6CF4573F3003F83914EE2F603 +:1060500089750C6FCFBB006F67839FC4F92B1A8EB5 +:10606000C2EB7FCA09D1FE5FA56AF0ECC821B4BCBF +:10607000CE597C14E8E064AB19D775B23D3E406060 +:106080000C670AD245FF7063F3A8DA60F5EBE543CD +:106090004D4BA2DF282F32FD7A797172FFF30EE0AB +:1060A000FB3B3244FFE1D1401F6E4E1F8CEEB4F13A +:1060B0006B5A72FD36C338C6FA49BF30B505E5BC28 +:1060C0009A70FDC8FEE779478682DF39B6614802DB +:1060D0007CF758BDC50FDFE9AA77FAD97733FC7A88 +:1060E000BAAC5E14EF3F9C1C995F7FE3FEB3E747B9 +:1060F000482BF9DC4210F43F0CE9BF7FBFF8904E0B +:1061000029C5401FEDF2B7A077E2866B7A47C2BA85 +:1061100036AEB745F4992F82E79B0CDFA3EFA94772 +:10612000343C0D3E13DE2572445B27959323A9EC86 +:10613000063AA5C48C78F6D01113E8783D926D9993 +:1061400040BF634E54B1DD0B1FA2F4546309291EF6 +:1061500015C1DD0176D6DCB11ADFAB37FD8192DCEB +:1061600097BF91C9C3D0FE173A3A6D9779EB7C522D +:10617000EC20F47B735BABA6819CFCF2D5ABB89DA5 +:10618000E22F82757F454C53814FBE22BF758CD65E +:10619000D965D3131536BF654C3FFBE87FB03E6A27 +:1061A000A719F47559A3B15E4AAE4D037E285D2947 +:1061B00093009D7B05E87B6DDD94EF2F4B64765C4F +:1061C00019A95B0A76CAC3329909F89EEB24D2005A +:1061D0002A276A5E5B5D5442EB37249A90AE8E515B +:1061E000FB4EA572A82289D931952901C54DDB3F07 +:1061F0006F1D7DE3C504DE0F2C05B9E6B313D77A16 +:10620000D217EEF39619E777B6F947CF979025386E +:106210005F6D1EDAB8DA3CC40D823B10C39E9D97B9 +:106220002844EC645ADE9968B45F17415D67DFDE8D +:1062300017555F1255D7E844E674624EF42C4A4C69 +:1062400005BA084F413B8D50FAC88BF45322FDEE3E +:106250003B533F33F413B1DF9233F5B346C67B3083 +:1062600056BF9AD736BFEAA3F454F9CA530E42E593 +:10627000F997923FCD459F57AF7FC001703A2AF9F9 +:106280001C80EF2F03E2D458F0DADD0B2FB74D005E +:106290003F02499BC2FDA547A6839DF4ED7AD9290B +:1062A000D22EDE0DE6A099D26F6D6BC534928FF5BC +:1062B00083ACFEE00911EA6D467C56BEF8549A6A3A +:1062C000473C307B9B04D1EEA86DFE620AC8712F5B +:1062D00009231D46BF07DF3F9D847C5FA224F46D28 +:1062E000A7F3443BD9CBF9CCDBFAC809D101E515BA +:1062F0009DC067DE283A2AEFD52F21A598CEE795D5 +:10630000447BCA910B69F547E447200F34B89000ED +:10631000B32B1A363E937F90CEABABF9370E214F9D +:106320002F47183D9E6C99F7F31D6AFFF2A69BFB61 +:106330004591F702F89EDAC6EC20D2CECA6A39E857 +:1063400000BBB37AADECA2944AAA373FFFC2B3E0D8 +:10635000AF7D6A467FAD6AF39B1F8DA7F5AA2D72AC +:10636000CA34B61C9B9016C18F97FE6FD1A8083E09 +:106370002A7FF9A6A28E64CFEF4D8AE0A56ACB1ED4 +:10638000858CEC0BC7492D7B94902D067E5A0E4EC2 +:1063900001BBA561E3770AF85F5FEE16487A6EDF0E +:1063A000F7CBD7BE897A11E084F8E4F8EAC55F1F1D +:1063B000BC05A7EF28C47E4E909767C39B9FCBE98F +:1063C0009AD7EC2491CEA3FCF7E6C034C0E7CB7794 +:1063D0003A603D9D521DA3F3D50FA4B9E9F7CB65F3 +:1063E0005F9A134BF6BC7CCD5D487F65425D9A1386 +:1063F000F9C99D6942D9EDCB84752E68BA01D75988 +:106400004A3C4887E5ABC5E2002DBF91C8D42D3189 +:10641000F8A42889F149E73A8A5CBACE4EB0FBC1AC +:10642000DEFEAD18588FFEE9ED04E4FF5D7CCD542F +:106430005362FD1B0BC3972DC9A4F98B1603FD36C0 +:106440003FD801783A36D09D0EF3A470F071B809A8 +:106450003FD071C50F2E4F677822AA54C4DFA3FA2C +:1064600060123C87FE1DB2DB9A6F788FCB4FF6FD32 +:1064700085FCFB74DE71A0DF3AD3A87D1F637D73BA +:10648000617DA817A99ED3D1998EDF19FF373FC42C +:10649000F85DE3FFC08CA9D07EEA43C647F01EE852 +:1064A000133AAF603AB6EFB95E40F96026C1587C46 +:1064B000DE2C733E37B67B29BF429C40A3133A7F44 +:1064C0004948D0D30BFD4E12E201FD95D295F47DE3 +:1064D000BD7D03DFC57E4AE4B94EAF9471B95090DB +:1064E00044E5417C441E90A6D473B223AB65E2031D +:1064F00093B3FA5333FAE3D59BE56258FFF14DFBB2 +:106500003EBA99D2F9F1168D6F8D72359A6FCBB76D +:10651000AE17804EA3F9F67839D5E2B1F8963E8FE2 +:10652000C9B7E5A1FFA7725583DFAC24A33CA5F250 +:1065300071109810FDC1315A3E7E03F6566A5FF91C +:1065400048FF3E24457DE950A33F8DEEA80537085E +:10655000E47A2F7D6AF4D74B9F1AFD45AFD708BF69 +:10656000E8F6C1E023513A29DE4E2D3A8ACFEA7689 +:106570002160463EF7BD35A010E1E446F546FC6FCC +:106580000D48D1D70351F596A8FEEEA87A71547F35 +:106590004F54BDCED0BFBA6D9F4210FF41433FF371 +:1065A000A2E7C8E731FC414DFF785B4F283EA08B46 +:1065B000ECB002724F5E424D3788AFED1231BED65D +:1065C000A3861D49F4F90356E6A7F538793D91D520 +:1065D000C3A9CA52907BDAF3B095A07FDE531C7634 +:1065E00024EAFCFF83EDA243A5EDA10099AA8F2325 +:1065F00044E6D380F80E91FEDA59DCB027CE918FB5 +:10660000DF8BCB0900FD5D2EDA721681BFE7175DC7 +:10661000947CC8FCC5373908A5B39EF621D7CCA415 +:10662000CF17BC2D82B94DD1E3963229DDCCE3746E +:106630007C94F89EBE84AE6F5E3BB3C3E72F8F4D54 +:10664000F795BC7FA96DA102F295DAD187F471D1DB +:106650004AB21CE9AEBC29EA79FB55C81F9551FC2A +:10666000E1E1FEC32E8D3F0A4801CA174298FFCBD5 +:10667000E5F2E562DE3533291E7AF68BC4AC823F43 +:106680002B92A5B0CE4D4200E205C4978A7C564BB2 +:10669000C2280F353875011F0DEB5F4E756DFB532A +:1066A000D13D402FAFFE21FF395A76BDFAE9D09D8A +:1066B000507FEDE39C3F90BEFD27EDFE7E36E8B3B4 +:1066C0009EDD668C8BF5ECFE55CE3D50DF61C6B885 +:1066D00058CF12B31BF8C0B7DB1E381FDA0732FFE2 +:1066E000A161D777F921D4AFF723DE8E2631FFE5FC +:1066F00064FB9F0F082950D25581FDB03B1EF9C89D +:10670000BBC38AFE7ACFAEEF8A3CB67FDE7A6A15CB +:10671000E2417AB493995B817E1359FCD8BB73DC58 +:10672000F38BE9F76B5AF728F368FBA4D7FF9A0FAE +:10673000F2B3672BB38BBAE5D01AE222E4EBA4B232 +:10674000876488F301336511F278F2862B7C79B186 +:10675000E0C2E0D043E100EBA2702907B9DF1F3CA3 +:10676000E29215A4F77F3D789C98CDE4DA8F08C4B7 +:1067700085227011DCECB93D601170FDECF9EEEF93 +:10678000F241EE1C6F598CF6CAD9D63D22F95F95BD +:106790000EFEABEB1682E7B2EEA9FFB2F866F4FF8D +:1067A0005E928AF38CE683BE74FEDA4FB0FEB2DDF1 +:1067B00085F33D47FE2FFFDF86F7AD14EF8EB3E381 +:1067C000FDC1FFB1787F9BE3DDEE34833CDBF55701 +:1067D0008CB36AEB3FDBBA5FF81FBA6ECD8EFF95C4 +:1067E00049FDB080F67F9BF83F1C4AE7D994BDEF86 +:1067F0008302DA3A5120C5B1EC938F92991F385138 +:1068000030A1FF471205EEFF31BF6900B723062C08 +:106810002C457B6340F6A3683710495D09FB77BFC1 +:10682000CA99E77A187B8CFAC40375E7A5BC6EF4A5 +:106830001F9F13885BA036E8809CABF683FD9A9D72 +:106840002DA27D4B4BB46BDF704C65CFAB1583DF56 +:106850007405D1D5E9BAA6A418FDA2C97CBCCBC9E0 +:10686000E00F0BE8FC2FB7C8CE0005D115133C1282 +:10687000ACE78A4C81F875FB4793A3FCA7ADD4C65F +:10688000D4C7D7FE5EF85952989F395118BCB21838 +:10689000E03750C4F8E159E107C61EC2AB20F03022 +:1068A000D845928BC12FA9C685F157EE57C37633D1 +:1068B000D82B926D6907F0AD44A85FCCE68FFEB48B +:1068C000E617F70767C2FD6C897F5283BB942DBA28 +:1068D000ADC6F1101E1A3EFE5E3C68F8FB47F1F1B2 +:1068E0007BC0C798083EB24F3925E0CF49DC1F98DE +:1068F0007CAA43C47AB64BC2FD17EE0F4CB0254AB2 +:10690000E00F5C2A7D20025F9659B657C23E82C5D1 +:1069100025205D0FEB32A1BF63291410EEC31B25A8 +:10692000AC7F60728E01437BFAC5AF1DBF9B403CBC +:10693000D9AD30C3BB98C5F3FFF2C30F9714415CC8 +:1069400085FD95D1FF5D4DFDB1F94D241847E1B4AA +:1069500040223E487158401775C8100F36D6E1EFF7 +:10696000B2B4C83867EBDF9F1CF96797AF51B975B0 +:10697000E87C42B643C982FD92DE6FFE513B8397AD +:10698000F71D12188CF106B758ACDB67FBF714261D +:106990003F5EFBE3D6D1103F9BD09397C0E469A143 +:1069A00009E8D2CBFD8293444D807C8593ED431260 +:1069B000701F71BF68F7C488DB6CE4FEF42FEA3106 +:1069C000A84C7A9A895F04BF8984317EEB6BB6C488 +:1069D000DC0F9E9B62E274C3F146FFC422D8B7600D +:1069E000DF5F405F4DD0E3AD6BDA97527E5F3CC016 +:1069F000DF21DDFECA3F0A5FF0DF01BE1BADA1292A +:106A0000C531E4C7420EBFE97BBFC778E705ED6B30 +:106A10004D40BF17349B0CFB93D529DCEF1A45463C +:106A2000C1BCA6EFB5DA0B012FFB459795AECFDBC6 +:106A30007E42F1C4D8E78A86278C0F71F49752D82A +:106A4000BEC04EB9651EC075E75716E2A3F8DDAEAD +:106A5000F8AB62CD33258DC9B905A4E5CEFCDC7F4A +:106A60003DF84EE8B10527829FD94C785C239AFE09 +:106A700008D2F1C90D2400FA14FC52900B273711EB +:106A8000D4E714248F825F4DF9FDC7FA38CDB0B634 +:106A90002DBF003BA0B65D709A687BAD1452201EDE +:106AA000EB6D4B1441EF16A8C48DFBC39273E4F554 +:106AB0003ABE78294542F8EE1BBFF316F8EED75DD3 +:106AC0000A017BC4FD46D8017AFBEBF6D1C807FD6D +:106AD000ADEB97F5A472B20CE33079184D0F799BAA +:106AE000E20CF58B454F16F0D7747368A12B06FEA8 +:106AF000A6A5323A3B67F916F8FF4CBE7DA8C93708 +:106B00008F58ACE3A3945446F73AF9961E4BBEDD7A +:106B100021A8E900F73B760D4907BCDEF1B69C1AC7 +:106B20004BBE6DAE67FB7FAF507E84B2A795CAB7F0 +:106B30008B74F2AD95CAB7DCBEEFFDED5CE55BE0B2 +:106B4000BF87FF36837C8BB1DE440E3F4DBEE5B779 +:106B50001F44F996DF6A22AACE7EB0A49E4DBE09DC +:106B6000A9D7833DBC5F76C5C7A09FCDDCFE7E85DF +:106B7000E7EDC17740CEFD5B2ADB2F3D5739979972 +:106B8000C6F8E4AC72EEBF09CE9A9CBB631B95734A +:106B9000B9B1E890C9B93BB6533927003D323977CE +:106BA000C72EC2E26F51F26D781FF946B07F6D902B +:106BB000BDEF6DCB7DE6563ADE28B7ECB2D0FEA332 +:106BC00022F26E8C5EDEFD5BAA8470EE23EFF69FF0 +:106BD0009BBCDBC6E51D95638341BE46D387AB3DB9 +:106BE000CE50DF39AE73D32F815FDE15717FF10395 +:106BF00013DB077A6F5C6721D0D72A3E1F2FA7BF10 +:106C0000EE7A1F8E3FE90DB6BE9A4D2CFE5DDBCAB3 +:106C1000ECC3DA6631A0D27F4E19FFBD02F3AFD8C4 +:106C20002590745A9F61F63F6D0319FCA24CB85F22 +:106C300034AD40470FF3C756611CBFC1EA5847281F +:106C40001FCF978805E2F555B6295F821D5C359602 +:106C5000C5F7ABF873C2F306B43CC8D2B6DBDF1A93 +:106C600040FAE60F4C37333C4E7F5E08ACCD85FCD6 +:106C700025637B5554FEE3637C9D33C410C285BC01 +:106C80002FC6CC63782C1A1EFB393CE8FA0DF008AD +:106C90000831E141313AAD202DB2FE8A77434B21D4 +:106CA0009E5FB14AC07D5F0D1ED1EBD4E0A3C5A7A6 +:106CB000ABF8FBDEF6DB71DF3F7AFD1AFCFAAC5B6A +:106CC0008367D4FAFDA97CDFAB808C867C1A4A0FDF +:106CD000283F7CBFA670A0DF299E707EBA5E1E3F53 +:106CE000CDE130DA3F61522601B8913AA09FD2C679 +:106CF000DBDFCAA4EB1FF3893A0AD4E4C5E3CD1E57 +:106D0000D847DD680DA37CD3E8AB53A3773ECECE46 +:106D1000ACBA89E8AFB7094EB02FBC412BC2D14BFA +:106D2000E9CC4ABBEC5BF5ED140E47A719F98AEBE9 +:106D30001D0A7713F8539A1EA27007BE19DD7E0252 +:106D4000F7730B4918F74B6A1B055790AEA3B68D26 +:106D5000C14B93B7F4CFA6C7470C7A9462D1238175 +:106D6000207151440F56F17ED3CDFE8F601F663ADD +:106D7000A5F7B52482C7E1F43FC063349E34789E02 +:106D80008D3EBFE0F6C76680A30DE0156676549091 +:106D9000EA057BA4DD2BF90C709CF4EC69465FBB23 +:106DA0000415F6137AE104F44ADBC7B4337A05B864 +:106DB000A900F7F61211EAA514BEC9B97DD709FBDF +:106DC000977AFEADD875908DBF5A709118F4ABAD1F +:106DD000BB3FFAFD47E9B6338A6EDFB386DF190D94 +:106DE00074BB4B607184F644C3BEA3398DEDBB6F99 +:106DF000B452FA86FDAEB765D73AB52F9F9FE6F03D +:106E000004FB5FD5C5A546C002602F708305F3CF94 +:106E1000701E83997DA997AF9BAD24F5FAC2FEC77A +:106E200057B83FD09F7DA3D547C2F740EEB5D1EF0D +:106E30000D8F7C2F5ABE6BFEFED9D6959CF68FAD7A +:106E4000AB377F9374E0FE9339D1734F0AC67F58F6 +:106E50007ED28D3C3F89CE00ED2C5DBF8CD431FDC0 +:106E6000F7231916D4C377F2BCF8CB451BF1D175C3 +:106E70007CED96914EA996FEDD25209727523D4246 +:106E80008BAFDF19F3F1ADD82EE27ED435EF26D7E4 +:106E9000C03EDD35208CE8F36B0A04D4BF1FC06010 +:106EA000E3C08EB510B79993306D1FFBA3C4C0C368 +:106EB000B4BDA0D93F49A5FC346A43A0014AD7A478 +:106EC00070CA7B00BF092201F875B8932781FEBA0A +:106ED000F30B5220AAA867719C51FB492AF41BEFBF +:106EE0004E4577605CEBCA49101F9DB1CF66033AEF +:106EF0001FDE64221E1DFD8E278106D8871F77D8CE +:106F00007D1DF05F39B51720EE5CDEBEB6C101F520 +:106F100026C1A5D2F1BD3ECF14079DD7E6C61353B7 +:106F20002E043EA4FD60186F13EBE76D165C902AEB +:106F30005BDABE02F3714A9B05E284FE018158D8F8 +:106F4000B8010B1D7773137D9FD6CBE07D18B7F981 +:106F5000C487D7019FBF23B2F737B17DEB52FA9EAA +:106F60000AF4DA7C3B8E57D124900C3A5EF926263F +:106F7000FFCBDF915DD0DEBA6715EAB169F47B998A +:106F8000B920EF8393A14E460B4EB0B749F6CDC85A +:106F9000D73D9CAF49D74C2637045EE77E836637E2 +:106FA000ED4D63F9C1A5AEC54A321DE7BDB1A9B922 +:106FB0009026E06D3B81FBD187299C3D14CE1FF0CC +:106FC0007C8E7D633F57423AFDF359DA10A4C3F932 +:106FD0006D1330CF610129C63C87E9E398BDF6FE09 +:106FE000A5D68040E7F5BE1CCE86E7FB2E35A3FD77 +:106FF000DBBD59C6FDE2EE81218C4F7736C904F224 +:10700000351A9A44948B9D9B981E1757DF30251391 +:10701000E0B75E7081DCDCD7344901BDD61910F0D1 +:10702000FD49ABEF4A637E0C93879ADF56EAAC309A +:10703000E88F68F9A6C9BF1A0E87683957A3E9997E +:1070400028395703FBCD0E288DCFBDC4C6E41FD809 +:10705000FD80F7E0F748BFB5EFC804EC7EE1F3AE82 +:107060002998B7057A93B68F6B17DCB0CF5FFE898E +:107070003980F66AA064CE4F417E7F6A26820A7903 +:10708000F014EE542E8C3587FFF8247DFEE50716AC +:10709000C890A174528270D6F2450BD7B3FC96C249 +:1070A0000F56A695021C2627A39C2D6B14894727F3 +:1070B0002FBE14DCD7DDCCE4B173BD4E1E152AFE05 +:1070C00052D05FCE742607D5F532E48C906D5C3ECD +:1070D000517BDA0D7643C5F615690AEDB794E7835F +:1070E00054EC5A914645036900BD45FB57286CFC9A +:1070F0008ADD8273AD6E7CED7D6D3C6D1C65BB7170 +:107100009C21BB78FD1CC7D1E6A17DBF3F7B7CECF9 +:107110007F9C5E29D0F1C6BE2F6292F2D8CFA70D18 +:10712000D1EF7768A5167F2DFAD044DC3AB88DFDF3 +:10713000631C71EBE8A2750CE56F8AB7ABDB983D79 +:10714000D43AE6A05253887527F0732D8FD3D64ECC +:1071500066FB56AD051FDC0FFC3DAD50403A203EAE +:107160008F929C8276900AF1F1B242F67E197D1FD1 +:10717000F8AE7515E3432A0F549017B54D2BA66052 +:10718000FF664185F15BD796A09E2F1F2B126C6F77 +:107190003E88764779DBC114E057CA9F2B41EFD672 +:1071A0005E6276027F687CA7F1F1FB32CB0F21167D +:1071B000E74838075096A6C6E45FF11DC2FCD44DDF +:1071C00032F29D772CE3CBF7378BC8CFFB2EBD690E +:1071D0000AF061F77AA11F3EA67C5A18E153713577 +:1071E000CBD729DBC8FC957D4D4C3E74B6323B7144 +:1071F000D26AF96AA897BD2B1316F762F6E0B9F2C6 +:10720000731F3B65436C7EEE8F7FA7CB2D1FDD493F +:10721000E777CDCB74FE6A045E932EBBDB8171FAF7 +:10722000CB66E17A3539542AB17CA6F9FEC52CDF4C +:107230005762796F7FF7BCA2E6F1609A3D2247441E +:10724000A0F7449627DD2C23BD47F3E33FCA47FF51 +:107250002CBEDEC6E9489B8FB88BBD0F7965410A0D +:10726000C75F6D7A1EF35ABF7AE9E074C073D54EDA +:107270004ABF74BDDD9BEC2408724B0AA0BEA96C0A +:1072800015317F9C48C1A2EBEC7AFE64F94955AFF9 +:10729000D8916E2AB7B2BCD3CA573FCFC77C9125CD +:1072A00061CCBBF2BDC4ED4D5F281FE8BB526279D3 +:1072B00052D1FC3E219DD99F5DDBE367C23A840D2C +:1072C0007B70BFB5B2E52619E8AF577EA4CB5A3F15 +:1072D000DCC7F451FA857D7698DF8C91FAF92D465A +:1072E0003C756D64FC5FD92607AC30BF0D6B319ED9 +:1072F000EDDD7002F3E327BDB219E308DE36D19865 +:1073000017B9410C9A317F533C6846BFC6989F58C5 +:10731000DB5A83FB6EB52D3CFF2F2A2FAEEA955D1D +:10732000AFFA2868AA7EF9A203E4C1B18EF50E80F7 +:10733000271D0FF30A2F3B2519F2A3FACF07761B5F +:10734000F30D5B1EE2F986577792FCBEF986C7E023 +:107350001FA06FD2A3F2353724F3FCEE6051718C7D +:10736000787EEFB99FCDDFAC813CF9AEADC7D7C019 +:10737000FCABFFF6F51AC86F22BBADA8A7BC2FFD6A +:107380000EF38AB5F716A7337AEBDEF822E66577B7 +:107390007F6A467FA77B57670EE4B7756FF93E0D8E +:1073A000E2730B775D8EF1CB85DB26A59318F25E39 +:1073B0002B813E03E790171E8D8F7DADFB300FEBC9 +:1073C000AB4FCC28DF7AF3475B6A585EAECAF34610 +:1073D00037C5CEC3D7F21C6B5BAFBBE65290D7ADBF +:1073E000CCBEEBCD7B3C5BBEE88714AF179D03FEA4 +:1073F00036F1BCE096AB63E68B7E05FFA078FA79A8 +:10740000BA315FF49BD6053F7F16DA5A93FBCD174E +:107410000D9E03DCB43CFFEA74F74BE9C0475BE325 +:107420007D190C6F816902D881DFE4C0F988A372ED +:1074300018F340C2BBCC4EC87BACDCF531F24BF745 +:10744000B60F30DE4A789E7D37E9FD63F9D0025FE2 +:1074500067B39DE59972F8431EAAEAC0E73CDF9442 +:10746000D1B19687DA5FFE69289D9F1FE6E70E6A15 +:10747000A8DFC4F2D42379A9C258C0D741435EAF74 +:10748000B6EEE8F19C5C8E46F2AA63E7F96A79846D +:107490007DF1C5F48A9637DDBD96E75BD3E7D9A3C6 +:1074A000204F8EE9736F40F838167EB5BCEA3F4432 +:1074B000E1575B5F7F7CA1F1E7D9E6FD5F85CBBB40 +:1074C000E92C9EADC1A7EB2FB1E5F4B79CDFA9DF96 +:1074D000FA4DBACEBF9DC3FD560D6EDA7C97B6301D +:1074E000BBA26B03F31FA2F99BAEC71D2BCF5ECAD5 +:1074F00060F66F6DDB9E7C90435D7BB773BA6374FF +:107500005DBBE920CBD3A5723BA097DB84C591A3DB +:10751000C773F0F1BCEDB1C7F36E3A1173BC63925F +:10752000FB2698FFB10E66471D6B11A706628C7F84 +:107530009AEBA5DE75DB15CC97121D71684F2DB443 +:107540008FFD2421054A05F37E1A16F33CA1FB5C4E +:107550001900E706FB9504E6F300C047177F909DEE +:107560001E02769C9C515C28AA91F96AED4A8A8990 +:1075700004F4F89782D920DF0F1474CA30DE675103 +:107580007193CF24B2349DCEEB339FE05AACF66FAB +:10759000776B75CFBDA221CE516B0E1F00FB9DBC3A +:1075A0006EC5B8B5B8DBEAC3B8D91A2BAE73DFB66F +:1075B000EF5E007875FFDC4CD83E02250C2A17CA16 +:1075C00078FCA273DB776BFE0C7626BC4CBF5FB6F3 +:1075D00086F607FB7A533CFA033D5B13F2D19E7C9F +:1075E000FD9EE92037CA4087819DF74A7AA0818EA7 +:1075F000772495D58F6C1E88E709AAB6DA31DF703B +:10760000DFB6D76A41FE77BF120FDBD1E42B39F426 +:1076100037A87B772690B52ADA81AA5EDF56104913 +:10762000D5DB79555037E4BF10F4D3311E47E9B9A3 +:10763000AA2D01CF8FE8FA717EF665B1F332C12C25 +:10764000E03B6A4F1ABEA3B55F9F31989FEF0DFFD5 +:1076500084DDAFC0FA7B957029ABFBB318DF766091 +:10766000FF128D5E797BDF7159FF3919830DFDB4EF +:10767000F76BCDA42E161F546708FC7CEF5F87C5FF +:10768000BACF22C6FCF1F95D02F199C00ED8620DA5 +:10769000405CA35A090E85FCF65715B63F52ED081B +:1076A0000E85FCF69D5CFE55C7D13A7D9EC5E7016F +:1076B000FDA14E2CA19701DF35AF5909E427D5BCB8 +:1076C0006E77039E6B5EFDEEC8738590CF168F714B +:1076D000AB9AD7FF1DF15F630ECE06FA0F6F3193A1 +:1076E00075B47FD796B773C08EE89283394967D84F +:1076F000F7A969311BF6B1B5751CAB0F9C07E7D72D +:10770000B5738B95FDC88B5D19CC1E5D91E17E3CF8 +:1077100003F9DAE644790DE389304EDB10FDB9E672 +:107720004A35B61C6BCA900DE768C5C839C526181E +:10773000F72B125A9A455152238471FFBC72C389A8 +:1077400091E00F7FF6B30B715FEB33253C12E4F64B +:107750006739E1917A797CB4DEA24A32C625B0EC71 +:10776000597BA2348B40FEA075662CF9B439231ED8 +:10777000E751796F7CCCF3A03B38BDAD061A4C6560 +:10778000DF853884F6DDCF948002F3C8CB54B1BDD9 +:10779000323BA0C0F3AA0DDB8718EE9D90FCD88F7A +:1077A000F217C2A382AC540A6D7DE54AC5229B2A1A +:1077B000E1F968E93F7BE94D8CE009839C90A7C61D +:1077C00071483513C641B5F300925C6C017829A469 +:1077D000D82989806A3FF2691C69C1D246CD11A6B9 +:1077E00087EA08E4151DE5FBB766497D1CE4877947 +:1077F000BF88F2FC6C70FB558603E76D96EA880B38 +:10780000ED8E694EB0AB059F87FC40E9A1A17EC318 +:1078100090C36CFFDF0DF9700EC2E6E770BEF53D58 +:10782000D80794CED0CFF65D46020DF47B92C2EA23 +:10783000642209C4DA8FEFE27820BE3D287F6C24F1 +:10784000F217A6F5789450F4BB097F1B0B7EAECDE2 +:1078500049826037C5DB48309E96B63CE9989E7FEA +:107860001D84D507537206B9E6BCC4D81E4DD7C4D3 +:10787000259DEA958B22BE7F2AEAFD53677A5F83B6 +:1078800087D73224979D7F677089E36BF04D749D95 +:107890000E013CF21DAE06C0A3123E700FC023DFE6 +:1078A000C6FCC49446A2F7E38664327975BFC0F47F +:1078B00025FD2BB6E9C6234E0BC64F1FE270EFED38 +:1078C000AFC555FAF4B74A00D73EFDADFDF58F8B35 +:1078D000DDDFDEDF7CE263CF27B19FF17DB1FBD737 +:1078E000BEFEF17B41151E32B9211193760E7A4806 +:1078F00026F85B0907D24A1855B07D8228BCC5011D +:10790000FD517A883B4FF71CFE2F4F87BFC131F0E6 +:107910004F824877257C3EB46ECBA4F3BB994F775A +:107920007233DBC7BC75218B23DD7C2F3B2F74F0BA +:1079300067ECDCFEAD8DCCDFBE7511DB3723E5ECEB +:107940001C9093FE07DFBB0D06A1F8BECD2F04826D +:10795000B9700F4E94FDDA7BDFCE5D12F42F898A69 +:10796000C768F4A49D5B9AC7EDEB5C4E9F0B48D8AB +:107970000E7C1F7D8EBE3583E5A55177CC0DEBBB0C +:1079800085AF4FD303BE156438DC0B209AE25CB0A0 +:107990003F22F273ABC4A1B0BCE5EB930CF2E7E479 +:1079A000703501F41D79833FE7F711DD71859AAEDB +:1079B0003FE7259D8EC7FB471A645706C845F9F473 +:1079C0005544A57CA19C1E4254DD39346ADF21B3A5 +:1079D000CB4E82711CC9594CCAC02E4CE4749672AD +:1079E00065AF1DF63E85CB1D2B543C077B5326D33C +:1079F0002F0F67152F00BA101D635D1E5B5FBCFA69 +:107A0000B6B1F535C0FA72FBCEBB4171B9D00EBD2F +:107A1000925A1018EF7159603EA259FD5805FEFCAC +:107A20008D4CC0FFEF0B0786CF93294901C87F9982 +:107A3000EF78F800D0EDF27A27EEA32DAB1F8EE59C +:107A4000C3F51968872EAD7761A9C1C5E2F2BB45C0 +:107A50000A67CB796C3C8BD3C3EC0CAA8720FF421E +:107A600072D605A16EC9AE2360FF5A7BE1E347F8E9 +:107A700028BD750FD6CD50A7A5DC380DE14BDF270B +:107A8000651047CDF22C07F858D50B88AAA30B73C5 +:107A9000C62843BD0FDC34FAD8CCE0F7A8C0E823F1 +:107AA0001A7E8FCA1D2AEC3F3F7A45EFBD36083F4C +:107AB0006AEE33F8FD9AEDCFF50B3F6712DAB3F3B8 +:107AC0008B96CE6EA08F1EE1FB900FD68F45783D32 +:107AD00004795DC3C03F70632902FC281D99F37CC3 +:107AE00044A4EF9B553667B3ADD86D2A64B40BF050 +:107AF000136D0C9EE68C3ADC8FB3D818BC449B0FF8 +:107B0000E122DB18BC441BA33785D72580DF687CC6 +:107B10001F9F53F8B5668E013C8C37C04B4999784E +:107B20006EF05B45E147E791C2F92B1A0E29704EC2 +:107B3000212FC257FDD9754FD1F5831E7F86C2070D +:107B4000CAD47EFCC7D42C2647534C757B6480472F +:107B500012E1FAC547B28B084B5584BF0C1F51A1E7 +:107B60002EB0799066235E45A71475EF9BFA0CD072 +:107B7000C1CAB76513EC938A8BAE329C271567BADE +:107B8000135584A74700FDFC48BD8AF85B01781CAB +:107B900006FA91F9630F707C3E087C82F865FCF16F +:107BA00028E797C7399F34B8D8F989E553595E5605 +:107BB0004A8189DF871624FABCA744570B51E8BCD9 +:107BC000D0C656B10CA29DF18939703E7D2F3E8FF3 +:107BD000B8814E123FB93B806B25C599601725725D +:107BE000FB975CA226CEC283B44189F9215414A22A +:107BF0005FD3618A750F56836BAF05E2A6FDCD6733 +:107C0000CF8C57912E4B2FC2F46092EC299EB580F9 +:107C1000D66D8DF1181F8C77798A1E003E6FB423C4 +:107C20009DDAE8FCCB74788FEF07AFCF665D61CA51 +:107C3000A2742882D146F1FB44E3102BC0F929B984 +:107C40003813E4EB535CCF521CA8FA7DA82E2E27E4 +:107C50001D851718FCD995B21BDF735E6294032B48 +:107C6000B9DC4D9A6CA4774DEE7ED42B773DA930CC +:107C70009FB4D393911F53AE8D2D7F1B64C507F71F +:107C80000A348C64FCEE2B51D0FE8B210F30AE7D7C +:107C9000D233741DC8538DBE9610267F7C24CE85AA +:107CA000FA88DFA3A3D9C7CBE0BE412E67A114CFCA +:107CB00053906ED26E35617EDE727E5FD66394BE67 +:107CC000A0F453FA82F2D22CB69FB1C4320AEF6DFF +:107CD0006BB099505E489F9A0336B057F78C734249 +:107CE0001C41925D1D6E8807DAA5967504FA155A37 +:107CF000E03E0921B1D00974F0AD7DFEA033E5E18D +:107D000051740A4047CE946272280F770FF05CB32B +:107D1000ECBC96405CF199943A2BC02D2F8BF95D09 +:107D20008D254508470ADF8959A99171D2675ED927 +:107D30007BDF160CFB4C3FE7A3A767713B3ADB47A1 +:107D4000CED3F17BA3C0ED30D54786EBF87EC9F9E1 +:107D50005308EC2BF5E5F77EE4D97A26CFEE1762CF +:107D6000CB33CDFED4E4991C2527B472E9A0A986B3 +:107D7000F35D4A8A0B68174A9F89A248F25DF4E8CE +:107D80002D890887790007927165AF5FFBE3C160B9 +:107D90005716C5A4B7683936BF57AFBBD3004F4796 +:107DA00065357D16D0D3DBFDE9757729D2A17F80BB +:107DB0000A7A69CF1357615CE7F0137615E450D95E +:107DC000E987503F949E1E876579E315A8CF8527E4 +:107DD000AF2E027AE86CBA3CFF5388F3F8EDA8B7EF +:107DE0003B1B270DC5FD487FBC0AF91D9D8DB4BD09 +:107DF00030D20EF9E2A22E5F8040F45D77FE9B1434 +:107E0000AA68976AF79E51BFCE311EE242AB453C4D +:107E1000D754FAA4DD0DF6677FF457DA143B1E0041 +:107E2000BA16E2AEF483C3C18EDEE3181F0ED27120 +:107E3000E7AF63FB080D8AFB4810ECA627ACB80F30 +:107E4000D99014FB5E900559972F0739B020CBFDD0 +:107E500014E2C9C6EE29ED9F1FD8F78FC02633EC78 +:107E6000633DCBEF47913C8E19867D36B68F758486 +:107E7000C75988A59FF638DEAEF6D3EE60F922C466 +:107E800019BB5DF333E2237E460BACA3A6F1F8D217 +:107E90004F115EDCCFE0F33E2AB3791F7DC11C5841 +:107EA0001283FE8FF2FC940A81C157E383A3BDF6CF +:107EB0009107EFC389A65361DD8867C6D171BFDE24 +:107EC0002FA3DEA8A6F48574B56E1CE6C70B4F8CF5 +:107ED0007B1CF2864FBD23627BE5692BB677DDE71D +:107EE0007A06F29EC2EFCA04E4D3A9FD9727B03800 +:107EF00091318E7DDB0026170E71F9507AFA11A4AC +:107F0000DF5E3AF12F5080FF4A4F3FC6E87B838007 +:107F1000F756125FF5BB13CEE3F4391EDEAFB87A25 +:107F200009C0FB123FEE9394AD37BBC01E88C6F369 +:107F3000A12CD510F7280B2DC77109B5BF5274FBC2 +:107F4000E947799E71D969765F2171FA4806F00395 +:107F5000974F113A36DE43DB658D1DA73FC9ED9F74 +:107F6000D2D3171BFC8CC8FA2EC3E7A55CFF9785FC +:107F7000C6613DB29E67C6C55A4F641D9760FFAE8D +:107F8000C4D8DFCFE4703E525F4EDC54BE952BACBC +:107F90005FA9FF2E05E44E69536292A05B575963B7 +:107FA0009521CFA3ACA94499AB1B378287A5EF4E8F +:107FB000902278C87C6EF1D54B6C601714CB03808F +:107FC0009FD65514FD5485F1987CFA52F6E780BC93 +:107FD000EE6CBCD311EBDC44E68028FC3472FC5020 +:107FE000BBBA50871F0D2FD1EF1F595B56F4538832 +:107FF00047AF62B790F42F7FA2F0961B1B6EA37A57 +:10800000E1361CF38DCE0EB70B0D79457DE0C6F140 +:10801000ABC1457B4EEDA80B078C81EF11767EA797 +:1080200091E1FF6CF08A7C97E37F42EC75CCEC5DCC +:10803000C722E2A38C3AFFACEBB887F82C675887CD +:10804000867FF28201FF339F5B8B7CA8E17BFEDEA3 +:108050005548BFF3293FC27E7FA7FF2E47ACFCA245 +:1080600099FDE1FD3C1FC92BFABF87F72F655F0E15 +:10807000E495F95658D11F39BAEE911C3D9C17640E +:108080004DB80DF0429A53CF497FF826BAF6837F58 +:10809000E97B42C678DA962C4F19BC5FCEFDF0FB27 +:1080A00013A70C8D651F3C50BF7F04C4E91AEA3B3F +:1080B000B094B97D49C0BECC457BC91DEB7EAF6590 +:1080C00003985C79A0BE83C53D2D3EE2D49F272650 +:1080D000CC7EFA4FC2E235DA7B8AEC7142FC54E185 +:1080E000E79D65C9B32CB710E21E29053E1DFC961D +:1080F0000E60E7919667EC75C2B962331D1FE239D5 +:10810000966CE9A4719F93D50B844F45C86F965325 +:108110005A08C643F3E8731DBC95940E437C3A1A83 +:108120000E92C581FB4D1261F69CB67EFA04F5D223 +:10813000835C2FADE471CDA7EB5B30EEBF24DE8115 +:10814000FA6FE92013F3A72C12DE57634E64FD95F6 +:1081500004366F2BC4BD45D0AB41ACDBE1461F11EB +:10816000AF4613A09E485401EAC924B814EF4999B8 +:1081700010FA093C7765780280C76F333B0E081010 +:10818000C72EF60C03FDDB28FA0A54DAFFE762B8C3 +:1081900000FAE5D0A64F92583908F2A13DBA7D2DDC +:1081A000764FA8AA8F0B46D7072D92A2F67BFE32F8 +:1081B0004CDFBE22C3FD0ACCA3C1CAEE194AF95C4A +:1081C000C0FD9C062BBB6FA8C17E6302E8F15F0F68 +:1081D00060763BD201D0D17E66CF9C94D4842416A5 +:1081E0002755DF30C4F92DEA1BBAEF48DCDF6BA658 +:1081F0007429E9F655CE93DC26A09BF3FDF4B97EF5 +:108200009E31E2714936BC9637E67E8E363FC8DB3A +:1082100007388AA7A7A0BF164D0F3B7BE3CC3E11C2 +:10822000F0394BBBBF58BA9FD51389F687FED7A745 +:10823000BDF6E8FDACCEF739BD73D93E66434902C1 +:10824000E6C769F398D5FE6007D8A9B3DA33E7C16A +:10825000FED62CDBD02FA0DC2987F7C6831D7897AC +:1082600080E74A6EFEDD1B723C2DB77DB80ECF3322 +:108270007FC1E5E96C12C67BE13DC4C9F7D903F8BB +:108280007C2E71F17A8B0C7EFDADC1C00D57D3DA17 +:108290006D6F04AE06B36DF6FEF09B20063C2DCE4E +:1082A00029B887A0BDD7E67A8BD5D97BBDEB972CB3 +:1082B000B89EC87A2DB87E6D7D74A608FF5EF8F072 +:1082C000FB9A34788873E9BA29BDCC4AB8F14A726E +:1082D00006BB7C966DF8176CD384CD271A3EA7A0F9 +:1082E00089DA8F5D03DC249BE2EF0F03DC0294D577 +:1082F00096708E3418F944867AADE81904A9CF5FD8 +:108300000DF40C4B053874249F93FC3C6065FC7F96 +:1083100000E819F2BC4EA7E0BAB47BE8F7DDDD69EE +:1083200007BB73E9B68FF19EE51A31F4E84D180FDB +:1083300015D16F3AD93AEC8CE7CF0E409C8AEABF50 +:1083400081D9DA394BB6CE3912E39339ADF1988F32 +:108350003F679168B8477ACE2296CF47A48EFCEB50 +:108360000DF6FAFDFD8E03F182E871E62D9A443E8A +:108370001F0DFBB4CE09183F58C3E86BDE64B70885 +:10838000F9CEE39709B8DF3AEEB0DA16A2F57981B3 +:108390004417B0E7BCBBFF6308DC7350DBC1E2816C +:1083A000E9E2ED05F7419C652FD3E350BF1DE8C41A +:1083B000E6566DBAFD822EB9AE00EEFBF3DD6673B4 +:1083C00003FF975CEFFE14EFF3E5F10A4DAFBED665 +:1083D000588279B225B7AA6301FF252D5637961624 +:1083E00022C551395622110B94E90A91AC50C6119D +:1083F0000B94454BD8BDDDA58D33D03E708C2D56EA +:10840000E03EDE92F617BF81F7CBA4E01E763F0573 +:10841000834F49FBDBDF035E17B88B319FF1C20D41 +:108420008AC10F1CD962AC5FD466AC17048DF5D13C +:10843000FB8DF5F5D904E968AEE5BA3C80D7DE5D81 +:1084400066AA8B20FFCF8CF92E8704861FDF462B70 +:10845000CAC34955ED45E0071F7FD96E023F7AE751 +:108460005F7F89FBE1E1CDF104F2ACF6FC3E8EC406 +:1084700041BEE22BD675D05E457107F1CBAA57AC51 +:108480006BC10F7FF502CD8F0FE4C37A5EFD1BCB6E +:10849000AF096F3407607FFCF8F6175F86FDB4E321 +:1084A0001B07A07D7548F099E2E0FB5FB2F8678892 +:1084B000DF1717E2F7C5556D30FAC5776433391306 +:1084C0005A7271422CBB492B876724E74DA673EB88 +:1084D00079C83C07E240C31A8D70D1FA8D08189F05 +:1084E000DFC3C71F4F94089DE6429E40A0C101FA1A +:1084F000F7F9D8F7242FE1FCF3D24BBDEF89FC9EAE +:1085000038A2EACE4D45E437593800F23700FE83F1 +:1085100023CFAB886E3E3AFB642A1FFF6B0BCB6701 +:108520004EE1F7F71FABDF8F7ABFD7EEAB77BB27F4 +:10853000EBEAA58D7BD24AC07F6ADA93365707AF44 +:10854000EA8DFBD26EC1BC270922B8A47AD60B8F64 +:1085500041BCA27AA3D802F38476805B57CB9B0EF2 +:10856000E847EDE151100789D8A397BB27EBF8F84E +:10857000EFA55B8DDFAAB9FDF2DAD88E2990A75E50 +:10858000D528B8A05B55CB0DD75D0DF06E62E75CCA +:108590008B24522C52FEAADE72C35523216F66F53E +:1085A0001817CC870E713D3CAFDA7402CF333C1CF8 +:1085B000F5BB075AB9239BD985B47FD044FB3F7CD8 +:1085C000A3AD1CE4171DF70DA8EF1DBE0EEF5771EC +:1085D0001C65FB0FF4F927266AB71C9DE87BEF1694 +:1085E000FAEA71D2F2D1D510576A34D223A56F01BD +:1085F000ECB2F07AC1B50E9F2E29BA164C6EF76216 +:10860000CCF7A5ED73629DB7AE0818C789C6FB47C6 +:108610007CBEF46FB89E7EA2FB254FF3613E79F5D8 +:10862000222A0F757182EAC37EBC5F32FA3B444F47 +:10863000D7CC9E202AC8C3CD2C6F86FE0996229ED9 +:10864000A73B84D5F15E45A0534A28551790C92A07 +:10865000C0FB5A3215CAF12057E03EFDB12DF9D0CA +:108660007F87107AE1391CCF8E72BCCB19C47B2670 +:10867000B3F839D32E95D57B789C536BAF6CB7622A +:108680009ECDF1AF1494B38B5BF6611E7DD7CB56B4 +:108690009389CA83E35B9227423E66570BBBA7F8D8 +:1086A000584BF244E50C7A3B5A6E68FAF420FC937E +:1086B000EADD3F67BBBFCD063D753FCB574D4FAEA3 +:1086C0002B88F5FB17DA7B294A5D01F831E1DB6C79 +:1086D000AE7508275FAE8471F00C17E40995086C3D +:1086E000DCB841C5E240DADF4EFB423C3A69BF8864 +:1086F000BFD7F0B9E8FA897308DE278F76D0FC423D +:108700000FDE4F49EE677995F324129428BDCD030F +:108710007D948F7594CBF39A04CC2B9BBFDCB81E51 +:10872000B82757AF472B4880DD6FA18F230E867C7B +:1087300017AA6FE05E4B0BCBBFA86C36BE574582C5 +:10874000389FEA4D3F9863C1EB1BA2ADCB9D0DEB6B +:1087500012AEB5E0BCEE7C2A81EDF728C40DFA34E8 +:10876000FC941DE57B15F1E0783773BDEEBDBBC40D +:108770003D1FE4F0A279EEF9C970DE96E93F74F985 +:1087800090BFD9BD5B5593497020BB7783805EADA8 +:108790006A178223A16E213EC728F61CEE1F807542 +:1087A000EBCFD794133F7EAFBCC9F89C7CC8F05A7E +:1087B000CDCF3192665DFB60B0CF183CAA37990DE2 +:1087C000719DF19B049F1DCFBB061AD2E8FC6A8FF6 +:1087D000525941204FF507B3617CC8E719837A9F4E +:1087E0005829DE9EEA95EB8111B1F2FC0F70383EFC +:1087F00075436926F0EBE360B76671408F45B9C5F4 +:10880000E3072468A1DF891BDD5BC7F6A225AC3E28 +:108810007DF50BD31B2FA17E9EECC17DA17962F16A +:108820005B701EECC5419E6B013FF34CEE1C09F9D9 +:10883000D63D14E3A18B181C9E195537A22E861D18 +:10884000A8E1F969A12508FBB2BEEDCCFEB21786FE +:1088500065BD7EAD1EC8E451C2DE109E9B086F133D +:10886000F09CE52AE1209E475C75854AC0BFCFA0F9 +:10887000780279BC4A20F7C37D5C85AD336E7F13E7 +:10888000F05C18E7829FBBA8699D20D6D870FDCC0C +:108890004E8BAF5B0BFB39E973868F023AA7EB9ED9 +:1088A000732D7D7EFB4015BF97696378CF58E2CB6F +:1088B00085DF814AD85B7CFB9BC08723E3F09C6CFF +:1088C0003A85953D09CB65607F6590C502F47BCA0A +:1088D000C1C64F35897366407D14AB27DD2BB8D7F1 +:1088E00021F1ADC0F1D3CD642ACC139E831D6981E3 +:1088F000B802B607187E27D515C078E9435899A263 +:1089000004B3619C777AF1ED41BF6221D7630BB765 +:108910004C48073FEF9D2EEA7053B9F54E86660F1F +:10892000056DF8FB50E70D67FDB95FB8B0809D3766 +:1089300048C931F6EB91DD09A3418E7EC0ECF853B6 +:108940003637C6A72F5662C7B39E1BC8EC16EF6911 +:108950008104747AC03BF35BB42BBDA725C3F3AE8F +:108960007A8B21CFB9BA7C2F9EBBAF211D98875D32 +:10897000D3126FC8DBBD382EF67735FAF69E16890E +:108980002FE67715E3F3D3C9C4971CAB5F9AF1398F +:108990005D87A1DEF65DEF3AE039191B72803F3842 +:1089A0008DDBB53D01934FBE2882976E67C8A077D7 +:1089B000BA5556EFE1FB715ABB367EF74C859F2BBB +:1089C00062F72A037C7CC30879B6FD04C6A3ABDB3F +:1089D000F74C61BFEFC5E8420F279F4E7EA4357468 +:1089E000044D94B77F3BF0E86379232889EDD5F8EF +:1089F000F8D8636ECAB769A2C9C0D7F185BD7C8EAD +:108A0000E2E52993C8E5C2F1C7265FA2AFB3FE91A4 +:108A1000F7BBA64FA6B67D611E7BFF8F03BF7A6FA3 +:108A2000C97911B944D791536CD7D52D51751BAD68 +:108A30008FD4D59D51ED2951ED1951F56CD6BFCB91 +:108A40001ECC115D84740E3C315D1A07FBD8C1D970 +:108A500070A3C0F286AFA74FA6F59AC20ECC9FA90D +:108A60006D175CB8ADAFE5C7BB989D657385F0F732 +:108A7000ECE20B3BDE023950DD2638054AEFB696B4 +:108A80002D9857530DEFA9BAF75A98DF59DD721098 +:108A9000DFEB77FCE126E4E787871FC27EDAFED1B1 +:108AA0004DA4F7F73A4E0F043CB674323D1CB57F27 +:108AB000D49DE9DE87F230EAFCAB17C6B545E85E27 +:108AC000EBFF8791EDBF8361E2179E582CD1FE7FAB +:108AD000AAE91C03F612DC710972FF69213002F465 +:108AE000F3B3C43302F4D16D35E7EF31D17E07E43F +:108AF000D06AB8AA61688EF51A89CAE903F6D0402F +:108B000081CA92E16B92AF01781E480DE10D0D3FD5 +:108B10005B93C2DA078606C2BE6B5ECE8F59FDFC40 +:108B2000D06AA85FBFE602561F191A28D2F707FBC2 +:108B30002EBC06E0BFDE199B6F07E63079AECD6F25 +:108B400066813B2307ECCD6AA62FE0F8A585CAC550 +:108B5000D995C736AFA77098FDD3789457EBBBAEC5 +:108B6000BBB218D7EF2B863C3776C53BD767289723 +:108B700025B4033241872545F061CFE95051DE5FCE +:108B800050B705F47EFAEC3C94F7A7B2DDF53963F3 +:108B900022E59F87B0B23E879DF748174D986F90AA +:108BA0007E8F1DEDA0C7F97E12E51BC4AF8DE36378 +:108BB000540E937FA372989F9435F0F27A58CFCDDC +:108BC000DC3E5DF95060A395C2FFF740242918DF11 +:108BD000467BF796B5546E24403E853B13E4C12D89 +:108BE00010FFCD8BD435FB7D6501ADDB227EDACA6B +:108BF00019EE4C7D1ED0CAB5AC5D93372B73D9FBF3 +:108C00009ADE496F60F0497F7CC43A5847BC44F013 +:108C1000FCC5829943D72D46FD7D2DAE9BB8DD99CD +:108C2000E07F1FAE186C02BB52C3CFA202F7345CC8 +:108C30008FC8F2D5353C69DFAFE7EB9E2752FD4F79 +:108C4000D7593FC883EBA7F6403E4B2E60F6403D18 +:108C500004625323F02552680C3CFF5F04A7DBA19C +:108C6000FD1F85530C79F133E857B388CA0B934E37 +:108C70005E70F83D2D04E5F442DDFD25F439F88100 +:108C8000370DF43C90A3DBC7997D4F0DDA7FDABC3A +:108C9000E2FFFDB5A93791BE7C166D9F1DF8BD653D +:108CA00039C6019516948B07AE24AEC5203FF8BE99 +:108CB000AC665F16FDB4EA1DF0A34EE688F89E553B +:108CC000C3AB50BCA594C2E921AA56E13CBA6F06D9 +:108CD000CBEFD1F4E64A7EEFEECABB2FC43CBF1EF9 +:108CE00012C2DF65F38D2528FF7ADB670DC5768A12 +:108CF0006F9F15F8BD220E7F77606501C173362B1B +:108D0000675D80ED3BB5B8D22C0B7E67E50C464F16 +:108D10002B2B581E26E811805B7FF490D6C0E21BF7 +:108D20004472E7EBF301DEE5F88B2F0C6DFB18ECDA +:108D3000CAE556B42B4177E2FE883F1DBF47F1BA22 +:108D40000DE599E6473D99C9EE9B252EF4CF1FB45A +:108D5000BB4B505EDD17AFC2FC9BAC64996514B889 +:108D600023E47E947B7C3EC4FF0CE679CCE1F6DA0A +:108D700067E527ED600FBCC1E50D100CF8CB73095A +:108D80006B9F7B6FFC41F06FE6DECBEE9B25CB2E1D +:108D9000771BF73BE85CD3203ECEFF1AC376808377 +:108DA00007DE73C0F8FF6987FB4C3CF7B2F3BDC424 +:108DB00047DFD7E5437F0CFC0B717691CD9FD4C77D +:108DC000ABB1EE05FD98CB773A7FB7FE7BDA77A2A1 +:108DD000C7A5FEDD2740A714EE41380716BE4FE4B5 +:108DE000BFD76A9C6F8A127ED44ADB67D78B894BC8 +:108DF000283C3D8BECB85E6DBE73D2C397B2DF8565 +:108E0000358E7F24BEB608E2E19A3F42EE35FA6322 +:108E10001097E8AD8B98278D7E4D9FE7DC9F8DF6F0 +:108E20000309F99B59DFAFF79C862A44CD9FD39560 +:108E30002A4880370FCF5F5094F06CBC572A6ADE07 +:108E40001A3C9541260E774617D1F05606717A885E +:108E500082778A121A08E37A1699114ED1E36BFAD7 +:108E6000F1192BF1811FD9280848AF8D77C7A3BE10 +:108E7000231686676F659C0AF4FBAC12C63C27DF9D +:108E80000EF6FBA03DD6F0AB28B7CE63F1869EF779 +:108E9000C4B5D0AF3B95D17DF77699F31B61F74C04 +:108EA000BC27AEC376818DDBBD381EF3A7E07CA85E +:108EB00002E7367D7FAE87F88BE6E77FFE2ABB6F41 +:108EC000017ED747EF27C3B9DAF25111F981F7C70D +:108ED00000BFB7C5F33892A702BF774B1C813C8D0A +:108EE0005A938079BFB59517E03913C2EF79AEE692 +:108EF00053AB35517F7154440ED49A0E0D057FABA0 +:108F0000DAB21CEF7FA6ED6F809F063FC3DBFB3B11 +:108F10001FB97DF150BBFCF85FF1DC7BAB913EAA41 +:108F2000237484E7E72AF574951BA117B4C7418E13 +:108F30004C26786EDFCEEBF1533B0210C7F1F2B84E +:108F400046EA5E76AFADBDB085405CD57B94D92353 +:108F5000E3DBD7EE03FF38716A077864B43F8BCB4D +:108F6000459F2F1AD7BE4204BF4FB363747EE78874 +:108F70006B47EA4B761E17FC58F85E081E01FF4847 +:108F80004CFF3DCDF51FD59328AF17F887A19E0460 +:108F90003D06724EF38341EE819C7971D0C45B072C +:108FA000A5C27D86136F1AC4F66946A0DDEF3BB7F4 +:108FB000FD28AD1FF8C3678E9731B8855725303926 +:108FC000023F100A71E4DFC86B1FC6F949ECBEC648 +:108FD000D5B92897B5384E358F6395F2B84F298F9C +:108FE000FB40DC559F170B714D7DBD9ACB851AF860 +:108FF000BD29BC4FC01CC98B8578CF6412B4433BDC +:10900000C47D1CECFC9DFE7D2F094C9290CE7F30E0 +:109010001BEECD5AC9D63B87E37D9595C57BC6DF50 +:10902000BB5664412CB6DE8451EEDC070A23F77789 +:109030007DC1F1A4C1256ED0C412807B9CC8EE3FD7 +:109040000F3FC07E0FFB30D5DF5B783CE45A1B9EA0 +:109050003F769F07790B9233E7DA18BFEBFAF00EF1 +:109060002BDEE3EFE7F2487B3E6510CBF7C5381106 +:10907000C07D713CDAE114CCF940474583357D4A27 +:10908000F2213E7590E77FD6DE68F3C078211E3767 +:109090005F3D88E98DD583D8EF3F68F55EBF8FD3FC +:1090A0008BB6CF05F11A7D7CBBB9B73F8BAF68FAA1 +:1090B000F7E98AB8B5ECBE778D6E4D78BE323EAF1B +:1090C000588138D30E2E474AB83FBF033670419EB1 +:1090D000B4F0B8B4E49C0DBF1BB4E3681EE653A61D +:1090E000284CBEECB8398E407EDFFE632F3DF21E69 +:1090F0006D3F7954C1FBF2E6F378EC0EB8171EE42D +:10910000E53633C619AB15664F56EF1EC9EC18C5C8 +:10911000B30AF2BE7D5B658C7B553B021B5FC0F6DC +:109120004C17C52C9C176576F0F678F67E5CE01738 +:109130002F835FBA3BDDE5A3FD176578F6021F6557 +:1091400099D504A2EDBB0A91F3A48702CC6E3E042C +:109150008207BED36EE7BF33E0CE5C40C7F9FCA107 +:10916000745C0F95B7685F7DFE9819F7D59EEEFD8C +:109170002E8B8F1E928BF13E9943DB0A5CD4F32435 +:109180003DC54A10E2DFDEC799BD37CFA4AE01F876 +:1091900090DDF12E83BFFA5819BB5FA2F2DEE967BA +:1091A000DAE706F9AE8FFF7693700EFAABE5835BD4 +:1091B00020DFB4BB7D848B6D6765E0264A2DDF7FA1 +:1091C0003E2C33F88677C948CFE73A3ED045EFEFDB +:1091D000E089047FDF4DBFDF16BD4FD1B7CEF0E889 +:1091E000DD91CEED3A63FB75D99E53C06FB54F7CD0 +:1091F0007760910ADF0BA33C247E166F3F2CBB6780 +:1092000003DD264E0E1AF2B86C2AF70FCCDCFE23D3 +:109210004145CF875A7BD14412735FE7FF002E3F51 +:10922000E0290080000000001F8B08000000000003 +:10923000000BC57D0B7854D5B5F03E73CEBC92992A +:1092400064663209931739790792C01043448B3A08 +:10925000090103469D002A5A8BC31B943C046D638D +:109260004B9B814408881A2E01010127084AAFD878 +:10927000062F20D64807448AADDE3F3EDA8B7A2F90 +:109280005F508A6805225A7EDAABF55F6BED7D92FE +:10929000394322D8DBDB3F7CB0D967BFD65E6BEDAC +:1092A000B5D65E7BED9D5855622C91317B37F385A9 +:1092B0008A18FB067F6EE84F635503953336C5CC9D +:1092C0009218BB96F19F8CD350DFC6984D55191B51 +:1092D0000DDF4F874DB3209FB1246C9A2BD200A491 +:1092E000278D2C6C298574A33DB42D135BFA18F6D9 +:1092F00033770CFC179ACE95598BA504BFABFB7B3B +:10930000DC8C9DDAEBF4AE82EFECAB6F6456C6D822 +:109310000C26EA9959ABC5C5D88B2D52D802F566F3 +:109320006C306FB3427F65CB7CB21DF2BD5B24EF26 +:1093300036A837A3A53C6F23E4EFDD53EC95A16974 +:109340001C8E83F990332443FD6B1BC7B18FAE6233 +:109350006C96396452E03B7B4E623B18F5DF82FD30 +:109360002F8446C92597E261DE063363163EF76F08 +:10937000F09F50443E0BFAEDEC9019CC97ED84EF42 +:1093800005FDDF172AE183521C63B59D51EDD9DF3E +:10939000CC7DF5105016243CBB4DEC1EBF8D263DF8 +:1093A000A4A698B13FE27F93198BC9F05FAD121D5F +:1093B00072864CB6C3BC2BF8BC7A774B84D75AD68E +:1093C0006062D84F7B0263D7448C6B61E158484F91 +:1093D000C9412A9F6B5E4369B59A4974BB97F5985A +:1093E0005836F6DB6BF2170FCE07D597E1839B0556 +:1093F0001F2C3CCDC2D7C1780B97B070ED089EDA18 +:10940000219DABB0601CE0752EE0205EA431251CD0 +:10941000AF6A413F5E1684F479C4A71A8167C463BA +:109420006479FDFE6FCC91F92126C6ACAE7E3A037D +:10943000A108AE21E31A4635009CD72E09C90CE6D7 +:109440009792EEBB3107BEC796F2F9D61FB358D438 +:109450009198F7B32CA8F7655AF90BB930DF7A85E4 +:10946000F93AA13C16F0D201DFB7585910FB7F2A18 +:1094700097CFD763E2FC6B54FC6C940DE9D21D3698 +:10948000205D129903F951C3E7163BB42BC1761244 +:10949000B5EB6B6F612D3111ED2B7E65650CD6CB75 +:1094A0008597EC213354654A20C309FD257D60660C +:1094B000AB207FF657F6F9D8DF59239BD609F5DDA7 +:1094C000326BE8247E594EF4F919D23511B9A9222C +:1094D0009521EF4B93529907CB97D178B54EE0AFDA +:1094E00001E8DB579ED97D3BE72BB3BA0DC6BBE045 +:1094F000ECF921E6011E1684FC0F91CE88973DE31E +:1095000046FD04BED7FB6D5E8EFDC028E457B3FC5C +:10951000C0ED16E0AF09F292DE87601EB5E936872E +:10952000199A5466FCE71FEE84FC277B8CCC8C7464 +:10953000DE316E1ACBBA140E2D5D10327ED813B107 +:109540005EEEDBA9CFD776EAF3F54CF9B047E3033B +:1095500040C116D5EE3E5548B2C3FB0DF0B7D9DC7D +:1095600070BA03E035BF6CF62E85CF8BD4C0365C65 +:109570004F7586DE23886773C667230280978A8CBF +:10958000AF8EA422FE7FCABC08F7056BF90CA2C7F8 +:1095900046AB1A8C905FF582FFDB87565379FB262A +:1095A000B32AF1F2EAD120B7E6D312A62A1603E0D5 +:1095B000BF7EC3C44FA411546E417AB4039F52BB03 +:1095C00017A4D05268377FC3BC6A06E56758C864E1 +:1095D00001783ED1F02C774DB0C07FDB5D55C35094 +:1095E000BE285F2B7EA4FF0AECEA9A7E7CFDBA6F50 +:1095F0007D5ADA4E025E6E62128BC7793B03BFC69C +:1096000079D65A7A4CE5D0CF0D5F7F4972795EE307 +:10961000ABD927AF4279E39B41F486F9A11C99F7B6 +:10962000D041FA2E4DB6107CA7D26D21337C7F75C8 +:10963000A399E79D26CA9FDA22517E5EA714B264E1 +:1096400062FD8B09E528BFB7181D6676299EA2F139 +:10965000F2F1E6FF886300F2C78C55E1FA628E866C +:1096600038BF1DCB1AE2261723BE6EFC04E5D7BC1B +:109670002DB2378C72FA15BB3797617EFCB0393644 +:109680006CFF454239E26FEB78874CDF653FCA21BA +:10969000A6F8BA6F80EFCAD6AB555C2F87B770B803 +:1096A000E7392DCF209D6FF85A26FE570C2CB0DBE2 +:1096B0008674F00DC375A76EDE3101F1FB714D8A22 +:1096C00081EA3F2F3107E2C3D99884DFE7498A1F37 +:1096D000D7D9FC0D0BAA595C3FDE57A932AD9BF2DE +:1096E0008C25493D36E2FBDB51DFD56E013EC7F1EB +:1096F00027BFFF873BDDFD7C2F4DDE70CBB5D8FF4C +:10970000B346E22FAD9FFACD370BFE602C0C789A52 +:1097100027F064CE589287E35F6E3DCC5BD690E72E +:10972000B05D7E5DF4ADF7CD7C7D489912C955964C +:10973000E6223D33D87AD4F493ADC040F2DEE26540 +:10974000BE1D900E31339F04F22B2F53213CE46554 +:109750009AA89EF297453BDF04F8F7A981F84CF8E8 +:109760009EC17CA350CFA8BD8E8A78E8CD860C52CE +:109770008A7098433B48CE411EF0B43E913DB32AD7 +:1097800002CE2CEC6F34AD574F26F47BF6BDAF8E76 +:10979000201EEB867E3602F576FDC52F4D2AD0D3EE +:1097A000D625919CB579FD0CF9A3BEAB86CD2EEAEA +:1097B000978FF55E2EBFA3E7559B69E4EBCCDD4B9D +:1097C000FDDC9CC5D75DBB93AFCF4D8D3121947B24 +:1097D0009BDC212B021D5B1A6428DF6F2995BD08D5 +:1097E000B666A7F82D9C5E16DFAB4C467EF5CA5ECA +:1097F00014F1DDBE8F5A1220FF66E978AF0C799B19 +:10980000EFE9D62C9CB7D728CAB38338EF37C69672 +:1098100093BD728B4FA671D9FCB810AA8A6EDF3B3C +:10982000EED930EEADCCB7F624D0B10A9437D2B130 +:109830001BC7067A9D7104C6225EB4F9DCEC9DB8A4 +:10984000F664A49DE1E3F6007CE27AAC74603C949B +:10985000A8E51548A71BAEE774F8F4797368198C6E +:10986000FFA915F44C84BEF8D4CEF5CED44CAEC7C7 +:1098700018EB1C8A72BF2FAF0C33E0BA7FC0C1F166 +:10988000E136750EC5F5F62749DFCFBDAD320B8148 +:109890009C59D02AB11080F8E9CF5F1C8AF2F79367 +:1098A0001D2F0E9D19015F743B2D9DAE8DD7F68443 +:1098B000CF02E3CD64DA78E1341C6FA6D77C02E5F1 +:1098C000076B1DEFEB89B01F484246D4671B7C2411 +:1098D000BFCFC16A44BED3DA9D9B1FE3433BF31C59 +:1098E000B38424186A66971C36637F3E5F8E1BE83C +:1098F0005DA7B58FEA7F03F20FC025ED97C276A86A +:109900001F5BD44BF27681C57F24158A16201DA1DA +:10991000FE44A4A384FCEA33E1BC1589CBF3330EE7 +:10992000FF834887396D7A3A66663AB87C77B8899A +:10993000EEA63A9B82FA22A999713BF0414308F5C1 +:10994000B53B266E04033BC694E2B1A19CBA212F1D +:10995000A6C5108FDF8786B07E7A4A01B50B567098 +:10996000FE0E26B150B3845D364864073A7A9802F9 +:10997000DFD3C630C72A944599DC4EF430EF069900 +:10998000ECC44E09ED440D0F9A7C47BE41B9F7A9CE +:109990006421BE91BA24B2FB6443E774EC77303E95 +:1099A000DA12C5475BFEC97CF4ECA07C1450898FA9 +:1099B0003C9681F908F64DDFA93E0BFA15C0D71089 +:1099C00081AFC7857CE97DD04274831F09E75B2D99 +:1099D000FAABB6D8C2F20892139FF5C96FE86733A5 +:1099E000D89FB84F4946FB19D2D4E6192AB7DFBB36 +:1099F0007B24E82FF66A0BE9BD470CDD9968E70F79 +:109A000019DEB01BF963C8F4A29266B24FD29C284B +:109A1000F751D6E0FCEB1AC7F9B91D00FD221FD59E +:109A200098683F51F750B99FDB0155B43EEA575B48 +:109A300055D467E3BA3297227FD42F01FB08E5EFB4 +:109A4000FE8E8D73215F37D5E6453BC56A995284FA +:109A5000ED58AB7E9DAD943AC92E0E4E645E94DBFC +:109A6000E74286A07124CAD99EAD3F413DBEA0C841 +:109A70001B5471BD09BECC61A417DA9DBE6417E00A +:109A800075DFDF64DA17B58F823CA42F0B7AB6D767 +:109A9000F8929D909FB9DA4A786FEFE0E5E7EC80A5 +:109AA00020E83F45E6FDB1780BD73397CA030BE2B8 +:109AB0003D690CD37E36603E45CBB73D41768CB6D2 +:109AC000DEDB33393CF6227F265ABE017574770CF3 +:109AD000F04F926CD0364541B4BB63714C9EF7E1B8 +:109AE00070EB0C00480A66BF5E53393632CFEBF795 +:109AF000B77F6472651AE9D7BE72041BF4AE96F79D +:109B000059018E15F6FE7205EC49CB7E49B4BF763D +:109B1000F2F81C98BF24C60F9AD6F800DEC7AD4CE9 +:109B2000375E247C4A54FF4615F7F5A27E70A47F69 +:109B30003C545857A2B56F6EF301FC8F1BF5FD1115 +:109B40004A457BCC68E3FD2EE7776B568FEDD7FF58 +:109B5000600F38B346F7DB012BDEAF6E1B0963C520 +:109B60003ABE30A17ED5F479BD5B223B237ABDA6F7 +:109B700066717F05D8B5A95911F66E35DABB32D9B1 +:109B8000B9137069D52FF133B42FC16EC8C0F1CEAF +:109B9000BEF7D9A983F0BD7DF2A764E7D75F54C8AB +:109BA000FEA807FB03ED764B17B767D97E23E95D67 +:109BB0008DEEF70AF9D3EE04BD8F7CFA8A341AF9D8 +:109BC00094B186A1B7010D9AB37CC3100E6D3F16F8 +:109BD0000D6F4516B7CBEB0B2A36E661FFDB25860A +:109BE0007A7F55C18749689FD4779D489A13D16E73 +:109BF000C1FE758487053B8D03CEBF228BDB9B7531 +:109C00002FEDF5E17AFF3424D15A9EAF8456A25D40 +:109C1000397FBE012D35561A9A7127AE7B36CDC4D9 +:109C200072617E05C2AEA9DF3925782DEEDBE0AF8B +:109C3000049F36F9E7D2FADE34CD62639908E7CCA7 +:109C4000FB090F8E181FE261554145328E53573381 +:109C5000C181FE937AB0B3B0BCEEA1BBC89FD267FE +:109C600007EF3756A1FD5506F6D6BF01DCE9AE4930 +:109C7000555E588FA9F2EE518B21BF7E10F9FB5E25 +:109C800036A7678BE40FDE8AEBFE2589ED50FBCB10 +:109C900033F673BBEEAE2C6E076ADFEFCA52A8DD57 +:109CA000D860F738E4BD034A4F2CDABFF5CCF7395A +:109CB000EE3B99DFA6EE203A71B9E36E52C9AF646C +:109CC00071F73C3212CBC72AB49F604ACF5A1CF7B7 +:109CD000EC4AB7771513FC8BF9878A4228478F66C1 +:109CE00005E621FF94093BF2EC4B378E9A59D46F6D +:109CF00027ADECB08696011E56DAD57FA942F9F65B +:109D00001785E41BB3F4768F437AFCD545FDAEB4DA +:109D1000865622FD836B8C54BE3B25B008F9E67451 +:109D20004D551EEE83992D985703FC6474B731B4DA +:109D30001760FB407E068BDBCF54C88F0BCE5024C0 +:109D400094F351F6C738F4F3D0BE010687EF1542FD +:109D50006CE502179CB2D01268F926A1DF1E39FA11 +:109D6000D554053F6A768AC11258804D2BA7C5305D +:109D700019F97E79EF1103CC27D6DD4D766C6DA7EE +:109D800044E3D416BC6042BFC97D9D7C5DD68B7D0B +:109D900000E06F28DA038F64C58AFD670BF55BCF9F +:109DA000BA691FCD76717A3206F5EC91FB89A5541C +:109DB0004FEBCFB48CFBBD6A853F067AA4F2F56207 +:109DC000BD6BFE095898C23EE0E3AE97BA7D32E221 +:109DD0007594E48DE41B2D7D3E8BEBF7F843BD13AA +:109DE00070FDF6027FA15F66A35473FF6B30BF8DD9 +:109DF000A3877BD184F2003BC925F81D5811F05E82 +:109E0000BAFFF309C8376070D37AADDB5F2ED7DABB +:109E1000486FD3FE71486C4307960FB9A780F46A68 +:109E2000CC55EC9EC9F0FD05B1CE926DDCCFE55965 +:109E300016CC5C5484E3FBEF7F0DC72F8E213FE5EA +:109E400010A08DDD45692BFA853C6CA984F5D6C53B +:109E5000F1FE130DF23D3545247729EFF24ABE6D30 +:109E600090766539A97FD87755219CF89DF663C017 +:109E700019B89F453F17F633249BA76793C30A0A77 +:109E8000884DAC67EB0EE4CFFD6607E2A97AFF6F61 +:109E90008EA1BEACB6B04E19ED95283B6349FA943D +:109EA000D7903FCF9D39B5F561F8B6EEB67DDE00AF +:109EB000D1456F3F44EF17B66195E4C1EDBD0FFA90 +:109EC000E8C9EDBDBEFC3FDCDEE3767D7047ACBA91 +:109ED00023429ED78B7DDAB9F9E7E350CF7CDC07CC +:109EE0000FE8E9B27E7B65E6F6D813B8AEFAECFE71 +:109EF00028BBE1E833B141A4FFF94E2BF9E914B4D2 +:109F00007B009E33F6DE1F2272DC26BF4FC2FDC3EC +:109F10006EA37719F4577FEFA7BF30C0BA533AC08A +:109F2000EE89477B5F8D2739FBBACC76A05DA6F81A +:109F30001CE8F7D0E0579C133CA8B75BC4FC179A09 +:109F4000C279640799D87CCAC785F3D0EE7959E8FD +:109F50009D85319087EF8D9EC0D748B714339757B2 +:109F6000D80EBF77087BAB0350E240BC1C837D77E3 +:109F7000A6D0DFB8FF79343DB48AFC3816A2E74793 +:109F800007CCDBD0CFF35181216CE27E09F263A9CB +:109F9000AD0A4B86FAEA316B48E5FE2E8B01F4FFE1 +:109FA000ACC7EF7B03F715B30E703FD6AC7B97DCE5 +:109FB00082FB8F8F264F30A1BC99C302E4779EC7E6 +:109FC000B81F7A010B717F35731870BCFB406C6C45 +:109FD00042511304EC5F0D9F2583847685DA027964 +:109FE000329A7D6D5530EECC1603ED4B66B5EAFD29 +:109FF000E91756DD5F857A7C458B81DB8FAD12E9F1 +:10A00000F159CCE741BB43C36B617602C983608BD6 +:10A01000C187E38CCBE67A054814A2F989B4C52838 +:10A02000FCF0028EA5CC10C6D420F1748543A91A89 +:10A03000483F6BFDB5181B2CE80FEB4D37901FF810 +:10A0400082C9378DFCA8AE3C867EC4167B436B1557 +:10A050002FA73573C1DAEBA7F2EB146EF031D5857B +:10A06000F23233DB40FD45CF774E9B3E1F7D3EB144 +:10A0700020A4CFCF6281FCE46CF41BE9BF67667358 +:10A080003D706155A63807F0D239408B517D3B13A6 +:10A09000E5D54A85E4E5D2348E2F433A4FB39C95FB +:10A0A000D3887F9D605F10BC1CFEACEBDC12EACD58 +:10A0B0001627E7CBFF29DCD1F0DE949DC7F18B4654 +:10A0C0001E8CD7B2520A717C71B8AFD47FB1305BAD +:10A0D000BFEFECCBFFE3F79D9C1F57CA62BD394829 +:10A0E0000ECD74F0397D24799F09E3771BD80700E2 +:10A0F000F7AC957209DA29E3A6D8681E7507ACE4B7 +:10A100006FAD5DD23314D7515D454F5EC3007845C6 +:10A1100068154D7E41BD996ED827E0BA6DD59F5325 +:10A1200081A66591E74E53D27C4BB313713FF2D1B8 +:10A13000EEDF20BD775B493FC1FF0E9A517EBD9493 +:10A140004976535E5A606536EAF598F0D66733D1A2 +:10A150004EE176526D97B903EDC0992D11E75EF887 +:10A16000CF6AFD39186B75917F83B5EBBFCFDF1CCC +:10A17000D5EE927331AEEFD79B02C3D0BEBBE17A6E +:10A180005F32CAD5330B0C0CE93B4BF6CE45397226 +:10A19000C6AAB7BFCFD839BD76666BF2DD9B877490 +:10A1A000EECB5F42676F1ED27996810522FBA945EF +:10A1B0003A037D170A3A9FD97B751ED2F9B3DD5752 +:10A1C000E7219DD71BDB7CB86E9ECD08EC423C9E00 +:10A1D0001CEF27FB09E455DE77E1C70351FC78E06B +:10A1E0007F8F1FA9DD60FAF0B77D70E8F5A1DBA4D1 +:10A1F000A6A13C9C69317FAB5EC49F01FD6B163309 +:10A20000F9250E7CF5C563CFA01DD225931DA2F5BF +:10A2100077400964A35FE1C0318F37280DDEFF83EB +:10A22000C26EF5585810FD1F9ADDAFD98FD1F2F8E4 +:10A23000B898CFD96C5F0DED1785BF76BEE8D31205 +:10A24000FA82DBA9DB25F2C75AD44E1FDABD75AFFF +:10A25000CC70A0BFF67488FB67EBF68E22FFED8210 +:10A26000D0ABE154B40BBB2407EE1F166C3F118733 +:10A27000E7DDB01F3D934D78E3FBD1F1623F7A3AC1 +:10A28000F4511C9E8BC3F837E33E22D6DD6B42FEB1 +:10A29000AD837D1A5461754AEF11ECAFCECDBC4150 +:10A2A0001415FBF5FB36EDFC7293DF44F26E539709 +:10A2B00014C27D5A9229909986FA89A5394EC5F61D +:10A2C000AF97FFCEF6A5E0B966FFB9B1EF6B84CBCF +:10A2D0008DE74DD0BE67633CF1618F91F9C80ED810 +:10A2E000681772492139F5E7CD4EDAF7D00FD4FF60 +:10A2F000732893F29ABE9EABB0B002789F3BD5F71D +:10A300001ED20DE577384A7E47E6FBCEA35937D7F4 +:10A310002F20CFC3039D8F8B736A3CDF8D6C5FC78B +:10A320007AA91D9EF3EAFAD5F601AC61940A70DFB2 +:10A3300077B7CD8BF64B3DF07563493F1F2E145315 +:10A34000D1F8B04EF879EBE77F48FB81FAFD920334 +:10A35000FDBB0BBD9C0F17C23EC93CE2D275CB3A88 +:10A36000810F23E01E6C1D5F9DA35FC77DF97F9267 +:10A370003FB322476FCF6AF3D7FCE27DF3EC92F84C +:10A38000FA8A9A57F4FE32DA9FADED0FAF54AEDD84 +:10A39000D9070FC7475FFE9F2CD7E644E165B0F3AE +:10A3A00082EF2CD7A2CF0D72B81F1CCF0DF05CF737 +:10A3B0007F7A6EF089DA9664203DE8D39DA7A29D4E +:10A3C0008EE3B46E91C93E9820F373E85ABB99FCB2 +:10A3D000B4D1E7ADF5EA0471BED8FD876B507FEECE +:10A3E0003132D4EBF36DF3E83CB35EDE6572A80363 +:10A3F0009C332A07C97EFFAEE7EF8FE6F49DBF6767 +:10A40000E2F97B59855E3EBF6AFB22211041E78A53 +:10A410002230FC07E0678B1264AE88EF4FE6707B5A +:10A42000F8551127E331B1568CBF78DC1EEBC37DA4 +:10A4300087C7C0E3789AB3FC5B500E5A548EC7A707 +:10A440005EBA8319607E4F193B495E046B6D5E9462 +:10A450007B9A9F45EBDF2EFC0557CADF7BA3D6FB1B +:10A46000DE7FF27AFFB536DE773D07DB00B8D1AD8F +:10A470000346E75D6FE0F94DE6A5FC3A583F83F1EE +:10A48000EDDB39FE377368BDF946D0B9FE15CA95C4 +:10A49000D8D2DE8FD09FC3F69855DC57A05F83F4E7 +:10A4A000E1EA64AEA7146F19E219ECB9328C833A71 +:10A4B0008EFFBD6670FBEF74DFBAE7F6DFE941E5BA +:10A4C000CFDF67FF3565F83FC5799E2CF7E5A17EA4 +:10A4D0005C6107F8715FF7731E3FB3D9CAF973B3B4 +:10A4E000C4F992352668FE119A57F0797EFE1DCD8B +:10A4F000572C57CF577DF97FB2DCB4F5C1F1BF2C93 +:10A5000037E7FF350EFD9C83F71324BA9555741376 +:10A51000DE7A5F91D8B608FF737D378F434B17F013 +:10A520006ADFFF2AECBFB9B9BEA118CFF5D97B16F7 +:10A530000B8B075307790CED2EBF8DFCFF759D3CEF +:10A540004EA46E09A3F3DE3AF46F16A1DFAF86A125 +:10A550007DB74F0D1460FB15EFDB82723CFAC52707 +:10A5600033B2EBDEE3F9456AA088E2C596F4E8CEA3 +:10A5700019CABEF96239FA2D005EF203B8D12F1361 +:10A5800041A769B9FC7C404B6F8B821FFDF4C4FF6F +:10A590009D7208EDC158B59BFCFE757BB89156269F +:10A5A000FBC83FCFEE7331E4A3BA3DE5A35EA3FA47 +:10A5B000D65168CF967D50ED403FC467D7B929BECC +:10A5C00060A8DCB300EDA9A359817108AFBD343494 +:10A5D00011EDD10CB047D1BEFD6CF7C45108B726C0 +:10A5E000FFD6A37F1BFA5D6FD7FBAF99C597F930F4 +:10A5F000FAB7B70DA1FDE1EE94C0CDB9B84FB37273 +:10A6000078836BAC7CBD0ABF76F4FAD7D6FD10D93F +:10A6100040E30CF9BE85CEA135B9B0DEC80296EC98 +:10A620007E7972958897037CF078BDAE1A1EE7217B +:10A63000F236B73E6EF16CF6F8AB707E57E5F2B8C5 +:10A640009439965E09FDEC73C4F9FB8D228E428B22 +:10A65000A33AE3F0CFC6FA6C4955FFB97B16B6773B +:10A6600070FE17F131B117B99D9CE53011DFD85B51 +:10A67000193F3702BE41FA8CEDED1E170FF3C96981 +:10A680000F8F457C1EB868207C28356FD079493CF7 +:10A69000920DFAC95EDDB3321FFD258E77AF43BA46 +:10A6A000A86D8E0A44DD3ED5FF00C1A13414E0FE42 +:10A6B000B1E2F7461E0FF84A2CE9F9F6A10B291E64 +:10A6C000F0ECFBC0AF9997EA032D0DB26514FF972C +:10A6D000B5FF1DF2DBDBF74803C6753E9E6BE3E773 +:10A6E00049C16E8A336363DD840FE5950F82685F2D +:10A6F000282B15F254B4187D062BD27529233F7BE5 +:10A700006EBBC38074C9107125E70EFCF78800ED9D +:10A7100047343F7D8852C5D8B31CF757CAD29EEB49 +:10A720006105B3DA3D4E431DFA358DBD75E41779E9 +:10A730002596FC9F19FBB3977D0FF219AD0E26A14C +:10A74000FCF9D57D19C8D7419867EE00F36CCCE5CC +:10A75000713BCA2BB106D45BCA1A4671888A33A9E9 +:10A7600082E05E0779E86791E01BEDFC11C0F5A07F +:10A770003E9A9B1BD88E788E15728035C690BFD0BE +:10A78000AE70BF86BDF1FDE797427EABF0B71E3AD3 +:10A79000503899FC732B1509E970C13923C301DFC7 +:10A7A0007F99CBED11BBD2CD1CB648FC1FA2B8CB14 +:10A7B000AC57785C9A62E47CA2AC7477A0FFEFCBD4 +:10A7C000B400C5975ED71296E9FCCA71726D951AEE +:10A7D000B17FD9C0F548DD4EBE6F8EDEAF5C4E7FD7 +:10A7E0001CCDD5DBDD7DF97F925DF24EDFF87FE792 +:10A7F0003E84E9F76FD1F649F47EED12FB3AAABF29 +:10A80000C1EC142D8EA3A27F1CE28757ED9A1D1474 +:10A81000D4C5B954D8F8B8CCA2EFFFF94C2E27B460 +:10A82000B897A4667529C697F7FE94913F4D8BCBD8 +:10A83000D1E27082157C9F103480DCCBC4F39F364C +:10A840008ABF49656149227BBF8761FB2118870365 +:10A85000ED7B72B3A8FF2DCCDB2A935C542584DFFB +:10A860008AF11B09087768E35C1CEF361B8D67C50E +:10A87000F88D04DA27D03A4EF1F3B8CD71F379BCF4 +:10A88000670AE85FCCA7E470BEB44E33511CA7162C +:10A8900097A1C56F6878A910F84EC99F9B89FB01E5 +:10A8A0002DCE637D4CE8E75619E33B84DC5F6020E6 +:10A8B000B9AFC5CFB5E7AA21E4F77318E769BBF2D2 +:10A8C000788E68FC6A711D37A40792F346535C07C3 +:10A8D000E9512D1E43E397083A06AD30FEA657B85E +:10A8E000FD5E31DF44F09F5B3089FC87E716181866 +:10A8F000AEA38A2E33E7BFA8F1364D33B130F6ABA5 +:10A9000084AC283F353EB89CFD0A742D40FFECA175 +:10A91000A69DD92761CD1F6EEAA4F49C55EA944701 +:10A9200062DA3B1D25D58867874E51AEC13895DE6A +:10A93000A112B04EC9CE9CA9944FEC3D8EF949F9B5 +:10A94000374F55404F9CCBEDDD2A619C49FE89294C +:10A9500094479E4C616CCC33BF9F12A479737FD314 +:10A9600038E16F323B03D7E525E27D809EE5DDE4EB +:10A97000D7E171FD18F787F4F0D84C64DF7844BC58 +:10A9800025AB14F19778F202F9E6E451745E6D6339 +:10A99000EA9E6E2C4F33737DCF383F37E7727F309E +:10A9A000A948949D699AFFA82788F2AA39D349ED4E +:10A9B000FBE4EA1E7388FBB1F8F86FED2DA6732651 +:10A9C0002D8E943147FAD4628A37D1E51FB7F273DE +:10A9D0004FA638D2D17E68360A3B55E463D202775F +:10A9E000E545D8496F8DFF5111AE8733FB7E9283C9 +:10A9F00072EA4613D8F103C8A5D4022E97CE196D7A +:10AA0000AD12D86D6FA4066621BE8EC54E9FE08440 +:10AA1000794D4B28373911DEE0CF6594938982DE7A +:10AA2000CEA91C3E67A55F9A03FD365B613D43FBE3 +:10AA3000C480E2237B3D3055BA0DE06E9684FDCE96 +:10AA4000D478B2DB0BD4783CD75BD8F80EC555CBA5 +:10AA5000420EC8420EBCDDD493A3E482CAED5C234F +:10AA6000A3BDFD8E385F7E2793DD5333803F737D1A +:10AA70001EB70F27CB6A31F291FBE1B1EF54035FB0 +:10AA8000C8266F88E8976E5791DF0FDACB3C3DD030 +:10AA90008F94F1D3528C4B6E4EFF6929C695C82E08 +:10AAA000AFC71F915F9FC7F9B812EB21DE621B4A47 +:10AAB000518FFDC3FA8B87FE8AFEFEFEFAFA3173D0 +:10AAC000B8165A7A872AB03EBD9EC026A4DB8519E7 +:10AAD00027E8BCF587296F1DC7F888B78C6DE3E2BE +:10AAE000500E654A826FB9BD76245FF36BF2B8F6FB +:10AAF0002385DCAF097288C74F16F37B34D5531911 +:10AB0000ADE76A115731C1C1EF254D28CDF436C3E9 +:10AB1000D46E61BD0ACAE909C7FC71483F36355099 +:10AB2000EA2F1EDC0E631EA31A295726AA1179F8F4 +:10AB30007B53813E7FB3579FBF75CCD7F991F935D1 +:10AB40001EDF8B38EF97251EA719BC8639689E6ECD +:10AB50002988F652E18B291DC27F4BF184FF2AF62A +:10AB6000732F8E61549EB4D3B20DEF17687E705967 +:10AB700094177A9825C345F8203DDB2B89B84437D4 +:10AB80009DF5B07DF73B38FEA0AE09FAD93743A555 +:10AB9000759C6433B0EB71AD975AC87ED2D645B37D +:10ABA00015F81BF058966A89417E6F367A37605FD8 +:10ABB000728C5945BD5A1E67A1BEE59F29A4979680 +:10ABC0005ACD14DA7AE8D118CA9729CC8FF1180037 +:10ABD000E2544CDF327A430D385FA887F36D76324A +:10ABE0009257729989F434F44B743DB4C6106234B0 +:10ABF000FF7285E22D05CCDABA8391E8FB13625D22 +:10AC0000CB06162639966221397618FAC77E0FBD13 +:10AC10002E77901FAD40BD1BCBCF5BF2E9FE4D7D83 +:10AC2000DFBD22C580C015083BCAD9C5EF7F69EBDF +:10AC300059932FD1EB19A4608E3B89711055FC07F5 +:10AC4000A691847A9F913DAF9D0FA65BB472C58794 +:10AC5000E324F7D5E7F7AF92443E353F93D61B5434 +:10AC6000091B4AD0FEF8CD5F906F35F9B075C5CF9E +:10AC7000483E5C8AFF8207293FC9EEE0F8CF4FC308 +:10AC80007528C7E4A7A1BE6B767A557F44BE0096AF +:10AC9000D13417E207EA417E4AD5891C25C2FF97C5 +:10ACA0009AAF92B0847ABE0480E390554DC3F53AD2 +:10ACB000C0B8B57CDCD87FECB81E1817EA1DB2C34B +:10ACC000B8506FBBD51C36C40D34FE1815C7BBDC9D +:10ACD000B8804E42EA248167E08B20FAA50ED90D98 +:10ACE000C49F93447CEEA1443E1E2BD0C7CFE4C446 +:10ACF000C0F8E46FD5C7CBDC286D6E41BDFC843550 +:10AD00006E1BF2E36F049F1C89FD590EDA55BF9943 +:10AD10009E7718E5CA84F8A52DC824935827C91B27 +:10AD20004DEE5D483E518679907FD7E603DD7F98F2 +:10AD3000F5D674ECFCB0F3891CD47F201FBE979F1E +:10AD40007829FC1A3F6A70231FE23AE8E3C328F827 +:10AD5000353E62B7745280E116B04B31D5EC54C623 +:10AD60001A781CB89ADE3F3F60E20996063E8FA52E +:10AD70004182FB46E75A8A371B312CE047B8A68D43 +:10AD8000FC7CA882953D33F2711F06F0D6FCFF844F +:10AD900037DA2EBF5C3CB40657F43AD6C69726EF96 +:10ADA000A478E8FAA9368A8F1E27E24AEBE71B2827 +:10ADB0004E08F66F64F7D7314B08E5F0B5C28ED672 +:10ADC000E2F47F2571FF6770AF59DD11618F5F1A63 +:10ADD00027AD521C7670098FA7EEB3B76BB9BDDDF6 +:10ADE000A7D7C4BD80F6515C96B7DFAF52BCC4CBC9 +:10ADF00012AF1F9CC1B8BD5E23CAE738443C05CCE6 +:10AE000025A93F5EBDBD8311FFB7DBB3A83C45E676 +:10AE1000FA877D8FEB9FF64C6E4FB6DF9947E5B012 +:10AE20002F1886789F2583FDCCCFE7F9FE20978FDA +:10AE300017EDA75D9FCFEDB23E3B47E4A3FDB2CF38 +:10AE400066043622DFCF29F20D9580AF6699B8DF10 +:10AE500015F86E33DE89A9620DDB956CBC5FD1F00D +:10AE6000AE219BF8EE29E2BB42E0BB6C1DDF85F210 +:10AE70004773F98BC254E3BB3E7E2B888E870BFC55 +:10AE80001CFB6977767E5087FB8A2E33D1418B6B12 +:10AE90008C5EE711F09C347278DCB24CF0EC1E084A +:10AEA0009E2BE1FF487E1BC2389F0FB60E86282CD2 +:10AEB000682FE95F076B3C81308EDBB71E96F37D10 +:10AEC000E42570CB36E28BDBEF9439BFC6727D8E02 +:10AED000E749C9307E8D18FFF695FE4A27D6AB911B +:10AEE000080F355DB514F7C52AF9B99017FE203C57 +:10AEF000CD42CE69E757D344FB298E1A23FAE3A645 +:10AF000056EBCF91A6D9F839D5ED538D1F46DA3DD2 +:10AF1000D3D8EACF314E711A9E3369F5818FDECFD7 +:10AF2000B7BBE9FC5B65F978CE7458F859CE015F80 +:10AF300023DFBF96386FF3FDC077F94F1695A03F1A +:10AF40006E7CD282ED6B20FFECA6E1947F2DE9FBB5 +:10AF50000FBC85E55BF3285F6990884FCFD5F2F68B +:10AF60000565774ECA8C43F92FFAC5F584FBF59831 +:10AF7000407B0DD4F38CC82AC1F8D14AE137387729 +:10AF80003FA3F29B46DA7948EE3C95FC7E9531A2D0 +:10AF9000FC07BCDF3746FD4709C6115766F54E472B +:10AFA000FE7EA3E4E5E1983F2C7D3E7DA03886C27D +:10AFB00002293C0CF052E9E2F5AB4B7E9E827E9872 +:10AFC000CA0A9E2FF496AFCCC672C3F9E903DDEF2F +:10AFD0008D11FB9EBEFB6A625DBFE83B41F7D3FC6F +:10AFE00016C98B53F48F39417E0766931CE83AF3F8 +:10AFF000FB3215F4738FF3F138D30ACBD264945F2C +:10B00000B7044CA5182FECB08C3A8C7104F163CACC +:10B0100047235DC75918D115F83CAE00D6D7B4AB5D +:10B020003F1F1A87CC65D3F3B9C647351A7F57EA55 +:10B03000F918D6A71BDB5F4EDE0EC6C730FED00266 +:10B040005C67DFD3EB9BBEFEA2D65B74FF83C901B6 +:10B05000FC89948BFD7074D2BA4AC3E8BD6C5C77EE +:10B060006DDABA1B89F33019BAE99E4E86E41D4E9B +:10B070001756C7782DA48FA2E0D6E04B07D9C64A51 +:10B080002E850B7F14CD5EE43F6EF44BA48972686D +:10B09000E763AE7EB860FC1B100F6C3987678BD4FA +:10B0A000C0E586D81F68FE8C3A6DBEFBF5F32D8B8C +:10B0B000E1F7D63DE877C276EE51C3BF0DEE7AA137 +:10B0C0004FA75AFC8F9A610EB73967113FDC011AFE +:10B0D000CD09F3FF5B6AA006F1D12C055FE9C92415 +:10B0E0007F3CC57700BD271744D8011A5CD1F8A86A +:10B0F0001B441E46C31D8D877EFA742763AADD7725 +:10B10000EB9B57D47CA2ED02B749EFCF7309BF9BED +:10B11000ABDFCF5680E5D52CC64B7E36AF44FBA8BF +:10B120006AD0F32847ABAB18F9475C3603F9D9343A +:10B130007D3F187FDF703D9737D50B99B84FC7E734 +:10B1400011CD5F4358CF83F49E8345DD381BD7ED87 +:10B150007C9B2E0EBEDAC6FDF32B0B24E197EF1974 +:10B160008D7E89BEFC25FEE09ED1283FA6CBFA73DA +:10B17000AAEA8BDC1FECBA28515AED3D311AFD2C9E +:10B18000AEAA9ED128871E19EA5B85743D6EE0FE4B +:10B19000F24BFC160506CD1F7C457C174D0FEDFCD0 +:10B1A0002F26CDBF01C73923759761E1862C713EEB +:10B1B000C30299C8974E476639FA7140CE7DF30DA8 +:10B1C0006E1EB108F035262310C2767730FF78BCAA +:10B1D0006BE9AA0A18F97905A3F92F12F31F2FF4C6 +:10B1E000DFF9CD3CAEA2D257F0041E89D41F35B290 +:10B1F00010AD3F1FE9B1FB04FCE741D585B1FE2E40 +:10B200003BE9C179AFCFA27889FC0D86FE772BE0B0 +:10B21000EFB0508CEEDD8AC29D2E5DBEB83345572F +:10B220007FE4FE2C5DF9A8F0705DF955474B74F989 +:10B23000D1DDD7EAEA5F7DAC4297BFA66792AEFE4A +:10B24000F74E4FD6E5AFEBBD4B57FFA3BE7DBCD04D +:10B25000DF415F7701CC7BB6C69F1767EADAFF292B +:10B260006EC251E4CFD9AB79FC77396048F78E478D +:10B270001BD7F30DF007E93B9EF552DC5D5D48F20C +:10B280008619C691E9ED8005FB3B088F97BBF79EB9 +:10B29000EF9E6140D3F78302116F7235BB9AC78D61 +:10B2A0007E3B5DF358CEDF4557B3474F57ABAAA758 +:10B2B0006B6C819EAE76AF9EAEF163F47475FAF45A +:10B2C000744DA8D2D335D1AFA7EB90697ABA2607CF +:10B2D000F4744D9DAFA76B7A839EAE198D7ABA65D3 +:10B2E00006EFD5950F466F4D1E66B72ED2D5EFA34C +:10B2F000BB7F3EC511E5B6FD58D7BF46F720FC41E0 +:10B30000BAE73311EFF83FA47BF2303DBD417FA493 +:10B310000C1B4D7A3F1DD369F9C2BEF60FACF73551 +:10B32000F913A96723F79783C9A54BF48AD86F0E41 +:10B33000AA57A2F69BEF31D07B34C86AF21FDD29F1 +:10B34000F8F3500CC7FB1758740DD4833A6300AE62 +:10B35000F7106E18E7BD9842F20BDCC53A8DD8FFA6 +:10B36000DDAC9BD2E9AC97D20073901E9DC9BC9412 +:10B37000CE667E93F013DC302C11FD073D65A88767 +:10B380002FCC78EB389D2FBD917045EF3D7C88E741 +:10B3900018B98C9D12F2E0249E6740FEAC55F8D39C +:10B3A0007C4C7547E0ED94F0FBCD1C27913E647218 +:10B3B0000CC559CDBC43227D32F3FFF2F48E61DC23 +:10B3C0001E8D4E9B1B35FCF17DCADA612AC9F7340C +:10B3D000D629F41E0BD8B2A91F7EFEF0B489F693CD +:10B3E0001E0B87EF798929635C74ED8CE8EAB170F4 +:10B3F000789E37320BE2F339165091188F2820A22D +:10B40000F87D87E1C81F33FFEF5B59E82F8B59B5F3 +:10B410007B6AE535783E125C4AFEEA1F30BDBFFA12 +:10B42000EE0689FCD53F003821F538BC1ED4975A6A +:10B430003E88F0C23C2AB11E7C1FE26990D03FF4E6 +:10B440000FEB6FCF8F79BDBFB3BFBE7E18870B7F69 +:10B45000907E9AFFB1C0C0E3157AEFE7FB94ED3F11 +:10B4600060DC8FD6182C0FE2F9A40C1B4A8C6732D3 +:10B47000F27BE86B8765F2FB6EAC9BF6F9EC8866B5 +:10B480005F0648FE16897B0E67C5F9DEDC0E0BC32E +:10B490007899A2DD075D789E371778B01BF5B0125A +:10B4A000A077568A36BEE6E2FE37A313EF2F6AFA7C +:10B4B0007F703E55D8A988FB02C0770D03D91F7B4A +:10B4C00086F373FAE6A6EE61781EA7C1F370D35136 +:10B4D000CACB8A97E20CF11D2667447B931BCA23D3 +:10B4E000E49D6283F61172C868F3D36326CB9BBADE +:10B4F000E99CCF28DE8B5A91B6C81188D8C7BD30D9 +:10B500008C8FCF2C41E64862C204C754398572ED56 +:10B51000AF8CEF67CD1EE827527E5E4C64917EFAB9 +:10B52000D6A66304EF722910C04ECC392C6C05FAF4 +:10B530009815BC730BDF37DE7814E3A94CF645DEB3 +:10B54000B03A38DECC1EE542A43C7D7598D8470B56 +:10B5500079FA2F4DBD85384E73538F862F86E7A617 +:10B56000C1647E8FBEB9E913FA6EA85289DF5EDD31 +:10B57000987F5085F2E3F017DFB531BB395CECA260 +:10B580009BF4EA74C107E8134B07FE39DE68243EDA +:10B590005B9C6E237FFDE237730FFA603D9B60BAC0 +:10B5A000F27780BB7F1C8E279390A7C04F7E940FAD +:10B5B000A61485FCF62EC764A2D3DFDB9F865F93BB +:10B5C00095D17B44A6741BD905570AE7B9287D0598 +:10B5D0007821F9BF58E0457B5FE9F8038CF60B8BC7 +:10B5E0001FE2FEBBC5B58CE2FD5923FC94F5F38D3B +:10B5F000A66712F12518F8D8D6042B0EBA78ACC974 +:10B60000C202F96087607C7C763F1DDB7C8A138FE9 +:10B61000FAD754BA6B307D6CCCC936147F8F8FFD4E +:10B62000B21B53F4D5E3F88E061642FB98CEE061C8 +:10B630007CE77CC8C3F871A23C2EC0F3F1A23C7E2B +:10B640001ACFA7FB5E902A11B0A873A5749B6B62FA +:10B650000ECAE9D98CDFB716EF2D6C11FA22D5E6A8 +:10B66000AAA9C4F2BB19DDBFD0CA9F14E5C9B60FA1 +:10B670005BB3518F4CD5B7DF28F030C4F661DB38AF +:10B680003A7FD2976BE73B89B6F347A97D91BE7CA1 +:10B690009D686FB79DEF1E87E539FAF11F15E5B17B +:10B6A000362E0F999FF1770144F923A2DC8AE53801 +:10B6B000BE9797CBDAFB17A2DE4A0107C6B691FF09 +:10B6C0007318F77F6E6DB214115D9A2E127D1E6B8A +:10B6D00062949F34DCC5EF6557717CBBDC9C1F1CFA +:10B6E0008D6CC0F700260DE7FBAA38B5C7E71B40F5 +:10B6F000EE69E52E077FEF40F698889FCC3621371C +:10B70000C47AEC931B5283973319F7975F8EAF611E +:10B71000A15D40FB6828FC205FA73D60608108793F +:10B7200099B230860522EA7B66BB74F9A4BB5374D8 +:10B73000F5DD53B374E5B6D2E1BA7236D545EB66A2 +:10B7400091E0AF98A2125DB9F60E03DB2EEA89F5FF +:10B750006BCCB95657EF7C811A8F3C7E6A22E81F6A +:10B760008A2BF05A503E2CB2670D41FDF35CD31882 +:10B7700042CEF3B0AEC06865BB9C3CDE7C179EE356 +:10B7800041F9BF36F9E8FB0E2857217D1AD69D0AEC +:10B79000F53B9A1C947FAAC943E9962695D2279B2C +:10B7A0000AA87C639397F24F40FF98AE837EF0FB2C +:10B7B000DAA62ACAAF69F253FEF1A669947FB429CA +:10B7C00040E9234DF3E9FBCAA606CAAF686AA4F4B0 +:10B7D000E1A620A5CD4DAD541E14F4DE25EEAFEE4E +:10B7E0002AE7F7D2A3E9F8F07049F75E9CBD3F7EE7 +:10B7F000E4E1E1183FD2D94376B8163F82F3A6FEC2 +:10B80000AC7CFED1FD6D1ACEFD09C359F7D258BEEE +:10B810009EE99C3677BF77592CF07D6A03A743E6F3 +:10B82000FE5E2A4F9ECF69B149E865E60EB2B4329A +:10B830003AADA77A67A5EE8A587EBE4DFE0CE6812A +:10B84000799689779288ED4206844B19C3F5A7460D +:10B85000D7BE793B399C38FF81E0DD21E0954B3B39 +:10B86000F9FB27556D6164FB185F03BD7F6299E6A4 +:10B870000F2B90BAFD017A8F61F8C509B0390379B1 +:10B8800073F17AA6429AB650BF6F4B995DA2DB174F +:10B89000C9171F632AC8015B917E7F1593B348D7F0 +:10B8A000CE92F6635DB9C9BD4C573EF3BECCE51EE2 +:10B8B000C4672A3FE731AF5ECA9201AE39ED6B082B +:10B8C000AE77041DCF4A2ADDE30EEED6E21EF8FE67 +:10B8D000E259A15F986535D963F94E9ECD8B0F1A59 +:10B8E000503F7CF66FF124979E79CA10427F2E88D4 +:10B8F0002703AEFF4230FBB0BC98F5501E435630D4 +:10B900003F8AA932E6AF62BDB4BF82FDC5EF866350 +:10B91000FCA81C78CA0AF933E9816779FC5A98F4C3 +:10B92000679EA0679EB69FDAA044FB79DF1A4E7C23 +:10B93000A8BFC7D622F6172D56EE7F5BEA2C1B82D6 +:10B9400076EBD941E20DED9E578FCC067CDB930F51 +:10B9500052AA7D7F54350C784FFB8F51FC3F0C98D9 +:10B960005DF0FF1F119E33A56F27A11BAA2EA7977D +:10B97000D6C159C9E79981F87D5DE6FC083B2E9C4C +:10B980009F22F0ABEC2EF7CC003C2A6F667B83AC99 +:10B990007F9C679A8E65633C8096CF13F1B23B9B88 +:10B9A00092732A23BE3B0B393C05ACBB0AF55541CB +:10B9B00091C11BC28E7D0E9D1FC39AD3E6C377072C +:10B9C0009412E64531378CB52D43DDADFC4DA6789C +:10B9D00027E5D0354C85FD8CCD1666181FA6F5CB16 +:10B9E000843FE4012137BF7454C6D37B92297DF292 +:10B9F0000F7524FBD2E6EB463EFAB2DDC8E7754888 +:10BA00005F5E60E3715C730B4C2155C2F7CBDAE8E3 +:10BA1000BD4465ABC4D232118E718407B62F96F83F +:10BA20003076C3081684F552EA0CFC05F9E44C584C +:10BA3000DD67C8163C09F56A0B4DDBD03ECB47BC31 +:10BA4000D8102F77E654E2D0390584DF3962DE79E9 +:10BA5000857CBDB6A447C1C3BC3E7C57746EBBE6B3 +:10BA6000C7D1CFF3D1D28A5BF1FDC5E66E99ABB5F4 +:10BA7000287CAE32768F98015D9FE901B8648233ED +:10BA8000AF10E5C2863216243DCEE757FB94C4368C +:10BA900065925CAA223D3EDAC022CF31B5B4B8909F +:10BAA000CBDF9786F3F7DAEC9E23C48FFDF9C3470B +:10BAB00066033E9E33B0023ABF35F0FDB116372320 +:10BAC000A31F00D29F146AFED2163609F5B6D340E2 +:10BAD00071A072470CDD4F959D0AC59FB7D82A1DEE +:10BAE000F7623F0E85CE6B26C863BBD18E363B0D09 +:10BAF00057A11D7E78DB8FBB317E474E5718FABDAC +:10BB00005A1C0AB743D20C1497A7382B2D78BE9332 +:10BB1000673B598EF83CD8F1437A8F417E50C4CEB2 +:10BB200008BF985190AC853550FFC13445BCEBE25D +:10BB3000AB1E95248E2654DC0F557D82FBEDC38E03 +:10BB4000F356DC17A8B6B9E40FAC2BE4FB44239EF4 +:10BB5000E341FEA925E79D28BF5EEF58EECA447B6E +:10BB60003AA4902D52F075730ABD3BD061A27711B3 +:10BB700034BC660415DD79607AA33E6F8E3A1734C3 +:10BB800046DD479B85E3939F781A0B47CCC7E8E1D6 +:10BB9000FB37E6B6D1FEA7AE50BC8729F273300F53 +:10BBA000A4D8690CA678013F873AE666E0BC2EBCB3 +:10BBB00014A0F8EFC1ECFFD242558C17B41AE8FD7F +:10BBC000DDB015E3C1B737312FDA79969042F1F83D +:10BBD0003B843CCBB171FEF717713E8F4E73DAF8A0 +:10BBE000BA5376C58462916E8ECE9220ACF3C25762 +:10BBF000273215F4608EC367407F7C4EA3C98BF655 +:10BC0000E7845FDA884FCEDB783C95D2F8888ADF0C +:10BC10009BB7951544DEB30B3539BC289FB6355913 +:10BC2000BC18A31E1A44BE663B0D14C7AE1A785C3E +:10BC300065BB588FED85B194AE1572E6692538194C +:10BC4000E17C1AE889F1F3075773FB78D1520BC1F5 +:10BC5000B1E8F56CB2AF06C3DB334D1E6F0EC2B355 +:10BC6000DA9082FEAAF29539ABF09D8C4576FE8E75 +:10BC7000B01C3F9CFCB6EC774686F67C73DCB5DEE8 +:10BC80005911F25D8E1F5B807C25CBC114F4E7FC5B +:10BC9000BCF0DC6D18570BF4DB84F9DDCFFDE13629 +:10BCA0008CA3DD690FA6609CED4BCFBDCFCB13837A +:10BCB0009B30CEF6E073C779797A30C500F9D79F0B +:10BCC000FB9097E7063761FEADE74EF1723C030348 +:10BCD000D9F9DE739FDE16447F8BC93B1F05F22F17 +:10BCE00000FE2258629D22FD40E0452B7F01BFC32C +:10BCF000066C8F48A3CBF78976FB0729FF9528EFC1 +:10BD00001AA4FF03A25D7890F68744BBC383B43FB7 +:10BD100022DA1D1DA4FCB7A2FC8D41FAFF77D1AE3B +:10BD20007B90F66F8B76EF0ED2FE0FA2DDB141CA8B +:10BD3000DF17E5FF19D5FF7151BF477CCFB2AF7E4A +:10BD40001FFDF7592047502E15D857BB709D6F6BBC +:10BD50002D25FE6F2EE3E7541ABF67498CDEF7AD41 +:10BD60002EE2EF8A551771F9FB67D13FF0E1E3C886 +:10BD7000778BDE9429AEA7D9E03D1D4239BACA407F +:10BD8000F6C0A2D7F97E7DD14A2514792FE7CF518D +:10BD9000F02F47F880715B3085F576A690C7F59B4C +:10BDA0003D1E6F75843C333AF47990170CE52EC82C +:10BDB0006F8ADF2E5859D15A00F95497812C10A55B +:10BDC000D612C6F73A14BBD00B8ED2B60284CFA6D9 +:10BDD000D03B059A9C67368FCEAFD16253E8DD36F3 +:10BDE000D9CECB27FC72AC03EDAC1616E8F6617B1E +:10BDF0008F4276FCC1D61207CA3D937DB603D7EFBA +:10BE0000BBC57C5E9575053128AFE5470D24BF0F96 +:10BE10003BF87ADFEAE1F14EA057E89E13C86B2F9A +:10BE2000EA887C165E8A7273E763FB66703F1FB315 +:10BE30008F2AA37B44DAF9B6A444EC03AE2BE2F8D4 +:10BE4000C9107A4441FD02E9D3A5E2FE4B90FBA361 +:10BE50003214E6498DB8C77B5D91CCEF1F2988234A +:10BE6000E84BAEA6F7AB862E5174E708690FE8F3EE +:10BE7000A628BDA144E995EC569093BAF313872EFA +:10BE80005F5424FC3C5EE6453B76C22F57933C3C16 +:10BE90008FFA4D1A5CEEF5C95F218F9F4604A01CF6 +:10BEA0000DF27BE4075797FC16E9BD68A581DE8D8E +:10BEB000BE5239FA678405F0901B90482FC0845217 +:10BEC00070DF74393CE41AFD2E7A57E332F8C85D0E +:10BED00057EA42799B1B50A8FF4BF4C665F0F5BCAE +:10BEE000E43D16403A3A63845D0D0C807E3B574C2E +:10BEF00007C6179B843F458B17568628FC5D7C71CF +:10BF00005F55167CFC30F3A9AE6C7C17A881FCFB56 +:10BF10008B773FE041BB7D8521E0C0FC51D7A45E1B +:10BF20001C67116CFA117F3BB10F7A1FF3B7B7FB97 +:10BF300000FECE90497BBF328CFFECC63820ED7DF1 +:10BF40004C0FD96BA2FEB5B75702DE3B1547219ABD +:10BF5000A04B775DB7DE781DD437B1BEFA78EFEE2F +:10BF6000B9C306F17EE6B8F595209776C730DDFBBC +:10BF7000A0BBD1CF4EFD4D588FEF81C27837C9B0ED +:10BF8000375B5B74F37A5B723F3CEB8AA7AC5F8AEA +:10BF90000E3BB14F7132FEAEFB19B5270E970FEC79 +:10BFA000577E5204F4ADED389914B95FD7EAC78BC8 +:10BFB000FA755DBD75BB54AABF94EAEFEF8D2B22D5 +:10BFC0007CF79645D68F137E8088FA2BBEAD7E8196 +:10BFD00006CFAEB76F2FE2F51FC5FA67D59E248A4C +:10BFE000AD898227E1D2FED77E5BFFC345FD33E1F9 +:10BFF000B7A9FE59D693549C49ED3661BB736FBC0B +:10C000005D26E69D84E738EFDA7C4F16815C6AC0D6 +:10C010003ED07E561A54FCDE696973A0FD6635B6C3 +:10C02000F9510EE7E03B5F63FAD3ADA83C465FFAF7 +:10C030003D9A9F3B2D2CA11AF9B5D140FB9BFD3DAC +:10C040008647902FB7A68D75E0FE79B7A9BBA408E7 +:10C05000EDD7BD36B25F0D199F59D16F6ECEE7EBAC +:10C06000DFEA6CF01641DE9A5E44EF74CA0F2DEAE7 +:10C07000A4F7C27FCADFD1527E660A6C477E0C2FBE +:10C080002A9813B1BED7151B09BE95AFD956E3FE4A +:10C0900060A5D1DB968F76B85DA1F84BE567FB26EE +:10C0A000917DF80B0323F90FF3AC807E5B6628F4D7 +:10C0B000FB0E4E14CF3C5844F8F0FB2BA0DED044CE +:10C0C00045C27B3A0F2B7E0B9E7798855DB7D5CB0B +:10C0D000EF6969E37E2CECCF8F8BF8BBEE5BD32E40 +:10C0E000BC37CF8DEF3098E87EA56DA1216C8AC357 +:10C0F000FB66DB4ECF437AC6F6ACC4FBC631298A59 +:10C1000003E7F7643594D1B95C277D0FD61A68DF51 +:10C1100090B0D0E043FF634C8E49E7EFB0C1389157 +:10C12000FE906F8A03C710EEABDE546E423C7BEE8E +:10C1300037D03BA48F7ADEB51800CEB8527D7BC7CE +:10C14000587D7B57A5BEDC5DAD2F4F9AAA2FF7DC3B +:10C150006D8AF2EBE8F33334BE029960033D15C3F8 +:10C160008B588CED4213EE7B56BC16C3883E4BD6E3 +:10C17000B7E5E3FA8CED257CC50C8F21BFC08A643E +:10C1800013C9F515C5DCAF7F28DD7413E5615EC802 +:10C190001F5BD38ED07EE412BCD84E7F8DFDDB5862 +:10C1A000C477B4338A7D7F291ACDF39E32F4E3310C +:10C1B0009287CF4B3EEF41C4F75BDC5FB1B591FB9B +:10C1C000B11F9DCAE311690665B8DE79FD38CBEA77 +:10C1D0006EDC97C5D95AEFC738CB68BC2689F38681 +:10C1E000AD78CB16F92EC0DF675EAEDD77C2EF65A6 +:10C1F000747B81DE1F1B3F82F38B53D809F19E8431 +:10C20000A296887B1349C26FF2F8D89956D41FBB07 +:10C21000C57B1E7DFDA934280F3D45BF72B124F6B4 +:10C2200053BCFD7AED9C47E4139D3CBFFBB0EB266D +:10C230005C5FEBA7BA4A70BFBF42D877F16926DFCF +:10C240003098D7DAA3A6A03412F20A3B6C04BB6084 +:10C25000B78B8F6B7A3D2688F7F3D67A4AE9BEDF33 +:10C260007562BC17CABDEFE07AEF857584715F6BAC +:10C27000DD5E6B8938370D027C685AE03EE56075FB +:10C2800009ED77D7FABC56D49B6BD3BC568C97B6C6 +:10C29000262B0E8C077579147A8F6DAD25E040FB47 +:10C2A000C7058AD484E749E96D13E99E1BE0DA509B +:10C2B000C68F1A988833C438BF0481CFAD9ED90E7B +:10C2C0007C1FC19DB3E747E8A74FC0FEE2783BC49F +:10C2D0009353E0697CB14A70BB45FF09B35FA0FA94 +:10C2E000F8D35216D19FA0A369220BE13E4D1B5FEC +:10C2F000EBA7AF7FE6A37380E5BFE5785B9ACEDF5F +:10C30000A132DDC7683FF742796027F2596F720C9E +:10C31000C9BB144F4A05F251CAD14D93F1FEC3F285 +:10C32000DFC6F071E6707E4F5198E57A9C7762C067 +:10C3300081788C5EAFC987DB6A902935BA44AFDF5C +:10C340006485B5CAAE4BD771B2C75D91376280F5CF +:10C350001CB55E928FF63E88FD47AFEB2DB1C74707 +:10C36000713D12F15DBE7CBE45EA5949723859A152 +:10C3700075961E351EBE6787798919548C4F5E5796 +:10C38000ECD4DEAD5211AFBB4D8E71367EDE4EFC6D +:10C3900055F1E2EABB7E07F90BF87B73A056EAD1B0 +:10C3A000B66ED28BFB03F9587FB312780AFDE99B76 +:10C3B0008F0DA17722CDB1FC9D4F53D4BB259ABEE2 +:10C3C0005857CCF7316AD4FB96DF35ED4C4B2B74C4 +:10C3D00000CFAC7BFEB77FB024FEE3ED9FB4C39DDE +:10C3E0004B6DB0A6B7ECBA653DC6475ADFE4E59B96 +:10C3F000211F54102F0BC9EF7268E8BD34FFE6F718 +:10C40000CCE4CF2A96BD1B30CF3EB0923F6EE7DE24 +:10C41000B1D3709D34DBCB54B4F79F11F267BB5896 +:10C42000CFD1F3924DDE00DA03D1DFB7168B73095B +:10C43000E63DD601F42D7EDA44EF25F5C547745864 +:10C44000F9EF331376E86C21CF66EF5B35F420C348 +:10C45000F7306AF615C3B8B3ED9549084FEA458938 +:10C460000540FE6D16E7B3A9EE1724943369EEC3B9 +:10C47000E528EFD359F752941BE90DFAF3B2D48BA8 +:10C480000AB5DB9DE2A3FEF007EF399B9858D3AEC7 +:10C49000005B8A723E859FB7981C31FC7EBAA7521A +:10C4A000779F597B47F655810F13E0D45802A94D69 +:10C4B000E1F7E7A3EA1F15F892D16F8FCE7FC791FE +:10C4C00063D4AF4DF92CF25D16DC9792D05AC8CFE9 +:10C4D0003F014F41DC87B278173F2FF5F9D4C8B838 +:10C4E000D65490BBE6128C3F09529C48B2B89FA02C +:10C4F000C5F500069CE877D3E23EB631BD3DA2A566 +:10C50000DAFE3CA751A67D47E1AB56BE3F686521E8 +:10C51000AB84FE3046722767353F9FD6FC62D5B8A4 +:10C5200098683D380C3CFEA793E29935BB0AE84B6E +:10C53000726765D47B4FDA7BD55F88F5B4B9C941A2 +:10C5400074D4CAD302D174D49F736AF5522FA6B2A1 +:10C55000404264BF21EA37B5710FF143EAC5A154E7 +:10C56000BEB949BD4CFF5983F49F4CFC3278FF693A +:10C5700054BE25FCAEF31640C593BD7B9C7E15E5ED +:10C580004A78A277003CA73EA0979323F7EBE5AE4D +:10C590008697CD8ACF5D03F8DEFC80C1DBC130FE1B +:10C5A000545FAF2AF3F74EFE7EB4563FEC9E82F501 +:10C5B00017F2FADF3BADAFEF2FDF1B5D9FE0BBE172 +:10C5C00062947D18459F687801AEC4DB22E01A674B +:10C5D000D1FFFEB869332E812BF18E08B86EF4E8D6 +:10C5E000EB07960E0CD74D05E66F854BAB77EB98B6 +:10C5F0002BAB173D8F2955E641F0CEEBDF31EDCA6D +:10C60000FAFDFEFC6FAF774F63F43841EDFC4867ED +:10C610008F243472FBDDC17A29CE44B33B5CCC213C +:10C62000E2BFB8DDF00EFE17F6B34B46F86F1D31D2 +:10C630001AF1EFBB7B9D8AF754B8BE62D5FC7D48EA +:10C64000D8971447BE7FDD0FD732EAF7658C772283 +:10C650003D6BF1A2DD5998CA2CC9687C794259F822 +:10C660000ED8F4119ABCE6F1E5C305EE9E4FE95CE5 +:10C67000E4A4751E72213CDF75DC7B47F8E68C482C +:10C68000ECAF3F98BF45C393C9D449BF3FA1B7D6CC +:10C69000E645FDF02E1641BBA76F3787D1AED6E237 +:10C6A000508FC54E3F92A8D2FB038BB1FF69774CE8 +:10C6B0005C8E79E95082BAC886F7977AB47B9E3F40 +:10C6C00042BC2DB40432920C74BE9A8FFB61E64FCB +:10C6D000109782FDC503C56968F0544A1CFF316993 +:10C6E0008120F65369E8DEEAC76F4A37DF673B12FD +:10C6F000F9FB47F8CECD00EB5FC34385E8E7A0D157 +:10C70000FB552FCCEFE09A78BA0F3F3BE18EE9F86A +:10C7100036CA1C833F090FD023E07E8CE0B6CDC81B +:10C720004846B88D026E4BA2C0BB2FE7DBE0EE8B14 +:10C7300097F9A9A4BD534EF917834EBA776E367C8C +:10C74000F1EE14D4C3C5062FDA9D9BC1BEC077D6C7 +:10C75000FE8FC0F7163C6371D1777A7FCD23EE5FF1 +:10C7600079D61BE8BD157FC54B44A7A7EB6C5EDCF3 +:10C77000B7CF602ABD6F3A4BDC47F963F97FBFD270 +:10C7800003F3DB3522F02CD2E79E04C3D077098E69 +:10C790004021BD6735F6CAE267B573F8C9C23E9855 +:10C7A00023F03885F9286EF7361630E2B86F9F35DA +:10C7B000F9D02E7D5BC423DFC182F4FD4E16A2F4B6 +:10C7C000FB2C4CF57F802FB742FEADD811E98D00D0 +:10C7D0005FCD13F9B9B81E23F0FE8AE0977BDC9C8D +:10C7E0005F3E1E82786F4FBC22FEAD9138FE968C64 +:10C7F000081CC1798FB3A86E2FC2E41897867E9467 +:10C80000BEF55399C8F94F71E47EDBFAE93EAFDD1E +:10C81000BBF7D992CBF0DD2DFE73A3EF3E8A17C78D +:10C82000B87C37D0A15BE5F70D416CD88340A7AA4F +:10C830007299E2F6567C2EEE49A31303EAFD669444 +:10C840004CEF8469E792B788FE6E49E3F706ABCBFD +:10C85000A7B4C4035E267CD5531A86B42A4D7F8FB5 +:10C8600070A2BB839E0E9F94A3FF7E136BA303E273 +:10C87000EA227D9CF92D51FECF833836F0D527234F +:10C8800044BCE470363CF2BEC1ADA2EDF9EA2F4CD7 +:10C89000E760FCF491815EC4E3A29BFF389DF675CE +:10C8A0000A7BF32A985FDDBFCB644F7ED80433C97F +:10C8B000C7B86A0BF381C17F0AEC0ACC9F6EF250B5 +:10C8C000FA29D801987ED65440E5679BBC941F3F57 +:10C8D000D2FF17A4F3CCD6CF15D4472BB4786C0174 +:10C8E000871657B842C44F2CB62F3A86F10B8B29C6 +:10C8F000E09DC1626F9B80E0DFBBBFF308A6F05DE7 +:10C90000C67DC8E23512F975E61C0E2C4732CF7B86 +:10C91000A3E7161413A37F7F3209F7E9B568C702AE +:10C92000EB2F76F92C23617C5FD789230950FFE335 +:10C93000A63104DF274D3E82EF4F4D55944E1FE93F +:10C940008FA37AEC737A6FE9E65D2714FC3D68E308 +:10C950007D12F9EFAFF7B15008F0BAC1C8E5FB0698 +:10C9600090EFB83ECB8B276F7900E11B11F08C0460 +:10C97000FCDDE69A353E01BEDF32668682F5EEF8D2 +:10C980000A7450663F1F5E8EAFCF1C90083F670E43 +:10C9900038091F1A9E6A05BDCEEC2BBC15DF1F3B64 +:10C9A0007054A6F8D3F3170D04DFF96331149F1AFE +:10C9B000DD7ED1DEEC21688FFD09E887071F8BF64D +:10C9C00016923FFE4FCFFF488D8CFBFD93ABF3C219 +:10C9D000FB28A7FE8BCB29B0374F6D423996964284 +:10C9E000EFE8F4C5ABB18658D4637526B1BE40CE2E +:10C9F00060FE4F317C1F5CF68BD40A5C2F381EC65C +:10CA00007B99C5EF9B80FE8EFF18FADBB7C943EF19 +:10CA1000EE7CB6FB892C1C7F67E79CF73741FF67EC +:10CA200042FCF74D9C619D677F85F274BB8DFC963F +:10CA30002B24800BF5E98E14CA17484A4C2339334E +:10CA400042B46E0B2455C177C816BEB03105F90B40 +:10CA5000EF8B635CFDCB6B62494EBD6CF41E6FC403 +:10CA6000FEB6F0FE9E7DECA10FF763FA686DC94338 +:10CA700090DE3ED245789FFD2F0B86637BD0D7F4A6 +:10CA80007B959F7B510AA31FA4B8FDE0328C631AEB +:10CA9000B9F9842105D251DBA5664C0BD3271D457E +:10CAA000FFC1DD235582E3AA5D9932C6A60F4F0967 +:10CAB000BD7F038F1BD1E9F7A2F6CF2B709BA9E9AD +:10CAC000F9E152E7A71DB82F1E7AAC84DFEFE2EF41 +:10CAD00044EFED9AF2CEF719CE032C08847B8689B9 +:10CAE000E22E5828D881743E1328F0D2FB26FEE0AF +:10CAF00046E4AF3381247A4F7A9F211887BF2F29CC +:10CB0000789CFF5E9F17B7BF1587F114F17B8C0CE3 +:10CB10007FFF74EDA8DE09141F92AED27E3C7DEB40 +:10CB20008D55889FBA3D7B3BA89F85162FFA63E7FA +:10CB3000EFFD82EEBDB0893C0EF5CC1E9E7FA4D2E7 +:10CB400047EF8ACFEFF833CF77FB29EF97839974BC +:10CB50007F6216B7779E10FA8CF58C6091EF1269A0 +:10CB6000F47A048AB17C43663019DF9FD2F420E85E +:10CB7000AF265C7FE876A4F68E29FCBEFA15EA2F74 +:10CB800093D0475A7F4F98F87BB92846F0F7CF6C7F +:10CB90003671BDBB03E40DF28BA67761DCC7715C17 +:10CBA00093B82F930A4A7614CC27F5093397DF57A9 +:10CBB000387EF4BD52CD0E9996D04CF7473F4B0DC1 +:10CBC0003C89F241BB47CA142FBDEFF741AA6FF36E +:10CBD000C8D1FCDD0C9C03E8C510D6AB93C18ECA4E +:10CBE0008EB0A32C57A617FF96EA7B06DB5F69FD84 +:10CBF00068393C56C0BFD86E203C2C5E67267FD873 +:10CC00005871BF74ECF963B1284F16FFB984E44A38 +:10CC1000336303E2E795261EE7FD6BF423407ADDDC +:10CC2000973D32ED470E1B161E01FD4A2090FFB0C6 +:10CC3000B739BE94F23E24F7F55F1A06DC2F6A2955 +:10CC4000D0EB359C9FEF2BBDFFE186AF1CF4FB2999 +:10CC500099CD7545F3EE7F67473F7FEDBD2B985F1C +:10CC60000FEAF7C59F1B887F177F5E4272B3EB0AFE +:10CC7000E76B75FBFE03E91A3D1F80FFBF0682BF0D +:10CC80008FDF7BAF0CFE072546BFD707D415F9B75A +:10CC9000BBC47B025D0B8AE85D8B7DF82E08CACD94 +:10CCA000C9FCDE5117F60DF5BB121DF4EEC6CB46DE +:10CCB0009E0FDE29DA8B771ABBEE4CE1EF66981BEC +:10CCC0007E578CFD37F3F8B82E63887E1F6CD74FE4 +:10CCD00013E83E81163F7E4CC8ED6629FC7D7A0F35 +:10CCE000E47313E3EFEA8553EB4BF11D90E154FF3E +:10CCF00098F8FDC957FAAEDE5D823EED1DA11DEB31 +:10CD0000018EFF07358A15A9008000000000000091 +:10CD10001F8B080000000000000BED7D0B7894D500 +:10CD2000B5E8FEE79F99CC24936412421E8484C91F +:10CD3000831024E0E40501421820A1A8680308023A +:10CD4000C638212184BC0848CF492D3583090F15E9 +:10CD50006B38468D8A3A58A0A0600705440D9E01A5 +:10CD6000D4521F35D5EAB1DA6202880F1E0941FD9F +:10CD7000B0D7DBDEB5D6DE3B33FF2451DB73FDEEEF +:10CD800077BEEFA65FDDEC7FBFD75A7BEDB5D763EB +:10CD90004FDBBC74BBCBC6D80895357832186B4BCB +:10CDA00072C44542FAA1812DC6FC9F19FCC531F61B +:10CDB0009881B9CC918C5D655F166D1FCE98F38616 +:10CDC000103D0BC742479C92C3D82315A3D9DD0A57 +:10CDD000645B1F622C9AB1C526467F4B83C326B085 +:10CDE000ABE99F0ED344C616F2CF6CC9F29D66A77D +:10CDF00005F255E66E6502631F54DD196A83F1166C +:10CE00003A556F501854B8B1C8D195CEEBFE2319DE +:10CE1000C775D0B8AC6218639321D57BCB198CFB56 +:10CE200072AF89DD9D0475F06FBA2F65CCC518D43B +:10CE3000FFCCCCC7AFF3CCB8FF8CEC0FFE5F65B472 +:10CE40006C56C2B13CD1CD60FCFD239CA3EDB98CE6 +:10CE5000AD3A7CCDFD674CBE7A15CB8BD298CE37E0 +:10CE60006EE03881E335BB752E038C37CAB420E3FE +:10CE70000C346986021DCCD3E531BB7726E1BC7B3F +:10CE8000FFBC02F2CD8BAFB2DF0DD939F34D0E25C9 +:10CE90008AB1BE0341EE2005BF073B705DCD47421E +:10CEA000DD3AC8DFAA70F8372B8CBEBBF61BDC3B23 +:10CEB000E15BADD1BD6717B4AB7D79AC1D4666872C +:10CEC0008CF01F2C7F31849787399236E460790C7F +:10CED000E1F725832D9CCA7FAF322A0FF6A64500C5 +:10CEE000BC1B639DB310AE238200FF16EC977F3FFF +:10CEF00089EB00F89C846E11BFAE8650EA9789BC1E +:10CF0000F317C3DC77D37A1C71CB317FDB385A8FB0 +:10CF100013E701F362F50AADF7A4D57D571A949F84 +:10CF2000EC184EF38812F470B2F8EBB72641BD93BB +:10CF300087553BF6F99746D56B0CC3728E0F65BECD +:10CF400029AD1DDA9D7E31D41E04E525F7D5BC89B7 +:10CF5000DF4BEEAC9B4B69F5BA1B18D4EFBAF3A3C9 +:10CF60004467C6407C94D4422B3F3CAEB23B4A114E +:10CF7000BFF7D89D65B8DE55195D950CE8EAA2B1FA +:10CF8000F371A632F6FE4867057EEF79E1D35DF8CE +:10CF90001DF094563C1E96A1073A41FAED9A407452 +:10CFA000BD4AD0EFB04C6735F607702C65298C85EB +:10CFB00064741A711E6CDDF01F44275F74EC3CA48E +:10CFC000C03835C11DF594AAEE09D8CF39C51BA6C6 +:10CFD000A4101C9DB8FFCE5BBD61880FA70EF28028 +:10CFE0009F9ADDDA75E19F1EE65583FF8076351E38 +:10CFF000D561C6FDC3DC469C7F0D33FAEA27F17D7F +:10D00000887400FD3C49FBD5F297D25F001EAAF759 +:10D010008CCDBA1BF0531371F85753A91EB493FB70 +:10D02000451D9897EB19381FBEBEF3621F9C872FD2 +:10D0300006A49FBD419CFE19A78F8B7BE204FD7067 +:10D04000BABDB8678C1BE7132DF6CD45C5A50BC639 +:10D0500076BF64F69D302F66F74C9C371E67EF99BC +:10D06000383F94B10715CE9F6A86792622BF92FC7D +:10D070008B993C13E641394BF74C980FF55F12F54D +:10D0800058B1278DBEBB3D69D8FE908E55213CE539 +:10D090007CAA9F8EDF4EF030F1FD5AFDF438828F6E +:10D0A0001CA719F94838A6409F6103D7FD5BBBC296 +:10D0B000F77FE8C418E46B43E13F3D765806B2922F +:10D0C0008B4B8CB73AA0DF31ED464D3FB2DE58B7FF +:10D0D000F6FB61D1FFA8007C8E507B8F06C17CD906 +:10D0E000AF014E6CE078FF89ED804E9F7AAA1F7FDA +:10D0F0002AC72763364937368213C7D39F8D124F0D +:10D100006BE3815FD7204C927DF03A94E98C8F8459 +:10D11000F422E661FE8722200F69BD80BFCC4BB8A8 +:10D1200007D2DF9D7FAE8CEF82F6E7ED3A9A57206B +:10D130005CD703FCB0BCD9C06E2D86F65F349D4829 +:10D140003963F0ADE76C93C301474D7FBEB23DD369 +:10D1500084FB6EC5B64CD3323FB837EFCE3E610389 +:10D16000BC9EDFADC79158B3DEFDAB2951F85DF52C +:10D17000B818959B1C380FCBB13F60BDCA6D1159D3 +:10D18000AACDD77E457B91A3C20FFEE3766BF1312A +:10D19000DEA3CD5F7D589BFF1AB95AEE3FDF2ED339 +:10D1A000ABCD679FD0E63FFDD3DA45B80D9ECFE308 +:10D1B000FBE63377A8DB0470ADFA68F6093C473F1D +:10D1C0003BF47C18E2ABE6AF15AFC5335C87964EF7 +:10D1D000018F8A1ED6EBDAA510BDAC7407EE5FC1D5 +:10D1E0003706ECEBF5B41EDC59FE741388DF73CC04 +:10D1F000B3C801F455DBF86ECA996C98D75C20640B +:10D2000098CF64CF5623B30C1C6F28FEC12C0E1B85 +:10D2100003FA2BCBE365531A67B1D3D01FDBF2C7F8 +:10D22000D9B85FCBEE5148DE287B6ECC2B4837DD7A +:10D23000FB975C4BE9A239048772E630223F5CD150 +:10D24000A17843216FCDB31DEE8276CBDD8A1DE739 +:10D25000BDAC25C8C7CFE0FF155B02E6D1E6570E8F +:10D26000F35F71F8E8370AF45FB54DDB6E25C00B4C +:10D27000CF8FEA1DFF08F2FF0E8210C16B4AC776FE +:10D2800015D7BD5CCC5F9E7FCC55C0707D537813A5 +:10D290007606FF03E746F028676E66AEEF1C9CD269 +:10D2A000C6DB03E32BC375D7598C365C779D897930 +:10D2B00043603E27428D0E2B7CBFDC1E4AF2436545 +:10D2C000107399B22865E62C6C670FC77667DF5636 +:10D2D000494EAA03DE43FD3CA1B89BB11F55E1F9BD +:10D2E0005FF3FC4AE6A5F520DD38FCD7E9D6E65920 +:10D2F000EB30924B6AF5DEA308976AD645F066805C +:10D300004F878423C0AD16D6F94124CA5FDAF6AB45 +:10D310009887EAAF3AFC8F20FFEF20673213D4DF03 +:10D32000160C29CDDF4D70548DCCA18379AA7704DA +:10D33000BB5D24871407239D1AF0BC00B8B6DDE559 +:10D3400048C3796F501C6956E4635BCD76E4634B48 +:10D35000B7F373A82D02E45768DFB6F22A6ABF1448 +:10D36000E529945396707ED716E1F122DF6F7B207A +:10D3700089CB537F57092EBDF79ADD4F42FDB64C3E +:10D380002EF7B46D1D43ED915F923C756F286F3F92 +:10D390008FC3B56DB8D5ED82FC873845804FDB76FD +:10D3A000479A89DA819C96E43BA7A43CFD9B51CE29 +:10D3B000DB10DF72BD52FE66553F4CDEDC29CECF5E +:10D3C000DEAD304FE8FF8C52FC9ACE4F1E6EC9E4A2 +:10D3D000FC7FE24CC72E51CF8EF52A74F3EE9E0EE1 +:10D3E000F3AD7850676B4EF2C19D391C6908E73385 +:10D3F0005BCD5948671367021F06FA3B99C9F97953 +:10D40000480E73B821BD57F47B6FA64E93C6060332 +:10D41000FD413F678ABC06C46F684EB111CF4338E7 +:10D42000C3899F07AEE361D14F85B1F8F56983CC1D +:10D43000A79F0E0AB9DC7266B5F2249F17C7F3C422 +:10D44000FF30DB9B69DD7C7E12EE4037B974DE0B6A +:10D45000BE15D14F27EE3D6640ED56294F23FE15F0 +:10D460000D9D103CDBEE1D4F785C2AF0CCEE350BA9 +:10D470003A61EC6F585E64A372A013824F5B26E0A2 +:10D48000CDE23BF7DAE639E222FCCE23A0032A07FD +:10D490007CEFCF1C3EF0BE25F1CDF4EEDCE2D0A156 +:10D4A000F1BD2C2F62A202A08ED7335710C005CF3A +:10D4B0003C82CB5D7AF79D309F917A0EFF043DA7A9 +:10D4C0002FE0CEAEE02CAAEF3042BEECFE15CC0130 +:10D4D000F5CBE2995DE1F55938D6876E5448F1CC29 +:10D4E000C07665E1BCDFB218E6BE53C8FDC8AF52D6 +:10D4F000314DA67E1DBA48DE3E2C8BDABB74BCBD16 +:10D50000430FE9A814BE5F7A3704D1FE29DB94905B +:10D5100086743077A6960E52B338DDC8B435CB2664 +:10D52000CE197B2CEEEF652D63E9DC683617D71D2D +:10D53000447CED0B2179B06CE32DD7E7E2FC9E191A +:10D5400086120EFBE286FD1391DE96B52CF9D97B8F +:10D55000781FD96DA6EFFBB29C1FE3FEFA42B1958E +:10D560001E840FCB161E37C6427BA767DE851721A8 +:10D57000BDC1B5FF0F2817DC70A34AF56F609EAFE1 +:10D580003F44BED0C2C7B9DE75491F0BFD5D9FAFDA +:10D59000302CEF365B1357C3FCCB04FECE09FA6D7B +:10D5A00036B3C5CF5A705E0969C9F0FD7A94540745 +:10D5B0009103C76609397186B20DE59E51B3F8FE35 +:10D5C00092F5B11FECF76A8407D4FB5AEC2B99074C +:10D5D000B852FD8ACD41DD2961981ABC63205D9463 +:10D5E00033F36FB8CEB9C96C36DE9B7A7FAEB22703 +:10D5F00069BEBD65B4EF43D36CB8EF9D8C7989EFFC +:10D60000B9C712DD77CFE8EDDE04F9EEED63ECCDBE +:10D61000C4D7F9FD7DB995D1F9DE3D83F335C95FF6 +:10D620004E5ABB42895EC57DBE5C90C6278DB31E37 +:10D630009C04F5CB2DC66E3C0F963FB020CC06F374 +:10D640002C6F83FB3C9C636C8BF63E0FF7EDA8AC14 +:10D65000DC81F7F2C0FB37D20CD251C51685E870D9 +:10D6600054B3DD18477C4CB1E2FA2A2CDE543CFF5F +:10D670002AEC663B969F6F72DC7F06E4C38B4D738A +:10D680002865DF02DC619E5721F260DFA7673B93CC +:10D69000B2008E65AD65749F0CC970127F720ABAB4 +:10D6A0009B0B605690DFE8BBE2701FBE9329BE471C +:10D6B0005AD32C44CF668670E83658D3705EDD1B93 +:10D6C000CC3A3C37E7DEC9E91AF699490FEDEFD2BB +:10D6D000B360DCEF3DD81EC62B59AF2FDE0EF9919B +:10D6E00026A60F8D44BACA24BA6ECF717E8DFCE097 +:10D6F000B35FB23C940BCAB76CA5F948BA60FACED6 +:10D70000C26128E7ED4CCAC2FBB5A4A3F69C997987 +:10D7100008BF7E7AB851213A80F4680AD1C3FC6907 +:10D72000583E77A637750DCCAB48AD650ED433C4E3 +:10D73000327B10CCBF8FF5923CD107F2049E6792EA +:10D740009F48BE0174E03045FBF0BBAB09A6023C2C +:10D7500079779389D2A79AAC4C0FF0DDDB144BF9A3 +:10D76000679A6C947A9AD2E9FBB34D76CA1F68CA5D +:10D77000A3FCA12607E50F37CDA1F4C5A662FA2EBA +:10D78000F912C085F890E42B921F497A927C299077 +:10D790008E4A01BC0559D49EF89EE477B80E5D967A +:10D7A0008F1F49FC262BC5AED824E4635D4B905FE8 +:10D7B00014A9E7F73D0FF0EDABB2D8836C0817CE94 +:10D7C000F7FA2C263AE7138DEC30DEFF9B573BBA75 +:10D7D00037F99DAB3757294CEF47B7B7349899DEE7 +:10D7E0008F6E6F6D8CD0E44B1ADF7D3506FAFF47E4 +:10D7F000827335D2DFC93BCE3EF65FF0FD893BBE7A +:10D80000188DF88679EC7C08C75D17DC3F8F48CC13 +:10D81000B718E89C1915CCEF49A382F93D09FF1010 +:10D820003FCB18DFA74FDCF137DAE7DD8D41361546 +:10D83000E50FC417C0F72F025FCB1A83088E651B54 +:10D840004EEF7B1EF7FB3A23F1BB652D627F6E0620 +:10D85000B8FAC96DA7E218C9678A83B14680DFA903 +:10D860005F1ABD70F6B3538AC9AD4043052E4D25EE +:10D8700008D7CDBFFB00E56DA5F104C9C74E93C520 +:10D88000ABE2FC5C86F3FEFD298DAF513DD635320F +:10D89000E26C086D4586700CC97118914F206D239C +:10D8A000FE96A51F63B8BF59AB621D0DEBAA10DF32 +:10D8B0002B362B247748F83F92A5D2BE7A2F534FB0 +:10D8C0006936EED9E1C4C0E89C92740B7CC3E1C612 +:10D8D000FDD19A69ACF4E3C7CBC4F7F2741DA5F28D +:10D8E000FB7BB02D914EB2114990DE9D9E6C5C4E3B +:10D8F000FCCE66447E20EB2F4BCFDA989C83FDCC88 +:10D9000088627EFB7257969EDABD9769E5F331C156 +:10D910003906ED6A87380FA47CF219FE7332CD9F69 +:10D92000EE5FD5CF3CFDCC8BA897F82888F0547DCE +:10D93000B5D06F64B8272E20B9C66151609DF5023D +:10D94000FF854FFF35AC0BCA571DE0FA5348BB317A +:10D95000AD5F5745FAB27AB88F1644227F359CEAFC +:10D96000F2A3CB579EF928AC8BEE17AE785D2CA6B0 +:10D97000DE780669FD81D3B319F6C77A375A2D03CD +:10D98000DBAD52BEA57BA65C47D191AFA2697CE519 +:10D990004A34D53FB2217A303DC82AA63FD5BF7F51 +:10D9A00049CFE0D0E8D556B12D975498EFAA7573BA +:10D9B0003E453A0FACFF41566814D20F9BC42691E6 +:10D9C0001E43CF7488EF35260E873EF7E870F61DAC +:10D9D000FA9755EDD00844AD3EBD2DDC0EF3ED6158 +:10D9E0006CCE607849C8E6E7F405D8470CEE523DA6 +:10D9F0007B55BA2FF4EC0D25FAAFDF7BFF6B53217B +:10DA00005FBF43C161591DEB2438D51F5099C9FF31 +:10DA10003C43FDCEB0A1E759F3746803D2D34A8FDB +:10DA2000E2D809F3E933D9C287FBCDE76F829E6A5A +:10DA3000823C1309AE62FEBD829FC97A2B3BEE3752 +:10DA400022BEA0DE45925F7E1BC2486FC67AFF8071 +:10DA5000F33CB72DDB8EFABD959EFDF574FEEF0D00 +:10DA6000B18E86757C21F4FCB21F6336DF4FC66C25 +:10DA70002E6F9C13FADC73CFA8C487709EB80FBFBB +:10DA80004039D76F9E16D1CE22E0F61CEEC75C5F00 +:10DA9000FD959EEEB054A8FFE9E177298DCEE6EB27 +:10DAA0005A69E99C80E7E6A70742E6B8297D74F643 +:10DAB0004B30DE05CF8C28C56F5FA5641B383EB6A2 +:10DAC000A973105ECC3D4CC8F91E5ACFB9BDF10AFE +:10DAD000DD6F11DE20E79F3BF05C988EF6AD4B8347 +:10DAE000479D89EB6983226C42CE34B5A2BCB11448 +:10DAF000A4BB70E07775072ED1F91BF85DD6A7FDA2 +:10DB00001687F7EF5ED26BC09F0EE9B7CECA715E83 +:10DB1000A466C4E03E28BDDA76D3CDC8C7DE307037 +:10DB20003C8CB43D84F7AAD2B78791DE628DC116D2 +:10DB300083F92FDF848B20CCBB345BECEFD8AE5C59 +:10DB4000D4737627F173BD76335C54603D2300EFC8 +:10DB50002E5872AD5B654EC8ABE23E734D7632AD6A +:10DB6000EF912A9DC34876166F1AEA3D4F1A994BDA +:10DB70004579F95933B7072473BDFE2348EF90D692 +:10DB8000467AD386A1FE4BE0B1763E94FBE1B3F634 +:10DB9000496F1ACA2FE78D5CCF87E5564CB378BD25 +:10DBA000664137D80FF6DB9D64BD4872E6C15086EA +:10DBB000F2BEEEF950AE57F88DF9C920BF737389E4 +:10DBC000A02B90995CB87ED74E3E3F9C17CACF2BB6 +:10DBD0008DAD69285FCA715786B5D278E7C5782BB5 +:10DBE000835BB97DC2C8F591589FC63730B2A3F4A4 +:10DBF000EE092239F58BB8CE4338FE177BC6323C8E +:10DC0000C7BB93DC9587A91CE437C047F553415E39 +:10DC10009CEFE77B42DD0CEA7F6EE0F2D0E7A1D11A +:10DC2000240F9D087DB094EC323B8214D4AB7CAEC3 +:10DC300030632C96EFE4768CEAA646B23F54C37666 +:10DC4000675994CE6191583E96F42D9FFF1EF6A918 +:10DC500042DF37E377276B2DBD1DF7DDEE10D2BB1A +:10DC60007DF1D4FF1A3B98DDA27A8756BF24E940A4 +:10DC700096DF9ECDEF1BB767F37BC11DD9FC9CA936 +:10DC80000BF13C984CEBE4FB15F040F72ED81FD17C +:10DC9000A8EF3EE979215AB1209CBD698F22DC773B +:10DCA000F3FBCD177B0D6477A97E3ED4417A9C4D62 +:10DCB0009374785E54AB5C0EAED601F82055EED866 +:10DCC0009D867276F31E7316C203E04DF7C8DE9D83 +:10DCD000AA18878FFBF9AE04AED7F78AFCA1F1A48E +:10DCE000D79F1BC96E9D4F72CEB60908D7CB3B425A +:10DCF000744817308E4301F854DFFE0B0ECFF04A04 +:10DD000092CB61FF11BFAC15FCB26ED3D4F0A9B8B1 +:10DD10009FDE5619CA0597F5F618E48781F07A4B0D +:10DD2000F0959A438F19D16E570BFBC609FBA64697 +:10DD3000D8C76A9E5248AEABD938F521E2837F300E +:10DD4000B0D1308FF39EFBC3FCF1F1BCE067BEF6AF +:10DD500076AA5F03F579FB37C2683EBB0C769C4F11 +:10DD6000201E7F70FBA7D41FD4BE9F3E3C70AE4FD9 +:10DD700018B8EECBACF3DF3E427EB2D74CFA2BC0E4 +:10DD80007B22CA1DE70C9E4A5CF7B97D66E233E749 +:10DD900022F87EFF14F8A16B0CCEE3BAFB48BFF16A +:10DDA000CE0286E7C10AB7B65F396E87E0BF75C39A +:10DDB000ECE1A827AB033C607F80979F52FBB70D37 +:10DDC000D43E701D8F8A76FDFB735F08D1CBB911ED +:10DDD0001C1FE79E1943E74A7704A773986F22DE5A +:10DDE00057CE45F094A1300274502DEEA3E766782B +:10DDF000E8FE7D4ED94F69B781B7AB6E147663A04C +:10DE0000BB58A41BA449B48799B674A23C81FAEA12 +:10DE10008959947A832207EA9D913EF11C8ACAE1CE +:10DE2000FB8BE178D1C2FE41728AC7887CD929E494 +:10DE3000B8DABD03ED7088DFDABD0AD9912E8B7395 +:10DE400010671D25F5E5408F352EC561C6F9B4ACC8 +:10DE50005E4976A486AD3723BDCB75D4E8D91CBC0A +:10DE60000F752B2ACDA7DB0CFB06E1E03F9E9FDC64 +:10DE7000F577C10FF0CF1A4D722609D7BA1C1BA730 +:10DE80001FC8B6427FB52DCA161A2749DE2BF9FAEC +:10DE9000249C002C46D497C17D9F970FB17E39CF2B +:10DEA000C0F5CBF944E770FEDE9D64BB2F1FF1FD8A +:10DEB000966AC77BFAE56FB3C323BF432EC39B5B50 +:10DEC000BFDE18E69F823405EB3A8BFC0DF733EA90 +:10DED000A5619E69DBB4F690F41DDAFC557BB5F9BB +:10DEE0008C03DAFC840E6DDEFE8A361F22C6957026 +:10DEF000C27BAF6D0CBFF7628AF75E5B10BFF76243 +:10DF00001EEFBD98E2BD17BFE3BD17F378EFC53C28 +:10DF1000DE7B318FF75E4CF1DE8BDF6F1470AA155C +:10DF20007A47C403DA65D80B666967A7FDD2B324C4 +:10DF30009AF8A7B493F6ACCCA07CBF5E679E89F438 +:10DF40003AA4BB01B964C1486741CE70B49F766EF4 +:10DF50008C43BCE9BB489FBBEA45AECFADCD325B3D +:10DF600050CFD0B5E1D38D283EA58D74CECA81F5B2 +:10DF7000F6187A77111DE8BDC437BAD6DBDE9ECE1F +:10DF8000F147FA0E6689A4FB49199E779143E33164 +:10DF9000D0AEC2B668ED28817695407B4A201D48F8 +:10DFA0003BCA1386DE38E4F7A7F798B6E0FC4F0BC0 +:10DFB0003D195B6C22F94BCAD545AA85E0B4E65EF3 +:10DFC000E5493CA72A7222A97DDF0990B707396F7E +:10DFD000655A7E259BE4EAFEFC164547761AA78320 +:10DFE000CEA1DBC49C1295DEEE4D4823A13A3AC780 +:10DFF0002F5B74742FB8FC2795E48831ED3ACD7A05 +:10E00000C6BA8335F4356E7764803D7084A6FED53C +:10E01000879303EC815769ED5437AE3F8AF7EB05E0 +:10E020005BB235F52A8AA706C051CC5BC8A5CDEBFB +:10E03000DA1391FFDC16DA47F3BFEDA099FC2E2A24 +:10E04000E07C71C0BAAB3003FCB1CAE4B801E1575F +:10E05000E53144A05EAB5C9C3FAC517B1E57E99917 +:10E06000CB1AE9A3BB2A2B734440FB0B99ADBB74BD +:10E0700080B70BBA6D0FE6DBD0BEB43DD10A74B5E4 +:10E0800056F1444F86FE4E4738FF03E933D1E0FD99 +:10E090005509F2CBFD296C3DD43BBDE5B93092BBAF +:10E0A000059D251AACC188EFEDAD2ADD0B503F85EB +:10E0B000FA20490FDB5B8705A75A7CEBF4E1FF5B95 +:10E0C0005A1FE085FC46FA2CC746DE86729C87AF55 +:10E0D000B76A86E2223959AC678D3857580BEF671B +:10E0E000ADC89F11F705B9BEF3638F4EB0A15DB304 +:10E0F000E970A28A7C5CB777571CCA1731CE7DB80D +:10E100007FAAB68FFEAF7C18B7FA3D95A11DF99393 +:10E11000B659619351FEDC67B0CF85FCA6D65F1B74 +:10E12000F15E50AD771BF1DE59B567BB11EDFF3FD6 +:10E13000D9BD9DBE57EE2EA3FBF60AD640F7C8CF39 +:10E140000CFC9C96F0A89AA96CB3C2BC87E772B984 +:10E15000AF2A98FB8314A9F9AF46E17A772B99B8D7 +:10E16000DE1B8BF71BCBE0FBEF047F09DC1F7D6F11 +:10E170002E281A8E7A250FB7830EB51F167AC7D2AE +:10E180007E58702589D21BAF8CA37BD57BAC783CA5 +:10E19000F1898C80FBEC9B2AD79B75F07D5065F450 +:10E1A000462DC07DF2B281F6491DF0AFBC2CBC27D4 +:10E1B000333605D2E27C5543AFAB0A4334F4BC9806 +:10E1C000456AECCA8BD8084DFEC6B9299AFA37DDE4 +:10E1D000382E80FEB37CE5C447A668FC57EAD6B962 +:10E1E0006C0AE9D1666ABF43BA8EE8EC5A4DFB3A35 +:10E1F00036DF570FEFC13BFE487066ACD388F7ADF2 +:10E200002A1DF7D759ECEC16DFBBE83B2C44B30FC3 +:10E2100047A5D8FF8B9F8B06D2CF4BFDF462FC77CE +:10E22000CA60E722205A8C1BAE72FD82532B777492 +:10E23000D2FD93713CD4097D4F5D3AD7F7D4B93AFA +:10E240008D0D1682BF3E1E4052DFAA903E0FEA9B04 +:10E25000E223797E1D7E3F60F0E95918EFEF0A96C0 +:10E260009F50CB70BF0496D7C3BA51CEA8477D0D3F +:10E27000E999E67C4A7A26398EE85FD2E98A76AD5A +:10E28000FEA81EF53A7EF85C9A6B237AADDEBDFFE0 +:10E29000B511009F05C51199B88F6A3DF30C65193A +:10E2A00003E94DF2F9CB553AB27BF7BD799CE8AD65 +:10E2B000AF4A4F74FD7D70A97770BD66201D56C2B0 +:10E2C000BA4C307EE501C5EE56783D84CF08A4CF28 +:10E2D00000F8C40F023709AF7EF80594AFC07FE4A1 +:10E2E000A03F81E2F6260D06970078CA7102E0C5CC +:10E2F000F2B4F0A874DADE46FE53794265EE1FB040 +:10E30000FE15B84E9C07AC13E731FF0AD79B487B3C +:10E31000C2A22B7ACAF7D34D31C02B0BF79D769F43 +:10E32000F6D35131DF370BAF4453BB1F8B9EBE8FEB +:10E330008EE4FC25DFF6EDA33B896F3A7343A3CE51 +:10E3400002AB807FE7125F10FC7568B9D4C5F9A8ED +:10E35000537BCE8CBA238FFC8EFA2CC92457F49FA2 +:10E3600043566DF99AD0E4182C770ABD9DE4C74E48 +:10E37000514F8E5306E5B66148D723A3511FBBB159 +:10E380002525B1CB4F5E716E3044A3BE3071FD3098 +:10E390004ACBCCD6683C47CAD6ABC5783E9EBA2B92 +:10E3A000263A0FF5F31B0C5173A1EB533FCF496491 +:10E3B000E3315F44E9E9AD418BFDF5DC32BD4B9CB7 +:10E3C0002775777C40E7DA05DD9B618B71DF6D385F +:10E3D0001886AE37351BDE9D6805916453847373D0 +:10E3E0002ED951B7EFB222DCACDB27A09EBA1DEFCD +:10E3F0001EC37DF243F586A218D48BD5FEFDF8E34B +:10E4000078EE3BD71BA251FEFCFC4F702E2A74AE57 +:10E4100091DCF09999D17DE9B39D216EB4DF7FA69F +:10E420003007DA7756AA47275835E76CC7229CC7CA +:10E43000EE18673B1FDFBD2B16C7B7BBC83FD3B96C +:10E440007E74F8607A1499AE6AE772DD2EA9C7155A +:10E45000FA5E94E7318FF23C1BC3E579CCA33C8F85 +:10E4600029CAF3F8FD90D0E38F6AEECDC4FBA86B08 +:10E47000264B6FA073D7928EF2FA6D4AB01DF9CF7A +:10E480006D8A3D06F563EC4F11FCBC0DC0AF4CA787 +:10E49000F582CCE547F7D3AF9898BF9FD90C16A16A +:10E4A000C9CF32C569EA17599334E53F891DAB29B5 +:10E4B000BFC696A9C95F973E5953FF7AFB0C4DFE24 +:10E4C000A779D768EACF73CCD3E417CC59A2A9BFF8 +:10E4D000B0B84C537ED3E2959AF225CED59AFCCDB6 +:10E4E000553FD7D4BFA561BDA6DCC1AC7A3CF73A95 +:10E4F000F09E05707F19EF5990DEF6D6688B3F5E6F +:10E50000F367E91A06D3D37F2CE8376392E343A479 +:10E510008F041DA743481D28425C10E74A3CF32A9C +:10E52000FC9EDB19877413582FB03C3FE4D8651B61 +:10E53000E0F0A6892137EB813FE44F3A969D02F93E +:10E54000270ECDE3F9A9C79E4B86FC6F26DEC7F3E5 +:10E55000571FBB8CE5A39E5F74B31EF84EFE0246A8 +:10E5600022C77387BE5EEA8275E44F4FDE62E77AA8 +:10E570009241FD34FBF52C0007F46F443860EA0546 +:10E58000FAC4F418D027A6AF007D5618187B0DE802 +:10E5900013D31370DFC4EFAFC37D13D337E1BE894C +:10E5A000E91FE0BE896927DC37317DA76931A57F86 +:10E5B0006A7252BBF79BAA28FDA0A981BE7FD8D45E +:10E5C00048E95F9A5CF4DD3C51EA2FBCA47F917668 +:10E5D000A67AB4EFA17EEEB0E1BCBF1D56DA09A564 +:10E5E0005DB0B9817585E03EEDD2479C35F9EC7D93 +:10E5F00043F3593D3BEB27876D8D75444D24BDC6D4 +:10E60000482BD97BC4F799CA820434FDCD9DE01C08 +:10E6100081E50BB3CA378403FF98FE6D8301E9E5FA +:10E620003DE1A71AD8FF855C2E0F1B2639464D8485 +:10E63000B4C0C4FDF00A4CDCCFAE40DFD58CFCA8E2 +:10E64000F92B66433F9AA3A146E24FCD77E9DDA8B7 +:10E65000A754BE64949F16C528DFFC5527F9E5151D +:10E6600058EDB174DE887CBFFD1CFFFCFC65A43D49 +:10E670005BFAC9147ED9350BE5806916A32D28C035 +:10E68000FE8E76EBA3A1EFCBF9301C4FDAC9777C75 +:10E69000C5BCBA093E7B7881A93309F504D3D69A63 +:10E6A000ECFEFE3FD2EEAD7CD9A9E27922FD7CE4FE +:10E6B0003872BEA17AE82FCBE7C75360F564A25F3A +:10E6C00043739D85FA8B81EFC62CAAE750A99D273D +:10E6D00013F5C0D36A2D76D46F4B7B7B8C5837D41F +:10E6E000A375167EE9247F8369C2DF00FB31F172D6 +:10E6F00017F6332DCA1BA7C7F53718EDA80F7D4CA9 +:10E7000081F6593EFB3FD60FF1DBBF384FEC37F5B2 +:10E710006B982FCAED0E07C17781BCBFD9445E9CB0 +:10E72000CFCC3493F457AAC81F9BE07422DE8B83AE +:10E73000AC7F0DA17D9E92807A8E79426EFF0E7A1B +:10E74000598E74F6DFA71707C7F74846FAB440BAE0 +:10E75000917891781E8A8E24DEFDFCB508CFFDFEEF +:10E7600057A29F40FA1A8AAE243D159838DE11AFA1 +:10E77000E84723E948F9D2B39DD6516BA2734ED234 +:10E7800051201D0CA4234E97CD3F33517F03E9C880 +:10E79000877F84C7BF4E479D2A9EBBFF2CFDDCDAD6 +:10E7A000CB668743D12FAE765EC8457FA02BB6D708 +:10E7B000305FCE66CC469292E52D439407D297AC5B +:10E7C000FF34D6CF1D58DFF965AF21DC8F2EA78926 +:10E7D00033F0F521FA7F43F8C5BF6196FE1E0E4B5C +:10E7E00026D0C12CC1876F2BE2F4352749257BC683 +:10E7F000AC8C1524DF330B978F6DF03FD2B709FB3C +:10E80000FAB5A2DDEC6F8B5B709CD9515AF9FB5ABB +:10E810002177CF09B0B75F9BF11392C3AF0D90B3CF +:10E820007F3F51C8D1492C89DFAFB790FC5B28F6F8 +:10E8300063BCC0778A4D65F900F722E6D4E321F086 +:10E84000CA45A303FBFB097351FE1AE6A6F43AE698 +:10E850002539E07A383030FF53D87A983F1E72431A +:10E86000C92AE86F56F6AC54FC5E6BEA4D34EAD028 +:10E870003BD0F921EEE77AD5F931CA9917129C639A +:10E88000F07E7CACD04672D831530AC985B89F0C53 +:10E890007EFACADFC3399A0AE7DC713867317D1521 +:10E8A000CED95438EF7E07E72CE6AF4D5FCFB0DD11 +:10E8B0006C9BD6BF47B6BFCE3A8BE9870D7D8E5D88 +:10E8C00037E18591A8C77A23624C21E2ED8D884912 +:10E8D00085B8DE372262743C0D32523AFEF9D4C15B +:10E8E000E45649AFBEF166D37881F095F00C84A36D +:10E8F00084EFBF004FFDA4DC81F0BC806730EA4F9D +:10E900004DEF86C526A39D51C4D385703E58F7FCB4 +:10E91000F8185C47AD89C3655AE3544A0B1A27338C +:10E920007D36D9995C08DFCF7109A8700ED0B3315C +:10E93000FD4CCAFF4CD0567A8C331AE7713ECB9B04 +:10E94000061219FB745B7318FA675E7846B5E3BD6F +:10E95000A656B56DB1A39EFC0D95C7057D7B3C11F8 +:10E96000ED9B6CC7E0FED2B526093F17C1B5ED6A35 +:10E9700007ED3786D6D9689F5C333288FB199379C7 +:10E98000216B6839676230E7332383387F94F882DC +:10E9900076FCDC857E26025F8BBF2F98EE3579A34F +:10E9A0001CE3713DAC9069EE05527FD117A5D2F9F9 +:10E9B00050C0D21EC2FB7BE10903DDDFFB0A192F29 +:10E9C0008FE5F6CABE139755DCEF45A10A1B96E406 +:10E9D0008B9B098AD5319B9F3C6DB605339B1FDD10 +:10E9E00086A4476AF2A1F6119AFAE179C99AF20867 +:10E9F000C7559AF26173B234F9E1C55334F5631621 +:10EA0000CFD4E4E39CD76AEAC757CDD7E4253F8A41 +:10EA1000E79F5842C3524DFB518DCB34F5935CD5E3 +:10EA20009A723538EC498A3B75393AD3A3915FF134 +:10EA3000BF94CD6B34F51E0DE37120732C9573716B +:10EA40001F8E6EBD5D3B2FF54D85E23A6D9C0FBA72 +:10EA5000E07F88DFA2582D5F9C65D5EA1BE21BF49E +:10EA60009A7CF524E18F34814D203EF87D78765EE6 +:10EA7000A5C173203C00EF762FD68773D505F9A288 +:10EA8000DF97EBF1DC47BB82FFFCD1AEE0BF5EB4A9 +:10EA90002BF8E7D1AEE05F1FED0AFEE56857F02FD7 +:10EAA000CF3EA1C5736EA716CF933ED0E259D2DFF9 +:10EAB00050F898DCA5A583407C4CFD2C802E041ECC +:10EAC00016C3FF06C3035D1180FE673530D29B7D00 +:10EAD0001F5E1E9B24CE278117C003C5F5F58D0C44 +:10EAE000253C3C26E65FE01D4771B145A8374BF257 +:10EAF000ADE73171EEFE769873F724D8DFBFB365CA +:10EB0000C5223F9ACEB85D7376ADCEEE85EE9F0AF4 +:10EB1000C0FF84B1CE7D587FF1B0CB8946A4875E1B +:10EB2000E718BC4F7E28F424817E9C2E1007280E07 +:10EB3000E17695E26F4EEA5A15E4CBDE04E721E474 +:10EB40001BB76634109DC6B2E2FD9530BFD2FF0CF4 +:10EB5000223B4EE9281EAFCB32BA28CE41F2BBD2BF +:10EB600078EE47F4F2246117B6737FA2A393B83C02 +:10EB70001B6AB792DF7159068FE3806B5762E978A1 +:10EB800084CF9BE631089F366E37E9C278E1285F73 +:10EB9000BC30CA9B28DF2508F9AAF9CF2613AE633B +:10EBA0004C3BD39C9363DD268DDFEBB8DD564D7E69 +:10EBB000BC275653FFEAC3364D79A6375D539E7D79 +:10EBC000C2AEC9E776E669EA4FFAC0A1C94FEE9A2C +:10EBD000A3A93FF5B3624D3E9EF53E8CF01DA5F016 +:10EBE000FBFE3793B8FF14EC55B2E3956E8AE071E3 +:10EBF000A0420F20E569E90FED14F41D28A78F321C +:10EC00007239B5398EF17B9849DCB798565E770A30 +:10EC10007F6629A73297D69F59FA31F7CBF5426E16 +:10EC200097F2B19F1FB3C3DF8FB954C46F079E7FA4 +:10EC3000863CAE1F099CFF28235F6FF3CF8D1437EE +:10EC400022E715381F6716A7DB9DA6C1E37786E587 +:10EC5000713DC1F8CCE2903C481F37D8DDA447197C +:10EC6000309EBDCB85F7CA5F1AED77DABE7FBCD286 +:10EC7000ABF97A4A74BA5BE76590BFD8E267FDC624 +:10EC80004F11E3064D51065D5F6938F7E762E146D3 +:10EC90001BD2EFD0E37178C61A590BC51909BFFF13 +:10ECA0005BB678EE1D034525C65603292F98DB80F9 +:10ECB000F4307726C853998C1DDAFFEC2316906741 +:10ECC0001E6FD4939EE7AAC33125AE545F1CC7289C +:10ECD000B86F207DA0CC82F7944727737FE5EBF2D5 +:10ECE000F8FA8AD46FFBFDEFC97EC198382718F96E +:10ECF000C30C426F4487721D3F963FBEA4DB403871 +:10ED0000C9FB2513FE8EA9625E127E723F48F8C9C8 +:10ED10007808DB6A43F193168AAB98837E64127F8E +:10ED2000BF9DCCF9D12F053CB01EF2A3A1EA15A9D5 +:10ED300019E1A80FEF63B670EB77E87B7FC4380565 +:10ED400082FF50F15543F187017C618878ABA1E8DF +:10ED500093FEFE89B82B3FFEC0FD7A043EDCA93A43 +:10ED6000B2A36F0AD5EEE3A7047F9827F6139CE3BE +:10ED7000964C2D9F60A8BF6FDEA00A3EC1CF6F9456 +:10ED80006BF0FBF20D063A4F192B7E10E3883E69BB +:10ED900033907F6B81C336DBCEEDF324DF90DD0B48 +:10EDA000A656E6D29EDB20473C89F789E9CCBE1106 +:10EDB000ED19E59BB5E52B2CB33F47B96179C0BD93 +:10EDC0007485B8AFAE08B8976ECB13E7B19DD9493B +:10EDD0001E1376FE2A51A79F8EDC29E142EF42FBEB +:10EDE0001352F20B9370B1A1BD26DB9707F805A76C +:10EDF000E339DDA21FD45FAF1F7E43F8239C477F1A +:10EE0000041BEEF73E8AB7EA3B60E6764A690F12CA +:10EE1000F5CFBB2E5339D6C7DE2E64764E4079A788 +:10EE2000DF7E146087EAB3E8C2F2B0BFBD06EA4FE6 +:10EE3000FA5B54FFCD3DC1EA674F7676A91AFF967B +:10EE4000C0D4B9FE20F95F6C8A70BE8A7CFC9CDE5F +:10EE50006E42FCDD6539168D71F27385DE2670BE5B +:10EE6000FDF26DBEC2EDB02E1E37DB3747213F00ED +:10EE7000E0830CF78DF41B98C7BC51984A7B8C73C8 +:10EE8000F36482B3B4C7947927D33C1736AF300408 +:10EE90004395AE87D71505DB7C769AAE04EEF73343 +:10EEA00094BD66C1954CEAEFC62B53A99F337949AF +:10EEB0005CEE6AB97735D2D155BB9901D7D915E047 +:10EEC000F72ED31B27F3FDB01A633172FDFC89D6F0 +:10EED0002B44E76B1426FD8B884FCBFCE556912F16 +:10EEE000E2F9DB36F07C9781BF33B34BE81B709DB2 +:10EEF00098E27AF05EBC57E823701D98E23AF03B46 +:10EF0000F225CC235FC23CF225CC235FC214F91258 +:10EF10007E5FC68A1333556E572AF4DB3768572A4B +:10EF2000F4937BD0AEE49F47BB927F7DB42BF997DF +:10EF3000A35DC9BF1CED4AFE79B42BF9D747BB923C +:10EF40007F9EE55DE3CB231F73CCD3E417809C5FEA +:10EF5000E8B76FD1AEE4DF3FDA9534FD39576BDAAD +:10EF6000DFCC1A35EDD1AEE45FFFD646456377BA04 +:10EF700055BC0750DE3E8CE863EF84E2A4C980DF15 +:10EF80008F43FEFE3303DE37D48E9548B76BEA829B +:10EF9000ED1CCFAD7338DE758CE3B97709E1799D4F +:10EFA00091E78BB8FFF160F69B4203B7DF608AF60A +:10EFB0001B4CD17E8329DA6F0A4773FB0DA668BF0D +:10EFC000C1EF68BFC114ED3798A2FD0653B4DF60EE +:10EFD0008AF61B4CD17E83EDD07E8329DA6FF03B1D +:10EFE000DA6F3045FB0D7E3F897624BF7733504E74 +:10EFF0004FD5DC1F810E35F747AB268F72BA7F7D68 +:10F0000094D3FDCB514EF72F4739DD3F8F72BA7F36 +:10F010007D94D3FDF3CBF36CB4BF505EF76F87F2F2 +:10F02000BA7F7E7CABEB55D41D5DBFEDE22B9876AD +:10F03000852A8F2BC00A964DDE578276B62EB39264 +:10F0400018019CD2B0FED99242D8B34EE1C73781A5 +:10F05000F5EA10DF646707BC39BD8CFC8EC77F13EF +:10F0600047E5D2AE4B7F80F7CC038CE4FE43225EB3 +:10F0700053B6B733AB8AA9ACEFCB0F5E2F707C5978 +:10F080008FF8A5DF3CE06298897E2699EB2C59E841 +:10F090002FBF4BA7707FD33BB9BF6F205D3D28E4E6 +:10F0A000A05DBAFDC782D17FA84CB1631C439A9E74 +:10F0B0009D3064219C1AB2503EB8637284F0076E92 +:10F0C0009882FE4772DE520F087C82E2D7F27B996B +:10F0D000B102C699F625332E47FE6EE47201B6C31F +:10F0E000FBE23897E278D28FBE374FE6E79BD3B585 +:10F0F0007A4A057C1FB7B7610AC6C5CD0DE6ED7E1D +:10F10000F34418C1F18616E5498C3FCCDFCB1C18BF +:10F11000EFBA55F0D3717BADC60A1AD74AF174B273 +:10F12000DFB26D8914FF57C6BA0A31BE82E5280CDA +:10F13000EDA3126EB0BE57707D69B0550C247FF2FE +:10F14000B89C60119723E37182228A17E6E5FAE200 +:10F1500072A6E54414A15F1CEB60760C03BE3EA7CB +:10F160006CC370E8DFE976D8D1AF68DA970DAF529B +:10F170007E4731E5890C26D23874AE8D7129F4BEF4 +:10F18000C60DAEEDBA281BC6EBAE374463FDBDCC51 +:10F190008EE20E1C3514772AE797C13A756605F1A1 +:10F1A000CE8E0FF3A323E0003722DE33ED067A7F05 +:10F1B000639EDE6A40BE11788E0FF45B0C901302E2 +:10F1C000FC4B9AD77D90A826A37F89CEEE45BE75CD +:10F1D0003084E40529EF94097FB3CB2DAF0EBF092E +:10F1E000CACBF673F9C0D9AE10FF93FE267529EE8F +:10F1F000441DCA0B23B64F8854F9F98F7CF19CEB60 +:10F20000B945B845CB36BC4A7111651B72C3795CF0 +:10F2100014B7435408385508BF2296618D4639F318 +:10F2200014F01DC718F24B0CA7B8C2562ECF49BD1B +:10F230008E9407E5FB31656F65BF86782F7B4CBCEC +:10F24000CBB2B98CE2AF02FD7C6A84BCB7B2C540D8 +:10F25000FE432B03E4C11AE12F5413200F9E9C2C74 +:10F26000F440521E14F717E9CF5BF6D6F18524AFB0 +:10F270003418C82E57B29ECB2F6C3F73633C43C9E2 +:10F28000FA593A7C37A4E4A0C3AE0C42276F0B397D +:10F29000666E9799E03AFF4A3CA58BAEC4517AD38B +:10F2A00015EE4789B12F48075D2F3092A3DF157205 +:10F2B000CB42F4ABC478445790F09F642437653256 +:10F2C0006B11F28FAB1CCA7114FBE61A9C1BD06F3A +:10F2D00073EE7646F147D7A37C03FD2F467907F5F9 +:10F2E000EE39494514873147A17896EB73560BFAEE +:10F2F000067A6748EF2E41BFC594EF3F17049D3B48 +:10F300005DDD7A84FBF52EC588EFF039C53D56D218 +:10F310007120BD978608FD9385EB97FAF54F385914 +:10F320007AD4C6740BFAB796A26E7004E388079875 +:10F330008766F0F2D829A65B5AF052F3DFD44B94DB +:10F34000E8743CDE09E42DE4ABB7ACCD342EF3E336 +:10F350002F9F4C9D39696AAE0FEFCB02E2F4D6DCE9 +:10F36000353AE6BBE245CB01CEB84F4AC3BB7E0679 +:10F3700014CAF2A6304721889E4B985C27F3A25FFF +:10F38000E052915F3E25F3AF9B33083E94CF793135 +:10F39000FA1617F155CEB76E46BEA522BF72664D5E +:10F3A000217ED5351BF11192D12BDE21E0F10E81AA +:10F3B0007A88E553381E02F511E5199C9F33BD2D5F +:10F3C000F1668A0BB6913E4FCEFF94411BA729D31D +:10F3D0005BA670BEFC63C537FCAF14E70DB8BE0773 +:10F3E000753C6E7E84DACA845E88F6BFE41F4CBC2E +:10F3F00023E1C33FC869644757ACFEF8776E56787F +:10F400009CFA10FA1B96DEFBF04ED4DF351919C6B4 +:10F41000B93E91C6E9E889DB8D248797183B5FC523 +:10F4200077B2241C3F6AFC0F03E9FF997734BEFFD3 +:10F43000B5B4C16C47FEFCC9D4E28A29C3111F765A +:10F44000C2C724D866D8FFC984E215F8BD6ECBD1F7 +:10F45000C7316E7F554712C591961DCEDC88EF8966 +:10F460007C32D5598BEB2DB3588D788ED7B744D0DD +:10F47000B9561A23E23A592FD9A924FC5BA6F0F316 +:10F48000744A3EEFBF47DC479061CED3D4137EDC95 +:10F4900001FB44EA0503F50B81EF380CB57FA41E90 +:10F4A00001F506463FBDA2D44B18D24F2DC173B40F +:10F4B000C4A88D3F94E941A97713F7C1E5FDE7584A +:10F4C000C6EC18949BB72A563CC72A2CB69B2643F9 +:10F4D000BEE284013D30D9DC481B7FBFE32EFE7EB7 +:10F4E000C732D8AFC86F4A843F5645FB64DA6F1500 +:10F4F0006E48B387DE97376F3D9EF002D28FD741BB +:10F5000071F915568731D26FDF97B72A9AB87E996D +:10F51000DF3945A5799780988EF0BB656D9211DF34 +:10F52000D02901F102FDFB0E4EB169E2AAA11EF93C +:10F5300035CC4D66AFF1F79360DE497CBC2CBFFE45 +:10F5400097B56ADF2780FA2417FD764A28E1AFCC09 +:10F550000AEB4EC2D44AF30438109C7AEF85FE6C55 +:10F56000340EE1A3DCEB36E0BDBB04FD2920BFD4A3 +:10F57000EA36E038CB5AF87B21CE2D7C1CE7E60832 +:10F58000E378949BF4566302C20F2FCB51343FE2D1 +:10F59000831500178CB792719781F02913F3AD682A +:10F5A0008DD0CA63AD5B0D888F2543BC57D02DE845 +:10F5B0007659CB0C8A37AFD03B289EC129E0FBC9D6 +:10F5C0006AF3DD681758D2F6902109F27F14F4DB54 +:10F5D0002DF6DDDC64EF687A1768B5D98EF35C62CE +:10F5E0006DA5F5F5C3F701808782EFCF14137C81F9 +:10F5F0002E5CE89F57D1A6C5A76F3E1CBE156D6552 +:10F60000B4DF2AF54EA3D57F1EED4747A31FCA12CC +:10F61000D8DFF8DE11B33A29BEE9EC033725D23A38 +:10F62000619EE40765B7CDC6777E804E888E25BD86 +:10F63000C8B86C39DE3753785CE637DFBB2F1D2442 +:10F64000D734037E51DF3DD4BE346260178C6BAC7F +:10F65000E0EFAF05EE53B93FFBED07629FCAFDFB3C +:10F66000B8A1D81BABF8F80C9CB70DCF0E02A74978 +:10F6700053F97C970ABC025C5FF18FE3B24DE578E9 +:10F680002D49D6EE77EC0FFB0D93E533BDA331EE9C +:10F6900052D697E39644F27648F7486F61623CACE5 +:10F6A000BF86EA6BE351CAFBF9C5DE0DD1C82FF660 +:10F6B0002B24F7AEB9F778C2BFA33CBB8FCBB3E71F +:10F6C0006A77D6C7A1DCA87727FABF8B55E1E5FC9E +:10F6D0006139C83FC82F2AC539BD2FCB9930D5CF46 +:10F6E0007FA2E2FE7D694ECE5FBCC85FFEB2EFA591 +:10F6F000F7A6D87CE7A79CFFB2CD7F349459FCE1F4 +:10F70000C5D777777A1FC5D9955B8C36F45F2E6F96 +:10F7100029237ECB62E15EA1F8F01D4807652D0A22 +:10F72000BD2F56DE38D1ADFE5FE4CBE55BE6D19B65 +:10F7300048124FF2BD13799ECAF93BC4FC970A3AAE +:10F740009E3595EFBFA55549C64ADAF749C672A45A +:10F750007F51BEA442FBBD1F4FFD76EC8C8DB83FA0 +:10F76000306E88EE275B0C5CCFB73794E4D5736BB3 +:10F770009EFFC322A8F7C583DB13513E91F35821A6 +:10F78000F479CB855EAE52C8AD80A7F953FDF8EC95 +:10F790008A27389ECA9F79EBAFF82E5749B2E067A7 +:10F7A000F7F278FE659EFD84B7259BB71A92105F2D +:10F7B000F848AD5FFBF206B8E8023C976EDE6E409B +:10F7C0003EB04CAE3780DE4B84BFAF842B9E3B8A6D +:10F7D0009FDD42D647FEB71FC659BBDA1C86FA69C1 +:10F7E00039CE3D53B9DC54DE101189E3953794FDD1 +:10F7F0000AEF1D92DF07EEBBD366BE1F96417FB8AE +:10F800002F4FCFB0535C33DAB5063B57EF9CCACFCE +:10F81000D5470DFCFDC6F810CF1E8443FCAA603B03 +:10F82000F287D4D42EB21B233DE3BC8D3AFEDE63B7 +:10F830006A6DD7259C0788D4E49F8229BE33852230 +:10F840007634E49FD4F1F8AB6495A7BB057CA0DCCB +:10F850008BE52CAA8BDE9DEB7F3729805E8D6CC7F4 +:10F86000667CEFC618C5ECCD361F7DCA7E247D4A66 +:10F87000FA1D6A7DEE1FB8BED349421F916E4FC478 +:10F880003895D2FBC6D8513FF37DEB348AF707FB9E +:10F89000D70BC49A1739C87A53F9BD65E8F5B61580 +:10F8A000450FB2DEC075CA7D227DDAFBED0BADDC03 +:10F8B000BE705A81F30BDA9D5E6D26FF2FB92EA91B +:10F8C000FFFEA17108AF4C8D147A9DAE5094234B6E +:10F8D00082C5FEF7F23C7E9FE7F75D9EFBF2BD36E8 +:10F8E000C99FCF3488739175DD8BFB9935A6D0FB0A +:10F8F00024275B4F87E27B29A767F0F9C9766B0D58 +:10F900003CCE98851A6DF8FE21DCAF4E36A2DDA7FD +:10F910002586EE91B734A6105FB8C515C1F50F4224 +:10F92000BEAF147C30646DD9467CE77B797B925501 +:10F930008171965BEC67DBA9FD383BCA83216DF3CF +:10F940008CC924F7F27B80B413AD555831C58D2195 +:10F950009FC4FDA53B9A8AE7CE8A767E0F98AB635B +:10F960009BD14E38AAB978761CF28987158A3367FD +:10F97000DBB4EF58A567177F4CF7BF8077E0D61A46 +:10F980003C8E18E4E3206FA0BE69B9A598E4F65256 +:10F99000412727DBBAE93D7A09D701F13F461E0727 +:10F9A000DC1BAA233DDC0F8D03AA1076254937D234 +:10F9B0002EF508FE6732C249A573AD482DA1F79414 +:10F9C00036B6CDA2B4626BD183AEF1187F5C1C3D1C +:10F9D00085E66D203D5945DD2C1EAFFB645004DEED +:10F9E0006F120DAE447FB9B462FB268AFFF96CBB7F +:10F9F00099E27F0AADF30A23A2E8BD638AAF93F5CB +:10FA0000C2F3F979515D374B13BFB31CFAC4773693 +:10FA1000BFF284901F9A8CCBA98D7106E7E7F2F8AC +:10FA20009CC9361E971347F56D83EAC5657AB6897A +:10FA3000C779F8C51BDDB004DAD7D63D1786FDD4EB +:10FA40003CF0EE44AB8EF450D1F9C3FDE28DDA798F +:10FA5000BC518CB82FCD8D2C5EB404E1FF7B95E0BA +:10FA60003FD4785587158D1DEF167738C9AD4E2FC9 +:10FA700033A21DD9696524177FA6B2469403A4FC5E +:10FA800022BF5F95CFF9D567E1AD89481F2B773D40 +:10FA90009488E7CBE7A13C5FB2EBA6D7915F3977BB +:10FAA0000471F95CCF481E2E7771F99A5545CAF753 +:10FAB00048CDA5404739F921FCDDA3766DBCB97C62 +:10FAC000E7F6733D7F9F07E38D90DE3FD27B972360 +:10FAD0007E3F02F915EFB1E1F99C3E3F6A5567930D +:10FAE000DF106C1494433E6A7D2E14E3A1A5BC562E +:10FAF000A4FEC581EFFFAC39C8E382F17D7A7A2B91 +:10FB000054E841EA851E64CD0B86D9F151247FD19A +:10FB1000975ABDD73818FEAA857CD59F3FB09FEE77 +:10FB20006DB57BB9FC50EBE926F941CA2332EEB042 +:10FB3000666F37C913B25DFD010E97BA03FC7B599E +:10FB4000BA4EEA511C4A2ADEA715CAAF9E9251BA94 +:10FB50005E931F57BA5E8FA9D0DBEB7B491EBC3B7F +:10FB6000FD1DBA87D7B5887E216FF01B6F0912D1B2 +:10FB700070FE3DC582ED6D1AFFDABA0311D4DE5B6B +:10FB800017BC19CF7947BD458F69739D85CEFD6D33 +:10FB90000DBA74F4537728C17694E33A84FFD6F013 +:10FBA0009AF7CDA83F8863BDC7F1BD5D6F82B316DC +:10FBB000F7430CBEEEA2FAE2897A8E7C9A8DFD178D +:10FBC0008CEABA8C6F6A18D64F2A453BC5DA7CB1ED +:10FBD0008E8CAE6CA4EBE1C7387F7ECCC036D3BB35 +:10FBE000CDFA6286FA7BAFB02FBABED1D1FBB31D7E +:10FBF0008AF7D7FEF2D51EB16F8B83B89DF1FE094F +:10FC0000CE5FE23C7EAA18C667927FA33A1AFBEF4A +:10FC100011764829A7CE14FC3941DCAF8C23622D24 +:10FC200048C7D2AF4F713828DEF3CE8C63E5783EFB +:10FC3000DFD36BA2788199BDC124B7268C9843E7A6 +:10FC4000997CB75DB1E95909D43F96A1F3625CDCB8 +:10FC50003DCCC4FD024C01F2ADCE4CFEC94AC7EF0B +:10FC6000BE41BE1EAF5E3A1E8EFEB2FFAED0FBA3FB +:10FC7000A57D671F7B9BE17DD89D49F1D009CE878B +:10FC8000108527FBE6743B0175F7583D263B3F2F57 +:10FC900098FF3A3A7EFE4D58A4CE37BF9EDEB3F4AD +:10FCA000AE634FAF89F4B6333BC43B8701F3E989B8 +:10FCB000B5919F34D42379B3C7A2A3F7DD66761C30 +:10FCC000A7F70A67CAF70C4DDAF70C992D2102F550 +:10FCD000CAA44B05E120BA99E3AF205C7B5FECC876 +:10FCE000E7F26287E02381EFDDCBB81579AEBC6C1B +:10FCF000D9750BD74BF17DBA4ADAF9AF24933CD1D1 +:10FD0000D791F29DEF58BC8B7205C80BA7AE76BC9D +:10FD1000923FDC77AE2E147092E7B38C5B5828E0EC +:10FD2000B5D0A2E3F009F8DD1549378174E1C33B92 +:10FD30008FF792F864B777BE8AF15880C7F1F73130 +:10FD4000C2DFDB488F27BF7973033EBB3042757437 +:10FD50003B937E14FCD1FBDD3F187F9D81F8F39A25 +:10FD6000C7A01CF1808EE408E9EFE814EFB54BBFA3 +:10FD70004796CE881F94AAC1A42F748A77DA810F80 +:10FD8000BC8A7C40EEFF5173BAC6E3397A12AEE802 +:10FD900038BF2E9D87BE874FE3FE862359679CF0B0 +:10FDA000CFC945F94DF5BD4F4D74DFACB81FAE441A +:10FDB000FFCB8516F273EF7107BC4F2DDE31EF617B +:10FDC000823F2C96EF98C37E86766D4B7879FF3B09 +:10FDD000E6A319DDA3DA32591ACA5F6DE2777F868E +:10FDE0007CC77C6524E94D1F79C43D16CF03F97E9D +:10FDF000F5F404A779DAF081EF573FA8142FC1DF9B +:10FE000081718DE7F3ED5A12FCCC2E0E6E2FEA7B3A +:10FE10004E3686D2BBDD924EA59E7B94ABFB6184B1 +:10FE2000938CABFD58D09B84BF8C2B8C0AC083A4D1 +:10FE3000BBFEDF8B59C7E9AFDF9FB69E913E6524BD +:10FE40004C2584FC23ED3684EB3D89CE249C7FF346 +:10FE50006A8033E9D1B99FE749F17B1681FB2963B9 +:10FE60009A4EDA89295EA0549C6BA5323EA0511BA4 +:10FE70001F10F8BE69F0C8E209D3609D1794772778 +:10FE8000E2C737FFB73AA8DFC9A4699C8FA7C63A73 +:10FE9000274EA3F36DA6468E7C33F3D304FA7D99E7 +:10FEA0006F8F8FC473EFA684E2C9D8AF3995DB0D8D +:10FEB0003E8EEBA2F88E8F97FC2D81F4CEEBF8BB33 +:10FEC000AC3F749E03E399391DDCB69CFB23C6B39B +:10FED00006A2DF585F9CAC19E7F13F2D9ED9176F42 +:10FEE000BC9B7E57E4E5264FCA99D103F1911F745C +:10FEF000EC391BDC681A8E1C2AA5F8DEF063B725E6 +:10FF000041BEF1C84B3C1F7FEC7212E0E6F6231DA8 +:10FF10003C3FEED8658C075E77E44829C5FFA2DD3B +:10FF2000600463771C79B9D405F8A89EE06C427C24 +:10FF30002DBAD2F02A1EC3EFAD9FBF3C89E259E72C +:10FF400025A4F378D6B558BE307AD98670C517CFB8 +:10FF5000BA6D1AB4037AE8B9C4E9BFE712A7F7206B +:10FF6000E403C3FFF554C6F54AFE3B149F94FBEF30 +:10FF7000C78A4B96FB98EDB26F362031BAFEE57812 +:10FF8000E14768DF04C40BF7187A1F277BD2256688 +:10FF9000C338C4A3A1EFDBF09C68CEE5F18C4A6FB7 +:10FFA000A70DFD30F27378BEF952A70DF93BE6516B +:10FFB000AFD513C1E31C653C6CF3256F1CEE937C3D +:10FFC0008C5B84FA85BDBDA5C86FF2D18F3709FB64 +:10FFD0007FEDB8188F617F3B2EF178C31E73A7CDDC +:10FFE0002AC6C17E60DC24E48BF96B4DE46FD47CBF +:10FFF000A96135F55362E91F570918D7F4DDE3CE3F +:020000023000CC +:1000000052FCC64DEDE3719D38AE4D33AE97E281A3 +:10001000A13F8A3BED89B0C7E27D5FE60BB11CF2E0 +:100020000F89DFA7C8B77955E4FF323E2AC628DE1C +:10003000E116F715A847F1983BFAF83A2F3679AB55 +:10004000713F150A7E5D68E4E725D305DBD10FBB60 +:1000500048FDF6B578BC97BCC0EF258541C5DB707F +:100060003FD6EB39BF6151F277D23A57FE06EABD6F +:10007000131D4FBF2B3632F6104BC57BF1AA391931 +:10008000785E80BCFD11E2FB1DD6AAF0DFDFE2ED59 +:1000900017CC0921FF939E23637271FFCC0FB21D11 +:1000A00064B06F4F4DBB44FB747EB82D176F3AA7F9 +:1000B0008E5CE6F918DB41B4EB9AD8A5D242BAA718 +:1000C000713BED4D3E3BEDA7B82FEBE65C3072B9CE +:1000D000AC97DE673E378D9F5F20B793DCD17B8D79 +:1000E000786F33C3968BE58986DE30845BCFB77A31 +:1000F000FE5E2DEB0DBBD1CF2EFB78077FC7369070 +:10010000AEF715F0736055AA85DE39AB8F359928A7 +:10011000EDB8349B7E07465F9C8AF7028771707D3D +:10012000E313055CDE4CDA68F4D9DDE1FC700433DE +:100130009977B13CC6B6FF5B70FFBD0B8F18E368C3 +:10014000710F73599F284CD5D47760FDFE72C69FFE +:100150006793ED47BEAC7F02EDF8341EE2B992FB27 +:100160004D049E17A5D32335FE568F4599C9DF2A26 +:1001700055157A3CA86B257D20B7DBC6FFA799E211 +:10018000E77698391DA6EA78BA4327E27C859E4F28 +:10019000DE5F7E31DD397E7A2EF5E3A57ED4FD99D2 +:1001A000284FC4310F8D2FE532590FE42F33311909 +:1001B000F13B6FF9AA6E5078BE5230C351908B74E8 +:1001C000ED629FF89D131743C21AFDF157AF6AF510 +:1001D0009DAF14CCA476B27D5DE32CF609C5217ADF +:1001E000897EEA5275745FAD57D92BF47B03AC93CB +:1001F000EC98B2DDFBC0273FA1F71A1C947E00FCEF +:10020000F213F2F35B4CE95F9A9CF4FD645315A57D +:100210005D4D0DF4FD545323A58B6E0ECD41FA5F59 +:1002200075783DFBC4EF7CACF3189CFE7E35EFCFB8 +:10023000189C8E2A051DBD9F3478795301978BDE5B +:100240002FE0F8EC59CEE54BA0CB166BE4D0F24290 +:100250004F28F747786926A7F39E389E7716F077E0 +:10026000421D3AD68EED5F9AC9DF617F3F5947EF55 +:1002700039382279BFEFA7E9484EBB76F68C528415 +:1002800093231ABE67F9F2EF5FC5CB1D23F87739C8 +:100290005F593E7E7ABFFE208DDF8BB9DD1DE89D64 +:1002A000FAEFC76F219F5F607DE9471F088FA36248 +:1002B000DFD2BE40B91DF74192DFBEA8B7D1BE90D4 +:1002C0007428E9AF743A87736A90A07338BB087ECC +:1002D0007886E1BD38C64C72AC03ED16B09E1D2287 +:1002E000CE7DC07E107600B91FE43E90F41E0FFB59 +:1002F0008CDB39F83AA6A983EBE73715F07B6A6700 +:1003000074E8CF08AF1D062B9E37D3546E6FE8E913 +:10031000589883FEE0459B2C0D83F1AF9745FB7FFA +:10032000190E921F0C018701EB370A7DFD3FB97E44 +:10033000E26FC8B797737FCC407ADD5B20F915A7D1 +:10034000DB570A1CBB907E7A14B31EEF273DE6C133 +:10035000FDC75F9AC9F785A49FD2E94CBC3F03EB68 +:100360004C19C8EFE47AFAD7B98211DF4B1571C680 +:1003700081F895EBF2E37B1D057E7A27C6405E810E +:100380007E46D65AE87E2AE9F7E2F06F2AF1FC9A17 +:100390005360E3F6179D2ADE81E5E749FF7745A51F +:1003A000782BBF7386A1DCD27B84DBE1BC704F422B +:1003B0003B16EA9EFDE3ADBF16FCA26F71AE0EF5D3 +:1003C0000317BFB6B8F0DCBA38A2F724CA2517DB8A +:1003D000F93BE7D0E35C05FD4530EEC786BFD7C2E9 +:1003E000ED1FEAC35F9D4479A8F26195E4978B788D +:1003F0005D8676AB1EE0BF6F27FD066B45BBE6F65C +:10040000CB8BE877CD803E51FEF9C45C9F8C72F1B6 +:10041000AC871F3881EFAE571E5450CDCC8EA3BE93 +:100420001DF26777ABFCF75545BCC96CE1D75FBDE2 +:1004300093FBF5D7629C09CA2F07B63F88BF3B598B +:10044000B7DBC0CCF07D36BE8F06E3ACF084C205CE +:1004500012FA6DD3C6A5FE84B936A21EB96A9BF600 +:100460007BF50E6DBE36C05FF15281F04B1CCB3276 +:10047000C92FB18DEB8925DF1E28EFBA387F5C23A9 +:10048000FD74BFA477BDD5235F259EB2F0FC3C91DF +:10049000EF86FC85AF38FC25DCEA05CFBF10C772BC +:1004A0003CB0BEFA23662BDEFFEB5FE0FA818B9E49 +:1004B0007082F3AAE02EB227B017552BCA61771DC0 +:1004C00056499F50D761FE35FE1E6DFD4185DEA960 +:1004D000AD3B1CE4E6F0B95489E52B0E9BAD362C00 +:1004E0007F3188A1DEF922E00DFD612F267411FE17 +:1004F00011AFA88F80BFB9F8BB1512FFEAC3DC8E1D +:100500005CB947E0A7FD363DE1D5ADB098A4817850 +:100510009278FE9DEEE97E3C61BB590FBFF79AC011 +:100520003BC3389BE3EDE5F47B1812DFC6239F2421 +:10053000A2DC2BF1AC029E7F21DBDBC43B78DF81A8 +:10054000E72AC4B3E59FC7F3EB054CC6FB9D7D14BA +:10055000E5DE5023D9CFA53E43EA2F86D7BCFF6AFC +:10056000140C3C3AF63992734B23CFD5AD66A43FB9 +:100570009B341DF59FD7BC853FE7CBDEB9F6E94C30 +:10058000A48F664317FD5E8C2B82BF27DF93346FE9 +:10059000DBF3305E61E43789FB71DFBC1C4466939A +:1005A0005982AFE29FC9FF3DC00E33E9D9EA3A82D2 +:1005B000B85EED80D66ED613C77F9FAFC8D85BBA42 +:1005C0001AE572E80FC791F7C19A0EF1BB2FE2FE50 +:1005D0005623F50C7B03DE85B2BE45F54AA627D32C +:1005E0003C5262A6D9900F352F61CEE094EFE2F72E +:1005F0005C7F237F276F48397008BE2FE53FE6D226 +:10060000EA3924FF59217E57B27F7F887CD57A57FB +:10061000984925BAA378F1DAC7F8EF2A7E8A7417C9 +:10062000E6A3A77A1197F6EABFBDAEC7DF67EAD99E +:10063000C1FD2280433E88FEF9E73D3C0EAE3AA75D +:100640007BA2D786BFCFC1F9D0CABD8ADB9634085A +:100650001D31F746FE9E7D003DEDFDEEF70E6F9FCE +:100660002EE2DDC6B2F1FF00786EC7F8A35C1FBFB3 +:10067000088C9BEC3FBF027EBFE37F5A1C775F066E +:10068000ACE73BEC8C3F89D5BEDF728D4DFBFB4C5C +:10069000D7A56B7F9FA9CF22E023E44129A7EE9E37 +:1006A000CEE599C054C2F77ABB761C792FFE699EBD +:1006B00076BC790EED783F142F3F563CEBF7C1EF37 +:1006C0003531EE0931EEEB62DC7F154E321D6ABC2E +:1006D000FF9FFEBF49FF0F426139640080000000A8 +:1006E0001F8B080000000000000BB55B0B7C94D54D +:1006F00095BFDF7CF3CC7308210904C22424216058 +:10070000880324542B96C9D300D6065C2D68840137 +:1007100052C83B80B5D2167F190411105BA8D1A234 +:10072000224E82E1A1619D08C144431D14B288D6C6 +:100730008D748BFDFD56DCF828F23213A374E55757 +:100740002D7BFEE77E1F990CA1DAEE6EF2D3937338 +:100750005FDFB9E77DCFBDD414E718BE9A22446E9F +:10076000CC59734F8410AE953D4589D942F4BDA94B +:100770008A268710C2ED3D561F2B446DC770B129E4 +:1007800099F092BEB70CC0DBC6D93751FFC6F63F11 +:10079000BC83FEDE03AAC342FDAFB77F1C85752E66 +:1007A0007C152EC470CCFB384A105E7D49617C13E9 +:1007B000F53B089FD9AA0A7F26AD67F499D17F211E +:1007C00055C7BD6641B0A4A5D5DC43B06A4F2BF731 +:1007D000BFE9330DEEDFD338A8DF8EF104AB8CDE3A +:1007E000283BC173EDFA7A7E1E5F9DAAB8BC68DF14 +:1007F000F387B8A518D7F26EDC128297F133E36A5B +:10080000F8D9C11732DD34AFA683D6891858A7A608 +:10081000C3A4E192EEEAD4D6A218E2976851441A32 +:10082000810B628B5845FCAC6A6FAE16D45E957135 +:10083000B749105F023EB518DFA71F8388A37976FA +:10084000FA8BF877C1F745D4125AF735DFD1DB5C64 +:1008500004039D6F44E1BB8103343E73809EE92E07 +:10086000E25F0EA059881134EFC01B510EEADFE899 +:100870007B43F2DBE8E77DBFAEE10182CCE7769512 +:10088000F75DF195CAFCD7D7BBC5A5F23A33DBD3E8 +:1008900022B1AF133EF9BD392E876C4F5D5406FA75 +:1008A0008F27CCCF5193996E17F0C0C4D9CD9B88B8 +:1008B000942A1FAD9B7935DF9668EB7699C43C1F6F +:1008C000E496BABF6B14E9C7F1E2E193A9E7CAB8AD +:1008D000BB5D061E576476A72EA77127221C917652 +:1008E0005AEFC1E2719190EBEB80682FDE697613CD +:1008F000AC3C20BF77C2DE1D057D3B7160AAEA518A +:1009000006D6BB43FBAE101E860372F3B09CCABD75 +:100910008D115867407EB27D8ECBCEE38F7BDFBDDD +:10092000F36EDADF898C7027E4D26516E53ED613C4 +:10093000FA08BED799D8083EE8DF9B0379D0BC40BF +:100940008681E5DADB6ED2C6DDDD2C068D33B1DCC7 +:100950002E3C37981EBBF7C35FDD4DE3AB9F51853F +:10096000859AAB4DCBE3B0FF4FB70FA6AF5CE373F7 +:10097000B5C91F1717A4AFD51D57EC2582F5BB438A +:10098000B70F07CB5397E3890C55D29560F10A2234 +:10099000B9BAB599F59ACCCD639BC250D8092686D1 +:1009A00077272BB4FFC4FBADCEB544FF738AD66F57 +:1009B000201843B841E266825682CF98643BCC1639 +:1009C000F3C7903815C24DC5E3720C29B48EDA3ADC +:1009D00019727D7186EB5117EDFF97334A26CD20B2 +:1009E0007842F42D15F4CD9A8B111E112D44A1FAE5 +:1009F000FE13F86EFF019380FFA8B176547E427A11 +:100A0000DAEF244321BAFBB79BBC1ED63F57843292 +:100A10004D88A53748BBF9D4E19EA68EA3F16B0C97 +:100A2000BCBFEA16D56BA371BDF5C40262F967AD10 +:100A3000C93F82BE561F53ED56DA77BE2FF9D7D382 +:100A400081B7989C169A5FEBA346C26BF7285E8726 +:100A50005C5FC02E6B6E605D17A76DB529228BE0C1 +:100A60009A3E33C69D3EA488C768DC2361514DA0E1 +:100A7000BB2673D659258AA0BA797D22ADB76C9B67 +:100A8000E9A31EAB9C7B99FEABEBDCCA7A5BE11D54 +:100A9000DC5EB567305E238C0338ADDF8C3F6E14AF +:100AA000A2CD15197BFA3AFA7B82987059059FA658 +:100AB000C7C31E8E43AEC447D140CC1E29C4BD93CC +:100AC0009CF1B0FB8D46C72CF021D069B2835F75D5 +:100AD00087F657806E6F7598D3405BAD5DF52AF34E +:100AE00035F025F1FD7A820982F71F1092BF8176D9 +:100AF000A9E77526C56BC57CE221AF6755BC6BA81D +:100B00002BE0E98F62FF244431EC62E5FC1C03FC1E +:100B10001CCC581029BFD6ED41B11995684069FF2A +:100B20003F30F6A8C382FCC47FB95298FE02B3706E +:100B3000FBA8FDDE486734F47EAC352A0B748DB516 +:100B40002679C1F7B1C6BE35F8FE23A314C783B416 +:100B5000F4E1AC57262BC06B239CD0132561911177 +:100B6000FC7864D42223F47DACDD97519239801750 +:100B7000A01FF620BCFCBDA208B711DF796EA4E26D +:100B800037D0FA011BD1073B31DA4DA02F6092B864 +:100B9000106B06D1471E89F1FF77FAEC445FC40061 +:100BA0007D24EF68CCFF229BF84330698E10DDEC8A +:100BB0001796B35FD0F97981F4BD806495A648BDDE +:100BC000A9DE7EB808FD35A27B3DE61545C97D143A +:100BD000613FC0C3245473A5BC7235785FAE8C2FBF +:100BE000BAFFECC8751973096ECB2D310316AA999B +:100BF000F13D43F8FB958A95F5E40BB23FF8E37BB2 +:100C0000962BF6D48C01FDD6EDAA4E365DB19FAA87 +:100C1000DFEF348B147CCED59D41FDE542DAF5C281 +:100C200055367B6AB01DC1CE881FE5F68A5B05D9B3 +:100C30009B7B559C3D752AB5AB17CC02BAA7D957FB +:100C40002CFD5E4E19C2BE7C2176D93E18F7DBA47E +:100C50009EFB2315EF5AA23F3577B0DD256976D08C +:100C6000E856787F8D5F1B19F7942A5EF0FC0E6AB8 +:100C70005C15A36D0EE3CA73BD888F77105A8AF690 +:100C80008658B653EE24FFF52FDA3EEF30FA0FC345 +:100C90007F1C35F992EDD475B4C6EAC4FAF3052584 +:100CA0003AE4D74A4537C393E1B56D7E5EDC33063F +:100CB000FAF59EDBE2441ED6B8AE29127E3C4BAC60 +:100CC000B39FCE405221F65C9E7AED7C8614479C01 +:100CD000D6E582404C790AE4ADCB755BAE2B2F375D +:100CE000E7DAF3ABFED876DBF7E0BFEE6B36C74B47 +:100CF00035E9CE983620375DAE75C2C374EBF2BAD3 +:100D0000223FA27D34F8A15E98C37EE65955705EFD +:100D1000A1C9CF4ABF43C94FE7EF0C4D0ECB3AA450 +:100D20003F0A95ABCEEF1FD382F83EC5D1ED2C0F15 +:100D30006161FF172AF76F930B6598A5E8CA8FB515 +:100D400008C833D120FD63E252D213A2FB6EE13E0C +:100D5000D443F0CEF0B74DAC879A7CEE817C68E846 +:100D60007BC2FBC38CE4FF3BF974E496DC1F6C8709 +:100D7000A176772D3BAB7638FF5D8F7BE469C8BEEB +:100D800042EC33C4FE7479B95745B19D5D91A3DA45 +:100D900022ED55935704FD0E696FF883BE57D3AE0D +:100DA00078FDC9DFC1FE14229CE4F65888DDE9F223 +:100DB000B996DFD1FDD429E13F6AA7FD9F4C917917 +:100DC00080E767166F33F0744339FCDEC98912EE91 +:100DD000D7FC5B283C45798E42716C53C6891188DB +:100DE000D727CDFA3A366F33D17F6A4DF79815344D +:100DF000FF54AE8427911706E1AE30B1107EFDD4CA +:100E0000488B077C3AA54CC8437C38A5DC7F9BC443 +:100E1000E3CD0EE0F3E3F3EC849F34C9F17A5CD1C7 +:100E2000FDFFA9F9DF2BE0718A38027E381451C228 +:100E3000DF51949862A2E7D47D6953D68A81FD3749 +:100E4000E51A789E57F3DF4407F3BDEFE78AB789C9 +:100E50009A1622A410FDC979BF2D4EA1F60F7E313E +:100E60006E32E4EB5A39F8FB88D7C9D703DFCAEBF7 +:100E7000FCE0AB3ED3A2A0B874254E167C2EDBCB93 +:100E8000720CB097724D86AE9809D1904FBF775CC7 +:100E900034E28E1E87FA8FED8F7007C9ED2CC529BD +:100EA000313E089FF06852701C3BBCEB9174AC5310 +:100EB0006EF66439A9FD4CE3D349C837CA773D9C27 +:100EC000CE79F0AE8DE938CF94373D92EE623CDCBE +:100ED000CDE729A3DCF7F97D37EEDC14947757E5ED +:100EE000AB4C7FA9F57021E2EDACEB3E7BC84EE345 +:100EF000D27EA1D8A15EF788EE87101F17203FC6CB +:100F0000F9ADC1CAFE9CD67341FECD137EF81CEC30 +:100F1000F878C6C7A6321A7729D7C8FC5920BC9BD7 +:100F2000E3A95F6C50ECCD2278FC98468C5FB44E00 +:100F30003127C00F2C1F36597560DE30A663F1864D +:100F4000C95D685FB05AB6CFB2780F9CC03ABF3562 +:100F50003B9B1DEC6F524A260DD07F29D7CCF31650 +:100F60006E5638FFD7BF93F6445C63F03E2F69F2AC +:100F7000175F5B14C8E5479A5C6E5DFDEE91045AFD +:100F8000D71EEBBE0CBFF1CEE3A753FDD45E1073AA +:100F900036137A9E66763F55817D37599CD84776C1 +:100FA00056A21A4FE3A7FC34F731C085AB173D5565 +:100FB000017FBBCDCAE7369DBE958AD3007FFC4634 +:100FC000E38F17836F671EB772DEBEB2717CBC18E9 +:100FD000C24E75B89BE4EFA083CEDE7A2BC317EA2E +:100FE000EDC241FAB0AF3E81F117EB1D0CC53CA933 +:100FF0005F2BB5F3F1B5D69BFA55B870503E9BBD4B +:10100000C1261CE4A792E25CA3F2689F69136B9A65 +:10101000366AFB4AA3F9933DC9F9E043F6C6155D6C +:101020004879CD79F23CF6D6890D4970CACB567F06 +:10103000B8A382FAE7E4958CCBA376EBF6CFB9AEF2 +:10104000F046C7C30BC0EFF2268BDC9FB6EF338FA1 +:10105000A7C73F45EB7BDE34F179BF6EFB873B369C +:10106000125CB279853958DFBFEB7E93357ABECDFD +:10107000AEAEC5877FDCAE1E4962FB6922BBCAFCEF +:10108000E7EDAA6EF51AE6DFFD7925B3C0F7332642 +:101090004F12ECE9CC849B59CF3D8714E6BFEEC7D5 +:1010A000F5F9C5DA7EAB0CBECDD39307FCF84591BC +:1010B000CDFC3DDCF1693AF2DE8BEDF3FFEEBE0FC5 +:1010C000D2BEFDB4EF76E2AF7FFCD5FDD3CCEE719E +:1010D0004EDADF3483CC77AFCA5BF30C5ABDA0DBAA +:1010E0005C122979AEA02EA3C54F8A639E68A2A781 +:1010F000BA53F18765219EDD72D688F31E9D1B3F92 +:101100000ACE23E8E7A3A0B87D2D7ABF0DD6629D55 +:10111000B401BFFBBD3F19843F284EDFD81326FC26 +:1011200041DFBD723EA13633C9A9B76324FB05C8B0 +:10113000CD887A5CC78426E067CD528EBD07296FC3 +:1011400092751CA14E1BD8E7D98EF359F0B3A1FBC1 +:10115000AD7DE53CEB4775FBC39F2BBCFF99678DCD +:1011600059DFBEFFC3BBCE67417E674D3DD370DE06 +:10117000EA35F764410EB5AF4A7FFE8FF2416FAF9B +:10118000D8401B213BAF55ACAC2785EA05AE1BF41C +:101190001E937583DA8E9DEC4FFB3B65FDA6CED08A +:1011A0005D148F7AC7F20FBBE0CFFA13E4398AD609 +:1011B00077816FD3C76971D0D8973487FCDA4B57E2 +:1011C000F4419EFFCEC07EC7631D5F35FC80C80A18 +:1011D00017C82BCEC19EA97DC1AAE4F5D0F333DE9A +:1011E0001153E01FDFCAFA6B2DD7FB5E0BB7AB9C28 +:1011F000F7506B90FCAEECC3AB0AD7A07A40B87046 +:10120000058DAB333B7EC4F9F1715520AFAB9B2804 +:10121000ED49BC22EDA966DD617342D07A3B604F97 +:101220004CB7CC1767BDF657B6CBD5335C9DB0CB6A +:1012300070F842AC9710ED55146D1CC9BF56A32130 +:10124000A2533BF717ABDC5FD7AE8A91989310E9B6 +:101250004DA37D148B2D46E4D3B3846F3AEA36C296 +:10126000D8F3AB9BA87FF66BEAD44D82CF4F0B4BE4 +:10127000F85CE94E5D89FCC8A0687CF565CF098EF5 +:101280006779324E4D57158E637D23C3394F993997 +:10129000AFA614F4EAE3B286C971B40EE759C2DB13 +:1012A000973507F6E9EFCB9A1B3930EECED7C297C8 +:1012B000735C14BEEC3B83BE13962FEBA35F501CF4 +:1012C000819ED45D94F58E42F5EB27909FAF3C4410 +:1012D000FA82FCD090FC9E017E9CF80CB99E27B946 +:1012E000BA107FDCC2E582FD4C1AE185FDD4ED53D6 +:1012F000841175A20E4B13EA48B5A69E38E8F3C6D2 +:10130000F63F9AA1CF756DEF9A1D93305FD69DC8B9 +:1013100020D98FD769F1ABA67DFC7BA8F3D51C93B0 +:1013200051B4C6F82E9FDFAB0EB4F239BD5AF8F9AE +:101330009C5EDD32585FFA131C5C1709B58FB07CD8 +:10134000C720BB98B94DDAC59DAA580E3F27B43ABD +:10135000EDCC8478CE4706E6C97CD7A59E7F08F9F8 +:101360004B2045712AB45420CCB30E7991275DE609 +:101370003381DFBD90BD94FD8A37FB76DA5740CBD1 +:1013800077676ED86A5483E899D929EB92813051F6 +:101390007E90E5ED1E0D39085749447E0EDB55164B +:1013A000FC6AC020EBA8A1FBA8D7EA45C7514FCAE9 +:1013B0001CA07B7662A2F463C2CBFAD36590DF7780 +:1013C00019A87FCAC0FCC5F972FEC07948D6C1AE63 +:1013D000E55776917CCA483E7B48CE80CF533C2E61 +:1013E000233FD342F118F8BF523C06F4D56770FB97 +:1013F0004BF54EC60FD4DFC0F8C17A17E3EDF5C543 +:101400000C5FA92FE1F6E320F5FBF8DFD38DD08741 +:101410002ED8D8A801FC644C083E6AF0F89331CA73 +:10142000607C94C2E3B3F39F6EF464A26E6AD7EC5F +:10143000DB1189FCEB8C4DD6A1CED8641DAA759426 +:10144000FBA67CEA2F9BB976973C87BAD231AE20B7 +:10145000663E9F5FFBE9FC0A7FB422DF9D07B91C53 +:101460003B969FBA95FDA48DEBA027EFBA2E9AEB81 +:10147000806FD2799C3E9D9B31755D36E1B9110A32 +:10148000EB2FF98BEB4BF47325AD93DF29EF510A6A +:10149000D5EA32ACBF72A46D2AFCEF172EF7ADA0CF +:1014A00043E777D1A865A9C887BA4C8EF750C7F52E +:1014B000FCDE24709ED2EB7DFAB80E57EE5D9837B5 +:1014C0003363DCBA29F03B6464F0732EB368015DCA +:1014D0002E43B8B296FD96C3083F7097A6C7790E03 +:1014E0009917FBCD0E630CEA3761B9B11E9AD7A5E7 +:1014F000C9F99826E7E39A9CDF469D8CE03BD40E21 +:10150000D84DED809374FE1AFB986F4FE49594B11B +:10151000FE8ABE24E07A5D7016EC4BFA9B24E8F557 +:10152000664D7F13347FD3955B5225E7F9789D2A6A +:10153000ADDE765EBB07D1F7ABCF1B982F18CEBDC3 +:101540005E78ACF0F32FCB73A7184DF908E1735F09 +:101550008E673FA45A6FCFFC84EC7CEE54790E105A +:10156000FB2D725C82230776B256ABB7F67A0D1E5E +:1015700013EAD331DDE93188BF9A7DE9F8C1BFA90B +:10158000ECAF6BA6104EF05545EEAF666E77FA30B5 +:10159000CC576C06AE6F37C9FE139AFDD5A468EB25 +:1015A00069FB11565F12E41138F472D262C23745FA +:1015B000F8974ABFEF4F677F2DFCE973E11715DFFE +:1015C00007C2497965C1D4C5C691E0876F07F0EAC3 +:1015D000829CC5C61BD1DFFA813DB87F842F49B1FB +:1015E00003CF96FD235A770C7306E1A6973E40BFC2 +:1015F000D990B3B880F0D916EFB17AE8CD8B52BF4D +:101600006CFBDA4E836F551D326FCFDBD776E12549 +:10161000C4E5B64827DCFBDEFC64E6F7DA8EDD9B2A +:10162000A16FBDADF23E6053CB1F77FC92C75970DE +:101630004D42EBFAB2057D67C591FF5804BA668743 +:10164000FBBE04FEE091194CE7ECE1D2AE1F3E92E6 +:10165000B71876DADBB6EF67B0BFD9D194D0829EE7 +:10166000176C5C87A8DC3FA10076DA1BD9BD00EBC4 +:10167000D73E6F71424F2BF7C7E7A13E70305FD660 +:10168000C32B266E49429C35BCB277D72F71BFFA67 +:10169000BC8DEF85EA62649E57A9364E5BC1F2DBD2 +:1016A000B9EB69D0BDD7C6F7B315A855115EB12BFC +:1016B0008DEBF8AF7EF3F102C8A150DDBE0BED5FFC +:1016C0003E6733800F27CCAEE89B6187274C7CDEDA +:1016D000ACD0F08A93C3253DE13D452CBFD82D49C0 +:1016E00088B395C37F7E1BE89EAD6ED981F38ED8FB +:1016F0006DE1BB89B37B896F34EF6CB3690AA4DCFD +:10170000BB37D2087D39AF6C59F014D66F96E3CE53 +:10171000DBB6303F3DCDE305BE47E304FCD679653B +:10172000EBA0F6B3CDBBB3701E3DF7FC6C3E97EA61 +:10173000FAABDB4BE573964171913D01F9A34AED9C +:101740006F61F788088AB7151A7AEEE093BD4F8962 +:1017500081F9E75A4C7E33F1A8C222D6596306ECD0 +:10176000A132F19662ECAFD2D0988EBCA5626ACF5E +:1017700002D8C5599BB026D0B8B7B4B8557960CD5A +:101780001CE4BFD7A2E7B2E68F2E26C8F875B1DDFC +:10179000E60DBE970C85EFD70BFBDB6903F83DCB5D +:1017A0002D9CC3EBEBBD65F655E39C561B23FDC793 +:1017B0000734BE85FCD8375ABC5BB86AF0F8FEFC2B +:1017C00018FE7EADB9271DF14F5F3F90AFFBB59E70 +:1017D00074F8ABD079B3918EC08FBCA0B01FA93C78 +:1017E000A07CA8129F2AAD1EAF0ABE08B3BE4FE36D +:1017F0006545CE4B98A6F19DE66E2848E6EF56B6B5 +:10180000D85C369A5715D61385BCA83AB2270AF980 +:101810004EEF2BAA68D2C4151BA7C92745135950F0 +:10182000BDB1C26772D9B2869033F2271AB70C7F66 +:10183000D3F79F2948E1FD94B787F3F784BD671A72 +:10184000F4B47CFBE079D8973DC8FE7ADB77C60517 +:101850009FCB5334BA03CA876C27816F3E4A82DC20 +:101860002B0D621DEE2FCFD11CDC6B122EAC12E7BC +:101870007BCFCABF4484415FCE5DAC66BBED557A79 +:10188000D8AFBD533087FD52AFA987FDDA1B47EEB5 +:1018900064FFD03BAC6701FCD43B05CB64FFC89E22 +:1018A000050EEADFA7E36304C7FDF78FD4B0FF9806 +:1018B000ADCA771562A7C92EEB411B4ED6F3F9C20C +:1018C000E4083E7F9F2AD0EA3D03F2E173976E372A +:1018D000BDC2B1EF00ECB03C82EB3A9447B5BC849A +:1018E0007C6F7E9C13EF35CA314FEA8139F8BE31E7 +:1018F00036E6D252C8E7F6D1EEA2821CDC6FF6F0D3 +:101900003982B49AE34DEDEF2C7C9E0C98FA76C1A7 +:101910004FA58F76CF2A203AAACDDDEBB389A40B51 +:10192000A69E2E94C867A9D21F89DD52AF7A33775D +:10193000CA7B1AEDBEF22E8DFF820E318DD00B4583 +:10194000CAF78DF6FD6FC3AFF4768F637F1C6A37DD +:1019500067DB1F8B827FF813C5714FD079FF4F8BE8 +:1019600076F33DEB3CBC0721B878DD607DE8FFFAFB +:10197000763EF789CD41EDD0C386C178A81E411FC0 +:10198000FD83FC8E87F9BE4DB3ABAABCEE5AF0E1E5 +:101990000A3E977035087F3D040F192F4A649EB0A8 +:1019A0000DF19FF8513DC67F92CFE9FB4C027E7C42 +:1019B0002DC52FC6DBC2BD38AF18F6517C8A95F114 +:1019C0000971A12AAA9BEB53BD6D16BEEF7DB0E352 +:1019D000D324EC9FF490EB30551D2FC7E1FCBE578C +:1019E0003B2F501C8CE3F7316D1D713877E8EDD536 +:1019F000065F3AE8A28C88F375BDBD46F5A783FE65 +:101A00002AA53B0BFD7B41378F275C052E781FD520 +:101A10008AB477D1A1B23F0F95DB939ABE925FC88B +:101A2000E2F71DAFC8FA80EE072A347FF23ADA33C4 +:101A3000A5DDDBF57B259A5A017B1FC23F2414E804 +:101A400079F172AEDF3C5EE090B8369FD795F52510 +:101A5000EEAF7DF57C564A26E669E382FDD0B801FB +:101A6000BF02FB4F60FB7FD01447FBAADCA138D735 +:101A7000C24F95AE29A2E16299714511D7CD8487F5 +:101A8000CF6DA17485EAD1E402C9A74AC3B0C2D818 +:101A9000A0F5CE914F4F98C27EC60FBFF393D847A3 +:101AA0008B50A7F871A97C377025DE04DB39F6B3BB +:101AB0005DFA7198CD65C3D57ABC6C79E3FAF821EB +:101AC000E808A5B3C2DD5814E7B8BA5DA7F79C4D86 +:101AD000A72FCF3422980FF3D6148D20B8CCFACF8D +:101AE000F241EEF75C87C58FB85A51BA627DF410A7 +:101AF0007A73553CD81E14BF52205F2FDF6F5C8B6A +:101B0000FE5058ADF84FA25E24C8AE9AD9BEC85E4A +:101B100082E2C28D05217587F2456391570BF7A2CA +:101B2000B1883364570B9C439C2FC9418E32F09B84 +:101B3000110FC3507AFE5C20DF25DD5820ED7CF5C7 +:101B40000C57007EF366D5C07978E87A5F15C87CBB +:101B5000A23B2EF23EFD3D07847DB32AF99668E84C +:101B60007F07F6961817E9C07D50617EB81C77C8CC +:101B70006647FD2670E812D777030F45CC93F7062A +:101B8000116224F577254C6A0A8E23BF2994FB0D38 +:101B9000CF96794B5D86E9EFD7873223AFD487386C +:101BA0006FC80CE7FB92DEF62F386E053A73ECB87F +:101BB000D7E8EDA6D321D953DD37FF1D87F8DADB4F +:101BC000F9677E87D6FBF5A7FC3E6DA3F63EF0F5E0 +:101BD00076ED7D57B72312ED81E28F8B306E930641 +:101BE00007EA04B25EAC43FDFCABD70382CEC1A3CF +:101BF0000B873E07C7B82382EB048EF8A1EA2AC1FF +:101C00007582D434592700449D20D524EB04C0515B +:101C10002700449D00EDA81300479D0038EA04C04A +:101C2000512700449D00ED5FCE93EF6502A4C4B23E +:101C30007E19C1FEFDDE66D58BFCFCDE43F21EEA9A +:101C4000DE4685DF695DA0EF23CE5DF55EE780F6B9 +:101C50005EC7B795EFF5EADA5427445567EA3B8A41 +:101C6000BA4E5DABE25C03FF523F8FBFBFB133E7BB +:101C7000BD52B4379B9C0607E474310EF5AACACE58 +:101C800066AE3F15C41F32B37C5B14817AE99D16A2 +:101C900079CEAD51A9750ADF87721E5C63E9E6F360 +:101CA00047D51EC55E167C9F7BC3E7EC07D6DAA23C +:101CB0009A40678DCF662F1BE2FD07DF0B3BC49573 +:101CC000FBE6A57288A88928E2FBE6A5B867262866 +:101CD000D4AF8D7C7F4C07D3E1D047BCABCA805BCF +:101CE000B74BBB0F794F55D9D9BA3E515C7D0F8D9B +:101CF000CA00E41F7AFFEC2E8C8C3D1D0E47212676 +:101D0000236F2A7EBC6C5F1B7DAF7F8B85F38E15A6 +:101D1000F9EE65D0A3A32617D7498E1EB2F1F9E8D4 +:101D200093ADE307D549BE70B9AB0BF97E7E34D7CE +:101D30002D569A148ECBF9C5E3E2F9DDC03113C7F5 +:101D40009F0E57492DC6AD9CE4E0FA54A145DCC76F +:101D5000EB68EFB408B23D15AE55BC06C21709A733 +:101D600019F6B390D8C6FA628AD880F7540B857CEE +:101D7000DFA0EBCDCAAD0AE7055C2888C3BDA4E4AB +:101D8000EFC2CE7FBB84F70B4B2C327F4D34C8FBA8 +:101D9000ECC44DF27DCB4F84DB8C78BB8CE22220EF +:101DA000C5C9DFF550BB3B7C7492CCCF1DF1587F89 +:101DB000D17113BFF72D8CFF61BA9BE37501BF632F +:101DC00050FC77AB97AFBBB6FD84BE63386A92FE1A +:101DD00085F8C8E7A22EE825D767DC0C8FD79733A4 +:101DE0009C3443FAC72BEF12494676D01FDEF70129 +:101DF000CE8B89F1914EF83BDDEEAF7A9F1826A18C +:101E0000FE3E710C4111F43E71B3CBC1FE2ED17078 +:101E100062AA03FCF84B8413FCD0DF29AE9E51B2BA +:101E200013727245090FBE8B7B942DC4D7226C446C +:101E3000419DDBE75251B73EA4D8F95DF4557E725F +:101E4000EB4378C75397AAD81507EAE15B0AE38802 +:101E5000EEA29464A6BBAE5DD64B994371A8A76B66 +:101E6000F6E072B7158E18689FADD9452F8D977A19 +:101E7000729317FAF61DEAA8CF61BC47D89CCDDA59 +:101E8000790D729F7DDD18AEA7EA7AD3DF12DF04E9 +:101E9000BD79B350C699D2D2774DC803BA72DD4727 +:101EA000B0FF05659F3F14C7FB1BBA8E457E94EFBC +:101EB0002543EB58BA5FDEA5D5C1E13F8D5A9DD5CC +:101EC000A8D5598D5A9DD5A8D5598D5A9DD5A8D537 +:101ED000598D5A9DD5A8D5598D5A9DD5C8F5BBE5C4 +:101EE0000CDFA95FC5B0BBDEC3FD41FEFFFD6BF893 +:101EF000FFD03AE8C718175A0715564734C751B2EA +:101F00006F597F0EA97B160F5FBC81F897DF607653 +:101F1000A249AF83E2FDF2BD11EC0F2E140E59FF62 +:101F2000D4F916C1F5D27E619B02FEE7658C331AA7 +:101F3000A8FF2F9A1CF4FA23EC03FB837D00C23E1A +:101F40008C6903F6F18C994C385BC67B0FC77B1B01 +:101F5000CB75FD1AF21F842F11F641FEE34288FF74 +:101F6000A083C75DA06369A77CD7A4BFDFCC23F0A3 +:101F7000D59421FC894FFA933161BEBDF8CE98DA31 +:101F8000307E1F7C547B8F7574A37C1757264AF8CC +:101F9000BB43F89528C863C9F0BE0F9EA6F14B1E3F +:101FA00089E0BC65FDC8A5D3FE377EE5F342C98F45 +:101FB000DFD6FB2B3F215A0AC2A4FE15984506EE38 +:101FC0006B84218CEDA050DDACE07E74E53D623287 +:101FD000E45C6029D90E3AE3B5FB6D11ABD55B8D9E +:101FE000DD15BB093F1197E8C4BDD6E8848302EF35 +:101FF0009F0AEB8A33E117FD63DC138A72F07E7966 +:102000008B82F9E19972FFB717873741AF0287C614 +:10201000E740DE732D8E36D4019C45094B70CE9F70 +:102020001BEDC8411DC0D9354AE2F18E36C5895431 +:1020300036614901BF3FB36EF9C48A776B8A88A6BF +:102040007D5986B973F09D9AE2CFE4B959F4711CB9 +:10205000BBB1489EBF46BC2EFCB8B7EA9B19C9F776 +:102060006722D391837ECA2BBF5F44FA77E407AE21 +:102070009B0013353AE3718BA842AADD36C0E3DA40 +:102080007D5E97C15D0A5814E53172BBC19B0DF8A6 +:1020900096C1F753B4933E17619DA2C7264FCC203B +:1020A0003CD1E2633FD9E172DD02FA5E9CE12A068F +:1020B0000CAD9F43B638E7133DB7A23FF41D962EF3 +:1020C000CF254552EFCB8AA4FF98BE56DEC786CAFD +:1020D000BDACC8A0F9B7BF4F37D15B8AEFE9F48B2D +:1020E0002D8BB2410FD17B0FF641F42E001411312C +:1020F0005CEFB8B69E79F87B654552BFC89F557DA9 +:1021000022FD19C374A37718F2C7510F788781DEB7 +:10211000518D7D36FC3B8C673D7D36C4F76757F7A4 +:10212000D9D0FEAC4BBE930E5DBFB148BE9F489F59 +:10213000DEC7F3C7D2B7BA394FEF1B863C2ABDFCC6 +:1021400093F5F2DE2583E3CB582DBE8C7D20A5BD13 +:1021500087F46DEC93D17CBF2D0A62B9BFD22AED12 +:10216000B4F281B2836D04C76F237A83F2AF095E44 +:10217000A27B505E64EC97EF2D09079FF6981887B5 +:10218000CE22BFAA11F2BDE528CD6F206F2B25BF4F +:1021900050537EE412BF03C07CAC8F3B5BE85FBB57 +:1021A00049E214AE711E5D366F4D179F0FB75D6922 +:1021B000D7CE9BADEB717EA6FC6D507B65D9E12E31 +:1021C000C49BAA3D83DB6B967FCEE758CADF06B57A +:1021D000DFF3D30FF99D4D5DFBE07692EF5390BF97 +:1021E0002EDFA326DF049CF78ED68439E5BF1FF0CF +:1021F000AD80BD375547F0FBD99DBFC963BDD1E563 +:102200004DF39BBE9B7EACE5F19E3C91017BF83685 +:10221000D80BFF9436C83F79B8CE372B92FD4E9D30 +:1022200076BEAA2DB3739C4FACB5B2FF2A54C39CA3 +:10223000C06B8DD2CF886255F3533EB6FF13B70DF6 +:10224000E37A1E6F0078CC247E771CB756E27D239C +:102250002CEC1F0A0D25D5BB091E312C673F908041 +:10226000179724F767E01F54D8AFBC7FA833FB143F +:1022700079BFEFC8C17957BF6F6AD8E86D3D80F369 +:10228000B2E27D7229EA8A7744F0FD4100F546DA30 +:102290004FC330E9471BE6A7731C088892D215C8C4 +:1022A00043E68571FDB16198E351DC2736544CE477 +:1022B0003CFAE0DF64DCED9B6375228F6A98EC5892 +:1022C00083F72A0D0F38B8FF5545AEE77954F2A7CA +:1022D000618EDC7F43450C9F7B74393434BA46E20F +:1022E0007E6AC618F77F426EA3B4FBB986646A277C +:1022F000F8845232FF27586792A477D20C07CBEDAF +:10230000E8FC898FEE727038F1E39EA86E56E4A067 +:1023100073F1FF008751D9F610370000000000006C +:102320000000000000000000050015000000000093 +:00000001FF -- cgit v0.10.2 From ca00392cb8f5227c67ff52c656d91a764d022ab9 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 22:53:28 -0700 Subject: bnx2x: Using the new FW The new FW improves the packets per second rate. It required a lot of change in the FW which implies many changes in the driver to support it. It is now also possible for the driver to use a separate MSI-X vector for Rx and Tx - this also add some to the complicity of this change. All things said - after this patch, practically all performance matrixes show improvement. Though Vladislav Zolotarov is not signed on this patch, he did most of the job and deserves credit for that. Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 8bd80fc..16ccba8 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -142,6 +142,9 @@ struct sw_rx_bd { struct sw_tx_bd { struct sk_buff *skb; u16 first_bd; + u8 flags; +/* Set on the first BD descriptor when there is a split BD */ +#define BNX2X_TSO_SPLIT_BD (1<<0) }; struct sw_rx_page { @@ -149,6 +152,11 @@ struct sw_rx_page { DECLARE_PCI_UNMAP_ADDR(mapping) }; +union db_prod { + struct doorbell_set_prod data; + u32 raw; +}; + /* MC hsi */ #define BCM_PAGE_SHIFT 12 @@ -234,15 +242,14 @@ struct bnx2x_fastpath { struct napi_struct napi; + u8 is_rx_queue; + struct host_status_block *status_blk; dma_addr_t status_blk_mapping; - struct eth_tx_db_data *hw_tx_prods; - dma_addr_t tx_prods_mapping; - struct sw_tx_bd *tx_buf_ring; - struct eth_tx_bd *tx_desc_ring; + union eth_tx_bd_types *tx_desc_ring; dma_addr_t tx_desc_mapping; struct sw_rx_bd *rx_buf_ring; /* BDs mappings ring */ @@ -272,6 +279,8 @@ struct bnx2x_fastpath { u8 cl_id; /* eth client id */ u8 sb_id; /* status block number in HW */ + union db_prod tx_db; + u16 tx_pkt_prod; u16 tx_pkt_cons; u16 tx_bd_prod; @@ -309,21 +318,24 @@ struct bnx2x_fastpath { struct xstorm_per_client_stats old_xclient; struct bnx2x_eth_q_stats eth_q_stats; - char name[IFNAMSIZ]; + /* The size is calculated using the following: + sizeof name field from netdev structure + + 4 ('-Xx-' string) + + 4 (for the digits and to make it DWORD aligned) */ +#define FP_NAME_SIZE (sizeof(((struct net_device *)0)->name) + 8) + char name[FP_NAME_SIZE]; struct bnx2x *bp; /* parent */ }; #define bnx2x_fp(bp, nr, var) (bp->fp[nr].var) -#define BNX2X_HAS_WORK(fp) (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp)) - /* MC hsi */ #define MAX_FETCH_BD 13 /* HW max BDs per packet */ #define RX_COPY_THRESH 92 #define NUM_TX_RINGS 16 -#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_tx_bd)) +#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_tx_bd_types)) #define MAX_TX_DESC_CNT (TX_DESC_CNT - 1) #define NUM_TX_BD (TX_DESC_CNT * NUM_TX_RINGS) #define MAX_TX_BD (NUM_TX_BD - 1) @@ -395,7 +407,7 @@ struct bnx2x_fastpath { #define DPM_TRIGER_TYPE 0x40 #define DOORBELL(bp, cid, val) \ do { \ - writel((u32)val, (bp)->doorbells + (BCM_PAGE_SIZE * cid) + \ + writel((u32)(val), bp->doorbells + (BCM_PAGE_SIZE * (cid)) + \ DPM_TRIGER_TYPE); \ } while (0) @@ -902,8 +914,6 @@ struct bnx2x { u16 rx_quick_cons_trip; u16 rx_ticks_int; u16 rx_ticks; -/* Maximal coalescing timeout in us */ -#define BNX2X_MAX_COALESCE_TOUT (0xf0*12) u32 lin_cnt; @@ -985,19 +995,20 @@ struct bnx2x { }; -#define BNX2X_MAX_QUEUES(bp) (IS_E1HMF(bp) ? (MAX_CONTEXT / E1HVN_MAX) : \ - MAX_CONTEXT) -#define BNX2X_NUM_QUEUES(bp) max(bp->num_rx_queues, bp->num_tx_queues) -#define is_multi(bp) (BNX2X_NUM_QUEUES(bp) > 1) +#define BNX2X_MAX_QUEUES(bp) (IS_E1HMF(bp) ? (MAX_CONTEXT/(2 * E1HVN_MAX)) \ + : (MAX_CONTEXT/2)) +#define BNX2X_NUM_QUEUES(bp) (bp->num_rx_queues + bp->num_tx_queues) +#define is_multi(bp) (BNX2X_NUM_QUEUES(bp) > 2) #define for_each_rx_queue(bp, var) \ for (var = 0; var < bp->num_rx_queues; var++) #define for_each_tx_queue(bp, var) \ - for (var = 0; var < bp->num_tx_queues; var++) + for (var = bp->num_rx_queues; \ + var < BNX2X_NUM_QUEUES(bp); var++) #define for_each_queue(bp, var) \ for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++) #define for_each_nondefault_queue(bp, var) \ - for (var = 1; var < BNX2X_NUM_QUEUES(bp); var++) + for (var = 1; var < bp->num_rx_queues; var++) void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32); diff --git a/drivers/net/bnx2x_fw_defs.h b/drivers/net/bnx2x_fw_defs.h index e2df238..931dcac 100644 --- a/drivers/net/bnx2x_fw_defs.h +++ b/drivers/net/bnx2x_fw_defs.h @@ -12,48 +12,117 @@ (IS_E1H_OFFSET ? 0x7000 : 0x1000) #define CSTORM_ASSERT_LIST_OFFSET(idx) \ (IS_E1H_OFFSET ? (0x7020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) -#define CSTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ - (IS_E1H_OFFSET ? (0x8522 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100) + (index * 0x4)) : (0x1922 + (function * \ +#define CSTORM_DEF_SB_HC_DISABLE_C_OFFSET(function, index) \ + (IS_E1H_OFFSET ? (0x8622 + ((function>>1) * 0x40) + \ + ((function&1) * 0x100) + (index * 0x4)) : (0x3562 + (function * \ 0x40) + (index * 0x4))) -#define CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x8500 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100)) : (0x1900 + (function * 0x40))) -#define CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x8508 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100)) : (0x1908 + (function * 0x40))) +#define CSTORM_DEF_SB_HC_DISABLE_U_OFFSET(function, index) \ + (IS_E1H_OFFSET ? (0x8822 + ((function>>1) * 0x80) + \ + ((function&1) * 0x200) + (index * 0x4)) : (0x35e2 + (function * \ + 0x80) + (index * 0x4))) +#define CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8600 + ((function>>1) * 0x40) + \ + ((function&1) * 0x100)) : (0x3540 + (function * 0x40))) +#define CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8800 + ((function>>1) * 0x80) + \ + ((function&1) * 0x200)) : (0x35c0 + (function * 0x80))) +#define CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8608 + ((function>>1) * 0x40) + \ + ((function&1) * 0x100)) : (0x3548 + (function * 0x40))) +#define CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8808 + ((function>>1) * 0x80) + \ + ((function&1) * 0x200)) : (0x35c8 + (function * 0x80))) #define CSTORM_FUNCTION_MODE_OFFSET \ (IS_E1H_OFFSET ? 0x11e8 : 0xffffffff) -#define CSTORM_HC_BTR_OFFSET(port) \ - (IS_E1H_OFFSET ? (0x8704 + (port * 0xf0)) : (0x1984 + (port * 0xc0))) -#define CSTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index) \ - (IS_E1H_OFFSET ? (0x801a + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4)) : (0x141a + (port * 0x280) + (cpu_id * 0x28) + \ +#define CSTORM_HC_BTR_C_OFFSET(port) \ + (IS_E1H_OFFSET ? (0x8c04 + (port * 0xf0)) : (0x36c4 + (port * 0xc0))) +#define CSTORM_HC_BTR_U_OFFSET(port) \ + (IS_E1H_OFFSET ? (0x8de4 + (port * 0xf0)) : (0x3844 + (port * 0xc0))) +#define CSTORM_ISCSI_CQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6680 + (function * 0x8)) : (0x25a0 + \ + (function * 0x8))) +#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x66c0 + (function * 0x8)) : (0x25b0 + \ + (function * 0x8))) +#define CSTORM_ISCSI_EQ_CONS_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6040 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2410 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6044 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2414 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x604c + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x241c + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6057 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2427 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_PROD_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6042 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2412 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6056 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2426 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6054 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2424 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_HQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6640 + (function * 0x8)) : (0x2590 + \ + (function * 0x8))) +#define CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6004 + (function * 0x8)) : (0x2404 + \ + (function * 0x8))) +#define CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6002 + (function * 0x8)) : (0x2402 + \ + (function * 0x8))) +#define CSTORM_ISCSI_PAGE_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6000 + (function * 0x8)) : (0x2400 + \ + (function * 0x8))) +#define CSTORM_SB_HC_DISABLE_C_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET ? (0x811a + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4)) : (0x305a + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4))) +#define CSTORM_SB_HC_DISABLE_U_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET ? (0xb01a + (port * 0x800) + (cpu_id * 0x80) + \ + (index * 0x4)) : (0x401a + (port * 0x800) + (cpu_id * 0x80) + \ (index * 0x4))) -#define CSTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index) \ - (IS_E1H_OFFSET ? (0x8018 + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4)) : (0x1418 + (port * 0x280) + (cpu_id * 0x28) + \ +#define CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET ? (0x8118 + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4)) : (0x3058 + (port * 0x280) + (cpu_id * 0x28) + \ (index * 0x4))) -#define CSTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id) \ - (IS_E1H_OFFSET ? (0x8000 + (port * 0x280) + (cpu_id * 0x28)) : \ - (0x1400 + (port * 0x280) + (cpu_id * 0x28))) -#define CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, cpu_id) \ - (IS_E1H_OFFSET ? (0x8008 + (port * 0x280) + (cpu_id * 0x28)) : \ - (0x1408 + (port * 0x280) + (cpu_id * 0x28))) +#define CSTORM_SB_HC_TIMEOUT_U_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET ? (0xb018 + (port * 0x800) + (cpu_id * 0x80) + \ + (index * 0x4)) : (0x4018 + (port * 0x800) + (cpu_id * 0x80) + \ + (index * 0x4))) +#define CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET ? (0x8100 + (port * 0x280) + (cpu_id * 0x28)) : \ + (0x3040 + (port * 0x280) + (cpu_id * 0x28))) +#define CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET ? (0xb000 + (port * 0x800) + (cpu_id * 0x80)) : \ + (0x4000 + (port * 0x800) + (cpu_id * 0x80))) +#define CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET ? (0x8108 + (port * 0x280) + (cpu_id * 0x28)) : \ + (0x3048 + (port * 0x280) + (cpu_id * 0x28))) +#define CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET ? (0xb008 + (port * 0x800) + (cpu_id * 0x80)) : \ + (0x4008 + (port * 0x800) + (cpu_id * 0x80))) +#define CSTORM_SB_STATUS_BLOCK_C_SIZE 0x10 +#define CSTORM_SB_STATUS_BLOCK_U_SIZE 0x60 #define CSTORM_STATS_FLAGS_OFFSET(function) \ (IS_E1H_OFFSET ? (0x1108 + (function * 0x8)) : (0x5108 + \ (function * 0x8))) #define TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x31c0 + (function * 0x20)) : 0xffffffff) + (IS_E1H_OFFSET ? (0x3200 + (function * 0x20)) : 0xffffffff) #define TSTORM_ASSERT_LIST_INDEX_OFFSET \ (IS_E1H_OFFSET ? 0xa000 : 0x1000) #define TSTORM_ASSERT_LIST_OFFSET(idx) \ (IS_E1H_OFFSET ? (0xa020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) #define TSTORM_CLIENT_CONFIG_OFFSET(port, client_id) \ - (IS_E1H_OFFSET ? (0x3350 + (port * 0x190) + (client_id * 0x10)) \ - : (0x9c0 + (port * 0x130) + (client_id * 0x10))) + (IS_E1H_OFFSET ? (0x33a0 + (port * 0x1a0) + (client_id * 0x10)) \ + : (0x9c0 + (port * 0x120) + (client_id * 0x10))) #define TSTORM_COMMON_SAFC_WORKAROUND_ENABLE_OFFSET \ - (IS_E1H_OFFSET ? 0x1ad8 : 0xffffffff) + (IS_E1H_OFFSET ? 0x1ed8 : 0xffffffff) +#define TSTORM_COMMON_SAFC_WORKAROUND_TIMEOUT_10USEC_OFFSET \ + (IS_E1H_OFFSET ? 0x1eda : 0xffffffff) #define TSTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ (IS_E1H_OFFSET ? (0xb01a + ((function>>1) * 0x28) + \ ((function&1) * 0xa0) + (index * 0x4)) : (0x141a + (function * \ @@ -65,95 +134,133 @@ (IS_E1H_OFFSET ? (0xb008 + ((function>>1) * 0x28) + \ ((function&1) * 0xa0)) : (0x1408 + (function * 0x28))) #define TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2b80 + (function * 0x8)) : (0x4b68 + \ + (IS_E1H_OFFSET ? (0x2940 + (function * 0x8)) : (0x4928 + \ (function * 0x8))) #define TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x3000 + (function * 0x38)) : (0x1500 + \ - (function * 0x38))) + (IS_E1H_OFFSET ? (0x3000 + (function * 0x40)) : (0x1500 + \ + (function * 0x40))) #define TSTORM_FUNCTION_MODE_OFFSET \ - (IS_E1H_OFFSET ? 0x1ad0 : 0xffffffff) + (IS_E1H_OFFSET ? 0x1ed0 : 0xffffffff) #define TSTORM_HC_BTR_OFFSET(port) \ (IS_E1H_OFFSET ? (0xb144 + (port * 0x30)) : (0x1454 + (port * 0x18))) #define TSTORM_INDIRECTION_TABLE_OFFSET(function) \ (IS_E1H_OFFSET ? (0x12c8 + (function * 0x80)) : (0x22c8 + \ (function * 0x80))) #define TSTORM_INDIRECTION_TABLE_SIZE 0x80 +#define TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(function, pblEntry) \ + (IS_E1H_OFFSET ? (0x60c0 + (function * 0x40) + (pblEntry * 0x8)) \ + : (0x4c30 + (function * 0x40) + (pblEntry * 0x8))) +#define TSTORM_ISCSI_ERROR_BITMAP_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6340 + (function * 0x8)) : (0x4cd0 + \ + (function * 0x8))) +#define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6004 + (function * 0x8)) : (0x4c04 + \ + (function * 0x8))) +#define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6002 + (function * 0x8)) : (0x4c02 + \ + (function * 0x8))) +#define TSTORM_ISCSI_PAGE_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6000 + (function * 0x8)) : (0x4c00 + \ + (function * 0x8))) +#define TSTORM_ISCSI_RQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6080 + (function * 0x8)) : (0x4c20 + \ + (function * 0x8))) +#define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6040 + (function * 0x8)) : (0x4c10 + \ + (function * 0x8))) +#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6042 + (function * 0x8)) : (0x4c12 + \ + (function * 0x8))) +#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6044 + (function * 0x8)) : (0x4c14 + \ + (function * 0x8))) #define TSTORM_MAC_FILTER_CONFIG_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x3008 + (function * 0x38)) : (0x1508 + \ - (function * 0x38))) + (IS_E1H_OFFSET ? (0x3008 + (function * 0x40)) : (0x1508 + \ + (function * 0x40))) #define TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, stats_counter_id) \ - (IS_E1H_OFFSET ? (0x2010 + (port * 0x5b0) + (stats_counter_id * \ - 0x50)) : (0x4080 + (port * 0x5b0) + (stats_counter_id * 0x50))) + (IS_E1H_OFFSET ? (0x2010 + (port * 0x490) + (stats_counter_id * \ + 0x40)) : (0x4010 + (port * 0x490) + (stats_counter_id * 0x40))) #define TSTORM_STATS_FLAGS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2c00 + (function * 0x8)) : (0x4b88 + \ + (IS_E1H_OFFSET ? (0x29c0 + (function * 0x8)) : (0x4948 + \ (function * 0x8))) -#define TSTORM_TPA_EXIST_OFFSET (IS_E1H_OFFSET ? 0x3680 : 0x1c20) -#define USTORM_AGG_DATA_OFFSET (IS_E1H_OFFSET ? 0xa040 : 0x2c10) -#define USTORM_AGG_DATA_SIZE (IS_E1H_OFFSET ? 0x2440 : 0x1200) +#define TSTORM_TCP_MAX_CWND_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x4004 + (function * 0x8)) : (0x1fb4 + \ + (function * 0x8))) +#define USTORM_AGG_DATA_OFFSET (IS_E1H_OFFSET ? 0xa000 : 0x3000) +#define USTORM_AGG_DATA_SIZE (IS_E1H_OFFSET ? 0x2000 : 0x1000) #define USTORM_ASSERT_LIST_INDEX_OFFSET \ - (IS_E1H_OFFSET ? 0x8960 : 0x1000) + (IS_E1H_OFFSET ? 0x8000 : 0x1000) #define USTORM_ASSERT_LIST_OFFSET(idx) \ - (IS_E1H_OFFSET ? (0x8980 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) + (IS_E1H_OFFSET ? (0x8020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) #define USTORM_CQE_PAGE_BASE_OFFSET(port, clientId) \ - (IS_E1H_OFFSET ? (0x8018 + (port * 0x4b0) + (clientId * 0x30)) : \ - (0x5330 + (port * 0x260) + (clientId * 0x20))) -#define USTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ - (IS_E1H_OFFSET ? (0x9522 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100) + (index * 0x4)) : (0x1922 + (function * \ - 0x40) + (index * 0x4))) -#define USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x9500 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100)) : (0x1900 + (function * 0x40))) -#define USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x9508 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100)) : (0x1908 + (function * 0x40))) + (IS_E1H_OFFSET ? (0x1010 + (port * 0x680) + (clientId * 0x40)) : \ + (0x4010 + (port * 0x360) + (clientId * 0x30))) +#define USTORM_CQE_PAGE_NEXT_OFFSET(port, clientId) \ + (IS_E1H_OFFSET ? (0x1028 + (port * 0x680) + (clientId * 0x40)) : \ + (0x4028 + (port * 0x360) + (clientId * 0x30))) +#define USTORM_ETH_PAUSE_ENABLED_OFFSET(port) \ + (IS_E1H_OFFSET ? (0x2ad4 + (port * 0x8)) : 0xffffffff) #define USTORM_ETH_RING_PAUSE_DATA_OFFSET(port, clientId) \ - (IS_E1H_OFFSET ? (0x8020 + (port * 0x4b0) + (clientId * 0x30)) : \ + (IS_E1H_OFFSET ? (0x1030 + (port * 0x680) + (clientId * 0x40)) : \ 0xffffffff) #define USTORM_ETH_STATS_QUERY_ADDR_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2a50 + (function * 0x8)) : (0x1d98 + \ + (IS_E1H_OFFSET ? (0x2a50 + (function * 0x8)) : (0x1dd0 + \ (function * 0x8))) #define USTORM_FUNCTION_MODE_OFFSET \ (IS_E1H_OFFSET ? 0x2448 : 0xffffffff) -#define USTORM_HC_BTR_OFFSET(port) \ - (IS_E1H_OFFSET ? (0x9704 + (port * 0xf0)) : (0x1984 + (port * 0xc0))) +#define USTORM_ISCSI_CQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7044 + (function * 0x8)) : (0x2414 + \ + (function * 0x8))) +#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7046 + (function * 0x8)) : (0x2416 + \ + (function * 0x8))) +#define USTORM_ISCSI_ERROR_BITMAP_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7688 + (function * 0x8)) : (0x29c8 + \ + (function * 0x8))) +#define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7648 + (function * 0x8)) : (0x29b8 + \ + (function * 0x8))) +#define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7004 + (function * 0x8)) : (0x2404 + \ + (function * 0x8))) +#define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7002 + (function * 0x8)) : (0x2402 + \ + (function * 0x8))) +#define USTORM_ISCSI_PAGE_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7000 + (function * 0x8)) : (0x2400 + \ + (function * 0x8))) +#define USTORM_ISCSI_R2TQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7040 + (function * 0x8)) : (0x2410 + \ + (function * 0x8))) +#define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7080 + (function * 0x8)) : (0x2420 + \ + (function * 0x8))) +#define USTORM_ISCSI_RQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7084 + (function * 0x8)) : (0x2424 + \ + (function * 0x8))) #define USTORM_MAX_AGG_SIZE_OFFSET(port, clientId) \ - (IS_E1H_OFFSET ? (0x8010 + (port * 0x4b0) + (clientId * 0x30)) : \ - (0x5328 + (port * 0x260) + (clientId * 0x20))) + (IS_E1H_OFFSET ? (0x1018 + (port * 0x680) + (clientId * 0x40)) : \ + (0x4018 + (port * 0x360) + (clientId * 0x30))) #define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2408 + (function * 0x8)) : (0x5308 + \ + (IS_E1H_OFFSET ? (0x2408 + (function * 0x8)) : (0x1da8 + \ (function * 0x8))) -#define USTORM_PAUSE_ENABLED_OFFSET(port) \ - (IS_E1H_OFFSET ? (0x2ad4 + (port * 0x8)) : 0xffffffff) #define USTORM_PER_COUNTER_ID_STATS_OFFSET(port, stats_counter_id) \ (IS_E1H_OFFSET ? (0x2450 + (port * 0x2d0) + (stats_counter_id * \ - 0x28)) : (0x4740 + (port * 0x2d0) + (stats_counter_id * 0x28))) + 0x28)) : (0x1500 + (port * 0x2d0) + (stats_counter_id * 0x28))) #define USTORM_RX_PRODS_OFFSET(port, client_id) \ - (IS_E1H_OFFSET ? (0x8000 + (port * 0x4b0) + (client_id * 0x30)) \ - : (0x5318 + (port * 0x260) + (client_id * 0x20))) -#define USTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index) \ - (IS_E1H_OFFSET ? (0x901a + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4)) : (0x141a + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4))) -#define USTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index) \ - (IS_E1H_OFFSET ? (0x9018 + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4)) : (0x1418 + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4))) -#define USTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id) \ - (IS_E1H_OFFSET ? (0x9000 + (port * 0x280) + (cpu_id * 0x28)) : \ - (0x1400 + (port * 0x280) + (cpu_id * 0x28))) -#define USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, cpu_id) \ - (IS_E1H_OFFSET ? (0x9008 + (port * 0x280) + (cpu_id * 0x28)) : \ - (0x1408 + (port * 0x280) + (cpu_id * 0x28))) + (IS_E1H_OFFSET ? (0x1000 + (port * 0x680) + (client_id * 0x40)) \ + : (0x4000 + (port * 0x360) + (client_id * 0x30))) #define USTORM_STATS_FLAGS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x29f0 + (function * 0x8)) : (0x1d80 + \ + (IS_E1H_OFFSET ? (0x29f0 + (function * 0x8)) : (0x1db8 + \ (function * 0x8))) +#define USTORM_TPA_BTR_OFFSET (IS_E1H_OFFSET ? 0x3da5 : 0x5095) +#define USTORM_TPA_BTR_SIZE 0x1 #define XSTORM_ASSERT_LIST_INDEX_OFFSET \ (IS_E1H_OFFSET ? 0x9000 : 0x1000) #define XSTORM_ASSERT_LIST_OFFSET(idx) \ (IS_E1H_OFFSET ? (0x9020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) #define XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) \ - (IS_E1H_OFFSET ? (0x24a8 + (port * 0x50)) : (0x3ba0 + (port * 0x50))) + (IS_E1H_OFFSET ? (0x24a8 + (port * 0x50)) : (0x3a80 + (port * 0x50))) #define XSTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ (IS_E1H_OFFSET ? (0xa01a + ((function>>1) * 0x28) + \ ((function&1) * 0xa0) + (index * 0x4)) : (0x141a + (function * \ @@ -165,22 +272,73 @@ (IS_E1H_OFFSET ? (0xa008 + ((function>>1) * 0x28) + \ ((function&1) * 0xa0)) : (0x1408 + (function * 0x28))) #define XSTORM_E1HOV_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2c10 + (function * 0x2)) : 0xffffffff) + (IS_E1H_OFFSET ? (0x2c10 + (function * 0x8)) : 0xffffffff) #define XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2418 + (function * 0x8)) : (0x3b70 + \ + (IS_E1H_OFFSET ? (0x2418 + (function * 0x8)) : (0x3a50 + \ (function * 0x8))) #define XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2588 + (function * 0x90)) : (0x3c80 + \ + (IS_E1H_OFFSET ? (0x2588 + (function * 0x90)) : (0x3b60 + \ (function * 0x90))) #define XSTORM_FUNCTION_MODE_OFFSET \ - (IS_E1H_OFFSET ? 0x2c20 : 0xffffffff) + (IS_E1H_OFFSET ? 0x2c50 : 0xffffffff) #define XSTORM_HC_BTR_OFFSET(port) \ (IS_E1H_OFFSET ? (0xa144 + (port * 0x30)) : (0x1454 + (port * 0x18))) +#define XSTORM_ISCSI_HQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x80c0 + (function * 0x8)) : (0x1c30 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8080 + (function * 0x8)) : (0x1c20 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8081 + (function * 0x8)) : (0x1c21 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8082 + (function * 0x8)) : (0x1c22 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8083 + (function * 0x8)) : (0x1c23 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8084 + (function * 0x8)) : (0x1c24 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8085 + (function * 0x8)) : (0x1c25 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8086 + (function * 0x8)) : (0x1c26 + \ + (function * 0x8))) +#define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8004 + (function * 0x8)) : (0x1c04 + \ + (function * 0x8))) +#define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8002 + (function * 0x8)) : (0x1c02 + \ + (function * 0x8))) +#define XSTORM_ISCSI_PAGE_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8000 + (function * 0x8)) : (0x1c00 + \ + (function * 0x8))) +#define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x80c4 + (function * 0x8)) : (0x1c34 + \ + (function * 0x8))) +#define XSTORM_ISCSI_SQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x80c2 + (function * 0x8)) : (0x1c32 + \ + (function * 0x8))) +#define XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8043 + (function * 0x8)) : (0x1c13 + \ + (function * 0x8))) +#define XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8042 + (function * 0x8)) : (0x1c12 + \ + (function * 0x8))) +#define XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8041 + (function * 0x8)) : (0x1c11 + \ + (function * 0x8))) +#define XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8040 + (function * 0x8)) : (0x1c10 + \ + (function * 0x8))) #define XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, stats_counter_id) \ - (IS_E1H_OFFSET ? (0xc000 + (port * 0x3f0) + (stats_counter_id * \ - 0x38)) : (0x3378 + (port * 0x3f0) + (stats_counter_id * 0x38))) + (IS_E1H_OFFSET ? (0xc000 + (port * 0x360) + (stats_counter_id * \ + 0x30)) : (0x3378 + (port * 0x360) + (stats_counter_id * 0x30))) #define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2548 + (function * 0x90)) : (0x3c40 + \ + (IS_E1H_OFFSET ? (0x2548 + (function * 0x90)) : (0x3b20 + \ (function * 0x90))) #define XSTORM_SPQ_PAGE_BASE_OFFSET(function) \ (IS_E1H_OFFSET ? (0x2000 + (function * 0x10)) : (0x3328 + \ @@ -189,8 +347,15 @@ (IS_E1H_OFFSET ? (0x2008 + (function * 0x10)) : (0x3330 + \ (function * 0x10))) #define XSTORM_STATS_FLAGS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x23d8 + (function * 0x8)) : (0x3b60 + \ + (IS_E1H_OFFSET ? (0x23d8 + (function * 0x8)) : (0x3a40 + \ (function * 0x8))) +#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(port) \ + (IS_E1H_OFFSET ? (0x4000 + (port * 0x8)) : (0x1960 + (port * 0x8))) +#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(port) \ + (IS_E1H_OFFSET ? (0x4001 + (port * 0x8)) : (0x1961 + (port * 0x8))) +#define XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x4060 + ((function>>1) * 0x8) + ((function&1) \ + * 0x4)) : (0x1978 + (function * 0x4))) #define COMMON_ASM_INVALID_ASSERT_OPCODE 0x0 /** @@ -211,6 +376,9 @@ #define TCP_IPV4_HASH_TYPE 2 #define IPV6_HASH_TYPE 3 #define TCP_IPV6_HASH_TYPE 4 +#define VLAN_PRI_HASH_TYPE 5 +#define E1HOV_PRI_HASH_TYPE 6 +#define DSCP_HASH_TYPE 7 /* Ethernet Ring parameters */ @@ -218,30 +386,26 @@ #define FIRST_BD_IN_PKT 0 #define PARSE_BD_INDEX 1 #define NUM_OF_ETH_BDS_IN_PAGE ((PAGE_SIZE)/(STRUCT_SIZE(eth_tx_bd)/8)) - +#define U_ETH_NUM_OF_SGES_TO_FETCH 8 +#define U_ETH_MAX_SGES_FOR_PACKET 3 /* Rx ring params */ -#define U_ETH_LOCAL_BD_RING_SIZE 16 -#define U_ETH_LOCAL_SGE_RING_SIZE 12 +#define U_ETH_LOCAL_BD_RING_SIZE 8 +#define U_ETH_LOCAL_SGE_RING_SIZE 10 #define U_ETH_SGL_SIZE 8 -#define U_ETH_BDS_PER_PAGE_MASK \ - ((PAGE_SIZE/(STRUCT_SIZE(eth_rx_bd)/8))-1) -#define U_ETH_CQE_PER_PAGE_MASK \ - ((PAGE_SIZE/(STRUCT_SIZE(eth_rx_cqe)/8))-1) -#define U_ETH_SGES_PER_PAGE_MASK \ - ((PAGE_SIZE/(STRUCT_SIZE(eth_rx_sge)/8))-1) - #define U_ETH_SGES_PER_PAGE_INVERSE_MASK \ (0xFFFF - ((PAGE_SIZE/((STRUCT_SIZE(eth_rx_sge))/8))-1)) - -#define TU_ETH_CQES_PER_PAGE \ - (PAGE_SIZE/(STRUCT_SIZE(eth_rx_cqe_next_page)/8)) +#define TU_ETH_CQES_PER_PAGE (PAGE_SIZE/(STRUCT_SIZE(eth_rx_cqe)/8)) #define U_ETH_BDS_PER_PAGE (PAGE_SIZE/(STRUCT_SIZE(eth_rx_bd)/8)) #define U_ETH_SGES_PER_PAGE (PAGE_SIZE/(STRUCT_SIZE(eth_rx_sge)/8)) +#define U_ETH_BDS_PER_PAGE_MASK (U_ETH_BDS_PER_PAGE-1) +#define U_ETH_CQE_PER_PAGE_MASK (TU_ETH_CQES_PER_PAGE-1) +#define U_ETH_SGES_PER_PAGE_MASK (U_ETH_SGES_PER_PAGE-1) + #define U_ETH_UNDEFINED_Q 0xFF /* values of command IDs in the ramrod message */ @@ -266,8 +430,8 @@ #define T_ETH_CRC32_HASH_SEED 0x00000000 /* Maximal L2 clients supported */ -#define ETH_MAX_RX_CLIENTS_E1 19 -#define ETH_MAX_RX_CLIENTS_E1H 25 +#define ETH_MAX_RX_CLIENTS_E1 18 +#define ETH_MAX_RX_CLIENTS_E1H 26 /* Maximal aggregation queues supported */ #define ETH_MAX_AGGREGATION_QUEUES_E1 32 @@ -276,6 +440,9 @@ /* ETH RSS modes */ #define ETH_RSS_MODE_DISABLED 0 #define ETH_RSS_MODE_REGULAR 1 +#define ETH_RSS_MODE_VLAN_PRI 2 +#define ETH_RSS_MODE_E1HOV_PRI 3 +#define ETH_RSS_MODE_IP_DSCP 4 /** @@ -332,12 +499,14 @@ #define HC_INDEX_DEF_C_ETH_SLOW_PATH 3 #define HC_INDEX_DEF_C_ETH_RDMA_CQ_CONS 4 #define HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS 5 +#define HC_INDEX_DEF_C_ETH_FCOE_CQ_CONS 6 #define HC_INDEX_DEF_U_ETH_RDMA_RX_CQ_CONS 0 #define HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS 1 #define HC_INDEX_DEF_U_ETH_RDMA_RX_BD_CONS 2 #define HC_INDEX_DEF_U_ETH_ISCSI_RX_BD_CONS 3 - +#define HC_INDEX_DEF_U_ETH_FCOE_RX_CQ_CONS 4 +#define HC_INDEX_DEF_U_ETH_FCOE_RX_BD_CONS 5 /* used by the driver to get the SB offset */ #define USTORM_ID 0 diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h index 7de83c4..da62cc5 100644 --- a/drivers/net/bnx2x_hsi.h +++ b/drivers/net/bnx2x_hsi.h @@ -1218,9 +1218,9 @@ struct host_func_stats { }; -#define BCM_5710_FW_MAJOR_VERSION 4 -#define BCM_5710_FW_MINOR_VERSION 8 -#define BCM_5710_FW_REVISION_VERSION 53 +#define BCM_5710_FW_MAJOR_VERSION 5 +#define BCM_5710_FW_MINOR_VERSION 0 +#define BCM_5710_FW_REVISION_VERSION 21 #define BCM_5710_FW_ENGINEERING_VERSION 0 #define BCM_5710_FW_COMPILE_FLAGS 1 @@ -1270,6 +1270,22 @@ struct doorbell { /* + * doorbell message sent to the chip + */ +struct doorbell_set_prod { +#if defined(__BIG_ENDIAN) + u16 prod; + u8 zero_fill1; + struct doorbell_hdr header; +#elif defined(__LITTLE_ENDIAN) + struct doorbell_hdr header; + u8 zero_fill1; + u16 prod; +#endif +}; + + +/* * IGU driver acknowledgement register */ struct igu_ack_register { @@ -1304,6 +1320,62 @@ struct igu_ack_register { /* + * IGU driver acknowledgement register + */ +struct igu_backward_compatible { + u32 sb_id_and_flags; +#define IGU_BACKWARD_COMPATIBLE_SB_INDEX (0xFFFF<<0) +#define IGU_BACKWARD_COMPATIBLE_SB_INDEX_SHIFT 0 +#define IGU_BACKWARD_COMPATIBLE_SB_SELECT (0x1F<<16) +#define IGU_BACKWARD_COMPATIBLE_SB_SELECT_SHIFT 16 +#define IGU_BACKWARD_COMPATIBLE_SEGMENT_ACCESS (0x7<<21) +#define IGU_BACKWARD_COMPATIBLE_SEGMENT_ACCESS_SHIFT 21 +#define IGU_BACKWARD_COMPATIBLE_BUPDATE (0x1<<24) +#define IGU_BACKWARD_COMPATIBLE_BUPDATE_SHIFT 24 +#define IGU_BACKWARD_COMPATIBLE_ENABLE_INT (0x3<<25) +#define IGU_BACKWARD_COMPATIBLE_ENABLE_INT_SHIFT 25 +#define IGU_BACKWARD_COMPATIBLE_RESERVED_0 (0x1F<<27) +#define IGU_BACKWARD_COMPATIBLE_RESERVED_0_SHIFT 27 + u32 reserved_2; +}; + + +/* + * IGU driver acknowledgement register + */ +struct igu_regular { + u32 sb_id_and_flags; +#define IGU_REGULAR_SB_INDEX (0xFFFFF<<0) +#define IGU_REGULAR_SB_INDEX_SHIFT 0 +#define IGU_REGULAR_RESERVED0 (0x1<<20) +#define IGU_REGULAR_RESERVED0_SHIFT 20 +#define IGU_REGULAR_SEGMENT_ACCESS (0x7<<21) +#define IGU_REGULAR_SEGMENT_ACCESS_SHIFT 21 +#define IGU_REGULAR_BUPDATE (0x1<<24) +#define IGU_REGULAR_BUPDATE_SHIFT 24 +#define IGU_REGULAR_ENABLE_INT (0x3<<25) +#define IGU_REGULAR_ENABLE_INT_SHIFT 25 +#define IGU_REGULAR_RESERVED_1 (0x1<<27) +#define IGU_REGULAR_RESERVED_1_SHIFT 27 +#define IGU_REGULAR_CLEANUP_TYPE (0x3<<28) +#define IGU_REGULAR_CLEANUP_TYPE_SHIFT 28 +#define IGU_REGULAR_CLEANUP_SET (0x1<<30) +#define IGU_REGULAR_CLEANUP_SET_SHIFT 30 +#define IGU_REGULAR_BCLEANUP (0x1<<31) +#define IGU_REGULAR_BCLEANUP_SHIFT 31 + u32 reserved_2; +}; + +/* + * IGU driver acknowledgement register + */ +union igu_consprod_reg { + struct igu_regular regular; + struct igu_backward_compatible backward_compatible; +}; + + +/* * Parser parsing flags field */ struct parsing_flags { @@ -1434,12 +1506,10 @@ struct ustorm_eth_st_context_config { #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC_SHIFT 1 #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA (0x1<<2) #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA_SHIFT 2 -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING (0x1<<3) -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING_SHIFT 3 -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS (0x1<<4) -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS_SHIFT 4 -#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0x7<<5) -#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 5 +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS (0x1<<3) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS_SHIFT 3 +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0xF<<4) +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 4 u8 status_block_id; u8 clientId; u8 sb_index_numbers; @@ -1462,12 +1532,10 @@ struct ustorm_eth_st_context_config { #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC_SHIFT 1 #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA (0x1<<2) #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA_SHIFT 2 -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING (0x1<<3) -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING_SHIFT 3 -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS (0x1<<4) -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS_SHIFT 4 -#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0x7<<5) -#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 5 +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS (0x1<<3) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS_SHIFT 3 +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0xF<<4) +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 4 #endif #if defined(__BIG_ENDIAN) u16 bd_buff_size; @@ -1487,11 +1555,36 @@ struct ustorm_eth_st_context_config { u8 __local_bd_prod; u8 __local_sge_prod; #endif - u32 reserved; +#if defined(__BIG_ENDIAN) + u16 __sdm_bd_expected_counter; + u8 cstorm_agg_int; + u8 __expected_bds_on_ram; +#elif defined(__LITTLE_ENDIAN) + u8 __expected_bds_on_ram; + u8 cstorm_agg_int; + u16 __sdm_bd_expected_counter; +#endif +#if defined(__BIG_ENDIAN) + u16 __ring_data_ram_addr; + u16 __hc_cstorm_ram_addr; +#elif defined(__LITTLE_ENDIAN) + u16 __hc_cstorm_ram_addr; + u16 __ring_data_ram_addr; +#endif +#if defined(__BIG_ENDIAN) + u8 reserved1; + u8 max_sges_for_packet; + u16 __bd_ring_ram_addr; +#elif defined(__LITTLE_ENDIAN) + u16 __bd_ring_ram_addr; + u8 max_sges_for_packet; + u8 reserved1; +#endif u32 bd_page_base_lo; u32 bd_page_base_hi; u32 sge_page_base_lo; u32 sge_page_base_hi; + struct regpair reserved2; }; /* @@ -1514,8 +1607,8 @@ struct eth_rx_sge { * Local BDs and SGEs rings (in ETH) */ struct eth_local_rx_rings { - struct eth_rx_bd __local_bd_ring[16]; - struct eth_rx_sge __local_sge_ring[12]; + struct eth_rx_bd __local_bd_ring[8]; + struct eth_rx_sge __local_sge_ring[10]; }; /* @@ -1607,13 +1700,13 @@ struct xstorm_eth_extra_ag_context_section { */ struct xstorm_eth_ag_context { #if defined(__BIG_ENDIAN) - u16 __bd_prod; + u16 agg_val1; u8 __agg_vars1; u8 __state; #elif defined(__LITTLE_ENDIAN) u8 __state; u8 __agg_vars1; - u16 __bd_prod; + u16 agg_val1; #endif #if defined(__BIG_ENDIAN) u8 cdu_reserved; @@ -1626,7 +1719,7 @@ struct xstorm_eth_ag_context { u8 __agg_vars4; u8 cdu_reserved; #endif - u32 __more_packets_to_send; + u32 __bd_prod; #if defined(__BIG_ENDIAN) u16 __agg_vars5; u16 __agg_val4_th; @@ -1892,8 +1985,8 @@ struct eth_tx_bd_flags { #define ETH_TX_BD_FLAGS_VLAN_TAG_SHIFT 0 #define ETH_TX_BD_FLAGS_IP_CSUM (0x1<<1) #define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT 1 -#define ETH_TX_BD_FLAGS_TCP_CSUM (0x1<<2) -#define ETH_TX_BD_FLAGS_TCP_CSUM_SHIFT 2 +#define ETH_TX_BD_FLAGS_L4_CSUM (0x1<<2) +#define ETH_TX_BD_FLAGS_L4_CSUM_SHIFT 2 #define ETH_TX_BD_FLAGS_END_BD (0x1<<3) #define ETH_TX_BD_FLAGS_END_BD_SHIFT 3 #define ETH_TX_BD_FLAGS_START_BD (0x1<<4) @@ -1909,7 +2002,7 @@ struct eth_tx_bd_flags { /* * The eth Tx Buffer Descriptor */ -struct eth_tx_bd { +struct eth_tx_start_bd { __le32 addr_lo; __le32 addr_hi; __le16 nbd; @@ -1917,10 +2010,21 @@ struct eth_tx_bd { __le16 vlan; struct eth_tx_bd_flags bd_flags; u8 general_data; -#define ETH_TX_BD_HDR_NBDS (0x3F<<0) -#define ETH_TX_BD_HDR_NBDS_SHIFT 0 -#define ETH_TX_BD_ETH_ADDR_TYPE (0x3<<6) -#define ETH_TX_BD_ETH_ADDR_TYPE_SHIFT 6 +#define ETH_TX_START_BD_HDR_NBDS (0x3F<<0) +#define ETH_TX_START_BD_HDR_NBDS_SHIFT 0 +#define ETH_TX_START_BD_ETH_ADDR_TYPE (0x3<<6) +#define ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT 6 +}; + +/* + * Tx regular BD structure + */ +struct eth_tx_bd { + u32 addr_lo; + u32 addr_hi; + u16 total_pkt_bytes; + u16 nbytes; + u8 reserved[4]; }; /* @@ -1930,8 +2034,8 @@ struct eth_tx_parse_bd { u8 global_data; #define ETH_TX_PARSE_BD_IP_HDR_START_OFFSET (0xF<<0) #define ETH_TX_PARSE_BD_IP_HDR_START_OFFSET_SHIFT 0 -#define ETH_TX_PARSE_BD_CS_ANY_FLG (0x1<<4) -#define ETH_TX_PARSE_BD_CS_ANY_FLG_SHIFT 4 +#define ETH_TX_PARSE_BD_UDP_CS_FLG (0x1<<4) +#define ETH_TX_PARSE_BD_UDP_CS_FLG_SHIFT 4 #define ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN (0x1<<5) #define ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN_SHIFT 5 #define ETH_TX_PARSE_BD_LLC_SNAP_EN (0x1<<6) @@ -1956,10 +2060,10 @@ struct eth_tx_parse_bd { #define ETH_TX_PARSE_BD_CWR_FLG (0x1<<7) #define ETH_TX_PARSE_BD_CWR_FLG_SHIFT 7 u8 ip_hlen; - s8 cs_offset; + s8 reserved; __le16 total_hlen; - __le16 lso_mss; __le16 tcp_pseudo_csum; + __le16 lso_mss; __le16 ip_id; __le32 tcp_send_seq; }; @@ -1968,15 +2072,16 @@ struct eth_tx_parse_bd { * The last BD in the BD memory will hold a pointer to the next BD memory */ struct eth_tx_next_bd { - u32 addr_lo; - u32 addr_hi; + __le32 addr_lo; + __le32 addr_hi; u8 reserved[8]; }; /* - * union for 3 Bd types + * union for 4 Bd types */ union eth_tx_bd_types { + struct eth_tx_start_bd start_bd; struct eth_tx_bd reg_bd; struct eth_tx_parse_bd parse_bd; struct eth_tx_next_bd next_bd; @@ -2005,11 +2110,35 @@ struct xstorm_eth_st_context { #define XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE_SHIFT 7 u16 tx_bd_cons; #endif - u32 db_data_addr_lo; - u32 db_data_addr_hi; - u32 __pkt_cons; - u32 __gso_next; - u32 is_eth_conn_1b; + u32 __reserved1; + u32 __reserved2; +#if defined(__BIG_ENDIAN) + u8 __ram_cache_index; + u8 __double_buffer_client; + u16 __pkt_cons; +#elif defined(__LITTLE_ENDIAN) + u16 __pkt_cons; + u8 __double_buffer_client; + u8 __ram_cache_index; +#endif +#if defined(__BIG_ENDIAN) + u16 __statistics_address; + u16 __gso_next; +#elif defined(__LITTLE_ENDIAN) + u16 __gso_next; + u16 __statistics_address; +#endif +#if defined(__BIG_ENDIAN) + u8 __local_tx_bd_cons; + u8 safc_group_num; + u8 safc_group_en; + u8 __is_eth_conn; +#elif defined(__LITTLE_ENDIAN) + u8 __is_eth_conn; + u8 safc_group_en; + u8 safc_group_num; + u8 __local_tx_bd_cons; +#endif union eth_tx_bd_types __bds[13]; }; @@ -2074,9 +2203,9 @@ struct eth_tx_doorbell { /* - * ustorm status block + * cstorm default status block, generated by ustorm */ -struct ustorm_def_status_block { +struct cstorm_def_status_block_u { __le16 index_values[HC_USTORM_DEF_SB_NUM_INDICES]; __le16 status_block_index; u8 func; @@ -2085,9 +2214,9 @@ struct ustorm_def_status_block { }; /* - * cstorm status block + * cstorm default status block, generated by cstorm */ -struct cstorm_def_status_block { +struct cstorm_def_status_block_c { __le16 index_values[HC_CSTORM_DEF_SB_NUM_INDICES]; __le16 status_block_index; u8 func; @@ -2122,17 +2251,17 @@ struct tstorm_def_status_block { */ struct host_def_status_block { struct atten_def_status_block atten_status_block; - struct ustorm_def_status_block u_def_status_block; - struct cstorm_def_status_block c_def_status_block; + struct cstorm_def_status_block_u u_def_status_block; + struct cstorm_def_status_block_c c_def_status_block; struct xstorm_def_status_block x_def_status_block; struct tstorm_def_status_block t_def_status_block; }; /* - * ustorm status block + * cstorm status block, generated by ustorm */ -struct ustorm_status_block { +struct cstorm_status_block_u { __le16 index_values[HC_USTORM_SB_NUM_INDICES]; __le16 status_block_index; u8 func; @@ -2141,9 +2270,9 @@ struct ustorm_status_block { }; /* - * cstorm status block + * cstorm status block, generated by cstorm */ -struct cstorm_status_block { +struct cstorm_status_block_c { __le16 index_values[HC_CSTORM_SB_NUM_INDICES]; __le16 status_block_index; u8 func; @@ -2155,8 +2284,8 @@ struct cstorm_status_block { * host status block */ struct host_status_block { - struct ustorm_status_block u_status_block; - struct cstorm_status_block c_status_block; + struct cstorm_status_block_u u_status_block; + struct cstorm_status_block_c c_status_block; }; @@ -2172,15 +2301,6 @@ struct eth_client_setup_ramrod_data { /* - * L2 dynamic host coalescing init parameters - */ -struct eth_dynamic_hc_config { - u32 threshold[3]; - u8 hc_timeout[4]; -}; - - -/* * regular eth FP CQE parameters struct */ struct eth_fast_path_rx_cqe { @@ -2344,12 +2464,10 @@ struct eth_spe { /* - * doorbell data in host memory + * array of 13 bds as appears in the eth xstorm context */ -struct eth_tx_db_data { - __le32 packets_prod; - __le16 bds_prod; - __le16 reserved; +struct eth_tx_bds_array { + union eth_tx_bd_types bds[13]; }; @@ -2377,8 +2495,10 @@ struct tstorm_eth_function_common_config { #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM_SHIFT 8 #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM (0x1<<9) #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM_SHIFT 9 -#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x3F<<10) -#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 10 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA (0x1<<10) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA_SHIFT 10 +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x1F<<11) +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 11 #elif defined(__LITTLE_ENDIAN) u16 config_flags; #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY (0x1<<0) @@ -2397,8 +2517,10 @@ struct tstorm_eth_function_common_config { #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM_SHIFT 8 #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM (0x1<<9) #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM_SHIFT 9 -#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x3F<<10) -#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 10 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA (0x1<<10) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA_SHIFT 10 +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x1F<<11) +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 11 u8 rss_result_mask; u8 leading_client_id; #endif @@ -2406,11 +2528,38 @@ struct tstorm_eth_function_common_config { }; /* + * RSS idirection table update configuration + */ +struct rss_update_config { +#if defined(__BIG_ENDIAN) + u16 toe_rss_bitmap; + u16 flags; +#define RSS_UPDATE_CONFIG_ETH_UPDATE_ENABLE (0x1<<0) +#define RSS_UPDATE_CONFIG_ETH_UPDATE_ENABLE_SHIFT 0 +#define RSS_UPDATE_CONFIG_TOE_UPDATE_ENABLE (0x1<<1) +#define RSS_UPDATE_CONFIG_TOE_UPDATE_ENABLE_SHIFT 1 +#define __RSS_UPDATE_CONFIG_RESERVED0 (0x3FFF<<2) +#define __RSS_UPDATE_CONFIG_RESERVED0_SHIFT 2 +#elif defined(__LITTLE_ENDIAN) + u16 flags; +#define RSS_UPDATE_CONFIG_ETH_UPDATE_ENABLE (0x1<<0) +#define RSS_UPDATE_CONFIG_ETH_UPDATE_ENABLE_SHIFT 0 +#define RSS_UPDATE_CONFIG_TOE_UPDATE_ENABLE (0x1<<1) +#define RSS_UPDATE_CONFIG_TOE_UPDATE_ENABLE_SHIFT 1 +#define __RSS_UPDATE_CONFIG_RESERVED0 (0x3FFF<<2) +#define __RSS_UPDATE_CONFIG_RESERVED0_SHIFT 2 + u16 toe_rss_bitmap; +#endif + u32 reserved1; +}; + +/* * parameters for eth update ramrod */ struct eth_update_ramrod_data { struct tstorm_eth_function_common_config func_config; u8 indirectionTable[128]; + struct rss_update_config rss_config; }; @@ -2455,8 +2604,9 @@ struct tstorm_cam_target_table_entry { #define TSTORM_CAM_TARGET_TABLE_ENTRY_RDMA_MAC_SHIFT 3 #define TSTORM_CAM_TARGET_TABLE_ENTRY_RESERVED0 (0xF<<4) #define TSTORM_CAM_TARGET_TABLE_ENTRY_RESERVED0_SHIFT 4 - u8 client_id; + u8 reserved1; u16 vlan_id; + u32 clients_bit_vector; }; /* @@ -2485,7 +2635,7 @@ struct mac_configuration_entry_e1h { __le16 msb_mac_addr; __le16 vlan_id; __le16 e1hov_id; - u8 client_id; + u8 reserved0; u8 flags; #define MAC_CONFIGURATION_ENTRY_E1H_PORT (0x1<<0) #define MAC_CONFIGURATION_ENTRY_E1H_PORT_SHIFT 0 @@ -2493,8 +2643,9 @@ struct mac_configuration_entry_e1h { #define MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE_SHIFT 1 #define MAC_CONFIGURATION_ENTRY_E1H_RDMA_MAC (0x1<<2) #define MAC_CONFIGURATION_ENTRY_E1H_RDMA_MAC_SHIFT 2 -#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED0 (0x1F<<3) -#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED0_SHIFT 3 +#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED1 (0x1F<<3) +#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED1_SHIFT 3 + u32 clients_bit_vector; }; /* @@ -2519,13 +2670,13 @@ struct tstorm_eth_approximate_match_multicast_filtering { */ struct tstorm_eth_client_config { #if defined(__BIG_ENDIAN) - u8 max_sges_for_packet; + u8 reserved0; u8 statistics_counter_id; u16 mtu; #elif defined(__LITTLE_ENDIAN) u16 mtu; u8 statistics_counter_id; - u8 max_sges_for_packet; + u8 reserved0; #endif #if defined(__BIG_ENDIAN) u16 drop_flags; @@ -2537,8 +2688,8 @@ struct tstorm_eth_client_config { #define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 2 #define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<3) #define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 3 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0xFFF<<4) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 4 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2 (0xFFF<<4) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2_SHIFT 4 u16 config_flags; #define TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE (0x1<<0) #define TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE_SHIFT 0 @@ -2546,10 +2697,8 @@ struct tstorm_eth_client_config { #define TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE_SHIFT 1 #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<2) #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 2 -#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING (0x1<<3) -#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING_SHIFT 3 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0xFFF<<4) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 4 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x1FFF<<3) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 3 #elif defined(__LITTLE_ENDIAN) u16 config_flags; #define TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE (0x1<<0) @@ -2558,10 +2707,8 @@ struct tstorm_eth_client_config { #define TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE_SHIFT 1 #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<2) #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 2 -#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING (0x1<<3) -#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING_SHIFT 3 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0xFFF<<4) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 4 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x1FFF<<3) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 3 u16 drop_flags; #define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR (0x1<<0) #define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR_SHIFT 0 @@ -2571,8 +2718,8 @@ struct tstorm_eth_client_config { #define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 2 #define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<3) #define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 3 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0xFFF<<4) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 4 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2 (0xFFF<<4) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2_SHIFT 4 #endif }; @@ -2695,7 +2842,6 @@ struct rate_shaping_vars_per_port { u32 rs_threshold; }; - /* * per-port fairness variables */ @@ -2705,7 +2851,6 @@ struct fairness_vars_per_port { u32 fairness_timeout; }; - /* * per-port SAFC variables */ @@ -2722,7 +2867,6 @@ struct safc_struct_per_port { u16 cos_to_pause_mask[NUM_OF_SAFC_BITS]; }; - /* * Per-port congestion management variables */ @@ -2735,11 +2879,23 @@ struct cmng_struct_per_port { /* + * Dynamic host coalescing init parameters + */ +struct dynamic_hc_config { + u32 threshold[3]; + u8 shift_per_protocol[HC_USTORM_SB_NUM_INDICES]; + u8 hc_timeout0[HC_USTORM_SB_NUM_INDICES]; + u8 hc_timeout1[HC_USTORM_SB_NUM_INDICES]; + u8 hc_timeout2[HC_USTORM_SB_NUM_INDICES]; + u8 hc_timeout3[HC_USTORM_SB_NUM_INDICES]; +}; + + +/* * Protocol-common statistics collected by the Xstorm (per client) */ struct xstorm_per_client_stats { - struct regpair total_sent_bytes; - __le32 total_sent_pkts; + __le32 reserved0; __le32 unicast_pkts_sent; struct regpair unicast_bytes_sent; struct regpair multicast_bytes_sent; @@ -2747,11 +2903,10 @@ struct xstorm_per_client_stats { __le32 broadcast_pkts_sent; struct regpair broadcast_bytes_sent; __le16 stats_counter; - __le16 reserved0; - __le32 reserved1; + __le16 reserved1; + __le32 reserved2; }; - /* * Common statistics collected by the Xstorm (per port) */ @@ -2759,7 +2914,6 @@ struct xstorm_common_stats { struct xstorm_per_client_stats client_statistics[MAX_X_STAT_COUNTER_ID]; }; - /* * Protocol-common statistics collected by the Tstorm (per port) */ @@ -2770,19 +2924,16 @@ struct tstorm_per_port_stats { __le32 mac_discard; }; - /* * Protocol-common statistics collected by the Tstorm (per client) */ struct tstorm_per_client_stats { - struct regpair total_rcv_bytes; struct regpair rcv_unicast_bytes; struct regpair rcv_broadcast_bytes; struct regpair rcv_multicast_bytes; struct regpair rcv_error_bytes; __le32 checksum_discard; __le32 packets_too_big_discard; - __le32 total_rcv_pkts; __le32 rcv_unicast_pkts; __le32 rcv_broadcast_pkts; __le32 rcv_multicast_pkts; @@ -2790,7 +2941,6 @@ struct tstorm_per_client_stats { __le32 ttl0_discard; __le16 stats_counter; __le16 reserved0; - __le32 reserved1; }; /* @@ -2893,6 +3043,15 @@ struct pram_fw_version { /* + * The send queue element + */ +struct protocol_common_spe { + struct spe_hdr hdr; + struct regpair phy_address; +}; + + +/* * a single rate shaping counter. can be used as protocol or vnic counter */ struct rate_shaping_counter { diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 665ed36..762f37a 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -10,7 +10,7 @@ * Written by: Eliezer Tamir * Based on code from Michael Chan's bnx2 driver * UDP CSUM errata workaround by Arik Gendelman - * Slowpath rework by Vladislav Zolotarov + * Slowpath and fastpath rework by Vladislav Zolotarov * Statistics and Link management by Yitchak Gertner * */ @@ -80,7 +80,18 @@ MODULE_VERSION(DRV_MODULE_VERSION); static int multi_mode = 1; module_param(multi_mode, int, 0); -MODULE_PARM_DESC(multi_mode, " Use per-CPU queues"); +MODULE_PARM_DESC(multi_mode, " Multi queue mode " + "(0 Disable; 1 Enable (default))"); + +static int num_rx_queues; +module_param(num_rx_queues, int, 0); +MODULE_PARM_DESC(num_rx_queues, " Number of Rx queues for multi_mode=1" + " (default is half number of CPUs)"); + +static int num_tx_queues; +module_param(num_tx_queues, int, 0); +MODULE_PARM_DESC(num_tx_queues, " Number of Tx queues for multi_mode=1" + " (default is half number of CPUs)"); static int disable_tpa; module_param(disable_tpa, int, 0); @@ -542,16 +553,15 @@ static void bnx2x_panic_dump(struct bnx2x *bp) /* Tx */ for_each_tx_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; - struct eth_tx_db_data *hw_prods = fp->hw_tx_prods; BNX2X_ERR("fp%d: tx_pkt_prod(%x) tx_pkt_cons(%x)" " tx_bd_prod(%x) tx_bd_cons(%x) *tx_cons_sb(%x)\n", i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod, fp->tx_bd_cons, le16_to_cpu(*fp->tx_cons_sb)); BNX2X_ERR(" fp_c_idx(%x) *sb_c_idx(%x)" - " bd data(%x,%x)\n", le16_to_cpu(fp->fp_c_idx), + " tx_db_prod(%x)\n", le16_to_cpu(fp->fp_c_idx), fp->status_blk->c_status_block.status_block_index, - hw_prods->packets_prod, hw_prods->bds_prod); + fp->tx_db.data.prod); } /* Rings */ @@ -790,16 +800,6 @@ static u16 bnx2x_ack_int(struct bnx2x *bp) * fast path service functions */ -static inline int bnx2x_has_tx_work(struct bnx2x_fastpath *fp) -{ - u16 tx_cons_sb; - - /* Tell compiler that status block fields can change */ - barrier(); - tx_cons_sb = le16_to_cpu(*fp->tx_cons_sb); - return (fp->tx_pkt_cons != tx_cons_sb); -} - static inline int bnx2x_has_tx_work_unload(struct bnx2x_fastpath *fp) { /* Tell compiler that consumer and producer can change */ @@ -814,7 +814,8 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp, u16 idx) { struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx]; - struct eth_tx_bd *tx_bd; + struct eth_tx_start_bd *tx_start_bd; + struct eth_tx_bd *tx_data_bd; struct sk_buff *skb = tx_buf->skb; u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons; int nbd; @@ -824,51 +825,46 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp, /* unmap first bd */ DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx); - tx_bd = &fp->tx_desc_ring[bd_idx]; - pci_unmap_single(bp->pdev, BD_UNMAP_ADDR(tx_bd), - BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE); + tx_start_bd = &fp->tx_desc_ring[bd_idx].start_bd; + pci_unmap_single(bp->pdev, BD_UNMAP_ADDR(tx_start_bd), + BD_UNMAP_LEN(tx_start_bd), PCI_DMA_TODEVICE); - nbd = le16_to_cpu(tx_bd->nbd) - 1; - new_cons = nbd + tx_buf->first_bd; + nbd = le16_to_cpu(tx_start_bd->nbd) - 1; #ifdef BNX2X_STOP_ON_ERROR - if (nbd > (MAX_SKB_FRAGS + 2)) { + if ((nbd - 1) > (MAX_SKB_FRAGS + 2)) { BNX2X_ERR("BAD nbd!\n"); bnx2x_panic(); } #endif + new_cons = nbd + tx_buf->first_bd; - /* Skip a parse bd and the TSO split header bd - since they have no mapping */ - if (nbd) - bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + /* Get the next bd */ + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); - if (tx_bd->bd_flags.as_bitfield & (ETH_TX_BD_FLAGS_IP_CSUM | - ETH_TX_BD_FLAGS_TCP_CSUM | - ETH_TX_BD_FLAGS_SW_LSO)) { - if (--nbd) - bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); - tx_bd = &fp->tx_desc_ring[bd_idx]; - /* is this a TSO split header bd? */ - if (tx_bd->bd_flags.as_bitfield & ETH_TX_BD_FLAGS_SW_LSO) { - if (--nbd) - bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); - } + /* Skip a parse bd... */ + --nbd; + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + + /* ...and the TSO split header bd since they have no mapping */ + if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) { + --nbd; + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); } /* now free frags */ while (nbd > 0) { DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx); - tx_bd = &fp->tx_desc_ring[bd_idx]; - pci_unmap_page(bp->pdev, BD_UNMAP_ADDR(tx_bd), - BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE); + tx_data_bd = &fp->tx_desc_ring[bd_idx].reg_bd; + pci_unmap_page(bp->pdev, BD_UNMAP_ADDR(tx_data_bd), + BD_UNMAP_LEN(tx_data_bd), PCI_DMA_TODEVICE); if (--nbd) bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); } /* release skb */ WARN_ON(!skb); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); tx_buf->first_bd = 0; tx_buf->skb = NULL; @@ -910,7 +906,7 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp) return; #endif - txq = netdev_get_tx_queue(bp->dev, fp->index); + txq = netdev_get_tx_queue(bp->dev, fp->index - bp->num_rx_queues); hw_cons = le16_to_cpu(*fp->tx_cons_sb); sw_cons = fp->tx_pkt_cons; @@ -940,8 +936,6 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp) /* TBD need a thresh? */ if (unlikely(netif_tx_queue_stopped(txq))) { - __netif_tx_lock(txq, smp_processor_id()); - /* Need to make the tx_bd_cons update visible to start_xmit() * before checking for netif_tx_queue_stopped(). Without the * memory barrier, there is a small possibility that @@ -954,8 +948,6 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp) (bp->state == BNX2X_STATE_OPEN) && (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)) netif_tx_wake_queue(txq); - - __netif_tx_unlock(txq); } } @@ -1023,6 +1015,7 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp, break; case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT): + case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DISABLED): DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n"); break; @@ -1688,7 +1681,6 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) { struct bnx2x_fastpath *fp = fp_cookie; struct bnx2x *bp = fp->bp; - int index = fp->index; /* Return here if interrupt is disabled */ if (unlikely(atomic_read(&bp->intr_sem) != 0)) { @@ -1697,20 +1689,34 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) } DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB [%d:%d]\n", - index, fp->sb_id); + fp->index, fp->sb_id); bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0); #ifdef BNX2X_STOP_ON_ERROR if (unlikely(bp->panic)) return IRQ_HANDLED; #endif + /* Handle Rx or Tx according to MSI-X vector */ + if (fp->is_rx_queue) { + prefetch(fp->rx_cons_sb); + prefetch(&fp->status_blk->u_status_block.status_block_index); - prefetch(fp->rx_cons_sb); - prefetch(fp->tx_cons_sb); - prefetch(&fp->status_blk->c_status_block.status_block_index); - prefetch(&fp->status_blk->u_status_block.status_block_index); + napi_schedule(&bnx2x_fp(bp, fp->index, napi)); - napi_schedule(&bnx2x_fp(bp, index, napi)); + } else { + prefetch(fp->tx_cons_sb); + prefetch(&fp->status_blk->c_status_block.status_block_index); + + bnx2x_update_fpsb_idx(fp); + rmb(); + bnx2x_tx_int(fp); + + /* Re-enable interrupts */ + bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, + le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID, + le16_to_cpu(fp->fp_c_idx), IGU_INT_ENABLE, 1); + } return IRQ_HANDLED; } @@ -1720,6 +1726,7 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) struct bnx2x *bp = netdev_priv(dev_instance); u16 status = bnx2x_ack_int(bp); u16 mask; + int i; /* Return here if interrupt is shared and it's not for us */ if (unlikely(status == 0)) { @@ -1739,18 +1746,38 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) return IRQ_HANDLED; #endif - mask = 0x2 << bp->fp[0].sb_id; - if (status & mask) { - struct bnx2x_fastpath *fp = &bp->fp[0]; + for (i = 0; i < BNX2X_NUM_QUEUES(bp); i++) { + struct bnx2x_fastpath *fp = &bp->fp[i]; - prefetch(fp->rx_cons_sb); - prefetch(fp->tx_cons_sb); - prefetch(&fp->status_blk->c_status_block.status_block_index); - prefetch(&fp->status_blk->u_status_block.status_block_index); + mask = 0x2 << fp->sb_id; + if (status & mask) { + /* Handle Rx or Tx according to SB id */ + if (fp->is_rx_queue) { + prefetch(fp->rx_cons_sb); + prefetch(&fp->status_blk->u_status_block. + status_block_index); - napi_schedule(&bnx2x_fp(bp, 0, napi)); + napi_schedule(&bnx2x_fp(bp, fp->index, napi)); - status &= ~mask; + } else { + prefetch(fp->tx_cons_sb); + prefetch(&fp->status_blk->c_status_block. + status_block_index); + + bnx2x_update_fpsb_idx(fp); + rmb(); + bnx2x_tx_int(fp); + + /* Re-enable interrupts */ + bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, + le16_to_cpu(fp->fp_u_idx), + IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID, + le16_to_cpu(fp->fp_c_idx), + IGU_INT_ENABLE, 1); + } + status &= ~mask; + } } @@ -2298,7 +2325,7 @@ static void bnx2x_link_attn(struct bnx2x *bp) pause_enabled = 1; REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_PAUSE_ENABLED_OFFSET(port), + USTORM_ETH_PAUSE_ENABLED_OFFSET(port), pause_enabled); } @@ -3756,7 +3783,7 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) estats->no_buff_discard_hi = 0; estats->no_buff_discard_lo = 0; - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; int cl_id = fp->cl_id; struct tstorm_per_client_stats *tclient = @@ -3795,11 +3822,24 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) } qstats->total_bytes_received_hi = - qstats->valid_bytes_received_hi = - le32_to_cpu(tclient->total_rcv_bytes.hi); + le32_to_cpu(tclient->rcv_broadcast_bytes.hi); qstats->total_bytes_received_lo = + le32_to_cpu(tclient->rcv_broadcast_bytes.lo); + + ADD_64(qstats->total_bytes_received_hi, + le32_to_cpu(tclient->rcv_multicast_bytes.hi), + qstats->total_bytes_received_lo, + le32_to_cpu(tclient->rcv_multicast_bytes.lo)); + + ADD_64(qstats->total_bytes_received_hi, + le32_to_cpu(tclient->rcv_unicast_bytes.hi), + qstats->total_bytes_received_lo, + le32_to_cpu(tclient->rcv_unicast_bytes.lo)); + + qstats->valid_bytes_received_hi = + qstats->total_bytes_received_hi; qstats->valid_bytes_received_lo = - le32_to_cpu(tclient->total_rcv_bytes.lo); + qstats->total_bytes_received_lo; qstats->error_bytes_received_hi = le32_to_cpu(tclient->rcv_error_bytes.hi); @@ -3832,9 +3872,19 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) UPDATE_EXTEND_USTAT(bcast_no_buff_pkts, no_buff_discard); qstats->total_bytes_transmitted_hi = - le32_to_cpu(xclient->total_sent_bytes.hi); + le32_to_cpu(xclient->unicast_bytes_sent.hi); qstats->total_bytes_transmitted_lo = - le32_to_cpu(xclient->total_sent_bytes.lo); + le32_to_cpu(xclient->unicast_bytes_sent.lo); + + ADD_64(qstats->total_bytes_transmitted_hi, + le32_to_cpu(xclient->multicast_bytes_sent.hi), + qstats->total_bytes_transmitted_lo, + le32_to_cpu(xclient->multicast_bytes_sent.lo)); + + ADD_64(qstats->total_bytes_transmitted_hi, + le32_to_cpu(xclient->broadcast_bytes_sent.hi), + qstats->total_bytes_transmitted_lo, + le32_to_cpu(xclient->broadcast_bytes_sent.lo)); UPDATE_EXTEND_XSTAT(unicast_pkts_sent, total_unicast_packets_transmitted); @@ -3950,7 +4000,7 @@ static void bnx2x_net_stats_update(struct bnx2x *bp) nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi); nstats->rx_dropped = estats->mac_discard; - for_each_queue(bp, i) + for_each_rx_queue(bp, i) nstats->rx_dropped += le32_to_cpu(bp->fp[i].old_tclient.checksum_discard); @@ -4004,7 +4054,7 @@ static void bnx2x_drv_stats_update(struct bnx2x *bp) estats->rx_err_discard_pkt = 0; estats->rx_skb_alloc_failed = 0; estats->hw_csum_err = 0; - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { struct bnx2x_eth_q_stats *qstats = &bp->fp[i].eth_q_stats; estats->driver_xoff += qstats->driver_xoff; @@ -4034,6 +4084,8 @@ static void bnx2x_stats_update(struct bnx2x *bp) bnx2x_drv_stats_update(bp); if (bp->msglevel & NETIF_MSG_TIMER) { + struct bnx2x_fastpath *fp0_rx = bp->fp; + struct bnx2x_fastpath *fp0_tx = &(bp->fp[bp->num_rx_queues]); struct tstorm_per_client_stats *old_tclient = &bp->fp->old_tclient; struct bnx2x_eth_q_stats *qstats = &bp->fp->eth_q_stats; @@ -4044,13 +4096,13 @@ static void bnx2x_stats_update(struct bnx2x *bp) printk(KERN_DEBUG "%s:\n", bp->dev->name); printk(KERN_DEBUG " tx avail (%4x) tx hc idx (%x)" " tx pkt (%lx)\n", - bnx2x_tx_avail(bp->fp), - le16_to_cpu(*bp->fp->tx_cons_sb), nstats->tx_packets); + bnx2x_tx_avail(fp0_tx), + le16_to_cpu(*fp0_tx->tx_cons_sb), nstats->tx_packets); printk(KERN_DEBUG " rx usage (%4x) rx hc idx (%x)" " rx pkt (%lx)\n", - (u16)(le16_to_cpu(*bp->fp->rx_cons_sb) - - bp->fp->rx_comp_cons), - le16_to_cpu(*bp->fp->rx_cons_sb), nstats->rx_packets); + (u16)(le16_to_cpu(*fp0_rx->rx_cons_sb) - + fp0_rx->rx_comp_cons), + le16_to_cpu(*fp0_rx->rx_cons_sb), nstats->rx_packets); printk(KERN_DEBUG " %s (Xoff events %u) brb drops %u " "brb truncate %u\n", (netif_queue_stopped(bp->dev) ? "Xoff" : "Xon"), @@ -4263,12 +4315,13 @@ static void bnx2x_zero_sb(struct bnx2x *bp, int sb_id) { int port = BP_PORT(bp); - bnx2x_init_fill(bp, USTORM_INTMEM_ADDR + - USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0, - sizeof(struct ustorm_status_block)/4); - bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR + - CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0, - sizeof(struct cstorm_status_block)/4); + /* "CSTORM" */ + bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY + + CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), 0, + CSTORM_SB_STATUS_BLOCK_U_SIZE / 4); + bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY + + CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), 0, + CSTORM_SB_STATUS_BLOCK_C_SIZE / 4); } static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb, @@ -4284,17 +4337,17 @@ static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb, u_status_block); sb->u_status_block.status_block_id = sb_id; - REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id), U64_LO(section)); - REG_WR(bp, BAR_USTRORM_INTMEM + - ((USTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id)) + 4), + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id), U64_LO(section)); + REG_WR(bp, BAR_CSTRORM_INTMEM + + ((CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id)) + 4), U64_HI(section)); - REG_WR8(bp, BAR_USTRORM_INTMEM + FP_USB_FUNC_OFF + - USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), func); + REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_USB_FUNC_OFF + + CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), func); for (index = 0; index < HC_USTORM_SB_NUM_INDICES; index++) - REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_DISABLE_OFFSET(port, sb_id, index), 1); + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id, index), 1); /* CSTORM */ section = ((u64)mapping) + offsetof(struct host_status_block, @@ -4302,16 +4355,16 @@ static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb, sb->c_status_block.status_block_id = sb_id; REG_WR(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id), U64_LO(section)); + CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id), U64_LO(section)); REG_WR(bp, BAR_CSTRORM_INTMEM + - ((CSTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id)) + 4), + ((CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id)) + 4), U64_HI(section)); REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_CSB_FUNC_OFF + - CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), func); + CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), func); for (index = 0; index < HC_CSTORM_SB_NUM_INDICES; index++) REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id, index), 1); + CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id, index), 1); bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); } @@ -4320,16 +4373,16 @@ static void bnx2x_zero_def_sb(struct bnx2x *bp) { int func = BP_FUNC(bp); - bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR + + bnx2x_init_fill(bp, TSEM_REG_FAST_MEMORY + TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, sizeof(struct tstorm_def_status_block)/4); - bnx2x_init_fill(bp, USTORM_INTMEM_ADDR + - USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, - sizeof(struct ustorm_def_status_block)/4); - bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR + - CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, - sizeof(struct cstorm_def_status_block)/4); - bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR + + bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY + + CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), 0, + sizeof(struct cstorm_def_status_block_u)/4); + bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY + + CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), 0, + sizeof(struct cstorm_def_status_block_c)/4); + bnx2x_init_fill(bp, XSEM_REG_FAST_MEMORY + XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, sizeof(struct xstorm_def_status_block)/4); } @@ -4381,17 +4434,17 @@ static void bnx2x_init_def_sb(struct bnx2x *bp, u_def_status_block); def_sb->u_def_status_block.status_block_id = sb_id; - REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); - REG_WR(bp, BAR_USTRORM_INTMEM + - ((USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func), U64_LO(section)); + REG_WR(bp, BAR_CSTRORM_INTMEM + + ((CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func)) + 4), U64_HI(section)); - REG_WR8(bp, BAR_USTRORM_INTMEM + DEF_USB_FUNC_OFF + - USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_USB_FUNC_OFF + + CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), func); for (index = 0; index < HC_USTORM_DEF_SB_NUM_INDICES; index++) - REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_DEF_SB_HC_DISABLE_U_OFFSET(func, index), 1); /* CSTORM */ section = ((u64)mapping) + offsetof(struct host_def_status_block, @@ -4399,16 +4452,16 @@ static void bnx2x_init_def_sb(struct bnx2x *bp, def_sb->c_def_status_block.status_block_id = sb_id; REG_WR(bp, BAR_CSTRORM_INTMEM + - CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); + CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func), U64_LO(section)); REG_WR(bp, BAR_CSTRORM_INTMEM + - ((CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), + ((CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func)) + 4), U64_HI(section)); REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_CSB_FUNC_OFF + - CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), func); for (index = 0; index < HC_CSTORM_DEF_SB_NUM_INDICES; index++) REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); + CSTORM_DEF_SB_HC_DISABLE_C_OFFSET(func, index), 1); /* TSTORM */ section = ((u64)mapping) + offsetof(struct host_def_status_block, @@ -4459,23 +4512,23 @@ static void bnx2x_update_coalesce(struct bnx2x *bp) int sb_id = bp->fp[i].sb_id; /* HC_INDEX_U_ETH_RX_CQ_CONS */ - REG_WR8(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_TIMEOUT_OFFSET(port, sb_id, - U_SB_ETH_RX_CQ_INDEX), + REG_WR8(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_TIMEOUT_U_OFFSET(port, sb_id, + U_SB_ETH_RX_CQ_INDEX), bp->rx_ticks/12); - REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_DISABLE_OFFSET(port, sb_id, - U_SB_ETH_RX_CQ_INDEX), + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id, + U_SB_ETH_RX_CQ_INDEX), (bp->rx_ticks/12) ? 0 : 1); /* HC_INDEX_C_ETH_TX_CQ_CONS */ REG_WR8(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_TIMEOUT_OFFSET(port, sb_id, - C_SB_ETH_TX_CQ_INDEX), + CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, sb_id, + C_SB_ETH_TX_CQ_INDEX), bp->tx_ticks/12); REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id, - C_SB_ETH_TX_CQ_INDEX), + CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id, + C_SB_ETH_TX_CQ_INDEX), (bp->tx_ticks/12) ? 0 : 1); } } @@ -4548,6 +4601,9 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp) fp->rx_cons_sb = BNX2X_RX_SB_INDEX; fp->rx_bd_cons_sb = BNX2X_RX_SB_BD_INDEX; + /* Mark queue as Rx */ + fp->is_rx_queue = 1; + /* "next page" elements initialization */ /* SGE ring */ for (i = 1; i <= NUM_RX_SGE_PAGES; i++) { @@ -4657,17 +4713,21 @@ static void bnx2x_init_tx_ring(struct bnx2x *bp) struct bnx2x_fastpath *fp = &bp->fp[j]; for (i = 1; i <= NUM_TX_RINGS; i++) { - struct eth_tx_bd *tx_bd = - &fp->tx_desc_ring[TX_DESC_CNT * i - 1]; + struct eth_tx_next_bd *tx_next_bd = + &fp->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd; - tx_bd->addr_hi = + tx_next_bd->addr_hi = cpu_to_le32(U64_HI(fp->tx_desc_mapping + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); - tx_bd->addr_lo = + tx_next_bd->addr_lo = cpu_to_le32(U64_LO(fp->tx_desc_mapping + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); } + fp->tx_db.data.header.header = DOORBELL_HDR_DB_TYPE; + fp->tx_db.data.zero_fill1 = 0; + fp->tx_db.data.prod = 0; + fp->tx_pkt_prod = 0; fp->tx_pkt_cons = 0; fp->tx_bd_prod = 0; @@ -4703,16 +4763,15 @@ static void bnx2x_init_context(struct bnx2x *bp) { int i; - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { struct eth_context *context = bnx2x_sp(bp, context[i].eth); struct bnx2x_fastpath *fp = &bp->fp[i]; u8 cl_id = fp->cl_id; - u8 sb_id = fp->sb_id; context->ustorm_st_context.common.sb_index_numbers = BNX2X_RX_SB_INDEX_NUM; context->ustorm_st_context.common.clientId = cl_id; - context->ustorm_st_context.common.status_block_id = sb_id; + context->ustorm_st_context.common.status_block_id = fp->sb_id; context->ustorm_st_context.common.flags = (USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT | USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS); @@ -4728,8 +4787,7 @@ static void bnx2x_init_context(struct bnx2x *bp) U64_LO(fp->rx_desc_mapping); if (!fp->disable_tpa) { context->ustorm_st_context.common.flags |= - (USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA | - USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING); + USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA; context->ustorm_st_context.common.sge_buff_size = (u16)min((u32)SGE_PAGE_SIZE*PAGES_PER_SGE, (u32)0xffff); @@ -4737,6 +4795,13 @@ static void bnx2x_init_context(struct bnx2x *bp) U64_HI(fp->rx_sge_mapping); context->ustorm_st_context.common.sge_page_base_lo = U64_LO(fp->rx_sge_mapping); + + context->ustorm_st_context.common.max_sges_for_packet = + SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT; + context->ustorm_st_context.common.max_sges_for_packet = + ((context->ustorm_st_context.common. + max_sges_for_packet + PAGES_PER_SGE - 1) & + (~(PAGES_PER_SGE - 1))) >> PAGES_PER_SGE_SHIFT; } context->ustorm_ag_context.cdu_usage = @@ -4744,24 +4809,27 @@ static void bnx2x_init_context(struct bnx2x *bp) CDU_REGION_NUMBER_UCM_AG, ETH_CONNECTION_TYPE); + context->xstorm_ag_context.cdu_reserved = + CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i), + CDU_REGION_NUMBER_XCM_AG, + ETH_CONNECTION_TYPE); + } + + for_each_tx_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + struct eth_context *context = + bnx2x_sp(bp, context[i - bp->num_rx_queues].eth); + + context->cstorm_st_context.sb_index_number = + C_SB_ETH_TX_CQ_INDEX; + context->cstorm_st_context.status_block_id = fp->sb_id; + context->xstorm_st_context.tx_bd_page_base_hi = U64_HI(fp->tx_desc_mapping); context->xstorm_st_context.tx_bd_page_base_lo = U64_LO(fp->tx_desc_mapping); - context->xstorm_st_context.db_data_addr_hi = - U64_HI(fp->tx_prods_mapping); - context->xstorm_st_context.db_data_addr_lo = - U64_LO(fp->tx_prods_mapping); - context->xstorm_st_context.statistics_data = (cl_id | + context->xstorm_st_context.statistics_data = (fp->cl_id | XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE); - context->cstorm_st_context.sb_index_number = - C_SB_ETH_TX_CQ_INDEX; - context->cstorm_st_context.status_block_id = sb_id; - - context->xstorm_ag_context.cdu_reserved = - CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i), - CDU_REGION_NUMBER_XCM_AG, - ETH_CONNECTION_TYPE); } } @@ -4799,18 +4867,6 @@ static void bnx2x_set_client_config(struct bnx2x *bp) } #endif - if (bp->flags & TPA_ENABLE_FLAG) { - tstorm_client.max_sges_for_packet = - SGE_PAGE_ALIGN(tstorm_client.mtu) >> SGE_PAGE_SHIFT; - tstorm_client.max_sges_for_packet = - ((tstorm_client.max_sges_for_packet + - PAGES_PER_SGE - 1) & (~(PAGES_PER_SGE - 1))) >> - PAGES_PER_SGE_SHIFT; - - tstorm_client.config_flags |= - TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING; - } - for_each_queue(bp, i) { tstorm_client.statistics_counter_id = bp->fp[i].cl_id; @@ -4893,17 +4949,6 @@ static void bnx2x_init_internal_common(struct bnx2x *bp) { int i; - if (bp->flags & TPA_ENABLE_FLAG) { - struct tstorm_eth_tpa_exist tpa = {0}; - - tpa.tpa_exist = 1; - - REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_TPA_EXIST_OFFSET, - ((u32 *)&tpa)[0]); - REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_TPA_EXIST_OFFSET + 4, - ((u32 *)&tpa)[1]); - } - /* Zero this manually as its initialization is currently missing in the initTool */ for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++) @@ -4915,8 +4960,10 @@ static void bnx2x_init_internal_port(struct bnx2x *bp) { int port = BP_PORT(bp); - REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_HC_BTR_OFFSET(port), BNX2X_BTR); - REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_OFFSET(port), BNX2X_BTR); + REG_WR(bp, + BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_U_OFFSET(port), BNX2X_BTR); + REG_WR(bp, + BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_C_OFFSET(port), BNX2X_BTR); REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(port), BNX2X_BTR); REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), BNX2X_BTR); } @@ -4976,6 +5023,12 @@ static void bnx2x_init_internal_func(struct bnx2x *bp) tstorm_config.config_flags = MULTI_FLAGS(bp); tstorm_config.rss_result_mask = MULTI_MASK; } + + /* Enable TPA if needed */ + if (bp->flags & TPA_ENABLE_FLAG) + tstorm_config.config_flags |= + TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA; + if (IS_E1HMF(bp)) tstorm_config.config_flags |= TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM; @@ -5087,6 +5140,14 @@ static void bnx2x_init_internal_func(struct bnx2x *bp) USTORM_CQE_PAGE_BASE_OFFSET(port, fp->cl_id) + 4, U64_HI(fp->rx_comp_mapping)); + /* Next page */ + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id), + U64_LO(fp->rx_comp_mapping + BCM_PAGE_SIZE)); + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id) + 4, + U64_HI(fp->rx_comp_mapping + BCM_PAGE_SIZE)); + REG_WR16(bp, BAR_USTRORM_INTMEM + USTORM_MAX_AGG_SIZE_OFFSET(port, fp->cl_id), max_agg_size); @@ -5197,6 +5258,9 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) fp->index = i; fp->cl_id = BP_L_ID(bp) + i; fp->sb_id = fp->cl_id; + /* Suitable Rx and Tx SBs are served by the same client */ + if (i >= bp->num_rx_queues) + fp->cl_id -= bp->num_rx_queues; DP(NETIF_MSG_IFUP, "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d sb %d\n", i, bp, fp->status_blk, fp->cl_id, fp->sb_id); @@ -5729,10 +5793,10 @@ static int bnx2x_init_common(struct bnx2x *bp) bnx2x_init_block(bp, USDM_BLOCK, COMMON_STAGE); bnx2x_init_block(bp, XSDM_BLOCK, COMMON_STAGE); - bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); - bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); - bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); - bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); + bnx2x_init_fill(bp, TSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp)); + bnx2x_init_fill(bp, USEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp)); + bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp)); + bnx2x_init_fill(bp, XSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp)); bnx2x_init_block(bp, TSEM_BLOCK, COMMON_STAGE); bnx2x_init_block(bp, USEM_BLOCK, COMMON_STAGE); @@ -5765,11 +5829,6 @@ static int bnx2x_init_common(struct bnx2x *bp) bnx2x_init_block(bp, CDU_BLOCK, COMMON_STAGE); val = (4 << 24) + (0 << 12) + 1024; REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val); - if (CHIP_IS_E1(bp)) { - /* !!! fix pxp client crdit until excel update */ - REG_WR(bp, CDU_REG_CDU_DEBUG, 0x264); - REG_WR(bp, CDU_REG_CDU_DEBUG, 0); - } bnx2x_init_block(bp, CFC_BLOCK, COMMON_STAGE); REG_WR(bp, CFC_REG_INIT_REG, 0x7FF); @@ -5782,19 +5841,14 @@ static int bnx2x_init_common(struct bnx2x *bp) bnx2x_init_block(bp, HC_BLOCK, COMMON_STAGE); bnx2x_init_block(bp, MISC_AEU_BLOCK, COMMON_STAGE); - /* PXPCS COMMON comes here */ bnx2x_init_block(bp, PXPCS_BLOCK, COMMON_STAGE); /* Reset PCIE errors for debug */ REG_WR(bp, 0x2814, 0xffffffff); REG_WR(bp, 0x3820, 0xffffffff); - /* EMAC0 COMMON comes here */ bnx2x_init_block(bp, EMAC0_BLOCK, COMMON_STAGE); - /* EMAC1 COMMON comes here */ bnx2x_init_block(bp, EMAC1_BLOCK, COMMON_STAGE); - /* DBU COMMON comes here */ bnx2x_init_block(bp, DBU_BLOCK, COMMON_STAGE); - /* DBG COMMON comes here */ bnx2x_init_block(bp, DBG_BLOCK, COMMON_STAGE); bnx2x_init_block(bp, NIG_BLOCK, COMMON_STAGE); @@ -5875,10 +5929,12 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0); - /* Port PXP comes here */ bnx2x_init_block(bp, PXP_BLOCK, init_stage); - /* Port PXP2 comes here */ bnx2x_init_block(bp, PXP2_BLOCK, init_stage); + + bnx2x_init_block(bp, TCM_BLOCK, init_stage); + bnx2x_init_block(bp, UCM_BLOCK, init_stage); + bnx2x_init_block(bp, CCM_BLOCK, init_stage); #ifdef BCM_ISCSI /* Port0 1 * Port1 385 */ @@ -5904,17 +5960,14 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i)); #endif - /* Port CMs come here */ bnx2x_init_block(bp, XCM_BLOCK, init_stage); - /* Port QM comes here */ #ifdef BCM_ISCSI REG_WR(bp, TM_REG_LIN0_SCAN_TIME + func*4, 1024/64*20); REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + func*4, 31); bnx2x_init_block(bp, TIMERS_BLOCK, init_stage); #endif - /* Port DQ comes here */ bnx2x_init_block(bp, DQ_BLOCK, init_stage); bnx2x_init_block(bp, BRB1_BLOCK, init_stage); @@ -5941,15 +5994,11 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0 + port*4, high); - /* Port PRS comes here */ bnx2x_init_block(bp, PRS_BLOCK, init_stage); - /* Port TSDM comes here */ + bnx2x_init_block(bp, TSDM_BLOCK, init_stage); - /* Port CSDM comes here */ bnx2x_init_block(bp, CSDM_BLOCK, init_stage); - /* Port USDM comes here */ bnx2x_init_block(bp, USDM_BLOCK, init_stage); - /* Port XSDM comes here */ bnx2x_init_block(bp, XSDM_BLOCK, init_stage); bnx2x_init_block(bp, TSEM_BLOCK, init_stage); @@ -5957,9 +6006,7 @@ static int bnx2x_init_port(struct bnx2x *bp) bnx2x_init_block(bp, CSEM_BLOCK, init_stage); bnx2x_init_block(bp, XSEM_BLOCK, init_stage); - /* Port UPB comes here */ bnx2x_init_block(bp, UPB_BLOCK, init_stage); - /* Port XPB comes here */ bnx2x_init_block(bp, XPB_BLOCK, init_stage); bnx2x_init_block(bp, PBF_BLOCK, init_stage); @@ -5989,11 +6036,8 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR_DMAE(bp, SRC_REG_LASTFREE0 + func*4, wb_write, 2); REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + func*4, 10); - /* Port SRCH comes here */ #endif - /* Port CDU comes here */ bnx2x_init_block(bp, CDU_BLOCK, init_stage); - /* Port CFC comes here */ bnx2x_init_block(bp, CFC_BLOCK, init_stage); if (CHIP_IS_E1(bp)) { @@ -6010,15 +6054,10 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, (IS_E1HMF(bp) ? 0xF7 : 0x7)); - /* Port PXPCS comes here */ bnx2x_init_block(bp, PXPCS_BLOCK, init_stage); - /* Port EMAC0 comes here */ bnx2x_init_block(bp, EMAC0_BLOCK, init_stage); - /* Port EMAC1 comes here */ bnx2x_init_block(bp, EMAC1_BLOCK, init_stage); - /* Port DBU comes here */ bnx2x_init_block(bp, DBU_BLOCK, init_stage); - /* Port DBG comes here */ bnx2x_init_block(bp, DBG_BLOCK, init_stage); bnx2x_init_block(bp, NIG_BLOCK, init_stage); @@ -6040,9 +6079,7 @@ static int bnx2x_init_port(struct bnx2x *bp) } } - /* Port MCP comes here */ bnx2x_init_block(bp, MCP_BLOCK, init_stage); - /* Port DMAE comes here */ bnx2x_init_block(bp, DMAE_BLOCK, init_stage); switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) { @@ -6302,8 +6339,7 @@ static void bnx2x_free_mem(struct bnx2x *bp) /* status blocks */ BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk), bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_status_block) + - sizeof(struct eth_tx_db_data)); + sizeof(struct host_status_block)); } /* Rx */ for_each_rx_queue(bp, i) { @@ -6332,7 +6368,7 @@ static void bnx2x_free_mem(struct bnx2x *bp) BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring)); BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring), bnx2x_fp(bp, i, tx_desc_mapping), - sizeof(struct eth_tx_bd) * NUM_TX_BD); + sizeof(union eth_tx_bd_types) * NUM_TX_BD); } /* end of fastpath */ @@ -6383,8 +6419,7 @@ static int bnx2x_alloc_mem(struct bnx2x *bp) /* status blocks */ BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, status_blk), &bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_status_block) + - sizeof(struct eth_tx_db_data)); + sizeof(struct host_status_block)); } /* Rx */ for_each_rx_queue(bp, i) { @@ -6411,19 +6446,12 @@ static int bnx2x_alloc_mem(struct bnx2x *bp) /* Tx */ for_each_tx_queue(bp, i) { - bnx2x_fp(bp, i, hw_tx_prods) = - (void *)(bnx2x_fp(bp, i, status_blk) + 1); - - bnx2x_fp(bp, i, tx_prods_mapping) = - bnx2x_fp(bp, i, status_blk_mapping) + - sizeof(struct host_status_block); - /* fastpath tx rings: tx_buf tx_desc */ BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring), sizeof(struct sw_tx_bd) * NUM_TX_BD); BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring), &bnx2x_fp(bp, i, tx_desc_mapping), - sizeof(struct eth_tx_bd) * NUM_TX_BD); + sizeof(union eth_tx_bd_types) * NUM_TX_BD); } /* end of fastpath */ @@ -6600,7 +6628,12 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp) for_each_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; - sprintf(fp->name, "%s.fp%d", bp->dev->name, i); + if (i < bp->num_rx_queues) + sprintf(fp->name, "%s-rx-%d", bp->dev->name, i); + else + sprintf(fp->name, "%s-tx-%d", + bp->dev->name, i - bp->num_rx_queues); + rc = request_irq(bp->msix_table[i + offset].vector, bnx2x_msix_fp_int, 0, fp->name, fp); if (rc) { @@ -6613,16 +6646,11 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp) } i = BNX2X_NUM_QUEUES(bp); - if (is_multi(bp)) - printk(KERN_INFO PFX - "%s: using MSI-X IRQs: sp %d fp %d - %d\n", - bp->dev->name, bp->msix_table[0].vector, - bp->msix_table[offset].vector, - bp->msix_table[offset + i - 1].vector); - else - printk(KERN_INFO PFX "%s: using MSI-X IRQs: sp %d fp %d\n", - bp->dev->name, bp->msix_table[0].vector, - bp->msix_table[offset + i - 1].vector); + printk(KERN_INFO PFX "%s: using MSI-X IRQs: sp %d fp[%d] %d" + " ... fp[%d] %d\n", + bp->dev->name, bp->msix_table[0].vector, + 0, bp->msix_table[offset].vector, + i - 1, bp->msix_table[offset + i - 1].vector); return 0; } @@ -6730,7 +6758,8 @@ static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set) config->config_table[0].target_table_entry.flags = 0; else CAM_INVALIDATE(config->config_table[0]); - config->config_table[0].target_table_entry.client_id = 0; + config->config_table[0].target_table_entry.clients_bit_vector = + cpu_to_le32(1 << BP_L_ID(bp)); config->config_table[0].target_table_entry.vlan_id = 0; DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)\n", @@ -6749,7 +6778,8 @@ static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set) TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST; else CAM_INVALIDATE(config->config_table[1]); - config->config_table[1].target_table_entry.client_id = 0; + config->config_table[1].target_table_entry.clients_bit_vector = + cpu_to_le32(1 << BP_L_ID(bp)); config->config_table[1].target_table_entry.vlan_id = 0; bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, @@ -6762,11 +6792,6 @@ static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set) struct mac_configuration_cmd_e1h *config = (struct mac_configuration_cmd_e1h *)bnx2x_sp(bp, mac_config); - if (set && (bp->state != BNX2X_STATE_OPEN)) { - DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state); - return; - } - /* CAM allocation for E1H * unicasts: by func number * multicast: 20+FUNC*20, 20 each @@ -6783,7 +6808,8 @@ static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set) swab16(*(u16 *)&bp->dev->dev_addr[2]); config->config_table[0].lsb_mac_addr = swab16(*(u16 *)&bp->dev->dev_addr[4]); - config->config_table[0].client_id = BP_L_ID(bp); + config->config_table[0].clients_bit_vector = + cpu_to_le32(1 << BP_L_ID(bp)); config->config_table[0].vlan_id = 0; config->config_table[0].e1hov_id = cpu_to_le16(bp->e1hov); if (set) @@ -6880,49 +6906,94 @@ static int bnx2x_setup_multi(struct bnx2x *bp, int index) static int bnx2x_poll(struct napi_struct *napi, int budget); -static void bnx2x_set_int_mode(struct bnx2x *bp) +static void bnx2x_set_int_mode_msix(struct bnx2x *bp, int *num_rx_queues_out, + int *num_tx_queues_out) +{ + int _num_rx_queues = 0, _num_tx_queues = 0; + + switch (bp->multi_mode) { + case ETH_RSS_MODE_DISABLED: + _num_rx_queues = 1; + _num_tx_queues = 1; + break; + + case ETH_RSS_MODE_REGULAR: + if (num_rx_queues) + _num_rx_queues = min_t(u32, num_rx_queues, + BNX2X_MAX_QUEUES(bp)); + else + _num_rx_queues = min_t(u32, num_online_cpus(), + BNX2X_MAX_QUEUES(bp)); + + if (num_tx_queues) + _num_tx_queues = min_t(u32, num_tx_queues, + BNX2X_MAX_QUEUES(bp)); + else + _num_tx_queues = min_t(u32, num_online_cpus(), + BNX2X_MAX_QUEUES(bp)); + + /* There must be not more Tx queues than Rx queues */ + if (_num_tx_queues > _num_rx_queues) { + BNX2X_ERR("number of tx queues (%d) > " + "number of rx queues (%d)" + " defaulting to %d\n", + _num_tx_queues, _num_rx_queues, + _num_rx_queues); + _num_tx_queues = _num_rx_queues; + } + break; + + + default: + _num_rx_queues = 1; + _num_tx_queues = 1; + break; + } + + *num_rx_queues_out = _num_rx_queues; + *num_tx_queues_out = _num_tx_queues; +} + +static int bnx2x_set_int_mode(struct bnx2x *bp) { - int num_queues; + int rc = 0; switch (int_mode) { case INT_MODE_INTx: case INT_MODE_MSI: - num_queues = 1; - bp->num_rx_queues = num_queues; - bp->num_tx_queues = num_queues; - DP(NETIF_MSG_IFUP, - "set number of queues to %d\n", num_queues); + bp->num_rx_queues = 1; + bp->num_tx_queues = 1; + DP(NETIF_MSG_IFUP, "set number of queues to 1\n"); break; case INT_MODE_MSIX: default: - if (bp->multi_mode == ETH_RSS_MODE_REGULAR) - num_queues = min_t(u32, num_online_cpus(), - BNX2X_MAX_QUEUES(bp)); - else - num_queues = 1; - bp->num_rx_queues = num_queues; - bp->num_tx_queues = num_queues; - DP(NETIF_MSG_IFUP, "set number of rx queues to %d" - " number of tx queues to %d\n", + /* Set interrupt mode according to bp->multi_mode value */ + bnx2x_set_int_mode_msix(bp, &bp->num_rx_queues, + &bp->num_tx_queues); + + DP(NETIF_MSG_IFUP, "set number of queues to: rx %d tx %d\n", bp->num_rx_queues, bp->num_tx_queues); + /* if we can't use MSI-X we only need one fp, * so try to enable MSI-X with the requested number of fp's * and fallback to MSI or legacy INTx with one fp */ - if (bnx2x_enable_msix(bp)) { + rc = bnx2x_enable_msix(bp); + if (rc) { /* failed to enable MSI-X */ - num_queues = 1; - bp->num_rx_queues = num_queues; - bp->num_tx_queues = num_queues; if (bp->multi_mode) BNX2X_ERR("Multi requested but failed to " - "enable MSI-X set number of " - "queues to %d\n", num_queues); + "enable MSI-X (rx %d tx %d), " + "set number of queues to 1\n", + bp->num_rx_queues, bp->num_tx_queues); + bp->num_rx_queues = 1; + bp->num_tx_queues = 1; } break; } bp->dev->real_num_tx_queues = bp->num_tx_queues; + return rc; } static void bnx2x_set_rx_mode(struct net_device *dev); @@ -6931,16 +7002,16 @@ static void bnx2x_set_rx_mode(struct net_device *dev); static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) { u32 load_code; - int i, rc = 0; + int i, rc; + #ifdef BNX2X_STOP_ON_ERROR - DP(NETIF_MSG_IFUP, "enter load_mode %d\n", load_mode); if (unlikely(bp->panic)) return -EPERM; #endif bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD; - bnx2x_set_int_mode(bp); + rc = bnx2x_set_int_mode(bp); if (bnx2x_alloc_mem(bp)) return -ENOMEM; @@ -6953,17 +7024,6 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), bnx2x_poll, 128); -#ifdef BNX2X_STOP_ON_ERROR - for_each_rx_queue(bp, i) { - struct bnx2x_fastpath *fp = &bp->fp[i]; - - fp->poll_no_work = 0; - fp->poll_calls = 0; - fp->poll_max_calls = 0; - fp->poll_complete = 0; - fp->poll_exit = 0; - } -#endif bnx2x_napi_enable(bp); if (bp->flags & USING_MSIX_FLAG) { @@ -6973,6 +7033,8 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) goto load_error1; } } else { + /* Fall to INTx if failed to enable MSI-X due to lack of + memory (in bnx2x_set_int_mode()) */ if ((rc != -ENOMEM) && (int_mode != INT_MODE_INTx)) bnx2x_enable_msi(bp); bnx2x_ack_int(bp); @@ -7065,17 +7127,18 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) bp->state = BNX2X_STATE_DISABLED; } - if (bp->state == BNX2X_STATE_OPEN) + if (bp->state == BNX2X_STATE_OPEN) { for_each_nondefault_queue(bp, i) { rc = bnx2x_setup_multi(bp, i); if (rc) goto load_error3; } - if (CHIP_IS_E1(bp)) - bnx2x_set_mac_addr_e1(bp, 1); - else - bnx2x_set_mac_addr_e1h(bp, 1); + if (CHIP_IS_E1(bp)) + bnx2x_set_mac_addr_e1(bp, 1); + else + bnx2x_set_mac_addr_e1h(bp, 1); + } if (bp->port.pmf) bnx2x_initial_phy_init(bp, load_mode); @@ -7083,14 +7146,18 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* Start fast path */ switch (load_mode) { case LOAD_NORMAL: - /* Tx queue should be only reenabled */ - netif_tx_wake_all_queues(bp->dev); + if (bp->state == BNX2X_STATE_OPEN) { + /* Tx queue should be only reenabled */ + netif_tx_wake_all_queues(bp->dev); + } /* Initialize the receive filter. */ bnx2x_set_rx_mode(bp->dev); break; case LOAD_OPEN: netif_tx_start_all_queues(bp->dev); + if (bp->state != BNX2X_STATE_OPEN) + netif_tx_disable(bp->dev); /* Initialize the receive filter. */ bnx2x_set_rx_mode(bp->dev); break; @@ -9184,18 +9251,19 @@ static int bnx2x_get_coalesce(struct net_device *dev, return 0; } +#define BNX2X_MAX_COALES_TOUT (0xf0*12) /* Maximal coalescing timeout in us */ static int bnx2x_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) { struct bnx2x *bp = netdev_priv(dev); bp->rx_ticks = (u16) coal->rx_coalesce_usecs; - if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT) - bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT; + if (bp->rx_ticks > BNX2X_MAX_COALES_TOUT) + bp->rx_ticks = BNX2X_MAX_COALES_TOUT; bp->tx_ticks = (u16) coal->tx_coalesce_usecs; - if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT) - bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT; + if (bp->tx_ticks > BNX2X_MAX_COALES_TOUT) + bp->tx_ticks = BNX2X_MAX_COALES_TOUT; if (netif_running(dev)) bnx2x_update_coalesce(bp); @@ -9554,12 +9622,14 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) unsigned int pkt_size, num_pkts, i; struct sk_buff *skb; unsigned char *packet; - struct bnx2x_fastpath *fp = &bp->fp[0]; + struct bnx2x_fastpath *fp_rx = &bp->fp[0]; + struct bnx2x_fastpath *fp_tx = &bp->fp[bp->num_rx_queues]; u16 tx_start_idx, tx_idx; u16 rx_start_idx, rx_idx; - u16 pkt_prod; + u16 pkt_prod, bd_prod; struct sw_tx_bd *tx_buf; - struct eth_tx_bd *tx_bd; + struct eth_tx_start_bd *tx_start_bd; + struct eth_tx_parse_bd *pbd = NULL; dma_addr_t mapping; union eth_rx_cqe *cqe; u8 cqe_fp_flags; @@ -9591,57 +9661,64 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) } packet = skb_put(skb, pkt_size); memcpy(packet, bp->dev->dev_addr, ETH_ALEN); - memset(packet + ETH_ALEN, 0, (ETH_HLEN - ETH_ALEN)); + memset(packet + ETH_ALEN, 0, ETH_ALEN); + memset(packet + 2*ETH_ALEN, 0x77, (ETH_HLEN - 2*ETH_ALEN)); for (i = ETH_HLEN; i < pkt_size; i++) packet[i] = (unsigned char) (i & 0xff); /* send the loopback packet */ num_pkts = 0; - tx_start_idx = le16_to_cpu(*fp->tx_cons_sb); - rx_start_idx = le16_to_cpu(*fp->rx_cons_sb); + tx_start_idx = le16_to_cpu(*fp_tx->tx_cons_sb); + rx_start_idx = le16_to_cpu(*fp_rx->rx_cons_sb); - pkt_prod = fp->tx_pkt_prod++; - tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)]; - tx_buf->first_bd = fp->tx_bd_prod; + pkt_prod = fp_tx->tx_pkt_prod++; + tx_buf = &fp_tx->tx_buf_ring[TX_BD(pkt_prod)]; + tx_buf->first_bd = fp_tx->tx_bd_prod; tx_buf->skb = skb; + tx_buf->flags = 0; - tx_bd = &fp->tx_desc_ring[TX_BD(fp->tx_bd_prod)]; + bd_prod = TX_BD(fp_tx->tx_bd_prod); + tx_start_bd = &fp_tx->tx_desc_ring[bd_prod].start_bd; mapping = pci_map_single(bp->pdev, skb->data, skb_headlen(skb), PCI_DMA_TODEVICE); - tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); - tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); - tx_bd->nbd = cpu_to_le16(1); - tx_bd->nbytes = cpu_to_le16(skb_headlen(skb)); - tx_bd->vlan = cpu_to_le16(pkt_prod); - tx_bd->bd_flags.as_bitfield = (ETH_TX_BD_FLAGS_START_BD | - ETH_TX_BD_FLAGS_END_BD); - tx_bd->general_data = ((UNICAST_ADDRESS << - ETH_TX_BD_ETH_ADDR_TYPE_SHIFT) | 1); + tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + tx_start_bd->nbd = cpu_to_le16(2); /* start + pbd */ + tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb)); + tx_start_bd->vlan = cpu_to_le16(pkt_prod); + tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; + tx_start_bd->general_data = ((UNICAST_ADDRESS << + ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT) | 1); + + /* turn on parsing and get a BD */ + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + pbd = &fp_tx->tx_desc_ring[bd_prod].parse_bd; + + memset(pbd, 0, sizeof(struct eth_tx_parse_bd)); wmb(); - le16_add_cpu(&fp->hw_tx_prods->bds_prod, 1); - mb(); /* FW restriction: must not reorder writing nbd and packets */ - le32_add_cpu(&fp->hw_tx_prods->packets_prod, 1); - DOORBELL(bp, fp->index, 0); + fp_tx->tx_db.data.prod += 2; + barrier(); + DOORBELL(bp, fp_tx->index - bp->num_rx_queues, fp_tx->tx_db.raw); mmiowb(); num_pkts++; - fp->tx_bd_prod++; + fp_tx->tx_bd_prod += 2; /* start + pbd */ bp->dev->trans_start = jiffies; udelay(100); - tx_idx = le16_to_cpu(*fp->tx_cons_sb); + tx_idx = le16_to_cpu(*fp_tx->tx_cons_sb); if (tx_idx != tx_start_idx + num_pkts) goto test_loopback_exit; - rx_idx = le16_to_cpu(*fp->rx_cons_sb); + rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb); if (rx_idx != rx_start_idx + num_pkts) goto test_loopback_exit; - cqe = &fp->rx_comp_ring[RCQ_BD(fp->rx_comp_cons)]; + cqe = &fp_rx->rx_comp_ring[RCQ_BD(fp_rx->rx_comp_cons)]; cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; if (CQE_TYPE(cqe_fp_flags) || (cqe_fp_flags & ETH_RX_ERROR_FALGS)) goto test_loopback_rx_exit; @@ -9650,7 +9727,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) if (len != pkt_size) goto test_loopback_rx_exit; - rx_buf = &fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)]; + rx_buf = &fp_rx->rx_buf_ring[RX_BD(fp_rx->rx_bd_cons)]; skb = rx_buf->skb; skb_reserve(skb, cqe->fast_path_cqe.placement_offset); for (i = ETH_HLEN; i < pkt_size; i++) @@ -9661,14 +9738,14 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) test_loopback_rx_exit: - fp->rx_bd_cons = NEXT_RX_IDX(fp->rx_bd_cons); - fp->rx_bd_prod = NEXT_RX_IDX(fp->rx_bd_prod); - fp->rx_comp_cons = NEXT_RCQ_IDX(fp->rx_comp_cons); - fp->rx_comp_prod = NEXT_RCQ_IDX(fp->rx_comp_prod); + fp_rx->rx_bd_cons = NEXT_RX_IDX(fp_rx->rx_bd_cons); + fp_rx->rx_bd_prod = NEXT_RX_IDX(fp_rx->rx_bd_prod); + fp_rx->rx_comp_cons = NEXT_RCQ_IDX(fp_rx->rx_comp_cons); + fp_rx->rx_comp_prod = NEXT_RCQ_IDX(fp_rx->rx_comp_prod); /* Update producers */ - bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, - fp->rx_sge_prod); + bnx2x_update_rx_prod(bp, fp_rx, fp_rx->rx_bd_prod, fp_rx->rx_comp_prod, + fp_rx->rx_sge_prod); test_loopback_exit: bp->link_params.loopback_mode = LOOPBACK_NONE; @@ -10001,7 +10078,7 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf) case ETH_SS_STATS: if (is_multi(bp)) { k = 0; - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { for (j = 0; j < BNX2X_NUM_Q_STATS; j++) sprintf(buf + (k + j)*ETH_GSTRING_LEN, bnx2x_q_stats_arr[j].string, i); @@ -10035,7 +10112,7 @@ static int bnx2x_get_stats_count(struct net_device *dev) int i, num_stats; if (is_multi(bp)) { - num_stats = BNX2X_NUM_Q_STATS * BNX2X_NUM_QUEUES(bp); + num_stats = BNX2X_NUM_Q_STATS * bp->num_rx_queues; if (!IS_E1HMF_MODE_STAT(bp)) num_stats += BNX2X_NUM_STATS; } else { @@ -10060,7 +10137,7 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev, if (is_multi(bp)) { k = 0; - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { hw_stats = (u32 *)&bp->fp[i].eth_q_stats; for (j = 0; j < BNX2X_NUM_Q_STATS; j++) { if (bnx2x_q_stats_arr[j].size == 0) { @@ -10273,15 +10350,11 @@ static int bnx2x_poll(struct napi_struct *napi, int budget) goto poll_panic; #endif - prefetch(fp->tx_buf_ring[TX_BD(fp->tx_pkt_cons)].skb); prefetch(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb); prefetch((char *)(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb) + 256); bnx2x_update_fpsb_idx(fp); - if (bnx2x_has_tx_work(fp)) - bnx2x_tx_int(fp); - if (bnx2x_has_rx_work(fp)) { work_done = bnx2x_rx_int(fp, budget); @@ -10290,11 +10363,11 @@ static int bnx2x_poll(struct napi_struct *napi, int budget) goto poll_again; } - /* BNX2X_HAS_WORK() reads the status block, thus we need to + /* bnx2x_has_rx_work() reads the status block, thus we need to * ensure that status block indices have been actually read - * (bnx2x_update_fpsb_idx) prior to this check (BNX2X_HAS_WORK) + * (bnx2x_update_fpsb_idx) prior to this check (bnx2x_has_rx_work) * so that we won't write the "newer" value of the status block to IGU - * (if there was a DMA right after BNX2X_HAS_WORK and + * (if there was a DMA right after bnx2x_has_rx_work and * if there is no rmb, the memory reading (bnx2x_update_fpsb_idx) * may be postponed to right before bnx2x_ack_sb). In this case * there will never be another interrupt until there is another update @@ -10302,7 +10375,7 @@ static int bnx2x_poll(struct napi_struct *napi, int budget) */ rmb(); - if (!BNX2X_HAS_WORK(fp)) { + if (!bnx2x_has_rx_work(fp)) { #ifdef BNX2X_STOP_ON_ERROR poll_panic: #endif @@ -10327,10 +10400,11 @@ poll_again: */ static noinline u16 bnx2x_tx_split(struct bnx2x *bp, struct bnx2x_fastpath *fp, - struct eth_tx_bd **tx_bd, u16 hlen, + struct sw_tx_bd *tx_buf, + struct eth_tx_start_bd **tx_bd, u16 hlen, u16 bd_prod, int nbd) { - struct eth_tx_bd *h_tx_bd = *tx_bd; + struct eth_tx_start_bd *h_tx_bd = *tx_bd; struct eth_tx_bd *d_tx_bd; dma_addr_t mapping; int old_len = le16_to_cpu(h_tx_bd->nbytes); @@ -10346,7 +10420,7 @@ static noinline u16 bnx2x_tx_split(struct bnx2x *bp, /* now get a new data BD * (after the pbd) and fill it */ bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); - d_tx_bd = &fp->tx_desc_ring[bd_prod]; + d_tx_bd = &fp->tx_desc_ring[bd_prod].reg_bd; mapping = HILO_U64(le32_to_cpu(h_tx_bd->addr_hi), le32_to_cpu(h_tx_bd->addr_lo)) + hlen; @@ -10354,17 +10428,16 @@ static noinline u16 bnx2x_tx_split(struct bnx2x *bp, d_tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); d_tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); d_tx_bd->nbytes = cpu_to_le16(old_len - hlen); - d_tx_bd->vlan = 0; - /* this marks the BD as one that has no individual mapping - * the FW ignores this flag in a BD not marked start - */ - d_tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_SW_LSO; + + /* this marks the BD as one that has no individual mapping */ + tx_buf->flags |= BNX2X_TSO_SPLIT_BD; + DP(NETIF_MSG_TX_QUEUED, "TSO split data size is %d (%x:%x)\n", d_tx_bd->nbytes, d_tx_bd->addr_hi, d_tx_bd->addr_lo); - /* update tx_bd for marking the last BD flag */ - *tx_bd = d_tx_bd; + /* update tx_bd */ + *tx_bd = (struct eth_tx_start_bd *)d_tx_bd; return bd_prod; } @@ -10499,18 +10572,19 @@ exit_lbl: static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); - struct bnx2x_fastpath *fp; + struct bnx2x_fastpath *fp, *fp_stat; struct netdev_queue *txq; struct sw_tx_bd *tx_buf; - struct eth_tx_bd *tx_bd; + struct eth_tx_start_bd *tx_start_bd; + struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL; struct eth_tx_parse_bd *pbd = NULL; u16 pkt_prod, bd_prod; int nbd, fp_index; dma_addr_t mapping; u32 xmit_type = bnx2x_xmit_type(bp, skb); - int vlan_off = (bp->e1hov ? 4 : 0); int i; u8 hlen = 0; + __le16 pkt_size = 0; #ifdef BNX2X_STOP_ON_ERROR if (unlikely(bp->panic)) @@ -10520,10 +10594,11 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) fp_index = skb_get_queue_mapping(skb); txq = netdev_get_tx_queue(dev, fp_index); - fp = &bp->fp[fp_index]; + fp = &bp->fp[fp_index + bp->num_rx_queues]; + fp_stat = &bp->fp[fp_index]; if (unlikely(bnx2x_tx_avail(fp) < (skb_shinfo(skb)->nr_frags + 3))) { - fp->eth_q_stats.driver_xoff++, + fp_stat->eth_q_stats.driver_xoff++; netif_tx_stop_queue(txq); BNX2X_ERR("BUG! Tx ring full when queue awake!\n"); return NETDEV_TX_BUSY; @@ -10552,7 +10627,7 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Please read carefully. First we use one BD which we mark as start, - then for TSO or xsum we have a parsing info BD, + then we have a parsing info BD (used for TSO or xsum), and only then we have the rest of the TSO BDs. (don't forget to mark the last one as last, and to unmap only AFTER you write to the BD ...) @@ -10564,42 +10639,40 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* get a tx_buf and first BD */ tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)]; - tx_bd = &fp->tx_desc_ring[bd_prod]; + tx_start_bd = &fp->tx_desc_ring[bd_prod].start_bd; - tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; - tx_bd->general_data = (UNICAST_ADDRESS << - ETH_TX_BD_ETH_ADDR_TYPE_SHIFT); + tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; + tx_start_bd->general_data = (UNICAST_ADDRESS << + ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT); /* header nbd */ - tx_bd->general_data |= (1 << ETH_TX_BD_HDR_NBDS_SHIFT); + tx_start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT); /* remember the first BD of the packet */ tx_buf->first_bd = fp->tx_bd_prod; tx_buf->skb = skb; + tx_buf->flags = 0; DP(NETIF_MSG_TX_QUEUED, "sending pkt %u @%p next_idx %u bd %u @%p\n", - pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_bd); + pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_start_bd); #ifdef BCM_VLAN if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb) && (bp->flags & HW_VLAN_TX_FLAG)) { - tx_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb)); - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG; - vlan_off += 4; + tx_start_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG; } else #endif - tx_bd->vlan = cpu_to_le16(pkt_prod); + tx_start_bd->vlan = cpu_to_le16(pkt_prod); - if (xmit_type) { - /* turn on parsing and get a BD */ - bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); - pbd = (void *)&fp->tx_desc_ring[bd_prod]; + /* turn on parsing and get a BD */ + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + pbd = &fp->tx_desc_ring[bd_prod].parse_bd; - memset(pbd, 0, sizeof(struct eth_tx_parse_bd)); - } + memset(pbd, 0, sizeof(struct eth_tx_parse_bd)); if (xmit_type & XMIT_CSUM) { - hlen = (skb_network_header(skb) - skb->data + vlan_off) / 2; + hlen = (skb_network_header(skb) - skb->data) / 2; /* for now NS flag is not used in Linux */ pbd->global_data = @@ -10612,15 +10685,16 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) hlen += pbd->ip_hlen + tcp_hdrlen(skb) / 2; pbd->total_hlen = cpu_to_le16(hlen); - hlen = hlen*2 - vlan_off; + hlen = hlen*2; - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_TCP_CSUM; + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM; if (xmit_type & XMIT_CSUM_V4) - tx_bd->bd_flags.as_bitfield |= + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IP_CSUM; else - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IPV6; + tx_start_bd->bd_flags.as_bitfield |= + ETH_TX_BD_FLAGS_IPV6; if (xmit_type & XMIT_CSUM_TCP) { pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check); @@ -10628,13 +10702,11 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) } else { s8 fix = SKB_CS_OFF(skb); /* signed! */ - pbd->global_data |= ETH_TX_PARSE_BD_CS_ANY_FLG; - pbd->cs_offset = fix / 2; + pbd->global_data |= ETH_TX_PARSE_BD_UDP_CS_FLG; DP(NETIF_MSG_TX_QUEUED, - "hlen %d offset %d fix %d csum before fix %x\n", - le16_to_cpu(pbd->total_hlen), pbd->cs_offset, fix, - SKB_CS(skb)); + "hlen %d fix %d csum before fix %x\n", + le16_to_cpu(pbd->total_hlen), fix, SKB_CS(skb)); /* HW bug: fixup the CSUM */ pbd->tcp_pseudo_csum = @@ -10649,17 +10721,18 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) mapping = pci_map_single(bp->pdev, skb->data, skb_headlen(skb), PCI_DMA_TODEVICE); - tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); - tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); - nbd = skb_shinfo(skb)->nr_frags + ((pbd == NULL) ? 1 : 2); - tx_bd->nbd = cpu_to_le16(nbd); - tx_bd->nbytes = cpu_to_le16(skb_headlen(skb)); + tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + nbd = skb_shinfo(skb)->nr_frags + 2; /* start_bd + pbd + frags */ + tx_start_bd->nbd = cpu_to_le16(nbd); + tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb)); + pkt_size = tx_start_bd->nbytes; DP(NETIF_MSG_TX_QUEUED, "first bd @%p addr (%x:%x) nbd %d" " nbytes %d flags %x vlan %x\n", - tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, le16_to_cpu(tx_bd->nbd), - le16_to_cpu(tx_bd->nbytes), tx_bd->bd_flags.as_bitfield, - le16_to_cpu(tx_bd->vlan)); + tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo, + le16_to_cpu(tx_start_bd->nbd), le16_to_cpu(tx_start_bd->nbytes), + tx_start_bd->bd_flags.as_bitfield, le16_to_cpu(tx_start_bd->vlan)); if (xmit_type & XMIT_GSO) { @@ -10668,11 +10741,11 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) skb->len, hlen, skb_headlen(skb), skb_shinfo(skb)->gso_size); - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO; + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO; if (unlikely(skb_headlen(skb) > hlen)) - bd_prod = bnx2x_tx_split(bp, fp, &tx_bd, hlen, - bd_prod, ++nbd); + bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd, + hlen, bd_prod, ++nbd); pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size); pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq); @@ -10693,33 +10766,31 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN; } + tx_data_bd = (struct eth_tx_bd *)tx_start_bd; for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); - tx_bd = &fp->tx_desc_ring[bd_prod]; + tx_data_bd = &fp->tx_desc_ring[bd_prod].reg_bd; + if (total_pkt_bd == NULL) + total_pkt_bd = &fp->tx_desc_ring[bd_prod].reg_bd; mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset, frag->size, PCI_DMA_TODEVICE); - tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); - tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); - tx_bd->nbytes = cpu_to_le16(frag->size); - tx_bd->vlan = cpu_to_le16(pkt_prod); - tx_bd->bd_flags.as_bitfield = 0; + tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + tx_data_bd->nbytes = cpu_to_le16(frag->size); + le16_add_cpu(&pkt_size, frag->size); DP(NETIF_MSG_TX_QUEUED, - "frag %d bd @%p addr (%x:%x) nbytes %d flags %x\n", - i, tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, - le16_to_cpu(tx_bd->nbytes), tx_bd->bd_flags.as_bitfield); + "frag %d bd @%p addr (%x:%x) nbytes %d\n", + i, tx_data_bd, tx_data_bd->addr_hi, tx_data_bd->addr_lo, + le16_to_cpu(tx_data_bd->nbytes)); } - /* now at last mark the BD as the last BD */ - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_END_BD; - - DP(NETIF_MSG_TX_QUEUED, "last bd @%p flags %x\n", - tx_bd, tx_bd->bd_flags.as_bitfield); + DP(NETIF_MSG_TX_QUEUED, "last bd @%p\n", tx_data_bd); bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); @@ -10729,6 +10800,9 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) if (TX_BD_POFF(bd_prod) < nbd) nbd++; + if (total_pkt_bd != NULL) + total_pkt_bd->total_pkt_bytes = pkt_size; + if (pbd) DP(NETIF_MSG_TX_QUEUED, "PBD @%p ip_data %x ip_hlen %u ip_id %u lso_mss %u" @@ -10748,25 +10822,24 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) */ wmb(); - le16_add_cpu(&fp->hw_tx_prods->bds_prod, nbd); - mb(); /* FW restriction: must not reorder writing nbd and packets */ - le32_add_cpu(&fp->hw_tx_prods->packets_prod, 1); - DOORBELL(bp, fp->index, 0); + fp->tx_db.data.prod += nbd; + barrier(); + DOORBELL(bp, fp->index - bp->num_rx_queues, fp->tx_db.raw); mmiowb(); fp->tx_bd_prod += nbd; if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) { + netif_tx_stop_queue(txq); /* We want bnx2x_tx_int to "see" the updated tx_bd_prod if we put Tx into XOFF state. */ smp_mb(); - netif_tx_stop_queue(txq); - fp->eth_q_stats.driver_xoff++; + fp_stat->eth_q_stats.driver_xoff++; if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3) netif_tx_wake_queue(txq); } - fp->tx_pkt++; + fp_stat->tx_pkt++; return NETDEV_TX_OK; } @@ -10842,8 +10915,9 @@ static void bnx2x_set_rx_mode(struct net_device *dev) cpu_to_le16(port); config->config_table[i]. target_table_entry.flags = 0; - config->config_table[i]. - target_table_entry.client_id = 0; + config->config_table[i].target_table_entry. + clients_bit_vector = + cpu_to_le32(1 << BP_L_ID(bp)); config->config_table[i]. target_table_entry.vlan_id = 0; diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 8e9e7a2..25639e2 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -370,7 +370,6 @@ #define CFC_REG_NUM_LCIDS_LEAVING 0x104018 /* [RW 8] The event id for aggregated interrupt 0 */ #define CSDM_REG_AGG_INT_EVENT_0 0xc2038 -#define CSDM_REG_AGG_INT_EVENT_1 0xc203c #define CSDM_REG_AGG_INT_EVENT_10 0xc2060 #define CSDM_REG_AGG_INT_EVENT_11 0xc2064 #define CSDM_REG_AGG_INT_EVENT_12 0xc2068 @@ -378,37 +377,27 @@ #define CSDM_REG_AGG_INT_EVENT_14 0xc2070 #define CSDM_REG_AGG_INT_EVENT_15 0xc2074 #define CSDM_REG_AGG_INT_EVENT_16 0xc2078 -#define CSDM_REG_AGG_INT_EVENT_17 0xc207c -#define CSDM_REG_AGG_INT_EVENT_18 0xc2080 -#define CSDM_REG_AGG_INT_EVENT_19 0xc2084 #define CSDM_REG_AGG_INT_EVENT_2 0xc2040 -#define CSDM_REG_AGG_INT_EVENT_20 0xc2088 -#define CSDM_REG_AGG_INT_EVENT_21 0xc208c -#define CSDM_REG_AGG_INT_EVENT_22 0xc2090 -#define CSDM_REG_AGG_INT_EVENT_23 0xc2094 -#define CSDM_REG_AGG_INT_EVENT_24 0xc2098 -#define CSDM_REG_AGG_INT_EVENT_25 0xc209c -#define CSDM_REG_AGG_INT_EVENT_26 0xc20a0 -#define CSDM_REG_AGG_INT_EVENT_27 0xc20a4 -#define CSDM_REG_AGG_INT_EVENT_28 0xc20a8 -#define CSDM_REG_AGG_INT_EVENT_29 0xc20ac #define CSDM_REG_AGG_INT_EVENT_3 0xc2044 -#define CSDM_REG_AGG_INT_EVENT_30 0xc20b0 -#define CSDM_REG_AGG_INT_EVENT_31 0xc20b4 #define CSDM_REG_AGG_INT_EVENT_4 0xc2048 -/* [RW 1] The T bit for aggregated interrupt 0 */ -#define CSDM_REG_AGG_INT_T_0 0xc20b8 -#define CSDM_REG_AGG_INT_T_1 0xc20bc -#define CSDM_REG_AGG_INT_T_10 0xc20e0 -#define CSDM_REG_AGG_INT_T_11 0xc20e4 -#define CSDM_REG_AGG_INT_T_12 0xc20e8 -#define CSDM_REG_AGG_INT_T_13 0xc20ec -#define CSDM_REG_AGG_INT_T_14 0xc20f0 -#define CSDM_REG_AGG_INT_T_15 0xc20f4 -#define CSDM_REG_AGG_INT_T_16 0xc20f8 -#define CSDM_REG_AGG_INT_T_17 0xc20fc -#define CSDM_REG_AGG_INT_T_18 0xc2100 -#define CSDM_REG_AGG_INT_T_19 0xc2104 +#define CSDM_REG_AGG_INT_EVENT_5 0xc204c +#define CSDM_REG_AGG_INT_EVENT_6 0xc2050 +#define CSDM_REG_AGG_INT_EVENT_7 0xc2054 +#define CSDM_REG_AGG_INT_EVENT_8 0xc2058 +#define CSDM_REG_AGG_INT_EVENT_9 0xc205c +/* [RW 1] For each aggregated interrupt index whether the mode is normal (0) + or auto-mask-mode (1) */ +#define CSDM_REG_AGG_INT_MODE_10 0xc21e0 +#define CSDM_REG_AGG_INT_MODE_11 0xc21e4 +#define CSDM_REG_AGG_INT_MODE_12 0xc21e8 +#define CSDM_REG_AGG_INT_MODE_13 0xc21ec +#define CSDM_REG_AGG_INT_MODE_14 0xc21f0 +#define CSDM_REG_AGG_INT_MODE_15 0xc21f4 +#define CSDM_REG_AGG_INT_MODE_16 0xc21f8 +#define CSDM_REG_AGG_INT_MODE_6 0xc21d0 +#define CSDM_REG_AGG_INT_MODE_7 0xc21d4 +#define CSDM_REG_AGG_INT_MODE_8 0xc21d8 +#define CSDM_REG_AGG_INT_MODE_9 0xc21dc /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define CSDM_REG_CFC_RSP_START_ADDR 0xc2008 /* [RW 16] The maximum value of the competion counter #0 */ @@ -1421,6 +1410,8 @@ /* [RW 1] e1hmf for WOL. If clr WOL signal o the PXP will be send on bit 0 only. */ #define MISC_REG_E1HMF_MODE 0xa5f8 +/* [RW 32] Debug only: spare RW register reset by core reset */ +#define MISC_REG_GENERIC_CR_0 0xa460 /* [RW 32] GPIO. [31-28] FLOAT port 0; [27-24] FLOAT port 0; When any of these bits is written as a '1'; the corresponding SPIO bit will turn off it's drivers and become an input. This is the reset state of all GPIO @@ -1729,6 +1720,7 @@ /* [RW 3] for port0 enable for llfc ppp and pause. b0 - brb1 enable; b1- tsdm enable; b2- usdm enable */ #define NIG_REG_LLFC_EGRESS_SRC_ENABLE_0 0x16070 +#define NIG_REG_LLFC_EGRESS_SRC_ENABLE_1 0x16074 /* [RW 1] SAFC enable for port0. This register may get 1 only when ~ppp_enable.ppp_enable = 0 and pause_enable.pause_enable =0 for the same port */ @@ -2079,6 +2071,7 @@ #define PXP2_REG_PGL_ADDR_94_F0 0x120540 #define PXP2_REG_PGL_CONTROL0 0x120490 #define PXP2_REG_PGL_CONTROL1 0x120514 +#define PXP2_REG_PGL_DEBUG 0x120520 /* [RW 32] third dword data of expansion rom request. this register is special. reading from it provides a vector outstanding read requests. if a bit is zero it means that a read request on the corresponding tag did @@ -2239,6 +2232,9 @@ allocated for vq22 */ #define PXP2_REG_RD_MAX_BLKS_VQ22 0x1203d0 /* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq25 */ +#define PXP2_REG_RD_MAX_BLKS_VQ25 0x1203dc +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be allocated for vq6 */ #define PXP2_REG_RD_MAX_BLKS_VQ6 0x120390 /* [RW 8] The maximum number of blocks in Tetris Buffer that can be @@ -3835,6 +3831,7 @@ #define TM_REG_LIN0_PHY_ADDR 0x164270 /* [RW 1] Linear0 physical address valid. */ #define TM_REG_LIN0_PHY_ADDR_VALID 0x164248 +#define TM_REG_LIN0_SCAN_ON 0x1640d0 /* [RW 24] Linear0 array scan timeout. */ #define TM_REG_LIN0_SCAN_TIME 0x16403c /* [RW 32] Linear1 logic address. */ @@ -4363,6 +4360,7 @@ #define USDM_REG_AGG_INT_EVENT_31 0xc40b4 #define USDM_REG_AGG_INT_EVENT_4 0xc4048 #define USDM_REG_AGG_INT_EVENT_5 0xc404c +#define USDM_REG_AGG_INT_EVENT_6 0xc4050 /* [RW 1] For each aggregated interrupt index whether the mode is normal (0) or auto-mask-mode (1) */ #define USDM_REG_AGG_INT_MODE_0 0xc41b8 @@ -4379,6 +4377,10 @@ #define USDM_REG_AGG_INT_MODE_19 0xc4204 #define USDM_REG_AGG_INT_MODE_4 0xc41c8 #define USDM_REG_AGG_INT_MODE_5 0xc41cc +#define USDM_REG_AGG_INT_MODE_6 0xc41d0 +/* [RW 1] The T bit for aggregated interrupt 5 */ +#define USDM_REG_AGG_INT_T_5 0xc40cc +#define USDM_REG_AGG_INT_T_6 0xc40d0 /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define USDM_REG_CFC_RSP_START_ADDR 0xc4008 /* [RW 16] The maximum value of the competion counter #0 */ diff --git a/firmware/Makefile b/firmware/Makefile index 44313b2..317212c 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -32,7 +32,7 @@ fw-shipped-$(CONFIG_ADAPTEC_STARFIRE) += adaptec/starfire_rx.bin \ adaptec/starfire_tx.bin fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw -fw-shipped-$(CONFIG_BNX2X) += bnx2x-e1-4.8.53.0.fw bnx2x-e1h-4.8.53.0.fw +fw-shipped-$(CONFIG_BNX2X) += bnx2x-e1-5.0.21.0.fw bnx2x-e1h-5.0.21.0.fw fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-4.6.17.fw \ bnx2/bnx2-rv2p-09-4.6.15.fw \ bnx2/bnx2-mips-06-4.6.16.fw \ -- cgit v0.10.2 From a1d58179d1337ff8f8530c9fac8b9e98b2f7761f Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 22:53:55 -0700 Subject: bnx2x: Removing old FW files Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/firmware/bnx2x-e1-4.8.53.0.fw.ihex b/firmware/bnx2x-e1-4.8.53.0.fw.ihex deleted file mode 100644 index f1edb1e..0000000 --- a/firmware/bnx2x-e1-4.8.53.0.fw.ihex +++ /dev/null @@ -1,10364 +0,0 @@ -:10000000000028600000006000000630000028C8E2 -:100010000000160800002F000000009400004510AA -:10002000000073C8000045A8000000C40000B978B3 -:100030000000A4680000BA400000007400015EB037 -:100040000000559000015F28000000B80001B4C016 -:100050000000D1F80001B580000000040002878094 -:10006000020400480000000F020400540000004594 -:1000700002040058000000840204005C0000000636 -:100080000204007000000004020400780000000078 -:100090000204007C121700000204008022170000F6 -:1000A00002040084321700000604008800000005E6 -:1000B0000204009C12150000020400A0221500009A -:1000C000020400A432150000060400A80000000489 -:1000D000020400B802100000020400BC001000007E -:1000E000020400C010100000020400C42010000030 -:1000F000020400C830100000060400CC0000000418 -:10010000020400DC00100000020400E012140000F1 -:10011000020400E422140000020400E8321400008B -:10012000060400EC000000040104012400000000AB -:1001300001040128000000000104012C000000005F -:10014000010401300000000002040004000000FF70 -:1001500002040008000000FF0204000C000000FF81 -:1001600002040010000000FF02040014000000FF61 -:1001700002040018000000FF0204001C000000FF41 -:1001800002040020000000FF020400240000003EE2 -:1001900002040028000000000204002C0000003FC0 -:1001A000020400300000003F020400340000003F61 -:1001B00002040038000000000204003C0000003F80 -:1001C000020400400000003F020400440000003F21 -:1001D00002042008000004110204200C00000400A6 -:1001E000020420100000040402042014000004197A -:1001F0000204201C0000FFFF020420200000FFFF7B -:10020000020420240000FFFF020420280000FFFF5A -:1002100006042038000000020204204000000034E0 -:100220000204204400000035060420480000007C41 -:100230000204223807FFFFFF0204223C0000003FB7 -:100240000204224007FFFFFF020422440000000FC7 -:1002500001042248000000000104224C00000000BC -:10026000010422500000000001042254000000009C -:1002700001042258000000000104225C000000007C -:10028000010422600000000001042264000000005C -:1002900001042268000000000104226C000000003C -:1002A000010422700000000001042274000000001C -:1002B00001042278000000000104227C00000000FC -:1002C000020424BC000000010C042000000003E82C -:1002D0000A042000000000010B0420000000000AB6 -:1002E0000205004400000020020500480000003222 -:1002F000020500900215002002050094021500205E -:1003000002050098000000300205009C0810000063 -:10031000020500A000000033020500A40000003028 -:10032000020500A800000031020500AC0000000238 -:10033000020500B000000005020500B40000000640 -:10034000020500B800000002020500BC0000000227 -:10035000020500C000000000020500C40000000506 -:10036000020500C800000002020500CC00000002E7 -:10037000020500D000000002020500D400000001C8 -:1003800002050114000000010205011C000000012B -:100390000205012000000002020502040000000125 -:1003A0000205020C0000004002050210000000409F -:1003B0000205021C000000200205022000000013BC -:1003C0000205022400000020060502400000000A89 -:1003D0000405028000200000020500500000000714 -:1003E0000205005400000007020500580000000844 -:1003F0000205005C00000008060500600000000423 -:10040000020500D800000006020500E00000000D13 -:10041000020500E40000002D020500E800000007CE -:10042000020500EC00000027020500F000000007B4 -:10043000020500F400000027020500F80000000794 -:10044000020500FC00000027020500040000000176 -:1004500002050008000000010205000C0000000178 -:100460000205001000000001020500140000000158 -:1004700002050018000000010205001C0000000138 -:100480000205002000000001020500240000000118 -:1004900002050028000000010205002C00000001F8 -:1004A00002050030000000010205003400000001D8 -:1004B00002050038000000010205003C00000001B8 -:1004C00002050040000000010406100002000020A8 -:1004D000020600DC00000001010600D80000000058 -:1004E0000406020000030220020600DC00000000F7 -:1004F00002060068000000B802060078000001143F -:10050000010600B800000000010600C8000000005D -:100510000206006C000000B80206007C0000011416 -:10052000010600BC00000000010600CC0000000035 -:100530000718040000930000081807600014022345 -:10054000071C0000324F0000071C800033250C946C -:10055000071D00000E4D195E081D1E005C4002259F -:100560000118000000000000011800040000000055 -:1005700001180008000000000118000C0000000035 -:100580000118001000000000011800140000000015 -:1005900002180020000000010218002400000002E0 -:1005A00002180028000000030218002C00000000C0 -:1005B000021800300000000402180034000000019E -:1005C00002180038000000000218003C0000000182 -:1005D000021800400000000402180044000000005F -:1005E00002180048000000010218004C000000033F -:1005F0000218005000000000021800540000000122 -:1006000002180058000000040218005C00000000FE -:1006100002180060000000010218006400000003DE -:1006200002180068000000000218006C00000001C1 -:10063000021800700000000402180074000000009E -:1006400002180078000000040218007C000000037B -:100650000618008000000002021800A400003FFFFE -:10066000021800A8000003FF021802240000000086 -:1006700002180234000000000218024C00000000C2 -:10068000021802E4000000FF061810000000040039 -:10069000021B8BC000000001021B80000000003420 -:1006A000021B804000000018021B80800000000C2C -:1006B000021B80C0000000200C1B83000007A1204B -:1006C0000A1B8300000001380B1B83000000138805 -:1006D000021B83C0000001F4061A2000000000B2D3 -:1006E000061A23C8000000C1041A26CC0001022704 -:1006F000061A1020000000C8061A100000000002B0 -:10070000061A1C1800000004061A1C100000000243 -:10071000061A080000000002061A0808000000027D -:10072000061A081000000004041A1FB00004022872 -:10073000041A4CB00008022C061A22C8000000203F -:10074000061A40000000016C021A4B600000000015 -:10075000061A14000000000A061A145000000006D1 -:10076000061A150000000002041A150800050234DC -:10077000061A151C00000007061A1570000000126A -:10078000061A09C00000004C061A0800000000020A -:10079000061A08200000000E041A1FB000020239D9 -:1007A000061A290800000002061A2348000000204B -:1007B000061A45B00000016C021A4B6400000000EC -:1007C000061A14280000000A061A14680000000621 -:1007D000061A153800000002041A15400005023BF5 -:1007E000061A155400000007061A15B8000000127A -:1007F000061A0AF00000004C061A08080000000261 -:10080000061A08580000000E041A1FB80002024021 -:10081000061A2910000000020200A2800000000158 -:100820000200A294071D29110200A29800000000F6 -:100830000200A29C009C04240200A2A00000000070 -:100840000200A2A4000002090200A4FCFF000000B4 -:10085000020100B400000001020100B80000000124 -:10086000020100DC000000010201010000000001A3 -:1008700002010104000000010201007C00300000C0 -:1008800002010084000000280201008C000000002A -:1008900002010130000000040201025C00000001BE -:1008A000020103280000000002010554000000308E -:1008B000020100C400000001020100CC00000001A0 -:1008C000020100F800000001020100F00000000138 -:1008D00002010080003000000201008800000028B2 -:1008E0000201009000000000020101340000000439 -:1008F000020102DC000000010201032C00000000E4 -:100900000201056400000030020100C8000000017F -:10091000020100D000000001020100FC0000000103 -:10092000020100F400000001020C10000000002091 -:10093000020C200800000A11020C200C00000A0022 -:10094000020C201000000A04020C201C0000FFFF13 -:10095000020C20200000FFFF020C20240000FFFFFB -:10096000020C20280000FFFF020C2038000000C607 -:10097000020C203C00000000020C2040000000346B -:10098000020C204400000035060C20480000001C2A -:10099000020C20B800000001060C20BC0000005F23 -:1009A000020C223807FFFFFF020C223C0000003F30 -:1009B000020C224007FFFFFF020C22440000000F40 -:1009C000010C224800000000010C224C0000000035 -:1009D000010C225000000000010C22540000000015 -:1009E000010C225800000000010C225C00000000F5 -:1009F000010C226000000000010C226400000000D5 -:100A0000010C226800000000010C226C00000000B4 -:100A1000010C227000000000010C22740000000094 -:100A2000010C227800000000010C227C0000000074 -:100A3000020C24BC000000010C0C2000000003E8A4 -:100A40000A0C2000000000010B0C20000000000A2E -:100A5000020C400800000A11020C400C00000A00C1 -:100A6000020C401000000A04020C401400000A218D -:100A7000020C401C0000FFFF020C40200000FFFFA2 -:100A8000020C40240000FFFF020C40280000FFFF82 -:100A9000020C403800000046020C403C00000005FB -:100AA000020C404000000034020C404400000035BD -:100AB000060C40480000005C020C41B80000000138 -:100AC000060C41BC0000001F020C423807FFFFFF6C -:100AD000020C423C0000003F020C424007FFFFFFB7 -:100AE000020C42440000000F010C424800000000CC -:100AF000010C424C00000000010C425000000000BC -:100B0000010C425400000000010C4258000000009B -:100B1000010C425C00000000010C4260000000007B -:100B2000010C426400000000010C4268000000005B -:100B3000010C426C00000000010C4270000000003B -:100B4000010C427400000000010C4278000000001B -:100B5000010C427C00000000010C428000000000FB -:100B6000020C44C0000000010C0C4000000003E82F -:100B70000A0C4000000000010B0C40000000000ABD -:100B8000020D004400000032020D008C021500200E -:100B9000020D009002150020020D009408100000C4 -:100BA000020D009800000033020D009C00000002BE -:100BB000020D00A000000000020D00A400000005CE -:100BC000020D00A800000005060D00AC00000002A8 -:100BD000020D00B400000002020D00B80000000386 -:100BE000020D00BC00000002020D00C00000000168 -:100BF000020D00C800000002020D00CC000000023F -:100C0000020D010800000001020D015C000000015E -:100C1000020D016400000001020D016800000002E5 -:100C2000020D020400000001020D020C0000002071 -:100C3000020D021000000040020D021400000040EE -:100C4000020D022000000003020D02240000001823 -:100C5000060D028000000012040D03000024024271 -:100C6000020D004C00000001020D005000000002C7 -:100C7000020D005400000008020D0058000000089A -:100C8000060D005C00000004020D00C4000000041A -:100C9000020D011400000009020D011800000029D6 -:100CA000020D011C0000000A020D01200000002AB4 -:100CB000020D012400000007020D0128000000279A -:100CC000020D012C00000007020D0130000000277A -:100CD000020D01340000000C020D01380000002C50 -:100CE000020D013C0000000C020D01400000002C30 -:100CF000020D01440000000C020D01480000002C10 -:100D0000020D000400000001020D000800000001B7 -:100D1000020D000C00000001020D00100000000197 -:100D2000020D001400000001020D00180000000177 -:100D3000020D001C00000001020D00200000000157 -:100D4000020D002400000001020D00280000000137 -:100D5000020D002C00000001020D00300000000117 -:100D6000020D003400000001020D003800000001F7 -:100D7000020D003C00000001020E004C0000003299 -:100D8000020E009402150020020E009802150020A9 -:100D9000020E009C00000030020E00A008100000AF -:100DA000020E00A400000033020E00A80000003074 -:100DB000020E00AC00000031020E00B00000000284 -:100DC000020E00B400000004020E00B80000000093 -:100DD000020E00BC00000002020E00C00000000273 -:100DE000020E00C400000000020E00C80000000255 -:100DF000020E00CC00000007020E00D0000000022E -:100E0000020E00D400000002020E00D80000000113 -:100E1000020E00E400000001020E01440000000187 -:100E2000020E014C00000001020E01500000000201 -:100E3000020E020400000001020E020C000000403D -:100E4000020E021000000040020E021C000000040E -:100E5000020E022000000020020E02240000000EFC -:100E6000020E02280000001B060E03000000001204 -:100E7000040E0280001B0266020E005400000010E7 -:100E8000020E005800000007020E005C0000000F78 -:100E9000020E006000000010060E00640000000456 -:100EA000020E00DC00000003020E01100000000F23 -:100EB000020E01140000002F020E01180000000EA7 -:100EC000020E011C0000002E020E000400000001B2 -:100ED000020E000800000001020E000C00000001DC -:100EE000020E001000000001020E001400000001BC -:100EF000020E001800000001020E001C000000019C -:100F0000020E002000000001020E0024000000017B -:100F1000020E002800000001020E002C000000015B -:100F2000020E003000000001020E0034000000013B -:100F3000020E003800000001020E003C000000011B -:100F4000020E004000000001020E004400000001FB -:100F50000730040000C30000083007680013028156 -:100F600007340000314C00000734800035EF0C548A -:100F700007350000361319D00735800007112755B3 -:100F800008358EE04E24028301300000000000008E -:100F900001300004000000000130000800000000E3 -:100FA0000130000C000000000130001000000000C3 -:100FB0000130001400000000023000200000000199 -:100FC000023000240000000202300028000000036C -:100FD0000230002C0000000002300030000000044D -:100FE0000230003400000001023000380000000030 -:100FF0000230003C0000000102300040000000040C -:1010000002300044000000000230004800000001EF -:101010000230004C000000030230005000000000CD -:1010200002300054000000010230005800000004AB -:101030000230005C0000000002300060000000018F -:10104000023000640000000302300068000000006D -:101050000230006C0000000102300070000000044B -:10106000023000740000000002300078000000042C -:101070000230007C00000003063000800000000207 -:10108000023000A400003FFF023000A8000003FF70 -:101090000230022400000000023002340000000090 -:1010A0000230024C00000000023002E40000FFFFAA -:1010B000063020000000080002338BC00000000151 -:1010C000023380000000001A023380400000004E0E -:1010D0000233808000000010023380C00000002036 -:1010E0000C3383000007A1200A338300000001387D -:1010F0000B33830000001388023383C0000001F427 -:101100000C3383801DCD65000A3383800004C4B492 -:101110000B338380004C4B4006325000000000C26D -:1011200006321020000000C8063210000000000245 -:101130000632464000000040063257F0000000042E -:10114000063257D800000005043257EC0001028532 -:1011500006321C60000000200432283000020286A3 -:10116000023308000100000004330C000010028864 -:10117000023308000000000004330C400010029805 -:1011800006321400000000A0063219000000001012 -:10119000063219800000003006324740000000B4DB -:1011A00002321D900000000006321B4000000004C7 -:1011B00006321B6000000020063253180000009821 -:1011C00006321680000000A0063219400000001010 -:1011D00006321A400000003006324A10000000B407 -:1011E00002321D940000000006321B500000000473 -:1011F00006321BE0000000200632557800000098FF -:10120000072004000071000008200780001002A8D9 -:1012100007240000322900000724800023630C8B80 -:101220000824C930654002AA012000000000000027 -:101230000120000400000000012000080000000060 -:101240000120000C00000000012000100000000040 -:101250000120001400000000022000200000000116 -:1012600002200024000000020220002800000003E9 -:101270000220002C000000000220003000000004CA -:1012800002200034000000010220003800000000AD -:101290000220003C00000001022000400000000489 -:1012A000022000440000000002200048000000016D -:1012B0000220004C0000000302200050000000004B -:1012C0000220005400000001022000580000000429 -:1012D0000220005C0000000002200060000000010D -:1012E00002200064000000030220006800000000EB -:1012F0000220006C000000010220007000000004C9 -:1013000002200074000000000220007800000004A9 -:101310000220007C00000003062000800000000284 -:10132000022000A400003FFF022000A8000003FFED -:10133000022002240000000002200234000000000D -:101340000220024C00000000022002E40000FFFF27 -:10135000062020000000080002238BC000000001CE -:1013600002238000000000100223804000000012D1 -:101370000223808000000030022380C00000000EA5 -:10138000022383C0000001F4062250000000004246 -:1013900006221020000000C80622100000000002F3 -:1013A00006222000000000C00622307000000080ED -:1013B0000622428000000004062225C000000240F0 -:1013C00004222EC8000802AC02230800013FFFFFE0 -:1013D00004230C00001002B40223080000000000E7 -:1013E00004230C40001002C406221400000000A0D8 -:1013F00006221900000000100622198000000030AB -:101400000222511800000000062223000000000EF6 -:1014100006223040000000060622241000000030A2 -:1014200006221680000000A00622194000000010CD -:1014300006221A40000000300222511C0000000069 -:10144000062223380000000E062230580000000655 -:10145000062224D0000000300216100000000020F8 -:1014600002170008000000020217002C0000000311 -:101470000217003C000000040217004400000008AE -:1014800002170048000000020217004C0000009004 -:1014900002170050000000900217005400800090D6 -:1014A0000217005808140000021700600000008AAC -:1014B000021700640000008002170068000000901E -:1014C0000217006C00000080021700700000000688 -:1014D00002170078000007D00217007C0000076C9C -:1014E00002170038007C1004021700040000000FEF -:1014F0000616402400000002021640700000001C86 -:10150000021642080000000102164210000000010D -:1015100002164220000000010216422800000001CD -:10152000021642300000000102164238000000019D -:1015300002164260000000010C16401C0003D0900F -:101540000A16401C0000009C0B16401C000009C439 -:101550000216403000000008021640340000000C63 -:10156000021640380000001002164044000000201F -:101570000216400000000001021640D800000001E1 -:1015800002164008000000010216400C0000000195 -:101590000216401000000001021642400000000048 -:1015A00002164248000000000616427000000002C9 -:1015B00002164250000000000216425800000000CF -:1015C00006164280000000020216600800000614A1 -:1015D0000216600C000006000216601000000604EF -:1015E0000216601C0000FFFF021660200000FFFFD3 -:1015F000021660240000FFFF021660280000FFFFB3 -:1016000002166038000000200216603C0000002036 -:1016100002166040000000340216604400000035ED -:1016200002166048000000230216604C00000024EF -:1016300002166050000000250216605400000026CB -:1016400002166058000000270216605C00000029A6 -:10165000021660600000002A021660640000002B81 -:10166000021660680000002C0216606C0000002D5D -:101670000616607000000052021661B800000001FA -:10168000061661BC0000001F0216623807FFFFFF4C -:101690000216623C0000003F0216624007FFFFFF97 -:1016A000021662440000000F0116624800000000AC -:1016B0000116624C0000000001166250000000009C -:1016C000011662540000000001166258000000007C -:1016D0000116625C0000000001166260000000005C -:1016E000011662640000000001166268000000003C -:1016F0000116626C0000000001166270000000001C -:1017000001166274000000000116627800000000FB -:101710000116627C00000000021664BC000000019B -:101720000C166000000003E80A16600000000001CB -:101730000B1660000000000A021680400000000640 -:101740000216804400000005021680480000000ACE -:101750000216804C000000050216805400000002B2 -:10176000021680CC00000004021680D000000004A5 -:10177000021680D400000004021680D80000000485 -:10178000021680DC00000004021680E00000000465 -:10179000021680E400000004021680E80000000445 -:1017A0000216880400000004021680300000007C4D -:1017B000021680340000003D021680380000003F11 -:1017C0000216803C0000009C021680F0000000071A -:1017D000061680F4000000050216880C01010101C4 -:1017E00002168108000000000216810C00000004AF -:1017F000021681100000000402168114000000028D -:101800000216881008012004021681180000000545 -:101810000216811C00000005021681200000000550 -:1018200002168124000000050216882C20081001F1 -:1018300002168128000000080216812C0000000614 -:1018400002168130000000070216813400000000FB -:1018500002168830010101200616813800000004BC -:1018600002168834010101010616814800000004B7 -:101870000216883801010101061681580000000493 -:101880000216883C01010101061681680000000370 -:101890000216817400000001021688400101010156 -:1018A00002168178000000010216817C0000000110 -:1018B00002168180000000010216818400000001F0 -:1018C000021688440101010102168188000000010E -:1018D0000216818C000000040216819000000004B2 -:1018E00002168194000000020216884808012004B4 -:1018F00002168198000000050216819C0000000578 -:10190000021681A000000005021681A40000000557 -:101910000216881420081001021681A80000000891 -:10192000021681AC00000006021681B0000000071C -:10193000021681B40000000102168818010101207E -:10194000021681B800000001021681BC00000001EF -:10195000021681C000000001021681C400000001CF -:101960000216881C01010101021681C80000000155 -:10197000021681CC00000001021681D00000000197 -:10198000021681D400000001021688200101010125 -:10199000021681D800000001021681DC000000015F -:1019A000021681E000000001021681E4000000013F -:1019B0000216882401010101021681E800000001DD -:1019C000021681EC00000001021681F00000000107 -:1019D000021688280101010102168240FFFF003F24 -:1019E00006168244000000020216824CFFFF003FF0 -:1019F000021682500000010002168254000001000D -:101A0000061682580000000202168260000000C024 -:101A100002168264000000C00216826800001E00E8 -:101A20000216826C00001E00021682700000400048 -:101A300002168274000040000216827800008000C6 -:101A40000216827C000080000216828000002000C6 -:101A5000021682840000200006168288000000071B -:101A6000021682A400000001061682A80000000AE7 -:101A7000021681F400000C08021681F800000040F4 -:101A8000021681FC00000100021682000000002006 -:101A9000021682040000001702168208000000806F -:101AA0000216820C000002000216821000000000E4 -:101AB00002168218FFFF01FF02168214FFFF01FFCA -:101AC0000216823C00000013021680900000013FC5 -:101AD0000216806000000140021680640000014090 -:101AE000061680680000000202168070000000C028 -:101AF00006168074000000070216809C0000004853 -:101B0000021680A000000048061680A40000000213 -:101B1000021680AC00000048061680B000000007E6 -:101B2000021682380000800002168234000025E48C -:101B30000216809400007FFF02168220000000073A -:101B40000216821C00000007021682280000000016 -:101B500002168224FFFFFFFF021682300000000001 -:101B60000216822CFFFFFFFF021680EC000000FF30 -:101B700002140000000000010214000C000000012B -:101B800002140040000000010214004400007FFF26 -:101B90000214000C0000000002140000000000000D -:101BA0000214006C00000000021400040000000198 -:101BB00002140030000000010214000400000000C4 -:101BC0000214005C00000000021400080000000184 -:101BD000021400340000000102140008000000009C -:101BE00002140060000000000202005800000032F1 -:101BF000020200A003150020020200A40315002029 -:101C0000020200A801000030020200AC081000002F -:101C1000020200B000000033020200B400000030F5 -:101C2000020200B800000031020200BC0000000304 -:101C3000020200C000000006020200C4000000030F -:101C4000020200C800000003020200CC00000002F3 -:101C5000020200D000000000020200D400000002D6 -:101C6000020200DC00000000020200E000000006AA -:101C7000020200E400000004020200E8000000028A -:101C8000020200EC00000002020200F0000000016D -:101C9000020200FC00000006020201200000000019 -:101CA0000202013400000002020201B00000000143 -:101CB0000202020C000000010202021400000001F6 -:101CC00002020218000000020202040400000001E7 -:101CD0000202040C00000040020204100000004058 -:101CE0000202041C00000004020204200000002084 -:101CF0000202042400000002020204280000001F67 -:101D0000060205000000001204020480001F02D435 -:101D1000020200600000000F0202006400000007E1 -:101D2000020200680000000B0202006C0000000EBE -:101D30000602007000000004020200F4000000042B -:101D4000020200040000000102020008000000017D -:101D50000202000C0000000102020010000000015D -:101D6000020200140000000102020018000000013D -:101D70000202001C0000000102020020000000011D -:101D800002020024000000010202002800000001FD -:101D90000202002C000000010202003000000001DD -:101DA00002020034000000010202003800000001BD -:101DB0000202003C0000000102020040000000019D -:101DC000020200440000000102020048000000017D -:101DD0000202004C0000000102020050000000015D -:101DE00002020108000000C80202011800000002FF -:101DF000020201C400000000020201CC0000000049 -:101E0000020201D400000002020201DC0000000214 -:101E1000020201E4000000FF020201EC000000FFEA -:101E20000202010C000000C80202011C00000002B6 -:101E3000020201C800000000020201D00000000000 -:101E4000020201D800000002020201E000000002CC -:101E5000020201E8000000FF020201F0000000FFA2 -:101E60000728040000B5000008280768001302F3E3 -:101E7000072C000033660000072C800038B30CDA12 -:101E8000072D00003BB11B07072D80002A2629F4EF -:101E9000082DD6C0452802F50128000000000000EA -:101EA00001280004000000000128000800000000D4 -:101EB0000128000C000000000128001000000000B4 -:101EC000012800140000000002280020000000018A -:101ED000022800240000000202280028000000035D -:101EE0000228002C0000000002280030000000043E -:101EF0000228003400000001022800380000000021 -:101F00000228003C000000010228004000000004FC -:101F100002280044000000000228004800000001E0 -:101F20000228004C000000030228005000000000BE -:101F3000022800540000000102280058000000049C -:101F40000228005C00000000022800600000000180 -:101F5000022800640000000302280068000000005E -:101F60000228006C0000000102280070000000043C -:101F7000022800740000000002280078000000041D -:101F80000228007C000000030628008000000002F8 -:101F9000022800A400003FFF022800A8000003FF61 -:101FA0000228022400000000022802340000000081 -:101FB0000228024C00000000022802E40000FFFF9B -:101FC0000628200000000800022B8BC00000000142 -:101FD000022B800000000000022B8040000000184F -:101FE000022B80800000000C022B80C000000066E5 -:101FF0000C2B83000007A1200A2B8300000001386E -:102000000B2B830000001388022B83C0000001F417 -:102010000C2B8340000001F40A2B834000000000D9 -:102020000B2B8340000000050A2B83800004C4B4FE -:102030000C2B83801DCD65000B2B8380004C4B4007 -:10204000062A3D6000000004042A3D70000202F7E9 -:10205000062A300000000048062A1020000000C8B0 -:10206000062A100000000002062A31280000008E17 -:10207000022A336800000000042A3370000202F9CB -:10208000042A3B90000402FB042A3E20000202FFC7 -:10209000022A151800000001022A18300000000072 -:1020A000022A183800000000042A18200002030148 -:1020B000062A4AC000000002062A4B000000000465 -:1020C000042A1F4800020303022B0800000000003E -:1020D000042B0C0000100305022B08000100000077 -:1020E000042B0C4000080315022B0800020000001E -:1020F000042B0C600008031D062A3BA000000014FE -:10210000062A3C4000000024062A14000000000AB1 -:10211000062A145000000006062A3378000000FC4E -:10212000022A3B5800000000042A3D7800020325E3 -:10213000042A3D8800100327022A15000000000031 -:10214000022A150800000001062A502000000002A3 -:10215000062A503000000002062A5000000000024B -:10216000062A501000000002022A50400000000021 -:10217000062A50480000000E022A50B80000000154 -:10218000042A4AC800020337062A4B100000004206 -:10219000062A4D2000000004062A3BF0000000142F -:1021A000062A3CD000000024062A14280000000A59 -:1021B000062A146800000006062A3768000000FCA2 -:1021C000022A3B5C00000000042A3D800002033923 -:1021D000042A3DC80010033B022A15040000000039 -:1021E000022A150C00000001062A502800000002F7 -:1021F000062A503800000002062A5008000000029B -:10220000062A501800000002022A50440000000074 -:10221000062A50800000000E022A50BC0000000177 -:10222000042A4AD00002034B062A4C180000004240 -:10223000062A4D30000000040210100800000001C2 -:10224000021010000003D000021010040000003D36 -:10225000091018000200034D091011000020054D5F -:102260000610118000000002091011880006056D9B -:10227000061011A00000001806102400000000E065 -:102280000210201C000000000210202000000001AD -:10229000021020C000000001021020040000000114 -:1022A000021020080000000109103C000005057321 -:1022B00009103C2000050578091038000005057D4F -:1022C00002104028000000100210404400003FFFB0 -:1022D0000210405800280000021040840084924AF6 -:1022E0000210405800000000061080680000000442 -:1022F00002108000000010800610802800000002FC -:102300000210803800000010021080400000FFFF23 -:10231000021080440000FFFF021080500000000007 -:102320000210810000000000061081200000000261 -:1023300002108008000002B50210801000000000AA -:10234000061082000000004A021081080001FFFF11 -:1023500006108140000000020210800000001A8078 -:102360000610900000000024061091200000004A92 -:10237000061093700000004A061095C00000004A45 -:10238000021080040000108006108030000000025F -:102390000210803C00000010021080480000FFFF87 -:1023A0000210804C0000FFFF02108054000000006B -:1023B00002108104000000000610812800000002C5 -:1023C0000210800C000002B5021080140000000012 -:1023D000061084000000004A0210810C0001FFFF7B -:1023E00006108148000000020210800400001A80DC -:1023F0000610909000000024061092480000004A49 -:10240000061094980000004A061096E80000004A62 -:102410000212049000E383400212051400003C10F5 -:1024200002120494FFFFFFFF02120498FFFFFFFF58 -:102430000212049CFFFFFFFF021204A0FFFFFFFF38 -:10244000021204A4FFFFFFFF021204A8FFFFFFFF18 -:10245000021204ACFFFFFFFF021204B0FFFFFFFFF8 -:10246000021204B8FFFFFFFF021204BCFFFFFFFFD0 -:10247000021204C0FFFFFFFF021204C4FFFFFFFFB0 -:10248000021204C8FFFFFFFF021204CCFFFFFFFF90 -:10249000021204D0FFFFFFFF021204DCFFFFFFFF68 -:1024A000021204E0FFFFFFFF021204E4FFFFFFFF40 -:1024B000021204E8FFFFFFFF021204ECFFFFFFFF20 -:1024C000021204F0FFFFFFFF021204F4FFFFFFFF00 -:1024D000021204F8FFFFFFFF021204FCFFFFFFFFE0 -:1024E00002120500FFFFFFFF02120504FFFFFFFFBE -:1024F00002120508FFFFFFFF0212050CFFFFFFFF9E -:1025000002120510FFFFFFFF021204D4FFFF333059 -:10251000021204D8FFFF3340021204B4F00030006E -:1025200002120390000000080212039C0000000841 -:10253000021203A000000008021203A4000000021F -:10254000021203BC00000004021203C000000005D8 -:10255000021203C400000004021203D000000000B5 -:102560000212036C00000001021203680000003F29 -:10257000021201BC00000040021201C00000180855 -:10258000021201C400000803021201C8000008037F -:10259000021201CC00000040021201D00000000332 -:1025A000021201D400000803021201D8000008033F -:1025B000021201DC00000803021201E00001000326 -:1025C000021201E400000803021201E800000803FF -:1025D000021201EC00000003021201F000000003EF -:1025E000021201F400000003021201F800000003CF -:1025F000021201FC000000030212020000000003AE -:10260000021202040000000302120208000000038C -:102610000212020C0000000302120210000000036C -:10262000021202140000000302120218000000034C -:102630000212021C0000000302120220000000032C -:1026400002120224000000030212022800002403E8 -:102650000212022C0000002F0212023000000009BA -:102660000212023400000019021202380000018434 -:102670000212023C00000183021202400000030625 -:102680000212024400000019021202480000000673 -:102690000212024C00000306021202500000030660 -:1026A00002120254000003060212025800000C86B7 -:1026B0000212025C00000306021202600000030620 -:1026C0000212026400000006021202680000000606 -:1026D0000212026C000000060212027000000006E6 -:1026E00002120274000000060212027800000006C6 -:1026F0000212027C000000060212028000000006A6 -:102700000212028400000006021202880000000685 -:102710000212028C00000006021202900000000665 -:102720000212029400000006021202980000000645 -:102730000212029C00000006021202A00000030622 -:10274000021202A400000013021202A800000006F8 -:10275000021202B000001004021202B400001004C1 -:102760000212032400106440021203280010644087 -:10277000021201B0000000010600A00000000016D7 -:102780000200A06CBF5C00000200A070FFF51FEF0C -:102790000200A0740000FFFF0200A078500003E0D8 -:1027A0000200A07C000000000200A0800000A00049 -:1027B0000600A084000000050200A0980FE00000C1 -:1027C0000600A09C000000140200A0EC555400007C -:1027D0000200A0F0555555550200A0F400005555D3 -:1027E0000200A0F8000000000200A0FC5554000008 -:1027F0000200A100555555550200A1040000555591 -:102800000200A108000000000200A22C000000004D -:102810000600A230000000030200A06000000007D4 -:102820000200A10CBF5C00000200A110FFF51FEF29 -:102830000200A1140000FFFF0200A118500003E0F5 -:102840000200A11C000000000200A1200000A00066 -:102850000600A124000000050200A1380FE00000DE -:102860000600A13C000000140200A18C5554000099 -:102870000200A190555555550200A19400005555F0 -:102880000200A198000000000200A19C5554000025 -:102890000200A1A0555555550200A1A400005555B0 -:1028A0000200A1A8000000000200A23C00000000FD -:1028B0000600A240000000030200A0640000000720 -:1028C00000000000000000000000002E00000000DA -:1028D00000000000000000000000000000000000F8 -:1028E00000000000000000000000000000000000E8 -:1028F00000000000000000000000000000000000D8 -:1029000000000000000000000000000000000000C7 -:1029100000000000000000000000000000000000B7 -:10292000002E005000000000000000000000000029 -:102930000000000000000000000000000000000097 -:102940000000000000000000000000000050008DAA -:102950000000000000000000000000000000000077 -:102960000000000000000000000000000000000067 -:102970000000000000000000008D00920092009610 -:102980000096009A00000000000000000000000017 -:102990000000000000000000000000000000000037 -:1029A00000000000009A00DB00DB00E900E900F70E -:1029B0000000000000000000000000000000000017 -:1029C0000000000000000000000000000000000007 -:1029D00000000000000000000000000000000000F7 -:1029E00000000000000000000000000000000000E7 -:1029F00000000000000000000000000000000000D7 -:102A000000000000000000000000000000000000C6 -:102A100000000000000000000000000000000000B6 -:102A200000000000000000000000000000000000A6 -:102A30000000000000000000000000000000000096 -:102A40000000000000000000000000000000000086 -:102A50000000000000000000000000000000000076 -:102A60000000000000000000000000000000000066 -:102A70000000000000000000000000000000000056 -:102A800000F700FE00000000000000000000000051 -:102A90000000000000000000000000000000000036 -:102AA0000000000000000000000000000000000026 -:102AB0000000000000000000000000000000000016 -:102AC0000000000000000000000000000000000006 -:102AD000000000000000000000FE01030103010EE1 -:102AE000010E0119000000000000000000000000BD -:102AF00000000000000000000000000000000000D6 -:102B000000000000000000000000000000000000C5 -:102B100000000000000000000000000000000000B5 -:102B200000000000000000000000000000000000A5 -:102B30000119011A00000000000000000000000060 -:102B40000000000000000000000000000000000085 -:102B5000000000000000000000000000011A013E1B -:102B60000000000000000000000000000000000065 -:102B70000000000000000000000000000000000055 -:102B80000000000000000000013E016400000000A1 -:102B90000000000000000000000000000000000035 -:102BA0000000000000000000000000000000000025 -:102BB00000000000016401A300000000000000000C -:102BC0000000000000000000000000000000000005 -:102BD00000000000000000000000000000000000F5 -:102BE00001A301DE00000000000000000000000062 -:102BF00000000000000000000000000000000000D5 -:102C000000000000000000000000000001DE0224BF -:102C10000224022C022C02340000000000000000FC -:102C200000000000000000000000000000000000A4 -:102C300000000000000000000234027102710278FE -:102C40000278027F00000000000000000000000089 -:102C50000000000000000000000000000000000074 -:102C600000000000027F0280000000000000000061 -:102C70000000000000000000000000000000000054 -:102C80000000000000000000000000000000000044 -:102C9000028002920000000000000000000000001E -:102CA0000000000000000000000000000000000024 -:102CB000000000000000000000000000029202A7D7 -:102CC00002A702AA02AA02AD000000000000000054 -:102CD00000000000000000000000000000000000F4 -:102CE000000000000000000002AD02DB0000000058 -:102CF00000000000000000000000000000000000D4 -:102D000000000000000000000000000000000000C3 -:102D10000000000002DB0362000000000000000071 -:102D200000000000000000000000000000000000A3 -:102D30000000000000000000000000000000000093 -:102D4000036203690369036D036D037100000000F2 -:102D50000000000000000000000000000000000073 -:102D6000000000000000000000000000037103B03C -:102D700003B003B803B803C0000000000000000067 -:102D80000000000000000000000000000000000043 -:102D9000000000000000000003C004130413042717 -:102DA0000427043B000000000000000000000000B9 -:102DB0000000000000000000000000000000000013 -:102DC00000000000043B044300000000000000007D -:102DD00000000000000000000000000000000000F3 -:102DE00000000000000000000000000000000000E3 -:102DF000044304490000000000000000000000003F -:102E000000000000000000000000000000000000C2 -:102E10000000000000000000000000000449044C15 -:102E200000000000000000000000000000000000A2 -:102E30000000000000000000000000000000000092 -:102E40000000000000000000044C045100000000DD -:102E50000000000000000000000000000000000072 -:102E60000000000000000000000000000000000062 -:102E70000000000004510452045204640464047607 -:102E80000000000000000000000000000000000042 -:102E90000000000000000000000000000000000032 -:102EA000047604E3000000000000000000000000C1 -:102EB0000000000000000000000000000000000012 -:102EC00000000000000000000000000004E304E433 -:102ED00004E404F804F8050C000000000000000001 -:102EE00000000000000000000000000000000000E2 -:102EF00000000000000000000000000000000000D2 -:102F000000010000000204C00003098000040E401C -:102F100000051300000617C000071C8000082140B0 -:102F200000092600000A2AC0000B2F80000C344044 -:102F3000000D3900000E3DC0000F428000104740D8 -:102F400000114C00001250C00013558000145A406C -:102F500000155F00001663C00017688000186D4000 -:102F600000197200001A76C0001B7B80001C804094 -:102F7000001D8500001E89C0001F8E800020934028 -:102F80000000200000004000000060000000800001 -:102F90000000A0000000C0000000E00000010000F0 -:102FA00000012000000140000001600000018000DD -:102FB0000001A0000001C0000001E00000020000CC -:102FC00000022000000240000002600000028000B9 -:102FD0000002A0000002C0000002E00000030000A8 -:102FE0000003200000034000000360000003800095 -:102FF0000003A0000003C0000003E0000004000084 -:103000000004200000044000000460000004800070 -:103010000004A0000004C0000004E000000500005F -:10302000000520000005400000056000000580004C -:103030000005A0000005C0000005E000000600003B -:103040000006200000064000000660000006800028 -:103050000006A0000006C0000006E0000007000017 -:103060000007200000074000000760000007800004 -:103070000007A0000007C0000007E00000080000F3 -:1030800000082000000840000008600000088000E0 -:103090000008A0000008C0000008E00000090000CF -:1030A00000092000000940000009600000098000BC -:1030B0000009A0000009C0000009E000000A0000AB -:1030C000000A2000000A4000000A6000000A800098 -:1030D000000AA000000AC000000AE000000B000087 -:1030E000000B2000000B4000000B6000000B800074 -:1030F000000BA000000BC000000BE000000C000063 -:10310000000C2000000C4000000C6000000C80004F -:10311000000CA000000CC000000CE000000D00003E -:10312000000D2000000D4000000D6000000D80002B -:10313000000DA000000DC000000DE000000E00001A -:10314000000E2000000E4000000E6000000E800007 -:10315000000EA000000EC000000EE000000F0000F6 -:10316000000F2000000F4000000F6000000F8000E3 -:10317000000FA000000FC000000FE00000100000D2 -:1031800000102000001040000010600000108000BF -:103190000010A0000010C0000010E00000110000AE -:1031A000001120000011400000116000001180009B -:1031B0000011A0000011C0000011E000001200008A -:1031C0000012200000124000001260000012800077 -:1031D0000012A0000012C0000012E0000013000066 -:1031E0000013200000134000001360000013800053 -:1031F0000013A0000013C0000013E0000014000042 -:10320000001420000014400000146000001480002E -:103210000014A0000014C0000014E000001500001D -:10322000001520000015400000156000001580000A -:103230000015A0000015C0000015E00000160000F9 -:1032400000162000001640000016600000168000E6 -:103250000016A0000016C0000016E00000170000D5 -:1032600000172000001740000017600000178000C2 -:103270000017A0000017C0000017E00000180000B1 -:10328000001820000018400000186000001880009E -:103290000018A0000018C0000018E000001900008D -:1032A000001920000019400000196000001980007A -:1032B0000019A0000019C0000019E000001A000069 -:1032C000001A2000001A4000001A6000001A800056 -:1032D000001AA000001AC000001AE000001B000045 -:1032E000001B2000001B4000001B6000001B800032 -:1032F000001BA000001BC000001BE000001C000021 -:10330000001C2000001C4000001C6000001C80000D -:10331000001CA000001CC000001CE000001D0000FC -:10332000001D2000001D4000001D6000001D8000E9 -:10333000001DA000001DC000001DE000001E0000D8 -:10334000001E2000001E4000001E6000001E8000C5 -:10335000001EA000001EC000001EE000001F0000B4 -:10336000001F2000001F4000001F6000001F8000A1 -:10337000001FA000001FC000001FE0000020000090 -:10338000002020000020400000206000002080007D -:103390000020A0000020C0000020E000002100006C -:1033A0000021200000214000002160000021800059 -:1033B0000021A0000021C0000021E0000022000048 -:1033C0000022200000224000002260000022800035 -:1033D0000022A0000022C0000022E0000023000024 -:1033E0000023200000234000002360000023800011 -:1033F0000023A0000023C0000023E0000024000000 -:1034000000242000002440000024600000248000EC -:103410000024A0000024C0000024E00000250000DB -:1034200000252000002540000025600000258000C8 -:103430000025A0000025C0000025E00000260000B7 -:1034400000262000002640000026600000268000A4 -:103450000026A0000026C0000026E0000027000093 -:103460000027200000274000002760000027800080 -:103470000027A0000027C0000027E000002800006F -:10348000002820000028400000286000002880005C -:103490000028A0000028C0000028E000002900004B -:1034A0000029200000294000002960000029800038 -:1034B0000029A0000029C0000029E000002A000027 -:1034C000002A2000002A4000002A6000002A800014 -:1034D000002AA000002AC000002AE000002B000003 -:1034E000002B2000002B4000002B6000002B8000F0 -:1034F000002BA000002BC000002BE000002C0000DF -:10350000002C2000002C4000002C6000002C8000CB -:10351000002CA000002CC000002CE000002D0000BA -:10352000002D2000002D4000002D6000002D8000A7 -:10353000002DA000002DC000002DE000002E000096 -:10354000002E2000002E4000002E6000002E800083 -:10355000002EA000002EC000002EE000002F000072 -:10356000002F2000002F4000002F6000002F80005F -:10357000002FA000002FC000002FE000003000004E -:10358000003020000030400000306000003080003B -:103590000030A0000030C0000030E000003100002A -:1035A0000031200000314000003160000031800017 -:1035B0000031A0000031C0000031E0000032000006 -:1035C00000322000003240000032600000328000F3 -:1035D0000032A0000032C0000032E00000330000E2 -:1035E00000332000003340000033600000338000CF -:1035F0000033A0000033C0000033E00000340000BE -:1036000000342000003440000034600000348000AA -:103610000034A0000034C0000034E0000035000099 -:103620000035200000354000003560000035800086 -:103630000035A0000035C0000035E0000036000075 -:103640000036200000364000003660000036800062 -:103650000036A0000036C0000036E0000037000051 -:10366000003720000037400000376000003780003E -:103670000037A0000037C0000037E000003800002D -:10368000003820000038400000386000003880001A -:103690000038A0000038C0000038E0000039000009 -:1036A00000392000003940000039600000398000F6 -:1036B0000039A0000039C0000039E000003A0000E5 -:1036C000003A2000003A4000003A6000003A8000D2 -:1036D000003AA000003AC000003AE000003B0000C1 -:1036E000003B2000003B4000003B6000003B8000AE -:1036F000003BA000003BC000003BE000003C00009D -:10370000003C2000003C4000003C6000003C800089 -:10371000003CA000003CC000003CE000003D000078 -:10372000003D2000003D4000003D6000003D800065 -:10373000003DA000003DC000003DE000003E000054 -:10374000003E2000003E4000003E6000003E800041 -:10375000003EA000003EC000003EE000003F000030 -:10376000003F2000003F4000003F6000003F80001D -:10377000003FA000003FC000003FE000003FE0012C -:1037800000000000000001FF0000020000007FF8C0 -:1037900000007FF8000002920000350000000001E8 -:1037A0000000000300BEBC200000000300BEBC20DF -:1037B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 -:1037C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 -:1037D000FFFFFFFF00000000FFFFFFFF00000000F1 -:1037E000FFFFFFFF0000000300BEBC20FFFFFFFF44 -:1037F00000000000FFFFFFFF00000000FFFFFFFFD1 -:103800000000000300BEBC2000002000000040C0FB -:1038100000006180000082400000A3000000C3C0DF -:103820000000E4800001054000012600000146C0C0 -:1038300000016780000188400001A9000001C9C0A3 -:103840000001EA8000020B4000022C0000024CC084 -:1038500000026D8000028E400002AF000002CFC067 -:103860000002F0800003114000033200000352C048 -:1038700000037380000394400003B5000003D5C02B -:103880000003F6800004174000043800000458C00C -:103890000004798000049A40000080000001038049 -:1038A0000001870000020A8000028E0000031180E0 -:1038B000000395000004188000049C0000051F8090 -:1038C0000005A300000626800006AA0000072D8040 -:1038D0000007B100000834800008B80000093B80F0 -:1038E0000009BF00000A4280000AC600000B4980A0 -:1038F000000BCD00000C5080000CD400000D578050 -:10390000000DDB0000007FF800007FF8000003E5F9 -:10391000000015000000190000000000FFFFFFFF7D -:103920004000000040000000400000004000000097 -:103930004000000040000000400000004000000087 -:103940004000000040000000400000004000000077 -:103950004000000040000000400000004000000067 -:103960004000000040000000400000004000000057 -:103970004000000040000000400000004000000047 -:103980004000000040000000400000004000000037 -:103990004000000040000000400000004000000027 -:1039A00000007FF800007FF8000003C80000150049 -:1039B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 -:1039C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 -:1039D00040000000400000004000000040000000E7 -:1039E00040000000400000004000000040000000D7 -:1039F00040000000400000004000000040000000C7 -:103A000040000000400000004000000040000000B6 -:103A100040000000400000004000000040000000A6 -:103A20004000000040000000400000004000000096 -:103A30004000000040000000400000004000000086 -:103A40004000000040000000400000004000000076 -:103A500000001000000020800000310000004180C4 -:103A600000005200000062800000730000008380AC -:103A7000000094000000A4800000B5000000C58094 -:103A80000000D6000000E6800000F700000107807B -:103A90000001180000012880000139000001498060 -:103AA00000015A0000016A8000017B0000018B8048 -:103AB00000019C000001AC800001BD000001CD8030 -:103AC0000001DE000001EE800001FF0000007FF831 -:103AD00000007FF800000207000035001000000021 -:103AE000000028AD000000000001000100350804BE -:103AF000CCCCCCC1FFFFFFFFFFFFFFFF7058103C95 -:103B000000000000CCCC0201CCCCCCCC00000000EA -:103B1000FFFFFFFF400000004000000040000000E9 -:103B20004000000040000000400000004000000095 -:103B30004000000040000000400000004000000085 -:103B40004000000040000000400000004000000075 -:103B50004000000040000000400000004000000065 -:103B60004000000040000000400000004000000055 -:103B70004000000040000000400000004000000045 -:103B80004000000040000000400000004000000035 -:103B900040000000000E01B7011600D60000FFFF34 -:103BA000000000000000FFFF000000000000FFFF19 -:103BB000000000000000FFFF000000000000FFFF09 -:103BC000000000000000FFFF000000000000FFFFF9 -:103BD000000000000000FFFF0000000000100000D7 -:103BE00000000000007201BB012300F30000FFFF92 -:103BF000000000000000FFFF000000000000FFFFC9 -:103C0000000000000000FFFF000000000000FFFFB8 -:103C1000000000000000FFFF000000000000FFFFA8 -:103C2000000000000000FFFF000000000010000086 -:103C300000000000FFFFFFF3320FFFFF0C30C30C4A -:103C4000C30C30C3CF3CF300F3CF3CF30000CF3CB8 -:103C5000CDCDCDCDFFFFFFF130EFFFFF0C30C30C1A -:103C6000C30C30C3CF3CF300F3CF3CF30001CF3C97 -:103C7000CDCDCDCDFFFFFFF6305FFFFF0C30C30C85 -:103C8000C30C30C3CF3CF300F3CF3CF30002CF3C76 -:103C9000CDCDCDCDFFFFF4061CBFFFFF0C30C3051B -:103CA000C30C30C3CF300014F3CF3CF30004CF3C3F -:103CB000CDCDCDCDFFFFFFF2304FFFFF0C30C30C59 -:103CC000C30C30C3CF3CF300F3CF3CF30008CF3C30 -:103CD000CDCDCDCDFFFFFFFA302FFFFF0C30C30C51 -:103CE000C30C30C3CF3CF300F3CF3CF30010CF3C08 -:103CF000CDCDCDCDFFFFFFF731EFFFFF0C30C30C73 -:103D0000C30C30C3CF3CF300F3CF3CF30020CF3CD7 -:103D1000CDCDCDCDFFFFFFF5302FFFFF0C30C30C15 -:103D2000C30C30C3CF3CF300F3CF3CF30040CF3C97 -:103D3000CDCDCDCDFFFFFFF3310FFFFF0C30C30C16 -:103D4000C30C30C3CF3CF300F3CF3CF30000CF3CB7 -:103D5000CDCDCDCDFFFFFFF1310FFFFF0C30C30CF8 -:103D6000C30C30C3CF3CF300F3CF3CF30001CF3C96 -:103D7000CDCDCDCDFFFFFFF6305FFFFF0C30C30C84 -:103D8000C30C30C3CF3CF300F3CF3CF30002CF3C75 -:103D9000CDCDCDCDFFFFF4061CBFFFFF0C30C3051A -:103DA000C30C30C3CF300014F3CF3CF30004CF3C3E -:103DB000CDCDCDCDFFFFFFF2304FFFFF0C30C30C58 -:103DC000C30C30C3CF3CF300F3CF3CF30008CF3C2F -:103DD000CDCDCDCDFFFFFFFA302FFFFF0C30C30C50 -:103DE000C30C30C3CF3CF300F3CF3CF30010CF3C07 -:103DF000CDCDCDCDFFFFFFF730EFFFFF0C30C30C73 -:103E0000C30C30C3CF3CF300F3CF3CF30020CF3CD6 -:103E1000CDCDCDCDFFFFFFF5304FFFFF0C30C30CF4 -:103E2000C30C30C3CF3CF300F3CF3CF30040CF3C96 -:103E3000CDCDCDCDFFFFFFF331EFFFFF0C30C30C35 -:103E4000C30C30C3CF3CF300F3CF3CF30000CF3CB6 -:103E5000CDCDCDCDFFFFFFF1310FFFFF0C30C30CF7 -:103E6000C30C30C3CF3CF300F3CF3CF30001CF3C95 -:103E7000CDCDCDCDFFFFFFF6305FFFFF0C30C30C83 -:103E8000C30C30C3CF3CF300F3CF3CF30002CF3C74 -:103E9000CDCDCDCDFFFFF4061CBFFFFF0C30C30519 -:103EA000C30C30C3CF300014F3CF3CF30004CF3C3D -:103EB000CDCDCDCDFFFFFFF2304FFFFF0C30C30C57 -:103EC000C30C30C3CF3CF300F3CF3CF30008CF3C2E -:103ED000CDCDCDCDFFFFFFFA302FFFFF0C30C30C4F -:103EE000C30C30C3CF3CF300F3CF3CF30010CF3C06 -:103EF000CDCDCDCDFFFFFF97056FFFFF0C30C30C7D -:103F0000C30C30C3CF3CC000F3CF3CF30020CF3C08 -:103F1000CDCDCDCDFFFFFFF5310FFFFF0C30C30C32 -:103F2000C30C30C3CF3CF300F3CF3CF30040CF3C95 -:103F3000CDCDCDCDFFFFFFF3320FFFFF0C30C30C13 -:103F4000C30C30C3CF3CF300F3CF3CF30000CF3CB5 -:103F5000CDCDCDCDFFFFFFF1310FFFFF0C30C30CF6 -:103F6000C30C30C3CF3CF300F3CF3CF30001CF3C94 -:103F7000CDCDCDCDFFFFFFF6305FFFFF0C30C30C82 -:103F8000C30C30C3CF3CF300F3CF3CF30002CF3C73 -:103F9000CDCDCDCDFFFFF4061CBFFFFF0C30C30518 -:103FA000C30C30C3CF300014F3CF3CF30004CF3C3C -:103FB000CDCDCDCDFFFFFFF2304FFFFF0C30C30C56 -:103FC000C30C30C3CF3CF300F3CF3CF30008CF3C2D -:103FD000CDCDCDCDFFFFFF8A042FFFFF0C30C30CEA -:103FE000C30C30C3CF3CC000F3CF3CF30010CF3C38 -:103FF000CDCDCDCDFFFFFF9705CFFFFF0C30C30C1C -:10400000C30C30C3CF3CC000F3CF3CF30020CF3C07 -:10401000CDCDCDCDFFFFFFF5310FFFFF0C30C30C31 -:10402000C30C30C3CF3CF300F3CF3CF30040CF3C94 -:10403000CDCDCDCDFFFFFFF3300FFFFF0C30C30C14 -:10404000C30C30C3CF3CF300F3CF3CF30000CF3CB4 -:10405000CDCDCDCDFFFFFFF1300FFFFF0C30C30CF6 -:10406000C30C30C3CF3CF300F3CF3CF30001CF3C93 -:10407000CDCDCDCDFFFFFFF6305FFFFF0C30C30C81 -:10408000C30C30C3CF3CF300F3CF3CF30002CF3C72 -:10409000CDCDCDCDFFFFF4061CBFFFFF0C30C30517 -:1040A000C30C30C3CF300014F3CF3CF30004CF3C3B -:1040B000CDCDCDCDFFFFFFF2304FFFFF0C30C30C55 -:1040C000C30C30C3CF3CF300F3CF3CF30008CF3C2C -:1040D000CDCDCDCDFFFFFFFA302FFFFF0C30C30C4D -:1040E000C30C30C3CF3CF300F3CF3CF30010CF3C04 -:1040F000CDCDCDCDFFFFFF97040FFFFF0C30C30CDC -:10410000C30C30C3CF3CC000F3CF3CF30020CF3C06 -:10411000CDCDCDCDFFFFFFF5300FFFFF0C30C30C31 -:10412000C30C30C3CF3CF300F3CF3CF30040CF3C93 -:10413000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C47 -:10414000C30C30C3CF3CF3CCF3CF3CF30000CF3CE7 -:10415000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C27 -:10416000C30C30C3CF3CF3CCF3CF3CF30001CF3CC6 -:10417000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C07 -:10418000C30C30C3CF3CF3CCF3CF3CF30002CF3CA5 -:10419000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CE7 -:1041A000C30C30C3CF3CF3CCF3CF3CF30004CF3C83 -:1041B000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CC7 -:1041C000C30C30C3CF3CF3CCF3CF3CF30008CF3C5F -:1041D000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CA7 -:1041E000C30C30C3CF3CF3CCF3CF3CF30010CF3C37 -:1041F000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C87 -:10420000C30C30C3CF3CF3CCF3CF3CF30020CF3C06 -:10421000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C66 -:10422000C30C30C3CF3CF3CCF3CF3CF30040CF3CC6 -:10423000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C46 -:10424000C30C30C3CF3CF3CCF3CF3CF30000CF3CE6 -:10425000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C26 -:10426000C30C30C3CF3CF3CCF3CF3CF30001CF3CC5 -:10427000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C06 -:10428000C30C30C3CF3CF3CCF3CF3CF30002CF3CA4 -:10429000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CE6 -:1042A000C30C30C3CF3CF3CCF3CF3CF30004CF3C82 -:1042B000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CC6 -:1042C000C30C30C3CF3CF3CCF3CF3CF30008CF3C5E -:1042D000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CA6 -:1042E000C30C30C3CF3CF3CCF3CF3CF30010CF3C36 -:1042F000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C86 -:10430000C30C30C3CF3CF3CCF3CF3CF30020CF3C05 -:10431000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C65 -:10432000C30C30C3CF3CF3CCF3CF3CF30040CF3CC5 -:10433000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C45 -:10434000C30C30C3CF3CF3CCF3CF3CF30000CF3CE5 -:10435000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C25 -:10436000C30C30C3CF3CF3CCF3CF3CF30001CF3CC4 -:10437000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C05 -:10438000C30C30C3CF3CF3CCF3CF3CF30002CF3CA3 -:10439000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CE5 -:1043A000C30C30C3CF3CF3CCF3CF3CF30004CF3C81 -:1043B000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CC5 -:1043C000C30C30C3CF3CF3CCF3CF3CF30008CF3C5D -:1043D000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CA5 -:1043E000C30C30C3CF3CF3CCF3CF3CF30010CF3C35 -:1043F000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C85 -:10440000C30C30C3CF3CF3CCF3CF3CF30020CF3C04 -:10441000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C64 -:10442000C30C30C3CF3CF3CCF3CF3CF30040CF3CC4 -:10443000CDCDCDCD0010000000070100000281703D -:10444000000B81980002025000010270000F0280F0 -:1044500000010370000800000008008000028100D5 -:10446000000B8128000201E0000102000007021099 -:1044700000020280000F0000000800F000028170BE -:10448000000B81980002025000010270000B828034 -:1044900000080338001000000008010000028180BD -:1044A000000B81A80002026000018280000E829849 -:1044B0000008038000028000000B8028000200E05A -:1044C000000101000000811000000118CCCCCCCC10 -:1044D000CCCCCCCCCCCCCCCCCCCCCCCC000020002C -:1044E000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC0C -:1044F00000002000CCCCCCCCCCCCCCCCCCCCCCCC0C -:10450000CCCCCCCC0000200000000000000000005B -:104510001F8B08000000000000FFFB51CFC0F0031C -:104520008A45D91918FC3811FCA18059981918D856 -:10453000809803883D80B8819181A1919178FDDABE -:10454000620876BF3003C36E20E611029A23821000 -:104550009F0254F306C85F0F15B312656038263A00 -:10456000F07EA706DE2A8D29364512C1DE86451E5D -:10457000196F4793FF2289CADF4140FF40632965D5 -:1045800054BE9D22845EA604A1A5D1E4EDA1F2D77C -:10459000A1FE9251C66EEE0DA83C00F85C49656024 -:1045A00003000000000000001F8B08000000000056 -:1045B00000FFED7D0B7854D5B5F03E73CE9C994944 -:1045C000CE4C4E4212F2224C1288A0210CAF808AAF -:1045D0007F270122F539202858D40142087983D455 -:1045E0004BAFEDCD8424101135F447058B76885000 -:1045F000D1A20D34D260C10E20147B6D6FF0FAC0D1 -:10460000EAF50B4841312FB1207EC5CBBFD6DAE7A2 -:1046100064E64C2680D8DBAFFFFFFDB4B8D9E7ECE9 -:10462000B3F7DAEBB5D75A7BED3D92750293BFC76E -:10463000D845FC03E54F4D8CB109C1F26766F680A1 -:104640002787B1C9BDFE3A473C63556D193BA29D12 -:104650008C25EC9921142850FED5232C5082DFBFE5 -:1046600065C397F0FFB619423E7C97D0E911E6C3C7 -:10467000FBE4D5026B873A939C310CEA8CB9194B59 -:10468000642C6B12A33F224B8D82FFE07325398F80 -:10469000B134FC2774754661AEC078C6321E535CD7 -:1046A000D4D0A93815783F847FC6D2BC25B731074E -:1046B00063CF03BCC971F0BC5A3ADE61E5EF2EC28C -:1046C000DFA1F33A6ACD58AE303E7732A789654113 -:1046D000BF3EE3F3AC46633D9BD9E34F46C33FEC9B -:1046E000CC7E518C308F13B18C013CCB540E2F6398 -:1046F000BDB26754101F9B6A58A2322C580F2F85E9 -:1047000065873356035E97ED165C16F8FE396C2FFD -:1047100031E6D7BE6BD6EA153E5962A3A10404B5B3 -:10472000E4F4EF6711CBBF11F1FE302BA0B24AEADF -:10473000955580AFAA5A76FB95FEED673389E8540C -:1047400029B9F65B61FCDE5AE66A86F19799D502D3 -:10475000AC2FFB91D3E5837A6663472183FAD03689 -:10476000818919C1EFAF009EDB917F001E2A2BA526 -:10477000DE420674ECDD2BB0E60C1C87F7BB6C77D1 -:1047800006F3650C0CE758662638E732413A89741F -:10479000713007D2C1BC24F38942A8CE54DCF3B0F7 -:1047A0007F9FE29D87EDF4E7490BE638BD0057F2A5 -:1047B0005066A057B1B53A9D653256EA692944BEA4 -:1047C00038B5EC8D5558029E1324C0F77C8BA70892 -:1047D000FBA998579DCD80A7E659188D3FB42DFFB2 -:1047E0003309F80CBAF3C5C4213F31763C844FF04D -:1047F000CFF1115A5D1C98DE972B8BB01F09F10584 -:104800007217011F3F42A026E0284D543A57FC2959 -:104810006BD8A0D0FA5B59C3C66900E511BC0C3F48 -:1048200061AC4308E54BBD1CBA3BFFB0943B303C48 -:10483000FFD3F30474127EAB00B7C81F1576D9BF3F -:1048400012F861CAABE6C0F7803F2A360B7E0BD464 -:104850004DAFDBE87DF7265E0FD86537F24FD716F0 -:10486000A80BF0BDA5FDF11B91BF5E155933763B3A -:1048700022CA84FAE5A4063B1B0F75C047B18D57C9 -:104880002B36EFBB1FBF2F69B3301BF457B17BF141 -:104890001D37427DF16133C326155B6BE514A82FEC -:1048A000F10B2D58EF29E0F0F97689FEADD0BEC7A7 -:1048B000D19E381BE873BAC6CA9C326375F6F6C43B -:1048C00059C067A5FE1D85F85DE976C185689FF230 -:1048D000EAD643C938AF17B97C976D8B664E1D7FFA -:1048E000F0F764AB18F81EBC5F06F364D0EF62D635 -:1048F00054887AB062EB3AD9690FE2EB748D4AE3DF -:10490000F4C9DF8B300E7C57F98AE0C229569A9899 -:1049100017E5B07BB76DCEF30ACEAF56CEB6E3BC8B -:1049200056CBD86EB17FFE2E54CDA5FECD7221BCE4 -:104930002FDDB4592E0E91DBB26D838C706DC81AC9 -:10494000EC8D20D7417880D7B283F552D403A80FDD -:1049500025BF3C2384CF2A8558E2CBB26D22731A3F -:10496000F888D3DDF72EFC13F0E5DB6B27BCEA7487 -:10497000EBD3A71ADDCEA81A1DA5DEBC1911F8F8D5 -:1049800071A403C0D384788272AD069F6332CB9743 -:10499000A07F879BA902BB3C5F3699D97C0663F553 -:1049A000B007DDD2F55097D952E682F550FAB17BC7 -:1049B0002AD49304EF67389F7AC15BC2D7AB9624A1 -:1049C0000FE07995C0E6E0FC8F21D030AF55C9C02B -:1049D0009F80F7A66979CF8B82067B3CD68B7FB10F -:1049E0002683FA3943FD98A19FACCBF7A3164E322C -:1049F000F4A31696E8FDFC8DFAB15D593F4D85375D -:104A000018E1292CD5FB910468576FBFB279A937FB -:104A10004F36C2737339F5133BD5C5BC0AAEE71ADE -:104A20003FB076B708EF95EDB163D7B050BE2850D0 -:104A30000580DB0E5212CA173193A20C7C18EB8E44 -:104A400033D4A127F5E47541FD138895697C394578 -:104A500026BD909F62A5FA43290AE985876EF05E1C -:104A600083EB208ECD92A12E7B47AB11F81AE01478 -:104A7000581296601724F57FBFDACCF150907A2156 -:104A8000FB187C5F65EACD8E85FA35A6FC6B116F4D -:104A90002E81EBE528915563BB280B23FDB43A2307 -:104AA000EF795F089E1A8700FD8560BF8D666F12E3 -:104AB000F2D7F8DA677C12C0B76A08CC2705BA12B9 -:104AC0009E09F8603D5A3DA43809F1699141BE4301 -:104AD000C79761FC1C1AFF06C4A31BC74FE83FBE63 -:104AE000257392617C6B7A89617CAB0CE303BF4FC9 -:104AF000AD6DD6C607FCDDC0D834A199C6B7A49762 -:104B0000D0F8AB655662183FAA6FFC5B70FE9E81C1 -:104B1000E69F798371FEE9A5C6F9CB7CFEB36A5F97 -:104B2000D2C68FA2F9CF165EE2F34F2FE5F3B7F0AE -:104B30007EFBC677F4E1FF5E9CBF7780F12D599331 -:104B40008DF31F5A6E9CBF858F5F54BB531B5FA1B3 -:104B5000F117093BF9FC8796D3F8B2C5EB423E92B8 -:104B600053A3AAFD684FA481400C261DE5A672043C -:104B70001805A01F860A9904C743519CEFCE450132 -:104B8000BF29417DC7FC2051A0CF2A359E2FDB9E37 -:104B90002FA39EA5F7896837F13F456D22AD376C8D -:104BA000BDC53F1CE0ED6E137D582F5A7F935FA467 -:104BB000F58EDBE560C605F0F95F9E1CD51C3AAFAB -:104BC000F0725193F96487418E383CBE0236A21AC6 -:104BD000E06B47269810AC9F043D0AC62F3B0E7A27 -:104BE00014CB53666E8F9C003DCBE450B9A9E5F61B -:104BF000888FBD9303F3BA5B83FFA4C4F17D72B9C0 -:104C0000E047FC9F5BB75446FDB4A8098CE91079D6 -:104C1000AFD2E8D4BBDBE26F16089F4EC4CF3D2471 -:104C20008A8CFD9766D72FDE30C8F0DD3CE66F48F2 -:104C300082F60BD7CE1FA2C2FC7F30C73216ED53CF -:104C400090845413C9314B35816F31A7759D391547 -:104C50002AF7CC311BECFAB95E63FD0725C67AB79B -:104C6000D96F36A1BDB144609BA1DFFBAA8DEFF5E2 -:104C7000713609719CAEDA7877277278EFC3722C9F -:104C80003E5689AEF7ABFC5B1D9EAA87CD2C40EB50 -:104C9000654702433AFA12C85EF3AA7CDEE1F0DE11 -:104CA0006FB6BA3D00CFFD3F12099FE1F077BC1E01 -:104CB000ED36811DD7B1E14B33DAB7E1F30987FF58 -:104CC0008115E1F35165D4F7F37DE1CF399F84F38A -:104CD00053555BFEA01321ED2A5ABE3FE844087FDE -:104CE000956D9B61A82FF1CF35B45FBC61BEE1FD2E -:104CF000A2A62586F70B1B971AEAF37D3F32B47FF5 -:104D00006045ADE1FD7DD58F18DEFFA0649DA13E1D -:104D1000D7BBD1D0FE9E399B0DEF4DAF8FBC13E5B5 -:104D2000A8EE5D91E1BA715639F938DA836715C991 -:104D300085F4F8B42689E4E0748D93CAEEB6715612 -:104D40002FD783C50C4C9C5EE19CAF7132EA65465F -:104D5000FAF3AFC2059F0FEA7F139C843F7183CCA7 -:104D600002C0C2028BEBE3E35E31E47DC765DE6F18 -:104D700000411FD7FFBDD811F97955F3FCA16A0492 -:104D8000FF2128B72C15D7B91E6D7D0F7F5F2E3000 -:104D90004FE873C656929CD769EB4CB9CCF541F9F4 -:104DA000CEE402F4BFCBE54076F5A5C66B01A4A224 -:104DB0009E44EB3C01F901A4C0C02F5906F9EEDC7A -:104DC00027125C95A81340AFAE639EC126D43381F1 -:104DD00003E9778D4238DC49546F4BA075BDB3664B -:104DE000FAA01312D2C743E5A73573A83C59E3A52F -:104DF000F2444D0995C76BAAA9ECA85941E5C735FE -:104E00003E2A3FAA69A4F2CF354D541EADD940E5E4 -:104E10007B357E2ABB6BDC54F6F92BBAFE8DD7ECC2 -:104E200055CDAF809587EA67B4B9D443DB769273EA -:104E30005712CAF919E55C36DAE3678E8263993155 -:104E400030BEC2F96D603ABAC95E29F603FDC7F5F6 -:104E50007F6F8BE274B299D87470A6D923C37FE1B7 -:104E60005A9043750959061624D70C7B847E61ED50 -:104E7000437A5D8E4ECCDD9B3B13E871F299BFE522 -:104E800061BF75DAFA177540A47598059E7721BD44 -:104E900042F046EB5AEFAB9ABEBF0CFEBAFAF0D71F -:104EA0009E8EFEFB4141A5FECFB45A988478DC1358 -:104EB000ED07E667670E3FEF40795C9664524F441A -:104EC000C0835E56B464A84AE8FAD366AC9F691200 -:104ED000A6B7D07AEC8C99350AF94A554F0C43FAAB -:104EE0002751A9F7B32C49564F80BC9EDE9615C3B7 -:104EF000D76F3F5F07B7C712BF825F48EDFFDEF095 -:104F00000CD48F0E0F63ADEC132BEA037897F5EDFD -:104F1000FD7226FD95E2576C8FF91CDA0B16F87BB3 -:104F200091E20712D5F57EAB5A449F65343EDF6EA1 -:104F3000180FBE73EA3EF7C5CC4BF1ADC44E86C424 -:104F400011D669F1C6B26D36D5B8AEC41AEA556D40 -:104F5000C9AA619DC17F80FCB36A4142BE29D7B80E -:104F6000A847521A0580AFDCE4A47EAB04DEAEC2D3 -:104F7000DA217BE151572BA7DB40F09DAE39EC9451 -:104F800040DE4BACE001027C252D23A7A29EEB6AFC -:104F9000AD4B447BB04C3CF39027C2F73B4D028DA8 -:104FA000B7C46FEE35AEA31A7F30E8577F4E7E163A -:104FB000534E86D43B4DDCCE0EEFF780D6EFE5F0B6 -:104FC00053B9FD48E18DCEFE78AA6CFB42F6921CE7 -:104FD000C1FFF28278D2F1576EF21C407D5ABAEDD1 -:104FE00018D9A39F9A7DD90F5F423FF59F9F9244A6 -:104FF00071527D5E3E3029619C055A7C17F8F79E00 -:105000000F613DFDECDFCD6C0DC0C72E402B786FDE -:10501000D65F331333417DA1565BD05A4671DDCF45 -:105020004CDC8E2A621E07D18135E5A11DD9C54C05 -:10503000D3114F5DEC6DC7B8103A9C32C9A4671606 -:10504000361AED18B07F0DF5C51B8CF5623633119D -:10505000F549F17A33F30B343FC3FBF74D2AE17F77 -:1050600031AB5E85EBAAA4F9230B5426A5027C156F -:10507000BF79366F3EC65F4CDC0FD1E3234BE2387D -:10508000FCA5F17ED90DEF3F691D77F78D48068BA2 -:105090007F15C689580C736D65FDF1FB6DE10F87B7 -:1050A000575FAFFBC5693438C46D82DB1F817F2F2A -:1050B000687CA6EBEB5B44D5E017DC8DF510BF21D7 -:1050C00046D4E2B2221391EE5DAAD5678AA1F71405 -:1050D000B7F7EDB4B8EA80DE3F3779068913C84EDA -:1050E000C86521ED7E6EF2D2F34EE1AD62B45B99FC -:1050F00014C8453B14D618E25359E30731CA918BC3 -:10510000F1663B837514E86F41F8A09F55F692DB7A -:10511000582EC6BB41DEA1BFC71C858705A8DB94FE -:105120005686FD59928CF17C9BD358AFC27F201DCF -:1051300046308A3F458F90C2F01860A80FED2EE3ED -:10514000F351E88491DD1F203E76108B43695502B0 -:10515000228CCF26499D7DFE5626FA7B1C7E8A2F07 -:1051600040FBE52A6F5FA9C5CF977F503038EE121C -:10517000FAA8EA3C68904121753DBE7F5E62FE71EF -:10518000DF416F3A61550DD19B734DDE69480FD4F5 -:1051900093089F00E3780D76609A1A2AE70BC2F80D -:1051A000E3AAE1886706FD5D6EF2DE2D26F487E353 -:1051B000AAFB4FEAD7FF8248F3BCEAFE87F5EBBFB4 -:1051C0003252FF15BF7979970FF8A9F4574F3A80FB -:1051D00099D9675253A20BE85EBEB5C18172F9A995 -:1051E000E473205D3FF38BD323C9E71651974FB784 -:1051F00022E411FF101F9D7EE9D13BD0AE3AB7D516 -:10520000AC527C609B256001A6AC6C5DC2E5639BE3 -:10521000E518AFAFFE02F9B3AACDA82F4A5F7832E6 -:1052200011E3CD4049CD7F0E907F50B9E52F8568C1 -:105230007755B15ED27BE1DFE1F8E7E3C81E982F36 -:10524000C7F47FAFEFF3556978A96A7DF40B9184B9 -:10525000A583FCCDF0F6259ABDFFA4688FA738DFA3 -:10526000443611F94CC707F3737BBFEEC5A7738FA4 -:10527000013C9D5BFEDD21E484F227D77B675A1653 -:10528000FEFC35E7C0F2D40D7A31D4AED6D76767CD -:105290009BE6A7ECE165B939E0403FB07CB3D9E5C6 -:1052A00043BABEFCFC2F9EC1B8CC0716D770E8BF2E -:1052B000ECE583EFDD00F5B21DE6F8DBF8341421F0 -:1052C0003148972AF8BB626C900EA5BF3E283B4739 -:1052D000F1E73F8E0BD2A36CC73E998DEA8F8F29E1 -:1052E0002DFBE40E25025D5A8E15A23F51F7E257C1 -:1052F00032EAAFCF5E17D8E08C08F8DC7C90EC6225 -:10530000C413D151A3531FDDC2DA57015D50BFEA68 -:10531000740A7FFF2F9AFEC7FE9C39C4CFAFBC86AC -:10532000FB287FB6B870FE25AF3CE8C0799C92AAF6 -:10533000395F3FDB90E886714BCCBE44954AFEBC9A -:10534000E4B91F12BF2D3EF2C3448A7F3077B28981 -:105350006C055F32CE6FD1A6D934BF62E625BE2B75 -:105360007956F4E0FEE059894DDF11412E5224AE0A -:105370008F4F355B704D65A770E1C07D85B745FFE8 -:10538000568AFF2DA5F8CA0FF5FD20B68CEA67AD49 -:105390009C4E5F88FABE1AAC3CA1FCBA65753BD244 -:1053A000E7F410F7608C1B5731C9A7E143B808FD3B -:1053B0008A47A60DE6F4614E294FFB0EF4FD147CDE -:1053C0008EEDDBCD6E5BAEE13B76312338FE726D48 -:1053D0007C803B0AEDD5538960FF45985FA1A4AF5F -:1053E00037605785F057887C7379DFF208976F5DD7 -:1053F000DEFD33A6E3FBBFBEC3E507BF437B05E08D -:105400000A0CA6F7FB6609A40F2C2C1049AEB7981E -:1054100035B936BED7F904E09670DDEDE317EC3F01 -:105420008EF04F766CF17AF82E445F56E1788EFE5E -:10543000FDE972BB5893FF04C928FF6C1397FB81E9 -:10544000FD091F8F4B98FDBF7806E515E413F7AFF4 -:10545000CB5F367B70DE9F6F3FF0DEBD20A79FB72E -:10546000E8726AD49FE1725AB273028B24A79F63D9 -:105470001A42243985E711E554E9203EFE47E94FF9 -:105480001D7F3785E14FD78703E1315C1FFE5974DB -:1054900046D487F0E71D96D79FFF74BED3F9ADF4CD -:1054A000971543293EA6F3A5CE777D7CA9F35DBF72 -:1054B00078A3017FE1EF2D188301B83CBBCD1447E1 -:1054C00028DFC3F77FE1BB43A9E3094F6E5AC658F3 -:1054D000D3A1D4F8D0BA3FACDE12D6DE1D56F78485 -:1054E000B5F786D5AB0DEDCBDB0EC83CAF256068BC -:1054F00027AE78867D322812BFFAB95FDAFA85ECDA -:1055000043BE507AE97BF34AE6B3633C7CAF48F193 -:10551000911EC0F12A18A7677B861FF3241A6C3CE2 -:10552000EED4A3F63AD05E6C88E5F5DE047915EA90 -:105530003DFD79AF8DC7F57A3CBD8ED810FBEDD817 -:105540001E91F476879F4D8FE467C28A4272D4C160 -:10555000067ACFE3FDD344257D05C65F9A441786BE -:10556000748A6AEF71609E41CF9EAC3BE7C0F34501 -:105570006F8AB48DD883767B0C92C72D2587F877F8 -:105580009F32DF5393317EBF87FB79456BC3EC11AC -:10559000B696F8A958592EA33E05BFECB871FF8204 -:1055A000CB45A9D65FC926E37BFD7BDCC145FBBDAE -:1055B000748BF1BD578B0734EB7232868DD1FC7141 -:1055C0001E8FD2F4F23431E7CE39408F9EC322C30E -:1055D000FDFB337B44A2C799ED7CBF9EE2F6D72347 -:1055E0007FF7923ED4F1D489F2240FACAF3A5FFD3D -:1055F000AFBC87916F767D98FB33283B777D90FD1C -:105600005BACFFE6FDF40F59FFF6535EB7D13E49A0 -:10561000CFEB76E2F79EBD7F4C7F18EBBB2D149F3E -:10562000EE79FDAB5CE49F9E959612D4773D438066 -:10563000FE681FECFD2AB783D6D77AA2DB1F259917 -:10564000DB477BFEF6B1108F25CC0AED86D7A34948 -:105650009EAA5EB3513CAD67EF5779A176FF779D67 -:105660004FA5B67FD963677376227CB17CDFA7EA4A -:10567000B7D73F5F8BF917ADFBE485F07ECAEFBE6D -:10568000C9453DDAB393DB43DDE68EE7707FEE6814 -:10569000FDDC9566C073370A550AAC9B0DCF14A08C -:1056A000DCF4C7CB371427BC527CF4FC5F830FC1FA -:1056B000CDF59DDD6F1570DE5F7FFC21EA85D72D6E -:1056C000C497FA7C3F6FA9257BE572F37698799CA5 -:1056D000E4FF9D790B812B99F728F33F37BD7F2D90 -:1056E00039892EE172D09FCFF73E44F597ED2E8297 -:1056F000F70AF9FDF67FF2F97F6BBAEF04BA3B2E99 -:105700003FEFF27FF2790F4CF737EFD7E8AE627ECA -:105710004BD5EFBE21F8BEAD9E5BFB4F2EEF03CD08 -:105720005FB7EBD7985C4D99189F43AF01D669C519 -:105730003EB311C3856B46CC54D1CE14C3F62BF5C2 -:1057400072AF99FB4D22EE5B629C6F088FF331CDF7 -:105750008FA22D3D185A528AC98E959455DCBE965B -:105760005CED6EC0CB9A6B17B82877888D3DEAC583 -:105770007ADA6417C5AFC3FCC97A81B905B06FA5E1 -:105780006B6F398CFE8D79842960C9A5F21896ABB0 -:10579000B5B8A459950D7E8F9263ACDB9CC6BA4513 -:1057A000EBCFCA38FCD624E6C7F8B43872BF8A7982 -:1057B0006DE218890950B7B1261FFA179624E3F74E -:1057C0001B31C01E12CFBD5A3CF6F6E1716CBB1BFB -:1057D000F138D244716B4A2E25BCB8FC6B789E8D93 -:1057E000D588D755ED884F09FD5F6E7F91DFCC34AA -:1057F0007F59D2BA904698DC36633BCD4FBE2C9D84 -:10580000385DD2CB353A2D33D045A74304FA18E89A -:10581000A2E3F9DBD2279C2EE1F8DF6F7612FE07B8 -:10582000A2974E9734C5CD505ECD9ABF3015FD4935 -:10583000ACA77918ED336BFE8214EF663EA493EAB1 -:1058400062482FF4DB02E0B7FD7EFBF31427EA7A0F -:10585000E9D81D084FD96F456605FC756FB7B300D1 -:105860007E2FF965F4434B5B458AFB3329907757CC -:10587000C8BEAF6EF797FDCA4EF329DD69F1DF06AA -:10588000DF97EEFA2497ECB095BDE4D7F85E1238B6 -:10589000DD7D1DB9B8AF5B2A71FF239C5F62659EF9 -:1058A00027D0B93B7A0EC66D846D3CDFB6B4E51ED9 -:1058B000B3C5907F66D6DB915EF0BD2850BE13C2A3 -:1058C000179AE7A9FB1D9D2F0A1CBE36B31FF3765E -:1058D0004BB7EDE8C6F853E9518B0BC3D255DBBE8D -:1058E000A0FD8D29BF7AD9D141FEB668883FF4F377 -:1058F000FBB789C41F95AD15E487409DF8A2B2257A -:1059000072FCEB72FE69D9AFF6EEF2010ACB7EFDB6 -:105910008203E35BA7DBB73AC8FFDF76E9B85B3FFA -:105920003FBFE5914BFAF9A7F11FE0BFDC2087C527 -:1059300049B60D227F04E0CB8B94EFADF35BD9CB5E -:10594000679FC33874E7CECF9F4378CBFFFBCBE78D -:10595000D09F60AFDBD4AD889797DEA5389EFEDD83 -:105960002C99C79DBB5F7C81E29FDD1F80DF017F9B -:10597000BAF79E4A477FB27BC7D789182F59BE779F -:10598000DA609CEFF257A70C6611F4885E22DFFA0A -:10599000AF20FE1A4EAF03AD07C8EFE9027AA3DFCE -:1059A000D917B769A9E07130A716AFD91E39CEDD76 -:1059B0002F3ED37AD79D378DC7D2EC72B22B88D3C6 -:1059C000BC03741C7D05F4DBFE88E67F46A65F17EA -:1059D000FE03E8B42C8C7E675B17FDFC197CD73A7C -:1059E00068C0384DE00AF0A6C7D1BF27BB7F22A30D -:1059F0007CEDFC25C5C5906EB7C144BB5F3E9B8E58 -:105A0000FB0F9F9A7BEFE7E7322C2AC61B4AF7BEB3 -:105A10004FF2D3FDEA118A53332D9EDDCDFAFEF00D -:105A2000F8A3965359B5C5CEE33B1AFE31FEE37495 -:105A3000D0732DCEC3F9588FFF0C14F7699579DE1A -:105A4000881EDFAFD8F2A1164F09D24B9884743A62 -:105A500076C9FD081D0F2AE26162681C33727CADB5 -:105A60002FDEADD10BE987F1CBBE3825D4D3306E14 -:105A7000E517DE6711F441F7661EFFEC3647CEA34B -:105A8000D2E39ABF0A9753FF95C5332F07FFB7C5D7 -:105A90008F5F7652BFE178EABC10598FBF2DF37546 -:105AA000FFAAF7C5CA0543BE41B9C97B04F9B1A233 -:105AB000F598CCCFA5F0F352FA7C3BB5BCD1CE978C -:105AC000448A77AD6A39407A3C5C5FE8FBA6E1F036 -:105AD0009ED0E0AD6CE3EB44E74EBB5F817E3AF7CE -:105AE000EF267EAEDC7E8CE26D87B6FD5AEE08595D -:105AF00057719DF087C0DFF9CABE5C1EB7E579EC2F -:105B0000E1E39CD1F461D59EC8E3546DFFC2304EF1 -:105B100099AF45E6EBFDA5C73B2DB9EFC1FE4EB7EA -:105B20009B19E6799E6E11A7473A17F5AEB66EEA55 -:105B3000E77E70BDA47CFD23FC5CCCF8B7A3281FD6 -:105B40007EF991E91FC6C463098487FE5A6B399FA9 -:105B5000B6FEC49D8AF46E3D72AF88EBD42EC46F3E -:105B6000889D9FF74EF5143BE885BC8F3CE3915D23 -:105B7000C3F5CDC4A32603FC30CE605C07EAA11FA9 -:105B80003CA782F96E088FE8289C8EF088AA49B558 -:105B900009FDE761563C745E40EFD7AC1ACF03B005 -:105BA0000BE39CD84FD24C1E474CBE8B973EFD3C1E -:105BB0004E7194BF0EE659A078D32CF07D927D7D76 -:105BC000C64186E7BF2651DE7696C5786EAC4B554A -:105BD0007C26D0DFCFE46C5937D949F907D7584232 -:105BE000F30F582017F9516FD7EF7D587E421A7E78 -:105BF00002FD881A7C595A7EC210D621A07DBDC9EB -:105C0000CECF270E55E24DF8FDF39ABDA99F3FEC8C -:105C1000775E31EC9CE2E5CE27C64FC95F3AD405EA -:105C2000FCB47ACF14CC5F8FBF277F47AA8A791242 -:105C30007F9E82E757E25FC81F930CF513AB1F9C52 -:105C40004AF5FFC81F930EF56F1AFF8DD7CB04CA14 -:105C5000572D583D7A2AF2EB55CBF92CC08851CEFE -:105C6000EF40BC75793EBA7B9113F31F7A658E5F66 -:105C7000E6C176432671BCA5291FED403C0D357564 -:105C8000D4227FFE7CEF57B1A8179C4C25FCA8AC12 -:105C90005E45FAC1A349172F9147179E4FA6EB9374 -:105CA000CD8AF70184E391F923E85CE0332533AD35 -:105CB0003C5FCF98C7C0D478A26791464F84D31A6F -:105CC000928FBF58F4C9FC5C4C93A6AFA6AA389E2D -:105CD000E02B172F5EF7EDE17A50E74BED5C69C8DA -:105CE00079C687105E9FE27DC892D0FF3CE31D1607 -:105CF000CF0A7C9F5C7C3E1DF95B3F9F187ECE9156 -:105D000049BDA648F65FB376CE7120783D56EF2A9E -:105D10001C37F377CE9D8741BE4617C92E4CCD1C4C -:105D2000BD627C82C4CF15529E439546BF24139713 -:105D300043F610A37DD61E8BE046BFB9E74195F42C -:105D4000775AD16DE457F54467B4603E50CFC3FC39 -:105D50005C29664CA31C0DD9131340BF0FE4E05C13 -:105D6000981C9C33AE73C6717B2E3ADB3AA83F5524 -:105D7000EB0F0CB0C4E0B9E01E91EBE59E1A27C111 -:105D80003184F9F6E1FA7EA5E36DB518CFFD02DEA8 -:105D90005F40BCE878FFE5C0F47B45A3DF2B91E8CA -:105DA000177EFE74BEC5FB6B6C7FAAF8D02A7415F3 -:105DB000C3CF9D86D3B54A6ADA88AE78E29E2F6853 -:105DC0009DD1E9367A852B411A64A0E3EBD8EFE840 -:105DD0003D5F98105E9D7E4F0F90EFFD070B5FCFEC -:105DE000C2C74B9CD391E28DB4FE60102E2158CFD8 -:105DF000B5E6D1F8834D3CDED3BFBD10713ED07FF8 -:105E0000E6A5F2307355DE2FE0FFFD50BEFF10F126 -:105E10003F2222FE3F46BC03FE3FC6F65780FF4F9F -:105E20002E857FDDAE2FD3F44219EE2B01FFFCC58A -:105E300039333113C62D1415E2FF255B456D1FD292 -:105E40007D5B7262508F2CB9BE7A9F19F870C9B30E -:105E500002F16991765EFD73ED5C4B785E5FF11C3B -:105E60001FE9C9CBE7F7F9490F956D333EBF10E441 -:105E7000DB74CAC7F5F1F393A22617E1F83FA368D4 -:105E8000FAA228D6D02E9C0E43AA4D863CF0E429D7 -:105E90007DFD909F976472BE4FF1B53F9819C6077C -:105EA000DC52FCF800E263BC3015FBCDD7E456EFC2 -:105EB0006FE80AE33A9FE1339EFBCB6A349EFB1BFB -:105EC000DE9462687FCD864CC3FB91FE6B0DEFAF15 -:105ED000DB36D6501FD57283A1FDE8B602437D4C58 -:105EE000E01643FB7187671AEA13DAEF35B49F783F -:105EF0007481E1FDF51DA586F7377EBACC50BFA9A8 -:105F0000F75F0DED038BB85EDC5F939486E70A7450 -:105F1000BCEC5F2A9B547CBE34DBA4E6863E4F7407 -:105F20003B73B1CC73A37F3590BC4CB126A785AE33 -:105F3000CFF9CC6CD06B53ACC67A8155E39774E043 -:105F40001720FECD56A35CA556CF6B02B39BA52CA4 -:105F50001946F9D2205FB758B97EBBC57A65FAED0C -:105F60004E6C7FAA3240E7ECC3E54B44F9CAA2D29B -:105F700047FBA9CC45F9961B6D463E4D1A40AFCC68 -:105F8000B31ACFC38BEA619B649013FDF9F9A8D0D3 -:105F9000E7C2E2DB286F67A07EE5A405B76E017D4E -:105FA00029277BA9D49FAF9A638A9897F790F53BEE -:105FB000FA491BFAD94F0F217EBB92DE7E0AF3CC41 -:105FC0002AE7F592BF946C31E22558770DE67954B3 -:105FD0004E7E8E50E5FFDC54D3782BAEF7FA3C179B -:105FE0007D303311F303D206F09F5ED5E6F15C4DB0 -:105FF000C9AD45C3B03FD5147ABF457AA0AA10FDFC -:1060000098A15A1EF453A6C8F94A3FD5FA198C0A2A -:1060100014ED035521FBA0ABF8238704F3F8779325 -:10602000F7A7C8170B46B7E7F173CB6ED74CB2ABE7 -:1060300054825FD743E98AE729D42BE94912736672 -:10604000F48767F03C6F6306BCAF8F33B914AAF7CF -:106050000A389EE5C78C0D82F1EAFF5B24F8EAF767 -:106060005F4FF93C16A59AE2A7FA3C99B6DFAFC795 -:106070008BCF26CD8A413CD65FDB776E8761FDAC46 -:10608000E26DC77ECFAE37D3B8F50582E1BD3E6F76 -:1060900069C31D741E2B5DE1F32E867923DC9634D3 -:1060A0000E57FD73024B23B8FEF7D243E8BFEC8ACC -:1060B0007661BC0DF0B189E8EDCE3867D2270FF3D9 -:1060C000AA18A434AF21FB25B21FFA9695AFDB4C7A -:1060D0009D9588F654F23546B8C5F566F20717C5A2 -:1060E0002A94AFE0AF59A1D1D538EF554933EF9C91 -:1060F0000BF0D4BD23324CFD7176342D3D04DF15F9 -:10610000B746BBFCCEFE78EF72723801EEB7106E68 -:10611000714321CD9BDA21DC3F17D83319C877DED4 -:10612000E944FF1413C37D9770F8FFD3CAE3C4EFAB -:1061300058559A879C547CEB9641581691DC1DB5B6 -:106140000EB8CE7F68E5EBFC87D608EBFCE5EEFDEC -:10615000289FD37E084BD16DD2ECDAEAEC507B1944 -:10616000F4D649EC57AF8B313FCEC57E07B6CB3C5A -:106170004DD91997B7CBD01E43FED3EDB1BF5A8D81 -:106180007664889EFD4AD3B35F5DA19EBD80ED4ECF -:10619000DD1B8868C724C891F5DC381BC77F952AAA -:1061A00033CAE31B209E9F6D8B6C1F0EB40E5DCE19 -:1061B000CFC88CD6F954D7EFDCDF60C532ED2F9C09 -:1061C000D9E07F241BF729E38751DEED40FDA4AE23 -:1061D000F8830DF1ABE36D88CD884FC0A3D3C6F92A -:1061E000C4698B640F96031E4D063C0EC7F603D997 -:1061F0008357ADDF4B8CE76EBA357C839E9771BCBD -:10620000AEBB3ECEC3B845E5EC73A4E7AF7A9C398C -:10621000C67544F7BF611C01E7DF7DD77F6B71B79F -:106220000E8A17D5BD7A4D0CC6A72A0AFAF48695B0 -:10623000DB8599A407BB7659DC0867571CCFE7ECD0 -:10624000DA35F110C6393EAF399C2985D82D5DAFBE -:106250001CC933437F5D3B8FE4499420E7277ED1FF -:10626000DF575CFCCF3C8F123C27D0C76F56BE0E69 -:10627000ADB7F1F8C9D398C7369AB1F7A363F9FA65 -:1062800091687A1C9F47BFE3F3A17E7F5470E5C7F6 -:10629000002B26DD554C66ABE58DA600968F0A6E69 -:1062A00011E355BE91FC3C4D52161B9101FD284750 -:1062B000DB03088EA3A3D78DDB29EAA7EA3E2C0BCC -:1062C00014EF02C47B5CAF2B097DFC37878DB3A133 -:1062D0005F214DE17AB7777E941FEF294A34B98F59 -:1062E00080AA67670E2F8CC5F77F8BE6F2F258D233 -:1062F00089265C8E7039A038D49B665ADF960D7162 -:10630000272F82EF974D88E77EE905987DC839965B -:10631000C7E367091407B9007881E714FA023EB5AC -:106320004BCC173316F4B089B955F00BEC9342EE11 -:10633000D9C1FF6876FC604DFFF6384D3E33E0452D -:106340007619DBD509EE0C5C4F7781FC0D03FAB4AE -:10635000D558A97CAD464D1806F2B8A72689EAAFF4 -:10636000D738A90CD48CA0E7FB6B5C548F36B5A74B -:10637000D37A2C55AF9B87FEF5FD120BBDB723BC1E -:10638000C47B568E87C8F9972EE69300AE2F353D15 -:1063900052FBD638E2AFA7C600D431FDBFFFD98A81 -:1063A0003F644D053D98FAA3C35953418E9F12781F -:1063B000FE021E188E742E552F9F32B7C4A2A9F06C -:1063C0006B1BF34D4DC2BCC8DE3F158E61CCF6E8A9 -:1063D0009FA64E1D09F3C7FDFE14C6F6DADEABC755 -:1063E00073D8A9FB3FAB8B81F9C86DFC3E9F8982B6 -:1063F000A756407D339BF30B933CB598CFD97337A9 -:1064000073E2FEBE3ECE5E1BB71376DBB89D3951FC -:10641000E0FCC1E6CA5A1E416F6EE8BA11DE3EEFDB -:10642000C0D7748F0F8CB72FD5305E2FC51107FAE8 -:106430002E75FFD7B48E5CE9773D1F49FC7C84C480 -:10644000F32BBAE6266EA6FD78681FBA8FDA2347CB -:10645000B6D7DED2D68106EDBEB79F65F07283A6B1 -:106460005724C6F5FF6BD105BF47B961DE38DA5F47 -:10647000AAD3E209933A7AE5F9767E2F5C3ED413EB -:106480004E78043C0FD7A5D13355601ECCFF486031 -:1064900033840228DD36CFDBD84FD2C24DBE97D130 -:1064A0005ED86571A2D9A3E3ABEE03D98AFA216164 -:1064B000CF31DA8FAA133A64A4F7978F7C4D71CB52 -:1064C0003A737532D56D171BB0FEB4BD7A23D699D9 -:1064D000EFEBA96F003F0CD6CEE1E313D463BB9082 -:1064E000E829583B57EF067ED865E6F52F1F394B54 -:1064F000FCB1CB5C3D9F8DE1F57A98EFAE586FAA69 -:1065000009549052FB65FDE19BB0AEB7FF92DA777C -:10651000DB546E3F2ADE0CA47F5F5D85BA3DA42E5E -:10652000F13AB3F2529F5FC581AF297FB8720FE78E -:1065300047C41BCE13EFCDC375E98C7AD451EBA4BD -:10654000B87336D7D701039FE9E753B798BC2C2A15 -:1065500044CF5E085BFF42CED9B1A88490FEB43828 -:10656000763A03BB342B186FCD642E2A87310F95F2 -:10657000D9DB96EE47B42DBBAFD5897A2B3ED7FA3F -:106580008097E868F41F9ED0F4E2FAE8FC1BA301B0 -:106590009EF582778D887AF165B34AE72F3A24B267 -:1065A000373BB5358CAD3053BD5C3BF76D5EE95D77 -:1065B0003312F5EE2293AB19D7B30C4FBE19BE2F91 -:1065C000DB9DE1AA65C1BCE7B2D896C4B14A30EF01 -:1065D00059AF3FAAF1D946B5C986F7D2E8FB439532 -:1065E0006DEBD2717FFBB37D1F903CBD1F95417C4D -:1065F0005CD17A44F6DA69BF4CC6F3299FD9FAD642 -:106600003F5AF7BE6C19740BEAF52FEB4D74B8794D -:10661000203DF406E83F3738C8876AAC54FEC25DB7 -:106620007D2D9ADE055129D36C60B4BF90E9569157 -:106630008FE6ADB9A6C10A7CF482AC8E443E9B17AE -:10664000954B7C5B162B72BE64B907DD92B6CF0DFD -:10665000F5D43565D3BE533CBEC8686F546D5288BF -:106660000FC00EC8473EA8DC60F2E17EA2C9DA4E38 -:10667000E77DE74531CD8F369E4F5CAFE93BDF6C60 -:106680001EDFBDDC39C592F351741E51AFBF1FE54B -:1066900024BE28917CB4FF5572DE41E718BFFB3859 -:1066A00056C379C8FEE32804873E4E79701CD25742 -:1066B000E51FEC273FF88D6B757BD64D71ACE53B44 -:1066C000B4FC059B7B30F6F3B4A62718FAB18077AB -:1066D00029A3AFEE9340CF1CECD333F90D53D390E5 -:1066E000BEC1F76C92410FB925A0D3C128ADEEFB16 -:1066F0007EE4F65161ED33F5FACC86A993FBC3F342 -:10670000B42D58B7427BE91B4B5F1DE1A373F5A184 -:10671000FDC5E9E3DF4BFDE9FC971AB5F0A00FF8E2 -:10672000EF60AC271FF37C7A673327CAE166498D97 -:106730007285D021358AAF3725E7AF35E03F88F73E -:106740005C03FD4FD5380DFB8A8B8B96D17998541D -:106750009D5ECCC7CF776DCA32EC27FE7F38AE1670 -:106760000EF700704CFD07C331C2305E108E1C0363 -:106770007C570B87183B6B7A06DA6B8F98280F28AB -:10678000D1E4B366A25DF66F268AA70C673C0F883A -:1067900029E30DFBB4997B2CF331FE9E29B1C3D2C2 -:1067A000589427B7B316D7A99F48645FC173AB3914 -:1067B0000E876E72E3FD4F2095D45F66B9B7821FD6 -:1067C000F2E6FB82FA3ED37095E5E3BDA09BA3E71A -:1067D000DF188DFB66731EAAC23C98E795F12F3532 -:1067E0003083BC921DD2202C253BE3ABA8871B70C5 -:1067F000BF767014B75B04F670C3E1E448EFB9BC30 -:106800009E5BF3F0348C1B34AF745E8BFE53B3CDC0 -:10681000DFB21FF3761E53E8DED6AC47FD8D9950EC -:1068200017D79968BD1463FDDB9A71DFFDC96C173A -:10683000DA11CD68BF60FB4714F26B56D538D3F040 -:106840007E923A6D1DD8B276B28A79C1F58A1487E4 -:10685000EBDD2A73F55C3C7731EED18D0DD6EB5133 -:106860008FB91A07A9BC9E948CEB9A33D33A467B16 -:106870000FC868AE75A6A8B1C1FAF06FC0FA203D86 -:10688000B3B1C19D86FD2E2BD5FA3B88718A17E2E4 -:1068900034BC68EF33FBF4D2C606CCCB126B83F565 -:1068A000A930DFADCF723D3518FA47FB0BE6E3C3E5 -:1068B0007B057B874B744ECA06633B607EB691991D -:1068C000B4DFD70C7A11EF2BEE1DC9DFEBFB34F2EE -:1068D0007013EDD3607B5C6F6CC9BCBD3C83DF572C -:1068E00020DB158A37C07A3015F39E14A6FF71F3AA -:1068F000B8A4B68F1185F70184F0A375ED323AF78D -:10690000691D66DC9F97D38C75897916A0BF27AA6D -:10691000C6E737466BF94183580ADA6DC34D3E131B -:10692000B61BC9FC545EC702648F8D621D541F8D57 -:106930005E63161E5B72D241AB71CC2DF238AA4752 -:10694000443B3171AE1E47F24E41BE74476B7661D7 -:106950000AEF3F7EC62CCAF7F569EFCD33863D318D -:106960000DE6B57EC6DDCE50FB4E5F2F75FBAD4804 -:1069700083F9CB6821A2BDA0DB7545365E4F98E553 -:106980007E7A14C611DBCD26BC9FAD588B63166F83 -:10699000C84F44BBAC68DF5CB287D74473BB6CD1D3 -:1069A000FA19B277149EF79A4F767FFEBA0931181A -:1069B000A76FB0B962AE47FEFD23BFDFF54AEDB168 -:1069C000E6C46B0A501E9BC1AFC6FB8F0E9ADDCA90 -:1069D00018E48B75C3C8CE6C8EF2D6C742BFCDFF0C -:1069E000EA74D541FD6736F7F823384E43147F8F9C -:1069F000F726216FF6EDF73F2F5C8C1E78FCF0FD3B -:106A0000FE83B191EFF1BD43C35FD0FEF090DDD9BD -:106A100060F6C4DC87F0BDCBE779D6EA89512F1147 -:106A200067FBB486E70376D6B85840E6F7D162BD77 -:106A3000A4683FDDAF5CD22250DC7C096B223D3A7A -:106A40004C89D5EEA731E6C59616BD4DED4B5B7969 -:106A5000FB32D642ED757AE1BDB501831D3ACEF029 -:106A6000FD1DD1DC6FDDAC781F43FBFF9119D9C44C -:106A70004FC06711F32DE207D877B9319AAF1F37AE -:106A800062DBC8F628F163B87DB85CE0E7B307C203 -:106A900053D57993613D0ADE9F21D37AD4ADF9496C -:106AA00087937CEB6F84F97F9FF54A24A7DABD2397 -:106AB00075825F42F9FABE33ECDE1B2D0F68BAA671 -:106AC00025FE43CBEFF93E6B79C30DFDDCCE02F41E -:106AD000DD61ED9E1214A4487919D0AF411FDC3A54 -:106AE000C258BFDD65ACDF3929F23D7D6B6BD4B494 -:106AF000D07BAAD60E708EF32D8D5E577FDF120BE2 -:106B0000CFEB7B0BE95E81F994B47FC1F3FA141BE0 -:106B1000F3A01ED9BFCF46FB21558ABC1943165599 -:106B2000E0EFE2BDF08A9D9F3740FF17E3058A99A9 -:106B3000B70FDE97C4F751123C495A3CC3953463F2 -:106B4000D4B7871BFD2ACA0B96D846DC770DE627FB -:106B50001AEFEDE88AFE380FFD6398CF6C8C4FE892 -:106B6000715A7D3EFF287F2C5ABBCF399C6E6B3407 -:106B7000F9A80BA3733DD23907DF73B9F952BB876C -:106B8000FF29C143796889261E17ACB3B98E529C80 -:106B900044F30FEAB4B806F37D5DEF56C2EC9510EE -:106BA000FF227DEDD7F5F539E477F338882D6A15A6 -:106BB000AEC30D36BD6EA6FAD3E6A600F9FDAF5AF8 -:106BC0009C181F83EFDD1867F3CD1D417E5D5D06C8 -:106BD0004BC17B0EDEB0CBB4FED6BD6A69C6F5D81C -:106BE0006DF376DB42F249BAECEFD1F9A608FDF974 -:106BF0000CFD0DF976FDC1F8AD8877FDFD1BF6A7FC -:106C00000222FFCE49F91B69ED1F7BA19EB8CB4242 -:106C1000714FFDF70FCACFE7D1FD8C7A7F13144E69 -:106C200087CE1AD5908F5D8E7A3707E5A09DF467E1 -:106C300045CB2083DED4F569C5F91B68BF2C4857C6 -:106C40002D2E21B5935EAA38FFBF68BC3B909E34C1 -:106C50004E12E9F781C74935E8E3E038930C70F745 -:106C60001F6732C1A18FC3DAA20CE79FEBCC3CAE09 -:106C7000726698332636821ED14B7183C970FF60CD -:106C80009DE4B262FF75CA4E35347F287C5F00EF09 -:106C9000C56421F0D5C17A86C1720BF3525E403DC6 -:106CA000F6132207A2D9A562BF62C2F8E9F92EC67F -:106CB000FE45B9BD107D7233F22DD88B3F583B7E17 -:106CC000950FEC49C9EC6947BA4A769313F3686BA0 -:106CD0001513C545EB92AC64FFAD12CA559473BD54 -:106CE0005FA9432238F47D8F81E6299F77D03CC38A -:106CF000EF3BFB9F1B4FA176FDEE573B30D7930F29 -:106D0000FD5B54930B455D4E53D82721F40FEF479D -:106D1000DA2045EC27BC9D8EFF01E96CEE70203D2A -:106D2000BAE3A58879101B95EF9807312F4C1F27E0 -:106D30001CCD0EE0F74287232383F4E54605F5A535 -:106D4000FDCC9FDC4ED2CBB4EFADAF7FE684A9562D -:106D50009E4F6CBC576F20FED3F1627DF341C6F3AA -:106D600053BD947F72393C4882CB43FB007629E2C5 -:106D7000BE36584286FC384931E64F35481EE2633C -:106D8000F34DD556DA27495B69C57D92D592330616 -:106D9000FDD8DE37C1FE83F9353A79BE6A78FF6BDC -:106DA000F01E66B4731553C4FB79A306B0AFBA34B2 -:106DB000FAACD97769FE01F5E1C175372A4E5271F7 -:106DC000DD359B39BC03AD4B7ABF03E1EBD17DFCD4 -:106DD000F71B2C39563FAEFFE1E3354A1E4F3EBC50 -:106DE0006F047870DFAC31CD4DF86D542515FDD5AD -:106DF000E81151CC1AEA6F65CCA2F767E2E3F1CC57 -:106E0000226B8C8F9C97A3E369B7F21DED1D6F1861 -:106E10005F0E7F8FE2E8217CD9A94CE8CF97BB9128 -:106E2000171338FCA1F7A65A338645BC7FB21F7FE3 -:106E300086F14DDE6446E7F70643B919FA6ED5EEE2 -:106E400043AAC0B50BFCF4F27B14A6C2FAE677E4C1 -:106E50005F4039C96BDFCFCFD1B426F07B1EB5EFD1 -:106E6000C3C75D62E7FEC812BB4A65CC51F72FF17C -:106E7000F7375ADBA39C785EB1352EB21F9363D7E8 -:106E8000F3689AB473081DB44FA1B7CF9BC7DCCD8C -:106E90000AC53D1BADE07F25F4B5FFA9B63F0282D0 -:106EA0000BE3DCF9DBEB9AF9F9513E7F8CAB62FB2B -:106EB000C4C48E5C41FC0E74DBC60CF7DB55583B3A -:106EC000B251CEE79ABC997618A7EA684722D65BFA -:106ED000DF3E9D4E7E6F1DB7377B774753DCA03F6B -:106EE0007D6AF979F2F329CC37A83FDDCAA500AD58 -:106EF000ABE5E7D3996F1CCDDB678D0BBEBFD3C26B -:106F0000D8A4B1C8001C4F889F48F430DB4D067AE6 -:106F1000803C5E67D7E88178EAA3B776EF4BA77627 -:106F2000BFE071CD5F612AF7D7F5FBA58E67F7E566 -:106F30005BD07D5BE536F713784F0B3B2252BEE604 -:106F4000C229FCFEC48516770CDA570BFF53146A6E -:106F5000697F93F3FD220D7F9DCC45F70EF8D6DABD -:106F6000F8BE4E987F96F154FEB83FC2F78BDA44D4 -:106F7000CA1B5F3045F161BF79ED05BFC4FDF9E281 -:106F8000C6683A77BEF07BAE9368D72D7CC2E6C464 -:106F9000DF7B59FE41667E32F4BBFCC90CD507DFAE -:106FA00045AFF024595DA0271FDB53887E45833011 -:106FB0007FBE3006FCCAC70EACC2B898F4CD94CFE1 -:106FC0006D507FF4B1775661BCE9B718E7263BF600 -:106FD000DD42B4635F42D0F4FD3FC0C14B874D5AE0 -:106FE000FDC4AAA9A0F2AF4D6835292AFA65275633 -:106FF000E139D9C438F718138CF78EFDB342EC6F22 -:10700000C113A3CE6D80F7E7ED17C8BE003A69DF64 -:107010000B374F01BBBB78B25E972D588F8F6686BA -:1070200038BE3933383EDAD9AD7A7C8B45DD8C7188 -:10703000F7E305D55324E83FC3A1AECE19C9D8C4A0 -:10704000F5F9AA1BC6CF76C4DD8CF198D6BE7D8338 -:10705000F8D5181F6B65DE0366787FD3E3436EB601 -:107060000262E30779C6A830FF41D629ABA7DFF457 -:107070001DE46344BFF3590DF60492934388D2F4A0 -:1070800015FCDEC23EF94EE37CDB571FD1C1CFC3F6 -:10709000E8F5245E6F5D19595FDC12C3F9BA352A31 -:1070A000F2FB664D3F00BE03147F6D8BF60FCF08D9 -:1070B000EA0F901FEB2492A7755C7F801CCDB493E0 -:1070C000DC46ECEFDBCA6BAB76AF79ABE48EC6F88F -:1070D00082AEC7308286E3CCB53B0DFA39AF7D0175 -:1070E000E9D751312A87C7C9F19330C5A84798B568 -:1070F0003D3B74DFFE77DA3C33AED3E33F013974B6 -:10710000DF69F98EFC4B9E9F2DC7387F88BD1D9C83 -:10711000C7548A67F4EB17FA736AFDBB72AE045F5B -:10712000EA65F0154FF8BADC3C83FD19E32FFDFB4F -:1071300093B57DC126E33A224786F3A4CE27807F0C -:107140005388FE2CD6F4A99E07D1BD6B24E54F06CB -:10715000C7E5E73181BEBFC4DF5DF2813E453D96A4 -:1071600027B96FC5F679ED712ADAEFC06FF51ABF4E -:1071700049C86F3A9D5BE3AAF369BEEB04B24BFAD0 -:10718000D941DA3A9AD724D0EF990D9EE715E787CF -:10719000C0A7EB7BE8BF55EB7F3CE7E767FBF8F95F -:1071A0003E941FCD9F67AE0EBA5F3D1CFE852873CF -:1071B0000921EBD5AB368AEBEB78BB5AFED7ED85D0 -:1071C000F201D725077D37F868C0E184768B511E20 -:1071D000505FB57C42F764B6B6890C7FB200E78D8C -:1071E0007A234FD793BE95870A24B25B827AD94916 -:1071F000F68BAE3703566BB0FDB9B52B0BEB51AF29 -:107200006AF7ECC78BA0C5C706E1487370BB7792DD -:107210009745FCDDB81CBB5DD723348F8D2B0AE866 -:107220005E852A6D3D9DD4E1A3785334E27142100E -:107230001FFA7A7DA7A5E315EDBC97811FF53AD813 -:107240002595A6AC60FFF87E6608DFE739381F8415 -:10725000D3E7BBEA27C0830FF1F0430DEF0950C716 -:107260007B2D9804EB17E6FDCC505C6B3242E05668 -:10727000B83E4E104D5C8F5D462EE20731EDF7585B -:10728000EC24CF417C70BBE5018716E7D5EE293FA2 -:10729000680239A17D363ECFEE5DC9D4EF6CADDD1D -:1072A000DF4B2F6FD6F296747BB1E2B5D4CD46F8A2 -:1072B000797FBB1C1C2F7947DD63D08E19EE515CA2 -:1072C000E81FE4B5CFDC8FF924D97BF00704827C7A -:1072D0009EDDC2E514B84BC3CB9BDB43FBAD74D83A -:1072E0007539FBBBCC23FB28E757A4CB7D21725A11 -:1072F000E35038BE607E16C4A764D4A37AF9F7833E -:10730000C3B31FCF2595033E506DEB786B6D99BFCE -:10731000D286727C94B9508EBB5BE69B46215D3170 -:1073200011CC19A21FD6F379E87628F0650BF2E5A7 -:107330003AC7101A6FF85177740EBC1F8E7613C6B9 -:107340007D5BEC7EF423FC0EEF2E07E27356EF1408 -:10735000DC4FAD8CAEAEB5853CEF6BDF06ED898FB3 -:10736000BD22EE1F953FC0F8BDF1DA7CA0A9CF0287 -:10737000E355C820A759540F20DE5A65DEBEF73EFC -:10738000FAA5115629F27BF960FDBE95F8F36D530D -:107390001CD217FD24B493CB454F1AEE7BB2C11615 -:1073A00017AE03E07710BF1FB431C906FDFF1E4AB8 -:1073B000D4D3D3C4A5748E6B5A9640FB44BA7F8F46 -:1073C0007A0BFDA43BBF174DFCC82E3C380CE3D311 -:1073D00009D19C4ED08F55EBC76A1D1B94BFFF4847 -:1073E0001F49FE8EBEBE1D1404EAE7E04DD735D717 -:1073F00085F841D81FEAFF83C28CB4A5C8FF9A1F45 -:1074000047F6617C70DD457B65AC21CEE6D3E0EBD1 -:1074100048473E0AB547D13EEDB3677DF357DF0CD1 -:107420007A76E2F496005E715FCB8A6EFE17E86FA3 -:107430001AD8B336C0C33E8D2F0E66F844DC4F3DDC -:10744000385CA0FBDC0F457973AA95E038895A5C5B -:107450002051CB334F8CE2E50F62B81EFC3C86AF67 -:10746000D737A8BC9EE8881C4798ADBDFFA989EB1B -:10747000F735F991F3D14F68FAF5AAEDDE1C21FC3E -:10748000BEEE138E09DA7DDD946FC7E3FD0B34FE8B -:10749000063B87E814B4ABF87E9D6E879E6D9F4DCA -:1074A000F51382F7BD7B042C3D4F909FF4AE48F15D -:1074B000A1E2586F22E6A55544458ECB0CD2F0F4DC -:1074C000590DA338EF29DCCFCBE6BFB785F5251BD7 -:1074D0009EA47B1D4A999FE2BD451B1A68BFAEC89A -:1074E0002F30A780FE9987C781353A946E110D71B0 -:1074F000E7C552B51C9B13E45BFC1DAED0F7259B82 -:10750000C619EA576F971618F23B827AA790ECBF1C -:10751000F07E753E0FB74F8FD7380DF1EE051B8605 -:1075200017F2CD78DE7E2173D17C17366619EF1104 -:107530006E4CB8B27B82C11EF545845326FDA83F30 -:107540003F0EF8F785C4F7177C3A8CE0F88BC37BC5 -:107550005D8C018E68E633C4CF26F3DF29B4F1F8E1 -:1075600023F08FEF5276407ECC77F507AE1DC01F1B -:10757000C8FD87FA037993B9FE654D02E5E04C9C9E -:107580006AB4CF66C7F0756E764CB4C13E2B9A676D -:107590006C37576B37576B77B9384AA85D2664A1AB -:1075A0003EE3FDE9BF1F9571FA6DCAFFDC10C3ED24 -:1075B000D79FAA6E6F0CF4BB563B77D06FDEDAEF25 -:1075C0004AAD35F7E585525EE0E66F1EACC3DF09D4 -:1075D000E9DD01F63FE8C1FC67DFA07BBAF4EF6E9E -:1075E0005FD132B408F054A9C973B98BCFAFDC15A1 -:1075F0009087413F29E51CAEB4967D8214F25D5A16 -:10760000096FB722C66CF02F7FA2D5FF35C649653A -:107610005A49401806ED52366D1124EC0F7F570B76 -:10762000E049A966FED0DF934A19CFED9ADBC76F18 -:107630001616E604F1D0689A91A3625C3531DA85BA -:10764000EBCC47AAB70EF150FE5180CE494CFCA8B6 -:107650005D42BBBD5B75D7237FEB78708A6A0AAE4B -:10766000A3D11F71389BFAFC62BEBE30F6A86647F4 -:1076700037EB76E961C6ED425AA712578E30FC3ED1 -:1076800061629CB64E2432EF4E85DA3732A227A3D0 -:10769000F924AECC6EE6762CA7F7B42CCF167C3E40 -:1076A0006DF0C8B178DF47D6DA8084BF3BFEDA26BA -:1076B00053C4FB519A35FCC33C9EC5F9E9F3B89C11 -:1076C0005ED0DB9907884FE8F2103D3DB2DFC1D8AC -:1076D000E3F43EFFD9F87BE9FECA7A997E4F4EC7A4 -:1076E0007FB7EA6941BCA6B46C160837DA787ADC51 -:1076F0000E9FA35C1E978DE73A0794FB153B8716F8 -:1077000085CA7DBD4CF4D91C96E7AFDBF77F88E1D5 -:10771000EBEA9058CF3EC44B65DB3A8AEF2CD9C2D6 -:107720007FF76740FC5C21FE8412EE0794CFE1FBFB -:107730005EF9CF4A44FFB27AFEFBACE5DB77F0B8E6 -:10774000CE8F990BF54379CB0EA128077F0773875E -:10775000B028049FA9E57ECA83BFC6AECB1FD75B06 -:10776000E1FC8E7162B4530ED9B87EE8CC577CB878 -:107770001FDC69F69663BBCEE46817E677E9F8FF8D -:10778000FD8E9BE9DCB57DA7258065A3A939C98A53 -:10779000FB0ED7CA2EE4AB6ED57B12E91327795ABC -:1077A000F1FBD878BBAB16BE755AD85855B9723CA8 -:1077B0004C0CE38F893FE67293A43AF4BC86B12463 -:1077C00037AA9DEB2D13D76787CC7C1E3B1987F713 -:1077D0000731EEB3248787E368DC94F2009D1FCA6B -:1077E00038BDD370CE30C85FEEBF7D1B7EFF3F2C0F -:1077F000A14B2800800000001F8B08000000000043 -:1078000000FFD57D7B7C54C5F5F8DCBDFB0AD90DA6 -:107810009BF73BDC100C28246C9E0401D924848740 -:10782000206E0228C86B7947926C02D2FED0FA6DA6 -:10783000168331E56B6BD41645A92E8896B65A830C -:10784000A2060DB82822D64723A58A2DDAA5202224 -:1078500084641BFBC056CB6FCE9999ECDE9B0D0F59 -:107860006BFBF97CE18FC9DC799F73E69C33E79C65 -:10787000991D33B5CDA88C22A4A69A38BC342DFD11 -:10788000E90EE98485900BF06F2221836C3221F19F -:1078900084A43CBD4D522C58BE7F5A1CD6272605C9 -:1078A000BE4BD8AE8696AFA0A95B22848C25E4A0FF -:1078B0008178CC3184B4E82A47D968FD9684487B26 -:1078C000132D3B667345DB687F96639D07ACB4EA76 -:1078D00098633EA38BF64BDAE9C76442DE3012129E -:1078E00041DB1D8C60EDD36D74902242261B89070D -:1078F000BF1B3D2314DADFC1A183B0BF97B7EAA64F -:107900007A697BC320B2D81932EF749B0EDBA56C69 -:10791000DD21E9E8F7B8485A1E323F51EF015B59C3 -:1079200026CC67CCD44E8443DD563DAEA7C2E81CBE -:10793000B66654B0DE68E88FD67BEDE64F8C7EFAF3 -:10794000FDC72FBD6F2450BF5572B4C1FC5BDF373C -:10795000CEC9A1A9E7E7324920643A61FF36BFF0FA -:10796000BE51A1DFA7EFA670A2F5EA76EFD22FA352 -:107970006957A9C5238D2624F3CC6B8B4821FDDEE6 -:10798000662211746EDD3657918DCEFBCD5D530EA0 -:10799000495184589F33F92015F021C49FE1B40662 -:1079A000E725523A30CE2F722AFDB310B246EF557A -:1079B00099F0DD955945EBB7C630F8CC1FCCE042C5 -:1079C0002CEC7B155F97800B1D7F0A8C5F91E5DCAB -:1079D00001FD542446D89B32619EF9AF9929DCEB16 -:1079E000EC923D82568D2B67F00C9D57654EB87911 -:1079F0006DC0F1E263D9F844EFCF807109F1B2EFC5 -:107A0000326921F9C1F67338BEE9771FFB4E863A19 -:107A10007382F3D7E26F834DC2FA61E86C11ACA3B5 -:107A2000F698CFC7E8AC530F749679E630E243D0AE -:107A3000CDCFB6EA3115FDD5D98CD85F9D4D8F706D -:107A4000D90C781A4C53032C9AA61BCC5E0F85C711 -:107A50009BF3261F9272297E6E31FA207D43B7B4C4 -:107A600016CADF4861E3B7E8746B21DF729785348B -:107A7000215E1D6E98CF6B3747217E6AE71ABD26BF -:107A8000DACF8F9F9758DE63F112FA67AD6BF6720B -:107A90006847E222EC4F02FE5C078C73ACFDE94ABA -:107AA000796EBF51A1DFA7B7B1FD27F050DBC6E863 -:107AB0004BEC0701D7203CBDAAFD24F0317FB08DEF -:107AC000D105A5178077CDCE08DB49331BEB02012A -:107AD000FA8C56E5EBDB936D274704F335F007D0BE -:107AE000C10E628179D6F279CED3B9EE83FD5567A6 -:107AF000F61F3450D4161F0DE07E1F887E6BD6FF14 -:107B00003AFB640121AB930E612AF6AD61A87A7F3E -:107B10006FE5786F8294B67B82D34D4D611BEECBBF -:107B20009A930DB89F2D53195FB31C238E503C13AD -:107B3000F243BEDE7BB17D4564DB6499C2BDE27178 -:107B4000C9D644FACF4FA4AB24E26CA3FD7DB6F5B1 -:107B5000F5A82500DFAF2EC8A498AE3782AD7737E1 -:107B6000E73B5D3B29C091DE1B8C24CC7A2FB73FCD -:107B7000E23B22013C6B38ECBB9E2E1FFB29A51774 -:107B8000CFCEC1F6ABE892CF3E3DEBF64FE9BCBBA2 -:107B9000764CB4CB40364D4EA49F407C847D3BA5B3 -:107BA0009F38994C9528DE37B4BD1E358EB6FBFC48 -:107BB00097A3F3816FBFCDF7FD99E7E5F50097BB7C -:107BC0007EF6EC75505EE395624D30CECEC7FF95E4 -:107BD00042FBA9DE510F10264DBF7CD5E8A7F574F6 -:107BE000DE6DECFBCEC136A8F7F913F75F07F06E38 -:107BF0006A6BC2F2334F6CC3FC6B3F7B76DF3F682E -:107C0000BD5A67941DEA9D797E3FE2A5D6A577C04F -:107C10007A07A2EBCDBBF6337ED926E17E2373191A -:107C20001F13742DE8F7F39F2D1E1B2A37C4F71678 -:107C300023973B83981C39CBF76F4D99A505D2B399 -:107C4000CF44CC85F5BA8DFEEC6898CF2846171F37 -:107C50007178D4B6AD31B82DD81EFBF980EE7B48D3 -:107C600073287D9EA2F44E6BEDB85000E3FD0AEB45 -:107C7000D37A251114BE372F382EC17C22473518F0 -:107C80006A709EBF64E574D5A1E5C5EB183D6AE94D -:107C9000E00B9B05EB8B7D90B2BB324D413E60B259 -:107CA000333ECED69752ED6AB2D2EFD7AF73D965D5 -:107CB0008AC7974F1F9E9C4AF33F1B211520FE65E4 -:107CC00089C9398F05C7A95B5F464ED0F9EAA2D9A9 -:107CD0007E49B011FDB5C807B631BAD713BD05F25C -:107CE000FA00F289BA162E0777B0791273206396DC -:107CF00015DB59AE8D09CE83B6B358301FC8B829ED -:107D000007E48E672ECA1DC588F33D23F801F1E410 -:107D10002ECC09EEB7041D7101FE138C34B5307EF4 -:107D20005349FB4F8F2E4D8A2E0AA6098358B91648 -:107D30004EB7F0F21F453B92A2015E3B6355F260E5 -:107D400020BEF2DACDDD4C6EBF721CE9D00D740896 -:107D5000E3BB4EAAE4F67264AE940EF71C473A5C9D -:107D6000DECEF8ABBBBDD4B88CA69B253217E6EFB0 -:107D7000E6F4047464A7F99BA2A3717DEEEBFCD931 -:107D8000C0A7BA39DD75EF61F4F6864EE701F8BC9D -:107D9000B17DE43690075AF928553B11DF6E8A6FA2 -:107DA00093047AD6BAC3A067D555133BEC57F76E48 -:107DB000BE1F1A08EE07777BE572E82F356E9A5DD5 -:107DC00096502F999C4AF3EE5A5204FB2D656BD9BD -:107DD0001EA00BD22E91AB205FEDDC0DEDAF8FAB73 -:107DE000B3CB9920F7B6279969FDEB471463FBCD18 -:107DF000E94A29F4E7A920B627216F70A13CDB9C52 -:107E00003CD20EF2CEEDDA887A175106D9A19CB891 -:107E1000F46BA1BEDBB3806C92C2ECE33D9203CB6A -:107E2000BD91DE08DA7E7A3BD37FDCED6C1F9F13B9 -:107E3000F011A9A173118CD7FD828978A4209DBD72 -:107E4000B9670A93B32F9A50CE9E6D749013543431 -:107E50008F8C5610AF028E35AD993AA05B42669971 -:107E6000601ECBF83C5A0D4C6E44733990752F9BB5 -:107E7000C772BE1F9647EB786AE4FBAF95C9059BB6 -:107E80002717E4E0393E1E924502977374E8BAE57D -:107E90003EDC27B54FB3FEE24C8EBCDB42E855E832 -:107EA000475A7A6CE2E3A66C3D20013349D95AA5C2 -:107EB000DAE7D757135F3D5DE7F55B75BE89B9A873 -:107EC00037DD82FC7C83916C97FAF7774F34E35B64 -:107ED00015B1CE3C09E4D7CD16D43FFAF6E9208798 -:107EE0002E02F4B87CC9DE84AB7016EA68BDD309F3 -:107EF000563BE0ED471C8E5A7DABAFBD460F9CD183 -:107F0000EAC9254369E9864173019E545FB798A188 -:107F10009D8DB6A7F512B68F7B6213F2AB26ECF7F8 -:107F2000F6681BEB27D659D8002C2ECBB98EC92763 -:107F3000AB3DDC7AD2A3859EBD284F07F433DB82AC -:107F4000FBE1C7AF484B19BD514128013DB2FD418E -:107F5000E8FE7852417A443DCADDE0F486A747B690 -:107F60005FDC54AF023D9BD2E35AA6275B08DB4F90 -:107F70008C2E23A73279007C2B549F15FB54BBEF2A -:107F800005FDF6EDFBCBDCEFDD06B61FBB291C8043 -:107F9000DEFBE8FC6546E79B36D0FD48CB37D1FDDC -:107FA000D814C2FFB5E71F98279C0704BF3D66732E -:107FB00076005F746F7FAB19C996F347F7CB3FC864 -:107FC000BE98DE6586CAB45F33DDAFA1F463A6E078 -:107FD000B6E663EA013911B95EAD4789F4836826D4 -:107FE000BFBEB1DE3842D2A3DEC3F155AB737D0014 -:107FF0007C1EF4464A1124633DD31B1340E600DE89 -:10800000B6477A413F4E4820AEE7C2CC673FDF67B4 -:10801000029FE2FC9010C5EAF7F27DFF29AFF74F0F -:108020009E869C4B703F283AD771220F2C8F443B81 -:108030003A2F2C17F3E93BD798D97C13EECADEBE52 -:1080400029048FC17D75753EE037EB5E9F7EA925C3 -:10805000388E908B5ABA81F983FC81F5548E1AB808 -:108060005EEB7E7E3ED3D07104DF5F7BA8B882B426 -:10807000D5E0FB2BEEC7355602FA222507472C9D8B -:1080800057FDBEE16C1F8D086443FBEA58D74D31A4 -:10809000B4DF3193F8FEA0DFABE09CA0271E530CA9 -:1080A000E0DDE0F587E0F9D318D67F8FD5EC91E9D4 -:1080B000FEB823D6150DED3D65C4EE03397307E513 -:1080C00027B06F89AF08F84D3DF147019CC7585D57 -:1080D000F13140BF726736C9A2FC57F2E7C2F763BD -:1080E0001151B984F6F371FB6F9F7985B65AF8CABE -:1080F000B985DF03FA7A312203E8E218D5973B51BC -:10810000DF560683BEDD4B94C1B630FC57A40BCCC2 -:108110003AB3BE20983F66559F2F447A4D0CC36FEB -:10812000FDF914E28985FE099EBF7B6214F65D1F8E -:108130003082EA567F3E8378687F1FEB48755B98F4 -:108140007137C5307ADB4DC8D470E5F7F171760F21 -:1081500065FB30B04DF2027FAC5EBFE1CF32E50788 -:10816000D5EBAC3E4C6931E86FD5368F4F47F3C73E -:108170000C8C1FD17FB3CDC541B947EBE9C7030EC6 -:108180003CF4204BF9E0522EB79635BCF925D813B4 -:10819000AAF5C43C9EF6B3DCEC3C984A8B3EB32C6B -:1081A0008F02B6BFF23BB725805C4A5CD0CAEC3286 -:1081B00064920DF45EC93143BE1079313D4B8FFAA4 -:1081C00031E29FE2EB8B18E74CC0F782C104F580E7 -:1081D00005B7457A3D217CD0CCE1A1A59B4FB87E67 -:1081E000A5ED7F766C1981FE3AA29C73813E16DC68 -:1081F000764EC5CFBA25FF538F025DADB1DA9F64CD -:10820000DD653843E8FE3B62BCF33AC4534F5E671A -:10821000F6FA4CA0DF40C68760CFEA30D93C0A941A -:108220001B11CFA2DD9F1A29E3CB0EE6979E1E36C7 -:1082300019E86B19B13703DE97B544124F083F03B5 -:108240000518E8C37D9E603F4B3BDE3C0AFCDCAD7D -:10825000F7239D2C355B108FEEF37A9C0769317400 -:10826000F9457B8AFB23518EDB607D9E7BC6479F51 -:108270001A493F26D2EFB87ED7EDF0FDA1C828E21B -:1082800000FA784BF60EA7F3EF352B836328BCEA90 -:108290008D940E4663374E7388FE43D2AC6AFC77EA -:1082A000BCF525CC67B9D9650439BEC241CFA73228 -:1082B000E0C957641B158AEFF1F28591978FEF455E -:1082C0007CBF7F6CA4F41F661FDDC7E1DF23EAA536 -:1082D000B07DF27106A97E0ED26B684ADB7D3C94BC -:1082E000E7F3793E9BD74B60F91D7C9F7C9CCBEAE2 -:1082F00069C7F1C530FE363BD6B115E045DBF98CD8 -:108300004017FB22BCA8B716527E07FC6D6D3AEAF7 -:10831000AD94AFEDC07AD9C4178DF54C28574803FA -:10832000E57BB0CF8B1484CFA6524A27B43CB0D79C -:1083300064DBAE04F12AF0A9C5637B8CF4EFC9C3FA -:1083400051923ED48E42E5617B0CB3A318617FD27B -:108350009918999E360CF18574225F3EBE6E8C6032 -:1083600078A0FBF4B518D47B7D39A1FBE504C79751 -:10837000E0671F0F52E3B58AE3E16D5E6F518C8DAC -:10838000C94F7B00F7DDC731AC7E5C169343420FCB -:10839000FF0387CB4D9A54C8953153D5FAC54D1C70 -:1083A0009F37C54409BC7E08F315F288F2175F3485 -:1083B000DD0F0B5E35217F211B03D9B0FF68BD6344 -:1083C000586E0A2C8AA572E426AADF18F3B1DD22C2 -:1083D00068DFEF3C3F4AD08595809C3E25D65318F8 -:1083E000407E4FE51DAE6B29A17C43BA34FE37D0E9 -:1083F0003AC994D6870C56D8F94EA60302ED8F20C1 -:108400000AF447E1FEE750B86BC73BC6E9E09F318D -:10841000921EF19647F2709FBDFF857521EDF29C8B -:10842000CDECD151BEFFB8CE7501FAE9BAFD2DD41D -:10843000CB8F197DD9AD9630E546DF630F49C1F288 -:10844000C53F973D46CA2F767776FDE466BAEEA51E -:108450009DB21D865C7AE75FDF1D037A75A7C10EAA -:10846000E7462ADFEFD5C3BC1B981E794CA7A6832D -:10847000B3DF559F73D26219BEA8DE83FA9CE03B3E -:10848000427EDF4A7C57815C5F461C4648FFB466EB -:10849000D50C42E1B7C2B20EF9D1E76BA7A11EBC61 -:1084A0009278B07C598BE14FA1F26145AB3ABFEABB -:1084B0006175FE56AF3ADF677F2E0F2FDFA7C732F9 -:1084C0003A3E4BD93EE03FB0C1E4053D485BAF9832 -:1084D000D7CBA43CB113F82495FB60475817E1486B -:1084E00004BEBE6E6F69E2C5EC7CF5E7AF21DE101D -:1084F0007D23A837E4126F6CFF7ECB63158423F4D1 -:10850000ABF071E0BC71B62CFC3A26C60A3D651092 -:10851000F627BE8B7E82E345E13CEACF9B07988F2E -:1085200005DB9F5D197E9C1BFAC6B1A9E464B07D92 -:108530001C936BFC1C2DE8A3FE7C127E1779A1070F -:1085400007DBA531FD8AA4D94E4506F994B0638BAB -:10855000FD704222E664B43BDDCFCFEBF65CB05F4A -:108560009F003D08F6E314659F9F4E71D9F7C666DC -:10857000EB8706F78B761D94AECEF843F8EEB25833 -:108580006B1C8E6B27761857D0FBA2DB2B06BBE843 -:108590007CFF786779A26B54283FF530BF8951E89A -:1085A0005F16959C251A39BCACFD2DD4BBA8BE9591 -:1085B0000D4CE7D3BDB723BDAF24CE04A0F39EBDC1 -:1085C000C3335CFF86FC15F399E559622098A79B9D -:1085D00098EEBF2A3E9F591D4CEFD3991D061CC72C -:1085E00041145B021EA5D97C29F3D4D3FC84BEF9C7 -:1085F00083918E90F17CFE12B4A7F09DC053B2D44B -:108600009504F336C1B874BC08E24D82B469AC5D20 -:108610008174A2E4D4B379303C4F260D69505F6772 -:10862000F6CB6C9D740609D0BE0F5E98B7F2FCC6FF -:10863000D9BD8B56C0778B15F98891CF63472CE550 -:108640008766E42F6658B7C9E2FB1CFD643CF594CD -:1086500029B88F3D4309DA3B06913602E35A2CE7ED -:108660003CB0581BB149908FB0F5FAE0FC70CE6673 -:10867000F1E846239FDC190B7C527A6725E085F2EE -:108680006566FF19A85CEFC373B7E073317C7E4D5C -:108690009CCF2513068758E2C0F11EB0AE9C414026 -:1086A0008459D649D07E4BD454F4EF2500E0697943 -:1086B000EC54BD8A6FC53BD5F9C4B9EA7CB24B9D79 -:1086C00037D3933FE88B92CF99742116CF5923C0AB -:1086D000DE62E0FCA299CFEB08A4743DEF713EFD91 -:1086E0008DF513BBFABCEE8E3112B4E32598CDD0D4 -:1086F0003FD557DE8B65FACA271E289703C8CFF3EC -:1087000026B6F9C0AED37C8364BF8B7E6FB62A1BBE -:10871000F494543DD32466C7D1DB4AF5B47C5B8620 -:10872000CDBE89E6EBC17E1D0BF3B7D53C8DF64976 -:1087300013AB4702CDE08FDCB6C966837A71E58161 -:10874000C946D08B5710DB761286BEBFA2FB86CE01 -:10875000F709C853BC489C5E220F29F3710DBC7CFD -:1087600007FC9DC5F2138BE15CCAFE6575E4753AA2 -:10877000C0EEE090512ED677E4BD6EA1E365CDCE7C -:10878000433BBCB39CF97309DFF76334FB6A5C902D -:10879000CEB13C8FE7877570BB6E9C89F96B6D74A9 -:1087A00088626636C0FA718CFEED44FC63FBF25AB7 -:1087B00012FC07FD9507FB473E3429581CDC677403 -:1087C000A87CB3BDA996D61BA3F7ED877D3C8EA7E9 -:1087D000793C7DA3F40694BF9D3A8B62D4B17D6D44 -:1087E000CE0213865306B814DB7ED004FD4C907C79 -:1087F00098664CBDBF09A65FC5ED47D14946EF0657 -:10880000BA8EA6128A67B477FCF920D8A5E5074985 -:1088100001E0E98841C839079ED3157A1CFB1A3A52 -:10882000986C40FDFC2F932AF03B01D58CCEBBD237 -:10883000C61621BE0F2C5F75283F6AE364E437B388 -:10884000A632BF6AFD5CB3579240CE10E677D2BB2A -:10885000326F0AB197083FC4FB0632775798F3444A -:108860006D1CD34FAB66303B6FFD46A3CA7F531DD3 -:10887000C7EC5E33E3268F8C4379C4FCA779715C27 -:108880006F1B4146009F0AE1234550AFABF4ED81D9 -:10889000F88CBA9CF399398E0203EAFD9CDF08BE7E -:1088A000EE1CC4F6F33C42D281AE679306E4FF8728 -:1088B0004B6F457E7313F118006F1F95B17802312D -:1088C000EF5953D57AD21CA73A7FF35CAD1EC5F0A1 -:1088D00021C69DE7529757093D78AA5A0F5EF0FFCF -:1088E000BE8A46B99AF854DD8521E0E760F600C0FB -:1088F0000BF373E8916EDC1B993FBCBE3DEF8D38E6 -:10890000D8677712BECF7649CBD1FFB24B5A1182CE -:10891000FFD45AAF047264B855D87D98DEE4347938 -:10892000F783DFC359831291BCCEE3490E403C4923 -:108930007E90BEAD65561657411CB5309F345BA482 -:108940001DF4FE165D3EDA655BA2AC2A3BFAA60D6D -:108950004A05D413F658C544F26D9C6EC29D77D774 -:10896000C531FEBA59627671CF3C339E2BE3B39C7E -:108970002A3F41BC4C8E829D70649C22EAA3FD6319 -:10898000B3C1955C4053AF44971117D25E261BD1FB -:10899000AEA8E14FF1B176B4EBC70FCE413BFD9CE1 -:1089A0008E3CB42F124B84FD2A29D8FF9CD9DBF4CE -:1089B00010A753DFB14DBFDC12A4BB7BE2B85C8DC6 -:1089C000249140AF7D76BAE74C68A77B5CE7FC5FFB -:1089D000A0CB5AA30FED7121F48ADF07928BAB383D -:1089E000BD18CA9CF356D0F9F5BC6BB4C3F9191D78 -:1089F0006DB4FFE7F744A39D515F45503E6D2C6574 -:108A00007CA407EC5F741D9F4557E3F960A3D48AEB -:108A1000F2A33B6632D2F16ACB013C07576FA574D3 -:108A200018229F56EF50E76B48279EDF6B9FEE475B -:108A3000CFC817051F76EF56B723C3D47C378FCB2B -:108A40008B7CA77D56054C7DAE3D8B9DC3E9418651 -:108A5000AEA3E81D23B7EF2EB09D8A0056FB947499 -:108A600031FDADC77A5A66FB9FC983223E8E566E92 -:108A70001571BDED3ACABFE0FC2AF4B022C2F2077C -:108A8000741D72922E38DF42DE4EE87F424E087C23 -:108A90009596105242F743A7E04F43C950C037EDB7 -:108AA0001FF78904914331D8BF07CE7DE3F878944E -:108AB0001E3C20B73D3AB317E8AB596A4039690606 -:108AC0003D9FA69B2417CA8397AA3D32C07B2C6981 -:108AD000983583D61B6FEE8C0438513A39124A3FD1 -:108AE0004DC497B14B52D111967745BF1D968E84D8 -:108AF0003CF37DC4F498E974C5D04F05387E687A9C -:108B00004062E7C829961FEBA1FDDBBA69482753ED -:108B100089570FF3ABB0A9F13F25499D9FA6F4A358 -:108B20000F8CC37070784E1FA12E77087E47D4FC3F -:108B30002E937C857A18F9C1C1EF805D21723D19B1 -:108B400001FA0DD544711F6AE9E0EBB86FDD6FF2F1 -:108B5000755C18BF490FB7135F4BFC2B9F96FAD378 -:108B600059F71BEBE5A4107A14FBE265038B7F90A9 -:108B70005E65FEA9123319E503FA2A647645B13F12 -:108B8000AE05FA8C09D25D31FF9E11CFE96C081950 -:108B9000027436A13DC22753BCE4F1FEAE05BACB48 -:108BA0000FEA23E25CD154D28FBE32A52CD45F7081 -:108BB000DF097DA4406A6BD267021FB9A709E61BD3 -:108BC000424F43E38B802F517AC27DDA4FCEAACB3E -:108BD00035F426F02EF4E552D28074365BA760EAB5 -:108BE000AB5C85F2B5DC325B0FEDDFAC62F43609CD -:108BF000E8310BEAABE9A5DCACCE6BE9918EA80BB2 -:108C00001D574B9F03D1DB10A037215F632F4D6FA2 -:108C1000D3E3BF757A9B1E7F117AD3D299E05FBBF5 -:108C2000226CE5A03FD7574B280F0ADE1DD604F96A -:108C3000E17599A84FEF8AB6A37E5DDFC0CA0B3BF2 -:108C40001D32C4BD64ADE3E599CE72C8D7AFA7E5C8 -:108C5000B4EBA2232C2E66D89DAC3CEFAE86D7ADEC -:108C6000A0677858FB973F6F96A368B9B799B72F5D -:108C70006D2D877C7D0B6BFF19F8A946437C9AB755 -:108C800009BE5F7D6FA69D1DAB99FE3E91AF7797A4 -:108C9000F4DCEBD8AE95B55B75D03C88E0F99FE984 -:108CA000E5D7F1754EDCCAD61977E2FAA90AA58B89 -:108CB00015010FEA6FA774B5C5C8DF06383F974A9C -:108CC000AD69904EA1EC175287D9DE220F657ECC9C -:108CD000ED74887BE299FD45F8FF20CEA032449FD9 -:108CE000B8279ED96345BD84188A01A08747ACA8E0 -:108CF0005F0BFFA4EF212281BC8735723D24ACBFFE -:108D0000724A5603EA115386083FA55FBF948E9BB3 -:108D100077E18BC9E1EC433FE2E39EE671137D7A94 -:108D2000B237530774B10B88240580F4DEAF417F5E -:108D3000DB057E4826A43CA404F0CAF25BE37FBDB9 -:108D4000A9653C85AFAE41EF01A1962161DCC9CC9C -:108D50004EE21B1CD57FFE53F4C467C4382636FF91 -:108D6000954D541E23D1317E3687E38F8CBF0AE99F -:108D70007736C7D3CF057F2A2005C09FE670BCDDBC -:108D800064A67A34F2C35683866F3C130F726ACBA3 -:108D900080FABBBA5CC357AAF9B82BB9DE7E2B099F -:108DA000A07E724AF2627A7A0BD3DB6B2C4750BFFB -:108DB000E97984E9EDB5C48FFA8FD6BE59B3539DD6 -:108DC000AF6B53E7EBDBD5F99E1C0F8ED3B3A5AE8B -:108DD00018EC8AD50FBF8B76EC6AC15FBC6AFE4285 -:108DE0001571C65F1EBA06ED51DF986F3C4D4F6F8F -:108DF000C5AAB8D0DF029CFAEC352FB2F81437615F -:108E000076821EEB88F9704E251A79A4E527799CA5 -:108E10009F08FB86E02F7984C9237A8E7DD7418213 -:108E20007C5CABD7F5C473BD979FD384FE9307FAE0 -:108E30000FD0D3350D48644139647FDB2487C89F48 -:108E4000798566C073BE99EE6780976CC971595475 -:108E5000F4F005CA9981CF7BEA720DBD88F3D62D57 -:108E60009C5E668127858EFF7BC981E7BAC3B732D6 -:108E70007A99635987F4FAD16A462FE2DC77E5E7FD -:108E80003C87FC4DCE797D741241F55E9A1E4917E0 -:108E9000E77CE68FAF97181DD4557DF818E8CF8290 -:108EA0002F1C6E24F1FA103ED134CD64063B4A9358 -:108EB000819D83AAA67F5CBC3484CF38224A1313D9 -:108EC0004059EE8847FB6C5DA47A9C66A9F3BB7F92 -:108ED00080F3D24F23D14ED4FB304195A477EB7071 -:108EE0008CDB3E6B607E52319F550777EEF3C37E7D -:108EF0005CFFEB083D959F3592F7C55A5AB6C4E41E -:108F0000CA86716A743E23B36376A25F578C3BB006 -:108F10005DD683F2D5F81A93C3016910C6E1D2EF8A -:108F2000D9A1FEB5D1898C4FDF11EB2A48880FCA31 -:108F30004B613FA45296A4C604FD26C1F8066637CD -:108F4000F90B715C32BE6163887D9EB60F1B8F5634 -:108F500096C0F8F5F729CE61DE07A31DE5309FD353 -:108F6000DC8F7B9AFBFD4E47313FE0CCBEFA2C757F -:108F7000F1F434F7139E8E51FB8744BDA509CC8EC6 -:108F800072B2D16CDEA807BF3A316F1C4649EC21A2 -:108F90005303C6932C6078EAD913BD6D5388FFA59F -:108FA0002EA1F4FB309F7FD89C3743BABCF5B83173 -:108FB000D40EDF23B1F3770FA7979E08968A71EB43 -:108FC000122ABF0F78EC99E7473CF6E5C78ABC1335 -:108FD000FBEF99C0F86B5FFE3B2C4FB8DD43D8F533 -:108FE00007F2F769FD7B54D0B0734004B3CF6BFD3B -:108FF000F30B053FE3FEF9059C1F2DEC607E8245D7 -:1090000066D29C4ACB177724B2736E94275BE59F98 -:10901000F7445E513C86A0CB9EF4CE3E7FF62321E2 -:10902000FEEC3AEECFAC13EBDBAD5EDF0309DFBA4B -:109030003FFB818430FE6C6DDCC38BA0470C0BE2E0 -:1090400061AD8DC1AD42AE2D077B6FEF728271E8CD -:109050006BDF5AD604F6E0B53F000B2AF231D4A7F5 -:10906000EB389C075A57BC534714959D7D105142CD -:10907000E69FEC8A51E551430F89034DAD4E51B542 -:109080004F6F18AAAA3F64FD35AAF24C4FBE2A9F23 -:10909000D572ADAAFE55AD65AAFCF087AF57D5CF06 -:1090A000234307A3FDEC900CB62172B5B74A553E99 -:1090B00072E72DAAF69F9186CDE369BDDD42FE7968 -:1090C0001C9DA38A8371CE396D4B55ED9BA4B6626E -:1090D0001FF0469FE49368BD151C5FCB3B99FF6270 -:1090E00074FB6A55FF67A3D83D18AD5F96762EA333 -:1090F0001ED62E9147A4FE7EDAEA8EFB9B21EEA8B7 -:10910000BFBF96F24DDA6E353DBF80FEA6D56F8E9D -:1091100026703F5D0A496174ADA50B0BEA7FBD5B0C -:1091200065B427E691EC87C623BC0CC4ABF4C75FDB -:109130002F6176AEDEA7AD7688FF59F5D632A4470B -:1091400053929A2E2214355D448E50D385D5AEA607 -:1091500083C1256A3AD0C23DDAA1A60BE2A7FF433C -:10916000E02DE02AE01E3B554D375A78E79300DAB0 -:10917000D9DD5EC9EE2361FCE2EDDB705D97D21FA5 -:10918000F5896AF8161C703459106E2CBE4CE861D3 -:1091900026AEFF68FD1342AF894BE47A15EF47F81E -:1091A000179A250FEA517DFEC2125F862F13F4A78E -:1091B00006C2EC44CEA4C4F07646FC3E909D51C05D -:1091C00075F620262F6B8803EDE12B880BF9DDC99E -:1091D000CA5BD13EB4CAF263F4BB9EAD627A52352B -:1091E000F1229FBFE2B802AA879210FBAB168E5203 -:1091F00087E4B302BFE1F22085740879E0C27813F6 -:109200004A86E662951F47ADE782DF30847F09BD5D -:10921000578C27E029F89A18CF441AE424D8171A53 -:109220003E474668FD486A3B8DB0F3E06021FE2270 -:10923000AD5D26440F6E91E938F290CC2642F1578D -:109240006073A0DDAF8874CE87EF25E6B626BDC279 -:10925000ED1357933EFBC480F2EA12FEE8591EC993 -:10926000FF68667F3FB4F06BD3E59FF8036D3C5E0B -:109270005210EF552F0F8F077AEA6FA7B41F7D8525 -:10928000F623EB02B1A1F6C3BEFB06921FD7731300 -:1092900071DC4D42F41037699B3C3F13ECC4544ED3 -:1092A0004641CAEC58A45DAB07EBD18EACA32B01B1 -:1092B000BAAF21217EDACC6039E6E5FE7911377448 -:1092C000297DE242A28DC73FB07827C2F9A0385F5E -:1092D0000E749E13711470CF16FC21224EA8399182 -:1092E0009F8373492EF44FF7DBA644B41FD0FD29AA -:1092F00085EEC7BEB8222CEFB71F35EB177114B23D -:10930000B510ED42CB42D77B19F0107ACB6FA83E57 -:1093100080F7341215A6D70D3AF681038A0B3B5518 -:10932000719EF5467A80017BC18B3C8EAF4DADAF0F -:109330003F9BC8E393F839E752F01A181F3CEE4EF2 -:10934000E0E332F530117727E0F8427FB8EF51C102 -:10935000B5EFBCD807F73DE1E02EE072AEA8F329E7 -:10936000C0976C3D9200F0EE8872EE83FAE947FDFB -:10937000A7245D705E157217C6CBF6B6CB783FCFCB -:109380003D81C55BB9F7C8C81ABA3B4CE837AD6E2A -:109390007F1DF5C2AE46CA68A91E76A6910EA9BF6A -:1093A00088BD4003EF81CE47623D1F68D62FE2752E -:1093B000E83A7F7F0938FC3E1C1C2AE45183E19E79 -:1093C000575F9C913E905115421FDA756CE6F4B0E0 -:1093D00056EF3C01FD1DEF4CDB0CFD55C81D07533E -:1093E000003EEB24BC7F35D1C4EECB26F3FB7425C5 -:1093F000FE063BDC374E4AB3E0FDA9E1DF919DE07C -:1094000017FE78DD6D31704F4CF43F5CD2E1FD4EBC -:10941000429EFBE48E42F0572EB06FA2B98526160D -:109420009791F9DD485F16E523AF1A8919F6A36114 -:109430006803DE6B0944CB68B78C93C924A03B3129 -:109440006F711F567C87FBFA70EF527C9FD81428EF -:10945000584BD30E4E0F62DD13CB03050D9620FC47 -:10946000455CA6163E5B383CDCF1C666D017BBCD2A -:10947000E2FCC95262D3239F596766FBE6D855E2E6 -:10948000FCEDB3C2B9D41DE1183C06F6DFFB32791E -:1094900092267FB1390647E3FA15D4C7D7D958BB0E -:1094A0006E1E07BFEEA3B244885F8E6F0A1F6FA6C1 -:1094B00024B1735C2DF7EF8BEFB57A1FC68DD542C3 -:1094C000BC7641F0FB95C66B8B78FC01E110AD27B3 -:1094D000FAD178EFDC79B17AAFFC4B0E7BBEBE3EA1 -:1094E0004927E20FD1EF4DCF5B61E30B4B93D8F9E6 -:1094F0002A1807E8C77BC37DF1857B4A13C945CE8F -:10950000FBEEF30E55DC9F8837779F9F84717EFDBD -:10951000FAA5FD2996605CE140F0DF92C8E6E58699 -:1095200078BF82D0EF0AFBDE374E1C8FDFF347C1D6 -:109530003EFD45BB8CF7EA7F714837757B9879D73C -:109540002731B85D13AFC77D33D2471CDBC28C2FE8 -:10955000EA89FB35E29EAA767EBBCBFC8B60FE10CF -:10956000471C6EBCA59C8EC4BC77C7307CB8F799ED -:10957000F09E05ED17E3BD77C7F857E2BEB0A9F13D -:109580007C3BB7D7ECBEDE9F81F7BCA6313BC34026 -:10959000F4E08D72FD04F5D89B69654A3FC5FA0673 -:1095A000C916B2FF2E450F41B8EB5478ED0F772363 -:1095B000E257F4FBF961BE4F89C302E7B7255CBEF1 -:1095C0002DD95183FAAF381F7DFEB08CF1179F1350 -:1095D000E627F9BC55C2F3CF521721EB291F5AF9E0 -:1095E00064413388B92549845C17C3BEDF09E94665 -:1095F000B59F7CF9BDFDEC872454AEAE200D2857F5 -:1096000056FE58DDAE9ADCFB67D09FB4FEFBE1DC72 -:109610002E27D6B139899E4740EF2926C5201FD66F -:109620003EF985314A19781F9CA67C77981EF8AFC1 -:1096300019D3AE461BA6BF48723C9644F1B727C962 -:10964000B50DD29EF759FFBDB5BD4C7E6C8D43B9AB -:10965000D564FD2EF2757908E3EBF7C03B09141EC3 -:109660002613D39712740D7214EA2D5EA487E3F1CA -:109670006BAA6662DE9E04741FF7CB295331CEEFCE -:1096800097910E80F7A652471ED8253655B27B9982 -:109690006613F3B37B7F31F63570830C6BBBBF0C65 -:1096A000CEC1B68EFD3EB0F7B4E8FE7C10E2575A4C -:1096B000AE63F18B093AFFFED490F1E223BD49E09D -:1096C000878F1F69C4388F38B934AF21245ECACD63 -:1096D00071D1DB9E8576C21E83B01BB645E0BDA866 -:1096E000DAA183818F5C43189E45DC1BCC2154DFBB -:1096F000EDA27084A04B91BFA64DF219A2F0FD120D -:10970000F4E3D4DEE54B980F72EAE77AF48389F943 -:10971000C5BD9A5C06FE2E219FE64B366647E3FAEE -:10972000FC3C22FE317FD95C4E27F3B81E3F3F92AE -:10973000C17B29B16740BB5BCC244A47B7D4FCF25C -:10974000B6225C678D211AF405E1F71958CF086F2E -:10975000FF723F6565F78DA54036747286C2E76279 -:10976000FB30C0F9B23B9BDDBB23C38803FC8CEE0E -:109770007DC3B7817DC23488F9AF297F3297E4A3D6 -:109780005E6D8673D4ADAF44F0F8222FBF4FECC8A6 -:1097900083F89CFAAAB47C8C13391AC07737BA0DB7 -:1097A000FE0CDCC794EF4854360EDAF2FD197AB895 -:1097B000AF9942F5359A2FD9722FCB0FF5AFD4D18F -:1097C000FC922D4FCDD0D3FDE1BEC67F0AF2355BB2 -:1097D00076B17CBE7FA54CF3CD5B5E65F5E160495B -:1097E00009ECC12D07677868FF67A2B9BCB7FBF128 -:1097F0009EB5FBE5E1BA503B6B6332E35B67B89D16 -:10980000F84C26595C05F01E11BEFEB2641D0F5ABD -:1098100069C554AC57B42749E1DB25F3716EE5F710 -:10982000A32746929608E6B7F344513C1CE8188EED -:109830007EC7AF9362989E6EF3E3FB38A21F014F81 -:10984000D19F187735C867E0CB9A78ACEC64863F37 -:109850003ACE461C679883DD2BAE4ACB03FC51BC45 -:10986000E939DEF4ECFCBB8DCD8FF61B9D8B72A02D -:1098700000ECF807BEA2F53383F3D6D24941329308 -:109880002FB736317F6B203A0BE96962247F67A5D9 -:1098900050BD8E660E87C6E4687E6F46C02B51C2EF -:1098A000719A381CD3FC78CFF24AD75DF11F5A77F2 -:1098B00008BE1CF05ECA81F6ABB7B3F5C4F07BCD31 -:1098C000FE8C18D4F7EE57F5776683A67D09C1B8EC -:1098D00036774C16B6BF278298F13BD9DED72E33A8 -:1098E00097E9ADA0CF8A772C88E73A12EA47EC7B5C -:1098F000AFA28DC56706D739A390AFD3C6D769632A -:10990000EBF4AAE8951C0964CCB6F6A7E33EF8F799 -:10991000F5372A9FF7A7DAE7E1FA837D3D105ED697 -:10992000733AF9D6F022E6A981671F9C35F313F04C -:1099300084FD8DED46A9E952CCB326599C9335FBA5 -:109940003BF31B8E57CADAD5DDCEE2B989A2A6EB6E -:10995000BADD993A882B10ED6AC127101FB4FF3D7C -:109960009ACCED8969246D80F8C4C7938BC2DA0D57 -:10997000F1BBF69CD813CDE2D5B5F68A9E787B274D -:10998000DCAFF49C63EF0A8CD3D86FC0CFF49C2576 -:10999000D82E285FD4F9739C3FF6B73F0532607E1E -:1099A00085A6B2E7153BD547B61C437E5D38B8ECBB -:1099B000B64C9A7F35F98FC8CF0B53CBBEC8A4FCE9 -:1099C0007C7FB29FE547967D3114F25BFCACFE4490 -:1099D000C7F3C0EF89C73F63527250AF782D59412A -:1099E000B8C9E53A027464022586AEC7F4AA09E351 -:1099F000F6045C074A0B4DBA8670F76FDFEEA307DB -:109A0000E65729813F15B0F3713B805FAFB203F495 -:109A100044B17BDF3D7BFF8EF75D3E487675021ECD -:109A2000EA23BB1665D2FC5D919FA01F4F72D03D0B -:109A300001F615C54616D0F94A5D9B9CA03F91D50D -:109A400076B31EE1CAED5E748D1728FC5ED9F7F37C -:109A5000EFA5B2619C308FB19C0FD4EFFBF26FE0A9 -:109A6000F7AD3F63B183F97A6CC796DB40FF1ADB31 -:109A7000F1F6974C0EB3FB3962DE63C1AE49BF9776 -:109A8000B49B70FE633BAE5E01F5C7FDB6230BE8E9 -:109A900064C2315F13B0859EBD2FA5AAEEE590CFBD -:109AA0002E1AD739A0DF4DC0E353AA540D4678F4DF -:109AB00032787C85F167DDF1879BFD68FC54DF7FA0 -:109AC000A2FA3AFA917BC9203BF833C47D7AADBD46 -:109AD000F468255D1FFD3E21406710A24F4F3C6F8B -:109AE000A68C24982F25D1AA7CB9395955BFC29686 -:109AF000A92A9F9274B5AA7C9A92A7CA4F1F315681 -:109B000055FF067BA92A7F63C93455FD4A47A52A1C -:109B10009FE76B53D52F38D4AE2E3F4264C043FE2F -:109B200051FBEB90169D74A0D9B5F874C3EB908EE1 -:109B3000FD0B0387D65E7CEDF9B6D7E1BBB0176BA2 -:109B4000EF3309FBF1CDB2C56B0C6F274ED2670521 -:109B5000DF1F9075EC3ED318ABEBEA94A2E07DA634 -:109B600089602FA648A8587CEE47E3004F0B983D2C -:109B7000ED282006E3BEAD68873C6A6878E60F2CC6 -:109B80000E201DF8DE84C05CD5BA279E77A9D65D6D -:109B90004A6ED5E0698D2A5F61BB5D557F4AD2066A -:109BA00055F934E5071A3CDDAFCADF60DFA2C1D347 -:109BB000360D9E7EAE2A17F4DDC1ED5AFBC01E4560 -:109BC000D3F1FECE72C0C375A703888F92CED67232 -:109BD000C0D3B547DB105F853E6739B0CBE2430D9C -:109BE000AF43EAA3E73168F75A6312A6071A15B420 -:109BF0006B1D6C1C81E9A1463B7EFF756309A6EFD6 -:109C0000343A307DAF712AA69D8D4E4CDB1ADBB005 -:109C1000FE738DEDCC2E16DBF7DE453AD807BA750C -:109C20007E377882173F927703F0CBEE41FE6EC805 -:109C3000DF45EC374CA2F925C044E8BEFC294F377C -:109C4000A43A028057371CCA8A82F1186D3A471E1F -:109C5000E8E177A44CF8A13E9D90BB3738936CD1D6 -:109C60002C6FA6794436C6B34DF8A18312D73320A2 -:109C70004AD0A933E106C8F744B07277CA841B40C2 -:109C80000FFFC6FE73473FFFF91D2961FCE7CF9C1C -:109C900056AC60D739FCD5702BC0E330B76F39486C -:109CA0009E61094D4BF5790690B34707B8B7F08030 -:109CB000AEB409E0D0A6B3CFC178EFEB0D04E8B79E -:109CC0004A62E75F51CF95CAE441CF0D263C4F1D54 -:109CD000D13956605C9914780CE0BC3DA512E1DEE8 -:109CE000630D6400FCBC294E968F0F3C26D943F2CD -:109CF00006069F07526EFCB6E1F35838F83C9162B5 -:109D000063FAB6CF910E7A80C81FA974D4C17E3E83 -:109D100052EAB80AEFCF384D6CFF3AADDEABD03E19 -:109D2000E4289A1362E719926A60F7D1E16222D8B7 -:109D30003B6F91719F6BE1392195E97B482770CE8C -:109D40009C1789E782233AF69E81B6FE020ED7B3AE -:109D500083C2DBE316A632BDA26C56DD332FD0FEE4 -:109D60007AD64560D73DCEE1A88FF53450E82A3445 -:109D70003DDD708E959BEC1C24E8BF9D0F7FD1F2DA -:109D8000673A6EFBEBEF68FD4FD645DA5186D8AEE9 -:109D900041F8DDC22B2F8C35A3FEB4B02ABD0CE4F4 -:109DA000E27CEE075C64D527A03B501F6D8427172B -:109DB000975BF29A2904C9CAB84A233C25559DB637 -:109DC000A619D2D5C3EE37C21329B5A37635831AA7 -:109DD0005B47B77011F23FFFBB8D745E8BD7CB0A28 -:109DE0003BCF89FBAE355714CF22E8F7088F3BA253 -:109DF00040C0F3EA220E6FD16E1187D78914AE3FAF -:109E0000E6909C0B6A3FD66740EF5D0BDFCD1EC02E -:109E1000CFA02EE7FAE3074636AEF6FD1231EEE2AA -:109E20005476FE3A62A49409FAE42D4C0EE4CEFD79 -:109E3000E2AE22BAFEDC0E9B0EE31516D7BD00780B -:109E4000E86DE778349076D84FB33C4B3EF91D224D -:109E5000264E758FF752F2D2DE692B0F9597857ECD -:109E60006779A8BC2C09B496835C14F251F84F7D35 -:109E70008DD59C2F37203F3DD0B81EF3071B3D9852 -:109E80001E6A6CE17CB915CBDF697C98F3652FE71E -:109E9000CB3BF17B47E35C4CF735BA583ECA19958A -:109EA0000AFBC4ECC2F8C437B69808F8E77A3B4C12 -:109EB000189F4177C4638FC641FC9109EF716AE333 -:109EC00090B47CBE8F1E76F77B372505C6E98B1FC5 -:109ED000027D71C8C0F474982856E04BF98FFEE4F7 -:109EE00006D0AF0F2B8A15F4E982D4CD2CEF50ACFD -:109EF000069A2F7C94E75D8AD504AC22F521E45BB9 -:109F0000873D8A3582E68B1F7D88957B093AF3C7AA -:109F10003DBAF5060FF059221D80FD516ECE9C44CE -:109F2000C50595D7A507605F4C495A3209F6C5CEDD -:109F30001405E9639AB2E100E4A78FD8A687ABFACB -:109F40000E4BDE4668571657A9877693D2D66C8497 -:109F5000769387DDAF0F6D3775D4AE8D909F61DF3F -:109F6000A607FD7427F0B1F8603F222FCA059F169F -:109F70007172A33B9C280F72DB9D280F045CCA669C -:109F800057DE0DF6CFFA76C926C13C664B7D410AF5 -:109F90001093E886F74929BFBE3EF597D60DB45D0C -:109FA0003DE4AFC5FC0F377CBBFCFBA6D430FCFB0B -:109FB00043BEDF41DE43DCFB8746F60ECC331C2E6E -:109FC000F51D4BACF88E2A715941CF7A9ECBF39791 -:109FD00020A5E59FF1B48B7F7F40E770C138AB527D -:109FE000B91FB23F7FA84965FB5F738F648072CE53 -:109FF0001FEA526DAAF73CEA08BBBF76A9383B6D51 -:10A000009CB836EE6435693BE8C8EC1F6F520BF71D -:10A01000DCB2FAC77F8B786A6D1C78DFB96A10E30F -:10A02000A77381D750BA6E491D904FDE7B0938DC8B -:10A030001B0E0EFDD643589C7BBF38241EEFAE5D31 -:10A040001771C5B3778D79FCBB767D822EFAAFAFE1 -:10A0500095C15FCFE04FF5BBC7607E158BAD04ECBB -:10A0600056A1FCE77717E13F5A7EF66DF1C99B17C1 -:10A07000D7E1BB6561F8D8F3E1F898B8CFAF4D856B -:10A080009E0AF7F3201E12DE3982737E65A26B1FD3 -:10A09000F4D35316F89B0ECEA171ECDDF083D1AE54 -:10A0A000FDF05D32B2B80611977C5AE7F915E86DFC -:10A0B000EF3DFA19F2B36E1016748FBC41F3A097FE -:10A0C000FDC3E67C13E04746F88DA1EF8F0F147FA8 -:10A0D000FB1B2EFFFAA76CDF8938D49E6D5F66A04C -:10A0E000FDEE12FB62207854C8E3FD703FA4B72454 -:10A0F00012E56797447CF0DE71576902EA2D5DE94D -:10A10000463DA4DFF6B9B82B3D1BFBD79E8FBB9213 -:10A110004BCC6CDCC953217D2FF95421C8BDDFF035 -:10A12000F8CB76A3A7E03DB00F8F8D40FFFE8D9258 -:10A13000BF10E0A03D5777BDB5A04CC9ED7FBEA6CE -:10A14000EB9B04EBAB3DAEBB1BBE5DE979BB76FD83 -:10A15000DF08C4B98F5BFF1581F7EFAEFCFCDD199A -:10A1600093AB805EE16A021219D345F5099ABF5498 -:10A17000FCD639899ED33343CEE5256FB3382E9E66 -:10A180006ACFE7FDDE095CED51C70D96FA8A305EB5 -:10A1900045F647E1BD601D7B6F43C473BDC9CFF376 -:10A1A000F4BC3E240DED709D19AAF3FA1D1F2DFA83 -:10A1B0001EF281088CEF78A6FD443CCCF58F9DF112 -:10A1C0003F794509D277BDED6F24F49DC0DAF5BD26 -:10A1D000AA7CD786E0FB56701FABF65F32CA252AF1 -:10A1E000C75A104FE435E3DA10F94ADAFEDC07EF1C -:10A1F000D194DF5502C050BE36CF74D07695FC3C6A -:10A200004448E48D0EDAAE929F1F8967252B8FE7B5 -:10A21000F53D9FB07CBA28FFE34CAC7F95E86F1CFE -:10A220002B4F1679DEDFD5229F782396678AF62595 -:10A230002C9F23C6AF64EDADACFEE4ADFF9C097A64 -:10A240008DE0F733D2B89CE0EF5251FEEF4C2BBAC1 -:10A2500068BC8EBA9CCB07F10E55C51DD322DF8595 -:10A260007DDC2661EC61ED9D06B4E79F8D69CB0D29 -:10A27000BD2F2FE27A9CE5568CF3AA7B71F8769974 -:10A28000C73B811EB39CFBE92B640BFA617AEF6537 -:10A290007C7E203D70E5FA9755F8EC57CEDFD3462B -:10A2A00047251DEFDC0F13F17E0219D689F102EE6E -:10A2B0003449C427E0BD6A11571797451C707E8E3C -:10A2C0007B2982BDA77AB213F9EFCA97987DBB6E3E -:10A2D000CBEB28EF96CA0ADA97BE1EEA5A07F0E9D6 -:10A2E000B6B2772F57AEDF87FBF431C5C6FD60816C -:10A2F00051A1F0BCB33FFC3D69F11785BFBAFC3FEB -:10A300000C7FAD5D5DDCD75F7D85F17FDD56E607B7 -:10A31000B6733CFD49A71473783D02F03AB7A233F7 -:10A320003B5A8620EE4E8C77AB90DF2982F3566F36 -:10A33000839500DEBBA5CEDC0FC3E05F7BAE389F0C -:10A34000415471693BFBC3F7E94BD0F7D3FF4DFA9A -:10A350004ED4FB8D76F01B1F65EFE51577FEC9180F -:10A360001A1FF44E1A3B070F6E677E311117172C18 -:10A37000B7323C71FF535DD53BE3C1FF24F6C3C444 -:10A3800048D206FE044AD7764ED776A06B41BF412D -:10A390003F146D1706BE41FA252C2E91C3E9B7FD77 -:10A3A000E1FAE125E0FAE17F13AEBBA93E8CFEDBCA -:10A3B0001722D04EA385F33F385C05BC23D32F0E64 -:10A3C000E7C8F4FF0C9C23D315959D43C07B20F96F -:10A3D000A4C58F9877987D5AF44DF6E923199C4FC0 -:10A3E000E9FD188FABC57B4C7A3FBC27A45F1CEFFF -:10A3F000EAF2FF30DEB570D3A6B5DC9FABFD5E9808 -:10A400003E20BFFB56E0F87FCD4FB0B061BFAA7CC5 -:10A41000F1FAB754E54B3CEF5F965F41D8FBFF5B29 -:10A42000FE05E15798F9FC2A1DF81FB5F24137C423 -:10A43000F923A0C71B5FFE7AD48730F9EA6C8CB78A -:10A44000BA8DAFE58BF17FFFE47B94BEBE6860F60A -:10A45000D663FB3F372839FDE965E1791D7184D06A -:10A46000D9C2F5EF1B40CF5A48D8FB54DAFA0FA6F1 -:10A47000337B30C64951BE30D74C0C71941FCC9DF4 -:10A48000CBEE4BCF0507630CA63E172D9FA9273EA9 -:10A49000788FBBD2A2F799D0EFA9BEFF6EE2EF751D -:10A4A00093B858D53D78D921639CDF9C12E62FBD27 -:10A4B000C5D286F787E71DBAEBDCF7602F6FF4147F -:10A4C000B1B87771FFF0F7BA2BF1833E087A2A9C76 -:10A4D000FB24EE5F5F6340FFBAB6DD2ABE9F66CA0B -:10A4E000128BA3D9C3E233C5FEA4EB3B64CA67F762 -:10A4F00060E0F7482A1B0CBEE1B9A067EF473DBBFF -:10A50000BE64432EE0AF7E9274DC941B3CEFD4AF6C -:10A51000FF0BB6D7F2676D7AB9F6D54F1A0F21BD8A -:10A520008873D1B1461FE6B5F6D60513FF17FD9324 -:10A5300063FFE26D8274DC578E0FC7D075FB1B3B47 -:10A54000FF2D7B82B02308BB82D64E21F88878BFCE -:10A55000D2976EE3EFB296A2DF83E8592AF8EDC1F5 -:10A56000FEFCF9D7E917D727D5E5FF61FE7CB9F4E2 -:10A570005F9BC4E4AA96EE8F56FD0CEDCF82BEB56C -:10A58000F4BF006252E8F80BEA25BC273E7755ABD2 -:10A59000619CF4CDE97DB5E56406839B462E5CB1F4 -:10A5A0003C50783C878CE70B93BCC60E760F8187B6 -:10A5B000AFD3D5EF0353BC48191797ABEAF2FFFAB4 -:10A5C00039E0E4A26F2617894A9F48CBE8B76EE5C9 -:10A5D00012EB56FE9BEB0EB9A7B448D605EFE3404D -:10A5E000FC35C481F678D9FDD4EACC56FCDD0352A3 -:10A5F0001288027E77EB5E99FD9E8EDEA14F0E796A -:10A600003FAD8BF83E007A5C359EBD3BA48D9B76BA -:10A61000F378EAD596DD78BF51FB0E9A88CB76F3B6 -:10A62000FEB4EFA189F6E29D03ED7B685332781CFE -:10A63000763EC967712917E7A3DD20CF43FC35DDDE -:10A640005F35A25DE1C6C74AEEF3A405F13227A348 -:10A650001FDF99977171BEA32EFF2FD3AF6CDD81E1 -:10A66000F7D8AE947E47643ADC407F822FF7F19BA7 -:10A67000574CC86FC43BF33D6B9EC1F7877ABE242D -:10A68000E897BDD43BE313BBD835C40927BD4D566D -:10A690008AD771C73C68AF1B7BC485F776C7BCE31C -:10A6A00080887F9277C029C3BC853E23F49B20FF1E -:10A6B000E2F7D9789CD5E5F2B92BF537FEA7FC8CEB -:10A6C000E25E5DB7C15704BFE7E0D91381BF03A1C4 -:10A6D0009DFF9319BA8BBE93DC11E57A12F0348B8F -:10A6E000CB09F15E7285CCDE49EFED94D15EB8EE18 -:10A6F0007F7EFBAB47954BDB15EA6DBD61CF6522D5 -:10A70000ADD7B17B2DF9E50AC649C2790DEC87C2F8 -:10A710009EA8AD7F4A297B2903ED5BE3F13DDADE9C -:10A7200087D97C06C257FDFA008E3F60391FBF7E75 -:10A730006F912DF49D95F3197DE743DB297310DFAD -:10A74000974B17FFD7CE2D3365E291A87CCD91BCF6 -:10A750004CEF254CFF5D403A315D440298BA08BB8E -:10A76000CFB094D8315D4E9C98AE555C5D191837CA -:10A770001448C0F8D317FF390AE8E6DC75E35A211C -:10A7800046F1DBF22369F5BE9E3C85BD97F4C23FDE -:10A790007F07F4D9F33F86CBE21B47A21C6448181D -:10A7A0003FD37BA532BBD754F25DDC17E2FD5D32AF -:10A7B00089F9E1962766E2FE09F2CDC46D826F82C7 -:10A7C0003F39E7B88EC5C3DC2AE17BC6ED7E1D6E3E -:10A7D000B19C15995EF8DDB9F6DDAC3CA72EDA2BFD -:10A7E000D17CCED80856BE26DA0BF74F16123FEEB4 -:10A7F000CBC570FB4486FB4B8C2F8ADF0BA02782D6 -:10A80000A1126DBFA2C3CCEE5110FF30E0FFB970B2 -:10A810007E0A174F3384F1F1D14319BF1F5DA6B6ED -:10A82000870CE5E5F72965DF0778B40C71640D81C5 -:10A83000FA319D9B1E2C043B908E809FE6B3B1B7EE -:10A84000A35F53B47B51291B01F59F9558BCBF678B -:10A850002FBF6F4C0209A1FEB1B54A792ED42B1A35 -:10A86000C2F8D3407085DF517486392F8AF8D1D170 -:10A87000706643BB3CC177D29E95587EF2E35B6F16 -:10A88000DC68415F8207F4E31715D744186FB49171 -:10A89000100BCCFFA7FC7E1B69C800BBE8AAC74C05 -:10A8A0003AD02F3EA2E218EEF7FC819EB721FD9828 -:10A8B0009E9B21FD233D37437A9C9E9B213D41CFAA -:10A8C000CD90AE386F87C7CCC989218EB9D0BFF083 -:10A8D000F769E75B3984F1D7BEF1F71A71FCFB1415 -:10A8E00017C2B70FDF7B08FEDEEDB3D18194988BE2 -:10A8F000D05BCFDEBFA39F7420B808FFA3B67C0A4D -:10A90000C76BEE6E3DCAFFDC767FD4CA907A2B8788 -:10A9100018B17DCE0B27A3A0FF6E5B1F7C1D125DBF -:10A92000F24C1DCBAF7CFCB91B378E82F93BBE0FBE -:10A930007441F7F96A4873DB7FFB00FC5E2AED1F68 -:10A94000E3247AA4C0663C2F68D6A1858358D7B388 -:10A95000D19D9BA0FDB32F0C859550BE43D8BE0161 -:10A960003A92C2AD7703AEE74653A010EE0BDD7806 -:10A97000410E1BA77D9F528A704E067A43FEDDCAA8 -:10A9800053465F026FDF747F6BFB23E2FD15E0A58A -:10A990000AC8A5AFA2402FACE4F104EDBB87FD06C9 -:10A9A000D6E9392413F8BDDAD131EAFDB78BE34992 -:10A9B000A4397B8D4EC0D7B37B4F0D83F789297E99 -:10A9C00086C17BC5DB865C45427FEF3167EC978FA4 -:10A9D0003C1887F5F1F769E7916D15103733DFBC47 -:10A9E000FF0D58D242DBF10A889B599C241D8474C8 -:10A9F00089923919E265C47D8365234A0FC2969A0C -:10AA000061AF447DAE14984C887C283747F247D814 -:10AA1000853C8A55E5A724A5AAEA4F53B254E5D34D -:10AA2000478C54958B7167D80B54F546C70486C282 -:10AA3000798EAE83BD03FFA48CF186392F1CB97EBD -:10AA400024CDCF7C6A0EBE43F92C2F9FF95CB91739 -:10AA5000F0D143E169A40AD5E9921F6C7E103AD384 -:10AA60009C176AF73E71D0A15CC679E112E7848138 -:10AA7000DE4F16EDB5E704CA371F00BE39FAC5D957 -:10AA800036F0DB3E3BF6CB148847FDCD10FEAE0C16 -:10AA90003F3F0C44377DFB435218DDBC259327C351 -:10AAA000D00D44F2323A64E9CCC3EC7EDE95F2B5C7 -:10AAB0004F81AFA1BDC043427F7F576BDF1B6DB499 -:10AAC000FFE636B047BD2BC30DA5BE7B932BE16FD0 -:10AAD0003948EF64F9B6BB93E3F0BB07F46137B7CD -:10AAE000F70D52B83E55BBFFEEE4C2603959775CB2 -:10AAF000559FDC2935ABF21B33D5F97B4B9B43DBF0 -:10AB00000FA48FAD7C7889D19503F76EA5B0BF37C0 -:10AB10002CE6F3FF010980D5200080000000000032 -:10AB20001F8B08000000000000FFB5190B5454658E -:10AB3000FABBF7CE0B1960782810427798440A8444 -:10AB4000895728B08DA01ED7DA1A4C8F545693E53A -:10AB500003794DE0B6F4D8E318AD8FB6076D5B69A5 -:10AB60006B355696E7E439B144462536AE5B49EB82 -:10AB7000D654A266E499D8424C70267A6D9D5AF755 -:10AB8000FBFEFF5E672E605B9DD64EE79FEFFFFFEB -:10AB9000FB7FEF279014CA70CE0008F6ACCC7099FA -:10ABA0000106F7D61AE41880D3F4EFE2F0DAB8F928 -:10ABB0007A8303CF5700383ACCE3CF01D601140390 -:10ABC0005C29817BA2F3145960E760FF65F1BD2F1A -:10ABD000010849009E178DDEED5684E35C06676E22 -:10ABE000F89E8DF04E0618D972FFEFBF2AC2F525E8 -:10ABF000B0E30E8CC4430DBD9BD7755C1471CD9F23 -:10AC000004D7D17779968098806B7055B407E200AD -:10AC10009A6A633C623E9E67860E992E04C8F1A62E -:10AC2000B59B52018E8A22C039440778A014EFE305 -:10AC30001B045F24A739EFA4DFB9C867CC2FC7E78F -:10AC40004532B035BF3294E9C67BD77E87E71CBF5B -:10AC500003A291CE3F804A8F034C5C2E04BBBD19EA -:10AC6000FE3F233F4DBD1218909F61F01DBA5A6000 -:10AC7000D7CCA925002BE9A74CFB1D0690D86F194E -:10AC8000707F95B2BFB27CE5A5108BF056FD4020D9 -:10AC90009BBD0FA7F1FFD57F6F3798F17CF553DA95 -:10ACA0007D420F53902FE5FB3AF0B377EB77E23D0F -:10ACB00053F85E23DCFD9984EF367669BF5F24C7C5 -:10ACC000240DE6E08F0228382DB16D91DE6B36F150 -:10ACD000F7E64ADFBD7B09EAB1E925C96EC4ADD10B -:10ACE000DDD3E200F98339A8E4D4F1F26BDA8C7A8F -:10ACF0002A0CC3A7764BF3BD745F17CAA89E315EBA -:10AD0000CE60C9E2F82C1C5F73C5D70B01F135F793 -:10AD1000E8D0D07E00CF4611E4083CCFED31AEF252 -:10AD20009AC3F4072D9CC7FC9E2F1366E7F2751D8E -:10AD3000D101ED1C2F70BF9821803E09F141B56013 -:10AD4000DF8E4B5F4F7225C9BF4F009F5CC09E587E -:10AD50006442FD5CC19FA37D3324E08F946C1DE1B0 -:10AD600059A8C8FD8AD27F7C23E0778B7B164F439E -:10AD70000AE050D7B23ED40C6C906D0CDF12F0E8B4 -:10AD8000492F7DF1CEF416A4F3324960F6DF171F88 -:10AD90001A16107F5F45B4D026B0F7EFA4F755BE62 -:10ADA000FAF4CE7437E36B8E6510F526382E904E8C -:10ADB000478F974758AE3A1854F52B7177217F9CEF -:10ADC0002BDD3EFB12F4DBD1A5603122BD974B6831 -:10ADD0003808C3ABDC8FAB49D63351AE823F81E834 -:10ADE0006C96176E91F1BBE4D67B41971821371D05 -:10ADF000F733552FAA1CC7D3A1E22DF73B90BFD143 -:10AE00001D02B39F46BBCCECB3B1FCE4834B107F77 -:10AE1000A35FB20B48CFB2EEBD47487E1D6B3B40EF -:10AE2000771E40E7DA6EB62E33997D521EE38BD93A -:10AE3000AD8846417CAD5660C6A7357C1EE67B0CCE -:10AE4000BC513F7C06CE043818EB7C9EF85BF3FBCC -:10AE5000CFFB9610B51BCAE3991F90AD9D1BA63F73 -:10AE6000DF006046FA43DBA3BD4F303C68AF25618D -:10AE70007B3DB127EB700B9E9F7853CFCC755FC5A0 -:10AE8000C3A76E4178CDF66826E71309E049A5F31C -:10AE900027A67B3D7861A518EA6F21B977C6D8B798 -:10AEA000E3F9F147A73FBB13E1DA67A7D9894CF271 -:10AEB0001F19E57D3C1D01DA7F3E957D07291CEFBA -:10AEC0000AC52FA56766DC574EE7CF24DA098FAA9B -:10AED000BFA147A31C80F2FA127C791634BD93827D -:10AEE0006750C487EBC49DC704B4CBDB0CAE83C4EE -:10AEF000F7EA47FE7AA80CF9A97AE6370FCF44FAA9 -:10AF00006ADF9B0CF44E58AFE3E2406C2097FCDF05 -:10AF1000C6FD5F914FDD8E28CBC71171A6A1235EC0 -:10AF2000033775A75A3E8E883775C0650CF5828E3B -:10AF3000F8A957FCAA5E741D25BA1A20C0E3228422 -:10AF40000C64570592E0A07810BAC7C8E43FD6CE8B -:10AF5000466591D1512F828BE27941229852C86F78 -:10AF60005D5C7EC17BA63F7117CA66923541F5FBD9 -:10AF7000AC853322EDB3BFF115B2CFCD46669FC38A -:10AF8000513C2F8DC5F31F399E7DBFC2F405F38759 -:10AF900033F9A4F5DF5A38171C14EF0ADAE4C29B20 -:10AFA000706D51F4722CC5295849EE1DF7EF3AC067 -:10AFB000E4B9F5E6A38477BF99E90F0E70B90705E8 -:10AFC0009E27D5F7569842A02B247AB7317AD5FD23 -:10AFD000C12D87F35CF8FEE00B397980F6BC4CF2AA -:10AFE0000FFE05E5732AC67FEC365C3BF7BF3B8559 -:10AFF000F2E0587AEB5B47D97B2A3C2CF038544F6F -:10B000007CE0FEF799CE64A213C3088B0F0377CDC3 -:10B0100060F29B2BE5C691FE8327B4F48DA5537D8A -:10B020005FA54F7D5FBD37CD2A32398E18FC7994EC -:10B03000F75FCC90357C8DC4FAF3E2CDB46FE17547 -:10B040004402C211F656433F51BF35268CDB485FA0 -:10B050004D8D606F03B6EFA1B889ABCF85E7F529B9 -:10B060002F2B7203A709ED78B162679094C8EC6E3C -:10B070001170BB5EACC4EDABA0430FE82F47C475A5 -:10B08000BF35A0FD0D773CA07745C65DCF51F1746B -:10B09000CE4F8FBB9E4AC8A6F83D6231B3BA669EBA -:10B0A00055D0B17BE9904EF7F0DCEE433BF0741ADB -:10B0B000ED6D48CFE3A2738115E5536FF0E5911F65 -:10B0C000A8DF3D2EBAD8FEB0706005E91B74BE3C07 -:10B0D00056EFC41B40C03A2338D9EE77505DF625B1 -:10B0E000B0B812D4434D27E22DAA12DD9DE6703C84 -:10B0F00054E367510EEEA35C2B685FF557B49BA237 -:10B100007CEDFD303F5AF8B895FB5D51A2E8EE9812 -:10B11000C05F6E57F4DC061D12F7679E47CB14B96B -:10B1200063DD2245D62D8D4A9C0FC69A3C12F25300 -:10B13000B61BF5827099CEB797568C02D08AFA9DCD -:10B14000053EFE5EB7369E530E59CAF2720ECBCB49 -:10B15000B31475AF17DC407A3551FEC2F52EC12FFE -:10B16000D1FA2B08B1D501161DADA806B6CE012720 -:10B170005BE7819BADF3A19DAD0BA083AD97829F53 -:10B18000AD7081AF0D583EB8DD3288F9187EBD52E2 -:10B19000A4BC5CB464E27AFC71455E67970746F92B -:10B1A000929F2F8F79E04A61749D4D2E53B399DDA4 -:10B1B000AB7231927DE27751E04DA1B50202EC9D78 -:10B1C0008BC990F19DD920EB08AE020783E7FE48BA -:10B1D0007994065C3A57EE0472A99AD84E7628768E -:10B1E000524C365D1CD6D787561E1754BD01D24926 -:10B1F000F960BC3E2183E82C8AAEFC5CC690F1DA93 -:10B20000B6F79D3A8CA34585952D36840F593FE5B9 -:10B210007059E5F399081FD976D2A99B49765E59F2 -:10B22000A8B76315BA6ED83907CF4D18FCA3504E96 -:10B23000924D82525C5D51B179807E6794ACEB7423 -:10B24000E857C6DB80C5195714809FD5B36865E4FD -:10B250002735BC7E5D63E17ADB6B70BD4A7EDA60C8 -:10B26000F2C5CAC8D39A757393295F6E30F0F73F61 -:10B270009A2CE7BC827232223E5341984F3CF744ED -:10B28000211C10E496566B18FF8FC0F7CF1FC277B2 -:10B290006B8AEB5D16CF4D5940FA4F53F2796767D1 -:10B2A000598A5D24FC16863F1093D5D28A470752EF -:10B2B0009C1FD27BC1186E771F5AB95ECEB69A32E8 -:10B2C0001D1F5827D80FAEFB7A978FE2D02748086A -:10B2D000BEF399D53540743489818C42D4D71DD1C1 -:10B2E000C70C6427AA1D0BA8BCA5C87F9B03BC067E -:10B2F000E61FE59633F5982DEC07C1E5F81ECAA5C3 -:10B30000C8E9ACD2E371498D7B1FADA5AEF62A3CEE -:10B31000213C41A2A7490AAD20BB3815FF9EE1138D -:10B32000E6A753B93D2AF1AB674FEF6D691C744234 -:10B33000841F36EDF9E6AB0F50DF4DA3663B5D0F82 -:10B34000FBDF9616EA0BB01AD4C417D52F67751B0E -:10B350007DD45F95ED3E7F39DDAB78AFDF4671FA86 -:10B36000E2FE401B95CBC19EC369DC2FD43AFE6B35 -:10B37000E1E7E493B9120575ACCB5E90BC46E4AB53 -:10B3800099EA0B05F6207CDC84761347F779BFA990 -:10B39000F6950DBDAF19A82FC1673CC46FAD42FF34 -:10B3A000AAAD375C4AF562AD57DB2FD6F57BD713D4 -:10B3B000DD753BB4FB6ABFD9A47C5F4FF59A8DEA7B -:10B3C0003EEDBD26EA37F3A8FED3EE67662AFDA65A -:10B3D00092FF40A933572A77883F33EBFF0C5E2357 -:10B3E000F2D6FC688BDD4270BAD9CEE26DFD0666FE -:10B3F000C7EA7DD89AC86C44F5DBDA8DC0EA675598 -:10B400008EF94F1B1DA48FFCA793595D8CF53CABA7 -:10B4100047309EF0FE1E6522A0DD3D171FCA1411A5 -:10B42000CF733DD976AAB75F5EEB807F9D17A64F9D -:10B43000ADF7E74A3BAB0CD447DD887D146E35F79A -:10B440003ED96642B87913D00D242D3B8EEAA6E290 -:10B45000FD1278E91DF03E508E6B971A4F52B0BE28 -:10B460008F9047943C09E409FA79A3A2B7E8EC0469 -:10B47000CD798CFD1CCDF771A599DAEF3D0E7F6E6D -:10B4800009C573FE7DBCE302CDFD36C16DF791CDDC -:10B4900004F03FBC57AE88B1C2BF82CD1D12E71782 -:10B4A00068EE6F889DB79FECBBFC0BDD183B704BC3 -:10B4B000647765018047502FB386B5E7C507DB2168 -:10B4C00016F1471DD48D99577880EA16A3ACDD5F3D -:10B4D000AEDAC55498AA99439C913BB7FBD1219110 -:10B4E000D945099CF7707911C9590F5E79BCDC46C2 -:10B4F00069A5FB6603F38B59BD2D768A47939D5A48 -:10B50000F927D768E59FEAD2CA3B6D9556DEE96E0A -:10B51000ADBCCF6DD5CAD7EAD1CACFB67196E6FE1B -:10B52000B4F64A0D3C7DF302CDFDF3BD0B3570CE74 -:10B530008EAB34F767742CD39CE777AFD69CAB7691 -:10B5400036D60E2EF4358FB13311C408FDAB7A56C2 -:10B55000EDA070FFAD1A3CFF6FFD6F1FA3FFA7C8E2 -:10B56000D731DEBD153B7437B9EB65D13CAE9D9943 -:10B570002794EB59BFF6B69C5815437795FCE654D3 -:10B58000F21B94FF91C3160EDBFDF67D14CF0A8EDD -:10B5900038AB88AEA2807B1F85F392A1F6AA38BA99 -:10B5A000EF00D932858F9CE8FEE5A502E8347E8560 -:10B5B000F094B03CAFF0AC93E2F072D977DE36167F -:10B5C0006EC9E94BC2F320A194E7856A4714E822CB -:10B5D000E452A1EC0325E92961F9ABF323EC07C0A0 -:10B5E00040FD8068F2B65927AA77EC9B25568FB9A3 -:10B5F000587DF686E06273A545267F06C5F7DF25F0 -:10B60000BBDECEC4B8764AB4CBAC9E13026DC45434 -:10B610009018A3A4E5A9AF76501F87ED2CCD2BFF82 -:10B6200074476DB52797916F0994F0B699FEF56749 -:10B63000BA8E64A2FC0704CBFA42FCF6AD5927335C -:10B64000287F1925944401CD4F1C47E9FCCCDC240C -:10B6500019F9C3781B10650F89C273ABC0FA9093B8 -:10B66000F4D8CC08FFDDA867790B94BEEC1A455ED0 -:10B670006A5FB654C13F804FACC2787E4DF71B4C19 -:10B680002E7529C3CA1CCA6DB7E0FB374C3517505D -:10B690005F0A8E423BEFE7D53E2D4DFA297955EDF5 -:10B6A0006BCF76BF2E6548D32FC3CEC409E7916315 -:10B6B000E75E61BEF9FB039BA2591E1AD894CEE641 -:10B6C0008BE1F74FB1F7AF71BFA3B193EB5ADFD75F -:10B6D000D8DFF59E8F34E781A4903E0DF90FEC4A38 -:10B6E0009D7735CA6FE4056309F5ABA8B7385B7180 -:10B6F000F8FDC03DD3E710BEFFCDE7A74CBEFD6B04 -:10B70000FD6CEEA6F2796CED110607D606D83A96D6 -:10B710004FB5BF5557C3DF209BEAE59030C93ED1F6 -:10B72000BCE6311BEF83FA674FA9A47CDC9F6ED087 -:10B73000F1358BC3A9A5260ECF9B4F6B506FDE480A -:10B74000FD6DBF000E01ED61A9E07CEC7AE4BB3A2F -:10B75000D9956BA37A7275284F87FED0941FB8567F -:10B76000407DBE1EEFCA27FE052C065313189D59B7 -:10B77000D4370C899E3C0163C14D4F765753FD3F32 -:10B7800034C9738A3276ADADAB9AFA832103F78F51 -:10B790005B9E7C84F9C3B716D74C7AE71341F2312C -:10B7A0007B7E49F06E67F616302C8CF8BB823AAF80 -:10B7B000A17E9BFA9B60145F67DBF8DF5F2AC7AC52 -:10B7C0004B6D3CAEDD426B31E9E5EE2CFA7BCAE80D -:10B7D0006623905F203E8748F87AF85C760AF2404C -:10B7E000750D566FAC5F2878D5E8A3F8A1CE751615 -:10B7F000DBACECBD241B9FD724DD67F4B6B1FCEEB7 -:10B80000CFA8463ADBF558EF50DF7010D81C6D8496 -:10B81000E661117A596CE3FD17DC08C0CF93B7D10C -:10B820007943EFC0318A27DF67BAAE24390C8872BA -:10B8300009C59386D8BDACDE6BB6C9EC3BA497F1C5 -:10B840008F71E14ED2CF2F380F5C45FA6D300578FD -:10B85000DDAACC03CF26B791E5FE8772D9FCCB9E3B -:10B8600041F4A9F422FDCDB688B99D4A7FF89D1F09 -:10B87000F60B75AEA5C2835B3664919FA15EF8BCE2 -:10B880005112AE5B38C1F70F2AFA3E96E2F410FE71 -:10B89000D56E3EF70BDB4DFBCD4749CFBD66162776 -:10B8A000CFF6FD583E1BF6F43279209FD7127F1158 -:10B8B0007CDE1BC9E748CFE18772E59FCF5F309DF3 -:10B8C000FF1D29B8ED9B0C19BF6FD8FDC611B2BB87 -:10B8D00006751EDFA59D33182761FF9A30D11C1D08 -:10B8E000B34F445D6654BF9FAAD37E8F0539CDA95F -:10B8F000BBC9DFA97E71F0BF8BA9F9B84BE96B8496 -:10B90000C0EB2C1F103EF287F58287E545758ED17E -:10B910002660DE23DDBA5A589E90CE35DBC99EBB29 -:10B92000D006FDE4073A47349B5F8FE9A3BF35B8E3 -:10B930007691FCD6BC53994C7D76E79B0B947E8D1B -:10B94000E7A962C52E8B093FD19F1BC7ECB548A163 -:10B95000AFC484F55026857C8FC4E715CAFC63D339 -:10B96000EB9A3EEFBF32596853001E000000000002 -:10B9700000000000000000001F8B08000000000015 -:10B9800000FFFB51CFC0F0038AC515191844D41924 -:10B99000184C341818566820C46989B5B829D39F43 -:10B9A000C9C2C0900DC4B9409C0FC47C4C0C0CFCA7 -:10B9B0004CC4EB171445B0F50419188480FC6F02D1 -:10B9C0000C0CD7851818BE8B30300803F92E40F1C7 -:10B9D0000420CE01626FA0580B905E04C4DD402CA1 -:10B9E000228ADF7C5102F26B8551F937D1F87B84D2 -:10B9F000F0EB5710C12FAF47401E1B16D1223F3E20 -:10BA00002229D03B10585F01955F26C7C0D0270F71 -:10BA10008C7FA8B80192FC4B20BB5C0EC2F69660EE -:10BA2000602806F20D15B09BEB03942F01CA7D85AB -:10BA3000CA0300CCCCBA8C680300000000000000F0 -:10BA40001F8B08000000000000FFE57D0B78144507 -:10BA5000B670F574F7CC2499994C12F2E03D490088 -:10BA600011030E2144C0709924C0A2460D021A147D -:10BA7000750292849097887EECAEFE330189A0A86F -:10BA8000F1B9AC17DD416137B2E8060C1835E0605A -:10BA900000B32EBAC145C0E72680BC362443F0B9B6 -:10BAA000CB5E6F9D53D533DD9D09C4C7DE7FEFFFAD -:10BAB0008F9F5FA5BAAAEB71DEE7D4E942328F27E8 -:10BAC000640A21DFC18F969F8B8490F850596F20B4 -:10BAD0002E924188D766F46D4CA6CF88237AE6680B -:10BAE0005A981DD1375843EFE9CBD59EA434691835 -:10BAF000210F791C5812E223844EB55A2005F51601 -:10BB0000A83B93E07D3A3E21FDE8F80F46E2F8308D -:10BB10002D99181A671031E07B53ADF989B01E4298 -:10BB20006A47E6C3FC163B21FD7B9F9F8E88EBA7EF -:10BB3000EF0DC1F724FA9EB5EFEF2965570EFD13FF -:10BB4000F6DF6DF66D1408F1EFFCC77158EF9986BA -:10BB5000390E135D6F76B7D93F05EABE6C9F89B683 -:10BB6000E76EFBC026D1FEE5DB4409DA0D3B23F08E -:10BB7000FDCE75820FEA95A6D647AEA4F5C03691E4 -:10BB80003C0FD3F82D069240C87133613F8715EB07 -:10BB90004511AC5ABE7ED76D305F49A38944D0F7BA -:10BBA0008F37882EA82FD928F8089DAFFCB5078CB1 -:10BBB00003E878C53EA13EC241EB1B1F333AE83E85 -:10BBC00097EFFCD8D646E17CDA63260E23EEA3A4D9 -:10BBD0003E8D9052DF96E903E8FBA59B052780BECA -:10BBE00074DDD94E585F69833C5CA4E32DAE8B2293 -:10BBF0008E916CEEEF08CCD77C14E7DB260F83F92F -:10BC00004ACEDF650424E56E93912ECAE93A60DFDF -:10BC1000CABCA73D6B713E059EE52FD2F968BF8A6D -:10BC20009705276CB1C240DCB08ECED7220A5EB039 -:10BC3000C0FEAA8D23ACEA7D146E877D94FAD61BD4 -:10BC4000A75B607DEB8D4569A1F116D7FDA7767DD9 -:10BC50006B5313DD69BDE3F3B487827444A85E4A75 -:10BC6000880BE94FF219818E95E7E78518C4F7E252 -:10BC70003A9138CCA1F1153AF07EC0E9748795F17C -:10BC800001C7DB123BE02C84B76E3BC7A314C8543A -:10BC90008FAF948F003EE87A6A3D762C1FF72461BF -:10BCA000F9A4C781707BDA3312CBB51E273E7FC65D -:10BCB0003301CB751E1796CF796660E9F3E463BF55 -:10BCC000E73D05586EF0B8F1F96F3D2558D679AAD1 -:10BCD000F0F926CF322C377BBCF8FC65CF2A2CEB51 -:10BCE0003DB5586E057CD1B2C1E3C37EDB3D7558CE -:10BCF000367AEAF1F9EB9E462CD77038DAB248B6BC -:10BD000044E16073113B453B89CD7365CBB41E9B09 -:10BD1000CFEA09F3BCD9465A4F70D33A85CB80326B -:10BD20007FB689D60754B1F621F7921C33AD0FF1D7 -:10BD3000B2F69435AE9C085A4FA965ED23D67973B7 -:10BD400022697D848FB58FDAECCF89A2F551F5ACED -:10BD50007D4C13C9B5D0FA183FABA7EF73E55A690C -:10BD60003DBD95D5333FF1E6DA683DB38DBD3FA9C2 -:10BD7000C3273A2C3DF1B055762C2014574DDEB92F -:10BD80002E89CA9BAD46C75DC449C87BDEF92E89A2 -:10BD9000CA8706D985ED6DDEC5AC6E74617BB77759 -:10BDA00029F6DF2EBBB15DAABE0FDBB71BDDD89E27 -:10BDB000505D83ED8DB217DB47563F8AED8D462FE0 -:10BDC000B64FAA5E8BF5D7651FB6E755AFC7FEAF76 -:10BDD0001B7DD8FEF8FD9B5C5369FD05C1BD1DE4CC -:10BDE000DE0AC15D4252819EEA9340EED570F9F9B8 -:10BDF0001C101D6DAFE96F443EDCFA6EE60BC0BF50 -:10BE0000F8EB07F5A2DF3E988CE3BC89E3C8741C0D -:10BE1000F1E2E3A4BF3741334EFA7B25CA382D380F -:10BE20004E44DFC6D9FADE24ED7ADE2B55C6D90F93 -:10BE3000FCB4C2DAB77DA5FF394BBB9E3F9729E31F -:10BE40007C84EB89E9DB7A1A3ED0C2A7E183207CAF -:10BE50008EE238F17D5B4FC6412D7C320E06E1D378 -:10BE600081E3F4EFDB380D07B5F069381884CF971C -:10BE7000089FC17DDB57C6212D7C320E05E1F35FA3 -:10BE8000B89EE4BE8DB3FD532D7CB67F1A848F49D6 -:10BE900080F50CEFDBBE323FD3C227F3B3207CEC3E -:10BEA00038CEA57D1B67FB675AF86CFF2C089FFEF8 -:10BEB00038CEE8BEED2BF3AF5AF864FE35089F1478 -:10BEC00001E033B66FEB69FC5C0B9FC6CF83F0B922 -:10BED0000CC719DFB7F54C38AE85CF84E341F86461 -:10BEE000E0BE26F66D9CC6E35AF8341E0FC26732D8 -:10BEF0008E33B96FFB9A70420B9F092782F0998E9F -:10BF0000E364BBEB985146C7B1F63ECEEB67B4F0A5 -:10BF100079FD4C103ED7E338D3E838A9171F675294 -:10BF2000A7163E933A83F029C071AEEADB38AF77AB -:10BF30006AE1F37A67103E8538CEB57DDBD7A42E53 -:10BF40002D7C267531F88C3B50956BA3ED54173A38 -:10BF500045FACA951D2E9740EBA29DD545BB93800F -:10BF60005D222AF606697589F47DCBE698F4078987 -:10BF7000DAEEC8B913E8C74AAD31B5DD113D21523B -:10BF800063E7C4B86235F5B8190334FDE3F35334FD -:10BF9000ED8905A334EDFDDDE99AFAC092499AFED8 -:10BFA00083AB7234F5A1CBAED6F44FF6DEA0A9A7D1 -:10BFB000AEBA59D37F78ED7C4DFB256B4B35ED97B1 -:10BFC000FA9668EA97D5FD42D37F74FD724DFBE582 -:10BFD0008D0F6ADAC7FA1FD7D4C7B53CA3E93FBEB5 -:10BFE000F5794DFB15873769DA27B66DD5D4AF3CA7 -:10BFF000F9BACECEB3D88F5FC6EB22D03D61767F43 -:10C000007FE6F7F8AD46AC1B0758D08EDF652D7282 -:10C010001CA3F835BEB5C0D18FE217700A7E45F675 -:10C0200080924BDAE8F37B26B92FB1D3E7F718DD1E -:10C0300097DBC3D8A7941E049204A5C300A5BEFD38 -:10C040000199D163CEC0F323DAE9FB9586C0881845 -:10C050005ACF12B31B817E770ACC2F8A144915F46C -:10C060008B3411F40B1E48CE7CC1ABA2D75583296B -:10C070001F0AA17157C9EE24B033DEAA6EF7821DE4 -:10C08000523398EE6B0021CD42BBDF4BFDB4070667 -:10C090001725B9E9782623B5D3D5F31BE9FC693810 -:10C0A0007F0BD0EB7B307F7CCFF94D291334F39B92 -:10C0B000879468E6371BE9FC7642DEAF3EC5E7A70A -:10C0C000489844C85F845338BF694809CEFF8091BF -:10C0D000FA2BEAF92383F31F86FD7FD6DBFE532676 -:10C0E00069F73FA454BB7F23DBFF91EAB37CFE4892 -:10C0F000DCFF51E12CDBFF9052B67F131B3738BFBA -:10C100002D08FF93307F672FF39B52B3B4FB1F5A68 -:10C11000A6DDBF89CDDF5DFD2D9FDF82F39F13BEBE -:10C1200065FB1F5A86F31B4D6E27D08F7160649597 -:10C130008FCE4F1D6107490472A1F340393216FDBD -:10C14000E49784145CC73D918CDEBE8AA4F486F229 -:10C15000C6CBFC581F956C99D4EFE2B4BE7873B689 -:10C1600011E412B6537F65215FEA1D8D22D2377923 -:10C17000D2E41B4ED7DBD9287AA17EC793937D20CA -:10C18000FF2A4DE4F67C784F227E78FEF953A39F78 -:10C1900057EF4B5F2EAC958FB7A9F82DE847E59088 -:10C1A00091551698D7AEA91FA17E10A1FEC527D420 -:10C1B000CF2094248FCA6CBECFA8BF04F536EA2FD7 -:10C1C000413B21D5B85FE2757D308CAE3F9F283F63 -:10C1D00017EEF32664293A9EC4F8F7C81AC107F887 -:10C1E000B87D5914057E683D85DE384D9DEE0FFB08 -:10C1F00007AE127CCF0B38861BE033938F4760BDB0 -:10C20000B45E6067EF1CA2E8EF4F51B060D5408A82 -:10C210008BD038B3884B4EA4EFCF595A2843E8A2AD -:10C220005510062F01FA5920539711E0E78D276921 -:10C230009C38E87A6FB6B3F167BAE4636DAAF51477 -:10C24000C866573E5D4F41A188EB9F3543DBFED169 -:10C25000CE2897610C2D573D81F3CCC9D7B6DF545A -:10C26000A0ADCF756BEB54EFC9A0F76E29D13FA7F6 -:10C2700060A1FB9C17842B5D285DE7AD1C0EB756B3 -:10C28000C95E0D5EC16D55DA21A0E026B82F7C5F36 -:10C29000ECD9FFF665DA7AA1575B5FB04A373EA763 -:10C2A0009BE31CFF47803E687902E883C2F318A72E -:10C2B0008F905CD5D2C78DC16D30FA50F6715C623B -:10C2C0002838BE8ED1C7C2DAA8F0F45018A4079758 -:10C2D0009ABE147AB88DD3C3A79C1E8AD76AE96A1E -:10C2E0002EF1AD4CA2EFDFB26617E2E9A050C8E82C -:10C2F000E1970A3DB469E8C1CDE9418FBFDB383D24 -:10C30000DCF673460F7A7CB6717A685B7B4E262921 -:10C310003DF14AF1A0A9533CE8F06E37023D507C54 -:10C3200084A587F9C17DD38DD3FA02DED6035F9C45 -:10C330001EB03D05C04E104EF87E6ACFFE544E68CA -:10C34000EAC56BC3E3BFB2313BEE986A5DE5F557D2 -:10C35000C51D53F55B5C3753535FE49BABE95FBC92 -:10C36000B650D3BEB07691A67DC1AA3B35F542EF5B -:10C37000CF35FD6F5F56AD69BFB56AB5A6FD969224 -:10C38000C734F5B9EE5F6BFADF54B05ED33E27FFDA -:10C39000454DFBAC195B34F599AED734FD0D3B2F01 -:10C3A000BD1EE831EBA048C0FE38E67120DD1FF766 -:10C3B0008CC4F2A4C7897C71DA3301CB7D8DCD4F5B -:10C3C0005C49BB7C192888264C7F16911842F62CB4 -:10C3D0007757AFCA027D4E50EFFE717951B5771095 -:10C3E00095530607C2396FAD91F8C711228052E20A -:10C3F000F307C4507B561B6D8FEBBD3D6FAD14B67C -:10C400003DAB4D0A3B6EE5E38543ED61E233217EB2 -:10C410002603C13EEAE2F6B9BEBD4C20F9EAE78444 -:10C420002C47FE8F3130FD5C666472A26C6BFF1C82 -:10C430006283BA7F44D585E6ABA7CC9508F491AA70 -:10C44000E1E3E2B59769E43C81E86D3CD0D938CDB1 -:10C45000F3C575576ADEEBD825E2BA2B4086507DCE -:10C460003D8CE4070CA097FDCD43668D8675BACE52 -:10C470001A405E35C6A3FDD8E19911774C023CE61F -:10C480006379D25380E5718F1BCB639E122C8F781A -:10C49000AAB06CF32CC3F2338F17CB4F3CABB0FC7C -:10C4A000C8538BE561CF5A2C0F7A7C581EF0D461AB -:10C4B000F9BEA71ECB564F23969D1E17960ABF297D -:10C4C000F0D0D3DD49AEA74F03FD5D80CEE2C407B7 -:10C4D000AA570D0AD159E28A87ABBD59A171F3D68B -:10C4E0009A389D2468E86108F864E3815E4C9C5E9C -:10C4F000C2B7E7AD952FD89ED526871DBFF2F97F2D -:10C500000DBDCDF991F416A2A7813A7A4ABD183D26 -:10C510004D12C787E8698EC1CEF41FA7A787601F99 -:10C5200061FC8F6230EAC6ABEC3A57148B67F37349 -:10C53000076AD1B278369F7B051DAE15ED3FDF4807 -:10C54000C073F7C8BF8F80787DF761AA28937BDF1F -:10C550009F9E5E7A87BB0BFDA0221F55A2E37AB691 -:10C56000474432B84618C80C924EC8EAE1BF75CEAF -:10C570004FC3BA4462E17D9F736698F32802674F08 -:10C58000891787EB0AEB576360BCE3CFFC2313CA20 -:10C59000398614E6DF348B68DF13FF0B4E806F5053 -:10C5A0001F999C4910070F0C37DAD13EF059B4F0AF -:10C5B000F3D27A66087EAB298C5A51DFD72621FC4C -:10C5C000867D35A27F1FE07731397F3178CEF70D38 -:10C5D000F897C0F362F2F1627291B81C2F37D2FD66 -:10C5E00077ED1C9DFEA003E4E085E1AD9C5FE9D7FB -:10C5F000F3BC287D2F3AEE4A50E8B87508A1F388BD -:10C60000A21DC7EF6EB884C92FC5EEDB66F2F50533 -:10C61000AF6792B5E33DC5F94F19AFBBE5051BF810 -:10C620005B4B920CF66361F0A094E5F5C9768BDA6A -:10C63000FE6CD4D6BB6B8519F568273AA2678F06C6 -:10C640003D61B71F1B06723B094B659C254946FBA4 -:10C65000312AF74ED7A546333FCFC7E4C1E6189439 -:10C6600017A73D66ECFF53AFA7B77194F510D24002 -:10C670008E9A411ED3B6D4DEFBF74ACFD217463C82 -:10C68000F76D92BF02FBD04CFFFF0EFC0D22615DE7 -:10C6900019B7B25EF49A2E87E79B35F3D1F71CCA1F -:10C6A00019EB772917E21B891C57E896EA8B635C24 -:10C6B0009F2CAE8BB06BEDCF184DBDB2B1BF5D639B -:10C6C0008FC21F54FE922A4102FA29E3E4D325596E -:10C6D0005609747D6F429010E85660FDCACD6D46D4 -:10C6E000B703CE9519DE7A5B1FC5DF4C89927C8932 -:10C6F000B916CF614BEA2F9D0A7AE64CC38A0488AB -:10C700001B2C16BBEFC90FF3BE2C3179BFC827070E -:10C71000B4F63DA70F42C7559E635C94588EABEAB2 -:10C720001D06168FD18F9B00E3C65F1C3E159BF73D -:10C730004F073B410FA78AC6B34637CA45FA5F6623 -:10C74000084E0AFCDE14F313243A7E695D3BC62DC5 -:10C750004ECADE11BFBC80BCECB93F4BD2F128D52C -:10C76000BEBCA415E6993F814F441C377D4CE5F8CB -:10C77000A93FC904E410394F7B65624886FB3B063C -:10C7800062C80CF93BF31B16E701BC4F81BF47E5BC -:10C79000E61D24DF867820B599E0DF9C218619000C -:10C7A000A733E47DDB38151E7225238733958294E9 -:10C7B0001E4CC1F1DDFDC1EF3215D4B48A63E0B97E -:10C7C000A4F83FC2771847720B98B750C09E7B8978 -:10C7D000B91AE897FA511A3F8DFA519A3AF5A334EB -:10C7E000F522724302E425143D29139F8070D2B4D0 -:10C7F0008F92EC88C762525503F6D1AF79FC6DBEBB -:10C800009D4803E93ECB5F7D36B390EEE76A89C56C -:10C81000FD9473F545B10C0EA5253EA3CBD2737FD5 -:10C82000471BC6DD48253F8CC7CECF6F36621E053D -:10C83000B44A99DCF449E97DFF890DA22BC206FDBB -:10C84000E87365BDC9DF7FFFFAFD12F238EEA3B4CD -:10C850006E2601FAEB9127C0F723D7092E5F187EC9 -:10C860002AE474AFE8A73B017EE343F1ACFB74F527 -:10C87000D51CBE4AFD295DFB0F962FFD8846BEBC28 -:10C8800029BAEF93C6337902F017A400F2D70F1E2E -:10C890003FA9C7F8AB811F7FB2F10769F99E8EFFF0 -:10C8A000D44FBAFE613DD6BF3EDCFACB5F7D69BB9B -:10C8B00097EA97D23F3C652394DF4E49B5094E8AEB -:10C8C000F7B28D2B6D2E903B92D7067C71CA27CE86 -:10C8D00008470F87B87CA506884580782BFC49C798 -:10C8E0003FBDE9A1EBC09EF86AA36CC7386A9DC939 -:10C8F0006FA2F45CD1B0288F8CC17A3BAB3F70162D -:10C90000E8BFB2513EA2A6D3D2DF3D95007935945F -:10C9100052061A92A0F4A37F52B1E1F3E9606F547A -:10C920009200F2ABFE3D98FF9B58D48785C6E89EE7 -:10C93000ED18984980F7D9AFB2E1A1B3A20DFE6A14 -:10C94000C33890BE7F09F7375A246B3F3C27B98222 -:10C950005C01F2548107F1317F63C58BBF1AD34E5E -:10C96000D7D3B1E14F36410527C54FEAAE5FF09B03 -:10C97000D71DBDCBEF4ECA876ABB56D14F8E46EE50 -:10C980002735B1B24CF6DBAEA4F2A46CBDECF4D208 -:10C99000C7652FBDF0DB67207EFDA1C9399C8EBF26 -:10C9A000F8A53D0727D1FAE22D72BF3CB60D8B905A -:10C9B00010C24B25FD7F597A080FA5AFEC313A46DE -:10C9C000B3E7F7C686F0B178CB2E2319DD131EB975 -:10C9D000F5BB8C6D963078A96F9F0E76DF8A17BFF6 -:10C9E0003682BC3BB5532089C961E0B97E0FDA8538 -:10C9F0000027C423C753106FBAFE95142FA05F14ED -:10CA00003CE9DB37717902E339D2909E5F7E9DCE9F -:10CA10005FF291C909FB2F79F92E1BECE38454C511 -:10CA2000E8FAD9950920DF4A646F821D4BF6BCE411 -:10CA3000B9BB91DE8AF7DF9DC0E292AEFE06D495C7 -:10CA4000DEFEB0BF85EBE6E0FE8A881BE9AEE45966 -:10CA500031DF47CB2F2532634B18BEB8566672F2D2 -:10CA6000C4F35423D0FD9D50F4C0FB22D70377625A -:10CA7000DCF36EBE176A3162FD4B33C3D330D9C0CD -:10CA8000E52CD32B417ADDF000EA8BD3835D8970EE -:10CA9000BE5619D20FA837C4FDD312197E989EC175 -:10CAA000F7A89EC985E7D0BF5576458CD1BC877A5B -:10CAB00045997F299F9FAE3B12ECB51309E1FD8F8D -:10CAC0009FCB0ADF53BB42455F2AFE66FCBE613541 -:10CAD000E36F85DF7D336740FB170718FFC07BA03E -:10CAE00067E9BAFC89D8BE6BB680F2C044FCE1F8B5 -:10CAF0007A83CCF95ADBAED0095DB72444ABE805A4 -:10CB0000C68F45F8A35E2F7A92BEA7929795309F65 -:10CB1000ADE7780ADF1673FE9F216BF99FAC8BEFB0 -:10CB2000533E6599ECFBED33C0AF943FBD0EE0572B -:10CB3000391FF6FDB7CDCD076FA67CFAB77A854FC2 -:10CB4000B5F253CFA7255BEF26409F7A3EFDDBA0D1 -:10CB50002A12964FE9F3B07C3AA8ED7F547E2AF072 -:10CB6000AB02F84585E0A7C8C3DEE0A8978756D991 -:10CB700011561ED2DF0192D993FE14BA53E8ADF4D8 -:10CB8000F7E54341EE04E952A1BB205D2A74A7DF1B -:10CB9000AF167EFAF64932C175E5BF26A3FF5CD613 -:10CBA000C4F242E97B7B0766209C5CA8C648EDDEA8 -:10CBB00081FDD4759FAE5EAFEBEFD2D5F375FDDD91 -:10CBC000BA7A95A67F5963B39120FEFD9A7EE2B2B0 -:10CBD00067C8D1B870F4EA637E59C359A317E8C295 -:10CBE00012C0F7E5E5C40B7986811D22C605BA2877 -:10CBF0008C6B207EB139D9E7A5726365048B3F74D5 -:10CC0000D903B6585AAE8C61F540BCB106E49EF229 -:10CC10003C10C1E28A5DF9015B8CCA9F6A6F1251B8 -:10CC20006EB7F9C88C707E16D528C8476DA4B77644 -:10CC300076EE354DB40C590671A55AD10936F81D5A -:10CC4000D537D9E0DCA9AB29F5FA02FA7CE11F451A -:10CC50004C7BE98AB48D817511AF4BEAAFF26F4E10 -:10CC600012EFD359747F0B9A989F73C71A9D3D4258 -:10CC7000D6203D1559961A419E527FE288F6BC8611 -:10CC8000F145291FAF649DB65D799FD201FAF3A5E6 -:10CC90001BB4ED6EEE0F7FA0F0C9583296FBA32CAB -:10CCA0000EC3E5F23431EDFA028A8FAE1691986820 -:10CCB000BDBB49447C746F167C104F23DE78E4B70B -:10CCC0000A124079A8C0A903F8C9D8BBBCEAD8F6B3 -:10CCD00069E62F816EB67F3CE63F69D9B1FDC3118D -:10CCE0006F40FDD543433E263DFBE7EE8CC073FF0E -:10CCF000AE9D56A4F7AE1DEF0EF925D45F33396112 -:10CD00009D5D3BBF1E03F4D3B5DC5402F2AE6B3025 -:10CD10008BC7AED8F1F59836D4AFF733FD6164FE1A -:10CD20006177D33F3E13FA4149770576C3CE28E4B5 -:10CD3000A7CAD72330DFBB6BC7D7996ECB4FB79F3E -:10CD40000A9EE7D16525055B617D312C8FA1F28DAF -:10CD5000892F54D3F9CB1B761917D0F6DC37FF395E -:10CD600006E468D756660F75CA6DCF411E4394F12D -:10CD7000DC7299E2AB13988A3ACDBF3366E402DFE6 -:10CD8000F484CB3F313ED65778A4FCAF8187E06274 -:10CD9000F2CEEA330BB0EF6F3FFB18E39A26A44BB9 -:10CDA00065BF7FABAF467BE562FBCEFE7F6EDF8269 -:10CDB000BF2FFB76FF9BEFFB38D7BB7A3EE849E7F6 -:10CDC0003BEEC1FA4B5627AEB78FF4EE85FDC7FF99 -:10CDD000FBEEFF7BE37D2BC5BBEDE2FBFECDFF5AF7 -:10CDE000BCFFF1368E773B7ED7F3E63F717DDF5790 -:10CDF000CEBDF96F8EF7DEF6AFD8F5AD862A7B068D -:10CE00005D5F01A9B582613137BEDB92E1806CD7ED -:10CE100073FD308F0ECE4BC3F84D0123F30B4D90B5 -:10CE200047077EFB1C41890BA21F751DB71FAE1B58 -:10CE3000548276C875AE8799DD2055B566D3FEADB0 -:10CE4000390B9C987349D20FBBA13E7B32AF6BFD6F -:10CE5000C9F704E212A81D7F5DCE352D60D75EEFC5 -:10CE600012D1EEA525DABB1F0C99CE9E4FD0FA3D0C -:10CE700073DDDAFA4D05DAFA1C3EDE8D84ADFFC6AD -:10CE80007CC107715553F613F11067352D948990C5 -:10CE90000CF942552BC1BF9893AF7D7F1FF8C1E3BA -:10CEA0007F3C1C534D0A1C97205C48B6E8DC48FACE -:10CEB0000047BEEED6D9637D90CF4C242783E38D07 -:10CEC000E54E8C83737F5BE6EFCB9655ADC0CFB25A -:10CED000CECF56FCE5DEE04DB8FF8DE3A484E02F15 -:10CEE000BB44F4BF659DFFADE0E5FBE243C1E38FCA -:10CEF000C5CB973ABC0CB2B808F0ABCCFD85A916EF -:10CF000027AB0FCA2778DEC8FD05A99F8B78D342CF -:10CF100079DF8BCCE66C385F338F1430DE71FD1A0D -:10CF200011F583394DC075E54F90318FF873437E0D -:10CF300026E03B6FDC1515BF60CB70023C1771B863 -:10CF400017912AB45FC9F9EFBECBCA84730682F683 -:10CF5000EF221721D752BFAD284BF0475278154B1F -:10CF6000C41B9D0E716F811CD1C4BDB575F8FD4702 -:10CF700042689C8BF5EF4DBEFCD4E55FA93C3B328B -:10CF80008CFA411E9EBB4958DC56F1AF6F6F627040 -:10CF9000AC2C137C2948777E395F75EEF81CE7834B -:10CFA000BFDE3B0EE564F6A3A3A3D1EF7739D06FC4 -:10CFB000A8E47E43B7D7110D71AEEEA6547E3E9B1A -:10CFC0006B53CB55A5DCCFFDEEBF407E212DBBA61C -:10CFD0000AB522F8712480F15CEFD408B2314CFE1E -:10CFE000EBFF311938FD54611C007E6226E091FD93 -:10CFF0008AE9ABD1B12ABCADB9F69434A6271EE0BC -:10D000007744750EF963E10B7E3EC0757F44DBF417 -:10D01000FC30FBAD35B13856DE5BDFE2779C373450 -:10D0200025CB00971BA68A9A73FB5526EE978D2376 -:10D03000E3605D796F5D659B087869119DF0DD6641 -:10D0400065D359A33BCC79B01E9E303EC4D58FCA60 -:10D05000CE2280E7D1872308F8D1EFF273C634F8E7 -:10D060006E220D433A2E882BFE9AC3B5D364C77245 -:10D07000565EB61C4FE74D6BB08F85A3D401BC7FC5 -:10D08000271821E3218987BDA7F41B50C6FAB51BD9 -:10D09000ED15E1F63F3C82EDBF9838EF9920FCFB9F -:10D0A000E12DFB51AB3F07EC83A93CAED283AE0927 -:10D0B000F247F70CC107FA1BFC61ACE7B1EF84DF64 -:10D0C00055BEB3BE81E95985EEF570DECBE1ACCC3F -:10D0D0007FDCC4E2AF7FE2FCA5C05981AF7EBD4AD0 -:10D0E0007F2AAFA6A8E351D7378E7D19EC9B8A26FD -:10D0F000C16EA04355486D46E0C3CAC6C764386FC9 -:10D1000099EB60E312297F8C3A9FA0D3C4F23B9A3B -:10D11000D3AFBC0DE8E4DC1A13E842E2BAE3AC0D8D -:10D12000E4F0BB06E79FE17B6AEF7B22D9780179C7 -:10D13000F5B1A7CE3555528F9B8CEB9C55962D4360 -:10D14000F8EC96B25D72A28A9E3A4DB1D8AE3C1F01 -:10D1500050E64887E7743E5C87F7111381EF42D2AF -:10D16000EA5BF1FBD45BAA62181D96D4EF32623DF4 -:10D1700019FB2BF329F3E8F969769E36EF78416EB7 -:10D18000DB20804B9EC9BFD419864E1F332BE78E00 -:10D19000DF534FB828DD8EF9FF484F2C55F4441B60 -:10D1A000E6B92BEFCF35333E57E989C4707A62492F -:10D1B000B52311F0B064476A2230C9923F4E4B0844 -:10D1C000A7273EF0B073E343FCBBEEAED9544F5CEF -:10D1D000AED213B323904EF4EFE59A95738D8BE89E -:10D1E00009056FFFC3F2E603D01361F8FB46B3569F -:10D1F0004FDCD854887AE2C6D9A2E6FBAA6BCD17D9 -:10D20000D313D90973B12E3BA3C2D0CF07DCBF39EA -:10D21000C4F3FB611ED0176BCC76849B5E6FF42643 -:10D22000D7C7F655AEFF5F82B322D797CC61F743DD -:10D23000F4A44382F4BC642E95EB02D02393EB4B11 -:10D240006EE5714E9D9CCD07399BA196B3ECFD0A0E -:10D2500037D30B958DC9BF9A47DB6FAE959D66DAC4 -:10D26000FFE690DCCD54CBDD356609E1DC43EE967C -:10D2700030B97BAE691CDA4FBDEDEF532E6FA93C80 -:10D280001BE60C431F05F3A234DFDF1D1DFB76DA1E -:10D290002BC02FEF8A787EFB39B703F68D7D3B03D9 -:10D2A000ECE9537C3DDBB8FCEBF4F85C53A91CC8FB -:10D2B000BD83D9D3E59B45845F4503E3FF8A619134 -:10D2C0003E07AD4F4FFF16CF6117EF60E7B0740711 -:10D2D00079D92AFC2F7EB7AD06CE0516AF17F01C04 -:10D2E00019BE5F0078167378163917E3394AF1DAF8 -:10D2F000F0E73FE5BCDFA2A6F5180F5FE4D3F62BFD -:10D300001F76F529F047F24C0C0F79AF08BEF5C92E -:10D3100090CFA0EBE75C8DE747E5F5DAE707F97E0C -:10D32000178AFEB457E8FBE4CFCCBFD3C3FBA01EE3 -:10D330002E253F122EFB295C32FEF570E90D0ED42E -:10D34000BEC7F3013D3C0E2B72259D64001F7E6E0F -:10D3500070A15CF1BE43E142E7BBE3B1E19AFB405F -:10D360008E73B8BC6B70D7F4877E1502F62B5EB750 -:10D37000654F02ADCFAB2763E178A178AD560F07BB -:10D38000F57E8303F5FABCAA2D02E4C72EE4DFFB89 -:10D3900095F81EC37B546E5D46F53CEDBF20DDE481 -:10D3A0008673F0FD1101949B0ADDC64730FB258E84 -:10D3B000CBA1A3030253513F350A76E4477F04D340 -:10D3C00057144F70BF4BF3C4AFA773BCB0B8522310 -:10D3D000C36325C51BF0F3F4265EAF6376E02D4AE8 -:10D3E000BD5EF0390490ABBB64765F8C40E2048E86 -:10D3F00004957E84F3D5EC04159E77B433FADF28C8 -:10D4000038F1818FFEF743F0DC2BDD333BA6AFF420 -:10D41000AEC0293E428BE7FD11AD79E3FAC1F99B1D -:10D42000E0C47B739A62F09CE8582DBBFF2595BF42 -:10D43000A7E70BF03BD4F7D1CC8485437EF38C086F -:10D44000CC0FC57953985DA6964FFA7B80BE6FFED0 -:10D45000512569457B2C94C7E87EDE04E3CD10346A -:10D46000F94E1009033AFF09C6BFD57C81F14992F4 -:10D470001DF396EFB22BCFEDECBB2C5E6F1E9C79AB -:10D48000681E85EFB955A2135CA89B0C8E835920AA -:10D490006F1E9409F0CBB97DB28BE98128D43B850E -:10D4A000EF1EC5EFD90A590E1A29BC8FE997A37C44 -:10D4B0003D1F51BDED82580AA91F0FF7E0CC76EE53 -:10D4C0009AE680784BC6FE9570CE392BD77EF02039 -:10D4D000E07335BB07E9C8AA5CF4D3EEBA53407ECB -:10D4E0003B4CF106EFCF999D7CF0209DF7D655F18E -:10D4F000786E39CF157F239C63CEDB273A1DB4DFCE -:10D5000082EBAD1638C7BC66A448DC2AF8DC4A5A60 -:10D5100031BE33AFEACE39B0EE12AA0FC56428F798 -:10D520004F4B84FA3A01DFAFF4BA8DF0BD66EBDA07 -:10D53000B3C60C3A7F11ED0760AF5CC7FA556E10A9 -:10D540009C90FA5DD4F418CACBA20D025E34D34A83 -:10D55000ED5F331BD767A6E3B6AEA3EFD37A31BC3A -:10D560000FE36E88B911CE272BE93AF1FD09D57882 -:10D570002E5D44DFA3CDA475C39D38DEA275028164 -:10D58000EF034B26243F3201C6DB273BA1FDD0AE83 -:10D590005F1B61DDB7D1F9FAD3F117886DD3A03FD6 -:10D5A000F9A560C7FB87EA4660DCAD0B360C2F544B -:10D5B0000DC73AE6133B100C923A1F654704FB4E29 -:10D5C000B86859750DECABCD1B9F6C40BA3A6B0433 -:10D5D0003D7E8CC2DB4D873C6A64792ECDDEA3C6CE -:10D5E00036951CFD282215DFBFA3311BF3261692AA -:10D5F0007CCC9B7057337BA47D65840FE26AEDB2CF -:10D600007D083C6F5E69C2E79D2F31FDD339B80DAF -:10D61000E3DB27D6C904BE5F5CB12EF569C0E389A0 -:10D62000CD32D29BF82CCB1B287E89C5C99AD7B1A5 -:10D63000714F2C35B27BB5A09DD68B5F54F20AB4E6 -:10D6400072ACC8518A724A2F97F4726BD193D54647 -:10D6500020D91EF26AE9749457A554EF00A1F59001 -:10D6600057836A306EAA975795C4A2C8A974885F79 -:10D6700016960FBE6D2DD0F1ADEC838156FF6B5F1A -:10D680003E057AB7CC4AE04985647F5A6074418090 -:10D690005FE6356DF912F8A0645E04DEC7751CF014 -:10D6A000007CB3260ECFAF8B7C85086F252FB77813 -:10D6B000AD96CE95F8E35CB7485C6AFD5512455CC3 -:10D6C000AA7E87EEA3F44AE7B9BD51F081A83C7465 -:10D6D0005FFBDEBB33B06EC7752DE3F6C11A2BD2EC -:10D6E000F3A19F9F5D09F47ADBBD02017B9D78DD8C -:10D6F00035A00F2BD60A0E880F17DFCBDE2FA6EF33 -:10D70000C3BA0FFD9AD115A56F07D07FC5BAC7F66A -:10D7100062FF0D8203C63FB4BE10ED8912AF48B060 -:10D720007D433BFA0F544F619E59B3574C00FAAFFB -:10D73000B8DF64075349A123852EDBF97D08C4ECCB -:10D740001C338BBEB70A1615DF931EC50221A84FE6 -:10D75000814E2ABD8CCEDA5F929D403617A74BF6DC -:10D760001DFC09AE5FC567E74C87EF748AA97E048C -:10D770003A6D5E976B043BE2844FC0FC8A9E74490D -:10D780002C6A3B4AA1CB670526AF7BD0A38E0E7BCC -:10D79000D01DA74B85FE2851A35F59B64F26F0FD3B -:10D7A000BD9E1EDD72FD8D90FF51F832DD0F5D6F65 -:10D7B0006ECDCFD15E57E048EB09502F9258DE8FE7 -:10D7C000C20FE512CB0FFBDEEBD3CDBF2982E7877B -:10D7D000013F882C7FC94FE77D7BF30B982F79663B -:10D7E00053FB7568DFBC41E900E0BFD94AFCE87F24 -:10D7F000F8500E953688986F4D247FE62C95DFAE55 -:10D80000E4BF2CFE8315E15DBAD5E4CBA3EF976EA0 -:10D810003F3A06F311960730BFC7BB4960E71FDEEA -:10D82000B631F0FD50A9C4F270F476C1F04816E7A5 -:10D83000EA782DAA00EC36A18EDDB3575A7F936C9F -:10D8400052C5750745CA382FED87E7635E8A67B80A -:10D850001F01D6A7BEDF4DC9BFE97891D15F69A38B -:10D860008CF65C69DD964EC8C32C3D6C423FB7B266 -:10D87000EEAC11FCD8DC3FBC84F7F355368A9A3CF9 -:10D88000BC1EF96F75A2DF04F95B0DE5787E43EBF2 -:10D89000ED58AF0F9F077AB13CADC57FD8B1DD4BD6 -:10D8A00041B8F895DFD9F0BEBED68D36FCEEA9EEB4 -:10D8B000C2F9A73DF2DDEA575F30DFED34FC4109E4 -:10D8C000EBBA485DBE601D936B747D99F961E2C44B -:10D8D000417BEBA52F9F837CEC8EAD7F7B0ED65BCF -:10D8E000F65FE79E83BC1AB233C20EF648E5A60F78 -:10D8F000309F5579AF2492D97F9D2FFE0EF3803B48 -:10D900003F343961B4CE1D278680BDD1B9E5DB0433 -:10D91000C8EF5DBA631AC673966ECB4D2461E205FB -:10D920004A0974EBEB431EB21E5FCD0DCD98FF7319 -:10D9300086E21BE443307FB1BE9CE5833A78DEE2A9 -:10D94000E6F0F9DE3DF2141B665D3F19E46203B3B5 -:10D950000B2E9AAF7880E2F1F23EE06FF36A2E4F21 -:10D96000C2E3EF0CFC41F15413A9CD57FCB261E1C5 -:10D970006F9E81B686B85EF315FD7D809B924F3E0B -:10D980002BD2F55824F0CDD6DF637E28E02DCF01D1 -:10D99000F2F9CB2110173E290730FE10D861C2EFF3 -:10D9A0002C4B771C42FEE9DCB61FF3B509CFEBEE3A -:10D9B00024C11FCBC3E5B19ECA0D5696E7C8E10F3F -:10D9C00079900E1B3EE7F98E8C8E953CC8DEF21FD7 -:10D9D0005B2253F87D2A2C4FB37CC3C73CAF308405 -:10D9E0002F6102E0A9FD8279A50A1CEC00872BD4E7 -:10D9F000F9BCE1F34C8379DF1C5F803F90D3C17C9D -:10DA00005D5A1F04F99B3EE11009230F3AD7B33C3E -:10DA1000E04E39FCF7CC4A7E6FB39E4F7D7DCBEB59 -:10DA2000BDD8FABF2F7C1A221D38AE1E4E1DE7C38B -:10DA3000CBF1E39CEF7FF0F7216582FEFB93CF8172 -:10DA40001ECB1BDA8D789F89E23FF1FD76F0785A84 -:10DA5000C72611F33E6BEA9B518EEBE545053F2748 -:10DA6000D1AFF71BBEDE8A46A6273AB65A7D163AD4 -:10DA70004EC75BAF213D576C6EC7BCD3BD75AF18A9 -:10DA8000DB54E7CBA0277CAAF577BCBC6B0CCA6D36 -:10DA90007EBF987E1E63149BA7B229FC3C959BCF4A -:10DAA0006AE659ECAD37DA2D179FEFB4E4BA09C630 -:10DAB0003BDDCAECA5D3F5E20C5F98F94F71BD4987 -:10DAC000482D3B0FA5FA12EF59B3B27BD5445B2426 -:10DAD000DA5F4BAD130E47F783D288792F2BAA79E3 -:10DAE0009ECC7DCE24C0F70AEBD504D6BB12E0ABAA -:10DAF000F2E365BB9B80DD2627E567A8CF5994F547 -:10DB00001BFB19884F85FFA5D61989E07F12C93BF9 -:10DB100008D6715DCAD712E8BF560F8BDF93F34763 -:10DB200087C1F356C9BE278E8EDB3A557042E8B5E1 -:10DB300027DDFB347186992EED7DB1F80D1CDD5F7C -:10DB4000B7D380F6A0D5E0B7D32EC41AD19A840EED -:10DB5000AC8338A404FC1402F3211EF49867C1FDC1 -:10DB6000C83642CD53E8E79434F79F444F9074F79A -:10DB7000A19003C328BD5A38BD2A71392BFB9B8E57 -:10DB8000DB86F7ACC4A4916A20DF355637DA0D4F37 -:10DB9000F0FB69E86F24E441C49248A7FAFE263AF4 -:10DBA000AFE6FB383AAFA61EE3D2D6E36648C7C25B -:10DBB000E99738BE8EE9A205E11033CDA0F86B7964 -:10DBC000C31342EB8E89274E3FB45F6BC1EF012830 -:10DBD0007B79D5FBB058B4EBA6EBD3C889E8B43653 -:10DBE000AF81AD53F3DC4E1C02EEDFA57D4ED7AB0B -:10DBF000A917467179271109E49DC5DC4A38FCBB99 -:10DC000035F0BE5FDA373801F043B85FED2590CFCD -:10DC100012CDF741E7D7F4B7437480CDAF1D870C21 -:10DC2000B2ABBF43BD9CEBBF5196FC2551949E32D5 -:10DC30008756616276561249C3EFA59BFAA17C4ACA -:10DC40005996837927422DA3AB616B08F2CDB000C2 -:10DC5000CF9BBA3F12ED5193997823D2E17B36E204 -:10DC600095D361161FCF43702C37D0A1A45594D6FD -:10DC7000E87B4D811CC3428A847A68A2E35746B987 -:10DC8000AAA3289FD6CC742719C6C2F6DE5EB93B7C -:10DC90000BB9F65288081AAAF7EE69198C2204EF1C -:10DCA000F120DEBD7B80C66B953A15ECF09D7F6D53 -:10DCB00064B0EE3253795F9BC2EA8F3EB47725DCC5 -:10DCC00037936ECF7F14F649CCF65178DEE58FD5C9 -:10DCD000DCF3DD9B7E51D63972833F17EE05BE3AE9 -:10DCE000C0EEF51D6E0D7E778F7A78A345A9FBD126 -:10DCF0008FC86FD88F72ADBC7E3FB61BA04ECBA134 -:10DD000071FEDC81749F2F471D9A9674291DAFA167 -:10DD100030093ED97F35EAD01EF8EE3004878F57A0 -:10DD2000EE1E148283B4FCC33D2D93D570F8700FA2 -:10DD3000D8217D85C3AB0F7D8870E8EBBE295D6C73 -:10DD400007BC5C936DC0FBD6AE386CC1F80AFD45CC -:10DD5000A03EE2E3ACEFE5BB6CC51FA1E3EC54D3FE -:10DD600097F29E4257BDD14D2AB18F62F76C6AE996 -:10DD7000A72BCAF536ACAB25CA758F351EF78FF7C2 -:10DD8000005CE3763BA78E0BD135B1B8C7C1FDEE81 -:10DD9000A32CF35BA354F2F29AEC25620AC4C98166 -:10DDA00017E243FB895FE68D1841F719EF3260DE19 -:10DDB000FC288BFB20CC632B08F82177EC0AE21EB1 -:10DDC000278821BE50E6ABD9C1FCF59A42836F3952 -:10DDD0003BEF1560BC107DB4E9E823C0E8A3B11D9A -:10DDE000E9A3A2A99DD14763754E64063B37033F63 -:10DDF000BF9604C602DE3BA2BE9A2651FA1F1A1530 -:10DE0000A801BA91BDE7A6E55D8A703D1D163F7C6D -:10DE10007DCABE7AC36F6D4BCA4369E04FEE33E0F3 -:10DE200079970237A55F8C85E5C5B658DD5F03FCA1 -:10DE30002A27B4ED85ED6F6D791FF3366CFB6ED834 -:10DE400005EFDB66530C3942F3D6EE5B8EF767D7EE -:10DE500006D87DD8D124E005BDDE3B3C18FF04E1A7 -:10DE600001764F1AC0A31DF96513FF5E2CAB5170EC -:10DE7000819E1F1AC5EE0D89B4B0F3EB211611D7A0 -:10DE800039C4C2CE59E2F7BD2582BF9575BF01FBEB -:10DE9000C74399A6DEFFFDBCBFA489AF2BF854E8A9 -:10DEA000894AD228B87FE44C8C3BD1A2A19FD8A844 -:10DEB00014D578CA7B8F7888F30EAA47AFD83DFF78 -:10DEC0002ED0AB947EBE00FC04FB8D9623006E4AE0 -:10DED0007FA0CF70F8A1EF0D87F9601EB017B6ECE8 -:10DEE0005E22E23D1A7DC46B26DC1B49FB6746912E -:10DEF000AAADF4FDCC685A423D8ED713797D202B14 -:10DF0000533F711A04FA7C3D8FBB4EB6F0FC31C909 -:10DF10003EEA86D15067765C565224EA05856FE169 -:10DF20000E0838B796F8F9754A20C5007853F858A6 -:10DF30000A18FC56AAB452248701F218DEF1D07DEB -:10DF40004BBDCB9DAB2F65DF71EA9FCFE4EBF9C1F1 -:10DF5000F6F5173DBEEF9E09F02D37B73D7203ADC4 -:10DF6000575C7A0ECF079747555C79A17B2FF4EB6E -:10DF70007FE7FCDB5140874DDF98C27E0F55C3E140 -:10DF8000D6E229C0F732F9BD2E2451C93356E5B186 -:10DF9000421BB7CB109529F81CEDACFF401108F8D7 -:10DFA000F44AB1F07E54329E1F4ED1E5ADFE879FFC -:10DFB000C5F932C130002571C92836CF37CC4E3271 -:10DFC000D3FFE09C691A3F177B4772AFB0D2F1DEF6 -:10DFD00021EC7C3533AEAA19EAC4C4C6CF26DAFBDD -:10DFE0000A32136BA7C6C2B8D1C918DFCA35EBDA3B -:10DFF00053BD12C869929A8C7989D388CA3E637AD4 -:10E0000003EDEE08BA2E90E3D78C2C744EE5EDE7C5 -:10E01000E8FF434DE4F6992A7FE32AC75CE7548D75 -:10E02000FD528BF701FDE99FE2EDE1F22C3EE3FCAE -:10E03000DFE2C977C2F9B31E9E390EE17EABA3279A -:10E04000DCF570D4C35D81AB1E8ED99F38A7C68620 -:10E0500081931E2ED348ED48D0630ADCF57079C752 -:10E06000CCE8E29D3413DEABF88EC4E0F80E352325 -:10E07000A11EA49B6811EF01CE8CE2F53747B0BA20 -:10E0800082EFA864C4B71EAE7A3866C6F1F7E358CB -:10E09000FFBD002F09E502E247A19BCCD4AADD31E8 -:10E0A0002A7A50ECEB691C2ED4BE46FB3937DE8A47 -:10E0B0007126B0AFA72584E0965BCED6953BDCF207 -:10E0C0003CF8A9F475BCBF720AE13FFF143C2FCAAB -:10E0D000E45505CE53BED1DAC9D39AA69F8238C380 -:10E0E0005093FB7EA0CF801083E77514EE477470C9 -:10E0F000D7BE67D7D6F570F803FC31B127BC143A08 -:10E10000FBC0C2E34E03C820B097C7BC96110DF206 -:10E110009B34C5868D4B5C71383F380EA757A4637E -:10E1200081B883CFEDA93F428EEDA35A5225C73661 -:10E130008BEED396F89E724CC1D3648E87C9C4BB54 -:10E140000BE24B9389F445D01F480EEDBF5BD9E736 -:10E15000403210F67983C5C1E43FDF6770DFD4BC7D -:10E1600084F9B3F8FC59660B7E5F4302524710CE28 -:10E170002978DF91D7181B5A8792BF4F86541166B2 -:10E18000CFCDC37BAE295CC87751A17598AC828492 -:10E19000F7FDF0759CA9337B218FAD5B7447819DA2 -:10E1A000D721EC1B83FB93FC2340FFE9DBCF35EE4B -:10E1B000AE8076DAAF08FBF1F52F1659FC21B0C31B -:10E1C000E47B3EB9773B95B235EA09857EB3E0FB47 -:10E1D000D4CB81DEFD0361DD5340D5D172E759F622 -:10E1E0001D437663BA04F3ECE96679FF39C42581EF -:10E1F0007DABA7DFEF4BA7A178456008F8298A5DC2 -:10E2000036D5EA1E69A5CF57F3EF669BCE8E18056B -:10E2100078F9C1F474404B4F0A1D51BA1A0FF0EC53 -:10E22000CAF8FC6930C7DFCD3897007A51B1DF43B7 -:10E23000768A6B02ACA7373B7E89D53DC57A013B18 -:10E240005EB1672EE68790DDD441A674741BC7CB00 -:10E250003C73ABCCEECD0F60FEFDEA48E55E3B477C -:10E2600024D891B7AD4ED95407E786D52CFE7E6BE6 -:10E2700095ACF183DD90DD86EFB3FB666F5FA66D35 -:10E28000FF4C60FE7EA157FB9C581234F7EDF69CC4 -:10E29000D7E035C0BCC323313F413FAF7E7FFA7921 -:10E2A000F5F3ADE67ED56A63ED48A7CA2E596065E1 -:10E2B000F650F7AAC7EBE0CABADEE0E7360F48939C -:10E2C00054F7ABB5AD8E2C08776F8C329E02EF7988 -:10E2D000C4CFE20055F2DFC3DD839BE566F181DE4A -:10E2E000E61D16988A76A0E149BF08F6FCB0004109 -:10E2F000FB3B2BE0322CD0F801CC4FEEE107C0BD48 -:10E3000026B45ED6B08BF901F5D5E84F94517F0263 -:10E31000F4CC7A389B1EC0179486FE41D0DF85FC72 -:10E32000A92CB8CF92FBC312A597D45AD67FA3F5D8 -:10E330005DE36A09FC5577924C2963E3C3EFD798F4 -:10E34000A95F55934C2208F5AB5E78F8FDE96BC0E8 -:10E350005F8E7509707F28ADD758FAF7DDBFDEF8FC -:10E36000F0FE1AB86F94FA65EBAC2A7FB737FE78E7 -:10E37000048C910BF047BA3D7F23F0A112AF688A5D -:10E38000E07C1F11A4BB6880974227572F9B8F7E8C -:10E3900045C425E787409E5816C7FF162B8FC346F6 -:10E3A000B1F79F12DD5B90BFDF3A3F02E2CBEF8C0B -:10E3B0003C8AFE5C9395C5E7F7794AD07E52F0B966 -:10E3C000CB2A703FC93F10F8EDDAF1CD71E09764C8 -:10E3D000C902DE43DA24FB9E4CCF007934DBBE82D7 -:10E3E0006E296BA211BF136B8AF00FBC5B65A7355A -:10E3F000F1FB4C9BCEEE1DA8CE631E66CDDD6545C0 -:10E40000FAF38B307E56C6EEC3A0EF7BD32F21FDEF -:10E41000E112407F90F3FB13F0FCA8618F0DE24204 -:10E420001DFC7E82330DCD09F36959BEE52F36F010 -:10E43000D7DEE7703823B5E23D4A65DB44BCFF8395 -:10E44000CE9B700BC4A71B1664B2EFF7D877678A10 -:10E45000FE4CFF67F3C07C1634C4EFC8147B72B265 -:10E46000D9EB83F535558B182F9EACBB376C0ABFA3 -:10E47000374C6F5F9EB42A71E904CC875A6A67F300 -:10E48000F4C64F59DFC4129F8ADFB224BF08EBCF16 -:10E49000FA2681C01597675A529EC8033F9EC8CE80 -:10E4A000E130AC4476A3FDCACF9FE86F37DC43BEB2 -:10E4B0009357DE6C3837EB4A2466FBFD970960778B -:10E4C000B9FBB1E022D3078A7D37E51B6D7C556F20 -:10E4D000E7E6348DBD7F204178B37FA722C0EE559B -:10E4E000EB61FF06A687B57B09790CE190BE2DF59F -:10E4F0001AB84729FD8F063BCCDB027C110FF83C94 -:10E5000087F7FC5410FF8DD05ED120DAFDB07E92EB -:10E510007119F09562372870693CDF6C1E43D79102 -:10E5200075D6605F4E877833F005FACFE3FEBC2FD7 -:10E530000EF4575340C27382ACB3BBA316A8E46079 -:10E54000D379033E7FF3FC5BDAE781D8CBE0BD2DC6 -:10E5500006E617EFDEFBF728904B6F9EEFC6F182C1 -:10E5600076434FBB18E1916B15837167B55D4CC461 -:10E57000AC0390B7352D9AAA31A177BB37FB137244 -:10E58000BF95F4B41F72C01E11C3D8111CCE743EC7 -:10E5900009F8486F575C6EE3F1E6C1241DEEA36CE9 -:10E5A0003C1FB718BF1F6E8AB22F477DCCECA5AEBB -:10E5B000DDA71FBF069EEF13D9FD11E745E4A7B7FE -:10E5C000762E1EDAA6E25B2A39114F5FF53FDBF9A2 -:10E5D00006EDFFD59E481647979C97A9BF7708F58B -:10E5E000F77178F907B0F338EF00B8D7E907DB2FF8 -:10E5F0001D3DFCFA3C1BDAC381E9A01E46AC6B371B -:10E6000002FE5BACF9D7D990DFEAA3002E5E92330D -:10E61000904C80F37A92037415A82676F027B6B54D -:10E62000180C80978C8DC998A7B3899F572EAAAFD5 -:10E630003526ABE862113FEF3A297B87C4AA9E1FBB -:10E64000B031F972724FE96F304FE34313191EC6B0 -:10E65000DE6CB0317DFB8AD17BCD66E877C480DF8C -:10E660000DEDDEFBFA5EB8CF78D161C75888FF3D6B -:10E67000627360BFC67D9B6A20CFB7F113D052543E -:10E68000AF6C28140D74DE378883C5EF0E18D01FC9 -:10E690000FC63D892B0EF6F9105FCF1B2D06CDF965 -:10E6A000D81BFCDEDD7B6D32B62FB18988C7AD2D5E -:10E6B0003971A0375AACEEBB6DA02F8EB5D5C01204 -:10E6C00094789F62AF4D3CB0F59AD1F4CF891D0686 -:10E6D0003BA0DB71E07911F6EB3849488C407AD8E1 -:10E6E0006F743C8F7ABC373AD878741D6F01BF2A9B -:10E6F000F0A79AFFA1345A7FA3558A85FC2E05FE08 -:10E70000CA3E94F91DF5C4B5DE82ACE4DA7A81B86C -:10E71000B3925F3ACE4E947F2F01E9D268733D6A7F -:10E7200063F60EDAD727F730BBE815AE474952E15A -:10E7300050809F82A77A1B8B332AEBE96DFEDFDBCB -:10E74000989E54CAEF4BD79B648717E9661BCB0F83 -:10E750007778FDE654C8236B4CC57FCF499567FB9E -:10E760007BA4E793DA7B051BDB0C06F80EAC628713 -:10E770001083E66D1FEDEB209D49F5487F8D8709DD -:10E78000F27169DD9D2CEE48E50DBF7F0DCFD18183 -:10E790007FF8797A7F8196139BD6AF1888F0F5DBE6 -:10E7A00080AF4270A27C036555AD11E875D1525619 -:10E7B00016F373E9456BDDC89F45EB587EE11E5BA0 -:10E7C00032AEE70CA75762881C00F9272E0E7F6532 -:10E7D000DD799C6E4F353CD10CF352FAFA13E0739D -:10E7E00052E3634FC372157A3DB541C6714A22B5F3 -:10E7F000E7F6AD7CBC6D0718BD4FDC20E7C0FD5FC0 -:10E8000013BDC40E71EC37366C14417EBF01F49C0D -:10E81000CCF81CF4EDC93D0F46FD02F45CBB814011 -:10E82000BCFC152329D9A2E28BDDEB5FD5F06F6923 -:10E830005DF53518976F8B1540CE2B7CABC0FD1561 -:10E84000A3F32AE4FFEB74FC3F95BD2F473BB0DFF9 -:10E85000139CFF9F9841F99F3E8AD91023C038AF7F -:10E8600018C3DF07F7F50FA4BFA05C6DEB2157BFFE -:10E870006672B5CD964AE7AFB8B61BE30CC1F57129 -:10E88000BA7962AA4237C902C0BF96627018C08BBB -:10E89000C215E899DACDB7DF90865CD922E1390F4D -:10E8A0003F47E2F91FCA77020ABF86E499C2B76EF2 -:10E8B0007334D8D553AB56805D1F97E745FA3C2596 -:10E8C000B887C6527D760AF8388C3C38C1E5C75700 -:10E8D000B2FB62F7EE0F007A2EA11E22EC87AC137A -:10E8E000EC8017A5DDB18EDDC33A3C5AD09CBF2B1E -:10E8F000F51F0CEF408FFB418747637C3A60843CF7 -:10E90000D5113EA6C7889083FC400C570F003E5B94 -:10E9100044F5D7CD2AFD754AAE453A55E0707934B5 -:10E92000935F5FC5B07DFF95D38515E285AA732FF0 -:10E93000EA904802E36751607C2EC2F8A7F64CBA11 -:10E940000AE9FDDAF0F46E07FF2A16FE3DA7F54846 -:10E950009F3133ECF81DCB1392332246631FF9B07D -:10E96000DCBDF157E8D701FD02BFF746FF2540FFA8 -:10E97000240CDDFB28DDABF0A7D001A58B6BA255E5 -:10E98000F2414F17CA79A302975774E7954F47335F -:10E9900079B080978E5EF26694FDFC603C9FEC81BE -:10E9A000E7F90CCF21BE027C2BF2E16717E1AF3D06 -:10E9B000D1766CAFF97401E6A9D4F273AB7A3E9FBD -:10E9C000B2EEA5D182E67C4B7FEE34CAE2BE2B5A72 -:10E9D000773EEA480BD1C7346ECF2ED968C273FF99 -:10E9E0002DD00278DBCDFEBD6CE53DBB440D4F0A5A -:10E9F000EA15D14C8E2BF4E1586624C3A8FFF255DA -:10EA000072E16EC8FFF959AB376F34DDC716A377D3 -:10EA1000F6B5E80738AF82F1AFCA33D8211F24C654 -:10EA2000651720DE81240A7CB88FCD332ED5791965 -:10EA3000FAC90EE73890070F737C29F855E0D09B90 -:10EA40009EEB0DAF7B387CE279BB5E8E1473FE9E2D -:10EA5000C2FB5D5C8E7845E0271B712F1761FD5965 -:10EA60004CFE05E54816C173C9977572E4E59F5ED3 -:10EA70008EBCAC912313DAC2CA11FA0BCBFFF11B87 -:10EA800016A21D4B0E87B7637746333D1C0FFA93D2 -:10EA9000F68BF7B2F3DE8739DD528AC4BCC9DA0DD2 -:10EAA00026CC1357E4906D36C9817FAFD906FA168C -:10EAB0007ACD761F9E0CE7C54946079C5F9F92035F -:10EAC00088F753D401AF45FAC8C7FBC7C3C82302B0 -:10EAD000F112EF4783D0EF9C2636219F2C994650A8 -:10EAE0007FEEDE7805D255495E8A00745B5A1723A3 -:10EAF000407BEC54BB01E494B28F2B9619C8B071E3 -:10EB0000C80707D472E40A6F15FEBBCD43E3DC49A6 -:10EB1000720C21471F3DFB3375BCA88DD6D5F12261 -:10EB20005A7FE0FBC48B8E46071E8078D13F6CAEC7 -:10EB30007698779425FF28EAB7C42A91A8E4D6C529 -:10EB4000ECB71F4A2F953C2E455AA9344ED0C481AC -:10EB50006FAB73601CF82B584FC580E34FC37078C0 -:10EB6000AF46587B9BADA31F970BE41382F8E89741 -:10EB70005F2542FC45913B067BACE22F0B9097A1B1 -:10EB8000F0DB7F031C7DB5D7008000000000000093 -:10EB90001F8B08000000000000FFCD7D097894D590 -:10EBA000D5F07DE79D2DCB2493C9427626ECBB039F -:10EBB00009ABB14E086090040710448D380990B03D -:10EBC000640391D2D6968120068A182BB554B10ED3 -:10EBD00014FA51451BB61ADBA013401A143456AD73 -:10EBE000D8AFA561911D8980FDD38AE53BE7DC7B29 -:10EBF00033F34E26026A9FE70F0FCFCD5DDE7BCF4A -:10EC00003DFB3D77492D63793B22199B90B350ED35 -:10EC100006A9C9CC3C161B831F2F6343793E7A0893 -:10EC2000E659986B20636BF27579DE018C5DC79FA6 -:10EC30003BFD69A2153E8E676CFED630EB4933B5BD -:10EC400067D7E17F795D8C265F599F643DD9C79F67 -:10EC50009F8FBF24C1FF334CCF12182B63E2A7E173 -:10EC6000CBDFFF7018B4C7DF55C6DE54DD89568090 -:10EC7000A7DCDC12D5DDCED833F9C713DC91D45232 -:10EC800087DF3D22C67871B9E3BDDE718C79DE5530 -:10EC9000D916C80F36193D4A34FCE264766B82E817 -:10ECA0000F7E9406C5671904F97F43552C6397FEC0 -:10ECB000ADA3F4C59FB8F232E0FB8A7A9D6339B404 -:10ECC000AB685018CB62CCD19579CD198CD58547DE -:10ECD0000D62D05FCEBE48A701CA2F2966AF298337 -:10ECE000D100088741C23FA2357D1BD4573798D841 -:10ECF0006AC85ECA61AC19E1D53BA2D9003F7E0764 -:10ED00001D7EA60FCC00CA6B1D2E0B639BC278FF25 -:10ED10009BC2647B7B3483B4DB92D1EC04C0A7D765 -:10ED200033160DF481C48369F6926E03F499301F93 -:10ED30003DF318804ED9AD3E15F1D2ADD5AE6391FD -:10ED4000FE71F4AD8CE6DB4D6FD73960FC3A81F78C -:10ED50009D4D3B543DE073D898DA6A15D2D228F71E -:10ED600058C4F3A8ECAA6A2C8FCDF7A86E689FA5AB -:10ED700054EDB3005ED878E6D802E5CC07838F84E3 -:10ED8000FA16D61805D998232DCE28281F75C6D96E -:10ED90003800E61DED620AF6C7D8321ABF5FA4CB71 -:10EDA00085FDB238A75200FD0CFB0723BCC87E7658 -:10EDB000368D56EC006F5CF318C51EC05F304DE217 -:10EDC000ABF5CCFE53ECD77348E740BADAEB987357 -:10EDD00023B4EFFA72BF312CCADFBED2AAD078B703 -:10EDE000BBDDB94646F379D80ADF8F9CEEDD6700BC -:10EDF0007886CFF1EC33DA03E63397517F292D1E65 -:10EE00009A47D211770EA68B2D31D4CFA833BEC628 -:10EE100001D0AE4B15CC07CAD39A3F5410AF6955F9 -:10EE2000CD0AD27167D35E8237B5793F4F8111EA3F -:10EE300020DD01725517308FC5161DCD63B145A178 -:10EE400074E5C599892EA87FC4EA5E6C19EA9FC74C -:10EE5000CA1C776215F4BFBEA95BFB7C7B02BCB702 -:10EE6000C1678827D9DF72AB91FA69B2B87F84F3A2 -:10EE7000AB9CDE7200796F47D39FA3482E1AE288BD -:10EE8000BE09878E133D129600CEA078FDA1850A9B -:10EE900083AAF5854033A5239E27B8DD8E31998856 -:10EEA0006F809FF8C71A3109F8F2628CBB06C791D0 -:10EEB000ED2714D922505FB4E7C577CF2E658E5960 -:10EEC0003D00CFFB8B77B26E4877F712A47B7BBBFC -:10EED000818F87213F318BB316FBBBA4B0E938CEBD -:10EEE0004B9842F94B069E97F8FAAB95E3EB11EB82 -:10EEF000A4C596788E272BF0F14B61BC5DB01E7ACD -:10EF0000D7CABFB30B7E61CD9C5F701EA8BF64BB28 -:10EF1000DDA2DFDB9DEE5C3DE793CD08E7C811DEA7 -:10EF20007DC8B7C3F33CFB90FFD398E0933CCE275A -:10EF3000C1FCBECF6AA37E469D696588F72C85B962 -:10EF400002E92ED3D710AEA1C8DFA3897F401EB639 -:10EF5000E378C352AA54038012C7AC135877C6DEB5 -:10EF6000B6DAA95DE608E73EE437ABD345F27C208C -:10EF7000C24AE52B33387FC0F77F40FC05CBD32E48 -:10EF800094A3017E398A437E8CECC88FBF13F0BCFA -:10EF90002DE4A563FFEE3F61FF71CD3AA7029D0C02 -:10EFA0003F12E965D074F8A22A15E18F63C0FF0013 -:10EFB000A06D8E3507E52CA5CCA1205D9B225C873A -:10EFC000ADD40F23BDB93247E7AD86EFE6463B89A6 -:10EFD0007EDFD83EEC676636CC6F1FC01EFC15E1A5 -:10EFE000037BB0B608F5F46FFF69443D6A97F2D72A -:10EFF0003424A238803FAE48BDE0A7F771D20B4160 -:10F00000F40ED673C1F4F6EB05AD9E037C5DE0F41F -:10F010007067229FC5352F52B97ED0EAB5CEE8D1B0 -:10F02000413F083A5C8A707E81F85C0C3288E37A52 -:10F0300046B33E58DE991D0E8B89A476FF453B1CD6 -:10F040001613DFD10EEBCCAD0715C04779836A5795 -:10F05000610AD58FD99C48FF17EB148709E5A441B5 -:10F06000257E78716538D94B09EF67BBA307B1DB03 -:10F070002015F2CFDCDDC98E56C688F1ED9087F100 -:10F080002F5979D6687527C504E893171BBE084326 -:10F090003CF74F64034EC6620BA7D60E830829F0D7 -:10F0A000BD097F5310AF836B5414AC69EE9D269558 -:10F0B000E8D61DFB1BCE5AFE9C0D70BDBC6DB4CEB8 -:10F0C0001DC837F55767EC05F82B23B85DBEB4F7BC -:10F0D0005A2FE433597FF79262D27B3F072B1913E3 -:10F0E000A01FDFEE7382EB6156683DD51F87762A3D -:10F0F000D723008551E63E7AF427D47087AAF527F6 -:10F100008839AA7B027E107F8DE184BFEA9E20773A -:10F110001904E748EC7FBFC5C892A0FC0AC823B613 -:10F1200093707F03784707E2D10F6FAAF55484E00C -:10F130000BD50F5F3B5D900ED0BF6AD1D33C2EB193 -:10F140007007D2B3CEE864487FCF51E11F08BA55AB -:10F15000089EBBD430F4881BE6F7E29154077E7F0B -:10F16000A9FE4A982E12FD46F7149C979AD61A8546 -:10F17000F6705FC395BE2D0348BF4DC5F22B874E79 -:10F18000D8DC03BED1FC6684A687767E95FAC89A41 -:10F1900040FF50617C7EC17CA43434FE4B1944F2A4 -:10F1A000C7501F7AD299B71AE6BD72A0E0A77B9923 -:10F1B0001DE53E98DE46ABAB2226406EFF15EDAA5C -:10F1C00042B8709C942134CF85981F747866A6410C -:10F1D00087F31BC3D06E4A7F0FFDEFB0217EFF4E39 -:10F1E000CEAF7DFE3DAF0D3AC468BE3FC67100F89C -:10F1F000E53A80AF128CC1EA8CC079FB881EE562CB -:10F200007EE5E6489F0AF361BB0C175AA41EE8D6B8 -:10F21000117EA04F0DC2E719ED38E246FAFE35D255 -:10F22000518DF8D1375BD15F85F9ACC67A36A2280B -:10F2300011E7DF2FD2B905F5FC4BCB18F1F3A55739 -:10F240009877134C76FB7E1DF1CB46D68FF8BE9F88 -:10F25000EEF20C5724C9F33A843BABB956877AB720 -:10F26000A7D7AE437DDAB7B94EA7233E70FF2286FB -:10F27000FCE49957F4005FFF6D55EA37E4076F68C7 -:10F280007EEF40AFCD81F49278CB167C908D7843A1 -:10F2900083D0AABFD062F6E30DE8C3526C1DFB63B6 -:10F2A000AC251DF1D4F8FAE95E2DD05FC51BA76728 -:10F2B000205E2AFE60222618F387BED1C8EF9FE5A4 -:10F2C00084F6672E2CAD72E8C19F7A25A61BD985DE -:10F2D00032D66C443FA1BC6E81431FA0CFA5FF7600 -:10F2E000C8D09C8FFD1F1AAAB26580E72B8EE15D06 -:10F2F00058083BD1EE2FA1BF06B02F47D811CFAF92 -:10F30000674573FFD146F620B8FDA1A5731C637A4B -:10F3100074DEDFA1C161D3BDF07D7E901F743486A1 -:10F32000DBB5B6186E8741213B11CE8BBFB7783D58 -:10F33000507471C847510CFDCC5D1F647A808F2ECC -:10F34000B2E647FE8872763592D671F9833FCA5C81 -:10F3500066F1CBE51D23F8DCEF78ED70941DDAE75C -:10F360006FDF17E709C0DF1D4C7FB59DAF33705CC1 -:10F3700046E3337D4B2FA407FBE3D9043BA4F9AF4D -:10F38000BF15C7F9204187745E24F4DBEFB028C0B5 -:10F39000DFCE5F52417C24F3E56D66E68D0DC8EB50 -:10F3A0009B8DB8042E6F8B645E68B737C612477AA0 -:10F3B000269925A39EE9145F3789CFE07289CF4350 -:10F3C00083CFA6A35FF15927FE706F1B6FD7CEF7CF -:10F3D0004BC14FD7FBF3EF7CA53EEC0AF15D848D6A -:10F3E000D3E98A636417F4F7F28DBE1ED610EDE4FC -:10F3F000FA32184F6F5F2B8DC07E7FDF66CA0B0518 -:10F4000097DEA6FB767ECA21802AC01FDCA6BA53EF -:10F410006DC21F9C0CF98ABE57C6D1BA5AF28BD066 -:10F420007B77304F23CA6F307F487AF7B001DDFA1F -:10F43000A372662948B78B3176CE37421EA47C046E -:10F44000E331389D6064EE50EB80AF62245EC39878 -:10F4500007F4E1231B0D64DF0F5FFBF8DE4CE0F7E0 -:10F46000D31B0CD6E530E49C17F6A53E03F57306D6 -:10F470009BAC0AE44FDB7D3D50EE4B5F505DC80F07 -:10F48000A7373C923013D2F320BF650047E946030B -:10F4900095CFD9F828959F15725DFA427C7FD49755 -:10F4A00087F7AF4E403ACEF9EA89694897ED466B47 -:10F4B000FFC190966D531C6302F03D6F739826BF99 -:10F4C0005DC7E6E03C245D99E26EAF47133FD5A6E9 -:10F4D000FB76711F9FD6DF04FF72AAA0E3C4293018 -:10F4E000EF8AA157C8AFDF77209CECC99B912AF91E -:10F4F0008FBEC1FFEF9DDB209FFB95DE41BE9DA02F -:10F50000F3584167B05CA4B74BCC3C9FFBBA9EFC60 -:10F51000CF5C8B4AF886F69163A1FE7BA2BD0FF407 -:10F520002CCA2153B3D78D847663A30D0CEDD0F78D -:10F530007CF3F219D8C93BDBF4C75B02E6339AD5FA -:10F54000F6417F38871982CA9D7A2CCF356BCBC79D -:10F55000F6B8FB2CFA0F63ADDA72C9778FD8B4FA1C -:10F5600062DF81733F9B00F32B39A492FF7C237DE4 -:10F57000FC2EC2AF473ABF5DB80DBE3B2CB072F84F -:10F58000DAE91549C857231486F1ACD3D742CBE347 -:10F590001FA45E6640DF3E7EFA1638E6B6E751DC11 -:10F5A000EF19B1A03D8FF0DFBC1EFB7A3D759B8D3E -:10F5B000C73382ED46B0DCFCB7EC46FEE0B7D23D87 -:10F5C000164A7F83E985ED5CEF06EB89603B21E11C -:10F5D0000A86B7BC4DA7B10F5FA11E191A68278C08 -:10F5E0006427BEC3F570836D68C7F530F831842F8A -:10F5F000CF303DADC3C1DF6AC4760322EDB139001F -:10F60000D20A6BB708B27F16F77E5B401CAAFFB622 -:10F610005A1DEA8DF6F88C411BA791EBD577849D96 -:10F62000A813FA1CD6ABB4CEDF18EE4ED4E3B8C99B -:10F6300046C7968C8EF8F948B4EFCCCF957EACBE19 -:10F6400086FBB18F585D9A3819EB93A889FBA25FAE -:10F650008EF2EDD91B4EF3FC54710D4239D433E7D1 -:10F66000DF6D01F4A93670F883E1898FE576923178 -:10F6700017F907B27CF6E8D07A5C89D553FB9C6712 -:10F68000EF4F47FFEDD3C607D251BF7E1A14E7ED07 -:10F690004C1E9E16F2FAA4B02331222EF014CA1189 -:10F6A000E441DA9DDBE1FB554B5D24573F5D3A9D1C -:10F6B000D267962EA1FA13B60C1ADF9AF367577722 -:10F6C000C0D3C9352AD989D94657AF18F8EEA459FD -:10F6D00047F18513559179BB22B19CD17A72F6B36B -:10F6E00013B67802E27E276C7AA24367F38C8FFD13 -:10F6F00066FABD9CB544A1BD6AE7D7231DECB52DC4 -:10F7000016E37FAC2501DB552ACDBDB6291DC7B751 -:10F7100032677C2CF29791F547B9A90BE7F628B828 -:10F720005D4A2CE7C3BFA11F0BFD7E8A762B849E0A -:10F73000B10B3A2FB438EDB1A4EF22C95F27B881DD -:10F740005FBE8C727647B8605DD613D3615D787CFE -:10F750006EB1C52AF8C3A9F0758EAB5F6C88F85BF3 -:10F7600067F19E6038DE11780D8E03C954C681861C -:10F77000C6F2F9BC6DB36AE24218FF0E15FFF979C3 -:10F780002CD7A31BC35B3C2ACAC3037C3DDE25DB0D -:10F79000A3607C2B25BF3607E35F77C5F2B8A52DA4 -:10F7A000CF9D88EBF6E444A303E336372B8F03EABF -:10F7B0009C7C5FC0AD2338D6377BC27A015C09CD13 -:10F7C000EE1C23A45371310DF8EDC2AA9621DDA0E1 -:10F7D0001D21236B7FB857918B6C689229F42840C8 -:10F7E0001A8672678C724F45BA0C9B55558D71FA0B -:10F7F0009432BEFF70567177B5019F9C7D2B3CA45F -:10F800003F5C22E8CF94D1C968FAB3361B08AEAC8E -:10F81000CD3F9F817C9FB5F92EBD12A08796C71A58 -:10F8200068FE67DF9AD795E2169F9858CF107AEA5C -:10F8300087825F1E1074D8690CCD7F8B45BB6FAC7F -:10F84000CF5B405569F5F9E2D880385B45F965D260 -:10F85000E79363ED34CEF3FABA03C980CFE767319B -:10F8600087078AE66DDD48F1D79DC6BAF1B8EFE4A7 -:10F87000A9D031A4FBFE037F38908C7EE42CFB6082 -:10F88000F423DABF3FF4D24A2C7F7E0E1B8CF84F54 -:10F89000F23EAD603CE69F61B584AF7F6E31B165ED -:10F8A00018B77DBF6EFC0F21BFBE4CC750BF04CF41 -:10F8B0001B4632E81231F519742338FD510F4ABA4C -:10F8C000030319911E926E88BFED90EEDFF21AC10C -:10F8D0002FE19A2AE2DEF3B66E1F8F7C925C6653AC -:10F8E000304E20E1BA913D7931F6DBD993EFD00E5D -:10F8F000BF121B222E1DC20EEF880D618783ED2FD4 -:10F90000B3387763BB1BD9E1E182FF36C606ED7FD2 -:10F91000E07E5908BA0D8DED100FDF1F1B62FFE36B -:10F9200046F1F0DEB172FF431B0F7FC9C8F56FAD22 -:10F930008D3D3C2984BC7413E3EBD6B51AD17EC649 -:10F94000352821F5D9628B51EE1F7E1C1BB05F124A -:10F95000AC8F43E0F728B6EFBBCDB7175B0D89E955 -:10F960001181EE5BBFEBB0DE0D31CE29813FFB2272 -:10F9700046FBA6F62A46FA0AF25E1E14F42914374C -:10F98000B0384F93DDBAC1BED59DD61CF283E43E9C -:10F99000D554ABD64F8C8B93ED9C9F239C699DD8FF -:10F9A000897F093CC1FCDB70DCB8454CB31F23F7F1 -:10F9B00061E2AA3C8A310BCD11A3F86AD758F7321D -:10F9C00003B46B1DC91C9B201F5D68CD417D6A9BE4 -:10F9D000E368C4FD9A9517793C7EE502E65D4EFD2D -:10F9E000F0F93277372FCA17D22D302E1011C7E118 -:10F9F0008888E3720676D21CC7E10A8F0BB0939217 -:10FA00001EBA753E95E8DA1ADA4E05D0D546DF778C -:10FA100042D7EF502EED7137E71FF78CBB05BE19AB -:10FA20001877737CF3144C4BECDF048F9789F30F3A -:10FA30001E0FF82C2BEE26F8ECEA2DEE8F1E8850C8 -:10FA4000BE5DDCA5235E27C485D0776BF2757D484B -:10FA50005FB3704728BB3A232EF2BF7D5E6486A059 -:10FA6000F72D9D1779F1272D46A4B3DCF790F0060A -:10FA70009F1391E5150D4A26AE3F73F65DA375C041 -:10FA8000A5C67FD33AA0E3790F3EEE42E403806738 -:10FA9000AC3AA0CE07F277799B9156EA2AB3FF22BF -:10FAA0001BE3F64D06E6B5537B33B6EFC778FB7E16 -:10FAB000DB563663DCAA1FD37BC47A54B9CEFDA8CB -:10FAC0006894E37E4D2A5B8DF9ADBCBE8A9997613F -:10FAD0005C3A7A848ED903F019E30C67F6007CC691 -:10FAE000E6D93479B94E9E2FC68D77256BBEEF329D -:10FAF000BD9BA67D92BB9FA63E65CE104D3EAD6AD6 -:10FB000094A67D57B0CF81F90CCFDD9AF6DD6B2638 -:10FB10006BF23D6B1FD0B43FCDAA9ECDC6797A9CC7 -:10FB2000CD3D00CE5902CEDEEB8B35DFF5D7D50DBE -:10FB3000F3A120F9141FEEFFCD166C324BC473FAFB -:10FB40007AE769FA3DFF6A5E9302F89D5D6B3819AA -:10FB5000189F217C007E4BEA15F61C8C5BBA5E5B1D -:10FB60003FA7E1E9952990CEF56ACBE7E1BE9C82FB -:10FB7000FCAD2DDFAD733D82EB9DED7122CE28E211 -:10FB80003DAC037F44D2B89737F07897EAE91DC4BB -:10FB90001F5A3AB16FC92F76C12FA6442DBF84D901 -:10FBA000B5FC527A70E7301FEB88FF883E417CE459 -:10FBB000817F017897F895F8B738B47CF55DE19DC1 -:10FBC00031AF91DB0D6DF93FE2B4F1B57E91EEE31B -:10FBD000A8B7AED42F5271BF8DE5F17DFB2BF55741 -:10FBE000071DB26BF6D73ADB4F3A1717185717FBBA -:10FBF0004997703FF1367613FB89FBFE85F800D9F3 -:10FC0000771B801FD80887B97DFF30CCBF7F14AC2D -:10FC100037650A76E3CB38B227FE7DD76AF87A5883 -:10FC2000F45F5C08AFDC8793E772E4F92116C9E75B -:10FC300029FB013CA8F143F1FC9F2D02D7ADDBF776 -:10FC40002FA4F5963C3FC4C4B9BF107E3FE9EF3AFC -:10FC5000FC3589FC81F0786ECF23316DF707C4F94C -:10FC60002E69CF3BEB47EEB775962A7B55DA3F6C92 -:10FC700055C21D9B42D8935EF1DF72FD75A6431CF1 -:10FC8000BA577CE0FAEBD12B07D0AE00DEFB62B9AD -:10FC9000C502F65AF1DBEB5F444411BFB61E54BDFA -:10FCA000BDA1E0B2D91E6D033C368469ED884CAB32 -:10FCB000CCC903F4B158AF3DE727F71183DB676385 -:10FCC000FB80FD27F84EE38FAC1CC2FDB5EC786ECF -:10FCD000DFBF88E4FEC11491AF0C5A1755D670BF30 -:10FCE0006C23F8E90D01FD4C89B750FBA511395380 -:10FCF000E2298EC0D7BB2B3314F227562A0AF921EA -:10FD000067A24753FDB5B89CC9C43F629C29E8BBB4 -:10FD1000C1FFDA6E1C1EBB388F23FB37C7F3F6E634 -:10FD2000F8D1944E89B78AB8B3B51FF2476584936A -:10FD3000FA35AAA1F7A5A6C7F379ADB530E9276AC8 -:10FD4000E2FEE384DEC438BF89FBA3F96313FC71D0 -:10FD50007EA6667F688C13F17D853E77A29EBA539E -:10FD6000D0BDB378BFB38F753F6E27758CF7FB128C -:10FD700043C6FB1DE328DE0F5FEA715EC1717FA4FD -:10FD80004384CD2F3F8FC4B7DB8354D44FF54677E0 -:10FD900035AEBB5A7783FF0EC57DBC2DB41F30F046 -:10FDA000507707AEAF5666B0BD16E4B7658CA17F3D -:10FDB0005FDFA25B1E06F56B3CCC8AF52337F0753E -:10FDC0005BE97ABB03A7698075B065885F1FAC8B60 -:10FDD0008F21BCD7B74C6EC4FD8135F7321B9AA179 -:10FDE0005A569B1B85FED0061672DDF89490B30917 -:10FDF000397B55D417F1E8DF87A0D353824EA00F8B -:10FE0000D6229D87B7BAAFF0FD38AE4F4825E2FA4B -:10FE100074BFCE1B6A3D3F373A771DF2C1406FE891 -:10FE2000F5C35A0BE7B77511AEE7A8DD2E7EEEB528 -:10FE300054EADF593AA607BA4F11749DB2819FDF89 -:10FE400060D7AE5F57A59FC8A87F867AA5F45E8B62 -:10FE500017E343A50D191E82CBA5387AA2BE687898 -:10FE6000DF85F9D2AC2C2BC6239C7F65CAA93EE462 -:10FE70006232AEBFF4EC94D42764C7E368DF69B2A2 -:10FE8000E0B7B5163B3F470D288E00FC976E58B67D -:10FE900017CFEF7CF46B46FB4B47D4D661D8D954CF -:10FEA00040CE922198EA5921C52BF8FED5BDA21F5C -:10FEB000CFBF615CB37FDCA90D07693E470CCC6303 -:10FEC000063EBAB4E73E3BFADB2BE3CD14C793FB07 -:10FED000B24755F7E36484F4AD1508DAFD0D115609 -:10FEE0008C7FFC43F05D46827B1FD2C7BD7C7C05C6 -:10FEF000DAC19665A674C4A37B79921A0770BAD743 -:10FF00002A34EFD1CB938C787E61E68AC1E3504FDF -:10FF10000D61CE9518DF7928968594D3F3F17C9DF9 -:10FF2000585C6560C6689A8411E32F176B148ABF0A -:10FF3000E0FE5B01D0678E985FF9AAF7A3883FECDB -:10FF4000F06F181ECBE53F73AA4A491EC1CE6BE481 -:10FF5000A78CD51993A09F796B6039DB8DECFDF1EF -:10FF60000EFE43C079EFF23A6D7D255BF3399D7F3C -:10FF700061E0EF5BD02E68EB3F95F2E8600EA4AB3A -:10FF80007BB1C58CE784460BBC14AD51ACA85F6651 -:10FF9000AE688CBF0FF2339B5407F2B4C40BEBE88E -:10FFA000EFD3398FCB4D3D693D70D96EEF82EDDCDB -:10FFB000515CFF2B7AF7702C7F28D63D1CD7F1AD12 -:10FFC0009F58189E9B39D606FE18C61ECD6C10C5CC -:10FFD0001FAC6CD0A4003B5A64B02660BCDFC316D3 -:10FFE0002632BEB7650E9C77A5790DF98195E80795 -:10FFF000F2F9911FF8502C67D5D6D7153A9FC3EA6E -:020000021000EC -:100000000DE4079A851F78D65E9B00AE17733D6E90 -:1000100020392DDE16437E68F18A5C23F26FF1AE43 -:1000200018D243E0077ED863989F8EC756641E4857 -:10003000847E8BEB321CAA967E5AFFB8E698A45BAE -:1000400047BF4F4BB793A1E806F4D294A72408FF0B -:100050004ED08B3D164B7E47E182B77A9A019ECBFC -:10006000556174EEA833FF83A5C6D1BE9E5C17E62A -:1000700025B7AFDF68DFFCCA9AA144B7607AE5FD17 -:1000800067E670B427ECAF16867AECA1EEECE1C916 -:1000900050FEB0C2E5EBA1EAF17928A759095C6FDF -:1000A000BEB714666864ECFDA566E6ECC5D8074BE0 -:1000B000AD94FF686922E53F5E6AA7F493A57D28A9 -:1000C0003D29E26852CE8001885F472570F91A9574 -:1000D00020E2DE6C5122AA8CBCFF7C305467C5A1A3 -:1000E000D2278C4D63EC1E272023C0DF997E6F043E -:1000F00012B93DDF62B08E4B44FF719542FABED813 -:1001000075BBA63DF825463CFFCDFA64FACBE99CC9 -:1001100098DD3819F8F0FEFC584DFB6935299AFC3A -:10012000E4043BCD7B525E774DF90385FD35F9A2A2 -:100130003640029E2F30DBF8FEAAD8B767CCC6D770 -:10014000EB56DEF66AD5F02EDF0778AF1E32507D13 -:10015000303D245D67ADD731378036733DCC0DFA25 -:100160003D593B93E4EAFC110BD9FD95DB32DF1DD1 -:1001700001F963DB0CB4BF7E6C45EC5ADC3F3EB644 -:100180002D3E8A41EA5EA9321FFAC17AAB9105E899 -:10019000B7DC15CBE8FC5691D7E440F92FDAEFF93C -:1001A00095CCDBD11F4420513E3E54BD3E85E8E74F -:1001B00024FCBE14E6DD02F933A0AFF1C8F8CC167A -:1001C0000ED71985ADC0FCD9B0BFF5FA3EC071B1EC -:1001D000A0B64487EB01F5503CE9CB1D2A43BE2D68 -:1001E0005C60A0FDBBB91FA91B31CF9421299CDE07 -:1001F0002A9D47642F99A87FD60A1C02ED16FDD6CA -:10020000B489D6774CE4770FF4AE16FC897C74265B -:10021000863963085885E03DF77EFC46ACF7E3D3AA -:100220003B08E7FDA5DEB53201F8EB5C897710E904 -:10023000B5C7E249AE82F17ED2C8F59607E540F136 -:10024000EB4BBF9C2D273E9D69702438485F652588 -:10025000A1BE3AB9C640E79899DE193589D63F3B29 -:10026000888FE53827F5F67108DFC99A0C86FB966A -:10027000C56B54F20790FF787B2FE7FFA755371B1C -:100280000EFDD6286ED6A523DF3CB260389D639A5A -:1002900021D641C17AE0339055772F7F7EDE1E7ED6 -:1002A000CE8665B5E8EF1D18388F157CBC44DEBFDF -:1002B0003C0750D6ED4F47D1E5BEDCD43D1AEDF0FA -:1002C000D90F55E2B3B3DD6A8725023D2FE8F60E5C -:1002D000FB3EE4CF17784EE921FF54B87B6702AEAE -:1002E00057746BD2956E783EF6C4DADBE1BB73AF20 -:1002F000181C24E64BE2497FCC7B696ED7C0F38E95 -:100300001DF5972F99EFBF389314C0E77C7BDD383C -:10031000EB005C77BB841DE2F8B1E3E62AE0C5BAE6 -:100320004EC143C3ECC450CB6A3C773D13C4243068 -:100330004E7842EC8F1F107A45FA09115D787EA63F -:100340008EF3377B5521BF0D7E34FABF529C4F94FC -:100350007A5FEAEB32564BFBC14712F839C6B98ACD -:1003600097DA55E0CE2EA8A8122B0F42976D35795B -:10037000BD19D49735D00F48EE62E7FB43C6579EB0 -:1003800045B62D65CD7C7E41EDCE19BC25CD191D20 -:10039000ED4D8975E30A1BF56F7060FCA454C869C4 -:1003A00079ADE2F5F17990DD94F18AD9C26E06DB80 -:1003B000A70EF628C80ECD0EB2B3AC566B5701DEB1 -:1003C000481C47C21B0CA72BC24278980770A1BDDE -:1003D0002D717B0F4C24B8150750B2033CA5CC35CA -:1003E0002606E701F53E7B47F882E7D5015E31CF6F -:1003F00060B84B1C9FFB70FF18CF8751BC29681E4B -:10040000921EC1FE9AA44B8987E3B7A441217A7E4C -:10041000DAEE07328A1B497E8105509DF67BD74470 -:10042000D467A5EB40FF66F8F947F2D33C56178531 -:10043000FC52C17C2B9350BE7C75D346A2DFBEE13B -:100440007D23CA49A1CDD7531783285CFBD3BCB405 -:1004500080F544109E6F44D76F8A379C955EC6BD69 -:10046000004FB337ABCEB0419A76E21C9187E4607F -:100470008EC763C4F8C61CB1EEBF119C957A7E6E20 -:10048000FC86F076E2277D5BB8F3BA68FD62BF9F19 -:10049000D5333A949E6AF7AF82ECFADF0C3C7E21AA -:1004A000F5F155BD93E225502EFCAE2A2B8F9B070C -:1004B000E9F1B42CD2E325C2AECB714EADDF49F1E8 -:1004C000B7D968F703CA3F5DB793E2FEC6576647E0 -:1004D000A1FF7D6AFDCCB578BEEBD4B69964E74B3D -:1004E0009F9376DE6D0CF41F72D717BDF863E4DFBF -:1004F000AD61149F2FD9EF16EB1ED0ABD0CEBE9EB0 -:10050000EB51B68EEBD552B48703C81EF6C6768B78 -:100510004BDCBD510E02CAC94E2E9EE9FEDD1EE81F -:1005200077F1CB110E0FA1C2EAD391DF6EF5A13D99 -:100530002C5FF8F1513CE70EF6FFA31F48FB0FD9E3 -:100540008D7AF7922E286FC2EE97AB1BD3ADE827BA -:10055000083BF15FC0BF3934FE8710FE8B11FF01ED -:10056000FB20C76B389E6706E1FFC41A4E9795DBE8 -:10057000BA47E1FAF1784D77F2B38E6FEB49F89F05 -:10058000B51AF0CFE35F5A3FAB06F08FEB08C43FDC -:10059000C05BBCDF2EF0EFE0F8AFE178676B783A34 -:1005A000AB039E3D748E61F1AF4D0EF41BCE84F90A -:1005B000C89F3AB35D65D5017E98F483BE60B5BF30 -:1005C000427F4DE27F6EAFE641A87F0A9FFE531443 -:1005D000D261EE761EA4EF807FE6EC82FEB87FFC4F -:1005E00076BFE9952EF1017ED34DD2A982B918D9F3 -:1005F000C5863F1DC17583E2844F6D788F46DCD779 -:10060000A8D7DED7C0331985368C2F38CC6684271F -:1006100035F81E8A9B611CF99F3D3F9FB190E4BC59 -:100620005573BE6D22F319BAA0FF58A7D0FDC6F2CC -:10063000453951390CE3D45504C7E92E8AE6FC78D4 -:10064000B9AA23FFB1CCC8FD48B93FF9AEF00FDE1F -:10065000EDC2D725EF75B1D27797C218D9814B1665 -:10066000A317EF23C07A2A11C7F7EC3111DD8E22D0 -:100670004C807FD528E2366002914F1F649C4F1F4B -:100680008C6CA23839AC545E40BBF8D0129383FC1A -:10069000DAB8688AD73E20F4DD83912B5D681F1E8F -:1006A0008A343A31857E3D7888CE301A8687F10DBE -:1006B000C946BAAF53686E790597BE0F279E78D4A6 -:1006C0000CA0DE06EE37C655E0D75DD7633BD2C53A -:1006D0004F1F6D9CA7323C74DCA355E04B713A2947 -:1006E0009E6382BEC3018E2B682FB1DC6EE5F19D47 -:1006F0000D40278B9FBEC1E5CCC3F703CAF05CE376 -:1007000028C6196404E15F932F33F2FAF0C4AF26D0 -:10071000ACCB66ECCFCC3E10E956863A04D7F74511 -:10072000D15E8C97DF83F1251BA67AE297C97AE622 -:10073000D1F1B42612CFCC8978D34481CFA92398A4 -:100740002F1AF0EE3BA88D77DDE7D3F97A037EEF21 -:10075000D1FB1A913F7566BBC10AE3B8F29421B888 -:100760002E295B7E73F0A6259AF3D7A5425EC7CFEC -:1007700085B5FE80C7211E046145BCCDD0B3FDEA1E -:1007800010CE0788974A9BDD43ED1628140F95710C -:100790003649FFC1D07D201D1F14F0413F3551F86F -:1007A000BD3134BDFA26CAF5731DADABE70BB99B5D -:1007B0002FE56D9B56DEC627DAA9BD827E30E0EDBF -:1007C0004191762617E344FFE312B95C64DDE278D9 -:1007D0002CB2359DCEB708792937F1FEE5F8F788B8 -:1007E000744CA28DFA95F000BF1EC77E74A00190D4 -:1007F0005F4FD656937F348705C4B533FCED245F35 -:1008000077CCB7EB11DD754C8DADB310F5CAF7C2DF -:100810001CA8471F34D6F5AC8AECD84EEEDB14B2D8 -:100820006603233D29E261C2FE8C5523E97C40A189 -:10083000C2EF0F5ECAB17874D118A73110690B638B -:10084000143A3FF137B17FF250F4E28928D785514D -:10085000463DA633582BF5FB776BB7E8FB18DE3324 -:100860005631760E038FC877C2B8D5A877787E8DBB -:10087000339BA24A227FC72127E0E1DE6B407FCA7B -:100880007F2FDF09FD5F7A4BD4B33BE9FB4B8F0B26 -:100890003EF6E4F2FCCF657D1ECFAF92F5F93CFF4A -:1008A000A4EC5FE49F0EAA5F1654FF4B9E5FBC3E14 -:1008B0003FDF837EEB68CED285A314D2537B84BE08 -:1008C000285CEE23FC16EAF6F27434F3E9B26EDC2F -:1008D0006E53A26B0FDA1FD572D282F6F7D564275A -:1008E000E59F4F702F4BC475D424C563447DFBA195 -:1008F00097ECC1C44ECE1FEDE9C2E3F89B92A0BFB6 -:10090000A17EFB05FDAC4E8CBFF57E1C491CAE8064 -:100910007E9EF926F0FCA7233C1BBE493FB392B54F -:10092000FD487F484975BE86F36327E334E745E613 -:10093000FFC4118DF12786E74500F5F397D7A5672A -:1009400042FFF35F7D3DBD04FD2561E72BDA74CCEA -:1009500089F734DB18A5E71B3F31E27DB38A5D8D53 -:10096000C671D0AE12D2DC00B8CA049C60E7F49322 -:1009700003EC7383D01B8C3DCDF7375F3DAB477ADB -:10098000CED7D59D7A0EEDF62825E43ECD66F1DD75 -:10099000D14ECE17EF157AE86A9AB311E7F96B8C4E -:1009A00021403EB7BA93FB60491C5F85C2EECD1C67 -:1009B0006631DB01CF433FE4FB54251B3286603CAC -:1009C000F8CD84D1EF247E6D3CB595C7531B783CA0 -:1009D000B5D0D6BC089437332695AD31DFC1D88465 -:1009E0005F48390391856FF34C325F9D3F269BC76B -:1009F000BB307F76FD636B506E9AC2B91FFBD0F09F -:100A000081E1A8175A3222745690E737E38B8C495C -:100A100043B1FC8E71589E63B2F42A22FC32E28B01 -:100A200037E35DC7905FB03DC641DC465FFC7D307B -:100A30000FF7DB2A9DA7750F8A7087DA77FA87C0D0 -:100A4000AB31C94A69139019FD1709871C1FFCF9BE -:100A500045CDD0DFC9E5498357DB719F25C7903469 -:100A6000D43F7E4682FB72E0F82775AC172E296EC4 -:100A7000168E4B020E03EE5D03BE5DD92A7306ACE3 -:100A8000F3268F89D0E4EFCD8F65CEC038EDBD2938 -:100A90009AFCF4C2EE9AF60FCCEAAFA92F30356774 -:100AA0005505F8B19DFB491E82A7D26209477FEE2A -:100AB000EF0D5FFCE541F4FF36AB0EF455E7EED9E0 -:100AC000F297DBA1D5653C4E45F1473BC5CBCEC97E -:100AD000F3287AA73E705FE8226BA6F33E9DED03F4 -:100AE000C975EE7CEB7E3A77F65DEF03F54A12EBC3 -:100AF000DD216C08DAC3CB551F51BCAE2292CFEF7B -:100B0000E2EBC78CB80F8AFB8AD781DFEFC20FD127 -:100B10003F6CF3503C3BB7FE18ED9B1D48E47ABA9E -:100B20002275811EEF1D55428A76681CE8AB68E08D -:100B300097E646367017EEBB6658B81FDE3699B199 -:100B400058E42B1EDF694A88A17BD7F36BF2A8BC5F -:100B5000A22D9CFA7F4F6D1E47E7095F5368FFA1E6 -:100B600020E5A1E5787EB829DC33E01118B7E077FD -:100B700077E521DE2A76F1F3B505EA9FB316405AF0 -:100B8000569B47DF17A8AC49017F61422EB7BF05CE -:100B900068F321AF0EB3AC46BBAB1A7DBD9E473D9B -:100BA00063B4909E896E7B80C6AF6C33D3F7F72415 -:100BB000717FD7D0C2E11ADBE6A272C90F5393BA94 -:100BC00069D60F86F8CD7A7C97C3D0C2A8FDDD6DBB -:100BD000FD2895F37DBBCFAFE93EAE21FEEAB81408 -:100BE00098F7DB718A95DC90203D7CA56A78340B00 -:100BF000A1A7DAC769E3E7F44C6DFCDC5E618A7398 -:100C00007E12C031F1B1163DEE07B148B315F13592 -:100C100071C4607B49807CA97BEF37227D0CEBDEC1 -:100C200037A29D36419A1B505F2ECE3304EBE90567 -:100C300049524F2FA354DA1D767506F9A933AC82B9 -:100C40000185FCCC10FA547EDF4C6B1AA0E36E1EBB -:100C5000C77F34C5BD02F545730E9BBE83F4667332 -:100C60003AEEC37C57F0039DCD0AF9892D741E75A9 -:100C7000E208BB0EE3FFAB045C528E6F348FC5A25B -:100C8000FD7B2A5B82FDBE77E79DCD4EE8AFF14745 -:100C90009999680FE4B8CF25F17B29CCDA7A0DD782 -:100CA00083956F44D851DE0B703186FB9D7B4CB42D -:100CB0004E8172DACFA87CC3B409EF895446C17A59 -:100CC00015C6CF7D33CC877CDCF866981EED46EFE9 -:100CD00074F77348CFDC377B8FC1F5A1B3C1A4672C -:100CE000E4F7389F273DDB09BC37D25BC17C26E5A2 -:100CF000D35DC3E5A548F069B1903FB790A32B55EC -:100D00005D480EAF3C0640E33EE963CAC05DE8279C -:100D1000D82DF47E9394CB025C0F417941FF183AB1 -:100D2000FF2BFD8D60392C6BB352BFE56D7621EF43 -:100D300036CA4BB92B167263127EC62CC1E7BB5361 -:100D4000DCEF205E0AAA41EEA3681F3F0BE5C9CF86 -:100D500037462BF217F04D624980FC5437DECFD076 -:100D60003F31C5B9886F66411AE89FCC6EF74FAC2A -:100D7000E31200FE892B327478DFA99D7FDBF9E650 -:100D8000E6F87F8F9097E2485F4FF4670D55610E4C -:100D90003C877E398EEFF72C5CC5F1B8D0E0CA45B0 -:100DA000FF62E12F158A97A1DF817A69D8912A63C2 -:100DB000601CE5FEB641CC0E7898D2D683D23713AC -:100DC000DC47110F456DD304BE067DA3FDC5A14EC2 -:100DD0001E4732784D8E8D19184772AB48E733693C -:100DE000CCFA4CE07EDE7A1DC5C3E4BEA38C2B9901 -:100DF000F0BC7C801DFD425F9B4EEF3704C79972AB -:100E0000B8DDBFB0D94076BFACF1CFC374507F2EF0 -:100E1000C3D905EDC9977A771BF2F5BCC9DE570D2A -:100E2000909FFFE4CEA891763F3EEBF4BE9E6847CC -:100E3000EB008F18EFAA5BA3E679B9BF13C1F7C91E -:100E4000387F4B7E0EE6F3796DDD889FAE5499C8EE -:100E50000E5D01BE65017648DA1DA9E7A5FD917C0E -:100E60005DAEE7FAAB3C32DAEBC908B43B935C39D0 -:100E7000C8777DF8791ABFDDD9B47614CAC1A53810 -:100E80003AB728ED46B01CBCB6141CD35E1DED8EDF -:100E9000D4EB52CF4BBB35FAE52F77FE15CD558AF3 -:100EA0007B4032E0EB6E3DB75F77EB2DC43F63E3F1 -:100EB00026E9916F6E5E8F1E137AF498468F5674F2 -:100EC00062070627DF9A1C7415EDF34CDC7F443D66 -:100ED0001FD8DFA329A3C7E03CC627733BFB5DC136 -:100EE000DD99FE1F9F7C6BFA7F58B288F7DD40FFCB -:100EF000172673FD1FACEF9995BFA773694F5F2F3E -:100F0000DA83A30CEC03DAC18608FB16610FC85E16 -:100F100084477BBFCE1E5C4D9B5988780A610F1EAB -:100F20004AFE16F640F2A1941B2927522E82E5486C -:100F3000CAC5849FC23A11E9F41EBF5750AEF76C80 -:100F4000A3FD467BC46094CF763F6E9742F2D6C134 -:100F50004E08F9F1CB8BD66E48B990F222E5A75C2A -:100F6000C8C5EC20B9D8A7D63D330AF7CB92DD6BC4 -:100F700093E3FD7252B623D83E74CA57185964B32E -:100F8000E3AA18F25539A4817C65EA441E9E49BE45 -:100F900035BF68D94DF2D36FFEFBFCF49B4EF8E9E8 -:100FA0007FBE0D3F75F4633FCEB2033C57B240DFC6 -:100FB00066F8F96DC23B8CFB0FDDF97A00D6970419 -:100FC0007793318DE23E13AEB32A8A2F0ABE947412 -:100FD00096FEC06C11773893E27A07E1C5F5C082BE -:100FE0009BD37B4467535CB311D727B3210DF40324 -:100FF0003AF37F9B6F51EFBD7193743E96FC9DFB5E -:101000008DC79243FB8DC7B1FC9BD2B5209789F861 -:10101000DE8F0B30DE38E1299167CB0A108FD34683 -:10102000C8FA9F3CE9EC81FA81C9B838C539DE536A -:1010300045DEB3F4F018683FE119E68F9B43FDD815 -:10104000ECE8F6B888C2FCED95E71F3BBC86E8519A -:10105000CBE5CCDDA2E7FB3F229F05794B407E44E8 -:10106000507E036F1FA56F6181E745909F94219C7F -:10107000CEAE00FF0186DF7F05ED85556118D7A84C -:101080008CDBF8D615D46BF50AED45B5E381D514A4 -:101090003853C5FBB9945F73D8093EC203BB78BE11 -:1010A0004F4AED931EBDE837E0DCBDA14E71D2B9C9 -:1010B00083118AB75B46477CF749D1DA27FCD16BAD -:1010C000BF67781EEF56BE6FBFCFD68DBEF7996E45 -:1010D00061FCFBB2439F7FFE5E0AE7EF3159D121ED -:1010E000EBC7A5A8BC1F1137A0F1A1684A5DE87B3A -:1010F000B013C5B8CDB85F42F8DCF624E2B7D92802 -:10110000F1FDF293C8776319D3C4CF607CCADF9F27 -:10111000F272418D9E4FD71984AFAF9BEF8014A917 -:10112000BFFDF8F204D1CBF435F87684C0B75DFB8F -:10113000BDEFEBE835ACC3F7826FE7483E766AF85F -:101140003D5AEF22FE8C8E53ACE84757B8C2D6E02A -:101150007AC12F9FBF27BE6C96FB031DE4EFB5023B -:1011600094BF0A8947CFEB4FA2FCBA74EDEDB93CAE -:10117000B6F33573F601BC52C80FBE7FE4F9FA2707 -:10118000312E097C41F594D707C01D2C8F7541F98C -:10119000EC20F915F247FA03ED01E0A927EAB7B808 -:1011A00063467B009FFC4CD0E9A2B827DA3C9AFB4F -:1011B00093CDDD78BA2385FB8FCF097C6E12ED9B32 -:1011C000C303F090AAE11F1FAE5B02E64D78BA3F61 -:1011D0004ECEFB93827CD063CD365EBF2DE5A32738 -:1011E0003DD9FE7C707FAFA67C528078F1F7FFF18D -:1011F00061F423EE1778DB9172E4B02752D039C145 -:10120000FF4E21F007BD63518EFCA174E48F1F7661 -:10121000E44F4FD0F7F44E7767DF7B3A7EEF0CFA5E -:101220009EE13DEA9BFF5ED02D3F88AE7941741D63 -:1012300013942F9479AF46FF4ABD5C5CFFF4E30939 -:101240007118DF54E838BF9F9F4F93BD996F95FC8D -:101250007BE630F2AB9F9FCF129E27D709BA79CE9B -:101260003D897A7812EAE151FEFC14D443943F5F41 -:1012700080FB617E7B7581EAEFAB91ED2F92FD7A69 -:101280006085ECEF33CA4B3A32CF25B277F70BBD0E -:10129000C33CADA4F7E735F0EF3F7DFEF3C35F2B12 -:1012A0000FB54178D91094F704B55F7703FBB622E8 -:1012B000E8FBC782EAD704E5D707E56BB4DF17CDB3 -:1012C00052480E8B46F0FDC960B90CE68F2F52DAFA -:1012D000E363EDF65C8924FF4E235713AA79FEFAE7 -:1012E000F3FF29A8890CC8A7B0891EB2EF305AC0F5 -:1012F000FD41D0B91E15F8C1D089DEBCD899DEEC0D -:10130000136CEF79FD3FF0D724DA2FD2F825FB5488 -:101310006DBE51957047BDBB2832605F955926E27E -:10132000BABAF3FD9B8889635203FC224FF84467E5 -:10133000C03C65FB715F5D5771BCF8D4F0899B714F -:101340007F68B4D8D7B4F114ECA58AF6BA52C46F4A -:10135000C6E1395D6C17EEEBB930D00F6275BD7028 -:101360009E8D3F52F9BB50D5401FC05311B3D37966 -:10137000D39978EABE3BD447472FF90D7CB7EF47A6 -:10138000EA12B4D34797C4D239A645A9DCEFDC17DB -:10139000DD356136E41B231E267DDBF8C4584AF791 -:1013A000AACE95AD56E83A357962645FAC8F263C9B -:1013B0003936C44F5C06FC9D996A2738DC366B428F -:1013C0003DFADBAB0DB45F082D7E45FCF3A469301C -:1013D000AEB78B96F5A7FDB0E29F4F1A87F7B08A9C -:1013E0001F37D03E498BCE4A7122F7EAB1742E6A7C -:1013F000D60A917AEEA2F4CDFFFCBA1AEF69B5BE17 -:10140000A0D0FB0E775CAD7B67109E9BACE94EF7DE -:101410002EDE8075009EFB3EBEBEB717CF219F0813 -:10142000ABA273A4D09EEE8B955EB3BF3B310BDBBA -:10143000ABD6E5D0FE1494A3FF7C6A95BA09EF41C0 -:10144000154559C2F1FCF6A9AF18C5754E3D6EA2FF -:1014500077228E47BA67AC8FA3FBB8E8E9B3538A0B -:101460003D4A013C4CDAD067626212969B047DFBD8 -:101470004415011E8A74EDFC43F6A42486E727A5D3 -:10148000F699B805E671EA97BDE97CD8C154E7E45E -:1014900054C0D72FD29C5352E3115E6EB7DEFC0FBF -:1014A000DF8FFCE385E204E4AF8752395FBFD1569A -:1014B0009C10F8BE77C9453DF1C19B46FB227A27B7 -:1014C000303C4DC17536F0412CC6CD6789750BF0A7 -:1014D000F3929D21FCABE1A92AD1ABF1A7F1D94848 -:1014E0005F3F5F0F7F17F519AD37205FB121732D77 -:1014F000DAB993A625EC440FD67EFE91ED0B233C82 -:1015000019B68579C332307EEA1C87FCCD12EB7A9E -:101510004DB604C8A168FF770F3FE7FB77688FEBF4 -:10152000BEBF7BFED712B89F21DB9746593CE85CD3 -:101530009CB658F4488FA3FAA5A7F03C5AC90B06ED -:10154000B203252FC43FD68AFA07F806E36BC1F32E -:10155000FA63AA81C7313A934BCF18AD5CB231130D -:1015600071BE9DC965CD86DC899B233B97CB522BF1 -:10157000D74FE35EE0EF51960EB5E8717F73F40B41 -:101580006F6DA17B740BC286E0BD89D2174C44AF4E -:10159000168BC563BD0DEF1358F431903E9BCAED19 -:1015A00069BD909F5C95E9CD4328A57B1272DFF061 -:1015B000EC92679EC5E397E79877DA70C0DF6527FE -:1015C000E7D3CBBB548A3F06EF23961FDC69CC617F -:1015D00037B18F7883FDC332D622DEDF0DFD7DF07B -:1015E000FEE1ABA9C1FB8706BA4F5E2AF60F73373F -:1015F000280477E9127ECF3F3796C78D4F2E05FA24 -:101600001B69DE1EEB103C0FCDED4E2953BC66F876 -:10161000F5AE0D0B288ED913F184716EF16EE2894F -:1016200030473AAEF34B5E0823FC96FE6AEE5F7ECF -:101630009985F7FA0AE202D7D5FB912F387E19DE99 -:101640001F94FD9C5EF6637AA731F745581FC37C53 -:101650004A63D8ABF76720BD92D2719F53B62B5D1A -:10166000FEA35EBC1DACAF611D5DB44AE5EFC7ECE7 -:1016700036911D04594F6401F72C67AD38683472F8 -:101680003BC6128709FFDAEEBF9F761CEAF1EA6ECD -:10169000A5B88726F127EF5115E9F8FB74853A853F -:1016A000EE578126A37B499753B95F7B3A959F6795 -:1016B000284A77D0FD9CF2B526C7F20CDE4FFB7DA1 -:1016C0004F58DF95EB9A4B683FF3F7268AAB54AE41 -:1016D00008738645F1F3173B06D0F96ABD11F05146 -:1016E00066E7FAE2B2986FA57DD25D749F41CF8E16 -:1016F000E8A1BEDCC2F563790CE03D92338A6E1836 -:10170000BE67C7E8DC24F69B3428607C4594433FE1 -:10171000F6287FBF4D3A5683711B6CDF7710E2319C -:1017200076DA7484EF1595E41990B47604FA7DAFF7 -:10173000A899B8DE2E5AB56F1CEADFF9DB07E38DF6 -:101740000956F4EA07643FE60BFAB7887367C59059 -:10175000C777B622D2B83CB9551E2F8A485334EF0A -:1017600010C9FAF255061EBF073D8F8AA57CD9C75E -:10177000D46FB9A53901F56FF96EC330D4D351696F -:101780005C2E8B97A5651F01BE2A3644D3BB8365AB -:101790009E0223E6CB6A15CAFBBF8B4F473E3DBF77 -:1017A000E2B528E49F1361BE9E68975A178439E812 -:1017B000DEA195C7EBCEAFE849F79566599B2DF8AA -:1017C0009EC1AC45DD6DA8BF8F5A7D46AC3F5A9790 -:1017D000A1C3BCD36ACDC6BC537F1BE5CF8BF32D11 -:1017E000F4837CA5703A976DDB67C4BF4F3244CC5D -:1017F000F7E22B1FF4C2F84F797A732FB42BC0078E -:10180000BD5210CF2F2964972BB6F1F3EE920F2A19 -:10181000900F40EEE6093EA8D8F5DAF7511E2A905F -:10182000FE433AF211F0F37E2ADFB1711CE3DFEFE1 -:10183000473E91760CF22B0C368CDFF17C661AA7B2 -:101840003F948FE1E59E01FC1C5DFB39048D1C7407 -:10185000465F571AB787C5CB4CA46F5D695C1E5AAB -:1018600056ED8E42FA5D7C65DF01DC6729DF0156AB -:10187000DA1E421E043E2A71FE51043FF9179538C4 -:10188000DF28FFFCDBF95EC86125E3F393F3ADD4F9 -:101890008BF9CB7AF1FD24C12F654CE06B576F2E8D -:1018A0007742CE508EE9BD0E313FB74DFB0EE5F7C6 -:1018B000C5FCDC2265D6BA28C40FD217F50F3E103E -:1018C0006994FA049A5CDCBE91CEF14B7A49F857E0 -:1018D000093840DF39636C7E3AB674F24E6495E0A5 -:1018E0009B638F7749AF07FC9DDF4ACF6C11BFEA3E -:1018F00003C6937C23C7CB7D79D2DD386FE8DF87C1 -:10190000FDCB718F7A22F4D8CF51C6E543C22FE5C3 -:1019100032B7FAA1BB074761BB8B96EE0370DE9C22 -:101920008EABD2ACF4BD13FD05F8DE59AF50DCFA36 -:101930009858E71F7BFCB5A8E2017E7E7F427C279A -:10194000F90C7F303E26E16DB2F1387030DC520F79 -:1019500049B8739FB8EF6E2C97F0E3BE51209F4AB1 -:101960003C4A7E95F7F582F996784EDA4FB573FECC -:10197000AE4C3D46E7773A9407F727FCA213E25CAA -:10198000796B3CE371FF1589FB35F78A188B0CB432 -:101990003FD28EC0CF1A7D80FD69BFA716E73C8B72 -:1019A00074BB90D68DFA3FC7EA8C39D06FD999E6CF -:1019B00071F8CE9DF443EFB8EA53A3315EB58B9F27 -:1019C0007793FC5276613FC941B9B8FF54B4EA83BA -:1019D00082E1C8EFBF35D0BE4ED1E3638DE8DFCFE3 -:1019E000DD327318A201EF41A05E3FBB796826BFCC -:1019F00059604D9886F721363F33ED01289F55AF4A -:101A0000D2BB0DD80FCA6FD1A399145F3D11D65226 -:101A1000300AFDF81FA856F4E36FDF32F4316C7F13 -:101A2000BBA56B0C3DB6B13996F24E7D34D907E9B2 -:101A3000F7CA7380D5E2DEC75F84DE3FDC9E2AE210 -:101A4000FC5F752FDC8F6FDD1846EFAC141AED7557 -:101A50003E1C6F4F175A67541AF1EA23DD5B25BF0E -:101A60006C8E9199938650B93909CA0F1A9A1F45FD -:101A70003B72F051CB607C3F92A9D78615737F9A59 -:101A8000EF3BC66ADF2D91707C24C60FEE4F7EDFE0 -:101A900084EB081BDD4FA4EFCFAEF8ED34B48367C1 -:101AA000B7F6B4E1BC4FEF09A3FB03A70DDA77CF7C -:101AB0006EF5DE57F07D29796FF5749AD68F93FC19 -:101AC0007EC37B377FD39E83BCD1B9A50B4B19DD79 -:101AD000FB7E398DD1F76322BEDA89E7084B6A4D68 -:101AE00056BC077312F91EF7B376ABFCFEA599CB73 -:101AF000C1C9DD9974BFB7E46F3C5F52A778F13E6E -:101B0000F2FEA79FA0F30AB3C1CFC4AB09EDFEF369 -:101B1000BAA7A7A1385C76B857E27DFECB5BF9F98E -:101B20008A0EEF321CDC7920C9DEB9DFFC5DFBCB0D -:101B3000320E119FAEBDCF2FF12CD74F6F023F8CCD -:101B400018E2C7DB674BE790BF7C61A99BD24BCA09 -:101B5000B1B5B7231F5BA2E9BEC01FEB9F51F1BD1A -:101B6000A8F25D83AFE13A78546434BD93F2D9D2E0 -:101B700025B48F7A616915A592DE320E77C7AE461D -:101B8000FAEEB3FACC06BC9FFB4664B4B003B69041 -:101B900074EDECDEB19CD7B91F70FA4AB8CF6D9DD9 -:101BA0001985F36A7C3EB66124D23522DA8A7E5FDB -:101BB000A93847726A3DF7ABCF98A37F930FF43DE6 -:101BC000B3614A02BE3737BBF1DE69585EB247B136 -:101BD000E27AC0B1675214AEDB3ED5B744E1FDA84E -:101BE0004FD7CB7B555EFA3B54A3F2D8146C3FCA57 -:101BF000A767F60CBE758D7C32F2829EEEBF9E8783 -:101C0000728A935C0BA73809FCC4E2B991D9AFF38F -:101C1000F84AFB3A57ACF36E17F37E34DD26F73102 -:101C2000A83C77042F3FBD61E744ECEFEC668315D9 -:101C3000E1FE6CB381FA9F07EB331DC07B662B5F1F -:101C4000F7601ED7CB67B7F2F5CDBC3ABEBE295FB1 -:101C50006070F2FBA25A7ECC0D6847EFFB74F25E17 -:101C6000C83C279FDF3CB09738DF60BE8D6175743C -:101C70008FEC9B9E170DE6DBF9925F857E68E7D7B8 -:101C8000CEF844E013E51DF955F2C3BCF57CDFDE68 -:101C900056373807F94EF247F03B59D546C6DF575D -:101CA000D485D37BB89322ED06B40F53E25AC620F5 -:101CB0005A3E4EE77E809AAB73E2BD37566D0AF905 -:101CC000CECE8A74EE57457465C4EFDE742B3FCFD9 -:101CD00029EE7FC914269286767B5284ED0B3B3425 -:101CE000793AFDAE7BF4C0CF936EB73DDADDC1D853 -:101CF0002FD30BEED1C37C2665DA767783FCF3BF56 -:101D00009AC0F3B7D9861A20BF4C9978CF18C8D794 -:101D1000A73B9F4A0F18E7EC962E69383F28FF191A -:101D200096D7C5BB7F8E69A5B80F7649691DB424C7 -:101D3000C3DFFEFD3D96A37FB4FBF32D0696EE18A0 -:101D40008079097FE8B425DDF9ABF4F88EE5C58C20 -:101D50003D4EE7F53CFC1E0EFCB8CC09784F8AF3EB -:101D60005BB1BC975313742FC7C1EF9FC9FB52F2ED -:101D70003E545FFF7DB20DB7729FEC9281FF1D2A2A -:101D8000C5A9BD0FA634FC89DEF9A9F6B09630A22C -:101D900083F69E4D39BE53771BDD0BA2FB874C6F3C -:101DA000277D3357FA3B68AC87F9DF296089FCFC53 -:101DB000C1A3821F4F2F653D7A80E89F7FB739CA44 -:101DC0000E705C98E8EB85FA2032DCFD27C4D7E979 -:101DD0000DD5A90BE3F01EAAC9910FEDCF78F97DBF -:101DE000CE32E1B7B2CDF1422FA8BE3BA15D534642 -:101DF000DF4D6887DE177C7521C397FE23D42B192E -:101E00007C9D04EDE83C5DDEF2BBE2B1DD85ED4F8B -:101E1000F4980D709B0006BCA7351EFA1C61A3F751 -:101E2000AA984AFBCF5EFE7E929E79A26CF8EED510 -:101E300033E9E23E11DD13947492F8EF4017181A5B -:101E4000FD599D991910EEBE6C03FDFD2F491FF938 -:101E5000CEE2C2DD3CFE427724451EE348A7CDE238 -:101E6000EF9F75B08B6F91BF0A62E9D1E89F0D3388 -:101E700043DBC9111B8DD8F5776D2FFF9D2EFC928A -:101E8000C16C70E03B92A5A2CD58B5D08EEF5B2D12 -:101E90008C37D37B250B5FE84EFCC196FC9005B6D2 -:101EA000631B62895F5666A884FFB9F58CDE1D2A24 -:101EB000A84FA6F394F9F5364AA3DA12A9FCEC6F01 -:101EC000DEC9E27A89D3A7E07FBA8CA6734BFFD331 -:101ED0009B52D6D97BA79166BACFBBF020B76B0BCC -:101EE000A7CABFC7C2EFAFBB0438AEC81A8A0BB9C6 -:101EF0003ADC53E7EF57BAF0BE007EE734507D6717 -:101F0000EF574AFC9A04DD82DFB39C7A303391DECE -:101F10007F14EF594E17ED9AC5BDB3CEDEB5BC4F59 -:101F2000B47B226A5C13F2DD746769C8772DF59E75 -:101F30003007FACF86D4487A47E13E37F8979AF5CA -:101F40004C8B1EF1302D9BBF733975BAB6DE90FDF8 -:101F500039E97343768777920CA88F4D2E6DFBEC91 -:101F6000AEC20EF5657DBFF65DD15423D94F3DBE9F -:101F70003B0BF969E25D51F40FD1FFBFECB410FFE8 -:101F80009BC43BB8CD2C2B11F5C2ADBE27FBFFDBAC -:101F9000FBB1C1EFC406BF03DB7FEB424D7E60DDCA -:101FA0000F35ED6FAB5FAEA91FEC5BADA9CF6CFA3F -:101FB00099263FB4F9394DFBE1473669EA47B6BC8B -:101FC000A4A9BFFDCC0E4DFE8ED63F68DADFD9B690 -:101FD0005793CF61EF68DAE79A3FD0E4C75AFF57CB -:101FE000D3FEAEC4139AFAF1F6F39AFA097DAE68FD -:101FF000F2058E2F35ED3F37BA577745BF22EA0CF1 -:10200000F1AD3A4361F844F9E5A62966D4076BBA05 -:102010000A7D24F86FB9B0D3AC07A37BAC63D56C51 -:102020001FF15F3DFFBBA0C1764F7FDEE5C4F81F07 -:102030007B8DDF6B8B067F521F307E8CD3CC02FFF3 -:10204000EE5D6C9E55938F77256ADA77996ED7D4BB -:1020500027B9FB68EA53E63834F9B4AA119AF65D59 -:10206000973835F90C4F9EA67DF71A9726DFB37681 -:10207000BAA67DEFF56E4D7D5FEF1C4D7DFFAD5532 -:102080009AFCC0BA259AF6B7D57B34F5837D359A8C -:10209000FACCA65A4D7E68F37A4DFBE147BC9AFA1A -:1020A000912D5B35F5B79FA9D3E4EF68ADD7B4BFE9 -:1020B000B3CDA7C9E7B0839AF6B9E6F735F9B1D63B -:1020C0004F34EDEF4A3CA6A91F6F3FABA9977ECED8 -:1020D000843E9F6BCB85DF53E0F897E6FBF6F76E07 -:1020E0007728741FEA5CD76EF27DC5963015FD2403 -:1020F00017C5996C781011F515DE27B7F1F33985FE -:1021000014AF8A237F884C941DCF0B81DF1085ABE1 -:10211000B68C0CF4AB23FCFE5BEAF5CC9BF7DFDA64 -:1021200084FFDCD5EEBE88F231AF6EFB387A9F9823 -:102130007956221CF2FDBF7783DE6D95E978F3199D -:10214000A60FF0170F86D5A60EF99A38C178F305B9 -:1021500086EFC1B6F72BE222F8C7BD1706F4BF160B -:10216000D617F8F7236B979AE96FC7FF6CA995F21A -:10217000EB962652FEFF003A29BF47008000000080 -:102180001F8B08000000000000FFED7D0B78544518 -:102190009670DDEEDB8F249DD07975779EDC3C490F -:1021A00048089DF0D8003E3A216040C0E635044919 -:1021B000A4C1A84143BA81F84F7475BB311002B273 -:1021C000B391D11095C1860164199D092EA3D1093F -:1021D0009AF09AE03A4C601CC5D91937A0A3E28E58 -:1021E000101EE3CFEE8FC37FCEA97B93BE9D0E382A -:1021F000FE3AFFF73FFAFBB4385575AB4E559D7369 -:10220000EA3CAA2AAD5E898922636DDE1C4A9FF3EF -:10221000DA9998C9D8366F31C1DBBD0E82FDDE7206 -:102220004A777A9D94BFCB5B41F01EAF8BD2BDDE67 -:102230001A4AF7793D54FE92B781E09F7A7D94B6B1 -:102240007B9B29FF156F0BC107BC6D04BFEAF553DB -:10225000DAE1DD4BE91BDE762AEFF47610FCA6B757 -:102260008BE02E6F0FC187BCBD041FF19E26F8982E -:10227000B78FD21EEF6794BEEDEDA7F277BC57097A -:10228000BE8EBFDB19FC2ACD9FE431263097E67A5B -:102290001EC2CCC92632F600FE4B82FFE24688CC35 -:1022A000C2D8FD8CFF3ED7B09A76139477FEF23FEA -:1022B0008502C674A58C8D1F0F6962F6CEC634C622 -:1022C00026B075E64F7218D34057D76307FB094E07 -:1022D000191319D6C3DF752DFEDFC7583CFCBF9418 -:1022E000E5784C836953091442FBBE55827F771A07 -:1022F00055D7203EAB8D1CBF695A1395573E2CF81D -:102300000D02635522F3E98B18FB7D5854011BC164 -:10231000D8258F2E47C47221DC0E8304F88F3A44EF -:102320000E7E5D2C8EB1A59D861D9BD206F1AA84E2 -:10233000EF35F0FD2B561A0CAB643D3AC403F21D89 -:10234000DA18C69EB7B8A64B90FF608AC6A787F674 -:1023500099C99FED8C64EC2D8B6B06E65FF2DC7700 -:102360000C1B7FC06CCFC67E661BBAE21741FFFD17 -:10237000C7B5F69DD2F0F3E16E29676CDC0DCADFBC -:102380003C97EC023CCAFFA275E1FC9FD04556F891 -:10239000F3012F49E0784A1A553ADBEA5A82F87C71 -:1023A00019E9B9470353F8E56DABF6AC812155AE99 -:1023B000CA1AE182EFEE822563198CCD65928E41B7 -:1023C000F97CE6389A064D2D642E8217311FA56FD1 -:1023D000C5BBAAB19DC5CC4FB06BB22135D4B88274 -:1023E000F172CB78B9657C94F471ABAB8EE3E520E8 -:1023F000BC4E4CBA231BC7A5E0F59655A27A73587C -:10240000FF76C4EFCB83173F113286D2C7774017D0 -:1024100026681EEB313DAC73A38ED1F78D8F087EFD -:10242000A46B852E2A9991B7FB18E40B817402F4F2 -:102430005184FCD29F3A3792E8E449091A7C7092A1 -:10244000D6A71F0BE3D4F8B3052DD1875E00FC1E81 -:102450008803FA481F9E0EEA9A210DE01FA0AF677D -:10246000B0BDF3AFFF5D0ECE97FBCD4912CE57A3A3 -:1024700006D601E8D8F7B6D6BE5B92991460ED9403 -:10248000317EA46B26DAED73C7E07AB1A54EA8DFE2 -:10249000AD650DFBF387F6FB2AAE17B47FC2A62B02 -:1024A000F753BB9CCF95F29FE2FAC563CAEBAD5ED2 -:1024B000F569AD16F03F71E89C5E1A13621C0D6F52 -:1024C000E76606E0EFEE3833DD6142E4FAF2E74515 -:1024D0000EE69F94E944A11FAD3ED2B5C314881700 -:1024E000EF17E8F9E74437D140CF1944CF9FF8E020 -:1024F000D3390669C42248FB606ABA2075BD60D62C -:1025000023DD2C67764AAB9993D20760F9917E9DC3 -:10251000BEA7F438EF0FB276CAAF2BBED782F47CD9 -:10252000BFC6958A702DEBA57C37EB2FB3C1FC2D70 -:102530006C5E7BD40658CF6F796A5A02CCEF3CFFB1 -:10254000B2A398CEDD257CE293883F7A10AF3EC1DE -:10255000B33E11FABFFBA592F549903F47CBD78513 -:10256000FD2B5F17457E048F1BF8A1978FCB41E3AE -:10257000D24695ABF8A1F209E610A09DFE8306FFB6 -:10258000CEB400FE287EE8DF93508E89FDF7E07A16 -:10259000BBDF34C4E07A3F08E21BC72938186B80E0 -:1025A000FE90D62A63882A88DE1F62E176ACF7B9EE -:1025B0004CDF9FA730A2EFCF05E66040BF1774A69F -:1025C0006601E55AAACB5604F8AC60BE2606E56E55 -:1025D000CD4B05384F2325D7A744D71FB53715A6B0 -:1025E000A1FCF7A70A28FFF719EC8D69AAFD845D05 -:1025F0008F4021E361389F3FC076C70EC54B283E10 -:10260000F69F421463063DF3198B88BFD944E4EB6F -:10261000443DF157234E6D06F6E3943CA6A1ED9F91 -:1026200090F1EDF94A4B74EF83F1EC1642F5C3F7E4 -:102630002B43F8603F243F2C8CFAD1A7713E56FA09 -:1026400063A6BE6427D0756A844B978682C116C77D -:10265000E58B99CB979EB44F33717DE64CDEA8C8CD -:10266000656A8FDDC6E5D1099DE443F844499A1DAA -:1026700024D7809CBDABF897A7118FBB8CA62E2DBD -:10268000A4EC16DD9FFA947D307D70FFBD4BD97FA1 -:102690006FE1FBEF1C99B5EF12BBBAF17BC6EC3AC8 -:1026A000C42F97FD5E998F6DB8DF2AF271C87E0B3B -:1026B00003EBC5F913252B8374B5C0C7BF3A25DCDE -:1026C0008F7CC436E7D2F8F4B2FC0CFEDE5AC15857 -:1026D000A651C613FE4B70195966CE209C54635602 -:1026E000C1291E9BAAFEC80649559EE6CB51956797 -:1026F00034DB5570564BB1AAFEA836870ACEF59743 -:10270000ABEAE7ED75AAE031ED15AAFA633B5CAAE6 -:10271000F2C2AE1A55F9B81E8F0A9ED0DBA0AAFFEE -:1027200077A77DAAF2497DCDAAF2299FB5A8E05BE3 -:10273000FBDB54F56FBFEA579597B07F56954F3541 -:10274000EE57C1D3CCAFABEABF80FB16F0CF1DB6BE -:102750006E55FE0CE9B8EABB3B734EAAE017E47570 -:10276000F62D0E27BE682DE7FBD16CFB07AA765825 -:10277000E768BEFE613C6F7BCF1F0B514E6ED7F4F6 -:10278000A721DD4A5A7322F27166F1DC4340662CC0 -:10279000DBB1AA14C55B4EF95387301DEDDC5F8AAF -:1027A0006C925F71F210A605AE8BA5D01CB3D74416 -:1027B0001FC6B4C85338D58AA834CC3D8CE944DF51 -:1027C000AAA928575F785C3F1AF9282A46A14F0723 -:1027D000D1677D8286F8B97EB1C98FF2C732C52430 -:1027E000329013961F5AD6B1024C8B9A316DF61A5D -:1027F000995F0FFA809751BAC96B66FE6C2067AF7C -:102800008DE0FA93F795A7433B23AB4433AA99E6AF -:10281000518F2548D0BEF5E5969C5D76C6D6EDB0C5 -:10282000CFD7E542FF199EC53BA2014E638E05300E -:102830007F1698233699B1253BDF76FAF287C29747 -:10284000339D4D2417C4F65CD4FF947637967E6E84 -:10285000D79821DFF74BE71198F7ADF1E1F41DC2EE -:1028600025995FA75D470BB60BF99EF6107CFC4CD3 -:102870001ADF7F97A4737D0A8784EB66E5CBC6AC2D -:10288000A0A78C80B9DC3AA9E10CEAF0A2D927A074 -:102890007C62D7E07B902B89582983E0DBC3014E13 -:1028A0004058626C7F96EBC7D8AFD5C5D8D900FA2F -:1028B00049A851C35B619ECF660EE2A35BAAF18972 -:1028C0003006DD8F9D763BF4B3AD0AC60BF0563D66 -:1028D000D737947AA3348CF6F72FD3F87ECEAECDCB -:1028E000B7A39EF4A53C9EE7BCFD8B3ECE447BEB9C -:1028F0002AA589351EC105F2CD5AE9B4FBA09EAECA -:1029000011E62384DEF28B3491BED71D7E4490A065 -:10291000DEA76912C189957E1A77520DB41B80BF5C -:102920004DF40966C8B73DE613103F9BD96967F0BF -:102930001D335A88FED7C83C616BF8CBA28F410F7C -:10294000D3799D76ACA7BB13E8331F27D46366B851 -:102950004EC9E347B010EBA3A4863E0D73DC409F45 -:102960008F4A7DD443FBC5DD26290BE8FB85C5A630 -:102970008A1D21DAFB549E9F0D31EAFE2D5A3E1F1F -:102980008ADCBE6CE6EBA8F0F19A68A692E36B5283 -:10299000C65B6F84AFB5CDC85C01F86E857ECCD0C8 -:1029A000BEE1AB55661C3FE8D04EEA4FE4F264C787 -:1029B0008F72C86E0A5EC721F408943FA208E9A38B -:1029C000CFDF087C68A8D2DB516FB2FE4393807BD7 -:1029D00073226B1150BE5853CA7A44DCD74457AEA9 -:1029E00033843E7933BA54D64FD99F83D74B773D42 -:1029F000E3FD129CEF7FD531D4C7561F8F8F710531 -:102A0000D0534C3AA7CB62D6A245FE98CCDA29BD6A -:102A100085F5527A1BEBA7D4C1CC22A6A5CC4E6972 -:102A20001973523A9D79282D672D94CE64ED94CE7A -:102A300062BD94823D43A99399C9EE9A07FB37A6DC -:102A40000B9893D2EF310FA599E99C7E2B580BC1BF -:102A500077B3764A3B80EF243DFA018C9476829CD2 -:102A6000C3F44D9073987679252665A31F2087D2ED -:102A7000235E3BA5C7BCC594F6781D54EF6D6F3936 -:102A8000A5EF789D949EF05650DAEB7551BD53DE5C -:102A90001A4ADFF57A287DCFDB40E969AF8FD2DFB4 -:102AA000799B291DA5077EC6F9CDE92B447D3EF50E -:102AB00023BD4302F9EC91E5D26187E699DCF1B8D8 -:102AC0006E1A66403A285B2320FD5973340E3FA4EA -:102AD0009B72560BF742BAE104D7DF0CD648D20FEF -:102AE000AD6DF58204ED76087DDA0858CBE9E9A9E9 -:102AF000738D209F4B3AD9BA083BC2194F1981EE0A -:102B000076E83CFD3BA0BC64A734D7087BD6E4C87C -:102B100053FFB18FC3543EE9086B34033C2B3DFB9C -:102B2000A93881E381C2EF7B3B73E6AECD443C25FF -:102B3000C2F3C534302C51BF7EC444FA7561DBD971 -:102B4000420DC0931A4C45681706D4EB42BA1FAE2B -:102B50005E70B9F2DDB65596469C870D9F805A0E81 -:102B600059A9197D85ABF3D5ED6ABE5EFF4C7B8319 -:102B7000FE03EB0937686F7F96A3327DC2FF7E3A72 -:102B80000FA66FDDF58FF66BC80F648EC1FD74570D -:102B9000349733FDA09FEE04BC77C5C8F0C64C1A2D -:102BA00017CA435CB70D9BD2FD3E80778539571F0E -:102BB000C7F27FD4D87742D1AE70D7A65C8233C932 -:102BC0003FB121C69313938FFA3CDF975A931F0DA1 -:102BD0009302F8BF399DCBAFADB75CE9DD81764498 -:102BE000B38665C1773B9B976FCC81767EBC19F429 -:102BF000078047DC5ABD310BCAD3376A266A65198C -:102C00008778FC7873F59E4DA85F258F8EC98676F0 -:102C1000336479991ADB57B806E8BC55AFB6A79567 -:102C2000F49F647EA98666CE826C4D95EDF41D3AC4 -:102C30005611B8DFFD4CC6EF57593CD5DDCEFD57D8 -:102C40008691E1FE2760FC2523B9BFC3B2CE48FEC2 -:102C50000E4BF27F9DBC03CA2DDB347654E9446BE6 -:102C6000ED5A1DEAFB8B593BF2E30E817FEF4BE1FE -:102C70007A21280AE97303ECF2ADDED38B3203FC30 -:102C800084B60A9F80F67BC9C85AA10FF79FE40754 -:102C900005B4FB2D152EC11589F68187CACF65B9FC -:102CA0007E920EF8D92AE1FB40FD92B912705DA127 -:102CB000DF8A76D2F35851607FA7B3F83CAC073B6C -:102CC00099F4D5757AC22B78BE4E65971EC0F695DD -:102CD000750C2EFF7E06B7AB773D015D201F4CE2E1 -:102CE00076F389DD89A43FCE690D77A0FD74E2A952 -:102CF000D165046F99EC403DF2C4EEC9D3319DB368 -:102D00006526D53B21B01EB487E76CB95BC4FCD403 -:102D10000CC00BDB3BA3277A9CB3E541F9FB47CB07 -:102D2000B0BC58E3FB09DA91C58DFB22D04E9E1C46 -:102D3000F94A12A627347DF5DDD0FF5D66F62BDC5F -:102D40009E9D1BE3FEB11CFE31F7A9741DEAD7BF9F -:102D50004B4FA7F59CCF1CC4075083ECBA5BF6F62B -:102D60001E064D8ADDD6DE3F15CC5CE6E8301FC17D -:102D7000B4B4CB5E86D357D6E33C82E9F45E4F19F8 -:102D8000AA2FE5A75B8E60BA24D7F53B9C9F17FF5F -:102D9000E17BAFBC08F0C8C7EBCDA807653ED137D3 -:102DA0006327F9EB740CF9216B92A7458B046C74C3 -:102DB000C6A07C78F6695183FBB921AD250C61C3AF -:102DC0007DE91AB40B7745B7D4D0B8B3C219CEE3B6 -:102DD000DBB00F215D64453B63909F802F691D3EF2 -:102DE00093E9D310ED3147637E18CF1FA817CEE1CA -:102DF000F303F55AC204EA274620FB13D406DCBFCE -:102E00006DF2FEDDC63C09381FD648CF0EF4EB64E8 -:102E10009570FE67919C2EB07AD344FA849CCD962F -:102E200016CF9DB80E5697E8EB0BA43BD80607F4D7 -:102E300091748219DAD75B050E839C21BCF0877EE2 -:102E40000C8BC9427A8D82BFB502DA0BD033701C6D -:102E5000F34C83DF2974179BC1C73542A6BFAC650D -:102E6000BC3D05DFB80C2E9F016F4983F868657C77 -:102E7000601C9A007C02EAD1F806F066761BD20547 -:102E8000487A81A74C1203C75FAD7184A15D647A53 -:102E9000F5FBE84F8942390278FE53F72423F269A3 -:102EA000F0387232D208DF46D087516F9FE9E2FCDA -:102EB000DB58E911C83E4218C79F2C3AD01F68352D -:102EC000AD167401E3B526F37D7A66A5A71BE5CAA6 -:102ED000CCE2083BD2F79DAC7D9D99F3F7914CC0B5 -:102EE0006F141BF899D8C441BDF0474FBF7B1297B0 -:102EF0003499B597E4E2FEF9F8FDB370FDB63E3AB9 -:102F0000B307F14FCC79AA3B061A745E94D77D19AA -:102F1000F7EBA46C133F0E1C479207E040BF448DB3 -:102F2000BA1CE841052B7465131AA271BFD144E4A1 -:102F3000CF9C817A4A9486E43BC829614148FD339D -:102F400088AEE4F957D6E7AE8C4C5A37AB89AF035D -:102F5000EBB71B1746CA8355D609FA6D04361F0115 -:102F600074DF58A6F50B68D762FD28ACCFE29D91BF -:102F700043D769874E9A3903E5F4C31AF36E367462 -:102F80005E81DC7E4B7AEDC371540EF9A291FC7D1B -:102F900001F86A43C1EAF5B859FD6DAC6BEE8CB42B -:102FA000A1F989C90B66E23E9B58CB68FD83CB47EC -:102FB0003DA65E57B237C7A3FF88F9BBBEC17ACE24 -:102FC0004CDE5586FA7CF0BA2A74971A1B7A5F1089 -:102FD00033395FA646D84F95935E21929EE04C11FF -:102FE000E303EDA20D197C1FBAFD3513ED43EC236D -:102FF000A31FB75C7B57EF93B9B00EA5573468AEEB -:10300000B0A3EF1CFAE14C48A7FDEADDD5FF0AF5B5 -:10301000A67D651A87F96FB0BE19E810F1F5809D9D -:1030200001F0DA2FF6B4A0A3A4B192D971DF55FA5A -:10303000D923F7F30B9DDF49F23557643B490E82E4 -:10304000651E402F0069897E78197356B690DD6839 -:10305000CDCC07598D6EBDF625B45FFE49CFD0EFBC -:1030600038AF42D295C0F8E7554ABA65E8C7175954 -:1030700039EA11F32BEC943FBFD2CEF38D3C7F4164 -:103080008583F217543A78BE09F2613E1656F87BF2 -:10309000BDD0EE42538CA4413F78A593975F355045 -:1030A000F93B600F6402C98787F949DEB77CA6E166 -:1030B000F1124FB85F005C0D91453D12CEDF7D1AD5 -:1030C0007B162486149199017EB6C2E9D742F9F3A2 -:1030D000CC9F8013F946F56A6736E4BF912C9A714C -:1030E0007C6F38C06EC6F9AB1569DEE907F01B3599 -:1030F000C914CFD821FBAD7D2B8CE467055D87FC1F -:10310000AC6C45A2ACC7F0F26DCBCD7ED4C7400EFF -:10311000D23AF6DF27921E00F2F0ED1CD48B5ECA85 -:10312000B4874948B76A7EB3542F2FA1F62A99195C -:10313000EDF25995BCBDC697347E0DEA55A679339C -:10314000910E1AF7323BDAAFCF569F2A8B45789B08 -:10315000DDCEE5875A2E34566F392EE1783C1A734E -:1031600016D5E77EAD464FE92EAD30C8CFB4DED2DE -:10317000A0FC182A6FEC3DD84E4255A97D13D4B35C -:10318000C038D18FBD4DCFF37DF7881467B0548B15 -:103190005DE68241FE4E91A7D0827C1845F245C57E -:1031A0005FA35F52C33F92F914F85DC471F97631A1 -:1031B0003BC9955DEA7A20273528AF52DAD4F96702 -:1031C000B204C52FA59A87E079B67AB8DC0B1EE762 -:1031D000E0B8BAC246D1B8347C5C28D7203FD77457 -:1031E00088F2732B45BB24A1BC6B3F85E31FF5928E -:1031F000C8BA009E555D3413E969D6660DB94366B9 -:10320000B35E920B371BB7E2DF081E67F0F8366437 -:103210006869DF1CD007D71B491F6C7DC4A4C1B8E7 -:1032200022E85BE1E8573897551A9E09F33022539C -:10323000D6D7AF6BB93C6934119DEAAC8FE504FA7F -:103240001F84D1A523B0BEEE7AECBC728A1BE9685C -:10325000DCC172AC58966393FA607C2AFF73389392 -:1032600002E6F7D6FE18157CFBD54455FD12102E4C -:1032700081E5538D79AAF269E6712AF80EDB1455BF -:10328000FD19D254157C67CE9DAAFAB3EDF355F023 -:103290005DC54B54F5E73AEE5595CF2F7F4855BEA7 -:1032A000D0B946052FAAF87B55FDC5AE4655F99213 -:1032B0009A2755E5C1F693929666723FCF569BE7E3 -:1032C000A483E48B4B70460EAD67A914FB03D73D76 -:1032D0002A82EB53C1F51AE5F57841E0FDB1FE48CD -:1032E0000DF29DE27F63ED912AFF5CD7E4C9C63EF3 -:1032F00013FA72ECEF23DDB213DC1FC5FCFC3BC5F7 -:103300007FD5FD04D483F65647A65B71BF43BFABA0 -:103310004B0FFDF935E4BFB736D70BB40F6EAEE7F0 -:103320007E95AB7AE68A0DC08385F37EE5788E8242 -:1033300027734470FF6018CFDF26FB959E43BF5272 -:1033400036633FB0287E7817B59B50ACF7A17F4617 -:10335000A8F6087A945B2E66364828079753FF979D -:103360002BEC2358887956D256AF8D39A07D5BBDA2 -:103370006FAD1EC656973969CBB3D0BCCDC3C81F3D -:10338000F368E6942D6B81E7FF2153A2754910F98C -:103390003C3F5FF7C6B93DD05F6B95A508E56A7005 -:1033A0007992BBF3E2B11B943FBFF2D50FEEBFD1D0 -:1033B000F7751D679A02CA87F58B56243247001DA0 -:1033C0004886D07EF91FC874E59EAC273FD6335A95 -:1033D000D793C8CF1726FFD7C4BDF0DD79E9CA3D22 -:1033E000A8A743FE0F301FEAD1BC9ECFBC44E729FB -:1033F00052F340BF47FD3B2C34DD1E94DB17AD95E7 -:10340000FDE8075A1DA997D0CE4F327E467EEA0EC0 -:103410001DB7AB83EDF7E707ECED76B2BFF7CBED69 -:10342000EC9653AD997FCF8C3E265AE4F84088F94C -:10343000D046B50928AF12ABC54F02F9A23B524F97 -:103440007E048B49F63B986A547E01C56FD01D7986 -:10345000BF80746FE95A417E7AF417607B07E57587 -:1034600009F6172419FFB4E8E3D81BB5CF06F223F9 -:103470008410FD04E1A1F82782FBF1A33E81FBCC7F -:10348000CA70D22782C77D39B3E450663CF248FF48 -:10349000C93B507E9FD2D17E381CBD8449E1CC1FF0 -:1034A000D07E6F26B7EF23726254F991F644E60F8F -:1034B000F45FB364F32711320C5BCC487DDFC65157 -:1034C000D8DFDBBCBF133ABB8DF441D8F6D0FE7B0E -:1034D0004FE6E7EE5C4669AB6C97B7011F63FA9C59 -:1034E000D74CFAD936E03F84B77B254AFDDE1C4A2B -:1034F000777AED54BECB5B4CF01EAF83E0BDDE723D -:103500004AF7799D94FF92B782E09F7A5D94B67BEB -:103510006B28FF15AF87E003DE06825F457D5044D0 -:103520003F7533A56F785BA8BCD3DB46F09B5E3F4D -:10353000A55DDEBD947FC8DB4EF0116F07C1C7BC2F -:103540005D04F7787B287DDBDB4BF9EF784F13DCEC -:103550002B8F93B1E65E2FFA2B5CA284FADDB3AE1B -:103560006A33EAD7B6651A338AF336976605FA39AD -:10357000B655F2789F6D9586FC40A087FA519FB3AF -:103580002D7BFAF8342A5F40E55BB149304AACAB99 -:10359000B8FECA56EAA99E150F02C177DB6A2BFD59 -:1035A0005A805BB2C3A9DCBA4A24BBED798D273AB5 -:1035B0009BEB5D24BFAD3AAE3F28741021FBE9229E -:1035C000B2444A976573FCA33242EF2319594AFC6F -:1035D000A4B907C767AB82F121BE55F5468C5F5A87 -:1035E000EF83F149A43FAE3A047824C378117FC039 -:1035F00087FCC26C19D797AD55EB08AFE465F3941F -:10360000786734DAE96D9EFAB9846FA5487ECD36C5 -:10361000D7A1E8FB504ECAE77CACF1E14E7FFE50EB -:103620007C3282F0DFC6B8DD900CFAD2FE10E300E7 -:103630008B47A9C7FD788F1943FAF126CB7A62B27E -:10364000C0F98F3D2C12FF6D67A0F7C177CF817E47 -:10365000E7433950BA6F15FAAB1ECD724DCC023C20 -:103660007E248D3F24021C53CEDB4FAF17F7A01EE4 -:103670000DEB7DAE09F2373EB8D989B671EC6669BB -:103680002DB25BDBB25713D0FF952CA8D74749CB9F -:10369000653CB63B787BCFD58BE44FB6AE3A90769F -:1036A00084F75B86FD268EFA7D18BA613216481AB9 -:1036B0001419C955E245EC2FECA1CDE5D85FFC66A5 -:1036C00087D25F21F6F775E769E4E365565708BCD2 -:1036D0008693273793238BB322E3488E24B1249417 -:1036E00023CFEBB8DCF29DE4FA241D869934B41F95 -:1036F000257EAEC4D383E3E835323D241942C76149 -:10370000570DE8FD3EAAB7DDB1C949E74B303E0B86 -:1037100045AB756C05AEF3EA9270F3DA10F4A0A431 -:103720005B508E01DFDF8B4623B5B3B99CB7A3E1B5 -:10373000EDDCCA56115C6232FB42C86B257D5A6EC5 -:10374000E7812C4EB7490FBEB4F118AEEFDB3A3A21 -:1037500013F49CC6BF11ED04DF092DC9D7446DFBDE -:103760008E3D017835CBE3794EEFCFB523FF407B1B -:10377000F92857915FF2C97FC16605CCBBF2DD5ACB -:10378000D98FFDA36B1BA229BE5CB52E0CF5A33609 -:1037900066247AB0EA3CD18501F46045BA0C411F39 -:1037A000FBB2F44A3CD5543211E3327C5F9E8A72FC -:1037B00009F03E581D45FBE1D465EFDE3916E05BAC -:1037C000AE8876D4CB9EABE5E71327FD5143E726C1 -:1037D000DE7C9CDB7DB7FDB7B21EF47B27C8E9B366 -:1037E00068E7417A4B33B377C1BADC526D22FFCD23 -:1037F000AD57C5B381761AB9A4C7A37DC1FD3553B2 -:10380000FAA13C80FE267DA6AE0F33AA453D23A13A -:103810004F9D6FAB3A70661AF4D356CB3F6EBBF632 -:10382000FE71847DF51AF29300F529F49340FE4D64 -:10383000D19780E716371A19C973EB32A319E541FE -:10384000B7259CE45FDB6213E9A11B325787A19E79 -:103850006CA8AA8FC674A4DEB7037DA7DDBBFF7D6D -:103860009E2D81E42D3F7F8184590CFAC0BD7AAE34 -:10387000E4F8FAB64CCB4479A9A1F2C3BBFF7D8B27 -:103880000F7D07AC85F090342C910F7E00BE9BE23B -:10389000D402DF2F40674E44F874AEAB07E54342D5 -:1038A0009CAF1B8BB69ACE56D2F9E2CA38E2335D92 -:1038B000B587E931BFB2C818C8E70A9FFCB5FCFF5D -:1038C000B41CE7BB991CB859BB37E3F79FA573BE7F -:1038D00019CE9E360C234F15FB18CF9A638A6C4B7A -:1038E000FBEA597D48FDEAF66CCE67C57A7E3E64F8 -:1038F0004EC5F4728AC3F8FA443CC79693CDF9A931 -:10390000CD124971E2B674D6857103DF720DF7F7F7 -:10391000C4F1FFDA2AD3C93FD42A78A27D19783EB0 -:10392000C29586EBD706731409FDB7A672B9CEFC13 -:103930001E33C6ABA19D9A40FCC1DEF3A9E9989164 -:103940003E4CFE0B2DF19EA40FF0B7A35F1CFD179C -:10395000C1DFDDDAAF866FBFAA864B984E054F35C3 -:10396000AAE16966356CC9E67AFA1D3675FE0C491E -:103970000D27A71C09D3F073EDA6017FB344F0BB5C -:1039800099017EA00D9A7601E725A5AF96FCB2AD10 -:10399000A9DCDF935CAFF67324B296B53102F96D02 -:1039A00054F9B6FC5502FA736CD5EA7C9807158C6D -:1039B000CB8AF4BF24D7959F8D71E9027EEE3A4BF6 -:1039C000EBE9CDC575688B233E4A93CF050DDD1F0E -:1039D000B7D0B89576900F7C01E345FA0F842FE6B7 -:1039E000BA2667C7733EF005EE97F97D3AE403A562 -:1039F000BFE1F841E1C762396EA29CABB922B7A51D -:103A00009CABA997CFC775049DC7B9925C46E78167 -:103A1000AEF4AE090FC577C867BE6CCE77986E94CA -:103A2000CFD720DFF9F49CEF30DFF0D52A6728FDEF -:103A3000F0BCBCAF3CB437CCFC71C0F856B647AB59 -:103A40006077478239F0BCD343F80F74BA37333A02 -:103A5000475A2B0FE78B33BFDBD308E95B5A970B31 -:103A6000D76765D6593D8F33F5EB51FE9E97F7DF4B -:103A70000D82DD385AC094DBA58D66BB11FDBDCC2F -:103A80009FA1F257287E87D52BD2AC3180FF8801C9 -:103A90003F82D34CE74DE333C98F1135D571372BB6 -:103AA000043CF7CC986F04A2DC854E5590C78F6517 -:103AB00097FDD0973C385E03FAAB02CE2319440F32 -:103AC00023B97335954901E7CA5B65FFC5001F9BA4 -:103AD0009697607F3FCC96783C8679D672FF9FDAC6 -:103AE0005F66B86A53B533D87EB2AADF56D92F7253 -:103AF000F3F6D5FE37C3D5F461DACF0E6ADF1CB218 -:103B0000FDC176D57EBCAF111F6F433E18CEFFB509 -:103B10005F96A71B6C9E5EF47FE918D89514070684 -:103B2000FA98886A23FF69C3F979535DB2DA0FA660 -:103B3000637E921FCF47D690FC48603E8ADF59983B -:103B400087F2D7474DE7F1BB60B9711379C1988708 -:103B5000A1DE00FDA9F2573FC2F7D346C1EE423CB9 -:103B600083C7F3FF8ADDAB891CDF4BFA734AB86465 -:103B7000B881DEDBEA7525E3F71BC23D3518EBFEA5 -:103B80003CBB2E763DE83D1B30C6087C7635BB71CC -:103B9000BECF84FB24A78FF5711AA227CBDD961D1B -:103BA000DA007AB2E85D69A8F75A34F2392FFCA13D -:103BB000BF6CBD65E7A610FD2BFA9B025B2B008F47 -:103BC00000BA6D95F5E681FE9624EED006B4633119 -:103BD000B80AA93FE55CA3D25FD337EB6FABECF734 -:103BE00052FAB3DEA31E9F55EFA1F159E5FD47E957 -:103BF0006F2B8E2F045FDDB43FD98E1EE86FA97A3C -:103C00007C568387C667D572FFE1407F4DDFACBF2E -:103C100036F91E934DE6D3E1CEFD370E9CAB761AF6 -:103C200051AEB429FE40797FBB14B4BFAD96F737CF -:103C3000E5FB4B71E9E4DFBDD433DF186A5FC3FDF8 -:103C40008CC97A2493F54826EB9108CF997AA63E41 -:103C50001EE8B0F0C5B6F922ECE3731E3A333E1508 -:103C6000E0192FF6CF17615F9AF3E2990349F0C983 -:103C7000CB2FBECCCB7F78E64A32949B7CEFCD2F06 -:103C800003382A96EFC70ADE4ABFB78DE27AA3BB94 -:103C9000E173EEBF04F98AFB5663AA87A17FF14264 -:103CA000727FD432A8EF4EE9B72C0F312F4AEA6E5B -:103CB000384F7E46147928FFE6E1BF40B4CF53EE7B -:103CC0006794ABEF6744456D22FD2F8CF9CD28EF4B -:103CD000228C0EBA4FF8D628BE1F2C64F60A6E3717 -:103CE0004859F2390DBACF31BF586ED77CCBCFB11E -:103CF0007CA1C6B11EEDD9DF4EAA8A47F558391707 -:103D00009737787F72D7F51B9C1F0EBE3F39E7238C -:103D100081EBC223B8BFA53B57E2F7B902FC86A8E6 -:103D2000F70E379FB5A3B87D3F389F0E3E9F310EEB -:103D30003E9FE6FEA8B5B0FEEEE87ECB13C49F5DC5 -:103D400021E76BC8BC06CD5FFD28A6D8795AA4B779 -:103D50009BCDB732AFCAF9C14641CAA2FDEA4F793D -:103D60002AFD8331BB142A8E83F419B8BFEA6D4E45 -:103D700086FE195D9C3D07CF9537FE451BF25CDE44 -:103D80006E793ED64685D3B9CEC6283DD9DBDD5106 -:103D90003319FA9745D3749A97B2A8723A6FA98DDE -:103DA00065ED688F069F23D78EB89BCE0169AD68FD -:103DB00041403A702ED961A4F889B9E886E7C8C5B0 -:103DC0009B9D238F99C9CF9147E9257459B445EA42 -:103DD000439E237F6C14DFF7BB713C71883F8C27B7 -:103DE0006D701CA299C7D1313F02F2F56617237F8F -:103DF000BA3CDEC7E47550EA1BCC1E86F240ABB776 -:103E00004BA8A768C3F93E61B069584E08BFC8F710 -:103E100047E9E8FB4F72CD34AF1A23D7CBE7FC5A02 -:103E200008E94F7A7594E24F0A4D67C3D1C93C0D3A -:103E30003F47A7F0E102939ECEF72D30D94AD10F2C -:103E4000B20008EFB39880FAB72DE2F78145BB0DB9 -:103E5000E9E737536EFFF96F18BAF9B97C3E35437D -:103E600047F7E34E09CC618F197A7ED5E98C9E869F -:103E70006E9ABB669D5987ECF7E2F2EF15617B867F -:103E8000E353751689EC9F7746A15CA84E5B1F0F24 -:103E9000F0A2CA421DDDDF94E344EE082EC79FD195 -:103EA000BA4E8EA278D1E751A54847627F2AE2A395 -:103EB000C48902EABD372A9EEACDE1D7C5A0DE1843 -:103EC00094D3677FEF62B41EB6507A12DA4F2C306B -:103ED0006E23CB07B4A302F3D17E6201EB272C2F14 -:103EE000B6F68590174A9A60DB92520D7C9E90D070 -:103EF00042A992FFAC435BEE0FB1AE57E575FDC62C -:103F0000764C1B603B71D08E01FBE52ACEDB17D5CA -:103F1000A72CE36148756517C98EB1E9153E9388F2 -:103F2000BF06611EAF04FB4575DEB0D5EB4BA1FBB0 -:103F3000FEF2386D2BD646A31D03551C489FDBBCF3 -:103F40006D29659983E3C8CE91E9138DB689A817C9 -:103F5000F35F725CCB0CF497249B34743E012653C0 -:103F6000752F616E59F4B4383445DDCC6E92D02E85 -:103F7000EF253D3FE1BA96F820E1F0628671ABA4EF -:103F8000B87601EF030DF423DF6FAE97E3B9575C0A -:103F900065348E04EBC0FECEC80E8DF3CD4579742A -:103FA000E5698E51C28FD5E5C971FCDCC2FDD5E152 -:103FB0007E09E83AA9B6574038010C38F4C5275CA9 -:103FC0006F4C6B4279F25A04F98BB56D99CC07F2BC -:103FD00027557445E5E03CFBA5FFA6C990070BDF1C -:103FE000AD7C209CF4B336A16506D925F769582825 -:103FF0003FCF981CEEC728C8E1FC9F606B4DA91EFF -:1040000087E9D344375F97CF6790B31DF4D9119FE9 -:104010002DFA581CD47B9A75A1E9739BDCEFC07E06 -:1040200021CF5F187319917FB582933B39F7EEDB8F -:10403000B7CF82CE1346E75536C97A8DD24E444E5D -:104040003B1546D81D0CCF450A6607DF07CC3E9BC3 -:104050000FD6ABF92B6D487BEBC11C791F496BB2B6 -:1040600061FDB24CBB0DFD94C1F7551AD326DA7031 -:104070007D1A670CD0A931705FE84ECB7E1FCF53FD -:10408000997A742CF01C5970AAC77321B1372897FC -:10409000CF97371DE2E7429B4C45BD780EA1C9146E -:1040A0005744C7FE4CFC9CA952DF643A46F2DE64DA -:1040B000E7F15613EE0F02A2C7E7A13BED18CD833F -:1040C000526F5A0E97AB267B17C3FB5BE1763FD549 -:1040D0000B139D3E0DE01F16C7E8FE4F9891F35558 -:1040E00004AC8F3180EF957E6FCBD1D1BC352517D5 -:1040F000F596107E22DE04674DB6221BEDDB38DF1D -:10410000D06F63B442DF9CAF1F97E75B69A7513E56 -:10411000FF7A4F43CEFCB258F41339D7E460BBA604 -:10412000E546B483B491E36FD8DE8661DB6B5E282D -:10413000B7F738F28536B2C88CEDE9505E84A0C37B -:1041400067E476FE57E3ED30B374DF97605A309F33 -:104150002D94DEA3A4468CA38F1BFADD3796BFEB0C -:10416000D47E2490BF7B71FC2B93CF1E2BA11CEE21 -:104170003FDA2EDB278A9D6191DBDE2EF07BE83E65 -:1041800021DC4EEF36C87687254C3D0F83F741F989 -:104190003A5CAEE0E7E62EC7318A6B04F3F3E577CD -:1041A0003E8A0EB44F50EF736473BB0453B44B1C80 -:1041B000B29F0D61F41BA09DA2F0FD805FB742FA93 -:1041C000A75B003F03C86F0DB42B247B88BE0DC9CD -:1041D0007D69C8E7A9F23B0543F6D75C2EA7854762 -:1041E0003F4B43FE2E8BEB4FC0EF82F9FC8547AE71 -:1041F00026E0785E983170CE86E243AB17A7F37B5A -:10420000D9C7FF1CED0AD1FECDEE7F459DDDB486FA -:10421000F4C0E55C0FFC5BDF07DBBE8CEB9D1D8211 -:10422000DAEFA4CDE57AE75FE47DCC7A55A4F72DEB -:10423000CE65B92E201FB60AE6E5287F531FE1E7B9 -:10424000E6563F5EFFD90321F84118EDFA734E8020 -:104250003D5CDCAC273F5AA3297DC48DE21CC3AF73 -:10426000B387CB71797D4B1E35F2F3242EAE175BED -:104270005CF7D33995E0F323C3D53B24CB3DA5BEF2 -:1042800001DB4779629A47FE804B6823A0BF4D96B9 -:104290007BC17876E264C8F36304B9127568451887 -:1042A000B6AB93EDB1ED8A3FA3A2C8E808F85EB7BC -:1042B000B8C8581A402F8D8C9FDF0D6EFFCEDC01E1 -:1042C0007D5AA5AFE8709F45DF509CF8A7013943A0 -:1042D0008A65B8CA8E51FA0F3E3F16705E2C8CF379 -:1042E00029B7675AF1DC18E8B76B2B968FC4F96DC4 -:1042F000155D2F58611EFA3F30D039E70F65BEECCF -:1043000093F972B8F5F3B143A08C31F6043B829770 -:10431000D6804EC68F40FE68CCD494FB438CB35CF1 -:104320001E6708FDFAD6DCAFA75F97E686D0AF51CF -:104330007F7604C51F0261D49B1D21F4EB1382EC30 -:104340000F90CFED9CD0491D7D300F276E1D616F02 -:1043500094E89E91C35E04F6C38B6732516F9F232E -:104360000CBCC723DB318C60B02316225E739967C7 -:10437000DF0302C5515AEE48A3EE045C8F9BADA744 -:1043800024FB1137C23A61DCA1F5DAB219A1E20CC3 -:10439000FF38402728BA02EF07C02A04C49586C414 -:1043A000CB82E263184E1938FFAB1D5AFFAE62751F -:1043B000FC6AE335EEBF30AC60FE27043C1FAA2E3A -:1043C0009F5FAE0B8ECFA9E25A0B9DBA607C7C88B2 -:1043D0006FB28C6FCAB607290E3E2D45E4FDAC6462 -:1043E00064CF07C7BD0C85BD0E2DEAC3158CF4F74D -:1043F000603F369E1725FF5E0563CF0974DE5A7D48 -:10440000DFE4E959E7F8FB1C2DE5D88F2D53C350A5 -:104410003F0EBEAFA0C49BF0984CE07D69E5DD2265 -:10442000CB620DE1C77CB753B9E29787FAA6124B6E -:10443000C0B9EE556CA03EDDA3F2851EF7D6D65965 -:1044400014EF4F1CEF29EC82A2243BA37948AA6603 -:104450006407C03CA8E2FA86945D34CE4B358CC527 -:10446000F238A0AA3C017670A44F18BF2ACE0FE301 -:1044700054C1C176E7CDEC4D434AE60DE5F9CDFCDC -:104480008D06395EF8466E641CE93B63D818D47714 -:104490002C8B9FA6F5B804EB817E59348442C5036A -:1044A0003743FB6807BA905FE2D1DFC454EFCA30EC -:1044B0008748F7C984628EB310EBE4F1E17C46FCD7 -:1044C0006D0807950BF859986C70E0BC1B0C00C385 -:1044D00090053D332640BE56F637AF1598883033E9 -:1044E000DB8DDC4FA8BC6BE3A7776D86EB0774FF11 -:1044F000BE30ECCFC7BF53FA19F28EDB0DBE27FBDF -:10450000CD1CFC7D19F91D95FE879BFFE1DE6DFB3F -:10451000C3D4772770BF6732D16BE520BD12BC4C86 -:10452000A647FC1EE5C2BD4AB1AD770CDE373CFBA9 -:1045300070841DFDE003E3F0DDA9E5EFD1FD75ED2D -:104540000DE0619348BE0F8C4B6EEFAF1D17FD025F -:10455000E4DA06BC3484E74F2A199D27B0B84ACF65 -:1045600089740E00C6A0921301EF13407B1B0EF15D -:1045700073AF5BF19D0B71B05FD42BD06EB0554221 -:104580007E083B4849AB19BF1FACE0D5A8073D1AD0 -:10459000E952C3F5E8D9A63E11CF35E9E2FA45E480 -:1045A0001FE7682EC707E8379ED1F90B6D927CCEC6 -:1045B00071A4C4DF4DCBE4FB9BD2CF84D11A59FE4A -:1045C000F7D2FB47B3234ED54B76C6F2F6C52F4440 -:1045D000FFFCEC11A7EAD3002ED867E170D2A92B1B -:1045E0006966C6ECFBAC0BD19F3F3BEFD495748062 -:1045F0008BF6D978F9144646CEF87D090BD19F3158 -:1046000061B459D5FE5B38D7F1DF3CD51A3421CFE0 -:1046100063DF365A394FC9E83EADB3F397A7312E61 -:10462000E954F647872E48DF81220BDE23937F7102 -:1046300051140F9D29D3D99DF8EE5214FA2DBB6861 -:104640007E470DFAE99FFE6BFCF482437997CACC52 -:104650002A81FF1B1B982B2C2380EE9943739D9F6F -:1046600003A6B881828FD2FF10BC6069C59840BC98 -:10467000B6513B0A5E170A0DA48705C7872E08FDB1 -:10468000DBF19C54C4CFD62FC275BA10D99F2A0033 -:104690001C9EB79ED6ED427CFF76C11E00EBF83A19 -:1046A00056EF2BA275FCA3D6513D7A02BEDBC5DFC7 -:1046B0006F6896E3504FC6BB7C689F01DDD1B9326D -:1046C0005F8A9EFC4865E30547A03FB06E34F7CB98 -:1046D0005C92D3698616CF49A04BF70181AD85FA6C -:1046E000EE6B97F5A89FCCEE3CA3473DBAEEC01900 -:1046F0003DDE4BAD4318DAA9DBA67784D2FFFE324C -:104700005AABF2972976D7D194ECF5E877ABAB1694 -:10471000E81EDEEAD7B91F6EF5321C256377DFB2DB -:104720009FFCB855CEEEF5982E657D47F1DD88C526 -:104730002EADEADCC0929A08553CBECA13AB8297F4 -:10474000B6C0EAC03EBBB42149F51DC35DCF82EFC0 -:10475000280EFED0FEAF90D771B16D732FFABB1645 -:10476000BBD47ACCECCEB5620CE2ED11EC1ACEFEE5 -:10477000127EB7848F10D200BD0AE67D5A07D7A3F8 -:10478000EA2A8C649F54220CF35A59ABF5E39373D5 -:104790004753F454EEEE10A8DC2D97BB6B046E5714 -:1047A000CBF275A98CE3928327A7D175529FA337CB -:1047B0003300DFA515E5E7881E657D43195785C4DD -:1047C000F58D0D29EFE9B0DDA5DF17586C1A8D4B7B -:1047D000A5472DA951C3551E5D909ED5A743F9BD90 -:1047E000B4419DFFF3D1F2BE9EC7F2909FDE182D1B -:1047F000889F1807E13FA5BC7702EF815DD23A0F91 -:10480000227DD6EABB0A70DFBBA47511AC94437E4F -:104810001DDFAFB8BEA201CEC3EF1B750E33DEA7FE -:10482000F5AD14886E97B000BD276DB03EC1DAA11A -:1048300070BF2277C39CF5E40F3D2898516F281371 -:104840001D22DE836F1CC68F7E51E68313AC2F1FA3 -:10485000F1CA46228575CA9E3F82F699ECB796F951 -:10486000308E943D4E20BFC49D80714311A622C955 -:104870009139B03784419AAD6DAF20F93E566FE65D -:10488000EF62DA58A0BC70FC331370BE1075B20B27 -:10489000937BE8FDBD396D9B2FA25CCCCC70143DA1 -:1048A00005F83D19C6FB7FF275C1BF16DAA9CB3FEB -:1048B00046F2D30AE481FDD6D96439DAA1F6CF5A9B -:1048C00051AE21C1CCCAA77E1394F832D015EDC3E6 -:1048D0005DA5A49F58E57E9F2D94B8DDFCA07C2E9D -:1048E0008DF9D6E2F9FABED18CF295F41BFBABCA76 -:1048F0000431285E50371AE679A5AD4F75DEE95BC5 -:104900006CBF01E92CB87D18BE2A5E394D7B2D8A1B -:10491000EE771DCCB0DEE8FE94D6A83EB7A4338770 -:1049200007DDBB53CB9FD9F6A4A07B771941F7EEE7 -:10493000F282EEDDA9EFF92D744E09BA77A7BEE732 -:1049400067B0CD54D50F93E6A9E0889CBB55F523FD -:10495000EDCBD5E7AE8EFFBC4248C777067D7D2EF6 -:10496000988766E08DE298C17D242F0A2A431A3E7B -:104970002ECC846973A1A10BE9A43991DBE786E30E -:104980000FDBBAA01DE388978CE86FFC89E02F4508 -:10499000FBC4289F5319FD1853ED33AF1570BE5259 -:1049A000D2DBF25CB3F3617DF2F74A49FC1DE0DE35 -:1049B000D1B83E467C6C03F9E6557EAF78AC6C47C7 -:1049C00028ED3C5F5832350FBECF7FCC3183E2EC0F -:1049D0001DFC7EF04E3D8FA7F85EE5E75BF33BFAEA -:1049E000348E00FE3E99C7F590679CA5141FA9EB75 -:1049F000845D16F9A9EDAC1EEF65D4757647E17EAE -:104A000056E03CAB47BFC960BEBCCF89FDE168AF93 -:104A1000FFAC3D743C6D6D9E9EF8E3982CD7AB1EA9 -:104A2000D672BB913966E1B971455E57EDE7E3ABEC -:104A30005AA8E7E760311A1D426E839C3EAB96C3CD -:104A40000EF57E708B7F3DCA0E90DFAA7A4B174C15 -:104A500027BBB712E436F231C87375797213C917E0 -:104A600090E7AA7C77DE803CCFBF0EDF9D766A425E -:104A70008EF3708148F378DA3595E6FF199847F49C -:104A8000A73D3364DEF87CDE6CBE5EC6B50F58B75A -:104A9000E07ABF2EE0EBF6F230F2FA7D795D770A2C -:104AA000BD45284CDDCE70A2DB254663099E7B38D0 -:104AB00096F26513C6E1AA7E2ED03DFD7FEB3E6ED9 -:104AC00041FD5FBFFFA805FD61EEF6A316B04D598D -:104AD000AD4E5A8B7A3CD0851DF59EBA8E2EC27F84 -:104AE00065FBB86ECC5FD921D0FB3DEE0317A7D391 -:104AF00038595F13C60B770E83D78FF2B8FEBE37D7 -:104B00004FE27E3017F489FBFD0183DF2F201D80EB -:104B10005C42BC5E17F0E535B673A3B122941EF576 -:104B20006FF27C1FD9A867E8AFAF85EF711CC75241 -:104B30008EE98D4847FB05B2B5DDED27174660FBD2 -:104B4000F53A86FA8582DF1729BD1FE2F83FA8D61D -:104B5000A1A78035566B69BE3FA8D7523BDAFB74DC -:104B6000042F5EC1CF551CAEFEA82909DAFDA05660 -:104B7000A07B0C53EFFBF3318417AFE0FA5A303DC2 -:104B80002BF41A4C9FC1F43B844E6BBE199D1EC979 -:104B900093EFD5E4B102DCE761DDA759917E1EE118 -:104BA000F7E32BAE1DD6A17F33BDC96C7F02E03188 -:104BB0005AFF7A0BCA89C3BCBCB07687C0E58D7436 -:104BC00037F26152B39EA1BDFB7E1E974BEFE37A95 -:104BD000C5E3D0FA058CAF31B1371DE5529A1C4FB1 -:104BE0007A45C72AF6535C90CB9B31AFD954EF96E8 -:104BF00037E571BD43918340E6AEFDE4976D4FC448 -:104C00007B142FCBE74153E5F6B232FAA7CF85F4F8 -:104C1000AA4C2F67643C14F8B24CFF6CDBCF681FC2 -:104C20009F2DC759663674D179CC3C83EB5394875A -:104C3000B352DFABC57DAE39FDED7C3A678D3725CC -:104C400026E2FBC9FC7778D2A7DBD660DC2F379C45 -:104C5000D631ECE053741E382C6BBC35549C434960 -:104C6000DD57257A8FB0EE6A3AA50A3CF7D0397D38 -:104C70001FD90117A7139F5CB5A9DE2DFC54C67B75 -:104C80008CF23E5D27F7F3809C168B8B06EB29F3A5 -:104C9000809E651C6F58D62E5AAF35AB5821A9752A -:104CA000EC29FECE66ED4901DFBD58A473E84C3017 -:104CB000DFEF8D60251F8BFC1D245736C64D8C748D -:104CC0002FFB84D74C70AFD746F029AF44E9AD61D4 -:104CD000CE887C6867E1114F16CEDBE1945627DE63 -:104CE00057BCF08E4EA66B33BF2F2ED3DAE54E2D78 -:104CF00033629CEB00E8E3C220FEF75C4DA4FBDDD1 -:104D0000BFC3FEA09F950DBF217967AFB9381DEDD8 -:104D1000A2C2DA334D08BB1BFE3C1DF5890F61FFB3 -:104D200020BD1EF47B9B8072E424BDD35D79358663 -:104D3000DA7959D33F1DF9CBF7A640F76F3EECB8AF -:104D4000A8B7F2FD89DC73782F1CFDF2B3F2A3B98A -:104D50001CE92CD4D0FA3A24D53BEBDDA3FF2B0A77 -:104D6000D7C3D820FD7A0A7EDFA365C8BF9B4AFB64 -:104D7000A3CC21E4EF69F4DF65F371B0ECA1E51594 -:104D80007A5F169E93AC90E938B8BC3C7FC03FA1D7 -:104D900073CAEFEB0801FEA12AC6DF3F05BBA72BB4 -:104DA0001CF8B8AA732AF967AA3CC20DFD33C3D117 -:104DB000E1D74DEB18F7CF2830DA8D817E4DB41B4B -:104DC00099AA7F1F7F072B25F386F774DC7D891452 -:104DD000CFAF6B6614EF5A797534A5E75FDF2021FA -:104DE000FF18C3FB5BE97E6BB686EC8C953EB5FE87 -:104DF00033A580CB8529057CDE5CF9602FE5B00109 -:104E00007B09ECA27BF3B95D147588A9ECA5E07C65 -:104E1000B2978CF23D1D1013AE5742E07D474169B9 -:104E20000D7E97CA5A88CED93BFCFE72F038D7E483 -:104E3000733E55F87A31F235D26F07E7EBE076E74B -:104E40001594AC413EDA384C7CAB5CE6FB956D8C3E -:104E5000E6CBDD1643F3F4056B7396025D7E0178B5 -:104E6000E03DD20B4E6744347C7FC1E58CC0F33DFE -:104E70008A1CA86B0BA7EF3666CE8BC573A3CD48F3 -:104E8000F7D0DEF98EA9469CE77BDA38FF29FD7D55 -:104E9000D8B53816F96982AE5F6F87F2E4CE335128 -:104EA000A8F74D787D7E2CF2E17078FEFD1819CFC1 -:104EB00086C4121E9787BD70A26C4F007EEE27BA83 -:104EC000E89DFA871A18D16FF7ABFF56877C7CBE36 -:104ED00033C28CFBE6170723E8BDCA0B6F1AE83D07 -:104EE0009A5AF97DD52F747D7348BF7C5D4BF722AC -:104EF000DD6FFE472BF2A3FB55039D3B7CA873C3DC -:104F000045DCF76A3B679CC377566B5FFADBF2C3FD -:104F1000CA8654D28B14F83FBC4627BEF37B5EE4AE -:104F200072E2A18E7F217DF7A16B970BF07CCA17EF -:104F300007FFC744946BEEB72E4F4479E6FEC5E5F4 -:104F40008958EE7E2DC2134A5FB95EC0FD3ECA7E0F -:104F500099F6AEA8F20FAD90E9236D5D0BBD073D4C -:104F6000E1E4027BE0BB0F13B2344EAC3FE1B76526 -:104F7000B1F7057CB7AE57A438E3F8936511D501B6 -:104F800074794F814EF12F7E23BF0E93DFC719F046 -:104F9000E3F4F2777F36F68AFC7DA31A81EEA183D3 -:104FA000FE32E45E1AADFF8A587ADF8889CE3BC7AD -:104FB0008C47388BDE05623EE3D1CC003D6971AF92 -:104FC000A6CB007454D169E822FDBE573C43B0AC77 -:104FD0003FDD73F1D3C83421847F26E7D43494E3D2 -:104FE000C17E1AF84522DE8ABE55E971A520FEC1B0 -:104FF000FE9BA51577907F28D87F93D62B6A668F66 -:10500000C7F7DFE93A2F8CF76923F28BA287E2FA20 -:105010001D08C1FF6BC67039A6F0D5BA5E1EFF5DD4 -:10502000D75B6ACC84B456E6AB03B09DFAA0FD759D -:105030009DF377A31F61DDB545116360BED6BD3B0F -:105040008F3D81FC6F2E3566E177D7EE302ECC1F79 -:10505000A497E0FEA68CE1F272404F1866DFCB9772 -:10506000F1FA5BED7F3963E4F36CFF87EF7F6087D4 -:105070008F1DC3EDF025DC4FC2EDF0E07D4391C7FD -:105080004ABB2E799D87CA63FE7748C05E2679ECBD -:105090001A2351BDE4CEB9B16447BFBB2056320DCF -:1050A0006D3F43B46B62F287B6AFE8716E9FE3A8C1 -:1050B00011ED1C8796FB491708F4BE99A2F7B99D1C -:1050C00002E9E3EE4A9D1FEB2978F52EE07ED585B7 -:1050D0000E9D3F4C18D40F15FD71A0DC2E50B9A2C7 -:1050E0004F2A7A63AF93FB71178CE7E5B786B91641 -:1050F000E17C7DD81546F91326F17CC69C479300C8 -:105100005EF43D8111FFCBFAA442A7C1FAE6A5CE19 -:105110008C1BBED7B34DA64F85CF5283F843D9BF62 -:105120009AF339DDD7E1FE1D8BFBF77FAAF4F2E09D -:105130007661FF7E08F16F461D12BE1FFF5BD1191D -:10514000CA3EFF4AD60BFE5E59BFDE232588AF72EA -:105150004E76B87DB54ED66F862B6FCEFF7AFCBCEF -:10516000471EDFDF8A9F778EF9BF439F1DD00BF567 -:10517000A1C7794741C94FC6C0BC866B3D749E73B9 -:10518000B8F7CD1E95F555B07355747C3445AF41D5 -:10519000BBC85DC3FD03CDD1D2AFC97E39AEA5F783 -:1051A000571E92EF733E78D54C692DEAC9902ED9DF -:1051B0007B92DED95D52A3C6BF197DB7F8FDAA3434 -:1051C0008AEB57B132F22B5575469BF1BC7F737C4D -:1051D000FB31E42BDF6EADB43BB0FEC6D1727D2354 -:1051E000F7B7D544D3DF8F61417A40952758DF5711 -:1051F000EB0553643FD170FAC12FBAC3B85CE9D153 -:10520000129FD739F9DF55D07772B9E06E0823BF06 -:1052100009DA6B88D7670D821FDF3D5F29D7FB4C0A -:10522000EC25FF13C5D3A0CAB9CEA72C0EB2DFD48C -:10523000F1A395BB7E4B7233388E1473408E0B0DE9 -:10524000C48D26D2799095604FE29FBC724BD25D9F -:1052500038FF801FF393DC71A8FC30977A3E22FB65 -:1052600073C9EB3CFE33247ED43C93C78FF0DD95AD -:10527000107EC8A5238F1DC5BFA374B3B8515DC7E9 -:1052800049BA473244FF08D23BAE8D51FB19478AD9 -:10529000DC8F3BB25330A37F6AA43C8F7FB7319C35 -:1052A000F4EAE97FA88E4579A0ACD3F9B97C5ECF4A -:1052B0007F70A504BF9BF807D11C06E3FAC507F56C -:1052C000BF49E2B06494F0BBFA08B463CEFF6175E5 -:1052D00004CEEB2F20C5BF2FF1DA6931A43FD22BCA -:1052E000CB2DD80FA30BC8BF2CFBA545D80F230788 -:1052F000FD39C1DF6D97BF6B063385FC98AFF3F8BE -:105300007E73826B26C1CFA633FE1EA683FCCEFF22 -:1053100002748DFEA23C182CC69F7F1ACED661BCAB -:10532000A839DEF536F1D1B31A09F908BEA73893CA -:105330006FBF44FB234E19C6730AF4FC5D46EA0CAA -:10534000D66BB4BC8E0960C7623C09B05980F1E6E7 -:105350003C39AE5310CE446CFF499D6B13BE97F998 -:1053600064B7685F4B4C608FC577BF83E34B828324 -:10537000C7C5953893121F1F2ECE24603F059CEEA3 -:10538000F8B91587807173259EC4BEE7A4205763C2 -:10539000B187CEF73F53C848AE7F8B719E25F92168 -:1053A000E24835C86324CFD571C54D39AF109DFE95 -:1053B000B5F1C43D63D8B71CFFE2F3138CF7F8E8EE -:1053C0004B16B2B7BEFAEF51B4CF765EA6FDF042EF -:1053D000BF41BE8FD0C7FDEC9D3AF22F5C00BB2DC4 -:1053E0003E609F3D9ACFDB3DD43995E8FF406F5931 -:1053F00004D63F2FE76F7C77C1FCD94897BD22BD0B -:10540000078BE7E3D00E3BD02B4E40BDE55B5C97AE -:10541000EF8F09B12EC6F0D0EF4CE4CB7C945FC087 -:10542000E963EA07DCFE72D7F3388A59960BEE720D -:105430003DC9C163291641F19F5B43C5595EEFA782 -:105440007DA36A8540F71CBE719CA5A35BDEB78275 -:10545000FCD3E5D3496E0EE7B70E889BABCAB715F0 -:105460000C9C8723FF75548199C61DE3292CC1B379 -:1054700087CAF8BFC575B8736C083AFB16DB5F695D -:10548000FF6EDB9F92F7DDB6BFE63B6E7F6DDE778A -:105490001BE7DEF11DE37FF53B6EFFCC773C3FAFB2 -:1054A000E5FFFF73000370709C3FF85C4070BCDF49 -:1054B00070FC3E1F966D1036F777416A8C7AB542C4 -:1054C00000512D46EFA27708664DE271B08D65461A -:1054D000FF0E61F07C80325F4B0BB91D61CEBFE8DF -:1054E0008B85794E75F496C5A29F6C127F87FD82DD -:1054F000FCCE2A13CDF4CE18D44CC0FBF1CD61A163 -:10550000E3AA61727BC3ED23CF1796DC31369EFE92 -:105510006C43C8FB1D2FC8FE47730723BF2413A588 -:105520008479D4AF9480FAD088233C3FAA8B397613 -:10553000105E52DA3CB207A534C46F8B1CEF8D9914 -:10554000999D86FEE818D00B311EF814C605298EE9 -:1055500065A67A4A7F1F8CE5FD6DD13181EE5BE552 -:10556000F2F34CACF9A02A9EF78EAEEBE36502C5D0 -:10557000F39623FEBFD274E5EF4C938918E637FF0C -:105580008099E28C2726BD487F775689EFAD31F3AD -:105590002A87D16E063CD61C1C47F4BBE4D0A4F786 -:1055A000F1E93377A6680F754F51F1179C96FD1DF1 -:1055B0008ABF40896BFD5EF6937C88FE17BA1F2276 -:1055C00051EA1DABF9B6F727EFD810FCBF45E0FE56 -:1055D00021DFAFB87F689CDE9E11786E72B33CAF5E -:1055E000CBBA78DC42F1F7EC93C733EE116D97013B -:1055F000F6D2714D63F4B8CF8F6B4A09C7B4C0E1DE -:10560000D7E07DF0C5D5FB35CAFA85A2A3D6B1B2E5 -:105610001FA3A79FE27AFF1214E7FF602C3FBF3061 -:10562000AF90E3F101D82408AFC9121B517D1C7162 -:105630008B591B2A9E54057631E2B9AC99E3ADCC67 -:105640007755973415FB3973B4BF09D3A29AB4A91F -:10565000E46FAFBDD884FA9BFBDAE563B793BF4C28 -:105660002FA13D714F9FDAEFB60AA3A5F18427FD64 -:105670009D5ADF0C91ECE3713344A29F98AA30B29B -:105680005F63744C6B42782ED78B8ACAE3A622CC18 -:105690001644933E58D42345DF973FE8078B995132 -:1056A0001F8FF374B3F8AAE24FBB35CCF11AAEE703 -:1056B0005F1B5F5DF9CEBB74AE541997322F4A9CC5 -:1056C00074B8F8AA72CEC15D7E45752EC32DF64F13 -:1056D00047FFE3B88367F4F2394B33FE1D6125FEC3 -:1056E0003AEEF58B147755E2AC6ECF45D2ABE13B89 -:1056F0003D7E3F0E963F2106DF17E2F1D757F19E20 -:10570000941EEFFF99E9BED41BF2FDC54E183FE68B -:10571000BFE9CDA1B4CB6BA7F490B7985277E7451A -:105720008AD77E38561DEF53E27997B4CE3363D5CE -:10573000E723090E8EF769C3B9BFC6DDA3A3BF97E0 -:10574000E17EC748F2BBA47319DDEBFAF2A46B2427 -:10575000E25D87F1B600BA38EFB087E13B61E79DC3 -:10576000F6308CB38DEB3EA7C7F32F7562AF1EFDED -:10577000618071121E4D741FB8C8CFF77696D0DFC6 -:10578000E3BA695CACE36F1317FB9FE541012100AD -:10579000800000001F8B08000000000000FFB5170C -:1057A0005D4C5367F47CB7B7E596DF0B2A3F227256 -:1057B000C16298A2DCC240A7311674AC135C8A4A5D -:1057C0000201B5662E92092DD9CCC2CBD23A8901FD -:1057D000DDC3B2B864F3A92683E8B687FA93AD6E49 -:1057E000550B0B84252EE2C39C71C9520D3333BA7D -:1057F0008162DCD85CD839DFBDB5BDD8BD2CDAA458 -:10580000393D3FDF39DFF9FF0A003007DAE756B9E3 -:1058100006E74CF8A5CFC6FF0F3DA44F8CE3DDBDD6 -:105820004BEB2617C4F1BB3EC9356903F85D9CCE2E -:10583000942B00F687CE5A1C041FCFAC7621FCEDCA -:10584000C2DFB54A3A80F7D24C2D20EEFD66A6960F -:10585000F8DEAFD27A02E94FDB7BD78E975E047019 -:1058600096416B10F9552EC17182E0B8C3FA4645D6 -:105870005C6EC02538E9FC80AD349BE8C75CA5D9D7 -:105880007B13F4F539456700E939AFDAAC89F409DF -:10589000BB19A006E90C5CC124F66B5581DBDF7FE8 -:1058A000D22A4F4A7A1CF1DB1DCC36E0DE50813C17 -:1058B000591EC7F7D38F02FC6E6622D40274E9B971 -:1058C000B86472D7AAA8AF3B3F6A8152A24C5B5C16 -:1058D000AB305EDF4BFDAC1260F8FCBEE268051732 -:1058E000952017A04D3F37E0DC5B9CB110C07F3D99 -:1058F00005CA98461391DF4A3F148E2A22DA69A717 -:105900005F78E5B6FCF7274CAB11BACDFE68C2BD97 -:10591000DA9D82C39AC9ED2E6DCE207931CE2F212A -:10592000A5D34BB7AD22CC5128E413F417C25A02C9 -:10593000D2A8AD366EEF06047EB0A17C9B5388A43E -:10594000A09DD6704A04506F955304DF8B087BCD21 -:105950008112467CF126E72B6F3611BF4FAE2A0429 -:10596000F4E3E7CB16794109BFDF6434218EAAF353 -:10597000D3FE523CAF763195DC6AEF34F2F19341BD -:105980007EEED6E3B23334FC7221F75F36019ECB54 -:105990001D03388E7677F618CFED6E75DE61743F95 -:1059A000F8A07F33CA814D900789DE6B94A33A3B00 -:1059B0008DF11F007026D64337D5410D41C6E1E772 -:1059C000E813D54515062A58113F37BF7E4674F9AE -:1059D000F9FA62F00CF117517D560DD828BF4D022F -:1059E0009401E1F5922D419F5F15B99E0F6501FC71 -:1059F00028D717DE3EC8307E7D8F5F915A506E4AA1 -:105A0000AE97CAD2E3B8F732D6531640F5F06C031E -:105A1000C5FB589881154D79F3F1BE28577DB16EBD -:105A20009CAD4EBCA7E6DF31CCF9443AD5819A0D46 -:105A30009A5F2061BCFC17586010ED55353D1C493C -:105A4000A3F8B9B2D53285ECD80EA523EE6D126B52 -:105A500018E12E3C40F80E1690F0E7F62B9D5B0007 -:105A6000ED54B7D8AF52DC5B3ACCAA1588DEDA40E9 -:105A7000F46B5950372912FFC47BA9C42F67AA556C -:105A800021BEB39EF88D5F4444AAE7AD14A56578A6 -:105A9000B7CB288D7DB3C1EA0E501F5537A311F443 -:105AA0006F47873540FEB5849BCD90CEEB41A0BEBD -:105AB0007B5BCFEDB7458F32A3489F095767915F56 -:105AC0000BCCD316156135EA2EC84178E1BE05B07E -:105AD0001FBCE2B44546B9733E4CAC05E04B9FC4D5 -:105AE00061C827836339C0D7BE7C0EC33E85D32FE0 -:105AF000FACA398CF8540E477C6B35A8CA3C9E957F -:105B0000E1FB02DD27A75970259B6F7EBD3E62F940 -:105B1000AA0BEF29A67B3EBAEA2E9693C8C7205A55 -:105B20002C14D66AFDC930675EE7C306B2E381E88C -:105B3000613AA760BE610D46218430EFBFEB6FAACA -:105B4000529B6FD902B893F167F4FA048722D03CD4 -:105B50007A4BD2FA7F78C55F3C9E5248B9B21EF3A9 -:105B6000E61937410AD28FD46B737FBE9EEB184F74 -:105B7000C0B8DDC078129CCF6FB5F8CB281FAD74CC -:105B80008F24E7A7F4FAC40A30BB32B49C32BC4F6E -:105B9000476C0E6020B2308F1D211649C53EDF19BB -:105BA000DE744724D8C3E096717E3CD77DD8E646A4 -:105BB000A589F3B6338D26F9135C4AD5E22C593406 -:105BC000D86FD5F65A935D8B730C6EB56B75719467 -:105BD0009A05EBFBE879163888FDE7A918BB4E73E8 -:105BE0002CCF01D08BC3C7939F1E31D13C0F99EFAF -:105BF0003D99E3D81F798A0C1D3994370C26F6415C -:105C0000817E0724C06D9463911C616E25CA2D1995 -:105C10009F257D9FD8156E2F77579001BA5004FEAF -:105C200083345F462D50771AED779D637090FA3B71 -:105C3000E00205F7FDE8F11B874F21DD738EC9B443 -:105C40008EBA8357F99EEF162778FF78C2772DBC5E -:105C50001E8337357A88390249F23A40FB1DED6ED2 -:105C6000467F686E741F300552D06EC339ADAFBD2C -:105C70000E4B40417CACE81D91F09DE719E4D11C2E -:105C8000532616A511FF80190225DCAFA6BA84FDA4 -:105C9000845F85FC8EEDCFD8FEF1C0F45821D56B22 -:105CA0002753230ADF3FB78CFB052F921BDF2FED15 -:105CB000A16133CD1BDC4306B9DD8E863B343F71D9 -:105CC000CF18E94B0EDFE7F98028AF53DC2F067EB3 -:105CD0008D3D63E16D2C095809157338CF3655CACF -:105CE0003CDFAD6EC6DC181F497075919F7091C97D -:105CF000346FE7C7ABD1AEF541A39F412FE677C81C -:105D0000A2D5C7D03A16F0A37C23A294F7A18B7B2F -:105D1000FC0CFD1CAA62AA40F120218CC7163D3E56 -:105D20002F801F6E4BFCA9706CAE1AE035AC612B56 -:105D3000D653A35E0F00016EA7F9E3D408BD238EEE -:105D40009A83F92A7F97F8F97D6755E0FCD414E827 -:105D500049D6AF6BEC75B36A0DC93DF3F7D32E7B13 -:105D600092F7D347F876223B7BED4C24BF30BE2B15 -:105D7000A9BFEF155DCB1C41F481C9B58FCE755914 -:105D800022ABA9BE1F98DC1C8FF191EEA1FD828B86 -:105D9000EF16F591008CCF8723E567CC949776A218 -:105DA000C7EE5B1297E3B8E969FCA10ACFDAEFA16D -:105DB000CA9AA7FD7E86FA17ABCF577F6EB2BC1D7D -:105DC000A2F997A47E7ED2E71FC01299F7CB933831 -:105DD00083B68764E0753CAAEFF57EA6FC487BC8D5 -:105DE000FF9D190695F85CEDCFD0F47FA6EB8BC133 -:105DF000511DF69B35B9F9F627F439FC8BC9718A28 -:105E0000EEBDF2A4004A82DFAB82A9A024F85D199E -:105E1000CA31E0F6C862837CF578A9815F33B1C2EC -:105E2000C05F73BDCA80BF145D67905FFF6BBD012B -:105E3000DF30BDC520BFF1CF6D063CD6BF7558B968 -:105E400089E73649AF1BE40A3B8D7E15F518FD2A1C -:105E5000EE35FA15D35BE237FAB7ACDFE85F4EF602 -:105E6000835C85DEA1FFFC9149FB60203CC3F334D9 -:105E7000359D02133447C4A8B61FC266BE17A6F0EC -:105E8000FFE2A2843C2CA7D73FDA19092FB3D2B97D -:105E90000F9D362BBDDB2E510D603EFE05D7762EB5 -:105EA00017E00E00000000000000000000000000ED -:105EB0001F8B08000000000000FFE3E36660F8515C -:105EC0000FC1D3B81818367221F84301B7334368AD -:105ED0003E16060601207EC7C8C0F09E91043338E6 -:105EE00010EC7E20BB0A88277150CF7D43112FE52F -:105EF000A19F5D5FA0763D1518787F83B083100366 -:105F0000839B300383B40884BF5F0455DE5108C10E -:105F10007E2E41995D9F81FA018DEBBB318003009C -:105F200000000000000000001F8B080000000000BF -:105F300000FFE57D0B7C54D5B5F73E731E33939976 -:105F40004C260F4242004F08202A842140088838FE -:105F50000990068D9A080888CA000142483211A9A2 -:105F6000975E6D672214D16A1B2D6DA397DA0141EC -:105F7000A3450D18E840031D4C41BC5A8D0A4A5BED -:105F8000B541313C0A4978E8C5D65BEF5E6BEF332B -:105F900099736642A2B6DFFDBEDF177FFE36FBECCB -:105FA00073F65E7BADFF5A7BEDB51F2359C613D345 -:105FB00015847C057FD71372482484F4EB4E3B0B89 -:105FC000683A8E107F8E39B0552024B4EFEFED245F -:105FD0008590B34DB355732621FBC79843D7D3F2B1 -:105FE000B381FC8099964FDD79C421D17CD54E5187 -:105FF0008272D33E2B7EDFB1510840DE6B6EFDF125 -:10600000B534DFB553249B69D5246437915442DA03 -:106010002D84FDA9F1985F6A65D9AA4DFBEF82F640 -:10602000CA836662A5DFB737896EC8AFDC2A040869 -:106030006DAF6AF783CA005ADFB280D06855697EB7 -:10604000EB638A1A4FC803FBFEEC68B31372DA677E -:1060500021AA82FD286F1C494845607BE100FA7D3A -:10606000C536C165A2F5576C3CD701F45534C9C398 -:10607000445ADF8A061B5147B0B6BF22D05ECB0719 -:10608000D8DE4E7928B457FEE53D0A11A19FB21B18 -:10609000BEABA27440BFB5764FFBEAB13D8D9F55B4 -:1060A000CFD1F6E87BD52F0A2EE862B58978808EAD -:1060B0008EDDD6B94FDBA17FB5CAF0F8C87E2CDCE7 -:1060C00005FDA8086C520AED40DF2665E9C8EEFA26 -:1060D0005634FC879EBEFAACFE9E8872637ADA471D -:1060E000593ABC3B5F4188BB91D64BA480523AAA37 -:1060F000FBF907422221E3A17E91A896EEFAA9E4DA -:106100001107FE23F49F940FFEBDF181AD99DD725E -:106110005BE9049975CBEDBC93CB51EACA8DAC5FBA -:106120004B7F0CF2A0F4D4F99C983EEE4BC37483E1 -:106130004F45BEFDDC3702D37A9F0B9F3FE9CBC3AF -:1061400074A3CF8DE953BE224C03BE127C6FB36F94 -:106150002EA65B7C1E7CFE8CAF1CD3065F0D3E7FA3 -:10616000DEB71AD36D3E3F3E7FD1B71ED3465F1DCB -:10617000A63B405E346DF205F0BD5DBE064C83BEAD -:10618000467CBEC717C4F411CE47C764922F513E58 -:1061900038DCC449C54E928ADDF932CD2795B07CF2 -:1061A000EA1DFE7C85E6533D344FF932A032946FF0 -:1061B000A6F90135AC7CF0FDA4C042F383FDAC7CB4 -:1061C000C823EE022BCD0FA963E5C337FA0BE268B3 -:1061D0007E7880955FBD2D5460A3F9AB1B5979760D -:1061E00033996AA7F9EC10CBE7BCE19E1A4FF3395B -:1061F000AD2C9FFB817FAA83E673DBD8F793CE0497 -:1062000044D51E2D871DB2BA9850596DF4CF704BEE -:1062100013695E51EF212ECA1FFFAD6E299DF24317 -:10622000766379C83F1FCB9B143796BFE32FC3FC1F -:106230002ED983E5C7FD552CAF78B0FC73FFBD9810 -:106240000FCA7E2CB7D4FA585EF163F980DAF5589C -:10625000FF1E3980E5236B1FC3F23D4A00CB1F5F51 -:10626000FBA47B1ACDAF113C3F073CD2B49C640128 -:106270009E1AD34A289ED609642EE0F707003A8A70 -:10628000CB75E90AEAE18E3FE43E0DFA8B7F299057 -:106290005FFACCC399F8FDAFB01E99D623F65E4FD6 -:1062A000CE9B79BA7A72DE2CD7EA6980F7D658FB92 -:1062B00056CF8E3727E9E979B342AB673BD213DF7C -:1062C000B77EE5BC35594FCF5B955A3D7B909EC458 -:1062D000BED1D37444CF9FA62361FEB4203DFDFA06 -:1062E00046CFB8F7F4FC19F75E983F6F603DE97D43 -:1062F000ABA7E93D3D7F9ADE0BF3E708F66B50DF75 -:10630000FA35EE7D3D7FC6BD1FE6CF47484F66DFBD -:10631000EAD9F5A19E3FBB3E0CF3E704D633AC6F40 -:10632000FDCAFD48CF9FDC8FC2FCE9C27AAEEA5BB2 -:106330003DBB3ED2F367D74761FE7C81F58CEA5BBB -:10634000BF72FFA2E74FEE5FC2FC310950CF98BE8B -:10635000D113FC54CF9FE0A761FED8B09EF17DA37E -:1063600027AF5DCF9FBCF6307F520490FBC4BED5F3 -:10637000136CD7F327D81EE6CF20ACE7BABEF52BB7 -:10638000EF849E3F7927C2FC198EFDCAA77A0FF4CD -:10639000105A4F7CCFF5EC39ABE7CF9EB361FE8C42 -:1063A000C67AA6D37AB27AAF6752879E3F933AC233 -:1063B000FCC9C37A66F4AD9E3D1D7AFEECE908F394 -:1063C000271FF97353DFFA35A953CF9F499D8C3F9F -:1063D000630FD74C75D0723A16BA44FAC9B567DC68 -:1063E0006E81E64527CB8B4E1701BF44D4FC0DD2FE -:1063F000EA16E9F7F66D89390F9348BFA3A014FA9E -:10640000154FBDB148BF23212F4EE7E724BA93743F -:10641000F9E4A201BAF7FB950CD195F79F7BB5AED5 -:106420003CDD93A3CB67944FD2BD3FA8A64097BF56 -:1064300062F50DBAF733FDB7EAF259EB6FD7BD3FFE -:10644000AC6E91AEFCCAFA0A5DF9558195BAFC357D -:106450000DFFAE7B7F54E303BAF2D1C18775E563CC -:10646000428FEBF2630F3DA97B7F7CEB665DF98485 -:10647000A3CFEBCA27B6EDD0E5AF3DB9C7E0E7D96A -:106480009DEDD7F0BC08B827CCEF4F57D0DF0BC538 -:106490002B985706D8D18FDF1FBF543D4EE5ABBCBC -:1064A000B2584DA1F20599123AAEE70F28BFB28D4E -:1064B0003EBF7792E74A277D7EAFE219ED8CE19FE0 -:1064C000523C08240D52D504A9B1FC4199E1B120F8 -:1064D000E3CBE1C7E8F75E53D7F0449AEF2FE6D756 -:1064E000035E9E124C88D33891D4C07B716682F3D0 -:1064F000820733739FF647E075FD20AA874277BD78 -:10650000EB654F1AF8199B6BDFF6831FB26E10ED27 -:10651000D700429E16DE0EF987D2EF072D4DF3D03D -:10652000FACC0AF5D323DB5768FB23B1FD0668FFDD -:10653000C51EDA370FC9D3B56F195CAE6BDFA2D0B9 -:10654000F69DD41FA8FD236F9F0A6112212F0B7F98 -:10655000C4F6CD83CBB1FD07153A5F896C3F2EDCC5 -:106560007E10F4771FB43F3E46FF874CD2F77F7012 -:1065700085BEFF0AEBFF2BB5C778FB71D8FF16E18C -:1065800018EBFFE00AD67F33AB37DCBE23CCFF43EA -:10659000D0FF377BEA7FD6647DFFAFA8D4F7DFCC8E -:1065A000DA7FA7F6146FDF8EEDBF2B9C62FDBFA2D2 -:1065B00012DB57CC1E17E047C988AB09D0F6C9409B -:1065C0006A98FA035C683B908E48A2A026E4516169 -:1065D00008D2716F1CC3DBE771146F686FFCF89C05 -:1065E00004A865CBA5F32E8EF515DBF215B04B583C -:1065F0004EE72B4B38A9654111F14D369803C3285E -:10660000BD1D41D10FF9B20DD705C0FE79CD644152 -:10661000097C2791103CFFF467A33647F6CB982EF0 -:10662000A993DBDB22F42D3C8F2A20236A287DD31B -:106630000104E3BBF31FD37910A1F38B0FE83C8374 -:1066400050487E22B3F63EA2F325C8B7D1F9129482 -:1066500013528BDFD1EA0EA751FA4B38FD1F4B4C7A -:106660005F3FBE4308F8A97E7EFEBD31384F5DB066 -:10667000DA4699DE4DC7427FB22E4FFBE5073975EA -:10668000ED3607360BC85F15F8558AAA49C8E2F5FA -:106690001994D7DDEFBF4FC59E4E597F1B71CBFDBF -:1066A000E9FB77AE12063969BBB3DDE61C364EB89E -:1066B000334CA8D724C39447C8AD4D63645A03290B -:1066C00075CB1FB745B43BB3489F9F5DA2CF77C83A -:1066D0006ED944E9EA2815C8265AEF9CB9FA72AD7A -:1066E0001DBB2989C999B75792CAE89B03690E3C1B -:1066F00076A29CE73AD9B71A3DDEC5329DC2823CEC -:10670000FDFD08C8D59F82EFDDEE64FD36D23B5714 -:10671000B6B84B683FE72E1403806F23FD7FDA671E -:10672000739BB269BAFEA7323145F7C748FF3C8F69 -:10673000B13F8D328CC3F3CB8DCF196EDAB9FC3FEC -:10674000067CD0F404E083D27F9CE3A3DBAE327CF2 -:1067500078CD9E9B010F5D4F8804E5CAF1721BC77F -:10676000CB923A3D2E08F1C820C76573859C8723DC -:10677000703087E36059BD1E377712BF9C1E432ED1 -:10678000F3366CFA619A1ADDBF0F396EE63FB21F1D -:10679000F913DD4F26A7BBB89CEEACD197DFC6E559 -:1067A0007A2797EBDCFAC70E50F3416E570332E8B5 -:1067B000BBF73E4D9E6D3A797AB83C8D74DEC5E5E7 -:1067C00079D7F7983C8DF4B67179B6D55F90C990BA -:1067D000687A8DF42D581DD51F05E4B9D01F5B9E36 -:1067E000DE607EF2F188E7558D33928F47E8D98AD3 -:1067F00086525D7E79609EEEFD65F50B75E54BEA90 -:1068000096EBCA17AFBF5B975FE8FF9EEEFD05AB47 -:106810006B75E577D63CA42B9F5FFE982E3FCFF398 -:1068200084EEFD397337E9CA67973CA72B9F59B4AB -:106830005D972F75EFD6BD6FDA77D52D80CF378E68 -:106840008804FC89CF5C27302EF8994B76C13BC772 -:106850007D2AE2BADD3702D3933E17E2FEB42F0F52 -:10686000D38E608B1DC6093A2E2E2589D4CC9B6E03 -:10687000AE5D3F10C66982E3E916D3AC5AFF6442AD -:106880007E6D5291DFC5F50A098D254480C186D3FE -:10689000D1254694B7F5525E4F0D7F727479715BC6 -:1068A000ECE7DEC7175EE18C1177E9D65392017EE3 -:1068B0004F27F7BB8DE5950229897C4EC803A8D7E1 -:1068C000E7F8B85BA930FDAFDC915E401C900F0D7E -:1068D000AFB95C7B8D14E4FD0127593A3D5E567FCC -:1068E0008DCEBE1388CAF603BC8DD53D5FD170AD89 -:1068F000EEBB33FB45A4BB1A6CC54418164B5E3780 -:10690000811D0EB50C9E390AE874BF6182712AD8C8 -:106910000FFDC233BEA2E4E312C8AF04D393BEB9E5 -:1069200098B6FB3C981EF79563FAB1AF06D336DFF5 -:106930006A4C3FF2F931FDC0B71ED33FF9EA303D52 -:10694000EAABC7F43D5F00D3C3BE064CDFF135624E -:10695000DAEA0B62DAE17363AAE95D6FB83BC9C793 -:10696000E1D380BF1838EB786055EDFAC9DD383BCC -:106970006FBAAFD63FB09BCFC5F5668E87541D1E4C -:10698000BE806033E2AC97F27A99E3B0A7EF6397E9 -:106990007B37FF6BF036DEC4FCCC6F8AB76E3C658C -:1069A00018F094D51B9EFA89E3BBF134DEE4647ED3 -:1069B0000FC7D38FA01F31E61505E084F48BF0D705 -:1069C000DC3616A7E6EB09D45365716ADEF61AFACF -:1069D0006E2BFA758111306E9C1FF1B7E110873F65 -:1069E0007FD44C277D3DF7CF88939EF9EEC6F9CD35 -:1069F000D2001DBCC646975BE3185FAD265244E843 -:106A0000B8F6D0B0675C8B46625E2249F07DC05517 -:106A10001A1FA35EEA2B037F7BE3EB9AF8CFB3A1A7 -:106A2000BEF627FF9E0BE97813F397E35A44F4DB95 -:106A300049E86917F0373C2E995D6910DFEE1AA618 -:106A400038D16F08D8F5FCF3D37C6E37FF1EA23C1B -:106A50006AC571B72E0DF937F4F3E1E97DE05F6F98 -:106A6000F6BD377E2E0A0CF897F0B337FBD89B5D46 -:106A7000246EF5C520ED7FE7BE51390FAB60078767 -:106A8000B0795A0FFCD6D6A58CF47CFF6BE2B833F4 -:106A900055C371EB6042DBF988EBCBF9A62B1340B1 -:106AA0002EB41E9C1F74EDE47E7E2F723D9BA9AF19 -:106AB000CF6BAC2F4121C268DA6EBCA29004426A4F -:106AC00044CFA322CE6F5C6D7E881BECB3B9D6A8F1 -:106AD000306F3CFD6648851AF5F185F3879E76C0D8 -:106AE0003C6C659AC9793C861CB5B4AA31D3698FD0 -:106AF0009CAF04F5F9F375425123CEE7D48459A332 -:106B0000609C713A8F0F05BB9F86A956CFCA34C5CA -:106B1000799CDADDD30D59096CFE1760F6645B22AF -:106B2000DA9BD33E0BBEFFCFA6A7A77A347A0869BB -:106B3000229F58C09ED3B2AC9EDFEF511FA48B0A98 -:106B4000C43749B3FC39CC37ADF4FFAF8640BD1232 -:106B5000E6B57ABD8DA2DF3C1A9E6FD3B547BF5311 -:106B6000B5B557F8AE67BD9348BB867B2ABF57F9CA -:106B7000FAF08A06AB53EFC726EAF2DE60BA53E7B3 -:106B8000D7C23FC071AF1124C05F25875FA7645F84 -:106B90000F78DA0CC14398BF08ECBD2A4B9BE25139 -:106BA000515D5A019F8BF234FCAB73FE4CEDD4A9BE -:106BB000D765027A46BEA454E5F2A920E2CD444C42 -:106BC00034BF98BFBDA86945318C5BA74C6CFE50A3 -:106BD000464A1C303F2E2775B9104F3D4B4C45A0FF -:106BE0009F67C93B8EB111FA784E54B0D2C5EBF510 -:106BF0007E3C9DDFEBF2CBEAF5F9A5E4D6545807CD -:106C00005FBA41260101EC86BEFC98E8C47A9791F0 -:106C10009A75306EFF9CC7BB1639899441E9ABFA6F -:106C2000CD2F7317523A2E896CFCD5D67197273128 -:106C3000FA2B660514377DFF93A6B1B7510B44BFFD -:106C40000FAC83756D7F29716D25D1F2FBBAF41BF2 -:106C5000E9D5FC81A8F5644E474A83E00EC4B063D1 -:106C60008A24303DE3F6EE6AC9A98B83E4423E22D2 -:106C70000EF28DF194427478DA2C7A064BE3197E89 -:106C8000000F82D4A578BE4DFD6951F55F2DF5FB4F -:106C900027D63F90D69FABAB3FF79F4AFFD028FA4D -:106CA0000B62D55FF59B1776F9A93DA978E9670EC8 -:106CB00042C7C953525DAA8BCAB572EB0F1D6E9ABB -:106CC0009E94FC0EC0EBA98058144BDEABC3F27649 -:106CD000DB0588BBC13F69FDA79FFF11C6233EDFCF -:106CE0002A3B319ED6600E99A93E56372D2F26D9C4 -:106CF000983FC6F20F9E13211FD4E3AFE2D99FA5A0 -:106D0000C2FE0A8A141E5F0AA13F5BBDE5D3421C86 -:106D10009F4817EA91F13B68FF5212DABF854A4259 -:106D20007439A513E3045ECE176FD38FCE890EF8A6 -:106D3000571BCEDF8DEF9773FF74B9149FD26EA3EC -:106D4000FF9E4026803DD4F84102CC3F5DF3DC2F0E -:106D5000B28F517ACE6C79DD2144F049D3A3F38D03 -:106D60008B7FB547EDD9DE76503D8BF483B4F14A85 -:106D70000D72BFBA99A59572C8712DD5FBCA4DB2D7 -:106D8000CB4F1F57BEF0F4334F421CF38F66D73002 -:106D90005AFF8A170EBC3789E6576C97538A5937C2 -:106DA000EC426AB75CBCF4FFD539DD72A878F98093 -:106DB000A28E62CFEF4FEA96C78AEDFB15322A9A70 -:106DC0001F531BF72B6DF61872693C56087EC29A4A -:106DD000E7FE4B81F8E2A97D02E99F19839F9B0E94 -:106DE000A01F007C4239723985E56678DF4BE502E9 -:106DF000F65A9393B1FC466E4FA03E7524E2F9C556 -:106E00003DB4FDF23F995DD0FFF217EF71403F4E68 -:106E100048350CD7BFFC612AD8AF72D99FEAC49419 -:106E20003D2F7FEABB88B7656F7F3715E349C49D67 -:106E30006EC2B1C79F0EFD5BB27136F66F29F120AD -:106E4000EECA7F29960468FA99448AB6C7D08B0E99 -:106E5000AE17273653478CF6EF04CC1FC15EBF2315 -:106E6000E2BE2A42EE26A0FFDFE57DA11E02E63F3C -:106E7000B330391D904C5CAFA8B71989D72D0FB628 -:106E8000827C4E0F72F78775162F91FC9C1FC2579C -:106E9000B45EF1EDE9FD997C882AE5F2EFE8383F30 -:106EA000159EC3FBADB2DB9AADFB8E7C95D9DDFEA2 -:106EB0002ADE3EA53B0EC6E713A9B1FDD501B2A659 -:106EC000F7749C8EC057847E337DDFF210D36F4DF4 -:106ED000DF03A545507EF130D31FF80EC63F4A5759 -:106EE000A83F96EF9F25A03DA0F3E6587ABD45E662 -:106EF0007AAD2FD77042E996848408BC40FD49C81A -:106F00007F5C5F59BA817E17612FBDD09E23BA3E48 -:106F10004D6F9771FD3F05FA7F4DB7FE938D4CEF96 -:106F20007BF69FFC2C6E23079E7912F495EAA75FEF -:106F3000057D954BA0DF7FDDD6F2DEED544FFFDA05 -:106F4000A8E9A9DE7E1AF5B47CC778124B4FFF6A18 -:106F50007791987A4A9FC7D4537B1BE2F8FF94FD40 -:106F6000D4F89728EBF9A7D9C39EF868B4872F4ABD -:106F70002AF2D3680FE9DF61921B8D3F0D771ADE8D -:106F80002A7E5D7505D89D302E35DC8571A9E12EF0 -:106F90002A7EABE39FB1FCCF106BA274CDB7D44F68 -:106FA000817984A58BE0BC2B7F9688EBA6968B0419 -:106FB000F5BE80C8B86FF07D53CD78F043A7FCFDD7 -:106FC000B6B3F7527AE713BFCCD6E5EB64F4EBBF68 -:106FD000FCEAABC9B43FB773FECEA7ECBE89CA6367 -:106FE000AE2484E2289DF324E24F4882F8AC403E70 -:106FF0008EA0637EB93E0F7F5352BBEBE9EDFDAF30 -:107000003B0FF9A6E9DB3EB676F52EA443B179290C -:10701000124FA52057CA3FEF38213004ED529B5440 -:107020001231AF7A9CDB9DB7A7CD1C0FFE4BFE9CA7 -:1070300051090CE783717EEBE5F6EBBC5F4D00BBBD -:107040007EBE390BE7AFE70F2D8E8FB56FB285E3AC -:10705000EC005F57E9B40B7522C57D27E942FFC5F7 -:107060006FB792AD31D6FDBE2F9BF8E483CB8DFE7A -:1070700089546E73390EE7D14F137222E436EBA6B2 -:107080005392235A0EF0F771C43CEBDBF217700DEC -:10709000FC6DB1B61596C488D7FD84F36FCA2B5F1B -:1070A000E0FED569CDF912F0719A5DD4C5391ED4D0 -:1070B000F475241909744D7965F9A3E3298EBD8708 -:1070C0004417EC57F5369F533C31E6BB467E42FDF4 -:1070D000E0471E909DC8AF2372C912E0EB91D956CC -:1070E00002EB96EF2AAEAA58744E37B378C83C52DA -:1070F000F2D938E1FF3EFEE6CF890F15507E9CB7EE -:10710000B3FDC0D1F8637A7FDE29046A05C0A1C847 -:10711000F2294200E26485C4F3E86401F5FDFA480F -:10712000FB951F2C7D01F6D554370B4E132DAF96D2 -:10713000DA14C0B137B85D02FFFC4695B831DE20E5 -:10714000D58C9A1511D73A204BC8AF96BFDD7E2754 -:10715000F0F7C22C3301BADC23CF3960DCBFD03C5E -:1071600016F5A0A77EFDC147A64C93A01E82F8305D -:10717000E2A130C5A6CBCF9E4A06BAA8DCA698DB12 -:10718000EE71C590DF3285E1ACCFF6CDF2FF997D8F -:107190009B4CED1BC3B51C69DF462B51F6AD7F2C14 -:1071A000FBB6B256ED0FB858B937AB3FC875E56BB3 -:1071B0004BFAC5B26FAFFAD8FCFD35BE0FBB7320DA -:1071C000B56FA323ECDB406ADF62C46DD315CDFF3E -:1071D000ECC5BE59FE77F4EF55B06F31FA3B52D192 -:1071E000DBB7A2E65AB46F450345DD7EA82C85CFF8 -:1071F000E77AB46F0B7F361BF3B2CB16033FC05751 -:10720000B06FAF713B07ED809D5BA438B1FDBEDA76 -:10721000B9D2BEDAB9FF253E6B766EE520769E23A5 -:107220001A87CCCEADCC64766EE55E66E7560E630B -:1072300076CE68DF0AA2EC1BFBBE7A04FD1EE78B4C -:1072400099BFB8839617CF955D16FA7EB1AA9D5F58 -:10725000A8191F69EF162912F239CADEB9CEE13931 -:1072600090DEECDD5B60EF86A21D1B0A7A64C4C76A -:107270000D436DBAFD7247BE68FFF54BA02F7F101E -:10728000719EFDBE89CD8BF67DD13E16F46E37A77B -:10729000E75185C9B3C3E7477B3A7524D3F7AA43BF -:1072A00071384E543709ACBFF70B0115C681BF5D6D -:1072B000C2F9F29D7BD97C798E99F183FC9BC8CE73 -:1072C0005D50162C8CC0C3DC4B1518D79C2B110BB2 -:1072D000F8AF0B0EDD700AFCD60597D6A3BFBB0036 -:1072E0009EC3BE89ED6DEB3268BB772E1770DEA1B1 -:1072F000EDEF9817B6977A3F767E73EC7D1A533888 -:107300003D53EE1302B02FA7B77D102F72FD9B23C4 -:10731000B621BFC85B62CCF8A4F65E984F2EC69724 -:10732000AA55CC6F0EF389F24D15A2F944255DBC28 -:1073300030B59B2F77EEA4FD4DE9B9BF1ADFA2F758 -:10734000E1B8713EB380BFD7131F343E47F59FF3BA -:107350009DFAA9B89FC7C88F46CDCE5C4346815ED3 -:10736000BE6FF23C3A1E70F49F942F94CEDBE60D74 -:10737000D39DE7D9C5F97293E7D8B45415F8486A94 -:107380000067B7976F3F904AFB778B3B330742E626 -:10739000B3FFA67820FED062ED423BA8E130CDCC11 -:1073A00070F8578EC323039CD370BC090A4ED4AF28 -:1073B00090C1CEF17D645ECA67D05F6F908F4F142D -:1073C0009FA09F85DA780572A1FFBCA999C9C55B0A -:1073D00023A05C6E265D0781EFD529822B44AB2A62 -:1073E0000C6EFF21ECB77AD54A9F839E970BAECDEA -:1073F0008C1DF6F4D498389662E1183709468C9BB8 -:107400000BE0BD24D8B768C6F6EFFC1EB347463F75 -:10741000658AB9F508D033E5DF64B2091E06E87F56 -:10742000113830FA31517AF035F7FDA472FBFD2A9C -:10743000C8C10EFCEE52C01FF286D8F8A3957B257A -:10744000751AF24D9343908E2FE3981C60A9DFC804 -:10745000E75BB43CE01FDE6F1664F87E06954F32A2 -:107460002D9A6AFAE2A08677B31ACD2F8827A4470F -:10747000D80DB06F91EB96D5C1B7914F37ACA2EE56 -:10748000991ACD274D3E60072FC7AF28FD09EE8F13 -:10749000B97FEA9BEA4F9A59AF3FFBAC5DAF8F864D -:1074A00038DA5E01ED0A694ED4C50FF2CC6C5ED6B7 -:1074B00062F520CEBB5E935D9BD568FB7315970B81 -:1074C000CC5722CFEF4D850EC1BAB1D34A3ED1FA87 -:1074D0003D84E12C723C78D5EA41F9F554FF045E15 -:1074E0007F4FFE9896FF0EB407FB16557D7BC6F1C5 -:1074F000488B27F5D6AF6966663FBE69BFB476BED6 -:10750000EEBA8397B462FC4D5B7FD82C7A7E2EC393 -:10751000FCB848D0AD7350CA71FDF29F50FF58E5DA -:1075200032F543FC2844F9FCEAB6A7315E7DF6F952 -:10753000633783FEACF8AD482C549F3AB6C5931020 -:10754000DB07A2809F50D124E27A169142B93323FF -:10755000FC0C42D6307EBC148F76A7628739504C23 -:10756000BFAFD8F54936C4DD3A1E60F6CFFF3CC741 -:10757000A3BF2D1BD6FB2B24B68E6F94CFBD1C9FB3 -:107580006776DBE682FD161AD879D78AC639B23912 -:1075900022CE506596595C7BB70DF759FB9F13704F -:1075A0009F32D01779CE52DBFF79E63966972B826E -:1075B0007200CECD56346CEF803878C55133FAAFB7 -:1075C000DE86730AF8A7535F7A01FD236F50D4C596 -:1075D00041A3E28F0D62C80CF1B3A62AB403347F35 -:1075E0000CF38DB1E3F0BDC5C956BCB477979FB21B -:1075F00070C5CBCF3AF0DC6CEB5607C6211B2E1FB3 -:10760000FF8F8A37363E74D978E3698E8F5F99F59C -:10761000EB35A42119E39094BEDC9218718B30EE07 -:107620005FF8EC29580F3BB3E3AF4F01BD95FFB8AE -:10763000F0D47DE08FEDB33A61BCF63E7F04D71302 -:10764000B4EF76733DEF78EE595C87E9F8A3D9057E -:10765000B575EC3D3118D6233AB67F910A71DB55EA -:107660007BA7E33C6DD5CEA9FD498C798096026E4F -:10767000037D580732CAABA5A96530D07996CA1BDD -:107680005CB670FCB8B18AC5E3551E37DE167BBD0B -:107690002D2A4EDC34F396EB60FC6E925D2AE943B2 -:1076A000BCF83095E3E83EC86FDB439ABD8F29BF35 -:1076B000B3F00F2AA7F70DF2FBAC69C9AF9E84B2F5 -:1076C000A6E41EE3C5A13EF04D5BCFDB62767F6C86 -:1076D00006BDD9F16B8CCF83DCE85C8374BCF0D938 -:1076E0006088B39C94BBEEC2FD337BCDB82FAA62F9 -:1076F000EFFBA83F1D3BDFC6F532C2D7D53A48F8AD -:107700008FAD83F0399C774B3C8B3373FE431C5A0F -:1077100075E0731E6F6638D6E2D03DC59FD32D6CE1 -:107720003F91B6CE58B5E5CF0A31C4F5853C90D32C -:10773000B1CBAE8B6A7C70021F2644AEA7C48EF319 -:1077400087D7DDB8BC407EE07F85D74B687E20C4FC -:10775000CF03C2FB24863DE8D8C4D6613AE4D8FB07 -:107760000FB5F595148B414F037D5B57E98DFEAF47 -:10777000CB1F19269BE3A3F974E6CBD8767C824510 -:10778000F876FB612A85A8F57F0BACCF371D5360D7 -:10779000FEA18D635A7FCFF079F299E7453CEFB1B6 -:1077A000AEB105EDB8D15E5413161F34D23B83D36E -:1077B0005B1D64E3C4991DF1013BADE7CC2BBB110C -:1077C000CFD5DB8E297E5ADFC1869795B688FD52CC -:1077D000304E0422E83FF3E2FE6CB67EC4E6E5C616 -:1077E00076E6F076BCCDB1DBF16E3BA76B6785BF6B -:1077F0005161E7772EDFDE69C93D07EA3BDD2A13D9 -:10780000D8BF7FBA512C0AC4687F9245D6E2F24CA9 -:107810006FE87889E71DE3D9F946314941FF7A5588 -:107820007CDED18414481515E2146B6AD9FED2357A -:10783000DF77A581BCD724DE86EB6D7506FE3A5353 -:107840009CF910BF704E2B19077035DA9B44B7496D -:1078500047FFAAF8A2FE701E7F2DF7C788E4C2F387 -:1078600097A2A3B008FA233A4D4E6B8CF505D95E6A -:10787000423C117C919DFAF392E4CBB12AD4A3ED62 -:10788000A3A9B4B41EC442A71BB70A4B79ECDDFC14 -:10789000594EEC77E7363E4F7013D599CAF683C13F -:1078A000B8D1B923219B8CC60F899BE2D1C69F0B0F -:1078B000DBF6EF077BB4D641DC8954CF285755312E -:1078C0000BCE8D8EB1085980D3736FFE96D66B6D3B -:1078D0001671FED069D7F685BA1341CF6CE411DC7E -:1078E000FF0750FE2AB99B4EE3BE4002AFA476DFED -:1078F0002B315DB4E3BCE7FC46160710C9D5BF9831 -:10790000CCE2702400F4F3F16405A7F33CA4F07E0C -:107910009982E73A96BDF6726E88303944F22BB9F7 -:10792000487FBEB4DEEAC8867579E277B7C2399976 -:10793000325E5FBF12FDB953AA7E7ED0D3255C4F65 -:10794000FFBAB4F010D8BF32CF52B4EBFDE7EACFA4 -:10795000A51AF75921BDB02F8CEADD9342F4BEABD6 -:10796000F2E6C7D6C17C397AFF151901FBC92A484E -:107970009C0BCEE7AC68D097EF03BB7915B093D8DA -:107980002F17EFEB95BF6DC37F3179DC65F9EB0AFB -:10799000C1FBDBE231AEB2ECB5C5689FCC697AFEC3 -:1079A0005A553D7F6D238C7CD4F339DEA5E79B3699 -:1079B000FFEC89CF0979FAF3BE463E4B84C71B0220 -:1079C0002C0E11B5BF2DB809E936F2D9C8D7760B00 -:1079D0005FF7E27CA57F25965466B281EE74298418 -:1079E0007A61D4A30C7B48807F0F4A09D4E257AE5A -:1079F00078B4EF69BC3F4219FBCE067A2402BD2E53 -:107A0000D42338D10776DE463E70B65B41589F904E -:107A1000AFAEE9599EF794FEFED822FAD546C0EFE4 -:107A200068D42B766E378904D664829EBA9C306EF9 -:107A300037FA2C6A9904F79F10B56C28DC7BE2C4F6 -:107A4000F4C77C1F4AE74882FB821B431753C13EA1 -:107A5000FD38A7EB66B07BDE25A404ECE0CD716CAD -:107A60009EB298A77FB72ADCAE4E7BED7AF8BE595E -:107A700056E15C7867F356CB30C80745BC7FC49BA2 -:107A8000587715B4DFD12C33BACA2C816110BFD816 -:107A90002B63BB1D6593F17C65D86F6B66FB403A29 -:107AA0009B3F712C8EB0E71DC19F5E05F1AC274C4A -:107AB000B1F79F0CB79AF8FD35DF70FC6D8CDA7F5B -:107AC00037DCCAF6C7FD7808ED4775E9793E0E3315 -:107AD0007DB896CBF9F74B6FC0FEEF6C1654184784 -:107AE0000AC53B6E1C45FB39F188C4E3302C2E39A6 -:107AF0008EBFBF9BB8D2801F13AF2302E8F3C43FF1 -:107B000012DCB735AE6629CEAB7EEBA038CF8675DA -:107B1000528A5BB07367ECE8BF8F6F9574B84C9C6A -:107B2000E6698179E684A304EDED84A3FAF23C12C0 -:107B300010B19D36FDF36B4FEAF305568E6F074982 -:107B4000057C6FF85244BA3ABB88EB015A6F67D98B -:107B500000BCEFA6F3229CDAA5E9976251AC717ED6 -:107B600026E081F2EB0985E0F8F2C4523BC6EF5FF4 -:107B7000595A71058CEB9F7FCF7345AC73E011763A -:107B80002981EDAF722750E229AED70A8CDF75E963 -:107B90002531F6EB6B38D670ADE1397D699C27D67F -:107BA000BEC40FADCC0F29583A4250605EB64F208C -:107BB000C0D78E073C973D37E3270F64003DDEE0DA -:107BC00005F4B32DCD823B969FB1CAEA60F3BE07A0 -:107BD000FCB5B01FEF5EAA94601F7BAE7703CEABFF -:107BE0006E87A02B7C67A95B88E7709758C866886A -:107BF000674B75E9B7C603EEA7CE5847E97DB2C417 -:107C000084727E427621FDFE2A4230BEC0E3B50377 -:107C10006F269B22CF23FFC09AFFB095D6FBB0D52D -:107C2000897249F6B804A0DFF5DFFFE500BDEEBCC0 -:107C30006446390EE0F31FEDBBAD9C4FA3E3DC6B54 -:107C400001FFA43C05F5C3E571A865C9702F01E5E6 -:107C50007B8C7554CD2F4DF250DB46E949B29BF039 -:107C60007E2EE276AB4E6DDF19E1EF45E8030909A0 -:107C700004F6A569F654681642F114FFE32CF610D9 -:107C8000CC3392CA69BF2909566261F5B54A67C209 -:107C9000E7AA719F3BC5652E1C6E22B8AF0D36D288 -:107CA00042FD9A9DD5ECF3DA4482F666ED635260AC -:107CB0000DAD67A3D46685F849A65B2D80AD444918 -:107CC000928AE7BD0795337DB465FD3231ECAF5044 -:107CD000651FF30F7141ACF5BA8FC3FCF2BC00FC19 -:107CE000CA3ED4F50AB8352E2B6BCF75C082FE790B -:107CF000D86E703FAC908FBB133F35B1FD02A1EB46 -:107D000071BF9DB68E66B41B540FDE1541AF3E9514 -:107D1000089ECF75D3FF72B52D7711F6838F93B977 -:107D2000C19A16F4DDC4912D80C76B5FC7BB38A222 -:107D3000ECC884373C6B80DE6F6A3F8C781813A2E6 -:107D4000FAC8E53352857B2A9CE13C94B75AF9FC8A -:107D50008EDB9B94D271FDD1AFE53833F257D36BF4 -:107D6000A3BEE7AC76B598B1D60032C1D80E11BA31 -:107D7000E950B3C01EBD21827FDF994FF142E9BABD -:107D800017F40EFCF38B8119809B0DCDDFB1827E41 -:107D90007CE3F1A3997E1DB1BFFA27A2A7C3CAF65F -:107DA000873B800FD5FB2FF2F12384720ECB95EA2F -:107DB00047643C44C3BD11E79A5EAC810B33B2F01B -:107DC0007C1C01F98842230AD64C363A81AF9A7F4F -:107DD000BD26ECCF26E2B99E554ED6DE1A59F3CB1E -:107DE0005D16E8EFAAF882FE975B17F55EA2F3979F -:107DF00088F3305EA90BE767DE4B0A09247F0B7E10 -:107E00000569EBB93A7EA5C4C5E05707E8D1F8FF8C -:107E100027FB936DECCF836A777FAE259EDFB6514B -:107E2000BB907B4F7D3AC305399C16890BBE5ED94A -:107E3000937EE751FD06D72D4A9F0D7A3CB199EA12 -:107E4000B1295A8F5D7209DE5BE7DA6B437B67D439 -:107E5000EB8BBC5F5E1BE37B8DE8991107F37153DD -:107E6000D760C05DB64A928B29B1D94191ADAFB60A -:107E700026EBC691E8F1DD8F7652F32F35BFD2F8AD -:107E80005ED8AFE4E38616CF148214FFB4DFF7C7E1 -:107E900079E6015FD738D9FC130E9A82BFFC03AB99 -:107EA000E70EA0CF46FB1007EB1A2342992C5E1277 -:107EB000D2E95B4FFA6533E84F6348C271CC4FC7D4 -:107EC000B16142CFF4F48B4B64F452AB027ECAC072 -:107ED0005CC21AAB26B8AF7B6036BB4766600EBB90 -:107EE000F7F1DFE3D87ACC7D716CDCD0D21F584B30 -:107EF000EE817EC912F19B73BE39DD402AC40FEFBB -:107F00008F73DF0DFCB014B9B11F194EE21228DED9 -:107F100032A44601F6372455AA028B1B1236EE40D6 -:107F20004AEBCB2856F361DCCAA0B616E22019CD85 -:107F3000B1CFF56C8893BF5DBCAB29EA3CCA8638EB -:107F4000E66F1F54687F938BD9799470DC86920F0B -:107F5000FCED88BF0D3BDBF1195B0FF527323E1BB3 -:107F6000E75F2030E897C4F33F5488644DC2F9912D -:107F7000DF04DF992C383FB2115723D8CF97E2584E -:107F80005C759DE05A0FF99F485D16B86F47C3FFB7 -:107F90008F27DFEA92E82B8EEBCE67C39C95EAC36E -:107FA000F320AF8EC9E787AFC51E740D6678738B5B -:107FB000BAFDEF9ADC82B24E6E56888744DAEB78CF -:107FC00005E7F71D429C0BE6431DCB0546A760E184 -:107FD000E703247D9C86DB436D1C78272E13E9B7CD -:107FE00011FF18BC1FCCE2B2003D1AFDE173A4865C -:107FF000739EC673A06959E1B84D3AEE932D51E0D6 -:108000008E2F72BED986FE97D7C1F4DF8887FE60B7 -:108010003C2E736E92F2AB15E4DB5FAE49047BDB62 -:10802000FFCEE30E90AF910F9D827FCC4158DFFAD7 -:10803000831C739F8896A6A50D28057F342D3D0DC2 -:1080400053ED79BD5D8A19073CCDF5EE1BE3B59E76 -:10805000580CF3C3D3D09FB39E77DE73A3BA776176 -:108060007CBC3E8EF1BB5ED1F8A826809E75E75D94 -:1080700009EC7E924476FF9093C97383CF522A49CC -:1080800091EFB9D11FE947DC33E68111D82093ADD8 -:10809000886B16BFD1CE655043C7E497C8E8FAB9DC -:1080A0006F4C29EC9F916DCC2E5DDC301DDB4B2598 -:1080B0000F588753BE2E2D31B920AE7376D19F1C39 -:1080C00070147C51466B2EE0FD88E8916DE331D44D -:1080D0008DF3B76573954088422AA59E1A2426978A -:1080E00019B8EEB8D01473FFB3DDC6E6DFCD714E1C -:1080F0004CD3D20697968D8DCC0F44396978A47AEB -:10810000985E36AEFB9C30C5470AB46FD4A74E9933 -:108110000461DD40B387299CFF9A3DD6F42105F424 -:108120000CD6014BA87DD4E43984BF9A8AF14AFC6D -:10813000139A5FFD02E6038EEB0AD0DE51FD5F8FDE -:10814000FA3282D96F2BD8D3883865E7DEF707C1BA -:10815000FADF87DFBF100FEB407F91BAE2C17E9E4E -:10816000BCFFDD783837F4E1FD2C5E7197611E3578 -:10817000C1C6ECFAA3B6926CE8D702DF7FE77A2299 -:10818000704956B3758DE501D1709E5C7F2F4F55B8 -:1081900063B2E19E1E3FD65BC5EFE732CAA192CB28 -:1081A00061F9B64D4A860AED7BDCB67E706E8FA013 -:1081B000BD3CD9148FF3118D9E45DBC6283077FA6C -:1081C0004BB399AF7FB7CA6C5C7017C37A9687F3CD -:1081D000CD48E7C17D36AC6FC9CFD8FE9485B4AD2C -:1081E000D5D4BE7A9AD9790B633F967CA816F6A7A8 -:1081F000C25BF29080F36278FF7E3A4E79563F88F8 -:10820000EB5EC67E1AEFCD319E5FD5E653CBB8FC50 -:10821000CB8807F52FEA5C6B335B9F36C6FFCE1F1A -:10822000CAB261FF6D3CFE914B26C079E81D87867E -:10823000245CEE3EE533FC1E26B8571AD2933E82EC -:1082400069B64D65F76434BF7D2FE0AA3AB81DEFDB -:1082500019FBBAF6A6AAF99403F6306B7687FA9161 -:10826000AB013FA44CD0F997D59B2E286CBECBF820 -:1082700070077F7E07F4371BF659AB3F9A4CE57CBD -:1082800047A57C31F21E32BF4D7FEEA6AFFDD5FA79 -:10829000A9F55B2BAFE2FBD18CDF69F8CFE6782C38 -:1082A000DB52BA6E0065D19ABD2706F3F368784EAB -:1082B00047C397113FCB484961BA108193E647B154 -:1082C0005F9A3CCBEA16F2FEFBD3F8BA5E1AC48F73 -:1082D0007AC38D111F1D72DB60D067233E3A7AB8D6 -:1082E0005FE42736E62794A9EE4288675137769DEA -:1082F00033C24F3929D51DBC0FF46C0BC379C4F8B8 -:10830000CB9CB9D7651CCF57C6ABFDE13E3D94DB96 -:1083100044D81760F6C37B5A3BED3EB76BA8047C8C -:108320002FC2F4B4AFC435746877F9D2272E38C0A1 -:108330008FEE1C41308ED311AFA7F7773611E9F9D4 -:108340001D9743A5D4FA8F3F838DDAD28AFB1DDABD -:10835000BFE471A02FCD45B1FAF927FE1DE1F786E4 -:10836000DDC5F54C9B972CE072BBAB99AD672FDA5E -:10837000588AF230EED77A43701666D0AA3C8D63E5 -:108380001490BF513E4B5CDFC17D605172228FF073 -:108390007D011EDCA753562F62DCC328BF7CBB9334 -:1083A0009DA3576B701EB7428ABD0E79A5DDF4B54B -:1083B000FA63ECC7C22601EDA491FE655B6AD70D96 -:1083C00020D07FD6BFE87E8406A25DE2FDD4FA55B8 -:1083D000465C78FF40D4FA50DBF524723FF5F2E6B4 -:1083E000C5B82FBF9AF69FB03812C68534FA357AD1 -:1083F0008DFD2814CFC81688E3AE165C609FA3EFEE -:108400002773EBEE3F5CD8B07F20C8AF5D62FB66A0 -:10841000DBFD02CE0B3B3F206C7D60BD80EB693DF8 -:10842000CAAF99ED07EA598E350ADCE757B651888D -:1084300029C765F5F9AEA111766A7960866BA88EB9 -:10844000DE46DC1FB2A2A154F77C809DC793B8FD25 -:10845000EE4DDF484D62CC3893A65F9ABE69FA971D -:108460006F57D93C470A1CCCC804BBFE18CE4BA89A -:108470005DBEDACED707E6D157AA9FB8A05B1F58DA -:1084800092C7E4B3442CC6E73DD957CA079D7D1E69 -:1084900067D7EF7FF8B6FDD1FAA1E985D63FA35E95 -:1084A00018F9AFC5D58C7230F21FE882F9C11B7B79 -:1084B0006D810704D07746A77FAF15E9EC482B7094 -:1084C000C139C83FC00794CEEAF4DB315F239694EC -:1084D000DA715EC7E74DE3FA163FC8E17ED64EABD0 -:1084E0007B2C3B4754920CB89852DB36D3E2A4F86D -:1084F0007C647421DC2B3AE5B1B69910FA5EF2C8BF -:108500009842B85F7ECAD6B6772D2EEAD7D58E2D83 -:1085100084FBE55780DD80F60796DB10573DE58943 -:10852000E7F27995BD3FCE5C329FDDCBCCCA2B29DB -:108530008F2D743CAB3C3CFCF7A09F95ADC545101E -:10854000B7A98488371DCFAADC8E902D9B8DE79329 -:10855000E87BDB6C9E5576F0EB2EADC5F1ADF2B04D -:1085600084FA440EB1B8A844FB6AA5DFAD8DA37EA2 -:108570002FE5EFDA248B0BE6AFF4B91FE6B56B936A -:10858000DCAA1AF15C931F7C0774AC35B175FBFD56 -:10859000AF0D4F68BBCC78BFDF4726C33CA4C5678F -:1085A000C1D4589EAF38F17C44BE89C5358CE5BF37 -:1085B000D2EC2C51330017D5871416AFA67FE04FAD -:1085C0005611A617D5849DEBAA3A4CF01C4BF5A189 -:1085D000423CC702FBFC3FD6E1F05F738EA51B5700 -:1085E0008C4F059230598AC0F534BB559717FB9BC9 -:1085F00046407F8818E78273186286A96607EDBF38 -:1086000078054D293F24A74B84FB5AEAA64E11E179 -:10861000BEA93532DF3F6262E7CCB5F69A387FB447 -:10862000F4B4BD6407C8FDEC5BADB936B67E81F32A -:1086300061ADBF6B04371160DE7580E0F9809C147A -:10864000D202FCB311771EE0ED3D7B12E7375B37BA -:10865000A67F1990BACCA697558AF7571F5984FA66 -:10866000E04A30DD9349F36FD997B17C86E9422621 -:1086700085F0DBF67296BFC6746108CDBF6B5FCE26 -:10868000F2B0C04907B623F68A42FF486887E37D07 -:108690009BFB1AC0B76462F117E91505D753B47D87 -:1086A000216BE9440BF0F81ED84D88A7D416FCDAEC -:1086B00006F1EA02B70AFB3D36F37B83BE69AAF1F5 -:1086C00055B49970FE0329F0FF43CE4F4D2EA4C937 -:1086D0007D0DEC8B258DEE6B601DEDB4DDD306F6C4 -:1086E00066EC1BAD53C07E37BDF3A75CBC9FFC0A94 -:1086F00056CFD837E89C90F6E7EC6F066D8A5C8F12 -:108700003E6DCFFF14BEA36240FF54509DE40EAAFD -:10871000876BDC4455B260BEAC9F2F3611669FB6A6 -:10872000D94ACE825CC9C0108E5B45F6924EC86BAA -:10873000F69CB426F5695F9B92BD5A847139292352 -:10874000787411D8FFDFB17B3D04B71BF773BE14FB -:10875000BED78CED0FB1C1FE10D07F1749F3A7F241 -:10876000F8178B2F9394DC887930EF07FD7E1AEC95 -:10877000379F6063FB0768BF44B0AB63888AE958E2 -:1087800088676581283D98DF431A8FDE47EB7FDCE1 -:10879000CAE2499606A28B0F66C7B338CB4C078B4B -:1087A0000FC6C98DB782FF10778E38C17FE8FCA550 -:1087B00022E1FE22C97923AE8F1D3411A0F7593969 -:1087C000E084F599AEAB247533E9AEAF93CB5BABE8 -:1087D000F77145BD0AE272731DCC3F7D369FE07E86 -:1087E000E8AE534A00D64D93322C3591F19F2BF9C8 -:1087F000770F390B32E321FEBC378E40FB13F6C5F1 -:1088000099400EBFDE9663053CBC043CA27C483216 -:108810003BEF86FA922E507A33F139DB272FA9638A -:1088200012287F27DD6057E1BEA967AD8D37E07E56 -:10883000D0174C78BFEE4B8AAB14F22F9D579D603A -:108840007F9FCD6C8CC3FEBC60C2FEBC14D775F597 -:108850004A4AF7C323587C4AB21109ECB2642A5041 -:10886000EFA6CF73E3D93C49B3D3CBE399FE3C2EBB -:10887000103C0F2099F2517FB4FD3A9D5D04F7EB57 -:10888000F49BD52A028EE34AB5B851488478CFE4E8 -:1088900012827EDB64BB8CE772607F309C1B9BC2C4 -:1088A000EDEF940F2A713D814AE030DC7FD962E719 -:1088B000F768F175C5EB394EAE236D22F891D75D9F -:1088C000222E88075D7F498AE9474EE7F53E23104F -:1088D0002981BE977F51950077F944EFE74DAF2F7F -:1088E0003C05E3E0548BE139F889488F1BCFF74F03 -:1088F000771AEE4F8EE7F3D6C16470E43E316D1DFA -:1089000068BA38F209F4538B1417F065BBDDFD3EED -:10891000AC7BFA5B6572B938E2333EB69F6FC4A593 -:10892000385CFFA1F8B4032EAEAEAFF35B69BFAF06 -:108930001ECAEA071C825DB9F29729C960E7CDF12A -:10894000CCDE68A9863BC0973381E1CB39BA5B3F67 -:1089500057C567E27B9ABE01EEA09E3D72607EAC79 -:1089600075658AD75580D7ED7682F3B31FA55BE690 -:10897000829E69EDEC8967F837A6EB6A57EE87753A -:108980001DFF676CBC9836E0921239DE7FE86438D0 -:10899000F3AA75336FA6FDF3DA655CBF49E5E78B93 -:1089A00022F1921E81170D771D7616EFD1F03375E7 -:1089B000F7BB223C9FFA1921CE4C129E8768F8998A -:1089C000E267389C72888D13BDE1C7DDE59C06E641 -:1089D000310A3787186E0A283EF0F7B77AC08F1130 -:1089E000374FF58A9B2FF13CFCAABD532FBB6E1865 -:1089F000F4E9F77D1AD389B6D8FB828F727EEF56E1 -:108A0000EA6ECC067B7193899D7F9348C6AD14E7CF -:108A1000BBE3B47BE56BB220BF5D62F6677BB31945 -:108A2000EDCF76BBC78371D7340B9ECB2692A70DB3 -:108A3000F6F5BB0658D4C8DFD1F82EC761A31C9A3F -:108A40007802FCEFD798FCF36ECA811BEC487A19C8 -:108A500093C3B893CA2611E2428EFCFD80AF4FE06B -:108A60004E2DC0C37105EF25AA3EAEA05DFCCDBE64 -:108A7000B70B21BEA9ED1F9EB0E7EDC28291F03E7B -:108A8000C3D96BDCAE6A793C4A0176D2702FFDC443 -:108A9000F07926FDBDF225809FECEE72E37DEB734D -:108AA000E084171D776E6D734D07B360BC6F7D4E0C -:108AB000889D1F9B7DD43D1D4C65D47DEB1C0FB75D -:108AC00091D65D7162F4FDDF747C3E160FF1FBD729 -:108AD000430AC4C11B959A6BD87CA2260BEC8FA6C7 -:108AE00077F847F9D6F8E108DD7DFFC3F8F8F38899 -:108AF0004B62F738B529B84EF82861DF35F271EBD3 -:108B00002BAEF739AB5E9C0FF6706CB91BD76D5767 -:108B100039457CFE1312B26481BC5C12AE7734CA54 -:108B2000EAD41342F77B442A1961A7E57BFAC58D85 -:108B300085F6EF70784C0EF02BA4AE43F0DD84493F -:108B40003963C16EDBC7AC4D86714CA39BD255B463 -:108B5000D5DE4D87465727C7C91D8E8526C778F6AF -:108B60001DD8A1E0B1760B7CAFE1A071EF3926FFF3 -:108B7000083C80FCBBF1202C80BCC6071B4FB5FC19 -:108B80003F1F0FA181209F1EF1007108C7B7C2438C -:108B900016F055C303F5D7AE02FE68FE5AA3C2F61F -:108BA0001D6A790D0745F67C7CCFA510DC3F44F6A5 -:108BB00059D9396D4F22AE57BCEC646D747ED83EE6 -:108BC00098BA9864B283F9EBDAEF898C0909E8570F -:108BD0008EA106E10EF4E306A23D74717E9176410A -:108BE000807B37716F7906F897A164D08B31E6E20C -:108BF00010E07F876D4A06F88739B6C95980AF5DA6 -:108C00002356BD0E43D6AE01E52F6F51BBFD27CDD8 -:108C1000EEB5F06AB5F66F7430FB74BD9B9D0F0224 -:108C2000BB1D498766FF412C4087109A63FACA86AC -:108C3000F6BAB90DEC39D041F9BA5F204DE01FE426 -:108C40009BDC2953C1CFEB179280CECEBD5F0C8643 -:108C5000386571F3AB4781DE626D3DD4A55F0F359A -:108C6000FAD19ABFA3CD2B347F489BCF82DF04E596 -:108C7000D9FCB9D3CCD6AD26872C786EF9F1F3EABE -:108C8000556EAEBF12ED4731EFC72DA415E9D2EEF8 -:108C90001DB999F3A3F8109D876643392137513EDA -:108CA000DCC4EF1DB9C9A5BF57E196BCD8F78E68E3 -:108CB000F5F4F6BE717CB8D6B06EF46DD3433E7653 -:108CC000CFC87FFAD83C77D210D12FC1809A97CEE7 -:108CD000EE6970323E1C52628F57FBB9FE4E32B5C0 -:108CE00065C3B9E5FD7BFE8EE3E32B7BFEFE1EF83C -:108CF00089134F4904F6B54E3A352E01D7E7F3D222 -:108D0000703D59ABD7FB69938DB0E7881FED77575E -:108D10000E527ADC0AD067C1F4B7671EFF29D477F8 -:108D2000F1B84422CF4D142A9EA110C72DE4BFBF35 -:108D3000735060FE92567E90FFEEC5F31CB7B021D3 -:108D400042BB8FC41C21E79BF83D199A5C6F3A59CE -:108D5000744ACA8E960FFCFD33E20B5A5CA199F35C -:108D60008FB4FC11CFB77CA7E96E09FCF3EFA4899F -:108D7000C41DD1EE0C95CEE023E21C2F3B0C7E4AA5 -:108D8000CB733FBD998E2BDE3744DC4AE86DDEFEA7 -:108D90007A36E45BC598F78F18F9FB9DE6BBF1FEC8 -:108DA0009121092AD2D35BFB93AEA638190D722705 -:108DB000CCCFCB65F77718E5FBCA9EFF486E1BD971 -:108DC00033BF7B92BF510EBF3D5380EB4EBDC9C335 -:108DD00088DB7DB49F7EDABF10EDA79FFA63AFF802 -:108DE0009C98FFBD2F0DF31A5EBD7B9F4E067F4EF4 -:108DF000C3E9F464869B89BB7F9A4CECDDF232F2C6 -:108E0000ED7307F36BE610D7EC9BE93F770AAE787A -:108E1000B4177ED20AFBB34A388D730E17A2FF41F6 -:108E2000F87910E33836471C89E7DE7BFDDD9BA12E -:108E3000F932985BE37805BFC702B8368E53456FA9 -:108E4000D449E0B2154AAB981DE37EBA469751CE9D -:108E5000474809F6A3273A8D3830D2ABF9E7DAEF65 -:108E6000C0507E4C4FA2F5DDAAE663FFA2C661CEDC -:108E7000979EC6DF9EFA959CC0E3DE1CFF174E4E00 -:108E80007B0BD8DB93BE19E5662CD7EC47213490D9 -:108E900083A91FFC912109A9A80F859714E2A6E3D5 -:108EA0000C19A83FFF4E8AAF40BCDDE364CF7AC205 -:108EB0005BF52513F12477E34E0E3E6603DCED9659 -:108EC000EA6C101FBDCE5EBA06546FDAA705B3F088 -:108ED0009E8736138190D9F4E6732D1047F01E2536 -:108EE000783EA0A079FF54C0E9EFA5569C47755E77 -:108EF00024E4B1083F33D8BCC6067E5830859D6F48 -:108F00003B984874FB90F72730BC068F9FBFD91D54 -:108F1000A3FC122F9F49DC29D9382EC763FCA3700C -:108F2000BD09FB3F4D701D4801BF659E80F385CE96 -:108F3000BD130EA4507A3BEE4C443B333DF8E0DDCC -:108F40004E2A88C6FF1E8BCFBB160A78CF40A1EAF7 -:108F5000C27C615926EEDF98F08FE499C5503E43FC -:108F6000C6F9CD74B1528278D4D9342107E68B7B0F -:108F700084B65AF81D5C7F296B8738FDC930FF7CA9 -:108F8000A738790CFE769CAAE587E1EF0312C33C73 -:108F90006DD5CE0BFBCDB47CD56C01F7EF4E77666B -:108FA000107F047E0AD753798EA5B86CEE5F00B8A7 -:108FB0009E59A43F3738BBC4460291EB168213EF8B -:108FC000213BC8F7697709FC5E7CAEE73770BCCF00 -:108FD000999BACFBAE94303FD3BB5364F771E4B3C1 -:108FE000DFA1D6F4EB46AE8737F0F9F13C4F868E21 -:108FF0008E6288D288403F5B47BEE5621B0ECFA5DC -:10900000E20787E7D3F66E1C6198D78A956B111734 -:10901000696C1D6F36EC8213C16EEADFBB254F9F72 -:109020008FA1C797B5139A3D98BD57C475C3D9F999 -:1090300094CF0289F2D3BFAEBD9860721D8078D004 -:10904000AD97DC788F4E94BDF8A0E81BD98BDF502C -:109050001DCCA37AFD64021F370791416037A68BB0 -:10906000DB7E0A38EAA4E3A639068EB471479BEF8B -:1090700017523D06DC90336C9D65FAA534DCEFA4F5 -:10908000CDF7C37684FA25AE18FED26F12B274F70C -:109090007A84ED4A845F22E77E7BBF643AF5479588 -:1090A0001CA06F20F18F457B8671C942D81805F14D -:1090B000C1B47318E7F14A74FE8AE3F3D3882FB082 -:1090C0007F4252B77E18FD152DCE3CD6A9F9537AB2 -:1090D0009C84E38DB3D87DA51A4E0A819FA0FFB36F -:1090E000448CEBF4861BADFDDEF012A2F6084C5664 -:1090F0008F78E1FAF775F1F2176D7C194A86F6055B -:10910000271A3E34BC18C79BFF34C4837A1A6FBA3F -:109110007A196F0E8C90D1AEF7E6D77CEAE4F3EAC9 -:109120000427A6375C351B7F97682CD811F037F9D8 -:10913000B8158E6BD5339C1C685B24C1FA9117EC73 -:109140004766B71CB478F0FF00C6C481D500800024 -:10915000000000001F8B08000000000000FFBD7C25 -:109160000B7C54D5B9EFB767EF7924334966924940 -:10917000323C841D082121090E21BC1137490811F8 -:10918000A20CA8888FD6011F6020094DADD5536F62 -:10919000332181526C3D58BDD67BF4F43758ED41F4 -:1091A0000D75080183277026A098F0D020F8C07AAA -:1091B000DA6829451B92185A0F6ACFF57CDFB7F69B -:1091C0004E662683A5F7DE73879F2ED65E6BAFF5BE -:1091D000ADEFF95FDF5A9B4AC09F0A50B315209844 -:1091E0000650F9E1864A4806E83B20011403D4966C -:1091F000C9411BFEB5B4FDB1C745DD0C5689DF5131 -:109200006126C0F5207E0B950EC5E60658E695BC96 -:10921000721680D62EDEBFE19225A862FD7AAFF9E4 -:10922000E31E9BE8FB35FF5F03C800B8517F7F1941 -:10923000FD0FFB2FD3A460185F5D363BBAFF8D97FF -:10924000CA3F91A6022CD7629EC34F3E93A7F2223B -:10925000CCBE24AC5744B78F7326B9CFD9F12FE3D6 -:1092600061FCD732C0C5F3656F51F7AFE977EDC840 -:10927000F2483D526601E8ACB77119DB5E6E017FC2 -:10928000C881254D50C4650052010A9DB8981958EF -:10929000BF64010DF9086313E0F7B93A1D1386DFC7 -:1092A0003F88E30770DC308E1FC8013854EFE4FAC2 -:1092B0006BF51EAE5F93822FA4E37F87BFB0A8B883 -:1092C0009EC5EDDF51FC38DFE24B0A8F3B9BD69306 -:1092D0004F0B8371B49E3FF716FDE30D30DCBFB634 -:1092E000FD338BBFF0F2EBF95BF3E7A7A83C3FCD72 -:1092F000AB150CCFBB44011883EB5C9A1BCD5F63AD -:109300009E58F9C6CA6FB9FE7EACFC56C4ACC79075 -:109310000FF4A2328D8AC3FF4B26D0A65F5E7E4338 -:10932000F2B1F8B3BD0523DB017EC9721A1E4F9757 -:1093300017742BBE42419719F5BA52B70BD4EF40C0 -:109340000ACAB9B213C28948D8F5E72B3E51A8F42E -:109350004AF071943E037C6CC85B1E1E7FD125E4ED -:109360006BDAF0BC8B146477113D1F0B8138EBA8CE -:10937000A17114EA1F60396CD9615A15C2755C631A -:10938000813B7D54268A32E094B87D93D3C4E3F6C2 -:10939000FFC56682AB015E3E985902489FD7EA3C02 -:1093A0000613014266E0F7BF4E52B9DFE6240824F7 -:1093B000E0FCA074DBC85E9412805CB43B65B4250D -:1093C000D88843362B611FD961BF578106B4DB2F84 -:1093D0008DF70E056E0714C9E68F734C8D59F47E18 -:1093E000B87B1EF69B55A4A8DBB08BCBAA7E87DA90 -:1093F000FB0E589DF45EFFFEEF7798699CBF8017C7 -:109400002984D70E5881DAE73BCC41F21F8BE4E385 -:10941000B209EBFD030056EC3F7F55B814506ED7F0 -:109420004077A313CBB924C738F27B8DD69BCEFEF1 -:10943000C3310AE5B44097D302DD6F951E90D98FF2 -:109440009426C941C81AF653D7EA325A806C253A95 -:1094500016B4E17AB1FDDA4B4A5CBFB4481F77E13C -:109460009F4121935C08D17ABBA84DF8A312D01478 -:10947000C0294B6D31EDE497909E45CEE8E773C966 -:1094800077A25EEF8EF14BF833D1BCF73BC5BC8BB6 -:10949000E4BF26F7E0FA5FB668EFCD437A074E9A4D -:1094A000E1597C0EE7B13267245FDAD0AE83399799 -:1094B000B78BFD07133515E97999F4C741F5D19AB2 -:1094C0003AF5F2FDA7F60C94607778B97985021326 -:1094D000581D4F7B3286F93D82AF3AFF63F9D9229E -:1094E00041931DF9BCB0DD5B46AE65041F3B918F17 -:1094F000F85EC980C6F35C291F0DFB78F95CA246B3 -:10950000FAFEF2B9D11ACDFF2AE96BFAB0FEEF3FAD -:109510003B9848FE13F9A82AA817032E9BF759D6A3 -:109520005FA1F7A15139C16D586FD1F5FCE5C48138 -:10953000A3F9C4EFEB4DDE67691A65E3C41585E452 -:1095400037B7969CC577240DA407D17E24D509771B -:10955000601940FB217D0BA402EB93194240F336C6 -:109560006AF034950BE6AB29C4EF411CB3DB41E351 -:10957000A929A4E7F0D78B337D8523F9DE528F0A22 -:1095800085F3B4D6DB34251B605FBD93EB6DF51E10 -:109590002E5FAD57B9DC742CF9C1208E53AB593412 -:1095A000256DF87D57AAB08F05E86788AE052005C0 -:1095B00003A8730B1ED6F55E91829B249213AE27EF -:1095C000829F2897C19EDC08FE36294D9366B235EE -:1095D000B0BC8BF24DFC3E06FFE0F35923FBA3DC4D -:1095E000A3EAAA4B627EE6BAB42417963F74F852F7 -:1095F000A86C916E397C01B8EE12F55BE50B38FE74 -:10960000F4F0427810E3C374140CF1157FB713FD26 -:10961000333A2C40F2C180CA7659A4D3A37D2E4997 -:10962000E7703E329DAFC7E07BD6CA30E9D13EE855 -:109630004923BE17DB7C76B428A443C855936EF645 -:109640004838DE9C748B5726D226FAA66F44FE75E6 -:10965000A4E384D8BFA32363AC8AF6A6296FBC4FCA -:1096600076ADD91C61812BCCBD3D11713C139E712F -:1096700052BC229FF635F2BDF377C901F66B8873B1 -:10968000C88F759E4AF686719E6B2ED9BC56D27FC6 -:109690007A11EDF56062F254F2CFD05DC6EBB8D628 -:1096A00026D6916FF617BBD89F850F9FC0F7FE6D2A -:1096B0001080FCE935DD1FCA80F4949AF2327B9069 -:1096C000CEC3D2E4142A9FFC5D720197A7927B89D6 -:1096D0003F074D7695E67DA75E2DCE467DD1DE72A5 -:1096E00098001DD682B71C0A9527EAA1381BF5E51C -:1096F000AD7A1B9727EB9D5C9EAAF7707918DB4922 -:109700009F5EC776D2B737B09DEA5DD84EE5311C73 -:1097100097CAA2DB9378BC96DB922CB48E83C9D017 -:109720006CCC4FFA144E0CB78217E03F1EFB6AABAD -:10973000ED2A8C97567FA1340DF9F4B3AF2A14ACFF -:109740001F5B3CEEA1BF60BBF967A61FDB90DE9BF1 -:109750004E395A8F63DD9EAAFCD841FA792C119DAF -:109760002399B5B94B433AA6936F1CCD6CD760369D -:10977000D6D3F47AC07C5DD97C8095A53DF9E042D2 -:10978000257159AFB3217F57DAFDDFA3BA25B0ABFE -:10979000A2EC2AAA6388247B97CC41B6F7B1927BCE -:1097A00005C6BB950EFF7F12BF0D7BD1A43FA491D0 -:1097B0007F98A949E072B3BC8393A4E1E746BF95C3 -:1097C0008E45FF49FABADE25B37DCD982F6941C792 -:1097D00048FB35FACD38AB9691FC669E2F6FA2728E -:1097E00059858BEBBE55B39AC8FECB1C977BBF94B3 -:1097F000DF7FD06566BD2D51B05F9C3868F49B8ECD -:109800004A46B87BA02B31F82CE9F5697F6312D664 -:109810001779B28A64DD3703D75D3BB6517BE5EB40 -:10982000AD6C57DE242FE1F299A89069D8BED02103 -:1098300079C3642AF33F6A4AA376A7E425B62DD4F8 -:10984000A69D28A6F66CD9BB90EAA7D5320A51A7E7 -:109850009485F32E60BFC5B9295E1BBE772AFCD064 -:1098600045D2DF85B949DE04F2F34AF0E91AAA7B52 -:10987000ADDE0695D6F15869328DA34A5E13D65BEC -:109880006E28FD1F4447892F052489DA5D0AE1D738 -:10989000277FF7C33227F66B192701D9CFA970DECE -:1098A0009F88FE859D896A02F9698BB38CDE6BB156 -:1098B00048CE4D5CF79552FF408E597D1EC73D7EC8 -:1098C0009B9DE341E55B058C838EDF3686E342E5B5 -:1098D0005BF34BA83C6E1278BDF2ADCA0A6E3741FD -:1098E000989C4AE5EDDFE2F7B697FEB0CC8DE31F1A -:1098F0001BEF62DF82722A5622FC24F60789DEBF44 -:10990000BD9AFB7748990F9DC5FE170B528AAC385C -:109910007FB93B21AA7FC55857547D49F6A86225D7 -:10992000C24F56166445D56F28968AB323FAFBE6D4 -:109930002744D55794B98AB323FADF54392AAABEEB -:10994000F2A6ACA8FA42D31CE13FEA617E99B0F3DB -:10995000F965D9208C89FCA953F47D03DBEF263B04 -:10996000EF12F8A9C885F809E552D655CC71B9D8D7 -:10997000AEFBAF00747B6692FF17BF2E1C8FDE8399 -:1099800020FE99497848FC1676231E207CA460DCD2 -:109990008EA0A7CC111DC72B40CD27FF5BD1B9846A -:1099A000F154B96779199A31F231FABD0AF9618136 -:1099B0004362E82EEA32C7A5B7626CF4FB06AEAB91 -:1099C000D0E96B31F99B52098B05B46EC235C67A6A -:1099D0000C3A2EB79E0AF98E3214FFDF5C572CFD2D -:1099E000001B797F114BD7A04BC78188A71807763A -:1099F000A6323EC49F3B1E3E30704F25FA3757A417 -:109A00007F7348EEE58597F76FC6B897C37BC6B8F6 -:109A1000C6FBD02CF3FCC6FB43CF5529FEF39DD8E3 -:109A20003F29CE73B714FFF973D1FD17286AA3033A -:109A3000EDF82848DE00F1FBB8AA10242B3DAD3527 -:109A400051B9E843BF427874F1D9401395F37A8352 -:109A5000C7ADB8FEEB726595F20D061E8A5DD78C18 -:109A600054B14F3A7A49B5ABD8DE1250EDB4BF6865 -:109A70007958B5D33EAA45830ADA2F6A134D1B697C -:109A8000BFA1E56389F59C54E1E7F352058E31CA25 -:109A900067657F5E2A96D5B69E47098BD47C316078 -:109AA00021307094705EC1489C7754093A68BEA317 -:109AB0000F071DBE083F7EA5386F14295B3AE9A742 -:109AC000A445FA91525B8216E93716395D51F5AF1C -:109AD0009CAAD8C77B4645BD779D9A15D50FF16BDB -:109AE0002EE1A0460BE42AE4474D895EC277B17CA3 -:109AF000FC177DFD5E8793E01398DDAAEC8F13972A -:109B0000BCA5827FB1CF57A48A7DEA6F683D586EAD -:109B10004F15F435C93E01E21037933EC4D6714F5C -:109B2000BA8AC6C3913DA4775EBBE922426FF84E64 -:109B3000EAD5D729A8CFDEE9A6EF4EC4FA23A98B30 -:109B4000447D9E69CF04ACFF34B55CD4AF364D374D -:109B50007B017E058BAF2BC37ABADBE74FC579FB60 -:109B6000CD8EAD12E219C52441917B78FFFB8805AB -:109B7000E3290A16954C7321AD76ABD82FD724A0D4 -:109B8000FFA3FE259A4AFCAA4930E4DC9341711DEB -:109B9000EECE3491BF30F66F760BBE87EFE7D8FC80 -:109BA000B5425FC2C92AFAA5FBF72FCA24BDD89EC9 -:109BB000EAE4F5E7EF99E7217F85747D97FAFD7F69 -:109BC000A46B533CBA9ACC629EDE96FC528ABBF9D7 -:109BD000E3511CD2B0BC70BBCFCF1342A82B8CCBAF -:109BE000358F84F54697C54B387DFB907CAFAC6CC8 -:109BF000D4F313B25DE88D9C62DAB81BCB9FEBFA0D -:109C0000F214CD3B83E61918B71CF5019C03E3560B -:109C1000148A3AE9832C170D10DE1EF8569297F736 -:109C2000C763077EFB03ACBF7747BE9770F4078915 -:109C3000823FAB82131A7BB03ECD1ABC2A8C743E95 -:109C400094E67F96F4E0366B7012EB9B6363128DA3 -:109C50002F69C0FB10637F87FB38D5327124EE1F5C -:109C6000392FD888CFB7CC117C36E6459EDA28EE5E -:109C7000BC375B3C37E8C0F95B88FF063D4374C0E6 -:109C80005827C7031079A445B243E461FF60E2BCE2 -:109C9000492D191FD6F79C35F1BEAECFD85780E6B7 -:109CA000583D939B789E392736C94C6C00FFCCD425 -:109CB0005948AFB6ADE77DFA8CEEE87DFAAC4E7F41 -:109CC000A903DF9BF57EFC7CC83C7DDCD910942980 -:109CD0005ECFE989EE374FDFA7CF3B1FFDFCCD54A8 -:109CE0003DBE8D86D191798E3A7DFF33787C420AD4 -:109CF000E929F93A19F96E5165989D3AEC375AEB12 -:109D0000B15F0EF9471B9785A79D7711FD6DF5A8EB -:109D1000D016F2931E2E0D7B2A3C0D77C2D4887983 -:109D200074BD37F838F8BEE0E3B49EDC9FCFC7BA05 -:109D3000B9D30C4175789D73753E0D82E0F3A0D3C5 -:109D4000C27C9ED9F5CBE9617C64F598408D585F63 -:109D5000829A086A843FB5E7A646D565433E3ACE67 -:109D600098AE8F9FE41D1D358E81370CF9BD9A5A30 -:109D7000DE493864BA631DE38E94D913A2C62D3E22 -:109D80001E2B27641CE17624F29F08D79F56A270F1 -:109D9000C62C77803800B33F546270C97699EC685E -:109DA000EED9E8E7E6B4CBC8ED72FC84A93F9FEF9B -:109DB000FEFBF9E9D2A2F9995611CDCF745F343F79 -:109DC000335745F36D943F9A2F63D64D896ABF6A26 -:109DD0006351547DFC8373A3FA6761008CAC4FDC44 -:109DE000BA24AAFFA4ED2BA2EA939FBA2DAA7F5E04 -:109DF000704D547BFECEAA2B927F61A82EAA1FB174 -:109E0000D7F40DF2BFBAED1FA2E6F9EF96FFA23428 -:109E10003D2FAFCB7F998E435C1AFAC7A2E138453C -:109E2000E915F293AEF637BEA0FC4BA044E5BC5357 -:109E30006009781BB1ED09D927915F1B83AC36A16E -:109E4000DF6832C13AF2F78F9A4C9C8734ECBC2A17 -:109E50004DE08BAA34E1F79F469BA6F866F0CFEC65 -:109E6000DE9E4478433699A09BE29AE265BF71C6B4 -:109E700001E16B713E7934705EAB3479F6B299A82A -:109E800087F29B32EF1FE5D17E50717D8DC71F3F5A -:109E900041F99F8B0E9B4AFA2AA7FA0314B7707DEB -:109EA000A1E761245E79AF3E3C89F649467D95671E -:109EB000E366EABFEA8E859368FF3AF4FC8E8E492A -:109EC000651172885CDF8A38F8E87B69223F67C4D5 -:109ED00087DBAC6A630FCA6B9A2CFC3FC685EFA583 -:109EE000E1FA3F901E360B9C1530D3BA314E72DE2C -:109EF000DF8580BA0ECB94E178A47E8D4AF5C184CB -:109F000068DCF9261144FB085B2AC7FF5B0D7FBBA9 -:109F10002E8FF936E888EE3F78F744C1CF6F23D70C -:109F200090DF672C621D06DDE7753FFCA9EE877B9D -:109F3000C9FF46E49BD7ED783C89F0F5995C81A791 -:109F40008DE7CFE8727D264DE0E9F53B139C9179D2 -:109F5000C7EA902BAA5EDB36CA7936420FD71BEBD5 -:109F6000F04B0AAD63836E3FD59D3DC9B701E3F168 -:109F7000A7D370DC9A1D17BFBD8FDE370D648838FC -:109F80001AE0F96E790F18D7DFF21544E1D297D2B3 -:109F9000447EE525A20BCB95583851DF56626C778D -:109FA00051F9C6FC72B23B7C1E96B0BEAC13CC8499 -:109FB000D396FBB3CCC4F453E07D672F2E6D5F9A2C -:109FC000CAF3DC043E33C5C577BF5D9D44FD86C63C -:109FD00033C61943B959D42B57C09C41F99A6B2405 -:109FE000C60D389F8D9EFBEE18B399E2AF31DFBBF3 -:109FF000E0BFF00EEAC50AF0F2B8C6F800A9517E3B -:10A00000F803CB901CED24BFBA2E5398F239756734 -:10A01000AC7CFED1DF30F0EB0790CEDF557DB15741 -:10A0200042BA7FBB7AE057FBF0F9AD4FA1DFC5B56F -:10A0300066DBFD87D322CEC3CEDC7D91ED0CF1C86B -:10A04000F34F92337AC9EA25FBF8A0EAA59C48BCF5 -:10A050007F226D6127BD07B3D3E29E47C4EE2BABD1 -:10A06000483FD96E55C699865EDEA7EB65DD0B933A -:10A07000F9795DD2D07A44FD7999F3577507ACBC74 -:10A08000BF7F47D787AA17BF9819999F6B41BD54C7 -:10A0900073A8747249E79C2AF266CFF1C1A9D46F04 -:10A0A000A3ECEF213D3978E9E364AAEF79F34B5E45 -:10A0B0000FDC7465F4F723F322F95C9B34F02EF97E -:10A0C00093EA7D5695F250A5FBF28EDD8EF59A4E01 -:10A0D000F43BB89E0BAE9E234FD37E6ABF04949789 -:10A0E000AA0927B073AF69958294C7AA6ADBBD65D8 -:10A0F0000CD6AB9A971793BAD6260B3F56D32205A8 -:10A10000693CF0A7317F8A74DB287D35EF1F0BB0E7 -:10A11000BDEFA818FF5C7D78EA59F44F7D2D9F9D17 -:10A12000233A36B459393F762E296C1983F35ED819 -:10A130002D8502EAB0DDF6B9C43E6A5DE8310BCD8B -:10A14000BBEEB9E5D9040FFBF69DB4907F5CD7FA5E -:10A1500058B9FEBC5884FB20DBC5FA9D1D9322F341 -:10A1600049F721FC83C8F881F40508F78290E309D8 -:10A170005D3EABDA273612BBD0AFED7D5A62BFE64B -:10A180007493DF3BB8EBDFFF95E6DDFF2F9398FF7D -:10A19000C557C67FF005184FD4E8F3C0F95316DA57 -:10A1A0001FD6B49ACFC53B17FABEDB77957BC6F0B6 -:10A1B000FE3616576FB18038B79900C1E7291E38AF -:10A1C000062CAB919E1F5107A447710E58D660DD37 -:10A1D00046764671C2E308C6DB17D7B9159E0FF75E -:10A1E000081BE39D57D6EAEDA56A8F85F270359E70 -:10A1F0005E0BE9754DF813715EDFF651B91667BF56 -:10A200005CED167ED3D003C3DEEBD2A7B05D98879A -:10A21000E260C8C6765FB86680E253DD7ED40EDAAF -:10A2200017B8FC034477606F824AEB2BDDF7C9CC8B -:10A230009E8879FEA4DB8751AF79F9A3A966E2E78E -:10A240009E8FA62A49C3CFFB321CEBE2E555AADD5F -:10A25000224E6F4EF69D8FB683046F18E7AD69B737 -:10A26000F3F907DAC1968EE2483BB875DD0ED2F3FA -:10A2700076D98B1601356DCBFD0DDC3FC94BE291D4 -:10A28000DB1606480F65A78FF513FE8AF3CDD4CFF2 -:10A290007D2652AEDB7F1BE991E2084F8ACC6BD45E -:10A2A000987A7ED121915CB76B269AAF08D86FC996 -:10A2B0000E5F0FEF9F8A3354DAC71E9E510EC4A75C -:10A2C0009F1E90385F6B4EF56FCD22F91E95B9BF7A -:10A2D000E5F00B013A97EE9B06C5449FB1DE9F4E19 -:10A2E0000B838CE36C2E042F4DBB79FF2D1ED2DF28 -:10A2F0009FA61F617C61F78680FC4A23E206CAE7BD -:10A30000D80B42611A2721D7572CE33C796E27F3EB -:10A31000CB62F57B291F944D755C874DF1AD23FA17 -:10A320006CEE44B19F1E7B6579BA3EB27F85CE1B31 -:10A33000FD9C2FE9330B3DEDBB0A185FF31D9D39E2 -:10A34000D4A409BEC1762E6BDB3AA646C6DB44F028 -:10A35000DBE879DFFE5BBC44BF3951D7F78C44B6EC -:10A360008BD8F9FF99F499E46E5AB3358BF84C7C8D -:10A370005347F67B5AEF67F003147F2ED92B92AA2E -:10A38000C5CB0F8D77973C4E72DD9CEACB7515F0EF -:10A39000F1AC00C39EC4B87687FDFF5764FF1FE988 -:10A3A000FCDCA2F86DC4DF4D7ADD6CF1A94EB67FFE -:10A3B0009F4AF30FAD6F74FCF5B5E9F6BA6582FFFD -:10A3C0001BD7B74F5F9F3915F58DC64B06EE674E0D -:10A3D0000E0648FF9A92A078133E3EEC2AF790DDD5 -:10A3E0006D39F4C538B2F7A624AF0728AF7560D62B -:10A3F0002AB2FB2DA36F63FDFFF485BC2239629E58 -:10A40000136925ADE4BF7E69ACCBE2CFA575FC42F4 -:10A41000D723635DE96EDFABEE88BC118C755F916D -:10A42000FE80BE9FF3EAF117F7739CFFEB87442F82 -:10A430009D27EED671B7023ED61B3B7855C6551AFE -:10A440001CA37B1F8D1D26D846CBA6E454C4395DC2 -:10A45000B26C32367D9A0DB7E6746C4CED6FBAEB88 -:10A46000963421BDFB21200B7C169DAF004DD2A45C -:10A47000C83CC56B55F1F314CFF81BC92EFF569E8F -:10A48000624ED8B4DA92F2F7E72BCEBAA3F73D9F2B -:10A49000BA55262A942BF431144E0C8ABC174CA7BB -:10A4A0007D5333F112FF7B06D7CAF62DF5E5DA5C52 -:10A4B000684FEEFBB76D1D8B76972DD64FF546FA9C -:10A4C0007BA7C03D43F98FD7A630EE463F27F3FE6A -:10A4D000DFA9D31223B762C46BC0F78852A3F22757 -:10A4E000E1235F26937EED4A55DF22B90C74C97CC7 -:10A4F0004F2441E9B1B8E2D8D93EC203E8F78BD383 -:10A50000C53EC4D626CE176DAAC67E31C1E99C26AB -:10A5100047D8C579B7C89F571FF9609C0531DC053E -:10A52000D3F1E4021C7FC3DE96644AC3AD3FF3F669 -:10A530004CBA9253A2F81DE9B8FE4FA51D3936C298 -:10A54000A95B8353893FA1F08414F293850A049494 -:10A55000A238F1F1A922DE14D73CC587FF50D83EBE -:10A560007D2DE1E5DAB0582FCD61C6A6BC36E07A84 -:10A570005F5B632A8D57FB6F074693BF7A295DE0C7 -:10A580009A172F4D11EF2BA050FFAC7497AEE741F7 -:10A5900013E50B5FD2F38C7D974CDCCF98BFB06D89 -:10A5A000A1EC443D28086F3FC479CD76AB4AF24D0B -:10A5B000780E043FDA131877D61E5C0C14E7FA5DA8 -:10A5C000E095B07D57E2C06F491F060E58553A77A7 -:10A5D0004D706E87541C7F977E4F2B0F15B2C5317F -:10A5E000FCDC982FA1FDE7941324BDE0F3DF0465A4 -:10A5F0003B5CE388E47712D35DA2EBD5AEC4B089AF -:10A60000CE450626E15E87E91AA613785E83CE3C26 -:10A61000F6FBBB2C03E77EE066BA9CA4077920E832 -:10A6200084F6C92AF9D104A7C6EB4870AADE8034A3 -:10A6300092AEDAA908FCD06E1E25E73577D8AE6B4E -:10A640001387EB36B4855D13403F8FFFD5363A8FC5 -:10A650001FAA9383993DFCFE2DE92F6C6B1ACBF951 -:10A66000BD808CA2B66399944AEB54797DE845B5D8 -:10A67000F422C107BAAF67B789F6A1FEA8E70EAA10 -:10A680003B443FAFD5695F92C5F64287D74378F028 -:10A690007E297CEE5AB4D7DEC77C2905B8AE5ED3DE -:10A6A000A1079AB1DF9F568772E83EE97356FF1AF9 -:10A6B000D2CF573E5CF34821F9DB5D666F25F99DEB -:10A6C0009EC0CF1887BF6856B745D81D8C1DC8E0FF -:10A6D000FB8031F3D49ED9F433C2D7FDFB2595CE50 -:10A6E000BDFBCD03E388EE9AF63F5AE8BE64EDFE6B -:10A6F0008F184F4B19FE1A9A6F765B03DF6B9B0323 -:10A70000DBF95E1BFA43BE9F18F2087F32783AE706 -:10A71000D98608393C912EEC0D06FCE3295EB5EB99 -:10A72000F67A90F6DD58EEEDB875228DBF57CF075B -:10A7300018EF35C0A131C4F74DF01A97C6F3FEA04B -:10A7400052417A96FFAEED4E2DA2FFA3E902BF3D26 -:10A750009A2E70667686BF89E85DDFF1B12599D6BD -:10A760007936348EF6B921454D71C6F12343F61B77 -:10A77000634FB5CA8085FAD79E07F62B28EFA6143B -:10A7800094DF4BEFB64D598DCFF7A24C5228AEE275 -:10A79000FE94E2EF5EB36F0CF56F78E7F3A9E4C7C0 -:10A7A0001E484FE7F57F7E60FD78E21BEA7F492275 -:10A7B000D9D96E60BF66D86901D929BE5F40FA5FFA -:10A7C0004CF53CF6CBBB2CDD4BD82EF79A80EC1227 -:10A7D000F59FED01F5DF49F8AEC089F6C0EF4F6691 -:10A7E0003BDFD56DD21827A35F9FC4F5921BA9BE8E -:10A7F000ABBBCCC9764EF7058AC85EC387789C1080 -:10A80000C024129D04BEA8FC883B99E936FCE5E70C -:10A810006ED0E3869AE2C575D86539CA3E22E2A4B5 -:10A82000A81B71F4C933DB9E407B81EED428DC0F7A -:10A83000EF0BBFFF5D3D56D5BD3E775933AEB3EE4E -:10A8400084CCED07F57D5E58D793437A7E86E28609 -:10A850003A5DDCEFA5E733B04EF75D676A1B4B0945 -:10A8600063CDAED87E98CAB9BE502941C8F9ABBAFB -:10A870000F9B8599E793FEB51EBA2E9FEECDF59FEF -:10A88000B1420292D8FAE5C06F5FC4B53D7010F9CD -:10A890001F274EE17258FF106F8D01CFC8F67EC999 -:10A8A000F023BD4B481FFB5AE5E13A1252838A4D13 -:10A8B000F577D23FDD16C0BA3F437B9F54E2C7997C -:10A8C000FEF7493FFB4F7E994166B9F7B4D8C7B749 -:10A8D0005AB47CD29FD609B8B58DA3A7AFA58B3C3F -:10A8E0004FB115E29E4B7EA5C7C19C003C22F1FEF4 -:10A8F0005C760651EE175A65CD82F8E73C0456CED9 -:10A90000237FA3E76FEF01FDA7E11F94CFBD7AF589 -:10A910001EC22B18B7EE7D62C4B9BF89F4696DBB46 -:10A9200004FF846B5FF74CFC7B09465EEBBEB61DF3 -:10A9300047C6A03CAB9E8BEEB761E89E7B88F7BD17 -:10A940001B9AA3EF1B7C95AEE396893091700BEABE -:10A9500013FB07B3029D56D4DF5732FD9F105E7E76 -:10A96000C924F8847E95EDF213B71E674A843F1A16 -:10A97000B8007C8F286F67E830DDD799DB9CE5A5B0 -:10A9800039E62AA27D6E5B16C719508232DD3798F0 -:10A99000ADF9CB195F07B4D3742F649DEE27C1893D -:10A9A0007F28BFA3AF6B9D8EE7EE0B46D33D07829A -:10A9B0008D34CFDA9DE2FED1FA9DF1BF13A8D5C741 -:10A9C000D9F0D4C923940EAC0E45F7ABD5F953DBBF -:10A9D00016FDBC057812189F117DCFFC4AEF43FC91 -:10A9E000C92CF0C5DBFA3846FBB519C27FD62079F1 -:10A9F00024DF0D4139487AB34E0A240B7C0B8ED5E7 -:10AA000048F75D86BEE8F765EFD6F97397AE2FBCC1 -:10AA10002E7CBFFA192948E78077FF249AFE7B42F3 -:10AA2000ABCB491F62F56A5DB399F16D156CB4103B -:10AA3000BE8DD5ABAA217DD96EA13816AB4F357E20 -:10AA4000E932740B5CFE7F4BF77A7398F34CEBFFA3 -:10AA5000A7E4A53CD4BDADDFB1505E74A47D08F978 -:10AA600056197AA2AFEBEF5DCFED867CA7C01496A6 -:10AA70006F45DA15EE83A2F1F46ECB509E92F37C13 -:10AA8000839D13383F6EE851EC38E53A2E5FFC1495 -:10AA90007079A1ADD44EF8A2FFB8C92BA99C7F4C08 -:10AAA0002E443E4C3F2003E18DFEF6898F0790FE39 -:10AAB000A213C53752BE7CFA098C3FD8BEA7B3F8A3 -:10AAC00057E45F11E1A4917D2FECCA4EFBBD83C713 -:10AAD000E1F8DD7FBCE8F14AF2C3C7CB8A695C09C3 -:10AAE000DBE97E78911E871A8E17D97B22E2D1FD91 -:10AAF0001922DFBEC5F3FB47695FB078B7D94BF9C0 -:10AB00008EC566FFA604A4AFE805C9DB80B31DE9C6 -:10AB10003EF4248D8BF6A452BE66F1EEEF1DA2F634 -:10AB2000DA5D12D3DFDFBE287F17C5C7A0ECA5B85A -:10AB3000D7DF7E57C1BD84730EDC537057C47C478A -:10AB400052855F597C9599E371EF68FB2F2B29CFD4 -:10AB5000A9ED60FFD0FBEA1E0B7F57B04B020FAE92 -:10AB6000F388E7F0AF890FBDFB4E5A08E497B69E15 -:10AB7000B4F4C4F1CF467901B77161CEBF6EB7F0BE -:10AB80003DCABD7FB0D07A6B9EFB88F369556D12CC -:10AB9000FBA7AA67E4A04A799E03AF58483F6B9A87 -:10ABA00025C8CC8A6C37733BF951AAFFB159F865B7 -:10ABB00043EFD7E87A6EE8BD61076B74FF75D7D6AF -:10ABC000683DBF17B42DA3F1FD7B9A57F33DA07BE1 -:10ABD000B6C7F75F861F5C4BFB528C2B6B9F8AEED0 -:10ABE00077DF907E07D8BFC7FAC95732F4F3D83C55 -:10ABF000C823FD1E0CAF19AFA03D7D7EB26A3CC4D8 -:10AC0000C93B1ED7F180118F07C3268E67B1FDFAAD -:10AC1000DA2E5A288ED676FE99F16B79FB672C874F -:10AC2000CAF60EBEAF7A3DF837101FAF6FB73B09BB -:10AC30004757F608BB5FD26E0D06256A0F35917C2B -:10AC4000FB0F8AEF3B02AF4A8CA340F77F6B757E08 -:10AC5000AED5F9B716F76763E8DE8ABEFFBE2F7779 -:10AC6000C711BAE251A33FDFD0753899F8B8048410 -:10AC70007F5A1212FEC99087115F46C6D1816F9329 -:10AC80003CD7B75BF9BEF852DD3F2D6D16DF93C59B -:10AC9000FA8BFE517691FFDD2BE88D8DA735ADD176 -:10ACA000FDBB32D2D9DF0FEA78F813C3DFE8F2A890 -:10ACB0001C003BE5E797A8B237C86F752B347FE7D8 -:10ACC0005489CF633BD58929F1EE4B19E59B3ACEE8 -:10ACD00037EACB284F86FD43CEED8EC87DFC8D999B -:10ACE00002AF54CD910324CF887DCFB2A2ACB8FB84 -:10ACF0001EC844BADF187BD74FA645EE7BB41D397A -:10AD0000A4673FF23C5E49F78C6A9B857FE89B8D88 -:10AD1000E3A6108E07C6C5B5CDD620ED4F6A514FBC -:10AD2000F87B30D20FB2BF766911E907EE1B1C9990 -:10AD300048CF723AAAC4F52F6FC3388EC32F2FFBAA -:10AD40008CF5AA2B5BAC1BF996196F1F61EC1F6A7F -:10AD50002E099C6A3CAF517A781F51D32EEE49B729 -:10AD60001EFA625C16D2DB7FE03FC6ADC67241A61A -:10AD700088BFAD25A18FE9BECFE7BB6C71F1E8902C -:10AD8000BF979AD80E6ACC3D198C57F6232E9C8516 -:10AD90007EF3ED4F79DFD17A28E14ECAC7F5ADF1E8 -:10ADA0008F777E839C1A6013E3DA4DD0C425E19E31 -:10ADB000481CB8D629EE0FDDABC749AA3F8C7A7D77 -:10ADC0002FF65D5014CFEE035BE64923EDDDF01B5B -:10ADD000D5BABEAF2FD8B1858EE063F151B56E47BD -:10ADE00088FC392EC6E2A21B33A3F5B4E1ED44C6BC -:10ADF000B9FD5DB29372C4C8D75F8C26DC87F87E3C -:10AE0000429C3CEBA7BA5EF6EAE7BE0DB365E69B53 -:10AE1000698E280D1C85FC637DE93FE908521CCB37 -:10AE20003FF8CA0492FFFA9DD1E745243F3FDFDF98 -:10AE30000AB2FCAA43763E4332DA5F3AF8CA14D229 -:10AE4000B386B7BFCC1172F922C7E2BE3C7D46295A -:10AE50004962FF6B92C4FE77AFD2934CFBAEDAFD32 -:10AE6000B22FF2FEBC21E7BB75FD0145ECF3D765BF -:10AE7000AA5C6F68177A613A204A9C7FA5C8F3984C -:10AE800079FE11ED25A82FDF10B780E842D9D79AB7 -:10AE90000758EF6A4F9A989EDA938319D911EF05F4 -:10AEA00068DC4CF27B0D1B80FD881DC8BF2EA5EF12 -:10AEB0000FB1BEF4FD04C65947263C5229CEAD64FD -:10AEC00020BFF5C0DB559323FDFF053DEE03F1C127 -:10AED0004328E70931BFCE874DB042CF13083DAEBE -:10AEE000D2712CEEAF9AC88E63F757578A931B0E18 -:10AEF0005881F2C7B51F58F93ED0E707D6F2FE1DBC -:10AF00002EF927939F01BFFF6A2A1F38B876323D7A -:10AF1000FFFCE07D5773DE53DA1495AF08107D1EF9 -:10AF2000C2517F79F776C2975D0AE390A2AED3EF64 -:10AF3000D2F9EA9E56337F9B59BD77C6E38124C27E -:10AF40004F454BE9BB9D3D9D0AEB1FE22A0347D9C4 -:10AF500019479D28661C85E3F8825C161FABA47117 -:10AF60004F9414533709DBC99F4D271CE518C6556C -:10AF7000063DFF9C29F8D9DF91C0F9130926083D49 -:10AF800083EC28BA37B4BECE3864439B1CF5BD862B -:10AF9000F1DEEE4C71AEB0D7D0B390A4B11EED1679 -:10AFA000E586B63D19B48EF5E610EB4943B359B4C6 -:10AFB000EF1225D0F9CD0CFED83840FC39468F5021 -:10AFC0002E4B2CC1B184DB770F9D07EAF73982E263 -:10AFD0005E5D63E744FE6E68B0738F3B5EFC394E86 -:10AFE000E73348DAD12CB1CF896DAFF3887CC6D175 -:10AFF00033C22F1E5DE89F1CCF3F06A044ECFB250B -:10B000005D7EADE68A78E7861B3D22DFB4736CE097 -:10B0100028E971EFEE043E37EC7589FC6C694B97BB -:10B0200042DF9FAC6F9566503C5A9FFB1E7F9F820C -:10B03000F562F683E1FD7C6E5ADDBCBB5C8B43C7D9 -:10B04000B51E111F97E8DF018FD057BDFD1478D3CF -:10B05000F57DDA23745E73AAD2EC14DF9989EF4A86 -:10B060006FD0FDF98DD79B19379D02D52CCE3FC4EB -:10B0700039C532DD2FDFA0FBF911DF3B3F039BE930 -:10B080009C22F67B67C3AFDFAC8FBF02341E37F65E -:10B09000BBF59B753C78B32FFAF9A54C1D07E6402C -:10B0A0000EF9F310C617BE1F9197C0717A69E1A41B -:10B0B000B83883BE0357F5EFC0A934E4DE90F71E1D -:10B0C000C7BFA31D677ECDDF139C49800971CEC524 -:10B0D00086E39FE13F6E12F2D6CF2DAA9D824643B2 -:10B0E000EE17700716991F33E43E46E7FFFFF13D68 -:10B0F000A05C5022F325CFCAFE311E3A9FB0F53234 -:10B10000FEC615701CC4758DD3D735CE1A11DF2E2F -:10B110008C5A1D577F87D7971A1071C4CD65479EEB -:10B120009571627548E2EFFBAAC3625F5B5D26F62C -:10B13000B539AD02A7AEBC490A6A12BBC3D3449F5E -:10B14000A13FCB6C020F187A32C42F5D7FA89DF00F -:10B15000C10D3A3E88D5A3C9D05D4EF9E65B34C92E -:10B160004BF72A477C3FBF6ADAEBE4EE2FA73FA8F4 -:10B170006FFCEF22C4EAD1F73DFE120FE5D3BA0708 -:10B180005716E2B847F3FE388EF4A6E63276F32D72 -:10B190008F88133B1D81A37CDFA4453FEF6FC96BF4 -:10B1A000EB217E7402E3C75E57F7963A81ABF9BC98 -:10B1B000BF3A9CC0DF4356B7DBF9BBB0EAD686C4C2 -:10B1C00029E47FDB65AF1DEB95AD27CB889F95C547 -:10B1D000E23E4AAD5DDC8BB3B9FDB7107DD77B3B5A -:10B1E000A2CFF92D3DBFA8FB063D8FF56B1B09A330 -:10B1F000A5FFF7F99B8D3A5FEABA2E664CC1A9FE0E -:10B2000090E6AF267DEC7FFD450B1DD7D54E79A589 -:10B210009CAE886DF4A8DCEFFAE68E264AF31AF4A9 -:10B2200077643AF9F95173702CE3D2822BBB0FD3B8 -:10B23000B0FF8DA914A7FA3ABAA65A22F4BBB70EEA -:10B24000FD731CF9358049B75B854B495AA1E3254D -:10B2500061C7B5070E67503EA297ECB780CA7792D8 -:10B26000B3B1ACDE7D2A7912E196BDA21CC219ED04 -:10B2700032F703A527E7E6A448FA36337D17426282 -:10B280001C809E9C1B0B23DB1BFF5FDBFFD3A427D3 -:10B29000D5B69E28FB37F884BB7CFE3E3770D0CAFB -:10B2A000F708E8BCC61521C757747F340B374B64C9 -:10B2B000A773E87C7A22413B05EEA0BA026125958E -:10B2C000CE8BC3B2B87F3796FDF74C7DFE594AB896 -:10B2D00083EEE9CED1CF37E74237F75B00035C6AF4 -:10B2E000E0E4EF8B4BC0CBE56C5B7829C1F1825079 -:10B2F00088BF9F096728AE7336FD3BE638F21EE62D -:10B300009B02E70C7EC8740E26EE1BC5AEA75BD76A -:10B31000C7599AF03B041DE87EEE6C08F1B9FB3585 -:10B32000D0A39FBFC75FC73CDCF7D1B9DB35683B13 -:10B3300089CC8F20F79F4FEB91E3ADA767298B193D -:10B34000CA9C449F14CE307D6DBFF275F4D36D4D11 -:10B35000CA57DF35D0F783E2E1734B6FFB1BEFD3A6 -:10B360007D6249D3F8BEB197BEC7A67D4E58E91D90 -:10B37000F2631300FEDDB3E637646FC6F71AE00729 -:10B38000BEE711FBBD062DF77CC6F03D35E3FEEDB3 -:10B39000CEE00A95EE6FAC72DBF8DFAD29B28D9B83 -:10B3A0004E79CA87D2FCBF21BDFA406A9EC4832869 -:10B3B000C1198C6375BDB283369BD62F69C6F7223F -:10B3C000C0FA32F4EF0164007FB763B78AEF691EF9 -:10B3D000413DB4A5B2F6AB740F1A1E2E55092F6F5E -:10B3E00071D9BCF45DAE95E8B50FD3DB6813F72FC8 -:10B3F0008CFB6BB17C6CB419794AAF8D7176CC77CC -:10B400003E77DAFCFF9BE8BF3FA924937060FECB38 -:10B41000F33D7C3F29C15877898DEBC3F71A193763 -:10B4200036D17D6AA4AB311DF81EE2E1A49C14BAAA -:10B430001FD5D825EE5337A607D87F9BFD12FBF307 -:10B44000C6CED24E8A07830E0BDFAB6E74F934AAD8 -:10B4500007D22144FE9FF83EDFE0BB6998EF21FD53 -:10B460005E5091EDD75751DE7F9A1B4AE9BD696165 -:10B470006D12F1C0F81E06E5E019954ECFA3EF7BE3 -:10B4800081E2E4FB17861C503158999DBA7C0DB9B6 -:10B49000388DEFF83525EA3B7E435E8F240AB99854 -:10B4A000E926CC447E57A57163E561F0FDBF008FAE -:10B4B00040AEB13049000000000000000000000074 -:10B4C0001F8B08000000000000FF3B24C3C0F0A356 -:10B4D0001E81EF4A313030F1A28AD112EFE364606D -:10B4E00010E062603005E2FB3C0C0C3380F44C2031 -:10B4F00016E566601003E21A20DE0DC47B80F819A1 -:10B5000050FC3910EF00E21B3C10FDBE4C0C0CFE51 -:10B51000401C08C4C140FC958181E11B03F1F67316 -:10B520000A33304C1547F02F03D99F24E9E7FFC1B8 -:10B5300086430CE96BDF71A07DF3AC107C46207B69 -:10B54000BE15AA9A0556F8CD588826BF088DBF1893 -:10B550008FFE720354FE5A4D34B3B581E90949CDCB -:10B560003A4DFC6E41C7AA40FFA9013100ADF15F21 -:10B57000CA68030000000000000000000000000096 -:10B580001F8B08000000000000FFE57D097894D5BE -:10B59000D5F07DE75D66269999BC816CAC4ED844A8 -:10B5A0000B7442421A10DB618B6811834B051798AC -:10B5B00008644F2620F5C7DAEFCF40005151438B86 -:10B5C000355AB40304051B34D88041020EE0822DA5 -:10B5D000D5D86A5DDAD2A0C81A93801BFE5DFCCE76 -:10B5E00039F7BEC9FB4E2682B5FFFFF5FBFEF8F822 -:10B5F0005CEE7BF7B3DD73CE3DF78EE218C7948B1C -:10B6000018FB12FFBEC798DDC6181BD79D32562304 -:10B61000D24A2DCFCD58D003FFCC62ACDCAD85979C -:10B62000A7333665871AF95E12E43748613BE46D4B -:10B630007B9D54DEBE9EE7236ECDCFA0FCA33AC80F -:10B640004BD0DEDEF2C06550DEB943661BB1DB9144 -:10B65000713696C2D83107E37F5990CF66ACC0C926 -:10B66000B3E51BF6CDC5F6454D76E684FECA7715E3 -:10B67000CEBC0CF28507558655CA372FD3FA43BE88 -:10B68000382C3560BE63329F5F68A71CDE0CF53B2B -:10B690003C2D2937B8183B55E5605E8DB16A774B74 -:10B6A000CAF5A3182B096FCFC57625F5920F973AE7 -:10B6B00065C7E697FBE1BAB64A3EBB97B1D22DF11A -:10B6C000CC3B92CFE14BF8FF58A31CF91E942F8678 -:10B6D0007532E8B790D5E43219C75FAB79DDDDF09C -:10B6E0003B55A5D33846BE7C2B8C03ED2A9E967C19 -:10B6F000B8C40A1B0B34C0F8EDBB9CB337B9707DDE -:10B70000CBB4116E5CD7DD1AD62B0CE7EF747A71CF -:10B710007E1BB45C282F59BF412B18D5DD5FE996FD -:10B72000BED679D50E4D0D98CAA3D353558C794703 -:10B7300074E74B18F33740BF4C096BB346777FFF74 -:10B74000802532968CFDCBCCEBE8EE1F2049DF4301 -:10B750006FC13F015EA13D6E82AB81B7C53AFCDB94 -:10B76000DB8DB7B3BAC0A3D2996DEEDF481F403C62 -:10B77000C07C6A104E90AE11F3F34C649314E8DF72 -:10B78000E367BAC47A5F8F91D6A82C9FC1580B4249 -:10B79000A3FDCA78C86B6C11F331F69315D9FEA9D5 -:10B7A00090BF9F05E6E2BC57488122C413630D6930 -:10B7B00048BFAB24361BD7FF039C3494AFEA07F491 -:10B7C0000970AF9996BD4996C4DC93305FF0C4BD53 -:10B7D000E9D44F21F5A3423F43CFDF8F9E9B63E91E -:10B7E00047CF2D32FAA9A47E9C17D64F4DEE04EB1D -:10B7F0007C724B8C7EEEA47EDC17B62EFD8A89D639 -:10B80000F95C5146FD244EF5B100D4970D7A602DB8 -:10B810007E19CA5DF58963EF6566BA98BC12F9DFD7 -:10B820000D5C62A68B849C380B1D26FAFB58F2D067 -:10B83000937EEC5B220F834412351A5FEBAF915C71 -:10B8400098D4DF41F93BFABB482EDC312170B10EB0 -:10B85000F3C0B1593FC86B816FEB31E81AE629B1EB -:10B86000344CBD364CA3CBEF56391C260FF8DB8881 -:10B8700023D03E68EB1C9108F9F5D2A45F205C361A -:10B88000331BC1274E6695582FCECE483EDD9D9E78 -:10B89000BD296482D3EA41807FA9BBDFD56A200D30 -:10B8A000E96B2BBB2184F4B66A10ACA73F634F85CC -:10B8B000AE8F8414683FA8200DE169D780BFCDE327 -:10B8C0006B30FE281AFF191C77078E3FAEE7F8F69B -:10B8D000213996F11D838B2CE33B34181FE87D172B -:10B8E000BB558C0FF09BC0D8F3A15B687CFBE022BA -:10B8F0001AFF6E8D1559C68FEB1AFF051CF7A5DED2 -:10B90000D63F648275FD834BACEBD7F8FA5F650BCD -:10B91000C5F871B4FE5F8716F0F50F2EE1EBB7F3B3 -:10B920007EBBC6F774C1FF751CF7ADDED63F74A2AF -:10B9300075FD179559D76FE7E3BFCBCAC5F82E1A27 -:10B94000FFBD50195FFF456534BE660FF8908EB499 -:10B9500001719561189F0D0486482519E5A7746447 -:10B960001FC6A0FD3A3684E070471CA7BBCFE2801B -:10B97000DE5CDDF28E8581A3409E55089A2FAD9F37 -:10B98000A4A19CA572907B0BC5541734C9B4DFB039 -:10B9900075F6F070986F7B931CC2FC827597876573 -:10B9A000DAEFD8BC3C6CA7B0087EFFF0A1D11BCD6C -:10B9B000EB8A4E17D6A8C75A2D7CC4E7139ACC46FB -:10B9C00056C2FCA621118CEBCE1F0339CA407EBEA5 -:10B9D0000F7214D3E32A8C07DF8F829C659A996FCC -:10B9E00096F17D3CC4DE1C99827282FF1D5338BCE7 -:10B9F0008F2D91C208FFCFD62ED2503E2DAC890795 -:10BA0000A077CF2328F0D4B9CB1EDE28113CBD0887 -:10BA10009F1B891519FB33A0B51F80B6B0B6AFA523 -:10BA2000DD2D2CBC320DEACF5F933F4887F5DF3C1C -:10BA3000DB3E56C6FD83F907D8888FD9005B0E63BD -:10BA4000B31BD7AA032073E36CF5FD5653FB3901F2 -:10BA50006BFEE6226BBE5D0DAB36D4378A25B60190 -:10BA6000FABDB5D25A6E8C9328F5E17815E3FD2026 -:10BA700085CFF7564CC7E2679DF03A57E76D8DF9D1 -:10BA800004EF525984F6CBD66446F84FA67A019D4E -:10BA9000AF3B7ABE7355873F0FE633F74E99E019F7 -:10BAA0003DFFD6BDF17EDB18486B3F569104A3D70E -:10BAB000133DFF794BA3D7A3931E961F8AFECEE9B1 -:10BAC000249A9E824D93FA1E35D52B6FB8B2EF5152 -:10BAD000137D956E9965C91787E758EA17D6E65B17 -:10BAE000CA17D6145BCAE7AF5E64C9E787EEB4D461 -:10BAF0009FB77499A5FCD6CA7B2CE53717ADB5E482 -:10BB0000E7041EB1D4BF71F6064BB96DEF25D720FF -:10BB10001F55BF2533DC373E751D7B00F5C14F5DDA -:10BB20008A0FF171A22A8DF8E0549597D2F6A64CAF -:10BB30004780CBC1025471162E6B08AD9E88729956 -:10BB400091FC2C5EB633141A08DAADE425F8C9B5B9 -:10BB50001A8B00094BAC4F171D77CAA6F2D6F39487 -:10BB6000D702A367F62C975B637F0F6ECCBF08E507 -:10BB70004E6FF200FE06E03ED721F6F7E8F232897A -:10BB8000E599BF33B69CF8FC9C90B3651A9707659E -:10BB9000CFF69BCC3C988F8CA8FCAAF11A00A82861 -:10BBA00027513B4F467A002EB0D0CB500B7FB7EDDC -:10BBB00093695E152813C6A3C8C95B23A19C891C81 -:10BBC000187CDD689C87FF7E09F9AE2999F6F5B6E9 -:10BBD000AAE97D8F2A889F3C4A4F54CDA6F4585538 -:10BBE00080D2A3554594BE5F5549696BD5524A0F23 -:10BBF000578528FD53D56A4ADFABAAA1F49DAA5AFE -:10BC00004AFF5015A6B4BDCA4FA9C10F5DF237490E -:10BC1000E8ABC2AE809D87F267C55A5640DD16E29A -:10BC2000735F1AF2F959D76723501F3FFB8E9DA10E -:10BC3000BEDF1BBCA2E9AD773CFA495F290803FED1 -:10BC4000337B963BE3389E9C36369D813CBA67F841 -:10BC500013BEDB46515E4192810DC937CB1DA3DF78 -:10BC6000618CF0753E3C317FE7986B011FC71EFD6C -:10BC70006B36F67B4EEC7F710764DA875964930F5D -:10BC8000F165821BED6B9D3B84BC3F0FFC3EEA825D -:10BC90005FCB6006E9044927FA3BDB68670AC2B15B -:10BCA000393E0CC4CFCE1EDCE4417E5C9C66D38F53 -:10BCB000C68083919637A4EB2EF3FED364CD9FAD5F -:10BCC00091A637903CF6265C3F1AE94AD78F0E437F -:10BCD000FCA7516AF4B3384DD38F02BF9EDA3234D9 -:10BCE00081EFDF61BE0FD62712BD825D48F5FFD51B -:10BCF000F3E9AD1F633E8C35B20F1C280FA06CE832 -:10BD0000F9ED9D1E78573ED1F2105FCDEA67A82F5E -:10BD1000C4C1FF5F0EC17E15CA1BFD061BE490FD6A -:10BD2000DBF8BDDE321EB4F31A3637B6EB9D6E1566 -:10BD300076CCA02B90571A1ACB64273A75EBBE929B -:10BD400068C9079BFAE9967D06FF01FC0F82524104 -:10BD5000BA291354D4A1B8564B30BF23283F012F22 -:10BD60004189D72B77B46A012F91630BEA19B7E5A4 -:10BD70001874E7BDF18F20EF4FFE4665F762F9DFDB -:10BD8000605650AE1AC520F76C909F2F72B735964B -:10BD9000CE40B977D2C6F7F9052CCF83464F11AB09 -:10BDA000C9463DE723669B8EF4FF11FB9D27D364B4 -:10BDB0006FF86C1AAD73FE6AEB3E0BFA99255F586B -:10BDC0006BCD17B06B5390DE0BD6A92C2C215F5A8C -:10BDD000CBBD369DFA2D6495ABC8DE417B05C6BD53 -:10BDE0004D67CA00985FF9738F65E743FE3B36AE37 -:10BDF000A71BF67B711F3EFF92A4B0E687F20F1AD5 -:10BE0000337F7019C3F6E15528A7426EE6DBCC7A82 -:10BE1000E2EFEBCE3F7ABEC67ED2C38F20E6216F23 -:10BE200091FCE11876DA349B24F4AD10A537E0BA22 -:10BE30004D7A6BBE8083912F8FCADF1995FFA7E9DA -:10BE40002D8959E8ED8814C8B72573FA427D41520F -:10BE50003AB5C037E93FAD47FFE5FFD2FE0742FFE5 -:10BE6000D996FEEFFC97F63FACC7FC57C6EABFFC7D -:10BE7000B96D3B43206F4A9E79C8C3601F3AA9D46D -:10BE8000A4F800EF659B577A900E4E28210FD2F34D -:10BE9000C9B03C3D163DEC467A203FA2DF25A15DAE -:10BEA00085FF84FE4F3D75DF4CDC673EDBACEA640A -:10BEB0002F6DB147ECC0AF158DC533D818CA1FE13F -:10BEC000F9BBCFC8986FB2D267C9930FA5A0FF0D79 -:10BED0002845D81311D2972AEA3ECCC57D28C83A06 -:10BEE00089CFA2DBE1F8E7FA907CCCD7127A96C32F -:10BEF0003C49CF0F0AB8041BEF3B23A3EF93B57265 -:10BF00003F6854FD22A1FFD4DBDC49C7C07462DF67 -:10BF100061DF417969C08385B9FE53BDF5E13147E1 -:10BF2000603E6D75BFF1482638197C76B661FE2FEC -:10BF30009EF7F62E8FDB859DD7DD2E4CEDBC4D4256 -:10BF40006F6BE669991AF1A05E5CB641F585E07306 -:10BF5000D9B64D4F3C8A76EABB76DF70E8BF74DB1A -:10BF60004B7F9800F9D2ED6AD20CBE0C9794D28D1B -:10BF70009720FCBF746C371E4A7EF592E61DCDBF3C -:10BF8000FFB84F373E4AB7EFD3D8E89EF098D2B00B -:10BF90004F6B75C5C04BC3915CD4AFAAB77EAEA141 -:10BFA0003D7972AFC452D363C073C34BA427209CA6 -:10BFB000088F024F5D788BAA1F04BCA03C37F01499 -:10BFC0005DFE80903FD89F7714D1F3D3CFA35FF964 -:10BFD0003DBB0FD75FF4F4ED1E5CC771A592D3F59E -:10BFE000632B53FC306E911A4AD129E5DF8B1EFF7B -:10BFF00021D15BE11B3F4CE1F6A0BF9F8DF6A6501F -:10C000003F5CDFC2F537D0FA0A5880E8AEE8313934 -:10C010002F0CE9A70A9BBE3D065F64C89C2F8E6F5C -:10C0200004850BD6771CED12F4B3FE4E0E6F267FFF -:10C03000C82286FCFF43C33FCE1653FE5307C79367 -:10C0400043B609BE026DCF4CAF7577B7207E4E0D5B -:10C05000F2A7A21F2DC894908087F425F42BBF313E -:10C060002D95E38779956CD10EF48029F81DEBB7F7 -:10C07000A87EE7184B3BF6657AF7F84BC4F830EF2B -:10C0800038DCBF8FA7B0A28618EBBB5536F81EF67A -:10C0900071137D99F89BF37BDD3D9CBF0D7E0FCF27 -:10C0A0009A8EE59FBCC9F907DBE1FE08F38AA4522A -:10C0B000F9BEEB259207761689C5D775AAE06B6B9A -:10C0C000B94127306F454A30D10BF6DF87E04FFE8C -:10C0D000B38275D0CE242F83389EA7677F06DF16E4 -:10C0E0000AFE1F255BF99FADE77CDFBB7E15A27DB5 -:10C0F000AE4C0D3FF128F22BF067C88BFCAAE6E1AD -:10C10000BA4FD71FF8C34DC0A7A71B0C3EB5CACF67 -:10C11000683E2D7A76B384F419CDA7A78B401B898E -:10C12000C5A7F03D269F16B5FE3F959F06FCAE8F36 -:10C13000829F210F7B8363B43C3C63F3123CA3E5F5 -:10C1400021FCBDC9B27BD29F417706BD95FCB2FCF4 -:10C1500022F217187469D05D175D1A74D7C3FF6295 -:10C16000815F74F960A405A093BC5D2AD95565CDA3 -:10C17000FC3C0CDABD3C208BE0E4A76D8CD5BC3CCC -:10C1800020C99C0F47E51BA2EAFBA3F27951F503F6 -:10C1900051F94A4BFDB2A6031A23FC472CF5EC4B90 -:10C1A0001F651FC4B0878CFD26D878460B215D0C17 -:10C1B000ECD450DEA9CB410545FFE01E99ECC50E3D -:10C1C00080F12A18A7A33E3D1C02B9B1D2C9EDF0F7 -:10C1D0000EBDD3D307D295893CDF99ACAD42B96788 -:10C1E0007CEF74723F47475EA727D1E4A738D22C73 -:10C1F00093DC6E0DB3E9B1FC20B0A310DE5B596F88 -:10C20000E5DCFF394D760D5E8AF6688DEC431377D9 -:10C21000C1B21B3DE82AE9681E7ACD6CF8BEF05524 -:10C22000998E553AE23C63705E2CE457FA99EC899A -:10C23000132CF4B389E8CF6CE676C5823551FA0841 -:10C240005B43F454E05AA2A13C053BE07DAB3F9731 -:10C25000F34589E8AF68BDB5DC688F275A68DF957C -:10C26000D459CB03C23EDA65F04906CB2039838628 -:10C270000FDAE7422E4F93475D331BF0D1715066C2 -:10C28000789E79B659267C9CADE7E7972C944CFCB8 -:10C2900056C13A491E1A706A437ED27A97576D3B4F -:10C2A000FE9C7D17D2CDCE3F8EF939A46D3BDF1DAC -:10C2B000B11BF3CFBD3DF88FAC67FD297B9DE43703 -:10C2C000EED8EB267AEFD8F3DBC177617E979DFC41 -:10C2D000751D7B3F1F83F4D7B1DC5E84F2AE631023 -:10C2E000B787AAF77C3EA695F6D71584B7A3B2C642 -:10C2F000F5A3E6BF1E9692308555A1DEB0379EF8B5 -:10C3000029F8BC93FC0B1D7B3ECF0EB8FE75EBA944 -:10C3100010E7391D6E36FB599C5F22F78307778F34 -:10C32000DFB40CCFA31BF769F3A17CCA0B7F1F837B -:10C3300072B4E359AE0FB5ABAD8FE3794587FCE13D -:10C340003215E0DC8E4CD59FB1FB94119343A36270 -:10C35000C1E5EFE437B95078680AB74FFFFDE12136 -:10C36000F9B9BC73871D12AEFB8BC37F44B9B0D73C -:10C370004E7469ACF774C332D257CEB7EEE1CA7FC0 -:10C38000173AB8D0754B910B59F7D47F737CFF5A8D -:10C39000F6D2FCA2F9A0279DEFB983F2DBDC3E9A2E -:10C3A000EF05D2FB82FF69787F16F0EE39FFBAAB5A -:10C3B000FFCDD7DD3BDE5F9D2BF0AEE3797FF085CF -:10C3C000BFD3FCBEAE9CDBF4DF94EE0DBDFE159B2F -:10C3D000F7CD0CA83F9DD5B850B1B8B27CFFAB19D2 -:10C3E00050FACAC0038938DFC951E73746FAA6C2F6 -:10C3F000EDA6C9928DEC419628097B90DB51038410 -:10C40000FE30604901E9210306DECFF506C5BB0E0B -:10C41000CF1F5F193CDF47B1146CEC3B01CCEB97AD -:10C420008BBCD59EFCB9C4FC78343A60F0F70FA2FF -:10C430005E3B70A04C7A2FA4A4EFBEE899CEBF97C4 -:10C440006916BBE74AAFD50ECA4DB2DA4B53457FEA -:10C45000D3189FFF3497140E031C260FFA6912FAA3 -:10C4600047270F579904F95C165881F6C55497B5BC -:10C47000BF063CC319F7CDE168570D380E599787B1 -:10C48000701C24939FF4BC70C47913DC32C2182F43 -:10C49000C3141F87639F721FF99D85BD4D474D9043 -:10C4A000575CAB5A909F15B497391CC8CE36ECE553 -:10C4B000DEE0CD84FDAD88210DF82B0365BFD3DA16 -:10C4C0001FD9DF065EBE2E3E0C3C7E53BCBC1B85D6 -:10C4D0009781AE450AF2EB74B417FA62FD0C9E1F09 -:10C4E0001852E8DC4DD80B57781729A4F70CCC501C -:10C4F000105F858EA6ABF01CC4E193681E17B7D9F8 -:10C50000687F70644904F791B50AE5DFB0E9E3108C -:10C51000DF332F7BEEF49D0CFDE67E8DC73DE5F10C -:10C52000F38FBF7DF9E5448C1714782C84FFAF4658 -:10C530003FFF7A168903382D545828A10FFABD25DC -:10C54000F6BEC5EF6DCDE3DF7753BAFB395FFDDE95 -:10C55000E4CABF3A7D0EE4D8FB00F35D980EA3E178 -:10C5600015B35DFD9D660EAFE021161EC2E32AE401 -:10C570003CD339E11D82FE9FFBD3B39968D74EEAC5 -:10C580001895C0E5EB30B21782C25E38CBBC093ECD -:10C5900017CAD7A10974FE795076C78A2BDC2AEC1A -:10C5A000ED5F627C09A41D75AC4646FB8D75921F3C -:10C5B0003754E7609B63C4B7E4AB869F4AE00DFE47 -:10C5C000E46C3C8FE1E32F84A60966BCB5CD38A9A5 -:10C5D0008CE98907FC7BDF741EF54DE18BF63DC2CB -:10C5E00077ABB335372F86FCB85DC06FE6FE2FC83A -:10C5F000FF7969F3061BD2EFA57536CBF96AA92A34 -:10C60000ECB1B16C2CCE6BE67EA73B0BF17250F611 -:10C61000613C67B0F98C1688712E180D4FEC1FFD28 -:10C62000E95B559DF86BB7DA301FE1BAFB2307438E -:10C630003B7A9756531A6B9E03EC7C9E0B59C3EDC5 -:10C6400063D2FFFDE03BA9C315998CF6671D137EED -:10C650008F68FA6344C767B7B030EEAF68AFA25CCB -:10C66000385BCF687F0790DC8F7637F0FBF7CC7EA6 -:10C670009C8B9BB6FF12F5828A6649C723860AA562 -:10C6800055433F6DB02951C67D38C36BC4BBEAA387 -:10C69000AF37F1C5565521F81E98B0FB661CF7E37D -:10C6A000368DA19EE27FB1D383FBF8C7CD99C40735 -:10C6B000BDADEB5755ECAAA948372A9787D1F4307E -:10C6C000AA3ECE92BF4C0EF447FE9A696F5DE28B94 -:10C6D00081BFEF6B923817BC40F916FEFF4CBEBD10 -:10C6E00069C8B7809C67E2A3BE5A0FF9961A4BBE81 -:10C6F0002D96BCA908F7C57B86A6225E17BFAA2681 -:10C70000C7926FDBAAF839E733224EB9A311E4DBF5 -:10C71000B74DF2AD11E45B8C7890BF5FA87C0BFF46 -:10C72000D7F0DF36946F31D6AB6B56F936A6F908E1 -:10C73000C9B7318D364B3CAF5D3B9F7C9392AF4781 -:10C74000FDF8A0EA8B8F413FDB843EFE8C884BC412 -:10C750007150CEE56A3A8D7FA172EEE20B9573FFC0 -:10C76000457036E4DCE21D8CE29C7BD22197738B12 -:10C7700077819C93901EB99C5BBC8771BF5C947C55 -:10C780001BD943BE31AA5F11E1ED834DE90FDF02F2 -:10C79000FD8DF5AB3E07D41FDB2DEFC699E55DAEF1 -:10C7A000A610DC7AC8BB831726EF76087907726C6F -:10C7B00008CAD768FAF0355BE3C1778F3F5EFF2B7D -:10C7C000E497DFCA74DEF8868D9F0FBD36FE7816BB -:10C7D000D2D763623E8B84DC6BAF0A51FF535EE4B9 -:10C7E000EB2B77F138F18A46AE1F56D44B612FFC04 -:10C7F0003377C2171ACEBF788FC452213FCBCEEB0E -:10C80000B3278DF3323623C3440F0B724AC9CFBF0F -:10C8100040610EF4E397BA724FA2FE5B9AC3FDFE2D -:10C82000A5E27BF1ABADABD0FF5DFC8844E7A5464C -:10C830007CAB11E7DB236EA27919F977A3E32766B6 -:10C840008AB8A999BF94C21B62C47F946EB1E67F77 -:10C8500022F86F96DC4AF062AFCB31E3388C7A5D18 -:10C86000703A28E05427D37EDA0527809B37BD270E -:10C870009C00D3333252BAE152FC5B586F56EFEB57 -:10C8800035E016BD6EC37F5D2AFAE90D0E069C7B6E -:10C89000AC5FC01DEC029293D1F058A775F9B53387 -:10C8A000314E09E886E44CE8D70017182F6FD27094 -:10C8B000CB7D974705FD64D64C9A82E10CB330AE30 -:10C8C0001CCA0B6A17BDDC0FE031EE1DEF58DC4EC1 -:10C8D0002F9B600FE039EC566727C941830EDB358B -:10C8E000AE071C14F0DDDDBF7232D9F94D928E7A9D -:10C8F0004830E224B80601AE78FF28A870FC068113 -:10C900001E91FF0E3CF21987E31EC98BFE9D5C63EE -:10C91000BF42BC40FDCC668E97605822BC64B14ECD -:10C920003A7FA9A8957C11845FD306829F219FE15D -:10C93000CF65C693897E9558F44B954CFB65A9A8A5 -:10C9400037D35EF307A4E7994FAA6C03811BFEFB64 -:10C950002A7A3E4F1C50349EDA04BCB6213C5D0856 -:10C96000B74EAE7745BEA0FB504679500959E03925 -:10C97000E5D1735F09AF7106BC908E51BE35E7CB30 -:10C98000982F689258DFF49EEBC5F35033BF17EF32 -:10C9900039C2FB7F4CF2B118EBBE60BAEE859E8BBC -:10C9A000806EF1BCA437BA8E86533BD2F3B7BAE996 -:10C9B000F93567E7A14CA4E73D12F74334275ACE77 -:10C9C000353D761EF7B5D509740FEBEE7C55F56D48 -:10C9D000F4C690CB82EED17E30DF37BB041782F1F4 -:10C9E000A25B1C14EF47F318C2F553B37CDEE66478 -:10C9F000C9D767F5DEBFDB2EC58C2737F423233F6D -:10CA00001AC7C3F8F926186F64F778D1FB83E12FB2 -:10CA100038DFBAFADBBFD9BA8C71BE6E3C5490B520 -:10CA2000105E8DB8A82352E0472AEA73D3254BFC49 -:10CA300015CC5CC8AD6FDC7FAA96DC7BFF2C4DA7C4 -:10CA4000FB74B7EBC6779DE8334F67E27C6FE2DBA0 -:10CA5000B8EF7FECE7E7985936F6D644DC3F26ABD3 -:10CA60000CE9EAE3432AF9A13F9ECAE36EAFF9ED70 -:10CA700001055D3ED7F0983876CD3889ECAC37B0FB -:10CA8000EBF1A8873B987F04C12F13EFED65D4D558 -:10CA90004CF1025F8FDD12AEC6D437A533E935C441 -:10CAA000DB249921DE5AFC7DA7B8207FFB872C036D -:10CAB0005DA0A01F50FBB1075932D69BE04F263333 -:10CAC000667CE3276F5E07F3187F48F679A1DEAC3A -:10CAD000032E17037D7AE47A1B0B98E0358185AB32 -:10CAE000D1DF34FEA8FF3A9C7711E83B784FA4A829 -:10CAF0007943B507F3EB256A1F0C05723DB09E6DB7 -:10CB0000B56772BF857201EA6137C1F5BC5EB04E90 -:10CB1000F261887241F35A8A2F2AA893E842E1B65B -:10CB2000B0C41CBCDFB003FADDB61EDA67E1FE0557 -:10CB3000EDB1DFBA336F5E877207E649EDEBF9B905 -:10CB40007C01B4F322BFD42DA2FE8AD74B0CEFB3E5 -:10CB500014D5F37DA9E890EAC3F2C67D8FD07E3B61 -:10CB600003C6EB978EFB50642ADD0BCA9474BA2F70 -:10CB7000191A4CF8EB601C7F6CFA20F20B52BCAB1C -:10CB800097C0A098E363FE641F42F2B3C0B74CEBBA -:10CB90000BFDBC96939C6E23BA3A43E7ED4701DE4A -:10CBA0000180F71B225EE540CE075AAB695FFCC2ED -:10CBB0003E949F9B344DA2388E852C8FE238668E32 -:10CBC000E7FAE6EB973BC3E8E77B5DED1C88DF0FF8 -:10CBD0005C6EA7EFEDDBB81C6E1FD44AFEF6E3EBEC -:10CBE0005586F758AAD7CB242F8ED7AB743F567EE5 -:10CBF0008CC731146EE3FAC781F5BCDFE3A8B7E157 -:10CC0000B9079643BE70AB11E7C0E5B4617F16E883 -:10CC10003CFEC290BBE562DD3DF6A175CB3424D964 -:10CC200068795B2EE471098B90BD1C2D77CBF11CCC -:10CC3000DD837C191D27E6EAB663900E225F105D46 -:10CC4000571C5219DA31D2076DB91497B647A2733F -:10CC50008BF1CD921FE31A8ADEB18749FF0EE7CF31 -:10CC6000FB11EE2FEFDA19862C1F433C809CCAB1D2 -:10CC700077FEE9A7F0FDE41B0E8C0802BAC927B8BD -:10CC80001B71BE599B793C4FD61BEB52F03E2F9B3C -:10CC9000DA97E44061ADCC0226397152F25F771326 -:10CCA000DF1F74D4770C7C66693505B8BF7ECBC1B5 -:10CCB000F755EF66156364D8EF843D04F6811FF5E0 -:10CCC0009BE25D6B5334131D14EF599B22C3F75540 -:10CCD000221EA61AF7576857ACF1718AF74AFA066E -:10CCE000D338463F46BFDA2EDE6EE81E9EF6D67F6C -:10CCF00031CE8FD6F9A986F222BA9F1EE3F7D24F22 -:10CD0000CEEFCFAD93605E39AFCB14AC9EF3C18C48 -:10CD1000A1E6731D2335FCCAD96FDA98DF04BF9CE6 -:10CD20003FC531BF09DF8DE380EF017F5737496190 -:10CD3000A784F9235A7916E575E4F30AE17FAE98E2 -:10CD4000CACFEB1A33DE58817C3F234B227A60A195 -:10CD500080D63789F4352FFAFD0BB378FB42688F04 -:10CD6000FCD8F808E74F90135E942315EBD7E652F2 -:10CD7000FD3AC98BFD376EC8277DA4284766545EEF -:10CD80007784F4A3A2A62349C8C7C0B7EB501FA855 -:10CD90009868D7518E1BFC68F0F7EBE23E2B73E8E6 -:10CDA000A3F17EC6FF46E68BC1D7F2212ED783F5CD -:10CDB0009C1F83399C5F5FDFA6E20A2F84BF899F97 -:10CDC0008F6FE1FC2A3F76432EDE872FDCCCEFC34A -:10CDD0001F583F45437DFA7858A2FDA6277F73BDB3 -:10CDE000359ABFAB25BEEF7D5DFDD2E06F838FE14D -:10CDF000EF6A1CAF0CF814EF4F46F3F54CB5E10F9A -:10CE0000B7C37CAF791AD603F39DF2DD3B3DAD2667 -:10CE10003909F914CC17283C9ECB902BE50A8FFBDF -:10CE2000FBDAF38B1A3F6CB7FA477E674FE4F1EBFE -:10CE3000752AD1FDF9F8B3079F5D207F5E285F9DBD -:10CE40008F3F8DF1E53DD67E7E27E82DBABF7680F7 -:10CE50006B04E0FA4AFD268AF3FDE8A92333113F6B -:10CE6000A5BB81CE91BEEADD2C82724E09D37E55E0 -:10CE7000D228D33D01A644B2AF739BF998C76D95F4 -:10CE80003EE3267A2A79D61E9E01ED4B767E3086C9 -:10CE9000E2689677525C5AE829A12F875AC7201F6B -:10CEA00094283C7E2C5A2E041CDC0FD7B62B7E36E1 -:10CEB000AE4FDAC2DF8F2869B851B59BCE256E74AC -:10CEC000A8463D3AD70D011DE3FD5D9C9FF9DD02AB -:10CED000236EAC6D2B9713254D2AD981255BB6B7F0 -:10CEE00063FC70C93B76F27705B79CA1FB10539E9B -:10CEF000D946FE9460936C397FEB11B7B9458ED853 -:10CF000031EEB0B19CCE1D217F84F20DB1E397CFFD -:10CF1000175F58FACC9E9D210061E9AF9EF4A07C7A -:10CF200039D5B2D98370877EBF326EBA479C66C34B -:10CF30003D5F19A7790AFF018C738F43D835469C52 -:10CF4000EB96BEA447C2FCB2F3629C7374E9E5DBC6 -:10CF50003E7D1CEF11B43D7BFA719C6FD93F3E7E44 -:10CF60001CE3C1D85E27ED77C1A7DEA2386CA3DD34 -:10CF700026B1DFB56F7D92E2D7DBDFB5FBB0B7F648 -:10CF80003DC707633C60FBF62F52D06FB964CF34C6 -:10CF9000F2EB2ED9312595C5D82F8C14E9367C01BA -:10CFA000F1F3D1F83AD07880E2D63E027CA3FCEBD4 -:10CFB0008ABB6D28E771CC5E116F5B1FFB9E428FB1 -:10CFC000F8DAC6EBAEB91CE57E23D71FCF1B67FB93 -:10CFD00026E0F1DB1780BF7AC32F101B7F1FE13FD4 -:10CFE000004FFBA2F0F769E3C25F3C8A658D7D7B51 -:10CFF0008DB38D5C00DC8C7B100F38FC871CC988DE -:10D00000E75F525C33E26D8617F79F4F07E3FD91B0 -:10D01000136AE75CBA5FB8C7AE63BC68C99EB789DC -:10D020007FDA77BC417E6826EE23B4B3AE3F1E3F65 -:10D030002E8975D6B9797CAE803FC6EF7A3DF45D16 -:10D04000C4E9723A36E2777B8BDB959D5CCF36EE96 -:10D050006794D7FD51C4C376E34BCA413C1DF9CA5E -:10D060007868030EBA90C3DD71E8B1E3A3BBEE2B81 -:10D07000087C21FE701FEA8A3387FCC0B1E4377A4E -:10D080009BC59007ED1B78FC7ABB1AFB5EB011972D -:10D09000FE8F683E0D5F583CFAF9E6FF75E1D381DB -:10D0A000CA4F724F38B5FD2DB61C4F774ADFEC9E44 -:10D0B0006199147D6FCAEB1C87713B4734B483BB05 -:10D0C000EC6CB1DE36E1576F7B4AA678E5550D076B -:10D0D000488E47CB8B0A7C2F25C67C33C57C2B9A88 -:10D0E000F83ED1F6AC3BEC827EDAF6EF227AAEA8BF -:10D0F0003F42F1D22F6FF995D66A8A8BC07D226CA0 -:10D100009A7FDBD3FBC690DC16EFB2448F33498C99 -:10D11000136C8E3D4EB0FE8C659CD25083A6BBCE68 -:10D120003FDE29C57F23F677AA85EB83A71AE4E9BA -:10D13000E118E30F73AAD677A160BFA4F767DCFC00 -:10D14000BD19D91347FAE51277CE3B0949986A14FD -:10D15000AF55BD4CC477FD872F0DF15DEDBE8AE163 -:10D160007C57227C4D7E1E550F30D44BD5B4BC2C41 -:10D17000F42B44CB1B2DC9C6C226FC2F714F4FF593 -:10D18000D279476420E2F370C67115FBFD4B949F82 -:10D19000EA2F0A5B950AF3FB4B48F22D837ED9DF19 -:10D1A0003E1894E7EED97F971EF163D9E257AAB0F3 -:10D1B000771E46BB84BDE0A4F80679AF93DEF9087C -:10D1C0003EEEA4F51ED8F1F913A45FFFC2CEF8B964 -:10D1D0000F582F20AF0A75DEC7F11D9F3FFE57D4B1 -:10D1E0009FB1318C5FF838D447BBA13E9EEC9C8E3A -:10D1F0006713C6A05FA4F085BB66A23C2B8CE7F446 -:10D2000058F84C6AB81AFA3B96CCF3C7B60DA27719 -:10D21000254A9F7553DCE8811DCF55E0BED4FE4CF6 -:10D220003CC37DA9FD05A1E7FF52BC5355AB7ACDA8 -:10D23000F1E3C54CF19AEFF39462DE12AFC4C82F4C -:10D24000417C84FEAAA604BA0704FAAFA59F8FD436 -:10D25000CE3B7C44C7A1FEFCFE53A43FCA83E87AC0 -:10D2600046F9BDCE21E25E39B47375D70F6A9D05CC -:10D270003C5FD39FCB9316AAFFB053F88F4579CF6D -:10D280007E79FD8784FCEEEE87B7AF10EFD044D3F4 -:10D29000EF46D16FE996BF5F1CEB9D9518F3A7EFA2 -:10D2A0003F9458C8867ACA7627BD7F85EF28E07DEF -:10D2B000859D1A3FD72AF344E89D9BDD421E97C502 -:10D2C00045E8DD9DFE621E581FF3CCD1FA34BD9FA8 -:10D2D000F69C93615C59F90B6E3FE2BB7CE7E7C7B4 -:10D2E0007E9E857189F114175FFEC2FF223A28B72E -:10D2F00047E6223F746EB7B38DC8E7DB5F1D8CFC39 -:10D30000DAA64606F7F98AF3BAF206BBF5FEBF586D -:10D31000C7A9AADACBF0BEBB71AFB6A41739F357D1 -:10D3200027D7A35F71FA5F7212BF5BDF733A55357F -:10D330003B13DF5930EA973862CBC577515E7C13D7 -:10D3400039EEEA713FF55D9CCF47AC2505FD3E15F2 -:10D35000A077A33C2FD9923E10FD04FB9DC63B0451 -:10D36000DE04DC8FF6AB5EB2A73135EF3327AA7C43 -:10D3700099CA30F4DF8CCC54601D1D1BCE14F467A9 -:10D380001847EA9C1D4BEE9D76C6D33A4A1CF69888 -:10D39000F79DCF09BA7A0F8DFE643E1EF28731EEFB -:10D3A0007E354C72F88E382FD52B01BB08BF976E97 -:10D3B000999369797F45A9A17AC0A704CF62B64E37 -:10D3C000CB32C96F63BCE2A559994A267E57FE4FFE -:10D3D00017BDCADD7866A124D20B150163B6AE9FD6 -:10D3E000E57E88A2E639107E1ACBD3151949A586A9 -:10D3F000F83D8E3550EA02758BBF5356C9504E9E8C -:10D4000010E7F6E8EFC2B41B5E7792DC0F0D626C9A -:10D41000783ABE07E14DD04DF053F1101EE6635748 -:10D420002A1997173374B493A550807D09F4545D7D -:10D43000353D13E911FEFC180749A607CCCFA3BF61 -:10D44000FC05EA4140A7FC3DBFEFB270358018C330 -:10D4500081C9AF3A99F177E856BFC3CCF6C6A5713A -:10D460009278E7681FC93117EBFEEB843C8A55942C -:10D47000B7D509FFC8C1734497CE22A817C6BB58B9 -:10D48000241E52D728E59499FF3D599037D1A93EE3 -:10D49000D15A1ECD1720D7A2C66D20F841BF9F4498 -:10D4A000F5FB4954BF9F7C55BF069C828E8D3E7C08 -:10D4B000A76265559E801B1FCF21E006F01989EFFA -:10D4C000E8315B9C4F9C87135CE3C46CEC581FF005 -:10D4D0005A1E974E78B92F616F27C641B3A45A865A -:10D4E00076EF0A89EFD3F097E732B563BA83F8F0A5 -:10D4F0001E314EB980F30AC33FD5A3BE93F4AF1ECD -:10D50000F59DBDD58F8B5DDFDDDB7CE263CF27B181 -:10D5100097FE6BE263F6FF75E552C50B6FBF86E7BA -:10D52000B65DF24907D05BF5CCF238D433138FFDEA -:10D53000A395BE703DD331D08AEF38A46FA0B7B8A1 -:10D5400061D6EFD174D21B7DE58B7540DED50FE03F -:10D550007093187F6A1D3FF7BE6509F7D38179E89C -:10D56000C7FA378BFA37390AC9DF70C4C6DFBFBACA -:10D57000A596EB91B7FC58A6F3E91EEF51E13F8069 -:10D58000DF6E5D2A8523E9B1DED76275783F6E9E36 -:10D59000183FFABDAA00F3E6AE9663BD57C5E9D2BF -:10D5A000B85717FD4EC5029627DE21B37E3FEBD458 -:10D5B000BBE467CDA8EE7D2CB416E81EF54FA07B2A -:10D5C0003C97C7EB621417E2D1785C48CB203A4F06 -:10D5D00033E4DFD991DE04DCAF997F30FFAEF3EFA7 -:10D5E0008BAFF4A69AEF1D2AE7E22CEFF554ABBE01 -:10D5F00034946FEA39D05FC154D6CE0D615E533991 -:10D60000E8ADC4FC18BE49722A4D09A35C54F43C31 -:10D6100056887AAF78EFC3A8AF255DD5A567BE0E53 -:10D62000FF6F8E4B26BE5CBCD64BF7B63F8BCFDB75 -:10D6300089F4247B727C01574F7A08EDE0EBAEC68B -:10D6400075A7F75C4FB5E6F391BE7D158080FC6F42 -:10D650003E07CE4FB67BDFF6E2FC7EA332F4BBF48E -:10D66000848FEF4418CACF8607507C889C306304AF -:10D670008EBF46BC6FBABA6A24A52BAA984879BC5B -:10D68000DC8A2AAF487344EA17E974AA776F551AFF -:10D69000E55755F92835E0EBF0D5D0FB938E617C4A -:10D6A0007C872EF0976413F00B90FEE548ABA473D3 -:10D6B00045A75E19C177DFD840D87770597A0DC178 -:10D6C00057D319F935A13EE5ED988754AD9D41F842 -:10D6D00052F44A5608E56FC5078E225C9DDE4B2D3D -:10D6E000EF5ADAD3C646BD7F1A056F83DEB671B82E -:10D6F000DF2F717A8B86FBFD6A8B17E322EEBFB2B8 -:10D70000EB5D29823B98431CEEBFE6E7B43DE1DECA -:10D71000327BBE09EEEEECE904F7FB049CEF1670D9 -:10D72000AD1678A816F0AC46B8537EA4C8FB443AB0 -:10D730009DD27BC4FBB72B111F90CA087780877DD1 -:10D740005488C9301EBA79F1CFEE1274ABDBC81F12 -:10D750002ABBF2FC08777B1287BBC3057820BA0688 -:10D76000B87BB13C44F0545D1CCE509FE341E415BE -:10D77000847B267EE7F800B8F78D1F87F27082055C -:10D78000CE5AD2E40B83FB237C7F4B127C1E0DBF51 -:10D79000248DBFAF6BF0776FFA71B588B7AE16EF17 -:10D7A00027221C51AF7908E0C3340E4FFE7DA4C878 -:10D7B000FB284D16F67F35E001CB1F16FA10C21973 -:10D7C000D31FC573FB3CC956B94F4538F5E1EFF29D -:10D7D000B0A4101B98CD78682FFEA5859817F3C6C6 -:10D7E000F9AFD74A3FB2AE44BD03E97D18E96DDD1C -:10D7F000ABAA0DCF3FE4A55759EE67CBB3FD895EC9 -:10D80000827F4042BDE63EC1876B915E687EDC1E32 -:10D810005E29E8E06EF1FEEE3D827EEE17FCFCA094 -:10D8200041373E7E3F64CD741EC798946113EF204C -:10D830004698394E30D1D7C0349817D9365E4AE968 -:10D840009D4BF68E9DF8367E14F3237D25BE7367BF -:10D8500098BF439BD70FF5A144E3DDD989DEC439D6 -:10D8600074313DA288F720656E4FB6C47CDFB5DA0F -:10D87000B7DF817E99DEE613EFF3A7AF84F1E26BA9 -:10D88000DD6447F50DE4CD590879572DD8550CCBFB -:10D89000B97C70C1BC0B4DF411DF8B5F47755D59CE -:10D8A00080F44AF638A43FA91DEA44F802ACBDE86A -:10D8B000BF7A48CDEB87FBC14389B1FD70B3E2B9B4 -:10D8C000BFC49375A9C59FB04EF5533B7DA255DEED -:10D8D000AC13FB439FA956FE30F683CB447F9FC514 -:10D8E000077E140F7496726E2AC9CFA46B63EF0F74 -:10D8F000D5AA16C2F739AA4773BE0EE56B5C6FEE68 -:10D900002177189D839C0D8CD888FE2F83BE96337B -:10D910002EE7428CEB93C6BA7E86F43E02F7019D59 -:10D92000E81EF701CCCBC334A29B945B6CE47F5818 -:10D9300025F8EC5EC15F6B045F3D807C3502DF81C2 -:10D94000F651FA13C14FEB90FF20DD129FCEF57810 -:10D95000F1BE9761C72C778CA5F71CAB5D36DA0F4B -:10D960009477ED6117DA05FBC6EBE8F791DD597A9C -:10D97000C08DE5590E3FC0434ACCD2915E3E732F15 -:10D98000B8E8ABE25B01FDF4AEB0A2727FA49E9456 -:10D99000C7DE1F45A753F49E80AA5FCBD03FFD7022 -:10D9A00052A513E1FC703C8FD3AACDCF26B8033E1D -:10D9B000B6C59BE2A552675FD5F51E1F76FF702F97 -:10D9C000EF12EC12F2820D0CB16126F9502BDE7BC6 -:10D9D00064DE101B699213CB87E732F4EBF5940FEA -:10D9E000BDC8CBCD5C5EAE9062CB4B437F37E46568 -:10D9F000B45C31D295174DB7DCA7545D3E46F26654 -:10DA0000646CFFC1EFE3EDFC1D6AE6F3E5A7F72CBC -:10DA10000778FDDE0C2FD4830C7FC5F762AC275A44 -:10DA20003E9EB8CAD85703F43ED002CDFBF0F8AF03 -:10DA3000DC57ADFB41E1B9D5A40F149CCBA1B4A830 -:10DA4000763AF111C3D318939D7C7CFD0F3D88DF9E -:10DA5000E3B5E27C7CBD1AC6B8A47D1BEF7A600EEC -:10DA6000C075C1E3329D8FE33D0DD914DFC2B2BC56 -:10DA7000A4A71BEF231E0FDFEE31C73114FCD4E93E -:10DA800047FDBF377A2C581FDB7F538DFF44BB8384 -:10DA9000F946A25D01FA5D6704F5BF9F38E9DD181C -:10DAA000231FDA18EF33C78F18E95BF1D3CE21DCDF -:10DAB000DF8AF73317D29DAB0F9DD7F4CE177CDCEE -:10DAC00063E833C773D247459C35C07D96C57FCA8E -:10DAD000CF498F097F1873F4521E27CABDBD947BAE -:10DAE000783C13D36397FFD37EA4513DECB421B8A7 -:10DAF000FEF2DAD3ABDEA52FD6F3806211C7BD608C -:10DB0000637C78790CBE5920EE072F10E75D067D07 -:10DB1000157FDFD0B3395D46D3ADF4D42544A71FBC -:10DB20001F54C95F5B01F4877A98F4D4787A8F69BF -:10DB3000D913973D780BC0F993433295979D731095 -:10DB40005DB6FF878FE2FC3B7FABD2EF267C727025 -:10DB50001AC5EBB78BF79EBBF8CEC5EDDA1B5C5C44 -:10DB6000AE149CBB97E8BB8BAEC2F335E4DB82738B -:10DB70000F905E5680EFBD4EC0758F78799222E887 -:10DB80007702B61F92BB1CEA15B6723E61134315AD -:10DB9000E48FDE10EFBB37063FDFE0F25AE2450BC1 -:10DBA0005BD750FF0CF4C324535CC802F1FB07851C -:10DBB00078B884E57A88A521DF08F9D64DFFD677B5 -:10DBC000B0DB9DD6751AE9C2AE754EB0D861DDEBFB -:10DBD000FC2EE773A16F14B6E6F07975ADE7E7E3C5 -:10DBE00063ADA77B1D13A97D7B62ECF1EF17E31FEB -:10DBF000AB2AC29B5BAC44BCB75B10BE5DC3F7D520 -:10DC00000AD627F6914CEB2AAC2DB5C42B15D4E6D9 -:10DC1000D3FB7A85EBF3B5DB4CFB53175E42FE97E3 -:10DC2000270DEBC6CBFD6B2E23BCA8AEBC3B917E73 -:10DC30008F3D557CC77B5EEC97E3E984161A534908 -:10DC4000F2EA764FACFB4DF747E3A956E009EC80CA -:10DC50002C139E0CFC44B73FB6B9FC8EF7F01CE2C7 -:10DC600011FE9A50EFF22B0A7FE9B1E1F7A4A0D799 -:10DC700063A00F042E087EDFB2C4CBF50A3F816F8C -:10DC8000033EC677D0E7C208B727913793B13F4E1E -:10DC90000FE7835BF7F8821E26C55ECF6B5DEB59FD -:10DCA000CA42A0C79CD4B83ED1FB7AEE6221C70518 -:10DCB000ACA78B4FF32D7CFADA9A5B389F0AFC9F56 -:10DCC000DC7F0FD1F5B170BC0FE3547A5BCF6B48AA -:10DCD00007E362D0C1B0101B95FD7F8F0E4E68FE2A -:10DCE000118FE03E02FB15EED3C54FDE3FC63CBFB1 -:10DCF000B7E227FD9EF6A59A0B3BA70E4DF61DF445 -:10DD0000D27E27FBAA6149435D813F63FB12CFA30B -:10DD10009FA19F6E45E2CFC6C4D28B5756052EC732 -:10DD2000F38BEAAAA2CBD18FAA0A3D97A19E9BCEE4 -:10DD30007F1723D67B7DCCCDF1BBB2AA92CE3F9884 -:10DD400023C4F494EE7700D8894CF2472B2EAB7E97 -:10DD5000A6A9011DFDDF9A78A7405502ABD3B3D029 -:10DD60005F94941132C1EF1F2E7EEEB2266DBF8EEE -:10DD7000E71A76E81FFD608E81CA598BFFEC456576 -:10DD8000415FC093F11C731C6BF04B12F913CF462B -:10DD9000F913CF5AE69104F3FE0A3B5B7178E81C55 -:10DDA0005261C28F2CE0015F681FBB5BE7EB5C1E1A -:10DDB000EF217D60D54536B2EBD609FFF4CFD02FE9 -:10DDC0004D7051E8BC01C3E0B0BE96C0D7E1C4734A -:10DDD0000C19EDAD08E5DDF862974C4F1F4A984FDE -:10DDE000645E09F37D596415DA0F1D935AEF203FE5 -:10DDF000A03390E606BC7ED6AFE5B084E712798109 -:10DE00008B11CEB57228C30BF57F21776660BDC13B -:10DE100050F44E1F9E5E84F71202A6F3CE21B48EFC -:10DE2000EEBCDC337FD15225EAFCEF6F179BCB5F52 -:10DE300071FA2FC679543BF9FB60491F4874BE57ED -:10DE4000DD75EE9447FBF26437C723D105D2D54187 -:10DE5000AE379D55BC097DC89F3D32F345CB3C7C18 -:10DE600096BC22ECD13AA0533CA732E86398E2B7C3 -:10DE7000211D0DAF81EF663CC6D077FBB8E879F085 -:10DE800098FAB9313F1897E8553E97CBF7E3287ACF -:10DE9000D82DF1F9878AEDDC6E642119F13AC7209B -:10DEA0003C6505CF2732E38FECB5778D7327B682BB -:10DEB000E7759E0BDEC6CFB9A3E733A7F9EE163C94 -:10DEC000EF99D3DC6F3E9E7BCE29BAF8434C77ABFB -:10DED0009DFBE3515EFC50227DF6A6B75E54E32124 -:10DEE000DDF1E6467A9F60AE9BEFBF7359A78AF8D3 -:10DEF0000F305DE3E756615ADF6DCC27F20D2AFA49 -:10DF00001D6E89846FB81A72B7BE18BE1AD5BDB916 -:10DF1000073B5F42B4051AF45C3A1B32DA35F95E0E -:10DF2000E679DEAE0B0E4EF1FB478A83D6D5BD6E89 -:10DF300007C1C15827D4247C74C149BCCF66C0A591 -:10DF40006BDDF1375F85FEF8DEE4DC1CC7E80F7996 -:10DF50009C3C9F57349C3EC12290930BDDFE1FB921 -:10DF6000A1FC7AB7FF2E4CCB1C9D839521C437555D -:10DF700098AF900317A5001C3E1A14B83819E1D1C8 -:10DF8000D2F782F4FEC34E2E0F0EA71B7A6DAB1B89 -:10DF9000E99BBDC8F55AE3F73256ED387EFF8D0098 -:10DFA0009F8F5EE5EFCD95CBDE6BEE22FFB2CC62AC -:10DFB000D921467A58F80D1E76DBC47BD17C9DF3BF -:10DFC000140EEF798DF174CF6EDE52D9F2BEFDBC26 -:10DFD000A53C7E95292D63AEB7D8092B045DF7ECDF -:10DFE00007FD1AD1FDCC5F3A99DE2DD9A9E993C876 -:10DFF000CFF138A7B3F953FD32C6FD4F582D911F0D -:10E0000069FC516F532BE4E787137DC8AEF3EF5CD7 -:10E010009C89EF9754B4703F67AABC28E33F207DEA -:10E02000683FDFEF31BF08E1E4F27B5DA6F39A368B -:10E03000B53243477ABED5E54779907FBDFF5DC4D1 -:10E04000A7E1E730F6DDE7400FC038CEFC5BBC3916 -:10E05000481FF90D4E3FA50EA6C4815CCB5798030F -:10E06000D3548D294E4CE39803D3ECE5427FAA9D0F -:10E0700045FA8327274FC3F7C4F39B9FFC14DB1794 -:10E080002A917D92899EF29B5FFD82EEC3F9F3286F -:10E090004EF75B5B348BDD39BAC19AFF7693359FBF -:10E0A00011B1E6330F5AF303706D267D73FF1E1E08 -:10E0B0009F527A9ADFEF7D1E60A0223CB6D9493E7E -:10E0C0004E296DCEC67887D34FBB6D58BEFBEFDCB3 -:10E0D000EEEEDCEAA47725F7BD17C7E292F01D6AE1 -:10E0E000E7462C3F1DD7908DFE45A84F714BB0BB26 -:10E0F0008E40BB71E7A506BD8629BE69E73FF8FDE6 -:10E1000094CEADF630C6519CDEF5E4D3489FA7B758 -:10E110000E207DEC792964C37E43F770FC4F88F3B1 -:10E1200058E454E916AB3D7E42E8011D27B579E875 -:10E1300017BAB8D6BAEE4BC2D67CA7A87F1B337DE0 -:10E140004FC7F810EFAA34DC6737C57EBFFD73C137 -:10E15000174F3DA519742B8BF71E9937A5FBBEE20F -:10E16000EEEE73DB2503808E4A111643BABF974645 -:10E170008DDB850FD17F92382FEBFCAD4CF03955FC -:10E18000556489EFE8D2FBAA7C69534DFB5141ED00 -:10E19000BE947CD257F7A5DC66DA67CAB61E48B9CA -:10E1A00019FA6BDBA2D0EFEB95CD79E2810949F842 -:10E1B0005D6EC0F96239FAE7DA1A5EF2603DD08B23 -:10E1C000C79AE3BD0A6BC7A54D35F1E9D7A54B83C7 -:10E1D0009FCA740E9FE7725A72F11E46692DFF1D89 -:10E1E000BED2861BAEBB1AE1BE9EDF4FCF56589EF5 -:10E1F0000CFC53B6FD86EF8F86EFC1C7C6F9703EA3 -:10E20000D9F8242DDEBBAD3F43F776EEB571FF4460 -:10E21000345C467B387EEFFD81AB08E512F4F7A253 -:10E220006D2CB53F68037DE4C4E4D06B374395D3D0 -:10E23000ACE10F57535C96959E803E25D4B73A3794 -:10E240004BBE8DF47579F6B5A85AFB97513C3A94BC -:10E25000C7B4378AC3D67EA2F17CA547327EF76861 -:10E26000A4995EA2EBF59D11A2DFB72A5B0A72CDDD -:10E27000A4EF971DADA178D8E871C819688A3BC191 -:10E28000FDD14B7CEC147A02931CD9225E7C28CF02 -:10E29000D3BBA748974010A597B2A95E84EBB56C95 -:10E2A0003AA6CF4B91076499CB03F2336D8B277954 -:10E2B000D0A6B73EF173A4A3FAD1741ED65FDCEFEB -:10E2C0006EF346E8BD58E37771DA749E2F69765293 -:10E2D0003CD5E98F349297CB308E13EB3FEDB4D918 -:10E2E000405F3BBDBDEF648C0B6E6BE0EF8A9F6AB5 -:10E2F000E83B59FB8AFD379AEF8D7DF108FE13DF6D -:10E300004FF5F88B3DB8DFACE071D3A97D2B332AF4 -:10E3100063E0C96897A45566A0BDD279ABCBB7912D -:10E32000EB53E90AF9DDD3C8AF922FFC49F7E9793D -:10E330007778A0BE1BEAFAE1FF3E07E58DE877FC9F -:10E3400040F6DDA10FED3E1F5F9015A0FBE3F40347 -:10E350003630FE7C854514A0B7F9B8AF8CA13CC916 -:10E36000CFF9EB258A235CB0C6BA1E7CE7DABC1F66 -:10E3700016E12F290EC5B8B0064A8BD65BCB8B7140 -:10E38000FFF050BC17C5CB94D459CB198B901FAD5F -:10E39000ACFE4B7B2CB87DCA8CF5F96B3C16B9A34F -:10E3A00092DCF950CEA3F595A23700D29BC4FE1C97 -:10E3B000BC33276D01A41D4B27A42DC8C47BEE7C64 -:10E3C0001F23D38EF898BF8F573A954506F1777182 -:10E3D00018EE8FA5CD526434E61D2CE419CBBFE3B3 -:10E3E000FB20B86EF33D3163DDB85EF377F626C7E8 -:10E3F000AB71CF10D76B2E2F137028ABB75BFC3AE5 -:10E4000013EAA590FBDB787FA995DA55347E69B7CE -:10E41000F42BF65FD8B79913F035A168838C8B790C -:10E42000A84B8E872F89750FE5B080DF433714F432 -:10E43000437E7D10F5CFFE02C039249F849F804526 -:10E440001C305E5C66579ECAB397F3FC3E4FE08A71 -:10E45000DA8160AFA9013A879A2FE7BD8CF71B4795 -:10E4600026065E42BCCCB7F9072BC4B7FE11E417F1 -:10E470005DCAE1F0F0D8CA4B2A63D9C502BF3F9309 -:10E480001AE85C3EB48BEFA3EEAC4ED5ECF7FE8BF6 -:10E49000904709FB5BE95E4FE70E89EE133F221DB3 -:10E4A000A1FBB68F5CE96568C7A7019E50EE3E22CE -:10E4B000B115F85E5E56E3AC452F219EB3E27C7841 -:10E4C000DE5FDE38492E77D1FAB9BE155FB901CFCC -:10E4D0008352E78D1C8B740EEB9E772D7CFFD0E36F -:10E4E000A5F1FAB938DED39687D2178FC2F1F316A9 -:10E4F000BD847C383A8EEEA1A702ACDC7D285D8D10 -:10E500007A541ACBD887FA60DA0CEF58F4B93FE4A2 -:10E51000E1E324DBE479B350CF1BCBF37D7E2CF910 -:10E52000371211AEA57152ED6C3ACE17BFA35EE85B -:10E53000403F82CB84EF299519387EEA509E2669A8 -:10E54000118A0F3C64E0BD99C7E92DD119C9E925AD -:10E550005F4C4A453BEE501B18D420BF0E0D34ECE7 -:10E56000CC888BF4F06123797D61F72DC9E0F75FEA -:10E5700092061BFA0FAFD7A1FA133251AEBEC1F506 -:10E58000F14F5C7EF2575FA6C58EBF4F48E0780A18 -:10E590009E8B636193FF3838FB33D21383E73C2CA7 -:10E5A0006CDA27F0BD4D731C7759D17EFA1D847249 -:10E5B000D642F701CA1BAC71E797C5C51ED7A0F3B9 -:10E5C000E0391B0BF525321E88F6D721A973D5C279 -:10E5D00024BA174BE73BC1731A0B99C60F9EEB6326 -:10E5E000CD77CD3385FAE9AEC7ACF59A3EA77A2C44 -:10E5F000A7D583E3B4EBADB48F04CF29D4CED86FC5 -:10E600003AC2B6900AFCDCEEE5E51DE23CCFA86F0D -:10E61000F4D73E5B13F7DEF8BBE86D552078002E8B -:10E620008F369F217F7459F33E828B410FDDF08935 -:10E630006721137C52AA5B2236E0ED690F6EB87B2E -:10E6400014D890C9FB051F8736DDED9F08E5F8BBA0 -:10E650000F26BE8ECFEAE27312330FD9642E174213 -:10E6600075774F9D68CA8BFA5DED439BAF980A346E -:10E6700095358AB7BFE6C1275E594E4E8B1A11DF1A -:10E68000DF3938CF6DCA3BA2F22EC88F36E5F5A828 -:10E69000F2A4A8F2B4A8FC405EBFCD1D192CFB402B -:10E6A000DE3FF8D415F8FB9E6DFD2273F1058F3522 -:10E6B000F2B62BF0F77CCBB3F8EFD356344B3EC910 -:10E6C000243F2BBACEF35BB5F9A3100E2D2FA31C5C -:10E6D000286B9274D4EB5D0DDB2394C7765E53BB3D -:10E6E000066E3F96351CA176BDF63FD2467C7CEF88 -:10E6F000C8F7A9DEF9CE9FD80CEBEF5BF5761E7557 -:10E70000440A2C4E48EE7E7FBD6DFBDBDDBF2F0A39 -:10E71000DFDBFBF90F901C8DBA071EC4F9B8BAF9FC -:10E72000C480E3BD23CFD27BB47F1CDDFC16AA03DB -:10E73000F14BCE2C53A0DD9FCB8F8F437D0BDFB4ED -:10E74000C57DE36752F812DC8F1E65814B70DC5B80 -:10E75000CB87EFC39F4C38ACB63E86EF956F78F011 -:10E76000E52B1498DF6177EB20FC09B74D096FF0BA -:10E770007C722B7F5145FF1DE1E7F0A0D64136C8E2 -:10E780003F99C0A6537E78EB63987F3DE104AF3F8D -:10E79000BA7590ACA30972F28AA990DFACC7E6F70C -:10E7A000DA04AE371BF39B36DCFF53840B2BE3FB01 -:10E7B0000D5E3376803C9D5B726ADB6680C7DC1F32 -:10E7C000C5939CDBDC76DD55790487501EC611A607 -:10E7D0000A78D37E48725D217DA21FEE817DBAF159 -:10E7E000E91EDCE2A5FDE2D2CAEDA837A4CE1D45A4 -:10E7F000FB45A1C72FE9C9DD69381952A82FE93AAD -:10E8000097EBB28DE22352EF72931EF5A0F83D0311 -:10E81000E03BA20F97C0CB36B19E6D09DCBFF680FE -:10E82000671AF5F39EE47FC42163CA424EF2A7C57E -:10E8300091BE72F306902B20D7D78979AF5B7B0905 -:10E84000F9296E463FF128FCEEEFD76754B7FEBFBB -:10E850002E03F2AE6EBB6EDD2C7F3FF3B9F6BA0D20 -:10E86000BCDC905BEBD2797B63BF4AADE6E3A43EB0 -:10E8700078C9465C47BCC2287E7BE1EC111B97D16E -:10E88000FE7F2DAD9FF9FDFDD00E3F5A3CC4867A28 -:10E89000A9819FC2E1FE5712603D3789DFEF35F055 -:10E8A000648C4FB7E2517F90417F403B353140EB64 -:10E8B000077D620C0F6EE0FA04D21633C19729ADC2 -:10E8C000E3F0FBFF2038B5FD2BE0F44F9F7747C9FD -:10E8D0002190370CFB2F5F7ADC72FFED3F01D123D3 -:10E8E0002A700080000000001F8B0800000000005C -:10E8F00000FFC57D0B7854D5B5F03E73CEBC929920 -:10E9000064264C9249C8E38440081071124344F0D5 -:10E9100031848851693B50D4D87A71203C022699C1 -:10E92000A8D5624BFF0C12790918342250C181021C -:10E93000C55BF506458C1A70448A7AAFF68EADB782 -:10E94000576C7FFF08888F4A32A2F5D297FDD75ABD -:10E950007BEF64CE24A9B4B6BDF93EDCEEB3CFD9CB -:10E960007BEDB5D76BAFB5F61EA6F54C0A5CC0D8EB -:10E9700066256ACEAE642C7C48F1ED61F007CF6766 -:10E980003B19FBF7B4A0D595C9D89FF1EF0AC6E6AD -:10E990007EBF29275806ED8D2318CB612CF5BBCF00 -:10E9A000D4DE00D5B94B3F7A7C0F7C3FF77BA98C36 -:10E9B000E903EF438F8CC1F7EFBC6D5BCF2E84D2A0 -:10E9C000D2193579A0BC86F956C07BEF98584327F9 -:10E9D000F4F70EBE7A096355DFBBE5353691B1DB3E -:10E9E0005D2A6393185BABF873988A250BDBE0BB59 -:10E9F000F02C4B644F11637D1153D80CFD75B82377 -:10EA00005B17C1B81DD795F9C2D05F1F637E86EF33 -:10EA10002D4BA5F73ADC3D4CC3F64B741740C20EA4 -:10EA20007EA1FA19D4E3375A22BB14785ECEC2769F -:10EA30006C5F323E1286FAF3300E7D7F634A640FBC -:10EA4000B6CF828FA0DE71A3371286FEEC2C624710 -:10EA5000783A76FA73321C8CE5AAAC05E1EF28828D -:10EA60003A94592BD9CD0107E2CF3F719673000F2D -:10EA70005F7799683EA9953D4FFF37F4C7D6DB7D98 -:10EA800063A0B0E1AB586FCF2678993B5885F86604 -:10EA90001AFC03B8EA1FC889ACC3E7CC5785EBB1B1 -:10EAA000DAE99F47F0FF205547F81FB6B335B60A9D -:10EAB0002815D666CB00FC0B7858FB43000C633757 -:10EAC000E3008097FFD770D6A9C3F32B5D0AAD078B -:10EAD000FCF96D558CCD67BC7DFEF2D477958958D5 -:10EAE000AA516B1A3C5B73A5BFC746EFB13F8FE2DB -:10EAF000A50DFA0B32F1B725EE44BA09E27769D8D1 -:10EB0000FFEF9DBA03EBF0FD445C76F8BE74E0FBCA -:10EB10003A17A3F9CF5539FCAC355547FC4AFCC828 -:10EB2000B24EC2D7FE903F713C394E72BFF7BAFC6D -:10EB30003722BE00EFD1740FE245A5754D86D7632D -:10EB4000896FB043FBDC56D57D37E033B8CC49F351 -:10EB500095F0DE9C1DBF8C150FEEFF746A739586D1 -:10EB6000F35FC6E99D2DB702E212F16219A8035DB9 -:10EB70002C64F163266588E75AF445847F5147C2C7 -:10EB8000F7F4DF2FAC89EF497E61BA9204BFA02B66 -:10EB90005DD170DD820A5F378B253E375036186EA7 -:10EBA00089CFD582EE245D24E37B35E27BD2607C85 -:10EBB0007B2C3DF9D86F709995F094DC3F6311FA86 -:10EBC000EE213BF00FD0DD1645217ADD72576A64E5 -:10EBD00025F2A73DBE17F1193A7C15AD77EF9214D7 -:10EBE0009DC12BDB2C30419433879D9C8F4B7A4AFF -:10EBF000909F7A61CE7E589FDED7D59D614502C138 -:10EC000058F3EBEA2EA4FFDE67AFE6FDAC48D5195A -:10EC1000D4438861183714FE432B03BC9E34C52CA3 -:10EC2000345E17E057C209FF7AE15F43C580BCE854 -:10EC3000C3061CBF8BCB0798E1121AE7DB296C1DBA -:10EC40008CDB6C52FC26686F5E3A3EB292C3614325 -:10EC50003E6A1420359B589B5231C0F7CDA6132530 -:10EC6000B795F1360DDEBB85F17581F78E2A005F11 -:10EC7000A36D7D4C45BA45FA87F6A5D85E3480FF72 -:10EC8000E6F5BFF913C2DF7CC048178D8F19E7B1D5 -:10EC900034919E8A06E824B592E389D5B0C81880DD -:10ECA000D729EAA9B5B1888A785A56CD4E02E966C5 -:10ECB0001EE99981F4E3ACEC64F3A10C7DC0FC1176 -:10ECC000807B4AF7CE9746C2FBEEDA583E4E37B409 -:10ECD000ECB68B4E5D34B0BE12CE4BBA37A9CC41E8 -:10ECE000E3D177008A7FBF83DE1B37FB82C4F26EDD -:10ECF000FA2ED3A412BDF6E023E41BCD9FA3C038A7 -:10ED00009B978C32E17AA6827C43B9BCB07DECAE95 -:10ED10001584677F09CAB707D380CE099FBE2A949E -:10ED20002FA5EEEA5FBBA0BFA7DCD5FF8D258E1314 -:10ED300070E2F44790BE48A6E764BD23DFCB2E6E99 -:10ED4000296F710CFF1EF017E12DBE359DCB0F4DC5 -:10ED5000A1FAA2FF30EF5C47F0694437B76D2F226C -:10ED600079DCC0DA89DE1A59C482F4BBC8C6C2692C -:10ED700040178BE0B57428176FB1323D61FD9644A2 -:10ED80008CF546210F6E6131FAFE967D49ED352CEA -:10ED9000EA84F6261B8BA662D9696C6F667141EF17 -:10EDA0007FB6263E671D7CBE378B7577D744D4204F -:10EDB000CC7BAB1D745706BED04EEB3365F94E5A73 -:10EDC000CFF40A7FD13DA84F5E35FB7601DDBE272B -:10EDD000D64BE2E75E57F5BB88F714D544F38FDFD7 -:10EDE0006325FC9C02BD8DEB7F9F9BDD3C1BCADE37 -:10EDF00056DD3B7A34A2C95530DB3918CFEB9EB3D0 -:10EE00003720DDB8DD26C2B77C7ECC65A67AD5DD9D -:10EE100002FF2B5223BB8A08DD13919EAA46497D2F -:10EE2000CA26CE82FABB6656D709F5E6EB1D41EC41 -:10EE3000AF07ED07A817B8B9DE28705B687EB22E61 -:10EE4000E72BE906C6A1FE522EE2A584638C5BC8BF -:10EE500041B6897F27F4EFE625293B49FFF6D3AF7A -:10EE60008911FD96052C88D7E7845C794ECA9536C2 -:10EE70002B972B9A6BEE32A83FF741996F1DE095C7 -:10EE80009582DE83EF1B3F4AD1919E5EF9E85FEFEA -:10EE9000FD19B49FFDC0A25BA17D01D218ACDB734C -:10EEA0000A9747607F30D48F8DC0F6386EE3C1B1CA -:10EEB000647F1CB408FB46C8CFC6B4E0D685D04FEB -:10EEC000E393993EA064F6BC39F2E85E6C3F64F7C8 -:10EED000ED817E1B53385E1B9F1B49DF3F610F4E48 -:10EEE00077C33C73AD919F3C8172E3052BD97B675F -:10EEF000597411C27FB6D3AEE07B27705EE95042F1 -:10EF00009B82F3EA76923D047C9AB310BE3BB936FD -:10EF10009BCF4BE0E9E48609C4179BCD7CBCF0B3E2 -:10EF20000ABD7FC21C989103F5134F97FB564053BF -:10EF30005FC012B5003D87EEE3765EBD49DF8178A4 -:10EF4000628753095EB91EA18D8B67627B68E9F207 -:10EF5000AFA37C1C8ECF51DEB304B9D9CBE205C878 -:10EF60004FDB1A467546519F748FF3915A655E5870 -:10EF70007CA01B177FF79499E3357EC84CF47CBEC8 -:10EF8000FDE37CB52AAE7F709C10C86526F98FE43E -:10EF900072425D1DAACEC8FE0C3D972DEC3A63FB74 -:10EFA000EBCEE01D6EA0BFE6FBFFE79D6584DF387A -:10EFB000C945D69E497C79CAEC9F8B74EBAE895AC1 -:10EFC000E627E8F30D82AFEAADC2FE63514B221F84 -:10EFD000CAF6AA6A23DDCB72BDA07F678CCBF7C1CE -:10EFE000ED26C11FDFB4A21E9BC2416685A8471C47 -:10EFF000D8BF4EFD4FF9206AA9877AE1F2A8659142 -:10F0000028914F00DF511BCCFBD45627E76F4003FC -:10F01000F6B36832237DB94805FBB5029FEB5D3D31 -:10F02000B02EA79F7673FAFA236005F03D8F89F71B -:10F03000AC60EF821C7BA64D89E27E60DE16EB2E73 -:10F040007B11F2B55F75E27A6E57488ECD6B9B5699 -:10F05000B215EA4B0F5C40EB9F3699D3E5D2889B03 -:10F06000F4E214211FEBAD110BD9DF3F5118F2016F -:10F07000F44F7674237C945331180F28D70DF41075 -:10F0800049A8835D34A593CB5506F29C25D84B52F5 -:10F09000DEA31C6749F69F913EC2521F71B9C7F4A7 -:10F0A0006C947B522EDFEB0A74B949AE8DCEC6F557 -:10F0B00085F5E47273BF42786D622DA44FA41EE8FB -:10F0C0001F57E891D36A98EB2BEB262A5F7717D16D -:10F0D000784B5927E913A95786A383D7BF840E7E9F -:10F0E000867400ED8D1FB0E865305EE372166D9A90 -:10F0F000C84BE744D28F5C4FDAB89EC432E53CF48B -:10F1000065B27E4CD687C97A30DBC2F59D5C6769F3 -:10F11000CF644FE776C094E51195C1FC36A6F93F60 -:10F12000CE9C3460D784DEB2D9F40BB11E60A3E06C -:10F13000BDC569D36ECA86F690C6FCC857A980972C -:10F140009DF07CBBB07B6BB339DD7B2D9C7ECD5AB3 -:10F1500080953B705D62B4CF8D673217D2A3C4E750 -:10F1600076277C5781DF71FDD4FFBD8DB5A5247C4A -:10F170005FFD9C9DE4EAE7CF3A2356B24782856E55 -:10F18000E82FEB5756B2537B9F73923EED15FAD0A2 -:10F1900083F628D1CB2AAE5F715D272135558F6468 -:10F1A00048FBCA352351044AFBACC9CDEDACC1F6CE -:10F1B00090682F8A5DCFE9CA4AFBCCCFDD3D7762EC -:10F1C0001DE061689FFF8F58E7D081E9E5DF87E7A1 -:10F1D000A180C3C7B11F2C477AB5AADFB9DE06F4F8 -:10F1E00035435D1EBF0BE6D194EF70A19EAB29FCA9 -:10F1F000F52F6F84FA8707CCCC8AEBBC677A1D1B8E -:10F2000035BCFC5D12319FE849E0975BF619EB4D88 -:10F210009DC67AA8CB582FC8707A4E4F20D9E1FBF3 -:10F2200033D0B5D5DAF2C14E80D7FABC95F4D1A768 -:10F23000EE607106CA5B53FC18E2D95AF8F144F447 -:10F240006F84BA3F51B0B402EDC4CA38FE91AF3FEB -:10F25000B7CF2B740D81B701FC319B89F00CD63AE6 -:10F260002F49CE85049F782CFE0F5F84F92F9A9D3D -:10F27000E2BA9B9EF8674EAA427B926064A12D572A -:10F280007F88FB2D786F09AEFFE959F01EC0D5B01D -:10F2900085EBC346164B43BE6D06BBD3064B7C477E -:10F2A000065F875BDAE25551F8DF8E8CDA7108A7CA -:10F2B000F6272D80F4B11AFB4DB093AFCDE07AE084 -:10F2C000967D76D729031EDD867AA82BC7752A91ED -:10F2D000FF84FC61798A96B81F7A57095E8BF86BB8 -:10F2E000B2F558A6C1F857FCE93392F78B97CDA732 -:10F2F0007DC4805D6D25F9B4F8AE203D7F692BDFBC -:10F30000179EDE6AD711EFA7B7F3FDE3E23C47C4CF -:10F3100006FF7B859BDBDB8BE13B45198CC764BC1F -:10F32000BDFFF0555EA4A3F7191F2FDCC9ED8FF7C1 -:10F330005D80AF62FE0EF6F77E17D8EF0AE2F9AAFB -:10F340000F512E2EDEAEFAD04E60879CE48F59BC52 -:10F35000FDCA710B1DD8DFA723A6A15F68C795E87A -:10F3600089C2F70211EED7895D01CFB51D17931D34 -:10F370007774BB95C3E9B6EDC5795CF12795F84A7A -:10F3800033B120DAC71D16FF38E467FDE13D337065 -:10F390005DDE9F956BA2F71F57980BF1E15E968596 -:10F3A000CF172B5A00F9B761CB929989F64E6A862E -:10F3B0004AEB35AD7079568F83F8E97AD4A34DDBEB -:10F3C000817F70FCD96FFFF2464F223FDD5EC54C56 -:10F3D00009F6CBC35F237AC2BF28E06BB1C0D75711 -:10F3E000E52B6BAAE48B961294A38BEF6E29710D1B -:10F3F0006157F4F3C5C39C0FEFCB50B8FF202FC368 -:10F40000B0CF186E5FE62835915EB1F9987F0F9402 -:10F41000D9B02DC6FDF7810C8DDA0F64707B5FFBD0 -:10F42000DD6DFB5E87794DCD086ECF807A21F39735 -:10F43000E3BAEB71573598B18862B2BBD8C3566E48 -:10F44000C76ADC8EDE9CC9F6AE4BD88F77627F9997 -:10F450002417F6623FBDC7FF780CF1DA5CF0F14487 -:10F46000B40F42E73EB3A01FCDD1AD903C77F80278 -:10F470000CE925D43D8B2D281B90C3211FD713C920 -:10F48000F3FA5306DFEF843C71EAE7FD119C7F3B02 -:10F49000DC9C3EB72D4B213FE4364FC48E40FFB578 -:10F4A0007C2AEDA525C2EF67DBFD945F45FA8E2827 -:10F4B000AE3158D7397FF435CC8DA830CE87BB8B91 -:10F4C000C9DFD977609A4F8536C7EE1FAD198578A9 -:10F4D000EA32FBF07D87AF270DE7F7E1EE9369385D -:10F4E000BF86DD2ACDBB21F249D6C2B201B9F033C5 -:10F4F00025F83ACA01E6521C38BE940F1FEEFE34BE -:10F500006B8183FB0B487F560E8D97A7DCD37E8ED5 -:10F51000DF5F71395F978F1EB74650EE7D6407FD40 -:10F5200096206F3F72727D772A43EEEF3A0B50DFE1 -:10F53000F4D76F2A35A19CF88E8BCFDF63E92C407E -:10F540007EFC8D62EC67E91A138B806C5FB206500B -:10F5500003F2E8A3479F294079FFE19E670AE62767 -:10F56000C097FC9D2C7BE578C26F26FDA81E4B340E -:10F570000FC79BEFB3727FE5307E54F93EDBC2FDCF -:10F58000A17D3EAB8E7428BFEB6B48F1A37DDBC73A -:10F590006C24FFE6770BBFACDF3FDA83FB18F97D05 -:10F5A00052FF151E4E4F4A9742FE83D4B238C9E32C -:10F5B000BF59DE7B603D13E43DACF3BF215F34D91E -:10F5C000E2C74632A20F0BE2CDD2ECD0503F65AD80 -:10F5D000E4F415BFC344FB2A4BAED781F2EC8A9208 -:10F5E00094361330A227256D22C601F2734BE9FD34 -:10F5F0007035A7FB7016237F5B0E6B51485EBBB85E -:10F60000DF3E6F3273AD83EAAC11DC9EF132DF1660 -:10F61000B598D65D41FF90C487D40B483F281F3F63 -:10F62000526C443F4AB74276A76AEA9C8BFD0E476C -:10F630004F1347C8FD3FA7A7FEFA3F899E268F18A4 -:10F640008E9E823AD193D736343D093FF179BFCFB0 -:10F65000C201DCBF660B7CDD27E44EFC0E9BF49BF5 -:10F660002B38DF99A2BF9936475445FDE1337F9C83 -:10F67000E8FF7D18EC5FDC27E5A0FD0EE5C895F3FB -:10F68000745A3716EB417F41EAC536D28FF79A623A -:10F690004568AF648F6FD98F74913DB7AC6225ED2B -:10F6A000FFF2DCA80F50B7921F745975E0D488049C -:10F6B0007BE110DFCF34DFE5A7E7D3BBB97D101ABC -:10F6C0006D217B38D4A584719D9B039608DA416B2C -:10F6D00015EE5F096FB0EB3CEEA3AFA0B8CF0F748F -:10F6E0001E178A48FF6FCF8EEF23BD3538C8EF91C4 -:10F6F0001C3F3AF885CAC71FC368FC8E721EAFEA6A -:10F70000B85AE7FE15B17E1DB3FC396EB407D618A2 -:10F71000F959C685FA9C8018186FFE7A3BAD43AE46 -:10F72000CAF1CCD26D5CFF0C960BE467CE9A2C1616 -:10F7300046C46FFAF91C2405D67345BB8C3739CB08 -:10F7400002456879BFBBE9B7AFA400BD66A19F8E33 -:10F750006FCAC268F7937F98D7C97DFCA00900C91A -:10F76000C5D6FF5C577369425DBC3FF0FDDC6B6B37 -:10F77000F248EFF6B723D8A08F65DD6FD7311E357D -:10F78000D0AE81BD6BEB52F8F761C7B5578E063C22 -:10F790002872FCFF5CEB477FA19D19C64B844F4B41 -:10F7A000EADF0CFD3B74F97EBCF64A78E1C10A59E8 -:10F7B000BF66AD1FE0BBCF6CEC8F502ABEC78A1C62 -:10F7C000EFD6AC6DEBD6E70DD8056027EC1A913972 -:10F7D000601FAC7E7B66FB853056AAEB530BEA5D5F -:10F7E000A9E7431E85EC8F647E3D20E4C3DF2C57E0 -:10F7F000F54176F4811124577B66204BC2FE83E4E9 -:10F8000076687980A13D07F64817C2DB7BFCE3D31D -:10F810002F427BEFECDF1F1BA9E37BB7CE45BB3745 -:10F82000744E23BA0DED53230AD0AD4DF00BE871A1 -:10F830008A0B487A5AEA1274EA0E338C73741C529B -:10F84000268589BE5A0AAE83B5CCF7F85F4238E404 -:10F85000BE3279DEBF1EC1F70FA1D2EAAD25D8FFB7 -:10F860006E85A19DB0AEF444D602DA37BD9BB530AB -:10F87000E1BB255D0F123E97EC330F89C75F8FE028 -:10F8800071DEE6679FF6A3DCF828A2904C68D022D0 -:10F890006BA740BDA1C1849620AB8CCCBB91E21C70 -:10F8A00075163606E67704ED268463DF37C353709A -:10F8B000DEF04F8147DB028B489F6EABB339284E99 -:10F8C000543AFF56C2832BC58F7858575A9D83E30D -:10F8D00034CF9AE1A2F808D871D8DE7CD7B7C82F08 -:10F8E00024E15AD765AE453BA70AECB9A700EEFC68 -:10F8F0008C6B6A7DC0C723D5FDE5B73B305E3EB457 -:10F900001CFF6E26A78B362510FE4625F94159A20D -:10F910005FB3B08BDB8D9F8DB018E22B9F8DE0F62F -:10F92000ECA5E1D874249FC35A4F2ADAD321E6FF0D -:10F9300004F7CF2CE0D0F7D03A7179E469D5C93F0C -:10F9400066F3F4DC7B21B65FAAD1FE85693D0FE04A -:10F95000B8BD6B3DBE754CF001D6EF2AA37D4FBDFF -:10F9600027A87832F9BC707D7B9FBDAA1CFD88D288 -:10F97000EE5AFBA89DF4E65AA77E7F2DCAD3DF6915 -:10F980003C1FC0168F4D877E96FE3E83C65D6B8FF3 -:10F99000ACC5F50FEF54A9BDD8117460BF4BBEB90B -:10F9A0006522D22B73444A508F9A3DED0CE918B66C -:10F9B0002BE42FB179020CE3C4D3C3F33405F5452E -:10F9C000923D331DFD55B45FF190BFB65AF0C71894 -:10F9D000A082D3366285B63F8F18B06F5EF9E31C04 -:10F9E0000D1F4ABBC764E3FEF39ABA1486F62D5B7B -:10F9F000153F66427FBD27C6D00E6EEA54689CA6AE -:10FA0000D2272DB86FB9A593F37748EC33007F0563 -:10FA100068578CF1A40A7BA08DFB3958ECD848C4F8 -:10FA2000F3637C3D1983F712FCAB8CADE0F240F43C -:10FA30006711718626E157024D48ED3E8FB45BEFAA -:10FA400016FDB7F3528CBB5989F955C46BB962F0F6 -:10FA500087CBF22AF17DFA91F80CE4DF38D017FA5F -:10FA600097B62AB36EFD29CC6FEBA4F13E34C1BC2E -:10FA7000404E6A053E075204BC57767D3203E98644 -:10FA8000D532E2D7E6AE696A9383C76FD05EC84EBF -:10FA90006DD989EDD93797927EC6F8C86C78FE3556 -:10FAA0000FE7B31C07F7D779EF0E1761BC33FD489A -:10FAB000E0D69FE2F817A490BF351BD6C69941E562 -:10FAC0001AF46F7959F98BA87FBD33F50A8447C6BC -:10FAD000F5302E38AB8CE438D5337C8A7F179437D9 -:10FAE00078DC340EECEF6A115E7C1E710CC419D107 -:10FAF0006F87E3621C0FCBDE9CA8467E7ED0E77B3F -:10FB0000904EBBAC2EC4D7CCAE97DF427D3BD3C664 -:10FB10003A29EE9A64B7C4D3BE19443AED3B737ADE -:10FB2000C73D08D775077D94CF92648F5C7139B754 -:10FB3000CB3FDA93AA233FEC12721BEC471E7F796E -:10FB40009CEF2393EDC8EFF6AF2FB723FBEB7F7746 -:10FB50003B92C317DEC3F328A47C0F897D5F5FC38C -:10FB6000D934D45F2B3DD2AE4DCAF7D82DF23DBA71 -:10FB700087CEF7D076F2F80F864149EEBA2D22AE45 -:10FB8000E5F7CE43FF87BB84E4C02B7B53C34837E4 -:10FB9000673BED6497696E4B14E16A7BDA1AC13CEE -:10FBA000883645E0EB90885759441C2CA344478382 -:10FBB000E2A02540723FFCA499C7ABD2228FEE850C -:10FBC0007AE3E11C11CF62D47FF8D954C277638AFB -:10FBD0009E8EFD37FEFB088671AA3E180FD7F909E5 -:10FBE0007B70BB87E25ABC7FF68255E7F1B3688928 -:10FBF0001BF0B033C2EDBF93A5A6A805E6BD93895F -:10FC00003C9FF532AEC5E7D9B761248FCBA03182D6 -:10FC1000FBB2B5DC5F542FE35587B91FAE5EC4A5B8 -:10FC20004ECE5EF408A658B4292DB5B84FFB7CDD46 -:10FC300034F29FDF79FF2C2AEBD718FDFD8BD03FE4 -:10FC40005F3C103F967EF7F9CC67E1F6F380FFD07A -:10FC500004F68CBE46AB46FD59C45C77A33ED0C3C8 -:10FC6000B07A1743D906251AF10A6019DED3D67A7D -:10FC70005270BD57B799486F85DB4C7E7C4FD2CB15 -:10FC8000AB1EAE67DFF570BD03A88EE038B26C33F3 -:10FC90008B7883E86F053345B13429BC5CEDD26ABB -:10FCA00087D2DFB2BF36738B6D1ADACDF926F277C1 -:10FCB0007F6EF1D791BF38A384D6A9CDD9B2A696CD -:10FCC000B7132F7D6E8F07A8FD328D1B964CCF404A -:10FCD00079FA8287C71792F1B6B0DD584F8EC32CE0 -:10FCE0008918EBF52C3836A798C70D129FBF20F462 -:10FCF000C4E7EB8A04BE7D1694BB72FE2BF238DE9D -:10FD00004CF9BC1C955F5D8774300AE3CA45587294 -:10FD1000BF2ACC84E01F75994721FA4882B7CDCD20 -:10FD2000E929BC96FB21FF5AF893E1FED09325F810 -:10FD3000D8EFC5B865BDCB4271E8F3F597A4641A56 -:10FD4000F7B7FDF5BFFFFE96EFE7D7AA22BFC6457E -:10FD50007269BE8BCFE5A4E2DB1BC5E70EB01F7056 -:10FD60001E6BD50A9423D3BFE9A079341F063982CC -:10FD700071ACE53D05A8D79BAB7B4A305E938C5FA9 -:10FD8000845693F20CDE9BEF81FD08DA0D6B8CF14B -:10FD9000B8C1F1557F616626EE7B4EEE7F19F5D72F -:10FDA0007E3BE92FF8BF17ADC8FFCF16915C8B38AB -:10FDB0008363312E144A89EEF87111DA31DC8E6AD0 -:10FDC000EAB6EE443B717E5B427C0FFFB3DE18EF78 -:10FDD000636B32C8EFCE3A8CCF1B1E4EFA6E50FCCE -:10FDE000AF9DD665B325380EF91DF410E51D9C595D -:10FDF0006262B8BEF5AA6F112AA93376A37D7EC6CA -:10FE0000C9D76B46A6D43F3EB2BFFAEB83D6D957CB -:10FE100082EB5C6F62C1C47E9A709D617D1BC53AA6 -:10FE20009F79FAE2125CE78FF75F5C82EBBCD9DC6A -:10FE3000EE47BE297507AF41FC9CBA3240F615E685 -:10FE4000EF201F9D2F3DDE94448F37FDE3E8B12E58 -:10FE5000311F32593F36F4E3CBA81F3D163D0FE565 -:10FE6000C17C9BF52FEA49FC1BD29F67B392FFE34D -:10FE7000F01F3FDD48F918DD2AD927B2BFC35AB0B9 -:10FE800018EDA3C36F797D6165F8FED385FDE5B5F7 -:10FE9000B130FA59E4BE40DA97C9F278B998CF0385 -:10FEA00099FEDF8CF81BE23CD27FDC20DEB1453EC0 -:10FEB000E576EF6EC5C7FDC79DE44F6E3E34CF8536 -:10FEC000FEE20F22DC7FDCFC7439F98F97445E8AF6 -:10FED000623E19EB565CB81F59B2FBDD34CC03907F -:10FEE000FB5ED8E7DE9F49F935C6FDEF07919369C0 -:10FEF00098370070BF8F70A77AE216A4FB66D8FF10 -:10FF000061DE60B3163F86FD367B18D905955DC668 -:10FF1000FDA08CEF6E0B5848EE6EEB562228AFB367 -:10FF20002CC1A23CD46B2CCF753A7580CF2299FEA0 -:10FF300017907E07E2EAFE5D5897FEA79EADE94462 -:10FF4000BF3D66E677A13CDBEA14F24C23F9F6DB11 -:10FF500087DD91750976C36F23DC4E5822F3C134D7 -:10FF600016D560BD16CDF11FC7F546791F4D92F726 -:10FF7000897519AFBF8545492F35B19EFEBCB0C408 -:10FF8000F792E3F9180737F4C35ACA75F493DDE41E -:10FF9000F0519CABEBCF56637B98EF9B811F96553E -:10FFA0000CD0AF5C0749BFCDC21F1D6A38B10AE94A -:10FFB00037D4A5B8707FDDE8E3F4DB08FB2FCC9BDA -:10FFC0004DE677D669CC131D8EFF7FDDCF779CFF82 -:10FFD0007F3DAC9CFAC7F85BDFEF973F9CEFE5FCF9 -:10FFE000A5FFBE7F9EDD0AE7CBA47925EF5B93FDDD -:10FFF000EE72DF79BEF2F08B247C7CF10FC6C77005 -:020000022000DC -:10000000F230256BE8FD42725CE3AF9687FFE0F8C3 -:10001000C623871E4A3381A8585214F672BBCE6F8E -:100020008817CF501D7E1E3755793E4572DC5D9F87 -:1000300021E2EE9C9F5F7A5AA5F56A12F1E1A64390 -:100040004E1FBEDAE0584CF1D9E4F8E952B67F060B -:100050002E51721CB511F9B8F8CBE3A91765393DDB -:10006000249F745684790AC9795A2F393E1D114C40 -:1000700058EFEA32D8080C41D7362DCC32129E4FB9 -:10008000CBE2F6F44B229FC86BE1E705EE73A6FACC -:10009000711FE335F17CA77C4F607AD62494EF0280 -:1000A0009FCFDEC04C809747CC9D244FC24D0E1F82 -:1000B000CA3FE9C791FDEF10718BF3A5F36F671984 -:1000C000E9BCBFFE4FE2FB8592BEFFDAB8DD16C089 -:1000D0008D811F18D1EF6B18672A1A4CB7C3F533FF -:1000E0001CFD2ECB0ADC9E4578F14FA4FCE6F39470 -:1000F0002FA995F193E82F6207AC3AFA376DE2FC2D -:100100000B5B9F23F6EBBEAA599497CDCF8FC87394 -:1001100036C3D98F1BFBF99FDB8FFDF5BF93FDC85D -:10012000DC81769CE7A9697ECAFB5FED04F8715F0C -:10013000F8A875C8F32CF2DCC597F95DF6F6C3CDC7 -:10014000E96AEFB070FF63E5E793FF34F9F9FB3438 -:10015000F4A30EDF4F58E47BC6FC229EC67625F83A -:10016000B743319EAFF79280573E7F44E8C5F46CA9 -:10017000FF515CA78F8FDB6C2C1D4C9E4A2E179B6A -:10018000030E8A2F3477F2BC97E6E58CE47733FAD6 -:100190004FCBD0AF388BA1BD373523F833FC7EF57C -:1001A000DB8EB09A8E7EF7D90CEDBBDEE3BCFEA9E8 -:1001B0003BF8736C0F2DEFA17846C7EC8F28EFAAA0 -:1001C000EACF9FAEAAAD2478C98FE0B11ACFAD7C3B -:1001D00091C5E30FB2FC43BF3CF1935FFFE3069E82 -:1001E0009F1DF2F85DE88F907EF1543D467EA6E6B5 -:1001F00003DC68AB52F97CD8F7F3889E9A0F4C2B3E -:1002000047FF29EBB497A39D5BF52B07EDF73EBEA7 -:100210002B97F224EA3DC10F513E3A2B2357A35DA1 -:100220005A08E3A0BDFBF1FEABCB116E29FF36A34C -:10023000FF1CC6DFEC34FAC7998DE7D92FDD9B4F41 -:10024000FBCB6247F053EC6FB39DC311DE23CEA30B -:1002500008BF7932FF4BBECF564D344EF6B76D1402 -:100260002F977261B399056DC503F2E478962EF26B -:100270004C445E63F72C9EA722EA0E8F31BFF381B8 -:10028000CC2B8F233CC7B3B4AF961FE618942F40F6 -:10029000FD627E18C505589CFC2DA9E7B81D3DCA16 -:1002A00065217A7202DF519C06E809EDF94BE3B152 -:1002B000E9789E6B7447F452C4F3E17326C2933617 -:1002C000EB358AD3A42B7CBCE2F53D6BC7A21FC6DD -:1002D000F5E665B8A47ABBAB1A513A3523909F4D29 -:1002E000FB8C96521CAFFABFCC3C9FF2502AF917F8 -:1002F0003A0A1A299FB2F76DABE13C4E7219667744 -:1003000053FEE4A8AE5F50BCC0794019322F76721C -:10031000B683F0D61C8ECDA01C9B4B3D2467B54305 -:10032000BFA238B5B6564309C4DACC7E139E430B40 -:10033000AF60E4EF1CD3E132E17A158AFC98BEC3CA -:100340007F9818A4FD8A8C0F44787E93B96715EEC8 -:10035000C3B4153D9787713D0EB84DCD65D85FBCD0 -:1003600099FC2D875219D24F6157F1DD53A15EB828 -:10037000C645F1B0BEE76E2924FF2ACC73CC10F33A -:100380002CCA36F3FE0FA59A509F699B980F47D54C -:10039000DC59D504F78350877E468A3C55193F4582 -:1003A0003F14EAA9F4ECE0D7303FB6FF1CD2B214F8 -:1003B0007E0E49E3FE12E7B2B71FC7F33D3B2CFCAC -:1003C0009CE791C3136693DF6FADA6E03A7CEEE63F -:1003D000F99437669B0CE74206F07F84F256471D7E -:1003E000FA05D76B3016F6AF9939BD686B3D3BD136 -:1003F000BFB8382D4879BA97B545558A9FB94E3D53 -:1004000050AB27EC73B6703DD3BC8FEFCB93F73571 -:100410005FA65F6ECB36DA2DFDF57F92DDF283FEAF -:10042000F1FFC6FD0A33EEF392ED97E47DDD203B4C -:100430003CA9BFE1EC18998F523D300EB7A79DD271 -:100440004E0A1BF275AA1DE27CA1CDD8FFE5235C04 -:10045000345F99BF93B5525F8179FAF11F30F2D7BB -:10046000C93CA27035CFF7099B6C74EED0CBDA296A -:100470007F68248B2A0AF9D37AE87C6D36E611C1AD -:1004800077EBB24751BFDB996F8D4AF25257106E2E -:100490003BE69F50BE6A64EB221CE73A078D63C7B8 -:1004A000FC938B3085C0BF15E5EBF4061E5FC805D5 -:1004B0007D8CF49B3B9AD3A1BD8EE7A1C83C1399D8 -:1004C0001722F1502DF09B3B765111CAC1B54AF06D -:1004D0005171AE99CBFF0D4E715E19EC6BCFC079A7 -:1004E000E43EC6FB0F3798F8796437AF778CD1F9C3 -:1004F00079A02FF839BB8E729E7732283F2509AF3D -:10050000323FE5C9B4E011E497E4F3CB924E12D642 -:100510008FCE476F3BC4EDFAEA060BCDA36FC9350A -:10052000E497EC5B6262A8FFABBBAD9CEE92C6DBCE -:1005300056676151EC578BD8517ECAF5FF32BB1616 -:10054000D6B514FDBE475A6B2F3A05383EDA1AA0CD -:10055000B2CFAE74AA17D2F9D2B928A99ED8F2F9AF -:10056000B55A0EE6DBC40B142099E7B77E3493EA44 -:1005700099F177B0FEEA16CFD73490C37D63E23BA2 -:100580001478FFFF797FC4DB911673197BF7A1877D -:1005900066861D5F41DFFD9125E7719C41BDD3C497 -:1005A0007A56C5C85F24F45D2597875E8785EC255C -:1005B000AFC83F6535221F15233B505F99534E71DD -:1005C0007B07D30FC4B03D8F9FCF8276A2FF956388 -:1005D000B87FDA26E882E549BF544F18E5DBCA2226 -:1005E000377DDF2F8F0F5823DC3FC6C77FE3E90B32 -:1005F00028BE25F36A1973E5CFB980F26C0CF5FBC0 -:10060000ECE21CA6E6CAC773EC2BCDC2EE15F5369C -:100610006730C58BF3443E047BEE8D2BBF5B867C3D -:1006200074E6E0F747A35CBBCA02FB8221E4D8EE84 -:100630001C2EC7FACC8E350A7C57E30C8EF0C2FA1A -:10064000BF953A77061E29A81B31CD82471758F867 -:100650005115F19A29E8C43D87C3E7AE0928987778 -:10066000BAD2CEC7CD0C6A7E3AF7109CA35C077055 -:10067000AF54B8BC868FD2C98E2AD5D3F11C61A3E2 -:1006800038D7AA0AB97149E72615EDF59FB7BE35E7 -:1006900055D306E0FB858887FFA2C8783EA2DCCB55 -:1006A000ED6259CE56F50B90FE56ADF0BC36F31206 -:1006B0007CCEE9F8CAB4659598A77D556A4B25FAB2 -:1006C00069073D4F87E76509752B7FAFD1162FC0AE -:1006D00073E60BEDC149888FCFE7BD7B27CA873B07 -:1006E00073DF7807F324DE300B3991AF88F5EE988D -:1006F0009E06EB79ACD82DF23C6C440FC7C6723F16 -:10070000647F1EDB3885F2FA66CEE1E749AF65B15A -:10071000B61EF89E9C15D03E637211D9913345DE0A -:10072000C58CB70269E8179871435C43393A9C5D00 -:100730007495D7ACF724F0C3D5BAB17E6DA9B1FEDC -:10074000359FB1FE8DC97F1A9B587FD9EE9F8DF4DE -:10075000F4BCC2F33EC3973017D1BD4709A3FD32A5 -:10076000E1995C710E97E727FEABD8773D3399513D -:100770007BD63EDB2E3C3720FDD7AA689FE065B6CE -:10078000C20C7EEF03EABBB822F21C3D14D3610712 -:100790006F75713F2EBC6B817E0ECED3893FAA460A -:1007A000DA52904EB21C267639F252A58DEC9A237D -:1007B00082EEE4B9EA2A8D0530CF02869C83E51BE0 -:1007C00066D78BE8A70E7FC818E7DB691AE55B8A56 -:1007D00031185B41F587045D1F91F2FF079A585766 -:1007E000E04018EFECFA5C1E872E65745EFE6C65C7 -:1007F00009D525DD4BFE01AE1E8DA14145F427E94B -:10080000F9A74E0BD1837ABF49F8BB34130259EADA -:10081000927080B8C9423DC9C8FE9571BA7C9B6C84 -:10082000D7FCF87E0E93757EDE2B4BD4A1296AAAE5 -:1008300040FDFCF2EF487F3B7C419C8725CD46E79D -:100840009386E3A35D827F7625F1914BBB9AF8E80E -:10085000A7CE923B08EE6B9C2ED4AFA53097BA0C76 -:100860002AFD232AF03BCE4F6A8A4F47BEF966ED38 -:10087000F1A95A829C86EF9BF8F7A9C6EFBDF07DDF -:1008800046C2F769F07DD9E0EF773B6D51D344EC78 -:10089000A74AEF217D18A5C95E23E6AD66F1EFAE4C -:1008A0001179B1A3D3E07DD45BA5C63C1336D967DB -:1008B000A3FCE4A4BC92AB94E539C85757DB9ABAC1 -:1008C0007BA0BF97C53A5E650A7EE682E72FCF2DF3 -:1008D000398AFC576B8B6898D7772D8BAEC2C5EDE4 -:1008E0009B167CC45D4CF2E159E4936635383603BF -:1008F000EA67CCEDA36F2D22FE79CE9B39185E49B5 -:1009000027125EA417A43F492FC970F7AFE7D73B62 -:1009100029116F3BD851584ABB8AB1169E77ADE773 -:100920000FCC0B886886AD6534DA352F2F0993DC40 -:10093000B8CAFD00E565BD9C1BFC4F946775177E2A -:1009400052A0E1CBDE796371DF00F0C6FE37E1959E -:10095000F6E3A0BCE30F2D86BCE3E1F84C8E1B420E -:10096000BB50C5FCE49D94471C9AE3F0E1799110DB -:10097000E6C15652FC8AECC2E7146E6F87159BB035 -:10098000E3CE373F99717BAFA9DFDE33E4D77794AD -:1009900073B83B6ED5E5FD35DC5E9CC7B83D394B81 -:1009A000B42F7451BBCCC3EFD8C9FD861D4F8FD572 -:1009B000B15FB003C97E60E9C2CE2C32DE9B837F7B -:1009C0004AD640DEF86633B75FB7997C5594E76244 -:1009D000E1F7E29C91FE8C317CFC64FF626E8E62DA -:1009E000884FF7D7FF4EFEC55277303F07FA5B5866 -:1009F000E62F504C0817F733027D3E1C6398FED655 -:100A0000321AEDFEAB59CB9BA662A2CFE21CA4CF5B -:100A100009409FC506FA1C9D93C9E524C225E9B388 -:100A20009F2E4B93F3CA8217603F1DEECE5F35A316 -:100A3000BDDC6DF5F1BC5A9E27982C0712E059A039 -:100A400071783CAA4AF04CC27193E1391F3E49A427 -:100A5000CF6CC6F961387EC9D658D85931C02F2F0E -:100A6000DB8335087F3FDFACE2FBA34170AB0EA216 -:100A7000AFEB6FE47194502AD747184FC981F167E3 -:100A800089F1AF5FCBE9F0FA7FB110DD02F8518454 -:100A90007FB6689FD5DD447954B36BCC2712ED0047 -:100AA00019B7A913EFCDF1949B9105E6CC34C64B51 -:100AB000EA6EE2F19AEB588B19E1BD7E8EB19F3A56 -:100AC000B6FE13CC0BABBBC9F83C98D31F67198B90 -:100AD0007196A3C28FD007FC82FCF4D3CCC50FDF84 -:100AE0000AF43BF6876515E877BA326BC9EE4D50CC -:100AF000FFF1B6F154FF69D6B7BFF306B6EF28A1F0 -:100B00007A0D26B9E13E08F911F54DD58DD714C1FE -:100B1000B847EDA2DF5BF939026F4AB06316BCE754 -:100B20009D388AF2216B84BCE95BC8DBAFBDD0C9BC -:100B3000535E6FD6C9DF5893C2EFF579ADFCBF2B7A -:100B4000303FB76694A8573C3F1EEB47954FE81ED1 -:100B500080DE268786F86FCEE57EDA09A54A741C0A -:100B6000E0A52643F4DFC4E735B3E2D15CE48F9A15 -:100B70006ADECF04DFB4B5C5F89EE92CD57B736D72 -:100B800069280F259FB5E770FD2CEDA980E0FB6774 -:100B9000FCEFB68D807E0336C587530C4C7E97DF05 -:100BA0005FE5E0E7CB02FE220DFDBCD3FD3C7FB349 -:100BB000DAB62207F7E75F0F5A2A715E2E5BF9510A -:100BC000B46FD2274F9B44F9BE3666463D0774DFAB -:100BD000417C78F1270569486C0E23DD4BBA9A25D4 -:100BE000E9BDC648D7C0AFDB7232BF5C5E1BE8DA36 -:100BF0003E40D7C3D9B900D78F09AEA946FDD53F2E -:100C00004E125F268F3B9CBCC0BF44793A005F27E1 -:100C1000F15F1E66C515237FB64BFEEC42382CA64D -:100C2000189DB329547CE3E960EA307686842F1F4F -:100C30007DAE1583E1C23F4DDA7FFCCF83FBF23CF2 -:100C4000D10EDFF959C6005C30FE2B240F577178A6 -:100C5000B62B2D5CBE087B5CEEE79BE57CBB8CF382 -:100C6000AD4AE1E7DEBDE87721DF7BF9F87EB8CF5A -:100C7000631DE47C42426FCFB1059C1698DB75EE94 -:100C80007AA29F1B58F869B48F963983FF17F174C5 -:100C9000C4143E84FB9C85CC4FF157A08F77721211 -:100CA000EC0D096F329E9A8791A7C9F349C6CFC050 -:100CB000BAC5C8BE93E7D8FAE77B9EF3947689C796 -:100CC00062F4776508FF5486F0472145A17E9EC9EE -:100CD000527CB82F98EE53C8BE98C96C249767D63B -:100CE000727D9EE1E0F687D4FBC3F1C7159733927E -:100CF00057331B993837C7E7954C87D9ACE70E2C8B -:100D000067DAF4AD0B90EFD14ED107E09FE9E07EBA -:100D1000ECEC5C213F58CF24D4F3FDF5417ABE675B -:100D200012CA9FE4FBC9669EE3FED28C738CCA99FB -:100D3000BE7727A19ECFA8ED998472CCE9F27B7390 -:100D4000270DDC1F988CC7D1B92619873B2FFA4C89 -:100D5000E61F193F6B7306C7E238D2CF714689553B -:100D6000E14B151E97E83F588474EC76154D43FF10 -:100D7000C51C1BE82318BACB15BC3017E9ED8F0052 -:100D80000F6E0EF155C0E37535C17B343E2CE1E1A9 -:100D90003681872B855E3DFBB04AF1891A7FE94396 -:100DA000184208BD626611E2573FE94579BFD8593C -:100DB00030A0A2F8FE634EB23316BF5A4FF195B180 -:100DC0005B4C4C4FD093E32229867B3226ECCB3010 -:100DD000D42FE8CC35BC7F61D728437B7974BCA184 -:100DE000FDA2572A0CF549B12986F72F7EABDA50C0 -:100DF000BFA4E71AC3FB533F986DA883C6D070DE2B -:100E00007B9F55D83698F765F16F19BEFFCDB6199F -:100E1000AF60BCF3A4D8F7B2B03F560A785820E9C7 -:100E2000F6DC7C637F5125AA5421DFF3BF05EB7903 -:100E3000BEF634C05C62BF0BDB8DF6C4E22DC67A11 -:100E400043F7A655281B07E779B454E35539C97908 -:100E50001E35AE7926A4CF502ED817E31011EC62C0 -:100E6000CC331B8ECFBF6CFD4BD8E82F5B7FFEFED3 -:100E7000160BD9F58B5F7DAA2A0A8FAC5EE3FADBED -:100E800075E3FAA7961AD7DFE933AE7FFA64E3FA7F -:100E9000BBFDC6F51F516B5CFFCC8071FDB3EB8CC5 -:100EA000EB9F1334AEFFC806E3FAE7B718D7BB7061 -:100EB00099713D8BC24B0DEDC9EB2FE565F19ADBC6 -:100EC0008CEF017A4D097420E96841A081F277C660 -:100ED000B47FCF304E323DC0BED144F7BFC13E6E6D -:100EE0009B72FEF401D28AFCBDC9F4F16FB9C2EE67 -:100EF000147401FAA813E50AD8174F61593756D868 -:100F0000FB81A1ED0B29BF12F579E2BE7838B93625 -:100F1000484F897DF2B07A0AF7C9F6817DF270F404 -:100F20007B1CB38FC88E5A4F7EA51B5D1C8E4FF164 -:100F3000D125E8CF7D82F4F271007032C07B1CE7CE -:100F400003E31F4F9940FE8D6FB328D9EDFF82193F -:100F50009630D8CD98A8ADE23D4F3A95F5426F2F27 -:100F600014FE8F85F6E05BB9DCEF519885E3E6C5AA -:100F7000E8BC147B6DC479DD237102E30820784F4F -:100F8000611C01CA5E3BA79BD352AEF899EE49C0E3 -:100F9000E7FCE94A29D9B56A0AE53DCDBF4121FD03 -:100FA00034FF7F781917FA2CB95CB94CE2B35DD8DD -:100FB00003DC2E48C7C39A1477624107E1CDE7C22C -:100FC0007586FEB81FFF47FC7CCDE30AD32667D0A9 -:100FD00031335A675C6F3C0FA5DA389C8F9B990DB3 -:100FE000F1398105C90EBC5703D1C6FB1BCFFB7B72 -:100FF0006314FAD354F5FF7CAD06E3CF382EFA9F85 -:101000001D3E86FE66D5EB63E8BF1AF4FCC014BA39 -:1010100024A3BFCEF87BF88778917EC23C412FBBDA -:101020009D8CFBBD92FC86235590C098BF63E6E77C -:10103000C3BDDA16BE9F3CE65B634D9837636637E7 -:101040009EE7FB327B08F36D4F27E4C7C3BA0C79E8 -:101050008FE9B43CAEEF57B6365C8671A25E1107DD -:10106000BBA7357819AEB7AAF9282F0EEF5772270C -:101070007C6FF1407B029F6A8E0643DDEC08105EB8 -:1010800056B5B610DD98C53D50ABF36E730513FC35 -:1010900012178E14F6862DCC5C594C98C6F0F7C109 -:1010A0007486F3555DDAE9C47DA8D50BFD25CA2BFE -:1010B000AD9025FAADD7B4B610DCAB9460103BB35D -:1010C0008E66513BE0DBAAE1595478BEF52A92675F -:1010D00016E76D3EBCF76738FC59BDDAE78972C880 -:1010E0003FD22887EE6FB55D8EF85AD9BA8CC69379 -:1010F000786B6F755D8EF58DAD5ED1BE82DA4DB5C4 -:10110000BA82F4711A6821867116ADC789713DB033 -:101110003319C603CD5E5B0499C8EAE1F0B2A305BA -:10112000441F735D1C06F48DE5037DBCB3CC4CFB02 -:10113000D3DBF31DF4FEEDAF8F79D10F7C60011E80 -:1011400051FF8AF9F48F23F06711728869C100F2A8 -:10115000952557237F74866B36ADE3DFDA9FC4BBDA -:10116000C5CE281FD492EF20BBEB7CE10C8D14F789 -:101170005009BC27E30FF04472F47681A7DBEFE25D -:101180007EBEDBEF6094C7CE96C15FD5005D8D1447 -:10119000F2259B05A86C6F05C15282EB6563410B7C -:1011A000E875D6492FDBD1BF83ED7ECD8DA1EA4D09 -:1011B000359E59586E9C7CAA1DD9F1BE4B3F8B6160 -:1011C00089BE74C497AB8145F0CC1FC58E3D781D98 -:1011D00035AFA789F6B43A5E4F17EDE9015ECFF758 -:1011E0003FA9D4206049F1977C47C6D5A351BE2DB5 -:1011F00060FC7CB2B8E7603B13F2C29131AB06DB16 -:101200006F6274BE40B6FF50B4E7384EAC29463921 -:101210003CC7F8FD5681876CC789F6E9149F31B643 -:10122000CBF84AA6E3EC2BF47D99B1FD41F1BDD397 -:101230007136361DDB471BC7DF20DA531D3CEF0834 -:10124000C4213F472FDAEF15ED766CC7F14B8DEDDA -:101250006BC5F82B9500AD433F9F89F8E48E569DF2 -:10126000EAC97CF6EAC80C7E8E59F0996B191BF21C -:10127000DCFCAB2379BE4C9ADEE3F70F210F657BD4 -:10128000864BA3B8AFEAB5101D591D428E083EEC3F -:1012900097234A8B8F1317F7977F193D03E17E8EB3 -:1012A000F2AC00FE909EF3BE6362C1047996DB98B7 -:1012B000C28209EF7B176418EA5937E51ADEF7CCCA -:1012C00019656877548E37B4B3583EF1C76D82AE56 -:1012D00052CA2A0CEDF2BE02A6733E9276B579F49C -:1012E00014C37B674BF574A4EDD357CBFBAB7C36B3 -:1012F000940BB7394765231FFEA475321ADF20EF20 -:101300006CA27489D24B47C956B6EAA25E4AF5C7A9 -:10131000DC3CAF7A65AB8FD78B189D6F5ED95A4B8B -:10132000F5C7812FB1FCD7563F957BA00E160EFB5B -:1013300011F4AF433F3BA17FAC3F02FD63B91DFAFF -:10134000C7F287D03FB66F857EB1FE10C085E583BA -:10135000D00F3E7F00FAC7FAA6D600D5EF6BADA33B -:10136000FA86D62095F7B636D0F3B5AD2D545FDDAD -:10137000BA8CCA7B5AC354AE6C5D43ED16A1371FBD -:1013800013E71F1F9BC6CF7D27AF7F469EF2D5EE8A -:10139000BBA804455E65C893C8C8C37D75A7312F37 -:1013A00010F14770D8391E93E1182BE018CF622B4B -:1013B00052B9DCA038EB982EDFDDA9C0A7235BF87B -:1013C000BA1775C5A93DA7818F3756CC9379C22C22 -:1013D000AF8A1FEFC5F77A9558752A8F37931F8309 -:1013E00079013F55E2DC339179C484706993417F80 -:1013F00027CCB31F5F6E0E27E26D28782BF2787C26 -:1014000043ADECE4F79BD4B64791CD52FC2D74BFAD -:1014100089AD2E10D5A0F40482744FC2F8733360E6 -:10142000930572EDDCE54C8732AFD1B8FFCA5D5051 -:1014300061D8E7A8E73632FD22E8B7CCB84F4A19A1 -:101440007D9BE13B5BDEF70CED16CFDD86F6F9B751 -:1014500014ADF2223E47328A3B59D7AF603900D7EC -:10146000C28E4D045750E0BD57D1F9FDEDFBC5EFDD -:101470004408FBFFC72E812FDB7ADAD78E75F36A1B -:10148000497AD884FAE7E3A7D2498EEE7DC444FEB8 -:10149000ED712C6242793301CC486CBF006F7256FB -:1014A000E9CA1C15EBE54C57B17E118BD3BE08EC95 -:1014B000FF3AA417B0FF1FB143FD4C7EF0C73CBFFD -:1014C0002B4A7ABA44AC6789DC076DD192FDC373AD -:1014D000F3C85F633C07D626F6012BDC55D918EF1D -:1014E000ED1D26FFCEE9FDD6D405B01ECE9C3A2ACE -:1014F000E5F30DBA69C873D1CBBE2ABF6C013D625A -:10150000E4976508FF99CA9F67A1BBAA79749CF804 -:10151000A6CD2CE5989E8E726CA0EE4B27BBA23B0D -:1015200087F0A389F5D9DB1AA4FC00394FED77D3F6 -:101530005C980F5622F24FF7B5DE3AB526211F66AA -:10154000B7A0DF5216AB453D5A5A66F245A827AF01 -:10155000C17F611FDDEEC773FA5A05F3A1181EC7DC -:10156000DAE9BCBAF6854A7940DA914B980E76B042 -:10157000C31165E1B2817E99F0837C47C8F5CF5CE9 -:1015800035340FAD40DA473ED4DDEC33873F867407 -:10159000F7598799B3E509637BA983919E5B546AE8 -:1015A00089E80AA623B4D33D8BDA0E85E515211C04 -:1015B000D3BDF3508F1F4C25BA4DDD524557C37B29 -:1015C0004CC1F57900C7991EFDA0491A57F05ED3AA -:1015D00004CB2EB41BC7225E709CD1A584C7856244 -:1015E000BEFB5A57109E9E15F368CBEFC73B87870B -:1015F000F9FC78CFE9A20EE9BF31CE734365F53728 -:10160000F0DEC6953155D874467CAE33C726CE532E -:1016100006E002389F453855849BFCBF7C7E4D8F89 -:1016200070BF19C8B15A8ABB4E32B1C4B8AB2CA333 -:1016300042FECDC87311BC4EEFDCA90B2E4AACDFC5 -:101640004474FDB8C2E71F766A3C2FCDEFD713FD77 -:10165000C4EBE47E599C7F4811F0F6DFE3369EE749 -:10166000613A586C0BE62D0DB71FFE252ECAA4C497 -:10167000FD30E81818579D64A33C9F75328F4B7F4F -:1016800043C77C332CF1FC8A4DD0E96AA731AFE423 -:101690005C1EB777CE89F5E8B371BEC6B8647956DB -:1016A000C2BD17DDF5E4FF9171CCBE6E9E0F2EFD1D -:1016B0006B4B0409F41DE578E87B58A5F8E592EE3C -:1016C0006BF97DA1871EA07B56A12F1DE9A15EBCF1 -:1016D0005FBFC6E8EF59B03BB02A451FEC575AC46C -:1016E000C2E4D748F62725FB917E9B27F6693E5634 -:1016F0008E71CA93EB8B8FA5E07EA688D1B9DB9162 -:10170000EA93748F3158FBED784F292BE3F7F424DB -:10171000AFFB250516C2F33EB9AE631CE467D837AC -:1017200089F3FFBE17CF7E7D0CF4F396AE18CE8101 -:10173000BCA59B098FE381AEB1EC64AC76A8FBA09D -:10174000B2F34D5FEDBCC0A5C6DFD768EAEA3996B3 -:10175000AA93BCCBCA0778FA8EFD3EAD8CF8274E13 -:10176000BF075157C4E141B8F1FCCB7ED3277313B7 -:10177000E9607CBEC6ED837CD35793BF3546B8CEB7 -:1017800094BD99750D876B1CC2D51B3D919568B7AB -:1017900048B8F60F73BFFAA55F154F938DFA200175 -:1017A0004F53FF129EF65B86866796C0CF4F8EF230 -:1017B000FB4206B77F45FDD56184F7CC63B1EB51A1 -:1017C0003C02BCB3087FDE5359143315F8EBAC145C -:1017D000F45929E48E8FCEA8B0D0DB17537E5EA7D4 -:1017E000C6DB43772E8AE07902DF8B0B0AD1DFE07C -:1017F0003C6EA57B9E42497922B25C2FE6B13F57F1 -:1018000019120FABF3B9BC78F1B5F9D4DFBD6F593C -:1018100019CA83ED22DFF55E57A70DEFEF9578C467 -:101820007A0594214B7C112ABA7B2B3FB3E98E2198 -:10183000C633F1F1EE4BE21B399E2C57E49772BB95 -:101840005439AAE23987FB2E7D93EED9BAAF5223E1 -:1018500099FB37E37F7D12FEA36F667D9DD3CB8A14 -:101860007CF4A32AEFA57D03EA2125FEB332C49FB1 -:101870002548F30FBD6D653B95C1786A14F42BE7DD -:1018800027E72FE1765EB680CE99E07A20E0ABC5FF -:10189000FB524FA40BBD87F3223D71A9C6CF894CE3 -:1018A000D2685DEF9B3C85CEF5EC17F914F14B2C1B -:1018B00043FE2EC333026FF79EFB450CEFA90D7755 -:1018C0009BE95E05A6F578BF0974147A5DA37B9A3F -:1018D000819E6AF1DEA8175F3B9B86FBE803F966F1 -:1018E00082FB403E97877DE7D45A3A6FF3DA672E42 -:1018F0003581FE9FCE57855D128BE1399A8D15FC9F -:10190000DC8043D8018ED74E3520FC8EC9DFB32A48 -:10191000097A764FBE95BEDB688967F9300E744848 -:101920006551EEDFA1FBEFFACF0BBA381E9A2B8F71 -:10193000929DE0E8E6F7E23D9DAF135C08F7417841 -:101940009E32EE33573DB657C278A306BE77BAF83B -:101950007AA64CE2F7D0DC77E9CF5D78EF5EBAC2C9 -:10196000E8FEE84B0ACC06395E5FC4D7A1B3321655 -:101970001B85FCE5D228AFB6337A9B0DED7AC917EB -:10198000A347A9F4DD6A9197BE7A7229F199A4E37D -:10199000B905C157916E36025F3C49764E2C309D99 -:1019A000F0E32AC7FCE3C795581DB73F2C2ED42F70 -:1019B000A5269381DF8A0B38DDC812EC52B277EE90 -:1019C00010B42CF57D5BC4C630BFFFB7E766A5A396 -:1019D0005DDA9627ED3CBF0DF1B55D09A417E1383E -:1019E000FFA5D2BEEFC5D74E34E0B86D302FE4DB93 -:1019F0007B7EEA588FF6499BCB4F7C2AC7D7DC26E3 -:101A0000B11EBC9FFD16FF2BE86F8CBBF97D4447D0 -:101A1000A65C6343FA87F74CD8CF7BADF80B1AD896 -:101A20004F0DF90716BA66CFC0EF16B1E02AB46BB6 -:101A30001775A8867B17EE11F262E1B914164DD81E -:101A40001F2C9CFC2D3A37B6F05C1A8B82BD758F2B -:101A500038177D8F3857C40A383D3B44E915E5DF18 -:101A6000CCF7BE24BD95F9CBBDF339DFB302E8B79F -:101A700049E9B114C1101BA7FC9ECEEBBCD7EA62AA -:101A8000D192047807CD73048B268CD3FFDE391BEB -:101A9000CD67607D39FD0ECCD7417878AFD54B78D6 -:101AA0001CBEFF91063C0EF43FCA80C7C1FD97D013 -:101AB000F8EFB5967E49FF1386E95F37C03FD0EF58 -:101AC000681AB7F7C8FC1FA702DF1D89DEBDEDF954 -:101AD0004AFC1D332BFD7E01EBEAACA673848F33E9 -:101AE0003A677AE7E1DFBD83F99A77EEB2F8708C56 -:101AF0003E737CAE6F083D339AB9C2789F972CC76E -:101B00001714D37C929FDBB4880BF3326DA59A0B2C -:101B10007F1FD1C66291BB71DF5269233927E3422F -:101B2000B2DF3FE5A9F23C3BC907796FCB12919731 -:101B300057EC085E81EBBED4D4DEFC13F8F683D2FA -:101B4000363A37CC989BF633326EA3E12FBF15A3FC -:101B50005F30C0F0FCCD137A70067EF74310271873 -:101B6000C7512FD81DC4BCB50D62DFB8C11EF3FA32 -:101B700012E4E60D05DA57B317DA93E876D22FF7B9 -:101B80004639DDDE50807E2235F6C4FC22CCB7ED2E -:101B900011F776E9168A77551EA3FBFEE6CB7DFF8B -:101BA0009AE4BC8E7C37DAD132CE94867977686B32 -:101BB0006CE4F7BED5A7F27AFD7F8CA07310B0FF5E -:101BC000492D43F9B25FE5FE2011DF3A2BE6D067DD -:101BD000DB5840F9F7221FE46CF74B74AFE4D935BA -:101BE0006368FDEB5FF83EDD0BB73F97EBB1BE439B -:101BF0004ED263F5565F15DE5BB83F97DBAB9D5A5F -:101C000034AD22C17E5D9D574DF2F9E335634C89B9 -:101C1000F18FEF0A79B051FA37B578159E67F9B8A8 -:101C200032FA33D2A307ECF43B51A683BFABA2FB3D -:101C30002D375AE97701AA0F8EDB5C87FBC3348D01 -:101C4000F2914D07ED04CF9975FC7E2DFC16E55DF4 -:101C5000D3C191F4FB56F5A971CA276C4AF195607E -:101C6000DCAFFEE054BAD7FFE486710528FF4E646E -:101C7000EA0574AFF1063CF409F54363F9F3B517CF -:101C8000D37955E7C6D4E0507E10A98F92EFEFDAF2 -:101C90009F5BDEDB85F81967F3A1FC7D4FF1F1B89E -:101CA000EF2BF1D93AC515F9F9D27AD769FA7DBC8B -:101CB000FA8E776F62F4DC43742BF773C9E3D50BAC -:101CC0007DB5DF129F8BBF4B56BF52E05DFC4E626D -:101CD000BDA99C7EAF4FE27D63D23DB74F08FD2486 -:101CE000CB93AF69745F20D81105E81F3A79D84AC1 -:101CF000747672E3043AAF2EC7AB079CB8802F4FBF -:101D000064E813715D9F16F2AA7E25DFA7CAE7304B -:101D10007E0C7FE7307E48A5BCAE3E573C0DE3927B -:101D2000F23D59EF9F4FB74ABF97B53FF7455A6FFE -:101D3000A02786F4647AC1497A3AF4827517AEE72F -:101D4000C7952C8CFECFF05BFCF7C78E1CB292FDC2 -:101D5000DC779CEF6F07DD9FE68817E0FDA1A117F8 -:101D600046921CEBCB8FEFE0F6B69DDFABF846F06A -:101D70006211FFCD11F711E6A09DF7F9217B14ED5B -:101D80003C28299E1066BBBDF4FC702A43FF0F94CB -:101D900014CF63CA012FFDEE0C6B17DFC7E8FB3BC6 -:101DA0000B8263512EDF590CFD3BF0FB53F4DEE751 -:101DB000A38217520C8AB15C315E2EF59B1F2CA4B6 -:101DC000E7CA675EFE7B2AEDA23D46ED216BF0621D -:101DD0009AC7AF9C6CE710F3FCAAF7EE1D2D1841D3 -:101DE000EB28E1063C93DD988C97B30526F17B3B0D -:101DF0001C1FC974D9BF9E5F021FFA5FE8BCF621A1 -:101E0000BE8EEBC659B81C593B81EC63D69662C8AE -:101E10009F5B7188DFC3D0BBC149EBDC67F63F84B1 -:101E2000FA28FE8699F17BEDC022403FC5E4A1F976 -:101E3000E523914FBF642DCFB3FBE8D1F70BE63913 -:101E4000F05CF2FB8673C9D25F089DA4A13FC6E196 -:101E5000D3D3E697717B5D25F8F8EF7A6D34EBF418 -:101E6000BB6BE10DE3C81F71D2A21FA4DF875B77B4 -:101E70008109E94A2D17F277139F9FBC2F4BDE7B18 -:101E8000958C9F8AC262927F4D2C7833DEA17E8230 -:101E9000E959C26146F7FF917BDF8469889A9FE226 -:101EA000B6AC85F4C2E07BF62C5FF2BB6CFFBBF5F1 -:101EB0002A5C2BF4EF9587D350AF7EE0E2FB463AE5 -:101EC0007D8F7A5DE5F36CC30F30AF8305A6144EAA -:101ED000A27692871F28BC5DCAB941F3477AC17EBA -:101EE000F03DE8EB9A42EE7F63AE0C71C82B6CC1FB -:101EF0003C4DA99F428A66C273F3A7DC7A1AD2E3EB -:101F0000A9B5C5192B300FC6AD6725DAD5A1A38CAD -:101F1000CE8BEB78DFF8C5F8FB32FE89E8F7DB9F64 -:101F200061F43B24C3F3E4B49EB989ED730AB99E0E -:101F30009B5F28F699854CE45726E38DAFFB62B191 -:101F4000EE6A79F072DA8726BDB7784BBAA087A41B -:101F5000E7EDCF7F97F2A01E36DE1349B15F18EF91 -:101F600083572C61E5422C5328AFBD611397730D45 -:101F7000AFCE2CB98BD7E95E85693BEFA1DFE35982 -:101F8000B0EBCA12C6E516AD83A4C70505FE12B4B0 -:101F9000E3E25B5517F245C31695E051CD3ED756A7 -:101FA000787E7A8B99ECBB0601CFE9BC601AAD9BB9 -:101FB000C6340BE0FDB4164C23FB75ABF8DDA1A4D1 -:101FC00079C07B6F6A1543E0C7C6D799F0533C04CC -:101FD0001DBC61A2755A80BF0B8970EC54C8BF79D3 -:101FE0003A3F7833D64FC1FE1FCFE9AB9B96D07DE9 -:101FF00036C9F83E6D0B127D2E16F391F84C1E4734 -:10200000E2B30FF189F6D22B5348EF851E5491624B -:10201000D98BDD9FD2BE7CDAA12BDF998ACF3781A5 -:10202000DDA2A39E1DF5B36FA39E5BA3528C7AFE27 -:10203000A1E22C96A4AF71FF39FFF53969A6043DE2 -:10204000A93EC8F1A43AE7A42DA4F7CF7E1DE9EB81 -:1020500084EECBAA4878EFF1C2FEB88361BDEA37BF -:10206000FD210DC769586FA679C975E9C379A07CB0 -:102070006B4F8D20FDF7E5C5A95FB94EFDF48DEBE3 -:1020800020E909DEFBAF429718274CF2E85451B023 -:10209000CA37049D2C7A00C6C5FEB638E9FED2F3D5 -:1020A0001D57E2A37FBD055F531DD7714711F9D1BD -:1020B0004D6F6874C8E044FB5505C8C7F5A02FD024 -:1020C0006F51AFC4DFA17B640F59E91EE6FA4DB72B -:1020D000DC8CE3D51FB79AB0FDD4E1AB26125C4986 -:1020E000EB0A782A188ADEFB8AE205BE04FC813DF1 -:1020F00041FC2DE7930037C101FB29BA8FA8AF0837 -:10210000D633410EBC59C8ED2E78DF6521FAE6F7CB -:1021100061F5CFD795345F57D27CDF6444DFCC17AD -:10212000A4F92C78DB6AC2E70BEEBFB604F73DA733 -:10213000D64DA7799DCAF04F44FE3A5500FD0F21B8 -:102140002F17DC0FF32CFB0BF36CB7D37A0D3BCFBF -:102150008CF80EF617E6F989A04339CFF7343D0D18 -:10216000F3F943CFAA0CFD2EA1FCC0C6A9BC4EBFFB -:10217000131732737A086D4AA57CDFDE6EFEFB040E -:10218000520EC078E7490F26A28753D5FAE6C9D088 -:10219000DFFF073F3717B700800000001F8B0800E4 -:1021A0000000000000FFCD7D0B7854D5B5FF3E73D5 -:1021B00066269364924C12088140983C09908449A9 -:1021C00002888A767804D1020D4F798993071042EC -:1021D0005EA0B5696BCD4002A2450D352A5AD401E7 -:1021E00081A2A20D0A0A15BC032A6245C5578BB607 -:1021F000E526405179C6A05EAEB5D7FFFAAD7D4E5B -:1022000072CE9054DBDEFB7DFF7C1FDF669FFD5AA4 -:102210007BEDB5D75EAFBDE7C23DAACBEF16E2E4DA -:10222000DD056FFFBC17A5F7AA2E81FC58DFCD0294 -:10223000F98FC32CFE144A938BA670FE659B6BA589 -:1022400022C489A6BFFD41A1FC857D36B7A0F20B53 -:102250002945F7CE467E8FEA5A41ED2F0C689F251F -:102260008673B9D844E5EA5D239A502E1E1EE6CA4D -:10227000A0F2F20D61426409FEFB56687F23E93B40 -:10228000520BA56B556F7834A54D2FFD44C9A56F32 -:1022900056378F57F3AB24F7DD347EB95558EDF937 -:1022A000A8DC9E392D4788F37B6D1303D9323F2379 -:1022B00087CB3FB052798D5DF85AF87BAD7D6A0EC1 -:1022C0008FE2B6D2388BA90F914AE9FA18EF60EA8B -:1022D0007F318D9342E37D8BBF1F5C0EDF0ECBE71A -:1022E0000B8AA89F7B6D62F673D95DF5F434DB4DE4 -:1022F0001DF6466D7B573B558825C63CE1A122243F -:10230000BF14794757BE32A4BC2AA47C47BFCFA7CD -:1023100014392F1F7F03C61FD185C7120D8F3B2C89 -:10232000F41DEB728F12D844FF2DB1BAEDCB09FE2C -:10233000E7C6889BD14FA95538AECD47BD0E9E5FED -:1023400089553486E5E3BB87EBE9F3A6FE1AC3E2C1 -:10235000281FD1CEE353BD8976439EDA9BE09AAB2A -:10236000C1A3A74BB785BB4EEAF3A07F552DB1A6FD -:102370007CCDEEBEAE93067C2FC57FFAD2BF49342A -:10238000FB91C08BFCABDADD7A3092E8A74DF1CD42 -:102390007553BF170E7E1D9DEDE6751F5944EB9BCF -:1023A000AFA63E7F98E6DBBE47F56C42BF6FD8FD17 -:1023B0004A0CFDE79B8B0F6EA7EFD52FA789BBDDDE -:1023C0005DF30FC5E385DD17A353E9FBF943F60879 -:1023D000318CE6B9377EAC9DE862475C7BB778AF5D -:1023E000D5D65DEFEFBCB5357AAAA1DE79D11A3D1D -:1023F000CD402F25BB2FD68B5CC69F5FCDEFC2EFA4 -:10240000897DBDC7AAF4BDF4F7FDC65A28BD5FC3D8 -:10241000DBBD36F7136B096EFF9E30CF1682FBFCD7 -:102420001BB32D687FFE8D722DBDCDCBE95F4F2490 -:1024300063FC688BA4777DBC356E0BF7536A697BB0 -:10244000EC1ADA8FA5BFEB93D290D2555E6AC9CF52 -:10245000C43A6FB7B52F00DCE715B14689EBEAE760 -:102460007EB79BDB9FDFF3C963E00F27EE1D904F24 -:10247000644DF941B93E2A3FFF5141A68BFA3D7F99 -:102480004F5F0FF8C2769BFB36A6B7BBA23CD8F7CE -:102490007A7F18A716FDEFB962A40FE947125ECA4A -:1024A000E7FAE4B87E25BFABDF688BFBBED1E0174F -:1024B000BFB779B650B2FCEF697D62313FECE76E91 -:1024C000D6A1744D98709BF8C94A86BB4478EC221B -:1024D0004D960B03BD958922FEBEB0C9FC7D11F15E -:1024E000097C5FBCDEFCBD5C34AD6EA5F92D09989E -:1024F000BF0BDA3FFE04EC6BFDAFC55E14057AFF3F -:1025000036CC544FF835FE401F095F25B41FC1C7B4 -:102510009E5102819558DFBB549E67E8BCDE75A7CB -:1025200070BB8722FF6741AB615D8F5B843591F0A3 -:102530007ADC2E1C89F9E8470885FAF5EF0B0B6C5D -:10254000A126770FFE2AB9047CAF31C22208BE5BF8 -:102550005DE07C42ACD8F74932FA295D53E86D352D -:10256000C077C1E67DE8E7D4BEFD5DE2D754EFF861 -:10257000D840D35882EBF8DDAAA7A11BB84EAFB163 -:10258000884001E1E32E2102F1947FF293E4625A44 -:1025900097CFB67C925C62A47F45CC36D2A39E12C4 -:1025A00024BC3EEF61EFD2FC8ED35C309FD07A5DCD -:1025B000EB6B8657C767B82A6ABBA387CF40F7542F -:1025C0009EF5775578B1EFF7D902A0CFC88D5F3C63 -:1025D000380FF4B9D7E64AA1B16BF6A95E95E62D9E -:1025E000F6A8810C9C637B4F4457E09CD953E05282 -:1025F0000DF3AED9A316E17C39BFFB62426936F711 -:1026000033C5ED44FB073CA0DF9EE0F89B5BFDF784 -:10261000F89FD7CCFFCE657F907003F8C0C6539962 -:10262000E0EFC407FFE6A6799ECFFCC68EBC10ADD6 -:1026300023417F045FB49BE0BC10F82A5A105C8EE3 -:10264000BDAA37D0CD3A44A5D8194FFF327C130923 -:10265000BE842EF8089EA894115D7056BBDBED3841 -:10266000672F38A273C14F694293F212B4F3C90DB8 -:10267000FE5A3A49107F1DBF67E1CA70C80B4D8AE8 -:10268000278CBE97ED55F9DC2ADB1B19C016183FC5 -:10269000C8C9F9D247D54018E527A8A3FF309BEA5F -:1026A0002FBE47F5D08E14FB37DEF6071BD6758399 -:1026B0004DA01C88035C4B34B896ECFDE1670A8D95 -:1026C000B378DF2D0730CEE207140F17A8F3EDE83B -:1026D00077C9438A88574067B6E3463A5BD864CEE9 -:1026E0002F12AD0B5415FCC1FC9DF09E5C41FD9674 -:1026F000EF0E73DD8DF102A1E542BC4AF0D468FF14 -:10270000CFCA583BF700D5CFDA68673C9C0F17E279 -:1027100008F6ABB53541200DB626631DCFEFF96B3A -:1027200032D6B1E677FF9529BA59BFCEFDB437AAA4 -:10273000D7A94821AE4E51C4B7A9A0FB8B538ABA82 -:10274000A96F1B20F7C5369BBF9F87CA0F6CFC8AF9 -:10275000F9C1853DBE81AE6EE8B76BBFFAC32D8966 -:102760004883E102E9F016D70DD827240F62BE3561 -:102770009B564FDB44F9F0976C38B9444D8693F77C -:102780000BF6C74243BFFA3ED906BE807484E40FFD -:10279000B601F21C3DAA9D7BDBF6774CC9E8069E8C -:1027A000A36E1BD7B30D105CEF5977D15CD05B845F -:1027B000C51F0DBE2DBC5E772FC2B3A2D157435D9E -:1027C000AD82EF89A289D3FEA285D34785F0395126 -:1027D0005F785CC0B3100362813FDEF38CCFBECC68 -:1027E000377FACAD217835E8C41F2B025BE8FFEAE8 -:1027F0004687506320EDB546A35154CEB4FB065234 -:10280000B9ED03D5A240DE1DA0AFA7C785FDF7A592 -:1028100073468C71FDF61F2E9988FEAA76A9228C2C -:10282000FA3BB7D326824ED4A7FD027C1CFEC29E83 -:1028300002BEB4571190976B288FEF35A3ADDE80A1 -:10284000012F77A4D8180FD52999F29CB67A0F4D8D -:10285000A27ECFBB4AEC90EB6D87CB26E2BCB125C4 -:1028600096D801D7FEC3631D2958B7582BEF9BD5C7 -:102870007BF5718FB8D07F54EC070C6F63B645447D -:1028800053BBC6A3610146A643F2A1300DAF8DC173 -:10289000F10E7737EBE317E393C4282ADFA94E0440 -:1028A0009CE75C252EACA32D96E8EE0A6A6FF34EEA -:1028B000BC9AFA0D8B8D8B077C6B52D2783DBF8A08 -:1028C000AD6538BF22F1C2CFFBB7B608F9C6FE65C9 -:1028D0002AE3BEE921DECF350E397ED43E95CF51B5 -:1028E00071A543E3DBEFBB4A699C05C9BE47410FB5 -:1028F0009DFC6DC4AB02FC39CB6261F9ACF135E7EC -:102900005AF021BDFC6C8AA4377D3D56F5B2BAC0A1 -:102910003F1ED5E87395ABC8916F98A7ADB745C377 -:1029200057910378DA612F3A84F3A59DBEE3DC3C2E -:102930009038CD013D85EA59D0CFA97ADA3176F4C5 -:102940003BC301FC2EEA553201ED168BDAD5D86F68 -:102950008BD7AB2268E0AB8D3639EEA24B11221833 -:10296000DF35EE225A3F6E7F295A04E9DC6D0C9761 -:10297000F51AA3E4FE792345EE9F0FB5F9B469F982 -:102980007F99AF7BCC7CFD5CEC1FB69648FEFE4683 -:102990000AF55BA5B44E48A1F9AD4EECB003BFA754 -:1029A000EA5D22986980F7B279C68BA061DCCE7AA5 -:1029B000971C3C9FAEF57033FC5DF375321E4ED50F -:1029C00027321E7BEE3FC984C7AEFE534D78BCBC98 -:1029D000FF4C1EFF547DD677F43FB487FEDD26F80A -:1029E000BBFA4DE771C56EDF40F0973B5DC40F98B1 -:1029F0006E885F50B95DF13D7E35E4DB8FC204E443 -:102A0000BEAFC27D835C06FEF00DCE65D6E782497F -:102A1000E0B77ED1CC69CDEE8B13D0DE4D7C01FBCF -:102A2000492FAF11ED0C27F885E88335B4BAB97C8E -:102A3000B76F10F4221D8E4E79E675A7DF42FB209A -:102A40006CDFDFA3B18F2F58DBA778286DD9AB4699 -:102A50001AF7757CAAA4A7B103BEC86DA5EFD56807 -:102A6000477CEFB697970E027EAAC3DA7301F7810F -:102A700097FF968B73E4AB7D4B07E2FB36AACFF250 -:102A800087BDBDDA63E82F5DB8FC96515DA933556B -:102A9000EEFFD0EFDBF635F4031CDB89BD09920BAA -:102AA000ABEB2A0A4EC6830D79EF07FF12C4B75865 -:102AB0001FDA3D5D1D03F9EE439279283F7C8F9428 -:102AC0001B860F10014B0AE4BE0F67834F548FB073 -:102AD000BBA00A47E41D61793B6284C3A550FDBFDA -:102AE000F797E3DB212FA4A17D613CE8F9CA64F1EB -:102AF000EFC96D1B42F64FF0BDEAED345E95DA3A50 -:102B0000659CC2FB283F157CFBAD2FDED6F4D704B5 -:102B1000ACCF019C6B04CFFB5A3F65A9BE2B50CFB5 -:102B2000E768BDE70AAA377356DF64E847C59A7EAF -:102B300026261152AE647E94033BC8E5E7B6D483E3 -:102B40005E527C3EE0C1DFD7E1C1F935344938FA45 -:102B5000125E456220751A8D3B21D5A2DB0F14C091 -:102B60003D449BE333FD5A96C7F2391988031DFD96 -:102B7000B3E34E4BF54E06FC7AFD0F67CDCBF175F6 -:102B8000736EE8F2BCDDDEB20C70B65739597FFCCB -:102B90000045D4EE89596141351A7A8A730DF4F9EA -:102BA000A3910B0EF6267C8C8FF2CD43FFB36FBC46 -:102BB0007E35F2CA8178F772D07371EB48D6EFC2D6 -:102BC0007D37A3BCD2E11B9840533C37C037280661 -:102BD000877C51BC5C27519453D42DFC129E6245D6 -:102BE0008EDF18E52B473FC596238F5D816FD62377 -:102BF0006C6F108DBDB99F737651DE9DFCAFE3E124 -:102C000098368FFD3671ED259ADFFE75319E06826E -:102C1000B7ECCE1B17D450BAD0529410544D70DF7D -:102C2000964A5D57FA8B07F62579EE9C4D83BB4E8D -:102C300083DBEACA34EEE750B81B7479E5170AEB78 -:102C400083FC47F917FDB181BB291F66B9F8C17430 -:102C50009C5B3916B6936C88A0BD457AE43B1A9C00 -:102C60008FD2BE73C4F1F735F89E1821DB273E687A -:102C700009C07E5034760FAFD313D54E8F4A6315FB -:102C80000BB71D7250A9F0B2FEFCD7317FDBD74ADB -:102C9000F36A4EF5DD07BCDD1C6F49FE80E1F00DE7 -:102CA0009D0A796BB49CC73F9037791ED384CBC6FD -:102CB0004299586B81FC31CD25A7B25091FB63BA84 -:102CC000F0DA30DE4CE1E37AEF9DB77BA14FBC0731 -:102CD0005D88E0BE51F8F9FB1C11E0749E0872FD9E -:102CE0009B442BE7757C137DDCDC4BD2C7277D54DE -:102CF000C6FF56C0FD6E64EE803A9AC7D48706655B -:102D0000B07ED5DC9BF1F35D704FD5E886F6EF6FB2 -:102D1000B18ED8BF33A89F693784ECDFF1BDF5F5DC -:102D2000CCF847FBE84847A7FEE4EC4B78B84E5B8D -:102D3000D2EBBC4B597F12C2C5F2D18FB47D5BA8D8 -:102D40003A452F5A9F236ED297089689639625623B -:102D5000BEAFAF106F15D03ABE3E46150D5CD3CB5B -:102D6000EDA668FD4DE93FE133D85B0F8B60AFE125 -:102D7000D4AEF092EFD518827B8ABABD3196CA27BD -:102D8000F627BDC6C0EFAEEFB5C30AFDEE8674F3FD -:102D9000F749D966FD67B2685231FE94E1E67AFBE5 -:102DA0008127A2B3F753A5FE22868821DFF27A0B92 -:102DB0008B713E1D932EDA2F101C1169BE8FB12E20 -:102DC000CB27FF7501C61556399FEAB755B6EB1DDF -:102DD00027798B28509CACA7932253CA25C87F4AD9 -:102DE000F203D2D3F56E4ECFD2798FF2F3F51ECE29 -:102DF00017A4159D40BF256B3EB7627DEE0C97F87A -:102E00002E6F699A00B02A76B71C445A162C9A8005 -:102E10006376D1A1DA8348EFECD4DB6A59BED3E103 -:102E2000BE45A3D35BA2A6FD3087D6E1963DAA8717 -:102E3000F303A64D9FDC0B791BE77BA2A3AA4B44AF -:102E400033245754ABDE2F0197776FDBC1789ADFBD -:102E500027F5A318EECFEABD0CF799FA899C4E4AE4 -:102E60002BFA1BE8CC2B3E67796CF2F6366B12D549 -:102E70002FF42A5EECDB6BBD2210A0FDB7DE26CF5F -:102E800081F5740E601F8FC999F6E8AD027CDA6790 -:102E90004BA37166DEB0A410E34C19556C45BD1B05 -:102EA000BF211920A58B4EBF8BEEF5F95769EB7644 -:102EB000EE6585F1D8B1332D0672C1F25D697D9062 -:102EC00012BFD4F5DD48E0ADE39285E1EC381AC1DC -:102ED000FA86DE6EF9AE48E63BCB07D803C260B790 -:102EE0003C43EB2C0CF2E699677EE2369E2B67E2C0 -:102EF0005ABEFA18FCED2F92BF916473EA11F0BF2D -:102F0000FEFD3CA093F39A9C4D7A4624CEBF6ACD39 -:102F1000AE08FE84FC990869CF1DF96CD258EC2FDD -:102F20008C471C4EE8FC2BF3D987527FEEEE1A6FCC -:102F30005BCBC28F1FA1FCB980C56FA3F3E99C686E -:102F400039FF3BF0DFCD4EB6EBDDA9103C387FB743 -:102F5000F4E37C96628DA8C3F92B02BCBFB314B70F -:102F6000B58EF855E5730FF703FDBD44381845E5F8 -:102F70002FAD8B647EF692CD73AC0EFD3D2AFBFB2C -:102F8000CDBD3F3DBE1BE93D55F93FC5F2A4C5315E -:102F9000FECB7EB56408DAD3F92EFA527F4FBFA874 -:102FA00004C3693FE734EF5FD997E01BB6A1CDD2E8 -:102FB0008FD2BCCD4A03D2A1036E3804BBF30D6996 -:102FC0006E6E5FB03D454DC236EC17F8F8077CEEEB -:102FD0009BE581ECE6CFC7F6135D72C110A5E5F461 -:102FE0004682352CF968BE8FF1D7C4F3D9B577FA8C -:102FF000FBF304E6411207E02EB67BF81C0AF83713 -:10300000623DCFF9B23CACD715F91F069D9DF32563 -:1030100078702EBD407AFC55A87FCCCAF37C71F342 -:10302000BBD1B0EBC4907E1C0E7F485EFB04D4AFD6 -:103030001AE0167E6A3FE0B1EB26023FD53B776D82 -:10304000E47E2A1D1EE8B9E5BB2E1E4C829C78BD8D -:10305000F064800E77CAFC2FC77B3D2A4DB57CE318 -:1030600097327FA488F345A4755A51BF54CA470FBD -:1030700069E79F68CD65FEC8A4EDEE5AAF5F523197 -:10308000CAD7A7F8FBC2AEAD9F9B74DE55A561AB56 -:10309000D865FB2363E725335EBEE77967D7CE2D7E -:1030A000BDBF87ECC21F4EFDC06C033BFA06BB3CA4 -:1030B000A7B7107F01BDE8E7348DFB0BEC5F6AEF2B -:1030C000053F4D52959C9D848FA487C258CEF8BE73 -:1030D000E3CF8E59CDE7B62E67D544483EC8670585 -:1030E000B55F18E5BB0BF35BA89DF3C2EACE861C67 -:1030F0003223CA7B37BE573ADA9331073A3FEF455E -:10310000BE5A25B92BCD207739E3BED7F95917E53B -:103110006DC67CBE6FFDB19104670C525DCF22ADD0 -:10312000A35B7E9CBABD05FCF88130C98FA30A98C9 -:103130001FE9F30BEDFF15DAF73EE233AFD179E289 -:1031400023DC8F738EB1F27ABE6AA93C48E770A186 -:103150001C01846C8D1DCE796F14E16FBC5315BEBC -:103160006EF4453DA5F57A1EF899D02BD254AFB038 -:1031700057AC1DFBF7FBCE5BD5D6478DD0F9A9BB6D -:10318000977076376F39CF5BC247F4015EC62ADF8E -:103190006FBE0E5BD141ACC338671E9F8BE39C535F -:1031A0008FF904C37F18DF43E7193A1FE1F87EF275 -:1031B000D28F15E1B760FF7D6E67FBDA5E5BEBD304 -:1031C000BF257CEE5D92ED819DE805F05EF0CF6855 -:1031D0003BCBB37BA3841F7C65EFD48400EC452FED -:1031E000414F04DFE82D6479B8ACBF770E95537F6B -:1031F000FDC2685FC05E342F42EB9F0646FB157D23 -:10320000B87D8352FB660EDAAF8864BE733420F952 -:1032100078736C709E4ADF9B3FCF14A8775404D616 -:10322000A4A2DEEDD25F43E54935D46FF3922112BB -:10323000CEFF51F9DC68CEF3F68D73321F67FB4C7D -:10324000F3546F5FF8AF7A69EBD5BC5196F7833DC5 -:1032500014E52994A7F4639BAC3F57ABF7914697CD -:10326000B4CF990FF8A6445A41E7FDD24BC2D29988 -:103270002979FBC2EFF3485906DB28E7565C9FC269 -:10328000F4A3D9CB666B7C5BEF0F0D1C23212FCBF6 -:10329000BF390BB784839E679687B741EE3B5ABE12 -:1032A000320A7AFB4C9F1A0C835C39A3D0DB29AF1E -:1032B000A5625CAF1CB74CD7FF82A5C0EBCBED0E6F -:1032C0007137CBF7C102A33EA5AF6F55CB9878A35A -:1032D000DE5C6127FE42F02CD1F66D9AD3D73B7DA0 -:1032E00004F4E9EBE38DFAF4A7650FE4F2FED2C62D -:1032F0003B5BEF8D3F990EB96D22A7FA789D7A0F4F -:10330000D64DE757A097DB25BD086BFB478B29DF20 -:10331000307B8807F6EA89D31C4C6F1D2DE12C1FEA -:1033200037CC8EF0C26ED7B02B8CED06376BFB839B -:10333000F428A61BFFBE28EEA7D22EF395CF65304A -:10334000DDBC600F3CB915E52F87B37FB6325A8ECE -:103350005BF9BB248D2EBD29AB7AB15F8EE9A53216 -:10336000C21DC3E5BF8F677A7A36DC57007C127DB9 -:10337000B25DBCD21ECC8C25FC1FD3E80F7A23FB98 -:10338000F56AA3986E8596F7FD3C9EF538927F7995 -:103390003CDF7D4339EFB37BFB2EC43E5A1EC9F0A0 -:1033A0001C73C9F26395B1BC0FE6DFB7F430FCC5FE -:1033B000C78AECBC5F8EED5559DEFA739D1A849F67 -:1033C0005BA7CF9A25C7DF86F9A8BAE1A3E4DDD4CD -:1033D000CFFC955593D06E7EC5ED5370DEF69AF610 -:1033E00029FB6943F7F3FC4AB37FD497EE9D8CF930 -:1033F000D56407761CA47E1E9C736A11D6D39FEEFB -:103400009B86F53E6F6F7DE14F0477EB8A3FB25E9E -:10341000747DB46F26BE5FD8F31BAE5FBDF2BF16DE -:1034200041CEAFB64A7AD1CFE31A8D7E45866F1E64 -:10343000EA57AE7C9DF581C8EC23927FDEFEFDF855 -:10344000CEE9BD5B5E50A8DDD288BDD59CAA815C6B -:103450009C6B679460B492067C4A3DEDAC2B188D52 -:1034600075F159A49CB8745B881F184B91A0D97F43 -:10347000A8DDD21619BF42F2821DF4195A7F297DA8 -:10348000E77ADFF37B856891DF6377DF7BB55CF7F5 -:10349000607038FCAE199BB0EEE776FD26D3E87776 -:1034A0000D4D2F8757CEFFACB65FCEEAFB65B6BD9C -:1034B000D35E00B9EBFC337D4C7476FEC9C19C3FF2 -:1034C000ADB42B114A977F57785A46727C8DB765F9 -:1034D00024E4E707B5EF4BE35B4682AFE97C4E3867 -:1034E0005A7259FFCF6AC985BEABF34751D492C90E -:1034F000DF032D9968FF8245DA53F88FE0A8783A08 -:1035000069E3DDD20FE1B70C477EE826E4F5711AD6 -:10351000C2251FE969BE8FA54B3BE6F939F69BBD75 -:10352000547FD07ABBA97C70C09CDF9A2EEDE70354 -:1035300043E26FFAA9EDFBC3708E3C21BAF5D73F89 -:10354000A38DF3D4539D713CAAA6CF0AB74E1F6E2C -:1035500029DFDB80EF8F3AF17D6B12F1E5A59863EF -:103560002ACF5F9E674F49FBCD0B79BE249C17E79E -:10357000811782FF8558CA6743BE9278D5F33A3ED9 -:1035800043E7BFF2A34549B0DF7E94AEDBF93C7D53 -:1035900040973ADE1A6CA4EF64433F2E2F386985BA -:1035A000DEEC492CB31AECDAEBF31CD8578B37E47A -:1035B000398C74D6B0ADE010491CE2EC36AB072074 -:1035C000375803F7427E6FD8A6B6F805973BBC5430 -:1035D000FFACF3C0DBA8B768436C3EE46DBDFDE211 -:1035E000F52312CB0C700EDD665E879C16737ED8B9 -:1035F0006E73FE04CE80DEFF7CBBBCA0395F70C85A -:103600009CFFE4835B67819CCB55FFBD2AF4893F17 -:103610004D3884F3F1D3175E8CC6FA2CFD4BD9419B -:10362000E849A17122B46E0AF408FF5685E9E3B2B5 -:1036300078911EF8811E0F819D61A4930AE13F6875 -:103640004DB9BCFE19D132CB4B745559B7BCE064AF -:103650004157BF57B6ACB343CE0B1DB7A7FD2F9C48 -:103660005E37EC6AC5A364D9557563C509F82DD6D4 -:10367000BE3B01F457FC4B85E58AE2E707BD0ABE75 -:10368000DFB663CE0D9CCE9AC8F8D0ED7D8BF72ABD -:10369000C128CABB4649BA5DB85E617DBDA4D11CD4 -:1036A0004757B63624DEA6D95CBE78F7FEFF869F64 -:1036B000BEDCF118C7335C1E271878057A5BC5A7F6 -:1036C00082ED3D159BBF0D3397CB792DD4E7E1BF3C -:1036D00096E3E1AE92553ACFB793C8D0F9F04B5785 -:1036E000516A06E1FDAAE68DAA949BBDC5EC9775CB -:1036F000DA39CEB0CA21829104CFA128BBD745DFE9 -:103700002FAE8F6279615118C99FF99C8A708E43E0 -:10371000F4C4A0DDA977549683AAE2251EAA1E57F9 -:1037200002B0C556C1488AFC1332BF04DE2655D20A -:103730008FD7003FD6CD98174D526FABB406F70325 -:103740002F9DE7C03673BD4A9AE7D138C859E6EFD6 -:10375000D5A29DEBD7ECFE36CCF8DD60DF657D525F -:10376000D76B55C83304A77A4704CBB3C49823401A -:1037700057AB14EFC30E15299DE3A0EF254E962FEE -:10378000E66E94E747338C839083D70D66B967AEB6 -:10379000E2CD04BEC4BA70D6A7A9DC1FDE8BE564F7 -:1037A0009643484E6639AA7D8E9DE3129BF35A825A -:1037B00090C79A1F48F1D00A327FE4F3E89E7096D2 -:1037C0007B9AA74AB9A7795D1F6EFF3140EB0B3991 -:1037D0005AE2B9F99E1C1EB79F2ADB893E520F2080 -:1037E000B93A137A02C1E541B92E4767C5FA4AB022 -:1037F000EEFAFC9B63DBA3E0C712E5F1DF4B6ED86A -:10380000A29D87EDEBC203F0539C548A0E5A0CF62E -:10381000A95B32E4F93172AC77AB568FFD1965962E -:10382000A977FF80E0297BD0E26E48E95A07E1F5ED -:103830006662FE27D785E783EE468E95F6A7637905 -:10384000929F470E171CBF73BBD6EFED1916539A04 -:103850001841F448FD9C2C94F6EDA8E1456C07A4B2 -:1038600035BAB9BB38903519F29C2AB317FDFE9AC8 -:103870006EE0E9A48BF152DE3DB94CD924E1F2723D -:10388000BCDFC85F85B3FDF0A476DEE8EB4174349D -:1038900082CF718D9FADD3E8665DCF7463A28BB983 -:1038A00090B7413773E4B9D84957DAFA12DDF07AA4 -:1038B000B7135D48BA11E26BB42F744B793B44DF08 -:1038C000EAD4B77BD0B7880E9EC8E86DA817420728 -:1038D000C21A18F18FFC2C25A362472AB40449565A -:1038E000E147DC2CCE46C6D75DD6C04A82A7BF557D -:1038F000AECB00ABA43B3A65FC11F95CDF8BF8D989 -:10390000E2FB170B2FD52F4E126CB74A27F926264C -:103910008EDB09A47007AAB0E7508AF6C531B2FF62 -:1039200062A26FC4B3517F5E4B9CC6DC46C27F2A45 -:10393000587E40FBE87C6EEFB7C8F65E2BA503D33C -:10394000E43E6A5F15C6F82BBE734026E864D25881 -:10395000339D24664A39414F1B33DDBADC90087E23 -:1039600050D23898CF9986F0A2AA5DD8A7CF487DCB -:10397000A378F54D934700BE67E33DD8C2A7A7ECF7 -:1039800060FF4A49E39C1F7F083D655B387FDF98F5 -:10399000E97B0F783FADB817ECA20F25335FB12755 -:1039A000527B5FCBD473BFA3748A7FC7DB9023A6FF -:1039B000CC50B9FE1421EDB9A2518E33D9FFB935DF -:1039C00091FA9B3C5AE1F094B67057F232F855B434 -:1039D000F53DA6D17743B898FD9C13700DC84CCD2A -:1039E000861F8224D46EE4E401995AFD31CA06C8C8 -:1039F0004303C7C9FDA7D7473FE8372D53EEB7CFDD -:103A0000B47DA7E709AF5CBF6C4D585B5A34525B7D -:103A10007010A5F3B2C69E039F99942A26AC07DEC8 -:103A20007FAA8A4D0C6F7B31F385A84C37F8828FC3 -:103A30001459A6FB6D8399EEDBC6B4B7DD49F9B620 -:103A40002D39D27EA7E9F30B5D82E582B63192EF84 -:103A5000B56F8964FE73CCD51A1527ED5DACDF9781 -:103A60006A24F1D7BA867BE1372E75DADB707E2CBB -:103A70007C603AFBFB4B9B49BF475CFD5AB37E4FD2 -:103A80007A78586637FA7AA85E0E9A011D95AD5578 -:103A9000980E073678EC7D99CF292ECCAFCC194CF7 -:103AA00007FF2FF384735CF0657AFB3784F791B0DE -:103AB0001F0B0EBA1A3AC8D70BE3163715B37E1A86 -:103AC00099ED63FE355025BC101DCFD4E86F12EC84 -:103AD000A0E04BD6D6BED897AF6568DFE35C994EC1 -:103AE000A6EB70BE6FD066736502BEB655E1169C3C -:103AF000B793564AFAA67DE7C0BD80BBAC2202FC54 -:103B0000E0B8D67EFE0A6BD146CAF777086B541C24 -:103B1000E82B8FE93B90E5FB0CEBF7E92FC428C8B5 -:103B20000DA56BD749B834FA10D623E3E3699C4F4F -:103B3000B7A4E4C3AEA0D353206B6C76E608035D54 -:103B4000CC50981E683E87609F9D9755928F72FA61 -:103B5000BE1FF432696C301D71D8856A25C7AB76FB -:103B6000240A0FE2873A443BCB231D248F803FEA8F -:103B70007C46E72744175E4742D77AEB7C656B3D6E -:103B8000814678DE56EFE0F4A97A97B0124FD85EFE -:103B90009FC8F967EBDD9CB6D467F1F7E7EA3D9C77 -:103BA000DF593F8AF32FD47B39BFBB7E22A7BFAB3F -:103BB0002FE2EF841FE64B3ADFD1F9934E5F3A9F35 -:103BC0000AA5AB058466DC33A0F6CC0F753E887978 -:103BD00058F2BBF893BECEA94A913F11FC50B4CE27 -:103BE00001FF2854CF3EF322E1B9A3DCC9F1A11DA6 -:103BF00042F2C10EA783CF8D64BBD80DFB40C33208 -:103C00006FDB9D8673785EB922AC06BABDA9365CBF -:103C1000580D747D735DAC293FBFEEFDD7FA50FFA0 -:103C20003F8BF12DC2FA1CBBE3D4A37FA4EF8FDF3F -:103C3000713A03EB4E706C7908E3DE1EA1C1D12A04 -:103C4000E1BADDCEF2D2C008A94FE1CF6188732D71 -:103C50004E897DFB3704E7316D1D06DA5DB346C141 -:103C60002EB34A75ADA42A1F63BDE8FB9FB5F52AA4 -:103C7000A90B637C96346AFBD418FF4CF83CDE57E2 -:103C8000B05CA77885801FE9F82FEC419211C471D0 -:103C9000C51150681C8594ADF9B017AE79FD28E4C4 -:103CA00074A5EE10CBD53E8793E32884DF76D6D873 -:103CB0009F527790EB89D6FEA638C8C8E15E3BF8E4 -:103CC00005681BEB56927540609F8B2685EFF1943B -:103CD00069DFCBD628A6F8E27B3355E68B8732AC7A -:103CE0009C0ECA149A13A589CF299D5E897F703CCA -:103CF0006359539E7D91812F9768DF4BB32CA67833 -:103D0000C74319322E6A109805A57767A5DA1732CE -:103D1000DF7373DCBD5EBF242B7F75EA70F483E82C -:103D2000A0AEF68F645AB9DDA10C9784C741E7595C -:103D300014C7E9747B2EE872CCA7F8EF950C3FEB23 -:103D40005915CF3EFD2CFC7B157F0AE3F3A9629841 -:103D500066DFC80E8C9CCEF28FD7A98C84FC2DD741 -:103D60007FFCD37F89467C54CD4E6957A5B40D693D -:103D7000F5EDE56C57ABF6D0FE88039F35FBCD5FC4 -:103D80007DF64FD1ADAC97F893B4F85B8EF7AADE11 -:103D90007982E3C0F4B8AFD07635CA37ACA7EA7100 -:103DA00001BA3FB6709F8DF74DCD1E85F5989A5D8F -:103DB0001713C0E76AF6AD4AE82E2E27B45F3D5EC2 -:103DC00040B7BFD588B59FC37F4884C3F80FADFF08 -:103DD000766654AF53430562D5AE603B8855701C80 -:103DE000C7722D8EB32390C17EE19EE4ED9AF5C497 -:103DF000F049BFEDB0BA6310AF7C418889DDAD53A7 -:103E0000FC20797E9FA37D04BFF085ED2ACB91171E -:103E1000B647F17EA8DE7EFF41C4DB556F56D88DD4 -:103E200057258E30DEAA77AAC261E00F35B00BC5E8 -:103E3000F70CE7D2A7A36A415F4B5A14EF16F8AD0F -:103E40001DEE98DE0678DA35FA5A1AD63292D74540 -:103E500083FF14F89A41CE5CB2F77E8E13A47AE702 -:103E600059AEF96D24C7B3510F6F03CE331B0AD877 -:103E70004FBDA4654735CB05DB235D10694EDBCC18 -:103E8000F729BED1C6FB4693D3CEC04F82F6CFAA48 -:103E90002C0F034EECCBD35A3CABDECE3248B6B33C -:103EA0006878FB0DF6E788AEFA4B5ADAA2D3A9FE82 -:103EB00027BBDFE7D43948EEE325CE23B938473FA7 -:103EC000D919C9F7ED3ED9F9EB092FD178E75AC6D0 -:103ED000F4520CFB6CE0201BD73FB741C601F32521 -:103EE00011D60F5A783E67B62729AC2703DF849F87 -:103EF000333B9F8FB6F03EF6FF7B71ABB3156BC8BB -:103F00007D84EBB24780FE5BB5FB11ED9AFDE57F4A -:103F1000A7FF6AED7B9B52A48D23EF3B083D0EC2A9 -:103F2000A5ED3BD5C9FB6E79949DEF2F2C18E6BE0D -:103F3000711EF8E89B328E51F4773F04FD6FC13B50 -:103F4000F16C6F596E73F741FE8BC336F6132C2854 -:103F5000F01CF5A17E8C9DED4A22B17504ECAD6D8F -:103F60002952BEA85C433B9350DC8FE8CD4FF8ACA0 -:103F70000C58848FF29307A5F2BA3E526EF1DAD94B -:103F8000FF13E4FB92C7ECC28F7B2FFEE7A47E5D9C -:103F9000992AFD0E8F607F515A1917CC8C87DD4E00 -:103FA000A39BCA69546EA09FCA4DC14CC84F67ED10 -:103FB000D21E8972E84D95F9B25E8346A7E807FDE7 -:103FC000B6A5B8CEB3BCBB2B4A40EFB0BC1825EDAC -:103FD00021BF09DF146638AF6F1A24E9B841F3072F -:103FE000FAB748F80017E4F825F6A64CC8B9FAB8AD -:103FF0004BA29B78BCB3DA784B229AA4FF448BC7C0 -:10400000437D1EDF26D8BFD3FE6418CBCBA7FB1E93 -:104010007901E39F7E7230C711B4A50416EDE6F274 -:10402000708EE3AE782A2C08783F7B328AED589F59 -:10403000D9A41CF6595402CB6187A21E5C80FE3ABB -:10404000368729E0A39F29C29E88F22DBD590EA86C -:10405000A8AF633F4905B117C8AF944E84DCF7D9C8 -:1040600096C16C27FAEC0D952F29D0F735F8EE1391 -:104070004D0B7EC6F2BFF43F9E7EEA6F83BBF3AF6B -:10408000546C36DBC3F4F5D7CBEF1824ED03770C73 -:10409000927AC9CA412EE97F8B6C793095E729F96C -:1040A00003AD03EB7FB41F13606F3FD6B22741719E -:1040B00002CFC1CC5F03EFDBA49E757ABB8DFD42BE -:1040C000152F4679D9FE74E7157CEFB042957278CA -:1040D0008545DEDBABD0EE99564467B27D8BF0CDE3 -:1040E0007A6DFB16551B478EFBD9D601D29F10D493 -:1040F000F22FE4F03DB84971E2E6692C5F6DC80526 -:104100005E2F6E8EE4F8791AC78BB8878A9FFD5CA4 -:10411000E2336611EB0774AE317FAED4F873D59DF0 -:1041200057C7E05E817847E5FB1217AD9E3EE0BFC2 -:10413000A1F87A4FE3634B5F7894F94125ED17C4FA -:10414000592DD5FCCB4B9F52589E5CBAFAEA879802 -:10415000EFBE6D13B85F70B6E5FE68E37AECD5F894 -:1041600067577B0FD75F4AF565FB37A3199EAD36BE -:104170000FE0095DC7EFDDFE29F55F6A5FD142F20E -:1041800045EEE5F3BF288EDCF627F095EDE16C6790 -:10419000A3F5E77B46676C2D8B30FF33CF8433BFAD -:1041A00039132BF7FD27749EFAED80E787F7B15D91 -:1041B000EDBDE902E7D0E280B95F1DAEFD1ADFAFC9 -:1041C0008AF7C4C04F5345EB81FE687D7EC4EDDFA6 -:1041D000B171FBD0F93C8E76230CFBF49948A69B79 -:1041E00033FDE4BA9C7976109F676DB192DE09DEEB -:1041F00064E84B6762658A1B3EA0870A97A48733F1 -:10420000635AD81E7046D9C1699B4DB6ABA8D3FC82 -:10421000DA447F89A01FD026ECA98EB54720C7803D -:10422000CF8FCCE73488FBCEA17673D029CEBFBE2A -:1042300059F2DC8478053ECF7E1BF6E3B4F03D7383 -:104240009F264F566EBFDC4F8875AADCAEB03FEBA1 -:104250009276FE02EA5EBADD9FE872A95FF1226EF5 -:104260006B69E3B225A0FBA5B5EBE681EEF5792CF1 -:10427000D5EE5FB7292AC3D3164EFB27FBF2F174A4 -:10428000FCAA598A1E9F275CFAF9457B382CCB2D56 -:10429000E988B24DD45F65A3B296C749D1F55B39C1 -:1042A0003F1D4FB8CD02FB5E9B76DFB9A7F9EB70DF -:1042B000F6044F5296E44F6D29F29E6FFB5BF2BEFF -:1042C000F6C56F0A62E2FE813CC891FA7A7F047FEC -:1042D000166810728FC6E796C2AE4E70666E30FBDF -:1042E00073B2369BF343B69BF3D93BCDF9DCBDE605 -:1042F000BCE75573DE85717B77E109FA36E203A1ED -:104300006F2385BEEDCE94FA36F2D0B79142DFC668 -:1043100077E8DBC843DF461EFA36F2D0B79142DFBA -:10432000C6F7391A9E2A357B29D681E3D4F684EB69 -:10433000F100BC5F2ECC49603E2AAC521FBDB024B8 -:104340009BE5C74E3BD35407DB99F438A7B7A27C53 -:10435000E3B27AC37F7B6475DF146EC7F6E79ADF3A -:1043600049FB73657EB813F68ED6559FAC86D8137D -:1043700088F24D44FD0BB6F6ADC06F55DD2BEC6FEA -:104380006F5DE17EE70772FDD8EEA2C72D15E3DC75 -:1043900003DF267D49C66F7B1C463B6AA85F48AC9D -:1043A00035E4213F359BF3A17E20F035AF695F35C1 -:1043B000311D3C6E6BEF0BBE7FE24907DFF33AA184 -:1043C000D9EDC46C17CB63BA3CDF298FDDA36CC277 -:1043D000F9BD242B8EDB771CCA30DDD30B4D4B2F60 -:1043E000E5B3BCDA995FAB58304ED98C15FB59AFA9 -:1043F0004E8CE673E9160DB64190FF0D700F0E441A -:1044000098E868E8B6B810BF653F53FD61BB5343F9 -:10441000FC96434CE5D3D71698EFB5175D6D2A1F70 -:1044200068EF8C877348FF96069F4BD6B9E8CCE7B8 -:10443000F986D64B563C7F84BF56BC25E5D3329ACD -:1044400087B7407B9F231FFE39EF14E0AFBCC51632 -:104450008BF3BE543B87449DF95C2EB70ABF2BAE4D -:104460008BEECA5DC21B4BEDBFB43625331DDD712B -:10447000345925142D19722437087DE58D2746827D -:10448000AEAAD48DC92E2ABF55096CC545ECD3718F -:104490003B12AEA4F2FFB4F81EC9A2754AB605EFEE -:1044A0009D0F3EBA234DE0BD91136B9F8FE6B83C44 -:1044B0008DFE926DAE08D0C1C62695F514D8CDD428 -:1044C000B82E3AD9D8141F01BDA67C8CE297727120 -:1044D000B449DF0BC547A19AFD8E9BE67BF1902A7C -:1044E000EF406AF35CEE92F545BA6CAFDFB3D7E705 -:1044F0007B52D3472B36BE96790B7D3F3B787F2E80 -:10450000AE8457D6EFE6792FB56CDFDA97D27B1DF4 -:10451000BE5D98D7F2B7C6455F49E37CB95DC687F3 -:10452000FFB5F989C7FCC44FEF6C7AC20EFB418519 -:104530003560871E5CFEE4463BE218AEDBB691BFF9 -:104540002FDA56CCF600FDBEDAA77A7CB3868FF25E -:10455000B1CA0617CDB3FF60C94FCA23641C4BA173 -:104560003AFA35DC13B8B84DC9C3BC6614EDB0E3F4 -:104570001EFF3B1ADF09DD371D87A717F686BDAB87 -:1045800045F120DFD33E9989CB72440FD32FB9393F -:104590009D716908EBD51F0AD2BE708E6487E8D77B -:1045A000875569CF433C12AD73B93DD86B3AE4856A -:1045B00097E5FB0F55740E8DCA87DE2EC4559416F1 -:1045C0008D564D745E333ED2B40F660BC3BEA2FE51 -:1045D00066897EA6FC8C4969A6FA37CE181AE2676E -:1045E000CEEF2A67FE7595E95D97AADBFD6E85E340 -:1045F0007BC69ABF537A3BD3D90DA6F655629AE98A -:104600005D97259BDF653C1395D9A18F956BF7418D -:1046100066FBDAB4EFADFC9D2662DAAF03D33C7FD4 -:1046200094E7A58DFD08BA1D7D36FE9FD6DD79196C -:10463000D1198F89F85BD83B7C6679E408EBA942F5 -:10464000AE4395668FAACA92F6A82AFF113BE29B59 -:1046500009FFD62442497593C2F646AAEF488A93C9 -:10466000F9DBF17DA7F95E07FABB84F2436A31F604 -:1046700057687935CD1BE74235EC47B083E9FD6BD0 -:10468000FDEAF4197ACF3EB41FDF6037EFE78A6D99 -:104690003B0EF623BC4C2F8ACD437C4965CB545B43 -:1046A00071F6E574A6F3FD8BE516B67F751C7E8565 -:1046B000E9ACA3DCEA91F1DDFF181FD55E696F0D4F -:1046C000A5BF45341FF89917ED543C0145D6035E4C -:1046D000FA812E43F092D40DBE743C75E22DA47C79 -:1046E00031FE331CF1114A007CF232BCE878D4FA76 -:1046F0005FE4132C67123C018627A43F312A74FF24 -:10470000DDC2EF20746C50844BF96E3C4CBB24ED41 -:104710003603D3E4BCDB77291EC8EBB32E59F97BF3 -:1047200027BD14C938F51993CCFBB3937E8AE47E78 -:1047300099792981DBFD6FD3D177D18FEE9F098DD8 -:10474000FFD6EF5D2D1AACDD4B1A21467CFB4FC422 -:10475000AFEB72404FE749E779E3D2F0EF4CEDF66B -:104760001C5E1E95CAF1DA3ECD8EA8F3639FD64E2D -:104770001FB798CADD05A0EFFE09B017AF6E4C4B0E -:1047800036BE17E35B65633B6FF28A784E8BC35D81 -:104790000938478A57C8774D8EDFD52701FE88E351 -:1047A000AB6CBD2651D7C77F3A3C59E4205FC8E9BE -:1047B000897561B38D76783D6D1A2CED35FA397EA9 -:1047C000CE72387A36F6DFAA5DD108055ABAEAFD0C -:1047D000912E3ACF57597C8F0F667FEF463ECF859B -:1047E0006B632EEC70BA3C51B1AAB00FCEFDCAFF7C -:1047F00079E5319CFBBE15B604C8A39F7DA00A8451 -:10480000CED079C672C4A7E192AE3FDD12C9F710CF -:104810003F558417FEA625EAFE5C97E95CDD3B0B5D -:10482000E3FFDE41E38EC0B881AD8918D7E3CFC482 -:10483000B8BE151931DDD957F4B466BD94F3B6EAA4 -:10484000F664CDEE0CF91E79C8F7706241BE471EC2 -:10485000F23D52C8F7F8BE4DF32F0C6C68CF837E43 -:10486000EA1F2BB26AF9BC7566417EBF4589F080AC -:10487000FFDCA278FA70BCC166F9DEC4F29075D58F -:10488000D36BDA490633D0ED0F2E3984316E6E8C3E -:104890008835E5C739FA9AEA17BA524CE5D7250E9A -:1048A00036955FEFCE33E57F9875A5A9FE64CF18E6 -:1048B00053FE47A3AE37D59FEA9D6ACA4F9F38C7BC -:1048C000547F6651B1A9FCC6D94B4CE5737CCB4CE7 -:1048D000F979E53F35D5BFA97685A9DC2B5C569CD7 -:1048E000777BA17711DE5F86DE45E92D6F65388D18 -:1048F000EB3A7A9CA5DB77794E697250BFA1DE3620 -:10490000D025EED7800E0768F767BEC0B9D21B7EF0 -:10491000C9A022F5DE237D4137A1F542CB47471ED2 -:10492000B8E8A6352C7A2A7AA695F8C4E82B0E1496 -:10493000A4517EF5538533ADC45F465F7DE0F954E5 -:10494000CA373DB54A960F3B7011E5514FDF20F352 -:10495000D3058B1A8F0CF97A869FE631FA07A96B7B -:104960003DD26ED26DBC69A73D88F080784DE001E4 -:104970006990E813E901A24FA4AF127D96A50B71CF -:1049800090E813E921D23FF1FDF7A47F223D4CFAD4 -:1049900027D2B749FF447A84F44FA4EFD5CFE6F489 -:1049A000837A1FB7FB437D39A747EB6BF9FBC7F54C -:1049B000759CFEB9DECFDF5D43743B4390ED31BAA9 -:1049C000FFAB1A7E47D8ED76DBCE1AFDC28A579E22 -:1049D000A7BABFB2A156B446629FB65A634F39BA5E -:1049E000FC903DF35BAB386590BF5E0FF7260DE1A1 -:1049F000F1FBBB986F6BDF8F89E903F2699D0A5267 -:104A00007D29289F995FBA2A86F8C70FBEA9B5816C -:104A10005E3EB4747F7FFB0B8D4EDA877833878CD4 -:104A2000E8F2BBEB7EEFCEF81A835F1EFE6C3D8E84 -:104A300047F7C7F39F213E47F793EBF141D76AEF62 -:104A400023E97E703DFE47EFB7F09260BE77CD1A46 -:104A50002BCB2D515611C4387A9CCF358E963CC441 -:104A60003B5C53E9E438B73EF41DEF23523D2FDEA3 -:104A700099DBFC25D5CFEDF2BBF7D1E641E53C8FC4 -:104A8000C24B3EB6D75EA3C51DA0BD4396F33B7592 -:104A9000881183FC4129DBE11E55A87D7E571C004F -:104AA000EA47CAFA41F497FE158D17DDB58F06C4A3 -:104AB000B5E4216E6C40B593E3C6368C09F2BDB9FE -:104AC000E9B1D7DED3AA224E38E6C7D8474FA7FAB6 -:104AD0006602CFEFEE730FF0507E5A5C5A6FA4530C -:104AE00043DEB5EB667DE6625D757CE978D7D74B32 -:104AF000C7B7219E8AF1FC5DEB17BA6EA1EBA5AF9B -:104B000053E1A52EFC037F97AF4FD7FAC13EFBFFC1 -:104B1000CBFA0CB7B6F07DCCB04A8707707DD77A58 -:104B2000DDDC2E26E03E78F125F741A44BD27C5FF8 -:104B3000807F968A31135CC0914BCD819D27B4DE76 -:104B4000F2EF59EFE1907A07E20AD67C9D7679BDC3 -:104B5000DD21F51A620BD67E2DED4C37E27C3DE46B -:104B6000B6B11FEDCD703D1EC3EBCCA3751CA7F1F4 -:104B7000A343A296CF0F12D7FC58DFF1DA528FCBA6 -:104B80005ECC72EE78A7596E9CF04D5123C69DD035 -:104B90002B448ED6FCE13768FD5E279AB8DFD07BC8 -:104BA000F23768F269E83DF9E78668F2658A4801FC -:104BB0009F1A2F3C122EEDBD83F12ED96F92462FF6 -:104BC000696E558C063D089F15CCF155BC77908BCE -:104BD00071FD9CBF5E0438FDA108723F938991224C -:104BE000FF23216CF29D03793FB35AF5FD27E42C96 -:104BF000FD5EE6C270DFABD877AF444E998FF728E1 -:104C0000C6158C4B47BB03E3DD2C9F1C70A4B1BCC5 -:104C1000847D658BEBDA7F6FD0F9926E95F7069104 -:104C2000E2DE603A6D96D7E9FC41FE86AC1502EDF6 -:104C300026B8CD71387AFB1FBAC60A6B41CFFCFD8E -:104C400087B97BFAC3AEF366ECA0F1B083BF197BE2 -:104C5000C578CCF7CDD83E169986D939CD7931BDF6 -:104C60003B794EA7E7AEF126086B7CCF78D6F11AD8 -:104C70008A4F1DCFFF025E2F7487D72F060B29376F -:104C8000474A3EA2E3B72AACF31E671F635C44A504 -:104C900043E2E933808C7BB87557F13C3EA917FDA0 -:104CA00081EF4575A3B83CD40E2536C7705E7FC72B -:104CB000ECCC83EF4627127CD7397CEA50C2CBD9A3 -:104CC000FC60264930E2930D0D7CEFFADCB3AA07B5 -:104CD000F27FA5EA5EEB014F7953653FA0F8E695B8 -:104CE00064F809C5E6EEE3A32B1D12AFBAFEB3329A -:104CF000AD88F7A7701524CAF7D5E43D725D1EE8AC -:104D00001F26E38BF5FBCC3DC9072323241FEB1F94 -:104D100026F9AEBE9ED48EF349D4CF48E25349F76C -:104D200045B03EB0DBE54D1A0A7FCA786192A7759F -:104D3000BDBFA3977C3FF05A91F9D068CA8F3F64FA -:104D400013012AEF182F4CF164856F94F2BB16FA09 -:104D5000FD98B044D2AF0CFC20DC1D617A6F343278 -:104D60002BCE948FF2F433D58F19956A2A8FF50ED6 -:104D70003195C74FCC37E57B175D65AADF67F658DD -:104D800053BEAFEF0653FDA4F269A6BCCE9792E4E2 -:104D90002731A076AEA9FDC0BA1253FD147F85F964 -:104DA000FD54BFF74856029E77947F696B9687BC87 -:104DB000AF6A1196915DEF90FC3A5ADE0799E85C74 -:104DC000C4EF916434FDCC0C8FFA8D8A732629468A -:104DD000E1F724AE739BF96061A2393FDE95F72AB3 -:104DE000966E9C2B34FE28A8809E926AADA6EFF3A7 -:104DF000866A7C3457E4B29EFE5DEBEF1B625AFF7D -:104E0000507C5D4E0FCFE705DDD29E6F9C17ECF90D -:104E100046BCC09E6FCCC39E6FAC0F7BBEB11CF670 -:104E20007C6379C121331D8C3862A6832B8E9AE96D -:104E300040A7CFD0F5BAB2D54C1FC2A7F8947FB027 -:104E40005E577F6AA69FD0F521098BD76F825311D9 -:104E50008FA4FCFBEBB52E64BD3AD787F00DF9F6B5 -:104E6000DAE050BE275B78481578B7E4516D9ED7DD -:104E70000DADE527C3B65B7DBFE67DAED155435F83 -:104E800049571D879E0F071F7D34A4FFD7FBF902EA -:104E9000A83F3BFE62B21DF4D12EDF456B031FEE2F -:104EA000DD15B7497ABABC77F23395E3188E599A73 -:104EB00014F0EB8218DF36F0CB9BB36B15F8671359 -:104EC00045D18E4588CBF98FB064E4170C94F77701 -:104ED00045762BDF7FD0F9E282241917D83254F3BC -:104EE000F37A64DCCEF343A5DD24CAE3E238E3E2DF -:104EF0006C79BF83D499E40539C0C7E1F041C0475C -:104F0000B385DF696CB5B9396EC4FF862AE0F783D3 -:104F10001C0BF9728026DF357CE47000FE41EB85C6 -:104F2000E99C1D1C7098E25B876E7399F2392D899C -:104F3000A6FAC376BB4DE579C12C5379C1218F29DF -:104F40003FE2C82853FD2B8E7A4DF92B5B279AEA56 -:104F50005FFD6991299F24DA1F067E072A528F3E42 -:104F6000333455E2C92D387E6FC19DB1F2DEA7A65C -:104F70005FEB72BA1EF7ECD3E83954DE1F68F771A5 -:104F80001C75435FE1E17B180E4D9F12663DC0A783 -:104F9000C52D77DEA3F09BE396F578E54E7D41D3F2 -:104FA0000F7439DD10AFEC35C62B2F08EBFE3DE05A -:104FB000FFD2D63D14FE817639DF869FDAF9DE888E -:104FC0000E57283C33B538DA2D8EEEEFF5D8B225E2 -:104FD0009D256514FD1DF4FE98CDD3CA6FDD5F36A7 -:104FE0009EA7D54FF4D5F00BBB67A5FBBBC75B30C5 -:104FF0004CCE67BEC572F3D46C8ECF32BD83DF3B1F -:105000005BEAFD51B94AB7F35B1023E3A7448CDD9B -:105010000DFAED793C89CF44BB68E4FB475A9CFF0D -:105020004D6B5BEE194445F3ED4DDA7B60011BE8F7 -:1050300061D25892C3F284D8B66557B393E4A2C73D -:10504000EAAC6C3FE9BFDD358B24B8CEFB1B0349CE -:10505000EF017D40B681BEB42147E571AEC19E1B14 -:1050600081FDF64D679C3DFB0584D0CE0BA94F75A5 -:10507000436F4C87FA3CFEAFE3ED43F1A4EBAD4246 -:105080008B334CD7E0D2F1D76977D0F0A7DF7F70B0 -:105090002FB3156D72F23D8A8988DBD2D7AF2547D1 -:1050A000D265AD860FD4033FEAA95EA19A1D03FB2A -:1050B000728770C7B8BAA1433DFDBFC28B8EFF9EF9 -:1050C000EE57F5C41F42F9C277DDB7EA894EFFD922 -:1050D0007B57063E21E368B47509A45BD83F7D6722 -:1050E00094793F6FCC96768D71DABEA2F3DD996725 -:1050F000E61702F6F18655AAC62FE4395E9C52C423 -:10510000EF118B3A17CB33E51A2FD6CFD7850FC8BF -:10511000F7E0AEF516255C45F992669BD848A015D8 -:10512000FBBB8FF366BF931B71FE9E44C0CD263739 -:105130001AB7B44909EC4FB9FCBDECC54EF97E5C19 -:10514000E8BBD98B35FD172F2A60DF86FA65EECFD5 -:10515000D6CE6B8FF07C2BE167BDA50B7E8DDE027A -:10516000F21D31E8C3AAB4F3709C968E3737FC2445 -:10517000F15D79C26F4416CEF3466BB771749DF83A -:10518000D5FD2A9D7EC2C31CAF1F1A1770D6FF4AD9 -:1051900074777E1ADD7FD3D33EE8F4DF7C875FA887 -:1051A000C369891E053E04FFBFDBE857F9F3488257 -:1051B00090FD2731F08FB46AFD898DB9DDDD4FF4A4 -:1051C000ADD8C5F110AB2CBEFF405CF219EA1FEF61 -:1051D000B0DEE53C9080FBF89334BBD3E5F3D6E436 -:1051E000B0D1F27E40875FE5F5EE9828EF73131F8C -:1051F00015D877BA1F7FAA08F642AAFB497C6B46EE -:1052000031FE753F49717014C339B361B10D4F4818 -:10521000B63E7C7B6184BBCB7FD23A40C6E7F4E4E8 -:1052200047997EC9C3FDCDB87415F7732C3B45CAA9 -:105230006B8DF72C039D0DD9266C9867ABADFBDF0A -:1052400019989223F7D152F8D27B1BE27E5628ACF4 -:10525000072C57841E07C47C5ECF5F6CD2F2853268 -:105260007FCB2A996FD5DEC5DAAAD93B304FA498F7 -:105270000FF4F0ED9A3D04F3408A79E03BF81AF21E -:10528000E06BC883AF210FBE86147C0DDF4B445109 -:10529000729E2AFD3DE30DFB03FE9EF106B909FE59 -:1052A0001E631EFE1E637DF87B8CE5F0F718CBE1D4 -:1052B000EF31E6E1EF31D687BFC79887BFC7581FE8 -:1052C000FE1E631EFE1E637DF87B8CE5F0F718CB97 -:1052D000E1EF31E6E1EF31D687BFC7587E739D62BB -:1052E000F207DDACBD3B50BA3E8EE9A339B52829A3 -:1052F00087D6F73F23FFE7C7B654ACF3DE25FC6E35 -:1053000060558447AE73D344B9EE1621D7B97D0EEC -:10531000AFF3ED76992F94F1C2A1F403BFCAF874EC -:10532000E957410ABF0A52F85590C2AF32DE2AFD52 -:105330002A48E157C177F85590C2AF82147E15A470 -:10534000F0AB20855F0529FC2A6807BF0A52F85593 -:10535000F01D7E15A4F0ABE0FB318203FE151D2E7F -:10536000C8F9E9263D94E8D0A487BA4C79C8F9C6B3 -:10537000FA90F38DE590F38DE590F38D79C8F9C639 -:10538000FA90F38DF91BF188716F29EF1BDB41DE79 -:1053900037E6739AFCAFC1863579C3F95791B646A3 -:1053A000298F292E92EB729E9A05FF586BB8921C9A -:1053B000EB213976C56F678DBF92F889166F972BF1 -:1053C000DA2D586FF67BD3BAF98282E38373FE3B02 -:1053D00091CB757F2BFFD1BAE7ED14AC376CCB9036 -:1053E00070E9ED3DC2A522D5EB77E5BBAF173ABE1C -:1053F0005E8FF9A5010E5228F310079177BB331F7A -:10540000F1ED5B2D8A8C0B5D29E37243E9AA49E338 -:105410004B5B2D3B0E4450BBF662C5837B07995610 -:1054200071C8960F3CD5E6439EA8CB89D5E2836B25 -:10543000AF423C900EB76E7F243EC1F7DD46B70BFE -:105440007B198D73CD17C28EDF5B986497F204DAF7 -:1054500041DF1CEA57BC9B0CF4BD32479E7B3EFFEC -:10546000B2ABCAE8FBD0EDB557E11EDDA408D9EE1A -:10547000378F47331EA7342A9BF0FEC9E8EDC28B55 -:10548000FBB1BFD4E01EBADD652FE3715D7CFF4E3A -:10549000EFB7784332DF172C16ADE313D927A1F00D -:1054A000FBE63ADE687EAF627EC4E20FC18EFC2F5F -:1054B000DFC32171F1FBDCC3B966786C21E2DBC488 -:1054C0005EF90EE4E4E1C5AB7A135CBE807C07F2C2 -:1054D0009A2F6A5FE3FC66F90E2493CF48868FCF3C -:1054E000C3417E85DFFF98E2DF68E9E5C6BDE015D0 -:1054F000B604D4DF2E3C500B060979AF559F57B642 -:1055000038620957402FE2957803FD11E798017A38 -:10551000C9F3D8F87D90A956970DFC4697738A5D1C -:1055200072EC4275740CDFF70B91132E36F6E6B869 -:105530008D7F3D8EA483EF932FDF15CE72858FF87C -:1055400007F8E6B93C197759B9ECC39196D4AE384F -:1055500092D32981AD78DFF374EA8EE8510ACB113A -:1055600087C05FDB1A9FE77B82C5AB5EE3FB10174A -:105570001B1F8896F7AAA47FA54CC39B6E6F5AA8E1 -:10558000AD4F99163F74BC5EBECF4BE730BFF7718D -:10559000B1D1C67246A8BC2884EB0F88732B6FB4B8 -:1055A000F1DDD3C56B8B57278AEE7E77C52BE3CF12 -:1055B000B5719734DA384EA85C7B472BF477589650 -:1055C0006A72E8D26DE6EF277242E44FFDFD44AD0A -:1055D0004EF15BAFCC6439A8D6C671EEF35748B92B -:1055E00048EC1001DC6798BF629C05EF58CCDFE502 -:1055F000F528DDD0D13B9A7C34098312DEA75E8A80 -:1056000060BE32ED523FCECFBA94C8E98D97B2E476 -:1056100077AC1DD14B6BA1BC5FFFBE2617CD441CE0 -:105620006501E4B23E4CD71D44D7182257E35743D7 -:10563000BCCA2B30C34FB2F956214E73D246C1F7C4 -:105640009126437EA282D990A70AB02F520AF93E32 -:10565000C64485EFB74C1EBE4CDB07B42F04F311D4 -:105660007EF7C3377E6A00F137B37D3B2C58777DD8 -:105670003FF8FC6DFC0EE664BF62C77B813E4DCFF8 -:10568000D6E93D745F2C88D4EC634E69FFEAB48F91 -:1056900001587E9C27F246C4B32E802DB39FB6B02E -:1056A00084AAA86C599E9C1B79632394AC7FD36E0B -:1056B00032DF6291F79F48FEE3787571A4B00FE581 -:1056C0008BD72AF98897D7E1FA7AD8D849C37A775D -:1056D000D14149E7FECCEE03BD60F95D1926FF4CD0 -:1056E000685A4AF8C63E5A10D3FA63FCD2D0845C9A -:1056F000E11D9F8877C8F5F98A20E202E76AF9DBA5 -:105700009EBDF28F6B9C8C27CE8FCDED7723E23F31 -:10571000FE65FE385FB11A7F37AA4DF17973E53D1A -:10572000C80958DFC8EC767EC76066A64B9E2F215D -:105730007696DB72DDF25D84107B4B69B63C6F843C -:10574000D59D3C8FFD3A6EB657EAF33E6E33DF339C -:10575000D5D3EA5C6937F8BFBA27F1A045DEFB7FF5 -:10576000C412D8F122D16BA0B76F01E6FB08E2BDED -:10577000197E1FCF4F7F47A3934F69EF65E8F474FD -:10578000ACEE22DF972871DADDAA819ECAD6287C8A -:105790001FB1A44EDE27F6AD51E4BDFC1EEC578FC1 -:1057A000CFF99ADF517AFC1711B250C3EF7CFB910D -:1057B000D71C295DF8FD53DDAF6C927F0633106F67 -:1057C0003FB7369CDF41FE7A58D18F017F64B687A0 -:1057D000D76912F134D49F1AE3FB29BE97882307B7 -:1057E000616F5CF0F3B7F87DE19ABD29FCEE61F1E1 -:1057F000EEBCD57847E5EB61BE3B72897E8B9D2E72 -:105800003BE490EAC6583E9717F4D1EEA98B76F6A2 -:10581000E7E9EBF360AE94078A3C729C0B9A3E4535 -:1058200008B34D35D593E77FE83ED4EDA2A1F695B8 -:10583000D0F72ABECB9E027B89DD6057D5ED31B60D -:10584000ACE373709ECFB777FFBB8DAFEB76474D60 -:105850009F5DD8A9CF664FE803B97F9DE2821DBD49 -:10586000CCE9BE11F1F565876C88F01493E2DCF2A7 -:10587000DD92BBE4BB2525B7E6313F9B8F35C9C719 -:10588000BD8751BC8FCB0294C6F7BCDFE7AD7B650B -:10589000C01ED053D0CBF7E0CB5C5E7B9C412E2A60 -:1058A0006D524CEF18E8F91773A51D723EA919C087 -:1058B000DF4DB7A6D8F186D07C128F1037F8BA46E4 -:1058C000277A3BAAC771259352C541F9AE14C19DF1 -:1058D00022C733FE4E514993F93D06AACF72DDFE31 -:1058E000DC28EEAFD845F34E41EA6238090F8CA7A9 -:1058F000F67BA83F378FC3EB511A0CD86037988FCF -:105900007816CACF75056C18A7A451BE8FE25B2B21 -:10591000C7F1AD89B5E7402EB0BAEC038CF260A3B5 -:105920007CCF78BEF6FB11042FCBCB658427DCF34C -:10593000D2EF7D86E2AB5883BFAC29D62C5F36AD63 -:10594000B3617DE6F4F05EC3971A1D97348EE1FBD8 -:10595000F565562FDF97F069F8FEEBB2F0BBE12753 -:1059600099D3FC902D05798D2F7D093CF7069E82F9 -:1059700019FC3ED2B2708E679EE36AE2F976E2FBD2 -:1059800001C20FE4155711E39BE8C48F38C0B2661B -:10599000F3FA76C11325DF656F2EE6FDB7C8EAB3CB -:1059A000BB8C70ACDF9F81FB5B7368DFE3FD27E19D -:1059B000F2F17DCC530FDCC8BFFB063881E7288F9E -:1059C0007B02DE3B22BA61BAD6E9674181DCCFFABD -:1059D0007851C3ACD20E3FECBBF6A9F720E4F30636 -:1059E0005A6FD8FF7BDAA7765C00A471ED65F2DD13 -:1059F000BAD07DABEF577D9FEAFB56DFCF8FD98AB8 -:105A000082894A17DFA1F3BDF6B96EF03449837776 -:105A1000AEB6AE84D75785C1AE376298DCDFF3539C -:105A2000CDFB1FFDA1DF54BD7C6C3003F73DF5FAC3 -:105A3000FAB8F3E3643BEC03D05BEA304B67FDE577 -:105A40005CDF62E21FA59DFC63FBAA04F08F1D0AC8 -:105A5000FBE196DF23E5BEE5CFC87BE16796BFF8A3 -:105A6000F62CAA77FAC18D0B8CF72FCA82925F2C85 -:105A700024790BFC6391260F6CCCF4E50D33ECE735 -:105A8000B2FB9FC9C4FE98DB92770A6FA8D1BCF91C -:105A9000BDA33F3FF3D28757B9BBCE5D7D1E256BBB -:105AA000DEB5153B8D7893F47E7756079F5BA5385E -:105AB000B7E853696331F36191487A8FD2B5EEA1AB -:105AC000F450DCA8B09C575A3732A0FE2FF2EBD22C -:105AD000B553F98D287DBDF4775FF47357877FA6A2 -:105AE000B64E73357A9E3D4CEEC3B9E529F645BCFA -:105AF000FF53ECF8BDCD395AF99C32F3F7CEF5726D -:105B000075F2FBD5D827B89F84F5EA586B93F6CB8E -:105B1000ED97AD5732E4021D8EC59A9D72A1666F56 -:105B20005CA4C9CBB45E8B8DEBB5F871B95EA5CF23 -:105B3000BEF517BC5346F3D3DEA393EF0A94B4EC3F -:105B4000E0759BB3669D2D85EAFD64588A29FEA801 -:105B5000B436CF053BFDDC351B6DE0073F1926F160 -:105B6000164AF7F3B5F8621DAF388F14833F47AF7D -:105B70000F3EB883C6B9755978B4F177ED021A3D76 -:105B800097D6C6C661BCD2DAE27BA17FE9E740E8DE -:105B9000FE3B112EF74509F587FD79628C87EF559D -:105BA000CFD77E372FB4FE431ADDFDDA26DFBF4C98 -:105BB0008A6C7992E33B6A223CE013E9E9AD018CFF -:105BC0000B7A06DC768B7C2F33BDB2F573C041A215 -:105BD0003CC7F520C57B5B10ED1328BFC922EF79C8 -:105BE000A5AA32DDA7E107A637948B5EADFC1E5F48 -:105BF000E7BB5121F46A179BD7E0DD1F7B2FC1EF74 -:105C0000A6E9F4A9F7A3D3A74EBF3DCD6FD7F79C64 -:105C1000DF8914CDCE92E54976D0B80BEE1BC4BF18 -:105C20006BF15DF3B46BEF3576CE374CFEDEC765B6 -:105C3000F34D97FA52CFF36D2E4CE866BEA1F3D424 -:105C4000F7891E43DFE94F6992FE94130A9D63D4DE -:105C5000EEC4B2708EABD3E7A5DBF5BFEFBD878F87 -:105C600086C569F6AAD628C897F3B5DF51114199C0 -:105C7000C7F7A986EFFAF9AFBF5FA7F3E993B5DAE3 -:105C8000F9285AEFC17E1675697C0FF558D389281B -:105C9000BC1373628C844F6F77AB4DDE73165176F5 -:105CA00037DECFBBE9D63CFEBD94858D7D589FBDC8 -:105CB000A92E8DF9C24D7E581745A71EB048E38323 -:105CC00091B716AFBE02F5D7A7F0EFC22D747A4E8A -:105CD000ADE7F6433D9013239BA7DA53591E96FA7E -:105CE00082EE17BB5511457C4F0D7C12FBCBB23FAA -:105CF0001DE7CFE2F5523F9864116BE03F1DD8508D -:105D000034A12FF8C4C38AFC3D9A0DE6F7BC860E79 -:105D10002AFA027C26F45DBC5B6D2D5EE8A782E466 -:105D20000ED8D1163A8B589EBF45E393C79ADBF83D -:105D3000BD7E1DAF8FE0BF78A72AC47E146A271AE4 -:105D4000A8D907FF1FAF8F7B3D0080000000000037 -:105D50001F8B08000000000000FFB57C0B5C546541 -:105D6000DAF87BCE992BCCC080C84512878B84850E -:105D700034C080D7DA518150BBA0BBB9BA218E653F -:105D8000CA650650DB5D77D7FE8CA1A6667DFA4515 -:105D9000A665ED80976AC376483428A8C90B99593F -:105DA0007F62376A2FB9635BE62D40BAFCEDBF6DA9 -:105DB0007DCFF3BCE7301751DBFDBE6FFCF97B797B -:105DC000DFF35E9FFBF3BCCF3963348C751B186324 -:105DD0002A8B8E413968488964998C8D09695F6185 -:105DE0004C89C3F625DB45C64640FB7C93C8621947 -:105DF0002BD731FA7D8FBF1F31761F3C37C3F3425B -:105E0000A934D607FDD737CCA072C9D6C26DAEF182 -:105E10008C250925B1936360C0E36AB6078A25CE55 -:105E20001977302BCCD3A48DD225C373B52B29C7BA -:105E3000E09F6F49E343490CC69D69D4CF77437B0C -:105E400081694E41148C5FBA332A5B32FBFB5D6F74 -:105E500011181BC958A573461C4B61CCF1DDE167D5 -:105E60004CA9B01F98D304F37FE50977BBA08BA39F -:105E7000AE2D4982233CAAB3A758A07F95D8316F95 -:105E800012CC734E70EF4DA0FEE63853C0FAA1E578 -:105E9000E93AC6CCE98C39FFCF8734CFE7E2893BBA -:105EA00016C07887737F04CE53F5F81FF201326C69 -:105EB0009D68CFB2E4E1BC8D7B4D121C747B6356B0 -:105EC000099CE3BEC7C746DA332F9FF7B668B6A86A -:105ED00004DACBDB18C157695FE88ED420DCED5EB5 -:105EE000A6316169629A6828CF486C9507CADB526F -:105EF000D8A2B9067FBB0DE100EB9E89DC9254026B -:105F0000ED157B9F48324379D6C8EBA57B7F7A9C01 -:105F10004540FFDD5A0DE2D5AE621A0B8CBBD7258A -:105F2000D8DC50B2F268C61210A36E7D9991B159B7 -:105F300096709AAF627B0E63B9FE7DC1736A3FAB08 -:105F400062C5B88F31F503D9CBA1FC8BCA7B1FE2A8 -:105F5000F32FB57A8B2B19F16226BCFC658B548428 -:105F6000EDAEFB053656C0FA7E631AAC5F16C96A01 -:105F7000717CA1F4579B04CF571C10B2B5307B78CD -:105F800066B7E61E039116D159B589D3D98A7675BD -:105F90005122E07F458B402D0E9557331CBE2A2F92 -:105FA0004D66E680FD56B6B668CCB08EA319CE0914 -:105FB000FD1D9E539AA5785EB685B17CC027FE89EB -:105FC000F86B3EA5B937003FD5AD1C2ECE56DEBED0 -:105FD0003803903B99B66213D2A0DE2650BD3E6BCB -:105FE000C2FC35AAC07AFEFC3569589A084E4C3579 -:105FF000905402F0DC94D1A341FC3BD7CAF3425D3C -:106000001DB05E0D12E548DE9E6AC0F1661AAF3C17 -:1060100077B646D178AF336C03BB0936516D50610A -:1060200059EF344460B9B356CC50597173611609B5 -:10603000E0DF111691C52261CAAA5E3D4012503BB5 -:10604000705884F6DC48FB83489F710CB802E83333 -:1060500091790506F4DFDFF9592ECE7FCB18DF17D3 -:106060000CB6AE5E337D7E01D0C3268B7C8E4C5F3A -:106070002ED2F1C84340AFB0BFA7D56C833E07CF47 -:1060800057C2E6423BCCC208CFDF84B9F7C0DFAFCE -:10609000316F22CECF74DE541CF79ACCA7255AC399 -:1060A0000601F6F59B14FB63B88F3B05F5F86C1100 -:1060B00071208DC57EFD6AFE9C6D79C2A603FC4FE2 -:1060C000E7E867A345E66240A29A51F106A463C1DE -:1060D0006663AB60FD07330FDDCB802E1E1ED03113 -:1060E0002D9CAF5ECFCF3D7D20EC9400FD468F2AE6 -:1060F000165916F437AB5829F43F94297A55D89F8E -:10610000E9DCD89FE90A6DBE0C599681FCD0887AEB -:106110001BF5EF78F31B01CA44E9E2E1483857E286 -:106120002F054B3DF4291B3CFDF4FF85B2F452537F -:10613000CBEFA1FC75A4BD19517772B0F8941D5036 -:10614000F6B0C9A3B364F2F902F7DFF1AB6F22A294 -:1061500045FFBEFA074EEF7BD98AA5CE22C0B8E92B -:106160001D92579B75F97EFAE361E3A9D48FE1395B -:10617000FB0DA25B10B0FFE10F717FD37506AF146A -:1061800081E3D4177C3AFF38661E1D75FA4646280F -:10619000F83E91B158DC3C8C1FB8687037C1B96FBC -:1061A00091F94FA1AF1E8B48F8E991F1A4C091E994 -:1061B000B222917EEBD58A5EF085B34C3F7FD6E864 -:1061C00038FF0C5E126D38FF60B9D6CD608AC18E83 -:1061D00054D2275792A77F0079CA40D7BC976AFB51 -:1061E00033C20FF94A07FC78970C2FC03FC3F9253B -:1061F00079FEBB64B8DD6510399C7E120227996E6A -:1062000014BA50F62F98635869B41F9FECD7DD4736 -:106210002393098FE3FF83E3EF13C2DF3727D60110 -:106220001BB151FF984578FC5FC09F57B4FE0BF837 -:10623000EB0EC59F577F3DE2EF71D1D284FC800801 -:10624000C8A1D226C2F9580623FE2F93C22C9BE088 -:106250007C76E4FF9B88EF8F22DF2BFC3EA6D837AD -:106260001EF5E449C69EC17DF9440FB5A766A71087 -:106270009F5FC7BA13B01DF09C3717F12ED876E890 -:10628000242C7DFB5E86F55D1506CB1E386FBF5B4B -:1062900074A961FE8628F78EA5B06EC35D991617A6 -:1062A000B63396D58672A03CCC827ABE218ACB8545 -:1062B0008605E9A4870F7E2725ADC2732C08B33469 -:1062C00041FF866CDF2313A0DE30D66C7141D757B7 -:1062D0000596BE1DC7CFD1D13A0D7338DD363C329D -:1062E000DA8D7A05F4CFF37AA83F591EC6F09C0DDB -:1062F0008DB68468A0CB9722ECA3B361FFA3244E94 -:10630000D70DC9D00EE536A164C17D38DF78BE6FE8 -:10631000DF82B017F7C22CFA341059D07E7295B1D3 -:1063200009E5A5429777A5737937C6756A07C2C98B -:10633000359D65D4C2FC7F93E94B81BB60636C558E -:10634000B41FFE0A9DC5C8701756737A734D97E542 -:10635000623573D70B085FE60B07F8966941414237 -:106360006934D9ADB8EFFAE5801709F7CFE17F526C -:1063700064E59E61F8E747282CF3884C04E48F32EB -:10638000C6F9A30CE908E96F15D05100FD31DF759E -:1063900051A7C3653A82F16B8D25D370BDCF853F80 -:1063A000E463E3897F4AF3875B67563697030BF410 -:1063B000F699D89FED8E14515FAE30F1F54E647FA3 -:1063C000361AF5C5C95FBD791D96C7234A6ECB86BF -:1063D000FEDB167C5D84E2FC6F093E359EE36F0BAD -:1063E000FEFF68B443CA56BF49F4FE43F759281963 -:1063F00032504EAF047DA615B0E474B0F23E467440 -:1064000090C86A896EE365FD050CA3473975F300F2 -:10641000D88ECABCF0FF4797746C89CE5F9FC6A226 -:1064200082EA33740941FD0B4DC941CF6F8D1F17AF -:10643000F47CA6393BA83E3B635250FFDB2DD38250 -:10644000EA774E9C19D47F8E6D4E50DDC64C241FCA -:106450003AEA8A733F01BBE1B5BA92DC4F5497E345 -:1064600063AAF6D07EB305E824DB3B5F3509EA91E9 -:10647000875626437D53CB115E4F3CF44532E06690 -:1064800073CBD1F92AD0DB536F3CF4450AD41F6D8E -:10649000E9E2CFA7C062A340ACB6BC39DF05F89AE9 -:1064A0009B62DF8AF89A77A9F6288AF9F7D7CCBDDC -:1064B0002F5942B930677406EC2737C5FE103EBF2E -:1064C0002BF69E759100FB1F7D5BAB463CBF985D34 -:1064D000B215E9A1FF22A7F353889791FF7E099691 -:1064E00003D9618A9CBD923C54F8AD03F4C61215E1 -:1064F000C24947A5B7CE44E5A1BA782A8FD499D925 -:10650000128063575D0695C7EA2CD47EBC6E229537 -:1065100027EA6C54BE5B574C65775D09950AFFB25C -:10652000BD960D6A2442972AEAB4CE4F8F57D263A4 -:106530002028D969059FD0F94DBDAD399BCE759DF9 -:1065400009E959693FDAF9815904FA9D6AD5113D83 -:106550004F35749B75565E47B9B8FB22F38A11BC60 -:106560009F2AB05F8C271BFD98A90E03F54B1B8457 -:106570007E59D8EFCD0494F7536B3516B4639E5013 -:1065800033971EF66F14DF90701DE320CA6CD80598 -:1065900018D53A905771A06BF139F4633A28770F08 -:1065A000F2F54647D72E47F934BACC60A9E7F29501 -:1065B000E44BE2086F02EE2F71A586DA8D628F1927 -:1065C000E5605F9D7716D269812CE70A345CEF3075 -:1065D00011E4BD807CFB6D5722DAF3EDDC9E2FD0F9 -:1065E00096EC44FAAE5671FE65317AF71E5C47D5DB -:1065F0005DF12CF4EB894DB46C4268C51F64696091 -:10660000B717D61467A2DCED615B88AFC15EFD13DE -:10661000D2DB8F3381DF459948609EF8E2F0A64DCA -:1066200002DAADD7E7215DCED59A0F30E0075FF6ED -:1066300000D1FBDC48731E7A0ABEECAF793DCE7CFC -:106640004080E7263630BF00EA55CFE94D9F04F081 -:10665000A9D3131554AF694B307D12C0A755F80765 -:10666000FA47B7092A94BB0E792BA704FB05C4B7D8 -:10667000B3F8730DDFDF8006EDD88BD966A26FB05B -:106680009749EF0FCC34BA9B60BF71236AB357A010 -:10669000FD9469CEC37E49EA8108F463FABF5515BB -:1066A000BBC9EF1988F8C9783F7D3DD321517B28BC -:1066B000DDB5E6707FAF26CDB019F1501DAFD351D7 -:1066C000D971B188919D56928676B94DC3FDCBD0D4 -:1066D000F17B73B81E495EAF21B940A208B66C0BBE -:1066E000634ADDC52632D6F88BB021BF07C0C93456 -:1066F00063653FC8356247415A507F1BF61F7A8E4B -:10670000F61CF38F4F7949BB63AD4A5E0FE96529EB -:1067100073A33F182AC7AB72A365B9C0F1FC748C90 -:10672000BE11F19C26017DE750C94C50268633B23C -:1067300037135FD7BB913E77EB39FDA789BCDC2DC2 -:10674000F2FE9A30E6427A57FC874DB9F629B979BC -:10675000348F97E6915AB291AE139887D657EC24AE -:10676000A51FD8437A1202AA8174C4D754491C16B3 -:106770009E2772A615E58C44FEB0B14F03E4775F07 -:1067800078C4AA40FC55E37843E0B8E9344E19EFE9 -:106790005C25B24F47905C243A72A689E42F564B91 -:1067A000EC8880FE16EBD6A09E53C6F5821CFC1426 -:1067B000F0F047908B587E08F210D7FF33C8432C77 -:1067C000FF0AF210DB4F823CC4D207F210DB3F0617 -:1067D0007988E5BCBB8D56E49F9AB669ECD3207EE0 -:1067E00050DB7D01F5DE69C3D39143A6A3DEE4E16E -:1067F0009FAFCBE17E45EF2D1C9FFDA0BFD1FF00D9 -:10680000BA5C6B8ABEB21EEF37B2F91E80D3B67C7B -:106810006E87F427F0FAD21C35D56D22DB8EE3B7F4 -:10682000E56BF8FA2962393EB745F3797BD345B277 -:106830009FA64E9EB624079EDB62A13DC75FEFBDBB -:10684000813FB78DE2ED437A567E3E25D7A4F8EF1F -:10685000E9DC2F65642701BDD3FC4AFFF726723EB1 -:106860000CEDEF4E138BDDC3C0E32D996F892FD054 -:106870009E463E480EE08B6A33F18542870AFD55FD -:10688000E57238A769653A07DD42F0431D83723A25 -:106890004E4FF625C0C5C6E03CBB05995F42F901E5 -:1068A0004AD4070A3F287CA0D07B22F09910ED3F04 -:1068B000C7CD21F4AA948FCAE7E88E35FE9CF0DAA2 -:1068C000A136A1DF7733CC87E313C5C177EF46FE4E -:1068D0008C359AD1F52C7CC8503B9C1CEBFAEFC24E -:1068E00043910B5780C76570D0F0F25F8503C939BB -:1068F00094E348BFC3C8ADFD39D1B25DCEE9F744DA -:106900008E6D1FD251BFA057A1DFD0AF67C3DAD9B8 -:10691000DBF2397F287454053A10EB8978CED4CB5A -:10692000E59E729EA1732E6324FFD2C2787B289EBF -:10693000957305C8BFC33901F11FC6B87D711DD855 -:1069400017E84F4DC935D33EFA477E56B695F9CF75 -:106950007F470E6F7F4A94881E14FD32D42E488BD9 -:10696000E66406E91D66423FAF534BFCEE057FE649 -:106970002518873E219BE43FBF20E37170FE58112C -:10698000EDBBBEAF0D2ED4637DA3064E0A30BE6FA5 -:106990003B18366497D86E1340EFDE073A06F5D4FD -:1069A00005907B2C9DB173721CA1CF73F124FA73F7 -:1069B000353B24A603504A3BBE9A87F4B4B4536DCA -:1069C000A2B8D0F6C78E213D9E6E15CC6897F4B55F -:1069D000C2F1A1BFB3C1E8D643FF22A863FF650699 -:1069E0008DDBCCD7A3F883435EEF537D750AC68554 -:1069F00066EC5013DC973E2FB9D13E3BBC7DA50A17 -:106A0000EBA7DD028B837145D2EAAE04A8573E2D79 -:106A100058B430CE61283A8BF182CAE799C50BF39E -:106A200057B618C9CF5DDAA0FED817605F94BBB720 -:106A30006AD0EE29DF19DC5EB93BB80EF822F9EF17 -:106A40006886F600F9FC6D8E3186ECCD712C1BED5D -:106A50004DD6C0E3B98A7CBFDC6E757139BA82CB82 -:106A60006DC6BE8C457F5FEAFC2AE96303AFCF9118 -:106A7000EBA7A0FEF9571C2F0A5CAAE5B53F4F60B3 -:106A8000560F9CB7BA536F42FFBFBAFDEF1118B74C -:106A9000AF09F3517C9FBD2299D0DEDBD826B91017 -:106AA000BECE0EFD2E11E0567DE03D8DD988705F83 -:106AB0004EF6CAADCCB51EE3DC5E5164DD4447DD65 -:106AC00014A766B681A5384F5FBBDE847640F52BF0 -:106AD0001F74DD8DF50302D3231E47FB884E96EE0F -:106AE0004086A52DDD26E4FBE94442BC229E3D9173 -:106AF00084AF658877C433E01DF12C213E71BC5111 -:106B0000E3E6742251FDF4731CBF0ADE8BA4CD1A98 -:106B10006CAF6CE4789EB163CFB630A2033593E9D5 -:106B200080F07E7A27C7BBA6739D6614D26F630878 -:106B30001DB46B87E800F777191D84E0BF02F08D64 -:106B40007220940E42F1DF93C3E506D8DFA79F427F -:106B5000FBDB087E01F3C7234656F51E8D81F5CA7F -:106B6000A2CF3B9743FBD8F89758DA088A7F15E401 -:106B700062FC6BE63BEB105D3DB35EC8467AA957FD -:106B8000FBF63C81718BA8708AE3F427CFD9F932E8 -:106B90009CBB20FA9BA416D87FCD6B5ABADE28C9BD -:106BA0001587EC358C9729F174C033C5C99C1D5AE3 -:106BB0001E176B2DB405FA73FD09FC5C859A81B232 -:106BC000E5E817C07CB88E60E37E5E55078F172816 -:106BD0007E59951237680E8E1B08A677A85F452E42 -:106BE0008F5FA5C6DD6C463BBC7E01B387A55E4DBD -:106BF0003FF078CCD3B2DF7445FBF10A7A42B11B87 -:106C0000992B386EA1C8A96513F91E8FFEE2B86AE8 -:106C100004C6FD760B848F8A0E904F70DE0AB7DAB9 -:106C20006D1602F849EEFF19D21BC0ED8CABF6A031 -:106C30002821DD1968BF0E993EAB918EE0BC95D638 -:106C40003722F09C0E59AE38DA8D147FAB645B8A24 -:106C500090EE2A613DEF30F454F95C0BF929D7A28C -:106C600027C5CEAC6E0DEEB7317748CE8CFF1EE057 -:106C7000BB016439D77B2E99FE3223F1DE6F9099E8 -:106C800023919F87F49FC0ED3745FE5CBF1D583CA4 -:106C900060DE716E1D5305AC7FE373A6A0FA784FDA -:106CA0007C50FF9BDACC41CFB3BD1941CF738F59D4 -:106CB00082EA79DD1383FA4FF8D016549FE42B0E45 -:106CC000EA3FE54C49507D3013CE7395FBC15BE341 -:106CD00085A0FE33CDFAA0F967674405D5070D32CC -:106CE0007C64BB52B1775FCEE5F66E68A9C0F776DB -:106CF0004BF03A8ABF7EE7C4E0F5E6D882D7FBA125 -:106D000078D90BFA54057EC273A05FB1FC1DF8134D -:106D10002AF0139AC19FC0FA8BE04F60E9017F020D -:106D2000DB5F027F02EBADE04F60FD20F83F586F64 -:106D3000AB2BA6F295BA126ABF16FCBAE4758FC9DE -:106D4000EB1E97D7FD77E174429EEF5D79BE6E9C96 -:106D50002FCDFFDC593C56BC04FC3C2DFAACC68759 -:106D60007EC30A5F11C62D06DE9218C6A599DD7D89 -:106D7000AC2E06F5D9088A33B39281B731AE527D75 -:106D800020D5B4C98CFAEC0FEFE2F3BE56C98C7C67 -:106D900079A8EDEF1138CF854B61745F4A7A10EF17 -:106DA0001BBF6154DF04CF310E3AB3050408E93745 -:106DB0000FE9B70B694ADD4DF7BD25CD2D1AC45338 -:106DC00015F2293C7FCBA30E7EFE5C63D07313F6D5 -:106DD00087B24AE5A638C2B936653E2FF577A4F1E9 -:106DE0007BCF73CF1D5E3F05F56FCBE211787F5EE1 -:106DF000D5FC5EECBD57C1C7E7075FC8A4FBCA76E8 -:106E000098CFE09FCFD9AE96EB7CFF8EB496A26868 -:106E1000541CCD021B0BC505B685EE5FAADAF63809 -:106E2000506E5565DCAD66009F7E8F24C737F8BD78 -:106E300091C3C4B81DE7F92202EF575FF71CBDC329 -:106E400086F8ED381C81EBF6B74A41FED3682BB7C4 -:106E50008F475B3584BF0BAD8723F05E77A3E730A8 -:106E600087BBCA4BE73F24D7FBA12478B74974FE00 -:106E70008A4B62D03D768655A27966B68D35E2B9E9 -:106E80007A3C7CBD1CAB99B7A72D5E82FB3F1EBF31 -:106E9000204F227B100435CAF11B66EF413BA4CA88 -:106EA00023D986F3EF0AE479BBD49C4EDF4ADBDFBB -:106EB00085F2F878F1886CD2118A9F69E5766F9136 -:106EC000C69E867AA4C76036229D3F589C6A44FCC1 -:106ED0001EC212DB8B7769EC06BCC7E6EBF598BAED -:106EE0002390EE7A5A7325B47794F9F2E57587E822 -:106EF0007B086F2EC253B9BBD180F3F8F1C7DB73A7 -:106F0000AC26EA7FDCFDDE3CB4AB7A32C2C92EE9A6 -:106F1000D230F2A7AB9AB95DDCD391D818784F92F2 -:106F20006395FDF20C91F0DAD7A696FBDDBD8705DF -:106F3000F553D3392FEC0EDE8FC97DEA51B4C71D4E -:106F40004F4B0CF5A2435D1B8BE7FF6C67F0FECA4D -:106F500065383BD4DED8D8007A75B40FF18D81E85E -:106F6000BC5DE11333E153C1634F06B7E77AE2F941 -:106F7000BDA4A3650FD1F5E5F1A4EE64F41F127F63 -:106F8000A9A378E7B5FC67C56E08F0AF18FA8BEADD -:106F9000E2D43C31C56F1FBC966BABB68E44BFAB21 -:106FA00084FCCA1E06F62CACE9447B3A92F21FB66A -:106FB000E1BA83AD6ABABF76EADA667D0276D9A015 -:106FC000051805F63DB8532DDF7BD90C68D72E95F3 -:106FD000EDDACFCCF67C09F4AF738D48E7736486A5 -:106FE000911FD327CBBDCF5B92EF24BBE1986442C6 -:106FF0007F688687DBC18E666ED7567B92FF632AD9 -:10700000DAEDCD6ACCD4608A1DE294ED90D3B2DD86 -:107010007B7ACD8086FC9B4E813D968C792A5BBB2A -:1070200012E1B9337316D9B34EA999EC8965DB83A4 -:10703000ED07B06F82EA55CF85DA17727CCB13DC8F -:10704000AEF887DBAC4376C638F4670AA5A971C8E9 -:107050000F2FC87855FC9B95E32D94B7B351659ECF -:10706000A5C421105E359DFB2B70DF6E479885FC13 -:107070008D55AF105CFBBFE47E4C7F3C2378F4332E -:107080000EDFFE364EE7356AC18DF9483540B6341D -:107090009F4E70AFC138B36B3082E41363C5C8171D -:1070A0002B16707FD586315F286B157E08D1ABB764 -:1070B000A87C5254809C68B3A650BF020DB3A33E77 -:1070C0005B69B4907E1BA3E3767AE16A4F36D2C344 -:1070D00018F0C7B501F1F831860101FBED7E80C7DC -:1070E000FF9578C21C95491D15A01F195B43FD959E -:1070F000F941A2F0F1D79ADF04F31BFCF303BC23A0 -:1071000011DE5F582DA4B793E628F7FFB5C497CAE0 -:10711000792E00BD611C1863348837C7CE37C89FED -:1071200073B2EEF538AE2882EFA308F783F5305E30 -:10713000FE5196E7B179BCBC4D2E15F9D590677B11 -:10714000DF0AF59579F63F5949AE99883E57CAB49A -:1071500002F64C9C6F18F9BBE21D89F0FA05F003AA -:10716000F2FBC25AC19C16642F713AAFE14DEC3C60 -:10717000F3F44E4538B86CDD1998D7C6387F2D5AD0 -:10718000A537A705DE0720BDA3FF5102FFF2D12FCF -:10719000E3BF7253C56D9457B52AD68CF71735C81F -:1071A0000F29D7A6FF50BA87DF4EA4B76AA6B5A0AD -:1071B0007EA9690B7D6E51A13DFE4D085F24C97407 -:1071C000DA6817E87EBDF15B158FA3950A1437BB0B -:1071D0000B1A914EE987FDCAA7B9717ECCB3A0FB0B -:1071E000AE861839EF2B86EEE17E229FFF2E95F7B3 -:1071F0000DE4EFA36A4F32C6718E3AF93DD502E62F -:10720000A17BDD52D64D656F78F5012F4DEE1A8DBD -:107210007EF807762DC5911AD7361951CE66B1B5CD -:1072200026BC1F033679EEFBDC2BDB1BA1F7689431 -:107230009F95E7C7F3CABC92F83CA0833380A3F8BC -:107240009CCBC757BD7F2002E17EFEFEFDF37ECAC8 -:10725000D00F02B905F354D6B664D0BD8C8B7567D8 -:10726000E4FBF1ABE053C11FB49983F00A67B90E98 -:10727000E0339F0DE4636ED3B5F0A9C039493DF00A -:10728000630425E8319243A17856E05ECD6AD53C8F -:10729000FE56FBEE02E8FFB3B5A219EDCACBF07EB5 -:1072A0000DFC78F5FC91D728903F7B257C29785AF6 -:1072B000C8BC54FF308A8FFB70A144F1C3FF697CC6 -:1072C00035E4D94BF2AEC2B7A17C7A25BE5CB42AB4 -:1072D000847F43F874882F2DF02F007FF65511C45A -:1072E0008F0A7E1D66F09351FF75182D6E76393E1C -:1072F000D1DFC5FD54B60AEC49E187F0AB8FFCE362 -:10730000507C01ADD8501F54E705F3A982C72BC9A3 -:107310002D45EE7DC4BC474D02DD67703EFE85966F -:10732000F2E994FB0CE5DEE2D13CAE6F42CB8FC0BC -:107330006EC17BA24D193D23D1DEEBD528F3F07B46 -:10734000D78FD6748FC67CCD8FA6F1B257C3F34CBE -:1073500094BA2D8CC7033F4AD0BA106E1F09E3A61A -:10736000A31DF091F0CB3B783D4E63C6FA82B8E99D -:1073700026A8F7AA95F8E183B2FC7653F9D18209E1 -:1073800005D44F6047101E668195D03A82105D0C7F -:10739000FBF9E8E76373F05E4039FF03793C8EF454 -:1073A0001BF91C43F1F65F09146F5F04AAC384F74D -:1073B00002D39F284E81F693BF4ECDA6FBCA15C1BE -:1073C000EBA3FE4DA638E5569AE7964B03EAC5991E -:1073D000FE7D0DE9CD828BBC7DC9D8A07C665BF4B7 -:1073E00038EE27BB5323518F297A6DF0D87E436046 -:1073F0001CF5AC1C771EAA8F7B2429502FBEB1F739 -:10740000E1749CA75CE3CAB218308FF9A924B41FB9 -:10741000CAF73E944E76EDDE8DE9E89F94373D9CA9 -:107420006EA37AB89DFC23153FF7F97D93766D0A1C -:10743000B0A36F9DC0EDFB52DD1B8568DFCEBAF1B6 -:10744000F37518B71FFB6B81E2700B59F73AD4B78D -:1074500065199CAF58838EE43FCC47F7A47BC6DD0B -:10746000BE1BE5FEF18CBFAB97A0FECD53D17C6572 -:10747000CCBD390EE36F1B048ABFF9FB8FA67BD707 -:10748000C56B054D7C0CEA519E77FDC7BC2882E395 -:107490003D1BB2BBB0BD6C356F9FA575B7F6E03C28 -:1074A0004F6828CF0A14654A49C03DF61FF3F83DDE -:1074B000DDA2CD72BEB1BCCED86DB18D81E7FCA38B -:1074C0008C7F56FE01C9833B65BCDCB6FABD23F157 -:1074D000306FA4DAFE67942BEF3E7E3A0DE55941FA -:1074E000F4D94CA4F3B11AFB931578EE262DC52BD5 -:1074F000AD5989521CF4CFB97FDA63582E5ABDF8C2 -:10750000C90A8CFB6ED7911FA6EC6F856016D15F00 -:107510003DDCF8D37B106E671EE779A42B1AAF8F82 -:10752000BB5AFEE2B3753C1FFCF93A1D952FD49966 -:1075300098198EB8AF2E9EEABFAF3353C9E673FADF -:1075400052F2A6AE345FEEA530CA5BB66ED0511EC5 -:107550007DAED6F6551EC06BEC0DCEA68DF2B9C62B -:10756000C2F86C57F20C848375E3F22E34614FE558 -:1075700071FFEAED9E0D496487AF3EF54C053CCFA7 -:10758000CC2FF90EC7EB765EA478C1E1F687CA105E -:10759000DEE54D5A7E3EF9DC671E4F8F7B12E3BC61 -:1075A0006FA9C97FAFD979EA998D50DEBB79B92629 -:1075B00090DE7FE879BF95F7732DBEBA121CFE7579 -:1075C000BE7A3889F8A709F82AF3DFE7AB9AD56BBA -:1075D000087E73F34BC6E6C3FECFA85D49C84F676C -:1075E000C6DD4C74EEEA1408FE8A1C57C6A7E6F303 -:1075F000FBE82AD1B399EC48598E7F059E23C2F748 -:107600008DF6CFD2D18EFEAA6DC155CF7DB00E3D85 -:10761000228C9BE9A80C7D9EAFB1A7625E71BEC8AB -:10762000EDE7D0E7B7E72B71781EB7C59F1090A79D -:10763000E2848D4546A3FE13BC6120979D6DB79EE5 -:1076400055A1FF067EE1C7C17628FB3840AF5F69D0 -:10765000BFD72AAB711E955FEE4EF85064DE003D39 -:107660003EC917C6BC01EB0EF92BD0A6A1FB9E04A8 -:10767000920B8837CC87EA6B1FD784F5B31A8EC775 -:10768000BE83E097F1B80C93F2FDE73CDB7E3E0B46 -:10769000E56CE879AB5F394FF4E1687BE8A240E73D -:1076A0009F79569575EDF3BFB1F77C16E2EFACDA32 -:1076B000978FFE579FC6978578A87E95CBF37F1549 -:1076C0000E4A7BC5060D8F130A26F2230BA50B1459 -:1076D00007E83BC6E300D5EDBB489E0E76F0784C3C -:1076E0008DD85D1487F18BDA535D28CF06E3B95F3F -:1076F00006F3DB28CF2155D683AA81A43920D71ED3 -:1077000019A207EE0F9E41FED5E03C1E07E561651C -:107710008533B42BCE213F437BD9AAE4F548E767F4 -:10772000DC2373503EBE9DF58F6A8ADFBD1E6E92CC -:10773000C88E9530C778084E43E7704B3CD18729F7 -:10774000767138B305F4ABD198EF24BFFA38BF9FF8 -:10775000ABB981F3137B85F39373ED1B9AF880F932 -:107760007E25F393624FCE7AFD1FC4970FE7DA9E12 -:1077700040BE0C475988F3C547521EB5F21E8772AA -:107780001F69E890FDF862899ED7B4490CEFE5586F -:10779000BC91F20A8AD916CAB79CC53C53795E8F50 -:1077A000EFD129F07CF6EB522EE6A1813D4DF7DBBF -:1077B0004561F634CCD3EA150519AE1EEB9C007D6D -:1077C000F67E3EF757A74A02E9B1818470B253664C -:1077D000CE7796E27E957E5A91EB339887EC2CE635 -:1077E0001EC8C27B55E61DC8C2FB56A5DFBCD7C369 -:1077F0006B492F328F755EC03AA7F379BCF30BBC8F -:107800001F07795223DFC3164ADF6E437F6B45277C -:10781000BF7FEC15933FC03C3317C019F17A1EF0BF -:107820006A43FD6367361BF2CFF8916EE49F9A7D41 -:1078300002C37CBDEA766D13C685AAD5BE58A4E7FF -:107840008D6DEF6B909E6BF05E763C8E6772BCDC4C -:107850004479BF3526C6EFF5DAAEFF00E376CE6396 -:107860005C8B3A55EF513C00E536AE57D5DA42FE17 -:10787000BF8379C9FF773407D3CD603C8FE787F2A8 -:10788000C9E97C73107FCCDCCEF9631EE6731B68FC -:1078900038C55F67C6C7915DE21FC7F16093CEAF81 -:1078A000433BA63F45A07CFCFE30D75AB48F5CE931 -:1078B000DCAEE97FED052BBDF7A3735B7F8CF93C54 -:1078C000B2DD3B73C3569514B09F991D3CDED81FA3 -:1078D000C6CA0F12DEEDD7213E7CB92567F231BE54 -:1078E000A31978770AC683441E1F0D3D875D8E6BF2 -:1078F0001C67FCFD2865DFB31313B93C636EA2A3BC -:107900002E39BF5BC9D751C6DF324150EED1B89F87 -:107910002458AEFA5E1ADED7609E2BDED760F93BA4 -:10792000391F16EF6BB0FEA29C0F8BF735D88EF780 -:1079300035586F95F361F1BE06EB785F83E52B72E6 -:107940003EEC71DC2AE5F16D7C0AE9A20B796D94BD -:10795000BFDE1B1D521F15DCBF375A08AE8F12A8A1 -:10796000BF69C2C6A730FF7893922FC5CC46B4C377 -:107970002AC2F9FB1AA9067BEC04F4F38B77ED45D8 -:107980007F1EF89BDE9F2B885E504AEF97C46819D4 -:10799000CAA3DB27D8474F80F1C78ECD48DB4A7298 -:1079A000524FF7ECBD3FBB3192E27A6F494C8225D2 -:1079B000A765E4AEB5427D9A4120FA85F96E2A5159 -:1079C000FC4C986746C762AB8ACB0713DACB85922B -:1079D0006309AEB322419F8B72F888D59E81FB511B -:1079E000E05D346A591ADA455D6AF307189F75BD80 -:1079F000A366E85729713CA5DF93D669F9B8BF990A -:107A000019A96B73707E60369477360D6BC6FDD9FD -:107A1000C470A19EE4975985F2207F02A79BE96676 -:107A20006E1F7B35665534FAF561D362F05EB74B55 -:107A3000C6F33119CFC7653CE33D57818ADF7361D7 -:107A400089F75C5886E6A32DCF2FB14D20780F24FF -:107A500005E6B3CD92DF97000AA1F7D49C721CF320 -:107A60004B59EE34E695DCCAC779689E2A398E7781 -:107A70005E1D7C6FA88CF38F6754CEBD89CB6B16CF -:107A8000A9E179BFD73117E615CF7D3981E2507D65 -:107A90006ED1A506BCCF055E4779C65EE6FE2E8B8D -:107AA000E77C33777F1CF5AB97E3A9CEE8EE747CD7 -:107AB000AFA34FE62FA57EF03B9E97E4CC81BA8121 -:107AC000DE23A1F339E776A74741BD4FD08B485F4E -:107AD000CE26FEBC47E63F678A3C9F7C1EA6F32469 -:107AE000213EFA3B5F4EC2F7103719BC4BB9FCF789 -:107AF000A693DC66DE74CC6F3A2F784E62BEF1AD91 -:107B00006D29A5986F7F5EED7906EBB3DBD2785DCA -:107B10006839690A7C3ED29384F9C8B7B6A59662E3 -:107B20003EF2F9912DCF445902EAEA974EE273CD25 -:107B30008369A5989F3C5BEB3E568774F37B4E5F51 -:107B4000FA7D074E237CAADAB9FD3E7DDF810B2F3B -:107B5000A17E3E60A4BC8275139209DFF5EDCF6E65 -:107B6000467AEB6B51133F6C6A7EFF99DF503F2DD5 -:107B70008559666B3D560CC994B41DBA1BF7353B4D -:107B8000DCF325D6174FBC89F6317B04E7EBA51350 -:107B9000734A914FFB0EECFB05EAB3D99160D8E232 -:107BA0007E5ED0137E2AF78F2BC0B8409FB1BB0CEE -:107BB000E7AFFE9D96E71FEC8F9B8E7182FF9CC006 -:107BC000F3312A6ED89284FA567CE5F9BDBFC1F82C -:107BD000E6EFF474DF5313CDEDBD4AA9317F39E1EF -:107BE0006FD75ECC5BE97B5E4FF7AF151893B3E2BE -:107BF0007BAC63293EFFEA3FFF5E8678289476EEF1 -:107C0000C5F62F77EB4584438FC6167933F2618F23 -:107C10009AFCCE0AB95ED13B82EF27DC5744F88B41 -:107C2000D99284FAB672C4AFEEC07DCF96B63C83CB -:107C30007E0F7B564B770E679F07B8C1B8B37BD4D6 -:107C4000984903FB30AA905ECE0B5BCA9EC4F9F73D -:107C5000F07EE7F55B089EAE3DD7335C0FFA31D47A -:107C6000C7E785AD41ED67F73C9B857EE9B9DFCD80 -:107C700026FF54A173855F2A776B83F422498258CB -:107C80008C5BCA3F938B1902E259E70EEEE87B92B8 -:107C9000F9C79F6B567B3500A30A2D5B8BF9CD0A84 -:107CA0003F5426DE5A8CE7AB141BD3D17EA9C8F50E -:107CB00095215F9CD5335D3CF47B5BD65B95AD6BCA -:107CC000E6A01D7CA5FDFC4596475FC97CF8559B49 -:107CD000DE1D78DF185AFEB58E994FA8FCF585B5E4 -:107CE0005AB2E595F9DED6781CE8AF554773F971BD -:107CF00012FA37831CFB93ACEF16AD0AEEFFEE04CD -:107D00009E4F59ADF1A5A3FE53E67F7B8289DB87A9 -:107D10002A5F3ACAABD071B32559DEBC2090BCA90A -:107D20006C154ED1FB2408D2583F3C2B752E37E6FC -:107D3000130D8787F87C190F12E6F170BEAA6CD676 -:107D4000DBF4304F55982F02ED2587D117817650FF -:107D5000DF2B126B92D117A3CC9FE25F4F89535652 -:107D600078D436FD70EBC171D04F5E867F03285604 -:107D70004FE47C53DE164EEB31932F1FE9B67C6740 -:107D8000F0383CA729801FFBDA76C506FAEB0CF722 -:107D90004DF751A7886FFAFFF931BD075E29B2B5DB -:107DA000784F794EE0EF83409DDE073927DF775625 -:107DB0007E6D0843FA39F79583F8B84FF0919C7BB4 -:107DC000B1CD4672AC4FED2339B76B6211AF47F9B5 -:107DD000CA506EBD38F1A7243FFA127C65F89ED2D6 -:107DE00066A58E2FCC811DD0D1B690E4C96C89E7F1 -:107DF00051B05D6A138F1371782F93E1C4D886DE7A -:107E00003AF243D466B4973A272AF7421AFFF92583 -:107E10003F3FF531F3BE56E4CF7203C57DC0BE6A65 -:107E20007E09EDC005B1168CA787C24DB95F8C895C -:107E3000FE6629E2E91DA37DECC43CBCCFF4919F12 -:107E400001D44EF67CF56B5AF237FBD5037B517E9D -:107E5000B98DF67113019E0E4DF77A547117D4BE89 -:107E60002E34ED6721BD911CE1F4D697B98BBF0785 -:107E700022DF4F4E92F100FA8C35227D081CCF870D -:107E8000DBF69F4079D3D79D4A723A949FCEB63D98 -:107E9000168172E343D0EFAE8078C0878B9FA57CBC -:107EA00080F9980702E53D6B83CF37F8ED8FC92F36 -:107EB000649B03DA911E1B82EBA17041BAF406F1B8 -:107EC000818BF67D3FF21BC0A76A7A7735C261A825 -:107ED0003E17EA5240FD50483DA43F2BE1F6C3FD5A -:107EE0001318CDEB18EDED253F7E1FCFEFAD07BD8D -:107EF00046F503E1743F2DEE03BD15C3F516EA8B7D -:107F0000AA886E8A5FF51DD0D2BDCA83ED9F25E198 -:107F1000F9811E294E53D5FE722CFAF7EB2698698B -:107F20007ED08FB1941773A03D16FD11A5DD217A87 -:107F3000D2E5F70CB2507E28ED4EC99B4E79E54252 -:107F400077163E5F27CB1987087509EB8CCEE110B9 -:107F500038DFB37689E47C28DE56C9F40AF2218B37 -:107F6000F2395EE1F103451E54C872E510B667723E -:107F7000FE3729F75278CF847C3F8C9CF85A8123B6 -:107F8000ABA5F8CEFD13CDBC2E8FA77979FC89E780 -:107F9000EDBD7A3E2B2513C79995F745FDF228D5FF -:107FA0002F5F500EC4931C78501D0BE7AA7C46B07F -:107FB000D4C3908AD23545D09D2D532D2FA2B81A07 -:107FC000E6E71A2EDF57281D454EE4F8AD14B91F19 -:107FD0005EB957A0FBA5736A7E6F07F286DE0F5865 -:107FE00056B0A608F9EFBE18A726D05FBED6FC4B48 -:107FF0001B82EBCB6AD714C50DC3E795ABB6768D64 -:108000006497CF57616F2C8A355FDEAEECFB9C5EC8 -:10801000D9E774F5C84078CC5F533412CA65BA7F8B -:10802000171EFCDCE7DAB55ECA572D5D43F7C4B70F -:108030005CAA0D8AB35E6BBE0AE6A67B902BED3F71 -:10804000B47408DE5E8C2B31E0AF3DC467C03701ED -:10805000EBC5CBF43A149F285F3C06FD53665F3CAA -:1080600026303E115AE29B3322E58AB8A8043E2C02 -:10807000B30C030FA5FFD1893CCE1A3F91D3F1A8D1 -:10808000D9553B5E6214D7E941F97BA5F74CFE2236 -:10809000EFEF07BF6732239CF7EBD49B30FED3DFB3 -:1080A000F90DC587FBD719E6F37B07034B80E75D26 -:1080B000F1E39B02E3C0AB26713B24DCCAED9D9A41 -:1080C0000CF5D5E34B99C6A1F812D91B99E174DFE1 -:1080D000D2D7F605E9B7FE8E3C13DE8BF475BB0DE7 -:1080E000C86F35FFFC7FB1A887FB3A3EA5BCB4BE84 -:1080F0006F3FA37CB58D72DEE0A13639DFABDB6C60 -:10810000C4F6FEE2BF1761BF4D72E98F2FF0F898F9 -:10811000522AF18300FFF93BD4537B4C1B1FC554FB -:1081200099CAB02D24BFC07F8E46BDE18F2B98E346 -:10813000868BC304C615D2543CAE8025C615D2D258 -:10814000785C01EB1857C012E30AD88E7105AC6356 -:108150005C01EB1857C03AC615B0C4B802B67F2907 -:10816000BFE7D10F828BC73D0D24F757627E33C026 -:108170006F6527BFBF5AB947A27B617CCF03F5DF8C -:1081800065793BAD72DE8E672BDD07D61C902C889F -:10819000227C1FC4958EF93B0347311E54D32258CD -:1081A000D698B17D3EED636347DE07A5D8BE476D27 -:1081B00011CD444F1C9F8D825B8F7CD5B187E257D8 -:1081C00005719D94EF5FD32C308CBBCED3723FD919 -:1081D00029416B0EDDAB921DEDD47693FF52F59CD9 -:1081E000600E7CEFBB66E2459213CA7DF552FE88B5 -:1081F000393D7AF392203D6BE37957F827ECC72994 -:10820000E777931D1260172DC57B6C6C97BEA5F7A1 -:108210004D9CE0E08E10AE9D7755D9D1B21EF3B5DE -:108220007E68FE55E124F9DE3A9BBF4752FCF89286 -:108230007D0760BDC12D5AB2536E9F60BF6D521E47 -:10824000E619D828EE72B4534F7ED6275BAF0F8A5B -:10825000BB144AD751DC63855A20FD7DC46A9F3B1D -:1082600009E87246F1BD146F99116F243E56E8F08B -:10827000496BC94F70DE15E3F977980AB5ECE7341E -:108280009F9CCFA5E0A9B05E70E3F72C16330BBD21 -:108290003FB008C0877151E5FB1F8B18CFAF50E886 -:1082A0006AC55681E88ABEBC10F0BD8445F83D1011 -:1082B000D07FF76AB9FD9B28F27BF2C44D3C8FE278 -:1082C0003E66A7FC9165487D12E9D7D77CD06E0F3A -:1082D000BF2E89DBF7E6389C7FF17135E50717C6BD -:1082E000DD9E6E273D5F40F91382F76EE9FB1BAF01 -:1082F000263F83F3278EAAB9DC0178929FD585F4B7 -:108300004AF11E3B95C7EBCAA99C22BF1F16FA5E15 -:10831000437FE7CB2D38BEB0C66041F85FF13DC06A -:10832000B0ABBFFFE694F3EB12C59E5C33C2E36BC8 -:108330008305E15118D749EF89A5CAF33F9C5BB289 -:1083400009F1698B602E5C1FEF69B6007C8BF040F1 -:1083500002C6D13D367CCF66A05330513EF56572E2 -:1083600074EB3ACC53A949134C18AF2D0ADB5218C1 -:108370000BF317A524D377766ADA781CB60F4A4E2A -:108380000753DC92C0C7AA62317ECFF1E8CBB53F7C -:108390003D29CFDF3E5BE6B3FE8E2F781EF1B5E3BD -:1083A000B4BBE9FB1C4C4FEFAFD30FF635FBC6D186 -:1083B00014AF55E868B039AE09E9A845D613A5A5AC -:1083C000EFA9D18E68CCB337231CCA965C5C174BDF -:1083D000E71C3E4EA6E4DF87C6C902E5EDFF46DE98 -:1083E000FD89BA5A2ADFAD5B4565779D8B9E07E80C -:1083F0008B2308BF1F106F7D7BD230F156A6334709 -:1084000092BE05BEE7F1ED90F82AF0BB18C0EF333D -:108410003AA2EED980F64883C682F7CD98FFBCD247 -:1084200040F2E1FD49C3C65915F819282E3BC8F49E -:10843000398887E919A92A119EFF6D921014E74423 -:10844000BEC17322DF60897CA352F9F9E6690DA3EE -:10845000EF94A17DE022FB404FF85DBF06E40AD413 -:10846000EF65A620B9722144AE8023F3337A5FAC66 -:1084700043CB3609FEFCCFE9505CCA1946CE78B82A -:108480009C191DE6799EBEB3501D46F9C5C0EF4448 -:10849000674737F2BCBD25AC84D61D46DED07B3E97 -:1084A000F78E1838F914F4BFF76103D939EB139636 -:1084B000E6FF77E4CD9F2771783C81DF73505DED57 -:1084C0007B0E9B05BC8F5DB1906523BE95EF39C4D3 -:1084D000C118F27BFFF5EF398C983C12BFE7E00A38 -:1084E000FA9E43DC15BEE7306AB27161E0F71C46C4 -:1084F0004D1EB130F87B0EC685F89DB2FFC1EF3935 -:10850000A44FCEBBFC7B0E374E36FFA0EF39803D2B -:108510009B89E34FE4D8C66399289F3BF4FDE5E3CC -:10852000F23D6497682FC5B228C2A5A276D16DC569 -:10853000F26DD1733FB6035F4C4478153D967D03D1 -:108540007E972551EBA1BCF227ADB64938FF6BB938 -:10855000B6C9F83C34DE5F2F9F0FF6730BF60BCDD8 -:108560001F53E8E2AEC95C0ECD93CBA9F5C3BFC7DC -:108570003F6F32BF4FBED6BE61BF77E07ACAFED929 -:1085800096C556DC0FECF74EDC27ECB7044B66883B -:108590000E7A0FF8727A75C9FB62742E908FB33F12 -:1085A000E1F62895E92A7714DA0DA31E7047E17EDB -:1085B00047350EE8F17D90DFBA06F4683FFC76F5AA -:1085C000801EDB7F6BE3F9DAA1F36F9FCCFD91F4A2 -:1085D000A903347E0CFCDD4DFEC14014DA6DE9E5E3 -:1085E0004734AE147A4F6DF62741769399F87B8C19 -:1085F000DC36E60191213D8CD9C1781E63410CE93E -:10860000B94A1DEF5AF9C0FD22D2D13837EC3B8070 -:10861000FEAEDFAE1A0C7EAFD74BE3AAE425C05EF8 -:108620000B7AEE643CBF74942C8FD05EC4EFD939C2 -:10863000CB8FD077A6C08E0B998FBE7930944F59CF -:10864000ADB3BFE63353BE6250BFA577FF663DFAB8 -:10865000B5E5A55B35E4172F69598FA5C3F19E26B3 -:108660008E917D19D41FECCBA0FA65FB0CD947F590 -:10867000FD17D7C70DB32ED0C156A413850E8EAAF1 -:108680003DE3D04F3DEA0CB3F0F71D3CF45D9A2674 -:10869000F9BDF45DFF39DDCAF365395DC0F81D3FF2 -:1086A0008C8EEAA9BFF21DAF6B958A1C1CFACE8D89 -:1086B00086B9285E39CB4872AE46F6FFAA9798C8AD -:1086C0001E51F8BA5AE539B51EFBC51879FE9B8ACA -:1086D000D1F7AB7AC45194CF4D3FACCF4AA5FBAC98 -:1086E000D87A8F17E71DB85DA0EFB9158473B95A12 -:1086F0002896389E85E74744FE5D81A7517E4898BD -:1087000047C1BF37302597BF3F10CFF877DB98CAF6 -:108710001CF29D36391E7AEDEFB4F1EF92CDE7F7FA -:10872000720D5125A5CBF1F9821BE8F9C1EF521F5B -:10873000B1E2FE2A94EFB4717BBF614E063D7F55D6 -:1087400030AF413DE17A805DE93B6D7AE4FB80EF3B -:10875000B3BD87F8BAD6F7D994EF0F1C5D70C32369 -:108760007B391CBD78EF5533CB18E4AFFF17313C94 -:108770009ED2C05600000000000000000000000073 -:088780000408350000000000B0 -:00000001FF diff --git a/firmware/bnx2x-e1h-4.8.53.0.fw.ihex b/firmware/bnx2x-e1h-4.8.53.0.fw.ihex deleted file mode 100644 index 48d7612..0000000 --- a/firmware/bnx2x-e1h-4.8.53.0.fw.ihex +++ /dev/null @@ -1,12028 +0,0 @@ -:10000000000039D8000000600000063000003A40CF -:100010000000191C000040780000009C0000599866 -:10002000000082E400005A38000000D40000DD2007 -:100030000000C7CC0000DDF8000000780001A5C872 -:10004000000056980001A648000000C00001FCE82E -:100050000000F1D40001FDB0000000040002EF88B0 -:10006000020400480000000F020400540000004594 -:1000700002040058000000840204005C0000000636 -:100080000204007000000004020400780000000078 -:100090000204007C121700000204008022170000F6 -:1000A00002040084321700000604008800000005E6 -:1000B0000204009C12150000020400A0221500009A -:1000C000020400A432150000060400A80000000489 -:1000D000020400B802100000020400BC001000007E -:1000E000020400C010100000020400C42010000030 -:1000F000020400C830100000020400CC40100000D0 -:10010000060400D000000003020400DC0010000020 -:10011000020400E012140000020400E422140000B3 -:10012000020400E832140000020400EC4214000053 -:10013000060400F000000003010401240000000098 -:1001400001040128000000000104012C000000004F -:100150000104013000000000020401D00000890603 -:1001600002040004000000FF02040008000000FF79 -:100170000204000C000000FF02040010000000FF59 -:1001800002040014000000FF02040018000000FF39 -:100190000204001C000000FF02040020000000FF19 -:1001A000020400240000003E0204002800000000B9 -:1001B0000204002C0000003F020400300000003F59 -:1001C000020400340000003F020400380000003F39 -:1001D0000204003C0000003F020400400000003F19 -:1001E000020400440000003F020404CC00000001AF -:1001F00002042008000002110204200C000002008A -:10020000020420100000020402042014000002195D -:100210000204201C0000FFFF020420200000FFFF5A -:10022000020420240000FFFF020420280000FFFF3A -:1002300002042038000000200204203C00000000DE -:100240000204204000000034020420440000003575 -:10025000060420480000001C020420B80000000131 -:10026000060420BC0000005F0204223807FFFFFFE5 -:100270000204223C0000003F0204224007FFFFFF6F -:10028000020422440000000F010422480000000084 -:100290000104224C00000000010422500000000074 -:1002A0000104225400000000010422580000000054 -:1002B0000104225C00000000010422600000000034 -:1002C0000104226400000000010422680000000014 -:1002D0000104226C000000000104227000000000F4 -:1002E00001042274000000000104227800000000D4 -:1002F0000104227C000000000C042000000003E840 -:100300000A042000000000010B0420000000000A85 -:1003100002050044000000200205004800000032F1 -:10032000020500900215002002050094021500202D -:1003300002050098000000300205009C0810000033 -:10034000020500A000000033020500A400000030F8 -:10035000020500A800000031020500AC0000000208 -:10036000020500B000000005020500B40000000610 -:10037000020500B800000002020500BC00000002F7 -:10038000020500C000000000020500C400000005D6 -:10039000020500C800000002020500CC00000002B7 -:1003A000020500D000000002020500D40000000198 -:1003B00002050114000000010205011C00000001FB -:1003C00002050120000000020205020400000001F5 -:1003D0000205020C0000004002050210000000406F -:1003E0000205021C0000002002050220000000138C -:1003F0000205022400000020060502400000000A59 -:1004000004050280002000000205005000000007E3 -:100410000205005400000007020500580000000813 -:100420000205005C000000080205006000000001F9 -:100430000605006400000003020500D80000000665 -:100440000205000400000001020500080000000190 -:100450000205000C00000001020500100000000170 -:100460000205001400000001020500180000000150 -:100470000205001C00000001020500200000000130 -:100480000205002400000001020500280000000110 -:100490000205002C000000010205003000000001F0 -:1004A00002050034000000010205003800000001D0 -:1004B0000205003C000000010205004000000001B0 -:1004C000020500E00000000D020500E80000000742 -:1004D000020500F000000007020500F80000000718 -:1004E000020500E40000002D020500EC00000027DA -:1004F000020500F400000027020500FC00000027B0 -:10050000020500E00000001D020500E800000017E1 -:10051000020500F000000017020500F800000017B7 -:10052000020500E40000003D020500EC0000003779 -:10053000020500F400000037020500FC000000374F -:10054000020500E00000004D020500E80000004741 -:10055000020500F000000047020500F80000004717 -:10056000020500E40000006D020500EC00000067D9 -:10057000020500F400000067020500FC00000067AF -:10058000020500E00000005D020500E800000057E1 -:10059000020500F000000057020500F800000057B7 -:1005A000020500E40000007D020500EC0000007779 -:1005B000020500F400000077020500FC000000774F -:1005C0000406100002000020020600DC000000010A -:1005D000010600D80000000004060200000302200B -:1005E000020600DC00000000010600B80000000068 -:1005F000010600C800000000010600BC0000000069 -:10060000010600CC0000000007180400009B000059 -:1006100008180798000D0223071C0000325E000036 -:10062000071C800035960C98071D00001AEA19FE79 -:10063000081D43D057860225011800000000000065 -:10064000011800040000000001180008000000006C -:100650000118000C0000000001180010000000004C -:100660000118001400000000021800200000000122 -:1006700002180024000000020218002800000003F5 -:100680000218002C000000000218003000000004D6 -:1006900002180034000000010218003800000000B9 -:1006A0000218003C00000001021800400000000495 -:1006B0000218004400000000021800480000000179 -:1006C0000218004C00000003021800500000000057 -:1006D0000218005400000001021800580000000435 -:1006E0000218005C00000000021800600000000119 -:1006F00002180064000000030218006800000000F7 -:100700000218006C000000010218007000000004D4 -:1007100002180074000000000218007800000004B5 -:100720000218007C00000003061800800000000290 -:10073000021800A400003FFF021800A8000003FFF9 -:100740000218022400000000021802340000000019 -:100750000218024C00000000021802E4000000FF32 -:100760000618100000000400021B8BC000000001EE -:10077000021B800000000034021B804000000018B3 -:10078000021B80800000000C021B80C000000020C3 -:100790000C1B83000007A1200A1B83000000013806 -:1007A0000B1B830000001388021B83C0000001F4B0 -:1007B000021B1480000000010A1B148000000000CE -:1007C000061A1000000002B3041A1ACC0001022716 -:1007D000061AA020000000C8061AA00000000002AF -:1007E000021A1AD000000000061A1AD800000004ED -:1007F000061A367800000006061A3670000000025D -:10080000061A500000000002061A500800000004FA -:10081000061A501800000004061A502800000004B0 -:10082000061A503800000004061A50480000000460 -:10083000061A505800000004061A50680000000410 -:10084000061A507800000002061A4000000000025C -:10085000061A400800000002041A62C000200228A4 -:10086000061A20000000016C061AB00000000028E3 -:10087000061AB1400000000C061A32C00000001237 -:10088000061A335000000064061A810800000002B6 -:10089000061A25B00000016C061AB0A0000000285E -:1008A000061AB1700000000C061A3308000000128E -:1008B000061A34E000000064061A811000000002ED -:1008C000021A2B6000000000061A3000000000022F -:1008D000041A300800050248061A301C0000000700 -:1008E000061A31C000000008061A5000000000027D -:1008F000061A508000000012061A40000000000294 -:10090000021A2B6400000000061A303800000002B2 -:10091000041A30400005024D061A3054000000074A -:10092000061A31E000000008061A5010000000020C -:10093000061A50C800000012061A40080000000203 -:10094000021A2B6800000000061A30700000000236 -:10095000041A307800050252061A308C0000000795 -:10096000061A320000000008061A5020000000029B -:10097000061A511000000012041A4010000202571B -:10098000021A2B6C00000000061A30A800000002BA -:10099000041A30B000050259061A30C400000007DE -:1009A000061A322000000008061A5030000000022B -:1009B000061A515800000012041A40180002025E84 -:1009C000021A2B7000000000061A30E0000000023E -:1009D000041A30E800050260061A30FC0000000727 -:1009E000061A324000000008061A504000000002BB -:1009F000061A51A000000012041A402000020265ED -:100A0000021A2B7400000000061A311800000002C0 -:100A1000041A312000050267061A3134000000076D -:100A2000061A326000000008061A5050000000024A -:100A3000061A51E800000012041A40280002026C55 -:100A4000021A2B7800000000061A31500000000244 -:100A5000041A31580005026E061A316C00000007B6 -:100A6000061A328000000008061A506000000002DA -:100A7000061A523000000012041A403000020273BD -:100A8000021A2B7C00000000061A318800000002C8 -:100A9000041A319000050275061A31A400000007FF -:100AA000061A32A000000008061A5070000000026A -:100AB000061A527800000012041A40380002027A26 -:100AC0000200A294071D29110200A2980000000054 -:100AD0000200A29C009C04240200A2A000000000CE -:100AE0000200A2A4000002090200A270000000009F -:100AF0000200A274000000000200A27000000000CA -:100B00000200A274000000000200A27000000000B9 -:100B10000200A274000000000200A27000000000A9 -:100B20000200A27400000000020100B400000001F5 -:100B3000020100B800000001020100DC0000000119 -:100B40000201010000000001020101040000000197 -:100B50000201007C00300000020100840000002837 -:100B60000201008C000000000201013000000004BE -:100B70000201025C000000010201032800000000E5 -:100B800002016080000000010201055400000030F5 -:100B9000020100C400000001020100CC00000001BD -:100BA000020100F800000001020100F00000000155 -:100BB00002010080003000000201008800000028CF -:100BC0000201009000000000020101340000000456 -:100BD000020102DC000000010201032C0000000001 -:100BE0000201608400000001020105640000003081 -:100BF000020100C800000001020100D00000000155 -:100C0000020100FC00000001020100F400000001EC -:100C1000020C100000000020020C2008000002114D -:100C2000020C200C00000200020C20100000020444 -:100C3000020C201C0000FFFF020C20200000FFFF20 -:100C4000020C20240000FFFF020C20280000FFFF00 -:100C5000020C2038000000C6020C203C00000000FE -:100C6000020C204000000034020C2044000000353B -:100C7000060C20480000001C020C20B800000001F7 -:100C8000060C20BC0000005F020C223807FFFFFFAB -:100C9000020C223C0000003F020C224007FFFFFF35 -:100CA000020C22440000000F010C2248000000004A -:100CB000010C224C00000000010C2250000000003A -:100CC000010C225400000000010C2258000000001A -:100CD000010C225C00000000010C226000000000FA -:100CE000010C226400000000010C226800000000DA -:100CF000010C226C00000000010C227000000000BA -:100D0000010C227400000000010C22780000000099 -:100D1000010C227C000000000C0C2000000003E805 -:100D20000A0C2000000000010B0C20000000000A4B -:100D3000020C400800000411020C400C00000400EA -:100D4000020C401000000404020C401400000421B6 -:100D5000020C401C0000FFFF020C40200000FFFFBF -:100D6000020C40240000FFFF020C40280000FFFF9F -:100D7000020C403800000046020C403C0000000518 -:100D8000020C404000000034020C404400000035DA -:100D9000020C404800000007060C404C0000005BBD -:100DA000020C41B800000001060C41BC0000000329 -:100DB000020C41C800000001060C41CC0000001BE1 -:100DC000020C423807FFFFFF020C423C0000003FCC -:100DD000020C424007FFFFFF020C42440000000FDC -:100DE000010C424800000000010C424C00000000D1 -:100DF000010C425000000000010C425400000000B1 -:100E0000010C425800000000010C425C0000000090 -:100E1000010C426000000000010C42640000000070 -:100E2000010C426800000000010C426C0000000050 -:100E3000010C427000000000010C42740000000030 -:100E4000010C427800000000010C427C0000000010 -:100E5000010C4280000000000C0C4000000003E880 -:100E60000A0C4000000000010B0C40000000000ACA -:100E7000020D004400000032020D008C021500201B -:100E8000020D009002150020020D009408100000D1 -:100E9000020D009800000033020D009C00000002CB -:100EA000020D00A000000000020D00A400000005DB -:100EB000020D00A800000005060D00AC00000002B5 -:100EC000020D00B400000002020D00B80000000393 -:100ED000020D00BC00000002020D00C00000000175 -:100EE000020D00C800000002020D00CC000000024C -:100EF000020D010800000001020D015C000000016C -:100F0000020D016400000001020D016800000002F2 -:100F1000020D020400000001020D020C000000207E -:100F2000020D021000000040020D021400000040FB -:100F3000020D022000000003020D02240000001830 -:100F4000060D028000000012040D03000024027C44 -:100F5000020D004C00000001020D005000000002D4 -:100F6000020D005400000008020D005800000008A7 -:100F7000060D005C00000004020D00C40000000427 -:100F8000020D000400000001020D00080000000135 -:100F9000020D000C00000001020D00100000000115 -:100FA000020D001400000001020D001800000001F5 -:100FB000020D001C00000001020D002000000001D5 -:100FC000020D002400000001020D002800000001B5 -:100FD000020D002C00000001020D00300000000195 -:100FE000020D003400000001020D00380000000175 -:100FF000020D003C00000001020D01140000000978 -:10100000020D011C0000000A020D0124000000076F -:10101000020D012C00000007020D01340000000C3D -:10102000020D013C0000000B020D0144000000070E -:10103000020D011800000029020D01200000002A05 -:10104000020D012800000027020D013000000027DA -:10105000020D01380000002C020D01400000002BA1 -:10106000020D014800000027020D011400000019C4 -:10107000020D011C0000001A020D012400000017DF -:10108000020D012C00000017020D01340000001CAD -:10109000020D013C0000001B020D0144000000177E -:1010A000020D011800000039020D01200000003A75 -:1010B000020D012800000037020D0130000000374A -:1010C000020D01380000003C020D01400000003B11 -:1010D000020D014800000037020D01140000004914 -:1010E000020D011C0000004A020D0124000000470F -:1010F000020D012C00000047020D01340000004CDD -:10110000020D013C0000004B020D014400000047AD -:10111000020D011800000069020D01200000006AA4 -:10112000020D012800000067020D01300000006779 -:10113000020D01380000006C020D01400000006B40 -:10114000020D014800000067020D01140000005963 -:10115000020D011C0000005A020D0124000000577E -:10116000020D012C00000057020D01340000005C4C -:10117000020D013C0000005B020D0144000000571D -:10118000020D011800000079020D01200000007A14 -:10119000020D012800000077020D013000000077E9 -:1011A000020D01380000007C020D01400000007BB0 -:1011B000020D014800000077020E004C00000032D2 -:1011C000020E009402150020020E00980215002065 -:1011D000020E009C00000030020E00A0081000006B -:1011E000020E00A400000033020E00A80000003030 -:1011F000020E00AC00000031020E00B00000000240 -:10120000020E00B400000004020E00B8000000004E -:10121000020E00BC00000002020E00C0000000022E -:10122000020E00C400000000020E00C80000000210 -:10123000020E00CC00000007020E00D000000002E9 -:10124000020E00D400000002020E00D800000001CF -:10125000020E00E400000001020E01440000000143 -:10126000020E014C00000001020E015000000002BD -:10127000020E020400000001020E020C00000040F9 -:10128000020E021000000040020E021C00000004CA -:10129000020E022000000020020E02240000000EB8 -:1012A000020E02280000001B060E030000000012C0 -:1012B000040E0280001B02A0020E00540000001069 -:1012C000020E005800000007020E005C0000000F34 -:1012D000020E006000000010020E00640000000B0F -:1012E000060E006800000003020E00DC0000000390 -:1012F000020E000400000001020E000800000001C0 -:10130000020E000C00000001020E0010000000019F -:10131000020E001400000001020E0018000000017F -:10132000020E001C00000001020E0020000000015F -:10133000020E002400000001020E0028000000013F -:10134000020E002C00000001020E0030000000011F -:10135000020E003400000001020E003800000001FF -:10136000020E003C00000001020E004000000001DF -:10137000020E004400000001020E01100000000FE8 -:10138000020E01180000000E020E012000000000F5 -:10139000020E012800000000020E01140000002FC0 -:1013A000020E011C0000002E020E012400000000AD -:1013B000020E012C00000000020E01100000001FB0 -:1013C000020E01180000001E020E012000000000A5 -:1013D000020E012800000000020E01140000003F70 -:1013E000020E011C0000003E020E0124000000005D -:1013F000020E012C00000000020E01100000004F40 -:10140000020E01180000004E020E01200000000034 -:10141000020E012800000000020E01140000006FFF -:10142000020E011C0000006E020E012400000000EC -:10143000020E012C00000000020E01100000005FEF -:10144000020E01180000005E020E012000000000E4 -:10145000020E012800000000020E01140000007FAF -:10146000020E011C0000007E020E0124000000009C -:10147000020E012C000000000730040000D2000022 -:10148000083007A8000B02BB0734000031B600008B -:101490000734800036500C6E0735000037591A03A8 -:1014A00007358000286127DA0835FF40401802BD63 -:1014B00001300000000000000130000400000000C6 -:1014C00001300008000000000130000C00000000A6 -:1014D0000130001000000000013000140000000086 -:1014E0000230002000000001023000240000000251 -:1014F00002300028000000030230002C0000000031 -:10150000023000300000000402300034000000010E -:1015100002300038000000000230003C00000001F2 -:1015200002300040000000040230004400000000CF -:1015300002300048000000010230004C00000003AF -:101540000230005000000000023000540000000192 -:1015500002300058000000040230005C000000006F -:10156000023000600000000102300064000000034F -:1015700002300068000000000230006C0000000132 -:10158000023000700000000402300074000000000F -:1015900002300078000000040230007C00000003EC -:1015A0000630008000000002023000A400003FFF6F -:1015B000023000A8000003FF0230022400000000F7 -:1015C00002300234000000000230024C0000000033 -:1015D000023002E40000FFFF063020000000080097 -:1015E00002338BC000000001023380000000001AAB -:1015F000023380400000004E023380800000001063 -:10160000023380C0000000200C3383000007A120BB -:101610000A338300000001380B3383000000138875 -:10162000023383C0000001F40C3383801DCD6500BC -:101630000A3383800004C4B40B338380004C4B40D6 -:101640000A331480000000000233148000000001FF -:10165000063220000000010206328980000000C826 -:1016600006328960000000020632322800000004C1 -:10167000063232000000000904323224000102BFA9 -:1016800006323180000000200632500000000400C5 -:10169000063240000000000204324008000102C08F -:1016A0000632400C0000000306326B6800000002A6 -:1016B00004326B70000202C106326B10000000029F -:1016C000043274C0000202C30233080001000000AB -:1016D00004330C00001002C50233080000000000B3 -:1016E00004330C40001002D506329000000000A028 -:1016F0000632950000000040063297000000003CD2 -:1017000006322450000000B406322AD00000000245 -:101710000632308000000020063280000000012CDC -:101720000232323800000000063250000000002073 -:101730000632510000000020063252000000002056 -:101740000632530000000020063254000000002042 -:10175000063255000000002006325600000000202E -:10176000063257000000002006325800000000201A -:10177000063259000000002006325A000000002006 -:1017800006325B000000002006325C0000000020F2 -:1017900006325D000000002006325E0000000020DE -:1017A00006325F000000002006326B780000005215 -:1017B00006326E080000000C06329280000000A085 -:1017C0000632960000000040063297F00000003C10 -:1017D00006322720000000B406322AD8000000029A -:1017E0000632310000000020063284B00000012CD7 -:1017F0000232323C0000000006325080000000201F -:101800000632518000000020063252800000002085 -:101810000632538000000020063254800000002071 -:10182000063255800000002006325680000000205D -:101830000632578000000020063258800000002049 -:10184000063259800000002006325A800000002035 -:1018500006325B800000002006325C800000002021 -:1018600006325D800000002006325E80000000200D -:1018700006325F800000002006326CC0000000527B -:1018800006326E380000000C02322A3000000000E0 -:10189000063230000000000406324018000000024A -:1018A00002322A340000000006323010000000042A -:1018B000063240280000000202322A3800000000F0 -:1018C00006323020000000040632403800000002DA -:1018D00002322A3C000000000632303000000004D2 -:1018E000063240480000000202322A400000000098 -:1018F000063230400000000406324058000000026A -:1019000002322A4400000000063230500000000479 -:10191000063240680000000202322A48000000003F -:1019200006323060000000040632407800000002F9 -:1019300002322A4C00000000063230700000000421 -:1019400006324088000000020720040000740000F6 -:1019500008200780001002E507240000322600005E -:1019600007248000246E0C8A0824CBB064F002E7C0 -:101970000120000000000000012000040000000021 -:1019800001200008000000000120000C0000000001 -:1019900001200010000000000120001400000000E1 -:1019A00002200020000000010220002400000002AC -:1019B00002200028000000030220002C000000008C -:1019C000022000300000000402200034000000016A -:1019D00002200038000000000220003C000000014E -:1019E000022000400000000402200044000000002B -:1019F00002200048000000010220004C000000030B -:101A000002200050000000000220005400000001ED -:101A100002200058000000040220005C00000000CA -:101A200002200060000000010220006400000003AA -:101A300002200068000000000220006C000000018D -:101A4000022000700000000402200074000000006A -:101A500002200078000000040220007C0000000347 -:101A60000620008000000002022000A400003FFFCA -:101A7000022000A8000003FF022002240000000052 -:101A800002200234000000000220024C000000008E -:101A9000022002E40000FFFF0620200000000800F2 -:101AA00002238BC000000001022380000000001010 -:101AB00002238040000000120223808000000030DA -:101AC000022380C00000000E022383C0000001F446 -:101AD00002231480000000010A231480000000008B -:101AE000062210000000004206227020000000C8FC -:101AF0000622700000000002022211E8000000002F -:101B000006223000000000C0062240700000008065 -:101B10000622528000000004062267000000010037 -:101B2000062290000000040004226B08002002E955 -:101B300002230800013FFFFF04230C0000100309EB -:101B4000022308000000000004230C4000100319C9 -:101B500006228000000000A0062285000000004050 -:101B6000062287000000003C0622404000000006DC -:101B700006228280000000A00622860000000040AD -:101B8000062287F00000003C0622405800000006B4 -:101B9000022211480000000006223300000000026B -:101BA00006226040000000300222114C00000000BC -:101BB0000622330800000002062261000000003007 -:101BC0000222115000000000062233100000000223 -:101BD000062261C000000030022211540000000003 -:101BE0000622331800000002062262800000003046 -:101BF00002221158000000000622332000000002DB -:101C000006226340000000300222115C0000000048 -:101C10000622332800000002062264000000003083 -:101C20000222116000000000062233300000000292 -:101C3000062264C00000003002221164000000008F -:101C400006223338000000020622658000000030C2 -:101C50000216100000000020021700080000000219 -:101C60000217002C000000030217003C00000004D3 -:101C7000021700440000000802170048000000029C -:101C80000217004C00000090021700500000009066 -:101C9000021700540080009002170058081400003A -:101CA000021700600000008A021700640000008034 -:101CB00002170068000000900217006C000000800E -:101CC000021700700000000602170078000007D01D -:101CD0000217007C0000076C02170038007C10041B -:101CE000021700040000000F061640240000000246 -:101CF000021640700000001C02164208000000019D -:101D000002164210000000010216422000000001ED -:101D100002164228000000010216423000000001B5 -:101D20000216423800000001021642600000000264 -:101D30000C16401C0003D0900A16401C0000009CAA -:101D40000B16401C000009C40216403000000008B9 -:101D5000021640340000000C02164038000000104B -:101D6000021640440000002002164000000000015E -:101D7000021640D8000000010216400800000001D1 -:101D80000216400C00000001021640100000000185 -:101D90000216424000000000021642480000000007 -:101DA00006164270000000020216425000000000B9 -:101DB0000216425800000000061642800000000291 -:101DC00002166008000004240216600C00000410D3 -:101DD00002166010000004140216601C0000FFFFD1 -:101DE000021660200000FFFF021660240000FFFFC3 -:101DF000021660280000FFFF021660380000002075 -:101E00000216603C00000020021660400000003412 -:101E100002166044000000350216604800000023EE -:101E20000216604C000000240216605000000025DD -:101E300002166054000000260216605800000027B9 -:101E40000216605C00000029021660600000002A93 -:101E5000021660640000002B021660680000002C6F -:101E60000216606C0000002D061660700000005223 -:101E7000021661B800000001061661BC0000001FD8 -:101E80000216623807FFFFFF0216623C0000003FA7 -:101E90000216624007FFFFFF021662440000000FB7 -:101EA00001166248000000000116624C00000000AC -:101EB000011662500000000001166254000000008C -:101EC00001166258000000000116625C000000006C -:101ED000011662600000000001166264000000004C -:101EE00001166268000000000116626C000000002C -:101EF000011662700000000001166274000000000C -:101F000001166278000000000116627C00000000EB -:101F10000C166000000003E80A16600000000001D3 -:101F20000B1660000000000A021680400000000648 -:101F30000216804400000005021680480000000AD6 -:101F40000216804C000000050216805400000002BA -:101F5000021680CC00000004021680D000000004AD -:101F6000021680D400000004021680D8000000048D -:101F7000021680DC00000004021680E0000000046D -:101F8000021680E400000004021680E8000000044D -:101F90000216880400000004021680300000007C55 -:101FA000021680340000003D021680380000003F19 -:101FB0000216803C0000009C021680F00000000722 -:101FC000061680F4000000050216880C01010101CC -:101FD00002168108000000000216810C00000004B7 -:101FE0000216811000000004021681140000000295 -:101FF000021688100801200402168118000000054E -:102000000216811C00000005021681200000000558 -:1020100002168124000000050216882C20081001F9 -:1020200002168128000000080216812C000000061C -:102030000216813000000007021681340000000003 -:1020400002168830010101200616813800000004C4 -:1020500002168834010101010216814800000000C7 -:102060000216814C0000000402168150000000049A -:10207000021681540000000202168838080120046C -:1020800002168158000000050216815C0000000560 -:102090000216816000000005021681640000000540 -:1020A0000216883C20081001021681680000000812 -:1020B0000216816C00000006021681700000000705 -:1020C00002168174000000010216884001010120FF -:1020D00002168178000000010216817C00000001D8 -:1020E00002168180000000010216818400000001B8 -:1020F00002168844010101010216818800000001D6 -:102100000216818C00000004021681900000000479 -:10211000021681940000000202168848080120047B -:1021200002168198000000050216819C000000053F -:10213000021681A000000005021681A4000000051F -:102140000216881420081001021681A80000000859 -:10215000021681AC00000006021681B000000007E4 -:10216000021681B400000001021688180101012046 -:10217000021681B800000001021681BC00000001B7 -:10218000021681C000000001021681C40000000197 -:102190000216881C01010101021681C8000000011D -:1021A000021681CC00000004021681D00000000459 -:1021B000021681D4000000020216882008012004C3 -:1021C000021681D800000005021681DC000000051F -:1021D000021681E000000005021681E400000005FF -:1021E0000216882420081001021681E80000000869 -:1021F000021681EC00000006021681F000000007C4 -:102200000216E40C000000000216882801010120DB -:102210000616E410000000040216E00001010101AE -:102220000216E420000000000216E424000000046E -:102230000216E428000000040216E42C000000024C -:102240000216E004080120040216E4300000000534 -:102250000216E434000000050216E4380000000510 -:102260000216E43C000000050216E00820081001F8 -:102270000216E440000000080216E44400000006D4 -:102280000216E448000000070216E44C00000000BB -:102290000216E00C010101200616E45000000004C3 -:1022A0000216E010010101010216E46000000000C6 -:1022B0000216E464000000040216E4680000000452 -:1022C0000216E46C000000020216E014080120046B -:1022D0000216E470000000050216E4740000000518 -:1022E0000216E478000000050216E47C00000005F8 -:1022F0000216E018200810010216E4800000000811 -:102300000216E484000000060216E48800000007BC -:102310000216E48C000000010216E01C01010120FD -:102320000216E490000000010216E494000000018F -:102330000216E498000000010216E49C000000016F -:102340000216E020010101010216E4A000000001D4 -:102350000216E4A4000000040216E4A80000000431 -:102360000216E4AC000000020216E024080120047A -:102370000216E4B0000000050216E4B400000005F7 -:102380000216E4B8000000050216E4BC00000005D7 -:102390000216E028200810010216E4C00000000820 -:1023A0000216E4C4000000060216E4C8000000079C -:1023B0000216E4CC000000010216E02C010101200D -:1023C0000216E4D0000000010216E4D4000000016F -:1023D0000216E4D8000000010216E4DC000000014F -:1023E0000216E030010101010216E4E000000001E4 -:1023F0000216E4E4000000040216E4E80000000411 -:102400000216E4EC000000020216E0340801200489 -:102410000216E4F0000000050216E4F400000005D6 -:102420000216E4F8000000050216E4FC00000005B6 -:102430000216E038200810010216E500000000082E -:102440000216E504000000060216E5080000000779 -:102450000216E03C0101012002168240003F003FCD -:1024600002168244000000000216E524003F003FEF -:102470000216E52800000000021682480000000055 -:102480000216824C003F003F0216E52C00000000BF -:102490000216E530003F003F0216825001000100A5 -:1024A00002168254010001000216E5340100010009 -:1024B0000216E538010001000616825800000002ED -:1024C0000216E53C000000000216E5400000000096 -:1024D0000216826000C000C00216826400C000C004 -:1024E0000216E54400C000C00216E54800C000C066 -:1024F000021682681E001E000216826C1E001E005C -:102500000216E54C1E001E000216E5501E001E00BD -:1025100002168270400040000216827440004000A3 -:102520000216E554400040000216E5584000400005 -:1025300002168278800080000216827C8000800073 -:102540000216E55C800080000216E56080008000D5 -:1025500002168280200020000216828420002000C3 -:102560000216E564200020000216E5682000200025 -:1025700006168288000000020216E56C00000000CA -:102580000216E570000000000216829000000000B4 -:1025900002168294000000000216E574000000009C -:1025A0000216E57800000000021682980000000084 -:1025B0000216829C000000000216E57C000000006C -:1025C0000216E58000000000021682A00000000054 -:1025D000021682A400000001061682A80000000A6C -:1025E000021681F400000C08021681F80000004079 -:1025F000021681FC0000010002168200000000208B -:1026000002168204000000170216820800000080F3 -:102610000216820C00000200021682100000000068 -:102620000216821801FF01FF0216821401FF01FF4A -:102630000216E51001FF01FF0216E50C01FF01FF84 -:102640000216823C00000013021680900000013F39 -:102650000216806000000140021680640000014004 -:10266000061680680000000202168070000000C09C -:1026700006168074000000070216809C00000048C7 -:10268000021680A000000048061680A40000000288 -:10269000021680AC00000048061680B0000000075B -:1026A000021682380000800002168234000025E401 -:1026B0000216809400007FFF0216822000070007A8 -:1026C0000216821C000700070216E5180007000723 -:1026D0000216E51400070007021682280000000019 -:1026E00002168224FFFFFFFF0216E5200000000013 -:1026F0000216E51CFFFFFFFF0216E6BC000000000B -:102700000216E6C0000000020216E6C40000000146 -:102710000216E6C8000000030216E6CC0000000422 -:102720000216E6D0000000060216E6D400000005FE -:102730000216E6D800000007021680EC000000FF39 -:1027400002140000000000010214000C000000014F -:1027500002140040000000010214004400007FFF4A -:102760000214000C00000000021400000000000031 -:102770000214006C000000000214000400000001BC -:1027800002140030000000010214000400000000E8 -:102790000214005C000000000214000800000001A8 -:1027A00002140034000000010214000800000000C0 -:1027B0000214006000000000020200580000003215 -:1027C000020200A003150020020200A4031500204D -:1027D000020200A801000030020200AC0810000054 -:1027E000020200B000000033020200B4000000301A -:1027F000020200B800000031020200BC0000000329 -:10280000020200C000000006020200C40000000333 -:10281000020200C800000003020200CC0000000217 -:10282000020200D000000000020200D400000002FA -:10283000020200DC00000000020200E000000006CE -:10284000020200E400000004020200E800000002AE -:10285000020200EC00000002020200F00000000191 -:10286000020200FC0000000602020120000000003D -:102870000202013400000002020201B00000000167 -:102880000202020C0000000102020214000000011A -:10289000020202180000000202020404000000010B -:1028A0000202040C0000004002020410000000407C -:1028B0000202041C000000040202042000000020A8 -:1028C000020204240000000202020428000000208A -:1028D000060205000000001204020480001F032904 -:1028E000020200600000000F020200640000000706 -:1028F000020200680000000B0202006C0000000EE3 -:10290000020200700000000E0602007400000003C6 -:10291000020200F4000000040202000400000001B2 -:1029200002020008000000010202000C0000000189 -:102930000202001000000001020200140000000169 -:1029400002020018000000010202001C0000000149 -:102950000202002000000001020200240000000129 -:1029600002020028000000010202002C0000000109 -:1029700002020030000000010202003400000001E9 -:1029800002020038000000010202003C00000001C9 -:1029900002020040000000010202004400000001A9 -:1029A00002020048000000010202004C0000000189 -:1029B000020200500000000102020108000000C8ED -:1029C0000202011800000002020201C4000000001F -:1029D000020201CC00000000020201D4000000024B -:1029E000020201DC00000002020201E4000000FF1C -:1029F000020201EC000000FF0202010000000000E2 -:102A00000202010C000000C80202011C00000002CA -:102A1000020201C800000000020201D00000000014 -:102A2000020201D800000002020201E000000002E0 -:102A3000020201E8000000FF020201F0000000FFB6 -:102A4000020201040000000002020108000000C8A8 -:102A50000202011800000002020201C4000000008E -:102A6000020201CC00000000020201D400000002BA -:102A7000020201DC00000002020201E4000000FF8B -:102A8000020201EC000000FF020201000000000051 -:102A90000202010C000000C80202011C000000023A -:102AA000020201C800000000020201D00000000084 -:102AB000020201D800000002020201E00000000250 -:102AC000020201E8000000FF020201F0000000FF26 -:102AD000020201040000000002020108000000C818 -:102AE0000202011800000002020201C400000000FE -:102AF000020201CC00000000020201D4000000022A -:102B0000020201DC00000002020201E4000000FFFA -:102B1000020201EC000000FF0202010000000000C0 -:102B20000202010C000000C80202011C00000002A9 -:102B3000020201C800000000020201D000000000F3 -:102B4000020201D800000002020201E000000002BF -:102B5000020201E8000000FF020201F0000000FF95 -:102B6000020201040000000002020108000000C887 -:102B70000202011800000002020201C4000000006D -:102B8000020201CC00000000020201D40000000299 -:102B9000020201DC00000002020201E4000000FF6A -:102BA000020201EC000000FF020201000000000030 -:102BB0000202010C000000C80202011C0000000219 -:102BC000020201C800000000020201D00000000063 -:102BD000020201D800000002020201E0000000022F -:102BE000020201E8000000FF020201F0000000FF05 -:102BF00002020104000000000728040000BD0000DC -:102C0000082807A8000B0348072C00003406000022 -:102C1000072C800037960D02072D00003BC31AE8F1 -:102C2000072D8000382629D9072E0000124537E3EA -:102C3000082E22203BBC034A0128000000000000AF -:102C40000128000400000000012800080000000026 -:102C50000128000C00000000012800100000000006 -:102C600001280014000000000228002000000001DC -:102C700002280024000000020228002800000003AF -:102C80000228002C00000000022800300000000490 -:102C90000228003400000001022800380000000073 -:102CA0000228003C0000000102280040000000044F -:102CB0000228004400000000022800480000000133 -:102CC0000228004C00000003022800500000000011 -:102CD00002280054000000010228005800000004EF -:102CE0000228005C000000000228006000000001D3 -:102CF00002280064000000030228006800000000B1 -:102D00000228006C0000000102280070000000048E -:102D1000022800740000000002280078000000046F -:102D20000228007C0000000306280080000000024A -:102D3000022800A400003FFF022800A8000003FFB3 -:102D400002280224000000000228023400000000D3 -:102D50000228024C00000000022802E40000FFFFED -:102D60000628200000000800022B8BC00000000194 -:102D7000022B800000000000022B804000000018A1 -:102D8000022B80800000000C022B80C00000006637 -:102D90000C2B83000007A1200A2B830000000138C0 -:102DA0000B2B830000001388022B83C0000001F46A -:102DB0000C2B8340000001F40A2B8340000000002C -:102DC0000B2B8340000000050A2B83800004C4B451 -:102DD0000C2B83801DCD65000A2B148000000000A1 -:102DE0000B2B8380004C4B40022B14800000000111 -:102DF000062A29C800000004042A29D80002034C2E -:102E0000062A208000000048062A9020000000C802 -:102E1000062A900000000002062A21A80000008671 -:102E2000062A200000000020022A23C8000000001B -:102E3000042A23D00002034E042A249800040350DD -:102E4000022A2C2000000000022A2C1000000000A2 -:102E5000042A2C0800020354022A3010000000014A -:102E6000062A404000000010042A400000100356CB -:102E7000062A6AC000000002062A6B000000000457 -:102E8000042A840800020366022B080000000000E8 -:102E9000042B0C0000100368022B08000100000046 -:102EA000042B0C4000080378022B080002000000ED -:102EB000042B0C6000080380062AC000000000FC00 -:102EC000062A24A800000014062A25480000002431 -:102ED000062A266800000024062A2788000000240D -:102EE000062A28A800000024062AA00000000028C6 -:102EF000062AA1400000000C042A29E000020388F1 -:102F0000022A300000000001062A502000000002C2 -:102F1000062A503000000002062A5000000000027D -:102F2000062A501000000002022A52080000000188 -:102F3000042A6AC80002038A062A6B1000000042B5 -:102F4000062A6D2000000004062AC3F0000000FCE1 -:102F5000062A24F800000014062A25D800000024C0 -:102F6000062A26F800000024062A2818000000245B -:102F7000062A293800000024062AA0A00000002804 -:102F8000062AA1700000000C042A29E80002038C24 -:102F9000022A300400000001062A50280000000226 -:102FA000062A503800000002062A500800000002DD -:102FB000062A501800000002022A520C00000001EC -:102FC000042A6AD00002038E062A6C180000004210 -:102FD000062A6D3000000004022AC7E0000000004D -:102FE000042A29F000100390062A50480000000E21 -:102FF000022AC7E400000000042A2A30001003A0BF -:10300000062A50800000000E022AC7E800000000D7 -:10301000042A2A70001003B0062A50B80000000EDF -:10302000022AC7EC00000000042A2AB0001003C0E6 -:10303000062A50F00000000E022AC7F0000000002F -:10304000042A2AF0001003D0062A51280000000E9E -:10305000022AC7F400000000042A2B30001003E00D -:10306000062A51600000000E022AC7F80000000086 -:10307000042A2B70001003F0062A51980000000E5D -:10308000022AC7FC00000000042A2BB00010040034 -:10309000062A51D00000000E0210100800000001A6 -:1030A0000210105000000001021010000003D000B8 -:1030B000021010040000003D091018000200041066 -:1030C0000910110000280610061011A000000018B9 -:1030D00006102400000000E00210201C0000000088 -:1030E0000210202000000001021020C00000000299 -:1030F000021020040000000102102008000000015E -:1031000009103C0000050638091038000005063D8E -:10311000091038200005064206104C00000001008E -:1031200002104028000000100210404400003FFF41 -:103130000210405800280000021040840084924A87 -:1031400002104058000000000210800000001080B3 -:10315000021080AC00000000021080380000001057 -:103160000210810000000000061081200000000213 -:1031700002108008000002B502108010000000005C -:10318000061082000000004A021081080001FFFFC3 -:1031900006108140000000020210800000001A802A -:1031A0000610900000000024061091200000004A44 -:1031B000061093700000004A061095C00000004AF7 -:1031C0000210800400001080021080B00000000196 -:1031D0000210803C0000001002108104000000007A -:1031E00006108128000000020210800C000002B5C9 -:1031F0000210801400000000061084000000004A45 -:103200000210810C0001FFFF06108148000000023F -:103210000210800400001A80061090900000002424 -:10322000061092480000004A061094980000004AD8 -:10323000061096E80000004A02108000000010808E -:10324000021080AC00000002021080380000001064 -:103250000210810000000000061081200000000222 -:1032600002108008000002B502108010000000006B -:10327000061082000000004A021081080001FFFFD2 -:1032800006108140000000020210800000001A8039 -:103290000610900000000024061091200000004A53 -:1032A000061093700000004A061095C00000004A06 -:1032B0000210800400001080021080B000000003A3 -:1032C0000210803C00000010021081040000000089 -:1032D00006108128000000020210800C000002B5D8 -:1032E0000210801400000000061084000000004A54 -:1032F0000210810C0001FFFF06108148000000024F -:103300000210800400001A80061090900000002433 -:10331000061092480000004A061094980000004AE7 -:10332000061096E80000004A02108000000010809D -:10333000021080AC00000004021080380000001071 -:103340000210810000000000061081200000000231 -:1033500002108008000002B502108010000000007A -:10336000061082000000004A021081080001FFFFE1 -:1033700006108140000000020210800000001A8048 -:103380000610900000000024061091200000004A62 -:10339000061093700000004A061095C00000004A15 -:1033A0000210800400001080021080B000000005B0 -:1033B0000210803C00000010021081040000000098 -:1033C00006108128000000020210800C000002B5E7 -:1033D0000210801400000000061084000000004A63 -:1033E0000210810C0001FFFF06108148000000025E -:1033F0000210800400001A80061090900000002443 -:10340000061092480000004A061094980000004AF6 -:10341000061096E80000004A0210800000001080AC -:10342000021080AC0000000602108038000000107E -:103430000210810000000000061081200000000240 -:1034400002108008000002B5021080100000000089 -:10345000061082000000004A021081080001FFFFF0 -:1034600006108140000000020210800000001A8057 -:103470000610900000000024061091200000004A71 -:10348000061093700000004A061095C00000004A24 -:103490000210800400001080021080B000000007BD -:1034A0000210803C000000100210810400000000A7 -:1034B00006108128000000020210800C000002B5F6 -:1034C0000210801400000000061084000000004A72 -:1034D0000210810C0001FFFF06108148000000026D -:1034E0000210800400001A80061090900000002452 -:1034F000061092480000004A061094980000004A06 -:10350000061096E80000004A021205B00000000113 -:103510000212049000E383400212051400003C10E4 -:103520000212066C0000000102120670000000008A -:1035300002120494FFFFFFFF02120498FFFFFFFF37 -:103540000212049CFFFFFFFF021204A0FFFFFFFF17 -:10355000021204A4FFFFFFFF021204A8FFFFFFFFF7 -:10356000021204ACFFFFFFFF021204B0FFFFFFFFD7 -:10357000021204BCFFFFFFFF021204C0FFFFFFFFA7 -:10358000021204C4FFFFFFFF021204C8FFFFFFFF87 -:10359000021204CCFFFFFFFF021204D0FFFFFFFF67 -:1035A000021204D8FFFFFFFF021204DCFFFFFFFF3F -:1035B000021204E0FFFFFFFF021204E4FFFFFFFF1F -:1035C000021204E8FFFFFFFF021204ECFFFFFFFFFF -:1035D000021204F0FFFFFFFF021204F4FFFFFFFFDF -:1035E000021204F8FFFFFFFF021204FCFFFFFFFFBF -:1035F00002120500FFFFFFFF02120504FFFFFFFF9D -:1036000002120508FFFFFFFF0212050CFFFFFFFF7C -:1036100002120510FFFFFFFF021204D4FF802000FA -:10362000021204B4F0005000021204B8F00080004E -:1036300002120390000000080212039C0000000820 -:10364000021203A000000008021203A400000002FE -:10365000021203BC00000004021203C000000005B7 -:10366000021203C400000004021203D00000000094 -:103670000212036C00000001021203680000003F08 -:10368000021201BC00000040021201C00000180834 -:10369000021201C400000803021201C8000008035E -:1036A000021201CC00000040021201D00000000311 -:1036B000021201D400000803021201D8000008031E -:1036C000021201DC00000803021201E00001000305 -:1036D000021201E400000803021201E800000803DE -:1036E000021201EC00000003021201F000000003CE -:1036F000021201F400000003021201F800000003AE -:10370000021201FC0000000302120200000000038C -:10371000021202040000000302120208000000036B -:103720000212020C0000000302120210000000034B -:10373000021202140000000302120218000000032B -:103740000212021C0000000302120220000000030B -:1037500002120224000000030212022800002403C7 -:103760000212022C0000002F021202300000000999 -:103770000212023400000019021202380000018413 -:103780000212023C00000183021202400000030604 -:103790000212024400000019021202480000000652 -:1037A0000212024C0000030602120250000003063F -:1037B00002120254000003060212025800000C8696 -:1037C0000212025C000003060212026000000306FF -:1037D00002120264000000060212026800000006E5 -:1037E0000212026C000000060212027000000006C5 -:1037F00002120274000000060212027800000006A5 -:103800000212027C00000006021202800000000684 -:103810000212028400000006021202880000000664 -:103820000212028C00000006021202900000000644 -:103830000212029400000006021202980000000624 -:103840000212029C00000006021202A00000030601 -:10385000021202A400000013021202A800000006D7 -:10386000021202B000001004021202B400001004A0 -:103870000212032400106440021203280010644066 -:10388000021205B400000001021201B000000001A4 -:103890000600A000000000160200A0EC5554000035 -:1038A0000200A0F0555555550200A0F400005555F2 -:1038B0000200A0F8F00000000200A0FC5554000037 -:1038C0000200A100555555550200A10400005555B0 -:1038D0000200A108F00000000200A18C5554000075 -:1038E0000200A190555555550200A1940000555570 -:1038F0000200A198F00000000200A19C000000005E -:103900000200A1A0000100000200A1A400005014C8 -:103910000200A1A8000000000200A45C00000C004E -:103920000200A61C000000030200A06CFF5C000067 -:103930000200A070FFF55FFF0200A0740000FFFF0F -:103940000200A078F00003E00200A07C000000006C -:103950000200A0800000A0000600A0840000000576 -:103960000200A0980FE000000600A09C00000007E5 -:103970000200A0B8000004000600A0BC0000000384 -:103980000200A0C8000010000600A0CC0000000348 -:103990000200A0D8000040000600A0DC00000003E8 -:1039A0000200A0E8000100000600A22C00000004B4 -:1039B0000200A10CFF5C00000200A110FFF55FFFF8 -:1039C0000200A1140000FFFF0200A118F00003E0B4 -:1039D0000200A11C000000000200A1200000A000C5 -:1039E0000600A124000000050200A1380FE000003D -:1039F0000600A13C000000070200A15800000800DA -:103A00000600A15C000000030200A1680000200085 -:103A10000600A16C000000030200A17800008000F5 -:103A20000600A17C000000030200A1880002000043 -:103A30000600A23C0000000400000000000000009E -:103A40000000003100000000000000000000000045 -:103A50000000000000000000000000000000000066 -:103A600000000000000000000000000000310032F3 -:103A70000000000000000000000000000000000046 -:103A80000000000000000000000000000000000036 -:103A9000000000000000000000320056000000009E -:103AA0000000000000000000000000000000000016 -:103AB0000000000000000000000000000000000006 -:103AC000000000000056008C000000000000000014 -:103AD000008C009000900094009400980098009C46 -:103AE000009C00A000A000A400A400A800A800ACB6 -:103AF00000AC00B100B100B300B300B5000000009D -:103B000000000000000000000000000000000000B5 -:103B100000000000000000000000000000B50100EF -:103B2000010001060106010C010C01140114011C25 -:103B3000011C01240124012C012C01340134013C1D -:103B4000013C01440144014C000000000000000061 -:103B50000000000000000000000000000000000065 -:103B60000000000000000000000000000000000055 -:103B70000000000000000000000000000000000045 -:103B80000000000000000000000000000000000035 -:103B90000000000000000000000000000000000025 -:103BA0000000000000000000000000000000000015 -:103BB0000000000000000000000000000000000005 -:103BC00000000000000000000000000000000000F5 -:103BD00000000000000000000000000000000000E5 -:103BE00000000000000000000000000000000000D5 -:103BF0000000000000000000014C01510000000026 -:103C000000000000015101520152015301530154BF -:103C100001540155015501560156015701570158EC -:103C200001580159000000000000000000000000E1 -:103C30000000000000000000000000000000000084 -:103C40000000000000000000000000000000000074 -:103C50000159015E015E016A016A017600000000FF -:103C60000000000000000000000000000000000054 -:103C70000000000000000000000000000000000044 -:103C80000000000000000000000000000000000034 -:103C90000000000000000000000000000000000024 -:103CA0000000000000000000017601770000000025 -:103CB0000000000000000000000000000000000004 -:103CC00000000000000000000000000000000000F4 -:103CD000000000000177019A0000000000000000D1 -:103CE00000000000000000000000000000000000D4 -:103CF00000000000000000000000000000000000C4 -:103D0000019A01C200000000000000000000000055 -:103D100000000000000000000000000000000000A3 -:103D200000000000000000000000000001C201F3DC -:103D3000000000000000000001F301FA01FA020196 -:103D4000020102080208020F020F02160216021DEB -:103D5000021D02240224022B022B02630000000039 -:103D600000000000026302670267026B026B026FD1 -:103D7000026F0273027302770277027B027B027F7B -:103D8000027F0283028302D102D102EB02EB030520 -:103D9000030503080308030B030B030E030E0311B3 -:103DA00003110314031403170317031A031A031D43 -:103DB000031D035E035E0362036203660366036919 -:103DC0000369036C036C036F036F03720372037563 -:103DD000037503780378037B037B037E037E037FF5 -:103DE00000000000000000000000000000000000D3 -:103DF00000000000000000000000000000000000C3 -:103E00000000000000000000037F0391000000009C -:103E100000000000000000000000000000000000A2 -:103E20000000000000000000000000000000000092 -:103E300000000000039103A603A603A903A903AC95 -:103E40000000000000000000000000000000000072 -:103E50000000000000000000000000000000000062 -:103E600003AC03D9000000000000000000000000C7 -:103E70000000000000000000000000000000000042 -:103E800000000000000000000000000003D904DC76 -:103E90000000000000000000000000000000000022 -:103EA0000000000000000000000000000000000012 -:103EB000000000000000000004DC04E304E304E769 -:103EC00004E704EB00000000000000000000000018 -:103ED00000000000000000000000000000000000E2 -:103EE0000000000004EB052B0000000000000000B3 -:103EF000052B05340534053D053D05460546054FB2 -:103F0000054F0558055805610561056A056A057381 -:103F1000057305CB05CB05DD05DD05EF05EF05F2E6 -:103F200005F205F505F505F805F805FB05FB05FEA9 -:103F300005FE060106010604060406070607060E2E -:103F40000000000000000000000000000000000071 -:103F50000000000000000000000000000000000061 -:103F60000000000000000000060E06140000000023 -:103F70000000000000000000000000000000000041 -:103F80000000000000000000000000000000000031 -:103F900000000000061406170000000000000000EA -:103FA0000000000000000000000000000000000011 -:103FB0000000000000000000000000000000000001 -:103FC0000617061D000000000000000000000000B1 -:103FD00000000000000000000000000000000000E1 -:103FE00000000000000000000000000000000000D1 -:103FF0000000000000000000061D062C062C063BF9 -:10400000063B064A064A06590659066806680677B8 -:1040100006770686068606950695070600000000C8 -:104020000000000000000000000000000000000090 -:104030000000000000000000000000000000000080 -:1040400000000000070607190719072A072A073B7F -:104050000000000000000000000000000000000060 -:104060000000000000000000000000000000000050 -:10407000000000000000000000010000000204C079 -:104080000003098000040E4000051300000617C05D -:1040900000071C800008214000092600000A2AC0F1 -:1040A000000B2F80000C3440000D3900000E3DC085 -:1040B000000F42800010474000114C00001250C019 -:1040C0000013558000145A4000155F00001663C0AD -:1040D0000017688000186D4000197200001A76C041 -:1040E000001B7B80001C8040001D8500001E89C0D5 -:1040F000001F8E8000209340000020000000400040 -:1041000000006000000080000000A0000000C0006F -:104110000000E0000001000000012000000140005C -:1041200000016000000180000001A0000001C0004B -:104130000001E00000020000000220000002400038 -:1041400000026000000280000002A0000002C00027 -:104150000002E00000030000000320000003400014 -:1041600000036000000380000003A0000003C00003 -:104170000003E000000400000004200000044000F0 -:1041800000046000000480000004A0000004C000DF -:104190000004E000000500000005200000054000CC -:1041A00000056000000580000005A0000005C000BB -:1041B0000005E000000600000006200000064000A8 -:1041C00000066000000680000006A0000006C00097 -:1041D0000006E00000070000000720000007400084 -:1041E00000076000000780000007A0000007C00073 -:1041F0000007E00000080000000820000008400060 -:1042000000086000000880000008A0000008C0004E -:104210000008E0000009000000092000000940003B -:1042200000096000000980000009A0000009C0002A -:104230000009E000000A0000000A2000000A400017 -:10424000000A6000000A8000000AA000000AC00006 -:10425000000AE000000B0000000B2000000B4000F3 -:10426000000B6000000B8000000BA000000BC000E2 -:10427000000BE000000C0000000C2000000C4000CF -:10428000000C6000000C8000000CA000000CC000BE -:10429000000CE000000D0000000D2000000D4000AB -:1042A000000D6000000D8000000DA000000DC0009A -:1042B000000DE000000E0000000E2000000E400087 -:1042C000000E6000000E8000000EA000000EC00076 -:1042D000000EE000000F0000000F2000000F400063 -:1042E000000F6000000F8000000FA000000FC00052 -:1042F000000FE0000010000000102000001040003F -:1043000000106000001080000010A0000010C0002D -:104310000010E0000011000000112000001140001A -:1043200000116000001180000011A0000011C00009 -:104330000011E000001200000012200000124000F6 -:1043400000126000001280000012A0000012C000E5 -:104350000012E000001300000013200000134000D2 -:1043600000136000001380000013A0000013C000C1 -:104370000013E000001400000014200000144000AE -:1043800000146000001480000014A0000014C0009D -:104390000014E0000015000000152000001540008A -:1043A00000156000001580000015A0000015C00079 -:1043B0000015E00000160000001620000016400066 -:1043C00000166000001680000016A0000016C00055 -:1043D0000016E00000170000001720000017400042 -:1043E00000176000001780000017A0000017C00031 -:1043F0000017E0000018000000182000001840001E -:1044000000186000001880000018A0000018C0000C -:104410000018E000001900000019200000194000F9 -:1044200000196000001980000019A0000019C000E8 -:104430000019E000001A0000001A2000001A4000D5 -:10444000001A6000001A8000001AA000001AC000C4 -:10445000001AE000001B0000001B2000001B4000B1 -:10446000001B6000001B8000001BA000001BC000A0 -:10447000001BE000001C0000001C2000001C40008D -:10448000001C6000001C8000001CA000001CC0007C -:10449000001CE000001D0000001D2000001D400069 -:1044A000001D6000001D8000001DA000001DC00058 -:1044B000001DE000001E0000001E2000001E400045 -:1044C000001E6000001E8000001EA000001EC00034 -:1044D000001EE000001F0000001F2000001F400021 -:1044E000001F6000001F8000001FA000001FC00010 -:1044F000001FE000002000000020200000204000FD -:1045000000206000002080000020A0000020C000EB -:104510000020E000002100000021200000214000D8 -:1045200000216000002180000021A0000021C000C7 -:104530000021E000002200000022200000224000B4 -:1045400000226000002280000022A0000022C000A3 -:104550000022E00000230000002320000023400090 -:1045600000236000002380000023A0000023C0007F -:104570000023E0000024000000242000002440006C -:1045800000246000002480000024A0000024C0005B -:104590000024E00000250000002520000025400048 -:1045A00000256000002580000025A0000025C00037 -:1045B0000025E00000260000002620000026400024 -:1045C00000266000002680000026A0000026C00013 -:1045D0000026E00000270000002720000027400000 -:1045E00000276000002780000027A0000027C000EF -:1045F0000027E000002800000028200000284000DC -:1046000000286000002880000028A0000028C000CA -:104610000028E000002900000029200000294000B7 -:1046200000296000002980000029A0000029C000A6 -:104630000029E000002A0000002A2000002A400093 -:10464000002A6000002A8000002AA000002AC00082 -:10465000002AE000002B0000002B2000002B40006F -:10466000002B6000002B8000002BA000002BC0005E -:10467000002BE000002C0000002C2000002C40004B -:10468000002C6000002C8000002CA000002CC0003A -:10469000002CE000002D0000002D2000002D400027 -:1046A000002D6000002D8000002DA000002DC00016 -:1046B000002DE000002E0000002E2000002E400003 -:1046C000002E6000002E8000002EA000002EC000F2 -:1046D000002EE000002F0000002F2000002F4000DF -:1046E000002F6000002F8000002FA000002FC000CE -:1046F000002FE000003000000030200000304000BB -:1047000000306000003080000030A0000030C000A9 -:104710000030E00000310000003120000031400096 -:1047200000316000003180000031A0000031C00085 -:104730000031E00000320000003220000032400072 -:1047400000326000003280000032A0000032C00061 -:104750000032E0000033000000332000003340004E -:1047600000336000003380000033A0000033C0003D -:104770000033E0000034000000342000003440002A -:1047800000346000003480000034A0000034C00019 -:104790000034E00000350000003520000035400006 -:1047A00000356000003580000035A0000035C000F5 -:1047B0000035E000003600000036200000364000E2 -:1047C00000366000003680000036A0000036C000D1 -:1047D0000036E000003700000037200000374000BE -:1047E00000376000003780000037A0000037C000AD -:1047F0000037E0000038000000382000003840009A -:1048000000386000003880000038A0000038C00088 -:104810000038E00000390000003920000039400075 -:1048200000396000003980000039A0000039C00064 -:104830000039E000003A0000003A2000003A400051 -:10484000003A6000003A8000003AA000003AC00040 -:10485000003AE000003B0000003B2000003B40002D -:10486000003B6000003B8000003BA000003BC0001C -:10487000003BE000003C0000003C2000003C400009 -:10488000003C6000003C8000003CA000003CC000F8 -:10489000003CE000003D0000003D2000003D4000E5 -:1048A000003D6000003D8000003DA000003DC000D4 -:1048B000003DE000003E0000003E2000003E4000C1 -:1048C000003E6000003E8000003EA000003EC000B0 -:1048D000003EE000003F0000003F2000003F40009D -:1048E000003F6000003F8000003FA000003FC0008C -:1048F000003FE000003FE00100000000000001FF79 -:104900000000020000007FF800007FF800000704AC -:104910000000350000000001FFFFFFFFFFFFFFFF69 -:10492000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 -:10493000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 -:10494000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 -:10495000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 -:10496000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 -:10497000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 -:10498000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 -:10499000FFFFFFFFFFFFFFFFFFFFFFFF0000000023 -:1049A000FFFFFFFF00000000FFFFFFFFFFFFFFFF13 -:1049B00000000000FFFFFFFF00000000FFFFFFFFFF -:1049C000FFFFFFFF00000000FFFFFFFF00000000EF -:1049D000FFFFFFFF0000000300BEBC20FFFFFFFF42 -:1049E00000000000FFFFFFFF00000000FFFFFFFFCF -:1049F0000000000300BEBC20FFFFFFFF000000001E -:104A0000FFFFFFFF00000000FFFFFFFF00000003AB -:104A100000BEBC20FFFFFFFF00000000FFFFFFFF04 -:104A200000000000FFFFFFFF0000000300BEBC20ED -:104A3000FFFFFFFF00000000FFFFFFFF000000007E -:104A4000FFFFFFFF0000000300BEBC20FFFFFFFFD1 -:104A500000000000FFFFFFFF00000000FFFFFFFF5E -:104A60000000000300BEBC2000002000000040C089 -:104A700000006180000082400000A3000000C3C06D -:104A80000000E4800001054000012600000146C04E -:104A900000016780000188400001A9000001C9C031 -:104AA0000001EA8000020B4000022C0000024CC012 -:104AB00000026D8000028E400002AF000002CFC0F5 -:104AC0000002F0800003114000033200000352C0D6 -:104AD00000037380000394400003B5000003D5C0B9 -:104AE0000003F6800004174000043800000458C09A -:104AF0000004798000049A400000800000010380D7 -:104B00000001870000020A8000028E00000311806D -:104B1000000395000004188000049C0000051F801D -:104B20000005A300000626800006AA0000072D80CD -:104B30000007B100000834800008B80000093B807D -:104B40000009BF00000A4280000AC600000B49802D -:104B5000000BCD00000C5080000CD400000D5780DD -:104B6000000DDB0000007FF800007FF800000487E4 -:104B700000001500000019000000002800100000CF -:104B80000000000000000000FFFFFFFF40000000E9 -:104B90004000000040000000400000004000000015 -:104BA0004000000040000000400000004000000005 -:104BB00040000000400000004000000040000000F5 -:104BC00040000000400000004000000040000000E5 -:104BD00040000000400000004000000040000000D5 -:104BE00040000000400000004000000040000000C5 -:104BF00040000000400000004000000040000000B5 -:104C000040000000400000004000000000007FF86D -:104C100000007FF8000003E000001500FFFFFFFF29 -:104C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 -:104C3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 -:104C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 -:104C5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 -:104C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 -:104C7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 -:104C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 -:104C9000FFFFFFFFFFFFFFFFFFFFFFFF40000000E0 -:104CA0004000000040000000400000004000000004 -:104CB00040000000400000004000000040000000F4 -:104CC00040000000400000004000000040000000E4 -:104CD00040000000400000004000000040000000D4 -:104CE00040000000400000004000000040000000C4 -:104CF00040000000400000004000000040000000B4 -:104D000040000000400000004000000040000000A3 -:104D100040000000400000004000000000001000C3 -:104D2000000020800000310000004180000052009F -:104D30000000628000007300000083800000940087 -:104D40000000A4800000B5000000C5800000D6006F -:104D50000000E6800000F700000107800001180055 -:104D600000012880000139000001498000015A003B -:104D700000016A8000017B0000018B8000019C0023 -:104D80000001AC800001BD000001CD800001DE000B -:104D90000001EE800001FF0000007FF800007FF8B6 -:104DA0000000023E0000350010000000000028ADA9 -:104DB000000000000001000100350804CCCCCCC587 -:104DC000FFFFFFFFFFFFFFFF7058103C00000000D7 -:104DD000CCCC0201CCCCCCCCCCCC0201CCCCCCCC3D -:104DE000CCCC0201CCCCCCCCCCCC0201CCCCCCCC2D -:104DF000CCCC0201CCCCCCCCCCCC0201CCCCCCCC1D -:104E0000CCCC0201CCCCCCCCCCCC0201CCCCCCCC0C -:104E100000000000FFFFFFFF400000004000000016 -:104E20004000000040000000400000004000000082 -:104E30004000000040000000400000004000000072 -:104E40004000000040000000400000004000000062 -:104E50004000000040000000400000004000000052 -:104E60004000000040000000400000004000000042 -:104E70004000000040000000400000004000000032 -:104E80004000000040000000400000004000000022 -:104E90004000000040000000000E0232011600D663 -:104EA000001000000000000000720236012300F331 -:104EB00000100000000000000000FFFF00000000E4 -:104EC0000000FFFF000000000000FFFF00000000E6 -:104ED0000000FFFF000000000000FFFF00000000D6 -:104EE0000000FFFF000000000000FFFF00000000C6 -:104EF0000000FFFF000000000000FFFF00000000B6 -:104F00000000FFFF000000000000FFFF00000000A5 -:104F10000000FFFF000000000000FFFF0000000095 -:104F20000000FFFF000000000000FFFF0000000085 -:104F30000000FFFF000000000000FFFF0000000075 -:104F40000000FFFF000000000000FFFF0000000065 -:104F50000000FFFF000000000000FFFF0000000055 -:104F60000000FFFF000000000000FFFF0000000045 -:104F70000000FFFF000000000000FFFF0000000035 -:104F80000000FFFF000000000000FFFF0000000025 -:104F90000000FFFF000000000000FFFF0000000015 -:104FA0000000FFFF000000000000FFFF0000000005 -:104FB0000000FFFF000000000000FFFF00000000F5 -:104FC0000000FFFF000000000000FFFF00000000E5 -:104FD0000000FFFF000000000000FFFF00000000D5 -:104FE0000000FFFF000000000000FFFF00000000C5 -:104FF0000000FFFF000000000000FFFF00000000B5 -:105000000000FFFF000000000000FFFF00000000A4 -:105010000000FFFF000000000000FFFF0000000094 -:105020000000FFFF000000000000FFFF0000000084 -:105030000000FFFF000000000000FFFF0000000074 -:105040000000FFFF000000000000FFFF0000000064 -:105050000000FFFF000000000000FFFF0000000054 -:105060000000FFFF000000000000FFFF0000000044 -:105070000000FFFF000000000000FFFF0000000034 -:105080000000FFFF000000000000FFFF0000000024 -:105090000000FFFF000000000000FFFF0000000014 -:1050A0000000FFFF000000000000FFFF0000000004 -:1050B0000000FFFF00000000FFFFFFF3320FFFFFC3 -:1050C0000C30C30CC30C30C3CF3CF300F3CF3CF324 -:1050D0000000CF3CCDCDCDCDFFFFFFF130EFFFFF86 -:1050E0000C30C30CC30C30C3CF3CF300F3CF3CF304 -:1050F0000001CF3CCDCDCDCDFFFFFFF6305FFFFFF0 -:105100000C30C30CC30C30C3CF3CF300F3CF3CF3E3 -:105110000002CF3CCDCDCDCDFFFFF4061CBFFFFF7D -:105120000C30C305C30C30C3CF300014F3CF3CF3B5 -:105130000004CF3CCDCDCDCDFFFFFFF2304FFFFFC0 -:105140000C30C30CC30C30C3CF3CF300F3CF3CF3A3 -:105150000008CF3CCDCDCDCDFFFFFFFA302FFFFFB4 -:105160000C30C30CC30C30C3CF3CF300F3CF3CF383 -:105170000010CF3CCDCDCDCDFFFFFFF731EFFFFFCE -:105180000C30C30CC30C30C3CF3CF300F3CF3CF363 -:105190000020CF3CCDCDCDCDFFFFFFF5302FFFFF61 -:1051A0000C30C30CC30C30C3CF3CF300F3CF3CF343 -:1051B0000040CF3CCDCDCDCDFFFFFFF3310FFFFF42 -:1051C0000C30C30CC30C30C3CF3CF300F3CF3CF323 -:1051D0000000CF3CCDCDCDCDFFFFFFF1310FFFFF64 -:1051E0000C30C30CC30C30C3CF3CF300F3CF3CF303 -:1051F0000001CF3CCDCDCDCDFFFFFFF6305FFFFFEF -:105200000C30C30CC30C30C3CF3CF300F3CF3CF3E2 -:105210000002CF3CCDCDCDCDFFFFF4061CBFFFFF7C -:105220000C30C305C30C30C3CF300014F3CF3CF3B4 -:105230000004CF3CCDCDCDCDFFFFFFF2304FFFFFBF -:105240000C30C30CC30C30C3CF3CF300F3CF3CF3A2 -:105250000008CF3CCDCDCDCDFFFFFFFA302FFFFFB3 -:105260000C30C30CC30C30C3CF3CF300F3CF3CF382 -:105270000010CF3CCDCDCDCDFFFFFFF730EFFFFFCE -:105280000C30C30CC30C30C3CF3CF300F3CF3CF362 -:105290000020CF3CCDCDCDCDFFFFFFF5304FFFFF40 -:1052A0000C30C30CC30C30C3CF3CF300F3CF3CF342 -:1052B0000040CF3CCDCDCDCDFFFFFFF331EFFFFF61 -:1052C0000C30C30CC30C30C3CF3CF300F3CF3CF322 -:1052D0000000CF3CCDCDCDCDFFFFFFF1310FFFFF63 -:1052E0000C30C30CC30C30C3CF3CF300F3CF3CF302 -:1052F0000001CF3CCDCDCDCDFFFFFFF6305FFFFFEE -:105300000C30C30CC30C30C3CF3CF300F3CF3CF3E1 -:105310000002CF3CCDCDCDCDFFFFF4061CBFFFFF7B -:105320000C30C305C30C30C3CF300014F3CF3CF3B3 -:105330000004CF3CCDCDCDCDFFFFFFF2304FFFFFBE -:105340000C30C30CC30C30C3CF3CF300F3CF3CF3A1 -:105350000008CF3CCDCDCDCDFFFFFFFA302FFFFFB2 -:105360000C30C30CC30C30C3CF3CF300F3CF3CF381 -:105370000010CF3CCDCDCDCDFFFFFF97056FFFFFD8 -:105380000C30C30CC30C30C3CF3CC000F3CF3CF394 -:105390000020CF3CCDCDCDCDFFFFFFF5310FFFFF7E -:1053A0000C30C30CC30C30C3CF3CF300F3CF3CF341 -:1053B0000040CF3CCDCDCDCDFFFFFFF3320FFFFF3F -:1053C0000C30C30CC30C30C3CF3CF300F3CF3CF321 -:1053D0000000CF3CCDCDCDCDFFFFFFF1310FFFFF62 -:1053E0000C30C30CC30C30C3CF3CF300F3CF3CF301 -:1053F0000001CF3CCDCDCDCDFFFFFFF6305FFFFFED -:105400000C30C30CC30C30C3CF3CF300F3CF3CF3E0 -:105410000002CF3CCDCDCDCDFFFFF4061CBFFFFF7A -:105420000C30C305C30C30C3CF300014F3CF3CF3B2 -:105430000004CF3CCDCDCDCDFFFFFFF2304FFFFFBD -:105440000C30C30CC30C30C3CF3CF300F3CF3CF3A0 -:105450000008CF3CCDCDCDCDFFFFFF8A042FFFFF4D -:105460000C30C30CC30C30C3CF3CC000F3CF3CF3B3 -:105470000010CF3CCDCDCDCDFFFFFF9705CFFFFF77 -:105480000C30C30CC30C30C3CF3CC000F3CF3CF393 -:105490000020CF3CCDCDCDCDFFFFFFF5310FFFFF7D -:1054A0000C30C30CC30C30C3CF3CF300F3CF3CF340 -:1054B0000040CF3CCDCDCDCDFFFFFFF3316FFFFFDF -:1054C0000C30C30CC30C30C3CF3CF300F3CF3CF320 -:1054D0000000CF3CCDCDCDCDFFFFFFF1302FFFFF42 -:1054E0000C30C30CC30C30C3CF3CF300F3CF3CF300 -:1054F0000001CF3CCDCDCDCDFFFFFFF6305FFFFFEC -:105500000C30C30CC30C30C3CF3CF300F3CF3CF3DF -:105510000002CF3CCDCDCDCDFFFFFFF630BFFFFF6A -:105520000C30C30CC30C30C3CF3CF314F3CF3CF3AB -:105530000004CF3CCDCDCDCDFFFFFFF2304FFFFFBC -:105540000C30C30CC30C30C3CF3CF300F3CF3CF39F -:105550000008CF3CCDCDCDCDFFFFFFFA302FFFFFB0 -:105560000C30C30CC30C30C3CF3CF300F3CF3CF37F -:105570000010CF3CCDCDCDCDFFFFFFF731CFFFFFEA -:105580000C30C30CC30C30C3CF3CF300F3CF3CF35F -:105590000020CF3CCDCDCDCDFFFFFFF0307FFFFF12 -:1055A0000C30C30CC30C30C3CF3CF300F3CF3CF33F -:1055B0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF73 -:1055C0000C30C30CC30C30C3CF3CF3CCF3CF3CF353 -:1055D0000000CF3CCDCDCDCDFFFFFFFF30CFFFFF93 -:1055E0000C30C30CC30C30C3CF3CF3CCF3CF3CF333 -:1055F0000001CF3CCDCDCDCDFFFFFFFF30CFFFFF72 -:105600000C30C30CC30C30C3CF3CF3CCF3CF3CF312 -:105610000002CF3CCDCDCDCDFFFFFFFF30CFFFFF50 -:105620000C30C30CC30C30C3CF3CF3CCF3CF3CF3F2 -:105630000004CF3CCDCDCDCDFFFFFFFF30CFFFFF2E -:105640000C30C30CC30C30C3CF3CF3CCF3CF3CF3D2 -:105650000008CF3CCDCDCDCDFFFFFFFF30CFFFFF0A -:105660000C30C30CC30C30C3CF3CF3CCF3CF3CF3B2 -:105670000010CF3CCDCDCDCDFFFFFFFF30CFFFFFE2 -:105680000C30C30CC30C30C3CF3CF3CCF3CF3CF392 -:105690000020CF3CCDCDCDCDFFFFFFFF30CFFFFFB2 -:1056A0000C30C30CC30C30C3CF3CF3CCF3CF3CF372 -:1056B0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF72 -:1056C0000C30C30CC30C30C3CF3CF3CCF3CF3CF352 -:1056D0000000CF3CCDCDCDCDFFFFFFFF30CFFFFF92 -:1056E0000C30C30CC30C30C3CF3CF3CCF3CF3CF332 -:1056F0000001CF3CCDCDCDCDFFFFFFFF30CFFFFF71 -:105700000C30C30CC30C30C3CF3CF3CCF3CF3CF311 -:105710000002CF3CCDCDCDCDFFFFFFFF30CFFFFF4F -:105720000C30C30CC30C30C3CF3CF3CCF3CF3CF3F1 -:105730000004CF3CCDCDCDCDFFFFFFFF30CFFFFF2D -:105740000C30C30CC30C30C3CF3CF3CCF3CF3CF3D1 -:105750000008CF3CCDCDCDCDFFFFFFFF30CFFFFF09 -:105760000C30C30CC30C30C3CF3CF3CCF3CF3CF3B1 -:105770000010CF3CCDCDCDCDFFFFFFFF30CFFFFFE1 -:105780000C30C30CC30C30C3CF3CF3CCF3CF3CF391 -:105790000020CF3CCDCDCDCDFFFFFFFF30CFFFFFB1 -:1057A0000C30C30CC30C30C3CF3CF3CCF3CF3CF371 -:1057B0000040CF3CCDCDCDCDFFFFFFFF30CFFFFF71 -:1057C0000C30C30CC30C30C3CF3CF3CCF3CF3CF351 -:1057D0000000CF3CCDCDCDCDFFFFFFFF30CFFFFF91 -:1057E0000C30C30CC30C30C3CF3CF3CCF3CF3CF331 -:1057F0000001CF3CCDCDCDCDFFFFFFFF30CFFFFF70 -:105800000C30C30CC30C30C3CF3CF3CCF3CF3CF310 -:105810000002CF3CCDCDCDCDFFFFFFFF30CFFFFF4E -:105820000C30C30CC30C30C3CF3CF3CCF3CF3CF3F0 -:105830000004CF3CCDCDCDCDFFFFFFFF30CFFFFF2C -:105840000C30C30CC30C30C3CF3CF3CCF3CF3CF3D0 -:105850000008CF3CCDCDCDCDFFFFFFFF30CFFFFF08 -:105860000C30C30CC30C30C3CF3CF3CCF3CF3CF3B0 -:105870000010CF3CCDCDCDCDFFFFFFFF30CFFFFFE0 -:105880000C30C30CC30C30C3CF3CF3CCF3CF3CF390 -:105890000020CF3CCDCDCDCDFFFFFFFF30CFFFFFB0 -:1058A0000C30C30CC30C30C3CF3CF3CCF3CF3CF370 -:1058B0000040CF3CCDCDCDCD001000000007010051 -:1058C00000028170000B81980002025000010270FA -:1058D000000F028000010370000800000008008033 -:1058E00000028100000B8128000201E0000102009B -:1058F0000007021000020280000F0000000800F004 -:1059000000028170000B81980002025000010270B9 -:10591000000B82800008033800100000000801001E -:1059200000028180000B81A80002026000018280D9 -:10593000000E829800080380000B0000000100B0F8 -:10594000000280C0000580E8000201400001016003 -:10595000000E017000038250CCCCCCCCCCCCCCCC93 -:10596000CCCCCCCCCCCCCCCC00002000CCCCCCCC87 -:10597000CCCCCCCCCCCCCCCCCCCCCCCC0000200077 -:10598000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC57 -:1059900004002000000000001F8B08000000000031 -:1059A00000FFFB51CFC0F0038A277033309CE345E2 -:1059B000F0E981831829D35FC6CEC05001C4554099 -:1059C000BC0B883FB132307C66255EFF352904DB95 -:1059D000488281211E88D7883130A84922C41DA45D -:1059E00019182603F9A150B147403A5F8A32770F60 -:1059F000169CA68029E62A8760A7639147C6196886 -:105A0000F24BE550F99904F40F34BEA28ECAFFA2FE -:105A10000AA113A0E257D1E4BF42E53BA0FEBAA61B -:105A20008EDDDC4E32FD5DC302A101FC99B04798CA -:105A300003000000000000001F8B080000000000B1 -:105A400000FFED7D0B7854D5B5F03E731E3393798E -:105A5000E424E43181104E1E2068080384888AB74C -:105A6000271030F6D27678D5582D0EAF10F2866B0F -:105A70002DBDB67F06084978A8C11F11ADD5E12913 -:105A8000F6821D3122B6880328D2ABBD37587C552B -:105A9000EB1FD10B8A90442A6AEFB5E5EEB5F63ECE -:105AA000C99C9309047BDBAFFFFFFD7C9FEEECC735 -:105AB000D97BEDF5DA6BADFD18C93181A40D23E476 -:105AC00022FCFB0621929D1032A1379DE32021D7B5 -:105AD000184292662FFDDD921442DCBAE2BF49A360 -:105AE000A9BBFEE41A9A5F5FECF0AFA44D5B1F4DBB -:105AF000786A092DBFEFA12FC34FD07CFAEC79ADA6 -:105B0000C5B47ECE24C90F5D1D1AAB1002EDE7D8D7 -:105B1000C276015281E5979030A17F92AFE8F845B7 -:105B200084B8E89F2497FE37891CB2A5603EE4D173 -:105B3000A09E029946483631FE55607E36FC09F536 -:105B4000447767D0EF759E77E513EC7F8E5F0ADBB5 -:105B5000E94773F20372C84DD3C6086D49C71DFBF0 -:105B60005D3908F9C00C99E46387B6D8FE6FCA0F97 -:105B70004C7514D2FE670B08FFF9D94936DA82CC8E -:105B8000A6EDE13B224E1F1ACC679FD9E8B8DFE0B3 -:105B9000DFDDDF40FFA7C05F4B09A1E5CB1C0C9EFA -:105BA000E4D9D9C530CE8919D71643BF73A61332AD -:105BB00088564D9D3DF69044F3EB1A89DF4EDBCDC0 -:105BC000290D1CCF81D9F8CBA79302E8978EEE6000 -:105BD0007D5FC4FFEB38EF643EDE3FCC1E2B10FA36 -:105BE00041F6978AA95D72A0F953D14B486A052DF9 -:105BF0001F1953EE9F769AD0F2E4E9E6F64013724D -:105C00001D2125C49372EA1AFA7716C9BA2842AD43 -:105C10006A0B8CEEE50F6B4AFFFDF922D001FA12F8 -:105C2000FBD61F6A9CE9E9A0F85A377B9687D0F427 -:105C3000F5C02C0FE0EFF5D9B3108FD6F673666779 -:105C400027025EFB1BEFFE063AD008FA3DC7B3B54C -:105C50007E9048EA23F4FB393AD1C331FDDF01934A -:105C60004D256409301B4DB325D5A6D2FA6C8DE8BD -:105C70009138E39502B1693B92499928E352F30FB9 -:105C800061BB3726D94AC371E67307EFC7551AB807 -:105C9000670EA56FD674127551BA1229AAC6E2759D -:105CA0005D8A541A8E03C7DD1C5E42687BCFC0E15B -:105CB0007165D802D09F32470CC4C2F50380674299 -:105CC0006F4AA24CEEE6F818FD72BFFB6C508F33A2 -:105CD0008FBB008E0990AAEC3B0E8F0C7C9301B217 -:105CE0009682FC43C26324E0FBCC1EB9240107E585 -:105CF0008FA1F01715AE2DA47BD41214B256EC4729 -:105D0000F4A42403BD5711DE0F29514F517E1542D3 -:105D1000AB848BD75C6A9E123965F035F0A93B19CC -:105D2000C7BF1C5E48A018E55231D48878C007E38D -:105D30002BF94DED02A5CBBAD1E57E946F8A219067 -:105D400033437EE1DF57F43B37FFCCBD9CD291CA91 -:105D5000916B39D38F8ADF2C67EB928EB50820C800 -:105D600064B9490F1012244077036FEBBEA278BCD0 -:105D700004BF5BFBDD6FC8E7603298C927933F051E -:105D8000FA07BD79D37E07F0F53ADF5E07CC6B5D8D -:105D9000FE5E827A8AD3C7E8D795AF5D52CED681B0 -:105DA0007C8D80EEC348A79EF2D1A7C6027E76A660 -:105DB0002AF78B747E3B9308EAD9756B48782BD011 -:105DC000B594E5B56F69E1B5748E3B9DBCBE98D6C0 -:105DD000D3BC06EDA9BEDB3A490B87687E6B8B8D81 -:105DE000B51FAB85459A1F319184148A4F6DC5C28A -:105DF000954E5ABE75A3EA17B55EFD34A225672DF0 -:105E0000B4DFB2DEA60AF0BD8FAD233BF3493844C0 -:105E1000C7DFB139F99B23693E14B2F987D34FF23A -:105E2000F8FA45D9A5442802B4313A9C21795CAEF0 -:105E30000402E5A9BC7CCB7EFFBF8EA4F03D365D9D -:105E4000F2AFA0453BD6CF4CD0289E766881043F68 -:105E50004D7FF0C07CCCEFCC0C2600DD766E9C9F95 -:105E6000004CF1C0E6991B46417B61D2611DE96C93 -:105E7000D6FF471F283AEC00384B999E4F6A0D7E9B -:105E800053A2F9BC4912B9894E21CFAD21DCDB1FE9 -:105E9000B211584FFBE86D8BBE4ED4CD7957EBB4A1 -:105EA0008F817F5D0F160920DA3B3586E7413792F7 -:105EB000F08AECBEE3EF5CC8EA13295D800E2EBFCA -:105EC000625967965AF856477970713CB95A751CF1 -:105ED0008F487A8990D68B57FA9F4662F0E97AF01C -:105EE0002881F5E98AE76381275DA07C0F83AB9C5D -:105EF000EFB91E1CF7CA5763E3F1B121EF1EA07F73 -:105F000022C577612404EB507A61240AFCE2C95768 -:105F100034B00B9A0931C9C5A1D1FB7C1D203713C0 -:105F2000223E58AFD78D7E83C98F5681F830E66FF9 -:105F3000B4F7E4B79358FBC1A88772F8CE537869D9 -:105F400039BB87CB594F7F84AD4724731CC2754F33 -:105F5000E161755E1C7D4CC80A94CB9749E07A815B -:105F6000A6DECDED51A7066CAEDF0079B7400291F9 -:105F700038DF4D13D87AD242745DA0E9A3442F16BE -:105F8000709D4B66FAD7B22EF5D19FBC5D16E9160F -:105F900040DF68D43E803487F831CD23014C4792EE -:105FA000564CAF26114CF3493BA605A41B5343AFF7 -:105FB000F8892A427EC4C4FAC920E7A4DA638BE5D3 -:105FC000BBD06432B23ECE3C9A2D787390F8EBF899 -:105FD0001D025FE748A68AFC43F87AF16EB018E824 -:105FE000C55428FCBBDBCCEFE224BE0E38EA3D6989 -:105FF000805733DD8D5454CD7C5A6DF0A944241C58 -:10600000C7321FC463CCB8D6FE5673FBC6989F9C9C -:10601000A2231F496E66CF5038F4BD71F0D1280815 -:106020007C9E41ABDC3AB229BF4B49B6C85A9A6B49 -:10603000744F76E8382F3F894767EB7CACF02ABE77 -:1060400081C1B3A9079E0ACB3AFA97C2F34FA6FEC5 -:10605000A44CB21DD60BA28670DE56BCF6F9DE4209 -:106060008FFEE4D29169D6574A8AD70287859F0668 -:10607000687F7CE34BEA7FE4C3FA1B21412AECA949 -:10608000F90101E67FAD401A13295EC868A2EDA0B0 -:1060900070CDF56ACC8E8B693719F491660BC97493 -:1060A000BECF92EE23D03EE427911DF4B367F36D8B -:1060B000A55B697DAA9FB663FD05401EAE1D6D0BF5 -:1060C00040B9D19F4E9E32F547FD2E11F0E136E8E2 -:1060D00063F1C3E4B136B41F957CA26F89235FC717 -:1060E000B97C151D71EAB09EB8CA94B0331BFA8F03 -:1060F00014433EB59AF8615D9FD4CDE651C6E130B8 -:10610000E69DFA5940007E6AF7313BC05548D03FC2 -:106110005432DA74F01FDDB40EF5427E541753503A -:106120003FA23FD81F9E3D5F3DED0BD07E7DD4B991 -:106130006A07BE92FCE9A09F578F56C860FABDF867 -:106140003B3BF6FFB9A762188999CF470DD1B10B38 -:10615000A9C170A6E118A6671BDA31ED6C780BD3E4 -:10616000FEE94A598EDACEEB7EE2D7C01E100F3F11 -:1061700047340FC01DD5755C171CA212B32E808248 -:1061800006FF6FD3D8BCF0DA6CC46B08E64DD56758 -:10619000787836E05B0A009E873822C2D27C867708 -:1061A000C03FD001CA8B8E3CB702F15C4DC6029E47 -:1061B00037C9A40CF43CE013D6897D82ED0E800330 -:1061C000F2F369FEFA8FFAC1FB5986F78C97299E84 -:1061D000004E494B64C6AD8EF2953B910B12D7270A -:1061E000BD7A92F9D9BDF6BDF6EF00CF964689ACDF -:1061F00085BCA6684A11B7F7414A8215D3C1DFDCD6 -:10620000563EFD28D80BB9E25787645A3EB45E3A31 -:10621000D911234F596574FDA476C2B0E5E6F2ECBE -:1062200090394F07407F34B7C55C3EC4C6F5AE8792 -:1062300078401EADF35AB6E85771FDD3550D24EAE8 -:106240009663F202C3A79117BC133B42747ECB4600 -:10625000118C034CB7B1F5B315BEA37C712F4FD78A -:106260005BFA315269A2DB46C6303D196F7DBADD5B -:10627000563CCE46FB6BB04D1E67A372E4922204DF -:10628000EC77975BD1E3F993D36D128E9F20B5EB3A -:106290002285ABFB3AE2DF4AF1BE4CEE8E827C2CCB -:1062A0002BD6FC215047FE30CA6312D56162F61529 -:1062B000C153027050784A6C384E04FBE9A6380787 -:1062C000FB7D99CCFA5D364A236837F603E75536ED -:1062D00019E10CD80409FD344E97551539F74DA333 -:1062E000D94E559F05FD67260567C17846B96F7E73 -:1062F00029FA6319C3CCF42B77D467017F540622A3 -:10630000D3807F4E7B5F6C92E9BCB73610BF44F1FF -:10631000FF9E2B701BF457737BFD08B07FDF065E7A -:1063200098002A3B807AACA564A55FA2E572891427 -:1063300095293FCA130FBF2517401A2A86388B9319 -:10634000D4337D47F54B2235BD1C23F58F217EA22A -:10635000803CD072556F25600F38A8DB703286EF15 -:10636000944C731E6CFAD87C7F7AE3722998E727E5 -:106370008703FE09DAE9DD49CC7F9226FA0B00DEBD -:106380007BAFFFA606F0FCC46633F967567F4D5A13 -:10639000FE6F69791068E2FEB6B4FCD5B4BCF1803A -:1063A00097569C9763CA32940B05F02432F907BFC5 -:1063B000BE671DE478F85BCFDB582F5737BC35F844 -:1063C000C3E120A71D833FA4C4592D0591FF423E80 -:1063D000F0B5281C92998F09784F1362526E1718E6 -:1063E000F69B9C5A887494DCD2A98E98F5DDC08FF8 -:1063F000B2FCDDC11F8E87F46D4CAD7855A4200131 -:106400003FD068D713B718E0FAEF34E2A979C41F78 -:10641000A53873A4B0786A7A5E280AF37252FD092F -:10642000EBD33D235F6BC5F081C50F3B94AD203F9F -:10643000B48CB6615CB36578E49002F90C6A40D123 -:106440007A67CA5D21886D4CCD637CE3F4B3F5D4E3 -:10645000353C8C7E98A1BFBD1C1F5EAD1CF5B3679B -:10646000A2D9DE31D601272BA2F436DB51CE94A679 -:106470004FC582BE7E9A539B761AE569A4B93F2325 -:10648000DED16EE3F18B6BC9B5683759E212FDE1DD -:10649000CD6BF87113D9BCDCD34918FCE6F48951F3 -:1064A000C49BD7CFF066D89B1E3EBF9B4A2304FCFB -:1064B000BE9EF8F3CD0C6FEBAF8BA27FB77EEC29BD -:1064C000B467BD851D263FCEF81ECAA1FEFCC4766A -:1064D000A8A1F618CB1B71238AA7E91969BDEB6146 -:1064E0002BB7DBAD7453279262D0634747A7158360 -:1064F000DEBEB784C24EAB3C7A589762F0ADF27EF6 -:10650000D47C86DF7BCBD87C697BF4D3EF9D9893DA -:1065100004E366F2F8B0117FEEF1CBEBCD784F28B3 -:10652000B4C4852D7EB7EA67F4524BCCE5AB395F36 -:106530002B22A7572A19CEE835303E4F32F8BC84BB -:10654000F17932DF37482FD10E011D924A99FF4D64 -:106550002C7EF34D291D8C5E378FC8003FFCFEA9B1 -:10656000DD3E669730BA26717EBCEFC61102C87157 -:10657000728926407D723EC35332C513AC77C9A5DC -:10658000CCEFF64ED4B05D5209A35B0B7C4CE15FBF -:1065900003748A891F3B4B5B75A07F6BF14E1D74A2 -:1065A0005932C5E1200ACFD4520A1BD89DB45F806E -:1065B000D75318C5B85A524970D8A5FC7A42A2825E -:1065C000CD87F8106C684BE93C25587E6862B22094 -:1065D000D07EEFA77CC0F180713C178FA3DF5F787E -:1065E00012F5DCFDF04D36C8A9F6EB1C9A27A5364E -:1065F0003FF807F797E608F1E2E7C6BCFB83CB2A32 -:10660000C712F83531FC7295C8E3DE16FE5D4722ED -:106610006A2EC857486FF7A5F5EA0F83FF7AE4653D -:1066200012E3CBFEF489A187DD2418B265F7D51FEC -:1066300092CEF8DE9E174079EB03EF24C6AF528A64 -:10664000B9FC3691DB7F865ED19207142727A10023 -:10665000AE7722D74F4FDA020BC554F0BBC3B84E0A -:10666000B8C874AE37199FCA9CFFA6E633BDE24A8C -:1066700089B076978DA73A90DFD634A8A81F5AC65E -:10668000DED59E43F1B06678931FBE738C6B19B94B -:106690008DF6DB3C7C79702B0CC0FD30D4BF22AC76 -:1066A000838C5F8D7D30030E9219D2619FCC097E61 -:1066B00011E06724DB5F902412B58FEB1DDF954757 -:1066C000E1CD6769289FC10DFEC9EBB6E02A9C6F3A -:1066D0007E6B94A29BCE9BC9CB6A21425C22CCEB01 -:1066E000727C1EB231BE8E9FF6F75D02ECD3C4E120 -:1066F000DFDD22DBA7592D478850087E1BED89F28C -:10670000C9EA6C6A97C781A391F36BD52E67F8C36A -:10671000187EAB892499F275FB33C21FC6FA117734 -:106720000AB84F51CDD158433AB200CFEF291AF6EB -:10673000576BEB48837C17E94E5B027810038F8B15 -:1067400074FD7752BEC4B8907B60EBD6E5F0A781AC -:106750000CD18540CBE4A90F79988E17DC07E3694B -:106760002A2BBFD271E3F0F50BB17C4DC457596AA7 -:10677000E56B7F14F9DA9D12C57AB79FF1B5C18F29 -:10678000899C1FAD7C688CBF9EC7AFD6723E5F33BD -:10679000A1498570DFDA519B309EE62CDA5C017CE2 -:1067A000DE32AA250C7CDE64F035DF17A1FE2EDB7D -:1067B0001FD35AA3B04E2672BE56D4EE06907BEB82 -:1067C0007C5D9338BC3405BE06B8395FBF07F893CB -:1067D000FDDD08AEC1D76B07CCD7BA456F9BD3FEA2 -:1067E000FC27D9C2D71E89F1E767C0D7004F0AB38B -:1067F00063DC3E96CA7EEADFC7E9E70689F9996B52 -:10680000B91CACE572B0B61F39F83F22F303FE9A0B -:1068100072308BC98143A2E58993AE8C1F25B0D31A -:10682000E3C87B9E24FCB5E1DE3443BC723CFE270A -:1068300030CD84BEF434D2CF44E7C0E43B8FC9737B -:106840007F72BE76687C38FE5364F4A7F82E9226D9 -:106850005C39BEFF5A7015727E36F04382C528B788 -:10686000317A663AC02BA9869E7904D3A979AD28DE -:10687000A786BE81580AFA2B6A2BC63B9C99AD6845 -:106880009F39F398BE31FC24EB7C8DB87813D73355 -:1068900049792102EB9F3D85703FAA9EF95199CC21 -:1068A0001F30E2D586FDA8187ED4D0BB709FA77993 -:1068B000783DDA97CD37D63BE2EDC336FBEE77F085 -:1068C0004D5FD33EEB1A5A0EFDAEC9BB9FC4B3C396 -:1068D0008C7918FB464E3E6E731EB5A8605CDF32A5 -:1068E000FCDE6AC73467B2FE7ABEE77A57EED1BBE8 -:1068F0002C8F76546E8C9F6FE9C7E00385E843A325 -:10690000103718E41E09E74C9A84043FD8C74D920B -:10691000209D72901E7BA95A891640FF2766BC9C59 -:1069200085F6B23DB806E4BCE9AB8003E2A9AB53FF -:106930005EF3C6969F9DF1E6B7C16CA5DFD5E27EFA -:106940008E8348B1FB6327DCDBD17E4BC837C7E9B8 -:106950009C14AE0902C413CCE50A8FBF2899E672D5 -:1069600099C75FA4144B39E70FB934BE5E7993EB36 -:1069700015DF02764EE7C41C16D73B712B4F6730EC -:10698000FE3EC7DB75F334C2F5EE5F531F25E5F617 -:10699000C2EF9BE2C7F822996547BB3E2B859D2B32 -:1069A00020B1E726E05F6BA24462FCCCA18197FF97 -:1069B00008F1D4610BBECA063C6B15EA615846DB90 -:1069C000A56C9CC76342F72818CFE63A8BFBF5020B -:1069D00045E3726A120BF4DBDB2185EFBDC0523A4E -:1069E0008F7B0591BFECC03722D0298CA98B44B195 -:1069F000DE433A309F081BE6B9E08751BF4BC433F2 -:106A00004C611BC68D7ECCF643D688786E83A80376 -:106A1000B4BFC9ED2AF89742887EE71AF877BE40DE -:106A20006B31C8C4E0B208C693ADED7C53D839A031 -:106A30003E7AFBAF4FDF375273818F542C37E81CFF -:106A400014F54E6942DFF25F8981F312C6AB58DC60 -:106A5000CD5A5F2AE91740DEACE5C20B7F3A057ECE -:106A6000F4AA6764F4A3A73C2347BF41F3355B0452 -:106A7000F4536D079DE80F773EC2F2518FA243FB9E -:106A800073DB058C07D5D9DBEFBD01E28ACF880423 -:106A9000FD8D7019EE8B9DE27326FB59BE9C07801D -:106AA0006AB61C9A0BDF57ECB713D877A8796EF14A -:106AB000B76FA0F9C5C764F4516A76AC50607F65C2 -:106AC00049588840BE6B32C1F143FBC4F00EDABEB8 -:106AD000CBDB9E36C70DFB2B0EA25D45E1F6B4A7BE -:106AE000CDA6F4A90C3F350DBEABDC2DF8C1FF9847 -:106AF000F2CC8EA319F4BB9A27043CA750B5CB4522 -:106B0000B418BA9C6A13A3DF80F8339D27F8C58BAD -:106B100049EB34C07BCD8E0D8A1613B73CD330922F -:106B200068F6DE7CCD13741CFA5DED93821FA658C7 -:106B30006B2341E08FCEE79C65DBDC30BF15CA08D4 -:106B40000FCCAB5981768BC3F3F6C17E7A65788B17 -:106B5000328DD6573EB245298FE1A7AA5DD7102DB9 -:106B6000863F4E6DCE4DBFD47A7B86AE5BB1F0547E -:106B700012A6B788145666C4EC7B76C8499C3F457C -:106B800053FF06DF875E2718C70A3DEF41BC1A7422 -:106B90005BA632BD60D0EDBCCAE9287517CD88B3BD -:106BA000AF7A2FD0C10EF12A15D3FB1B7C986E6CE7 -:106BB000D0903E9B007F57E1BE06967B279162886E -:106BC0008B7875A2C2529F3C5D2F96214E1260F9C0 -:106BD000B4DB83827689F91BE92639380F825CB7EA -:106BE000C94F4C96E8BABE49092E257E3ABEB47705 -:106BF00072C97560A705E7C8A9B09F1DAC60F1E830 -:106C0000880FE4A289EFCB7C4B66F2D694A1607C1E -:106C100064D3F78BB6A1ED41185E367DBF7C27ECBF -:106C2000ABD17EE6CA54AE1A65DA4FEEE5FB499B5E -:106C30003BD1D44FDADC0AA39FC5D88F7360FD6CBB -:106C40009A7BBD199EB995463FF5D88F6760F34A88 -:106C5000BB6392199E3BAAB19FF4DBFD681F8806B7 -:106C6000FF9076DC1775EF4E1AB796C4F2D1E41F89 -:106C7000C3781E2A55B17C943831C1244F497AB269 -:106C8000293FA874B0A97D6A20C7549F5E76B58558 -:106C90002FDDA8BF314F818A26B138AB325841BDB4 -:106CA000533CD881F9BB06BB51EFDC757DF02AB0AF -:106CB000F70056D0F37729C1316A1CBEA1F3120840 -:106CC000C6CF341BA47DEC32BEEF3979C85723DE22 -:106CD000A7DFD7D9BA4724D1FC434AF12330EFAD1F -:106CE00032B3E38D3843829DA0FE6BCE2EDA168A36 -:106CF000C16BCB50CA2F426FBF2D72D007FCB87347 -:106D0000F56F574A14BEA6A10A1E6E7A5CFEEDE12D -:106D100010B5999B8796FB00FF7685EA8FD8F11511 -:106D20003A7E3E8EBF1BC6DF2B333BD93ABE3D6752 -:106D3000A2697C475685697C8742C7A7F2B16FF587 -:106D40003B7C7C8ABFEB0979567E07C7B76755E065 -:106D5000F8CD0AA9308D9FD033FE01909FC3FDCDA1 -:106D60003FE77AF3FCB32ACDF357D8FC8FAEFE8011 -:106D70008F9F80F37F59FE80CD3FAB92CDDFCEFA5F -:106D8000ED19DFDB83FF5761FEAFF537FFDC49E626 -:106D9000F90FAB36CFDFCEC67F63F5277C7C378E0D -:106DA000FFA6FC099BFFB06A1C5FB107FDC047CA84 -:106DB00090847AF09FA961A461405DA3E3403A9278 -:106DC000C5A937C83908C75D098CEF3E4FA0FCE65E -:106DD000EED5A7244C2590EACB5ACED355BB8B15C4 -:106DE000E62F84D05F58C4415DB85FC4F58C6CB4A5 -:106DF000878753783BF78B21C82FDC78239E5BACC9 -:106E0000B313DC77A75630FA1FFFF1C0E8ADB1F33A -:106E1000B2A68B5A65CBFE1383C738EF5424ABA6BA -:106E2000FC2988A7503D7C12FC1F9A9E96E978B4F5 -:106E3000FC43F083AE8A951B762E8C7677229FCE0C -:106E4000EBBB1CFE5312C3F7A93B05DC47F87CC320 -:106E50005205F4D9A25697C96FA8E374EA7ECE8E84 -:106E6000FB8DC679BE5B501409F9FDC16F1D05BBD2 -:106E700071F1E641A6EF6E27E1D5701473C1FA797E -:106E800043553AFFDBCAECE3448C6BEB43581C9C44 -:106E90000C81B84959DB067908CDDC52269BECF908 -:106EA0005B83E6FC6D15E67CA71C966D60CF2C110C -:106EB000C816DAEFF7EB65CBB900368E5749E676A0 -:106EC000251BEFBB948619B4E8FB908E836215E90D -:106ED0003A5765DF1AF0D4DD2D9328AEC71DA9B847 -:106EE0000F144A45BF2DA8B2795BE19D2B3BF400FE -:106EF0008567EE8F44C4A715FE8E832EDD46EDF325 -:106F00008ECD7F90217E6C9D8F15FE3B965BE7A317 -:106F10002AB03ECC0B59CB199F58F9A96E7FF13698 -:106F2000B33D7BF3B658FBB56AD70C537E49F85690 -:106F300053FBC59BE799EA17B52E31D52F68596ADF -:106F4000CACF0BFDC8D4FE8EE52B4CF5DFAF5F63D7 -:106F5000AABFAD6283297F6BF02153FB5BCAB69851 -:106F6000EA6D07477D07E468D5EB229EFDBDE03E54 -:106F7000752FD89B17DC12EE737E44ED159083338A -:106F8000D45E81B473FF78F4A7A91E2C874DA2F9B3 -:106F9000CA98552D99A09709EACF7265C2AAD02444 -:106FA0008A17B0D7A97C889B15121D04CE4C720F8E -:106FB0001F778B31F51D97A9DF4C057D7CDF7AB1FA -:106FC000237E79DDD679C3D4387E6AAFDC9221B0D6 -:106FD000CE7559CE9F1869B5E53CA7B1BF7D81EB51 -:106FE000D96A85E983EABD1993617386FAE523E2DC -:106FF0009D9BECF93E22B00D48B0FE53811F869850 -:10700000F66BAA76E59AE4FBEC2111E1AA059D4016 -:10701000F5EA1752608D0272163D92356B34C0A1AD -:10702000AF5540EFEC4FC575FD6C43E936D8AF3F27 -:10703000D310C0F4A386324C4F350431FDB0A10209 -:10704000D3930DF59876342CC7F4BD8610A6EF3691 -:10705000B460FABB86564CDF6AD88CE91B0D614CD4 -:107060003B1B744C0D79E8D1BF016E0F1B1BD784FD -:10707000DBC37C2E8DA93DE7C270FFF7BCFBF3118B -:1070800060EF9F7FCB8EFB6CFDE1CBCA6FFDD351D0 -:10709000477BA53C3C089D636BBD3381D1C9692307 -:1070A000A5641CECFFECF4CFCFC7BCC42EF584FD67 -:1070B000333C71FA85785DFAE5E944F4EE829994FF -:1070C0001EA71EFEAF22E8F702AC7F60071C1171FD -:1070D0001D26D16D7EA0D795E24D78E1F759102F8E -:1070E0003BD783BFF62C888B5DABA8D8FFF9363B26 -:1070F00081F8D2F9032EBCCF75FED8362FC8E33203 -:107100009F188E3D47614D6B22D961B7C9EF36E7B5 -:10711000CFB70AA5781E9A6889B347035FA961387B -:107120000FD2D9E0C3D4E867994FC171CEECCA65DC -:1071300071337E5E83EC4E427EA57E27B6FF9F862E -:10714000A7BF7E0C780869231F38085E71BB98DBE7 -:107150007FFB7EF949FA4C81F82A39207F0EF682AE -:107160009DFE77111C652261DEE8B72E2286EC6356 -:10717000A07CB7693CFA9D66F8F417732EC5B7E694 -:10718000FB34220468BF469CA40AFE80F330F5025B -:10719000C6AB8C784997E46E11C6F4C64BEA78BC4E -:1071A000B8C6D1A10469D1B9B6DC4BEE9F9E69384F -:1071B000A6C239AF0A47AB02CE4F45645409E8B9BD -:1071C000736DABD2C01EAC12CFDF152F7E9B6767ED -:1071D00071BD2561B9DBBC8E72FE20B45FA39C1D1E -:1071E00072749F8AC99FB5313BDBDAEF04FBC0F6AE -:1071F0002D6A771F9F7683D6174FB5FB3F55303EDC -:107200002E11535CC9C0DF7B4A60829DE2A972D710 -:10721000FB688F7E248746DC7D09FDD4777E6E9FD8 -:10722000E97C7288B4C338F327F2818876CB3B744B -:107230003DFDF815999DDBE4E7807BF695F9BEFEF0 -:10724000029E9BDF5685E7843EDEF78F68FF2D2484 -:10725000012FD281B416811D798ED84A014FE7C81B -:107260006BDEF13174B8953A4A40EF052D663B86E6 -:10727000DABFA6FCE2CDE67C39999906FAA47CA394 -:107280004CC202CECF547FB35DC57E1793FA265809 -:107290005725EE8FCC57893484EAD59A677F5634C8 -:1072A0008FC211B4333FC888BF2C49667660654AE7 -:1072B00058817DC20FDAC67FF70620833DDC04715A -:1072C000289248FC3B485FFC5E29FC56788DF5BA55 -:1072D0004F1C88C321EE12E2EE03D6DA056ECF868C -:1072E000303DC0E76DF805C72CF915767EDE5224D7 -:1072F00022D0FD9CEA08D912B1DE1F8578DC5EBB86 -:107300007F950671FCC06A7B6A6FDCDF6897640F4B -:1073100062F959E1D5723CF720450BF0DE218FEF81 -:107320002B9C1FC4046F019C23F540DC1ECE753AD4 -:10733000BD5B21DFE4A9C0F31F7520EFB4BF7BBCA8 -:10734000D38E419CDA415AA33AE55FBBCFB21FA06E -:1073500099F32E904BD0675080E7A209C6B95C2301 -:10736000CDED3C7E73FE312E8F7481433EEE39DFCE -:10737000E67047E13C0999289DEDF1B772C0DF63E3 -:10738000F0C3FD56687FA7CADAD7F27DDD3BDF9EEA -:107390009C9E7C097D54F7A540C231EB489DD4AD3D -:1073A000001FD67D2961F9D7D69B1A5D5563F4E697 -:1073B0002B4AF059FB04A627013E818E13BBDF64E4 -:1073C000BD877002F861422F3F7C6D385288497F3B -:1073D000BFA7048FC583E36BF7EFEBD3FF09E0BBD7 -:1073E000FFB1FEF3FAF4DF110FFE9A67F7EC0BD151 -:1073F000F5B5F2170F78E110D3C7526B1A9CEFACBA -:10740000DEB1DA0B72F99114F2025D3F0E8B71EF6F -:10741000E7A63B0CBED3DD708FB096F3DD999FAF2E -:10742000FB36F82F9FEF90558C0FECB247ED942967 -:107430006BDB9630F9D8657F9FE59BF1BC53DD7E11 -:10744000B3BEA87CFC81340D0F5585B8FF1C45FFE9 -:10745000A076FB7F4C03BBAB8E74A3DEB37E07E349 -:107460007F998CF6C03C25B16FBD710EAB8EE3A544 -:10747000AE6D1DDE13AF6BBBF934139A0EF43BAD4A -:10748000DF5570BBDFE1309FDF34F042C2CCEE5FEE -:10749000F5C48305EF53B8CE6E7FC52BE4C7F22940 -:1074A000D37FE7230B1EFBA5D6BF5C7552FD186B7F -:1074B0005F1BEBB4B69FFB2B07585A2D47BDE00F5F -:1074C000566F91F1BC7BF59E6D3B1F86F8CCDB7649 -:1074D000FF70DA7FD59E97DEB89EE6AB9E9253A6EC -:1074E000B369B8E19EA2419F3AFADFF271BDF4A8F8 -:1074F0007CFA25451BCDCA7F9CDC4B97AAA70E2999 -:1075000064745F7C4C891C52D87EB6853E91F7A787 -:10751000815FB1EA892F14D05F1F1F14487A761C4F -:107520007C6E7909ED63C013D293D3AB877E96F658 -:1075300075942EA8172DF4B2B6FB98AF07D02FC4C0 -:10754000E3297F3FF94BD8B7F99DDD0F78A878F292 -:107550009FBC309FD3523DE3F39FAD4E83FB20157C -:1075600072284DC59495573CFA03E4BFC5C77F9078 -:10757000C6CEC5EA19FC5C5706CC73D12373709E46 -:10758000E524887C58F13376CFFC82444A9F8A23D5 -:1075900027F739D83A767AAB1D37114FC34202FB31 -:1075A00018AF89E11D180F64E70D7F60EC3F91650E -:1075B00098BFE060F45AE430EEF1D1A524967FB78D -:1075C00037B7039DCE0CD5D3218E5C47A410C78757 -:1075D0007091F62B1E9F9ACECF1D685211FF8EEA36 -:1075E000FF29500EEDDB65DD5960FA8E5CCCEE1D97 -:1075F000FF4E3E3E853B01ECD7D369D41E8C33BF92 -:10760000030E639DA676560C9FC5C83B93FFED6B9A -:1076100098BC1BF21F9E510AF59F9D607204DF818A -:10762000FD42E18AA663FDA1D902EA073B89C69320 -:10763000F3ED32977373BD955F28FC12ACC73D7CA8 -:1076400003E324231DD0BE2DDF48BF8FD5AB30AE62 -:10765000B76FBF861C2FE6FA60AD451F90475207F3 -:10766000B47F5B2D87773E0CF24BE535A481FCCAD5 -:10767000F85EC127BB8FBCF13D2AB79F440CB935DA -:10768000EB55ABDC56EC9D40E2C9ED276E3F892BF4 -:10769000B7B43CAEDCBA3B909FFFD67AD5C0E3D3FB -:1076A000163C1A7AB23F7C5AF5E4B71D5A5C3D4944 -:1076B000FF9D20457DF9D1E04383FF2AFFA506CF3A -:1076C0000BF5F0A9C1873D7C6AF0619F78A4098F12 -:1076D000D6FABBE16F3A85C07332C6CFAB0FB0FDAF -:1076E00067FADDD12185882F1D9739D27A74484AEF -:1076F0006C3E6CC9472CED754B3E60691FB4E4EBE2 -:107700004DEDABF71F51D8B99EA8A99DB8FCA7E4D1 -:107710008338F101631DAA6BFB5409017FB8BBF1EB -:107720007B79250979205EFEBC88F1F22E8AE3265A -:107730003A4ED7EE6C7C8F60B593C557BAD46E2F96 -:10774000D893AB9358BE3B5569023D6894773B593B -:10775000DCAF2BD0ED4D8AB1EFDE3F20A21EEF084B -:1077600093D2787E28DE40A1F8ED20FDD5B3FD80D0 -:107770002EB0D761BC84AC30F0E354D19DB51CE28F -:1077800035AD22DE6B5BB8E2162F9C23E93A90FB05 -:107790009D325ABEE8D722DBA60CE952468C1FF870 -:1077A00011096D9A24C0FEF57AE49F0507985FB829 -:1077B000707D7C79A8E4DF95BBEF5440EF527FEEFB -:1077C00064ECBE87D14FC52396F203FFC8E5A6152A -:1077D000E31F95DBCDF5411E3F18ECE4E7BEC792F1 -:1077E000B1DC7FB7C5DE0F9E2AE67FA78CD2A7EB60 -:1077F0009848E03CC1F90322D2E7FC6E767E00E3B4 -:10780000FCD701BF772BB1E7A9CE827C5DD5BF1E27 -:107810003BFBCCEF8BEE063EDAF74EC14F697A7632 -:10782000DFDB237E05F967DFCC7A87F46D3FE5A0C7 -:1078300013F755BA0E7A90FFBB9EFF4DD6DD907FB1 -:10784000CE8EF1ECAE835F14003F75ADB457801E51 -:10785000ECE2E7EF563DFF454107AEBF8D48C7A9B3 -:107860004EE64F9F3FF05FEFC1FD81F307E8ACC0EC -:10787000BE38E842F9AAFBA513E36F5DCF7F511430 -:10788000EB27FCA5F3A9E5FB9D5D1E52B617E04B67 -:1078900062FB4475BFBA6E1BBC2F51D3764859406A -:1078A000EBA7BCF0A702D0AF5D7B99DDD429773C74 -:1078B0000AFB7981350F34CA945E9D20648369FF89 -:1078C0006BDE280139EA8B973F615C71A0F858FCA8 -:1078D0007F0D3E049DE93F4F184C852907FFF8DED8 -:1078E0003BA0270EDA912F8DF97E125981F6CCE557 -:1078F000E6DDF4FFDCBC85E840E6BD03E63DE1EFF4 -:1079000077DED7C0A1A1D4BE72D097CF9FBF0BF3B3 -:107910007B3C7E847780FCFED2DFF9FCAF98EE7B67 -:1079200029DDBD979FF7877FE7F3EE9FEEBF9ECBE4 -:10793000E9AEC27998BA17FE84F05DA99E9312FE53 -:10794000BEE5BDBFF91BF6FE5A9BBF35271BCF9383 -:107950003AC0B0707B66B6407871EDC8992AD89D60 -:10796000623FEFD54C48607E9528B0F721C850168D -:107970000F24DCCF82630DF80E889BDD3B93DC4D3A -:10798000687713C9DFAE53BCACBD7ABE1FCF1A9166 -:10799000716F05219F39C98FF16E8BBFD928105D9A -:1079A000A0F6AE74F5378F81DF238FB445ED0598CF -:1079B000BE0F69338F63CAAA62F287DCF9E6BC5353 -:1079C00033E7EDBC3F0761F03B7C240CF16C71D4D4 -:1079D0006115CED3896325024FA538496B08FC0E8B -:1079E000BBCFFC7D5202E17EEF5F86C78A0416A7FB -:1079F000128571ED3AE071940DE3DC78481BF1E2F9 -:107A0000C7F7BA08F7AF7BF1DAD40EF894C03F6637 -:107A1000F617FAD584FBD312EF421A69D39DE676A6 -:107A2000DC8FBE2C9D185DB2AA399D9699E862D074 -:107A3000210E7D4C7431F07CA5F4B1D2C58AFFEBE8 -:107A400013185FF7472F832E996E1DEFD7C9DC7F80 -:107A500028013F13F2990182FBABDC7F905274BC8A -:107A6000A724AA7EBC97007E5C941AE02FEFDE86E6 -:107A7000F1A4733F7FFFDB004FD5AF44E2A0F8EBEA -:107A8000DCED2151F85E0A2BE09F56B689B84F40D5 -:107A9000A468D1AC987D62C30FA8FA8507E753B9F3 -:107AA000D71E9E4EBFAFDCF74101DA612BBBD1CFB1 -:107AB00009FD5C60740F7514C03E70A5C4FC112BE9 -:107AC000BFAC4960F196B3CFB9CA20AE23EC62E7F0 -:107AD0007F2B23B7C8F698734DA10499C59B9E735D -:107AE000A15E083D21E0F928802FF6DCA9E1879C02 -:107AF0007D4260F0ED97F19D98CA5D4F75427CAA7A -:107B0000F22DBB1FCCF8BA5D9FE27EC8945FECF10A -:107B100076A01F2E9AE2127DE201BB44E48FDAB612 -:107B20001AF443681EF9A236C2FDEF2BF457AB7E60 -:107B3000F1FC3EB87056F5F4E35E887F9D69DFE1A5 -:107B4000C5B8C0AE4BC7E7FAF8FF9135DCFFFFD6EA -:107B500069764F3BBEFF7F06FEA076F1D30996FB08 -:107B6000ABBB06B1F71449B4E852EF7155EDB9F06B -:107B700028C4AFCFEEFDE45180BBFACF7F7814FC70 -:107B80000A72D0A9C27D82BA9FBF8EF13EE3BBDFED -:107B9000703DD0F9C4E3182FED7C9BFA1FF45FE72A -:107BA000F3A7B3C0CFEC7CEA8F69104FB9F3F9A902 -:107BB000F86ECE9DCF4C492771F4899102FF86075C -:107BC00010AFB5D2ED48DB11F47FCE51BA83FFD9A7 -:107BD00013D789D4B07899C6E339BBE3C7C7FBC4D0 -:107BE0006FDA667DE7C6424865BF460610C7394171 -:107BF000E939660074DCCDE375916F5D328E730EEA -:107C0000FEA0F43A6BA1E385B6458F3D0C756D83FC -:107C1000FA8DE34407803F23FEBE3F41FF2201E48B -:107C200068EFBF60FC0CE8379D4EB873CF852CD849 -:107C3000BFF848EE9E8BEF853C6F57211E51F9FC33 -:107C40009B284F9DCF1CC7F836E171F04ED2F38FC1 -:107C5000C52BF999CCBAED1E16FFE17480F890E6B9 -:107C6000C5721E07627C6DC487FA8B0B8D71B17370 -:107C700027C6BE40CDF67778BCA5976EC244A0D784 -:107C8000FB97DCCF30F0A0021EAE8D8D7BC68FC37C -:107C9000F5C43D2D74037A42BCB327AE49D8137B9B -:107CA0007561E1CD7871F4CE2D2C5EDA29C73F8F56 -:107CB00065C441AF7659E29FE181C53F2F378F2BD5 -:107CC000C5D3609786FD5AF175F6ABF8FAFD5BAE49 -:107CD000819D5FE8777FADDA7C1FE63D2538DD05C5 -:107CE000FB6B6DEF2B04CFA774B3732B7CBE67F9CE -:107CF000F9D3B33F17312ED6143982FADDAA3F8C5F -:107D0000FD572BBC7770786BF7B3F5E3EC5E4FD87B -:107D10004DFB397BF839E4EBDADDEF635CEEE8AE7E -:107D2000A7958E98F516D68F70CC7CCE3E79A8801C -:107D3000C579E3DF1BAB71317BB3EE40FC71EA76B2 -:107D40007F6A1AA72A1451981D70E9F1CE48FA2DBE -:107D5000D0DF997619DF4D3A1311E3BE171C70C9B5 -:107D60007C1FA195C90F5D47F19EC071767FA7F07A -:107D7000B5043C577FE7F1D277E0FDB73BA95883C4 -:107D8000DDDFB682F169DB4FF42140EFB6E3DF13AC -:107D900061FDDA07F88DB1FF8B4ED44FF150FD50E5 -:107DA000F46EA010D8D5AA77AE7DCB66829F8E9355 -:107DB0000EEB4223ED07EE83C0B939BC57EE9D565A -:107DC0000AF088AA4D750A7DE721BBF97D55DEAF23 -:107DD000AC9AEF2190AFC66BD08F6F268B4B66CCE1 -:107DE0003252169F0C19F787CA13C2ABE87C7FAFDB -:107DF0000637BB285E7C9E8DD92F1178276AA20694 -:107E0000F6D3632E7EDEC14BBCECBC833B64A37A0D -:107E1000FD61FFF60D93089E67D8067CD9739E819D -:107E2000440B802F8D767DEA2DE71D32E1132A5A0F -:107E300022873317EE2550FDB26A86772BE41FF1B7 -:107E4000B0F7CDB248F72138DFB08DDBA3D960158C -:107E5000E7F67DE7ECEBBE6F9632A578E9303F851B -:107E6000D3F55F53E15C7CCA2DC54F0D5169852D5B -:107E7000631ADCA34979BC786C06CDCF5FFFF4347C -:107E8000ACFFF7E2B15934FF937B0EB2FA2A01CF6F -:107E9000C1BEB0AE761AF0EFD796FBD9143366B9EF -:107EA0007F05F0772EF0EE77176970AEA25BE1EFF9 -:107EB0006504A0DDD0890C7F99EE779F027F6598DD -:107EC000AD6305F0EB63CF7F9184F716F9FBA12A30 -:107ED0006954E1DC152D9A78F112E7F3FABCFBCC7A -:107EE000F5CB8D49C177813F9AE78DBC6F1A1DEFA5 -:107EF000E18A710E760ED0F24EA39A82745DC8E9C3 -:107F00004AF83DCB457C3E8BC590C202DFAD5C7F1D -:107F100019EF51578B57F41E3587ABDBD5EFFB6755 -:107F20007F00783393827F00FC59DF3F7BC515B813 -:107F300000F519E55FE27D5CE33D33EBBB6844EAA5 -:107F40008EFB3EFB56FE2E5A7FF0FE9B3B28BA6905 -:107F5000FF392F687B8F51391BB350F1C3D1CF311B -:107F6000CB0BFDD220C226047610A71F3CCF88F78A -:107F70001FEE22B85FDB651774F0AFBBFE49457D8D -:107F80009EB9703AFA5F5DAEEC089C33EABA5BC307 -:107F90007D3D8A0101E469E881C428F887541E3ECA -:107FA000B7C8C3E766FE378FDB7551DBDF81FDA9FC -:107FB000BC3F6AA0C5DC8BED12999EEE6AD0108E94 -:107FC000A1247408D6FD818E97E3E6EB37A7CF4650 -:107FD0009B9EEB9E80F81FEE8EC1FF2877BF74CC6E -:107FE00077333AE6BBE3D0D1FA6EDD7BAEE058687A -:107FF00077BAFC28BE5F677DAFCE4ADF3AA9F5218C -:10800000783B2BEDC0A7B8FE18F41BB37C2CD2290B -:10801000869E93008E31073EB501BC061D1FECE71E -:108020003C79A99BAD73D6F1D2CA3A0607E3B49F57 -:10803000E5D64CF70E0A1C457E89CA69BA8DC587FC -:10804000FAB6EFB7FF9C4B9DF32C5059BF14FF734A -:10805000004F06FE6F75F3FBEA7DF17F3BB4A3F89A -:10806000BF1DE63F00FCCFBB14FE0DFBBF8AEB87B4 -:108070002AD89FA27CF41FDACCB41C3AEE34D18DFE -:1080800072B06487C8F731D9FB5F863E59725DFDD7 -:1080900021B817B9E46702F2EB42FEFEE527FCFDCA -:1080A0004BEBB9C1F2B210EACBCB9F1F0CA33EAA97 -:1080B000DA652EFF6777CFBB975978DE172435AD89 -:1080C000F7BD4E2BFECFBBB9DE58E8B4C57B2FD72A -:1080D0004887D6DB4CE7CC33A6F4F483FEA0CFA6CA -:1080E000BD89F1B87F9509C4137429A510DE192044 -:1080F000854209F45BCCE5D7E86FD872F3FA9F1D8F -:1081000032DF43CC6D31DF431CDE6ABE8778D56633 -:10811000F33DC45161F33DC46B768D33E54747AE03 -:1081200037B51FB37FB2293F36FA4D53FBF1C7660F -:108130009AF213DABF676A7FED5BF34DF5D775549A -:108140009AEA6FF86899297F63F73F9BDA471731FE -:10815000FD78B8617911DC5B30F07278A96253A1C7 -:108160007CE9089B5A105B9EA66B059016E9E07FA0 -:10817000F5272F531C3F2A8A5DA78B896CD26F533A -:108180001CE67CD46DFE7D8F972C7235A47E52CB7D -:10819000089A1DBC240FCF6353F93AC6F5DBB10131 -:1081A000EAB7DFA07CD5469B206F952FE3BD019AEF -:1081B00086D88FADB0779F1F729AF9D4D78F5EF9AA -:1081C0009DDB3807D4CAFA53CBC64B263931CA3F98 -:1081D0002A8C2D17164FC77340FDF5ABF8165CB30C -:1081E0007D10BC3B3C0F53A3BCA9CC16F7DCDF676A -:1081F000EEBFD07FDADCC78EFA0CF07CCEF7DA2641 -:1082000038BF567B7B37FA511976335E7AF3EC5DD3 -:1082100063039E471A483EACF7C6FDB64534E1EB12 -:1082200036CE77D1DB33D3E09C41663FFE55A18744 -:10823000E9EB471B42D72C04C21187E95E7956B49B -:108240006E1AF839C3F879EB4DB6F8E7A0923C0CFA -:108250002FE9A048C15E50DD682F9C2B7FD70B4FC4 -:10826000C7DC680F2679E838F3C7B417B1FBD4BA76 -:108270007FE6E85EB80D7D94E50E6C02FD92E59315 -:108280008896DD179EF4DB832DF08E7863B2CDEFF8 -:10829000C67CB700E3D97F4CC8203A5EE39F458493 -:1082A000AFF1F075783EC8EEAEC7B8AB314FC2CF74 -:1082B000091871E60BBED98980CFC6AB7BEE07E10A -:1082C0007B9017DCC176E8F7C24619C76D9C2C98E5 -:1082D000EA8D794B9BBF8DF7BEB2DC6CDEE574DEB8 -:1082E00000B73D93C1D5F8A8403211AEFFBDF428C8 -:1082F000F835FB5CF8DE07C5C710C0C7393DFB7316 -:108300009B31793AAF9A41EEAD6BD19E89EFA74E82 -:1083100037E6A18F34D13BE32A33FCE24619FDC690 -:1083200045496E3CEF106E8872FA9AE7DFE49BF9DC -:108330009D5B295CAB4E88F8DEB6D6D1BAF428FD39 -:10834000AEBCCDE50F6B7DF17F4E63F052F8A77B9D -:1083500040DE364FC3F9E3796A80FF31813C9C0DE2 -:10836000FC172C453E186C23B06FD3C74EF0307904 -:108370009EED51D97B35BE722687BE85D76CA7FD91 -:108380009579FA5DF76FF3B075FF364F9C75FF7204 -:10839000EF075797B51F8554D445B43708A91F1167 -:1083A0006B47533D560EFD1B7931F1C705D06FFF6A -:1083B000769ABF6544F6E5ED34B0CF800F0DFBEC47 -:1083C0004E8FD9AE8CD1BB3FF430BDFB43CFC0F450 -:1083D000EE8FA1FDE9EF45E3DA35A94A7CBDF7B49C -:1083E00087DD1FAC531582E703FBD90FD8C9E5DA47 -:1083F0003AEFFED6A5CBF91F392E834FCDFAFEFCFE -:10840000312D11F454CA0742DC77B7862CBF6D3C7E -:10841000D06B9BAD7833CCF76716FE78684D9FF52F -:108420002BCCF1188E8BC76A8A479B098F3B3C97F0 -:10843000B00FBFB6BEAF30DFF3E9E4F8A67ABF09EC -:10844000C63B37EBBD22886BD4CEF91CF5FED71E98 -:10845000A7CCBCAE187E391D6705E0A173D69F7905 -:108460007CAE03E34AAB9EB92A11E25835930D7AEC -:1084700044F07DAAF3F939489773FBEC3AC0792EA2 -:10848000999D133DB7EFDAA310F7F8A4E158722CC9 -:108490007DCF3D79BC48A6FD9DDB7BBC48C2037700 -:1084A00061D33BD435177F5B1470F7DE4BE8E137BF -:1084B000075B8F363A597CE54138173786DABF6A51 -:1084C00012F2657A9AED5E28171DBF1DFC215C39FA -:1084D0003FE62FA659B24AD03316C17ED33C37EEC1 -:1084E00067F972C9C86CFA9D12AD87E3CCC4F96A0A -:1084F00098C0EF04B84E44F1F7023CEF7660F83EC6 -:10850000F143B2029EC2FFBD1A3C09784F3AAB0953 -:10851000891AC4778A6E1E4753690AD3BFDDB73AFA -:10852000F0F78C8405AFAA53A8FEDA3C93FD8EDDEC -:10853000F9630B92C01F695599DEF20DEBE163B44C -:108540008B07E76B371723E6757C574055191D924B -:10855000336C6B8A358CC7F9F398FE25521AFF3DB0 -:1085600029CAB71ECDA6431CD8F8CEC5BF2B52FCD6 -:10857000BFCE037846DBFCF04E8FFBAB6F38CA9260 -:1085800069FBCC28BE5F5E94C0E19DC3DE07EFFBB4 -:108590004EE345D37D18B5D4FC4EB727D0B414E2D2 -:1085A000FCD0EF6DC9F8CE8BB99EA2389196BB0B6B -:1085B000CDE5AE0A9A8FE147EB77D6F6865F92AEAD -:1085C0003238F63738100FBF6C50FD79948F0E3467 -:1085D000F8307FB041C334DA3012CB0F37F8312F87 -:1085E000DAF46C984FFAAF7F9014BBEEC2EF549D53 -:1085F0008CE1C37572E4ADF9808FDF8888AF15AF69 -:108600008E47FEDE349A8E3A86BD677332C6FEFE12 -:10861000E9F257D24A285F0DF9D1AFD34AC6C3EF6A -:1086200096B0F31770413AF61EEE7A25A0F993E062 -:108630007734C6343B86C2FBA4C15BC9589423FD82 -:10864000C589F0BB0B7B336CB47E9A94D7ECF807EA -:1086500080ABDE64E7AFE7E7331F9F6CD6AFE3BCC8 -:108660004CFF660AC5E3BC71F8097E5300FDAC39C6 -:10867000C6B907331E8954BFE1768AEBE6EFB3DF54 -:108680005F4854C7FBE1BDF7CD5EC3CEA9F7C5BEB9 -:10869000E7BE99FF0E44E2E1256817293EF63B103C -:1086A000290A7B0F8904934DEFEDCDE5FDCC06063D -:1086B0009AD0571FCFE6FD151D790EFB83DF9788F3 -:1086C000F5EF87F0DFC3D8CCF5D3743550EC4DED22 -:1086D0006D67D45BBFEB59776D21D10BF6430189F0 -:1086E00080BD04ED8A69BBD40F0302DCEF33CED723 -:1086F0003E0BF8CDEFFDDD937D02C3EB933C7D8A0D -:10870000FF4E49D4139807E3FB163C12DA0376CAEE -:108710003EBB06625274E48FF87E94F83BC501E7D5 -:10872000FC530FBCCFEEE5D93A1438BFB8D25B7C0E -:1087300013C45145A53E03F3F74E6F81FC839EFAA7 -:1087400087D8A3DDC537011FA4F3F706080400018D -:108750000E08AAE18F63FD43B34E65649FCCF22BF4 -:10876000BD37368732215F3F0FF808F28DB4BF7DE9 -:1087700049C121C0476EE186E6633742DE687F0368 -:10878000B6FF895765FE8F3B980DF64A4F5EA57977 -:108790004F4C5E6279E260A931BF9A237FC473D0E7 -:1087A000B507D83B5DA907660830CFD4FD3310FF6D -:1087B000E7D5B7BC2B348C878F60EB048B971BF409 -:1087C00030EEE1A6D983F77963F8619DD76CC7C411 -:1087D000DC27BC0FF0DDD31F8FAFCB36F69E4AF7F8 -:1087E0008FD8EFC60D037B5484B8B986692EDCA3FD -:1087F000A7FEC170125C3998D65FE3CD413A5EB5F1 -:108800003BFBCDA95A2F5FA7642977803E4EB5F870 -:1088100035D95C3F8F508B7F93482B370AC1B5F019 -:108820009E6C688FACE27D935D19284767B98E22F4 -:10883000F583315FCDEFBFCB2B836B47811E59C4CE -:10884000F46E5576A058A6DF573D978DBF0B67F0A5 -:108850005D5552246D9CBBF75CB791377E47E42190 -:10886000B5D509EFF218FB5AB5FB3764C13EFDC719 -:1088700087DE463B71496236C259D3765C81DF6937 -:10888000A96DA37C47BFFBD8D963C7A35FF287C894 -:10889000A06F02BEFED068C3CBDDFDD9552F52FDBF -:1088A000A6D385EA688303D39D7AFDD5E00A9CF0C0 -:1088B0002EB8C949F9E9F11C5D05FEEABCB71EF501 -:1088C000D8E38A3A0AF8AFD3FBC366E0E7AA24915B -:1088D000F3EB0F5FD6F3F87E3DCDEFB9B7EDA6BF52 -:1088E00068DF60A1D9FEA97BC48DFC41ED92DF0257 -:1088F0001FD56EB68560FDB339DAF1BE7327E81B6C -:10890000D45FE6FB991B05A60F4373581CFA72F758 -:10891000342BBE7491708CFDBD2491E9AB0A29847F -:10892000FB76155F7AB1FE2F1FC769BA0FDA771C85 -:1089300037D61BE354F78E837C52FDF661F4CF5F8C -:10894000BCDAB0AF75D4FF773EC5CF6138F574E8B7 -:10895000E741D9D027D4CFA47886E71E793E24F901 -:108960000879A947FFAC6D2EC904FAF6D613B37E79 -:10897000D2254AB79712783E747F73C9A438ED1395 -:108980002CED738CFC4FB17F2B3C0F3A7BF30EDA4E -:108990005EFA93BD270FF06DB059FA4B36C6DF86ED -:1089A000FD19FCB7C7BBFB6578EFE9A5A440F11042 -:1089B00066DF6820875B24157F87D1C0F31EBE3E2B -:1089C000557C798D09FFBD782F30959F6ED04CFB7B -:1089D000A18B172EC37B3F7BF83A564142EC3EDB1E -:1089E00023B9A67DD0FF0FC7D785A3B81F384AFE8D -:1089F000C6708C32E9815E38F24DE55F170E316941 -:108A0000766936EC53ADB1A19F90660B3972C06E9A -:108A1000FB5FECF71A203407E799A8616CDA57CEB0 -:108A200039609F07C6798E448E49E3409E746D0578 -:108A3000AC533F91D0AFA1E50E3919866ED5E1FD5B -:108A40002B2A95D85F4E75B08619F5E6776287AB0D -:108A5000A458A2E5E3D579B8EEE594DD5507F6FD17 -:108A60003677E1CF571393BCA27DB25A588AF6C726 -:108A70009AC4179B61DF383D81D9330279B1F95827 -:108A800046BC7A26AF2DF7BD7813C431B6AED4AE4E -:108A9000067F6EAB331C390CEBF93D6EFC3DAADC56 -:108AA00075E116F8BD0A71830DD74B3129BC6B2BCC -:108AB0009C177860841FEC8BAD60D740FB356E5CF3 -:108AC000FF5B1A42682FAFE2EBC0F6F5935438E72C -:108AD000DCE8969261BD6B91EB6F05B85EBAEF640E -:108AE000B3E33AD063FE96413CEFCB80754DCB713A -:108AF0008CE5F514195B576883C18534F2C3FF44D4 -:108B0000AD12D43327D10E6B742FAB043B8ED6BF7E -:108B1000ECA0787A3C99E385D7E7F4E8A593CDA05B -:108B200007C515BDF9123AEF1D3F637AEA09DA3F2E -:108B3000BC2B45E713827718BB4749E8872524C13A -:108B40006FC7D074740EFB9D5BAA17BDE8C7493888 -:108B50005F631F4919C57E0F1DDAC37A9390918315 -:108B6000FB98CA0CF65E83E271E3FD66E37756DD9F -:108B7000C4F8A7B37829DF677159DE4370AE5F8907 -:108B80009BE94E783721864F15CB7B0B1209CC071A -:108B90007B4B54CDE5BF49E4FB4A83D8EFAD0EB71C -:108BA00085D02EA35284E935248AF6D968D281F97A -:108BB00031E06DE6C2352C0D2F8E8D27BAC8E2BB91 -:108BC0000111ECC7B45B8D784CF0F544BADEBF966A -:108BD000C8E336FC778C536614E27E7D6612AB5F89 -:108BE00015C8BB0FECBC8D33A6619CC6B0EF8CF5ED -:108BF000D2B0DF16729857AB425C7BC1B0EB163A2D -:108C0000593E75B6FEE068886BB6530B341BEE2FE9 -:108C1000B3F86AF9E6E234B0CB161EBA15EDE44CAF -:108C200095D9658B36CE5082A3E1DEDA3CF4078A13 -:108C3000374C48847D84D54E7FE27585E867E2FB3A -:108C4000B903B5C7B6A65D3519E471AB8D1290CAEC -:108C5000FB4BB2EE1E0B7CB1210FEDCCAD09C1C6B2 -:108C600024DAEFD67FD6FCAB68FEA74EBDF0388C79 -:108C7000B33A81D5C3BB51C09B3DE712B6E1BBC936 -:108C8000FD8D6F3D97F052127B7FCAA8FF6F537E18 -:108C90007C7D0080000000001F8B080000000000A9 -:108CA00000FFBD7D0B7C94D595F8FD66BE796566A9 -:108CB00092C963F2220913C24B5E4E9E80224C126F -:108CC000C243B44C102A20E8F03490A7485DDCBAC7 -:108CD000FF0C043050B60657112BEA8462C5AABBBC -:108CE00041A31B35EA8080B8D66D44DAD216FD8FD9 -:108CF0004A1510488AB5D2FEDD65CF39F7DECC7C47 -:108D00009319F0B5FFB4FE3EEEF7DDE779DF73CEE1 -:108D1000BD73E912FC4D612C94A43056CAD8C151E0 -:108D20008CF58C618CA9DE2406CF4D066FD2E2341F -:108D3000C6FA7EA367BBE1F517666F92C3C6D82556 -:108D4000D12EFA79AA99B1A089B1B3CD6E161CC102 -:108D5000D8996633956B961F98C6A09F9A0E85B9D1 -:108D6000F2195BC5DA36633FAF3B9269DC55013DD2 -:108D70000B8E64F47709FE5BBDFC28D55FDDC9EB83 -:108D8000D7B20EAABF92314F073C6BF75A59D01C8D -:108D9000AE5FDF51AC691F4AD251BFD725FB063BFE -:108DA0009C8CDD5B3DFCBE2A789F565D62F6E1FA45 -:108DB000588EE313ABA8AF87F73AE6EB88B1AE77EE -:108DC000045CDE49828A4EACEDD0B132C6D63AE0C0 -:108DD0009F2EC61E50D87C6CB7F6F715192963C2B2 -:108DE000EDD62A9E0CC798F8706ABCA86781D48813 -:108DF000B2DA67C4F5355E34D2FBF30EB35F0763B6 -:108E00001EC9F43F702DAC7F26EB5319CC539F90B5 -:108E1000388E5DCD588B2571373E67BA0C7DA10821 -:108E200038303353717E33F82BF6EBC469479471B5 -:108E3000D83E40ED67D98EA90C4073C45E7303839E -:108E4000F737B090CA0A06CE0FFAFD28B2DF5923D1 -:108E5000B5E51BDDDAF2EC09DA32637E82D74F9A90 -:108E60009BCA4E1AC2FDFE04A6D611032EB70258A5 -:108E7000B17EED5E4BE064041EEB3B9235E5C6AE81 -:108E8000ACC0C988716AF11F59F05F135F779D58B4 -:108E9000F70746DFAD0EC05B3D0B1971DD40C146E3 -:108EA000EF58C6AC16E6457C1DD86FF1B012E8CF7E -:108EB000666EB7007C1BBBAB9525F0DE6A87EF3092 -:108EC0003F2796E16935F0FA8C05880EE08FDA3994 -:108ED000BD99ED5B15E413B7ABDAFECDE7DD00FF1E -:108EE000DD93024F953DAC2446ACA30ED6911E5E99 -:108EF000C739EB0765882F58CF6FECA5481746A6F2 -:108F00002485D7F3ADE1B55C0BAFC65D36A237184B -:108F1000E7BD4418A761A7CE6F84B2CEDC63447E60 -:108F2000B917E93C06DE721C4A4C3C6F433CC7E073 -:108F3000A7EDACFC3EE4C71CE41F18C7B6EE2765DE -:108F4000278B818FAA3717FAA0BE4D05FE86715474 -:108F5000F8BFA908C8D93B6D5532D0E9293BE7C312 -:108F60000D892E7AEE50BC0AE2355DE7C947FAD585 -:108F700027B843CCC1F1A366421960CBAEC162F9F8 -:108F8000BD1EE8EF21981BCB168409F078C8C2CB30 -:108F90002F39CAEFDD08E36E4AE6E50D3FBDB9D5CE -:108FA0003F09CA16599E43E5870C6D413DE0DDFF40 -:108FB00082C9F5443EB5F728585E3032F0044C4D76 -:108FC0003F8465235EA62642E720B7F42F9A769B5E -:108FD000A05ED0EEFB2784A75CFF39FBF13C362670 -:108FE000667F7E4D7F79DFAC3F18BF537775F8FB06 -:108FF000D4C49D413D6FE7C2762CA7E7033FF49FA1 -:10900000FEA2896D85E22306769B17DAD55D2C6377 -:10901000C10839D423F079B6D941725BBEAF43F9A8 -:109020003D06F9A987E4707D47AA46FE4AB95C7FF0 -:10903000F15A4D7F398E7CC257BDDA43F2ADFEE264 -:1090400064FA1E12F2F46C7326E989F8E30CD2C8B4 -:10905000F5F0381359B0F872E34CA2EF721CE6CB6E -:1090600022B9BD06E70C24A43782BC87712E0C758B -:1090700025255F469FD976029145AC679B1A3463DC -:10908000FFDBDC071CBE18FC20E544B8BD51DB1E2D -:10909000F4231B81F4ED6348B7FFAC7ACC91FAD48A -:1090A00066F038506FA8F68A232E37344D7E6486DA -:1090B0000A286951393D7FD9B681E8D16E701F41C8 -:1090C000FCDAED3A971FBEAFB7E93C48272D0E7387 -:1090D00000F1BD51B9C1817243F66B07318FF3B80E -:1090E000601B427A3DDE7AD58B89540F669219A9AE -:1090F0001FFFF7C683C5170F1C8FBD31F1880BFA10 -:10910000574B746E0BE00B91FA71041D44F763DF4B -:10911000A9C69C77743D09FFB8F836841211FEE7A2 -:109120006DBA198118F32E4D56BE9B9E5A1425DF39 -:10913000937F3B3C88ED95D00F0AF249FE9626A31B -:10914000FC2DBC9058E922399FEEB573B185E3B68A -:10915000D88E9A7DA48F98ED13D9BF3E3EFD49B8B5 -:1091600018DEAA64881F6004867AE34A70B02B4137 -:109170002FE29715AA0CE5D3403A6FA7F9F4D777F9 -:1091800043E711EB6F51DD0EA46BFD751E33CA99D9 -:10919000F58E39E6109437AAAED9F92087FADE02A7 -:1091A0007B12D6B729ADC81C8B8F5AC16EC4F92D5E -:1091B0004DD669D6239F661DE7DFE8F75B92B99E1F -:1091C00068DD3FB1C753129F7E40D279518F9BCB50 -:1091D00054C756589FDEC0E76B896307CA7EE3C158 -:1091E0006BCB7E0BC96975A83980F644F4789B5423 -:1091F000778F07BE6F82F9F8B19CC3C7DF54A23ADC -:109200007643D71657023347D437384B08FE176CCE -:10921000694C0FDF37213DC6989784D3BCE4EF68D3 -:109220003FF9A2E832F7B7C3D9100D5DB6C6A2CB9D -:1092300079A8374BF9FC993972FE4393BE8E7C8C2A -:10924000A69BB249CC837C9701CF76586FA7CA669C -:10925000EC437D80B6D64498DFCD36E600993E39A2 -:10926000B57C6732ACB7ACE78091213F743A691D99 -:1092700075A27DF4B8A6148E3F538A839E49C73DDC -:109280004F4F01F876F624B814F8D49902FA300654 -:109290007C8F08BC33D6C69F6A681CF28FAC5FB661 -:1092A000887976C3F350026B3583BDB24FC807C6C9 -:1092B000EEE74F151817C699FDCAE8DD642F8AF549 -:1092C0001F02B580F5D3D343E314FD77C0DB5E58AE -:1092D0007D04DEEACD21C2DBDB46DF6B089FC6E3FF -:1092E000A1742C771E3D9387F870B670FBB5EF25FF -:1092F0006B00E96E207ED6D3FCEA2E0E62FEE28180 -:1093000078AB5383A45FEB2EE6D17758B7DF9C127E -:10931000FE3E1B6C8609B02E66E67042F8C4C2475A -:10932000BBE06B890F50EBA3ED021F08A78FC43E73 -:10933000A71FEF4EE36606783F6BE6EF996724DFE1 -:1093400087097DFE51425E00F7331F0D07CE467A36 -:10935000505DE9917AA7CEE2B96F3EAC9BBDAB6799 -:109360004FC06359A5AD15EDAB65264F12DA5DCB45 -:10937000DED32BEBF30984C4072B043CCF32F75D1B -:10938000883FFF368BE309C29F76FF97BFA3BCF8E7 -:109390001D68BFA24BEF46937169A5CD8FFD96F571 -:1093A000543C6D87F72B5BAD2E06FD2E9BE2FE0431 -:1093B000EDBD65F7595C1BF271BF38A43C0BFA5D3B -:1093C000FB60BE03E581759D37D3EC0693E07EEB31 -:1093D0004C2BE06D93B264895208AC7D7FCA1615A0 -:1093E000F0ACFE57E56716285F757FC116F3758CE4 -:1093F000BD82B21CED59FFD09968DFFE12A746F678 -:109400002EB76F7F794427CAC55BA6820A18E5ECA0 -:10941000D4D960CE2B538AB79861FCF4144FA10EB7 -:10942000C65B93326126F6B7F4BEB17FDD09DF7704 -:10943000A4CC9AA9E613DE447BEFCCCAA1D06E92ED -:109440002CCFB354427F695616B6A72700BF0F0929 -:109450008F8FF67767BFFDBD60E6D41CC04B4553C8 -:10946000A50AFDBF9E72DB9631573136FE817287A9 -:1094700007C63F98B264A615F0DF6994F5976DF1C1 -:10948000C0589DCCF78601BEFFF1FEBA9966A89F31 -:1094900096EA2D74C0FA53CDF76F9991FB1DF865CC -:1094A000A412BD4F2C487112DF1C4690E6ADEB3381 -:1094B00072FD2AF83D87D3717F792494ED11E54C34 -:1094C0005EEEDC105B7E9C4EE572B93321F6778F41 -:1094D000904B00EFA00EE9B3CB1A18961F9627C049 -:1094E0004FE609C45FDBB93C01BE9A63273E8ED9C3 -:1094F000DF37E55F803BF5D3A97AACE8BF90720D0A -:109500006666C571BE4C7669E47559CF5292B7BF95 -:109510004A157CEBE2F071566AE50A33F70C47B85E -:10952000C8768BC53AF3474BFF52D088FCB9D6E2D8 -:10953000C9C0F9ACDD579EC12E6387D75D2CD7F823 -:109540004BC2EB984AEF07F40BFDB944FFEE315FD5 -:10955000075EC95780571A7DBFD23AC3FD69FD3BEC -:1095600003FBE37E9E017AC5187B9E1B53B85E41C8 -:10957000F8EB22E4DA4A215F416A913D7EFEC5ABF9 -:10958000766FCD8F1C7703F50FF87D7A0AEE2F41A9 -:10959000BEA21C2B533DB3B07E594F8A03ED79A078 -:1095A000B78D82DE54A43789E7CE94A6725AEF763F -:1095B000C5B13B861DF81339AF36C583F649C622BF -:1095C0009F7E49C4FCA4FC87FE3B45FF259C9E1F53 -:1095D000EDA7E7C5C83FC22FC4DC40DF6307CE5FFD -:1095E000C136CE08FDF5822580F39170FBB6F42FCD -:1095F000ED87BAB87A2A91DA651C0F26BAA09E21A7 -:10960000C5C5F9B9E3E3C46B515F75E999E2E2EBD3 -:1096100046B95126E5A4BFE748854A764C582EBB8B -:10962000C89E917233683687EBDFBFBD67C646942C -:10963000AB26BE2F4FD383142F0ACFE3E514AE2FF2 -:1096400027F89827961D7824D92EE508ADE3E17513 -:1096500095EC63589F5DE8D709213FF9B39E4C66AE -:10966000C23EE1F090FA7BB629F4AFDC4FA6A547E5 -:1096700059063BA5415710EE1FBFCF89A0FB63825F -:109680000EA2F1F35DE513C0C18F70484DE172C8C1 -:10969000096505ED0B15F417C0FF5CB5CDBD353F71 -:1096A00062DE362E8F9D7A1D976357E08BB454FE91 -:1096B000BDEF253BF173181EDC8EF92F01F7761DE7 -:1096C000ABC17DC1211DF009D2A28DAFF3FC8B5936 -:1096D000D4EFE7293AB9FEEF452EB71B613CCED750 -:1096E000643FD6BF3CA85D3B7FDEDFDC544E8F6518 -:1096F000C73D8568C70CF3DADCB85F28EB9973C007 -:1097000000E5E1DD8A036B4B3A1FDEC1F914A84B7B -:10971000C0E5AD6722FBB5A5723AFABED631FC387A -:10972000A757C4CBE2083ECD4DB57178C1FA4C08BD -:109730004F552B47E5F3FB9B87F78001D65B07F07E -:1097400040B12DE1D6D9B1648305F9F83873231FF0 -:109750009FEF58A21B8B78DDC9C8BEEB970F0FF0A7 -:1097600075487B14E8B203E9F2EAD45C1A6FD87149 -:109770008F750C7C1F867613FA953BEC01DC574CF9 -:109780004EF5CD4D4578CEEDAB64204A1AAC4DEB8D -:109790002D11EFFBEB77417DA2639F7E2CCEF3363C -:1097A000C6B6BAC2EB81A9FAD11F5A6F043E2DA0EA -:1097B0007210E1D669E4F5FB16338ACF34E8FB8CEE -:1097C000F81DF4F72CA2CFA3BA14C42FEE9BD06ED1 -:1097D000AED37B7314DCD76798DCA807601F42F414 -:1097E0007EC8C2540BF4FF263C514E57E9EFD88F88 -:1097F000F0AA2A50DC2D24AEDA85DC6041DC37CDBE -:109800009E62257A645FDD39B41AF5BF95E309FAE3 -:10981000318B7ECCE6A230FFFD3AEF2ADAFF48FD1D -:10982000764851A89F43D78DDEDD12B12FC2FE507E -:10983000FE1F52AA73EE40FA17FB3AB20FD3C27A58 -:1098400017ED95225B24DEFD627EA13CA4A3487B3C -:1098500014EDD37E7BD6DFB1653AC8D9F1333A82B5 -:109860003A0752D1F333FF01D65105F6AC05E0704B -:109870005B2A973387F2FDFA449CDF30583FBC3AAD -:109880009CE01BD3640B8F932EFC0FE946EE2F4810 -:109890004FE0CFBFA7723BE727695C1EFE218D9783 -:1098A000D31363FB2BBE10F55413971F5BCBB9FC8E -:1098B0008FAEB741F4FBADEDDE318A667F0F76EFF8 -:1098C00086546EF71AB95F88C713960AFA063B8763 -:1098D000F014B6AB783C50DAA15FF4CCA3F272F38B -:1098E0007BD9E8BFBFED9FE6DD87F4B6F2377AF2A9 -:1098F000579C14F18295C9BEF464DCBF27C4F6AB53 -:109900003C27D675BA99911FF8538C1B82EC3D8980 -:10991000714328AFDAF9E034E4BFD52C40FEE0E52E -:109920003B37515C707940612E05F7695EEE271672 -:10993000F858BD47AFF14BDFAE361993C784E977CE -:10994000459B366E58B3AB5853FEF6F669250B446B -:10995000C8A1B0FC9946EFA3FB95F41E6DA77ED479 -:10996000ECD2F8C397EE1C46EB97F5973137AD77FD -:10997000596B8166DEAC95F349BCF949BA45BBD455 -:109980001F739E46CDFB8F00FEFE08FFFFD25343A0 -:10999000691E2DA9BEFF40BA09CFC3CAFC1ABFDA9F -:1099A00024C727B05666E17E49A023FFE5EC81502D -:1099B0002AA7FF6F0FF7D171F605E3FEBFEE0BCAC2 -:1099C000267139CCDA14360C1EE3A76AEDB4BFA0B9 -:1099D000BE2BC5A795EB6B61472D5FA4AD7751D426 -:1099E000BB28EA5DC9BF12699F290528D7787F0D7A -:1099F000828FF3CF1C35BAA0DEF8346EC716393D1E -:109A00009750EF6CB3248E437FCA364B5E00F552FD -:109A1000FFFABA381D6D33483F8A3B03E1D6FE5F3B -:109A200077B6A888C77DB00F007958FEE841168A3E -:109A3000905337AE533CCB01DE7621EFEADC7C7DE0 -:109A400075EEA07128F4935DC7E795D3B15F5123FC -:109A5000DAE5D4087F5F9A41B3CFCCC1324E258D71 -:109A6000CBE39C9AA03214EA65EFDAA3A8D85F870B -:109A7000427A33BB0900134157D925DCBEB9B1A4E2 -:109A80005D5936260C87565DF51807E0A735DDEAE7 -:109A9000467D738FD337240DE7792218C4EDFCF887 -:109AA000133D2ADAEF3F757A0AD29C6138B8F48EFA -:109AB0006CD4A7D6137C9E6DFDFB63AE6728A24DC8 -:109AC000FEABDDDC9ED1B3238CDB87A4AFD2378C19 -:109AD00024BD27E7979E22F4453AF33D67A3FAADEC -:109AE0008CF0C9683DE91B86EFE6F62CC7775581F7 -:109AF000770FBEAFCAB8AAA805DE176C0BAA4BA198 -:109B0000DDCBBB62FB83CB853E81754CC2F5C9754D -:109B10005C492EC87A86387E0AC90FD619B1F71F5C -:109B200030227D2F7F346D21CEB76EA39199943072 -:109B3000FC7FEAF4CEC6F96477B42B081BE9DF9307 -:109B4000E34AFF1D7E47FEFCC828F996D35F5CFE02 -:109B50005FA7F72C8F94671B8D8427693F87E7C722 -:109B6000EDFDD5695CCFBEEAF42EC1F934746D27E2 -:109B70007FCFAA3D1F1A63F9ABA3F9E24A70546A7A -:109B8000F8BEA06EBE3980EB2F7F54253AA8DD6861 -:109B9000A43859DD33FBB89FE71EE6463951D7B1EB -:109BA0004F590EE3D63EB34F591101D74175010508 -:109BB000E733C22EF990CBAF68BA473F32DA2D8730 -:109BC0002D5C4E9C2DB7F91580EB5983AF0EEB9DA4 -:109BD000CDB2BAFDF9613CBCB96FFA11CC37B03FD8 -:109BE000670AE2B355B73BD30CF55A4719DD485F16 -:109BF0003F75FA36235C52546F27B64F4EB3BBD72E -:109C0000435B978915A1BCFBBA70181F4527E3EF8A -:109C1000E1FCD3857288DB9145C83F8134BBB4A792 -:109C200048AE1D36F0753CC7F87CFF9EEA7990E897 -:109C3000F8480A8D9B5D1754D09F9D7FE639926B43 -:109C4000B2FF309D791E89E4DF2BCFB3C388F45671 -:109C50002BE450F9A37B948F23E6FD4B30F4916EF7 -:109C6000B29F01BAB4D1F7FD33D3A83E33B9F0BDEA -:109C700042ED6AE1FB8A087923D71143EEECC3F584 -:109C8000D84EF41CE47227C8FD8D62BED1F87C1555 -:109C9000E51F7C9A06EA99DE1BFD23312E7A78486F -:109CA00002F527E54034DFBE2AE81CE5A5CE46FED6 -:109CB0005AB22BE5FC64BD2267C5FE3482430FC156 -:109CC000A17E974AEBA9327A87DE11C10FBF16FD3C -:109CD0001DB8F90323CAFD07FEFD5DA2C7FA36854C -:109CE000E2F1ACED5DE33CD447FEA7F46867CEE259 -:109CF0002601DBF1C2BB84A7599D5C2ED777EE53BA -:109D000097D9C2749A7FE6C0AD4867F51D2686FBD9 -:109D100022A0BFDF207CA2E954C247CADD78F8B494 -:109D2000CEE07294F98DE44785FD543EFA29A4DC17 -:109D3000FE7BAA4EF809F8FB0B69BC1CA61FDFA727 -:109D4000088FB0DCB5105FE49F293A60C67DB85B30 -:109D5000213F7F5A258767E4BCAAC7C6979BCE548C -:109D6000A137D450DE1C7B58BEF7CB7FD1FE0B81D0 -:109D70006F781FE4EFD910D4F372FED1F8CB77726D -:109D80007D1B83CEFE1BD711ADDFA43D20E9E6C9C4 -:109D90005DAA468FD89D46EACF0E1B739CC78E7274 -:109DA0001ECFD861E0FA6CC77A7300E5C99B0B78C7 -:109DB0005E997DA13188CF43BAA575F8FD50361F55 -:109DC000BF55A75B83E5D60D36D64278F5243A4BCE -:109DD000917E1219978F5C1E3EF03C9767757E5BF3 -:109DE00080C13FEB7C739753DC39CDE2C6B833F3C7 -:109DF0001D34CEB30FA42BD773FB8D2E783FAB83CE -:109E0000F39FC403C853A22FC90F12AE617872B872 -:109E10004B7E92F8F8BBF46703BD7CA7BCAA3DDA81 -:109E200078DCDB46DFD54EBECF3A6C70A19F86C78B -:109E300017E2D16FEDBAB7B34F821DB53AF32D7A61 -:109E40004ABE85FDAC86BF2709BC1738B9BEAF74C2 -:109E500072BAA92DE920BEAC3DD944FC6C9BC1E58A -:109E60009AED84561E33F6CF62BDDBA85D95B563CF -:109E70001AE677543DAE3870BF1F4F6EDEAEF0FC71 -:109E8000B84F77BD9188F972EC2BB0F2319E62E148 -:109E9000EB9DEBE472E2EC5E0038D17B93F172F65D -:109EA000FB95FA63C1630AC2B356C0FAEC3395134B -:109EB000FF847EECBD49EE61B0E4CF9EB9E9EE3F90 -:109EC000C1BCCFEE99E246F7655A8B97E8A7CF69F8 -:109ED00071E37E03C4F70CF417AEEF7823F15A68F0 -:109EE00077FAE9AB8B506ED78A799E795EBF0EE127 -:109EF000B2E1C97F9B8CDF6B034AAA09C7D9FBF883 -:109F00007F6763BEEA9E46F217B53CFDBA11F317B0 -:109F1000748176FE7E6F9203EB9DFEF9F6C908EF21 -:109F2000968E16FA7EE6E7ED543EF0E4BFBDF67776 -:109F3000F4E37813DD58EFCCF3FB092F753E95F26F -:109F4000DBE2D1F58E7DFBB9BC443D8F7C309FCBED -:109F50003149D7927E4F3F79DBC448BD21DFB70A34 -:109F60007F4E6B02D7239F09FEADADE0F1CECF9EB1 -:109F7000B5CCA7FD8131341CF7C57563385DDC2D88 -:109F8000E051D77187A1C146EDA99FDF02DFE373DE -:109F90002CD0E72723298564CF25CAD7F957AA0FE4 -:109FA000F526A0BFE7E6451F2A381FEB9826432D6C -:109FB000CDF369FE1D561DF9BD6C6D6C3FFBBF38BE -:109FC0006DC22EE07C90DD599DE3223960720F8BCB -:109FD000B087B36B7C2D1827BE7EADCFAD073CBEDE -:109FE0007CEAE8B441507E72A4524CF8D72B5CCF87 -:109FF000F96D344E3DFAC1818F760B3E497730F5CD -:10A000001A9203DC1F50A532D5467EAA3E9213F564 -:10A01000AD420FEE117E6E735FDE4D766A67BB2632 -:10A02000621F06ED6C362AF7E5FD10F34A67F8E784 -:10A0300093DE711969BE67A43C607EF27B4A7E8B19 -:10A04000F61BA1BCC1FCD1579DE55D281FE5333D42 -:10A050008EBFE4EFE2FBB8744F17CA15B63755A3AD -:10A060000FE2C99503379FE77AFB950F890E1B9086 -:10A070000E717CDF498DDE5E4EC215E8F0A50F89BA -:10A080000E977771F9DAD0556EC4FDD40EE1D76919 -:10A0900010F4847484FBE8BF3A93699C86C9A1E1FB -:10A0A00028A7CE0BBA3BFF12A7B7433A1DF9010E02 -:10A0B000ED1EDDDEA20CD48F4A8D97F0DD00F8E6B0 -:10A0C00076F3DAA36867D5D73037F26B43A7E0079A -:10A0D000B07B11BE0D5DD5CBB1BF416933C9DF0D7A -:10A0E00076C9B441506EA863A5C86FD9BB2A5E4239 -:10A0F000BA605D7C3F9E5D03F62CD24D5ABD5B9FDE -:10A100008F7A8FDBBDD78F2CA3F63B725D14E7F2FD -:10A1100057318AF3EF40FB19F55DD6686E3FFB3689 -:10A1200092DDC55C09E437653E750DD66FF02F6290 -:10A1300094D711CDC72F29B40F680858291F685626 -:10A1400017B77F1ABA381F9F93F0914F43CFADE4F2 -:10A150008F7FC1C4FC11FED0375F9ACEF5EC8B2601 -:10A16000D2B39F357BD8C7B0A0B785BC9770AC6D14 -:10A17000CBD721DD32769309E7B14CCCA3CDC0F526 -:10A1800046B2D00305DBF83CD474E1774CD789A7FD -:10A19000519BE7E2F0937FE19C188FC8225DE8397C -:10A1A00018BA7E7990F8A4EE19DE5F9AC9537867E1 -:10A1B00004BD4AFB289A1E0BC4B8D9BB0E2A284CF2 -:10A1C000B277CDD1F0F9F5352CD808EBBC7E972EBF -:10A1D00038651CD94D0B499EAF37B258F92A23D2A6 -:10A1E000B9FD5695EA2D44BF76D5CD3677A43FB953 -:10A1F0002AC1A3B3A01D5724FDD8DE128C1B9D4A93 -:10A20000B7BB116FE3D25DD20ED3D85B03F7DFDCAF -:10A210000EBCA1CD3F0EF71F81F509F329AE09DA77 -:10A220008DFCDC0E688FFBF7DDD7FE9CEFDF5BB8A3 -:10A23000FF020407C999546F09FA8F9D05DEB55CCA -:10A240003FD9DDB1D6F3AA93AFE7C0CDB716E23E52 -:10A25000B161AE8DF8E1815794A59CDE4011E2BE5C -:10A26000DAC7F983017F3CE1227A243BAAA1C91B0A -:10A27000884D8F9C5F1AC0AE423B1BE8710DB793AF -:10A280006D8CF313A74BB9BF47B91569CF4A3E8D03 -:10A29000E67B49BFFD7CFF35F9FDBC81F3E37980A6 -:10A2A00003D27B3F9DBFCCE97CEB7AE047F8BE153B -:10A2B000F8B12542FE47EF7F709EB81F90F2F61E60 -:10A2C000A777513ACAA1DD6F6DC650AB948F0D2FA1 -:10A2D0006F197E39BBCB8C95A15F33F06B24FD6089 -:10A2E0008CD65E444F3FEA09EBBAD8FE8FBBD26DE5 -:10A2F000DFCD3F3F302FE5AEF4D2817929E9A87355 -:10A30000106FBBAD01B48FA51F297A3E4B049F4946 -:10A310007CCAFD03C621B0FEFD82EF37897A8F88A3 -:10A3200067C4BE84F8C1A5F37D4879F671F4916CD9 -:10A33000F77DF9B5E438522F46D38D8CA3E07AAA85 -:10A34000C7C4AFD7B65FECCFA2E8F829C15F0B80D6 -:10A350003770DE6D86E017C48F77D819E513F8994A -:10A360002715E371AF8DE07C34B26F38B6B766FA6B -:10A37000BE44BA927E5D7C8F71AA5A11BFACDD6B70 -:10A3800008449E7FB93783D138BD76B35F0FFC9107 -:10A390009BE9DB87EDFD15CC1D443DF38F168A2B21 -:10A3A00081815B8AF2A691851211CEEF25FB5E209A -:10A3B000FAD5F70C47BFE33925340EDF9F10FEDADC -:10A3C00013C25FFB7ED77BCFBE02AD17BF726EF1AB -:10A3D0008F91CE5EB4E4217D9CB0F4E7BF25A1DD72 -:10A3E0007D81B9922E770E699159EF5523FC67272D -:10A3F000ECB1FD7F6F0B3C378A782B5319EDC3B757 -:10A400006770F9193EBFC4E3ADEFEBB4FE37F91C3A -:10A4100093C1E1DF19E71C506106DFD7740EE1FC40 -:10A42000D8D7AE50BCAF66DDFA3FEB412ED4ACB509 -:10A4300007E9099FD18EAB71F8833A289F3070B934 -:10A44000047F73CD6561FD07F5D449C8337E07C528 -:10A45000BF960AFDB5ACE9CDBFA15FA14665E6494F -:10A460004518C7F21E1E049F3EB52D4F44F1BFF2A2 -:10A470004777A6A37ECA58D426F2C1A63AD0FE5585 -:10A480003C37E82F592F676FA96427131D00DE1E84 -:10A49000CCF0F6221F2F4AE27EC145775A03FE0810 -:10A4A00079B857F06134FD7C10E7BCCD97191501E0 -:10A4B000EC6F61AAF76FD4EF9DE73472EDBC12FA2E -:10A4C000C523485F77D8DD4FF0EEF222F363D20563 -:10A4D000FC6B310E04A2B1B7B067F8BA7CA4E3BE3E -:10A4E000BCDFA15FABDBE4F0BBF0BB91BECB76F190 -:10A4F000E241F1E3402E23D247C34585E86169F785 -:10A500009BC751AE37A821A293A5661BE1B1E1A27A -:10A51000CAE9A9D5703624DB03EED7A47AD232601B -:10A520009EFE7B2725533C09F889C3172A459CE3E7 -:10A53000F832C3372803E0F79035F136DC7F5D3021 -:10A54000BB92308FADD108F4703575E73547D843ED -:10A550002CC7AEA583EEB7FE86F35A6EF61951AF3F -:10A56000AFF034D179B14549C152C79848BC4FD2F8 -:10A570005F1AFDF5F17E49C897F78D3C6F64209D09 -:10A58000733C6CCF10F5B239BFBC9FC76A9EC3E75E -:10A59000287842BBF787887291280F17F5D279790E -:10A5A0009AE097F7C7F17AD1E32C15E37C99E1990A -:10A5B0008C7082764123D2C76B163A67C44A40FE3C -:10A5C000A1BC5B934B762CC8B96908771827984CC7 -:10A5D000F54CA4675813C841C0676FA98BE0B3B5A9 -:10A5E0001CE805E341AF9A281E24F12BF11A8DCF08 -:10A5F0008519CA77CB4F1F18BF5E98513A307ECD70 -:10A60000D850C217D14B8CF31FF1F0F56B3BC70349 -:10A61000F0EBF20CD283C1B1917CB349C051CAB501 -:10A62000F713B478FD3C9DE3A15ED4BB84761FDABA -:10A63000D1EE3EE2BFF75378FDB402AE97A45DFEC3 -:10A640004F022E5FA66B9F52CF44FBD1BF14F2E2A4 -:10A65000CB74EE4707BCDE8DF395FA09E44C301954 -:10A66000F878D1EB2692336C631FE5D540BDFF83AC -:10A67000F05A64EABB3515F4CA0FC1DE311651BB7E -:10A680004B284706ECEFC748BAB033D4DBAD190E00 -:10A690006E1F94F4F1B8D748BEAEA50CE48772657E -:10A6A000FC630C210BE4F06B22BF42C1BCAE146210 -:10A6B0006717F60770FF978CD230DCA3C73B21E801 -:10A6C000E0D10C4525BC15B242C4DBADEF7E6E5F18 -:10A6D0000C5D9E13E765934DBE76ECE7ECDD6F9164 -:10A6E0009D7EC2181CDE668BF1DD187CEC2125FCFA -:10A6F000FDB6A7F47EE3D5987F7EF6C19B61DD4B66 -:10A700007BF46E1C72E93D5FBC331EEDEC1E03C58D -:10A710006B40DF6F5371DE4DDCAE3CA1D3D2C1671D -:10A720007769F73DAF0B7A90E772A5DC91FA7C155B -:10A730007373799390B81BCB1FDD713B9DCB5DCEBE -:10A74000BC873D00F7D36B66925D7C3BF3515ECFD7 -:10A75000B256ED39DB156DDAF2ED3B079CC32539B6 -:10A76000BC2A10FD5EF8A52B63EBFBF3822E3F3372 -:10A770008AF8FD7A53CCF8FDEF85FC09C7D9FBB404 -:10A78000F1FB572F1FBF6F8C8ADF87ED88E8F83DFC -:10A79000EFF713616F60BF9171FCCF2A62AFE3A343 -:10A7A0000C69B75835F9199F0CB05B12E97BE3458A -:10A7B0004B9CF9D8E8FD672B638FD3D73F8E365F6C -:10A7C00020DC9EE709C8FDB5A493C68B59A4676534 -:10A7D00059DAC7E17639F43DFABCBAF46F4BBEF8EA -:10A7E0005861E62CF2476D1776BC9BF2333F46BBAF -:10A7F00008F972BAEBB5104C71D98F270E578784C0 -:10A80000F9267A1D405F674211F2D898694F23FDFF -:10A81000EB666E3A9727E8FED6BBABE87CCFFFBD70 -:10A82000A73223326E2AF7530D46698FD934FA9630 -:10A8300045E9E3655D6F911D06F6D770143E7F7A9A -:10A84000F56ED2C32B99371DE9BDF7D511746EE5AE -:10A85000DBEA61399F9BFC4B0C3CBF358DEC8739A3 -:10A86000623E3775733B5067F618681C0F7339D218 -:10A87000698BCDE70B425485F275FDF347E71D6305 -:10A8800093C4FC156C0FF0BD4E3CD9525F26CEDB55 -:10A8900084E3EA310D269089CF96896E173EA7286A -:10A8A0005E95CF83E3791A6BCAC1FA3A7348CFD762 -:10A8B000093348C7F6FDF0A2B25D9437CEBD70EB08 -:10A8C0000A7C6FB3933C318A794CCF04B988FC6D14 -:10A8D00066665CB7C9163C4DF133F1F457B8888F02 -:10A8E000FD4318F9411258079D3FB5D9CEF971B112 -:10A8F0000EE650B06C715C08E27EE29CC3E6C7F3E2 -:10A90000C4202F6765A23F5FF9D54AC40BC867EE24 -:10A91000178AF75D0DF2F31142DEA588F9B50879C3 -:10A9200097C5DC8AB8C780E4DDFDF69537E07E2662 -:10A930008D79F7A3BC7B387106C5FD32988FE693FD -:10A940003A43D5C82DA7575BCE98AF46CB3B05E71A -:10A9500097E5D3BE37B3139497A404BD9997526972 -:10A960001F3612FD310621378E59783EC26631CF2F -:10A970003B3353886E8E59785EC2B7B65BDCDA7DA6 -:10A980007D430A3FBF7F3EDD6CC6F1C08EB913E147 -:10A990000776CC077E16CEDF2C9CD24179029B6FC6 -:10A9A00054DC1BE0FD66BB6BBD0AA4EB9FA9707F66 -:10A9B0008FEA28C77C9CF63C871BF3441B45BEF7F7 -:10A9C000668BA3F619F2639A783DD6B719E396ED34 -:10A9D0005B1D0EAC9756D937CD88FBAA15CCB19B21 -:10A9E000C5A0F7AF808F60BE3FC732E04911F46366 -:10A9F0003DE2BA85D620BEEFC17F17F0F29432DC7B -:10AA0000BFF2BF82EE423A77C93C7AD2978DDD859C -:10AA10006FD860BC82B985E4AFF756F2B82F1372D5 -:10AA200060BC1C57F0D9B561BAA7EF85A23CB45BF6 -:10AA3000F87FD34C3CAEEB8021CAC49143AC9FC697 -:10AA4000F9C1CDE41FE7D36B58F80FFBAB0CF74F00 -:10AA500072696AF87398EF60A822B3BBA50EEA8DFD -:10AA60005783FB91AFAF15CF42F13C547E23E9E50C -:10AA70001E9DCD65D4713E3717A0ABC3AB47B894CC -:10AA800039B6B4603FD729417AE6CDD8DE82D39F6C -:10AA900023FC4CC999C6009E376B99007826BFC825 -:10AAA0009F0FA3FF5AFF2FAC18F174CC20F59E27FF -:10AAB00089E7FFB9683DD50E3E5997CE337B2EC24C -:10AAC000F9283FCFC6D0748BF8FE97A9554997D780 -:10AAD000BB3C0F30254BCFE5E30C1E876D9C6FA66A -:10AAE000BCE546710F03537DF93F8CF0AFC8B8C584 -:10AAF000BB06367F5F8CFD464A16B707E6DCC0FD15 -:10AB0000C28D221F477E4FCCE27EB2BF644E7B37A0 -:10AB100093EC3D1E6FFD9D945F23D948945F11F225 -:10AB2000E58F245FCADF8E277FB4DF85FC99E72994 -:10AB300036D0BE40C82129EFBD22EF6801F31810BE -:10AB40004F3DE21E95A3E5AB480EDDCC7CF4FEF74D -:10AB5000153CFF0008D380FDDD34436B3FCDF36A25 -:10AB6000CB37CF8FB6AF383EE4B80B7CDAEF73A4A7 -:10AB70009D3C436B272FFA87AF9249CF67FCA2FE1B -:10AB8000D2E0703E5163543E5183C8276AEC2A3CA0 -:10AB90009416914FD4D8CDF3891ABAAE944FC4ED20 -:10ABA00029AF29B01FE324DE5AD294EC0D917F72B5 -:10ABB00010F34F8AC2746EAFB0F33C0CE6A1BCA296 -:10ABC0001C8795CE5DB4EA8AC88FDB9A68D7F8DD1A -:10ABD000B7AE7755613DE9BF95F9434837B1F6C344 -:10ABE000D9597C5FB343E17E74FF0233ED3B9D0591 -:10ABF0005E4D5CC1A967C7D1AFF86EA64BD6273FA3 -:10AC0000C90E832FAB189E0185D17989FEF67AB6DD -:10AC100091FC905172CA99EAA6388033692CF9F5F3 -:10AC2000E77517923F92D92CEE614AB8FF7973DB32 -:10AC300055CCEB69EC6E5797DBC27437364BEC435F -:10AC4000ACCC8AF4DAEFD77BCE447EBD6493B730C8 -:10AC50000BDAD71983E4BF8BA0577A1F4F5FDE2E24 -:10AC6000E8C550E15DB002E6D7FB8ED18DFB6B0AE3 -:10AC7000CC41FFCFBF944C7E49750E233DB5B19CAE -:10AC8000CB935EF493C13A3E4DE6F7FA6CAC66A402 -:10AC90005FCFA74C233A5EC502873DE847DB0574CA -:10ACA0001879CFD21E6DB98E7590FEA97B66003DD6 -:10ACB000937C94F2B89EB9F4068C1B746ADBB3A142 -:10ACC0005A395C28F447F1BCA92D98FF50ACE3F247 -:10ACD000912D770F9A43FBF5458E4F2C28727FA15B -:10ACE0005CCEAEEBB59FD273FEE77AA154F41FADF4 -:10ACF000BF4A853D3719E417EE6FA57D06F5A97C9F -:10AD000050D7ADCFD485E75922DA49BB50EA0B8939 -:10AD1000AFF2098CE179B5BBB2847C1AC28620BE41 -:10AD2000A17FE21305375829D4BF1FF785D78AF1D1 -:10AD3000801EFCA8BFFD3A7300E96BB3D244FAD27F -:10AD40008CF63F3CB72A3ED20BFF5EE3D7237D4C07 -:10AD5000644D37DD00F526997BAC28B7804EFE3177 -:10AD6000927E5A58306F9FA2A123FA7E36F9ED9851 -:10AD70007424F55AF0F7DC9E99C5BC74CF93E70FA5 -:10AD8000DCEE3AA8F07D26D89F07D1EE7A5B3793A8 -:10AD9000E864262C03EB5539B4F89F9EA92D47DFB4 -:10ADA0000FC5D05A284374487806549C4FF4BD51BF -:10ADB0001E29F79856EEE5B3AF78DEF896C33F420A -:10ADC000FF83751D1B89F60E58AAC48FD1F4B027D6 -:10ADD000EB7B8FB7ECC98A116FE9157EE56B58687C -:10ADE000E533CA407A3B7F689D3E33822E257FBC87 -:10ADF0006CE07913CAEB3CAE35C1CCC604112E25EC -:10AE0000DCFF28F9E31AA4D39430FD9589F787A4D1 -:10AE10007C19CC0623BD5DD76509EA013F85A2BF39 -:10AE20006B90FE8AC2F689DC77B44C184067F998BB -:10AE3000170EF64C01D295B44F8A958E163CE7FD5D -:10AE4000FC4BF7B6E07C23E8EA2D84C35905E88A79 -:10AE5000FC6A03F4ADF67B14DD49FC4B7BBA9C35F0 -:10AE6000D17E676E02D7B3C1EADB49CF82B824BA7C -:10AE70007B730EA7BB2AE621BA2B675A7AA9346BDB -:10AE8000CBD1740923EAB474E723BA8BA6D77874BC -:10AE90003718E94EEADBD42BD3DDE74877DFC58FDF -:10AEA0003990EE3ECF72C6A7BB687A93F26C9FC50D -:10AEB00051897675638D42FAA1F89DA12D581E51D6 -:10AEC0009F4F76F6BE6437D9DD8D4DFC7B498F47A9 -:10AED0008F7933056BC5F77C6F25961BD7C177E853 -:10AEE000BAF418CFAB197A0FFF5EB8A1E90DBCBF59 -:10AEF000A0D1CFDBBF7C7A339D870A6C16EDCBDB0C -:10AF00002AB1DCD8CADB7F8A71AEAB31BF2DD082CB -:10AF1000EFAFDA96EFE6DB6F6ED74F11EBDDA73CB4 -:10AF2000F706B56BE3ED6E3F6C4E60E427E0F6FA92 -:10AF300064B1CE29BBF83AD33EBE7E860BE86345AA -:10AF40009F9FECB94F74756524EFE2ECB3CB95B6D7 -:10AF50001C7C4E4739A647BCBB5BF543781C743755 -:10AF60000C717536F7D3C8F821E6295447D817571E -:10AF700067733B44D64B4F61747E8DFDCC4EFE72A1 -:10AF800019DF0C3EC414D407B8466197C48C774EC1 -:10AF90002F6822BB62FA6019E70CA94B61DCC24B37 -:10AFA0009F4F8BE5472ACBE6F6F329917721DFD730 -:10AFB00004F2754817FB9048E8FCF09077D09EDBD0 -:10AFC00097CC34E7DCF6E5F3F2D4ECBC7F6ECD0130 -:10AFD000F8EA9A54BCF78BE52994B7F2831E164C15 -:10AFE0004A1C38FFE92A0B1A290F8ACF7F658B513B -:10AFF000DC57C2E5DA3C813F366918D1EF5C81A7A6 -:10B00000EA6CA1178B5931CAA979026F3F343719FD -:10B01000B8BE6E3344C98F79D9283F1E8E6BCF6B73 -:10B02000BF47C9971A31EE4A61C7AF627DE43FFD61 -:10B0300044D8F1A71EE676FC6AD641FED3DE9F71A6 -:10B040003BBE1E9687F412ED07ADDDAB2DD77768BA -:10B05000CB0DA0DEB1FFC6AE28B93386FBA57B1FA2 -:10B06000AE2F433F64CDCE77C8FF5D23E54C402B28 -:10B0700067C040E772E6A151E4BFFAD6F2E319D8FF -:10B08000D59569F24BEFC97646F8775EE4792E0DD7 -:10B090008CFB117AED236FC17D2C8BD24FD172A521 -:10B0A00050C815E9FF90F25BCA9B42C6F514EC77D5 -:10B0B000DFF1609B283BEFE16CA1AFC4FE4DFA4D80 -:10B0C000A47D5488F611D2D7A82622BAB07E72BFCA -:10B0D0006DD247E8A5052566C47B9119F81BE1A64A -:10B0E000B78DF5D934F4F168F6E5F783DAEF51F46A -:10B0F00023F7630B05FDDC84911818FF0F721FB84E -:10B100008AD3CF5CE63D84F4F3FBD59C7EE4BEF0AD -:10B110009BEF033DFAC87DA0DC4F7EDDFD603FDD87 -:10B1200058C03E86E7B15CE917E0F1FD4685D3459E -:10B13000FD9CDF3D56C5C2F2E2683373AB8670B941 -:10B1400065A6C98C7E971603DF2FCD99F57ED9D2DF -:10B1500008F913B4971F40B8B16E27F977EBADDA51 -:10B1600071362B3D77FD11F7558F5AC9AF74E10841 -:10B170002393E5C2AE11940FFE9981C75BE57C6E07 -:10B180003FBCF7B510D45BB9EE9662CC2FA8550240 -:10B190002FD6C1B70FACBE7791BF6B7541712F67CA -:10B1A0000FC527E4B8F1FDBA7E92C7C6035C3FF72E -:10B1B000290994DF0BEF8747C6E9FE3888CBEFDC1F -:10B1C0004CDF07B81EA9475BFAF327F813B4301B0E -:10B1D0009412CEA708E74D707FCB5F98E78A79136A -:10B1E0001B23E204D03E66BEDB7921CF47617201AA -:10B1F000CC6765BAA717D77F4AC4854F8938E2A9BB -:10B20000441E57FC7B7F7DFEB40DE27AE894883BB8 -:10B210009E4AD1C69B64BD44F13CD96CF66E346045 -:10B22000BC9E793782FE703D646AA27C95451C5FA6 -:10B23000BD2F256BEE11C81A543E6A10B4FB99D38A -:10B24000AB1F04E32C6FD39E83EA15F7DBF60ABA33 -:10B25000E9B5F0A71C376B50F5286CD7BB80DFB37E -:10B26000DA5F9E28CB5EEABFF7BA10C9A3FEF28F61 -:10B2700042E29C3AF793C8F840BCF86174BC30FADB -:10B280009C6974BC7FB1E43711EF5F24E4D4E26EB3 -:10B290001E6FB8D5CC360F82EFB7756750FCB82655 -:10B2A000D13F5C13EFF75BBF519E87A4CFDEDC9EDE -:10B2B000FEF8F8CF22E2E3F5223E5A2FD7D7A95D58 -:10B2C000DF6401CFEF313E3E799073607C3C3A9F62 -:10B2D000E245B4330C613CAC7170B855E9EB2AD14E -:10B2E0004F7C6139A33CF7356F2D6B413FF29A2DAE -:10B2F000E296556177D70B38C75B97D3AB632E8D3A -:10B30000BF3E81B922D693E54BD194C9928FC83301 -:10B310001D5493AD699FDB3444537FF0BA519AEFCB -:10B32000F9FE224DB9A0F51A4DFD616D159AF2880E -:10B330009DD76BEA17B22149E46F3BA2475F12BB6E -:10B340002A3047F37DF4DE859AF69FB2A61D93A0BE -:10B350005EA7457B2F33F37B7AC69485F3A9C77626 -:10B360002CD5F4C3824A50290BDF33F699B8A7795C -:10B37000790F8F875CDDB55A334EADBE8EF0181D48 -:10B38000EF2D627DE4376E0828EE201B18FF5DD597 -:10B39000D54EEDAE64F7C878C8C64122DE97CDB26F -:10B3A000395D47D3858DECC30BBBF4E47F2C64C3BC -:10B3B0001F9A44F032B0806B20FE2E30EE17BBF0A7 -:10B3C0008CDD8D7945B7BFB58CE663CAD4D205DE76 -:10B3D0001F18B95EEB482D5DD8DD5A3A489AA0A5F2 -:10B3E000836878277BB474C142F0BFCBC03B7586BD -:10B3F000966EFEB7E0DC81F0B586E15B7CD0D3626F -:10B4000023B8F1BC35699F99843D141DD790764EC1 -:10B410007090B0BB453F322EB159F1935DD51F7787 -:10B420009C10CC0BE6A33DD5C4B85FC97B10E56F7B -:10B430000CBF24BD8FE79794709D9BC0F5672DF3DB -:10B4400092FC3E66E1FEA493D5ABC89FB4923591C1 -:10B45000DDFDD99CE9C2EFE8A77A57CA5318909F3F -:10B4600000F6298BF0D7AE068B1AEF1F8A86A7D27B -:10B47000AD04ED786E98754B7DE0A3FC150FDEED05 -:10B48000A989FF68ED5FE65122E597B487E5781258 -:10B490009E52AEC9714CAC499F897C1125E7D8C832 -:10B4A000E8F893D69F23FD41328E23E34CD1FE9BD7 -:10B4B00008BBB8558F71D2C1F92D78CEB7D8E1212C -:10B4C0003F6129EBB905DF4F3077B4A82EE1BFB853 -:10B4D0008AF5FB2FE2EAAB2BC4B56FF22BA147F242 -:10B4E00007C6B3657C1C96FFF11FA1F124C5958B9F -:10B4F000F398F3F20827D2D340BFA6FBF82BD08FE6 -:10B500005ED7978AF5AA30313D22DEFDA612A2F55C -:10B51000FC907936459EDB6F601DD36E217F32E84B -:10B5200049BC27A793FBBB5857B43DAC92BF590702 -:10B530002B41BAAF651171DEFCF0772AEB079665F7 -:10B540001ED295EC89A7F18272CAA3E0F9534CC8C8 -:10B5500041B9FF8CB7CF93F918F27E4F9977549485 -:10B5600023F8751C1B87FD03BF95E594A27F01F8A6 -:10B570005389E4C7FE3C25FA3E801FA3D62FF33142 -:10B58000F4F612F21B2D8B5CEFD78087B45B7E9CA8 -:10B59000C3E8E9C871D1B33EE1C46F3DF8B9A4472F -:10B5A000933FDA68840D0DFA135E1479811D5ABB3E -:10B5B000FD961C9D801BDFF75C095EF1F121F2F81E -:10B5C000043EBEAE1D26F3F8241C970C84FB0A0D26 -:10B5D0005CFBF78FFD705F110BEE122EE74A7B7E4E -:10B5E00081F8D2DB8FA523BC17A67A5763FDDCE375 -:10B5F000A14F145D785E55FAB394877BA14B4FE75A -:10B60000FF1AAEE372B0E1253D8986F3DD268AB3E9 -:10B61000D674BD4176E1D96610B406FCBD0C187233 -:10B62000D865FC0851F08EB74F92EBD99023F6E520 -:10B6300062FD32EF07D6B93927665E473F1CB4DF9B -:10B64000051CAAF46392F01C597FBE92DA97177911 -:10B650005F5FF43A2A7278FEDB29B3F73EECEFC362 -:10B660009E9C1DD85F95BEFB7036C267AD42E7BB9E -:10B67000A698F879DC2C715E6F42A8C98DE79933E2 -:10B6800073F87D66237EA4F7621CF9FDB577A6E00A -:10B690003934D9FF084547E747197BEE837F2CC132 -:10B6A000F8E62237DE6FBFD824EE2FBACB1A2C0073 -:10B6B00039F2BA91DF476518D244E766FA92F5E4A9 -:10B6C000D74CD3B3A9487772DEF2BCAD7C8FF701BB -:10B6D000605EB17C3FA5A5AF780DFA7B043DC875CF -:10B6E0004FA9EC2B6EB285E12FF33CA3E15325F873 -:10B6F00043EE431BF05E5BD0BFE7CDBC1C7DAF6D5E -:10B70000FFFE7458FF3D36F6C8B87E83C593341EDD -:10B71000F951DC6BFB17872789DF77A4BDA7F6BC3F -:10B72000C8B797BF5312EFDE9BFFCC51BE977B8209 -:10B73000E2E585CBBCFF7870694856997A359D73F0 -:10B74000F75EAEDE2BFFAD8FB9DFBE28BEF7DFD3CD -:10B75000F96AECBCC55EB1CE707E6188CE29F7E790 -:10B760002DBE547ED97B471AF03ED20838C8BCF6AD -:10B7700006BC8FB43846BFD09FCB76E57B87AAC482 -:10B78000BC1A308F3035F23DA7B7F03869222F3020 -:10B7900094887CFBCB2E3D9DE3FFE511DD8CDD31F4 -:10B7A000E69D9BCBE132CAA9121F8D0EF2FBB5E3D9 -:10B7B000D593E779E4B9D8E8F97556846EC5F9638D -:10B7C0009E72ACF11CB97C3F2BE7DD99C2F1D1F040 -:10B7D0009A89DF9BAAF27CF2CE94D04AE2138716B4 -:10B7E000CFC3041E3BAF0FE5D1B9B299DCEF108F88 -:10B7F0001E26A7FACA51BEC87BEECAD426C511C1FF -:10B800008F57A28730DCF51ABC0E84BB91BECB7E6D -:10B810004F1F157CCB3C36DCCF2D11FA6EC99E5ADA -:10B82000B287E57EE9F44E3DE56F9C663CAE72BAA8 -:10B830004DA1FDD0521F63EB402EAD7CA27833AA00 -:10B84000AE2599B09614FE1E7F1F66E9C6A8F8BA09 -:10B85000D85F49BD2AC75FBE4D6B17D7B06D7F4615 -:10B86000FBE9F4512E3F56B026D23F2B1FD0F6579E -:10B87000B367D6A738CFE8BC8011C28F372D57ECFD -:10B8800057CA5819EA8F354F7C6EC49F6089C71715 -:10B89000F8FB4F4387F1DF7DC227FE8E083E6FC95C -:10B8A000F5FC2017FD3EEFF2F9AECEF5CDC9457F90 -:10B8B000C9BB7C7E17EA2E703DB32B8DF45B8BFDEC -:10B8C0002E92FFFAC15CFEDF8BF735009C4C26718F -:10B8D0006FBAAE499F48F64D80E8EC43E71D737E92 -:10B8E00040657726F243DAD3D36760BFCEA7AD1E9B -:10B8F0005CDFD6724F21FA2FB656F3F3A166138F91 -:10B90000DF077E39F100865386766CAF40179DA322 -:10B910007B7F10FD42ADBA3F1FC6BC98D6C93C5FC5 -:10B92000325D17DA3F28623CA7359089F17DE768E0 -:10B930007E6F4E9ABEBC90CB7F6E2736085C5CE86B -:10B940002A207F62AF41FA173B2C742EAB8EFF2E5C -:10B95000C628C6F12FF3EA700E9176F1D966A6F9E2 -:10B960009D86511D4AD09048F7A8503CA86E4330A0 -:10B97000FD16D4674FA9144F93F34B7B3DAB02E305 -:10B9800066528FDDA238B8BF4DD8FD0B98FCE3712D -:10B99000B7F9829E16087BFF162B87F752E6CEC3B7 -:10B9A000760BCD2C5107AC764B654729ADB3D690BD -:10B9B0008C76858C1FC5B74762FBC91A7E61E7E7A5 -:10B9C0009E95BEE1D8C919F4415D863FDB853C698F -:10B9D00018CECFFFB1A1CC83F1CA86D746D0EF30C5 -:10B9E0009912783C1CE49619EF113A84FA1ED6BDE0 -:10B9F000EA158BC85B0A8873CDFCDED8C639394599 -:10BA0000741EF1781FDDFF71DE10CA23FE067984F3 -:10BA100037A6BE92FBBB1FE0BDEB0DD960D741F945 -:10BA200074EE9F7879486825DE1B9992778997474D -:10BA3000853EC1724E5EC26C2A178556EAA13C3E15 -:10BA40002F939771030A0436356FF06C3FDA2DC9D6 -:10BA5000C22E7087E8BC77C3CB237491FE58771E43 -:10BA6000976767843FF94C3EBB6D0EC27B64ECFA6E -:10BA70006979D2DE6EA3F5C9F5CAF62C3376BBFF21 -:10BA800010727E9538A73DC5CA5A2D3CFEE74F047B -:10BA90003C1CEC1E41F1CB7FCD4DE1FD3B42744F90 -:10BAA0008FEC27FA771CE4B8AB15FE7B59E7A3F2BD -:10BAB000BC7E97CBE52B8CB391C619EAE1E79BE7F7 -:10BAC000E41422FE006FAAC09BCAF7C9ED7C7ED0A9 -:10BAD0002FFEFE13E88762F4FB1FFC0AEAE787E704 -:10BAE0001D4D2727C538AB5A78DCB62FB980E869D9 -:10BAF0008A55DCF752A25DC7F83C6E9FBAF392C537 -:10BB0000791D09AF0C85C6691170CC090D9F33F6FC -:10BB10009BAFFBAFFF4BEB8EC09707EF6D39D8C5DE -:10BB2000EF371E9FC7F185F49C4276E0764D7F6724 -:10BB3000D647B59FC0285FAE21A580DADF2BEE6F18 -:10BB400095F7D961BBFC71DCBE45BB57DEA7C1FCD4 -:10BB50009359641CB2FFDE8C0E71BF70FF3A6F28E0 -:10BB600011EB7488753A22EF33ECE7CF637D79737C -:10BB7000ED03E9B81FFEFDFD8D2912FD69F83C5665 -:10BB80007FC8D7F1F072551E9727DF1B5EE43CA3F8 -:10BB9000E0D90FE7A8F94978227F53BB315ABA940C -:10BBA000F3CC11F43980BFF3BFE578E27ED9FABB5C -:10BBB00079BE387369E9BABE335F87F909B2DD0728 -:10BBC00078C0A034EC27BC214FEC2773584E9CBCA6 -:10BBD000476F9E33A67F91DE47EF277B93E5EFD932 -:10BBE00069FD1ABD4EFE7B39FE73FC7E836BA3FCA0 -:10BBF0003C188F7ACE166E17D62FDAF263027E03C8 -:10BC0000FD547D7938BF1253C5F3F83B5BABF34A63 -:10BC100067AB6077942455DC990FE5A6C7C693FC03 -:10BC20002E1954F1793EC8F3358F4DE0DF47577C2C -:10BC30003E04CB791379798AE77994F760B4CC9E86 -:10BC40009A15B62BEECC73D1B8FA4A1DDD6B67425C -:10BC50002306D6637ADD44F98012AEF19E25265D77 -:10BC600053ACF3BFF7F4D3038FBF4CC07FBAD01FE0 -:10BC700028FC052155E32FE84DE4E7CF7B5FFD92DB -:10BC8000CED7DC9BE75B9F07ED1BAD676FCD87F2DF -:10BC900006EB0714EF533C6087A01FC6E5608B607E -:10BCA000BECAD9AD5EB49FD86AB75925B80AFF1885 -:10BCB000DEA907F07BE5B5A77E3C880FE3C5794C8C -:10BCC0001472A0F1B5BFFD15E3C48D676C6E341B13 -:10BCD00027763F7C27DA5F13BBDFFE1BD7C3FC3C14 -:10BCE000909CF744F47FC2FB095D269AFFC4EEAB3B -:10BCF0005660FD6BDFEB2E403AB9EE44B005C5420D -:10BD0000EFABFF3E48730E887D7AD97CD1B8F1390C -:10BD1000098F3F01A093081E3FE7F0F88AF2D9CEC1 -:10BD20003B8F6E0E9193547BDE0AEC788A3B5F600A -:10BD3000096E8C7BC873FDD17ED5E3D5B03E787F8C -:10BD40005D1FCC20C29E9E72D10C82245C2E67C9DE -:10BD50009A72A5394B53BFCA91AFF93E3DF32ACD34 -:10BD6000F799AE424D79D6C8899AFA37BACB35E5FC -:10BD7000D913666AEA577BAA35E5C26087A67EF1C9 -:10BD8000912EEDF7634C8F78283AEE7E039FA5271E -:10BD90003DE49E2D3BD5F4063E27FE858323DAAF96 -:10BDA0007CCDC58E37F0BDF42B479F9F927EE69BDE -:10BDB000F5B68031B63F39532D08DF83A0D7F1F3B4 -:10BDC00053EF25FBFE807893E7A7A6A05F1990505C -:10BDD00075DBB99FE2EF325C58C4FD6EC711319438 -:10BDE0004F6E277FE57143D3B37FE47903B928F71A -:10BDF000AEEB9BAF59F7948B3ECDBACBD9AA283C7A -:10BE0000DDA1295739EED6D49F9EB95EF37DA66B8E -:10BE10004B149EB66BCA37BA1F8EC2537B149E9EBC -:10BE2000D27C97F4DD2DFC5FAFA1DF0A9E93423DEB -:10BE3000958887C9A7FA081F137ADA2A114FD71CE9 -:10BE4000EF207C9504BD95282ECB8E34BD81CF206C -:10BE5000ECCBB0DD81E64C7A1E6C7691FFEB70F393 -:10BE6000487A1E6976D3FBFF689E40CF5F357BE83A -:10BE7000F99FCD33E8D9D3ECA567477307D57FAEDB -:10BE8000B98BFBCF52FBEFDDC845BFC1795DA8017F -:10BE900023C68EC15B499E9E4F089DC7F2067FEB6D -:10BEA000ECA92034F0671D902F7F209E452E4FFB7C -:10BEB00060780E1ECCF8FD19227FA343E729443B8E -:10BEC0007CF4E30FDEA7E632B669BD37137F3A187C -:10BED000CB662813B2E9F7901EBCCF93C3D8B3A8A2 -:10BEE0004AE8BEF7076763B957FC9EE7E0C71F241F -:10BEF0003BFC5BC7D93D03E2ECA307C788B33F7B9C -:10BF0000CA65477FCFD1AF46D8111E4785DFCBC367 -:10BF10000A0DF83B1CE56AA101F5ECF138E7215464 -:10BF20005379C9E0525CB77B1EE5915F6FA0DFE1FA -:10BF30009BA3F0FDAFAC97ECE2FAA0F74613EDA798 -:10BF40008EE93C2B903F7A95BEC710CE373DFE144C -:10BF5000E9A95E7B5F1EC2AFFAF1BDBCECEC7B4C85 -:10BF60007147940D1C3E958F3F39DB6FFB5EE133CB -:10BF70001BD7110D9FB9831D7C5F11F4E4A21D2016 -:10BF8000CBC7AA3DF514572CF70CC3751CF59A388E -:10BF9000FF7AED8161E437F294CE8BF0FFF40C363A -:10BFA000D0FAE7A2DE443FE8427D20D6EF159E1F7F -:10BFB000CCED3DA213DC672EB0D2BEE0988EDFA39D -:10BFC000105DDFEEE2FBA3CFE2DC879C28BE57DCEE -:10BFD00054FFEC0BD05FEF5A0B75DDEB1D41F658AB -:10BFE0006F13401768BAF754D339FEDDE41620A169 -:10BFF00038EF2DF82FF8FE6CF79D5FFC06EA7FB056 -:10C00000D6EA261DE21845F05B282A2F4E3593FD0F -:10C01000B4784E6E05EAC55B44BCF056BB9A4E61DF -:10C020004335D9E8807E96DB0A370304D9CAB46A5F -:10C0300023FE64534DCE1D9BF1B97AE87623F25866 -:10C04000DD987D9BD18CAD07162E25F9177AA7199F -:10C05000E675DB3ABD8BEFE7E4F9DADA6F94F722A5 -:10C06000E9F798C84F0220D07E35C9A568F649493E -:10C07000824E1F182CE23163D9D84BDA78D74EE4C0 -:10C08000A3B38BDF191E271EA1FD2EECC7DF8A7B11 -:10C090009EA3EF4F91E33A5C7CFF75CC089489F640 -:10C0A000E442AE07C6CDFF7C4329AC7F5CB7434773 -:10C0B000790DB7D5BF8078B8D025F068605DC84FDE -:10C0C00037F9977CF01B424C9AE6DCF095F4A5BB5F -:10C0D000C75119A92F4B42DECA487D39A1AFAD1215 -:10C0E000F5A2D48FC1E61A218F9B488E1E6C5E4745 -:10C0F000E5C3CD7E7A1E696E15F2B88DBEFFAA79B2 -:10C10000A790C701218FF7D2FBEEE6F9F47CADD9F9 -:10C1100047CF85A9BED7116E328E3BD7ECA3BCDCCE -:10C12000430F9B18C6F12E749B288F0338E2B1474A -:10C13000D2304FC944E744A3F395A2E57C3F3D7458 -:10C140000EB8B7E56DE4F7FE3C23B41707C7A7A701 -:10C15000A3CC6547B9F4F1E0F324878EBA5C76B4DA -:10C16000A74F3E2ECA1E97DD00E53F0DEE25FD715F -:10C17000D4E7B29BA0FCC9E3BDFCBBDF65B740F9C7 -:10C18000D3C17DFC7B8051D0FFECE02F488E9533EE -:10C19000E520F247A5397F2AA80BD0D7E507912FD4 -:10C1A000A6672E998A7CB160B08BE872A66BFD41C0 -:10C1B0002CCF1AD9AEE215151E5BE1466C5791568D -:10C1C000AD62BBA939776CC476D3866E5723DBCDBD -:10C1D00018B36F23966F70B7AB689F2E4039561A0D -:10C1E000EE4796E57729A7653EDDD5DD5ED207E30C -:10C1F000BABCA40F245C2AE6566F42FF676397E23D -:10C20000C0DFA5A998ABF4273360EE6203DE930A82 -:10C21000F2FAFF3DAE77AC87753662F91A2AB7ADF0 -:10C22000FF06FAED7F00F6E231E800800000000032 -:10C230001F8B08000000000000FFD53C097854E582 -:10C24000B5E7CE9D2D64924C360842E2649924965F -:10C250002C43B6261064480CEE3001F944651910E1 -:10C26000C2164804EB17AB7E191A17E0698D6BD123 -:10C27000AA6FC4B5AFB6E461D458091DAA52D287DB -:10C280003A5510B47974A488F0999011DC78D2C72B -:10C290003BE7FCF766E6CE248014FDBE078693FFDD -:10C2A000FEFBD9CFF9FF5F008053F8B3027F603403 -:10C2B000FE38253D8C046804F167BFD16DB295034B -:10C2C000AC34078CA0A32F41A3AB1060AF0E9676C1 -:10C2D0001400A424C3FC7A0B968DB0740B96E75D12 -:10C2E0006803480568DABA206E8185DABBE36660C8 -:10C2F000FB4517E2AF38CE52056E54E0930AD49B4B -:10C300009C89344F9A4DD21FCAC76F8550784A0610 -:10C31000E8B79A3DBA048044937BAC0DC7ED9BFB14 -:10C320004E835887AF88D6316CBD1EEBE300326C6C -:10C33000561E1FCA8219545E09ED46C846B8F5CF8D -:10C34000FBA422DA97C52723844E435F205FECF9D4 -:10C350005416FE63063D54E07AE9036E6999D7707E -:10C36000206056EAF1673974EC706622DE5ED47E96 -:10C370006F04BF18BF43FB7D15E28DBE377569BFE3 -:10C3800003545B0F8D433002CBB8DFD912FE5E85BC -:10C39000FF0D8F874967C0C3A4A1F010B51FF01A25 -:10C3A000418EDED70ACB6EA673E4BEC09DCAFCD117 -:10C3B000088121F7A7F245F4FEDA05FEF502FF2514 -:10C3C00036E7745A5FDDFC389053008E6D35794D39 -:10C3D00099DCFFA93D2944179375832D9A3E5B5B39 -:10C3E0006783DE00B0ADD5CDD0D7BA14F476803FE8 -:10C3F000B53673F9ADD6162EEF68F530DCD9BA8EA6 -:10C40000E15F5ADBB97E57EB462EBFDBEA65E86F8A -:10C410007D91BF5F3B7F6586DB124DFFD5C9CE4561 -:10C42000C48F9E7BAA13993EB8F753C8AB9E1AC817 -:10C430006FB644C30183659D94C0658F11F7E1D940 -:10C4400016E36DC37DFD738CBB89C619A8097EAD4B -:10C45000437C434A80F1D030D2BD9ABE4B461C3A51 -:10C460008966F5E412FE0EEB3CBF0764D9569BD3F8 -:10C47000A5473E381A8F551700DC82650FCEF3783A -:10C48000AAAB85FA417EC048E39CA23F93717C0928 -:10C490006677F03A10A21C0EC408E8B1492C8FD17F -:10C4A00050C8DD40BA9FF960E0E91319B68233CB7A -:10C4B000C570F8A893AB039E32A46765ACC384D55E -:10C4C0007D12F8A412845346D6008ED3976ED413EF -:10C4D0009C14445650C7C39FC9DF226386F1CB1416 -:10C4E00048D4946BCDA335EDEBAC999AFABEF45CCD -:10C4F0001EFFD2B48B34EDFA46579AC5BC532F2396 -:10C50000D865746F5C80740956991C9BB0FEBD9809 -:10C51000F822280698161BBF89E07B31195E6A371E -:10C52000EDC0C914C07D4E937D238B105597DBC69B -:10C530006BC7ED995363C37657E65769D721C12579 -:10C54000B4DFAB1D5334DFA7575EAEE9EF32FB9388 -:10C5500008ADF5CE7ACDF7C696AF419F0C30B1E568 -:10C5600024E84B01C6FB3A34E394EEECD2B41FBF8F -:10C570001B6412EB927D8E3709961F74CAC42A156C -:10C58000879BDF2458F5A53F83F6014EB059519F94 -:10C590004B8ADC8347023D962729E5CAA0B72D8147 -:10C5A000E87012F2F548BF8930C2216363A9F2BF77 -:10C5B0004E101F4C5220003207F6AB164B80793AD2 -:10C5C0008BD798456A05E51BF5C106C991A6473882 -:10C5D000470E5450F928048A08CA3A979EF86B2AE5 -:10C5E000348FA5B209DC69043F4874BF4F7CDC2F4F -:10C5F00005DAC4E282C9C4CF753FFF68DE6DAC17AF -:10C60000621C265CDFEFBAFE914A6BFDBB3FF591E1 -:10C61000376C217E6FB27ECD7852CB8D2DC7197FBE -:10C620006AB96F2DCC77E192DB0D689F1036FEAFB3 -:10C63000CC760AEDDA3AA25323FCC9B8BA20D41E4C -:10C640003ABE18C47731EABF7A5AD304C2D7DF5D45 -:10C650004E6C576F1072089E45F54E1CA73E46293A -:10C66000834FD4A72AEDA1B29ECBE96A7D95686F6E -:10C6700057C77B58B41FAD9695F12E52CBCDA29CD7 -:10C68000A9CEF7A02817AAE5FF7071394EB43F6113 -:10C690009B55EF2908E9FF53AADD180FE3C96EA0E7 -:10C6A0003D9033C91E48BB1A981FA2ED85B65EB1F6 -:10C6B00017F37F237B8CC5448FCB63DF21B9EE90CA -:10C6C00080E4BAF17683D38BF37F9ED451B4C61243 -:10C6D000C2DFE7B7087CBB6AE39C32B65FF96ADE6B -:10C6E00026E223396EF7C885F8DD3A56C77AA74E99 -:10C6F000B63881E87BAFD0FB6AFF48D8D0F2868697 -:10C700009E51F5B2C4F3C16CFCC1F9FAEF1BF5F40C -:10C7100006C2598E3F9770939929F4DC48D4AD95A1 -:10C72000F8F336EA5933D23D251B9C3A6C9FF21A36 -:10C73000EA67A2F141BFD0C7AFC5F824149C958F1A -:10C74000BDC9F66FA18C528EF87B2DCF9D97897C49 -:10C750007A34CE9F4B7CDBD0B28DD7758DDDCAE3AA -:10C76000833558108ECFE2CC28FC979E01FFA53F61 -:10C7700026FE718203A4CF752874B4BEE596B778FF -:10C78000BFCB95EFAC5F3243EDB82C47978FC639DE -:10C7900032081F0E854E0774B60A055F5713BEFA9E -:10C7A00017FB7313B1ECF0F947BAD93EEC2A97881E -:10C7B000EECD7140743F2AF98BF60E41FF8ED60EF6 -:10C7C000B6CB5B5ABB18BE8473D0BA557CDD108DD6 -:10C7D000DFF967C0EFFC1F13BFA3F401A303FBAD98 -:10C7E000DA073C4E85FF8011C2F44C2BF125E2277D -:10C7F000A14BE2FA3AB92021A0A98F13FE528E7301 -:10C800003CF1E9CA19BBAA37482179981C0B1D31A4 -:10C8100049CCD70E85AF1DC4D72AFF223F96EA1117 -:10C82000CF6F9DC47E43E037C4BFC0F3A878BA3B46 -:10C830001AAF1B888EA7C1ABB6FE07C66B27FAC717 -:10C84000A43782AFC478376546E3F9770A5E557C32 -:10C850006F53E47F383C6F233CA79E7F3C6FCBB483 -:10C86000F1B891F81ECE3E45D2475DF710725A7E60 -:10C870002E723A2DDBAAF8DFE8771646D3FD6DA2BB -:10C88000BB5943F79E33C853CF8F294F91788B8480 -:10C890008D12B83A2CD1DF3FCB1C56DF9D173C4E92 -:10C8A0000ACED6F86793BF756BFCB329186169FD92 -:10C8B000D89B34E53AEBAD9AF697A6ADD5D45F6E2A -:10C8C0005BAFA9BF32FF014DF96AC763117EE6D3A2 -:10C8D0009AFA7AE76F34F5739BB76BEAE7B7F468B7 -:10C8E000EA1778FEAA29AB78DCDA0A1C2F6D6B35C3 -:10C8F0002BF1D3650CAB03FE5A12838B0F07D9DFE4 -:10C90000ACF4B7D7B24BB2AF83FDD1329FAB96C276 -:10C91000AA8A9DCD6F12F4B55A95782D8DE15BAD45 -:10C9200036D6EF3B5AF319EE6C7528F15A25C35DE4 -:10C93000AD4E254E73318CB40BAF66BBA764213D61 -:10C94000A6BDBC4407B880E97FF867C15E5ABC77D2 -:10C95000BC8EE2DC35CA5E8E577FB3FF36E4AFE3B0 -:10C96000CD2607957BB71F31D80AA3F965EEB732FC -:10C9700038C3F86C6ECB5F0DE467CD450FBA630822 -:10C98000399D9AA5637E20F703502FCC368321056D -:10C99000F5C1ECD992A30DF8BB079218FADC583F09 -:10C9A0004D0F3E1396EB2D7A9F299E97E632A33FBB -:10C9B0003D4B2C134C7AF0503DA424739C7E0D7D8E -:10C9C000B4A13C3865B818BFCF223F1CFB5D6FE9AE -:10C9D0003090DDBD6EE72FFA6FC37AB8D353CEF136 -:10C9E0003D5C6225FD2D793ED69D1A37BCBC2035B5 -:10C9F000E150185F4F25194EA5F8D1E17752DC7A46 -:10CA000093C1F19C2DBADF05CA7EA7C912FB6FC185 -:10CA1000D74DDE4D52483E717F3B4DB8CF26E201E7 -:10CA2000DA67B3C19757447EF676F6B39B2AD716DA -:10CA3000119D9A2E913E311585E29DA6962FD98F94 -:10CA40008FD4CF91F04CF190C36F65FEDBDFBA93CA -:10CA5000F9458D8B7A5B7D5C2E0BB86AC3E3A339F5 -:10CA600093FF4DA6B8A7EA4B11FF4C3CE9DCFB5302 -:10CA7000DC77A0D5FF2FE517D4BC829A6788CC5B02 -:10CA8000A87A64DEAD75096EDCEF9A2C5106F3943A -:10CA900074A6A35E4055DFDE9A156597EFC83ABDD0 -:10CAA0007ED6D6FFC0FAF96CF9BF314DD8D548BE55 -:10CAB000DF37E30503AD53E5EF48FE9F437D70FE8E -:10CAC000394D92D7837A7AF69276C344E9DCF97DC0 -:10CAD000B9E5A0888B23EDC2F7B60736A69B5C2B81 -:10CAE000737C61926F72501E44A5434734DD3ACF88 -:10CAF00040B7CE1F936ED176F1E0BC73B38BA0F13B -:10CB0000CFDFCB8AF2273EC83ABD1FA9ADFF81F720 -:10CB10006D1D6B63B87244EF3C5927EA457C620196 -:10CB20001DF2EF8057E6B87469667B3CC533501937 -:10CB30008C277DB7AC5B06F20F41EFD48F46FE5CCD -:10CB4000A2F0671FF83E247E5C05F77E4109982518 -:10CB5000D54BAE223DB7F40943084FFCAF93F32702 -:10CB6000AB947ECB2D9D46DAEFF267B5EDD4711A0A -:10CB70005F8AC81F575FFA19B0DDF073DE6F55A7E3 -:10CB8000B6DF77597129876259164B08EF67D2A72C -:10CB900047C9AE1BC2CA275B39BF203FF3E0039EE3 -:10CBA000B121FAC46447F1715CF6E9F9585BFF23DF -:10CBB000F3B11CF7AC91E8F97DF978BFDD9945EB4D -:10CBC00056F5F3A0DE79C3C47A67A0DC26F2A43759 -:10CBD000FDAE2D9EF8E40438881D162AF9D2856A28 -:10CBE000BE749D365F3AB9CFC779B94907BD6D713B -:10CBF00048F789BD1ECEDB55ED76B759B0FCD35D45 -:10CC00004E99FCA3F16FB9645AB7EADFA8FE4E480B -:10CC10008FE5B0BEE3BC6BF6D9EB3BD52EAAF63060 -:10CC2000D20E5606DB6BC9FE4DF8B6E34D82E72BFC -:10CC3000AF1E69F7DE8B137AE2A8C157BE97FC8C52 -:10CC4000D7631CCF41F4FAAFCB167EC64CCF02039C -:10CC5000CB1F091FCADB0C456EAE4F765F974DF5B3 -:10CC60008ABDD0999D06B2A37572DF23D7125FF9F2 -:10CC700065CE1BDE7CC707BFFFB5EDCCF98526EB83 -:10CC800071F63F868B339A74E0A6F8A2A4D6564A72 -:10CC90007E0CC56D944754F38A91ED9FB0D7ACC814 -:10CCA000E63C57B5DF49EBD928D6331CBD9A5ABEAE -:10CCB000D0E431879BBFA9BBDCBA304C3E5ECA16BC -:10CCC000F12ED2DB7AC81CA2F7D9F2C5FFB7F865FE -:10CCD0009A0C1E09ED6CA1E415FE2F083F780EF8A2 -:10CCE00019CE8320433758F97C6A2138182E021751 -:10CCF000C37CBBDB4B7C3360088E24BEEA7FF5BB74 -:10CD000002E29BFE8B27B657C1F93B5F8AF4FF0610 -:10CD1000C6DB78FE8157BEDB43FC397087E1ACF49B -:10CD2000C6EA646727F151E479CBBB53643ED7016F -:10CD3000FD7A968B7AABE80397A4721BEBD84CE68E -:10CD40008B90DE1CF5B4AA371760BFC24F74ACD706 -:10CD50006099E4B563D3AE808E45AC7071A657A6DA -:10CD600072A7A82F5C99E895B05C581523EA6F4A22 -:10CD7000F44226C5430196CBF900AC0F1780D08B47 -:10CD8000378293F78991419684FD176F3597703EEE -:10CD9000160239A4FF8B288E1A224EB7E608792F87 -:10CDA000CE12FABEB8469B17F9305BC91BDB6B4A43 -:10CDB000721056E738F7121D8B93FC1B1E2AA37CBA -:10CDC000900E36A17C7D56752B9F77AAFD1AED3506 -:10CDD000BD84BFCD1270BCE2E936799F13E78C2386 -:10CDE000C3CFCDF2EDB507A8DD115A7BF9F078C5B8 -:10CDF0007E1CF747CB9587D7574CB11BE7FBF14318 -:10CE000025CFCBE5FF79E6EBFA3B0BF84CC1437E2F -:10CE100072A3DD7D9CD76F04B0D0FA9F14711440CB -:10CE20007306E547973C65D2919FF1119A63C80359 -:10CE3000F81BC6DD04FF1BE367827FC7F899E02774 -:10CE4000183F13FC07C6CF04177F3B1E8322808D3B -:10CE5000394E4B4E79E81C3072BD861C81CFC1F92A -:10CE6000BB8D3C7F9DDDCDF81DA4F7EBE0A573994C -:10CE7000CD89C10B924EC36F03DDDFF0F9E9707805 -:10CE800051CF2523EBBF53E85AD4A967FB5FD415D4 -:10CE9000886F086B77418E91EB0B5F39184FE31F5A -:10CEA000B50EE2D729E196A7E944F982672D330848 -:10CEB000BF75766709ED1BE53C83F651D4F5C18358 -:10CEC00013CB787CAB64A375041FE5B821621F9176 -:10CED0007850F7B539D1BF81FA6F7E258B76827A8B -:10CEE0000784DC101F4943ED772DF3CF7453B0CC8A -:10CEF0008AEB9D7E4A6E1E0AFF75F6298CE77754F1 -:10CF00007E53CFC715FE52E976AEF21D391E906BE7 -:10CF1000847EE76AD2A536B24B27E3C92FAC57EE21 -:10CF2000197475E6BC47FBF4EC94C16E633ED6C839 -:10CF3000DF62855F5458D86D7411BD36771FCA59AA -:10CF40006461FAE42CC6F6B372EC9ABC6761D589C9 -:10CF5000C71F4AE1F6569AEA3A78BACE8AE3DF600A -:10CF6000DEFE366D69AEF593BA442CCF4F93761042 -:10CF70005C60CB9C9A64A3E57A79FD37E64FD94192 -:10CF8000227595A39EFDB929A464C2EC43AD3996E0 -:10CF90000E1F07CB75D6644DF9D2B4319AF697DBE4 -:10CFA000B235F557E68FD3D4ABF35EE528D5B42B75 -:10CFB0004E0A66515C87FB60B980E764AF5DA27D75 -:10CFC000EFBE621C96A73D3FCB416ECA66A57EDAD6 -:10CFD000965A2FD16300F1694487EA70E5FA471F3A -:10CFE000A2C122E286C6EE6776386DE710370C13D1 -:10CFF0002FAC00718E3F5CDC10192FA0FE7C90F4EA -:10D0000067F1ABD758DB70DCCD55272EB0E13EEF92 -:10D01000CCC13882EC8D12470CC73F837222D904F1 -:10D02000FFF4C8F0DC10FC03F00B851F059CF63EF6 -:10D03000FA3305DF5FBF7D4AFA8DF3071EC5EF5750 -:10D040006044BEAFD8E8786F0DE5A7DE9181CEF9D8 -:10D05000E124AE03EB1BE87739C4F7B0E8E9BB463F -:10D06000A7F0770FB9A6AB94FCDF1F7314BFAA71AA -:10D07000FB5DA3CB42F570F3279AF670BB74B7A69D -:10D080007C67A6B67CEF94BBC3FB0FE797356C5C5F -:10D090006074A39C363C2C39BD43E88BC1F5A428B1 -:10D0A000FAA17B09EBDB43DB97196D71D1ED57E1F9 -:10D0B0007894B76C18C6DEAA7AEA3A199A87AA7FDA -:10D0C000479DCF717EE7FB08714FF6CDF39AB0C351 -:10D0D0001F25B88DE17CB22F479C7BF43FF6C01D25 -:10D0E0005FD379EEEB22BEEA4F14F6A3A8F3339D8B -:10D0F0000E61F108C15F45D6808EECD2C0D2580FC8 -:10D10000A09C352D8BF3E88AC98F087E681E4F5E80 -:10D11000C72D0F9A91CE1FEB741ABB3C40C11696D7 -:10D12000FB9EFDD98C3BE9F702712FE97CEDB32F13 -:10D1300007847DAD117A631EF19F62B7005556D307 -:10D140005D3068C748CF105EA89C6BBFF5FD87C9EE -:10D15000CFEF117A83F20A37B05FE0B468F30D1DA8 -:10D160002CE7F8BB2DFC3ED759EB8FB7DA8D96F341 -:10D17000A84746D8B5798721F4C5FB57223D9B5E69 -:10D1800097F95ED0B1ADF60408D31F91786CDA2818 -:10D19000B39CABE5A35BE5CBBC6C0F8319F585D1E4 -:10D1A000F806A783E57FB555CCB77AD23733C84E9A -:10D1B000AFEED68B4B2FC3CDB34E065BD83C9BB79F -:10D1C0009996925D53D73F6055F449F75749530AF2 -:10D1D000045C3B847D45BFC090427E41BDC4F1EC00 -:10D1E0009EEE513584A73D12F86C253CC435665C33 -:10D1F000DF4C311C7DB7505E14D2F2F99EA51AD7D0 -:10D20000AAF1ECACEE5976F2633FEC5CB807290763 -:10D2100093ECD9CC4FD78287FDEE3D89AE74CA938B -:10D220004C53EE3FEC490CF691BFBD6752AC44F74E -:10D230001970FC3B697C755F7B0CAEF466DE9792DF -:10D240002F75FE443E157BF671A2AA67EBE4DBA7BF -:10D250005C49E7F773C04AF1EC7459F8D5F04721FF -:10D26000CFAA5E6D92FC496CAAED33A6DB114FA3E9 -:10D270005A7EA9E47DDB35F700CFD6AF1E8CA35FC5 -:10D2800094987F563944BCB1AAFAF347AEC5F95712 -:10D2900061BC4FFEDDC2AEEDFB087F91F1FD607C0D -:10D2A000F52FE67BA3E333D732DADFCD771CDF73CC -:10D2B0002D44C769837181EA5F3E17CBE7D6A85832 -:10D2C000857C28FC7A645BEEDE35587FE42F0666A9 -:10D2D000D73727FDEAE8AD58BEF9B958C6F391240F -:10D2E000F0901D39B229CFEBC1064B74C15EB26F0D -:10D2F000B0258ECF693E7B32EFB72F517EF2B776E5 -:10D30000F643487E6CE8C27C46F78FE8FBCBA3B9B6 -:10D310001FB8C5BC0D8A5CCA2F14DE5F4DF52F24E3 -:10D32000737E42A5DFE127639C14AC7D05BE222BF2 -:10D33000B2DEE792E710DD5B5CA17B69BF847CF91C -:10D34000D508F706DAF7F2C7FFF3C389B89FDA17F3 -:10D35000AEFE5515AE6FD907A940E384E83AB4DFB5 -:10D36000706C6BB6907F053F2B5E8CF11E0CD32743 -:10D370002B3B1235E5A6AED1DE83617A68F09E7252 -:10D38000A3C4E7048D8A5CED37BADBED94D7A5FB27 -:10D39000A94C3F711FB584CEAB08FFF79918FF91D8 -:10D3A0007CF6A25D396756F33CC9604E23B9750B14 -:10D3B000FC0DDC97B789E2319F3D49F13B82B933DF -:10D3C0000AC3F9B377D51B9CE731897B8F31439F23 -:10D3D000EB77DA13B97D83F94B4D9E6955CB094D37 -:10D3E000FE675501B01F50D2662BBD89CE8714BA97 -:10D3F000DC9FEE7A8DF1DEF1C0ABBB189F4FDCF203 -:10D4000031CDBBD3C2F4835D4A3C16116F3598BF52 -:10D4100050E4EF698D7F7EE8B1BD4594FF38F4CAD2 -:10D42000B822CAD32E94FD877E9DC9F79CF6DF866D -:10D4300070CBCEF7392F1EB9DEA87B0C92D0438D6E -:10D44000B48F64BAFFE37AC7CE722EF4C3810D8520 -:10D450008C3F351F3D7064E878505DA73ABEBA3EF8 -:10D46000757CB5DDDFEC225FD06FF41791FD5F4175 -:10D47000E73061FBEA8FF717255AE8BB55F81349E7 -:10D48000580EE3B77FF5BC2AF27C6AF05C56C947B8 -:10D49000EDD3ADFD9911F9AFAFE321833B5CEF7E96 -:10D4A000CF732A75BDEAFDDA7EAB85FD9B937625A9 -:10D4B0001F9F0EE9D40EEB1D3EF2BFB7981CE4C7C8 -:10D4C000279A5C908BF86934FAF8FE9ADA2FD1E447 -:10D4D000E6EF9179F9814423D0BDE58154E5FCF76D -:10D4E0002B60BD4271E8169CB7AC56D7BCC512D2B2 -:10D4F00087AAFE2C1B87DF0BE81EA93EE42720DF4E -:10D5000094156BDB87F6A32DFF7BAEA06359B26E3B -:10D51000C838B92457C8651B74C8429E851D9DA88C -:10D52000E01D0DBF1CEED7AC52F4FC40BCD9430744 -:10D53000BB13B78A7BAB13F5BEED04510B404B1206 -:10D540005D99F489F1BAB4FA9C6CC81CB6CBE3D8E7 -:10D550002E4F50C87DB7D4CCF75B43F75CFD32C18A -:10D560008B21C8D009563D412403C34BC0C5702A46 -:10D570003433BC0CDA195E011D0CAF023F43F8894D -:10D58000AF0DD81EDC6E65FFE9F2253AB2CB65D748 -:10D590000EED97CF52F0353C3E50CB579C3B3EA60C -:10D5A0002AF77287C5CBD87CE67B152F26E24FEC95 -:10D5B0001703DE34829320C0E34C2646CEA678DDE6 -:10D5C000C6F77E6BC1C9E5BAB3C44765C0AD77176E -:10D5D0000C8197DAA1F9649EC22703B9C0F851E91A -:10D5E000F548AE8DCB2ADD30504C237B104D4FC813 -:10D5F000A07596C5D61CA7A722B73F5F36538F7A72 -:10D60000B4ACB4660DA9905FE64E15E589352FD30D -:10D61000517DFBF3978A72714DA9C1815EE8DACB27 -:10D62000665E82FAD9ADDC2737A311A07B6372B6A0 -:10D630003817762BF7CA4D72E65ABA2F66BA0D58CC -:10D64000DFB86300FCECD722B791BCB8451C7BB3B4 -:10D6500055D0AF3AD67D4B2ED933B32FDE8674B872 -:10D66000796DDD28B29BF718C5F89FA4DAC6BD8195 -:10D67000F83299C4BD5675BF58EF89C17240B2AD3A -:10D6800069C90CAD4B5DC759CC7BD7E9E6CD4F7767 -:10D690006F203D023607C7156314FBBE65CBC4344B -:10D6A000F430701D565E47202E774D0B56DD91EEFF -:10D6B0007A84C61B88137CF808D1297578E8CB7565 -:10D6C0003E943BC4F781B5DFBCEA23BDF4292E04A8 -:10D6D000C7F94DAEFB715A47932E90518AF4FB4522 -:10D6E0002C7A000521BE96909873100F6D4EF01A9B -:10D6F000595E947736CAF9992A17038B713CC44F47 -:10D7000099CB558BEE2254CC6E7E9360A5BBBD1693 -:10D710006B689E17683D4D72B081F8E468E207C6F9 -:10D720004F596EC70AFE54F459F7B69EDBC688A25D -:10D730000BC2E4B269DB89AFFF86746F3A66715041 -:10D74000F3903C3EB6469CE75A34FA4695D3095DC1 -:10D75000263E389CB8F5A2C5D46ED207BDD9A4B771 -:10D7600027F706DAC87D1EE8DE3B46C889EAD77F80 -:10D77000239D8B7DF9CC8CFC914010F9235E9C831A -:10D7800073FCF48A38075FADE43DA9ECE17D8B784A -:10D79000548D3B57F6BC2DDE8579F06F05BD2B12FD -:10D7A0007F963E71E355C46F91EF8BD478B449698D -:10D7B000B7A2D77B37ED27F2BD5113C5A345C3BF31 -:10D7C000376A7AA296E3D1C8F746BDB94AFE4AB194 -:10D7D0008FA0F8A14B9436B43F0BC78746AF09F72B -:10D7E000B6FAC9350E2B95D32D0ED6C7573D0EE18F -:10D7F000EDE18964E619559E97AD93D8BF56F15A6D -:10D80000FCBCC949EB287E7E14FBCDE8EF8B7BE99D -:10D810004A3E91DE12D07B83CD89C12CBA67BAB95A -:10D820003BDF41FEF81F5A9DF00F43687D6A3C5074 -:10D8300027BF544BEF878E2DC2380B3FADEE79A634 -:10D84000CD8CE5D5EBE95510A584F313C8AF2ADFDD -:10D85000298397C601EF43D5083B153937A5E9C0A1 -:10D8600016868F18DB08B00D910F3029F48BCD4F41 -:10D87000D2D4C7392ED0F44FA8CCD2D4B7C588F7AC -:10D8800032E071FA0B2A42EF48129D3FD1F4830037 -:10D89000FEAD08BD17B9277EEA4E7E4FE26FE03C31 -:10D8A00045F265259AF62679AB4CFC5DFDA55E43F5 -:10D8B000CF9F52A61BF156B91BFD1C9C67429FB619 -:10D8C0003E26E001EA17B35BAFC94B986CDAF285EC -:10D8D000794A9E622C8CD5E42906F12EF8FED86197 -:10D8E0001DF34505E4FCAABA8CF06C00AF2D1A6F4D -:10D8F000C740F85DC7C65A1CF4966A42CFCB32C9FE -:10D9000041AA4B8BFF51B3B5F81FEDD6E27BCC5249 -:10D910002DBED39BB5F8BEB0458BD74C8F166FD9B3 -:10D92000EB2668DADBDB6B34E5BC8D5768DA5FE445 -:10D930009DA1298F7BF17A4DFBC28E859AFAE2AECA -:10D94000E59A7A95CF86E383F1BED511FCA603DD77 -:10D9500069F8A074E7CF35F3FD50F49F9FA7E80561 -:10D9600085FED72B76E5DDF8C3F792B84E8B157A96 -:10D970007030DF506DE078EE3D5B726D1CE905C5DF -:10D98000DEB9147B07394F89B255941D7E71BFA251 -:10D99000649FAB36DE46F72CC4FD8A8AC3EDB50919 -:10D9A000D43EE21DD6F44A4973DE1DF92E6BA667FC -:10D9B000AD9C20D1BD44713F31F21E84FA3EABDEF6 -:10D9C00019A339271FEEBD969A5FC278018C142FD8 -:10D9D000E8CCFC3E31DA1F726C94D95F73B3FFF66A -:10D9E00067C9CD79A76BCCFE0CE2EFECB1EEF5790F -:10D9F00088B7A33A878DFD3DE5FDD6006D8CDF2FFE -:10DA0000F5CCA43CE90086BB94D7D4DFB36326BD34 -:10DA10005BC4E55B031522ACA63F8FE6B91FA4717A -:10DA20000E48D6BB4BB1EFBB133ECF207B66A27333 -:10DA3000FE123EFF7E382FFCFC7B14EE0FF56D408E -:10DA400067F3F079EECF258E533EA7C1AAC2E477E3 -:10DA50009D41794F2AE2B6B90ABED4B86D8E32FF25 -:10DA6000011C6229EAF3B95D7F66BCAC48EB53E266 -:10DA7000BD668715C7BF71ACA584EF7B394B1D22EE -:10DA8000DE57E3B831F2F7B1B367BA87B522ED8854 -:10DA9000269E86979287CC5746E6C542FB16E31F23 -:10DAA000581FCB76E8C0FA74CE3F86C63FCAF985C8 -:10DAB000B9CDDAFBDDF35B3ED2F0DF02CF279AFA75 -:10DAC000404AD03006F71F7875F4D41B107FFDAFA5 -:10DAD000982A289E45BAF5E49587C60FDC97778982 -:10DAE000F01BCEB4CFCF791DBDCAFD5A759FFB5B2D -:10DAF000F77139D01A88B8EFE4D1C4BF2A34FE09CF -:10DB0000F2C98F0E4A231C43E57366E78B38A95789 -:10DB10007977DAABBC3BED55DE89F62AEF427B958F -:10DB200077A1EABBDD5E099C74BF648EE47A6A81EA -:10DB3000C4EF760FD13E9B96078BE85D635371600F -:10DB40009E24F3BBDD23F47D8877BB459295F46971 -:10DB5000EA35F46EF7F008CF51B2D8D9F989D75029 -:10DB6000BC70D828E4A3F4C56F66D27BBDC753DD73 -:10DB7000C789BF3F95641FF3F3EB129F2B8333607C -:10DB80009C7116EF7ABFCB13E73427F3C4B9890A27 -:10DB900047E60BBD564AB09CE8726F2EBFBBDA68F1 -:10DBA000E27757389F5317761F22F27D5CC91F4DCD -:10DBB0003ED21F6ADE27215F9C37D3BB395A67CA22 -:10DBC000FD26F16E2EE0CFA07776740FCA45F2BD28 -:10DBD0001B9CE21D5EDEA6F0F73009F9CA3DBD458B -:10DBE000A079A7B7B2E7C07ED227AFE5B993F353C8 -:10DBF00043EFC756C66F677FAF20DFC6F3E27A797F -:10DC0000FFA817EE24FA9CC77C61567E79F4FFD7F3 -:10DC10006038BCF52FF63F5A90197AF716F6DEAD4C -:10DC2000203F2CAFA7AE3F34CEE9E542CD7BA9E53E -:10DC3000438FDD934B72867411F948599A3F63887C -:10DC4000FED3F305FDEF4F774DA0F997378BBC60FE -:10DC5000886FDA6FF998E8DC6319F23EBFDA3F7239 -:10DC60009F2BB7F5303E709FF3687F61FBBC8CF053 -:10DC7000A5EEB3BF7BEFA305B673DFDFF77D776E4D -:10DC80001A81716DD2507976B43E617E9949ED3F2B -:10DC900056AFED8F0E39E5B1BB48DED16FE954E2E6 -:10DCA0001EB2CBC417AA5DEE54E22029B083ED0268 -:10DCB000CD4B7271B7E461FBA8E63BDA24B47F94E4 -:10DCC0005770AF617B215F6871105F7722EFF94970 -:10DCD0001EF4CE58CE7347C4D73F8B75DF4478BC53 -:10DCE000F9AF35A328FEDEF2972B94384ED8AB72ED -:10DCF000853FCB697EDA474102F36D99B2BE0A7364 -:10DD000033FBC955E091455E43C993ACDFC1F1DFF8 -:10DD1000FF011A14AFAAD043000000000000000069 -:10DD20001F8B08000000000000FFFB51CFC0F00374 -:10DD30008A739418187A351818366B32306868313F -:10DD400030883120E46885AF7153A69F9B9581810F -:10DD50001788F981581088D73331306C60225EFF04 -:10DD6000115104FB9E2003C351207F1990EE1466CD -:10DD7000605805641F03E22F40BE801003830C101F -:10DD8000FF1561603005D2C1406C03C4C745F19BEB -:10DD90007F82807CBC082ABF1B8D9F278C5FFF255C -:10DDA00011FCF20F08C863C33216E4C74722057A94 -:10DDB00007023729A2F28FCA33303C546060D05139 -:10DDC00082F09B91E4ED8062C7E421EC2992C0B817 -:10DDD00007CAB5286237772A50FE0450CE4B8934E3 -:10DDE000F7DCD341E5AF3484D000BC3E14E4A80393 -:10DDF00000000000000000001F8B08000000000071 -:10DE000000FFE57D0B7C54C5B9F89C3DE7EC6E92B4 -:10DE1000DDCD262121BCC22601440DB8400CA04115 -:10DE2000370F5294A8E1A1A2226C782421EF22F6A8 -:10DE3000621FBFDDF088C4521B1FC5D48B7651B062 -:10DE4000D18B3640D058175C9E458B6DE845A0D5E8 -:10DE50007A13405E06B240A5B645FDCFF7CD9CDDF6 -:10DE6000734E36266AEFFFF6FEFFDB9F1DE6CCCC35 -:10DE70003733DF7CF3BDE69B8964BE91D88713F20C -:10DE800025FC6E25E451891092184E9B3C93C69F49 -:10DE90009409B1ED7E24EA3B99840C9E6B7046D1C7 -:10DEA000A25F08644E4B0621C9658D7546FA3D791F -:10DEB000917DBCE808C319987CE4BABD09840C7252 -:10DEC000D3F66682BF2FE97F3FB737C69174C87912 -:10DED00085A231E1FA4A9ABC48FA7B87AABE9B1414 -:10DEE00075A6DD48FBFB51FD20B785901FC3784622 -:10DEF00042A9CB40B2E8B8785D6F2EFD3F3A0EAF35 -:10DF0000CDE85B2910221A1CB1442424262348A002 -:10DF10009DBE9F673CEDD74908A736AAC84AE74986 -:10DF2000C8B49608F57289807888CD76257BE97823 -:10DF3000577D2EE2BC570D22A49DD62792D34E6862 -:10DF40003A95C461BDC72D2306427ED5AE3F120768 -:10DF5000851B9B19245E15DC060F210E13C5AFC768 -:10DF60008CE92A8F9DA7C9C4710D21AB3D0E4C577A -:10DF7000794663FAD8D027DB7306D0F90C32D8E99A -:10DF800048488363A6DD91118627C72D30E73809FD -:10DF9000C92629AEC4545A2FD140C84D84DC42F35F -:10DFA0007523081949EC8450FC3D93BC2CCA9D0193 -:10DFB0007907E6450371C37C6332032E91E22DC6D7 -:10DFC00069CF951CE1EFF81B80DF5F782C15D6C177 -:10DFD0007D1BCCEF19E2ECF0029EDD46E7265A7F6E -:10DFE000A5EC4C5E4AE18A46DA2E83ADBB94101E46 -:10DFF000DF4CC01FED8FCCC9D5ACD730184722B449 -:10E0000073DC05EB6471B2755A097415611DE6F293 -:10E0100075586577D919FD384924FA11ED5AFAB1C6 -:10E020006468E98F7EB19FBA9EE769BF4D42ED3BC0 -:10E0300053E93CBD4B0CCE4DF4DB60A15100F80A16 -:10E04000BC25C480FD2AF9416552A063B41A9E170D -:10E05000CBE9F7F60E73CFEF2D06E252E872532AA2 -:10E060007C77C4CEA0E3266647EC4C6BCFF187E902 -:10E0700024D925C940EF0E4C1B0447AC00E37C4774 -:10E08000249B049C7F72A4F6FFD3ED08F1E17A375C -:10E09000F07554DA513C203D791F8B463C88503452 -:10E0A000390CE7171CCF17AD454F434A48E3685872 -:10E0B0005F9A5F87F463A6792BE69BB0DC1ECA3FAC -:10E0C0008BE5C9AC3E5D5EBA18BDE3555917DA6EF3 -:10E0D00003C29142705E44389650BF9B303F2094FB -:10E0E000FF25D61FCAEAF7B71F25EDCE0D9EC2F950 -:10E0F000BF2E3B009FC2DBD6C0AD942E0E6E107CAF -:10E10000269A0FEC8C41FE757EFD0C9F89E267D745 -:10E1100038930BEA9FDF9883F9BCEDEFDB245A5E5E -:10E12000B55D94206FD879D6D641F15B636A7FFCE8 -:10E1300066FA3DB85D242F6077D3719F9DE2B448A5 -:10E140003E63F9922896ADDAB06B1EC02D6B339109 -:10E15000280AA7EACDD23B6FA6F9D20332812A550D -:10E160009BEA8C83697E894F6881FC8A9D1F603F92 -:10E17000DDB9A40CF6F739E05B942F75DBDA93EE8A -:10E18000A6DFCB7D5B0AA07EF966C1094B5CBE7E33 -:10E19000D78700BFBC551E2152F815CD31C4A1DA76 -:10E1A0002F79DB17DF09E3AD7A472694ED91B2AB07 -:10E1B0000F199118A44623E0B56AD31346E09BE7F4 -:10E1C0003C07B01F059F552FD37E68BBEAD70427B5 -:10E1D0004CADDAC0F8CD8537A3E6BC688179D51996 -:10E1E0004741FB371F3542BD525FF1EB510E18DF3F -:10E1F0000663018C73FD0663898A6F5634FF5633BC -:10E20000AE534DE903DD19BDAFE739CEB7957C3983 -:10E21000154048DF92CF3843C5879E33C421FD5750 -:10E22000348BC411811F78DFE7FB608795F103BE53 -:10E230005E4BEDC01AC2EB75C9CED74F0A66CD88CA -:10E24000C0E71EE7F2A391CB8F27417ED0F4692E61 -:10E250003FD671F9D1E471E2F7673D93305DEF711C -:10E2600061FABC671AA63E4F11D67BC13307D38D26 -:10E270001E377E7FC9538669B3A716BFBFE2598E8A -:10E28000E9668F17BFBFE65983698BA711D3AD9E8F -:10E29000264C5B3D3EACF7BAA719D3364F0B7EFF39 -:10E2A000B5A70D53BF2780E94E585F9A063CED98FD -:10E2B000EEF61CC374AFA703DBEDF79CC1742DC74A -:10E2C000BB2D9BE448146F36174139185FE8CA919B -:10E2D000693EBE88E593E67A738C349FE4A6798A1A -:10E2E000C7C195811C13CD0FAE65E5293F24B966E2 -:10E2F0009A4FF1B2F2B4B5AEDC289A4F6B64E5A345 -:10E30000D67B73A3697E948F955FB739901B43F3D7 -:10E31000D7B5B0F2B17E9267A1F9B101961F7FD057 -:10E320009567A5F9F1ED2C9FF5A137CF46F3591D5F -:10E33000ACFD4D5D81BC589ABF29C8CA6FB94AF27D -:10E34000ED03402E0B98CFB5E4E4C7D17CAE9DE53C -:10E350000B86164B8E08F4B753EE5808227C86B015 -:10E36000D125517EB3D3D8F110157D64A1F0AA4B0D -:10E37000A2FC3320934550FEB0F03A96078C641906 -:10E38000943F2ABC8DE5BB650796FF5C38C0F2461A -:10E390000796FF877008F37B651796EF10FEC4F2AF -:10E3A000461796FF5E3881F9FDB21BCB3B852E9652 -:10E3B00037BAB1FC49E953573EED2FDFE09E2EDC22 -:10E3C0000872DB5D8672596A49067E59CFF9FF04EF -:10E3D00040062DAF1F644439B8F3F3AC174581D321 -:10E3E000F600C897BC04FA0585335B48047D82C2F9 -:10E3F00011FB8673CB179334706EF9A24C81F32016 -:10E40000C289EA1F9C9D5FDCA41DCF17E50A9C1200 -:10E410009C97B57FF3BAE5CB6CED78BEAC54E0D4F5 -:10E42000209CB8FE8D27204FD4C009C8A50A9CE5C2 -:10E430000827B17FE37119276BE0B88C4B1438754E -:10E44000086750FFE0048C376BC763AC50E03C8634 -:10E45000781ED6BF79B94C53B4E3315529709EC2AA -:10E46000F1A4F60FCE6EAB163FBBAD21FCAC473826 -:10E4700023FB37AF5C9B163FB9B6107E36219C6BF1 -:10E48000FB0767B74D8B9FDDB6107E5E43FC8CE9C2 -:10E49000DFBC7263B5F8C98D0DE1E70D1CCFB8FE86 -:10E4A0008D676FA2163F7B1343F809209C1BFB3737 -:10E4B0009EFC242D7EF29342F87907E14CEE1F9CDE -:10E4C000BD495AFCEC4D0AE1E70F08674AFFE695A3 -:10E4D0003F508B9FFC8121FC7C807072DCCD4CA96D -:10E4E000A470ACBDC3D93F4C8B9FFDC342F83989A2 -:10E4F00070A65238E97DC32948D1E2A72025849F20 -:10E50000F308E7B6FEC1D99FA2C5CFFE94107EAE38 -:10E51000209C3BFA37AF82E15AFC140C67F8B955DE -:10E520001A877286CA4E27D8E7DF199AE31232C1DA -:10E530004E6279D1EE24A0F7888A3E43DA5D22AD9F -:10E540006FD91C37FE31A2D66B728D064ACF56AA00 -:10E55000E5A9F59AD849D11A3D2ACE15AFC9274C5D -:10E560001BACA99F5894A6291F38E73A4DF920F70C -:10E57000784D7E48D94D9AFAC36A7335F9E1CB6F6D -:10E58000D7D44FF5CED4E4D3D7DCAFA93FB2718155 -:10E59000A6FC9AA6724DF9B5BEA59AFCF5CDDFD7BB -:10E5A000D41FD3B242537E43DB639AF27181273585 -:10E5B000F909079ED5D4BFB1FD054DF9C463AF6815 -:10E5C000CA27776CD5E46F3EF36B4DFD29C1DD9A08 -:10E5D000FCAD9FBDABA99F43FE53AB6F9B3FD0D417 -:10E5E0009F6A3FA129FF4EF2273A3D556B1FAFCCE2 -:10E5F00021CCAF3288D9AF01AB11F3C6C11666A7E3 -:10E60000584B1C2729FD18772F740CA0F4033403F2 -:10E610007651CEE0B26B3AE8F7EFDDE4BEC64EBF0E -:10E620007FCFE8BEC11E41BFA1F4269064481D06FD -:10E6300048F5E58FCA8CDE73875C1DD549DBD7189A -:10E6400082A3E268FE2331E73EA0C7F90603EE830A -:10E650006891D442BD681341BBE9D1D4AC17BDAABF -:10E66000FDB06618D5338430DC35B23B19F528C3CC -:10E67000F83AD09BEA87D1790D2664D18A71BBBC68 -:10E680002368FB6125C9E08F3019993F24D4BF91DD -:10E69000F69F81FD2F81FE6B7AE9DF943649D3BF67 -:10E6A00039A54CD3BFD948FBB713F290E126DEBFA2 -:10E6B00019FD36CB564CC6FE4D2965D8FFA3466AD8 -:10E6C00077A9FB8F0EF5FF8881F6EB3130BBB9C718 -:10E6D000FCD36ED2CE3FA55C3B7F239BFF4A432EEB -:10E6E000EF3F1AE7BF6A450E9B7F4A399BBF89C13E -:10E6F0000DF56F0BE1BF01FAFF692FFD9BD2B3B59A -:10E70000F31F5EA99DBF89F5FF94E176DEBF05FB8F -:10E710007F7AC56D6CFEC32BB17FA3C9ED04FA31BE -:10E720000E89AEF5D1FEC9506A250D0472A1FD40D7 -:10E730003A3A1EFD08771AD2701CDF8B66F47625F4 -:10E740009AD21BF2332FB3C37D947352BBAA9AD3D0 -:10E750007AC5E61C23F03D2C4F2264311FEAA23615 -:10E7600011E99B3C6DF28DA4E3BDD0267A21BFE870 -:10E77000E9293EE0AF352632BF08DA492400DF3F01 -:10E78000FED99817D4F3D2A78B1BE55391FC45DE35 -:10E790005C32BA968EEF0210812A7F9CDA71601883 -:10E7A0007F48ED1E42ED9F1332EBEF236AEF41BE2F -:10E7B00083DA7B6838933AE657F3BADE1F41C75FC6 -:10E7C00044949F0BE7792F6E290A4F62FBF7F85AA2 -:10E7D000C107EB317F790C457E783CC5DE044DBE28 -:10E7E000C6C4EA076F137C2F0808C30DF899C1E16E -:10E7F00011182FCDCFB1B3364777DEB15FB0D17DE1 -:10E80000B466085D8B309C59C4250FA4EDEF5E56AD -:10E810002C836BA75D1086819FB066A14C02683780 -:10E820007B134906270E3ADEFBED0CFE0C977C525B -:10E83000ED479B239B5D45743C738A451CFFAC6987 -:10E84000DAF23FED8C7119C6D274CD53D8CFDD45C5 -:10E85000DAF27BE768F3F7B9B5792A576590AB0F21 -:10E8600094E9BF53B42481DF31F41B00E37C90E3CF -:10E87000E1C15AD9AB59576A761B95727084B809B1 -:10E88000CE0BDB8B3DEBCF5FAECD177BB5F9856B48 -:10E8900074F039DD9CE2EB7F1CE883A6A7813E285B -:10E8A0003E4F72FA08F3552D7DDC139A06A30F65CF -:10E8B0001EA724B604A7D633FA58DC1813991E8A6B -:10E8C00043F4E052D397420FF3383DFC99D34369A8 -:10E8D0009396AEEE23BED5C9B4FD036B77E13A1D26 -:10E8E000118A193DFC40A1870E0D3DB8393DE8D78E -:10E8F0006F1EA787798F307AD0AF6707A7878EA65C -:10E90000CB3249EBB9AE741D3479BA0EBA75B7A3E0 -:10E910001F8AAE47447A58109A379D38CD2FE46548 -:10E920003DD68BD30396A701DA09E209DBA7F7AC42 -:10E930004FF984265FDA1479FD6BDA36AC3DA9FA1B -:10E940005ED5F2F25AB57FBBA2798B26BFC4F7A67B -:10E95000A67E69D32E4D7E71E33B9AFA0BD71CD26B -:10E96000E48BBD7FD4D49FBFBC5353FE60ED594DA3 -:10E97000F903651735F9FBDC7FD3D4BF778EF0132D -:10E9800075FEEEA2A89FA8EBCF9A16A7C9CF700D6F -:10E99000D2D437ECBCF62EA0C783EF8B04F48F4F94 -:10E9A0009DA7D1FFF9A95376429D931E07EE83538D -:10E9B0009ED1989EF138719F9CF34CC2F442DB1EAD -:10E9C0000BC8152A474BE0C8A674E596BA35D9207E -:10E9D000D709CADF8A956FD4798712B21494638AF3 -:10E9E000EFC22623094C204400E1C4C7151455E5A5 -:10E9F0001D7D9437514191D0B3BCB023F2F79A27D3 -:10EA00008B87DB239C7F84F73519027A52772FE7B7 -:10EA100024950229527F276405F281AD5C4FA93409 -:10EA2000327E51B975502EB1413E30AAF6ABFA6B29 -:10EA3000A19B6C20D049BA663F97365DAFE1F704E1 -:10EA4000BCCF89406F1334DF2B9A6FD6B4EBDA2535 -:10EA5000E2B8AB819750B9FD2A297A52043E15D805 -:10EA600093326B0C8CD3F514E6DB12518FECF2343D -:10EA7000AF85F3C7739E164CCF78DA303DE509AC0D -:10EA80008573C0939E03981EF7B463DAE13986E973 -:10EA9000479E0E4C3FF49CC1F44F9E20A6C73C9F5E -:10EAA000617AC4437E02700E7BCC98FEC163C7B40A -:10EAB000DD938CE9058F0FFB51F65D5F747786CB94 -:10EAC000ED73407F11E86CBB78AC6ECDD0309DBD4E -:10EAD000B9F223A43305CF854D264E0F491A7A0883 -:10EAE00080ED7723D04B1FE54D32A7C3DEDA472EEA -:10EAF000AF79E1BF87DEAE7C4B7A0BD3D3101D3DDF -:10EB0000A5F7454F1FAAE9E98AC1CEE420A7A71FB0 -:10EB1000F3736B7DBF51123BA70CE977AEDB0C8022 -:10EB2000AAA5FCDC84906998BFC4FB5E49C1B5A36B -:10EB30001EE81B0D72EBD2E8BF8F8273874BC7E8CC -:10EB4000E2A7F63E3F3D9DF48E7717DA43253EBAA5 -:10EB5000E80911C61BCDF01A6520D3C878421A46C1 -:10EB6000BEE45C90817989C4437B9F734684F33A09 -:10EB700042756BC06F5F785D69BD3216E09D7AF6B5 -:10EB80001F59905EE1FA75F41E11F57C1278D109D7 -:10EB9000F80DC925933319FCF3C191463BEA09648A -:10EBA000BA167FDEDB35F86B4855CECF1B93117F4D -:10EBB00023AE8C1AD40FFCF5C5DFFBC2E70298F731 -:10EBC0007F033EFBE28F7DF145E272BCD646E7DF74 -:10EBD000BD73CCF8C71CC007BF1ADFCA799C7E3C46 -:10EBE000F992F4B5E8B83B49A1E3F614885BD82460 -:10EBF000DA11FEA5D66B62615D4270FA584FE1ED05 -:10EC00003FA780BD7F3E550B2F4B07EFD281176D7D -:10EC100060772D4D5ED87032C23A2869554B5D83BE -:10EC200045AD87B669F3971A85692D382E47ECEC08 -:10EC30003120276A1B18DF5E8EA90267697209F608 -:10EC400073AE393D96D97B3EC60F36C721BF38E734 -:10EC500029C3FAFFECF1F40647190F21ADE484193A -:10EC6000F8312D4BEFBD7EAFF42CFDC588E7DD7E7E -:10EC7000F90AE88966FADF9760771009F30ADC9AE7 -:10EC800016D16BBA01BE6FD6F447DB399433E22F4D -:10EC9000D3BE6ADF48E49442B7545ED483BD80E7B4 -:10ECA0009B4B1AD47A5955CB7735F99AB6471AD473 -:10ECB0007A5C05FC83F25F522B484037959C8CBAF6 -:10ECC00025CB1A818EAF18824F808F08AC5E95B924 -:10ECD000C3E8A69FCEB7B275EB6D7CE73CE65488DF -:10ECE0003B283337E2397259CBB5F92067CEB7AE3E -:10ECF0004C02F95B215EFA5E5184F6BF94042E5FEC -:10ED0000E4A056CFE7F441285CD5BCE9CF12C21786 -:10ED1000CD7719985F460FB78DCB91BEF053BDF9F3 -:10ED200050C1CD8E9E78AA6EBB6874235FA4FFCBC2 -:10ED30000AE349C15FB154D426D171973777A2FF56 -:10ED4000E28CEC1DF583AFE0973DE767493E15A3E4 -:10ED50009A9797B4433F0B26F18E88E3DE0F281F66 -:10ED60003FFB5B99001F225769AD2C74CD70BBC768 -:10ED7000400C5961BB67416B4521E0FBECEBD3D103 -:10ED8000EE5B448A6CB80EA4310BEC9CF3C480712A -:10ED900055E7C91F6C1354EBF0B164E478A65C30FE -:10EDA00089BB3410BE7B10D85FA639F5EDE258F868 -:10EDB0002E297690F025CA15B780F11773D8772FD2 -:10EDC00031D701FD527B4A63AF517B4A93A7F6943A -:10EDD000265F426626413C45C9D332F10988274D5A -:10EDE000F941C98EE32B25B5F5A01FFD9CFBE1166B -:10EDF000D8893484CA87AA379ECB2AA6F3E9929889 -:10EE0000FF4B890F584265C5205A5E5EE633BA2C27 -:10EE10003DE777A275C23D94F3033C160770BFD15E -:10EE2000C7E26B8843CAE2AA4F5AEFF31FD82ABA47 -:10EE3000A26C508F7E57C69BFAF5E7AF9F2F214FEC -:10EE4000E23CCA9B67601C568F78073E1FB9597019 -:10EE5000F922EC27511634F12E0932C39FE2D71A5A -:10EE6000AECB5F0F7995DF6BA2AEFC1BF39701442D -:10EE7000C35F8A25F7703991F113C0BF2005717FF8 -:10EE80007D63F8C93DE05F2FDFF84F843F54BBEF4F -:10EE900029FC89FFD4F18FE831FEBC48F0ABDE7865 -:10EEA000F57588772CFFD5CF6C84EEB7B35263929B -:10EEB00093AE7BE5A6D53617F01DC96B837D71D661 -:10EEC000274E8B440FDF9779DC1F715904F0BBC2CA -:10EED0003F29FC73AFFCF84EB0A3AE6C92EDE84F47 -:10EEE0006D36054C949EAB5B971492B198EF64F924 -:10EEF000472F02FDD7B4C9C7D5745AFECB9F254111 -:10EF00007C10A5942186644803689F546FFCB80068 -:10EF1000F48D1A12C4FDAA6F07FD7F168FF2B0D8C8 -:10EF200018DBB31C1D3449D09EFD6A5A7F7C51B456 -:10EF3000417ADB69E06FD4B244BF90BE5D19B73B44 -:10EF40002A64EB00E4AB13C944E0AB0A5E888FD9B6 -:10EF50001D2B5F7E666C271D57D7C6DFDA0415BEF2 -:10EF6000147BE952CBC25FFCDAD13B1FBF40F7A351 -:10EF70005ABF55E494A38DDB4B7E9656CA011BC441 -:10EF800073556E909D5EFAB9F2D5175F7A16FCD96B -:10EF90007F34394752F815AFEE3B7213CD576C9161 -:10EFA0000714B2695884A4F0FAD4D0FF968F0FAF3B -:10EFB00047F9B67D46C718F6FD87F1E175A9D8B2C5 -:10EFC000CB48C6F4C4475ECB2E638725C2FAB4741F -:10EFD0001680FEB7F2E5BF1A81EF9DDD299081A969 -:10EFE00011F0B9611FEA8780275C4FBE5EA1F5D39F -:10EFF000D5AFA1EB027246BF5EFA7A859CBF005C7A -:10F0000088B3A1F4FDDAAF210EEE4F2627E0A1EC84 -:10F01000B5876C309FD3522DA3F3E7562701BF2B42 -:10F0200093BD49764CD9F7B2E71F46FA2B3DF470F1 -:10F0300012F357BA061950767A07C13C17AFBF1BB7 -:10F04000E75942DC488765CF89453E9A7E2A916917 -:10F050005B22EC934B7C9F9C7E812E2E9DE7694525 -:10F060002EFC41E472E1BBE80F7D98CF856A909851 -:10F07000FFD4CCD6EB806CD0C8D110FD6E7C14E5EB -:10F08000C7B961AE8170EE561396172847C4435333 -:10F0900007B275627207DB51B99307DFA17EBBEC43 -:10F0A0008A1AAB69877246E97F19EF9F8E3B1AF483 -:10F0B000B7D34991ED91E146850F503D434567AA8D -:10F0C000FDCEF6FFC606B6DF95FDEF9B310DCAFFFC -:10F0D0007298ED23680772978E2B3010CB77CD1680 -:10F0E000903F984820D23EDF28F37DAE2DD7D30B3A -:10F0F0001DBF24C4AAE806FA89C77540795FF234B7 -:10F100006DAFE2A335D0AFAD275C651F97727E70FF -:10F110001EF8C1F5617E40D627F62B5EB452F6BDCF -:10F12000F42CEC5FBA5FBD0ED8BF7211CCFF93CD4B -:10F130007B8EDC4FF7ED272DCABED5F255FDBE2DD7 -:10F14000DBFA30C69FEBF7ED27436B49C47D4BBF1D -:10F1500047DCB7433BFE47F8AA82C724A396AF2AF1 -:10F160007CB2377CEAF9E416D98178D5F349FA3BC9 -:10F170004CB27AD2A342870AFD95FF47D570E0478B -:10F18000213A55E83044A70A1DEAE7ADC5A3BEFC05 -:10F1900023F02D527A297A53C6F3954A3F8B03A662 -:10F1A000EDF60FC9447CB950CC91C6FD4306A8F3D7 -:10F1B0003E5DBE4557DFA5CB17E9EABB75F95A4D51 -:10F1C000FDCAB63D46827410D0D41397FF3B393147 -:10F1D0002112DDFA98BFA1F5A211EE39D45882D8D8 -:10F1E0005E5E41BC101F19DC21E2B95137C5713D8B -:10F1F000F83736A7FABC948FAC8E627E856E7BD0D2 -:10F20000164FD3D5712C1F4C34D6031F54BE07A301 -:10F2100098DFB1BB28688B53D95B9D7E11F9788745 -:10F220002FF2BD0D2A6970DD3B7AB9D7A19C8F758D -:10F2300047DBC6627FD1293EA0C7A9A2256539F860 -:10F24000A11A4527E8EC8BEAEEB5C17955B73FFD29 -:10F25000AE39F4FBE27744168EE37549835476D0D9 -:10F2600019E25D972D405CF05AA49F857E66172DAC -:10F270005A1B793F94F37625966546E0BBD40E3948 -:10F28000AE3EEF51E094ADD77DF74FE7FBA611ED11 -:10F29000FFF28DDA7237B79F7F64E4FC671C19C7F1 -:10F2A000ED57E6BFE17C7BAA9871D71CBA3EDD071B -:10F2B0004462A2F94B7E11D7E7D266C107FE37E25E -:10F2C0004DC4FD574D8246F57D882ED85FD7F4CECC -:10F2D000C7BAB6FF39EB074047AF7F30F6DF69DAD0 -:10F2E000F5FA1F47BD05F9378EA67C407AD6CFDBED -:10F2F0001985F102DD3BAD48FFDD3BDE4BF901E452 -:10F30000DF3439619CDD3BFF3A16E8A97B85A90C07 -:10F31000F860F730E6BF5DB9E3AF633B50FEAEC2C5 -:10F32000756C361A999FC9FF8F8FE0DEC2253F9D0D -:10F3300015E8173CAEBEE6D7513E82F0FF9AA5BE57 -:10F340000FF46DE753CDE343BAAD64CE56185F1C9E -:10F350008B7FA8796BF28B75B4FFAAD65DC685B496 -:10F360003CEFEDCFC7621CFD56A6375D903B9E87F4 -:10F37000F8876DC6EFAC94299E2FC026A346F65D94 -:10F38000A63579B08F7AE2E573F4A7F5171FEF1A67 -:10F39000997DFDAF8F0FC1C5F89FD5671660DE7FE1 -:10F3A000FBE803F4839A902E95F97ED25287FA4CAB -:10F3B0005FF33EFBBF860EFA3B6F21D09F799B4DDA -:10F3C000FFDAEBFDB8D181EBA2DF073DE97CC7F79F -:10F3D00030FFAAD589E3ED27BD8F36FD3FB6EE5B42 -:10F3E000E9BADBFA9EF777FEC5E7DDFBBABF338FDC -:10F3F000AFBB1DCE536BDEFE1CC7F775F95CE9FF92 -:10F4000052BA57F4FD7643AD3D938E6F0E69B482C8 -:10F4100062715FE2254BA603A2702F0FC0F83B3844 -:10F420005F8D6057359998BFCD241858BCDADD82BE -:10F43000E247443BEB4EAE5FDC39B40CF5903B5DEC -:10F440003F417D8248B5ED39B47E7BEE4227C66AE6 -:10F4500092F1C7DC909F3D85E7B5F6E6EF04E21236 -:10F46000A87E7F67EEF403A0E7DEE512510FA62920 -:10F47000EABFEFA714B0EF93B4F6D07D6E6DFEDE59 -:10F4800039DAFCDD1CDE3D848DFF9E22C1077E58EB -:10F4900053CE5389E097352D9689900A7146B5ABC6 -:10F4A000C1EEB8BB48DB7E1928672A7FE337C5E386 -:10F4B0006F43785C8A78213922DE03ED138F7CDC80 -:10F4C000EDB3C7F920CE9A484E86C77BAA9CE83791 -:10F4D000E7F6B8CCDBCB9635EDB09F659D1DAED879 -:10F4E000D3BDE19B70FB1CE1A485F12FBB44B4CFDD -:10F4F000659D7DAEACCBD75D0F651DBFEDBA3C07FA -:10F50000EB7263785D865A5C04F6ABCCED877C8B3E -:10F5100093E587161176AEE8C3FAD20017F1668438 -:10F52000E3D197988B2BE09CCC3C5A407FC85D6B15 -:10F5300045940FE60C01C7553449C6F8E38F0D45D5 -:10F5400059B0DE851326567F9F0DC309F85CC2F1C2 -:10F550005E426A517F2557BFFC323B0BCE2508EA3D -:10F56000BF4B5C84DC41EDB8926C21100DF16A1246 -:10F57000F1C68E073FB9408E6BFCE4DA3CFC6E4965 -:10F580000AC3E9AB7E6FFCE59F9DFE17E567C729BF -:10F590009174423A12BB97D476F77C3FC3634DA572 -:10F5A000E04B43BA0BC8EAFBD30566B60FFEEB8708 -:10F5B00013904FE6FC744C2CF30764E27DC41A6E82 -:10F5C000375CF23A62C10F76C99FCECF73F36C6A93 -:10F5D000BEAAA487B81DFE9F109748D3EE7CA15108 -:10F5E000043B8B04D1FFEBCD8FC27BC5FA76A3CC55 -:10F5F00006BEAF6BD12F003F11EEAFF27994D2A6C9 -:10F60000B1F1AA755B7BC759696CCF7580DF71D585 -:10F61000F9DDB7C52FD8FD80D743511D054511E64B -:10F620003B89E3AF70F7DFF0FEEA4C7FAA0C7899D4 -:10F63000992F6ACEF99D66EECF984026C0B80A771A -:10F64000DF669B0CEB724074C27DD51AFF45A33B6D -:10F65000C2F9B11E9F001FFCF027646709E0F3C4E4 -:10F660004FA208D8D5EFF173C90CB8CF9181AE1E67 -:10F6700017F81D73CCCC4FB8CE6CC77456618E9CF6 -:10F6800048FBCD68B58F8350B5C1BCFE3AB303CB00 -:10F6900087F0764ABDC195AC5EA7D15E1D69FEBFFD -:10F6A0008B12F87999F37B93847FBD75CBF9A935DB -:10F6B000900BFA41BEE267D1D335C1FD71699AE082 -:10F6C00003F90DF630E60B05D41FDE53EEAFCF6421 -:10F6D0007256A17B3D9EABCDDAF7021EE7787F889C -:10F6E000D387826705BFFAF12AF529BFBA55ED9F86 -:10F6F000BAAB6DDC6BA0DF54FB05BB8182AA963AE6 -:10F700008CB00F6BDA9E90E17CE63E07834BA4A29F -:10F71000B1EAF8837566160FB267FCCDF3804E2E02 -:10F72000AF35812C24AE45176DC087DF33387F0F8E -:10F73000716CDEDF8964D357F0AB0F3CF6F27C5975 -:10F740000D3715E733AB32470677DA0395BBE48113 -:10F750002A7A5A678EC772E5FBE04A07BE0F42FB62 -:10F76000C371781F3711B84F92D1D28EF76C1FA892 -:10F770008D637458D6B2CB88F954CD7B224A3FFAB8 -:10F78000FD34BB501BAFBC30AF6328E0A5D014588C -:10F79000E68C40A793A39473CAAF29275C946EC7E5 -:10F7A000FE7F2427962972A203E3E395F602DFE7A2 -:10F7B0002A393130929C585AE71808EBB07447FA4E -:10F7C00040D8244BDF999A14494EBCEF61E7CC47EF -:10F7D000F97DF6EED9544EDCA09213B3A3904EF40B -:10F7E000ED3E51F6495F724259B7FFCBFCE67D9082 -:10F7F0001311F6F7173A39718FBF18E5C43DB345B9 -:10F80000CDBDAC4FFB94133949F7615E76C644A079 -:10F810009FF7B97D7394DF0B807E405E6446D911FB -:10F820006F7AB9D11B5FFF537FF9FAFF109E15BEA7 -:10F83000BE94DA3FA6D4487448909E97DE47F9BA42 -:10F8400000F4C8F8FAD207B99F53C7678B80CF6618 -:10F85000AAF92C6B5FED6672A1A62DF599B9B4FCDF -:10F86000FE46D909A2F2FE30DFCD52F3DDCCA85E10 -:10F87000F86E19E3BB97FD13507FEA6D7E7FE6FCBF -:10F8800096F2B311CE08F431676E8CE6DEDE897134 -:10F89000BFC9D806FBE53D11CF793FE67AC0C171FB -:10F8A000BFC9047DFA493E9E797C3D2F7848793E58 -:10F8B000C55FDE22A64F576D16117FD5AD6CFF5781 -:10F8C000370B3E07CD178CFF1B9ED756EC60E7B574 -:10F8D00074068539AAF5AF78AFA31ECE092A36087B -:10F8E00078DE0CF71E009FA51C9F25CE0A3C5729E9 -:10F8F0006DD2FAC11BA26D2F901B101EFAC3AB78FC -:10F90000FD425310CF1D0A7F293837209FD4B6AB54 -:10F910001A71FB59B04F2A9A75DF9D0D78AE0437E6 -:10F92000D441AFAD6AD1967BF8BC178B818C6D1436 -:10F930003EF93DB3F3F478F7E8F153F62DF173880F -:10F94000E227F39F879F25FE5D785EF075F1A2C7E1 -:10F95000475D143F1F184F32613F7E6C70217FF16D -:10F96000BE2BE2BB4E8B9E18A9790FE5A71C2FEF8B -:10F9700019DCF583A05EB580F54AD76FD99744F3BB -:10F98000735BC8383866286DD2CAE390FC6F75A0E7 -:10F990007C9F5BBB4580B8DAC5FCBE6099EF097CF3 -:10F9A0003FE6C1E554DED3FA0BC79BDC705E7E28D0 -:10F9B0002A88FC53A1DF9D40BF946FFAF9384E0CA2 -:10F9C0000EE6A39C6A13ECB82F03514C6ED17582DE -:10F9D000776DF64CFE6B015F17E65F6A63EB584389 -:10F9E000D70DF675819FE75B983EF880FF223BE7D5 -:10F9F000F4EF92D9FB380249407EE744FB5C918FDB -:10FA000070EE9A93A45ADF1D9D8CFE37094EFCE0E0 -:10FA1000A3FFFB36EBDBCBBA2AFA4C7FD757C1D317 -:10FA20004EDD3A1F8A6A2F9C80E7728213DF0BF249 -:10FA3000C7E179D1C946F6FECD41AE1FE9F705D839 -:10FA40001FEAF77866C0C0212E7A5A14C69562BFA5 -:10FA5000694C3F53F329FD3B485F376EA986B4A339 -:10FA60005E168E7F74DF6E06B93F4DD0C449D11942 -:10FA7000E1BEFF27C097A3BE023E4936A37C79C8EA -:10FA8000CEBEEE196624F01EDAE53532D2D1BD06BF -:10FA9000C7916CE02F8FC904F6C7E583371E9D3BE5 -:10FAA00000CA45A48FE2F72654836BA598C5AA9196 -:10FAB000E247985C3AC1FBFF1395D7AE6B7897A0ED -:10FAC000077BE27C70BF74B673D75407F85B320FC4 -:10FAD000AD8673CF5979F62347601D1BD8BB4FC73E -:10FAE000D7E4A19DF6D07705DC67C7E87A019CBB17 -:10FAF00067A71E3942C7F7E09A443CB79CEB4ABC63 -:10FB000007CE31E71E149D0E5A6FE15D560B9C7FA8 -:10FB10004E1F2D12B70A2F0F9276F4EFCCADFDEEEB -:10FB2000DDB04FCAA83C84F79CCAFC87A60E84FCB3 -:10FB30007A01DBD778DD46B8E7D9DE74D19849FB86 -:10FB40002FA1F500DD35EB59BD9A8D02BE1758E2A5 -:10FB50007F02F964C946011FC469A7FAAF99C1F5CC -:10FB60008129D1BE9EB6A7F952680F7037C6DD0352 -:10FB7000E79335749CD87E521D9E5397D076B498E7 -:10FB8000B46FFC2EC25BB25E2070AFB06C52EAE381 -:10FB90009300DE41D909E54777FDDC08E39E47FB8A -:10FBA0001B44E12F143BA6427DF203C18EEF2E15BC -:10FBB0005E8BFBBA9BEF3B621FCDE21404A2DCEF2D -:10FBC00093D4F12A25D169B89F4A96D7D5C3BC3AB8 -:10FBD000BC89A906A4A78B4690E32729BEDD547FE4 -:10FBE0003D616471307BBC278C1D2AFEB9323A1D01 -:10FBF000DB2F6ACB413EB39814613C85BB8EE92371 -:10FC00009DABA37CE057EB94ED29F07DCF6A137E8A -:10FC1000BFF02A933B178675A07FFBF47A99C0BD8D -:10FC2000C795EBD3D7C13A9EDE2C3BE1DC407C8EFE -:10FC3000C51194BECAFC647BD633B8A79B197FCB91 -:10FC40007BEEEE02E0DBA5944F99707E5A3E56E2C1 -:10FC500028473EF55C14E34B7A7EA5E753658D1B80 -:10FC600022CBA1650591E5D0D07AEE378D2C9F6B24 -:10FC70008885E9BBE3C978F06316570D9BD704F478 -:10FC8000FC20BB70D01E78F3D39F81DCADB4E23B87 -:10FC900065D5927D9DC0E88300FF9FEBDFF229ECE4 -:10FCA00087B2B951F80ED929580FD8476B13F01CF9 -:10FCB000BBC4578C7857E2794B9BB4F4AEF821EF74 -:10FCC000738BC4A5965F6531C4A5AA77F447946E7B -:10FCD000693FF3DB041FB0CAA33FEADCFF7026E6EE -:10FCE000ED38AEE55C3F586B45BA3EFAC8C5D54025 -:10FCF000B7F37E2810D0DB89D75D0FF2B0BA497018 -:10FD0000809FB8F487AC7D296D0FE33EFA73465FA0 -:10FD100094CE1DB00FAAD73FB11FEB6F141C00FF8C -:10FD2000E88662D427CABC22C1F28D9D684750790B -:10FD300085F1687BBC6212EC83EA55263BB86215FC -:10FD40007A52E8B393BFA740CCCEB1B3683B67B457 -:10FD500003F9B29E2EC53942489E02FDD47819BDE2 -:10FD600075BE2A3B618BF44D9FEC1EBD427F22D0B5 -:10FD70005F6698FEF6ACCF33023D9EF60918679198 -:10FD800007F40BF4F9B2E29F2116B51ED5177DEAF0 -:10FD9000E9B007FDC1CB58E961FA54E8514F87C774 -:10FDA00025720F8CFBA1D551388FBCFA37EF59CE95 -:10FDB000F6199ECFE5D53F9204FBBA446271400A22 -:10FDC0005EAB241637D6635C4FD71907F5677CBA4C -:10FDD00071CC8A0EC9EDF120B7A93E4A02B49FDF6B -:10FDE0006C7E11E32BCFBFD27927EA376F513A00EF -:10FDF000FC6FB69200DA213EE447E5AD22C66913F6 -:10FE00002990354B65BF2B713115BFB222BECBB7E0 -:10FE10009A7C85B47DF9EB27C6625CC20AA67F7B1B -:10FE20005F11D83988B7632CDC3B2A97587C8E5EEB -:10FE30002FF85D34B3C3BBDE8C99037A9BD0CCDE44 -:10FE4000172C6FB95736A9FCBBFBA265A51E9E9364 -:10FE500079E93AC3FB0A303EF5FB764A5C4ED7CBD4 -:10FE60008CFECADB64D4E7CA9BB75C8078CDF263B2 -:10FE700026B4776B9A2F1AC19ECDFBD5ABEC1DC46F -:10FE8000365113A7D7233EAE590C9820AEABB50A16 -:10FE9000CF7168BE13F32D3C1EED6BC66F55FC6A27 -:10FEA000C7EB5E8AC28A6DBFB4E17B85ED9B6C783F -:10FEB0005FAAF9ABE3557BC4C3B534F078B83B4EC9 -:10FEC00013E48F91E3E1CEC13F28217D16AD8D87EC -:10FED00023CD8CBFD17166457A0F35A477BDFAE981 -:10FEE000F310CFDDB5F593E761DC955F5C7E1EE234 -:10FEF0006CA88268073DA5E695F731FE5569171F86 -:10FF0000C3EDA0977F89F1C317FE687202B40B3B63 -:10FF10004EA780FE7161CBDF92202E78D98EA9E8A2 -:10FF2000DF59B63D0FDFBDEDCD9E05FAF5F5237E19 -:10FF300059BF6E7B5AF7603CD079BAEEC027427148 -:10FF40008E2D552C7ED4C1E31B37478E17EF11CF72 -:10FF5000D83AEBAE29C01F5B999ED0675CE361BACB -:10FF60009E37F4631D37F3F8D5963BBE32AEF13CB5 -:10FF7000FC83AED7B8186D7CE8A7AD8B7FF12C94CD -:10FF8000B526F41AD718E807FE9478F4CFA35DD904 -:10FF90003189B0DEFF81F1A4B07E850EE0D79FA647 -:10FFA00080BFF88C1C44BF44708709EF6B96EF3814 -:10FFB0008AFBE9C2F64318EF4D785CF80512FAB1F6 -:10FFC000F85DEE03AAD96865F1907C1D205ED261D0 -:10FFD000C3EF3C2E92D1B5122FD95B9CE4B298347A -:10FFE000FE3E0B8BE7ACDAF8018F3F0CAF9B30097C -:10FFF000D6ABF32BE350153CD8010F13D571C0914C -:020000021000EC -:10000000E3524371C0BA7583F5043E1E8AF3A5F925 -:10001000A110EFE9138E468A2BBFB081C50F5F9008 -:1000200023DF8F56E2826B6274FBD6D7BF78E0BEC7 -:10003000E6F175F1343FC6A1A11B055F5D5723F3BF -:10004000F72763846F64B785EE9B540AFAFB2C4F45 -:10005000C4C07D99D64E23BE93A2D8557CBE5DDC2C -:10006000DFD6F58A8871A2F52D7B90BFEBF9473575 -:100070003F47D18F77231F6F751B931F5D5BAD3E8D -:100080000B85D3B5FB4DA4EBEACD9D18A7BABF797C -:100090009BB14375FE0CF2C3A71A7FD76BBBC62278 -:1000A0003FE7EFA2E9FBD9CAF9638D3F723F359B69 -:1000B0002F6AFAA9F0B618ED96BEFB3B27B9EE05FC -:1000C00078E7DA991E75AE459CE68BD0FFCF626467 -:1000D0006E5737323F3895A3F83E9C95BD0727DA17 -:1000E000A2512F5B669D740CDE215D6635625CCC8F -:1000F000CA3A1E47F3236732ACF74AEBED04C6BB9E -:100100001AF0ABB2EF65BB9B803E27271765AACFDD -:100110006194F11B0718884FBD8FADD306827D4ACD -:1001200024EF5018C79D697F95402EB67B987F9F1E -:100130005C3D3102BEB74BF67D09146E7BBEE00418 -:10014000D76C4FBA67F0437E0697F61D5DBC5347E8 -:10015000E777C969403DD16A08D86915628D6A4F51 -:100160004603D7411C52125EA5C07889C73CE611F0 -:10017000703FD446A8DA0AF59C92E65D95D849927C -:10018000EE9D15727804A5570BA757C55F6765FFED -:10019000A6703BF0FD96B80C5207E4BBD6EA467D4C -:1001A000E2299B0BEF3FD2DF6888938827D14EF579 -:1001B000BB50B45FCD7D3BDAAF261FE7D2E613A676 -:1001C000492723C99B043E8E02D18278889B6AE02E -:1001D000FAB2AB70645278DC7189C41980F23B2C9E -:1001E000788F806E2FAF7A1E168B76DC747C1A3E69 -:1001F000119BD1E135B0716ABEDB8903DF47A7E30C -:100200003DAE1BAF266FB5707E271109F89DC5DC8A -:100210004E38FE2F69F0BD4A2A8A4F224C64C238FC -:10022000E93021DE2596CF83F6AFA96F07EF01EB0A -:100230005F0B870CB5ABEFB5DEC0E5E0114B518A23 -:1002400085EE93ACE1B518B89D9D2CB84E4EA065D7 -:10025000FE01C89FD296E7615C8AD0C8E86AC45A9A -:1002600082FB664490C755AD8A463DD56426DEA81C -:10027000F1703F8E78E5F1D08B8F9F3F395618286B -:1002800028690DA535DACE1FCC352CA68BD00245BA -:1002900014FE108B6B0CF45F3FC39D6C1807D31BCF -:1002A00056BF7728EEDA6BC16368A81BBAFFC0148B -:1002B0006421F82E08F10EDD0F72B851C953C60E35 -:1002C000EF06344687F22E33E5F78D692C7FF3DA9B -:1002D000A1F5F07E4DA7BDE8660B8CC76CBF0ECFB5 -:1002E000C302F19AF7D57B932FCA38476F0CE4C14C -:1002F000FBC7B707D9FBC523ADA17BFC288F3759B6 -:10030000947C00ED8BA2D643C8D7AA5A0E61B901DE -:10031000F2341D9E10C81B42E779BF654C41F2B50F -:10032000145E6B71323CC1B1D03266BFA4C1C3B898 -:10033000FABDD9613C482B6ED0E1E186AF85878557 -:100340006B6FA887F755FA3B6F4A170B005FD373A3 -:100350000CF88EDBC46316F4BFD05F14CA230E679B -:10036000432FF7BC153B85C22957D397D24EA1AB7B -:10037000DEE8269DD8AF63EF836AE9E7DF2DAE871D -:1003800000DE328B2BDD9688F3C77705A6BB8B8BFF -:10039000F213C2744D2CEE09F0AEFE11CB821F5A3F -:1003A00054FEDAE9394BC5343ADE1F0123B8313C3B -:1003B0009FC4E5DEA851749E892E03C6D51FB1B82F -:1003C00057403BDB9C600062CB2612F704410CF7E0 -:1003D000A3EC8FFA1DCC8EAF2F36F856B0F360FC2D -:1003E000BB1D61FAE8D0D14790D1475B27D247B512 -:1003F000BF93D1475B5D6E343F57033BBA9104C74F -:10040000C1BA37590A0BA461946E6282F54037B2C3 -:10041000F7B682C228C4EB3A185F8FF5E1E352E6E3 -:10042000D5DBFA361E48FB7106D899070D781EA653 -:10043000E04DA9B7C3C2E246FFCDE67E11FAA99905 -:10044000D4B11F966FEB813F605C87EDE0CC5DD04F -:10045000DE369BAE9023DC6FE3C115F84E78237F28 -:10046000D73B9604BD20D77BC707DB3F217C80DECE -:100470009301F8E8C4FDF20ABF6796DD26B840CEC6 -:100480000F8F61EF90BC6E6176F5BB1691A74CAFF4 -:10049000493CB85B04FB2B7B9501EB27429AA19E5C -:1004A000FF2A5E5FD2F8DD957555E88972D218781B -:1004B000CFE4F978F71E2DFDC4C7A4A9E029ED1EED -:1004C000F790A245945026EE5DF010C8554A3F3E85 -:1004D0004DBB317214E02D443F943E23AD0F6D7738 -:1004E00088AD6B7C0CE80B5BF62E15F15D8E7EAE55 -:1004F0006B16BC4749EB67C590DAADB47D562C4D01 -:10050000219FC0F303797E084BD33F741A04FA7D10 -:1005100003F7CB9EE5782592FDBA996320CFF4B816 -:10052000ECE418940BCABE856754E05C5BE2E7DB41 -:1005300069C13403AC9BB28FA5A02160A5422B4DAD -:10054000721820CEE15D8FBB08CE0B7BE33BB75F1B -:10055000CBEE81EABF7FCEC7F38DF5EBBFF4B82FAA -:10056000FE39E0B7CADCF1F84C9AAFBEF632FA6950 -:1005700057C454DFFC55EF68E8C7FFEED5DFC40071 -:100580001DFA3F3345BC3F35CECAE8F180670EB651 -:10059000CBE2EF0492814A1CB22ACE15CAB85E861D -:1005A0004B9986DF51CFBA055920ACA7578A87F6F9 -:1005B00031A978AE78AB2EAE55392FBB25C0FC8063 -:1005C00059B1BE42ECEFFA74F6F7493E63FA9299DC -:1005D000FE0FCEA1A6F27333D731FB5E1087590907 -:1005E0008DF9083F3615FD5A3944FBFE41D640AF20 -:1005F0006480F2F454849767D695A713F45B916BEB -:10060000AEC3F94D252AFD0CE546A313F8F1F4D14C -:1006100094FEF9F7CBF4BFE126327F86CACEB8CD7F -:10062000715F51BE466F69C477857EFBB9383F5212 -:10063000FCC563213C1715413C801E8FB90E6195A6 -:10064000D5D113DF7AFCE9F1ADE0518FB79C0F9D56 -:10065000F9F18E9EF8D1E3237C7EE95B0BEB3075DC -:10066000B488F24BC17B4FFCB0F5FAEDB5B49E00F7 -:10067000F442F10DF84C1730BE272B86D34F6C3A5D -:10068000E2370B14C001480F98D7E3558FC7AC046D -:10069000DE3E81D5DF0FF81A89FC00ED2165DDB261 -:1006A000D26BF7C641DEC4E84CD1ABA772BC50BDDB -:1006B0001AF5E6BC442BFA9B40AF9E9A14C65B5ECB -:1006C000151B57DE48CB0B609FFE0AFCD1B1080614 -:1006D000DFC5BC95F05FE0563C5FCAE25905DFB765 -:1006E0007EA6D593A7FA0BCE82FE3DDCE45E6505BF -:1006F0007F8C1087E77914FFC775F8D7B6B36BF313 -:100700007A7CFC0AFE31B927DE147AABB372FD7C29 -:1007100030190AFAF2D8373363817F137F7C44BFE4 -:10072000C4C4634521389C6E919E05E20E7DB7A737 -:100730007F0B3E76904A49151FBB5372AFB3DED88C -:10074000938F29EB3585AFC714E2DD057EA62944DA -:10075000FA4BC81E480DCFFF792BF7B30D2143602C -:100760009E5F581C8CFFF37986E64DD54BE83F9B86 -:10077000F79F6DB6E0FD1B1294BA42784EC3F79313 -:10078000BCC6F8F0386465BD536A09D3E7E6E2FBFE -:10079000D9142FE4CB98F038B6590509DF0FE2E3FE -:1007A00038DF6CF6429CDBD392FB0D2BF83D848343 -:1007B00063717E526014C83F7DF9E5B6BDD5504ED9 -:1007C000EB95603D3EFE0A91F91F823B4CBE1752ED -:1007D0007BD753E9F64639A1D07136DC7BBD01E801 -:1007E0003E28C2B8FDFC5C65E74576CFC145ECAB61 -:1007F000AEA7F0F65D62F702F228DB817A7AFAEDB5 -:100800008B4EF349701EB4D3D3AB22CF1BF8FD5BE4 -:10081000453FBB6875BF0FEBDEC0EFE3FA2F8EBA22 -:100820000ED6E71BD3D5612D5D29F444E9EB38F4EE -:10083000D39DF9F13A50CBDFCBBC9C04F251D1E30C -:10084000C3FA8AEB63A8D79B3E3FDCE6EEB27E8517 -:100850003EAFE8357DD92364AF4446D371CEE3EB98 -:1008600033D7DC2EB38BC6418CD36F8856DECB7367 -:1008700044833E39AF21ED95663857AC637EF90766 -:100880006B658D3DEC86DBBED89EBD673B7FB9B600 -:10089000FC238AEF41F1F8CEADD68E86FD91147E11 -:1008A000CFB767BF062FC8C97923A3317E4EDFAF0C -:1008B0007E7EFA7EF5FD3570FBAAC1D838DAA9D262 -:1008C0004FEC3616477D69CD93CDF0145E6FF8730B -:1008D0009B87B8D47F6FAEA3217A4EA4F7681478B3 -:1008E0000ABEE7C2CB98E00FA895FF1EE99DDD6C1C -:1008F00037F313F4D6EF88603EEA8386A70322E835 -:10090000F5238204F5F0ECA0CBB050630F307BB937 -:10091000873D00EFA4D07C65EB2E660FB4D4A15DBB -:100920005149ED0A903B1BE01D90C17C401968279E -:1009300084EC5E88AFCA867732B95D0C4FA7A537C5 -:10094000B2FA331F4F37358C00BBD59D0C2F93CE99 -:10095000B45DFBA899DA57F5A9248A50FBAAC8769A -:10096000ED77D64EA2DC3BDE25C0BBA434FFA865E4 -:1009700072FFEDEC99B6D18F82BF81DA67B7D95497 -:10098000766F6FFBE3669B03F1D9DBFEE8B417CD0E -:1009900004388ADF82F221E407FE28BEFFA342F476 -:1009A000170B7853E8E5F6E50BD1CE88BAE66A0A6C -:1009B000C49365733A70DBB85F3686C1A9896170EC -:1009C000264A6E37F4D3BDFBEA28F03BBF3BFA045E -:1009D000DA797E2BF3DB1FF49415A9E3DB6B6D0250 -:1009E000A797C010D87F77DCB82701EC956C59C069 -:1009F000F74EFDB2EFE9F199C09F66DB57D2296649 -:100A00004F36E2FD327F5460C8C32A3DCECFDF4D62 -:100A1000F55FDC3F441DFFDC6ECDABB531F822C085 -:100A2000CFCEDC7B0CF480DEE44E58AEB804902BC5 -:100A3000E4EAA1243C5F6ADD67039F68177FE7E073 -:100A40007CEB9EA40534ADDAF29F36B0E3EA383E83 -:100A5000CE4BEDF85E53E57611DF13A1FD263D0088 -:100A60007EEBD68559ECDE1FBBAFA6C8D5F19FEF54 -:100A70001952C49C8978FF4CD137A798BD3E189F66 -:100A8000BF8EFD1DCC29BAF7C96EE5EF93E9F5CF0E -:100A9000676CB2E22FC3F8A96576D64F6FFB2BFBCC -:100AA000B304E253EDBF6C2920C2F8B33F4BC2EF51 -:100AB000E70FA43D5508F63D919D2301AC44F6A2F5 -:100AC0007ECBCFA7E86F2FBC7BBE9367DE6EBD3CAD -:100AD000EB66246E2AD704D0C7DC0398D391C907EC -:100AE00045FFBBF533ADDF55AF072B7232D73F6EF5 -:100AF000D510027877CCC2FB1307248CF7D2EBC950 -:100B0000538305BDE8C34F207D6D6D4D8F017BFE86 -:100B1000DF609F00DDB65EC6F783AA49E01E78C796 -:100B2000A9BA55B40760FC24F37AD8678A3EA1E0DD -:100B3000A5EDEA1EF358DA7FF645837D0505F176CB -:100B4000F02F68574FF8FDC1049067FEA084E707B7 -:100B5000D917F7C62C54F145FF55037E7FFBEA6E8B -:100B6000EDF760FCF5D06E8B81D9CB7BF7FF3D06AE -:100B7000F8D4DB572F21BC903ED1536F46FD3BCFBD -:100B80002A86FCD16ABD9988D98721DE6B6A2C152B -:100B90006B42EFFA70CE87649595F4D42B42782798 -:100BA0002E09F0D0431F56F0ACD3333EB2713D77DF -:100BB00018190FEF5EB65D4DA8C07BC7FE18FB0A83 -:100BC00094CF4C8FEADE7BEEC9E9F0FDA0C8DE9D34 -:100BD000B82AE27EDABDB36278876ADF524E8AEBCA -:100BE0007665D0C50B6FD1FA57F64533FFBAE4BC32 -:100BF0005E7D4F225CDFC7F11518CCCEE9BC83E1E6 -:100C0000BDA86FACCF74F5B0F7FF61433D39580014 -:100C1000E262D4FA4E23ACFFBFD98A3E67FCA52519 -:100C200006F88B97E40E21B4DFB268920B7415AC12 -:100C30002376B033B61F3018605D3237A5625CCFC3 -:100C40002BFC1C73494BA3315545174BF839D81968 -:100C5000D99B12AFFABE3296F19733FBCA7F8171EE -:100C60001D7F34919111F4D085B14CFE6E337AA77B -:100C70006F867AC70D78DF68EFFE5FEF877793970F -:100C80001C738C03BFE09458B60FDA0EBE520F717E -:100C9000C16D1F82D4A2726663B168A0FDBE451CFF -:100CA000CCAF7798FDBDD6903F94B812609E37C503 -:100CB00032BEFDD60183E6DCEC2DFEBEEFF5B18C35 -:100CC0000FA5C632BFDAD603B9090B70FFB947C406 -:100CD000821FF064473D6C45C50FA8E86F930F6F06 -:100CE0009D3E86FE737297C10ECBED38FC8208F3F1 -:100CF000759C21244E203DF4390A6FAC1ADE5B5DF1 -:100D00000C1E1DC76ED8AF0AFEA904FE7106CDBF2A -:100D1000D52EC5433C98827F651E4AFF8E16E2DAC7 -:100D200060C1ADE4DAFA15FE68E5EF314CB013E5C9 -:100D3000EF33205D6EB7B96E89C5726F0AE4CFECF0 -:100D4000637AD2362E4F4972F170C09FB24EF3795A -:100D5000AA8CA7B7FEEFE7E354D2AF4BD7AFC80ECC -:100D60002FD2CD76164FEEF006CCE91077D6968EC0 -:100D70007F9F4A15977B3F8EFF8CF6FDC2B60E8390 -:100D800001EE8F55EF10E250DDEDA7BE1DA233A995 -:100D900005E9AFED18C17D5CDEFC5DE68FA4729FB6 -:100DA000BFEB86E7EBB07FF839FB2081A693FD1BF4 -:100DB000560E41FC066CB0AFC278A2FB06D2DA46F2 -:100DC00023D0EB92652C2DE5E7D54B9ADCB83F4B51 -:100DD000D6B378C465B1A94C3E737A2586E8C1F8CC -:100DE000DEBA4D7B8FF01F5C7E9E6D7D6A0FF44BEB -:100DF000E9EBFB808F9BDA9E5807C355E8F5EC467C -:100E000019E194456BCFF33DB1CCCFB8FD30A3F7DA -:100E1000C91BE55C784F6CB297D8C1BFFDD6C64DF3 -:100E200022F0EFB7809E53D93E07797B66DF6331AE -:100E3000DF07F9D66920E047DF6624655B54FB6273 -:100E4000EF863734FBB7BCB96E3AFAEB3BE205E00C -:100E5000F3CABE55F0BECDE8BC0DF7FF9DBAFD9FAD -:100E6000CFDAB7C2BAD07A4FF1FDFFD434BAFFE976 -:100E7000A7B88D7102C0D9668CFCCEDC4BDF90FE2A -:100E8000427CB5A3075F7D2996F91F6CE9B4FFEAA0 -:100E90003B2EA1FF21343E4E374FE52B74932A00A1 -:100EA000FE1BE90A8E007C51BC023D533D7AFECC0C -:100EB0000CDC9507243CFFE1E74B3C2E0477946A59 -:100EC000BF86F999B26FDD6FC038B2F26B57829E60 -:100ED0009F50E845FA3C2BB887C753797616F671D0 -:100EE000047EB08EE3E38AECEEEB7DFFC140CF657C -:100EF000D46284F990F5821DD6452977AC67EFBDA1 -:100F00001EE6F094EF87BF2DBE833DDE213DCCF081 -:100F10001D34425CEB281F936344C8C5FD400CB7E9 -:100F20000F867DB684CAAFFB55F2EBACDC8874AAA1 -:100F3000E0E123CEB7AEC4B1793FCEC7E9071F5D6C -:100F4000A20AFF8224096C3F8B02DBE722C03FBB71 -:100F5000EFA6DB90DEEF884CEF76B0B7E2E1EF472B -:100F60006D40FA8C9B66C77B2F4F49CEA8388D7E8B -:100F7000E4C374EFA667D0CE03FA85FDDE1BFD97B0 -:100F800001FD930874EFA374AF5A3F850E285DFCF2 -:100F90001DF0A57CD7D385720EA9E0659BEE1C736E -:100FA000AA9DE1E9FF00528D6EB5008000000000AF -:100FB0001F8B08000000000000FFBD7D097C54D598 -:100FC000D5F87DF366C93233994C76B230490CA01E -:100FD0002C0E4980B0D84E08204A88C352D7A0931F -:100FE00000094B36109556948120068B18152DB6A6 -:100FF000208385EF431B6D10A858832610112D62A6 -:10100000DCB17FA54190454122A81FED87F53BE764 -:10101000DC7B33336F26026AFFE1C7EFE6DE77DF62 -:101020005DCE7ECF39F7C56ED3313684310763AEDE -:10103000E6018C7D8F3FBFF4978C2DA1E77337CFEE -:101040005E712482D1CFF7F0BFBA795E50BD76C70A -:10105000AF571CE9E7AFCFC55F52E0FF71A66789C4 -:101060008C55F147AC4CEF89B525C0FB119DD66C72 -:1010700098B466E2196384039F781983F66F631C42 -:10108000543EAA6FDED32B1FCA31CCE985A6399B0B -:1010900033158F99B105361BAD67F927D393DDB0B2 -:1010A000DE46C6C6E3BA9BC57C72DDD93685C699D5 -:1010B000E029738F898367664F9E7BA0FFF90766DF -:1010C0004F966D88BF3EA170BEEA18404B8CC47E1F -:1010D0006355980CE69FBFC9E4336532B6059FC4DB -:1010E000C32ADBA37C9B32FDEFD9F4CCA5B73396A2 -:1010F0006BCBA475C1EA5AB1EE58686497C1BCDFE6 -:101100006696B59BE1D1D51DDEE281B08F2D46EF0D -:10111000D489993898F31A1CFF9A629DED01586A98 -:10112000ACCBA63807D092695EB68FCF9397EDEC23 -:10113000CFB2A1EE70E6B92D8C8D12F862AD30C938 -:10114000703F1C42F1C6E1D9135E17207C86501710 -:101150007A7EE2D5A81B7D66FFF34401BF2F63783A -:10116000F9ADC1D3DB660E1D27603E554966CCCA7A -:101170003C4B555CFF2866DBE4F03F778C622E1C0D -:101180007F9A1857B6CBFA8FA6AFAE10FA9A867828 -:10119000AD8EE822BAEA53D06974C0BC4C19DD8B1D -:1011A000C1FA98EEDA5EAC80BAEA71BD0048552902 -:1011B000E0EBC7F6848D33D7239ED90113CBC90C3E -:1011C000DD67B5CDC0E1B6D130FA66E897E065B825 -:1011D00003C08B83E38535DE8AF86BDC686288D7D1 -:1011E0006F6339DCAC53D96803F4B7427F24F7C688 -:1011F000A99E035741BD31D9E850609E13862EC287 -:10120000FB89ABA08DE8C3AD20BE4FBC3AE29ADFAC -:1012100040BB77A28EE5C08B5B8DB005A4C3BFA792 -:10122000F9362948A72DC427F3C7B2C12678DEBEF8 -:101230006918D1D5ACE22C05E976CEE658059FDBDE -:10124000C7D8742AF3EF63D84295E813F8A0DE16E6 -:10125000808F61DE3A15E1D53BCE936C8865EC1149 -:10126000DB35E323D281CE3259241BCCD843505FE7 -:1012700009706BB4BB14164BF506730AF121632396 -:1012800008AEAD0CF0D418D55D774560FF2C5E7FBD -:10129000A4F1EA868634C69E897135229E3E30BB13 -:1012A0001FC1F98726D5A944E782AE7F80CE7E1282 -:1012B000BDD42E2C6287F3E0F70E660EA41B904778 -:1012C000B76E06F895E83D9B705D35BD8E3E8EC3CA -:1012D000D5B67C65F484A17BB98E782117D8C78CEC -:1012E000F011EFAE53CBCD7EB9B3C566174CED52BE -:1012F000265BFCFC8672EB7933973B59509A229817 -:10130000D762C77E3EA223ACC7E4FAE5D1CA62DD4C -:10131000785F183E7E0D89EB6794CFACE57FFFF2D6 -:101320009BA1D01F7F57899F5EE3FCC4E5F5A3C551 -:101330009F26223C9093F0BDDBC51CEB973ADFEA79 -:101340008B74B95F659BA03ED864F42A31B86DE612 -:10135000B0258AF1900D5B9456CB20A8FF4B612EEF -:10136000C0C3E97FA954AEBFD73D3E13DEAFD9A1BC -:10137000732E857E352D0AF183B337F345001D3773 -:101380004759073118AF70B7D96580F6D34A04C9F9 -:10139000659C00D76190EB2FE8CA6882E7F52DC005 -:1013A0007F503D5D08A8C6F5EA9D316C801FBE8365 -:1013B000DE7CB41FEC00DA1B9DC8674F45F2F19F3D -:1013C0008ACCF081108352BEE788014A6159826E4F -:1013D000F47AC662004F5078B11CB530DBA5073CEB -:1013E0002B7AE63500BE4675B5AA089FAC2E878ECF -:1013F00099FDF3E9BB18ED3B4BEFD03903F4D5D69B -:10140000BDCFAB7A80EBD0318DF52A9489319E6FB8 -:1014100010DE2346D5D5637B5CB157F540FF7CA534 -:101420006EB705E9EC1AE644B92AF924AE93B5C1C2 -:101430007259EC814E9715DA471C77B50D80FDC7C0 -:10144000B89982E349FD0D7CC662910EE35DCA4402 -:101450001867E83F18C1478EB375EF6805F93EBEBF -:10146000638CE218104AE76B98E3B738AE779FCEEB -:1014700089F8753433D70694137FBA620CC24BF6E1 -:10148000EF1DCBF5CA488FA7084415EE2706E71DC8 -:101490007EA36FB701D6336C9677B7D111B09FD9C1 -:1014A0008CC64BEDF4D23E520E780AB1CCB6C6D201 -:1014B00038238EB7B60D807E4975B01F684FEF7820 -:1014C0004F41B8A6D7752888CFAD7B77D17AD33A6C -:1014D000DA7929F8EB79611774DB03561DED23DB0C -:1014E000CAF5CDF2535C6F66C77AB2AD09FE7D2CAA -:1014F0002FF424D7C1F86BF66675EF17E5EE952843 -:10150000E403E4526EAC91C6B9CBEAE98FFBABBD04 -:10151000B1730FD2E0F37BDFB1127FB4C4137E133B -:10152000F77D4AF8485C48BA98ADD9375F4179B140 -:10153000A61470A684C259CA8D35B87EA21F5BF46A -:1015400024A0CF27ED9E82D8407BA5CC1E9D1520E0 -:1015500097E47B8F2F66EE19B09061EDE55B59162D -:10156000C9F77EB101F27DC2C0FB22919E9A2C2E5A -:1015700017B69F56D88D38CF335842FB33065E9747 -:10158000F07A40E0333B7652B6750887930DE8F861 -:101590009948DE4F2B8FEE8DD509BB83D30BEBE043 -:1015A000F482FB08B4BF66C6723C8C74798AF49CE2 -:1015B0004EA6E2FE8617F87623DD0E1BEFDD8DF4D6 -:1015C0009FCE049D8CE774A2A5F7DB63B97C1D71E7 -:1015D000BC8B21DCF315E60E67EF54C672BB29BE47 -:1015E0006334D10FF04319CE3734B54E35A0DC66E5 -:1015F000B609A87F7E13EBA07E7905AEDD486F3675 -:10160000979BF879BED9C6E92693D307BC3F271C20 -:101610003F6D433E1AE0E7A378A44773283DDE26DA -:10162000E0F41B01DFD0F13D77E1F8F11D3A9702BC -:10163000830C3B60F631E83A6C01E849E45306F468 -:101640000F0BB4CFB215229FA5563915C4EB02B3C8 -:10165000FB1EDCD772948DF948CF3A5F3DBC976C86 -:101660007311FE7EB49E6867116C68909DF5402CE6 -:10167000B7E35795A1BC7EFA5B23CA5387E4BFBD8D -:10168000B9D1E501F4F1C7507C3F120EDF5A39A7FA -:10169000C5B75F2E04CB3980D75A8E0F6EE7C77758 -:1016A0002C50B97C08966B3DE123443E083CFCC1BC -:1016B000ECDA84EBCCC64540E91DCDFA617B4FFAEC -:1016C000F8C558F34FB3672FAC8F5F8C4D08D5C763 -:1016D000BA88AED7158047758BEA50610BF58BEC55 -:1016E0002EC4FFFA66C58976E1EE1695E861FDF233 -:1016F00028D29B72BD5F6E8F19C4AE8452F03F6BCF -:101700008F257D5A1B2BE65F06BFC0FCA76DBCBAB8 -:10171000DDE6793D500EAD6FF92612E1DC3F5971DF -:101720001D41BB4AAB8F81851478DF84BF2908D760 -:10173000C10D2A32D6F59EAD2695F0F62E8E378C49 -:1017400075BE330AD6F5A7A6D1BA407BEBEC8EAFB7 -:101750006FDD05EBAF8DE6FAB9369AEBE7D3BBCE7A -:10176000F7417ABB76E174927BC3F49E8F03E5DC8C -:101770001BFD0E7339CC4A6D47FBE3D42EE5FB68A5 -:1017800000A135A29F1EED0A35CAA906DB15441C2F -:10179000F539001F845F5B14C1AF3E07F82E93D666 -:1017A0007902D7D96E31B214683F0BFC88FDE4BAD8 -:1017B0007FC47ACF845F6F9AED68B4A00BD5BFBEAB -:1017C0006EBC201E607CD5A2A77D9C66514EC4676E -:1017D000B3D1C510FFDE83C23E1078AB113477BAA7 -:1017E00065C8010FEC6FFD813427BE7F7AC7D948E9 -:1017F0009D19ED478F6A877DA9E95D56D487BB5B4C -:10180000CE5EDE3980E49BC10EEB3BBBEFB0DD3337 -:10181000E047EDCF6ABF88FDD5EACD0D817622AADB -:101820005952941A3A525ADAFEA90C22FE63280F32 -:10183000BD19CC570FFB5E3E50D0D354E640BED707 -:10184000E27BBBCD9D610FE0DBCD36B703D785F3DF -:10185000A4E6D23EB3B03EE8CDE979061DEE6F0CAA -:1018600043BD29ED3DB94FB4C72373FDFB93F65E2D -:10187000F7FE73CE0FDAC768DF83EC740E742CC5E5 -:10188000735A2D2885073203F7DF4A78A916FBAC77 -:101890008E30B7AAB02FB6CD70B253CA83ACD07D0C -:1018A000009E86F37D380F7810CF7F373BEB114ECB -:1018B000FA0E1BDAAFB0AF91B80F5650968C70F895 -:1018C000C0EC9A8CF2FE99258CE8FAF4B3CCF714AC -:1018D0006C7A4BBB8EE86603BB82E8FF0ADD995B3E -:1018E000DD66E2EBB1F87E7E47A30EE56F8ECFA1F9 -:1018F00043B97A7947B34E47F4E0192FE074560F95 -:10190000EBEBDF54A7FE48BA98149E2E42F0F6ABDC -:1019100040BC49B88D12F4300AE18632B94B7FB22F -:1019200033C20F37C00B4BB5878EC7586706C2A9A5 -:10193000EDC5637D3A61BC9A978FDD8A70A9F9ABDA -:10194000898861CC5F2F8F41BAFFB230BC5D737262 -:10195000719D5B0FC478AB3D8BE47B15EB30A2BD72 -:101960000072DDAD0F90EBD28EDB67E828C6F1F791 -:101970000D51D91280F359E7B02416465FC8723F63 -:10198000DA6D39007FF455E1F9E4C5FC186E47DAE9 -:1019900083FC5AB2DCB778967B8CA1E7F1F60D8E0A -:1019A000247F4EB1C61E7AC8CEED8DA7ED5CCF81E7 -:1019B0006076E13A4FFDC5E2F342D3A9DCF7AD0C06 -:1019C000E0746ADBBB795EA0A353ACE3F69790DFCB -:1019D000BE36D3B9AE78F0FB794B2C7EFEBC8AFBC9 -:1019E00052D8552FBC697540FFE22DBBE3BD01F015 -:1019F000BB8AE9BFEEA6EB4C9C97EF8FE93BFB203F -:101A00003ED84B27121D5016BFF86A3CA703383743 -:101A10000D45FF14E78F3F635380DD5DBCB0C63DCD -:101A2000262FC01F732E92F902EBFA0E231E89ABEC -:101A3000CF99A9FD76BB259EE44D2FD60BE54D8FA2 -:101A4000F0BA48786ADB253CF70D3E9181F6C597E0 -:101A50003DD8C507ECC17EAF37167BDC6372FCF561 -:101A6000BF7DA7DEE60EF35E8B18FFAC737812DA4B -:101A70007DC5C6D6CBC2F9E1E439530BA737CE57A3 -:101A800046E3B87F39671A1F6E5DDBEDBA9FE63F0C -:101A9000D807AB0AB00B4BF49E37EDDC5FB06A326F -:101AA000D46B2E3F3B8ECED9925E84DCBB8A79DB31 -:101AB000907FB5F421F1FDBEC45B2A4B45BC3D6966 -:101AC0007770BA11FC20F9430B476D39C1C83CE16E -:101AD000CE03CF75C3359279411EDEBEC1407AFE7A -:101AE000CDF31F4ECD037A3FB6D6605B0A53CE5A74 -:101AF000B73BED51F4A70D36D914A81F73B45E8619 -:101B00007C5FB94E75233D1C5B7B7BE27428BF0074 -:101B1000FEAD8275546E3050FBAC0D7750FB09C1A1 -:101B2000D795EB12FAA3BC7CB3FD8144C4E3ACEFC0 -:101B3000EEBF1EF1B2C568EB3F18CAAA26C53D2606 -:101B400000DE73364606D5B7E8D82CDC87C42B53A5 -:101B50003CDDCF1DB01E63DC4FC4636B881FD518FE -:101B6000C7EDCC9229B0EF9A2167C9BEDFBD278AA5 -:101B7000F4C92B6695ECC8D6C1FFF3B72BA15EF470 -:101B80009DDE49369EC0F358816786CE40A08F8A7D -:101B9000085E2F7A514F766891452578B7825C1D93 -:101BA000434ADE651E0BFD7E21DF5347AD1E0EFD51 -:101BB000C6C61818EAA15FB4CE2966A0277F794E61 -:101BC000FF6967C07E4633971EEDE24266086A5F92 -:101BD00011657D0AED5A184C8FFAB02822F8F9D811 -:101BE000CBAE3D81F6C4585B70BBA4BF9C38A0BF90 -:101BF000FE7EB9B17BCFE78F4C807D56EC53C99EFA -:101C0000BE905CDE8FFBCA417CBF51DA04EFBD2978 -:101C1000A0F3E6F963CB5290BE0A14867EAE63E76A -:101C2000C3F3E55C419F8C019EFBF9F13CD139BBCC -:101C3000BB8E6C7F5DC1BCEE3AAEFFE2E5D90FCB47 -:101C4000AB4E3BF76F68F587967FFE53FAA378F0AB -:101C5000AB195E0B95FF85E5C92D5CFE6AE58556DF -:101C60005FC87569D75B7D4E0DD213CF0979E2D776 -:101C700017467AFE339E8F6BE286849E8FC19E212B -:101C8000787987EAE95C0E76D7EDD86F80D911575D -:101C9000084B5A66CB8A46B9D664F1DC1917E0972F -:101CA000EADFD4A843F9D1EDAF3104FB6DE4F9F5D7 -:101CB0009E38BEFFF2385E87F32B9DFB3744799246 -:101CC000F5386F2FA333307E25CBFB85FC9076AFA4 -:101CD000B477A59D2BED597D03B767B363DD417ED6 -:101CE00033D6AF5F903F18ED74E473EFAE28DAE7B8 -:101CF000678A7B10F26915733D1417A007EB0D7C02 -:101D0000FDDAF5BC1627EC13E6263B41B6CF1C1DC9 -:101D10005E9E6F8DD353FFC2C76FCA403BEEB3B612 -:101D20009B3350CE7EA6F1FFF6C40F0F0B7E7D5085 -:101D3000E89358E1277808F908EAC0EDAE2DF0FEE7 -:101D40008AC56EE2ABDF2EBE91CA47172FA4E78F7C -:101D5000C565D2FCB6C277DCD900A7232B55D217B4 -:101D6000338DEE3EB1F0DE91081DF91B0ED799C7F9 -:101D70006F33633BA3F3E5CCC7276CF206F8011F72 -:101D8000C37D0CE9799FAF09BC5E2A9D56B34E2BEB -:101D9000EAAD6E7A3D10A2B7DB112FA7596722F684 -:101DA000AB553AFA3429A1F33FC85CAF61BF662353 -:101DB000EB8F7CD31CC5F592B6DF9B027FABD09E28 -:101DC00085F233D45F61E4CC3B825E7B5B5DEFC424 -:101DD00091BC3393DD4EEB56294EF43ECE07E7B46B -:101DE0000FF139C689D05F976DB575C755F879C7BA -:101DF000FD715C187F5C4FFE1FED3AEE89E770D5F0 -:101E0000FA856429FD42C7C47E16C5D982FC44E820 -:101E10000F0FE70FBA3ADE48FBDB10D5E9C5B8A8CB -:101E2000F7667E3E4F1AE555D0DF955ADC5888FE9E -:101E3000B07FC6713FA67DBC2719CFF1BD928D4EF4 -:101E4000F4E35C2C3F0E6876F138814747EB58D3BA -:101E5000E18DEC03EB4AECF0141AA134C426D2F85D -:101E600049AC6E09E20DFA1130F2DBA37C8A3C74B6 -:101E700043973C214761A591C877DBAD1E533CBC1D -:101E80003774465D3DFAED53AB783CE284E2E96D90 -:101E9000CF0E8D1BCB32395EF0AF88BBE66F34D0EE -:101EA000BAF2373E46F1D1FC8D57EB950039941FBD -:101EB0006FA0FE275E9DD39BFC181F858FBF0E88E9 -:101EC000E7F462461FE1108A8786A5BF7EF13F31A5 -:101ED000AEDC09F650B03CEF173F24206FA1FA0C9E -:101EE000C9737D3CD7237FC07C0558D31F66C87C4F -:101EF000850DE48FDD6A6CBE06E351DE1A1D43BC1E -:101F0000B7EFF92BC56B67CD7050BCB6FBFD7DCF2D -:101F10002CC7F63FCC628311FE29BE8715F4CF7C17 -:101F20001BC9E3C9DF6E32B125B0A5D96F37533C69 -:101F3000784D958EA17CD1EE1B6632E8785CDBA0F3 -:101F40002BE0F8473928F10E0464447C48BC21FC9E -:101F5000B698316EFC02AD5FAECB807EF004DCC77C -:101F6000966B904E7A55D915F417C8755D489F4CFD -:101F70008AFF69FAE467D4C3B7C55F9C1E9E81746B -:101F8000AED5C35AFDDB64715562BF0BE9E1134264 -:101F9000FE4D89D7C443307E16066FC7841C0CF0F3 -:101FA0008FDF19FF23FCE31FA11C09E31F7FC6C8B5 -:101FB000E56FA39DDD36290CBFBC27E6D7ADEE3219 -:101FC000A2FE8C6F51C2CAB36CAB51C61357E0FA74 -:101FD00064FC442B8FC3C0B711FB5FDED4BA0B7B0C -:101FE000E5C65E168DE6DB15DFC3B937CC3C6B0466 -:101FF0009F3B16308AA33AEA18C92BA8FBB893B0C6 -:1020000095F223001F4FE0B8178A639DB615921D05 -:1020100024E35686D8E0F3F89E78D9CFF547C46F0D -:102020007A0F7AE24F625DB0FF67B05FFC02161470 -:102030009F917199F83AAF62CC4775C4C8DFDA3B1B -:10204000CEB304F33FBA8633E753508F29B515A2B8 -:102050003CB5CF72B661FC66F929EE9F5F3E8FF901 -:10206000962A0179059E2CCA0342BC05FA07760A16 -:10207000F9B653AC1BF4E45FE3F9BA5AE203F4A4F3 -:10208000C4876E75AB4A78ED0AAFA702F0DAFE435B -:1020900078FD19F9F29D8BE4CB0F2F856EFE7191BF -:1020A00074F34B8C6F0C093BDF678857ED7C4067FE -:1020B0004783F8BE073ADB7889F1D2F9E69FA8A7F3 -:1020C00042E1FA5D7C42285C5716EBFA91BC6651FE -:1020D000CE707AD59660FE4FE791D812865C7A1E54 -:1020E000C9FA7B3B8D8867190791EBD5E68FC8F657 -:1020F0009A16250FCF9F85BBCFD339E074DBBFE89D -:102100001C109A07C2E79D0FE48DFC39561DD0DCE8 -:102110000AFC77A6C948277595397E370AFDF77BF3 -:102120000DCCE7A0FE11D8FF0AC6FB5FD1B4BC03FB -:10213000FD575730BD579C4795EFB91D15837C7CE3 -:10214000C55E95F2BFD866FEBC8E452C41FF744C2F -:10215000818E3902E019EB8A628E0078C68DB7074E -:10216000D5E53979AE9837C1DD2BE8FDA41BB382E4 -:10217000FAA778AE087A9E3A2B37A89E5E3722A837 -:102180007FEF85A383EA99DE6B83FA67374C0EAA4B -:10219000E734DE1CD4FF18AB7B7C14ECB33FFA5B56 -:1021A000003FCCEBEAB80CD63B43ACB7EF9AF2A0B9 -:1021B000F781FD5A311E385390C917CF8DDFAB0020 -:1021C0001C6708FFCEE5BE3941E3CF55AB887E677B -:1021D000361A8E04FA69F4AC6B4F2AC0B9C6A73818 -:1021E0005BA15EB926F8F9EC1D1BE8BDD9BEE0F68F -:1021F000B99B83EB83DE9CD29FE701B929BF72466E -:1022000042B0DF8785D08999E4F499B5DCFFA57ADF -:10221000FB6AE824185FEC27D28D43D08D293998CA -:102220006E221DC17453F9FAD6A108072DFCA3FB39 -:1022300069E8C90BFF7E00FE1667307D69E14EFB41 -:10224000837556EC50D8EF9550B8CF6A7978792AD3 -:102250000B853B633E23D71FC1ED8F68E0FD81D91D -:10226000F318CA89B33B16A8188763E3793CFFECDF -:102270008EAF07ED7384892FE584C497D62504F8C3 -:102280007F647CE934C619AF64171167DCFD4F84A5 -:1022900007C8008F01F3110B9C11DD71C5487F3C0D -:1022A000492B3F6509FAE3B904D22BFE786C3DBC9B -:1022B0003D34E60337AE53C6E564BE8ECC2B0A939D -:1022C0009FFC978404CC0FB447E3F9754BFB7C3A31 -:1022D00077C9BC2226F202C3D8FFA44F9AF1D714C3 -:1022E000B20B762670BDFE0A8ED76D1788BC2FA95B -:1022F000D77B1A47C6DF7A2A955D2AC513BB942877 -:10230000E75361F4CA47093F51BF85E68F7F14A8A0 -:10231000476AEE38BB07F50BC0FD636CB758406FDA -:102320002B7EBDFDBB682BD16BD7EBAAAF2F349CA6 -:102330008970C4D8018E2D22DFAF45E4FBC9F5D6E4 -:1023400045A4BAF479D81E9CFF27E38ADAFD8DC232 -:10235000FE71FE3ABC1764972CCFE576DB690187E6 -:102360000D166E271813B99D50AB391FD53670FB6B -:102370000CA4D7AC9680718C8916EADFDF5C684CC0 -:10238000C47184DF6579A64276C57245217BE47706 -:10239000B6D1F4FCCF09858644E8FF6F31AF1160F8 -:1023A000886563165F8F439317FE92E8FF52C268F9 -:1023B0002A8D8936E17FB65D81F4916A7619A95D2F -:1023C0000D1FA78A4EE4FB1A29F264B47180714292 -:1023D0006EA2DFDFC4EDD2E2B18941FEFEF78CF1DF -:1023E000C2DFAFD0EB2E9453BF1478EFC9FFEFEAF2 -:1023F000676B47F1ADF5FFAF8CE4FE7F191F08F165 -:10240000FF3BC785F5FF231EA2ED7EFEE993D82D85 -:102410009FD2503EED307AEAF1FCD5B51DEC7868DC -:10242000EEE7EBA4B8C0C07DD94E3C672DCF64BBAE -:102430002C486F4B18433B7F47A76E69243C5FE9EC -:1024400065367C3E7C2D3FBF55AE7138719B520E78 -:102450005C9DC8FD8706381F5B72F1BDC96D1827EA -:10246000583995D9510D35B2C6222BDA456B59D85A -:10247000F3E368414F130A7751FE764217CFB70F47 -:10248000EDA793767E21E2735897E72C8FCF717971 -:10249000422211CFA9ED3A5FB8737DB2ADE86AA4CC -:1024A000AF81BEF0E78891C24FE632BB27E2F80366 -:1024B000B7F17CD84A297F67E8981EF03E45E07561 -:1024C000CA5A9ED7C1CE7FFFBD2AED4546E333945D -:1024D0002B95532D3EF41355B6647A695D6EC599FC -:1024E00083F2A2E56D37D62BF3F36DE89770FD9D6F -:1024F0002947FB91A9C9B8FCD2B3A3529E901E8F65 -:10250000A738D464416F23F1B09C40727E6534C01B -:10251000BB72ED925D98D7F3FE1F19C59B0EA85DA7 -:102520004371B05F017016E662A967A5E4B748A6DB -:1025300071A68A71BCFF827923FCF3FEAAE575DAE5 -:10254000CF0103F346001D9DDE798303EDEEE5091F -:1025500011E4CF9371DA83AAE73E5242FAAE1A5CD5 -:10256000DA4D2DD136F4839CDEF9613AC64D3EB981 -:10257000E7AC05EDD87FE8BB2C982F7C7CD1BB164F -:1025800017C0F193452AE59DDD2AF48684FB7D89F9 -:102590001CEE1F27BA1721DC6F5BFCDDD0C03C2A84 -:1025A000B63081E879B64FA5905CB79CDD1C8D16DE -:1025B0004A77BDBA392EA82EF540B589D5853BBFDF -:1025C000BC24E86976D30663AA03E7F7AC42FA387D -:1025D000AEE774747C9BC5E7CDF4AFA7BC69B011BE -:1025E000ED837FB498582BEA337D8781E749BB8A16 -:1025F00015A00B8FC0BF769D7B5E8EA6F1663EC692 -:10260000E54719CCB510E0EB69994D7241BB8F9944 -:102610009F38C625015C67AE5018FAE3B0FF22C0B0 -:102620009F67E1FD5FA1FDA5DD679937580E48F969 -:102630005529F03CBD21F87965CB6F699C19CC43D5 -:1026400079206027699E5F730CF50AD84741ED67D2 -:10265000F6669B518F6F4914F1EDA16CD8F7F0FE2F -:10266000AE88EC184F187E92E5C9C53622D6CF1732 -:102670004750797C31A3725122A7E3AA96B7EF4461 -:102680007BA966C716238E73C9F1819613D69B99D1 -:102690005FEF96E83DAF211ED92C25284E50B3E1BF -:1026A000AC91EC32019F52D15E8AF0003CDCC21C3E -:1026B000ABF13C505A65F0C7E9E0FF5B72BFC36005 -:1026C000BF80DAD1913917B55FB94FB96FF9BC5AEC -:1026D000057A0CF3BEE48345421FCDD83869792FC3 -:1026E0000051FDCE63199DFCBC49F67891C06B5139 -:1026F000C4FD648F1785D8E3EC3DDCB7A4C74AE678 -:10270000243DA2A53B4907CC6CA0F72384BDDE4D38 -:102710006F2D0F125C243DCC5C5D68E4E69BC7C85E -:10272000ED4A6FB2F0D726A3BF16E830C83E06BA0E -:102730000BAA6BEDF12F0D9D19281FB476B8CCE7CD -:10274000D4C2E76022CF5F9AE1708DB30DC0738071 -:102750007B39F985F146CA10E4DBC63D7723DF6E8D -:10276000E47CF30F410FB3923C1149F0DCB3F49ACF -:102770001AC47FE7125306F2B367698A1A0FFD3D48 -:10278000AB1492C3A397A61811CED3970D1E877CC6 -:102790009DCB5C34FEB43816D66E189CC4E54779E0 -:1027A0009D811963082946F40B9F6A50C82F8C9AA3 -:1027B0006422E06B96C057F58AB7ADA4AF1CF06FEA -:1027C000285E1FE03FB3EA2A091F70EE08CBC7520C -:1027D000AF54B166630A8C3B67651BD1319C47825D -:1027E000FAD7B29584AFEA664D7BDDD5843FD8B980 -:1027F00011CF89B53B829FF74F127682933991BEF4 -:102800003D775A2230AF71B4804FD94AC586726B7A -:10281000FAB2B6841BA03E7DAFEA84ED74C387850F -:10282000FA23281FEDCCDE1CF2579C713892B09F22 -:10283000C7CAED5245EF1986EDD3E23CC3D0CFD8DD -:10284000F59185617EDFA1732A73E411950FA2FCD7 -:102850002A1B1B3429C0BE2F33D812311EE965F361 -:1028600093C53DB88840F8D446AC247EA8457E8800 -:10287000F0F3C3348C7BA1DDF3A24279846C473042 -:10288000BD9F703426C29190B9EF33909C2E6F8A11 -:10289000A5F371F9B22223EAD5F26DB1641FC1F933 -:1028A000F4BDCB86FAF1796859DE9E6418B7BC395D -:1028B000D3A906E331F4DC19B0CE390D8724FE8E9E -:1028C000F480BF23E1F007780B6A2F4F127249E0C2 -:1028D0008D2D8A23BD5A3AEFD59C0858D799BA480E -:1028E000CA93ECE97CC4668CA0FC03E9BF1ADFAB99 -:1028F000DBCF44793E67570E21FC69F136FEDFD30A -:1029000087A1BDCBFE6E6168674DCB66B74D86F67D -:10291000DB14CE6FD3EAAF198F76C4DD495C9EBD60 -:102920000572D0D597B1B7410EBA400EBE0BF21169 -:10293000EBEF2F4EA6FA878B1D547EB4B81F954738 -:1029400084BF5FF21D1002D1ED92242E179724C987 -:10295000F8FA82643469C6FFFBDD213A1BDE676C3E -:102960009B30369DB1EB5CC1FAF7C6A9C1FAB5D36D -:10297000601B978CE7DB150AD9A3E5EE9141FDE1D9 -:10298000DC64C47B2BAC5F9EBF9DF486C33819E822 -:10299000F1A6E2B8A0FED737A406D59F4872D0FAB8 -:1029A000268DCF0E6ABFB9B47F50BDEC9C9131A487 -:1029B000774701F1CF0291670407778E171BEFFB72 -:1029C00075DDB0A4BB60BD5FEF33D0732D3E245ED8 -:1029D00067AC519907C69BBE06E41F2CF148E3740F -:1029E000E2AF2F0E58E85CB2BC296F7F01D40F35DF -:1029F00019280FE8D0B2B85568AF1D6A4AB032281E -:102A00003DCB5561D7D88C2C40DE152D5B42F9A605 -:102A1000653E9393EC9776EF93B2EEC0F32A2E12B5 -:102A2000F9E43DD5D7AA10FE5C04DF6722E95EE138 -:102A300071B027F12AE1F44EBEAEE30A5B86F513CE -:102A4000911FF7B90BD6716A6263850EFD15EABE58 -:102A500004929FCFAB0CE9B6749E81F20C66BFAFB7 -:102A60006EC03A53725339BE55CAA366CF98687C7C -:102A7000D6051402FD163C6D7AEA01AEFF787DFBA7 -:102A800040DF03823E918E8EC732572C2D56A1F522 -:102A90007EFE76C2067CEE87A76F10EE7BBDC1FD81 -:102AA0006612E0EFF30ADF20926F8B1288AFB470EA -:102AB0003F62E4F2CB8B7CA0F8E5A69FCF96927E96 -:102AC000986E70263A496EE5A7A0DC3AB2D24076FD -:102AD00030D3BBAC93488F3E4F742CE739A2778C30 -:102AE000C3F51D69C864985F51BE52A5F30AD21F91 -:102AF000EFEFE3E7D487550FD824CCDBA07858520A -:102B000028DDDC3E6F18E55D6AED6D597E09BCEA93 -:102B100009B04BE6ECE479812CBF533F7560E03E91 -:102B200096F1F93C0541F94A5559AF1D34EBC82ED1 -:102B30008CC173C289F754A2B313598D4393019F7B -:102B40002775BB86DE05F52F267A8FEAA13E22DAAD -:102B5000F32F84EB5CDDCA0C250BF3FA0FAF1A09D7 -:102B6000EF7DFEACC1496C2EECFC39CFCCEEFD43C1 -:102B7000F615D81BBDB8DDE14AC1FBCF731DCD1AD8 -:102B80007B80C3C78149200017DB6A056D377678E3 -:102B900088E5013C574FD7314FE079E0B0C8E3B149 -:102BA00024F373A8B41BA6247339335DC7E99BBD16 -:102BB000AC707A03FB2A500F48B93D17F3AA55BFF2 -:102BC0001E9072BB8A3552FE8A2399DB2FB3151FE4 -:102BD000D9DD35988902FD2B6C3C6856B5D9E4F3F4 -:102BE00065D298B640FB607A329727738CCF3E8EC1 -:102BF000E45BC93AF83E35FD3E37F82A3A3243F5F0 -:102C00004F856DC3323B8D6F70A29FB752F06B75CD -:102C1000A3E26B253B85EB51E9579D29F4A8563F6C -:102C200085E8258D3E9AA9D1BBAC3158CFC27AE94F -:102C3000DEB25CAF769DEE680BC1610EAC0BF56F3A -:102C400085C7B7A784D6AD3801A321EBA964EE31BF -:102C5000B1B80F78DEEA085D9F765F21EB15FBD4F3 -:102C6000AEBBC2F9552BE6BB543529042FED3E24EB -:102C70003EB4769CC44B8597C3B7A245217C7ED6D3 -:102C80006D1F32F26F4BBA61CDF02FE07D4947B036 -:102C9000AF12946F95AB411E6786D2D31CD66C459C -:102CA000BAA961ADCB5390DF5A9BAF1F8E7E86B51C -:102CB0006FD3F9A9D4DE9AA38B05507A73578EBFD0 -:102CC000CA4FE7178A27FC5CF0C3DDE9A59F1EE029 -:102CD0003573A3EA8A1C14D44FE43F7A098EB3BC3F -:102CE0005E23FA6367093FE585D659ABE7F75F2EA8 -:102CF000B85E01CF9F7BDD0F27F76477853F17769E -:102D0000DB5B1A3DFFB181FB5BA57CFE5AEF22FF26 -:102D10002EB40B3BACCEC6E37D1AB99E9E4F72BD5E -:102D200042E87939CFD1355B295E3013ED8080F6EA -:102D3000CF566FA578A5F1D99956B4CB8FAE99BE71 -:102D40000AF3528F364D27BD5FF97BA9F73DC64088 -:102D50007BA2684DD9FA7B908E3747525CB1A2DDD9 -:102D600023CE452067A19F630D97AB6C3597B39534 -:102D7000A81F07907EEC8BFDEEACF0F4457E086852 -:102D800027BD79E774CF9F77C2B877FE29DAE925A6 -:102D900050D85A7564CFDB5A513F56CFFFF020DE32 -:102DA000D3017BE0FD5F4B7B00AA45064F5B32EA17 -:102DB00021610754AB1B326C683708BDF11F807F5F -:102DC0004478F8E712FCCB11FE01F1DB4F1B389C75 -:102DD000A76BE07F7825C7CBF2A66C2B9E2F3F6DAB -:102DE000C826BBEBD3A61C82FF8C0700FEDC5F1F4E -:102DF0006C773500FCF17C81F087F596B73B04FCDD -:102E00009D1CFE0D1CEE6C252F6784C0D94BF95715 -:102E100077FED1E4443BE278642BD957C7B7A8AC1E -:102E20003EC02E9376D137ACF149B4DF24FC67F76E -:102E3000E91884F2A7F4E1D7AC8887D95B785031E0 -:102E400004FECC9544F1C7EEF9BBEDA86F115FDD30 -:102E500076D445E2A986B919E9C796D70EE039427A -:102E60007171BF458DBC6FB623F8BE19E69295DA35 -:102E7000D1C5E28C88C0F5A469EFD37918C6BDBE70 -:102E8000CDF9EAD6F9C4E75D4179B925ACD580FE24 -:102E900036D6ACD03DEDEA0585D6428671B53A5AB4 -:102EA00087334509CACBAE5675644F5619457C44E5 -:102EB000E45524897E4929DC2F909C62A3F2742476 -:102EC000237D70DA62F4E17D2A385F25E3FCDE9D24 -:102ED00026C2DB415C13C05F350A3F33A842A4B76A -:102EE0005B18A7D35BCC7B29AE07279775A81FA7D4 -:102EF0002D3439C9CE8D8FA1F8D2CD42DEDD625E90 -:102F0000EE463D31CD6C746109E37A31F9D7301A60 -:102F1000A687F90DBD8C74EFB034A2F3593C12DFD3 -:102F2000967CF88E0858EA95608EA31F187EDDF611 -:102F30007D5C285EFCF809F64BD74685F78B0C17AD -:102F400070505C2EF23F9B60EC2858C7A814076FA6 -:102F500077D8B83F7A2DE0C9E2C7AFB69D7979FC42 -:102F6000B20AF3B1F9F758BC241F545D50BDCAC86A -:102F70009F4F796243F1EA34C6DE618E8188B72AB9 -:102F8000942178EE2F8BF1617CEF3AF487DBB1D49A -:102F900013BD4CD633AF8E970D663B0EC7FDE325B0 -:102FA000029EBF2A60AD3100F7D6D783FDF337B458 -:102FB000EA5AFB027CAFD3B7B6217DEA221C061B7E -:102FC000CCE31EAFE4E239A56AE9C5ADB7E289A654 -:102FD000E2D5A3A0AEE3F9AC5DBFE6FE895B805904 -:102FE000116EB7EA59BB9ACBE900E1526B7778A929 -:102FF000DF3C85E237322E20F13F18860FC4E32DE7 -:10300000627D304E8315DF3786C7D77C812FCC8C0D -:1030100046B8CF157C3757F25B5330BF3D827804FA -:103020003E55D02E06B8DD22CA9EF8E2A1146E47A6 -:103030003F94C2CFEFF75CE27CCCDC95417979829A -:103040005FAA4D7C7C39FF75A27C30C54EE3CBF581 -:1030500000BD7E8AE3E8400220BD1E69AC27FB6804 -:10306000160B88C365FAFB49BA0EAD77CB11DDF7B5 -:10307000581ABB6620E8955F443A518EDE626CCEEA -:10308000A93387F69371E652D661A0EF03493F99C1 -:10309000D03F635533E535952AFC1EF4E9428B5742 -:1030A0000776E2C722BE7B06EC469CA73456A1FCFD -:1030B000AF69317796205F975A8D7A2C3F16F1DFF2 -:1030C0005B59178DFF892D2BE60686DF4D5031E6C3 -:1030D000070BF8A4D805FBAD47F9C3EB2B5D69E4FA -:1030E0008D12F54FF7615C66EA79A003AA1F2E7670 -:1030F000C1BCA75F15CFD991627C7EFA3E41CFDE7D -:10310000E334DEE9C7E4F353FCF90AF9FC2B5E7FF4 -:10311000508E2FEA0F6B9E2FD13C7F82D75B9FF89A -:10312000AAD88BF6EB684EDAA523149257462137BE -:103130004A97B6129C4B75BB78399AB5EAF22FDCE8 -:10314000EF648ADB989280F7CE8F58500FFF33D50B -:10315000654C817E9F2679FE86E59C498AD78872D8 -:10316000F73D1FE985921EF2278D42AE9FEAE5A644 -:10317000F7A51E8371DEC3F12F759CBB43C7F9E42D -:10318000C78C734D6AC838477FCCBEFE9CCAE12409 -:10319000C791765171BA4BE985FC3A666490BF706D -:1031A000EEBDCE18F44B31CC7703D0CF5DDA9C91D5 -:1031B00007E3CF7DEEC58C0AB49B84BEAF39A7323E -:1031C00017C8A3DA730A955FB47D64C47BB335DB9B -:1031D000DA8CE3A05F2D944501EBAA12EB047DA7E6 -:1031E0009F1CA0A78DBD74426E3CCCF3329E3BA1C8 -:1031F000477CCED5351FFD3DEAEF114AD8F8F2974E -:10320000627F077BB81F61EEC5E551616F5734EEF1 -:10321000F314063960FCA2FAF0F902BF12EB28158C -:10322000FA6FFA504B8403E03CE43D1E5FAF589BBD -:10323000998BFE6263F2E804825B8F7ED62EEE6786 -:103240006DE17ED6527BC702FC4E99BB57EC83F8EA -:10325000DDB209BF937C062C0BEF8E37C97ABF898C -:103260006346713F18D6F37E9FF920F2CDDE286EBB -:10327000CF4E1B36300AE5436766B4CE06FCAC4F32 -:103280002A73F74AC0F6ABC6617BA1C9D2A78CE00E -:10329000CB882EF449EEFEB84EEC8FFE118FB1357F -:1032A000E106D887E70D95EE037806457BC2C5CBCE -:1032B0002FEFC5E5B9BB978DE0B15707EBCCF5AF64 -:1032C00043CE0F76FD820E18EFC8D294C10F38306E -:1032D0001E53785DAF04FFFCB3923CA302E73FA20C -:1032E000637DF06871B1EB182EF0711DC2064AF7CC -:1032F00028A0B780F3DEE431D141F5A9C571CC1522 -:10330000E8BF9D9A1A54BFB1343BA8FFCD33FA07EA -:103310003D9F68EAC8AF0BB0677BB697BC049F5A65 -:103320008B250AEDBA4F5ABEF9E016B40337AA4E00 -:10333000B45967EFDCF4C148E87506F01B477E49D5 -:1033400007F9D13E9779747A973E307E748A75502A -:10335000BEA23CD75E6CDC68AEAD9DF2097FAE7854 -:10336000D1BC5EE2FC9BCB72513F9EA97B9FFC7956 -:103370003566BECF532F1EE2DF2D44BD02747F356C -:10338000BE88F6E23910FCC0FF453B0E519CCD864D -:10339000C14DB4F7D3E6E9F1FE642D94A85FC68170 -:1033A000DC8A01BAE9686303B761DE48A685DBE51C -:1033B000E7A690BF7C6F14F7FBEC4D8CA5EF48CCD3 -:1033C0006DB886DA6BCE45D3F86FA91DE3282FFAC6 -:1033D0000585E2131353A72DC5FDEC8DF20EB81D24 -:1033E000E69DF8E7ABC723DC6AB6F17B0213D5771D -:1033F000F2E74159D5780DBD3F51657B15B01F628D -:10340000CEDD42E34E441B00EAEA50CB03A89755B9 -:10341000636B9F3FA0BC315A48DED49E8BA4F72635 -:103420001471FDFD7B214F0C9D7C5D63CF4DA2E7A8 -:10343000922E7CBDB282F2F70D091BF5F8BD214337 -:10344000A742FDAF3DD79F4AB9DF37FAFD91BE2FA6 -:103450006048F87A1CE68DBE11AFD8C82CD1C8E3FD -:10346000B375C362581879D53DCF399E6F6C3AC792 -:10347000F38FFF3BCDF517E4C392459D7A8C17314E -:1034800073840DE1555230D85111C067EAAE9B8C60 -:10349000881FC3EAB78DA8AF4D5016053CAF16F98B -:1034A000585A79DD22E483FC8E9BD43F2C7906D1D7 -:1034B000E7AD3641A0828F9E167C2CDFEFA0330E45 -:1034C000E0713BF7F3B7A679DE4239D151C86E7C83 -:1034D0009EE4674706C6697EAEF5039E2314B21BC1 -:1034E0003B29AFBEA4C0A1C3F8C07BDD7A87F3F34C -:1034F00085F6D126F6FD96CA16E2B86FFDF2971D45 -:103500002E18AFEDEEBC3CD40B72DECF7AF17B0B04 -:10351000CCD6751ECF87B52F473B90EF27E2E10C45 -:10352000E3A23B4D746E81768A77D4BE6C7A0AEF43 -:10353000BBD55AE1FC0AF317BD12D98A74DCF64AEE -:10354000A41EF5C71DBD3D9F217C8A5EE93B06CFC9 -:103550008BAE16939E91FDE33A4AF2B687F55E482C -:103560007E69E94CF2A7A781F34B99A0D372C17F82 -:103570001EC14767EB92880FCF2E8245633C759141 -:1035800032701BDA0B0E0B7D974EF2E5443C1F4167 -:10359000FBC4FEB1748FA1EA5C6C101F569FCB1464 -:1035A000FC1D47ED92DFCA059F98847D3143D0B55D -:1035B000B45B243FB2744F622AEC63623DF0BD9568 -:1035C000E2FEF9C84F7EBA31DA90BE806E922B02CD -:1035D000F8A7BEED2686768A29DE4D743303CA40ED -:1035E0003B6566B79D621B9708EB2F5996A9C37B75 -:1035F0009BF2796AEAA5D17F44AAC82730B7E6A032 -:103600005D6BA88B74E27D9A33F13C1E347F058795 -:10361000E37C83BB08ED8CF94F28E43F43FB03E5D3 -:10362000D2D00375C640BFCA4DE706513C7DCAB92A -:10363000CBA834267B2E4738949DBB5EE06BD08FA1 -:103640008A3F0E7171BF92C167726EC844BF9247C4 -:10365000453C1F4F67B64703E37D6B54F28FC9B8F3 -:10366000A4F43399F0DE4F803EFD46DF9841DFA39E -:10367000D1FA9D0AB9FE3FB9D140FABFAAED9DA18A -:103680003A78FE79A62B09F5C97A83A708F733673C -:10369000B2EF3903D4E73EB8D53ADCE18767B3BE71 -:1036A0003507F56933C011FD5FCD2BD5F13E6EF7BF -:1036B00044F3381AA76F49CF5A3A9F732E9BE07391 -:1036C000B6CE447AE82CD02D0BD04352EF48392F98 -:1036D000F58FA4EB6A3D975FD5E618CA23F3EB9DFF -:1036E00049EE42A4BB7E3C1FD0AF779E5A3502F90B -:1036F000E0743CE55D4BBD21F9E085C5C9944724E4 -:10370000F592E40329CFA57C97742FF5D6E83FFD09 -:10371000EFD6BFC3AF93D23C77A5027D5DABE7FA8E -:10372000EB5ABD85E8676CFC243DD2CDC5CBD143B7 -:10373000428E1E0A92A3353DE88145A9527E5E1C49 -:103740001FCC117C33DEC4ED4894F381E3B5A68D24 -:103750007E08F7B13A95EBD99F6BDD3DC9FFD5A93E -:103760009726FF97A45E9CFCFFEF54FE9D0AADBC1C -:10377000C70F71A3BC3FBDF3721FEA83830CF40330 -:10378000EAC19668C726A10F485F44C5F87E481F66 -:1037900014F69EFEDFA9E1F5C1666CFFB1FA40D2D6 -:1037A00097E41BC927922FB47C24F962C26FE1BC55 -:1037B00088787A8BDF8FAAD67B9B280EE9881E8CAF -:1037C000FCD96DC76D5388DF42F484E01F3FBF040E -:1037D000EB0DC91F925F24FF540BFE9829F843F2AA -:1037E000C56EB5F9D111980A90E6F908E588E49319 -:1037F000AAE7B5FAA147BA424F239B195FC790AE1B -:10380000AAA10CA42B530FFC70F012F5C2BE8BA41E -:10381000A7AFFEF3F4F4550FF474E6A7D053A81D38 -:10382000FB61BE03D673361FE46DA69FDE26FC8DBA -:1038300071FB219B9F07F646F17DEE35A693FF674E -:10384000C2F73CCF57DA033385BF41D2691ED80196 -:103850006943FCF8C7F3C0BC8B937B8467537C87B8 -:1038600011CF2733A10CB4037AB27F53D32E4DEE80 -:10387000458AFE17C2F380B49FDD6E1C90161EAF02 -:1038800003D37E025E2762A22AF92BB24B5CA3000F -:103890003F0F89BAB74F09C2F1FA02F9FCB2552EAF -:1038A0003DCA07D6FDDD75F477BCA5CA7ACEFE31D8 -:1038B000B09E098F32BF1F1D9E8F1D15D3ED1F5166 -:1038C00098BF7F715AD6FE95A4E71B45DE4AA79E96 -:1038D000C783443D1FEA96807A81A6BE96F7B7EA71 -:1038E0003B59603E09D28D92CBF1EC0EB01F60FACD -:1038F000F6B3A82F6C0A43FF466DFC8657CFA25C37 -:10390000DBA1506CAA1B0EDE810407FA3E38D507F6 -:10391000EF775DC6D8CDDB78FDF6B54356792F132A -:10392000E306DC1B32342B2ECA4728507C5999A160 -:10393000F0BE3D4DCA13B91E46F71402DE6798AFBC -:103940007729EF77E74D67D1FBADA64B98FF8651FE -:10395000E1EF6FAC10FDC6E4C7847DFE709ACAE14A -:103960002FFC06343F344D690E7F9FFF09C12F1D88 -:10397000183F21784E5A85FEED0EA384B77B15C201 -:103980007B2C63417E34989FEA1BD7BA4B1AF47C98 -:10399000BB2E0DBC7E68BF77A505DB03F49B065FDD -:1039A000A61F80F7DD61DE7704BFDFFA43F85A1205 -:1039B000F2BEA0DB59928E5D41F41EA377137DC643 -:1039C000C42B36B4A36BDC912BF1BCE0E7CFD21251 -:1039D000829B8C1384F0DFB4923103C84E12CF6FF8 -:1039E0005B85FCEBD675F7E7FC28E91AAF36015C7E -:1039F000C9F507EFBF9C76EB2AF44F025DD073AA9E -:103A0000EB03D6ADE5C7664D7D94867F05FF91FC3F -:103A1000407D0070CA41F9167FC8E808A0934F04A2 -:103A20009C4E897CF28ED1DC9EECC8E2E577693C45 -:103A30002EF599A0CB53929EA202E09016443FF43B -:103A4000F72102F64D70BA295EF2F3BD25C5C0BF5D -:103A50001D76FEFC7FD6FE669537CD5FD78EF7CFFD -:103A6000B5F796205CBAC7F72EDA8F76C44D026E92 -:103A7000DFADBD67BF7780C073A2FFBBAB401FF453 -:103A80003D9E6AA40F25943E5E0DA52FAFE67DFAFC -:103A90003B043DBDFFB75079E0D2BCCFF07B10179F -:103AA000FFBEC05BB106AFE335781DA3A997CABAC4 -:103AB0002F48FE4AB95CBEE3E1FB12E3D1AFA9D0C7 -:103AC00075243F3D3F48F43CD726E97715C1D54FD3 -:103AD000CF0FED47FA9DDC2CE9B591F4CF2494C3C8 -:103AE00023FCF5292887A8FE7009C6C5FCFAEA91CF -:103AF0005528B76F6890FD1FA5FE372F93E3ADA63D -:103B0000E7128F8C3D46FAEEA67CA9AF1E27B93F7F -:103B1000A785BFEF4CFFDDFE1FE487460D5CD66A2C -:103B2000EA5E4DFFD517D06FCB34EF2FD23C5FA9A3 -:103B3000A9AFD1D41B82DF2F9BA1101F9615F0389F -:103B4000A5962FB5F4E14AEFB673BAF5B96226FB34 -:103B50002E88AF26D4F3FAB5E91B4B1ACC01F575C4 -:103B60009B4A385FC06C01F79F41E67A55A0074336 -:103B70000F72B320BD07B9D94FABEFF9F37FE0AFB8 -:103B80002914370AB24B76ABC1F53655ACDBBB75A1 -:103B9000FF820181F1D5E74BF05CDD631CC7DB5C84 -:103BA0003226D02E62CD25AE807DCAFEE3BEFB5EFE -:103BB000C5F93CEBFE5CB2D18C714F11DFB4F3124E -:103BC000F4A58AFABA56F86FC6611E2FC693A25A98 -:103BD00073E60F08D8276BEE83FB6CBB5BE5DFB7A2 -:103BE000AB07FC009CCA9883F250A73317E5A5B633 -:103BF000C5C42CFC2F786FF7DDEA42D4D30717C673 -:103C0000515ED32BE9FC7CB13BA677E24CA8B745CB -:103C1000DF46F2B6EDFEB154EE525DCBBB6C8C2D9F -:103C20005EF74A89F9727C1E4370BA3BFDA5922566 -:103C300040EFF7A63BE87D8FDD96B803EDED070C6E -:103C40001437040E7892E8E741D3603C6F972DE972 -:103C50004F71B1F2C7268DC37BA4E5F719285ED258 -:103C6000A9B3919FC8F3C058CA939AB14C94DEABE4 -:103C7000A97CE5DF7FACC77BA65DEB14FA4ECD5582 -:103C80005F37FF6D10D42B1BB2E97EC6CBE774946F -:103C900017FEE99ABE3ECC533E1C5947F9A5D09F6A -:103CA000EEBB569E77EC2FC9C7FEAA0D53388E4245 -:103CB0003BDACF4757A84FE13DCE32AB250AF3BBE5 -:103CC0008F7EC7C8AF73F43E137DEFE653B3E7D6DC -:103CD00035F1748F092D7D765471581580C3DAF44F -:103CE000FD25C929D86E12F8DC6F2D033E2FD37540 -:103CF000D30FE9938A585E5FBBEECD924DB08FA390 -:103D00004FF4A57CB1840CD7BA7480D7E10CD7935B -:103D1000548AFBD9AFFC9BC7255F3A599E88F4B5FE -:103D200059D0F5CBE7CA1303FF6E41C5293DD1C178 -:103D30002B46C702FAEE6954BA82E76CA08338F4C6 -:103D40009BCF10E716A0E7855BC3D8574BD3B93D8F -:103D5000D6F6DB84518E20BAFE98E4299D37A0FE6A -:103D600062FA47A4E78E9816622E75773E24DB1D13 -:103D70004970323445FA2233D17FEA1AE7A2F34F71 -:103D8000739FC996003E14FD3FF1F2FCDF4FA03F48 -:103D90009EFB3EF1FE3F4B603C43F6AFB45ABC681D -:103DA0005C1CB358F4888F83FAC547313FAD629DE0 -:103DB00081F440C5BA84455D287F806ED0BFA6DD02 -:103DC0009729C3C0FD183DC6573F2F199316785E3B -:103DD0003941F2BB27BE7C37FD44C9C6013DF365BE -:103DE000A58DCBA771EBF8F7752B8758F474BF7BC3 -:103DF000DDAB9BE81EF0BCC85CBC5751B9CE44F8A3 -:103E0000EAB458BCB62BF1BE81451F0BE5A174AED8 -:103E10004FF5190EC24791CAF411B954D23D0A198F -:103E20003F3CB1F0D1C7311DF373E6BB7E18C0EF44 -:103E30008C8BD3E9996D2AF91FB5F1C4EAD7B71A6B -:103E40000BD98F8827F61047AC629DE2BBE2E1E315 -:103E500089DA38E2BFD2C5BDB3EE38A281BE875140 -:103E600029E288456B155A7FE542FEBD92A238EEE5 -:103E70003F3EB218E8A02FEDDF6BCBC53C69AE7FAB -:103E80002A99E28B805FAF5E3B8FFC9975E91C5EDF -:103E900065E23BB087239D1978DEAF58174970AEB5 -:103EA0007C72F6074FE4E37DC089F181E76B9BA04C -:103EB0000F189FE13D6839CEB125F7D077678BD6D3 -:103EC000C33919F3B463D973376522DE523230DE59 -:103ED00029FB552EBDBB0FEF07E76CD877D90A95A4 -:103EE0007F0F6BBB89F421F07C320BB82F3E63D976 -:103EF000EB4623D7672C79A8B0B31DFEFB6C9FC29D -:103F000073FC0441ADB8B726E127EF5B95E9F8F7FC -:103F1000364B750ADDC3028946F7977E91C1FDA332 -:103F20007919DCCE2DCB70D23D9EEA5526E7D24CD6 -:103F30003E4EF7BD7538E755EB3A2A28AEF9171310 -:103F4000F9576A9745BA22AD3C1FE3F9019477AD62 -:103F500037023CAA1C5C6EFC42D063AD63D2D594A0 -:103F60009FAE6707F0EF07565BB89CAC8E05B89B19 -:103F70003901E986E2F73919E553E2B8298302E607 -:103F800057443B8CE3B0FAC7DDAB630DE8A7C1FE35 -:103F9000970F4238C65D7F23AEEF5995F81A80B46B -:103FA000AA00EDBF67D53C3C7797ADD83D0EE5F054 -:103FB000DC2D83F146052B7BEE5DD2237305FE3BA2 -:103FC000453E5A39D4F1BB81376470B9E951B9DF44 -:103FD000E806012F4907F279F50A03F7E383BC47A6 -:103FE0000153BDE4431AB7DAD2918872B87ABB8123 -:103FF000EE87DF8CEB0638972F491F7500E8AADCA7 -:104000001043DF51ADF24E3462BDAA51A1BAFFBDDB -:10401000840CA4D32F96BD6045FA391CD99A83FA33 -:10402000A96B5EA493EE29DAB8DFEE8B653974AF25 -:104030006986ADC382DF6599B120DB8E72FCA0ADCD -:10404000D588CF0F3667EAB0EEB2D94661DDA5BF9D -:1040500092EA5F887C17FA41BA52389EAB9A761B77 -:10406000F1EF2FDD2BE8E2D4B3EFF6413F50754678 -:10407000471FD42F40077D5211CECF28A49F6B9AA3 -:10408000781EBCA4831AA403E0BB39820E6AB6BDB5 -:104090007017F2430DE23F37948E809EDBA9FDF945 -:1040A0000DE3187FBF1DE944EA33A82F33A03FCEAC -:1040B000C8EB8B05FEA17D0C6FF70EE0F975DDF9FD -:1040C00008417CD0137ED766E8043E4C2477D78A1B -:1040D000FD76AED86E45FC9D7A76F71E8CB7543FC0 -:1040E0000FDADA11861F043C6A71FF565A3FD9195C -:1040F000B5B85FAB7FFFDD742FF8B096F1FDC9FD59 -:10410000D6EAC5FEE573F1FE3AB1CF2A26E0B5AD99 -:104110002FE73BC167C8C7F4DD21B13F8F3DF8BB36 -:10412000BABBC5FE9A44C96CCD56840FE217E50FA1 -:10413000D08FCB28E5097439B56503E5F74B7CC909 -:10414000F5BFEFD72B2EFC9354128F9D3D7CF7B615 -:1041500045F0C9A1FB92327600FCBED84C9F0D24DD -:104160007AD507CC27E946CE57F4A749D7E2BE61F6 -:10417000FC561C5FCE7BD01BADC7710E32CE1F72BA -:10418000FD922F8BEAA75D3BD88AFD4E59B2D15ED6 -:1041900011787C3FC346EFBBD06E80F75D3B14F2D5 -:1041A0005F1F12E7FD43F7BD602D1FE0A7F777C53E -:1041B000BA259DE10FFAC9E47AF7DAB93F58BB6E28 -:1041C0002987E4BA8BEEBFE15A6C97EBC7F8512010 -:1041D0009D4A384A7A95F7FAB4744B3427F5AADA2F -:1041E000337DD7A61DA2FC9D9076ED78C23E3A2C79 -:1041F000F2CDBB9E56F97DE765C9ED41F78E1833C8 -:1042000007EA9F25F3AEB615623CB749A17B1E5263 -:10421000AFC0CF4A7D803E92F6C1F0DE3C7FA5362E -:10422000DE7502F15975BC631C7E9244DAA5577D98 -:10423000DDAAC6A0FF6A1BCF8393745375B29DF8A5 -:10424000A15ADC932A5BF1EEC46148F74F1B28CEDC -:104250005376DF5823DAFBB3374D1F8AE0C07B1259 -:1042600028DF4F6C1C9247E061B6C4EBF1BEC4C6B8 -:1042700047AFC7BF5F3A63874ADFA1C171908FCB59 -:10428000EEC8237FEBE1C8CE8923D0AEFFB56A43E9 -:10429000BB7EE4A6218BB0FF484BEF58FA78D0C61E -:1042A00038AABBF431A427A41D2CF303EBC5BD90A1 -:1042B000ECDE9CAF7A75978AC80BACEF83F1F9AE50 -:1042C0000D91F4DDA852A3A3B915E7DB9944E78E5D -:1042D0005A382625DBE99E2BD969B38C2C222597E9 -:1042E000DA233045F97543C71DA84F5EBFC33218A6 -:1042F000BF8BCBD4F343CBB97DCDE39071C1DF61EC -:1043000092EBC8EACDE9573B9E7C7F2F9E2BEC7445 -:104310009F91DE3FB1ECE9EB511F9ED89C63C77DB6 -:104320001FDB1949F70B8E1982BFE778A9F7C2B4D2 -:10433000F7A9E43DD7FCDEC1F69CA4FB0BDECBB9AC -:10434000ECD2F2984E2E66744FFC5C06E3FEE4E875 -:10435000EFB6627E6145A3C986F7648E20FD637C5B -:104360006BBB4ADF01A2BBDF80AF23DBF3E83E700B -:10437000C5C7BC5ED1ACF8F0FE72FBC3F753FEC2FA -:104380004CB037F16A79B73DBDFAE1EB910DCE380B -:104390003DCBF13B006736F37C8B90EF3ABCBE75AA -:1043A0004F8AE3FFBFFD2CFD13D37B07DF4793F05C -:1043B00096E7AA57802E0A72FDF0FB72F12CB29F8D -:1043C0004F2EF650795A39B46A24D2B32586EE15A9 -:1043D000BCB4E35115BF7353BD6DF0793C1F8F30F2 -:1043E000C7D0F79FBE5CBC90829A2717D7893F8AB7 -:1043F000B654F8157C545EB5AD8DDEFB72475E0B8E -:10440000DEEB7DD91CC3C59AAB20E83B9912BF3DBA -:10441000DD5796FBFAFCD71CCF72DD9F6F9E6EC5F1 -:104420007DB5FD21AE6538E2373AC6867660A5C80F -:104430002F39BA86DBD9C72362FEAB18F07C7CED3E -:104440009444FC0ED1CCB6A9D7637BC54EC586E794 -:1044500003E7CE49563CCF7DA6EFB4E23DAACFD6C6 -:10446000C8FB573EFABB7B23C6B329D87F44AB9E1B -:10447000393229844CF432FCA49EEECB7E01EDE46B -:104480003F391F45FE13F889C37C92992F72BF4BA9 -:10449000F7F9579CFF468A7DB7F7B6CBF806B517F4 -:1044A00015F0F6636BB796D0DF4FDE68B0E1BABFA8 -:1044B000DC68A0F1E7C0B94D07EB3DBE999F83B022 -:1044C0008EE7E8139BF979674E333FEF54CF33B84B -:1044D000F8FDD260BA2C0AE847DF2DEBE1BB23736D -:1044E0005C7C7F73407FE27E2F44BFB1AC99EE9F2E -:1044F0005D6A3EA9967EFFAA9117DD74DB13BD08A5 -:10450000B822FF23DD4ABA98B386C7F5EDCD830BF9 -:1045100091FE249D68BF03586F64FC3BB2BA28FA31 -:10452000EEF724B3C380FA624A7CE718044F5F07B2 -:1045300097AF6A91CE85F7E458BD29EC77C4DE15B4 -:10454000F2781ABC4BF7BB7ADBF8F7CFC47D315950 -:1045500082BE4A477D3E29DAFE8D03BA74AEFFF271 -:104560003A3DD0F5A491F63BB29D80D7F55FF37A42 -:104570009E7D7B16D43FEF7DF63A3DEC6FD295F6EB -:104580002106A82F59F2CD7563E0B9C9E13AD83BAD -:10459000609E139B92D2717FD07E08DBA7277A8E14 -:1045A00060592BEE8F9D56BA062DCCF4F77F7BA772 -:1045B000E5E04B0E7FBDD3C0E8BB3BA77BCBF587C7 -:1045C0002F9D0ED7A9DE09A1EDE58CDD47F97C5EB4 -:1045D0007E6F077EDC118978AF8AD35DB9BCC7D303 -:1045E000A0B9C7E3E4F7D5E4FD2A797FEA72FFFDBD -:1045F000B3B59772FFECFF0069F3B24F0080000083 -:10460000000000001F8B08000000000000FFE57D97 -:104610000B74545596E8B955B73E492A4925845438 -:1046200025A984AA7C2B90C0257C0C3148E5030485 -:104630008858286AD4A005A2808214011D74F455FC -:1046400061307C9AE98E9F1722462D10957178DD96 -:10465000D1B16D868F532032FC9A0EB463EB8CD3AC -:104660001DD0D168631B3138F40C366FEF7DCE4D11 -:10467000EA562A80BEE77B6FAD975EF6619F73EEC8 -:10468000F9ECB3FF67DF5B5F192CEBA564C6240F61 -:1046900063AB53A1745A596319947BFFE9CFD26875 -:1046A000C69A83AC3B2E8FC15FA3F5D35150CF7C0C -:1046B000BA4B502E4B481ACDC660991362D06F99F1 -:1046C00089B1AE12E8263B6DCCC2D81209FE9D011D -:1046D000FFF9CA194B676C9515FEED44B84287F097 -:1046E0008366467F9F05983FDFC0D81F4F742539EA -:1046F000F58C9D9D1D2E0CBB18FB65BCCFE69C0068 -:10470000ED1DCD8EA634C6BE7CC3A4D443FF9ED07F -:10471000DF27F960FCA57AE6EF84926D1FCED824DE -:10472000282FEAC353A0DF6157F1B68DF0BCCBA9A7 -:10473000630C9E3FEB0AE7FCF578C6822E93F232BB -:10474000A37E773280EB1E9F3E1CFB9D7D7D5DFE30 -:104750003DB06E93CC5812EC7B068C590E7830002D -:10476000AC2FC30742340EB40793A0BEC5F5740E38 -:10477000237C302F9BC8D80D8CEFEB0639BC1FF182 -:10478000C5946419F7379B6F0FDB83328CA33333E7 -:1047900003AEBB9875583F4D0098B18E4BC3607FF8 -:1047A00066C063329680C724C6A6EAA113ACAFE9FF -:1047B00097FA9009D6D784781470D085237A2CD7AD -:1047C000C3F88BC5BCCB8EBC6BC4C15810FE07EBC5 -:1047D0005922E65DDC71773D9ECB9290E14CB7C0EB -:1047E000F525FA7F0F9DC772D1EFFEF2AD469CE230 -:1047F000FE1DDA7ECBD9A6AFF5F0FC52D66DC4FD16 -:104800002EEB8C6AEFA8F90CD7BB7C97B6BEDE996D -:10481000988674C2C6B2B197F4544DE7BD48F49976 -:10482000AA6F74CAB89FE166C50413373D9F47F469 -:10483000C2DE0CB0C87EAC6318D14F8B4B4FE7B1D2 -:104840006497C49CE318BB7E5716734253FDAE6158 -:1048500054265DC8A0FACF5F3936DE5732705ED776 -:10486000BF6AABC6F55DFF6A1195EA3A9A041D4E20 -:10487000D5977486611DE72CB00E809B8EC0628137 -:104880007E9A6ED68718E19999B1BF572CC76B599C -:10489000DFA54F42580E8AFD4A97243A84643C1F94 -:1048A000EF613D437A621E03B53B9979CDA55CA0CB -:1048B0001BBB8E3963E0DF24CE2FCE19CF9CEE8157 -:1048C000763958FCB34A588761AE4109417B735C25 -:1048D000D236E43316F474E5C3730DE2B9AE384E44 -:1048E0003709EE54CDF32A1DDC2AFAAD4B9A76181F -:1048F000E9B2C1B388E82151C9D4ACC7A45F6A400A -:10490000FAB9D567F8A43B621CA25F58C70D5E29AF -:1049100084FC787383B6DD50F975AD4425D4478E99 -:10492000E7D5F6FB29D203D03B107E71243D0C9CC9 -:1049300083C5A3C373F02412BDCBCCB9B912E05B1D -:104940000E1B18EEDF14CFF7790E319786FD800F1E -:1049500060E2758817A84F2ED7E237C5A3C5E7B028 -:104960003A2D7E867BB5FBB735E46ADA337C233596 -:10497000ED598BCB3470B6BF42D37FC4EA6A0DECDD -:104980000ACED4F4CF5B7FA3062E68BD5DD3BFA84B -:104990007D81A6BD38749FA67DD48E260D5CDAF984 -:1049A00088A6FF985D8F6BDAC786376ADAC71D7EE7 -:1049B0004A034FE8DAA2E97FCD07DB34ED93BA5F13 -:1049C000D3B45FDBF386069EDCBB5BD37FCA850373 -:1049D0001AB88A1DD3F4AF31FF56034FB5FEABA60C -:1049E000FF74FBC79AF619CE3F6ADA67B9BFD1D216 -:1049F0006B3C9793D72BFFA579EE5993EFDF505F70 -:104A0000344B95DD4186F4EB243EBA354DA7840145 -:104A1000FE832A97041D9E1C612539C1F2598EB769 -:104A200014E9B0328C7C7C6E9744F2E0AB28BD2850 -:104A3000FFD1EB91A09DFD4A525E7622DD415DC41F -:104A4000FC291E339323D639ACCEAA81877BED9AFD -:104A5000FEB606A7A63DC3E7D6B4672D563470B69A -:104A6000BF5CD37FC46A8F067605EB34FDF3D67B3B -:104A70003570416B83A67F51BB4FD35E1C5AAC6926 -:104A80001FB5C3AF814B3B576BFA8FD915D4B48F89 -:104A90000DAFD7B48F3BDCAA812774B56BFA5FF3F7 -:104AA0004148D33EA97B87A6FDDA9E4E0D3CB977DF -:104AB00097A6FF940B610D5CC58E68FAD7984F6A74 -:104AC000E0A9D60F35FDA7DB4F6BDA67383FD7B4C7 -:104AD000AB76D02CF7D7DA7A61175DAFFC59F37C4F -:104AE000B0DAC3903E826F484AB313D6EB02E13F7F -:104AF0009CE47C779C1EED282F18148C0129AD4175 -:104B0000FD920C420CE90A488C35A6E22840AC2004 -:104B1000B74955C1F3C9684F0090AA73B9FCA01FEB -:104B200013D85AEBA766B21B1C9740DF5DC2BF29A2 -:104B3000834B94A09FAAEB85F966A14E023A6F724F -:104B4000F93C2E58CF7D9DAF4FCB626827045B7038 -:104B50001DA00793BB416F9E886377794B068F3703 -:104B6000C30C788998EF485CABA3CC32F4FC33CC0F -:104B700067A97FFFB8063EAE04FB6B8A18FFA7A0AB -:104B8000EE65B0FB5A03C037058C3D15B012FC4CE6 -:104B9000C04E705BC049657BC04DE5968042ED1DFF -:104BA0008172825F0878080E05EAA8DC16F052FDD3 -:104BB000F64003C1AF047C54EE082CA6F2B5809FEA -:104BC000DA77065613FCF34090CACEC07AAA7F2348 -:104BD000D04AF09B817682DF0A84A8DC15D841E5B3 -:104BE000EE4027B5EF0DEC22F8ED4098E070E03094 -:104BF000C107025D041F0C7C40F0A140379587037C -:104C00003D541E0DF452FBF1C0058207CE4B6B578D -:104C10003361572E1274C0D2B83D792F3F52F685BA -:104C20008E2D46BB7791A04343359887407786CC3D -:104C3000C26DCD2E3C6AA01337D1C971B42FAF9687 -:104C40004ED070407A0D563337D29B5AB654E9C9CC -:104C5000FE0CAE90422F73BB88EB6F3353F537B524 -:104C6000373E2885D09E9B0776B211F8E623619FD8 -:104C70007C14C7E5F539BFC18D765FA314AFC0665C -:104C800001FE77B23BE02F8CA47FD75ED356B49F52 -:104C9000D4F535C2383A18E7BFEC2E5A57233B6C8F -:104CA000C0F540BD470FFC72C6E6DBE202BABE2F7C -:104CB0005B17342213594285DE44C68C76DFF348F5 -:104CC000E7E7FCF71CC2C1175995429CE77A537875 -:104CD000F8AD307FEF11BDB2CD39345E96B7CE005E -:104CE000E17D99F6B73F77A01D5FF717BD0FCFE1C4 -:104CF0008421B1210474DDE99288CF3A5D3A4DD91F -:104D000066F7FD02D7F96DA2FF4E1DA0F2DBEB5650 -:104D1000BCB212B6D4B8A22019ED55F00F0C685FE2 -:104D2000CF614E03CA879B98E75D1CEA66E623F8CD -:104D30005616A452B6F976E1BE6E6321827D15A6A1 -:104D40009C58FB8A5ED73B38D8702C759AF290DD60 -:104D50007700C7FB36D143EB3A31697A21EE4B5DE0 -:104D60009739C349FD66B3DE17707DDFEEFBFA535A -:104D7000296F309DFC88F4618169B03F33C2793777 -:104D800003EFE038CD0F4B21A473953E1AC14CA719 -:104D9000F11F857A29925E804ED07F4BEBCD99939F -:104DA00048F4D24DF26F923E68047BFA842E542868 -:104DB000E9894E8C12AC73511AD049EED0F4F0C090 -:104DC0007A2823E420D0D91738DE9FFEE11A37E293 -:104DD0006DF9DB939C88B7661D9C07D073F0A89E85 -:104DE000EC042644BBFEDAD210F907B2A2CC29C5E6 -:104DF00073E37271BF9EAD7E3D86DC4DC8E5F474F1 -:104E0000C26EA80BD1B89CEFD5767D2E3F477D2E84 -:104E10003FDFA6159F2DD5C3FA4F1CF8DCE82C8D7B -:104E2000B18FD53F79283F82AE97EF3A3DCD837E53 -:104E300017EB2EB93171A0BE50CCABD291DE98E801 -:104E4000DB6A895C573F5DC7E7225DA7005DE7111C -:104E50005D7F8A76F96C9333F95628BB013561285A -:104E60007D2F5AC97F5CC0142A17322F958B800C76 -:104E7000908EBDC1278D88F7FB5827D53F507E7790 -:104E80003AD2F5BD3A1FF9D94B5917D52F67BDB5A1 -:104E900078B437AF5FF3AE1D567D53EB9353914417 -:104EA0006F0CCD7F17CB39DBA54F834EE293EC5CC3 -:104EB000C047B7E47F2213E6BF7D67D51359503F43 -:104EC0005BCFCF851DE3E7A2CA91E87D035F14E0C5 -:104ED000F3DFA678685FFAA43A0D5F343ECE3C1249 -:104EE0008CD3BBCF14DAE68AE093F2FBFF9085F215 -:104EF0004CEEBD13CF7BF9DBA6543CEFFB18D7FB80 -:104F000092478DAFA8FA9E11BDDFCFE215ECF78571 -:104F1000A0EF2FB219D1F71712388A65037628CB84 -:104F2000F1D9CBF206F4F672DDCED18827D0EB951D -:104F3000780EF77DDCD932D685FA2094837688E125 -:104F40003593D2ECD2E817762901858D9F213E7FDB -:104F50008AE38E19BC2EA9FCD09FD1EE301959D00E -:104F60005C467CCE26227F671A89BF9A11B57938B4 -:104F70008FD7E9B70C1EFF8458EFE1EFB83F1D84CF -:104F8000FDBC2CC59A87EB2F53FCC03C2447D2199B -:104F9000CD73472EE763753E66E976A09D7E34C1EA -:104FA000773B9E8F1A4752FDC8C3AECFF2F17C66A5 -:104FB000576C50E5338DC7AEE372E984C11944F8EC -:104FC00044954B0109D62F6F6F28FFA70F701D372F -:104FD000982D618C77B04AC3D97EFF3577401FDFAB -:104FE000A0EAE3CAA8F88E1AF7618A01D757CC3E27 -:104FF00052F141F11D554E0ED2BFB0B12EC49F8863 -:1050000097F5C779FEB93FCEA3C3798D428E32E6BC -:10501000777B23F8D4D600AE8BC67F30B37C8DFF70 -:1050200060D5C0D97EBBA6FF88D54E4DBB2BE8D638 -:10503000B4E7AD573470416BB9A67F51BB47031736 -:1050400087EA34FD47EDF06AE0D2CE064DFF31BB72 -:105050007C9AF6B1E1C59AF67187FD1A7842D76A53 -:105060004DFF6B3E086ADA2775AFD7B45FDBD3AA72 -:105070008127F7B66BFA4FB910D2B457B1BFD5B488 -:10508000D7985FD7C02FC6F178E754EB3F689E9B57 -:105090006EDFAF815F88E7F19A19CE23DAE7C5F9B1 -:1050A000066F8B277E98E53EA969DFFFC8C8CD8DC6 -:1050B000C02FA14774E47FB6D5713DC51AAA391D2A -:1050C000C4F1BED72B1F6AE6CBD1F7BA908E9D7A7A -:1050D0006B26F2757EF99C034076ACD0B3A21AC55C -:1050E0009DBBEEC903588EF4BE5E8D6C53D270F238 -:1050F0000096A37D5F570319336571CA3B5896F933 -:10510000C7D6D87089ABE7BC83E5C4E08A1A94B3EC -:1051100060267EB108D67D3E38926D84752565AADD -:10512000715E0FD1EDAA0C1DF1F9AADB2C14374BDF -:10513000BFD622A33EDF1CE81A7910ECDCF4A7D31B -:10514000D762DC693DD8F9A122B017C0EEC7F25989 -:10515000B0EB43E01C6D04BB1FCB4D60F763FD73E8 -:1051600060F7239CFE74D97A7C6ED5C97BEA7261A4 -:10517000FC110FCA563453D739752B0EC07AEC0F79 -:105180001AAD284B8CAE67E29CB08EEC65B08E0AEF -:10519000428B0751FDEC52301C32391C07FDEC2BC1 -:1051A000741AB81DFF45B02E588BCF973EE9DEAE7E -:1051B00030F6F9B6B337198A619F795DB76D4D0145 -:1051C000389779E602BED3F12C60FC93798FCD0934 -:1051D000960C8697147AFF487249EE2C463EB51617 -:1051E0007D9481EBDA50FD85A2B3E23C8FCC390887 -:1051F000EB7E7E78BC58E72373AAF2AF665CCF796A -:1052000094EF50EFEF8C2147FE53E8FF93795C2F2A -:10521000C39F15E5938D9308B3819D940CF276F3AB -:10522000A4D5A7D1A790AD4109E523BB08CF4F1462 -:1052300028C823784AFC441EB247795354E433E724 -:10524000C178361FD84E91F1B1C55A78339CE71911 -:10525000C3C07A0C77E98232ECC1F0925751609E5C -:105260008E79B05F80371BB5FE65918E917D719F01 -:10527000BAEE8B372968A7DD97C7F5F09680BBECAF -:105280001303FA7F4AD9274047998BFD920FE4AB6D -:10529000ADD1AB04A19FE1D2DFEF372261DFC53A88 -:1052A000519F63FD9A08BB27478C6BB8A427BC1994 -:1052B0009ABD4A6AC4FC06BDE4EF8C617795E6C9E5 -:1052C000FCB96646ED86771E969C305F666348BAE9 -:1052D00087C6F14B0AD4DBC2BC3EABB1535A08F0CF -:1052E0001D794E3A07759CACC5B0FE083CD9E5A0C7 -:1052F0006485E7ED8F0625C483DDEA555822E2DA9E -:105300004BFCBD52F0B47DF5C4B24F86E1BABD8A04 -:1053100017E79BA5F29BDFCA703D1F2BBFA942BDBB -:10532000F61B3DC3FB8C6F9C4A725A8C7DA8A5A9C5 -:105330005BCF3C97F16792721EF1939EBCDDE22C2D -:1053400000FE7DF1364BC3D6187476471EA7B375A1 -:1053500099AADEE2EB49D7733CA9FAEA1B2BA71FF7 -:10536000556EAD4CE1B03ACECAECF12437865A8F77 -:10537000AD3D8EF922D6BB19E6B1E2FDCC772BAC60 -:105380008837F021BC349FCCE5E9D6E7DDE4374629 -:10539000D3CF203E00D19B5C8674D91D6A06BA31FA -:1053A000CD332A682FDAFE5B8B84722493B54A28AA -:1053B000476DD9B58765D4E7B2AFD81BC38EBE128F -:1053C0003FA8E7A9DA2583CFCFF9BB2AB2430D0C5A -:1053D000E9B6C9E5B4E1F9A974DA746478AA2FE2F0 -:1053E0003CD70B3A2E67AD7AE4D30AD6496525EB54 -:1053F000A2F23AD64BA58759652CAB9942652DF39D -:1054000052398DF9A9AC63AD54CE649D54D6B32EF8 -:105410002AC1BFA3D2CBACE487DE08760C96739981 -:1054200097CA5B989FCA2D48DF13F0FEA195E0DB79 -:10543000592795BB80FF9D45181F3153B917E43993 -:10544000966F833CC7320CF2DC69C2F8889BCA8332 -:105450000185CA4381722A0F073CD4EF68A08ECA27 -:10546000E3012F9527020D5476057CD4EF5460316B -:1054700095EF05FC54BE1F584DE507812095FF129E -:10548000584F659111E40AE2DBDD3D16FD9A9C8FD1 -:105490008D1E27E8A34FF384FFEBD1FDF7E2F178EF -:1054A0008E3ABA83B1D5AE94901E6D6E9D2704E5F9 -:1054B000467793743794EB4E703BD6644B243BD9BC -:1054C000D6BE4A72C2B8BBA46E7D029CEDDEBC0F94 -:1054D000E798414F54ED656B1314847FFFA419E8DE -:1054E00070ABC1DFBB15DA7FF5D2BFCE3183CEAE54 -:1054F000483CF5C7D7384CED930EB2662BC007F287 -:105500004E3F9926F175A0103EFED2C773D6E4E354 -:105510003AB91C79D5058E36FA190F5BC8CF18DB5E -:105520007E66AC0EE049AB2D65E81F47F4A3B8F5E5 -:1055300050FDA2DBD5E73A56A437231ED67D0AEEEE -:105540008913E565F7588CCF458EABBBBAF999FE48 -:1055500032F347F6932E335E5191E754DEFF037426 -:105560001E4DDF864B1FBFAEA3F8983515F5FAF632 -:10557000142E777AB3E343DB60DDDB5305BC219F58 -:10558000F6B50E61D8D7BA8DB964C76F8FF3361DE3 -:10559000C1F6BFD129DBA0697BBC6F6331C1F914AF -:1055A000AF5997EA77A35ECA49E0FAB1CDF1489CBA -:1055B0003382FFFF22E4EEE6CABEAEADE84FADD7C0 -:1055C000B102786EDBFA051BDC30CE4B9BC02E029D -:1055D0003879F2C20D05D09EBB4137512F641EAE03 -:1055E000E3A54D0B5FD928E1B823530B61DC3C21C7 -:1055F0003F7386758F5D0974DE66D4C615FAF56350 -:105600003EE7978530CC19D0BF39225EB1D5C01A9C -:1056100022F566413E97B73545BC344CE1F13CD3A9 -:1056200088F8D0E3B0FFAA113CFE93BED64CF19FA0 -:1056300074C77F9E9C0EEDE91D3A054D5AD9B6748C -:105640008D01FD9EDB5827F2E356893F1FCCE6769D -:1056500032182CB97322FC1EB037CAF223E2A7F627 -:1056600086A084718CAA114B258C37A73BEE933012 -:10567000FE91DEE0937C89E827F9A9FDAE229F2BFD -:105680001FD6676F84E735F7B1BE0C3C5798B781DA -:10569000F20964561639DFEC228E872764203DB468 -:1056A000DFD71A695DD1F89AE5AE1E993F7CE01C00 -:1056B000A3DBBFCCE7E7B8FD719802F960128F1F3A -:1056C0009C783993ECE5D96DF11EF4234F3C39B247 -:1056D00096E0A72A3C68FF9E78B9621A96B39F9A13 -:1056E00049FD4E48EC30C605663F75BB8CF53979EF -:1056F000B02E1CEFB491E871F653F789E71FA9C5E6 -:10570000F6725DF0EFD09F2E6F7E2D01E3051589B7 -:105710006F64617942D7BD6A3FCC7F8395FD1AD50E -:10572000B57743DADFD4C13FE63C996BC0788C375C -:105730003F97CEF326E631F07C072FF9B7953BBAB9 -:10574000DE018B8E5DD7D95B83D7BA9E5DD6835839 -:1057500056871534A359ED61EF412CA775F96BD12C -:10576000BCA9FBA0F52096DD237D5EC4FFABFFED59 -:1057700096375E0578C463ABAC6887E63FDE3D6371 -:105780001BC52F0D0CF9A16092BF558F046CF6A6B6 -:10579000A27C78F6195987FADDE46A8D43D8744FF4 -:1057A000AE0EE34CDB535A17D3BE0BE219E2F128DD -:1057B000E821A48B82146F2AF213F0259DC39D82E9 -:1057C0003E4D297E6B0AD68B7B8EFE7EF11C5ED809 -:1057D000DFAF354EA27952A5A0C4CD08B423EC4268 -:1057E0009FB7337F06E2C396E8DF8AF1AD822ACE07 -:1057F000FF2C91D305766F99488F50103EBDD53F51 -:105800000BCFC1E6EBCF1BE074076AB0DF3EC925C2 -:1058100098EE7F364B1C063943EBC23F8CE7A45B06 -:10582000D2C9CE51D76F6B80F122EC0EDCC78D96BA -:1058300081E754BADB20F6F584280BE6F3F1D4F5C2 -:105840006ECCE77A1DD6EDD4E17AF4623DB00F5DFF -:10585000C47A22FAD1FEFAD7CD143BD205637E89F1 -:1058600097CC2947EE7FA1CE13371AD7FFD65F61B9 -:105870005C2909E508ACF367FB2799914FA3F7F181 -:1058800042BE88FB80BD8CFEC34C1FE7DFE646BFEF -:1058900084FE940D61DCBF43F6605CD46669920CB3 -:1058A00011FBB539B89E9ED9E8DF8F7265667982A3 -:1058B00082F43D8B75AEB572FE3E980FEB2B62FD08 -:1058C0007F163671C04E7CFE99F74EE2913A5867CA -:1058D0005531EACFC7EEA5BC89CD8FCC3C8CEBCF40 -:1058E000743FB93F1506F47E2DCE7D3E8F6F6577F0 -:1058F000C89ABC872CBFACC98BC858AC6D077AD08E -:10590000C02A5DD9A5D529A86F7409253367A09D44 -:1059100092A423F90E724A9A1BD31E8DA22B817F6B -:10592000F57CDECDCFA773B359F839B05EC57C7373 -:10593000A2D8AC7A4E306F33B07932D07D73AD3EA1 -:1059400024A11F8FFDF132B2970DF7260E3EA7ADB1 -:1059500006E7CC1928A71FD45929AF2A0AAFA06798 -:10596000FE99FC9407D3A81DEA6533C53D23D6AB49 -:105970008F056BCFE34AFD3B5878CE0CD7E0FA4C4D -:10598000C7DC99A8673397323AFFE8F6A247B5E734 -:105990004A7EEF788CA3B150F8079CE74CC7F65AC3 -:1059A000B4EFA3CF55A5BB9C61B1F5C223055C2F15 -:1059B000E42428A7EAC8AE90C94EF066CBC323FD05 -:1059C000A4EFF2B91F30E55716D243EC6373081FFA -:1059D00055C25D3F298673A8EED3A1FBC2DE3D7E92 -:1059E000E0E999504EFDF57B4DC7A0DFD4EF2CE3E5 -:1059F000B07E37EB9E8181A0E06103F98D6BBE7CA8 -:105A0000A5150344CD8D4C41BDABCEE328E0FA6E25 -:105A10008F21E425F95A2CB36D2407D9C54B11F415 -:105A200002909EE887B7316F632BF991B6FC12861E -:105A3000793CCDACF30ED297678D0CE3AF37363897 -:105A40000D55B0FF1B1B9D86F9789F21B33AB423F7 -:105A50006E6A50A8FEA64685D79B79FDDC060FD559 -:105A6000CF6DF4F07A0BD45B300F29D41580716FB1 -:105A7000B6A43A75781FD0E8E5ED174CD47E1CFC2F -:105A800001CC278C8F0B91BC6FEDD1F17B237F7CF8 -:105A90004882B59A12CB0E3B117FF7E8145017CC11 -:105AA000942D332BC0CF3678437A687F8E853210A1 -:105AB00091BB1736790BA17EB743B6E2FE76837BA6 -:105AC0008BF947C1A532E19DFE00DEBDD841F73A12 -:105AD0005B45FC3EB8C44CF166B07528DECC9664DC -:105AE0000A3B86B7772CB086D01E033948E7D87BAF -:105AF0008F4C7600C8C3A36EB48B76E62B189FCA72 -:105B00005CAAE5B7F4850BAA68BC4666453FBDBEF6 -:105B1000918FD7BC5317D2A15D65B97126D241F3DD -:105B20000EA6A03FFBECC253B5C310EE50142E3F9F -:105B3000B472A179E153479CB81FBFCE5A40FD799A -:105B40001CAFD95FBD5D2F0DF0339DB773407E0C48 -:105B50009637CA611C27635EB582F1C174D827C627 -:105B6000F33B8CBC3E78A74CF72DE90BE5B075F400 -:105B7000007F670B14A6231F26917CD1F0D7C89D08 -:105B80005AF879C1A7C0EF32EE2BB89D513E67D1CC -:105B9000766D3F90933A9457D9EDDAFA5B8BFAE33E -:105BA000021A3C44E3D9E6E7722F7A9F03FB0AC747 -:105BB00015D1BE747C5F28D7A0BED87280EA8B1B3B -:105BC00065C5E94479D7790AF75FB453666180EB1C -:105BD0001796CD447AAADFA4A3F0C8F5AC8BE4C233 -:105BE00095F6ADC63BA2F719BDBFEFF2F55C8EA8E6 -:105BF000F6E01366B207DB1EB6E8F09E15ECAD7852 -:105C00008C2BDC55541D2C407B40C81DC3253D9773 -:105C100027CD16A25383ED517764FCA16554F5138B -:105C200005D46FD88D753C6E41FB8E96633F17E3AC -:105C30004DEAD6E6E35DDB131F953FA6CDC79B7209 -:105C400021332A7F2C2F2A7F6C94A67DAA755C5461 -:105C5000FED8B551F963351A78967B96A6FFF5CA3A -:105C60004D1AF886F23B34FDE778EED6B4DF547770 -:105C7000BFA6FD66EF4A0D7C6BC35F6BFADFE66B78 -:105C8000D6B4DFB1F8279AF668FF492D771570F979 -:105C9000BED9EE3F49016CD0F791F73D6A99DE28F5 -:105CA000F7469E7B5202B7A7A2FBFDB980D3FB8BC0 -:105CB000129F8F05ED9A781CF3D835F1BA7045859F -:105CC000B91BC6711A95DF21DD62E20EBFBFB66B4C -:105CD000EED9F63F0EFD60BCA6C45C1BEA3B8CFF10 -:105CE000FA40B9378774745F615BBF4A223DB86977 -:105CF000158FAB5C30523CAF7F1DAC8EC6FB46DCD3 -:105D00006BA9EBEC1071A42D18474285E49941FD75 -:105D100056C6F17E3F4D57E38E3E1A37A3DC18A4DA -:105D2000FCBC857E09E3C0CD3E66C57B9374CB0287 -:105D30009AFF9B0625995D262EDA16B0330FCC67A5 -:105D40005F155C6384BD7D52D0F7D4B3F0BCDDCF6A -:105D5000281ED35BF0ED53188FE943E108749D21B1 -:105D6000733C3FF7C0EECF5F81F9DAE6A597A15CFF -:105D70008D6ECF5ABEF7EB4397697F6ED95B1FDEFE -:105D80007BB9E71FD875BA25A27DC838694326F3C9 -:105D900044D001E02CE6FD805CC8F5F9F20A23C589 -:105DA000B1AE01FC1502BEBFAAF8CF893BE0B93FF6 -:105DB00039FBEE443B1DEA65AC877E84D73FE59F07 -:105DC000A3FC929C5160DFA3FD1D179B6EC715724B -:105DD000BA956D8DBD18076A4A343AD1CFCF32BB20 -:105DE000CA3E1907746DE07E75B4FFFE5CBFBFDD6F -:105DF00049FE779118274B947A2B7F9E99834C4EBE -:105E000017F71431F0A14F6A97505E652E943F8DBD -:105E1000E48BFD89468A23A45B44DCC1B258131786 -:105E200050E306FB13EF9590EED3C34B289E8FF102 -:105E3000021C6F5CA193D6111D2FC832E7D3BA861E -:105E40001E9FF5D7274831E6895A871A9F889E27D3 -:105E500084F604EA9965F1644F44EF7B4961557912 -:105E6000E170E4D7DE93D3517E9F32903E1C8A5E70 -:105E700030CF3C1431FEB442EEDF63FE78643DE681 -:105E8000878722E3D9CC41EF2B100C2A6684B17BA3 -:105E90004311CE7794CF77C2A0D8C91E04B587FE30 -:105EA0005F7D21D703D330976D38F219F7CBDB81B3 -:105EB000AFB1DC12B0927DD601FC87F00B012795C3 -:105EC000A1809BCA6D0185DAB707CA097E25E0214A -:105ED0007847A08ECAD7025EAADF196820F8E701CA -:105EE0001F959D81C554FF46C04FF09B81D504BFCF -:105EF00085F66001C6A9D753B93BD04AED7B03EDC7 -:105F000004BF1D0851190EECA0FA03814E820F0642 -:105F100076117C281026F870E0309547035D547F99 -:105F20003CF001C137E33EC9AE58DF15C078854F5C -:105F300076A27DF7AC6FA115ED6BFB7C9D15C57945 -:105F4000BB4FB704E31C1D8DFC1E13EF23310E0461 -:105F5000766808ED39FBFC678E4CA5F6B9D4BE19FE -:105F60008704A7C4B682DBAF6C9991FAD930210AB5 -:105F70009EEB58DA18D203DC5A184FEDB61532F9F9 -:105F80006DCFE9FC2985DCEE22F96D3370FB41A56C -:105F90008335855CDEAE29E4F75C1F16F1734ACACF -:105FA0008BAD479E2D54EDA6F587717FF679B03FF6 -:105FB0005CEFBC5566BC97B5DDA3B3727B93DFCBBA -:105FC0003A60BFB87E580FC585D97C6E2FDBE6AD31 -:105FD000A57539E6DF48EDD6A24753D04F6FF7AF2E -:105FE0009A43EB6D9429AED9EE3B9082F76CCF8942 -:105FF0007C27DBF0786FA864F07A9E8D5A7F07E3E8 -:106000007E8303ECA5D763EC03D36E49CF3011C771 -:106010007BD41C338ED729E8D72171FE630FCAC405 -:106020007F2F30B0FBE0B92D60DF05510E54BFB6B5 -:1060300002E355BD85BE9D28379F778E3F20039C88 -:106040005AC7C7CF5D25BF8276349CF7E72D50BF76 -:10605000E1BE4D5E5CEAB04DCE35C86EEDF3DFCAF1 -:10606000C0F89743D29E8F5ABE2DF6F982878FB71C -:1060700065954CF164DB8A375D07F9BCBB91FF3352 -:106080008B3E8AC3304CDE5CA70E4586639EFC3592 -:10609000CE1777FFA63A42CD268F3ADF589CEF6A9B -:1060A000F134E2B15A9B2FC6BA869227579223BF8A -:1060B0002914EF8164B12C9423CF19B8DC0A9EE433 -:1060C000F62425054D1A3C8F9A2FA0E60F44E70BC6 -:1060D000FC5EE029CBC462DEE77ED64FBF413AD7F3 -:1060E000173C1BBD9467E3923149873519D8127A62 -:1060F000EFA72ADEBA26063DA8E55328C700C11F30 -:106100001632712E9BEAF8383A3ECE64B682E02A07 -:106110008B3518435EABE533629C7F2BE4749B7533 -:10612000DFCE0D87F07C8F1A28376A8B2EB401FDE5 -:1061300084E0093DC9D74C7DE7D65722D6F51741F3 -:106140009F5B8CA162BC876E87F14A50AE22BF94E0 -:1061500050FC82D547E05D7DEE3F841DF0FCC575A7 -:106160002974FF3C6F6D1CDA47EDCC4CF46033F8BA -:1061700053C646D0830DE932067D388B8C340EFC35 -:1061800059AA26E2BD0CD7CB35289760DDFB162631 -:10619000913EAC99FFDEAC310057F6C994CFB265A1 -:1061A00029CFD39CF4EF3ACA1379FB31EEF75DF7B0 -:1061B000502DBD9F9421CA67D1CF83B2723D53C287 -:1061C000702E950B2D14BF997C413E13E9A75148C1 -:1061D0007A3CFA173C5E736DAFAC790F6D528FB697 -:1061E0003F60548F764646B7B6DE3EEFCDD353615F -:1061F0009EF6A5FCE1F68BBF3B827070958EE22483 -:10620000EAFB64509341F14D399881F99B1BCC8C8A -:10621000E4B96DBED98AF2607F7A3CC9BFF6DB2C47 -:106220006487AECB6F8A433BD9346F550A96238C73 -:10623000C1AD183BBDE6D52D37D92791BC55F355D7 -:1062400082AC1CEC81BB8DDCC8093EF7F45419E527 -:1062500025CF6799F4EA96A783F9D8AD95D6E1D40E -:10626000B14CBEF97EF876BAB796B8BE701AA11DC9 -:10627000E079A37CD715417B465A703F366DB69CBA -:1062800069A47C6B4C3282F90D0BFDCC88F58D65D1 -:10629000E6483E57F9E4FBF27F3CC687875F590E1C -:1062A0005C69DC2BF17B413EE79BA1FC69D310F2DA -:1062B00054F58F1F29E0FC8B6C4B7AF58C31A67D51 -:1062C000F5AB22CE67E5469EA732BB615A1DDDC302 -:1062D00004BB65CCE77B51DC0BB5A727D23D717BB6 -:1062E0002E0BE3BD4170818EC77BD2F87FED8DB957 -:1062F000141F6A93FC29C13CCC97F0B9F0FCDA0179 -:106300004789307F5B0E97EB2CE4B7E27D358CB389 -:106310003872FDE0EF05B574CCC81EA6F8859E78EE -:10632000CF698C88B7635C1CE317D1CF4DEED5C223 -:10633000532E68E12A66D0C035662D3CD5AA853734 -:1063400015713B7DBA5D5B3FC3A9851DD907E37419 -:106350003CCFDFC222E249F0F75E7E441C68DD6874 -:10636000FE3E5F76F7528ACBB6E5F0788F639536BE -:10637000CE91C54212E22F7369543CD6BD663F866A -:1063800097ED0BA3E341FC5E02F0A1A947318A7CA3 -:10639000F0EA689E87DE3DD2B7BD08CEB3600C5FE1 -:1063A000C7AB1D4D743FC5DAD388AF5C225F69B0BF -:1063B000BE7C8AE8401D0FF92218B17FE48748F8B7 -:1063C000A151BE37701EE48B60A4FE2CE936D0FBD1 -:1063D000AB62BEA1F843E5CF72718FA2E6DDF4890E -:1063E000B1D4BC9B55225F705754BE4E9FA3361943 -:1063F000FDE7BEAE95F1B1F810F92E68E27C88E5B4 -:1064000006917F837C182CE27C88F5A6EF56786392 -:10641000D98B0B055DDCBF63C9864F22F6B7AC7321 -:1064200085065EBEEBE10D91F951F7E33F3008BF01 -:106430009E517EED52B19D2F4FFFCB2BCD0CCD4801 -:10644000DF0728CF96159C31F27BA75E239EEB4297 -:1064500061FF99CCB3F2D12FDB11E2F26C9D88374A -:10646000345B1533C681993B5513C750E3114D4B2F -:106470005CB654D847727F7CC16BA57CDCE1F91413 -:10648000DF48AAF1DCCEC632D653649C6B0662DDCF -:106490008EC156C0E9F957D93341C7C0BE4D17F870 -:1064A0007BC9FDB0EC67248F2EE468EADB449CA333 -:1064B0009FBF2D0BAA703E8BDB49FBB031FF1A1E2C -:1064C00017D4C6D14CE23DE7C1E33B34F56D227EE3 -:1064D00072E5F1B57139D385BC21C62F8C1ADF1A4C -:1064E00073FC8171B5F1BDABB8374F714F183A2EBF -:1064F00036D2CDE9699DDDDF85713183E07F6606A7 -:106500003A9988F280FFE9E3797EAEC1A18D8F19B7 -:1065100030AF0BFA3F97B898E48AFA3EB5FD99057B -:1065200012CACB27F0FDE8A4C1F2245A8ED844DE6B -:106530007CB41C81F93470D3C35CCF364B8A0FE531 -:1065400073F47EFE7FF1877589E3BBC8AECE8E778C -:106550009A2E630FB7058263F1B975F1FEC578070E -:106560007EF78E91694F94E37BEB8CF86CC58E2996 -:1065700073310FB64DF0EB13693AA2A7F4DBD3B732 -:10658000EA23E829DDE873A13D9CAE13F95FF887A3 -:1065900071B427D2B76D8C31BF6AD7A9B0AD01D61F -:1065A00011718E6DC29EEE9FEF8ECCADFA8871D2C6 -:1065B0004DBEB1345F7FFEA398AFE587CDB759C418 -:1065C000C3D4F96C776AF76733FA697F36A187D449 -:1065D000F936E3FE62F0D515E713FE75FF7C7769A7 -:1065E000F76733F9697F36F53B1BEA7C2D3F6C3E3C -:1065F000BBE0CF76F1DE973D9E7F3764A8F7239A04 -:10660000FBF3CCBD66942FED6ABC50E8BB7351FA26 -:10661000AE49E83BF5F97369B914FF3D77F8267385 -:106620002C3D87FA8D093B93093B93093B13E1D934 -:1066300035A7570D077AFCBB1D37CF9541AFCFBEAD -:10664000FFF4F81C80DFD9F18BB932E8A9D9AF9EED -:106650007E330B1E29FEDBFB38FCF4E93E07B45BFE -:1066600082CFCCAD05386918D7CFEABAD57977B9DA -:10667000B95DB97C751E8F6F829C453DD69CE367E2 -:10668000187FFCCAD19B341FFA2FCFEE4D5F100349 -:106690002F6AB97C75217F1EADC08998CFC648AFDF -:1066A000DDA8BEC752A77D8F25296923D987712C04 -:1066B0006445399660F6D0FB97D71673BD70335397 -:1066C0001AB85FE12C10791CF4DECB4DE5625C6BEF -:1066D000E52FB1FD669DE709F477FF79D2BCE1684B -:1066E0003EAB7973A306DE3BDDFE7DDE4F9EFDB142 -:1066F000C46DE5641E8F9936CAC9DF7B8B882BA2D7 -:106700005D3C143E3F7573FF7E009F1E8ECF540F7D -:10671000C7A7B537690D9CFFF294DEF4C7894FC354 -:1067200031F13508AF51F8FB939BA97EA01EED888F -:106730002BE15BC5AB9A5FD82C390BC85E67199A01 -:10674000FC60C61467AC7B1EA4CF483D6BB47B19BC -:10675000DAA38634C58DF9EFCD7FD1C7CCDB7315B5 -:106760008BF85E523CE57D362719C91FDF9F3493B5 -:1067700061FC59B64C23BCD426D5513EA67E18EBFD -:10678000447F353A0F5D9F7C3BE509E96DE8614048 -:10679000D99FC7EC31235FE93F56925D4800579976 -:1067A000872E5F290F3D7526CF434F323A315ED891 -:1067B0009E688C9987FEAD9BFB5DFB717F69B81F5E -:1067C00023FF6E88D8976CE5F7EE589F00F546AB2F -:1067D0008F51FC5DECFF5B6107A9FD4D563F43F90E -:1067E000A0372A4EB45FF4A95C7FE0775BDC31E22E -:1067F000285FBB0DF4FCFDA3AC5CCF99B9DD3EFB7B -:1068000037B1DF27282B9644BC2436DD0D453737BA -:10681000EA78DE9DCA97732D46CA079C6BB1D3F701 -:106820006CE60221F6A446F4BFEE56FE3EB5ACD8A7 -:10683000919E7E7BED945FFE96E1B50097DBA766A7 -:1068400018E8BDC25312F328A983F35DBDDE94A9F5 -:10685000B8CC1BEA4FAF45762C18C3C84E7A75C129 -:1068600043AD954EF28FEA8A919E7D73A6A20F7773 -:1068700063C3D877B1FFF2042ECFD5FBA5E509FCA1 -:106880007DDE6B64DF6CECFF55C51749D5485F7240 -:106890006F0EAE2BA23FDD3345F49F5B3C81FACFF8 -:1068A000E6AFDDF5D27739CEA59DF9C8C7E87CEC17 -:1068B000B1EC29F4B758E4BD86901FE87745D6A31C -:1068C000BFC522CE535A506EEB8E214FD432C33EF9 -:1068D0006EE442A0D78C8CB154AAF5CF7AF475A19E -:1068E00018E7FC9038E71FECF7B4C36A270EF83DB1 -:1068F000E0EF3C84F8F872E1A9F4F1B0A5076ABFB3 -:1069000026BFC76EECFFCE16F97103B0F6BEB32DED -:10691000D05B8CDF196088878911F98B62BFF625FF -:106920006B52D0EF81B3F420DD7604BC236B0D03F2 -:10693000CFBF2CE4080B16D2F306B12E475AEB0C4E -:106940008CBB382C3ACA7360CCAA9167736A53A681 -:10695000A6A10BBB9C291627FAF75DE41764E0FBA0 -:106960000D189F7CE73686F75F59699D12DA75FD31 -:10697000F388F7C657897BE13E5F2DED27C3D6EF3D -:106980009731F25FD38273506EF53DC35794F19205 -:10699000B6DD91C6F31FEE5D181F7202BD672DEDC7 -:1069A000C24F4FB00C70F830A69F71A9D9D5827232 -:1069B000E657091477D6B7E7B320C8FBB0ECFB1B4A -:1069C000C277C8F9902E4F6C169E5BB6289EECB924 -:1069D00076A97506F931F7E858AC78D1CE62EEA702 -:1069E000FC8F622BBFCFB54FE4F4631F3F72E1B859 -:1069F000ABE7FF77849EF949B293DE7F52EDA34D5A -:106A000043F8478E913A215F845E11F833339F1922 -:106A1000F9452F7979B074C76BAFBD96CEE8535B5B -:106A200048471B84FDA38E139F1FA2C678C543F25F -:106A300052B27AB8BEB0FAED4138AF75DFE963CE35 -:106A4000FF85A0FB35D90FD9B17FADD3E7C632FAA8 -:106A50003D98969C7BDD783E2D33FBE995ECBA960C -:106A600033CEDF613E56F028CF37D89F5D68C3EF45 -:106A700041590E1B64D365E2F146D027CECBD8191D -:106A80004691AFDE7280E799B658CABA30AFA1C559 -:106A90009256466AD8C2F356D5FE16CB21D20716B7 -:106AA00085DFDF5A507F48B84CC04709AEEB10E194 -:106AB00043ED7750C85D8B1266F85E5A9CD24AFD52 -:106AC000CCB2D78379CAE63446F744662BF017E296 -:106AD000355FC7CC31F4C9BE62AE4F5A4ACABAAAB2 -:106AE000697D327EB98EB5D8CBECA4E711EFF07C8E -:106AF000738696CFBF137857C76916F9B477AE4E31 -:106B000009D68EC33893F71BA4E716CB027310F592 -:106B10005AE2F8CB8E671A39D478FBD78AF1BE4394 -:106B200079AE4F2CB3E27806C6F7158DF7E1629C7B -:106B3000FFD5FB7BC02CBD474D301D58D81EEB7DCB -:106B4000ACFEF313F7F2D1CFFD6079BC561B870280 -:106B500079EC1E09FB5A5672E65035D5F0F8D30B86 -:106B6000C29F51FD927431F60B127FBF3F28C52B97 -:106B7000F45D0CE1A7A4C769F130F03E2D3F876FAB -:106B80001A781EDE37694C7C874ECBD7DF1CFF3866 -:106B900045939F057CEC31713FC623DEA7F588380D -:106BA0001DC2186FA0179D04FFF7C7891B9C3FC328 -:106BB000EFAC99408EEB605CC9E127FA3639BA5DDB -:106BC000C8EF39E2FB0FD178FEC9482EAFA5477A4E -:106BD0005C78AF519BD69B118BDF5F7CF84206EE51 -:106BE000E7C519FD793B74DFF4E269E7E602C4CB3F -:106BF00011EDFB6FEAF84D47CEA7F822FDA5C0E5E1 -:106C0000DF2F4B3AB37125D98D0BB8DDF87FFA7DB4 -:106C1000B317E6733B7597A495CF4F08B91C14FCC6 -:106C200060BB20D3F743EE2AF2AD403A6A93AC0B37 -:106C3000502EE73CCCF3F29A1E5BD5B328067FB406 -:106C40008CF2FDD5C808BFBA7CBD91E45EB3253790 -:106C5000F972F728439FBB9FE4947ADE558F9879A9 -:106C6000BE8A8FDBD1E9BE7B290F263A3F65A87E1D -:106C7000D5239D440F6A7F138E8FF2C57223C515ED -:106C8000CEA18F81713B2BB733A2D75989C898C049 -:106C9000F163067D997460491C8E6B10FEDC0B6AF3 -:106CA0005CA4A1CCEC8978DE705B99B93A824E9AEB -:106CB00019CF0F8E1EFF372355FB22ACB1630CA8F2 -:106CC0007F31C694269FED973B6478F2FCB4950320 -:106CD0007CCCE30E43E7A3C571BE2D237BAC0DF343 -:106CE000D2C00E5ED3B06004E2B74DF6BD68033C7F -:106CF000F47E68A23CEADF0B3EED167C3AD4F9053F -:106D0000D90130D2187B9C1DC497E2804EC6272340 -:106D10005F34E7EBEA4231F6795CECF332F67878EF -:106D2000E4F7B3C70F89FE1A7B1CED6D4FD4FD4607 -:106D3000248C76B627863D7E4212F105912774C2D7 -:106D4000E0DCD50D7839313999BE975690C0EF5DAA -:106D50004EA07F52067EC8ABA7F3D17E992DF57F5A -:106D60001749F8438C60F047FE05F9620EF3BFB691 -:106D700048223EE2F735781B9F7EE573DE3692D1DE -:106D8000BA36C0F9E1FD46DBC5F93362DD67A48E92 -:106D900052FD37506511EF13333C9D88FBAC41F732 -:106DA0007451F772786DD39F77AC1FDCFF8672ED5C -:106DB000BDD9868B3C2E625AC2428F4B9897AA6DE2 -:106DC000BFA9CE107D2FA8B94FBBD96B885E0F7DB0 -:106DD00017D421D69BDD711FDDBF4FCDE6F944A648 -:106DE000658CE204D1F76DA6B15D1E3DDACF0D8C46 -:106DF000ECFDE83839E6A952FCB081B12D12E579F5 -:106E00006BDF7379A6FE73FE7D94D63A9CC70E762F -:106E100010DAD3D1EF49A8F75AEAF751553CABDF66 -:106E20008F4ABF4D47EB63C129D4AEC6FDF17BB895 -:106E300055E911F9E42B587F7F7A7F2B187BDF9B74 -:106E4000DBEA29CF2073BC7F6C189AB2144678C84D -:106E50005AC8C86F003C68F2094CD9DB699FE71635 -:106E600033364C223C68DA3340D3D3FDC0426D7ECA -:106E700001EC530347FBAB57F2534DD9F99795F308 -:106E8000578A639AC4BDE49451E2FB97A5AC14ED14 -:106E9000A2F4DB9EA1F33807E781715F749C62DD89 -:106EA0003B6E82F1D18FFC77C12FCDE26E5BFDAEE0 -:106EB0000FF3C8F41E9B54CED72C0DF3F27BE912CE -:106EC000467C6E8A6766CC8F972A4C1EC4BBC90469 -:106ED000306C5932327306D4EB453C7B8DC46484EC -:106EE000995531F3F8A3FA5DA1107D5768A879D4BC -:106EF000EF2BB2207F4E9D67D077F52EF33CF97BC8 -:106F0000D6E8E76B299EA9CE3F14FE87FA8EDEBF36 -:106F1000D5BC3781C7531D44AF8D03F44AF07C4183 -:106F20008FF83CCA85BBD5667B5729FA0F671E4C84 -:106F300050364A11FB08CED2F3EF037EBFF1FAD7E9 -:106F4000617792BCEFDF9718EFFBEE8BFE22E4DA5D -:106F50003A7C5909F35E1A19E531A4FBAA3F972937 -:106F6000FF00F6A0911311DF4980F1D63DCEEF1F4F -:106F700036E3773EF0FEE7C040FEED13166CF7D126 -:106F80007736D4BC5CCCA35D5B32F03E72F47D837B -:106F9000BD11C689986FB2990513409FA4F43105BD -:106FA000BFF3ECB96854A6037E6C7DA05001BF937B -:106FB0009989EEA52AAD7E33FF0EE10A166967EFC7 -:106FC000976EA5EFBD86BF6494BF143ECF88EEC315 -:106FD0009FC3C4702EFFF8DDFB7AE4CBA97D5D7AF8 -:106FE000D4F393FBFCA47FF6D94F3DEDE2E7629921 -:106FF00011911F751D5B54CFE98A9F972CEA275F7B -:10700000306AF8FDDA5EA3461EC8175BBE46FD6512 -:10701000EA89AA67D33FE3E3F928DE2DDBB5ED5318 -:10702000443ED0DB2ADF5FC3AEA173BC981633CFDA -:107030006EE0DCD5736EE27174C6C7796E94F79F0B -:10704000464D40FFC04771E864C42FD8172995DD2D -:10705000CC8E7958E54C998E72BDB2F31DA487E4AD -:10706000B33C0F3C7AFCFD5FBE95857EC39EC99DF7 -:1070700059682FEDF9F2153D8E57D5D3CBB03E1997 -:107080004A1EA4584C78AA10B43350CFE34491F56B -:10709000B49E4AE765E5E4CF504E1A876EDF33D9D8 -:1070A000C2C2E4877526A03DC77C7CFE64B3CA5784 -:1070B000EC2F97705E84819FF654EA526A619F7B41 -:1070C0009E91156CDCD3F34602CEBFE7EC39CD7A46 -:1070D00098FE22F345ACFB5A71EE532B7BC9FE7E22 -:1070E0004AAC2BF96C2FC5A15395DE30EADBD4C333 -:1070F0007AFAFE37B3F0BCC8614CA1389ABA5EFC8C -:107100006E2A3ED78272DE88FBB3325628EC7E2888 -:10711000332A8355988F9ACC764A486B532B7D41FE -:10712000A4E7E4A59C9E93ADFEC318BF4F5EAFA33A -:107130003845F259DF06F4CB92CB6505C9E44AF82D -:10714000EC10F3B78AF9D4F9D5F58CA8F44BE87EA6 -:1071500024B3E362FEAE2A138EBF5ACCEF14EB5970 -:10716000C5E83B2CC967AD55E82F27839D41DF3328 -:10717000B8E2799A35F345B7274FD99945E7E0B199 -:107180001ED90AE3A5645B365441B9CEA123FF3270 -:10719000A987513C3DA9279DE47D524FA128278A0C -:1071A000FA69420F703993D4F3502DAF6FA1D2A476 -:1071B000CA17873F8CFB98DACBB87C717849BE98A8 -:1071C000D2B87C51E9B856952BCC5A321FEAF70F4A -:1071D000FFACB5069E7BF773FEFEE5BBD95CBEBC7B -:1071E000FB25F7FB4D69BFD3A35CAA42C305FA4D4B -:1071F000BBC0ED33951FABBA25361148639A83E7C0 -:10720000871FBAC89F3B84D9D500AF6312C929959F -:107210006E6B05DDAEB3EA8349D8FE8189DE773433 -:1072200039CEE598C11EFE83AEF7417CEFF8F73307 -:107230007AEF5D41F5827E434B492E9A846C39E4A6 -:107240005860413E847948AE1E7218E9BC0E083A77 -:107250003E67AFE908C33F5BCCDFFC693ED4FFC1AA -:107260009EEB40934C3D971E412F5F88F33B2BE8EC -:10727000A629DD7B53C904FCFE621ECD7BCEFE0D2C -:10728000BD7FB2DCF61F9FC6FA2EA73A8EFA7C4F5E -:1072900068A519CFF5D09B1F9F40B4ABE35F237B5C -:1072A000EFE4E37E339AF8D0123BCF7890FCF3AD55 -:1072B00088967F8B4A860FC8BF7A6691791E12E73F -:1072C000EB59421E4D55B8DD5E6FE5E7555FB25F85 -:1072D000A6FE8A8BF655AFD28DF2E45AE47F9BF27C -:1072E00024D14B7D3EA797BD829E0F0A7CCEEC63D6 -:1072F0009DE897ED2F986E190BF83EE2D213FF1C14 -:1073000019BBC65206CF1D2995F04B026C7AC9D61F -:10731000B5A900CF5224A2A7FA92AD1D4DD07F96F9 -:107320003541A903F8E8F9B31634AF0E05BC8497CC -:10733000E972F8E354179E1BC7D3CCCAB08CFE4F3A -:10734000BD63BF8CFAF66DC4AB11E32E1EC1677529 -:10735000041F576A2CB88F23A526212F3DE3515EC9 -:10736000CECA37D58FA1757C7D6C4C1ABE776F5015 -:10737000F8953CA7FFC9827EEACC276B53A0DFCCEF -:10738000926619D77BD42C91FC3CDAD744F993C789 -:107390003B39ACD22D3D077479BC6F5B7312B66F6D -:1073A00097483ED52B2F1DE2EA8FD3A73A7E0F0BCD -:1073B000B6E17730CF29AFB7603EF5B1BE05CFCC8F -:1073C000013C1C7F533FC4B84D1FADC071DF4C243E -:1073D0003A9E6D3569F4B18C4E69845EAD1E6FD3F3 -:1073E000C0F54A0DC5D3CF2992E50678DEF35DAD31 -:1073F0007B3991D152DA77BDE87B4CE17C79CCA125 -:1074000023BE3CD6F7B89C8AF05946FB919976DEAC -:10741000FA921AB2AFCE295BF54467820FD5F154C8 -:107420003A3E8A4F231EED9CFF8FF66DB320BD1DA3 -:1074300075BF23E3395D67891A57D0A1AADFF05DD4 -:1074400071A49FDA51FBF37E86EB5138FE6B94D723 -:107450008F237DD53B64A2A7A3CAFE9A1486BF27BB -:1074600062D2ECFFFE1DC99AF19775DA3470B45DF3 -:10747000B5CFFDDBA7CBC40E66A447D847F9C23E03 -:10748000D21F77E0FAAE681729EBE8F74906D9452D -:10749000F9DC2E8AB68754BE6ED689B8AC8EC76525 -:1074A000A3F9DF58FAC3EEF1D82A498EBCBF5BC6F8 -:1074B000BA7390BEE6A31286F11ED075A723FC1501 -:1074C000EB6D8B07397CADCC7669BFBFCABF373F48 -:1074D000BED4771EE59574364CDF6165AB18E507C1 -:1074E000E86B789E115E66AD88D48B25FDF12D8DFD -:1074F0005DA44BD89B8578AC386BE4F18F9EE8385F -:1075000097EA1F8525F22BAE522EEA93F9B87BE657 -:10751000F078677F79338F931509FCE5941A695DDC -:107520008A80F7DC16FB9EB5A454FA41F9A2DF0766 -:10753000DF2980EFAF90E6619E3D55B1D79152CAE9 -:10754000E3B5779778F24AA12C2AF11596225E3D91 -:10755000605FD377C53D649FA9E3BC33CAE316FDE2 -:107560004661C9BCDC0E8FEE07ED63689C86D8E3EC -:1075700040FB387A7E6EECF643B839FC7D23FB3055 -:10758000D243060C64A6F2522AE3E516FAAE468808 -:10759000FBE70D1ED2F34691AF88371091FCC7F47C -:1075A000F534BE1C9E41F7582DD82583FBF9917602 -:1075B00094AC846A22E3AD6AB9A894DF73CE28152F -:1075C000EFF34C6013C8AFA8BCFC3CEAF343CDC357 -:1075D000EC6557C87B5EF363D349FAC3E4275FA524 -:1075E0007D600E4A91DF391F6ABF894A941C8AC2A6 -:1075F000D350F35CED79DC22E8F66AD75D657ACC8E -:107600004EF9D12ECE076B057DF5DBD53F1E3FBE73 -:107610003F1F86FECAD9FBFE93F87E4A4268A53713 -:10762000C67E5E14FBF931E5C1D370CE1B8CA1FB85 -:10763000D1DE9907A76302D27BC7F2F1F005B09EB5 -:1076400037C5FC2D9695EB6F85475B1CBA98F91EE4 -:107650006FFE787AA20D3FD9FF95E3DCFB6D20A782 -:107660005B1E7DD0ACB08175306BD915CEF947E388 -:1076700013755D6D5B305E624DBDAAF7145A5CAF49 -:1076800024E07D69EDE74D76FC0E46B43DA0C6438F -:1076900054BDA5C64D54BBA4C2C1E31F33EDFC7B52 -:1076A0003D15F669A4DF0FB2AE1AF2AF303B6D2282 -:1076B000B10AFD19DD5AFBE43ABF57463B2ADA9E70 -:1076C000A84D3345D907BD7A94DF1517B5FD54FE93 -:1076D000F8AC54C45154791765479ACF9F4940BBC1 -:1076E000EBED0B67282E148D9FEB2E5CDE9FBDAE5D -:1076F0005D4FF783D171ADB72FE4D2FDA011AF1B61 -:10770000C1D4CACC3FC48C80974C7B6B9511EC18CC -:10771000A38329F8DD36FC5833C60D8D17789C7C81 -:10772000849DFBD7898BC12F85513395A07DC1786E -:107730007CCE48EFD3995DEF91BDBD09EA86219ECD -:10774000C79E19A68B110753CF638AC0EF6EE6B7A9 -:10775000E3EF814DB18BF7F72E46DB59FC3C2DA2B0 -:107760007FE2622D3E2DE23C27835B43DF79ECD341 -:107770003E6F11E76B591AFB1CECA3639F43A27A7F -:107780000E13B6C5E1396C59BC4D8A750E998B2F15 -:107790007F0E5B845FA9D2EFB4AC04B2AFF7A6E86A -:1077A000E8FB417B13C359CB31FEFDB299DECFAC70 -:1077B000107136B4A4109F6BB797BF8471DB71A3AF -:1077C000F5748E7B25D1FFBC8EFFFE60CF78EA1F5B -:1077D00027B383F8BB8007FBAAE9BB1BD1FCBBD353 -:1077E0007A00DD33B6CEB93D6B019C8325FB8099D1 -:1077F000FB9B83CF07EF3F4A05BE4B7BF8B954A6EE -:107800009DD4A3BD5EF266ECF351E38F7BA49D3A59 -:10781000202B36AAAF8BFC98913BA3ECE9B32D64E7 -:10782000675BC647D5F7C039D1BD8E9FEC16D9A18D -:107830003DAFEB8738A74A1187307F7D8AE265FB31 -:10784000FA4E717EE9D1C62527F75DFE9C5E13E7EF -:10785000B453C4A17E2EE2009DC27F7E23E0A4F239 -:10786000CD809BEADF0A2804EF0A940B61C1CF7731 -:10787000563ECB4717AFAA84FBED47CF73BF7D7F42 -:1078800062A883BEEF74DE42DF17A4BD4D14BFDBD8 -:10789000077C722CCE49BF1F7834DB4CF1B3A3A513 -:1078A000BFFB7B8ABB7C6BD1F1B80BC7B37A4EEBC5 -:1078B000704E186F5D858BEEA536E04714A1FFEE84 -:1078C0003289BEFF341B0E04EF45543A37F569F197 -:1078D000590FFF6595F1DF1DC8427F618C8BE8A4CD -:1078E00042EF73223E37BA4F915F1E57D8EE1B8787 -:1078F0007180F17A26BEFB143445AC3B0E6F42E03A -:1079000079538944DF731A0ABFD1E58654AE2FA399 -:10791000EBFF7534D7831BDDDBE83C773BBAB25015 -:10792000AFEF13F910B3642948BF5F2877DDB11CAE -:10793000F65B91651FBB11C02DA35368FDFB4A4F39 -:10794000531CF8D88557C621FD1DB3765A30CE7921 -:10795000CCC9DF53871395F97BB79DF22D31F2A483 -:10796000D5F258E922FAFD957FFC7CEFDAD17CDF75 -:107970004C52F50A8C5B81FB4D42F9DEB202F9C331 -:1079800098B983FCCCE873AA705FB388DEF364FC1B -:107990007B4FBFB6862C783F1CED67027D6C42FFA3 -:1079A00078F7043D7DAFAD5EE6E782E788E7A41F88 -:1079B000A3137E99767C66653E63FAC079601DDE0E -:1079C000D7D03AF13EAAEFADBF9262F8B583D6C9DF -:1079D000FC9E58F9B0D1CFCD76B2209A86B3151659 -:1079E00076A19F70309FC6996DE5E3CC12717C9BA8 -:1079F000A0FF59177594DF81F4D680CF95CC2779F5 -:107A000072CCF550571DACB71ECEC641FE469356FC -:107A10000E09395B5F5245F7BDC7DC07C6A3BEBF81 -:107A2000BE74E5E13227C29FD45441B729A52FD5B2 -:107A3000205D5A942E8A2F4C76CB745D787DB936B2 -:107A40004ED1AF17A3F44BB4BEA88F923B11F7549D -:107A50004E43C4F9CF729F4B88A483ABC7CB1C2F76 -:107A60007EAF7BD6051EA71D8C97F7E973A503781B -:107A7000893EEFD878893EA7013CADEAAACB1D8CA0 -:107A80005F156FBF2E79C91A99E71B8DB71F8AAF93 -:107A9000E6D15641AF5C9E5708BE7D3B3B4471B773 -:107AA000B74BF9EF4B1D73FF96E2BFB358A8630DB8 -:107AB000CA45E0CB3942F9E823E44C341E06F8F419 -:107AC0003F282EBFFBF3B7282EAACA2113F225EABE -:107AD00013C11FEAB999901F916F2FF0EF875E2DA8 -:107AE0007FA87C45EB213F38A48FCC1FFCDFC55F0E -:107AF0007B71CD18177616523CB8CAD1A5C77BAC9E -:107B0000C950D23D92887FD23A9C91F53C6E1C5967 -:107B10004F712FA1F7D4B8A6DABE3EBB2B41185542 -:107B2000A4474DC2DE51FDC47D8E53647FAAFA5432 -:107B300016F7FE57AB4FF7087D3A54FBDE73BB795F -:107B4000DCE7CB433D0F801C9F9C6FA4EFB84C0E2D -:107B50003FCCDFA3708449FE6F7437911F0CFB6923 -:107B600046A304E67544E6F3A9E5BEF36D0AD6EF35 -:107B700095BBF40AF507FF16E0038656FA9D860DBD -:107B80008F737D1357F451D6E5DE83BAB34F99E670 -:107B90004AC2EF616F5F83DF010B2A8CBEEB98B5A1 -:107BA000B48B45EEF7A531DCAF9D9CFFD61D076871 -:107BB000DD1FEA69DD6857039D4F969D0E05E7CFEF -:107BC000F6DB23FDEC7DD9F7DA9D00B77C696C0804 -:107BD000D17AC3A37E01F3EC33578D074B8DED7340 -:107BE0001F18F50BC0C74673D504CCA3ACB6DFDBBA -:107BF0003E1FE5DAD95B2660FC1BECBC56D4B7838C -:107C0000F6DFB7CD8CBF3B5DED789FD631A2AFAB31 -:107C100006BFBF5AEDE0F748BED1BE87C64C407BD9 -:107C200039ECC1734F349F0C22DD4C16EB65172FD6 -:107C300051FC41BD97D9739ED347FFF8400FB88FD1 -:107C40006BBF5C45F722B97DBAF926A0D5757D3C9E -:107C50007F0CDBF17BE058BF28861D00F35CE74B0F -:107C6000C6F3EBCABA3786DECDEDFB36E083E7F626 -:107C70006470BC44B76F1EC3ED82B8AFDECF7292A2 -:107C80003DC0F57FB0C012F33B55B7A9FAD21A3BFD -:107C90000F452D5579A5DA23805FB32102BF9BC61E -:107CA00070FFFD7CA9A703F1F77DE77F0A710BE563 -:107CB000F152CFF631C391AE045FAD9763C601EECA -:107CC0001CF3A3C52B6E4113EFABBE73E96FE986BE -:107CD000A6DB41746550E9F821A2E3FF8BF47BE257 -:107CE000FBD0EF207974FE14DDC347D3B14ABF0344 -:107CF00074C8E69B9206E87928BAC17E8B9206E8A2 -:107D00007AA87EFBCEBF1F93DE07C6E9BD2CDDAB94 -:107D1000F4B759D0917A0F5429CE79FDD78CECFE67 -:107D2000A33D46F577C6357E11E83FCAA3AEB072D3 -:107D3000B97FB43797FB193D66BA9F9AE95E29BEB1 -:107D4000BB0D5D23C6AD11F27EA6DB755939AFEAD6 -:107D50000B55DFFD4F7C774398008000000000004A -:107D60001F8B08000000000000FFED7D0B7454C75E -:107D70009560BDEED73FA9919E3E881692A085C022 -:107D8000164640EBFF053D7D10321FA7C1180B9032 -:107D90004C8BE0041B49DD60E2903D9EA131321224 -:107DA0009FCD621FCC7866BD390D038C9DB177C025 -:107DB000561C610BDCE237384BECC671189C4C3C0E -:107DC000C243086C6CD318C743B24ABCF7DE7A0FC3 -:107DD000F56B750BDB43EBCC6457E740A95EBDAA9E -:107DE000BA75EBFE6FD5D37A3363CCCED817F85380 -:107DF0003DBCAC081A19CB65F4F305FCDBE2F2EBF1 -:107E0000252B63DFB9EECBB443F9932CDF0A671E51 -:107E100063AF5F35CAAC88B1AEA9E3F6EAB387FABF -:107E20008F75088C15437B12748676EF54C17700EA -:107E30001E31D1272E9D1E7DDE9F4CFDAECD958738 -:107E4000B3FA329D63687AAF3E8DB159F89B0ECA82 -:107E500020932D33A0CCED5AC712A0CC2CF9369626 -:107E60004C622EB1843193F29EE9CA6BDF15F03972 -:107E7000931983FEEB95F556307F5D0DC031CFCC65 -:107E8000BCF189387AD3C9C9D05ECD970AE369D7E6 -:107E90001DDE9FFEA529F3E430362E57A0F5CDFB5D -:107EA0008CF94CF06B756EEB023603E78771CCD121 -:107EB000C7A9601E99E9011DE55EDB2AE83F6BAAB0 -:107EC000C9E1E5AF4BF8DE6CC6DF1B3ECE7AC64A91 -:107ED00086C6D9E209C8FA54C68E494CE92F5B6FB1 -:107EE000C167E7F8C37A85B23E536ECD55C4CBEB7C -:107EF00092C7E10778670F868D6F1DCB583A63559F -:107F00009F699F8B0E6D7D385C30FB58FAE54F5FA3 -:107F1000C07C4633C78F395D47F8795D32FA903EB1 -:107F20002AAED4EE6293184B96EC87FCF0DC2A99CB -:107F30001D3E053633F6537EAFB8020404ED9FC2F2 -:107F4000BF1480739B6EEF5A27D0DD166C4C1FA2B6 -:107F500097250B4C1A38962E49D4D49B9AC769EAB8 -:107F6000CB574FD4EC6F73DBDD9AFA431B666AEA9A -:107F7000AE274A35F5559DD59AF156EF9CAB69FF72 -:107F8000D6EE6F68EA6B9E7F50537F74FFCA11E98B -:107F9000221A5F88B691E98979053BD2BF884D3AAC -:107FA000FCCFC59CD3A3F7F7217FC27EBD6EAFB7D0 -:107FB000AD82FED5573F8DE7FDB4F4C5BC7200F924 -:107FC000A356D91798C72B407B8D52AD95BE45F46B -:107FD0005E633645E41B95EEB60A5611C7AF66DA06 -:107FE000FDAAB06DBDAE477E2E1AD0EB61BE5937EB -:107FF000B5FC572135FC06C767CCAFC7F584CBA5C8 -:10800000FFEE18937A399E60B57F01FCC4ACC98C31 -:108010009547C7A34AA7B75D37635F6FDDCAFCEA20 -:108020007A2B58A00EE93EDABA673BFC7A926B5184 -:10803000D61DBE5E15FEEF6F865F81EF5FFF23F3F7 -:10804000ED1310DBB288FCE6DF5DEBCFB52B400211 -:10805000BC27157AA8918227128B900E980365830E -:108060007190F9510ED433C16F8452961C04AF380D -:1080700068EF34302AEB717E711086A6D245EB355D -:108080000ECA8D286F452CA9EE9CC7EB8E065E8725 -:10809000F7A82ED5F2BAE73E5E8792EA5E27AF4395 -:1080A0003FAAEF5A8CF5CEB8C0894401EBBE2558E3 -:1080B000370E1E5ACA4BFF05814A99E49638E85D8F -:1080C000A7A77EEC22AF073771FAD0F283315EF6B4 -:1080D000F9B3195F3D3C3F81BF4DC2FD5CD76F00D6 -:1080E0003CD48A82C30EEFD50C32873F15F7D5E416 -:1080F00090D997E033A033316D88CF8C2C98B14A5A -:10810000203E790FF1ADCAEDE1E368E9AB1EF55A07 -:1081100001EC3BFCBE3119E530A7A7FAB2E0122C06 -:10812000F1F913D03E7B32FC4B1E4E1F2A5CA2326B -:108130005FA5B55F8FAAB6321826B75917D15985F2 -:10814000799D2CD987CB6D7150E52F2E2FC2E1562A -:10815000E5AD391FF86C1AFB3A7C96B90A6AB3AEE2 -:10816000BEABF0D9BA303E93ADF79684F019103219 -:10817000D3F0D9B7899E6E275F4E09837526184FB5 -:10818000F60CE823CA9954C04342243E9BFB1BB221 -:108190001FA2C89737F01758676E7E989C51F45C01 -:1081A000B5AAE7FEA8B3A2DDE2677A11CB707CC85E -:1081B0002C3B31D273B53CBE0906BA6BA80EF890C1 -:1081C0000F81BE631F15DC06CF9BC9CE62B85A80F3 -:1081D000C7AAE2318C6EAD712F9D90ECBC05F5EC19 -:1081E00018856E4E66A711DFC376BDC742E49DB504 -:1081F000E8CBF101CD3709C7736622BFD540DBC696 -:1082000082E1FD33B10FF09935C87C3E78CFEA08A2 -:108210000858AF46FD9E8DF4CFEA51FE575F09E83E -:1082200025EAA5E5975B7400BF3F01A4578B7C51FD -:10823000309C2E64E6D3E37E7CD5FDAFB61F349030 -:10824000BC0EDBFF9A41B0CF004E39D5E420FA1ABC -:108250006464CFC84EC1C748BEAC21BCA8F6E3AD2C -:10826000F6266817E8912E627BB340F6D0A76CB370 -:1082700081F305F3FA557A86E7CBAF303911ED3447 -:10828000CBF3D47E6C1323FAA8B6973C556747B856 -:108290000676CC44B824BD0A973F15C7BD60E2708E -:1082A000F9DA087FD50AFEE4411D3343BBBF4F69AD -:1082B0000FA35FFF20B7D3FC4FC42B70DDC8F04382 -:1082C000BF07D04E069368E5DD03FF4384F7DC6902 -:1082D000773FDF015DAE28F0FC6F856E3FDA2451F9 -:1082E000B93ECDF5FD7CA0C77F916E7CE266C80FDC -:1082F0003944F7D5F6CF27901E52F1D93786F410BE -:10830000C24DF8E8B34483DBAA107538BC0ABFE558 -:108310008CC8572A9C2A7C577C7AAB0BC67BB3E768 -:108320005F131CF621F84B45E77E84FBCDC14F67F8 -:10833000B888EF9235766634F96652FC88A44C967C -:108340002BA6A23E8873CC85758CCB74D1BA4C36E3 -:10835000A31DFD024B2793F360487382CF8CF0F787 -:10836000A737ECD243FBD6A92233C1FB5BB3BC36A3 -:108370005AA7FE0986EB9993E96103D6E8F377657E -:108380003E29119C835047BFC7C6F1A29F68F4F8ED -:10839000E0B95FC7D61C0AC1CBC102EE8F9DCDE705 -:1083A000E5DA171ED97629843FDA0FADD3D4DDBDC7 -:1083B000DFDB762954DE6E1044DC9736858EDBD900 -:1083C000C004F45F5A453BE1A143379086F56B2C1E -:1083D000787E0AAE0FE78F00FF3FE75B623DFFD27A -:1083E000A950F68FE1FE69FF241FF90DEAFC1F2B4F -:1083F000EBFF385F177338A6011EBAB3BFC5709F75 -:108400006A6C7C3F4D50727AE67243F577869E73B4 -:108410007951A53E0F3ADE73121DE91CA8764C99DE -:10842000F611E97D27D2BB71A8BEB548D7E88BF01D -:10843000FE730522C17BC016B93D5BA1979D135CFD -:10844000DDD9E8DF3FAB736C8625CECBDC3A1EE589 -:10845000FD56DB7AA253E6E2EB58C038BFCECBF430 -:108460007819E8D179FEB782422AD68DCCC286F837 -:1084700057F50BE7893ED101FDBBF2D79971DD5D60 -:10848000B6F5661CCF84D6826E383CEABA0FECE6AD -:10849000F3CECBF489E0E9B2B9B97BC501A83FA31B -:1084A000AC7B5EEE3A6AAF6AF49F14097FE06743E3 -:1084B000DDE868F5E23C2687BD46C23A736CC6B279 -:1084C0004F7889EC1355BF0DE94FAD9D72FABA9103 -:1084D000E463D7159DCF44F2535E3007DE9FAFBCF7 -:1084E0006D0D727BBE6BBFA35FC4F71C02F9E3F393 -:1084F00073BF4D769D35772EB7E7B3567991549873 -:108500004FF0A13F314FC55B9E565F191D17B7A0B5 -:10851000FA30DED4EAD1592CC090BE2AC2FCF370E6 -:108520007D3BBB40B1D7725931DA2B2D26DF63C8B2 -:108530000F960D423AC2A1E27545818EE820867CF5 -:10854000B06726945DD965B4AFFACCD31704985FB1 -:1085500017DF6643BED0DB8C7EC41BB38A1F0DA819 -:10856000F34DC2FF3325B2B7B08E842F7D3979FC2D -:108570006E96C786EBEC32B0A648F2A7B680F3FD44 -:1085800007597E920FD1DA8D1B04D27BAA7C376605 -:1085900032D937C278DB8C5CCE805FD22B40BF3EB5 -:1085A000A417A0FF175AB3F7E905A27B19E5F1ADAF -:1085B00052B1EF120BB91FFE668189CA93CA7E546D -:1085C0007F7136C33582FCAFAAF23084DF94CAC70C -:1085D0003365F2F14C222F7395713F2EE27CDC5C07 -:1085E000147BB95F9A337AFB1C4B7A8D87522890A3 -:1085F000E879DD9887492EC5126F39A38837A35DC6 -:10860000A13F07A713B5FD7345DEFFAA20E674B2AC -:10861000B47214E5412CE9A4E2CF83DECF97FF7951 -:10862000EC47DA68AEE3A399F2D442E093BF9C2E04 -:10863000DF83E596D723DBBBF3632F77D31E8072EE -:10864000F104DF3723E9B37985B197FB4BD1BE48FD -:10865000E1F645F8FCCB153D144B79D20465B31116 -:10866000D61F01FF8F8EC2FCCB7350EF727B81E56A -:108670009EB9A40FB1DFE167B22EC43E067B141C85 -:1086800041B443053992DDED8DFD7E2D7D483F647B -:10869000AFCC615C1FA8F32F2CE1F87A7A14E0B01C -:1086A00000DEEA256EAF9BC2E050CBBF2D8CBD7DB6 -:1086B0002AE943E04805BB1FCB0542447BAFA7D066 -:1086C00018737E1A0B78D9E2608D91E4C9C9D8EF8E -:1086D0004B9A0DCAAAE9CED328D7964B87E7605CA0 -:1086E000F9FBF81FE61BD279BE61A5C1E545FFAED7 -:1086F0004BB23BBC768C47ACA2FACA7CBB43AF52B0 -:108700003EB6DF947CDB056CD7517DE5EF241FDAA4 -:10871000C3DF17D69DC9C6F136EB1DFB18C69D9564 -:108720007C838DE71BAC369E9F106D3CEF60B529B6 -:1087300079071BCF3B586D4ADEC1C6F30E569B929C -:1087400077B0F1BC83D5A6E41D6C3CEF60B5297908 -:10875000071BCF3B586D6ADEC1D33815E391369EB7 -:1087600077B0DA78DEC16AE379079897E71D6C3C49 -:10877000EF0070F1BC832D72DEC13A947720FFF1D7 -:108780001896A467B85F7F54A9CF067BDD34637861 -:108790005EB56AE7FE2D1817AB0972FC5539785E95 -:1087A000D914B4770A307E4566B0DF04FE65451102 -:1087B000C3F0D5B0F9C3F313DDD9E7BD02FAA3B016 -:1087C0009729BC03E529EA187F3F7CFE6171573B7E -:1087D0008FE7D6657E8BF03BBB2C4878C3E71887C4 -:1087E000AD53F213B556ADFF2A7FE6B2F9715F992A -:1087F000D49908F890456DBB88F92F8CBB5EF1D7F2 -:1088000061DCB76A501B7715331BD4B83CCF4B845F -:10881000C139DFE11C5F046B6A017F2A01E6CFC129 -:10882000A415AE53127C5EA4B7DD1B88BEBC3B45CD -:10883000C71468AA0464609EA512206A86D254C632 -:10884000ACD24CF29B389DFED7D4BDF1D9280F0392 -:108850007A46046C233CA8F9850458BF3483FC2B6A -:10886000F2EF2A33FDBF473A50EB82CCF338825DFA -:1088700062CD802FF96E265C3693ABCE906FEB45C0 -:10888000E635C37341E9379B05294E2D3389F276CE -:10889000B5CC4165D174576911F0A3CEEC75E17A7E -:1088A000AAEC6609F9853DEE3CDB48F1E47AE93251 -:1088B000E04900F6F862DA48768AC82EABF81C4523 -:1088C000BB481F2F7822C9AD8AD8EB61B2832A0A30 -:1088D00019C9C72D2CB2FC7CAC84CBCF374B5DDFE4 -:1088E000443CD7FB16D58F872E8FBED04A799B6D1F -:1088F00061F1C25BFD8A626F4724E7903DB901E9EF -:108900007AF1048F0DE18816C7782AF6F0EC491B3E -:10891000C1AE7B7614EC5AD443B7EC2AFB9993FA98 -:10892000503BCAB10E4FBAD0EFBA929038AADDC30D -:108930003C14678D1CAF796914E22099A8BF13FE1F -:108940000B9D63EA3A02FB87E5FBBC54E1F88E42DB -:1089500087E34B63CF17D3A0D4273E610B8D1B77E2 -:1089600059040E9741D0C0F5B962FFFDA024F678F6 -:108970002A81727DA9FC2EF261D574F96758AA7C10 -:108980003BDFE1BA40FC292DAA4F02F9BC667F7695 -:1089900001EA8906DB5EE32A80F7D552F9FD223A27 -:1089A0006FF41F5B1E6EB11E8F47BCF7B922CBA3BD -:1089B000BB1109C5E44FDE28E2FEE467848728FE88 -:1089C000E4AF8B63BE2F7BEA7386FCC970FE1F5B2E -:1089D000CCE39D6347018E06285746F1EBA68CC277 -:1089E000FC8D5ABF6EBF3E44CE104185E6696CDCFB -:1089F000AF6311FC3D9735BABF377B14D6B110F386 -:108A000071B591F5DA7DC531F7AF967E03CA0733AC -:108A10005BFDA9D0C4BC306FDA50BEB2C9D5AF0F70 -:108A20008D733F38E1E037E508707EB338E672F2C7 -:108A30007C9C1EF975BD19E1E96A067E8DB05F2543 -:108A400025DCFF9B3BE111968876633A43F711E4FE -:108A500009CF3736297E6383A27F762A72D4532CBE -:108A600052E92CE5F5B951E8FAD7CAFB8D4A9CB614 -:108A70005162F22B91F47FECE9E6FC3828E7C671ED -:108A800038EF0DF3CFDF53F4C49ED8D3CF9E0CA0A4 -:108A900093B9B591F17530F674B17402CCBFD4F6C8 -:108AA000F41C90F8B02F9B0D945F9C2EBF580CEFD8 -:108AB0006D8BC2579F2B7869863E3AB0FB5BA03422 -:108AC00042F91090815440FAED55EC6F018E30144C -:108AD0002004DEF1E8E7F43AE41E7CCE5C6DE47F2E -:108AE00084C81BCA9F569939DF74A783FF88FE0E7E -:108AF00033D33993AE20CF9F7665F2FC68383C6A59 -:108B0000FEF46F458F19CF71776516C485F2DDEBE2 -:108B10009B98266FDC7585E785C14F8AD3FA49C9D2 -:108B2000E427858F9F90B9745EA87F24C8DC1F025C -:108B30007F26505C3CE417A9FECF987CF95CF17F5E -:108B400002FD1DCD9F1147490F8B30073EFFDD749D -:108B5000F9DF108F23D0D31FA3D0D39FB0DF7F3492 -:108B60007A62CC11B768CCF071BBB21EB7B58E700B -:108B70003F2021D31991CE54FA027A9B503276E8E5 -:108B80007D21F3B44A6F134B8ABF3EBD5DC0BEF07A -:108B9000EFACE1AFECD649D1FB9DB57ACC280FFA0A -:108BA00032D79BF19EC4D4992E07CE6B11996C00DD -:108BB00038BB5C3E339E7B003B2FBF6484BCC1CD81 -:108BC000222E3F7EADECFFDC099CFF2A960BBE7D7A -:108BD000C07F4D6C9701F74D7DFF5849ECFD887BB8 -:108BE0007248EE35968C20F75E56F8E273055F2BDF -:108BF000DAD629E7995844FB6755ECFD8C342B9461 -:108C00007352D745A4E35B7487E78522AC6714E20F -:108C1000E0E7C7E4E03C4CCD2B6D40FC3E56C4F190 -:108C200017CDFE7D6A14FCB38900D74AF69901FD81 -:108C30006959FFC7AC48E7118E15D9399C069003D6 -:108C400080DF9559BAB731FCD995A4B587D4F767B9 -:108C50002BFEAE6714E467520ECEC3F11A7E0E4CA3 -:108C60002DCFC53E1EB0B488FBB9FF80FC0EFC734F -:108C7000A8A458E3E7FEA864643FF7B57F8FDC1A29 -:108C800050E8A8CB11D99E7D21F6FB40E7E060DDDE -:108C9000EF7C15B9116E6FAAE59ED8DB7B69597A16 -:108CA0009C87C3D1C8B4E7246EF1DF28E02D5D8F27 -:108CB000F368E97725E3FA5F85C3581AF3738CE705 -:108CC00067E831FFC3F9797DA92BBE94EC368F1983 -:108CD000F537D80714675FB939251FCD2AD8676BD8 -:108CE000A996BE934A47A6EFE4D23B40DFAA9CFC7C -:108CF00017614C53A8BC99A8C89B69A5B1DFAF29DF -:108D000018AF488E2CAF2B631FE7DB73774E747957 -:108D1000AC9E37FB47411B4F6EBD258F634E4769A5 -:108D2000A9FA2179ACEA87703C8D865E480CD10B9C -:108D30000D51E4CC68C03136041FB59D02E5AF98F3 -:108D40008DF9A6C0AF9DD839E4DEC7965188134F80 -:108D50000F8D7FC860AF47A0E3DDA5B1CF7FA3BC77 -:108D6000E9377CDB36D2F947A3D5C5283F6273319A -:108D70003BEC9FB1B395F2F6C605AD9487669D02B4 -:108D8000E5FD98F42EF979AB6CDEA7307D365C9E5C -:108D90006C8D395E8B72D897F637C5287ECDEBF88F -:108DA0004A3AF937AFA33C1524EE47B30DCC4EF742 -:108DB000A4AF7CB9FB582F2012302F9AC4E83E761E -:108DC000A7E1C77ACC471B053EFE5CE6E7F94F9763 -:108DD00077FCA3F09EE5A0317F3B547F519A4DFB79 -:108DE000DE69E5CFBBF69BF39F84A59EB6159EC1B9 -:108DF000F3E153A727531CECC5038F6BECEC5ABC73 -:108E0000C7807EDF0B1E867EA229D33571243B9C52 -:108E1000317F92AE8C509AA8947A5EFA059D6DF8D7 -:108E2000FB3BF7F748E867BD78C04C727FEA819E4C -:108E3000F85521E32796713EB6063DFE1900AF3581 -:108E4000D3733209EF1D2BF9739179CED4C22B6302 -:108E5000A4009D0FDF91576B0EA5BB2EA9D64C79B0 -:108E6000E45C9D638A1DEBFC1C43FCF4DAFD82404C -:108E70007EDD2E1150EF9AE1BA867AEC0D89EBC3B4 -:108E8000A9536B49AB752AE71E76E42D3980EFC7ED -:108E90004FAFA7F13B59647BCC58C6E5F08B0699E0 -:108EA000E67DF18048E7C855BCDE697CD6CB300F43 -:108EB000E0A3DEA6A77BD8A78D4E11E5D0E93481CB -:108EC000ED822DDFE97885EE99EC8802EF2F4AB923 -:108ED0009FCA6CA9447FA7F7772E8F747E5FA5BFCA -:108EE000C93364A90CEDC0499E2694FFCCB6E43684 -:108EF0007CF124DFBF4387E6CF03FCCF7DC17F2217 -:108F00000EF7216BCF785CF707A5766ABF450F1F78 -:108F1000BD42F4B0C5C8EFE37875718E03B08E859D -:108F2000D60111CF4F18528394E76D2AE3F2748B68 -:108F3000CA0F63811FE03D7D06BF07C526DAA9CEB3 -:108F400026072784DEA39E55A6AC970532F1F9C209 -:108F5000F87737D81D8C15F6A6378BB0FE8589EFCC -:108F60006EC8867A49EF785ECF78F7B36C89B1B274 -:108F7000DE0C5E9FF6EE6793A05ED19BC9EB953049 -:108F8000D478B09B7AB39ABD7938BEA419BF150FB7 -:108F900072147FFD526FD2458C5F3528EB871F031B -:108FA000CEE3ECFB473AEFE2345BFD782E83C986D3 -:108FB000B0F8193485DC7760A90924FFD4FB0BF3E2 -:108FC000457F3FF6D799FD84DFBB5927D97380AD24 -:108FD000DD5F147E797B2E5CEE6DD9C85C784E8C9B -:108FE000B16609EF33084CD67DC1E3784E9C5F85AE -:108FF000479D7F185CB0B5C89F43703D4FE3A87094 -:109000005DCB377951DE7A6B59AE27044FD784E0B8 -:109010000F186C45DAAC1D0FE13E5D1B139C204020 -:109020003DB97C1BEDDBB5B1C11F088E90BA81EF55 -:10903000635B6F09ED639728B7219D9B8CD66E21EA -:1090400091B1EEB884190CE6D931D6E5C57B6E40F6 -:109050007774EFD89B65741C0038EB8BB4F9A1C70B -:10906000153AFB83220FE6987679CE015DBA7B0430 -:1090700086F770DC83378CA8FF16F65D3462BEA4D9 -:10908000A3E7A211E9BE03EB304EC7F3C688F96F20 -:1090900063B95EBD2F4AE791D64B1C4FA7B2EE7A5B -:1090A0002A15E0E9582DD0BDBCF54792E6607D7DDC -:1090B0002BAE92B1E55587E720B9B438FB9FC27259 -:1090C000251B38950A24B4CCA567F6103DB9624D2E -:1090D0003CB387E8C9164F8AA6BE7217ECCE0C289F -:1090E000376668FA31E5FEEA3236F483E7989A94F7 -:1090F0007D5C66DB19C0B8EE3297C13B1032DEC230 -:10910000BECD6232C2ED111C748DD2CBCF3FADE02B -:109110002B84521C7A1FCFF7F40AC4EF1D6D7ABA64 -:10912000C7D3DCCBEDAEE63582CF2E201EF8BD0DC9 -:1091300077AF40EDEEDEA7EB9311EF1B000F00477A -:10914000DAF8847D2C114793E9DCD54A055677DFA0 -:1091500039038EB3E23B02DD6755BF9BA0C2BFB2AD -:10916000A991CE91017C5EA44F759D4DF647E95CB7 -:10917000D5CA89970DA887617D970634F8D4D65B48 -:109180003CDAFACA8DDAFAD132E59EF234360DF9BC -:10919000E9789920E23924B5FE51D6F9B7F15EE7B6 -:1091A0006ED1790AE9B3CDE89F81FA7EB7E8A2BA19 -:1091B000DA0ECF3B18F19DF8E100F1B140FCB9C5E2 -:1091C000204B35F83D977681E87605B6ABF3670F0F -:1091D000BD4F75FDF0FA4D55EE5A9C1BE8BB30476C -:1091E0000509ED907A511693F3882F229E77F9BDE9 -:1091F000C2076FA3F603B8EE4222857DBAEBFE44A8 -:109200009F17E6BDEBCD563AE7765721D0811DF981 -:109210005E47E7D6E6E3792F28EF03796881F22EDF -:10922000FDA12692EF338D12C977E59C972A2FE492 -:1092300017B5E7B6E6679E213BEBBEE776D279B578 -:10924000C93972C1D3A80F2D7CFE1D4704DF6618F3 -:10925000A723EF34C9CF71323F2FD76153E4682F72 -:10926000C85175FDB0BFE350AE612269411ECD9B70 -:109270006E56A95D263928F86B75E8FF8E53E6DD3A -:109280005F6DA775A73D7A48C0756731EF6601E647 -:10929000BB823A7CEC50F955EDD7B5F80BE85D563A -:1092A000AFB5635B45D7E365305FBB6DC0C8CF2DFD -:1092B000068DA81FEEE0F8DE48E3C3F27574EE50A9 -:1092C000E2FB30473F988076CEFAA339E3D808F620 -:1092D0008DDEACD3C8118314A79137F373B5F26751 -:1092E000A1432B77BE5196A3695F244FD3B4DFDF30 -:1092F00058A8A93FE0ACD4BCFF60539DA66EB2CD88 -:10930000D3BC6FB12FD6D4E373976BDE1FE358A5A0 -:109310006937BDF5A32601ED71B377C00578E8067E -:10932000DE284B1ED223D312E06528E30A2D562CEB -:10933000BBF34D744EB67B3CE89744ECFF1D3A7787 -:10934000694E7CC95C03E5DF0BBE5AFC7E0EA0C9EA -:1093500085F6DB3D4F68E3F0C7AB385FA96543B9DD -:10936000EBC10A28F35EB067F07BE9817B707FCCAC -:10937000718CDB45AF99C92E9A89765388BF71B03D -:10938000BA667E39F67B42BE17F982F532690ABCAD -:10939000B7CF083B8B7AEE3523F5CBEB1DD085E6B6 -:1093A000F77F59CEE5C1B3CEDA7B71FC8E3ED0B2E9 -:1093B000C84FCF7D6844BFAEA3AF3F01F5D90CE7DE -:1093C0008746B4CF879E2B7A4E0CC6619CE31F0E56 -:1093D000E923DE63DD5E6EA4F14F2B72BDE53B7ABF -:1093E0003A4F8BF7376B4A86E473CBE1A01FEF63EC -:1093F000B7B4F37B9B788E36929C06F9FC61A8BCCF -:109400007D361DF4C14C1A4FA30F9697F9E9DE3E45 -:10941000C86FCDFB2B97345CC57C25C871EDF34C30 -:109420007E1E96B10103FA7320D735ED1BCB95FB59 -:109430009CD358DE1720072E3823DFDB7DBB8A9FA5 -:1094400033B8E0AAA37D7816F089E7479F1D863FD1 -:109450008ED7DBE1ED65A48190FD1B66FF5771FFA0 -:10946000EAE52872FBA2B2BFFB8440010A55B7337C -:109470008EE87785B975EDA542DC97CFB7A2BFDE40 -:10948000F22381EEC1FFB2FFAD343BACDF78F8547C -:109490001ADE97761F3A9586F789DB0CF6CD68CFF2 -:1094A000037DD03DE48E5E3FC1DF7EA8B01F9FB735 -:1094B000F70A0E14C9EE9EEB0DB44E36B015FDA39F -:1094C0007D51E03A58CEEDABC3E5762ADD2E9813F8 -:1094D000F57E8FC9E713901E403E215C47C00F8286 -:1094E000FABE6DE6A648F6D46505DF27B71919DE82 -:1094F000FB6D83FEB88ED359A78DF8BD8596C3B09A -:109500002E01D771EE81781C7F8381A19DA1C2F7C6 -:109510007156E0035CFFFBAB0D0CCF2D6F59AD27EF -:109520007CBFBF81DB27FA877FBD3503EACB802E66 -:10953000F13B0F2756DF389D01E3BEBF86DB69751F -:109540000F1B882F97AD136EDD4B0EA56B956EFF2D -:1095500046A1D370FA0DA7DB61F4BAE6EBD1EBDBE1 -:10956000E5B7EC9019A8F761FFE78C433AFA1E7350 -:109570001C407E1A3C611807704FDA2A39C0C36359 -:10958000D3F5BEA7D2506E9CE0EDF96D7B052E7F22 -:10959000ECCB717D19DD4686F7082E2AFB7651D972 -:1095A000373B0B0AF1C8CF626012CAA96C25CEF90D -:1095B0008A81351D46FF52E4F267FA8F6D7BB787CB -:1095C000D0EF7F2BE774ABCAC56946E63A6CC5F7A6 -:1095D0000F8D5F04E3BC6CE0E7352728E34DC90934 -:1095E000362C825257C1E5E46F1538D4FA9F143EE9 -:1095F00060277F43F85C68E6F89FB7D1DF8CEBF813 -:1096000099C975BD1CDE5F30E17C1BEABDEE493FA8 -:10961000C9E3DFB973901DEE56F07FA2FC37CF632C -:10962000EECF32358EF6D772F46909E9D932A568E2 -:10963000DC48F130F7CD6CE64A01BABA9943A55A35 -:109640005F74FCAA7180FC82EB0DC42F37D3E9B99B -:10965000DAEF5305EEE9468E07D6974A7A1BE4B651 -:109660005816926750F1A0FAE39629FB69BF1E5B7A -:10967000C728EECFD8D3848F156DE7845618E741FD -:10968000836CB002BECF2736ADBD3485B19F6C620E -:10969000CC050B3ABBC9CC5C77037D6C92A81ED875 -:1096A00064A3FABB9BEC545EB638C7A2FE79E0A473 -:1096B000670AE2ED44D61E672DCC73EDAC81F04114 -:1096C0003B06F4FD98426B37FAF4CC0CED377A94F4 -:1096D000EFAD28F03F743383B940BEFC02E7838EC0 -:1096E000ED1B7F4672CFB1E67A03FA49F96D17B7E1 -:1096F00062DDBDF1770D685F7C00FA04E90CEC7E59 -:109700006613509E9C33DA810E9A6FA6D0382FEBE9 -:10971000820DC877DE630243FAFCA0F7BA711CD74A -:1097200057742DE1F94D74E69F2DAD4822FCB8FB2E -:10973000F2757C7F8B74A1F729FAEFF94302EE876B -:1097400079A3FD9D4AEC7F46CF90AFB7D70613A40F -:109750000872F8028C8B97A3701D5886B73719BD15 -:1097600053F03C419342C7E1ED8B15FA044C1B9436 -:10977000EF2932218D9F23C19F1658526232F94141 -:10978000FE38E0E796BEBAAB22961E817DA8F5CFE3 -:10979000D88721767C343AFCB2257E43E6C3294340 -:1097A00075F42343EF7FA01F19E9FB82A6ACC9E340 -:1097B000468A77B907C0BE83FDEA00C3C99E82F41A -:1097C0003E8DCA4F8E74D9917FCC71C13DA82FD8E0 -:1097D0005D3AF23BDABD5A7BA841E18706C51E7AA5 -:1097E000B442EB3F819FD45EC1FDA484E34CE33FD0 -:1097F000853F27FFC98C7C05F34E83FD7925D2FE7A -:1098000054D5AEC77E13D82EA27306748EF415BE3F -:10981000CEBFA8E07A54E5EB65C8D748BFBD9CAF82 -:10982000C3C76DA9AAF90B1C775B947B10F757F19E -:10983000F1DA9F13085FEEE752084F1FB3E79CB5BC -:1098400040971F031CFB802EAF399DF149D0FF9A32 -:10985000CB199F6C1D92031DCFC553BF6D9317A7E6 -:10986000B442FD19A47B18EF93DE3A8A6F3EF41CD4 -:10987000E73F75BE0FFCCB52909F8A0D41A303DAE0 -:1098800033FB2E26A01D587CE4FE14E4C368706EE2 -:10989000AD54E0DCF8D8DA4B299C1EF01CEE5A459A -:1098A000BFB99FF41B11FF6B3732A2DFFED77ED901 -:1098B000817CFC495FBC84FAF0E3A3F15E94FFD79E -:1098C0008E997C3A81FC106F22C8B58F0D03F791F9 -:1098D000BD79442FA1FFE83EF6DB3DC88FEED74CA3 -:1098E00068F9B1B57D5DD751EFB5F5DD7B55C4F2B3 -:1098F000A5D1E587F68D8FD37AD5FA6F3799ED2804 -:10990000473F11B99C58DBFB2AD9BF6B076FCCC00E -:1099100038EAC747FF4F09CA35F79B374A509EB907 -:10992000DFB85182EDEE1FC77B22D92D71B3F484CD -:1099300057555F66BF276AE2451B14FAC8EEDCD5AF -:109940003809F0577C6E8903F3B66A7BF1149D13D6 -:10995000DF2FFE797DCAC321FD3A0322E58D8ACE31 -:10996000D5C7AF0EA1CB47AA0C9AEF947DD5380F7F -:10997000B6E2F72D6FC575023AFA0EECB680C8BF95 -:109980002FBB46F0A1BF01F64B783FB2A7AE3D9288 -:1099900042F71099E89C3FBD08EB531CDBED2856BD -:1099A000CCA72687D84BCB023ABF09E8A8A9CFE4B9 -:1099B000277B3F205EA4BA62473D74FD3763B285C2 -:1099C00008719ADC77E7A01C0F8FD7C0CF18845B93 -:1099D000B5AFCEA7F3F851A647D22D04B89A3B995C -:1099E00084781D16D7699A4BF1A2F0F88E3DB0DB52 -:1099F0008CFDEC937512C2ABDAA5B88F3D11E4C0B3 -:109A00005F567279A6F2576780E7F53A03B5E6C963 -:109A1000507E5769EF9174CC0B78E9ECBBFF00C620 -:109A2000173A071F8C9F0EF374BEB798619EE79A92 -:109A3000546B9E82FD06E79A1FC81BA29BF0F91A81 -:109A40002AB95D34642F44D67FA50A5F8F961E2CF9 -:109A5000ACFCF3D083E09F575472FF7C058F9F705E -:109A6000FF3C5C7FA872591D77AD82EFE172F92A45 -:109A7000D939E047935C5E5B69A7F732FB16A59086 -:109A80007FFDDE9214BB75F8F839A243979C377CB2 -:109A90007CD59E737BE55366F47B643DF1A77B899F -:109AA000E0C3FC976AFFB99D02D9E5EE66830FDF3C -:109AB00053E10A2CE1F1D8076483CF220CD989AA9B -:109AC0001D79ABDD2150BB6A57AAF663C0C9E3BB61 -:109AD0004B8A78FB658B6B55E5585CA7859E17977D -:109AE000F3E78C394FA15FF5E05281911C50EC4AAD -:109AF000954EC3EDCE4FFB7212478A433DAFD0A7C0 -:109B0000CA6713C2F843D563CF54707EEB403D5E05 -:109B1000887AFCF71AFB3C7C5CD0E38F57523F46B7 -:109B2000FD8B7E2E3A23F9EB6665FCADEAFE054E11 -:109B3000D620BC592CB019FDCC68FAF57B8A9D1350 -:109B4000ADFD19C57EBC1D3F1F56E4C868F1F3CBBF -:109B500095B7F270FFA9F9F9967D688C62BF57D569 -:109B6000BC86FB1FA7F7046A90FFFE9781E2EEE137 -:109B7000EF3DA5FA9F22D3ECCFA92CA30EFD23F72E -:109B80001A1E3FE84EB2BF437ECC5B7A86E3AC053B -:109B90007F10EDB8476F2651D986F632942B5E3888 -:109BA00047F988156BB4F077634C17FBAFCBA6F37E -:109BB000032DAC9EE24C2D7D49D216500ADD630F79 -:109BC0009D46BEF21ED0DB0F84BEFF88FABE99C749 -:109BD000E136A6FB28F71A660FB478C2ED7EAD7D9C -:109BE00050A9C48DA2D9096FF45BB85C39A3273E94 -:109BF000EFC078D34CC68C7D5C2EB837F23849471D -:109C0000DFE604FC086ABBD27E450C501C8AF26B6E -:109C1000F0EAD5BEA7D3E83E97ACCD27B5EFFF3924 -:109C2000C9CBF0BC52720F974BEE36BD92472AA1BA -:109C3000EF97B7833F390EED4BBBFD1B8877808BC9 -:109C4000F948DEC89AB8CB3E25AFF4E9997F253FA5 -:109C500074C5912879A4EE793C8FA47C2777781E6F -:109C6000E9F4A90CFBEDF3481DBDE7E81ECBEDF2CE -:109C700049A6AA5B711C8A3B4E14797C77629F20AF -:109C800061BC6A621F5F77E9B638B2AF1B7EB53A36 -:109C900005E581BA4F9F2CE2F8FDE4FDCF6AB05F85 -:109CA000C9AF44C902EB7AE3FD0D3FCBE075BBD9E8 -:109CB0008EFD36C4A33FF3C9AFD6C7237EDF801223 -:109CC000F7E7C717C4C8F1C9A178756615C59D9592 -:109CD00078B508FA70CC505C27BCDF8B555C6E748D -:109CE00083BB4271CD233CEFDF9DEE9A47F5BF9ECB -:109CF000C4F8DF2990291EFD2AD035C68DA6C16281 -:109D0000312FFD3FE35827E691BAC7BA7E427CF473 -:109D1000D73A3BF211F4A7FC93F7B09DF423866A7F -:109D200031CF33033F5B40F7315229DF738FB28F5E -:109D3000E9E0CFA25F09D02CC13CF43425DF332306 -:109D40008E8938FE0E836BFB54CC2FF58B8ECDC4E1 -:109D5000048E143C6F199E7712649E2F57F34F6A3E -:109D6000DE3C5AFE49C07994EF56F0F396B280F982 -:109D70007435CFC4963A29F9B5A5CC43F7427C8017 -:109D8000B3AF73DE6B84FCCFC31511F23FEB2B989E -:109D9000629F69F38DDB735F213AFDAA79C6C378B0 -:109DA000AEE28EE6C5ECDC0F0D83BB28E9D334F2BE -:109DB000BBFEF86F09A467FB6E903EBC1634B10081 -:109DC000C51F0778DCBDCF4071866BE0BF8D0DD11C -:109DD000B3EF54F0718FF7D511FDF704EAE3F1FD0D -:109DE000DF2BCFB7BDB7E47EB4F7BD01FE1D0BC6B8 -:109DF000B83FD613108BD16EB983FBF2646584F53E -:109E000099E3B87E0AE7A35285FF4AAB389EEBDEA2 -:109E1000E77E987B03CFAF488A5C707B785EFD74E9 -:109E2000569AA0C6D3C745CABF1C0992DE687944BA -:109E3000A0EFC97CD9FCCB33E991F3F12B7A2F4603 -:109E4000CEBF343690FC8C16CF0E8F63FF9D2AFF59 -:109E5000A6F338767A9544EB4EF6E4D78C6343EB61 -:109E6000BF83FBB07456847DB883E36F9C1DDBF128 -:109E7000EBCA633BFE13311E7F7B8CC7FF61796C9D -:109E8000F3EBBA8AD8C2FFDB18C3DF1F09FEFF5706 -:109E9000CF0784E7FFC3CF0B849F0330BDF5B01716 -:109EA000DBBA849D413FC3EF8DBFD624801C149341 -:109EB000F6D37DCE05E53C1FB6ADDEECDB2B0C9D6D -:109EC0001B50F1F56835F723A5BCEB5EFC5ED404AE -:109ED00039509F82F1B272FE7743AE59785E8C8919 -:109EE000523AE6C9E0CDF4C56097745B22E7595356 -:109EF00095F1A2E99183D5358B6715E31F3D8A7CE7 -:109F00000EFF874A1C52EAE5F7E999684F5F4CF368 -:109F1000DAD3D11E4A3CC99F27F899BC97E0B267B3 -:109F20002FE67FDC201BE17B46C9FF26CFBB2B1B26 -:109F3000E3D2C96017625EF069CC0F923F2BD17BF0 -:109F4000EA7C9766713FEA190313309FEB9DCACFF5 -:109F500039B19EDF91FDA6E6F5CE1AFC975A05CAE7 -:109F6000EBB523FC3FD5F9F3F6652B440CF8CDEBAC -:109F70009128DFF876F9DFE5BA681E9EE77B4CE2B0 -:109F8000AF9C40BF19E078EC6821D1EF8AE3E5FF90 -:109F9000D48CFEC76491F03CCCAF54E205179478A2 -:109FA000871A2F50F35BFFACC4493EC0F80B9403F3 -:109FB000180F8172FB2CDD9DD64FDB6745E0FF67F4 -:109FC000041E1FF2FE94C7870A8D8E9CD0F3947FE7 -:109FD000358BEF63AB9FE72FD478CF0F95F5147EC9 -:109FE0004FEFC7EFA1156E9D6E443D5FB8352B0E48 -:109FF000CB19B24F9706F85EB6FAB04EDDBF487483 -:10A00000B45759E7B63341CAEFBD1A96F7BF348B40 -:10A010009F6768A9E6FB7B09FFA018D41F9B226EEF -:10A0200041F331B14AD247CA2BB5805F8C70B67606 -:10A0300073B8557CB7F8ED7538CFC553C1AD581618 -:10A04000ACC9AEA3B87BDBF5AD68BFB9076F9CAEFA -:10A05000A67899D18EFEC44303DAB8DB13D53CFE53 -:10A06000FE2A1AE088B77B45F28F0BEF15897E92A6 -:10A070005B2CE4BF261B98DE8AF545DC2E2A684C53 -:10A08000ADC33A5B9244F660C1197BD2C379437188 -:10A09000B0E47B378C453CDD2ECFAAC6D32E5BE4E3 -:10A0A000E3B89F5F35CFDA7EF63D3A6FAAAE4BC577 -:10A0B0008B9A2F8D966755CF3DB81B3FD39CD3709D -:10A0C0008BC1068C3F161EBD6854CE5F4AB6ECA10C -:10A0D0003C6CE191EB947F55F3AD6ECF75B2ABA1C3 -:10A0E0009F11FBF76CE2F9D7D7000E2C7B61DDB234 -:10A0F00009EFA1DBA8EC8375E3F3639B72A9F46F0E -:10A100007250797C531995F899C9F464CCDB5EA739 -:10A11000BCEDD559C3CE4D525E6FB7E8FC08F115C2 -:10A1200092F7A37A78DE4F1FC7E335EE3306FABE07 -:10A13000A1FBAC99E4774D5FEB44F40F3E3FE79A07 -:10A1400088707760DE2D842E3E911D9624F4839DC9 -:10A150000E0BE6DB0AFBAF1AF13C4C871830623C71 -:10A160000C20CFC0238BEE9EEBFCDC6F5F8D05F1E6 -:10A170007BDBFC58EFFFCF8F7D95FC5877353F2771 -:10A18000ADCA9102A74EDE8BE519D9F270889CD832 -:10A19000E6E4F9946D9327111FEE764E4A5A1D326C -:10A1A0005E67238F5F24DF3BD912FAFC97D53C1FF3 -:10A1B000962C306724795633FBEBDDC71B416ED7F5 -:10A1C00044B2FB3FF929D0E54CA08B23DF9E3890A9 -:10A1D000C7193F341EB7AD71F5C431289F2E98D8EA -:10A1E000141EAFD3C4E358585E2E5A5C6E45A34E7E -:10A1F000B6D079A1E004D4DBE1F13326062770BDA7 -:10A200002E67E0BD1498318395B161F9B95F30DFF5 -:10A21000CF27C3FBCB1A75A42FD43C5D41A3C8360E -:10A22000017D166C34F8283FD7285EA476C56FEC04 -:10A23000940A3290CE3F386B9430AE161E1F7334A2 -:10A24000EEEF9E04FD1D6D02DD0BBA5D1E4F3D0756 -:10A25000DED2DB3F07E36DF96C57773DF4CF9FAC5F -:10A2600093F0FCF4F07C1E3FFF5DA0D839E171361D -:10A27000A433B44BC2E3F01B153AD8389BEBADD7EF -:10A28000147F531D47ED174E3F3F9DCDF56DB4B87C -:10A29000FE5165BCCEC6826D93717F17E818EA93B4 -:10A2A000CEC65AF3E490F176CCE6E7DB9EC1FC60C3 -:10A2B0006A687E90E701C3F382AA9C2BECFF7D03C2 -:10A2C000E27B37C86BD4636E1BCF1F141EAB398380 -:10A2D0007263084EAEB777C39E07C8BE732431BE03 -:10A2E0002EFA7B45DEA302C5E70A167C763C1EEA01 -:10A2F000CC9944F7B0DC67276FB1A23C5A2016E333 -:10A30000BD1EB753B89567C27CD2FDEFACA1EFBCC0 -:10A31000163E907F0EF7E58166039D0F54F5DEFD36 -:10A32000EF3435F0F6BD4FC6617BAEE0B0D8F179C1 -:10A33000237D3F76FE4B7EFABB580B113A90E781A6 -:10A34000B39744E49BCB16D7DF231F152E52F24C54 -:10A35000CD5C4F3FD0B7C8C0C8CED3EACD13599F0C -:10A36000533CE8465F21E58F52F0FC43DE90BE2966 -:10A370003C0A7A6CCC9DD3633F9D2D113E67821EB3 -:10A3800043789217F13C7DF8FEEF50F63F9A5E8AD3 -:10A39000268751FFF0FB63DE0CC1365C8FDB31EEAC -:10A3A000538AF63A94E3A2D3DF1F6671BA4E8A62EB -:10A3B000CFFD49A1DFA8E7A77A4727CFF487D97F48 -:10A3C0001E7963D5FF52F34DAABFF6A0620FAB65AD -:10A3D0009352FEBBEF37A0728D78BF2139F2FD8614 -:10A3E000870E0968A7A8F71B4E1959CDE1543C4FB9 -:10A3F000ABDC77F22D223BE9D4DFFC62EB8BA97852 -:10A40000DF4990501DB51F3A477ABE1DEC23B2A715 -:10A41000FA7ECBE3AD87F8F9F0F6DEC8DFDDDBAD21 -:10A42000D8DFF53223B9D1AE9CB76DE851F244B70D -:10A43000E2968F8BA1714BB73D30563DC7EB237F22 -:10A440004F1BC78C16B7EC60413AB7DBB14670A022 -:10A450007EB8DD39DC5DCA79DDA8714C79E473B969 -:10A46000E1714CB95A9BC7B96F96C4F7DB250868F0 -:10A47000EF9A75CE363AB77F4C90229DF35E5ACD57 -:10A48000E5F47C250F72D0C8E9E3608540F76FF0F2 -:10A490001E1EEEFBC163FC1ECEC1027E0F47CD7BAC -:10A4A000A8F76BA60EE53DE8FE9D7A2F47BD67C372 -:10A4B000988FE05AF45C1C7DC76B87E1908DDBBD03 -:10A4C0005E7E3F1A6510E6434DCC13895F6BAB6B24 -:10A4D000C46A7AEF8EDB4F8F5447F07B7D8A1FE989 -:10A4E000AE8EEA2FACAFD6FA0B540FF717EE54DE50 -:10A4F000E38BD9EC4EFBFB87631C8F9E323BB6F19E -:10A50000C4EC48FBB6C5A2FD1EAF5A5E56E4DFB0F0 -:10A51000EFC50DBB2FC9F57AB760FFA74ACAA71BC5 -:10A52000289FAECAD5EE317CFC1F29E3A9654029DE -:10A53000BBA37CD7F9974ABCAC4B947B10EE692F38 -:10A5400068E397D30F69E397337B9335F57CFF7806 -:10A55000CDFB85672669DA8B03F768DA4B2F146821 -:10A56000EAE503159AF72BAFD46AEAB382DAF86505 -:10A57000F5CDC561F7387DB4BE1AA0DCD07E75E696 -:10A580006F6ADECB58A35D579647BBAE891BB5EB10 -:10A5900052C7CDF66AD797D3AD5D5F32E6E3F2BE20 -:10A5A0007E3E2E7FB65DC9C7E558B0DF338D932D53 -:10A5B00068B7A9F7A9D5F7FE2F376658DF407F00A7 -:10A5C00000000000000000001F8B080000000000D9 -:10A5D00000FFB3E46660F8510FC17BB918186E72C2 -:10A5E00021F84301CF6786D06A2C0C0C1A40CCC6E8 -:10A5F000C4C0C0CE44BC7E714E047B1D0703C34C57 -:10A6000020DEC831F0FE1A487C9D877E76A9F34291 -:10A610006859C181F73708570A3130B40A3330C45A -:10A620008840F80CA2A8F2554208B6A924657639EC -:10A6300002F5030024CC7134800300000000000008 -:10A6400000000000000000001F8B08000000000058 -:10A6500000FFE57D0B7854D5B5F03E731E3393793A -:10A6600064F2200F02F18400A242180284870827B6 -:10A6700021C4A8018380BC54263C43483211A8BFA2 -:10A680006DBD77260411ADB551691BBCE81D1014D2 -:10A690001575A0D1061CE84014B1DADBA8F8A8D5DE -:10A6A0007650444048C2CB8B2DD57FAFB5CF49E61D -:10A6B0009C4C48D4F6BFFFFFFDF1F3DBECB3CFD9E0 -:10A6C0007BEDF5DA6BADBDF61EC1329A244E22E465 -:10A6D0005BF8A365842784F4E92CDB0ADA8F9164A4 -:10A6E00042FC2F8BF2368E10EE778EF0A45184BC94 -:10A6F000B5990B98693DBCCF4608AD9FDE343D60EF -:10A70000CE2264FF08B302EF9FDE9A8FF5C92FBDFA -:10A71000E714687BD54BBC0075D3BE13CE889D1063 -:10A72000AFB9E5A16BE9F3F69778B2850E45FC93D6 -:10A730004D2485906316C2FE2EB2FA522BAB566D95 -:10A74000DE7F07F45BDE642656DA4FD5EE65D3AEC6 -:10A75000A5F565874402AF546DAB95FAD2FAF200C5 -:10A760001784FA9A7D7FC671DA0A48797028212702 -:10A770007D16225F49EBCE969459F47945606711B6 -:10A78000BC5FB183739BE8FB159BF67F0CFD5734D0 -:10A790008A0379DAFF8AED36220F61637F4B601EF0 -:10A7A0004BA601BC556F88C44CEBE5975649047025 -:10A7B00024D44BA50E18FF614976C03887701C0D54 -:10A7C0009F55CFD071E877D52F706E985AB589789C -:10A7D000009ED6DDD6394FDA615EB5D260F87EF7DD -:10A7E0007D12BCB72C50F6B25506F8364B4500E743 -:10A7F000A6CDD2D2A19DFDADD8FEA60EAE630DD9D9 -:10A80000A99EA8766379D247886CEEAC5710A20453 -:10A81000ED0077409A3EACF3F9792E8190D1D03F8C -:10A820004F644B67FF9430C807FEF7E83F810FF68F -:10A830003A02DBB23AE9B5D245FF2D77D2EBAC4B09 -:10A84000A59FD09E17DDBF563E0474A0F0D4FB5CDC -:10A85000583EE24BC372834F46BCFDCA3704CB0659 -:10A860009F1B9F3FE61B8BE5269F82E513BE622C54 -:10A8700003BE527C6F8B6F0E965B7D1E7CFE94AF89 -:10A880001CCBEDBE1A7CFEACEF6E2C77F8FCF8FC0E -:10A8900005DF7A2C83BE7A2C77F91AB06CF405F0B8 -:10A8A000BD977DDBB16CF205F1F91E5F1396215F58 -:10A8B00018CB7D405F5A867D2D581EF07D88E5AB14 -:10A8C000BE087E77D0771CCB0755BC3B27907C8198 -:10A8D000E2CDA9101715179258A2E48BB49E58CA5E -:10A8E000EA29B7F9F3255A4FF1D03AC563DFCA70A8 -:10A8F000BE99D6FBD6B0F6CC7B488185D633FDAC6D -:10A900007DC0834A8195D607D4B3F6C19BFC0571FF -:10A91000B43E38C0DAAFDE112EB0D1FAD541D69EA2 -:10A92000132293EDB49E1366F5DCB794C90E5ACF8B -:10A930006D61F5BC8FFD939DB49E1761DF8F3F1550 -:10A940009E1C4FEBE3DB59FBC44BA4D045EB130932 -:10A9500087F5027B7E6102AD17B858BDA85F9920CC -:10A96000C7E0BF7D626411A1BCB0DD7FB322A4D378 -:10A97000BA145945DC149FFE39580F8B6431B4BFAB -:10A98000E52F538471B42E91D5D0FE177F05B61FE5 -:10A9900010656C6FF7AFC2F603928CEDA6DA7BB050 -:10A9A000FEAAA8607B72EDBDF8FEAB9282ED836BD0 -:10A9B0001FC2FA41D183ED636B7F8DEF1F943CD8AA -:10A9C000FEC8DA805248EBFFC179B6005FD7719EAE -:10A9D00072920DFC1A4C2BA5FCBA8E2373403E1EBE -:10A9E00000A6A6F2B02E5D5240BFEDFB47DE933CC1 -:10A9F000A7F27632D4973EF54016F6F31CF623D232 -:10AA00007EF89EFB99F8CD585D3F13BF29D7FA69B0 -:10AA100084F7EAACBDEB67DF37E3F5F07C53A1F5D3 -:10AA2000B317FB71F46E5E13BF9DA087E7DB4AADE1 -:10AA30009F83D84F42EFE0098B6374FD84C5655A4C -:10AA40003F7FC47EFAF40E1E451AA7EB4791966B22 -:10AA5000FD7C88FDA4F7AE9FB074AD1E1E6985D63F -:10AA6000CF11ECA77FEFE6A598AFD3C363AED2FAC0 -:10AA7000398974CFEA5D3F071C7AFC1C7074E0E7EB -:10AA80001CC233A877F32A70EAF153E0ECC0CF255B -:10AA9000ECE7AADEF573C0A9C7CF0167077E440EB5 -:10AAA000E635AC77F32A88D7E3A720BE033F4E0EE6 -:10AAB000E019D13B785EEDA3C7CFAB7D3AF0938A26 -:10AAC000F08CEE1D3C85297AFC14A674E04746788C -:10AAD000C6F5AE9F5753F4F87935A5033F57613F4C -:10AAE000D7F56E5E85A97AFC14A676E02717FBC918 -:10AAF000F76C477808EDC7D17D3F07FBEBF173B0EA -:10AB00007F077EAEC57EA6D07EB27BEEA728538F90 -:10AB10009FA2CC0EFC14229E6FE85D3F0733F5F830 -:10AB20003998D9819FA9D8CFD4DECDABE80A3D7E34 -:10AB30008AAE60F899248CC07586AE9D6E9E7E723A -:10AB40007DBF7C85A3EFF32E56E75D6E02760FAFD7 -:10AB5000D933A445E1E9FBF61D09B90F9068BBA6FE -:10AB6000E076C08F835A79D1764DFCD8389D1D95FB -:10AB7000A024EAEA49C57D75EFF7291DA06B4F9D1A -:10AB800073B5AE3DDD93ABAB67948FD7BDDFBFA68A -:10AB90004057BFE2EE1B75EF67F96FD1D5B3D7CF42 -:10ABA000D3BD3FA87EA1AEFDCA860A5DFB55819547 -:10ABB000BAFA35DB7FA27B7F58708DAE7D78D303E8 -:10ABC000BAF611E14774F591871ED3BD3FBA658B84 -:10ABD000AE7DCC87CFEADAC74576E9EAD71EDFA398 -:10ABE0007BFFBAF603BAFAA48BBFD7BD9F4FDED561 -:10ABF000DBDB963FEBDE9FE2FA4CD77E7DDA9706F1 -:10AC00003BD5EE3A768D5AE741AE08FA25FE740937 -:10AC1000EDD5B043C2BAD4D7CEFC14C752F928E55B -:10AC20001FE9C0223919F992FE51BB21BF6FF99576 -:10AC300011FAFCAEF19E2B5DF4F95D9267B82B869C -:10AC40007D43F98D236950CA26288DEDF7898CDF65 -:10AC50000B322E0D3E42BFF79ADA0727D0FA703E2C -:10AC60003F08F2F1326742BB3A8E2735F05E9C997D -:10AC7000A0DF745F56DE93FE287958DF9FDA195CF7 -:10AC800067BFEB454F1ADA51B59FF8C1CE59D79F30 -:10AC9000CEAB2F21AF709F84FD03E9F7FD97A67916 -:10ACA000687F6689FA19D1E34B74FCA1387E18E4F9 -:10ACB000E1208C3FBAEBF8E6016375E35B32CB75BC -:10ACC000E35B243ABE8B90DFD77EAE8E4F89309EF9 -:10ACD0009037B9CF717C7366398E7F9F44FDAEE8A3 -:10ACE000F1E33AC66F81F9BFDFDDFC078CD7CF3FB8 -:10ACF000B3423F7F89CDFFA3DAD3EAF87138FF3F33 -:10AD000073A7D9FC332BD8FCCDACDF8EF19D1DF899 -:10AD10008FC0F8C7BA19DF9C3D413FFF2B2AF5F3DE -:10AD200037B3F14FD65E50C7B7E3F85F7217D8FC60 -:10AD3000AFA8C4F125B3C70DFC2365C4D504E8F85A -:10AD4000A41F557CA9C02E741C28872452A12164FD -:10AD50001B3700E1B82B8EF1DB577194DF509FF960 -:10AD6000F1390950CD9947FD4695D757ECC8974022 -:10AD7000EF613BF5B796A8A02E6EE291BFC90673AE -:10AD8000601085B7B589F7437DF186EB02A05FBD02 -:10AD900066B2A014BE1348189E7FFECB615BA2E78B -:10ADA000652C97D48BC72251F2D6E1071690213536 -:10ADB00014BE29C004A33BEB9F523F0E1CE38FA996 -:10ADC000DF43A8FFF399C8C6FB0BF5F7A01EA1FE51 -:10ADD0001E3ACEA416BFA3DD1D4EA3F097AAF07FA6 -:10ADE0002A3079FDF4362EE0A7F2F9D58F47A07FFF -:10ADF000BDE06E1B457A271C65FE245D9DCECB0F02 -:10AE0000746ADF6D0E6CE110BF32E06B3A8A262166 -:10AE10008BD667505C77BEFFC1BEA907392721B723 -:10AE200012454CA5EFDFBE9AEBEFA2E3CE52CCB9B0 -:10AE30006C1D52324C28D724C33496905B1A478835 -:10AE4000B407325D113F8D448D3BA3585F9F55AAD7 -:10AE5000AFB78A8A68A270B54EE7C866DAEFEC39F8 -:10AE6000FA766D9C81A644466775BC528A9374FA43 -:10AE7000683694B9F0D885749EE362DF6AF078177B -:10AE800089248C7EBCBF0F01BAFA93F1BD792E36AE -:10AE90006F23BC73448B524AE739A78C0F007F1B8A -:10AEA000E1FF689F4D31E5D072FDA32231759D8F82 -:10AEB00011FEB91EE37C8222ACF3F3CB8DCF19DFF8 -:10AEC0001C53E9FF29F0072DBF00FEA0F01F55F924 -:10AED000A353AF32FEF09A3DD3801FDA37F204E974 -:10AEE000AAF2CBAD2ABF2CA9D7F305211E11E8B8D1 -:10AEF0006C0E97FB40141FCC56F96059839E6F6E01 -:10AF0000277E313D065DE66ED87C6F9ADC757E9FAC -:10AF1000A87C33FFC1FD889FAEF36474BA43A5D308 -:10AF2000ED35FAF65B55BADEAED2754EC3C3AF51FE -:10AF3000F541E6C90111E4DDFB538D9E111D3D3D38 -:10AF40002A3D8D70DEA1D2F38E1F337A1AE18DA8CF -:10AF5000F48C349C13C980AEF01AE15B707797F9DA -:10AF6000605CABCC1F9B9EDEA6FC5547A39E57059D -:10AF70006F5875344ACE566C9FAEAB2F0FCCD5BDF3 -:10AF8000BFACA14CD7BEA47EB9AE7DD1FA3B75F55E -:10AF900032FF8F75EF2FB8BB56D77E7BCDFDBAF64B -:10AFA000F9E50FEBEA733D1B75EFCF9EB359D73E22 -:10AFB000ABF4195DFB8CE29DBAFA7465B7EE7DD3F4 -:10AFC000BEAB6E06FE7CEB3D9E803D71C1FD05C6AD -:10AFD000332FB84537BC73D427235F1FF30DC1F25D -:10AFE000B8CF8D7C7FD23716CBD6A6663BAC137418 -:10AFF0005D5C4A12086932CDAB5DDF0FD66982EB2A -:10B0000069C8E4A9F5D37AB34946792869904878A4 -:10B0100024211C2C362A1CED7C547BA487F606AA1E -:10B02000F893BAB69744623FF73E527605F06577DB -:10B03000EB03FDCB00BBA74DB5EB8DED951C298D2A -:10B040007E4EC81A84C36A627647A5C4E4BF7257AD -:10B050007A0171423D3CB8E672E3052993A7029F4D -:10B0600064EBE47859C3353AFD4E209ADC07F86D5D -:10B07000A4EEF98AEDD7EABE3BB59F47B8AB41577E -:10B080008C8365B1F43313E8E17073E68C6100A73B -:10B090007214EB4D7DD02E3CE52B5E757410D0AF55 -:10B0A00014CBE3BE39581EF379B03CEA2BC7F253F8 -:10B0B0005F0D9611DFDD58FEC5E7C7F263DF7A2C1E -:10B0C0003FF2D563F9A1AF01CBF77D012C0FFBB6A1 -:10B0D00063F98E2F88658BAF09CB569F82A52677A3 -:10B0E0003DF1DD71751D3E09FC1783CFA43A7FED5C -:10B0F000FA099D7C16C7DF877CA6E1B9A4C1ACF232 -:10B10000438A8E1F12C097433EEBA1BD4154F9B054 -:10B11000BBEF63B77BB7FC6BF86DEA0FE4B74E7E0D -:10B12000CA30F053764FFC348C8FE2A7A92617B3B0 -:10B130007B547EFA19CC23865F310F8C903E51F6FA -:10B140009A926F82756CA5BA0F421F60FDAC3A7679 -:10B150001D7DB705EDBAC0105837CE0EF9DB60D8AB -:10B160004738FB21257E56F7F333F249F77857D05D -:10B17000BF591AA0444FEADA6E8D6378B59A483108 -:10B18000A1EBDAFD839E722F1C8A758124C2F70120 -:10B19000F774478C7EA9AD0CF8ED09AF758EAF72D0 -:10B1A000A0BF638FFD3D0FCAA926662FC735F36880 -:10B1B000B793F0936EC06FC7BA6476A741BCBD7DEC -:10B1C00090E442BB814CD6E3CF5FA0C3DFFD1447C0 -:10B1D0002DB8EED6A721FE067E3538BD17F8EB490F -:10B1E000BFF784CF8530EF7F013E7BD28F3DE945AD -:10B1F000A2C82F34D1F9B7ED1B96FB800CE35E1E7D -:10B20000DFDAFE9A119E5F7E473E6E4BD1F8B8257D -:10B2100093801FA4CACBD9C62BE3812E1DFDF44019 -:10B220004FEE779F6482FF7E3A4BDFDF7DC6FEE202 -:10B2300025C20DA7E33A2489C453BF92F76CE3D12A -:10B240009F7147FC1037D86773D7C9E0379EFCAFB2 -:10B25000B00C3DEBE30B670F3DE9043F6C651A5FF3 -:10B260007334061DB5B22A9855638FF6579AF4F5D4 -:10B27000B3F55C7110E725C7CF1C06EB8CABE6A8D5 -:10B28000087A3F0D4BAD9F9569128E73727B763CA9 -:10B29000F3FF024C9FEC48407D73D267C1F7FFD9A2 -:10B2A000F074D78F060F218DE4330BE873DA96DD47 -:10B2B000FDFBDDCA83705E82F82909895F81BF6961 -:10B2C000A5FF7F3B00FA15B0AEF5EB0DF27EF370F3 -:10B2D00078BE43371EFD4ED6F68CE1BBEEE54E2020 -:10B2E000C734BEA7F4FBABBABFBD62BBB5466FC7E0 -:10B2F00026E8EADEA6F41A9D5D0BFF00C3BD8613A7 -:10B300006009AB54D9B04DB0AF077EDA03C149F044 -:10B310005F38F65E9525227964149716E0D385632D -:10B3200035FE9767FF99EAA9136F8A04E48C5CA243 -:10B3300050E5A9AE20F29B8998687D91FAF6C2C6C5 -:10B340001525B06E9D78F926F44316935227F8C759 -:10B35000E5A43E0FE2B5A789A918E4F33479C7390B -:10B36000324A1EAD82849D2E5AAFB7E3A97FAFABA0 -:10B370002F6BD0D797925B5260DF7EE9069104383D -:10B38000D01BFAF6AF7917F6BB8CD4AC8375FB579C -:10B390006ABC6BA18B0819546F55FDF6F1BC320ADB -:10B3A000874B6071166D1F7A7922F37F2A66062417 -:10B3B00085BEFF59E3C85BA906A2DF07D6C17EBCE4 -:10B3C0007F3A716F235DE9F75DE137C2ABD9035D69 -:10B3D000F6C3553892B7734A20861ECB14382667B9 -:10B3E000AABE2B105CBAB8C73443FD7BF35332D1ED -:10B3F000F1D31EDE93278C66FC03FCC009ED92E7B7 -:10B4000087F49FD6A5FF827F6AFFFD68FF79BAFEA9 -:10B41000A7FD53FB1FD805FE79B1FAAFFAEDF32F64 -:10B42000FBA93EA978F1974E42D7C913427D8A9B6A -:10B43000D2B572DBBD4E8596C705BF13F8F54480C3 -:10B440002F8E45EF87054E1542C5CE41DC0DFE49D6 -:10B45000FB3FF9ECCF301EF1D536D185F1B4EDE6E6 -:10B46000B099CA6175E3F2129283F523AC7EDF19BD -:10B470001EEA4D7AFEAB78FA9729901F4239458D26 -:10B480002F85D19EADDEFA7911AC4F5ED28E7264FB -:10B49000FC0EC6BF9888FAAF4C8AEFDA4EE1C4388A -:10B4A0008157C58BB7F16767782794377C01FA829B -:10B4B0007A22E8C71BBF2B57EDD4358223F9988D2C -:10B4C000FE7B0C19037A51C30B09303BB5EE995F33 -:10B4D000E71CA1709DDAFAA6938BC297264F67836B -:10B4E0008BFE738FDCBDDE6DA5F2166D0F69EB96DA -:10B4F000DCA4DAD72156568A6127E4F3546E16DDB0 -:10B500007EFAB8F2F9279F7A0CE2997F32BB07D115 -:10B51000FE573CFFDAFBE3697DC54E31B9844DC36C -:10B52000CEA574D2C74BFFBF3BB7931E15BF794D55 -:10B530009287B1E7F72476D265C5CEFD1219D615EC -:10B540001F9383FBA5883D067D82478AC05EA87B4A -:10B55000E6BF2588339ED8C791D4AC18F8DCFC1A16 -:10B56000DA038027A4A74AAF0EFA19DEF752BA8091 -:10B57000DE36D2CBF8DE2255BF40BF906741F9FBE3 -:10B58000853D9007F591D90D78287F619513E6F3F5 -:10B590008550C3F8FCF17B53409F958BFE141796A2 -:10B5A000EC79F9133F42FE5BF6F68F5230BE4494BD -:10B5B0007413AE45FE7498E7924DB3709E4B8907A5 -:10B5C000F9B0FC71BE3440CB0B0229DE19434EACFE -:10B5D0002293932FB650E2D2797E01FE24E8EF77D2 -:10B5E000F8C036B4BBEF24A00F7EA4CE855A0C5809 -:10B5F000BF6061F4FAABBA2E10B03EA3F977EB7DD1 -:10B600002D40A793FD9554D877F112C1AFE283FB8B -:10B6100096F6CBBF3D2595D189C8429EFA1D5DF7B0 -:10B6200027C37378BF4554AC39BAEFC8B7599DE307 -:10B63000AF56C7A770C7C17AFD454A6CFB354FD4DA -:10B64000F4005DB7A3F82C4ADE99FC6FBD9FC9BB1F -:10B6500026FF81E9C5D07EFE309323F80ED6430A3B -:10B66000573815DBF7CFE4503F503F3A969C6F15A3 -:10B670005539D7B71BF985C22F70F1517C03E324EC -:10B68000221D70DF65E906FA7D941EF5C2B8CEAEC4 -:10B69000FD6A72BC4CF35B45BD3E209B981EE8DE04 -:10B6A000AEF2239E2AC5C0538F81FC5279F5CB2080 -:10B6B000BF6229CCFFCB1DCDEFCFA372FB655093AA -:10B6C0005BBD5E35CA6DF9AED12496DC7E69779399 -:10B6D00098724B9FC7945B7B04F9F9FFB45ED5F079 -:10B6E000380CF0784D271E353DD91D3E8D7AF290ED -:10B6F00020235E8D7A92FE1D26795DF951E3438DFC -:10B70000FF2A9EABBA02F451079F6A7CD8C1A71AE0 -:10B710001F7689EFEAF0686CBF00FB3414AEF9962F -:10B720008DD38E5257D2D24E70DF267F268FFBAA42 -:10B7300096F384E5811011F3433F30D58C063B75B9 -:10B74000E2DF6F3D7D1785773EF18B2C2FA05E44A5 -:10B75000BBFFD2B7DF4EA0F399A7E2793E45FB5479 -:10B760004A973902178EA370CE15883F3E11E2B773 -:10B770001CF9340A8EF9E5FA3AFC4D4CE9ECA7A71E -:10B78000F7BFAB9FF27DCBB7295D3F1D44C8BB50CF -:10B790008A38BC10CD57D381AE147FDE515C600077 -:10B7A000EAA988501AE577BD2032FBF3EDC219A350 -:10B7B000C1BEC99F3D2C9EF1FB60F47BBDAA3E3B00 -:10B7C000EB97E341CF9F0D65A37F7BF6D02247AC7B -:10B7D000BCD06695CF5E53F75DDAEC5C3D4FF9BFA8 -:10B7E0008DB4A37DE3B75BC9B618FB821B454D5FE3 -:10B7F000AB74A37F3C1D7F8ECA8773E9A7F1B95153 -:10B80000749B39F584E0EC4A07F8FB34CA0FFBA1BE -:10B81000F805BE06FC365B2345A531E279CFA9F8D1 -:10B820009B78E06BCCCF2D0CE50B80C7423BAF8BF8 -:10B83000833CA9C9EB503214E09A7860F9CF4753A2 -:10B840003EF61EE2DD908FEB0D9D913C31FC6123B5 -:10B850003EA17FB0338F882EC4D77B62E912C0EB44 -:10B860007BB3AC04F635DF95DC55B1E02C33B3F592 -:10B87000662E29BD308AFBBF0FBFF9B31DE1028AD6 -:10B880008FB37696F7DD95FF98DC9F7571815A0E20 -:10B89000F89067F5642E0071B422E2F9F9040EE520 -:10B8A0007D52B4FECA6F9AFE3CE4F55487389789FE -:10B8B000B6570B1109F8D8DBB45300FBFD269928C5 -:10B8C000188F106A86CD8C8A7B1D1105C457F3DF53 -:10B8D000E6DD0EF83D37D34C002E65E81927D80178 -:10B8E000E74223510EBA9BD71F7C645AA108FD1072 -:10B8F000E40F233F1425DB74F55993493F37A5DB4B -:10B90000447364953B06FDEA24C667BDD66F96FF77 -:10B91000CFF4DB04AADF185F8BD1FAED2689F17D25 -:10B92000947E4B8DA5DF56D6CAA9C0172BF766A704 -:10B93000025D57BEB1A44F2CFDF6BA8FF9F76FA880 -:10B9400079E66DFDA87E1B1EA5DFFA51FD1623AE1C -:10B950003B5AEAA57EB3FCCFC8DFEBA0DF62CCB7D1 -:10B9600058C59FA6DF8A43B5A8DF8AFBF1BA7CA938 -:10B9700049524FFAADEC97B3B02EBA6D31F807F0DB -:10B980000AFAED0D55CFC138A0E7FE5D727D273D67 -:10B9900057D55B3DF73F84674DCFADECCFA13DD38D -:10B9A000950F999E5B99C5F4DCCABD4CCFAD1CC404 -:10B9B000F49C51BF1574D16FECFBEA21F47BF423A6 -:10B9C000B37E7D1B6D2F9923BA2DF4FD12593B9F39 -:10B9D00051333A5ADFFDBBD48DBE739FC1732E3DE8 -:10B9E000E9BB3F82BE1B847A6C20C891913F6E1CDC -:10B9F00068D3E5D3BDF7F5B1E75E0479F9038FFEAF -:10BA0000F70726E627EDFBFAD84890BBF7001EAAF9 -:10BA1000EF9E51F9AFD5E7477D3A792893F7AA7B96 -:10BA200018FEAA1B3936DFD57C408675E06F17D12A -:10BA30008FBE7D2FF3A3679B5BFAD8C0CFFF5F2239 -:10BA4000CA25FD2B298BE28739172B30EEB92BCE77 -:10BA5000B905FCCC3902B1801DBBE0D08D27C07E7A -:10BA60005D70713DDABD0BE07922E9C8FB98DBA17E -:10BA700027F5F6EBBCA69DAF6590AEF91013CD8C03 -:10BA80002E13577181CD595DF323A85D86F92DC61C -:10BA90003C89DFABF39FCD47105FE48F7CCCF8E5AA -:10BAA000EF8D787233BC54ADE6F578AAE162E28995 -:10BAB00052BAA42CA5132FB7BF14599701EDCB3957 -:10BAC000F4B78CF3D6F0669CBF8647CDBF59A0BEB5 -:10BAD0003F3F7424669E8886E72EF9221ADE0DF811 -:10BAE000784BD333D7906120971F983C3F1F0D7C34 -:10BAF000F47B8A170AE7AD7307E9CE2BBDA3E26595 -:10BB0000AAE748618A0C782435C067F3CA77BE96E5 -:10BB100042E777B392950B21F5597F933C108F68DC -:10BB2000B6B6A31ED4F8709499C98559D52BEFF5F4 -:10BB30007515E27AD3C4B950BEC2063DA7E699791D -:10BB4000EF61F2D7CCFDF7BA8C518867582E489137 -:10BB5000B65E015DE83FA786185DBC4017FACF6965 -:10BB6000A4FD20E0BD3A997387E1FDA69DF7023F51 -:10BB7000BD6EA5CF41CECB39F716860E7B7ACA654E -:10BB8000F95888C5C718CCC8EB5C3F17C07B895DE6 -:10BB9000ED9389E696F7008E89546E36C3C300FD97 -:10BBA0002F8AFE46FBC5C8073DE50375C7EFB92AD6 -:10BBB0009E5F073AD801DFED12D843DE305B7FB4D9 -:10BBC00076AF201722DE343A34D1F56514A38329E9 -:10BBD000069E6FD6EA2A9EBD214E84EF6FA0FE6FAF -:10BBE0001207BB7E5F1FD4F8DD2C77C513C415D2B6 -:10BBF000A3F406E8B7E87DCDEAA6B7115F37AEA695 -:10BC0000E699DC155F1A7D400F5E0E6FDDCA4FD3DB -:10BC100091987961DF557E4699F5F2B3CFDAFEE669 -:10BC20007088ABEDE550AF9050822E7E30D3CCECD7 -:10BC30009666AB07F9BCFD0DD1BD45EEAA7FA6A85F -:10BC400074017F25FA7CE2649808E84D97957CA6FC -:10BC5000CD7B00E3B7E8F5E075AB07E9D75DFF33CF -:10BC6000CCCCFEEDCE1ED3EAD7C37890D728EBC755 -:10BC700033AE475A5CA9A77979D471BFEFBCB471D0 -:10BC8000BEEBBE8497B4603C4EDB9FD8C37B768905 -:10BC9000603F1673BA7D100A39EE6FFE13FABF5972 -:10BCA0001ADD7DFF103F0A533CBFBEE3498C639F02 -:10BCB0007EF6C834909F15AFF0C442E5AF75878318 -:10BCC00084599E8804764245238FFB5D4408E7CD66 -:10BCD00088B233A827C3F0F1A203F55EC52E73A086 -:10BCE000847E5FF1F26739107F6B5DC3F49FFF596B -:10BCF000951FFD911CC807A810D8FEBC913E8FA8C7 -:10BD0000FC796AB76D0EE86F6E3B3BC75B119C2DEB -:10BD10009AA3E20CF79B4516E7DE6DC33C6CFF333C -:10BD20001CE631037CD1E748B5FCD053CF30BD5C75 -:10BD3000D12406E03C70C5F69DAD1017AFF8D08C4D -:10BD4000F6AB77FB1909ECD3C92F3ECFCE1B37F1E9 -:10BD5000BA78689738E4763E6C86F8596315EA013C -:10BD60005A3F82F5A01AF7FB8E71B2152FEE7DD9DE -:10BD70004F51B8E2374F3BF15C70CB3627C623B743 -:10BD80005F7E5FA04BDC3178BF1A779CFA05C1F566 -:10BD90002176DCF1A4CA2721B33EEE48B627613CE8 -:10BDA00092C299571A237ED1C1FFCF5F7802F6CD98 -:10BDB0004EEDFAF20980BBF29B734FFC94E2932A9A -:10BDC0002017ACDBDE67DFC37D06EDBBF7557DD208 -:10BDD000FACCD3B84FD3FA27B31B7A6BDDFB4526D9 -:10BDE000EC53B4EEFC3A05E2B8ABF74E417F6DF58B -:10BDF0004B9353490C7F402B817F03BDD82732D210 -:10BE0000ADB9B13913E03C4DE90EEB77473C3958F9 -:10BE1000C5E2F4B21A47DE117B5FAE4BDCB871C6E7 -:10BE2000CDD7C13ADE28BA65D28BF8F1614ACFE1AD -:10BE3000BDA0E30E759F2038F5B2F1E3D3F00F4AB1 -:10BE4000AF0B667D1CFE42E392FF7C0CDA1A93BABC -:10BE50008D1F877B813F6DDF6FBF59211690A35DDA -:10BE6000CF61DC1EE8477D0FD2FAFC854C88BB1CF5 -:10BE700017DBEFC0FCEBBD66CCA3AAD8FB01CA530D -:10BE8000EB4B6FE3BE1A51F7DF5A49C71FDB27514F -:10BE90007D3AEF56078B3BAB7480B8B4ECC4E76ACD -:10BEA000FC99F1B51697EE2E1E3DD63280EDBFAB54 -:10BEB000FB91555BFF2C1143BC9F1B0BF43A72D9CD -:10BEC0007D540D0F2EC0C398E8FD96D8F1FF8EFD6E -:10BED0001603DD809E608F75ECA7D07A3F88AB0794 -:10BEE000B80F62EDDFB56E66FB34AD62ECBC456D3C -:10BEF000FF65A4C5B0EF12E8DDBE4B4FF3F8AE7896 -:10BF0000CA0627B44F577C9DBA145BBFDF6AE1D4E1 -:10BF10007B03BEE7BE7E2567CC1B98057C59D57890 -:10BF200044027B4A5BDFB4F99E52FDE753CFF278BF -:10BF30004E645DB019F5BB517F5413163734C25BA4 -:10BF40006E617AABBA89AD1FA776390276DACFA9CE -:10BF500003BB91AFAB771C91FCB4BF83DB7F234560 -:10BF6000A2F2AC60FD0844C17FEA85FD396C7F898F -:10BF7000F9EBC671EE52C7F186628FE3DD71463789 -:10BF8000CE0A7F5062E77E2E3FDE4941990DFD9D2E -:10BF90006C1109E4FD9F0CF2C58118E3CFB5885AF6 -:10BFA0003C8BC90F5D47F11CA6839DBBE41325B4F0 -:10BFB000BB573BC67E08E7FD573B2419E21775B512 -:10BFC0002C2FB5EEDFDC6940EFBA845B713FAEDE4B -:10BFD000805F57B22B1FE21AAEC2D251C0AE46BD2F -:10BFE00093A09874F0AF7614A7CA14CEB5AA9D4654 -:10BFF00004379E0BE59D45C5301FDE65725963EC25 -:10C000003B88F652E289C28BE8D29FE3249746CA66 -:10C01000D08F967F53696939888D2E05538C85B1F1 -:10C02000ECDDFC992E9C77DB0ED57F5088EC4A61C5 -:10C030007964B08EB4ED8ACF21C3F143A2507EB4AF -:10C04000A9CFB91DFBF7835E5AEB244A0295338AC8 -:10C050005599CF86F3AC232C5C36F0E999FF7A85AD -:10C06000F66B0DF1E857B4D9B57C522501E4CC4606 -:10C070001EC4BC4160E56F933AE134E613127825A3 -:10C08000EA3E8D29BC1DFDA1B39B587C802757FF3C -:10C090007A028BCF9100C0AFAE2F2B5438CF12E273 -:10C0A0000EC3FB3B1C180F58F6C622941FA0433446 -:10C0B000BE928AF5E75E1BACCE1CF067365A55BFC0 -:10C0C000C6AFB4C0399BC56ABF7D4AF5E762A918FF -:10C0D000FA415E97A8F2FAE5D2A243988FE6598A10 -:10C0E0007A3E758EFEDCAC314F4B20AA9F1C60FE61 -:10C0F0007397BCADA6CD08B7317F6BC5767D5DC3A8 -:10C10000E327A037AF027412FBE5E2803DE237324D -:10C11000F8D713467D77FC9AD3F4F8B5CA7AFCDADF -:10C120008618F1A7C7AFC3ADC797E6977687DFF844 -:10C13000B1FA73C8FF2AFC8A56D58E54F14AFF4AD9 -:10C140002D294C6503DCE94218E5C2284719F63071 -:10C1500007FFEE9F1CA8C5AFDC0ED4EF69EA7CB8E0 -:10C16000C5EC3B1BC8110FF0BA518EE02420E879D2 -:10C170001BF9D875CC0AC4FA8C7C7B4DF7F45C357E -:10C18000FDD5230BE9579B807F87233FB0F3BE8902 -:10C190002450970572EA76C1FA1DF459DC8B45B834 -:10C1A000F785B8170F82FB5E5C583EA4E6ABB40D72 -:10C1B00025786E30183E9F02FAE9A1DCF669A0F7F7 -:10C1C000BC4B4829E8C11FC5B1F3030FA865BF38B0 -:10C1D00049D5AB856F4C82EF43A20CE7D5DB42DB40 -:10C1E0002C83A0DEC4E33D2ADE84FAAB60FCD6904B -:10C1F000C8E05A6C090C8238C85E11C76D5D3C01FD -:10C20000CF6576D86F21962FD216FACCB9284A9FDF -:10C21000B7363D7A15C4B9369A62E7A94CB19A7E11 -:10C22000D8FA1BEC92B737C5CAF2EA1E1A40E7519A -:10C230003DFDACBA0E3379B856A5F3AB4B6FC4F9DC -:10C24000BF14E26458478AF8DB6E1A46E739EE3DC0 -:10C25000418DCFB078E528F5FD3AD02FA85FEBDF10 -:10C26000E5E9C3DD470502E7F446D52C457FEB152C -:10C2700027E573CA17794A7024F06D612801EFCD64 -:10C28000F17E4CD0AE1FDD22E8F8334F5D57F3222C -:10C29000545EC044F950DF3E2E2218ECA0000FFC83 -:10C2A00075ED71FDF38556D5EE729214E0F30D979E -:10C2B000780EF25EDBDA897B0D85BB6D715F84A33E -:10C2C000ED3C9CFAA5E525BE38D67ABFCACAF8620D -:10C2D000A344709DD9B8D48EF1C5034B2BAE80F525 -:10C2E000FDAB1F7BAE88758E3C4A3FC5B37C2C25C9 -:10C2F0009E8C05FE5ECB31BCD7A797C6C8F7D7F892 -:10C3000059E36F8DAFD397C67962E5357E63657665 -:10C310005AC1D2219C04FEDA3E0E8FE3B6AEF15C28 -:10C32000F6DC8D9FACC90078BC4DE7D0EEB6843802 -:10C330002596BDB1C1EAC4FE5BD7F86B218FEF2E05 -:10C340002A9CA027BBEF7703FA5B3F81A02C7C6778 -:10C35000A92FC373BC4B2C640BC4BB85FAF45B1CC4 -:10C36000C0FF936F5847E17DACD484EBEB46D18D91 -:10C37000F0FBAB08C1F8831ACFED378D6C8E3ECF42 -:10C38000FC8435FF592BA5C7B35617D225C9E3E660 -:10C39000007EF73FFEDB09F2DD76D18C74ECABFA60 -:10C3A00043DA77AF5999DD36334ED90ADF93F26419 -:10C3B0009413B7C7E95E3C12EE4DA0788F92A34E5E -:10C3C000FAF9F1BB440FD571149E44BB09F99228C8 -:10C3D0008AECD2C529FD28479A5C903047208F4DC2 -:10C3E000D3AB5C880B3BA81C8CB2D8C3E0772496F7 -:10C3F000D3795310ACC4C2FA6B114E759CCBC63CBA -:10C4000079CA977970388A6048141271A17F4DDF1C -:10C410006A7A7A6D02417959FBB010A8A3FD6C12BB -:10C42000225688AF64297201A41A250A329E17EF9A -:10C430005F4E30FFD296FD784287DD42857EC4375D -:10C44000FC8258FB797C9C862FCF1F406FE41C6ACE -:10C450003F00E68DDBCAC673BF66413BBD437FA884 -:10C46000F65891BAFE8EFBDCC4F209C29348F43E42 -:10C470009B517F68F6C9B8EB226B60BF68DC9F18E0 -:10C480009CB45B05BE1BADCEB7439FA8EBE69810EE -:10C49000D527F4FBDCD0C866B8072BF76326C75D49 -:10C4A000F4C9213F0FF8FBBE7AC4C81723C2542E2B -:10C4B000D5F6A132DCA7E1EAA843FB1983DE499E49 -:10C4C0003E2A15ED5C95DF8C78D6E4DB28F7B9774A -:10C4D000BB9BCD0C2EE6471AC6215C271C7236E8A2 -:10C4E000A5B778B0F7DBF2291E285CBF02F9A3F4E8 -:10C4F0004B381FB801E6BF2174BD15E4E47BAF27BC -:10C5000021FA75549EF6D3BC273EAE0FAE274EC01F -:10C5100043F5FEF3EA7A12467A77C8019593E878F4 -:10C5200089C6FF467ED7E4A30E2EDEC8C673760406 -:10C53000D6599E0BE2653066B2C90578D5ECED3A66 -:10C54000D5BE25FE74B4FF56BB88BA1E6506804F63 -:10C55000EA44CD5E775BA2E353AB1D05A997DB4FA1 -:10C56000F55EA4FE59D4391BAFD08EFE9BF7A28492 -:10C57000CFBF37FE9A2814793AFC8D891BDD157FD1 -:10C58000F17184B0FBC2FE9F9FDF0C237FDC277715 -:10C59000CEEF5AE2792542F547DEAAF57536193F06 -:10C5A000399C96D7552F68FB9FDDE901A3BC8FA965 -:10C5B000AC6FC6704B0FF2EEB5A9F8256406E8B370 -:10C5C000F1616AB7647595FFF3EAFCBC3686F7B68D -:10C5D0005BDB07833CADE73D3571682F464C26B0E9 -:10C5E0002B7613B47BDCFB8F3A51DE5B9274EB4FFE -:10C5F00057BBC08FF2A9D9A79A5D6A7CAFC32E55ED -:10C60000D71B2D3ECA355179A1F03C19E7F1031C27 -:10C61000752EE6BFC20157D0634F583D75C05F36D7 -:10C620003A9738D82F1912CE62F196B04E3EBB938E -:10C63000479B41DE82143FB0FEF9E9FA3788EB1ED2 -:10C640009EB171090C5EAA85C0BEE99747D860D536 -:10C6500004F3C7FBE5B0FB6BFAE5B2FB3237C73139 -:10C66000FB658BA17CC25AFA18CC4B1488DF9CFB6B -:10C67000FDE10650210EF9649CD200F8B0142B386D -:10C680008F0C17717394DE19429083BC89C44A9948 -:10C6900063F147D2B9FF48FBCB2891F3813F3206C3 -:10C6A000123C379A118A7D9EE89538F187D9EB8D37 -:10C6B0005DCEC1BCA2CACF4189CE37A9849D83E992 -:10C6C00088FB50F001BFAD8E5B71B2AD17D83EABA9 -:10C6D0003F81E1D9E8BF01C1605E825ABF57228223 -:10C6E0003511FD2B3FF0AFDF6441FFCA46DC41D07E -:10C6F000B71FC4B1F8EC3ACEBD1EEABF10DA2D70F8 -:10C70000CF8F26379A3C3C34E116B7405F755E7791 -:10C7100036077C5F2A17EF009E5B279C1DBC1667BF -:10C72000D29EC9F84EE175F9F61AFD9A441DFDAC8A -:10C73000105789D6F30E6908D8EDAD5C9C1BFCAA96 -:10C74000D6E51C8397B3A8E71104DD3CD36CCC1F5E -:10C750006953F5E7DFE3B2901FB5F584CE6F3DC6B0 -:10C760007F0DF3E838876A38776A3C979A96DD112F -:10C77000074AC77CDC5209EE3223674336B4E3BC78 -:10C78000CEF64C12E3BC646AC41AF35CB05652BCD9 -:10C790007D0D784B156B12401FA7DECEF488111F5C -:10C7A0006D9C7FC441D847FB8318331F452BD3D2E0 -:10C7B0006E4A584CDF4F4BBF014BED79835D8819B2 -:10C7C000574CB2713FECDC6403B118FCCD241BED77 -:10C7D000EFB4E79DF71514FF768CBB37C431BC3737 -:10C7E000C431BC37481A3EE57890BFCEBA5B97F7A4 -:10C7F000B4C1674910200FD19F8EF2B9C4C5E8DDDE -:10C80000F9BE82F64D1FA2DC301794C406916C432A -:10C81000BE67F121ED7CC8AF7CCF2440BE94DB968F -:10C82000A5FAFB1646DF0406F7F90D5370DC14B2C7 -:10C83000C63A98E27969A9C90D71A3D30B3F72C2B8 -:10C8400091E985192D79200FA7798F1BE6974A98D2 -:10C850005FB86C8E1408D32E931BA8C26274BA0101 -:10C86000F73BCB4C31F3AEC7D8D8FEE9D138179699 -:10C870006969D3904E9DF59204F04B8C7C4AE53566 -:10C880007DF1A8CE73CC946F145B0C796B134913B4 -:10C8900087EB5B18F195ACB1B3AAB7357949063986 -:10C8A000847DAB52AA47353A0F505F4DC1B828FE80 -:10C8B00071A1D7BF067FC3795D01EA454D8EC810CF -:10C8C000A6E7ADA077A3E2A16D7B3FE80FFB8E9FAB -:10C8D000FCDB3907EC3BFD556877809E3D7ECFBB86 -:10C8E0000E38C7F4C93D2C2E7287C14F5B6463FAC2 -:10C8F0007F8FAD741EE07781EF1F799E287E2577AC -:10C90000B3FD93E501DE70DE5D7F6F505530C97079 -:10C910008F901FF15AA5DE1F66A4C7461B8BB72C4C -:10C92000DFB159CA90617C4F258C7F5CF5438F370E -:10C930003AD0DFD1E059B8638404BED95F4366754D -:10C94000FFBD4564EB875202FB671E156F46380F2B -:10C95000AAF76A2FF925CB8F29A363DD4DF5B02700 -:10C96000C4CE7B18E7B1E413B92895126FC9FD1C3A -:10C97000FADDF0FE3D743DF3DC7D1FEEB319E7D91F -:10C98000F55E1F05FDB3652ABD8DE76D9785D83E21 -:10C99000F862E241F9EC72FE36C4CEC518E38D6749 -:10C9A0000F65DB000FBFB0A9F1C43C3206CE6DEFBE -:10C9B0003A3420FE72F7569F52EF8B827BBBA13C2C -:10C9C000EE2358CE032390E2BF32F4F65DC05FD56C -:10C9D0004D3BF13EB4EFAA8FAA42279C904BADE9A4 -:10C9E000256A876E03F9208B399D7D5ABDF99CC459 -:10C9F000FC6A869FDBD4E7B7013E7220DF5BFED97D -:10CA0000044AEFDB2AC5F3D1F7A53D6FD3EFC3F797 -:10CA100076BEDA3CB5796BED556A5E9CF13B4D0E06 -:10CA2000E6A97CB978EBF4757D298AEAF67E91A9AE -:10CA30009E93C3F3421A9F2D23A545E931F849A3DC -:10CA40006F07DF847E8EF3D3E8BAB8BE4CC5833F50 -:10CA50004DDD4F4C837895918F7A3AA7DD2A463287 -:10CA600041BE8D7CD2DACD7D28211BB32F16CB4A57 -:10CA700011C4CFA8F9BBCE1565DF1C17EA0FFE1451 -:10CA8000E46E2BE3FB0E3D084E31E8F737455CFFC3 -:10CA9000573AE454B8FF0FE9370EF213CC7E784FC3 -:10CAA0001BE7984F51068A80FF622C4FFA4A958106 -:10CAB000833ADB976E3CE704FBBB6D08C1B851AB12 -:10CAC000430FEF691B8F7AE3B44A8F4AA1E59B3F7E -:10CAD00083CEDADA827917C72EA971A74BE6E2581E -:10CAE000F3B4D839DDBD7877A872A8F9350B54FABC -:10CAF000DD1162FBE90B374D477A74C9BF54FDA1C4 -:10CB0000B2460EF58E913E4BDCD7633EDAA2403E34 -:10CB10007EDF855EE441A4BB916E77DA5DEC1E3763 -:10CB2000A146827BED8E6DE270FF7185107BFF73F5 -:10CB3000B6DDF49DE6639C4777F02FDB5ABBAE2F42 -:10CB400081F98F9080CF8DF06BF35F4214A6A7D44C -:10CB5000F976372F1299C4F234D4757F399C5B81F2 -:10CB6000FD93077996CFADC6A134F835788DF328BB -:10CB7000E22BF17C415B038F79D977F8D97D067779 -:10CB8000ACE570FDED8E4E9A5ED1F67BAA9BCA3065 -:10CB90006FCB43FB013BB6ED63C2F629D67378CF6A -:10CBA0005BB7F40CB17CA5EEE84908A3DB624A3719 -:10CBB000F03FBBDE9F90AF0C8CDE270ADCA00C8C14 -:10CBC000DEB72241CC5759B17DBAEEF98D76358E5C -:10CBD000A5EAF59EE48FD424C48C6F69F2A6C99FA0 -:10CBE000268F77DA65666F0A81831959809F87D10E -:10CBF000BFA1FA7A9E9DF93D0FCDA5AF546F3CA71A -:10CC0000DBA7583296D16B095F82CFBBD3BB140F21 -:10CC10003ABDBDD8AECFC3F8A1F3D1E6A1C98936DC -:10CC20003FA39C18BF37D2438BEF19E962A407C01A -:10CC3000097EC65B7B6D813514CEB73806B77FAFF2 -:10CC400015E16E4D9BACC0B9CDEAF4F958FE013E3A -:10CC50004C07FBB0B4CE8E76AEEA878DEA5D5C22DF -:10CC600057B5CB5EB22A23D9B9A7D224E09389B5B0 -:10CC700091191617218F3E585C04F7A44E7C383268 -:10CC80000342F1BF7EF04656DF1679D7E286FBFC01 -:10CC90004B8A0A69FD71D02FA02FFA95DBE0FB6E5D -:10CCA000EBC473F9BACCDE1F652E9DCFEEB166EDF5 -:10CCB00095D43EB3D0F5AEF2F0E057417E2B5B4AFF -:10CCC0008A212E54091178BADE5529CEB02D87ADB0 -:10CCD000FBE3E97B1FD93C4FD921EE76712DAE8B5A -:10CCE000958705942F7288C567053A572BFD6E6DA1 -:10CCF0001CB593297ED7265ADCE017D3E77EF09740 -:10CD0000D7262AB21CF55CA31F7C0770AC35B17C1A -:10CD100082FD6F0C8E8F5CC62ED8EF2325E0CF34BA -:10CD2000FB2C581ADBF325179EE7C837B17889B179 -:10CD3000FD6DBB76AE49CE00BEA83E24A1FCC31F4C -:10CD4000D89F5584C9493561E7D0AA0E133C775363 -:10CD50007DA808CFDDC0B9844F757AE05F73EEA679 -:10CD600093AF189E0A04AE44881AB7D06ED5D5F991 -:10CD700054D310980FE1E3DC706E84CF30D5ECA271 -:10CD8000F3E7AFA025C587E072F370FF4CFDE4899F -:10CD90003CDC9F5527AA792D26763EBE63DD57E5FC -:10CDA0004F2BFB394A8F02DD4FFFB125CFC6F6531B -:10CDB000D0AFD6E65BC72984037FED3582E71972D1 -:10CDC000934933E0CF4694B1C06F1647A2CA976C1F -:10CDD0003F9BFE6540E9369B7E23537EFFFAC19F51 -:10CDE00022FFBBE34DABB2689D73F8593DC3742E6F -:10CDF0008BB230EFA865F56B4CE706D0BAE858C3A4 -:10CE0000EAB0F14A173EB3A3AEC83F14C67131BAB7 -:10CE1000EE50AE01FE164C2CAE231C90707F47CB1B -:10CE200057594B7906F8D1E2607A745D6DC173365B -:10CE3000889B172832E44FEC51EF41FABEA5865784 -:10CE4000DE66427F094AC07FBC83E153A30B69546D -:10CE5000AE813C5E1254AE817DBD7E0E4FA2837EBC -:10CE60003FF2AD9689A0CF1BDFF9280FEF73BF8289 -:10CE7000F533F22DEA43D2F99CFE6DFFCDD1FBE4F0 -:10CE8000FD1CF9A9F01D2503DAAF9CEC22B751393E -:10CE9000AC53882C65839FADF72F1B09D34F1FD947 -:10CEA0004AAF70A03E09E33AF613BB6700D48D7E0B -:10CEB000336949EC55DE9D947337EE172566347D52 -:10CEC000B810D685DFB17B4A3845C1FCD3173BEE9D -:10CED0006B231897B2913837C48D899BA4F953D42A -:10CEE000F89A89F155725E94FFACCE877E5F08791F -:10CEF000F2636C2CBF81CE8F07FD3A82C8588E84B6 -:10CF0000385936A0D883F53D24F8E14F69FF8F5892 -:10CF1000597CCAB29DE8E28F650E16B779C0C9E2A6 -:10CF20008F7162F016B02BE2CE1017D8156D8F4BB3 -:10CF300002EECF0BAE9B70DFEEA009E3DC4F8B015E -:10CF400017EC17B55F25C85B48677F6D2ADDB57E96 -:10CF50001F91E4AB20EEF70B27AB3F9D4F308FBB0B -:10CF6000FD841480FDDCC40C4B4D743C699E83D958 -:10CF7000BBBF7315CC043A04F7C611187FCCBE387A -:10CF800013D0E3B91DB956E08B170147140F89661A -:10CF9000D79DD05FE2390A6F163E67F9FD823C22C9 -:10CFA0009EE277FC8D7619EED17ADA1ABC11F3562F -:10CFB0009F37E1BDC12F4AEEE9507FF1ACEC023D55 -:10CFC000FC7456300EE7F3BC09E7F3625CFBD52B2B -:10CFD00029DC0F0C61F12EC14604D0CF82A940BEDE -:10CFE000933E5FAEF2B1A6AF37811CD1FA231CC1CC -:10CFF000730C82291FE548CB276A6B27984FD467AB -:10D00000660B0FFC1C375D8B3B857988174D2825F7 -:10D0100068CF4DB08B78CE05F299E1BCDB44550F5B -:10D020004FFCB8B284E507BB0FC3BD9ECD76F57E3D -:10D0300030759F7392CA27D791086FA1EDD75D24F1 -:10D040006E88274DBAA8DF8F78CA605F4E51FB57B4 -:10D05000DA5D85F0389FE8EDBF290D4527603D2C4E -:10D06000208A00FC34D96268073BD209F7F0EB9FB5 -:10D070003FE050FDDC4C92199DC7A6ED434DE18782 -:10D080006E44FBB55872035E76DA950F203FC0DF21 -:10D090002292CBC5259FF2B17CC321176D04AE2C23 -:10D0A000A4FC6987F95CDD50EFB7D2795F3D90F55C -:10D0B0000F7C08FAE5CAC7939340DF8F57E9A5951F -:10D0C0001ADF017FB9E2197FB98677CAE7D38E2CC0 -:10D0D0007C4F9337E03BE8678F18981F6BBF9BF23C -:10D0E000EBD3C0AF3BED04FDB89FA55BE6809C6928 -:10D0F000E3B4AA7C6D2CD7D5AEDC0FBFFBE4BFC078 -:10D10000D68DC2BE17A5E875BF4F0283D72BD7CFE8 -:10D11000980679687611F3CC52D47351D1FC921EE3 -:10D12000C52F1ADFB5DA599C48E39FC9BBDFE5E19B -:10D13000F9E40B84B8B24887BFA2F1CF447F18F757 -:10D14000812712E69F18F9675737FC937F5E1640D8 -:10D150006F75E19F438C7FBAE31BDA0FDE6B61E4EE -:10D160009F771CAABDDD2DFF5CC2F3FCABF74EBE62 -:10D17000EC7E65934F9F9F6A2CC7D962E72FBB5403 -:10D18000BCEF96EA6FCA01BD31D5C4CEEF0924E3E6 -:10D19000160AEFEE38EDDEFC9A6CA8EF14981EDA52 -:10D1A0001932A31EDA69F778307E9B6661E757056E -:10D1B0004F04CE23B8FB5AE4E8DF21D9EE6076585D -:10D1C000500C8FFB02ECF137181F8C9D9ACB432A31 -:10D1D0005AFA62A617461D9736C3EFCF3DEACCBF79 -:10D1E000007C9606B8A3DF798F4A78CF52F55109B3 -:10D1F000F5E36FF7BD5D04F1512DCF79CC9EB78B70 -:10D200000A86C2FB8CDFFEA1EA65AD8E4740405F17 -:10D210001AEEDD1FD7711E4B7F6F7E29F0514E67CE -:10D22000BBF13EF9601CDB3F994D6411869871B4E7 -:10D23000F45EB8DECC78AFFCEC303BFF36F3B027C1 -:10D24000F6BDF22A7F18EF37A7F6778A13ECEFE7DF -:10D250005AF6416884C86CDD0E4A35D7303FA326A4 -:10D260001BF8499343FCA3F80B7E3244F7BB06B787 -:10D27000A9F37FD02DB0FBA92212EE4BFE9CB0EF9C -:10D2800082EA3A36CAC9F440EEEA17E6039C23CB99 -:10D290009566A0CBB32E16D7F905095BB2816E6EE9 -:10D2A00001F75382A23CF90BAEF33D22940EB1D3A9 -:10D2B000F63D7DE246C2F88F3A3D639C609F09EDE2 -:10D2C00087E0BB31E37347821EB78F589B04EB9A0C -:10D2D000063785AB789BBD130E0DAE814EC6978F7A -:10D2E0003ACBC6001EE03BD04B4D478E59E07B8DBC -:10D2F0001F827BCF303E88E20BE0834EBEE01640BB -:10D300005DC383A2AECFB7FD8BF8428B6BF4C81719 -:10D3100010B7707E2FBE980B7835F205B5E73CCE7E -:10D3200018F65C50627993C6E73FB1E7E3FB6E897C -:10D3300060DE13D96765BF6BE849C07D90DFB8D860 -:10D34000986D9F1CCBA4A62859E56476BDF63B2AB0 -:10D3500023C21CDA9F23A8A2B80DEDBC7EA827DD4E -:10D360002AFEC8318E83FB4631373E03ECD0701263 -:10D37000D86B23CC256190875DB68919603FE6DACA -:10D380002664C3FC5F1EB2FA4D58D25EEE5BFE9B74 -:10D39000AD72A77DA5E9C366B55B6DFC352A7F4CF0 -:10D3A00052D87927D0EBD17068EB039009E0E0C246 -:10D3B000B34DDFDA508F8722146F93000E8A87FDFA -:10D3C0001C6904FB21DFA4244F063BB04F580038F2 -:10D3D000DBF67E9D09F1CE92D0EB1F02BC25DA3E32 -:10D3E000AC5BBF0F6BB4B7357B48F33F347B49F37D -:10D3F0007BC1AE82F632D51F7199D9BED884B005F3 -:10D40000EF5378E4AC7C95A2CAB340E751A2CEE3D7 -:10D4100066D2827069F7A94C53F1517288FAAB3920 -:10D42000D04EC8548A87A9EA7D2A53DDFAFB226EC2 -:10D430001E1BFB3E15AD9F9EDE37AE1BD71AF6A313 -:10D440007E6879C8C7EE4FF9BD8FF9C3E307F07E58 -:10D4500001D6DFB159ECFE0917C3C32129F63A768C -:10D460005195EBF1A6480E9CC7DEBFE7EFB86E1EE4 -:10D47000D8F3F7F7C18E1C77422090973BFEC4A8E3 -:10D4800078CC0F182B235F69FD7A3F6FB411F69C9F -:10D4900044FFDECC410A8F7225C067C1F295538FDD -:10D4A0003C0AFD9D3F2A90E8731F45926720C4E522 -:10D4B0008BD4DF1D3AC8317B4A6B3FA8FEDEC71113 -:10D4C000956F212143BB67C51C45E7A9EAFD1F1ADB -:10D4D0005DA71E2F3E21E474A50FFCFD33E2105A18 -:10D4E000FCE19CAA0F49F39FF07CCEF58D770A6092 -:10D4F000BF5F9FC613256ADC1B64EAE947C5214E5E -:10D500003A0DF66FF3338F4E83BCE5B7784C81F458 -:10D510008676BE9903F5163EE6BD2A46FC5E1FBA26 -:10D5200013EF55991BCFE4A3A7F1C75F4DF96438FA -:10D53000D09D303B308FDD4B62A4EF813DFF9114D5 -:10D5400019DA3DBEBBA3BF910EAF9C2AC07DAC9E35 -:10D55000E861E4DB7D749EFE2BE177532DC48FBF21 -:10D560009BEAC2FAABBE34AC6BFCEADDFB6412D8BA -:10D57000791A9F4E49627C336EF7A349C4DE492F66 -:10D5800023DE86C533FE7FC9AAD925EE59D3E8A389 -:10D5900077E93A848CEA272D903756AAC23AFB7075 -:10D5A00011DA25443DCF625CDF66F3B74D0175DAD1 -:10D5B000D3EFFECC94CB7AF57B39C56FD50BB00E8B -:10D5C0001609AB991E53ED780D1E239DDF23A50888 -:10D5D0007F77F019F9C008E74B1DF9F60AAE07DAB4 -:10D5E000EFE0CC18982526C69887868F9984AEC719 -:10D5F000D9BD5F8F6F8CD7DBEFE78E17FE11D0DAC6 -:10D600009DBC19E9666CD7F447110C908BA51FECF3 -:10D6100093B9F12948DFA28B1251E83A43FAE9CFD6 -:10D62000F593922B91DF56B9D8B3EEF8ADFA224FAD -:10D630003C233BF94E6C7AD8067CB75BA8B7411CFB -:10D64000F53AFBF43A10BDC2CF0B66E2FD1511139B -:10D6500081D0DA94D099668833783F2478BEA120AF -:10D66000B47F32F0E9AB420BFA596DE7097938CA59 -:10D67000EE6C0AD5D9C02E6B4A66E7F30E26105D14 -:10D68000FEF4C578A66F9A8E9E9DA6C4681FEE62B2 -:10D69000FC3C8328C939F49F45EB297F801FDCC7F8 -:10D6A00081719242CEFD5A32D82D7339F423DAF6C5 -:10D6B0008E792D99C2DB7A7B02EA99294DF7DDE953 -:10D6C000A28408FE63243E6F2FE3F0FE8422D98DEE -:10D6D000F5A2C559E8F78DF926694609B4DF20A2FD -:10D6E000DF3385AF14205E753A8DC3AB3CF6709185 -:10D6F0005AF83D62FF74360E71F993C03F7DA7243E -:10D700006904FE669EACD507E1EF2E1283FFB6FAE0 -:10D71000A573FBCDB47DF52C0EF38DA7B832883FF1 -:10D720008A7F8AD64B38AF5B42A905C0D7338AF5CA -:10D73000E71EC3AA3D39ABD44602D1FBF99C0BE5E9 -:10D74000FAA0B5FD56FC1DF1BD2281F969727EA3D8 -:10D75000CAEFB3E724E9BE9B4E98DDA9C9D54DAA0F -:10D76000FCDDA8FACD733D19BAF14B09B387FE4031 -:10D77000DA0B8164F7B8D87EF4B4F696C3F3E125EA -:10D78000BEDF68D087370D31F8BD7CE55AE48B34B5 -:10D79000CE8DF7C8B8F5ED378FD5D78DF26BD40F96 -:10D7A000B3208B8FEFAA27347D306B2F2F423C683C -:10D7B000563EC533DAC57ABBBD277D3126AE1B7D0B -:10D7C0007149BE17CC902EFAE2E3E2EFA52F7E4B13 -:10D7D000DD96B154AEDF8E57D7CDFEA43FE88D293C -:10D7E000FC8E47818FDAE8BA698EC147DABAA3C5E1 -:10D7F000018AA81CA31E38C5F663A65C4C27FE91BF -:10D800009D71800E3D42ED12770C7BA9353E1BE5E4 -:10D81000AB43EF687A25CA2E11F37EB85D3285DA04 -:10D82000A3522EC0D70FE12B52EF252982842B88DB -:10D830001FA69DC1389057A0FE2CAECF4F227F81EE -:10D84000FEE3123BE5C368AF6871E80A97664FE9EB -:10D85000F9A5231E3993DDC3AAF14911E013E47F32 -:10D86000268FFB04FF1BD47F03B300800000000061 -:10D870001F8B08000000000000FFC57C097854558C -:10D8800096F079F55E2D495592AA6C148BF012B67C -:10D890008424588480EC165958A314A080CB688146 -:10D8A0000B6B129A719CEE69FFA642024343B78349 -:10D8B000D2DACEE8F457D83A831AB40801039DD0DF -:10D8C00015504C5834082EF8D91A6D1AD10E4984C7 -:10D8D000D646BBBFCFFF9C73EF4BAA2A854DFFFFF7 -:10D8E0003FDF9FB47DB9EFDE77EFB9673FE79E97E3 -:10D8F000DB9B55B3AD08E0F6998A071400D0F177A9 -:10D9000022C042E07FC3ACAD16F08EC7BED7FC6923 -:10D91000870DF8E73BFC2F9C90FC2CA450CF0B907C -:10D9200009B054CE5FFC577D333D5E3C277AFE52F2 -:10D9300098FDB9920C701BF8CD301CF7F3C58EFF23 -:10D94000EC4B15C7972E8B7E9EE94C4ABF9087FF04 -:10D95000180123BE5301CAD4BA9DB722BCDD275596 -:10D960008F554C33D1FE0F39C5FE0F35970C807C97 -:10D9700080DF7416A7F8B13DB611211C0DD0BAD1C5 -:10D98000C6ED71EC07F1C5EFE8E7663C9F05FC21A9 -:10D9900007B6B45221B701480518EDC4452760FF0A -:10D9A0002A9E3F0DC78624C0EF73245CD900AFE7E1 -:10D9B00098E704F1BDC3B85E00D70DE3FA015CF748 -:10D9C000C84627F75FDBE8E6FE0D2E446A06C0FA7C -:10D9D0001427AF372FF776871FDF5BE3CCE6E750DE -:10D9E0003EDA44F836E02F7B6A080410DFAF77ACEC -:10D9F000D09474802AB7E2B166F5D1014FE3588E16 -:10DA0000F3CB25BE2BB72A10C4E7E51FAE2B07C406 -:10DA10005F5733EE87F8A92A558336FC6749D363ED -:10DA20003B45DF0CD608FADE228E0233B516CD86D2 -:10DA3000FB2CF0281E15F7F13689F76FF52A411DEA -:10DA4000FF798B279A1E8763E8BE58AEB380FE0F1E -:10DA5000DF5B30470986719D0593A2DF5B7C75D63D -:10DA6000E7CAD8FE7CB498E83EB63FBFDC4E74B738 -:10DA7000E33F86C130A2FB958BA56F8D853EBAC56D -:10DA8000B6B1748E1DBF169DEF273A675C9BCEC65C -:10DA9000FB7F8BCE0F114E90BE70F41B8B9E04301B -:10DAA000BBE9071AD179F6558DD7AD32CE3314863E -:10DAB000D279FED459F86FB742DFFCAAA62F2DFE0B -:10DAC000826B9FE76FEDBF2245E7FD695F6F7EDFE9 -:10DAD000BEF33480C178CEF939D1F88DA56B2CBD59 -:10DAE00016CAF762E9B535E61C065DA013996860B1 -:10DAF0001CBC5F55198E6BD1AD972E16FF084F7E5B -:10DB0000FF71805FF3B9FAD693748276CD5720E027 -:10DB10003247C803F2752005E95BDE0AE14404ECF4 -:10DB2000968B733ED7A8F528F069C439E8E753838C -:10DB3000CE6ADFFA655707B2FC19FB966910B0147C -:10DB4000D2732197B1F055D23A23697E80F968CB20 -:10DB50002ED3B2109E63BA05EEF5519B28DA034E20 -:10DB6000A1071A9D265EB7FB2B9B096E0478E5F092 -:10DB7000806240F83C56E709D28B2133F0FB45C95F -:10DB80003ACFDF9C048104DC1FB4769B0FF9442B51 -:10DB900006C84139D306598235B8649D16F691DC22 -:10DBA000757B34A846B9BBD178EF48E02E40926C23 -:10DBB000FE7494A9268BDE0FB74FC57937156AFA24 -:10DBC000369CE2B2EA3FA0F1AE66AB93DEEB3EF8E4 -:10DBD000CF2D665AE72BF02084F05A3332158E4F42 -:10DBE000739883A437CAD493AA09FBDD3D00A48FA0 -:10DBF000A62D0B9700D26D3AB4D738B19D42748CE4 -:10DC000043BFBFD0793384DE1A88749A21E9344344 -:10DC1000EAAB926695F54649921A84AC3EFD74B320 -:10DC2000A4D18C407B490AEE3B43533C35D8BFF925 -:10DC3000AA16C58F2F933EBAB14F1F95C9F5BD3DAA -:10DC4000BA869601664234FF96350A3D54628B7956 -:10DC50002EED0FBEC97C55E68C1E9F42BA13F9FB10 -:10DC6000628C5E8218FB53A6FE35B903F1F08AC5BB -:10DC7000FBDE5484BBE7B4199EC5E770113B93FBF0 -:10DC8000E3A731C61EC5B6070F277A7584EB15E2E8 -:10DC90002307F50779F5B1D79E3FB6A3A7988EF174 -:10DCA0004ADD220DB2992DCFBA33FBF0DE0FBF92C1 -:10DCB0000EB178AD977ADEDBE87C8D8EDB0F8FAD11 -:10DCC000B3D89E97FC49D748F5FDBDF834E4E595F7 -:10DCD0000B895EE2FF572E0CF2B2FD4AD2593E0C80 -:10DCE000793878FE7222E951C4A7AE219FF4B86C4E -:10DCF0009E67999F851C84068E0A6EC3FE8524C18B -:10DD0000F7AF24F61CCF23BCDF62F23C4BDB68EBA1 -:10DD1000872F2A20FDB975D1793380E205E5872860 -:10DD20004F8AEE84BBB10DA03C11FF055221487211 -:10DD3000628610D0BE355E789ADA19D3F414C2FB2D -:10DD4000655CB3DD41EBE929C4F7F0D72B137D0502 -:10DD5000FDF15FBF117C1AEED3B0D1E6D3502F1C7A -:10DD6000D8E8E47EE34637B78736EADC6E3A91FCC2 -:10DD700043F21FAABC169F16A157E6A50AFD300361 -:10DD8000F50EC13503946000796FC623C0F2887226 -:10DD900010DCA410BDF03C397DF844FA5CEE88E854 -:10DDA00043AD563B2193A582E95E9867E2F7D1091E -:10DDB000083E9FD57F3ED23FAABF8CFC1684C3EF9E -:10DDC000F296B9B00D397CB35D88DF7A65E9D14B45 -:10DDD000C0FDB9F4BC5EB943BD84EB8F0FCF841F87 -:10DDE000A2BD188F8421BCE2CF5D04FF84160B1006 -:10DDF0007DD0B0B27C161AF2F9B5A25CC0FD4884A1 -:10DE0000BE1B8CEF59CBC3C44F07A0238DF05E64BB -:10DE1000F3D9497E97B9043F7895DBDD0AAE3739EF -:10DE2000C3E25109B4E1BEF1EB117F2D19B821CE47 -:10DE30006F69C91CA2E713B7BDF13EC9B7D7E608A1 -:10DE4000AB6C98CC9D1D11F67C003CE3247F927452 -:10DE5000DC7768475A3F4E0EB09EBB6A09925E6BF4 -:10DE60003D93EC09E33ED3AFDAD8BFACA717516EB0 -:10DE70000F27268F653D13420D43F26313E7986D1C -:10DE8000F6AF233CA0653E7A0ADFFBED6500D2AF1A -:10DE9000D3DB3F54C90F2D31E50EE840388F2AA35C -:10DEA00053A87DF2E3E47C6ECF2477127E0E9BECC8 -:10DEB0003AEDFBCE46BD7404F2CBA98D503A02F97F -:10DEC000E3AD8D366E4F6F74727B66A39BDBA33818 -:10DED0004EFCF33A8E137FBD81E3D46FC3716A4F5A -:10DEE000E03AD47ADF7298487E67BCE5D0A82DBCB2 -:10DEF0002B89DBFA3B932C748EC3C95067EC4FFC23 -:10DF0000144E0C378007E52ED5FD53DB0D683FAD71 -:10DF1000FE02651CC0D454F75C6D3AAE3B7BE88FC3 -:10DF2000BEC2F119A9C37E6A43786F3BE3683889A2 -:10DF3000FDD2C7F59F3A883F4F24A292243C64B794 -:10DF4000795136C793D218C468F7C224ECA719FDDB -:10DF5000ECB9A5C80A4B4A3AF2C005B0F3B1E17377 -:10DF60006D88DF2576FF3F51DF12689B533A9DFA9B -:10DF7000107092BC2BE620CBFB10257D11DABFADD3 -:10DF80000EFFC4D4087FC0ABFC218DF4C344AF02A4 -:10DF9000AE74A67770A4D2F7DC98B7D55136311598 -:10DFA000F9F7D72E95F969C234C51B74F4975F63EE -:10DFB000DE84F37A29D16FE2C559B5D42E98E3E215 -:10DFC000BE6FD94DB524FFA58E6BBD5FC2EF875CD8 -:10DFD00066D647C51ACE8B63178D79E391C9C8FF02 -:10DFE000EE694B0C3E4B7C7DD65F9384FD327756B9 -:10DFF000A12A753470DFB56B1B8D97BFDEC072E54B -:10E0000049F2E859C48AEDA569383ED3A178C22403 -:10E010002AD33EA94DA371A7E221B4CDF48E3B557E -:10E0200044E32354CF4CEA9FD54B9DD89ED1664EF6 -:10E03000BD84F366E7A4786CF8DE99F08FAE10FF2C -:10E04000CECC49F224E81417049FAEA4BEC7EAA9B7 -:10E05000D6E91C8F9524D33ABAE23161BFFED6923D -:10E06000FF457014FB52405168DCA5911FFBE4C7CB -:10E070003F2975E2BCFAA10A90FC9C09E7FE91E0F9 -:10E080009FD99AA8272040F5166729BD576F519C44 -:10E090009BB8EF2BA1F9815166FD795CF7E49D7681 -:10E0A000B607E56FE5B35F74F2CEC16C17CADF9AAD -:10E0B000564CED4993F0DBCBDF2A9FC3E326089350 -:10E0C0005229BFEB1FF8BD1D253F294DC7F54F0C49 -:10E0D00073B16E413A956A117A0DE78342EFDF55CD -:10E0E000C1F35B94013F3A8FF3AFE4A7145A71FF79 -:10E0F00059E90951F3E70C7145F5E78D1858AA4520 -:10E10000D8B1F2FCACA8FEAD454AE98888F9BE69F1 -:10E110000951FD45A5AED21111F36F2B1F18D55F24 -:10E12000725B56547FA669B2D01F1BA1BC54C87D38 -:10E130007929FB9BD9AC870A9D62EE1B387E3F8E06 -:10E1400017B6097FAAD085FE14D2A5B4AD88FD808C -:10E15000367C8FC68BEC528F05A0DD3D91EC80FCA8 -:10E1600009E22FF68B6577663BFA056389AE68B7DF -:10E1700023E02F7544DBF1FA44E127CC017FAD0B9E -:10E18000E939A7751EFB5765E9D54561207C46BF77 -:10E190001F0B372AD19D77131FB66AAC37E70C895E -:10E1A000D9AFADD4C17E8CF4EFE6C8B78C7D21E049 -:10E1B0006D27FFC63887B1FFB5CE33479DC67EE1D8 -:10E1C000DF3AD7AC9C85A5A971E15FCFFE4C2C9CB2 -:10E1D00079A9324F81FE15FB85ADA9EC2FE24F7A6C -:10E1E0003C3FC1F07FCA51CFB922F59C43495F58EB -:10E1F000706D3D67AC7B2DFFCF58D7781FEA54DE9A -:10E20000DF78BFF7B9AEC47FBE1BE727C5799EAEE6 -:10E21000C47FFE5CF4FC199A5EE340793E0E8A27C7 -:10E2200040783FA96BE49A959CF5D6525BF6A15FC6 -:10E2300023B770F6F9402DB5533B8327AD78FEB96F -:10E2400039AA4EF907C32FEA1767A50A7FE4F855E4 -:10E25000DDAEE3787D40B753DC51FF886EA7F8AAA6 -:10E26000DE0B73288EF40E37ADA738C49B872DF6CE -:10E27000EF4D15FA7E857CDF680FA9FE15047F85BA -:10E28000ADE351F2492ABFE9B1105F1C277F2FBFD0 -:10E29000BFBF775C0B3A68BFE38F041DBE087D7E6D -:10E2A000BDFEDE2262A60CE253C517A94F4A6C09D7 -:10E2B000BE48FD51E67445F5C793FF83EFCD760F59 -:10E2C0008C7A6FAE9E15350FFDD81CF2876A2C90A4 -:10E2D000A3913E35257AC8CF8BC5E3EFE5F93D0E16 -:10E2E00027B951604ED7557F1CFBE42911F88B7D6F -:10E2F000BE3D55C47383C89EE33A2752756E6B5575 -:10E300009F70E6D07F267E88ED63ACBA8CD6C3952D -:10E31000DDC4771EBBE90ABAE0F0D2E3F3E76A682E -:10E32000FF3DE34DFF381CFBC71E5F21FA534DFB39 -:10E33000B2B1DFFAF87DA27FA369BCD983EC19B82A -:10E340007F6E29F90BE9BE7F27FA759B1D5B15D4FB -:10E35000039509A8D7B0D54C0A14A6F7C5C7DB2D7D -:10E36000685F91C0C86C5E17D2C06E15F17465C24B -:10E37000D020D913ADD8AB13DE2A130C7A77649270 -:10E380009D87DA0951719DDD82EFE1FB6536FF0B58 -:10E39000826FC2C93AEAA5870E960D20FE3891EA2F -:10E3A000643CE4ED9BEA267D85F0ED21FBFEFF0158 -:10E3B000BEE678F0D59AC53E9DF57925648FF38643 -:10E3C0002179943EFA156A3A3F4F0821EFB0BFEE2B -:10E3D0007553FEB1C665F190FF7E42F2EFF5B6359A -:10E3E000328FA1DA051FA929A6F57BB17D5BF2CF9B -:10E3F00019B92F6ABEA10B913FC0D933745181E87E -:10E40000137FA86A610FF9E13DFF90E4A1F8F98359 -:10E4100044813F18D2F3D18FF1F97B77E779B6F1D8 -:10E420007381A765C1EC9A0EEC8FB3066FA0FCE375 -:10E43000A134FF4784873BADC191CC878EF549B4A9 -:10E440008FE2058E538CF80FE33CDD32BC7F5C70AD -:10E45000EDFDC1467665E9648177637FC4B18DE8DF -:10E46000F1DE24F1DC8007E1E8263E30E0EA8507B2 -:10E470008638398F0022FFD425E38B2E5A8FECA7E4 -:10E48000EA1079DC3F9838FF5245C28AFD7DE74D9E -:10E490001C0F1A79E02210FB4D3EB54965E003F8E8 -:10E4A0003B51A2965E695CCBF1FD84762D26FEF68B -:10E4B000B23D9D2ADFBFA9D55FE2A0F6FDE8795302 -:10E4C000651C3F09822AC559933B62C61BE77F46FC -:10E4D000EB4FBD18FD3C294DDAC3413028324FB215 -:10E4E00041C64D974F66A7101F6B182BA8480F8B7E -:10E4F000AEC2A4D43E3DD3B011E759499FDAB82D3E -:10E5000038EBBC8FF669DC880C3F9AF4AA9B5B431E -:10E51000EE0ACEC2BD3036621F2917061E2FBF2F4E -:10E52000F038AE23E797D3B06F6E354350EFC3C3D7 -:10E5300014892F0CDF38FEBB7CD1C1F66B62DB6225 -:10E5400095E4D9EA36811E71BE043D11F4087D6C54 -:10E55000CF498DEAAB929EB509D17ECA78B94F9268 -:10E560006750D47A86BF62D0F350EAAC56F263C6E5 -:10E570003B56B1DF9232293B6AFDA293D1F82E04BB -:10E580009F97E263CF87C071C0C4B35A947F32298A -:10E59000BC83F963D287D1CFA79C8FEE97A6C9FC25 -:10E5A000562CDDAE854F18FBCB69E97F3F3E5DDE23 -:10E5B000687CA6CD89C667862F1A9F039645E36BB4 -:10E5C000A03F1A1F83578D891ABF617D61547FD880 -:10E5D0000FA744CDCF428319D91FBE755ED4FC91DD -:10E5E0003B1645F5473F7567D4FCDCE08AA8F1BCD3 -:10E5F000DD6BFE2EFA17843644CD27349BBE87FE92 -:10E600003736FE4BD47EFF53F4AF8DA1FF56D2E7D1 -:10E6100013885EA8370BFBEC19B925A43F5D4D6F3D -:10E620007C43799B40B1CEF9AAC03CF0D4E0D82F0E -:10E63000549F427A6E30A2DA847AA3D604ABC81E05 -:10E640003C6A32711ED390F317D3843FF2629AC8AA -:10E650007B19787B1AED22D94155EA4373FA8E244F -:10E66000F253549309DAC9FE691ED61FE71C10BE87 -:10E6700019F7550701E7C54A92272D9888FCA8BECF -:10E68000A972FCA90EF2838EF6A4E6E4CE53849F11 -:10E690002B0E9B4E7CABA6FA0364DFF09CA1E7A196 -:10E6A000BF9FF3DE465849F196D15FE65EBF99E61B -:10E6B0002FBB7BE6488A7F7B9FDFADAC2C8DA043D0 -:10E6C000E43917C5F1AB0EA409FB67D813C37EDC90 -:10E6D00069D56B3AD03E8C53857D40BB71200DF1DE -:10E6E000F181F28859F86901339D1FED2ADF27B8BF -:10E6F000D021DF806D4A9FDDD2BF43E6FA203BDAAE -:10E700006F7D9300A33844F7F03DE31D86FE5D95D1 -:10E71000CBF8BBEC889E7FF9FEE102AFF720F690C4 -:10E720000EE72CE23C06FC17A55EFE42EAE54ED25F -:10E73000C711F9EB55BB7626917F7E2E47F8E3C6CD -:10E74000F3DF493AFF2E4DE5F3AFDD9DB0FE7C04CB -:10E75000DE2A42AEA87E55E3C0F591F9CDB5C639A3 -:10E76000FC8A46E75827E5A8A2B523F94E607FFE4C -:10E77000C3345CB772D7957B0ED0FBA69E4C616705 -:10E7800003BCDFD2F780E382A57F8128BFB633CDFB -:10E79000CC7075A689386109364EE4BB25E803B80C -:10E7A000A87D63DA2CE23F7C1E56B0BFA015CCA436 -:10E7B000BF16FAB3CC84F433E079673F1EEDCF691E -:10E7C0003AEF731BF8F87EFBDD7B2A92D80F34D624 -:10E7D00033D64181203FEF3D57C09C49799FE90ADC -:10E7E000FB17B89F8D9EFBEE1EBC99ECB0B1DFBB52 -:10E7F000E0BFF40EF2C522F0F0BAC6FA40D73411E9 -:10E800007AF9034B2F1DED44BF0D6DA630E585361B -:10E810009CB3F2BD4A7775CFCB0F239C1FAFF9662F -:10E82000BF82707FB4BCE7BF0EE0F33B9E5241470E -:10E83000BEF1D9FD5A7A44BC79EEFE2B2C6FE8AFBD -:10E840003CFF2429A597AC1E92930FD6BC342A32E4 -:10E850005E484E9F99904EF73B93D2E2DE6FC4C65E -:10E86000A56B883F597E75F64B0DBE5C2DF972C3C2 -:10E870000BA3F9F986A4DEF388FEF32AE7C1363448 -:10E880005B39AFF18EE487352F7E333132CF578F2E -:10E890007CA95BA975724BF7A63AFA09FB4E5E1E7E -:10E8A000CB71ABEACFA2731EBEFA6932F5F7BDF9A0 -:10E8B0002D9F076EBB3EF8BB11799178AE4AEA797D -:10E8C00097F44AC501AB4EF9AC9203B927EEC27E6C -:10E8D000652BEA1F3CCF2557C7B1A7291E3BA800CF -:10E8E000E5B72AC309ACE42B1B9420E5C3D634EE6C -:10E8F000DD3218FB6BEA161611BB56250B7D5659F7 -:10E90000AF0437B11F3E87E95C2865A3E450EEBF32 -:10E91000E5E378D771B1FE858DB0F63CC69D5DF517 -:10E920005F5E2038D6355A39CF7621296C198CFB99 -:10E930005EDAAB84027A9FDC76B9441CB62AF4987E -:10E9400085F65DF5DCC211E436761D386D213DB9E2 -:10E95000AAE1B159F2799130FF41968BB5BB9595FB -:10E960009179ACD5E80E42A4FD42F80213FBEA40CF -:10E970004E49FA2C6B1A5E43E842BDB6FF6985F535 -:10E98000DA42E2970F0EEFF9DD6F68DF83FF3D9209 -:10E99000F15F747DF8075F80FD8B4AB90F5C3C63C3 -:10E9A000A1F8B2B2C17C21DEFD5263BAEF1EDACF0C -:10E9B000888F63FDEE2D1610F73FD9107C9EEC82F8 -:10E9C000A3C7B21CE1F9579A80F068CE1ECB0AECBF -:10E9D000DB48CEC85EB81DC17871F5BE748DF18478 -:10E9E000B1C4FA78F7A021395EA27758289F57E979 -:10E9F000EEB4105F57863F17F7FF8D9FCCF2C689A4 -:10EA0000B75F4E57A4333F274ADE37648C61B93075 -:10EA1000F7DAC3908DE5BE60450FD9A90D07913B8C -:10EA200014A2B7BF87E00EEC4FD0E97C25073E9FCC -:10EA3000D811B1CF1FA57CF4E6595EF964AC99F00A -:10EA4000B9EF93B15A52DFF3AE4CC7AA78799997D0 -:10EA5000D385DDDE9CECBB182D07099E30EE5BD91B -:10EA600064E77B1494832D2D45917270C7AA5DC411 -:10EA7000E74DAA0725022A1B17FAAB797E9287C8B1 -:10EA8000A336CE0C101FAA4E1FF327FC15F79B28A8 -:10EA9000EF8F50FFCD4DF73F4D72AC396065641E6E -:10EAA000A4D2D4F1AB1685E8BAC36BA2FD0A81F5F6 -:10EAB00096EAF075703C5594A953DC7B74C22C2007 -:10EAC0003CFDBC59E1BCAF39D5BF358BE87B5CE57B -:10EAD000F996A32F04E8BEBB6B1C14117CC6797F8A -:10EAE0003E2E0C2AAEB3B9003CB4EDE6834BDDC438 -:10EAF000BF3FCF38C67E86DD1302D22B35E83F50AC -:10EB0000DEC79E1F0AD33A0939BE2215F75993EE84 -:10EB100064BEB458FD1ECA273D20FB36CDB78AE03F -:10EB2000B3A5278AF87BC8F5E5F9BA48FECD746F1E -:10EB3000E9E77C4B9759F069D70DC07122D7FC4C9F -:10EB4000A6212FE3CD063BB8AD6A54D646DAD744AA -:10EB5000F0DBE879D7C1A51E82DF9C2DF93D33910A -:10EB6000E52276FF8F889FA9CEC0B4626B16E1992B -:10EB7000F0A6F79FF7A1E47B031FA0F973485E118D -:10EB8000546FBCFC923FBDF82CD17573AA2FC7956A -:10EB9000CFD7BCC2297627C6953B9CFF01C9B731A8 -:10EBA000BF95F089EF6FD1FC36C2EF51895FB3C5D5 -:10EBB000A73B59FE7D3AEDDF7BBE41F1CFF78D3C9F -:10EBC000DF966CFFF79EEFCFF27CE654E4375A2FC6 -:10EBD00019789E39391820FEAB4D82A24DF8F8A85D -:10EBE0006B969BE46ECB916F8692BCD72679DC4006 -:10EBF00079B1E69B9691DC6F197427F3FF172FE428 -:10EC000016AA11FB24A7177F45E73B2FCFB1C5E21A -:10EC1000CFA1737C2CCF699C6B49BAEF2FE911F916 -:10EC20002618927E5DFCB3D7B8D794719E47DA61FF -:10EC30008CF3388FD80D895C7FB657FAE11AF898B3 -:10EC40007FECE0D1D9BFF2C209AA2BA96931C13644 -:10EC50003A3E25B522EEFD925593110C7A6D18B20D -:10EC6000D335348D3B9FD839AF16E13E080155F8B6 -:10EC700069D1F90CF02A5E25328FF1DA9AEBCB6379 -:10EC80003CE3AF21798DCD634C0E9B965B52AE2356 -:10EC90009FF1DABCB8F98CD119D171514186CEC03F -:10ECA0008572047F86C28941913783F194BFEA2639 -:10ECB0005B85E39FE39959DE95AE1C9B0BEDE0135A -:10ECC0004F6CDB3A0DE57084C003F56B88C9F5F134 -:10ECD000EC07F5E6475E1BC37E38EA3D95F3024E2E -:10ECE000094B0C1D8BD07F1341A5272ABF123EF67E -:10ECF0006D32F1DB9E54FD2DA24F4F9BCA75280942 -:10ED00005A87C51547EE0E907F8076E09F33843E8C -:10ED1000B7358A7B4B9BEE653D99E0748E5323E4B7 -:10ED2000242F43D8A58A631F0CB5A02C5D329D4CBF -:10ED3000CEC7F5D7EDAF4FA634DEDA736F4FA4D24E -:10ED40009F3B35FF820C3CFF17CAAE5136F25BB7D2 -:10ED500006C7127E42E16CAECF2CD020A015F687FC -:10ED6000A7EA293C14BA04954FA5715BD0347E25DF -:10ED7000F15F55589C97F630A38ACC6D54B8DFD517 -:10ED800058934AEB55FDB67910E9AF9732849FF35B -:10ED9000E2D53CF1BE061ACDBF3FC325992A68A231 -:10EDA0007CE34B324FD97555E579C6FE058D335559 -:10EDB00027F2417E78C711CE8B365975A26FC27388 -:10EDC00020F0D194C07E68D5E1D94076AFDB051E36 -:10EDD00005C7F724F67C44FCD0D36CD5E93E37C197 -:10EDE000B9035271FD3DB21E2C1719B6DED1F7DC06 -:10EDF000D82FA1E997944324BEE07BE5046D074C2E -:10EE00007744E23B49D859C9577B12C326BA67E910 -:10EE100041DFEF5986AB0F4EE07D0D3873D90EEC14 -:10EE2000B1F45CF8713AC3E5243EC8050127348D7E -:10EE3000D649AF2638BD7C8E04A7EE0928FDE1AA8D -:10EE40001A8B8E20CACFA3A4CCA6F4C97755625FD3 -:10EE5000DF86B2B0271BA4FCB76E2B9D16D9478561 -:10EE600033A9EFFDFF78E2F8B6DA219CFF0BA84842 -:10EE70007F3BB649A9744E21572812DE8C42810788 -:10EE8000AA0BB4DBC478EF7CE473472ADB7F9EE7F0 -:10EE9000B13AEDF3B2585EF87ED1F00F1F52C217AF -:10EEA0006E46D2763EE64BC9C773759A8E3C5C8738 -:10EEB000F3FEB83C342A8CFD16ABFF79E2CF573F06 -:10EEC0005CB1BD80F4EF1EB3A79CF44F47E071F630 -:10EED000CB5F34EBDB22E40E86F46472DD61CC3E62 -:10EEE00055E7363D4EFE76F74145A7FBF46E73CFEE -:10EEF0005082BBB2E9330BD563561DFC84FDEBB2E7 -:10EF00004CFF5EDA6F526335D7CF4D861D5C3F876D -:10EF10007A91EB20436EA14F2E9F1DF56C75041D59 -:10EF2000DE93F2063DFE6164BF9AA4BC1EA6381CA7 -:10EF3000DBFD2D770CA7F5F7CBFC80F15E351C19B6 -:10EF40004C78DF04AF716B3CEF0E6A5CBF9CF7AE90 -:10EF5000ED5E6FC4FCD352FE4FCBFD5667FADF2047 -:10EF600078D7B67C6AA1D2C2AAF3A1A114F78634DD -:10EF70003DC519478FF4CA6F8C3C55693D169A5FA1 -:10EF8000751158AF20BD6B53907E2FBDDB386639AD -:10EF90003EDF8F3449213B8BF12AD9E3FD66DF60E8 -:10EFA0009A5FFDCED763498F1D2420F07F5F37AF76 -:10EFB0001D467843FE2F4E2439DB0BACD70C39CDE0 -:10EFC0002739C5F7F389FF8BA89FCB7A798FA57D69 -:10EFD0001ECBE57E13905C22FFB33C20FF3BC9DFD4 -:10EFE000CB77A23CF0FBA359CEF7B49BBCEC37A384 -:10EFF0005E1FC9FDE2C5D4DFD35EEA6439A73A8457 -:10F000004292D7F0115E270440D7F2450AF822FD5C -:10F01000FFBC8C64712F24F1393943D883508E9E04 -:10F02000E2C173D855354A3E22ECA5E84B7B5A9A8B -:10F03000F9976DBF98465226ED8453DA49FF78D68A -:10F04000FBFF286DD586D7A72CA8C3736E38A5F211 -:10F05000F86119F785259F1C91F91AB21B7A9AA8B5 -:10F060001FA6E713B04FF5E513BDEB4BC81C4D9A37 -:10F07000B3E328B5537CA11272DBA62D6B3F6A1651 -:10F08000629E47FCD770646E1ED5E3759FB3420243 -:10F0900082D8F06DCF472F221E1E3E8CF88F63A7BB -:10F0A000F038CC7FE87F0D0677FFF16E45EA91409E -:10F0B000D27CE2C7AE06B5AF8F8054226353DFFD2A -:10F0C000A47D7B006DE77F677A0767223ECF0CF057 -:10F0D00073DB7DFADB4C12CBFD67455CDF60F1E64C -:10F0E00011FF346463A81B874FAD9922EF536485E9 -:10F0F000B8F79C37670A39181580ED0AC7EBAA33B1 -:10F100008874BFD4A07A2DE82F5D84C092A9A46F23 -:10F11000645EF701903F5EFC45FA3C28BB0F90DF30 -:10F120008276EBC15FC4D61178D96F31F25800EB0B -:10F130004DC45F2B9B14F80FC4C5AA67A2E7AF9319 -:10F1400075F2AB1B771D1B8C745DF35CCC38F92D0D -:10F150007CFF11E278785D5D743DC3CD99D27F1953 -:10F160000EC3C97F41BE623D61D6A0D58A7CAC602A -:10F17000144322F69249E00BF52BCB67BE616F8AF0 -:10F18000855EEAB9045CA794BB3B7494EA81A6D47B -:10F190006579688F299A189FD29825EEA7B4A04A5E -:10F1A000750C93BCFE59EC7707BC67A9DE6495D457 -:10F1B00097E0C45FCAFBC8D3AF92FEDDEA606C9DE6 -:10F1C000A8C053959C37198235B4EFCADDA2DE6919 -:10F1D000EDEEE8F955124FEB9E3A7D8CD28515A1E4 -:10F1E000987189A7AAC6983A16B138DC9F29EFAD65 -:10F1F000647DFBF5D65BFCD12CFC8DB7E53AC6F8F7 -:10F20000E64C91EFADC463107DD705D520F1D12A2E -:10F2100025902CFC5E702CC7F3DD67B081ACCFBDB0 -:10F220005FE2E93EC93F7C7E7CBFE219F17DC5FD0E -:10F230003F8B867F0DF82C83F1F9830D3FB050DEB4 -:10F240003196DF56D599D9FF5D23F113CB5F6B7AE9 -:10F25000F9678785EC5B2C7F55FA956BC02FFCF620 -:10F26000FF5BF80D3AAF91CBAC3587393FB5F60966 -:10F27000C543F9AB6B9DABF73CF27C7FEFB99E3594 -:10F28000E83D06C630BDE7A45D17BD63FDEDBD9644 -:10F29000DEBC26E7052FB766733EDDE0ABD87566AA -:10F2A00049BF7DF653C27FBDD4586227FFA3FBA49C -:10F2B000C9A3E89CAF4C2EC0F38F6F5681FC91EE32 -:10F2C000A6E13B03087FE1A9A2C5945F1F7F0AED79 -:10F2D00013DD07B716FD5702DF077BD248EE67B68E -:10F2E0008D48FBBD83D761FBDE7DB2706739E9E9EC -:10F2F00093A545B4AE82E3549F5E28ED54F5C94210 -:10F300007B4784BDFA4DA6C8CF6F71FFFE518A1BA3 -:10F3100066EF357B283F32DBECDF9480F015BEA032 -:10F3200078AA71B763ED479EA47551BE28CD8AF3C4 -:10F33000FEE9088D57ED5118FEEEA6B2BC3D643FC4 -:10F3400083AA87EC6277D37DF90F921FD4FC40FE2D -:10F350007D11FB1D4B15FA66F60D66B6D79D83EC45 -:10F36000BF2EA7BCA87717EB8DCE43FB2CFC7DC32B -:10F370001E05DC78CE63EEA32F131E3A0F9CB65009 -:10F380001050D270DAD211477F1BED250CF3C29CCE -:10F39000AFDD61E1FACDFD7FB0D0792B9FFB84F327 -:10F3A0006F6B287E203FEF1995BF773ADAFCAA856C -:10F3B000F8B4B24E81015991E3661E27FD4AFDCF94 -:10F3C000EA849E36F87F85E47783FF0D795821F52E -:10F3D000DA7D5BE3F3BBA1FF1E04EF9641B8DE03C9 -:10F3E00075CBB90EE9811DD1F35752FC7A23CD17A5 -:10F3F000FCBEF2A9E8F1D5BD7C1E60FD1FAB47BF86 -:10F4000033F47F2EE4129F5F0EAF18A6A13C7D7DE2 -:10F410007ACD308893AF3C29FD06C36E5F0E9BD832 -:10F42000EEC5CEEB6ABC62217B5BD5FA27F673672B -:10F43000357DC9F4286F6AE17AD95BC0BF8EF07957 -:10F440004B93DD49FE767987D003F39AACC1A04295 -:10F45000E3A15AA273F761F1BD49E090C2FE1648DC -:10F46000BDB852E275A5C4E34A8CE306537D8C8C8B -:10F47000E32B65BCBE3A67D7312A29A994E3EBDABE -:10F480008E26131EE781D05BF342426F19F431ECF4 -:10F4900050ACBE400B770FD1776D9395EBD6E74B11 -:10F4A000BD35BF0EF596D25F7F740FB48BFCF17E35 -:10F4B0000177ACDDAD6C889EEF1A20FCD8CBD27FF3 -:10F4C0002E1C104D97F21EB0537E7F9EAE7A82FCAA -:10F4D00056BB46FBB78E457EC3F55BF5E129F1EAE5 -:10F4E000B58CF64D191718FD059467C3F921E70E81 -:10F4F0004764DCFF9F03847FB366B21A20BA46C418 -:10F50000490B0AB3E2C6497309F43786DCF7B371D5 -:10F5100091719277D728E2B77F75EF2CA7BAA6AA88 -:10F520003AA12FBA26E1BA29E4F703FBD15575D6E3 -:10F5300020C53355C82FFC7D1AF109C96393524683 -:10F540007C8271C6EDB4FE42BAEAC4F32F6C44FB70 -:10F550008ECB2F2CFD92F9AB6D843837E26D40BC19 -:10F56000B8C388372AAF0ABFD6785EA97570DC5158 -:10F57000D924EAB51B8E7C33340BE1ED6EFEF3D05B -:10F58000E5544F3E40D8E786E2D0A75457F4F51E25 -:10F590005B5CFFB557FF2BB52C0F95E68E4CF66BD9 -:10F5A0000EA21F7913EAD1B7BFE038A5E148C2BD6A -:10F5B00094CFEB5AE11FE6FC1E3A55C326F683377B -:10F5C000412DB7E41F45FA8D2B9DA24EE941693FBD -:10F5D000A9FF08F2F583387746617FF937F449854A -:10F5E000E4EBD510D83255E9AF072AA4DCACCDDF67 -:10F5F000B585AEF663FDA70A294F1831B0BD8CF56D -:10F600009FFE33865FABDF4E64FFB8BB4D7552AED5 -:10F6100019F1FBAB41E427625C901D275FFB85E499 -:10F62000CF4E797F5C3D4965FC99268BD6F0B710AB -:10F630008FCC37DDA71D41B26F79875FCD263E584D -:10F64000BB3BFADE89E8E8E7BAB1A0C84785EC7CA5 -:10F6500017658CBF74F8D531C46FD56F7F3B4AD026 -:10F66000E79B5196F46BC367B48A22E2669322E269 -:10F67000E6FD5A4732C56B5507555F643DBF41EF04 -:10F6800097A53C8126F203F50374E6ABEA26C11F79 -:10F69000A666D1E2FE4B447EC8CCFBF71B2F46BECC -:10F6A000F91E7B060417F24095B987F9AFEAB489D1 -:10F6B000E1A93A7D397344C47B015A7700E9BFEA76 -:10F6C00075C0FAC40EA46FE7D3F791D89FFF7E02EE -:10F6D000FB61C7B2B7978BFB2F15487F3DFCF69AAD -:10F6E000D191F660E200712F0E840737793FBF1089 -:10F6F000FB4B3C6C824532BF20F879AF8C9B302E9F -:10F700007B73409CB8EC7AFDE9EA662B50FEB9EABF -:10F71000032BD7197DDDBC92E37EB8EA1F4DFA06B4 -:10F72000FCFE1BA97DF8F0CAD1F4FCEBC3AB6FE47F -:10F730007CA9B2292ACF1120F8DCE45F7DF5EE5DCB -:10F74000E47FB669EC9F14B69D7D97EE69F7359816 -:10F75000F9DBD18AFD13760692C8AF2A9C4FDF11E0 -:10F76000ED6BD598FFD0DF32FC2B3BFB57A78AD837 -:10F77000BFC2757C416E8B4E94D3BAA78A8B689AB0 -:10F7800082E3A4D7C6937FE5E8F3B70C783E93F8FD -:10F79000EC6E49E0BC8B02D982CF604414DCEB1ADA -:10F7A0005E67FF645DA31AF5FD88F1DE5F06887B66 -:10F7B00087EF0C3E0B295EE6A3BDA25DD7B82F9361 -:10F7C000CEB1D61C623EA9AE338BF13DA205BA077D -:10F7D0009AC01F4107083F27E811D2659E2538844B -:10F7E000FCFABDBDF78AB22E2428EAF56A5A87F3DF -:10F7F000774C975BF7A5C7B34327E99E071DBEE388 -:10F8000059221E8A1DFFAD5BE4418E9F13FAF1F869 -:10F810004CFFE8787A3200C5225FA048FA3588EFBD -:10F82000ED63E735D37A78FEDD4302C7898F3BF776 -:10F8300026F0FD63A74BE4754BEADB34FA1E666DD8 -:10F84000833281ECD2DA9CF7F87B19EC17919E5C3D -:10F850001B3EC8F7AF15757B6779E3C0B1DD2DECB2 -:10F86000C33CF99D72ECF87C397E063C19329EDB74 -:10F870004EF73E67CACD4EF1DD9BF8EEF556A9D79F -:10F8800017DF62663FEA0CE866717F22EE391648A0 -:10F89000BD7DABD4F7B1DF631BFAFD76B9CEC2678D -:10F8A0006033DD73C47E9F7DBBF40F178197D7EF64 -:10F8B000F75DBDF41363FFFE42895BEAF551308AC0 -:10F8C000F47A08ED0DD75BE426B0DD9E5F3032AEF2 -:10F8D000DF41DFA9EBF23B756A0DFA57E7BEC7F6C9 -:10F8E000F078CBB997F9FB867309901DE79EADCFF1 -:10F8F0001E1A7AE436417779EF51E114301AF4BFD9 -:10F9000084115A647ECDA0FF83920EFFC7754539DE -:10F91000A045E6630EA9FE07DD195447DDC9FE3890 -:10F920009E80ED219E6BA83CD7506B849DBB3470AC -:10F93000795C3EEE3B5F6A40D893746E5B72ADECCF -:10F9400037568414FEEEB0220CA27F9BC2F9CA5136 -:10F950000D2D5CBFB1A454F178855A3C4BF0197C55 -:10F96000B4C026FC03835F7AF125F988C6C95FB865 -:10F9700055FA0BB1FC341ADA67D1FA4BBD8A87EA23 -:10F9800036AFC947CBC6BD4EE1EEB5F808F9D24C4B -:10F990007A31969F5E73FB1F25FC75B75F5E5280C0 -:10F9A000EB1FCFFD6C28F14FE535E4E84549BFDD9D -:10F9B0008EC071AE63A9977504F5B98D1D849756F5 -:10F9C00060BFB2D3D5BE6583F0B7B98EA0229CC00C -:10F9D000F5A5154D76FE6EADA2A13A710CE9E326B0 -:10F9E000D563C77E79C3E952CA239417893A972A07 -:10F9F000BBA8BBABB28BBABBB9E9FEE7DC13F8EF2F -:10FA00000344D711583A7EB5E17BF83E56DF359373 -:10FA10000F37E17F4E0F354BFC6C68BB923986C4C3 -:10FA200034DD7F88E0EE7EFD450B7D8A5135E6D5DD -:10FA3000595482D6ECD679DE2D752DB5945636E024 -:10FA4000B7BB9D42EF9A8343D86FCDBFBE7A9BEA86 -:10FA5000836F8C25FBD5D5D236D612C1EF9D1B50B6 -:10FA60006FC7A1633598A41C6BDC2ACA22E9470939 -:10FA7000B9AE6A3E9A49F98B4E92E77C6ADF491E1D -:10FA8000816DC5DE33C923C99FD92F5A63BD4B4D44 -:10FA90002ACF03AD63D4ED4991F06D66F82E85C48D -:10FAA0003A001DA31617448ED7FCBFD60717853E14 -:10FAB000E888D207069E4216E0EF880387AD5CA770 -:10FAC00040F73FAE083A6A0305FD6EC2608AE476ED -:10FAD00032DD7B0F27974F83BBA9AF41584BA5FB66 -:10FAE000E9B02AEAFB86B0BE9F28F7BF490BB750A2 -:10FAF0003DF064795F3A05DA79DE0CE8E1D60B4E29 -:10FB0000FE0EBA183CDC4EB285E7535A2B3F14E286 -:10FB1000EF7BC2999AEB824D7E6F1D87DE7D78D395 -:10FB2000E082810F95EED5443D53EC796E1828FCA8 -:10FB3000BC9BBC420F914B41F5C09320C4F7F9D355 -:10FB4000A143DEEBC73FC7548C0BE91E6F3ABA31B5 -:10FB5000898C8F20CF9F46E751E39DA7633E931981 -:10FB60004A9D049F12CE347D67BFFE7374533528BF -:10FB7000E5BDEFEBE9FA7151DF3DA8A7E98DF7A9E3 -:10FB80007E59F17AB9BED943DF8D53FC13D63A7B47 -:10FB9000F55936C098812B72064EE8FB6E04FCC006 -:10FBA0007524B1DF8D447C27021723FE2E9251E786 -:10FBB000BB3BB848A73A9165E936FE7B3B85B6A1C9 -:10FBC000E329AF7928CD9F333083EA7DEB46F2629B -:10FBD0005A7002FBB992BFECE09D447850BCC6F766 -:10FBE0002BC07CD3FBF70B3281BF27B25BC5773EBE -:10FBF000DB911F6DA92C053AD55FC323253AF9D3B4 -:10FC00005B5C360F7D476C25B8ED7D70D7D8441D01 -:10FC1000488D4DD47918F572B178ADB119794E8F00 -:10FC20008DFDF198EF907E62F3DF42787A28A998F3 -:10FC3000FF0E53DE2BD3DC5C0F25BF7FAA4930F0CB -:10FC4000506CE3E77DF594EC67D6523D37C259938B -:10FC5000015CFF783469540AD565D5B4897AEE9A87 -:10FC60008C00EB77B35F617D5FD35AD24AF6E2B284 -:10FC7000C3C275DD352E51071FC880D0F37A343DDD -:10FC8000A619F4A0FB4B598F64D0655C3A94D07BE5 -:10FC9000E3C2DE91849342DBCB37D0FDC2B87074EF -:10FCA0007D19D26935D1A9F73B1ECDC9F51E067D58 -:10FCB000907198D99D92EE06BD9CC6DF23F06A51E3 -:10FCC0007F8FC0A0E3F644412F3355E00CE77775F2 -:10FCD0005A37964EFF1BE114C1BAB04B000000002A -:10FCE00000000000000000001F8B08000000000062 -:10FCF00000FFCB936560F8518FC0F9D20C0CDEBCCD -:10FD0000A862B4C40C5C0C0C41405C0EC41A407B6D -:10FD10006F01E9DB401CCECDC01001C4FB81F81F90 -:10FD200010FF07620D20D604E25F407945A81B5BF7 -:10FD3000981818DA80B80388BB805887918141975A -:10FD40009178FB93841918DE8923F87A120C0CCD74 -:10FD500052F4F3FF60C33156F4B5EF29D03E4E178D -:10FD6000043FC71998245C50D570BBE03783074D1A -:10FD70009E178DCF87477F9E212ABF5C0B953F4DF5 -:10FD80008781E123929A0A2DFC6E41C78A460C0CAA -:10FD90004A46C4ABDF608CCA0F3081D000F9ADB1E8 -:10FDA00009A803000000000000000000000000009F -:10FDB0001F8B08000000000000FFE57D097C54D582 -:10FDC000F5F07DF3969949662693900D0871028AA5 -:10FDD000A88013086940B4C322A2228E5BC50D26F9 -:10FDE00002D93710FDF0AFFD3210362DD6D0824645 -:10FDF0008B74C0A0C182040D1824E0002EF82FD50A -:10FE0000D8BF7B5B0C4AC31692801B7EB5E57FCEC4 -:10FE1000B9F725EF4D26806DBF5FFBFDBF69F1E6A9 -:10FE2000BC7BDF5DCE76CF3DF7DCFB14DB2896F89C -:10FE300063C6CEE00FD2AB2C8CB151DDE96CDBA0F8 -:10FE4000A187FA74E7FF5965D3EA87421EABD06EEB -:10FE50001ED6FD9CB185547E408C6B38BB1CD3F400 -:10FE6000101B0E8F6DC91696CCD87D6E46BF01094A -:10FE7000BE742991B1CE1556F7BA0C78AE7A5C08EB -:10FE8000DFF7C8207750C2F73CC95216E43FA2BA48 -:10FE9000D701CCBE3F23B36CC666DAE06F0FFCC35C -:10FEA0007AA0BE7CAC6C1063EA699905A07FEA7702 -:10FEB00012A5033436C3EF0078F92D6CDCD0EEFECA -:10FEC000B913FDEC7380B7E8F9897E5BC0907F09B8 -:10FED00093A8FFECFB4AAA5F6F6FF1F25B6C3E07E1 -:10FEE0003616948DCF3B967FE9C2E78B9B6EA17A45 -:10FEF00018532CD8CF72B7C84FFC5C6396EEFABB90 -:10FF0000F114A27674D8D304EDFE8831E9B5BFB6FA -:10FF100032C043D556D56305BC4CD8AA867F0C7039 -:10FF2000E95A2984B065979D31C04BFB6A0E879DC5 -:10FF30009A0FCB9FA80518AA28B736FFFC0AC4DB86 -:10FF40005699ADA366FC84F7561BC73B6BE4709EC5 -:10FF50009D83A56B774FC7F70B1AADCC0EF5956E49 -:10FF6000CF9F7A05C0F9FB5486454AD72FD0FA01B6 -:10FF70005C1892EA11EE18CFA8FDE03639B41ECA1B -:10FF800077B89A936F83F11FABB431CFC5D06F6749 -:10FF900073F2AD8087A2D09649F85ED146C98B2C0A -:10FFA0003461EBFA37FBC27BA51B24AF15F0525C22 -:10FFB00017CB3C43781FCEC0BFD60639FC63C89F21 -:10FFC0000BE3641948D7EA494CC6F657681E6737F1 -:10FFD0009E8E550E611E6B375CBA01DA81F7CA5EE0 -:10FFE00094BC38C4320B0B205FB66FB74F7BD68101 -:10FFF000E35BA00D76E2B8966A582E3F94BBCDEE37 -:020000022000DC -:10000000C1FEADD526417ED1EAB55A9E81FEC575A9 -:1000100097318FCDD0AF9A412946FE884C8F019BF6 -:1000200018FB53C498AF1EF94409693719E4A29F1D -:10003000144FF42EAE934DF50326194B82FF7E002C -:100040007F02BE823B9D84579D6E73051FE9743B02 -:1000500025E487299DD9C6FAF5F4E74807E84F75E6 -:10006000A59BD25F54A652BAB2D243F47902F107EB -:10007000E972D16FD758364E81765D3EE646314BF8 -:1000800098E21BA7029CE0E770F2DD01C97396F1CC -:10009000EBE9136A20176572159BE453FA02AC056D -:1000A000E6302FB4AFDCE89B389AB1D759E0711C29 -:1000B000FF222950807465AC3ED50F745922811EF1 -:1000C000017C2DC541021E96F4057E063A3D714F16 -:1000D000F6B3B224C69A8870DE738F66503D3554ED -:1000E0008F0AF50C3A773DC9D3734CF5244F2FD0C6 -:1000F000EB594BF5D8CFAF9E27A68F31F7677A9192 -:100100005ECF0B586E91F3FCC6953C63ACB93F33A0 -:100110004AA89E94BBBD2C00E5659D7F58B34F86D1 -:100120007CC7C6F8118F32231F8DDF86F53941AAAF -:100130008C7C1497136392A7785F8209EE33B99F82 -:10014000A97C927FA0293F65DAA5117CE970B75E92 -:100150002660E854385EA3FE6AFD34D23BE3FAD948 -:10016000087EA09F83F4CE03630217BBA1DFD8579C -:1001700006F47F400B5CEE8EC237302E89A562EA12 -:10018000B1601A99BF54E5781BDFFFFBC107E1FDA1 -:10019000724BE7E07880FF4B1AF7218EFB8FA84C5B -:1001A000816E3132ABC072315646FA6F6946F6B392 -:1001B00041035E970D007E91BAEB5DA60652911F3A -:1001C0005B821541E4CF253041B07E8C1D6415E182 -:1001D000E085F0FE80BC54C4BF5503FD616C5F83B5 -:1001E000F68752FBADD87E5B2FED5B07E698DAB75A -:1001F000A51798DAB769D03EC8476770BE681FF088 -:100200003786B1936C3EB56F4D2FA0F6976AACC0A0 -:10021000D47E4C57FBDF60BBDF63FB4951C63F70A8 -:100220008C79FCE945E6F16B7CFC6C4150B41F43D2 -:10023000E397A4201F7F7A111FBF95D7DBD5BEABF4 -:100240000BFF9A04ED3AA45EC63F68AC79FC1794A4 -:1002500098C76FE5EDBB172C13ED3BA8FD78691926 -:100260001FFF0525D4BE660D78918FB4FE31152190 -:100270009C4FD34080524807FA281D92C018E8933B -:10028000DFB2818487076238DF7D1303FCE6E8D69E -:10029000A72C041208F37099E0E9E28DE3343E3FA5 -:1002A00007695E9F2DBA3AAB51A6F98CADB4862E84 -:1002B00082FEB637CA418467ADBC3224D37C0A764D -:1002C00002BEA7B0303EFFF3AA61EB8CE38A4C6715 -:1002D00057ABAD2D06B9EAD2EFE3D9900AE85F0536 -:1002E00032C1A86EB815F434033DFC39E8634C0FF5 -:1002F000ABDC2E39047A9C5D6C949B05DC2E09B234 -:10030000F78740FF7F22FADFAA707CB7CE9342883E -:10031000FF6F56CCD1509FCDAE8E05A477F7A35C6E -:10032000D0A973BB3544F6144C07889FDB491419D8 -:10033000FBD3AE1BDE945C303FD6F431BD77370B78 -:100340002D4E85F23397E70E70C3F8EF9A661D21A4 -:10035000E3FCC47CFD2D24C7ACBF2587B1690D2B00 -:10036000D4FE00DC3E4DFDBCC5F0FE1D01337C57C4 -:1003700081196E5743AA05ED994289AD857AEFA997 -:1003800030E7EBED4C9612385D457B3F011CF48560 -:1003900047F7603A021FBB89AED3DDFC5DBD3FE588 -:1003A0000FA92C4CF3714B1223FA2751B9809B8F64 -:1003B0003BB2BFD3559BCF0FFD99FEA04CF88CEC00 -:1003C0007FCBAE589F05ECD9969A2F5564C1C8F1E2 -:1003D00044F67FC6FCC8F1B8359C1F728391CF39B3 -:1003E0009F44F25379E3B85F1E32F05369FDB5BF05 -:1003F0003C6478AFB8EE26135C18BAC3543EBF26EF -:10040000D7943FBBBAD0943F73D91C139C1B7CD0AC -:10041000547EC6FC05A6FC7B2A1E31E5DF55B0C222 -:1004200004DF1178CA54FEF6696B4DF9965D97DCCE -:10043000887254F581CC70DEF8DAD1FA73B437BF24 -:1004400076285EA4C711B057500E8E81BD82697B9D -:10045000E348B2AB410FE63130A1564BFB83CBC62C -:10046000A25E66A43F43D2EF83C134C69E973C840C -:100470003FB94663616061892574F171A76CC86FEB -:1004800039477E0D08FAC89EF9724BF4E7E5EB7226 -:100490002F40BDD39B3E805F7F9CE73A843D1099FF -:1004A0005F2231BFF1B9BE7EBA5CE27ABE44AC5382 -:1004B0004A5EEA3B9EB9100E0FAE385B7BF5805466 -:1004C000D49368FD27213F801418E8515C37C82475 -:1004D000DF6DBB65EA5719EA04D0AB99CCBF574230 -:1004E0003D13DE9B7ECB30EC87EF75D4FBAC3189BE -:1004F000E6F5B6CAC9BF3CA4227DFC941EA99C4661 -:10050000696B6580D2439505947E5E5941694BE5E0 -:100510007C4A0F540629FD63E5324A3FADACA6F490 -:10052000E3CA1A4A3FAC0C51DA5EE9A35497872E0E -:10053000FDEB17F6B058B7C0036E0F8BB12C82B22B -:10054000CD24E7DE5494F3538E6F06A3BD7FEA6398 -:1005500060A28CDEF115C96FBDD3D147F64A5E08A3 -:1005600098A74FCF7C7B0CA793DDC22633D0478F53 -:100570005CF49CF7DEA1042BC832C0A9DE9B9C5121 -:10058000EA85B90FE9752E3A315FE7705C67B73ECF -:10059000FD976CACF77269209F87F7CA340FB3F0F0 -:1005A000B35EA4D70FC59BF4DA9FD25BA0DC892E83 -:1005B000FC35A73348E7486EAAFF5483952988C7BE -:1005C000A6D8102E8D4FED7BD685F2383755AE3E2E -:1005D00034B2777C95D667543B0CE3296F34C3A7BC -:1005E000AAA5C9DC7FE089BB7518F295BBFAD04596 -:1005F00048FF544AF57AE6A66AD4CEB1BA41717C76 -:10060000FE0EF17970633CF12BAC3BA9FC3FBB3F84 -:10061000BDD5A3F787B106F6850DF501E40D3AF7D0 -:10062000FAA807DD95AF343FD2AB49FD06ED85183A -:10063000F8776620D6AB10ACD75B5E2F07AD97E39B -:10064000F38DA6F6E03D8FBEA6C7F77AE75B85B5CA -:10065000EAE3047D75A5F0E714D7D9ABCDF34ABC26 -:10066000092E6FEC5B6D9A67F00F907F562129C8B9 -:100670003F25829B3A14C73209FA976AF150BDE5CB -:10068000122F576A6BD1021E62C766B433EECDD10A -:10069000F9CF73FB1F40DF1FFDADCA1EC57CE1D73C -:1006A00051F56CB06F2DE8E711D0BD0DC55350EF7B -:1006B0001DDD763DD927B398DF858BA402569D8D2D -:1006C00076CE0966998CFC7F82FDDE35D2B0DEC81D -:1006D000B768D49F99CBCCF32CD8672638BFC60C0B -:1006E000E7B19B9391DFF356AA30B7A05C9AF36F02 -:1006F000B7B849BEF259C5125AEF083FD8BD6EA629 -:10070000F407B92F7DE599ECDCA1E887E0FA5BF707 -:100710000F1426703BA52831A4F920FF8B86913F4A -:10072000B982E1FBA125A8A7824EE65DCF7AD2EF80 -:1007300087F63FB2BFFA7CD2C34F21FA21D749BE18 -:10074000509475DAC31649D85B414A978B71EB76A2 -:100750006B4D045C1B01D747C07F37BF253213BFE9 -:10076000A55A02359624CE5F682F484AA716F84747 -:10077000EA4FED517FED3FB5FE34A83FDB547FFDDE -:100780003FB5FE0B7BF4BF295AFDA5AF6CDA16040A -:100790007D53B479958BC13C7454A94EF602DD4B60 -:1007A000D62F76211F1C51822EE4E7A321797234C3 -:1007B0007EF8D222FCA2CCE790705D857F42FDC717 -:1007C0005EF8D954B4E7BE59AFBA69BD54670D5B42 -:1007D000414ECB1A0AA7A0DF17E0831C5E7A52466F -:1007E000B8D1CC9F45CFAF4A46FF1E708A584F8480 -:1007F000C95E2AABFDF3249C87CA5927C959E47BFB -:10080000D8FEE904D28FB95A5CCF7CE827D9F9E544 -:10081000022FE50D3F3B29BB30BDF630EA13B04C4B -:10082000C80E8F7CAF40D841872CCEC4565842B1F9 -:100830001FB11FA1DED4F1C242DC0EAADAF0E4F04F -:1008400083D0AFB6DADFBA2403BE74793B553FF3E9 -:10085000D7AF7A7AD7CBED62BDD7FD5E88DEF334B1 -:100860000AFBAD89A7256AD885F671C95AD51B84BC -:10087000C7259B9E7DEE695CAF7E62F55E04F51731 -:100880006F7AE3C33100176F5113A7F06138A4E406 -:100890006EFA94C3BFF923BAE951F4F21B9A6718B0 -:1008A0007FFE7042375D8AB7ECD6D8B09EF898507C -:1008B000BF5B6B7144A14FFDC1496867556DF85628 -:1008C000C375E5D15D124BC98882CFB56F90BD80ED -:1008D00078227A0A7A75D12FA27C39D005F57A244C -:1008E000BD22CBBD81FA6514AF17FD93C0DF2FBECB -:1008F0008A7EEC4FAD5EC443C18BF7B9703C8795DF -:100900000ACEE7CF2C4E463F7D811A4C7653CA9FC4 -:1009100017ACB99FF82FFFBDFB93F9FAD0D7D74298 -:100920007355B02F8E73F6EADB689C792C407C58A7 -:10093000F08CEC0F41FAB5C2266F892227C5329799 -:1009400093C3EB80B830CEC3B84E41BFEEEFE5D0D5 -:100950007AF28FCC61A80FEED7FDF16C2EC15F8BC0 -:10096000FD8471B2455FE7DA4CFC5BBBB419E974F6 -:100970006C802F05FD6AE54C090A7C4867A05EF98A -:10098000BDAB53389D9847C916EF815D30019F6319 -:10099000F966D5671F6E7A8F9DC9E86E7F9E681FC6 -:1009A000FA1D83F3F9E16456501F657C35B2AE073A -:1009B000605E37F09941DEB9FCD73EC2E55D97FF36 -:1009C000D04D9331FFABF7B91CE17B385F42BFC21A -:1009D0002994BFFB5689F4839585A3C979AD2AE490 -:1009E000DC9C1FC92FD07F458A33F00DB69340742D -:1009F00020BF5ADE4A78DFA857B15D57CF7A7539E4 -:100A0000CE17FA204F067D7059B73E60ABB91EE88D -:100A1000DDEE0AF2F59B1A7AEE69945F90D7A00793 -:100A2000E557F5E3F88F6FDCFBE19D20B7C7EB7569 -:100A3000B935EBD548B92D7869BD847C1A29B7C77B -:100A40000BC04A8926B7F03CAADC16B4FC4BF4AACA -:100A50008EC7C765B35ED5F5646FF88CD49397CA1B -:100A60009EA87A127EEFB3EC9EFCA8F3A1CE7F4540 -:100A7000BF29BD80FC093A9FEA7CD8C5A73A1FF67A -:100A8000F0CF98F018997F3BF2040CC1BF5D257F31 -:100A9000624913DF8F83F7DEEC9F45F8F2D134C74C -:100AA000AADFEC9F68844311707D44795F04EC8F6A -:100AB000281F88802B4CE54B1AF76A8CF8206C2A8B -:100AC000679DFF2BF6459475AC3E0F95379CD482FD -:100AD000C81F699D1AEA3F752198A8E83FDC299351 -:100AE000FFB00370BC04DAE9D898110A821E596C71 -:100AF000E7EBCD0E77A72B01D2C5F11CEE4CD296B9 -:100B0000A01ED49F77DAB91FA4C3DFE98A37F83172 -:100B10000E36C9A4C75B426C72343F09CC3484DF03 -:100B200016D65B3EF78F76E0BE33B687FBCE40CF5E -:100B3000AB6547FA7C5CBF56CB5E6023366BC1ED7C -:100B40002E74A177340DBA711A3C9FFDB6CCB76DE7 -:100B5000823EA5AF61DD7184059F182BE17EDE72B8 -:100B6000E29F994D7C1D326B7974792812EFE5393B -:100B7000E669A87761FDF0B9D10FACD753B03AE27E -:100B800079D3F5426EAA693D58546BCE0F88F5D4DF -:100B900037BAFEC96499A47F70A184EB7AA1B7AF7C -:100BA0009687DE380DE8D3B14F66B8BF7AAA4926DA -:100BB000FA9CDAC8F753593089E4AF8C7592BED4E9 -:100BC000F1D686F27571EF7AAC6DEB9FB21F423EA3 -:100BD000DAF687E1BF82B46DDB27837720FCCA4752 -:100BE000E97F603DCB4FD865273F73C72E27F17F44 -:100BF000C7CEDFA53F84F0762BF9F73A767D3B1C14 -:100C0000F9B163A1B500F560C700BE7EAADAF9EDBF -:100C1000F0169A7F17111D33148DE87DAAE92F076E -:100C2000302EE054138C0AED8B5DB1245FE5AFDA12 -:100C3000C91FD1B1F3DBEC80E39F379E32B1FFD304 -:100C4000E164D35EC2FEC573BF79F98ED1CF2EC0E9 -:100C5000FDF186DDDA4CC89FF0DA5F87A37EED7880 -:100C600089DB4DED6ACB1ADCDF18BA485EA802BDFD -:100C7000DA51C8FA31B66FD1C4F128473DF1F257C5 -:100C8000F2B39C2F3E26287C3DFBEF8F0FC9C7F5A2 -:100C90009F33649370DCDF1DF803EA895D56E24BF5 -:100CA0007DBCC7EB17903D73AE71DFFB3F6EDC522E -:100CB000F87CC6BDE0DF9CFFAD8A87FA1729073DA7 -:100CC000F97CE703046F727AA9BFE7C9EF6BFFA74E -:100CD000D1FD25A0BBEBDCE30EFF3F4BF7B7A70B25 -:100CE000BABB313EA0FCB5BF52FF7EA89E6BF93760 -:100CF000A77B6FE3D7EDFDB72C9EF733A1FC6456BD -:100D0000ED40C3E2DAD23D6F6742EE5B697BE3B14F -:100D1000BFE323F67BF4345EE5FEB6F1B8EF03EDF6 -:100D2000B27849AC17F93AABBFB02FFACFCB233B1F -:100D3000A47FDA63644F30C5B312F72BDF4A9FE913 -:100D4000A5D80B36E2E300C2EE2B056C5E6FFE4ABF -:100D5000623EDC4AED9F7EFD3EB473D3D264B28323 -:100D60002125FBF775D764FEBC4433AD87AEF598FB -:100D7000D7479312CDEBA889A2BEAB19EFFFD50ED2 -:100D80002914023C8C1FF0CB44F4A78EBF48651297 -:100D9000C093586011AE3B263ACCF59DC07D6C8364 -:100DA000BFF1EFC5E3C42E3C0E5CE9473C0E90C991 -:100DB000AF7A4E3C62BF096F99218CC7618A97E375 -:100DC00031A1D44B7E6AB11EC76EA21DA3389634E2 -:100DD000A33C2BB89EE678A075B8BE9EEE0DDF4C06 -:100DE000ACCF15D1A48E7F254DF6D9CDF5D1FA5CC7 -:100DF000A7CB0FA5874EC77F942EC9AA992E698EBF -:100E0000390ACAEB645C3F8CC4F2991C4E0B2AB4BD -:100E1000DF24D60FD778E628418027A4652A48AF7B -:100E20007CDBF6228C1FB57925EAC7C56D169A1FA3 -:100E30006C5912E17D488D42F07B16F728A4F7D457 -:100E40002B5E39FE20433FBB4FE306BA9FEF977CF2 -:100E50007FE6CCD86CF4C7F01FC67FDE00EBB75935 -:100E6000AB593806F0345B61C1B804F4934BEC73B2 -:100E7000939FDC0CE3EFAAE4EE7ACE55BE37BDF2C9 -:100E8000CF4E5F013DF6F9458C6DC7946F8A28C639 -:100E9000F5F68F9A38BECAF7B3D0401E8721FB0DF6 -:100EA000FB8A2FABDC3FF3CA1F5F1A89EBDC711D95 -:100EB00043E3B87ECDE271A962BD708A79E2BC0ECF -:100EC000D4AF83E268BF749FEC8C16E7B841ACBF27 -:100ED0007F83F1289076D4B26A19D757AC93FCBEC1 -:100EE000C15A1B5B1F251E668D6A117E224137F891 -:100EF000C9D9B87FC3DB9F0DAFC619E9D636E5A8BF -:100F000032BC271DF0F7B961FFEA1FC52FAEF711FC -:100F1000BF1BEC2D93FC51F447BDC0DFD43DDF91E6 -:100F20009FF4D2A6B516E4DF4B6B2DA6FDD83A553B -:100F3000F83146B011D8AFA97BECCE2CA4CB3ED96A -:100F40008BF1A5E54D27B540947DC4487C62FDE852 -:100F50007F6F55DDD4EE0EB57E26E275C7091BC343 -:100F600075F576ADBA385A3FEFB4F27ECE66F5F736 -:100F70000DCFF8F7C3EFB80E47783CAE3F6B99F052 -:100F80008344F21F233E3E55C74238BFE27A15F52F -:100F9000C2A98D8CE67740C963B8FE0679FFB1D14E -:100FA000AF7371E396DFA05D50D624B9714BA24CAC -:100FB00069D1D08F5BDE182FE33C9CE9D1E36FDD74 -:100FC000C36E35C845ABAA10BEF68ED97117B6FBF5 -:100FD000659BC6D04EF1BDDEE9C279FCCBA691245B -:100FE00007BD8DEBE54A563411E31C843E8CE48743 -:100FF000A11B634CF01572A01FCAD7546BCB3C6F7A -:1010000014FA2DD324B18F789EFA2DF4FF997E7BAC -:101010005FD76F01D96F9023BFC09B41BFA544D359 -:101020006F73254F0AE27DEECE412948D7B96FABE9 -:1010300049D1F4DBA64ABE2FBA59C44D7734807E1D -:10104000BBDCA0DF1A40BF45891F19A3E97EFA73F4 -:10105000E8B7D0BF46FE36A17E8B32DE1B04FE749D -:10106000FD36BCE920E9B7E10D16533CF0444DF8DC -:101070009B7AD56F52D2AD681FEF53BDB151F8675F -:1010800093B0C7378B38466C07F55C95F6C3F45CB4 -:10109000DEF9EAB97F119E753D37772BA3B8E89E3C -:1010A0007CC8F5DCDCEDA0E724E447AEE7E6EE64BF -:1010B000DC2F17A1DF86F4D06F8CCA9785F9FBE58A -:1010C0008D194FDE0DF58DF0A95E1B941FD1ADEF8C -:1010D0004619F55D95D68BBEDB777EFA6EABD07781 -:1010E000A0C706A27E8DE40F6F9339DE7CC7E8C3EC -:1010F0001B5F4679F99D4CFB92EF59F8FED13BA35B -:101100000F67217F7D2AFAF3A2C6E9D95E19A4FAF6 -:1011100027BCCEC757BA91FBCBCB1AB87D58562BFC -:10112000873CF0E7A431DF69D8FFC29D124B01F87C -:10113000266BF5130EB4EB9F5799581F4DC934F029 -:10114000C3AC9C62F2FB57D95DEBF0FCD12C85D986 -:10115000D0BF5FEC987414EDE0E21CBE1F502C9ED3 -:10116000EB71B0B3BBF464443C48E39C37FBB39EE3 -:10117000711653AD9CAE539F954218B7DA33EE22E9 -:10118000447AA1B8CEFCFC5D217F37C92D842FF6AF -:10119000AE1C35EE432FD785A77D024F8017139ED7 -:1011A0004252543C01A5A7642677E3A5F0772D4B66 -:1011B000705FA0F02989F69123C7ADE32D72FC3A48 -:1011C0001E753F77B1A82FBF692D9D6B8AC48B8E8A -:1011D000E7487C74E13D021FEF695D7EED9118D711 -:1011E000047C437A26F89F801768C73FEE22D3F924 -:1011F0009B8F045E46568F9B80E10F37611C3AE45B -:10120000E7D5CC79B32FE063D4C79E11389D5E310A -:10121000C61AC07DDA0DF64ED2833A1F0EB3723E67 -:10122000D4845ED9D1AF623CADF31B2537DA21E51A -:10123000613BE1B51CF8D10E45F63EF5CD24815752 -:10124000379DAF6A14F313D0C182EB267DBE0AF13D -:10125000F358239B385DCAEB385DB25827EDC7942D -:10126000D548DE308CA7AC710EC5A1EBFA197E0E05 -:10127000239DA2F0AF128D7F193A9BB3BBE7CD62DD -:10128000516EAAB5FA43DCE7990AF2B196D810FE7E -:101290007716FE3E57FC5024BD2E1378DB847875FC -:1012A00020FE3AB9FD15FE8ECE69E9F9E54AD084F3 -:1012B000D7094F9FE6FCB753F2A05FAC0B6FC8CFC6 -:1012C000903F4AC71BF233D2A1295746380FF0DDB1 -:1012D00027A3E77871BFD428F7853B0FF2FA9F91D7 -:1012E000BC2CCAB87F307FFF40BEEE4DDE8759C5AB -:1012F0003A41F0F73BF6CEFD2391BF774ADC2FD180 -:10130000146FDAF7BCC1CAD74D1BEC2007B8DFF663 -:10131000B6EA5DE7E9A91FAEB27239C0F584C7E04D -:10132000F7BA040782F1A675368A17A47E0CE4F694 -:10133000AA515F6FB2B3A45BB37AAF7F8AA8BF37FD -:101340007B498787617BA8471BA1BD21DDED45CE89 -:1013500017BAFFE05CE3BA43F0CFDF3B2EBD9D1F21 -:101360001A4F55CE9A695F4C8FAB4AB5045E51D186 -:10137000BE9B2C99E2B7A0E782CEFF70FDB76AA3AF -:101380007AAF9FA5DAC88ED0CFCB5E2D3B5810F038 -:10139000F6A54F2579012BE383B1387F8C8779102F -:1013A000922FF78FFAE86ECA97699FEDC6DFF5298D -:1013B000C57DC81B790C1DBB315322FBE13DAC6CD4 -:1013C00034DAE136E6B38A26213FE747F1213CD7FC -:1013D00092595B3DC103723DA22E5485A9774267A5 -:1013E000E23B48AF7132437A35FBFA4CC0F9F7BEA5 -:1013F0003FB34CDC8A073B81EA19B18F2561B931D3 -:10140000BE245ACE8C6EF8EAFD5BA07FA3F7CB5EBC -:101410000F94BB69AFC381723664B585050C78192A -:10142000C34255E8771A7DC8770BEA8302B07BF098 -:101430007C4941D3DA2A17C2AB257ABF3C1898E41D -:1014400082FE6DAA3939E932D40B500EAB295FCD3B -:10145000CB95D74A5E0C71CE6B5A41F14879B512E3 -:101460001D60DC1492988DD71BB241BD9B56C3FB07 -:1014700059387FC1FB586FEDC9F76F41BD03FDA41B -:10148000F737F2FDFA3C78CF8372523B87EA2B5C48 -:101490002D313C0753B091CF4F05FB552FE637EC6C -:1014A0007E8AE6DD29D05EDF0C9C8FC213E93CD139 -:1014B00048C94DE7381FBE80F456070E185FF0A5E7 -:1014C000F3F80949C062FDA3DB7FFD6DFC5C539E10 -:1014D0007781D607EA79272729C342FC7492F6E17F -:1014E0000F01BE03569C37793CCBDE9C2FB416C34C -:1014F000FC98631B44EFCF6A1C47711EB3999FE2AF -:101500003CA68EE676E7BB57DA43E8EF7B57ED4C17 -:10151000C3E77BAFB4D2F3F64D5C0FB70F6821BFC2 -:10152000FBE1D52AC3F32F55AB65D2138737AA74D5 -:101530006E577E86C737E46FE276C8DED5BCDEC361 -:1015400075DC7E9BF0CC6D93701ECE5FCFCFF9EA39 -:101550007A5A5F87E6B90B4DF35BA49ED5F570A967 -:10156000C04741F55ADA4F8FD4BBA5FA7C18A16F5A -:101570004B719F9DF6D3C32447A5F591F1658E6EFF -:10158000BF0DF243F83BE2EFB2FD2AC3758DF4457F -:10159000DB248A67C3F91EF24737493E8C7B28F863 -:1015A000D81A227B3C943BE33F709EF9C4CAF0C832 -:1015B000482BD203F4548EB5F38FBF84E747DFB3D3 -:1015C00061E410F04F2EE15F8F13CE5ACFE37EB26D -:1015D000DE5B998CE78DD9C43EA407F26B641630AC -:1015E000E88DA392EF963BF9FCE046FB47A76B968C -:1015F000569D87F36C918DEB47CF7A95CE8BC70BB9 -:1016000018D60B3EB4770AB7AF48D60CFC50B87367 -:101610004532A80EB644C4CB548973E6851A6FA729 -:101620007097E45E6B6847AF47AF57DBCEDF1BB404 -:1016300093A7BDD55F88FDA3717EADA1DE88ACA761 -:1016400047FBBDD493F35FA757E2B9FF9C77650AC8 -:1016500076CFF962CA20E33E8F9EEA7EE6ECF72D54 -:10166000CC67C05FCE1F6398CF40EF865120FF400C -:10167000BF1B1AB93DD730EAA0569A45B01BE5BD4D -:101680004CF8A3CB26F2FDBB86CCF716A1FC4FC9C4 -:1016900092881F5830A0F54924FBCD83FB00F959EF -:1016A000FCFD7C781FE5B2E1292EA7A02F3CA84FB6 -:1016B000CA56AF9844E56B250FD6DFB03697EC924B -:1016C000821C99517EED41B2930A1A0F26A23C83E7 -:1016D000FCAE447BA06CACD58DEA58974B5DCEDF59 -:1016E00015E76199CD3D0CCF77E0765834F996F740 -:1016F0003361B772B92CCFE172FBEE261547783E05 -:10170000724E72ADCBB18C729CD52DC77B574FD02A -:1017100050AE0F87248AA399807A00E57C831EE768 -:10172000C4EDD8F395F373D999A520BF385FEA7259 -:10173000AECB75A43C372B2DB7623FEEBBD24EE348 -:101740009870D5F60FEFE3FA8AF65F275CF5603202 -:10175000EAC73C85C779E9782D55785C608F7EAD06 -:101760005CA0F53D9FFE45F4E333ABD95F126F8B70 -:10177000E7F1EFB52AF1FDB9E4B3879C9DA77C9E04 -:10178000AF5C9D4B3EF5F6E59DE67AE2916947F543 -:10179000ACAF1DF018063CBEB5F1598A0F3EF1C240 -:1017A000C1A94887E21DC0E7C85F1B9D2C8C7A4EFB -:1017B00009D1BC55D420D33903A684B36F711AE57F -:1017C00098C775156F76123F15BD640D4D81F78B67 -:1017D000B67D319CE26A167652DC5AF005612F071D -:1017E0005B86A31C14293CBE2C522FFCDAC6EDE705 -:1017F000B6EDB1D3707C521DBFDFA2A8FE76D56ACC -:10180000D8A778C2A652BB508EF67983C0C778FE9F -:1018100017FB67BC57418F2B6BDBC0F54451A31AF4 -:10182000C27B328AEAB6B463BC71D1C756F27F95E7 -:10183000D79DA4F31413366F22FF4A79A36CDA8F75 -:10184000EB11DF592787AD1897D8504AFB90001F3E -:1018500024B85EC453FEC0F8C3E2CD3BB705018592 -:10186000C52F3FEF42FD72AC79BD0BF10EF59E35F1 -:10187000DEBA473C67FD23229EF386C3746F4B2F6D -:10188000F19CC7F00F1094B76DE6784E56D787ECF1 -:101890004BE867B63FCAFE47977DBEE9EB35781E39 -:1018A000A1EDA5E36BB0DF257FFB720DC689B15DAD -:1018B000769AF7CA5FF880E2B7F5F7BEB0097FC83D -:1018C00086E729FEBDFD13AB176B6BDF79381DE38F -:1018D00006DBB77C978CFECC793BAF267FEFBCADA7 -:1018E0001352589479434F917F43E7117F1F49B7B3 -:1018F000BD0D7B299EED04D01DF560579C6E7D29A2 -:101900008F7FF688F8DC8DD1CF3BF488C76DB8E5C2 -:10191000C62B51FF37707BF29C71B9EF033D2F3F0F -:101920000F3A6E14F1D7F5379C352EF704FE01F40B -:10193000B2D8CD74FCBA61F6AF9FC6BC863EBDC6B8 -:10194000E586CF037FFA798A776C3EA71DE5E8A587 -:10195000DF503C34D26F8A07E7A3AFD3F13CCA1102 -:10196000B5733ACE3F9D3BAD74DF4FD1CE8F489ECD -:10197000DAB7BE477E6A26CE35B4B3AE1F8F3F9727 -:10198000C4786B9D3C9E57D001E37D3D2E7A2EE2BC -:101990007A395FEBF1BEBDC5F95E6D1F28EE0FE031 -:1019A000F1C8A5B57F10F1B3DD749372905E07CFD7 -:1019B0001A47ADE3C12DF472771C7BF4B8EAAE3858 -:1019C000F608BA213D719EEA8A5307386D04F94939 -:1019D0003E8A762EA27D2D8F7F6F57A39F37D6E349 -:1019E000DA7D11F4D6C7DB9BBCE8727BAE71FC508C -:1019F0003CD16642524F7CB57D1F5DBFCFB44B7F5B -:101A0000D7FABEEBBC548914791EEB5EE4CBD286C8 -:101A100083E4CFEC5A7F8BF1B609FF7BDB0B32C539 -:101A2000392FA9DF4BFA3D527F94E1BD2D51FA7B4E -:101A3000BF5DD8E78D7CFE687BC91972403D6D7B28 -:101A4000B6135F976D3C4871D66FD6BDACB518E242 -:101A50002770FE0819C6D3F6E2EEE1A4CFC5FD302B -:101A600091ED548976CA9BA2B753BEF1A4A99DE219 -:101A700060BDE6769CBBBD638AEF76ACEF5833B7AA -:101A8000138FD5CB9343D1F669ECAAD8EFAFE629F3 -:101A9000CCA3740F8E93DF7B23BB62C8EE9CE7CC94 -:101AA000F9382E11538DE2BAAA168838B09F7A53AE -:101AB00091DE55CEEB18F67731E2D7E0FF51DD012C -:101AC00086F6AA9AEACF42BF43A4DED1122D2C6437 -:101AD000A0F73CE7E4140FED8B84D3909E07320F00 -:101AE000AB58EF6711FEABCF14B62405FAF7595087 -:101AF000F22E807AD9F75F0CF03B7BD6AFC381879B -:101B00006593BFA9CCDA7900D72BEC353BED47C8FC -:101B1000BBEC747F48F91A3B8D77EFD66F9F23BBE0 -:101B2000FBD756C6F787605583F796B9791D87B7F7 -:101B30007EBBE62F6857E3CBD07EFE1A288FEB8959 -:101B40008DB1B4FEE978298EEE51CB7FEDA1A9A825 -:101B5000D7F263393FE66F4E0955417DAD491C6EA2 -:101B6000DD3480EEAB287EC949F1A57BB7BE528635 -:101B7000F354FBE6580C3360EDAF09FBFF37E27E10 -:101B8000AD1AD5638C332F648AC7782EA818615399 -:101B90005C13233F06C911FAB11AE3E83C11D8C51A -:101BA000A67A4EA89D0F78898F83FDF839AA703FD9 -:101BB000D40791E5F4FCFD767E8EBDDC0AEF39BAE0 -:101BC000CB976B9D791CAEEEC7F5493395FF44E783 -:101BD0007391DFB35E5EFE23BDDEAE7AF8FB65E295 -:101BE0007E9B48FE3DD4A557FE7A71B4FB5BA2F400 -:101BF0009F9EDF2FB1A005ED962D76BAB70BEF674C -:101C0000C0730EDB34BEFF55E20AD3FD393B843E80 -:101C10002E8909D37D3EFD443FB03CC2CCD6F22292 -:101C2000D2BDF4153BC3F8B3D2D79C3EA477E9B636 -:101C30006F5B7F9585F18BB1E4D72B7DED7F111F15 -:101C4000945AC3D3E9FEBC2D5686F7E7B56D793BB0 -:101C50001DE5B54D0DA7279C655FAFB4DE6ABE5785 -:101C6000408CE35865E842BC77413FAF5BD48B9E24 -:101C7000B93286DBD7F6189F3586E4DD7C4FD4B1C8 -:101C8000CAC641C6F3FB459EE87AB17F8CFA8F9DA8 -:101C90004377F438F7DA3F2609ED99E66474409605 -:101CA000813D8EFABCA8EEE430F41F7C16A3DF6FF2 -:101CB000E089C3F9E833AD7318EABFCFD23B871987 -:101CC000E7992395368FA2925F87D28EB527F3FAD4 -:101CD000318C37B54F8BA6F786C5C412FE8A1E8E8F -:101CE0008D7A8E7A4C0CE7AB34681F536C17E54342 -:101CF0006FF7332D447AB831C6C3EB490B69F8BC92 -:101D0000B86EFB20231E0A956A2A07724AF82C64D3 -:101D10002BB52C83FED6DB2B9CEFF028743F81F291 -:101D20007FBAF855EEA6333991318E51E014665CD6 -:101D3000F233EBE74814D56F43FC69CCEF5664648B -:101D4000956A92F718564FA903CC2E7E5F5A054329 -:101D50003D7944ECEFA31F0CD36E7C3D487A3F38AD -:101D600080B18B32F0BE094F9CDB80BF6B70B33EFD -:101D700009E3692B18D71753DC688F48C1003B0370 -:101D8000FC5455593788DF03C27C182F49262CF4A0 -:101D9000CFE57EF33BB483804FF93D8457B15015B6 -:101DA000A018C386C9EF3A9EF1FBF3967DCC8CEB6D -:101DB0008F12410716DC4D7ACCC1BA7F9D00A35A21 -:101DC000457D5B15F7B71CDC9F73B85918EDC358F8 -:101DD000070BC742EA18AA1C33CABF2B0B60035F6C -:101DE000BAC79AF323E502F45A44BBF5843FA8F737 -:101DF000AB887ABF8AA8F7ABB3D5ABE3A9DC3628AA -:101E000003EFA5585C592FF0C6DBB309BC017E86F1 -:101E1000E03D7FCC12E315FBE684D718D11B2B964F -:101E200007BA6E8EC9207EFA59DCAE4E8C97668951 -:101E3000350CD7C38B24FDBE4FE67718DE636E1BCF -:101E4000C9E123A29DCD02CF8B74BF558FF276B22C -:101E5000BF7A94B7F7563E267A79676FFD898DDE93 -:101E60009FF85EEAAF8E8D5AFF0FD54B65AF7DF4BC -:101E70000EEEEF76E92737A0DE6C676E46FD541A4A -:101E8000DFFAB7167AC2ED4C5B9A99DE31C8DFC033 -:101E90006F31179A9F47F24914FE72F48571DF295A -:101EA000DABBF3617E5E4DE7835C31BE89B57C9F12 -:101EB000FCEE79DC8F07CB461FE6DF25F2EFAEE1C3 -:101EC000F6E3DD0FCBB40F1B79BFD5C1FFCDEFE13A -:101ED000B8071F80BCDD335F0A8533A2DDDBC5DEBA -:101EE0008F877A6788FE44DE8315609E49CBE4685D -:101EF000F76071BED4CFE145DE7F318BF9C5FD6659 -:101F0000E6E759316EE2DB2225A4550FED9EC7822C -:101F10002B80EFD1FE04BEC7FD2F599CC7662E8DC6 -:101F2000C7D7DF9A60D27FA78678E270BE66AF8B94 -:101F3000E76EFE7CEEB59E14E37945E574ACE91ED0 -:101F4000A02AD59B8AFA4D3D7D3DF3801C6AA707E8 -:101F5000318F211FEC56127E0CF3243D95AA84503C -:101F60002F2A6E3FCB47BB379EF3B35E5E4BBCAEB2 -:101F7000CBCE7C17FE1D46E681FFCF5DE1A1F3DFEE -:101F80005739FCA771FE955D39DE80A3273F04B762 -:101F9000F27157E1B8337A8EA74AF37AC9DEBE0EE2 -:101FA000E645F2CB796DD83FD9EAF9C883FDFBADA0 -:101FB000CAD00FD3133FDE2321C83F15EA4F712447 -:101FC00072DC94C1D8FE72BC6F14F4FF3271BFE8AA -:101FD000A24A26521E57B708EF1FA53447A43E91C8 -:101FE0004EA6728F8A7B4A97547A29D5F16BF356A5 -:101FF000D33D98B60B79FB36B7A05FA245E02F40E2 -:10200000F6972DB582F61DEDEE8A30DE27C7D26039 -:10201000DEC161B9AB09BF9A9B91BF13CA136C456E -:102020001852B5660AD1497157B07CC84F7504067D -:10203000C7A27DE331DF87694D1D71D6FB31BBF847 -:102040006D13C7FB6312E7B748BC3FA6367B306E03 -:10205000E2B16BBBEEAB22BCC37288E3FD3FF97EFD -:102060006E4FBC374F9B69C0BB337B32E1FD6702CB -:10207000CF4B055EAB041DAA043EABC4BDAF55E219 -:10208000DEDC2A81DF2AC43BA48F887B7B17233DBB -:10209000209511EFC0BFD6A14126437B7C0F0F5284 -:1020A00087E05BB785FCA4B2C3EF43BC5B1339DEAA -:1020B0006D0EA003F135E0DD83F941C2A7EAE078B7 -:1020C00086F29C0E025610EF23F139A707E0FDB609 -:1020D000D824D487634C78D612C79F1FDE9FE2F3C3 -:1020E0005BA290F348FC256AFC5E605DBE7BB38F0B -:1020F000AB445C7695B89711F18876CD2AC00FBBBA -:1021000098E3933F1F22602FA54962FD5F0574C0CD -:10211000FC27853D8478C674672C5FB7245A2A76DD -:10212000AB88A7047EDF0F4B0CB2B46CC64380F1C2 -:10213000971A641E84F5FDE15A33FFC86E25E27ECE -:1021400049CF93C86F2BDF562DB87F2FCFBFDE74DA -:10215000AE5B9EE68BF710FE0312DA353F1372B8C2 -:1021600002F985FAC7D7C38B051F2C15F7063F2246 -:10217000F8E73121CF8FEB7CE3E5E748964FE6F1B6 -:102180008E89991671BF629819E309E3BDF54C83F6 -:102190007ED1DAC64329DD9FC93EB692DCC60E6504 -:1021A0003EE4AFF88F1F0CF1FB70FD7DD11E8AD786 -:1021B000EFBF1DEB89BF830EB4871571CFA4CCD7B9 -:1021C00093CD51EF8DADF2EEB1A15FA6B7FEECBE9F -:1021D000691BF173DEE5441ED627E0BF6336C08E6F -:1021E0001A5857C12FD61BC85E8C7AA5C649FCEB7E -:1021F00080FEE71BF824B617FFCE54C7B51B505F0F -:10220000BC80062430C12F6A06D911CF80730FFA23 -:10221000B156A9FEBE382FAC8A8FEE8FFB652CDF3E -:102220008770655D6AF22BAC547DF49E7BAC59EFF0 -:10223000AC14F344C244B39CE8F3C24F457D573914 -:10224000023BB15FC9A727923C27DE1C7D9EA852A6 -:10225000B520DEF751358CCB773057E3F6730FFDA1 -:10226000C3689FE45460F03AF483E97CB690717DD2 -:102270001764DCAED4C7F504F2BD15E70337F13FB0 -:10228000CE0708CB176AFCDEE3BB2DE4875822E4B7 -:10229000ED512167CB857CFD1CE5CB8AF7587B2966 -:1022A000FD8590AB952887901E8FCDE0F6BCB83F9A -:1022B0004C5FCF2CB48DA0FB22AB1C169A17944F09 -:1022C000AC2107AE0F768F76A3FF477666B9034E33 -:1022D000CCCFA2FBDCA5F82C37F2CD37CE59179C1A -:1022E0002D1E16C84FF7162B2AF74BEAF7C8578949 -:1022F000FB0854F7CD0CFDD54F2656D829DE359670 -:10230000C787D7E46613DE811E9DB186755ACAB4AD -:10231000EBBAEEFBC3EA9FECE55E83EF85DE606916 -:102320004176A1414FD488FB249927C88618F4C56B -:10233000C28B2631F4EFF5D413BDE8CDF55C6F2EDA -:1023400092A2EB4DDD8ED7F566A47ED1D3C5174C96 -:10235000369DBF541D5E467A6748743F42B2C3CA79 -:10236000F72F99D79B9BD1331FF095EC30E00BED05 -:1023700021DD6FF1E328E389D49347AED3E7D7009B -:10238000DD3B344BF33C39FAACF3AB795EC83FFD2F -:1023900008CD4F79A747535A50732DD9230C77692D -:1023A0000CF72E1C5E7DBF0BE97BB846EC9FAF5649 -:1023B0004318BF74B8667119C1D5760FD266DC2F89 -:1023C0001E74E13D4DB3D6C8B49F7E2426984EF1CD -:1023D0009FDF9F39231BE26316AC5D9A8EFC386B3E -:1023E000DD523A377B24C137D86F80599687EC7914 -:1023F000FDFEC6BC67AD3EB4C77BE3DBBCD5D1FDFB -:102400003D55F827AE53987708AE4376BBC6748621 -:10241000810F8EFCC24EEB822A2DD88E70D5BA5811 -:102420007C83552544BF0F28D571B50FE994EAF098 -:102430005D8B297324D07E4FEF72C4DB6F455F3B09 -:10244000EEBB3E2DEE45023ADD64F2BBF27DD7567F -:10245000E14763B65EF26344BEA7977C178F936231 -:10246000EEE8F97FB7FF69688FF55D318EBFB4E69E -:10247000F8924FE889791FA150C48BCF5A171B5A85 -:102480001845CE6689F3C7B3C47E99CE8F85D7EB46 -:10249000F639E7E3483E975EB884F8FACB7D2ACD5B -:1024A0006B65C0AFA8EFA51746D37D500B9EBBE26E -:1024B000718C0BFC6ABF4CF925A7EDC4C7ED3FF545 -:1024C000D23982CEDFA9F49D88AFF65D4DE701DAFF -:1024D000C5FDD33A9ED29C7C3DBCC6C1F550DEE919 -:1024E0009F913C74F15768A686729E77FAE75C5E0E -:1024F000F0FED93138ECEBDE1C77A1E06B80D72CF5 -:102500009F346921D49BDFC2E58A8D0D96911F7B94 -:102510006DACF7D128F2BFC6E131F9B5F25B96F3A5 -:10252000F7C0AE4C34C499CC12DF7BC83FCDEF6509 -:1025300065EE204B457912FAB05B0ECCF772B7DB33 -:10254000CDE3D4D317BBC6798569FDD63DCEABE8C4 -:10255000799EB053F25B4613DC3D9E5F8D8E369EB6 -:10256000EE718CA5F2EDF1D1DBFF50B4DF5A59C00A -:102570007CA04F8BC4FDBF79A1FB34D41F79ABE3A2 -:102580001324C3B8F26B8A4DF14F7935B974DF5F0C -:10259000FEEA5CED5E83BC76D185CD36D1E543475E -:1025A00080E832D5E1DFE340B97CA1F0814F3D58AE -:1025B0002FA7D3112D38BC82F4DB7DAE68E7A73E90 -:1025C0008CA4538DA013AC1FB20C74D2E913F97E06 -:1025D000EBFAD2073EC5FD8BA7F8ED45BDEBB10880 -:1025E000FA6544C75FA783F36B2BD80F81F3C2DF73 -:1025F00065A6F8BB5EF127E8ADE3477F0EF6DF5135 -:1026000094FB4E94CD51581FE78773E1ADBB7DC15C -:102610000FE3A28F27C5A9F3C37C1604013EAA715C -:10262000FBA3F7F13CC482B6F3184F979C2E36F10A -:10263000438A7301975341FFA37B1E21BE6E0DC5D4 -:102640007AED19BD8F27C5D90B1F5C186443B3FF02 -:10265000EFF1C111CD37F8299C4760DEC279BDF09A -:10266000F9C7861BFB97EA1897E6C479A9FAFCF626 -:10267000B783E3BDFB701D1E5C277BAB6048258ED6 -:10268000C0607CBFC8F5F437E8DF5B14FFC4F068B6 -:1026900076F4E2CA7D97A0DFB5AAB2995255D8C5A3 -:1026A0000CEDE20CFE5D8F68F7055E2BF4EBE2CAE1 -:1026B00066EEB7B50599DB70CF003B3292FCD88A45 -:1026C000C36CCF696AC08D7E734DDC83A02A81659F -:1026D0001959E8674ACC0C1AF0778D93EFD72C4F35 -:1026E000DDE3C6FD102BD48FFE335B9A72CAE4770C -:1026F0007B5D99E5043AE9D744C7B07A9F24911FDE -:10270000F254841FF294A91F89CDA67D8A48BC2863 -:1027100036FE1D288509FFB3C087FE9DA4A56E3E29 -:10272000CE95C28FFD04FAAF2F023B36D645F6C1D7 -:10273000920B2C7C7D6853E8BE2B6B3C2FAFC5F110 -:1027400071D871FF43C6F559986027DE1026D3D59E -:102750008B12C2F1CC2321DC878597E07AA3635CDE -:10276000CB03F8FC797B20D70978FFA66FF301092A -:10277000F733FC818B11CF357230D303E57F2D7792 -:102780006662B974C8FA3881A717E0398780619FFB -:1027900094DFD7DC0DCB3DE10BE62B11FB86DF5F31 -:1027A0006CCCB7C7F82AB01F91DFCB4AFC42A2FD20 -:1027B00041FC4C079FFFFD343F2F77F27505F10771 -:1027C000F2D73E6E3F9D523C71B8EF87D879DDB4A9 -:1027D000EF63F3BC6E684F11EBD85AE057C5B04FAA -:1027E00077A1E2B3203F5D540DCF8DFD8D62272789 -:1027F00038E8DAF2A876BDDE3F3CAF83F8944F4F5D -:10280000227B24922F7674ED27F0EF69DDA1339EB1 -:10281000B288C3F14CFFD1FAEE93AEFDAA451C7607 -:1028200073A8FC5EBE3FFE696E1CC599EAFDB8A3A5 -:10283000696933DAC57734F59D89F8BCA3E0E23FD6 -:1028400063BA43EDDC138BFAE27E89CE97DDF9C1E2 -:10285000EB6A2CA45BDF5F47F71F3C2FE4713AEB78 -:102860005491FE01E6D6F87E5788DF47C5BC02AE1C -:1028700057D15F71773874DB0D00DDF37AE80634E9 -:10288000F7A6EFEB7C03D543A0DE3D89F694F4F781 -:102890001ABD6F7298BFD7357EC546E3E91EAF8D6E -:1028A000C6AF8F0F7A4AF8EFC28FB8F74DC7C7F897 -:1028B000997CDC77C4DE751D3BCB3AE00EDBB03F84 -:1028C000F3783EDE9F48FC7C8559A01F5F74FAF6C2 -:1028D000203F3EE3F4ED45BD5762EB4C570692BCFA -:1028E000BC85CFCBE4C005C930FE130302172721F6 -:1028F0001E9AFB9C97BD7FC0CEF9FB809DF3F781AC -:102900000C9DAF5B9CC8D7EC74228D53FF7EC792A1 -:10291000AD871FBB1DF8FBC4DBFC3EBB52D973E384 -:1029200043E4979699312E3E323D20FC0C2D5D7C80 -:10293000C8C73B43E1F232A32196CEC1CC982F9B6E -:10294000EEDB9F319FC7C332A579F8ADA675C222D1 -:1029500011D7D2B31EF48344D63373FE04BA17657D -:102960009BE61E477E91359CCF664EF4C9788E60FB -:10297000CC3289F6F1471FF234B6003C3314EF45F0 -:10298000319DF9E07F0DC2FB51CA9AB97F34459E53 -:1029900093F9534857EDE1F33DC273104F0E9FC7B3 -:1029A00061D8CF69532B32DDC8CFF7387CA80772C6 -:1029B0006FF57D8274D5FD22FABCFB0AD801181789 -:1029C0009A7BB72707F924B7DEEEA3D4C69418D0B4 -:1029D0006BB90AB3619AA231C58E690CB3619ABD15 -:1029E00050D84F353791FDE0CAF16B78BF796ED37F -:1029F000F35FE3FBF94A78B764E0ABDCA6B7BFA3AB -:102A000073763E3FC5FD5E56A799D69FC3EACDF0CB -:102A1000E58D6638336C8647EE33C36538366867B4 -:102A20008CF81EE19E9D5686DF2B2BDE6CA538F4BC -:102A30005771AEA0785E3BE9C509C54DD91827711D -:102A4000FC45A705FD953BFEFA32C559746E8A65B3 -:102A50001867B8FBD318168371BC9BEDEB30BF1819 -:102A60006887FED9E2CDF6B5184FB3ED529D4F43BE -:102A7000140FB5ED6FFCBC4BE7066B08E32E8E6FB1 -:102A80007FFE45E4CBE31BFA931DF6AA14B4607DE8 -:102A9000C14738DDC708BD3E46E8F5E23AF37AFCA7 -:102AA0000A976EAFBA87E2FC372681E3BBB5B22F37 -:102AB00087C5772574FB6D8CB067DD40CFCF8776F7 -:102AC000D37988D0CF79A17B351FD16B410CEAB384 -:102AD0008EA3DA0CF44B5D5C63C6A3CEDF9784CC87 -:102AE000CF27BA24A1E70CCF33305EC5B32415E756 -:102AF000EF67A3DF537FBD8BDB192FBCA0E9F2206A -:102B00008B7B2A99C770AEB25BEFB379FD319E081B -:102B1000E935B0FB797144BB7AFDB12E2ECF5FDA77 -:102B2000F879824481876395FBC86EE8B2232B7DD8 -:102B3000BE890638AF6677722EE16F77F2BD86F9EF -:102B4000AA64C3DEE4BB304EAE4E418F362BB9E3F0 -:102B5000B99F8F49C4E7723DF613F3118F6DF56F7E -:102B6000B8B01CD8D9238C7167F93557FB261AE405 -:102B7000FE87F2B94EB71237C7CB2B39CD93F09CF5 -:102B800048710DFF8E6171FD6DB7DC80F85ECDCFB1 -:102B9000D3672BCC2F833C966CB9EDFA61F0BCFC6B -:102BA00099515EEC0F54712B3E2FDE7892CE153D7D -:102BB0006AE1FE8E48FA04059F3DFA134701EA399F -:102BC000A8EF75CB087A7F9F05EC9B23E383EFDCAE -:102BD00005458EB3FA0F6FA0F830339F02DF4B68C4 -:102BE000BF75AE97BCEBE8E9C2EC9BD154F72DA0C2 -:102BF0007879C88FBA7E290C99EB89A4EF6AC16FE6 -:102C0000F01B62E493C8727DA604E9DC74C97CD031 -:102C10009306FF43C9A16A8ACF8D6C07235898C1D8 -:102C20000EDA81E17528979B789C16FC245BB688A8 -:102C3000631FC461BAC715F91118A2F85236D183BF -:102C400078BD994DC654D7376D39F5C3B1FCAB5239 -:102C5000CB73BFA2FA9C24E76DEE30DD6FDB4F9C97 -:102C6000476FF37058FFEE8F9E5FD464A7B8AEE352 -:102C70002734D2BF0B309E14CBBF68B758C0683D15 -:102C8000BEA5CF788C536EABE7F7A51FABEF335ED5 -:102C90003BCBBC1EA94FF4F9F620FE391AFD7ABED3 -:102CA0002617CE838B781C774A9F8ACC8A2874D2C9 -:102CB000DF4BD42A3271FDD3798FC3BB8EF014CC95 -:102CC00050C8EF9F4A7E9A5CE19F3AE8F6BFED025A -:102CD000BA39A1AC0FFE25EC93D7A1DFF30BD9FBDA -:102CE000807B50F73EFDACAC009DDFA30FF440FBB2 -:102CF0003315165680DF66E23C359C609A4F67AE0E -:102D000096289E71D672F378F0BE6EE3FC5AC0AA84 -:102D1000A9DE22564F69C16A737E21CE472E3C2719 -:102D2000C7E3768A6ACDF9FAB9C0928D67ACD1F063 -:102D3000F635D3C7E7FB02C727DD6CA3FEDDB72A54 -:102D40008EEF7769CC87F36DE72A27E9FF6216A03B -:102D50007EDC29E6FDF207737DB320ED983FD33783 -:102D6000AB0F9ECBE7F3232D19499EF9BD7EC5130A -:102D7000597800BFCF87E1BC5BDC248587216C03D9 -:102D8000511DC19FE3BD26387EE379367DFC386E48 -:102D9000E373F63EA76F119E9B92F9B88DF9250259 -:102DA0001F251BAD267FD1988D52D079399EAF6AF1 -:102DB000A1F7CA1ACE584DF58A791DEC016607BAFB -:102DC0008D29582BE3605675E9F1D025D1CECB1C67 -:102DD00010785C755B5E5F94DBC7D1BEED27109DFC -:102DE000437A4AF8A358D806EDC58CEC82293F7B7C -:102DF000218793E21EBDA6268DBE2F4AFB61336557 -:102E0000FF9B780EB3323ED0370EDA9969F1A52BCD -:102E100024BFBEC1E46F9DCFF1F0E4888A4B2AA2A3 -:102E2000ACB7753A3F21D5539C40703B9FA79D5945 -:102E30009D6AC0201723E3B8BE8CDBD342E78F3AEC -:102E4000B74A74FEF929E9209D0F7EEA5A0F43FF25 -:102E5000402AD009F5EF53125B84F7FC6535DC346A -:102E6000E70DA473568C17E30F4A1BC6C9A50E1AAB -:102E70003FB7E3622BD6E2BE54CA8C212390DF61B8 -:102E8000DC336E86E7A3E33CD45E5F07A77BEAC230 -:102E900060C6DCA1D8BE7FCE1B288FC362E8BC7C95 -:102EA0000AE0CA9940E932B4CF5259E66EB43353BE -:102EB000A77846A04F7F958BB793649167DC84F623 -:102EC000E3080E273C2CF9D61113AEA07652ACFCC9 -:102ED000937AF81CED4D1BFA271C067A4FA8C8C43C -:102EE000F65306F134510BA7613DFBBBE81EA075FC -:102EF000C83C37237D3DEFBB7129B82EDCDF060BC4 -:102F000075D063FBD3F4FD97B083ECFB0B87F0F235 -:102F1000C24E9997C9CFE724A6EBF6152FD7A1FA91 -:102F2000E246A25E7D8FDBF95F397CE407BF42EBAE -:102F3000E53C80A053F9E9581632CC0BE5D3BE210D -:102F4000FBB3FCB4CBF41CEF0935C6959714ECA188 -:102F5000EF3B94B2663A9F505A6F8E83BF22267A17 -:102F6000BB3A9F979F9659306ABB9AF9F9E93E2C74 -:102F7000D8275AB964F3F3D392196EFC569453E8E8 -:102F800039CB6971E1FA710ACE47A8674296A07AF7 -:102F900079375DDADD2DA679A8DDC3E10EB1BFA8D2 -:102FA000E7EBF5B74FD3C4393D7ECF7B5B252820B7 -:102FB000C0CFD34D27C9DF5DD2B49BF0A3F3453713 -:102FC0009E6259D080A7E4AAE6B00564FCE9B8FD8A -:102FD0004B875E0224D9A3CBF33B4B7D63211FBFFC -:102FE0006B6190EFD8AC2E792775B3CA220BFDF038 -:102FF000EED289638D302FDFFD7EF3351381B7B2BA -:1030000086F2F76BE3DE7B6B21C606759D3BE84CD1 -:10301000F73B0DB02D0276003CCC00BB23F213230E -:10302000F25323E0345EBECD194E97BD8C6D8EFBFE -:10303000E01A05F45C5BDFF074BC796479D547D79E -:10304000E0F78E4BB3F8F77BCB9A24AF64D0A3653F -:103050005E1E87E4F0B6683387221E9ADF447D50F7 -:10306000D228B971FDE0A8DF122618DFF318DEAB15 -:10307000E7EBD392FA83F45EAFF50FB1903C3F3AA1 -:10308000E4732A77AEFD2D36C5FC3DAFDEF6BB52AC -:103090002D81B750DFEAF7C7B76DF9A8FB7BAA20EF -:1030A0007FED7D7D7B499F469C5B2FC7FE38BAE54F -:1030B00045C7E3A3434ED17DBA7F18D6F4019A07E2 -:1030C000B1F34E2EC0AB75FF547A7814DA5F7827CF -:1030D0002FCE1F4F48A14B705E7A9A052EC176EF16 -:1030E00029BD68377E6AEC80DAF20C5E09F34DDCAC -:1030F00049C2FF0167CB00FC64DDE9C7FFC2E1A460 -:1031000016BA09E6B6EAEFAFC1EFCD1E18D032C04D -:1031100002F0F78F5F3A99E08B5A9E41F8C2EA04B9 -:103120000E0F6B1920C3FB03837D2623FDD6BBA3A3 -:10313000CBFD09A16FF4FEC50EF61D8943FBAA84E1 -:10314000CF3B782CDA067A757AD1B14DEB011FD3DB -:10315000FF2396F4DDFAB65BAEF3131E827E8C6F0E -:103160004C11F8A67991F4BB42F6445F9C0B13BA5C -:10317000E9E94C6FF6D0BC7169C516B41F52A60FB1 -:10318000A579E35597EF27EE51DDE9E9249EFEC4CA -:10319000EDE6FA5BB650BC46CA434EB2AB1E17DF33 -:1031A0006700B923FE7008BA58DC7C3CFF0D197328 -:1031B000D11B0080000000001F8B080000000000F1 -:1031C00000FFDD7D0D7894C5B5F0BCBBEFFEEF26AA -:1031D000BB9B4DB209F979F343081071139318A9F9 -:1031E000D64D881831B50B22626B7149F84930C948 -:1031F00046AD162DBD5948548208D146040AB8E19F -:1032000002622BFD82458C1AE88288F62BBDDF72A4 -:10321000EBAD3FBDD71B7E8A884256B45CEA6DEBAE -:103220009D736626D977935CA87A7B9FE78B8FBEC8 -:10323000CE3BF3CE9C3973FEE69C33B31ABB86902B -:1032400064428E25DC30C74E9FDF31E6159D4C224F -:10325000A4BB33F49C494BC87B1221C44548F009F8 -:1032600053687B0E21DFEDD1047589B4DEE14D7327 -:1032700016D1B2447CBD45C3E5BD7FD5DEE5B3D2F2 -:1032800072312DD3E7AB12998BF533BD690E5AFE1F -:1032900002FEAEA7E51E569FAE25AD589FC3BE7F6A -:1032A000AA84DCE5A3CFD4763A6E297DAE9DB8B56D -:1032B0009D8E6B918917CA0BE7166C5D4E616A7320 -:1032C000CC427889D79B2651F84E36E66A56D1769D -:1032D000BFA7AFC835845C51E0CDB097D1F940FFAE -:1032E000741CD2442795363CFE1C9837ADAFD77A74 -:1032F000B3643ACFDB1DFE39D0BE5EE39D42B4D04D -:1033000089B7C07705B423889F39763BB627F2404A -:1033100019BCFFFF084F95B8EE5F114F77EF34757A -:103320009D2C24F8F705FDB7B9D7A12A07FAD2BA20 -:103330004E1A87CB77C3FFD07148AD2493143A2C33 -:10334000AB226E8DFF36E8BF79E9077AA28137514B -:103350003DF42FF0BE4E0AEB52E9FC82FB24CF76FF -:10336000C2DECFB2119295E8BF13E621E09EF7C30B -:10337000E6347FD1F07C2C3F78A9E6765A9CB7E4FE -:10338000CCAEEDF4FB790F59085186DBD31E719D4D -:10339000DF7FCFB89A5C499FFADEB086E2EBFD1979 -:1033A000C4B39CB67B5F431A00FFEF73BC953F74B8 -:1033B000F7113285905FD9B5F89D49D083E4DBBD24 -:1033C00088E2B753224123D0C34C3DD2C36088D298 -:1033D000C395B0FE747DE8FBEE07278782747D06F7 -:1033E000C90091613E15C4BE5D89A9BFA300EB2948 -:1033F0009D044DB43EDA680E6D95805E28A0A55000 -:103400003F09EB5F95D8FA07EF30E238DD33191D3D -:1034100076373A43C11C00B68B00DEC6A2A3947671 -:1034200082744864EF9499B6617C6CE372C1523A3D -:10343000F0E2DBB43FB2DAE4194F1FB0843294BB40 -:1034400052713C4A0FAB91BE640647FD8FD342AB2D -:10345000705C4F39ACCBA336EF7C781FFD914501F2 -:10346000F83799C84A63097D4AA4C3E8A4EBC0E1D0 -:10347000215D4F13A083BB60008A877F6F386F5335 -:10348000E8FB9FD825840308CD584E481D61F5758B -:10349000CB2CC7A429F0D4860D09F4DDCA1BBC03CC -:1034A00082BE72D9D348FBF373BA22EBA336C08332 -:1034B0001FBE4B80FE3FB7295628D3EFA7C0F2D3DB -:1034C000EF0B87BFFF39F07D19C0C7E0276D166588 -:1034D000BB348C1FF1FCB980AFEB696FEC78629C58 -:1034E000F87E8FD9BDFF07F045F11E4E74015EB422 -:1034F000B8AEF1F0BAF4D1C74DB47E5E9BD6B182BE -:10350000E2D3BFD486F315F0DE951ABD8EE48DECC0 -:10351000FF94A5A55C86F92F65744F961928E26281 -:10352000F1A21F2E53D25D48A28735D228EFE5F0D5 -:1035300001807F5177CCF7F8DFBF1A62DB09BE212B -:103540008A14073FA72B459261DDFC125B37BD3E15 -:103550003A0FE4563CDC029FFFC6E58DA08B787CD9 -:10356000FF1BE0BB6C24BE5DFA814CE8D7BFD48062 -:10357000788AEF9F90107EF7B489044D94EED64B75 -:1035800012D2EBFA072D21909B83A6E80EC067604C -:10359000FF8DB8DEE71ACD0AA14D36EA19BF05F74F -:1035A000DB181F170C1480DC3B47E7ECA5EB73EE30 -:1035B00037DA9EA0248020A4E537DAAD40FFE75E2D -:1035C000BE89F5B3DCA2105A0E0086E9B881E07F0F -:1035D000B6118A57699611C73FB1570A19A0BE8F15 -:1035E000E239465E9EA3FF36940CCB8D41A800388D -:1035F000FA2C08079D69238EF75D335945C76FD1B3 -:10360000485E0DAD6F593229D4CEE031C6CAD51609 -:103610000DE9904A86F9BF4573BCE0DE225627A724 -:103620007079AC60BB431285B3C9B83AA205FA05FC -:103630003EA0F54BA03E67781D5A567FF417984779 -:10364000CB1E357D343DAF9EC79258BACA19A61716 -:103650004B29C317A926A1F1145E1B2F5B6A2221F7 -:103660002DE063E93472E22ADAF4E0C074A0235B4F -:10367000692FA9A3CFC069E20D51B8A7F6F7BC36F0 -:103680008EB677D4443261BA81A5BFCD3B79D5F0EF -:103690003A0B38AFE97F424BAC381E7E4741F1EE22 -:1036A000B662BB89B3AE887DAEC0EF92354C2F0FAA -:1036B000C02BE01F99E9CD755C6F52FD8AF27A61EB -:1036C000D704D4AFA0FF40CE3D95C0F431C83D90A3 -:1036D000336D8EAAAB1C749E6667D51447191BC741 -:1036E0006783E927A1FE88A7EB783D24DAA5E6B534 -:1036F00016B75AC76E47F90CF116DD90C8E4882C4E -:103700006179D1AF753DAB103E19E9E6DECD3928C0 -:10371000971B48971EE8BC8984F440C78B8C24987B -:1037200040E962116D96489F8BD71B8812B37E8D3E -:103730002175B989CB85BB4904BFBF7B675C7D35EB -:1037400009DB687DB391842DF0EC55D7B7507D8EA1 -:103750007CD6F78521F63DE966F3BD8BAFBBA33A76 -:10376000A4F5D3796F3051DDEA84065DB83E5397F6 -:10377000F5E07A269678731E06BDF22B9D672BA581 -:10378000DB3FF0F512F83966AFAA00BC9BB51A9C76 -:103790007FF46103E2E724D5E3B0FE6B1DE4AE598C -:1037A000F479AE8D78F37580267BD62CDB483CAF60 -:1037B0007AC5D40074D3E0D0A8E82AD3A1C372F9A3 -:1037C0000A8EFFE596D0D61C44F714A0A7F25CA1A0 -:1037D00057C99499B47C4C47ED3B5A6E9963F543B5 -:1037E0007F03604FD0F2FD0E26CFEE77E8713D45A6 -:1037F00059CC57D00D1D07FB335FC59E028E654324 -:10380000ED9F6074C3F5F0BA46730FEAE121FAD573 -:1038100010A4DF229F1EF0FA0A972BF3C16EA1F8C5 -:103820007E851214C88F602FB35F293EE62DA5E573 -:10383000574E1779562940674CDEBCF21D3359416B -:10384000877CF3CC4F1FFB275A7FFEB45E31D0FA42 -:1038500005406B74FD5E918817C60BBE680881BE7B -:103860006CD2337BB469FF15CC9ED1FB372C8471AD -:103870005ED079C0DE694A083DB703EBD33C94A221 -:10388000C9AB3A86CFE0CB16F6BD39F4B39FBBA0E7 -:103890003ED513A4EDA326FF4658D7748392887AA9 -:1038A000F9D75AC2C6091738285E8F8798DD7D9CE4 -:1038B0005649304EBF0DFBA17C9AB690F673A233E9 -:1038C00015E743E52FDA5927D618B682FC5D373461 -:1038D000AE84ED8FEB7CD3D368F9F88BC59EE5B44D -:1038E0006AD0A70FEB293D07D632BBAF5EA36C01B0 -:1038F000FC90FD169C87588FC09AC5B5501F58B2D2 -:10390000EC16908F63F139C87B122337CF9168167C -:10391000F0D3C686DCDE30E895FE891E54AFC44D78 -:10392000179FD28D9DB53DA963F88DEED3213D5FE4 -:103930006EFF40177239D343304E80CA6522F80FAC -:10394000E5724C593B5A99AD63E095546EDFA9EB93 -:103950005312FC47605D5A9EFC8FF7972A305E1425 -:10396000E522E94A46BE3CA9F3CE03BA755487F571 -:1039700075317AFDA483D999F5066E0792B03E960B -:103980000F457D79959AEEC5F304A77F5B84C9F74F -:1039900091F51ACE1FB71A408F4D6520936CD02336 -:1039A00056E85FC1FEA79E0EEBEB69397B5958BF05 -:1039B000883F814F28BEC3463AEF931B6C8CBF29CA -:1039C0001AA09F451504F5E5222DB5634BE0BDD245 -:1039D0003740D7E5D48B0EA42FF2678A158AEFF90A -:1039E00084B73350BB97CAB1973AA430EC0BE6AF1B -:1039F000376C35E5005F7BB53658CFCD12CAB1F9CB -:103A00001D95051B6879C99E2B70FD132A185D2E24 -:103A10000939502F4EE5F2B1DE10D2A31DFE3389D5 -:103A2000C03E88F68FF67413FD28AD64241E40AEA8 -:103A3000ABE8211453A6F6D1D45E26570995E724A6 -:103A4000C66E12F21EE43889B303D5F41114FA8855 -:103A5000C93DA2A482DC1372F998DD97E8443B3E8D -:103A60003F15D697AE27939BBB25C46B3369457D25 -:103A700022F4C0D0B85C8F9CD20699BE323C81CF74 -:103A80007C670EAEEB12D28BFA44E895B1E820DFEA -:103A9000A9E1FB88D1E960BC53C1FE9A4E93F07551 -:103AA00074BCA66524DC3C853D6D53503F323D69B6 -:103AB000647A129EE6CBD097F1FA315E1FC6EBC155 -:103AC000543DD377629D853D933A8DD901539785B7 -:103AD000B4A408FC35DEEA94E461BB26F08ED1A8DC -:103AE0005C09651FC905F99E50F9622AAD0FC8C46B -:103AF0000B7C65A178E9A1EF3773FBB72795CDD78C -:103B0000AD67F4AB937DA4D80AEB12C17D6F3499F5 -:103B1000D8811E053E37DBE87725F01DE3B7A1EF1E -:103B20008DA4C31CF37DD52B26D43F175EB6850C20 -:103B3000688FF8B31DB4BF94DF1BD04E3DF78A0DDC -:103B4000F5E939AE0F5DC2EF401E617E16BEAE4193 -:103B500052358E00ED4B33C6810814F659B383D924 -:103B60005923ED215E9F1399C3E8CA80FBCD0B8ECC -:103B70008107A04CE121A07F6E71327E0FEC995637 -:103B8000FC43FA3EE0B37A18F6FDC540AF06EDF708 -:103B9000E718297D4DD72E8B3E48E7D19C69B58328 -:103BA0007EABCEFED7DFDD41CB1FEED11103ACF3F0 -:103BB000F6697349EED8F2B731A43B3E10C32F77B4 -:103BC000EF54979B7BD5E5409FBA7CBFD3E63A651F -:103BD00041D9E1F982D2B5C1D07ABA87C26B78D522 -:103BE00080FA6886D3FF9013E4AD267A18F06CC88B -:103BF000FE780AF83B02FD9F48F03450368A1431B3 -:103C0000FC035F5F30CDCFB68F82B761FC11A30696 -:103C1000F14CAD75F6443917E07CE2D27B3F3C4075 -:103C2000E7BF6896D9BE02DF786BCBCAC19E441845 -:103C30004960FD4D1FC2BE8BB66B84F53F3593B610 -:103C4000A37035AC67FAB0894412806F5BA8DD6958 -:103C5000A44BFC1BCE6F777744CBC3F47FBB9D3561 -:103C600013014EF92FB20FE8E351E837C64EDEEAF2 -:103C70006472FC4BFB993246F899B602FE9A8D03AA -:103C8000FA4A3AFEF57FF90CE5FDE2A5AFE13E8286 -:103C9000CE633EB3AB4D0AC8A7C50F1EC0F762DFA7 -:103CA000762AD38AFBB6D7361858D9A1C7F2A9CD40 -:103CB0006C5FB9B8570AC13CA55917932A412F6CBC -:103CC000D6D90D64245EE3F1F8C1A6B713C0EFF5B1 -:103CD00001221DF67B12B3C7ECAD09B87F505A1311 -:103CE000C0BE0CACBFF143908F8B376B3D602F9003 -:103CF0007D36F4CF2CDE7CC3C48556E8E7D3A44AD6 -:103D0000F0136DB9013C54D0CE17627E9EC8F5F415 -:103D1000BDBCE56A05F8F1D06606FF62877107D081 -:103D2000D1F57FD1227FC91AE2073BB95BEF9D082D -:103D30007CAD6CDA3E1DD6E78399E91A6CBF4B2245 -:103D400076C08B63690ABC5F2CC93EE0E386F58DC3 -:103D5000B5B1764F9D93F9C72AB397A50C5891AF8B -:103D6000E6803E6DDE4CF908C69FF5DEEFEE700D85 -:103D7000F395346BFD2D53A1FF67751EE0BB217BCE -:103D800066D3B790BEE02F4CF1B598E3EBABF29958 -:103D9000C122F8A4B500E4EAE215AD05F651EC8CB9 -:103DA000213ED944F9723221A79D12F902FC9319E0 -:103DB0004ED5BE63AC7D9AB550837AC6E821DEED60 -:103DC000F4994AB7C9B01FB725C9586F4BD2237DA4 -:103DD000CB7FBA77E76FE8BC9E74FA2F80BECC2603 -:103DE000DE62D06B4AD45E45CD5A4035DA61641349 -:103DF000B3AF89CCFC85EB92C98E5531FB7353125E -:103E0000DB4F5039F105F473EEDD3F1F06FCB6645D -:103E10007D3C05EC85C0C5CFF4E05FB3F64B28DFF1 -:103E2000AD1E1F01BA09F4CF240B8A86E572C0C308 -:103E3000F446FCBCE624E9981C7545B19F4A97827C -:103E4000E56E07417ADAB8D48CF6FE4657C80440CE -:103E5000FFAD7C2BECA746EE0F346EFB85570B7441 -:103E60001E92ECE3A1AC30FE186C9817D2D2713ED2 -:103E7000DC9617C4F29E4A8F96D659B7FDE3CA5C0A -:103E8000C0539FCE03EDAD9E810498DF87DB4E24A7 -:103E9000C0FC1AB66971DE0DA14F5216160DCB0982 -:103EA0009DC65F900476825DB2C2F8425E7CB8ED3A -:103EB000D3940556E63F407D5A3A3A5ECCCECAC905 -:103EC000F0FDF5DF64EB726697210472F08C89F9DE -:103ED000F745BB3336A6FFAE4B12FECDDE2CD03FEE -:103EE000436579A206E4C4F7ED6CFE2E7D6F16F0F3 -:103EF000E54792BA9F252BB52444E552E34A8984CD -:103F0000A8CC3FF3DC4B5920FF3FDCFE52565D0C42 -:103F10007CF1DF89E78D496A7F9AF0AFBAF4E10C52 -:103F200018AFCE63607ECC31FCABA23D59CFFCA470 -:103F300083946B810EC577830D662FD8BB83C4181D -:103F400002975B5D3FF7D77ABDF92ED8D788EFE3AC -:103F5000FA5F0DF444E192FA24F427588AA2289FCC -:103F6000BFB4FC77D1F58C91FF749D8DB04ECDC65A -:103F7000E8E17104E9430F78D3B75865D05729EDCC -:103F80008CBEA2F76B709FE532274C81B8803EDD76 -:103F90006D05F9767D81B9439308EFB342D03E3386 -:103FA000BD10BF0B5631FA0FA610F4C3A5915609E8 -:103FB000FDB476E6E7CFA820F655B4F8B32466E75B -:103FC000B88967BD360FD75FC23807C78BD00F409F -:103FD00047202FCF4846A423A95F427B54ABE99DDD -:103FE00007FD8E45572BC5BA72BA1A2AFF9DE8EA1B -:103FF0004941C723E8CAAF205DB98DA3D315F72384 -:104000005F767B12F4C1BE3695E36B2D973FD1FBF3 -:104010008DC2AF2EC17C6B797FB5466B580B7AC4CD -:10402000A3FB38D63FBC89DAC5B07F4A03BB9E3EAE -:10403000C7B5CF5770DD486400FC0896AB8DA82F3C -:104040001FD34472C08E499DD4BA1BE823755E51BC -:10405000493BEE0B331CA01740D7A27F74E9341FF5 -:10406000B323581C283A538FFB9C96072B7DCC8E8C -:10407000A8417E09AC3629A007A7F5E72C07FA0866 -:104080002C231E03D271CF8645E0CF9D6DF580AC09 -:1040900013F125B252CD779D128B53056F22180F65 -:1040A0001B8E330D6CF921E8FFC622F49B0CF98FAF -:1040B000F309EA8DCB8D43D6AD3621DE45FC68D0C1 -:1040C00046117425FA91B13F9268647A68A47C40E5 -:1040D000FF734A05117FEBA19C2ECA3CDE23F85FDB -:1040E000C4A36C45BE1CB0C82B9C39BF32439C0492 -:1040F000FC776CB31684FD00FA8D5919DDCA4F693F -:104100002820E950FB9FABAA3362CABCFDD0F7C19F -:104110005537575F8BFA77A81EC0A67A5994BD26EB -:1041200005E255C3F532B5838D7D12FFBEE2E61B75 -:10413000A8AA1E94C4F87FEEF4821FD14454E3C5AC -:10414000C227C7F5AFA3FD5B15DE3E38EE26E8EFCC -:10415000A912517EA0D34BE15BAB53F78728E5DF73 -:1041600043418CF77F530EAF5A9D316C1F507BE15A -:10417000CF4965C376C2A3EFD5765D49C7B2D83FB4 -:10418000D583FE15FA3EE092D00E89E7D70497F466 -:10419000D5EC6B65847D9DE062F6F5746049BA2FBD -:1041A00041F91D58E62360DF52BBC4E942BBE4E39A -:1041B000530768FDB9599F1F1EA740BB7BE6C1BED0 -:1041C0002A705146F91BD8A90D49946F8CFDCCAECD -:1041D000A6FA1CE305827E96D839FD388204FC9746 -:1041E000DDFBA432A077425AB36EA36BF903973775 -:1041F00013C7E1FBCDF87997BB985F205058B5A164 -:1042000000FADF2611B01756151E4F5980FBA9631F -:10421000290B63BE6BEC7B0AF1D9B853372A1ECB4E -:10422000A9E104786C79F9452FC88D3321096542DD -:10423000831CEA04BBB6A141031621290DCDBF039F -:10424000E31F73F5643C9D5F06D777819DB706A792 -:10425000C2BCE9BF127DB5D1B708E5C4C6B9462BCB -:10426000C6910AEBEE413CD8CD5EC0C3AAC2AA34C7 -:1042700018A765E6743BC64DA83D07F52D0F7E07D0 -:10428000FD4502AE557DBA1AB077CAA95DF70B0A93 -:1042900077A673468D87F2F538EDEEE2FBAC10574A -:1042A0001F5D8EFFBF6446171D922FF8ED52F48FED -:1042B00092587F67761FB31F6F71E955FEF15B5C03 -:1042C000CCAEBD36189906E4B25F1EB0805D1D20ED -:1042D000DE4F605F4D7C56653BAE13935FAE360597 -:1042E000FD6646D7C0635742FDB532EE67883CF0A5 -:1042F0006318F75CA7CBB38A703E80F283452190A8 -:10430000C7FB5CFEEFC2FA96737BF5DCCB371683F6 -:104310007F51D85F9DCF99506F76DA94276B404ECE -:10432000FE49667903C668641AED67C9E74E1CB793 -:10433000D314EA84F50FF668B1BEC9EA5F04F4DB72 -:1043400078EBFA299887600D15801ED5B9BA08D088 -:1043500031DDBEA01FC5E8F21188234F0BCE972593 -:10436000D0177176CD34F063E1BEC5857EDC2ACEF0 -:104370001FE329159C32222B747C91346CE7BCF925 -:10438000E7D932BC14F68FC6C8FCEED573CD04EC69 -:104390005CF248F4B006FCF8AE08017BB8B957C22D -:1043A000719A0B5FD0C3FEE5EE5EC6DF01BEDFA0F3 -:1043B000F8CBC27894CBC2ED810E46672472781C8C -:1043C000E0F979B69E84D076317E5742963379C033 -:1043D000FBD3F3F84333F737514D88F5AB5CC2CECE -:1043E00058A18E5BF071D74911AF16F05A2CA9FC79 -:1043F000E4E2D9C3BF4F3C189D0EFC1BA5F4057E1B -:10440000A70DD2CC7B5EA7F3DB5036C903A6989BE1 -:104410009293B604DE5352A4782FEDFB643AD00D8C -:10442000A921C8AF2D7D95DA662B8BEB605E8CA53C -:10443000B507EA53EF2A44FD0C719359F4FDB31C00 -:10444000AF6956E6C773AF08E6401C34F1A0EF9E93 -:10445000D761FC2BCCE8874DA56B6373E27325F81D -:10446000BDDCA4F800E86777AD5202F088781FC47D -:104470000B67160DE7E3383D92772B7DEE76399882 -:10448000DFCE406A005E781FB20EC71FC19F07E3F0 -:10449000427C0F9EE7D2C232FAFFC9C096EDB8EF58 -:1044A00037603E486DDF1BEF80FEAD35925E8CC7F6 -:1044B000C6D92DD589B7BE02F43F78F6D4968701C8 -:1044C000AEDBF67A30EF25CE1EB9FE9BCC3E3FB375 -:1044D000DDA2003F6CE5729BDA8FC827C15D6C3F9F -:1044E000196F471E75A9F72743E5AFDD8E64F00508 -:1044F000B7B33C0B21DF037CFF37D8703E01F4D704 -:10450000BF0DC113970FB28DE783F48F9E0FF2E6B4 -:104510000E4B10E8E17CAF09FD92328F7B9DB545D3 -:104520001F002475380ECF01791B5872E6E71ACAAE -:104530007F720F8B23C9128F33FD4A4B585CCC6BB3 -:1045400007FF8B805B764C777B8B403EB27937716F -:10455000BF5193B34061F12E9637D494102E007B57 -:10456000EA55AE879ACC2C5E35E8D087615DA326EC -:10457000FF1F5D18D762DF935F1A94D8B8564F8833 -:10458000D975270A35613D9D670FD807B06EAB59C5 -:104590007C6B289F60BFA1C7C0E290581EECCC4145 -:1045A00039592FE256FB993FAE9EC7A74ECC5AF41D -:1045B0000CA45C7448AD35B03FBBB0AA12FDE80F47 -:1045C0003C39139FF52BD57EFF45E0A7CF1B8E23EB -:1045D0000BFF7B1DF1E899BD3CEC47D450FB4559DE -:1045E000295781BECC21F61520FF95205DADABE9A2 -:1045F000B3833EC168973412D83972A7CB0CEBFB5A -:10460000688706F554B043E3857602CF39C9CC8F6D -:10461000744D32F36BD0A50AC138E2D9A1E371071A -:10462000DEDF72A209C35323B1E7A376B966347DF6 -:104630002DFAEBD0B51AC14F17CDD4A0DFFB82DE27 -:104640003B17FDC6CE020279541DB6D69535AC1E79 -:1046500079E78229EAC3FAEB64664812C509F233A6 -:104660003599E7CBC5E16D6197BA1C1F8F690CA91D -:10467000CBF5C43F212D8FC50F62DFA72633F97517 -:1046800061550EC7B707F3E3C4FC976730BC6932C6 -:10469000D93337B36A2ED0412EC49773E0C9FCAB2F -:1046A0007426087FEE752E09E9230EDE0E30DA80BF -:1046B000BE3A593CF46F853F1EEECAE414AE1FBCEF -:1046C0006E885FD6DBF5188FBE5C3F495DB25A0E2F -:1046D0000D95BFFEFD2CDB27756A799E8D1DE5507B -:1046E0009D9DCDE584E4D91186F7566A2FC03C3AEA -:1046F000B525603F4CBBD58AF368D96F423F70F354 -:10470000B2812CD0E32D55030510B789C72F402B5C -:104710000BF945DBD5B9E8FE03EC84D8763C5F4B5A -:104720001D67F5FE20B90CF6392776BF01FA6AB786 -:1047300009F515FDBF0306F0B3BC9C83F6CC8736A4 -:104740007F1BB40B98C35B9ECD01BB85D94DCDFDBE -:10475000861EB00BEB3A62E27CF09FD5EAB81F5997 -:10476000E944FF3BE956BF6FD814F7DD883860177E -:10477000AEF33ABD7F22F03BD53B987F70B65183B4 -:104780007903F55ACF2290B7674D6A7BFCAC8DADAB -:10479000D796A175F6A0BDB565CC75F614C03AD70D -:1047A0006B883FB69F665867BABE4D7C9DCFBE787A -:1047B0007501ACF3C7BBAF2E80755EA7EBF202DFCD -:1047C000B439FC5B9369BF276FF0A13D25F2582FE8 -:1047D000971EF724ABFD2B43E5FF21FFCA58FA30A3 -:1047E0003C04875A1FBAF44A06C8833AA3E1BFD5EE -:1047F0008BF037AA1FCF68407FC7FE3F7FBA66079E -:10480000C8817E2DDA23A2BFFDB23F0FECA1FDEFE0 -:10481000B83D4169ECFE1BB95FD86D2441F0AB880F -:104820007D80B027E3E5F15B7C3E1F257B6F00BBFD -:10483000E6CBFA8D1BF83B63E85366E76E933CCCFE -:104840006FDC8B7EE4967DF3EDE0273E1D627EE318 -:1048500096178BD16FDC187A2D0C7965A45FB2C3E3 -:10486000FEA371DBB104C80710FB5CBAAF3D938CAB -:10487000F4A8DEEF9E0E9D4880FC010A7725E871C2 -:104880008B2BAA07BA6FA1FB3DC8236C91A387A10C -:10489000DF1617C13C97D23EF5FE4FC47937FAF4C4 -:1048A000287737F64B2190D7297A7F4E06E8359244 -:1048B00061C77820E7B38BC9DED494B2D8F8BAF7D1 -:1048C000F3E4E4E17CB0810D8948BF033AE2B583AB -:1048D0003CDB60E3F24C46F9F6C74D8E10CB0F631C -:1048E000EDFF18627642A3C80B934958A6EBB56852 -:1048F000B6F75D586F90F7E138791F5B1671FBBB17 -:104900004918F552331918CA0F8B6D171FD78778BE -:10491000B8AA1FD25AAC801FEC4EAB07E081F8B8A2 -:10492000BA3EC8F6EB941F96960CD3AF580741BF1A -:104930002DDC0F1D6838FE08D06FA04FB2837DD7E5 -:10494000E461F4DB44F75B90471BCFEFA4579D373E -:104950003A16FF97A6A8F5D150F9EFE45FBD3E45A2 -:10496000CDF762FEC26F3F34CF7E89F165DCBCE2D9 -:10497000F7A9F1FE76B1CFBC5C793827452D0F87BA -:10498000CA7F67795837B42EF1F2501DCFF89BE5F6 -:10499000E1FF705CE3997D4F27C0BE03EC78D8A798 -:1049A000ACDCAE63F91314FDB1F1E2E95AAB97C583 -:1049B0004FB5A25E1D8757A6F3383CE3EBD75ED414 -:1049C000E2BA35F33871F33E9B079A365817639C69 -:1049D000363E7EBA84EC9E0E4B151F476D027ECE8E -:1049E000BB743C75750A8B8F525872206F213E6FD5 -:1049F000EB35EBA749FE9875AF2AA21B8251E8DB85 -:104A000028078933E6FDC6146657BFC6F38BDC7AE8 -:104A1000768E60ADCDE285FD8C5BC3F29F7EE0F2C9 -:104A20006D82BC18A3C2F1FAF2ED4443F1F28CAEF0 -:104A300017E54AB0D9EA013928FC37A2FF8B3C5E62 -:104A400071D9FA3F8EDEF7FC0FD37B3C7EF68BF1FB -:104A5000FED6B8DD7A8A1B155F10A4E323105FCA67 -:104A60001949BF63F533161D1F4DF11D496176FECF -:104A700014CC57B84C3963298D9E003F11D963502F -:104A8000C0AF097E12D48FABD3783EAAA77C26E6AE -:104A900069B37325E21CCE5876E40743EBC3ECC838 -:104AA0000FC65C9F2F6747DEEEF07D087476B2D2AA -:104AB0008BE7011EB551F8617FF89C61D4732EE23B -:104AC0003CC6A5FC2D5FC4D1D517FF4B72D4923ADA -:104AD000965DF975CBD1CF13C07F3A763F419EFFEB -:104AE0001941BC45F749646B8C5F3B1061F97B1938 -:104AF0001C5EF1FE3FF8BEA121D59B994ADF7FFCE9 -:104B0000AED14812A99E2E6572B1C567C5B8424B99 -:104B10002FCB7F695946508EB780DFB408FC8933AC -:104B200009D87D4F3AFD13208FEED1F7AC416D22AD -:104B3000F8DB6711B0F3CEBDCBCA339CFEC99867D2 -:104B4000B76C00E318DDB3CE601E56F9179F3E52D6 -:104B5000538AF0A23FC165509F67B93D95C933F1B3 -:104B60009C3D846F2FFAF33F6E60F9DA0197D70E00 -:104B70007E09E10FB728118C2BB4EC61C65BB996A6 -:104B8000CD87FC3003E9A9654F6531F84D49AFA9E0 -:104B900018ECDDF2DF5B71DFF7F183E99827B1CF25 -:104BA000E5AF027CD84A4337817D9A4DC701BBF7F8 -:104BB000E3DD371503DC42FEAD03BF391D7F9D4D9C -:104BC000ED1727469677BF644726EE339BACFE5A17 -:104BD00098FF3A138323B89D9F4FE1FEF278FE17AA -:104BE0007C9FAAD5E038A9DF35629C5CC885753A00 -:104BF000E237E60DCB93129E671870F13CC7FE9921 -:104C00002C4F8597AD2E75BEE747C93794003C25DC -:104C1000A9F2578B675947E40B94A4B27896EA5CE3 -:104C2000A2E522B3A773ED7AA427DB4AC2E254942B -:104C30009EC0AEBF361A9906E7BCF2BBC3D7029E30 -:104C4000F75FD4209EE49947303E9328B1F1F256A5 -:104C50000F744E007F8CFDADEB6049952E7B15A047 -:104C6000F449A7EF8154E4FFD64218AFEA5F742CF1 -:104C7000BF729F05FD0CDD594D985F79EE3D83EACB -:104C80007C4EFC334856603E656EDF6F314E60DB14 -:104C9000238D9A27FB44AA15F9A62518998E393633 -:104CA000D7BA50CECAFB7E1F04BB43EE944102919B -:104CB0000E9D5703E7D382CB09FAF5C777DB35B0F2 -:104CC0005ED93C3F6670FF7F4EF1E3BE45C40542AE -:104CD0002CBF4937F008ECC7E4E503DF0CC27AECDF -:104CE00071685AC07FAA8BB6A0DF659F05FDACD95D -:104CF0007D792BBE41CBD92BED18071B7CE5EE6CE3 -:104D0000CCE7A7F31C3FCA3C1F4A65F948F23E8B2B -:104D100006F499FC04F1C0A8B223A50AE17E8A96A4 -:104D2000693FDF077A4A1E8E9B823F0AF45443AAEA -:104D30007F07D0CDD0B9A4A566762E899FA7B52DC3 -:104D40007D6F179CF7D9C2FDB907F74F9E85FEBF4F -:104D50004E598275B8E060F9952FA4B278E248FC0C -:104D60001FC43CD6DC7DBF657A8DE202FA97758C54 -:104D70005EE44E570FF8195F49F063DEEE751D6172 -:104D80002DC6CDEC277F5CA3C4EC77D6333DD3B2E0 -:104D900093EDCFE3F73797D22FBF1E92334CBF0C62 -:104DA00095FF4E76CBEFE2F4CADFBC6F21EAFD5EE1 -:104DB000BCFD12BFBF1B618FC7F537961D23F25094 -:104DC000AA86C761F6B44DD84941559E4E95959F28 -:104DD0003B34AAFB5F9F64477A10793B29EDCA7286 -:104DE000C8DB8FFE88A0DF4EE415893CA26015CB9E -:104DF000F7096A8C782ED14DBA307F681C094B12A6 -:104E0000FAD706F0FC6D2AE411D1EF4FA4E662FF59 -:104E10009B8967A516E5A62201FC26C83F4902B872 -:104E2000431B16C178B759713C13E49F24E13E033C -:104E3000F939DDC7F256A735B0B8433AD5CF504E51 -:104E4000CF6774699AABC73C56915722F24F045E04 -:104E5000AA38BED3272CCA01B928F254D6993DE509 -:104E60006017C1396838BF1C6C34F3BC13D66F7738 -:104E7000632E9E4FFEB27929F17816F929FA447F04 -:104E8000A6BB6CE43967413731EB89706DDCC7EC48 -:104E9000FCAA063DCE63B07106FA2B071B3504EC65 -:104EA00081AA7E03A3C3B8F136CED59330F42B8705 -:104EB0004C204F053D5CCACEA5EB5B08FEE0836D40 -:104EC0003BF34E52DE3FD4D68BCF4193D4ABBD12D1 -:104ED000CFA1CE03C9F58DB4FC5AF91AC8B78966BB -:104EE0004994846AD3AFFA964CF5C46072F47D2875 -:104EF000DFBEE17BAC3C3EBA45A2ED9BD33E62ED0A -:104F00008136D3A9D85EFFEFB541EB57D07F7F261E -:104F1000F1F91C35EE64F4EB3C12413F12D77FA54A -:104F20004C3EBAAD7AB49FDC3C1F9554F3FC5488D8 -:104F3000F8D0727B5A31C6EFAD44D91381FA0C0315 -:104F4000B32708E387F6F1CC6F6DE4F4403284BFF9 -:104F50006A2008F2AE3DC781DF0FC9E73D8610F336 -:104F60009BB1F18FBE78059E4B1279B684D833671A -:104F70005F81F936AAF25A133FA729DB33E1BC7BE4 -:104F8000BB8EDBC1BC7CC4E65F88F304BEA4F6DD47 -:104F9000D11B7E5004FC7476EF0FF341CEDDA8A741 -:104FA000FB8451E45A593A936B833AEB4A897EB7B2 -:104FB000C6E66F013A7CC7326F3A1C319A9B54A9FE -:104FC0007700BCC1E7B480D7644E278ED90C3E472A -:104FD000B54F823CD476131B37D92F7BF15C847F8D -:104FE000B6741B85BB5D62F29B7E94887655A19258 -:104FF0000871C8267EEE55CBE58896CB917F6E1B57 -:10500000C897A9C1784DEF135AB0E77FCBE3E2BF51 -:10501000CD519F9FE87133B8C5739656B902E8CF5A -:10502000A5AB3A524BE940ABF78470FD326D1837AF -:105030003E602B770FD0EFA5EC1F95423E777BE6C5 -:105040008F4A21BEA7757ADCBE98728F9BD17F35BF -:10505000B403BC595A4BC1EFFBB5F59748FB2BFA8B -:10506000F2FD0DF56360703519A359706EFE59930A -:105070007F3BACFF85F9C7302EFC40FAD1F721AF5A -:10508000E3A88ED15D3093E7E393EE690994EE0EC9 -:10509000E739785E0A8BBF1E9EC0FCA8547EB1FC27 -:1050A000D18912E621D6CE66E7626F26918E01FA8B -:1050B0003D3A5968FDF48A1CB47F6B799EC8F47739 -:1050C0007C09B07ED36F8FCA20F7C7B2E76E74EB4E -:1050D0009481183EBE4951976F2E5497BFE5519762 -:1050E000BF5DF19709B16593D97B10E8F55589DF6C -:1050F00047710DB1237FBAA420D85D935F4AE7E7DB -:1051000089593EE54FF97EF1A50A82F5293B8D5B71 -:105110008D50CFFDEF5A5E3FD94D8CD94EC407EA72 -:10512000E9A8C4F3325D1893227BEFB1333F346DAD -:10513000ABA7FDEC9DAF201FA75835E49BC0EBA5A6 -:1051400046B4C3045FB49B287D533C968F339A8149 -:10515000DEDB759EF5D097D66C50402F572618B1E0 -:105160006FED3FC8A8D7969B0CC44ECB071F376383 -:10517000B95C263EC823A120CE86E7519D27D40ADC -:10518000F3A5ED60BEED0E1657D796EB51CFD37E4B -:10519000715D0F3EA109119C7FA58CF9A61C66C10B -:1051A0007774247CFF34E76BAD8684518EA5B37B86 -:1051B000390ED1FEA1DF83BFD2F6A0DFAE50B91306 -:1051C000EACF1B27E0B9A8C0D0792F5903C015DA60 -:1051D000B97CE867E7F2043F0BF942A55EBE2B8578 -:1051E000309014F80F053B05EC0482FB0011B7CC9E -:1051F000348A7AD90BFDA60DB567E7E05278995647 -:1052000085352560A7BCF127A0C3B1E445611A9399 -:1052100013E229E4C516C3C3476AAF196D3D0AEF0F -:10522000C7F20C9B9DADC7840CE04BAD794206E8FC -:10523000CD768747F1C5940BE9766AAE13F045DB6E -:10524000D1F2AD35C7F2E518FD5498C6E4006DE71C -:105250004DA2F01E342919C0BFA38CDBCCC6B57C8F -:10526000BDE3BAE9B8B4DD411B1D97B6DB663284F5 -:105270003509A38D5FA1C078971A97A21D913F832E -:10528000AF03A59320F8C10EDA3448AF3378BEF2ED -:10529000C164361E2954E7FFE49BE9F8985FA6CE67 -:1052A000F7B951DAD4017AFA6953C256A0CF373828 -:1052B000DD1CB6FC433ED8696FCC2B388472267156 -:1052C000790710D10CD28BF246C8C10B69C7CAA1AD -:1052D0004CE5E18D6974DE0FE41E9D079D1F723C55 -:1052E0009D8FF6A5D95B935636127E419F026EA024 -:1052F00053E08B213A8D835FD01BB9A51713253757 -:10530000533B179EC2EE25A495E5C52B99C3F3A385 -:10531000443EDDD8CAE6D11844B86F74FC18F3E6F1 -:10532000EE18E7FF1EC035F7CA4FF0BE22E29E3FDF -:1053300001F67714DE7969C9FF7BF0C6DBF997CAFD -:105340000F1F8BCFC5F8D2AC9D981F1E986DC57CE2 -:10535000F1693C3F36D0A0C1B800DD0FE23EA28526 -:1053600018432097A772BB5C9C5B784562FED6E031 -:105370008B06457D3F517CDEB88279E9C1652CBF43 -:105380007CC87E6F56D07E1FD273FC9C44773193CD -:10539000EDDDF728EAFB89E613F5FD440BED2171FD -:1053A0006F8A94329CBFDFDD4390FEBB6DB9589F7E -:1053B000AE65FA887C83E9A3EE1CA2BA1F699D3909 -:1053C0003411F394785EC146C83FF86FF20B7E9AB1 -:1053D00026A9FCC243E5AFC92FDCE6F0EF023A5B39 -:1053E00058E4CD92283DD6EB997F98D2EBA6088160 -:1053F00074C5D67CD8A7DD445ADFD2E421BDFE02B5 -:10540000E97532A5D73C15BDEE61FC1544212DE8A8 -:1054100075884E0BE3F300FDFB60DC6E47EFEF5B3E -:10542000605FD36FF0B03C6896D7192F1F62E059C8 -:105430002033785C5A2DC2F33AF4130FCFE5F04DC8 -:105440002C9DA612C61F63F14FAA4C82B69261FE34 -:105450003199FD6FC1B8437CF408DBCF8E805B6B64 -:10546000457A9A73078B7F052CCC2E8038581A1DED -:105470007F261F7F4EA7AFDA01ED664A0C0F61FA57 -:105480000F857F16AF9FD9DF8C7970B3AA75C7637C -:10549000ED20212F45DC6D2E6F7FAB7DA60EF2D265 -:1054A00067D7AAE35D73EF64F1B639B3D5FDCC25B8 -:1054B000AB3FC17C4DD2AA03FCCDBD535DFF49DAA1 -:1054C000509C6C02C4C90E713FD020E513E0A3D7F5 -:1054D00093176FBA87D2F9849F149580DFF0869472 -:1054E000C66D4FD0F2B31B2761F9F594EF7EFF280C -:1054F000D46F29C072355CE204FB56E043CA67856D -:10550000E577CCC849007DC2FBBD87E07BB7D9DF1A -:105510003D93B6734FC9C53CD66AEED7185CC8EA4E -:105520006FBED2C65295EF52D05F5C6D66F7351DE7 -:10553000297EBB04F2AAAB7379B9E4D549503E2465 -:105540007D82F73A9C6BB6CAB00E2DE9CCCF3EB93E -:10555000500A4FA478A976F2FE9BD9BC6A4B9E4BA9 -:10556000073EA9AE62FD4CF65476E6413BCD792C60 -:105570009F4B372600FE05BFE5F07D95B02B7D5C87 -:105580004EBCE43DD69144FBF519250F4CD1577123 -:105590008CDD4B6665E7037DDE1C19FCF4D3BC2C67 -:1055A000EFB6CAB83C0DE4E12D7E7D29CCCB6E2C44 -:1055B0003E0479118915956598A76D24B8BE94FEAF -:1055C000C7A7033F5EFD495602109D554DFF82BEA1 -:1055D000660ABAAF56D337E5DBC9E9659796DF2A85 -:1055E000FA360DD3F758F63E85AB02E1FA865AAF8C -:1055F0000D8D13C79FF1E38E2537E02F56FE0EC3A6 -:10560000D78B7C9801D98D79C0A75D824F6F023806 -:10561000F49A089E8FCA963C93F0807185C7887A69 -:105620002F8E5F057C99E0332F190917FCC9C26ED4 -:10563000657F2EF0A364F07AFA9D973887E1A2E3A4 -:10564000DF910E7AFC1106CF66A995C919BE2F11FC -:10565000FE971631DF3EF57CCBCDEC1E0337F8CB41 -:105660003076523C6908EECB5807319F00D7E7B33C -:105670008D3E9B9ECEED36473DD2CFED54A33A28CA -:105680005EC274FF0F701ED404F7C17E6F21F162F9 -:10569000FC9CD247203DC66E12F0C6E3A9650CB94A -:1056A0001A3F9F78FC0CAF5B240D9EE2FCE1D07C9E -:1056B0002F739EF1F68A4BAFF65B3AB97FD139EC86 -:1056C0004F2C84FA5A62F6A03FD123E17EAF96DADE -:1056D0001F20A76B6B08FA719C560DFA13851D32BB -:1056E000169F5CFF4D26B76A9B083FF7C8E6174F29 -:1056F0008FA964E07E78D61A950D0B80FF1BACAAAB -:105700007306B556168F784EC8113250067A7FA8A8 -:105710003C42EF0F94811C8ABF7FAEF622F37B3BA5 -:105720002F4AF8ACF51C2B03BDEFAC1928037956B2 -:1057300067F7FE14D655DC13198FCFBDE91A919780 -:105740007259741ACF47220E7AC4E67F393DC63F9C -:1057500075568AA09F75B5CBCEE7E7CF017A76D88C -:10576000732AC1EF34DBD8AA03BB38D1E13F90CE16 -:10577000E4E8175FC0E6179A523CDE56ED7F5866A4 -:10578000C3221EEEE578B881EBD9F39BB4B80FA91C -:10579000F6163E0DA1A0C09B3A1242BEF5A27E14A1 -:1057A000F7C69DA7065518DA3F6F437DBBF857F53E -:1057B00018279BB05E4394187D39316456DD7F32E3 -:1057C00079A75355BEA2375DD5FECABE5C557D7123 -:1057D0007892AAFEAA374B54E5B2C85455FBABDF0A -:1057E000A95295AF1998A16ABF03F43DC5E3374E9E -:1057F000CF52BDFF68E3F437213E7D5DF43BAAEF55 -:105800004F703F04097A238574FE0B04BD5EAC53D0 -:105810007D4FCD9AB0540E7CCFFE16AC6679F795CD -:105820001463B1FD2DEC52DB13379028E62BB684C0 -:10583000244F9840DE9DBABEB1AF07F17AA97B0F25 -:1058400026B8E66BC05497C6513B632220825C0D9C -:10585000798363F1FBA5D6BF80E47FA9F537B8D57E -:10586000EB6F52D4EB6F2954AFBFCDA35EFFC40AD8 -:10587000F5FA3BBCEAF54FAA51AF7FB24FBDFEA986 -:1058800073D5EB9FE657AFFFB806F5BA67B6AAD750 -:105890003B7BA97A5D73824B54F5F17420E849C8CB -:1058A000CFBC95F7AADB53A46862E842D0D9025F67 -:1058B00003E6638DEF7A48355E3C7D4C203C8FF4E7 -:1058C0002BD247E5386E7F72BAA07AA96A5C32DAC9 -:1058D0001937C073EE046EFFFB46B73384FC8AD5DC -:1058E000EBB1FBE6B1E4DA087DC5F7D163EA2BD86A -:1058F000479B86F7D163D1EFBB84EA591C7C35FA0C -:10590000CFEEB033380E9A993DFF29545D43DBD179 -:10591000361514DE77613E74FC77CD93D10FF21DFE -:10592000D2AB8371EF24117CCE23517CFA895D7553 -:10593000BE6501F1E9B95F6409E0A9C938500E7A82 -:10594000FFC2FCA3EF637CEE48D265DD07721CE268 -:105950003FE30939C5E5C9498803D1F23913F7276F -:105960007A89E28AC1E729EEF7AC9B26A19E255AE7 -:1059700033E6B1D5DD2EA19EAAFB0FF66C1FC7F44E -:10598000DA88E75281D72E6E1F303BA10F0EDD6201 -:10599000FC90F8AD688F7AECB0DEB43F1687F9471B -:1059A000767FB1DBC8E0DC2511B9C289C70671DD9D -:1059B00061FDE17C9BDBC8E0DBA52346C0EF64E230 -:1059C00047FBF031998A3CD6EF24D6EFD15CF01733 -:1059D0009ACD6F7EAB1AF2A9E5E072F4DF7F8FA853 -:1059E000FDF777B64AE8BFFF1E859B3EDD768F1B2D -:1059F000F4B228EF02B8211E00EDE8FB5477AB04A7 -:105A0000FEB1AFADBF3D0FB1765FB2BFA17E0883DF -:105A10000BFE603D857F3683D2B781D2CBB6EF11C6 -:105A2000F41FC6FB6BC769A90681FC311DBB97C07B -:105A30002DAF67FBE2C31EBBCACF44740E38477A52 -:105A4000297B0EF2BE4FC59CD3A07434EAFDBA1F69 -:105A500065B07CA4F6B6C844884B9EE371D787DB5B -:105A6000DEC4B256F6605E26DCF7E588F95EEFA28A -:105A7000F531724EB6D2EF63E48DCEEAC3CB6B1E26 -:105A8000698B60BC53C7EF257B34E35EBB3FC6BF69 -:105A9000F2CE386E271983C49E42B8694FFF4E4F2D -:105AA00023403F5ABB7C2A761F6D70D3FE62F5EE11 -:105AB000C564121B7F58D9F60EC2FD88E4F7436710 -:105AC000867C1236517C1B6438034DDF6FB811E5BC -:105AD000AFDE76AF07EEA11A0B7F06B77C21567EAC -:105AE0007E388EDFCFC5E5E7936DD1C9304E7BDBC5 -:105AF000800A6F5D6D17F1FD9A3652C4EA3FC47A91 -:105B00004D8D82F4738AD24204E27AF2800DFCC198 -:105B1000D43E26107FD6B98D186F30B818BCE4A2D9 -:105B20000BE9639E9DC1003EBF4C4A1FEF2FD5E19C -:105B3000FEFABE4C2BB6BFEF37E30F7829DFEA2918 -:105B40001AB47FC37C86C761F8D373F94964BF0F69 -:105B5000E4803E5DC63885D33E0BD7F1CBF627F007 -:105B6000AE3711CC47D6675AD15EB85C38DD196ABA -:105B7000BCC7E38FE209E5FF7D1C4FF73DC8FC93EE -:105B8000F7DD4FF03C05594AFFCA87E96A1C978741 -:105B9000A9C487CFAE362A080DB05E46E29F40ED1D -:105BA00011D28B8D4DE0A7827AAFEC80D48827AAE2 -:105BB0005D33E1B9A6E26417B0E3DA6B3F8BC01343 -:105BC0006211802F7B0309C155BC98AB40C777F8A1 -:105BD000593981D727CC65E5445E9FE863E54CEFF2 -:105BE0000B523500161747CBB43A6FCA0779BC8001 -:105BF000B073F1FC7E8DCD84CB0BAB736635D4DFF7 -:105C000049F09C8BA8FF09AF4FB31E5F99077A63D9 -:105C1000B6FAFB0D1C0FA9D6E35DD330DEA6AE1796 -:105C2000F1AC64EBF937F1FB2275FD53FC7B9BF57E -:105C30007C641AD4E7ABC77F9CD75BAC2CEF8DCAD2 -:105C40007E767F03AF7F8CD79BA01EC62F64F55A4C -:105C500071DF096FD7C9E118E2331E430C2633BF49 -:105C6000F2963623F2573CBFDD07F773950DF39B91 -:105C70007D2919F5DE86FB3298DC495006BCDE51E1 -:105C8000E4A2A877DA65CC37D0BAF5484F062B974F -:105C9000279C1F87E489D4EA6144C6E4F4A5E89A06 -:105CA00012F005906B59F40FE83AE3FB1AE28F917A -:105CB00073E94D66E28FE583054E5539E5CE74559F -:105CC0007BD7EC5C55BDB57492AA9ECC76229FDC46 -:105CD000CBE9CB5C54A2AA17F765906DBC9D9DB52E -:105CE000D3E54F55B53B5FA824028D9FBA49DCA38D -:105CF000E631827CB8D7969B0AFCF8B3B60A444ECC -:105D00003BE527F6B4F3A71B8C59FA5478B910CBAE -:105D1000CF3B587E7F7B9B879573089EAF6F6FABA1 -:105D2000C1F22ECA9FF0FC699B179FDB6959A1CF76 -:105D30007FA4FD2BB49F1EDA3F949FA1FDC3733354 -:105D4000ED1F9E3FA1FD43FD06DA2F949FA670C173 -:105D5000F329DA0FBCFF31ED1FCA4FB4F9B0BCB65E -:105D60006D2E961F6FF3E3F3B1B6067CDFD9D68AAA -:105D7000E547DB96E2F3E1B6203EDBDB56627D2FA2 -:105D8000A793E7F979DCE72BD9BD03F1EBDF9F217E -:105D900061BB2F9D9F534A157AB92A3FA73F03FC49 -:105DA00002BDEAFC54C01FC26162788C87E36806BA -:105DB000B30F2791C8720B931F18071FDFE75961B4 -:105DC000A1FC35AE95AD7B4E5F14EBD31AD8784766 -:105DD000B99D405C419251CE8E9B43BB7352A4CA85 -:105DE000C2F207D00F43DC143FE5EC5A7246E621BD -:105DF0000DC02557503D1E33AF217C39189C80B70C -:105E0000D1E0FD578E376D692FBB5FA7A62B0C6CB9 -:105E100066F6B6E2FD3AC6B9BEB04C9F2E9F1FEFA4 -:105E2000E99874713ADD2452F976F19B44A1CF8C44 -:105E300026F5FE317D41896A7FA6BDB8862857D1F7 -:105E40007E8BD4FB3C73FEBDAAEF8C190FA9EAF53B -:105E5000AE15AAFABABB731E71033EC7B1B89961F9 -:105E6000F5720221E485DD4F205CE64C368F73929B -:105E7000C27E5F6037FF3D13BE7F79D6CEF1655C91 -:105E80008DFBF2090E562C480C6A400F7DFC8B44AA -:105E9000947F3B9ED1A09F7E22096940DE4CA6E6FE -:105EA00024D45F01378C6BF1AA262D948B89A285AF -:105EB000F255248AFB3ABA7FD164D2F56BD1FA9FAE -:105EC00031D1F2D94CFFB32CBF308CFABA80AF6716 -:105ED00081D8C7AD97E3FDDCC64CF437A9CF257652 -:105EE000F0FD4B8789F90D973BCA53C10E3E3746EB -:105EF0003EA8CD7DE28D0514DFB6B463F814EF1F24 -:105F00005734A39ED7CFCB94BE5A5EF77AAA4FD40C -:105F10007C9307F3385BFACF29E0766BC98F22FFB9 -:105F200074E8843C5312419E0D973D8924661E3BC4 -:105F3000DADEC9935121FA116F325F37315FF94FC1 -:105F40009576C84B2CE079D13BDBD2F2ABC70F7F03 -:105F5000EFE37450482235A05F0B8B349E1074E041 -:105F6000B5ABFC31A6FC2E2F9C0B934B8807C4F2DB -:105F700044D285F729C87FD5623E9A7CF01AA25098 -:105F8000FBD86A0D9360D170BF84FB75BECFE5FC72 -:105F900067F66A9C8F9C25EC260FE874F299D51B56 -:105FA000013AFCAC5BC7D8F4B8BABED04A50EF2D6A -:105FB0002AD4871409EECBEBC27B40E52D12C9C869 -:105FC0000138A6B9E7837EDF6B413AB6AC2FC79F95 -:105FD00030B859E3AF40FC0E287B35C2E8A2ED9AF9 -:105FE00027EBB7823D3901F06205BCDC915F0D43C0 -:105FF000E717221E17F2792FE4F3E8C81CC23F838B -:106000008778BC701FEFA26EE18F52CFF3F1D2AA56 -:106010006FC3BDA2ED112DFF9922353E57E92253E2 -:10602000E64BC37051381766825C01B8AF820FD857 -:10603000FC9A9F91C8C61C946B35686F9469303F79 -:106040003D9E2E9B3299DC8F66D8D97DE4EE534875 -:10605000CFC3E5936F2C48C2FD33B35B6C32CB8F5B -:10606000F47A9558BFF72AE15FE4E772CC1CDEA111 -:106070007B0527B1BC602B89AC87BCB4B1F6F52B8E -:10608000327370DCE17D3DB55D203FA5CC88795C45 -:10609000AB443EA172549969634F385765E474FA72 -:1060A000A84D9DF7B39DCF6F3B5F8F41A3C87BF297 -:1060B000D616C79CF3A9EBAF473F9688D30E72FF65 -:1060C000E1A0591D576DE4A43078A8ABCA0CF1C10A -:1060D0002E16A76DECBF99DD6BBBEFC7782F30EDA7 -:1060E00053017AA8E7EDEB57AAFD580B77FA915FB9 -:1060F000E3FD64F17E318A393DEC1FE3FD625B33E1 -:10610000F97EC2438A210E7B6275DE6133EC7772C1 -:10611000089E0F1FA77D01EFDDA6BB812EB84F970C -:1061200014B1FBA3E2D7FF54961EF1B253ACEF7843 -:106130002BDAA53BCB981CD879E0FC2DE3693F2BEB -:106140007324D5F98095393A5CA7B7297DC3B397F5 -:10615000909AD1EE293B94A9F96A72EF5AF5EFC1F2 -:1061600034F70D1CB62828FF5E03BA1F3CFC7942A9 -:1061700011F251147FBFC408C23099C10DE7B37644 -:106180006B3E99174B0F6F67CA58FF36A78B2F0DC1 -:1061900057B51AAEB3456FA5CC6070FD0EE4C6B915 -:1061A000F0F194587B46C0B57B8CDF03F8F0ABE28E -:1061B000A942AD1F62F074FABFC3D36EFDE8F0FCD4 -:1061C00095C3F3B343EC5E9B91F55F519F75ABE1D3 -:1061D0003DFB7C640E88490AEF5F117FEE9329181E -:1061E00013E6F8EB2DE5F459CAE58F07CF5091C0BF -:1061F0007B57631E66AF4C926AA15CBE007FF72C92 -:1062000093EFC3021A3F9EBF21EF1946957FD764D3 -:1062100031BADE9D2E8D8A87D22C36CF0347EAB263 -:10622000C1BFF1D83B0602726133CFBF7ECCDE6BBB -:10623000847BA6051EA15C429F017D741128BCC70A -:106240004A3F332AD651C6D3B0F1D6C6F18D184F86 -:106250003CA76415327B553AA48573386BAF7D0B30 -:10626000EF7F5B5B2AA3ECFDD2F85F1D87FFF05B3D -:1062700029B7307A999245E16B91FE90F06D5A0EF4 -:1062800048D17F2A827C15BD1FE71FA078EC91467C -:10629000E2292D8BD18B989F98BF80DB76DD025C45 -:1062A00007DBBB06541AA5BCBDD017895CFFC1BC77 -:1062B000505F5C2BB3734C6532AEFBDA8AA978EE83 -:1062C0006C37CF17895EA31FF577441670BC3D76F7 -:1062D000F1B711B84739D8AFC3FB3F883CE0BE15D2 -:1062E000EE1FFF8D8CF789537AAA81FBCC0E1C39E7 -:1062F0009F00FBEBF9593A847B3E97878317B535AE -:10630000781EECC867766D0CFDD76569B97D12897A -:10631000C039AF3525EC3C8B95DB03D623271B001A -:106320007E6BC543062986DE66651910AE35FA68B0 -:106330008A87F617D8A72561E6FFC17B1987CEB3F8 -:10634000DA191E5A4A0FA1BD60ED67F735D66529E7 -:106350004CCE52B8F7D2F7E6899FD9EBA1BE948E06 -:10636000973BFCBDCDCED6D35CC6EE4B5A7BED3F02 -:10637000DBE13EC844F81D47D8EFF2790AB89272C3 -:1063800035BCDF482417F8CB2E63BE5A6FF85E2366 -:10639000D8FB822FDECAD562BB47F93989472B0A61 -:1063A0004370AE4CD0B135DBFF4016CC8FF2C50B3D -:1063B00068EF447CD3103FF662C833DF2545E632F0 -:1063C0003B446F073E2CD46854FC16E1EB269E54E8 -:1063D000FDA3DD733FA75DA1F73B424602E74DFEFB -:1063E00078716622D8A71D19C2DEF31A015F9B25BA -:1063F0005F620E8CF32F5ADC0F1E3872BC01C6EDA3 -:10640000A0F302BE7DF875EB6AB0533AEC5EE4533C -:1064100031BEECD0F0F560FDECD67BDF047F64D4B8 -:10642000C1EECD3A38758611E89FB6D3403F7FA0C4 -:10643000FBF7F004E8A71AFD060BEDB3A6C3778BB4 -:1064400088FF11B06F17756B55F7833CCCE5C5C25B -:106450008B16128ED92F2CACF80E9E6B5C78310106 -:10646000DF3FCCCFED3FCCCFBDEDE2F878993F5F79 -:10647000CFFA8AFB6F4F9CDE4AFEDD8E3AC6F7BB31 -:1064800060FD9AA5013DA8FA35533FC7F3647F68C4 -:10649000B393B02106DE11F34C22E1987187DA5DE7 -:1064A00034917052ECFA32FA1D9EAF15EBFFD0E634 -:1064B000463C8EDDFF38151E87FBCF53E17164FF2C -:1064C0000558FF87B6C24BF43F798CFE7354F00F2A -:1064D000F79B8FEFCF1DAC7BD642F9EE6078C5C637 -:1064E000574BE1F7F70CF87B1BA4AFB70ACFB9EE17 -:1064F00022780EFA81FD7F7A1FF2521FD8AAF7C0C8 -:106500001883BAE83CCF287A269FD88370EF9C780E -:10651000BE9D9587EB1CFFDE2887EC90676A2C9464 -:10652000EDA0E78C24125A01FB975223CA3911DFE0 -:1065300012FDFE3453AB92B3E27EA1469E7FD86833 -:1065400061F1AF26ABFF2CACFF124D57CBCF681FCC -:10655000A70B3BF07C3B210EDCD788F88E0CFBC5EB -:106560003C707DF9089C0B9B97E3FF0CBEFB091563 -:106570002B10EFD15EB1CD0FF9798FF37DE4E3A657 -:1065800088DB13233F75D9F257B31BBAE2E8B7ECA7 -:10659000773BC28C7E75D940BFDAC8CFEB72E07C06 -:1065A000E300BF674E41FBB9AEF430DE475927FC2C -:1065B000022BE3F356321D604F8B785402E41782AE -:1065C000DDB086DD53586F61E5FA5F27E1B917BA90 -:1065D0001FB214819CD9AD65FE221E073BCF611E00 -:1065E00034AEC902FC0EF27C97F3FDAFE1BDA7E724 -:1065F000578E473AA8FFE50FF11EC3DDE94C9F0D0A -:10660000EEB3A13EAB3778CAE15ECDDDE9CC6EEDED -:1066100095C309253176ECA3195528A73F5E395E4D -:10662000131B27199FCDE4C21AE1FF94A3E570CE96 -:10663000EAE3D2F03FA13EDD63C2DF1BD3ECFD53A2 -:1066400039DEBFBAC680BF6351B577E2BAB9B05F71 -:106650004C90311F5BB3D784F09C5DC5EE83836F94 -:1066600041EE35EF1D87BFCB566F8962DE64B3D92B -:106670005300F1C1FABDDFC0DF9F38F1F8C42C90A0 -:1066800083C793952CBC6FFB718A743AEFE3FB26AA -:10669000B0F79D57E3B96ADB1A8B7F34FF88D04B84 -:1066A000F1F7CDED4E2F3ED707F89968F4801C5EC8 -:1066B00038E45F67F707D6BF199DA524A0FF06F34E -:1066C00017EAEDA7F0F71DEBBB8FDD49303EE9423D -:1066D000FA15FBBCF871EBB9FEDAAD8FCE83DFD5CE -:1066E000AB6FE7F8E7BFF759AF29C6DF9B14F85F38 -:1066F00013771FF3F738DEC5F3C41119EFB9A47689 -:106700004516F88F4EEC3720BD9D583319EF5710C2 -:10671000E3D55358ED944F8F3B9529B0BE0BB2157E -:1067200036FF76B67F15EFE9F811F8BDCEE83E2DBD -:10673000E6AF0DDAA30910C714ED4479683EFD5A9F -:10674000FCBDB7DDE90770DD295D11A02BCD2F6DF4 -:10675000A8B703BF64BF1BF7712909829F34F88E65 -:1067600001F77B07F719D09E1E7C979DCF1F71EF15 -:106770009F359A05F7DC067E390EE5DA6066740B04 -:10678000B3BF4D78CFE4E051FFD53C5E9CC6EFD15E -:106790004C03BBEFC23E5318EC3EFAC4B843906CB6 -:1067A00073E3FBFD16BC2F883ED9F924698F1B7F4C -:1067B000378974F1EF23F8FD0359FE0920A71FC89C -:1067C000A3FD5BE1FB93D8EE42AEFF4A8C591192D8 -:1067D000CEC74BC77E33FDD9F85EFACCCD7E0FA86D -:1067E0008BD747B03E60F05F8DF3F8BD8DF48C32EF -:1067F000CFAF7A5FE47DD949B88E026E8A67B42341 -:10680000E3F1D293CDF69F021FF17439B49E9780C5 -:106810000FFC3278BFC03EB68EAB26EA993CE99CAD -:106820008CF632DE30149327B87CDF074897833A22 -:10683000EFD3A097A2477584DDC3482D03F05754CA -:10684000B076F516E6F710709CE1E7071A3B591E83 -:10685000E199E73EC89A6F85F3F31FA8CECF0BFFEF -:1068600021ED2401FC33568F925057C4EC762DC293 -:10687000C57E8F6E8D4EC1DF0B0C3E3E11FD122783 -:10688000F4CA5EBC0776D5151AA0276D3197BF4FA5 -:10689000B07989FBDDC43D6DF17819C866FAB2990B -:1068A000F8EF823BFE8F132585074BF1BE4A74FF3C -:1068B0006B20CD52F69A587E3BEA8591F742EA2F3B -:1068C000F17B82FFBBE553B05665809F6002E8D53F -:1068D000D376B67FC45B2240BF6BD93C3BE003B8A4 -:1068E000FF82F84E835EC45B25281E4E4BAC3E9E55 -:1068F000CE84BC1B810FA01BE817BEA37D7F9E9D8D -:10690000C3F63F76273F9417D4435EAAD057014978 -:10691000D6C07D0F271D4A02D0E5C9CE3CE772C81C -:10692000F7712829B1F676E010C17B0E1438FF7399 -:1069300035FC2E92770AF805773BD5FE8878785E8D -:10694000A81C40FDF35F98C6C553008000000000FE -:106950001F8B08000000000000FFB57D0B7854D5A8 -:10696000B5FF3E73662633794E1E8484409824E436 -:10697000018430090F4141074810156878092885BE -:10698000930710421E88B6175BDB0C24205AB441D3 -:1069900051D18B76404154B4414141037700A55811 -:1069A0005163D5566DCB0D88BC1F31A897FFADAD97 -:1069B000FFF55BFB9C64CE90A8B5B7F93ED8D967CC -:1069C000BFD75A7BEDF5DA3BDF7C433FD7096175D2 -:1069D0002B42F41022CE6D11629810A3DC82F34298 -:1069E000D885C811FCF38DCA89DB3A5C8885F88D9F -:1069F000AAAAF9DAB59EC82BEB2D5C1FE375467782 -:106A0000F1BDF1B5FF50F228B3214C0887FE3D5D82 -:106A1000880F311E8D7BEA90DDA70C461A2EAC093B -:106A20004254AC75FA451AA56F4ECCBA53E685426E -:106A300075C76C5C99D84AE3966F2ACA1291B21F47 -:106A400041F3AAD0E7559EEACD52870AD1F6A8EACB -:106A5000DA84F6EB559E8F6AF3B81EA5EF27D6DBD6 -:106A60005CCBA99F0A7D3E277A6BD1C5B994B70A42 -:106A7000ABBD80F2562DDA45FD2E78542DF677B158 -:106A80003EAAF781B5A00BF8604D893A7C32A81E6A -:106A9000D66994E3BFF7687257D1FCC2E977CC633B -:106AA000A3E2F7D1FC4EF4D1E6217FFC9330B18212 -:106AB000F2EADA45D1EEDC2BE17DC2A1457B720121 -:106AC0005FB91E039EA1E318F0BC0878C620BDBACA -:106AD000C54BF0AB7D48F5A0CEBEE64BD180DF982C -:106AE0003D4547AEC1F7B561228CDAEC3B9CFECE4A -:106AF000AD348F8BAB55413D8AD23D198982C6DBBF -:106B00006EF97C2EE073BF4DCC7A91D2D2B7A747F5 -:106B10005B28FD46A71FF5210927356A7AF47CAE6C -:106B2000DF3EB998F2C7DC9EC482A07A3FD6E92C3A -:106B3000145F656BFF168D712AD6D8785D065E2EC0 -:106B4000621D34BF8B8D11FEE504978BBDDBB85FF2 -:106B5000034F46BF15C083414F546FA5DBA58FE39C -:106B6000B31747115CD3B4E19E2EE864C183342E81 -:106B7000FA5B1FE575E67DFF710D7874E09B962545 -:106B80000CFC038F4FA46DBC97BE59DEB30AD193A2 -:106B9000E0D0787DAA42DFCBF6840985FA2B53DA60 -:106BA0008E28099C77FB14AC7FF13C8C57F67198CA -:106BB00005E5C7F75E9FC7F30AC12BC129B52B7A3C -:106BC000BF98D696EA0982DFC53E6D7379BE067D11 -:106BD00074CE9BE751BB374C605F5C4C237C4676A0 -:106BE000C2B101F819C6F55D76A66F6F1EE0D7B188 -:106BF0005E57C87A5D21EBFD40307D0B8FC6EB29D7 -:106C0000FF24CC82EFE50FDC94E5A6718EDF3B8E8E -:106C1000D7753CCE9B87FD753C95FACFBD729DE53F -:106C20000FD03A73BF659D8D4EC657B7EB8C6B7B0B -:106C3000427CCB3A37EA7468ACF333AB3BDA8AFA7E -:106C4000BB55B19C8A6AFB14DF7F8DCCBB56D0D07C -:106C5000B536490FB56B23FCC0D78566DB047F6E64 -:106C6000271FA0F1BE273D58981E8E8F753F3C020E -:106C7000F4759FEAF2B9019721EFFC9CF2C7EF5738 -:106C80005D02F9B1127EC40F2CE00FC7538B27733E -:106C90007EAFCDB582FAF9B4F16F7F04FD5CDC63A1 -:106CA000730B5E5FF1FDB390A7F982AF115C6EC606 -:106CB000B854CEEB57EF19D68872F1E86057A6BBEF -:106CC0000BBE1402E78A35AA691FD201C1E3D53E83 -:106CD00090E2C63A0C381387CD9A3AA8131EC84FD3 -:106CE0001FD409975ABBD09AF8FB12FB944141FC80 -:106CF0000CF04997E744FF3CC9C7D2A283F673C89A -:106D0000FC42F98F51CF48FFD2C157CCFC7851706B -:106D10009EE05019925F1CC237AA42CAAB43CAB761 -:106D2000F7FA9CF940E8F813D3E4BE31E058AAC35F -:106D300071BB45917CE43EC5BF897E2DB5BAED4B54 -:106D400069FE2F8E11F3D04F995538AEE57DD9CE1F -:106D5000EB2BB58A86B0027CF7703D63DDD45F43D0 -:106D6000581CE5C3251FA27A13EC417983DF1AF37F -:106D7000094F93F030D2C55B9D8DC783E059DD1478 -:106D80006BCAD7EE4A6E3CEEE8CC2FC62FC9F46F23 -:106D900022AD7E38E0227FAA77B51E8C20FA49B258 -:106DA00068E169D4EFC583FF1B9DEB66BC0F2F26FE -:106DB000FC16A8E92F1DA6F5B6ED563D9BD0EF9B1E -:106DC000F2FC115F5F7A781B7DAFD99B21EE75775E -:106DD000AE3F148E17775D8A4EA7EF170ED9C30505 -:106DE000C901A5CDF163EDD1BCBFBA84BB5B87BB44 -:106DF000D1DF056B6BF494A07A17446BF4D4207A3E -:106E000029DD75A94EE431FC7C6A101FFF744F8F99 -:106E1000B12A7D2FFB7DAFB1164AC7E9FDDE6F7346 -:106E20003FB986E6EDDB1DE6D94CF3BEF0E62C0B50 -:106E3000DA5F78B3424F7FEAE5F4B34F53317EB463 -:106E400045D2BB31DE8834294F95598E3E311AFC2C -:106E5000FFD59E69F5699DE56596822CE0799BAD2D -:106E60006D2EE67D4111AB95B8CE7EC6A5B9B9FDB4 -:106E700085DD279F007FF8F4FE3E05602B177667BF -:106E8000E769547EE1E321592EEAF7C27DC91EF07D -:106E9000856D36F74F99DEEE89F260DF1BFD619C50 -:106EA00025E87FF755C335A41FCBF9523E4F93E336 -:106EB000FA9482CE7EA32DEE5F8F02BFF8BDCDB3D4 -:106EC0009992A57FCFE8198BF5613F778187B2D57D -:106ED00061C26DE2272B78DEA5C263871C84721124 -:106EE000445FE5A298BFCF6F347F5F407C02DF171D -:106EF000AE377FAF108DAB5A697D8BFCE6EF82F623 -:106F00008F2F11FBDAF869E2F37EF1D66FC24CF5F0 -:106F1000844FE70F0EE6C7A5B41FC1C79E57FCFEFE -:106F200015C0EF3D2AAF33745DCBD3D2781D8F44AB -:106F3000FC636E6B105E8F59843589E07ACC2E1C11 -:106F40004905E847089CABBE3D61FECDD4E4DEFEBA -:106F50005FA59632DF4BB2E03CB8C305CE47FDEDEE -:106F600039998A7ECA5617795B83E677D1E67DE444 -:106F7000E79057DF237E4DF58E8DF5378EA5791D71 -:106F8000BB57F5D47731AF33249FF9E3091EF728B7 -:106F9000C23F84F2CF9C4C2D21BC9CDE7C32B534A8 -:106FA00098FE15312B981E8D9466C2EB82AC89F445 -:106FB00018AD05EB09ADD7895FF37C0D783A55B173 -:106FC000A42B7A7814744FE5397F5705E4CE9A3DA7 -:106FD000363FE83362E3170FDF0AFA6CB6B940DADE -:106FE000B57B542FE474B15BF567E21C6BFE34BAD9 -:106FF00012E7CCEE212E3568DD740E17E37CB9B0B4 -:10700000EB5262592EF73319F244ED9E873CA0DF14 -:10701000EEE6F15C9AFAAFF13FAF99FF9DCFFD200C -:10702000F146F0818D27B2C0DF890F3E9786FD992A -:10703000F5B51D79215A8783FE687E2CBF5FF47FEA -:10704000C5F2A5A359F5FABBC0C39E343BC3FF07E5 -:10705000CF6F02CD2FB1737E349F3DE0CBC63C6B2A -:10706000DC6D769CB3171DD179E0A7B4A089F989AE -:10707000FAF9E4067F2D9B2888BF16EE9EBFC20951 -:1070800079A151F1400F286F56F9DC2ADFA0FADD13 -:107090008497C2ECBBF63B219F3E44E5D474BC3AD6 -:1070A000EA8FB3A8FEC2FB54CEEFDBF8D33FDA8001 -:1070B000D70D3611063C86476FD2C7637968913E7B -:1070C000BF45CD379D56A0B7EC513D01B4DF1CE55F -:1070D000C1F7B2D5B663C1F4351FBF507FF3D72BCC -:1070E000FE401AF884B9FCC2309FCE2742BE6F5CC6 -:1070F00035757F02522BEB898BFCE672FCBC4EF39C -:10710000A9D57FDF9AB9A617F073C129440BF6AB56 -:10711000B595F51D11684D051E2FECFE2C1578ACAC -:107120007DF57FB24417F8EBD84FCD510927228463 -:10713000384BE7C63716D0FDA5C9C55DD47FB18FE2 -:10714000DC175B6DBE5E9063F76FFC8AF9C1C5DD2D -:107150005A5F5717F4DBB95F7D4E4B12D280532034 -:107160001DDAE4BA11FB84E4C17B411F9B564DDD5F -:107170004479E76B364842A2363392F70BF6C7FCE8 -:10718000A07E8D7DB2157C01E930C91F5EEC23E540 -:1071900084D5BABCB0755FFBE4CC2EE6B33ACD26FD -:1071A000CFDB3E926FCC4D2B0E4F879C61F1450398 -:1071B0001FC2EB7527107C159DBEEA972D51F03D3F -:1071C000493472DA5B3471FAB8105A24EA0B8F0B27 -:1071D0007016A24F2CE0C77B9ED7AB31DFFC898EA7 -:1071E0003BF06AD0832F56F837D3EFEA46875063D7 -:1071F00020EDB546A351D4A0A9BFEE4BE5B60F5480 -:10720000D69FD43E063E3D2EE0F7CBC8E931C1F80B -:10721000DB77B87402FAABDE497A2EF5777E874DBC -:1072200004A0575969BF503DDBE12FEC69E04BCD1D -:107230008A80BC5C4B797CAF1D65F5FA83E0929740 -:107240002EE1919A9EC570BB60F51E9A08FA73955F -:10725000DA21D7DB0E974FC079634B2AB5635EFB0B -:107260000E8F75A4016FB156DE37AB9A8D715B5CE2 -:10727000E83F2AF6039E6F43AE454453BB868FC258 -:10728000FC0C4C87E443613A5C1B02850E7717F8CF -:10729000F189C2143182CA77A81330CFF3AE5217E6 -:1072A000F0688B957687309B7702F49AB0D8B878DF -:1072B000CC6F447A06CFFFABD8253CCFAF48BC801B -:1072C000BE41F27A31F20DBDCB55867DE323BC8FF2 -:1072D0006B1D72FCA83D2A9FA362A443E7DBEFBBB2 -:1072E000CA689CC8BEDA24D083319FA861AF0BF076 -:1072F000E71C8B85E5B3863722D7802F18E51BD294 -:1073000025BD19F858996075817F3CAED3E74A577F -:10731000B1A320689DB61E161D5EC50EC069BBBD1B -:10732000F810CE9736FA8E73737FD25407F414AAEE -:1073300067413F27EA68C764A3DFE90EC07741428F -:10734000E978B45B2896ACC27E5BB85E1581203EBE -:10735000DB6093E32EB81C2102433AC75D40F8E39B -:10736000F697A3F97B8353D66B8892FBE7CE7429FB -:107370002FAED4D3B57AFA83F9BAC7CCD7CFC7FE2C -:10738000714BA9E4EF77A653BFD54AEB788826ABBB -:1073900092DAED80EF893A97088405CDF78A75C6B1 -:1073A0008B40D0381DF52E3B45203E181F6EC6473A -:1073B000E77A23B9FC445D12C3B1FBFE534C70EC79 -:1073C000EC3FC304C72BFBCFE2F2137539DFD1FFCB -:1073D000C06EFA4F33CDBFB3DF7EFC5DECD2FA82D4 -:1073E000BFDCED227EC074D3CA7626BBA2FD067632 -:1073F0002FF1719880DCF79553CB7605F1876DE915 -:10740000765D9F0BA480DFFAC43A4E6B775D1A8FCE -:10741000F66EE20B6CE7D0CB6B451BCF13FC02FA88 -:10742000BD48B6BAB97C97960DBDC89847873CF35E -:10743000BB489F85F641D89EBF47631F5FB4B64DDA -:10744000867DAAA9598D08DED707F4FD31B6CF177E -:1074500079B0D7D5A01DF1BD9FEE5D9C0DF8D48409 -:10746000B5E561DEFBF7FE2D0FE7C8577B16F7C5C4 -:10747000F7AD549FE50F7B5B8D27A8BF7EC2E5B3B8 -:107480008CE84C9BF5FD1FFA7DEB9EFA5E98C736A3 -:10749000D83D482EAC59F656C6F178B021EF83E0BE -:1074A0005F82F816EB43BBA6A96320DF7D48320F4D -:1074B000E587EE9672C3D03EC26F4983DCF7E12CBC -:1074C000F0899A61761754E1F0FC1696B7C38739B4 -:1074D0005C389F9FED93C1EBB3434EC840FBA2784D -:1074E000A6E754F1AFC96D1B42F64FE00F35DB68DC -:1074F000BC6AB575F23885F7D131F0A99AB7BF7873 -:1075000047D75F13819F5A8C4BF0785FEF27214359 -:107510003B897A9AA3F5BEABA8DE8C9B9353A11F3F -:1075200095E8FA9998484019C9FC6810EC20579ED4 -:10753000DB520F7A4DD134C0C197ECF0E0FC1A98C1 -:10754000221CC971D8D0FEF4A934EE57E916C32E17 -:10755000AA60DE03F4353DDFAB69692C9F93FE38EA -:10756000D0D13F3BAE25C3FB77F00BA3FE8737DFBF -:107570003A48EBE2DC30E479BBBDE936CCB3AD3A56 -:1075800092F54798F3D0EEC99BC3022AEC8AB6C89D -:10759000D5D0E73F8A987BB007C1E3FE282D228330 -:1075A000DACD9A79C32AE495FDF1EEA5A0E792D64B -:1075B000E1C0E7D34E2D2683C6AF72687D1369897B -:1075C000E7FB68D93138E48BE3259E44F1A0E22E35 -:1075D000E72FE753A2C8F10F476949E8A7C4D2F2E1 -:1075E000C455F8666D617B8368E8C1FD9CB78B8AE2 -:1075F000AEE47F030E47F475ECB3896B2FD3FAF634 -:10760000AD8DF1D4D37CCBEF9E39B796D2F996E20B -:10761000C4806A9A7716D655E52BE99B4CF2F3792C -:107620009B3EEF65FABCADAEACE0FD1C3AEF7A4391 -:107630005EF985C2FA20FF50FE155FACFF5ECA8777 -:10764000592E7D300DE7D6200BDB493684D3DE2260 -:107650003DF25D7D9E8FD3BE73C4F1F7D5F89E14C5 -:107660002EDB273D6CF1C37E503C7637E3E9C99AA7 -:10767000488F4A639508B71D725099F0B25CFCD9E7 -:1076800098BFED69A575156668D7016EF3E22DA95F -:107690001FF03CB48153206F8D92EBF8167993D78D -:1076A0003155B86C2C94893516C81F535D7229F377 -:1076B00015B93FA609AF0DE3CD101AD7FBC305BB23 -:1076C00017FAC41FA00BD1BC670A1F7F9F2DFC9C1B -:1076D000DE2A025CFFC7A295F306BC893EE6254878 -:1076E000FA38D95365F8DF8C79BF1791D76719AD90 -:1076F00063CA23D999AC5FADEBC1F0F9AE794FD134 -:10770000E986F6EF3CF483FD3B9DFA997A63C8FE67 -:107710002DEC61E033F3DBF6514B7B87FE14994C83 -:1077200070B85E47E9F5DEC5AC3F15A991C247F8D0 -:107730006919A5FA21771CF22E4F48A075DCFDB916 -:10774000D4837EB75CBC3D84CA7F374615F5DCD256 -:10775000CBF2D464BD9FC9BDC79F869DF5B00824F8 -:107760000CA5B9175DD65E8FA1F94E56B735C45238 -:10777000F984DEA4C704F1BD1B12B65BA1D7DDD826 -:10778000CFFC7D62AE59DF99241A55C079F250734F -:10779000BD7D800FD1D78A0CA9B788016280EEDF4A -:1077A00063B9FB477A1FED132FD9E10B793543BB42 -:1077B00007705C3AE9B3B9185758E57A6ADE51D9CF -:1077C0009E778CE42C2F9DDFC7EBE8840893F208AA -:1077D000F2A7486E407AA6CECDE9393AE7517EA1AC -:1077E000CE23EB67143F807D56BAFA732BF072B745 -:1077F00053C2F96E67AA1F76B58AA6C6F1985EE5F0 -:10780000AEA68348CB03C5E371CC2E38B4E420D2B6 -:10781000BB3BF4B6250EDD5FC0F3BF5DA7D3DBA392 -:10782000A6DE3488F6C9EDBBA5DFEBF63E53A74DC7 -:107830004A40DEC6F9EEE8A8FAB22234DA22CFA82E -:10784000DECD58B7B7F9E8C1785AE7C9BA113CFF9D -:10785000D3755E9EFFD9BA099CFE3DA3F839AE27C9 -:107860003E67796CD2B6A3D614AA5FE455BCD8B7EC -:10787000D77A85DF4F74B1DE26CF81F5740E601F95 -:107880008F1934F5F13B30E90C6D27DACFB871511F -:1078900011C6993CA2C48A7A33BF16223EAD934EDC -:1078A000BF8BEE8DF557EBF83BBF5761789EDF1B22 -:1078B000CBF06CDF911103F960E9CE8C9E48896FA3 -:1078C0001A7A6F04E0D77ED9C2F36DFF289CF58E3B -:1078D000D0F64B770EEC897A6709DF2248DE3CFB55 -:1078E000FC7FB883CF95B3714D5F7D02FEF657C91B -:1078F000DF48B239F118F85FEF5E1ED0CB055DCEE0 -:10790000263D2302E75F8D6E57047F42FE6CB8B4BC -:10791000E70E7F21652CF617C673139CC31C19B99B -:10792000C787707F477E46FDBDFC589207FAEFB9C6 -:10793000ED8FA463FCAD4DF33F798CFA3FEFB7F8C0 -:107940006C744E9D174D175E051F7E2A92ED7B7756 -:107950002B342F9CC39B7B713E47B1862FC3392CA0 -:10796000FCBCCF7314B77519F1ADAA171FED057ADA -:107970007C8D603082CA5F5B1BC17CED359BE7C8A4 -:1079800032F4F7B8ECEFE9FBEF3CB60BE97DD50537 -:107990007752FA65461CE3A1FC814503D09ECE795F -:1079A000914CFD3DF78A1280BF6AD0BA7D2B926957 -:1079B0007E83371CB5F4A234FF29A51EE9C03E37EB -:1079C0001E82FDF96F196E6E3F645B9A9A826DD9C3 -:1079D000CBFFC9757CFE9BE582DC759F8FED253A58 -:1079E000E583014AD3998D34D7B0D48F0A348663A6 -:1079F00023AF6767F3B4F76F155807491E98778967 -:107A0000DDC3E791DFB711783EAFE57858BF2BF6BD -:107A10003D0A7A3BAF257A703EBD4CFAFCD5A87F73 -:107A2000C4CAEB7CE5A9F7A261DF89213DD909BF72 -:107A3000487EDB78D4AFEEE316F087F579E2FA09F9 -:107A4000804FCD8E9D1BB99F2A8707FA6EC5CE4BFE -:107A50000753202FDE203C99A0C71D32FFAB42AF59 -:107A600047A5A5566CFC52E65B8A395F4CDA27FCC9 -:107A7000FEA24CCA498FE8E7A068CD637EC924EE18 -:107A8000EEC4D7AFA818E5EBD37CC9B06F1BE727CE -:107A90009D7BA9FDB065ECB27DCBD85B53192EDF81 -:107AA000F3DCB3EBE797D1DF2376E173523F30DFAE -:107AB000C09EBEC12ECFEBCDC467402FC6794DE32B -:107AC000E6F593EDBDE0AF29AA326807C123E59141 -:107AD000309637BEEFF8B36256F1F96DC85BB5E189 -:107AE000922FF2D941ED5F88D2AEEE370C76327923 -:107AF000DE0BAB3B17F2C8E351DE6BFAB1BCD59697 -:107B00008A35D0397A1DE653A392FC9511247F451E -:107B1000C67DAF733410E52D42FBEF5B7F6C04CD67 -:107B2000330629F1EF68A486DE455A4897FC397D73 -:107B30005B13F8F34361923F470D61BE64AC33744D -:107B40009C03C40734E23B6FD039A3113F181739A7 -:107B5000C6CA787DDD527590CEE522390208DA1A60 -:107B60003B94F3DE28826361A42AB42EF4472325D4 -:107B7000BCCDC73AC7274498EA1525C4DAB18FBFF0 -:107B8000EFFA551D4F6AB83CBFD47083BFBA137467 -:107B9000BF7DC8FAE57A6F770E63BE3A56F97EEB81 -:107BA0002EB215DF093C8F8BCCE773735CE4942312 -:107BB0009AE075D4E17BE87A43D7251CDF4F8EFA33 -:107BC00089227C16ECC7CFED6C776BB6B53EF75BC0 -:107BD000826BF3A25C0FEC472FD3BE70809F4EB533 -:107BE000B39CDB0CD992EA37F770715CCB6BBADFD0 -:107BF000DC375B6FEF147CBE34CFEEC57EF45E6184 -:107C00003410EC48F5D26FD26C5BF216CEEBE6E5A1 -:107C1000291E9A8150C1EF69CB7CE497FCBC5E09B8 -:107C2000DC0A7F81EF73BB40FD75B1FED5E9945F3F -:107C3000F78B0C9ECF47A48FD762BC8A70E65BEBB4 -:107C400062BDC971049F97FFA1F279B22E9FF29194 -:107C5000CCD7D96EB36E8A37197EAD041D6FEB3663 -:107C6000CAF25EB093A23C4DB6FFC426EBDFA2D7AA -:107C70004BD0F1FBB14EA7B4FF993F689323ACA062 -:107C8000FF77FB95BEC6FB467893E1177AAC3C9331 -:107C90006D98B754DE90C6F4A4DBD366E9FCDCE84B -:107CA000170D1CC3214FCB9FD9F3373B41DF332A3C -:107CB0009C47211F7E54B1220A7AFD0C4D0D842170 -:107CC000BE6A7A91B743AE4BC7B85E396EB9A11F91 -:107CD00006CA00DFBD6D0E712FCBFF8121C1FA9660 -:107CE00081E745FABEAD6E1AF360B07E5D6927FE8E -:107CF0003318E5723F57456ABF077DD5EEBAE1C13B -:107D000060BDFB54F94379BCEFF471CFD5791F3CCA -:107D10009E09396F02A7C6B81DFA11F049FDF6D5C4 -:107D2000CF73DAEF3E0BF0DAE494FA92B5EDE38527 -:107D300094AF9F3580CFF709531D5ED8F5DA77846D -:107D4000F961AFAD9F15EEC5BAEAF744F9615798EE -:107D5000A7EF1BD2BBF8BB6FBB8DE9ADCAEE7F6648 -:107D60000BB5ABDADB9FE989E895ED96BE57236446 -:107D700079B4376DE55094F764FA79CDE68EE1F287 -:107D80003755C1E5E181AC5882779B533B8575132C -:107D9000BDB2FDBCCA2EBF1FD1E912FA25FBFF966A -:107DA0004471BF42CF6B3F8F677D4F58BDC9F39180 -:107DB000BF7D20AF47B3CB7D216AA47E78C425E781 -:107DC00075A4399EF785418F478AB7DC939580EF7C -:107DD00024AFD2FCFEB24C0DC01F6ED09F32F5F224 -:107DE000DB5751BB4F5F55D96F33E7D78B0FE3FBA1 -:107DF0009C15D51339ADBC6B329FCBF51FA7EEA2F6 -:107E0000F284A9A7D8BF6BE07F4E95D99F9A98E9D5 -:107E1000553381DF5CFFF68354FFE1D9271600AFAD -:107E2000C333354726ECDBF6D697FF4CF36D5DFE8A -:107E300027D6A336446B11F87E71F7D35CBF66C5B5 -:107E4000FF2C807E50639574639CDBB53A3DBF91F7 -:107E5000A9C5A2FFAA15BF633D2222B745F2D7BB31 -:107E6000BE1F3F3AD3BCF96585DA2D0E6FAEE154E3 -:107E7000F5E7E1FC3BAB04A2950C862BEB75E75CC8 -:107E80008168E047B348B972F1D610BF315092A86B -:107E9000DB8BA8DDE226558F57F4DB41A7A1F51750 -:107EA000D377AEF73DBF578A26F93D76D7FDD73059 -:107EB000FE4500FEAE33CF646E023D9CDFF9745682 -:107EC000B09F3634BD72BE72FDE7F47D738EBED8AE -:107ED000406FDBC24CF6850BCF24EBF426E9E9C2F8 -:107EE00033D9ECE74ED4F7D905C5670947BB5F081E -:107EF0008E67109EA6E11C97E36D1A0EB9FB619D7B -:107F00002F2E8E6F1A0EBE67F041E168CA63BB4127 -:107F10004E531EF464837F8AE2A62CFEEE6FCA42A3 -:107F2000FB972DD20E63CCA7F2B9148E7BA2B5F0CD -:107F3000FEAE7C6EE026E48D71EA9D92EFD43B2587 -:107F40007F095DB79629EDE8A44FE61EA7B3A43ECE -:107F500096F4825CE49365DE29F30B3794D8E16FE5 -:107F6000AFB7C9BC6B7D89FD18E6F73569B5C44F5D -:107F70007374BFC5027FA9DD0BFBFEFAE5E11C3F70 -:107F800031DB3ECF4B69F67ABB695C030FFDFDE642 -:107F9000EF8BF4F9F40D890BEAA5B6ED0BC339F6B6 -:107FA000A4E8328E6049A6B4E33EFB6C477C91AAFC -:107FB000EBDBC26DD0A15BEA1B8CD78FED065EEFC9 -:107FC00048A1F92FD6E3A55EB648B8FA9E957CE3A2 -:107FD000E57C2D05E7D505C01DE75C2CE57321EF99 -:107FE00049BC1979035FA1F05DF1F18214D8959F26 -:107FF000C894F6C7507C2C8F1ADE13E5065CCFD4EC -:108000001DCA00DC8D759DA8F37AE968EBB4BFAF9B -:10801000CF77688C8F7C47307DD76F1D7288242086 -:10802000716EABD58325D45BFDF743BFA8DFAA36BD -:10803000F904973B80977391FBDF41BD051B620BF1 -:10804000A00F18ED17AE2FF29607CD7BE056335EEA -:10805000063599F3837799F35B71060DFBE7DBE552 -:1080600007CCF92187CCF9931FDC7133B64F85EA31 -:10807000BB5F85BEF3E7F187704E9F7AF99568E0A4 -:108080006BF15FCB0F428F0B8D67213C2AD0737C45 -:108090005B14A6972BE25ABAE14346DC06766230BF -:1080A000DD540ADF416BDA95F5CF8AA69BBD4467A4 -:1080B00055CBDECF907AB3EC7764D35A3BE4CED085 -:1080C00071BBE33B22D2EBC63E2A1921CBAE5E3612 -:1080D0004E7C8AFED6BC371EF458F22B85E59B9267 -:1080E00097B25F07DD1CDD3EFB464E6F9EC0F03051 -:1080F000EC920B9B954014E55D2344877F1FF18B29 -:10810000A50D21F19F6B42E282D699CB17EEDAF7EB -:10811000FF104750E17882E32EAE8C67F41F805E3B -:1081200059794AB07DAAF2A96FC2CCE5725DF3F528 -:108130007518E7ADF05DCBF17B57CBAAE238FEA313 -:1081400073E9A84B3B8573CB3877AF5EB75195F297 -:10815000BCB784FDC891768E8BAC76884004CDEB9D -:108160005094DDEBA2EF97D647B1BCB280E45CE857 -:108170008B940A27C74D7A62D0EEC4BB2ACB65D553 -:10818000F1121ED5BF51FCB01D57C3A88BFC933212 -:10819000BF4804D8BE0B3AF206AD03F80BCE8B46AF -:1081A000A95F565903FB009F8E7368ABB95E15AD8E -:1081B000F3A338C87BE6EF35A28DEBD7EEFA262C79 -:1081C000F87B903D9AF55E43FF5675F94AFD653898 -:1081D000CB4F74208483BE6CBADCBEEE1E92236843 -:1081E0007D2B0D7BF85A29DFDDB2519E63249F67FA -:1081F000014EEBD6927C86EFA46F20CE442C0AF77A -:108200004BF95EEA0BEB6667B15CF4F23F5E0A4045 -:108210001F697B4861BBD2BA7CD9EFBAFBFA7339CC -:10822000F8A7C2E384B11CB66E8A51DE87F5914F80 -:1082300030C564C8F9FAF71E6EFEDE4BF566C13E26 -:10824000221E74B27DC490FB0DB9BE2E56CBC91A46 -:10825000D6B9FE75B16D51F0BB898AF8EF25B76CC0 -:10826000D6CFE3365A3FFC2AC795E283F08F19F543 -:108270004666C97365F858EF16BD1EFB5FCA2D53DD -:10828000EEBD8EE655FEB0C50D7BA18107E1F5661A -:10829000010EC7D73A0B4077C3C74A7BD9917CC937 -:1082A000E723860A8E371AABF73B36CB624A93C276 -:1082B000891EA99FE345D21E1F35B498ED9624135D -:1082C000CCEB2A6E65B2DE4FB9BDF8F7A3BB984F71 -:1082D000075D144AF9FBF86DCA26392F2FC7270E00 -:1082E0007FC0C9F6CEE3FA3964E081E86818CB0FA5 -:1082F0003A5F8B0DA19BB5A0079C87A00725986EC0 -:10830000CC74718B22E12BEE93F2F7BA589937E8CF -:1083100082F43FF1BFA09B22C1F0EF4E0F34D6DBB9 -:108320009D1E4874B00874D0512F840E84D53FEC44 -:10833000DBFC42A52362872B848214ABF021CE178D -:108340006724C3EB1EAB1FB178BDAD122F7DAC927D -:10835000EEE8B4F18517707D2FE27D4B1E5C28BCE2 -:1083600054BF2445B07DAD1FC9553171DC4E204549 -:10837000588E0ABB13A5685F1223FB2FE92938FE2C -:108380008EFAF35AE274E6361CFE5EC17205DA47D5 -:1083900017707B9F45B6F75A29ED9B21F598B69546 -:1083A000611CBF5C72779F2CD0C9C4B1663A39A2F8 -:1083B000D39591DE94EDD68D759E24F083D286FE02 -:1083C0007CDED43B8BAB77029FCF47B0FC59B2EA3F -:1083D000C79386617E2FC47B80C23393B7B33FA817 -:1083E000B461F64F3E84BEB4D5C9DF2BB2B5F559A2 -:1083F00090FF15F7DC9DF4A174C6017B12B5D79AE6 -:10840000A69C7F95D2C9BEEDEF409E983C5DE5FAF3 -:108410009385B43F8B0639CE24DFE7D624EA6FD2AA -:108420002885C3698E3A5DA9B7C10FA4E3F7A92CCB -:1084300045977FE43D8192557DB2D273E13F21C9DA -:10844000B80B39FD53A3FE186503E4A5BEE3E4FEB3 -:1084500033EAA31FF47B3A4BCA55BFD5E162E40966 -:10846000AE5CBF7C75D8D18C68A4B64036A5E9FD5A -:10847000C7BE84754E4C17E3D703EE77AA6213CFBD -:10848000B7AD84F94254961BF4AB9142CDFAE3D6D2 -:10849000FECC278F8E693B7A37E58F6E1E24ED8CDC -:1084A000BA7D61BE4BB07C70748CE4776D9B239871 -:1084B000FE8FB85AA3E2A43D8EED0D653A497CB615 -:1084C000ACFE7EF8B9CB22ED47717ECC7F681AC72F -:1084D0002794AD530361B807B0C66C6FA88AD4DE89 -:1084E000C67E08B51B84DA074033A0A3F2350AD351 -:1084F00061DF7A8F3D99F99CE2C2FACA2303FD70CD -:108500000E947B9C1CC77C85FDE06B82FB70D8B908 -:10851000050789B5676B9F004E258D25ACEF46E4B6 -:108520006ACCBFFAAA0417EC179DFE26C25E0BBEEA -:10853000646D4DC6BEFC55969BF13031CE9515C984 -:1085400074EDE4FB11476DAE2CCCEFE84AA705E7CC -:10855000EDC41592BE69DF39708FE11EAB08073F8D -:10856000D89A25FB9DB3DC5ABC91F2BD1DC21A15E9 -:1085700007FACA67FA5ED85FFB2DE675EA17620450 -:10858000E489B2356BE5BC74FA10D696C2781AE766 -:10859000D4E6B402D8013AE4DBFE63DB01C70EBACD -:1085A00098AE303DD07A0EC18E9CDEBFF432CAE95F -:1085B000FB3ED0CBC4B1817E881B2F52AB38BEB6F8 -:1085C0003D4978E0776C176D2C8FB4933C02BE6701 -:1085D000F019839F105D781D899DF8DE5247532264 -:1085E0001EBEB5CEC1E9B3752E6125786FAB4BE2E7 -:1085F000FC0B756E4E9BEA72F8FB8B751ECEEFA8D6 -:108600001BC1F997EBBC9CDF553781D357EB8AF937 -:10861000BBC1AF083ECC970CBE63F02783BE0C3EB7 -:10862000154A577309CCB81741ED991F1A7C10EB06 -:10863000B01474F22703CFE94AB12F09FC50B4CE2D -:1086400006FF2852CF3DFF0AC1B9BD2292ED22EDAF -:1086500042F2C1F648079F07A976B10BF689FADB0B -:10866000BC47EF0E3A876FAD508435888E7FBCC40F -:1086700029AC41743C6F59AC293F67D9FB6FF4A416 -:10868000FEDF8DD172B3691E477E79E2F13FD1F7EB -:10869000DFFCF24C26F04EF3D8FC08C6BD2B5C9FE5 -:1086A00047AB9CD75D769697FA864B7DAB6FB8D477 -:1086B000B7F0E3088ACF3DA2E3A3242DF69DA7B12E -:1086C0006FECAE9B47C04EB452DE4BFA04F8A3F2F7 -:1086D000BFE8F82B5D16C6702D6DD0F76B70DC36D9 -:1086E000C1F558B260F94EF10A01BFD7B15FD803A6 -:1086F000242B88638AC3AF407622E56B0EEC98ABDF -:108700007FF711E47665D92196B3354724C77F08F2 -:108710009FED5C707FCAB2835C4FB4F636C56F467E -:108720000CF5DAC13740E3C05F69CE7E81FD2E1AB9 -:1087300015BE7F54AE7F2F5FAD98E2A26764ABF2A7 -:10874000DE459695D3F359423F471AF9BC32E89675 -:10875000F808C7619637E6DB1704F1E752FD7B594D -:108760008EC514A7797F969DFB398FCD49FDDE9B81 -:10877000936E9FCFFCCFCDF7058CFAA53905AB6082 -:108780004F2E5D83A8A6CEF625D9567D5E2EA97FF5 -:1087900039E85C8BE2F8A22ECF07439E39855F470C -:1087A000F2FC59EFAA7CE1B917E08FACFC73189F7B -:1087B00053958375FB4AAE7FF8349683BC91CA709B -:1087C000C8E112FF85CFFD351A715DB53BA4BD9799 -:1087D000D2A3486BEEAA60FB5E8D87F6491CF8AD0C -:1087E000D9EFFFFA0B7FE6FB9D84B0143D6E98E352 -:1087F000D46A767CCAF16BB0C7F986727F1C5F1DA4 -:10880000DABE56F99AF557422CC3A768CF97893C30 -:108810008F9D9712C1E76AF7AC4CEC2A8E28B41FE3 -:1088200023CEC1B0FFD58A359FC3CF597BD7849360 -:1088300092DE65FFA1ED1ECA8E4A38315020C6EE89 -:108840002AB6935805C79F2CD5ED38EDFE4CF6633C -:10885000772777D7AEA7462492B55BDD3188B3BEC4 -:1088600028C484AEF0F449B6946BCFD33E823FFB6C -:10887000E23695E5CA8BDBA2783FD46C7BF020E230 -:10888000046B9E52D8ED582D5A38CEAF66872A1CFD -:10889000C1E71DEC47F1DDCF73F173514B405F8BA6 -:1088A0009A14EF669A4FBBC31DD323683EAF80BEB8 -:1088B00088341787350D47FFC6FC9F077F0B92371B -:1088C00017353FC8F18D54EF02CB37BF8DE0383CF0 -:1088D0003AC9DEC13CCF6E18C2FEF5454DDB6B5880 -:1088E0003ED816E182E9E98CCD7C0FE4803EDE8142 -:1088F0006C298F9CD5EDD1675F50591FC23CB12FB9 -:10890000CFE871B846BB37F5766F664BF9A7265BA3 -:10891000EE4FA3FEA2A6A3D1FDA8FEC95DEF73FA98 -:10892000BEBE6F1645B6F03DCF933B22F89EE0C920 -:108930001DFF39FE351AEF7CD3980425689F9DC82A -:10894000B6C97DBA41C62FF32517D6139A783D676D -:10895000B7A528AC2F03DEA4B79FDDF112DF4336A5 -:10896000E4EB1F1C2F384BB186DCA3183D08728D39 -:10897000A355BFD7D1A6DB63FE6FFAAFD1BF27598E -:108980008AF571E43D0D61C46FB864BD2235B72727 -:10899000F6DDDCC1EE99B8972DDE927197A2B7FB98 -:1089A00011E87F73DF8D67BBCB529BBB27F25F1C47 -:1089B000268595E0337788CE57925A87C1BE7B349F -:1089C0004DCA15863FAD6AB522BC04BF5E44673E02 -:1089D000E4FDAAD06007C949677C3D5661F1DA71B0 -:1089E0003E46D9992EEAB73B37C1BE75C42E7CEC02 -:1089F0007F7BD129FD27E9D20FF218F617A5557113 -:108A000081AC78D8F174BAA99A4AE541F453B529F2 -:108A1000900539EA9C5DDA2B510EFDA9AA40D6AB30 -:108A2000D7E914FDA0DFA369AE0B2CF7EE8C12D0B2 -:108A30003F2CAF4449BBC8D3CE4D6141E776BF1C44 -:108A40008B1177C7FE4ADF66393FCC0BF2FC227BE5 -:108A50006316E45D63DC45D18D3CDE397DBC45E1C8 -:108A60008DD29FA3C711A23E8F6F13EC776A7B262E -:108A70008CE5E633C92D2F63FC33CFF4E7B887A329 -:108A800069FE05BBB8DCC9F1E795CF860530DFD3B9 -:108A9000CF44B15DEBB44DCA63A7A312591E3B147A -:108AA000F5F05CF6633D15A6C02E745A11F62494B9 -:108AB0006FEEC1F24065DD32F6D754127B811C4B5C -:108AC000E904C87FA737F7677BD1E93755BE5C411A -:108AD000DF57E3BB261AE7FE8CF58008B6239E79A4 -:108AE000F66FFD83FD3B465AF994D93E66D083511B -:108AF0005E9423F960518ED4536EC871715A1DD1A2 -:108B0000F4703AAF53F207C203EB81B41F1361EF65 -:108B10003FD2B43B5189049C0359FF09B86F95FAC1 -:108B2000D6996D36F65355BE12E5653BD4DD57F147 -:108B30007DC94A55CAE3951679DF50F9E556B6FF67 -:108B4000D43FE32C003C08DEACDFB66D56F571E493 -:108B5000B8A7B7F4917E8D809E7F7910FB3526C62D -:108B600089795359CEDA9007B85E7A2A82E3FE6992 -:108B70001C2FE2342A7FF67309CF9805AC27D0C1A9 -:108B8000CDFCB94AE7CFD5775F1383FB10E25D9543 -:108B9000EF795CB27A7A82FF86C2EBD11C9D3FBF2F -:108BA000FC38F3832ADA37880F5BACFB13173FAB33 -:108BB000B05CB978D5358F30DF7DC726702FE25C89 -:108BC000D383D1C1F8A8CF91FCB0B3BD87EB2FA65A -:108BD000FAB2FD5BD13C9F2D360FE6138AC7EFDD5D -:108BE000FE59F507B5AF6C22F922EFCAF55F122DD9 -:108BF0003FFD33F8CB3627FB5109FF7C3FEAACAD94 -:108C00006901D67FF67927F39DB3B172DF9FA4F394 -:108C1000D4978DF9DCF46BB6CBFC619AC039B4D033 -:108C20006FEED798D7EA1C9BA4B7784F0CFC44D5BD -:108C3000840FF447F8F911B77FD7C6ED43D7B34097 -:108C40006FD7B14F9F8F60BA39DB4BE2E5EC0BD9A0 -:108C50007C9E1D8D95F44EF34D85DE743656A6B878 -:108C600099047AA874497A383BA689ED026795ED94 -:108C70009C1EB5C97695CB747F3BD15F12E807B4D3 -:108C800009BBAA634D0BE419F0F9E1059C06704F8E -:108C90003BD48E0E3AC5F9D7AAEF33E31D05F6EBA8 -:108CA000B09FA789EFC76BBA3C59B5ED4A7F25F055 -:108CB00054B54D617FDA7F19FDD0AC130C3F00D164 -:108CC000E5629FC2EF222C6EB86D11FBD396ACBD4E -:108CD00015746FAC63B17E6FFCA8A2F27C8E3A690A -:108CE000FFE45E399E01DFDFE7281DEF75B88CF3E6 -:108CF0008BF6F03B396E4947946DA4FEAA1A943561 -:108D00003C4E9AA1E7CAF5197022B0D861E73BAA98 -:108D1000DFD3EE6EFDC63CBB9BCF319DCF1F4D9385 -:108D2000F793DBDE96F7CC2F7D3D2426EE5BE44106 -:108D3000BE6160F487B863D020F5F322F81CF635E5 -:108D4000ECEB34CFAC0D66FF4ECE53E6FC806DE607 -:108D50007CEE0E733EAFD99CF7BC6ECEFF09E30EDE -:108D6000EB8413F46FC43542FF460AFDDB1D26F584 -:108D70006FE4A17F2385FE8DEFD0BF9187FE8D3CF0 -:108D8000F46FE4A17F2385FE8DEFEEFE124E55BAFF -:108D9000BD1478E0B8BADD4E233E81F7CBC5D98942 -:108DA000CC478555EAA51717E5B2FCD8616F9AE262 -:108DB000607B93118F9518AD85F7471C80D2B22A3E -:108DC000398DDBB11DBAF6556987AE2A7046C2EE01 -:108DD000D1BAF2E42A883DA7A3B418D4BF686BDBEC -:108DE00002F8562F3BC07EFFD6E5EE77AF93F863CF -:108DF000FB8B115F5582730F7C9BF4251977EE7105 -:108E000004DB5343FD44624D501EF2D33A733ED40B -:108E10002F04BEE635EDAB46C6C76F6C6DC9E0FBEF -:108E20009F3EE3E0FB699FEAF63B31CBC1F298211C -:108E3000CF23CE1B70597A9FB209E795A77F1CC339 -:108E4000B9FD50A6E97E61685A767908CBF31DF921 -:108E5000358A05E3944F5FBE8FF56ACDCBE7D2ED3F -:108E6000FADCB2D75B4CF3EEEF0F37D1D1C0AD7166 -:108E7000217ECC5EA6FA8377A587F8310798CAA72A -:108E8000AD1962BE8F5F7C8DA9BCAFBD236ECFA133 -:108E9000FBB9E4FC5CB2CEA5C8025E6F68BD54C5E8 -:108EA000F327F86FC5DB524E2DA773C61BAFBF2B40 -:108EB00052007F9D7732E057D1648B859DAD4C3F4A -:108EC00087C432F3B95C61153E575C27DD55B88421 -:108ED0003796DA7F696D4C653AFAE547A92A8168C9 -:108EE000D180963CE8AF8BDE7C7238E8AA5ADD98D8 -:108EF000EAA2F23B14FF165C203F13B73D712495A4 -:108F000027A95A497FC273AA2D70FF1CF0D1ED1911 -:108F100002EFA47CBAE6A5688E1FD4E92FD5E60A35 -:108F2000071D6C6C54594F81FD4C8DEBA4938D8DB6 -:108F3000F1E1D06B2AC6283EC8C7065C0CFA08854A -:108F400007C9EFEFBA69BD970EC9F7948C752E75F6 -:108F5000C9FAA241B637DE0730D67B5CD7472B373C -:108F6000BE91753B7D3FD77F5F9E1B7EDCBA5DBCAB -:108F7000EEC5966D5B92297DC7A1DD85752D7D7B44 -:108F80005CF4481AE7CB6D32AEFDB3754F3EE1237A -:108F90007E7A77E39376E80F9556BF9DDFCD7966AD -:108FA000A31DF10ED76FDDC8DF176C2D617B8071BB -:108FB000CFEE941197ADC3A362ACB2C145EB3CDEDA -:108FC0005FCA8515E1329EA6481DF54602D6B55505 -:108FD000C9C7BAA6176FB7E3FD8187F57AA1FBA6CB -:108FE000FDF0B4A21EB07B35291CC7D4DD3E99111B -:108FF000E8CFFB64DAE5344EA75F1EC87ADE8782CD -:10900000B42F9C23B921FAF56155DAF59A55F94E3A -:10901000983D90300DF2C25EF96E45359D43230AAE -:10902000A0B70B7135A5C5A354139DD7164698F666 -:10903000C12C11B4AFA8BF9B452F537EFAC40C536B -:10904000FD99D30786F89D0B3ACB997F5D6D7A8F9A -:10905000A6FA2E9F5B61BBC758F3774AEF623ABB13 -:10906000D1D4BE5A4C35BD47B3E8A9F718CE4465F4 -:1090700076C4E154E8F758666947F5EFADFC9D16F4 -:1090800062DAAF7D333C7F92E7A58DFD09863D7D99 -:10909000167ECFE8EABC0CEF881745BC30EC1D9A71 -:1090A000591E69613D55483C54EBF6A8EA1C698F8E -:1090B000AAF6B5D8118F4DF0B7A610486A1A15B6A2 -:1090C00037527D474A9CCCDF85EF3BCCF752D0DF4F -:1090D00065941F524BB0BF42CB6B68DD38176A6096 -:1090E00047623BD884936C0733C6D1FB37E834F42E -:1090F0007D80D0FE060C7033FFAEDCBAFD602F829F -:10910000CFB4E2D87CC49D54354DB195E45E496F2F -:1091100006FFBF546161BF7EFBE1034C6FED155646 -:109120008F8C4BFF76B8D478A5DD35940E17D0BA66 -:10913000E07F5EB043F1F815590FF0E905FA0C81B4 -:109140004F4A177033E0D501BF90727E3F6E28E220 -:1091500026E47B0A57C025149EFA380B34C17227C7 -:10916000CDCBCFF30AE9578C08DD8FB7DBD9FFB041 -:1091700041112EE5BBE131F5B2B4E3F4CD90EB6FD4 -:10918000DBA97820BFDF7CD9CADF3BE8A758C6D966 -:109190004F9F68DEAF1DF4542CF7CF8CCB89DCEEEB -:1091A000DF4557DF454F86FF26347EDDB847E61999 -:1091B000A0DFB71A26867DF34FC4E11BF24177E7A3 -:1091C0004CC739E4D2F11099DEE5F9BC342A9DE3AD -:1091D000CC35DDBE68F0694D6F678C5B42E5EE789B -:1091E000D07B6F7E67715543466AF0FB37DA4A1BC6 -:1091F000DB815397C7735AE27425E27C29592EDF2D -:109200006939764FCF44F8298EADB4254CA4AE8F82 -:10921000DD3934550C42BE88D34FD786CD0AB6CF40 -:109220001BE92D03E4F9619CEFE72D87A367613FFC -:10923000AEDC198D90A1C52BDF1FEEA273BED9A2A3 -:109240002D1AC0FEE08D7CCE0BD7C63CD8E70C397A -:10925000A37265514FC80355FF38F004E4016DB99E -:109260002D1172EAE90F5481D01A3AE758BE38E559 -:1092700094F47D6A7304DFAB3CA5082FFC518BD4BA -:109280007D792ED379DB7C33C68F70D2B8C330AEF4 -:109290007F4B12C6F5F8B230AEB63C33A62BBB8B73 -:1092A00091D6AE97F2DF16C3CEACDBA321F7230F26 -:1092B000B95F644BB91F79C8FD4821F7E37B0DFC0A -:1092C0000EF01BD7B7E5436FF58D15394BF81C8EA3 -:1092D000CC815C7FBB12EE013FBA5DF1F4E478848F -:1092E0000F62E5F91B8257231DDD46B25910DD5E82 -:1092F00077D92182E3EBC68858537E9C23D954BF8B -:10930000C895662ABF3EA9BFA9FC0677BE297F5330 -:10931000CE4853FD499E31A6FC8F46DC60AA3FC56E -:109320003BC5949F3661B6A9FE8CE21253F9CC5925 -:109330008B4CE5B3B5DB4CF95B2BEE34D5FFF192EA -:10934000E5A672AF7059710E36431F23B8EF853E04 -:1093500046E9ED6F674606E375D4384B97EF0C3559 -:109360000D90FA5674AEF739D025EE09810EFBE860 -:10937000F780F6E29C1906BF654091FA704B32E81F -:1093800026B45E68F9A888FD97F09465FFE76E9FA4 -:1093900061253E31EAAAFD4332287FFBC0E619561B -:1093A000E22FA3AED9FF523AE57FF1DC37B27CF071 -:1093B000FE4B285772F7CBFC34C122C8AF06CE9BB8 -:1093C000E1A3758CBA2E7D8D47DA53BA8C53355292 -:1093D000C001719D8003D200D127D2FD449F485F18 -:1093E00027FA2CB7097190E813E921D24BF1FDF768 -:1093F000A497223D4C7A29D277482F45DA427A2920 -:10940000D23FD4CDE2F4833A8DDBFDB1AE82D38F6F -:10941000EA96F0F74FEA9671FA973A1F7FFF648059 -:10942000617F08B09DC6F08BD5C01F097BDE2EDBA7 -:10943000B960BFB1E295E7ABE1C7AC5F225A23B098 -:109440004F5BADB1271C9DFEC9EEF9AD559C08924E -:10945000CB9CE1DECF06F0F8BD5DCCB7F5EF47C49D -:10946000B43E0584A74FD3B5B3E007330ACA56C646 -:1094700010FFB8EEEB2536D0CB8796AEEFA3EFD535 -:10948000F9DBA703BD6DE8F75AFD5DA66B1D32AE93 -:10949000F05A6B6B3DDBDBBF146EC403ED33ECEFB6 -:1094A000F758F95EB1F285E0FCE804C1F9FA2F5BE8 -:1094B000380EF15A972789CF1D3D6FC40575F8FD09 -:1094C000F11314EF63F8E18D789FC22F5AC7413E24 -:1094D000181D69778785C40DC0DFBE2FEA8FC6BC13 -:1094E000F87D27C3BFFFD4972280F7F20C3FFEB56B -:1094F0008E9634D81546DFE1F004C73319FE7AE5BD -:109500008B1615E78911AF648C63CC3BCA4AFD15F5 -:1095100074C6235DEB6ACA475C467D7524F7D79312 -:10952000BEE3DD49AAE755B95D533EECC7A3AB22C4 -:109530003D42E98C13E8A9AF9BEAF13A0BBFD03862 -:109540004E62B41E27817E1CB29CDF011C9D104818 -:10955000C6FB9FA397D83DB0833E8EB8B382CEB8EA -:1095600005D48F08DAC79827FAEDF715CD17F2BCA6 -:10957000D7CBF09DE692F429DC7A5E3FAF85632C71 -:10958000DBBB543D5F1CE6FA6B04D1CFAD19DA901A -:1095900081D4DF1F948CCC7CD617327A60DF4F09E0 -:1095A0007947B00BFA1931F0FF847EBC12EFBD058C -:1095B000DBE142E9C8C08F414F06DEBBA32B830E1F -:1095C00082E2D018EF1D71657A7FA1F4D61D9D1936 -:1095D000F475AD43D201F08CF82083AE942F9AF845 -:1095E0001EEBE82A079F7F065D85D2C5957425E9A5 -:1095F000B4FE270EEEEF4ABAEAA407C0E587D355BA -:109600008B8AF3F89FA5A7796D623CEEFF975C7695 -:109610001F44DAAB9FB6177CA64C8C190F12132E81 -:109620007510EC62A1F532BAA9174A7FA1ED6EBCA4 -:10963000A25D466E70BB71FA5919DAAE12ED7A046A -:10964000B71BC271116FE9F708DE721A712D9E996E -:1096500090530EB96DF22D2FE18DCC27BA19A7F3D7 -:10966000F34362099FBF24EEFA404F853A698DCBE0 -:109670005DC8FA426164D7710537EAEDC77F5DDCEA -:1096800080F98C4F30CBE337EAF2FCF5A291FB0F67 -:109690007D47E1C6DCEB59CE0F7D4761F3403DFECF -:1096A000204DA481DF170A8F9C9FFE0E46A1BECFDE -:1096B0005374BAC970AB62541CEE9B6A561C32AF2D -:1096C000E31D8C3C8CEBE3FC0DC2CFE94D22C0FDC9 -:1096D0004CA20309F91F096193EF5FC8FBBA35AAD1 -:1096E000F6DF90578D7BBA4F3BB557B0CF0F444C48 -:1096F0009E83774AC60D19D70FEDF617BA59CEDB00 -:10970000EFC860B913FBD216D7C927DEA473BA5FBE -:10971000A6BC378A14F746FBD179FA3B3AC791BF0A -:109720003167B940BBF16E73BC93D1FE26D7386167 -:109730008DEFFE9CBC296F776FD8CDDE8ACD2E04CD -:109740007EDF8ABDAA10EB7D2BB6A745A661764EBB -:1097500007BDD2AF2BB9D8A0FBCEF1C6F378DDC1DF -:10976000D9806B283C0D38FF00B81EEB0AAE7B0792 -:10977000089637AA23245FAD8E907CD580737558E8 -:10978000C77DDE9EC1F127550E09AFF9CBAE11564C -:1097900012F5172C1BC9F99375C207B89FC69260C2 -:1097A000100FB1F709EB58CE1BEFDC9D7DF8BDE83B -:1097B000249AE72A87F63F98DFB98240164984E267 -:1097C000E4867ABE8F7FFE05D5037DAA4A75AFF188 -:1097D000C0CEFA962AEF717D7D2015FE58F154D740 -:1097E000F1E8550E095F439F1CD2AF98F7ADB15F0A -:1097F00085FEBE80215FF50E93F1DCC63DF7EEE4F9 -:10980000ADE1E192AFF50E93FCD8C0EB06BB7EEE66 -:10981000533FC3898FA6FC3A9CF5AB98586F4C2EEA -:10982000EC8385C2A49F187695F604F97ECAB5220A -:10983000EB9151942F3C64137E2A6F074340799239 -:10984000F4B3B61FBAA482EF174529FC3E86716FA8 -:10985000292CC922DC417CC2E90E37BD4B1B911378 -:1098600067CA47797A99EAC78C483795C77A0798C3 -:10987000CAE3271498F23D8AAF36D5EF396BAC298D -:109880009FACDD68AA9F5231D59437F8588AFC24E2 -:10989000FA2CB9C5D4BEEFB25253FD345FA5A95C12 -:1098A000C53B9B3140ABB7252711CF81CA9F8CD5D3 -:1098B0004B43DEE3B508CBF0CE776BFE335ADECBFD -:1098C0009910B980DFAFC96CFC99799EEA446B2C82 -:1098D000A5D7BBCD7CB128C99C1F17B94F81DF71BB -:1098E0009CCBCC9F5396584DF91FE5EAFC344FE4CE -:1098F000B1DDE3BBF0AF0D30E13F144E440FFC7E11 -:10990000683B9DEF3ECCEBCD327E0F077E93E0753A -:10991000C06F120C07F84D82F3F09B04D787DF2449 -:10992000B81C7E93E0F22187CCF81FD662C6FF55A3 -:109930001F99F16FD06577781AD96AA60FA1299A75 -:10994000F22D78BAE694997E42F1731D895BB109D4 -:10995000C087E209B87F38BE5686E08BF0C3F73780 -:10996000DB7B47317E1ED7D7756D6020DF972E3A9F -:10997000A40ABC6F63ACF371FDDC3F6DD51A73892B -:10998000CFFCCE5D90043E769D907EDBF155164F68 -:1099900080BA7F20649CD929DA43A83F2BFE52AAC3 -:1099A0001D74D226DFCF7B0E7C79D895F1B23E12A2 -:1099B0004FF8BEF6CF54BE2775C4D2A8808FAF8EA5 -:1099C000D19E009F9997BB84D79B248AB72F405C78 -:1099D000D47F85A5223FB7AFBCC72D725BF9FE8946 -:1099E000C127E7A6C8B8A92DB9BA7FDD23E3A79E92 -:1099F000C995727794C7C571DE25B9F27E0DA98B22 -:109A0000A97307013E879DD980CF3A0BBFEBD98A56 -:109A10007BE4099DF7C8210F43FEECA3CB7FF51F24 -:109A20003B1C5847F67A613A7FFBFB1DA6F8E281A2 -:109A30005B5DA6FCA0A62453FDC1BBDCA6F2FC40E6 -:109A40008EA97CC8218F293FAC6584A9FE551F795A -:109A50004DF991AD134CF5AF39556CCAA788B6478F -:109A600001DFBE8AB4531CCD4D97FAB95B70DCE4BC -:109A7000DCBB63E57D5FDD7E61C8FB46DCB9A6D358 -:109A800075A81ED1D72EE5E8FA6421F54687AE1FEA -:109A90000AB33EA1E971E31DF7587CE6B871235E75 -:109AA000BC43EFD0F58A8E7B349DF1E2DEE078F1A5 -:109AB000B9615DBF1F7D5EC77BE8FCFBDAE57AEB31 -:109AC000EFB4F3BD1D635EA1F349C99674BBD9D150 -:109AD000F5BDAABFE54AFB466B66F125D0FD1336FE -:109AE0004F2BFF6D842BC6F3B4225EB7FE1776CFE3 -:109AF0000AF7778F3777B05CCF1C8B65DE945C8E6E -:109B00008B33FDDD84884192BEAD8375FB4AC878F6 -:109B1000736364DC9A88B1BB41BFDD8F27E1996430 -:109B2000170D7CFF4BBF67F1E3354DF7A1688EBD84 -:109B3000517F3FCE6F033D4C1C4BF2593EC9135B26 -:109B40007A3D144972CA13CBAC6C9F8A7BFE57379F -:109B5000FBFA75DE9FE94BFA10E803B20EF4A80792 -:109B6000F25429B70C92EB2B52BFEEB8E7C07E1827 -:109B700021F4F34370BC4F17F4C67468ACE3DF758F -:109B8000EFC1A0DB503819FAAFD0E33BFB19F3D299 -:109B9000E167EC07037EC6FD13F76DB6E24D917CDD -:109BA0008F6502E2E50CFC6DC993F6C6053A3C50A0 -:109BB0000FFCA8BB7A456A6E0CECF7EDC21DE3EA18 -:109BC000820E3BEAFF9BE062C0BFBBFB6DDDF1870D -:109BD00050BEF05DF7DDBAA3D37FF6DE5B109F9039 -:109BE000F14B3A5EFCFD2C1C17707794793F3F32A5 -:109BF00048F2899183F4FDE423FDD6CC2F04FC0FB9 -:109C0000F52B559D5FC8F3BC24AD98DFAFC6F98A2C -:109C1000FB5BF3374AF94788E2C4AB87C28F6FE337 -:109C2000FBCBD77A05DB6D4A1B153FDEF92AF175B0 -:109C3000AD0FB39FCFCD7207BF3BC8264D6A5746C5 -:109C4000EDF6A55DF9CEFAC248F9EE60E8FBEA0B45 -:109C500075BD192F6A60DF86FABDEE19A4FBB13C11 -:109C6000C2C3F29C1ED750A1D7E9A037BF7C6F0EAC -:109C70007A32F631A51C1F67C0CD0D3FD490CE3C83 -:109C8000C1373C07E77983B5CBF8C50EF81A7EAB30 -:109C90000EBFEC61BE27111A8F71CE7720BA2B3F11 -:109CA00098E11FEB6E1F74F8C7BEC3EFD61E69891B -:109CB000C6DFF169DF26DF67E9F45BFD65B8CB221B -:109CC000FD5331F03FB5EAFD898D795DDD0FD59605 -:109CD000EFE43894668BB67310ADEF2CF58F777B7D -:109CE000EF89DC9F88771126EA76A92BD7ADCBCDFB -:109CF000A314E98FF6A98CEFF609F25E3DF15181CC -:109D00007D67C44F4C118104A4861F4A5B3D92E1DC -:109D10006FF8A14A0223799E33EA17DAF0E468EB80 -:109D2000A3771585BB3BFD53AD7D645C54777EAA5C -:109D30006997F3B9BFE997AFE17E3E189426E5B67F -:109D400086FB6E039D0DD82A6C5867ABADEBBF4BFD -:109D500051A8F3AB12E89A3D82E2AD962BBC2F9648 -:109D60002AC288BF623E6FE42F35EAF92299BF7D8F -:109D7000A5CCB7EAEFA76DD1ED20582752AC077AF2 -:109D8000F936DD4E827520C53AF01D7C0D79F0352F -:109D9000E4C1D790075F430ABE86EFA5A2381576C7 -:109DA0005BF8D30A83F607FC6985417213FC69C12D -:109DB00079F8D382EBC39F165C0E7F5A7039FC6929 -:109DC000C179F8D382EBC39F169C873F2DB83EFC28 -:109DD00069C179F8D382EBC39F165C0E7F5A703944 -:109DE000FC69C179F8D382EBC39F165C3E6F996220 -:109DF000F2B7CDD3DF7F285B1FCFF45198511C9B66 -:109E000047F8FDEF887FFCC4960E3C372F02DD2E0D -:109E1000AD0EF7483C374E9078B70889E7B6D98C35 -:109E2000E7BBEC325F24E3B443E9077EAB429BF42B -:109E30005B2185DF0A29FC5648E1B72ACC947E2BAA -:109E4000A4F05BE13BFC5648E1B7420ABF1552F86B -:109E5000AD90C26F85147E2BB483DF0A29FC56F8BF -:109E60000EBF1552F8ADF0FD08CD03FE2B635E90DA -:109E7000F3FB99F452A243935EEA32E521E707D758 -:109E8000879C1F5C0E393FB81C727E701E727E70FC -:109E90007DC8F9C1F94983DCBCBF20EF07B783BC9B -:109EA0001F9C1FD4E87B03B6AB491B2EBC8EB43578 -:109EB0004A7942710931352F7326FC8BAD4E253519 -:109EC000D623846DF980998594D7F438C73CD16640 -:109ED00001BE39AE80F0A60504C7650FFA7FC95CE4 -:109EE0006EF8B3F987F09EBF43B0DE50A3DFAF3505 -:109EF000DA7B844B456AD4EFCC775D2F747CA31E4C -:109F0000F3CBA0799062998F7893FCBB220B70AF52 -:109F1000608B4591F1B82B643C74285DADCA93E722 -:109F2000FB16CBF6FDE1885329513CB8EF9165153E -:109F3000876C0580D392027EF72A2F565FD792ABAB -:109F4000118765CCDBB04B129FE07B86A3DA84BD22 -:109F50009CC619FD85B0E3EF734CB44B7902EDA0BC -:109F60006F0EF429DE4D41F4BD2C4F9E7B9AEFB667 -:109F7000ABCBE9FBC06D4BAEC6FDC589E1B2DDD30D -:109F8000BF8966384E6E50F89ECEA86DC28BFBC955 -:109F9000CB757E3A709BCB5ECEE3BAF8DEA3D16F71 -:109FA000C98654BEA759225A0B710F450C55F83D6E -:109FB0007C036EB4BED7B1BE2CDA2AB02FFFE0FB13 -:109FC0004F242E7E9FFB4FA387C61621AE5034CB65 -:109FD000F742270D2D59D983E6A5F9E57BA1A3BF4B -:109FE00058F206E79F92EF8532F90CE7F9F179987C -:109FF000ED53F8FD95C9BE8D960437EE652FB72554 -:10A00000A2FE36E1815805F508F78A8D75E58A16B6 -:10A010008B5301BD8803F141F4479C633AE825DF87 -:10A0200063E3F759A6585D36F01B43CE2971C9B1D9 -:10A030008BD451317CCF32444EB8D4D083E3627E8E -:10A04000789C4E3BDFE75FBAD3C97285B65E61BECE -:10A05000793E5FC6BB56DDF6E1704B7A679CCE99C0 -:10A0600034FF16BC037B267D7BF40885E588BD792B -:10A0700004D7A30D2FF13DCD92956FF03D944B0D7C -:10A080000F45CBFB6CD2FF52AEC3CDB03BCDD7F169 -:10A0900053AEC7691DAB93EF3AD339CCEFAE5C6AD0 -:10A0A000B0B19C112A2F1AF2A7F11E9110AE3FC237 -:10A0B000CE53D160E33BC00BD794AC4A1257CA9140 -:10A0C0008B75397351838DE3B22AF4F7D442FF6E56 -:10A0D000CF623D1E6BF156F3F74FF242E450E37D41 -:10A0E0004DBD4EC9DB0766B03CB4C4C6FECD39CB0E -:10A0F000A57C24B60B3FEE93CC593ECE82F766E6A4 -:10A10000ECF47A942EE8E95D5D4E9AD8EA64F84F53 -:10A11000B91CC1FC65EAE514CEDF7C3999D3999767 -:10A1200065DC2AEE22816E5A8BE43B07EFEBF2D11D -:10A130000CC4B1C6433EEBC9F4DD4EF48D21F2747C -:10A14000BE35C0AB1C807838D1A6AD449CECC48D24 -:10A1500082EF834D821C45FDCF825C158FFD9156A9 -:10A16000C4F76126287CBF68D2D0DBF4FD40FB43F6 -:10A17000303FE1F757B4C2297EC439CDD2B65B80F7 -:10A180007F635F68BEA3FC5EEA249F62C73B929A2E -:10A19000AE6F1B741FBA3FE646E876B2486907EB1C -:10A1A000B09361B27824C9B76A26E4D3B9B06DF62A -:10A1B000D20981601F952BCB7BFC76D5CC069241D2 -:10A1C000FF55FBC91C8B45DE3F233990EF0B88966A -:10A1D000A29E942F59A314403F32E6F5B967EC389C -:10A1E000CFB04E3A28EDD8A7F21EE5D27B324D7E95 -:10A1F0009BD0B48CE08DFD3437A6F5270A6168F456 -:10A2000060E12D1C81F7EB85F1285400F198B7E847 -:10A21000F9EAC13BFFB43A97E1C4F991BF7D68A662 -:10A220002FF25FE09373146BF0DF1B4BB268570D96 -:10A23000EEC1F750C703BF11B96DFC9E444AB64B3F -:10A24000F2A9107B4BF56089C750BB4B59AE3C77E8 -:10A2500084D59D7A2BFB7BDC6CB734D67DCC66BE77 -:10A26000E76BA4F307EBE75EDDBFE79ECAC316F911 -:10A27000FEC26316FFF657885E2FF7D06660BD8F6B -:10A2800021DE9EE7AFF1FA8CF74C3AF895FE6E8925 -:10A29000414F47965DE2FB2AA59176B71A444FE5F8 -:10A2A000AB15BE0F5ABA4CDEE7D6562BF25D846E64 -:10A2B000EC58BF99FDBFFC9ED56F7E112E0B75F833 -:10A2C000CEB1B7BCE148EB84EF9F973D60937C34FF -:10A2D0009089FB0EB72C71F2BBD99F7B8AAB060F1E -:10A2E000039E3C8CA771D8E5547F4B8CB604DF4BA2 -:10A2F00045CB41D81DE7FEFC6D7E8FBAB6398DDFA8 -:10A30000BF2CD995BF0AEFD97CEED17E82F5974458 -:10A31000BAEC90476A1A62F97C9EDB53BFCF2BDA06 -:10A32000D8CF67E0E7BEC1D28E777DBE1CE7A2AE74 -:10A330005711C06C534CF5BAB6631AF6D1503B4B6B -:10A34000E8BB21DF655781DDC41E645F35EC32B6A2 -:10A350009C63B371AECFB177FDF73EF7EAF337F404 -:10A36000DAF91D7A6DEEF89E90FFD72A2ED8D3CB5E -:10A3700023DD3371BFA1FC900D91B462629C5BBE82 -:10A380001F738F7C3FA6F48E7CE66773809302DC9C -:10A390003B19C9FBB8DC4FE990EEF7FBAD6B0FF44E -:10A3A000D90D7A0A78F91D827297D71E17241F9546 -:10A3B000352AA677248CFC0B8355C99748DD00FC11 -:10A3C0007E7C479A1D6F39CD213109F1997B412758 -:10A3D000C33ADB513D8E3F99982E0ECAF7BD14FE4D -:10A3E000BBE4182FF8EF5B95369ADFC3A0FA2CDF99 -:10A3F000ED1A1CC5FD95B868DD69485D3C4F8203C8 -:10A40000C3A9ED3EEACFCDE3303ECA027E1BEC0786 -:10A410007310F742F95B5C7E1BC6296D90EFD46820 -:10A420006BE438DAEA58FB20C8075697BD4FB05C9A -:10A43000D820DFBD9EA3FFDD119A2FCBCDE50427E9 -:10A44000DCB333EEDD86C2AB449F7F7963AC59CE7B -:10A450006C5C6B037E6677F35EC639DD0E5DDA30C9 -:10A4600086DF3728B77AF9BE8AA6C3FBB3DB9CF731 -:10A47000C25F327BDD23B634CAFF65B0946BCFE98F -:10A48000FB71627A2093DFA9BACDC9F1E3B35D8D88 -:10A49000BCDE0E783F44F081DCE22A6678139DF83A -:10A4A000106F59BECE8CDFCEF944C977FCD795F03A -:10A4B000FE5B60D5ECAEE079ACDF9789F8A1D9B44A -:10A4C000EFF10E9770697C1FF6C44333F9EF056214 -:10A4D0009E1CCFE6718FC7BB5344374CD706FD187F -:10A4E000F7F38DF1AC1EABB4C77BBE6B9F7A0F4206 -:10A4F0004EAF277CC30FD0DD3EB5E302268D6B2F18 -:10A5000097EF075EC1EFF4FDFAFF016A916CD3008B -:10A51000800000001F8B08000000000000FFED7DA0 -:10A520007B5C5565BAF0BBD6DA57D8C0668BB051A4 -:10A53000C00D0262116D10101575A1805B736A6306 -:10A540003729C48DB7500191ACA89FF3B10D6FA905 -:10A5500095262A9675B6A68D957570B2461B9BD921 -:10A560006A9A5D0F3A8DD33953B6CD32BB09D234D6 -:10A570009F7DD399BEE779DEB560AF0DA475A6F9CE -:10A58000CEEFFC3EFCE3F57DD77B7DEECFF35E7630 -:10A5900022634CB23136789883B1818C1918934577 -:10A5A000C83FA177FBED02639571ACBE2D13D22895 -:10A5B00056FF6B0B63DFE3DFF89E74A253642C8FAE -:10A5C000B1DBA05D1B7CAF10D9ABCCD6F33DD3295A -:10A5D000D0F78A1436D31DD41EFBC37EE3D5EF1308 -:10A5E000FC698B337BEAABE356D878BBA9D07E9A63 -:10A5F00005EB8BDDF51BA83ECFB3E92691C53236BE -:10A60000DB04FF87A594487B56C4E632D6B057706A -:10A610001AA1A8E14189B118489F8BF0B164C6BE68 -:10A6200068F8CD3BB740BDCF376FAF64437BE635AD -:10A63000C73F8A39463036F75236730C606CDEA558 -:10A640003194560FF364380706D5DBF85CBA07C6B9 -:10A65000BFAD2DFBDC7F305AB79FE530F6FE73BFF0 -:10A66000FDE368E897319FDE7D4DCF3A66AD3EA1B0 -:10A67000AFB204C38DAF734D4657158379CEB6186C -:10A680001C1214CD5E5EC5649827B333671AE413B9 -:10A6900075CC2B42BF6CFD16D904EBF330FE57B5D9 -:10A6A0005C90A95D63BE4F82F50C867AC61C5EDFA6 -:10A6B0000CF0F7580C678448A8E82D910319BCCD1D -:10A6C000F7293DF81D0CA921A707EF890A1DCC5ECB -:10A6D00057066D7BF0050333960FEB651CAEEAFC65 -:10A6E000A72AF3BF6DBD20FBA0DE0D4E07CF572775 -:10A6F0001BE6C17AE7AC4F36CC86B45CF95E3E47C8 -:10A700005BDE8D2FAB8AAFCC9576584F571BC75762 -:10A71000D73A3DE1AB6B4F2F7C2531A9671E7700FF -:10A72000BED8008E2F3682E30B53C057A5332FA817 -:10A73000DEBF707CCD7EFEED0F5E76D0FAA8FFCE38 -:10A74000078DBE1DD0FFACB6BD84B7F2D51BF4C9D2 -:10A7500050AFCE994C7051DBCFAECFB63280E76DA3 -:10A76000ABB7EB1D16FCEEE893EE219559103F4177 -:10A770009E099067BA40BC3BA2A77E39A47B619C2E -:10A78000258BCD91ECDA9E71B628F43CBB3EDA867F -:10A79000E3CDAEAF7A886571FA7767F6E6BFB36648 -:10A7A000CE17B3A03FE4CFB345CE24E48B0A51D4F7 -:10A7B000F09B9A3E847883793D06E03523FEC3DB27 -:10A7C0009E46380C5E14E66C864FA9A9011F8E8B3D -:10A7D000F48CF33688CC6B827AA935818B388F5410 -:10A7E000A0286C8769848D52160BF91D30ED024844 -:10A7F00053249EEE73F2F5C3773F7E6731813C5C54 -:10A80000BF4ACFA1F46A603B57A700FE0D31CCD9F7 -:10A81000ECE8A14FB51F953E55FAED6F7D7BAE700C -:10A820007D6793393C598633C904E3563E3CCCB925 -:10A8300046B8FC3A0D61000F5BD07A81580B6C7DF5 -:10A84000AC3735905776CD0FADB7A524B68FF586CA -:10A85000AE53E5933926CEC3C02751019877D7FA76 -:10A86000A1510CF12D302FCA9DB38BCD22CE5B5D53 -:10A87000D7534D5019E6B6BBC944E9334DC068C340 -:10A88000003E4D76CA3FDFE4A0B4AD2983CADB9D0C -:10A89000369A3F6381886980A78A3085FFFD3C8FA7 -:10A8A000E56541E5536D9CEE4E5B0311B62039FD25 -:10A8B00071BD790D8B42FA0E3C88FCCC1A87B25DD3 -:10A8C00030D4E9F56723C44CA44F3E3FB5DD127D7B -:10A8D00027C93F166170EC02969BB124FB7423E0FC -:10A8E0006BEEF2382790129BD13894E4C20C6FB40F -:10A8F0009300B07E0B4378CC53E460F892AA952382 -:10A90000B17E6BB2558071E65A9CE75AA9FDD5CE4F -:10A91000FBF17B4B99212593AACA26906377287275 -:10A920006C89C0DCC88777A09C44FE120FA5A2FEEC -:10A93000B9A355F01B29CF560B00D721CDEED27805 -:10A9400094135B05E70E6CBB0DE4A9A9479E760D39 -:10A95000737F817A817D07F407FD5F252002715D99 -:10A960006D721CCAF14D827517C379B90D089F0528 -:10A970000A9D9C6E3913E1C8EC81EBA3F85F10656A -:10A98000CC238B286F1B143D86644079454E0E31D5 -:10A9900070F841CADA113F3AA709E9A0CB9212C573 -:10A9A000FA286F884889C3F239AD12C945959EAA25 -:10A9B000D535287C3317BEA3DE2B912A6291BE5673 -:10A9C000B64CA474CE8692CD5EA0E324C11D3B9A02 -:10A9D000D6A367B89E39B513AF47BC55EF30469B39 -:10A9E000006F497A6F524E103FCED9BE2A8941BBC3 -:10A9F000F3DBCDD351FE175BCB8AA3A1FDBC6DD198 -:10AA0000D952901E49CAE67A6441EDC43806F0ACCA -:10AA1000F9FB9127ACA08FE7429F56E8FF9BB670E9 -:10AA20009F17AAD434ED4F9280E7DE3179E2B3A1CB -:10AA3000FE42F1E02DA3501F08BEA7E2A9BE23CE1F -:10AA4000DA873C50D373C00F0EA0F7DAFFF51EF57E -:10AA5000F395F8D6F5E5D0BEA6F68548EC67E1A6F5 -:10AA60003FE45BA1FCA0E849C3FE3F17B63F654544 -:10AA7000026CDD9E857A7CEEA6B4284F1FF217F992 -:10AA800000F151BD5F20F8AAE5337C510684BBC7B5 -:10AA9000CF0C564CADCC80F47E5E628D680FA8F66C -:10AAA0008C5A3E329BCBADF351EB93904EE63FB5C3 -:10AAB0002509F5CC67113C5FF1D4AD6FA0DCF2EC59 -:10AAC000341A10AF1E1D3338519F7941BF221D55D6 -:10AAD00003FFC693DD61AE047A2ACA0E27B8CE6F93 -:10AAE0001D41FA519D177CA7F2CF74CC85F318D283 -:10AAF000DC998D74FF679D7F2EE2F3CFF566A71773 -:10AB0000F199CDF5DB9FD74BA558EE0586417BE447 -:10AB1000CFEB5F8848B5F4D86F25D2FBB28476D6E8 -:10AB20008B4236EAEDF0CC76C32CB21B18D1599D7E -:10AB300095D359C3017DE9E018B2C7A8A446E73709 -:10AB4000F485AF058ABDD59DDFB7D7807C52B3872A -:10AB5000DB11356D67C88E50ED925A859F17EE391F -:10AB6000437685DAAE6E1F874BED3E5E5E9501C87B -:10AB70001DCDE5800042BA0AF105F9FBFEF5D7D3F9 -:10AB80009769F27B297FDFB5562E0F759D49A8B7CF -:10AB9000D6649C3420FE6B972BFD425E1F34DEBCD6 -:10ABA000EC81042F2C1F6AC1F60E8DFD50BB2F9A2D -:10ABB000DAFB6BC356A3BE97EB2C3A4C9B6B2DA4D0 -:10ABC000FFB7D58B19BA5C9C5C9813EDB983619182 -:10ABD000592847072E3C650648026A3B8F8850BEBD -:10ABE0003ACA732FD2671C03AE90506FF805B45F5A -:10ABF0003B5EF97404F63F6E48E06B0653D70BBF1B -:10AC00009B5E0CF26419982D641F670646201D0F89 -:10AC10003CCCE5F4E37AB61AF51BD3B9D93428F75E -:10AC2000A3DC423C7F1BE6DB05FFFF1DF30FC6FEE6 -:10AC300099C93F14DBBDA4D0A7DB68592DC0BCAEB9 -:10AC40001EEA59834BBE41D05F932D220EA434AC33 -:10AC5000D7A1E7DF557B758222A713C18E40BBC801 -:10AC600030C86E413A6E36F3F509B2CC1A611EF760 -:10AC7000671E9E8D7A7A6DA78919619D133AC3C8A4 -:10AC80007E4D1CE422BDD66C4E22BD2D3874AC0224 -:10AC9000EA1FCE14FD3AACCF4C3EACCF4C2176AE81 -:10ACA0006896B19D70F0B56F51BE0F962E1E8982C9 -:10ACB000F50DBE477036439DCAAE738FFF1BA415BA -:10ACC0009776ECFD5748FF2DCAB313E17ABACB75DE -:10ACD000C603A85B6B6D3339B9DE60C1EB3878EF22 -:10ACE000B79136B1677E1D9DE79EFB4D2EA62627A8 -:10ACF000EA9F090725D21FA1F3E9B0C3C487523DDB -:10AD0000B23B3B2CA24F10B0FE91F7707E134C1655 -:10AD1000BF84F6BA49FF65B07E618EC4E87357936D -:10AD20004A61DF8391108B93477D74D14276EB3873 -:10AD3000850F553A7B2B9BDB8F6F297255853373BB -:10AD4000C82C58AFA8F06CD6ABFA2210CE327BF8E4 -:10AD5000769152AFEB9228931D5E6DF431E8B2EB21 -:10AD6000E050D233FDC9D93FA0DD01F6C4F254F959 -:10AD70005D842753F4EECD0AFC54FD2D29FDDFAC94 -:10AD8000C0F1668BC8E1765308DC147A0AA5971ED9 -:10AD90007A8841DBA31BCFECBEF6A351C984DF6BDD -:10ADA0001EE678FD90F0FAED5B2B80CDD8A0BF4D6C -:10ADB00021FCFE0C78F58BB93F02AFEDA178F59B35 -:10ADC00087215E37896467A01D8876A307E5C0B533 -:10ADD00094E7F66006233951298539D724E3778033 -:10ADE0004316C987A3281F54B930C415B806F5E91E -:10ADF0006970E5717E01B18D97E7A4105D24B0F60E -:10AE0000782C07BCE7A17D279986667E0C72B7E592 -:10AE100001DFDEDF403FCD826FEB3C988FF7668B22 -:10AE200013EDB70E9FE8D5C33C5AA259D67E18BF82 -:10AE300065FE554E2F9633456E4C37F8D07E83EF26 -:10AE4000498DF8BD9C7F7FE9EF671F44FBAC338DD4 -:10AE5000D1BA5AB2593ADA672D6519F4FDB7AADCAE -:10AE6000793082B72FE3F4DD32DFE6433DF4E8A327 -:10AE7000BEE1A8275AB6CBF136480D519EF81C9872 -:10AE8000FF2089D37D4B329443BA597097CFC57E4A -:10AE9000AEE1F30D94873DFF1474654E05D106E5D0 -:10AEA000A71B2376A05C55E974F0302EDF8778CF9E -:10AEB0006C45387927B08C7AE8FF4385DE54F80B6F -:10AEC000C0368D00F798103CA87417A3C05F58CA0D -:10AED000E9CF3B41594F1DF3A1BF910053090738FA -:10AEE000571AC1F0837496D5938DF36F5E0CF89169 -:10AEF000701D1C0FA74556DDD6075F15E628F10D1E -:10AF00001802F9A69271BEA944BA427A6C04BA0A30 -:10AF1000A2471648883E17AED015CA8308F7B81C5A -:10AF200058E757C21FF2B1F0ADFF94A6F735CEA493 -:10AF30001C2E2F1E337B4A7348EF4DD0D89D6F6572 -:10AF40007F9A88FAE5F4BDAF25609A14E59E8CEBF4 -:10AF5000D85CFED75214FF1FC607F4B88E0FCBFF84 -:10AF60004F22DA2D954B5F23FABFD2799699983705 -:10AF70001CE01E5D2C38FD00BF792D46E724F81635 -:10AF8000575C750CE159D66A74189156D8628D1CBD -:10AF90003B2B8F40378A1DDA6A24BA39F74B89F484 -:10AFA000C1B9928BAF0E800FE756084EAC57D63220 -:10AFB0006C2590372B2916A85E9957A07A65A91C95 -:10AFC0005F271A05A23740AF253B28DE31A7F58E53 -:10AFD000A988DF13C55F0FA4F8C17A1847E5632E6F -:10AFE000DE489E9529F5AB561B9147BBBF97B5AC84 -:10AFF000BA88FC3FD31B52DE3AE953ECB7AC515B45 -:10B00000EEC635821D77574E440CCA07E664CEEF74 -:10B010001148F240F20FFA93BB407144CF300FC297 -:10B02000C389BC617AA4EB990857A0DBE8A57CDD55 -:10B0300033A70ABE49B0CE9916CE671F9609BEFB4C -:10B04000053EFF0940EF65501E0B745D16C3E438E2 -:10B0500048DD26E60FC7792E1DF609CADBD338D4A2 -:10B0600028AAEF8FB4A15CF7E81189B7322FA5E5C4 -:10B07000CC47E9EDCC4FF398C13A937490AF93FC71 -:10B080002B318EF32BB36703D2D75F8B4E9C16E028 -:10B09000FBDD3942DE2894438D0368DD975B1F702A -:10B0A000A5807606AA41AC5F96E37E14FBB3CA4C3A -:10B0B0008F71AB74958E5A993715D617BBDEE29B0C -:10B0C00004EB8B6BF51CC2F5A64F373810EF8313DA -:10B0D000F83A1374DC9F3F546E60A3810E363F181C -:10B0E000E6433ADBBC3520DAA1FEE6038001CC97CB -:10B0F000AF14BCF0DDEA614E8CD359751E11EDFE24 -:10B10000A2568F1808E2A7E1B241443991BED32379 -:10B11000A29EB45AD7533D355FACD44F3779065908 -:10B12000C94E9E4EF4335CA11FB59FD456835F0475 -:10B13000B817C94A7D99B757FB618A9E56DB6139BA -:10B14000D2677AABA34F3F454D5B503F838FF808E2 -:10B15000C605D27BCA1F71FDDA84F01B78F3AB36CB -:10B160004C370321F8711C9DC74CE379F83CD3158B -:10B17000DA87BFBF7F8FE3631EF0BBB9F5FE22E421 -:10B18000A3CD001FC4F3E69DB3CCD4CFF4599A7974 -:10B1900031A986F22508074BEF753CA2CC2F3DD58F -:10B1A000235A69BDCE4368E7A5CB8CE2016A3F769E -:10B1B0001D7405F46A777A857ACCCB905A94B84797 -:10B1C0003A8EB34E40FF315DC157496BFD6133F696 -:10B1D000E366145F4CCF85FEA1FE268483A137FC75 -:10B1E00042E7995ECCE77342A9DF8EF194746CE775 -:10B1F00058114374C5E7D7D5EA14621C97B18FA0E4 -:10B20000FDC9907E9EC2B80CA4CF4E7E6D4A2EB46E -:10B210007FFED19776B4D0520E3EB30FE556ABF514 -:10B22000E69B709C83229FFF4D72E25D98DF6D204C -:10B230003D9ABE534EDB44799313FDEBAE56DF557A -:10B240002F42BD2C18C664EB3D8F130A9CDA153AC9 -:10B25000383979CB205CEF5345772C5802ED875F66 -:10B26000F7388D3B7CCAFC9416C80F9BF8CBAB30EB -:10B270007F5F8EC73C02E4FEB0D25FDEB60FE56AA8 -:10B28000E9FC1C8297C57645F2A939DAE3F502BFDD -:10B290003747DC528EFCB8D26670482477EB19FA37 -:10B2A00059CD1177DBB1BFE5D1F9264C0DD6BF36AC -:10B2B000A19C3C6EC931211E9A2D131896EBAC0A45 -:10B2C0009EBE1B4FFA40528872778473BA4C74E565 -:10B2D0006428270C0906ADBCD671792FD91D3EB460 -:10B2E0009FBAACF54881CC600954A07C935479692D -:10B2F000717A713CC9E2B4A3BFB44291372C86AFD6 -:10B30000D36039F79F38AF5EFD632E96504B7F8632 -:10B31000B0CC2841F93FDA9BC6103E575383C5BBDA -:10B3200018F544687F5D2070508EA34F4776337EBA -:10B3300048EEDD5EB21B347AA45B5E7AA2F521F2A0 -:10B34000521E817AA2582079E961EB0CB8FE120CEA -:10B35000B2005C3CDBB85E54F97B26CE05F0E549D3 -:10B3600065915C5EE9E473260EC6EFD1AE5C2A45BA -:10B37000221E025EC9E0E9C39FF778937F501E9DAD -:10B3800041FA87A90790FE21FD44E10F8F8A076FDC -:10B39000D9F5A3505FCB12D90395CB8536B4CFE254 -:10B3A000BCD14769BEC5DC2E6897BFA6F51C2A89AB -:10B3B0004B44797962D999C7EF41BDBE299CF4FF0E -:10B3C000A4A56756603C6EA657701A21EF591A7DE6 -:10B3D000F77B986F343A5D903FABF081FB974591D6 -:10B3E000684F08B8CE8C9E75561632839BE239F1B1 -:10B3F0003396403B4FA3E0343B7AE0A1C77A52EF4B -:10B40000F505BC3746FED0FA3FBCD7A8C859773EF1 -:10B41000CAD9A2C6E4870A705DEBF57C9E8DD1D7B0 -:10B4200053DE27393976B91C9EA9D83F9EA5B3575C -:10B43000C6C3F7C06A41F9CEF156A9C8E540E38812 -:10B4400063183F0D2C17483E79BC52A21FDACD5C21 -:10B450009E4D78EF280A905DD8E53DB4925A2B7244 -:10B46000DEA37436178C58946FA7DFE3FE9F47FE68 -:10B470006325B69BD3A2B5832602FD0C40B8BC67FA -:10B4800026FDE9F196D1BAEFF04569EA55AD8ED3C4 -:10B49000E43DAB8BAEC7B0E7AC7B27523CAF9239F3 -:10B4A0002291DE2A656E37C19F251BE633579D4FDB -:10B4B00031B7C72A8BC17EA2EF5A7BB0C7FE893352 -:10B4C00020DFA87854F1133AEF5E7619E376D0AC1A -:10B4D00075DA7ADD761030168ABACAE5DA76BF32C6 -:10B4E000BB9F45B9E8DE38E01BF2ABAE501E828050 -:10B4F000217F6E26E3711FA6E843D5CE2F597A51DE -:10B500008F726866E3453DC273E6D21FE6A75F38D7 -:10B51000B5F3BEA1204ABB3E394E93BFD13544534B -:10B52000FF66F730CDF75BA75FABF95EEE19A9C9EF -:10B53000DF5E3D5E537F46FD24AD1C7A379AD6A36D -:10B54000E2A7BF79BFA5E8A37742EC12359D3AE2A6 -:10B550003F1391BF3F2C67E4BF7C7833D3F8311D94 -:10B56000232482E7805C3DF931F7E5C8EF8F20BFE7 -:10B57000C94FF4A1C2F34373A1C928A27F62E47E3C -:10B5800079A85F729039505ECED4B1FD42548FFFDE -:10B59000670EF39CC7FEBAE30D4B0FF17843881F8B -:10B5A00073A578FF7006CCBF0F79794D2EF7C316BF -:10B5B000EE36AFFF38088EB56DD19AFCA2FDF1EBE7 -:10B5C0003F0ED63B4B041DAEB346E1935A16A07D09 -:10B5D00052BBE8A0FEEAC4402CE63B58676CB4F4CA -:10B5E0008F838B0A0F808F253728DEA9FAC33F1976 -:10B5F0003E450A9ECBB4701A93CBE3905F8F10291F -:10B60000DD9C23C7E7FE03F11CB49EF4DCBC7FDCA9 -:10B610007A2247C859089F9F1BAFDFE31E0F94177C -:10B620008E900B7F26B84CFE47C2A547CF472FD838 -:10B630000DFAA3729D81FBFDDE335CBF3772FDFE08 -:10B640007CB48FF6879BF344E70E07ED97D23EE973 -:10B65000A17B8D611918DF59A1237D797A99908199 -:10B66000FEC226218CFC360FAB4816C8BEB978C87E -:10B6700048FD31AA07EDFD3A90F351053E6B09E410 -:10B68000DFCCE571B1356E714A8A03F5F61FAC1E49 -:10B690008A8B7AE2111E9EFD30E16B69DF45EE2B4D -:10B6A0007E12D06BE5D112858F5FCCD5D13A1F2E9B -:10B6B00014B99D942ABA701F6315D8A968570696C5 -:10B6C000EB285F91C7E9596DF71F0A9DC794DD14F8 -:10B6D00086F388DA24BA7D7D8CFB512E8F0F3D795D -:10B6E0005718EDB3012A7468EFDBBDD6692E58AF49 -:10B6F000BDD0968DB6DFDADC68EA6F4D469715CF80 -:10B70000A1FC8C7478CA8EFEA0C0FA8C33CD55E6AD -:10B71000ABEE0F5894FE36E941BFA29D2298281E39 -:10B7200061F11AF9F91567B126DECA1C020B6EA782 -:10B73000D6F328F46AC7421BE197F6EFD578B15DDE -:10B74000A117A41BC4BB4ACFA1FD8389EC8DCCE912 -:10B7500089F3D915528E1AE5D98D748FFDEA901FA1 -:10B76000BC5CFE076EBEC4E32CDED7DEC37988E185 -:10B770005F529C0CEC4ACE5F4B43E2BE3F914F02BE -:10B78000660ECF4084561EDEABD0C9DA7F82DE481B -:10B79000BA02BC3E9CCBE58FABC0FD36CA3BC7B2FC -:10B7A000D430A2FB1F0B2796604538515EBA723821 -:10B7B00079F33D1F109E74CC6FB4717F0BF9E17269 -:10B7C0007CA4C23149649EBEF4F2883CE5FB1BCAEE -:10B7D0007EAEB76AC80FD9612877C502C6D22CCC15 -:10B7E00061BCB6FF7A0E9C8F85E86A39D2E5AE96C9 -:10B7F0009430E4CF6465BCCA9BD2A70C77A05F20CD -:10B8000018D00E04BFC3C0E33FDC4E57E57A4FB9F2 -:10B81000D67EC4724F668F1FA6DAF7EA773C97820E -:10B82000E3AAF359A5D861FDCD7755124B72A2DC7E -:10B830005A768F80F0DCB15AD4F87D715E612503B1 -:10B840003F3ECE7FAF13FD8E38B0AFCD28CF75F51C -:10B850008233085E817B810A381387F82BE04FE240 -:10B860003ABD67895E42C757D7B1AB858F1BE75D8D -:10B870002CC8909F54512FA0DFB756997F5C05A329 -:10B88000EF69993E01E3219E16568AE3555633032C -:10B89000C6F52A33995386F2CAC64374DEEDB9025F -:10B8A00039256F20C94F3A4FE32AF0A4E7011D4D17 -:10B8B0004D28437667B84B86F1897F161DA7B54C96 -:10B8C000F0A2EF59D4E23C84FE01D011C57D3C2D9D -:10B8D000011A5FE7E571725D8BC1E98075488D657E -:10B8E000B4FF21551B9C32D43BB629DF8FF1952D37 -:10B8F0008DDCDF0DF59374D6FAD7C3D15FAB109909 -:10B9000044010A792AFA5956852E5630773BEEF7CC -:10B910003319FE41BB48A5DC5A3D6F2A6622E5D0AB -:10B920007883DC139F409E6BDC40B2D394AA8D6772 -:10B93000482D2BC9AF33627DA8AC0F897748D5A5B8 -:10B94000141797ACDAF25BF32262088E593C1E9E04 -:10B9500073EF888DB7C27C727F79E31F303D8741DA -:10B9600033805BFEB23B074C87FF16ACD87823A62A -:10B970004FBCCEE89CC18FE057668CFAF1FCFAE828 -:10B9800095F2ABB2260FD0B9C2AF7DD2BF1A4F0924 -:10B99000E54F95FE43F94E4DD75E867FD7260512BB -:10B9A000910F4FDF3B3203DB5736DE73C8C7885F2A -:10B9B0000507D077A577711123BA605697D05B5EE3 -:10B9C00084370B49ECBF371F3F867C3BFEEFE71304 -:10B9D0007F08DF95098CCE6381FD49F69C9AAADF2A -:10B9E00023F2B93EBD906724BC4E46C10AAC3B056C -:10B9F000DAE0BEC778604E2BA47F2EF03C8BE34D7F -:10BA0000813C9EEF7BFD406B0CAE374BC7F58EA79C -:10BA1000DB8EE67648B7FFA8D80F59063605EDDC71 -:10BA2000C02611776E59E0C0E73BD6E2BE6BB9C9BC -:10BA30009906EBCABADF48F484048AF6519668A7DF -:10BA4000B8E5AEB68FCB699FB1D1C0D2286EE00EFB -:10BA5000C3736400CFB0AA4CB257C3AC68AF7A8549 -:10BA6000A4AA881E7B08F5220AB42CEFAD53AC3093 -:10BA7000FEAE42B047337BEC1CD5FE599C9F4CEB8D -:10BA800057ED2068C7B0DD8FE5A74A0B4B22BB19E5 -:10BA9000E683FBF7B64C2690ED1352FFF43223D920 -:10BAA000AF76AF7BCA70B45B97A7E6A0DD0AE39AD6 -:10BAB000246E7FFD3BCA67BB4EF95E28E6E0B949BC -:10BAC000751F800574D1188753EDAAFEE7A563E7BB -:10BAD00054B905957F9B2F9FC17EFF5972DD635539 -:10BAE000E84D4D63F879E0E90ABD8DCF37539A9E52 -:10BAF000FFB3DB73A7AE93FE79EBFE39D7E1FA9F74 -:10BB0000B18ED8FF21F8D83CF97FC63A6E99F24F32 -:10BB10005C87375F6EC8CF4379D646E788EC2E7EC8 -:10BB20002E1CE4DE3DBC9CCB398B930964C7FF74AB -:10BB300079D784FD9D411F1CCFA17877083A1867FB -:10BB400088A5A188ECCDA58CF681862CE5FB404329 -:10BB5000963A4D22DA03166E270E52ECCE414BB9BF -:10BB6000DD19A79C2B888B117D32D43FF6CB5BCAA5 -:10BB7000E7C6E0BE9091ECD5E636DDF516D4535E0F -:10BB800089CE8F86DA89D2D2954A9C5F6B9FAAF6BE -:10BB9000681AE379FDB2B3B44FA7DAA34394F2B4C1 -:10BBA000A57C3F60488BD61E8DABD6DA8FFA82100B -:10BBB0003B73A9BA7FD049EBD32DD7E9F1FC7FA81D -:10BBC000DD897BB0A81407AB7A06B4FE4DD730F6FA -:10BBD000747EF7F98C1CDC1F9AB95AD0E83955CF1E -:10BBE0000224287EA4E2E343D473883FF734B55F90 -:10BBF000D26F3EAF48704C2E4FD79C5362EC7E1EE6 -:10BC00002F71733AFAF5EA116BD1AEDDB7EEC63794 -:10BC1000317D69FD9DE1E504AFF5546F7FCBC6EB47 -:10BC200030FF5076BB3D12E6F5D0A853EF09D0EFB8 -:10BC30006A3CE385EBB378298FB6149E8BD0B37A38 -:10BC4000DADFDBA40F4C9F0DE52B12451C91BE23C0 -:10BC50001D9832189D9F3059787EF5358CEEE33073 -:10BC6000E55C9F1A87093DD7B7CAC3C75905F0C419 -:10BC7000733596187E1FA939E1FEE908EF668781C2 -:10BC8000E139398B72EE4F62D5AE2AA877DC7EBFE0 -:10BC90007D16EE0B6718887EA498CE26C493D99E95 -:10BCA00063AFC27142E235CD29E9372059BCB5FBFB -:10BCB000F09E67207D7BCFC92F319D2AB5EFC3F35E -:10BCC000255246889FD26BBF9811DC9B87335F4A11 -:10BCD00032963B6E10914E75EB6F9A86FE54C150B2 -:10BCE000E71A584F5802F31B601E61BDF689797B35 -:10BCF000A9209CCED54896F5150DD8DFA808BA7FA7 -:10BD0000C0BE03AECBA7F34DF457F680A8473A0E5A -:10BD100053F68FC3327BED1FD3FCC2304DE1593B4C -:10BD2000E4C3157A5F637BCA87FB776B13526E108F -:10BD30001D3DF5695F19D6BBF2BB1BAB685FFD26E5 -:10BD40009315CF9F8529FBCAA1E374A53A5B67438E -:10BD50006AB418647316F1550F5F72E0D85383E626 -:10BD600001F5FA9CA73A6E731EC783DA9FD1C264AD -:10BD7000B42343F7AD43FB817970BE56EAA9FD3188 -:10BD8000D646E70174888B517DB5ABA7B90DDFE9C5 -:10BD900024BB1FFF82E382CC1A43FC35AC55DBCEBB -:10BDA0009CCACF0DA8F4182A2FA5D0FDF7D47A6F1E -:10BDB00038E1819F2708AD1F0AD7D0F6F0B7335876 -:10BDC000DEDD60E1FB885DA99DB922AC7BA53D4726 -:10BDD000337F5ABFD0D37FEFFD3C6DBE4C36F6B9F2 -:10BDE0003E94077DCD77824EBB6F596CD1B62F8DB7 -:10BDF000D17E772568F39245E9DF916DA2F31A8E23 -:10BE00007C139EF753F9D818E2EFF78ADF2AFA2E4F -:10BE100091C9741E7593DE790EE5C4E33340D201F7 -:10BE20007D3C2CF8CC582E55B45B510FC6ADD39346 -:10BE30009C7AFCAE5BCEE0BDA016A06B84E571F7EA -:10BE4000479B6EC57CB148F10D9BFB7039D251CB3D -:10BE5000775FBF371BCF9F3A0D74CE5B3DB7B1758F -:10BE6000AC612B1E0B8ACB94CD69F0FDA12AE68430 -:10BE700099B02363632371FC2DD1A215F5DDF3D1B5 -:10BE8000F5FF8E7194E6198CF61942E15737D246C8 -:10BE900072366E75B680F75B1E1E9B5F8972310627 -:10BEA000FC6594AF90CA7DC517C715F0F8C0B6C53C -:10BEB0002FC523BE37580FDB699E15A213A7D85292 -:10BEC000C1E57F8B85D13E7BF3A852371E4DEC72C6 -:10BED000C90E3C8BD8E2DE41F35E592D72D9AC9C81 -:10BEE000970158C851399CBE0C364AFD986E34B340 -:10BEF000F839289792C2E87C507FF681B484CB57FA -:10BF00006C6FCCE9BFDE43118DF1C85CCB67E49F59 -:10BF10009F0BFD6D9DB199F2AA3C8D53E8BBBBDF31 -:10BF2000103DBA1BF04B72361AE42C9EC7638E8705 -:10BF300089B775F5C2B4203AD555807CCDE2E72E9D -:10BF4000307EBBBEA834E387FC4C9D9BCBE51855E7 -:10BF50001EBBEB9761DC05DAFB515F633F78CE0FC8 -:10BF60005219D7B751A83F447EF30C8303EF39E849 -:10BF70002A400E437B5D82564F1C18C9F135FBC128 -:10BF8000BBCC9EA0384D8C721E66A3BEDE9C06EB19 -:10BF9000D93843746E07786CA96810FA8AC7C455FB -:10BFA000707E990DF5D16FDE5291131BBC9E668C8D -:10BFB00073C0D036D70F9FDBD385C8BF5D2379BC54 -:10BFC000BD67DD1CBE71403FA8879A4797AEE66A01 -:10BFD000DA41725567E56D6DAE7A3A07D955C1CF32 -:10BFE0005DAD13F87E82A4C4CB9B8BF249BFF44BAA -:10BFF0002F152B499F84E2579D3FFDE507E91199D5 -:10C00000F1F119879BB4CE4CFAE107DA3B74F94A97 -:10C010007DD40B1E6D7FBA625136E3F8A85F10AF76 -:10C020003AE6C57B93A1FD952AFC163A1FC969E043 -:10C03000EDB19D8DF88BF4DB6901E0C8E982CEA1FA -:10C04000B3F7383CB7243A7C6BF8012ED28774AE34 -:10C050002BA5F7788F098E65B8EFE87D5DA2F3E731 -:10C06000A17A4FCDAB7030B136E79C3EEC4D9C0FC2 -:10C07000EA3569A7D789FA01D0978AED362A4B09A4 -:10C08000BBB3D45CE0E8ADD7BA5C6DABAF82729362 -:10C090008399F6033C4C53997F30C079ED33CF1C24 -:10C0A000BF8AF53D0EAE03F899E0BCE6F94733E6EA -:10C0B000407BF3EDAD26B4B943CFA1F56EEFA47686 -:10C0C000714BAB4CD319C5236554B986080BD9AF56 -:10C0D000CC7486E4B334C9C6EDA7103DB90EF85050 -:10C0E0008FF04A6404AFD03871E8F84905C9FCDE26 -:10C0F000E4E2521A774345A71EE3905DAE7AC54E3F -:10C10000F2F4A9EF42FBB17B3AA723FF77151AC8D7 -:10C110001E7EF8C1499311CFDE6512C5D17AD17B5D -:10C12000C8BA3D23F59CAE1C8BCD287FB7CCB9DBBC -:10C13000ECE8C3FED852318BCE2F5A96703B63A5E4 -:10C14000BD81E488A542B9E7A2D8CB71AABF13A2EA -:10C1500027B7543798F1DE9B7ADE9085D8DB97EDD0 -:10C16000BF1FBDBB61F98BF1A84FEE2A6988C77963 -:10C170006F89F04F7713DFD5939F02F2381EE5F1F8 -:10C18000A2910E922FDDF27FC6393B0E1E18695523 -:10C19000F88ADB435FE27F41BF668D92A714601C83 -:10C1A0002DB5448E7660BC74DFBBD300AE93BD7AF0 -:10C1B000F2638DFB81F4C12F322638495F9E1E68E1 -:10C1C000B0229DAC6AFC468FF76BCEE2E955E87F62 -:10C1D0005502B78756C51898DF42F3A1454F752E13 -:10C1E00066A8A7F509DC3701BFC58F79162310FDB6 -:10C1F0004C8EF1BAAD00872931BEBB30AD4AACD709 -:10C20000D9609C1247B480F09DA263C5061EAF9D05 -:10C2100085F35C11F311C55927A7C5D17D54A3C57A -:10C22000ADC3FBC97A67D5F6B58CCE8B51BC15B0C2 -:10C230004AF7E18C18C7BDB6278EABEE13A9F1DC27 -:10C24000750529042F21C1FF2DE223CB1A10F11E01 -:10C250007E983E40F6F8AA4613F941CD093BDA91A3 -:10C260003D3223F83EA47A3E17E063B1027C560CBF -:10C27000BC9BD6959414BB17E7A5FA91F120AF505B -:10C28000DE6525CC9B8AEB4B7AC3ED4A867AC60CD9 -:10C290005D366016E0EAB9A278AC1EC6213C58D8DB -:10C2A000384CFBABBF22D140F1D8D0F2270B785CE1 -:10C2B000320B0521AEEB5E13DDCF5D75E0BEF7AA54 -:10C2C000507E1E3039C967678114BCFFDE1D77665A -:10C2D0007CFFDDAE9CBFB5DB0D743FA63BBECCF84A -:10C2E000BEBC1AE7881AE5D98C78F231C721F4C7A9 -:10C2F000FEAB718F1B46CA4F607FAC6DC015C56326 -:10C30000C2C6EA689F2729857982F7055629EB5F1F -:10C31000D50D877A3BEAF575289407F60F878D3798 -:10C32000E7BB2622DD46EC8847FDDA47BC431317FE -:10C33000C17B2879B10462FA93AA799C2466EA3C0D -:10C340008A774853F93ED90A1660FCDCA0C0847C89 -:10C35000BAEA4BFD0D7087E8D7CC7A929391AE90F4 -:10C36000B8482F7F45E6766588DCDBA2F0F9F1025C -:10C3700025EE91CFF2BFE79325BB2852D9F7891854 -:10C38000954272E811570AD943C41C41F0BE9C9DE6 -:10C390007350B1877EA79C8FF72BE7830F2BE78322 -:10C3A0005FC5770BC0903F86EF16407ABCC949E560 -:10C3B0006F341528CA99E36F45EE9248B21F94F97D -:10C3C000E994F9ADB04E7325037E566DD3D37958F9 -:10C3D00063C284E968CF32AFDC9E11DB73EF8775EF -:10C3E000C2BFFC9E73A75D091E3A4F3AC7CAF73F0A -:10C3F000557C2D54EAAF12B619905FC7766AE136C4 -:10C40000FE52A4C6AE2C62DAF397134D4334F54BBB -:10C41000ACDAF39793ECD76ABE4F7668CF5F5E973E -:10C42000313E641F564B570B13806E804EAA337DEE -:10C4300034FF85D6528A7BCD0DB9C77447AB363FE2 -:10C44000DFA7CD2FDCADCDABE7C9C34629F43092D1 -:10C450008DFC31F14EE4F70C85EF0701BF6FB33A65 -:10C460009911DACF1678BFF81EC6001BED4BC976BE -:10C470008C23ACE3F79FB05CC7CBBDC395F67ABE07 -:10C480006FC58EDBE8BE1D4BCCE1ED06F0EF7EFC08 -:10C490008EA4F1720EAF87FE12D61BA2F453C3E531 -:10C4A000939C45FE829BEC33236BB3626A01FEC210 -:10C4B000349A39E99E750CAB27BF7590727F325163 -:10C4C000E8A4BC43B086613E4570A6F0F8858FE4D1 -:10C4D000C35049FE752AF1895B7447F4E6970DB99C -:10C4E000BA07F0AAF8860291E4E2235646EFF9D89B -:10C4F0005CF713BF6EC316B06E336B8F49157AF8B5 -:10C50000E7EDBC61C45F135C0EDA2FB515240B7820 -:10C510002EA588859CCB364569E8A3C41A17425FCF -:10C520004342E84B4B7F7F9DECD5453990CE42E8A6 -:10C53000F02FBEE5512C18AF4C8FFA058FD58976B8 -:10C540004A059ECA02964F75469B31EE678BD173A2 -:10C5500079A5D83FA54A9FABE459EBB2E1FB6B56F6 -:10C56000D149E6F6BA2D3DF12518DF9600F635EAF9 -:10C570006399915C7DB0D31F7635D47F04FCFF6551 -:10C580000CFD1BEB64BCEF65B5E4105F3F624979BD -:10C5900000F35ED0E8587F4331F7AFE5E86C82EFF7 -:10C5A00051A1BE05EFA53DC2F24CA9C1F52DBCFEBF -:10C5B0007A596451909F183182EABF9D6766F8CE20 -:10C5C0008177A0D98771EC63F2AC77DD41EB7F7B9B -:10C5D00014D707AF191CF1A80F1E997C77A687D234 -:10C5E000748D5F684B10E4BECE17858F3672BD9296 -:10C5F0005BE2C7787C74C234579903FD1DB70BE921 -:10C6000042E712F1E85B37FD442B7EA8E406C10F38 -:10C610004B9B745D0E43FFE3110B77351E299ED5AE -:10C620005286F90291EE03D95CE2EBD9B8AE027EF4 -:10C63000FEF04AE571A81E18329ADBBF9386443C8F -:10C640003014FADF50245AB1FF0D7A2BDDE7F14E9A -:10C6500066E45717BBEA97E0BC6D09110CCF6FDA9F -:10C660000A1A78BED8C0CC004F936BBD17F1694A47 -:10C67000F58CC0F647077E7A1CED195B82483A704C -:10C68000A2CBF9AE1BEB1728F19DE279EB703C9B36 -:10C6900045B49A590F1C54B9BE9EC9CBC9FFB20A02 -:10C6A000F4DECC0A6B430DCEE7918470B2F36DAE2D -:10C6B000060BE279C3403DD14149227F576A55C2FA -:10C6C000B40ACCFF62A09171BEF32F1F8AFE815382 -:10C6D000A075355B1A685EC72E8939C1EF96A8A987 -:10C6E000D9A185CFEF46F1F89009E3F1809FB7F526 -:10C6F000CC9C9A8BF4A3A778537F7C6B735DCE7E22 -:10C70000FB61FE2A94030B11BE8597C2984F40FA35 -:10C710003D2961FE777F015B80D6D960C1FE416E05 -:10C72000BBFAA2BF88D19C7E9B0B0E4BF84E82D7E2 -:10C7300021101F345B4E4E443E7828B58CE8E8A1AA -:10C74000828F9A892F86F3FCDB79F7EE413C7A13CE -:10C75000C3697FE7A1825931C1F4BE609448F432C5 -:10C76000EE6F614E3FE2639481F8FB9108C7568CEF -:10C770004F79F3CC64BF4B8275D96C98E7C46228BB -:10C7800087FEA25D623EF17E75058F0B2B307ED554 -:10C79000653B84F8904A66317EAE4939F71491EFD3 -:10C7A0005C4335B4FA6F952597DECFD892D07042AE -:10C7B000D9B620BB6A9022570694884528DF0659CF -:10C7C000B85D65EB940594BBA1FB47AABED729EDE4 -:10C7D0008C325BA6A3541B37D215707D1B6A7FE990 -:10C7E0002CDC5EC33FBC8FAECF353F89E738743158 -:10C7F000DA7A7F19A59C730AB1AF543ADF60E57A03 -:10C800006243AED18774BDA198DB592A1FABF247B2 -:10C8100085BF2A87D47B7EEF28F695514E5E3687FA -:10C82000E4EA99E5786F07D49E7317C37B8956FABB -:10C83000FEAE721FF194626FBDA7D85BFFA1D85BFB -:10C84000EFA3BD05F986518308BF37142E76DD08A6 -:10C85000F31A902011DF143A4E4CC4EDAF71192732 -:10C860002C7DD96111D1A20EE3058F34F27B4936BC -:10C8700097ED9815F159CF95F92C6B766934BBBCBF -:10C880007CF2E37AD2D13EE4EB7B55B94F794C99F7 -:10C89000FF7165FE6F28F357ED8F4943BE32A1BC8F -:10C8A000DF10AFEF477E29FC29A7D0B9A85079B592 -:10C8B00001C408E9EB2291FC9F2078E76AE4BD25DA -:10C8C00020F7F54E59C9681EBFDB6076572C467CB1 -:10C8D0004E6614A79DE8AA27B96503B94572B3F857 -:10C8E0005CEB6CCA473883E59E518163B1CB5A8EAD -:10C8F00072BE38464F1F5724A4D0BD5BD5FE0E1D17 -:10C90000F772F00C9567A682F55EE2F3FF47726C52 -:10C910002CE3E38EBD243AFD5CDE1C4F2679239187 -:10C920007C0AED5F95376F63CC6420BE4F64A1FB3A -:10C9300000770A614E84E79D287C303F97D17DFFC8 -:10C94000C18A3D6757DED1014EA1B8CED84EB0F5B1 -:10C9500083F87AFC2553F71B6CDC8E8FD6E4279A7C -:10C96000E235F54BACC99AEF93ECC335DF273BB208 -:10C9700035F9EB324669EAFFC259A4C9DF50305994 -:10C9800053BF4C2ED3E46566A577480E36ED1EFAEC -:10C99000B11EFDA7B6A11FA7F5864FA1F1F00B0EA2 -:10C9A00060E1B5A38B67E80046855187EF4C86FCB4 -:10C9B000C6D19367E880EF0A071FFE3A195868D37B -:10C9C000E8293C7FF5E1AF5320BF65F4753C3F8615 -:10C9D00091F0DC3A7AEA0C2FE0591CEA797434D0F1 -:10C9E000F12D97EA8FA23DF8C765D3E6264BF84EA6 -:10C9F00040596206CCE76C8AE761FC7E73ECAC15AB -:10CA0000781176FC77F5748FED37A379BB8E8BFCAC -:10CA10005D8D8E8BFC1D0DBBC8F1F65353F5BECB5F -:10CA2000040E9A7EDF5F11647EAF05FDCD3969DCAF -:10CA3000DFC414FD4D4CD1DFC414FDCD397AEE6F47 -:10CA4000628AFE2696A3BF89E95B4D32A5EF34B911 -:10CA5000286D6F7253DA7DBFE029E76A3D0A38EF2F -:10CA60004F8B5B98C3E417114EA1E74A3AF49D4FF0 -:10CA7000D07ECA45E6C0FB1287224E3970BFAC3962 -:10CA8000CF44742E74B63B4CF0BD3097E79B2FB665 -:10CA90003B507E611EED9E8EE8B66C94BFCDB51600 -:10CAA00027EEBB355FF4C7239F14D61BE8DE4C711D -:10CAB0006727C5E90A2DFCBD844311C78E28E39181 -:10CAC0005CDA7991F9457C27C7DCEEB02AE3603F58 -:10CAD000306E32EAB7C225302EF55BBF98FAA9B0A6 -:10CAE000748F2B848C6BFAE171270A41E3A67631AF -:10CAF0007A1701C77568C6F54B743FFCA25FC27810 -:10CB00006147B4D38E714D355F8CDF21BF45CFDFD8 -:10CB10005F2C74F825D493B8BD89EF5BC681D833F8 -:10CB2000D3790D1FC965A84771B99D5D7C9D179A82 -:10CB3000FC0B909F8A957760C08CA57B9B4C0C73F7 -:10CB4000A2BE2891BE3B363817DF39E3EFA0151B94 -:10CB5000DDDB901FEB745CDEB01833DF57D0B5CF50 -:10CB6000FF15D43B193B98EC9504FB4B2C7504B492 -:10CB70005FE4CA44BBE3245B4F72687594E77F8F20 -:10CB8000067ABE31B35E50F427F5637785EFC0FDBA -:10CB9000888E5786E5211F4D333A5E64C0BF7F1FE4 -:10CBA000DD44FC3C2DCA91872FACFD7DF40A9E8F9D -:10CBB00073BC883783ADAC694671FC8F3F2F45F15C -:10CBC0000D749AA70A3AB47FD4735376D1133606FC -:10CBD000E054EBFACAC0E7D769C07870D41807C12F -:10CBE0006FE06146E7983A2747F876E07EDF80FA03 -:10CBF0006C8C87B24C471ED64BD277D27DF28EEF2B -:10CC0000F8FD27A819795350FCFE898392ABAFF841 -:10CC1000E3C931DC4E5D946A598778A8B39B4C9484 -:10CC20001EBC48E78299CE9D8AF16BD9D0F77BA9CB -:10CC3000AF8EE1FA2179A54131024174C294E53009 -:10CC4000A6E6BD0CF4D0F6BBC3BADF8B037032434B -:10CC50009AC8F3DE1D8F17EB34F565ACDFFD1DE3DD -:10CC6000F4ACA7BDFCDBCD8F2F4F55C6437A99C7D7 -:10CC7000C87F0CD53B6B0B6DEA3B3F84E7C763CCA9 -:10CC8000DBE93D5249798714EA5A314E11CEE83D2D -:10CC9000AEC1BF37FB9A819E769A393DA78A3CDDAB -:10CCA00029F2FAEA3BA5EABB6BCF147A6E2BCCA330 -:10CCB0007EFCD48FB4371BDFCB88676D34BEFA6E31 -:10CCC000945A2F01F420092B5D673AE2AB5012FB16 -:10CCD00084E7E7638AE6201D5C68F2B24F82F4CDF8 -:10CCE00085F0C8C660FCD549DAF75A3F1F3381DAB0 -:10CCF000A9ED6B1B27B24F2878E9273AAA4D156991 -:10CD00001FBD4E62AFE23B9C20590DA897D576A778 -:10CD100040DEE278EF82FCC5F43D90BB9FE8D13E57 -:10CD20009D4EE9FB4D1E2A3FDD544D69A0A99ECAC8 -:10CD30003F6A6AA4F496DB2372917F16ED5FC63ECC -:10CD400009A2F7DA36BD2710943F55D4371DAD51EF -:10CD5000E8E85472DFDF9F1CC3EDBB53E3383E3B72 -:10CD6000C0DEC0F7DA802E975B6DFDDB1D1DCAFDAE -:10CD7000AEA3E3F9FE65473CCF2F1FC3FD6E596498 -:10CD8000ADD8FEE87803EF3F45ACC6EFB28DF77B38 -:10CD90002A5DA477A47E35B1E8FE31583F16CA73E8 -:10CDA0007AF2A7AEE2DFE541BC5C9DAFFAFDB64288 -:10CDB000ABFAEE613A7FCF8FDFF7027AA7FED5FAA2 -:10CDC0006326703E0CADEF4BE5E7C943E1F1A9C224 -:10CDD000B7C4176867231F2407F1459D83F842A550 -:10CDE0004395FED6167238A71A153A0FE7E7EE07F5 -:10CDF000A32E847683E3CCB48F20E3BBCBB09E9D7F -:10CE000082C22FA1FCA0BC63ACF283CA072ABD0F6B -:10CE1000063EE3EF34F3758C95FA795F5859477BFA -:10CE20006CC45D84D7837A2BEAADB1127F2F79B0C1 -:10CE3000D8F5CEEDC89FB1110E8C9196ACB2D4F757 -:10CE400025C73EFEAFC243950BFDC0A3171C0CCAFD -:10CE5000BBC33F120E24E7508E23FDF621B74E8C44 -:10CE6000B1297617A7DFCFC7C86F221D7508661DC9 -:10CE7000DE7BE830F77D5FF0E878BE0E958ED61643 -:10CE8000324A07E33A87F6967BEA7ABAD7790723DC -:10CE9000F9971AC6CB43F1ACAE2B48FE9DC179A9D8 -:10CEA000F0640CEC1FE827A1C642EFE8DD56E8E08D -:10CEB000FC36F0D3CA0DAC67FD358A3E7B4C94F846 -:10CEC0007BC88A7EE92E17A49965991ABD4347CF7E -:10CED0003A5FE1EF8AFB45568DEF72A36F1D1C1779 -:10CEE0001F52C8E543D7F43C11F7132FFCD542F786 -:10CEF0008B2F0CEA3C8DF6CE85563D53DE239B2AC4 -:10CF000080DE9D8B3E130CF9A5F29EF3E7E8F70E49 -:10CF1000837A6D174FA3BDB568ABC44C789E60EBA8 -:10CF200037B7203DCD7B454FE7999A5B371E477A4F -:10CF30003CB74FC0E76FD9857D02C5316B5B227C62 -:10CF400066A85F0A79AC7FC76EC9C7E38B32C53963 -:10CF50006A94F13E31D7A5A05D3E71EB5D3A84FB4A -:10CF6000BCED028B837E8FB4DE790CDF1D39B78D6B -:10CF7000DF2F6B3647EEC0F9974AEB0C83A07CC1DC -:10CF8000765E5E6329FD0CF743173CCD28FEB36047 -:10CF90006F04F98FF35AF41F0582EC8EEA6DDAFC08 -:10CFA0007CD666403A58B0535B5EB307F241F279E3 -:10CFB00050A1122F19CEB2295ED2C2E307AA7CEF8C -:10CFC0006D5F7BB91C6D50DEFF667F89A5F70F5F33 -:10CFD000F926E9230BCF9729F93390FFEA1B8E1727 -:10CFE000152E75CAD85FC5B3DC365867DD2B662BA6 -:10CFF000FAED7507CE46E279B04561017A1799BD21 -:10D000002C59D1DE7B60BFE445F8D61E343F89FB46 -:10D0100098752F9E30603CA174DF62B2572631EFC5 -:10D020004AF49BFDA2C8DA898EDAE97D5F2677CEC5 -:10D03000C37E2E1C305BD10EA87BF94FC76EC7FC98 -:10D040008B02DDA7BC9018203A99B755A27B430C00 -:10D050002DB4FC1E3A9110AF88E7B6287A8FE50E02 -:10D06000C43BE219F0EE48463AE171D0794F4BF4F7 -:10D07000BDB9B5D980F5CFF9387E55BC974A4B0973 -:10D08000CF0B1EE7F89CB875D7E630A483A7F564EC -:10D090008F1F817683783B0D1D185EE1FD5FD8C53B -:10D0A000CF9177D3C10163371DE03C2F4707C0A75D -:10D0B000A4F72F47079DE89792BFFFDDB9C7D00EB1 -:10D0C0008FE0E787D5771BD5771A072E3C7514DFDD -:10D0D000E74AB3BF407677A5ED8BDAC58CDE099DB4 -:10D0E0005388E74B26BFBD02D17772CAB3D9142F3C -:10D0F000D507766DC178437438C5C73A92CBB6E18F -:10D10000FB98C5B66F93F6C23A16FDCE48E711EB11 -:10D11000157EC63F3C07A2BE4B0C78A7F319B50796 -:10D120008DFC5CC63EEDFBE11DF19CCE4B0C9D954C -:10D130008BD14F80FE701C41E6FEE9C283FC1D4589 -:10D14000D59F5CA8BEA7B847FB6E83607D9BEA3D78 -:10D1500050984270181A37D68176797339F3840D56 -:10D16000FD217DC1DFA97C5CF18BFAB527FBD11BCA -:10D17000AA1DC9BC21F7DA15B97547019FE3D1BBD8 -:10D18000DFD0E17B8C1D3BF9EF3BCC3F08F22A0658 -:10D19000F719F51AB953A7D4FF14E90FE076DE5B4F -:10D1A000FF922805CB97F78BB19F9AA7793F7548D7 -:10D1B000571457F56F0E83FEBE6CD333E497054CBE -:10D1C0009137FB23286ED44BBEECDCBE12CDF7505A -:10D1D000BA5A0876262E2294BEEAF669EB3D5DA87F -:10D1E000EC7B0E67D7E0F9FFAF31E090D7235FBA51 -:10D1F000DFE9678E28E4EF6E7D2868EFEF0F6B059F -:10D20000960FEA77B8CFC463A44AFEEADD564DFE16 -:10D210009A36BBA6FEB5FB1D9AEFD9FE0CCDF711D1 -:10D22000C79D9A7C5E7B81A6FEC8F7644D7E54C084 -:10D23000A5A93FE6BC5B93EFCA84F5F461CFA8E9EA -:10D2400024BBA0A93FD961D6F47F5D46B426DF6533 -:10D2500051E0A3D899AAFDFBA7426EFF86A62A7CBF -:10D260007FE1D48EA3FAED371468C72B93B5E35D45 -:10D27000295EF01D419D9EFF7E02A6F8FB09BA348F -:10D28000FEFB0998C7DF4FC0147F3F01CB7FDDE471 -:10D29000A4FCBEA602CABF047E09E6F7839F82E90A -:10D2A000CBE09F60F9E5E0774C19F7B832EE1BCA86 -:10D2B000B83F154E6F29FDBDA3F487EF0DEAF43D8D -:10D2C000DF6B5D79E225E0E322DB67745F596E086E -:10D2D00094621CA3F37589E1F967E6F11D6F8A4139 -:10D2E000FD3680A19DC4DC9D6FE23E6EDD8B43ADBB -:10D2F00078AEEF81FD7F7807BF5FD82751BCE6F09D -:10D30000FEB391D8CF9797C2E9300AE945C8D77CD8 -:10D310002B507E0D7CC7736793F74ACABB676DA419 -:10D32000EFBE4C55F33EBA2FEDDEB3D780785AB836 -:10D330007B2F7D7F1DF85AF37DF776CD772BD6872F -:10D3400074A1CE477185CFF7ABFDF9A97E4D2A7F39 -:10D350003FFEF3DD47568E417DBCB76A00C6B51768 -:10D36000EE39113BFB07F0F1D54BCF66A21EA83D6D -:10D370002029E7D1787FB507F44A9ECFBF26756F85 -:10D38000299E37637B04BAB3F4255B4FE7C416EEDE -:10D39000DF5583727661C6ED7A8A7FB5494ABC83D0 -:10D3A000BFD3506365DCAE6BFB3A12DFA9FF7DDBB8 -:10D3B000D1EBF11E74C7C123F45E4CC73E49E34F65 -:10D3C0008D1DCBF13B762CF7FFBEDC772412CF0905 -:10D3D0003ED07684C35DE7A7F51F56F21D9012BCC0 -:10D3E000F74BB4FEF99724CDEF01B8C071A1FBCD86 -:10D3F000FBD322705D27DBF878D3407D50796AD566 -:10D400001C9CFF1BF6F23CE57D32FADDA18EABAE33 -:10D41000DB857276619BD4E779F739D82FCCEF980A -:10D420009ED3E9EBA92F1C1B04707FC335209B748E -:10D430008452AF622CD79BA5064F2AEA91931647D8 -:10D4400004D2F9FDAEA11188DFC39862B9EB49BAE5 -:10D4500007BE601F1FEFA4B53D12E9EEE4BE1152F6 -:10D46000F0FECB2DCA7ABAE9BB1B6F5EC253B56F13 -:10D47000BB05FBE9C11F2F9F36D64AF5DFF09DB8EB -:10D4800005EDAC9319FCDDC0630646FEF5C23DDC3C -:10D490004E3E7970F0F6E0FB59D3147C7464F07D55 -:10D4A000F50BFBF54ABDDB77314D3D3DC7D74EED62 -:10D4B0007CACBE330FA17D5EF3B844671D6AF4F502 -:10D4C000B1B8FE4FB769E757ADC0B946EF8F8D0DC4 -:10D4D000A2D79A03DD7C63213A3FA0F28983F0A9A9 -:10D4E000E2F16486C4E765E7EFF8D5ECDD4574DD6D -:10D4F0003BBEC4E3B783EF313929BE74197F5AB5F7 -:10D500001B82FC2DFABD23BD6B689E98D2631F9CC5 -:10D510002E941F1A9B877E989BFCCC930CEC5B1877 -:10D52000B316EDEB28FA1D89CD386ED73E3DBDFF11 -:10D530005F6B3AB000DF23EF7202A3C0BCBBB6E959 -:10D54000BBDF67463B779E62E77EEAF0E44BA07F55 -:10D550006B9789B4BE9A3D920FCF175C50E4DE57AB -:10D560007B936F407AAD392E59D13F9AD896FC7093 -:10D57000612EE977B257EBDAB89D5CB75B20BB58F8 -:10D58000B5436A153BE49C62079F5BD6C9EDE35740 -:10D5900004B611EAAD0D037B04E65D9B3985ECDA38 -:10D5A0005A69DDCAC10E3C47A5B51BE61F3C44E7DE -:10D5B000AEC0CED1942FDCADCDD7B669F3AABFF8FB -:10D5C000D2D86E3B6338FA372552611CF2C39B0AEE -:10D5D0005E557FE7CE6B9CF4FB270FE81C53D4B855 -:10D5E00004C26BD12B2FCCC779FB6AC29CE47F3479 -:10D5F000FE96E0DAF117EED774E0DE1BF233E3F0CB -:10D60000EDD8CFE97C915EF0E1EFBA2C425D81FD6F -:10D610009904DF328C3B7BBB22493E29E7081ACABA -:10D62000B9FF2A630C18A6B27E2CF7E743F5EA3857 -:10D630005D408A0E921381B12954AFD8C0CF57DE16 -:10D6400019E124FD36C4C4EDF521266EAF0FD17566 -:10D650002EA3DF851824F07D8EAC9769FF606D9D49 -:10D6600085F617047B950EE1B17650950EE97D881D -:10D67000B52D03FD3A355F8CDF337BEC83528B474E -:10D6800087E3EC8C17947D04AE4FCB74567D749079 -:10D690007E656C99667EEA3DCC9F7D7E56989FA5FF -:10D6A000677E80EF286CFF75AE93EC86A432F5F7A9 -:10D6B0001AEA492EA8F0FC12E8BD187045776C8173 -:10D6C0006E6AB61D22FFB296B5AFC476A5917C1DD9 -:10D6D000A506FEBE5169184F75E3B8FC2A51D2A5C4 -:10D6E000E3B4F6C39171B27E1CA43BC6B94DE3F21C -:10D6F000683F9579617D0D6FF377D643E53E9413CE -:10D700003D7D0D7C88F26F46BD604DD5D8699CBFCC -:10D7100016F1A26E3E5AF8F693C427EA39CC6AC6CF -:10D72000F97B66A3D99A1AC4178B90DFD0DE77C332 -:10D73000BF7C8C13F0BF6AEB7C3A97E9698CB5A289 -:10D740005FB748FA92F6257E2CDF2DDAAFCDFBCD00 -:10D750009CFEFD1102F94919E3BAE30DC48F490A91 -:10D760007F6CF708740E60FB773A1ECFAB10287EF3 -:10D7700077331436DA944962BDEA22BA4F7233E342 -:10D780004763594B8CF2BB3D31B46F7993B2EE9B3A -:10D7900075FE4328578EEADB92319E74B4D6E4C4FA -:10D7A000FECB591BBD6F5AC1DA293D155EF7A29F0A -:10D7B0003AF72622DDFDC963A478D6F6E53B225070 -:10D7C000BE67B1E556DC4F0450ECC6B701FBB3733E -:10D7D00042F71DD5FBC4602FC7217D02FE27211D06 -:10D7E0009C07DCD8737AB75FF8C71723117F5F2CCB -:10D7F00079E1965B19FA5F9DE4472DA85F46F75DD6 -:10D80000819CDA33F27BF0AAE25DC55B375E1DF0E6 -:10D810002F18AFB0A6048493F46519C9A57F91E8C9 -:10D820009CD6E5F0AAC27DBC829F3B0E70F9158A9A -:10D830006F150FB7E2BBF54349EF6E233C3123C9A7 -:10D84000CB507AB81CBE8030E93CD9C41823F9A16A -:10D8500083452E4F07CF13285E793BF3BC1280F42B -:10D8600096F0F7F5FCDE0AC75B8582B73F31DF2F04 -:10D870003292FF71783B32CEDD346E606FBE0DE5C3 -:10D88000D3FEF8B2C6E1FC37555FFA18F263083FE1 -:10D8900087F06B371E9DF02F088F9EC648E2CB6E37 -:10D8A0007C4B7BAE4C2FE27F308EB55FF0F993AFAF -:10D8B000805F0546BFBFF8F838ADDE54F1A6C2A5BB -:10D8C000BFB8E007CC7FD42AD0BE0AE7E3BB8D7493 -:10D8D000FF43DD5751F74F5E19C7F55C68FA01D871 -:10D8E0004BB85FB526E3E440B4334F19D47EF8FE5D -:10D8F000EF07CBDA13F1F7B63E28E2E92903FFDDA3 -:10D900000F352F87F1B8E407F1462FC2E90361F81C -:10D9100004D4331F08F75CCFF3710607E6CBE32688 -:10D92000E03D90537A358E79BF127FF0F179948F74 -:10D930002CA67A02FF5D4A07FEDE1DF62B0836177D -:10D94000CCE783BBD2E87D9DEE7D8D71DC0E7F46FA -:10D95000594777DCFF5E81E2FE335135E1FEC48436 -:10D960002D2E7C87F3F47D43B369DFB4413B3EEA5F -:10D97000FD648A976EE0E7FE2E75EAAB82F45BB732 -:10D98000BE2DBEC8CBE7E4D1EF8CA8BF4727DB860E -:10D9900073FFDCC77FDF50D5675DC75FB004C77317 -:10D9A0003F53E2DFDDF9E10F2605EBC3434FAD4DF9 -:10D9B000C77EAA0DDE2CA7057F87EEB124B45BAA33 -:10D9C0009F5A954EF6F4530FA4A35F54BD636DBAEE -:10D9D0004CF9700FF9653ABEEE2F9E1B45E7F3D464 -:10D9E000FEF6CADCAFA8301D2A41BD3DE5EAAF56C0 -:10D9F000E0FE41DA7D02C5FF66B0F615A8672B335D -:10DA0000385FB11613C97FE88FF66B770DFFC54EEF -:10DA100094076F649CD5CF817A123E203510DFD5F4 -:10DA2000F2ADA3DF095CCD7F27B0A77E22EDFF56C4 -:10DA30002D17E89DAB19F5FC77F3A4F1D104C75974 -:10DA4000ABB38FD1FB574B79F914A36FDF49EC6768 -:10DA50008B81DF3F64EE94E0FB7092B25F38739D80 -:10DA6000F27B71CA38699B63B707AF5352F61D59F1 -:10DA7000EA7724DF6E50F03275E98957EDD0EF5424 -:10DA8000BDC73C1EBEBFB3E95CAA9F611CF4333A1C -:10DA90005F9866F03C3A1FD7BDC34871D2DCACC179 -:10DAA000521CD4CF5952B411D3994BAB1E9D8F72D7 -:10DAB000B8D594CD8F35F2F935084E11E5F491EDD6 -:10DAC000B7CE42B89DDFC47FFFAB61FB30FADDC249 -:10DAD000FEE4DEAF9AF8EFF93DDD64A2F4D9262B1F -:10DAE000C3A3EBCF35D929FFAF4D0E4AD9F43CCDB6 -:10DAF000EFD8F4D7DF884BE1F4BB73B9ABCDF43B7F -:10DB0000880D4639753CC02BEDAADA1D0F28EBC2F3 -:10DB1000F7B8B2BDC913110EB90F2C3E86A6B37566 -:10DB20003CDF977DF3E4EA2414D6772C3DF3C47CE4 -:10DB3000F87EFB78F7350827D3B68B14A7387260C8 -:10DB40005525C2BB7A8791AF4F59F7F94DE9718FCF -:10DB5000627CF9753DC50D166D3BF3C4030C7F87E0 -:10DB600077B12198DEAF74BD578FE77EE6E5F8AA5E -:10DB70003F38FC78BE5A9B44FCB303F82AF3A7F362 -:10DB8000D5A2A5CB087ECBC6BB6F42B89DD77B93F1 -:10DB9000909FCE0F1F4B74EE7D4520F8AB72BCDB1F -:10DBA000AF56E0BF506C5B5798DC23C7BF61B90428 -:10DBB000DF43073E4D47FBF99BFDE53FB8EE97601D -:10DBC000DDFE6118AF33511AFA3DDFE019EA84F542 -:10DBD000E5F7F33EE8D2F16AFC9F9F53C03F213640 -:10DBE000F89D21E68D82F9D41C14FC6159A8CF263A -:10DBF0007DA643BF11FCCF8F34E78C19FB28489FCB -:10DC0000F737DFCBA575D84F5A8FDC1DF99EC8FCBE -:10DC1000417A7B54208CF983C6EDF673A0CC40FB8F -:10DC20004EF12417106F782EECC281E13B30FF9942 -:10DC300081E3F1C24B604FF1781093F27BD6F9D9B2 -:10DC4000812FB250CE86AEB7EEE52F883E6AF6AF92 -:10DC5000BA28D0FA277FA6CBBAFCFA0F3DF54516B5 -:10DC6000E2EF337D201FFDB60B864016E2A1EEB732 -:10DC70005C9EFF5838A8E5F3571BE8F73AEB04130E -:10DC8000D14989F425C51F2E1CE7F187BA034F92AD -:10DC90003CED3AC8E3408BC4F6D2388C9BD49F3914 -:10DCA00086F2ACCBCEFD31E89FDE712B1CAAE84199 -:10DCB0005D6712DEF73BD84D0FDC8F3C8FFC3B0CD1 -:10DCC000FB69A3F3BD2C2B9CA15DF139F2F3307CF1 -:10DCD000BF307925D2F979DFC01C948F6F66FDAD16 -:10DCE0008EE286BF0FA77BB2B56D92E69C79F73ABC -:10DCF0007C123F70C454FB299CC9C1E7B90C8E1B30 -:10DD0000C86E7E83EF132EBA8AF3137B99F353ED1B -:10DD1000F243067B507FBB157E52EDC829BFFF1B27 -:10DD2000F1E5B38532FD04D54FA5C7FF9FFEF74C43 -:10DD3000FF2F4133EC630080000000001F8B0800C0 -:10DD40000000000000FFA55A0D705455963EEFBD2F -:10DD5000FE4927DD4913421208840642881A6203ED -:10DD60008172D6C4E9FC6E2033BB016B2DC4088DD3 -:10DD700022249D7482E8EC6AB96E1A02AC6475368E -:10DD80008C59471D479B9F8028EC769440C0A00D7E -:10DD90000ACBA26B45AA263A555B54ABAC0EE0A663 -:10DDA00023823BD6E2B8E73BEFB5DD1DE24FEDA69F -:10DDB0008ABA7DEECFB9E79E7BCE77CE3D8FB45247 -:10DDC00022CA226ACFCD082A0AFFA66EA245446D58 -:10DDD00029247FF641451FAFD364BC7D40A3C958B9 -:10DDE00093EB08CE9E415447DD269A45B4844265A4 -:10DDF000A471BF29F2CB5B79BCFE0D6D4117936115 -:10DE00001BAD6AB013D5A67A0B3614130DABCAAA94 -:10DE10008662CC0B952E9D4BF40DFE7E4A749B873B -:10DE2000994F222AD3140FF61B9D9C16DCC95D8BDB -:10DE300097FB1B494D98A7EAF3984F53087C82A3A0 -:10DE4000254B1DD868B46499233EEF8E37D2D60790 -:10DE5000314EA1D23B12F6F94B8F856821D117CBF9 -:10DE600017AA0F65F279AEDA037433518D76ED2976 -:10DE700085F7DD70CC4C5605FC67BCAFF239026704 -:10DE800034EA65FA52470A79ACCCCE4B1E0FCF1B51 -:10DE9000993B29D8C5E76F3FA09089E7B51DB1EE42 -:10DEA0004CE1796DE648B69BF7DD36F03B8B87DBBE -:10DEB000F6FEF72CAEB958CF4736439E1415FA6DCF -:10DEC00077F24F17917F60CEFB77313FFF694DF4BA -:10DED000ED37BD6721D6D7059E8FFD5A0EF6D58248 -:10DEE0006EA5F05627DAFD3CAF48BF9B6FF8DFE523 -:10DEF0005C5786B3387EBEF8395DA2A718BDF869B5 -:10DF00003EF702D68B46EB437659EE21967B716E37 -:10DF1000CE8E2E25719DAE5F8F76694B0ECB159DF3 -:10DF2000A9B81566154D0D6C76421F858AB39717F3 -:10DF3000475F7FB9742DF49B122CBD9DCF17B59010 -:10DF4000DCC7E2C7B69BB40479160F6A1EDC433403 -:10DF5000959A0EC9BD7BA7E23EA8BC61A96712D6FF -:10DF60008DBE7B2B6F195579BDFDFA7304CA757987 -:10DF7000CEB0A9C97D1B72D7E7E5ED80FED900C4FC -:10DF80008E4EA9FAFE1E95C7E7C7D7BF689CA74665 -:10DF90002BCE89F0F806C59DE31C679F58BB87F51B -:10DFA000BE86EFE945BE6FB42F753869CD6CA2FD12 -:10DFB0001DB942FF73874BDA504791F4BFD2E11687 -:10DFC000FA60C72D421FEAF0083DD05127EDD18EEF -:10DFD00006E93F0351FF8C70A020ECE2147C6D4AEF -:10DFE0009C1ECE1C434F499E3F9CA924D353149999 -:10DFF000FF70B83C1860FAA532A79C938DCAD1C0B7 -:10E00000FA684E4B2FA10CB4F9414A67BBB17B03B0 -:10E010001EB6FB3FD4EDDA4333C5CF4B30AF3AF3F6 -:10E02000CE46F8DBE52C2B69ACCFC31EEFDF63DEF9 -:10E03000E9D35505DBD13F68735BF9FE8757DC9464 -:10E0400001BD47FF4D238DB7AE285AB0B994E90AF8 -:10E05000BB2276CCFC6E6EC866BBC64FE65335B8A5 -:10E06000BAD4A4E38473B602FDB7AEC13E1B26DB6F -:10E07000165879FC4AB9F757D827A6F7DA29EB0AD8 -:10E08000BCD08BD9F5BECAF302FF6EA65E9EF780A8 -:10E09000C39D64DF47CB2B82B09BC545B336CF070A -:10E0A0007F76BAD9BC3FBBF57EC8E751D3944EC149 -:10E0B000319709B810C4FDF33E952E45EC306C71D4 -:10E0C0009932997F38B5222BC0EB4E19F77DDAB81B -:10E0D000EF33C67DBFC3FDD5DCBECBFD6887B81F5F -:10E0E000ED8A989E4DA385D05FF0A70D2F7944EF60 -:10E0F000A3F9A0A3665A0E3B5C023FD3F127BF8170 -:10E10000E578A25C97E36E037F866E6BE8D3D785D4 -:10E11000844F8B85BCB0FF4B589F609FB175F1F564 -:10E1200024EDB29B2990C2E7A0C3B620F4445389E2 -:10E13000805FCB0EE7082E6929B38ACF4F647A013E -:10E14000099ED2AB567D5EAE6B21FC857524FB8C9F -:10E1500004D58099EDC49F395498C9F28E187E1663 -:10E16000A30FFD4913FCF6CF679ADBD714FD7CFEA5 -:10E1700065438513B05EB1A9B033FF4E7DFCACE1C1 -:10E1800087FE99063FE33C9412CAC77D448F1DCE9B -:10E19000BF87E92E7B78AD1E07C28582DF142E5C17 -:10E1A000069C5442E7C84DD477FC7DAFE927D047A1 -:10E1B000E879D0FDC77FAFD34ADF3967E2F8A450D2 -:10E1C000BEE204FD8141F73D3FC19D409B5F398721 -:10E1D00071CBA6DF7BAB27336E5883A73B6037FF3D -:10E1E000A2DB97ED40FF27D05BCB112BC12E2B0F6D -:10E1F000F47FF60A8FB7F43BDC80FBA86786E8BBA8 -:10E20000F3C8DEC7616F237D66F187AEFDBF7BFE7D -:10E2100011996725985BBD35544ABCCFD1E37FE3A4 -:10E2200035619FB4D015D06F579C1739EA27EAFEA5 -:10E230003D54F1A93700BDF51FF86BC4B5FA0C0ABF -:10E24000C06EE965BE4766E47BF5866A2AE171C760 -:10E25000D04AF06F7BC9EA869DFA5ECDA9841F5F24 -:10E26000F3CC14FB6BBEB13B1F71573DBA6FCF238C -:10E2700059986723C8DB9EC976C47AF5693B16DDD9 -:10E280002FF7B76BCF6F20F73E1BED643ECDCC036D -:10E29000FB35EF991D0CF0D15EFBFAE395B8871AB8 -:10E2A000EDB93DE8BFB2DBA6420F672D9E8C72F838 -:10E2B000E159B3BB17EB0CBA7978A22E4F5AA4568A -:10E2C000EE2FAB3B1F71D737F1E1BF80DCF55AF77A -:10E2D000F3CFE23C7BAD843871611FEB8DD75DE8F5 -:10E2E00035CFC72D8FEC7398602F9794EE95CF8222 -:10E2F0007FAF3EEF92AD5BF419E89D43D88FE711F5 -:10E30000E2F225657B52FF85DEBD255ED6DFC5972F -:10E31000EA8BBD09F61BF317DF6E6B527C14246089 -:10E320005CF219BFC919203BC7DF6683BC78E89946 -:10E33000916729BEFEE27E73D8C23A6AB6D2E694ED -:10E34000CCB83FF8F2FEBC0EE7F3A93B0A91C73404 -:10E350002F88AC845F5CB0514A2ECF7BDB885FBED8 -:10E36000831B972A25DF2D4F4D85EEC75773F53850 -:10E370007675C0160C28DF1D8FFEA3839CEFCC8E14 -:10E38000D377AF677E29717E6F5B42AD6EDEB72DAE -:10E3900053C78F733C7F3FE35895B1CFAA8792E76D -:10E3A000DF529129F6D3668914220EC6F82FAC8865 -:10E3B000E15AA4107835765D3DD213E0C8CB8AE0EF -:10E3C00088EFA0F2A1966EA8343BAE4F5F4A20A81A -:10E3D000958C7F0FB98B8C7B605EEF55E87EE5DB1B -:10E3E0006FF3D8984F4B6A241D7953AB23928E7CE0 -:10E3F00068E4A8463B8DEBCB8AF19F19DFAF494615 -:10E40000B83F64F6D8C6DB8F8F433C6F1D7EB32ABE -:10E410003EA9D0FDA669204DF623676411ECB6E94C -:10E42000B9E47538A733C11F470676657B13E28FC1 -:10E43000CF903BAA7C287E13FDFAA37CD8814FA500 -:10E44000CD0AABF622AFB1650A4D293A1DB0B1E550 -:10E45000FBBEB4A7C27E2E5E6D153F1E5122827395 -:10E46000B927AE0A3E8C982382738ECAFF11FC181E -:10E4700099105909DCCAADB4AF96F1C991952E1E19 -:10E48000FFB2C2A0A791E40385273257034FEAB534 -:10E49000D1B711376997D9093F89E97B9DA127A297 -:10E4A000C7863B78FC0F41B30BF1614EA562E40BCC -:10E4B00096F8F9B5B83F8D90EBC041F86793DDDD74 -:10E4C0002BA3C1FDAF201FBC33DBDDE5BA5E6F328D -:10E4D00087E5CACAFC6A2DEE293BDDFB8F15CCDF30 -:10E4E0005F1CC907CEB1B54B1C6A7BDDBA13FB4775 -:10E4F000CDA37B805F171CDE272B589FAD96A1AD67 -:10E50000A52CD267E6C829A4F84B606F8223BABD58 -:10E510008D14EFB2089F1E562AEB6797710F944B2C -:10E52000B403F6A1E8F7FCE6C0ABEF006F468666E1 -:10E53000094E8FF5A70B034FA603373EE0F81E9850 -:10E5400013EFFF60F55E0BFA97BFB8C312E1F69EBA -:10E55000CDC9E7BB7CEDF60CF80B3D9ED00F7BECF4 -:10E5600049A6C7EA0576194EF28380E8FD9CC729C3 -:10E57000F2B7540EB5410FDFD2CB98D612E8136331 -:10E58000E831F3A941CF1FCE7948F8B64E0B0F43BF -:10E590006F2307CC047CEFE4B826747F5A10EF1A7F -:10E5A000F500C7AD2C3D6E215EB4A40FADC4BD8C8B -:10E5B000F45B9D98BFE9C8A7F9383FDB633ECEDB2B -:10E5C00072E47036C1CE8DF704C7C76C8CB7F41FE8 -:10E5D000C9C6BB24D6DFAA860A211747B812E0476E -:10E5E000ACDFAF850B217F8B325482F128E496F9A2 -:10E5F0004C6BA049CED1AAE87E4F4734C1F9B1F7A0 -:10E60000F651856EAF8C0F25C807371DBD5412B16A -:10E61000C7F1A0D9C09513E82FD6FDDFB9C8C0094E -:10E620005EDA0CBF1F0727BC31DCA3F516C87DAE30 -:10E6300042973BB65EF8CA3B2320E36DAF5D2A9953 -:10E64000598C75C63C4AC0A359717C010EE40A0E70 -:10E650006C3267F3B97CCF2BEE4E5ED2DCB8B1964C -:10E66000A7D33AD3FDB5D06B1305E45D3756AEB1F1 -:10E6700076F470857EBF3E557F8FFBF628C14E969F -:10E68000EB22637DEE7CC19B30F0675DF5C65AF8E6 -:10E69000DF7D597E4BE2BBF987F8AFED49A6D7ADD8 -:10E6A000DF589B338E9FFB1EDA7E6A125DCFAFD997 -:10E6B000BBA336DB757D7F4CEE8BB6989C95E64907 -:10E6C00089FA58BEB17612B7EB52FEAFFAD0CF7DC1 -:10E6D000F188358CB8CBFAB5E0FCB7FD71BD2509E2 -:10E6E000B77F805F33056B9D33BE5BFEB16DAB12B0 -:10E6F0001E56804FEC5FBDE267EC3709FB6DAA1830 -:10E7000053A7685A3D1D793779574F4FAC538C6DDD -:10E710001928A7A8B788BD49CB7EB8D23D8E3E62E6 -:10E72000F36FAED4649F4D861D4FA96F79E6151E19 -:10E730007FB9CC5356C97E55AEA992BF8FDDA7A62F -:10E7400052CF0F86B21DBF803D4507CD4EF849B967 -:10E75000A6EB334FBDFC2EFC312FDBE1EA647E35A6 -:10E760005569FABC633627EA40D1635FE57BE0FF79 -:10E770005BECCBA5CE62B2D3641E3F953B57F03D18 -:10E78000B6CFC7C63E69A57ABED35E64FEFE3A53D5 -:10E79000B1E3DB3A93E41BC569C1D91287BF90F896 -:10E7A000161D5CE8D45CC0F7A01DFED6FEF57F67A1 -:10E7B000230E8F0CFE67BA0BB875EDD374D8CFB6A5 -:10E7C000818FD3810F27066639D09E1D7239D01FE5 -:10E7D000ADFBB816F3BA8C365E67308B9CB136F65B -:10E7E0007E8ED51312DED1CDD06BAF73DB2F4B6194 -:10E7F000EFA9DD8263FC8ECE44FC88D7195C39E337 -:10E80000D56512EB0C05B3F53A035AD4190ACC7A44 -:10E810009D0134EA0C685167403FEA0CA051670043 -:10E820008D3A0368D419D0A2CE80FE2BA86BB1BC60 -:10E83000514EDE50DFAAD1EC82FF0FF46A41E4F5BD -:10E840000F1CD3747A8712C47D7FC6FB230E46AF9C -:10E85000E875B028C75379E71F34CBFB201ADA5E7E -:10E860003713F7D6AFB97155171137D914DBCDA3CC -:10E8700027511F6AEF53DC1B5DE85F2E726C1B5C37 -:10E88000F87E23FA7BCD6ED585FBBA9A8DFA976F09 -:10E89000B057EA58D539C72C72CFFB15CAE1FDEF46 -:10E8A000B0EAEF64BFC6BD2CF7B045953CDA6F1DEA -:10E8B00092F74BCB8B8A734D421EDA7ECBE78213E5 -:10E8C0009DB6F49D90D71FB239D724C5578FE47DEC -:10E8D0007EFC74C18D3C43454CAFD5A790DF5E7B79 -:10E8E000013821F948427EB4D6D9FC33E467A45DEF -:10E8F00033E1FC7E7EE84E64F9D63D6DFE2892B091 -:10E900007F733099F60DF66DCD23C899DC8F4A03DD -:10E91000E2B23F94DC1FAA74647D92C63FE6D13C0C -:10E92000E45B75FFB4E6403FEF77B9DB2AF9CA61D3 -:10E930008FF77025FBF149B347EA2F278FD9E4BD44 -:10E94000757EFB9CA4FA4B8D3655EA1F1BCC8AC4FE -:10E95000F12BE5DE63B0CBAABA7BA5EE5295EB10A6 -:10E960007F8ED9E1D1F28637C077C35C97D4BF6A76 -:10E97000ACF40BE1C77E2FF73C68167FABE95482FD -:10E980002AD3ABC96D817FAD62758A3D99ED8F2920 -:10E99000EC0FAB78AFC604BBDAB05D91BC420A1095 -:10E9A000ACE795863E570DFEEB570AFBCBBD563DB7 -:10E9B0000FCE5355E19FD7C5718BE7DF475E0BFC48 -:10E9C000661DC755B41C675F8F70BF376D6ABE9EEA -:10E9D000E7BB72C07FF51933014F6A727E5EE8951E -:10E9E000785FEDFC84EF5B09DFA57D73D3F7E1A8C9 -:10E9F000893E49C86B4F9A75FC617DCA7BEB14EC6C -:10EA000055EA3E5E69CF743449BBA28CC4FF0B3417 -:10EA10003D6F2FE0BB72664ADDA20FEB6BDAED6E45 -:10EA2000E83F860BBB8DFCBE40E596E7ED4ED55B1F -:10EA30000BD329DC3F8D5BCA147E61E77CD4715C0B -:10EA4000C23F4F3DBBC0057D7C6977431F3539C749 -:10EA5000E6E1DD31CBE0FF7259C355DC97279D021B -:10EA6000D89F8F43DDACDF5A1C48415D3DE4D15057 -:10EA7000273FA638F1AEBF1E4FB76F71C2CF0A1441 -:10EA800027EAB7B5A9DD35D9CCBF76E60C37F09CBF -:10EA9000F155EA6123DCEA76706B5053F4B5A66C4D -:10EAA000D4F30DFF29F7A6544D8AF7D71B7E141D0A -:10EAB000FC221DF1F547D46D77837F806CEE5E8379 -:10EAC0003FECA0FEA66952BF8DD9D1E5FD393B616F -:10EAD0004753ABF4758D8DEF99914F0CDDE6CDC1A9 -:10EAE000FE2BD77CBE255BCE397EBD8C713703B83B -:10EAF0003BB65E16C3F13D46FD1D786B32EABA2681 -:10EB0000A3AE6B32EABA26A3AE6B32EABA26A3AE44 -:10EB10006B32EABA26A3AE6B32EABA26A913AE97D5 -:10EB2000F6DD8E87A41DEA08C87842BCB8B9EAC7EA -:10EB3000D55D17558D5377A5145786C45DF67BBDFB -:10EB4000DE3DA6CECAFEAE26F87BD5E0847B1E4312 -:10EB50005ED26371B338546BF1163C60177CF0548D -:10EB60008D5B6F8DE9CF2EF5D9CB649B8F7BA82C65 -:10EB70009A655251C734EE2356EF84DFE09CF01BB8 -:10EB8000B4F01BD3ECB8DFFCD6C2AE5DAAE7090136 -:10EB9000C9136C72BF5B3732AE307D2F399370E58D -:10EBA000B331B8C20F9A159063EDA095BA743F23A4 -:10EBB000F84F25377F9C3F0ECE84749C99961ADAC5 -:10EBC000877DA6B5A5BA9117B3BF8B9D9DDCA6889E -:10EBD000BFAFA106D9771CBC49479E7CEFC4D17357 -:10EBE000BFE1F9F7FE835DF29DAD93D72EFAFFE00A -:10EBF0004D4D95AE8F5F77847DE75996EA54B643C5 -:10EC00008E57D5162A92BAB89A2AFE50A33DAE580E -:10EC100080A377D33CDC77B5B5E139C899C3FE2E24 -:10EC2000EFDF2CA3BE6B1A6ADECBF4D9EC3C37BE07 -:10EC3000AB4DCD3D44050B804775C5B0ABB3D4ADEE -:10EC400060DD6319DEBF83BFDC5ECCA756E3FE96B2 -:10EC50005397B6B34BEE63CE42DCFB32ABAB1FF542 -:10EC6000862D6F9E907AC2B20CD742D41BB6BC7967 -:10EC70005AA7735CFD8A1BE5B213ABAB7F82F866C3 -:10EC8000EB3E9F1067FDA1094974FBC0E4EEF30958 -:10EC900071AE053FF89D4E3F534CB8AF5643945C60 -:10ECA000D5BB1DF2F9EBFE4B7FCFD3A8C4C9A7AAF1 -:10ECB000745C9C7482C2B0E7D1C50EF9FE973371C3 -:10ECC000FD3CD4DBA8D8B510F338AFFD35ECF8E245 -:10ECD000AD9EA7C127CF38770EF1793558C7900D73 -:10ECE000ED19E3BBE429D5DB88B6363D60927E356D -:10ECF000588AF66D35F420FAD92F76814FED93F3CB -:10ED00006E2C623ACF1A9AB7DE8E78E9D98DFE73EF -:10ED1000659E5EEC37B6EEDF699C8FE5D98779C3D7 -:10ED200085AAE4F9C337EA6DCC2EC2553A0E1D37D9 -:10ED3000FCA8AC93E4FBE758FB395EA51A78F9FD13 -:10ED400072B3BC47204F4C7EEA5E5D0A7958DEA361 -:10ED500086BCAF619CEC99528FF96E7B0DC87EC763 -:10ED60000D3B657C6C39AFE3A3B485A6E004E40DEC -:10ED7000531E0D4E80BC53768CDA5CDCBE1018B589 -:10ED8000217F78E16F476DE87FC14375E3E1BF56AE -:10ED9000AD09DFC2B251593F9DF71A9277C2E8041C -:10EDA000E46F854D6F59026CB7739EE67D93F2B7A1 -:10EDB000228963D30D5B9AFEA84AB087E9CF90E41D -:10EDC000AB549D25E3BE14DDFF7D8F3EA8C28E6E41 -:10EDD00008B2DC09F637E769D3E54812DFB0AC6B5F -:10EDE000317083F3B5A4713F3347BE3CC5C023E403 -:10EDF0008F8D8C37FEA6B7BE42BEC879DC187E8CDC -:10EE00004D311C26C45DEFEB1117FC2079DEDABB17 -:10EE10001ED98AF76D53E3768BBC8FD7F46D45DB33 -:10EE2000DAFA9E258724BF4C9ACFF965127D9D9C06 -:10EE300063E4687BF0F3AD39E3ECCB76702DD10E53 -:10EE40004E9A4337E0BD7AD29FEA0E481C09DD0F87 -:10EE50007CD9D96A7723AEECFA55A5D8D7B7F5A9EE -:10EE6000328FA9FA47D951A7CC0F545211FCE6872B -:10EE7000DA11E0E1EC243C0C48DD72894370AEDD30 -:10EE80007807B6AD714A3E12F3EB3653E8C3AD983E -:10EE900097E590EF110CB745A62C7C6F9AE2EE4AED -:10EEA000C82BCE2E9915049DDD190A83EFE8CF15E6 -:10EEB00037EAC8D5693AAED6A80DAD7B79FC2D35B9 -:10EEC0002CB8F15BE007F36FB7AC977645D94CB13E -:10EED000DB5C0A29FAFF67702DC47B3DF63DAD6708 -:10EEE0005BB0EF20DEFB4AF099B5A88FFE955DE49C -:10EEF0008906D58099CFD3338104B77BEE2C94B8A3 -:10EF000013A586C6FB91FF2C4F953A6ACF04D71301 -:10EF1000F86EDAD37CA3E4F587FEA4C7FBD1A5295C -:10EF20006EE4713DF35C1B71AE9E475D32FE9AA2AA -:10EF3000F30B3CA1EBA767A97ECE9EE64C799FC55B -:10EF4000EEA167876732BEBF5932BCE5D5A803186A -:10EF5000DF1F7B66703FB74F290D77DE073E737565 -:10EF6000795794B9E4DE4EDE79E3137B747D86F144 -:10EF70001DAC7D8923E9FDFEBFFE80CBB3202200BE -:10EF80000000000000000000040835000000000040 -:00000001FF -- cgit v0.10.2 From 2691d51d7243560aa0870dadbf5c6b98f647f751 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:22:08 +0000 Subject: bnx2x: Supporting Device Control Channel In multi-function mode, the FW can receive special management control commands to set the Min/Max BW and the the function link state Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 16ccba8..5864ae2 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -128,6 +128,11 @@ #define SHMEM_RD(bp, field) REG_RD(bp, SHMEM_ADDR(bp, field)) #define SHMEM_WR(bp, field, val) REG_WR(bp, SHMEM_ADDR(bp, field), val) +#define SHMEM2_ADDR(bp, field) (bp->common.shmem2_base + \ + offsetof(struct shmem2_region, field)) +#define SHMEM2_RD(bp, field) REG_RD(bp, SHMEM2_ADDR(bp, field)) +#define SHMEM2_WR(bp, field, val) REG_WR(bp, SHMEM2_ADDR(bp, field), val) + #define EMAC_RD(bp, reg) REG_RD(bp, emac_base + reg) #define EMAC_WR(bp, reg, val) REG_WR(bp, emac_base + reg, val) @@ -535,6 +540,7 @@ struct bnx2x_common { #define NVRAM_PAGE_SIZE 256 u32 shmem_base; + u32 shmem2_base; u32 hw_config; diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h index da62cc5..8e2261f 100644 --- a/drivers/net/bnx2x_hsi.h +++ b/drivers/net/bnx2x_hsi.h @@ -658,6 +658,8 @@ struct drv_func_mb { #define DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS 0x20010000 #define DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP 0x20020000 #define DRV_MSG_CODE_UNLOAD_DONE 0x21000000 +#define DRV_MSG_CODE_DCC_OK 0x30000000 +#define DRV_MSG_CODE_DCC_FAILURE 0x31000000 #define DRV_MSG_CODE_DIAG_ENTER_REQ 0x50000000 #define DRV_MSG_CODE_DIAG_EXIT_REQ 0x60000000 #define DRV_MSG_CODE_VALIDATE_KEY 0x70000000 @@ -692,6 +694,7 @@ struct drv_func_mb { #define FW_MSG_CODE_DRV_UNLOAD_PORT 0x20110000 #define FW_MSG_CODE_DRV_UNLOAD_FUNCTION 0x20120000 #define FW_MSG_CODE_DRV_UNLOAD_DONE 0x21100000 +#define FW_MSG_CODE_DCC_DONE 0x30100000 #define FW_MSG_CODE_DIAG_ENTER_DONE 0x50100000 #define FW_MSG_CODE_DIAG_REFUSE 0x50200000 #define FW_MSG_CODE_DIAG_EXIT_DONE 0x60100000 @@ -742,6 +745,14 @@ struct drv_func_mb { u32 drv_status; #define DRV_STATUS_PMF 0x00000001 +#define DRV_STATUS_DCC_EVENT_MASK 0x0000ff00 +#define DRV_STATUS_DCC_DISABLE_ENABLE_PF 0x00000100 +#define DRV_STATUS_DCC_BANDWIDTH_ALLOCATION 0x00000200 +#define DRV_STATUS_DCC_CHANGE_MAC_ADDRESS 0x00000400 +#define DRV_STATUS_DCC_RESERVED1 0x00000800 +#define DRV_STATUS_DCC_SET_PROTOCOL 0x00001000 +#define DRV_STATUS_DCC_SET_PRIORITY 0x00002000 + u32 virt_mac_upper; #define VIRT_MAC_SIGN_MASK 0xffff0000 #define VIRT_MAC_SIGNATURE 0x564d0000 @@ -778,10 +789,9 @@ struct shared_mf_cfg { struct port_mf_cfg { u32 dynamic_cfg; /* device control channel */ -#define PORT_MF_CFG_OUTER_VLAN_TAG_MASK 0x0000ffff -#define PORT_MF_CFG_OUTER_VLAN_TAG_SHIFT 0 -#define PORT_MF_CFG_DYNAMIC_CFG_ENABLED 0x00010000 -#define PORT_MF_CFG_DYNAMIC_CFG_DEFAULT 0x00000000 +#define PORT_MF_CFG_E1HOV_TAG_MASK 0x0000ffff +#define PORT_MF_CFG_E1HOV_TAG_SHIFT 0 +#define PORT_MF_CFG_E1HOV_TAG_DEFAULT PORT_MF_CFG_E1HOV_TAG_MASK u32 reserved[3]; @@ -885,6 +895,22 @@ struct shmem_region { /* SharedMem Offset (size) */ }; /* 0x6dc */ +struct shmem2_region { + + u32 size; + + u32 dcc_support; +#define SHMEM_DCC_SUPPORT_NONE 0x00000000 +#define SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV 0x00000001 +#define SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV 0x00000004 +#define SHMEM_DCC_SUPPORT_CHANGE_MAC_ADDRESS_TLV 0x00000008 +#define SHMEM_DCC_SUPPORT_SET_PROTOCOL_TLV 0x00000040 +#define SHMEM_DCC_SUPPORT_SET_PRIORITY_TLV 0x00000080 +#define SHMEM_DCC_SUPPORT_DEFAULT SHMEM_DCC_SUPPORT_NONE + +}; + + struct emac_stats { u32 rx_stat_ifhcinoctets; u32 rx_stat_ifhcinbadoctets; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 762f37a..8abce3c 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -2104,6 +2104,12 @@ static void bnx2x_calc_fc_adv(struct bnx2x *bp) static void bnx2x_link_report(struct bnx2x *bp) { + if (bp->state == BNX2X_STATE_DISABLED) { + netif_carrier_off(bp->dev); + printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name); + return; + } + if (bp->link_vars.link_up) { if (bp->state == BNX2X_STATE_OPEN) netif_carrier_on(bp->dev); @@ -2240,6 +2246,46 @@ static void bnx2x_init_port_minmax(struct bnx2x *bp) bp->cmng.fair_vars.fairness_timeout = fair_periodic_timeout_usec / 4; } +/* Calculates the sum of vn_min_rates. + It's needed for further normalizing of the min_rates. + Returns: + sum of vn_min_rates. + or + 0 - if all the min_rates are 0. + In the later case fainess algorithm should be deactivated. + If not all min_rates are zero then those that are zeroes will be set to 1. + */ +static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp) +{ + int all_zero = 1; + int port = BP_PORT(bp); + int vn; + + bp->vn_weight_sum = 0; + for (vn = VN_0; vn < E1HVN_MAX; vn++) { + int func = 2*vn + port; + u32 vn_cfg = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); + u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >> + FUNC_MF_CFG_MIN_BW_SHIFT) * 100; + + /* Skip hidden vns */ + if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE) + continue; + + /* If min rate is zero - set it to 1 */ + if (!vn_min_rate) + vn_min_rate = DEF_MIN_RATE; + else + all_zero = 0; + + bp->vn_weight_sum += vn_min_rate; + } + + /* ... only if all min rates are zeros - disable fairness */ + if (all_zero) + bp->vn_weight_sum = 0; +} + static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func) { struct rate_shaping_vars_per_vn m_rs_vn; @@ -2383,6 +2429,8 @@ static void bnx2x_link_attn(struct bnx2x *bp) static void bnx2x__link_status_update(struct bnx2x *bp) { + int func = BP_FUNC(bp); + if (bp->state != BNX2X_STATE_OPEN) return; @@ -2393,6 +2441,9 @@ static void bnx2x__link_status_update(struct bnx2x *bp) else bnx2x_stats_handle(bp, STATS_EVENT_STOP); + bp->mf_config = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); + bnx2x_calc_vn_weight_sum(bp); + /* indicate link status */ bnx2x_link_report(bp); } @@ -2421,6 +2472,152 @@ static void bnx2x_pmf_update(struct bnx2x *bp) * General service functions */ +/* send the MCP a request, block until there is a reply */ +u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) +{ + int func = BP_FUNC(bp); + u32 seq = ++bp->fw_seq; + u32 rc = 0; + u32 cnt = 1; + u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10; + + SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq)); + DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq)); + + do { + /* let the FW do it's magic ... */ + msleep(delay); + + rc = SHMEM_RD(bp, func_mb[func].fw_mb_header); + + /* Give the FW up to 2 second (200*10ms) */ + } while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 200)); + + DP(BNX2X_MSG_MCP, "[after %d ms] read (%x) seq is (%x) from FW MB\n", + cnt*delay, rc, seq); + + /* is this a reply to our command? */ + if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK)) + rc &= FW_MSG_CODE_MASK; + else { + /* FW BUG! */ + BNX2X_ERR("FW failed to respond!\n"); + bnx2x_fw_dump(bp); + rc = 0; + } + + return rc; +} + +static void bnx2x_set_storm_rx_mode(struct bnx2x *bp); +static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set); +static void bnx2x_set_rx_mode(struct net_device *dev); + +static void bnx2x_e1h_disable(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int i; + + bp->rx_mode = BNX2X_RX_MODE_NONE; + bnx2x_set_storm_rx_mode(bp); + + netif_tx_disable(bp->dev); + bp->dev->trans_start = jiffies; /* prevent tx timeout */ + + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0); + + bnx2x_set_mac_addr_e1h(bp, 0); + + for (i = 0; i < MC_HASH_SIZE; i++) + REG_WR(bp, MC_HASH_OFFSET(bp, i), 0); + + netif_carrier_off(bp->dev); +} + +static void bnx2x_e1h_enable(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1); + + bnx2x_set_mac_addr_e1h(bp, 1); + + /* Tx queue should be only reenabled */ + netif_tx_wake_all_queues(bp->dev); + + /* Initialize the receive filter. */ + bnx2x_set_rx_mode(bp->dev); +} + +static void bnx2x_update_min_max(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int vn, i; + + /* Init rate shaping and fairness contexts */ + bnx2x_init_port_minmax(bp); + + bnx2x_calc_vn_weight_sum(bp); + + for (vn = VN_0; vn < E1HVN_MAX; vn++) + bnx2x_init_vn_minmax(bp, 2*vn + port); + + if (bp->port.pmf) { + int func; + + /* Set the attention towards other drivers on the same port */ + for (vn = VN_0; vn < E1HVN_MAX; vn++) { + if (vn == BP_E1HVN(bp)) + continue; + + func = ((vn << 1) | port); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 + + (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1); + } + + /* Store it to internal memory */ + for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++) + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i*4, + ((u32 *)(&bp->cmng))[i]); + } +} + +static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event) +{ + int func = BP_FUNC(bp); + + DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event); + bp->mf_config = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); + + if (dcc_event & DRV_STATUS_DCC_DISABLE_ENABLE_PF) { + + if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) { + DP(NETIF_MSG_IFDOWN, "mf_cfg function disabled\n"); + bp->state = BNX2X_STATE_DISABLED; + + bnx2x_e1h_disable(bp); + } else { + DP(NETIF_MSG_IFUP, "mf_cfg function enabled\n"); + bp->state = BNX2X_STATE_OPEN; + + bnx2x_e1h_enable(bp); + } + dcc_event &= ~DRV_STATUS_DCC_DISABLE_ENABLE_PF; + } + if (dcc_event & DRV_STATUS_DCC_BANDWIDTH_ALLOCATION) { + + bnx2x_update_min_max(bp); + dcc_event &= ~DRV_STATUS_DCC_BANDWIDTH_ALLOCATION; + } + + /* Report results to MCP */ + if (dcc_event) + bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE); + else + bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK); +} + /* the slow path queue is odd since completions arrive on the fastpath ring */ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, u32 data_hi, u32 data_lo, int common) @@ -2806,9 +3003,12 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn) int func = BP_FUNC(bp); REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0); + val = SHMEM_RD(bp, func_mb[func].drv_status); + if (val & DRV_STATUS_DCC_EVENT_MASK) + bnx2x_dcc_event(bp, + (val & DRV_STATUS_DCC_EVENT_MASK)); bnx2x__link_status_update(bp); - if (SHMEM_RD(bp, func_mb[func].drv_status) & - DRV_STATUS_PMF) + if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF)) bnx2x_pmf_update(bp); } else if (attn & BNX2X_MC_ASSERT_BITS) { @@ -4968,47 +5168,6 @@ static void bnx2x_init_internal_port(struct bnx2x *bp) REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), BNX2X_BTR); } -/* Calculates the sum of vn_min_rates. - It's needed for further normalizing of the min_rates. - Returns: - sum of vn_min_rates. - or - 0 - if all the min_rates are 0. - In the later case fainess algorithm should be deactivated. - If not all min_rates are zero then those that are zeroes will be set to 1. - */ -static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp) -{ - int all_zero = 1; - int port = BP_PORT(bp); - int vn; - - bp->vn_weight_sum = 0; - for (vn = VN_0; vn < E1HVN_MAX; vn++) { - int func = 2*vn + port; - u32 vn_cfg = - SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); - u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >> - FUNC_MF_CFG_MIN_BW_SHIFT) * 100; - - /* Skip hidden vns */ - if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE) - continue; - - /* If min rate is zero - set it to 1 */ - if (!vn_min_rate) - vn_min_rate = DEF_MIN_RATE; - else - all_zero = 0; - - bp->vn_weight_sum += vn_min_rate; - } - - /* ... only if all min rates are zeros - disable fairness */ - if (all_zero) - bp->vn_weight_sum = 0; -} - static void bnx2x_init_internal_func(struct bnx2x *bp) { struct tstorm_eth_function_common_config tstorm_config = {0}; @@ -6272,44 +6431,6 @@ init_hw_err: return rc; } -/* send the MCP a request, block until there is a reply */ -u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) -{ - int func = BP_FUNC(bp); - u32 seq = ++bp->fw_seq; - u32 rc = 0; - u32 cnt = 1; - u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10; - - SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq)); - DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq)); - - do { - /* let the FW do it's magic ... */ - msleep(delay); - - rc = SHMEM_RD(bp, func_mb[func].fw_mb_header); - - /* Give the FW up to 2 second (200*10ms) */ - } while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 200)); - - DP(BNX2X_MSG_MCP, "[after %d ms] read (%x) seq is (%x) from FW MB\n", - cnt*delay, rc, seq); - - /* is this a reply to our command? */ - if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK)) { - rc &= FW_MSG_CODE_MASK; - - } else { - /* FW BUG! */ - BNX2X_ERR("FW failed to respond!\n"); - bnx2x_fw_dump(bp); - rc = 0; - } - - return rc; -} - static void bnx2x_free_mem(struct bnx2x *bp) { @@ -6996,7 +7117,6 @@ static int bnx2x_set_int_mode(struct bnx2x *bp) return rc; } -static void bnx2x_set_rx_mode(struct net_device *dev); /* must be called with rtnl_lock */ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) @@ -7103,6 +7223,12 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* Setup NIC internals and enable interrupts */ bnx2x_nic_init(bp, load_code); + if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) && + (bp->common.shmem2_base)) + SHMEM2_WR(bp, dcc_support, + (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV | + SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV)); + /* Send LOAD_DONE command to MCP */ if (!BP_NOMCP(bp)) { load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE); @@ -7735,8 +7861,10 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) bp->common.flash_size, bp->common.flash_size); bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); + bp->common.shmem2_base = REG_RD(bp, MISC_REG_GENERIC_CR_0); bp->link_params.shmem_base = bp->common.shmem_base; - BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base); + BNX2X_DEV_INFO("shmem offset 0x%x shmem2 offset 0x%x\n", + bp->common.shmem_base, bp->common.shmem2_base); if (!bp->common.shmem_base || (bp->common.shmem_base < 0xA0000) || @@ -8290,22 +8418,33 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) bp->mf_config = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); - val = (SHMEM_RD(bp, mf_cfg.func_mf_config[func].e1hov_tag) & + val = (SHMEM_RD(bp, mf_cfg.func_mf_config[FUNC_0].e1hov_tag) & FUNC_MF_CFG_E1HOV_TAG_MASK); - if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { - - bp->e1hov = val; + if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) bp->e1hmf = 1; - BNX2X_DEV_INFO("MF mode E1HOV for func %d is %d " - "(0x%04x)\n", - func, bp->e1hov, bp->e1hov); - } else { - BNX2X_DEV_INFO("single function mode\n"); - if (BP_E1HVN(bp)) { + BNX2X_DEV_INFO("%s function mode\n", + IS_E1HMF(bp) ? "multi" : "single"); + + if (IS_E1HMF(bp)) { + val = (SHMEM_RD(bp, mf_cfg.func_mf_config[func]. + e1hov_tag) & + FUNC_MF_CFG_E1HOV_TAG_MASK); + if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { + bp->e1hov = val; + BNX2X_DEV_INFO("E1HOV for func %d is %d " + "(0x%04x)\n", + func, bp->e1hov, bp->e1hov); + } else { BNX2X_ERR("!!! No valid E1HOV for func %d," " aborting\n", func); rc = -EPERM; } + } else { + if (BP_E1HVN(bp)) { + BNX2X_ERR("!!! VN %d in single function mode," + " aborting\n", BP_E1HVN(bp)); + rc = -EPERM; + } } } -- cgit v0.10.2 From 0c593270432035b7b9ba27ee7dd4f32f6feea2e0 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:22:13 +0000 Subject: bnx2x: Advertize flow control normally in MF mode Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 8abce3c..a695e7f 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -2149,9 +2149,7 @@ static u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode) /* Initialize link parameters structure variables */ /* It is recommended to turn off RX FC for jumbo frames for better performance */ - if (IS_E1HMF(bp)) - bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH; - else if (bp->dev->mtu > 5000) + if (bp->dev->mtu > 5000) bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_TX; else bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH; -- cgit v0.10.2 From 2f9044603c8b9ead9eb4d88e360093b44d362b58 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:22:16 +0000 Subject: bnx2x: BCM8481 LED4 instead of LASI The BCM8481 does not generate LASI interrupt for 10M, 100M and 1G link, so we are using LED4 output as the interrupt input to the 57711. This requires some adaptation in the link interrupt routines Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 1f17334..9e1f19a 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -37,6 +37,10 @@ /* Shortcut definitions */ /***********************************************************/ +#define NIG_LATCH_BC_ENABLE_MI_INT 0 + +#define NIG_STATUS_EMAC0_MI_INT \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT #define NIG_STATUS_XGXS0_LINK10G \ NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G #define NIG_STATUS_XGXS0_LINK_STATUS \ @@ -1589,8 +1593,9 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, static u8 bnx2x_link_settings_status(struct link_params *params, - struct link_vars *vars, - u32 gp_status) + struct link_vars *vars, + u32 gp_status, + u8 ext_phy_link_up) { struct bnx2x *bp = params->bp; u16 new_line_speed; @@ -1696,6 +1701,16 @@ static u8 bnx2x_link_settings_status(struct link_params *params, Comes to deals with possible FIFO glitch due to clk change when speed is decreased without link down indicator */ if (new_line_speed != vars->line_speed) { + if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) != + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT && + ext_phy_link_up) { + DP(NETIF_MSG_LINK, "Internal link speed %d is" + " different than the external" + " link speed %d\n", new_line_speed, + vars->line_speed); + vars->phy_link_up = 0; + return 0; + } REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); msleep(1); @@ -1709,9 +1724,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params, (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) || (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) || - (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481))) { + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) { vars->autoneg = AUTO_NEG_ENABLED; if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) { @@ -3182,6 +3195,130 @@ static void bnx2x_set_preemphasis(struct link_params *params) } } + +static void bnx2x_8481_set_led4(struct link_params *params, + u32 ext_phy_type, u8 ext_phy_addr) +{ + struct bnx2x *bp = params->bp; + + /* PHYC_CTL_LED_CTL */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, 0xa482); + + /* Unmask LED4 for 10G link */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_SIGNAL_MASK, (1<<6)); + /* 'Interrupt Mask' */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + 0xFFFB, 0xFFFD); +} +static void bnx2x_8481_set_legacy_led_mode(struct link_params *params, + u32 ext_phy_type, u8 ext_phy_addr) +{ + struct bnx2x *bp = params->bp; + + /* LED1 (10G Link): Disable LED1 when 10/100/1000 link */ + /* LED2 (1G/100/10 Link): Enable LED2 when 10/100/1000 link) */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_SHADOW, + (1<<15) | (0xd << 10) | (0xc<<4) | 0xe); +} + +static void bnx2x_8481_set_10G_led_mode(struct link_params *params, + u32 ext_phy_type, u8 ext_phy_addr) +{ + struct bnx2x *bp = params->bp; + u16 val1; + + /* LED1 (10G Link) */ + /* Enable continuse based on source 7(10G-link) */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + &val1); + /* Set bit 2 to 0, and bits [1:0] to 10 */ + val1 &= ~((1<<0) | (1<<2)); /* Clear bits 0,2*/ + val1 |= (1<<1); /* Set bit 1 */ + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + val1); + + /* Unmask LED1 for 10G link */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + &val1); + /* Set bit 2 to 0, and bits [1:0] to 10 */ + val1 |= (1<<7); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + val1); + + /* LED2 (1G/100/10G Link) */ + /* Mask LED2 for 10G link */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED2_MASK, + 0); + + /* LED3 (10G/1G/100/10G Activity) */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + &val1); + /* Enable blink based on source 4(Activity) */ + val1 &= ~((1<<7) | (1<<8)); /* Clear bits 7,8 */ + val1 |= (1<<6); /* Set only bit 6 */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + val1); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + &val1); + val1 |= (1<<4); /* Unmask LED3 for 10G link */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + val1); +} + + static void bnx2x_init_internal_phy(struct link_params *params, struct link_vars *vars) { @@ -3947,16 +4084,109 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) break; } case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: - DP(NETIF_MSG_LINK, - "Setting the BCM8481 LASI control\n"); + /* This phy uses the NIG latch mechanism since link + indication arrives through its LED4 and not via + its LASI signal, so we get steady signal + instead of clear on read */ + bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4, + 1 << NIG_LATCH_BC_ENABLE_MI_INT); + + bnx2x_8481_set_led4(params, ext_phy_type, ext_phy_addr); + if (params->req_line_speed == SPEED_AUTO_NEG) { + + u16 autoneg_val, an_1000_val, an_10_100_val; + /* set 1000 speed advertisement */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_1000T_CTRL, + &an_1000_val); - bnx2x_cl45_write(bp, params->port, - ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_LASI_CTRL, 0x1); + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) { + an_1000_val |= (1<<8); + if (params->req_duplex == DUPLEX_FULL) + an_1000_val |= (1<<9); + DP(NETIF_MSG_LINK, "Advertising 1G\n"); + } else + an_1000_val &= ~((1<<8) | (1<<9)); - /* Restart autoneg */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_1000T_CTRL, + an_1000_val); + + /* set 100 speed advertisement */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_AN_ADV, + &an_10_100_val); + + if (params->speed_cap_mask & + (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL | + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) { + an_10_100_val |= (1<<7); + if (params->req_duplex == DUPLEX_FULL) + an_10_100_val |= (1<<8); + DP(NETIF_MSG_LINK, + "Advertising 100M\n"); + } else + an_10_100_val &= ~((1<<7) | (1<<8)); + + /* set 10 speed advertisement */ + if (params->speed_cap_mask & + (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL | + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) { + an_10_100_val |= (1<<5); + if (params->req_duplex == DUPLEX_FULL) + an_10_100_val |= (1<<6); + DP(NETIF_MSG_LINK, "Advertising 10M\n"); + } + else + an_10_100_val &= ~((1<<5) | (1<<6)); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_AN_ADV, + an_10_100_val); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + &autoneg_val); + + /* Disable forced speed */ + autoneg_val &= ~(1<<6|1<<13); + + /* Enable autoneg and restart autoneg + for legacy speeds */ + autoneg_val |= (1<<9|1<<12); + + if (params->req_duplex == DUPLEX_FULL) + autoneg_val |= (1<<8); + else + autoneg_val &= ~(1<<8); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + autoneg_val); + + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) { + DP(NETIF_MSG_LINK, "Advertising 10G\n"); + /* Restart autoneg for 10G*/ bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, @@ -3968,6 +4198,76 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ext_phy_addr, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val); + } + } else { + /* Force speed */ + u16 autoneg_ctrl, pma_ctrl; + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + &autoneg_ctrl); + + /* Disable autoneg */ + autoneg_ctrl &= ~(1<<12); + + /* Set 1000 force */ + switch (params->req_line_speed) { + case SPEED_10000: + DP(NETIF_MSG_LINK, + "Unable to set 10G force !\n"); + break; + case SPEED_1000: + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + &pma_ctrl); + autoneg_ctrl &= ~(1<<13); + autoneg_ctrl |= (1<<6); + pma_ctrl &= ~(1<<13); + pma_ctrl |= (1<<6); + DP(NETIF_MSG_LINK, + "Setting 1000M force\n"); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + pma_ctrl); + break; + case SPEED_100: + autoneg_ctrl |= (1<<13); + autoneg_ctrl &= ~(1<<6); + DP(NETIF_MSG_LINK, + "Setting 100M force\n"); + break; + case SPEED_10: + autoneg_ctrl &= ~(1<<13); + autoneg_ctrl &= ~(1<<6); + DP(NETIF_MSG_LINK, + "Setting 10M force\n"); + break; + } + + /* Duplex mode */ + if (params->req_duplex == DUPLEX_FULL) { + autoneg_ctrl |= (1<<8); + DP(NETIF_MSG_LINK, + "Setting full duplex\n"); + } else + autoneg_ctrl &= ~(1<<8); + + /* Update autoneg ctrl and pma ctrl */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + autoneg_ctrl); + } bnx2x_save_bcm_spirom_ver(bp, params->port, ext_phy_type, @@ -4104,7 +4404,8 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params) static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, - struct link_vars *vars) + struct link_vars *vars, + u8 is_mi_int) { struct bnx2x *bp = params->bp; u32 ext_phy_type; @@ -4647,48 +4948,77 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, } break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: - /* Clear LASI interrupt */ - bnx2x_cl45_read(bp, params->port, - ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_LASI_STATUS, &val1); - DP(NETIF_MSG_LINK, "8481 LASI status reg = 0x%x\n", - val1); - /* Check 10G-BaseT link status */ - /* Check Global PMD signal ok */ + /* Check PMD signal ok */ bnx2x_cl45_read(bp, params->port, ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, - &rx_sd); - /* Check PCS block lock */ + ext_phy_addr, + MDIO_AN_DEVAD, + 0xFFFA, + &val1); bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, - MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, - &pcs_status); - DP(NETIF_MSG_LINK, "8481 1.a = 0x%x, 1.20 = 0x%x\n", - rx_sd, pcs_status); - if (rx_sd & pcs_status & 0x1) { + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_PMD_SIGNAL, + &val2); + DP(NETIF_MSG_LINK, "PMD_SIGNAL 1.a811 = 0x%x\n", val2); + + /* Check link 10G */ + if (val2 & (1<<11)) { vars->line_speed = SPEED_10000; ext_phy_link_up = 1; - } else { - - /* Check 1000-BaseT link status */ - bnx2x_cl45_read(bp, params->port, ext_phy_type, - ext_phy_addr, - MDIO_AN_DEVAD, 0xFFE1, - &val1); + bnx2x_8481_set_10G_led_mode(params, + ext_phy_type, + ext_phy_addr); + } else { /* Check Legacy speed link */ + u16 legacy_status, legacy_speed; + + /* Enable expansion register 0x42 + (Operation mode status) */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, + 0xf42); - bnx2x_cl45_read(bp, params->port, ext_phy_type, - ext_phy_addr, - MDIO_AN_DEVAD, 0xFFE1, - &val2); - DP(NETIF_MSG_LINK, "8481 7.FFE1 =" - "0x%x-->0x%x\n", val1, val2); - if (val2 & (1<<2)) { - vars->line_speed = SPEED_1000; - ext_phy_link_up = 1; + /* Get legacy speed operation status */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_EXPANSION_REG_RD_RW, + &legacy_status); + + DP(NETIF_MSG_LINK, "Legacy speed status" + " = 0x%x\n", legacy_status); + ext_phy_link_up = ((legacy_status & (1<<11)) + == (1<<11)); + if (ext_phy_link_up) { + legacy_speed = (legacy_status & (3<<9)); + if (legacy_speed == (0<<9)) + vars->line_speed = SPEED_10; + else if (legacy_speed == (1<<9)) + vars->line_speed = + SPEED_100; + else if (legacy_speed == (2<<9)) + vars->line_speed = + SPEED_1000; + else /* Should not happen */ + vars->line_speed = 0; + + if (legacy_status & (1<<8)) + vars->duplex = DUPLEX_FULL; + else + vars->duplex = DUPLEX_HALF; + + DP(NETIF_MSG_LINK, "Link is up " + "in %dMbps, is_duplex_full" + "= %d\n", + vars->line_speed, + (vars->duplex == DUPLEX_FULL)); + bnx2x_8481_set_legacy_led_mode(params, + ext_phy_type, + ext_phy_addr); } } @@ -4775,12 +5105,47 @@ static void bnx2x_link_int_enable(struct link_params *params) REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)); } - +static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port, + u8 is_mi_int) +{ + u32 latch_status = 0, is_mi_int_status; + /* Disable the MI INT ( external phy int ) + * by writing 1 to the status register. Link down indication + * is high-active-signal, so in this case we need to write the + * status to clear the XOR + */ + /* Read Latched signals */ + latch_status = REG_RD(bp, + NIG_REG_LATCH_STATUS_0 + port*8); + is_mi_int_status = REG_RD(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + port*4); + DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x," + "latch_status = 0x%x\n", + is_mi_int, is_mi_int_status, latch_status); + /* Handle only those with latched-signal=up.*/ + if (latch_status & 1) { + /* For all latched-signal=up,Write original_signal to status */ + if (is_mi_int) + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + + port*4, + NIG_STATUS_EMAC0_MI_INT); + else + bnx2x_bits_dis(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + + port*4, + NIG_STATUS_EMAC0_MI_INT); + /* For all latched-signal=up : Re-Arm Latch signals */ + REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8, + (latch_status & 0xfffe) | (latch_status & 1)); + } +} /* * link management */ static void bnx2x_link_int_ack(struct link_params *params, - struct link_vars *vars, u8 is_10g) + struct link_vars *vars, u8 is_10g, + u8 is_mi_int) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -4791,6 +5156,10 @@ static void bnx2x_link_int_ack(struct link_params *params, (NIG_STATUS_XGXS0_LINK10G | NIG_STATUS_XGXS0_LINK_STATUS | NIG_STATUS_SERDES0_LINK_STATUS)); + if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) + == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) { + bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int); + } if (vars->phy_link_up) { if (is_10g) { /* Disable the 10G link interrupt @@ -4810,7 +5179,8 @@ static void bnx2x_link_int_ack(struct link_params *params, PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); - DP(NETIF_MSG_LINK, "1G XGXS phy link up\n"); + DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n", + vars->line_speed); bnx2x_bits_en(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, ((1 << ser_lane) << @@ -5270,7 +5640,7 @@ u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars) &gp_status); /* link is up only if both local phy and external phy are up */ if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) && - bnx2x_ext_phy_is_link_up(params, vars)) + bnx2x_ext_phy_is_link_up(params, vars, 1)) return 0; return -ESRCH; @@ -5758,16 +6128,19 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) u8 link_10g; u8 ext_phy_link_up, rc = 0; u32 ext_phy_type; + u8 is_mi_int = 0; DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n", - port, - (vars->phy_flags & PHY_XGXS_FLAG), - REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); + port, (vars->phy_flags & PHY_XGXS_FLAG), + REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); + is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + + port*0x18) > 0); DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n", - REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), - REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), - REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c)); + REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), + is_mi_int, + REG_RD(bp, + NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c)); DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n", REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), @@ -5779,7 +6152,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Check external link change only for non-direct */ - ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars); + ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars, is_mi_int); /* Read gp_status */ CL45_RD_OVER_CL22(bp, port, params->phy_addr, @@ -5787,7 +6160,8 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) MDIO_GP_STATUS_TOP_AN_STATUS1, &gp_status); - rc = bnx2x_link_settings_status(params, vars, gp_status); + rc = bnx2x_link_settings_status(params, vars, gp_status, + ext_phy_link_up); if (rc != 0) return rc; @@ -5799,7 +6173,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) (vars->line_speed == SPEED_15000) || (vars->line_speed == SPEED_16000)); - bnx2x_link_int_ack(params, vars, link_10g); + bnx2x_link_int_ack(params, vars, link_10g, is_mi_int); /* In case external phy link is up, and internal link is down ( not initialized yet probably after link initialization, it needs diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 25639e2..9a20da5 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -1681,6 +1681,24 @@ /* [RW 17] Debug only. RX_EOP_DSCR_lb_FIFO in NIG_RX_EOP. Data packet_length[13:0]; mac_error[14]; trunc_error[15]; parity[16] */ #define NIG_REG_INGRESS_EOP_LB_FIFO 0x104e4 +/* [RW 27] 0 - must be active for Everest A0; 1- for Everest B0 when latch + logic for interrupts must be used. Enable per bit of interrupt of + ~latch_status.latch_status */ +#define NIG_REG_LATCH_BC_0 0x16210 +/* [RW 27] Latch for each interrupt from Unicore.b[0] + status_emac0_misc_mi_int; b[1] status_emac0_misc_mi_complete; + b[2]status_emac0_misc_cfg_change; b[3]status_emac0_misc_link_status; + b[4]status_emac0_misc_link_change; b[5]status_emac0_misc_attn; + b[6]status_serdes0_mac_crs; b[7]status_serdes0_autoneg_complete; + b[8]status_serdes0_fiber_rxact; b[9]status_serdes0_link_status; + b[10]status_serdes0_mr_page_rx; b[11]status_serdes0_cl73_an_complete; + b[12]status_serdes0_cl73_mr_page_rx; b[13]status_serdes0_rx_sigdet; + b[14]status_xgxs0_remotemdioreq; b[15]status_xgxs0_link10g; + b[16]status_xgxs0_autoneg_complete; b[17]status_xgxs0_fiber_rxact; + b[21:18]status_xgxs0_link_status; b[22]status_xgxs0_mr_page_rx; + b[23]status_xgxs0_cl73_an_complete; b[24]status_xgxs0_cl73_mr_page_rx; + b[25]status_xgxs0_rx_sigdet; b[26]status_xgxs0_mac_crs */ +#define NIG_REG_LATCH_STATUS_0 0x18000 /* [RW 1] led 10g for port 0 */ #define NIG_REG_LED_10G_P0 0x10320 /* [RW 1] led 10g for port 1 */ @@ -1871,6 +1889,7 @@ #define NIG_REG_XGXS_LANE_SEL_P0 0x102e8 /* [RW 1] selection for port0 for NIG_MUX block : 0 = SerDes; 1 = XGXS */ #define NIG_REG_XGXS_SERDES0_MODE_SEL 0x102e0 +#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT (0x1<<0) #define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS (0x1<<9) #define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G (0x1<<15) #define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS (0xf<<18) @@ -5889,6 +5908,13 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_PMA_REG_7101_VER1 0xc026 #define MDIO_PMA_REG_7101_VER2 0xc027 +#define MDIO_PMA_REG_8481_PMD_SIGNAL 0xa811 +#define MDIO_PMA_REG_8481_LED1_MASK 0xa82c +#define MDIO_PMA_REG_8481_LED2_MASK 0xa82f +#define MDIO_PMA_REG_8481_LED3_MASK 0xa832 +#define MDIO_PMA_REG_8481_SIGNAL_MASK 0xa835 +#define MDIO_PMA_REG_8481_LINK_SIGNAL 0xa83b + #define MDIO_WIS_DEVAD 0x2 /*bcm*/ @@ -5942,6 +5968,12 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_AN_REG_8073_2_5G 0x8329 +#define MDIO_AN_REG_8481_LEGACY_MII_CTRL 0xffe0 +#define MDIO_AN_REG_8481_LEGACY_AN_ADV 0xffe4 +#define MDIO_AN_REG_8481_1000T_CTRL 0xffe9 +#define MDIO_AN_REG_8481_EXPANSION_REG_RD_RW 0xfff5 +#define MDIO_AN_REG_8481_EXPANSION_REG_ACCESS 0xfff7 +#define MDIO_AN_REG_8481_LEGACY_SHADOW 0xfffc #define IGU_FUNC_BASE 0x0400 -- cgit v0.10.2 From b1607af526fd408b244c7b32a0c256c1ef163a17 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:22:54 +0000 Subject: bnx2x: Reading the FW version of the BCM8481 PHY Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 9e1f19a..c925249 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -2046,6 +2046,111 @@ static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port, (u32)(fw_ver1<<16 | fw_ver2)); } + +static void bnx2x_save_8481_spirom_version(struct bnx2x *bp, u8 port, + u8 ext_phy_addr, u32 shmem_base) +{ + u16 val, fw_ver1, fw_ver2, cnt; + /* For the 32 bits registers in 8481, access via MDIO2ARM interface.*/ + /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA819, 0x0014); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81A, + 0xc200); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81B, + 0x0000); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81C, + 0x0300); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA817, + 0x0009); + + for (cnt = 0; cnt < 100; cnt++) { + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA818, + &val); + if (val & 1) + break; + udelay(5); + } + if (cnt == 100) { + DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(1)\n"); + bnx2x_save_spirom_version(bp, port, + shmem_base, 0); + return; + } + + + /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA819, 0x0000); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA81A, 0xc200); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA817, 0x000A); + for (cnt = 0; cnt < 100; cnt++) { + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA818, + &val); + if (val & 1) + break; + udelay(5); + } + if (cnt == 100) { + DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(2)\n"); + bnx2x_save_spirom_version(bp, port, + shmem_base, 0); + return; + } + + /* lower 16 bits of the register SPI_FW_STATUS */ + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81B, + &fw_ver1); + /* upper 16 bits of register SPI_FW_STATUS */ + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81C, + &fw_ver2); + + bnx2x_save_spirom_version(bp, port, + shmem_base, (fw_ver2<<16) | fw_ver1); +} + static void bnx2x_bcm8072_external_rom_boot(struct link_params *params) { struct bnx2x *bp = params->bp; @@ -4269,11 +4374,10 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) autoneg_ctrl); } - bnx2x_save_bcm_spirom_ver(bp, params->port, - ext_phy_type, - ext_phy_addr, - params->shmem_base); - + /* Save spirom version */ + bnx2x_save_8481_spirom_version(bp, params->port, + ext_phy_addr, + params->shmem_base); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: DP(NETIF_MSG_LINK, @@ -5320,7 +5424,11 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + status = bnx2x_format_ver(spirom_ver, version, len); + break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: + spirom_ver = ((spirom_ver & 0xF80) >> 7) << 16 | + (spirom_ver & 0x7F); status = bnx2x_format_ver(spirom_ver, version, len); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: -- cgit v0.10.2 From 97b41dad385bce97d60b8cdd56342f07f93fc5d2 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:22:59 +0000 Subject: bnx2x: get_ext_phy_fw_version returns NULL if not applicable To avoid confusion, if the PHY does not have a FW (and so, no FW version) make sure that the string is NULL. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index c925249..aee9fff 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -5393,7 +5393,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, struct bnx2x *bp; u32 ext_phy_type = 0; u32 spirom_ver = 0; - u8 status = 0 ; + u8 status; if (version == NULL || params == NULL) return -EINVAL; @@ -5403,6 +5403,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, offsetof(struct shmem_region, port_mb[params->port].ext_phy_fw_version)); + status = 0; /* reset the returned value to zero */ ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); switch (ext_phy_type) { @@ -5421,7 +5422,6 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: status = bnx2x_format_ver(spirom_ver, version, len); @@ -5432,6 +5432,8 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, status = bnx2x_format_ver(spirom_ver, version, len); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + version[0] = '\0'; break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: -- cgit v0.10.2 From bc7f0a053021491e292fc00810c4f2a8524453dd Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:01 +0000 Subject: bnx2x: BCM8727 FW load The BCM8727 is a dual port PHY. The FW must be loaded in a given order on all designs - including those which swapped the ports (calling port number zero the second port) Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index aee9fff..db4f3c0 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -6430,7 +6430,7 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) { u8 ext_phy_addr[PORT_MAX]; - s8 port; + s8 port, first_port, i; u32 swap_val, swap_override; DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n"); swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); @@ -6439,8 +6439,13 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override)); msleep(5); + if (swap_val && swap_override) + first_port = PORT_0; + else + first_port = PORT_1; + /* PART1 - Reset both phys */ - for (port = PORT_MAX - 1; port >= PORT_0; port--) { + for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) { /* Extract the ext phy address for the port */ u32 ext_phy_config = REG_RD(bp, shmem_base + offsetof(struct shmem_region, @@ -6470,7 +6475,7 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) msleep(150); /* PART2 - Download firmware to both phys */ - for (port = PORT_MAX - 1; port >= PORT_0; port--) { + for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) { u16 fw_ver1; bnx2x_bcm8727_external_rom_boot(bp, port, @@ -6482,16 +6487,13 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) MDIO_PMA_REG_ROM_VER1, &fw_ver1); if (fw_ver1 == 0 || fw_ver1 == 0x4321) { DP(NETIF_MSG_LINK, - "bnx2x_8073_common_init_phy port %x:" + "bnx2x_8727_common_init_phy port %x:" "Download failed. fw version = 0x%x\n", port, fw_ver1); return -EINVAL; } - } - - return 0; } -- cgit v0.10.2 From 239d686d494f10ecd83a89ddc4e31f9462ca4901 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:04 +0000 Subject: bnx2x: Adding XAUI CL73 autoneg support Adding CL73 support to the built in PHY in the 5771x device. Also supporting fallbacks to CL73 if the link partner does not respond. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index db4f3c0..371310d 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -1151,7 +1151,8 @@ static void bnx2x_set_parallel_detection(struct link_params *params, } static void bnx2x_set_autoneg(struct link_params *params, - struct link_vars *vars) + struct link_vars *vars, + u8 enable_cl73) { struct bnx2x *bp = params->bp; u16 reg_val; @@ -1181,7 +1182,9 @@ static void bnx2x_set_autoneg(struct link_params *params, params->phy_addr, MDIO_REG_BANK_SERDES_DIGITAL, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, ®_val); - reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN; + reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN | + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT); + reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE; if (vars->line_speed == SPEED_AUTO_NEG) reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; else @@ -1213,8 +1216,51 @@ static void bnx2x_set_autoneg(struct link_params *params, MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, reg_val); - /* CL73 Autoneg Disabled */ - reg_val = 0; + if (enable_cl73) { + /* Enable Cl73 FSM status bits */ + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_UCTRL, + MDIO_CL73_USERB0_CL73_UCTRL_USTAT1_MUXSEL); + + /* Enable BAM Station Manager*/ + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_BAM_CTRL1, + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN); + + /* Merge CL73 and CL37 aneg resolution */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_BAM_CTRL3, + ®_val); + + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) { + /* Set the CL73 AN speed */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, + ®_val); + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, + reg_val | MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4); + + } + /* CL73 Autoneg Enabled */ + reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN; + + } else /* CL73 Autoneg Disabled */ + reg_val = 0; CL45_WR_OVER_CL22(bp, params->port, params->phy_addr, @@ -1297,7 +1343,7 @@ static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params) CL45_WR_OVER_CL22(bp, params->port, params->phy_addr, MDIO_REG_BANK_OVER_1G, - MDIO_OVER_1G_UP3, 0); + MDIO_OVER_1G_UP3, 0x400); } static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) @@ -1345,28 +1391,46 @@ static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params, MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc); } -static void bnx2x_restart_autoneg(struct link_params *params) +static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73) { struct bnx2x *bp = params->bp; u16 mii_control; + DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n"); /* Enable and restart BAM/CL37 aneg */ - CL45_RD_OVER_CL22(bp, params->port, - params->phy_addr, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - &mii_control); - DP(NETIF_MSG_LINK, - "bnx2x_restart_autoneg mii_control before = 0x%x\n", - mii_control); - CL45_WR_OVER_CL22(bp, params->port, - params->phy_addr, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - (mii_control | - MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | - MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); + if (enable_cl73) { + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + &mii_control); + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + (mii_control | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN)); + } else { + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + DP(NETIF_MSG_LINK, + "bnx2x_restart_autoneg mii_control before = 0x%x\n", + mii_control); + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); + } } static void bnx2x_initialize_sgmii_process(struct link_params *params, @@ -1438,7 +1502,7 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params, } else { /* AN mode */ /* enable and restart AN */ - bnx2x_restart_autoneg(params); + bnx2x_restart_autoneg(params, 0); } } @@ -1591,7 +1655,73 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl); } - +static void bnx2x_check_fallback_to_cl37(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 rx_status, ustat_val, cl37_fsm_recieved; + DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n"); + /* Step 1: Make sure signal is detected */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_RX0, + MDIO_RX0_RX_STATUS, + &rx_status); + if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) != + (MDIO_RX0_RX_STATUS_SIGDET)) { + DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73." + "rx_status(0x80b0) = 0x%x\n", rx_status); + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN); + return; + } + /* Step 2: Check CL73 state machine */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_USTAT1, + &ustat_val); + if ((ustat_val & + (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK | + MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) != + (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK | + MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) { + DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. " + "ustat_val(0x8371) = 0x%x\n", ustat_val); + return; + } + /* Step 3: Check CL37 Message Pages received to indicate LP + supports only CL37 */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_REMOTE_PHY, + MDIO_REMOTE_PHY_MISC_RX_STATUS, + &cl37_fsm_recieved); + if ((cl37_fsm_recieved & + (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG | + MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) != + (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG | + MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) { + DP(NETIF_MSG_LINK, "No CL37 FSM were received. " + "misc_rx_status(0x8330) = 0x%x\n", + cl37_fsm_recieved); + return; + } + /* The combined cl37/cl73 fsm state information indicating that we are + connected to a device which does not support cl73, but does support + cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */ + /* Disable CL73 */ + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + 0); + /* Restart CL37 autoneg */ + bnx2x_restart_autoneg(params, 0); + DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n"); +} static u8 bnx2x_link_settings_status(struct link_params *params, struct link_vars *vars, u32 gp_status, @@ -1755,6 +1885,13 @@ static u8 bnx2x_link_settings_status(struct link_params *params, vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->autoneg = AUTO_NEG_DISABLED; vars->mac_type = MAC_TYPE_NONE; + + if ((params->req_line_speed == SPEED_AUTO_NEG) && + ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT))) { + /* Check signal is detected */ + bnx2x_check_fallback_to_cl37(params); + } } DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n", @@ -3425,7 +3562,8 @@ static void bnx2x_8481_set_10G_led_mode(struct link_params *params, static void bnx2x_init_internal_phy(struct link_params *params, - struct link_vars *vars) + struct link_vars *vars, + u8 enable_cl73) { struct bnx2x *bp = params->bp; if (!(vars->phy_flags & PHY_SGMII_FLAG)) { @@ -3440,7 +3578,7 @@ static void bnx2x_init_internal_phy(struct link_params *params, DP(NETIF_MSG_LINK, "not SGMII, no AN\n"); /* disable autoneg */ - bnx2x_set_autoneg(params, vars); + bnx2x_set_autoneg(params, vars, 0); /* program speed and duplex */ bnx2x_program_serdes(params, vars); @@ -3456,10 +3594,10 @@ static void bnx2x_init_internal_phy(struct link_params *params, vars->ieee_fc); /* enable autoneg */ - bnx2x_set_autoneg(params, vars); + bnx2x_set_autoneg(params, vars, enable_cl73); /* enable and restart AN */ - bnx2x_restart_autoneg(params); + bnx2x_restart_autoneg(params, enable_cl73); } } else { /* SGMII mode */ @@ -5815,11 +5953,10 @@ static u8 bnx2x_link_initialize(struct link_params *params, if (non_ext_phy || (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) || (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) || - (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) || (params->loopback_mode == LOOPBACK_EXT_PHY)) { if (params->req_line_speed == SPEED_AUTO_NEG) bnx2x_set_parallel_detection(params, vars->phy_flags); - bnx2x_init_internal_phy(params, vars); + bnx2x_init_internal_phy(params, vars, non_ext_phy); } if (!non_ext_phy) @@ -6296,7 +6433,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) && (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) && (ext_phy_link_up && !vars->phy_link_up)) - bnx2x_init_internal_phy(params, vars); + bnx2x_init_internal_phy(params, vars, 0); /* link is up only if both local phy and external phy are up */ vars->link_up = (ext_phy_link_up && vars->phy_link_up); diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 9a20da5..9998386 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -5596,6 +5596,9 @@ #define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KR 0x0080 #define MDIO_REG_BANK_RX0 0x80b0 +#define MDIO_RX0_RX_STATUS 0x10 +#define MDIO_RX0_RX_STATUS_SIGDET 0x8000 +#define MDIO_RX0_RX_STATUS_RX_SEQ_DONE 0x1000 #define MDIO_RX0_RX_EQ_BOOST 0x1c #define MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK 0x7 #define MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL 0x10 @@ -5789,12 +5792,22 @@ #define MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT 7 #define MDIO_OVER_1G_LP_UP3 0x1E +#define MDIO_REG_BANK_REMOTE_PHY 0x8330 +#define MDIO_REMOTE_PHY_MISC_RX_STATUS 0x10 +#define MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG 0x0010 +#define MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG 0x0600 + #define MDIO_REG_BANK_BAM_NEXT_PAGE 0x8350 #define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL 0x10 #define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE 0x0001 #define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN 0x0002 #define MDIO_REG_BANK_CL73_USERB0 0x8370 +#define MDIO_CL73_USERB0_CL73_UCTRL 0x10 +#define MDIO_CL73_USERB0_CL73_UCTRL_USTAT1_MUXSEL 0x0002 +#define MDIO_CL73_USERB0_CL73_USTAT1 0x11 +#define MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK 0x0100 +#define MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37 0x0400 #define MDIO_CL73_USERB0_CL73_BAM_CTRL1 0x12 #define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN 0x8000 #define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN 0x4000 -- cgit v0.10.2 From 01cd452846c98609dd3efbee0deea050e6706f02 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:08 +0000 Subject: bnx2x: MDC/MDIO CL45 IOCTLs As suggested by Ben Hutchings , using the MDC/MDIO IOCTL Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9948fa2..29935a9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2722,6 +2722,7 @@ config BNX2X select FW_LOADER select ZLIB_INFLATE select LIBCRC32C + select MDIO help This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards. To compile this driver as a module, choose M here: the module diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 5864ae2..903c89d 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -30,6 +30,8 @@ #define BNX2X_NEW_NAPI + +#include #include "bnx2x_reg.h" #include "bnx2x_fw_defs.h" #include "bnx2x_hsi.h" @@ -895,6 +897,7 @@ struct bnx2x { struct link_params link_params; struct link_vars link_vars; + struct mdio_if_info mdio; struct bnx2x_common common; struct bnx2x_port port; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index a695e7f..14586676 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -8331,6 +8331,7 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) u32 val, val2; u32 config; u16 i; + u32 ext_phy_type; bp->link_params.bp = bp; bp->link_params.port = port; @@ -8390,6 +8391,21 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) bnx2x_link_settings_requested(bp); + /* + * If connected directly, work with the internal PHY, otherwise, work + * with the external PHY + */ + ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) + bp->mdio.prtad = bp->link_params.phy_addr; + + else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) && + (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) + bp->mdio.prtad = + (bp->link_params.ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT; + val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper); val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff); @@ -8614,7 +8630,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) } else cmd->port = PORT_TP; - cmd->phy_address = bp->port.phy_addr; + cmd->phy_address = bp->mdio.prtad; cmd->transceiver = XCVR_INTERNAL; if (bp->link_params.req_line_speed == SPEED_AUTO_NEG) @@ -11149,54 +11165,77 @@ static int bnx2x_change_mac_addr(struct net_device *dev, void *p) } /* called with rtnl_lock */ -static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int bnx2x_mdio_read(struct net_device *netdev, int prtad, + int devad, u16 addr) { - struct mii_ioctl_data *data = if_mii(ifr); - struct bnx2x *bp = netdev_priv(dev); - int port = BP_PORT(bp); - int err; + struct bnx2x *bp = netdev_priv(netdev); + u16 value; + int rc; + u32 phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); - switch (cmd) { - case SIOCGMIIPHY: - data->phy_id = bp->port.phy_addr; + DP(NETIF_MSG_LINK, "mdio_read: prtad 0x%x, devad 0x%x, addr 0x%x\n", + prtad, devad, addr); - /* fallthrough */ + if (prtad != bp->mdio.prtad) { + DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n", + prtad, bp->mdio.prtad); + return -EINVAL; + } + + /* The HW expects different devad if CL22 is used */ + devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad; - case SIOCGMIIREG: { - u16 mii_regval; + bnx2x_acquire_phy_lock(bp); + rc = bnx2x_cl45_read(bp, BP_PORT(bp), phy_type, prtad, + devad, addr, &value); + bnx2x_release_phy_lock(bp); + DP(NETIF_MSG_LINK, "mdio_read_val 0x%x rc = 0x%x\n", value, rc); - if (!netif_running(dev)) - return -EAGAIN; + if (!rc) + rc = value; + return rc; +} - mutex_lock(&bp->port.phy_mutex); - err = bnx2x_cl45_read(bp, port, 0, bp->port.phy_addr, - DEFAULT_PHY_DEV_ADDR, - (data->reg_num & 0x1f), &mii_regval); - data->val_out = mii_regval; - mutex_unlock(&bp->port.phy_mutex); - return err; +/* called with rtnl_lock */ +static int bnx2x_mdio_write(struct net_device *netdev, int prtad, int devad, + u16 addr, u16 value) +{ + struct bnx2x *bp = netdev_priv(netdev); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); + int rc; + + DP(NETIF_MSG_LINK, "mdio_write: prtad 0x%x, devad 0x%x, addr 0x%x," + " value 0x%x\n", prtad, devad, addr, value); + + if (prtad != bp->mdio.prtad) { + DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n", + prtad, bp->mdio.prtad); + return -EINVAL; } - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + /* The HW expects different devad if CL22 is used */ + devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad; - if (!netif_running(dev)) - return -EAGAIN; + bnx2x_acquire_phy_lock(bp); + rc = bnx2x_cl45_write(bp, BP_PORT(bp), ext_phy_type, prtad, + devad, addr, value); + bnx2x_release_phy_lock(bp); + return rc; +} - mutex_lock(&bp->port.phy_mutex); - err = bnx2x_cl45_write(bp, port, 0, bp->port.phy_addr, - DEFAULT_PHY_DEV_ADDR, - (data->reg_num & 0x1f), data->val_in); - mutex_unlock(&bp->port.phy_mutex); - return err; +/* called with rtnl_lock */ +static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct bnx2x *bp = netdev_priv(dev); + struct mii_ioctl_data *mdio = if_mii(ifr); - default: - /* do nothing */ - break; - } + DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n", + mdio->phy_id, mdio->reg_num, mdio->val_in); - return -EOPNOTSUPP; + if (!netif_running(dev)) + return -EAGAIN; + + return mdio_mii_ioctl(&bp->mdio, mdio, cmd); } /* called with rtnl_lock */ @@ -11420,6 +11459,14 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, dev->vlan_features |= NETIF_F_TSO6; #endif + /* get_port_hwinfo() will set prtad and mmds properly */ + bp->mdio.prtad = MDIO_PRTAD_NONE; + bp->mdio.mmds = 0; + bp->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + bp->mdio.dev = dev; + bp->mdio.mdio_read = bnx2x_mdio_read; + bp->mdio.mdio_write = bnx2x_mdio_write; + return 0; err_out_unmap: -- cgit v0.10.2 From f57a60256d02daba1316c98da472f02cd98a58d3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:11 +0000 Subject: bnx2x: Supporting PHY FW upgrade There are 3 operations that the driver needs to support to allow applications to access the PHY FW (on top of the MDC/MDIO access). Since those are essentially nvram access commands, adding them to the ethtool -E interface. Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 371310d..98e3e8f 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -1996,7 +1996,7 @@ static u8 bnx2x_emac_program(struct link_params *params, /*****************************************************************************/ /* External Phy section */ /*****************************************************************************/ -static void bnx2x_hw_reset(struct bnx2x *bp, u8 port) +void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port) { bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, MISC_REGISTERS_GPIO_OUTPUT_LOW, port); @@ -2035,7 +2035,7 @@ static void bnx2x_ext_phy_reset(struct link_params *params, params->port); /* HW reset */ - bnx2x_hw_reset(bp, params->port); + bnx2x_ext_phy_hw_reset(bp, params->port); bnx2x_cl45_write(bp, params->port, ext_phy_type, @@ -2106,8 +2106,7 @@ static void bnx2x_ext_phy_reset(struct link_params *params, params->port); /* HW reset */ - bnx2x_hw_reset(bp, params->port); - + bnx2x_ext_phy_hw_reset(bp, params->port); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: @@ -2118,7 +2117,7 @@ static void bnx2x_ext_phy_reset(struct link_params *params, params->port); /* HW reset */ - bnx2x_hw_reset(bp, params->port); + bnx2x_ext_phy_hw_reset(bp, params->port); bnx2x_cl45_write(bp, params->port, ext_phy_type, @@ -2146,7 +2145,7 @@ static void bnx2x_ext_phy_reset(struct link_params *params, case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: DP(NETIF_MSG_LINK, "SerDes 5482\n"); - bnx2x_hw_reset(bp, params->port); + bnx2x_ext_phy_hw_reset(bp, params->port); break; default: @@ -6573,7 +6572,7 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); - bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override)); + bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override)); msleep(5); if (swap_val && swap_override) @@ -6647,7 +6646,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT))); REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val); - bnx2x_hw_reset(bp, 1); + bnx2x_ext_phy_hw_reset(bp, 1); msleep(5); for (port = 0; port < PORT_MAX; port++) { /* Extract the ext phy address for the port */ @@ -6714,9 +6713,7 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base) return rc; } - - -static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr) +void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr) { u16 val, cnt; @@ -7032,7 +7029,7 @@ static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port, for (cnt = 0; cnt < 100; cnt++) msleep(5); - bnx2x_hw_reset(bp, port); + bnx2x_ext_phy_hw_reset(bp, port); for (cnt = 0; cnt < 100; cnt++) msleep(5); diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index d25ef45..9805d21 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -187,6 +187,10 @@ u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars); /* One-time initialization for external phy after power up */ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base); +/* Reset the external PHY using GPIO */ +void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port); + +void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr); u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, u8 byte_cnt, u8 *o_buf); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 14586676..7853977 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -9353,7 +9353,8 @@ static int bnx2x_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *eebuf) { struct bnx2x *bp = netdev_priv(dev); - int rc; + int port = BP_PORT(bp); + int rc = 0; if (!netif_running(dev)) return -EAGAIN; @@ -9365,27 +9366,62 @@ static int bnx2x_set_eeprom(struct net_device *dev, /* parameters already validated in ethtool_set_eeprom */ - /* If the magic number is PHY (0x00504859) upgrade the PHY FW */ - if (eeprom->magic == 0x00504859) - if (bp->port.pmf) { + /* PHY eeprom can be accessed only by the PMF */ + if ((eeprom->magic >= 0x50485900) && (eeprom->magic <= 0x504859FF) && + !bp->port.pmf) + return -EINVAL; + + if (eeprom->magic == 0x50485950) { + /* 'PHYP' (0x50485950): prepare phy for FW upgrade */ + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + bnx2x_acquire_phy_lock(bp); + rc |= bnx2x_link_reset(&bp->link_params, + &bp->link_vars, 0); + if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, + MISC_REGISTERS_GPIO_HIGH, port); + bnx2x_release_phy_lock(bp); + bnx2x_link_report(bp); + + } else if (eeprom->magic == 0x50485952) { + /* 'PHYR' (0x50485952): re-init link after FW upgrade */ + if ((bp->state == BNX2X_STATE_OPEN) || + (bp->state == BNX2X_STATE_DISABLED)) { bnx2x_acquire_phy_lock(bp); - rc = bnx2x_flash_download(bp, BP_PORT(bp), - bp->link_params.ext_phy_config, - (bp->state != BNX2X_STATE_CLOSED), - eebuf, eeprom->len); - if ((bp->state == BNX2X_STATE_OPEN) || - (bp->state == BNX2X_STATE_DISABLED)) { - rc |= bnx2x_link_reset(&bp->link_params, - &bp->link_vars, 1); - rc |= bnx2x_phy_init(&bp->link_params, - &bp->link_vars); - } + rc |= bnx2x_link_reset(&bp->link_params, + &bp->link_vars, 1); + + rc |= bnx2x_phy_init(&bp->link_params, + &bp->link_vars); bnx2x_release_phy_lock(bp); + bnx2x_calc_fc_adv(bp); + } + } else if (eeprom->magic == 0x53985943) { + /* 'PHYC' (0x53985943): PHY FW upgrade completed */ + if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) { + u8 ext_phy_addr = + (bp->link_params.ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT; + + /* DSP Remove Download Mode */ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, + MISC_REGISTERS_GPIO_LOW, port); - } else /* Only the PMF can access the PHY */ - return -EINVAL; - else + bnx2x_acquire_phy_lock(bp); + + bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr); + + /* wait 0.5 sec to allow it to run */ + msleep(500); + bnx2x_ext_phy_hw_reset(bp, port); + msleep(500); + bnx2x_release_phy_lock(bp); + } + } else rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); return rc; -- cgit v0.10.2 From cdea52128f6099e8f84459823c45790a78264022 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:14 +0000 Subject: bnx2x: Removing old PHY FW upgrade code This code should not have resided in the driver. Now that we have a new interface, this logic can reside in the application that whishes to upgrade the PHY FW Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 98e3e8f..dc3b69e 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -5471,59 +5471,6 @@ static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len) return 0; } - -static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr, - u32 ext_phy_type) -{ - u32 cnt = 0; - u16 ctrl = 0; - /* Enable EMAC0 in to enable MDIO */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, - (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); - msleep(5); - - /* take ext phy out of reset */ - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_HIGH, - port); - - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_HIGH, - port); - - /* wait for 5ms */ - msleep(5); - - for (cnt = 0; cnt < 1000; cnt++) { - msleep(1); - bnx2x_cl45_read(bp, port, - ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_CTRL, - &ctrl); - if (!(ctrl & (1<<15))) { - DP(NETIF_MSG_LINK, "Reset completed\n\n"); - break; - } - } -} - -static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port) -{ - /* put sf to reset */ - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_LOW, - port); - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_LOW, - port); -} - u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, u8 *version, u16 len) { @@ -6743,377 +6690,3 @@ void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr) break; } } -#define RESERVED_SIZE 256 -/* max application is 160K bytes - data at end of RAM */ -#define MAX_APP_SIZE (160*1024 - RESERVED_SIZE) - -/* Header is 14 bytes */ -#define HEADER_SIZE 14 -#define DATA_OFFSET HEADER_SIZE - -#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \ - bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \ - ext_phy_addr, \ - MDIO_PCS_DEVAD, \ - MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1) - -/* Programs an image to DSP's flash via the SPI port*/ -static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port, - u8 ext_phy_addr, - char data[], u32 size) -{ - const u16 num_trans = size/4; /* 4 bytes can be sent at a time */ - /* Doesn't include last trans!*/ - const u16 last_trans_size = size%4; /* Num bytes on last trans */ - u16 trans_cnt, byte_cnt; - u32 data_index; - u16 tmp; - u16 code_started = 0; - u16 image_revision1, image_revision2; - u16 cnt; - - DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size); - /* Going to flash*/ - if ((size-HEADER_SIZE) > MAX_APP_SIZE) { - /* This very often will be the case, because the image is built - with 160Kbytes size whereas the total image size must actually - be 160Kbytes-RESERVED_SIZE */ - DP(NETIF_MSG_LINK, "Warning, file size was %d bytes " - "truncated to %d bytes\n", size, MAX_APP_SIZE); - size = MAX_APP_SIZE+HEADER_SIZE; - } - DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]); - DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]); - /* Put the DSP in download mode by setting FLASH_CFG[2] to 1 - and issuing a reset.*/ - - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_HIGH, port); - - bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr); - - /* wait 0.5 sec */ - for (cnt = 0; cnt < 100; cnt++) - msleep(5); - - /* Make sure we can access the DSP - And it's in the correct mode (waiting for download) */ - - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_DSP_ACCESS, &tmp); - - if (tmp != 0x000A) { - DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. " - "Expected 0x000A, read 0x%04X\n", tmp); - DP(NETIF_MSG_LINK, "Download failed\n"); - return -EINVAL; - } - - /* Mux the SPI interface away from the internal processor */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_MUX, 1); - - /* Reset the SPI port */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0); - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_CTRL_ADDR, - (1<>16)); - /* Bits 15-8 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - (data_index>>8)); - - /* Bits 7-0 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - ((u16)data_index)); - - byte_cnt = 0; - while (byte_cnt < 4 && data_index < size) { - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - data[data_index++]); - byte_cnt++; - } - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - byte_cnt+4); - - SPI_START_TRANSFER(bp, port, ext_phy_addr); - msleep(5); /* Wait 5 ms minimum between transs */ - - /* Let the user know something's going on.*/ - /* a pacifier ever 4K */ - if ((data_index % 1023) == 0) - DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size); - } - - DP(NETIF_MSG_LINK, "\n"); - /* Transfer the last block if there is data remaining */ - if (last_trans_size) { - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD); - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - 1); - - SPI_START_TRANSFER(bp, port, ext_phy_addr); - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD); - - /* Bits 23-16 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - (data_index>>16)); - /* Bits 15-8 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - (data_index>>8)); - - /* Bits 7-0 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - ((u16)data_index)); - - byte_cnt = 0; - while (byte_cnt < last_trans_size && data_index < size) { - /* Bits 7-0 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - data[data_index++]); - byte_cnt++; - } - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - byte_cnt+4); - - SPI_START_TRANSFER(bp, port, ext_phy_addr); - } - - /* DSP Remove Download Mode */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_LOW, port); - - bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr); - - /* wait 0.5 sec to allow it to run */ - for (cnt = 0; cnt < 100; cnt++) - msleep(5); - - bnx2x_ext_phy_hw_reset(bp, port); - - for (cnt = 0; cnt < 100; cnt++) - msleep(5); - - /* Check that the code is started. In case the download - checksum failed, the code won't be started. */ - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_DSP_ACCESS, - &tmp); - - code_started = (tmp & (1<<4)); - if (!code_started) { - DP(NETIF_MSG_LINK, "Download failed. Please check file.\n"); - return -EINVAL; - } - - /* Verify that the file revision is now equal to the image - revision within the DSP */ - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_7101_VER1, - &image_revision1); - - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_7101_VER2, - &image_revision2); - - if (data[0x14e] != (image_revision2&0xFF) || - data[0x14f] != ((image_revision2&0xFF00)>>8) || - data[0x150] != (image_revision1&0xFF) || - data[0x151] != ((image_revision1&0xFF00)>>8)) { - DP(NETIF_MSG_LINK, "Download failed.\n"); - return -EINVAL; - } - DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size); - return 0; -} - -u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config, - u8 driver_loaded, char data[], u32 size) -{ - u8 rc = 0; - u32 ext_phy_type; - u8 ext_phy_addr; - ext_phy_addr = ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - - ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); - - switch (ext_phy_type) { - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: - DP(NETIF_MSG_LINK, - "Flash download not supported for this ext phy\n"); - rc = -EINVAL; - break; - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - /* Take ext phy out of reset */ - if (!driver_loaded) - bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type); - rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr, - data, size); - if (!driver_loaded) - bnx2x_turn_off_sf(bp, port); - break; - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN: - default: - DP(NETIF_MSG_LINK, "Invalid ext phy type\n"); - rc = -EINVAL; - break; - } - return rc; -} - diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index 9805d21..6d26d6c 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -174,8 +174,6 @@ u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed, u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port, u32 led_idx, u32 value); -u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config, - u8 driver_loaded, char data[], u32 size); /* bnx2x_handle_module_detect_int should be called upon module detection interrupt */ void bnx2x_handle_module_detect_int(struct link_params *params); -- cgit v0.10.2 From 6fe49bb978de3de0ba7ff9d6b2d55a15518db2a3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:17 +0000 Subject: bnx2x: Reporting host statistics to management FW This is required for NCSI statistics Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 903c89d..1d0b727 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -777,6 +777,7 @@ struct bnx2x_slowpath { struct nig_stats nig_stats; struct host_port_stats port_stats; struct host_func_stats func_stats; + struct host_func_stats func_stats_base; u32 wb_comp; u32 wb_data[4]; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 7853977..88f30d2 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -3365,53 +3365,6 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp) } } -static void bnx2x_stats_init(struct bnx2x *bp) -{ - int port = BP_PORT(bp); - int i; - - bp->stats_pending = 0; - bp->executer_idx = 0; - bp->stats_counter = 0; - - /* port stats */ - if (!BP_NOMCP(bp)) - bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx); - else - bp->port.port_stx = 0; - DP(BNX2X_MSG_STATS, "port_stx 0x%x\n", bp->port.port_stx); - - memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats)); - bp->port.old_nig_stats.brb_discard = - REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38); - bp->port.old_nig_stats.brb_truncate = - REG_RD(bp, NIG_REG_STAT0_BRB_TRUNCATE + port*0x38); - REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50, - &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2); - REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50, - &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2); - - /* function stats */ - for_each_queue(bp, i) { - struct bnx2x_fastpath *fp = &bp->fp[i]; - - memset(&fp->old_tclient, 0, - sizeof(struct tstorm_per_client_stats)); - memset(&fp->old_uclient, 0, - sizeof(struct ustorm_per_client_stats)); - memset(&fp->old_xclient, 0, - sizeof(struct xstorm_per_client_stats)); - memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats)); - } - - memset(&bp->dev->stats, 0, sizeof(struct net_device_stats)); - memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats)); - - bp->stats_state = STATS_STATE_DISABLED; - if (IS_E1HMF(bp) && bp->port.pmf && bp->port.port_stx) - bnx2x_stats_handle(bp, STATS_EVENT_PMF); -} - static void bnx2x_hw_stats_post(struct bnx2x *bp) { struct dmae_command *dmae = &bp->stats_dmae; @@ -3972,7 +3925,8 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) struct bnx2x_eth_stats *estats = &bp->eth_stats; int i; - memset(&(fstats->total_bytes_received_hi), 0, + memcpy(&(fstats->total_bytes_received_hi), + &(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi), sizeof(struct host_func_stats) - 2*sizeof(u32)); estats->error_bytes_received_hi = 0; estats->error_bytes_received_lo = 0; @@ -4451,6 +4405,173 @@ static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event) state, event, bp->stats_state); } +static void bnx2x_port_stats_base_init(struct bnx2x *bp) +{ + struct dmae_command *dmae; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!bp->port.pmf || !bp->port.port_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats)); + dmae->dst_addr_lo = bp->port.port_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_port_stats) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); +} + +static void bnx2x_func_stats_base_init(struct bnx2x *bp) +{ + int vn, vn_max = IS_E1HMF(bp) ? E1HVN_MAX : E1VN_MAX; + int port = BP_PORT(bp); + int func; + u32 func_stx; + + /* sanity */ + if (!bp->port.pmf || !bp->func_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + /* save our func_stx */ + func_stx = bp->func_stx; + + for (vn = VN_0; vn < vn_max; vn++) { + func = 2*vn + port; + + bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param); + bnx2x_func_stats_init(bp); + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); + } + + /* restore our func_stx */ + bp->func_stx = func_stx; +} + +static void bnx2x_func_stats_base_update(struct bnx2x *bp) +{ + struct dmae_command *dmae = &bp->stats_dmae; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!bp->func_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + memset(dmae, 0, sizeof(struct dmae_command)); + + dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae->src_addr_lo = bp->func_stx >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats_base)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats_base)); + dmae->len = sizeof(struct host_func_stats) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); +} + +static void bnx2x_stats_init(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int i; + + bp->stats_pending = 0; + bp->executer_idx = 0; + bp->stats_counter = 0; + + /* port and func stats for management */ + if (!BP_NOMCP(bp)) { + bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx); + bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param); + + } else { + bp->port.port_stx = 0; + bp->func_stx = 0; + } + DP(BNX2X_MSG_STATS, "port_stx 0x%x func_stx 0x%x\n", + bp->port.port_stx, bp->func_stx); + + /* port stats */ + memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats)); + bp->port.old_nig_stats.brb_discard = + REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38); + bp->port.old_nig_stats.brb_truncate = + REG_RD(bp, NIG_REG_STAT0_BRB_TRUNCATE + port*0x38); + REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50, + &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2); + REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50, + &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2); + + /* function stats */ + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + memset(&fp->old_tclient, 0, + sizeof(struct tstorm_per_client_stats)); + memset(&fp->old_uclient, 0, + sizeof(struct ustorm_per_client_stats)); + memset(&fp->old_xclient, 0, + sizeof(struct xstorm_per_client_stats)); + memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats)); + } + + memset(&bp->dev->stats, 0, sizeof(struct net_device_stats)); + memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats)); + + bp->stats_state = STATS_STATE_DISABLED; + + if (bp->port.pmf) { + if (bp->port.port_stx) + bnx2x_port_stats_base_init(bp); + + if (bp->func_stx) + bnx2x_func_stats_base_init(bp); + + } else if (bp->func_stx) + bnx2x_func_stats_base_update(bp); +} + static void bnx2x_timer(unsigned long data) { struct bnx2x *bp = (struct bnx2x *) data; @@ -4933,6 +5054,10 @@ static void bnx2x_init_tx_ring(struct bnx2x *bp) fp->tx_cons_sb = BNX2X_TX_SB_INDEX; fp->tx_pkt = 0; } + + /* clean tx statistics */ + for_each_rx_queue(bp, i) + bnx2x_fp(bp, i, tx_pkt) = 0; } static void bnx2x_init_sp_ring(struct bnx2x *bp) @@ -6412,11 +6537,8 @@ static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) bp->fw_drv_pulse_wr_seq = (SHMEM_RD(bp, func_mb[func].drv_pulse_mb) & DRV_PULSE_SEQ_MASK); - bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param); - DP(BNX2X_MSG_MCP, "drv_pulse 0x%x func_stx 0x%x\n", - bp->fw_drv_pulse_wr_seq, bp->func_stx); - } else - bp->func_stx = 0; + DP(BNX2X_MSG_MCP, "drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq); + } /* this needs to be done before gunzip end */ bnx2x_zero_def_sb(bp); -- cgit v0.10.2 From 619e7a66b515f5f6b1cbe6f378f6a4ca3a65ac52 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:20 +0000 Subject: bnx2x: Prefetch the page containing the BD descriptor Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 88f30d2..bdc2e71 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -1498,6 +1498,13 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) bd_prod = RX_BD(bd_prod); bd_cons = RX_BD(bd_cons); + /* Prefetch the page containing the BD descriptor + at producer's index. It will be needed when new skb is + allocated */ + prefetch((void *)(PAGE_ALIGN((unsigned long) + (&fp->rx_desc_ring[bd_prod])) - + PAGE_SIZE + 1)); + cqe = &fp->rx_comp_ring[comp_ring_cons]; cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; -- cgit v0.10.2 From a119a069349b6ad32807ff1b09e417cf23514020 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:23 +0000 Subject: bnx2x: Adding Likely directive Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index bdc2e71..039fdd4 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -1613,7 +1613,8 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) skb = new_skb; - } else if (bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0) { + } else + if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) { pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping), bp->rx_buf_size, -- cgit v0.10.2 From a18f5128828cd1af8091602f5233b00422e74c9a Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:26 +0000 Subject: bnx2x: Configurable pause scheme When a given ring is running out of space, the FW can send pause towards the network. When working with multi-queues, when one queue is getting out of space it can block all other queues. The preferred scheme is to send pause frames only when running out of the shared internal chip buffers and if a given queue cannot place a packet on the host, it will drop it. Since some users might want to work in drop-less mode, allowing changing the behavior as a module parameter. Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 1d0b727..004f4a8 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -967,6 +967,8 @@ struct bnx2x { dma_addr_t qm_mapping; #endif + int dropless_fc; + int dmae_ready; /* used to synchronize dmae accesses */ struct mutex dmae_mutex; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 039fdd4..0ebbc77 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -101,6 +101,10 @@ static int int_mode; module_param(int_mode, int, 0); MODULE_PARM_DESC(int_mode, " Force interrupt mode (1 INT#x; 2 MSI)"); +static int dropless_fc; +module_param(dropless_fc, int, 0); +MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring"); + static int poll; module_param(poll, int, 0); MODULE_PARM_DESC(poll, " Use polling (for debug)"); @@ -2369,7 +2373,7 @@ static void bnx2x_link_attn(struct bnx2x *bp) if (bp->link_vars.link_up) { /* dropless flow control */ - if (CHIP_IS_E1H(bp)) { + if (CHIP_IS_E1H(bp) && bp->dropless_fc) { int port = BP_PORT(bp); u32 pause_enabled = 0; @@ -6359,9 +6363,6 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4, (IS_E1HMF(bp) ? 0x1 : 0x2)); - /* support pause requests from USDM, TSDM and BRB */ - REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0 + port*4, 0x7); - { REG_WR(bp, NIG_REG_LLFC_ENABLE_0 + port*4, 0); REG_WR(bp, NIG_REG_LLFC_OUT_EN_0 + port*4, 0); @@ -8677,6 +8678,11 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) bp->dev->features |= NETIF_F_LRO; } + if (CHIP_IS_E1(bp)) + bp->dropless_fc = 0; + else + bp->dropless_fc = dropless_fc; + bp->mrrs = mrrs; bp->tx_ring_size = MAX_TX_AVAIL; -- cgit v0.10.2 From df4770de03d2eec3f66b0ac4d2248d471a1ccc0b Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:28 +0000 Subject: bnx2x: Calling pci_set_drvdata earlier In case of error, bnx2x_init_dev calls pci_set_drvdata(pdev, NULL) Signed-off-by: Yitchak Gertner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 0ebbc77..8e77e93 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11885,14 +11885,14 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, bp = netdev_priv(dev); bp->msglevel = debug; + pci_set_drvdata(pdev, dev); + rc = bnx2x_init_dev(pdev, dev); if (rc < 0) { free_netdev(dev); return rc; } - pci_set_drvdata(pdev, dev); - rc = bnx2x_init_bp(bp); if (rc) goto init_one_exit; -- cgit v0.10.2 From e3553b29c6f395c6692afccc2ed5eff9c3d1daef Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:31 +0000 Subject: bnx2x: Stop loading if error condition detected Signed-off-by: Benjamin Li Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 004f4a8..633acca 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -89,6 +89,7 @@ } while (0) #else #define bnx2x_panic() do { \ + bp->panic = 1; \ BNX2X_ERR("driver assert\n"); \ bnx2x_panic_dump(bp); \ } while (0) diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 8e77e93..c289670 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -7109,6 +7109,9 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx, } msleep(1); + + if (bp->panic) + return -EIO; } /* timeout! */ @@ -7373,7 +7376,12 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) rc = bnx2x_setup_leading(bp); if (rc) { BNX2X_ERR("Setup leading failed!\n"); +#ifndef BNX2X_STOP_ON_ERROR goto load_error3; +#else + bp->panic = 1; + return -EBUSY; +#endif } if (CHIP_IS_E1H(bp)) -- cgit v0.10.2 From 37f9ce6231cafb2973e09f7f72ad62bc6348d1b3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:34 +0000 Subject: bnx2x: Combine get_pcie_width and get_pcie_speed The functions bnx2x_get_pcie_width() and bnx2x_get_pcie_speed() were combined into bnx2x_get_pcie_width_speed() so that there is only 1 PCI read to PCICFG_OFFSET + PCICFG_LINK_CONTROL rather then 2 reads. Signed-off-by: Benjamin Li Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index c289670..807c156 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11671,31 +11671,26 @@ err_out: return rc; } -static int __devinit bnx2x_get_pcie_width(struct bnx2x *bp) +static void __devinit bnx2x_get_pcie_width_speed(struct bnx2x *bp, + int *width, int *speed) { u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL); - val = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT; - return val; -} - -/* return value of 1=2.5GHz 2=5GHz */ -static int __devinit bnx2x_get_pcie_speed(struct bnx2x *bp) -{ - u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL); + *width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT; - val = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT; - return val; + /* return value of 1=2.5GHz 2=5GHz */ + *speed = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT; } + static int __devinit bnx2x_check_firmware(struct bnx2x *bp) { + const struct firmware *firmware = bp->firmware; struct bnx2x_fw_file_hdr *fw_hdr; struct bnx2x_fw_file_section *sections; - u16 *ops_offsets; u32 offset, len, num_ops; + u16 *ops_offsets; int i; - const struct firmware *firmware = bp->firmware; - const u8 * fw_ver; + const u8 *fw_ver; if (firmware->size < sizeof(struct bnx2x_fw_file_hdr)) return -EINVAL; @@ -11709,7 +11704,8 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp) offset = be32_to_cpu(sections[i].offset); len = be32_to_cpu(sections[i].len); if (offset + len > firmware->size) { - printk(KERN_ERR PFX "Section %d length is out of bounds\n", i); + printk(KERN_ERR PFX "Section %d length is out of " + "bounds\n", i); return -EINVAL; } } @@ -11721,7 +11717,8 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp) for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) { if (be16_to_cpu(ops_offsets[i]) > num_ops) { - printk(KERN_ERR PFX "Section offset %d is out of bounds\n", i); + printk(KERN_ERR PFX "Section offset %d is out of " + "bounds\n", i); return -EINVAL; } } @@ -11878,6 +11875,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, static int version_printed; struct net_device *dev = NULL; struct bnx2x *bp; + int pcie_width, pcie_speed; int rc; if (version_printed++ == 0) @@ -11918,11 +11916,11 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, goto init_one_exit; } + bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed); printk(KERN_INFO "%s: %s (%c%d) PCI-E x%d %s found at mem %lx," " IRQ %d, ", dev->name, board_info[ent->driver_data].name, (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4), - bnx2x_get_pcie_width(bp), - (bnx2x_get_pcie_speed(bp) == 2) ? "5GHz (Gen2)" : "2.5GHz", + pcie_width, (pcie_speed == 2) ? "5GHz (Gen2)" : "2.5GHz", dev->base_addr, bp->pdev->irq); printk(KERN_CONT "node addr %pM\n", dev->dev_addr); -- cgit v0.10.2 From 938cf5416d59769ec2e7ce4eb7967cb3b61242a3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:37 +0000 Subject: bnx2x: Move printing of version from probe to the init Move printing of version from probe to the init function Rather then checking if this is the first module probe call to print the version of the driver only once, the statement is moved to the init function of the module where init is only called once Signed-off-by: Benjamin Li Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 807c156..f1bd0a3 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11872,15 +11872,11 @@ request_firmware_exit: static int __devinit bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - static int version_printed; struct net_device *dev = NULL; struct bnx2x *bp; int pcie_width, pcie_speed; int rc; - if (version_printed++ == 0) - printk(KERN_INFO "%s", version); - /* dev zeroed in init_etherdev */ dev = alloc_etherdev_mq(sizeof(*bp), MAX_CONTEXT); if (!dev) { @@ -12218,6 +12214,8 @@ static int __init bnx2x_init(void) { int ret; + printk(KERN_INFO "%s", version); + bnx2x_wq = create_singlethread_workqueue("bnx2x"); if (bnx2x_wq == NULL) { printk(KERN_ERR PFX "Cannot create workqueue\n"); -- cgit v0.10.2 From 0d28e49a2616b927bca5fde0f16dfdfd2a501107 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:40 +0000 Subject: bnx2x: Updating regdump_len at drvinfo Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index f1bd0a3..276d846 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -8947,50 +8947,15 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return 0; } -#define PHY_FW_VER_LEN 10 - -static void bnx2x_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct bnx2x *bp = netdev_priv(dev); - u8 phy_fw_ver[PHY_FW_VER_LEN]; - - strcpy(info->driver, DRV_MODULE_NAME); - strcpy(info->version, DRV_MODULE_VERSION); - - phy_fw_ver[0] = '\0'; - if (bp->port.pmf) { - bnx2x_acquire_phy_lock(bp); - bnx2x_get_ext_phy_fw_version(&bp->link_params, - (bp->state != BNX2X_STATE_CLOSED), - phy_fw_ver, PHY_FW_VER_LEN); - bnx2x_release_phy_lock(bp); - } - - snprintf(info->fw_version, 32, "BC:%d.%d.%d%s%s", - (bp->common.bc_ver & 0xff0000) >> 16, - (bp->common.bc_ver & 0xff00) >> 8, - (bp->common.bc_ver & 0xff), - ((phy_fw_ver[0] != '\0') ? " PHY:" : ""), phy_fw_ver); - strcpy(info->bus_info, pci_name(bp->pdev)); - info->n_stats = BNX2X_NUM_STATS; - info->testinfo_len = BNX2X_NUM_TESTS; - info->eedump_len = bp->common.flash_size; - info->regdump_len = 0; -} - #define IS_E1_ONLINE(info) (((info) & RI_E1_ONLINE) == RI_E1_ONLINE) #define IS_E1H_ONLINE(info) (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE) static int bnx2x_get_regs_len(struct net_device *dev) { - static u32 regdump_len; struct bnx2x *bp = netdev_priv(dev); + int regdump_len = 0; int i; - if (regdump_len) - return regdump_len; - if (CHIP_IS_E1(bp)) { for (i = 0; i < REGS_COUNT; i++) if (IS_E1_ONLINE(reg_addrs[i].info)) @@ -9057,6 +9022,38 @@ static void bnx2x_get_regs(struct net_device *dev, } } +#define PHY_FW_VER_LEN 10 + +static void bnx2x_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct bnx2x *bp = netdev_priv(dev); + u8 phy_fw_ver[PHY_FW_VER_LEN]; + + strcpy(info->driver, DRV_MODULE_NAME); + strcpy(info->version, DRV_MODULE_VERSION); + + phy_fw_ver[0] = '\0'; + if (bp->port.pmf) { + bnx2x_acquire_phy_lock(bp); + bnx2x_get_ext_phy_fw_version(&bp->link_params, + (bp->state != BNX2X_STATE_CLOSED), + phy_fw_ver, PHY_FW_VER_LEN); + bnx2x_release_phy_lock(bp); + } + + snprintf(info->fw_version, 32, "BC:%d.%d.%d%s%s", + (bp->common.bc_ver & 0xff0000) >> 16, + (bp->common.bc_ver & 0xff00) >> 8, + (bp->common.bc_ver & 0xff), + ((phy_fw_ver[0] != '\0') ? " PHY:" : ""), phy_fw_ver); + strcpy(info->bus_info, pci_name(bp->pdev)); + info->n_stats = BNX2X_NUM_STATS; + info->testinfo_len = BNX2X_NUM_TESTS; + info->eedump_len = bp->common.flash_size; + info->regdump_len = bnx2x_get_regs_len(dev); +} + static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct bnx2x *bp = netdev_priv(dev); -- cgit v0.10.2 From 5ff7b6d4c129a430e355b2f88162a36d9e058f88 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:44 +0000 Subject: bnx2x: Remove the init_dmae field from bp Moved the dmae_command from the heap to the stack. This will save 56 bytes per bnx2x structure. As a side benefit, we can also reduce the time the dmae_mutex is held. This is because do we not need to hold this mutex when setting up the dmae command. The memory where is dmae command is stored is not a shared resource and doesn not need to be protected. Signed-off-by: Benjamin Li Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 633acca..a231780 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -973,7 +973,6 @@ struct bnx2x { int dmae_ready; /* used to synchronize dmae accesses */ struct mutex dmae_mutex; - struct dmae_command init_dmae; /* used to synchronize stats collecting */ int stats_state; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 276d846..59aacd8 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -203,7 +203,7 @@ static void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, u32 len32) { - struct dmae_command *dmae = &bp->init_dmae; + struct dmae_command dmae; u32 *wb_comp = bnx2x_sp(bp, wb_comp); int cnt = 200; @@ -216,43 +216,43 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, return; } - mutex_lock(&bp->dmae_mutex); - - memset(dmae, 0, sizeof(struct dmae_command)); + memset(&dmae, 0, sizeof(struct dmae_command)); - dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | - DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | - DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | + dmae.opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | #ifdef __BIG_ENDIAN - DMAE_CMD_ENDIANITY_B_DW_SWAP | + DMAE_CMD_ENDIANITY_B_DW_SWAP | #else - DMAE_CMD_ENDIANITY_DW_SWAP | + DMAE_CMD_ENDIANITY_DW_SWAP | #endif - (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | - (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); - dmae->src_addr_lo = U64_LO(dma_addr); - dmae->src_addr_hi = U64_HI(dma_addr); - dmae->dst_addr_lo = dst_addr >> 2; - dmae->dst_addr_hi = 0; - dmae->len = len32; - dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_val = DMAE_COMP_VAL; + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae.src_addr_lo = U64_LO(dma_addr); + dmae.src_addr_hi = U64_HI(dma_addr); + dmae.dst_addr_lo = dst_addr >> 2; + dmae.dst_addr_hi = 0; + dmae.len = len32; + dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); + dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); + dmae.comp_val = DMAE_COMP_VAL; DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n" DP_LEVEL "src_addr [%x:%08x] len [%d *4] " "dst_addr [%x:%08x (%08x)]\n" DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", - dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, - dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, dst_addr, - dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); + dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo, + dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, dst_addr, + dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val); DP(BNX2X_MSG_OFF, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n", bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); + mutex_lock(&bp->dmae_mutex); + *wb_comp = 0; - bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); + bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp)); udelay(5); @@ -276,7 +276,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) { - struct dmae_command *dmae = &bp->init_dmae; + struct dmae_command dmae; u32 *wb_comp = bnx2x_sp(bp, wb_comp); int cnt = 200; @@ -291,41 +291,41 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) return; } - mutex_lock(&bp->dmae_mutex); - - memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4); - memset(dmae, 0, sizeof(struct dmae_command)); + memset(&dmae, 0, sizeof(struct dmae_command)); - dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | - DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | - DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | + dmae.opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | #ifdef __BIG_ENDIAN - DMAE_CMD_ENDIANITY_B_DW_SWAP | + DMAE_CMD_ENDIANITY_B_DW_SWAP | #else - DMAE_CMD_ENDIANITY_DW_SWAP | + DMAE_CMD_ENDIANITY_DW_SWAP | #endif - (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | - (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); - dmae->src_addr_lo = src_addr >> 2; - dmae->src_addr_hi = 0; - dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data)); - dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data)); - dmae->len = len32; - dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_val = DMAE_COMP_VAL; + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae.src_addr_lo = src_addr >> 2; + dmae.src_addr_hi = 0; + dmae.dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data)); + dmae.dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data)); + dmae.len = len32; + dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); + dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); + dmae.comp_val = DMAE_COMP_VAL; DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n" DP_LEVEL "src_addr [%x:%08x] len [%d *4] " "dst_addr [%x:%08x (%08x)]\n" DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", - dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, - dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, src_addr, - dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); + dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo, + dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, src_addr, + dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val); + mutex_lock(&bp->dmae_mutex); + + memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4); *wb_comp = 0; - bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); + bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp)); udelay(5); -- cgit v0.10.2 From 54016b260e873d0d4d30cf1fdbd0cdcf0e26251b Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:48 +0000 Subject: bnx2x: Check unzip return code Without this check, when running out of memory, we will see PSOD's in bnx2x_init_fill() when doing a memset(). This is because at that time, bp->gunzip_buf is not pointing to a valid allocated space. Signed-off-by: Benjamin Li Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 59aacd8..edd7b13 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -6512,7 +6512,9 @@ static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) bp->dmae_ready = 0; mutex_init(&bp->dmae_mutex); - bnx2x_gunzip_init(bp); + rc = bnx2x_gunzip_init(bp); + if (rc) + return rc; switch (load_code) { case FW_MSG_CODE_DRV_LOAD_COMMON: -- cgit v0.10.2 From 6f65497b567ef9a518d930ef30fe6b8f27051688 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:51 +0000 Subject: bnx2x: Keep only one HW path active Disable bmac access while working with emac and keep the single lane SerDes in reset while working with 4 lanes XGXS Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index dc3b69e..b81a057 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -397,7 +397,8 @@ static u8 bnx2x_emac_enable(struct link_params *params, /* enable access for bmac registers */ REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); - } + } else + REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0); vars->mac_type = MAC_TYPE_EMAC; return 0; @@ -1021,8 +1022,8 @@ static u8 bnx2x_reset_unicore(struct link_params *params) MDIO_COMBO_IEEE0_MII_CONTROL, (mii_control | MDIO_COMBO_IEEO_MII_CONTROL_RESET)); - - bnx2x_set_serdes_access(params); + if (params->switch_cfg == SWITCH_CFG_1G) + bnx2x_set_serdes_access(params); /* wait for the reset to self clear */ for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) { -- cgit v0.10.2 From 57937203aa077520a7e1665bfb7071b3cbb3f5a9 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:53 +0000 Subject: bnx2x: Remove SGMII configuration when not required Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index b81a057..c163c42 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -1276,14 +1276,14 @@ static void bnx2x_program_serdes(struct link_params *params, struct bnx2x *bp = params->bp; u16 reg_val; - /* program duplex, disable autoneg */ - + /* program duplex, disable autoneg and sgmii*/ CL45_RD_OVER_CL22(bp, params->port, params->phy_addr, MDIO_REG_BANK_COMBO_IEEE0, MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX | - MDIO_COMBO_IEEO_MII_CONTROL_AN_EN); + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK); if (params->req_duplex == DUPLEX_FULL) reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; CL45_WR_OVER_CL22(bp, params->port, @@ -5271,6 +5271,13 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, ext_phy_link_up = 0; break; } + /* Set SGMII mode for external phy */ + if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) { + if (vars->line_speed < SPEED_1000) + vars->phy_flags |= PHY_SGMII_FLAG; + else + vars->phy_flags &= ~PHY_SGMII_FLAG; + } } else { /* SerDes */ ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config); -- cgit v0.10.2 From 8924665a7d77bb79ee895b98864e3201507f6ef2 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:56 +0000 Subject: bnx2x: Missing smp_wmb for statistics state machine Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index edd7b13..1e8e7e1 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -4412,6 +4412,9 @@ static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event) bnx2x_stats_stm[state][event].action(bp); bp->stats_state = bnx2x_stats_stm[state][event].next_state; + /* Make sure the state has been "changed" */ + smp_wmb(); + if ((event != STATS_EVENT_UPDATE) || (bp->msglevel & NETIF_MSG_TIMER)) DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n", state, event, bp->stats_state); -- cgit v0.10.2 From 1ef70b9c12407f0bf332ba775a8aa8f8035d0a24 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:59 +0000 Subject: bnx2x: Re-arrange the link structures for better alignment Change ieee_fc to u16 instead of u32 and re-arrange the link parameters structures Signed-off-by: Yitchak Gertner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index c163c42..74f4d10 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -1347,7 +1347,7 @@ static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params) MDIO_OVER_1G_UP3, 0x400); } -static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) +static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u16 *ieee_fc) { *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX; /* resolve pause mode and advertisement @@ -1381,7 +1381,7 @@ static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) } static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params, - u32 ieee_fc) + u16 ieee_fc) { struct bnx2x *bp = params->bp; /* for AN, we are always publishing full duplex */ @@ -1389,7 +1389,7 @@ static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params, CL45_WR_OVER_CL22(bp, params->port, params->phy_addr, MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc); + MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc); } static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73) diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index 6d26d6c..e0d7eef 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -81,6 +81,11 @@ struct link_params { #define SWITCH_CFG_AUTO_DETECT PORT_FEATURE_CON_SWITCH_AUTO_DETECT u16 hw_led_mode; /* part of the hw_config read from the shmem */ + + /* phy_addr populated by the phy_init function */ + u8 phy_addr; + /*u8 reserved1;*/ + u32 lane_config; u32 ext_phy_config; #define XGXS_EXT_PHY_TYPE(ext_phy_config) (ext_phy_config & \ @@ -90,39 +95,41 @@ struct link_params { /* Phy register parameter */ u32 chip_id; - /* phy_addr populated by the CLC */ - u8 phy_addr; u16 xgxs_config_rx[4]; /* preemphasis values for the rx side */ - u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */ + u32 feature_config_flags; #define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0) #define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2) #define FEATURE_CONFIG_BCM8727_NOC (1<<3) + /* Device pointer passed to all callback functions */ struct bnx2x *bp; }; /* Output parameters */ struct link_vars { + u8 phy_flags; + + u8 mac_type; +#define MAC_TYPE_NONE 0 +#define MAC_TYPE_EMAC 1 +#define MAC_TYPE_BMAC 2 + u8 phy_link_up; /* internal phy link indication */ u8 link_up; + + u16 line_speed; u16 duplex; + u16 flow_ctrl; - u32 ieee_fc; - u8 mac_type; + u16 ieee_fc; -#define MAC_TYPE_NONE 0 -#define MAC_TYPE_EMAC 1 -#define MAC_TYPE_BMAC 2 - u16 line_speed; u32 autoneg; #define AUTO_NEG_DISABLED 0x0 #define AUTO_NEG_ENABLED 0x1 #define AUTO_NEG_COMPLETE 0x2 -#define AUTO_NEG_PARALLEL_DETECTION_USED 0x3 - - u8 phy_flags; +#define AUTO_NEG_PARALLEL_DETECTION_USED 0x3 /* The same definitions as the shmem parameter */ u32 link_status; -- cgit v0.10.2 From 659bc5c4f2e84e69e1b10b36c16cd52ff7eb317a Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:02 +0000 Subject: bnx2x: Using macro for phy address Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 74f4d10..c2b0010 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -1547,10 +1547,7 @@ static u8 bnx2x_ext_phy_resove_fc(struct link_params *params, u8 ret = 0; u32 ext_phy_type; u8 port = params->port; - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* read twice */ @@ -2011,9 +2008,8 @@ static void bnx2x_ext_phy_reset(struct link_params *params, { struct bnx2x *bp = params->bp; u32 ext_phy_type; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); + DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* The PHY reset is controled by GPIO 1 @@ -2292,9 +2288,7 @@ static void bnx2x_bcm8072_external_rom_boot(struct link_params *params) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Need to wait 200ms after reset */ @@ -2342,9 +2336,7 @@ static u8 bnx2x_8073_is_snr_needed(struct link_params *params) /* This is only required for 8073A1, version 102 only */ struct bnx2x *bp = params->bp; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u16 val; /* Read 8073 HW revision*/ @@ -2375,9 +2367,7 @@ static u8 bnx2x_8073_is_snr_needed(struct link_params *params) static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params) { struct bnx2x *bp = params->bp; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u16 val, cnt, cnt1 ; bnx2x_cl45_read(bp, params->port, @@ -2519,9 +2509,7 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Need to wait 100ms after reset */ @@ -2607,9 +2595,7 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params, u16 val = 0; u16 i; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); if (byte_cnt > 16) { DP(NETIF_MSG_LINK, "Reading from eeprom is" @@ -2691,9 +2677,7 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params, struct bnx2x *bp = params->bp; u16 val, i; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); if (byte_cnt > 16) { @@ -2946,9 +2930,7 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params, { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u16 cur_limiting_mode; bnx2x_cl45_read(bp, port, @@ -3014,9 +2996,7 @@ static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params, u8 port = params->port; u16 phy_identifier; u16 rom_ver2_val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, @@ -3120,9 +3100,7 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params) struct bnx2x *bp = params->bp; u16 edc_mode; u8 rc = 0; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); u32 val = REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, dev_info. @@ -3212,9 +3190,8 @@ void bnx2x_handle_module_detect_int(struct link_params *params) else DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n"); } else { - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); u32 val = REG_RD(bp, params->shmem_base + @@ -3238,9 +3215,7 @@ static void bnx2x_bcm807x_force_10G(struct link_params *params) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Force KR or KX */ @@ -3266,9 +3241,7 @@ static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params) struct bnx2x *bp = params->bp; u8 port = params->port; u16 val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); bnx2x_cl45_read(bp, params->port, @@ -3333,9 +3306,7 @@ static void bnx2x_8073_set_pause_cl37(struct link_params *params, struct bnx2x *bp = params->bp; u16 cl37_val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); bnx2x_cl45_read(bp, params->port, @@ -3378,9 +3349,7 @@ static void bnx2x_ext_phy_set_pause(struct link_params *params, { struct bnx2x *bp = params->bp; u16 val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* read modify write pause advertizing */ @@ -3617,9 +3586,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) u16 val = 0; u8 rc = 0; if (vars->phy_flags & PHY_XGXS_FLAG) { - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Make sure that the soft reset is off (expect for the 8072: @@ -4555,9 +4522,7 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params) { struct bnx2x *bp = params->bp; u16 mod_abs, rx_alarm_status; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 val = REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, dev_info. port_feature_config[params->port]. @@ -4657,10 +4622,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, u8 ext_phy_link_up = 0; u8 port = params->port; if (vars->phy_flags & PHY_XGXS_FLAG) { - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: @@ -5608,10 +5570,8 @@ static void bnx2x_ext_phy_loopback(struct link_params *params) if (params->switch_cfg == SWITCH_CFG_10G) { ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); /* CL37 Autoneg Enabled */ - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN: @@ -6180,9 +6140,8 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, { /* Disable Transmitter */ - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = + XGXS_EXT_PHY_ADDR(params->ext_phy_config); if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) bnx2x_sfp_set_transmitter(bp, port, @@ -6200,9 +6159,8 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: { - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = + XGXS_EXT_PHY_ADDR(params->ext_phy_config); /* Set soft reset */ bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr); break; @@ -6420,10 +6378,7 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) NIG_MASK_SERDES0_LINK_STATUS | NIG_MASK_MI_INT)); - ext_phy_addr[port] = - ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config); /* Need to take the phy out of low power mode in order to write to access its registers */ @@ -6549,9 +6504,7 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) NIG_MASK_SERDES0_LINK_STATUS | NIG_MASK_MI_INT)); - ext_phy_addr[port] = ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config); /* Reset the phy */ bnx2x_cl45_write(bp, port, @@ -6609,10 +6562,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) offsetof(struct shmem_region, dev_info.port_hw_config[port].external_phy_config)); - ext_phy_addr = - ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr = XGXS_EXT_PHY_ADDR(ext_phy_config); DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n", ext_phy_addr); diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index e0d7eef..f3e2522 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -88,10 +88,14 @@ struct link_params { u32 lane_config; u32 ext_phy_config; -#define XGXS_EXT_PHY_TYPE(ext_phy_config) (ext_phy_config & \ - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK) -#define SERDES_EXT_PHY_TYPE(ext_phy_config) (ext_phy_config & \ - PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) +#define XGXS_EXT_PHY_TYPE(ext_phy_config) \ + ((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK) +#define XGXS_EXT_PHY_ADDR(ext_phy_config) \ + (((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> \ + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT) +#define SERDES_EXT_PHY_TYPE(ext_phy_config) \ + ((ext_phy_config) & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) + /* Phy register parameter */ u32 chip_id; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 1e8e7e1..d22c6b7 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -8546,9 +8546,7 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) && (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) bp->mdio.prtad = - (bp->link_params.ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT; + XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config); val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper); val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); @@ -9549,9 +9547,7 @@ static int bnx2x_set_eeprom(struct net_device *dev, if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) { u8 ext_phy_addr = - (bp->link_params.ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT; + XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config); /* DSP Remove Download Mode */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, -- cgit v0.10.2 From 0fc5d0094de11bb005c35f03fb1d3b52b0bd85e3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:05 +0000 Subject: bnx2x: Adding explicit casting Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index d22c6b7..6b6aa89 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -2927,7 +2927,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) REG_WR(bp, reg_offset, val); BNX2X_ERR("FATAL HW block attention set0 0x%x\n", - (attn & HW_INTERRUT_ASSERT_SET_0)); + (u32)(attn & HW_INTERRUT_ASSERT_SET_0)); bnx2x_panic(); } } @@ -2958,7 +2958,7 @@ static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn) REG_WR(bp, reg_offset, val); BNX2X_ERR("FATAL HW block attention set1 0x%x\n", - (attn & HW_INTERRUT_ASSERT_SET_1)); + (u32)(attn & HW_INTERRUT_ASSERT_SET_1)); bnx2x_panic(); } } @@ -2998,7 +2998,7 @@ static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn) REG_WR(bp, reg_offset, val); BNX2X_ERR("FATAL HW block attention set2 0x%x\n", - (attn & HW_INTERRUT_ASSERT_SET_2)); + (u32)(attn & HW_INTERRUT_ASSERT_SET_2)); bnx2x_panic(); } } -- cgit v0.10.2 From e4ed7113372a04df9b7aa985ce3860207dbb1141 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:10 +0000 Subject: bnx2x: Using PCI_DEVICE macro Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 6b6aa89..b084e8b 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -138,12 +138,9 @@ static struct { static const struct pci_device_id bnx2x_pci_tbl[] = { - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57710 }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57711 }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711E, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57711E }, + { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 }, + { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 }, + { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E }, { 0 } }; -- cgit v0.10.2 From 573f203574581faaf80ca4fc079d33452327fc3b Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:14 +0000 Subject: bnx2x: Re-factor the initialization code Moving the code to a more logical place and beautifying it. No real change in behavior. Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index a231780..97bc5e0 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -116,16 +116,22 @@ #define REG_RD_DMAE(bp, offset, valp, len32) \ do { \ bnx2x_read_dmae(bp, offset, len32);\ - memcpy(valp, bnx2x_sp(bp, wb_data[0]), len32 * 4); \ + memcpy(valp, bnx2x_sp(bp, wb_data[0]), (len32) * 4); \ } while (0) #define REG_WR_DMAE(bp, offset, valp, len32) \ do { \ - memcpy(bnx2x_sp(bp, wb_data[0]), valp, len32 * 4); \ + memcpy(bnx2x_sp(bp, wb_data[0]), valp, (len32) * 4); \ bnx2x_write_dmae(bp, bnx2x_sp_mapping(bp, wb_data), \ offset, len32); \ } while (0) +#define VIRT_WR_DMAE_LEN(bp, data, addr, len32) \ + do { \ + memcpy(GUNZIP_BUF(bp), data, (len32) * 4); \ + bnx2x_write_big_buf_wb(bp, addr, len32); \ + } while (0) + #define SHMEM_ADDR(bp, field) (bp->common.shmem_base + \ offsetof(struct shmem_region, field)) #define SHMEM_RD(bp, field) REG_RD(bp, SHMEM_ADDR(bp, field)) @@ -988,6 +994,9 @@ struct bnx2x { dma_addr_t gunzip_mapping; int gunzip_outlen; #define FW_BUF_SIZE 0x8000 +#define GUNZIP_BUF(bp) (bp->gunzip_buf) +#define GUNZIP_PHYS(bp) (bp->gunzip_mapping) +#define GUNZIP_OUTLEN(bp) (bp->gunzip_outlen) struct raw_op *init_ops; /* Init blocks offsets inside init_ops */ @@ -1003,6 +1012,18 @@ struct bnx2x { const u8 *xsem_pram_data; const u8 *csem_int_table_data; const u8 *csem_pram_data; +#define INIT_OPS(bp) (bp->init_ops) +#define INIT_OPS_OFFSETS(bp) (bp->init_ops_offsets) +#define INIT_DATA(bp) (bp->init_data) +#define INIT_TSEM_INT_TABLE_DATA(bp) (bp->tsem_int_table_data) +#define INIT_TSEM_PRAM_DATA(bp) (bp->tsem_pram_data) +#define INIT_USEM_INT_TABLE_DATA(bp) (bp->usem_int_table_data) +#define INIT_USEM_PRAM_DATA(bp) (bp->usem_pram_data) +#define INIT_XSEM_INT_TABLE_DATA(bp) (bp->xsem_int_table_data) +#define INIT_XSEM_PRAM_DATA(bp) (bp->xsem_pram_data) +#define INIT_CSEM_INT_TABLE_DATA(bp) (bp->csem_int_table_data) +#define INIT_CSEM_PRAM_DATA(bp) (bp->csem_pram_data) + const struct firmware *firmware; }; @@ -1030,6 +1051,9 @@ int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port); int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); u32 bnx2x_fw_command(struct bnx2x *bp, u32 command); +void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); +void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr, + u32 addr, u32 len); static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, int wait) diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x_init.h index 3ba4d88..65b26cb 100644 --- a/drivers/net/bnx2x_init.h +++ b/drivers/net/bnx2x_init.h @@ -15,24 +15,11 @@ #ifndef BNX2X_INIT_H #define BNX2X_INIT_H -#define COMMON 0x1 -#define PORT0 0x2 -#define PORT1 0x4 - -#define INIT_EMULATION 0x1 -#define INIT_FPGA 0x2 -#define INIT_ASIC 0x4 -#define INIT_HARDWARE 0x7 - -#define TSTORM_INTMEM_ADDR TSEM_REG_FAST_MEMORY -#define CSTORM_INTMEM_ADDR CSEM_REG_FAST_MEMORY -#define XSTORM_INTMEM_ADDR XSEM_REG_FAST_MEMORY -#define USTORM_INTMEM_ADDR USEM_REG_FAST_MEMORY /* RAM0 size in bytes */ #define STORM_INTMEM_SIZE_E1 0x5800 #define STORM_INTMEM_SIZE_E1H 0x10000 -#define STORM_INTMEM_SIZE(bp) ((CHIP_IS_E1H(bp) ? STORM_INTMEM_SIZE_E1H : \ - STORM_INTMEM_SIZE_E1) / 4) +#define STORM_INTMEM_SIZE(bp) ((CHIP_IS_E1(bp) ? STORM_INTMEM_SIZE_E1 : \ + STORM_INTMEM_SIZE_E1H) / 4) /* Init operation types and structures */ @@ -53,65 +40,68 @@ #define OP_WR_ASIC 0xc /* write single register on ASIC */ /* Init stages */ -#define COMMON_STAGE 0 -#define PORT0_STAGE 1 -#define PORT1_STAGE 2 -/* Never reorder FUNCx stages !!! */ -#define FUNC0_STAGE 3 -#define FUNC1_STAGE 4 -#define FUNC2_STAGE 5 -#define FUNC3_STAGE 6 -#define FUNC4_STAGE 7 -#define FUNC5_STAGE 8 -#define FUNC6_STAGE 9 -#define FUNC7_STAGE 10 -#define STAGE_IDX_MAX 11 - -#define STAGE_START 0 -#define STAGE_END 1 +/* Never reorder stages !!! */ +#define COMMON_STAGE 0 +#define PORT0_STAGE 1 +#define PORT1_STAGE 2 +#define FUNC0_STAGE 3 +#define FUNC1_STAGE 4 +#define FUNC2_STAGE 5 +#define FUNC3_STAGE 6 +#define FUNC4_STAGE 7 +#define FUNC5_STAGE 8 +#define FUNC6_STAGE 9 +#define FUNC7_STAGE 10 +#define STAGE_IDX_MAX 11 + +#define STAGE_START 0 +#define STAGE_END 1 /* Indices of blocks */ -#define PRS_BLOCK 0 -#define SRCH_BLOCK 1 -#define TSDM_BLOCK 2 -#define TCM_BLOCK 3 -#define BRB1_BLOCK 4 -#define TSEM_BLOCK 5 -#define PXPCS_BLOCK 6 -#define EMAC0_BLOCK 7 -#define EMAC1_BLOCK 8 -#define DBU_BLOCK 9 -#define MISC_BLOCK 10 -#define DBG_BLOCK 11 -#define NIG_BLOCK 12 -#define MCP_BLOCK 13 -#define UPB_BLOCK 14 -#define CSDM_BLOCK 15 -#define USDM_BLOCK 16 -#define CCM_BLOCK 17 -#define UCM_BLOCK 18 -#define USEM_BLOCK 19 -#define CSEM_BLOCK 20 -#define XPB_BLOCK 21 -#define DQ_BLOCK 22 -#define TIMERS_BLOCK 23 -#define XSDM_BLOCK 24 -#define QM_BLOCK 25 -#define PBF_BLOCK 26 -#define XCM_BLOCK 27 -#define XSEM_BLOCK 28 -#define CDU_BLOCK 29 -#define DMAE_BLOCK 30 -#define PXP_BLOCK 31 -#define CFC_BLOCK 32 -#define HC_BLOCK 33 -#define PXP2_BLOCK 34 -#define MISC_AEU_BLOCK 35 +#define PRS_BLOCK 0 +#define SRCH_BLOCK 1 +#define TSDM_BLOCK 2 +#define TCM_BLOCK 3 +#define BRB1_BLOCK 4 +#define TSEM_BLOCK 5 +#define PXPCS_BLOCK 6 +#define EMAC0_BLOCK 7 +#define EMAC1_BLOCK 8 +#define DBU_BLOCK 9 +#define MISC_BLOCK 10 +#define DBG_BLOCK 11 +#define NIG_BLOCK 12 +#define MCP_BLOCK 13 +#define UPB_BLOCK 14 +#define CSDM_BLOCK 15 +#define USDM_BLOCK 16 +#define CCM_BLOCK 17 +#define UCM_BLOCK 18 +#define USEM_BLOCK 19 +#define CSEM_BLOCK 20 +#define XPB_BLOCK 21 +#define DQ_BLOCK 22 +#define TIMERS_BLOCK 23 +#define XSDM_BLOCK 24 +#define QM_BLOCK 25 +#define PBF_BLOCK 26 +#define XCM_BLOCK 27 +#define XSEM_BLOCK 28 +#define CDU_BLOCK 29 +#define DMAE_BLOCK 30 +#define PXP_BLOCK 31 +#define CFC_BLOCK 32 +#define HC_BLOCK 33 +#define PXP2_BLOCK 34 +#define MISC_AEU_BLOCK 35 +#define PGLUE_B_BLOCK 36 +#define IGU_BLOCK 37 + /* Returns the index of start or end of a specific block stage in ops array*/ #define BLOCK_OPS_IDX(block, stage, end) \ - (2*(((block)*STAGE_IDX_MAX) + (stage)) + (end)) + (2*(((block)*STAGE_IDX_MAX) + (stage)) + (end)) struct raw_op { @@ -158,199 +148,5 @@ union init_op { struct raw_op raw; }; -/**************************************************************************** -* PXP -****************************************************************************/ -/* - * This code configures the PCI read/write arbiter - * which implements a weighted round robin - * between the virtual queues in the chip. - * - * The values were derived for each PCI max payload and max request size. - * since max payload and max request size are only known at run time, - * this is done as a separate init stage. - */ - -#define NUM_WR_Q 13 -#define NUM_RD_Q 29 -#define MAX_RD_ORD 3 -#define MAX_WR_ORD 2 - -/* configuration for one arbiter queue */ -struct arb_line { - int l; - int add; - int ubound; -}; - -/* derived configuration for each read queue for each max request size */ -static const struct arb_line read_arb_data[NUM_RD_Q][MAX_RD_ORD + 1] = { -/* 1 */ { {8, 64, 25}, {16, 64, 25}, {32, 64, 25}, {64, 64, 41} }, - { {4, 8, 4}, {4, 8, 4}, {4, 8, 4}, {4, 8, 4} }, - { {4, 3, 3}, {4, 3, 3}, {4, 3, 3}, {4, 3, 3} }, - { {8, 3, 6}, {16, 3, 11}, {16, 3, 11}, {16, 3, 11} }, - { {8, 64, 25}, {16, 64, 25}, {32, 64, 25}, {64, 64, 41} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, -/* 10 */{ {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, -/* 20 */{ {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 64, 25}, {16, 64, 41}, {32, 64, 81}, {64, 64, 120} } -}; - -/* derived configuration for each write queue for each max request size */ -static const struct arb_line write_arb_data[NUM_WR_Q][MAX_WR_ORD + 1] = { -/* 1 */ { {4, 6, 3}, {4, 6, 3}, {4, 6, 3} }, - { {4, 2, 3}, {4, 2, 3}, {4, 2, 3} }, - { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, - { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, - { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, - { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, - { {8, 64, 25}, {16, 64, 25}, {32, 64, 25} }, - { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, - { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, -/* 10 */{ {8, 9, 6}, {16, 9, 11}, {32, 9, 21} }, - { {8, 47, 19}, {16, 47, 19}, {32, 47, 21} }, - { {8, 9, 6}, {16, 9, 11}, {16, 9, 11} }, - { {8, 64, 25}, {16, 64, 41}, {32, 64, 81} } -}; - -/* register addresses for read queues */ -static const struct arb_line read_arb_addr[NUM_RD_Q-1] = { -/* 1 */ {PXP2_REG_RQ_BW_RD_L0, PXP2_REG_RQ_BW_RD_ADD0, - PXP2_REG_RQ_BW_RD_UBOUND0}, - {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, - PXP2_REG_PSWRQ_BW_UB1}, - {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, - PXP2_REG_PSWRQ_BW_UB2}, - {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, - PXP2_REG_PSWRQ_BW_UB3}, - {PXP2_REG_RQ_BW_RD_L4, PXP2_REG_RQ_BW_RD_ADD4, - PXP2_REG_RQ_BW_RD_UBOUND4}, - {PXP2_REG_RQ_BW_RD_L5, PXP2_REG_RQ_BW_RD_ADD5, - PXP2_REG_RQ_BW_RD_UBOUND5}, - {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, - PXP2_REG_PSWRQ_BW_UB6}, - {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, - PXP2_REG_PSWRQ_BW_UB7}, - {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, - PXP2_REG_PSWRQ_BW_UB8}, -/* 10 */{PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, - PXP2_REG_PSWRQ_BW_UB9}, - {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, - PXP2_REG_PSWRQ_BW_UB10}, - {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, - PXP2_REG_PSWRQ_BW_UB11}, - {PXP2_REG_RQ_BW_RD_L12, PXP2_REG_RQ_BW_RD_ADD12, - PXP2_REG_RQ_BW_RD_UBOUND12}, - {PXP2_REG_RQ_BW_RD_L13, PXP2_REG_RQ_BW_RD_ADD13, - PXP2_REG_RQ_BW_RD_UBOUND13}, - {PXP2_REG_RQ_BW_RD_L14, PXP2_REG_RQ_BW_RD_ADD14, - PXP2_REG_RQ_BW_RD_UBOUND14}, - {PXP2_REG_RQ_BW_RD_L15, PXP2_REG_RQ_BW_RD_ADD15, - PXP2_REG_RQ_BW_RD_UBOUND15}, - {PXP2_REG_RQ_BW_RD_L16, PXP2_REG_RQ_BW_RD_ADD16, - PXP2_REG_RQ_BW_RD_UBOUND16}, - {PXP2_REG_RQ_BW_RD_L17, PXP2_REG_RQ_BW_RD_ADD17, - PXP2_REG_RQ_BW_RD_UBOUND17}, - {PXP2_REG_RQ_BW_RD_L18, PXP2_REG_RQ_BW_RD_ADD18, - PXP2_REG_RQ_BW_RD_UBOUND18}, -/* 20 */{PXP2_REG_RQ_BW_RD_L19, PXP2_REG_RQ_BW_RD_ADD19, - PXP2_REG_RQ_BW_RD_UBOUND19}, - {PXP2_REG_RQ_BW_RD_L20, PXP2_REG_RQ_BW_RD_ADD20, - PXP2_REG_RQ_BW_RD_UBOUND20}, - {PXP2_REG_RQ_BW_RD_L22, PXP2_REG_RQ_BW_RD_ADD22, - PXP2_REG_RQ_BW_RD_UBOUND22}, - {PXP2_REG_RQ_BW_RD_L23, PXP2_REG_RQ_BW_RD_ADD23, - PXP2_REG_RQ_BW_RD_UBOUND23}, - {PXP2_REG_RQ_BW_RD_L24, PXP2_REG_RQ_BW_RD_ADD24, - PXP2_REG_RQ_BW_RD_UBOUND24}, - {PXP2_REG_RQ_BW_RD_L25, PXP2_REG_RQ_BW_RD_ADD25, - PXP2_REG_RQ_BW_RD_UBOUND25}, - {PXP2_REG_RQ_BW_RD_L26, PXP2_REG_RQ_BW_RD_ADD26, - PXP2_REG_RQ_BW_RD_UBOUND26}, - {PXP2_REG_RQ_BW_RD_L27, PXP2_REG_RQ_BW_RD_ADD27, - PXP2_REG_RQ_BW_RD_UBOUND27}, - {PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, - PXP2_REG_PSWRQ_BW_UB28} -}; - -/* register addresses for write queues */ -static const struct arb_line write_arb_addr[NUM_WR_Q-1] = { -/* 1 */ {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, - PXP2_REG_PSWRQ_BW_UB1}, - {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, - PXP2_REG_PSWRQ_BW_UB2}, - {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, - PXP2_REG_PSWRQ_BW_UB3}, - {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, - PXP2_REG_PSWRQ_BW_UB6}, - {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, - PXP2_REG_PSWRQ_BW_UB7}, - {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, - PXP2_REG_PSWRQ_BW_UB8}, - {PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, - PXP2_REG_PSWRQ_BW_UB9}, - {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, - PXP2_REG_PSWRQ_BW_UB10}, - {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, - PXP2_REG_PSWRQ_BW_UB11}, -/* 10 */{PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, - PXP2_REG_PSWRQ_BW_UB28}, - {PXP2_REG_RQ_BW_WR_L29, PXP2_REG_RQ_BW_WR_ADD29, - PXP2_REG_RQ_BW_WR_UBOUND29}, - {PXP2_REG_RQ_BW_WR_L30, PXP2_REG_RQ_BW_WR_ADD30, - PXP2_REG_RQ_BW_WR_UBOUND30} -}; - - -/**************************************************************************** -* CDU -****************************************************************************/ - -#define CDU_REGION_NUMBER_XCM_AG 2 -#define CDU_REGION_NUMBER_UCM_AG 4 - -/** - * String-to-compress [31:8] = CID (all 24 bits) - * String-to-compress [7:4] = Region - * String-to-compress [3:0] = Type - */ -#define CDU_VALID_DATA(_cid, _region, _type) \ - (((_cid) << 8) | (((_region) & 0xf) << 4) | (((_type) & 0xf))) -#define CDU_CRC8(_cid, _region, _type) \ - calc_crc8(CDU_VALID_DATA(_cid, _region, _type), 0xff) -#define CDU_RSRVD_VALUE_TYPE_A(_cid, _region, _type) \ - (0x80 | (CDU_CRC8(_cid, _region, _type) & 0x7f)) -#define CDU_RSRVD_VALUE_TYPE_B(_crc, _type) \ - (0x80 | ((_type) & 0xf << 3) | (CDU_CRC8(_cid, _region, _type) & 0x7)) -#define CDU_RSRVD_INVALIDATE_CONTEXT_VALUE(_val) ((_val) & ~0x80) - - -/* registers addresses are not in order - so these arrays help simplify the code */ -static const int cm_blocks[9] = { - MISC_BLOCK, TCM_BLOCK, UCM_BLOCK, CCM_BLOCK, XCM_BLOCK, - TSEM_BLOCK, USEM_BLOCK, CSEM_BLOCK, XSEM_BLOCK -}; - #endif /* BNX2X_INIT_H */ diff --git a/drivers/net/bnx2x_init_ops.h b/drivers/net/bnx2x_init_ops.h index 32552b9..38b970a 100644 --- a/drivers/net/bnx2x_init_ops.h +++ b/drivers/net/bnx2x_init_ops.h @@ -11,85 +11,68 @@ * Maintained by: Eilon Greenstein * Written by: Vladislav Zolotarov */ + #ifndef BNX2X_INIT_OPS_H #define BNX2X_INIT_OPS_H -static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len); + static void bnx2x_init_str_wr(struct bnx2x *bp, u32 addr, const u32 *data, u32 len) { - int i; + u32 i; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) REG_WR(bp, addr + i*4, data[i]); - if (!(i % 10000)) { - touch_softlockup_watchdog(); - cpu_relax(); - } - } } static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, const u32 *data, - u16 len) + u32 len) { - int i; + u32 i; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) REG_WR_IND(bp, addr + i*4, data[i]); - if (!(i % 10000)) { - touch_softlockup_watchdog(); - cpu_relax(); - } - } } static void bnx2x_write_big_buf(struct bnx2x *bp, u32 addr, u32 len) { - int offset = 0; - - if (bp->dmae_ready) { - while (len > DMAE_LEN32_WR_MAX) { - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, DMAE_LEN32_WR_MAX); - offset += DMAE_LEN32_WR_MAX * 4; - len -= DMAE_LEN32_WR_MAX; - } - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, len); - } else - bnx2x_init_str_wr(bp, addr, bp->gunzip_buf, len); + if (bp->dmae_ready) + bnx2x_write_dmae_phys_len(bp, GUNZIP_PHYS(bp), addr, len); + else + bnx2x_init_str_wr(bp, addr, GUNZIP_BUF(bp), len); } static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len) { - u32 buf_len = (((len * 4) > FW_BUF_SIZE) ? FW_BUF_SIZE : (len * 4)); - u32 buf_len32 = buf_len / 4; - int i; + u32 buf_len = (((len*4) > FW_BUF_SIZE) ? FW_BUF_SIZE : (len*4)); + u32 buf_len32 = buf_len/4; + u32 i; - memset(bp->gunzip_buf, fill, buf_len); + memset(GUNZIP_BUF(bp), (u8)fill, buf_len); for (i = 0; i < len; i += buf_len32) { u32 cur_len = min(buf_len32, len - i); - bnx2x_write_big_buf(bp, addr + i * 4, cur_len); + bnx2x_write_big_buf(bp, addr + i*4, cur_len); } } static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, const u32 *data, u32 len64) { - u32 buf_len32 = FW_BUF_SIZE / 4; - u32 len = len64 * 2; + u32 buf_len32 = FW_BUF_SIZE/4; + u32 len = len64*2; u64 data64 = 0; - int i; + u32 i; /* 64 bit value is in a blob: first low DWORD, then high DWORD */ data64 = HILO_U64((*(data + 1)), (*data)); + len64 = min((u32)(FW_BUF_SIZE/8), len64); for (i = 0; i < len64; i++) { - u64 *pdata = ((u64 *)(bp->gunzip_buf)) + i; + u64 *pdata = ((u64 *)(GUNZIP_BUF(bp))) + i; *pdata = data64; } @@ -97,7 +80,7 @@ static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, const u32 *data, for (i = 0; i < len; i += buf_len32) { u32 cur_len = min(buf_len32, len - i); - bnx2x_write_big_buf(bp, addr + i * 4, cur_len); + bnx2x_write_big_buf(bp, addr + i*4, cur_len); } } @@ -118,97 +101,81 @@ static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, const u32 *data, static const u8 *bnx2x_sel_blob(struct bnx2x *bp, u32 addr, const u8 *data) { IF_IS_INT_TABLE_ADDR(TSEM_REG_INT_TABLE, addr) - data = bp->tsem_int_table_data; - else IF_IS_INT_TABLE_ADDR(CSEM_REG_INT_TABLE, addr) - data = bp->csem_int_table_data; - else IF_IS_INT_TABLE_ADDR(USEM_REG_INT_TABLE, addr) - data = bp->usem_int_table_data; - else IF_IS_INT_TABLE_ADDR(XSEM_REG_INT_TABLE, addr) - data = bp->xsem_int_table_data; - else IF_IS_PRAM_ADDR(TSEM_REG_PRAM, addr) - data = bp->tsem_pram_data; - else IF_IS_PRAM_ADDR(CSEM_REG_PRAM, addr) - data = bp->csem_pram_data; - else IF_IS_PRAM_ADDR(USEM_REG_PRAM, addr) - data = bp->usem_pram_data; - else IF_IS_PRAM_ADDR(XSEM_REG_PRAM, addr) - data = bp->xsem_pram_data; + data = INIT_TSEM_INT_TABLE_DATA(bp); + else + IF_IS_INT_TABLE_ADDR(CSEM_REG_INT_TABLE, addr) + data = INIT_CSEM_INT_TABLE_DATA(bp); + else + IF_IS_INT_TABLE_ADDR(USEM_REG_INT_TABLE, addr) + data = INIT_USEM_INT_TABLE_DATA(bp); + else + IF_IS_INT_TABLE_ADDR(XSEM_REG_INT_TABLE, addr) + data = INIT_XSEM_INT_TABLE_DATA(bp); + else + IF_IS_PRAM_ADDR(TSEM_REG_PRAM, addr) + data = INIT_TSEM_PRAM_DATA(bp); + else + IF_IS_PRAM_ADDR(CSEM_REG_PRAM, addr) + data = INIT_CSEM_PRAM_DATA(bp); + else + IF_IS_PRAM_ADDR(USEM_REG_PRAM, addr) + data = INIT_USEM_PRAM_DATA(bp); + else + IF_IS_PRAM_ADDR(XSEM_REG_PRAM, addr) + data = INIT_XSEM_PRAM_DATA(bp); return data; } static void bnx2x_write_big_buf_wb(struct bnx2x *bp, u32 addr, u32 len) { - int offset = 0; - - if (bp->dmae_ready) { - while (len > DMAE_LEN32_WR_MAX) { - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, DMAE_LEN32_WR_MAX); - offset += DMAE_LEN32_WR_MAX * 4; - len -= DMAE_LEN32_WR_MAX; - } - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, len); - } else - bnx2x_init_ind_wr(bp, addr, bp->gunzip_buf, len); + if (bp->dmae_ready) + bnx2x_write_dmae_phys_len(bp, GUNZIP_PHYS(bp), addr, len); + else + bnx2x_init_ind_wr(bp, addr, GUNZIP_BUF(bp), len); } static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data, u32 len) { - /* This is needed for NO_ZIP mode, currently supported - in little endian mode only */ - data = (const u32*)bnx2x_sel_blob(bp, addr, (const u8*)data); + data = (const u32 *)bnx2x_sel_blob(bp, addr, (const u8 *)data); - if ((len * 4) > FW_BUF_SIZE) { - BNX2X_ERR("LARGE DMAE OPERATION ! " - "addr 0x%x len 0x%x\n", addr, len*4); - return; - } - memcpy(bp->gunzip_buf, data, len * 4); - - bnx2x_write_big_buf_wb(bp, addr, len); + if (bp->dmae_ready) + VIRT_WR_DMAE_LEN(bp, data, addr, len); + else + bnx2x_init_ind_wr(bp, addr, data, len); } -static void bnx2x_init_wr_zp(struct bnx2x *bp, u32 addr, - u32 len, u32 blob_off) +static void bnx2x_init_wr_zp(struct bnx2x *bp, u32 addr, u32 len, u32 blob_off) { - int rc, i; - const u8 *data = NULL; + const u8 *data = NULL; + int rc; + u32 i; - data = bnx2x_sel_blob(bp, addr, data) + 4*blob_off; - - if (data == NULL) { - panic("Blob not found for addr 0x%x\n", addr); - return; - } + data = bnx2x_sel_blob(bp, addr, data) + blob_off*4; rc = bnx2x_gunzip(bp, data, len); - if (rc) { - BNX2X_ERR("gunzip failed ! addr 0x%x rc %d\n", addr, rc); - BNX2X_ERR("blob_offset=0x%x\n", blob_off); + if (rc) return; - } /* gunzip_outlen is in dwords */ - len = bp->gunzip_outlen; + len = GUNZIP_OUTLEN(bp); for (i = 0; i < len; i++) - ((u32 *)bp->gunzip_buf)[i] = - cpu_to_le32(((u32 *)bp->gunzip_buf)[i]); + ((u32 *)GUNZIP_BUF(bp))[i] = + cpu_to_le32(((u32 *)GUNZIP_BUF(bp))[i]); bnx2x_write_big_buf_wb(bp, addr, len); } static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage) { - int hw_wr, i; u16 op_start = - bp->init_ops_offsets[BLOCK_OPS_IDX(block,stage,STAGE_START)]; + INIT_OPS_OFFSETS(bp)[BLOCK_OPS_IDX(block, stage, STAGE_START)]; u16 op_end = - bp->init_ops_offsets[BLOCK_OPS_IDX(block,stage,STAGE_END)]; + INIT_OPS_OFFSETS(bp)[BLOCK_OPS_IDX(block, stage, STAGE_END)]; union init_op *op; - u32 op_type, addr, len; + int hw_wr; + u32 i, op_type, addr, len; const u32 *data, *data_base; /* If empty block */ @@ -222,11 +189,11 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage) else hw_wr = OP_WR_ASIC; - data_base = bp->init_data; + data_base = INIT_DATA(bp); for (i = op_start; i < op_end; i++) { - op = (union init_op *)&(bp->init_ops[i]); + op = (union init_op *)&(INIT_OPS(bp)[i]); op_type = op->str_wr.op; addr = op->str_wr.offset; @@ -234,7 +201,7 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage) data = data_base + op->str_wr.data_off; /* HW/EMUL specific */ - if (unlikely((op_type > OP_WB) && (op_type == hw_wr))) + if ((op_type > OP_WB) && (op_type == hw_wr)) op_type = OP_WR; switch (op_type) { @@ -265,35 +232,179 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage) break; default: /* happens whenever an op is of a diff HW */ -#if 0 - DP(NETIF_MSG_HW, "skipping init operation " - "index %d[%d:%d]: type %d addr 0x%x " - "len %d(0x%x)\n", - i, op_start, op_end, op_type, addr, len, len); -#endif break; } } } -/* PXP */ -static void bnx2x_init_pxp(struct bnx2x *bp) + +/**************************************************************************** +* PXP Arbiter +****************************************************************************/ +/* + * This code configures the PCI read/write arbiter + * which implements a weighted round robin + * between the virtual queues in the chip. + * + * The values were derived for each PCI max payload and max request size. + * since max payload and max request size are only known at run time, + * this is done as a separate init stage. + */ + +#define NUM_WR_Q 13 +#define NUM_RD_Q 29 +#define MAX_RD_ORD 3 +#define MAX_WR_ORD 2 + +/* configuration for one arbiter queue */ +struct arb_line { + int l; + int add; + int ubound; +}; + +/* derived configuration for each read queue for each max request size */ +static const struct arb_line read_arb_data[NUM_RD_Q][MAX_RD_ORD + 1] = { +/* 1 */ { {8, 64, 25}, {16, 64, 25}, {32, 64, 25}, {64, 64, 41} }, + { {4, 8, 4}, {4, 8, 4}, {4, 8, 4}, {4, 8, 4} }, + { {4, 3, 3}, {4, 3, 3}, {4, 3, 3}, {4, 3, 3} }, + { {8, 3, 6}, {16, 3, 11}, {16, 3, 11}, {16, 3, 11} }, + { {8, 64, 25}, {16, 64, 25}, {32, 64, 25}, {64, 64, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, +/* 10 */{ {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 64, 6}, {16, 64, 11}, {32, 64, 21}, {32, 64, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, +/* 20 */{ {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 64, 25}, {16, 64, 41}, {32, 64, 81}, {64, 64, 120} } +}; + +/* derived configuration for each write queue for each max request size */ +static const struct arb_line write_arb_data[NUM_WR_Q][MAX_WR_ORD + 1] = { +/* 1 */ { {4, 6, 3}, {4, 6, 3}, {4, 6, 3} }, + { {4, 2, 3}, {4, 2, 3}, {4, 2, 3} }, + { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, + { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, + { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, + { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, + { {8, 64, 25}, {16, 64, 25}, {32, 64, 25} }, + { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, + { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, +/* 10 */{ {8, 9, 6}, {16, 9, 11}, {32, 9, 21} }, + { {8, 47, 19}, {16, 47, 19}, {32, 47, 21} }, + { {8, 9, 6}, {16, 9, 11}, {16, 9, 11} }, + { {8, 64, 25}, {16, 64, 41}, {32, 64, 81} } +}; + +/* register addresses for read queues */ +static const struct arb_line read_arb_addr[NUM_RD_Q-1] = { +/* 1 */ {PXP2_REG_RQ_BW_RD_L0, PXP2_REG_RQ_BW_RD_ADD0, + PXP2_REG_RQ_BW_RD_UBOUND0}, + {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, + PXP2_REG_PSWRQ_BW_UB1}, + {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, + PXP2_REG_PSWRQ_BW_UB2}, + {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, + PXP2_REG_PSWRQ_BW_UB3}, + {PXP2_REG_RQ_BW_RD_L4, PXP2_REG_RQ_BW_RD_ADD4, + PXP2_REG_RQ_BW_RD_UBOUND4}, + {PXP2_REG_RQ_BW_RD_L5, PXP2_REG_RQ_BW_RD_ADD5, + PXP2_REG_RQ_BW_RD_UBOUND5}, + {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, + PXP2_REG_PSWRQ_BW_UB6}, + {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, + PXP2_REG_PSWRQ_BW_UB7}, + {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, + PXP2_REG_PSWRQ_BW_UB8}, +/* 10 */{PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, + PXP2_REG_PSWRQ_BW_UB9}, + {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, + PXP2_REG_PSWRQ_BW_UB10}, + {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, + PXP2_REG_PSWRQ_BW_UB11}, + {PXP2_REG_RQ_BW_RD_L12, PXP2_REG_RQ_BW_RD_ADD12, + PXP2_REG_RQ_BW_RD_UBOUND12}, + {PXP2_REG_RQ_BW_RD_L13, PXP2_REG_RQ_BW_RD_ADD13, + PXP2_REG_RQ_BW_RD_UBOUND13}, + {PXP2_REG_RQ_BW_RD_L14, PXP2_REG_RQ_BW_RD_ADD14, + PXP2_REG_RQ_BW_RD_UBOUND14}, + {PXP2_REG_RQ_BW_RD_L15, PXP2_REG_RQ_BW_RD_ADD15, + PXP2_REG_RQ_BW_RD_UBOUND15}, + {PXP2_REG_RQ_BW_RD_L16, PXP2_REG_RQ_BW_RD_ADD16, + PXP2_REG_RQ_BW_RD_UBOUND16}, + {PXP2_REG_RQ_BW_RD_L17, PXP2_REG_RQ_BW_RD_ADD17, + PXP2_REG_RQ_BW_RD_UBOUND17}, + {PXP2_REG_RQ_BW_RD_L18, PXP2_REG_RQ_BW_RD_ADD18, + PXP2_REG_RQ_BW_RD_UBOUND18}, +/* 20 */{PXP2_REG_RQ_BW_RD_L19, PXP2_REG_RQ_BW_RD_ADD19, + PXP2_REG_RQ_BW_RD_UBOUND19}, + {PXP2_REG_RQ_BW_RD_L20, PXP2_REG_RQ_BW_RD_ADD20, + PXP2_REG_RQ_BW_RD_UBOUND20}, + {PXP2_REG_RQ_BW_RD_L22, PXP2_REG_RQ_BW_RD_ADD22, + PXP2_REG_RQ_BW_RD_UBOUND22}, + {PXP2_REG_RQ_BW_RD_L23, PXP2_REG_RQ_BW_RD_ADD23, + PXP2_REG_RQ_BW_RD_UBOUND23}, + {PXP2_REG_RQ_BW_RD_L24, PXP2_REG_RQ_BW_RD_ADD24, + PXP2_REG_RQ_BW_RD_UBOUND24}, + {PXP2_REG_RQ_BW_RD_L25, PXP2_REG_RQ_BW_RD_ADD25, + PXP2_REG_RQ_BW_RD_UBOUND25}, + {PXP2_REG_RQ_BW_RD_L26, PXP2_REG_RQ_BW_RD_ADD26, + PXP2_REG_RQ_BW_RD_UBOUND26}, + {PXP2_REG_RQ_BW_RD_L27, PXP2_REG_RQ_BW_RD_ADD27, + PXP2_REG_RQ_BW_RD_UBOUND27}, + {PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, + PXP2_REG_PSWRQ_BW_UB28} +}; + +/* register addresses for write queues */ +static const struct arb_line write_arb_addr[NUM_WR_Q-1] = { +/* 1 */ {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, + PXP2_REG_PSWRQ_BW_UB1}, + {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, + PXP2_REG_PSWRQ_BW_UB2}, + {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, + PXP2_REG_PSWRQ_BW_UB3}, + {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, + PXP2_REG_PSWRQ_BW_UB6}, + {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, + PXP2_REG_PSWRQ_BW_UB7}, + {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, + PXP2_REG_PSWRQ_BW_UB8}, + {PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, + PXP2_REG_PSWRQ_BW_UB9}, + {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, + PXP2_REG_PSWRQ_BW_UB10}, + {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, + PXP2_REG_PSWRQ_BW_UB11}, +/* 10 */{PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, + PXP2_REG_PSWRQ_BW_UB28}, + {PXP2_REG_RQ_BW_WR_L29, PXP2_REG_RQ_BW_WR_ADD29, + PXP2_REG_RQ_BW_WR_UBOUND29}, + {PXP2_REG_RQ_BW_WR_L30, PXP2_REG_RQ_BW_WR_ADD30, + PXP2_REG_RQ_BW_WR_UBOUND30} +}; + +static void bnx2x_init_pxp_arb(struct bnx2x *bp, int r_order, int w_order) { - u16 devctl; - int r_order, w_order; u32 val, i; - pci_read_config_word(bp->pdev, - bp->pcie_cap + PCI_EXP_DEVCTL, &devctl); - DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl); - w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); - if (bp->mrrs == -1) - r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12); - else { - DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs); - r_order = bp->mrrs; - } - if (r_order > MAX_RD_ORD) { DP(NETIF_MSG_HW, "read order of %d order adjusted to %d\n", r_order, MAX_RD_ORD); @@ -367,6 +478,11 @@ static void bnx2x_init_pxp(struct bnx2x *bp) REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x18 << w_order)); if (CHIP_IS_E1H(bp)) { + /* MPS w_order optimal TH presently TH + * 128 0 0 2 + * 256 1 1 3 + * >=512 2 2 3 + */ val = ((w_order == 0) ? 2 : 3); REG_WR(bp, PXP2_REG_WR_HC_MPS, val); REG_WR(bp, PXP2_REG_WR_USDM_MPS, val); @@ -382,61 +498,4 @@ static void bnx2x_init_pxp(struct bnx2x *bp) } } -/***************************************************************************** - * Description: - * Calculates crc 8 on a word value: polynomial 0-1-2-8 - * Code was translated from Verilog. - ****************************************************************************/ -static u8 calc_crc8(u32 data, u8 crc) -{ - u8 D[32]; - u8 NewCRC[8]; - u8 C[8]; - u8 crc_res; - u8 i; - - /* split the data into 31 bits */ - for (i = 0; i < 32; i++) { - D[i] = data & 1; - data = data >> 1; - } - - /* split the crc into 8 bits */ - for (i = 0; i < 8; i++) { - C[i] = crc & 1; - crc = crc >> 1; - } - - NewCRC[0] = D[31] ^ D[30] ^ D[28] ^ D[23] ^ D[21] ^ D[19] ^ D[18] ^ - D[16] ^ D[14] ^ D[12] ^ D[8] ^ D[7] ^ D[6] ^ D[0] ^ C[4] ^ - C[6] ^ C[7]; - NewCRC[1] = D[30] ^ D[29] ^ D[28] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^ - D[20] ^ D[18] ^ D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[13] ^ - D[12] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[4] ^ C[5] ^ C[6]; - NewCRC[2] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[22] ^ D[17] ^ D[15] ^ - D[13] ^ D[12] ^ D[10] ^ D[8] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ - C[0] ^ C[1] ^ C[4] ^ C[5]; - NewCRC[3] = D[30] ^ D[29] ^ D[26] ^ D[25] ^ D[23] ^ D[18] ^ D[16] ^ - D[14] ^ D[13] ^ D[11] ^ D[9] ^ D[7] ^ D[3] ^ D[2] ^ D[1] ^ - C[1] ^ C[2] ^ C[5] ^ C[6]; - NewCRC[4] = D[31] ^ D[30] ^ D[27] ^ D[26] ^ D[24] ^ D[19] ^ D[17] ^ - D[15] ^ D[14] ^ D[12] ^ D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[2] ^ - C[0] ^ C[2] ^ C[3] ^ C[6] ^ C[7]; - NewCRC[5] = D[31] ^ D[28] ^ D[27] ^ D[25] ^ D[20] ^ D[18] ^ D[16] ^ - D[15] ^ D[13] ^ D[11] ^ D[9] ^ D[5] ^ D[4] ^ D[3] ^ C[1] ^ - C[3] ^ C[4] ^ C[7]; - NewCRC[6] = D[29] ^ D[28] ^ D[26] ^ D[21] ^ D[19] ^ D[17] ^ D[16] ^ - D[14] ^ D[12] ^ D[10] ^ D[6] ^ D[5] ^ D[4] ^ C[2] ^ C[4] ^ - C[5]; - NewCRC[7] = D[30] ^ D[29] ^ D[27] ^ D[22] ^ D[20] ^ D[18] ^ D[17] ^ - D[15] ^ D[13] ^ D[11] ^ D[7] ^ D[6] ^ D[5] ^ C[3] ^ C[5] ^ - C[6]; - - crc_res = 0; - for (i = 0; i < 8; i++) - crc_res |= (NewCRC[i] << i); - - return crc_res; -} - #endif /* BNX2X_INIT_OPS_H */ diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index b084e8b..8b6bb99 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -153,7 +153,7 @@ MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl); /* used only at init * locking is done by mcp */ -static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val) +void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val) { pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr); pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val); @@ -346,6 +346,21 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) mutex_unlock(&bp->dmae_mutex); } +void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr, + u32 addr, u32 len) +{ + int offset = 0; + + while (len > DMAE_LEN32_WR_MAX) { + bnx2x_write_dmae(bp, phys_addr + offset, + addr + offset, DMAE_LEN32_WR_MAX); + offset += DMAE_LEN32_WR_MAX * 4; + len -= DMAE_LEN32_WR_MAX; + } + + bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len); +} + /* used only for slowpath so not inlined */ static void bnx2x_wb_wr(struct bnx2x *bp, int reg, u32 val_hi, u32 val_lo) { @@ -5917,6 +5932,24 @@ static void bnx2x_reset_common(struct bnx2x *bp) REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403); } +static void bnx2x_init_pxp(struct bnx2x *bp) +{ + u16 devctl; + int r_order, w_order; + + pci_read_config_word(bp->pdev, + bp->pcie_cap + PCI_EXP_DEVCTL, &devctl); + DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl); + w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); + if (bp->mrrs == -1) + r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12); + else { + DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs); + r_order = bp->mrrs; + } + + bnx2x_init_pxp_arb(bp, r_order, w_order); +} static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp) { @@ -6479,9 +6512,15 @@ static int bnx2x_init_func(struct bnx2x *bp) if (CHIP_IS_E1H(bp)) { - for (i = 0; i < 9; i++) - bnx2x_init_block(bp, - cm_blocks[i], FUNC0_STAGE + func); + bnx2x_init_block(bp, MISC_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, TCM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, UCM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, CCM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, XCM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, TSEM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, USEM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, CSEM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, XSEM_BLOCK, FUNC0_STAGE + func); REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1); REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->e1hov); @@ -11834,22 +11873,22 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev) BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err, be16_to_cpu_n); /* STORMs firmware */ - bp->tsem_int_table_data = bp->firmware->data + - be32_to_cpu(fw_hdr->tsem_int_table_data.offset); - bp->tsem_pram_data = bp->firmware->data + - be32_to_cpu(fw_hdr->tsem_pram_data.offset); - bp->usem_int_table_data = bp->firmware->data + - be32_to_cpu(fw_hdr->usem_int_table_data.offset); - bp->usem_pram_data = bp->firmware->data + - be32_to_cpu(fw_hdr->usem_pram_data.offset); - bp->xsem_int_table_data = bp->firmware->data + - be32_to_cpu(fw_hdr->xsem_int_table_data.offset); - bp->xsem_pram_data = bp->firmware->data + - be32_to_cpu(fw_hdr->xsem_pram_data.offset); - bp->csem_int_table_data = bp->firmware->data + - be32_to_cpu(fw_hdr->csem_int_table_data.offset); - bp->csem_pram_data = bp->firmware->data + - be32_to_cpu(fw_hdr->csem_pram_data.offset); + INIT_TSEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->tsem_int_table_data.offset); + INIT_TSEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->tsem_pram_data.offset); + INIT_USEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->usem_int_table_data.offset); + INIT_USEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->usem_pram_data.offset); + INIT_XSEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->xsem_int_table_data.offset); + INIT_XSEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->xsem_pram_data.offset); + INIT_CSEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->csem_int_table_data.offset); + INIT_CSEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->csem_pram_data.offset); return 0; init_offsets_alloc_err: diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 9998386..1e6f5aa 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -6019,3 +6019,116 @@ Theotherbitsarereservedandshouldbezero*/ #define COMMAND_REG_SIMD_NOMASK 0x1c +#define IGU_MEM_BASE 0x0000 + +#define IGU_MEM_MSIX_BASE 0x0000 +#define IGU_MEM_MSIX_UPPER 0x007f +#define IGU_MEM_MSIX_RESERVED_UPPER 0x01ff + +#define IGU_MEM_PBA_MSIX_BASE 0x0200 +#define IGU_MEM_PBA_MSIX_UPPER 0x0200 + +#define IGU_CMD_BACKWARD_COMP_PROD_UPD 0x0201 +#define IGU_MEM_PBA_MSIX_RESERVED_UPPER 0x03ff + +#define IGU_CMD_INT_ACK_BASE 0x0400 +#define IGU_CMD_INT_ACK_UPPER\ + (IGU_CMD_INT_ACK_BASE + MAX_SB_PER_PORT * NUM_OF_PORTS_PER_PATH - 1) +#define IGU_CMD_INT_ACK_RESERVED_UPPER 0x04ff + +#define IGU_CMD_E2_PROD_UPD_BASE 0x0500 +#define IGU_CMD_E2_PROD_UPD_UPPER\ + (IGU_CMD_E2_PROD_UPD_BASE + MAX_SB_PER_PORT * NUM_OF_PORTS_PER_PATH - 1) +#define IGU_CMD_E2_PROD_UPD_RESERVED_UPPER 0x059f + +#define IGU_CMD_ATTN_BIT_UPD_UPPER 0x05a0 +#define IGU_CMD_ATTN_BIT_SET_UPPER 0x05a1 +#define IGU_CMD_ATTN_BIT_CLR_UPPER 0x05a2 + +#define IGU_REG_SISR_MDPC_WMASK_UPPER 0x05a3 +#define IGU_REG_SISR_MDPC_WMASK_LSB_UPPER 0x05a4 +#define IGU_REG_SISR_MDPC_WMASK_MSB_UPPER 0x05a5 +#define IGU_REG_SISR_MDPC_WOMASK_UPPER 0x05a6 + +#define IGU_REG_RESERVED_UPPER 0x05ff + + +#define CDU_REGION_NUMBER_XCM_AG 2 +#define CDU_REGION_NUMBER_UCM_AG 4 + + +/** + * String-to-compress [31:8] = CID (all 24 bits) + * String-to-compress [7:4] = Region + * String-to-compress [3:0] = Type + */ +#define CDU_VALID_DATA(_cid, _region, _type)\ + (((_cid) << 8) | (((_region)&0xf)<<4) | (((_type)&0xf))) +#define CDU_CRC8(_cid, _region, _type)\ + (calc_crc8(CDU_VALID_DATA(_cid, _region, _type), 0xff)) +#define CDU_RSRVD_VALUE_TYPE_A(_cid, _region, _type)\ + (0x80 | ((CDU_CRC8(_cid, _region, _type)) & 0x7f)) +#define CDU_RSRVD_VALUE_TYPE_B(_crc, _type)\ + (0x80 | ((_type)&0xf << 3) | ((CDU_CRC8(_cid, _region, _type)) & 0x7)) +#define CDU_RSRVD_INVALIDATE_CONTEXT_VALUE(_val) ((_val) & ~0x80) + +/****************************************************************************** + * Description: + * Calculates crc 8 on a word value: polynomial 0-1-2-8 + * Code was translated from Verilog. + * Return: + *****************************************************************************/ +static inline u8 calc_crc8(u32 data, u8 crc) +{ + u8 D[32]; + u8 NewCRC[8]; + u8 C[8]; + u8 crc_res; + u8 i; + + /* split the data into 31 bits */ + for (i = 0; i < 32; i++) { + D[i] = (u8)(data & 1); + data = data >> 1; + } + + /* split the crc into 8 bits */ + for (i = 0; i < 8; i++) { + C[i] = crc & 1; + crc = crc >> 1; + } + + NewCRC[0] = D[31] ^ D[30] ^ D[28] ^ D[23] ^ D[21] ^ D[19] ^ D[18] ^ + D[16] ^ D[14] ^ D[12] ^ D[8] ^ D[7] ^ D[6] ^ D[0] ^ C[4] ^ + C[6] ^ C[7]; + NewCRC[1] = D[30] ^ D[29] ^ D[28] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^ + D[20] ^ D[18] ^ D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[13] ^ + D[12] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[4] ^ C[5] ^ + C[6]; + NewCRC[2] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[22] ^ D[17] ^ D[15] ^ + D[13] ^ D[12] ^ D[10] ^ D[8] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ + C[0] ^ C[1] ^ C[4] ^ C[5]; + NewCRC[3] = D[30] ^ D[29] ^ D[26] ^ D[25] ^ D[23] ^ D[18] ^ D[16] ^ + D[14] ^ D[13] ^ D[11] ^ D[9] ^ D[7] ^ D[3] ^ D[2] ^ D[1] ^ + C[1] ^ C[2] ^ C[5] ^ C[6]; + NewCRC[4] = D[31] ^ D[30] ^ D[27] ^ D[26] ^ D[24] ^ D[19] ^ D[17] ^ + D[15] ^ D[14] ^ D[12] ^ D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[2] ^ + C[0] ^ C[2] ^ C[3] ^ C[6] ^ C[7]; + NewCRC[5] = D[31] ^ D[28] ^ D[27] ^ D[25] ^ D[20] ^ D[18] ^ D[16] ^ + D[15] ^ D[13] ^ D[11] ^ D[9] ^ D[5] ^ D[4] ^ D[3] ^ C[1] ^ + C[3] ^ C[4] ^ C[7]; + NewCRC[6] = D[29] ^ D[28] ^ D[26] ^ D[21] ^ D[19] ^ D[17] ^ D[16] ^ + D[14] ^ D[12] ^ D[10] ^ D[6] ^ D[5] ^ D[4] ^ C[2] ^ C[4] ^ + C[5]; + NewCRC[7] = D[30] ^ D[29] ^ D[27] ^ D[22] ^ D[20] ^ D[18] ^ D[17] ^ + D[15] ^ D[13] ^ D[11] ^ D[7] ^ D[6] ^ D[5] ^ C[3] ^ C[5] ^ + C[6]; + + crc_res = 0; + for (i = 0; i < 8; i++) + crc_res |= (NewCRC[i] << i); + + return crc_res; +} + + -- cgit v0.10.2 From 45a4864d80264f6708528dcaa2c5c0b3933a8d7f Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:18 +0000 Subject: bnx2x: Beautify bnx2x_dump.h Signed-off-by: Yitchak Gertner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_dump.h b/drivers/net/bnx2x_dump.h index 78c6b03..3bb9a91 100644 --- a/drivers/net/bnx2x_dump.h +++ b/drivers/net/bnx2x_dump.h @@ -13,31 +13,35 @@ * The signature is time stamp, diag version and grc_dump version */ +#ifndef BNX2X_DUMP_H +#define BNX2X_DUMP_H + + struct dump_sign { u32 time_stamp; u32 diag_ver; u32 grc_dump_ver; }; -#define TSTORM_WAITP_ADDR 0x1b8a80 -#define CSTORM_WAITP_ADDR 0x238a80 -#define XSTORM_WAITP_ADDR 0x2b8a80 -#define USTORM_WAITP_ADDR 0x338a80 -#define TSTORM_CAM_MODE 0x1b1440 +#define TSTORM_WAITP_ADDR 0x1b8a80 +#define CSTORM_WAITP_ADDR 0x238a80 +#define XSTORM_WAITP_ADDR 0x2b8a80 +#define USTORM_WAITP_ADDR 0x338a80 +#define TSTORM_CAM_MODE 0x1b1440 -#define RI_E1 0x1 -#define RI_E1H 0x2 -#define RI_ONLINE 0x100 +#define RI_E1 0x1 +#define RI_E1H 0x2 +#define RI_ONLINE 0x100 -#define RI_E1_OFFLINE (RI_E1) -#define RI_E1_ONLINE (RI_E1 | RI_ONLINE) -#define RI_E1H_OFFLINE (RI_E1H) -#define RI_E1H_ONLINE (RI_E1H | RI_ONLINE) -#define RI_ALL_OFFLINE (RI_E1 | RI_E1H) -#define RI_ALL_ONLINE (RI_E1 | RI_E1H | RI_ONLINE) +#define RI_E1_OFFLINE (RI_E1) +#define RI_E1_ONLINE (RI_E1 | RI_ONLINE) +#define RI_E1H_OFFLINE (RI_E1H) +#define RI_E1H_ONLINE (RI_E1H | RI_ONLINE) +#define RI_ALL_OFFLINE (RI_E1 | RI_E1H) +#define RI_ALL_ONLINE (RI_E1 | RI_E1H | RI_ONLINE) -#define MAX_TIMER_PENDING 200 -#define TIMER_SCAN_DONT_CARE 0xFF +#define MAX_TIMER_PENDING 200 +#define TIMER_SCAN_DONT_CARE 0xFF struct dump_hdr { @@ -67,443 +71,444 @@ struct wreg_addr { }; -#define REGS_COUNT 558 +#define REGS_COUNT 558 static const struct reg_addr reg_addrs[REGS_COUNT] = { - { 0x2000, 341, RI_ALL_ONLINE}, { 0x2800, 103, RI_ALL_ONLINE}, - { 0x3000, 287, RI_ALL_ONLINE}, { 0x3800, 331, RI_ALL_ONLINE}, - { 0x8800, 6, RI_E1_ONLINE}, { 0xa000, 223, RI_ALL_ONLINE}, - { 0xa388, 1, RI_ALL_ONLINE}, { 0xa398, 1, RI_ALL_ONLINE}, - { 0xa39c, 7, RI_E1H_ONLINE}, { 0xa3c0, 3, RI_E1H_ONLINE}, - { 0xa3d0, 1, RI_E1H_ONLINE}, { 0xa3d8, 1, RI_E1H_ONLINE}, - { 0xa3e0, 1, RI_E1H_ONLINE}, { 0xa3e8, 1, RI_E1H_ONLINE}, - { 0xa3f0, 1, RI_E1H_ONLINE}, { 0xa3f8, 1, RI_E1H_ONLINE}, - { 0xa400, 69, RI_ALL_ONLINE}, { 0xa518, 1, RI_ALL_ONLINE}, - { 0xa520, 1, RI_ALL_ONLINE}, { 0xa528, 1, RI_ALL_ONLINE}, - { 0xa530, 1, RI_ALL_ONLINE}, { 0xa538, 1, RI_ALL_ONLINE}, - { 0xa540, 1, RI_ALL_ONLINE}, { 0xa548, 1, RI_ALL_ONLINE}, - { 0xa550, 1, RI_ALL_ONLINE}, { 0xa558, 1, RI_ALL_ONLINE}, - { 0xa560, 1, RI_ALL_ONLINE}, { 0xa568, 1, RI_ALL_ONLINE}, - { 0xa570, 1, RI_ALL_ONLINE}, { 0xa580, 1, RI_ALL_ONLINE}, - { 0xa590, 1, RI_ALL_ONLINE}, { 0xa5a0, 1, RI_ALL_ONLINE}, - { 0xa5c0, 1, RI_ALL_ONLINE}, { 0xa5e0, 1, RI_E1H_ONLINE}, - { 0xa5e8, 1, RI_E1H_ONLINE}, { 0xa5f0, 1, RI_E1H_ONLINE}, - { 0xa5f8, 10, RI_E1H_ONLINE}, { 0x10000, 236, RI_ALL_ONLINE}, - { 0x103bc, 1, RI_ALL_ONLINE}, { 0x103cc, 1, RI_ALL_ONLINE}, - { 0x103dc, 1, RI_ALL_ONLINE}, { 0x10400, 57, RI_ALL_ONLINE}, - { 0x104e8, 2, RI_ALL_ONLINE}, { 0x104f4, 2, RI_ALL_ONLINE}, - { 0x10500, 146, RI_ALL_ONLINE}, { 0x10750, 2, RI_ALL_ONLINE}, - { 0x10760, 2, RI_ALL_ONLINE}, { 0x10770, 2, RI_ALL_ONLINE}, - { 0x10780, 2, RI_ALL_ONLINE}, { 0x10790, 2, RI_ALL_ONLINE}, - { 0x107a0, 2, RI_ALL_ONLINE}, { 0x107b0, 2, RI_ALL_ONLINE}, - { 0x107c0, 2, RI_ALL_ONLINE}, { 0x107d0, 2, RI_ALL_ONLINE}, - { 0x107e0, 2, RI_ALL_ONLINE}, { 0x10880, 2, RI_ALL_ONLINE}, - { 0x10900, 2, RI_ALL_ONLINE}, { 0x12000, 1, RI_ALL_ONLINE}, - { 0x14000, 1, RI_ALL_ONLINE}, { 0x16000, 26, RI_E1H_ONLINE}, - { 0x16070, 18, RI_E1H_ONLINE}, { 0x160c0, 27, RI_E1H_ONLINE}, - { 0x16140, 1, RI_E1H_ONLINE}, { 0x16160, 1, RI_E1H_ONLINE}, - { 0x16180, 2, RI_E1H_ONLINE}, { 0x161c0, 2, RI_E1H_ONLINE}, - { 0x16204, 5, RI_E1H_ONLINE}, { 0x18000, 1, RI_E1H_ONLINE}, - { 0x18008, 1, RI_E1H_ONLINE}, { 0x20000, 24, RI_ALL_ONLINE}, - { 0x20060, 8, RI_ALL_ONLINE}, { 0x20080, 138, RI_ALL_ONLINE}, - { 0x202b4, 1, RI_ALL_ONLINE}, { 0x202c4, 1, RI_ALL_ONLINE}, - { 0x20400, 2, RI_ALL_ONLINE}, { 0x2040c, 8, RI_ALL_ONLINE}, - { 0x2042c, 18, RI_E1H_ONLINE}, { 0x20480, 1, RI_ALL_ONLINE}, - { 0x20500, 1, RI_ALL_ONLINE}, { 0x20600, 1, RI_ALL_ONLINE}, - { 0x28000, 1, RI_ALL_ONLINE}, { 0x28004, 8191, RI_ALL_OFFLINE}, - { 0x30000, 1, RI_ALL_ONLINE}, { 0x30004, 16383, RI_ALL_OFFLINE}, - { 0x40000, 98, RI_ALL_ONLINE}, { 0x40194, 1, RI_ALL_ONLINE}, - { 0x401a4, 1, RI_ALL_ONLINE}, { 0x401a8, 11, RI_E1H_ONLINE}, - { 0x40200, 4, RI_ALL_ONLINE}, { 0x40400, 43, RI_ALL_ONLINE}, - { 0x404b8, 1, RI_ALL_ONLINE}, { 0x404c8, 1, RI_ALL_ONLINE}, - { 0x404cc, 3, RI_E1H_ONLINE}, { 0x40500, 2, RI_ALL_ONLINE}, - { 0x40510, 2, RI_ALL_ONLINE}, { 0x40520, 2, RI_ALL_ONLINE}, - { 0x40530, 2, RI_ALL_ONLINE}, { 0x40540, 2, RI_ALL_ONLINE}, - { 0x42000, 164, RI_ALL_ONLINE}, { 0x4229c, 1, RI_ALL_ONLINE}, - { 0x422ac, 1, RI_ALL_ONLINE}, { 0x422bc, 1, RI_ALL_ONLINE}, - { 0x422d4, 5, RI_E1H_ONLINE}, { 0x42400, 49, RI_ALL_ONLINE}, - { 0x424c8, 38, RI_ALL_ONLINE}, { 0x42568, 2, RI_ALL_ONLINE}, - { 0x42800, 1, RI_ALL_ONLINE}, { 0x50000, 20, RI_ALL_ONLINE}, - { 0x50050, 8, RI_ALL_ONLINE}, { 0x50070, 88, RI_ALL_ONLINE}, - { 0x501dc, 1, RI_ALL_ONLINE}, { 0x501ec, 1, RI_ALL_ONLINE}, - { 0x501f0, 4, RI_E1H_ONLINE}, { 0x50200, 2, RI_ALL_ONLINE}, - { 0x5020c, 7, RI_ALL_ONLINE}, { 0x50228, 6, RI_E1H_ONLINE}, - { 0x50240, 1, RI_ALL_ONLINE}, { 0x50280, 1, RI_ALL_ONLINE}, - { 0x52000, 1, RI_ALL_ONLINE}, { 0x54000, 1, RI_ALL_ONLINE}, - { 0x54004, 3327, RI_ALL_OFFLINE}, { 0x58000, 1, RI_ALL_ONLINE}, - { 0x58004, 8191, RI_ALL_OFFLINE}, { 0x60000, 71, RI_ALL_ONLINE}, - { 0x60128, 1, RI_ALL_ONLINE}, { 0x60138, 1, RI_ALL_ONLINE}, - { 0x6013c, 24, RI_E1H_ONLINE}, { 0x60200, 1, RI_ALL_ONLINE}, - { 0x61000, 1, RI_ALL_ONLINE}, { 0x61004, 511, RI_ALL_OFFLINE}, - { 0x70000, 8, RI_ALL_ONLINE}, { 0x70020, 21496, RI_ALL_OFFLINE}, - { 0x85000, 3, RI_ALL_ONLINE}, { 0x8500c, 4, RI_ALL_OFFLINE}, - { 0x8501c, 7, RI_ALL_ONLINE}, { 0x85038, 4, RI_ALL_OFFLINE}, - { 0x85048, 1, RI_ALL_ONLINE}, { 0x8504c, 109, RI_ALL_OFFLINE}, - { 0x85200, 32, RI_ALL_ONLINE}, { 0x85280, 11104, RI_ALL_OFFLINE}, - { 0xa0000, 16384, RI_ALL_ONLINE}, { 0xb0000, 16384, RI_E1H_ONLINE}, - { 0xc1000, 7, RI_ALL_ONLINE}, { 0xc1028, 1, RI_ALL_ONLINE}, - { 0xc1038, 1, RI_ALL_ONLINE}, { 0xc1800, 2, RI_ALL_ONLINE}, - { 0xc2000, 164, RI_ALL_ONLINE}, { 0xc229c, 1, RI_ALL_ONLINE}, - { 0xc22ac, 1, RI_ALL_ONLINE}, { 0xc22bc, 1, RI_ALL_ONLINE}, - { 0xc2400, 49, RI_ALL_ONLINE}, { 0xc24c8, 38, RI_ALL_ONLINE}, - { 0xc2568, 2, RI_ALL_ONLINE}, { 0xc2600, 1, RI_ALL_ONLINE}, - { 0xc4000, 165, RI_ALL_ONLINE}, { 0xc42a0, 1, RI_ALL_ONLINE}, - { 0xc42b0, 1, RI_ALL_ONLINE}, { 0xc42c0, 1, RI_ALL_ONLINE}, - { 0xc42e0, 7, RI_E1H_ONLINE}, { 0xc4400, 51, RI_ALL_ONLINE}, - { 0xc44d0, 38, RI_ALL_ONLINE}, { 0xc4570, 2, RI_ALL_ONLINE}, - { 0xc4600, 1, RI_ALL_ONLINE}, { 0xd0000, 19, RI_ALL_ONLINE}, - { 0xd004c, 8, RI_ALL_ONLINE}, { 0xd006c, 91, RI_ALL_ONLINE}, - { 0xd01e4, 1, RI_ALL_ONLINE}, { 0xd01f4, 1, RI_ALL_ONLINE}, - { 0xd0200, 2, RI_ALL_ONLINE}, { 0xd020c, 7, RI_ALL_ONLINE}, - { 0xd0228, 18, RI_E1H_ONLINE}, { 0xd0280, 1, RI_ALL_ONLINE}, - { 0xd0300, 1, RI_ALL_ONLINE}, { 0xd0400, 1, RI_ALL_ONLINE}, - { 0xd4000, 1, RI_ALL_ONLINE}, { 0xd4004, 2559, RI_ALL_OFFLINE}, - { 0xd8000, 1, RI_ALL_ONLINE}, { 0xd8004, 8191, RI_ALL_OFFLINE}, - { 0xe0000, 21, RI_ALL_ONLINE}, { 0xe0054, 8, RI_ALL_ONLINE}, - { 0xe0074, 85, RI_ALL_ONLINE}, { 0xe01d4, 1, RI_ALL_ONLINE}, - { 0xe01e4, 1, RI_ALL_ONLINE}, { 0xe0200, 2, RI_ALL_ONLINE}, - { 0xe020c, 8, RI_ALL_ONLINE}, { 0xe022c, 18, RI_E1H_ONLINE}, - { 0xe0280, 1, RI_ALL_ONLINE}, { 0xe0300, 1, RI_ALL_ONLINE}, - { 0xe1000, 1, RI_ALL_ONLINE}, { 0xe2000, 1, RI_ALL_ONLINE}, - { 0xe2004, 2047, RI_ALL_OFFLINE}, { 0xf0000, 1, RI_ALL_ONLINE}, - { 0xf0004, 16383, RI_ALL_OFFLINE}, { 0x101000, 12, RI_ALL_ONLINE}, - { 0x10103c, 1, RI_ALL_ONLINE}, { 0x10104c, 1, RI_ALL_ONLINE}, - { 0x101050, 1, RI_E1H_ONLINE}, { 0x101100, 1, RI_ALL_ONLINE}, - { 0x101800, 8, RI_ALL_ONLINE}, { 0x102000, 18, RI_ALL_ONLINE}, - { 0x102054, 1, RI_ALL_ONLINE}, { 0x102064, 1, RI_ALL_ONLINE}, - { 0x102080, 17, RI_ALL_ONLINE}, { 0x1020c8, 8, RI_E1H_ONLINE}, - { 0x102400, 1, RI_ALL_ONLINE}, { 0x103000, 26, RI_ALL_ONLINE}, - { 0x103074, 1, RI_ALL_ONLINE}, { 0x103084, 1, RI_ALL_ONLINE}, - { 0x103094, 1, RI_ALL_ONLINE}, { 0x103098, 5, RI_E1H_ONLINE}, - { 0x103800, 8, RI_ALL_ONLINE}, { 0x104000, 63, RI_ALL_ONLINE}, - { 0x104108, 1, RI_ALL_ONLINE}, { 0x104118, 1, RI_ALL_ONLINE}, - { 0x104200, 17, RI_ALL_ONLINE}, { 0x104400, 64, RI_ALL_ONLINE}, - { 0x104500, 192, RI_ALL_OFFLINE}, { 0x104800, 64, RI_ALL_ONLINE}, - { 0x104900, 192, RI_ALL_OFFLINE}, { 0x105000, 7, RI_ALL_ONLINE}, - { 0x10501c, 1, RI_ALL_OFFLINE}, { 0x105020, 3, RI_ALL_ONLINE}, - { 0x10502c, 1, RI_ALL_OFFLINE}, { 0x105030, 3, RI_ALL_ONLINE}, - { 0x10503c, 1, RI_ALL_OFFLINE}, { 0x105040, 3, RI_ALL_ONLINE}, - { 0x10504c, 1, RI_ALL_OFFLINE}, { 0x105050, 3, RI_ALL_ONLINE}, - { 0x10505c, 1, RI_ALL_OFFLINE}, { 0x105060, 3, RI_ALL_ONLINE}, - { 0x10506c, 1, RI_ALL_OFFLINE}, { 0x105070, 3, RI_ALL_ONLINE}, - { 0x10507c, 1, RI_ALL_OFFLINE}, { 0x105080, 3, RI_ALL_ONLINE}, - { 0x10508c, 1, RI_ALL_OFFLINE}, { 0x105090, 3, RI_ALL_ONLINE}, - { 0x10509c, 1, RI_ALL_OFFLINE}, { 0x1050a0, 3, RI_ALL_ONLINE}, - { 0x1050ac, 1, RI_ALL_OFFLINE}, { 0x1050b0, 3, RI_ALL_ONLINE}, - { 0x1050bc, 1, RI_ALL_OFFLINE}, { 0x1050c0, 3, RI_ALL_ONLINE}, - { 0x1050cc, 1, RI_ALL_OFFLINE}, { 0x1050d0, 3, RI_ALL_ONLINE}, - { 0x1050dc, 1, RI_ALL_OFFLINE}, { 0x1050e0, 3, RI_ALL_ONLINE}, - { 0x1050ec, 1, RI_ALL_OFFLINE}, { 0x1050f0, 3, RI_ALL_ONLINE}, - { 0x1050fc, 1, RI_ALL_OFFLINE}, { 0x105100, 3, RI_ALL_ONLINE}, - { 0x10510c, 1, RI_ALL_OFFLINE}, { 0x105110, 3, RI_ALL_ONLINE}, - { 0x10511c, 1, RI_ALL_OFFLINE}, { 0x105120, 3, RI_ALL_ONLINE}, - { 0x10512c, 1, RI_ALL_OFFLINE}, { 0x105130, 3, RI_ALL_ONLINE}, - { 0x10513c, 1, RI_ALL_OFFLINE}, { 0x105140, 3, RI_ALL_ONLINE}, - { 0x10514c, 1, RI_ALL_OFFLINE}, { 0x105150, 3, RI_ALL_ONLINE}, - { 0x10515c, 1, RI_ALL_OFFLINE}, { 0x105160, 3, RI_ALL_ONLINE}, - { 0x10516c, 1, RI_ALL_OFFLINE}, { 0x105170, 3, RI_ALL_ONLINE}, - { 0x10517c, 1, RI_ALL_OFFLINE}, { 0x105180, 3, RI_ALL_ONLINE}, - { 0x10518c, 1, RI_ALL_OFFLINE}, { 0x105190, 3, RI_ALL_ONLINE}, - { 0x10519c, 1, RI_ALL_OFFLINE}, { 0x1051a0, 3, RI_ALL_ONLINE}, - { 0x1051ac, 1, RI_ALL_OFFLINE}, { 0x1051b0, 3, RI_ALL_ONLINE}, - { 0x1051bc, 1, RI_ALL_OFFLINE}, { 0x1051c0, 3, RI_ALL_ONLINE}, - { 0x1051cc, 1, RI_ALL_OFFLINE}, { 0x1051d0, 3, RI_ALL_ONLINE}, - { 0x1051dc, 1, RI_ALL_OFFLINE}, { 0x1051e0, 3, RI_ALL_ONLINE}, - { 0x1051ec, 1, RI_ALL_OFFLINE}, { 0x1051f0, 3, RI_ALL_ONLINE}, - { 0x1051fc, 1, RI_ALL_OFFLINE}, { 0x105200, 3, RI_ALL_ONLINE}, - { 0x10520c, 1, RI_ALL_OFFLINE}, { 0x105210, 3, RI_ALL_ONLINE}, - { 0x10521c, 1, RI_ALL_OFFLINE}, { 0x105220, 3, RI_ALL_ONLINE}, - { 0x10522c, 1, RI_ALL_OFFLINE}, { 0x105230, 3, RI_ALL_ONLINE}, - { 0x10523c, 1, RI_ALL_OFFLINE}, { 0x105240, 3, RI_ALL_ONLINE}, - { 0x10524c, 1, RI_ALL_OFFLINE}, { 0x105250, 3, RI_ALL_ONLINE}, - { 0x10525c, 1, RI_ALL_OFFLINE}, { 0x105260, 3, RI_ALL_ONLINE}, - { 0x10526c, 1, RI_ALL_OFFLINE}, { 0x105270, 3, RI_ALL_ONLINE}, - { 0x10527c, 1, RI_ALL_OFFLINE}, { 0x105280, 3, RI_ALL_ONLINE}, - { 0x10528c, 1, RI_ALL_OFFLINE}, { 0x105290, 3, RI_ALL_ONLINE}, - { 0x10529c, 1, RI_ALL_OFFLINE}, { 0x1052a0, 3, RI_ALL_ONLINE}, - { 0x1052ac, 1, RI_ALL_OFFLINE}, { 0x1052b0, 3, RI_ALL_ONLINE}, - { 0x1052bc, 1, RI_ALL_OFFLINE}, { 0x1052c0, 3, RI_ALL_ONLINE}, - { 0x1052cc, 1, RI_ALL_OFFLINE}, { 0x1052d0, 3, RI_ALL_ONLINE}, - { 0x1052dc, 1, RI_ALL_OFFLINE}, { 0x1052e0, 3, RI_ALL_ONLINE}, - { 0x1052ec, 1, RI_ALL_OFFLINE}, { 0x1052f0, 3, RI_ALL_ONLINE}, - { 0x1052fc, 1, RI_ALL_OFFLINE}, { 0x105300, 3, RI_ALL_ONLINE}, - { 0x10530c, 1, RI_ALL_OFFLINE}, { 0x105310, 3, RI_ALL_ONLINE}, - { 0x10531c, 1, RI_ALL_OFFLINE}, { 0x105320, 3, RI_ALL_ONLINE}, - { 0x10532c, 1, RI_ALL_OFFLINE}, { 0x105330, 3, RI_ALL_ONLINE}, - { 0x10533c, 1, RI_ALL_OFFLINE}, { 0x105340, 3, RI_ALL_ONLINE}, - { 0x10534c, 1, RI_ALL_OFFLINE}, { 0x105350, 3, RI_ALL_ONLINE}, - { 0x10535c, 1, RI_ALL_OFFLINE}, { 0x105360, 3, RI_ALL_ONLINE}, - { 0x10536c, 1, RI_ALL_OFFLINE}, { 0x105370, 3, RI_ALL_ONLINE}, - { 0x10537c, 1, RI_ALL_OFFLINE}, { 0x105380, 3, RI_ALL_ONLINE}, - { 0x10538c, 1, RI_ALL_OFFLINE}, { 0x105390, 3, RI_ALL_ONLINE}, - { 0x10539c, 1, RI_ALL_OFFLINE}, { 0x1053a0, 3, RI_ALL_ONLINE}, - { 0x1053ac, 1, RI_ALL_OFFLINE}, { 0x1053b0, 3, RI_ALL_ONLINE}, - { 0x1053bc, 1, RI_ALL_OFFLINE}, { 0x1053c0, 3, RI_ALL_ONLINE}, - { 0x1053cc, 1, RI_ALL_OFFLINE}, { 0x1053d0, 3, RI_ALL_ONLINE}, - { 0x1053dc, 1, RI_ALL_OFFLINE}, { 0x1053e0, 3, RI_ALL_ONLINE}, - { 0x1053ec, 1, RI_ALL_OFFLINE}, { 0x1053f0, 3, RI_ALL_ONLINE}, - { 0x1053fc, 769, RI_ALL_OFFLINE}, { 0x108000, 33, RI_ALL_ONLINE}, - { 0x108090, 1, RI_ALL_ONLINE}, { 0x1080a0, 1, RI_ALL_ONLINE}, - { 0x1080ac, 5, RI_E1H_ONLINE}, { 0x108100, 5, RI_ALL_ONLINE}, - { 0x108120, 5, RI_ALL_ONLINE}, { 0x108200, 74, RI_ALL_ONLINE}, - { 0x108400, 74, RI_ALL_ONLINE}, { 0x108800, 152, RI_ALL_ONLINE}, - { 0x109000, 1, RI_ALL_ONLINE}, { 0x120000, 347, RI_ALL_ONLINE}, - { 0x120578, 1, RI_ALL_ONLINE}, { 0x120588, 1, RI_ALL_ONLINE}, - { 0x120598, 1, RI_ALL_ONLINE}, { 0x12059c, 23, RI_E1H_ONLINE}, - { 0x120614, 1, RI_E1H_ONLINE}, { 0x12061c, 30, RI_E1H_ONLINE}, - { 0x12080c, 65, RI_ALL_ONLINE}, { 0x120a00, 2, RI_ALL_ONLINE}, - { 0x122000, 2, RI_ALL_ONLINE}, { 0x128000, 2, RI_E1H_ONLINE}, - { 0x140000, 114, RI_ALL_ONLINE}, { 0x1401d4, 1, RI_ALL_ONLINE}, - { 0x1401e4, 1, RI_ALL_ONLINE}, { 0x140200, 6, RI_ALL_ONLINE}, - { 0x144000, 4, RI_ALL_ONLINE}, { 0x148000, 4, RI_ALL_ONLINE}, - { 0x14c000, 4, RI_ALL_ONLINE}, { 0x150000, 4, RI_ALL_ONLINE}, - { 0x154000, 4, RI_ALL_ONLINE}, { 0x158000, 4, RI_ALL_ONLINE}, - { 0x15c000, 7, RI_E1H_ONLINE}, { 0x161000, 7, RI_ALL_ONLINE}, - { 0x161028, 1, RI_ALL_ONLINE}, { 0x161038, 1, RI_ALL_ONLINE}, - { 0x161800, 2, RI_ALL_ONLINE}, { 0x164000, 60, RI_ALL_ONLINE}, - { 0x1640fc, 1, RI_ALL_ONLINE}, { 0x16410c, 1, RI_ALL_ONLINE}, - { 0x164110, 2, RI_E1H_ONLINE}, { 0x164200, 1, RI_ALL_ONLINE}, - { 0x164208, 1, RI_ALL_ONLINE}, { 0x164210, 1, RI_ALL_ONLINE}, - { 0x164218, 1, RI_ALL_ONLINE}, { 0x164220, 1, RI_ALL_ONLINE}, - { 0x164228, 1, RI_ALL_ONLINE}, { 0x164230, 1, RI_ALL_ONLINE}, - { 0x164238, 1, RI_ALL_ONLINE}, { 0x164240, 1, RI_ALL_ONLINE}, - { 0x164248, 1, RI_ALL_ONLINE}, { 0x164250, 1, RI_ALL_ONLINE}, - { 0x164258, 1, RI_ALL_ONLINE}, { 0x164260, 1, RI_ALL_ONLINE}, - { 0x164270, 2, RI_ALL_ONLINE}, { 0x164280, 2, RI_ALL_ONLINE}, - { 0x164800, 2, RI_ALL_ONLINE}, { 0x165000, 2, RI_ALL_ONLINE}, - { 0x166000, 164, RI_ALL_ONLINE}, { 0x16629c, 1, RI_ALL_ONLINE}, - { 0x1662ac, 1, RI_ALL_ONLINE}, { 0x1662bc, 1, RI_ALL_ONLINE}, - { 0x166400, 49, RI_ALL_ONLINE}, { 0x1664c8, 38, RI_ALL_ONLINE}, - { 0x166568, 2, RI_ALL_ONLINE}, { 0x166800, 1, RI_ALL_ONLINE}, - { 0x168000, 270, RI_ALL_ONLINE}, { 0x168444, 1, RI_ALL_ONLINE}, - { 0x168454, 1, RI_ALL_ONLINE}, { 0x168800, 19, RI_ALL_ONLINE}, - { 0x168900, 1, RI_ALL_ONLINE}, { 0x168a00, 128, RI_ALL_ONLINE}, - { 0x16a000, 1, RI_ALL_ONLINE}, { 0x16a004, 1535, RI_ALL_OFFLINE}, - { 0x16c000, 1, RI_ALL_ONLINE}, { 0x16c004, 1535, RI_ALL_OFFLINE}, - { 0x16e000, 16, RI_E1H_ONLINE}, { 0x16e100, 1, RI_E1H_ONLINE}, - { 0x16e200, 2, RI_E1H_ONLINE}, { 0x16e400, 183, RI_E1H_ONLINE}, - { 0x170000, 93, RI_ALL_ONLINE}, { 0x170180, 1, RI_ALL_ONLINE}, - { 0x170190, 1, RI_ALL_ONLINE}, { 0x170200, 4, RI_ALL_ONLINE}, - { 0x170214, 1, RI_ALL_ONLINE}, { 0x178000, 1, RI_ALL_ONLINE}, - { 0x180000, 61, RI_ALL_ONLINE}, { 0x180100, 1, RI_ALL_ONLINE}, - { 0x180110, 1, RI_ALL_ONLINE}, { 0x180120, 1, RI_ALL_ONLINE}, - { 0x180130, 1, RI_ALL_ONLINE}, { 0x18013c, 2, RI_E1H_ONLINE}, - { 0x180200, 58, RI_ALL_ONLINE}, { 0x180340, 4, RI_ALL_ONLINE}, - { 0x180400, 1, RI_ALL_ONLINE}, { 0x180404, 255, RI_ALL_OFFLINE}, - { 0x181000, 4, RI_ALL_ONLINE}, { 0x181010, 1020, RI_ALL_OFFLINE}, - { 0x1a0000, 1, RI_ALL_ONLINE}, { 0x1a0004, 1023, RI_ALL_OFFLINE}, - { 0x1a1000, 1, RI_ALL_ONLINE}, { 0x1a1004, 4607, RI_ALL_OFFLINE}, - { 0x1a5800, 2560, RI_E1H_OFFLINE}, { 0x1a8000, 64, RI_ALL_OFFLINE}, - { 0x1a8100, 1984, RI_E1H_OFFLINE}, { 0x1aa000, 1, RI_E1H_ONLINE}, - { 0x1aa004, 6655, RI_E1H_OFFLINE}, { 0x1b1800, 128, RI_ALL_OFFLINE}, - { 0x1b1c00, 128, RI_ALL_OFFLINE}, { 0x1b2000, 1, RI_ALL_OFFLINE}, - { 0x1b2400, 64, RI_E1H_OFFLINE}, { 0x1b8200, 1, RI_ALL_ONLINE}, - { 0x1b8240, 1, RI_ALL_ONLINE}, { 0x1b8280, 1, RI_ALL_ONLINE}, - { 0x1b82c0, 1, RI_ALL_ONLINE}, { 0x1b8a00, 1, RI_ALL_ONLINE}, - { 0x1b8a80, 1, RI_ALL_ONLINE}, { 0x1c0000, 2, RI_ALL_ONLINE}, - { 0x200000, 65, RI_ALL_ONLINE}, { 0x200110, 1, RI_ALL_ONLINE}, - { 0x200120, 1, RI_ALL_ONLINE}, { 0x200130, 1, RI_ALL_ONLINE}, - { 0x200140, 1, RI_ALL_ONLINE}, { 0x20014c, 2, RI_E1H_ONLINE}, - { 0x200200, 58, RI_ALL_ONLINE}, { 0x200340, 4, RI_ALL_ONLINE}, - { 0x200400, 1, RI_ALL_ONLINE}, { 0x200404, 255, RI_ALL_OFFLINE}, - { 0x202000, 4, RI_ALL_ONLINE}, { 0x202010, 2044, RI_ALL_OFFLINE}, - { 0x220000, 1, RI_ALL_ONLINE}, { 0x220004, 1023, RI_ALL_OFFLINE}, - { 0x221000, 1, RI_ALL_ONLINE}, { 0x221004, 4607, RI_ALL_OFFLINE}, - { 0x225800, 1536, RI_E1H_OFFLINE}, { 0x227000, 1, RI_E1H_ONLINE}, - { 0x227004, 1023, RI_E1H_OFFLINE}, { 0x228000, 64, RI_ALL_OFFLINE}, - { 0x228100, 8640, RI_E1H_OFFLINE}, { 0x231800, 128, RI_ALL_OFFLINE}, - { 0x231c00, 128, RI_ALL_OFFLINE}, { 0x232000, 1, RI_ALL_OFFLINE}, - { 0x232400, 64, RI_E1H_OFFLINE}, { 0x238200, 1, RI_ALL_ONLINE}, - { 0x238240, 1, RI_ALL_ONLINE}, { 0x238280, 1, RI_ALL_ONLINE}, - { 0x2382c0, 1, RI_ALL_ONLINE}, { 0x238a00, 1, RI_ALL_ONLINE}, - { 0x238a80, 1, RI_ALL_ONLINE}, { 0x240000, 2, RI_ALL_ONLINE}, - { 0x280000, 65, RI_ALL_ONLINE}, { 0x280110, 1, RI_ALL_ONLINE}, - { 0x280120, 1, RI_ALL_ONLINE}, { 0x280130, 1, RI_ALL_ONLINE}, - { 0x280140, 1, RI_ALL_ONLINE}, { 0x28014c, 2, RI_E1H_ONLINE}, - { 0x280200, 58, RI_ALL_ONLINE}, { 0x280340, 4, RI_ALL_ONLINE}, - { 0x280400, 1, RI_ALL_ONLINE}, { 0x280404, 255, RI_ALL_OFFLINE}, - { 0x282000, 4, RI_ALL_ONLINE}, { 0x282010, 2044, RI_ALL_OFFLINE}, - { 0x2a0000, 1, RI_ALL_ONLINE}, { 0x2a0004, 1023, RI_ALL_OFFLINE}, - { 0x2a1000, 1, RI_ALL_ONLINE}, { 0x2a1004, 4607, RI_ALL_OFFLINE}, - { 0x2a5800, 2560, RI_E1H_OFFLINE}, { 0x2a8000, 64, RI_ALL_OFFLINE}, - { 0x2a8100, 960, RI_E1H_OFFLINE}, { 0x2a9000, 1, RI_E1H_ONLINE}, - { 0x2a9004, 7679, RI_E1H_OFFLINE}, { 0x2b1800, 128, RI_ALL_OFFLINE}, - { 0x2b1c00, 128, RI_ALL_OFFLINE}, { 0x2b2000, 1, RI_ALL_OFFLINE}, - { 0x2b2400, 64, RI_E1H_OFFLINE}, { 0x2b8200, 1, RI_ALL_ONLINE}, - { 0x2b8240, 1, RI_ALL_ONLINE}, { 0x2b8280, 1, RI_ALL_ONLINE}, - { 0x2b82c0, 1, RI_ALL_ONLINE}, { 0x2b8a00, 1, RI_ALL_ONLINE}, - { 0x2b8a80, 1, RI_ALL_ONLINE}, { 0x2c0000, 2, RI_ALL_ONLINE}, - { 0x300000, 65, RI_ALL_ONLINE}, { 0x300110, 1, RI_ALL_ONLINE}, - { 0x300120, 1, RI_ALL_ONLINE}, { 0x300130, 1, RI_ALL_ONLINE}, - { 0x300140, 1, RI_ALL_ONLINE}, { 0x30014c, 2, RI_E1H_ONLINE}, - { 0x300200, 58, RI_ALL_ONLINE}, { 0x300340, 4, RI_ALL_ONLINE}, - { 0x300400, 1, RI_ALL_ONLINE}, { 0x300404, 255, RI_ALL_OFFLINE}, - { 0x302000, 4, RI_ALL_ONLINE}, { 0x302010, 2044, RI_ALL_OFFLINE}, - { 0x320000, 1, RI_ALL_ONLINE}, { 0x320004, 1023, RI_ALL_OFFLINE}, - { 0x321000, 1, RI_ALL_ONLINE}, { 0x321004, 4607, RI_ALL_OFFLINE}, - { 0x325800, 2560, RI_E1H_OFFLINE}, { 0x328000, 64, RI_ALL_OFFLINE}, - { 0x328100, 536, RI_E1H_OFFLINE}, { 0x328960, 1, RI_E1H_ONLINE}, - { 0x328964, 8103, RI_E1H_OFFLINE}, { 0x331800, 128, RI_ALL_OFFLINE}, - { 0x331c00, 128, RI_ALL_OFFLINE}, { 0x332000, 1, RI_ALL_OFFLINE}, - { 0x332400, 64, RI_E1H_OFFLINE}, { 0x338200, 1, RI_ALL_ONLINE}, - { 0x338240, 1, RI_ALL_ONLINE}, { 0x338280, 1, RI_ALL_ONLINE}, - { 0x3382c0, 1, RI_ALL_ONLINE}, { 0x338a00, 1, RI_ALL_ONLINE}, - { 0x338a80, 1, RI_ALL_ONLINE}, { 0x340000, 2, RI_ALL_ONLINE} + { 0x2000, 341, RI_ALL_ONLINE }, { 0x2800, 103, RI_ALL_ONLINE }, + { 0x3000, 287, RI_ALL_ONLINE }, { 0x3800, 331, RI_ALL_ONLINE }, + { 0x8800, 6, RI_E1_ONLINE }, { 0xa000, 223, RI_ALL_ONLINE }, + { 0xa388, 1, RI_ALL_ONLINE }, { 0xa398, 1, RI_ALL_ONLINE }, + { 0xa39c, 7, RI_E1H_ONLINE }, { 0xa3c0, 3, RI_E1H_ONLINE }, + { 0xa3d0, 1, RI_E1H_ONLINE }, { 0xa3d8, 1, RI_E1H_ONLINE }, + { 0xa3e0, 1, RI_E1H_ONLINE }, { 0xa3e8, 1, RI_E1H_ONLINE }, + { 0xa3f0, 1, RI_E1H_ONLINE }, { 0xa3f8, 1, RI_E1H_ONLINE }, + { 0xa400, 69, RI_ALL_ONLINE }, { 0xa518, 1, RI_ALL_ONLINE }, + { 0xa520, 1, RI_ALL_ONLINE }, { 0xa528, 1, RI_ALL_ONLINE }, + { 0xa530, 1, RI_ALL_ONLINE }, { 0xa538, 1, RI_ALL_ONLINE }, + { 0xa540, 1, RI_ALL_ONLINE }, { 0xa548, 1, RI_ALL_ONLINE }, + { 0xa550, 1, RI_ALL_ONLINE }, { 0xa558, 1, RI_ALL_ONLINE }, + { 0xa560, 1, RI_ALL_ONLINE }, { 0xa568, 1, RI_ALL_ONLINE }, + { 0xa570, 1, RI_ALL_ONLINE }, { 0xa580, 1, RI_ALL_ONLINE }, + { 0xa590, 1, RI_ALL_ONLINE }, { 0xa5a0, 1, RI_ALL_ONLINE }, + { 0xa5c0, 1, RI_ALL_ONLINE }, { 0xa5e0, 1, RI_E1H_ONLINE }, + { 0xa5e8, 1, RI_E1H_ONLINE }, { 0xa5f0, 1, RI_E1H_ONLINE }, + { 0xa5f8, 10, RI_E1H_ONLINE }, { 0x10000, 236, RI_ALL_ONLINE }, + { 0x103bc, 1, RI_ALL_ONLINE }, { 0x103cc, 1, RI_ALL_ONLINE }, + { 0x103dc, 1, RI_ALL_ONLINE }, { 0x10400, 57, RI_ALL_ONLINE }, + { 0x104e8, 2, RI_ALL_ONLINE }, { 0x104f4, 2, RI_ALL_ONLINE }, + { 0x10500, 146, RI_ALL_ONLINE }, { 0x10750, 2, RI_ALL_ONLINE }, + { 0x10760, 2, RI_ALL_ONLINE }, { 0x10770, 2, RI_ALL_ONLINE }, + { 0x10780, 2, RI_ALL_ONLINE }, { 0x10790, 2, RI_ALL_ONLINE }, + { 0x107a0, 2, RI_ALL_ONLINE }, { 0x107b0, 2, RI_ALL_ONLINE }, + { 0x107c0, 2, RI_ALL_ONLINE }, { 0x107d0, 2, RI_ALL_ONLINE }, + { 0x107e0, 2, RI_ALL_ONLINE }, { 0x10880, 2, RI_ALL_ONLINE }, + { 0x10900, 2, RI_ALL_ONLINE }, { 0x12000, 1, RI_ALL_ONLINE }, + { 0x14000, 1, RI_ALL_ONLINE }, { 0x16000, 26, RI_E1H_ONLINE }, + { 0x16070, 18, RI_E1H_ONLINE }, { 0x160c0, 27, RI_E1H_ONLINE }, + { 0x16140, 1, RI_E1H_ONLINE }, { 0x16160, 1, RI_E1H_ONLINE }, + { 0x16180, 2, RI_E1H_ONLINE }, { 0x161c0, 2, RI_E1H_ONLINE }, + { 0x16204, 5, RI_E1H_ONLINE }, { 0x18000, 1, RI_E1H_ONLINE }, + { 0x18008, 1, RI_E1H_ONLINE }, { 0x20000, 24, RI_ALL_ONLINE }, + { 0x20060, 8, RI_ALL_ONLINE }, { 0x20080, 138, RI_ALL_ONLINE }, + { 0x202b4, 1, RI_ALL_ONLINE }, { 0x202c4, 1, RI_ALL_ONLINE }, + { 0x20400, 2, RI_ALL_ONLINE }, { 0x2040c, 8, RI_ALL_ONLINE }, + { 0x2042c, 18, RI_E1H_ONLINE }, { 0x20480, 1, RI_ALL_ONLINE }, + { 0x20500, 1, RI_ALL_ONLINE }, { 0x20600, 1, RI_ALL_ONLINE }, + { 0x28000, 1, RI_ALL_ONLINE }, { 0x28004, 8191, RI_ALL_OFFLINE }, + { 0x30000, 1, RI_ALL_ONLINE }, { 0x30004, 16383, RI_ALL_OFFLINE }, + { 0x40000, 98, RI_ALL_ONLINE }, { 0x40194, 1, RI_ALL_ONLINE }, + { 0x401a4, 1, RI_ALL_ONLINE }, { 0x401a8, 11, RI_E1H_ONLINE }, + { 0x40200, 4, RI_ALL_ONLINE }, { 0x40400, 43, RI_ALL_ONLINE }, + { 0x404b8, 1, RI_ALL_ONLINE }, { 0x404c8, 1, RI_ALL_ONLINE }, + { 0x404cc, 3, RI_E1H_ONLINE }, { 0x40500, 2, RI_ALL_ONLINE }, + { 0x40510, 2, RI_ALL_ONLINE }, { 0x40520, 2, RI_ALL_ONLINE }, + { 0x40530, 2, RI_ALL_ONLINE }, { 0x40540, 2, RI_ALL_ONLINE }, + { 0x42000, 164, RI_ALL_ONLINE }, { 0x4229c, 1, RI_ALL_ONLINE }, + { 0x422ac, 1, RI_ALL_ONLINE }, { 0x422bc, 1, RI_ALL_ONLINE }, + { 0x422d4, 5, RI_E1H_ONLINE }, { 0x42400, 49, RI_ALL_ONLINE }, + { 0x424c8, 38, RI_ALL_ONLINE }, { 0x42568, 2, RI_ALL_ONLINE }, + { 0x42800, 1, RI_ALL_ONLINE }, { 0x50000, 20, RI_ALL_ONLINE }, + { 0x50050, 8, RI_ALL_ONLINE }, { 0x50070, 88, RI_ALL_ONLINE }, + { 0x501dc, 1, RI_ALL_ONLINE }, { 0x501ec, 1, RI_ALL_ONLINE }, + { 0x501f0, 4, RI_E1H_ONLINE }, { 0x50200, 2, RI_ALL_ONLINE }, + { 0x5020c, 7, RI_ALL_ONLINE }, { 0x50228, 6, RI_E1H_ONLINE }, + { 0x50240, 1, RI_ALL_ONLINE }, { 0x50280, 1, RI_ALL_ONLINE }, + { 0x52000, 1, RI_ALL_ONLINE }, { 0x54000, 1, RI_ALL_ONLINE }, + { 0x54004, 3327, RI_ALL_OFFLINE }, { 0x58000, 1, RI_ALL_ONLINE }, + { 0x58004, 8191, RI_ALL_OFFLINE }, { 0x60000, 71, RI_ALL_ONLINE }, + { 0x60128, 1, RI_ALL_ONLINE }, { 0x60138, 1, RI_ALL_ONLINE }, + { 0x6013c, 24, RI_E1H_ONLINE }, { 0x60200, 1, RI_ALL_ONLINE }, + { 0x61000, 1, RI_ALL_ONLINE }, { 0x61004, 511, RI_ALL_OFFLINE }, + { 0x70000, 8, RI_ALL_ONLINE }, { 0x70020, 21496, RI_ALL_OFFLINE }, + { 0x85000, 3, RI_ALL_ONLINE }, { 0x8500c, 4, RI_ALL_OFFLINE }, + { 0x8501c, 7, RI_ALL_ONLINE }, { 0x85038, 4, RI_ALL_OFFLINE }, + { 0x85048, 1, RI_ALL_ONLINE }, { 0x8504c, 109, RI_ALL_OFFLINE }, + { 0x85200, 32, RI_ALL_ONLINE }, { 0x85280, 11104, RI_ALL_OFFLINE }, + { 0xa0000, 16384, RI_ALL_ONLINE }, { 0xb0000, 16384, RI_E1H_ONLINE }, + { 0xc1000, 7, RI_ALL_ONLINE }, { 0xc1028, 1, RI_ALL_ONLINE }, + { 0xc1038, 1, RI_ALL_ONLINE }, { 0xc1800, 2, RI_ALL_ONLINE }, + { 0xc2000, 164, RI_ALL_ONLINE }, { 0xc229c, 1, RI_ALL_ONLINE }, + { 0xc22ac, 1, RI_ALL_ONLINE }, { 0xc22bc, 1, RI_ALL_ONLINE }, + { 0xc2400, 49, RI_ALL_ONLINE }, { 0xc24c8, 38, RI_ALL_ONLINE }, + { 0xc2568, 2, RI_ALL_ONLINE }, { 0xc2600, 1, RI_ALL_ONLINE }, + { 0xc4000, 165, RI_ALL_ONLINE }, { 0xc42a0, 1, RI_ALL_ONLINE }, + { 0xc42b0, 1, RI_ALL_ONLINE }, { 0xc42c0, 1, RI_ALL_ONLINE }, + { 0xc42e0, 7, RI_E1H_ONLINE }, { 0xc4400, 51, RI_ALL_ONLINE }, + { 0xc44d0, 38, RI_ALL_ONLINE }, { 0xc4570, 2, RI_ALL_ONLINE }, + { 0xc4600, 1, RI_ALL_ONLINE }, { 0xd0000, 19, RI_ALL_ONLINE }, + { 0xd004c, 8, RI_ALL_ONLINE }, { 0xd006c, 91, RI_ALL_ONLINE }, + { 0xd01e4, 1, RI_ALL_ONLINE }, { 0xd01f4, 1, RI_ALL_ONLINE }, + { 0xd0200, 2, RI_ALL_ONLINE }, { 0xd020c, 7, RI_ALL_ONLINE }, + { 0xd0228, 18, RI_E1H_ONLINE }, { 0xd0280, 1, RI_ALL_ONLINE }, + { 0xd0300, 1, RI_ALL_ONLINE }, { 0xd0400, 1, RI_ALL_ONLINE }, + { 0xd4000, 1, RI_ALL_ONLINE }, { 0xd4004, 2559, RI_ALL_OFFLINE }, + { 0xd8000, 1, RI_ALL_ONLINE }, { 0xd8004, 8191, RI_ALL_OFFLINE }, + { 0xe0000, 21, RI_ALL_ONLINE }, { 0xe0054, 8, RI_ALL_ONLINE }, + { 0xe0074, 85, RI_ALL_ONLINE }, { 0xe01d4, 1, RI_ALL_ONLINE }, + { 0xe01e4, 1, RI_ALL_ONLINE }, { 0xe0200, 2, RI_ALL_ONLINE }, + { 0xe020c, 8, RI_ALL_ONLINE }, { 0xe022c, 18, RI_E1H_ONLINE }, + { 0xe0280, 1, RI_ALL_ONLINE }, { 0xe0300, 1, RI_ALL_ONLINE }, + { 0xe1000, 1, RI_ALL_ONLINE }, { 0xe2000, 1, RI_ALL_ONLINE }, + { 0xe2004, 2047, RI_ALL_OFFLINE }, { 0xf0000, 1, RI_ALL_ONLINE }, + { 0xf0004, 16383, RI_ALL_OFFLINE }, { 0x101000, 12, RI_ALL_ONLINE }, + { 0x10103c, 1, RI_ALL_ONLINE }, { 0x10104c, 1, RI_ALL_ONLINE }, + { 0x101050, 1, RI_E1H_ONLINE }, { 0x101100, 1, RI_ALL_ONLINE }, + { 0x101800, 8, RI_ALL_ONLINE }, { 0x102000, 18, RI_ALL_ONLINE }, + { 0x102054, 1, RI_ALL_ONLINE }, { 0x102064, 1, RI_ALL_ONLINE }, + { 0x102080, 17, RI_ALL_ONLINE }, { 0x1020c8, 8, RI_E1H_ONLINE }, + { 0x102400, 1, RI_ALL_ONLINE }, { 0x103000, 26, RI_ALL_ONLINE }, + { 0x103074, 1, RI_ALL_ONLINE }, { 0x103084, 1, RI_ALL_ONLINE }, + { 0x103094, 1, RI_ALL_ONLINE }, { 0x103098, 5, RI_E1H_ONLINE }, + { 0x103800, 8, RI_ALL_ONLINE }, { 0x104000, 63, RI_ALL_ONLINE }, + { 0x104108, 1, RI_ALL_ONLINE }, { 0x104118, 1, RI_ALL_ONLINE }, + { 0x104200, 17, RI_ALL_ONLINE }, { 0x104400, 64, RI_ALL_ONLINE }, + { 0x104500, 192, RI_ALL_OFFLINE }, { 0x104800, 64, RI_ALL_ONLINE }, + { 0x104900, 192, RI_ALL_OFFLINE }, { 0x105000, 7, RI_ALL_ONLINE }, + { 0x10501c, 1, RI_ALL_OFFLINE }, { 0x105020, 3, RI_ALL_ONLINE }, + { 0x10502c, 1, RI_ALL_OFFLINE }, { 0x105030, 3, RI_ALL_ONLINE }, + { 0x10503c, 1, RI_ALL_OFFLINE }, { 0x105040, 3, RI_ALL_ONLINE }, + { 0x10504c, 1, RI_ALL_OFFLINE }, { 0x105050, 3, RI_ALL_ONLINE }, + { 0x10505c, 1, RI_ALL_OFFLINE }, { 0x105060, 3, RI_ALL_ONLINE }, + { 0x10506c, 1, RI_ALL_OFFLINE }, { 0x105070, 3, RI_ALL_ONLINE }, + { 0x10507c, 1, RI_ALL_OFFLINE }, { 0x105080, 3, RI_ALL_ONLINE }, + { 0x10508c, 1, RI_ALL_OFFLINE }, { 0x105090, 3, RI_ALL_ONLINE }, + { 0x10509c, 1, RI_ALL_OFFLINE }, { 0x1050a0, 3, RI_ALL_ONLINE }, + { 0x1050ac, 1, RI_ALL_OFFLINE }, { 0x1050b0, 3, RI_ALL_ONLINE }, + { 0x1050bc, 1, RI_ALL_OFFLINE }, { 0x1050c0, 3, RI_ALL_ONLINE }, + { 0x1050cc, 1, RI_ALL_OFFLINE }, { 0x1050d0, 3, RI_ALL_ONLINE }, + { 0x1050dc, 1, RI_ALL_OFFLINE }, { 0x1050e0, 3, RI_ALL_ONLINE }, + { 0x1050ec, 1, RI_ALL_OFFLINE }, { 0x1050f0, 3, RI_ALL_ONLINE }, + { 0x1050fc, 1, RI_ALL_OFFLINE }, { 0x105100, 3, RI_ALL_ONLINE }, + { 0x10510c, 1, RI_ALL_OFFLINE }, { 0x105110, 3, RI_ALL_ONLINE }, + { 0x10511c, 1, RI_ALL_OFFLINE }, { 0x105120, 3, RI_ALL_ONLINE }, + { 0x10512c, 1, RI_ALL_OFFLINE }, { 0x105130, 3, RI_ALL_ONLINE }, + { 0x10513c, 1, RI_ALL_OFFLINE }, { 0x105140, 3, RI_ALL_ONLINE }, + { 0x10514c, 1, RI_ALL_OFFLINE }, { 0x105150, 3, RI_ALL_ONLINE }, + { 0x10515c, 1, RI_ALL_OFFLINE }, { 0x105160, 3, RI_ALL_ONLINE }, + { 0x10516c, 1, RI_ALL_OFFLINE }, { 0x105170, 3, RI_ALL_ONLINE }, + { 0x10517c, 1, RI_ALL_OFFLINE }, { 0x105180, 3, RI_ALL_ONLINE }, + { 0x10518c, 1, RI_ALL_OFFLINE }, { 0x105190, 3, RI_ALL_ONLINE }, + { 0x10519c, 1, RI_ALL_OFFLINE }, { 0x1051a0, 3, RI_ALL_ONLINE }, + { 0x1051ac, 1, RI_ALL_OFFLINE }, { 0x1051b0, 3, RI_ALL_ONLINE }, + { 0x1051bc, 1, RI_ALL_OFFLINE }, { 0x1051c0, 3, RI_ALL_ONLINE }, + { 0x1051cc, 1, RI_ALL_OFFLINE }, { 0x1051d0, 3, RI_ALL_ONLINE }, + { 0x1051dc, 1, RI_ALL_OFFLINE }, { 0x1051e0, 3, RI_ALL_ONLINE }, + { 0x1051ec, 1, RI_ALL_OFFLINE }, { 0x1051f0, 3, RI_ALL_ONLINE }, + { 0x1051fc, 1, RI_ALL_OFFLINE }, { 0x105200, 3, RI_ALL_ONLINE }, + { 0x10520c, 1, RI_ALL_OFFLINE }, { 0x105210, 3, RI_ALL_ONLINE }, + { 0x10521c, 1, RI_ALL_OFFLINE }, { 0x105220, 3, RI_ALL_ONLINE }, + { 0x10522c, 1, RI_ALL_OFFLINE }, { 0x105230, 3, RI_ALL_ONLINE }, + { 0x10523c, 1, RI_ALL_OFFLINE }, { 0x105240, 3, RI_ALL_ONLINE }, + { 0x10524c, 1, RI_ALL_OFFLINE }, { 0x105250, 3, RI_ALL_ONLINE }, + { 0x10525c, 1, RI_ALL_OFFLINE }, { 0x105260, 3, RI_ALL_ONLINE }, + { 0x10526c, 1, RI_ALL_OFFLINE }, { 0x105270, 3, RI_ALL_ONLINE }, + { 0x10527c, 1, RI_ALL_OFFLINE }, { 0x105280, 3, RI_ALL_ONLINE }, + { 0x10528c, 1, RI_ALL_OFFLINE }, { 0x105290, 3, RI_ALL_ONLINE }, + { 0x10529c, 1, RI_ALL_OFFLINE }, { 0x1052a0, 3, RI_ALL_ONLINE }, + { 0x1052ac, 1, RI_ALL_OFFLINE }, { 0x1052b0, 3, RI_ALL_ONLINE }, + { 0x1052bc, 1, RI_ALL_OFFLINE }, { 0x1052c0, 3, RI_ALL_ONLINE }, + { 0x1052cc, 1, RI_ALL_OFFLINE }, { 0x1052d0, 3, RI_ALL_ONLINE }, + { 0x1052dc, 1, RI_ALL_OFFLINE }, { 0x1052e0, 3, RI_ALL_ONLINE }, + { 0x1052ec, 1, RI_ALL_OFFLINE }, { 0x1052f0, 3, RI_ALL_ONLINE }, + { 0x1052fc, 1, RI_ALL_OFFLINE }, { 0x105300, 3, RI_ALL_ONLINE }, + { 0x10530c, 1, RI_ALL_OFFLINE }, { 0x105310, 3, RI_ALL_ONLINE }, + { 0x10531c, 1, RI_ALL_OFFLINE }, { 0x105320, 3, RI_ALL_ONLINE }, + { 0x10532c, 1, RI_ALL_OFFLINE }, { 0x105330, 3, RI_ALL_ONLINE }, + { 0x10533c, 1, RI_ALL_OFFLINE }, { 0x105340, 3, RI_ALL_ONLINE }, + { 0x10534c, 1, RI_ALL_OFFLINE }, { 0x105350, 3, RI_ALL_ONLINE }, + { 0x10535c, 1, RI_ALL_OFFLINE }, { 0x105360, 3, RI_ALL_ONLINE }, + { 0x10536c, 1, RI_ALL_OFFLINE }, { 0x105370, 3, RI_ALL_ONLINE }, + { 0x10537c, 1, RI_ALL_OFFLINE }, { 0x105380, 3, RI_ALL_ONLINE }, + { 0x10538c, 1, RI_ALL_OFFLINE }, { 0x105390, 3, RI_ALL_ONLINE }, + { 0x10539c, 1, RI_ALL_OFFLINE }, { 0x1053a0, 3, RI_ALL_ONLINE }, + { 0x1053ac, 1, RI_ALL_OFFLINE }, { 0x1053b0, 3, RI_ALL_ONLINE }, + { 0x1053bc, 1, RI_ALL_OFFLINE }, { 0x1053c0, 3, RI_ALL_ONLINE }, + { 0x1053cc, 1, RI_ALL_OFFLINE }, { 0x1053d0, 3, RI_ALL_ONLINE }, + { 0x1053dc, 1, RI_ALL_OFFLINE }, { 0x1053e0, 3, RI_ALL_ONLINE }, + { 0x1053ec, 1, RI_ALL_OFFLINE }, { 0x1053f0, 3, RI_ALL_ONLINE }, + { 0x1053fc, 769, RI_ALL_OFFLINE }, { 0x108000, 33, RI_ALL_ONLINE }, + { 0x108090, 1, RI_ALL_ONLINE }, { 0x1080a0, 1, RI_ALL_ONLINE }, + { 0x1080ac, 5, RI_E1H_ONLINE }, { 0x108100, 5, RI_ALL_ONLINE }, + { 0x108120, 5, RI_ALL_ONLINE }, { 0x108200, 74, RI_ALL_ONLINE }, + { 0x108400, 74, RI_ALL_ONLINE }, { 0x108800, 152, RI_ALL_ONLINE }, + { 0x109000, 1, RI_ALL_ONLINE }, { 0x120000, 347, RI_ALL_ONLINE }, + { 0x120578, 1, RI_ALL_ONLINE }, { 0x120588, 1, RI_ALL_ONLINE }, + { 0x120598, 1, RI_ALL_ONLINE }, { 0x12059c, 23, RI_E1H_ONLINE }, + { 0x120614, 1, RI_E1H_ONLINE }, { 0x12061c, 30, RI_E1H_ONLINE }, + { 0x12080c, 65, RI_ALL_ONLINE }, { 0x120a00, 2, RI_ALL_ONLINE }, + { 0x122000, 2, RI_ALL_ONLINE }, { 0x128000, 2, RI_E1H_ONLINE }, + { 0x140000, 114, RI_ALL_ONLINE }, { 0x1401d4, 1, RI_ALL_ONLINE }, + { 0x1401e4, 1, RI_ALL_ONLINE }, { 0x140200, 6, RI_ALL_ONLINE }, + { 0x144000, 4, RI_ALL_ONLINE }, { 0x148000, 4, RI_ALL_ONLINE }, + { 0x14c000, 4, RI_ALL_ONLINE }, { 0x150000, 4, RI_ALL_ONLINE }, + { 0x154000, 4, RI_ALL_ONLINE }, { 0x158000, 4, RI_ALL_ONLINE }, + { 0x15c000, 7, RI_E1H_ONLINE }, { 0x161000, 7, RI_ALL_ONLINE }, + { 0x161028, 1, RI_ALL_ONLINE }, { 0x161038, 1, RI_ALL_ONLINE }, + { 0x161800, 2, RI_ALL_ONLINE }, { 0x164000, 60, RI_ALL_ONLINE }, + { 0x1640fc, 1, RI_ALL_ONLINE }, { 0x16410c, 1, RI_ALL_ONLINE }, + { 0x164110, 2, RI_E1H_ONLINE }, { 0x164200, 1, RI_ALL_ONLINE }, + { 0x164208, 1, RI_ALL_ONLINE }, { 0x164210, 1, RI_ALL_ONLINE }, + { 0x164218, 1, RI_ALL_ONLINE }, { 0x164220, 1, RI_ALL_ONLINE }, + { 0x164228, 1, RI_ALL_ONLINE }, { 0x164230, 1, RI_ALL_ONLINE }, + { 0x164238, 1, RI_ALL_ONLINE }, { 0x164240, 1, RI_ALL_ONLINE }, + { 0x164248, 1, RI_ALL_ONLINE }, { 0x164250, 1, RI_ALL_ONLINE }, + { 0x164258, 1, RI_ALL_ONLINE }, { 0x164260, 1, RI_ALL_ONLINE }, + { 0x164270, 2, RI_ALL_ONLINE }, { 0x164280, 2, RI_ALL_ONLINE }, + { 0x164800, 2, RI_ALL_ONLINE }, { 0x165000, 2, RI_ALL_ONLINE }, + { 0x166000, 164, RI_ALL_ONLINE }, { 0x16629c, 1, RI_ALL_ONLINE }, + { 0x1662ac, 1, RI_ALL_ONLINE }, { 0x1662bc, 1, RI_ALL_ONLINE }, + { 0x166400, 49, RI_ALL_ONLINE }, { 0x1664c8, 38, RI_ALL_ONLINE }, + { 0x166568, 2, RI_ALL_ONLINE }, { 0x166800, 1, RI_ALL_ONLINE }, + { 0x168000, 270, RI_ALL_ONLINE }, { 0x168444, 1, RI_ALL_ONLINE }, + { 0x168454, 1, RI_ALL_ONLINE }, { 0x168800, 19, RI_ALL_ONLINE }, + { 0x168900, 1, RI_ALL_ONLINE }, { 0x168a00, 128, RI_ALL_ONLINE }, + { 0x16a000, 1, RI_ALL_ONLINE }, { 0x16a004, 1535, RI_ALL_OFFLINE }, + { 0x16c000, 1, RI_ALL_ONLINE }, { 0x16c004, 1535, RI_ALL_OFFLINE }, + { 0x16e000, 16, RI_E1H_ONLINE }, { 0x16e100, 1, RI_E1H_ONLINE }, + { 0x16e200, 2, RI_E1H_ONLINE }, { 0x16e400, 183, RI_E1H_ONLINE }, + { 0x170000, 93, RI_ALL_ONLINE }, { 0x170180, 1, RI_ALL_ONLINE }, + { 0x170190, 1, RI_ALL_ONLINE }, { 0x170200, 4, RI_ALL_ONLINE }, + { 0x170214, 1, RI_ALL_ONLINE }, { 0x178000, 1, RI_ALL_ONLINE }, + { 0x180000, 61, RI_ALL_ONLINE }, { 0x180100, 1, RI_ALL_ONLINE }, + { 0x180110, 1, RI_ALL_ONLINE }, { 0x180120, 1, RI_ALL_ONLINE }, + { 0x180130, 1, RI_ALL_ONLINE }, { 0x18013c, 2, RI_E1H_ONLINE }, + { 0x180200, 58, RI_ALL_ONLINE }, { 0x180340, 4, RI_ALL_ONLINE }, + { 0x180400, 1, RI_ALL_ONLINE }, { 0x180404, 255, RI_ALL_OFFLINE }, + { 0x181000, 4, RI_ALL_ONLINE }, { 0x181010, 1020, RI_ALL_OFFLINE }, + { 0x1a0000, 1, RI_ALL_ONLINE }, { 0x1a0004, 1023, RI_ALL_OFFLINE }, + { 0x1a1000, 1, RI_ALL_ONLINE }, { 0x1a1004, 4607, RI_ALL_OFFLINE }, + { 0x1a5800, 2560, RI_E1H_OFFLINE }, { 0x1a8000, 64, RI_ALL_OFFLINE }, + { 0x1a8100, 1984, RI_E1H_OFFLINE }, { 0x1aa000, 1, RI_E1H_ONLINE }, + { 0x1aa004, 6655, RI_E1H_OFFLINE }, { 0x1b1800, 128, RI_ALL_OFFLINE }, + { 0x1b1c00, 128, RI_ALL_OFFLINE }, { 0x1b2000, 1, RI_ALL_OFFLINE }, + { 0x1b2400, 64, RI_E1H_OFFLINE }, { 0x1b8200, 1, RI_ALL_ONLINE }, + { 0x1b8240, 1, RI_ALL_ONLINE }, { 0x1b8280, 1, RI_ALL_ONLINE }, + { 0x1b82c0, 1, RI_ALL_ONLINE }, { 0x1b8a00, 1, RI_ALL_ONLINE }, + { 0x1b8a80, 1, RI_ALL_ONLINE }, { 0x1c0000, 2, RI_ALL_ONLINE }, + { 0x200000, 65, RI_ALL_ONLINE }, { 0x200110, 1, RI_ALL_ONLINE }, + { 0x200120, 1, RI_ALL_ONLINE }, { 0x200130, 1, RI_ALL_ONLINE }, + { 0x200140, 1, RI_ALL_ONLINE }, { 0x20014c, 2, RI_E1H_ONLINE }, + { 0x200200, 58, RI_ALL_ONLINE }, { 0x200340, 4, RI_ALL_ONLINE }, + { 0x200400, 1, RI_ALL_ONLINE }, { 0x200404, 255, RI_ALL_OFFLINE }, + { 0x202000, 4, RI_ALL_ONLINE }, { 0x202010, 2044, RI_ALL_OFFLINE }, + { 0x220000, 1, RI_ALL_ONLINE }, { 0x220004, 1023, RI_ALL_OFFLINE }, + { 0x221000, 1, RI_ALL_ONLINE }, { 0x221004, 4607, RI_ALL_OFFLINE }, + { 0x225800, 1536, RI_E1H_OFFLINE }, { 0x227000, 1, RI_E1H_ONLINE }, + { 0x227004, 1023, RI_E1H_OFFLINE }, { 0x228000, 64, RI_ALL_OFFLINE }, + { 0x228100, 8640, RI_E1H_OFFLINE }, { 0x231800, 128, RI_ALL_OFFLINE }, + { 0x231c00, 128, RI_ALL_OFFLINE }, { 0x232000, 1, RI_ALL_OFFLINE }, + { 0x232400, 64, RI_E1H_OFFLINE }, { 0x238200, 1, RI_ALL_ONLINE }, + { 0x238240, 1, RI_ALL_ONLINE }, { 0x238280, 1, RI_ALL_ONLINE }, + { 0x2382c0, 1, RI_ALL_ONLINE }, { 0x238a00, 1, RI_ALL_ONLINE }, + { 0x238a80, 1, RI_ALL_ONLINE }, { 0x240000, 2, RI_ALL_ONLINE }, + { 0x280000, 65, RI_ALL_ONLINE }, { 0x280110, 1, RI_ALL_ONLINE }, + { 0x280120, 1, RI_ALL_ONLINE }, { 0x280130, 1, RI_ALL_ONLINE }, + { 0x280140, 1, RI_ALL_ONLINE }, { 0x28014c, 2, RI_E1H_ONLINE }, + { 0x280200, 58, RI_ALL_ONLINE }, { 0x280340, 4, RI_ALL_ONLINE }, + { 0x280400, 1, RI_ALL_ONLINE }, { 0x280404, 255, RI_ALL_OFFLINE }, + { 0x282000, 4, RI_ALL_ONLINE }, { 0x282010, 2044, RI_ALL_OFFLINE }, + { 0x2a0000, 1, RI_ALL_ONLINE }, { 0x2a0004, 1023, RI_ALL_OFFLINE }, + { 0x2a1000, 1, RI_ALL_ONLINE }, { 0x2a1004, 4607, RI_ALL_OFFLINE }, + { 0x2a5800, 2560, RI_E1H_OFFLINE }, { 0x2a8000, 64, RI_ALL_OFFLINE }, + { 0x2a8100, 960, RI_E1H_OFFLINE }, { 0x2a9000, 1, RI_E1H_ONLINE }, + { 0x2a9004, 7679, RI_E1H_OFFLINE }, { 0x2b1800, 128, RI_ALL_OFFLINE }, + { 0x2b1c00, 128, RI_ALL_OFFLINE }, { 0x2b2000, 1, RI_ALL_OFFLINE }, + { 0x2b2400, 64, RI_E1H_OFFLINE }, { 0x2b8200, 1, RI_ALL_ONLINE }, + { 0x2b8240, 1, RI_ALL_ONLINE }, { 0x2b8280, 1, RI_ALL_ONLINE }, + { 0x2b82c0, 1, RI_ALL_ONLINE }, { 0x2b8a00, 1, RI_ALL_ONLINE }, + { 0x2b8a80, 1, RI_ALL_ONLINE }, { 0x2c0000, 2, RI_ALL_ONLINE }, + { 0x300000, 65, RI_ALL_ONLINE }, { 0x300110, 1, RI_ALL_ONLINE }, + { 0x300120, 1, RI_ALL_ONLINE }, { 0x300130, 1, RI_ALL_ONLINE }, + { 0x300140, 1, RI_ALL_ONLINE }, { 0x30014c, 2, RI_E1H_ONLINE }, + { 0x300200, 58, RI_ALL_ONLINE }, { 0x300340, 4, RI_ALL_ONLINE }, + { 0x300400, 1, RI_ALL_ONLINE }, { 0x300404, 255, RI_ALL_OFFLINE }, + { 0x302000, 4, RI_ALL_ONLINE }, { 0x302010, 2044, RI_ALL_OFFLINE }, + { 0x320000, 1, RI_ALL_ONLINE }, { 0x320004, 1023, RI_ALL_OFFLINE }, + { 0x321000, 1, RI_ALL_ONLINE }, { 0x321004, 4607, RI_ALL_OFFLINE }, + { 0x325800, 2560, RI_E1H_OFFLINE }, { 0x328000, 64, RI_ALL_OFFLINE }, + { 0x328100, 536, RI_E1H_OFFLINE }, { 0x328960, 1, RI_E1H_ONLINE }, + { 0x328964, 8103, RI_E1H_OFFLINE }, { 0x331800, 128, RI_ALL_OFFLINE }, + { 0x331c00, 128, RI_ALL_OFFLINE }, { 0x332000, 1, RI_ALL_OFFLINE }, + { 0x332400, 64, RI_E1H_OFFLINE }, { 0x338200, 1, RI_ALL_ONLINE }, + { 0x338240, 1, RI_ALL_ONLINE }, { 0x338280, 1, RI_ALL_ONLINE }, + { 0x3382c0, 1, RI_ALL_ONLINE }, { 0x338a00, 1, RI_ALL_ONLINE }, + { 0x338a80, 1, RI_ALL_ONLINE }, { 0x340000, 2, RI_ALL_ONLINE } }; -#define IDLEREGS_COUNT 277 -static const struct reg_addr idle_addrs[IDLEREGS_COUNT] = { - { 0x2114, 1, RI_ALL_ONLINE}, { 0x2120, 1, RI_ALL_ONLINE}, - { 0x212c, 4, RI_ALL_ONLINE}, { 0x2814, 1, RI_ALL_ONLINE}, - { 0x281c, 2, RI_ALL_ONLINE}, { 0xa38c, 1, RI_ALL_ONLINE}, - { 0xa408, 1, RI_ALL_ONLINE}, { 0xa42c, 12, RI_ALL_ONLINE}, - { 0xa600, 5, RI_E1H_ONLINE}, { 0xa618, 1, RI_E1H_ONLINE}, - { 0xc09c, 1, RI_ALL_ONLINE}, { 0x103b0, 1, RI_ALL_ONLINE}, - { 0x103c0, 1, RI_ALL_ONLINE}, { 0x103d0, 1, RI_E1H_ONLINE}, - { 0x2021c, 11, RI_ALL_ONLINE}, { 0x202a8, 1, RI_ALL_ONLINE}, - { 0x202b8, 1, RI_ALL_ONLINE}, { 0x20404, 1, RI_ALL_ONLINE}, - { 0x2040c, 2, RI_ALL_ONLINE}, { 0x2041c, 2, RI_ALL_ONLINE}, - { 0x40154, 14, RI_ALL_ONLINE}, { 0x40198, 1, RI_ALL_ONLINE}, - { 0x404ac, 1, RI_ALL_ONLINE}, { 0x404bc, 1, RI_ALL_ONLINE}, - { 0x42290, 1, RI_ALL_ONLINE}, { 0x422a0, 1, RI_ALL_ONLINE}, - { 0x422b0, 1, RI_ALL_ONLINE}, { 0x42548, 1, RI_ALL_ONLINE}, - { 0x42550, 1, RI_ALL_ONLINE}, { 0x42558, 1, RI_ALL_ONLINE}, - { 0x50160, 8, RI_ALL_ONLINE}, { 0x501d0, 1, RI_ALL_ONLINE}, - { 0x501e0, 1, RI_ALL_ONLINE}, { 0x50204, 1, RI_ALL_ONLINE}, - { 0x5020c, 2, RI_ALL_ONLINE}, { 0x5021c, 1, RI_ALL_ONLINE}, - { 0x60090, 1, RI_ALL_ONLINE}, { 0x6011c, 1, RI_ALL_ONLINE}, - { 0x6012c, 1, RI_ALL_ONLINE}, { 0xc101c, 1, RI_ALL_ONLINE}, - { 0xc102c, 1, RI_ALL_ONLINE}, { 0xc2290, 1, RI_ALL_ONLINE}, - { 0xc22a0, 1, RI_ALL_ONLINE}, { 0xc22b0, 1, RI_ALL_ONLINE}, - { 0xc2548, 1, RI_ALL_ONLINE}, { 0xc2550, 1, RI_ALL_ONLINE}, - { 0xc2558, 1, RI_ALL_ONLINE}, { 0xc4294, 1, RI_ALL_ONLINE}, - { 0xc42a4, 1, RI_ALL_ONLINE}, { 0xc42b4, 1, RI_ALL_ONLINE}, - { 0xc4550, 1, RI_ALL_ONLINE}, { 0xc4558, 1, RI_ALL_ONLINE}, - { 0xc4560, 1, RI_ALL_ONLINE}, { 0xd016c, 8, RI_ALL_ONLINE}, - { 0xd01d8, 1, RI_ALL_ONLINE}, { 0xd01e8, 1, RI_ALL_ONLINE}, - { 0xd0204, 1, RI_ALL_ONLINE}, { 0xd020c, 3, RI_ALL_ONLINE}, - { 0xe0154, 8, RI_ALL_ONLINE}, { 0xe01c8, 1, RI_ALL_ONLINE}, - { 0xe01d8, 1, RI_ALL_ONLINE}, { 0xe0204, 1, RI_ALL_ONLINE}, - { 0xe020c, 2, RI_ALL_ONLINE}, { 0xe021c, 2, RI_ALL_ONLINE}, - { 0x101014, 1, RI_ALL_ONLINE}, { 0x101030, 1, RI_ALL_ONLINE}, - { 0x101040, 1, RI_ALL_ONLINE}, { 0x102058, 1, RI_ALL_ONLINE}, - { 0x102080, 16, RI_ALL_ONLINE}, { 0x103004, 2, RI_ALL_ONLINE}, - { 0x103068, 1, RI_ALL_ONLINE}, { 0x103078, 1, RI_ALL_ONLINE}, - { 0x103088, 1, RI_ALL_ONLINE}, { 0x10309c, 2, RI_E1H_ONLINE}, - { 0x104004, 1, RI_ALL_ONLINE}, { 0x104018, 1, RI_ALL_ONLINE}, - { 0x104020, 1, RI_ALL_ONLINE}, { 0x10403c, 1, RI_ALL_ONLINE}, - { 0x1040fc, 1, RI_ALL_ONLINE}, { 0x10410c, 1, RI_ALL_ONLINE}, - { 0x104400, 64, RI_ALL_ONLINE}, { 0x104800, 64, RI_ALL_ONLINE}, - { 0x105000, 3, RI_ALL_ONLINE}, { 0x105010, 3, RI_ALL_ONLINE}, - { 0x105020, 3, RI_ALL_ONLINE}, { 0x105030, 3, RI_ALL_ONLINE}, - { 0x105040, 3, RI_ALL_ONLINE}, { 0x105050, 3, RI_ALL_ONLINE}, - { 0x105060, 3, RI_ALL_ONLINE}, { 0x105070, 3, RI_ALL_ONLINE}, - { 0x105080, 3, RI_ALL_ONLINE}, { 0x105090, 3, RI_ALL_ONLINE}, - { 0x1050a0, 3, RI_ALL_ONLINE}, { 0x1050b0, 3, RI_ALL_ONLINE}, - { 0x1050c0, 3, RI_ALL_ONLINE}, { 0x1050d0, 3, RI_ALL_ONLINE}, - { 0x1050e0, 3, RI_ALL_ONLINE}, { 0x1050f0, 3, RI_ALL_ONLINE}, - { 0x105100, 3, RI_ALL_ONLINE}, { 0x105110, 3, RI_ALL_ONLINE}, - { 0x105120, 3, RI_ALL_ONLINE}, { 0x105130, 3, RI_ALL_ONLINE}, - { 0x105140, 3, RI_ALL_ONLINE}, { 0x105150, 3, RI_ALL_ONLINE}, - { 0x105160, 3, RI_ALL_ONLINE}, { 0x105170, 3, RI_ALL_ONLINE}, - { 0x105180, 3, RI_ALL_ONLINE}, { 0x105190, 3, RI_ALL_ONLINE}, - { 0x1051a0, 3, RI_ALL_ONLINE}, { 0x1051b0, 3, RI_ALL_ONLINE}, - { 0x1051c0, 3, RI_ALL_ONLINE}, { 0x1051d0, 3, RI_ALL_ONLINE}, - { 0x1051e0, 3, RI_ALL_ONLINE}, { 0x1051f0, 3, RI_ALL_ONLINE}, - { 0x105200, 3, RI_ALL_ONLINE}, { 0x105210, 3, RI_ALL_ONLINE}, - { 0x105220, 3, RI_ALL_ONLINE}, { 0x105230, 3, RI_ALL_ONLINE}, - { 0x105240, 3, RI_ALL_ONLINE}, { 0x105250, 3, RI_ALL_ONLINE}, - { 0x105260, 3, RI_ALL_ONLINE}, { 0x105270, 3, RI_ALL_ONLINE}, - { 0x105280, 3, RI_ALL_ONLINE}, { 0x105290, 3, RI_ALL_ONLINE}, - { 0x1052a0, 3, RI_ALL_ONLINE}, { 0x1052b0, 3, RI_ALL_ONLINE}, - { 0x1052c0, 3, RI_ALL_ONLINE}, { 0x1052d0, 3, RI_ALL_ONLINE}, - { 0x1052e0, 3, RI_ALL_ONLINE}, { 0x1052f0, 3, RI_ALL_ONLINE}, - { 0x105300, 3, RI_ALL_ONLINE}, { 0x105310, 3, RI_ALL_ONLINE}, - { 0x105320, 3, RI_ALL_ONLINE}, { 0x105330, 3, RI_ALL_ONLINE}, - { 0x105340, 3, RI_ALL_ONLINE}, { 0x105350, 3, RI_ALL_ONLINE}, - { 0x105360, 3, RI_ALL_ONLINE}, { 0x105370, 3, RI_ALL_ONLINE}, - { 0x105380, 3, RI_ALL_ONLINE}, { 0x105390, 3, RI_ALL_ONLINE}, - { 0x1053a0, 3, RI_ALL_ONLINE}, { 0x1053b0, 3, RI_ALL_ONLINE}, - { 0x1053c0, 3, RI_ALL_ONLINE}, { 0x1053d0, 3, RI_ALL_ONLINE}, - { 0x1053e0, 3, RI_ALL_ONLINE}, { 0x1053f0, 3, RI_ALL_ONLINE}, - { 0x108094, 1, RI_ALL_ONLINE}, { 0x1201b0, 2, RI_ALL_ONLINE}, - { 0x12032c, 1, RI_ALL_ONLINE}, { 0x12036c, 3, RI_ALL_ONLINE}, - { 0x120408, 2, RI_ALL_ONLINE}, { 0x120414, 15, RI_ALL_ONLINE}, - { 0x120478, 2, RI_ALL_ONLINE}, { 0x12052c, 1, RI_ALL_ONLINE}, - { 0x120564, 3, RI_ALL_ONLINE}, { 0x12057c, 1, RI_ALL_ONLINE}, - { 0x12058c, 1, RI_ALL_ONLINE}, { 0x120608, 1, RI_E1H_ONLINE}, - { 0x120808, 1, RI_E1_ONLINE}, { 0x12080c, 2, RI_ALL_ONLINE}, - { 0x120818, 1, RI_ALL_ONLINE}, { 0x120820, 1, RI_ALL_ONLINE}, - { 0x120828, 1, RI_ALL_ONLINE}, { 0x120830, 1, RI_ALL_ONLINE}, - { 0x120838, 1, RI_ALL_ONLINE}, { 0x120840, 1, RI_ALL_ONLINE}, - { 0x120848, 1, RI_ALL_ONLINE}, { 0x120850, 1, RI_ALL_ONLINE}, - { 0x120858, 1, RI_ALL_ONLINE}, { 0x120860, 1, RI_ALL_ONLINE}, - { 0x120868, 1, RI_ALL_ONLINE}, { 0x120870, 1, RI_ALL_ONLINE}, - { 0x120878, 1, RI_ALL_ONLINE}, { 0x120880, 1, RI_ALL_ONLINE}, - { 0x120888, 1, RI_ALL_ONLINE}, { 0x120890, 1, RI_ALL_ONLINE}, - { 0x120898, 1, RI_ALL_ONLINE}, { 0x1208a0, 1, RI_ALL_ONLINE}, - { 0x1208a8, 1, RI_ALL_ONLINE}, { 0x1208b0, 1, RI_ALL_ONLINE}, - { 0x1208b8, 1, RI_ALL_ONLINE}, { 0x1208c0, 1, RI_ALL_ONLINE}, - { 0x1208c8, 1, RI_ALL_ONLINE}, { 0x1208d0, 1, RI_ALL_ONLINE}, - { 0x1208d8, 1, RI_ALL_ONLINE}, { 0x1208e0, 1, RI_ALL_ONLINE}, - { 0x1208e8, 1, RI_ALL_ONLINE}, { 0x1208f0, 1, RI_ALL_ONLINE}, - { 0x1208f8, 1, RI_ALL_ONLINE}, { 0x120900, 1, RI_ALL_ONLINE}, - { 0x120908, 1, RI_ALL_ONLINE}, { 0x14005c, 2, RI_ALL_ONLINE}, - { 0x1400d0, 2, RI_ALL_ONLINE}, { 0x1400e0, 1, RI_ALL_ONLINE}, - { 0x1401c8, 1, RI_ALL_ONLINE}, { 0x140200, 6, RI_ALL_ONLINE}, - { 0x16101c, 1, RI_ALL_ONLINE}, { 0x16102c, 1, RI_ALL_ONLINE}, - { 0x164014, 2, RI_ALL_ONLINE}, { 0x1640f0, 1, RI_ALL_ONLINE}, - { 0x166290, 1, RI_ALL_ONLINE}, { 0x1662a0, 1, RI_ALL_ONLINE}, - { 0x1662b0, 1, RI_ALL_ONLINE}, { 0x166548, 1, RI_ALL_ONLINE}, - { 0x166550, 1, RI_ALL_ONLINE}, { 0x166558, 1, RI_ALL_ONLINE}, - { 0x168000, 1, RI_ALL_ONLINE}, { 0x168008, 1, RI_ALL_ONLINE}, - { 0x168010, 1, RI_ALL_ONLINE}, { 0x168018, 1, RI_ALL_ONLINE}, - { 0x168028, 2, RI_ALL_ONLINE}, { 0x168058, 4, RI_ALL_ONLINE}, - { 0x168070, 1, RI_ALL_ONLINE}, { 0x168238, 1, RI_ALL_ONLINE}, - { 0x1682d0, 2, RI_ALL_ONLINE}, { 0x1682e0, 1, RI_ALL_ONLINE}, - { 0x168300, 67, RI_ALL_ONLINE}, { 0x168410, 2, RI_ALL_ONLINE}, - { 0x168438, 1, RI_ALL_ONLINE}, { 0x168448, 1, RI_ALL_ONLINE}, - { 0x168a00, 128, RI_ALL_ONLINE}, { 0x16e200, 128, RI_E1H_ONLINE}, - { 0x16e404, 2, RI_E1H_ONLINE}, { 0x16e584, 70, RI_E1H_ONLINE}, - { 0x1700a4, 1, RI_ALL_ONLINE}, { 0x1700ac, 2, RI_ALL_ONLINE}, - { 0x1700c0, 1, RI_ALL_ONLINE}, { 0x170174, 1, RI_ALL_ONLINE}, - { 0x170184, 1, RI_ALL_ONLINE}, { 0x1800f4, 1, RI_ALL_ONLINE}, - { 0x180104, 1, RI_ALL_ONLINE}, { 0x180114, 1, RI_ALL_ONLINE}, - { 0x180124, 1, RI_ALL_ONLINE}, { 0x18026c, 1, RI_ALL_ONLINE}, - { 0x1802a0, 1, RI_ALL_ONLINE}, { 0x1a1000, 1, RI_ALL_ONLINE}, - { 0x1aa000, 1, RI_E1H_ONLINE}, { 0x1b8000, 1, RI_ALL_ONLINE}, - { 0x1b8040, 1, RI_ALL_ONLINE}, { 0x1b8080, 1, RI_ALL_ONLINE}, - { 0x1b80c0, 1, RI_ALL_ONLINE}, { 0x200104, 1, RI_ALL_ONLINE}, - { 0x200114, 1, RI_ALL_ONLINE}, { 0x200124, 1, RI_ALL_ONLINE}, - { 0x200134, 1, RI_ALL_ONLINE}, { 0x20026c, 1, RI_ALL_ONLINE}, - { 0x2002a0, 1, RI_ALL_ONLINE}, { 0x221000, 1, RI_ALL_ONLINE}, - { 0x227000, 1, RI_E1H_ONLINE}, { 0x238000, 1, RI_ALL_ONLINE}, - { 0x238040, 1, RI_ALL_ONLINE}, { 0x238080, 1, RI_ALL_ONLINE}, - { 0x2380c0, 1, RI_ALL_ONLINE}, { 0x280104, 1, RI_ALL_ONLINE}, - { 0x280114, 1, RI_ALL_ONLINE}, { 0x280124, 1, RI_ALL_ONLINE}, - { 0x280134, 1, RI_ALL_ONLINE}, { 0x28026c, 1, RI_ALL_ONLINE}, - { 0x2802a0, 1, RI_ALL_ONLINE}, { 0x2a1000, 1, RI_ALL_ONLINE}, - { 0x2a9000, 1, RI_E1H_ONLINE}, { 0x2b8000, 1, RI_ALL_ONLINE}, - { 0x2b8040, 1, RI_ALL_ONLINE}, { 0x2b8080, 1, RI_ALL_ONLINE}, - { 0x2b80c0, 1, RI_ALL_ONLINE}, { 0x300104, 1, RI_ALL_ONLINE}, - { 0x300114, 1, RI_ALL_ONLINE}, { 0x300124, 1, RI_ALL_ONLINE}, - { 0x300134, 1, RI_ALL_ONLINE}, { 0x30026c, 1, RI_ALL_ONLINE}, - { 0x3002a0, 1, RI_ALL_ONLINE}, { 0x321000, 1, RI_ALL_ONLINE}, - { 0x328960, 1, RI_E1H_ONLINE}, { 0x338000, 1, RI_ALL_ONLINE}, - { 0x338040, 1, RI_ALL_ONLINE}, { 0x338080, 1, RI_ALL_ONLINE}, - { 0x3380c0, 1, RI_ALL_ONLINE} +#define IDLE_REGS_COUNT 277 +static const struct reg_addr idle_addrs[IDLE_REGS_COUNT] = { + { 0x2114, 1, RI_ALL_ONLINE }, { 0x2120, 1, RI_ALL_ONLINE }, + { 0x212c, 4, RI_ALL_ONLINE }, { 0x2814, 1, RI_ALL_ONLINE }, + { 0x281c, 2, RI_ALL_ONLINE }, { 0xa38c, 1, RI_ALL_ONLINE }, + { 0xa408, 1, RI_ALL_ONLINE }, { 0xa42c, 12, RI_ALL_ONLINE }, + { 0xa600, 5, RI_E1H_ONLINE }, { 0xa618, 1, RI_E1H_ONLINE }, + { 0xc09c, 1, RI_ALL_ONLINE }, { 0x103b0, 1, RI_ALL_ONLINE }, + { 0x103c0, 1, RI_ALL_ONLINE }, { 0x103d0, 1, RI_E1H_ONLINE }, + { 0x2021c, 11, RI_ALL_ONLINE }, { 0x202a8, 1, RI_ALL_ONLINE }, + { 0x202b8, 1, RI_ALL_ONLINE }, { 0x20404, 1, RI_ALL_ONLINE }, + { 0x2040c, 2, RI_ALL_ONLINE }, { 0x2041c, 2, RI_ALL_ONLINE }, + { 0x40154, 14, RI_ALL_ONLINE }, { 0x40198, 1, RI_ALL_ONLINE }, + { 0x404ac, 1, RI_ALL_ONLINE }, { 0x404bc, 1, RI_ALL_ONLINE }, + { 0x42290, 1, RI_ALL_ONLINE }, { 0x422a0, 1, RI_ALL_ONLINE }, + { 0x422b0, 1, RI_ALL_ONLINE }, { 0x42548, 1, RI_ALL_ONLINE }, + { 0x42550, 1, RI_ALL_ONLINE }, { 0x42558, 1, RI_ALL_ONLINE }, + { 0x50160, 8, RI_ALL_ONLINE }, { 0x501d0, 1, RI_ALL_ONLINE }, + { 0x501e0, 1, RI_ALL_ONLINE }, { 0x50204, 1, RI_ALL_ONLINE }, + { 0x5020c, 2, RI_ALL_ONLINE }, { 0x5021c, 1, RI_ALL_ONLINE }, + { 0x60090, 1, RI_ALL_ONLINE }, { 0x6011c, 1, RI_ALL_ONLINE }, + { 0x6012c, 1, RI_ALL_ONLINE }, { 0xc101c, 1, RI_ALL_ONLINE }, + { 0xc102c, 1, RI_ALL_ONLINE }, { 0xc2290, 1, RI_ALL_ONLINE }, + { 0xc22a0, 1, RI_ALL_ONLINE }, { 0xc22b0, 1, RI_ALL_ONLINE }, + { 0xc2548, 1, RI_ALL_ONLINE }, { 0xc2550, 1, RI_ALL_ONLINE }, + { 0xc2558, 1, RI_ALL_ONLINE }, { 0xc4294, 1, RI_ALL_ONLINE }, + { 0xc42a4, 1, RI_ALL_ONLINE }, { 0xc42b4, 1, RI_ALL_ONLINE }, + { 0xc4550, 1, RI_ALL_ONLINE }, { 0xc4558, 1, RI_ALL_ONLINE }, + { 0xc4560, 1, RI_ALL_ONLINE }, { 0xd016c, 8, RI_ALL_ONLINE }, + { 0xd01d8, 1, RI_ALL_ONLINE }, { 0xd01e8, 1, RI_ALL_ONLINE }, + { 0xd0204, 1, RI_ALL_ONLINE }, { 0xd020c, 3, RI_ALL_ONLINE }, + { 0xe0154, 8, RI_ALL_ONLINE }, { 0xe01c8, 1, RI_ALL_ONLINE }, + { 0xe01d8, 1, RI_ALL_ONLINE }, { 0xe0204, 1, RI_ALL_ONLINE }, + { 0xe020c, 2, RI_ALL_ONLINE }, { 0xe021c, 2, RI_ALL_ONLINE }, + { 0x101014, 1, RI_ALL_ONLINE }, { 0x101030, 1, RI_ALL_ONLINE }, + { 0x101040, 1, RI_ALL_ONLINE }, { 0x102058, 1, RI_ALL_ONLINE }, + { 0x102080, 16, RI_ALL_ONLINE }, { 0x103004, 2, RI_ALL_ONLINE }, + { 0x103068, 1, RI_ALL_ONLINE }, { 0x103078, 1, RI_ALL_ONLINE }, + { 0x103088, 1, RI_ALL_ONLINE }, { 0x10309c, 2, RI_E1H_ONLINE }, + { 0x104004, 1, RI_ALL_ONLINE }, { 0x104018, 1, RI_ALL_ONLINE }, + { 0x104020, 1, RI_ALL_ONLINE }, { 0x10403c, 1, RI_ALL_ONLINE }, + { 0x1040fc, 1, RI_ALL_ONLINE }, { 0x10410c, 1, RI_ALL_ONLINE }, + { 0x104400, 64, RI_ALL_ONLINE }, { 0x104800, 64, RI_ALL_ONLINE }, + { 0x105000, 3, RI_ALL_ONLINE }, { 0x105010, 3, RI_ALL_ONLINE }, + { 0x105020, 3, RI_ALL_ONLINE }, { 0x105030, 3, RI_ALL_ONLINE }, + { 0x105040, 3, RI_ALL_ONLINE }, { 0x105050, 3, RI_ALL_ONLINE }, + { 0x105060, 3, RI_ALL_ONLINE }, { 0x105070, 3, RI_ALL_ONLINE }, + { 0x105080, 3, RI_ALL_ONLINE }, { 0x105090, 3, RI_ALL_ONLINE }, + { 0x1050a0, 3, RI_ALL_ONLINE }, { 0x1050b0, 3, RI_ALL_ONLINE }, + { 0x1050c0, 3, RI_ALL_ONLINE }, { 0x1050d0, 3, RI_ALL_ONLINE }, + { 0x1050e0, 3, RI_ALL_ONLINE }, { 0x1050f0, 3, RI_ALL_ONLINE }, + { 0x105100, 3, RI_ALL_ONLINE }, { 0x105110, 3, RI_ALL_ONLINE }, + { 0x105120, 3, RI_ALL_ONLINE }, { 0x105130, 3, RI_ALL_ONLINE }, + { 0x105140, 3, RI_ALL_ONLINE }, { 0x105150, 3, RI_ALL_ONLINE }, + { 0x105160, 3, RI_ALL_ONLINE }, { 0x105170, 3, RI_ALL_ONLINE }, + { 0x105180, 3, RI_ALL_ONLINE }, { 0x105190, 3, RI_ALL_ONLINE }, + { 0x1051a0, 3, RI_ALL_ONLINE }, { 0x1051b0, 3, RI_ALL_ONLINE }, + { 0x1051c0, 3, RI_ALL_ONLINE }, { 0x1051d0, 3, RI_ALL_ONLINE }, + { 0x1051e0, 3, RI_ALL_ONLINE }, { 0x1051f0, 3, RI_ALL_ONLINE }, + { 0x105200, 3, RI_ALL_ONLINE }, { 0x105210, 3, RI_ALL_ONLINE }, + { 0x105220, 3, RI_ALL_ONLINE }, { 0x105230, 3, RI_ALL_ONLINE }, + { 0x105240, 3, RI_ALL_ONLINE }, { 0x105250, 3, RI_ALL_ONLINE }, + { 0x105260, 3, RI_ALL_ONLINE }, { 0x105270, 3, RI_ALL_ONLINE }, + { 0x105280, 3, RI_ALL_ONLINE }, { 0x105290, 3, RI_ALL_ONLINE }, + { 0x1052a0, 3, RI_ALL_ONLINE }, { 0x1052b0, 3, RI_ALL_ONLINE }, + { 0x1052c0, 3, RI_ALL_ONLINE }, { 0x1052d0, 3, RI_ALL_ONLINE }, + { 0x1052e0, 3, RI_ALL_ONLINE }, { 0x1052f0, 3, RI_ALL_ONLINE }, + { 0x105300, 3, RI_ALL_ONLINE }, { 0x105310, 3, RI_ALL_ONLINE }, + { 0x105320, 3, RI_ALL_ONLINE }, { 0x105330, 3, RI_ALL_ONLINE }, + { 0x105340, 3, RI_ALL_ONLINE }, { 0x105350, 3, RI_ALL_ONLINE }, + { 0x105360, 3, RI_ALL_ONLINE }, { 0x105370, 3, RI_ALL_ONLINE }, + { 0x105380, 3, RI_ALL_ONLINE }, { 0x105390, 3, RI_ALL_ONLINE }, + { 0x1053a0, 3, RI_ALL_ONLINE }, { 0x1053b0, 3, RI_ALL_ONLINE }, + { 0x1053c0, 3, RI_ALL_ONLINE }, { 0x1053d0, 3, RI_ALL_ONLINE }, + { 0x1053e0, 3, RI_ALL_ONLINE }, { 0x1053f0, 3, RI_ALL_ONLINE }, + { 0x108094, 1, RI_ALL_ONLINE }, { 0x1201b0, 2, RI_ALL_ONLINE }, + { 0x12032c, 1, RI_ALL_ONLINE }, { 0x12036c, 3, RI_ALL_ONLINE }, + { 0x120408, 2, RI_ALL_ONLINE }, { 0x120414, 15, RI_ALL_ONLINE }, + { 0x120478, 2, RI_ALL_ONLINE }, { 0x12052c, 1, RI_ALL_ONLINE }, + { 0x120564, 3, RI_ALL_ONLINE }, { 0x12057c, 1, RI_ALL_ONLINE }, + { 0x12058c, 1, RI_ALL_ONLINE }, { 0x120608, 1, RI_E1H_ONLINE }, + { 0x120808, 1, RI_E1_ONLINE }, { 0x12080c, 2, RI_ALL_ONLINE }, + { 0x120818, 1, RI_ALL_ONLINE }, { 0x120820, 1, RI_ALL_ONLINE }, + { 0x120828, 1, RI_ALL_ONLINE }, { 0x120830, 1, RI_ALL_ONLINE }, + { 0x120838, 1, RI_ALL_ONLINE }, { 0x120840, 1, RI_ALL_ONLINE }, + { 0x120848, 1, RI_ALL_ONLINE }, { 0x120850, 1, RI_ALL_ONLINE }, + { 0x120858, 1, RI_ALL_ONLINE }, { 0x120860, 1, RI_ALL_ONLINE }, + { 0x120868, 1, RI_ALL_ONLINE }, { 0x120870, 1, RI_ALL_ONLINE }, + { 0x120878, 1, RI_ALL_ONLINE }, { 0x120880, 1, RI_ALL_ONLINE }, + { 0x120888, 1, RI_ALL_ONLINE }, { 0x120890, 1, RI_ALL_ONLINE }, + { 0x120898, 1, RI_ALL_ONLINE }, { 0x1208a0, 1, RI_ALL_ONLINE }, + { 0x1208a8, 1, RI_ALL_ONLINE }, { 0x1208b0, 1, RI_ALL_ONLINE }, + { 0x1208b8, 1, RI_ALL_ONLINE }, { 0x1208c0, 1, RI_ALL_ONLINE }, + { 0x1208c8, 1, RI_ALL_ONLINE }, { 0x1208d0, 1, RI_ALL_ONLINE }, + { 0x1208d8, 1, RI_ALL_ONLINE }, { 0x1208e0, 1, RI_ALL_ONLINE }, + { 0x1208e8, 1, RI_ALL_ONLINE }, { 0x1208f0, 1, RI_ALL_ONLINE }, + { 0x1208f8, 1, RI_ALL_ONLINE }, { 0x120900, 1, RI_ALL_ONLINE }, + { 0x120908, 1, RI_ALL_ONLINE }, { 0x14005c, 2, RI_ALL_ONLINE }, + { 0x1400d0, 2, RI_ALL_ONLINE }, { 0x1400e0, 1, RI_ALL_ONLINE }, + { 0x1401c8, 1, RI_ALL_ONLINE }, { 0x140200, 6, RI_ALL_ONLINE }, + { 0x16101c, 1, RI_ALL_ONLINE }, { 0x16102c, 1, RI_ALL_ONLINE }, + { 0x164014, 2, RI_ALL_ONLINE }, { 0x1640f0, 1, RI_ALL_ONLINE }, + { 0x166290, 1, RI_ALL_ONLINE }, { 0x1662a0, 1, RI_ALL_ONLINE }, + { 0x1662b0, 1, RI_ALL_ONLINE }, { 0x166548, 1, RI_ALL_ONLINE }, + { 0x166550, 1, RI_ALL_ONLINE }, { 0x166558, 1, RI_ALL_ONLINE }, + { 0x168000, 1, RI_ALL_ONLINE }, { 0x168008, 1, RI_ALL_ONLINE }, + { 0x168010, 1, RI_ALL_ONLINE }, { 0x168018, 1, RI_ALL_ONLINE }, + { 0x168028, 2, RI_ALL_ONLINE }, { 0x168058, 4, RI_ALL_ONLINE }, + { 0x168070, 1, RI_ALL_ONLINE }, { 0x168238, 1, RI_ALL_ONLINE }, + { 0x1682d0, 2, RI_ALL_ONLINE }, { 0x1682e0, 1, RI_ALL_ONLINE }, + { 0x168300, 67, RI_ALL_ONLINE }, { 0x168410, 2, RI_ALL_ONLINE }, + { 0x168438, 1, RI_ALL_ONLINE }, { 0x168448, 1, RI_ALL_ONLINE }, + { 0x168a00, 128, RI_ALL_ONLINE }, { 0x16e200, 128, RI_E1H_ONLINE }, + { 0x16e404, 2, RI_E1H_ONLINE }, { 0x16e584, 70, RI_E1H_ONLINE }, + { 0x1700a4, 1, RI_ALL_ONLINE }, { 0x1700ac, 2, RI_ALL_ONLINE }, + { 0x1700c0, 1, RI_ALL_ONLINE }, { 0x170174, 1, RI_ALL_ONLINE }, + { 0x170184, 1, RI_ALL_ONLINE }, { 0x1800f4, 1, RI_ALL_ONLINE }, + { 0x180104, 1, RI_ALL_ONLINE }, { 0x180114, 1, RI_ALL_ONLINE }, + { 0x180124, 1, RI_ALL_ONLINE }, { 0x18026c, 1, RI_ALL_ONLINE }, + { 0x1802a0, 1, RI_ALL_ONLINE }, { 0x1a1000, 1, RI_ALL_ONLINE }, + { 0x1aa000, 1, RI_E1H_ONLINE }, { 0x1b8000, 1, RI_ALL_ONLINE }, + { 0x1b8040, 1, RI_ALL_ONLINE }, { 0x1b8080, 1, RI_ALL_ONLINE }, + { 0x1b80c0, 1, RI_ALL_ONLINE }, { 0x200104, 1, RI_ALL_ONLINE }, + { 0x200114, 1, RI_ALL_ONLINE }, { 0x200124, 1, RI_ALL_ONLINE }, + { 0x200134, 1, RI_ALL_ONLINE }, { 0x20026c, 1, RI_ALL_ONLINE }, + { 0x2002a0, 1, RI_ALL_ONLINE }, { 0x221000, 1, RI_ALL_ONLINE }, + { 0x227000, 1, RI_E1H_ONLINE }, { 0x238000, 1, RI_ALL_ONLINE }, + { 0x238040, 1, RI_ALL_ONLINE }, { 0x238080, 1, RI_ALL_ONLINE }, + { 0x2380c0, 1, RI_ALL_ONLINE }, { 0x280104, 1, RI_ALL_ONLINE }, + { 0x280114, 1, RI_ALL_ONLINE }, { 0x280124, 1, RI_ALL_ONLINE }, + { 0x280134, 1, RI_ALL_ONLINE }, { 0x28026c, 1, RI_ALL_ONLINE }, + { 0x2802a0, 1, RI_ALL_ONLINE }, { 0x2a1000, 1, RI_ALL_ONLINE }, + { 0x2a9000, 1, RI_E1H_ONLINE }, { 0x2b8000, 1, RI_ALL_ONLINE }, + { 0x2b8040, 1, RI_ALL_ONLINE }, { 0x2b8080, 1, RI_ALL_ONLINE }, + { 0x2b80c0, 1, RI_ALL_ONLINE }, { 0x300104, 1, RI_ALL_ONLINE }, + { 0x300114, 1, RI_ALL_ONLINE }, { 0x300124, 1, RI_ALL_ONLINE }, + { 0x300134, 1, RI_ALL_ONLINE }, { 0x30026c, 1, RI_ALL_ONLINE }, + { 0x3002a0, 1, RI_ALL_ONLINE }, { 0x321000, 1, RI_ALL_ONLINE }, + { 0x328960, 1, RI_E1H_ONLINE }, { 0x338000, 1, RI_ALL_ONLINE }, + { 0x338040, 1, RI_ALL_ONLINE }, { 0x338080, 1, RI_ALL_ONLINE }, + { 0x3380c0, 1, RI_ALL_ONLINE } }; +#define WREGS_COUNT_E1 1 static const u32 read_reg_e1_0[] = { 0x1b1000 }; -#define WREGS_COUNT_E1 1 static const struct wreg_addr wreg_addrs_e1[WREGS_COUNT_E1] = { { 0x1b0c00, 192, 1, read_reg_e1_0, RI_E1_OFFLINE } }; + +#define WREGS_COUNT_E1H 1 static const u32 read_reg_e1h_0[] = { 0x1b1040, 0x1b1000 }; -#define WREGS_COUNT_E1H 1 static const struct wreg_addr wreg_addrs_e1h[WREGS_COUNT_E1H] = { { 0x1b0c00, 256, 2, read_reg_e1h_0, RI_E1H_OFFLINE } }; @@ -512,15 +517,18 @@ static const struct wreg_addr wreg_addrs_e1h[WREGS_COUNT_E1H] = { static const struct dump_sign dump_sign_all = { 0x49aa93ee, 0x40835, 0x22 }; -#define TIMER_REGS_COUNT_E1 2 +#define TIMER_REGS_COUNT_E1 2 static const u32 timer_status_regs_e1[TIMER_REGS_COUNT_E1] = { 0x164014, 0x164018 }; static const u32 timer_scan_regs_e1[TIMER_REGS_COUNT_E1] = { 0x1640d0, 0x1640d4 }; -#define TIMER_REGS_COUNT_E1H 2 + +#define TIMER_REGS_COUNT_E1H 2 static const u32 timer_status_regs_e1h[TIMER_REGS_COUNT_E1H] = { 0x164014, 0x164018 }; static const u32 timer_scan_regs_e1h[TIMER_REGS_COUNT_E1H] = { 0x1640d0, 0x1640d4 }; + +#endif /* BNX2X_DUMP_H */ -- cgit v0.10.2 From 9c63de6293775b537614550fd61075a33ada9469 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:25 +0000 Subject: bnx2x: Removing unused definitions Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 1e6f5aa..95ebf3f 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -190,12 +190,6 @@ _(0..15) stands for the connection type (one of 16). */ #define CCM_REG_N_SM_CTX_LD_0 0xd004c #define CCM_REG_N_SM_CTX_LD_1 0xd0050 -#define CCM_REG_N_SM_CTX_LD_10 0xd0074 -#define CCM_REG_N_SM_CTX_LD_11 0xd0078 -#define CCM_REG_N_SM_CTX_LD_12 0xd007c -#define CCM_REG_N_SM_CTX_LD_13 0xd0080 -#define CCM_REG_N_SM_CTX_LD_14 0xd0084 -#define CCM_REG_N_SM_CTX_LD_15 0xd0088 #define CCM_REG_N_SM_CTX_LD_2 0xd0054 #define CCM_REG_N_SM_CTX_LD_3 0xd0058 #define CCM_REG_N_SM_CTX_LD_4 0xd005c @@ -622,24 +616,6 @@ #define DMAE_REG_GO_C1 0x102084 /* [RW 1] Command 10 go. */ #define DMAE_REG_GO_C10 0x102088 -#define DMAE_REG_GO_C10_SIZE 1 -/* [RW 1] Command 11 go. */ -#define DMAE_REG_GO_C11 0x10208c -#define DMAE_REG_GO_C11_SIZE 1 -/* [RW 1] Command 12 go. */ -#define DMAE_REG_GO_C12 0x102090 -#define DMAE_REG_GO_C12_SIZE 1 -/* [RW 1] Command 13 go. */ -#define DMAE_REG_GO_C13 0x102094 -#define DMAE_REG_GO_C13_SIZE 1 -/* [RW 1] Command 14 go. */ -#define DMAE_REG_GO_C14 0x102098 -#define DMAE_REG_GO_C14_SIZE 1 -/* [RW 1] Command 15 go. */ -#define DMAE_REG_GO_C15 0x10209c -#define DMAE_REG_GO_C15_SIZE 1 -/* [RW 1] Command 10 go. */ -#define DMAE_REG_GO_C10 0x102088 /* [RW 1] Command 11 go. */ #define DMAE_REG_GO_C11 0x10208c /* [RW 1] Command 12 go. */ @@ -789,7 +765,6 @@ #define MCP_REG_MCPR_NVM_READ 0x86410 #define MCP_REG_MCPR_NVM_SW_ARB 0x86420 #define MCP_REG_MCPR_NVM_WRITE 0x86408 -#define MCP_REG_MCPR_NVM_WRITE1 0x86428 #define MCP_REG_MCPR_SCRATCH 0xa0000 /* [R 32] read first 32 bit after inversion of function 0. mapped as follows: [0] NIG attention for function0; [1] NIG attention for @@ -1175,19 +1150,7 @@ #define MISC_REG_AEU_GENERAL_ATTN_10 0xa028 #define MISC_REG_AEU_GENERAL_ATTN_11 0xa02c #define MISC_REG_AEU_GENERAL_ATTN_12 0xa030 -#define MISC_REG_AEU_GENERAL_ATTN_13 0xa034 -#define MISC_REG_AEU_GENERAL_ATTN_14 0xa038 -#define MISC_REG_AEU_GENERAL_ATTN_15 0xa03c -#define MISC_REG_AEU_GENERAL_ATTN_16 0xa040 -#define MISC_REG_AEU_GENERAL_ATTN_17 0xa044 -#define MISC_REG_AEU_GENERAL_ATTN_18 0xa048 -#define MISC_REG_AEU_GENERAL_ATTN_19 0xa04c -#define MISC_REG_AEU_GENERAL_ATTN_10 0xa028 -#define MISC_REG_AEU_GENERAL_ATTN_11 0xa02c -#define MISC_REG_AEU_GENERAL_ATTN_12 0xa030 #define MISC_REG_AEU_GENERAL_ATTN_2 0xa008 -#define MISC_REG_AEU_GENERAL_ATTN_20 0xa050 -#define MISC_REG_AEU_GENERAL_ATTN_21 0xa054 #define MISC_REG_AEU_GENERAL_ATTN_3 0xa00c #define MISC_REG_AEU_GENERAL_ATTN_4 0xa010 #define MISC_REG_AEU_GENERAL_ATTN_5 0xa014 @@ -1279,133 +1242,7 @@ set. if the appropriate bit is clear (the driver request to free a client it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will be asserted). */ -#define MISC_REG_DRIVER_CONTROL_10 0xa3e0 -#define MISC_REG_DRIVER_CONTROL_10_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ -#define MISC_REG_DRIVER_CONTROL_11 0xa3e8 -#define MISC_REG_DRIVER_CONTROL_11_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ -#define MISC_REG_DRIVER_CONTROL_12 0xa3f0 -#define MISC_REG_DRIVER_CONTROL_12_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ -#define MISC_REG_DRIVER_CONTROL_13 0xa3f8 -#define MISC_REG_DRIVER_CONTROL_13_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ #define MISC_REG_DRIVER_CONTROL_1 0xa510 -#define MISC_REG_DRIVER_CONTROL_14 0xa5e0 -#define MISC_REG_DRIVER_CONTROL_14_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ -#define MISC_REG_DRIVER_CONTROL_15 0xa5e8 -#define MISC_REG_DRIVER_CONTROL_15_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ -#define MISC_REG_DRIVER_CONTROL_16 0xa5f0 -#define MISC_REG_DRIVER_CONTROL_16_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ #define MISC_REG_DRIVER_CONTROL_7 0xa3c8 /* [RW 1] e1hmf for WOL. If clr WOL signal o the PXP will be send on bit 0 only. */ @@ -1650,8 +1487,6 @@ /* [RW 1] MAC configuration for packets of port0. If 1 - all packet outputs to emac for port0; other way to bmac for port0 */ #define NIG_REG_EGRESS_EMAC0_PORT 0x10058 -/* [RW 32] TX_MNG_FIFO in NIG_TX_PORT0; data[31:0] written in FIFO order. */ -#define NIG_REG_EGRESS_MNG0_FIFO 0x1045c /* [RW 1] Input enable for TX PBF user packet port0 IF */ #define NIG_REG_EGRESS_PBF0_IN_EN 0x100cc /* [RW 1] Input enable for TX PBF user packet port1 IF */ @@ -2161,11 +1996,8 @@ #define PXP2_REG_PSWRQ_BW_ADD1 0x1201c0 #define PXP2_REG_PSWRQ_BW_ADD10 0x1201e4 #define PXP2_REG_PSWRQ_BW_ADD11 0x1201e8 -#define PXP2_REG_PSWRQ_BW_ADD10 0x1201e4 -#define PXP2_REG_PSWRQ_BW_ADD11 0x1201e8 #define PXP2_REG_PSWRQ_BW_ADD2 0x1201c4 #define PXP2_REG_PSWRQ_BW_ADD28 0x120228 -#define PXP2_REG_PSWRQ_BW_ADD28 0x120228 #define PXP2_REG_PSWRQ_BW_ADD3 0x1201c8 #define PXP2_REG_PSWRQ_BW_ADD6 0x1201d4 #define PXP2_REG_PSWRQ_BW_ADD7 0x1201d8 @@ -2175,11 +2007,8 @@ #define PXP2_REG_PSWRQ_BW_L1 0x1202b0 #define PXP2_REG_PSWRQ_BW_L10 0x1202d4 #define PXP2_REG_PSWRQ_BW_L11 0x1202d8 -#define PXP2_REG_PSWRQ_BW_L10 0x1202d4 -#define PXP2_REG_PSWRQ_BW_L11 0x1202d8 #define PXP2_REG_PSWRQ_BW_L2 0x1202b4 #define PXP2_REG_PSWRQ_BW_L28 0x120318 -#define PXP2_REG_PSWRQ_BW_L28 0x120318 #define PXP2_REG_PSWRQ_BW_L3 0x1202b8 #define PXP2_REG_PSWRQ_BW_L6 0x1202c4 #define PXP2_REG_PSWRQ_BW_L7 0x1202c8 @@ -2189,11 +2018,8 @@ #define PXP2_REG_PSWRQ_BW_UB1 0x120238 #define PXP2_REG_PSWRQ_BW_UB10 0x12025c #define PXP2_REG_PSWRQ_BW_UB11 0x120260 -#define PXP2_REG_PSWRQ_BW_UB10 0x12025c -#define PXP2_REG_PSWRQ_BW_UB11 0x120260 #define PXP2_REG_PSWRQ_BW_UB2 0x12023c #define PXP2_REG_PSWRQ_BW_UB28 0x1202a0 -#define PXP2_REG_PSWRQ_BW_UB28 0x1202a0 #define PXP2_REG_PSWRQ_BW_UB3 0x120240 #define PXP2_REG_PSWRQ_BW_UB6 0x12024c #define PXP2_REG_PSWRQ_BW_UB7 0x120250 @@ -2784,16 +2610,6 @@ #define QM_REG_QVOQIDX_107 0x16e4b8 #define QM_REG_QVOQIDX_108 0x16e4bc #define QM_REG_QVOQIDX_109 0x16e4c0 -#define QM_REG_QVOQIDX_100 0x16e49c -#define QM_REG_QVOQIDX_101 0x16e4a0 -#define QM_REG_QVOQIDX_102 0x16e4a4 -#define QM_REG_QVOQIDX_103 0x16e4a8 -#define QM_REG_QVOQIDX_104 0x16e4ac -#define QM_REG_QVOQIDX_105 0x16e4b0 -#define QM_REG_QVOQIDX_106 0x16e4b4 -#define QM_REG_QVOQIDX_107 0x16e4b8 -#define QM_REG_QVOQIDX_108 0x16e4bc -#define QM_REG_QVOQIDX_109 0x16e4c0 #define QM_REG_QVOQIDX_11 0x168120 #define QM_REG_QVOQIDX_110 0x16e4c4 #define QM_REG_QVOQIDX_111 0x16e4c8 @@ -2805,16 +2621,6 @@ #define QM_REG_QVOQIDX_117 0x16e4e0 #define QM_REG_QVOQIDX_118 0x16e4e4 #define QM_REG_QVOQIDX_119 0x16e4e8 -#define QM_REG_QVOQIDX_110 0x16e4c4 -#define QM_REG_QVOQIDX_111 0x16e4c8 -#define QM_REG_QVOQIDX_112 0x16e4cc -#define QM_REG_QVOQIDX_113 0x16e4d0 -#define QM_REG_QVOQIDX_114 0x16e4d4 -#define QM_REG_QVOQIDX_115 0x16e4d8 -#define QM_REG_QVOQIDX_116 0x16e4dc -#define QM_REG_QVOQIDX_117 0x16e4e0 -#define QM_REG_QVOQIDX_118 0x16e4e4 -#define QM_REG_QVOQIDX_119 0x16e4e8 #define QM_REG_QVOQIDX_12 0x168124 #define QM_REG_QVOQIDX_120 0x16e4ec #define QM_REG_QVOQIDX_121 0x16e4f0 @@ -2824,14 +2630,6 @@ #define QM_REG_QVOQIDX_125 0x16e500 #define QM_REG_QVOQIDX_126 0x16e504 #define QM_REG_QVOQIDX_127 0x16e508 -#define QM_REG_QVOQIDX_120 0x16e4ec -#define QM_REG_QVOQIDX_121 0x16e4f0 -#define QM_REG_QVOQIDX_122 0x16e4f4 -#define QM_REG_QVOQIDX_123 0x16e4f8 -#define QM_REG_QVOQIDX_124 0x16e4fc -#define QM_REG_QVOQIDX_125 0x16e500 -#define QM_REG_QVOQIDX_126 0x16e504 -#define QM_REG_QVOQIDX_127 0x16e508 #define QM_REG_QVOQIDX_13 0x168128 #define QM_REG_QVOQIDX_14 0x16812c #define QM_REG_QVOQIDX_15 0x168130 @@ -2877,16 +2675,6 @@ #define QM_REG_QVOQIDX_57 0x1681d8 #define QM_REG_QVOQIDX_58 0x1681dc #define QM_REG_QVOQIDX_59 0x1681e0 -#define QM_REG_QVOQIDX_50 0x1681bc -#define QM_REG_QVOQIDX_51 0x1681c0 -#define QM_REG_QVOQIDX_52 0x1681c4 -#define QM_REG_QVOQIDX_53 0x1681c8 -#define QM_REG_QVOQIDX_54 0x1681cc -#define QM_REG_QVOQIDX_55 0x1681d0 -#define QM_REG_QVOQIDX_56 0x1681d4 -#define QM_REG_QVOQIDX_57 0x1681d8 -#define QM_REG_QVOQIDX_58 0x1681dc -#define QM_REG_QVOQIDX_59 0x1681e0 #define QM_REG_QVOQIDX_6 0x16810c #define QM_REG_QVOQIDX_60 0x1681e4 #define QM_REG_QVOQIDX_61 0x1681e8 @@ -2894,16 +2682,6 @@ #define QM_REG_QVOQIDX_63 0x1681f0 #define QM_REG_QVOQIDX_64 0x16e40c #define QM_REG_QVOQIDX_65 0x16e410 -#define QM_REG_QVOQIDX_66 0x16e414 -#define QM_REG_QVOQIDX_67 0x16e418 -#define QM_REG_QVOQIDX_68 0x16e41c -#define QM_REG_QVOQIDX_69 0x16e420 -#define QM_REG_QVOQIDX_60 0x1681e4 -#define QM_REG_QVOQIDX_61 0x1681e8 -#define QM_REG_QVOQIDX_62 0x1681ec -#define QM_REG_QVOQIDX_63 0x1681f0 -#define QM_REG_QVOQIDX_64 0x16e40c -#define QM_REG_QVOQIDX_65 0x16e410 #define QM_REG_QVOQIDX_69 0x16e420 #define QM_REG_QVOQIDX_7 0x168110 #define QM_REG_QVOQIDX_70 0x16e424 @@ -2916,29 +2694,9 @@ #define QM_REG_QVOQIDX_77 0x16e440 #define QM_REG_QVOQIDX_78 0x16e444 #define QM_REG_QVOQIDX_79 0x16e448 -#define QM_REG_QVOQIDX_70 0x16e424 -#define QM_REG_QVOQIDX_71 0x16e428 -#define QM_REG_QVOQIDX_72 0x16e42c -#define QM_REG_QVOQIDX_73 0x16e430 -#define QM_REG_QVOQIDX_74 0x16e434 -#define QM_REG_QVOQIDX_75 0x16e438 -#define QM_REG_QVOQIDX_76 0x16e43c -#define QM_REG_QVOQIDX_77 0x16e440 -#define QM_REG_QVOQIDX_78 0x16e444 -#define QM_REG_QVOQIDX_79 0x16e448 #define QM_REG_QVOQIDX_8 0x168114 #define QM_REG_QVOQIDX_80 0x16e44c #define QM_REG_QVOQIDX_81 0x16e450 -#define QM_REG_QVOQIDX_82 0x16e454 -#define QM_REG_QVOQIDX_83 0x16e458 -#define QM_REG_QVOQIDX_84 0x16e45c -#define QM_REG_QVOQIDX_85 0x16e460 -#define QM_REG_QVOQIDX_86 0x16e464 -#define QM_REG_QVOQIDX_87 0x16e468 -#define QM_REG_QVOQIDX_88 0x16e46c -#define QM_REG_QVOQIDX_89 0x16e470 -#define QM_REG_QVOQIDX_80 0x16e44c -#define QM_REG_QVOQIDX_81 0x16e450 #define QM_REG_QVOQIDX_85 0x16e460 #define QM_REG_QVOQIDX_86 0x16e464 #define QM_REG_QVOQIDX_87 0x16e468 @@ -2955,23 +2713,11 @@ #define QM_REG_QVOQIDX_97 0x16e490 #define QM_REG_QVOQIDX_98 0x16e494 #define QM_REG_QVOQIDX_99 0x16e498 -#define QM_REG_QVOQIDX_90 0x16e474 -#define QM_REG_QVOQIDX_91 0x16e478 -#define QM_REG_QVOQIDX_92 0x16e47c -#define QM_REG_QVOQIDX_93 0x16e480 -#define QM_REG_QVOQIDX_94 0x16e484 -#define QM_REG_QVOQIDX_95 0x16e488 -#define QM_REG_QVOQIDX_96 0x16e48c -#define QM_REG_QVOQIDX_97 0x16e490 -#define QM_REG_QVOQIDX_98 0x16e494 -#define QM_REG_QVOQIDX_99 0x16e498 /* [RW 1] Initialization bit command */ #define QM_REG_SOFT_RESET 0x168428 /* [RW 8] The credit cost per every task in the QM. A value per each VOQ */ #define QM_REG_TASKCRDCOST_0 0x16809c #define QM_REG_TASKCRDCOST_1 0x1680a0 -#define QM_REG_TASKCRDCOST_10 0x1680c4 -#define QM_REG_TASKCRDCOST_11 0x1680c8 #define QM_REG_TASKCRDCOST_2 0x1680a4 #define QM_REG_TASKCRDCOST_4 0x1680ac #define QM_REG_TASKCRDCOST_5 0x1680b0 @@ -2984,24 +2730,18 @@ /* [R 16] The credit value for each VOQ */ #define QM_REG_VOQCREDIT_0 0x1682d0 #define QM_REG_VOQCREDIT_1 0x1682d4 -#define QM_REG_VOQCREDIT_10 0x1682f8 -#define QM_REG_VOQCREDIT_11 0x1682fc #define QM_REG_VOQCREDIT_4 0x1682e0 /* [RW 16] The credit value that if above the QM is considered almost full */ #define QM_REG_VOQCREDITAFULLTHR 0x168090 /* [RW 16] The init and maximum credit for each VoQ */ #define QM_REG_VOQINITCREDIT_0 0x168060 #define QM_REG_VOQINITCREDIT_1 0x168064 -#define QM_REG_VOQINITCREDIT_10 0x168088 -#define QM_REG_VOQINITCREDIT_11 0x16808c #define QM_REG_VOQINITCREDIT_2 0x168068 #define QM_REG_VOQINITCREDIT_4 0x168070 #define QM_REG_VOQINITCREDIT_5 0x168074 /* [RW 1] The port of which VOQ belongs */ #define QM_REG_VOQPORT_0 0x1682a0 #define QM_REG_VOQPORT_1 0x1682a4 -#define QM_REG_VOQPORT_10 0x1682c8 -#define QM_REG_VOQPORT_11 0x1682cc #define QM_REG_VOQPORT_2 0x1682a8 /* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ #define QM_REG_VOQQMASK_0_LSB 0x168240 @@ -3099,36 +2839,6 @@ #define QM_REG_WRRWEIGHTS_0 0x16880c #define QM_REG_WRRWEIGHTS_1 0x168810 #define QM_REG_WRRWEIGHTS_10 0x168814 -#define QM_REG_WRRWEIGHTS_10_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_11 0x168818 -#define QM_REG_WRRWEIGHTS_11_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_12 0x16881c -#define QM_REG_WRRWEIGHTS_12_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_13 0x168820 -#define QM_REG_WRRWEIGHTS_13_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_14 0x168824 -#define QM_REG_WRRWEIGHTS_14_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_15 0x168828 -#define QM_REG_WRRWEIGHTS_15_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_16 0x16e000 -#define QM_REG_WRRWEIGHTS_16_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_17 0x16e004 -#define QM_REG_WRRWEIGHTS_17_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_18 0x16e008 -#define QM_REG_WRRWEIGHTS_18_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_19 0x16e00c -#define QM_REG_WRRWEIGHTS_19_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_10 0x168814 #define QM_REG_WRRWEIGHTS_11 0x168818 #define QM_REG_WRRWEIGHTS_12 0x16881c #define QM_REG_WRRWEIGHTS_13 0x168820 @@ -3140,36 +2850,6 @@ #define QM_REG_WRRWEIGHTS_19 0x16e00c #define QM_REG_WRRWEIGHTS_2 0x16882c #define QM_REG_WRRWEIGHTS_20 0x16e010 -#define QM_REG_WRRWEIGHTS_20_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_21 0x16e014 -#define QM_REG_WRRWEIGHTS_21_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_22 0x16e018 -#define QM_REG_WRRWEIGHTS_22_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_23 0x16e01c -#define QM_REG_WRRWEIGHTS_23_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_24 0x16e020 -#define QM_REG_WRRWEIGHTS_24_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_25 0x16e024 -#define QM_REG_WRRWEIGHTS_25_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_26 0x16e028 -#define QM_REG_WRRWEIGHTS_26_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_27 0x16e02c -#define QM_REG_WRRWEIGHTS_27_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_28 0x16e030 -#define QM_REG_WRRWEIGHTS_28_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_29 0x16e034 -#define QM_REG_WRRWEIGHTS_29_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_20 0x16e010 #define QM_REG_WRRWEIGHTS_21 0x16e014 #define QM_REG_WRRWEIGHTS_22 0x16e018 #define QM_REG_WRRWEIGHTS_23 0x16e01c @@ -3181,12 +2861,6 @@ #define QM_REG_WRRWEIGHTS_29 0x16e034 #define QM_REG_WRRWEIGHTS_3 0x168830 #define QM_REG_WRRWEIGHTS_30 0x16e038 -#define QM_REG_WRRWEIGHTS_30_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_31 0x16e03c -#define QM_REG_WRRWEIGHTS_31_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_30 0x16e038 #define QM_REG_WRRWEIGHTS_31 0x16e03c #define QM_REG_WRRWEIGHTS_4 0x168834 #define QM_REG_WRRWEIGHTS_5 0x168838 @@ -3196,362 +2870,6 @@ #define QM_REG_WRRWEIGHTS_9 0x168848 /* [R 6] Keep the fill level of the fifo from write client 1 */ #define QM_REG_XQM_WRC_FIFOLVL 0x168000 -#define BRB1_BRB1_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define BRB1_BRB1_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define BRB1_BRB1_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define BRB1_BRB1_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define BRB1_BRB1_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define BRB1_BRB1_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define BRB1_BRB1_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define BRB1_BRB1_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define CCM_CCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define CCM_CCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define CCM_CCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define CCM_CCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define CCM_CCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define CCM_CCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define CCM_CCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define CCM_CCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define CDU_CDU_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define CDU_CDU_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define CDU_CDU_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define CDU_CDU_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define CDU_CDU_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define CDU_CDU_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define CDU_CDU_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define CDU_CDU_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define CFC_CFC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define CFC_CFC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define CFC_CFC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define CFC_CFC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define CFC_CFC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define CFC_CFC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define CFC_CFC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define CFC_CFC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define CSDM_CSDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSDM_CSDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSDM_CSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSDM_CSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSDM_CSDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSDM_CSDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSDM_CSDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSDM_CSDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSEM_CSEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSEM_CSEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSEM_CSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSEM_CSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSEM_CSEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSEM_CSEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSEM_CSEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSEM_CSEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define DBG_DBG_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define DBG_DBG_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define DBG_DBG_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define DBG_DBG_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define DBG_DBG_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define DBG_DBG_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define DBG_DBG_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define DBG_DBG_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define DMAE_DMAE_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define DMAE_DMAE_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define DMAE_DMAE_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define DMAE_DMAE_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define DMAE_DMAE_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define DMAE_DMAE_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define DMAE_DMAE_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define DMAE_DMAE_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define DORQ_DORQ_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define DORQ_DORQ_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define DORQ_DORQ_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define DORQ_DORQ_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define DORQ_DORQ_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define DORQ_DORQ_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define DORQ_DORQ_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define DORQ_DORQ_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define HC_HC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define HC_HC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define HC_HC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define HC_HC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define HC_HC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define HC_HC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define HC_HC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define HC_HC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define MISC_MISC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define MISC_MISC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define MISC_MISC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define MISC_MISC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define MISC_MISC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define MISC_MISC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define MISC_MISC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define MISC_MISC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define NIG_NIG_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define NIG_NIG_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define NIG_NIG_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define NIG_NIG_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define NIG_NIG_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define NIG_NIG_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define NIG_NIG_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define NIG_NIG_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define PBF_PBF_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define PBF_PBF_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define PBF_PBF_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define PBF_PBF_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define PBF_PBF_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define PBF_PBF_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define PBF_PBF_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define PBF_PBF_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define PB_PB_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define PB_PB_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define PB_PB_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define PB_PB_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define PB_PB_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define PB_PB_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define PB_PB_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define PB_PB_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define PRS_PRS_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define PRS_PRS_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define PRS_PRS_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define PRS_PRS_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define PRS_PRS_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define PRS_PRS_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define PRS_PRS_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define PRS_PRS_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define PXP2_PXP2_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP2_PXP2_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP2_PXP2_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP2_PXP2_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP2_PXP2_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP2_PXP2_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP2_PXP2_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP2_PXP2_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP_PXP_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP_PXP_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP_PXP_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP_PXP_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP_PXP_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP_PXP_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP_PXP_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP_PXP_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define QM_QM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define QM_QM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define QM_QM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define QM_QM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define QM_QM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define QM_QM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define QM_QM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define QM_QM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define SEM_FAST_SEM_FAST_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define SEM_FAST_SEM_FAST_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define SEM_FAST_SEM_FAST_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define SEM_FAST_SEM_FAST_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define SEM_FAST_SEM_FAST_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define SEM_FAST_SEM_FAST_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define SEM_FAST_SEM_FAST_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define SEM_FAST_SEM_FAST_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define SRC_SRC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define SRC_SRC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define SRC_SRC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define SRC_SRC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define SRC_SRC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define SRC_SRC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define SRC_SRC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define SRC_SRC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define TCM_TCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define TCM_TCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define TCM_TCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define TCM_TCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define TCM_TCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define TCM_TCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define TCM_TCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define TCM_TCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define TM_TM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define TM_TM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define TM_TM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define TM_TM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define TM_TM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define TM_TM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define TM_TM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define TM_TM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define TSDM_TSDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSDM_TSDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSDM_TSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSDM_TSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSDM_TSDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSDM_TSDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSDM_TSDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSDM_TSDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSEM_TSEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSEM_TSEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSEM_TSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSEM_TSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSEM_TSEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSEM_TSEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSEM_TSEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSEM_TSEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define UCM_UCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define UCM_UCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define UCM_UCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define UCM_UCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define UCM_UCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define UCM_UCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define UCM_UCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define UCM_UCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define USDM_USDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define USDM_USDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define USDM_USDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define USDM_USDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define USDM_USDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define USDM_USDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define USDM_USDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define USDM_USDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define USEM_USEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define USEM_USEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define USEM_USEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define USEM_USEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define USEM_USEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define USEM_USEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define USEM_USEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define USEM_USEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define XCM_XCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define XCM_XCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define XCM_XCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define XCM_XCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define XCM_XCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define XCM_XCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define XCM_XCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define XCM_XCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define XSDM_XSDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSDM_XSDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSDM_XSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSDM_XSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSDM_XSDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSDM_XSDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSDM_XSDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSDM_XSDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSEM_XSEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSEM_XSEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSEM_XSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSEM_XSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSEM_XSEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSEM_XSEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSEM_XSEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSEM_XSEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define CFC_DEBUG1_REG_WRITE_AC (0x1<<4) -#define CFC_DEBUG1_REG_WRITE_AC_SIZE 4 -/* [R 1] debug only: This bit indicates whether indicates that external - buffer was wrapped (oldest data was thrown); Relevant only when - ~dbg_registers_debug_target=2 (PCI) & ~dbg_registers_full_mode=1 (wrap); */ -#define DBG_REG_WRAP_ON_EXT_BUFFER 0xc124 -#define DBG_REG_WRAP_ON_EXT_BUFFER_SIZE 1 -/* [R 1] debug only: This bit indicates whether the internal buffer was - wrapped (oldest data was thrown) Relevant only when - ~dbg_registers_debug_target=0 (internal buffer) */ -#define DBG_REG_WRAP_ON_INT_BUFFER 0xc128 -#define DBG_REG_WRAP_ON_INT_BUFFER_SIZE 1 -#define QM_QM_PRTY_STS_REG_WRBUFF (0x1<<8) -#define QM_QM_PRTY_STS_REG_WRBUFF_SIZE 8 -#define QM_QM_PRTY_STS_CLR_REG_WRBUFF (0x1<<8) -#define QM_QM_PRTY_STS_CLR_REG_WRBUFF_SIZE 8 -#define QM_QM_PRTY_STS_WR_REG_WRBUFF (0x1<<8) -#define QM_QM_PRTY_STS_WR_REG_WRBUFF_SIZE 8 -#define QM_QM_PRTY_MASK_REG_WRBUFF (0x1<<8) -#define QM_QM_PRTY_MASK_REG_WRBUFF_SIZE 8 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_0 0x16880c -#define QM_REG_WRRWEIGHTS_0_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_1 0x168810 -#define QM_REG_WRRWEIGHTS_1_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_10 0x168814 -#define QM_REG_WRRWEIGHTS_10_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_11 0x168818 -#define QM_REG_WRRWEIGHTS_11_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_12 0x16881c -#define QM_REG_WRRWEIGHTS_12_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_13 0x168820 -#define QM_REG_WRRWEIGHTS_13_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_14 0x168824 -#define QM_REG_WRRWEIGHTS_14_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_15 0x168828 -#define QM_REG_WRRWEIGHTS_15_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_2 0x16882c -#define QM_REG_WRRWEIGHTS_2_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_3 0x168830 -#define QM_REG_WRRWEIGHTS_3_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_4 0x168834 -#define QM_REG_WRRWEIGHTS_4_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_5 0x168838 -#define QM_REG_WRRWEIGHTS_5_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_6 0x16883c -#define QM_REG_WRRWEIGHTS_6_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_7 0x168840 -#define QM_REG_WRRWEIGHTS_7_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_8 0x168844 -#define QM_REG_WRRWEIGHTS_8_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_9 0x168848 -#define QM_REG_WRRWEIGHTS_9_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_16 0x16e000 -#define QM_REG_WRRWEIGHTS_16_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_17 0x16e004 -#define QM_REG_WRRWEIGHTS_17_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_18 0x16e008 -#define QM_REG_WRRWEIGHTS_18_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_19 0x16e00c -#define QM_REG_WRRWEIGHTS_19_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_20 0x16e010 -#define QM_REG_WRRWEIGHTS_20_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_21 0x16e014 -#define QM_REG_WRRWEIGHTS_21_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_22 0x16e018 -#define QM_REG_WRRWEIGHTS_22_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_23 0x16e01c -#define QM_REG_WRRWEIGHTS_23_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_24 0x16e020 -#define QM_REG_WRRWEIGHTS_24_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_25 0x16e024 -#define QM_REG_WRRWEIGHTS_25_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_26 0x16e028 -#define QM_REG_WRRWEIGHTS_26_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_27 0x16e02c -#define QM_REG_WRRWEIGHTS_27_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_28 0x16e030 -#define QM_REG_WRRWEIGHTS_28_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_29 0x16e034 -#define QM_REG_WRRWEIGHTS_29_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_30 0x16e038 -#define QM_REG_WRRWEIGHTS_30_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_31 0x16e03c -#define QM_REG_WRRWEIGHTS_31_SIZE 1 #define SRC_REG_COUNTFREE0 0x40500 /* [RW 1] If clr the searcher is compatible to E1 A0 - support only two ports. If set the searcher support 8 functions. */ @@ -3651,12 +2969,6 @@ type (one of 16). */ #define TCM_REG_N_SM_CTX_LD_0 0x50050 #define TCM_REG_N_SM_CTX_LD_1 0x50054 -#define TCM_REG_N_SM_CTX_LD_10 0x50078 -#define TCM_REG_N_SM_CTX_LD_11 0x5007c -#define TCM_REG_N_SM_CTX_LD_12 0x50080 -#define TCM_REG_N_SM_CTX_LD_13 0x50084 -#define TCM_REG_N_SM_CTX_LD_14 0x50088 -#define TCM_REG_N_SM_CTX_LD_15 0x5008c #define TCM_REG_N_SM_CTX_LD_2 0x50058 #define TCM_REG_N_SM_CTX_LD_3 0x5005c #define TCM_REG_N_SM_CTX_LD_4 0x50060 @@ -3863,8 +3175,6 @@ #define TM_REG_LIN_SETCLR_FIFO_ALFULL_THR 0x164070 /* [RW 2] Load value for pci arbiter credit cnt. */ #define TM_REG_PCIARB_CRDCNT_VAL 0x164260 -/* [RW 1] Timer software reset - active high. */ -#define TM_REG_TIMER_SOFT_RST 0x164004 /* [RW 20] The amount of hardware cycles for each timer tick. */ #define TM_REG_TIMER_TICK_SIZE 0x16401c /* [RW 8] Timers Context region. */ @@ -3876,44 +3186,12 @@ /* [RW 8] The event id for aggregated interrupt 0 */ #define TSDM_REG_AGG_INT_EVENT_0 0x42038 #define TSDM_REG_AGG_INT_EVENT_1 0x4203c -#define TSDM_REG_AGG_INT_EVENT_10 0x42060 -#define TSDM_REG_AGG_INT_EVENT_11 0x42064 -#define TSDM_REG_AGG_INT_EVENT_12 0x42068 -#define TSDM_REG_AGG_INT_EVENT_13 0x4206c -#define TSDM_REG_AGG_INT_EVENT_14 0x42070 -#define TSDM_REG_AGG_INT_EVENT_15 0x42074 -#define TSDM_REG_AGG_INT_EVENT_16 0x42078 -#define TSDM_REG_AGG_INT_EVENT_17 0x4207c -#define TSDM_REG_AGG_INT_EVENT_18 0x42080 -#define TSDM_REG_AGG_INT_EVENT_19 0x42084 #define TSDM_REG_AGG_INT_EVENT_2 0x42040 -#define TSDM_REG_AGG_INT_EVENT_20 0x42088 -#define TSDM_REG_AGG_INT_EVENT_21 0x4208c -#define TSDM_REG_AGG_INT_EVENT_22 0x42090 -#define TSDM_REG_AGG_INT_EVENT_23 0x42094 -#define TSDM_REG_AGG_INT_EVENT_24 0x42098 -#define TSDM_REG_AGG_INT_EVENT_25 0x4209c -#define TSDM_REG_AGG_INT_EVENT_26 0x420a0 -#define TSDM_REG_AGG_INT_EVENT_27 0x420a4 -#define TSDM_REG_AGG_INT_EVENT_28 0x420a8 -#define TSDM_REG_AGG_INT_EVENT_29 0x420ac #define TSDM_REG_AGG_INT_EVENT_3 0x42044 -#define TSDM_REG_AGG_INT_EVENT_30 0x420b0 -#define TSDM_REG_AGG_INT_EVENT_31 0x420b4 #define TSDM_REG_AGG_INT_EVENT_4 0x42048 /* [RW 1] The T bit for aggregated interrupt 0 */ #define TSDM_REG_AGG_INT_T_0 0x420b8 #define TSDM_REG_AGG_INT_T_1 0x420bc -#define TSDM_REG_AGG_INT_T_10 0x420e0 -#define TSDM_REG_AGG_INT_T_11 0x420e4 -#define TSDM_REG_AGG_INT_T_12 0x420e8 -#define TSDM_REG_AGG_INT_T_13 0x420ec -#define TSDM_REG_AGG_INT_T_14 0x420f0 -#define TSDM_REG_AGG_INT_T_15 0x420f4 -#define TSDM_REG_AGG_INT_T_16 0x420f8 -#define TSDM_REG_AGG_INT_T_17 0x420fc -#define TSDM_REG_AGG_INT_T_18 0x42100 -#define TSDM_REG_AGG_INT_T_19 0x42104 /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define TSDM_REG_CFC_RSP_START_ADDR 0x42008 /* [RW 16] The maximum value of the competion counter #0 */ @@ -4198,12 +3476,6 @@ connection type (one of 16). */ #define UCM_REG_N_SM_CTX_LD_0 0xe0054 #define UCM_REG_N_SM_CTX_LD_1 0xe0058 -#define UCM_REG_N_SM_CTX_LD_10 0xe007c -#define UCM_REG_N_SM_CTX_LD_11 0xe0080 -#define UCM_REG_N_SM_CTX_LD_12 0xe0084 -#define UCM_REG_N_SM_CTX_LD_13 0xe0088 -#define UCM_REG_N_SM_CTX_LD_14 0xe008c -#define UCM_REG_N_SM_CTX_LD_15 0xe0090 #define UCM_REG_N_SM_CTX_LD_2 0xe005c #define UCM_REG_N_SM_CTX_LD_3 0xe0060 #define UCM_REG_N_SM_CTX_LD_4 0xe0064 @@ -4353,30 +3625,7 @@ /* [RW 8] The event id for aggregated interrupt 0 */ #define USDM_REG_AGG_INT_EVENT_0 0xc4038 #define USDM_REG_AGG_INT_EVENT_1 0xc403c -#define USDM_REG_AGG_INT_EVENT_10 0xc4060 -#define USDM_REG_AGG_INT_EVENT_11 0xc4064 -#define USDM_REG_AGG_INT_EVENT_12 0xc4068 -#define USDM_REG_AGG_INT_EVENT_13 0xc406c -#define USDM_REG_AGG_INT_EVENT_14 0xc4070 -#define USDM_REG_AGG_INT_EVENT_15 0xc4074 -#define USDM_REG_AGG_INT_EVENT_16 0xc4078 -#define USDM_REG_AGG_INT_EVENT_17 0xc407c -#define USDM_REG_AGG_INT_EVENT_18 0xc4080 -#define USDM_REG_AGG_INT_EVENT_19 0xc4084 #define USDM_REG_AGG_INT_EVENT_2 0xc4040 -#define USDM_REG_AGG_INT_EVENT_20 0xc4088 -#define USDM_REG_AGG_INT_EVENT_21 0xc408c -#define USDM_REG_AGG_INT_EVENT_22 0xc4090 -#define USDM_REG_AGG_INT_EVENT_23 0xc4094 -#define USDM_REG_AGG_INT_EVENT_24 0xc4098 -#define USDM_REG_AGG_INT_EVENT_25 0xc409c -#define USDM_REG_AGG_INT_EVENT_26 0xc40a0 -#define USDM_REG_AGG_INT_EVENT_27 0xc40a4 -#define USDM_REG_AGG_INT_EVENT_28 0xc40a8 -#define USDM_REG_AGG_INT_EVENT_29 0xc40ac -#define USDM_REG_AGG_INT_EVENT_3 0xc4044 -#define USDM_REG_AGG_INT_EVENT_30 0xc40b0 -#define USDM_REG_AGG_INT_EVENT_31 0xc40b4 #define USDM_REG_AGG_INT_EVENT_4 0xc4048 #define USDM_REG_AGG_INT_EVENT_5 0xc404c #define USDM_REG_AGG_INT_EVENT_6 0xc4050 @@ -4384,16 +3633,6 @@ or auto-mask-mode (1) */ #define USDM_REG_AGG_INT_MODE_0 0xc41b8 #define USDM_REG_AGG_INT_MODE_1 0xc41bc -#define USDM_REG_AGG_INT_MODE_10 0xc41e0 -#define USDM_REG_AGG_INT_MODE_11 0xc41e4 -#define USDM_REG_AGG_INT_MODE_12 0xc41e8 -#define USDM_REG_AGG_INT_MODE_13 0xc41ec -#define USDM_REG_AGG_INT_MODE_14 0xc41f0 -#define USDM_REG_AGG_INT_MODE_15 0xc41f4 -#define USDM_REG_AGG_INT_MODE_16 0xc41f8 -#define USDM_REG_AGG_INT_MODE_17 0xc41fc -#define USDM_REG_AGG_INT_MODE_18 0xc4200 -#define USDM_REG_AGG_INT_MODE_19 0xc4204 #define USDM_REG_AGG_INT_MODE_4 0xc41c8 #define USDM_REG_AGG_INT_MODE_5 0xc41cc #define USDM_REG_AGG_INT_MODE_6 0xc41d0 @@ -4703,10 +3942,6 @@ /* [RC 1] Set at message length mismatch (relative to last indication) at the nig1 interface. */ #define XCM_REG_NIG1_LENGTH_MIS 0x2023c -/* [RW 3] The weight of the input nig1 in the WRR mechanism. 0 stands for - weight 8 (the most prioritised); 1 stands for weight 1(least - prioritised); 2 stands for weight 2; tc. */ -#define XCM_REG_NIG1_WEIGHT 0x200d8 /* [RW 5] The number of double REG-pairs; loaded from the STORM context and sent to STORM; for a specific connection type. The double REG-pairs are used in order to align to STORM context row size of 128 bits. The offset @@ -4714,12 +3949,6 @@ connection type (one of 16). */ #define XCM_REG_N_SM_CTX_LD_0 0x20060 #define XCM_REG_N_SM_CTX_LD_1 0x20064 -#define XCM_REG_N_SM_CTX_LD_10 0x20088 -#define XCM_REG_N_SM_CTX_LD_11 0x2008c -#define XCM_REG_N_SM_CTX_LD_12 0x20090 -#define XCM_REG_N_SM_CTX_LD_13 0x20094 -#define XCM_REG_N_SM_CTX_LD_14 0x20098 -#define XCM_REG_N_SM_CTX_LD_15 0x2009c #define XCM_REG_N_SM_CTX_LD_2 0x20068 #define XCM_REG_N_SM_CTX_LD_3 0x2006c #define XCM_REG_N_SM_CTX_LD_4 0x20070 @@ -4896,30 +4125,8 @@ #define XSDM_REG_AGG_INT_EVENT_12 0x166068 #define XSDM_REG_AGG_INT_EVENT_13 0x16606c #define XSDM_REG_AGG_INT_EVENT_14 0x166070 -#define XSDM_REG_AGG_INT_EVENT_15 0x166074 -#define XSDM_REG_AGG_INT_EVENT_16 0x166078 -#define XSDM_REG_AGG_INT_EVENT_17 0x16607c -#define XSDM_REG_AGG_INT_EVENT_18 0x166080 -#define XSDM_REG_AGG_INT_EVENT_19 0x166084 -#define XSDM_REG_AGG_INT_EVENT_10 0x166060 -#define XSDM_REG_AGG_INT_EVENT_11 0x166064 -#define XSDM_REG_AGG_INT_EVENT_12 0x166068 -#define XSDM_REG_AGG_INT_EVENT_13 0x16606c -#define XSDM_REG_AGG_INT_EVENT_14 0x166070 #define XSDM_REG_AGG_INT_EVENT_2 0x166040 -#define XSDM_REG_AGG_INT_EVENT_20 0x166088 -#define XSDM_REG_AGG_INT_EVENT_21 0x16608c -#define XSDM_REG_AGG_INT_EVENT_22 0x166090 -#define XSDM_REG_AGG_INT_EVENT_23 0x166094 -#define XSDM_REG_AGG_INT_EVENT_24 0x166098 -#define XSDM_REG_AGG_INT_EVENT_25 0x16609c -#define XSDM_REG_AGG_INT_EVENT_26 0x1660a0 -#define XSDM_REG_AGG_INT_EVENT_27 0x1660a4 -#define XSDM_REG_AGG_INT_EVENT_28 0x1660a8 -#define XSDM_REG_AGG_INT_EVENT_29 0x1660ac #define XSDM_REG_AGG_INT_EVENT_3 0x166044 -#define XSDM_REG_AGG_INT_EVENT_30 0x1660b0 -#define XSDM_REG_AGG_INT_EVENT_31 0x1660b4 #define XSDM_REG_AGG_INT_EVENT_4 0x166048 #define XSDM_REG_AGG_INT_EVENT_5 0x16604c #define XSDM_REG_AGG_INT_EVENT_6 0x166050 @@ -4930,16 +4137,6 @@ or auto-mask-mode (1) */ #define XSDM_REG_AGG_INT_MODE_0 0x1661b8 #define XSDM_REG_AGG_INT_MODE_1 0x1661bc -#define XSDM_REG_AGG_INT_MODE_10 0x1661e0 -#define XSDM_REG_AGG_INT_MODE_11 0x1661e4 -#define XSDM_REG_AGG_INT_MODE_12 0x1661e8 -#define XSDM_REG_AGG_INT_MODE_13 0x1661ec -#define XSDM_REG_AGG_INT_MODE_14 0x1661f0 -#define XSDM_REG_AGG_INT_MODE_15 0x1661f4 -#define XSDM_REG_AGG_INT_MODE_16 0x1661f8 -#define XSDM_REG_AGG_INT_MODE_17 0x1661fc -#define XSDM_REG_AGG_INT_MODE_18 0x166200 -#define XSDM_REG_AGG_INT_MODE_19 0x166204 /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define XSDM_REG_CFC_RSP_START_ADDR 0x166008 /* [RW 16] The maximum value of the competion counter #0 */ @@ -5147,10 +4344,6 @@ #define MCPR_NVM_COMMAND_FIRST (1L<<7) #define MCPR_NVM_COMMAND_LAST (1L<<8) #define MCPR_NVM_COMMAND_WR (1L<<5) -#define MCPR_NVM_COMMAND_WREN (1L<<16) -#define MCPR_NVM_COMMAND_WREN_BITSHIFT 16 -#define MCPR_NVM_COMMAND_WRDI (1L<<17) -#define MCPR_NVM_COMMAND_WRDI_BITSHIFT 17 #define MCPR_NVM_SW_ARB_ARB_ARB1 (1L<<9) #define MCPR_NVM_SW_ARB_ARB_REQ_CLR1 (1L<<5) #define MCPR_NVM_SW_ARB_ARB_REQ_SET1 (1L<<1) @@ -5251,10 +4444,6 @@ #define MISC_REGISTERS_SPIO_7 7 #define MISC_REGISTERS_SPIO_CLR_POS 16 #define MISC_REGISTERS_SPIO_FLOAT (0xffL<<24) -#define GRC_MISC_REGISTERS_SPIO_FLOAT7 0x80000000 -#define GRC_MISC_REGISTERS_SPIO_FLOAT6 0x40000000 -#define GRC_MISC_REGISTERS_SPIO_FLOAT5 0x20000000 -#define GRC_MISC_REGISTERS_SPIO_FLOAT4 0x10000000 #define MISC_REGISTERS_SPIO_FLOAT_POS 24 #define MISC_REGISTERS_SPIO_INPUT_HI_Z 2 #define MISC_REGISTERS_SPIO_INT_OLD_SET_POS 16 -- cgit v0.10.2 From ab6ad5a4875e99dffe957a411fe890402a91f67f Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:29 +0000 Subject: bnx2x: Whitespaces and comments Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 97bc5e0..bbf8422 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -314,9 +314,11 @@ struct bnx2x_fastpath { __le16 *rx_cons_sb; __le16 *rx_bd_cons_sb; + unsigned long tx_pkt, rx_pkt, rx_calls; + /* TPA related */ struct sw_rx_bd tpa_pool[ETH_MAX_AGGREGATION_QUEUES_E1H]; u8 tpa_state[ETH_MAX_AGGREGATION_QUEUES_E1H]; @@ -998,20 +1000,20 @@ struct bnx2x { #define GUNZIP_PHYS(bp) (bp->gunzip_mapping) #define GUNZIP_OUTLEN(bp) (bp->gunzip_outlen) - struct raw_op *init_ops; + struct raw_op *init_ops; /* Init blocks offsets inside init_ops */ - u16 *init_ops_offsets; + u16 *init_ops_offsets; /* Data blob - has 32 bit granularity */ - u32 *init_data; + u32 *init_data; /* Zipped PRAM blobs - raw data */ - const u8 *tsem_int_table_data; - const u8 *tsem_pram_data; - const u8 *usem_int_table_data; - const u8 *usem_pram_data; - const u8 *xsem_int_table_data; - const u8 *xsem_pram_data; - const u8 *csem_int_table_data; - const u8 *csem_pram_data; + const u8 *tsem_int_table_data; + const u8 *tsem_pram_data; + const u8 *usem_int_table_data; + const u8 *usem_pram_data; + const u8 *xsem_int_table_data; + const u8 *xsem_pram_data; + const u8 *csem_int_table_data; + const u8 *csem_pram_data; #define INIT_OPS(bp) (bp->init_ops) #define INIT_OPS_OFFSETS(bp) (bp->init_ops_offsets) #define INIT_DATA(bp) (bp->init_data) @@ -1024,7 +1026,7 @@ struct bnx2x { #define INIT_CSEM_INT_TABLE_DATA(bp) (bp->csem_int_table_data) #define INIT_CSEM_PRAM_DATA(bp) (bp->csem_pram_data) - const struct firmware *firmware; + const struct firmware *firmware; }; @@ -1111,9 +1113,9 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, #define DMAE_COMP_VAL 0xe0d0d0ae #define MAX_DMAE_C_PER_PORT 8 -#define INIT_DMAE_C(bp) (BP_PORT(bp)*MAX_DMAE_C_PER_PORT + \ +#define INIT_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \ BP_E1HVN(bp)) -#define PMF_DMAE_C(bp) (BP_PORT(bp)*MAX_DMAE_C_PER_PORT + \ +#define PMF_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \ E1HVN_MAX) @@ -1138,7 +1140,8 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, /* must be used on a CID before placing it on a HW ring */ -#define HW_CID(bp, x) ((BP_PORT(bp) << 23) | (BP_E1HVN(bp) << 17) | x) +#define HW_CID(bp, x) ((BP_PORT(bp) << 23) | \ + (BP_E1HVN(bp) << 17) | (x)) #define SP_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_spe)) #define MAX_SP_DESC_CNT (SP_DESC_CNT - 1) @@ -1226,8 +1229,8 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR | \ - AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR |\ - AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR |\ AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR | \ @@ -1255,7 +1258,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY | \ (bp->multi_mode << \ TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE_SHIFT)) - #define MULTI_MASK 0x7f diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index c2b0010..e32d337 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -182,6 +182,7 @@ static void bnx2x_set_serdes_access(struct link_params *params) { struct bnx2x *bp = params->bp; u32 emac_base = (params->port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + /* Set Clause 22 */ REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 1); REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000); @@ -194,6 +195,7 @@ static void bnx2x_set_serdes_access(struct link_params *params) static void bnx2x_set_phy_mdio(struct link_params *params, u8 phy_flags) { struct bnx2x *bp = params->bp; + if (phy_flags & PHY_XGXS_FLAG) { REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + params->port*0x18, 0); @@ -465,7 +467,6 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars, REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2); - /* set rx mtu */ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; wb_data[1] = 0; @@ -684,6 +685,7 @@ void bnx2x_link_status_update(struct link_params *params, static void bnx2x_update_mng(struct link_params *params, u32 link_status) { struct bnx2x *bp = params->bp; + REG_WR(bp, params->shmem_base + offsetof(struct shmem_region, port_mb[params->port].link_status), @@ -780,7 +782,6 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed); return -EINVAL; - break; } } REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd); @@ -800,6 +801,7 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port) { u32 emac_base; + switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: @@ -905,7 +907,7 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type, val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL | EMAC_MDIO_MODE_CLOCK_CNT)); val |= (EMAC_MDIO_MODE_CLAUSE_45 | - (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); + (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val); REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); udelay(40); @@ -1535,14 +1537,14 @@ static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result) } } -static u8 bnx2x_ext_phy_resove_fc(struct link_params *params, +static u8 bnx2x_ext_phy_resolve_fc(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; u8 ext_phy_addr; - u16 ld_pause; /* local */ - u16 lp_pause; /* link partner */ - u16 an_complete; /* AN complete */ + u16 ld_pause; /* local */ + u16 lp_pause; /* link partner */ + u16 an_complete; /* AN complete */ u16 pause_result; u8 ret = 0; u32 ext_phy_type; @@ -1642,7 +1644,7 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result); bnx2x_pause_resolve(vars, pause_result); } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && - (bnx2x_ext_phy_resove_fc(params, vars))) { + (bnx2x_ext_phy_resolve_fc(params, vars))) { return; } else { if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) @@ -1784,7 +1786,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params, "link speed unsupported gp_status 0x%x\n", gp_status); return -EINVAL; - break; + case GP_STATUS_10G_KX4: case GP_STATUS_10G_HIG: case GP_STATUS_10G_CX4: @@ -1821,8 +1823,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params, DP(NETIF_MSG_LINK, "link speed unsupported gp_status 0x%x\n", gp_status); - return -EINVAL; - break; + return -EINVAL; } /* Upon link speed change set the NIG into drain mode. @@ -2061,16 +2062,17 @@ static void bnx2x_ext_phy_reset(struct link_params *params, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); - break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + DP(NETIF_MSG_LINK, "XGXS 8072\n"); + /* Unset Low Power Mode and SW reset */ /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); - DP(NETIF_MSG_LINK, "XGXS 8072\n"); bnx2x_cl45_write(bp, params->port, ext_phy_type, ext_phy_addr, @@ -2078,8 +2080,9 @@ static void bnx2x_ext_phy_reset(struct link_params *params, MDIO_PMA_REG_CTRL, 1<<15); break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: - { + DP(NETIF_MSG_LINK, "XGXS 8073\n"); /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, @@ -2089,9 +2092,6 @@ static void bnx2x_ext_phy_reset(struct link_params *params, bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); - - DP(NETIF_MSG_LINK, "XGXS 8073\n"); - } break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: @@ -2107,7 +2107,6 @@ static void bnx2x_ext_phy_reset(struct link_params *params, break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: - /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, MISC_REGISTERS_GPIO_OUTPUT_HIGH, @@ -2146,20 +2145,18 @@ static void bnx2x_ext_phy_reset(struct link_params *params, break; default: - DP(NETIF_MSG_LINK, - "BAD SerDes ext_phy_config 0x%x\n", + DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n", params->ext_phy_config); break; } } } - static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port, u32 shmem_base, u32 spirom_ver) { - DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x\n", - (u16)(spirom_ver>>16), (u16)spirom_ver); + DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n", + (u16)(spirom_ver>>16), (u16)spirom_ver, port); REG_WR(bp, shmem_base + offsetof(struct shmem_region, port_mb[port].ext_phy_fw_version), @@ -2171,6 +2168,7 @@ static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port, u32 shmem_base) { u16 fw_ver1, fw_ver2; + bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &fw_ver1); bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, @@ -2423,7 +2421,6 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params) } DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n"); return -EINVAL; - } static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port, @@ -2565,6 +2562,7 @@ static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port, u8 tx_en) { u16 val; + DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n", tx_en, port); /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/ @@ -2597,6 +2595,7 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params, u8 port = params->port; u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + if (byte_cnt > 16) { DP(NETIF_MSG_LINK, "Reading from eeprom is" " is limited to 0xf\n"); @@ -2808,6 +2807,7 @@ static u8 bnx2x_get_edc_mode(struct link_params *params, case SFP_EEPROM_CON_TYPE_VAL_COPPER: { u8 copper_module_type; + /* Check if its active cable( includes SFP+ module) of passive cable*/ if (bnx2x_read_sfp_module_eeprom(params, @@ -2842,7 +2842,6 @@ static u8 bnx2x_get_edc_mode(struct link_params *params, DP(NETIF_MSG_LINK, "Optic module detected\n"); check_limiting_mode = 1; break; - default: DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n", val); @@ -3169,6 +3168,7 @@ void bnx2x_handle_module_detect_int(struct link_params *params) struct bnx2x *bp = params->bp; u32 gpio_val; u8 port = params->port; + /* Set valid module led off */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, MISC_REGISTERS_GPIO_HIGH, @@ -3236,6 +3236,7 @@ static void bnx2x_bcm807x_force_10G(struct link_params *params) MDIO_AN_REG_CTRL, 0x0000); } + static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params) { struct bnx2x *bp = params->bp; @@ -3303,7 +3304,6 @@ static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params) static void bnx2x_8073_set_pause_cl37(struct link_params *params, struct link_vars *vars) { - struct bnx2x *bp = params->bp; u16 cl37_val; u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); @@ -3535,6 +3535,7 @@ static void bnx2x_init_internal_phy(struct link_params *params, u8 enable_cl73) { struct bnx2x *bp = params->bp; + if (!(vars->phy_flags & PHY_SGMII_FLAG)) { if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) && @@ -3585,6 +3586,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) u16 ctrl = 0; u16 val = 0; u8 rc = 0; + if (vars->phy_flags & PHY_XGXS_FLAG) { ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); @@ -3881,14 +3883,12 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_8073_set_pause_cl37(params, vars); if (ext_phy_type == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){ + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) bnx2x_bcm8072_external_rom_boot(params); - } else { - + else /* In case of 8073 with long xaui lines, don't set the 8073 xaui low power*/ bnx2x_bcm8073_set_xaui_low_power_mode(params); - } bnx2x_cl45_read(bp, params->port, ext_phy_type, @@ -3953,10 +3953,8 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ext_phy_addr, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val); - if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) { - bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, @@ -4290,7 +4288,6 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_save_spirom_version(params->bp, params->port, params->shmem_base, (u32)(fw_ver1<<16 | fw_ver2)); - break; } case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: @@ -4621,6 +4618,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, u16 rx_sd, pcs_status; u8 ext_phy_link_up = 0; u8 port = params->port; + if (vars->phy_flags & PHY_XGXS_FLAG) { ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); @@ -4729,7 +4727,6 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, break; } } - if (val2 & (1<<1)) vars->line_speed = SPEED_1000; else @@ -4786,8 +4783,9 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, if ((val1 & (1<<8)) == 0) { DP(NETIF_MSG_LINK, "8727 Power fault" - " has been detected on port" - " %d\n", params->port); + " has been detected on " + "port %d\n", + params->port); printk(KERN_ERR PFX "Error: Power" " fault on %s Port %d has" " been detected and the" @@ -4894,6 +4892,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, { u16 link_status = 0; u16 an1000_status = 0; + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) { bnx2x_cl45_read(bp, params->port, @@ -4909,7 +4908,6 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, DP(NETIF_MSG_LINK, "870x LASI status 0x%x->0x%x\n", val1, val2); - } else { /* In 8073, port1 is directed through emac0 and * port0 is directed through emac1 @@ -5039,8 +5037,6 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH, 0x0333); - - } bnx2x_cl45_read(bp, params->port, ext_phy_type, @@ -5225,7 +5221,6 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, ext_phy_addr); } } - break; default: DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", @@ -5272,6 +5267,7 @@ static void bnx2x_link_int_enable(struct link_params *params) u32 ext_phy_type; u32 mask; struct bnx2x *bp = params->bp; + /* setting the status to report on link up for either XGXS or SerDes */ @@ -5303,10 +5299,10 @@ static void bnx2x_link_int_enable(struct link_params *params) bnx2x_bits_en(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, mask); - DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port, + + DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port, (params->switch_cfg == SWITCH_CFG_10G), REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); - DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n", REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), @@ -5738,6 +5734,7 @@ u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed, u8 rc = 0; u32 tmp; u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode); DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n", speed, hw_led_mode); @@ -5816,6 +5813,7 @@ static u8 bnx2x_link_initialize(struct link_params *params, u8 rc = 0; u8 non_ext_phy; u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + /* Activate the external PHY */ bnx2x_ext_phy_reset(params, vars); @@ -5889,11 +5887,11 @@ static u8 bnx2x_link_initialize(struct link_params *params, u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; - u32 val; - DP(NETIF_MSG_LINK, "Phy Initialization started \n"); - DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n", - params->req_line_speed, params->req_flow_ctrl); + + DP(NETIF_MSG_LINK, "Phy Initialization started\n"); + DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n", + params->req_line_speed, params->req_flow_ctrl); vars->link_status = 0; vars->phy_link_up = 0; vars->link_up = 0; @@ -5907,7 +5905,6 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) else vars->phy_flags = PHY_XGXS_FLAG; - /* disable attentions */ bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4, (NIG_MASK_XGXS0_LINK_STATUS | @@ -5918,6 +5915,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_emac_init(params, vars); if (CHIP_REV_IS_FPGA(bp)) { + vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; @@ -5926,7 +5924,8 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) /* enable on E1.5 FPGA */ if (CHIP_IS_E1H(bp)) { vars->flow_ctrl |= - (BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX); + (BNX2X_FLOW_CTRL_TX | + BNX2X_FLOW_CTRL_RX); vars->link_status |= (LINK_STATUS_TX_FLOW_CONTROL_ENABLED | LINK_STATUS_RX_FLOW_CONTROL_ENABLED); @@ -5935,8 +5934,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_emac_enable(params, vars, 0); bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed); /* disable drain */ - REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE - + params->port*4, 0); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); /* update shared memory */ bnx2x_update_mng(params, vars->link_status); @@ -5966,6 +5964,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) } else if (params->loopback_mode == LOOPBACK_BMAC) { + vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; @@ -5980,7 +5979,9 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); + } else if (params->loopback_mode == LOOPBACK_EMAC) { + vars->link_up = 1; vars->line_speed = SPEED_1000; vars->duplex = DUPLEX_FULL; @@ -5996,8 +5997,10 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->duplex); REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); + } else if ((params->loopback_mode == LOOPBACK_XGXS_10) || - (params->loopback_mode == LOOPBACK_EXT_PHY)) { + (params->loopback_mode == LOOPBACK_EXT_PHY)) { + vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; @@ -6034,7 +6037,6 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) } else /* No loopback */ { - bnx2x_phy_deassert(params, vars->phy_flags); switch (params->switch_cfg) { case SWITCH_CFG_1G: @@ -6042,8 +6044,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) if ((params->ext_phy_config & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) == PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) { - vars->phy_flags |= - PHY_SGMII_FLAG; + vars->phy_flags |= PHY_SGMII_FLAG; } val = REG_RD(bp, @@ -6064,7 +6065,6 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) default: DP(NETIF_MSG_LINK, "Invalid switch_cfg\n"); return -EINVAL; - break; } DP(NETIF_MSG_LINK, "Phy address = 0x%x\n", params->phy_addr); @@ -6089,7 +6089,6 @@ static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr) u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, u8 reset_ext_phy) { - struct bnx2x *bp = params->bp; u32 ext_phy_config = params->ext_phy_config; u16 hw_led_mode = params->hw_led_mode; @@ -6102,7 +6101,6 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, config)); /* disable attentions */ - vars->link_status = 0; bnx2x_update_mng(params, vars->link_status); bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, @@ -6198,6 +6196,7 @@ static u8 bnx2x_update_link_down(struct link_params *params, { struct bnx2x *bp = params->bp; u8 port = params->port; + DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port); bnx2x_set_led(bp, port, LED_MODE_OFF, 0, params->hw_led_mode, @@ -6234,6 +6233,7 @@ static u8 bnx2x_update_link_up(struct link_params *params, struct bnx2x *bp = params->bp; u8 port = params->port; u8 rc = 0; + vars->link_status |= LINK_STATUS_LINK_UP; if (link_10g) { bnx2x_bmac_enable(params, vars, 0); @@ -6547,6 +6547,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) u8 ext_phy_addr; u32 val; s8 port; + /* Use port1 because of the static port-swap */ /* Enable the module detection interrupt */ val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 8b6bb99..466c447 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -63,8 +63,8 @@ #include #include "bnx2x_fw_file_hdr.h" /* FW files */ -#define FW_FILE_PREFIX_E1 "bnx2x-e1-" -#define FW_FILE_PREFIX_E1H "bnx2x-e1h-" +#define FW_FILE_PREFIX_E1 "bnx2x-e1-" +#define FW_FILE_PREFIX_E1H "bnx2x-e1h-" /* Time in jiffies before concluding the transmitter is hung */ #define TX_TIMEOUT (5*HZ) @@ -723,7 +723,6 @@ static void bnx2x_int_disable(struct bnx2x *bp) REG_WR(bp, addr, val); if (REG_RD(bp, addr) != val) BNX2X_ERR("BUG! proper val not read from IGU!\n"); - } static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw) @@ -1660,6 +1659,7 @@ reuse_rx: } skb_record_rx_queue(skb, fp->index); + #ifdef BCM_VLAN if ((bp->vlgrp != NULL) && (bp->flags & HW_VLAN_RX_FLAG) && (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & @@ -2418,14 +2418,12 @@ static void bnx2x_link_attn(struct bnx2x *bp) int func; int vn; + /* Set the attention towards other drivers on the same port */ for (vn = VN_0; vn < E1HVN_MAX; vn++) { if (vn == BP_E1HVN(bp)) continue; func = ((vn << 1) | port); - - /* Set the attention towards other drivers - on the same port */ REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 + (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1); } @@ -2880,6 +2878,7 @@ static inline void bnx2x_fan_failure(struct bnx2x *bp) " damage. Please contact Dell Support for assistance\n", bp->dev->name); } + static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) { int port = BP_PORT(bp); @@ -7660,9 +7659,11 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; + /* Set "drop all" */ bp->rx_mode = BNX2X_RX_MODE_NONE; bnx2x_set_storm_rx_mode(bp); + /* Disable HW interrupts, NAPI and Tx */ bnx2x_netif_stop(bp, 1); del_timer_sync(&bp->timer); @@ -9158,8 +9159,7 @@ static int bnx2x_nway_reset(struct net_device *dev) return 0; } -static u32 -bnx2x_get_link(struct net_device *dev) +static u32 bnx2x_get_link(struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); @@ -10169,7 +10169,7 @@ static int bnx2x_test_nvram(struct bnx2x *bp) __be32 buf[0x350 / 4]; u8 *data = (u8 *)buf; int i, rc; - u32 magic, csum; + u32 magic, crc; rc = bnx2x_nvram_read(bp, 0, data, 4); if (rc) { @@ -10194,10 +10194,10 @@ static int bnx2x_test_nvram(struct bnx2x *bp) goto test_nvram_exit; } - csum = ether_crc_le(nvram_tbl[i].size, data); - if (csum != CRC32_RESIDUAL) { + crc = ether_crc_le(nvram_tbl[i].size, data); + if (crc != CRC32_RESIDUAL) { DP(NETIF_MSG_PROBE, - "nvram_tbl[%d] csum value (0x%08x)\n", i, csum); + "nvram_tbl[%d] crc value (0x%08x)\n", i, crc); rc = -ENODEV; goto test_nvram_exit; } @@ -11771,17 +11771,17 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp) BCM_5710_FW_MINOR_VERSION, BCM_5710_FW_REVISION_VERSION, BCM_5710_FW_ENGINEERING_VERSION); - return -EINVAL; + return -EINVAL; } return 0; } -static void inline be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n) +static inline void be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n) { + const __be32 *source = (const __be32 *)_source; + u32 *target = (u32 *)_target; u32 i; - const __be32 *source = (const __be32*)_source; - u32 *target = (u32*)_target; for (i = 0; i < n/4; i++) target[i] = be32_to_cpu(source[i]); @@ -11791,66 +11791,67 @@ static void inline be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n) Ops array is stored in the following format: {op(8bit), offset(24bit, big endian), data(32bit, big endian)} */ -static void inline bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n) +static inline void bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n) { + const __be32 *source = (const __be32 *)_source; + struct raw_op *target = (struct raw_op *)_target; u32 i, j, tmp; - const __be32 *source = (const __be32*)_source; - struct raw_op *target = (struct raw_op*)_target; - for (i = 0, j = 0; i < n/8; i++, j+=2) { + for (i = 0, j = 0; i < n/8; i++, j += 2) { tmp = be32_to_cpu(source[j]); target[i].op = (tmp >> 24) & 0xff; target[i].offset = tmp & 0xffffff; target[i].raw_data = be32_to_cpu(source[j+1]); } } -static void inline be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n) + +static inline void be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n) { + const __be16 *source = (const __be16 *)_source; + u16 *target = (u16 *)_target; u32 i; - u16 *target = (u16*)_target; - const __be16 *source = (const __be16*)_source; for (i = 0; i < n/2; i++) target[i] = be16_to_cpu(source[i]); } #define BNX2X_ALLOC_AND_SET(arr, lbl, func) \ - do { \ - u32 len = be32_to_cpu(fw_hdr->arr.len); \ - bp->arr = kmalloc(len, GFP_KERNEL); \ + do { \ + u32 len = be32_to_cpu(fw_hdr->arr.len); \ + bp->arr = kmalloc(len, GFP_KERNEL); \ if (!bp->arr) { \ - printk(KERN_ERR PFX "Failed to allocate %d bytes for "#arr"\n", len); \ + printk(KERN_ERR PFX "Failed to allocate %d bytes " \ + "for "#arr"\n", len); \ goto lbl; \ } \ - func(bp->firmware->data + \ - be32_to_cpu(fw_hdr->arr.offset), \ - (u8*)bp->arr, len); \ + func(bp->firmware->data + be32_to_cpu(fw_hdr->arr.offset), \ + (u8 *)bp->arr, len); \ } while (0) - static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev) { char fw_file_name[40] = {0}; - int rc, offset; struct bnx2x_fw_file_hdr *fw_hdr; + int rc, offset; /* Create a FW file name */ if (CHIP_IS_E1(bp)) - offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1); + offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1); else offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1H); sprintf(fw_file_name + offset, "%d.%d.%d.%d.fw", BCM_5710_FW_MAJOR_VERSION, - BCM_5710_FW_MINOR_VERSION, - BCM_5710_FW_REVISION_VERSION, - BCM_5710_FW_ENGINEERING_VERSION); + BCM_5710_FW_MINOR_VERSION, + BCM_5710_FW_REVISION_VERSION, + BCM_5710_FW_ENGINEERING_VERSION); printk(KERN_INFO PFX "Loading %s\n", fw_file_name); rc = request_firmware(&bp->firmware, fw_file_name, dev); if (rc) { - printk(KERN_ERR PFX "Can't load firmware file %s\n", fw_file_name); + printk(KERN_ERR PFX "Can't load firmware file %s\n", + fw_file_name); goto request_firmware_exit; } @@ -11870,7 +11871,8 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev) BNX2X_ALLOC_AND_SET(init_ops, init_ops_alloc_err, bnx2x_prep_ops); /* Offsets */ - BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err, be16_to_cpu_n); + BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err, + be16_to_cpu_n); /* STORMs firmware */ INIT_TSEM_INT_TABLE_DATA(bp) = bp->firmware->data + @@ -11891,6 +11893,7 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev) be32_to_cpu(fw_hdr->csem_pram_data.offset); return 0; + init_offsets_alloc_err: kfree(bp->init_ops); init_ops_alloc_err: @@ -11902,7 +11905,6 @@ request_firmware_exit: } - static int __devinit bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 95ebf3f..0695be1 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -4561,7 +4561,8 @@ #define LATCHED_ATTN_SCPAD_PARITY_MCP 33 #define GENERAL_ATTEN_WORD(atten_name) ((94 + atten_name) / 32) -#define GENERAL_ATTEN_OFFSET(atten_name) (1 << ((94 + atten_name) % 32)) +#define GENERAL_ATTEN_OFFSET(atten_name)\ + (1UL << ((94 + atten_name) % 32)) /* * This file defines GRC base address for every block. * This file is included by chipsim, asm microcode and cpp microcode. -- cgit v0.10.2 From c458bc50e31631f7e9333ea6f1832fc54d4e2c1e Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:31 +0000 Subject: bnx2x: update version to 1.52.1 Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 466c447..b318d16 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -56,8 +56,8 @@ #include "bnx2x_init_ops.h" #include "bnx2x_dump.h" -#define DRV_MODULE_VERSION "1.48.114-1" -#define DRV_MODULE_RELDATE "2009/07/29" +#define DRV_MODULE_VERSION "1.52.1" +#define DRV_MODULE_RELDATE "2009/08/12" #define BNX2X_BC_VER 0x040200 #include -- cgit v0.10.2 From 1c4bdf9be010ae7c2324c0a90dd2296e0d1a775e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Aug 2009 08:23:24 +0200 Subject: ALSA: hda - Enable line-out detection only with speakers Enable line-out detection for IDT/STAC codecs only when speaker pins exist. In some cases, the speaker itself is identified as line-out, and this confuses the situation. Only the extra line-outs should do auto-muting. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 2760730..3ac0112 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4350,7 +4350,8 @@ static int stac92xx_init(struct hda_codec *codec) hda_nid_t nid = cfg->hp_pins[i]; enable_pin_detect(codec, nid, STAC_HP_EVENT); } - if (cfg->line_out_type == AUTO_PIN_LINE_OUT) { + if (cfg->line_out_type == AUTO_PIN_LINE_OUT && + cfg->speaker_outs > 0) { /* enable pin-detect for line-outs as well */ for (i = 0; i < cfg->line_outs; i++) { hda_nid_t nid = cfg->line_out_pins[i]; -- cgit v0.10.2 From c4ff357ada4fc7a73d899a496b636c698519b958 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Wed, 12 Aug 2009 11:34:25 +0800 Subject: ASoC: add output/input widgets in ad1938 to make dac/adc dynamic PM work According to the function dapm_dac_check_power() in sound/soc/soc-dapm.c, dac power can't be on/off stand-alone without any output widget as sink. And according to dapm_adc_check_power(), adc power can't be on/off stand-alone without any input widget as source. So we can't only define some stand-alone SND_SOC_DAPM_DAC/SND_SOC_DAPM_ADC to hope their power can be managed dynamically. Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 2ffb1af..051f68c 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -99,11 +99,23 @@ static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1), SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0), + SND_SOC_DAPM_OUTPUT("DAC1OUT"), + SND_SOC_DAPM_OUTPUT("DAC2OUT"), + SND_SOC_DAPM_OUTPUT("DAC3OUT"), + SND_SOC_DAPM_OUTPUT("DAC4OUT"), + SND_SOC_DAPM_INPUT("ADC1IN"), + SND_SOC_DAPM_INPUT("ADC2IN"), }; static const struct snd_soc_dapm_route audio_paths[] = { { "DAC", NULL, "ADC_PWR" }, { "ADC", NULL, "ADC_PWR" }, + { "DAC1OUT", "DAC1 Switch", "DAC" }, + { "DAC2OUT", "DAC2 Switch", "DAC" }, + { "DAC3OUT", "DAC3 Switch", "DAC" }, + { "DAC4OUT", "DAC4 Switch", "DAC" }, + { "ADC", "ADC1 Switch", "ADC1IN" }, + { "ADC", "ADC2 Switch", "ADC2IN" }, }; /* -- cgit v0.10.2 From 73fec1209433d6b33924c1b06122ee217ce98931 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 13 Aug 2009 21:33:06 +1000 Subject: Revert crypto: fips - Select CPRNG This reverts commit 215ccd6f55a2144bd553e0a3d12e1386f02309fd. It causes CPRNG and everything selected by it to be built-in whenever FIPS is enabled. The problem is that it is selecting a tristate from a bool, which is usually not what is intended. Signed-off-by: Herbert Xu diff --git a/crypto/Kconfig b/crypto/Kconfig index 5105cf1..1db0995 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -23,7 +23,6 @@ comment "Crypto core or helper" config CRYPTO_FIPS bool "FIPS 200 compliance" - select CRYPTO_ANSI_CPRNG help This options enables the fips boot option which is required if you want to system to operate in a FIPS 200 -- cgit v0.10.2 From aef27136b8b5e526f2e96ca1caa30a6d07e70f42 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 13 Aug 2009 23:10:39 +1000 Subject: crypto: ctr - Use chainiv on raw counter mode Raw counter mode only works with chainiv, which is no longer the default IV generator on SMP machines. This broke raw counter mode as it can no longer instantiate as a givcipher. This patch fixes it by always picking chainiv on raw counter mode. This is based on the diagnosis and a patch by Huang Ying. Signed-off-by: Herbert Xu diff --git a/crypto/ctr.c b/crypto/ctr.c index 2d7425f..6c3bfab 100644 --- a/crypto/ctr.c +++ b/crypto/ctr.c @@ -219,6 +219,8 @@ static struct crypto_instance *crypto_ctr_alloc(struct rtattr **tb) inst->alg.cra_blkcipher.encrypt = crypto_ctr_crypt; inst->alg.cra_blkcipher.decrypt = crypto_ctr_crypt; + inst->alg.cra_blkcipher.geniv = "chainiv"; + out: crypto_mod_put(alg); return inst; -- cgit v0.10.2 From 9008adf9a9c3a43ef237f6cd416857569beb0029 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 13 Aug 2009 15:59:34 +0300 Subject: ASoC: TWL4030: Introduce PGAs for outputs Dynamically control and control only the needed output amplifier muting/un-muting. The original code was muting and un-muting the following output amplifiers: Earpiece PreDrivL/R, CarkitL/R at the same time regardless which pin is actually in use at the given moment. Move these as separate PGA so only the needed amplifier will be touched. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 818fb37..1a65004 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -225,55 +225,11 @@ static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute) return; if (mute) { - /* Bypass the reg_cache and mute the volumes - * Headset mute is done in it's own event handler - * Things to mute: Earpiece, PreDrivL/R, CarkitL/R - */ - reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_EAR_CTL); - twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - reg_val & (~TWL4030_EAR_GAIN), - TWL4030_REG_EAR_CTL); - - reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PREDL_CTL); - twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - reg_val & (~TWL4030_PREDL_GAIN), - TWL4030_REG_PREDL_CTL); - reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PREDR_CTL); - twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - reg_val & (~TWL4030_PREDR_GAIN), - TWL4030_REG_PREDL_CTL); - - reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKL_CTL); - twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - reg_val & (~TWL4030_PRECKL_GAIN), - TWL4030_REG_PRECKL_CTL); - reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL); - twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - reg_val & (~TWL4030_PRECKR_GAIN), - TWL4030_REG_PRECKR_CTL); - /* Disable PLL */ reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); reg_val &= ~TWL4030_APLL_EN; twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val); } else { - /* Restore the volumes - * Headset mute is done in it's own event handler - * Things to restore: Earpiece, PreDrivL/R, CarkitL/R - */ - twl4030_write(codec, TWL4030_REG_EAR_CTL, - twl4030_read_reg_cache(codec, TWL4030_REG_EAR_CTL)); - - twl4030_write(codec, TWL4030_REG_PREDL_CTL, - twl4030_read_reg_cache(codec, TWL4030_REG_PREDL_CTL)); - twl4030_write(codec, TWL4030_REG_PREDR_CTL, - twl4030_read_reg_cache(codec, TWL4030_REG_PREDR_CTL)); - - twl4030_write(codec, TWL4030_REG_PRECKL_CTL, - twl4030_read_reg_cache(codec, TWL4030_REG_PRECKL_CTL)); - twl4030_write(codec, TWL4030_REG_PRECKR_CTL, - twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL)); - /* Enable PLL */ reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); reg_val |= TWL4030_APLL_EN; @@ -560,6 +516,41 @@ static int micpath_event(struct snd_soc_dapm_widget *w, return 0; } +/* + * Output PGA builder: + * Handle the muting and unmuting of the given output (turning off the + * amplifier associated with the output pin) + * On mute bypass the reg_cache and mute the volume + * On unmute: restore the register content + * Outputs handled in this way: Earpiece, PreDrivL/R, CarkitL/R + */ +#define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \ +static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ + struct snd_kcontrol *kcontrol, int event) \ +{ \ + u8 reg_val; \ + \ + switch (event) { \ + case SND_SOC_DAPM_POST_PMU: \ + twl4030_write(w->codec, reg, \ + twl4030_read_reg_cache(w->codec, reg)); \ + break; \ + case SND_SOC_DAPM_POST_PMD: \ + reg_val = twl4030_read_reg_cache(w->codec, reg); \ + twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \ + reg_val & (~mask), \ + reg); \ + break; \ + } \ + return 0; \ +} + +TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL, TWL4030_EAR_GAIN); +TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL, TWL4030_PREDL_GAIN); +TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL, TWL4030_PREDR_GAIN); +TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL, TWL4030_PRECKL_GAIN); +TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL, TWL4030_PRECKR_GAIN); + static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp) { unsigned char hs_ctl; @@ -1253,13 +1244,22 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, &twl4030_dapm_earpiece_controls[0], ARRAY_SIZE(twl4030_dapm_earpiece_controls)), + SND_SOC_DAPM_PGA_E("Earpiece PGA", SND_SOC_NOPM, + 0, 0, NULL, 0, earpiecepga_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), /* PreDrivL/R */ SND_SOC_DAPM_MIXER("PredriveL Mixer", SND_SOC_NOPM, 0, 0, &twl4030_dapm_predrivel_controls[0], ARRAY_SIZE(twl4030_dapm_predrivel_controls)), + SND_SOC_DAPM_PGA_E("PredriveL PGA", SND_SOC_NOPM, + 0, 0, NULL, 0, predrivelpga_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER("PredriveR Mixer", SND_SOC_NOPM, 0, 0, &twl4030_dapm_predriver_controls[0], ARRAY_SIZE(twl4030_dapm_predriver_controls)), + SND_SOC_DAPM_PGA_E("PredriveR PGA", SND_SOC_NOPM, + 0, 0, NULL, 0, predriverpga_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), /* HeadsetL/R */ SND_SOC_DAPM_MIXER("HeadsetL Mixer", SND_SOC_NOPM, 0, 0, &twl4030_dapm_hsol_controls[0], @@ -1277,9 +1277,15 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_MIXER("CarkitL Mixer", SND_SOC_NOPM, 0, 0, &twl4030_dapm_carkitl_controls[0], ARRAY_SIZE(twl4030_dapm_carkitl_controls)), + SND_SOC_DAPM_PGA_E("CarkitL PGA", SND_SOC_NOPM, + 0, 0, NULL, 0, carkitlpga_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER("CarkitR Mixer", SND_SOC_NOPM, 0, 0, &twl4030_dapm_carkitr_controls[0], ARRAY_SIZE(twl4030_dapm_carkitr_controls)), + SND_SOC_DAPM_PGA_E("CarkitR PGA", SND_SOC_NOPM, + 0, 0, NULL, 0, carkitrpga_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), /* Output MUX controls */ /* HandsfreeL/R */ @@ -1371,16 +1377,19 @@ static const struct snd_soc_dapm_route intercon[] = { {"Earpiece Mixer", "AudioL1", "Analog L1 Playback Mixer"}, {"Earpiece Mixer", "AudioL2", "Analog L2 Playback Mixer"}, {"Earpiece Mixer", "AudioR1", "Analog R1 Playback Mixer"}, + {"Earpiece PGA", NULL, "Earpiece Mixer"}, /* PreDrivL */ {"PredriveL Mixer", "Voice", "Analog Voice Playback Mixer"}, {"PredriveL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, {"PredriveL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, {"PredriveL Mixer", "AudioR2", "Analog R2 Playback Mixer"}, + {"PredriveL PGA", NULL, "PredriveL Mixer"}, /* PreDrivR */ {"PredriveR Mixer", "Voice", "Analog Voice Playback Mixer"}, {"PredriveR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, {"PredriveR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, {"PredriveR Mixer", "AudioL2", "Analog L2 Playback Mixer"}, + {"PredriveR PGA", NULL, "PredriveR Mixer"}, /* HeadsetL */ {"HeadsetL Mixer", "Voice", "Analog Voice Playback Mixer"}, {"HeadsetL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, @@ -1395,10 +1404,12 @@ static const struct snd_soc_dapm_route intercon[] = { {"CarkitL Mixer", "Voice", "Analog Voice Playback Mixer"}, {"CarkitL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, {"CarkitL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, + {"CarkitL PGA", NULL, "CarkitL Mixer"}, /* CarkitR */ {"CarkitR Mixer", "Voice", "Analog Voice Playback Mixer"}, {"CarkitR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, {"CarkitR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, + {"CarkitR PGA", NULL, "CarkitR Mixer"}, /* HandsfreeL */ {"HandsfreeL Mux", "Voice", "Analog Voice Playback Mixer"}, {"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"}, @@ -1422,13 +1433,13 @@ static const struct snd_soc_dapm_route intercon[] = { /* outputs */ {"OUTL", NULL, "Analog L2 Playback Mixer"}, {"OUTR", NULL, "Analog R2 Playback Mixer"}, - {"EARPIECE", NULL, "Earpiece Mixer"}, - {"PREDRIVEL", NULL, "PredriveL Mixer"}, - {"PREDRIVER", NULL, "PredriveR Mixer"}, + {"EARPIECE", NULL, "Earpiece PGA"}, + {"PREDRIVEL", NULL, "PredriveL PGA"}, + {"PREDRIVER", NULL, "PredriveR PGA"}, {"HSOL", NULL, "HeadsetL PGA"}, {"HSOR", NULL, "HeadsetR PGA"}, - {"CARKITL", NULL, "CarkitL Mixer"}, - {"CARKITR", NULL, "CarkitR Mixer"}, + {"CARKITL", NULL, "CarkitL PGA"}, + {"CARKITR", NULL, "CarkitR PGA"}, {"HFL", NULL, "HandsfreeL PGA"}, {"HFR", NULL, "HandsfreeR PGA"}, {"Vibra Route", "Audio", "Vibra Mux"}, -- cgit v0.10.2 From 7eaae41ea54af5516138aef5fd33bc55598cbf48 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Thu, 13 Aug 2009 11:59:32 +0800 Subject: new ad1836 codec driver based on asoc There has been an ad1836 driver in sound/blackfin based on traditional alsa. The new driver is based on asoc. The architecture of ad1836 codec driver is very much like ad1938. Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 31a6d21..05e2279 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -68,6 +68,9 @@ config SND_SOC_AC97_CODEC tristate select SND_AC97_CODEC +config SND_SOC_AD1836 + tristate + config SND_SOC_AD1938 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 78dce5d..9cbcf8f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -1,4 +1,5 @@ snd-soc-ac97-objs := ac97.o +snd-soc-ad1836-objs := ad1836.o snd-soc-ad1938-objs := ad1938.o snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o @@ -45,6 +46,7 @@ snd-soc-wm9713-objs := wm9713.o snd-soc-max9877-objs := max9877.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o +obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o obj-$(CONFIG_SND_SOC_AD1938) += snd-soc-ad1938.o obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c new file mode 100644 index 0000000..79b9d19 --- /dev/null +++ b/sound/soc/codecs/ad1836.c @@ -0,0 +1,451 @@ +/* + * File: sound/soc/codecs/ad1836.c + * Author: Barry Song + * + * Created: Aug 04 2009 + * Description: Driver for AD1836 sound chip + * + * Modified: + * Copyright 2009 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ad1836.h" + +/* codec private data */ +struct ad1836_priv { + struct snd_soc_codec codec; + u16 reg_cache[AD1836_NUM_REGS]; +}; + +static struct snd_soc_codec *ad1836_codec; +struct snd_soc_codec_device soc_codec_dev_ad1836; +static int ad1836_register(struct ad1836_priv *ad1836); +static void ad1836_unregister(struct ad1836_priv *ad1836); + +/* + * AD1836 volume/mute/de-emphasis etc. controls + */ +static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"}; + +static const struct soc_enum ad1836_deemp_enum = + SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp); + +static const struct snd_kcontrol_new ad1836_snd_controls[] = { + /* DAC volume control */ + SOC_DOUBLE_R("DAC1 Volume", AD1836_DAC_L1_VOL, + AD1836_DAC_R1_VOL, 0, 0x3FF, 0), + SOC_DOUBLE_R("DAC2 Volume", AD1836_DAC_L2_VOL, + AD1836_DAC_R2_VOL, 0, 0x3FF, 0), + SOC_DOUBLE_R("DAC3 Volume", AD1836_DAC_L3_VOL, + AD1836_DAC_R3_VOL, 0, 0x3FF, 0), + + /* ADC switch control */ + SOC_DOUBLE("ADC1 Switch", AD1836_ADC_CTRL2, AD1836_ADCL1_MUTE, + AD1836_ADCR1_MUTE, 1, 1), + SOC_DOUBLE("ADC2 Switch", AD1836_ADC_CTRL2, AD1836_ADCL2_MUTE, + AD1836_ADCR2_MUTE, 1, 1), + + /* DAC switch control */ + SOC_DOUBLE("DAC1 Switch", AD1836_DAC_CTRL2, AD1836_DACL1_MUTE, + AD1836_DACR1_MUTE, 1, 1), + SOC_DOUBLE("DAC2 Switch", AD1836_DAC_CTRL2, AD1836_DACL2_MUTE, + AD1836_DACR2_MUTE, 1, 1), + SOC_DOUBLE("DAC3 Switch", AD1836_DAC_CTRL2, AD1836_DACL3_MUTE, + AD1836_DACR3_MUTE, 1, 1), + + /* ADC high-pass filter */ + SOC_SINGLE("ADC High Pass Filter Switch", AD1836_ADC_CTRL1, + AD1836_ADC_HIGHPASS_FILTER, 1, 0), + + /* DAC de-emphasis */ + SOC_ENUM("Playback Deemphasis", ad1836_deemp_enum), +}; + +static const struct snd_soc_dapm_widget ad1836_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DAC", "Playback", AD1836_DAC_CTRL1, + AD1836_DAC_POWERDOWN, 1), + SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1836_ADC_CTRL1, + AD1836_ADC_POWERDOWN, 1, NULL, 0), + SND_SOC_DAPM_OUTPUT("DAC1OUT"), + SND_SOC_DAPM_OUTPUT("DAC2OUT"), + SND_SOC_DAPM_OUTPUT("DAC3OUT"), + SND_SOC_DAPM_INPUT("ADC1IN"), + SND_SOC_DAPM_INPUT("ADC2IN"), +}; + +static const struct snd_soc_dapm_route audio_paths[] = { + { "DAC", NULL, "ADC_PWR" }, + { "ADC", NULL, "ADC_PWR" }, + { "DAC1OUT", "DAC1 Switch", "DAC" }, + { "DAC2OUT", "DAC2 Switch", "DAC" }, + { "DAC3OUT", "DAC3 Switch", "DAC" }, + { "ADC", "ADC1 Switch", "ADC1IN" }, + { "ADC", "ADC2 Switch", "ADC2IN" }, +}; + +/* + * DAI ops entries + */ + +static int ad1836_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + /* at present, we support adc aux mode to interface with + * blackfin sport tdm mode + */ + case SND_SOC_DAIFMT_DSP_A: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + /* ALCLK,ABCLK are both output, AD1836 can only be master */ + case SND_SOC_DAIFMT_CBM_CFM: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ad1836_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int word_len = 0; + + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + word_len = 3; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + word_len = 1; + break; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S32_LE: + word_len = 0; + break; + } + + snd_soc_update_bits(codec, AD1836_DAC_CTRL1, + AD1836_DAC_WORD_LEN_MASK, word_len); + + snd_soc_update_bits(codec, AD1836_ADC_CTRL2, + AD1836_ADC_WORD_LEN_MASK, word_len); + + return 0; +} + + +/* + * interface to read/write ad1836 register + */ +#define AD1836_SPI_REG_SHFT 12 +#define AD1836_SPI_READ (1 << 11) +#define AD1836_SPI_VAL_MSK 0x3FF + +/* + * write to the ad1836 register space + */ + +static int ad1836_write_reg(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 *reg_cache = codec->reg_cache; + int ret = 0; + + if (value != reg_cache[reg]) { + unsigned short buf; + struct spi_transfer t = { + .tx_buf = &buf, + .len = 2, + }; + struct spi_message m; + + buf = (reg << AD1836_SPI_REG_SHFT) | + (value & AD1836_SPI_VAL_MSK); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + ret = spi_sync(codec->control_data, &m); + if (ret == 0) + reg_cache[reg] = value; + } + + return ret; +} + +/* + * read from the ad1836 register space cache + */ +static unsigned int ad1836_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *reg_cache = codec->reg_cache; + + if (reg >= codec->reg_cache_size) + return -EINVAL; + + return reg_cache[reg]; +} + +static int __devinit ad1836_spi_probe(struct spi_device *spi) +{ + struct snd_soc_codec *codec; + struct ad1836_priv *ad1836; + + ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL); + if (ad1836 == NULL) + return -ENOMEM; + + codec = &ad1836->codec; + codec->control_data = spi; + codec->dev = &spi->dev; + + dev_set_drvdata(&spi->dev, ad1836); + + return ad1836_register(ad1836); +} + +static int __devexit ad1836_spi_remove(struct spi_device *spi) +{ + struct ad1836_priv *ad1836 = dev_get_drvdata(&spi->dev); + + ad1836_unregister(ad1836); + return 0; +} + +static struct spi_driver ad1836_spi_driver = { + .driver = { + .name = "ad1836-spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ad1836_spi_probe, + .remove = __devexit_p(ad1836_spi_remove), +}; + +static struct snd_soc_dai_ops ad1836_dai_ops = { + .hw_params = ad1836_hw_params, + .set_fmt = ad1836_set_dai_fmt, +}; + +/* codec DAI instance */ +struct snd_soc_dai ad1836_dai = { + .name = "AD1836", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 6, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &ad1836_dai_ops, +}; +EXPORT_SYMBOL_GPL(ad1836_dai); + +static int ad1836_register(struct ad1836_priv *ad1836) +{ + int ret; + struct snd_soc_codec *codec = &ad1836->codec; + + if (ad1836_codec) { + dev_err(codec->dev, "Another ad1836 is registered\n"); + return -EINVAL; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + codec->private_data = ad1836; + codec->reg_cache = ad1836->reg_cache; + codec->reg_cache_size = AD1836_NUM_REGS; + codec->name = "AD1836"; + codec->owner = THIS_MODULE; + codec->dai = &ad1836_dai; + codec->num_dai = 1; + codec->write = ad1836_write_reg; + codec->read = ad1836_read_reg_cache; + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + ad1836_dai.dev = codec->dev; + ad1836_codec = codec; + + /* default setting for ad1836 */ + /* de-emphasis: 48kHz, power-on dac */ + codec->write(codec, AD1836_DAC_CTRL1, 0x300); + /* unmute dac channels */ + codec->write(codec, AD1836_DAC_CTRL2, 0x0); + /* high-pass filter enable, power-on adc */ + codec->write(codec, AD1836_ADC_CTRL1, 0x100); + /* unmute adc channles, adc aux mode */ + codec->write(codec, AD1836_ADC_CTRL2, 0x180); + /* left/right diff:PGA/MUX */ + codec->write(codec, AD1836_ADC_CTRL3, 0x3A); + /* volume */ + codec->write(codec, AD1836_DAC_L1_VOL, 0x3FF); + codec->write(codec, AD1836_DAC_R1_VOL, 0x3FF); + codec->write(codec, AD1836_DAC_L2_VOL, 0x3FF); + codec->write(codec, AD1836_DAC_R2_VOL, 0x3FF); + codec->write(codec, AD1836_DAC_L3_VOL, 0x3FF); + codec->write(codec, AD1836_DAC_R3_VOL, 0x3FF); + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + kfree(ad1836); + return ret; + } + + ret = snd_soc_register_dai(&ad1836_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + kfree(ad1836); + return ret; + } + + return 0; +} + +static void ad1836_unregister(struct ad1836_priv *ad1836) +{ + snd_soc_unregister_dai(&ad1836_dai); + snd_soc_unregister_codec(&ad1836->codec); + kfree(ad1836); + ad1836_codec = NULL; +} + +static int ad1836_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (ad1836_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = ad1836_codec; + codec = ad1836_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, ad1836_snd_controls, + ARRAY_SIZE(ad1836_snd_controls)); + snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets, + ARRAY_SIZE(ad1836_dapm_widgets)); + snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); + snd_soc_dapm_new_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +/* power down chip */ +static int ad1836_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_ad1836 = { + .probe = ad1836_probe, + .remove = ad1836_remove, + /* The power management of ad1836 is very simple. There are + * only adc&dac 2 components to control. Dapm handles them. + */ + .suspend = NULL, + .resume = NULL, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836); + +static int __init ad1836_init(void) +{ + int ret; + + ret = spi_register_driver(&ad1836_spi_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register ad1836 SPI driver: %d\n", + ret); + } + + return ret; +} +module_init(ad1836_init); + +static void __exit ad1836_exit(void) +{ + spi_unregister_driver(&ad1836_spi_driver); +} +module_exit(ad1836_exit); + +MODULE_DESCRIPTION("ASoC ad1836 driver"); +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ad1836.h b/sound/soc/codecs/ad1836.h new file mode 100644 index 0000000..7660ee6 --- /dev/null +++ b/sound/soc/codecs/ad1836.h @@ -0,0 +1,64 @@ +/* + * File: sound/soc/codecs/ad1836.h + * Based on: + * Author: Barry Song + * + * Created: Aug 04, 2009 + * Description: definitions for AD1836 registers + * + * Modified: + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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. + */ + +#ifndef __AD1836_H__ +#define __AD1836_H__ + +#define AD1836_DAC_CTRL1 0 +#define AD1836_DAC_POWERDOWN 2 +#define AD1836_DAC_SERFMT_MASK 0xE0 +#define AD1836_DAC_SERFMT_PCK256 (0x4 << 5) +#define AD1836_DAC_SERFMT_PCK128 (0x5 << 5) +#define AD1836_DAC_WORD_LEN_MASK 0x18 + +#define AD1836_DAC_CTRL2 1 +#define AD1836_DACL1_MUTE 0 +#define AD1836_DACR1_MUTE 1 +#define AD1836_DACL2_MUTE 2 +#define AD1836_DACR2_MUTE 3 +#define AD1836_DACL3_MUTE 4 +#define AD1836_DACR3_MUTE 5 + +#define AD1836_DAC_L1_VOL 2 +#define AD1836_DAC_R1_VOL 3 +#define AD1836_DAC_L2_VOL 4 +#define AD1836_DAC_R2_VOL 5 +#define AD1836_DAC_L3_VOL 6 +#define AD1836_DAC_R3_VOL 7 + +#define AD1836_ADC_CTRL1 12 +#define AD1836_ADC_POWERDOWN 7 +#define AD1836_ADC_HIGHPASS_FILTER 8 + +#define AD1836_ADC_CTRL2 13 +#define AD1836_ADCL1_MUTE 0 +#define AD1836_ADCR1_MUTE 1 +#define AD1836_ADCL2_MUTE 2 +#define AD1836_ADCR2_MUTE 3 +#define AD1836_ADC_WORD_LEN_MASK 0x30 +#define AD1836_ADC_SERFMT_MASK (7 << 6) +#define AD1836_ADC_SERFMT_PCK256 (0x4 << 6) +#define AD1836_ADC_SERFMT_PCK128 (0x5 << 6) + +#define AD1836_ADC_CTRL3 14 + +#define AD1836_NUM_REGS 16 + +extern struct snd_soc_dai ad1836_dai; +extern struct snd_soc_codec_device soc_codec_dev_ad1836; +#endif -- cgit v0.10.2 From e9ade7f933d629698cbe5f09f1e5511269180fea Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Aug 2009 15:19:42 +0100 Subject: ASoC: Minor cleanups to AD1938 driver - Build in SND_SOC_ALL_CODECS. - Remove null suspend/resume stuff. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 05e2279..dd9b295 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -12,6 +12,7 @@ config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" select SND_SOC_L3 select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS + select SND_SOC_AD1836 if SPI_MASTER select SND_SOC_AD1938 if SPI_MASTER select SND_SOC_AD1980 if SND_SOC_AC97_BUS select SND_SOC_AD73311 if I2C diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 79b9d19..3612bb9 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -418,11 +418,6 @@ static int ad1836_remove(struct platform_device *pdev) struct snd_soc_codec_device soc_codec_dev_ad1836 = { .probe = ad1836_probe, .remove = ad1836_remove, - /* The power management of ad1836 is very simple. There are - * only adc&dac 2 components to control. Dapm handles them. - */ - .suspend = NULL, - .resume = NULL, }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836); -- cgit v0.10.2 From 667067d8980249a71ccf82a55202fff2cd1cd54f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Aug 2009 18:14:42 +0200 Subject: ALSA: hda - Fix / clean up IDT92HD83xxx codec parser A few improvements for IDT 92HD83xxx codec pareser: - Remove unused / deprecated mixer-amp controls - Handle d-mics as normal inputs since this codec has no separate MUXes for analog and digital - Don't create duplicated controls for capture volumes with Mux capture volumes Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f6d7ef4..7d33e0a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -359,14 +359,9 @@ static unsigned long stac92hd73xx_capvols[] = { }; #define stac92hd73xx_capsws stac92hd73xx_capvols -#define STAC92HD83XXX_NUM_DMICS 2 -static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { - 0x11, 0x12, 0 -}; - #define STAC92HD83_DAC_COUNT 3 -static hda_nid_t stac92hd83xxx_dmux_nids[2] = { +static hda_nid_t stac92hd83xxx_mux_nids[2] = { 0x17, 0x18, }; @@ -386,10 +381,6 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = { 0x03, 0x0c, 0x20, 0x40, }; -static hda_nid_t stac92hd83xxx_amp_nids[1] = { - 0xc, -}; - #define STAC92HD83XXX_NUM_CAPS 2 static unsigned long stac92hd83xxx_capvols[] = { HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), @@ -1212,26 +1203,6 @@ static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = { }; -static struct snd_kcontrol_new stac92hd83xxx_mixer[] = { - HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT), - - HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x4, HDA_INPUT), - - HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x0, HDA_INPUT), - - HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x2, HDA_INPUT), - - /* - HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x1, HDA_INPUT), - */ - { } /* end */ -}; - static struct snd_kcontrol_new stac92hd71bxx_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2) }; @@ -3521,19 +3492,33 @@ static int stac92xx_beep_switch_ctl(struct hda_codec *codec) static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - int wcaps, nid, i, err = 0; + int i, j, err = 0; for (i = 0; i < spec->num_muxes; i++) { + hda_nid_t nid; + unsigned int wcaps; + unsigned long val; + nid = spec->mux_nids[i]; wcaps = get_wcaps(codec, nid); + if (!(wcaps & AC_WCAP_OUT_AMP)) + continue; - if (wcaps & AC_WCAP_OUT_AMP) { - err = stac92xx_add_control_idx(spec, - STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; + /* check whether already the same control was created as + * normal Capture Volume. + */ + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + for (j = 0; j < spec->num_caps; j++) { + if (spec->capvols[j] == val) + break; } + if (j < spec->num_caps) + continue; + + err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, i, + "Mux Capture Volume", val); + if (err < 0) + return err; } return 0; }; @@ -3588,6 +3573,24 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, return -1; } +/* create a volume assigned to the given pin (only if supported) */ +static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid, + const char *label) +{ + unsigned int caps, nums; + char name[32]; + + if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) + return 0; + caps = query_amp_caps(codec, nid, HDA_OUTPUT); + nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; + if (!nums) + return 0; + snprintf(name, sizeof(name), "%s Capture Volume", label); + return stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); +} + /* create playback/capture controls for input pins on dmic capable codecs */ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) @@ -3597,7 +3600,6 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, struct hda_input_mux *dimux = &spec->private_dimux; int err, i, active_mics; unsigned int def_conf; - char name[32]; dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; dimux->items[dimux->num_items].index = 0; @@ -3605,6 +3607,10 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, active_mics = 0; for (i = 0; i < spec->num_dmics; i++) { + /* check the validity: sometimes it's a dead vendor-spec node */ + if (get_wcaps_type(get_wcaps(codec, spec->dmic_nids[i])) + != AC_WID_PIN) + continue; def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) active_mics++; @@ -3613,14 +3619,15 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, for (i = 0; i < spec->num_dmics; i++) { hda_nid_t nid; int index; - unsigned int wcaps; const char *label; - def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); + nid = spec->dmic_nids[i]; + if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) + continue; + def_conf = snd_hda_codec_get_pincfg(codec, nid); if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) continue; - nid = spec->dmic_nids[i]; index = get_connection_index(codec, spec->dmux_nids[0], nid); if (index < 0) continue; @@ -3630,21 +3637,9 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, else label = stac92xx_dmic_labels[dimux->num_items]; - wcaps = get_wcaps(codec, nid) & - (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); - - if (wcaps) { - sprintf(name, "%s Capture Volume", label); - - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_VOL, - name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - (wcaps & AC_WCAP_OUT_AMP) ? - HDA_OUTPUT : HDA_INPUT)); - if (err < 0) - return err; - } + err = create_elem_capture_vol(codec, nid, label); + if (err < 0) + return err; dimux->items[dimux->num_items].label = label; dimux->items[dimux->num_items].index = index; @@ -3746,29 +3741,29 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const { struct sigmatel_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux; - hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; - int i, j, k; + int i, j; for (i = 0; i < AUTO_PIN_LAST; i++) { - int index; + hda_nid_t nid = cfg->input_pins[i]; + int index, err; - if (!cfg->input_pins[i]) + if (!nid) continue; index = -1; for (j = 0; j < spec->num_muxes; j++) { - int num_cons; - num_cons = snd_hda_get_connections(codec, - spec->mux_nids[j], - con_lst, - HDA_MAX_NUM_INPUTS); - for (k = 0; k < num_cons; k++) - if (con_lst[k] == cfg->input_pins[i]) { - index = k; - goto found; - } + index = get_connection_index(codec, spec->mux_nids[j], + nid); + if (index >= 0) + break; } - continue; - found: + if (index < 0) + continue; + + err = create_elem_capture_vol(codec, nid, + auto_pin_cfg_labels[i]); + if (err < 0) + return err; + imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; imux->items[imux->num_items].index = index; imux->num_items++; @@ -5299,22 +5294,16 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; spec->mono_nid = 0x19; spec->digbeep_nid = 0x21; - spec->dmic_nids = stac92hd83xxx_dmic_nids; - spec->dmux_nids = stac92hd83xxx_dmux_nids; + spec->mux_nids = stac92hd83xxx_mux_nids; + spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids); spec->adc_nids = stac92hd83xxx_adc_nids; spec->pwr_nids = stac92hd83xxx_pwr_nids; - spec->amp_nids = stac92hd83xxx_amp_nids; spec->pwr_mapping = stac92hd83xxx_pwr_mapping; spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); spec->multiout.dac_nids = spec->dac_nids; spec->init = stac92hd83xxx_core_init; - spec->mixer = stac92hd83xxx_mixer; spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids); - spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids); - spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); - spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids); - spec->num_dmics = STAC92HD83XXX_NUM_DMICS; spec->pin_nids = stac92hd83xxx_pin_nids; spec->num_caps = STAC92HD83XXX_NUM_CAPS; spec->capvols = stac92hd83xxx_capvols; -- cgit v0.10.2 From a2342ae325bb1f65d90a9f38baab4c9762018a5e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 29 Jul 2009 21:21:49 +0100 Subject: ASoC: Factor out shared code from WM8993 The WM8993 analogue control is shared with other devices in the same product line. Since this is a very substantial proportion of the driver move the definitions of these controls into a new wm_hubs module which allows them to be shared between the two. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index dd9b295..910b916 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -64,6 +64,10 @@ config SND_SOC_ALL_CODECS If unsure select "N". +config SND_SOC_WM_HUBS + tristate + default y if SND_SOC_WM8993=y + default m if SND_SOC_WM8993=m config SND_SOC_AC97_CODEC tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9cbcf8f..c7fd229 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -41,6 +41,7 @@ snd-soc-wm9081-objs := wm9081.o snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o +snd-soc-wm-hubs-objs := wm_hubs.o # Amp snd-soc-max9877-objs := max9877.o @@ -88,6 +89,7 @@ obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o +obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index e246ca0..cd15669 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -27,6 +27,7 @@ #include #include "wm8993.h" +#include "wm_hubs.h" static u16 wm8993_reg_defaults[WM8993_REGISTER_COUNT] = { 0x8993, /* R0 - Software Reset */ @@ -557,28 +558,6 @@ static int configure_clock(struct snd_soc_codec *codec) return 0; } -static void wait_for_dc_servo(struct snd_soc_codec *codec, int mask) -{ - unsigned int reg; - int count = 0; - - dev_dbg(codec->dev, "Waiting for DC servo...\n"); - do { - count++; - msleep(1); - reg = wm8993_read(codec, WM8993_DC_SERVO_READBACK_0); - dev_dbg(codec->dev, "DC servo status: %x\n", reg); - } while ((reg & WM8993_DCS_CAL_COMPLETE_MASK) - != WM8993_DCS_CAL_COMPLETE_MASK && count < 1000); - - if ((reg & WM8993_DCS_CAL_COMPLETE_MASK) - != WM8993_DCS_CAL_COMPLETE_MASK) - dev_err(codec->dev, "Timed out waiting for DC Servo\n"); -} - -static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1650, 150, 0); -static const DECLARE_TLV_DB_SCALE(inmix_sw_tlv, 0, 3000, 0); -static const DECLARE_TLV_DB_SCALE(inmix_tlv, -1500, 300, 1); static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0); static const DECLARE_TLV_DB_SCALE(drc_comp_threash, -4500, 75, 0); static const DECLARE_TLV_DB_SCALE(drc_comp_amp, -2250, 75, 0); @@ -593,33 +572,6 @@ static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -1800, 300, 0); static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); -static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0); -static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0); -static const DECLARE_TLV_DB_SCALE(spkmix_tlv, -300, 300, 0); -static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1); -static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0); -static const unsigned int spkboost_tlv[] = { - TLV_DB_RANGE_HEAD(7), - 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0), - 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0), -}; -static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0); - -static const char *speaker_ref_text[] = { - "SPKVDD/2", - "VMID", -}; - -static const struct soc_enum speaker_ref = - SOC_ENUM_SINGLE(WM8993_SPEAKER_MIXER, 8, 2, speaker_ref_text); - -static const char *speaker_mode_text[] = { - "Class D", - "Class AB", -}; - -static const struct soc_enum speaker_mode = - SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text); static const char *dac_deemph_text[] = { "None", @@ -731,73 +683,7 @@ static const char *drc_smooth_text[] = { static const struct soc_enum drc_smooth = SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 4, 3, drc_smooth_text); - -/* - * Update the DC servo calibration on gain changes - */ -static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int ret; - - ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); - - /* Only need to do this if the outputs are active */ - if (wm8993_read(codec, WM8993_POWER_MANAGEMENT_1) - & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA)) - snd_soc_update_bits(codec, - WM8993_DC_SERVO_0, - WM8993_DCS_TRIG_SINGLE_0 | - WM8993_DCS_TRIG_SINGLE_1, - WM8993_DCS_TRIG_SINGLE_0 | - WM8993_DCS_TRIG_SINGLE_1); - - return ret; -} - static const struct snd_kcontrol_new wm8993_snd_controls[] = { -SOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0, - inpga_tlv), -SOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1), -SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 0), - -SOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0, - inpga_tlv), -SOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1), -SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 0), - - -SOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0, - inpga_tlv), -SOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1), -SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 0), - -SOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0, - inpga_tlv), -SOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1), -SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 0), - -SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0, - inmix_sw_tlv), -SOC_SINGLE_TLV("MIXINL IN1L Volume", WM8993_INPUT_MIXER3, 4, 1, 0, - inmix_sw_tlv), -SOC_SINGLE_TLV("MIXINL Output Record Volume", WM8993_INPUT_MIXER3, 0, 7, 0, - inmix_tlv), -SOC_SINGLE_TLV("MIXINL IN1LP Volume", WM8993_INPUT_MIXER5, 6, 7, 0, inmix_tlv), -SOC_SINGLE_TLV("MIXINL Direct Voice Volume", WM8993_INPUT_MIXER5, 0, 6, 0, - inmix_tlv), - -SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8993_INPUT_MIXER4, 7, 1, 0, - inmix_sw_tlv), -SOC_SINGLE_TLV("MIXINR IN1R Volume", WM8993_INPUT_MIXER4, 4, 1, 0, - inmix_sw_tlv), -SOC_SINGLE_TLV("MIXINR Output Record Volume", WM8993_INPUT_MIXER4, 0, 7, 0, - inmix_tlv), -SOC_SINGLE_TLV("MIXINR IN1RP Volume", WM8993_INPUT_MIXER6, 6, 7, 0, inmix_tlv), -SOC_SINGLE_TLV("MIXINR Direct Voice Volume", WM8993_INPUT_MIXER6, 0, 6, 0, - inmix_tlv), - SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE, 5, 9, 12, 0, sidetone_tlv), @@ -840,112 +726,11 @@ SOC_SINGLE_TLV("Playback Boost Volume", WM8993_AUDIO_INTERFACE_2, 10, 3, 0, dac_boost_tlv), SOC_ENUM("DAC Deemphasis", dac_deemph), -SOC_SINGLE_TLV("Left Output Mixer IN2RN Volume", WM8993_OUTPUT_MIXER5, 6, 7, 1, - outmix_tlv), -SOC_SINGLE_TLV("Left Output Mixer IN2LN Volume", WM8993_OUTPUT_MIXER3, 6, 7, 1, - outmix_tlv), -SOC_SINGLE_TLV("Left Output Mixer IN2LP Volume", WM8993_OUTPUT_MIXER3, 9, 7, 1, - outmix_tlv), -SOC_SINGLE_TLV("Left Output Mixer IN1L Volume", WM8993_OUTPUT_MIXER3, 0, 7, 1, - outmix_tlv), -SOC_SINGLE_TLV("Left Output Mixer IN1R Volume", WM8993_OUTPUT_MIXER3, 3, 7, 1, - outmix_tlv), -SOC_SINGLE_TLV("Left Output Mixer Right Input Volume", - WM8993_OUTPUT_MIXER5, 3, 7, 1, outmix_tlv), -SOC_SINGLE_TLV("Left Output Mixer Left Input Volume", - WM8993_OUTPUT_MIXER5, 0, 7, 1, outmix_tlv), -SOC_SINGLE_TLV("Left Output Mixer DAC Volume", WM8993_OUTPUT_MIXER5, 9, 7, 1, - outmix_tlv), - -SOC_SINGLE_TLV("Right Output Mixer IN2LN Volume", - WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv), -SOC_SINGLE_TLV("Right Output Mixer IN2RN Volume", - WM8993_OUTPUT_MIXER4, 6, 7, 1, outmix_tlv), -SOC_SINGLE_TLV("Right Output Mixer IN1L Volume", - WM8993_OUTPUT_MIXER4, 3, 7, 1, outmix_tlv), -SOC_SINGLE_TLV("Right Output Mixer IN1R Volume", - WM8993_OUTPUT_MIXER4, 0, 7, 1, outmix_tlv), -SOC_SINGLE_TLV("Right Output Mixer IN2RP Volume", - WM8993_OUTPUT_MIXER4, 9, 7, 1, outmix_tlv), -SOC_SINGLE_TLV("Right Output Mixer Left Input Volume", - WM8993_OUTPUT_MIXER6, 3, 7, 1, outmix_tlv), -SOC_SINGLE_TLV("Right Output Mixer Right Input Volume", - WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv), -SOC_SINGLE_TLV("Right Output Mixer DAC Volume", - WM8993_OUTPUT_MIXER6, 9, 7, 1, outmix_tlv), - -SOC_DOUBLE_R_TLV("Output Volume", WM8993_LEFT_OPGA_VOLUME, - WM8993_RIGHT_OPGA_VOLUME, 0, 63, 0, outpga_tlv), -SOC_DOUBLE_R("Output Switch", WM8993_LEFT_OPGA_VOLUME, - WM8993_RIGHT_OPGA_VOLUME, 6, 1, 0), -SOC_DOUBLE_R("Output ZC Switch", WM8993_LEFT_OPGA_VOLUME, - WM8993_RIGHT_OPGA_VOLUME, 7, 1, 0), - -SOC_SINGLE("Earpiece Switch", WM8993_HPOUT2_VOLUME, 5, 1, 1), -SOC_SINGLE_TLV("Earpiece Volume", WM8993_HPOUT2_VOLUME, 4, 1, 1, earpiece_tlv), - -SOC_SINGLE_TLV("SPKL Input Volume", WM8993_SPKMIXL_ATTENUATION, - 5, 1, 1, spkmix_tlv), -SOC_SINGLE_TLV("SPKL IN1LP Volume", WM8993_SPKMIXL_ATTENUATION, - 4, 1, 1, spkmix_tlv), -SOC_SINGLE_TLV("SPKL Output Volume", WM8993_SPKMIXL_ATTENUATION, - 3, 1, 1, spkmix_tlv), SOC_SINGLE_TLV("SPKL DAC Volume", WM8993_SPKMIXL_ATTENUATION, - 2, 1, 1, spkmix_tlv), - -SOC_SINGLE_TLV("SPKR Input Volume", WM8993_SPKMIXR_ATTENUATION, - 5, 1, 1, spkmix_tlv), -SOC_SINGLE_TLV("SPKR IN1RP Volume", WM8993_SPKMIXR_ATTENUATION, - 4, 1, 1, spkmix_tlv), -SOC_SINGLE_TLV("SPKR Output Volume", WM8993_SPKMIXR_ATTENUATION, - 3, 1, 1, spkmix_tlv), -SOC_SINGLE_TLV("SPKR DAC Volume", WM8993_SPKMIXR_ATTENUATION, - 2, 1, 1, spkmix_tlv), - -SOC_DOUBLE_R_TLV("Speaker Mixer Volume", - WM8993_SPKMIXL_ATTENUATION, WM8993_SPKMIXR_ATTENUATION, - 0, 3, 1, spkmixout_tlv), -SOC_DOUBLE_R_TLV("Speaker Volume", - WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT, - 0, 63, 0, outpga_tlv), -SOC_DOUBLE_R("Speaker Switch", - WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT, - 6, 1, 0), -SOC_DOUBLE_R("Speaker ZC Switch", - WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT, - 7, 1, 0), -SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 0, 3, 7, 0, - spkboost_tlv), -SOC_ENUM("Speaker Reference", speaker_ref), -SOC_ENUM("Speaker Mode", speaker_mode), + 2, 1, 1, wm_hubs_spkmix_tlv), -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Volume", - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_READWRITE, - .tlv.p = outpga_tlv, - .info = snd_soc_info_volsw_2r, - .get = snd_soc_get_volsw_2r, .put = wm8993_put_dc_servo, - .private_value = (unsigned long)&(struct soc_mixer_control) { - .reg = WM8993_LEFT_OUTPUT_VOLUME, - .rreg = WM8993_RIGHT_OUTPUT_VOLUME, - .shift = 0, .max = 63 - }, -}, -SOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME, - WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0), -SOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME, - WM8993_RIGHT_OUTPUT_VOLUME, 7, 1, 0), - -SOC_SINGLE("LINEOUT1N Switch", WM8993_LINE_OUTPUTS_VOLUME, 6, 1, 1), -SOC_SINGLE("LINEOUT1P Switch", WM8993_LINE_OUTPUTS_VOLUME, 5, 1, 1), -SOC_SINGLE_TLV("LINEOUT1 Volume", WM8993_LINE_OUTPUTS_VOLUME, 4, 1, 1, - line_tlv), - -SOC_SINGLE("LINEOUT2N Switch", WM8993_LINE_OUTPUTS_VOLUME, 2, 1, 1), -SOC_SINGLE("LINEOUT2P Switch", WM8993_LINE_OUTPUTS_VOLUME, 1, 1, 1), -SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1, - line_tlv), +SOC_SINGLE_TLV("SPKR DAC Volume", WM8993_SPKMIXR_ATTENUATION, + 2, 1, 1, wm_hubs_spkmix_tlv), }; static const struct snd_kcontrol_new wm8993_eq_controls[] = { @@ -956,31 +741,6 @@ SOC_SINGLE_TLV("EQ4 Volume", WM8993_EQ5, 0, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ5 Volume", WM8993_EQ6, 0, 24, 0, eq_tlv), }; -static int wm8993_earpiece_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *control, int event) -{ - struct snd_soc_codec *codec = w->codec; - u16 reg = wm8993_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - reg |= WM8993_HPOUT2_IN_ENA; - wm8993_write(codec, WM8993_ANTIPOP1, reg); - udelay(50); - break; - - case SND_SOC_DAPM_POST_PMD: - wm8993_write(codec, WM8993_ANTIPOP1, reg); - break; - - default: - BUG(); - break; - } - - return 0; -} - static int clk_sys_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1006,8 +766,8 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w, * Currently the only supported paths are the direct DAC->headphone * paths (which provide minimum power consumption anyway). */ -static int wm8993_class_w_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int class_w_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = widget->codec; @@ -1052,160 +812,9 @@ static int wm8993_class_w_put(struct snd_kcontrol *kcontrol, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_enum_double, \ .get = snd_soc_dapm_get_enum_double, \ - .put = wm8993_class_w_put, \ + .put = class_w_put, \ .private_value = (unsigned long)&xenum } -static int hp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - unsigned int reg = wm8993_read(codec, WM8993_ANALOGUE_HP_0); - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, - WM8993_CP_ENA, WM8993_CP_ENA); - - msleep(5); - - snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, - WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, - WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA); - - reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY; - wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg); - - /* Start the DC servo */ - snd_soc_update_bits(codec, WM8993_DC_SERVO_0, - WM8993_DCS_ENA_CHAN_0 | - WM8993_DCS_ENA_CHAN_1 | - WM8993_DCS_TRIG_STARTUP_1 | - WM8993_DCS_TRIG_STARTUP_0, - WM8993_DCS_ENA_CHAN_0 | - WM8993_DCS_ENA_CHAN_1 | - WM8993_DCS_TRIG_STARTUP_1 | - WM8993_DCS_TRIG_STARTUP_0); - wait_for_dc_servo(codec, WM8993_DCS_TRIG_STARTUP_0 | - WM8993_DCS_TRIG_STARTUP_1); - snd_soc_update_bits(codec, WM8993_DC_SERVO_1, - WM8993_DCS_TIMER_PERIOD_01_MASK, 0xa); - - reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | - WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; - wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg); - break; - - case SND_SOC_DAPM_PRE_PMD: - reg &= ~(WM8993_HPOUT1L_RMV_SHORT | - WM8993_HPOUT1L_DLY | - WM8993_HPOUT1L_OUTP | - WM8993_HPOUT1R_RMV_SHORT | - WM8993_HPOUT1R_DLY | - WM8993_HPOUT1R_OUTP); - - snd_soc_update_bits(codec, WM8993_DC_SERVO_1, - WM8993_DCS_TIMER_PERIOD_01_MASK, 0); - snd_soc_update_bits(codec, WM8993_DC_SERVO_0, - WM8993_DCS_ENA_CHAN_0 | - WM8993_DCS_ENA_CHAN_1, 0); - - wm8993_write(codec, WM8993_ANALOGUE_HP_0, reg); - snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, - WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, - 0); - - snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, - WM8993_CP_ENA, 0); - break; - } - - return 0; -} - -static const struct snd_kcontrol_new in1l_pga[] = { -SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0), -SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0), -}; - -static const struct snd_kcontrol_new in1r_pga[] = { -SOC_DAPM_SINGLE("IN1RP Switch", WM8993_INPUT_MIXER2, 1, 1, 0), -SOC_DAPM_SINGLE("IN1RN Switch", WM8993_INPUT_MIXER2, 0, 1, 0), -}; - -static const struct snd_kcontrol_new in2l_pga[] = { -SOC_DAPM_SINGLE("IN2LP Switch", WM8993_INPUT_MIXER2, 7, 1, 0), -SOC_DAPM_SINGLE("IN2LN Switch", WM8993_INPUT_MIXER2, 6, 1, 0), -}; - -static const struct snd_kcontrol_new in2r_pga[] = { -SOC_DAPM_SINGLE("IN2RP Switch", WM8993_INPUT_MIXER2, 3, 1, 0), -SOC_DAPM_SINGLE("IN2RN Switch", WM8993_INPUT_MIXER2, 2, 1, 0), -}; - -static const struct snd_kcontrol_new mixinl[] = { -SOC_DAPM_SINGLE("IN2L Switch", WM8993_INPUT_MIXER3, 8, 1, 0), -SOC_DAPM_SINGLE("IN1L Switch", WM8993_INPUT_MIXER3, 5, 1, 0), -}; - -static const struct snd_kcontrol_new mixinr[] = { -SOC_DAPM_SINGLE("IN2R Switch", WM8993_INPUT_MIXER4, 8, 1, 0), -SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0), -}; - -static const struct snd_kcontrol_new left_output_mixer[] = { -SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0), -SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0), -SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0), -SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0), -SOC_DAPM_SINGLE("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0), -SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0), -SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0), -SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0), -}; - -static const struct snd_kcontrol_new right_output_mixer[] = { -SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0), -SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0), -SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0), -SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0), -SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0), -SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0), -SOC_DAPM_SINGLE("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0), -SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0), -}; - -static const struct snd_kcontrol_new earpiece_mixer[] = { -SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_HPOUT2_MIXER, 5, 1, 0), -SOC_DAPM_SINGLE("Left Output Switch", WM8993_HPOUT2_MIXER, 4, 1, 0), -SOC_DAPM_SINGLE("Right Output Switch", WM8993_HPOUT2_MIXER, 3, 1, 0), -}; - -static const struct snd_kcontrol_new left_speaker_mixer[] = { -SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 7, 1, 0), -SOC_DAPM_SINGLE("IN1LP Switch", WM8993_SPEAKER_MIXER, 5, 1, 0), -SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 3, 1, 0), -SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 6, 1, 0), -}; - -static const struct snd_kcontrol_new right_speaker_mixer[] = { -SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 6, 1, 0), -SOC_DAPM_SINGLE("IN1RP Switch", WM8993_SPEAKER_MIXER, 4, 1, 0), -SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 2, 1, 0), -SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 0, 1, 0), -}; - -static const struct snd_kcontrol_new left_speaker_boost[] = { -SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 5, 1, 0), -SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 4, 1, 0), -SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 3, 1, 0), -}; - -static const struct snd_kcontrol_new right_speaker_boost[] = { -SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 2, 1, 0), -SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 1, 1, 0), -SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 0, 1, 0), -}; - static const char *hp_mux_text[] = { "Mixer", "DAC", @@ -1223,71 +832,26 @@ static const struct soc_enum hpr_enum = static const struct snd_kcontrol_new hpr_mux = SOC_DAPM_ENUM_W("Right Headphone Mux", hpr_enum); -static const struct snd_kcontrol_new line1_mix[] = { -SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER1, 2, 1, 0), -SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER1, 1, 1, 0), -SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER1, 0, 1, 0), -}; - -static const struct snd_kcontrol_new line1n_mix[] = { -SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 6, 1, 0), -SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER1, 5, 1, 0), -}; - -static const struct snd_kcontrol_new line1p_mix[] = { -SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0), -}; - -static const struct snd_kcontrol_new line2_mix[] = { -SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0), -SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0), -SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), -}; - -static const struct snd_kcontrol_new line2n_mix[] = { -SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0), -SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0), +static const struct snd_kcontrol_new left_speaker_mixer[] = { +SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 7, 1, 0), +SOC_DAPM_SINGLE("IN1LP Switch", WM8993_SPEAKER_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 3, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 6, 1, 0), }; -static const struct snd_kcontrol_new line2p_mix[] = { -SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), +static const struct snd_kcontrol_new right_speaker_mixer[] = { +SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 6, 1, 0), +SOC_DAPM_SINGLE("IN1RP Switch", WM8993_SPEAKER_MIXER, 4, 1, 0), +SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 2, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 0, 1, 0), }; static const struct snd_soc_dapm_widget wm8993_dapm_widgets[] = { -SND_SOC_DAPM_INPUT("IN1LN"), -SND_SOC_DAPM_INPUT("IN1LP"), -SND_SOC_DAPM_INPUT("IN2LN"), -SND_SOC_DAPM_INPUT("IN2LP/VXRN"), -SND_SOC_DAPM_INPUT("IN1RN"), -SND_SOC_DAPM_INPUT("IN1RP"), -SND_SOC_DAPM_INPUT("IN2RN"), -SND_SOC_DAPM_INPUT("IN2RP/VXRP"), - SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8993_BUS_CONTROL_1, 1, 0, clk_sys_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("TOCLK", WM8993_CLOCKING_1, 14, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8993_CLOCKING_3, 0, 0, NULL, 0), -SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0), -SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0), - -SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0, - in1l_pga, ARRAY_SIZE(in1l_pga)), -SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0, - in1r_pga, ARRAY_SIZE(in1r_pga)), - -SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0, - in2l_pga, ARRAY_SIZE(in2l_pga)), -SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0, - in2r_pga, ARRAY_SIZE(in2r_pga)), - -/* Dummy widgets to represent differential paths */ -SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), - -SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0, - mixinl, ARRAY_SIZE(mixinl)), -SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0, - mixinr, ARRAY_SIZE(mixinr)), SND_SOC_DAPM_ADC("ADCL", "Capture", WM8993_POWER_MANAGEMENT_2, 1, 0), SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0), @@ -1295,110 +859,19 @@ SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0), SND_SOC_DAPM_DAC("DACL", "Playback", WM8993_POWER_MANAGEMENT_3, 1, 0), SND_SOC_DAPM_DAC("DACR", "Playback", WM8993_POWER_MANAGEMENT_3, 0, 0), -SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0, - left_output_mixer, ARRAY_SIZE(left_output_mixer)), -SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0, - right_output_mixer, ARRAY_SIZE(right_output_mixer)), - -SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0), -SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0), - -SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, - earpiece_mixer, ARRAY_SIZE(earpiece_mixer)), -SND_SOC_DAPM_PGA_E("Earpiece Driver", WM8993_POWER_MANAGEMENT_1, 11, 0, - NULL, 0, wm8993_earpiece_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), +SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0, left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), SND_SOC_DAPM_MIXER("SPKR", WM8993_POWER_MANAGEMENT_3, 9, 0, right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), -SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0, - left_speaker_boost, ARRAY_SIZE(left_speaker_boost)), -SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0, - right_speaker_boost, ARRAY_SIZE(right_speaker_boost)), - -SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0, - NULL, 0), -SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0, - NULL, 0), - -SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), -SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), -SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, - NULL, 0, - hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - -SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0, - line1_mix, ARRAY_SIZE(line1_mix)), -SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0, - line2_mix, ARRAY_SIZE(line2_mix)), - -SND_SOC_DAPM_MIXER("LINEOUT1N Mixer", SND_SOC_NOPM, 0, 0, - line1n_mix, ARRAY_SIZE(line1n_mix)), -SND_SOC_DAPM_MIXER("LINEOUT1P Mixer", SND_SOC_NOPM, 0, 0, - line1p_mix, ARRAY_SIZE(line1p_mix)), -SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0, - line2n_mix, ARRAY_SIZE(line2n_mix)), -SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0, - line2p_mix, ARRAY_SIZE(line2p_mix)), - -SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, - NULL, 0), -SND_SOC_DAPM_PGA("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0, - NULL, 0), -SND_SOC_DAPM_PGA("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0, - NULL, 0), -SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, - NULL, 0), - -SND_SOC_DAPM_OUTPUT("SPKOUTLP"), -SND_SOC_DAPM_OUTPUT("SPKOUTLN"), -SND_SOC_DAPM_OUTPUT("SPKOUTRP"), -SND_SOC_DAPM_OUTPUT("SPKOUTRN"), -SND_SOC_DAPM_OUTPUT("HPOUT1L"), -SND_SOC_DAPM_OUTPUT("HPOUT1R"), -SND_SOC_DAPM_OUTPUT("HPOUT2P"), -SND_SOC_DAPM_OUTPUT("HPOUT2N"), -SND_SOC_DAPM_OUTPUT("LINEOUT1P"), -SND_SOC_DAPM_OUTPUT("LINEOUT1N"), -SND_SOC_DAPM_OUTPUT("LINEOUT2P"), -SND_SOC_DAPM_OUTPUT("LINEOUT2N"), }; static const struct snd_soc_dapm_route routes[] = { - { "IN1L PGA", "IN1LP Switch", "IN1LP" }, - { "IN1L PGA", "IN1LN Switch", "IN1LN" }, - - { "IN1R PGA", "IN1RP Switch", "IN1RP" }, - { "IN1R PGA", "IN1RN Switch", "IN1RN" }, - - { "IN2L PGA", "IN2LP Switch", "IN2LP/VXRN" }, - { "IN2L PGA", "IN2LN Switch", "IN2LN" }, - - { "IN2R PGA", "IN2RP Switch", "IN2RP/VXRP" }, - { "IN2R PGA", "IN2RN Switch", "IN2RN" }, - - { "Direct Voice", NULL, "IN2LP/VXRN" }, - { "Direct Voice", NULL, "IN2RP/VXRP" }, - - { "MIXINL", "IN1L Switch", "IN1L PGA" }, - { "MIXINL", "IN2L Switch", "IN2L PGA" }, - { "MIXINL", NULL, "Direct Voice" }, - { "MIXINL", NULL, "IN1LP" }, - { "MIXINL", NULL, "Left Output Mixer" }, - - { "MIXINR", "IN1R Switch", "IN1R PGA" }, - { "MIXINR", "IN2R Switch", "IN2R PGA" }, - { "MIXINR", NULL, "Direct Voice" }, - { "MIXINR", NULL, "IN1RP" }, - { "MIXINR", NULL, "Right Output Mixer" }, - - { "ADCL", NULL, "MIXINL" }, { "ADCL", NULL, "CLK_SYS" }, { "ADCL", NULL, "CLK_DSP" }, - { "ADCR", NULL, "MIXINR" }, { "ADCR", NULL, "CLK_SYS" }, { "ADCR", NULL, "CLK_DSP" }, @@ -1407,128 +880,22 @@ static const struct snd_soc_dapm_route routes[] = { { "DACR", NULL, "CLK_SYS" }, { "DACR", NULL, "CLK_DSP" }, - { "Left Output Mixer", "Left Input Switch", "MIXINL" }, - { "Left Output Mixer", "Right Input Switch", "MIXINR" }, - { "Left Output Mixer", "IN2RN Switch", "IN2RN" }, - { "Left Output Mixer", "IN2LN Switch", "IN2LN" }, - { "Left Output Mixer", "IN2LP Switch", "IN2LP/VXRN" }, - { "Left Output Mixer", "IN1L Switch", "IN1L PGA" }, - { "Left Output Mixer", "IN1R Switch", "IN1R PGA" }, { "Left Output Mixer", "DAC Switch", "DACL" }, - { "Right Output Mixer", "Left Input Switch", "MIXINL" }, - { "Right Output Mixer", "Right Input Switch", "MIXINR" }, - { "Right Output Mixer", "IN2LN Switch", "IN2LN" }, - { "Right Output Mixer", "IN2RN Switch", "IN2RN" }, - { "Right Output Mixer", "IN2RP Switch", "IN2RP/VXRP" }, - { "Right Output Mixer", "IN1L Switch", "IN1L PGA" }, - { "Right Output Mixer", "IN1R Switch", "IN1R PGA" }, { "Right Output Mixer", "DAC Switch", "DACR" }, - { "Left Output PGA", NULL, "Left Output Mixer" }, { "Left Output PGA", NULL, "CLK_SYS" }, - { "Left Output PGA", NULL, "TOCLK" }, - { "Right Output PGA", NULL, "Right Output Mixer" }, { "Right Output PGA", NULL, "CLK_SYS" }, - { "Right Output PGA", NULL, "TOCLK" }, - - { "Earpiece Mixer", "Direct Voice Switch", "Direct Voice" }, - { "Earpiece Mixer", "Left Output Switch", "Left Output PGA" }, - { "Earpiece Mixer", "Right Output Switch", "Right Output PGA" }, - { "Earpiece Driver", NULL, "Earpiece Mixer" }, - { "HPOUT2N", NULL, "Earpiece Driver" }, - { "HPOUT2P", NULL, "Earpiece Driver" }, - - { "SPKL", "Input Switch", "MIXINL" }, - { "SPKL", "IN1LP Switch", "IN1LP" }, - { "SPKL", "Output Switch", "Left Output Mixer" }, { "SPKL", "DAC Switch", "DACL" }, { "SPKL", NULL, "CLK_SYS" }, - { "SPKL", NULL, "TOCLK" }, - { "SPKR", "Input Switch", "MIXINR" }, - { "SPKR", "IN1RP Switch", "IN1RP" }, - { "SPKR", "Output Switch", "Right Output Mixer" }, { "SPKR", "DAC Switch", "DACR" }, { "SPKR", NULL, "CLK_SYS" }, - { "SPKR", NULL, "TOCLK" }, - - { "SPKL Boost", "Direct Voice Switch", "Direct Voice" }, - { "SPKL Boost", "SPKL Switch", "SPKL" }, - { "SPKL Boost", "SPKR Switch", "SPKR" }, - - { "SPKR Boost", "Direct Voice Switch", "Direct Voice" }, - { "SPKR Boost", "SPKR Switch", "SPKR" }, - { "SPKR Boost", "SPKL Switch", "SPKL" }, - - { "SPKL Driver", NULL, "SPKL Boost" }, - { "SPKL Driver", NULL, "CLK_SYS" }, - - { "SPKR Driver", NULL, "SPKR Boost" }, - { "SPKR Driver", NULL, "CLK_SYS" }, - - { "SPKOUTLP", NULL, "SPKL Driver" }, - { "SPKOUTLN", NULL, "SPKL Driver" }, - { "SPKOUTRP", NULL, "SPKR Driver" }, - { "SPKOUTRN", NULL, "SPKR Driver" }, { "Left Headphone Mux", "DAC", "DACL" }, - { "Left Headphone Mux", "Mixer", "Left Output Mixer" }, { "Right Headphone Mux", "DAC", "DACR" }, - { "Right Headphone Mux", "Mixer", "Right Output Mixer" }, - - { "Headphone PGA", NULL, "Left Headphone Mux" }, - { "Headphone PGA", NULL, "Right Headphone Mux" }, - { "Headphone PGA", NULL, "CLK_SYS" }, - { "Headphone PGA", NULL, "TOCLK" }, - - { "HPOUT1L", NULL, "Headphone PGA" }, - { "HPOUT1R", NULL, "Headphone PGA" }, - - { "LINEOUT1N", NULL, "LINEOUT1N Driver" }, - { "LINEOUT1P", NULL, "LINEOUT1P Driver" }, - { "LINEOUT2N", NULL, "LINEOUT2N Driver" }, - { "LINEOUT2P", NULL, "LINEOUT2P Driver" }, -}; - -static const struct snd_soc_dapm_route lineout1_diff_routes[] = { - { "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" }, - { "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" }, - { "LINEOUT1 Mixer", "Output Switch", "Left Output Mixer" }, - - { "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" }, - { "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" }, -}; - -static const struct snd_soc_dapm_route lineout1_se_routes[] = { - { "LINEOUT1N Mixer", "Left Output Switch", "Left Output Mixer" }, - { "LINEOUT1N Mixer", "Right Output Switch", "Left Output Mixer" }, - - { "LINEOUT1P Mixer", "Left Output Switch", "Left Output Mixer" }, - - { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, - { "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" }, -}; - -static const struct snd_soc_dapm_route lineout2_diff_routes[] = { - { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" }, - { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" }, - { "LINEOUT2 Mixer", "Output Switch", "Right Output Mixer" }, - - { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" }, - { "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" }, -}; - -static const struct snd_soc_dapm_route lineout2_se_routes[] = { - { "LINEOUT2N Mixer", "Left Output Switch", "Left Output Mixer" }, - { "LINEOUT2N Mixer", "Right Output Switch", "Left Output Mixer" }, - - { "LINEOUT2P Mixer", "Right Output Switch", "Right Output Mixer" }, - - { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, - { "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" }, }; static int wm8993_set_bias_level(struct snd_soc_codec *codec, @@ -1950,26 +1317,11 @@ static int wm8993_probe(struct platform_device *pdev) snd_soc_dapm_new_controls(codec, wm8993_dapm_widgets, ARRAY_SIZE(wm8993_dapm_widgets)); + wm_hubs_add_analogue_controls(codec); snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes)); - - if (wm8993->pdata.lineout1_diff) - snd_soc_dapm_add_routes(codec, - lineout1_diff_routes, - ARRAY_SIZE(lineout1_diff_routes)); - else - snd_soc_dapm_add_routes(codec, - lineout1_se_routes, - ARRAY_SIZE(lineout1_se_routes)); - - if (wm8993->pdata.lineout2_diff) - snd_soc_dapm_add_routes(codec, - lineout2_diff_routes, - ARRAY_SIZE(lineout2_diff_routes)); - else - snd_soc_dapm_add_routes(codec, - lineout2_se_routes, - ARRAY_SIZE(lineout2_se_routes)); + wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff, + wm8993->pdata.lineout2_diff); snd_soc_dapm_new_widgets(codec); @@ -2066,30 +1418,6 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, wm8993->class_w_users = 2; /* Latch volume update bits and default ZC on */ - snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME, - WM8993_IN1_VU, WM8993_IN1_VU); - snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, - WM8993_IN1_VU, WM8993_IN1_VU); - snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_3_4_VOLUME, - WM8993_IN2_VU, WM8993_IN2_VU); - snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, - WM8993_IN2_VU, WM8993_IN2_VU); - - snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT, - WM8993_SPKOUT_VU, WM8993_SPKOUT_VU); - - snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME, - WM8993_HPOUT1L_ZC, WM8993_HPOUT1L_ZC); - snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME, - WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC, - WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC); - - snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME, - WM8993_MIXOUTL_ZC, WM8993_MIXOUTL_ZC); - snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME, - WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU, - WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU); - snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME, WM8993_DAC_VU, WM8993_DAC_VU); snd_soc_update_bits(codec, WM8993_RIGHT_ADC_DIGITAL_VOLUME, diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c new file mode 100644 index 0000000..e8fc474 --- /dev/null +++ b/sound/soc/codecs/wm_hubs.c @@ -0,0 +1,758 @@ +/* + * wm_hubs.c -- WM8993/4 common code + * + * Copyright 2009 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8993.h" +#include "wm_hubs.h" + +const DECLARE_TLV_DB_SCALE(wm_hubs_spkmix_tlv, -300, 300, 0); +EXPORT_SYMBOL_GPL(wm_hubs_spkmix_tlv); + +static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1650, 150, 0); +static const DECLARE_TLV_DB_SCALE(inmix_sw_tlv, 0, 3000, 0); +static const DECLARE_TLV_DB_SCALE(inmix_tlv, -1500, 300, 1); +static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0); +static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1); +static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0); +static const unsigned int spkboost_tlv[] = { + TLV_DB_RANGE_HEAD(7), + 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0), + 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0), +}; +static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0); + +static const char *speaker_ref_text[] = { + "SPKVDD/2", + "VMID", +}; + +static const struct soc_enum speaker_ref = + SOC_ENUM_SINGLE(WM8993_SPEAKER_MIXER, 8, 2, speaker_ref_text); + +static const char *speaker_mode_text[] = { + "Class D", + "Class AB", +}; + +static const struct soc_enum speaker_mode = + SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text); + +static void wait_for_dc_servo(struct snd_soc_codec *codec) +{ + unsigned int reg; + int count = 0; + + dev_dbg(codec->dev, "Waiting for DC servo...\n"); + do { + count++; + msleep(1); + reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_0); + dev_dbg(codec->dev, "DC servo status: %x\n", reg); + } while ((reg & WM8993_DCS_CAL_COMPLETE_MASK) + != WM8993_DCS_CAL_COMPLETE_MASK && count < 1000); + + if ((reg & WM8993_DCS_CAL_COMPLETE_MASK) + != WM8993_DCS_CAL_COMPLETE_MASK) + dev_err(codec->dev, "Timed out waiting for DC Servo\n"); +} + +/* + * Update the DC servo calibration on gain changes + */ +static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int ret; + + ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); + + /* Only need to do this if the outputs are active */ + if (snd_soc_read(codec, WM8993_POWER_MANAGEMENT_1) + & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA)) + snd_soc_update_bits(codec, + WM8993_DC_SERVO_0, + WM8993_DCS_TRIG_SINGLE_0 | + WM8993_DCS_TRIG_SINGLE_1, + WM8993_DCS_TRIG_SINGLE_0 | + WM8993_DCS_TRIG_SINGLE_1); + + return ret; +} + +static const struct snd_kcontrol_new analogue_snd_controls[] = { +SOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0, + inpga_tlv), +SOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1), +SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 0), + +SOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0, + inpga_tlv), +SOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1), +SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 0), + + +SOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0, + inpga_tlv), +SOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1), +SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 0), + +SOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0, + inpga_tlv), +SOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1), +SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 0), + +SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0, + inmix_sw_tlv), +SOC_SINGLE_TLV("MIXINL IN1L Volume", WM8993_INPUT_MIXER3, 4, 1, 0, + inmix_sw_tlv), +SOC_SINGLE_TLV("MIXINL Output Record Volume", WM8993_INPUT_MIXER3, 0, 7, 0, + inmix_tlv), +SOC_SINGLE_TLV("MIXINL IN1LP Volume", WM8993_INPUT_MIXER5, 6, 7, 0, inmix_tlv), +SOC_SINGLE_TLV("MIXINL Direct Voice Volume", WM8993_INPUT_MIXER5, 0, 6, 0, + inmix_tlv), + +SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8993_INPUT_MIXER4, 7, 1, 0, + inmix_sw_tlv), +SOC_SINGLE_TLV("MIXINR IN1R Volume", WM8993_INPUT_MIXER4, 4, 1, 0, + inmix_sw_tlv), +SOC_SINGLE_TLV("MIXINR Output Record Volume", WM8993_INPUT_MIXER4, 0, 7, 0, + inmix_tlv), +SOC_SINGLE_TLV("MIXINR IN1RP Volume", WM8993_INPUT_MIXER6, 6, 7, 0, inmix_tlv), +SOC_SINGLE_TLV("MIXINR Direct Voice Volume", WM8993_INPUT_MIXER6, 0, 6, 0, + inmix_tlv), + +SOC_SINGLE_TLV("Left Output Mixer IN2RN Volume", WM8993_OUTPUT_MIXER5, 6, 7, 1, + outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer IN2LN Volume", WM8993_OUTPUT_MIXER3, 6, 7, 1, + outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer IN2LP Volume", WM8993_OUTPUT_MIXER3, 9, 7, 1, + outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer IN1L Volume", WM8993_OUTPUT_MIXER3, 0, 7, 1, + outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer IN1R Volume", WM8993_OUTPUT_MIXER3, 3, 7, 1, + outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer Right Input Volume", + WM8993_OUTPUT_MIXER5, 3, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer Left Input Volume", + WM8993_OUTPUT_MIXER5, 0, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Left Output Mixer DAC Volume", WM8993_OUTPUT_MIXER5, 9, 7, 1, + outmix_tlv), + +SOC_SINGLE_TLV("Right Output Mixer IN2LN Volume", + WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer IN2RN Volume", + WM8993_OUTPUT_MIXER4, 6, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer IN1L Volume", + WM8993_OUTPUT_MIXER4, 3, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer IN1R Volume", + WM8993_OUTPUT_MIXER4, 0, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer IN2RP Volume", + WM8993_OUTPUT_MIXER4, 9, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer Left Input Volume", + WM8993_OUTPUT_MIXER6, 3, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer Right Input Volume", + WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv), +SOC_SINGLE_TLV("Right Output Mixer DAC Volume", + WM8993_OUTPUT_MIXER6, 9, 7, 1, outmix_tlv), + +SOC_DOUBLE_R_TLV("Output Volume", WM8993_LEFT_OPGA_VOLUME, + WM8993_RIGHT_OPGA_VOLUME, 0, 63, 0, outpga_tlv), +SOC_DOUBLE_R("Output Switch", WM8993_LEFT_OPGA_VOLUME, + WM8993_RIGHT_OPGA_VOLUME, 6, 1, 0), +SOC_DOUBLE_R("Output ZC Switch", WM8993_LEFT_OPGA_VOLUME, + WM8993_RIGHT_OPGA_VOLUME, 7, 1, 0), + +SOC_SINGLE("Earpiece Switch", WM8993_HPOUT2_VOLUME, 5, 1, 1), +SOC_SINGLE_TLV("Earpiece Volume", WM8993_HPOUT2_VOLUME, 4, 1, 1, earpiece_tlv), + +SOC_SINGLE_TLV("SPKL Input Volume", WM8993_SPKMIXL_ATTENUATION, + 5, 1, 1, wm_hubs_spkmix_tlv), +SOC_SINGLE_TLV("SPKL IN1LP Volume", WM8993_SPKMIXL_ATTENUATION, + 4, 1, 1, wm_hubs_spkmix_tlv), +SOC_SINGLE_TLV("SPKL Output Volume", WM8993_SPKMIXL_ATTENUATION, + 3, 1, 1, wm_hubs_spkmix_tlv), + +SOC_SINGLE_TLV("SPKR Input Volume", WM8993_SPKMIXR_ATTENUATION, + 5, 1, 1, wm_hubs_spkmix_tlv), +SOC_SINGLE_TLV("SPKR IN1RP Volume", WM8993_SPKMIXR_ATTENUATION, + 4, 1, 1, wm_hubs_spkmix_tlv), +SOC_SINGLE_TLV("SPKR Output Volume", WM8993_SPKMIXR_ATTENUATION, + 3, 1, 1, wm_hubs_spkmix_tlv), + +SOC_DOUBLE_R_TLV("Speaker Mixer Volume", + WM8993_SPKMIXL_ATTENUATION, WM8993_SPKMIXR_ATTENUATION, + 0, 3, 1, spkmixout_tlv), +SOC_DOUBLE_R_TLV("Speaker Volume", + WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT, + 0, 63, 0, outpga_tlv), +SOC_DOUBLE_R("Speaker Switch", + WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT, + 6, 1, 0), +SOC_DOUBLE_R("Speaker ZC Switch", + WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT, + 7, 1, 0), +SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 0, 3, 7, 0, + spkboost_tlv), +SOC_ENUM("Speaker Reference", speaker_ref), +SOC_ENUM("Speaker Mode", speaker_mode), + +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Volume", + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_READWRITE, + .tlv.p = outpga_tlv, + .info = snd_soc_info_volsw_2r, + .get = snd_soc_get_volsw_2r, .put = wm8993_put_dc_servo, + .private_value = (unsigned long)&(struct soc_mixer_control) { + .reg = WM8993_LEFT_OUTPUT_VOLUME, + .rreg = WM8993_RIGHT_OUTPUT_VOLUME, + .shift = 0, .max = 63 + }, +}, +SOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME, + WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0), +SOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME, + WM8993_RIGHT_OUTPUT_VOLUME, 7, 1, 0), + +SOC_SINGLE("LINEOUT1N Switch", WM8993_LINE_OUTPUTS_VOLUME, 6, 1, 1), +SOC_SINGLE("LINEOUT1P Switch", WM8993_LINE_OUTPUTS_VOLUME, 5, 1, 1), +SOC_SINGLE_TLV("LINEOUT1 Volume", WM8993_LINE_OUTPUTS_VOLUME, 4, 1, 1, + line_tlv), + +SOC_SINGLE("LINEOUT2N Switch", WM8993_LINE_OUTPUTS_VOLUME, 2, 1, 1), +SOC_SINGLE("LINEOUT2P Switch", WM8993_LINE_OUTPUTS_VOLUME, 1, 1, 1), +SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1, + line_tlv), +}; + +static int hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + unsigned int reg = snd_soc_read(codec, WM8993_ANALOGUE_HP_0); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, + WM8993_CP_ENA, WM8993_CP_ENA); + + msleep(5); + + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, + WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, + WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA); + + reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY; + snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); + + /* Start the DC servo */ + snd_soc_update_bits(codec, WM8993_DC_SERVO_0, + WM8993_DCS_ENA_CHAN_0 | + WM8993_DCS_ENA_CHAN_1 | + WM8993_DCS_TRIG_STARTUP_1 | + WM8993_DCS_TRIG_STARTUP_0, + WM8993_DCS_ENA_CHAN_0 | + WM8993_DCS_ENA_CHAN_1 | + WM8993_DCS_TRIG_STARTUP_1 | + WM8993_DCS_TRIG_STARTUP_0); + wait_for_dc_servo(codec); + snd_soc_update_bits(codec, WM8993_DC_SERVO_1, + WM8993_DCS_TIMER_PERIOD_01_MASK, 0xa); + + reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | + WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; + snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); + break; + + case SND_SOC_DAPM_PRE_PMD: + reg &= ~(WM8993_HPOUT1L_RMV_SHORT | + WM8993_HPOUT1L_DLY | + WM8993_HPOUT1L_OUTP | + WM8993_HPOUT1R_RMV_SHORT | + WM8993_HPOUT1R_DLY | + WM8993_HPOUT1R_OUTP); + + snd_soc_update_bits(codec, WM8993_DC_SERVO_1, + WM8993_DCS_TIMER_PERIOD_01_MASK, 0); + snd_soc_update_bits(codec, WM8993_DC_SERVO_0, + WM8993_DCS_ENA_CHAN_0 | + WM8993_DCS_ENA_CHAN_1, 0); + + snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); + snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, + WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, + 0); + + snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, + WM8993_CP_ENA, 0); + break; + } + + return 0; +} + +static int earpiece_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *control, int event) +{ + struct snd_soc_codec *codec = w->codec; + u16 reg = snd_soc_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + reg |= WM8993_HPOUT2_IN_ENA; + snd_soc_write(codec, WM8993_ANTIPOP1, reg); + udelay(50); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_write(codec, WM8993_ANTIPOP1, reg); + break; + + default: + BUG(); + break; + } + + return 0; +} + +static const struct snd_kcontrol_new in1l_pga[] = { +SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0), +SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0), +}; + +static const struct snd_kcontrol_new in1r_pga[] = { +SOC_DAPM_SINGLE("IN1RP Switch", WM8993_INPUT_MIXER2, 1, 1, 0), +SOC_DAPM_SINGLE("IN1RN Switch", WM8993_INPUT_MIXER2, 0, 1, 0), +}; + +static const struct snd_kcontrol_new in2l_pga[] = { +SOC_DAPM_SINGLE("IN2LP Switch", WM8993_INPUT_MIXER2, 7, 1, 0), +SOC_DAPM_SINGLE("IN2LN Switch", WM8993_INPUT_MIXER2, 6, 1, 0), +}; + +static const struct snd_kcontrol_new in2r_pga[] = { +SOC_DAPM_SINGLE("IN2RP Switch", WM8993_INPUT_MIXER2, 3, 1, 0), +SOC_DAPM_SINGLE("IN2RN Switch", WM8993_INPUT_MIXER2, 2, 1, 0), +}; + +static const struct snd_kcontrol_new mixinl[] = { +SOC_DAPM_SINGLE("IN2L Switch", WM8993_INPUT_MIXER3, 8, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_INPUT_MIXER3, 5, 1, 0), +}; + +static const struct snd_kcontrol_new mixinr[] = { +SOC_DAPM_SINGLE("IN2R Switch", WM8993_INPUT_MIXER4, 8, 1, 0), +SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0), +}; + +static const struct snd_kcontrol_new left_output_mixer[] = { +SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0), +SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0), +SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0), +SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0), +SOC_DAPM_SINGLE("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0), +SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0), +}; + +static const struct snd_kcontrol_new right_output_mixer[] = { +SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0), +SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0), +SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0), +SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0), +SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0), +SOC_DAPM_SINGLE("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0), +SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0), +}; + +static const struct snd_kcontrol_new earpiece_mixer[] = { +SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_HPOUT2_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("Left Output Switch", WM8993_HPOUT2_MIXER, 4, 1, 0), +SOC_DAPM_SINGLE("Right Output Switch", WM8993_HPOUT2_MIXER, 3, 1, 0), +}; + +static const struct snd_kcontrol_new left_speaker_boost[] = { +SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 5, 1, 0), +SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 4, 1, 0), +SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 3, 1, 0), +}; + +static const struct snd_kcontrol_new right_speaker_boost[] = { +SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 2, 1, 0), +SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 1, 1, 0), +SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 0, 1, 0), +}; + +static const struct snd_kcontrol_new line1_mix[] = { +SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER1, 2, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER1, 1, 1, 0), +SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER1, 0, 1, 0), +}; + +static const struct snd_kcontrol_new line1n_mix[] = { +SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 6, 1, 0), +SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER1, 5, 1, 0), +}; + +static const struct snd_kcontrol_new line1p_mix[] = { +SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0), +}; + +static const struct snd_kcontrol_new line2_mix[] = { +SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0), +SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0), +SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), +}; + +static const struct snd_kcontrol_new line2n_mix[] = { +SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0), +SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0), +}; + +static const struct snd_kcontrol_new line2p_mix[] = { +SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), +}; + +static const struct snd_soc_dapm_widget analogue_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("IN1LN"), +SND_SOC_DAPM_INPUT("IN1LP"), +SND_SOC_DAPM_INPUT("IN2LN"), +SND_SOC_DAPM_INPUT("IN2LP/VXRN"), +SND_SOC_DAPM_INPUT("IN1RN"), +SND_SOC_DAPM_INPUT("IN1RP"), +SND_SOC_DAPM_INPUT("IN2RN"), +SND_SOC_DAPM_INPUT("IN2RP/VXRP"), + +SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0), +SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0), + +SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0, + in1l_pga, ARRAY_SIZE(in1l_pga)), +SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0, + in1r_pga, ARRAY_SIZE(in1r_pga)), + +SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0, + in2l_pga, ARRAY_SIZE(in2l_pga)), +SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0, + in2r_pga, ARRAY_SIZE(in2r_pga)), + +/* Dummy widgets to represent differential paths */ +SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), + +SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0, + mixinl, ARRAY_SIZE(mixinl)), +SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0, + mixinr, ARRAY_SIZE(mixinr)), + +SND_SOC_DAPM_ADC("ADCL", "Capture", WM8993_POWER_MANAGEMENT_2, 1, 0), +SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0), + +SND_SOC_DAPM_DAC("DACL", "Playback", WM8993_POWER_MANAGEMENT_3, 1, 0), +SND_SOC_DAPM_DAC("DACR", "Playback", WM8993_POWER_MANAGEMENT_3, 0, 0), + +SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0, + left_output_mixer, ARRAY_SIZE(left_output_mixer)), +SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0, + right_output_mixer, ARRAY_SIZE(right_output_mixer)), + +SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0), + +SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, + NULL, 0, + hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, + earpiece_mixer, ARRAY_SIZE(earpiece_mixer)), +SND_SOC_DAPM_PGA_E("Earpiece Driver", WM8993_POWER_MANAGEMENT_1, 11, 0, + NULL, 0, earpiece_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + +SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0, + left_speaker_boost, ARRAY_SIZE(left_speaker_boost)), +SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0, + right_speaker_boost, ARRAY_SIZE(right_speaker_boost)), + +SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0, + NULL, 0), +SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0, + NULL, 0), + +SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0, + line1_mix, ARRAY_SIZE(line1_mix)), +SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0, + line2_mix, ARRAY_SIZE(line2_mix)), + +SND_SOC_DAPM_MIXER("LINEOUT1N Mixer", SND_SOC_NOPM, 0, 0, + line1n_mix, ARRAY_SIZE(line1n_mix)), +SND_SOC_DAPM_MIXER("LINEOUT1P Mixer", SND_SOC_NOPM, 0, 0, + line1p_mix, ARRAY_SIZE(line1p_mix)), +SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0, + line2n_mix, ARRAY_SIZE(line2n_mix)), +SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0, + line2p_mix, ARRAY_SIZE(line2p_mix)), + +SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0, + NULL, 0), + +SND_SOC_DAPM_OUTPUT("SPKOUTLP"), +SND_SOC_DAPM_OUTPUT("SPKOUTLN"), +SND_SOC_DAPM_OUTPUT("SPKOUTRP"), +SND_SOC_DAPM_OUTPUT("SPKOUTRN"), +SND_SOC_DAPM_OUTPUT("HPOUT1L"), +SND_SOC_DAPM_OUTPUT("HPOUT1R"), +SND_SOC_DAPM_OUTPUT("HPOUT2P"), +SND_SOC_DAPM_OUTPUT("HPOUT2N"), +SND_SOC_DAPM_OUTPUT("LINEOUT1P"), +SND_SOC_DAPM_OUTPUT("LINEOUT1N"), +SND_SOC_DAPM_OUTPUT("LINEOUT2P"), +SND_SOC_DAPM_OUTPUT("LINEOUT2N"), +}; + +static const struct snd_soc_dapm_route analogue_routes[] = { + { "IN1L PGA", "IN1LP Switch", "IN1LP" }, + { "IN1L PGA", "IN1LN Switch", "IN1LN" }, + + { "IN1R PGA", "IN1RP Switch", "IN1RP" }, + { "IN1R PGA", "IN1RN Switch", "IN1RN" }, + + { "IN2L PGA", "IN2LP Switch", "IN2LP/VXRN" }, + { "IN2L PGA", "IN2LN Switch", "IN2LN" }, + + { "IN2R PGA", "IN2RP Switch", "IN2RP/VXRP" }, + { "IN2R PGA", "IN2RN Switch", "IN2RN" }, + + { "Direct Voice", NULL, "IN2LP/VXRN" }, + { "Direct Voice", NULL, "IN2RP/VXRP" }, + + { "MIXINL", "IN1L Switch", "IN1L PGA" }, + { "MIXINL", "IN2L Switch", "IN2L PGA" }, + { "MIXINL", NULL, "Direct Voice" }, + { "MIXINL", NULL, "IN1LP" }, + { "MIXINL", NULL, "Left Output Mixer" }, + + { "MIXINR", "IN1R Switch", "IN1R PGA" }, + { "MIXINR", "IN2R Switch", "IN2R PGA" }, + { "MIXINR", NULL, "Direct Voice" }, + { "MIXINR", NULL, "IN1RP" }, + { "MIXINR", NULL, "Right Output Mixer" }, + + { "ADCL", NULL, "MIXINL" }, + { "ADCR", NULL, "MIXINR" }, + + { "Left Output Mixer", "Left Input Switch", "MIXINL" }, + { "Left Output Mixer", "Right Input Switch", "MIXINR" }, + { "Left Output Mixer", "IN2RN Switch", "IN2RN" }, + { "Left Output Mixer", "IN2LN Switch", "IN2LN" }, + { "Left Output Mixer", "IN2LP Switch", "IN2LP/VXRN" }, + { "Left Output Mixer", "IN1L Switch", "IN1L PGA" }, + { "Left Output Mixer", "IN1R Switch", "IN1R PGA" }, + + { "Right Output Mixer", "Left Input Switch", "MIXINL" }, + { "Right Output Mixer", "Right Input Switch", "MIXINR" }, + { "Right Output Mixer", "IN2LN Switch", "IN2LN" }, + { "Right Output Mixer", "IN2RN Switch", "IN2RN" }, + { "Right Output Mixer", "IN2RP Switch", "IN2RP/VXRP" }, + { "Right Output Mixer", "IN1L Switch", "IN1L PGA" }, + { "Right Output Mixer", "IN1R Switch", "IN1R PGA" }, + + { "Left Output PGA", NULL, "Left Output Mixer" }, + { "Left Output PGA", NULL, "TOCLK" }, + + { "Right Output PGA", NULL, "Right Output Mixer" }, + { "Right Output PGA", NULL, "TOCLK" }, + + { "Earpiece Mixer", "Direct Voice Switch", "Direct Voice" }, + { "Earpiece Mixer", "Left Output Switch", "Left Output PGA" }, + { "Earpiece Mixer", "Right Output Switch", "Right Output PGA" }, + + { "Earpiece Driver", NULL, "Earpiece Mixer" }, + { "HPOUT2N", NULL, "Earpiece Driver" }, + { "HPOUT2P", NULL, "Earpiece Driver" }, + + { "SPKL", "Input Switch", "MIXINL" }, + { "SPKL", "IN1LP Switch", "IN1LP" }, + { "SPKL", "Output Switch", "Left Output Mixer" }, + { "SPKL", NULL, "TOCLK" }, + + { "SPKR", "Input Switch", "MIXINR" }, + { "SPKR", "IN1RP Switch", "IN1RP" }, + { "SPKR", "Output Switch", "Right Output Mixer" }, + { "SPKR", NULL, "TOCLK" }, + + { "SPKL Boost", "Direct Voice Switch", "Direct Voice" }, + { "SPKL Boost", "SPKL Switch", "SPKL" }, + { "SPKL Boost", "SPKR Switch", "SPKR" }, + + { "SPKR Boost", "Direct Voice Switch", "Direct Voice" }, + { "SPKR Boost", "SPKR Switch", "SPKR" }, + { "SPKR Boost", "SPKL Switch", "SPKL" }, + + { "SPKL Driver", NULL, "SPKL Boost" }, + { "SPKL Driver", NULL, "CLK_SYS" }, + + { "SPKR Driver", NULL, "SPKR Boost" }, + { "SPKR Driver", NULL, "CLK_SYS" }, + + { "SPKOUTLP", NULL, "SPKL Driver" }, + { "SPKOUTLN", NULL, "SPKL Driver" }, + { "SPKOUTRP", NULL, "SPKR Driver" }, + { "SPKOUTRN", NULL, "SPKR Driver" }, + + { "Left Headphone Mux", "Mixer", "Left Output Mixer" }, + { "Right Headphone Mux", "Mixer", "Right Output Mixer" }, + + { "Headphone PGA", NULL, "Left Headphone Mux" }, + { "Headphone PGA", NULL, "Right Headphone Mux" }, + { "Headphone PGA", NULL, "CLK_SYS" }, + + { "HPOUT1L", NULL, "Headphone PGA" }, + { "HPOUT1R", NULL, "Headphone PGA" }, + + { "LINEOUT1N", NULL, "LINEOUT1N Driver" }, + { "LINEOUT1P", NULL, "LINEOUT1P Driver" }, + { "LINEOUT2N", NULL, "LINEOUT2N Driver" }, + { "LINEOUT2P", NULL, "LINEOUT2P Driver" }, +}; + +static const struct snd_soc_dapm_route lineout1_diff_routes[] = { + { "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" }, + { "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" }, + { "LINEOUT1 Mixer", "Output Switch", "Left Output Mixer" }, + + { "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" }, + { "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" }, +}; + +static const struct snd_soc_dapm_route lineout1_se_routes[] = { + { "LINEOUT1N Mixer", "Left Output Switch", "Left Output Mixer" }, + { "LINEOUT1N Mixer", "Right Output Switch", "Left Output Mixer" }, + + { "LINEOUT1P Mixer", "Left Output Switch", "Left Output Mixer" }, + + { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, + { "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" }, +}; + +static const struct snd_soc_dapm_route lineout2_diff_routes[] = { + { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" }, + { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" }, + { "LINEOUT2 Mixer", "Output Switch", "Right Output Mixer" }, + + { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" }, + { "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" }, +}; + +static const struct snd_soc_dapm_route lineout2_se_routes[] = { + { "LINEOUT2N Mixer", "Left Output Switch", "Left Output Mixer" }, + { "LINEOUT2N Mixer", "Right Output Switch", "Left Output Mixer" }, + + { "LINEOUT2P Mixer", "Right Output Switch", "Right Output Mixer" }, + + { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, + { "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" }, +}; + +int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec) +{ + /* Latch volume update bits & default ZC on */ + snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME, + WM8993_IN1_VU, WM8993_IN1_VU); + snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, + WM8993_IN1_VU, WM8993_IN1_VU); + snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_3_4_VOLUME, + WM8993_IN2_VU, WM8993_IN2_VU); + snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, + WM8993_IN2_VU, WM8993_IN2_VU); + + snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT, + WM8993_SPKOUT_VU, WM8993_SPKOUT_VU); + + snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME, + WM8993_HPOUT1L_ZC, WM8993_HPOUT1L_ZC); + snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME, + WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC, + WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC); + + snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME, + WM8993_MIXOUTL_ZC, WM8993_MIXOUTL_ZC); + snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME, + WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU, + WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU); + + snd_soc_add_controls(codec, analogue_snd_controls, + ARRAY_SIZE(analogue_snd_controls)); + + snd_soc_dapm_new_controls(codec, analogue_dapm_widgets, + ARRAY_SIZE(analogue_dapm_widgets)); + return 0; +} +EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls); + +int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec, + int lineout1_diff, int lineout2_diff) +{ + snd_soc_dapm_add_routes(codec, analogue_routes, + ARRAY_SIZE(analogue_routes)); + + if (lineout1_diff) + snd_soc_dapm_add_routes(codec, + lineout1_diff_routes, + ARRAY_SIZE(lineout1_diff_routes)); + else + snd_soc_dapm_add_routes(codec, + lineout1_se_routes, + ARRAY_SIZE(lineout1_se_routes)); + + if (lineout2_diff) + snd_soc_dapm_add_routes(codec, + lineout2_diff_routes, + ARRAY_SIZE(lineout2_diff_routes)); + else + snd_soc_dapm_add_routes(codec, + lineout2_se_routes, + ARRAY_SIZE(lineout2_se_routes)); + + return 0; +} +EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes); + +MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h new file mode 100644 index 0000000..ec09cb6 --- /dev/null +++ b/sound/soc/codecs/wm_hubs.h @@ -0,0 +1,24 @@ +/* + * wm_hubs.h -- WM899x common code + * + * Copyright 2009 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef _WM_HUBS_H +#define _WM_HUBS_H + +struct snd_soc_codec; + +extern const unsigned int wm_hubs_spkmix_tlv[]; + +extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); +extern int wm_hubs_add_analogue_routes(struct snd_soc_codec *, int, int); + +#endif -- cgit v0.10.2 From 6a99fb5fb85f267d075310fd30c4bf6f0ae63062 Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Tue, 11 Aug 2009 16:58:52 -0400 Subject: ASoC: DaVinci: McASP driver enhacements On DA830/OMAP-L137 and DA850/OMAP-L138 SoCs, the McASP peripheral has FIFO support. This FIFO provides additional data buffering. It also provides tolerance to variation in host/DMA controller response times. The read and write FIFO sizes are 256 bytes each. If FIFO is enabled, the DMA events from McASP are sent to the FIFO which in turn sends DMA requests to the host CPU according to the thresholds programmed. More details of the FIFO operation can be found at http://focus.ti.com/general/docs/lit/getliterature.tsp?literatureNumber= sprufm1&fileType=pdf This patch adds support for FIFO configuration. The platform data has a version field which differentiates the McASP on different SoCs. Signed-off-by: Chaithrika U S Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 2a56fb7..12a6c54 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -406,6 +406,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + dma_params->acnt = dma_params->data_type; rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1); xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1); diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index f0c0347..e672f43 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -102,6 +102,11 @@ /* Receive Buffer for Serializer n */ #define DAVINCI_MCASP_RXBUF_REG 0x280 +/* McASP FIFO Registers */ +#define DAVINCI_MCASP_WFIFOCTL (0x1010) +#define DAVINCI_MCASP_WFIFOSTS (0x1014) +#define DAVINCI_MCASP_RFIFOCTL (0x1018) +#define DAVINCI_MCASP_RFIFOSTS (0x101C) /* * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management @@ -276,6 +281,13 @@ */ #define TXDATADMADIS BIT(0) +/* + * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits + */ +#define FIFO_ENABLE BIT(16) +#define NUMEVT_MASK (0xFF << 8) +#define NUMDMA_MASK (0xFF) + #define DAVINCI_MCASP_NUM_SERIALIZER 16 static inline void mcasp_set_bits(void __iomem *reg, u32 val) @@ -345,6 +357,9 @@ static void mcasp_start_rx(struct davinci_audio_dev *dev) static void mcasp_start_tx(struct davinci_audio_dev *dev) { + u8 offset = 0, i; + u32 cnt; + mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); @@ -353,6 +368,19 @@ static void mcasp_start_tx(struct davinci_audio_dev *dev) mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0); + for (i = 0; i < dev->num_serializer; i++) { + if (dev->serial_dir[i] == TX_MODE) { + offset = i; + break; + } + } + + /* wait for TX ready */ + cnt = 0; + while (!(mcasp_get_reg(dev->base + DAVINCI_MCASP_XRSRCTL_REG(offset)) & + TXSTATE) && (cnt < 100000)) + cnt++; + mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0); } @@ -362,6 +390,13 @@ static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream) mcasp_start_tx(dev); else mcasp_start_rx(dev); + + /* enable FIFO */ + if (dev->txnumevt) + mcasp_set_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE); + + if (dev->rxnumevt) + mcasp_set_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE); } static void mcasp_stop_rx(struct davinci_audio_dev *dev) @@ -382,6 +417,13 @@ static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream) mcasp_stop_tx(dev); else mcasp_stop_rx(dev); + + /* disable FIFO */ + if (dev->txnumevt) + mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE); + + if (dev->rxnumevt) + mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE); } static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, @@ -401,7 +443,6 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x7 << 26)); break; - case SND_SOC_DAIFMT_CBM_CFM: /* codec is clock and frame master */ mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); @@ -505,6 +546,8 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev, static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) { int i; + u8 tx_ser = 0; + u8 rx_ser = 0; /* Default configuration */ mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); @@ -525,12 +568,37 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream) for (i = 0; i < dev->num_serializer; i++) { mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i), dev->serial_dir[i]); - if (dev->serial_dir[i] == TX_MODE) + if (dev->serial_dir[i] == TX_MODE) { mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AXR(i)); - else if (dev->serial_dir[i] == RX_MODE) + tx_ser++; + } else if (dev->serial_dir[i] == RX_MODE) { mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AXR(i)); + rx_ser++; + } + } + + if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (dev->txnumevt * tx_ser > 64) + dev->txnumevt = 1; + + mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, tx_ser, + NUMDMA_MASK); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, + ((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK); + mcasp_set_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE); + } + + if (dev->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) { + if (dev->rxnumevt * rx_ser > 64) + dev->rxnumevt = 1; + + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, rx_ser, + NUMDMA_MASK); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, + ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK); + mcasp_set_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE); } } @@ -543,6 +611,8 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) for (i = 0; i < active_slots; i++) mask |= (1 << i); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC); + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { /* bit stream is MSB first with no delay */ /* DSP_B mode */ @@ -622,8 +692,16 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct davinci_pcm_dma_params *dma_params = dev->dma_params[substream->stream]; int word_length; + u8 numevt; davinci_hw_common_param(dev, substream->stream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + numevt = dev->txnumevt; + else + numevt = dev->rxnumevt; + + if (!numevt) + numevt = 1; if (dev->op_mode == DAVINCI_MCASP_DIT_MODE) davinci_hw_dit_param(dev); @@ -650,6 +728,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); return -EINVAL; } + + if (dev->version == MCASP_VERSION_2) { + dma_params->data_type *= numevt; + dma_params->acnt = 4 * numevt; + } else + dma_params->acnt = dma_params->data_type; + davinci_config_channel_size(dev, word_length); return 0; @@ -778,6 +863,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dev->num_serializer = pdata->num_serializer; dev->serial_dir = pdata->serial_dir; dev->codec_fmt = pdata->codec_fmt; + dev->version = pdata->version; + dev->txnumevt = pdata->txnumevt; + dev->rxnumevt = pdata->rxnumevt; dma_data[count].name = "I2S PCM Stereo out"; dma_data[count].eventq_no = pdata->eventq_no; @@ -807,9 +895,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) } dma_data[count].channel = res->start; - davinci_mcasp_dai[pdev->id].private_data = dev; - davinci_mcasp_dai[pdev->id].dev = &pdev->dev; - ret = snd_soc_register_dai(&davinci_mcasp_dai[pdev->id]); + davinci_mcasp_dai[pdata->op_mode].private_data = dev; + davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev; + ret = snd_soc_register_dai(&davinci_mcasp_dai[pdata->op_mode]); if (ret != 0) goto err_release_region; @@ -827,12 +915,13 @@ err_release_dev: static int davinci_mcasp_remove(struct platform_device *pdev) { + struct snd_platform_data *pdata = pdev->dev.platform_data; struct davinci_pcm_dma_params *dma_data; struct davinci_audio_dev *dev; struct resource *mem; - snd_soc_unregister_dai(&davinci_mcasp_dai[pdev->id]); - dev = davinci_mcasp_dai[pdev->id].private_data; + snd_soc_unregister_dai(&davinci_mcasp_dai[pdata->op_mode]); + dev = davinci_mcasp_dai[pdata->op_mode].private_data; clk_disable(dev->clk); clk_put(dev->clk); dev->clk = NULL; diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 36b7104..554354c 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -50,6 +50,11 @@ struct davinci_audio_dev { u8 op_mode; u8 num_serializer; u8 *serial_dir; + u8 version; + + /* McASP FIFO related */ + u8 txnumevt; + u8 rxnumevt; }; #endif /* DAVINCI_MCASP_H */ diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index ab43a53..091dacb 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -67,6 +67,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) dma_addr_t src, dst; unsigned short src_bidx, dst_bidx; unsigned int data_type; + unsigned short acnt; unsigned int count; period_size = snd_pcm_lib_period_bytes(substream); @@ -91,11 +92,12 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) dst_bidx = data_type; } + acnt = prtd->params->acnt; edma_set_src(lch, src, INCR, W8BIT); edma_set_dest(lch, dst, INCR, W8BIT); edma_set_src_index(lch, src_bidx, 0); edma_set_dest_index(lch, dst_bidx, 0); - edma_set_transfer_params(lch, data_type, count, 1, 0, ASYNC); + edma_set_transfer_params(lch, acnt, count, 1, 0, ASYNC); prtd->period++; if (unlikely(prtd->period >= runtime->periods)) diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index eb4287f..63d9625 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -19,6 +19,7 @@ struct davinci_pcm_dma_params { char *name; /* stream identifier */ int channel; /* sync dma channel ID */ + unsigned short acnt; dma_addr_t dma_addr; /* device physical address for DMA */ enum dma_event_q eventq_no; /* event queue number */ unsigned char data_type; /* xfer data type */ -- cgit v0.10.2 From 517ee6cf699967b421bcf8967e7bbeb3c45ded1a Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Tue, 11 Aug 2009 16:59:12 -0400 Subject: ASoC: DaVinci: Add a DAI format to McASP driver The patch adds a DAI format: Codec bit clock master and frame sync slave, to the driver. Signed-off-by: Chaithrika U S Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index e672f43..eca22d7 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -443,6 +443,16 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x7 << 26)); break; + case SND_SOC_DAIFMT_CBM_CFS: + /* codec is clock master and frame slave */ + mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); + mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE); + + mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); + mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); + + mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x2d << 26)); + break; case SND_SOC_DAIFMT_CBM_CFM: /* codec is clock and frame master */ mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); -- cgit v0.10.2 From 30230f4cd7c002a40c13758d12c1c6d96100461d Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Tue, 11 Aug 2009 16:59:21 -0400 Subject: ASoC: DaVinci: Add audio support fot DA850/OMAP-L138 EVM There is one instance of McASP on DA850/OMAP-L138 SoC. This is connected to TLV320AIC3106 codec for audio playback and capture. This patch adds audio support on this platform. Some of the structure prefix names which are common for DA830/OMAP-L137 EVM and DA850/OMAP-L138 EVM have been renamed to da8xx from da830. Signed-off-by: Chaithrika U S Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 677a538..4dfd4ad 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -43,12 +43,21 @@ config SND_DAVINCI_SOC_SFFSDR Lyrtech SFFSDR board. config SND_DA830_SOC_EVM - tristate "SoC Audio support for DA830/OMAPL137 EVM" + tristate "SoC Audio support for DA830/OMAP-L137 EVM" depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM select SND_DAVINCI_SOC_MCASP select SND_SOC_TLV320AIC3X help Say Y if you want to add support for SoC audio on TI - DA830/OMAPL137 EVM + DA830/OMAP-L137 EVM + +config SND_DA850_SOC_EVM + tristate "SoC Audio support for DA850/OMAP-L138 EVM" + depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM + select SND_DAVINCI_SOC_MCASP + select SND_SOC_TLV320AIC3X + help + Say Y if you want to add support for SoC audio on TI + DA850/OMAP-L138 EVM diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index 5e2195f..a6939d7 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -14,4 +14,5 @@ snd-soc-sffsdr-objs := davinci-sffsdr.o obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o +obj-$(CONFIG_SND_DA850_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index a5a9212..46c1b0c 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -54,7 +54,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream, else if (machine_is_davinci_evm()) sysclk = 12288000; - else if (machine_is_davinci_da830_evm()) + else if (machine_is_davinci_da830_evm() || + machine_is_davinci_da850_evm()) sysclk = 24576000; else @@ -165,7 +166,7 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = { .ops = &evm_ops, }, }; -static struct snd_soc_dai_link da830_evm_dai = { +static struct snd_soc_dai_link da8xx_evm_dai = { .name = "TLV320AIC3X", .stream_name = "AIC3X", .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI], @@ -191,8 +192,15 @@ static struct snd_soc_card dm6467_snd_soc_card_evm = { }; static struct snd_soc_card da830_snd_soc_card = { - .name = "DA830 EVM", - .dai_link = &da830_evm_dai, + .name = "DA830/OMAP-L137 EVM", + .dai_link = &da8xx_evm_dai, + .platform = &davinci_soc_platform, + .num_links = 1, +}; + +static struct snd_soc_card da850_snd_soc_card = { + .name = "DA850/OMAP-L138 EVM", + .dai_link = &da8xx_evm_dai, .platform = &davinci_soc_platform, .num_links = 1, }; @@ -209,7 +217,7 @@ static struct aic3x_setup_data dm6467_evm_aic3x_setup = { .i2c_address = 0x18, }; -static struct aic3x_setup_data da830_evm_aic3x_setup = { +static struct aic3x_setup_data da8xx_evm_aic3x_setup = { .i2c_bus = 1, .i2c_address = 0x18, }; @@ -232,7 +240,13 @@ static struct snd_soc_device dm6467_evm_snd_devdata = { static struct snd_soc_device da830_evm_snd_devdata = { .card = &da830_snd_soc_card, .codec_dev = &soc_codec_dev_aic3x, - .codec_data = &da830_evm_aic3x_setup, + .codec_data = &da8xx_evm_aic3x_setup, +}; + +static struct snd_soc_device da850_evm_snd_devdata = { + .card = &da850_snd_soc_card, + .codec_dev = &soc_codec_dev_aic3x, + .codec_data = &da8xx_evm_aic3x_setup, }; static struct platform_device *evm_snd_device; @@ -255,6 +269,9 @@ static int __init evm_init(void) } else if (machine_is_davinci_da830_evm()) { evm_snd_dev_data = &da830_evm_snd_devdata; index = 1; + } else if (machine_is_davinci_da850_evm()) { + evm_snd_dev_data = &da850_evm_snd_devdata; + index = 0; } else return -EINVAL; -- cgit v0.10.2 From 4ac0478f2afaf8e778b4190d6218459a9dbf2a8f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 30 Jul 2009 02:55:01 +0200 Subject: ALSA: Allow passing platform_data for pxa2xx-ac97 This patch adds support for passing platform data to ac97 bus devices from PXA2xx-AC97 driver.. Signed-off-by: Marek Vasut Signed-off-by: Mark Brown diff --git a/arch/arm/mach-pxa/include/mach/audio.h b/arch/arm/mach-pxa/include/mach/audio.h index 16eb025..a3449e3 100644 --- a/arch/arm/mach-pxa/include/mach/audio.h +++ b/arch/arm/mach-pxa/include/mach/audio.h @@ -3,10 +3,12 @@ #include #include +#include /* * @reset_gpio: AC97 reset gpio (normally gpio113 or gpio95) * a -1 value means no gpio will be used for reset + * @codec_pdata: AC97 codec platform_data * reset_gpio should only be specified for pxa27x CPUs where a silicon * bug prevents correct operation of the reset line. If not specified, @@ -20,6 +22,7 @@ typedef struct { void (*resume)(void *); void *priv; int reset_gpio; + void *codec_pdata[AC97_BUS_MAX_DEVICES]; } pxa2xx_audio_ops_t; extern void pxa_set_ac97_info(pxa2xx_audio_ops_t *ops); diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 9b1c098..3dae3f7 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -32,6 +32,9 @@ #include "control.h" #include "info.h" +/* maximum number of devices on the AC97 bus */ +#define AC97_BUS_MAX_DEVICES 4 + /* * AC'97 codec registers */ diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index c570ebd..6c00ea4 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -170,6 +170,13 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) struct snd_ac97_bus *ac97_bus; struct snd_ac97_template ac97_template; int ret; + pxa2xx_audio_ops_t *pdata = dev->dev.platform_data; + + if (dev->id >= 0) { + dev_err(&dev->dev, "PXA2xx has only one AC97 port.\n"); + ret = -ENXIO; + goto err_dev; + } ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, 0, &card); @@ -200,6 +207,8 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) snprintf(card->longname, sizeof(card->longname), "%s (%s)", dev->dev.driver->name, card->mixername); + if (pdata && pdata->codec_data) + snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata); snd_card_set_dev(card, &dev->dev); ret = snd_card_register(card); if (ret == 0) { @@ -212,6 +221,7 @@ err_remove: err: if (card) snd_card_free(card); +err_dev: return ret; } diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index d9c94d7..7330e5c 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "pxa2xx-pcm.h" #include "pxa2xx-ac97.h" @@ -241,9 +242,18 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops); static int __devinit pxa2xx_ac97_dev_probe(struct platform_device *pdev) { int i; + pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data; - for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++) + if (pdev->id >= 0) { + dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n"); + return -ENXIO; + } + + for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++) { pxa_ac97_dai[i].dev = &pdev->dev; + if (pdata && pdata->codec_pdata) + pxa_ac97_dai[i].ac97_pdata = pdata->codec_pdata; + } /* Punt most of the init to the SoC probe; we may need the machine * driver to do interesting things with the clocking to get us up -- cgit v0.10.2 From 60d970c254b95ec7a0fc4c590b510253987b64a0 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 13 Aug 2009 23:37:26 +0200 Subject: tracing: Fix syscall tracing on !HAVE_FTRACE_SYSCALLS architectures The new syscall_regfunc()/unregfunc() functions rely on the existence of TIF_SYSCALL_FTRACE - but that TIF flag is only offered by HAVE_FTRACE_SYSCALLS. Cc: Frederic Weisbecker Cc: Jason Baron Cc: Steven Rostedt Cc: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 070a42b..35dd27a 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -579,6 +579,8 @@ __initcall(init_tracepoints); #endif /* CONFIG_MODULES */ +#ifdef CONFIG_FTRACE_SYSCALLS + static DEFINE_MUTEX(regfunc_mutex); static int sys_tracepoint_refcount; @@ -615,3 +617,4 @@ void syscall_unregfunc(void) } mutex_unlock(®func_mutex); } +#endif -- cgit v0.10.2 From 9b0365f1954b0b54a896171b4438ed42ad7ef02f Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Wed, 12 Aug 2009 21:01:29 +0000 Subject: be2net:Creating/destroying queues regardless of netif_running() in suspend/resume path Signed-off-by: sarveshwarb Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 2db879c..45507d8 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1972,9 +1972,9 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) if (netif_running(netdev)) { rtnl_lock(); be_close(netdev); - be_clear(adapter); rtnl_unlock(); } + be_clear(adapter); pci_save_state(pdev); pci_disable_device(pdev); @@ -1997,9 +1997,9 @@ static int be_resume(struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); + be_setup(adapter); if (netif_running(netdev)) { rtnl_lock(); - be_setup(adapter); be_open(netdev); rtnl_unlock(); } -- cgit v0.10.2 From a6fa32866567351503db8a5c3466a676ba08595f Mon Sep 17 00:00:00 2001 From: Jens Rosenboom Date: Wed, 12 Aug 2009 22:16:04 +0000 Subject: ipv6: Log the explicit address that triggered DAD failure If an interface has multiple addresses, the current message for DAD failure isn't really helpful, so this patch adds the address itself to the printk. Signed-off-by: Jens Rosenboom Signed-off-by: David S. Miller diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 9eb68e9..1ba42bd 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -955,8 +955,8 @@ static void ndisc_recv_na(struct sk_buff *skb) */ if (skb->pkt_type != PACKET_LOOPBACK) ND_PRINTK1(KERN_WARNING - "ICMPv6 NA: someone advertises our address on %s!\n", - ifp->idev->dev->name); + "ICMPv6 NA: someone advertises our address %pI6 on %s!\n", + &ifp->addr, ifp->idev->dev->name); in6_ifa_put(ifp); return; } -- cgit v0.10.2 From 8dd07086a1f8048428d33a1917b6209978750cb1 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Mon, 10 Aug 2009 01:29:52 +0000 Subject: lmc: Read outside array bounds If dev_alloc_skb() fails on the first iteration of the allocation loop, then we end up writing before the start of the array. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index d1492ae..6e6b08c 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1897,11 +1897,12 @@ static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/ /* * Sets end of ring */ - sc->lmc_rxring[i - 1].length |= 0x02000000; /* Set end of buffers flag */ - sc->lmc_rxring[i - 1].buffer2 = virt_to_bus (&sc->lmc_rxring[0]); /* Point back to the start */ + if (i != 0) { + sc->lmc_rxring[i - 1].length |= 0x02000000; /* Set end of buffers flag */ + sc->lmc_rxring[i - 1].buffer2 = virt_to_bus(&sc->lmc_rxring[0]); /* Point back to the start */ + } LMC_CSR_WRITE (sc, csr_rxlist, virt_to_bus (sc->lmc_rxring)); /* write base address */ - /* Initialize the transmit rings and buffers */ for (i = 0; i < LMC_TXDESCS; i++) { -- cgit v0.10.2 From 3982d3d28b02bed5312015762fe2112ccbaf9051 Mon Sep 17 00:00:00 2001 From: "Fischer, Anna" Date: Thu, 13 Aug 2009 06:55:16 +0000 Subject: net/bridge: Add 'hairpin' port forwarding mode This patch adds a 'hairpin' (also called 'reflective relay') mode port configuration to the Linux Ethernet bridge kernel module. A bridge supporting hairpin forwarding mode can send frames back out through the port the frame was received on. Hairpin mode is required to support basic VEPA (Virtual Ethernet Port Aggregator) capabilities. You can find additional information on VEPA here: http://tech.groups.yahoo.com/group/evb/ http://www.ieee802.org/1/files/public/docs2009/new-hudson-vepa_seminar-20090514d.pdf http://www.internet2.edu/presentations/jt2009jul/20090719-congdon.pdf An additional patch 'bridge-utils: Add 'hairpin' port forwarding mode' is provided to allow configuring hairpin mode from userspace tools. Signed-off-by: Paul Congdon Signed-off-by: Anna Fischer Acked-by: Arnd Bergmann Signed-off-by: David S. Miller diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index d2c27c8..bc1704a 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -22,7 +22,8 @@ static inline int should_deliver(const struct net_bridge_port *p, const struct sk_buff *skb) { - return (skb->dev != p->dev && p->state == BR_STATE_FORWARDING); + return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) && + p->state == BR_STATE_FORWARDING); } static inline unsigned packet_length(const struct sk_buff *skb) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index eb404dc..e486f1f 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -256,6 +256,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, p->path_cost = port_cost(dev); p->priority = 0x8000 >> BR_PORT_BITS; p->port_no = index; + p->flags = 0; br_init_port(p); p->state = BR_STATE_DISABLED; br_stp_port_timer_init(p); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d5b5537..8319247 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -81,6 +81,9 @@ struct net_bridge_port struct timer_list message_age_timer; struct kobject kobj; struct rcu_head rcu; + + unsigned long flags; +#define BR_HAIRPIN_MODE 0x00000001 }; struct net_bridge diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 4a3cdf8..820643a 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -143,6 +143,22 @@ static ssize_t store_flush(struct net_bridge_port *p, unsigned long v) } static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush); +static ssize_t show_hairpin_mode(struct net_bridge_port *p, char *buf) +{ + int hairpin_mode = (p->flags & BR_HAIRPIN_MODE) ? 1 : 0; + return sprintf(buf, "%d\n", hairpin_mode); +} +static ssize_t store_hairpin_mode(struct net_bridge_port *p, unsigned long v) +{ + if (v) + p->flags |= BR_HAIRPIN_MODE; + else + p->flags &= ~BR_HAIRPIN_MODE; + return 0; +} +static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR, + show_hairpin_mode, store_hairpin_mode); + static struct brport_attribute *brport_attrs[] = { &brport_attr_path_cost, &brport_attr_priority, @@ -159,6 +175,7 @@ static struct brport_attribute *brport_attrs[] = { &brport_attr_forward_delay_timer, &brport_attr_hold_timer, &brport_attr_flush, + &brport_attr_hairpin_mode, NULL }; -- cgit v0.10.2 From f16aea4d201018a124f3c1efd7f247fd3b11e4e1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 12 Aug 2009 12:22:46 +0000 Subject: korina: fix printk formatting, add final info line The macro DRV_NAME contains "korina", the field dev->name points to the actual interface name. So messages were formerly prefixed with 'korinaeth2:' (on my system). Signed-off-by: Phil Sutter Signed-off-by: David S. Miller diff --git a/drivers/net/korina.c b/drivers/net/korina.c index b4cf602..6df9d25 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -338,7 +338,7 @@ static irqreturn_t korina_rx_dma_interrupt(int irq, void *dev_id) napi_schedule(&lp->napi); if (dmas & DMA_STAT_ERR) - printk(KERN_ERR DRV_NAME "%s: DMA error\n", dev->name); + printk(KERN_ERR "%s: DMA error\n", dev->name); retval = IRQ_HANDLED; } else @@ -555,7 +555,7 @@ static void korina_tx(struct net_device *dev) dev->stats.tx_dropped++; /* Should never happen */ - printk(KERN_ERR DRV_NAME "%s: split tx ignored\n", + printk(KERN_ERR "%s: split tx ignored\n", dev->name); } else if (devcs & ETH_TX_TOK) { dev->stats.tx_packets++; @@ -641,7 +641,7 @@ korina_tx_dma_interrupt(int irq, void *dev_id) dev->trans_start = jiffies; } if (dmas & DMA_STAT_ERR) - printk(KERN_ERR DRV_NAME "%s: DMA error\n", dev->name); + printk(KERN_ERR "%s: DMA error\n", dev->name); retval = IRQ_HANDLED; } else @@ -917,8 +917,7 @@ static int korina_restart(struct net_device *dev) ret = korina_init(dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME "%s: cannot restart device\n", - dev->name); + printk(KERN_ERR "%s: cannot restart device\n", dev->name); return ret; } korina_multicast_list(dev); @@ -1005,7 +1004,7 @@ static int korina_open(struct net_device *dev) /* Initialize */ ret = korina_init(dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME "%s: cannot open device\n", dev->name); + printk(KERN_ERR "%s: cannot open device\n", dev->name); goto out; } @@ -1015,14 +1014,14 @@ static int korina_open(struct net_device *dev) ret = request_irq(lp->rx_irq, &korina_rx_dma_interrupt, IRQF_DISABLED, "Korina ethernet Rx", dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME "%s: unable to get Rx DMA IRQ %d\n", + printk(KERN_ERR "%s: unable to get Rx DMA IRQ %d\n", dev->name, lp->rx_irq); goto err_release; } ret = request_irq(lp->tx_irq, &korina_tx_dma_interrupt, IRQF_DISABLED, "Korina ethernet Tx", dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME "%s: unable to get Tx DMA IRQ %d\n", + printk(KERN_ERR "%s: unable to get Tx DMA IRQ %d\n", dev->name, lp->tx_irq); goto err_free_rx_irq; } @@ -1031,7 +1030,7 @@ static int korina_open(struct net_device *dev) ret = request_irq(lp->ovr_irq, &korina_ovr_interrupt, IRQF_DISABLED, "Ethernet Overflow", dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME"%s: unable to get OVR IRQ %d\n", + printk(KERN_ERR "%s: unable to get OVR IRQ %d\n", dev->name, lp->ovr_irq); goto err_free_tx_irq; } @@ -1040,7 +1039,7 @@ static int korina_open(struct net_device *dev) ret = request_irq(lp->und_irq, &korina_und_interrupt, IRQF_DISABLED, "Ethernet Underflow", dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME "%s: unable to get UND IRQ %d\n", + printk(KERN_ERR "%s: unable to get UND IRQ %d\n", dev->name, lp->und_irq); goto err_free_ovr_irq; } @@ -1137,7 +1136,7 @@ static int korina_probe(struct platform_device *pdev) dev->base_addr = r->start; lp->eth_regs = ioremap_nocache(r->start, r->end - r->start); if (!lp->eth_regs) { - printk(KERN_ERR DRV_NAME "cannot remap registers\n"); + printk(KERN_ERR DRV_NAME ": cannot remap registers\n"); rc = -ENXIO; goto probe_err_out; } @@ -1145,7 +1144,7 @@ static int korina_probe(struct platform_device *pdev) r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_dma_rx"); lp->rx_dma_regs = ioremap_nocache(r->start, r->end - r->start); if (!lp->rx_dma_regs) { - printk(KERN_ERR DRV_NAME "cannot remap Rx DMA registers\n"); + printk(KERN_ERR DRV_NAME ": cannot remap Rx DMA registers\n"); rc = -ENXIO; goto probe_err_dma_rx; } @@ -1153,14 +1152,14 @@ static int korina_probe(struct platform_device *pdev) r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_dma_tx"); lp->tx_dma_regs = ioremap_nocache(r->start, r->end - r->start); if (!lp->tx_dma_regs) { - printk(KERN_ERR DRV_NAME "cannot remap Tx DMA registers\n"); + printk(KERN_ERR DRV_NAME ": cannot remap Tx DMA registers\n"); rc = -ENXIO; goto probe_err_dma_tx; } lp->td_ring = kmalloc(TD_RING_SIZE + RD_RING_SIZE, GFP_KERNEL); if (!lp->td_ring) { - printk(KERN_ERR DRV_NAME "cannot allocate descriptors\n"); + printk(KERN_ERR DRV_NAME ": cannot allocate descriptors\n"); rc = -ENXIO; goto probe_err_td_ring; } @@ -1193,10 +1192,13 @@ static int korina_probe(struct platform_device *pdev) rc = register_netdev(dev); if (rc < 0) { printk(KERN_ERR DRV_NAME - ": cannot register net device %d\n", rc); + ": cannot register net device: %d\n", rc); goto probe_err_register; } setup_timer(&lp->media_check_timer, korina_poll_media, (unsigned long) dev); + + printk(KERN_INFO "%s: " DRV_NAME "-" DRV_VERSION " " DRV_RELDATE "\n", + dev->name); out: return rc; -- cgit v0.10.2 From 7010837a44813711b66d9e82e90f9641464e515d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 12 Aug 2009 12:52:32 +0000 Subject: korina: add error-handling to korina_alloc_ring This also avoids a potential buffer overflow in case the very first receive descriptor fails to allocate, as an index of -1 would be used afterwards. Kudos to Roel Kluin for pointing this out and providing an initial patch. Signed-off-by: Phil Sutter Signed-off-by: David S. Miller diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 6df9d25..51ca54c 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -750,7 +750,7 @@ static struct ethtool_ops netdev_ethtool_ops = { .get_link = netdev_get_link, }; -static void korina_alloc_ring(struct net_device *dev) +static int korina_alloc_ring(struct net_device *dev) { struct korina_private *lp = netdev_priv(dev); struct sk_buff *skb; @@ -771,7 +771,7 @@ static void korina_alloc_ring(struct net_device *dev) for (i = 0; i < KORINA_NUM_RDS; i++) { skb = dev_alloc_skb(KORINA_RBSIZE + 2); if (!skb) - break; + return -ENOMEM; skb_reserve(skb, 2); lp->rx_skb[i] = skb; lp->rd_ring[i].control = DMA_DESC_IOD | @@ -790,6 +790,8 @@ static void korina_alloc_ring(struct net_device *dev) lp->rx_chain_head = 0; lp->rx_chain_tail = 0; lp->rx_chain_status = desc_empty; + + return 0; } static void korina_free_ring(struct net_device *dev) @@ -832,7 +834,11 @@ static int korina_init(struct net_device *dev) writel(ETH_INT_FC_EN, &lp->eth_regs->ethintfc); /* Allocate rings */ - korina_alloc_ring(dev); + if (korina_alloc_ring(dev)) { + printk(KERN_ERR "%s: descriptor allocation failed\n", dev->name); + korina_free_ring(dev); + return -ENOMEM; + } writel(0, &lp->rx_dma_regs->dmas); /* Start Rx DMA */ -- cgit v0.10.2 From 1e5053b7635c6a985a7cd8108e538883d961de2a Mon Sep 17 00:00:00 2001 From: Wan ZongShun Date: Sun, 9 Aug 2009 03:06:19 +0000 Subject: Add support for w90p910 mac driver I fixed up my mac driver, which relatives to previous mac driver actually in the tree. Signed-off-by: Wan ZongShun Signed-off-by: David S. Miller diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c index 616fb79..890716f 100644 --- a/drivers/net/arm/w90p910_ether.c +++ b/drivers/net/arm/w90p910_ether.c @@ -143,16 +143,17 @@ struct recv_pdesc { struct tran_pdesc { struct w90p910_txbd desclist[TX_DESC_SIZE]; - char tran_buf[RX_DESC_SIZE][MAX_TBUFF_SZ]; + char tran_buf[TX_DESC_SIZE][MAX_TBUFF_SZ]; }; struct w90p910_ether { struct recv_pdesc *rdesc; - struct recv_pdesc *rdesc_phys; struct tran_pdesc *tdesc; - struct tran_pdesc *tdesc_phys; + dma_addr_t rdesc_phys; + dma_addr_t tdesc_phys; struct net_device_stats stats; struct platform_device *pdev; + struct resource *res; struct sk_buff *skb; struct clk *clk; struct clk *rmiiclk; @@ -169,7 +170,6 @@ struct w90p910_ether { unsigned int start_tx_ptr; unsigned int start_rx_ptr; unsigned int linkflag; - spinlock_t lock; }; static void update_linkspeed_register(struct net_device *dev, @@ -275,59 +275,75 @@ static void w90p910_write_cam(struct net_device *dev, __raw_writel(msw, ether->reg + REG_CAMM_BASE + x * CAM_ENTRY_SIZE); } -static void w90p910_init_desc(struct net_device *dev) +static int w90p910_init_desc(struct net_device *dev) { struct w90p910_ether *ether; - struct w90p910_txbd *tdesc, *tdesc_phys; - struct w90p910_rxbd *rdesc, *rdesc_phys; - unsigned int i, j; + struct w90p910_txbd *tdesc; + struct w90p910_rxbd *rdesc; + struct platform_device *pdev; + unsigned int i; ether = netdev_priv(dev); + pdev = ether->pdev; ether->tdesc = (struct tran_pdesc *) - dma_alloc_coherent(NULL, sizeof(struct tran_pdesc), - (dma_addr_t *) ðer->tdesc_phys, GFP_KERNEL); + dma_alloc_coherent(&pdev->dev, sizeof(struct tran_pdesc), + ðer->tdesc_phys, GFP_KERNEL); + + if (!ether->tdesc) { + dev_err(&pdev->dev, "Failed to allocate memory for tx desc\n"); + return -ENOMEM; + } ether->rdesc = (struct recv_pdesc *) - dma_alloc_coherent(NULL, sizeof(struct recv_pdesc), - (dma_addr_t *) ðer->rdesc_phys, GFP_KERNEL); + dma_alloc_coherent(&pdev->dev, sizeof(struct recv_pdesc), + ðer->rdesc_phys, GFP_KERNEL); + + if (!ether->rdesc) { + dev_err(&pdev->dev, "Failed to allocate memory for rx desc\n"); + dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc), + ether->tdesc, ether->tdesc_phys); + return -ENOMEM; + } for (i = 0; i < TX_DESC_SIZE; i++) { - tdesc = &(ether->tdesc->desclist[i]); + unsigned int offset; - j = ((i + 1) / TX_DESC_SIZE); + tdesc = &(ether->tdesc->desclist[i]); - if (j != 0) { - tdesc_phys = &(ether->tdesc_phys->desclist[0]); - ether->start_tx_ptr = (unsigned int)tdesc_phys; - tdesc->next = (unsigned int)ether->start_tx_ptr; - } else { - tdesc_phys = &(ether->tdesc_phys->desclist[i+1]); - tdesc->next = (unsigned int)tdesc_phys; - } + if (i == TX_DESC_SIZE - 1) + offset = offsetof(struct tran_pdesc, desclist[0]); + else + offset = offsetof(struct tran_pdesc, desclist[i + 1]); - tdesc->buffer = (unsigned int)ether->tdesc_phys->tran_buf[i]; + tdesc->next = ether->tdesc_phys + offset; + tdesc->buffer = ether->tdesc_phys + + offsetof(struct tran_pdesc, tran_buf[i]); tdesc->sl = 0; tdesc->mode = 0; } + ether->start_tx_ptr = ether->tdesc_phys; + for (i = 0; i < RX_DESC_SIZE; i++) { - rdesc = &(ether->rdesc->desclist[i]); + unsigned int offset; - j = ((i + 1) / RX_DESC_SIZE); + rdesc = &(ether->rdesc->desclist[i]); - if (j != 0) { - rdesc_phys = &(ether->rdesc_phys->desclist[0]); - ether->start_rx_ptr = (unsigned int)rdesc_phys; - rdesc->next = (unsigned int)ether->start_rx_ptr; - } else { - rdesc_phys = &(ether->rdesc_phys->desclist[i+1]); - rdesc->next = (unsigned int)rdesc_phys; - } + if (i == RX_DESC_SIZE - 1) + offset = offsetof(struct recv_pdesc, desclist[0]); + else + offset = offsetof(struct recv_pdesc, desclist[i + 1]); + rdesc->next = ether->rdesc_phys + offset; rdesc->sl = RX_OWEN_DMA; - rdesc->buffer = (unsigned int)ether->rdesc_phys->recv_buf[i]; + rdesc->buffer = ether->rdesc_phys + + offsetof(struct recv_pdesc, recv_buf[i]); } + + ether->start_rx_ptr = ether->rdesc_phys; + + return 0; } static void w90p910_set_fifo_threshold(struct net_device *dev) @@ -456,8 +472,6 @@ static void w90p910_reset_mac(struct net_device *dev) { struct w90p910_ether *ether = netdev_priv(dev); - spin_lock(ðer->lock); - w90p910_enable_tx(dev, 0); w90p910_enable_rx(dev, 0); w90p910_set_fifo_threshold(dev); @@ -486,8 +500,6 @@ static void w90p910_reset_mac(struct net_device *dev) if (netif_queue_stopped(dev)) netif_wake_queue(dev); - - spin_unlock(ðer->lock); } static void w90p910_mdio_write(struct net_device *dev, @@ -541,7 +553,7 @@ static int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg) return data; } -static int set_mac_address(struct net_device *dev, void *addr) +static int w90p910_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr *address = addr; @@ -557,11 +569,14 @@ static int set_mac_address(struct net_device *dev, void *addr) static int w90p910_ether_close(struct net_device *dev) { struct w90p910_ether *ether = netdev_priv(dev); + struct platform_device *pdev; - dma_free_writecombine(NULL, sizeof(struct w90p910_rxbd), - ether->rdesc, (dma_addr_t)ether->rdesc_phys); - dma_free_writecombine(NULL, sizeof(struct w90p910_txbd), - ether->tdesc, (dma_addr_t)ether->tdesc_phys); + pdev = ether->pdev; + + dma_free_coherent(&pdev->dev, sizeof(struct recv_pdesc), + ether->rdesc, ether->rdesc_phys); + dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc), + ether->tdesc, ether->tdesc_phys); netif_stop_queue(dev); @@ -597,6 +612,7 @@ static int w90p910_send_frame(struct net_device *dev, txbd = ðer->tdesc->desclist[ether->cur_tx]; buffer = ether->tdesc->tran_buf[ether->cur_tx]; + if (length > 1514) { dev_err(&pdev->dev, "send data %d bytes, check it\n", length); length = 1514; @@ -612,7 +628,9 @@ static int w90p910_send_frame(struct net_device *dev, w90p910_trigger_tx(dev); - ether->cur_tx = (ether->cur_tx+1) % TX_DESC_SIZE; + if (++ether->cur_tx >= TX_DESC_SIZE) + ether->cur_tx = 0; + txbd = ðer->tdesc->desclist[ether->cur_tx]; dev->trans_start = jiffies; @@ -632,7 +650,7 @@ static int w90p910_ether_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb_irq(skb); return 0; } - return -1; + return -EAGAIN; } static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id) @@ -640,27 +658,25 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id) struct w90p910_ether *ether; struct w90p910_txbd *txbd; struct platform_device *pdev; - struct tran_pdesc *tran_pdesc; struct net_device *dev; unsigned int cur_entry, entry, status; - dev = (struct net_device *)dev_id; + dev = dev_id; ether = netdev_priv(dev); pdev = ether->pdev; - spin_lock(ðer->lock); - w90p910_get_and_clear_int(dev, &status); cur_entry = __raw_readl(ether->reg + REG_CTXDSA); - tran_pdesc = ether->tdesc_phys; - entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]); + entry = ether->tdesc_phys + + offsetof(struct tran_pdesc, desclist[ether->finish_tx]); while (entry != cur_entry) { txbd = ðer->tdesc->desclist[ether->finish_tx]; - ether->finish_tx = (ether->finish_tx + 1) % TX_DESC_SIZE; + if (++ether->finish_tx >= TX_DESC_SIZE) + ether->finish_tx = 0; if (txbd->sl & TXDS_TXCP) { ether->stats.tx_packets++; @@ -675,20 +691,19 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id) if (netif_queue_stopped(dev)) netif_wake_queue(dev); - entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]); + entry = ether->tdesc_phys + + offsetof(struct tran_pdesc, desclist[ether->finish_tx]); } if (status & MISTA_EXDEF) { dev_err(&pdev->dev, "emc defer exceed interrupt\n"); } else if (status & MISTA_TXBERR) { - dev_err(&pdev->dev, "emc bus error interrupt\n"); - w90p910_reset_mac(dev); - } else if (status & MISTA_TDU) { - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); - } - - spin_unlock(ðer->lock); + dev_err(&pdev->dev, "emc bus error interrupt\n"); + w90p910_reset_mac(dev); + } else if (status & MISTA_TDU) { + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } return IRQ_HANDLED; } @@ -698,20 +713,20 @@ static void netdev_rx(struct net_device *dev) struct w90p910_ether *ether; struct w90p910_rxbd *rxbd; struct platform_device *pdev; - struct recv_pdesc *rdesc_phys; struct sk_buff *skb; unsigned char *data; unsigned int length, status, val, entry; ether = netdev_priv(dev); pdev = ether->pdev; - rdesc_phys = ether->rdesc_phys; rxbd = ðer->rdesc->desclist[ether->cur_rx]; do { val = __raw_readl(ether->reg + REG_CRXDSA); - entry = (unsigned int)&rdesc_phys->desclist[ether->cur_rx]; + + entry = ether->rdesc_phys + + offsetof(struct recv_pdesc, desclist[ether->cur_rx]); if (val == entry) break; @@ -743,22 +758,23 @@ static void netdev_rx(struct net_device *dev) dev_err(&pdev->dev, "rx runt err\n"); ether->stats.rx_length_errors++; } else if (status & RXDS_CRCE) { - dev_err(&pdev->dev, "rx crc err\n"); - ether->stats.rx_crc_errors++; - } - - if (status & RXDS_ALIE) { + dev_err(&pdev->dev, "rx crc err\n"); + ether->stats.rx_crc_errors++; + } else if (status & RXDS_ALIE) { dev_err(&pdev->dev, "rx aligment err\n"); ether->stats.rx_frame_errors++; } else if (status & RXDS_PTLE) { - dev_err(&pdev->dev, "rx longer err\n"); - ether->stats.rx_over_errors++; - } + dev_err(&pdev->dev, "rx longer err\n"); + ether->stats.rx_over_errors++; } + } rxbd->sl = RX_OWEN_DMA; rxbd->reserved = 0x0; - ether->cur_rx = (ether->cur_rx+1) % RX_DESC_SIZE; + + if (++ether->cur_rx >= RX_DESC_SIZE) + ether->cur_rx = 0; + rxbd = ðer->rdesc->desclist[ether->cur_rx]; dev->last_rx = jiffies; @@ -772,28 +788,23 @@ static irqreturn_t w90p910_rx_interrupt(int irq, void *dev_id) struct platform_device *pdev; unsigned int status; - dev = (struct net_device *)dev_id; + dev = dev_id; ether = netdev_priv(dev); pdev = ether->pdev; - spin_lock(ðer->lock); - w90p910_get_and_clear_int(dev, &status); if (status & MISTA_RDU) { netdev_rx(dev); - w90p910_trigger_rx(dev); - spin_unlock(ðer->lock); return IRQ_HANDLED; } else if (status & MISTA_RXBERR) { - dev_err(&pdev->dev, "emc rx bus error\n"); - w90p910_reset_mac(dev); - } + dev_err(&pdev->dev, "emc rx bus error\n"); + w90p910_reset_mac(dev); + } netdev_rx(dev); - spin_unlock(ðer->lock); return IRQ_HANDLED; } @@ -826,6 +837,7 @@ static int w90p910_ether_open(struct net_device *dev) if (request_irq(ether->rxirq, w90p910_rx_interrupt, 0x0, pdev->name, dev)) { dev_err(&pdev->dev, "register irq rx failed\n"); + free_irq(ether->txirq, dev); return -EAGAIN; } @@ -908,7 +920,7 @@ static const struct net_device_ops w90p910_ether_netdev_ops = { .ndo_start_xmit = w90p910_ether_start_xmit, .ndo_get_stats = w90p910_ether_stats, .ndo_set_multicast_list = w90p910_ether_set_multicast_list, - .ndo_set_mac_address = set_mac_address, + .ndo_set_mac_address = w90p910_set_mac_address, .ndo_do_ioctl = w90p910_ether_ioctl, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = eth_change_mtu, @@ -949,8 +961,6 @@ static int w90p910_ether_setup(struct net_device *dev) get_mac_address(dev); - spin_lock_init(ðer->lock); - ether->cur_tx = 0x0; ether->cur_rx = 0x0; ether->finish_tx = 0x0; @@ -972,30 +982,29 @@ static int __devinit w90p910_ether_probe(struct platform_device *pdev) { struct w90p910_ether *ether; struct net_device *dev; - struct resource *res; int error; dev = alloc_etherdev(sizeof(struct w90p910_ether)); if (!dev) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { + ether = netdev_priv(dev); + + ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (ether->res == NULL) { dev_err(&pdev->dev, "failed to get I/O memory\n"); error = -ENXIO; goto failed_free; } - res = request_mem_region(res->start, resource_size(res), pdev->name); - if (res == NULL) { + if (!request_mem_region(ether->res->start, + resource_size(ether->res), pdev->name)) { dev_err(&pdev->dev, "failed to request I/O memory\n"); error = -EBUSY; goto failed_free; } - ether = netdev_priv(dev); - - ether->reg = ioremap(res->start, resource_size(res)); + ether->reg = ioremap(ether->res->start, resource_size(ether->res)); if (ether->reg == NULL) { dev_err(&pdev->dev, "failed to remap I/O memory\n"); error = -ENXIO; @@ -1056,7 +1065,7 @@ failed_free_txirq: failed_free_io: iounmap(ether->reg); failed_free_mem: - release_mem_region(res->start, resource_size(res)); + release_mem_region(ether->res->start, resource_size(ether->res)); failed_free: free_netdev(dev); return error; @@ -1068,10 +1077,19 @@ static int __devexit w90p910_ether_remove(struct platform_device *pdev) struct w90p910_ether *ether = netdev_priv(dev); unregister_netdev(dev); + clk_put(ether->rmiiclk); clk_put(ether->clk); + + iounmap(ether->reg); + release_mem_region(ether->res->start, resource_size(ether->res)); + + free_irq(ether->txirq, dev); + free_irq(ether->rxirq, dev); + del_timer_sync(ðer->check_timer); platform_set_drvdata(pdev, NULL); + free_netdev(dev); return 0; } -- cgit v0.10.2 From e9b3cc1b3779fe10a80de4c3e7404bd308d0eae3 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 13 Aug 2009 05:19:44 +0000 Subject: net: skb ftracer - add tracepoint to skb_copy_datagram_iovec (v3) skb allocation / cosumption tracer - Add consumption tracepoint This patch adds a tracepoint to skb_copy_datagram_iovec, which is called each time a userspace process copies a frame from a socket receive queue to a user space buffer. It allows us to hook in and examine each sk_buff that the system receives on a per-socket bases, and can be use to compile a list of which skb's were received by which processes. Signed-off-by: Neil Horman include/trace/events/skb.h | 20 ++++++++++++++++++++ net/core/datagram.c | 3 +++ 2 files changed, 23 insertions(+) Signed-off-by: David S. Miller diff --git a/include/trace/events/skb.h b/include/trace/events/skb.h index e499863..4b2be6d 100644 --- a/include/trace/events/skb.h +++ b/include/trace/events/skb.h @@ -5,6 +5,7 @@ #define _TRACE_SKB_H #include +#include #include /* @@ -34,6 +35,25 @@ TRACE_EVENT(kfree_skb, __entry->skbaddr, __entry->protocol, __entry->location) ); +TRACE_EVENT(skb_copy_datagram_iovec, + + TP_PROTO(const struct sk_buff *skb, int len), + + TP_ARGS(skb, len), + + TP_STRUCT__entry( + __field( const void *, skbaddr ) + __field( int, len ) + ), + + TP_fast_assign( + __entry->skbaddr = skb; + __entry->len = len; + ), + + TP_printk("skbaddr=%p len=%d", __entry->skbaddr, __entry->len) +); + #endif /* _TRACE_SKB_H */ /* This part must be outside protection */ diff --git a/net/core/datagram.c b/net/core/datagram.c index b0fe692..1c6cf3a 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -55,6 +55,7 @@ #include #include #include +#include /* * Is a socket 'connection oriented' ? @@ -284,6 +285,8 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, int i, copy = start - offset; struct sk_buff *frag_iter; + trace_skb_copy_datagram_iovec(skb, len); + /* Copy header. */ if (copy > 0) { if (copy > len) -- cgit v0.10.2 From 5a165657bef7c47e5ff4cd138f7758ef6278e87b Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 13 Aug 2009 05:20:45 +0000 Subject: net: skb ftracer - Add config option to enable new ftracer (v3) skb allocation / consumption corelator - Add config option This patch adds a Kconfig option to enable the addtition of the skb source tracer. Signed-off-by: Neil Horman Kconfig | 10 ++++++++++ 1 file changed, 10 insertions(+) Signed-off-by: David S. Miller diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 019f380..f09d763 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -234,6 +234,16 @@ config BOOT_TRACER You must pass in initcall_debug and ftrace=initcall to the kernel command line to enable this on bootup. +config SKB_SOURCES_TRACER + bool "Trace skb source information" + select GENERIC_TRACER + help + This tracer helps developers/sysadmins correlate skb allocation and + consumption. The idea being that some processes will primarily consume data + that was allocated on certain numa nodes. By being able to visualize which + nodes the data was allocated on, a sysadmin or developer can optimize the + scheduling of those processes to cut back on cross node chatter. + config TRACE_BRANCH_PROFILING bool select GENERIC_TRACER -- cgit v0.10.2 From 9ec04da7489d2c9ae01ea6e9b5fa313ccf3d35fb Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 13 Aug 2009 05:23:56 +0000 Subject: net: skb ftracer - Add actual ftrace code to kernel (v3) skb allocation / consumption correlator Add ftracer module to kernel to print out a list that correlates a process id, an skb it read, and the numa nodes on wich the process was running when it was read along with the numa node the skbuff was allocated on. Signed-off-by: Neil Horman Makefile | 1 trace.h | 19 ++++++ trace_skb_sources.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) Signed-off-by: David S. Miller diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index 844164d..ee5e5b1 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o ifeq ($(CONFIG_BLOCK),y) obj-$(CONFIG_EVENT_TRACING) += blktrace.o endif +obj-$(CONFIG_SKB_SOURCES_TRACER) += trace_skb_sources.o obj-$(CONFIG_EVENT_TRACING) += trace_events.o obj-$(CONFIG_EVENT_TRACING) += trace_export.o obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 8b9f4f6..8a6281b 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,7 @@ enum trace_type { TRACE_KMEM_FREE, TRACE_POWER, TRACE_BLK, + TRACE_SKB_SOURCE, __TRACE_LAST_TYPE, }; @@ -171,6 +173,21 @@ struct trace_power { struct power_trace state_data; }; +struct skb_record { + pid_t pid; /* pid of the copying process */ + int anid; /* node where skb was allocated */ + int cnid; /* node to which skb was copied in userspace */ + char ifname[IFNAMSIZ]; /* Name of the receiving interface */ + int rx_queue; /* The rx queue the skb was received on */ + int ccpu; /* Cpu the application got this frame from */ + int len; /* length of the data copied */ +}; + +struct trace_skb_event { + struct trace_entry ent; + struct skb_record event_data; +}; + enum kmemtrace_type_id { KMEMTRACE_TYPE_KMALLOC = 0, /* kmalloc() or kfree(). */ KMEMTRACE_TYPE_CACHE, /* kmem_cache_*(). */ @@ -323,6 +340,8 @@ extern void __ftrace_bad_type(void); TRACE_SYSCALL_ENTER); \ IF_ASSIGN(var, ent, struct syscall_trace_exit, \ TRACE_SYSCALL_EXIT); \ + IF_ASSIGN(var, ent, struct trace_skb_event, \ + TRACE_SKB_SOURCE); \ __ftrace_bad_type(); \ } while (0) diff --git a/kernel/trace/trace_skb_sources.c b/kernel/trace/trace_skb_sources.c new file mode 100644 index 0000000..40eb071 --- /dev/null +++ b/kernel/trace/trace_skb_sources.c @@ -0,0 +1,154 @@ +/* + * ring buffer based tracer for analyzing per-socket skb sources + * + * Neil Horman + * Copyright (C) 2009 + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "trace.h" +#include "trace_output.h" + +EXPORT_TRACEPOINT_SYMBOL_GPL(skb_copy_datagram_iovec); + +static struct trace_array *skb_trace; +static int __read_mostly trace_skb_source_enabled; + +static void probe_skb_dequeue(const struct sk_buff *skb, int len) +{ + struct ring_buffer_event *event; + struct trace_skb_event *entry; + struct trace_array *tr = skb_trace; + struct net_device *dev; + + if (!trace_skb_source_enabled) + return; + + if (in_interrupt()) + return; + + event = trace_buffer_lock_reserve(tr, TRACE_SKB_SOURCE, + sizeof(*entry), 0, 0); + if (!event) + return; + entry = ring_buffer_event_data(event); + + entry->event_data.pid = current->pid; + entry->event_data.anid = page_to_nid(virt_to_page(skb->data)); + entry->event_data.cnid = cpu_to_node(smp_processor_id()); + entry->event_data.len = len; + entry->event_data.rx_queue = skb->queue_mapping; + entry->event_data.ccpu = smp_processor_id(); + + dev = dev_get_by_index(sock_net(skb->sk), skb->iif); + if (dev) { + memcpy(entry->event_data.ifname, dev->name, IFNAMSIZ); + dev_put(dev); + } else { + strcpy(entry->event_data.ifname, "Unknown"); + } + + trace_buffer_unlock_commit(tr, event, 0, 0); +} + +static int tracing_skb_source_register(void) +{ + int ret; + + ret = register_trace_skb_copy_datagram_iovec(probe_skb_dequeue); + if (ret) + pr_info("skb source trace: Couldn't activate dequeue tracepoint"); + + return ret; +} + +static void start_skb_source_trace(struct trace_array *tr) +{ + trace_skb_source_enabled = 1; +} + +static void stop_skb_source_trace(struct trace_array *tr) +{ + trace_skb_source_enabled = 0; +} + +static void skb_source_trace_reset(struct trace_array *tr) +{ + trace_skb_source_enabled = 0; + unregister_trace_skb_copy_datagram_iovec(probe_skb_dequeue); +} + + +static int skb_source_trace_init(struct trace_array *tr) +{ + int cpu; + skb_trace = tr; + + trace_skb_source_enabled = 1; + tracing_skb_source_register(); + + for_each_cpu(cpu, cpu_possible_mask) + tracing_reset(tr, cpu); + return 0; +} + +static enum print_line_t skb_source_print_line(struct trace_iterator *iter) +{ + int ret = 0; + struct trace_entry *entry = iter->ent; + struct trace_skb_event *event; + struct skb_record *record; + struct trace_seq *s = &iter->seq; + + trace_assign_type(event, entry); + record = &event->event_data; + if (entry->type != TRACE_SKB_SOURCE) + return TRACE_TYPE_UNHANDLED; + + ret = trace_seq_printf(s, " %d %d %d %s %d %d %d\n", + record->pid, + record->anid, + record->cnid, + record->ifname, + record->rx_queue, + record->ccpu, + record->len); + + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + + return TRACE_TYPE_HANDLED; +} + +static void skb_source_print_header(struct seq_file *s) +{ + seq_puts(s, "# PID ANID CNID IFC RXQ CCPU LEN\n"); + seq_puts(s, "# | | | | | | |\n"); +} + +static struct tracer skb_source_tracer __read_mostly = +{ + .name = "skb_sources", + .init = skb_source_trace_init, + .start = start_skb_source_trace, + .stop = stop_skb_source_trace, + .reset = skb_source_trace_reset, + .print_line = skb_source_print_line, + .print_header = skb_source_print_header, +}; + +static int init_skb_source_trace(void) +{ + return register_tracer(&skb_source_tracer); +} +device_initcall(init_skb_source_trace); -- cgit v0.10.2 From e651f03afe833326faa0abe55948c1c6cfd0b8ac Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Sun, 9 Aug 2009 08:12:48 +0000 Subject: inet6: Conversion from u8 to int This replaces assignments of the type "int on LHS" = "u8 on RHS" with simpler code. The LHS can express all of the unsigned right hand side values, hence the assigned value can not be negative. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index eab62a7..e2325f6 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -323,7 +323,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, int iif = 0; int addr_type = 0; int len; - int hlimit, tclass; + int hlimit; int err = 0; if ((u8 *)hdr < skb->head || @@ -469,10 +469,6 @@ route_done: if (hlimit < 0) hlimit = ip6_dst_hoplimit(dst); - tclass = np->tclass; - if (tclass < 0) - tclass = 0; - msg.skb = skb; msg.offset = skb_network_offset(skb); msg.type = type; @@ -488,8 +484,8 @@ route_done: err = ip6_append_data(sk, icmpv6_getfrag, &msg, len + sizeof(struct icmp6hdr), - sizeof(struct icmp6hdr), - hlimit, tclass, NULL, &fl, (struct rt6_info*)dst, + sizeof(struct icmp6hdr), hlimit, + np->tclass, NULL, &fl, (struct rt6_info*)dst, MSG_DONTWAIT); if (err) { ip6_flush_pending_frames(sk); @@ -522,7 +518,6 @@ static void icmpv6_echo_reply(struct sk_buff *skb) struct dst_entry *dst; int err = 0; int hlimit; - int tclass; saddr = &ipv6_hdr(skb)->daddr; @@ -562,10 +557,6 @@ static void icmpv6_echo_reply(struct sk_buff *skb) if (hlimit < 0) hlimit = ip6_dst_hoplimit(dst); - tclass = np->tclass; - if (tclass < 0) - tclass = 0; - idev = in6_dev_get(skb->dev); msg.skb = skb; @@ -573,7 +564,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) msg.type = ICMPV6_ECHO_REPLY; err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), - sizeof(struct icmp6hdr), hlimit, tclass, NULL, &fl, + sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl, (struct rt6_info*)dst, MSG_DONTWAIT); if (err) { diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 93beee9..6ad5aad 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -194,7 +194,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, struct ipv6hdr *hdr; u8 proto = fl->proto; int seg_len = skb->len; - int hlimit, tclass; + int hlimit = -1; + int tclass = 0; u32 mtu; if (opt) { @@ -237,19 +238,13 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, /* * Fill in the IPv6 header */ - - hlimit = -1; - if (np) + if (np) { + tclass = np->tclass; hlimit = np->hop_limit; + } if (hlimit < 0) hlimit = ip6_dst_hoplimit(dst); - tclass = -1; - if (np) - tclass = np->tclass; - if (tclass < 0) - tclass = 0; - *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; hdr->payload_len = htons(seg_len); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index a7fdf9a..c390b1e 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -1037,8 +1037,6 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, case IPV6_TCLASS: val = np->tclass; - if (val < 0) - val = 0; break; case IPV6_RECVTCLASS: diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d6c3c1c..5068410 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -877,11 +877,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, hlimit = ip6_dst_hoplimit(dst); } - if (tclass < 0) { + if (tclass < 0) tclass = np->tclass; - if (tclass < 0) - tclass = 0; - } if (msg->msg_flags&MSG_CONFIRM) goto do_confirm; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index d79fa67..20d2ffc 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -946,11 +946,8 @@ do_udp_sendmsg: hlimit = ip6_dst_hoplimit(dst); } - if (tclass < 0) { + if (tclass < 0) tclass = np->tclass; - if (tclass < 0) - tclass = 0; - } if (msg->msg_flags&MSG_CONFIRM) goto do_confirm; -- cgit v0.10.2 From 26ced1e4aa181c01379b0b7ef156a29c000d1f8c Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Sun, 9 Aug 2009 08:12:49 +0000 Subject: inet6: Set default traffic class This patch addresses: * assigning -1 to np->tclass as it is currently done is not very meaningful, since it turns into 0xff; * RFC 3542, 6.5 allows -1 for clearing the sticky IPV6_TCLASS option and specifies -1 to mean "use kernel default": - RFC 2460, 7. requires that the default traffic class must be zero for all 8 bits, - this is consistent with RFC 2474, 4.1 which recommends a default PHB of 0, in combination with a value of the ECN field of "non-ECT" (RFC 3168, 5.). This patch changes the meaning of -1 from assigning 255 to mean the RFC 2460 default, which at the same time allows to satisfy clearing the sticky TCLASS option as per RFC 3542, 6.5. (When passing -1 as ancillary data, the fallback remains np->tclass, which has either been set via socket options, or contains the default value.) Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index c390b1e..f5e0682 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -315,6 +315,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, goto e_inval; if (val < -1 || val > 0xff) goto e_inval; + /* RFC 3542, 6.5: default traffic class of 0x0 */ + if (val == -1) + val = 0; np->tclass = val; retv = 0; break; -- cgit v0.10.2 From e5e2a8fd8358d1b3a2c51c3248edee72e4194703 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 13 Aug 2009 04:11:52 +0000 Subject: bonding: wipe out printk's I did not introduce new lines over 80 chars. I even eliminated some of them. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index be799d2..cea5cfe 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1124,7 +1124,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) // detect loopback situation if (!MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->actor_system))) { // INFO_RECEIVED_LOOPBACK_FRAMES - printk(KERN_ERR DRV_NAME ": %s: An illegal loopback occurred on " + pr_err(DRV_NAME ": %s: An illegal loopback occurred on " "adapter (%s). Check the configuration to verify that all " "Adapters are connected to 802.3ad compliant switch ports\n", port->slave->dev->master->name, port->slave->dev->name); @@ -1306,11 +1306,13 @@ static void ad_port_selection_logic(struct port *port) } } if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list - printk(KERN_WARNING DRV_NAME ": %s: Warning: Port %d (on %s) was " - "related to aggregator %d but was not on its port list\n", - port->slave->dev->master->name, - port->actor_port_number, port->slave->dev->name, - port->aggregator->aggregator_identifier); + pr_warning(DRV_NAME ": %s: Warning: Port %d (on %s) " + "was related to aggregator %d but was not " + "on its port list\n", + port->slave->dev->master->name, + port->actor_port_number, + port->slave->dev->name, + port->aggregator->aggregator_identifier); } } // search on all aggregators for a suitable aggregator for this port @@ -1379,7 +1381,8 @@ static void ad_port_selection_logic(struct port *port) pr_debug("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); } else { - printk(KERN_ERR DRV_NAME ": %s: Port %d (on %s) did not find a suitable aggregator\n", + pr_err(DRV_NAME ": %s: Port %d (on %s) did not find " + "a suitable aggregator\n", port->slave->dev->master->name, port->actor_port_number, port->slave->dev->name); } @@ -1456,10 +1459,10 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best, break; default: - printk(KERN_WARNING DRV_NAME - ": %s: Impossible agg select mode %d\n", - curr->slave->dev->master->name, - __get_agg_selection_mode(curr->lag_ports)); + pr_warning(DRV_NAME + ": %s: Impossible agg select mode %d\n", + curr->slave->dev->master->name, + __get_agg_selection_mode(curr->lag_ports)); break; } @@ -1562,7 +1565,7 @@ static void ad_agg_selection_logic(struct aggregator *agg) // check if any partner replys if (best->is_individual) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: No 802.3ad" + pr_warning(DRV_NAME ": %s: Warning: No 802.3ad" " response from the link partner for any" " adapters in the bond\n", best->slave->dev->master->name); @@ -1885,7 +1888,8 @@ int bond_3ad_bind_slave(struct slave *slave) struct aggregator *aggregator; if (bond == NULL) { - printk(KERN_ERR DRV_NAME ": %s: The slave %s is not attached to its bond\n", + pr_err(DRV_NAME ": %s: The slave %s is not attached to " + "its bond\n", slave->dev->master->name, slave->dev->name); return -1; } @@ -1961,9 +1965,9 @@ void bond_3ad_unbind_slave(struct slave *slave) // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": Warning: %s: Trying to " - "unbind an uninitialized port on %s\n", - slave->dev->master->name, slave->dev->name); + pr_warning(DRV_NAME ": Warning: %s: Trying to " + "unbind an uninitialized port on %s\n", + slave->dev->master->name, slave->dev->name); return; } @@ -1994,8 +1998,8 @@ void bond_3ad_unbind_slave(struct slave *slave) pr_debug("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) { - printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n", - aggregator->slave->dev->master->name); + pr_info(DRV_NAME ": %s: Removing an active aggregator\n", + aggregator->slave->dev->master->name); // select new active aggregator select_new_active_agg = 1; } @@ -2025,17 +2029,17 @@ void bond_3ad_unbind_slave(struct slave *slave) ad_agg_selection_logic(__get_first_agg(port)); } } else { - printk(KERN_WARNING DRV_NAME ": %s: Warning: unbinding aggregator, " - "and could not find a new aggregator for its ports\n", - slave->dev->master->name); + pr_warning(DRV_NAME ": %s: Warning: unbinding aggregator, " + "and could not find a new aggregator for its ports\n", + slave->dev->master->name); } } else { // in case that the only port related to this aggregator is the one we want to remove select_new_active_agg = aggregator->is_active; // clear the aggregator ad_clear_agg(aggregator); if (select_new_active_agg) { - printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n", - slave->dev->master->name); + pr_info(DRV_NAME ": %s: Removing an active aggregator\n", + slave->dev->master->name); // select new active aggregator ad_agg_selection_logic(__get_first_agg(port)); } @@ -2061,8 +2065,8 @@ void bond_3ad_unbind_slave(struct slave *slave) // clear the aggregator ad_clear_agg(temp_aggregator); if (select_new_active_agg) { - printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n", - slave->dev->master->name); + pr_info(DRV_NAME ": %s: Removing an active aggregator\n", + slave->dev->master->name); // select new active aggregator ad_agg_selection_logic(__get_first_agg(port)); } @@ -2110,8 +2114,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work) // select the active aggregator for the bond if ((port = __get_first_port(bond))) { if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: bond's first port is " - "uninitialized\n", bond->dev->name); + pr_warning(DRV_NAME ": %s: Warning: bond's first port is " + "uninitialized\n", bond->dev->name); goto re_arm; } @@ -2124,8 +2128,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work) // for each port run the state machines for (port = __get_first_port(bond); port; port = __get_next_port(port)) { if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: Found an uninitialized " - "port\n", bond->dev->name); + pr_warning(DRV_NAME ": %s: Warning: Found an uninitialized " + "port\n", bond->dev->name); goto re_arm; } @@ -2166,8 +2170,9 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u port = &(SLAVE_AD_INFO(slave).port); if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: port of slave %s is " - "uninitialized\n", slave->dev->name, slave->dev->master->name); + pr_warning(DRV_NAME ": %s: Warning: port of slave %s " + "is uninitialized\n", + slave->dev->name, slave->dev->master->name); return; } @@ -2212,9 +2217,9 @@ void bond_3ad_adapter_speed_changed(struct slave *slave) // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": Warning: %s: speed " - "changed for uninitialized port on %s\n", - slave->dev->master->name, slave->dev->name); + pr_warning(DRV_NAME ": Warning: %s: speed " + "changed for uninitialized port on %s\n", + slave->dev->master->name, slave->dev->name); return; } @@ -2240,9 +2245,9 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: duplex changed " - "for uninitialized port on %s\n", - slave->dev->master->name, slave->dev->name); + pr_warning(DRV_NAME ": %s: Warning: duplex changed " + "for uninitialized port on %s\n", + slave->dev->master->name, slave->dev->name); return; } @@ -2269,9 +2274,9 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": Warning: %s: link status changed for " - "uninitialized port on %s\n", - slave->dev->master->name, slave->dev->name); + pr_warning(DRV_NAME ": Warning: %s: link status changed for " + "uninitialized port on %s\n", + slave->dev->master->name, slave->dev->name); return; } @@ -2375,8 +2380,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) } if (bond_3ad_get_active_agg_info(bond, &ad_info)) { - printk(KERN_DEBUG DRV_NAME ": %s: Error: " - "bond_3ad_get_active_agg_info failed\n", dev->name); + pr_debug(DRV_NAME ": %s: Error: " + "bond_3ad_get_active_agg_info failed\n", dev->name); goto out; } @@ -2385,9 +2390,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) if (slaves_in_agg == 0) { /*the aggregator is empty*/ - printk(KERN_DEBUG DRV_NAME ": %s: Error: active " - "aggregator is empty\n", - dev->name); + pr_debug(DRV_NAME ": %s: Error: active aggregator is empty\n", + dev->name); goto out; } @@ -2405,7 +2409,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) } if (slave_agg_no >= 0) { - printk(KERN_ERR DRV_NAME ": %s: Error: Couldn't find a slave to tx on " + pr_err(DRV_NAME ": %s: Error: Couldn't find a slave to tx on " "for aggregator ID %d\n", dev->name, agg_id); goto out; } diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index bf45d20..2108706 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -194,7 +194,7 @@ static int tlb_initialize(struct bonding *bond) new_hashtbl = kzalloc(size, GFP_KERNEL); if (!new_hashtbl) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Failed to allocate TLB hash table\n", bond->dev->name); return -1; @@ -510,7 +510,7 @@ static void rlb_update_client(struct rlb_client_info *client_info) client_info->slave->dev->dev_addr, client_info->mac_dst); if (!skb) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: failed to create an ARP packet\n", client_info->slave->dev->master->name); continue; @@ -521,7 +521,7 @@ static void rlb_update_client(struct rlb_client_info *client_info) if (client_info->tag) { skb = vlan_put_tag(skb, client_info->vlan_id); if (!skb) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: failed to insert VLAN tag\n", client_info->slave->dev->master->name); continue; @@ -605,7 +605,7 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip) client_info = &(bond_info->rx_hashtbl[hash_index]); if (!client_info->slave) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: found a client with no channel in " "the client's hash table\n", bond->dev->name); @@ -802,7 +802,7 @@ static int rlb_initialize(struct bonding *bond) new_hashtbl = kmalloc(size, GFP_KERNEL); if (!new_hashtbl) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Failed to allocate RLB hash table\n", bond->dev->name); return -1; @@ -924,7 +924,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) skb = vlan_put_tag(skb, vlan->vlan_id); if (!skb) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: failed to insert VLAN tag\n", bond->dev->name); continue; @@ -954,7 +954,7 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) memcpy(s_addr.sa_data, addr, dev->addr_len); s_addr.sa_family = dev->type; if (dev_set_mac_address(dev, &s_addr)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: dev_set_mac_address of dev %s failed! ALB " "mode requires that the base driver support setting " "the hw address also when the network device's " @@ -1170,13 +1170,15 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr, bond->alb_info.rlb_enabled); - printk(KERN_WARNING DRV_NAME - ": %s: Warning: the hw address of slave %s is in use by " - "the bond; giving it the hw address of %s\n", - bond->dev->name, slave->dev->name, free_mac_slave->dev->name); + pr_warning(DRV_NAME + ": %s: Warning: the hw address of slave %s is " + "in use by the bond; giving it the hw address " + "of %s\n", + bond->dev->name, slave->dev->name, + free_mac_slave->dev->name); } else if (has_bond_addr) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: the hw address of slave %s is in use by the " "bond; couldn't find a slave with a free hw address to " "give it (this should not have happened)\n", diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c index 0d73bf5..83921ab 100644 --- a/drivers/net/bonding/bond_ipv6.c +++ b/drivers/net/bonding/bond_ipv6.c @@ -79,14 +79,14 @@ static void bond_na_send(struct net_device *slave_dev, ND_OPT_TARGET_LL_ADDR); if (!skb) { - printk(KERN_ERR DRV_NAME ": NA packet allocation failed\n"); + pr_err(DRV_NAME ": NA packet allocation failed\n"); return; } if (vlan_id) { skb = vlan_put_tag(skb, vlan_id); if (!skb) { - printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n"); + pr_err(DRV_NAME ": failed to insert VLAN tag\n"); return; } } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 3bf0cc6..4798d30 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4837,7 +4837,7 @@ static int bond_check_params(struct bond_params *params) } if (bond_mode == BOND_MODE_ALB) { - printk(KERN_NOTICE DRV_NAME + pr_notice(DRV_NAME ": In ALB mode you might experience client " "disconnections upon reconnection of a link if the " "bonding module updelay parameter (%d msec) is " @@ -4961,9 +4961,9 @@ static int bond_check_params(struct bond_params *params) arp_ip_count); for (i = 0; i < arp_ip_count; i++) - printk(" %s", arp_ip_target[i]); + pr_info(" %s", arp_ip_target[i]); - printk("\n"); + pr_info("\n"); } else if (max_bonds) { /* miimon and arp_interval not set, we need one so things diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 55bf34f..6044e12 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -218,9 +218,8 @@ static ssize_t bonding_store_slaves(struct device *d, /* Quick sanity check -- is the bond interface up? */ if (!(bond->dev->flags & IFF_UP)) { - printk(KERN_WARNING DRV_NAME - ": %s: doing slave updates when interface is down.\n", - bond->dev->name); + pr_warning(DRV_NAME ": %s: doing slave updates when " + "interface is down.\n", bond->dev->name); } /* Note: We can't hold bond->lock here, as bond_create grabs it. */ @@ -778,12 +777,14 @@ static ssize_t bonding_store_downdelay(struct device *d, goto out; } else { if ((new_value % bond->params.miimon) != 0) { - printk(KERN_WARNING DRV_NAME - ": %s: Warning: down delay (%d) is not a multiple " - "of miimon (%d), delay rounded to %d ms\n", - bond->dev->name, new_value, bond->params.miimon, - (new_value / bond->params.miimon) * - bond->params.miimon); + pr_warning(DRV_NAME + ": %s: Warning: down delay (%d) is not a " + "multiple of miimon (%d), delay rounded " + "to %d ms\n", + bond->dev->name, new_value, + bond->params.miimon, + (new_value / bond->params.miimon) * + bond->params.miimon); } bond->params.downdelay = new_value / bond->params.miimon; pr_info(DRV_NAME ": %s: Setting down delay to %d.\n", @@ -838,12 +839,14 @@ static ssize_t bonding_store_updelay(struct device *d, goto out; } else { if ((new_value % bond->params.miimon) != 0) { - printk(KERN_WARNING DRV_NAME - ": %s: Warning: up delay (%d) is not a multiple " - "of miimon (%d), updelay rounded to %d ms\n", - bond->dev->name, new_value, bond->params.miimon, - (new_value / bond->params.miimon) * - bond->params.miimon); + pr_warning(DRV_NAME + ": %s: Warning: up delay (%d) is not a " + "multiple of miimon (%d), updelay rounded " + "to %d ms\n", + bond->dev->name, new_value, + bond->params.miimon, + (new_value / bond->params.miimon) * + bond->params.miimon); } bond->params.updelay = new_value / bond->params.miimon; pr_info(DRV_NAME ": %s: Setting up delay to %d.\n", @@ -1299,9 +1302,9 @@ static ssize_t bonding_store_active_slave(struct device *d, new_active = slave; if (new_active == old_active) { /* do nothing */ - printk(KERN_INFO DRV_NAME - ": %s: %s is already the current active slave.\n", - bond->dev->name, slave->dev->name); + pr_info(DRV_NAME + ": %s: %s is already the current active slave.\n", + bond->dev->name, slave->dev->name); goto out; } else { @@ -1309,17 +1312,17 @@ static ssize_t bonding_store_active_slave(struct device *d, (old_active) && (new_active->link == BOND_LINK_UP) && IS_UP(new_active->dev)) { - printk(KERN_INFO DRV_NAME - ": %s: Setting %s as active slave.\n", - bond->dev->name, slave->dev->name); - bond_change_active_slave(bond, new_active); + pr_info(DRV_NAME + ": %s: Setting %s as active slave.\n", + bond->dev->name, slave->dev->name); + bond_change_active_slave(bond, new_active); } else { - printk(KERN_INFO DRV_NAME - ": %s: Could not set %s as active slave; " - "either %s is down or the link is down.\n", - bond->dev->name, slave->dev->name, - slave->dev->name); + pr_info(DRV_NAME + ": %s: Could not set %s as active slave; " + "either %s is down or the link is down.\n", + bond->dev->name, slave->dev->name, + slave->dev->name); } goto out; } @@ -1537,8 +1540,8 @@ int bond_create_sysfs(void) /* Is someone being kinky and naming a device bonding_master? */ if (__dev_get_by_name(&init_net, class_attr_bonding_masters.attr.name)) - printk(KERN_ERR - "network device named %s already exists in sysfs", + pr_err("network device named %s already " + "exists in sysfs", class_attr_bonding_masters.attr.name); ret = 0; } @@ -1566,7 +1569,7 @@ int bond_create_sysfs_entry(struct bonding *bond) err = sysfs_create_group(&(dev->dev.kobj), &bonding_group); if (err) - printk(KERN_EMERG "eek! didn't create group!\n"); + pr_emerg("eek! didn't create group!\n"); return err; } -- cgit v0.10.2 From a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565c Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 13 Aug 2009 09:44:51 -0400 Subject: Networking: use CAP_NET_ADMIN when deciding to call request_module The networking code checks CAP_SYS_MODULE before using request_module() to try to load a kernel module. While this seems reasonable it's actually weakening system security since we have to allow CAP_SYS_MODULE for things like /sbin/ip and bluetoothd which need to be able to trigger module loads. CAP_SYS_MODULE actually grants those binaries the ability to directly load any code into the kernel. We should instead be protecting modprobe and the modules on disk, rather than granting random programs the ability to load code directly into the kernel. Instead we are going to gate those networking checks on CAP_NET_ADMIN which still limits them to root but which does not grant those processes the ability to load arbitrary code into the kernel. Signed-off-by: Eric Paris Acked-by: Serge Hallyn Acked-by: Paul Moore Acked-by: David S. Miller Signed-off-by: James Morris diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 9d7c993..640f65c 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1752,12 +1752,12 @@ static int comedi_open(struct inode *inode, struct file *file) mutex_lock(&dev->mutex); if (dev->attached) goto ok; - if (!capable(CAP_SYS_MODULE) && dev->in_request_module) { + if (!capable(CAP_NET_ADMIN) && dev->in_request_module) { DPRINTK("in request module\n"); mutex_unlock(&dev->mutex); return -ENODEV; } - if (capable(CAP_SYS_MODULE) && dev->in_request_module) + if (capable(CAP_NET_ADMIN) && dev->in_request_module) goto ok; dev->in_request_module = 1; @@ -1770,8 +1770,8 @@ static int comedi_open(struct inode *inode, struct file *file) dev->in_request_module = 0; - if (!dev->attached && !capable(CAP_SYS_MODULE)) { - DPRINTK("not attached and not CAP_SYS_MODULE\n"); + if (!dev->attached && !capable(CAP_NET_ADMIN)) { + DPRINTK("not attached and not CAP_NET_ADMIN\n"); mutex_unlock(&dev->mutex); return -ENODEV; } diff --git a/net/core/dev.c b/net/core/dev.c index 6a94475..278d489 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1031,7 +1031,7 @@ void dev_load(struct net *net, const char *name) dev = __dev_get_by_name(net, name); read_unlock(&dev_base_lock); - if (!dev && capable(CAP_SYS_MODULE)) + if (!dev && capable(CAP_NET_ADMIN)) request_module("%s", name); } diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index e92beb9..6428b34 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -116,7 +116,7 @@ int tcp_set_default_congestion_control(const char *name) spin_lock(&tcp_cong_list_lock); ca = tcp_ca_find(name); #ifdef CONFIG_MODULES - if (!ca && capable(CAP_SYS_MODULE)) { + if (!ca && capable(CAP_NET_ADMIN)) { spin_unlock(&tcp_cong_list_lock); request_module("tcp_%s", name); @@ -246,7 +246,7 @@ int tcp_set_congestion_control(struct sock *sk, const char *name) #ifdef CONFIG_MODULES /* not found attempt to autoload module */ - if (!ca && capable(CAP_SYS_MODULE)) { + if (!ca && capable(CAP_NET_ADMIN)) { rcu_read_unlock(); request_module("tcp_%s", name); rcu_read_lock(); -- cgit v0.10.2 From 9188499cdb117d86a1ea6b04374095b098d56936 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 13 Aug 2009 09:44:57 -0400 Subject: security: introducing security_request_module Calling request_module() will trigger a userspace upcall which will load a new module into the kernel. This can be a dangerous event if the process able to trigger request_module() is able to control either the modprobe binary or the module binary. This patch adds a new security hook to request_module() which can be used by an LSM to control a processes ability to call request_module(). Signed-off-by: Eric Paris Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/include/linux/security.h b/include/linux/security.h index 57ead99..1e3dd86 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -678,6 +678,9 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @inode points to the inode to use as a reference. * The current task must be the one that nominated @inode. * Return 0 if successful. + * @kernel_module_request: + * Ability to trigger the kernel to automatically upcall to userspace for + * userspace to load a kernel module with the given name. * @task_setuid: * Check permission before setting one or more of the user identity * attributes of the current process. The @flags parameter indicates @@ -1489,6 +1492,7 @@ struct security_operations { void (*cred_commit)(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); int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags); int (*task_fix_setuid) (struct cred *new, const struct cred *old, int flags); @@ -1741,6 +1745,7 @@ 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); 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); int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags); int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags); @@ -2292,6 +2297,11 @@ static inline int security_kernel_create_files_as(struct cred *cred, return 0; } +static inline int security_kernel_module_request(void) +{ + return 0; +} + static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) { diff --git a/kernel/kmod.c b/kernel/kmod.c index 385c31a..5a7ae57 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -78,6 +78,10 @@ int __request_module(bool wait, const char *fmt, ...) #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ static int kmod_loop_msg; + ret = security_kernel_module_request(); + if (ret) + return ret; + va_start(args, fmt); ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); va_end(args); diff --git a/security/capability.c b/security/capability.c index ec05730..1b943f5 100644 --- a/security/capability.c +++ b/security/capability.c @@ -396,6 +396,11 @@ static int cap_kernel_create_files_as(struct cred *new, struct inode *inode) return 0; } +static int cap_kernel_module_request(void) +{ + return 0; +} + static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) { return 0; @@ -945,6 +950,7 @@ void security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, cred_commit); 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); set_to_cap_if_null(ops, task_setuid); set_to_cap_if_null(ops, task_fix_setuid); set_to_cap_if_null(ops, task_setgid); diff --git a/security/security.c b/security/security.c index 4501c5e..0e993f4 100644 --- a/security/security.c +++ b/security/security.c @@ -709,6 +709,11 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode) return security_ops->kernel_create_files_as(new, inode); } +int security_kernel_module_request(void) +{ + return security_ops->kernel_module_request(); +} + int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) { return security_ops->task_setuid(id0, id1, id2, flags); -- cgit v0.10.2 From 25354c4fee169710fd9da15f3bb2abaa24dcf933 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 13 Aug 2009 09:45:03 -0400 Subject: SELinux: add selinux_kernel_module_request This patch adds a new selinux hook so SELinux can arbitrate if a given process should be allowed to trigger a request for the kernel to try to load a module. This is a different operation than a process trying to load a module itself, which is already protected by CAP_SYS_MODULE. Signed-off-by: Eric Paris Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5dee883..5aa45b1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3296,6 +3296,11 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) return 0; } +static int selinux_kernel_module_request(void) +{ + return task_has_system(current, SYSTEM__MODULE_REQUEST); +} + static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) { return current_has_perm(p, PROCESS__SETPGID); @@ -5404,6 +5409,7 @@ static struct security_operations selinux_ops = { .cred_prepare = selinux_cred_prepare, .kernel_act_as = selinux_kernel_act_as, .kernel_create_files_as = selinux_kernel_create_files_as, + .kernel_module_request = selinux_kernel_module_request, .task_setpgid = selinux_task_setpgid, .task_getpgid = selinux_task_getpgid, .task_getsid = selinux_task_getsid, diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index 31df1d7..2b683ad 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h @@ -107,6 +107,7 @@ S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read") S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod") S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console") + S_(SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, "module_request") S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown") S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override") S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search") diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index d645192..21c7226 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h @@ -508,6 +508,7 @@ #define SYSTEM__SYSLOG_READ 0x00000002UL #define SYSTEM__SYSLOG_MOD 0x00000004UL #define SYSTEM__SYSLOG_CONSOLE 0x00000008UL +#define SYSTEM__MODULE_REQUEST 0x00000010UL #define CAPABILITY__CHOWN 0x00000001UL #define CAPABILITY__DAC_OVERRIDE 0x00000002UL #define CAPABILITY__DAC_READ_SEARCH 0x00000004UL -- cgit v0.10.2 From f322abf83feddc3c37c3a91794e0c5aece4af18e Mon Sep 17 00:00:00 2001 From: James Morris Date: Fri, 14 Aug 2009 11:19:29 +1000 Subject: security: update documentation for security_request_module Update documentation for security_request_module to indicate return value, as suggested by Serge Hallyn. Signed-off-by: James Morris diff --git a/include/linux/security.h b/include/linux/security.h index 1e3dd86..a16d6b7 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -681,6 +681,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @kernel_module_request: * Ability to trigger the kernel to automatically upcall to userspace for * userspace to load a kernel module with the given name. + * Return 0 if successful. * @task_setuid: * Check permission before setting one or more of the user identity * attributes of the current process. The @flags parameter indicates -- cgit v0.10.2 From 63b5ac286d5d7f668da537cc53a552578f7674a2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 14 Aug 2009 22:55:35 +1000 Subject: crypto: blkcipher - Do not use eseqiv on stream ciphers Recently we switched to using eseqiv on SMP machines in preference over chainiv. However, eseqiv does not support stream ciphers so they should still default to chainiv. This patch applies the same check as done by eseqiv to weed out the stream ciphers. In particular, all algorithms where the IV size is not equal to the block size will now default to chainiv. Signed-off-by: Herbert Xu diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 03fb5fa..f6f0833 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -183,6 +183,12 @@ EXPORT_SYMBOL_GPL(crypto_givcipher_type); const char *crypto_default_geniv(const struct crypto_alg *alg) { + if (((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == + CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize : + alg->cra_ablkcipher.ivsize) != + alg->cra_blocksize) + return "chainiv"; + return alg->cra_flags & CRYPTO_ALG_ASYNC ? "eseqiv" : skcipher_default_geniv; } -- cgit v0.10.2 From e30eb4ab45211c2f27b6bb9b29124ac431e01ce9 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Wed, 5 Aug 2009 01:52:07 +0200 Subject: ath5k: fix missing output in monitor mode after ifconfig up Let ath5k_chan_set() always call ath5k_reset(). This fixes the bug that we don't get any packets in monitor mode after: ifconfig wlan0 down iwconfig wlan0 mode monitor channel 1 ifconfig wlan0 up but they arrive after iwconfig wlan0 channel 2 Signed-off-by: Joerg Albert Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 3a1c156d..5d50285 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1071,10 +1071,9 @@ ath5k_setup_bands(struct ieee80211_hw *hw) } /* - * Set/change channels. If the channel is really being changed, - * it's done by reseting the chip. To accomplish this we must - * first cleanup any pending DMA, then restart stuff after a la - * ath5k_init. + * Set/change channels. We always reset the chip. + * To accomplish this we must first cleanup any pending DMA, + * then restart stuff after a la ath5k_init. * * Called with sc->lock. */ @@ -1084,19 +1083,13 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n", sc->curchan->center_freq, chan->center_freq); - if (chan->center_freq != sc->curchan->center_freq || - chan->hw_value != sc->curchan->hw_value) { - - /* - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. - */ - return ath5k_reset(sc, chan); - } - - return 0; + /* + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. + */ + return ath5k_reset(sc, chan); } static void @@ -2811,9 +2804,11 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&sc->lock); - ret = ath5k_chan_set(sc, conf->channel); - if (ret < 0) - goto unlock; + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ret = ath5k_chan_set(sc, conf->channel); + if (ret < 0) + goto unlock; + } if ((changed & IEEE80211_CONF_CHANGE_POWER) && (sc->power_level != conf->power_level)) { -- cgit v0.10.2 From 63b08b8d97a2a5ff23436cd52e8cd70c1de0319c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 4 Aug 2009 10:05:30 -0700 Subject: ath9k: use new FIF_PSPOLL configure filter We used to set pspoll filter on ath9k on AP mode but we no longer need this mode specific check as mac80211 now does the check for us and informs us when we should enable pspoll through FIF_PSPOLL. Cc: Igor Perminov Cc: Jouni Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 61edfab..6b07ced 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -448,8 +448,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) else rfilt |= ATH9K_RX_FILTER_BEACON; - /* If in HOSTAP mode, want to enable reception of PSPOLL frames */ - if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) + if (sc->rx.rxfilter & FIF_PSPOLL) rfilt |= ATH9K_RX_FILTER_PSPOLL; if (sc->sec_wiphy) { -- cgit v0.10.2 From 14b46c8a87f835f4327afa32fad2a523a8fe584d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 4 Aug 2009 14:04:17 -0700 Subject: zd1211rw: make it clear we don't use leds.h LED stuff zd1211rw uses its own LED stuff so let rename its LED stuff as such. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 2c813d8..5e110a2 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -1278,11 +1278,11 @@ int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) other_led = chip->link_led == LED1 ? LED2 : LED1; switch (status) { - case LED_OFF: + case ZD_LED_OFF: ioreqs[0].value = FW_LINK_OFF; ioreqs[1].value = v[1] & ~(LED1|LED2); break; - case LED_SCANNING: + case ZD_LED_SCANNING: ioreqs[0].value = FW_LINK_OFF; ioreqs[1].value = v[1] & ~other_led; if (get_seconds() % 3 == 0) { @@ -1291,7 +1291,7 @@ int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) ioreqs[1].value |= chip->link_led; } break; - case LED_ASSOCIATED: + case ZD_LED_ASSOCIATED: ioreqs[0].value = FW_LINK_TX; ioreqs[1].value = v[1] & ~other_led; ioreqs[1].value |= chip->link_led; diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index ee42751..678c139 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -897,9 +897,9 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip); int zd_chip_unlock_phy_regs(struct zd_chip *chip); enum led_status { - LED_OFF = 0, - LED_SCANNING = 1, - LED_ASSOCIATED = 2, + ZD_LED_OFF = 0, + ZD_LED_SCANNING = 1, + ZD_LED_ASSOCIATED = 2, }; int zd_chip_control_leds(struct zd_chip *chip, enum led_status status); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 54abdd0c..55b7fbd 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -1013,7 +1013,7 @@ static void link_led_handler(struct work_struct *work) spin_unlock_irq(&mac->lock); r = zd_chip_control_leds(chip, - is_associated ? LED_ASSOCIATED : LED_SCANNING); + is_associated ? ZD_LED_ASSOCIATED : ZD_LED_SCANNING); if (r) dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); @@ -1038,5 +1038,5 @@ static void housekeeping_disable(struct zd_mac *mac) dev_dbg_f(zd_mac_dev(mac), "\n"); cancel_rearming_delayed_workqueue(zd_workqueue, &mac->housekeeping.link_led_work); - zd_chip_control_leds(&mac->chip, LED_OFF); + zd_chip_control_leds(&mac->chip, ZD_LED_OFF); } -- cgit v0.10.2 From c10e47f458653a68b1d3956237b7bf2e1ab1e8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Tue, 4 Aug 2009 23:57:32 +0200 Subject: b43: Add LP 2063 radio init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add B2063 radio init code and tables for LP-PHY. Rename structures common between B2062 and B2063 to B206X. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index aa1486a..184fdaf 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -333,7 +333,17 @@ static void lpphy_2062_init(struct b43_wldev *dev) /* Initialize the 2063 radio. */ static void lpphy_2063_init(struct b43_wldev *dev) { - //TODO + b2063_upload_init_table(dev); + b43_radio_write(dev, B2063_LOGEN_SP5, 0); + b43_radio_set(dev, B2063_COMM8, 0x38); + b43_radio_write(dev, B2063_REG_SP1, 0x56); + b43_radio_mask(dev, B2063_RX_BB_CTL2, ~0x2); + b43_radio_write(dev, B2063_PA_SP7, 0); + b43_radio_write(dev, B2063_TX_RF_SP6, 0x20); + b43_radio_write(dev, B2063_TX_RF_SP9, 0x40); + b43_radio_write(dev, B2063_PA_SP3, 0xa0); + b43_radio_write(dev, B2063_PA_SP4, 0xa0); + b43_radio_write(dev, B2063_PA_SP2, 0x18); } static void lpphy_sync_stx(struct b43_wldev *dev) @@ -533,6 +543,7 @@ static void lpphy_tx_pctl_init(struct b43_wldev *dev) static int b43_lpphy_op_init(struct b43_wldev *dev) { /* TODO: band SPROM */ + /* TODO: tables init */ lpphy_baseband_init(dev); lpphy_radio_init(dev); //TODO calibrate RC diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index 4ea734d..cadfe81 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -28,22 +28,22 @@ #include "phy_lp.h" -/* Entry of the 2062 radio init table */ -struct b2062_init_tab_entry { +/* Entry of the 2062/2063 radio init table */ +struct b206x_init_tab_entry { u16 offset; u16 value_a; u16 value_g; u8 flags; }; -#define B2062_FLAG_A 0x01 /* Flag: Init in A mode */ -#define B2062_FLAG_G 0x02 /* Flag: Init in G mode */ +#define B206X_FLAG_A 0x01 /* Flag: Init in A mode */ +#define B206X_FLAG_G 0x02 /* Flag: Init in G mode */ -static const struct b2062_init_tab_entry b2062_init_tab[] = { +static const struct b206x_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_N_COMM1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = 0x0001, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ @@ -56,42 +56,42 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_N_COMM14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_COMM15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_PDN_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_PDN_CTL1, .value_a = 0x0000, .value_g = 0x00CA, .flags = B2062_FLAG_G, }, + { .offset = B2062_N_PDN_CTL1, .value_a = 0x0000, .value_g = 0x00CA, .flags = B206X_FLAG_G, }, /* { .offset = B2062_N_PDN_CTL2, .value_a = 0x0018, .value_g = 0x0018, .flags = 0, }, */ - { .offset = B2062_N_PDN_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_N_PDN_CTL4, .value_a = 0x0015, .value_g = 0x002A, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_PDN_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_N_PDN_CTL4, .value_a = 0x0015, .value_g = 0x002A, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_GEN_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_IQ_CALIB, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ - { .offset = B2062_N_LGENC, .value_a = 0x00DB, .value_g = 0x00FF, .flags = B2062_FLAG_A, }, + { .offset = B2062_N_LGENC, .value_a = 0x00DB, .value_g = 0x00FF, .flags = B206X_FLAG_A, }, /* { .offset = B2062_N_LGENA_LPF, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_BIAS0, .value_a = 0x0041, .value_g = 0x0041, .flags = 0, }, */ /* { .offset = B2062_N_LGNEA_BIAS1, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_CTL0, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_LGENA_TUNE0, .value_a = 0x00DD, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_LGENA_TUNE0, .value_a = 0x00DD, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_LGENA_TUNE1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_LGENA_TUNE2, .value_a = 0x00DD, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_N_LGENA_TUNE3, .value_a = 0x0077, .value_g = 0x00B5, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_N_LGENA_CTL3, .value_a = 0x0000, .value_g = 0x00FF, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_LGENA_TUNE2, .value_a = 0x00DD, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_N_LGENA_TUNE3, .value_a = 0x0077, .value_g = 0x00B5, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_N_LGENA_CTL3, .value_a = 0x0000, .value_g = 0x00FF, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_LGENA_CTL4, .value_a = 0x001F, .value_g = 0x001F, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_CTL5, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_CTL6, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ - { .offset = B2062_N_LGENA_CTL7, .value_a = 0x0033, .value_g = 0x0033, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_LGENA_CTL7, .value_a = 0x0033, .value_g = 0x0033, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_RXA_CTL0, .value_a = 0x0009, .value_g = 0x0009, .flags = 0, }, */ - { .offset = B2062_N_RXA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_G, }, + { .offset = B2062_N_RXA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, /* { .offset = B2062_N_RXA_CTL2, .value_a = 0x0018, .value_g = 0x0018, .flags = 0, }, */ /* { .offset = B2062_N_RXA_CTL3, .value_a = 0x0027, .value_g = 0x0027, .flags = 0, }, */ /* { .offset = B2062_N_RXA_CTL4, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */ /* { .offset = B2062_N_RXA_CTL5, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ /* { .offset = B2062_N_RXA_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_RXA_CTL7, .value_a = 0x0008, .value_g = 0x0008, .flags = 0, }, */ - { .offset = B2062_N_RXBB_CTL0, .value_a = 0x0082, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_RXBB_CTL0, .value_a = 0x0082, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_RXBB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_RXBB_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_RXBB_GAIN0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_RXBB_GAIN1, .value_a = 0x0004, .value_g = 0x0004, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_N_RXBB_GAIN2, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_RXBB_GAIN1, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_N_RXBB_GAIN2, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_RXBB_GAIN3, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */ /* { .offset = B2062_N_RXBB_RSSI0, .value_a = 0x0043, .value_g = 0x0043, .flags = 0, }, */ /* { .offset = B2062_N_RXBB_RSSI1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ @@ -112,8 +112,8 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_N_TX_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_TX_CTL2, .value_a = 0x0084, .value_g = 0x0084, .flags = 0, }, */ /* { .offset = B2062_N_TX_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_TX_CTL4, .value_a = 0x0003, .value_g = 0x0003, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_N_TX_CTL5, .value_a = 0x0002, .value_g = 0x0002, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_TX_CTL4, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_N_TX_CTL5, .value_a = 0x0002, .value_g = 0x0002, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_TX_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_TX_CTL7, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ /* { .offset = B2062_N_TX_CTL8, .value_a = 0x0082, .value_g = 0x0082, .flags = 0, }, */ @@ -121,7 +121,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_N_TX_CTL_A, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_TX_GC2G, .value_a = 0x00FF, .value_g = 0x00FF, .flags = 0, }, */ /* { .offset = B2062_N_TX_GC5G, .value_a = 0x00FF, .value_g = 0x00FF, .flags = 0, }, */ - { .offset = B2062_N_TX_TUNE, .value_a = 0x0088, .value_g = 0x001B, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_TX_TUNE, .value_a = 0x0088, .value_g = 0x001B, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_TX_PAD, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ /* { .offset = B2062_N_TX_PGA, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ /* { .offset = B2062_N_TX_PADAUX, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ @@ -150,7 +150,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_S_RADIO_ID_CODE, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ @@ -162,24 +162,24 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_S_COMM13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_PDS_CTL0, .value_a = 0x00FF, .value_g = 0x00FF, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_PDS_CTL0, .value_a = 0x00FF, .value_g = 0x00FF, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_PDS_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_PDS_CTL2, .value_a = 0x008E, .value_g = 0x008E, .flags = 0, }, */ /* { .offset = B2062_S_PDS_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_BG_CTL0, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ /* { .offset = B2062_S_BG_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_BG_CTL2, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */ - { .offset = B2062_S_LGENG_CTL0, .value_a = 0x00F8, .value_g = 0x00D8, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_LGENG_CTL1, .value_a = 0x003C, .value_g = 0x0024, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_LGENG_CTL0, .value_a = 0x00F8, .value_g = 0x00D8, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_LGENG_CTL1, .value_a = 0x003C, .value_g = 0x0024, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_LGENG_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_LGENG_CTL3, .value_a = 0x0041, .value_g = 0x0041, .flags = 0, }, */ /* { .offset = B2062_S_LGENG_CTL4, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ /* { .offset = B2062_S_LGENG_CTL5, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ /* { .offset = B2062_S_LGENG_CTL6, .value_a = 0x0022, .value_g = 0x0022, .flags = 0, }, */ /* { .offset = B2062_S_LGENG_CTL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_LGENG_CTL8, .value_a = 0x0088, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_LGENG_CTL8, .value_a = 0x0088, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_LGENG_CTL9, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ - { .offset = B2062_S_LGENG_CTL10, .value_a = 0x0088, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_LGENG_CTL10, .value_a = 0x0088, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_LGENG_CTL11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_REFPLL_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_REFPLL_CTL1, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ @@ -198,41 +198,41 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_S_REFPLL_CTL14, .value_a = 0x0075, .value_g = 0x0075, .flags = 0, }, */ /* { .offset = B2062_S_REFPLL_CTL15, .value_a = 0x00B4, .value_g = 0x00B4, .flags = 0, }, */ /* { .offset = B2062_S_REFPLL_CTL16, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL0, .value_a = 0x0098, .value_g = 0x0098, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL1, .value_a = 0x0010, .value_g = 0x0010, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL0, .value_a = 0x0098, .value_g = 0x0098, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL1, .value_a = 0x0010, .value_g = 0x0010, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RFPLL_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL5, .value_a = 0x0043, .value_g = 0x0043, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL6, .value_a = 0x0047, .value_g = 0x0047, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL7, .value_a = 0x000C, .value_g = 0x000C, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL8, .value_a = 0x0011, .value_g = 0x0011, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL9, .value_a = 0x0011, .value_g = 0x0011, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL10, .value_a = 0x000E, .value_g = 0x000E, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL11, .value_a = 0x0008, .value_g = 0x0008, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL12, .value_a = 0x0033, .value_g = 0x0033, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL13, .value_a = 0x000A, .value_g = 0x000A, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL14, .value_a = 0x0006, .value_g = 0x0006, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL5, .value_a = 0x0043, .value_g = 0x0043, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL6, .value_a = 0x0047, .value_g = 0x0047, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL7, .value_a = 0x000C, .value_g = 0x000C, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL8, .value_a = 0x0011, .value_g = 0x0011, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL9, .value_a = 0x0011, .value_g = 0x0011, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL10, .value_a = 0x000E, .value_g = 0x000E, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL11, .value_a = 0x0008, .value_g = 0x0008, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL12, .value_a = 0x0033, .value_g = 0x0033, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL13, .value_a = 0x000A, .value_g = 0x000A, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL14, .value_a = 0x0006, .value_g = 0x0006, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RFPLL_CTL15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL16, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL17, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL18, .value_a = 0x003E, .value_g = 0x003E, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL19, .value_a = 0x0013, .value_g = 0x0013, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL18, .value_a = 0x003E, .value_g = 0x003E, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL19, .value_a = 0x0013, .value_g = 0x0013, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RFPLL_CTL20, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL21, .value_a = 0x0062, .value_g = 0x0062, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL22, .value_a = 0x0007, .value_g = 0x0007, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL23, .value_a = 0x0016, .value_g = 0x0016, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL24, .value_a = 0x005C, .value_g = 0x005C, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL25, .value_a = 0x0095, .value_g = 0x0095, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL21, .value_a = 0x0062, .value_g = 0x0062, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL22, .value_a = 0x0007, .value_g = 0x0007, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL23, .value_a = 0x0016, .value_g = 0x0016, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL24, .value_a = 0x005C, .value_g = 0x005C, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL25, .value_a = 0x0095, .value_g = 0x0095, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RFPLL_CTL26, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL27, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL28, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL29, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL30, .value_a = 0x00A0, .value_g = 0x00A0, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL31, .value_a = 0x0004, .value_g = 0x0004, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL30, .value_a = 0x00A0, .value_g = 0x00A0, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL31, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RFPLL_CTL32, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL33, .value_a = 0x00CC, .value_g = 0x00CC, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL34, .value_a = 0x0007, .value_g = 0x0007, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL33, .value_a = 0x00CC, .value_g = 0x00CC, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL34, .value_a = 0x0007, .value_g = 0x0007, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RXG_CNT0, .value_a = 0x0010, .value_g = 0x0010, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ @@ -241,7 +241,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_S_RXG_CNT5, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT6, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT7, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ - { .offset = B2062_S_RXG_CNT8, .value_a = 0x000F, .value_g = 0x000F, .flags = B2062_FLAG_A, }, + { .offset = B2062_S_RXG_CNT8, .value_a = 0x000F, .value_g = 0x000F, .flags = B206X_FLAG_A, }, /* { .offset = B2062_S_RXG_CNT9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT10, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT11, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ @@ -253,19 +253,337 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_S_RXG_CNT17, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ }; +static const struct b206x_init_tab_entry b2063_init_tab[] = { + { .offset = B2063_COMM1, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + /* { .offset = B2063_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_COMM10, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A, }, + /* { .offset = B2063_COMM11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM12, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM14, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ + /* { .offset = B2063_COMM15, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ + { .offset = B2063_COMM16, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM17, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM18, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM19, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM20, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM21, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM22, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM23, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM24, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + /* { .offset = B2063_PWR_SWITCH_CTL, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */ + /* { .offset = B2063_PLL_SP1, .value_a = 0x003f, .value_g = 0x003f, .flags = 0, }, */ + /* { .offset = B2063_PLL_SP2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_LOGEN_SP1, .value_a = 0x00e8, .value_g = 0x00d4, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2063_LOGEN_SP2, .value_a = 0x00a7, .value_g = 0x0053, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_LOGEN_SP3, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + { .offset = B2063_LOGEN_SP4, .value_a = 0x00f0, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_LOGEN_SP5, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + { .offset = B2063_G_RX_SP1, .value_a = 0x001f, .value_g = 0x005e, .flags = B206X_FLAG_G, }, + { .offset = B2063_G_RX_SP2, .value_a = 0x007f, .value_g = 0x007e, .flags = B206X_FLAG_G, }, + { .offset = B2063_G_RX_SP3, .value_a = 0x0030, .value_g = 0x00f0, .flags = B206X_FLAG_G, }, + /* { .offset = B2063_G_RX_SP4, .value_a = 0x0035, .value_g = 0x0035, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SP5, .value_a = 0x003f, .value_g = 0x003f, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_G_RX_SP7, .value_a = 0x007f, .value_g = 0x007f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_G_RX_SP8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SP9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_G_RX_SP10, .value_a = 0x000c, .value_g = 0x000c, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_G_RX_SP11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_A_RX_SP1, .value_a = 0x003c, .value_g = 0x003f, .flags = B206X_FLAG_A, }, + { .offset = B2063_A_RX_SP2, .value_a = 0x00fc, .value_g = 0x00fe, .flags = B206X_FLAG_A, }, + /* { .offset = B2063_A_RX_SP3, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SP4, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SP5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_A_RX_SP7, .value_a = 0x0008, .value_g = 0x0008, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_RX_BB_SP1, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_SP2, .value_a = 0x0022, .value_g = 0x0022, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_SP3, .value_a = 0x00a8, .value_g = 0x00a8, .flags = 0, }, */ + { .offset = B2063_RX_BB_SP4, .value_a = 0x0060, .value_g = 0x0060, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_RX_BB_SP5, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_SP7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_RX_BB_SP8, .value_a = 0x0030, .value_g = 0x0030, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_TX_RF_SP1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP2, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ + { .offset = B2063_TX_RF_SP3, .value_a = 0x000c, .value_g = 0x000b, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2063_TX_RF_SP4, .value_a = 0x0010, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_TX_RF_SP5, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP6, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP7, .value_a = 0x0068, .value_g = 0x0068, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP8, .value_a = 0x0068, .value_g = 0x0068, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP9, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP10, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP11, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP12, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP13, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP14, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP15, .value_a = 0x00c0, .value_g = 0x00c0, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP16, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP17, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + { .offset = B2063_PA_SP1, .value_a = 0x003d, .value_g = 0x00fd, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_PA_SP2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ + /* { .offset = B2063_PA_SP3, .value_a = 0x0096, .value_g = 0x0096, .flags = 0, }, */ + /* { .offset = B2063_PA_SP4, .value_a = 0x005a, .value_g = 0x005a, .flags = 0, }, */ + /* { .offset = B2063_PA_SP5, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */ + /* { .offset = B2063_PA_SP6, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */ + /* { .offset = B2063_PA_SP7, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + { .offset = B2063_TX_BB_SP1, .value_a = 0x0002, .value_g = 0x0002, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_TX_BB_SP2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_BB_SP3, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */ + /* { .offset = B2063_REG_SP1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_BANDGAP_CTL1, .value_a = 0x0056, .value_g = 0x0056, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_BANDGAP_CTL2, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ + /* { .offset = B2063_LPO_CTL1, .value_a = 0x000e, .value_g = 0x000e, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL1, .value_a = 0x007e, .value_g = 0x007e, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL2, .value_a = 0x0015, .value_g = 0x0015, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL3, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL10, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_CALNRST, .value_a = 0x0004, .value_g = 0x0004, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_IN_PLL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_IN_PLL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_CP1, .value_a = 0x00cf, .value_g = 0x00cf, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_CP2, .value_a = 0x0059, .value_g = 0x0059, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_CP3, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_CP4, .value_a = 0x0042, .value_g = 0x0042, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_LF1, .value_a = 0x00db, .value_g = 0x00db, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_LF2, .value_a = 0x0094, .value_g = 0x0094, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_LF3, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_LF4, .value_a = 0x0063, .value_g = 0x0063, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_SG1, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_SG2, .value_a = 0x00d3, .value_g = 0x00d3, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_SG3, .value_a = 0x00b1, .value_g = 0x00b1, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_SG4, .value_a = 0x003b, .value_g = 0x003b, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_SG5, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO1, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ + { .offset = B2063_PLL_JTAG_PLL_VCO2, .value_a = 0x00f7, .value_g = 0x00f7, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB3, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB5, .value_a = 0x0009, .value_g = 0x0009, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB6, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB7, .value_a = 0x0016, .value_g = 0x0016, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB8, .value_a = 0x006b, .value_g = 0x006b, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB10, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_XTAL_12, .value_a = 0x0004, .value_g = 0x0004, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_XTAL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_ACL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_ACL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_ACL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_ACL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_ACL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_INPUTS, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_WAITCNT, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVR1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVR2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL3, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL4, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL5, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL6, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL7, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CALVLD1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CALVLD2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_CALIB_EN, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_PEAKDET1, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_RCCR1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_VCOBUF1, .value_a = 0x0060, .value_g = 0x0060, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_MIXER1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_MIXER2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_BUF1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_BUF2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_DIV1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_DIV2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_DIV3, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_CBUFRX1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_CBUFRX2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_CBUFTX1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_CBUFTX2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_IDAC1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_SPARE1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_SPARE2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_SPARE3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_1ST1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_G_RX_1ST2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_1ST3, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND1, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND2, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND3, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND5, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND7, .value_a = 0x0035, .value_g = 0x0035, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PS1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PS2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PS3, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PS4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PS5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_MIX1, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ + /* { .offset = B2063_G_RX_MIX2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_G_RX_MIX3, .value_a = 0x0071, .value_g = 0x0071, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2063_G_RX_MIX4, .value_a = 0x0071, .value_g = 0x0071, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_G_RX_MIX5, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ + /* { .offset = B2063_G_RX_MIX6, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_G_RX_MIX7, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ + /* { .offset = B2063_G_RX_MIX8, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PDET1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SPARES1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SPARES2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SPARES3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_1ST1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_A_RX_1ST2, .value_a = 0x00f0, .value_g = 0x0030, .flags = B206X_FLAG_A, }, + /* { .offset = B2063_A_RX_1ST3, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_A_RX_1ST4, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_A_RX_1ST5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND1, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND4, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND7, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PS1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PS2, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PS3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PS4, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PS5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_A_RX_PS6, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_A_RX_MIX1, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_A_RX_MIX2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_MIX3, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ + { .offset = B2063_A_RX_MIX4, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2063_A_RX_MIX5, .value_a = 0x000f, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2063_A_RX_MIX6, .value_a = 0x000f, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_A_RX_MIX7, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ + /* { .offset = B2063_A_RX_MIX8, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PWRDET1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SPARE1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SPARE2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SPARE3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_RX_TIA_CTL1, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_RX_TIA_CTL2, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ + { .offset = B2063_RX_TIA_CTL3, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_RX_TIA_CTL4, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ + /* { .offset = B2063_RX_TIA_CTL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RX_TIA_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL1, .value_a = 0x0074, .value_g = 0x0074, .flags = 0, }, */ + { .offset = B2063_RX_BB_CTL2, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_RX_BB_CTL3, .value_a = 0x00a2, .value_g = 0x00a2, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL4, .value_a = 0x00aa, .value_g = 0x00aa, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL5, .value_a = 0x0024, .value_g = 0x0024, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL6, .value_a = 0x00a9, .value_g = 0x00a9, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL7, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL8, .value_a = 0x0010, .value_g = 0x0010, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL9, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL1, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_IDAC_LO_RF_I, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_IDAC_LO_RF_Q, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_IDAC_LO_BB_I, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_IDAC_LO_BB_Q, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL2, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL3, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL4, .value_a = 0x00b8, .value_g = 0x00b8, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL5, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL6, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL7, .value_a = 0x0078, .value_g = 0x0078, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL8, .value_a = 0x00c0, .value_g = 0x00c0, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL9, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL10, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_PA_CTL1, .value_a = 0x0000, .value_g = 0x0004, .flags = B206X_FLAG_A, }, + /* { .offset = B2063_PA_CTL2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL5, .value_a = 0x0096, .value_g = 0x0096, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL6, .value_a = 0x0077, .value_g = 0x0077, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL7, .value_a = 0x005a, .value_g = 0x005a, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL10, .value_a = 0x0021, .value_g = 0x0021, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL11, .value_a = 0x0070, .value_g = 0x0070, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL12, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_BB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_BB_CTL2, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */ + /* { .offset = B2063_TX_BB_CTL3, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ + /* { .offset = B2063_TX_BB_CTL4, .value_a = 0x000b, .value_g = 0x000b, .flags = 0, }, */ + /* { .offset = B2063_GPIO_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_VREG_CTL1, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_AMUX_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_IQ_CALIB_GVAR, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */ + /* { .offset = B2063_IQ_CALIB_CTL1, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ + /* { .offset = B2063_IQ_CALIB_CTL2, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */ + /* { .offset = B2063_TEMPSENSE_CTL1, .value_a = 0x0046, .value_g = 0x0046, .flags = 0, }, */ + /* { .offset = B2063_TEMPSENSE_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_RX_LOOPBACK1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_RX_LOOPBACK2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_EXT_TSSI_CTL1, .value_a = 0x0021, .value_g = 0x0021, .flags = 0, }, */ + /* { .offset = B2063_EXT_TSSI_CTL2, .value_a = 0x0023, .value_g = 0x0023, .flags = 0, }, */ + /* { .offset = B2063_AFE_CTL , .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ +}; + void b2062_upload_init_table(struct b43_wldev *dev) { - const struct b2062_init_tab_entry *e; + const struct b206x_init_tab_entry *e; unsigned int i; for (i = 0; i < ARRAY_SIZE(b2062_init_tab); i++) { e = &b2062_init_tab[i]; if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - if (!(e->flags & B2062_FLAG_G)) + if (!(e->flags & B206X_FLAG_G)) + continue; + b43_radio_write(dev, e->offset, e->value_g); + } else { + if (!(e->flags & B206X_FLAG_A)) + continue; + b43_radio_write(dev, e->offset, e->value_a); + } + } +} + +void b2063_upload_init_table(struct b43_wldev *dev) +{ + const struct b206x_init_tab_entry *e; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b2063_init_tab); i++) { + e = &b2063_init_tab[i]; + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + if (!(e->flags & B206X_FLAG_G)) continue; b43_radio_write(dev, e->offset, e->value_g); } else { - if (!(e->flags & B2062_FLAG_A)) + if (!(e->flags & B206X_FLAG_A)) continue; b43_radio_write(dev, e->offset, e->value_a); } diff --git a/drivers/net/wireless/b43/tables_lpphy.h b/drivers/net/wireless/b43/tables_lpphy.h index 0b8d028..52ce32f 100644 --- a/drivers/net/wireless/b43/tables_lpphy.h +++ b/drivers/net/wireless/b43/tables_lpphy.h @@ -26,6 +26,7 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, unsigned int nr_elements, const void *data); void b2062_upload_init_table(struct b43_wldev *dev); +void b2063_upload_init_table(struct b43_wldev *dev); #endif /* B43_TABLES_LPPHY_H_ */ -- cgit v0.10.2 From c03e20fc9a6ec5741d9df561130ecba38ef50eb6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 4 Aug 2009 15:06:26 -0700 Subject: mac80211: fix compilation of mesh (although its disabled) Mesh is currently disabled on mac80211, its marked as broken. This patch gets it to compile though, to account for the mac80211 workqueue changes. There was a simple typo in the patches for mesh for the workqueue migration, but we never compile tested it as we couldn't even select mesh as its broken. Lets at least let it compile for those interested in getting it fixed. Reported-by: Pat Erley Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2f4f518..8c068e2 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -54,7 +54,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) return; } - ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&local->hw, &ifmsh->work); } /** @@ -357,7 +357,7 @@ static void ieee80211_mesh_path_timer(unsigned long data) return; } - ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&local->hw, &ifmsh->work); } struct mesh_table *mesh_table_grow(struct mesh_table *tbl) @@ -471,7 +471,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; ifmsh->housekeeping = true; - ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&local->hw, &ifmsh->work); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED); } @@ -619,7 +619,7 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) if (ieee80211_vif_is_mesh(&sdata->vif)) - ieee80211_queue_work(local->hw.workqueue, &sdata->u.mesh.work); + ieee80211_queue_work(&local->hw, &sdata->u.mesh.work); rcu_read_unlock(); } @@ -692,7 +692,7 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: skb_queue_tail(&ifmsh->skb_queue, skb); - ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&local->hw, &ifmsh->work); return RX_QUEUED; } diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 11ab71a..e1a763e 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -660,14 +660,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) spin_unlock(&ifmsh->mesh_preq_queue_lock); if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) - ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); else if (time_before(jiffies, ifmsh->last_preq)) { /* avoid long wait if did not send preqs for a long time * and jiffies wrapped around */ ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; - ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); } else mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + min_preq_int_jiff(sdata)); -- cgit v0.10.2 From 7c81e98a60cc525e21a6d86cb4357a626f530699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Wed, 5 Aug 2009 00:25:42 +0200 Subject: b43: Typo fixes & minor cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make use of HostFlags defines in the LP-PHY code. Fix fallout from the IEEE80211_IF_TYPE to NL80211_IFTYPE change. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index b6811cf..d57ee9b 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -639,7 +639,7 @@ struct b43_wl { u8 mac_addr[ETH_ALEN]; /* Current BSSID */ u8 bssid[ETH_ALEN]; - /* Interface type. (IEEE80211_IF_TYPE_XXX) */ + /* Interface type. (NL80211_IFTYPE_XXX) */ int if_type; /* Is the card operating in AP, STA or IBSS mode? */ bool operating; diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 184fdaf..ed3a528 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -130,7 +130,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006); b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005); b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF); - b43_hf_write(dev, b43_hf_read(dev) | 0x0800ULL << 32); + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W); } if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000); -- cgit v0.10.2 From c45fa8c50c2149eec260a55c84e76339a2a761dd Mon Sep 17 00:00:00 2001 From: gregor kowski Date: Wed, 5 Aug 2009 00:44:23 +0200 Subject: b43: remove wrong probe_resp_plcp write The tkip hw support uncovered a bug in b43_write_probe_resp_template : it is writing at the wrong shm offset, it is in the B43_SHM_SH_TKIPTSCTTAK zone. Remove b43_write_probe_resp_template, b43_write_probe_resp_plcp and b43_write_probe_resp_plcp because the probe response offload is currently not supported by mac80211. Signed-off-by: Gregor Kowski Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 925f346..997dd55 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1429,116 +1429,6 @@ static void b43_write_beacon_template(struct b43_wldev *dev, b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset); } -static void b43_write_probe_resp_plcp(struct b43_wldev *dev, - u16 shm_offset, u16 size, - struct ieee80211_rate *rate) -{ - struct b43_plcp_hdr4 plcp; - u32 tmp; - __le16 dur; - - plcp.data = 0; - b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value); - dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->vif, size, - rate); - /* Write PLCP in two parts and timing for packet transfer */ - tmp = le32_to_cpu(plcp.data); - b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF); - b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 2, tmp >> 16); - b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 6, le16_to_cpu(dur)); -} - -/* Instead of using custom probe response template, this function - * just patches custom beacon template by: - * 1) Changing packet type - * 2) Patching duration field - * 3) Stripping TIM - */ -static const u8 *b43_generate_probe_resp(struct b43_wldev *dev, - u16 *dest_size, - struct ieee80211_rate *rate) -{ - const u8 *src_data; - u8 *dest_data; - u16 src_size, elem_size, src_pos, dest_pos; - __le16 dur; - struct ieee80211_hdr *hdr; - size_t ie_start; - - src_size = dev->wl->current_beacon->len; - src_data = (const u8 *)dev->wl->current_beacon->data; - - /* Get the start offset of the variable IEs in the packet. */ - ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable)); - - if (B43_WARN_ON(src_size < ie_start)) - return NULL; - - dest_data = kmalloc(src_size, GFP_ATOMIC); - if (unlikely(!dest_data)) - return NULL; - - /* Copy the static data and all Information Elements, except the TIM. */ - memcpy(dest_data, src_data, ie_start); - src_pos = ie_start; - dest_pos = ie_start; - for ( ; src_pos < src_size - 2; src_pos += elem_size) { - elem_size = src_data[src_pos + 1] + 2; - if (src_data[src_pos] == 5) { - /* This is the TIM. */ - continue; - } - memcpy(dest_data + dest_pos, src_data + src_pos, - elem_size); - dest_pos += elem_size; - } - *dest_size = dest_pos; - hdr = (struct ieee80211_hdr *)dest_data; - - /* Set the frame control. */ - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_PROBE_RESP); - dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->vif, *dest_size, - rate); - hdr->duration_id = dur; - - return dest_data; -} - -static void b43_write_probe_resp_template(struct b43_wldev *dev, - u16 ram_offset, - u16 shm_size_offset, - struct ieee80211_rate *rate) -{ - const u8 *probe_resp_data; - u16 size; - - size = dev->wl->current_beacon->len; - probe_resp_data = b43_generate_probe_resp(dev, &size, rate); - if (unlikely(!probe_resp_data)) - return; - - /* Looks like PLCP headers plus packet timings are stored for - * all possible basic rates - */ - /* FIXME this is the wrong offset : it goes in tkip rx phase1 shm */ -#if 0 - b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]); - b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]); - b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]); - b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]); -#endif - - size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6)); - b43_write_template_common(dev, probe_resp_data, - size, ram_offset, shm_size_offset, - rate->hw_value); - kfree(probe_resp_data); -} - static void b43_upload_beacon0(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; @@ -1546,10 +1436,6 @@ static void b43_upload_beacon0(struct b43_wldev *dev) if (wl->beacon0_uploaded) return; b43_write_beacon_template(dev, 0x68, 0x18); - /* FIXME: Probe resp upload doesn't really belong here, - * but we don't use that feature anyway. */ - b43_write_probe_resp_template(dev, 0x268, 0x4A, - &__b43_ratetable[3]); wl->beacon0_uploaded = 1; } -- cgit v0.10.2 From bedaf80866f5d438b47d05e02fb1852065fe5d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Wed, 5 Aug 2009 01:28:20 +0200 Subject: b43: Fix fallout from the IEEE80211_IF_TYPE to NL80211_IFTYPE change. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update a comment that still says IEEE80211_IF_TYPE instead of NL80211_IFTYPE. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index d57ee9b..102094a 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -845,7 +845,7 @@ static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev) return ssb_get_drvdata(ssb_dev); } -/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */ +/* Is the device operating in a specified mode (NL80211_IFTYPE_XXX). */ static inline int b43_is_mode(struct b43_wl *wl, int type) { return (wl->operating && wl->if_type == type); -- cgit v0.10.2 From a42dd7efd934888833c01199dbd21b242100ee92 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 5 Aug 2009 15:07:13 +0800 Subject: wireless: display wext SSID when connected by cfg80211 cfg80211 displays correct link info when connected by wext. But if the connection is setup by cfg80211, wext cannot display the SSID. This patch fixed this issue. Cc: Johannes Berg Signed-off-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 7bacbd1..e4a054a 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -206,7 +206,15 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, data->flags = 0; wdev_lock(wdev); - if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { + if (wdev->current_bss) { + const u8 *ie = ieee80211_bss_get_ie(&wdev->current_bss->pub, + WLAN_EID_SSID); + if (ie) { + data->flags = 1; + data->length = ie[1]; + memcpy(ssid, ie + 2, data->length); + } + } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { data->flags = 1; data->length = wdev->wext.connect.ssid_len; memcpy(ssid, wdev->wext.connect.ssid, data->length); -- cgit v0.10.2 From bb7e43c061ad1e52a4738d5b45595ec9e1638b6a Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:27 +0100 Subject: orinoco: prefer_port3 can be a single bit This is a boolean value set based on firmware capabilities, so move the variable to the capabilities section and reduce the structure size. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 5f4f5c9..2a4eef1 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -107,10 +107,10 @@ struct orinoco_private { unsigned int do_fw_download:1; unsigned int broken_disableport:1; unsigned int broken_monitor:1; + unsigned int prefer_port3:1; /* Configuration paramaters */ enum nl80211_iftype iw_mode; - int prefer_port3; u16 encode_alg, wep_restrict, tx_key; struct orinoco_key keys[ORINOCO_MAX_KEYS]; int bitratemode; -- cgit v0.10.2 From 5c9f41e285ad60013f0962746192769f899757be Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:28 +0100 Subject: orinoco: use local types for auth alg and sequence length This helps in the refactorring required to convert the driver to cfg80211. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index fa508af..d069fe8 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -642,7 +642,7 @@ int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc) { hermes_t *hw = &priv->hw; int err = 0; - u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE]; + u8 tsc_arr[4][ORINOCO_SEQ_LEN]; if ((key < 0) || (key > 4)) return -EINVAL; @@ -840,14 +840,14 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) if (priv->wpa_enabled) enc_flag = 2; - else if (priv->encode_alg == IW_ENCODE_ALG_WEP) + else if (priv->encode_alg == ORINOCO_ALG_WEP) enc_flag = 1; else enc_flag = 0; switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ - if (priv->encode_alg == IW_ENCODE_ALG_WEP) { + if (priv->encode_alg == ORINOCO_ALG_WEP) { /* Enable the shared-key authentication. */ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFAUTHENTICATION_AGERE, @@ -872,7 +872,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - if (priv->encode_alg == IW_ENCODE_ALG_WEP) { + if (priv->encode_alg == ORINOCO_ALG_WEP) { if (priv->wep_restrict || (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | @@ -913,11 +913,11 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, { struct { __le16 idx; - u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; + u8 rsc[ORINOCO_SEQ_LEN]; u8 key[TKIP_KEYLEN]; u8 tx_mic[MIC_KEYLEN]; u8 rx_mic[MIC_KEYLEN]; - u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; + u8 tsc[ORINOCO_SEQ_LEN]; } __attribute__ ((packed)) buf; hermes_t *hw = &priv->hw; int ret; diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index e8c550a..931f7de 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -380,7 +380,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - if (priv->encode_alg == IW_ENCODE_ALG_TKIP) + if (priv->encode_alg == ORINOCO_ALG_TKIP) tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | HERMES_TXCTRL_MIC; @@ -462,7 +462,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) } /* Calculate Michael MIC */ - if (priv->encode_alg == IW_ENCODE_ALG_TKIP) { + if (priv->encode_alg == ORINOCO_ALG_TKIP) { u8 mic_buf[MICHAEL_MIC_LEN + 1]; u8 *mic; size_t offset; @@ -2040,7 +2040,7 @@ int orinoco_init(struct orinoco_private *priv) priv->channel = 0; /* use firmware default */ priv->promiscuous = 0; - priv->encode_alg = IW_ENCODE_ALG_NONE; + priv->encode_alg = ORINOCO_ALG_NONE; priv->tx_key = 0; priv->wpa_enabled = 0; priv->tkip_cm_active = 0; diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 2a4eef1..badfc56 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -25,6 +25,7 @@ #define MAX_SCAN_LEN 4096 +#define ORINOCO_SEQ_LEN 8 #define ORINOCO_MAX_KEY_SIZE 14 #define ORINOCO_MAX_KEYS 4 @@ -42,6 +43,12 @@ struct orinoco_tkip_key { u8 rx_mic[MIC_KEYLEN]; }; +enum orinoco_alg { + ORINOCO_ALG_NONE, + ORINOCO_ALG_WEP, + ORINOCO_ALG_TKIP +}; + typedef enum { FIRMWARE_TYPE_AGERE, FIRMWARE_TYPE_INTERSIL, @@ -111,7 +118,8 @@ struct orinoco_private { /* Configuration paramaters */ enum nl80211_iftype iw_mode; - u16 encode_alg, wep_restrict, tx_key; + enum orinoco_alg encode_alg; + u16 wep_restrict, tx_key; struct orinoco_key keys[ORINOCO_MAX_KEYS]; int bitratemode; char nick[IW_ESSID_MAX_SIZE+1]; diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index b6ff3db..33d81b4 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -180,7 +180,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct orinoco_private *priv = ndev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; int setindex = priv->tx_key; - int encode_alg = priv->encode_alg; + enum orinoco_alg encode_alg = priv->encode_alg; int restricted = priv->wep_restrict; u16 xlen = 0; int err = -EINPROGRESS; /* Call commit handler */ @@ -202,7 +202,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, return -EBUSY; /* Clear any TKIP key we have */ - if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP)) + if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP)) (void) orinoco_clear_tkip_key(priv, setindex); if (erq->length > 0) { @@ -212,15 +212,13 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, /* Adjust key length to a supported value */ if (erq->length > SMALL_KEY_SIZE) xlen = LARGE_KEY_SIZE; - else if (erq->length > 0) + else /* (erq->length > 0) */ xlen = SMALL_KEY_SIZE; - else - xlen = 0; /* Switch on WEP if off */ - if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) { + if (encode_alg != ORINOCO_ALG_WEP) { setindex = index; - encode_alg = IW_ENCODE_ALG_WEP; + encode_alg = ORINOCO_ALG_WEP; } } else { /* Important note : if the user do "iwconfig eth0 enc off", @@ -242,7 +240,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, } if (erq->flags & IW_ENCODE_DISABLED) - encode_alg = IW_ENCODE_ALG_NONE; + encode_alg = ORINOCO_ALG_NONE; if (erq->flags & IW_ENCODE_OPEN) restricted = 0; if (erq->flags & IW_ENCODE_RESTRICTED) @@ -825,7 +823,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, /* Set the requested key first */ switch (alg) { case IW_ENCODE_ALG_NONE: - priv->encode_alg = alg; + priv->encode_alg = ORINOCO_ALG_NONE; priv->keys[idx].len = 0; break; @@ -837,7 +835,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, else goto out; - priv->encode_alg = alg; + priv->encode_alg = ORINOCO_ALG_WEP; priv->keys[idx].len = cpu_to_le16(key_len); key_len = min(ext->key_len, key_len); @@ -854,7 +852,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, (ext->key_len > sizeof(priv->tkip_key[0]))) goto out; - priv->encode_alg = alg; + priv->encode_alg = ORINOCO_ALG_TKIP; memset(&priv->tkip_key[idx], 0, sizeof(priv->tkip_key[idx])); memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); @@ -914,19 +912,21 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, encoding->flags = idx + 1; memset(ext, 0, sizeof(*ext)); - ext->alg = priv->encode_alg; switch (priv->encode_alg) { - case IW_ENCODE_ALG_NONE: + case ORINOCO_ALG_NONE: + ext->alg = IW_ENCODE_ALG_NONE; ext->key_len = 0; encoding->flags |= IW_ENCODE_DISABLED; break; - case IW_ENCODE_ALG_WEP: + case ORINOCO_ALG_WEP: + ext->alg = IW_ENCODE_ALG_WEP; ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), max_key_len); memcpy(ext->key, priv->keys[idx].data, ext->key_len); encoding->flags |= IW_ENCODE_ENABLED; break; - case IW_ENCODE_ALG_TKIP: + case ORINOCO_ALG_TKIP: + ext->alg = IW_ENCODE_ALG_TKIP; ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), max_key_len); memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); -- cgit v0.10.2 From 16e158480d542f3909b5aca8b125af986ae128c1 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:29 +0100 Subject: orinoco: pass orinoco_set_tkip_key the sequence lengths When we store the keys for cfg80211, the sequence lengths will also be stored. So avoid assuming the sequence lengths at this level. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index d069fe8..35516a9 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -905,11 +905,12 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) } /* key must be 32 bytes, including the tx and rx MIC keys. - * rsc must be 8 bytes - * tsc must be 8 bytes or NULL + * rsc must be NULL or up to 8 bytes + * tsc must be NULL or up to 8 bytes */ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, u8 *key, u8 *rsc, u8 *tsc) + int set_tx, u8 *key, u8 *rsc, size_t rsc_len, + u8 *tsc, size_t tsc_len) { struct { __le16 idx; @@ -934,17 +935,22 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, memcpy(buf.key, key, sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); - if (rsc == NULL) - memset(buf.rsc, 0, sizeof(buf.rsc)); - else - memcpy(buf.rsc, rsc, sizeof(buf.rsc)); + if (rsc_len > sizeof(buf.rsc)) + rsc_len = sizeof(buf.rsc); + + if (tsc_len > sizeof(buf.tsc)) + tsc_len = sizeof(buf.tsc); + + memset(buf.rsc, 0, sizeof(buf.rsc)); + memset(buf.tsc, 0, sizeof(buf.tsc)); + + if (rsc != NULL) + memcpy(buf.rsc, rsc, rsc_len); - if (tsc == NULL) { - memset(buf.tsc, 0, sizeof(buf.tsc)); + if (tsc != NULL) + memcpy(buf.tsc, tsc, tsc_len); + else buf.tsc[4] = 0x10; - } else { - memcpy(buf.tsc, tsc, sizeof(buf.tsc)); - } /* Wait upto 100ms for tx queue to empty */ for (k = 100; k > 0; k--) { diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 27b4276..33a31fa 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -38,7 +38,8 @@ int __orinoco_hw_set_wap(struct orinoco_private *priv); int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); int __orinoco_hw_setup_enc(struct orinoco_private *priv); int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, u8 *key, u8 *rsc, u8 *tsc); + int set_tx, u8 *key, u8 *rsc, size_t rsc_len, + u8 *tsc, size_t tsc_len); int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, struct dev_addr_list *mc_list, diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 33d81b4..7e18bb4 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -863,7 +863,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, err = __orinoco_hw_set_tkip_key(priv, idx, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, (u8 *) &priv->tkip_key[idx], - tkip_iv, NULL); + tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); if (err) printk(KERN_ERR "%s: Error %d setting TKIP key" "\n", dev->name, err); -- cgit v0.10.2 From 07542d08ee573b6d8281f38430117b52fccaf50a Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:30 +0100 Subject: orinoco: move disassociation to hw.c This allows the disassociation to be called via cfg80211. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 35516a9..3e9021c 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -1248,3 +1248,27 @@ int orinoco_hw_trigger_scan(struct orinoco_private *priv, return err; } + +/* Disassociate from node with BSSID addr */ +int orinoco_hw_disassociate(struct orinoco_private *priv, + u8 *addr, u16 reason_code) +{ + hermes_t *hw = &priv->hw; + int err; + + struct { + u8 addr[ETH_ALEN]; + __le16 reason_code; + } __attribute__ ((packed)) buf; + + /* Currently only supported by WPA enabled Agere fw */ + if (!priv->has_wpa) + return -EOPNOTSUPP; + + memcpy(buf.addr, addr, ETH_ALEN); + buf.reason_code = cpu_to_le16(reason_code); + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFDISASSOCIATE, + &buf); + return err; +} diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 33a31fa..b096786 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -51,5 +51,7 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, s32 *rates, int max); int orinoco_hw_trigger_scan(struct orinoco_private *priv, const struct cfg80211_ssid *ssid); +int orinoco_hw_disassociate(struct orinoco_private *priv, + u8 *addr, u16 reason_code); #endif /* _ORINOCO_HW_H_ */ diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 7e18bb4..f324bf9 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -1136,7 +1136,6 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct orinoco_private *priv = ndev_priv(dev); - hermes_t *hw = &priv->hw; struct iw_mlme *mlme = (struct iw_mlme *)extra; unsigned long flags; int ret = 0; @@ -1150,19 +1149,11 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev, break; case IW_MLME_DISASSOC: - { - struct { - u8 addr[ETH_ALEN]; - __le16 reason_code; - } __attribute__ ((packed)) buf; - - memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN); - buf.reason_code = cpu_to_le16(mlme->reason_code); - ret = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFDISASSOCIATE, - &buf); + + ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data, + mlme->reason_code); break; - } + default: ret = -EOPNOTSUPP; } -- cgit v0.10.2 From 2b2603515e26466685895e93cae59bc061389f11 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:31 +0100 Subject: orinoco: add function to retrieve current bssid We will need this from the cfg80211 disassociate call. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 3e9021c..5b12654 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -1272,3 +1272,15 @@ int orinoco_hw_disassociate(struct orinoco_private *priv, &buf); return err; } + +int orinoco_hw_get_current_bssid(struct orinoco_private *priv, + u8 *addr) +{ + hermes_t *hw = &priv->hw; + int err; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, + ETH_ALEN, NULL, addr); + + return err; +} diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index b096786..8df6e87 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -53,5 +53,7 @@ int orinoco_hw_trigger_scan(struct orinoco_private *priv, const struct cfg80211_ssid *ssid); int orinoco_hw_disassociate(struct orinoco_private *priv, u8 *addr, u16 reason_code); +int orinoco_hw_get_current_bssid(struct orinoco_private *priv, + u8 *addr); #endif /* _ORINOCO_HW_H_ */ diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index f324bf9..f68bbe3 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -156,7 +156,6 @@ static int orinoco_ioctl_getwap(struct net_device *dev, { struct orinoco_private *priv = ndev_priv(dev); - hermes_t *hw = &priv->hw; int err = 0; unsigned long flags; @@ -164,8 +163,7 @@ static int orinoco_ioctl_getwap(struct net_device *dev, return -EBUSY; ap_addr->sa_family = ARPHRD_ETHER; - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, ap_addr->sa_data); + err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data); orinoco_unlock(priv, &flags); -- cgit v0.10.2 From 4af198fb7a99b07980b1bd52df550ba3f24688df Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:32 +0100 Subject: orinoco: consolidate storage of WEP and TKIP keys When TKIP support was added, we stored the keys separately to avoid issues when both TKIP and WEP keys are sent to the driver. We need to consolidate the storage to convert to cfg80211, so do this first and try iron out the issues. Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 5b12654..40d8dfa 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -768,12 +768,29 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; int err = 0; + int i; switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: + { + struct orinoco_key keys[ORINOCO_MAX_KEYS]; + + memset(&keys, 0, sizeof(keys)); + for (i = 0; i < ORINOCO_MAX_KEYS; i++) { + int len = min(priv->keys[i].key_len, + ORINOCO_MAX_KEY_SIZE); + memcpy(&keys[i].data, priv->keys[i].key, len); + if (len > SMALL_KEY_SIZE) + keys[i].len = cpu_to_le16(LARGE_KEY_SIZE); + else if (len > 0) + keys[i].len = cpu_to_le16(SMALL_KEY_SIZE); + else + keys[i].len = cpu_to_le16(0); + } + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFWEPKEYS_AGERE, - &priv->keys); + &keys); if (err) return err; err = hermes_write_wordrec(hw, USER_BAP, @@ -782,28 +799,38 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) if (err) return err; break; + } case FIRMWARE_TYPE_INTERSIL: case FIRMWARE_TYPE_SYMBOL: { int keylen; - int i; /* Force uniform key length to work around * firmware bugs */ - keylen = le16_to_cpu(priv->keys[priv->tx_key].len); + keylen = priv->keys[priv->tx_key].key_len; if (keylen > LARGE_KEY_SIZE) { printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", priv->ndev->name, priv->tx_key, keylen); return -E2BIG; - } + } else if (keylen > SMALL_KEY_SIZE) + keylen = LARGE_KEY_SIZE; + else if (keylen > 0) + keylen = SMALL_KEY_SIZE; + else + keylen = 0; /* Write all 4 keys */ for (i = 0; i < ORINOCO_MAX_KEYS; i++) { + u8 key[LARGE_KEY_SIZE] = { 0 }; + + memcpy(key, priv->keys[i].key, + priv->keys[i].key_len); + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDEFAULTKEY0 + i, HERMES_BYTES_TO_RECLEN(keylen), - priv->keys[i].data); + key); if (err) return err; } @@ -829,8 +856,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) int auth_flag; int enc_flag; - /* Setup WEP keys for WEP and WPA */ - if (priv->encode_alg) + /* Setup WEP keys */ + if (priv->encode_alg == ORINOCO_ALG_WEP) __orinoco_hw_setup_wepkeys(priv); if (priv->wep_restrict) @@ -976,7 +1003,6 @@ int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx) hermes_t *hw = &priv->hw; int err; - memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx])); err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, key_idx); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 931f7de..2c7dc65 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -341,12 +341,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; + struct orinoco_tkip_key *key; hermes_t *hw = &priv->hw; int err = 0; u16 txfid = priv->txfid; struct ethhdr *eh; int tx_control; unsigned long flags; + int do_mic; if (!netif_running(dev)) { printk(KERN_ERR "%s: Tx on stopped device!\n", @@ -378,9 +380,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < ETH_HLEN) goto drop; + key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key; + + do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) && + (key != NULL)); + tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - if (priv->encode_alg == ORINOCO_ALG_TKIP) + if (do_mic) tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | HERMES_TXCTRL_MIC; @@ -462,7 +469,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) } /* Calculate Michael MIC */ - if (priv->encode_alg == ORINOCO_ALG_TKIP) { + if (do_mic) { u8 mic_buf[MICHAEL_MIC_LEN + 1]; u8 *mic; size_t offset; @@ -480,8 +487,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) len = MICHAEL_MIC_LEN; } - orinoco_mic(priv->tx_tfm_mic, - priv->tkip_key[priv->tx_key].tx_mic, + orinoco_mic(priv->tx_tfm_mic, key->tx_mic, eh->h_dest, eh->h_source, 0 /* priority */, skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic); @@ -926,6 +932,7 @@ static void orinoco_rx(struct net_device *dev, /* Calculate and check MIC */ if (status & HERMES_RXSTAT_MIC) { + struct orinoco_tkip_key *key; int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> HERMES_MIC_KEY_ID_SHIFT); u8 mic[MICHAEL_MIC_LEN]; @@ -939,14 +946,18 @@ static void orinoco_rx(struct net_device *dev, skb_trim(skb, skb->len - MICHAEL_MIC_LEN); length -= MICHAEL_MIC_LEN; - orinoco_mic(priv->rx_tfm_mic, - priv->tkip_key[key_id].rx_mic, - desc->addr1, - src, + key = (struct orinoco_tkip_key *) priv->keys[key_id].key; + + if (!key) { + printk(KERN_WARNING "%s: Received encrypted frame from " + "%pM using key %i, but key is not installed\n", + dev->name, src, key_id); + goto drop; + } + + orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src, 0, /* priority or QoS? */ - skb->data, - skb->len, - &mic[0]); + skb->data, skb->len, &mic[0]); if (memcmp(mic, rxmic, MICHAEL_MIC_LEN)) { diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index badfc56..9ac6f1d 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -120,7 +120,8 @@ struct orinoco_private { enum nl80211_iftype iw_mode; enum orinoco_alg encode_alg; u16 wep_restrict, tx_key; - struct orinoco_key keys[ORINOCO_MAX_KEYS]; + struct key_params keys[ORINOCO_MAX_KEYS]; + int bitratemode; char nick[IW_ESSID_MAX_SIZE+1]; char desired_essid[IW_ESSID_MAX_SIZE+1]; @@ -150,7 +151,6 @@ struct orinoco_private { u8 *wpa_ie; int wpa_ie_len; - struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS]; struct crypto_hash *rx_tfm_mic; struct crypto_hash *tx_tfm_mic; diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index f68bbe3..3e56f76 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -22,6 +22,67 @@ #define MAX_RID_LEN 1024 +/* Helper routine to record keys + * Do not call from interrupt context */ +static int orinoco_set_key(struct orinoco_private *priv, int index, + enum orinoco_alg alg, const u8 *key, int key_len, + const u8 *seq, int seq_len) +{ + kzfree(priv->keys[index].key); + kzfree(priv->keys[index].seq); + + if (key_len) { + priv->keys[index].key = kzalloc(key_len, GFP_KERNEL); + if (!priv->keys[index].key) + goto nomem; + } else + priv->keys[index].key = NULL; + + if (seq_len) { + priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL); + if (!priv->keys[index].seq) + goto free_key; + } else + priv->keys[index].seq = NULL; + + priv->keys[index].key_len = key_len; + priv->keys[index].seq_len = seq_len; + + if (key_len) + memcpy(priv->keys[index].key, key, key_len); + if (seq_len) + memcpy(priv->keys[index].seq, seq, seq_len); + + switch (alg) { + case ORINOCO_ALG_TKIP: + priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP; + break; + + case ORINOCO_ALG_WEP: + priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ? + WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40; + break; + + case ORINOCO_ALG_NONE: + default: + priv->keys[index].cipher = 0; + break; + } + + return 0; + +free_key: + kfree(priv->keys[index].key); + priv->keys[index].key = NULL; + +nomem: + priv->keys[index].key_len = 0; + priv->keys[index].seq_len = 0; + priv->keys[index].cipher = 0; + + return -ENOMEM; +} + static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) { struct orinoco_private *priv = ndev_priv(dev); @@ -180,7 +241,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, int setindex = priv->tx_key; enum orinoco_alg encode_alg = priv->encode_alg; int restricted = priv->wep_restrict; - u16 xlen = 0; int err = -EINPROGRESS; /* Call commit handler */ unsigned long flags; @@ -207,12 +267,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; - /* Adjust key length to a supported value */ - if (erq->length > SMALL_KEY_SIZE) - xlen = LARGE_KEY_SIZE; - else /* (erq->length > 0) */ - xlen = SMALL_KEY_SIZE; - /* Switch on WEP if off */ if (encode_alg != ORINOCO_ALG_WEP) { setindex = index; @@ -229,7 +283,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, } } else { /* Set the index : Check that the key is valid */ - if (priv->keys[index].len == 0) { + if (priv->keys[index].key_len == 0) { err = -EINVAL; goto out; } @@ -245,10 +299,8 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, restricted = 1; if (erq->pointer && erq->length > 0) { - priv->keys[index].len = cpu_to_le16(xlen); - memset(priv->keys[index].data, 0, - sizeof(priv->keys[index].data)); - memcpy(priv->keys[index].data, keybuf, erq->length); + err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf, + erq->length, NULL, 0); } priv->tx_key = setindex; @@ -277,7 +329,6 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, { struct orinoco_private *priv = ndev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; - u16 xlen = 0; unsigned long flags; if (!priv->has_wep) @@ -299,11 +350,9 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, else erq->flags |= IW_ENCODE_OPEN; - xlen = le16_to_cpu(priv->keys[index].len); + erq->length = priv->keys[index].key_len; - erq->length = xlen; - - memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); + memcpy(keybuf, priv->keys[index].key, erq->length); orinoco_unlock(priv, &flags); return 0; @@ -789,7 +838,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, int idx, alg = ext->alg, set_key = 1; unsigned long flags; int err = -EINVAL; - u16 key_len; if (orinoco_lock(priv, &flags) != 0) return -EBUSY; @@ -822,24 +870,17 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, switch (alg) { case IW_ENCODE_ALG_NONE: priv->encode_alg = ORINOCO_ALG_NONE; - priv->keys[idx].len = 0; + err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE, + NULL, 0, NULL, 0); break; case IW_ENCODE_ALG_WEP: - if (ext->key_len > SMALL_KEY_SIZE) - key_len = LARGE_KEY_SIZE; - else if (ext->key_len > 0) - key_len = SMALL_KEY_SIZE; - else + if (ext->key_len <= 0) goto out; priv->encode_alg = ORINOCO_ALG_WEP; - priv->keys[idx].len = cpu_to_le16(key_len); - - key_len = min(ext->key_len, key_len); - - memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE); - memcpy(priv->keys[idx].data, ext->key, key_len); + err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP, + ext->key, ext->key_len, NULL, 0); break; case IW_ENCODE_ALG_TKIP: @@ -847,20 +888,21 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, u8 *tkip_iv = NULL; if (!priv->has_wpa || - (ext->key_len > sizeof(priv->tkip_key[0]))) + (ext->key_len > sizeof(struct orinoco_tkip_key))) goto out; priv->encode_alg = ORINOCO_ALG_TKIP; - memset(&priv->tkip_key[idx], 0, - sizeof(priv->tkip_key[idx])); - memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) tkip_iv = &ext->rx_seq[0]; + err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP, + ext->key, ext->key_len, tkip_iv, + ORINOCO_SEQ_LEN); + err = __orinoco_hw_set_tkip_key(priv, idx, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, - (u8 *) &priv->tkip_key[idx], + priv->keys[idx].key, tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); if (err) printk(KERN_ERR "%s: Error %d setting TKIP key" @@ -918,16 +960,14 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, break; case ORINOCO_ALG_WEP: ext->alg = IW_ENCODE_ALG_WEP; - ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), - max_key_len); - memcpy(ext->key, priv->keys[idx].data, ext->key_len); + ext->key_len = min(priv->keys[idx].key_len, max_key_len); + memcpy(ext->key, priv->keys[idx].key, ext->key_len); encoding->flags |= IW_ENCODE_ENABLED; break; case ORINOCO_ALG_TKIP: ext->alg = IW_ENCODE_ALG_TKIP; - ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), - max_key_len); - memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); + ext->key_len = min(priv->keys[idx].key_len, max_key_len); + memcpy(ext->key, priv->keys[idx].key, ext->key_len); encoding->flags |= IW_ENCODE_ENABLED; break; } -- cgit v0.10.2 From b935df01ed4f0848f29b1e39c4f95d87b0206dea Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Thu, 6 Aug 2009 04:52:42 -0400 Subject: cfg80211: fix disassociation warning due to misuse of wdev->current_bss WARN_ON was triggered at mlme.c:213 when dissociating from an AP. wdev->current_bss->pub.bssid should be used in place of wdev->current_bss for BSSID comparison. Signed-off-by: Pavel Roskin Reviewed-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 525e8e2..b44b6c0 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -198,7 +198,7 @@ static void __cfg80211_send_disassoc(struct net_device *dev, return; if (wdev->current_bss && - memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) { + memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { for (i = 0; i < MAX_AUTH_BSSES; i++) { if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) continue; -- cgit v0.10.2 From f5fc0f86b02afef1119b523623b4cde41475bc8c Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 6 Aug 2009 16:25:28 +0300 Subject: wl1271: add wl1271 driver files This driver supports the wl1271 chipset from Texas Instruments based on the WiLink(tm) 6.0 mobile platform. Support for wl1273 should be relatively easy to add. This chipset is designed for embedded devices, with good powersaving capabilities. The wl1271 chipset is the successor of wl1251 and supports the 802.11b/g/n standards, but currently this driver supports only b/g. More information about this chipset can be found here: http://focus.ti.com/general/docs/wtbu/wtbuproductcontent.tsp?templateId=6123&navigationId=12762&contentId=29993 Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h new file mode 100644 index 0000000..55818f9 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -0,0 +1,407 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_H__ +#define __WL1271_H__ + +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "wl1271" +#define DRIVER_PREFIX DRIVER_NAME ": " + +enum { + DEBUG_NONE = 0, + DEBUG_IRQ = BIT(0), + DEBUG_SPI = BIT(1), + DEBUG_BOOT = BIT(2), + DEBUG_MAILBOX = BIT(3), + DEBUG_NETLINK = BIT(4), + DEBUG_EVENT = BIT(5), + DEBUG_TX = BIT(6), + DEBUG_RX = BIT(7), + DEBUG_SCAN = BIT(8), + DEBUG_CRYPT = BIT(9), + DEBUG_PSM = BIT(10), + DEBUG_MAC80211 = BIT(11), + DEBUG_CMD = BIT(12), + DEBUG_ACX = BIT(13), + DEBUG_ALL = ~0, +}; + +#define DEBUG_LEVEL (DEBUG_NONE) + +#define DEBUG_DUMP_LIMIT 1024 + +#define wl1271_error(fmt, arg...) \ + printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) + +#define wl1271_warning(fmt, arg...) \ + printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) + +#define wl1271_notice(fmt, arg...) \ + printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1271_info(fmt, arg...) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1271_debug(level, fmt, arg...) \ + do { \ + if (level & DEBUG_LEVEL) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) + +#define wl1271_dump(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + 0); \ + } while (0) + +#define wl1271_dump_ascii(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + true); \ + } while (0) + +#define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ + CFG_BSSID_FILTER_EN) + +#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \ + CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ + CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ + CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) + +#define WL1271_FW_NAME "wl1271-fw.bin" +#define WL1271_NVS_NAME "wl1271-nvs.bin" + +#define WL1271_BUSY_WORD_LEN 8 + +#define WL1271_ELP_HW_STATE_ASLEEP 0 +#define WL1271_ELP_HW_STATE_IRQ 1 + +enum wl1271_state { + WL1271_STATE_OFF, + WL1271_STATE_ON, + WL1271_STATE_PLT, +}; + +enum wl1271_partition_type { + PART_DOWN, + PART_WORK, + PART_DRPW, + + PART_TABLE_LEN +}; + +struct wl1271_partition { + u32 size; + u32 start; +}; + +struct wl1271_partition_set { + struct wl1271_partition mem; + struct wl1271_partition reg; +}; + +struct wl1271; + +/* FIXME: I'm not sure about this structure name */ +struct wl1271_chip { + u32 id; + char fw_ver[21]; +}; + +struct wl1271_stats { + struct acx_statistics *fw_stats; + unsigned long fw_stats_update; + + unsigned int retry_count; + unsigned int excessive_retries; +}; + +struct wl1271_debugfs { + struct dentry *rootdir; + struct dentry *fw_statistics; + + struct dentry *tx_internal_desc_overflow; + + struct dentry *rx_out_of_mem; + struct dentry *rx_hdr_overflow; + struct dentry *rx_hw_stuck; + struct dentry *rx_dropped; + struct dentry *rx_fcs_err; + struct dentry *rx_xfr_hint_trig; + struct dentry *rx_path_reset; + struct dentry *rx_reset_counter; + + struct dentry *dma_rx_requested; + struct dentry *dma_rx_errors; + struct dentry *dma_tx_requested; + struct dentry *dma_tx_errors; + + struct dentry *isr_cmd_cmplt; + struct dentry *isr_fiqs; + struct dentry *isr_rx_headers; + struct dentry *isr_rx_mem_overflow; + struct dentry *isr_rx_rdys; + struct dentry *isr_irqs; + struct dentry *isr_tx_procs; + struct dentry *isr_decrypt_done; + struct dentry *isr_dma0_done; + struct dentry *isr_dma1_done; + struct dentry *isr_tx_exch_complete; + struct dentry *isr_commands; + struct dentry *isr_rx_procs; + struct dentry *isr_hw_pm_mode_changes; + struct dentry *isr_host_acknowledges; + struct dentry *isr_pci_pm; + struct dentry *isr_wakeups; + struct dentry *isr_low_rssi; + + struct dentry *wep_addr_key_count; + struct dentry *wep_default_key_count; + /* skipping wep.reserved */ + struct dentry *wep_key_not_found; + struct dentry *wep_decrypt_fail; + struct dentry *wep_packets; + struct dentry *wep_interrupt; + + struct dentry *pwr_ps_enter; + struct dentry *pwr_elp_enter; + struct dentry *pwr_missing_bcns; + struct dentry *pwr_wake_on_host; + struct dentry *pwr_wake_on_timer_exp; + struct dentry *pwr_tx_with_ps; + struct dentry *pwr_tx_without_ps; + struct dentry *pwr_rcvd_beacons; + struct dentry *pwr_power_save_off; + struct dentry *pwr_enable_ps; + struct dentry *pwr_disable_ps; + struct dentry *pwr_fix_tsf_ps; + /* skipping cont_miss_bcns_spread for now */ + struct dentry *pwr_rcvd_awake_beacons; + + struct dentry *mic_rx_pkts; + struct dentry *mic_calc_failure; + + struct dentry *aes_encrypt_fail; + struct dentry *aes_decrypt_fail; + struct dentry *aes_encrypt_packets; + struct dentry *aes_decrypt_packets; + struct dentry *aes_encrypt_interrupt; + struct dentry *aes_decrypt_interrupt; + + struct dentry *event_heart_beat; + struct dentry *event_calibration; + struct dentry *event_rx_mismatch; + struct dentry *event_rx_mem_empty; + struct dentry *event_rx_pool; + struct dentry *event_oom_late; + struct dentry *event_phy_transmit_error; + struct dentry *event_tx_stuck; + + struct dentry *ps_pspoll_timeouts; + struct dentry *ps_upsd_timeouts; + struct dentry *ps_upsd_max_sptime; + struct dentry *ps_upsd_max_apturn; + struct dentry *ps_pspoll_max_apturn; + struct dentry *ps_pspoll_utilization; + struct dentry *ps_upsd_utilization; + + struct dentry *rxpipe_rx_prep_beacon_drop; + struct dentry *rxpipe_descr_host_int_trig_rx_data; + struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; + struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; + struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; + + struct dentry *tx_queue_len; + + struct dentry *retry_count; + struct dentry *excessive_retries; +}; + +#define NUM_TX_QUEUES 4 +#define NUM_RX_PKT_DESC 8 + +/* FW status registers */ +struct wl1271_fw_status { + u32 intr; + u8 fw_rx_counter; + u8 drv_rx_counter; + u8 reserved; + u8 tx_results_counter; + u32 rx_pkt_descs[NUM_RX_PKT_DESC]; + u32 tx_released_blks[NUM_TX_QUEUES]; + u32 fw_localtime; + u32 padding[2]; +} __attribute__ ((packed)); + +struct wl1271_rx_mem_pool_addr { + u32 addr; + u32 addr_extra; +}; + +struct wl1271 { + struct ieee80211_hw *hw; + bool mac80211_registered; + + struct spi_device *spi; + + void (*set_power)(bool enable); + int irq; + + spinlock_t wl_lock; + + enum wl1271_state state; + struct mutex mutex; + + int physical_mem_addr; + int physical_reg_addr; + int virtual_mem_addr; + int virtual_reg_addr; + + struct wl1271_chip chip; + + int cmd_box_addr; + int event_box_addr; + + u8 *fw; + size_t fw_len; + u8 *nvs; + size_t nvs_len; + + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; + u8 bss_type; + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + u8 listen_int; + int channel; + + struct wl1271_acx_mem_map *target_mem_map; + + /* Accounting for allocated / available TX blocks on HW */ + u32 tx_blocks_freed[NUM_TX_QUEUES]; + u32 tx_blocks_available; + u8 tx_results_count; + + /* Transmitted TX packets counter for chipset interface */ + int tx_packets_count; + + /* Time-offset between host and chipset clocks */ + int time_offset; + + /* Session counter for the chipset */ + int session_counter; + + /* Frames scheduled for transmission, not handled yet */ + struct sk_buff_head tx_queue; + bool tx_queue_stopped; + + struct work_struct tx_work; + struct work_struct filter_work; + + /* Pending TX frames */ + struct sk_buff *tx_frames[16]; + + /* FW Rx counter */ + u32 rx_counter; + + /* Rx memory pool address */ + struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; + + /* The target interrupt mask */ + struct work_struct irq_work; + + /* The mbox event mask */ + u32 event_mask; + + /* Mailbox pointers */ + u32 mbox_ptr[2]; + + /* Are we currently scanning */ + bool scanning; + + /* Our association ID */ + u16 aid; + + /* Default key (for WEP) */ + u32 default_key; + + unsigned int rx_config; + unsigned int rx_filter; + + /* is firmware in elp mode */ + bool elp; + + struct completion *elp_compl; + + /* we can be in psm, but not in elp, we have to differentiate */ + bool psm; + + /* PSM mode requested */ + bool psm_requested; + + /* in dBm */ + int power_level; + + struct wl1271_stats stats; + struct wl1271_debugfs debugfs; + + u32 buffer_32; + u32 buffer_cmd; + u8 buffer_busyword[WL1271_BUSY_WORD_LEN]; + struct wl1271_rx_descriptor *rx_descriptor; + + struct wl1271_fw_status *fw_status; + struct wl1271_tx_hw_res_if *tx_res_if; +}; + +int wl1271_plt_start(struct wl1271 *wl); +int wl1271_plt_stop(struct wl1271 *wl); + +#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ + +#define SESSION_COUNTER_MAX 7 /* maximum value for the session counter */ + +#define WL1271_DEFAULT_POWER_LEVEL 0 + +#define WL1271_TX_QUEUE_MAX_LENGTH 20 + +/* WL1271 needs a 200ms sleep after power on */ +#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c new file mode 100644 index 0000000..f622a40 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -0,0 +1,961 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1271_acx.h" + +#include +#include +#include +#include + +#include "wl1271.h" +#include "wl12xx_80211.h" +#include "wl1271_reg.h" +#include "wl1271_spi.h" +#include "wl1271_ps.h" + +int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event, + u8 listen_interval) +{ + struct acx_wake_up_condition *wake_up; + int ret; + + wl1271_debug(DEBUG_ACX, "acx wake up conditions"); + + wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); + if (!wake_up) { + ret = -ENOMEM; + goto out; + } + + wake_up->wake_up_event = wake_up_event; + wake_up->listen_interval = listen_interval; + + ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, + wake_up, sizeof(*wake_up)); + if (ret < 0) { + wl1271_warning("could not set wake up conditions: %d", ret); + goto out; + } + +out: + kfree(wake_up); + return ret; +} + +int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) +{ + struct acx_sleep_auth *auth; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sleep auth"); + + auth = kzalloc(sizeof(*auth), GFP_KERNEL); + if (!auth) { + ret = -ENOMEM; + goto out; + } + + auth->sleep_auth = sleep_auth; + + ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); + if (ret < 0) + return ret; + +out: + kfree(auth); + return ret; +} + +int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len) +{ + struct acx_revision *rev; + int ret; + + wl1271_debug(DEBUG_ACX, "acx fw rev"); + + rev = kzalloc(sizeof(*rev), GFP_KERNEL); + if (!rev) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); + if (ret < 0) { + wl1271_warning("ACX_FW_REV interrogate failed"); + goto out; + } + + /* be careful with the buffer sizes */ + strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); + + /* + * if the firmware version string is exactly + * sizeof(rev->fw_version) long or fw_len is less than + * sizeof(rev->fw_version) it won't be null terminated + */ + buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; + +out: + kfree(rev); + return ret; +} + +int wl1271_acx_tx_power(struct wl1271 *wl, int power) +{ + struct acx_current_tx_power *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); + + if (power < 0 || power > 25) + return -EINVAL; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->current_tx_power = power * 10; + + ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("configure of tx power failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_feature_cfg(struct wl1271 *wl) +{ + struct acx_feature_config *feature; + int ret; + + wl1271_debug(DEBUG_ACX, "acx feature cfg"); + + feature = kzalloc(sizeof(*feature), GFP_KERNEL); + if (!feature) { + ret = -ENOMEM; + goto out; + } + + /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ + feature->data_flow_options = 0; + feature->options = 0; + + ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG, + feature, sizeof(*feature)); + if (ret < 0) { + wl1271_error("Couldnt set HW encryption"); + goto out; + } + +out: + kfree(feature); + return ret; +} + +int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, + size_t len) +{ + int ret; + + wl1271_debug(DEBUG_ACX, "acx mem map"); + + ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time) +{ + struct acx_rx_msdu_lifetime *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx rx msdu life time"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->lifetime = life_time; + ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set rx msdu life time: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter) +{ + struct acx_rx_config *rx_config; + int ret; + + wl1271_debug(DEBUG_ACX, "acx rx config"); + + rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); + if (!rx_config) { + ret = -ENOMEM; + goto out; + } + + rx_config->config_options = config; + rx_config->filter_options = filter; + + ret = wl1271_cmd_configure(wl, ACX_RX_CFG, + rx_config, sizeof(*rx_config)); + if (ret < 0) { + wl1271_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(rx_config); + return ret; +} + +int wl1271_acx_pd_threshold(struct wl1271 *wl) +{ + struct acx_packet_detection *pd; + int ret; + + wl1271_debug(DEBUG_ACX, "acx data pd threshold"); + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + ret = -ENOMEM; + goto out; + } + + /* FIXME: threshold value not set */ + + ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); + if (ret < 0) { + wl1271_warning("failed to set pd threshold: %d", ret); + goto out; + } + +out: + kfree(pd); + return 0; +} + +int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) +{ + struct acx_slot *slot; + int ret; + + wl1271_debug(DEBUG_ACX, "acx slot"); + + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + ret = -ENOMEM; + goto out; + } + + slot->wone_index = STATION_WONE_INDEX; + slot->slot_time = slot_time; + + ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); + if (ret < 0) { + wl1271_warning("failed to set slot time: %d", ret); + goto out; + } + +out: + kfree(slot); + return ret; +} + +int wl1271_acx_group_address_tbl(struct wl1271 *wl) +{ + struct acx_dot11_grp_addr_tbl *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx group address tbl"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* MAC filtering */ + acx->enabled = 0; + acx->num_groups = 0; + memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); + + ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set group addr table: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_service_period_timeout(struct wl1271 *wl) +{ + struct acx_rx_timeout *rx_timeout; + int ret; + + rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); + if (!rx_timeout) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_ACX, "acx service period timeout"); + + rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; + rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; + + ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, + rx_timeout, sizeof(*rx_timeout)); + if (ret < 0) { + wl1271_warning("failed to set service period timeout: %d", + ret); + goto out; + } + +out: + kfree(rx_timeout); + return ret; +} + +int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) +{ + struct acx_rts_threshold *rts; + int ret; + + wl1271_debug(DEBUG_ACX, "acx rts threshold"); + + rts = kzalloc(sizeof(*rts), GFP_KERNEL); + if (!rts) { + ret = -ENOMEM; + goto out; + } + + rts->threshold = rts_threshold; + + ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); + if (ret < 0) { + wl1271_warning("failed to set rts threshold: %d", ret); + goto out; + } + +out: + kfree(rts); + return ret; +} + +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl) +{ + struct acx_beacon_filter_option *beacon_filter; + int ret; + + wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); + + beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); + if (!beacon_filter) { + ret = -ENOMEM; + goto out; + } + + beacon_filter->enable = 0; + beacon_filter->max_num_beacons = 0; + + ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, + beacon_filter, sizeof(*beacon_filter)); + if (ret < 0) { + wl1271_warning("failed to set beacon filter opt: %d", ret); + goto out; + } + +out: + kfree(beacon_filter); + return ret; +} + +int wl1271_acx_beacon_filter_table(struct wl1271 *wl) +{ + struct acx_beacon_filter_ie_table *ie_table; + int ret; + + wl1271_debug(DEBUG_ACX, "acx beacon filter table"); + + ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); + if (!ie_table) { + ret = -ENOMEM; + goto out; + } + + ie_table->num_ie = 0; + memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); + + ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, + ie_table, sizeof(*ie_table)); + if (ret < 0) { + wl1271_warning("failed to set beacon filter table: %d", ret); + goto out; + } + +out: + kfree(ie_table); + return ret; +} + +int wl1271_acx_sg_enable(struct wl1271 *wl) +{ + struct acx_bt_wlan_coex *pta; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sg enable"); + + pta = kzalloc(sizeof(*pta), GFP_KERNEL); + if (!pta) { + ret = -ENOMEM; + goto out; + } + + pta->enable = SG_ENABLE; + + ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); + if (ret < 0) { + wl1271_warning("failed to set softgemini enable: %d", ret); + goto out; + } + +out: + kfree(pta); + return ret; +} + +int wl1271_acx_sg_cfg(struct wl1271 *wl) +{ + struct acx_bt_wlan_coex_param *param; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sg cfg"); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + + /* BT-WLAN coext parameters */ + param->min_rate = RATE_INDEX_24MBPS; + param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; + param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; + param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; + param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; + param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; + param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; + param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; + param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; + param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; + param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; + param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; + param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; + param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; + param->antenna_type = PTA_ANTENNA_TYPE_DEF; + param->signal_type = PTA_SIGNALING_TYPE_DEF; + param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; + param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; + param->max_cts = PTA_MAX_NUM_CTS_DEF; + param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; + param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; + param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; + param->wlan_elp_hp = PTA_ELP_HP_DEF; + param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; + param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; + param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; + param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; + param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; + + ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); + if (ret < 0) { + wl1271_warning("failed to set sg config: %d", ret); + goto out; + } + +out: + kfree(param); + return ret; +} + +int wl1271_acx_cca_threshold(struct wl1271 *wl) +{ + struct acx_energy_detection *detection; + int ret; + + wl1271_debug(DEBUG_ACX, "acx cca threshold"); + + detection = kzalloc(sizeof(*detection), GFP_KERNEL); + if (!detection) { + ret = -ENOMEM; + goto out; + } + + detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; + detection->tx_energy_detection = 0; + + ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, + detection, sizeof(*detection)); + if (ret < 0) { + wl1271_warning("failed to set cca threshold: %d", ret); + return ret; + } + +out: + kfree(detection); + return ret; +} + +int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) +{ + struct acx_beacon_broadcast *bb; + int ret; + + wl1271_debug(DEBUG_ACX, "acx bcn dtim options"); + + bb = kzalloc(sizeof(*bb), GFP_KERNEL); + if (!bb) { + ret = -ENOMEM; + goto out; + } + + bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; + bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; + bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; + bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; + + ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); + if (ret < 0) { + wl1271_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(bb); + return ret; +} + +int wl1271_acx_aid(struct wl1271 *wl, u16 aid) +{ + struct acx_aid *acx_aid; + int ret; + + wl1271_debug(DEBUG_ACX, "acx aid"); + + acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); + if (!acx_aid) { + ret = -ENOMEM; + goto out; + } + + acx_aid->aid = aid; + + ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); + if (ret < 0) { + wl1271_warning("failed to set aid: %d", ret); + goto out; + } + +out: + kfree(acx_aid); + return ret; +} + +int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) +{ + struct acx_event_mask *mask; + int ret; + + wl1271_debug(DEBUG_ACX, "acx event mbox mask"); + + mask = kzalloc(sizeof(*mask), GFP_KERNEL); + if (!mask) { + ret = -ENOMEM; + goto out; + } + + /* high event mask is unused */ + mask->high_event_mask = 0xffffffff; + + mask->event_mask = event_mask; + + ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, + mask, sizeof(*mask)); + if (ret < 0) { + wl1271_warning("failed to set acx_event_mbox_mask: %d", ret); + goto out; + } + +out: + kfree(mask); + return ret; +} + +int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble) +{ + struct acx_preamble *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx_set_preamble"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->preamble = preamble; + + ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of preamble failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_cts_protect(struct wl1271 *wl, + enum acx_ctsprotect_type ctsprotect) +{ + struct acx_ctsprotect *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ctsprotect = ctsprotect; + + ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of ctsprotect failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) +{ + int ret; + + wl1271_debug(DEBUG_ACX, "acx statistics"); + + ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, + sizeof(*stats)); + if (ret < 0) { + wl1271_warning("acx statistics failed: %d", ret); + return -ENOMEM; + } + + return 0; +} + +int wl1271_acx_rate_policies(struct wl1271 *wl) +{ + struct acx_rate_policy *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx rate policies"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* configure one default (one-size-fits-all) rate class */ + acx->rate_class_cnt = 1; + acx->rate_class[0].enabled_rates = ACX_RATE_MASK_ALL; + acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].aflags = 0; + + ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of rate policies failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_ac_cfg(struct wl1271 *wl) +{ + struct acx_ac_cfg *acx; + int i, ret = 0; + + wl1271_debug(DEBUG_ACX, "acx access category config"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* + * FIXME: Configure each AC with appropriate values (most suitable + * values will probably be different for each AC. + */ + for (i = 0; i < WL1271_ACX_AC_COUNT; i++) { + acx->ac = i; + + /* + * FIXME: The following default values originate from + * the TI reference driver. What do they mean? + */ + acx->cw_min = 15; + acx->cw_max = 63; + acx->aifsn = 3; + acx->reserved = 0; + acx->tx_op_limit = 0; + + ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of access category " + "config: %d", ret); + goto out; + } + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_tid_cfg(struct wl1271 *wl) +{ + struct acx_tid_config *acx; + int i, ret = 0; + + wl1271_debug(DEBUG_ACX, "acx tid config"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* FIXME: configure each TID with a different AC reference */ + for (i = 0; i < WL1271_ACX_TID_COUNT; i++) { + acx->queue_id = i; + acx->tsid = WL1271_ACX_AC_BE; + acx->ps_scheme = WL1271_ACX_PS_SCHEME_LEGACY; + acx->ack_policy = WL1271_ACX_ACK_POLICY_LEGACY; + + ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of tid config failed: %d", ret); + goto out; + } + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_frag_threshold(struct wl1271 *wl) +{ + struct acx_frag_threshold *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx frag threshold"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; + ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of frag threshold failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_tx_config_options(struct wl1271 *wl) +{ + struct acx_tx_config_options *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx tx config options"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->tx_compl_timeout = WL1271_ACX_TX_COMPL_TIMEOUT; + acx->tx_compl_threshold = WL1271_ACX_TX_COMPL_THRESHOLD; + ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of tx options failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_mem_cfg(struct wl1271 *wl) +{ + struct wl1271_acx_config_memory *mem_conf; + int ret; + + wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); + + mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); + if (!mem_conf) { + ret = -ENOMEM; + goto out; + } + + /* memory config */ + mem_conf->num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf->rx_mem_block_num = ACX_RX_MEM_BLOCKS; + mem_conf->tx_min_mem_block_num = ACX_TX_MIN_MEM_BLOCKS; + mem_conf->num_ssid_profiles = ACX_NUM_SSID_PROFILES; + mem_conf->total_tx_descriptors = ACX_TX_DESCRIPTORS; + + ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); + if (ret < 0) { + wl1271_warning("wl1271 mem config failed: %d", ret); + goto out; + } + +out: + kfree(mem_conf); + return ret; +} + +int wl1271_acx_init_mem_config(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_mem_cfg(wl); + if (ret < 0) + return ret; + + wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), + GFP_KERNEL); + if (!wl->target_mem_map) { + wl1271_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map, + sizeof(struct wl1271_acx_mem_map)); + if (ret < 0) { + wl1271_error("couldn't retrieve firmware memory map"); + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + return ret; + } + + /* initialize TX block book keeping */ + wl->tx_blocks_available = wl->target_mem_map->num_tx_mem_blocks; + wl1271_debug(DEBUG_TX, "available tx blocks: %d", + wl->tx_blocks_available); + + return 0; +} + +int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) +{ + struct wl1271_acx_rx_config_opt *rx_conf; + int ret; + + wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config"); + + rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL); + if (!rx_conf) { + ret = -ENOMEM; + goto out; + } + + rx_conf->threshold = WL1271_RX_INTR_THRESHOLD_DEF; + rx_conf->timeout = WL1271_RX_INTR_TIMEOUT_DEF; + rx_conf->mblk_threshold = USHORT_MAX; /* Disabled */ + rx_conf->queue_type = RX_QUEUE_TYPE_RX_LOW_PRIORITY; + + ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, + sizeof(*rx_conf)); + if (ret < 0) { + wl1271_warning("wl1271 rx config opt failed: %d", ret); + goto out; + } + +out: + kfree(rx_conf); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h new file mode 100644 index 0000000..9068daa --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -0,0 +1,1221 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_ACX_H__ +#define __WL1271_ACX_H__ + +#include "wl1271.h" +#include "wl1271_cmd.h" + +/************************************************************************* + + Host Interrupt Register (WiLink -> Host) + +**************************************************************************/ +/* HW Initiated interrupt Watchdog timer expiration */ +#define WL1271_ACX_INTR_WATCHDOG BIT(0) +/* Init sequence is done (masked interrupt, detection through polling only ) */ +#define WL1271_ACX_INTR_INIT_COMPLETE BIT(1) +/* Event was entered to Event MBOX #A*/ +#define WL1271_ACX_INTR_EVENT_A BIT(2) +/* Event was entered to Event MBOX #B*/ +#define WL1271_ACX_INTR_EVENT_B BIT(3) +/* Command processing completion*/ +#define WL1271_ACX_INTR_CMD_COMPLETE BIT(4) +/* Signaling the host on HW wakeup */ +#define WL1271_ACX_INTR_HW_AVAILABLE BIT(5) +/* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */ +#define WL1271_ACX_INTR_DATA BIT(6) +/* Trace meassge on MBOX #A */ +#define WL1271_ACX_INTR_TRACE_A BIT(7) +/* Trace meassge on MBOX #B */ +#define WL1271_ACX_INTR_TRACE_B BIT(8) + +#define WL1271_ACX_INTR_ALL 0xFFFFFFFF +#define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \ + WL1271_ACX_INTR_INIT_COMPLETE | \ + WL1271_ACX_INTR_EVENT_A | \ + WL1271_ACX_INTR_EVENT_B | \ + WL1271_ACX_INTR_CMD_COMPLETE | \ + WL1271_ACX_INTR_HW_AVAILABLE | \ + WL1271_ACX_INTR_DATA) + +#define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \ + WL1271_ACX_INTR_EVENT_B | \ + WL1271_ACX_INTR_DATA) + +/* Target's information element */ +struct acx_header { + struct wl1271_cmd_header cmd; + + /* acx (or information element) header */ + u16 id; + + /* payload length (not including headers */ + u16 len; +}; + +struct acx_error_counter { + struct acx_header header; + + /* The number of PLCP errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 PLCP_error; + + /* The number of FCS errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 FCS_error; + + /* The number of MPDUs without PLCP header errors received*/ + /* since the last time this information element was interrogated. */ + /* This field is automatically cleared when it is interrogated.*/ + u32 valid_frame; + + /* the number of missed sequence numbers in the squentially */ + /* values of frames seq numbers */ + u32 seq_num_miss; +} __attribute__ ((packed)); + +struct acx_revision { + struct acx_header header; + + /* + * The WiLink firmware version, an ASCII string x.x.x.x, + * that uniquely identifies the current firmware. + * The left most digit is incremented each time a + * significant change is made to the firmware, such as + * code redesign or new platform support. + * The second digit is incremented when major enhancements + * are added or major fixes are made. + * The third digit is incremented for each GA release. + * The fourth digit is incremented for each build. + * The first two digits identify a firmware release version, + * in other words, a unique set of features. + * The first three digits identify a GA release. + */ + char fw_version[20]; + + /* + * This 4 byte field specifies the WiLink hardware version. + * bits 0 - 15: Reserved. + * bits 16 - 23: Version ID - The WiLink version ID + * (1 = first spin, 2 = second spin, and so on). + * bits 24 - 31: Chip ID - The WiLink chip ID. + */ + u32 hw_version; +} __attribute__ ((packed)); + +enum wl1271_psm_mode { + /* Active mode */ + WL1271_PSM_CAM = 0, + + /* Power save mode */ + WL1271_PSM_PS = 1, + + /* Extreme low power */ + WL1271_PSM_ELP = 2, +}; + +struct acx_sleep_auth { + struct acx_header header; + + /* The sleep level authorization of the device. */ + /* 0 - Always active*/ + /* 1 - Power down mode: light / fast sleep*/ + /* 2 - ELP mode: Deep / Max sleep*/ + u8 sleep_auth; + u8 padding[3]; +} __attribute__ ((packed)); + +enum { + HOSTIF_PCI_MASTER_HOST_INDIRECT, + HOSTIF_PCI_MASTER_HOST_DIRECT, + HOSTIF_SLAVE, + HOSTIF_PKT_RING, + HOSTIF_DONTCARE = 0xFF +}; + +#define DEFAULT_UCAST_PRIORITY 0 +#define DEFAULT_RX_Q_PRIORITY 0 +#define DEFAULT_NUM_STATIONS 1 +#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ +#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ +#define TRACE_BUFFER_MAX_SIZE 256 + +#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_RX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_COMPLETE_TIME_OUT 20 +#define FW_TX_CMPLT_BLOCK_SIZE 16 + +#define TX_MSDU_LIFETIME_MIN 0 +#define TX_MSDU_LIFETIME_MAX 3000 +#define TX_MSDU_LIFETIME_DEF 512 +#define RX_MSDU_LIFETIME_MIN 0 +#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF +#define RX_MSDU_LIFETIME_DEF 512000 + +struct acx_rx_msdu_lifetime { + struct acx_header header; + + /* + * The maximum amount of time, in TU, before the + * firmware discards the MSDU. + */ + u32 lifetime; +} __attribute__ ((packed)); + +/* + * RX Config Options Table + * Bit Definition + * === ========== + * 31:14 Reserved + * 13 Copy RX Status - when set, write three receive status words + * to top of rx'd MPDUs. + * When cleared, do not write three status words (added rev 1.5) + * 12 Reserved + * 11 RX Complete upon FCS error - when set, give rx complete + * interrupt for FCS errors, after the rx filtering, e.g. unicast + * frames not to us with FCS error will not generate an interrupt. + * 10 SSID Filter Enable - When set, the WiLink discards all beacon, + * probe request, and probe response frames with an SSID that does + * not match the SSID specified by the host in the START/JOIN + * command. + * When clear, the WiLink receives frames with any SSID. + * 9 Broadcast Filter Enable - When set, the WiLink discards all + * broadcast frames. When clear, the WiLink receives all received + * broadcast frames. + * 8:6 Reserved + * 5 BSSID Filter Enable - When set, the WiLink discards any frames + * with a BSSID that does not match the BSSID specified by the + * host. + * When clear, the WiLink receives frames from any BSSID. + * 4 MAC Addr Filter - When set, the WiLink discards any frames + * with a destination address that does not match the MAC address + * of the adaptor. + * When clear, the WiLink receives frames destined to any MAC + * address. + * 3 Promiscuous - When set, the WiLink receives all valid frames + * (i.e., all frames that pass the FCS check). + * When clear, only frames that pass the other filters specified + * are received. + * 2 FCS - When set, the WiLink includes the FCS with the received + * frame. + * When cleared, the FCS is discarded. + * 1 PLCP header - When set, write all data from baseband to frame + * buffer including PHY header. + * 0 Reserved - Always equal to 0. + * + * RX Filter Options Table + * Bit Definition + * === ========== + * 31:12 Reserved - Always equal to 0. + * 11 Association - When set, the WiLink receives all association + * related frames (association request/response, reassocation + * request/response, and disassociation). When clear, these frames + * are discarded. + * 10 Auth/De auth - When set, the WiLink receives all authentication + * and de-authentication frames. When clear, these frames are + * discarded. + * 9 Beacon - When set, the WiLink receives all beacon frames. + * When clear, these frames are discarded. + * 8 Contention Free - When set, the WiLink receives all contention + * free frames. + * When clear, these frames are discarded. + * 7 Control - When set, the WiLink receives all control frames. + * When clear, these frames are discarded. + * 6 Data - When set, the WiLink receives all data frames. + * When clear, these frames are discarded. + * 5 FCS Error - When set, the WiLink receives frames that have FCS + * errors. + * When clear, these frames are discarded. + * 4 Management - When set, the WiLink receives all management + * frames. + * When clear, these frames are discarded. + * 3 Probe Request - When set, the WiLink receives all probe request + * frames. + * When clear, these frames are discarded. + * 2 Probe Response - When set, the WiLink receives all probe + * response frames. + * When clear, these frames are discarded. + * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK + * frames. + * When clear, these frames are discarded. + * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames + * that have reserved frame types and sub types as defined by the + * 802.11 specification. + * When clear, these frames are discarded. + */ +struct acx_rx_config { + struct acx_header header; + + u32 config_options; + u32 filter_options; +} __attribute__ ((packed)); + +struct acx_packet_detection { + struct acx_header header; + + u32 threshold; +} __attribute__ ((packed)); + + +enum acx_slot_type { + SLOT_TIME_LONG = 0, + SLOT_TIME_SHORT = 1, + DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, + MAX_SLOT_TIMES = 0xFF +}; + +#define STATION_WONE_INDEX 0 + +struct acx_slot { + struct acx_header header; + + u8 wone_index; /* Reserved */ + u8 slot_time; + u8 reserved[6]; +} __attribute__ ((packed)); + + +#define ADDRESS_GROUP_MAX (8) +#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) + +struct acx_dot11_grp_addr_tbl { + struct acx_header header; + + u8 enabled; + u8 num_groups; + u8 pad[2]; + u8 mac_table[ADDRESS_GROUP_MAX_LEN]; +} __attribute__ ((packed)); + + +#define RX_TIMEOUT_PS_POLL_MIN 0 +#define RX_TIMEOUT_PS_POLL_MAX (200000) +#define RX_TIMEOUT_PS_POLL_DEF (15) +#define RX_TIMEOUT_UPSD_MIN 0 +#define RX_TIMEOUT_UPSD_MAX (200000) +#define RX_TIMEOUT_UPSD_DEF (15) + +struct acx_rx_timeout { + struct acx_header header; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a PS-poll has been + * transmitted. + */ + u16 ps_poll_timeout; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a frame has been sent + * from an UPSD enabled queue. + */ + u16 upsd_timeout; +} __attribute__ ((packed)); + +#define RTS_THRESHOLD_MIN 0 +#define RTS_THRESHOLD_MAX 4096 +#define RTS_THRESHOLD_DEF 2347 + +struct acx_rts_threshold { + struct acx_header header; + + u16 threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_beacon_filter_option { + struct acx_header header; + + u8 enable; + + /* + * The number of beacons without the unicast TIM + * bit set that the firmware buffers before + * signaling the host about ready frames. + * When set to 0 and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + u8 max_num_beacons; + u8 pad[2]; +} __attribute__ ((packed)); + +/* + * ACXBeaconFilterEntry (not 221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * + * ACXBeaconFilterEntry (221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * 2 3 OUI + * 5 1 Type + * 6 2 Version + * + * + * Treatment bit mask - The information element handling: + * bit 0 - The information element is compared and transferred + * in case of change. + * bit 1 - The information element is transferred to the host + * with each appearance or disappearance. + * Note that both bits can be set at the same time. + */ +#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) +#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) +#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) +#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) +#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ + BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ + (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ + BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) + +struct acx_beacon_filter_ie_table { + struct acx_header header; + + u8 num_ie; + u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; + u8 pad[3]; +} __attribute__ ((packed)); + +enum { + SG_ENABLE = 0, + SG_DISABLE, + SG_SENSE_NO_ACTIVITY, + SG_SENSE_ACTIVE +}; + +struct acx_bt_wlan_coex { + struct acx_header header; + + /* + * 0 -> PTA enabled + * 1 -> PTA disabled + * 2 -> sense no active mode, i.e. + * an interrupt is sent upon + * BT activity. + * 3 -> PTA is switched on in response + * to the interrupt sending. + */ + u8 enable; + u8 pad[3]; +} __attribute__ ((packed)); + +#define PTA_ANTENNA_TYPE_DEF (0) +#define PTA_BT_HP_MAXTIME_DEF (2000) +#define PTA_WLAN_HP_MAX_TIME_DEF (5000) +#define PTA_SENSE_DISABLE_TIMER_DEF (1350) +#define PTA_PROTECTIVE_RX_TIME_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_DEF (1500) +#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) +#define PTA_SIGNALING_TYPE_DEF (1) +#define PTA_AFH_LEVERAGE_ON_DEF (0) +#define PTA_NUMBER_QUIET_CYCLE_DEF (0) +#define PTA_MAX_NUM_CTS_DEF (3) +#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) +#define PTA_NUMBER_OF_BT_PACKETS_DEF (2) +#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) +#define PTA_CYCLE_TIME_FAST_DEF (8700) +#define PTA_RX_FOR_AVALANCHE_DEF (5) +#define PTA_ELP_HP_DEF (0) +#define PTA_ANTI_STARVE_PERIOD_DEF (500) +#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) +#define PTA_ALLOW_PA_SD_DEF (1) +#define PTA_TIME_BEFORE_BEACON_DEF (6300) +#define PTA_HPDM_MAX_TIME_DEF (1600) +#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) +#define PTA_AUTO_MODE_NO_CTS_DEF (0) +#define PTA_BT_HP_RESPECTED_DEF (3) +#define PTA_WLAN_RX_MIN_RATE_DEF (24) +#define PTA_ACK_MODE_DEF (1) + +struct acx_bt_wlan_coex_param { + struct acx_header header; + + /* + * The minimum rate of a received WLAN packet in the STA, + * during protective mode, of which a new BT-HP request + * during this Rx will always be respected and gain the antenna. + */ + u32 min_rate; + + /* Max time the BT HP will be respected. */ + u16 bt_hp_max_time; + + /* Max time the WLAN HP will be respected. */ + u16 wlan_hp_max_time; + + /* + * The time between the last BT activity + * and the moment when the sense mode returns + * to SENSE_INACTIVE. + */ + u16 sense_disable_timer; + + /* Time before the next BT HP instance */ + u16 rx_time_bt_hp; + u16 tx_time_bt_hp; + + /* range: 10-20000 default: 1500 */ + u16 rx_time_bt_hp_fast; + u16 tx_time_bt_hp_fast; + + /* range: 2000-65535 default: 8700 */ + u16 wlan_cycle_fast; + + /* range: 0 - 15000 (Msec) default: 1000 */ + u16 bt_anti_starvation_period; + + /* range 400-10000(Usec) default: 3000 */ + u16 next_bt_lp_packet; + + /* Deafult: worst case for BT DH5 traffic */ + u16 wake_up_beacon; + + /* range: 0-50000(Usec) default: 1050 */ + u16 hp_dm_max_guard_time; + + /* + * This is to prevent both BT & WLAN antenna + * starvation. + * Range: 100-50000(Usec) default:2550 + */ + u16 next_wlan_packet; + + /* 0 -> shared antenna */ + u8 antenna_type; + + /* + * 0 -> TI legacy + * 1 -> Palau + */ + u8 signal_type; + + /* + * BT AFH status + * 0 -> no AFH + * 1 -> from dedicated GPIO + * 2 -> AFH on (from host) + */ + u8 afh_leverage_on; + + /* + * The number of cycles during which no + * TX will be sent after 1 cycle of RX + * transaction in protective mode + */ + u8 quiet_cycle_num; + + /* + * The maximum number of CTSs that will + * be sent for receiving RX packet in + * protective mode + */ + u8 max_cts; + + /* + * The number of WLAN packets + * transferred in common mode before + * switching to BT. + */ + u8 wlan_packets_num; + + /* + * The number of BT packets + * transferred in common mode before + * switching to WLAN. + */ + u8 bt_packets_num; + + /* range: 1-255 default: 5 */ + u8 missed_rx_avalanche; + + /* range: 0-1 default: 1 */ + u8 wlan_elp_hp; + + /* range: 0 - 15 default: 4 */ + u8 bt_anti_starvation_cycles; + + u8 ack_mode_dual_ant; + + /* + * Allow PA_SD assertion/de-assertion + * during enabled BT activity. + */ + u8 pa_sd_enable; + + /* + * Enable/Disable PTA in auto mode: + * Support Both Active & P.S modes + */ + u8 pta_auto_mode_enable; + + /* range: 0 - 20 default: 1 */ + u8 bt_hp_respected_num; +} __attribute__ ((packed)); + +#define CCA_THRSH_ENABLE_ENERGY_D 0x140A +#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF + +struct acx_energy_detection { + struct acx_header header; + + /* The RX Clear Channel Assessment threshold in the PHY */ + u16 rx_cca_threshold; + u8 tx_energy_detection; + u8 pad; +} __attribute__ ((packed)); + +#define BCN_RX_TIMEOUT_DEF_VALUE 10000 +#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 +#define RX_BROADCAST_IN_PS_DEF_VALUE 1 +#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 + +struct acx_beacon_broadcast { + struct acx_header header; + + u16 beacon_rx_timeout; + u16 broadcast_timeout; + + /* Enables receiving of broadcast packets in PS mode */ + u8 rx_broadcast_in_ps; + + /* Consecutive PS Poll failures before updating the host */ + u8 ps_poll_threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_event_mask { + struct acx_header header; + + u32 event_mask; + u32 high_event_mask; /* Unused */ +} __attribute__ ((packed)); + +#define CFG_RX_FCS BIT(2) +#define CFG_RX_ALL_GOOD BIT(3) +#define CFG_UNI_FILTER_EN BIT(4) +#define CFG_BSSID_FILTER_EN BIT(5) +#define CFG_MC_FILTER_EN BIT(6) +#define CFG_MC_ADDR0_EN BIT(7) +#define CFG_MC_ADDR1_EN BIT(8) +#define CFG_BC_REJECT_EN BIT(9) +#define CFG_SSID_FILTER_EN BIT(10) +#define CFG_RX_INT_FCS_ERROR BIT(11) +#define CFG_RX_INT_ENCRYPTED BIT(12) +#define CFG_RX_WR_RX_STATUS BIT(13) +#define CFG_RX_FILTER_NULTI BIT(14) +#define CFG_RX_RESERVE BIT(15) +#define CFG_RX_TIMESTAMP_TSF BIT(16) + +#define CFG_RX_RSV_EN BIT(0) +#define CFG_RX_RCTS_ACK BIT(1) +#define CFG_RX_PRSP_EN BIT(2) +#define CFG_RX_PREQ_EN BIT(3) +#define CFG_RX_MGMT_EN BIT(4) +#define CFG_RX_FCS_ERROR BIT(5) +#define CFG_RX_DATA_EN BIT(6) +#define CFG_RX_CTL_EN BIT(7) +#define CFG_RX_CF_EN BIT(8) +#define CFG_RX_BCN_EN BIT(9) +#define CFG_RX_AUTH_EN BIT(10) +#define CFG_RX_ASSOC_EN BIT(11) + +#define SCAN_PASSIVE BIT(0) +#define SCAN_5GHZ_BAND BIT(1) +#define SCAN_TRIGGERED BIT(2) +#define SCAN_PRIORITY_HIGH BIT(3) + +struct acx_feature_config { + struct acx_header header; + + u32 options; + u32 data_flow_options; +} __attribute__ ((packed)); + +struct acx_current_tx_power { + struct acx_header header; + + u8 current_tx_power; + u8 padding[3]; +} __attribute__ ((packed)); + +enum acx_wake_up_event { + WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ + WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ + WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ + WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ + WAKE_UP_EVENT_BITS_MASK = 0x0F +}; + +struct acx_wake_up_condition { + struct acx_header header; + + u8 wake_up_event; /* Only one bit can be set */ + u8 listen_interval; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_aid { + struct acx_header header; + + /* + * To be set when associated with an AP. + */ + u16 aid; + u8 pad[2]; +} __attribute__ ((packed)); + +enum acx_preamble_type { + ACX_PREAMBLE_LONG = 0, + ACX_PREAMBLE_SHORT = 1 +}; + +struct acx_preamble { + struct acx_header header; + + /* + * When set, the WiLink transmits the frames with a short preamble and + * when cleared, the WiLink transmits the frames with a long preamble. + */ + u8 preamble; + u8 padding[3]; +} __attribute__ ((packed)); + +enum acx_ctsprotect_type { + CTSPROTECT_DISABLE = 0, + CTSPROTECT_ENABLE = 1 +}; + +struct acx_ctsprotect { + struct acx_header header; + u8 ctsprotect; + u8 padding[3]; +} __attribute__ ((packed)); + +struct acx_tx_statistics { + u32 internal_desc_overflow; +} __attribute__ ((packed)); + +struct acx_rx_statistics { + u32 out_of_mem; + u32 hdr_overflow; + u32 hw_stuck; + u32 dropped; + u32 fcs_err; + u32 xfr_hint_trig; + u32 path_reset; + u32 reset_counter; +} __attribute__ ((packed)); + +struct acx_dma_statistics { + u32 rx_requested; + u32 rx_errors; + u32 tx_requested; + u32 tx_errors; +} __attribute__ ((packed)); + +struct acx_isr_statistics { + /* host command complete */ + u32 cmd_cmplt; + + /* fiqisr() */ + u32 fiqs; + + /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ + u32 rx_headers; + + /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ + u32 rx_completes; + + /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ + u32 rx_mem_overflow; + + /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ + u32 rx_rdys; + + /* irqisr() */ + u32 irqs; + + /* (INT_STS_ND & INT_TRIG_TX_PROC) */ + u32 tx_procs; + + /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ + u32 decrypt_done; + + /* (INT_STS_ND & INT_TRIG_DMA0) */ + u32 dma0_done; + + /* (INT_STS_ND & INT_TRIG_DMA1) */ + u32 dma1_done; + + /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ + u32 tx_exch_complete; + + /* (INT_STS_ND & INT_TRIG_COMMAND) */ + u32 commands; + + /* (INT_STS_ND & INT_TRIG_RX_PROC) */ + u32 rx_procs; + + /* (INT_STS_ND & INT_TRIG_PM_802) */ + u32 hw_pm_mode_changes; + + /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ + u32 host_acknowledges; + + /* (INT_STS_ND & INT_TRIG_PM_PCI) */ + u32 pci_pm; + + /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ + u32 wakeups; + + /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ + u32 low_rssi; +} __attribute__ ((packed)); + +struct acx_wep_statistics { + /* WEP address keys configured */ + u32 addr_key_count; + + /* default keys configured */ + u32 default_key_count; + + u32 reserved; + + /* number of times that WEP key not found on lookup */ + u32 key_not_found; + + /* number of times that WEP key decryption failed */ + u32 decrypt_fail; + + /* WEP packets decrypted */ + u32 packets; + + /* WEP decrypt interrupts */ + u32 interrupt; +} __attribute__ ((packed)); + +#define ACX_MISSED_BEACONS_SPREAD 10 + +struct acx_pwr_statistics { + /* the amount of enters into power save mode (both PD & ELP) */ + u32 ps_enter; + + /* the amount of enters into ELP mode */ + u32 elp_enter; + + /* the amount of missing beacon interrupts to the host */ + u32 missing_bcns; + + /* the amount of wake on host-access times */ + u32 wake_on_host; + + /* the amount of wake on timer-expire */ + u32 wake_on_timer_exp; + + /* the number of packets that were transmitted with PS bit set */ + u32 tx_with_ps; + + /* the number of packets that were transmitted with PS bit clear */ + u32 tx_without_ps; + + /* the number of received beacons */ + u32 rcvd_beacons; + + /* the number of entering into PowerOn (power save off) */ + u32 power_save_off; + + /* the number of entries into power save mode */ + u16 enable_ps; + + /* + * the number of exits from power save, not including failed PS + * transitions + */ + u16 disable_ps; + + /* + * the number of times the TSF counter was adjusted because + * of drift + */ + u32 fix_tsf_ps; + + /* Gives statistics about the spread continuous missed beacons. + * The 16 LSB are dedicated for the PS mode. + * The 16 MSB are dedicated for the PS mode. + * cont_miss_bcns_spread[0] - single missed beacon. + * cont_miss_bcns_spread[1] - two continuous missed beacons. + * cont_miss_bcns_spread[2] - three continuous missed beacons. + * ... + * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. + */ + u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; + + /* the number of beacons in awake mode */ + u32 rcvd_awake_beacons; +} __attribute__ ((packed)); + +struct acx_mic_statistics { + u32 rx_pkts; + u32 calc_failure; +} __attribute__ ((packed)); + +struct acx_aes_statistics { + u32 encrypt_fail; + u32 decrypt_fail; + u32 encrypt_packets; + u32 decrypt_packets; + u32 encrypt_interrupt; + u32 decrypt_interrupt; +} __attribute__ ((packed)); + +struct acx_event_statistics { + u32 heart_beat; + u32 calibration; + u32 rx_mismatch; + u32 rx_mem_empty; + u32 rx_pool; + u32 oom_late; + u32 phy_transmit_error; + u32 tx_stuck; +} __attribute__ ((packed)); + +struct acx_ps_statistics { + u32 pspoll_timeouts; + u32 upsd_timeouts; + u32 upsd_max_sptime; + u32 upsd_max_apturn; + u32 pspoll_max_apturn; + u32 pspoll_utilization; + u32 upsd_utilization; +} __attribute__ ((packed)); + +struct acx_rxpipe_statistics { + u32 rx_prep_beacon_drop; + u32 descr_host_int_trig_rx_data; + u32 beacon_buffer_thres_host_int_trig_rx_data; + u32 missed_beacon_host_int_trig_rx_data; + u32 tx_xfr_host_int_trig_rx_data; +} __attribute__ ((packed)); + +struct acx_statistics { + struct acx_header header; + + struct acx_tx_statistics tx; + struct acx_rx_statistics rx; + struct acx_dma_statistics dma; + struct acx_isr_statistics isr; + struct acx_wep_statistics wep; + struct acx_pwr_statistics pwr; + struct acx_aes_statistics aes; + struct acx_mic_statistics mic; + struct acx_event_statistics event; + struct acx_ps_statistics ps; + struct acx_rxpipe_statistics rxpipe; +} __attribute__ ((packed)); + +#define ACX_MAX_RATE_CLASSES 8 +#define ACX_RATE_MASK_UNSPECIFIED 0 +#define ACX_RATE_MASK_ALL 0x1eff +#define ACX_RATE_RETRY_LIMIT 10 + +struct acx_rate_class { + u32 enabled_rates; + u8 short_retry_limit; + u8 long_retry_limit; + u8 aflags; + u8 reserved; +}; + +struct acx_rate_policy { + struct acx_header header; + + u32 rate_class_cnt; + struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; +} __attribute__ ((packed)); + +#define WL1271_ACX_AC_COUNT 4 + +struct acx_ac_cfg { + struct acx_header header; + u8 ac; + u8 cw_min; + u16 cw_max; + u8 aifsn; + u8 reserved; + u16 tx_op_limit; +} __attribute__ ((packed)); + +enum wl1271_acx_ac { + WL1271_ACX_AC_BE = 0, + WL1271_ACX_AC_BK = 1, + WL1271_ACX_AC_VI = 2, + WL1271_ACX_AC_VO = 3, + WL1271_ACX_AC_CTS2SELF = 4, + WL1271_ACX_AC_ANY_TID = 0x1F, + WL1271_ACX_AC_INVALID = 0xFF, +}; + +enum wl1271_acx_ps_scheme { + WL1271_ACX_PS_SCHEME_LEGACY = 0, + WL1271_ACX_PS_SCHEME_UPSD_TRIGGER = 1, + WL1271_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, + WL1271_ACX_PS_SCHEME_SAPSD = 3, +}; + +enum wl1271_acx_ack_policy { + WL1271_ACX_ACK_POLICY_LEGACY = 0, + WL1271_ACX_ACK_POLICY_NO_ACK = 1, + WL1271_ACX_ACK_POLICY_BLOCK = 2, +}; + +#define WL1271_ACX_TID_COUNT 7 + +struct acx_tid_config { + struct acx_header header; + u8 queue_id; + u8 channel_type; + u8 tsid; + u8 ps_scheme; + u8 ack_policy; + u8 padding[3]; + u32 apsd_conf[2]; +} __attribute__ ((packed)); + +struct acx_frag_threshold { + struct acx_header header; + u16 frag_threshold; + u8 padding[2]; +} __attribute__ ((packed)); + +#define WL1271_ACX_TX_COMPL_TIMEOUT 5 +#define WL1271_ACX_TX_COMPL_THRESHOLD 5 + +struct acx_tx_config_options { + struct acx_header header; + u16 tx_compl_timeout; /* msec */ + u16 tx_compl_threshold; /* number of packets */ +} __attribute__ ((packed)); + +#define ACX_RX_MEM_BLOCKS 64 +#define ACX_TX_MIN_MEM_BLOCKS 64 +#define ACX_TX_DESCRIPTORS 32 +#define ACX_NUM_SSID_PROFILES 1 + +struct wl1271_acx_config_memory { + struct acx_header header; + + u8 rx_mem_block_num; + u8 tx_min_mem_block_num; + u8 num_stations; + u8 num_ssid_profiles; + u32 total_tx_descriptors; +} __attribute__ ((packed)); + +struct wl1271_acx_mem_map { + struct acx_header header; + + void *code_start; + void *code_end; + + void *wep_defkey_start; + void *wep_defkey_end; + + void *sta_table_start; + void *sta_table_end; + + void *packet_template_start; + void *packet_template_end; + + /* Address of the TX result interface (control block) */ + u32 tx_result; + u32 tx_result_queue_start; + + void *queue_memory_start; + void *queue_memory_end; + + u32 packet_memory_pool_start; + u32 packet_memory_pool_end; + + void *debug_buffer1_start; + void *debug_buffer1_end; + + void *debug_buffer2_start; + void *debug_buffer2_end; + + /* Number of blocks FW allocated for TX packets */ + u32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + u32 num_rx_mem_blocks; + + /* the following 4 fields are valid in SLAVE mode only */ + u8 *tx_cbuf; + u8 *rx_cbuf; + void *rx_ctrl; + void *tx_ctrl; +} __attribute__ ((packed)); + +enum wl1271_acx_rx_queue_type { + RX_QUEUE_TYPE_RX_LOW_PRIORITY, /* All except the high priority */ + RX_QUEUE_TYPE_RX_HIGH_PRIORITY, /* Management and voice packets */ + RX_QUEUE_TYPE_NUM, + RX_QUEUE_TYPE_MAX = USHORT_MAX +}; + +#define WL1271_RX_INTR_THRESHOLD_DEF 0 /* no pacing, send interrupt on + * every event */ +#define WL1271_RX_INTR_THRESHOLD_MIN 0 +#define WL1271_RX_INTR_THRESHOLD_MAX 15 + +#define WL1271_RX_INTR_TIMEOUT_DEF 5 +#define WL1271_RX_INTR_TIMEOUT_MIN 1 +#define WL1271_RX_INTR_TIMEOUT_MAX 100 + +struct wl1271_acx_rx_config_opt { + struct acx_header header; + + u16 mblk_threshold; + u16 threshold; + u16 timeout; + u8 queue_type; + u8 reserved; +} __attribute__ ((packed)); + +enum { + ACX_WAKE_UP_CONDITIONS = 0x0002, + ACX_MEM_CFG = 0x0003, + ACX_SLOT = 0x0004, + ACX_AC_CFG = 0x0007, + ACX_MEM_MAP = 0x0008, + ACX_AID = 0x000A, + /* ACX_FW_REV is missing in the ref driver, but seems to work */ + ACX_FW_REV = 0x000D, + ACX_MEDIUM_USAGE = 0x000F, + ACX_RX_CFG = 0x0010, + ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ + ACX_STATISTICS = 0x0013, /* Debug API */ + ACX_PWR_CONSUMPTION_STATISTICS = 0x0014, + ACX_FEATURE_CFG = 0x0015, + ACX_TID_CFG = 0x001A, + ACX_PS_RX_STREAMING = 0x001B, + ACX_BEACON_FILTER_OPT = 0x001F, + ACX_NOISE_HIST = 0x0021, + ACX_HDK_VERSION = 0x0022, /* ??? */ + ACX_PD_THRESHOLD = 0x0023, + ACX_TX_CONFIG_OPT = 0x0024, + ACX_CCA_THRESHOLD = 0x0025, + ACX_EVENT_MBOX_MASK = 0x0026, + ACX_CONN_MONIT_PARAMS = 0x002D, + ACX_CONS_TX_FAILURE = 0x002F, + ACX_BCN_DTIM_OPTIONS = 0x0031, + ACX_SG_ENABLE = 0x0032, + ACX_SG_CFG = 0x0033, + ACX_BEACON_FILTER_TABLE = 0x0038, + ACX_ARP_IP_FILTER = 0x0039, + ACX_ROAMING_STATISTICS_TBL = 0x003B, + ACX_RATE_POLICY = 0x003D, + ACX_CTS_PROTECTION = 0x003E, + ACX_SLEEP_AUTH = 0x003F, + ACX_PREAMBLE_TYPE = 0x0040, + ACX_ERROR_CNT = 0x0041, + ACX_IBSS_FILTER = 0x0044, + ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, + ACX_TSF_INFO = 0x0046, + ACX_CONFIG_PS_WMM = 0x0049, + ACX_ENABLE_RX_DATA_FILTER = 0x004A, + ACX_SET_RX_DATA_FILTER = 0x004B, + ACX_GET_DATA_FILTER_STATISTICS = 0x004C, + ACX_RX_CONFIG_OPT = 0x004E, + ACX_FRAG_CFG = 0x004F, + ACX_BET_ENABLE = 0x0050, + ACX_RSSI_SNR_TRIGGER = 0x0051, + ACX_RSSI_SNR_WEIGHTS = 0x0051, + ACX_KEEP_ALIVE_MODE = 0x0052, + ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, + ACX_BA_SESSION_RESPONDER_POLICY = 0x0055, + ACX_BA_SESSION_INITIATOR_POLICY = 0x0056, + ACX_PEER_HT_CAP = 0x0057, + ACX_HT_BSS_OPERATION = 0x0058, + ACX_COEX_ACTIVITY = 0x0059, + DOT11_RX_MSDU_LIFE_TIME = 0x1004, + DOT11_CUR_TX_PWR = 0x100D, + DOT11_RX_DOT11_MODE = 0x1012, + DOT11_RTS_THRESHOLD = 0x1013, + DOT11_GROUP_ADDRESS_TBL = 0x1014, + + MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, + + MAX_IE = 0xFFFF +}; + + +int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event, + u8 listen_interval); +int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); +int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len); +int wl1271_acx_tx_power(struct wl1271 *wl, int power); +int wl1271_acx_feature_cfg(struct wl1271 *wl); +int wl1271_acx_mem_map(struct wl1271 *wl, + struct acx_header *mem_map, size_t len); +int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time); +int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter); +int wl1271_acx_pd_threshold(struct wl1271 *wl); +int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); +int wl1271_acx_group_address_tbl(struct wl1271 *wl); +int wl1271_acx_service_period_timeout(struct wl1271 *wl); +int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl); +int wl1271_acx_beacon_filter_table(struct wl1271 *wl); +int wl1271_acx_sg_enable(struct wl1271 *wl); +int wl1271_acx_sg_cfg(struct wl1271 *wl); +int wl1271_acx_cca_threshold(struct wl1271 *wl); +int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); +int wl1271_acx_aid(struct wl1271 *wl, u16 aid); +int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask); +int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); +int wl1271_acx_cts_protect(struct wl1271 *wl, + enum acx_ctsprotect_type ctsprotect); +int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); +int wl1271_acx_rate_policies(struct wl1271 *wl); +int wl1271_acx_ac_cfg(struct wl1271 *wl); +int wl1271_acx_tid_cfg(struct wl1271 *wl); +int wl1271_acx_frag_threshold(struct wl1271 *wl); +int wl1271_acx_tx_config_options(struct wl1271 *wl); +int wl1271_acx_mem_cfg(struct wl1271 *wl); +int wl1271_acx_init_mem_config(struct wl1271 *wl); +int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); + +#endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c new file mode 100644 index 0000000..4c22f25 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -0,0 +1,540 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include + +#include "wl1271_acx.h" +#include "wl1271_reg.h" +#include "wl1271_boot.h" +#include "wl1271_spi.h" +#include "wl1271_event.h" + +static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { + [PART_DOWN] = { + .mem = { + .start = 0x00000000, + .size = 0x000177c0 + }, + .reg = { + .start = REGISTERS_BASE, + .size = 0x00008800 + }, + }, + + [PART_WORK] = { + .mem = { + .start = 0x00040000, + .size = 0x00014fc0 + }, + .reg = { + .start = REGISTERS_BASE, + .size = 0x0000b000 + }, + }, + + [PART_DRPW] = { + .mem = { + .start = 0x00040000, + .size = 0x00014fc0 + }, + .reg = { + .start = DRPW_BASE, + .size = 0x00006000 + } + } +}; + +static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) +{ + u32 cpu_ctrl; + + /* 10.5.0 run the firmware (I) */ + cpu_ctrl = wl1271_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + /* 10.5.1 run the firmware (II) */ + cpu_ctrl |= flag; + wl1271_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); +} + +static void wl1271_boot_fw_version(struct wl1271 *wl) +{ + struct wl1271_static_data static_data; + + wl1271_spi_mem_read(wl, wl->cmd_box_addr, + &static_data, sizeof(static_data)); + + strncpy(wl->chip.fw_ver, static_data.fw_version, + sizeof(wl->chip.fw_ver)); + + /* make sure the string is NULL-terminated */ + wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0'; +} + +static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, + size_t fw_data_len, u32 dest) +{ + int addr, chunk_num, partition_limit; + u8 *p; + + /* whal_FwCtrl_LoadFwImageSm() */ + + wl1271_debug(DEBUG_BOOT, "starting firmware upload"); + + wl1271_debug(DEBUG_BOOT, "fw_data_len %d chunk_size %d", fw_data_len, + CHUNK_SIZE); + + + if ((fw_data_len % 4) != 0) { + wl1271_error("firmware length not multiple of four"); + return -EIO; + } + + wl1271_set_partition(wl, dest, + part_table[PART_DOWN].mem.size, + part_table[PART_DOWN].reg.start, + part_table[PART_DOWN].reg.size); + + /* 10.1 set partition limit and chunk num */ + chunk_num = 0; + partition_limit = part_table[PART_DOWN].mem.size; + + while (chunk_num < fw_data_len / CHUNK_SIZE) { + /* 10.2 update partition, if needed */ + addr = dest + (chunk_num + 2) * CHUNK_SIZE; + if (addr > partition_limit) { + addr = dest + chunk_num * CHUNK_SIZE; + partition_limit = chunk_num * CHUNK_SIZE + + part_table[PART_DOWN].mem.size; + + /* FIXME: Over 80 chars! */ + wl1271_set_partition(wl, + addr, + part_table[PART_DOWN].mem.size, + part_table[PART_DOWN].reg.start, + part_table[PART_DOWN].reg.size); + } + + /* 10.3 upload the chunk */ + addr = dest + chunk_num * CHUNK_SIZE; + p = buf + chunk_num * CHUNK_SIZE; + wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + p, addr); + wl1271_spi_mem_write(wl, addr, p, CHUNK_SIZE); + + chunk_num++; + } + + /* 10.4 upload the last chunk */ + addr = dest + chunk_num * CHUNK_SIZE; + p = buf + chunk_num * CHUNK_SIZE; + wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%d B) 0x%p to 0x%x", + fw_data_len % CHUNK_SIZE, p, addr); + wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + + return 0; +} + +static int wl1271_boot_upload_firmware(struct wl1271 *wl) +{ + u32 chunks, addr, len; + u8 *fw; + + fw = wl->fw; + chunks = be32_to_cpup((u32 *) fw); + fw += sizeof(u32); + + wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks); + + while (chunks--) { + addr = be32_to_cpup((u32 *) fw); + fw += sizeof(u32); + len = be32_to_cpup((u32 *) fw); + fw += sizeof(u32); + + if (len > 300000) { + wl1271_info("firmware chunk too long: %u", len); + return -EINVAL; + } + wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u", + chunks, addr, len); + wl1271_boot_upload_firmware_chunk(wl, fw, len, addr); + fw += len; + } + + return 0; +} + +static int wl1271_boot_upload_nvs(struct wl1271 *wl) +{ + size_t nvs_len, burst_len; + int i; + u32 dest_addr, val; + u8 *nvs_ptr, *nvs, *nvs_aligned; + + nvs = wl->nvs; + if (nvs == NULL) + return -ENODEV; + + nvs_ptr = nvs; + + nvs_len = wl->nvs_len; + + /* Update the device MAC address into the nvs */ + nvs[11] = wl->mac_addr[0]; + nvs[10] = wl->mac_addr[1]; + nvs[6] = wl->mac_addr[2]; + nvs[5] = wl->mac_addr[3]; + nvs[4] = wl->mac_addr[4]; + nvs[3] = wl->mac_addr[5]; + + /* + * Layout before the actual NVS tables: + * 1 byte : burst length. + * 2 bytes: destination address. + * n bytes: data to burst copy. + * + * This is ended by a 0 length, then the NVS tables. + */ + + /* FIXME: Do we need to check here whether the LSB is 1? */ + while (nvs_ptr[0]) { + burst_len = nvs_ptr[0]; + dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); + + /* FIXME: Due to our new wl1271_translate_reg_addr function, + we need to add the REGISTER_BASE to the destination */ + dest_addr += REGISTERS_BASE; + + /* We move our pointer to the data */ + nvs_ptr += 3; + + for (i = 0; i < burst_len; i++) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + wl1271_debug(DEBUG_BOOT, + "nvs burst write 0x%x: 0x%x", + dest_addr, val); + wl1271_reg_write32(wl, dest_addr, val); + + nvs_ptr += 4; + dest_addr += 4; + } + } + + /* + * We've reached the first zero length, the first NVS table + * is 7 bytes further. + */ + nvs_ptr += 7; + nvs_len -= nvs_ptr - nvs; + nvs_len = ALIGN(nvs_len, 4); + + /* FIXME: The driver sets the partition here, but this is not needed, + since it sets to the same one as currently in use */ + /* Now we must set the partition correctly */ + wl1271_set_partition(wl, + part_table[PART_WORK].mem.start, + part_table[PART_WORK].mem.size, + part_table[PART_WORK].reg.start, + part_table[PART_WORK].reg.size); + + /* Copy the NVS tables to a new block to ensure alignment */ + nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); + + /* And finally we upload the NVS tables */ + /* FIXME: In wl1271, we upload everything at once. + No endianness handling needed here?! The ref driver doesn't do + anything about it at this point */ + wl1271_spi_mem_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len); + + kfree(nvs_aligned); + return 0; +} + +static void wl1271_boot_enable_interrupts(struct wl1271 *wl) +{ + enable_irq(wl->irq); + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(WL1271_INTR_MASK)); + wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); +} + +static int wl1271_boot_soft_reset(struct wl1271 *wl) +{ + unsigned long timeout; + u32 boot_data; + + /* perform soft reset */ + wl1271_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + + /* SOFT_RESET is self clearing */ + timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); + while (1) { + boot_data = wl1271_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); + wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); + if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) + break; + + if (time_after(jiffies, timeout)) { + /* 1.2 check pWhalBus->uSelfClearTime if the + * timeout was reached */ + wl1271_error("soft reset timeout"); + return -1; + } + + udelay(SOFT_RESET_STALL_TIME); + } + + /* disable Rx/Tx */ + wl1271_reg_write32(wl, ENABLE, 0x0); + + /* disable auto calibration on start*/ + wl1271_reg_write32(wl, SPARE_A2, 0xffff); + + return 0; +} + +static int wl1271_boot_run_firmware(struct wl1271 *wl) +{ + int loop, ret; + u32 chip_id, interrupt; + + wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + + chip_id = wl1271_reg_read32(wl, CHIP_ID_B); + + wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); + + if (chip_id != wl->chip.id) { + wl1271_error("chip id doesn't match after firmware boot"); + return -EIO; + } + + /* wait for init to complete */ + loop = 0; + while (loop++ < INIT_LOOP) { + udelay(INIT_LOOP_DELAY); + interrupt = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + + if (interrupt == 0xffffffff) { + wl1271_error("error reading hardware complete " + "init indication"); + return -EIO; + } + /* check that ACX_INTR_INIT_COMPLETE is enabled */ + else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) { + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + WL1271_ACX_INTR_INIT_COMPLETE); + break; + } + } + + if (loop >= INIT_LOOP) { + wl1271_error("timeout waiting for the hardware to " + "complete initialization"); + return -EIO; + } + + /* get hardware config command mail box */ + wl->cmd_box_addr = wl1271_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); + + /* get hardware config event mail box */ + wl->event_box_addr = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + + /* set the working partition to its "running" mode offset */ + wl1271_set_partition(wl, + part_table[PART_WORK].mem.start, + part_table[PART_WORK].mem.size, + part_table[PART_WORK].reg.start, + part_table[PART_WORK].reg.size); + + wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", + wl->cmd_box_addr, wl->event_box_addr); + + wl1271_boot_fw_version(wl); + + /* + * in case of full asynchronous mode the firmware event must be + * ready to receive event from the command mailbox + */ + + /* enable gpio interrupts */ + wl1271_boot_enable_interrupts(wl); + + /* unmask all mbox events */ + wl->event_mask = 0xffffffff; + + ret = wl1271_event_unmask(wl); + if (ret < 0) { + wl1271_error("EVENT mask setting failed"); + return ret; + } + + wl1271_event_mbox_config(wl); + + /* firmware startup completed */ + return 0; +} + +static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) +{ + u32 polarity, status, i; + + wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY); + wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ); + + /* Wait until the command is complete (ie. bit 18 is set) */ + for (i = 0; i < OCP_CMD_LOOP; i++) { + polarity = wl1271_reg_read32(wl, OCP_DATA_READ); + if (polarity & OCP_READY_MASK) + break; + } + if (i == OCP_CMD_LOOP) { + wl1271_error("OCP command timeout!"); + return -EIO; + } + + status = polarity & OCP_STATUS_MASK; + if (status != OCP_STATUS_OK) { + wl1271_error("OCP command failed (%d)", status); + return -EIO; + } + + /* We use HIGH polarity, so unset the LOW bit */ + polarity &= ~POLARITY_LOW; + + wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY); + wl1271_reg_write32(wl, OCP_DATA_WRITE, polarity); + wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE); + + return 0; +} + +int wl1271_boot(struct wl1271 *wl) +{ + int ret = 0; + u32 tmp, clk, pause; + + if (REF_CLOCK == 0 || REF_CLOCK == 2) + /* ref clk: 19.2/38.4 */ + clk = 0x3; + else if (REF_CLOCK == 1 || REF_CLOCK == 3) + /* ref clk: 26/52 */ + clk = 0x5; + + wl1271_reg_write32(wl, PLL_PARAMETERS, clk); + + pause = wl1271_reg_read32(wl, PLL_PARAMETERS); + + wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); + + pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be + * WU_COUNTER_PAUSE_VAL instead of + * 0x3ff (magic number ). How does + * this work?! */ + pause |= WU_COUNTER_PAUSE_VAL; + wl1271_reg_write32(wl, WU_COUNTER_PAUSE, pause); + + /* Continue the ELP wake up sequence */ + wl1271_reg_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + udelay(500); + + wl1271_set_partition(wl, + part_table[PART_DRPW].mem.start, + part_table[PART_DRPW].mem.size, + part_table[PART_DRPW].reg.start, + part_table[PART_DRPW].reg.size); + + /* Read-modify-write DRPW_SCRATCH_START register (see next state) + to be used by DRPw FW. The RTRIM value will be added by the FW + before taking DRPw out of reset */ + + wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START); + clk = wl1271_reg_read32(wl, DRPW_SCRATCH_START); + + wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); + + /* 2 */ + clk |= (REF_CLOCK << 1) << 4; + wl1271_reg_write32(wl, DRPW_SCRATCH_START, clk); + + wl1271_set_partition(wl, + part_table[PART_WORK].mem.start, + part_table[PART_WORK].mem.size, + part_table[PART_WORK].reg.start, + part_table[PART_WORK].reg.size); + + /* Disable interrupts */ + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + + ret = wl1271_boot_soft_reset(wl); + if (ret < 0) + goto out; + + /* 2. start processing NVS file */ + ret = wl1271_boot_upload_nvs(wl); + if (ret < 0) + goto out; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); + + wl1271_reg_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG); + + tmp = wl1271_reg_read32(wl, CHIP_ID_B); + + wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); + + /* 6. read the EEPROM parameters */ + tmp = wl1271_reg_read32(wl, SCR_PAD2); + + ret = wl1271_boot_write_irq_polarity(wl); + if (ret < 0) + goto out; + + /* FIXME: Need to check whether this is really what we want */ + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_ALL_EVENTS_VECTOR); + + /* WL1271: The reference driver skips steps 7 to 10 (jumps directly + * to upload_fw) */ + + ret = wl1271_boot_upload_firmware(wl); + if (ret < 0) + goto out; + + /* 10.5 start firmware */ + ret = wl1271_boot_run_firmware(wl); + if (ret < 0) + goto out; + + /* set the wl1271 default filters */ + wl->rx_config = WL1271_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + + wl1271_event_mbox_config(wl); + +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h new file mode 100644 index 0000000..b0d8fb4 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_boot.h @@ -0,0 +1,72 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __BOOT_H__ +#define __BOOT_H__ + +#include "wl1271.h" + +int wl1271_boot(struct wl1271 *wl); + +#define WL1271_NO_SUBBANDS 8 +#define WL1271_NO_POWER_LEVELS 4 +#define WL1271_FW_VERSION_MAX_LEN 20 + +struct wl1271_static_data { + u8 mac_address[ETH_ALEN]; + u8 padding[2]; + u8 fw_version[WL1271_FW_VERSION_MAX_LEN]; + u32 hw_version; + u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS]; +}; + +/* number of times we try to read the INIT interrupt */ +#define INIT_LOOP 20000 + +/* delay between retries */ +#define INIT_LOOP_DELAY 50 + +#define REF_CLOCK 2 +#define WU_COUNTER_PAUSE_VAL 0x3FF +#define WELP_ARM_COMMAND_VAL 0x4 + +#define OCP_CMD_LOOP 32 + +#define OCP_CMD_WRITE 0x1 +#define OCP_CMD_READ 0x2 + +#define OCP_READY_MASK BIT(18) +#define OCP_STATUS_MASK (BIT(16) | BIT(17)) + +#define OCP_STATUS_NO_RESP 0x00000 +#define OCP_STATUS_OK 0x10000 +#define OCP_STATUS_REQ_FAILED 0x20000 +#define OCP_STATUS_RESP_ERROR 0x30000 + +#define OCP_REG_POLARITY 0x30032 + +#define CMD_MBOX_ADDRESS 0x407B4 + +#define POLARITY_LOW BIT(1) + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c new file mode 100644 index 0000000..2a4351f --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -0,0 +1,813 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include + +#include "wl1271.h" +#include "wl1271_reg.h" +#include "wl1271_spi.h" +#include "wl1271_acx.h" +#include "wl12xx_80211.h" +#include "wl1271_cmd.h" + +/* + * send command to firmware + * + * @wl: wl struct + * @id: command id + * @buf: buffer containing the command, must work with dma + * @len: length of the buffer + */ +int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) +{ + struct wl1271_cmd_header *cmd; + unsigned long timeout; + u32 intr; + int ret = 0; + + cmd = buf; + cmd->id = id; + cmd->status = 0; + + WARN_ON(len % 4 != 0); + + wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len); + + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + + timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); + + intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { + if (time_after(jiffies, timeout)) { + wl1271_error("command complete timeout"); + ret = -ETIMEDOUT; + goto out; + } + + msleep(1); + + intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + } + + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + WL1271_ACX_INTR_CMD_COMPLETE); + +out: + return ret; +} + +int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) +{ + struct wl1271_cmd_cal_channel_tune *cmd; + int ret = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->test.id = TEST_CMD_CHANNEL_TUNE; + + cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4; + /* set up any channel, 7 is in the middle of the range */ + cmd->channel = 7; + + ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); + if (ret < 0) + wl1271_warning("TEST_CMD_CHANNEL_TUNE failed"); + + kfree(cmd); + return ret; +} + +int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) +{ + struct wl1271_cmd_cal_update_ref_point *cmd; + int ret = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT; + + /* FIXME: still waiting for the correct values */ + cmd->ref_power = 0; + cmd->ref_detector = 0; + + cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G; + + ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); + if (ret < 0) + wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed"); + + kfree(cmd); + return ret; +} + +int wl1271_cmd_cal_p2g(struct wl1271 *wl) +{ + struct wl1271_cmd_cal_p2g *cmd; + int ret = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->test.id = TEST_CMD_P2G_CAL; + + cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G; + + ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); + if (ret < 0) + wl1271_warning("TEST_CMD_P2G_CAL failed"); + + kfree(cmd); + return ret; +} + +int wl1271_cmd_cal(struct wl1271 *wl) +{ + /* + * FIXME: we must make sure that we're not sleeping when calibration + * is done + */ + int ret; + + wl1271_notice("performing tx calibration"); + + ret = wl1271_cmd_cal_channel_tune(wl); + if (ret < 0) + return ret; + + ret = wl1271_cmd_cal_update_ref_point(wl); + if (ret < 0) + return ret; + + ret = wl1271_cmd_cal_p2g(wl); + if (ret < 0) + return ret; + + return ret; +} + +int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait) +{ + static bool do_cal = true; + unsigned long timeout; + struct wl1271_cmd_join *join; + int ret, i; + u8 *bssid; + + /* FIXME: remove when we get calibration from the factory */ + if (do_cal) { + ret = wl1271_cmd_cal(wl); + if (ret < 0) + wl1271_warning("couldn't calibrate"); + else + do_cal = false; + } + + + join = kzalloc(sizeof(*join), GFP_KERNEL); + if (!join) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd join"); + + /* Reverse order BSSID */ + bssid = (u8 *) &join->bssid_lsb; + for (i = 0; i < ETH_ALEN; i++) + bssid[i] = wl->bssid[ETH_ALEN - i - 1]; + + join->rx_config_options = wl->rx_config; + join->rx_filter_options = wl->rx_filter; + + join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | + RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; + + join->beacon_interval = beacon_interval; + join->dtim_interval = dtim_interval; + join->bss_type = bss_type; + join->channel = wl->channel; + join->ssid_len = wl->ssid_len; + memcpy(join->ssid, wl->ssid, wl->ssid_len); + join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH; + + /* increment the session counter */ + wl->session_counter++; + if (wl->session_counter >= SESSION_COUNTER_MAX) + wl->session_counter = 0; + + join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; + + + ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); + if (ret < 0) { + wl1271_error("failed to initiate cmd join"); + goto out_free; + } + + timeout = msecs_to_jiffies(JOIN_TIMEOUT); + + /* + * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to + * simplify locking we just sleep instead, for now + */ + if (wait) + msleep(10); + +out_free: + kfree(join); + +out: + return ret; +} + +/** + * send test command to firmware + * + * @wl: wl struct + * @buf: buffer containing the command, with all headers, must work with dma + * @len: length of the buffer + * @answer: is answer needed + */ +int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) +{ + int ret; + + wl1271_debug(DEBUG_CMD, "cmd test"); + + ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len); + + if (ret < 0) { + wl1271_warning("TEST command failed"); + return ret; + } + + if (answer) { + struct wl1271_command *cmd_answer; + + /* + * The test command got in, we can read the answer. + * The answer would be a wl1271_command, where the + * parameter array contains the actual answer. + */ + wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + + cmd_answer = buf; + + if (cmd_answer->header.status != CMD_STATUS_SUCCESS) + wl1271_error("TEST command answer error: %d", + cmd_answer->header.status); + } + + return 0; +} + +/** + * read acx from firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer for the response, including all headers, must work with dma + * @len: lenght of buf + */ +int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd interrogate"); + + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_error("INTERROGATE command failed"); + goto out; + } + + /* the interrogate command got in, we can read the answer */ + wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, len); + + acx = buf; + if (acx->cmd.status != CMD_STATUS_SUCCESS) + wl1271_error("INTERROGATE command error: %d", + acx->cmd.status); + +out: + return ret; +} + +/** + * write acx value to firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer containing acx, including all headers, must work with dma + * @len: length of buf + */ +int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd configure"); + + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len); + if (ret < 0) { + wl1271_warning("CONFIGURE command NOK"); + return ret; + } + + return 0; +} + +int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) +{ + struct cmd_enabledisable_path *cmd; + int ret; + u16 cmd_rx, cmd_tx; + + wl1271_debug(DEBUG_CMD, "cmd data path"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->channel = channel; + + if (enable) { + cmd_rx = CMD_ENABLE_RX; + cmd_tx = CMD_ENABLE_TX; + } else { + cmd_rx = CMD_DISABLE_RX; + cmd_tx = CMD_DISABLE_TX; + } + + ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_error("rx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + goto out; + } + + wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", + enable ? "start" : "stop", channel); + + ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_error("tx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + return ret; + } + + wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", + enable ? "start" : "stop", channel); + +out: + kfree(cmd); + return ret; +} + +int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) +{ + struct wl1271_cmd_ps_params *ps_params = NULL; + int ret = 0; + + /* FIXME: this should be in ps.c */ + ret = wl1271_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); + if (ret < 0) { + wl1271_error("couldn't set wake up conditions"); + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd set ps mode"); + + ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); + if (!ps_params) { + ret = -ENOMEM; + goto out; + } + + ps_params->ps_mode = ps_mode; + ps_params->send_null_data = 1; + ps_params->retries = 5; + ps_params->hang_over_period = 128; + ps_params->null_data_rate = 1; /* 1 Mbps */ + + ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, + sizeof(*ps_params)); + if (ret < 0) { + wl1271_error("cmd set_ps_mode failed"); + goto out; + } + +out: + kfree(ps_params); + return ret; +} + +int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, + size_t len) +{ + struct cmd_read_write_memory *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd read memory"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + WARN_ON(len > MAX_READ_SIZE); + len = min_t(size_t, len, MAX_READ_SIZE); + + cmd->addr = addr; + cmd->size = len; + + ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_error("read memory command failed: %d", ret); + goto out; + } + + /* the read command got in, we can now read the answer */ + wl1271_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + + if (cmd->header.status != CMD_STATUS_SUCCESS) + wl1271_error("error in read command result: %d", + cmd->header.status); + + memcpy(answer, cmd->value, len); + +out: + kfree(cmd); + return ret; +} + +int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, + u8 active_scan, u8 high_prio, u8 num_channels, + u8 probe_requests) +{ + + struct wl1271_cmd_trigger_scan_to *trigger = NULL; + struct wl1271_cmd_scan *params = NULL; + int i, ret; + u16 scan_options = 0; + + if (wl->scanning) + return -EINVAL; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + + params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); + params->params.rx_filter_options = + cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); + + if (!active_scan) + scan_options |= WL1271_SCAN_OPT_PASSIVE; + if (high_prio) + scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; + params->params.scan_options = scan_options; + + params->params.num_channels = num_channels; + params->params.num_probe_requests = probe_requests; + params->params.tx_rate = cpu_to_le32(RATE_MASK_2MBPS); + params->params.tid_trigger = 0; + params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; + + for (i = 0; i < num_channels; i++) { + params->channels[i].min_duration = + cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); + params->channels[i].max_duration = + cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); + memset(¶ms->channels[i].bssid_lsb, 0xff, 4); + memset(¶ms->channels[i].bssid_msb, 0xff, 2); + params->channels[i].early_termination = 0; + params->channels[i].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR; + params->channels[i].channel = i + 1; + } + + if (len && ssid) { + params->params.ssid_len = len; + memcpy(params->params.ssid, ssid, len); + } + + ret = wl1271_cmd_build_probe_req(wl, ssid, len); + if (ret < 0) { + wl1271_error("PROBE request template failed"); + goto out; + } + + trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); + if (!trigger) { + ret = -ENOMEM; + goto out; + } + + /* disable the timeout */ + trigger->timeout = 0; + + ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + sizeof(*trigger)); + if (ret < 0) { + wl1271_error("trigger scan to failed for hw scan"); + goto out; + } + + wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); + + wl->scanning = true; + + ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); + if (ret < 0) { + wl1271_error("SCAN failed"); + goto out; + } + + wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); + + if (params->header.status != CMD_STATUS_SUCCESS) { + wl1271_error("Scan command error: %d", + params->header.status); + wl->scanning = false; + ret = -EIO; + goto out; + } + +out: + kfree(params); + return ret; +} + +int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, + void *buf, size_t buf_len) +{ + struct wl1271_cmd_template_set *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id); + + WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); + buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->len = cpu_to_le16(buf_len); + cmd->template_type = template_id; + cmd->enabled_rates = ACX_RATE_MASK_UNSPECIFIED; + cmd->short_retry_limit = ACX_RATE_RETRY_LIMIT; + cmd->long_retry_limit = ACX_RATE_RETRY_LIMIT; + + if (buf) + memcpy(cmd->template_data, buf, buf_len); + + ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_warning("cmd set_template failed: %d", ret); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +static int wl1271_build_basic_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + + return index; +} + +static int wl1271_build_extended_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_OFDM_RATE_6MB; + rates[index++] = IEEE80211_OFDM_RATE_9MB; + rates[index++] = IEEE80211_OFDM_RATE_12MB; + rates[index++] = IEEE80211_OFDM_RATE_18MB; + rates[index++] = IEEE80211_OFDM_RATE_24MB; + rates[index++] = IEEE80211_OFDM_RATE_36MB; + rates[index++] = IEEE80211_OFDM_RATE_48MB; + rates[index++] = IEEE80211_OFDM_RATE_54MB; + + return index; +} + +int wl1271_cmd_build_null_data(struct wl1271 *wl) +{ + struct wl12xx_null_data_template template; + + if (!is_zero_ether_addr(wl->bssid)) { + memcpy(template.header.da, wl->bssid, ETH_ALEN); + memcpy(template.header.bssid, wl->bssid, ETH_ALEN); + } else { + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + } + + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC); + + return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template, + sizeof(template)); + +} + +int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) +{ + struct wl12xx_ps_poll_template template; + + memcpy(template.bssid, wl->bssid, ETH_ALEN); + memcpy(template.ta, wl->mac_addr, ETH_ALEN); + template.aid = aid; + template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); + + return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template, + sizeof(template)); + +} + +int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len) +{ + struct wl12xx_probe_req_template template; + struct wl12xx_ie_rates *rates; + char *ptr; + u16 size; + + ptr = (char *)&template; + size = sizeof(struct ieee80211_header); + + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + + /* IEs */ + /* SSID */ + template.ssid.header.id = WLAN_EID_SSID; + template.ssid.header.len = ssid_len; + if (ssid_len && ssid) + memcpy(template.ssid.ssid, ssid, ssid_len); + size += sizeof(struct wl12xx_ie_header) + ssid_len; + ptr += size; + + /* Basic Rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_SUPP_RATES; + rates->header.len = wl1271_build_basic_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; + + /* Extended rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_EXT_SUPP_RATES; + rates->header.len = wl1271_build_extended_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + + wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); + + return wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, + &template, size); +} + +int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) +{ + struct wl1271_cmd_set_keys *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->id = id; + cmd->key_action = KEY_SET_ID; + cmd->key_type = KEY_WEP; + + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_warning("cmd set_default_wep_key failed: %d", ret); + goto out; + } + +out: + kfree(cmd); + + return ret; +} + +int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, const u8 *addr) +{ + struct wl1271_cmd_set_keys *cmd; + int ret = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + if (key_type != KEY_WEP) + memcpy(cmd->addr, addr, ETH_ALEN); + + cmd->key_action = action; + cmd->key_size = key_size; + cmd->key_type = key_type; + + /* we have only one SSID profile */ + cmd->ssid_profile = 0; + + cmd->id = id; + + /* FIXME: this is from wl1251, needs to be checked */ + if (key_type == KEY_TKIP) { + /* + * We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(cmd->key, key, 16); + memcpy(cmd->key + 16, key + 24, 8); + memcpy(cmd->key + 24, key + 16, 8); + + } else { + memcpy(cmd->key, key, key_size); + } + + wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_warning("could not set keys"); + goto out; + } + +out: + kfree(cmd); + + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h new file mode 100644 index 0000000..951a844 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -0,0 +1,464 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_CMD_H__ +#define __WL1271_CMD_H__ + +#include "wl1271.h" + +struct acx_header; + +int wl1271_cmd_send(struct wl1271 *wl, u16 type, void *buf, size_t buf_len); +int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait); +int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); +int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); +int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); +int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable); +int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode); +int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, + size_t len); +int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, + u8 active_scan, u8 high_prio, u8 num_channels, + u8 probe_requests); +int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, + void *buf, size_t buf_len); +int wl1271_cmd_build_null_data(struct wl1271 *wl); +int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); +int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len); +int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); +int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, const u8 *addr); + +enum wl1271_commands { + CMD_INTERROGATE = 1, /*use this to read information elements*/ + CMD_CONFIGURE = 2, /*use this to write information elements*/ + CMD_ENABLE_RX = 3, + CMD_ENABLE_TX = 4, + CMD_DISABLE_RX = 5, + CMD_DISABLE_TX = 6, + CMD_SCAN = 8, + CMD_STOP_SCAN = 9, + CMD_START_JOIN = 11, + CMD_SET_KEYS = 12, + CMD_READ_MEMORY = 13, + CMD_WRITE_MEMORY = 14, + CMD_SET_TEMPLATE = 19, + CMD_TEST = 23, + CMD_NOISE_HIST = 28, + CMD_LNA_CONTROL = 32, + CMD_SET_BCN_MODE = 33, + CMD_MEASUREMENT = 34, + CMD_STOP_MEASUREMENT = 35, + CMD_DISCONNECT = 36, + CMD_SET_PS_MODE = 37, + CMD_CHANNEL_SWITCH = 38, + CMD_STOP_CHANNEL_SWICTH = 39, + CMD_AP_DISCOVERY = 40, + CMD_STOP_AP_DISCOVERY = 41, + CMD_SPS_SCAN = 42, + CMD_STOP_SPS_SCAN = 43, + CMD_HEALTH_CHECK = 45, + CMD_DEBUG = 46, + CMD_TRIGGER_SCAN_TO = 47, + CMD_CONNECTION_SCAN_CFG = 48, + CMD_CONNECTION_SCAN_SSID_CFG = 49, + CMD_START_PERIODIC_SCAN = 50, + CMD_STOP_PERIODIC_SCAN = 51, + CMD_SET_STA_STATE = 52, + + NUM_COMMANDS, + MAX_COMMAND_ID = 0xFFFF, +}; + +#define MAX_CMD_PARAMS 572 + +enum cmd_templ { + CMD_TEMPL_NULL_DATA = 0, + CMD_TEMPL_BEACON, + CMD_TEMPL_CFG_PROBE_REQ_2_4, + CMD_TEMPL_CFG_PROBE_REQ_5, + CMD_TEMPL_PROBE_RESPONSE, + CMD_TEMPL_QOS_NULL_DATA, + CMD_TEMPL_PS_POLL, + CMD_TEMPL_KLV, + CMD_TEMPL_DISCONNECT, + CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */ + CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */ + CMD_TEMPL_BAR, /* for firmware internal use only */ + CMD_TEMPL_CTS, /* + * For CTS-to-self (FastCTS) mechanism + * for BT/WLAN coexistence (SoftGemini). */ + CMD_TEMPL_MAX = 0xff +}; + +/* unit ms */ +#define WL1271_COMMAND_TIMEOUT 2000 +#define WL1271_CMD_TEMPL_MAX_SIZE 252 + +struct wl1271_cmd_header { + u16 id; + u16 status; + /* payload */ + u8 data[0]; +} __attribute__ ((packed)); + +#define WL1271_CMD_MAX_PARAMS 572 + +struct wl1271_command { + struct wl1271_cmd_header header; + u8 parameters[WL1271_CMD_MAX_PARAMS]; +} __attribute__ ((packed)); + +enum { + CMD_MAILBOX_IDLE = 0, + CMD_STATUS_SUCCESS = 1, + CMD_STATUS_UNKNOWN_CMD = 2, + CMD_STATUS_UNKNOWN_IE = 3, + CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, + CMD_STATUS_RX_BUSY = 13, + CMD_STATUS_INVALID_PARAM = 14, + CMD_STATUS_TEMPLATE_TOO_LARGE = 15, + CMD_STATUS_OUT_OF_MEMORY = 16, + CMD_STATUS_STA_TABLE_FULL = 17, + CMD_STATUS_RADIO_ERROR = 18, + CMD_STATUS_WRONG_NESTING = 19, + CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ + CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ + MAX_COMMAND_STATUS = 0xff +}; + + +/* + * CMD_READ_MEMORY + * + * The host issues this command to read the WiLink device memory/registers. + * + * Note: The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +/* + * CMD_WRITE_MEMORY + * + * The host issues this command to write the WiLink device memory/registers. + * + * The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +#define MAX_READ_SIZE 256 + +struct cmd_read_write_memory { + struct wl1271_cmd_header header; + + /* The address of the memory to read from or write to.*/ + u32 addr; + + /* The amount of data in bytes to read from or write to the WiLink + * device.*/ + u32 size; + + /* The actual value read from or written to the Wilink. The source + of this field is the Host in WRITE command or the Wilink in READ + command. */ + u8 value[MAX_READ_SIZE]; +}; + +#define CMDMBOX_HEADER_LEN 4 +#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 + +enum { + BSS_TYPE_IBSS = 0, + BSS_TYPE_STA_BSS = 2, + BSS_TYPE_AP_BSS = 3, + MAX_BSS_TYPE = 0xFF +}; + +#define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ +#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 + +struct wl1271_cmd_join { + struct wl1271_cmd_header header; + + u32 bssid_lsb; + u16 bssid_msb; + u16 beacon_interval; /* in TBTTs */ + u32 rx_config_options; + u32 rx_filter_options; + + /* + * The target uses this field to determine the rate at + * which to transmit control frame responses (such as + * ACK or CTS frames). + */ + u32 basic_rate_set; + u8 dtim_interval; + /* + * bits 0-2: This bitwise field specifies the type + * of BSS to start or join (BSS_TYPE_*). + * bit 4: Band - The radio band in which to join + * or start. + * 0 - 2.4GHz band + * 1 - 5GHz band + * bits 3, 5-7: Reserved + */ + u8 bss_type; + u8 channel; + u8 ssid_len; + u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ctrl; /* JOIN_CMD_CTRL_* */ + u8 reserved[3]; +} __attribute__ ((packed)); + +struct cmd_enabledisable_path { + struct wl1271_cmd_header header; + + u8 channel; + u8 padding[3]; +} __attribute__ ((packed)); + +struct wl1271_cmd_template_set { + struct wl1271_cmd_header header; + + u16 len; + u8 template_type; + u8 index; /* relevant only for KLV_TEMPLATE type */ + u32 enabled_rates; + u8 short_retry_limit; + u8 long_retry_limit; + u8 aflags; + u8 reserved; + u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE]; +} __attribute__ ((packed)); + +#define TIM_ELE_ID 5 +#define PARTIAL_VBM_MAX 251 + +struct wl1271_tim { + u8 identity; + u8 length; + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ +} __attribute__ ((packed)); + +enum wl1271_cmd_ps_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct wl1271_cmd_ps_params { + struct wl1271_cmd_header header; + + u8 ps_mode; /* STATION_* */ + u8 send_null_data; /* Do we have to send NULL data packet ? */ + u8 retries; /* Number of retires for the initial NULL data packet */ + + /* + * TUs during which the target stays awake after switching + * to power save mode. + */ + u8 hang_over_period; + u32 null_data_rate; +} __attribute__ ((packed)); + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 +#define MAX_KEY_SIZE 32 + +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +/* When set, disable HW decryption */ +#define DF_SNIFF_MODE_ENABLE 0x80 + +enum wl1271_cmd_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum wl1271_cmd_key_type { + KEY_NONE = 0, + KEY_WEP = 1, + KEY_TKIP = 2, + KEY_AES = 3, + KEY_GEM = 4 +}; + +/* FIXME: Add description for key-types */ + +struct wl1271_cmd_set_keys { + struct wl1271_cmd_header header; + + /* Ignored for default WEP key */ + u8 addr[ETH_ALEN]; + + /* key_action_e */ + u16 key_action; + + u16 reserved_1; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + u8 ssid_profile; + + /* + * TKIP, AES: frame's key id field. + * For WEP default key: key id; + */ + u8 id; + u8 reserved_2[6]; + u8 key[MAX_KEY_SIZE]; + u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __attribute__ ((packed)); + + +#define WL1271_SCAN_MAX_CHANNELS 24 +#define WL1271_SCAN_DEFAULT_TAG 1 +#define WL1271_SCAN_CURRENT_TX_PWR 0 +#define WL1271_SCAN_OPT_ACTIVE 0 +#define WL1271_SCAN_OPT_PASSIVE 1 +#define WL1271_SCAN_OPT_PRIORITY_HIGH 4 +#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */ +#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */ + +struct basic_scan_params { + u32 rx_config_options; + u32 rx_filter_options; + /* Scan option flags (WL1271_SCAN_OPT_*) */ + u16 scan_options; + /* Number of scan channels in the list (maximum 30) */ + u8 num_channels; + /* This field indicates the number of probe requests to send + per channel for an active scan */ + u8 num_probe_requests; + /* Rate bit field for sending the probes */ + u32 tx_rate; + u8 tid_trigger; + u8 ssid_len; + /* in order to align */ + u8 padding1[2]; + u8 ssid[IW_ESSID_MAX_SIZE]; + /* Band to scan */ + u8 band; + u8 use_ssid_list; + u8 scan_tag; + u8 padding2; +} __attribute__ ((packed)); + +struct basic_scan_channel_params { + /* Duration in TU to wait for frames on a channel for active scan */ + u32 min_duration; + u32 max_duration; + u32 bssid_lsb; + u16 bssid_msb; + u8 early_termination; + u8 tx_power_att; + u8 channel; + /* FW internal use only! */ + u8 dfs_candidate; + u8 activity_detected; + u8 pad; +} __attribute__ ((packed)); + +struct wl1271_cmd_scan { + struct wl1271_cmd_header header; + + struct basic_scan_params params; + struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; +} __attribute__ ((packed)); + +struct wl1271_cmd_trigger_scan_to { + struct wl1271_cmd_header header; + + u32 timeout; +}; + +struct wl1271_cmd_test_header { + u8 id; + u8 padding[3]; +}; + +enum wl1271_channel_tune_bands { + WL1271_CHANNEL_TUNE_BAND_2_4, + WL1271_CHANNEL_TUNE_BAND_5, + WL1271_CHANNEL_TUNE_BAND_4_9 +}; + +#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 + +#define TEST_CMD_P2G_CAL 0x02 +#define TEST_CMD_CHANNEL_TUNE 0x0d +#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d + +struct wl1271_cmd_cal_channel_tune { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + u8 band; + u8 channel; + + u16 radio_status; +} __attribute__ ((packed)); + +struct wl1271_cmd_cal_update_ref_point { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + s32 ref_power; + s32 ref_detector; + u8 sub_band; + u8 padding[3]; +} __attribute__ ((packed)); + +#define MAX_TLV_LENGTH 400 +#define MAX_NVS_VERSION_LENGTH 12 + +#define WL1271_CAL_P2G_BAND_B_G BIT(0) + +struct wl1271_cmd_cal_p2g { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + u16 len; + u8 buf[MAX_TLV_LENGTH]; + u8 type; + u8 padding; + + s16 radio_status; + u8 nvs_version[MAX_NVS_VERSION_LENGTH]; + + u8 sub_band_mask; + u8 padding2; +} __attribute__ ((packed)); + +#endif /* __WL1271_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c new file mode 100644 index 0000000..c1805e5 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c @@ -0,0 +1,518 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1271_debugfs.h" + +#include + +#include "wl1271.h" +#include "wl1271_acx.h" +#include "wl1271_ps.h" + +/* ms */ +#define WL1271_DEBUGFS_STATS_LIFETIME 1000 + +/* debugfs macros idea from mac80211 */ + +#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ +static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl1271 *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + res = scnprintf(buf, buflen, fmt "\n", ##value); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = wl1271_open_file_generic, \ +}; + +#define DEBUGFS_ADD(name, parent) \ + wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ + wl, &name## _ops); \ + if (IS_ERR(wl->debugfs.name)) { \ + ret = PTR_ERR(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + goto out; \ + } + +#define DEBUGFS_DEL(name) \ + do { \ + debugfs_remove(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + } while (0) + +#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ +static ssize_t sub## _ ##name## _read(struct file *file, \ + char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl1271 *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + wl1271_debugfs_update_stats(wl); \ + \ + res = scnprintf(buf, buflen, fmt "\n", \ + wl->stats.fw_stats->sub.name); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations sub## _ ##name## _ops = { \ + .read = sub## _ ##name## _read, \ + .open = wl1271_open_file_generic, \ +}; + +#define DEBUGFS_FWSTATS_ADD(sub, name) \ + DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) + +#define DEBUGFS_FWSTATS_DEL(sub, name) \ + DEBUGFS_DEL(sub## _ ##name) + +static void wl1271_debugfs_update_stats(struct wl1271 *wl) +{ + int ret; + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if (wl->state == WL1271_STATE_ON && + time_after(jiffies, wl->stats.fw_stats_update + + msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) { + wl1271_acx_statistics(wl, wl->stats.fw_stats); + wl->stats.fw_stats_update = jiffies; + } + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1271_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); +/* skipping wep.reserved */ +DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); +/* skipping cont_miss_bcns_spread for now */ +DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, + 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); + +DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); +DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", + wl->stats.excessive_retries); + +static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + u32 queue_len; + char buf[20]; + int res; + + queue_len = skb_queue_len(&wl->tx_queue); + + res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +static const struct file_operations tx_queue_len_ops = { + .read = tx_queue_len_read, + .open = wl1271_open_file_generic, +}; + +static void wl1271_debugfs_delete_files(struct wl1271 *wl) +{ + DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_DEL(rx, out_of_mem); + DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); + DEBUGFS_FWSTATS_DEL(rx, hw_stuck); + DEBUGFS_FWSTATS_DEL(rx, dropped); + DEBUGFS_FWSTATS_DEL(rx, fcs_err); + DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_DEL(rx, path_reset); + DEBUGFS_FWSTATS_DEL(rx, reset_counter); + + DEBUGFS_FWSTATS_DEL(dma, rx_requested); + DEBUGFS_FWSTATS_DEL(dma, rx_errors); + DEBUGFS_FWSTATS_DEL(dma, tx_requested); + DEBUGFS_FWSTATS_DEL(dma, tx_errors); + + DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); + DEBUGFS_FWSTATS_DEL(isr, fiqs); + DEBUGFS_FWSTATS_DEL(isr, rx_headers); + DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_DEL(isr, rx_rdys); + DEBUGFS_FWSTATS_DEL(isr, irqs); + DEBUGFS_FWSTATS_DEL(isr, tx_procs); + DEBUGFS_FWSTATS_DEL(isr, decrypt_done); + DEBUGFS_FWSTATS_DEL(isr, dma0_done); + DEBUGFS_FWSTATS_DEL(isr, dma1_done); + DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); + DEBUGFS_FWSTATS_DEL(isr, commands); + DEBUGFS_FWSTATS_DEL(isr, rx_procs); + DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); + DEBUGFS_FWSTATS_DEL(isr, pci_pm); + DEBUGFS_FWSTATS_DEL(isr, wakeups); + DEBUGFS_FWSTATS_DEL(isr, low_rssi); + + DEBUGFS_FWSTATS_DEL(wep, addr_key_count); + DEBUGFS_FWSTATS_DEL(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_DEL(wep, key_not_found); + DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); + DEBUGFS_FWSTATS_DEL(wep, packets); + DEBUGFS_FWSTATS_DEL(wep, interrupt); + + DEBUGFS_FWSTATS_DEL(pwr, ps_enter); + DEBUGFS_FWSTATS_DEL(pwr, elp_enter); + DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); + DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); + DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_DEL(pwr, power_save_off); + DEBUGFS_FWSTATS_DEL(pwr, enable_ps); + DEBUGFS_FWSTATS_DEL(pwr, disable_ps); + DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_DEL(mic, rx_pkts); + DEBUGFS_FWSTATS_DEL(mic, calc_failure); + + DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_DEL(event, heart_beat); + DEBUGFS_FWSTATS_DEL(event, calibration); + DEBUGFS_FWSTATS_DEL(event, rx_mismatch); + DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); + DEBUGFS_FWSTATS_DEL(event, rx_pool); + DEBUGFS_FWSTATS_DEL(event, oom_late); + DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); + DEBUGFS_FWSTATS_DEL(event, tx_stuck); + + DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); + DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); + + DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_DEL(tx_queue_len); + DEBUGFS_DEL(retry_count); + DEBUGFS_DEL(excessive_retries); +} + +static int wl1271_debugfs_add_files(struct wl1271 *wl) +{ + int ret = 0; + + DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_ADD(rx, out_of_mem); + DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); + DEBUGFS_FWSTATS_ADD(rx, hw_stuck); + DEBUGFS_FWSTATS_ADD(rx, dropped); + DEBUGFS_FWSTATS_ADD(rx, fcs_err); + DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_ADD(rx, path_reset); + DEBUGFS_FWSTATS_ADD(rx, reset_counter); + + DEBUGFS_FWSTATS_ADD(dma, rx_requested); + DEBUGFS_FWSTATS_ADD(dma, rx_errors); + DEBUGFS_FWSTATS_ADD(dma, tx_requested); + DEBUGFS_FWSTATS_ADD(dma, tx_errors); + + DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); + DEBUGFS_FWSTATS_ADD(isr, fiqs); + DEBUGFS_FWSTATS_ADD(isr, rx_headers); + DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_ADD(isr, rx_rdys); + DEBUGFS_FWSTATS_ADD(isr, irqs); + DEBUGFS_FWSTATS_ADD(isr, tx_procs); + DEBUGFS_FWSTATS_ADD(isr, decrypt_done); + DEBUGFS_FWSTATS_ADD(isr, dma0_done); + DEBUGFS_FWSTATS_ADD(isr, dma1_done); + DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); + DEBUGFS_FWSTATS_ADD(isr, commands); + DEBUGFS_FWSTATS_ADD(isr, rx_procs); + DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); + DEBUGFS_FWSTATS_ADD(isr, pci_pm); + DEBUGFS_FWSTATS_ADD(isr, wakeups); + DEBUGFS_FWSTATS_ADD(isr, low_rssi); + + DEBUGFS_FWSTATS_ADD(wep, addr_key_count); + DEBUGFS_FWSTATS_ADD(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_ADD(wep, key_not_found); + DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); + DEBUGFS_FWSTATS_ADD(wep, packets); + DEBUGFS_FWSTATS_ADD(wep, interrupt); + + DEBUGFS_FWSTATS_ADD(pwr, ps_enter); + DEBUGFS_FWSTATS_ADD(pwr, elp_enter); + DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); + DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); + DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_ADD(pwr, power_save_off); + DEBUGFS_FWSTATS_ADD(pwr, enable_ps); + DEBUGFS_FWSTATS_ADD(pwr, disable_ps); + DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_ADD(mic, rx_pkts); + DEBUGFS_FWSTATS_ADD(mic, calc_failure); + + DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_ADD(event, heart_beat); + DEBUGFS_FWSTATS_ADD(event, calibration); + DEBUGFS_FWSTATS_ADD(event, rx_mismatch); + DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); + DEBUGFS_FWSTATS_ADD(event, rx_pool); + DEBUGFS_FWSTATS_ADD(event, oom_late); + DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); + DEBUGFS_FWSTATS_ADD(event, tx_stuck); + + DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); + DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); + + DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); + DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); + DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); + +out: + if (ret < 0) + wl1271_debugfs_delete_files(wl); + + return ret; +} + +void wl1271_debugfs_reset(struct wl1271 *wl) +{ + memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); + wl->stats.retry_count = 0; + wl->stats.excessive_retries = 0; +} + +int wl1271_debugfs_init(struct wl1271 *wl) +{ + int ret; + + wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + if (IS_ERR(wl->debugfs.rootdir)) { + ret = PTR_ERR(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + goto err; + } + + wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", + wl->debugfs.rootdir); + + if (IS_ERR(wl->debugfs.fw_statistics)) { + ret = PTR_ERR(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + goto err_root; + } + + wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), + GFP_KERNEL); + + if (!wl->stats.fw_stats) { + ret = -ENOMEM; + goto err_fw; + } + + wl->stats.fw_stats_update = jiffies; + + ret = wl1271_debugfs_add_files(wl); + + if (ret < 0) + goto err_file; + + return 0; + +err_file: + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + +err_fw: + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + +err_root: + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +err: + return ret; +} + +void wl1271_debugfs_exit(struct wl1271 *wl) +{ + wl1271_debugfs_delete_files(wl); + + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +} diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.h b/drivers/net/wireless/wl12xx/wl1271_debugfs.h new file mode 100644 index 0000000..00a45b2 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.h @@ -0,0 +1,33 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef WL1271_DEBUGFS_H +#define WL1271_DEBUGFS_H + +#include "wl1271.h" + +int wl1271_debugfs_init(struct wl1271 *wl); +void wl1271_debugfs_exit(struct wl1271 *wl); +void wl1271_debugfs_reset(struct wl1271 *wl); + +#endif /* WL1271_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c new file mode 100644 index 0000000..f3afd4a --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -0,0 +1,125 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1271.h" +#include "wl1271_reg.h" +#include "wl1271_spi.h" +#include "wl1271_event.h" +#include "wl1271_ps.h" + +static int wl1271_event_scan_complete(struct wl1271 *wl, + struct event_mailbox *mbox) +{ + wl1271_debug(DEBUG_EVENT, "status: 0x%x", + mbox->scheduled_scan_status); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, false); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + return 0; +} + +static void wl1271_event_mbox_dump(struct event_mailbox *mbox) +{ + wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); + wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); + wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); +} + +static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) +{ + int ret; + u32 vector; + + wl1271_event_mbox_dump(mbox); + + vector = mbox->events_vector & ~(mbox->events_mask); + wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); + + if (vector & SCAN_COMPLETE_EVENT_ID) { + ret = wl1271_event_scan_complete(wl, mbox); + if (ret < 0) + return ret; + } + + if (vector & BSS_LOSE_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); + + if (wl->psm_requested && wl->psm) { + ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + } + } + + return 0; +} + +int wl1271_event_unmask(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask)); + if (ret < 0) + return ret; + + return 0; +} + +void wl1271_event_mbox_config(struct wl1271 *wl) +{ + wl->mbox_ptr[0] = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); + + wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", + wl->mbox_ptr[0], wl->mbox_ptr[1]); +} + +int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) +{ + struct event_mailbox mbox; + int ret; + + wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); + + if (mbox_num > 1) + return -EINVAL; + + /* first we read the mbox descriptor */ + wl1271_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, + sizeof(struct event_mailbox)); + + /* process the descriptor */ + ret = wl1271_event_process(wl, &mbox); + if (ret < 0) + return ret; + + /* then we let the firmware know it can go on...*/ + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h new file mode 100644 index 0000000..2cdce7c --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_event.h @@ -0,0 +1,110 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_EVENT_H__ +#define __WL1271_EVENT_H__ + +/* + * Mbox events + * + * The event mechanism is based on a pair of event buffers (buffers A and + * B) at fixed locations in the target's memory. The host processes one + * buffer while the other buffer continues to collect events. If the host + * is not processing events, an interrupt is issued to signal that a buffer + * is ready. Once the host is done with processing events from one buffer, + * it signals the target (with an ACK interrupt) that the event buffer is + * free. + */ + +enum { + MEASUREMENT_START_EVENT_ID = BIT(8), + MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), + SCAN_COMPLETE_EVENT_ID = BIT(10), + SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11), + AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), + PS_REPORT_EVENT_ID = BIT(13), + PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), + DISCONNECT_EVENT_COMPLETE_ID = BIT(15), + JOIN_EVENT_COMPLETE_ID = BIT(16), + CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), + BSS_LOSE_EVENT_ID = BIT(18), + REGAINED_BSS_EVENT_ID = BIT(19), + ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), + SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), + SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), + SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), + PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), + DBG_EVENT_ID = BIT(26), + HEALTH_CHECK_REPLY_EVENT_ID = BIT(27), + PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), + PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), + BA_SESSION_TEAR_DOWN_EVENT_ID = BIT(30), + EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, +}; + +struct event_debug_report { + u8 debug_event_id; + u8 num_params; + u16 pad; + u32 report_1; + u32 report_2; + u32 report_3; +} __attribute__ ((packed)); + +#define NUM_OF_RSSI_SNR_TRIGGERS 8 + +struct event_mailbox { + u32 events_vector; + u32 events_mask; + u32 reserved_1; + u32 reserved_2; + + u8 dbg_event_id; + u8 num_relevant_params; + u16 reserved_3; + u32 event_report_p1; + u32 event_report_p2; + u32 event_report_p3; + + u8 number_of_scan_results; + u8 scan_tag; + u8 reserved_4[2]; + u32 compl_scheduled_scan_status; + + u16 scheduled_scan_attended_channels; + u8 soft_gemini_sense_info; + u8 soft_gemini_protective_info; + s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; + u8 channel_switch_status; + u8 scheduled_scan_status; + u8 ps_status; + + u8 reserved_5[29]; +} __attribute__ ((packed)); + +int wl1271_event_unmask(struct wl1271 *wl); +void wl1271_event_mbox_config(struct wl1271 *wl); +int wl1271_event_handle(struct wl1271 *wl, u8 mbox); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c new file mode 100644 index 0000000..490df21 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -0,0 +1,397 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl1271_init.h" +#include "wl12xx_80211.h" +#include "wl1271_acx.h" +#include "wl1271_cmd.h" +#include "wl1271_reg.h" + +static int wl1271_init_hwenc_config(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_feature_cfg(wl); + if (ret < 0) { + wl1271_warning("couldn't set feature config"); + return ret; + } + + ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key); + if (ret < 0) { + wl1271_warning("couldn't set default key"); + return ret; + } + + return 0; +} + +static int wl1271_init_templates_config(struct wl1271 *wl) +{ + int ret; + + /* send empty templates for fw memory reservation */ + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, + sizeof(struct wl12xx_probe_req_template)); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, + sizeof(struct wl12xx_null_data_template)); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL, + sizeof(struct wl12xx_ps_poll_template)); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, + sizeof + (struct wl12xx_qos_null_data_template)); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, + sizeof + (struct wl12xx_probe_resp_template)); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, + sizeof + (struct wl12xx_beacon_template)); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) +{ + int ret; + + ret = wl1271_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); + if (ret < 0) + return ret; + + ret = wl1271_acx_rx_config(wl, config, filter); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_phy_config(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_pd_threshold(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME); + if (ret < 0) + return ret; + + ret = wl1271_acx_group_address_tbl(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_service_period_timeout(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_beacon_filter(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_beacon_filter_opt(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_beacon_filter_table(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_pta(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_sg_enable(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_sg_cfg(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_energy_detection(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_cca_threshold(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_beacon_broadcast(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_bcn_dtim_options(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_general_parms(struct wl1271 *wl) +{ + struct wl1271_general_parms *gen_parms; + int ret; + + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); + if (!gen_parms) + return -ENOMEM; + + gen_parms->id = TEST_CMD_INI_FILE_GENERAL_PARAM; + + gen_parms->ref_clk = REF_CLK_38_4_E; + /* FIXME: magic numbers */ + gen_parms->settling_time = 5; + gen_parms->clk_valid_on_wakeup = 0; + gen_parms->dc2dcmode = 0; + gen_parms->single_dual_band = 0; + gen_parms->tx_bip_fem_autodetect = 1; + gen_parms->tx_bip_fem_manufacturer = 1; + gen_parms->settings = 1; + + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); + if (ret < 0) { + wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); + return ret; + } + + kfree(gen_parms); + return 0; +} + +static int wl1271_init_radio_parms(struct wl1271 *wl) +{ + /* + * FIXME: All these magic numbers should be moved to some place where + * they can be configured (separate file?) + */ + + struct wl1271_radio_parms *radio_parms; + int ret; + u8 compensation[] = { 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, 0xfc, 0x00, + 0x08, 0x10, 0xf0, 0xf8, 0x00, 0x0a, 0x14 }; + + u8 tx_rate_limits_normal[] = { 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 }; + u8 tx_rate_limits_degraded[] = { 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 }; + + u8 tx_channel_limits_11b[] = { 0x22, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x22, 0x50, + 0x22, 0x50 }; + + u8 tx_channel_limits_ofdm[] = { 0x20, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x20, 0x50, + 0x20, 0x50 }; + + u8 tx_pdv_rate_offsets[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + u8 tx_ibias[] = { 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }; + + radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); + if (!radio_parms) + return -ENOMEM; + + radio_parms->id = TEST_CMD_INI_FILE_RADIO_PARAM; + + /* Static radio parameters */ + radio_parms->rx_trace_loss = 10; + radio_parms->tx_trace_loss = 10; + memcpy(radio_parms->rx_rssi_and_proc_compens, compensation, + sizeof(compensation)); + + /* We don't set the 5GHz -- N/A */ + + /* Dynamic radio parameters */ + radio_parms->tx_ref_pd_voltage = cpu_to_le16(0x24e); + radio_parms->tx_ref_power = 0x78; + radio_parms->tx_offset_db = 0x0; + + memcpy(radio_parms->tx_rate_limits_normal, tx_rate_limits_normal, + sizeof(tx_rate_limits_normal)); + memcpy(radio_parms->tx_rate_limits_degraded, tx_rate_limits_degraded, + sizeof(tx_rate_limits_degraded)); + + memcpy(radio_parms->tx_channel_limits_11b, tx_channel_limits_11b, + sizeof(tx_channel_limits_11b)); + memcpy(radio_parms->tx_channel_limits_ofdm, tx_channel_limits_ofdm, + sizeof(tx_channel_limits_ofdm)); + memcpy(radio_parms->tx_pdv_rate_offsets, tx_pdv_rate_offsets, + sizeof(tx_pdv_rate_offsets)); + memcpy(radio_parms->tx_ibias, tx_ibias, + sizeof(tx_ibias)); + + radio_parms->rx_fem_insertion_loss = 0x14; + + ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); + if (ret < 0) + wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); + + kfree(radio_parms); + return ret; +} + +int wl1271_hw_init(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_init_general_parms(wl); + if (ret < 0) + return ret; + + ret = wl1271_init_radio_parms(wl); + if (ret < 0) + return ret; + + /* Template settings */ + ret = wl1271_init_templates_config(wl); + if (ret < 0) + return ret; + + /* Default memory configuration */ + ret = wl1271_acx_init_mem_config(wl); + if (ret < 0) + return ret; + + /* RX config */ + ret = wl1271_init_rx_config(wl, + RX_CFG_PROMISCUOUS | RX_CFG_TSF, + RX_FILTER_OPTION_DEF); + /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, + RX_FILTER_OPTION_FILTER_ALL); */ + if (ret < 0) + goto out_free_memmap; + + /* PHY layer config */ + ret = wl1271_init_phy_config(wl); + if (ret < 0) + goto out_free_memmap; + + /* Beacon filtering */ + ret = wl1271_init_beacon_filter(wl); + if (ret < 0) + goto out_free_memmap; + + /* Configure TX patch complete interrupt behavior */ + ret = wl1271_acx_tx_config_options(wl); + if (ret < 0) + goto out_free_memmap; + + /* RX complete interrupt pacing */ + ret = wl1271_acx_init_rx_interrupt(wl); + if (ret < 0) + goto out_free_memmap; + + /* Bluetooth WLAN coexistence */ + ret = wl1271_init_pta(wl); + if (ret < 0) + goto out_free_memmap; + + /* Energy detection */ + ret = wl1271_init_energy_detection(wl); + if (ret < 0) + goto out_free_memmap; + + /* Beacons and boradcast settings */ + ret = wl1271_init_beacon_broadcast(wl); + if (ret < 0) + goto out_free_memmap; + + /* Default fragmentation threshold */ + ret = wl1271_acx_frag_threshold(wl); + if (ret < 0) + goto out_free_memmap; + + /* Default TID configuration */ + ret = wl1271_acx_tid_cfg(wl); + if (ret < 0) + goto out_free_memmap; + + /* Default AC configuration */ + ret = wl1271_acx_ac_cfg(wl); + if (ret < 0) + goto out_free_memmap; + + /* Configure TX rate classes */ + ret = wl1271_acx_rate_policies(wl); + if (ret < 0) + goto out_free_memmap; + + /* Enable data path */ + ret = wl1271_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + goto out_free_memmap; + + /* Configure for ELP power saving */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); + if (ret < 0) + goto out_free_memmap; + + /* Configure HW encryption */ + ret = wl1271_init_hwenc_config(wl); + if (ret < 0) + goto out_free_memmap; + + return 0; + + out_free_memmap: + kfree(wl->target_mem_map); + + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h new file mode 100644 index 0000000..bd8ff0f --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_init.h @@ -0,0 +1,115 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_INIT_H__ +#define __WL1271_INIT_H__ + +#include "wl1271.h" + +int wl1271_hw_init_power_auth(struct wl1271 *wl); +int wl1271_hw_init(struct wl1271 *wl); + +/* These are not really a TEST_CMD, but the ref driver uses them as such */ +#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 +#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E + +struct wl1271_general_parms { + u8 id; + u8 padding[3]; + + u8 ref_clk; + u8 settling_time; + u8 clk_valid_on_wakeup; + u8 dc2dcmode; + u8 single_dual_band; + + u8 tx_bip_fem_autodetect; + u8 tx_bip_fem_manufacturer; + u8 settings; +} __attribute__ ((packed)); + +enum ref_clk_enum { + REF_CLK_19_2_E, + REF_CLK_26_E, + REF_CLK_38_4_E, + REF_CLK_52_E +}; + +#define RSSI_AND_PROCESS_COMPENSATION_SIZE 15 +#define NUMBER_OF_SUB_BANDS_5 7 +#define NUMBER_OF_RATE_GROUPS 6 +#define NUMBER_OF_CHANNELS_2_4 14 +#define NUMBER_OF_CHANNELS_5 35 + +struct wl1271_radio_parms { + u8 id; + u8 padding[3]; + + /* Static radio parameters */ + /* 2.4GHz */ + u8 rx_trace_loss; + u8 tx_trace_loss; + s8 rx_rssi_and_proc_compens[RSSI_AND_PROCESS_COMPENSATION_SIZE]; + + /* 5GHz */ + u8 rx_trace_loss_5[NUMBER_OF_SUB_BANDS_5]; + u8 tx_trace_loss_5[NUMBER_OF_SUB_BANDS_5]; + s8 rx_rssi_and_proc_compens_5[RSSI_AND_PROCESS_COMPENSATION_SIZE]; + + /* Dynamic radio parameters */ + /* 2.4GHz */ + s16 tx_ref_pd_voltage; + s8 tx_ref_power; + s8 tx_offset_db; + + s8 tx_rate_limits_normal[NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded[NUMBER_OF_RATE_GROUPS]; + + s8 tx_channel_limits_11b[NUMBER_OF_CHANNELS_2_4]; + s8 tx_channel_limits_ofdm[NUMBER_OF_CHANNELS_2_4]; + s8 tx_pdv_rate_offsets[NUMBER_OF_RATE_GROUPS]; + + u8 tx_ibias[NUMBER_OF_RATE_GROUPS]; + u8 rx_fem_insertion_loss; + + u8 padding2; + + /* 5GHz */ + s16 tx_ref_pd_voltage_5[NUMBER_OF_SUB_BANDS_5]; + s8 tx_ref_power_5[NUMBER_OF_SUB_BANDS_5]; + s8 tx_offset_db_5[NUMBER_OF_SUB_BANDS_5]; + + s8 tx_rate_limits_normal_5[NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded_5[NUMBER_OF_RATE_GROUPS]; + + s8 tx_channel_limits_ofdm_5[NUMBER_OF_CHANNELS_5]; + s8 tx_pdv_rate_offsets_5[NUMBER_OF_RATE_GROUPS]; + + /* FIXME: this is inconsistent with the types for 2.4GHz */ + s8 tx_ibias_5[NUMBER_OF_RATE_GROUPS]; + s8 rx_fem_insertion_loss_5[NUMBER_OF_SUB_BANDS_5]; + + u8 padding3[2]; +} __attribute__ ((packed)); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c new file mode 100644 index 0000000..3bb45ce --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -0,0 +1,1396 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wl1271.h" +#include "wl12xx_80211.h" +#include "wl1271_reg.h" +#include "wl1271_spi.h" +#include "wl1271_event.h" +#include "wl1271_tx.h" +#include "wl1271_rx.h" +#include "wl1271_ps.h" +#include "wl1271_init.h" +#include "wl1271_debugfs.h" +#include "wl1271_cmd.h" +#include "wl1271_boot.h" + +static int wl1271_plt_init(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_init_mem_config(wl); + if (ret < 0) + return ret; + + ret = wl1271_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + return ret; + + return 0; +} + +static void wl1271_disable_interrupts(struct wl1271 *wl) +{ + disable_irq(wl->irq); +} + +static void wl1271_power_off(struct wl1271 *wl) +{ + wl->set_power(false); +} + +static void wl1271_power_on(struct wl1271 *wl) +{ + wl->set_power(true); +} + +static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status) +{ + u32 total = 0; + int i; + + /* + * FIXME: Reading the FW status directly from the registers seems to + * be the right thing to do, but it doesn't work. And in the + * reference driver, there is a workaround called + * USE_SDIO_24M_WORKAROUND, which reads the status from memory + * instead, so we do the same here. + */ + + wl1271_spi_mem_read(wl, STATUS_MEM_ADDRESS, status, sizeof(*status)); + + wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " + "drv_rx_counter = %d, tx_results_counter = %d)", + status->intr, + status->fw_rx_counter, + status->drv_rx_counter, + status->tx_results_counter); + + /* update number of available TX blocks */ + for (i = 0; i < NUM_TX_QUEUES; i++) { + u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i]; + wl->tx_blocks_freed[i] = status->tx_released_blks[i]; + wl->tx_blocks_available += cnt; + total += cnt; + } + + /* if more blocks are available now, schedule some tx work */ + if (total && !skb_queue_empty(&wl->tx_queue)) + schedule_work(&wl->tx_work); + + /* update the host-chipset time offset */ + wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime; +} + +#define WL1271_IRQ_MAX_LOOPS 10 +static void wl1271_irq_work(struct work_struct *work) +{ + u32 intr, ctr = WL1271_IRQ_MAX_LOOPS; + int ret; + struct wl1271 *wl = + container_of(work, struct wl1271, irq_work); + + mutex_lock(&wl->mutex); + + wl1271_debug(DEBUG_IRQ, "IRQ work"); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, true); + if (ret < 0) + goto out; + + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + + intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + if (!intr) { + wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); + goto out_sleep; + } + + intr &= WL1271_INTR_MASK; + + do { + wl1271_fw_status(wl, wl->fw_status); + + + if (intr & (WL1271_ACX_INTR_EVENT_A | + WL1271_ACX_INTR_EVENT_B)) { + wl1271_debug(DEBUG_IRQ, + "WL1271_ACX_INTR_EVENT (0x%x)", intr); + if (intr & WL1271_ACX_INTR_EVENT_A) + wl1271_event_handle(wl, 0); + else + wl1271_event_handle(wl, 1); + } + + if (intr & WL1271_ACX_INTR_INIT_COMPLETE) + wl1271_debug(DEBUG_IRQ, + "WL1271_ACX_INTR_INIT_COMPLETE"); + + if (intr & WL1271_ACX_INTR_HW_AVAILABLE) + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); + + if (intr & WL1271_ACX_INTR_DATA) { + u8 tx_res_cnt = wl->fw_status->tx_results_counter - + wl->tx_results_count; + + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); + + /* check for tx results */ + if (tx_res_cnt) + wl1271_tx_complete(wl, tx_res_cnt); + + wl1271_rx(wl, wl->fw_status); + } + + intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + intr &= WL1271_INTR_MASK; + } while (intr && --ctr); + +out_sleep: + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(WL1271_INTR_MASK)); + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static irqreturn_t wl1271_irq(int irq, void *cookie) +{ + struct wl1271 *wl; + unsigned long flags; + + wl1271_debug(DEBUG_IRQ, "IRQ"); + + wl = cookie; + + /* complete the ELP completion */ + spin_lock_irqsave(&wl->wl_lock, flags); + if (wl->elp_compl) { + complete(wl->elp_compl); + wl->elp_compl = NULL; + } + + schedule_work(&wl->irq_work); + spin_unlock_irqrestore(&wl->wl_lock, flags); + + return IRQ_HANDLED; +} + +static int wl1271_fetch_firmware(struct wl1271 *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev); + + if (ret < 0) { + wl1271_error("could not get firmware: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl1271_error("firmware size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->fw_len = fw->size; + wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); + + if (!wl->fw) { + wl1271_error("could not allocate memory for the firmware"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->fw, fw->data, wl->fw_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static int wl1271_fetch_nvs(struct wl1271 *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev); + + if (ret < 0) { + wl1271_error("could not get nvs file: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl1271_error("nvs size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->nvs_len = fw->size; + wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); + + if (!wl->nvs) { + wl1271_error("could not allocate memory for the nvs file"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->nvs, fw->data, wl->nvs_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static void wl1271_fw_wakeup(struct wl1271 *wl) +{ + u32 elp_reg; + + elp_reg = ELPCTRL_WAKE_UP; + wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); +} + +static int wl1271_setup(struct wl1271 *wl) +{ + wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL); + if (!wl->fw_status) + return -ENOMEM; + + wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL); + if (!wl->tx_res_if) { + kfree(wl->fw_status); + return -ENOMEM; + } + + INIT_WORK(&wl->irq_work, wl1271_irq_work); + INIT_WORK(&wl->tx_work, wl1271_tx_work); + return 0; +} + +static int wl1271_chip_wakeup(struct wl1271 *wl) +{ + int ret = 0; + + wl1271_power_on(wl); + msleep(WL1271_POWER_ON_SLEEP); + wl1271_spi_reset(wl); + wl1271_spi_init(wl); + + /* We don't need a real memory partition here, because we only want + * to use the registers at this point. */ + wl1271_set_partition(wl, + 0x00000000, + 0x00000000, + REGISTERS_BASE, + REGISTERS_DOWN_SIZE); + + /* ELP module wake up */ + wl1271_fw_wakeup(wl); + + /* whal_FwCtrl_BootSm() */ + + /* 0. read chip id from CHIP_ID */ + wl->chip.id = wl1271_reg_read32(wl, CHIP_ID_B); + + /* 1. check if chip id is valid */ + + switch (wl->chip.id) { + case CHIP_ID_1271_PG10: + wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", + wl->chip.id); + + ret = wl1271_setup(wl); + if (ret < 0) + goto out; + break; + case CHIP_ID_1271_PG20: + wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", + wl->chip.id); + + ret = wl1271_setup(wl); + if (ret < 0) + goto out; + break; + default: + wl1271_error("unsupported chip id: 0x%x", wl->chip.id); + ret = -ENODEV; + goto out; + } + + if (wl->fw == NULL) { + ret = wl1271_fetch_firmware(wl); + if (ret < 0) + goto out; + } + + /* No NVS from netlink, try to get it from the filesystem */ + if (wl->nvs == NULL) { + ret = wl1271_fetch_nvs(wl); + if (ret < 0) + goto out; + } + +out: + return ret; +} + +static void wl1271_filter_work(struct work_struct *work) +{ + struct wl1271 *wl = + container_of(work, struct wl1271, filter_work); + int ret; + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + /* FIXME: replace the magic numbers with proper definitions */ + ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +int wl1271_plt_start(struct wl1271 *wl) +{ + int ret; + + mutex_lock(&wl->mutex); + + wl1271_notice("power up"); + + if (wl->state != WL1271_STATE_OFF) { + wl1271_error("cannot go into PLT state because not " + "in off state: %d", wl->state); + ret = -EBUSY; + goto out; + } + + wl->state = WL1271_STATE_PLT; + + ret = wl1271_chip_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_boot(wl); + if (ret < 0) + goto out; + + wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); + + ret = wl1271_plt_init(wl); + if (ret < 0) + goto out; + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +int wl1271_plt_stop(struct wl1271 *wl) +{ + int ret = 0; + + mutex_lock(&wl->mutex); + + wl1271_notice("power down"); + + if (wl->state != WL1271_STATE_PLT) { + wl1271_error("cannot power down because not in PLT " + "state: %d", wl->state); + ret = -EBUSY; + goto out; + } + + wl1271_disable_interrupts(wl); + wl1271_power_off(wl); + + wl->state = WL1271_STATE_OFF; + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + + +static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct wl1271 *wl = hw->priv; + + skb_queue_tail(&wl->tx_queue, skb); + + /* + * The chip specific setup must run before the first TX packet - + * before that, the tx_work will not be initialized! + */ + + schedule_work(&wl->tx_work); + + /* + * The workqueue is slow to process the tx_queue and we need stop + * the queue here, otherwise the queue will get too long. + */ + if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) { + ieee80211_stop_queues(wl->hw); + + /* + * FIXME: this is racy, the variable is not properly + * protected. Maybe fix this by removing the stupid + * variable altogether and checking the real queue state? + */ + wl->tx_queue_stopped = true; + } + + return NETDEV_TX_OK; +} + +static int wl1271_op_start(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + int ret = 0; + + wl1271_debug(DEBUG_MAC80211, "mac80211 start"); + + mutex_lock(&wl->mutex); + + if (wl->state != WL1271_STATE_OFF) { + wl1271_error("cannot start because not in off state: %d", + wl->state); + ret = -EBUSY; + goto out; + } + + ret = wl1271_chip_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_boot(wl); + if (ret < 0) + goto out; + + ret = wl1271_hw_init(wl); + if (ret < 0) + goto out; + + wl->state = WL1271_STATE_ON; + + wl1271_info("firmware booted (%s)", wl->chip.fw_ver); + +out: + if (ret < 0) + wl1271_power_off(wl); + + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl1271_op_stop(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + int i; + + wl1271_info("down"); + + wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); + + mutex_lock(&wl->mutex); + + WARN_ON(wl->state != WL1271_STATE_ON); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, true); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + wl->state = WL1271_STATE_OFF; + + wl1271_disable_interrupts(wl); + + mutex_unlock(&wl->mutex); + + cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->tx_work); + cancel_work_sync(&wl->filter_work); + + mutex_lock(&wl->mutex); + + /* let's notify MAC80211 about the remaining pending TX frames */ + wl1271_tx_flush(wl); + wl1271_power_off(wl); + + memset(wl->bssid, 0, ETH_ALEN); + memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1); + wl->ssid_len = 0; + wl->listen_int = 1; + wl->bss_type = MAX_BSS_TYPE; + + wl->rx_counter = 0; + wl->elp = false; + wl->psm = 0; + wl->tx_queue_stopped = false; + wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + wl->tx_blocks_available = 0; + wl->tx_results_count = 0; + wl->tx_packets_count = 0; + wl->time_offset = 0; + wl->session_counter = 0; + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_blocks_freed[i] = 0; + + wl1271_debugfs_reset(wl); + mutex_unlock(&wl->mutex); +} + +static int wl1271_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct wl1271 *wl = hw->priv; + DECLARE_MAC_BUF(mac); + int ret = 0; + + wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", + conf->type, print_mac(mac, conf->mac_addr)); + + mutex_lock(&wl->mutex); + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + wl->bss_type = BSS_TYPE_STA_BSS; + break; + case NL80211_IFTYPE_ADHOC: + wl->bss_type = BSS_TYPE_IBSS; + break; + default: + ret = -EOPNOTSUPP; + goto out; + } + + /* FIXME: what if conf->mac_addr changes? */ + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static void wl1271_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); +} + +#if 0 +static int wl1271_op_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct wl1271 *wl = hw->priv; + struct sk_buff *beacon; + DECLARE_MAC_BUF(mac); + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %s", + print_mac(mac, conf->bssid)); + wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid, + conf->ssid_len); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + + ret = wl1271_cmd_build_null_data(wl); + if (ret < 0) + goto out_sleep; + + wl->ssid_len = conf->ssid_len; + if (wl->ssid_len) + memcpy(wl->ssid, conf->ssid, wl->ssid_len); + + if (wl->bss_type != BSS_TYPE_IBSS) { + /* FIXME: replace the magic numbers with proper definitions */ + ret = wl1271_cmd_join(wl, wl->bss_type, 5, 100, 1); + if (ret < 0) + goto out_sleep; + } + + if (conf->changed & IEEE80211_IFCC_BEACON) { + beacon = ieee80211_beacon_get(hw, vif); + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, + beacon->data, beacon->len); + + if (ret < 0) { + dev_kfree_skb(beacon); + goto out_sleep; + } + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, + beacon->data, beacon->len); + + dev_kfree_skb(beacon); + + if (ret < 0) + goto out_sleep; + + /* FIXME: replace the magic numbers with proper definitions */ + ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); + + if (ret < 0) + goto out_sleep; + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} +#endif + +static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct wl1271 *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + int channel, ret = 0; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", + channel, + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if (channel != wl->channel) { + u8 old_channel = wl->channel; + wl->channel = channel; + + /* FIXME: use beacon interval provided by mac80211 */ + ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) { + wl->channel = old_channel; + goto out_sleep; + } + } + + ret = wl1271_cmd_build_null_data(wl); + if (ret < 0) + goto out_sleep; + + if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { + wl1271_info("psm enabled"); + + wl->psm_requested = true; + + /* + * We enter PSM only if we're already associated. + * If we're not, we'll enter it when joining an SSID, + * through the bss_info_changed() hook. + */ + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + } else if (!(conf->flags & IEEE80211_CONF_PS) && + wl->psm_requested) { + wl1271_info("psm disabled"); + + wl->psm_requested = false; + + if (wl->psm) + ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); + } + + if (conf->power_level != wl->power_level) { + ret = wl1271_acx_tx_power(wl, conf->power_level); + if (ret < 0) + goto out; + + wl->power_level = conf->power_level; + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | \ + FIF_OTHER_BSS) + +static void wl1271_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *total, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct wl1271 *wl = hw->priv; + + wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter"); + + *total &= WL1271_SUPPORTED_FILTERS; + changed &= WL1271_SUPPORTED_FILTERS; + + if (changed == 0) + return; + + /* FIXME: wl->rx_config and wl->rx_filter are not protected */ + wl->rx_config = WL1271_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + + /* + * FIXME: workqueues need to be properly cancelled on stop(), for + * now let's just disable changing the filter settings. They will + * be updated any on config(). + */ + /* schedule_work(&wl->filter_work); */ +} + +static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key_conf) +{ + struct wl1271 *wl = hw->priv; + const u8 *addr; + int ret; + u8 key_type; + + static const u8 bcast_addr[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); + + addr = sta ? sta->addr : bcast_addr; + + wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); + wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); + wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + key_conf->alg, key_conf->keyidx, + key_conf->keylen, key_conf->flags); + wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); + + if (is_zero_ether_addr(addr)) { + /* We dont support TX only encryption */ + ret = -EOPNOTSUPP; + goto out; + } + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out_unlock; + + switch (key_conf->alg) { + case ALG_WEP: + key_type = KEY_WEP; + + key_conf->hw_key_idx = key_conf->keyidx; + break; + case ALG_TKIP: + key_type = KEY_TKIP; + + key_conf->hw_key_idx = key_conf->keyidx; + break; + case ALG_CCMP: + key_type = KEY_AES; + + key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + default: + wl1271_error("Unknown key algo 0x%x", key_conf->alg); + + ret = -EOPNOTSUPP; + goto out_sleep; + } + + switch (cmd) { + case SET_KEY: + ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, + key_conf->keyidx, key_type, + key_conf->keylen, key_conf->key, + addr); + if (ret < 0) { + wl1271_error("Could not add or replace key"); + goto out_sleep; + } + break; + + case DISABLE_KEY: + ret = wl1271_cmd_set_key(wl, KEY_REMOVE, + key_conf->keyidx, key_type, + key_conf->keylen, key_conf->key, + addr); + if (ret < 0) { + wl1271_error("Could not remove key"); + goto out_sleep; + } + break; + + default: + wl1271_error("Unsupported key cmd 0x%x", cmd); + ret = -EOPNOTSUPP; + goto out_sleep; + + break; + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out_unlock: + mutex_unlock(&wl->mutex); + +out: + return ret; +} + +static int wl1271_op_hw_scan(struct ieee80211_hw *hw, + struct cfg80211_scan_request *req) +{ + struct wl1271 *wl = hw->priv; + int ret; + u8 *ssid = NULL; + size_t ssid_len = 0; + + wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan"); + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + ssid_len = req->ssids[0].ssid_len; + } + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + ret = wl1271_cmd_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wl1271 *wl = hw->priv; + int ret; + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + ret = wl1271_acx_rts_threshold(wl, (u16) value); + if (ret < 0) + wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + enum wl1271_cmd_ps_mode mode; + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + wl->aid = bss_conf->aid; + + ret = wl1271_cmd_build_ps_poll(wl, wl->aid); + if (ret < 0) + goto out_sleep; + + ret = wl1271_acx_aid(wl, wl->aid); + if (ret < 0) + goto out_sleep; + + /* If we want to go in PSM but we're not there yet */ + if (wl->psm_requested && !wl->psm) { + mode = STATION_POWER_SAVE_MODE; + ret = wl1271_ps_set_mode(wl, mode); + if (ret < 0) + goto out_sleep; + } + } + } + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT); + else + ret = wl1271_acx_slot(wl, SLOT_TIME_LONG); + if (ret < 0) { + wl1271_warning("Set slot time failed %d", ret); + goto out_sleep; + } + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + else + wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (bss_conf->use_cts_prot) + ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE); + else + ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE); + if (ret < 0) { + wl1271_warning("Set ctsprotect failed %d", ret); + goto out_sleep; + } + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_rate wl1271_rates[] = { + { .bitrate = 10, + .hw_value = 0x1, + .hw_value_short = 0x1, }, + { .bitrate = 20, + .hw_value = 0x2, + .hw_value_short = 0x2, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = 0x4, + .hw_value_short = 0x4, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = 0x20, + .hw_value_short = 0x20, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = 0x8, + .hw_value_short = 0x8, }, + { .bitrate = 90, + .hw_value = 0x10, + .hw_value_short = 0x10, }, + { .bitrate = 120, + .hw_value = 0x40, + .hw_value_short = 0x40, }, + { .bitrate = 180, + .hw_value = 0x80, + .hw_value_short = 0x80, }, + { .bitrate = 240, + .hw_value = 0x200, + .hw_value_short = 0x200, }, + { .bitrate = 360, + .hw_value = 0x400, + .hw_value_short = 0x400, }, + { .bitrate = 480, + .hw_value = 0x800, + .hw_value_short = 0x800, }, + { .bitrate = 540, + .hw_value = 0x1000, + .hw_value_short = 0x1000, }, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_channel wl1271_channels[] = { + { .hw_value = 1, .center_freq = 2412}, + { .hw_value = 2, .center_freq = 2417}, + { .hw_value = 3, .center_freq = 2422}, + { .hw_value = 4, .center_freq = 2427}, + { .hw_value = 5, .center_freq = 2432}, + { .hw_value = 6, .center_freq = 2437}, + { .hw_value = 7, .center_freq = 2442}, + { .hw_value = 8, .center_freq = 2447}, + { .hw_value = 9, .center_freq = 2452}, + { .hw_value = 10, .center_freq = 2457}, + { .hw_value = 11, .center_freq = 2462}, + { .hw_value = 12, .center_freq = 2467}, + { .hw_value = 13, .center_freq = 2472}, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_supported_band wl1271_band_2ghz = { + .channels = wl1271_channels, + .n_channels = ARRAY_SIZE(wl1271_channels), + .bitrates = wl1271_rates, + .n_bitrates = ARRAY_SIZE(wl1271_rates), +}; + +static const struct ieee80211_ops wl1271_ops = { + .start = wl1271_op_start, + .stop = wl1271_op_stop, + .add_interface = wl1271_op_add_interface, + .remove_interface = wl1271_op_remove_interface, + .config = wl1271_op_config, +/* .config_interface = wl1271_op_config_interface, */ + .configure_filter = wl1271_op_configure_filter, + .tx = wl1271_op_tx, + .set_key = wl1271_op_set_key, + .hw_scan = wl1271_op_hw_scan, + .bss_info_changed = wl1271_op_bss_info_changed, + .set_rts_threshold = wl1271_op_set_rts_threshold, +}; + +static int wl1271_register_hw(struct wl1271 *wl) +{ + int ret; + + if (wl->mac80211_registered) + return 0; + + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + + ret = ieee80211_register_hw(wl->hw); + if (ret < 0) { + wl1271_error("unable to register mac80211 hw: %d", ret); + return ret; + } + + wl->mac80211_registered = true; + + wl1271_notice("loaded"); + + return 0; +} + +static int wl1271_init_ieee80211(struct wl1271 *wl) +{ + /* + * The tx descriptor buffer and the TKIP space. + * + * FIXME: add correct 1271 descriptor size + */ + wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE; + + /* unit us */ + /* FIXME: find a proper value */ + wl->hw->channel_change_time = 10000; + + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; + + SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); + + return 0; +} + +static void wl1271_device_release(struct device *dev) +{ + +} + +static struct platform_device wl1271_device = { + .name = "wl1271", + .id = -1, + + /* device model insists to have a release function */ + .dev = { + .release = wl1271_device_release, + }, +}; + +#define WL1271_DEFAULT_CHANNEL 0 +static int __devinit wl1271_probe(struct spi_device *spi) +{ + struct wl12xx_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl1271 *wl; + int ret, i; + static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; + + pdata = spi->dev.platform_data; + if (!pdata) { + wl1271_error("no platform data"); + return -ENODEV; + } + + hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); + if (!hw) { + wl1271_error("could not alloc ieee80211_hw"); + return -ENOMEM; + } + + wl = hw->priv; + memset(wl, 0, sizeof(*wl)); + + wl->hw = hw; + dev_set_drvdata(&spi->dev, wl); + wl->spi = spi; + + skb_queue_head_init(&wl->tx_queue); + + INIT_WORK(&wl->filter_work, wl1271_filter_work); + wl->channel = WL1271_DEFAULT_CHANNEL; + wl->scanning = false; + wl->default_key = 0; + wl->listen_int = 1; + wl->rx_counter = 0; + wl->rx_config = WL1271_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + wl->elp = false; + wl->psm = 0; + wl->psm_requested = false; + wl->tx_queue_stopped = false; + wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + + /* We use the default power on sleep time until we know which chip + * we're using */ + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + wl->tx_frames[i] = NULL; + + spin_lock_init(&wl->wl_lock); + + /* + * In case our MAC address is not correctly set, + * we use a random but Nokia MAC. + */ + memcpy(wl->mac_addr, nokia_oui, 3); + get_random_bytes(wl->mac_addr + 3, 3); + + wl->state = WL1271_STATE_OFF; + mutex_init(&wl->mutex); + + wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); + if (!wl->rx_descriptor) { + wl1271_error("could not allocate memory for rx descriptor"); + ret = -ENOMEM; + goto out_free; + } + + /* This is the only SPI value that we need to set here, the rest + * comes from the board-peripherals file */ + spi->bits_per_word = 32; + + ret = spi_setup(spi); + if (ret < 0) { + wl1271_error("spi_setup failed"); + goto out_free; + } + + wl->set_power = pdata->set_power; + if (!wl->set_power) { + wl1271_error("set power function missing in platform data"); + ret = -ENODEV; + goto out_free; + } + + wl->irq = spi->irq; + if (wl->irq < 0) { + wl1271_error("irq missing in platform data"); + ret = -ENODEV; + goto out_free; + } + + ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); + if (ret < 0) { + wl1271_error("request_irq() failed: %d", ret); + goto out_free; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + + disable_irq(wl->irq); + + ret = platform_device_register(&wl1271_device); + if (ret) { + wl1271_error("couldn't register platform device"); + goto out_irq; + } + dev_set_drvdata(&wl1271_device.dev, wl); + + ret = wl1271_init_ieee80211(wl); + if (ret) + goto out_platform; + + ret = wl1271_register_hw(wl); + if (ret) + goto out_platform; + + wl1271_debugfs_init(wl); + + wl1271_notice("initialized"); + + return 0; + + out_platform: + platform_device_unregister(&wl1271_device); + + out_irq: + free_irq(wl->irq, wl); + + out_free: + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + + ieee80211_free_hw(hw); + + return ret; +} + +static int __devexit wl1271_remove(struct spi_device *spi) +{ + struct wl1271 *wl = dev_get_drvdata(&spi->dev); + + ieee80211_unregister_hw(wl->hw); + + wl1271_debugfs_exit(wl); + platform_device_unregister(&wl1271_device); + free_irq(wl->irq, wl); + kfree(wl->target_mem_map); + kfree(wl->fw); + wl->fw = NULL; + kfree(wl->nvs); + wl->nvs = NULL; + + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + + kfree(wl->fw_status); + kfree(wl->tx_res_if); + + ieee80211_free_hw(wl->hw); + + return 0; +} + + +static struct spi_driver wl1271_spi_driver = { + .driver = { + .name = "wl1271", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = wl1271_probe, + .remove = __devexit_p(wl1271_remove), +}; + +static int __init wl1271_init(void) +{ + int ret; + + ret = spi_register_driver(&wl1271_spi_driver); + if (ret < 0) { + wl1271_error("failed to register spi driver: %d", ret); + goto out; + } + +out: + return ret; +} + +static void __exit wl1271_exit(void) +{ + spi_unregister_driver(&wl1271_spi_driver); + + wl1271_notice("unloaded"); +} + +module_init(wl1271_init); +module_exit(wl1271_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c new file mode 100644 index 0000000..1dc74b0 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -0,0 +1,142 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1271_reg.h" +#include "wl1271_ps.h" +#include "wl1271_spi.h" + +#define WL1271_WAKEUP_TIMEOUT 500 + +/* Routines to toggle sleep mode while in ELP */ +void wl1271_ps_elp_sleep(struct wl1271 *wl) +{ + /* + * FIXME: due to a problem in the firmware (causing a firmware + * crash), ELP entry is prevented below. Remove the "true" to + * re-enable ELP entry. + */ + if (true || wl->elp || !wl->psm) + return; + + /* + * Go to ELP unless there is work already pending - pending work + * will immediately wakeup the chipset anyway. + */ + if (!work_pending(&wl->irq_work) && !work_pending(&wl->tx_work)) { + wl1271_debug(DEBUG_PSM, "chip to elp"); + wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + wl->elp = true; + } +} + +int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) +{ + DECLARE_COMPLETION_ONSTACK(compl); + unsigned long flags; + int ret; + u32 start_time = jiffies; + bool pending = false; + + if (!wl->elp) + return 0; + + wl1271_debug(DEBUG_PSM, "waking up chip from elp"); + + /* + * The spinlock is required here to synchronize both the work and + * the completion variable in one entity. + */ + spin_lock_irqsave(&wl->wl_lock, flags); + if (work_pending(&wl->irq_work) || chip_awake) + pending = true; + else + wl->elp_compl = &compl; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + + if (!pending) { + ret = wait_for_completion_timeout( + &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); + if (ret == 0) { + wl1271_error("ELP wakeup timeout!"); + ret = -ETIMEDOUT; + goto err; + } else if (ret < 0) { + wl1271_error("ELP wakeup completion error."); + goto err; + } + } + + wl->elp = false; + + wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", + jiffies_to_msecs(jiffies - start_time)); + goto out; + +err: + spin_lock_irqsave(&wl->wl_lock, flags); + wl->elp_compl = NULL; + spin_unlock_irqrestore(&wl->wl_lock, flags); + return ret; + +out: + return 0; +} + +int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) +{ + int ret; + + switch (mode) { + case STATION_POWER_SAVE_MODE: + wl1271_debug(DEBUG_PSM, "entering psm"); + ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + return ret; + + wl1271_ps_elp_sleep(wl); + if (ret < 0) + return ret; + + wl->psm = 1; + break; + case STATION_ACTIVE_MODE: + default: + wl1271_debug(DEBUG_PSM, "leaving psm"); + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + return ret; + + ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + + wl->psm = 0; + break; + } + + return ret; +} + + diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h new file mode 100644 index 0000000..de2bd3c --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_ps.h @@ -0,0 +1,35 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_PS_H__ +#define __WL1271_PS_H__ + +#include "wl1271.h" +#include "wl1271_acx.h" + +int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode); +void wl1271_ps_elp_sleep(struct wl1271 *wl); +int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); + + +#endif /* __WL1271_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h new file mode 100644 index 0000000..f8ed4a4 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_reg.h @@ -0,0 +1,758 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __REG_H__ +#define __REG_H__ + +#include + +#define REGISTERS_BASE 0x00300000 +#define DRPW_BASE 0x00310000 + +#define REGISTERS_DOWN_SIZE 0x00008800 +#define REGISTERS_WORK_SIZE 0x0000b000 + +#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC +#define STATUS_MEM_ADDRESS 0x40400 + +/* ELP register commands */ +#define ELPCTRL_WAKE_UP 0x1 +#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 +#define ELPCTRL_SLEEP 0x0 +/* ELP WLAN_READY bit */ +#define ELPCTRL_WLAN_READY 0x2 + +/*=============================================== + Host Software Reset - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 SOFT_RESET Soft Reset - When this bit is set, + it holds the Wlan hardware in a soft reset state. + This reset disables all MAC and baseband processor + clocks except the CardBus/PCI interface clock. + It also initializes all MAC state machines except + the host interface. It does not reload the + contents of the EEPROM. When this bit is cleared + (not self-clearing), the Wlan hardware + exits the software reset state. +===============================================*/ +#define ACX_REG_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000) + +#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) +#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) +#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) +/* + * Interrupt registers. + * 64 bit interrupt sources registers ws ced. + * sme interupts were removed and new ones were added. + * Order was changed. + */ +#define FIQ_MASK (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) +#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) +#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) +#define IRQ_MASK (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) +#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) +#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) +#define ECPU_MASK (REGISTERS_BASE + 0x0448) +#define FIQ_STS_L (REGISTERS_BASE + 0x044C) +#define FIQ_STS_H (REGISTERS_BASE + 0x0450) +#define IRQ_STS_L (REGISTERS_BASE + 0x0454) +#define IRQ_STS_H (REGISTERS_BASE + 0x0458) +#define INT_STS_ND (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) +#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) +#define INT_ACK (REGISTERS_BASE + 0x046C) +#define INT_ACK_L (REGISTERS_BASE + 0x046C) +#define INT_ACK_H (REGISTERS_BASE + 0x0470) +#define INT_TRIG (REGISTERS_BASE + 0x0474) +#define INT_TRIG_L (REGISTERS_BASE + 0x0474) +#define INT_TRIG_H (REGISTERS_BASE + 0x0478) +#define HOST_STS_L (REGISTERS_BASE + 0x045C) +#define HOST_STS_H (REGISTERS_BASE + 0x0460) +#define HOST_MASK (REGISTERS_BASE + 0x0430) +#define HOST_MASK_L (REGISTERS_BASE + 0x0430) +#define HOST_MASK_H (REGISTERS_BASE + 0x0434) +#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) +#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) + +#define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) +#define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) + +/* Host Interrupts*/ +#define HINT_MASK (REGISTERS_BASE + 0x0494) +#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) +#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) +#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) +/*1150 spec calls this HINT_STS_RAW*/ +#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) +#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) +#define HINT_ACK (REGISTERS_BASE + 0x04A8) +#define HINT_TRIG (REGISTERS_BASE + 0x04AC) + +/*============================================= + Host Interrupt Mask Register - 32bit (RW) + ------------------------------------------ + Setting a bit in this register masks the + corresponding interrupt to the host. + 0 - RX0 - Rx first dubble buffer Data Interrupt + 1 - TXD - Tx Data Interrupt + 2 - TXXFR - Tx Transfer Interrupt + 3 - RX1 - Rx second dubble buffer Data Interrupt + 4 - RXXFR - Rx Transfer Interrupt + 5 - EVENT_A - Event Mailbox interrupt + 6 - EVENT_B - Event Mailbox interrupt + 7 - WNONHST - Wake On Host Interrupt + 8 - TRACE_A - Debug Trace interrupt + 9 - TRACE_B - Debug Trace interrupt + 10 - CDCMP - Command Complete Interrupt + 11 - + 12 - + 13 - + 14 - ICOMP - Initialization Complete Interrupt + 16 - SG SE - Soft Gemini - Sense enable interrupt + 17 - SG SD - Soft Gemini - Sense disable interrupt + 18 - - + 19 - - + 20 - - + 21- - + Default: 0x0001 +*==============================================*/ +#define ACX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC) + +/*============================================= + Host Interrupt Mask Set 16bit, (Write only) + ------------------------------------------ + Setting a bit in this register sets + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +==============================================*/ +#define ACX_REG_HINT_MASK_SET (REGISTERS_BASE + 0x04E0) + +/*============================================= + Host Interrupt Mask Clear 16bit,(Write only) + ------------------------------------------ + Setting a bit in this register clears + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +=============================================*/ +#define ACX_REG_HINT_MASK_CLR (REGISTERS_BASE + 0x04E4) + +/*============================================= + Host Interrupt Status Nondestructive Read + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register doesn't + effect its content. +=============================================*/ +#define ACX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8) + +/*============================================= + Host Interrupt Status Clear on Read Register + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register clears it, + thus making all interrupts inactive. +==============================================*/ +#define ACX_REG_INTERRUPT_CLEAR (REGISTERS_BASE + 0x04F8) + +/*============================================= + Host Interrupt Acknowledge Register + 16bit,(Write only) + ------------------------------------------ + The host can set individual bits in this + register to clear (acknowledge) the corresp. + interrupt status bits in the HINT_STS_CLR and + HINT_STS_ND registers, thus making the + assotiated interrupt inactive. (0-no effect) +==============================================*/ +#define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0) + +#define RX_DRIVER_DUMMY_WRITE_ADDRESS (REGISTERS_BASE + 0x0534) +#define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538) + +/* Device Configuration registers*/ +#define SOR_CFG (REGISTERS_BASE + 0x0800) + +/* Embedded ARM CPU Control */ + +/*=============================================== + Halt eCPU - 32bit RW + ------------------------------------------ + 0 HALT_ECPU Halt Embedded CPU - This bit is the + compliment of bit 1 (MDATA2) in the SOR_CFG register. + During a hardware reset, this bit holds + the inverse of MDATA2. + When downloading firmware from the host, + set this bit (pull down MDATA2). + The host clears this bit after downloading the firmware into + zero-wait-state SSRAM. + When loading firmware from Flash, clear this bit (pull up MDATA2) + so that the eCPU can run the bootloader code in Flash + HALT_ECPU eCPU State + -------------------- + 1 halt eCPU + 0 enable eCPU + ===============================================*/ +#define ACX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804) + +#define HI_CFG (REGISTERS_BASE + 0x0808) + +/*=============================================== + EEPROM Burst Read Start - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 ACX_EE_START - EEPROM Burst Read Start 0 + Setting this bit starts a burst read from + the external EEPROM. + If this bit is set (after reset) before an EEPROM read/write, + the burst read starts at EEPROM address 0. + Otherwise, it starts at the address + following the address of the previous access. + TheWlan hardware hardware clears this bit automatically. + + Default: 0x00000000 +*================================================*/ +#define ACX_REG_EE_START (REGISTERS_BASE + 0x080C) + +#define OCP_POR_CTR (REGISTERS_BASE + 0x09B4) +#define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8) +#define OCP_DATA_READ (REGISTERS_BASE + 0x09BC) +#define OCP_CMD (REGISTERS_BASE + 0x09C0) + +#define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8) + +#define CHIP_ID_B (REGISTERS_BASE + 0x5674) + +#define CHIP_ID_1271_PG10 (0x4030101) +#define CHIP_ID_1271_PG20 (0x4030111) + +#define ENABLE (REGISTERS_BASE + 0x5450) + +/* Power Management registers */ +#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) +#define ELP_CMD (REGISTERS_BASE + 0x5808) +#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) +#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) +#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) + +#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) + +/* Scratch Pad registers*/ +#define SCR_PAD0 (REGISTERS_BASE + 0x5608) +#define SCR_PAD1 (REGISTERS_BASE + 0x560C) +#define SCR_PAD2 (REGISTERS_BASE + 0x5610) +#define SCR_PAD3 (REGISTERS_BASE + 0x5614) +#define SCR_PAD4 (REGISTERS_BASE + 0x5618) +#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) +#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) +#define SCR_PAD5 (REGISTERS_BASE + 0x5624) +#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) +#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) +#define SCR_PAD6 (REGISTERS_BASE + 0x5630) +#define SCR_PAD7 (REGISTERS_BASE + 0x5634) +#define SCR_PAD8 (REGISTERS_BASE + 0x5638) +#define SCR_PAD9 (REGISTERS_BASE + 0x563C) + +/* Spare registers*/ +#define SPARE_A1 (REGISTERS_BASE + 0x0994) +#define SPARE_A2 (REGISTERS_BASE + 0x0998) +#define SPARE_A3 (REGISTERS_BASE + 0x099C) +#define SPARE_A4 (REGISTERS_BASE + 0x09A0) +#define SPARE_A5 (REGISTERS_BASE + 0x09A4) +#define SPARE_A6 (REGISTERS_BASE + 0x09A8) +#define SPARE_A7 (REGISTERS_BASE + 0x09AC) +#define SPARE_A8 (REGISTERS_BASE + 0x09B0) +#define SPARE_B1 (REGISTERS_BASE + 0x5420) +#define SPARE_B2 (REGISTERS_BASE + 0x5424) +#define SPARE_B3 (REGISTERS_BASE + 0x5428) +#define SPARE_B4 (REGISTERS_BASE + 0x542C) +#define SPARE_B5 (REGISTERS_BASE + 0x5430) +#define SPARE_B6 (REGISTERS_BASE + 0x5434) +#define SPARE_B7 (REGISTERS_BASE + 0x5438) +#define SPARE_B8 (REGISTERS_BASE + 0x543C) + +#define PLL_PARAMETERS (REGISTERS_BASE + 0x6040) +#define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008) +#define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100) +#define DRPW_SCRATCH_START (DRPW_BASE + 0x002C) + + +#define ACX_SLV_SOFT_RESET_BIT BIT(1) +#define ACX_REG_EEPROM_START_BIT BIT(1) + +/* Command/Information Mailbox Pointers */ + +/*=============================================== + Command Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the command mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to + find the location of the command mailbox. + The Wlan hardware initializes the command mailbox + pointer with the default address of the command mailbox. + The command mailbox pointer is not valid until after + the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) + +/*=============================================== + Information Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the information mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to find + the location of the information mailbox. + The Wlan hardware initializes the information mailbox pointer + with the default address of the information mailbox. + The information mailbox pointer is not valid + until after the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) + + +/* Misc */ + +#define REG_ENABLE_TX_RX (ENABLE) +/* + * Rx configuration (filter) information element + * --------------------------------------------- + */ +#define REG_RX_CONFIG (RX_CFG) +#define REG_RX_FILTER (RX_FILTER_CFG) + + +#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 + +/* promiscuous - receives all valid frames */ +#define RX_CFG_PROMISCUOUS 0x0008 + +/* receives frames from any BSSID */ +#define RX_CFG_BSSID 0x0020 + +/* receives frames destined to any MAC address */ +#define RX_CFG_MAC 0x0010 + +#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 +#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 +#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 +#define RX_CFG_ENABLE_ANY_BSSID 0x0000 + +/* discards all broadcast frames */ +#define RX_CFG_DISABLE_BCAST 0x0200 + +#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 +#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 +#define RX_CFG_COPY_RX_STATUS 0x2000 +#define RX_CFG_TSF 0x10000 + +#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ + | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ + | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) + +#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ + | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) + +#define RX_FILTER_OPTION_FILTER_ALL 0 + +#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ + | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) + +#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ + | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ + | CFG_RX_PRSP_EN) + + +/*=============================================== + Phy regs + ===============================================*/ +#define ACX_PHY_ADDR_REG SBB_ADDR +#define ACX_PHY_DATA_REG SBB_DATA +#define ACX_PHY_CTRL_REG SBB_CTL +#define ACX_PHY_REG_WR_MASK 0x00000001ul +#define ACX_PHY_REG_RD_MASK 0x00000002ul + + +/*=============================================== + EEPROM Read/Write Request 32bit RW + ------------------------------------------ + 1 EE_READ - EEPROM Read Request 1 - Setting this bit + loads a single byte of data into the EE_DATA + register from the EEPROM location specified in + the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. + EE_DATA is valid when this bit is cleared. + + 0 EE_WRITE - EEPROM Write Request - Setting this bit + writes a single byte of data from the EE_DATA register into the + EEPROM location specified in the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. +*===============================================*/ +#define ACX_EE_CTL_REG EE_CTL +#define EE_WRITE 0x00000001ul +#define EE_READ 0x00000002ul + +/*=============================================== + EEPROM Address - 32bit RW + ------------------------------------------ + This register specifies the address + within the EEPROM from/to which to read/write data. + ===============================================*/ +#define ACX_EE_ADDR_REG EE_ADDR + +/*=============================================== + EEPROM Data - 32bit RW + ------------------------------------------ + This register either holds the read 8 bits of + data from the EEPROM or the write data + to be written to the EEPROM. + ===============================================*/ +#define ACX_EE_DATA_REG EE_DATA + +/*=============================================== + EEPROM Base Address - 32bit RW + ------------------------------------------ + This register holds the upper nine bits + [23:15] of the 24-bit Wlan hardware memory + address for burst reads from EEPROM accesses. + The EEPROM provides the lower 15 bits of this address. + The MSB of the address from the EEPROM is ignored. + ===============================================*/ +#define ACX_EE_CFG EE_CFG + +/*=============================================== + GPIO Output Values -32bit, RW + ------------------------------------------ + [31:16] Reserved + [15: 0] Specify the output values (at the output driver inputs) for + GPIO[15:0], respectively. + ===============================================*/ +#define ACX_GPIO_OUT_REG GPIO_OUT +#define ACX_MAX_GPIO_LINES 15 + +/*=============================================== + Contention window -32bit, RW + ------------------------------------------ + [31:26] Reserved + [25:16] Max (0x3ff) + [15:07] Reserved + [06:00] Current contention window value - default is 0x1F + ===============================================*/ +#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG +#define ACX_CONT_WIND_MIN_MASK 0x0000007f +#define ACX_CONT_WIND_MAX 0x03ff0000 + +/* + * Indirect slave register/memory registers + * ---------------------------------------- + */ +#define HW_SLAVE_REG_ADDR_REG 0x00000004 +#define HW_SLAVE_REG_DATA_REG 0x00000008 +#define HW_SLAVE_REG_CTRL_REG 0x0000000c + +#define SLAVE_AUTO_INC 0x00010000 +#define SLAVE_NO_AUTO_INC 0x00000000 +#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 + +#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR +#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA +#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL +#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL + +#define HW_FUNC_EVENT_INT_EN 0x8000 +#define HW_FUNC_EVENT_MASK_REG 0x00000034 + +#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) + +/*=============================================== + HI_CFG Interface Configuration Register Values + ------------------------------------------ + ===============================================*/ +#define HI_CFG_UART_ENABLE 0x00000004 +#define HI_CFG_RST232_ENABLE 0x00000008 +#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 +#define HI_CFG_HOST_INT_ENABLE 0x00000020 +#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 +#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 +#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 +#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 +#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 + +/* + * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile + * for platforms using active high interrupt level + */ +#ifdef USE_ACTIVE_HIGH +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) +#else +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) + +#endif + +#define REF_FREQ_19_2 0 +#define REF_FREQ_26_0 1 +#define REF_FREQ_38_4 2 +#define REF_FREQ_40_0 3 +#define REF_FREQ_33_6 4 +#define REF_FREQ_NUM 5 + +#define LUT_PARAM_INTEGER_DIVIDER 0 +#define LUT_PARAM_FRACTIONAL_DIVIDER 1 +#define LUT_PARAM_ATTN_BB 2 +#define LUT_PARAM_ALPHA_BB 3 +#define LUT_PARAM_STOP_TIME_BB 4 +#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 +#define LUT_PARAM_NUM 6 + +#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) +#define USE_EEPROM 0 +#define SOFT_RESET_MAX_TIME 1000000 +#define SOFT_RESET_STALL_TIME 1000 +#define NVS_DATA_BUNDARY_ALIGNMENT 4 + + +/* Firmware image load chunk size */ +#define CHUNK_SIZE 512 + +/* Firmware image header size */ +#define FW_HDR_SIZE 8 + +#define ECPU_CONTROL_HALT 0x00000101 + + +/****************************************************************************** + + CHANNELS, BAND & REG DOMAINS definitions + +******************************************************************************/ + + +enum { + RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ + RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ + RADIO_BAND_JAPAN_4_9_GHZ = 2, + DEFAULT_BAND = RADIO_BAND_2_4GHZ, + INVALID_BAND = 0xFE, + MAX_RADIO_BANDS = 0xFF +}; + +enum { + NO_RATE = 0, + RATE_1MBPS = 0x0A, + RATE_2MBPS = 0x14, + RATE_5_5MBPS = 0x37, + RATE_6MBPS = 0x0B, + RATE_9MBPS = 0x0F, + RATE_11MBPS = 0x6E, + RATE_12MBPS = 0x0A, + RATE_18MBPS = 0x0E, + RATE_22MBPS = 0xDC, + RATE_24MBPS = 0x09, + RATE_36MBPS = 0x0D, + RATE_48MBPS = 0x08, + RATE_54MBPS = 0x0C +}; + +enum { + RATE_INDEX_1MBPS = 0, + RATE_INDEX_2MBPS = 1, + RATE_INDEX_5_5MBPS = 2, + RATE_INDEX_6MBPS = 3, + RATE_INDEX_9MBPS = 4, + RATE_INDEX_11MBPS = 5, + RATE_INDEX_12MBPS = 6, + RATE_INDEX_18MBPS = 7, + RATE_INDEX_22MBPS = 8, + RATE_INDEX_24MBPS = 9, + RATE_INDEX_36MBPS = 10, + RATE_INDEX_48MBPS = 11, + RATE_INDEX_54MBPS = 12, + RATE_INDEX_MAX = RATE_INDEX_54MBPS, + MAX_RATE_INDEX, + INVALID_RATE_INDEX = MAX_RATE_INDEX, + RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF +}; + +enum { + RATE_MASK_1MBPS = 0x1, + RATE_MASK_2MBPS = 0x2, + RATE_MASK_5_5MBPS = 0x4, + RATE_MASK_11MBPS = 0x20, +}; + +#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +enum { + CCK_LONG = 0, + CCK_SHORT = SHORT_PREAMBLE_BIT, + PBCC_LONG = PBCC_RATE_BIT, + PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, + OFDM = OFDM_RATE_BIT +}; + +/****************************************************************************** + +Transmit-Descriptor RATE-SET field definitions... + +Define a new "Rate-Set" for TX path that incorporates the +Rate & Modulation info into a single 16-bit field. + +TxdRateSet_t: +b15 - Indicates Preamble type (1=SHORT, 0=LONG). + Notes: + Must be LONG (0) for 1Mbps rate. + Does not apply (set to 0) for RevG-OFDM rates. +b14 - Indicates PBCC encoding (1=PBCC, 0=not). + Notes: + Does not apply (set to 0) for rates 1 and 2 Mbps. + Does not apply (set to 0) for RevG-OFDM rates. +b13 - Unused (set to 0). +b12-b0 - Supported Rate indicator bits as defined below. + +******************************************************************************/ + + +#define TNETW1251_CHIP_ID_PG1_0 0x07010101 +#define TNETW1251_CHIP_ID_PG1_1 0x07020101 +#define TNETW1251_CHIP_ID_PG1_2 0x07030101 + +/************************************************************************* + + Interrupt Trigger Register (Host -> WiLink) + +**************************************************************************/ + +/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ + +/* + * Host Command Interrupt. Setting this bit masks + * the interrupt that the host issues to inform + * the FW that it has sent a command + * to the Wlan hardware Command Mailbox. + */ +#define INTR_TRIG_CMD BIT(0) + +/* + * Host Event Acknowlegde Interrupt. The host + * sets this bit to acknowledge that it received + * the unsolicited information from the event + * mailbox. + */ +#define INTR_TRIG_EVENT_ACK BIT(1) + +/* + * The host sets this bit to inform the Wlan + * FW that a TX packet is in the XFER + * Buffer #0. + */ +#define INTR_TRIG_TX_PROC0 BIT(2) + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #0. + */ +#define INTR_TRIG_RX_PROC0 BIT(3) + +#define INTR_TRIG_DEBUG_ACK BIT(4) + +#define INTR_TRIG_STATE_CHANGED BIT(5) + + +/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #1. + */ +#define INTR_TRIG_RX_PROC1 BIT(17) + +/* + * The host sets this bit to inform the Wlan + * hardware that a TX packet is in the XFER + * Buffer #1. + */ +#define INTR_TRIG_TX_PROC1 BIT(18) + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c new file mode 100644 index 0000000..ad8b690 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -0,0 +1,200 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1271.h" +#include "wl1271_acx.h" +#include "wl1271_reg.h" +#include "wl1271_rx.h" +#include "wl1271_spi.h" + +static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status, + u32 drv_rx_counter) +{ + return status->rx_pkt_descs[drv_rx_counter] & RX_MEM_BLOCK_MASK; +} + +static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status, + u32 drv_rx_counter) +{ + return (status->rx_pkt_descs[drv_rx_counter] & RX_BUF_SIZE_MASK) >> + RX_BUF_SIZE_SHIFT_DIV; +} + +/* The values of this table must match the wl1271_rates[] array */ +static u8 wl1271_rx_rate_to_idx[] = { + /* MCS rates are used only with 11n */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */ + + 11, /* WL1271_RATE_54 */ + 10, /* WL1271_RATE_48 */ + 9, /* WL1271_RATE_36 */ + 8, /* WL1271_RATE_24 */ + + /* TI-specific rate */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22 */ + + 7, /* WL1271_RATE_18 */ + 6, /* WL1271_RATE_12 */ + 3, /* WL1271_RATE_11 */ + 5, /* WL1271_RATE_9 */ + 4, /* WL1271_RATE_6 */ + 2, /* WL1271_RATE_5_5 */ + 1, /* WL1271_RATE_2 */ + 0 /* WL1271_RATE_1 */ +}; + +static void wl1271_rx_status(struct wl1271 *wl, + struct wl1271_rx_descriptor *desc, + struct ieee80211_rx_status *status, + u8 beacon) +{ + memset(status, 0, sizeof(struct ieee80211_rx_status)); + + if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) + status->band = IEEE80211_BAND_2GHZ; + else + wl1271_warning("unsupported band 0x%x", + desc->flags & WL1271_RX_DESC_BAND_MASK); + + /* + * FIXME: Add mactime handling. For IBSS (ad-hoc) we need to get the + * timestamp from the beacon (acx_tsf_info). In BSS mode (infra) we + * only need the mactime for monitor mode. For now the mactime is + * not valid, so RX_FLAG_TSFT should not be set + */ + status->signal = desc->rssi; + + /* FIXME: Should this be optimized? */ + status->qual = (desc->rssi - WL1271_RX_MIN_RSSI) * 100 / + (WL1271_RX_MAX_RSSI - WL1271_RX_MIN_RSSI); + status->qual = min(status->qual, 100); + status->qual = max(status->qual, 0); + + /* + * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we + * need to divide by two for now, but TI has been discussing about + * changing it. This needs to be rechecked. + */ + status->noise = desc->rssi - (desc->snr >> 1); + + status->freq = ieee80211_channel_to_frequency(desc->channel); + + if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + + if (likely(!(desc->flags & WL1271_RX_DESC_DECRYPT_FAIL))) + status->flag |= RX_FLAG_DECRYPTED; + + if (unlikely(desc->flags & WL1271_RX_DESC_MIC_FAIL)) + status->flag |= RX_FLAG_MMIC_ERROR; + } + + status->rate_idx = wl1271_rx_rate_to_idx[desc->rate]; + + if (status->rate_idx == WL1271_RX_RATE_UNSUPPORTED) + wl1271_warning("unsupported rate"); +} + +static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) +{ + struct ieee80211_rx_status rx_status; + struct wl1271_rx_descriptor *desc; + struct sk_buff *skb; + u16 *fc; + u8 *buf; + u8 beacon = 0; + + skb = dev_alloc_skb(length); + if (!skb) { + wl1271_error("Couldn't allocate RX frame"); + return; + } + + buf = skb_put(skb, length); + wl1271_spi_reg_read(wl, WL1271_SLV_MEM_DATA, buf, length, true); + + /* the data read starts with the descriptor */ + desc = (struct wl1271_rx_descriptor *) buf; + + /* now we pull the descriptor out of the buffer */ + skb_pull(skb, sizeof(*desc)); + + fc = (u16 *)skb->data; + if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + beacon = 1; + + wl1271_rx_status(wl, desc, &rx_status, beacon); + + wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + beacon ? "beacon" : ""); + + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx(wl->hw, skb); +} + +void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) +{ + struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; + u32 buf_size; + u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + u32 mem_block; + + while (drv_rx_counter != fw_rx_counter) { + mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); + buf_size = wl1271_rx_get_buf_size(status, drv_rx_counter); + + if (buf_size == 0) { + wl1271_warning("received empty data"); + break; + } + + wl->rx_mem_pool_addr.addr = + (mem_block << 8) + wl_mem_map->packet_memory_pool_start; + wl->rx_mem_pool_addr.addr_extra = + wl->rx_mem_pool_addr.addr + 4; + + /* Choose the block we want to read */ + wl1271_spi_reg_write(wl, WL1271_SLV_REG_DATA, + &wl->rx_mem_pool_addr, + sizeof(wl->rx_mem_pool_addr), false); + + wl1271_rx_handle_data(wl, buf_size); + + wl->rx_counter++; + drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + } + + wl1271_reg_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); + + /* This is a workaround for some problems in the chip */ + wl1271_reg_write32(wl, RX_DRIVER_DUMMY_WRITE_ADDRESS, 0x1); + +} diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h new file mode 100644 index 0000000..d1ca60e --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_rx.h @@ -0,0 +1,121 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_RX_H__ +#define __WL1271_RX_H__ + +#include + +#define WL1271_RX_MAX_RSSI -30 +#define WL1271_RX_MIN_RSSI -95 + +#define WL1271_RX_ALIGN_TO 4 +#define WL1271_RX_ALIGN(len) (((len) + WL1271_RX_ALIGN_TO - 1) & \ + ~(WL1271_RX_ALIGN_TO - 1)) + +#define SHORT_PREAMBLE_BIT BIT(0) +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +#define PLCP_HEADER_LENGTH 8 +#define RX_DESC_PACKETID_SHIFT 11 +#define RX_MAX_PACKET_ID 3 + +#define NUM_RX_PKT_DESC_MOD_MASK 7 +#define WL1271_RX_RATE_UNSUPPORTED 0xFF + +#define RX_DESC_VALID_FCS 0x0001 +#define RX_DESC_MATCH_RXADDR1 0x0002 +#define RX_DESC_MCAST 0x0004 +#define RX_DESC_STAINTIM 0x0008 +#define RX_DESC_VIRTUAL_BM 0x0010 +#define RX_DESC_BCAST 0x0020 +#define RX_DESC_MATCH_SSID 0x0040 +#define RX_DESC_MATCH_BSSID 0x0080 +#define RX_DESC_ENCRYPTION_MASK 0x0300 +#define RX_DESC_MEASURMENT 0x0400 +#define RX_DESC_SEQNUM_MASK 0x1800 +#define RX_DESC_MIC_FAIL 0x2000 +#define RX_DESC_DECRYPT_FAIL 0x4000 + +/* + * RX Descriptor flags: + * + * Bits 0-1 - band + * Bit 2 - STBC + * Bit 3 - A-MPDU + * Bit 4 - HT + * Bits 5-7 - encryption + */ +#define WL1271_RX_DESC_BAND_MASK 0x03 +#define WL1271_RX_DESC_ENCRYPT_MASK 0xE0 + +#define WL1271_RX_DESC_BAND_BG 0x00 +#define WL1271_RX_DESC_BAND_J 0x01 +#define WL1271_RX_DESC_BAND_A 0x02 + +#define WL1271_RX_DESC_STBC BIT(2) +#define WL1271_RX_DESC_A_MPDU BIT(3) +#define WL1271_RX_DESC_HT BIT(4) + +#define WL1271_RX_DESC_ENCRYPT_WEP 0x20 +#define WL1271_RX_DESC_ENCRYPT_TKIP 0x40 +#define WL1271_RX_DESC_ENCRYPT_AES 0x60 +#define WL1271_RX_DESC_ENCRYPT_GEM 0x80 + +/* + * RX Descriptor status + * + * Bits 0-2 - status + * Bits 3-7 - reserved + */ +#define WL1271_RX_DESC_STATUS_MASK 0x07 + +#define WL1271_RX_DESC_SUCCESS 0x00 +#define WL1271_RX_DESC_DECRYPT_FAIL 0x01 +#define WL1271_RX_DESC_MIC_FAIL 0x02 +#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03 + +#define RX_MEM_BLOCK_MASK 0xFF +#define RX_BUF_SIZE_MASK 0xFFF00 +#define RX_BUF_SIZE_SHIFT_DIV 6 + +struct wl1271_rx_descriptor { + u16 length; + u8 status; + u8 flags; + u8 rate; + u8 channel; + s8 rssi; + u8 snr; + u32 timestamp; + u8 packet_class; + u8 process_id; + u8 pad_len; + u8 reserved; +} __attribute__ ((packed)); + +void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c new file mode 100644 index 0000000..4a12880 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -0,0 +1,382 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include "wl1271.h" +#include "wl12xx_80211.h" +#include "wl1271_spi.h" + +static int wl1271_translate_reg_addr(struct wl1271 *wl, int addr) +{ + return addr - wl->physical_reg_addr + wl->virtual_reg_addr; +} + +static int wl1271_translate_mem_addr(struct wl1271 *wl, int addr) +{ + return addr - wl->physical_mem_addr + wl->virtual_mem_addr; +} + + +void wl1271_spi_reset(struct wl1271 *wl) +{ + u8 *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl1271_error("could not allocate cmd for spi reset"); + return; + } + + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + memset(cmd, 0xff, WSPI_INIT_CMD_LEN); + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); +} + +void wl1271_spi_init(struct wl1271 *wl) +{ + u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl1271_error("could not allocate cmd for spi init"); + return; + } + + memset(crc, 0, sizeof(crc)); + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + /* + * Set WSPI_INIT_COMMAND + * the data is being send from the MSB to LSB + */ + cmd[2] = 0xff; + cmd[3] = 0xff; + cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; + cmd[0] = 0; + cmd[7] = 0; + cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; + cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; + + if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) + cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; + else + cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; + + cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS + | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; + + crc[0] = cmd[1]; + crc[1] = cmd[0]; + crc[2] = cmd[7]; + crc[3] = cmd[6]; + crc[4] = cmd[5]; + + cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; + cmd[4] |= WSPI_INIT_CMD_END; + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); +} + +/* Set the SPI partitions to access the chip addresses + * + * There are two VIRTUAL (SPI) partitions (the memory partition and the + * registers partition), which are mapped to two different areas of the + * PHYSICAL (hardware) memory. This function also makes other checks to + * ensure that the partitions are not overlapping. In the diagram below, the + * memory partition comes before the register partition, but the opposite is + * also supported. + * + * PHYSICAL address + * space + * + * | | + * ...+----+--> mem_start + * VIRTUAL address ... | | + * space ... | | [PART_0] + * ... | | + * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * part_size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * part_size | | ... | | + * + <--+----+... ...+----+--> reg_start + * reg_size ... | | + * ... | | [PART_1] + * ... | | + * ...+----+--> reg_start + reg_size + * | | + * + */ +int wl1271_set_partition(struct wl1271 *wl, + u32 mem_start, u32 mem_size, + u32 reg_start, u32 reg_size) +{ + struct wl1271_partition *partition; + struct spi_transfer t; + struct spi_message m; + size_t len, cmd_len; + u32 *cmd; + int addr; + + cmd_len = sizeof(u32) + 2 * sizeof(struct wl1271_partition); + cmd = kzalloc(cmd_len, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + spi_message_init(&m); + memset(&t, 0, sizeof(t)); + + partition = (struct wl1271_partition *) (cmd + 1); + addr = HW_ACCESS_PART0_SIZE_ADDR; + len = 2 * sizeof(struct wl1271_partition); + + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + + /* Make sure that the two partitions together don't exceed the + * address range */ + if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { + wl1271_debug(DEBUG_SPI, "Total size exceeds maximum virtual" + " address range. Truncating partition[0]."); + mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; + wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + if ((mem_start < reg_start) && + ((mem_start + mem_size) > reg_start)) { + /* Guarantee that the memory partition doesn't overlap the + * registers partition */ + wl1271_debug(DEBUG_SPI, "End of partition[0] is " + "overlapping partition[1]. Adjusted."); + mem_size = reg_start - mem_start; + wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } else if ((reg_start < mem_start) && + ((reg_start + reg_size) > mem_start)) { + /* Guarantee that the register partition doesn't overlap the + * memory partition */ + wl1271_debug(DEBUG_SPI, "End of partition[1] is" + " overlapping partition[0]. Adjusted."); + reg_size = mem_start - reg_start; + wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + partition[0].start = mem_start; + partition[0].size = mem_size; + partition[1].start = reg_start; + partition[1].size = reg_size; + + wl->physical_mem_addr = mem_start; + wl->physical_reg_addr = reg_start; + + wl->virtual_mem_addr = 0; + wl->virtual_reg_addr = mem_size; + + t.tx_buf = cmd; + t.len = cmd_len; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + kfree(cmd); + + return 0; +} + +void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + struct spi_transfer t[3]; + struct spi_message m; + u8 *busy_buf; + u32 *cmd; + + cmd = &wl->buffer_cmd; + busy_buf = wl->buffer_busyword; + + *cmd = 0; + *cmd |= WSPI_CMD_READ; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = 4; + spi_message_add_tail(&t[0], &m); + + /* Busy and non busy words read */ + t[1].rx_buf = busy_buf; + t[1].len = WL1271_BUSY_WORD_LEN; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = buf; + t[2].len = len; + spi_message_add_tail(&t[2], &m); + + spi_sync(wl->spi, &m); + + /* FIXME: check busy words */ + + wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); + wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); +} + +void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + struct spi_transfer t[2]; + struct spi_message m; + u32 *cmd; + + cmd = &wl->buffer_cmd; + + *cmd = 0; + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = sizeof(*cmd); + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = buf; + t[1].len = len; + spi_message_add_tail(&t[1], &m); + + spi_sync(wl->spi, &m); + + wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); + wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); +} + +void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl1271_translate_mem_addr(wl, addr); + + wl1271_spi_read(wl, physical, buf, len, false); +} + +void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl1271_translate_mem_addr(wl, addr); + + wl1271_spi_write(wl, physical, buf, len, false); +} + +void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed) +{ + int physical; + + physical = wl1271_translate_reg_addr(wl, addr); + + wl1271_spi_read(wl, physical, buf, len, fixed); +} + +void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed) +{ + int physical; + + physical = wl1271_translate_reg_addr(wl, addr); + + wl1271_spi_write(wl, physical, buf, len, fixed); +} + +u32 wl1271_mem_read32(struct wl1271 *wl, int addr) +{ + return wl1271_read32(wl, wl1271_translate_mem_addr(wl, addr)); +} + +void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl1271_write32(wl, wl1271_translate_mem_addr(wl, addr), val); +} + +u32 wl1271_reg_read32(struct wl1271 *wl, int addr) +{ + return wl1271_read32(wl, wl1271_translate_reg_addr(wl, addr)); +} + +void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl1271_write32(wl, wl1271_translate_reg_addr(wl, addr), val); +} diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h new file mode 100644 index 0000000..2c99684 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_spi.h @@ -0,0 +1,113 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_SPI_H__ +#define __WL1271_SPI_H__ + +#include "wl1271_reg.h" + +#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 + +#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 +#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 +#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 +#define HW_ACCESS_PART1_START_ADDR 0x1FFCC + +#define HW_ACCESS_REGISTER_SIZE 4 + +#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 + +#define WSPI_CMD_READ 0x40000000 +#define WSPI_CMD_WRITE 0x00000000 +#define WSPI_CMD_FIXED 0x20000000 +#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 +#define WSPI_CMD_BYTE_LENGTH_OFFSET 17 +#define WSPI_CMD_BYTE_ADDR 0x0001FFFF + +#define WSPI_INIT_CMD_CRC_LEN 5 + +#define WSPI_INIT_CMD_START 0x00 +#define WSPI_INIT_CMD_TX 0x40 +/* the extra bypass bit is sampled by the TNET as '1' */ +#define WSPI_INIT_CMD_BYPASS_BIT 0x80 +#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 +#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 +#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 +#define WSPI_INIT_CMD_IOD 0x40 +#define WSPI_INIT_CMD_IP 0x20 +#define WSPI_INIT_CMD_CS 0x10 +#define WSPI_INIT_CMD_WS 0x08 +#define WSPI_INIT_CMD_WSPI 0x01 +#define WSPI_INIT_CMD_END 0x01 + +#define WSPI_INIT_CMD_LEN 8 + +#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ + ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) +#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 + + +/* Raw target IO, address is not translated */ +void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed); +void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed); + +/* Memory target IO, address is tranlated to partition 0 */ +void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, size_t len); +void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, size_t len); +u32 wl1271_mem_read32(struct wl1271 *wl, int addr); +void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val); + +/* Registers IO */ +void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed); +void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed); +u32 wl1271_reg_read32(struct wl1271 *wl, int addr); +void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val); + +/* INIT and RESET words */ +void wl1271_spi_reset(struct wl1271 *wl); +void wl1271_spi_init(struct wl1271 *wl); +int wl1271_set_partition(struct wl1271 *wl, + u32 part_start, u32 part_size, + u32 reg_start, u32 reg_size); + +static inline u32 wl1271_read32(struct wl1271 *wl, int addr) +{ + wl1271_spi_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); + + return wl->buffer_32; +} + +static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl->buffer_32 = val; + wl1271_spi_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); +} + +#endif /* __WL1271_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c new file mode 100644 index 0000000..ff22125 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -0,0 +1,378 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl1271.h" +#include "wl1271_spi.h" +#include "wl1271_reg.h" +#include "wl1271_ps.h" +#include "wl1271_tx.h" + +static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) +{ + int i; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] == NULL) { + wl->tx_frames[i] = skb; + return i; + } + + return -EBUSY; +} + +static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) +{ + struct wl1271_tx_hw_descr *desc; + u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; + u32 total_blocks, excluded; + int id, ret = -EBUSY; + + /* allocate free identifier for the packet */ + id = wl1271_tx_id(wl, skb); + if (id < 0) + return id; + + /* approximate the number of blocks required for this packet + in the firmware */ + /* FIXME: try to figure out what is done here and make it cleaner */ + total_blocks = (skb->len) >> TX_HW_BLOCK_SHIFT_DIV; + excluded = (total_blocks << 2) + (skb->len & 0xff) + 34; + total_blocks += (excluded > 252) ? 2 : 1; + total_blocks += TX_HW_BLOCK_SPARE; + + if (total_blocks <= wl->tx_blocks_available) { + desc = (struct wl1271_tx_hw_descr *)skb_push( + skb, total_len - skb->len); + + desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; + desc->total_mem_blocks = total_blocks; + desc->id = id; + + wl->tx_blocks_available -= total_blocks; + + ret = 0; + + wl1271_debug(DEBUG_TX, + "tx_allocate: size: %d, blocks: %d, id: %d", + total_len, total_blocks, id); + } else + wl->tx_frames[id] = NULL; + + return ret; +} + +static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, + u32 extra, struct ieee80211_tx_info *control) +{ + struct wl1271_tx_hw_descr *desc; + int pad; + + desc = (struct wl1271_tx_hw_descr *) skb->data; + + /* configure packet life time */ + desc->start_time = jiffies_to_usecs(jiffies) - wl->time_offset; + desc->life_time = TX_HW_MGMT_PKT_LIFETIME_TU; + + /* configure the tx attributes */ + desc->tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; + /* FIXME: do we know the packet priority? can we identify mgmt + packets, and use max prio for them at least? */ + desc->tid = 0; + desc->aid = TX_HW_DEFAULT_AID; + desc->reserved = 0; + + /* align the length (and store in terms of words) */ + pad = WL1271_TX_ALIGN(skb->len); + desc->length = pad >> 2; + + /* calculate number of padding bytes */ + pad = pad - skb->len; + desc->tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; + + wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); + return 0; +} + +static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + + struct wl1271_tx_hw_descr *desc; + int len; + + /* FIXME: This is a workaround for getting non-aligned packets. + This happens at least with EAPOL packets from the user space. + Our DMA requires packets to be aligned on a 4-byte boundary. + */ + if (unlikely((long)skb->data & 0x03)) { + int offset = (4 - (long)skb->data) & 0x03; + wl1271_debug(DEBUG_TX, "skb offset %d", offset); + + /* check whether the current skb can be used */ + if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { + unsigned char *src = skb->data; + + /* align the buffer on a 4-byte boundary */ + skb_reserve(skb, offset); + memmove(skb->data, src, skb->len); + } else { + wl1271_info("No handler, fixme!"); + return -EINVAL; + } + } + + len = WL1271_TX_ALIGN(skb->len); + + /* perform a fixed address block write with the packet */ + wl1271_spi_reg_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); + + /* write packet new counter into the write access register */ + wl->tx_packets_count++; + wl1271_reg_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); + + desc = (struct wl1271_tx_hw_descr *) skb->data; + wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", + desc->id, skb, len, desc->length); + + return 0; +} + +/* caller must hold wl->mutex */ +static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info; + u32 extra = 0; + int ret = 0; + u8 idx; + + if (!skb) + return -EINVAL; + + info = IEEE80211_SKB_CB(skb); + + if (info->control.hw_key && + info->control.hw_key->alg == ALG_TKIP) + extra = WL1271_TKIP_IV_SPACE; + + if (info->control.hw_key) { + idx = info->control.hw_key->hw_key_idx; + + /* FIXME: do we have to do this if we're not using WEP? */ + if (unlikely(wl->default_key != idx)) { + ret = wl1271_cmd_set_default_wep_key(wl, idx); + if (ret < 0) + return ret; + } + } + + ret = wl1271_tx_allocate(wl, skb, extra); + if (ret < 0) + return ret; + + ret = wl1271_tx_fill_hdr(wl, skb, extra, info); + if (ret < 0) + return ret; + + ret = wl1271_tx_send_packet(wl, skb, info); + if (ret < 0) + return ret; + + return ret; +} + +void wl1271_tx_work(struct work_struct *work) +{ + struct wl1271 *wl = container_of(work, struct wl1271, tx_work); + struct sk_buff *skb; + bool woken_up = false; + int ret; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + while ((skb = skb_dequeue(&wl->tx_queue))) { + if (!woken_up) { + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + woken_up = true; + } + + ret = wl1271_tx_frame(wl, skb); + if (ret == -EBUSY) { + /* firmware buffer is full, stop queues */ + wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " + "stop queues"); + ieee80211_stop_queues(wl->hw); + wl->tx_queue_stopped = true; + skb_queue_head(&wl->tx_queue, skb); + goto out; + } else if (ret < 0) { + dev_kfree_skb(skb); + goto out; + } else if (wl->tx_queue_stopped) { + /* firmware buffer has space, restart queues */ + wl1271_debug(DEBUG_TX, + "complete_packet: waking queues"); + ieee80211_wake_queues(wl->hw); + wl->tx_queue_stopped = false; + } + } + +out: + if (woken_up) + wl1271_ps_elp_sleep(wl); + + mutex_unlock(&wl->mutex); +} + +static void wl1271_tx_complete_packet(struct wl1271 *wl, + struct wl1271_tx_hw_res_descr *result) +{ + + struct ieee80211_tx_info *info; + struct sk_buff *skb; + u32 header_len; + int id = result->id; + + /* check for id legality */ + if (id >= TX_HW_RESULT_QUEUE_LEN || wl->tx_frames[id] == NULL) { + wl1271_warning("TX result illegal id: %d", id); + return; + } + + skb = wl->tx_frames[id]; + info = IEEE80211_SKB_CB(skb); + + /* update packet status */ + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { + if (result->status == TX_SUCCESS) + info->flags |= IEEE80211_TX_STAT_ACK; + if (result->status & TX_RETRY_EXCEEDED) { + /* FIXME */ + /* info->status.excessive_retries = 1; */ + wl->stats.excessive_retries++; + } + } + + /* FIXME */ + /* info->status.retry_count = result->ack_failures; */ + wl->stats.retry_count += result->ack_failures; + + /* get header len */ + if (info->control.hw_key && + info->control.hw_key->alg == ALG_TKIP) + header_len = WL1271_TKIP_IV_SPACE + + sizeof(struct wl1271_tx_hw_descr); + else + header_len = sizeof(struct wl1271_tx_hw_descr); + + wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" + " status 0x%x", + result->id, skb, result->ack_failures, + result->rate_class_index, result->status); + + /* remove private header from packet */ + skb_pull(skb, header_len); + + /* return the packet to the stack */ + ieee80211_tx_status(wl->hw, skb); + wl->tx_frames[result->id] = NULL; +} + +/* Called upon reception of a TX complete interrupt */ +void wl1271_tx_complete(struct wl1271 *wl, u32 count) +{ + struct wl1271_acx_mem_map *memmap = + (struct wl1271_acx_mem_map *)wl->target_mem_map; + u32 i; + + wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); + + /* read the tx results from the chipset */ + wl1271_spi_mem_read(wl, memmap->tx_result, + wl->tx_res_if, sizeof(*wl->tx_res_if)); + + /* verify that the result buffer is not getting overrun */ + if (count > TX_HW_RESULT_QUEUE_LEN) { + wl1271_warning("TX result overflow from chipset: %d", count); + count = TX_HW_RESULT_QUEUE_LEN; + } + + /* process the results */ + for (i = 0; i < count; i++) { + struct wl1271_tx_hw_res_descr *result; + u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; + + /* process the packet */ + result = &(wl->tx_res_if->tx_results_queue[offset]); + wl1271_tx_complete_packet(wl, result); + + wl->tx_results_count++; + } + + /* write host counter to chipset (to ack) */ + wl1271_mem_write32(wl, memmap->tx_result + + offsetof(struct wl1271_tx_hw_res_if, + tx_result_host_counter), + wl->tx_res_if->tx_result_fw_counter); +} + +/* caller must hold wl->mutex */ +void wl1271_tx_flush(struct wl1271 *wl) +{ + int i; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + + /* TX failure */ +/* control->flags = 0; FIXME */ + + while ((skb = skb_dequeue(&wl->tx_queue))) { + info = IEEE80211_SKB_CB(skb); + + wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + } + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] != NULL) { + skb = wl->tx_frames[i]; + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + wl->tx_frames[i] = NULL; + } +} diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h new file mode 100644 index 0000000..4a61406 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h @@ -0,0 +1,130 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_TX_H__ +#define __WL1271_TX_H__ + +#define TX_HW_BLOCK_SPARE 2 +#define TX_HW_BLOCK_SHIFT_DIV 8 + +#define TX_HW_MGMT_PKT_LIFETIME_TU 2000 +/* The chipset reference driver states, that the "aid" value 1 + * is for infra-BSS, but is still always used */ +#define TX_HW_DEFAULT_AID 1 + +#define TX_HW_ATTR_SAVE_RETRIES BIT(0) +#define TX_HW_ATTR_HEADER_PAD BIT(1) +#define TX_HW_ATTR_SESSION_COUNTER (BIT(2) | BIT(3) | BIT(4)) +#define TX_HW_ATTR_RATE_POLICY (BIT(5) | BIT(6) | BIT(7) | \ + BIT(8) | BIT(9)) +#define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) +#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) + +#define TX_HW_ATTR_OFST_SAVE_RETRIES 0 +#define TX_HW_ATTR_OFST_HEADER_PAD 1 +#define TX_HW_ATTR_OFST_SESSION_COUNTER 2 +#define TX_HW_ATTR_OFST_RATE_POLICY 5 +#define TX_HW_ATTR_OFST_LAST_WORD_PAD 10 +#define TX_HW_ATTR_OFST_TX_CMPLT_REQ 12 + +#define TX_HW_RESULT_QUEUE_LEN 16 +#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf + +#define WL1271_TX_ALIGN_TO 4 +#define WL1271_TX_ALIGN(len) (((len) + WL1271_TX_ALIGN_TO - 1) & \ + ~(WL1271_TX_ALIGN_TO - 1)) +#define WL1271_TKIP_IV_SPACE 4 + +struct wl1271_tx_hw_descr { + /* Length of packet in words, including descriptor+header+data */ + u16 length; + /* Number of extra memory blocks to allocate for this packet in + addition to the number of blocks derived from the packet length */ + u8 extra_mem_blocks; + /* Total number of memory blocks allocated by the host for this packet. + Must be equal or greater than the actual blocks number allocated by + HW!! */ + u8 total_mem_blocks; + /* Device time (in us) when the packet arrived to the driver */ + u32 start_time; + /* Max delay in TUs until transmission. The last device time the + packet can be transmitted is: startTime+(1024*LifeTime) */ + u16 life_time; + /* Bitwise fields - see TX_ATTR... definitions above. */ + u16 tx_attr; + /* Packet identifier used also in the Tx-Result. */ + u8 id; + /* The packet TID value (as User-Priority) */ + u8 tid; + /* Identifier of the remote STA in IBSS, 1 in infra-BSS */ + u8 aid; + u8 reserved; +} __attribute__ ((packed)); + +enum wl1271_tx_hw_res_status { + TX_SUCCESS = 0, + TX_HW_ERROR = 1, + TX_DISABLED = 2, + TX_RETRY_EXCEEDED = 3, + TX_TIMEOUT = 4, + TX_KEY_NOT_FOUND = 5, + TX_PEER_NOT_FOUND = 6, + TX_SESSION_MISMATCH = 7 +}; + +struct wl1271_tx_hw_res_descr { + /* Packet Identifier - same value used in the Tx descriptor.*/ + u8 id; + /* The status of the transmission, indicating success or one of + several possible reasons for failure. */ + u8 status; + /* Total air access duration including all retrys and overheads.*/ + u16 medium_usage; + /* The time passed from host xfer to Tx-complete.*/ + u32 fw_handling_time; + /* Total media delay + (from 1st EDCA AIFS counter until TX Complete). */ + u32 medium_delay; + /* LS-byte of last TKIP seq-num (saved per AC for recovery). */ + u8 lsb_security_sequence_number; + /* Retry count - number of transmissions without successful ACK.*/ + u8 ack_failures; + /* The rate that succeeded getting ACK + (Valid only if status=SUCCESS). */ + u8 rate_class_index; + /* for 4-byte alignment. */ + u8 spare; +} __attribute__ ((packed)); + +struct wl1271_tx_hw_res_if { + u32 tx_result_fw_counter; + u32 tx_result_host_counter; + struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN]; +} __attribute__ ((packed)); + +void wl1271_tx_work(struct work_struct *work); +void wl1271_tx_complete(struct wl1271 *wl, u32 count); +void wl1271_tx_flush(struct wl1271 *wl); + +#endif -- cgit v0.10.2 From 30d742d5468c954969766bb0e809f218abc73af7 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 6 Aug 2009 16:25:29 +0300 Subject: wl1271: add wl1271 to Kconfig and the Makefile This patch adds support for the wl1271 driver in the Kconfig and in the Makefile. Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 82a0f97..af31eab 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -16,3 +16,15 @@ config WL1251 If you choose to build a module, it'll be called wl1251. Say N if unsure. + +config WL1271 + tristate "TI wl1271 support" + depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS + select FW_LOADER + select CRC7 + ---help--- + This module adds support for wireless adapters based on the + TI wl1271 chipset. + + If you choose to build a module, it'll be called wl1271. Say N if + unsure. diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index d5595a8..ecb8833 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -3,3 +3,9 @@ wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \ wl1251_acx.o wl1251_boot.o wl1251_init.o \ wl1251_ops.o wl1251_debugfs.o obj-$(CONFIG_WL1251) += wl1251.o + +wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \ + wl1271_event.o wl1271_tx.o wl1271_rx.o \ + wl1271_ps.o wl1271_acx.o wl1271_boot.o \ + wl1271_init.o wl1271_debugfs.o +obj-$(CONFIG_WL1271) += wl1271.o -- cgit v0.10.2 From e21546a2a3953a7d4b9d5c9b1cf12184ffceab96 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Aug 2009 20:41:32 +0200 Subject: mac80211: stay authenticated after disassoc After being disassociated by the AP, mac80211 currently reports this to cfg80211, and then goes to delete the association. That's fine, but cfg80211 assumes that it's still authenticated, however, mac80211 throws away all state. This fixes mac80211 to keep track of the authentication in that case so that cfg80211 can request a deauth or new association properly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 630a438..9895917 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -284,6 +284,7 @@ struct ieee80211_if_managed { struct mutex mtx; struct ieee80211_bss *associated; + struct ieee80211_mgd_work *old_associate_work; struct list_head work_list; u8 bssid[ETH_ALEN]; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6d5a1ee..c374d2d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -880,10 +880,11 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss *bss, + struct ieee80211_mgd_work *wk, u32 bss_info_changed) { struct ieee80211_local *local = sdata->local; + struct ieee80211_bss *bss = wk->bss; bss_info_changed |= BSS_CHANGED_ASSOC; /* set timing information */ @@ -896,6 +897,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss->cbss.capability, bss->has_erp_value, bss->erp_value); sdata->u.mgd.associated = bss; + sdata->u.mgd.old_associate_work = wk; memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); /* just to be sure */ @@ -1010,7 +1012,8 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; } -static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) +static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, + bool deauth) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -1028,6 +1031,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) ifmgd->associated = NULL; memset(ifmgd->bssid, 0, ETH_ALEN); + if (deauth) { + kfree(ifmgd->old_associate_work); + ifmgd->old_associate_work = NULL; + } else { + struct ieee80211_mgd_work *wk = ifmgd->old_associate_work; + + wk->state = IEEE80211_MGD_STATE_IDLE; + list_add(&wk->list, &ifmgd->work_list); + } + /* * we need to commit the associated = NULL change because the * scan code uses that to determine whether this iface should @@ -1345,7 +1358,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, sdata->dev->name, bssid, reason_code); if (!wk) { - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, true); } else { list_del(&wk->list); kfree(wk); @@ -1378,7 +1391,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", sdata->dev->name, reason_code); - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, false); return RX_MGMT_CFG80211_DISASSOC; } @@ -1581,7 +1594,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; bss_conf->assoc_capability = capab_info; - ieee80211_set_associated(sdata, wk->bss, changed); + /* this will take ownership of wk */ + ieee80211_set_associated(sdata, wk, changed); /* * Start timer to probe the connection to the AP now. @@ -1590,7 +1604,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); mod_beacon_timer(sdata); - kfree(wk); return RX_MGMT_CFG80211_ASSOC; } @@ -2096,7 +2109,7 @@ static void ieee80211_sta_work(struct work_struct *work) printk(KERN_DEBUG "No probe response from AP %pM" " after %dms, disconnecting.\n", bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, true); mutex_unlock(&ifmgd->mtx); /* * must be outside lock due to cfg80211, @@ -2500,7 +2513,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { bssid = req->bss->bssid; - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, true); } else list_for_each_entry(wk, &ifmgd->work_list, list) { if (&wk->bss->cbss == req->bss) { bssid = req->bss->bssid; @@ -2552,7 +2565,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return -ENOLINK; } - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, false); mutex_unlock(&ifmgd->mtx); -- cgit v0.10.2 From e458b8a22d33eef62765c9f89889efeb4041f073 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Aug 2009 20:41:33 +0200 Subject: cfg80211: fix nl80211 disconnected events When reporting a disconnection to userspace, we try to report whether it was from the AP or by our own choice. However, we misreported a broadcast deauth or disassoc as being by own choice, which is wrong. Fix this by checking the sender address instead of the destination address. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index b44b6c0..51d5df6 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -149,7 +149,7 @@ static void __cfg80211_send_deauth(struct net_device *dev, reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; + from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, @@ -215,7 +215,7 @@ static void __cfg80211_send_disassoc(struct net_device *dev, reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; + from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); } -- cgit v0.10.2 From b6f0b639089fb160b10984ac56e07e7043dabad7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Aug 2009 20:41:34 +0200 Subject: cfg80211: fix SME association after disassociation When an AP disassociates us, we currently go into a weird state because the SME doesn't handle authenticated but not associated well unless it's within its own state machine, it can't recover from that. However, it shouldn't need to, since we don't do any decisions in it really -- so when we get disconnected, simply deauthenticate too. Reported-by: Pavel Roskin Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 8a7dcbf..0b776b7 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -570,10 +570,30 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, wdev->ssid_len = 0; if (wdev->conn) { + const u8 *bssid; + int ret; + kfree(wdev->conn->ie); wdev->conn->ie = NULL; kfree(wdev->conn); wdev->conn = NULL; + + /* + * If this disconnect was due to a disassoc, we + * we might still have an auth BSS around. For + * the userspace SME that's currently expected, + * but for the kernel SME (nl80211 CONNECT or + * wireless extensions) we want to clear up all + * state. + */ + for (i = 0; i < MAX_AUTH_BSSES; i++) { + if (!wdev->auth_bsses[i]) + continue; + bssid = wdev->auth_bsses[i]->pub.bssid; + ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, + WLAN_REASON_DEAUTH_LEAVING); + WARN(ret, "deauth failed: %d\n", ret); + } } nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); -- cgit v0.10.2 From bcba8eae12fce23686b84a56d19f5fc78bf182ae Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 6 Aug 2009 21:04:41 +0200 Subject: cfg80211: Set WEP ciphers With iwconfig there is no way to properly set the ciphers when trying to connect to a WEP SSID. Although mac80211 based drivers dont need it, several fullmac drivers do. This patch basically sets the WEP ciphers whenever they're not set at all. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 0b776b7..340934f 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -658,14 +658,28 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, if (connkeys && connkeys->def >= 0) { int idx; + u32 cipher; idx = connkeys->def; + cipher = connkeys->params[idx].cipher; /* If given a WEP key we may need it for shared key auth */ - if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 || - connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) { + if (cipher == WLAN_CIPHER_SUITE_WEP40 || + cipher == WLAN_CIPHER_SUITE_WEP104) { connect->key_idx = idx; connect->key = connkeys->params[idx].key; connect->key_len = connkeys->params[idx].key_len; + + /* + * If ciphers are not set (e.g. when going through + * iwconfig), we have to set them appropriately here. + */ + if (connect->crypto.cipher_group == 0) + connect->crypto.cipher_group = cipher; + + if (connect->crypto.n_ciphers_pairwise == 0) { + connect->crypto.n_ciphers_pairwise = 1; + connect->crypto.ciphers_pairwise[0] = cipher; + } } } -- cgit v0.10.2 From 87b5bee86d281383ac2e5cae20ec47afa8fa374a Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:01 +0530 Subject: ath9k: Remove unneeded assignment of protocol field Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6b07ced..f6a8b1c 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -788,7 +788,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) DMA_FROM_DEVICE); skb_put(skb, ds->ds_rxstat.rs_datalen); - skb->protocol = cpu_to_be16(ETH_P_CONTROL); /* see if any padding is done by the hw and remove it */ hdr = (struct ieee80211_hdr *)skb->data; -- cgit v0.10.2 From 54e4cec69e70ba30aec68650fb95b3a7e1e6dc18 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:09 +0530 Subject: ath9k: Cleanup function return types Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 4cb64a0..86b13d1 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -35,7 +35,6 @@ static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) { - if (fbin == AR5416_BCHAN_UNUSED) return fbin; @@ -95,7 +94,7 @@ static inline bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) return sc->bus_ops->eeprom_read(ah, off, data); } -static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, +static inline void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, u8 *pVpdList, u16 numIntercepts, u8 *pRetVpdList) { @@ -120,8 +119,6 @@ static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, pRetVpdList[i] = (u8) k; currPwr += 2; } - - return true; } static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 71a3bcc..6514dc7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4019,14 +4019,12 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) ath9k_ps_restore(ah->ah_sc); } -bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) +void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) { if (setting) ah->misc_mode |= AR_PCU_TX_ADD_TSF; else ah->misc_mode &= ~AR_PCU_TX_ADD_TSF; - - return true; } bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index d4aaf4f..e83e900 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -601,7 +601,7 @@ void ath9k_hw_write_associd(struct ath_softc *sc); u64 ath9k_hw_gettsf64(struct ath_hw *ah); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); -bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); +void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 6f923e3..800bfab 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -40,20 +40,15 @@ u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q) return REG_READ(ah, AR_QTXDP(q)); } -bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) +void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) { REG_WRITE(ah, AR_QTXDP(q), txdp); - - return true; } -bool ath9k_hw_txstart(struct ath_hw *ah, u32 q) +void ath9k_hw_txstart(struct ath_hw *ah, u32 q) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q); - REG_WRITE(ah, AR_Q_TXE, 1 << q); - - return true; } u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) @@ -178,7 +173,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) #undef ATH9K_TIME_QUANTUM } -bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, +void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 segLen, bool firstSeg, bool lastSeg, const struct ath_desc *ds0) { @@ -202,8 +197,6 @@ bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, ads->ds_txstatus4 = ads->ds_txstatus5 = 0; ads->ds_txstatus6 = ads->ds_txstatus7 = 0; ads->ds_txstatus8 = ads->ds_txstatus9 = 0; - - return true; } void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds) @@ -888,7 +881,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, return 0; } -bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, +void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) { struct ar5416_desc *ads = AR5416DESC(ds); @@ -901,8 +894,6 @@ bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, ads->ds_rxstatus8 &= ~AR_RxDone; if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) memset(&(ads->u), 0, sizeof(ads->u)); - - return true; } bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 1176bce..7b39822 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -628,12 +628,12 @@ struct ath9k_channel; struct ath_rate_table; u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); -bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); -bool ath9k_hw_txstart(struct ath_hw *ah, u32 q); +void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); +void ath9k_hw_txstart(struct ath_hw *ah, u32 q); u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q); -bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, +void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 segLen, bool firstSeg, bool lastSeg, const struct ath_desc *ds0); void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds); @@ -668,7 +668,7 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q); bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q); int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, u32 pa, struct ath_desc *nds, u64 tsf); -bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, +void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags); bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); -- cgit v0.10.2 From c16c9d0657268daaf8a03e7895fb5c5f005285db Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:11 +0530 Subject: ath9k: Try to fix whitespace damage Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 86b13d1..4303a4d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -2854,7 +2854,6 @@ static struct eeprom_ops eep_def_ops = { .get_spur_channel = ath9k_hw_def_get_spur_channel }; - static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) { return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; @@ -2871,22 +2870,24 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) u16 *eep_data; int addr, eep_start_loc = AR9287_EEP_START_LOC; eep_data = (u16 *)eep; + if (!ath9k_hw_use_flash(ah)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); + "Reading from EEPROM, not flash\n"); } for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); addr++) { if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); + "Unable to read eeprom region \n"); return false; } eep_data++; } return true; } + static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) { u32 sum = 0, el, integer; @@ -2996,7 +2997,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) } static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, - enum eeprom_param param) + enum eeprom_param param) { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; @@ -3059,6 +3060,7 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, { #define TMP_VAL_VPD_TABLE \ ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); + int i, j, k; int16_t ss; u16 idxL = 0, idxR = 0, numPiers; @@ -3079,6 +3081,7 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; ath9k_hw_get_channel_centers(ah, chan, ¢ers); + for (numPiers = 0; numPiers < availPiers; numPiers++) { if (bChans[numPiers] == AR9287_BCHAN_UNUSED) break; @@ -3205,16 +3208,18 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, } static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, - u8 *pCalChans, u16 availPiers, - int8_t *pPwr) + struct ath9k_channel *chan, + struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, + u8 *pCalChans, u16 availPiers, + int8_t *pPwr) { u8 pcdac, i = 0; u16 idxL = 0, idxR = 0, numPiers; bool match; struct chan_centers centers; + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + for (numPiers = 0; numPiers < availPiers; numPiers++) { if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED) break; @@ -3272,9 +3277,9 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, } } - static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) { struct cal_data_per_freq_ar9287 *pRawDataset; struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; @@ -3430,7 +3435,6 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, *pTxPowerIndexOffset = 0; } - static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, u16 AntennaReduction, u16 twiceMaxRegulatoryPower, @@ -3440,8 +3444,8 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, - AR5416_MAX_RATE_POWER }; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; int i; int16_t twiceLargestAntenna; struct cal_ctl_data_ar9287 *rep; @@ -3452,8 +3456,9 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0} }; u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11g[] = {CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, - CTL_11G_EXT, CTL_2GHT40}; + u16 ctlModesFor11g[] = + {CTL_11B, CTL_11G, CTL_2GHT20, + CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40}; u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; struct chan_centers centers; int tx_chainmask; @@ -3464,7 +3469,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, ath9k_hw_get_channel_centers(ah, chan, ¢ers); twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], - pEepData->modalHeader.antennaGainCh[1]); + pEepData->modalHeader.antennaGainCh[1]); twiceLargestAntenna = (int16_t)min((AntennaReduction) - twiceLargestAntenna, 0); @@ -3489,42 +3494,41 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, scaledPower = max((u16)0, scaledPower); if (IS_CHAN_2GHZ(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g) - - SUB_NUM_CTL_MODES_AT_2G_40; + numCtlModes = + ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; pCtlMode = ctlModesFor11g; ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR9287_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, false); + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); + pEepData->calTargetPower2GHT20, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); if (IS_CHAN_HT40(chan)) { numCtlModes = ARRAY_SIZE(ctlModesFor11g); ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT40, - AR9287_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); + pEepData->calTargetPower2GHT40, + AR9287_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR9287_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, 4, true); + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); } } for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || (pCtlMode[ctlMode] == CTL_2GHT40); if (isHt40CtlMode) @@ -3534,14 +3538,15 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, else freq = centers.ctl_center; - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) + ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d," "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); + for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, @@ -3552,12 +3557,12 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, pEepData->ctlIndex[i], chan->channel); if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & - CTL_MODE_M) | SD_NO_CTL))) { + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & + CTL_MODE_M) | SD_NO_CTL))) { rep = &(pEepData->ctlData[i]); twiceMinEdgePower = ath9k_hw_get_max_edge_power( @@ -3592,7 +3597,6 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, scaledPower, minCtlPower); - switch (pCtlMode[ctlMode]) { case CTL_11B: @@ -3650,9 +3654,13 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, } } - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; + ratesArray[rate6mb] = + ratesArray[rate9mb] = + ratesArray[rate12mb] = + ratesArray[rate18mb] = + ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; @@ -3663,7 +3671,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, if (IS_CHAN_2GHZ(chan)) { ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = + ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; @@ -3680,35 +3688,38 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, if (IS_CHAN_2GHZ(chan)) ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; } + #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN #undef REDUCE_SCALED_POWER_BY_THREE_CHAIN } static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, u16 cfgCtl, - u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, - u8 powerLimit) + struct ath9k_channel *chan, u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) { #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; int16_t txPowerIndexOffset = 0; u8 ht40PowerIncForPdadc = 2; int i; + memset(ratesArray, 0, sizeof(ratesArray)); if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= - AR9287_EEP_MINOR_VER_2) + AR9287_EEP_MINOR_VER_2) ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; ath9k_hw_set_AR9287_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit); - + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset); @@ -3723,99 +3734,85 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; } - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0) - ); + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0) - ); + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); if (IS_CHAN_2GHZ(chan)) { REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0) - ); + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0) - ); + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); } REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0) - ); + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0) - ); + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); if (IS_CHAN_HT40(chan)) { if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, ATH9K_POW_SM(ratesArray[rateHt40_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0], 0) - ); + | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0], 0)); REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, ATH9K_POW_SM(ratesArray[rateHt40_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4], 0) - ); + | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4], 0)); } else { REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, ATH9K_POW_SM(ratesArray[rateHt40_3] + ht40PowerIncForPdadc, 24) | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) + ht40PowerIncForPdadc, 16) | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) + ht40PowerIncForPdadc, 8) | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0) - ); + ht40PowerIncForPdadc, 0)); REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, ATH9K_POW_SM(ratesArray[rateHt40_7] + ht40PowerIncForPdadc, 24) | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) + ht40PowerIncForPdadc, 16) | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) + ht40PowerIncForPdadc, 8) | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0) - ); - + ht40PowerIncForPdadc, 0)); } REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0) - ); + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } - if (IS_CHAN_2GHZ(chan)) i = rate1l; else @@ -3840,7 +3837,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, break; default: DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Invalid chainmask configuration\n"); + "Invalid chainmask configuration\n"); break; } } @@ -3848,7 +3845,6 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, struct ath9k_channel *chan) { - return; } static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, @@ -3856,7 +3852,6 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; - u16 antWrites[AR9287_ANT_16S]; u32 regChainOffset; u8 txRxAttenLocal; @@ -3886,7 +3881,6 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); } - REG_WRITE(ah, AR_PHY_SWITCH_COM, ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); @@ -3899,11 +3893,11 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); txRxAttenLocal = pModal->txRxAttenCh[i]; @@ -3995,23 +3989,20 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, } static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, - enum ieee80211_band freq_band) + enum ieee80211_band freq_band) { return 1; } - - - static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, - struct ath9k_channel *chan) + struct ath9k_channel *chan) { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + return pModal->antCtrlCommon & 0xFFFF; } - static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) { @@ -4020,8 +4011,8 @@ static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, u16 spur_val = AR_NO_SPUR; DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); switch (ah->config.spurmode) { case SPUR_DISABLE: @@ -4055,10 +4046,10 @@ static struct eeprom_ops eep_AR9287_ops = { .get_spur_channel = ath9k_hw_AR9287_get_spur_channel }; - int ath9k_hw_eeprom_init(struct ath_hw *ah) { int status; + if (AR_SREV_9287(ah)) { ah->eep_map = EEP_MAP_AR9287; ah->eep_ops = &eep_AR9287_ops; diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index db77e90..a644709 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -385,106 +385,103 @@ struct calDataPerFreqOpLoop { } __packed; struct modal_eep_4k_header { - u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; - u32 antCtrlCommon; - u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; - u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; - u8 adcDesiredSize; - u8 pgaDesiredSize; - u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; - u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; - u8 pdGainOverlap; - u8 ob_01; - u8 db1_01; - u8 xpaBiasLvl; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; - u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; - u8 swSettleHt40; - u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; - u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; - u8 db2_01; - u8 version; - u16 ob_234; - u16 db1_234; - u16 db2_234; - u8 futureModal[4]; - + u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; + u32 antCtrlCommon; + u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; + u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; + u8 adcDesiredSize; + u8 pgaDesiredSize; + u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; + u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; + u8 pdGainOverlap; + u8 ob_01; + u8 db1_01; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; + u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; + u8 swSettleHt40; + u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; + u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; + u8 db2_01; + u8 version; + u16 ob_234; + u16 db1_234; + u16 db2_234; + u8 futureModal[4]; struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; } __packed; struct base_eep_ar9287_header { - u16 length; - u16 checksum; - u16 version; - u8 opCapFlags; - u8 eepMisc; - u16 regDmn[2]; - u8 macAddr[6]; - u8 rxMask; - u8 txMask; - u16 rfSilent; - u16 blueToothOptions; - u16 deviceCap; - u32 binBuildNumber; - u8 deviceType; - u8 openLoopPwrCntl; - int8_t pwrTableOffset; - int8_t tempSensSlope; - int8_t tempSensSlopePalOn; - u8 futureBase[29]; + u16 length; + u16 checksum; + u16 version; + u8 opCapFlags; + u8 eepMisc; + u16 regDmn[2]; + u8 macAddr[6]; + u8 rxMask; + u8 txMask; + u16 rfSilent; + u16 blueToothOptions; + u16 deviceCap; + u32 binBuildNumber; + u8 deviceType; + u8 openLoopPwrCntl; + int8_t pwrTableOffset; + int8_t tempSensSlope; + int8_t tempSensSlopePalOn; + u8 futureBase[29]; } __packed; struct modal_eep_ar9287_header { - u32 antCtrlChain[AR9287_MAX_CHAINS]; - u32 antCtrlCommon; - int8_t antennaGainCh[AR9287_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR9287_MAX_CHAINS]; - u8 rxTxMarginCh[AR9287_MAX_CHAINS]; - int8_t adcDesiredSize; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - int8_t iqCalICh[AR9287_MAX_CHAINS]; - int8_t iqCalQCh[AR9287_MAX_CHAINS]; - u8 pdGainOverlap; - u8 xpaBiasLvl; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR9287_MAX_CHAINS]; - u8 bswMargin[AR9287_MAX_CHAINS]; - u8 swSettleHt40; - u8 version; - u8 db1; - u8 db2; - u8 ob_cck; - u8 ob_psk; - u8 ob_qam; - u8 ob_pal_off; - u8 futureModal[30]; - struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS]; + u32 antCtrlChain[AR9287_MAX_CHAINS]; + u32 antCtrlCommon; + int8_t antennaGainCh[AR9287_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR9287_MAX_CHAINS]; + u8 rxTxMarginCh[AR9287_MAX_CHAINS]; + int8_t adcDesiredSize; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + int8_t iqCalICh[AR9287_MAX_CHAINS]; + int8_t iqCalQCh[AR9287_MAX_CHAINS]; + u8 pdGainOverlap; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR9287_MAX_CHAINS]; + u8 bswMargin[AR9287_MAX_CHAINS]; + u8 swSettleHt40; + u8 version; + u8 db1; + u8 db2; + u8 ob_cck; + u8 ob_psk; + u8 ob_qam; + u8 ob_pal_off; + u8 futureModal[30]; + struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS]; } __packed; - - struct cal_data_per_freq { u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; @@ -525,7 +522,6 @@ struct cal_data_op_loop_ar9287 { u8 empty[2][5]; } __packed; - struct cal_data_per_freq_ar9287 { u8 pwrPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; u8 vpdPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; @@ -601,26 +597,25 @@ struct ar5416_eeprom_4k { } __packed; struct ar9287_eeprom { - struct base_eep_ar9287_header baseEepHeader; + struct base_eep_ar9287_header baseEepHeader; u8 custData[AR9287_DATA_SZ]; struct modal_eep_ar9287_header modalHeader; u8 calFreqPier2G[AR9287_NUM_2G_CAL_PIERS]; union cal_data_per_freq_ar9287_u - calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS]; + calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS]; struct cal_target_power_leg - calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS]; + calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS]; struct cal_target_power_leg - calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS]; + calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS]; struct cal_target_power_ht - calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS]; + calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS]; struct cal_target_power_ht - calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS]; + calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS]; u8 ctlIndex[AR9287_NUM_CTLS]; struct cal_ctl_data_ar9287 ctlData[AR9287_NUM_CTLS]; u8 padding; } __packed; - enum reg_ext_bitmap { REG_EXT_JAPAN_MIDBAND = 1, REG_EXT_FCC_DFS_HT40 = 2, -- cgit v0.10.2 From 6780ccf5652a04493f72fafd9af0d9964ee977ad Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:13 +0530 Subject: ath9k: Remove a few DEBUG mesages We have never used these at all. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 4303a4d..7931022 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -236,9 +236,6 @@ static void ath9k_olc_get_pdadcs(struct ath_hw *ah, pPDADCValues[i] = 0xFF; } - - - static void ath9k_hw_get_target_powers(struct ath_hw *ah, struct ath9k_channel *chan, struct cal_target_power_ht *powInfo, @@ -905,20 +902,8 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " - "EXT_ADDITIVE %d\n", - ctlMode, numCtlModes, isHt40CtlMode, - (pCtlMode[ctlMode] & EXT_ADDITIVE)); - for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " - "chan %d\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == @@ -936,13 +921,6 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, IS_CHAN_2GHZ(chan), AR5416_EEP4K_NUM_BAND_EDGES); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " MATCH-EE_IDX %d: ch %d is2 %d " - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains - (tx_chainmask)); if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { twiceMaxEdgePower = min(twiceMaxEdgePower, @@ -956,12 +934,6 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " SEL-Min ctlMode %d pCtlMode %d " - "2xMaxEdge %d sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - switch (pCtlMode[ctlMode]) { case CTL_11B: for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); @@ -2491,20 +2463,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " - "EXT_ADDITIVE %d\n", - ctlMode, numCtlModes, isHt40CtlMode, - (pCtlMode[ctlMode] & EXT_ADDITIVE)); - for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " - "chan %d\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); - if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || @@ -2517,13 +2476,6 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " MATCH-EE_IDX %d: ch %d is2 %d " - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains - (tx_chainmask)); if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { twiceMaxEdgePower = min(twiceMaxEdgePower, twiceMinEdgePower); @@ -2536,12 +2488,6 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, minCtlPower = min(twiceMaxEdgePower, scaledPower); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " SEL-Min ctlMode %d pCtlMode %d " - "2xMaxEdge %d sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - switch (pCtlMode[ctlMode]) { case CTL_11B: for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { @@ -2898,17 +2844,15 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) if (!ath9k_hw_use_flash(ah)) { if (!ath9k_hw_nvram_read - (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Reading Magic # failed\n"); + "Reading Magic # failed\n"); return false; } DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { - - magic2 = swab16(magic); if (magic2 == AR5416_EEPROM_MAGIC) { @@ -2924,13 +2868,14 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) } } else { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "endianness mismatch.\n"); - return -EINVAL; } + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } } } DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? - "True" : "False"); + "True" : "False"); if (need_swap) el = swab16(ah->eeprom.map9287.baseEepHeader.length); @@ -3360,19 +3305,19 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, if (i == 0) { if (!ath9k_hw_AR9287_get_eeprom( - ah, EEP_OL_PWRCTRL)) { + ah, EEP_OL_PWRCTRL)) { REG_WRITE(ah, AR_PHY_TPCRG5 + - regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | - SM(gainBoundaries[0], + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); } } @@ -3394,6 +3339,7 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, pdadcValues[ AR9287_NUM_PDADC_VALUES-diff]; } + if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; @@ -3412,6 +3358,7 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PDADC: Chain %d | " "PDADC %3d Value %3d | " @@ -3542,20 +3489,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d," - "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, - isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); - - for (i = 0; (i < AR9287_NUM_CTLS) - && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "LOOP-Ctlidx %d: cfgCtl 0x%2.2x" - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x" - "chan %d chanctl=xxxx\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); - + for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || @@ -3571,13 +3505,6 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, tx_chainmask) - 1], IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "MATCH-EE_IDX %d: ch %d is2 %d" - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains(tx_chainmask)); - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) twiceMaxEdgePower = min( twiceMaxEdgePower, @@ -3591,14 +3518,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d" - "sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - switch (pCtlMode[ctlMode]) { - case CTL_11B: for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); @@ -3670,7 +3590,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; if (IS_CHAN_2GHZ(chan)) { - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; ratesArray[rate5_5s] = ratesArray[rate5_5l] = @@ -3686,7 +3606,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; if (IS_CHAN_2GHZ(chan)) - ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; } #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN -- cgit v0.10.2 From b5aec950eeb433d4850c1e5fcf14b666048e647d Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:15 +0530 Subject: ath9k: Split eeprom.c into manageable pieces Add eeprom_def.c, eeprom_4k.c and eeprom_9287.c This improves maintainability. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 783bc39..28443e0 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -1,5 +1,8 @@ ath9k-y += hw.o \ eeprom.o \ + eeprom_def.o \ + eeprom_4k.o \ + eeprom_9287.o \ mac.o \ calib.o \ ani.o \ diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 7931022..958948b 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -16,9 +16,16 @@ #include "ath9k.h" -static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, - u32 reg, u32 mask, - u32 shift, u32 val) +static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) +{ + if (fbin == AR5416_BCHAN_UNUSED) + return fbin; + + return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); +} + +void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, + u32 shift, u32 val) { u32 regVal; @@ -33,18 +40,8 @@ static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, return; } -static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) -{ - if (fbin == AR5416_BCHAN_UNUSED) - return fbin; - - return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); -} - -static inline int16_t ath9k_hw_interpolate(u16 target, - u16 srcLeft, u16 srcRight, - int16_t targetLeft, - int16_t targetRight) +int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, + int16_t targetLeft, int16_t targetRight) { int16_t rv; @@ -58,9 +55,8 @@ static inline int16_t ath9k_hw_interpolate(u16 target, return rv; } -static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, - u16 listSize, u16 *indexL, - u16 *indexR) +bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, + u16 *indexL, u16 *indexR) { u16 i; @@ -87,16 +83,16 @@ static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, return false; } -static inline bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) +bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) { struct ath_softc *sc = ah->ah_sc; return sc->bus_ops->eeprom_read(ah, off, data); } -static inline void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, - u8 *pVpdList, u16 numIntercepts, - u8 *pRetVpdList) +void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, + u8 *pVpdList, u16 numIntercepts, + u8 *pRetVpdList) { u16 i, k; u8 currPwr = pwrMin; @@ -121,12 +117,12 @@ static inline void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, } } -static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_target_power_leg *powInfo, - u16 numChannels, - struct cal_target_power_leg *pNewPower, - u16 numRates, bool isExtTarget) +void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_leg *powInfo, + u16 numChannels, + struct cal_target_power_leg *pNewPower, + u16 numRates, bool isExtTarget) { struct chan_centers centers; u16 clo, chi; @@ -176,72 +172,12 @@ static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, } } -static void ath9k_get_txgain_index(struct ath_hw *ah, - struct ath9k_channel *chan, - struct calDataPerFreqOpLoop *rawDatasetOpLoop, - u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) -{ - u8 pcdac, i = 0; - u16 idxL = 0, idxR = 0, numPiers; - bool match; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) - if (calChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - - match = ath9k_hw_get_lower_upper_index( - (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), - calChans, numPiers, &idxL, &idxR); - if (match) { - pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; - *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; - } else { - pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; - *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + - rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; - } - - while (pcdac > ah->originalGain[i] && - i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) - i++; - - *pcdacIdx = i; - return; -} - -static void ath9k_olc_get_pdadcs(struct ath_hw *ah, - u32 initTxGain, - int txPower, - u8 *pPDADCValues) -{ - u32 i; - u32 offset; - - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, - AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, - AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); - - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, - AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); - - offset = txPower; - for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) - if (i < offset) - pPDADCValues[i] = 0x0; - else - pPDADCValues[i] = 0xFF; -} - -static void ath9k_hw_get_target_powers(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_target_power_ht *powInfo, - u16 numChannels, - struct cal_target_power_ht *pNewPower, - u16 numRates, bool isHt40Target) +void ath9k_hw_get_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_ht *powInfo, + u16 numChannels, + struct cal_target_power_ht *pNewPower, + u16 numRates, bool isHt40Target) { struct chan_centers centers; u16 clo, chi; @@ -291,9 +227,8 @@ static void ath9k_hw_get_target_powers(struct ath_hw *ah, } } -static u16 ath9k_hw_get_max_edge_power(u16 freq, - struct cal_ctl_edges *pRdEdgesPower, - bool is2GHz, int num_band_edges) +u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, + bool is2GHz, int num_band_edges) { u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; int i; @@ -319,3653 +254,6 @@ static u16 ath9k_hw_get_max_edge_power(u16 freq, return twiceMaxEdgePower; } -/****************************************/ -/* EEPROM Operations for 4K sized cards */ -/****************************************/ - -static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) -{ - return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); -} - -static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) -{ - return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); -} - -static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) -{ -#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) - u16 *eep_data = (u16 *)&ah->eeprom.map4k; - int addr, eep_start_loc = 0; - - eep_start_loc = 64; - - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); - } - - for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { - if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); - return false; - } - eep_data++; - } - - return true; -#undef SIZE_EEPROM_4K -} - -static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) -{ -#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) - struct ar5416_eeprom_4k *eep = - (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; - u16 *eepdata, temp, magic, magic2; - u32 sum = 0, el; - bool need_swap = false; - int i, addr; - - - if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Reading Magic # failed\n"); - return false; - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *) (&ah->eeprom); - - for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "endianness mismatch.\n"); - return -EINVAL; - } - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); - - if (need_swap) - el = swab16(ah->eeprom.map4k.baseEepHeader.length); - else - el = ah->eeprom.map4k.baseEepHeader.length; - - if (el > sizeof(struct ar5416_eeprom_4k)) - el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; - - if (need_swap) { - u32 integer; - u16 word; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing\n"); - - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; - - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; - - integer = swab32(eep->modalHeader.antCtrlCommon); - eep->modalHeader.antCtrlCommon = integer; - - for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { - integer = swab32(eep->modalHeader.antCtrlChain[i]); - eep->modalHeader.antCtrlChain[i] = integer; - } - - for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { - word = swab16(eep->modalHeader.spurChans[i].spurChan); - eep->modalHeader.spurChans[i].spurChan = word; - } - } - - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || - ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); - return -EINVAL; - } - - return 0; -#undef EEPROM_4K_SIZE -} - -static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, - enum eeprom_param param) -{ - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - struct modal_eep_4k_header *pModal = &eep->modalHeader; - struct base_eep_header_4k *pBase = &eep->baseEepHeader; - - switch (param) { - case EEP_NFTHRESH_2: - return pModal->noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_OB_2: - return pModal->ob_01; - case EEP_DB_2: - return pModal->db1_01; - case EEP_MINOR_REV: - return pBase->version & AR5416_EEP_VER_MINOR_MASK; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - case EEP_FRAC_N_5G: - return 0; - default: - return 0; - } -} - -static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq_4k *pRawDataSet, - u8 *bChans, u16 availPiers, - u16 tPdGainOverlap, int16_t *pMinCalPower, - u16 *pPdGainBoundaries, u8 *pPDADCValues, - u16 numXpdGains) -{ -#define TMP_VAL_VPD_TABLE \ - ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; - u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; -#define PD_GAIN_BOUNDARY_DEFAULT 58; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index( - (u8)FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)), bChans, numPiers, - &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL].pwrPdg[i], - pRawDataSet[idxL].vpdPdg[i], - AR5416_EEP4K_PD_GAIN_ICEPTS, - vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], - pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); - - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR5416_EEP4K_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR5416_EEP4K_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8)(ath9k_hw_interpolate((u16) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), - bChans[idxL], bChans[idxR], - vpdTableL[i][j], vpdTableR[i][j])); - } - } - } - - *pMinCalPower = (int16_t)(minPwrT4[0] / 2); - - k = 0; - - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = - (u16)(maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = - (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); - - pPdGainBoundaries[i] = - min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); - - if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t)(0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else { - ss = (int16_t)((pPdGainBoundaries[i - 1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - } - vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < sizeCurrVpdTable) ? - tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) - pPDADCValues[k++] = vpdTableI[i][ss++]; - - vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - if (tgtIndex >= maxIndex) { - while ((ss <= tgtIndex) && - (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t) TMP_VAL_VPD_TABLE; - pPDADCValues[k++] = (u8)((tmpVal > 255) ? - 255 : tmpVal); - ss++; - } - } - } - - while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; - i++; - } - - while (k < AR5416_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k - 1]; - k++; - } - - return; -#undef TMP_VAL_VPD_TABLE -} - -static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ - struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - struct cal_data_per_freq_4k *pRawDataset; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK]; - u16 numPiers, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 }; - u32 reg32, regOffset, regChainOffset; - - xpdMask = pEepData->modalHeader.xpdGain; - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - pdGainOverlap_t2 = - pEepData->modalHeader.pdGainOverlap; - } else { - pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } - - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; - - numXpdGain = 0; - - for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); - - for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && - (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; - - if (pEepData->baseEepHeader.txMask & (1 << i)) { - pRawDataset = pEepData->calPierData2G[i]; - - ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, - pRawDataset, pCalBChans, - numPiers, pdGainOverlap_t2, - &tMinCalPower, gainBoundaries, - pdadcValues, numXpdGain); - - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { - REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) - | SM(gainBoundaries[0], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); - } - - regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | - ((pdadcValues[4 * j + 1] & 0xFF) << 8) | - ((pdadcValues[4 * j + 2] & 0xFF) << 16)| - ((pdadcValues[4 * j + 3] & 0xFF) << 24); - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC: Chain %d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - - *pTxPowerIndexOffset = 0; -} - -static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, - u16 powerLimit) -{ - struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - - int i; - int16_t twiceLargestAntenna; - struct cal_ctl_data_4k *rep; - struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { - 0, { 0, 0, 0, 0} - }; - struct cal_target_power_leg targetPowerOfdmExt = { - 0, { 0, 0, 0, 0} }, targetPowerCckExt = { - 0, { 0, 0, 0, 0 } - }; - struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { - 0, {0, 0, 0, 0} - }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u16 twiceMinEdgePower; - - tx_chainmask = ah->txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; - - twiceLargestAntenna = (int16_t)min(AntennaReduction - - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); - scaledPower = max((u16)0, scaledPower); - - numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT40, - AR5416_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || - (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && - pEepData->ctlIndex[i]; i++) { - - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & CTL_MODE_M) | - SD_NO_CTL))) { - rep = &(pEepData->ctlData[i]); - - twiceMinEdgePower = - ath9k_hw_get_max_edge_power(freq, - rep->ctlEdges[ar5416_get_ntxchains - (tx_chainmask) - 1], - IS_CHAN_2GHZ(chan), - AR5416_EEP4K_NUM_BAND_EDGES); - - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { - twiceMaxEdgePower = - min(twiceMaxEdgePower, - twiceMinEdgePower); - } else { - twiceMaxEdgePower = twiceMinEdgePower; - break; - } - } - } - - minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); - i++) { - targetPowerCck.tPow2x[i] = - min((u16)targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); - i++) { - targetPowerOfdm.tPow2x[i] = - min((u16)targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); - i++) { - targetPowerHt20.tPow2x[i] = - min((u16)targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = min((u16) - targetPowerCckExt.tPow2x[0], - minCtlPower); - break; - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = min((u16) - targetPowerOfdmExt.tPow2x[0], - minCtlPower); - break; - case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); - i++) { - targetPowerHt40.tPow2x[i] = - min((u16)targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; - ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; - - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - ratesArray[rateHt40_0 + i] = - targetPowerHt40.tPow2x[i]; - } - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; - } -} - -static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ - struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - struct modal_eep_4k_header *pModal = &pEepData->modalHeader; - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i; - - memset(ratesArray, 0, sizeof(ratesArray)); - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } - - ath9k_hw_set_4k_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit); - - ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); - - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR5416_MAX_RATE_POWER) - ratesArray[i] = AR5416_MAX_RATE_POWER; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0)); - - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); - - if (IS_CHAN_HT40(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0)); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); - } - - i = rate6mb; - - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->regulatory.max_power_level = ratesArray[i]; - -} - -static void ath9k_hw_4k_set_addac(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct modal_eep_4k_header *pModal; - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - u8 biaslevel; - - if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) - return; - - if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) - return; - - pModal = &eep->modalHeader; - - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - INI_RA(&ah->iniAddac, 7, 1) = - (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; - } -} - -static void ath9k_hw_4k_set_gain(struct ath_hw *ah, - struct modal_eep_4k_header *pModal, - struct ar5416_eeprom_4k *eep, - u8 txRxAttenLocal, int regChainOffset) -{ - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[0]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - txRxAttenLocal = pModal->txRxAttenCh[0]; - - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal->xatten2Margin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); - - /* Set the block 1 value to block 0 value */ - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, - pModal->bswMargin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal->xatten2Margin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, - pModal->xatten2Db[0]); - } - - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); - - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, - AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, - AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); - - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); -} - -/* - * Read EEPROM header info and program the device for correct operation - * given the channel value. - */ -static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct modal_eep_4k_header *pModal; - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - u8 txRxAttenLocal; - u8 ob[5], db1[5], db2[5]; - u8 ant_div_control1, ant_div_control2; - u32 regVal; - - pModal = &eep->modalHeader; - txRxAttenLocal = 23; - - REG_WRITE(ah, AR_PHY_SWITCH_COM, - ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); - - /* Single chain for 4K EEPROM*/ - ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); - - /* Initialize Ant Diversity settings from EEPROM */ - if (pModal->version >= 3) { - ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); - ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); - regVal = REG_READ(ah, 0x99ac); - regVal &= (~(0x7f000000)); - regVal |= ((ant_div_control1 & 0x1) << 24); - regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); - regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); - regVal |= ((ant_div_control2 & 0x3) << 25); - regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); - REG_WRITE(ah, 0x99ac, regVal); - regVal = REG_READ(ah, 0x99ac); - regVal = REG_READ(ah, 0xa208); - regVal &= (~(0x1 << 13)); - regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); - REG_WRITE(ah, 0xa208, regVal); - regVal = REG_READ(ah, 0xa208); - } - - if (pModal->version >= 2) { - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = (pModal->ob_01 >> 4) & 0xf; - ob[2] = (pModal->ob_234 & 0xf); - ob[3] = ((pModal->ob_234 >> 4) & 0xf); - ob[4] = ((pModal->ob_234 >> 8) & 0xf); - - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = ((pModal->db1_01 >> 4) & 0xf); - db1[2] = (pModal->db1_234 & 0xf); - db1[3] = ((pModal->db1_234 >> 4) & 0xf); - db1[4] = ((pModal->db1_234 >> 8) & 0xf); - - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = ((pModal->db2_01 >> 4) & 0xf); - db2[2] = (pModal->db2_234 & 0xf); - db2[3] = ((pModal->db2_234 >> 4) & 0xf); - db2[4] = ((pModal->db2_234 >> 8) & 0xf); - - } else if (pModal->version == 1) { - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = db1[2] = db1[3] = - db1[4] = ((pModal->db1_01 >> 4) & 0xf); - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = db2[2] = db2[3] = - db2[4] = ((pModal->db2_01 >> 4) & 0xf); - } else { - int i; - for (i = 0; i < 5; i++) { - ob[i] = pModal->ob_01; - db1[i] = pModal->db1_01; - db2[i] = pModal->db1_01; - } - } - - if (AR_SREV_9271(ah)) { - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9271_AN_RF2G3_OB_cck, - AR9271_AN_RF2G3_OB_cck_S, - ob[0]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9271_AN_RF2G3_OB_psk, - AR9271_AN_RF2G3_OB_psk_S, - ob[1]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9271_AN_RF2G3_OB_qam, - AR9271_AN_RF2G3_OB_qam_S, - ob[2]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9271_AN_RF2G3_DB_1, - AR9271_AN_RF2G3_DB_1_S, - db1[0]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9271_AN_RF2G4_DB_2, - AR9271_AN_RF2G4_DB_2_S, - db2[0]); - } else { - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_0, - AR9285_AN_RF2G3_OB_0_S, - ob[0]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_1, - AR9285_AN_RF2G3_OB_1_S, - ob[1]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_2, - AR9285_AN_RF2G3_OB_2_S, - ob[2]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_3, - AR9285_AN_RF2G3_OB_3_S, - ob[3]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_4, - AR9285_AN_RF2G3_OB_4_S, - ob[4]); - - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_0, - AR9285_AN_RF2G3_DB1_0_S, - db1[0]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_1, - AR9285_AN_RF2G3_DB1_1_S, - db1[1]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_2, - AR9285_AN_RF2G3_DB1_2_S, - db1[2]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_3, - AR9285_AN_RF2G4_DB1_3_S, - db1[3]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_4, - AR9285_AN_RF2G4_DB1_4_S, db1[4]); - - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_0, - AR9285_AN_RF2G4_DB2_0_S, - db2[0]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_1, - AR9285_AN_RF2G4_DB2_1_S, - db2[1]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_2, - AR9285_AN_RF2G4_DB2_2_S, - db2[2]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_3, - AR9285_AN_RF2G4_DB2_3_S, - db2[3]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_4, - AR9285_AN_RF2G4_DB2_4_S, - db2[4]); - } - - - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); - - REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, - pModal->switchSettling); - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, - pModal->adcDesiredSize); - - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, - pModal->txEndToRxOn); - REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, - pModal->thresh62); - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, - pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, - pModal->txFrameToPaOn); - } - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, - pModal->swSettleHt40); - } -} - -static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - struct modal_eep_4k_header *pModal = &eep->modalHeader; - - return pModal->antCtrlCommon & 0xFFFF; -} - -static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah, - enum ieee80211_band freq_band) -{ - return 1; -} - -static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) -{ -#define EEP_MAP4K_SPURCHAN \ - (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) - - u16 spur_val = AR_NO_SPUR; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); - - switch (ah->config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = EEP_MAP4K_SPURCHAN; - break; - } - - return spur_val; - -#undef EEP_MAP4K_SPURCHAN -} - -static struct eeprom_ops eep_4k_ops = { - .check_eeprom = ath9k_hw_4k_check_eeprom, - .get_eeprom = ath9k_hw_4k_get_eeprom, - .fill_eeprom = ath9k_hw_4k_fill_eeprom, - .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, - .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, - .get_num_ant_config = ath9k_hw_4k_get_num_ant_config, - .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg, - .set_board_values = ath9k_hw_4k_set_board_values, - .set_addac = ath9k_hw_4k_set_addac, - .set_txpower = ath9k_hw_4k_set_txpower, - .get_spur_channel = ath9k_hw_4k_get_spur_channel -}; - -/************************************************/ -/* EEPROM Operations for non-4K (Default) cards */ -/************************************************/ - -static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah) -{ - return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF); -} - -static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) -{ - return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); -} - -static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) -{ -#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) - u16 *eep_data = (u16 *)&ah->eeprom.def; - int addr, ar5416_eep_start_loc = 0x100; - - for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { - if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, - eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Unable to read eeprom region\n"); - return false; - } - eep_data++; - } - return true; -#undef SIZE_EEPROM_DEF -} - -static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) -{ - struct ar5416_eeprom_def *eep = - (struct ar5416_eeprom_def *) &ah->eeprom.def; - u16 *eepdata, temp, magic, magic2; - u32 sum = 0, el; - bool need_swap = false; - int i, addr, size; - - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); - return false; - } - - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - size = sizeof(struct ar5416_eeprom_def); - need_swap = true; - eepdata = (u16 *) (&ah->eeprom); - - for (addr = 0; addr < size / sizeof(u16); addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "Endianness mismatch.\n"); - return -EINVAL; - } - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); - - if (need_swap) - el = swab16(ah->eeprom.def.baseEepHeader.length); - else - el = ah->eeprom.def.baseEepHeader.length; - - if (el > sizeof(struct ar5416_eeprom_def)) - el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; - - if (need_swap) { - u32 integer, j; - u16 word; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing.\n"); - - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; - - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; - - for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { - struct modal_eep_header *pModal = - &eep->modalHeader[j]; - integer = swab32(pModal->antCtrlCommon); - pModal->antCtrlCommon = integer; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - integer = swab32(pModal->antCtrlChain[i]); - pModal->antCtrlChain[i] = integer; - } - - for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { - word = swab16(pModal->spurChans[i].spurChan); - pModal->spurChans[i].spurChan = word; - } - } - } - - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || - ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); - return -EINVAL; - } - - return 0; -} - -static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, - enum eeprom_param param) -{ - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - struct modal_eep_header *pModal = eep->modalHeader; - struct base_eep_header *pBase = &eep->baseEepHeader; - - switch (param) { - case EEP_NFTHRESH_5: - return pModal[0].noiseFloorThreshCh[0]; - case EEP_NFTHRESH_2: - return pModal[1].noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_OB_5: - return pModal[0].ob; - case EEP_DB_5: - return pModal[0].db; - case EEP_OB_2: - return pModal[1].ob; - case EEP_DB_2: - return pModal[1].db; - case EEP_MINOR_REV: - return AR5416_VER_MASK; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - case EEP_RXGAIN_TYPE: - return pBase->rxGainType; - case EEP_TXGAIN_TYPE: - return pBase->txGainType; - case EEP_OL_PWRCTRL: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) - return pBase->openLoopPwrCntl ? true : false; - else - return false; - case EEP_RC_CHAIN_MASK: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) - return pBase->rcChainMask; - else - return 0; - case EEP_DAC_HPWR_5G: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) - return pBase->dacHiPwrMode_5G; - else - return 0; - case EEP_FRAC_N_5G: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) - return pBase->frac_n_5g; - else - return 0; - default: - return 0; - } -} - -static void ath9k_hw_def_set_gain(struct ath_hw *ah, - struct modal_eep_header *pModal, - struct ar5416_eeprom_def *eep, - u8 txRxAttenLocal, int regChainOffset, int i) -{ - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { - txRxAttenLocal = pModal->txRxAttenCh[i]; - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, - pModal->bswMargin[i]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, - pModal->bswAtten[i]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal->xatten2Margin[i]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, - pModal->xatten2Db[i]); - } else { - REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) - | SM(pModal-> bswMargin[i], - AR_PHY_GAIN_2GHZ_BSW_MARGIN)); - REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) - | SM(pModal->bswAtten[i], - AR_PHY_GAIN_2GHZ_BSW_ATTEN)); - } - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); - } else { - REG_WRITE(ah, - AR_PHY_RXGAIN + regChainOffset, - (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & - ~AR_PHY_RXGAIN_TXRX_ATTEN) - | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | - SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); - } -} - -static void ath9k_hw_def_set_board_values(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct modal_eep_header *pModal; - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - int i, regChainOffset; - u8 txRxAttenLocal; - - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; - - REG_WRITE(ah, AR_PHY_SWITCH_COM, - ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_9280(ah)) { - if (i >= 2) - break; - } - - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - else - regChainOffset = i * 0x1000; - - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[i]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) - ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, - regChainOffset, i); - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - if (IS_CHAN_2GHZ(chan)) { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_OB, - AR_AN_RF2G1_CH0_OB_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_DB, - AR_AN_RF2G1_CH0_DB_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_OB, - AR_AN_RF2G1_CH1_OB_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_DB, - AR_AN_RF2G1_CH1_DB_S, - pModal->db_ch1); - } else { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_OB5, - AR_AN_RF5G1_CH0_OB5_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_DB5, - AR_AN_RF5G1_CH0_DB5_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_OB5, - AR_AN_RF5G1_CH1_OB5_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_DB5, - AR_AN_RF5G1_CH1_DB5_S, - pModal->db_ch1); - } - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_XPABIAS_LVL, - AR_AN_TOP2_XPABIAS_LVL_S, - pModal->xpaBiasLvl); - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_LOCALBIAS, - AR_AN_TOP2_LOCALBIAS_S, - pModal->local_bias); - REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, - pModal->force_xpaon); - } - - REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, - pModal->switchSettling); - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, - pModal->adcDesiredSize); - - if (!AR_SREV_9280_10_OR_LATER(ah)) - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_PGA, - pModal->pgaDesiredSize); - - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) - | SM(pModal->txEndToXpaOff, - AR_PHY_RF_CTL4_TX_END_XPAB_OFF) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAA_ON) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAB_ON)); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, - pModal->txEndToRxOn); - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, - AR_PHY_EXT_CCA0_THRESH62, - pModal->thresh62); - } else { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, - AR_PHY_EXT_CCA_THRESH62, - pModal->thresh62); - } - - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, - AR_PHY_TX_END_DATA_START, - pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, - pModal->txFrameToPaOn); - } - - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, - pModal->swSettleHt40); - } - - if (AR_SREV_9280_20_OR_LATER(ah) && - AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) - REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, - AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, - pModal->miscBits); - - - if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { - if (IS_CHAN_2GHZ(chan)) - REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, - eep->baseEepHeader.dacLpMode); - else if (eep->baseEepHeader.dacHiPwrMode_5G) - REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); - else - REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, - eep->baseEepHeader.dacLpMode); - - REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, - pModal->miscBits >> 2); - - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, - AR_PHY_TX_DESIRED_SCALE_CCK, - eep->baseEepHeader.desiredScaleCCK); - } -} - -static void ath9k_hw_def_set_addac(struct ath_hw *ah, - struct ath9k_channel *chan) -{ -#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) - struct modal_eep_header *pModal; - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - u8 biaslevel; - - if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) - return; - - if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) - return; - - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - } else { - u16 resetFreqBin, freqBin, freqCount = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - resetFreqBin = FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)); - freqBin = XPA_LVL_FREQ(0) & 0xff; - biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); - - freqCount++; - - while (freqCount < 3) { - if (XPA_LVL_FREQ(freqCount) == 0x0) - break; - - freqBin = XPA_LVL_FREQ(freqCount) & 0xff; - if (resetFreqBin >= freqBin) - biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); - else - break; - freqCount++; - } - } - - if (IS_CHAN_2GHZ(chan)) { - INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac, - 7, 1) & (~0x18)) | biaslevel << 3; - } else { - INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac, - 6, 1) & (~0xc0)) | biaslevel << 6; - } -#undef XPA_LVL_FREQ -} - -static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq *pRawDataSet, - u8 *bChans, u16 availPiers, - u16 tPdGainOverlap, int16_t *pMinCalPower, - u16 *pPdGainBoundaries, u8 *pPDADCValues, - u16 numXpdGains) -{ - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - static u8 vpdTableL[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR5416_NUM_PD_GAINS]; - u8 maxPwrT4[AR5416_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)), - bChans, numPiers, &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL].pwrPdg[i], - pRawDataSet[idxL].vpdPdg[i], - AR5416_PD_GAIN_ICEPTS, - vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], - pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); - - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR5416_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR5416_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8)(ath9k_hw_interpolate((u16) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), - bChans[idxL], bChans[idxR], - vpdTableL[i][j], vpdTableR[i][j])); - } - } - } - - *pMinCalPower = (int16_t)(minPwrT4[0] / 2); - - k = 0; - - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = - (u16)(maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = - (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); - - pPdGainBoundaries[i] = - min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); - - if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t)(0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else { - ss = (int16_t)((pPdGainBoundaries[i - 1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - } - vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < sizeCurrVpdTable) ? - tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - pPDADCValues[k++] = vpdTableI[i][ss++]; - } - - vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - if (tgtIndex > maxIndex) { - while ((ss <= tgtIndex) && - (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + - (ss - maxIndex + 1) * vpdStep)); - pPDADCValues[k++] = (u8)((tmpVal > 255) ? - 255 : tmpVal); - ss++; - } - } - } - - while (i < AR5416_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; - i++; - } - - while (k < AR5416_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k - 1]; - k++; - } - - return; -} - -static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ -#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) -#define SM_PDGAIN_B(x, y) \ - SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) - - struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; - struct cal_data_per_freq *pRawDataset; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; - u16 numPiers, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; - u32 reg32, regOffset, regChainOffset; - int16_t modalIdx; - - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; - xpdMask = pEepData->modalHeader[modalIdx].xpdGain; - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - pdGainOverlap_t2 = - pEepData->modalHeader[modalIdx].pdGainOverlap; - } else { - pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } - - if (IS_CHAN_2GHZ(chan)) { - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_NUM_2G_CAL_PIERS; - } else { - pCalBChans = pEepData->calFreqPier5G; - numPiers = AR5416_NUM_5G_CAL_PIERS; - } - - if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { - pRawDataset = pEepData->calPierData2G[0]; - ah->initPDADC = ((struct calDataPerFreqOpLoop *) - pRawDataset)->vpdPdg[0][0]; - } - - numXpdGain = 0; - - for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16)(AR5416_PD_GAINS_IN_MASK - i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, - xpdGainValues[2]); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && - (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; - - if (pEepData->baseEepHeader.txMask & (1 << i)) { - if (IS_CHAN_2GHZ(chan)) - pRawDataset = pEepData->calPierData2G[i]; - else - pRawDataset = pEepData->calPierData5G[i]; - - - if (OLC_FOR_AR9280_20_LATER) { - u8 pcdacIdx; - u8 txPower; - - ath9k_get_txgain_index(ah, chan, - (struct calDataPerFreqOpLoop *)pRawDataset, - pCalBChans, numPiers, &txPower, &pcdacIdx); - ath9k_olc_get_pdadcs(ah, pcdacIdx, - txPower/2, pdadcValues); - } else { - ath9k_hw_get_def_gain_boundaries_pdadcs(ah, - chan, pRawDataset, - pCalBChans, numPiers, - pdGainOverlap_t2, - &tMinCalPower, - gainBoundaries, - pdadcValues, - numXpdGain); - } - - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { - if (OLC_FOR_AR9280_20_LATER) { - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(0x6, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | - SM_PD_GAIN(1) | SM_PD_GAIN(2) | - SM_PD_GAIN(3) | SM_PD_GAIN(4)); - } else { - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| - SM_PDGAIN_B(0, 1) | - SM_PDGAIN_B(1, 2) | - SM_PDGAIN_B(2, 3) | - SM_PDGAIN_B(3, 4)); - } - } - - regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | - ((pdadcValues[4 * j + 1] & 0xFF) << 8) | - ((pdadcValues[4 * j + 2] & 0xFF) << 16)| - ((pdadcValues[4 * j + 3] & 0xFF) << 24); - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC: Chain %d | PDADC %3d " - "Value %3d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d | PDADC %3d " - "Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - - *pTxPowerIndexOffset = 0; -#undef SM_PD_GAIN -#undef SM_PDGAIN_B -} - -static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, - u16 powerLimit) -{ -#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ -#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ - - struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - - int i; - int16_t twiceLargestAntenna; - struct cal_ctl_data *rep; - struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { - 0, { 0, 0, 0, 0} - }; - struct cal_target_power_leg targetPowerOfdmExt = { - 0, { 0, 0, 0, 0} }, targetPowerCckExt = { - 0, { 0, 0, 0, 0 } - }; - struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { - 0, {0, 0, 0, 0} - }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11a[] = - { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u16 twiceMinEdgePower; - - tx_chainmask = ah->txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = max( - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[0], - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); - - twiceLargestAntenna = max((u8)twiceLargestAntenna, - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); - - twiceLargestAntenna = (int16_t)min(AntennaReduction - - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); - - switch (ar5416_get_ntxchains(tx_chainmask)) { - case 1: - break; - case 2: - scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; - break; - case 3: - scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; - break; - } - - scaledPower = max((u16)0, scaledPower); - - if (IS_CHAN_2GHZ(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g) - - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT40, - AR5416_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - } else { - numCtlModes = ARRAY_SIZE(ctlModesFor11a) - - SUB_NUM_CTL_MODES_AT_5G_40; - pCtlMode = ctlModesFor11a; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower5GHT20, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11a); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower5GHT40, - AR5416_NUM_5G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || - (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { - rep = &(pEepData->ctlData[i]); - - twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, - rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], - IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { - twiceMaxEdgePower = min(twiceMaxEdgePower, - twiceMinEdgePower); - } else { - twiceMaxEdgePower = twiceMinEdgePower; - break; - } - } - } - - minCtlPower = min(twiceMaxEdgePower, scaledPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { - targetPowerCck.tPow2x[i] = - min((u16)targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11A: - case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { - targetPowerOfdm.tPow2x[i] = - min((u16)targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_5GHT20: - case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { - targetPowerHt20.tPow2x[i] = - min((u16)targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = min((u16) - targetPowerCckExt.tPow2x[0], - minCtlPower); - break; - case CTL_11A_EXT: - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = min((u16) - targetPowerOfdmExt.tPow2x[0], - minCtlPower); - break; - case CTL_5GHT40: - case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - targetPowerHt40.tPow2x[i] = - min((u16)targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = - targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = - targetPowerCck.tPow2x[2]; - ratesArray[rate11s] = ratesArray[rate11l] = - targetPowerCck.tPow2x[3]; - } - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - ratesArray[rateHt40_0 + i] = - targetPowerHt40.tPow2x[i]; - } - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rateExtCck] = - targetPowerCckExt.tPow2x[0]; - } - } -} - -static void ath9k_hw_def_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ -#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) - struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; - struct modal_eep_header *pModal = - &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i, cck_ofdm_delta = 0; - - memset(ratesArray, 0, sizeof(ratesArray)); - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } - - ath9k_hw_set_def_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit); - - ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset); - - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR5416_MAX_RATE_POWER) - ratesArray[i] = AR5416_MAX_RATE_POWER; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0)); - - if (IS_CHAN_2GHZ(chan)) { - if (OLC_FOR_AR9280_20_LATER) { - cck_ofdm_delta = 2; - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) - | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) - | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) - | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) - | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); - } else { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); - } - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); - - if (IS_CHAN_HT40(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0)); - if (OLC_FOR_AR9280_20_LATER) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); - } else { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); - } - } - - REG_WRITE(ah, AR_PHY_POWER_TX_SUB, - ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) - | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); - - i = rate6mb; - - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->regulatory.max_power_level = ratesArray[i]; - - switch(ar5416_get_ntxchains(ah->txchainmask)) { - case 1: - break; - case 2: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; - break; - case 3: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Invalid chainmask configuration\n"); - break; - } -} - -static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, - enum ieee80211_band freq_band) -{ - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - struct modal_eep_header *pModal = - &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); - struct base_eep_header *pBase = &eep->baseEepHeader; - u8 num_ant_config; - - num_ant_config = 1; - - if (pBase->version >= 0x0E0D) - if (pModal->useAnt1) - num_ant_config += 1; - - return num_ant_config; -} - -static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - struct modal_eep_header *pModal = - &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - - return pModal->antCtrlCommon & 0xFFFF; -} - -static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) -{ -#define EEP_DEF_SPURCHAN \ - (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) - - u16 spur_val = AR_NO_SPUR; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); - - switch (ah->config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = EEP_DEF_SPURCHAN; - break; - } - - return spur_val; - -#undef EEP_DEF_SPURCHAN -} - -static struct eeprom_ops eep_def_ops = { - .check_eeprom = ath9k_hw_def_check_eeprom, - .get_eeprom = ath9k_hw_def_get_eeprom, - .fill_eeprom = ath9k_hw_def_fill_eeprom, - .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, - .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, - .get_num_ant_config = ath9k_hw_def_get_num_ant_config, - .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg, - .set_board_values = ath9k_hw_def_set_board_values, - .set_addac = ath9k_hw_def_set_addac, - .set_txpower = ath9k_hw_def_set_txpower, - .get_spur_channel = ath9k_hw_def_get_spur_channel -}; - -static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) -{ - return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; -} - -static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) -{ - return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; -} - -static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) -{ - struct ar9287_eeprom *eep = &ah->eeprom.map9287; - u16 *eep_data; - int addr, eep_start_loc = AR9287_EEP_START_LOC; - eep_data = (u16 *)eep; - - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); - } - - for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); - addr++) { - if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); - return false; - } - eep_data++; - } - return true; -} - -static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) -{ - u32 sum = 0, el, integer; - u16 temp, word, magic, magic2, *eepdata; - int i, addr; - bool need_swap = false; - struct ar9287_eeprom *eep = &ah->eeprom.map9287; - - if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read - (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Reading Magic # failed\n"); - return false; - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *)(&ah->eeprom); - - for (addr = 0; - addr < sizeof(struct ar9287_eeprom) / sizeof(u16); - addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "endianness mismatch.\n"); - return -EINVAL; - } - } - } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? - "True" : "False"); - - if (need_swap) - el = swab16(ah->eeprom.map9287.baseEepHeader.length); - else - el = ah->eeprom.map9287.baseEepHeader.length; - - if (el > sizeof(struct ar9287_eeprom)) - el = sizeof(struct ar9287_eeprom) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); - for (i = 0; i < el; i++) - sum ^= *eepdata++; - - if (need_swap) { - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; - - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; - - integer = swab32(eep->modalHeader.antCtrlCommon); - eep->modalHeader.antCtrlCommon = integer; - - for (i = 0; i < AR9287_MAX_CHAINS; i++) { - integer = swab32(eep->modalHeader.antCtrlChain[i]); - eep->modalHeader.antCtrlChain[i] = integer; - } - - for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) { - word = swab16(eep->modalHeader.spurChans[i].spurChan); - eep->modalHeader.spurChans[i].spurChan = word; - } - } - - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER - || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); - return -EINVAL; - } - - return 0; -} - -static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, - enum eeprom_param param) -{ - struct ar9287_eeprom *eep = &ah->eeprom.map9287; - struct modal_eep_ar9287_header *pModal = &eep->modalHeader; - struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; - u16 ver_minor; - - ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; - switch (param) { - case EEP_NFTHRESH_2: - return pModal->noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_MINOR_REV: - return ver_minor; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - case EEP_DEV_TYPE: - return pBase->deviceType; - case EEP_OL_PWRCTRL: - return pBase->openLoopPwrCntl; - case EEP_TEMPSENSE_SLOPE: - if (ver_minor >= AR9287_EEP_MINOR_VER_2) - return pBase->tempSensSlope; - else - return 0; - case EEP_TEMPSENSE_SLOPE_PAL_ON: - if (ver_minor >= AR9287_EEP_MINOR_VER_3) - return pBase->tempSensSlopePalOn; - else - return 0; - default: - return 0; - } -} - - -static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq_ar9287 *pRawDataSet, - u8 *bChans, u16 availPiers, - u16 tPdGainOverlap, int16_t *pMinCalPower, - u16 *pPdGainBoundaries, u8 *pPDADCValues, - u16 numXpdGains) -{ -#define TMP_VAL_VPD_TABLE \ - ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); - - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR9287_NUM_PD_GAINS]; - u8 maxPwrT4[AR9287_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; - static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR9287_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index( - (u8)FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)), bChans, numPiers, - &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL].pwrPdg[i], - pRawDataSet[idxL].vpdPdg[i], - AR9287_PD_GAIN_ICEPTS, vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1], - pPwrR[AR9287_PD_GAIN_ICEPTS - 1]); - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR9287_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR9287_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8)(ath9k_hw_interpolate((u16) - FREQ2FBIN(centers. synth_center, - IS_CHAN_2GHZ(chan)), - bChans[idxL], bChans[idxR], - vpdTableL[i][j], vpdTableR[i][j])); - } - } - } - *pMinCalPower = (int16_t)(minPwrT4[0] / 2); - - k = 0; - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = (u16)((maxPwrT4[i] + - minPwrT4[i+1]) / 4); - - pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER, - pPdGainBoundaries[i]); - - - if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else - minDelta = 0; - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t)(0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else - ss = (int16_t)((pPdGainBoundaries[i-1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - - vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8)(pPdGainBoundaries[i] + - tPdGainOverlap - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < sizeCurrVpdTable) ? - tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1))) - pPDADCValues[k++] = vpdTableI[i][ss++]; - - vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - if (tgtIndex > maxIndex) { - while ((ss <= tgtIndex) && - (k < (AR9287_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t) TMP_VAL_VPD_TABLE; - pPDADCValues[k++] = (u8)((tmpVal > 255) ? - 255 : tmpVal); - ss++; - } - } - } - - while (i < AR9287_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; - i++; - } - - while (k < AR9287_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k-1]; - k++; - } - -#undef TMP_VAL_VPD_TABLE -} - -static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, - u8 *pCalChans, u16 availPiers, - int8_t *pPwr) -{ - u8 pcdac, i = 0; - u16 idxL = 0, idxR = 0, numPiers; - bool match; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index( - (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), - pCalChans, numPiers, - &idxL, &idxR); - - if (match) { - pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; - *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; - } else { - pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; - *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + - pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; - } - - while ((pcdac > ah->originalGain[i]) && - (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) - i++; -} - -static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, - int32_t txPower, u16 chain) -{ - u32 tmpVal; - u32 a; - - tmpVal = REG_READ(ah, 0xa270); - tmpVal = tmpVal & 0xFCFFFFFF; - tmpVal = tmpVal | (0x3 << 24); - REG_WRITE(ah, 0xa270, tmpVal); - - tmpVal = REG_READ(ah, 0xb270); - tmpVal = tmpVal & 0xFCFFFFFF; - tmpVal = tmpVal | (0x3 << 24); - REG_WRITE(ah, 0xb270, tmpVal); - - if (chain == 0) { - tmpVal = REG_READ(ah, 0xa398); - tmpVal = tmpVal & 0xff00ffff; - a = (txPower)&0xff; - tmpVal = tmpVal | (a << 16); - REG_WRITE(ah, 0xa398, tmpVal); - } - - if (chain == 1) { - tmpVal = REG_READ(ah, 0xb398); - tmpVal = tmpVal & 0xff00ffff; - a = (txPower)&0xff; - tmpVal = tmpVal | (a << 16); - REG_WRITE(ah, 0xb398, tmpVal); - } -} - -static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ - struct cal_data_per_freq_ar9287 *pRawDataset; - struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - u8 pdadcValues[AR9287_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK]; - u16 numPiers = 0, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0}; - u32 reg32, regOffset, regChainOffset; - int16_t modalIdx, diff = 0; - struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; - xpdMask = pEepData->modalHeader.xpdGain; - if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= - AR9287_EEP_MINOR_VER_2) - pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; - else - pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - - if (IS_CHAN_2GHZ(chan)) { - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR9287_NUM_2G_CAL_PIERS; - if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { - pRawDatasetOpenLoop = - (struct cal_data_op_loop_ar9287 *) - pEepData->calPierData2G[0]; - ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; - } - } - - numXpdGain = 0; - for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR9287_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16)(AR9287_PD_GAINS_IN_MASK-i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, - xpdGainValues[2]); - - for (i = 0; i < AR9287_MAX_CHAINS; i++) { - regChainOffset = i * 0x1000; - if (pEepData->baseEepHeader.txMask & (1 << i)) { - pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *) - pEepData->calPierData2G[i]; - if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { - int8_t txPower; - ar9287_eeprom_get_tx_gain_index(ah, chan, - pRawDatasetOpenLoop, - pCalBChans, numPiers, - &txPower); - ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i); - } else { - pRawDataset = - (struct cal_data_per_freq_ar9287 *) - pEepData->calPierData2G[i]; - ath9k_hw_get_AR9287_gain_boundaries_pdadcs( - ah, chan, pRawDataset, - pCalBChans, numPiers, - pdGainOverlap_t2, - &tMinCalPower, gainBoundaries, - pdadcValues, numXpdGain); - } - - if (i == 0) { - if (!ath9k_hw_AR9287_get_eeprom( - ah, EEP_OL_PWRCTRL)) { - REG_WRITE(ah, AR_PHY_TPCRG5 + - regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | - SM(gainBoundaries[0], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); - } - } - - if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB != - pEepData->baseEepHeader.pwrTableOffset) { - diff = (u16) - (pEepData->baseEepHeader.pwrTableOffset - - (int32_t)AR9287_PWR_TABLE_OFFSET_DB); - diff *= 2; - - for (j = 0; - j < ((u16)AR9287_NUM_PDADC_VALUES-diff); - j++) - pdadcValues[j] = pdadcValues[j+diff]; - - for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff); - j < AR9287_NUM_PDADC_VALUES; j++) - pdadcValues[j] = - pdadcValues[ - AR9287_NUM_PDADC_VALUES-diff]; - } - - if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { - regOffset = AR_PHY_BASE + (672 << 2) + - regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = ((pdadcValues[4*j + 0] - & 0xFF) << 0) | - ((pdadcValues[4*j + 1] - & 0xFF) << 8) | - ((pdadcValues[4*j + 2] - & 0xFF) << 16) | - ((pdadcValues[4*j + 3] - & 0xFF) << 24) ; - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC: Chain %d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, - pdadcValues[4 * j + 1], - 4 * j + 2, - pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - } - - *pTxPowerIndexOffset = 0; -} - -static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, - struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, - u16 AntennaReduction, u16 twiceMaxRegulatoryPower, - u16 powerLimit) -{ -#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 -#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 - - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - int i; - int16_t twiceLargestAntenna; - struct cal_ctl_data_ar9287 *rep; - struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, - targetPowerCck = {0, {0, 0, 0, 0} }; - struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} }, - targetPowerCckExt = {0, {0, 0, 0, 0} }; - struct cal_target_power_ht targetPowerHt20, - targetPowerHt40 = {0, {0, 0, 0, 0} }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11g[] = - {CTL_11B, CTL_11G, CTL_2GHT20, - CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40}; - u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u16 twiceMinEdgePower; - struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; - tx_chainmask = ah->txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], - pEepData->modalHeader.antennaGainCh[1]); - - twiceLargestAntenna = (int16_t)min((AntennaReduction) - - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); - - scaledPower = min(powerLimit, maxRegAllowedPower); - - switch (ar5416_get_ntxchains(tx_chainmask)) { - case 1: - break; - case 2: - scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; - break; - case 3: - scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; - break; - } - scaledPower = max((u16)0, scaledPower); - - if (IS_CHAN_2GHZ(chan)) { - numCtlModes = - ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR9287_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT40, - AR9287_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR9287_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || - (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & - CTL_MODE_M) | SD_NO_CTL))) { - - rep = &(pEepData->ctlData[i]); - twiceMinEdgePower = ath9k_hw_get_max_edge_power( - freq, - rep->ctlEdges[ar5416_get_ntxchains( - tx_chainmask) - 1], - IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) - twiceMaxEdgePower = min( - twiceMaxEdgePower, - twiceMinEdgePower); - else { - twiceMaxEdgePower = twiceMinEdgePower; - break; - } - } - } - - minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; - i < ARRAY_SIZE(targetPowerCck.tPow2x); - i++) { - targetPowerCck.tPow2x[i] = (u8)min( - (u16)targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11A: - case CTL_11G: - for (i = 0; - i < ARRAY_SIZE(targetPowerOfdm.tPow2x); - i++) { - targetPowerOfdm.tPow2x[i] = (u8)min( - (u16)targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_5GHT20: - case CTL_2GHT20: - for (i = 0; - i < ARRAY_SIZE(targetPowerHt20.tPow2x); - i++) { - targetPowerHt20.tPow2x[i] = (u8)min( - (u16)targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = (u8)min( - (u16)targetPowerCckExt.tPow2x[0], - minCtlPower); - break; - case CTL_11A_EXT: - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = (u8)min( - (u16)targetPowerOfdmExt.tPow2x[0], - minCtlPower); - break; - case CTL_5GHT40: - case CTL_2GHT40: - for (i = 0; - i < ARRAY_SIZE(targetPowerHt40.tPow2x); - i++) { - targetPowerHt40.tPow2x[i] = (u8)min( - (u16)targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = - ratesArray[rate9mb] = - ratesArray[rate12mb] = - ratesArray[rate18mb] = - ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = - targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = - targetPowerCck.tPow2x[2]; - ratesArray[rate11s] = ratesArray[rate11l] = - targetPowerCck.tPow2x[3]; - } - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) - ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; - - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - if (IS_CHAN_2GHZ(chan)) - ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; - } - -#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN -#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN -} - -static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ -#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 -#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 - - struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; - struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i; - - memset(ratesArray, 0, sizeof(ratesArray)); - - if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= - AR9287_EEP_MINOR_VER_2) - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - - ath9k_hw_set_AR9287_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit); - - ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset); - - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR9287_MAX_RATE_POWER) - ratesArray[i] = AR9287_MAX_RATE_POWER; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0)); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0)); - - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); - - if (IS_CHAN_HT40(chan)) { - if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0], 0)); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4], 0)); - } else { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0)); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0)); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); - } - - if (IS_CHAN_2GHZ(chan)) - i = rate1l; - else - i = rate6mb; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = - ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; - else - ah->regulatory.max_power_level = ratesArray[i]; - - switch (ar5416_get_ntxchains(ah->txchainmask)) { - case 1: - break; - case 2: - ah->regulatory.max_power_level += - INCREASE_MAXPOW_BY_TWO_CHAIN; - break; - case 3: - ah->regulatory.max_power_level += - INCREASE_MAXPOW_BY_THREE_CHAIN; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Invalid chainmask configuration\n"); - break; - } -} - -static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, - struct ath9k_channel *chan) -{ -} - -static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ar9287_eeprom *eep = &ah->eeprom.map9287; - struct modal_eep_ar9287_header *pModal = &eep->modalHeader; - u16 antWrites[AR9287_ANT_16S]; - u32 regChainOffset; - u8 txRxAttenLocal; - int i, j, offset_num; - - pModal = &eep->modalHeader; - - antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); - antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); - antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); - antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); - antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); - antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); - antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); - antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); - - offset_num = 8; - - for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); - antWrites[j++] = 0; - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); - antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); - } - - REG_WRITE(ah, AR_PHY_SWITCH_COM, - ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); - - for (i = 0; i < AR9287_MAX_CHAINS; i++) { - regChainOffset = i * 0x1000; - - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[i]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) - & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - txRxAttenLocal = pModal->txRxAttenCh[i]; - - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, - pModal->bswMargin[i]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, - pModal->bswAtten[i]); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, - txRxAttenLocal); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, - pModal->rxTxMarginCh[i]); - } - - - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); - else - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, pModal->switchSettling); - - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); - - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) - | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) - | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) - | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, - AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); - - REG_RMW_FIELD(ah, AR_PHY_CCA, - AR9280_PHY_CCA_THRESH62, pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, - AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); - - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1, - AR9287_AN_RF2G3_DB1_S, pModal->db1); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2, - AR9287_AN_RF2G3_DB2_S, pModal->db2); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, - AR9287_AN_RF2G3_OB_CCK, - AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, - AR9287_AN_RF2G3_OB_PSK, - AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, - AR9287_AN_RF2G3_OB_QAM, - AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, - AR9287_AN_RF2G3_OB_PAL_OFF, - AR9287_AN_RF2G3_OB_PAL_OFF_S, - pModal->ob_pal_off); - - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, - AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S, - pModal->db1); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2, - AR9287_AN_RF2G3_DB2_S, pModal->db2); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, - AR9287_AN_RF2G3_OB_CCK, - AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, - AR9287_AN_RF2G3_OB_PSK, - AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, - AR9287_AN_RF2G3_OB_QAM, - AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, - AR9287_AN_RF2G3_OB_PAL_OFF, - AR9287_AN_RF2G3_OB_PAL_OFF_S, - pModal->ob_pal_off); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, - AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, - AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn); - - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2, - AR9287_AN_TOP2_XPABIAS_LVL, - AR9287_AN_TOP2_XPABIAS_LVL_S, - pModal->xpaBiasLvl); -} - -static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, - enum ieee80211_band freq_band) -{ - return 1; -} - -static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ar9287_eeprom *eep = &ah->eeprom.map9287; - struct modal_eep_ar9287_header *pModal = &eep->modalHeader; - - return pModal->antCtrlCommon & 0xFFFF; -} - -static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, - u16 i, bool is2GHz) -{ -#define EEP_MAP9287_SPURCHAN \ - (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) - u16 spur_val = AR_NO_SPUR; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); - - switch (ah->config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = EEP_MAP9287_SPURCHAN; - break; - } - - return spur_val; - -#undef EEP_MAP9287_SPURCHAN -} - -static struct eeprom_ops eep_AR9287_ops = { - .check_eeprom = ath9k_hw_AR9287_check_eeprom, - .get_eeprom = ath9k_hw_AR9287_get_eeprom, - .fill_eeprom = ath9k_hw_AR9287_fill_eeprom, - .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver, - .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev, - .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config, - .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg, - .set_board_values = ath9k_hw_AR9287_set_board_values, - .set_addac = ath9k_hw_AR9287_set_addac, - .set_txpower = ath9k_hw_AR9287_set_txpower, - .get_spur_channel = ath9k_hw_AR9287_get_spur_channel -}; - int ath9k_hw_eeprom_init(struct ath_hw *ah) { int status; diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index a644709..7d825b6 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -656,10 +656,39 @@ struct eeprom_ops { u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); }; +void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, + u32 shift, u32 val); +int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, + int16_t targetLeft, + int16_t targetRight); +bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, + u16 *indexL, u16 *indexR); +bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data); +void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, + u8 *pVpdList, u16 numIntercepts, + u8 *pRetVpdList); +void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_leg *powInfo, + u16 numChannels, + struct cal_target_power_leg *pNewPower, + u16 numRates, bool isExtTarget); +void ath9k_hw_get_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_ht *powInfo, + u16 numChannels, + struct cal_target_power_ht *pNewPower, + u16 numRates, bool isHt40Target); +u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, + bool is2GHz, int num_band_edges); +int ath9k_hw_eeprom_init(struct ath_hw *ah); + #define ar5416_get_ntxchains(_txchainmask) \ (((_txchainmask >> 2) & 1) + \ ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) -int ath9k_hw_eeprom_init(struct ath_hw *ah); +extern const struct eeprom_ops eep_def_ops; +extern const struct eeprom_ops eep_4k_ops; +extern const struct eeprom_ops eep_AR9287_ops; #endif /* EEPROM_H */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c new file mode 100644 index 0000000..111f4d7 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -0,0 +1,1181 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) +{ + return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); +} + +static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) +{ + return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); +} + +static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) +{ +#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + u16 *eep_data = (u16 *)&ah->eeprom.map4k; + int addr, eep_start_loc = 0; + + eep_start_loc = 64; + + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); + return false; + } + eep_data++; + } + + return true; +#undef SIZE_EEPROM_4K +} + +static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) +{ +#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + struct ar5416_eeprom_4k *eep = + (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr; + + + if (!ath9k_hw_use_flash(ah)) { + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, + &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Reading Magic # failed\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + need_swap = true; + eepdata = (u16 *) (&ah->eeprom); + + for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ah->eeprom.map4k.baseEepHeader.length); + else + el = ah->eeprom.map4k.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_4k)) + el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ah->eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing\n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + integer = swab32(eep->modalHeader.antCtrlCommon); + eep->modalHeader.antCtrlCommon = integer; + + for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { + integer = swab32(eep->modalHeader.antCtrlChain[i]); + eep->modalHeader.antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(eep->modalHeader.spurChans[i].spurChan); + eep->modalHeader.spurChans[i].spurChan = word; + } + } + + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || + ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); + return -EINVAL; + } + + return 0; +#undef EEPROM_4K_SIZE +} + +static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) +{ + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + struct base_eep_header_4k *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_2: + return pModal->noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_2: + return pModal->ob_01; + case EEP_DB_2: + return pModal->db1_01; + case EEP_MINOR_REV: + return pBase->version & AR5416_EEP_VER_MINOR_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_FRAC_N_5G: + return 0; + default: + return 0; + } +} + +static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq_4k *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ +#define TMP_VAL_VPD_TABLE \ + ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; +#define PD_GAIN_BOUNDARY_DEFAULT 58; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), bChans, numPiers, + &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) + pPDADCValues[k++] = vpdTableI[i][ss++]; + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex >= maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t) TMP_VAL_VPD_TABLE; + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +#undef TMP_VAL_VPD_TABLE +} + +static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + struct cal_data_per_freq_4k *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 }; + u32 reg32, regOffset, regChainOffset; + + xpdMask = pEepData->modalHeader.xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader.pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; + + numXpdGain = 0; + + for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); + + for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + pRawDataset = pEepData->calPierData2G[i]; + + ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, + pRawDataset, pCalBChans, + numPiers, pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { + REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) + | SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; +} + +static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data_4k *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ah->txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + scaledPower = max((u16)0, scaledPower); + + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && + pEepData->ctlIndex[i]; i++) { + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | + SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = + ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains + (tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), + AR5416_EEP4K_NUM_BAND_EDGES); + + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = + min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); + i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); + i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); + i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); + i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; + + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } +} + +static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &pEepData->modalHeader; + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + ath9k_hw_set_4k_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); + + ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->regulatory.max_power_level = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->regulatory.max_power_level = ratesArray[i]; + +} + +static void ath9k_hw_4k_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + u8 biaslevel; + + if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) + return; + + if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &eep->modalHeader; + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + INI_RA(&ah->iniAddac, 7, 1) = + (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; + } +} + +static void ath9k_hw_4k_set_gain(struct ath_hw *ah, + struct modal_eep_4k_header *pModal, + struct ar5416_eeprom_4k *eep, + u8 txRxAttenLocal, int regChainOffset) +{ + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[0]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[0]; + + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); + + /* Set the block 1 value to block 0 value */ + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, + pModal->xatten2Db[0]); + } + + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); +} + +/* + * Read EEPROM header info and program the device for correct operation + * given the channel value. + */ +static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + u8 txRxAttenLocal; + u8 ob[5], db1[5], db2[5]; + u8 ant_div_control1, ant_div_control2; + u32 regVal; + + pModal = &eep->modalHeader; + txRxAttenLocal = 23; + + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); + + /* Single chain for 4K EEPROM*/ + ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); + + /* Initialize Ant Diversity settings from EEPROM */ + if (pModal->version >= 3) { + ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); + ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); + regVal = REG_READ(ah, 0x99ac); + regVal &= (~(0x7f000000)); + regVal |= ((ant_div_control1 & 0x1) << 24); + regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); + regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); + regVal |= ((ant_div_control2 & 0x3) << 25); + regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); + REG_WRITE(ah, 0x99ac, regVal); + regVal = REG_READ(ah, 0x99ac); + regVal = REG_READ(ah, 0xa208); + regVal &= (~(0x1 << 13)); + regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); + REG_WRITE(ah, 0xa208, regVal); + regVal = REG_READ(ah, 0xa208); + } + + if (pModal->version >= 2) { + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = (pModal->ob_01 >> 4) & 0xf; + ob[2] = (pModal->ob_234 & 0xf); + ob[3] = ((pModal->ob_234 >> 4) & 0xf); + ob[4] = ((pModal->ob_234 >> 8) & 0xf); + + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = ((pModal->db1_01 >> 4) & 0xf); + db1[2] = (pModal->db1_234 & 0xf); + db1[3] = ((pModal->db1_234 >> 4) & 0xf); + db1[4] = ((pModal->db1_234 >> 8) & 0xf); + + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = ((pModal->db2_01 >> 4) & 0xf); + db2[2] = (pModal->db2_234 & 0xf); + db2[3] = ((pModal->db2_234 >> 4) & 0xf); + db2[4] = ((pModal->db2_234 >> 8) & 0xf); + + } else if (pModal->version == 1) { + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = db1[2] = db1[3] = + db1[4] = ((pModal->db1_01 >> 4) & 0xf); + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = db2[2] = db2[3] = + db2[4] = ((pModal->db2_01 >> 4) & 0xf); + } else { + int i; + for (i = 0; i < 5; i++) { + ob[i] = pModal->ob_01; + db1[i] = pModal->db1_01; + db2[i] = pModal->db1_01; + } + } + + if (AR_SREV_9271(ah)) { + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_cck, + AR9271_AN_RF2G3_OB_cck_S, + ob[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_psk, + AR9271_AN_RF2G3_OB_psk_S, + ob[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_qam, + AR9271_AN_RF2G3_OB_qam_S, + ob[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_DB_1, + AR9271_AN_RF2G3_DB_1_S, + db1[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9271_AN_RF2G4_DB_2, + AR9271_AN_RF2G4_DB_2_S, + db2[0]); + } else { + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_0, + AR9285_AN_RF2G3_OB_0_S, + ob[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_1, + AR9285_AN_RF2G3_OB_1_S, + ob[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_2, + AR9285_AN_RF2G3_OB_2_S, + ob[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_3, + AR9285_AN_RF2G3_OB_3_S, + ob[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_4, + AR9285_AN_RF2G3_OB_4_S, + ob[4]); + + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_0, + AR9285_AN_RF2G3_DB1_0_S, + db1[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_1, + AR9285_AN_RF2G3_DB1_1_S, + db1[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_2, + AR9285_AN_RF2G3_DB1_2_S, + db1[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_3, + AR9285_AN_RF2G4_DB1_3_S, + db1[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_4, + AR9285_AN_RF2G4_DB1_4_S, db1[4]); + + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_0, + AR9285_AN_RF2G4_DB2_0_S, + db2[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_1, + AR9285_AN_RF2G4_DB2_1_S, + db2[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_2, + AR9285_AN_RF2G4_DB2_2_S, + db2[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_3, + AR9285_AN_RF2G4_DB2_3_S, + db2[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_4, + AR9285_AN_RF2G4_DB2_4_S, + db2[4]); + } + + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } +} + +static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + + return pModal->antCtrlCommon & 0xFFFF; +} + +static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + +static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) +{ +#define EEP_MAP4K_SPURCHAN \ + (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) + + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); + + switch (ah->config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = EEP_MAP4K_SPURCHAN; + break; + } + + return spur_val; + +#undef EEP_MAP4K_SPURCHAN +} + +const struct eeprom_ops eep_4k_ops = { + .check_eeprom = ath9k_hw_4k_check_eeprom, + .get_eeprom = ath9k_hw_4k_get_eeprom, + .fill_eeprom = ath9k_hw_4k_fill_eeprom, + .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_4k_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_4k_set_board_values, + .set_addac = ath9k_hw_4k_set_addac, + .set_txpower = ath9k_hw_4k_set_txpower, + .get_spur_channel = ath9k_hw_4k_get_spur_channel +}; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c new file mode 100644 index 0000000..aeb7f48 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -0,0 +1,1183 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) +{ + return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; +} + +static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) +{ + return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; +} + +static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) +{ + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + u16 *eep_data; + int addr, eep_start_loc = AR9287_EEP_START_LOC; + eep_data = (u16 *)eep; + + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); + addr++) { + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); + return false; + } + eep_data++; + } + return true; +} + +static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) +{ + u32 sum = 0, el, integer; + u16 temp, word, magic, magic2, *eepdata; + int i, addr; + bool need_swap = false; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + + if (!ath9k_hw_use_flash(ah)) { + if (!ath9k_hw_nvram_read + (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Reading Magic # failed\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + need_swap = true; + eepdata = (u16 *)(&ah->eeprom); + + for (addr = 0; + addr < sizeof(struct ar9287_eeprom) / sizeof(u16); + addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } + } + } + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? + "True" : "False"); + + if (need_swap) + el = swab16(ah->eeprom.map9287.baseEepHeader.length); + else + el = ah->eeprom.map9287.baseEepHeader.length; + + if (el > sizeof(struct ar9287_eeprom)) + el = sizeof(struct ar9287_eeprom) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ah->eeprom); + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + integer = swab32(eep->modalHeader.antCtrlCommon); + eep->modalHeader.antCtrlCommon = integer; + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + integer = swab32(eep->modalHeader.antCtrlChain[i]); + eep->modalHeader.antCtrlChain[i] = integer; + } + + for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) { + word = swab16(eep->modalHeader.spurChans[i].spurChan); + eep->modalHeader.spurChans[i].spurChan = word; + } + } + + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER + || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); + return -EINVAL; + } + + return 0; +} + +static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) +{ + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; + u16 ver_minor; + + ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; + switch (param) { + case EEP_NFTHRESH_2: + return pModal->noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_MINOR_REV: + return ver_minor; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_DEV_TYPE: + return pBase->deviceType; + case EEP_OL_PWRCTRL: + return pBase->openLoopPwrCntl; + case EEP_TEMPSENSE_SLOPE: + if (ver_minor >= AR9287_EEP_MINOR_VER_2) + return pBase->tempSensSlope; + else + return 0; + case EEP_TEMPSENSE_SLOPE_PAL_ON: + if (ver_minor >= AR9287_EEP_MINOR_VER_3) + return pBase->tempSensSlopePalOn; + else + return 0; + default: + return 0; + } +} + + +static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq_ar9287 *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ +#define TMP_VAL_VPD_TABLE \ + ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); + + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR9287_NUM_PD_GAINS]; + u8 maxPwrT4[AR9287_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; + static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR9287_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), bChans, numPiers, + &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR9287_PD_GAIN_ICEPTS, vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1], + pPwrR[AR9287_PD_GAIN_ICEPTS - 1]); + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR9287_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR9287_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. synth_center, + IS_CHAN_2GHZ(chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = (u16)((maxPwrT4[i] + + minPwrT4[i+1]) / 4); + + pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER, + pPdGainBoundaries[i]); + + + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else + minDelta = 0; + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else + ss = (int16_t)((pPdGainBoundaries[i-1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + + tPdGainOverlap - (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1))) + pPDADCValues[k++] = vpdTableI[i][ss++]; + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR9287_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t) TMP_VAL_VPD_TABLE; + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR9287_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; + i++; + } + + while (k < AR9287_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k-1]; + k++; + } + +#undef TMP_VAL_VPD_TABLE +} + +static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, + u8 *pCalChans, u16 availPiers, + int8_t *pPwr) +{ + u8 pcdac, i = 0; + u16 idxL = 0, idxR = 0, numPiers; + bool match; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + pCalChans, numPiers, + &idxL, &idxR); + + if (match) { + pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; + *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; + } else { + pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; + *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + + pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; + } + + while ((pcdac > ah->originalGain[i]) && + (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) + i++; +} + +static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, + int32_t txPower, u16 chain) +{ + u32 tmpVal; + u32 a; + + tmpVal = REG_READ(ah, 0xa270); + tmpVal = tmpVal & 0xFCFFFFFF; + tmpVal = tmpVal | (0x3 << 24); + REG_WRITE(ah, 0xa270, tmpVal); + + tmpVal = REG_READ(ah, 0xb270); + tmpVal = tmpVal & 0xFCFFFFFF; + tmpVal = tmpVal | (0x3 << 24); + REG_WRITE(ah, 0xb270, tmpVal); + + if (chain == 0) { + tmpVal = REG_READ(ah, 0xa398); + tmpVal = tmpVal & 0xff00ffff; + a = (txPower)&0xff; + tmpVal = tmpVal | (a << 16); + REG_WRITE(ah, 0xa398, tmpVal); + } + + if (chain == 1) { + tmpVal = REG_READ(ah, 0xb398); + tmpVal = tmpVal & 0xff00ffff; + a = (txPower)&0xff; + tmpVal = tmpVal | (a << 16); + REG_WRITE(ah, 0xb398, tmpVal); + } +} + +static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ + struct cal_data_per_freq_ar9287 *pRawDataset; + struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + u8 pdadcValues[AR9287_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK]; + u16 numPiers = 0, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0}; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx, diff = 0; + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader.xpdGain; + if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= + AR9287_EEP_MINOR_VER_2) + pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; + else + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR9287_NUM_2G_CAL_PIERS; + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + pRawDatasetOpenLoop = + (struct cal_data_op_loop_ar9287 *) + pEepData->calPierData2G[0]; + ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; + } + } + + numXpdGain = 0; + for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR9287_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR9287_PD_GAINS_IN_MASK-i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + regChainOffset = i * 0x1000; + if (pEepData->baseEepHeader.txMask & (1 << i)) { + pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *) + pEepData->calPierData2G[i]; + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + int8_t txPower; + ar9287_eeprom_get_tx_gain_index(ah, chan, + pRawDatasetOpenLoop, + pCalBChans, numPiers, + &txPower); + ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i); + } else { + pRawDataset = + (struct cal_data_per_freq_ar9287 *) + pEepData->calPierData2G[i]; + ath9k_hw_get_AR9287_gain_boundaries_pdadcs( + ah, chan, pRawDataset, + pCalBChans, numPiers, + pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + } + + if (i == 0) { + if (!ath9k_hw_AR9287_get_eeprom( + ah, EEP_OL_PWRCTRL)) { + REG_WRITE(ah, AR_PHY_TPCRG5 + + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + } + + if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB != + pEepData->baseEepHeader.pwrTableOffset) { + diff = (u16) + (pEepData->baseEepHeader.pwrTableOffset + - (int32_t)AR9287_PWR_TABLE_OFFSET_DB); + diff *= 2; + + for (j = 0; + j < ((u16)AR9287_NUM_PDADC_VALUES-diff); + j++) + pdadcValues[j] = pdadcValues[j+diff]; + + for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff); + j < AR9287_NUM_PDADC_VALUES; j++) + pdadcValues[j] = + pdadcValues[ + AR9287_NUM_PDADC_VALUES-diff]; + } + + if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + regOffset = AR_PHY_BASE + (672 << 2) + + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4*j + 0] + & 0xFF) << 0) | + ((pdadcValues[4*j + 1] + & 0xFF) << 8) | + ((pdadcValues[4*j + 2] + & 0xFF) << 16) | + ((pdadcValues[4*j + 3] + & 0xFF) << 24) ; + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, + pdadcValues[4 * j + 1], + 4 * j + 2, + pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + } + + *pTxPowerIndexOffset = 0; +} + +static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, + struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, + u16 AntennaReduction, u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ +#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 +#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 + + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data_ar9287 *rep; + struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, + targetPowerCck = {0, {0, 0, 0, 0} }; + struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} }, + targetPowerCckExt = {0, {0, 0, 0, 0} }; + struct cal_target_power_ht targetPowerHt20, + targetPowerHt40 = {0, {0, 0, 0, 0} }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11g[] = + {CTL_11B, CTL_11G, CTL_2GHT20, + CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40}; + u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; + tx_chainmask = ah->txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], + pEepData->modalHeader.antennaGainCh[1]); + + twiceLargestAntenna = (int16_t)min((AntennaReduction) - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + + scaledPower = min(powerLimit, maxRegAllowedPower); + + switch (ar5416_get_ntxchains(tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + break; + case 3: + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + break; + } + scaledPower = max((u16)0, scaledPower); + + if (IS_CHAN_2GHZ(chan)) { + numCtlModes = + ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR9287_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & + CTL_MODE_M) | SD_NO_CTL))) { + + rep = &(pEepData->ctlData[i]); + twiceMinEdgePower = ath9k_hw_get_max_edge_power( + freq, + rep->ctlEdges[ar5416_get_ntxchains( + tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); + + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) + twiceMaxEdgePower = min( + twiceMaxEdgePower, + twiceMinEdgePower); + else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; + i < ARRAY_SIZE(targetPowerCck.tPow2x); + i++) { + targetPowerCck.tPow2x[i] = (u8)min( + (u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; + i < ARRAY_SIZE(targetPowerOfdm.tPow2x); + i++) { + targetPowerOfdm.tPow2x[i] = (u8)min( + (u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; + i < ARRAY_SIZE(targetPowerHt20.tPow2x); + i++) { + targetPowerHt20.tPow2x[i] = (u8)min( + (u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = (u8)min( + (u16)targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = (u8)min( + (u16)targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; + i < ARRAY_SIZE(targetPowerHt40.tPow2x); + i++) { + targetPowerHt40.tPow2x[i] = (u8)min( + (u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = + ratesArray[rate9mb] = + ratesArray[rate12mb] = + ratesArray[rate18mb] = + ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = + targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = + targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = + targetPowerCck.tPow2x[3]; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) + ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; + + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } + +#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN +#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN +} + +static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ +#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 +#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 + + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= + AR9287_EEP_MINOR_VER_2) + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + + ath9k_hw_set_AR9287_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); + + ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset); + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR9287_MAX_RATE_POWER) + ratesArray[i] = AR9287_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0], 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4], 0)); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + if (IS_CHAN_2GHZ(chan)) + i = rate1l; + else + i = rate6mb; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->regulatory.max_power_level = + ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; + else + ah->regulatory.max_power_level = ratesArray[i]; + + switch (ar5416_get_ntxchains(ah->txchainmask)) { + case 1: + break; + case 2: + ah->regulatory.max_power_level += + INCREASE_MAXPOW_BY_TWO_CHAIN; + break; + case 3: + ah->regulatory.max_power_level += + INCREASE_MAXPOW_BY_THREE_CHAIN; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); + break; + } +} + +static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) +{ +} + +static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + u16 antWrites[AR9287_ANT_16S]; + u32 regChainOffset; + u8 txRxAttenLocal; + int i, j, offset_num; + + pModal = &eep->modalHeader; + + antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); + antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); + antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); + antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); + antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); + antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); + antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); + antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); + + offset_num = 8; + + for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); + antWrites[j++] = 0; + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); + antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); + } + + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + regChainOffset = i * 0x1000; + + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[i]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) + & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + txRxAttenLocal = pModal->txRxAttenCh[i]; + + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, + pModal->bswAtten[i]); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, + txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, + pModal->rxTxMarginCh[i]); + } + + + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); + else + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, pModal->switchSettling); + + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, + AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); + + REG_RMW_FIELD(ah, AR_PHY_CCA, + AR9280_PHY_CCA_THRESH62, pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, + AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1, + AR9287_AN_RF2G3_DB1_S, pModal->db1); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2, + AR9287_AN_RF2G3_DB2_S, pModal->db2); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_CCK, + AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_PSK, + AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_QAM, + AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_PAL_OFF, + AR9287_AN_RF2G3_OB_PAL_OFF_S, + pModal->ob_pal_off); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S, + pModal->db1); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2, + AR9287_AN_RF2G3_DB2_S, pModal->db2); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_CCK, + AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_PSK, + AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_QAM, + AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_PAL_OFF, + AR9287_AN_RF2G3_OB_PAL_OFF_S, + pModal->ob_pal_off); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2, + AR9287_AN_TOP2_XPABIAS_LVL, + AR9287_AN_TOP2_XPABIAS_LVL_S, + pModal->xpaBiasLvl); +} + +static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + +static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + + return pModal->antCtrlCommon & 0xFFFF; +} + +static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, + u16 i, bool is2GHz) +{ +#define EEP_MAP9287_SPURCHAN \ + (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); + + switch (ah->config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = EEP_MAP9287_SPURCHAN; + break; + } + + return spur_val; + +#undef EEP_MAP9287_SPURCHAN +} + +const struct eeprom_ops eep_AR9287_ops = { + .check_eeprom = ath9k_hw_AR9287_check_eeprom, + .get_eeprom = ath9k_hw_AR9287_get_eeprom, + .fill_eeprom = ath9k_hw_AR9287_fill_eeprom, + .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_AR9287_set_board_values, + .set_addac = ath9k_hw_AR9287_set_addac, + .set_txpower = ath9k_hw_AR9287_set_txpower, + .get_spur_channel = ath9k_hw_AR9287_get_spur_channel +}; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c new file mode 100644 index 0000000..5211ad9 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -0,0 +1,1385 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static void ath9k_get_txgain_index(struct ath_hw *ah, + struct ath9k_channel *chan, + struct calDataPerFreqOpLoop *rawDatasetOpLoop, + u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) +{ + u8 pcdac, i = 0; + u16 idxL = 0, idxR = 0, numPiers; + bool match; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) + if (calChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + calChans, numPiers, &idxL, &idxR); + if (match) { + pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; + *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; + } else { + pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; + *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + + rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; + } + + while (pcdac > ah->originalGain[i] && + i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) + i++; + + *pcdacIdx = i; + return; +} + +static void ath9k_olc_get_pdadcs(struct ath_hw *ah, + u32 initTxGain, + int txPower, + u8 *pPDADCValues) +{ + u32 i; + u32 offset; + + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, + AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, + AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); + + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, + AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); + + offset = txPower; + for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) + if (i < offset) + pPDADCValues[i] = 0x0; + else + pPDADCValues[i] = 0xFF; +} + +static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah) +{ + return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF); +} + +static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) +{ + return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); +} + +static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) +{ +#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) + u16 *eep_data = (u16 *)&ah->eeprom.def; + int addr, ar5416_eep_start_loc = 0x100; + + for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, + eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Unable to read eeprom region\n"); + return false; + } + eep_data++; + } + return true; +#undef SIZE_EEPROM_DEF +} + +static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) +{ + struct ar5416_eeprom_def *eep = + (struct ar5416_eeprom_def *) &ah->eeprom.def; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr, size; + + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); + return false; + } + + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + size = sizeof(struct ar5416_eeprom_def); + need_swap = true; + eepdata = (u16 *) (&ah->eeprom); + + for (addr = 0; addr < size / sizeof(u16); addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "Endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ah->eeprom.def.baseEepHeader.length); + else + el = ah->eeprom.def.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_def)) + el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ah->eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer, j; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing.\n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { + struct modal_eep_header *pModal = + &eep->modalHeader[j]; + integer = swab32(pModal->antCtrlCommon); + pModal->antCtrlCommon = integer; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = swab32(pModal->antCtrlChain[i]); + pModal->antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(pModal->spurChans[i].spurChan); + pModal->spurChans[i].spurChan = word; + } + } + } + + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || + ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); + return -EINVAL; + } + + return 0; +} + +static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) +{ + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct modal_eep_header *pModal = eep->modalHeader; + struct base_eep_header *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_5: + return pModal[0].noiseFloorThreshCh[0]; + case EEP_NFTHRESH_2: + return pModal[1].noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_5: + return pModal[0].ob; + case EEP_DB_5: + return pModal[0].db; + case EEP_OB_2: + return pModal[1].ob; + case EEP_DB_2: + return pModal[1].db; + case EEP_MINOR_REV: + return AR5416_VER_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_RXGAIN_TYPE: + return pBase->rxGainType; + case EEP_TXGAIN_TYPE: + return pBase->txGainType; + case EEP_OL_PWRCTRL: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + return pBase->openLoopPwrCntl ? true : false; + else + return false; + case EEP_RC_CHAIN_MASK: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + return pBase->rcChainMask; + else + return 0; + case EEP_DAC_HPWR_5G: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) + return pBase->dacHiPwrMode_5G; + else + return 0; + case EEP_FRAC_N_5G: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) + return pBase->frac_n_5g; + else + return 0; + default: + return 0; + } +} + +static void ath9k_hw_def_set_gain(struct ath_hw *ah, + struct modal_eep_header *pModal, + struct ar5416_eeprom_def *eep, + u8 txRxAttenLocal, int regChainOffset, int i) +{ + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[i]; + + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, + pModal->bswAtten[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, + pModal->xatten2Db[i]); + } else { + REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) + | SM(pModal-> bswMargin[i], + AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) + | SM(pModal->bswAtten[i], + AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + } + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); + } else { + REG_WRITE(ah, + AR_PHY_RXGAIN + regChainOffset, + (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & + ~AR_PHY_RXGAIN_TXRX_ATTEN) + | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | + SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); + } +} + +static void ath9k_hw_def_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_header *pModal; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + int i, regChainOffset; + u8 txRxAttenLocal; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; + + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_9280(ah)) { + if (i >= 2) + break; + } + + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + else + regChainOffset = i * 0x1000; + + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[i]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) + ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, + regChainOffset, i); + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + if (IS_CHAN_2GHZ(chan)) { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_OB, + AR_AN_RF2G1_CH0_OB_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_DB, + AR_AN_RF2G1_CH0_DB_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_OB, + AR_AN_RF2G1_CH1_OB_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_DB, + AR_AN_RF2G1_CH1_DB_S, + pModal->db_ch1); + } else { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_OB5, + AR_AN_RF5G1_CH0_OB5_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_DB5, + AR_AN_RF5G1_CH0_DB5_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_OB5, + AR_AN_RF5G1_CH1_OB5_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_DB5, + AR_AN_RF5G1_CH1_DB5_S, + pModal->db_ch1); + } + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_XPABIAS_LVL, + AR_AN_TOP2_XPABIAS_LVL_S, + pModal->xpaBiasLvl); + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_LOCALBIAS, + AR_AN_TOP2_LOCALBIAS_S, + pModal->local_bias); + REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, + pModal->force_xpaon); + } + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + if (!AR_SREV_9280_10_OR_LATER(ah)) + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_PGA, + pModal->pgaDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, + AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, + AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + } else { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, + AR_PHY_EXT_CCA_THRESH62, + pModal->thresh62); + } + + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } + + if (AR_SREV_9280_20_OR_LATER(ah) && + AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, + AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, + pModal->miscBits); + + + if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { + if (IS_CHAN_2GHZ(chan)) + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, + eep->baseEepHeader.dacLpMode); + else if (eep->baseEepHeader.dacHiPwrMode_5G) + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); + else + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, + eep->baseEepHeader.dacLpMode); + + REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, + pModal->miscBits >> 2); + + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, + AR_PHY_TX_DESIRED_SCALE_CCK, + eep->baseEepHeader.desiredScaleCCK); + } +} + +static void ath9k_hw_def_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) +{ +#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) + struct modal_eep_header *pModal; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + u8 biaslevel; + + if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) + return; + + if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + } else { + u16 resetFreqBin, freqBin, freqCount = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + resetFreqBin = FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)); + freqBin = XPA_LVL_FREQ(0) & 0xff; + biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); + + freqCount++; + + while (freqCount < 3) { + if (XPA_LVL_FREQ(freqCount) == 0x0) + break; + + freqBin = XPA_LVL_FREQ(freqCount) & 0xff; + if (resetFreqBin >= freqBin) + biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); + else + break; + freqCount++; + } + } + + if (IS_CHAN_2GHZ(chan)) { + INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac, + 7, 1) & (~0x18)) | biaslevel << 3; + } else { + INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac, + 6, 1) & (~0xc0)) | biaslevel << 6; + } +#undef XPA_LVL_FREQ +} + +static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), + bChans, numPiers, &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_PD_GAIN_ICEPTS, + vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + pPDADCValues[k++] = vpdTableI[i][ss++]; + } + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + + (ss - maxIndex + 1) * vpdStep)); + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +} + +static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ +#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) +#define SM_PDGAIN_B(x, y) \ + SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) + + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + struct cal_data_per_freq *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx; + + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader[modalIdx].xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader[modalIdx].pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + } else { + pCalBChans = pEepData->calFreqPier5G; + numPiers = AR5416_NUM_5G_CAL_PIERS; + } + + if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { + pRawDataset = pEepData->calPierData2G[0]; + ah->initPDADC = ((struct calDataPerFreqOpLoop *) + pRawDataset)->vpdPdg[0][0]; + } + + numXpdGain = 0; + + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + if (IS_CHAN_2GHZ(chan)) + pRawDataset = pEepData->calPierData2G[i]; + else + pRawDataset = pEepData->calPierData5G[i]; + + + if (OLC_FOR_AR9280_20_LATER) { + u8 pcdacIdx; + u8 txPower; + + ath9k_get_txgain_index(ah, chan, + (struct calDataPerFreqOpLoop *)pRawDataset, + pCalBChans, numPiers, &txPower, &pcdacIdx); + ath9k_olc_get_pdadcs(ah, pcdacIdx, + txPower/2, pdadcValues); + } else { + ath9k_hw_get_def_gain_boundaries_pdadcs(ah, + chan, pRawDataset, + pCalBChans, numPiers, + pdGainOverlap_t2, + &tMinCalPower, + gainBoundaries, + pdadcValues, + numXpdGain); + } + + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { + if (OLC_FOR_AR9280_20_LATER) { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(0x6, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM_PD_GAIN(1) | SM_PD_GAIN(2) | + SM_PD_GAIN(3) | SM_PD_GAIN(4)); + } else { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| + SM_PDGAIN_B(0, 1) | + SM_PDGAIN_B(1, 2) | + SM_PDGAIN_B(2, 3) | + SM_PDGAIN_B(3, 4)); + } + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC: Chain %d | PDADC %3d " + "Value %3d | PDADC %3d Value %3d | " + "PDADC %3d Value %3d | PDADC %3d " + "Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; +#undef SM_PD_GAIN +#undef SM_PDGAIN_B +} + +static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ +#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ +#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ + + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11a[] = + { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ah->txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = max( + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[0], + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); + + twiceLargestAntenna = max((u8)twiceLargestAntenna, + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + + switch (ar5416_get_ntxchains(tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + break; + case 3: + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + break; + } + + scaledPower = max((u16)0, scaledPower); + + if (IS_CHAN_2GHZ(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - + SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } else { + numCtlModes = ARRAY_SIZE(ctlModesFor11a) - + SUB_NUM_CTL_MODES_AT_5G_40; + pCtlMode = ctlModesFor11a; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT20, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11a); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT40, + AR5416_NUM_5G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); + + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = min(twiceMaxEdgePower, scaledPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = + targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = + targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = + targetPowerCck.tPow2x[3]; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rateExtCck] = + targetPowerCckExt.tPow2x[0]; + } + } +} + +static void ath9k_hw_def_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ +#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + struct modal_eep_header *pModal = + &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i, cck_ofdm_delta = 0; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + ath9k_hw_set_def_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); + + ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset); + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + if (OLC_FOR_AR9280_20_LATER) { + cck_ofdm_delta = 2; + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) + | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) + | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) + | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) + | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + if (OLC_FOR_AR9280_20_LATER) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + } + + REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) + | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->regulatory.max_power_level = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->regulatory.max_power_level = ratesArray[i]; + + switch(ar5416_get_ntxchains(ah->txchainmask)) { + case 1: + break; + case 2: + ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; + break; + case 3: + ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); + break; + } +} + +static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) +{ + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct modal_eep_header *pModal = + &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); + struct base_eep_header *pBase = &eep->baseEepHeader; + u8 num_ant_config; + + num_ant_config = 1; + + if (pBase->version >= 0x0E0D) + if (pModal->useAnt1) + num_ant_config += 1; + + return num_ant_config; +} + +static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct modal_eep_header *pModal = + &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + return pModal->antCtrlCommon & 0xFFFF; +} + +static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) +{ +#define EEP_DEF_SPURCHAN \ + (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) + + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); + + switch (ah->config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = EEP_DEF_SPURCHAN; + break; + } + + return spur_val; + +#undef EEP_DEF_SPURCHAN +} + +const struct eeprom_ops eep_def_ops = { + .check_eeprom = ath9k_hw_def_check_eeprom, + .get_eeprom = ath9k_hw_def_get_eeprom, + .fill_eeprom = ath9k_hw_def_fill_eeprom, + .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_def_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_def_set_board_values, + .set_addac = ath9k_hw_def_set_addac, + .set_txpower = ath9k_hw_def_set_txpower, + .get_spur_channel = ath9k_hw_def_get_spur_channel +}; -- cgit v0.10.2 From a37414a220990614de376a155e23dfed471efbdc Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:19 +0530 Subject: ath9k: Cleanup ath9k_hw_4k_set_gain() interface regChainOffset is always zero, remove it. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 111f4d7..aafc6d3 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -844,13 +844,13 @@ static void ath9k_hw_4k_set_addac(struct ath_hw *ah, static void ath9k_hw_4k_set_gain(struct ath_hw *ah, struct modal_eep_4k_header *pModal, struct ar5416_eeprom_4k *eep, - u8 txRxAttenLocal, int regChainOffset) + u8 txRxAttenLocal) { - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0, pModal->antCtrlChain[0]); - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | @@ -860,14 +860,14 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, AR5416_EEP_MINOR_VER_3) { txRxAttenLocal = pModal->txRxAttenCh[0]; - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, pModal->xatten2Margin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); /* Set the block 1 value to block 0 value */ @@ -884,9 +884,9 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, pModal->xatten2Db[0]); } - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, @@ -919,7 +919,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); /* Single chain for 4K EEPROM*/ - ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); + ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal); /* Initialize Ant Diversity settings from EEPROM */ if (pModal->version >= 3) { -- cgit v0.10.2 From 066edc80ebd9e429d593dcfe97b3ed01c9823847 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:21 +0530 Subject: ath9k: Add macros for Antenna Diversity A subsequent patch would use these for configuring antennae on AR9285. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 27bd93c..5317e05 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -312,7 +312,25 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12)) #define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000 #define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000 -#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac + +#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac +#define AR_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000 +#define AR_PHY_9285_ANT_DIV_CTL 0x01000000 +#define AR_PHY_9285_ANT_DIV_CTL_S 24 +#define AR_PHY_9285_ANT_DIV_ALT_LNACONF 0x06000000 +#define AR_PHY_9285_ANT_DIV_ALT_LNACONF_S 25 +#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF 0x18000000 +#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S 27 +#define AR_PHY_9285_ANT_DIV_ALT_GAINTB 0x20000000 +#define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S 29 +#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000 +#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30 +#define AR_PHY_9285_ANT_DIV_LNA1 2 +#define AR_PHY_9285_ANT_DIV_LNA2 1 +#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3 +#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0 +#define AR_PHY_9285_ANT_DIV_GAINTB_0 0 +#define AR_PHY_9285_ANT_DIV_GAINTB_1 1 #define AR_PHY_EXT_CCA0 0x99b8 #define AR_PHY_EXT_CCA0_THRESH62 0x000000FF -- cgit v0.10.2 From 7f63845f2a5f54c64968a4221561c619468b8a54 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:23 +0530 Subject: ath9k: Clean antenna configuration for 4K EEPROM chips This patch revamps the antenna configuration mechanism for 4K chips. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 7d825b6..4fe33f7 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -404,8 +404,13 @@ struct modal_eep_4k_header { u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; u8 pdGainOverlap; - u8 ob_01; - u8 db1_01; +#ifdef __BIG_ENDIAN_BITFIELD + u8 ob_1:4, ob_0:4; + u8 db1_1:4, db1_0:4; +#else + u8 ob_0:4, ob_1:4; + u8 db1_0:4, db1_1:4; +#endif u8 xpaBiasLvl; u8 txFrameToDataStart; u8 txFrameToPaOn; @@ -415,11 +420,27 @@ struct modal_eep_4k_header { u8 swSettleHt40; u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; - u8 db2_01; +#ifdef __BIG_ENDIAN_BITFIELD + u8 db2_1:4, db2_0:4; +#else + u8 db2_0:4, db2_1:4; +#endif u8 version; - u16 ob_234; - u16 db1_234; - u16 db2_234; +#ifdef __BIG_ENDIAN_BITFIELD + u8 ob_3:4, ob_2:4; + u8 antdiv_ctl1:4, ob_4:4; + u8 db1_3:4, db1_2:4; + u8 antdiv_ctl2:4, db1_4:4; + u8 db2_2:4, db2_3:4; + u8 reserved:4, db2_4:4; +#else + u8 ob_2:4, ob_3:4; + u8 ob_4:4, antdiv_ctl1:4; + u8 db1_2:4, db1_3:4; + u8 db1_4:4, antdiv_ctl2:4; + u8 db2_2:4, db2_3:4; + u8 db2_4:4, reserved:4; +#endif u8 futureModal[4]; struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; } __packed; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index aafc6d3..c963615 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -197,9 +197,9 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, case EEP_RF_SILENT: return pBase->rfSilent; case EEP_OB_2: - return pModal->ob_01; + return pModal->ob_0; case EEP_DB_2: - return pModal->db1_01; + return pModal->db1_1; case EEP_MINOR_REV: return pBase->version & AR5416_EEP_VER_MINOR_MASK; case EEP_TX_MASK: @@ -923,58 +923,67 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, /* Initialize Ant Diversity settings from EEPROM */ if (pModal->version >= 3) { - ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); - ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); - regVal = REG_READ(ah, 0x99ac); - regVal &= (~(0x7f000000)); - regVal |= ((ant_div_control1 & 0x1) << 24); - regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); - regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); - regVal |= ((ant_div_control2 & 0x3) << 25); - regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); - REG_WRITE(ah, 0x99ac, regVal); - regVal = REG_READ(ah, 0x99ac); - regVal = REG_READ(ah, 0xa208); - regVal &= (~(0x1 << 13)); - regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); - REG_WRITE(ah, 0xa208, regVal); - regVal = REG_READ(ah, 0xa208); + ant_div_control1 = pModal->antdiv_ctl1; + ant_div_control2 = pModal->antdiv_ctl2; + + regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); + regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL)); + + regVal |= SM(ant_div_control1, + AR_PHY_9285_ANT_DIV_CTL); + regVal |= SM(ant_div_control2, + AR_PHY_9285_ANT_DIV_ALT_LNACONF); + regVal |= SM((ant_div_control2 >> 2), + AR_PHY_9285_ANT_DIV_MAIN_LNACONF); + regVal |= SM((ant_div_control1 >> 1), + AR_PHY_9285_ANT_DIV_ALT_GAINTB); + regVal |= SM((ant_div_control1 >> 2), + AR_PHY_9285_ANT_DIV_MAIN_GAINTB); + + + REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal); + regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); + regVal = REG_READ(ah, AR_PHY_CCK_DETECT); + regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + regVal |= SM((ant_div_control1 >> 3), + AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + + REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal); + regVal = REG_READ(ah, AR_PHY_CCK_DETECT); } if (pModal->version >= 2) { - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = (pModal->ob_01 >> 4) & 0xf; - ob[2] = (pModal->ob_234 & 0xf); - ob[3] = ((pModal->ob_234 >> 4) & 0xf); - ob[4] = ((pModal->ob_234 >> 8) & 0xf); - - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = ((pModal->db1_01 >> 4) & 0xf); - db1[2] = (pModal->db1_234 & 0xf); - db1[3] = ((pModal->db1_234 >> 4) & 0xf); - db1[4] = ((pModal->db1_234 >> 8) & 0xf); - - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = ((pModal->db2_01 >> 4) & 0xf); - db2[2] = (pModal->db2_234 & 0xf); - db2[3] = ((pModal->db2_234 >> 4) & 0xf); - db2[4] = ((pModal->db2_234 >> 8) & 0xf); - + ob[0] = pModal->ob_0; + ob[1] = pModal->ob_1; + ob[2] = pModal->ob_2; + ob[3] = pModal->ob_3; + ob[4] = pModal->ob_4; + + db1[0] = pModal->db1_0; + db1[1] = pModal->db1_1; + db1[2] = pModal->db1_2; + db1[3] = pModal->db1_3; + db1[4] = pModal->db1_4; + + db2[0] = pModal->db2_0; + db2[1] = pModal->db2_1; + db2[2] = pModal->db2_2; + db2[3] = pModal->db2_3; + db2[4] = pModal->db2_4; } else if (pModal->version == 1) { - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = db1[2] = db1[3] = - db1[4] = ((pModal->db1_01 >> 4) & 0xf); - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = db2[2] = db2[3] = - db2[4] = ((pModal->db2_01 >> 4) & 0xf); + ob[0] = pModal->ob_0; + ob[1] = ob[2] = ob[3] = ob[4] = pModal->ob_1; + db1[0] = pModal->db1_0; + db1[1] = db1[2] = db1[3] = db1[4] = pModal->db1_1; + db2[0] = pModal->db2_0; + db2[1] = db2[2] = db2[3] = db2[4] = pModal->db2_1; } else { int i; + for (i = 0; i < 5; i++) { - ob[i] = pModal->ob_01; - db1[i] = pModal->db1_01; - db2[i] = pModal->db1_01; + ob[i] = pModal->ob_0; + db1[i] = pModal->db1_0; + db2[i] = pModal->db1_0; } } diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 5317e05..e83cd4a 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -419,6 +419,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0 #define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6 #define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 +#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S 13 #define AR_PHY_GAIN_2GHZ 0xA20C #define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000 -- cgit v0.10.2 From bf466fb67c8e0559ba1875232b03ee8dee32ae09 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:30 +0530 Subject: ath9k: Cleanup TX power calculation for 4K chips Write CCK power-per-rate array always and report correct TX power to regulatory. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index c963615..29878e0 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -703,11 +703,11 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, } static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) { struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; struct modal_eep_4k_header *pModal = &pEepData->modalHeader; @@ -724,10 +724,10 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, } ath9k_hw_set_4k_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit); + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); @@ -737,11 +737,23 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, ratesArray[i] = AR5416_MAX_RATE_POWER; } + + /* Update regulatory */ + + i = rate6mb; + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + ah->regulatory.max_power_level = ratesArray[i]; + if (AR_SREV_9280_10_OR_LATER(ah)) { for (i = 0; i < Ar5416RateSize; i++) ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; } + /* OFDM power per rate */ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, ATH9K_POW_SM(ratesArray[rate18mb], 24) | ATH9K_POW_SM(ratesArray[rate12mb], 16) @@ -753,19 +765,19 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ATH9K_POW_SM(ratesArray[rate24mb], 0)); - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); - } - + /* CCK power per rate */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + + /* HT20 power per rate */ REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) @@ -777,6 +789,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + /* HT40 power per rate */ if (IS_CHAN_HT40(chan)) { REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, ATH9K_POW_SM(ratesArray[rateHt40_3] + @@ -796,27 +809,12 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, ht40PowerIncForPdadc, 8) | ATH9K_POW_SM(ratesArray[rateHt40_4] + ht40PowerIncForPdadc, 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } - - i = rate6mb; - - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->regulatory.max_power_level = ratesArray[i]; - } static void ath9k_hw_4k_set_addac(struct ath_hw *ah, -- cgit v0.10.2 From 180d674bab10ce10747f7bc7214462da185431bd Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:33 +0530 Subject: ath9k: Remove local chainmask variable The chainmask can be obtained directly from ath_hw. Also, use a helper macro for comparing CTLs - this improves readability. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 29878e0..d34dd23 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -502,14 +502,23 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, u16 twiceMaxRegulatoryPower, u16 powerLimit) { - struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; +#define CMP_TEST_GRP \ + (((cfgCtl & ~CTL_MODE_M)| (pCtlMode[ctlMode] & CTL_MODE_M)) == \ + pEepData->ctlIndex[i]) \ + || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ + ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL)) int i; int16_t twiceLargestAntenna; + u16 twiceMinEdgePower; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; struct cal_ctl_data_4k *rep; + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { 0, { 0, 0, 0, 0} }; @@ -520,27 +529,18 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { 0, {0, 0, 0, 0} }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; u16 ctlModesFor11g[] = { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u16 twiceMinEdgePower; - - tx_chainmask = ah->txchainmask; ath9k_hw_get_channel_centers(ah, chan, ¢ers); twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; - twiceLargestAntenna = (int16_t)min(AntennaReduction - twiceLargestAntenna, 0); maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { maxRegAllowedPower -= (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); @@ -584,6 +584,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) freq = centers.synth_center; else if (pCtlMode[ctlMode] & EXT_ADDITIVE) @@ -596,22 +597,17 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, twiceMaxEdgePower = AR5416_MAX_RATE_POWER; for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && - pEepData->ctlIndex[i]; i++) { - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & CTL_MODE_M) | - SD_NO_CTL))) { + pEepData->ctlIndex[i]; i++) { + + if (CMP_TEST_GRP) { rep = &(pEepData->ctlData[i]); - twiceMinEdgePower = - ath9k_hw_get_max_edge_power(freq, - rep->ctlEdges[ar5416_get_ntxchains - (tx_chainmask) - 1], - IS_CHAN_2GHZ(chan), - AR5416_EEP4K_NUM_BAND_EDGES); + twiceMinEdgePower = ath9k_hw_get_max_edge_power( + freq, + rep->ctlEdges[ + ar5416_get_ntxchains(ah->txchainmask) - 1], + IS_CHAN_2GHZ(chan), + AR5416_EEP4K_NUM_BAND_EDGES); if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { twiceMaxEdgePower = @@ -628,42 +624,38 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, switch (pCtlMode[ctlMode]) { case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); - i++) { + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { targetPowerCck.tPow2x[i] = min((u16)targetPowerCck.tPow2x[i], minCtlPower); } break; case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); - i++) { + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { targetPowerOfdm.tPow2x[i] = min((u16)targetPowerOfdm.tPow2x[i], minCtlPower); } break; case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); - i++) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { targetPowerHt20.tPow2x[i] = min((u16)targetPowerHt20.tPow2x[i], minCtlPower); } break; case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = min((u16) - targetPowerCckExt.tPow2x[0], - minCtlPower); + targetPowerCckExt.tPow2x[0] = + min((u16)targetPowerCckExt.tPow2x[0], + minCtlPower); break; case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = min((u16) - targetPowerOfdmExt.tPow2x[0], - minCtlPower); + targetPowerOfdmExt.tPow2x[0] = + min((u16)targetPowerOfdmExt.tPow2x[0], + minCtlPower); break; case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); - i++) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { targetPowerHt40.tPow2x[i] = min((u16)targetPowerHt40.tPow2x[i], minCtlPower); @@ -674,9 +666,13 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, } } - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; + ratesArray[rate6mb] = + ratesArray[rate9mb] = + ratesArray[rate12mb] = + ratesArray[rate18mb] = + ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; @@ -700,6 +696,8 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; } + +#undef CMP_TEST_GRP } static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, -- cgit v0.10.2 From 5e32b1ed7e81558b09bf0a6bf9e73c34db3c337c Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:36 +0530 Subject: ath9k: Update beacon RSSI ANI uses the beacon RSSI for its operation. Update this properly. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index f6a8b1c..1a08c69 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -252,6 +252,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, else if (ds->ds_rxstat.rs_rssi > 127) ds->ds_rxstat.rs_rssi = 127; + /* Update Beacon RSSI, this is used by ANI. */ + if (ieee80211_is_beacon(fc)) + sc->nodestats.ns_avgbrssi = ds->ds_rxstat.rs_rssi; + rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); rx_status->band = hw->conf.channel->band; rx_status->freq = hw->conf.channel->center_freq; -- cgit v0.10.2 From b8010790c480f495520fd458197f86d758f0c83a Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:32:48 +0300 Subject: wl1251: remove fixed address support from spi commands The fixed addresses are not used in wl1251, only in wl1271. So it can be safely removed. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index c5da79d..c2b813f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -255,8 +255,7 @@ int wl1251_set_partition(struct wl1251 *wl, return 0; } -void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, - size_t len, bool fixed) +void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len) { struct spi_transfer t[3]; struct spi_message m; @@ -271,9 +270,6 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; - if (fixed) - *cmd |= WSPI_CMD_FIXED; - spi_message_init(&m); memset(t, 0, sizeof(t)); @@ -298,8 +294,7 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); } -void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, - size_t len, bool fixed) +void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len) { struct spi_transfer t[2]; struct spi_message m; @@ -312,9 +307,6 @@ void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; - if (fixed) - *cmd |= WSPI_CMD_FIXED; - spi_message_init(&m); memset(t, 0, sizeof(t)); @@ -339,7 +331,7 @@ void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, physical = wl1251_translate_mem_addr(wl, addr); - wl1251_spi_read(wl, physical, buf, len, false); + wl1251_spi_read(wl, physical, buf, len); } void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, @@ -349,27 +341,25 @@ void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, physical = wl1251_translate_mem_addr(wl, addr); - wl1251_spi_write(wl, physical, buf, len, false); + wl1251_spi_write(wl, physical, buf, len); } -void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, - bool fixed) +void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len) { int physical; physical = wl1251_translate_reg_addr(wl, addr); - wl1251_spi_read(wl, physical, buf, len, fixed); + wl1251_spi_read(wl, physical, buf, len); } -void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, - bool fixed) +void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len) { int physical; physical = wl1251_translate_reg_addr(wl, addr); - wl1251_spi_write(wl, physical, buf, len, fixed); + wl1251_spi_write(wl, physical, buf, len); } u32 wl1251_mem_read32(struct wl1251 *wl, int addr) diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index 6e8daf4..7076352 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -71,10 +71,8 @@ /* Raw target IO, address is not translated */ -void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, - size_t len, bool fixed); -void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, - size_t len, bool fixed); +void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len); +void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len); /* Memory target IO, address is tranlated to partition 0 */ void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); @@ -83,10 +81,8 @@ u32 wl1251_mem_read32(struct wl1251 *wl, int addr); void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); /* Registers IO */ -void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, - bool fixed); -void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, - bool fixed); +void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len); +void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len); u32 wl1251_reg_read32(struct wl1251 *wl, int addr); void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); @@ -99,8 +95,7 @@ int wl1251_set_partition(struct wl1251 *wl, static inline u32 wl1251_read32(struct wl1251 *wl, int addr) { - wl1251_spi_read(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); + wl1251_spi_read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); return wl->buffer_32; } @@ -108,8 +103,7 @@ static inline u32 wl1251_read32(struct wl1251 *wl, int addr) static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) { wl->buffer_32 = val; - wl1251_spi_write(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); + wl1251_spi_write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); } #endif /* __WL1251_SPI_H__ */ -- cgit v0.10.2 From 0764de64c8628f653c7e8493017d6bd8d43f4e3b Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:32:56 +0300 Subject: wl1251: separate bus i/o code into io.c In order to eventually support wl1251 spi and sdio interfaces, move the register and memory transfer functions to a common file. Also rename wl1251_spi_mem_{read,write} to indicate its common usage. We still use spi_read internally until SDIO interface is introduced so nothing functional should change here. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index ecb8833..a1a15ce 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,7 +1,7 @@ wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \ wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ wl1251_acx.o wl1251_boot.o wl1251_init.o \ - wl1251_ops.o wl1251_debugfs.o + wl1251_ops.o wl1251_debugfs.o wl1251_io.o obj-$(CONFIG_WL1251) += wl1251.o wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \ diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index a46c92a..2e3171a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -6,7 +6,7 @@ #include "wl1251.h" #include "reg.h" -#include "wl1251_spi.h" +#include "wl1251_cmd.h" #include "wl1251_ps.h" int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index d8a155d..5702398 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -25,7 +25,7 @@ #include "reg.h" #include "wl1251_boot.h" -#include "wl1251_spi.h" +#include "wl1251_io.h" #include "wl1251_event.h" static void wl1251_boot_enable_interrupts(struct wl1251 *wl) diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index dc04d1f..2c30c70 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -6,7 +6,7 @@ #include "wl1251.h" #include "reg.h" -#include "wl1251_spi.h" +#include "wl1251_io.h" #include "wl1251_ps.h" #include "wl1251_acx.h" @@ -31,7 +31,7 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) WARN_ON(len % 4 != 0); - wl1251_spi_mem_write(wl, wl->cmd_box_addr, buf, len); + wl1251_mem_write(wl, wl->cmd_box_addr, buf, len); wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); @@ -86,7 +86,7 @@ int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) * The answer would be a wl1251_command, where the * parameter array contains the actual answer. */ - wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len); cmd_answer = buf; @@ -125,7 +125,7 @@ int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) } /* the interrogate command got in, we can read the answer */ - wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, len); + wl1251_mem_read(wl, wl->cmd_box_addr, buf, len); acx = buf; if (acx->cmd.status != CMD_STATUS_SUCCESS) @@ -379,7 +379,7 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, } /* the read command got in, we can now read the answer */ - wl1251_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); if (cmd->header.status != CMD_STATUS_SUCCESS) wl1251_error("error in read command result: %d", diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 1a0a0bc..1b4f8d2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -24,7 +24,7 @@ #include "wl1251.h" #include "reg.h" -#include "wl1251_spi.h" +#include "wl1251_io.h" #include "wl1251_event.h" #include "wl1251_ps.h" @@ -112,7 +112,7 @@ int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) return -EINVAL; /* first we read the mbox descriptor */ - wl1251_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, + wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, sizeof(struct event_mailbox)); /* process the descriptor */ diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c new file mode 100644 index 0000000..1fa2674 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_io.c @@ -0,0 +1,86 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1251.h" +#include "reg.h" +#include "wl1251_io.h" + +static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) +{ + /* If the address is lower than REGISTERS_BASE, it means that this is + * a chip-specific register address, so look it up in the registers + * table */ + if (addr < REGISTERS_BASE) { + /* Make sure we don't go over the table */ + if (addr >= ACX_REG_TABLE_LEN) { + wl1251_error("address out of range (%d)", addr); + return -EINVAL; + } + addr = wl->chip.acx_reg_table[addr]; + } + + return addr - wl->physical_reg_addr + wl->virtual_reg_addr; +} + +static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) +{ + return addr - wl->physical_mem_addr + wl->virtual_mem_addr; +} + +void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) +{ + int physical; + + physical = wl1251_translate_mem_addr(wl, addr); + + wl1251_spi_read(wl, physical, buf, len); +} + +void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) +{ + int physical; + + physical = wl1251_translate_mem_addr(wl, addr); + + wl1251_spi_write(wl, physical, buf, len); +} + +u32 wl1251_mem_read32(struct wl1251 *wl, int addr) +{ + return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); +} + +void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) +{ + wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); +} + +u32 wl1251_reg_read32(struct wl1251 *wl, int addr) +{ + return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); +} + +void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) +{ + wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); +} diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl12xx/wl1251_io.h new file mode 100644 index 0000000..e2bb954 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_io.h @@ -0,0 +1,54 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#ifndef __WL1251_IO_H__ +#define __WL1251_IO_H__ + +#include "wl1251.h" +#include "wl1251_spi.h" + +/* Raw target IO, address is not translated */ +void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len); +void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len); + +static inline u32 wl1251_read32(struct wl1251 *wl, int addr) +{ + u32 response; + + wl1251_spi_read(wl, addr, &response, sizeof(u32)); + + return response; +} + +static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) +{ + wl1251_spi_write(wl, addr, &val, sizeof(u32)); +} + +/* Memory target IO, address is translated to partition 0 */ +void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); +void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); +u32 wl1251_mem_read32(struct wl1251 *wl, int addr); +void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); +/* Registers IO */ +u32 wl1251_reg_read32(struct wl1251 *wl, int addr); +void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index da4c688..a858e4d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -35,6 +35,7 @@ #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_ops.h" +#include "wl1251_io.h" #include "wl1251_spi.h" #include "wl1251_event.h" #include "wl1251_tx.h" @@ -877,7 +878,7 @@ static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len, if (ret < 0) wl1251_error("SCAN failed"); - wl1251_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); + wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); if (params->header.status != CMD_STATUS_SUCCESS) { wl1251_error("TEST command answer error: %d", diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c index e7b9aab..506123f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -26,7 +26,7 @@ #include "wl1251_ops.h" #include "reg.h" -#include "wl1251_spi.h" +#include "wl1251_io.h" #include "wl1251_boot.h" #include "wl1251_event.h" #include "wl1251_acx.h" @@ -130,7 +130,7 @@ static int wl1251_upload_firmware(struct wl1251 *wl) p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", p, addr); - wl1251_spi_mem_write(wl, addr, p, CHUNK_SIZE); + wl1251_mem_write(wl, addr, p, CHUNK_SIZE); chunk_num++; } @@ -140,7 +140,7 @@ static int wl1251_upload_firmware(struct wl1251 *wl) p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); - wl1251_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 68ff7f1..0581677 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -23,7 +23,8 @@ #include "reg.h" #include "wl1251_ps.h" -#include "wl1251_spi.h" +#include "wl1251_cmd.h" +#include "wl1251_io.h" #define WL1251_WAKEUP_TIMEOUT 2000 diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index 0dbb483..af81879 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -27,8 +27,9 @@ #include "wl1251.h" #include "reg.h" -#include "wl1251_spi.h" +#include "wl1251_io.h" #include "wl1251_rx.h" +#include "wl1251_cmd.h" #include "wl1251_acx.h" static void wl1251_rx_header(struct wl1251 *wl, @@ -40,7 +41,7 @@ static void wl1251_rx_header(struct wl1251 *wl, if (wl->rx_current_buffer) rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - wl1251_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); + wl1251_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); } static void wl1251_rx_status(struct wl1251 *wl, @@ -136,7 +137,7 @@ static void wl1251_rx_body(struct wl1251 *wl, } rx_buffer = skb_put(skb, length); - wl1251_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); + wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); /* The actual lenght doesn't include the target's alignment */ skb->len = desc->length - PLCP_HEADER_LENGTH; diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index c2b813f..031a3ba 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -29,29 +29,6 @@ #include "reg.h" #include "wl1251_spi.h" -static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) -{ - /* If the address is lower than REGISTERS_BASE, it means that this is - * a chip-specific register address, so look it up in the registers - * table */ - if (addr < REGISTERS_BASE) { - /* Make sure we don't go over the table */ - if (addr >= ACX_REG_TABLE_LEN) { - wl1251_error("address out of range (%d)", addr); - return -EINVAL; - } - addr = wl->chip.acx_reg_table[addr]; - } - - return addr - wl->physical_reg_addr + wl->virtual_reg_addr; -} - -static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) -{ - return addr - wl->physical_mem_addr + wl->virtual_mem_addr; -} - - void wl1251_spi_reset(struct wl1251 *wl) { u8 *cmd; @@ -323,61 +300,3 @@ void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len) wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } - -void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, - size_t len) -{ - int physical; - - physical = wl1251_translate_mem_addr(wl, addr); - - wl1251_spi_read(wl, physical, buf, len); -} - -void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, - size_t len) -{ - int physical; - - physical = wl1251_translate_mem_addr(wl, addr); - - wl1251_spi_write(wl, physical, buf, len); -} - -void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len) -{ - int physical; - - physical = wl1251_translate_reg_addr(wl, addr); - - wl1251_spi_read(wl, physical, buf, len); -} - -void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len) -{ - int physical; - - physical = wl1251_translate_reg_addr(wl, addr); - - wl1251_spi_write(wl, physical, buf, len); -} - -u32 wl1251_mem_read32(struct wl1251 *wl, int addr) -{ - return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); -} - -void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); -} - -u32 wl1251_reg_read32(struct wl1251 *wl, int addr) -{ - return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); -} - -void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); -} diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index 7076352..ca9a851 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -69,23 +69,6 @@ ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 - -/* Raw target IO, address is not translated */ -void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len); -void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len); - -/* Memory target IO, address is tranlated to partition 0 */ -void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); -void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); -u32 wl1251_mem_read32(struct wl1251 *wl, int addr); -void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); - -/* Registers IO */ -void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len); -void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len); -u32 wl1251_reg_read32(struct wl1251 *wl, int addr); -void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); - /* INIT and RESET words */ void wl1251_spi_reset(struct wl1251 *wl); void wl1251_spi_init(struct wl1251 *wl); @@ -93,17 +76,4 @@ int wl1251_set_partition(struct wl1251 *wl, u32 part_start, u32 part_size, u32 reg_start, u32 reg_size); -static inline u32 wl1251_read32(struct wl1251 *wl, int addr) -{ - wl1251_spi_read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); - - return wl->buffer_32; -} - -static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl->buffer_32 = val; - wl1251_spi_write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); -} - #endif /* __WL1251_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index 2652a22..7ddc9a3 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -30,6 +30,7 @@ #include "wl1251_spi.h" #include "wl1251_tx.h" #include "wl1251_ps.h" +#include "wl1251_io.h" static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) { @@ -235,7 +236,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, else addr = wl->data_path->tx_packet_ring_addr; - wl1251_spi_mem_write(wl, addr, skb->data, len); + wl1251_mem_write(wl, addr, skb->data, len); wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); @@ -451,7 +452,7 @@ void wl1251_tx_complete(struct wl1251 *wl) return; /* First we read the result */ - wl1251_spi_mem_read(wl, wl->data_path->tx_complete_addr, + wl1251_mem_read(wl, wl->data_path->tx_complete_addr, result, sizeof(result)); result_index = wl->next_tx_complete; @@ -482,41 +483,41 @@ void wl1251_tx_complete(struct wl1251 *wl) */ if (result_index > wl->next_tx_complete) { /* Only 1 write is needed */ - wl1251_spi_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - num_complete * - sizeof(struct tx_result)); + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + num_complete * + sizeof(struct tx_result)); } else if (result_index < wl->next_tx_complete) { /* 2 writes are needed */ - wl1251_spi_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - (FW_TX_CMPLT_BLOCK_SIZE - - wl->next_tx_complete) * - sizeof(struct tx_result)); - - wl1251_spi_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - (num_complete - - FW_TX_CMPLT_BLOCK_SIZE + - wl->next_tx_complete) * - sizeof(struct tx_result)); + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + (FW_TX_CMPLT_BLOCK_SIZE - + wl->next_tx_complete) * + sizeof(struct tx_result)); + + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + (num_complete - + FW_TX_CMPLT_BLOCK_SIZE + + wl->next_tx_complete) * + sizeof(struct tx_result)); } else { /* We have to write the whole array */ - wl1251_spi_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - FW_TX_CMPLT_BLOCK_SIZE * - sizeof(struct tx_result)); + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + FW_TX_CMPLT_BLOCK_SIZE * + sizeof(struct tx_result)); } } -- cgit v0.10.2 From 6c766f413c81d5a11588552934fa093eab6ae06e Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:04 +0300 Subject: wl1251: use wiphy_dev instead of wl->spi->dev Remove a dependency on the bus-specific struct device by using wiphy_dev when requesting firmware. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index a858e4d..953cdb4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -75,9 +75,10 @@ static irqreturn_t wl1251_irq(int irq, void *cookie) static int wl1251_fetch_firmware(struct wl1251 *wl) { const struct firmware *fw; + struct device *dev = wiphy_dev(wl->hw->wiphy); int ret; - ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); + ret = request_firmware(&fw, wl->chip.fw_filename, dev); if (ret < 0) { wl1251_error("could not get firmware: %d", ret); @@ -113,9 +114,10 @@ out: static int wl1251_fetch_nvs(struct wl1251 *wl) { const struct firmware *fw; + struct device *dev = wiphy_dev(wl->hw->wiphy); int ret; - ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); + ret = request_firmware(&fw, wl->chip.nvs_filename, dev); if (ret < 0) { wl1251_error("could not get nvs file: %d", ret); -- cgit v0.10.2 From 08d9f57251841e4870cfd286e867ffcbef81d9a4 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:11 +0300 Subject: wl1251: introduce wl1251_if_operations struct Introduce an ops struct with read, write, and reset functions to abstract away the details of the wl1251 bus interface. Doing this will allow SDIO to coexist with SPI by supplying its own I/O routines. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 665aca0..284bb50 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -281,11 +281,18 @@ struct wl1251_debugfs { struct dentry *excessive_retries; }; +struct wl1251_if_operations { + void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); + void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); + void (*reset)(struct wl1251 *wl); +}; + struct wl1251 { struct ieee80211_hw *hw; bool mac80211_registered; struct spi_device *spi; + struct wl1251_if_operations *if_ops; void (*set_power)(bool enable); int irq; diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 5702398..5c6f327 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -26,6 +26,7 @@ #include "reg.h" #include "wl1251_boot.h" #include "wl1251_io.h" +#include "wl1251_spi.h" #include "wl1251_event.h" static void wl1251_boot_enable_interrupts(struct wl1251 *wl) diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c index 1fa2674..bc95785 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.c +++ b/drivers/net/wireless/wl12xx/wl1251_io.c @@ -53,7 +53,7 @@ void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) physical = wl1251_translate_mem_addr(wl, addr); - wl1251_spi_read(wl, physical, buf, len); + wl->if_ops->read(wl, physical, buf, len); } void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) @@ -62,7 +62,7 @@ void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) physical = wl1251_translate_mem_addr(wl, addr); - wl1251_spi_write(wl, physical, buf, len); + wl->if_ops->write(wl, physical, buf, len); } u32 wl1251_mem_read32(struct wl1251 *wl, int addr) diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl12xx/wl1251_io.h index e2bb954..1fa2ab1 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.h +++ b/drivers/net/wireless/wl12xx/wl1251_io.h @@ -22,24 +22,19 @@ #define __WL1251_IO_H__ #include "wl1251.h" -#include "wl1251_spi.h" - -/* Raw target IO, address is not translated */ -void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len); -void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len); static inline u32 wl1251_read32(struct wl1251 *wl, int addr) { u32 response; - wl1251_spi_read(wl, addr, &response, sizeof(u32)); + wl->if_ops->read(wl, addr, &response, sizeof(u32)); return response; } static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) { - wl1251_spi_write(wl, addr, &val, sizeof(u32)); + wl->if_ops->write(wl, addr, &val, sizeof(u32)); } /* Memory target IO, address is translated to partition 0 */ diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 953cdb4..0f30d0a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -168,8 +168,7 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) wl1251_power_on(wl); msleep(wl->chip.power_on_sleep); - wl1251_spi_reset(wl); - wl1251_spi_init(wl); + wl->if_ops->reset(wl); /* We don't need a real memory partition here, because we only want * to use the registers at this point. */ @@ -1192,6 +1191,8 @@ static int wl1251_init_ieee80211(struct wl1251 *wl) return 0; } +extern struct wl1251_if_operations wl1251_spi_ops; + #define WL1251_DEFAULT_CHANNEL 1 static int __devinit wl1251_probe(struct spi_device *spi) { @@ -1219,6 +1220,7 @@ static int __devinit wl1251_probe(struct spi_device *spi) wl->hw = hw; dev_set_drvdata(&spi->dev, wl); wl->spi = spi; + wl->if_ops = &wl1251_spi_ops; wl->data_in_count = 0; diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c index 506123f..758280a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -27,6 +27,7 @@ #include "wl1251_ops.h" #include "reg.h" #include "wl1251_io.h" +#include "wl1251_spi.h" #include "wl1251_boot.h" #include "wl1251_event.h" #include "wl1251_acx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 031a3ba..61a0852 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -29,7 +29,7 @@ #include "reg.h" #include "wl1251_spi.h" -void wl1251_spi_reset(struct wl1251 *wl) +static void wl1251_spi_reset(struct wl1251 *wl) { u8 *cmd; struct spi_transfer t; @@ -55,7 +55,7 @@ void wl1251_spi_reset(struct wl1251 *wl) wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); } -void wl1251_spi_init(struct wl1251 *wl) +static void wl1251_spi_init(struct wl1251 *wl) { u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; struct spi_transfer t; @@ -109,6 +109,13 @@ void wl1251_spi_init(struct wl1251 *wl) wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); } +static void wl1251_spi_reset_wake(struct wl1251 *wl) +{ + wl1251_spi_reset(wl); + wl1251_spi_init(wl); +} + + /* Set the SPI partitions to access the chip addresses * * There are two VIRTUAL (SPI) partitions (the memory partition and the @@ -232,7 +239,8 @@ int wl1251_set_partition(struct wl1251 *wl, return 0; } -void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len) +static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, + size_t len) { struct spi_transfer t[3]; struct spi_message m; @@ -271,7 +279,8 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len) wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); } -void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len) +static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, + size_t len) { struct spi_transfer t[2]; struct spi_message m; @@ -300,3 +309,9 @@ void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len) wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } + +const struct wl1251_if_operations wl1251_spi_ops = { + .read = wl1251_spi_read, + .write = wl1251_spi_write, + .reset = wl1251_spi_reset_wake, +}; diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index ca9a851..7c6da21 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -69,9 +69,6 @@ ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 -/* INIT and RESET words */ -void wl1251_spi_reset(struct wl1251 *wl); -void wl1251_spi_init(struct wl1251 *wl); int wl1251_set_partition(struct wl1251 *wl, u32 part_start, u32 part_size, u32 reg_start, u32 reg_size); -- cgit v0.10.2 From 0d77e141331b25adf190ce30d69fe5744a69c5bd Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:18 +0300 Subject: wl1251: make wl1251_set_partition bus agnostic The same partition setting code can be used for both SPI and SDIO modes, if we remove the spi-specific commands and use the more generic buffer write routines. Do that and move it to io.c since it deals with register/memory address offsets. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c index bc95785..db2cfbf 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.c +++ b/drivers/net/wireless/wl12xx/wl1251_io.c @@ -84,3 +84,98 @@ void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) { wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); } + +/* Set the partitions to access the chip addresses. + * + * There are two VIRTUAL partitions (the memory partition and the + * registers partition), which are mapped to two different areas of the + * PHYSICAL (hardware) memory. This function also makes other checks to + * ensure that the partitions are not overlapping. In the diagram below, the + * memory partition comes before the register partition, but the opposite is + * also supported. + * + * PHYSICAL address + * space + * + * | | + * ...+----+--> mem_start + * VIRTUAL address ... | | + * space ... | | [PART_0] + * ... | | + * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * part_size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * part_size | | ... | | + * + <--+----+... ...+----+--> reg_start + * reg_size ... | | + * ... | | [PART_1] + * ... | | + * ...+----+--> reg_start + reg_size + * | | + * + */ +void wl1251_set_partition(struct wl1251 *wl, + u32 mem_start, u32 mem_size, + u32 reg_start, u32 reg_size) +{ + struct wl1251_partition partition[2]; + + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + + /* Make sure that the two partitions together don't exceed the + * address range */ + if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { + wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" + " address range. Truncating partition[0]."); + mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + if ((mem_start < reg_start) && + ((mem_start + mem_size) > reg_start)) { + /* Guarantee that the memory partition doesn't overlap the + * registers partition */ + wl1251_debug(DEBUG_SPI, "End of partition[0] is " + "overlapping partition[1]. Adjusted."); + mem_size = reg_start - mem_start; + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } else if ((reg_start < mem_start) && + ((reg_start + reg_size) > mem_start)) { + /* Guarantee that the register partition doesn't overlap the + * memory partition */ + wl1251_debug(DEBUG_SPI, "End of partition[1] is" + " overlapping partition[0]. Adjusted."); + reg_size = mem_start - reg_start; + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + partition[0].start = mem_start; + partition[0].size = mem_size; + partition[1].start = reg_start; + partition[1].size = reg_size; + + wl->physical_mem_addr = mem_start; + wl->physical_reg_addr = reg_start; + + wl->virtual_mem_addr = 0; + wl->virtual_reg_addr = mem_size; + + wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition, + sizeof(partition)); +} diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl12xx/wl1251_io.h index 1fa2ab1..b89d2ac 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.h +++ b/drivers/net/wireless/wl12xx/wl1251_io.h @@ -23,6 +23,17 @@ #include "wl1251.h" +#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 + +#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 +#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 +#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 +#define HW_ACCESS_PART1_START_ADDR 0x1FFCC + +#define HW_ACCESS_REGISTER_SIZE 4 + +#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 + static inline u32 wl1251_read32(struct wl1251 *wl, int addr) { u32 response; @@ -46,4 +57,8 @@ void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); u32 wl1251_reg_read32(struct wl1251 *wl, int addr); void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); +void wl1251_set_partition(struct wl1251 *wl, + u32 part_start, u32 part_size, + u32 reg_start, u32 reg_size); + #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 61a0852..ceb237b 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -115,130 +115,6 @@ static void wl1251_spi_reset_wake(struct wl1251 *wl) wl1251_spi_init(wl); } - -/* Set the SPI partitions to access the chip addresses - * - * There are two VIRTUAL (SPI) partitions (the memory partition and the - * registers partition), which are mapped to two different areas of the - * PHYSICAL (hardware) memory. This function also makes other checks to - * ensure that the partitions are not overlapping. In the diagram below, the - * memory partition comes before the register partition, but the opposite is - * also supported. - * - * PHYSICAL address - * space - * - * | | - * ...+----+--> mem_start - * VIRTUAL address ... | | - * space ... | | [PART_0] - * ... | | - * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size - * | | ... | | - * |MEM | ... | | - * | | ... | | - * part_size <--+----+... | | {unused area) - * | | ... | | - * |REG | ... | | - * part_size | | ... | | - * + <--+----+... ...+----+--> reg_start - * reg_size ... | | - * ... | | [PART_1] - * ... | | - * ...+----+--> reg_start + reg_size - * | | - * - */ -int wl1251_set_partition(struct wl1251 *wl, - u32 mem_start, u32 mem_size, - u32 reg_start, u32 reg_size) -{ - struct wl1251_partition *partition; - struct spi_transfer t; - struct spi_message m; - size_t len, cmd_len; - u32 *cmd; - int addr; - - cmd_len = sizeof(u32) + 2 * sizeof(struct wl1251_partition); - cmd = kzalloc(cmd_len, GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - spi_message_init(&m); - memset(&t, 0, sizeof(t)); - - partition = (struct wl1251_partition *) (cmd + 1); - addr = HW_ACCESS_PART0_SIZE_ADDR; - len = 2 * sizeof(struct wl1251_partition); - - *cmd |= WSPI_CMD_WRITE; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - - /* Make sure that the two partitions together don't exceed the - * address range */ - if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { - wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" - " address range. Truncating partition[0]."); - mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - if ((mem_start < reg_start) && - ((mem_start + mem_size) > reg_start)) { - /* Guarantee that the memory partition doesn't overlap the - * registers partition */ - wl1251_debug(DEBUG_SPI, "End of partition[0] is " - "overlapping partition[1]. Adjusted."); - mem_size = reg_start - mem_start; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } else if ((reg_start < mem_start) && - ((reg_start + reg_size) > mem_start)) { - /* Guarantee that the register partition doesn't overlap the - * memory partition */ - wl1251_debug(DEBUG_SPI, "End of partition[1] is" - " overlapping partition[0]. Adjusted."); - reg_size = mem_start - reg_start; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - partition[0].start = mem_start; - partition[0].size = mem_size; - partition[1].start = reg_start; - partition[1].size = reg_size; - - wl->physical_mem_addr = mem_start; - wl->physical_reg_addr = reg_start; - - wl->virtual_mem_addr = 0; - wl->virtual_reg_addr = mem_size; - - t.tx_buf = cmd; - t.len = cmd_len; - spi_message_add_tail(&t, &m); - - spi_sync(wl->spi, &m); - - kfree(cmd); - - return 0; -} - static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len) { diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index 7c6da21..cb0c228 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -29,17 +29,6 @@ #include "wl1251_acx.h" #include "reg.h" -#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 - -#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 -#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 -#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 -#define HW_ACCESS_PART1_START_ADDR 0x1FFCC - -#define HW_ACCESS_REGISTER_SIZE 4 - -#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 - #define WSPI_CMD_READ 0x40000000 #define WSPI_CMD_WRITE 0x00000000 #define WSPI_CMD_FIXED 0x20000000 @@ -69,8 +58,4 @@ ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 -int wl1251_set_partition(struct wl1251 *wl, - u32 part_start, u32 part_size, - u32 reg_start, u32 reg_size); - #endif /* __WL1251_SPI_H__ */ -- cgit v0.10.2 From 8e639c0673a9b676bb7c6bd4e50f9003bdda423e Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:26 +0300 Subject: wl1251: move module probe methods into spi.c This change moves all of the spi specific code from main.c into spi.c. The module initialization code also moves, but common code for initializing mac80211 etc. stays in main.c, as this will eventually form a common library module also used by wl1251_sdio. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 284bb50..df4c06d 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -292,7 +292,7 @@ struct wl1251 { bool mac80211_registered; struct spi_device *spi; - struct wl1251_if_operations *if_ops; + const struct wl1251_if_operations *if_ops; void (*set_power)(bool enable); int irq; @@ -404,6 +404,11 @@ struct wl1251 { int wl1251_plt_start(struct wl1251 *wl); int wl1251_plt_stop(struct wl1251 *wl); +irqreturn_t wl1251_irq(int irq, void *cookie); +struct ieee80211_hw *wl1251_alloc_hw(void); +int wl1251_free_hw(struct wl1251 *wl); +int wl1251_init_ieee80211(struct wl1251 *wl); + #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 2e3171a..91fe16c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -2,7 +2,6 @@ #include #include -#include #include "wl1251.h" #include "reg.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 2c30c70..dfbf681 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -2,7 +2,6 @@ #include #include -#include #include "wl1251.h" #include "reg.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 0f30d0a..74544e1 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -26,17 +26,15 @@ #include #include #include -#include #include #include -#include #include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_ops.h" #include "wl1251_io.h" -#include "wl1251_spi.h" +#include "wl1251_cmd.h" #include "wl1251_event.h" #include "wl1251_tx.h" #include "wl1251_rx.h" @@ -59,7 +57,7 @@ static void wl1251_power_on(struct wl1251 *wl) wl->set_power(true); } -static irqreturn_t wl1251_irq(int irq, void *cookie) +irqreturn_t wl1251_irq(int irq, void *cookie) { struct wl1251 *wl; @@ -1169,8 +1167,10 @@ static int wl1251_register_hw(struct wl1251 *wl) return 0; } -static int wl1251_init_ieee80211(struct wl1251 *wl) +int wl1251_init_ieee80211(struct wl1251 *wl) { + int ret; + /* The tx descriptor buffer and the TKIP space */ wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) + WL1251_TKIP_IV_SPACE; @@ -1186,41 +1186,37 @@ static int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; - SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); + ret = wl1251_register_hw(wl); + if (ret) + goto out; - return 0; -} + wl1251_debugfs_init(wl); + wl1251_notice("initialized"); -extern struct wl1251_if_operations wl1251_spi_ops; + ret = 0; + +out: + return ret; +} #define WL1251_DEFAULT_CHANNEL 1 -static int __devinit wl1251_probe(struct spi_device *spi) +struct ieee80211_hw *wl1251_alloc_hw(void) { - struct wl12xx_platform_data *pdata; struct ieee80211_hw *hw; struct wl1251 *wl; - int ret, i; + int i; static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; - pdata = spi->dev.platform_data; - if (!pdata) { - wl1251_error("no platform data"); - return -ENODEV; - } - hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); if (!hw) { wl1251_error("could not alloc ieee80211_hw"); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } wl = hw->priv; memset(wl, 0, sizeof(*wl)); wl->hw = hw; - dev_set_drvdata(&spi->dev, wl); - wl->spi = spi; - wl->if_ops = &wl1251_spi_ops; wl->data_in_count = 0; @@ -1268,74 +1264,15 @@ static int __devinit wl1251_probe(struct spi_device *spi) wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); if (!wl->rx_descriptor) { wl1251_error("could not allocate memory for rx descriptor"); - ret = -ENOMEM; - goto out_free; + ieee80211_free_hw(hw); + return ERR_PTR(-ENOMEM); } - /* This is the only SPI value that we need to set here, the rest - * comes from the board-peripherals file */ - spi->bits_per_word = 32; - - ret = spi_setup(spi); - if (ret < 0) { - wl1251_error("spi_setup failed"); - goto out_free; - } - - wl->set_power = pdata->set_power; - if (!wl->set_power) { - wl1251_error("set power function missing in platform data"); - ret = -ENODEV; - goto out_free; - } - - wl->irq = spi->irq; - if (wl->irq < 0) { - wl1251_error("irq missing in platform data"); - ret = -ENODEV; - goto out_free; - } - - ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); - if (ret < 0) { - wl1251_error("request_irq() failed: %d", ret); - goto out_free; - } - - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - - disable_irq(wl->irq); - - ret = wl1251_init_ieee80211(wl); - if (ret) - goto out_irq; - - ret = wl1251_register_hw(wl); - if (ret) - goto out_irq; - - wl1251_debugfs_init(wl); - - wl1251_notice("initialized"); - - return 0; - - out_irq: - free_irq(wl->irq, wl); - - out_free: - kfree(wl->rx_descriptor); - wl->rx_descriptor = NULL; - - ieee80211_free_hw(hw); - - return ret; + return hw; } -static int __devexit wl1251_remove(struct spi_device *spi) +int wl1251_free_hw(struct wl1251 *wl) { - struct wl1251 *wl = dev_get_drvdata(&spi->dev); - ieee80211_unregister_hw(wl->hw); wl1251_debugfs_exit(wl); @@ -1355,44 +1292,3 @@ static int __devexit wl1251_remove(struct spi_device *spi) return 0; } - - -static struct spi_driver wl1251_spi_driver = { - .driver = { - /* FIXME: use wl12xx name to not break the user space */ - .name = "wl12xx", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - - .probe = wl1251_probe, - .remove = __devexit_p(wl1251_remove), -}; - -static int __init wl1251_init(void) -{ - int ret; - - ret = spi_register_driver(&wl1251_spi_driver); - if (ret < 0) { - wl1251_error("failed to register spi driver: %d", ret); - goto out; - } - -out: - return ret; -} - -static void __exit wl1251_exit(void) -{ - spi_unregister_driver(&wl1251_spi_driver); - - wl1251_notice("unloaded"); -} - -module_init(wl1251_init); -module_exit(wl1251_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo , " - "Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index ceb237b..13e7a72 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -21,9 +21,11 @@ * */ +#include #include #include #include +#include #include "wl1251.h" #include "reg.h" @@ -55,7 +57,7 @@ static void wl1251_spi_reset(struct wl1251 *wl) wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); } -static void wl1251_spi_init(struct wl1251 *wl) +static void wl1251_spi_wake(struct wl1251 *wl) { u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; struct spi_transfer t; @@ -112,7 +114,7 @@ static void wl1251_spi_init(struct wl1251 *wl) static void wl1251_spi_reset_wake(struct wl1251 *wl) { wl1251_spi_reset(wl); - wl1251_spi_init(wl); + wl1251_spi_wake(wl); } static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, @@ -191,3 +193,122 @@ const struct wl1251_if_operations wl1251_spi_ops = { .write = wl1251_spi_write, .reset = wl1251_spi_reset_wake, }; + +static int __devinit wl1251_spi_probe(struct spi_device *spi) +{ + struct wl12xx_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl1251 *wl; + int ret; + + pdata = spi->dev.platform_data; + if (!pdata) { + wl1251_error("no platform data"); + return -ENODEV; + } + + hw = wl1251_alloc_hw(); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + wl = hw->priv; + + SET_IEEE80211_DEV(hw, &spi->dev); + dev_set_drvdata(&spi->dev, wl); + wl->spi = spi; + wl->if_ops = &wl1251_spi_ops; + + /* This is the only SPI value that we need to set here, the rest + * comes from the board-peripherals file */ + spi->bits_per_word = 32; + + ret = spi_setup(spi); + if (ret < 0) { + wl1251_error("spi_setup failed"); + goto out_free; + } + + wl->set_power = pdata->set_power; + if (!wl->set_power) { + wl1251_error("set power function missing in platform data"); + return -ENODEV; + } + + wl->irq = spi->irq; + if (wl->irq < 0) { + wl1251_error("irq missing in platform data"); + return -ENODEV; + } + + ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); + if (ret < 0) { + wl1251_error("request_irq() failed: %d", ret); + goto out_free; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + + disable_irq(wl->irq); + + ret = wl1251_init_ieee80211(wl); + if (ret) + goto out_irq; + + return 0; + + out_irq: + free_irq(wl->irq, wl); + + out_free: + ieee80211_free_hw(hw); + + return ret; +} + +static int __devexit wl1251_spi_remove(struct spi_device *spi) +{ + struct wl1251 *wl = dev_get_drvdata(&spi->dev); + + wl1251_free_hw(wl); + + return 0; +} + +static struct spi_driver wl1251_spi_driver = { + .driver = { + .name = "wl12xx", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = wl1251_spi_probe, + .remove = __devexit_p(wl1251_spi_remove), +}; + +static int __init wl1251_spi_init(void) +{ + int ret; + + ret = spi_register_driver(&wl1251_spi_driver); + if (ret < 0) { + wl1251_error("failed to register spi driver: %d", ret); + goto out; + } + +out: + return ret; +} + +static void __exit wl1251_spi_exit(void) +{ + spi_unregister_driver(&wl1251_spi_driver); + + wl1251_notice("unloaded"); +} + +module_init(wl1251_spi_init); +module_exit(wl1251_spi_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo "); +MODULE_AUTHOR("Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index 7ddc9a3..f20bab6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -27,7 +27,6 @@ #include "wl1251.h" #include "reg.h" -#include "wl1251_spi.h" #include "wl1251_tx.h" #include "wl1251_ps.h" #include "wl1251_io.h" -- cgit v0.10.2 From af8c78ebbf2a15ecf9b2b6b7b051b0d4c3ba1163 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:34 +0300 Subject: wl1251: split spi interface into separate module This creates a module called wl1251_spi.ko which contains just the SPI-specific code. The core remains in the module wl1251.ko. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index af31eab..f8cb8b8 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -7,15 +7,26 @@ menuconfig WL12XX config WL1251 tristate "TI wl1251 support" - depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS + depends on WL12XX && GENERIC_HARDIRQS select FW_LOADER select CRC7 ---help--- This module adds support for wireless adapters based on TI wl1251 chipset. - If you choose to build a module, it'll be called wl1251. Say N if - unsure. + If you choose to build a module, it'll be called wl1251. Say + N if unsure. + +config WL1251_SPI + tristate "TI wl1251 SPI support" + depends on WL1251 && SPI_MASTER + ---help--- + This module adds support for the SPI interface of adapters using + TI wl1251 chipset. Select this if your platform is using + the SPI bus. + + If you choose to build a module, it'll be called wl1251_spi. + Say N if unsure. config WL1271 tristate "TI wl1271 support" diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index a1a15ce..ea0477f 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,8 +1,10 @@ -wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \ +wl1251-objs = wl1251_main.o wl1251_event.o \ wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ wl1251_acx.o wl1251_boot.o wl1251_init.o \ wl1251_ops.o wl1251_debugfs.o wl1251_io.o + obj-$(CONFIG_WL1251) += wl1251.o +obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \ wl1271_event.o wl1271_tx.o wl1271_rx.o \ diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index df4c06d..ebe2c70 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -291,7 +291,7 @@ struct wl1251 { struct ieee80211_hw *hw; bool mac80211_registered; - struct spi_device *spi; + void *if_priv; const struct wl1251_if_operations *if_ops; void (*set_power)(bool enable); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 74544e1..abe157a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -69,6 +69,7 @@ irqreturn_t wl1251_irq(int irq, void *cookie) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(wl1251_irq); static int wl1251_fetch_firmware(struct wl1251 *wl) { @@ -1198,6 +1199,7 @@ int wl1251_init_ieee80211(struct wl1251 *wl) out: return ret; } +EXPORT_SYMBOL_GPL(wl1251_init_ieee80211); #define WL1251_DEFAULT_CHANNEL 1 struct ieee80211_hw *wl1251_alloc_hw(void) @@ -1270,6 +1272,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) return hw; } +EXPORT_SYMBOL_GPL(wl1251_alloc_hw); int wl1251_free_hw(struct wl1251 *wl) { @@ -1292,3 +1295,9 @@ int wl1251_free_hw(struct wl1251 *wl) return 0; } +EXPORT_SYMBOL_GPL(wl1251_free_hw); + +MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo "); +MODULE_AUTHOR("Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 13e7a72..5967317 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -31,6 +31,11 @@ #include "reg.h" #include "wl1251_spi.h" +static struct spi_device *wl_to_spi(struct wl1251 *wl) +{ + return wl->if_priv; +} + static void wl1251_spi_reset(struct wl1251 *wl) { u8 *cmd; @@ -52,7 +57,7 @@ static void wl1251_spi_reset(struct wl1251 *wl) t.len = WSPI_INIT_CMD_LEN; spi_message_add_tail(&t, &m); - spi_sync(wl->spi, &m); + spi_sync(wl_to_spi(wl), &m); wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); } @@ -106,7 +111,7 @@ static void wl1251_spi_wake(struct wl1251 *wl) t.len = WSPI_INIT_CMD_LEN; spi_message_add_tail(&t, &m); - spi_sync(wl->spi, &m); + spi_sync(wl_to_spi(wl), &m); wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); } @@ -149,7 +154,7 @@ static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, t[2].len = len; spi_message_add_tail(&t[2], &m); - spi_sync(wl->spi, &m); + spi_sync(wl_to_spi(wl), &m); /* FIXME: check busy words */ @@ -182,13 +187,13 @@ static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, t[1].len = len; spi_message_add_tail(&t[1], &m); - spi_sync(wl->spi, &m); + spi_sync(wl_to_spi(wl), &m); wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } -const struct wl1251_if_operations wl1251_spi_ops = { +static const struct wl1251_if_operations wl1251_spi_ops = { .read = wl1251_spi_read, .write = wl1251_spi_write, .reset = wl1251_spi_reset_wake, @@ -215,7 +220,7 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi) SET_IEEE80211_DEV(hw, &spi->dev); dev_set_drvdata(&spi->dev, wl); - wl->spi = spi; + wl->if_priv = spi; wl->if_ops = &wl1251_spi_ops; /* This is the only SPI value that we need to set here, the rest -- cgit v0.10.2 From 3ec410d747fa1da035183c43775a64c0e285e399 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:42 +0300 Subject: wl1251: add sdio support This adds the wl1251_sdio module, enabling the SDIO interface for wl1251, as used by the Google G1 phone and others. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index f8cb8b8..7b14d5b 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -28,6 +28,17 @@ config WL1251_SPI If you choose to build a module, it'll be called wl1251_spi. Say N if unsure. +config WL1251_SDIO + tristate "TI wl1251 SDIO support" + depends on WL1251 && MMC + ---help--- + This module adds support for the SDIO interface of adapters using + TI wl1251 chipset. Select this if your platform is using + the SDIO bus. + + If you choose to build a module, it'll be called + wl1251_sdio. Say N if unsure. + config WL1271 tristate "TI wl1271 support" depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index ea0477f..207e852 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -5,6 +5,7 @@ wl1251-objs = wl1251_main.o wl1251_event.o \ obj-$(CONFIG_WL1251) += wl1251.o obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o +obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \ wl1271_event.o wl1271_tx.o wl1271_rx.o \ diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c new file mode 100644 index 0000000..f1d9e76 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c @@ -0,0 +1,188 @@ +/* + * wl12xx SDIO routines + * + * 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 + * published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * Copyright (C) 2005 Texas Instruments Incorporated + * Copyright (C) 2008 Google Inc + * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com) + */ +#include +#include +#include +#include +#include +#include +#include + +#include "wl1251.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251_ps.h" +#include "wl1251_io.h" +#include "wl1251_tx.h" +#include "wl1251_debugfs.h" + +#ifndef SDIO_VENDOR_ID_TI +#define SDIO_VENDOR_ID_TI 0x104c +#endif + +#ifndef SDIO_DEVICE_ID_TI_WL1251 +#define SDIO_DEVICE_ID_TI_WL1251 0x9066 +#endif + +static struct sdio_func *wl_to_func(struct wl1251 *wl) +{ + return wl->if_priv; +} + +static void wl1251_sdio_interrupt(struct sdio_func *func) +{ + wl1251_irq(0, sdio_get_drvdata(func)); +} + +static const struct sdio_device_id wl1251_devices[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1251) }, + {} +}; +MODULE_DEVICE_TABLE(sdio, wl1251_devices); + + +void wl1251_sdio_read(struct wl1251 *wl, int addr, void *buf, size_t len) +{ + int ret; + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + ret = sdio_memcpy_fromio(func, buf, addr, len); + if (ret) + wl1251_error("sdio read failed (%d)", ret); + sdio_release_host(func); +} + +void wl1251_sdio_write(struct wl1251 *wl, int addr, void *buf, size_t len) +{ + int ret; + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + ret = sdio_memcpy_toio(func, addr, buf, len); + if (ret) + wl1251_error("sdio write failed (%d)", ret); + sdio_release_host(func); +} + +void wl1251_sdio_reset(struct wl1251 *wl) +{ +} + +void wl1251_sdio_set_power(bool enable) +{ +} + +struct wl1251_if_operations wl1251_sdio_ops = { + .read = wl1251_sdio_read, + .write = wl1251_sdio_write, + .reset = wl1251_sdio_reset, +}; + +int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int ret; + struct wl1251 *wl; + struct ieee80211_hw *hw; + + hw = wl1251_alloc_hw(); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + wl = hw->priv; + + sdio_claim_host(func); + ret = sdio_enable_func(func); + if (ret) + goto release; + + sdio_set_block_size(func, 512); + + SET_IEEE80211_DEV(hw, &func->dev); + wl->if_priv = func; + wl->if_ops = &wl1251_sdio_ops; + wl->set_power = wl1251_sdio_set_power; + + sdio_release_host(func); + ret = wl1251_init_ieee80211(wl); + sdio_claim_host(func); + if (ret) + goto disable; + + ret = sdio_claim_irq(func, wl1251_sdio_interrupt); + if (ret) + goto no_irq; + + sdio_release_host(func); + sdio_set_drvdata(func, wl); + return ret; + +no_irq: + wl1251_free_hw(wl); +disable: + sdio_disable_func(func); +release: + sdio_release_host(func); + return ret; +} + +static void __devexit wl1251_sdio_remove(struct sdio_func *func) +{ + struct wl1251 *wl = sdio_get_drvdata(func); + + wl1251_free_hw(wl); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); +} + +static struct sdio_driver wl1251_sdio_driver = { + .name = "wl1251_sdio", + .id_table = wl1251_devices, + .probe = wl1251_sdio_probe, + .remove = __devexit_p(wl1251_sdio_remove), +}; + +static int __init wl1251_sdio_init(void) +{ + int err; + + err = sdio_register_driver(&wl1251_sdio_driver); + if (err) + wl1251_error("failed to register sdio driver: %d", err); + return err; +} + +static void __exit wl1251_sdio_exit(void) +{ + sdio_unregister_driver(&wl1251_sdio_driver); + wl1251_notice("unloaded"); +} + +module_init(wl1251_sdio_init); +module_exit(wl1251_sdio_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo "); +MODULE_AUTHOR("Luciano Coelho "); -- cgit v0.10.2 From b5ed9c1b6f8fcb2d2315f12599fd5808f7933f16 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:49 +0300 Subject: wl1251: make irq handling interface specific In SDIO, the host driver requests the IRQ and invokes a callback to the card driver. This differs from SPI, so the relevant code needs to be interface-specific. This patch pushes the irq code down into _spi.c and _sdio.c, and adds enable/disable callbacks. This fixes the following warning: [ 566.343887] ------------[ cut here ]------------ [ 566.349105] WARNING: at kernel/irq/manage.c:222 __enable_irq+0x3c/0x6c() [ 566.356735] Unbalanced enable for IRQ 0 [ 566.361099] Modules linked in: msm_wifi wl12xx_sdio wl12xx mac80211 cfg80211 rfkill_backport lib80211_crypt_ccmp lib80211_crypt_wep lib80211_crypt_tkip lib80211 [ 566.381240] [] (dump_stack+0x0/0x14) from [] (warn_slowpath+0x70/0x8c) [ 566.391860] [] (warn_slowpath+0x0/0x8c) from [] (__enable_irq+0x3c/0x6c) [ 566.402572] r3:00000000 r2:c02cad13 [ 566.407516] r7:00001002 r6:00000000 r5:c0310be4 r4:c0310be4 [ 566.415786] [] (__enable_irq+0x0/0x6c) from [] (enable_irq+0x38/0x64) [ 566.425826] r5:c0310be4 r4:a0000013 [ 566.430709] [] (enable_irq+0x0/0x64) from [] (wl12xx_boot_run_firmware+0xfc/0x170 [wl12xx]) [ 566.442947] r7:00001002 r6:c440a9fc r5:00000072 r4:c440a9e0 [ 566.450851] [] (wl12xx_boot_run_firmware+0x0/0x170 [wl12xx]) from [] (wl1251_boot+0xd4/0x108 [wl12xx]) [ 566.464492] r5:00000000 r4:c440a9e0 [ 566.469466] [] (wl1251_boot+0x0/0x108 [wl12xx]) from [] (wl12xx_op_start+0x54/0xb8 [wl12xx]) [ 566.482162] r5:00000000 r4:c440a9e0 [ 566.487472] [] (wl12xx_op_start+0x0/0xb8 [wl12xx]) from [] (ieee80211_open+0x2dc/0x720 [mac80211]) [ 566.500594] r7:00001002 r6:c4950800 r5:c440a220 r4:00000000 [ 566.508865] [] (ieee80211_open+0x0/0x720 [mac80211]) from [] (dev_open+0x9c/0xfc) [ 566.520705] [] (dev_open+0x0/0xfc) from [] (dev_change_flags+0x98/0x170) [ 566.531417] r5:00000041 r4:c4950800 [ 566.536330] [] (dev_change_flags+0x0/0x170) from [] (devinet_ioctl+0x3a8/0x784) [ 566.547683] r7:c128e380 r6:00000001 r5:00008914 r4:00000000 [ 566.555587] [] (devinet_ioctl+0x0/0x784) from [] (inet_ioctl+0xdc/0x114) [ 566.566299] [] (inet_ioctl+0x0/0x114) from [] (sock_ioctl+0x1f0/0x248) [ 566.576827] r5:00008914 r4:c572c1a0 [ 566.581771] [] (sock_ioctl+0x0/0x248) from [] (vfs_ioctl+0x34/0x94) [ 566.592086] r7:c572c1a0 r6:bee497e8 r5:00008914 r4:c572c1a0 [ 566.599990] [] (vfs_ioctl+0x0/0x94) from [] (do_vfs_ioctl+0x52c/0x584) [ 566.610549] r7:c572c1a0 r6:00008914 r5:c572c1a0 r4:c3201228 [ 566.618453] [] (do_vfs_ioctl+0x0/0x584) from [] (sys_ioctl+0x40/0x64) [ 566.628890] [] (sys_ioctl+0x0/0x64) from [] (ret_fast_syscall+0x0/0x2c) [ 566.639541] r7:00000036 r6:00000000 r5:00000004 r4:001a11f3 [ 566.647445] ---[ end trace 15c26ef7dd5e7b03 ]--- Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index ebe2c70..13f0589 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -285,6 +285,8 @@ struct wl1251_if_operations { void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); void (*reset)(struct wl1251 *wl); + void (*enable_irq)(struct wl1251 *wl); + void (*disable_irq)(struct wl1251 *wl); }; struct wl1251 { @@ -404,10 +406,11 @@ struct wl1251 { int wl1251_plt_start(struct wl1251 *wl); int wl1251_plt_stop(struct wl1251 *wl); -irqreturn_t wl1251_irq(int irq, void *cookie); struct ieee80211_hw *wl1251_alloc_hw(void); int wl1251_free_hw(struct wl1251 *wl); int wl1251_init_ieee80211(struct wl1251 *wl); +void wl1251_enable_interrupts(struct wl1251 *wl); +void wl1251_disable_interrupts(struct wl1251 *wl); #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 5c6f327..8b50d44 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -29,11 +29,6 @@ #include "wl1251_spi.h" #include "wl1251_event.h" -static void wl1251_boot_enable_interrupts(struct wl1251 *wl) -{ - enable_irq(wl->irq); -} - void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) { wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); @@ -278,7 +273,7 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) */ /* enable gpio interrupts */ - wl1251_boot_enable_interrupts(wl); + wl1251_enable_interrupts(wl); wl->chip.op_target_enable_interrupts(wl); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index abe157a..4c1aad3 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -42,9 +42,14 @@ #include "wl1251_init.h" #include "wl1251_debugfs.h" -static void wl1251_disable_interrupts(struct wl1251 *wl) +void wl1251_enable_interrupts(struct wl1251 *wl) { - disable_irq(wl->irq); + wl->if_ops->enable_irq(wl); +} + +void wl1251_disable_interrupts(struct wl1251 *wl) +{ + wl->if_ops->disable_irq(wl); } static void wl1251_power_off(struct wl1251 *wl) @@ -57,20 +62,6 @@ static void wl1251_power_on(struct wl1251 *wl) wl->set_power(true); } -irqreturn_t wl1251_irq(int irq, void *cookie) -{ - struct wl1251 *wl; - - wl1251_debug(DEBUG_IRQ, "IRQ"); - - wl = cookie; - - schedule_work(&wl->irq_work); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL_GPL(wl1251_irq); - static int wl1251_fetch_firmware(struct wl1251 *wl) { const struct firmware *fw; @@ -1280,7 +1271,6 @@ int wl1251_free_hw(struct wl1251 *wl) wl1251_debugfs_exit(wl); - free_irq(wl->irq, wl); kfree(wl->target_mem_map); kfree(wl->data_path); kfree(wl->fw); diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index f1d9e76..f7e451f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c @@ -50,7 +50,12 @@ static struct sdio_func *wl_to_func(struct wl1251 *wl) static void wl1251_sdio_interrupt(struct sdio_func *func) { - wl1251_irq(0, sdio_get_drvdata(func)); + struct wl1251 *wl = sdio_get_drvdata(func); + + wl1251_debug(DEBUG_IRQ, "IRQ"); + + /* FIXME should be synchronous for sdio */ + schedule_work(&wl->irq_work); } static const struct sdio_device_id wl1251_devices[] = { @@ -88,6 +93,24 @@ void wl1251_sdio_reset(struct wl1251 *wl) { } +static void wl1251_sdio_enable_irq(struct wl1251 *wl) +{ + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + sdio_claim_irq(func, wl1251_sdio_interrupt); + sdio_release_host(func); +} + +static void wl1251_sdio_disable_irq(struct wl1251 *wl) +{ + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); +} + void wl1251_sdio_set_power(bool enable) { } @@ -96,6 +119,8 @@ struct wl1251_if_operations wl1251_sdio_ops = { .read = wl1251_sdio_read, .write = wl1251_sdio_write, .reset = wl1251_sdio_reset, + .enable_irq = wl1251_sdio_enable_irq, + .disable_irq = wl1251_sdio_disable_irq, }; int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) @@ -124,21 +149,14 @@ int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) sdio_release_host(func); ret = wl1251_init_ieee80211(wl); - sdio_claim_host(func); if (ret) goto disable; - ret = sdio_claim_irq(func, wl1251_sdio_interrupt); - if (ret) - goto no_irq; - - sdio_release_host(func); sdio_set_drvdata(func, wl); return ret; -no_irq: - wl1251_free_hw(wl); disable: + sdio_claim_host(func); sdio_disable_func(func); release: sdio_release_host(func); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 5967317..7d1031b 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -31,6 +31,19 @@ #include "reg.h" #include "wl1251_spi.h" +static irqreturn_t wl1251_irq(int irq, void *cookie) +{ + struct wl1251 *wl; + + wl1251_debug(DEBUG_IRQ, "IRQ"); + + wl = cookie; + + schedule_work(&wl->irq_work); + + return IRQ_HANDLED; +} + static struct spi_device *wl_to_spi(struct wl1251 *wl) { return wl->if_priv; @@ -193,10 +206,22 @@ static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } +static void wl1251_spi_enable_irq(struct wl1251 *wl) +{ + return enable_irq(wl->irq); +} + +static void wl1251_spi_disable_irq(struct wl1251 *wl) +{ + return disable_irq(wl->irq); +} + static const struct wl1251_if_operations wl1251_spi_ops = { .read = wl1251_spi_read, .write = wl1251_spi_write, .reset = wl1251_spi_reset_wake, + .enable_irq = wl1251_spi_enable_irq, + .disable_irq = wl1251_spi_disable_irq, }; static int __devinit wl1251_spi_probe(struct spi_device *spi) @@ -274,6 +299,7 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi) { struct wl1251 *wl = dev_get_drvdata(&spi->dev); + free_irq(wl->irq, wl); wl1251_free_hw(wl); return 0; -- cgit v0.10.2 From 0e71bb084adc4986b9a4be3581897f0ee703cbd5 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:33:57 +0300 Subject: wl1251: remove wl1251_ops Now wl1271 is splitted to separate files, no need to use wl1251_ops anymore. So remove struct wl1251_chip and wl1251_ops.c. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 207e852..62e37ad 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,7 +1,7 @@ wl1251-objs = wl1251_main.o wl1251_event.o \ wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ wl1251_acx.o wl1251_boot.o wl1251_init.o \ - wl1251_ops.o wl1251_debugfs.o wl1251_io.o + wl1251_debugfs.o wl1251_io.o obj-$(CONFIG_WL1251) += wl1251.o obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 13f0589..44c5001 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -143,35 +143,6 @@ struct wl1251_partition_set { struct wl1251; -/* FIXME: I'm not sure about this structure name */ -struct wl1251_chip { - u32 id; - - const char *fw_filename; - const char *nvs_filename; - - char fw_ver[21]; - - unsigned int power_on_sleep; - int intr_cmd_complete; - int intr_init_complete; - - int (*op_upload_fw)(struct wl1251 *wl); - int (*op_upload_nvs)(struct wl1251 *wl); - int (*op_boot)(struct wl1251 *wl); - void (*op_set_ecpu_ctrl)(struct wl1251 *wl, u32 flag); - void (*op_target_enable_interrupts)(struct wl1251 *wl); - int (*op_hw_init)(struct wl1251 *wl); - int (*op_plt_init)(struct wl1251 *wl); - void (*op_tx_flush)(struct wl1251 *wl); - void (*op_fw_version)(struct wl1251 *wl); - int (*op_cmd_join)(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait); - - struct wl1251_partition_set *p_table; - enum wl12xx_acx_int_reg *acx_reg_table; -}; - struct wl1251_stats { struct acx_statistics *fw_stats; unsigned long fw_stats_update; @@ -307,8 +278,6 @@ struct wl1251 { int virtual_mem_addr; int virtual_reg_addr; - struct wl1251_chip chip; - int cmd_box_addr; int event_box_addr; struct boot_attr boot_attr; @@ -401,6 +370,9 @@ struct wl1251 { u32 buffer_cmd; u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; struct wl1251_rx_descriptor *rx_descriptor; + + u32 chip_id; + char fw_ver[21]; }; int wl1251_plt_start(struct wl1251 *wl); @@ -420,16 +392,25 @@ void wl1251_disable_interrupts(struct wl1251 *wl); #define WL1251_TX_QUEUE_MAX_LENGTH 20 -/* Different chips need different sleep times after power on. WL1271 needs - * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we - * know the chip ID, we change the sleep value in the wl1251 chip structure, - * so in subsequent power ons, we don't waste more time then needed. */ -#define WL1251_DEFAULT_POWER_ON_SLEEP 200 - #define CHIP_ID_1251_PG10 (0x7010101) #define CHIP_ID_1251_PG11 (0x7020101) #define CHIP_ID_1251_PG12 (0x7030101) #define CHIP_ID_1271_PG10 (0x4030101) #define CHIP_ID_1271_PG20 (0x4030111) +#define WL1251_FW_NAME "wl1251-fw.bin" +#define WL1251_NVS_NAME "wl1251-nvs.bin" + +#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ + +#define WL1251_PART_DOWN_MEM_START 0x0 +#define WL1251_PART_DOWN_MEM_SIZE 0x16800 +#define WL1251_PART_DOWN_REG_START REGISTERS_BASE +#define WL1251_PART_DOWN_REG_SIZE REGISTERS_DOWN_SIZE + +#define WL1251_PART_WORK_MEM_START 0x28000 +#define WL1251_PART_WORK_MEM_SIZE 0x14000 +#define WL1251_PART_WORK_REG_START REGISTERS_BASE +#define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE + #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 91fe16c..0a225c6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -837,3 +837,82 @@ int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) return 0; } + +int wl1251_acx_rate_policies(struct wl1251 *wl) +{ + struct acx_rate_policy *acx; + int ret = 0; + + wl1251_debug(DEBUG_ACX, "acx rate policies"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* configure one default (one-size-fits-all) rate class */ + acx->rate_class_cnt = 1; + acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; + acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].aflags = 0; + + ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("Setting of rate policies failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1251_acx_mem_cfg(struct wl1251 *wl) +{ + struct wl1251_acx_config_memory *mem_conf; + int ret, i; + + wl1251_debug(DEBUG_ACX, "acx mem cfg"); + + mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); + if (!mem_conf) { + ret = -ENOMEM; + goto out; + } + + /* memory config */ + mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf->mem_config.rx_mem_block_num = 35; + mem_conf->mem_config.tx_min_mem_block_num = 64; + mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; + mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; + mem_conf->mem_config.num_ssid_profiles = 1; + mem_conf->mem_config.debug_buffer_size = + cpu_to_le16(TRACE_BUFFER_MAX_SIZE); + + /* RX queue config */ + mem_conf->rx_queue_config.dma_address = 0; + mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; + mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; + mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; + + /* TX queue config */ + for (i = 0; i < MAX_TX_QUEUES; i++) { + mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; + mem_conf->tx_queue_config[i].attributes = i; + } + + ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); + if (ret < 0) { + wl1251_warning("wl1251 mem config failed: %d", ret); + goto out; + } + +out: + kfree(mem_conf); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 2e7b193..cafb914 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -1031,6 +1031,150 @@ struct acx_statistics { struct acx_rxpipe_statistics rxpipe; } __attribute__ ((packed)); +#define ACX_MAX_RATE_CLASSES 8 +#define ACX_RATE_MASK_UNSPECIFIED 0 +#define ACX_RATE_RETRY_LIMIT 10 + +struct acx_rate_class { + u32 enabled_rates; + u8 short_retry_limit; + u8 long_retry_limit; + u8 aflags; + u8 reserved; +}; + +struct acx_rate_policy { + struct acx_header header; + + u32 rate_class_cnt; + struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; +} __attribute__ ((packed)); + +struct wl1251_acx_memory { + __le16 num_stations; /* number of STAs to be supported. */ + u16 reserved_1; + + /* + * Nmber of memory buffers for the RX mem pool. + * The actual number may be less if there are + * not enough blocks left for the minimum num + * of TX ones. + */ + u8 rx_mem_block_num; + u8 reserved_2; + u8 num_tx_queues; /* From 1 to 16 */ + u8 host_if_options; /* HOST_IF* */ + u8 tx_min_mem_block_num; + u8 num_ssid_profiles; + __le16 debug_buffer_size; +} __attribute__ ((packed)); + + +#define ACX_RX_DESC_MIN 1 +#define ACX_RX_DESC_MAX 127 +#define ACX_RX_DESC_DEF 32 +struct wl1251_acx_rx_queue_config { + u8 num_descs; + u8 pad; + u8 type; + u8 priority; + __le32 dma_address; +} __attribute__ ((packed)); + +#define ACX_TX_DESC_MIN 1 +#define ACX_TX_DESC_MAX 127 +#define ACX_TX_DESC_DEF 16 +struct wl1251_acx_tx_queue_config { + u8 num_descs; + u8 pad[2]; + u8 attributes; +} __attribute__ ((packed)); + +#define MAX_TX_QUEUE_CONFIGS 5 +#define MAX_TX_QUEUES 4 +struct wl1251_acx_config_memory { + struct acx_header header; + + struct wl1251_acx_memory mem_config; + struct wl1251_acx_rx_queue_config rx_queue_config; + struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; +} __attribute__ ((packed)); + +struct wl1251_acx_mem_map { + struct acx_header header; + + void *code_start; + void *code_end; + + void *wep_defkey_start; + void *wep_defkey_end; + + void *sta_table_start; + void *sta_table_end; + + void *packet_template_start; + void *packet_template_end; + + void *queue_memory_start; + void *queue_memory_end; + + void *packet_memory_pool_start; + void *packet_memory_pool_end; + + void *debug_buffer1_start; + void *debug_buffer1_end; + + void *debug_buffer2_start; + void *debug_buffer2_end; + + /* Number of blocks FW allocated for TX packets */ + u32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + u32 num_rx_mem_blocks; +} __attribute__ ((packed)); + +/************************************************************************* + + Host Interrupt Register (WiLink -> Host) + +**************************************************************************/ + +/* RX packet is ready in Xfer buffer #0 */ +#define WL1251_ACX_INTR_RX0_DATA BIT(0) + +/* TX result(s) are in the TX complete buffer */ +#define WL1251_ACX_INTR_TX_RESULT BIT(1) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_TX_XFR BIT(2) + +/* RX packet is ready in Xfer buffer #1 */ +#define WL1251_ACX_INTR_RX1_DATA BIT(3) + +/* Event was entered to Event MBOX #A */ +#define WL1251_ACX_INTR_EVENT_A BIT(4) + +/* Event was entered to Event MBOX #B */ +#define WL1251_ACX_INTR_EVENT_B BIT(5) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) + +/* Trace meassge on MBOX #A */ +#define WL1251_ACX_INTR_TRACE_A BIT(7) + +/* Trace meassge on MBOX #B */ +#define WL1251_ACX_INTR_TRACE_B BIT(8) + +/* Command processing completion */ +#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) + +/* Init sequence is done */ +#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) + +#define WL1251_ACX_INTR_ALL 0xFFFFFFFF + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -1142,5 +1286,7 @@ int wl1251_acx_cts_protect(struct wl1251 *wl, enum acx_ctsprotect_type ctsprotect); int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); +int wl1251_acx_rate_policies(struct wl1251 *wl); +int wl1251_acx_mem_cfg(struct wl1251 *wl); #endif /* __WL1251_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 8b50d44..88e9cb0 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -28,6 +28,7 @@ #include "wl1251_io.h" #include "wl1251_spi.h" #include "wl1251_event.h" +#include "wl1251_acx.h" void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) { @@ -208,18 +209,30 @@ int wl1251_boot_init_seq(struct wl1251 *wl) return 0; } +static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) +{ + u32 cpu_ctrl; + + /* 10.5.0 run the firmware (I) */ + cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + /* 10.5.1 run the firmware (II) */ + cpu_ctrl &= ~flag; + wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); +} + int wl1251_boot_run_firmware(struct wl1251 *wl) { int loop, ret; u32 chip_id, interrupt; - wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); chip_id = wl1251_reg_read32(wl, CHIP_ID_B); wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); - if (chip_id != wl->chip.id) { + if (chip_id != wl->chip_id) { wl1251_error("chip id doesn't match after firmware boot"); return -EIO; } @@ -236,9 +249,9 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) return -EIO; } /* check that ACX_INTR_INIT_COMPLETE is enabled */ - else if (interrupt & wl->chip.intr_init_complete) { + else if (interrupt & WL1251_ACX_INTR_INIT_COMPLETE) { wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - wl->chip.intr_init_complete); + WL1251_ACX_INTR_INIT_COMPLETE); break; } } @@ -256,16 +269,15 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); /* set the working partition to its "running" mode offset */ - wl1251_set_partition(wl, - wl->chip.p_table[PART_WORK].mem.start, - wl->chip.p_table[PART_WORK].mem.size, - wl->chip.p_table[PART_WORK].reg.start, - wl->chip.p_table[PART_WORK].reg.size); + wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START, + WL1251_PART_WORK_MEM_SIZE, + WL1251_PART_WORK_REG_START, + WL1251_PART_WORK_REG_SIZE); wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", wl->cmd_box_addr, wl->event_box_addr); - wl->chip.op_fw_version(wl); + wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver)); /* * in case of full asynchronous mode the firmware event must be @@ -275,7 +287,14 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) /* enable gpio interrupts */ wl1251_enable_interrupts(wl); - wl->chip.op_target_enable_interrupts(wl); + /* Enable target's interrupts */ + wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | + WL1251_ACX_INTR_RX1_DATA | + WL1251_ACX_INTR_TX_RESULT | + WL1251_ACX_INTR_EVENT_A | + WL1251_ACX_INTR_EVENT_B | + WL1251_ACX_INTR_INIT_COMPLETE; + wl1251_boot_target_enable_interrupts(wl); /* unmask all mbox events */ wl->event_mask = 0xffffffff; @@ -291,3 +310,218 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) /* firmware startup completed */ return 0; } + +static int wl1251_boot_upload_firmware(struct wl1251 *wl) +{ + int addr, chunk_num, partition_limit; + size_t fw_data_len; + u8 *p; + + /* whal_FwCtrl_LoadFwImageSm() */ + + wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", + wl1251_reg_read32(wl, CHIP_ID_B)); + + /* 10.0 check firmware length and set partition */ + fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | + (wl->fw[6] << 8) | (wl->fw[7]); + + wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, + CHUNK_SIZE); + + if ((fw_data_len % 4) != 0) { + wl1251_error("firmware length not multiple of four"); + return -EIO; + } + + wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START, + WL1251_PART_DOWN_MEM_SIZE, + WL1251_PART_DOWN_REG_START, + WL1251_PART_DOWN_REG_SIZE); + + /* 10.1 set partition limit and chunk num */ + chunk_num = 0; + partition_limit = WL1251_PART_DOWN_MEM_SIZE; + + while (chunk_num < fw_data_len / CHUNK_SIZE) { + /* 10.2 update partition, if needed */ + addr = WL1251_PART_DOWN_MEM_START + + (chunk_num + 2) * CHUNK_SIZE; + if (addr > partition_limit) { + addr = WL1251_PART_DOWN_MEM_START + + chunk_num * CHUNK_SIZE; + partition_limit = chunk_num * CHUNK_SIZE + + WL1251_PART_DOWN_MEM_SIZE; + wl1251_set_partition(wl, + addr, + WL1251_PART_DOWN_MEM_SIZE, + WL1251_PART_DOWN_REG_START, + WL1251_PART_DOWN_REG_SIZE); + } + + /* 10.3 upload the chunk */ + addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + p, addr); + wl1251_mem_write(wl, addr, p, CHUNK_SIZE); + + chunk_num++; + } + + /* 10.4 upload the last chunk */ + addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", + fw_data_len % CHUNK_SIZE, p, addr); + wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + + return 0; +} + +static int wl1251_boot_upload_nvs(struct wl1251 *wl) +{ + size_t nvs_len, nvs_bytes_written, burst_len; + int nvs_start, i; + u32 dest_addr, val; + u8 *nvs_ptr, *nvs; + + nvs = wl->nvs; + if (nvs == NULL) + return -ENODEV; + + nvs_ptr = nvs; + + nvs_len = wl->nvs_len; + nvs_start = wl->fw_len; + + /* + * Layout before the actual NVS tables: + * 1 byte : burst length. + * 2 bytes: destination address. + * n bytes: data to burst copy. + * + * This is ended by a 0 length, then the NVS tables. + */ + + while (nvs_ptr[0]) { + burst_len = nvs_ptr[0]; + dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); + + /* We move our pointer to the data */ + nvs_ptr += 3; + + for (i = 0; i < burst_len; i++) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + wl1251_debug(DEBUG_BOOT, + "nvs burst write 0x%x: 0x%x", + dest_addr, val); + wl1251_mem_write32(wl, dest_addr, val); + + nvs_ptr += 4; + dest_addr += 4; + } + } + + /* + * We've reached the first zero length, the first NVS table + * is 7 bytes further. + */ + nvs_ptr += 7; + nvs_len -= nvs_ptr - nvs; + nvs_len = ALIGN(nvs_len, 4); + + /* Now we must set the partition correctly */ + wl1251_set_partition(wl, nvs_start, + WL1251_PART_DOWN_MEM_SIZE, + WL1251_PART_DOWN_REG_START, + WL1251_PART_DOWN_REG_SIZE); + + /* And finally we upload the NVS tables */ + nvs_bytes_written = 0; + while (nvs_bytes_written < nvs_len) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + val = cpu_to_le32(val); + + wl1251_debug(DEBUG_BOOT, + "nvs write table 0x%x: 0x%x", + nvs_start, val); + wl1251_mem_write32(wl, nvs_start, val); + + nvs_ptr += 4; + nvs_bytes_written += 4; + nvs_start += 4; + } + + return 0; +} + +int wl1251_boot(struct wl1251 *wl) +{ + int ret = 0, minor_minor_e2_ver; + u32 tmp, boot_data; + + ret = wl1251_boot_soft_reset(wl); + if (ret < 0) + goto out; + + /* 2. start processing NVS file */ + ret = wl1251_boot_upload_nvs(wl); + if (ret < 0) + goto out; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); + + /* 6. read the EEPROM parameters */ + tmp = wl1251_reg_read32(wl, SCR_PAD2); + + /* 7. read bootdata */ + wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; + wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; + tmp = wl1251_reg_read32(wl, SCR_PAD3); + + /* 8. check bootdata and call restart sequence */ + wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; + minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; + + wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " + "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", + wl->boot_attr.radio_type, wl->boot_attr.major, + wl->boot_attr.minor, minor_minor_e2_ver); + + ret = wl1251_boot_init_seq(wl); + if (ret < 0) + goto out; + + /* 9. NVS processing done */ + boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); + + /* 10. check that ECPU_CONTROL_HALT bits are set in + * pWhalBus->uBootData and start uploading firmware + */ + if ((boot_data & ECPU_CONTROL_HALT) == 0) { + wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); + ret = -EIO; + goto out; + } + + ret = wl1251_boot_upload_firmware(wl); + if (ret < 0) + goto out; + + /* 10.5 start firmware */ + ret = wl1251_boot_run_firmware(wl); + if (ret < 0) + goto out; + +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h index 798362d..9006369 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.h +++ b/drivers/net/wireless/wl12xx/wl1251_boot.h @@ -30,6 +30,7 @@ int wl1251_boot_soft_reset(struct wl1251 *wl); int wl1251_boot_init_seq(struct wl1251 *wl); int wl1251_boot_run_firmware(struct wl1251 *wl); void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); +int wl1251_boot(struct wl1251 *wl); /* number of times we try to read the INIT interrupt */ #define INIT_LOOP 20000 diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index dfbf681..53f5da6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -37,7 +37,7 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - while (!(intr & wl->chip.intr_cmd_complete)) { + while (!(intr & WL1251_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1251_error("command complete timeout"); ret = -ETIMEDOUT; @@ -50,7 +50,7 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) } wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - wl->chip.intr_cmd_complete); + WL1251_ACX_INTR_CMD_COMPLETE); out: return ret; diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index df6c60f..1c587ec 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -28,6 +28,7 @@ #include "wl12xx_80211.h" #include "wl1251_acx.h" #include "wl1251_cmd.h" +#include "reg.h" int wl1251_hw_init_hwenc_config(struct wl1251 *wl) { @@ -198,3 +199,215 @@ int wl1251_hw_init_power_auth(struct wl1251 *wl) { return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); } + +int wl1251_hw_init_mem_config(struct wl1251 *wl) +{ + int ret; + + ret = wl1251_acx_mem_cfg(wl); + if (ret < 0) + return ret; + + wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), + GFP_KERNEL); + if (!wl->target_mem_map) { + wl1251_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = wl1251_acx_mem_map(wl, wl->target_mem_map, + sizeof(struct wl1251_acx_mem_map)); + if (ret < 0) { + wl1251_error("couldn't retrieve firmware memory map"); + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + return ret; + } + + return 0; +} + +static int wl1251_hw_init_txq_fill(u8 qid, + struct acx_tx_queue_qos_config *config, + u32 num_blocks) +{ + config->qid = qid; + + switch (qid) { + case QOS_AC_BE: + config->high_threshold = + (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BE_DEF * num_blocks) / 100; + break; + case QOS_AC_BK: + config->high_threshold = + (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BK_DEF * num_blocks) / 100; + break; + case QOS_AC_VI: + config->high_threshold = + (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VI_DEF * num_blocks) / 100; + break; + case QOS_AC_VO: + config->high_threshold = + (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VO_DEF * num_blocks) / 100; + break; + default: + wl1251_error("Invalid TX queue id: %d", qid); + return -EINVAL; + } + + return 0; +} + +static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) +{ + struct acx_tx_queue_qos_config *config; + struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; + int ret, i; + + wl1251_debug(DEBUG_ACX, "acx tx queue config"); + + config = kzalloc(sizeof(*config), GFP_KERNEL); + if (!config) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < MAX_NUM_OF_AC; i++) { + ret = wl1251_hw_init_txq_fill(i, config, + wl_mem_map->num_tx_mem_blocks); + if (ret < 0) + goto out; + + ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, + config, sizeof(*config)); + if (ret < 0) + goto out; + } + +out: + kfree(config); + return ret; +} + +static int wl1251_hw_init_data_path_config(struct wl1251 *wl) +{ + int ret; + + /* asking for the data path parameters */ + wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), + GFP_KERNEL); + if (!wl->data_path) { + wl1251_error("Couldnt allocate data path parameters"); + return -ENOMEM; + } + + ret = wl1251_acx_data_path_params(wl, wl->data_path); + if (ret < 0) { + kfree(wl->data_path); + wl->data_path = NULL; + return ret; + } + + return 0; +} + + +int wl1251_hw_init(struct wl1251 *wl) +{ + struct wl1251_acx_mem_map *wl_mem_map; + int ret; + + ret = wl1251_hw_init_hwenc_config(wl); + if (ret < 0) + return ret; + + /* Template settings */ + ret = wl1251_hw_init_templates_config(wl); + if (ret < 0) + return ret; + + /* Default memory configuration */ + ret = wl1251_hw_init_mem_config(wl); + if (ret < 0) + return ret; + + /* Default data path configuration */ + ret = wl1251_hw_init_data_path_config(wl); + if (ret < 0) + goto out_free_memmap; + + /* RX config */ + ret = wl1251_hw_init_rx_config(wl, + RX_CFG_PROMISCUOUS | RX_CFG_TSF, + RX_FILTER_OPTION_DEF); + /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, + RX_FILTER_OPTION_FILTER_ALL); */ + if (ret < 0) + goto out_free_data_path; + + /* TX queues config */ + ret = wl1251_hw_init_tx_queue_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* PHY layer config */ + ret = wl1251_hw_init_phy_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacon filtering */ + ret = wl1251_hw_init_beacon_filter(wl); + if (ret < 0) + goto out_free_data_path; + + /* Bluetooth WLAN coexistence */ + ret = wl1251_hw_init_pta(wl); + if (ret < 0) + goto out_free_data_path; + + /* Energy detection */ + ret = wl1251_hw_init_energy_detection(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacons and boradcast settings */ + ret = wl1251_hw_init_beacon_broadcast(wl); + if (ret < 0) + goto out_free_data_path; + + /* Enable data path */ + ret = wl1251_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + goto out_free_data_path; + + /* Default power state */ + ret = wl1251_hw_init_power_auth(wl); + if (ret < 0) + goto out_free_data_path; + + wl_mem_map = wl->target_mem_map; + wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", + wl_mem_map->num_tx_mem_blocks, + wl->data_path->tx_control_addr, + wl_mem_map->num_rx_mem_blocks, + wl->data_path->rx_control_addr); + + return 0; + + out_free_data_path: + kfree(wl->data_path); + + out_free_memmap: + kfree(wl->target_mem_map); + + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index 8596188..b3b25ec 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -35,5 +35,7 @@ int wl1251_hw_init_pta(struct wl1251 *wl); int wl1251_hw_init_energy_detection(struct wl1251 *wl); int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); int wl1251_hw_init_power_auth(struct wl1251 *wl); +int wl1251_hw_init_mem_config(struct wl1251 *wl); +int wl1251_hw_init(struct wl1251 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c index db2cfbf..04e486c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.c +++ b/drivers/net/wireless/wl12xx/wl1251_io.c @@ -25,6 +25,21 @@ #include "reg.h" #include "wl1251_io.h" +/* FIXME: this is static data nowadays and the table can be removed */ +static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { + [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), + [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), + [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), + [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), + [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), + [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), + [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), + [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), + [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), + [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), + [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) +}; + static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) { /* If the address is lower than REGISTERS_BASE, it means that this is @@ -36,7 +51,7 @@ static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) wl1251_error("address out of range (%d)", addr); return -EINVAL; } - addr = wl->chip.acx_reg_table[addr]; + addr = wl1251_io_reg_table[addr]; } return addr - wl->physical_reg_addr + wl->virtual_reg_addr; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 4c1aad3..8c88fe2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -32,7 +32,6 @@ #include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" -#include "wl1251_ops.h" #include "wl1251_io.h" #include "wl1251_cmd.h" #include "wl1251_event.h" @@ -41,6 +40,7 @@ #include "wl1251_ps.h" #include "wl1251_init.h" #include "wl1251_debugfs.h" +#include "wl1251_boot.h" void wl1251_enable_interrupts(struct wl1251 *wl) { @@ -68,7 +68,7 @@ static int wl1251_fetch_firmware(struct wl1251 *wl) struct device *dev = wiphy_dev(wl->hw->wiphy); int ret; - ret = request_firmware(&fw, wl->chip.fw_filename, dev); + ret = request_firmware(&fw, WL1251_FW_NAME, dev); if (ret < 0) { wl1251_error("could not get firmware: %d", ret); @@ -107,7 +107,7 @@ static int wl1251_fetch_nvs(struct wl1251 *wl) struct device *dev = wiphy_dev(wl->hw->wiphy); int ret; - ret = request_firmware(&fw, wl->chip.nvs_filename, dev); + ret = request_firmware(&fw, WL1251_NVS_NAME, dev); if (ret < 0) { wl1251_error("could not get nvs file: %d", ret); @@ -157,7 +157,7 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) int ret = 0; wl1251_power_on(wl); - msleep(wl->chip.power_on_sleep); + msleep(WL1251_POWER_ON_SLEEP); wl->if_ops->reset(wl); /* We don't need a real memory partition here, because we only want @@ -174,22 +174,19 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) /* whal_FwCtrl_BootSm() */ /* 0. read chip id from CHIP_ID */ - wl->chip.id = wl1251_reg_read32(wl, CHIP_ID_B); + wl->chip_id = wl1251_reg_read32(wl, CHIP_ID_B); /* 1. check if chip id is valid */ - switch (wl->chip.id) { + switch (wl->chip_id) { case CHIP_ID_1251_PG12: wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", - wl->chip.id); - - wl1251_setup(wl); - + wl->chip_id); break; case CHIP_ID_1251_PG10: case CHIP_ID_1251_PG11: default: - wl1251_error("unsupported chip id: 0x%x", wl->chip.id); + wl1251_error("unsupported chip id: 0x%x", wl->chip_id); ret = -ENODEV; goto out; } @@ -211,6 +208,107 @@ out: return ret; } +static void wl1251_irq_work(struct work_struct *work) +{ + u32 intr; + struct wl1251 *wl = + container_of(work, struct wl1251, irq_work); + int ret; + + mutex_lock(&wl->mutex); + + wl1251_debug(DEBUG_IRQ, "IRQ work"); + + if (wl->state == WL1251_STATE_OFF) + goto out; + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); + + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); + + if (wl->data_path) { + wl->rx_counter = + wl1251_mem_read32(wl, wl->data_path->rx_control_addr); + + /* We handle a frmware bug here */ + switch ((wl->rx_counter - wl->rx_handled) & 0xf) { + case 0: + wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); + intr &= ~WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 1: + wl1251_debug(DEBUG_IRQ, "RX: FW +1"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 2: + wl1251_debug(DEBUG_IRQ, "RX: FW +2"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr |= WL1251_ACX_INTR_RX1_DATA; + break; + default: + wl1251_warning("RX: FW and host out of sync: %d", + wl->rx_counter - wl->rx_handled); + break; + } + + wl->rx_handled = wl->rx_counter; + + + wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); + } + + intr &= wl->intr_mask; + + if (intr == 0) { + wl1251_debug(DEBUG_IRQ, "INTR is 0"); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + ~(wl->intr_mask)); + + goto out_sleep; + } + + if (intr & WL1251_ACX_INTR_RX0_DATA) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); + wl1251_rx(wl); + } + + if (intr & WL1251_ACX_INTR_RX1_DATA) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); + wl1251_rx(wl); + } + + if (intr & WL1251_ACX_INTR_TX_RESULT) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); + wl1251_tx_complete(wl); + } + + if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); + if (intr & WL1251_ACX_INTR_EVENT_A) + wl1251_event_handle(wl, 0); + else + wl1251_event_handle(wl, 1); + } + + if (intr & WL1251_ACX_INTR_INIT_COMPLETE) + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); + + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + +out_sleep: + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + static void wl1251_filter_work(struct work_struct *work) { struct wl1251 *wl = @@ -227,7 +325,7 @@ static void wl1251_filter_work(struct work_struct *work) goto out; /* FIXME: replace the magic numbers with proper definitions */ - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out_sleep; @@ -289,11 +387,11 @@ static int wl1251_op_start(struct ieee80211_hw *hw) if (ret < 0) goto out; - ret = wl->chip.op_boot(wl); + ret = wl1251_boot(wl); if (ret < 0) goto out; - ret = wl->chip.op_hw_init(wl); + ret = wl1251_hw_init(wl); if (ret < 0) goto out; @@ -303,7 +401,7 @@ static int wl1251_op_start(struct ieee80211_hw *hw) wl->state = WL1251_STATE_ON; - wl1251_info("firmware booted (%s)", wl->chip.fw_ver); + wl1251_info("firmware booted (%s)", wl->fw_ver); out: if (ret < 0) @@ -346,7 +444,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) mutex_lock(&wl->mutex); /* let's notify MAC80211 about the remaining pending TX frames */ - wl->chip.op_tx_flush(wl); + wl1251_tx_flush(wl); wl1251_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); @@ -467,7 +565,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) if (channel != wl->channel) { /* FIXME: use beacon interval provided by mac80211 */ - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out_sleep; @@ -1041,7 +1139,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out; @@ -1232,15 +1330,14 @@ struct ieee80211_hw *wl1251_alloc_hw(void) wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; - /* We use the default power on sleep time until we know which chip - * we're using */ - wl->chip.power_on_sleep = WL1251_DEFAULT_POWER_ON_SLEEP; - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) wl->tx_frames[i] = NULL; wl->next_tx_complete = 0; + INIT_WORK(&wl->irq_work, wl1251_irq_work); + INIT_WORK(&wl->tx_work, wl1251_tx_work); + /* * In case our MAC address is not correctly set, * we use a random but Nokia MAC. diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h deleted file mode 100644 index 68183c4..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_ops.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_OPS_H__ -#define __WL1251_OPS_H__ - -#include - -#include "wl1251.h" -#include "wl1251_acx.h" - -#define WL1251_FW_NAME "wl1251-fw.bin" -#define WL1251_NVS_NAME "wl1251-nvs.bin" - -#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ - -void wl1251_setup(struct wl1251 *wl); - - -struct wl1251_acx_memory { - __le16 num_stations; /* number of STAs to be supported. */ - u16 reserved_1; - - /* - * Nmber of memory buffers for the RX mem pool. - * The actual number may be less if there are - * not enough blocks left for the minimum num - * of TX ones. - */ - u8 rx_mem_block_num; - u8 reserved_2; - u8 num_tx_queues; /* From 1 to 16 */ - u8 host_if_options; /* HOST_IF* */ - u8 tx_min_mem_block_num; - u8 num_ssid_profiles; - __le16 debug_buffer_size; -} __attribute__ ((packed)); - - -#define ACX_RX_DESC_MIN 1 -#define ACX_RX_DESC_MAX 127 -#define ACX_RX_DESC_DEF 32 -struct wl1251_acx_rx_queue_config { - u8 num_descs; - u8 pad; - u8 type; - u8 priority; - __le32 dma_address; -} __attribute__ ((packed)); - -#define ACX_TX_DESC_MIN 1 -#define ACX_TX_DESC_MAX 127 -#define ACX_TX_DESC_DEF 16 -struct wl1251_acx_tx_queue_config { - u8 num_descs; - u8 pad[2]; - u8 attributes; -} __attribute__ ((packed)); - -#define MAX_TX_QUEUE_CONFIGS 5 -#define MAX_TX_QUEUES 4 -struct wl1251_acx_config_memory { - struct acx_header header; - - struct wl1251_acx_memory mem_config; - struct wl1251_acx_rx_queue_config rx_queue_config; - struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; -} __attribute__ ((packed)); - -struct wl1251_acx_mem_map { - struct acx_header header; - - void *code_start; - void *code_end; - - void *wep_defkey_start; - void *wep_defkey_end; - - void *sta_table_start; - void *sta_table_end; - - void *packet_template_start; - void *packet_template_end; - - void *queue_memory_start; - void *queue_memory_end; - - void *packet_memory_pool_start; - void *packet_memory_pool_end; - - void *debug_buffer1_start; - void *debug_buffer1_end; - - void *debug_buffer2_start; - void *debug_buffer2_end; - - /* Number of blocks FW allocated for TX packets */ - u32 num_tx_mem_blocks; - - /* Number of blocks FW allocated for RX packets */ - u32 num_rx_mem_blocks; -} __attribute__ ((packed)); - -/************************************************************************* - - Host Interrupt Register (WiLink -> Host) - -**************************************************************************/ - -/* RX packet is ready in Xfer buffer #0 */ -#define WL1251_ACX_INTR_RX0_DATA BIT(0) - -/* TX result(s) are in the TX complete buffer */ -#define WL1251_ACX_INTR_TX_RESULT BIT(1) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_TX_XFR BIT(2) - -/* RX packet is ready in Xfer buffer #1 */ -#define WL1251_ACX_INTR_RX1_DATA BIT(3) - -/* Event was entered to Event MBOX #A */ -#define WL1251_ACX_INTR_EVENT_A BIT(4) - -/* Event was entered to Event MBOX #B */ -#define WL1251_ACX_INTR_EVENT_B BIT(5) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) - -/* Trace meassge on MBOX #A */ -#define WL1251_ACX_INTR_TRACE_A BIT(7) - -/* Trace meassge on MBOX #B */ -#define WL1251_ACX_INTR_TRACE_B BIT(8) - -/* Command processing completion */ -#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) - -/* Init sequence is done */ -#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) - -#define WL1251_ACX_INTR_ALL 0xFFFFFFFF - -#endif -- cgit v0.10.2 From 46e947b9c382f67f84cffec3bf068d6d23695058 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:05 +0300 Subject: wl1251: reorder wl1251_cmd_join() arguments It's more common to have beacon interval before dtim period. Also use bool instead of u8. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 53f5da6..50daa9b 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -251,8 +251,8 @@ out: return ret; } -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait) +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, + u8 dtim_interval, bool wait) { unsigned long timeout; struct cmd_join *join; diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index 64f228d..f9177d6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -36,8 +36,8 @@ int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait); +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, + u8 dtim_interval, bool wait); int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 8c88fe2..47b82fa 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -325,7 +325,7 @@ static void wl1251_filter_work(struct work_struct *work) goto out; /* FIXME: replace the magic numbers with proper definitions */ - ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); if (ret < 0) goto out_sleep; @@ -565,7 +565,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) if (channel != wl->channel) { /* FIXME: use beacon interval provided by mac80211 */ - ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); if (ret < 0) goto out_sleep; @@ -1113,7 +1113,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl1251_cmd_join(wl, wl->bss_type, 5, 100, 1); + ret = wl1251_cmd_join(wl, wl->bss_type, 100, 5, true); if (ret < 0) goto out_sleep; wl1251_warning("Set ctsprotect failed %d", ret); @@ -1139,7 +1139,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); if (ret < 0) goto out; -- cgit v0.10.2 From e2fd4611d50a1cd13a370f84b672a5f29472ee09 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:12 +0300 Subject: wl1251: use beacon interval and dtim period provided by mac80211 wl1251 was using hardcoded beacon intervals and dtim periods, use the ones provided by mac80211 instead. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 44c5001..86d2abe 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -360,6 +360,9 @@ struct wl1251 { /* PSM mode requested */ bool psm_requested; + u16 beacon_int; + u8 dtim_period; + /* in dBm */ int power_level; @@ -392,6 +395,9 @@ void wl1251_disable_interrupts(struct wl1251 *wl); #define WL1251_TX_QUEUE_MAX_LENGTH 20 +#define WL1251_DEFAULT_BEACON_INT 100 +#define WL1251_DEFAULT_DTIM_PERIOD 1 + #define CHIP_ID_1251_PG10 (0x7010101) #define CHIP_ID_1251_PG11 (0x7020101) #define CHIP_ID_1251_PG12 (0x7030101) diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 50daa9b..9cd46ce 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -273,7 +273,10 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, if (ret < 0) goto out; - wl1251_debug(DEBUG_CMD, "cmd join"); + wl1251_debug(DEBUG_CMD, "cmd join%s %d %d%s", + bss_type == BSS_TYPE_IBSS ? " ibss" : "", + beacon_interval, dtim_interval, + wait ? " wait" : ""); /* Reverse order BSSID */ bssid = (u8 *) &join->bssid_lsb; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 47b82fa..7014233 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -324,8 +324,8 @@ static void wl1251_filter_work(struct work_struct *work) if (ret < 0) goto out; - /* FIXME: replace the magic numbers with proper definitions */ - ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); + ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, + wl->dtim_period, false); if (ret < 0) goto out_sleep; @@ -564,8 +564,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) goto out; if (channel != wl->channel) { - /* FIXME: use beacon interval provided by mac80211 */ - ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); + ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, + wl->dtim_period, false); if (ret < 0) goto out_sleep; @@ -1057,6 +1057,11 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { + wl->beacon_int = bss_conf->beacon_int; + wl->dtim_period = bss_conf->dtim_period; + + /* FIXME: call join */ + wl->aid = bss_conf->aid; ret = wl1251_build_ps_poll(wl, wl->aid); @@ -1074,6 +1079,10 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; } + } else { + /* use defaults when not associated */ + wl->beacon_int = WL1251_DEFAULT_BEACON_INT; + wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; } } if (changed & BSS_CHANGED_ERP_SLOT) { @@ -1113,7 +1122,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl1251_cmd_join(wl, wl->bss_type, 100, 5, true); + ret = wl1251_cmd_join(wl, wl->bss_type, + wl->beacon_int, + wl->dtim_period, true); if (ret < 0) goto out_sleep; wl1251_warning("Set ctsprotect failed %d", ret); @@ -1139,7 +1150,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); + ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, + wl->dtim_period, false); if (ret < 0) goto out; @@ -1329,6 +1341,8 @@ struct ieee80211_hw *wl1251_alloc_hw(void) wl->psm_requested = false; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; + wl->beacon_int = WL1251_DEFAULT_BEACON_INT; + wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) wl->tx_frames[i] = NULL; -- cgit v0.10.2 From 7a33732fd9f2181bfe639691ead3def7a1e87c7d Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:19 +0300 Subject: wl1251: remove wait parameter from wl1251_cmd_join() We should wait everytime for the join command to finish, not waiting for it might create problems. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 9cd46ce..e276cb5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -252,7 +252,7 @@ out: } int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, - u8 dtim_interval, bool wait) + u8 dtim_interval) { unsigned long timeout; struct cmd_join *join; @@ -273,10 +273,9 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, if (ret < 0) goto out; - wl1251_debug(DEBUG_CMD, "cmd join%s %d %d%s", + wl1251_debug(DEBUG_CMD, "cmd join%s %d %d", bss_type == BSS_TYPE_IBSS ? " ibss" : "", - beacon_interval, dtim_interval, - wait ? " wait" : ""); + beacon_interval, dtim_interval); /* Reverse order BSSID */ bssid = (u8 *) &join->bssid_lsb; @@ -307,8 +306,7 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to * simplify locking we just sleep instead, for now */ - if (wait) - msleep(10); + msleep(10); out: kfree(join); diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index f9177d6..ffeabf2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -37,7 +37,7 @@ int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, - u8 dtim_interval, bool wait); + u8 dtim_interval); int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 7014233..d031692 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -325,7 +325,7 @@ static void wl1251_filter_work(struct work_struct *work) goto out; ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period, false); + wl->dtim_period); if (ret < 0) goto out_sleep; @@ -565,7 +565,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) if (channel != wl->channel) { ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period, false); + wl->dtim_period); if (ret < 0) goto out_sleep; @@ -1124,7 +1124,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (wl->bss_type != BSS_TYPE_IBSS) { ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period, true); + wl->dtim_period); if (ret < 0) goto out_sleep; wl1251_warning("Set ctsprotect failed %d", ret); @@ -1151,7 +1151,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period, false); + wl->dtim_period); if (ret < 0) goto out; -- cgit v0.10.2 From 9780279c60c32cb5f14531aa34ae991bb714c90c Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:27 +0300 Subject: wl1251: initialise default channel to zero Because wl->channel was initialised to one, the first join command in wl1251_op_config() always failed. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 86d2abe..998e4b6 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -398,6 +398,8 @@ void wl1251_disable_interrupts(struct wl1251 *wl); #define WL1251_DEFAULT_BEACON_INT 100 #define WL1251_DEFAULT_DTIM_PERIOD 1 +#define WL1251_DEFAULT_CHANNEL 0 + #define CHIP_ID_1251_PG10 (0x7010101) #define CHIP_ID_1251_PG11 (0x7020101) #define CHIP_ID_1251_PG12 (0x7030101) diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index d031692..2514c94 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -461,6 +461,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) wl->psm = 0; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; + wl->channel = WL1251_DEFAULT_CHANNEL; wl1251_debugfs_reset(wl); @@ -1302,7 +1303,6 @@ out: } EXPORT_SYMBOL_GPL(wl1251_init_ieee80211); -#define WL1251_DEFAULT_CHANNEL 1 struct ieee80211_hw *wl1251_alloc_hw(void) { struct ieee80211_hw *hw; -- cgit v0.10.2 From c88f87540fa4b90a0b8696dae8bce801ecc142d3 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:34 +0300 Subject: wl1251: add channel to wl1251_cmd_join() parameters Because join channel tunes to a channel, better to make it more obvious by adding a parameter for it. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index e276cb5..4e796db 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -251,8 +251,8 @@ out: return ret; } -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, - u8 dtim_interval) +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, + u16 beacon_interval, u8 dtim_interval) { unsigned long timeout; struct cmd_join *join; @@ -273,9 +273,9 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, if (ret < 0) goto out; - wl1251_debug(DEBUG_CMD, "cmd join%s %d %d", + wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", bss_type == BSS_TYPE_IBSS ? " ibss" : "", - beacon_interval, dtim_interval); + channel, beacon_interval, dtim_interval); /* Reverse order BSSID */ bssid = (u8 *) &join->bssid_lsb; @@ -291,7 +291,7 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, join->beacon_interval = beacon_interval; join->dtim_interval = dtim_interval; join->bss_type = bss_type; - join->channel = wl->channel; + join->channel = channel; join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index ffeabf2..dff798ad 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -36,8 +36,8 @@ int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, - u8 dtim_interval); +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, + u16 beacon_interval, u8 dtim_interval); int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 2514c94..5e90459 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -324,7 +324,7 @@ static void wl1251_filter_work(struct work_struct *work) if (ret < 0) goto out; - ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, + ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, wl->beacon_int, wl->dtim_period); if (ret < 0) goto out_sleep; @@ -565,8 +565,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) goto out; if (channel != wl->channel) { - ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period); + ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); if (ret < 0) goto out_sleep; @@ -1123,7 +1123,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl1251_cmd_join(wl, wl->bss_type, + ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, wl->beacon_int, wl->dtim_period); if (ret < 0) @@ -1152,7 +1152,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period); + wl->channel, wl->dtim_period); if (ret < 0) goto out; -- cgit v0.10.2 From ae46ae17d1d8b953eb5859764737c065e4e3c86b Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:42 +0300 Subject: wl1251: create wl1251_join() Better to use wl1251_cmd_join() only for sending the command and move the logic to wl1251_join(). Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 4e796db..d7800a3 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -254,7 +254,6 @@ out: int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, u16 beacon_interval, u8 dtim_interval) { - unsigned long timeout; struct cmd_join *join; int ret, i; u8 *bssid; @@ -265,14 +264,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, goto out; } - /* FIXME: this should be in main.c */ - ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, - DEFAULT_HW_GEN_MODULATION_TYPE, - wl->tx_mgmt_frm_rate, - wl->tx_mgmt_frm_mod); - if (ret < 0) - goto out; - wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", bss_type == BSS_TYPE_IBSS ? " ibss" : "", channel, beacon_interval, dtim_interval); @@ -300,14 +291,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, goto out; } - timeout = msecs_to_jiffies(JOIN_TIMEOUT); - - /* - * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to - * simplify locking we just sleep instead, for now - */ - msleep(10); - out: kfree(join); return ret; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 5e90459..e575b78 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -309,6 +309,34 @@ out: mutex_unlock(&wl->mutex); } +static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, + u16 beacon_interval, u8 dtim_period) +{ + int ret; + + ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, + DEFAULT_HW_GEN_MODULATION_TYPE, + wl->tx_mgmt_frm_rate, + wl->tx_mgmt_frm_mod); + if (ret < 0) + goto out; + + + ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval, + dtim_period); + if (ret < 0) + goto out; + + /* + * FIXME: we should wait for JOIN_EVENT_COMPLETE_ID but to simplify + * locking we just sleep instead, for now + */ + msleep(10); + +out: + return ret; +} + static void wl1251_filter_work(struct work_struct *work) { struct wl1251 *wl = @@ -324,8 +352,8 @@ static void wl1251_filter_work(struct work_struct *work) if (ret < 0) goto out; - ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, wl->beacon_int, - wl->dtim_period); + ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, + wl->dtim_period); if (ret < 0) goto out_sleep; @@ -565,8 +593,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) goto out; if (channel != wl->channel) { - ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, - wl->beacon_int, wl->dtim_period); + ret = wl1251_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); if (ret < 0) goto out_sleep; @@ -1123,9 +1151,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, - wl->beacon_int, - wl->dtim_period); + ret = wl1251_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); if (ret < 0) goto out_sleep; wl1251_warning("Set ctsprotect failed %d", ret); @@ -1151,8 +1178,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->channel, wl->dtim_period); + ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, + wl->channel, wl->dtim_period); if (ret < 0) goto out; -- cgit v0.10.2 From fe9a98460b6c8dac47d0e34bcb04850193d41565 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:49 +0300 Subject: wl1251: fix channel setting in wl1251_op_config() There is a bug in wl1251_op_config(). It was calling join with previous channel. Fix it by setting assigning wl->channel before calling join command. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index e575b78..568b640 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -593,12 +593,12 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) goto out; if (channel != wl->channel) { + wl->channel = channel; + ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, wl->dtim_period); if (ret < 0) goto out_sleep; - - wl->channel = channel; } ret = wl1251_build_null_data(wl); -- cgit v0.10.2 From 4a8189227fc4718a767ffca74d13a7d552e42189 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:56 +0300 Subject: wl1251: move wl1251_acx_wake_up_conditions() to wl1251_ps_set_mode() It should not be hidden inside wl1251_cmd_ps_mode(). Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index d7800a3..74ea1fd 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -301,14 +301,6 @@ int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode) struct wl1251_cmd_ps_params *ps_params = NULL; int ret = 0; - /* FIXME: this should be in ps.c */ - ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, - wl->listen_int); - if (ret < 0) { - wl1251_error("couldn't set wake up conditions"); - goto out; - } - wl1251_debug(DEBUG_CMD, "cmd set ps mode"); ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 0581677..36acde0 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -118,6 +118,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) switch (mode) { case STATION_POWER_SAVE_MODE: wl1251_debug(DEBUG_PSM, "entering psm"); + + ret = wl1251_acx_wake_up_conditions(wl, + WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); + if (ret < 0) + return ret; + ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); if (ret < 0) return ret; @@ -135,6 +142,12 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) if (ret < 0) return ret; + ret = wl1251_acx_wake_up_conditions(wl, + WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); + if (ret < 0) + return ret; + ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; -- cgit v0.10.2 From 16e711f9ed16e32126270652d79225836a7062cb Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:35:04 +0300 Subject: wl1251: use workqueue provided by mac80211 wl1251 should use workqueue created by mac80211 to not block the events workqueue too long. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 568b640..c5f2d9d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -375,7 +375,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * before that, the tx_work will not be initialized! */ - schedule_work(&wl->tx_work); + ieee80211_queue_work(wl->hw, &wl->tx_work); /* * The workqueue is slow to process the tx_queue and we need stop diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index f7e451f..20668e2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c @@ -55,7 +55,7 @@ static void wl1251_sdio_interrupt(struct sdio_func *func) wl1251_debug(DEBUG_IRQ, "IRQ"); /* FIXME should be synchronous for sdio */ - schedule_work(&wl->irq_work); + ieee80211_queue_work(wl->hw, &wl->irq_work); } static const struct sdio_device_id wl1251_devices[] = { diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 7d1031b..e088334 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -39,7 +39,7 @@ static irqreturn_t wl1251_irq(int irq, void *cookie) wl = cookie; - schedule_work(&wl->irq_work); + ieee80211_queue_work(wl->hw, &wl->irq_work); return IRQ_HANDLED; } -- cgit v0.10.2 From 29d904c452d466fbf51b2fde10f405b5c8f14c74 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:35:11 +0300 Subject: wl1251: rename reg.h to wl1251_reg.h Now that wl1271 doesn't use reg.h anymore, it can be renamed to wl1251_reg.h. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h deleted file mode 100644 index 2de47cc..0000000 --- a/drivers/net/wireless/wl12xx/reg.h +++ /dev/null @@ -1,744 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __REG_H__ -#define __REG_H__ - -#include - -#define REGISTERS_BASE 0x00300000 -#define DRPW_BASE 0x00310000 - -#define REGISTERS_DOWN_SIZE 0x00008800 -#define REGISTERS_WORK_SIZE 0x0000b000 - -#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC - -/* ELP register commands */ -#define ELPCTRL_WAKE_UP 0x1 -#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 -#define ELPCTRL_SLEEP 0x0 -/* ELP WLAN_READY bit */ -#define ELPCTRL_WLAN_READY 0x2 - -/* - * Interrupt registers. - * 64 bit interrupt sources registers ws ced. - * sme interupts were removed and new ones were added. - * Order was changed. - */ -#define FIQ_MASK (REGISTERS_BASE + 0x0400) -#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) -#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) -#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) -#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) -#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) -#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) -#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) -#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) -#define IRQ_MASK (REGISTERS_BASE + 0x0418) -#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) -#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) -#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) -#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) -#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) -#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) -#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) -#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) -#define ECPU_MASK (REGISTERS_BASE + 0x0448) -#define FIQ_STS_L (REGISTERS_BASE + 0x044C) -#define FIQ_STS_H (REGISTERS_BASE + 0x0450) -#define IRQ_STS_L (REGISTERS_BASE + 0x0454) -#define IRQ_STS_H (REGISTERS_BASE + 0x0458) -#define INT_STS_ND (REGISTERS_BASE + 0x0464) -#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) -#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) -#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) -#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) -#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) -#define INT_ACK (REGISTERS_BASE + 0x046C) -#define INT_ACK_L (REGISTERS_BASE + 0x046C) -#define INT_ACK_H (REGISTERS_BASE + 0x0470) -#define INT_TRIG (REGISTERS_BASE + 0x0474) -#define INT_TRIG_L (REGISTERS_BASE + 0x0474) -#define INT_TRIG_H (REGISTERS_BASE + 0x0478) -#define HOST_STS_L (REGISTERS_BASE + 0x045C) -#define HOST_STS_H (REGISTERS_BASE + 0x0460) -#define HOST_MASK (REGISTERS_BASE + 0x0430) -#define HOST_MASK_L (REGISTERS_BASE + 0x0430) -#define HOST_MASK_H (REGISTERS_BASE + 0x0434) -#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) -#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) -#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) -#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) -#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) -#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) - -/* Host Interrupts*/ -#define HINT_MASK (REGISTERS_BASE + 0x0494) -#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) -#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) -#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) -/*1150 spec calls this HINT_STS_RAW*/ -#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) -#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) -#define HINT_ACK (REGISTERS_BASE + 0x04A8) -#define HINT_TRIG (REGISTERS_BASE + 0x04AC) - -/* Device Configuration registers*/ -#define SOR_CFG (REGISTERS_BASE + 0x0800) -#define ECPU_CTRL (REGISTERS_BASE + 0x0804) -#define HI_CFG (REGISTERS_BASE + 0x0808) -#define EE_START (REGISTERS_BASE + 0x080C) - -#define CHIP_ID_B (REGISTERS_BASE + 0x5674) - -#define CHIP_ID_1251_PG10 (0x7010101) -#define CHIP_ID_1251_PG11 (0x7020101) -#define CHIP_ID_1251_PG12 (0x7030101) - -#define ENABLE (REGISTERS_BASE + 0x5450) - -/* Power Management registers */ -#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) -#define ELP_CMD (REGISTERS_BASE + 0x5808) -#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) -#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) -#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) - -#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) - -/* Scratch Pad registers*/ -#define SCR_PAD0 (REGISTERS_BASE + 0x5608) -#define SCR_PAD1 (REGISTERS_BASE + 0x560C) -#define SCR_PAD2 (REGISTERS_BASE + 0x5610) -#define SCR_PAD3 (REGISTERS_BASE + 0x5614) -#define SCR_PAD4 (REGISTERS_BASE + 0x5618) -#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) -#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) -#define SCR_PAD5 (REGISTERS_BASE + 0x5624) -#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) -#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) -#define SCR_PAD6 (REGISTERS_BASE + 0x5630) -#define SCR_PAD7 (REGISTERS_BASE + 0x5634) -#define SCR_PAD8 (REGISTERS_BASE + 0x5638) -#define SCR_PAD9 (REGISTERS_BASE + 0x563C) - -/* Spare registers*/ -#define SPARE_A1 (REGISTERS_BASE + 0x0994) -#define SPARE_A2 (REGISTERS_BASE + 0x0998) -#define SPARE_A3 (REGISTERS_BASE + 0x099C) -#define SPARE_A4 (REGISTERS_BASE + 0x09A0) -#define SPARE_A5 (REGISTERS_BASE + 0x09A4) -#define SPARE_A6 (REGISTERS_BASE + 0x09A8) -#define SPARE_A7 (REGISTERS_BASE + 0x09AC) -#define SPARE_A8 (REGISTERS_BASE + 0x09B0) -#define SPARE_B1 (REGISTERS_BASE + 0x5420) -#define SPARE_B2 (REGISTERS_BASE + 0x5424) -#define SPARE_B3 (REGISTERS_BASE + 0x5428) -#define SPARE_B4 (REGISTERS_BASE + 0x542C) -#define SPARE_B5 (REGISTERS_BASE + 0x5430) -#define SPARE_B6 (REGISTERS_BASE + 0x5434) -#define SPARE_B7 (REGISTERS_BASE + 0x5438) -#define SPARE_B8 (REGISTERS_BASE + 0x543C) - -enum wl12xx_acx_int_reg { - ACX_REG_INTERRUPT_TRIG, - ACX_REG_INTERRUPT_TRIG_H, - -/*============================================= - Host Interrupt Mask Register - 32bit (RW) - ------------------------------------------ - Setting a bit in this register masks the - corresponding interrupt to the host. - 0 - RX0 - Rx first dubble buffer Data Interrupt - 1 - TXD - Tx Data Interrupt - 2 - TXXFR - Tx Transfer Interrupt - 3 - RX1 - Rx second dubble buffer Data Interrupt - 4 - RXXFR - Rx Transfer Interrupt - 5 - EVENT_A - Event Mailbox interrupt - 6 - EVENT_B - Event Mailbox interrupt - 7 - WNONHST - Wake On Host Interrupt - 8 - TRACE_A - Debug Trace interrupt - 9 - TRACE_B - Debug Trace interrupt - 10 - CDCMP - Command Complete Interrupt - 11 - - 12 - - 13 - - 14 - ICOMP - Initialization Complete Interrupt - 16 - SG SE - Soft Gemini - Sense enable interrupt - 17 - SG SD - Soft Gemini - Sense disable interrupt - 18 - - - 19 - - - 20 - - - 21- - - Default: 0x0001 -*==============================================*/ - ACX_REG_INTERRUPT_MASK, - -/*============================================= - Host Interrupt Mask Set 16bit, (Write only) - ------------------------------------------ - Setting a bit in this register sets - the corresponding bin in ACX_HINT_MASK register - without effecting the mask - state of other bits (0 = no effect). -==============================================*/ - ACX_REG_HINT_MASK_SET, - -/*============================================= - Host Interrupt Mask Clear 16bit,(Write only) - ------------------------------------------ - Setting a bit in this register clears - the corresponding bin in ACX_HINT_MASK register - without effecting the mask - state of other bits (0 = no effect). -=============================================*/ - ACX_REG_HINT_MASK_CLR, - -/*============================================= - Host Interrupt Status Nondestructive Read - 16bit,(Read only) - ------------------------------------------ - The host can read this register to determine - which interrupts are active. - Reading this register doesn't - effect its content. -=============================================*/ - ACX_REG_INTERRUPT_NO_CLEAR, - -/*============================================= - Host Interrupt Status Clear on Read Register - 16bit,(Read only) - ------------------------------------------ - The host can read this register to determine - which interrupts are active. - Reading this register clears it, - thus making all interrupts inactive. -==============================================*/ - ACX_REG_INTERRUPT_CLEAR, - -/*============================================= - Host Interrupt Acknowledge Register - 16bit,(Write only) - ------------------------------------------ - The host can set individual bits in this - register to clear (acknowledge) the corresp. - interrupt status bits in the HINT_STS_CLR and - HINT_STS_ND registers, thus making the - assotiated interrupt inactive. (0-no effect) -==============================================*/ - ACX_REG_INTERRUPT_ACK, - -/*=============================================== - Host Software Reset - 32bit RW - ------------------------------------------ - [31:1] Reserved - 0 SOFT_RESET Soft Reset - When this bit is set, - it holds the Wlan hardware in a soft reset state. - This reset disables all MAC and baseband processor - clocks except the CardBus/PCI interface clock. - It also initializes all MAC state machines except - the host interface. It does not reload the - contents of the EEPROM. When this bit is cleared - (not self-clearing), the Wlan hardware - exits the software reset state. -===============================================*/ - ACX_REG_SLV_SOFT_RESET, - -/*=============================================== - EEPROM Burst Read Start - 32bit RW - ------------------------------------------ - [31:1] Reserved - 0 ACX_EE_START - EEPROM Burst Read Start 0 - Setting this bit starts a burst read from - the external EEPROM. - If this bit is set (after reset) before an EEPROM read/write, - the burst read starts at EEPROM address 0. - Otherwise, it starts at the address - following the address of the previous access. - TheWlan hardware hardware clears this bit automatically. - - Default: 0x00000000 -*================================================*/ - ACX_REG_EE_START, - -/* Embedded ARM CPU Control */ - -/*=============================================== - Halt eCPU - 32bit RW - ------------------------------------------ - 0 HALT_ECPU Halt Embedded CPU - This bit is the - compliment of bit 1 (MDATA2) in the SOR_CFG register. - During a hardware reset, this bit holds - the inverse of MDATA2. - When downloading firmware from the host, - set this bit (pull down MDATA2). - The host clears this bit after downloading the firmware into - zero-wait-state SSRAM. - When loading firmware from Flash, clear this bit (pull up MDATA2) - so that the eCPU can run the bootloader code in Flash - HALT_ECPU eCPU State - -------------------- - 1 halt eCPU - 0 enable eCPU - ===============================================*/ - ACX_REG_ECPU_CONTROL, - - ACX_REG_TABLE_LEN -}; - -#define ACX_SLV_SOFT_RESET_BIT BIT(1) -#define ACX_REG_EEPROM_START_BIT BIT(1) - -/* Command/Information Mailbox Pointers */ - -/*=============================================== - Command Mailbox Pointer - 32bit RW - ------------------------------------------ - This register holds the start address of - the command mailbox located in the Wlan hardware memory. - The host must read this pointer after a reset to - find the location of the command mailbox. - The Wlan hardware initializes the command mailbox - pointer with the default address of the command mailbox. - The command mailbox pointer is not valid until after - the host receives the Init Complete interrupt from - the Wlan hardware. - ===============================================*/ -#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) - -/*=============================================== - Information Mailbox Pointer - 32bit RW - ------------------------------------------ - This register holds the start address of - the information mailbox located in the Wlan hardware memory. - The host must read this pointer after a reset to find - the location of the information mailbox. - The Wlan hardware initializes the information mailbox pointer - with the default address of the information mailbox. - The information mailbox pointer is not valid - until after the host receives the Init Complete interrupt from - the Wlan hardware. - ===============================================*/ -#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) - - -/* Misc */ - -#define REG_ENABLE_TX_RX (ENABLE) -/* - * Rx configuration (filter) information element - * --------------------------------------------- - */ -#define REG_RX_CONFIG (RX_CFG) -#define REG_RX_FILTER (RX_FILTER_CFG) - - -#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 - -/* promiscuous - receives all valid frames */ -#define RX_CFG_PROMISCUOUS 0x0008 - -/* receives frames from any BSSID */ -#define RX_CFG_BSSID 0x0020 - -/* receives frames destined to any MAC address */ -#define RX_CFG_MAC 0x0010 - -#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 -#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 -#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 -#define RX_CFG_ENABLE_ANY_BSSID 0x0000 - -/* discards all broadcast frames */ -#define RX_CFG_DISABLE_BCAST 0x0200 - -#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 -#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 -#define RX_CFG_COPY_RX_STATUS 0x2000 -#define RX_CFG_TSF 0x10000 - -#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ - RX_CFG_ENABLE_ONLY_MY_BSSID) - -#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ - | RX_CFG_ENABLE_ANY_BSSID) - -#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ - RX_CFG_ENABLE_ANY_BSSID) - -#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ - | RX_CFG_ENABLE_ONLY_MY_BSSID) - -#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ - | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ - | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) - -#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) - -#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ - RX_CFG_ENABLE_ONLY_MY_DEST_MAC) - -#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ - RX_CFG_ENABLE_ONLY_MY_DEST_MAC) - -#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ - | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ - | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) - -#define RX_FILTER_OPTION_FILTER_ALL 0 - -#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ - | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) - -#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ - | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ - | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ - | CFG_RX_PRSP_EN) - - -/*=============================================== - Phy regs - ===============================================*/ -#define ACX_PHY_ADDR_REG SBB_ADDR -#define ACX_PHY_DATA_REG SBB_DATA -#define ACX_PHY_CTRL_REG SBB_CTL -#define ACX_PHY_REG_WR_MASK 0x00000001ul -#define ACX_PHY_REG_RD_MASK 0x00000002ul - - -/*=============================================== - EEPROM Read/Write Request 32bit RW - ------------------------------------------ - 1 EE_READ - EEPROM Read Request 1 - Setting this bit - loads a single byte of data into the EE_DATA - register from the EEPROM location specified in - the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. - EE_DATA is valid when this bit is cleared. - - 0 EE_WRITE - EEPROM Write Request - Setting this bit - writes a single byte of data from the EE_DATA register into the - EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. -*===============================================*/ -#define ACX_EE_CTL_REG EE_CTL -#define EE_WRITE 0x00000001ul -#define EE_READ 0x00000002ul - -/*=============================================== - EEPROM Address - 32bit RW - ------------------------------------------ - This register specifies the address - within the EEPROM from/to which to read/write data. - ===============================================*/ -#define ACX_EE_ADDR_REG EE_ADDR - -/*=============================================== - EEPROM Data - 32bit RW - ------------------------------------------ - This register either holds the read 8 bits of - data from the EEPROM or the write data - to be written to the EEPROM. - ===============================================*/ -#define ACX_EE_DATA_REG EE_DATA - -/*=============================================== - EEPROM Base Address - 32bit RW - ------------------------------------------ - This register holds the upper nine bits - [23:15] of the 24-bit Wlan hardware memory - address for burst reads from EEPROM accesses. - The EEPROM provides the lower 15 bits of this address. - The MSB of the address from the EEPROM is ignored. - ===============================================*/ -#define ACX_EE_CFG EE_CFG - -/*=============================================== - GPIO Output Values -32bit, RW - ------------------------------------------ - [31:16] Reserved - [15: 0] Specify the output values (at the output driver inputs) for - GPIO[15:0], respectively. - ===============================================*/ -#define ACX_GPIO_OUT_REG GPIO_OUT -#define ACX_MAX_GPIO_LINES 15 - -/*=============================================== - Contention window -32bit, RW - ------------------------------------------ - [31:26] Reserved - [25:16] Max (0x3ff) - [15:07] Reserved - [06:00] Current contention window value - default is 0x1F - ===============================================*/ -#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG -#define ACX_CONT_WIND_MIN_MASK 0x0000007f -#define ACX_CONT_WIND_MAX 0x03ff0000 - -/* - * Indirect slave register/memory registers - * ---------------------------------------- - */ -#define HW_SLAVE_REG_ADDR_REG 0x00000004 -#define HW_SLAVE_REG_DATA_REG 0x00000008 -#define HW_SLAVE_REG_CTRL_REG 0x0000000c - -#define SLAVE_AUTO_INC 0x00010000 -#define SLAVE_NO_AUTO_INC 0x00000000 -#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 - -#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR -#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA -#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL -#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL - -#define HW_FUNC_EVENT_INT_EN 0x8000 -#define HW_FUNC_EVENT_MASK_REG 0x00000034 - -#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) - -/*=============================================== - HI_CFG Interface Configuration Register Values - ------------------------------------------ - ===============================================*/ -#define HI_CFG_UART_ENABLE 0x00000004 -#define HI_CFG_RST232_ENABLE 0x00000008 -#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 -#define HI_CFG_HOST_INT_ENABLE 0x00000020 -#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 -#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 -#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 -#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 -#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 - -/* - * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile - * for platforms using active high interrupt level - */ -#ifdef USE_ACTIVE_HIGH -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) -#else -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) - -#endif - -#define REF_FREQ_19_2 0 -#define REF_FREQ_26_0 1 -#define REF_FREQ_38_4 2 -#define REF_FREQ_40_0 3 -#define REF_FREQ_33_6 4 -#define REF_FREQ_NUM 5 - -#define LUT_PARAM_INTEGER_DIVIDER 0 -#define LUT_PARAM_FRACTIONAL_DIVIDER 1 -#define LUT_PARAM_ATTN_BB 2 -#define LUT_PARAM_ALPHA_BB 3 -#define LUT_PARAM_STOP_TIME_BB 4 -#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 -#define LUT_PARAM_NUM 6 - -#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) -#define USE_EEPROM 0 -#define SOFT_RESET_MAX_TIME 1000000 -#define SOFT_RESET_STALL_TIME 1000 -#define NVS_DATA_BUNDARY_ALIGNMENT 4 - - -/* Firmware image load chunk size */ -#define CHUNK_SIZE 512 - -/* Firmware image header size */ -#define FW_HDR_SIZE 8 - -#define ECPU_CONTROL_HALT 0x00000101 - - -/****************************************************************************** - - CHANNELS, BAND & REG DOMAINS definitions - -******************************************************************************/ - - -enum { - RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ - RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ - RADIO_BAND_JAPAN_4_9_GHZ = 2, - DEFAULT_BAND = RADIO_BAND_2_4GHZ, - INVALID_BAND = 0xFE, - MAX_RADIO_BANDS = 0xFF -}; - -enum { - NO_RATE = 0, - RATE_1MBPS = 0x0A, - RATE_2MBPS = 0x14, - RATE_5_5MBPS = 0x37, - RATE_6MBPS = 0x0B, - RATE_9MBPS = 0x0F, - RATE_11MBPS = 0x6E, - RATE_12MBPS = 0x0A, - RATE_18MBPS = 0x0E, - RATE_22MBPS = 0xDC, - RATE_24MBPS = 0x09, - RATE_36MBPS = 0x0D, - RATE_48MBPS = 0x08, - RATE_54MBPS = 0x0C -}; - -enum { - RATE_INDEX_1MBPS = 0, - RATE_INDEX_2MBPS = 1, - RATE_INDEX_5_5MBPS = 2, - RATE_INDEX_6MBPS = 3, - RATE_INDEX_9MBPS = 4, - RATE_INDEX_11MBPS = 5, - RATE_INDEX_12MBPS = 6, - RATE_INDEX_18MBPS = 7, - RATE_INDEX_22MBPS = 8, - RATE_INDEX_24MBPS = 9, - RATE_INDEX_36MBPS = 10, - RATE_INDEX_48MBPS = 11, - RATE_INDEX_54MBPS = 12, - RATE_INDEX_MAX = RATE_INDEX_54MBPS, - MAX_RATE_INDEX, - INVALID_RATE_INDEX = MAX_RATE_INDEX, - RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF -}; - -enum { - RATE_MASK_1MBPS = 0x1, - RATE_MASK_2MBPS = 0x2, - RATE_MASK_5_5MBPS = 0x4, - RATE_MASK_11MBPS = 0x20, -}; - -#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ -#define OFDM_RATE_BIT BIT(6) -#define PBCC_RATE_BIT BIT(7) - -enum { - CCK_LONG = 0, - CCK_SHORT = SHORT_PREAMBLE_BIT, - PBCC_LONG = PBCC_RATE_BIT, - PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, - OFDM = OFDM_RATE_BIT -}; - -/****************************************************************************** - -Transmit-Descriptor RATE-SET field definitions... - -Define a new "Rate-Set" for TX path that incorporates the -Rate & Modulation info into a single 16-bit field. - -TxdRateSet_t: -b15 - Indicates Preamble type (1=SHORT, 0=LONG). - Notes: - Must be LONG (0) for 1Mbps rate. - Does not apply (set to 0) for RevG-OFDM rates. -b14 - Indicates PBCC encoding (1=PBCC, 0=not). - Notes: - Does not apply (set to 0) for rates 1 and 2 Mbps. - Does not apply (set to 0) for RevG-OFDM rates. -b13 - Unused (set to 0). -b12-b0 - Supported Rate indicator bits as defined below. - -******************************************************************************/ - - -#define TNETW1251_CHIP_ID_PG1_0 0x07010101 -#define TNETW1251_CHIP_ID_PG1_1 0x07020101 -#define TNETW1251_CHIP_ID_PG1_2 0x07030101 - -/************************************************************************* - - Interrupt Trigger Register (Host -> WiLink) - -**************************************************************************/ - -/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ - -/* - * Host Command Interrupt. Setting this bit masks - * the interrupt that the host issues to inform - * the FW that it has sent a command - * to the Wlan hardware Command Mailbox. - */ -#define INTR_TRIG_CMD BIT(0) - -/* - * Host Event Acknowlegde Interrupt. The host - * sets this bit to acknowledge that it received - * the unsolicited information from the event - * mailbox. - */ -#define INTR_TRIG_EVENT_ACK BIT(1) - -/* - * The host sets this bit to inform the Wlan - * FW that a TX packet is in the XFER - * Buffer #0. - */ -#define INTR_TRIG_TX_PROC0 BIT(2) - -/* - * The host sets this bit to inform the FW - * that it read a packet from RX XFER - * Buffer #0. - */ -#define INTR_TRIG_RX_PROC0 BIT(3) - -#define INTR_TRIG_DEBUG_ACK BIT(4) - -#define INTR_TRIG_STATE_CHANGED BIT(5) - - -/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ - -/* - * The host sets this bit to inform the FW - * that it read a packet from RX XFER - * Buffer #1. - */ -#define INTR_TRIG_RX_PROC1 BIT(17) - -/* - * The host sets this bit to inform the Wlan - * hardware that a TX packet is in the XFER - * Buffer #1. - */ -#define INTR_TRIG_TX_PROC1 BIT(18) - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 0a225c6..10b26c4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -4,7 +4,7 @@ #include #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_cmd.h" #include "wl1251_ps.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 88e9cb0..592c3b5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -23,7 +23,7 @@ #include -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_boot.h" #include "wl1251_io.h" #include "wl1251_spi.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 74ea1fd..6cd024b 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -4,7 +4,7 @@ #include #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_io.h" #include "wl1251_ps.h" #include "wl1251_acx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 1b4f8d2..7bd1b6a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -23,7 +23,7 @@ */ #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_io.h" #include "wl1251_event.h" #include "wl1251_ps.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index 1c587ec..b2ee4f4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -28,7 +28,7 @@ #include "wl12xx_80211.h" #include "wl1251_acx.h" #include "wl1251_cmd.h" -#include "reg.h" +#include "wl1251_reg.h" int wl1251_hw_init_hwenc_config(struct wl1251 *wl) { diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c index 04e486c..f1c232e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.c +++ b/drivers/net/wireless/wl12xx/wl1251_io.c @@ -22,7 +22,7 @@ */ #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_io.h" /* FIXME: this is static data nowadays and the table can be removed */ diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index c5f2d9d..3fe8b65 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -31,7 +31,7 @@ #include "wl1251.h" #include "wl12xx_80211.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_io.h" #include "wl1251_cmd.h" #include "wl1251_event.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 36acde0..c53e287 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -21,7 +21,7 @@ * */ -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_ps.h" #include "wl1251_cmd.h" #include "wl1251_io.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h new file mode 100644 index 0000000..2de47cc --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_reg.h @@ -0,0 +1,744 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * 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 published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __REG_H__ +#define __REG_H__ + +#include + +#define REGISTERS_BASE 0x00300000 +#define DRPW_BASE 0x00310000 + +#define REGISTERS_DOWN_SIZE 0x00008800 +#define REGISTERS_WORK_SIZE 0x0000b000 + +#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC + +/* ELP register commands */ +#define ELPCTRL_WAKE_UP 0x1 +#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 +#define ELPCTRL_SLEEP 0x0 +/* ELP WLAN_READY bit */ +#define ELPCTRL_WLAN_READY 0x2 + +/* + * Interrupt registers. + * 64 bit interrupt sources registers ws ced. + * sme interupts were removed and new ones were added. + * Order was changed. + */ +#define FIQ_MASK (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) +#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) +#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) +#define IRQ_MASK (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) +#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) +#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) +#define ECPU_MASK (REGISTERS_BASE + 0x0448) +#define FIQ_STS_L (REGISTERS_BASE + 0x044C) +#define FIQ_STS_H (REGISTERS_BASE + 0x0450) +#define IRQ_STS_L (REGISTERS_BASE + 0x0454) +#define IRQ_STS_H (REGISTERS_BASE + 0x0458) +#define INT_STS_ND (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) +#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) +#define INT_ACK (REGISTERS_BASE + 0x046C) +#define INT_ACK_L (REGISTERS_BASE + 0x046C) +#define INT_ACK_H (REGISTERS_BASE + 0x0470) +#define INT_TRIG (REGISTERS_BASE + 0x0474) +#define INT_TRIG_L (REGISTERS_BASE + 0x0474) +#define INT_TRIG_H (REGISTERS_BASE + 0x0478) +#define HOST_STS_L (REGISTERS_BASE + 0x045C) +#define HOST_STS_H (REGISTERS_BASE + 0x0460) +#define HOST_MASK (REGISTERS_BASE + 0x0430) +#define HOST_MASK_L (REGISTERS_BASE + 0x0430) +#define HOST_MASK_H (REGISTERS_BASE + 0x0434) +#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) +#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) + +/* Host Interrupts*/ +#define HINT_MASK (REGISTERS_BASE + 0x0494) +#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) +#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) +#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) +/*1150 spec calls this HINT_STS_RAW*/ +#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) +#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) +#define HINT_ACK (REGISTERS_BASE + 0x04A8) +#define HINT_TRIG (REGISTERS_BASE + 0x04AC) + +/* Device Configuration registers*/ +#define SOR_CFG (REGISTERS_BASE + 0x0800) +#define ECPU_CTRL (REGISTERS_BASE + 0x0804) +#define HI_CFG (REGISTERS_BASE + 0x0808) +#define EE_START (REGISTERS_BASE + 0x080C) + +#define CHIP_ID_B (REGISTERS_BASE + 0x5674) + +#define CHIP_ID_1251_PG10 (0x7010101) +#define CHIP_ID_1251_PG11 (0x7020101) +#define CHIP_ID_1251_PG12 (0x7030101) + +#define ENABLE (REGISTERS_BASE + 0x5450) + +/* Power Management registers */ +#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) +#define ELP_CMD (REGISTERS_BASE + 0x5808) +#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) +#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) +#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) + +#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) + +/* Scratch Pad registers*/ +#define SCR_PAD0 (REGISTERS_BASE + 0x5608) +#define SCR_PAD1 (REGISTERS_BASE + 0x560C) +#define SCR_PAD2 (REGISTERS_BASE + 0x5610) +#define SCR_PAD3 (REGISTERS_BASE + 0x5614) +#define SCR_PAD4 (REGISTERS_BASE + 0x5618) +#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) +#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) +#define SCR_PAD5 (REGISTERS_BASE + 0x5624) +#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) +#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) +#define SCR_PAD6 (REGISTERS_BASE + 0x5630) +#define SCR_PAD7 (REGISTERS_BASE + 0x5634) +#define SCR_PAD8 (REGISTERS_BASE + 0x5638) +#define SCR_PAD9 (REGISTERS_BASE + 0x563C) + +/* Spare registers*/ +#define SPARE_A1 (REGISTERS_BASE + 0x0994) +#define SPARE_A2 (REGISTERS_BASE + 0x0998) +#define SPARE_A3 (REGISTERS_BASE + 0x099C) +#define SPARE_A4 (REGISTERS_BASE + 0x09A0) +#define SPARE_A5 (REGISTERS_BASE + 0x09A4) +#define SPARE_A6 (REGISTERS_BASE + 0x09A8) +#define SPARE_A7 (REGISTERS_BASE + 0x09AC) +#define SPARE_A8 (REGISTERS_BASE + 0x09B0) +#define SPARE_B1 (REGISTERS_BASE + 0x5420) +#define SPARE_B2 (REGISTERS_BASE + 0x5424) +#define SPARE_B3 (REGISTERS_BASE + 0x5428) +#define SPARE_B4 (REGISTERS_BASE + 0x542C) +#define SPARE_B5 (REGISTERS_BASE + 0x5430) +#define SPARE_B6 (REGISTERS_BASE + 0x5434) +#define SPARE_B7 (REGISTERS_BASE + 0x5438) +#define SPARE_B8 (REGISTERS_BASE + 0x543C) + +enum wl12xx_acx_int_reg { + ACX_REG_INTERRUPT_TRIG, + ACX_REG_INTERRUPT_TRIG_H, + +/*============================================= + Host Interrupt Mask Register - 32bit (RW) + ------------------------------------------ + Setting a bit in this register masks the + corresponding interrupt to the host. + 0 - RX0 - Rx first dubble buffer Data Interrupt + 1 - TXD - Tx Data Interrupt + 2 - TXXFR - Tx Transfer Interrupt + 3 - RX1 - Rx second dubble buffer Data Interrupt + 4 - RXXFR - Rx Transfer Interrupt + 5 - EVENT_A - Event Mailbox interrupt + 6 - EVENT_B - Event Mailbox interrupt + 7 - WNONHST - Wake On Host Interrupt + 8 - TRACE_A - Debug Trace interrupt + 9 - TRACE_B - Debug Trace interrupt + 10 - CDCMP - Command Complete Interrupt + 11 - + 12 - + 13 - + 14 - ICOMP - Initialization Complete Interrupt + 16 - SG SE - Soft Gemini - Sense enable interrupt + 17 - SG SD - Soft Gemini - Sense disable interrupt + 18 - - + 19 - - + 20 - - + 21- - + Default: 0x0001 +*==============================================*/ + ACX_REG_INTERRUPT_MASK, + +/*============================================= + Host Interrupt Mask Set 16bit, (Write only) + ------------------------------------------ + Setting a bit in this register sets + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +==============================================*/ + ACX_REG_HINT_MASK_SET, + +/*============================================= + Host Interrupt Mask Clear 16bit,(Write only) + ------------------------------------------ + Setting a bit in this register clears + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +=============================================*/ + ACX_REG_HINT_MASK_CLR, + +/*============================================= + Host Interrupt Status Nondestructive Read + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register doesn't + effect its content. +=============================================*/ + ACX_REG_INTERRUPT_NO_CLEAR, + +/*============================================= + Host Interrupt Status Clear on Read Register + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register clears it, + thus making all interrupts inactive. +==============================================*/ + ACX_REG_INTERRUPT_CLEAR, + +/*============================================= + Host Interrupt Acknowledge Register + 16bit,(Write only) + ------------------------------------------ + The host can set individual bits in this + register to clear (acknowledge) the corresp. + interrupt status bits in the HINT_STS_CLR and + HINT_STS_ND registers, thus making the + assotiated interrupt inactive. (0-no effect) +==============================================*/ + ACX_REG_INTERRUPT_ACK, + +/*=============================================== + Host Software Reset - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 SOFT_RESET Soft Reset - When this bit is set, + it holds the Wlan hardware in a soft reset state. + This reset disables all MAC and baseband processor + clocks except the CardBus/PCI interface clock. + It also initializes all MAC state machines except + the host interface. It does not reload the + contents of the EEPROM. When this bit is cleared + (not self-clearing), the Wlan hardware + exits the software reset state. +===============================================*/ + ACX_REG_SLV_SOFT_RESET, + +/*=============================================== + EEPROM Burst Read Start - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 ACX_EE_START - EEPROM Burst Read Start 0 + Setting this bit starts a burst read from + the external EEPROM. + If this bit is set (after reset) before an EEPROM read/write, + the burst read starts at EEPROM address 0. + Otherwise, it starts at the address + following the address of the previous access. + TheWlan hardware hardware clears this bit automatically. + + Default: 0x00000000 +*================================================*/ + ACX_REG_EE_START, + +/* Embedded ARM CPU Control */ + +/*=============================================== + Halt eCPU - 32bit RW + ------------------------------------------ + 0 HALT_ECPU Halt Embedded CPU - This bit is the + compliment of bit 1 (MDATA2) in the SOR_CFG register. + During a hardware reset, this bit holds + the inverse of MDATA2. + When downloading firmware from the host, + set this bit (pull down MDATA2). + The host clears this bit after downloading the firmware into + zero-wait-state SSRAM. + When loading firmware from Flash, clear this bit (pull up MDATA2) + so that the eCPU can run the bootloader code in Flash + HALT_ECPU eCPU State + -------------------- + 1 halt eCPU + 0 enable eCPU + ===============================================*/ + ACX_REG_ECPU_CONTROL, + + ACX_REG_TABLE_LEN +}; + +#define ACX_SLV_SOFT_RESET_BIT BIT(1) +#define ACX_REG_EEPROM_START_BIT BIT(1) + +/* Command/Information Mailbox Pointers */ + +/*=============================================== + Command Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the command mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to + find the location of the command mailbox. + The Wlan hardware initializes the command mailbox + pointer with the default address of the command mailbox. + The command mailbox pointer is not valid until after + the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) + +/*=============================================== + Information Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the information mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to find + the location of the information mailbox. + The Wlan hardware initializes the information mailbox pointer + with the default address of the information mailbox. + The information mailbox pointer is not valid + until after the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) + + +/* Misc */ + +#define REG_ENABLE_TX_RX (ENABLE) +/* + * Rx configuration (filter) information element + * --------------------------------------------- + */ +#define REG_RX_CONFIG (RX_CFG) +#define REG_RX_FILTER (RX_FILTER_CFG) + + +#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 + +/* promiscuous - receives all valid frames */ +#define RX_CFG_PROMISCUOUS 0x0008 + +/* receives frames from any BSSID */ +#define RX_CFG_BSSID 0x0020 + +/* receives frames destined to any MAC address */ +#define RX_CFG_MAC 0x0010 + +#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 +#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 +#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 +#define RX_CFG_ENABLE_ANY_BSSID 0x0000 + +/* discards all broadcast frames */ +#define RX_CFG_DISABLE_BCAST 0x0200 + +#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 +#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 +#define RX_CFG_COPY_RX_STATUS 0x2000 +#define RX_CFG_TSF 0x10000 + +#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ + | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ + | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) + +#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ + | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) + +#define RX_FILTER_OPTION_FILTER_ALL 0 + +#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ + | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) + +#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ + | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ + | CFG_RX_PRSP_EN) + + +/*=============================================== + Phy regs + ===============================================*/ +#define ACX_PHY_ADDR_REG SBB_ADDR +#define ACX_PHY_DATA_REG SBB_DATA +#define ACX_PHY_CTRL_REG SBB_CTL +#define ACX_PHY_REG_WR_MASK 0x00000001ul +#define ACX_PHY_REG_RD_MASK 0x00000002ul + + +/*=============================================== + EEPROM Read/Write Request 32bit RW + ------------------------------------------ + 1 EE_READ - EEPROM Read Request 1 - Setting this bit + loads a single byte of data into the EE_DATA + register from the EEPROM location specified in + the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. + EE_DATA is valid when this bit is cleared. + + 0 EE_WRITE - EEPROM Write Request - Setting this bit + writes a single byte of data from the EE_DATA register into the + EEPROM location specified in the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. +*===============================================*/ +#define ACX_EE_CTL_REG EE_CTL +#define EE_WRITE 0x00000001ul +#define EE_READ 0x00000002ul + +/*=============================================== + EEPROM Address - 32bit RW + ------------------------------------------ + This register specifies the address + within the EEPROM from/to which to read/write data. + ===============================================*/ +#define ACX_EE_ADDR_REG EE_ADDR + +/*=============================================== + EEPROM Data - 32bit RW + ------------------------------------------ + This register either holds the read 8 bits of + data from the EEPROM or the write data + to be written to the EEPROM. + ===============================================*/ +#define ACX_EE_DATA_REG EE_DATA + +/*=============================================== + EEPROM Base Address - 32bit RW + ------------------------------------------ + This register holds the upper nine bits + [23:15] of the 24-bit Wlan hardware memory + address for burst reads from EEPROM accesses. + The EEPROM provides the lower 15 bits of this address. + The MSB of the address from the EEPROM is ignored. + ===============================================*/ +#define ACX_EE_CFG EE_CFG + +/*=============================================== + GPIO Output Values -32bit, RW + ------------------------------------------ + [31:16] Reserved + [15: 0] Specify the output values (at the output driver inputs) for + GPIO[15:0], respectively. + ===============================================*/ +#define ACX_GPIO_OUT_REG GPIO_OUT +#define ACX_MAX_GPIO_LINES 15 + +/*=============================================== + Contention window -32bit, RW + ------------------------------------------ + [31:26] Reserved + [25:16] Max (0x3ff) + [15:07] Reserved + [06:00] Current contention window value - default is 0x1F + ===============================================*/ +#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG +#define ACX_CONT_WIND_MIN_MASK 0x0000007f +#define ACX_CONT_WIND_MAX 0x03ff0000 + +/* + * Indirect slave register/memory registers + * ---------------------------------------- + */ +#define HW_SLAVE_REG_ADDR_REG 0x00000004 +#define HW_SLAVE_REG_DATA_REG 0x00000008 +#define HW_SLAVE_REG_CTRL_REG 0x0000000c + +#define SLAVE_AUTO_INC 0x00010000 +#define SLAVE_NO_AUTO_INC 0x00000000 +#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 + +#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR +#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA +#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL +#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL + +#define HW_FUNC_EVENT_INT_EN 0x8000 +#define HW_FUNC_EVENT_MASK_REG 0x00000034 + +#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) + +/*=============================================== + HI_CFG Interface Configuration Register Values + ------------------------------------------ + ===============================================*/ +#define HI_CFG_UART_ENABLE 0x00000004 +#define HI_CFG_RST232_ENABLE 0x00000008 +#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 +#define HI_CFG_HOST_INT_ENABLE 0x00000020 +#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 +#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 +#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 +#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 +#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 + +/* + * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile + * for platforms using active high interrupt level + */ +#ifdef USE_ACTIVE_HIGH +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) +#else +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) + +#endif + +#define REF_FREQ_19_2 0 +#define REF_FREQ_26_0 1 +#define REF_FREQ_38_4 2 +#define REF_FREQ_40_0 3 +#define REF_FREQ_33_6 4 +#define REF_FREQ_NUM 5 + +#define LUT_PARAM_INTEGER_DIVIDER 0 +#define LUT_PARAM_FRACTIONAL_DIVIDER 1 +#define LUT_PARAM_ATTN_BB 2 +#define LUT_PARAM_ALPHA_BB 3 +#define LUT_PARAM_STOP_TIME_BB 4 +#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 +#define LUT_PARAM_NUM 6 + +#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) +#define USE_EEPROM 0 +#define SOFT_RESET_MAX_TIME 1000000 +#define SOFT_RESET_STALL_TIME 1000 +#define NVS_DATA_BUNDARY_ALIGNMENT 4 + + +/* Firmware image load chunk size */ +#define CHUNK_SIZE 512 + +/* Firmware image header size */ +#define FW_HDR_SIZE 8 + +#define ECPU_CONTROL_HALT 0x00000101 + + +/****************************************************************************** + + CHANNELS, BAND & REG DOMAINS definitions + +******************************************************************************/ + + +enum { + RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ + RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ + RADIO_BAND_JAPAN_4_9_GHZ = 2, + DEFAULT_BAND = RADIO_BAND_2_4GHZ, + INVALID_BAND = 0xFE, + MAX_RADIO_BANDS = 0xFF +}; + +enum { + NO_RATE = 0, + RATE_1MBPS = 0x0A, + RATE_2MBPS = 0x14, + RATE_5_5MBPS = 0x37, + RATE_6MBPS = 0x0B, + RATE_9MBPS = 0x0F, + RATE_11MBPS = 0x6E, + RATE_12MBPS = 0x0A, + RATE_18MBPS = 0x0E, + RATE_22MBPS = 0xDC, + RATE_24MBPS = 0x09, + RATE_36MBPS = 0x0D, + RATE_48MBPS = 0x08, + RATE_54MBPS = 0x0C +}; + +enum { + RATE_INDEX_1MBPS = 0, + RATE_INDEX_2MBPS = 1, + RATE_INDEX_5_5MBPS = 2, + RATE_INDEX_6MBPS = 3, + RATE_INDEX_9MBPS = 4, + RATE_INDEX_11MBPS = 5, + RATE_INDEX_12MBPS = 6, + RATE_INDEX_18MBPS = 7, + RATE_INDEX_22MBPS = 8, + RATE_INDEX_24MBPS = 9, + RATE_INDEX_36MBPS = 10, + RATE_INDEX_48MBPS = 11, + RATE_INDEX_54MBPS = 12, + RATE_INDEX_MAX = RATE_INDEX_54MBPS, + MAX_RATE_INDEX, + INVALID_RATE_INDEX = MAX_RATE_INDEX, + RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF +}; + +enum { + RATE_MASK_1MBPS = 0x1, + RATE_MASK_2MBPS = 0x2, + RATE_MASK_5_5MBPS = 0x4, + RATE_MASK_11MBPS = 0x20, +}; + +#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +enum { + CCK_LONG = 0, + CCK_SHORT = SHORT_PREAMBLE_BIT, + PBCC_LONG = PBCC_RATE_BIT, + PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, + OFDM = OFDM_RATE_BIT +}; + +/****************************************************************************** + +Transmit-Descriptor RATE-SET field definitions... + +Define a new "Rate-Set" for TX path that incorporates the +Rate & Modulation info into a single 16-bit field. + +TxdRateSet_t: +b15 - Indicates Preamble type (1=SHORT, 0=LONG). + Notes: + Must be LONG (0) for 1Mbps rate. + Does not apply (set to 0) for RevG-OFDM rates. +b14 - Indicates PBCC encoding (1=PBCC, 0=not). + Notes: + Does not apply (set to 0) for rates 1 and 2 Mbps. + Does not apply (set to 0) for RevG-OFDM rates. +b13 - Unused (set to 0). +b12-b0 - Supported Rate indicator bits as defined below. + +******************************************************************************/ + + +#define TNETW1251_CHIP_ID_PG1_0 0x07010101 +#define TNETW1251_CHIP_ID_PG1_1 0x07020101 +#define TNETW1251_CHIP_ID_PG1_2 0x07030101 + +/************************************************************************* + + Interrupt Trigger Register (Host -> WiLink) + +**************************************************************************/ + +/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ + +/* + * Host Command Interrupt. Setting this bit masks + * the interrupt that the host issues to inform + * the FW that it has sent a command + * to the Wlan hardware Command Mailbox. + */ +#define INTR_TRIG_CMD BIT(0) + +/* + * Host Event Acknowlegde Interrupt. The host + * sets this bit to acknowledge that it received + * the unsolicited information from the event + * mailbox. + */ +#define INTR_TRIG_EVENT_ACK BIT(1) + +/* + * The host sets this bit to inform the Wlan + * FW that a TX packet is in the XFER + * Buffer #0. + */ +#define INTR_TRIG_TX_PROC0 BIT(2) + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #0. + */ +#define INTR_TRIG_RX_PROC0 BIT(3) + +#define INTR_TRIG_DEBUG_ACK BIT(4) + +#define INTR_TRIG_STATE_CHANGED BIT(5) + + +/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #1. + */ +#define INTR_TRIG_RX_PROC1 BIT(17) + +/* + * The host sets this bit to inform the Wlan + * hardware that a TX packet is in the XFER + * Buffer #1. + */ +#define INTR_TRIG_TX_PROC1 BIT(18) + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index af81879..17c54b5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -26,7 +26,7 @@ #include #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_io.h" #include "wl1251_rx.h" #include "wl1251_cmd.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index 20668e2..9577ed6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c @@ -29,7 +29,7 @@ #include "wl1251.h" #include "wl12xx_80211.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_ps.h" #include "wl1251_io.h" #include "wl1251_tx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index e088334..612d565 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -28,7 +28,7 @@ #include #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_spi.h" static irqreturn_t wl1251_irq(int irq, void *cookie) diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index cb0c228..2e273a9 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -27,7 +27,7 @@ #include "wl1251_cmd.h" #include "wl1251_acx.h" -#include "reg.h" +#include "wl1251_reg.h" #define WSPI_CMD_READ 0x40000000 #define WSPI_CMD_WRITE 0x00000000 diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index f20bab6..f859706 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -26,7 +26,7 @@ #include #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_tx.h" #include "wl1251_ps.h" #include "wl1251_io.h" -- cgit v0.10.2 From b1b0a2b8b51fa3f0cd349f947a38ab4c6ab192c6 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:35:19 +0300 Subject: wl1251: remove Luciano as maintainer Luciano is maintaining wl1271 part. Signed-off-by: Kalle Valo Acked-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 3fe8b65..7148934 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1427,5 +1427,4 @@ EXPORT_SYMBOL_GPL(wl1251_free_hw); MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo "); -MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Kalle Valo "); diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index 9577ed6..9423f22 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c @@ -202,5 +202,4 @@ module_init(wl1251_sdio_init); module_exit(wl1251_sdio_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo "); -MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Kalle Valo "); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 612d565..14eff2b 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -341,5 +341,4 @@ module_init(wl1251_spi_init); module_exit(wl1251_spi_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo "); -MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Kalle Valo "); -- cgit v0.10.2 From 2789da9e58cc8db4e74359491a425712b5fcfdb6 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:35:26 +0300 Subject: wl1251: add hw scan completed debug message The logs currently don't show when hw scan has completed, fix that. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 7bd1b6a..00076c4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -39,6 +39,7 @@ static int wl1251_event_scan_complete(struct wl1251 *wl, mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); + wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); wl->scanning = false; } -- cgit v0.10.2 From f26b32ed4bd5780855a79bb17fb1a431fa867dad Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:35:33 +0300 Subject: wl1251: hack to disable filters for fixing association Commit 9cef8737 "mac80211: fix managed mode BSSID handling" broke association in wl1251, most probably because the driver configured the bssid filter incorrectly. Workaround this by disabling filter altogether. This needs to be fixed properly soon. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 6cd024b..770f260 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -276,6 +276,15 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, join->rx_config_options = wl->rx_config; join->rx_filter_options = wl->rx_filter; + /* + * FIXME: disable temporarily all filters because after commit + * 9cef8737 "mac80211: fix managed mode BSSID handling" broke + * association. The filter logic needs to be implemented properly + * and once that is done, this hack can be removed. + */ + join->rx_config_options = 0; + join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; + join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; -- cgit v0.10.2 From 59bbb6f7574bc693ed8313b98eac641116c95b94 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 17:22:35 +0200 Subject: cfg80211: validate channel settings across interfaces Currently, there's a problem that affects regulatory enforcement and connection stability, in that it is possible to switch the channel while connected to a network or joined to an IBSS. The problem comes from the fact that we only validate the channel against the current interface's type, not against any other interface. Thus, you have any type of interface up, additionally bring up a monitor mode interface and switch the channel on the monitor. This will obviously also switch the channel on the other interface. The problem now is that if you do that while sending beacons for IBSS mode, you can switch to a disabled channel or a channel that doesn't allow beaconing. Combined with a managed mode interface connected to an AP instead of an IBSS interface, you can easily break the connection that way. To fix this, this patch validates any channel change with all available interfaces, and disallows such changes on secondary interfaces if another interface is connected to an AP or joined to an IBSS. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/Makefile b/net/wireless/Makefile index d74cc77..3ecaa91 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -5,7 +5,8 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o -cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o +cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o +cfg80211-y += mlme.o ibss.o sme.o chan.o cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o diff --git a/net/wireless/chan.c b/net/wireless/chan.c new file mode 100644 index 0000000..bc00c9a --- /dev/null +++ b/net/wireless/chan.c @@ -0,0 +1,88 @@ +/* + * This file contains helper code to handle channel + * settings and keeping track of what is possible at + * any point in time. + * + * Copyright 2009 Johannes Berg + */ + +#include +#include "core.h" + +struct ieee80211_channel * +rdev_fixed_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *for_wdev) +{ + struct wireless_dev *wdev; + struct ieee80211_channel *result = NULL; + + WARN_ON(!mutex_is_locked(&rdev->devlist_mtx)); + + list_for_each_entry(wdev, &rdev->netdev_list, list) { + if (wdev == for_wdev) + continue; + + /* + * Lock manually to tell lockdep about allowed + * nesting here if for_wdev->mtx is held already. + * This is ok as it's all under the rdev devlist + * mutex and as such can only be done once at any + * given time. + */ + mutex_lock_nested(&wdev->mtx, SINGLE_DEPTH_NESTING); + if (wdev->current_bss) + result = wdev->current_bss->pub.channel; + wdev_unlock(wdev); + + if (result) + break; + } + + return result; +} + +int rdev_set_freq(struct cfg80211_registered_device *rdev, + int freq, enum nl80211_channel_type channel_type) +{ + struct ieee80211_channel *chan; + struct ieee80211_sta_ht_cap *ht_cap; + int result; + + if (rdev_fixed_channel(rdev, NULL)) + return -EBUSY; + + if (!rdev->ops->set_channel) + return -EOPNOTSUPP; + + chan = ieee80211_get_channel(&rdev->wiphy, freq); + + /* Primary channel not allowed */ + if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + + if (channel_type == NL80211_CHAN_HT40MINUS && + chan->flags & IEEE80211_CHAN_NO_HT40MINUS) + return -EINVAL; + else if (channel_type == NL80211_CHAN_HT40PLUS && + chan->flags & IEEE80211_CHAN_NO_HT40PLUS) + return -EINVAL; + + ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; + + if (channel_type != NL80211_CHAN_NO_HT) { + if (!ht_cap->ht_supported) + return -EINVAL; + + if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || + ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) + return -EINVAL; + } + + result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type); + if (result) + return result; + + rdev->channel = chan; + + return 0; +} diff --git a/net/wireless/core.h b/net/wireless/core.h index 325c17e..5696b95 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -366,4 +366,10 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx); void __cfg80211_scan_done(struct work_struct *wk); void cfg80211_upload_connect_keys(struct wireless_dev *wdev); +struct ieee80211_channel * +rdev_fixed_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *for_wdev); +int rdev_set_freq(struct cfg80211_registered_device *rdev, + int freq, enum nl80211_channel_type channel_type); + #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 4d7a084..42840a0 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -78,10 +78,15 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct cfg80211_cached_keys *connkeys) { struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_channel *chan; int err; ASSERT_WDEV_LOCK(wdev); + chan = rdev_fixed_channel(rdev, wdev); + if (chan && chan != params->channel) + return -EBUSY; + if (wdev->ssid_len) return -EALREADY; @@ -112,9 +117,11 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev = dev->ieee80211_ptr; int err; + mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); err = __cfg80211_join_ibss(rdev, dev, params, connkeys); wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); return err; } @@ -264,27 +271,32 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, int cfg80211_ibss_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, - struct iw_freq *freq, char *extra) + struct iw_freq *wextfreq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; - struct ieee80211_channel *chan; - int err; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct ieee80211_channel *chan = NULL; + int err, freq; /* call only for ibss! */ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) return -EINVAL; - if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) + if (!rdev->ops->join_ibss) return -EOPNOTSUPP; - chan = cfg80211_wext_freq(wdev->wiphy, freq); - if (chan && IS_ERR(chan)) - return PTR_ERR(chan); + freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); + if (freq < 0) + return freq; - if (chan && - (chan->flags & IEEE80211_CHAN_NO_IBSS || - chan->flags & IEEE80211_CHAN_DISABLED)) - return -EINVAL; + if (freq) { + chan = ieee80211_get_channel(wdev->wiphy, freq); + if (!chan) + return -EINVAL; + if (chan->flags & IEEE80211_CHAN_NO_IBSS || + chan->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + } if (wdev->wext.ibss.channel == chan) return 0; @@ -292,8 +304,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, wdev_lock(wdev); err = 0; if (wdev->ssid_len) - err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), - dev, true); + err = __cfg80211_leave_ibss(rdev, dev, true); wdev_unlock(wdev); if (err) @@ -307,9 +318,11 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, wdev->wext.ibss.channel_fixed = false; } + mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); - err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); + err = cfg80211_ibss_wext_join(rdev, wdev); wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); return err; } @@ -347,6 +360,7 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, struct iw_point *data, char *ssid) { struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); size_t len = data->length; int err; @@ -354,14 +368,13 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) return -EINVAL; - if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) + if (!rdev->ops->join_ibss) return -EOPNOTSUPP; wdev_lock(wdev); err = 0; if (wdev->ssid_len) - err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), - dev, true); + err = __cfg80211_leave_ibss(rdev, dev, true); wdev_unlock(wdev); if (err) @@ -375,9 +388,11 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, memcpy(wdev->wext.ibss.ssid, ssid, len); wdev->wext.ibss.ssid_len = len; + mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); - err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); + err = cfg80211_ibss_wext_join(rdev, wdev); wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); return err; } @@ -414,6 +429,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, struct sockaddr *ap_addr, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); u8 *bssid = ap_addr->sa_data; int err; @@ -421,7 +437,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) return -EINVAL; - if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) + if (!rdev->ops->join_ibss) return -EOPNOTSUPP; if (ap_addr->sa_family != ARPHRD_ETHER) @@ -443,8 +459,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, wdev_lock(wdev); err = 0; if (wdev->ssid_len) - err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), - dev, true); + err = __cfg80211_leave_ibss(rdev, dev, true); wdev_unlock(wdev); if (err) @@ -456,9 +471,11 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, } else wdev->wext.ibss.bssid = NULL; + mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); - err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); + err = cfg80211_ibss_wext_join(rdev, wdev); wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); return err; } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0cd5482..2ff7376 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -701,15 +701,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - struct ieee80211_channel *chan; - struct ieee80211_sta_ht_cap *ht_cap; u32 freq; - if (!rdev->ops->set_channel) { - result = -EOPNOTSUPP; - goto bad_res; - } - result = -EINVAL; if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { @@ -723,42 +716,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) } freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); - chan = ieee80211_get_channel(&rdev->wiphy, freq); - - /* Primary channel not allowed */ - if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) - goto bad_res; - - if (channel_type == NL80211_CHAN_HT40MINUS && - (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)) - goto bad_res; - else if (channel_type == NL80211_CHAN_HT40PLUS && - (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)) - goto bad_res; - - /* - * At this point we know if that if HT40 was requested - * we are allowed to use it and the extension channel - * exists. - */ - ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; - - /* no HT capabilities or intolerant */ - if (channel_type != NL80211_CHAN_NO_HT) { - if (!ht_cap->ht_supported) - goto bad_res; - if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || - (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) - goto bad_res; - } - - result = rdev->ops->set_channel(&rdev->wiphy, chan, - channel_type); + mutex_lock(&rdev->devlist_mtx); + result = rdev_set_freq(rdev, freq, channel_type); + mutex_unlock(&rdev->devlist_mtx); if (result) goto bad_res; - - rdev->channel = chan; } changed = 0; @@ -3453,7 +3416,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev; struct net_device *dev; struct cfg80211_crypto_settings crypto; - struct ieee80211_channel *chan; + struct ieee80211_channel *chan, *fixedchan; const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; int err, ssid_len, ie_len = 0; bool use_mfp = false; @@ -3496,6 +3459,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) goto out; } + mutex_lock(&rdev->devlist_mtx); + fixedchan = rdev_fixed_channel(rdev, NULL); + if (fixedchan && chan != fixedchan) { + err = -EBUSY; + mutex_unlock(&rdev->devlist_mtx); + goto out; + } + mutex_unlock(&rdev->devlist_mtx); + ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 340934f..219c3bc 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -256,9 +256,11 @@ void cfg80211_sme_scan_done(struct net_device *dev) { struct wireless_dev *wdev = dev->ieee80211_ptr; + mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); wdev_lock(wdev); __cfg80211_sme_scan_done(dev); wdev_unlock(wdev); + mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); } void cfg80211_sme_rx_auth(struct net_device *dev, @@ -644,6 +646,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, struct cfg80211_cached_keys *connkeys) { struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_channel *chan; int err; ASSERT_WDEV_LOCK(wdev); @@ -651,6 +654,10 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, if (wdev->sme_state != CFG80211_SME_IDLE) return -EALREADY; + chan = rdev_fixed_channel(rdev, wdev); + if (chan && chan != connect->channel) + return -EBUSY; + if (WARN_ON(wdev->connect_keys)) { kfree(wdev->connect_keys); wdev->connect_keys = NULL; @@ -785,9 +792,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, { int err; + mutex_lock(&rdev->devlist_mtx); wdev_lock(dev->ieee80211_ptr); err = __cfg80211_connect(rdev, dev, connect, connkeys); wdev_unlock(dev->ieee80211_ptr); + mutex_unlock(&rdev->devlist_mtx); return err; } diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index e4e90e2..17648dc 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -267,39 +267,26 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); * @wiphy: the wiphy * @freq: the wext freq encoding * - * Returns a channel, %NULL for auto, or an ERR_PTR for errors! + * Returns a frequency, or a negative error code, or 0 for auto. */ -struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, - struct iw_freq *freq) +int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq) { - struct ieee80211_channel *chan; - int f; - /* - * Parse frequency - return NULL for auto and + * Parse frequency - return 0 for auto and * -EINVAL for impossible things. */ if (freq->e == 0) { if (freq->m < 0) - return NULL; - f = ieee80211_channel_to_frequency(freq->m); + return 0; + return ieee80211_channel_to_frequency(freq->m); } else { int i, div = 1000000; for (i = 0; i < freq->e; i++) div /= 10; if (div <= 0) - return ERR_PTR(-EINVAL); - f = freq->m / div; + return -EINVAL; + return freq->m / div; } - - /* - * Look up channel struct and return -EINVAL when - * it cannot be found. - */ - chan = ieee80211_get_channel(wiphy, f); - if (!chan) - return ERR_PTR(-EINVAL); - return chan; } int cfg80211_wext_siwrts(struct net_device *dev, @@ -761,33 +748,29 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); int cfg80211_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, - struct iw_freq *freq, char *extra) + struct iw_freq *wextfreq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); - struct ieee80211_channel *chan; - int err; + int freq, err; switch (wdev->iftype) { case NL80211_IFTYPE_STATION: - return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra); + return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra); case NL80211_IFTYPE_ADHOC: - return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); + return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); default: - chan = cfg80211_wext_freq(wdev->wiphy, freq); - if (!chan) + freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); + if (freq < 0) + return freq; + if (freq == 0) return -EINVAL; - if (IS_ERR(chan)) - return PTR_ERR(chan); - err = rdev->ops->set_channel(wdev->wiphy, chan, - NL80211_CHAN_NO_HT); - if (err) - return err; - rdev->channel = chan; - return 0; + mutex_lock(&rdev->devlist_mtx); + err = rdev_set_freq(rdev, freq, NL80211_CHAN_NO_HT); + mutex_unlock(&rdev->devlist_mtx); + return err; } } -EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); int cfg80211_wext_giwfreq(struct net_device *dev, struct iw_request_info *info, diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h index 9a37747..20b3dae 100644 --- a/net/wireless/wext-compat.h +++ b/net/wireless/wext-compat.h @@ -42,8 +42,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid); -struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, - struct iw_freq *freq); +int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); extern const struct iw_handler_def cfg80211_wext_handler; diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index e4a054a..fe1a536 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -52,25 +52,31 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, int cfg80211_mgd_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, - struct iw_freq *freq, char *extra) + struct iw_freq *wextfreq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); - struct ieee80211_channel *chan; - int err; + struct ieee80211_channel *chan = NULL; + int err, freq; /* call only for station! */ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; - chan = cfg80211_wext_freq(wdev->wiphy, freq); - if (chan && IS_ERR(chan)) - return PTR_ERR(chan); + freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); + if (freq < 0) + return freq; - if (chan && (chan->flags & IEEE80211_CHAN_DISABLED)) - return -EINVAL; + if (freq) { + chan = ieee80211_get_channel(wdev->wiphy, freq); + if (!chan) + return -EINVAL; + if (chan->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + } cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); if (wdev->sme_state != CFG80211_SME_IDLE) { @@ -84,9 +90,8 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, /* if SSID set, we'll try right again, avoid event */ if (wdev->wext.connect.ssid_len) event = false; - err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), - dev, WLAN_REASON_DEAUTH_LEAVING, - event); + err = __cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, event); if (err) goto out; } @@ -95,17 +100,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, wdev->wext.connect.channel = chan; /* SSID is not set, we just want to switch channel */ - if (wdev->wext.connect.ssid_len && chan) { - err = -EOPNOTSUPP; - if (rdev->ops->set_channel) - err = rdev->ops->set_channel(wdev->wiphy, chan, - NL80211_CHAN_NO_HT); + if (chan && !wdev->wext.connect.ssid_len) { + err = rdev_set_freq(rdev, freq, NL80211_CHAN_NO_HT); goto out; } - err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); + err = cfg80211_mgd_wext_connect(rdev, wdev); out: wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); return err; } @@ -143,6 +146,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, struct iw_point *data, char *ssid) { struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); size_t len = data->length; int err; @@ -157,7 +161,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, if (len > 0 && ssid[len - 1] == '\0') len--; - cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); + cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); err = 0; @@ -173,9 +178,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, /* if SSID set now, we'll try to connect, avoid event */ if (len) event = false; - err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), - dev, WLAN_REASON_DEAUTH_LEAVING, - event); + err = __cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, event); if (err) goto out; } @@ -186,10 +190,11 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, wdev->wext.connect.crypto.control_port = false; - err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); + err = cfg80211_mgd_wext_connect(rdev, wdev); out: wdev_unlock(wdev); - cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); + mutex_unlock(&rdev->devlist_mtx); + cfg80211_unlock_rdev(rdev); return err; } @@ -230,6 +235,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, struct sockaddr *ap_addr, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); u8 *bssid = ap_addr->sa_data; int err; @@ -244,7 +250,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) bssid = NULL; - cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); + cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); if (wdev->sme_state != CFG80211_SME_IDLE) { @@ -258,9 +265,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) goto out; - err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), - dev, WLAN_REASON_DEAUTH_LEAVING, - false); + err = __cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, false); if (err) goto out; } @@ -271,10 +277,11 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, } else wdev->wext.connect.bssid = NULL; - err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); + err = cfg80211_mgd_wext_connect(rdev, wdev); out: wdev_unlock(wdev); - cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); + mutex_unlock(&rdev->devlist_mtx); + cfg80211_unlock_rdev(rdev); return err; } -- cgit v0.10.2 From f401a6f7ede753e56b84025e7d2db0d5ef560ce6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 14:51:05 +0200 Subject: cfg80211: use reassociation when possible With the move of everything related to the SME from mac80211 to cfg80211, we lost the ability to send reassociation frames. This adds them back, but only for wireless extensions. With the userspace SME, it shall control assoc vs. reassoc (it already can do so with the nl80211 interface). I haven't touched the connect() implementation, so it is not possible to reassociate with the nl80211 connect primitive. I think that should be done with the NL80211_CMD_ROAM command, but we'll have to see how that can be handled in the future, especially with fullmac chips. This patch addresses only the immediate regression we had in mac80211, which previously sent reassoc. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 64df51d..1ee30fc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1335,10 +1335,10 @@ struct wireless_dev { struct cfg80211_cached_keys *keys; u8 *ie; size_t ie_len; - u8 bssid[ETH_ALEN]; + u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; s8 default_key, default_mgmt_key; - bool ps; + bool ps, prev_bssid_valid; int ps_timeout; } wext; #endif diff --git a/net/wireless/core.h b/net/wireless/core.h index 5696b95..92e0492 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -335,7 +335,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, int __cfg80211_connect(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_connect_params *connect, - struct cfg80211_cached_keys *connkeys); + struct cfg80211_cached_keys *connkeys, + const u8 *prev_bssid); int cfg80211_connect(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_connect_params *connect, @@ -353,6 +354,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); void cfg80211_conn_work(struct work_struct *work); +bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); /* internal helpers */ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 51d5df6..da64071 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -67,6 +67,16 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); + /* + * This is a bit of a hack, we don't notify userspace of + * a (re-)association reply if we tried to send a reassoc + * and got a reject -- we only try again with an assoc + * frame instead of reassoc. + */ + if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && + cfg80211_sme_failed_reassoc(wdev)) + goto out; + nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); if (status_code == WLAN_STATUS_SUCCESS) { @@ -97,6 +107,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) cfg80211_put_bss(&bss->pub); } + out: wdev_unlock(wdev); } EXPORT_SYMBOL(cfg80211_send_rx_assoc); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 219c3bc..104b33e 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -27,10 +27,10 @@ struct cfg80211_conn { CFG80211_CONN_ASSOCIATE_NEXT, CFG80211_CONN_ASSOCIATING, } state; - u8 bssid[ETH_ALEN]; + u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; u8 *ie; size_t ie_len; - bool auto_auth; + bool auto_auth, prev_bssid_valid; }; @@ -110,6 +110,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); struct cfg80211_connect_params *params; + const u8 *prev_bssid = NULL; int err; ASSERT_WDEV_LOCK(wdev); @@ -135,15 +136,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) case CFG80211_CONN_ASSOCIATE_NEXT: BUG_ON(!rdev->ops->assoc); wdev->conn->state = CFG80211_CONN_ASSOCIATING; - /* - * We could, later, implement roaming here and then actually - * set prev_bssid to non-NULL. But then we need to be aware - * that some APs don't like that -- so we'd need to retry - * the association. - */ + if (wdev->conn->prev_bssid_valid) + prev_bssid = wdev->conn->prev_bssid; err = __cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel, params->bssid, - NULL, + prev_bssid, params->ssid, params->ssid_len, params->ie, params->ie_len, false, ¶ms->crypto); @@ -316,6 +313,28 @@ void cfg80211_sme_rx_auth(struct net_device *dev, } } +bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev) +{ + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + if (WARN_ON(!wdev->conn)) + return false; + + if (!wdev->conn->prev_bssid_valid) + return false; + + /* + * Some stupid APs don't accept reassoc, so we + * need to fall back to trying regular assoc. + */ + wdev->conn->prev_bssid_valid = false; + wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; + schedule_work(&rdev->conn_work); + + return true; +} + void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, const u8 *req_ie, size_t req_ie_len, const u8 *resp_ie, size_t resp_ie_len, @@ -359,8 +378,11 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, memset(&wrqu, 0, sizeof(wrqu)); wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if (bssid && status == WLAN_STATUS_SUCCESS) + if (bssid && status == WLAN_STATUS_SUCCESS) { memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); + memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); + wdev->wext.prev_bssid_valid = true; + } wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); } #endif @@ -511,6 +533,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, memset(&wrqu, 0, sizeof(wrqu)); wrqu.ap_addr.sa_family = ARPHRD_ETHER; memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); + memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); + wdev->wext.prev_bssid_valid = true; wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); #endif } @@ -643,7 +667,8 @@ EXPORT_SYMBOL(cfg80211_disconnected); int __cfg80211_connect(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_connect_params *connect, - struct cfg80211_cached_keys *connkeys) + struct cfg80211_cached_keys *connkeys, + const u8 *prev_bssid) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct ieee80211_channel *chan; @@ -742,6 +767,11 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, wdev->sme_state = CFG80211_SME_CONNECTING; wdev->connect_keys = connkeys; + if (prev_bssid) { + memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN); + wdev->conn->prev_bssid_valid = true; + } + /* we're good if we have both BSSID and channel */ if (wdev->conn->params.bssid && wdev->conn->params.channel) { wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; @@ -794,7 +824,7 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, mutex_lock(&rdev->devlist_mtx); wdev_lock(dev->ieee80211_ptr); - err = __cfg80211_connect(rdev, dev, connect, connkeys); + err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL); wdev_unlock(dev->ieee80211_ptr); mutex_unlock(&rdev->devlist_mtx); diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index fe1a536..9074700 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -15,6 +15,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev) { struct cfg80211_cached_keys *ck = NULL; + const u8 *prev_bssid = NULL; int err, i; ASSERT_RDEV_LOCK(rdev); @@ -42,8 +43,12 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, for (i = 0; i < 6; i++) ck->params[i].key = ck->data[i]; } + + if (wdev->wext.prev_bssid_valid) + prev_bssid = wdev->wext.prev_bssid; + err = __cfg80211_connect(rdev, wdev->netdev, - &wdev->wext.connect, ck); + &wdev->wext.connect, ck, prev_bssid); if (err) kfree(ck); @@ -184,6 +189,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, goto out; } + wdev->wext.prev_bssid_valid = false; wdev->wext.connect.ssid = wdev->wext.ssid; memcpy(wdev->wext.ssid, ssid, len); wdev->wext.connect.ssid_len = len; -- cgit v0.10.2 From f5ea9120be2e5d5c846243416cfdce01d02f5836 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 16:17:38 +0200 Subject: nl80211: add generation number to all dumps In order for userspace to be able to figure out whether it obtained a consistent snapshot of data or not when using netlink dumps, we need to have a generation number in each dump message that indicates whether the list has changed or not -- its value is arbitrary. This patch adds such a number to all dumps, this needs some mac80211 involvement to keep track of a generation number to start with when adding/removing mesh paths or stations. The wiphy and netdev lists can be fully handled within cfg80211, of course, but generation numbers need to be stored there as well. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index cb3dc60..a8d71ed 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -480,10 +480,6 @@ enum nl80211_commands { * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive * scanning and include a zero-length SSID (wildcard) for wildcard scan - * @NL80211_ATTR_SCAN_GENERATION: the scan generation increases whenever the - * scan result list changes (BSS expired or added) so that applications - * can verify that they got a single, consistent snapshot (when all dump - * messages carried the same generation number) * @NL80211_ATTR_BSS: scan result BSS * * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain @@ -580,6 +576,14 @@ enum nl80211_commands { * * @NL80211_ATTR_PID: Process ID of a network namespace. * + * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for + * dumps. This number increases whenever the object list being + * dumped changes, and as such userspace can verify that it has + * obtained a complete and consistent snapshot by verifying that + * all dump messages contain the same generation number. If it + * changed then the list changed and the dump should be repeated + * completely from scratch. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -651,7 +655,7 @@ enum nl80211_attrs { NL80211_ATTR_SCAN_FREQUENCIES, NL80211_ATTR_SCAN_SSIDS, - NL80211_ATTR_SCAN_GENERATION, + NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */ NL80211_ATTR_BSS, NL80211_ATTR_REG_INITIATOR, @@ -716,6 +720,9 @@ enum nl80211_attrs { NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 }; +/* source-level API compatibility */ +#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION + /* * Allow user space programs to use #ifdef on new attributes by defining them * here diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1ee30fc..de7d116 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -372,6 +372,10 @@ struct rate_info { * @txrate: current unicast bitrate to this station * @rx_packets: packets received from this station * @tx_packets: packets transmitted to this station + * @generation: generation number for nl80211 dumps. + * This number should increase every time the list of stations + * changes, i.e. when a station is added or removed, so that + * userspace can tell whether it got a consistent snapshot. */ struct station_info { u32 filled; @@ -385,6 +389,8 @@ struct station_info { struct rate_info txrate; u32 rx_packets; u32 tx_packets; + + int generation; }; /** @@ -444,6 +450,10 @@ enum mpath_info_flags { * @flags: mesh path flags * @discovery_timeout: total mesh path discovery timeout, in msecs * @discovery_retries: mesh path discovery retries + * @generation: generation number for nl80211 dumps. + * This number should increase every time the list of mesh paths + * changes, i.e. when a station is added or removed, so that + * userspace can tell whether it got a consistent snapshot. */ struct mpath_info { u32 filled; @@ -454,6 +464,8 @@ struct mpath_info { u32 discovery_timeout; u8 discovery_retries; u8 flags; + + int generation; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4bbf500..5608f6c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -323,6 +323,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = sta->sdata; + sinfo->generation = sdata->local->sta_generation; + sinfo->filled = STATION_INFO_INACTIVE_TIME | STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | @@ -909,6 +911,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, else memset(next_hop, 0, ETH_ALEN); + pinfo->generation = mesh_paths_generation; + pinfo->filled = MPATH_INFO_FRAME_QLEN | MPATH_INFO_DSN | MPATH_INFO_METRIC | diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9895917..9943322 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -678,6 +678,7 @@ struct ieee80211_local { struct list_head sta_list; struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; + int sta_generation; struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; struct tasklet_struct tx_pending_tasklet; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2a2ed18..ce53881 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -265,6 +265,8 @@ void mesh_path_discard_frame(struct sk_buff *skb, void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); void mesh_path_restart(struct ieee80211_sub_if_data *sdata); +extern int mesh_paths_generation; + #ifdef CONFIG_MAC80211_MESH extern int mesh_allocated; diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 04b9e4d..431865a 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -38,6 +38,8 @@ struct mpath_node { static struct mesh_table *mesh_paths; static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ +int mesh_paths_generation; + /* This lock will have the grow table function as writer and add / delete nodes * as readers. When reading the table (i.e. doing lookups) we are well protected * by RCU @@ -243,6 +245,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) grow = 1; + mesh_paths_generation++; + spin_unlock(&mesh_paths->hashwlock[hash_idx]); read_unlock(&pathtbl_resize_lock); if (grow) { @@ -484,6 +488,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) err = -ENXIO; enddel: + mesh_paths_generation++; spin_unlock(&mesh_paths->hashwlock[hash_idx]); read_unlock(&pathtbl_resize_lock); return err; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a360bce..eec0014 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -349,6 +349,7 @@ int sta_info_insert(struct sta_info *sta) goto out_free; } list_add(&sta->list, &local->sta_list); + local->sta_generation++; local->num_sta++; sta_info_hash_add(local, sta); @@ -485,6 +486,7 @@ static void __sta_info_unlink(struct sta_info **sta) } local->num_sta--; + local->sta_generation++; if (local->ops->sta_notify) { if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) diff --git a/net/wireless/core.c b/net/wireless/core.c index 1e18930..62e1ac0 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -32,6 +32,7 @@ MODULE_DESCRIPTION("wireless configuration support"); * only read the list, and that can happen quite * often because we need to do it for each command */ LIST_HEAD(cfg80211_rdev_list); +int cfg80211_rdev_list_generation; /* * This is used to protect the cfg80211_rdev_list @@ -511,6 +512,7 @@ int wiphy_register(struct wiphy *wiphy) wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); list_add(&rdev->list, &cfg80211_rdev_list); + cfg80211_rdev_list_generation++; mutex_unlock(&cfg80211_mutex); @@ -593,6 +595,7 @@ void wiphy_unregister(struct wiphy *wiphy) reg_device_remove(wiphy); list_del(&rdev->list); + cfg80211_rdev_list_generation++; device_del(&rdev->wiphy.dev); debugfs_remove(rdev->wiphy.debugfsdir); @@ -653,6 +656,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, spin_lock_init(&wdev->event_lock); mutex_lock(&rdev->devlist_mtx); list_add(&wdev->list, &rdev->netdev_list); + rdev->devlist_generation++; /* can only change netns with wiphy */ dev->features |= NETIF_F_NETNS_LOCAL; @@ -733,6 +737,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, if (!list_empty(&wdev->list)) { sysfs_remove_link(&dev->dev.kobj, "phy80211"); list_del_init(&wdev->list); + rdev->devlist_generation++; mutex_destroy(&wdev->mtx); #ifdef CONFIG_WIRELESS_EXT kfree(wdev->wext.keys); diff --git a/net/wireless/core.h b/net/wireless/core.h index 92e0492..639db52 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -49,6 +49,7 @@ struct cfg80211_registered_device { /* associate netdev list */ struct mutex devlist_mtx; struct list_head netdev_list; + int devlist_generation; /* BSSes/scanning */ spinlock_t bss_lock; @@ -101,6 +102,7 @@ bool wiphy_idx_valid(int wiphy_idx) extern struct mutex cfg80211_mutex; extern struct list_head cfg80211_rdev_list; +extern int cfg80211_rdev_list_generation; #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2ff7376..b3d5c1d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -408,6 +408,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, + cfg80211_rdev_list_generation); + NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, dev->wiphy.retry_short); NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, @@ -825,6 +828,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); + + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, + rdev->devlist_generation ^ + (cfg80211_rdev_list_generation << 2)); + return genlmsg_end(msg, hdr); nla_put_failure: @@ -838,12 +846,12 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * int if_idx = 0; int wp_start = cb->args[0]; int if_start = cb->args[1]; - struct cfg80211_registered_device *dev; + struct cfg80211_registered_device *rdev; struct wireless_dev *wdev; mutex_lock(&cfg80211_mutex); - list_for_each_entry(dev, &cfg80211_rdev_list, list) { - if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) continue; if (wp_idx < wp_start) { wp_idx++; @@ -851,21 +859,21 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * } if_idx = 0; - mutex_lock(&dev->devlist_mtx); - list_for_each_entry(wdev, &dev->netdev_list, list) { + mutex_lock(&rdev->devlist_mtx); + list_for_each_entry(wdev, &rdev->netdev_list, list) { if (if_idx < if_start) { if_idx++; continue; } if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - dev, wdev->netdev) < 0) { - mutex_unlock(&dev->devlist_mtx); + rdev, wdev->netdev) < 0) { + mutex_unlock(&rdev->devlist_mtx); goto out; } if_idx++; } - mutex_unlock(&dev->devlist_mtx); + mutex_unlock(&rdev->devlist_mtx); wp_idx++; } @@ -1616,6 +1624,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, sinfo->generation); + sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); if (!sinfoattr) goto nla_put_failure; @@ -2101,6 +2111,8 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, pinfo->generation); + pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); if (!pinfoattr) goto nla_put_failure; @@ -3090,8 +3102,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, if (!hdr) return -1; - NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION, - rdev->bss_generation); + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); bss = nla_nest_start(msg, NL80211_ATTR_BSS); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0ccf3a0..1bcb131 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -562,6 +562,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) spin_lock_bh(&dev->bss_lock); list_del(&bss->list); + dev->bss_generation++; rb_erase(&bss->rbn, &dev->bss_tree); spin_unlock_bh(&dev->bss_lock); -- cgit v0.10.2 From c555b9b3713e05586fabe85f4e46f28859e72930 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 16:23:43 +0200 Subject: mac80211: explain TX retry and status Add some more documentation including an example so that it's clearer what should be done for TX retries. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e2fb576..467eed7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -338,6 +338,21 @@ enum mac80211_rate_control_flags { * * When used for transmit status reporting, the driver should * always report the rate along with the flags it used. + * + * &struct ieee80211_tx_info contains an array of these structs + * in the control information, and it will be filled by the rate + * control algorithm according to what should be sent. For example, + * if this array contains, in the format { , } the + * information + * { 3, 2 }, { 2, 2 }, { 1, 4 }, { -1, 0 }, { -1, 0 } + * then this means that the frame should be transmitted + * up to twice at rate 3, up to twice at rate 2, and up to four + * times at rate 1 if it doesn't get acknowledged. Say it gets + * acknowledged by the peer after the fifth attempt, the status + * information should then contain + * { 3, 2 }, { 2, 2 }, { 1, 1 }, { -1, 0 } ... + * since it was transmitted twice at rate 3, twice at rate 2 + * and once at rate 1 after which we received an acknowledgement. */ struct ieee80211_tx_rate { s8 idx; -- cgit v0.10.2 From ab5b5342fd0ba5b9a2f58a94c5d41dd074b7c48e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 16:28:09 +0200 Subject: mac80211: document TX powersave filter requirements This documents what's required to implement that TX powersave filter properly wrt. handling hardware queues. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 467eed7..cd4eb20 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -239,7 +239,14 @@ struct ieee80211_bss_conf { * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211. * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted - * because the destination STA was in powersave mode. + * because the destination STA was in powersave mode. Note that to + * avoid race conditions, the filter must be set by the hardware or + * firmware upon receiving a frame that indicates that the station + * went to sleep (must be done on device to filter frames already on + * the queue) and may only be unset after mac80211 gives the OK for + * that by setting the IEEE80211_TX_CTL_CLEAR_PS_FILT (see above), + * since only then is it guaranteed that no more frames are in the + * hardware queue. * @IEEE80211_TX_STAT_ACK: Frame was acknowledged * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status * is for the whole aggregation. -- cgit v0.10.2 From ad5351db89681515681c5d5659ddf4c69e3cc6f5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 16:42:15 +0200 Subject: mac80211: allow DMA optimisation If we have a lot of frames to transmit at once, for instance with fragmentation, it can be an optimisation to only tell the DMA engine about them on the last fragment/frame to avoid banging the IO too much. This patch allows implementation such an optimisation by telling the driver when more frames can be expected. Currently, this is used by mac80211 only on fragmented frames, but could also be used in the future on other frames when the queue was full and there are multiple frames pending. Note that drivers need to be careful when using this flag, they need to kick their DMA engines not just when this flag is clear, but also when the queue gets full so that progress can be made. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index cd4eb20..76d43e1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -268,6 +268,10 @@ struct ieee80211_bss_conf { * @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?) * This frame is a response to a PS-poll frame and should be sent * although the station is in powersave mode. + * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the + * transmit function after the current frame, this can be used + * by drivers to kick the DMA queue only if unset or when the + * queue gets full. */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), @@ -288,6 +292,7 @@ enum mac80211_tx_control_flags { IEEE80211_TX_INTFL_RETRIED = BIT(15), IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), IEEE80211_TX_CTL_PSPOLL_RESPONSE = BIT(17), + IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), }; /** diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7cffaa0..7f2e4cd 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1154,6 +1154,9 @@ static int __ieee80211_tx(struct ieee80211_local *local, next = skb->next; len = skb->len; + if (next) + info->flags |= IEEE80211_TX_CTL_MORE_FRAMES; + sdata = vif_to_sdata(info->control.vif); switch (sdata->vif.type) { -- cgit v0.10.2 From 5ba63533bbf653631faab60f6988506160ec6ba4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 17:54:07 +0200 Subject: cfg80211: fix alignment problem in scan request The memory layout for scan requests was rather wrong, we put the scan SSIDs before the channels which could lead to the channel pointers being unaligned in memory. It turns out that using a pointer to the channel array isn't necessary anyway since we can embed a zero-length array into the struct. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index de7d116..d5756c9 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -559,7 +559,6 @@ struct cfg80211_ssid { struct cfg80211_scan_request { struct cfg80211_ssid *ssids; int n_ssids; - struct ieee80211_channel **channels; u32 n_channels; const u8 *ie; size_t ie_len; @@ -568,6 +567,9 @@ struct cfg80211_scan_request { struct wiphy *wiphy; struct net_device *dev; bool aborted; + + /* keep last */ + struct ieee80211_channel *channels[0]; }; /** diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9943322..d6bd7dd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -715,7 +715,7 @@ struct ieee80211_local { struct mutex scan_mtx; unsigned long scanning; struct cfg80211_ssid scan_ssid; - struct cfg80211_scan_request int_scan_req; + struct cfg80211_scan_request *int_scan_req; struct cfg80211_scan_request *scan_req; struct ieee80211_channel *scan_channel; const u8 *orig_ies; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0c4f8e1..b03fd84 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -765,9 +765,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) supp_ht = supp_ht || sband->ht_cap.ht_supported; } - local->int_scan_req.n_channels = channels; - local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL); - if (!local->int_scan_req.channels) + local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + + sizeof(void *) * channels, GFP_KERNEL); + if (!local->int_scan_req) return -ENOMEM; /* if low-level driver supports AP, we also support VLAN */ @@ -882,13 +882,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) /* alloc internal scan request */ i = 0; - local->int_scan_req.ssids = &local->scan_ssid; - local->int_scan_req.n_ssids = 1; + local->int_scan_req->ssids = &local->scan_ssid; + local->int_scan_req->n_ssids = 1; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (!hw->wiphy->bands[band]) continue; for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { - local->int_scan_req.channels[i] = + local->int_scan_req->channels[i] = &hw->wiphy->bands[band]->channels[j]; i++; } @@ -920,7 +920,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) fail_workqueue: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: - kfree(local->int_scan_req.channels); + kfree(local->int_scan_req->channels); return result; } EXPORT_SYMBOL(ieee80211_register_hw); @@ -962,7 +962,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); ieee80211_led_exit(local); - kfree(local->int_scan_req.channels); + kfree(local->int_scan_req); } EXPORT_SYMBOL(ieee80211_unregister_hw); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 244f53f..e091cbc 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -277,7 +277,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (test_bit(SCAN_HW_SCANNING, &local->scanning)) ieee80211_restore_scan_ies(local); - if (local->scan_req != &local->int_scan_req) + if (local->scan_req != local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; @@ -423,7 +423,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, local->scan_req = req; local->scan_sdata = sdata; - if (req != &local->int_scan_req && + if (req != local->int_scan_req && sdata->vif.type == NL80211_IFTYPE_STATION && !list_empty(&ifmgd->work_list)) { /* actually wait for the work it's doing to finish/time out */ @@ -743,10 +743,10 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, if (local->scan_req) goto unlock; - memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); - local->int_scan_req.ssids[0].ssid_len = ssid_len; + memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); + local->int_scan_req->ssids[0].ssid_len = ssid_len; - ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req); + ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req); unlock: mutex_unlock(&local->scan_mtx); return ret; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b3d5c1d..667a87d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3002,10 +3002,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) goto out; } - request->channels = (void *)((char *)request + sizeof(*request)); request->n_channels = n_channels; if (n_ssids) - request->ssids = (void *)(request->channels + n_channels); + request->ssids = (void *)&request->channels[n_channels]; request->n_ssids = n_ssids; if (ie_len) { if (request->ssids) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 1bcb131..e6c1f11 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -612,8 +612,8 @@ int cfg80211_wext_siwscan(struct net_device *dev, creq->wiphy = wiphy; creq->dev = dev; - creq->ssids = (void *)(creq + 1); - creq->channels = (void *)(creq->ssids + 1); + /* SSIDs come after channels */ + creq->ssids = (void *)&creq->channels[n_channels]; creq->n_channels = n_channels; creq->n_ssids = 1; diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 104b33e..8e2ef54 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -65,7 +65,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) if (!request) return -ENOMEM; - request->channels = (void *)((char *)request + sizeof(*request)); if (wdev->conn->params.channel) request->channels[0] = wdev->conn->params.channel; else { @@ -82,7 +81,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) } } request->n_channels = n_channels; - request->ssids = (void *)(request->channels + n_channels); + request->ssids = (void *)&request->channels[n_channels]; request->n_ssids = 1; memcpy(request->ssids[0].ssid, wdev->conn->params.ssid, -- cgit v0.10.2 From 66d2d089c394c7e31020947d682523f77a93244b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 6 Aug 2009 10:36:50 +0200 Subject: b43: Fix hardware key index handling This fixes the hardware encryption keys index and array size handling. Thanks to Gregor Kowski for reporting this issue. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 102094a..a1b3b73 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -493,6 +493,10 @@ enum { /* Max size of a security key */ #define B43_SEC_KEYSIZE 16 +/* Max number of group keys */ +#define B43_NR_GROUP_KEYS 4 +/* Max number of pairwise keys */ +#define B43_NR_PAIRWISE_KEYS 50 /* Security algorithms. */ enum { B43_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ @@ -819,8 +823,7 @@ struct b43_wldev { /* encryption/decryption */ u16 ktp; /* Key table pointer */ - u8 max_nr_keys; - struct b43_key key[58]; + struct b43_key key[B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS]; /* Firmware data */ struct b43_firmware fw; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 997dd55..950beef 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -796,18 +796,19 @@ static void key_write(struct b43_wldev *dev, static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) { u32 addrtmp[2] = { 0, 0, }; - u8 per_sta_keys_start = 8; + u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2; if (b43_new_kidx_api(dev)) - per_sta_keys_start = 4; + pairwise_keys_start = B43_NR_GROUP_KEYS; - B43_WARN_ON(index < per_sta_keys_start); - /* We have two default TX keys and possibly two default RX keys. + B43_WARN_ON(index < pairwise_keys_start); + /* We have four default TX keys and possibly four default RX keys. * Physical mac 0 is mapped to physical key 4 or 8, depending * on the firmware version. * So we must adjust the index here. */ - index -= per_sta_keys_start; + index -= pairwise_keys_start; + B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS); if (addr) { addrtmp[0] = addr[0]; @@ -818,27 +819,11 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) addrtmp[1] |= ((u32) (addr[5]) << 8); } - if (dev->dev->id.revision >= 5) { - /* Receive match transmitter address mechanism */ - b43_shm_write32(dev, B43_SHM_RCMTA, - (index * 2) + 0, addrtmp[0]); - b43_shm_write16(dev, B43_SHM_RCMTA, - (index * 2) + 1, addrtmp[1]); - } else { - /* RXE (Receive Engine) and - * PSM (Programmable State Machine) mechanism - */ - if (index < 8) { - /* TODO write to RCM 16, 19, 22 and 25 */ - } else { - b43_shm_write32(dev, B43_SHM_SHARED, - B43_SHM_SH_PSM + (index * 6) + 0, - addrtmp[0]); - b43_shm_write16(dev, B43_SHM_SHARED, - B43_SHM_SH_PSM + (index * 6) + 4, - addrtmp[1]); - } - } + /* Receive match transmitter address (RCMTA) mechanism */ + b43_shm_write32(dev, B43_SHM_RCMTA, + (index * 2) + 0, addrtmp[0]); + b43_shm_write16(dev, B43_SHM_RCMTA, + (index * 2) + 1, addrtmp[1]); } static void do_key_write(struct b43_wldev *dev, @@ -846,20 +831,20 @@ static void do_key_write(struct b43_wldev *dev, const u8 *key, size_t key_len, const u8 *mac_addr) { u8 buf[B43_SEC_KEYSIZE] = { 0, }; - u8 per_sta_keys_start = 8; + u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2; if (b43_new_kidx_api(dev)) - per_sta_keys_start = 4; + pairwise_keys_start = B43_NR_GROUP_KEYS; - B43_WARN_ON(index >= dev->max_nr_keys); + B43_WARN_ON(index >= ARRAY_SIZE(dev->key)); B43_WARN_ON(key_len > B43_SEC_KEYSIZE); - if (index >= per_sta_keys_start) + if (index >= pairwise_keys_start) keymac_write(dev, index, NULL); /* First zero out mac. */ if (key) memcpy(buf, key, key_len); key_write(dev, index, algorithm, buf); - if (index >= per_sta_keys_start) + if (index >= pairwise_keys_start) keymac_write(dev, index, mac_addr); dev->key[index].algorithm = algorithm; @@ -872,21 +857,24 @@ static int b43_key_write(struct b43_wldev *dev, struct ieee80211_key_conf *keyconf) { int i; - int sta_keys_start; + int pairwise_keys_start; if (key_len > B43_SEC_KEYSIZE) return -EINVAL; - for (i = 0; i < dev->max_nr_keys; i++) { + for (i = 0; i < ARRAY_SIZE(dev->key); i++) { /* Check that we don't already have this key. */ B43_WARN_ON(dev->key[i].keyconf == keyconf); } if (index < 0) { /* Pairwise key. Get an empty slot for the key. */ if (b43_new_kidx_api(dev)) - sta_keys_start = 4; + pairwise_keys_start = B43_NR_GROUP_KEYS; else - sta_keys_start = 8; - for (i = sta_keys_start; i < dev->max_nr_keys; i++) { + pairwise_keys_start = B43_NR_GROUP_KEYS * 2; + for (i = pairwise_keys_start; + i < pairwise_keys_start + B43_NR_PAIRWISE_KEYS; + i++) { + B43_WARN_ON(i >= ARRAY_SIZE(dev->key)); if (!dev->key[i].keyconf) { /* found empty */ index = i; @@ -914,7 +902,7 @@ static int b43_key_write(struct b43_wldev *dev, static int b43_key_clear(struct b43_wldev *dev, int index) { - if (B43_WARN_ON((index < 0) || (index >= dev->max_nr_keys))) + if (B43_WARN_ON((index < 0) || (index >= ARRAY_SIZE(dev->key)))) return -EINVAL; do_key_write(dev, index, B43_SEC_ALGO_NONE, NULL, B43_SEC_KEYSIZE, NULL); @@ -929,15 +917,19 @@ static int b43_key_clear(struct b43_wldev *dev, int index) static void b43_clear_keys(struct b43_wldev *dev) { - int i; + int i, count; - for (i = 0; i < dev->max_nr_keys; i++) + if (b43_new_kidx_api(dev)) + count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS; + else + count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS; + for (i = 0; i < count; i++) b43_key_clear(dev, i); } static void b43_dump_keymemory(struct b43_wldev *dev) { - unsigned int i, index, offset; + unsigned int i, index, count, offset, pairwise_keys_start; u8 mac[ETH_ALEN]; u16 algo; u32 rcmta0; @@ -951,7 +943,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev) hf = b43_hf_read(dev); b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n", !!(hf & B43_HF_USEDEFKEYS)); - for (index = 0; index < dev->max_nr_keys; index++) { + if (b43_new_kidx_api(dev)) { + pairwise_keys_start = B43_NR_GROUP_KEYS; + count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS; + } else { + pairwise_keys_start = B43_NR_GROUP_KEYS * 2; + count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS; + } + for (index = 0; index < count; index++) { key = &(dev->key[index]); printk(KERN_DEBUG "Key slot %02u: %s", index, (key->keyconf == NULL) ? " " : "*"); @@ -965,11 +964,11 @@ static void b43_dump_keymemory(struct b43_wldev *dev) B43_SHM_SH_KEYIDXBLOCK + (index * 2)); printk(" Algo: %04X/%02X", algo, key->algorithm); - if (index >= 4) { + if (index >= pairwise_keys_start) { rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, - ((index - 4) * 2) + 0); + ((index - pairwise_keys_start) * 2) + 0); rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, - ((index - 4) * 2) + 1); + ((index - pairwise_keys_start) * 2) + 1); *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0); *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1); printk(" MAC: %pM", mac); @@ -2876,17 +2875,14 @@ error: static void b43_security_init(struct b43_wldev *dev) { - dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20; - B43_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key)); dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP); /* KTP is a word address, but we address SHM bytewise. * So multiply by two. */ dev->ktp *= 2; - if (dev->dev->id.revision >= 5) { - /* Number of RCMTA address slots */ - b43_write16(dev, B43_MMIO_RCMTA_COUNT, dev->max_nr_keys - 8); - } + /* Number of RCMTA address slots */ + b43_write16(dev, B43_MMIO_RCMTA_COUNT, B43_NR_PAIRWISE_KEYS); + /* Clear the key memory. */ b43_clear_keys(dev); } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 5b85e7d..5280ebc 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -237,7 +237,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, int wlhdr_len; size_t iv_len; - B43_WARN_ON(key_idx >= dev->max_nr_keys); + B43_WARN_ON(key_idx >= ARRAY_SIZE(dev->key)); key = &(dev->key[key_idx]); if (unlikely(!key->keyconf)) { @@ -578,7 +578,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) * key index, but the ucode passed it slightly different. */ keyidx = b43_kidx_to_raw(dev, keyidx); - B43_WARN_ON(keyidx >= dev->max_nr_keys); + B43_WARN_ON(keyidx >= ARRAY_SIZE(dev->key)); if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) { wlhdr_len = ieee80211_hdrlen(fctl); -- cgit v0.10.2 From 718126a75e5fd4c6df6ee0567f00c7345b2370f4 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 7 Aug 2009 19:38:51 +0200 Subject: p54: Write outside array bounds This patch fixes a coding error which allowed the to upper-layer to corrupt limited portions of the phy data. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index a0d0e72..b99ee9b 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -317,7 +317,7 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, int ret; mutex_lock(&priv->conf_mutex); - if ((params) && !(queue > 4)) { + if (queue < dev->queues) { P54_SET_QUEUE(priv->qos_params[queue], params->aifs, params->cw_min, params->cw_max, params->txop); ret = p54_set_edcf(priv); -- cgit v0.10.2 From 6208f8b22cb24e446f24eb9f4aa9f4c3a9a1d52e Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 7 Aug 2009 19:39:05 +0200 Subject: p54: implement rfkill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch implements a basic rfkill support for p54 hardware and removes a rfkill related WARNING: fwio.c: In function ‘p54_setup_mac’: fwio.c:323: warning: ‘radio_enabled’ is deprecated. by abandoning radio_enable in flavour for IEEE80211_CONF_CHANGE_IDLE. Tested-by: Larry Finger Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 21f1901..e7b9e9c 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -320,7 +320,7 @@ int p54_setup_mac(struct p54_common *priv) return -ENOMEM; setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); - if (priv->hw->conf.radio_enabled) { + if (!(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) { switch (priv->mode) { case NL80211_IFTYPE_STATION: mode = P54_FILTER_TYPE_STATION; @@ -348,8 +348,9 @@ int p54_setup_mac(struct p54_common *priv) (priv->filter_flags & FIF_OTHER_BSS)) && (mode != P54_FILTER_TYPE_PROMISCUOUS)) mode |= P54_FILTER_TYPE_TRANSPARENT; - } else + } else { mode = P54_FILTER_TYPE_HIBERNATE; + } setup->mac_mode = cpu_to_le16(mode); memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index b99ee9b..4a741df 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -288,6 +288,11 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) if (ret) goto out; } + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + ret = p54_setup_mac(priv); + if (ret) + goto out; + } out: mutex_unlock(&priv->conf_mutex); diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 704685f..6fc0b61 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -552,6 +552,12 @@ static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb) break; case P54_TRAP_TIMER: break; + case P54_TRAP_FAA_RADIO_OFF: + wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); + break; + case P54_TRAP_FAA_RADIO_ON: + wiphy_rfkill_set_hw_state(priv->hw->wiphy, false); + break; default: printk(KERN_INFO "%s: received event:%x freq:%d\n", wiphy_name(priv->hw->wiphy), event, freq); -- cgit v0.10.2 From 34b921cf6fb4014e0e8d414492959a4725049000 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 7 Aug 2009 13:16:15 -0700 Subject: MAINTAINERS: NETWORKING [WIRELESS] additional patterns Added file patterns drivers/net/wireless and net/mac80211 (and net/rfkill -- JWL) Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index 22af496..7b10f42 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3583,9 +3583,12 @@ M: "John W. Linville" L: linux-wireless@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git S: Maintained +F: net/mac80211/ +F: net/rfkill/ F: net/wireless/ F: include/net/ieee80211* F: include/linux/wireless.h +F: drivers/net/wireless/ NETWORKING DRIVERS L: netdev@vger.kernel.org -- cgit v0.10.2 From 3d816c77ecb05d3a3e974a205e53392e5353553e Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 7 Aug 2009 15:41:37 -0700 Subject: iwlwifi: re-introduce per device debugging Commit "iwlwifi: make debug level more user friendly" cleaned up the debug level handling. In doing so it created a single global debug level for all devices. Some setups do consits of more that one iwlwifi device and in these setups there is a requirement that debug levels should be unique per device. We now re-introduce the per device debugging while maintaining the cleanup effort of the previous patch. The maintain the global debug level and now introduce a per-device debug level that will be used if it (the per-device debug level) is set. The per-device debug level can be controlled via the debug_level sysfs file while the global debug level is controlled by the debug module parameter. Signed-off-by: Reinette Chatre Acked-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e1b0ef3..7ad0207 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -502,14 +502,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(IWL_DL_RX, data, length); + iwl_print_hex_dump(priv, IWL_DL_RX, data, length); } static void iwl3945_dbg_report_frame(struct iwl_priv *priv, struct iwl_rx_packet *pkt, struct ieee80211_hdr *header, int group100) { - if (iwl_debug_level & IWL_DL_RX) + if (iwl_get_debug_level(priv) & IWL_DL_RX) _iwl3945_dbg_report_frame(priv, pkt, header, group100); } diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 6702148..62436a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -46,7 +46,7 @@ #include "iwl-sta.h" static int iwl4965_send_tx_power(struct iwl_priv *priv); -static int iwl4965_hw_get_temperature(const struct iwl_priv *priv); +static int iwl4965_hw_get_temperature(struct iwl_priv *priv); /* Highest firmware API version supported */ #define IWL4965_UCODE_API_MAX 2 @@ -1680,7 +1680,7 @@ static s32 sign_extend(u32 oper, int index) * * A return of <0 indicates bogus data in the statistics */ -static int iwl4965_hw_get_temperature(const struct iwl_priv *priv) +static int iwl4965_hw_get_temperature(struct iwl_priv *priv) { s32 temperature; s32 vt; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index db580cb..24c1ae6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -896,7 +896,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { + if (iwl_get_debug_level(priv) & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -931,7 +931,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -1045,7 +1045,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -1076,7 +1076,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) inta = priv->inta; #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { + if (iwl_get_debug_level(priv) & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", @@ -1104,7 +1104,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -2455,15 +2455,15 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, * * See the level definitions in iwl for details. * - * FIXME This file can be deprecated as the module parameter is - * writable and users can thus also change the debug level - * using the /sys/module/iwl3945/parameters/debug file. + * The debug_level being managed using sysfs below is a per device debug + * level that is used instead of the global debug level if it (the per + * device debug level) is set. */ - static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - return sprintf(buf, "0x%08X\n", iwl_debug_level); + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); } static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, @@ -2477,7 +2477,7 @@ static ssize_t store_debug_level(struct device *d, if (ret) IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); else - iwl_debug_level = val; + priv->debug_level = val; return strnlen(buf, count); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2ffbd27..30f1953 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1278,7 +1278,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) struct iwl_rxon_cmd *rxon = &priv->staging_rxon; IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); - iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n", @@ -1508,7 +1508,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_FW_ERRORS) { + if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) { iwl_dump_nic_error_log(priv); iwl_dump_nic_event_log(priv); iwl_print_rx_config_cmd(priv); @@ -1985,7 +1985,7 @@ static irqreturn_t iwl_isr(int irq, void *data) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " "fh 0x%08x\n", inta, inta_mask, inta_fh); @@ -2310,7 +2310,7 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " "notification for %s:\n", le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index fbe1776..09af046 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -46,7 +46,7 @@ do { \ #ifdef CONFIG_IWLWIFI_DEBUG #define IWL_DEBUG(__priv, level, fmt, args...) \ do { \ - if (iwl_debug_level & (level)) \ + if (iwl_get_debug_level(__priv) & (level)) \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ @@ -54,15 +54,15 @@ do { \ #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \ do { \ - if ((iwl_debug_level & (level)) && net_ratelimit()) \ + if ((iwl_get_debug_level(__priv) & (level)) && net_ratelimit()) \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ } while (0) -#define iwl_print_hex_dump(level, p, len) \ +#define iwl_print_hex_dump(priv, level, p, len) \ do { \ - if (iwl_debug_level & level) \ + if (iwl_get_debug_level(priv) & level) \ print_hex_dump(KERN_DEBUG, "iwl data: ", \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) @@ -106,7 +106,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv); #else #define IWL_DEBUG(__priv, level, fmt, args...) #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) -static inline void iwl_print_hex_dump(int level, void *p, u32 len) +static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, + void *p, u32 len) {} #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cab6255..1bf3e4c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1175,6 +1175,8 @@ struct iwl_priv { #ifdef CONFIG_IWLWIFI_DEBUG /* debugging info */ + u32 debug_level; /* per device debugging will override global + iwl_debug_level if set */ u32 framecnt_to_us; atomic_t restrict_refcnt; bool disable_ht40; @@ -1211,8 +1213,27 @@ static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) #ifdef CONFIG_IWLWIFI_DEBUG const char *iwl_get_tx_fail_reason(u32 status); +/* + * iwl_get_debug_level: Return active debug level for device + * + * Using sysfs it is possible to set per device debug level. This debug + * level will be used if set, otherwise the global debug level which can be + * set via module parameter is used. + */ +static inline u32 iwl_get_debug_level(struct iwl_priv *priv) +{ + if (priv->debug_level) + return priv->debug_level; + else + return iwl_debug_level; +} #else static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; } + +static inline u32 iwl_get_debug_level(struct iwl_priv *priv) +{ + return iwl_debug_level; +} #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index e002c8b..98f0142 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -645,7 +645,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, u32 tsf_low; int rssi; - if (likely(!(iwl_debug_level & IWL_DL_RX))) + if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX))) return; /* MAC header */ @@ -741,7 +741,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(IWL_DL_RX, header, length); + iwl_print_hex_dump(priv, IWL_DL_RX, header, length); } #endif @@ -1060,7 +1060,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, /* Set "1" to report good data frames in groups of 100 */ #ifdef CONFIG_IWLWIFI_DEBUG - if (unlikely(iwl_debug_level & IWL_DL_RX)) + if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) iwl_dbg_report_frame(priv, rx_start, len, header, 1); #endif IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index efcae0d..def1254 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1088,7 +1088,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) IWL_DEBUG_DROP(priv, "Station %pM not in station map. " "Defaulting to broadcast...\n", hdr->addr1); - iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; default: diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 288b871..0cac06c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -884,8 +884,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", le16_to_cpu(out_cmd->hdr.sequence)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); /* Set up entry for this TFD in Tx byte-count array */ if (info->flags & IEEE80211_TX_CTL_AMPDU) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index ea051b7..0babce2 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -614,8 +614,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", le16_to_cpu(out_cmd->hdr.sequence)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags)); - iwl_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr, + iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx)); + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr, ieee80211_hdrlen(fc)); /* @@ -1646,7 +1646,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { + if (iwl_get_debug_level(priv) & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -1681,7 +1681,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -1760,7 +1760,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -3311,14 +3311,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * * See the level definitions in iwl for details. * - * FIXME This file can be deprecated as the module parameter is - * writable and users can thus also change the debug level - * using the /sys/module/iwl3945/parameters/debug file. + * The debug_level being managed using sysfs below is a per device debug + * level that is used instead of the global debug level if it (the per + * device debug level) is set. */ static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - return sprintf(buf, "0x%08X\n", iwl_debug_level); + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); } static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, @@ -3332,7 +3333,7 @@ static ssize_t store_debug_level(struct device *d, if (ret) IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf); else - iwl_debug_level = val; + priv->debug_level = val; return strnlen(buf, count); } -- cgit v0.10.2 From 7aafef1c6e2e24f9a10dc2972bf0ee70624ccc47 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:38 -0700 Subject: iwlwifi: name changed from "fat" to "ht40" Rename "fat" to "ht40" The term "fat channel" is deprecated in favor of "HT40" Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index cf3fbc6..191718a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -117,8 +117,8 @@ static struct iwl_lib_ops iwl1000_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index b569c6f..1677278 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -176,7 +176,7 @@ struct iwl3945_eeprom { * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory * txpower (MSB). * - * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) + * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) * channels (only for 4965, not supported by 3945) appear later in the EEPROM. * * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7ad0207..9e33507 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2851,8 +2851,8 @@ static struct iwl_lib_ops iwl3945_lib = { EEPROM_REGULATORY_BAND_3_CHANNELS, EEPROM_REGULATORY_BAND_4_CHANNELS, EEPROM_REGULATORY_BAND_5_CHANNELS, - EEPROM_REGULATORY_BAND_NO_FAT, - EEPROM_REGULATORY_BAND_NO_FAT, + EEPROM_REGULATORY_BAND_NO_HT40, + EEPROM_REGULATORY_BAND_NO_HT40, }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwl3945_eeprom_acquire_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index a71a489..b34322a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -188,7 +188,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * * 1) Regulatory information (max txpower and channel usage flags) is provided * separately for each channel that can possibly supported by 4965. - * 40 MHz wide (.11n fat) channels are listed separately from 20 MHz + * 40 MHz wide (.11n HT40) channels are listed separately from 20 MHz * (legacy) channels. * * See struct iwl4965_eeprom_channel for format, and struct iwl4965_eeprom @@ -251,8 +251,8 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * no reduction (such as with regulatory txpower limits) is required. * * Saturation and Backoff values apply equally to 20 Mhz (legacy) channel - * widths and 40 Mhz (.11n fat) channel widths; there is no separate - * factory measurement for fat channels. + * widths and 40 Mhz (.11n HT40) channel widths; there is no separate + * factory measurement for ht40 channels. * * The result of this step is the final target txpower. The rest of * the steps figure out the proper settings for the device to achieve diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 62436a9..f02023e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -317,7 +317,7 @@ restart: queue_work(priv->workqueue, &priv->restart); } -static bool is_fat_channel(__le32 rxon_flags) +static bool is_ht40_channel(__le32 rxon_flags) { int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK) >> RXON_FLG_CHANNEL_MODE_POS; @@ -806,7 +806,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE; priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; - priv->hw_params.fat_channel = BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -1266,7 +1266,7 @@ static const struct gain_entry gain_table[2][108] = { }; static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, - u8 is_fat, u8 ctrl_chan_high, + u8 is_ht40, u8 ctrl_chan_high, struct iwl4965_tx_power_db *tx_power_tbl) { u8 saturation_power; @@ -1298,8 +1298,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, user_target_power = 2 * priv->tx_power_user_lmt; /* Get current (RXON) channel, band, width */ - IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_fat %d\n", channel, band, - is_fat); + IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_ht40 %d\n", channel, band, + is_ht40); ch_info = iwl_get_channel_info(priv, priv->band, channel); @@ -1318,7 +1318,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, IWL_DEBUG_TXPOWER(priv, "channel %d belongs to txatten group %d\n", channel, txatten_grp); - if (is_fat) { + if (is_ht40) { if (ctrl_chan_high) channel -= 2; else @@ -1342,8 +1342,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, /* regulatory txpower limits ... reg_limit values are in half-dBm, * max_power_avg values are in dBm, convert * 2 */ - if (is_fat) - reg_limit = ch_info->fat_max_power_avg * 2; + if (is_ht40) + reg_limit = ch_info->ht40_max_power_avg * 2; else reg_limit = ch_info->max_power_avg * 2; @@ -1509,7 +1509,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, /** * iwl4965_send_tx_power - Configure the TXPOWER level user limit * - * Uses the active RXON for channel, band, and characteristics (fat, high) + * Uses the active RXON for channel, band, and characteristics (ht40, high) * The power limit is taken from priv->tx_power_user_lmt. */ static int iwl4965_send_tx_power(struct iwl_priv *priv) @@ -1517,7 +1517,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) struct iwl4965_txpowertable_cmd cmd = { 0 }; int ret; u8 band = 0; - bool is_fat = false; + bool is_ht40 = false; u8 ctrl_chan_high = 0; if (test_bit(STATUS_SCANNING, &priv->status)) { @@ -1530,9 +1530,9 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) band = priv->band == IEEE80211_BAND_2GHZ; - is_fat = is_fat_channel(priv->active_rxon.flags); + is_ht40 = is_ht40_channel(priv->active_rxon.flags); - if (is_fat && + if (is_ht40 && (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) ctrl_chan_high = 1; @@ -1541,7 +1541,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) ret = iwl4965_fill_txpower_tbl(priv, band, le16_to_cpu(priv->active_rxon.channel), - is_fat, ctrl_chan_high, &cmd.tx_power); + is_ht40, ctrl_chan_high, &cmd.tx_power); if (ret) goto out; @@ -1595,7 +1595,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) { int rc; u8 band = 0; - bool is_fat = false; + bool is_ht40 = false; u8 ctrl_chan_high = 0; struct iwl4965_channel_switch_cmd cmd = { 0 }; const struct iwl_channel_info *ch_info; @@ -1604,9 +1604,9 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) ch_info = iwl_get_channel_info(priv, priv->band, channel); - is_fat = is_fat_channel(priv->staging_rxon.flags); + is_ht40 = is_ht40_channel(priv->staging_rxon.flags); - if (is_fat && + if (is_ht40 && (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) ctrl_chan_high = 1; @@ -1621,7 +1621,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) else cmd.expect_beacon = 1; - rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat, + rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40, ctrl_chan_high, &cmd.tx_power); if (rc) { IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc); @@ -1688,8 +1688,8 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv) u32 R4; if (test_bit(STATUS_TEMPERATURE, &priv->status) && - (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) { - IWL_DEBUG_TEMP(priv, "Running FAT temperature calibration\n"); + (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)) { + IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n"); R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]); @@ -2330,8 +2330,8 @@ static struct iwl_lib_ops iwl4965_lib = { EEPROM_REGULATORY_BAND_3_CHANNELS, EEPROM_REGULATORY_BAND_4_CHANNELS, EEPROM_REGULATORY_BAND_5_CHANNELS, - EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS, - EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS + EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS, + EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 87957c0..755c184 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -845,7 +845,7 @@ int iwl5000_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_bsm_size = 0; - priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) | + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -1547,8 +1547,8 @@ struct iwl_lib_ops iwl5000_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, @@ -1597,8 +1597,8 @@ static struct iwl_lib_ops iwl5150_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 4450943..c3ec6c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -118,8 +118,8 @@ static struct iwl_lib_ops iwl6000_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 52a4810..0c3ed23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -97,7 +97,7 @@ struct iwl_scale_tbl_info { enum iwl_table_type lq_type; u8 ant_type; u8 is_SGI; /* 1 = short guard interval */ - u8 is_fat; /* 1 = 40 MHz channel width */ + u8 is_ht40; /* 1 = 40 MHz channel width */ u8 is_dup; /* 1 = duplicated data streams */ u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ u8 max_search; /* maximun number of tables we can search */ @@ -539,11 +539,11 @@ static u32 rate_n_flags_from_tbl(struct iwl_priv *priv, RATE_MCS_ANT_ABC_MSK); if (is_Ht(tbl->lq_type)) { - if (tbl->is_fat) { + if (tbl->is_ht40) { if (tbl->is_dup) rate_n_flags |= RATE_MCS_DUP_MSK; else - rate_n_flags |= RATE_MCS_FAT_MSK; + rate_n_flags |= RATE_MCS_HT40_MSK; } if (tbl->is_SGI) rate_n_flags |= RATE_MCS_SGI_MSK; @@ -579,7 +579,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, return -EINVAL; } tbl->is_SGI = 0; /* default legacy setup */ - tbl->is_fat = 0; + tbl->is_ht40 = 0; tbl->is_dup = 0; tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); tbl->lq_type = LQ_NONE; @@ -598,9 +598,9 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, if (rate_n_flags & RATE_MCS_SGI_MSK) tbl->is_SGI = 1; - if ((rate_n_flags & RATE_MCS_FAT_MSK) || + if ((rate_n_flags & RATE_MCS_HT40_MSK) || (rate_n_flags & RATE_MCS_DUP_MSK)) - tbl->is_fat = 1; + tbl->is_ht40 = 1; if (rate_n_flags & RATE_MCS_DUP_MSK) tbl->is_dup = 1; @@ -776,7 +776,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, if (num_of_ant(tbl->ant_type) > 1) tbl->ant_type = ANT_A;/*FIXME:RS*/ - tbl->is_fat = 0; + tbl->is_ht40 = 0; tbl->is_SGI = 0; tbl->max_search = IWL_MAX_SEARCH; } @@ -880,7 +880,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, if ((info->status.rates[0].idx < 0) || (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) || - (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || + (tbl_type.is_ht40 != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) || (tbl_type.ant_type != info->antenna_sel_tx) || (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) || @@ -1049,7 +1049,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, else tbl->expected_tpt = expected_tpt_A; } else if (is_siso(tbl->lq_type)) { - if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_ht40 && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_siso40MHzSGI; else @@ -1059,7 +1059,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, else tbl->expected_tpt = expected_tpt_siso20MHz; } else if (is_mimo2(tbl->lq_type)) { - if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_ht40 && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI; else @@ -1069,7 +1069,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, else tbl->expected_tpt = expected_tpt_mimo2_20MHz; } else if (is_mimo3(tbl->lq_type)) { - if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_ht40 && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI; else @@ -1217,13 +1217,13 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_mimo2_rate; - if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) - tbl->is_fat = 1; + if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) + tbl->is_ht40 = 1; else - tbl->is_fat = 0; + tbl->is_ht40 = 0; /* FIXME: - don't toggle SGI here - if (tbl->is_fat) { + if (tbl->is_ht40) { if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; else @@ -1283,13 +1283,13 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; rate_mask = lq_sta->active_mimo3_rate; - if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) - tbl->is_fat = 1; + if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) + tbl->is_ht40 = 1; else - tbl->is_fat = 0; + tbl->is_ht40 = 0; /* FIXME: - don't toggle SGI here - if (tbl->is_fat) { + if (tbl->is_ht40) { if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; else @@ -1342,13 +1342,13 @@ static int rs_switch_to_siso(struct iwl_priv *priv, tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_siso_rate; - if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) - tbl->is_fat = 1; + if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) + tbl->is_ht40 = 1; else - tbl->is_fat = 0; + tbl->is_ht40 = 0; /* FIXME: - don't toggle SGI here - if (tbl->is_fat) { + if (tbl->is_ht40) { if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; else @@ -1586,11 +1586,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, goto out; break; case IWL_SISO_SWITCH_GI: - if (!tbl->is_fat && + if (!tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ)) break; - if (tbl->is_fat && + if (tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ)) break; @@ -1726,11 +1726,11 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, break; case IWL_MIMO2_SWITCH_GI: - if (!tbl->is_fat && + if (!tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ)) break; - if (tbl->is_fat && + if (tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ)) break; @@ -1890,11 +1890,11 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, break; case IWL_MIMO3_SWITCH_GI: - if (!tbl->is_fat && + if (!tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ)) break; - if (tbl->is_fat && + if (tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ)) break; @@ -2576,7 +2576,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI; if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK) info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA; - if (lq_sta->last_rate_n_flags & RATE_MCS_FAT_MSK) + if (lq_sta->last_rate_n_flags & RATE_MCS_HT40_MSK) info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK) info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; @@ -2963,7 +2963,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (is_siso(tbl->lq_type)) ? "SISO" : ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); desc += sprintf(buff+desc, " %s", - (tbl->is_fat) ? "40MHz" : "20MHz"); + (tbl->is_ht40) ? "40MHz" : "20MHz"); desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "", (lq_sta->is_green) ? "GF enabled" : ""); } @@ -3028,12 +3028,13 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, return -ENOMEM; for (i = 0; i < LQ_SIZE; i++) { - desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n" + desc += sprintf(buff+desc, + "%s type=%d SGI=%d HT40=%d DUP=%d GF=%d\n" "rate=0x%X\n", lq_sta->active_tbl == i ? "*" : "x", lq_sta->lq_info[i].lq_type, lq_sta->lq_info[i].is_SGI, - lq_sta->lq_info[i].is_fat, + lq_sta->lq_info[i].is_ht40, lq_sta->lq_info[i].is_dup, lq_sta->is_green, lq_sta->lq_info[i].current_rate); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 39ede57..6188c54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -283,7 +283,7 @@ struct iwl3945_power_per_rate { * 1) Dual stream (MIMO) * 2) Triple stream (MIMO) * - * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data + * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data * * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"): * 3-0: 0xD) 6 Mbps @@ -320,11 +320,11 @@ struct iwl3945_power_per_rate { #define RATE_MCS_GF_POS 10 #define RATE_MCS_GF_MSK 0x400 -/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */ -#define RATE_MCS_FAT_POS 11 -#define RATE_MCS_FAT_MSK 0x800 +/* Bit 11: (1) Use 40Mhz HT40 chnl width, (0) use 20 MHz legacy chnl width */ +#define RATE_MCS_HT40_POS 11 +#define RATE_MCS_HT40_MSK 0x800 -/* Bit 12: (1) Duplicate data on both 20MHz chnls. FAT (bit 11) must be set. */ +/* Bit 12: (1) Duplicate data on both 20MHz chnls. HT40 (bit 11) must be set. */ #define RATE_MCS_DUP_POS 12 #define RATE_MCS_DUP_MSK 0x1000 @@ -459,7 +459,7 @@ struct iwl_init_alive_resp { /* calibration values from "initialize" uCode */ __le32 voltage; /* signed, higher value is lower voltage */ - __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for FAT channel*/ + __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */ __le32 therm_r2[2]; /* signed */ __le32 therm_r3[2]; /* signed */ __le32 therm_r4[2]; /* signed */ @@ -610,7 +610,7 @@ enum { #define RXON_FLG_HT_OPERATING_MODE_POS (23) #define RXON_FLG_HT_PROT_MSK cpu_to_le32(0x1 << 23) -#define RXON_FLG_FAT_PROT_MSK cpu_to_le32(0x2 << 23) +#define RXON_FLG_HT40_PROT_MSK cpu_to_le32(0x2 << 23) #define RXON_FLG_CHANNEL_MODE_POS (25) #define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) @@ -891,7 +891,7 @@ struct iwl_qosparam_cmd { #define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18) #define STA_FLG_MAX_AGG_SIZE_POS (19) #define STA_FLG_MAX_AGG_SIZE_MSK cpu_to_le32(3 << 19) -#define STA_FLG_FAT_EN_MSK cpu_to_le32(1 << 21) +#define STA_FLG_HT40_EN_MSK cpu_to_le32(1 << 21) #define STA_FLG_MIMO_DIS_MSK cpu_to_le32(1 << 22) #define STA_FLG_AGG_MPDU_DENSITY_POS (23) #define STA_FLG_AGG_MPDU_DENSITY_MSK cpu_to_le32(7 << 23) @@ -1984,10 +1984,10 @@ struct iwl_link_qual_agg_params { * a) Use this same initial rate for first 3 entries. * b) Find next lower available rate using same mode (SISO or MIMO), * use for next 3 entries. If no lower rate available, switch to - * legacy mode (no FAT channel, no MIMO, no short guard interval). + * legacy mode (no HT40 channel, no MIMO, no short guard interval). * c) If using MIMO, set command's mimo_delimiter to number of entries * using MIMO (3 or 6). - * d) After trying 2 HT rates, switch to legacy mode (no FAT channel, + * d) After trying 2 HT rates, switch to legacy mode (no HT40 channel, * no MIMO, no short guard interval), at the next lower bit rate * (e.g. if second HT bit rate was 54, try 48 legacy), and follow * legacy procedure for remaining table entries. @@ -3017,7 +3017,7 @@ struct iwl_statistics_cmd { * one channel that has just been scanned. */ #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) -#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8) +#define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8) struct iwl3945_notif_statistics { __le32 flag; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 30f1953..5315d34 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -105,7 +105,7 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, r->flags |= IEEE80211_TX_RC_MCS; if (rate_n_flags & RATE_MCS_GF_MSK) r->flags |= IEEE80211_TX_RC_GREEN_FIELD; - if (rate_n_flags & RATE_MCS_FAT_MSK) + if (rate_n_flags & RATE_MCS_HT40_MSK) r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (rate_n_flags & RATE_MCS_DUP_MSK) r->flags |= IEEE80211_TX_RC_DUP_DATA; @@ -400,7 +400,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, (WLAN_HT_CAP_SM_PS_DISABLED << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; - if (priv->hw_params.fat_channel & BIT(band)) { + if (priv->hw_params.ht40_channel & BIT(band)) { ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; ht_info->cap |= IEEE80211_HT_CAP_SGI_40; ht_info->mcs.rx_mask[4] = 0x01; @@ -540,7 +540,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) if (ch->flags & EEPROM_CHANNEL_RADAR) geo_ch->flags |= IEEE80211_CHAN_RADAR; - geo_ch->flags |= ch->fat_extension_channel; + geo_ch->flags |= ch->ht40_extension_channel; if (ch->max_power_avg > priv->tx_power_channel_lmt) priv->tx_power_channel_lmt = ch->max_power_avg; @@ -604,16 +604,16 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, return 0; if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) - return !(ch_info->fat_extension_channel & + return !(ch_info->ht40_extension_channel & IEEE80211_CHAN_NO_HT40PLUS); else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) - return !(ch_info->fat_extension_channel & + return !(ch_info->ht40_extension_channel & IEEE80211_CHAN_NO_HT40MINUS); return 0; } -u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, +u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, struct ieee80211_sta_ht_cap *sta_ht_inf) { struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; @@ -637,7 +637,7 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, le16_to_cpu(priv->staging_rxon.channel), iwl_ht_conf->extension_chan_offset); } -EXPORT_SYMBOL(iwl_is_fat_tx_allowed); +EXPORT_SYMBOL(iwl_is_ht40_tx_allowed); static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) { @@ -866,7 +866,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) if (!ht_info->is_ht) { rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | - RXON_FLG_FAT_PROT_MSK | + RXON_FLG_HT40_PROT_MSK | RXON_FLG_HT_PROT_MSK); return; } @@ -877,12 +877,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); /* Set up channel bandwidth: - * 20 MHz only, 20/40 mixed or pure 40 if fat ok */ + * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ /* clear the HT channel mode before set the mode */ rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); - if (iwl_is_fat_tx_allowed(priv, NULL)) { - /* pure 40 fat */ + if (iwl_is_ht40_tx_allowed(priv, NULL)) { + /* pure ht40 */ if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; /* Note: control channel is opposite of extension channel */ @@ -2428,7 +2428,7 @@ static void iwl_ht_conf(struct iwl_priv *priv, else if (conf_is_ht40_plus(&priv->hw->conf)) iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - /* If no above or below channel supplied disable FAT channel */ + /* If no above or below channel supplied disable HT40 channel */ if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) iwl_conf->supported_chan_width = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 10ddcdd..dd66148 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -264,7 +264,7 @@ int iwl_full_rxon_required(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); -u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, +u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, struct ieee80211_sta_ht_cap *sta_ht_inf); void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band); void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1bf3e4c..624656a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -277,8 +277,8 @@ struct iwl_channel_info { struct iwl4965_channel_tgd_info tgd; struct iwl4965_channel_tgh_info tgh; struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ - struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for - * FAT channel */ + struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for + * HT40 channel */ u8 channel; /* channel number */ u8 flags; /* flags copied from EEPROM */ @@ -291,13 +291,13 @@ struct iwl_channel_info { u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ enum ieee80211_band band; - /* FAT channel info */ - s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ - s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ - s8 fat_min_power; /* always 0 */ - s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */ - u8 fat_flags; /* flags copied from EEPROM */ - u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ + /* HT40 channel info */ + s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + s8 ht40_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ + s8 ht40_min_power; /* always 0 */ + s8 ht40_scan_power; /* (dBm) eeprom, direct scans, any rate */ + u8 ht40_flags; /* flags copied from EEPROM */ + u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ /* Radio/DSP gain settings for each "normal" data Tx rate. * These include, in addition to RF and DSP gain, a few fields for @@ -649,7 +649,7 @@ struct iwl_sensitivity_ranges { * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR * @max_stations: * @bcast_sta_id: - * @fat_channel: is 40MHz width possible in band 2.4 + * @ht40_channel: is 40MHz width possible in band 2.4 * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ) * @sw_crypto: 0 for hw, 1 for sw * @max_xxx_size: for ucode uses @@ -673,7 +673,7 @@ struct iwl_hw_params { u32 max_pkt_size; u8 max_stations; u8 bcast_sta_id; - u8 fat_channel; + u8 ht40_channel; u8 max_beacon_itrvl; /* in 1024 ms */ u32 max_inst_size; u32 max_data_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 51eed72..78c4a32 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -127,11 +127,11 @@ static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ 145, 149, 153, 157, 161, 165 }; -static const u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */ +static const u8 iwl_eeprom_band_6[] = { /* 2.4 ht40 channel */ 1, 2, 3, 4, 5, 6, 7 }; -static const u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */ +static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 }; @@ -462,13 +462,13 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_5; break; - case 6: /* 2.4GHz FAT channels */ + case 6: /* 2.4GHz ht40 channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); *eeprom_ch_info = (struct iwl_eeprom_channel *) iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_6; break; - case 7: /* 5 GHz FAT channels */ + case 7: /* 5 GHz ht40 channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); *eeprom_ch_info = (struct iwl_eeprom_channel *) iwl_eeprom_query_addr(priv, offset); @@ -484,14 +484,14 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, ? # x " " : "") /** - * iwl_set_fat_chan_info - Copy fat channel info into driver's priv. + * iwl_set_ht40_chan_info - Copy ht40 channel info into driver's priv. * * Does not set up a command, or touch hardware. */ -static int iwl_set_fat_chan_info(struct iwl_priv *priv, +static int iwl_set_ht40_chan_info(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, const struct iwl_eeprom_channel *eeprom_ch, - u8 fat_extension_channel) + u8 ht40_extension_channel) { struct iwl_channel_info *ch_info; @@ -501,7 +501,7 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv, if (!is_channel_valid(ch_info)) return -1; - IWL_DEBUG_INFO(priv, "FAT Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):" + IWL_DEBUG_INFO(priv, "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):" " Ad-Hoc %ssupported\n", ch_info->channel, is_channel_a_band(ch_info) ? @@ -517,13 +517,13 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv, && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); - ch_info->fat_eeprom = *eeprom_ch; - ch_info->fat_max_power_avg = eeprom_ch->max_power_avg; - ch_info->fat_curr_txpow = eeprom_ch->max_power_avg; - ch_info->fat_min_power = 0; - ch_info->fat_scan_power = eeprom_ch->max_power_avg; - ch_info->fat_flags = eeprom_ch->flags; - ch_info->fat_extension_channel = fat_extension_channel; + ch_info->ht40_eeprom = *eeprom_ch; + ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg; + ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg; + ch_info->ht40_min_power = 0; + ch_info->ht40_scan_power = eeprom_ch->max_power_avg; + ch_info->ht40_flags = eeprom_ch->flags; + ch_info->ht40_extension_channel = ht40_extension_channel; return 0; } @@ -589,9 +589,9 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Copy the run-time flags so they are there even on * invalid channels */ ch_info->flags = eeprom_ch_info[ch].flags; - /* First write that fat is not enabled, and then enable + /* First write that ht40 is not enabled, and then enable * one by one */ - ch_info->fat_extension_channel = + ch_info->ht40_extension_channel = (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS); @@ -642,17 +642,17 @@ int iwl_init_channel_map(struct iwl_priv *priv) } } - /* Check if we do have FAT channels */ + /* Check if we do have HT40 channels */ if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] == - EEPROM_REGULATORY_BAND_NO_FAT && + EEPROM_REGULATORY_BAND_NO_HT40 && priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] == - EEPROM_REGULATORY_BAND_NO_FAT) + EEPROM_REGULATORY_BAND_NO_HT40) return 0; - /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */ + /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */ for (band = 6; band <= 7; band++) { enum ieee80211_band ieeeband; - u8 fat_extension_chan; + u8 ht40_extension_chan; iwl_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); @@ -669,19 +669,19 @@ int iwl_init_channel_map(struct iwl_priv *priv) (eeprom_ch_index[ch] == 6) || (eeprom_ch_index[ch] == 7))) /* both are allowed: above and below */ - fat_extension_chan = 0; + ht40_extension_chan = 0; else - fat_extension_chan = + ht40_extension_chan = IEEE80211_CHAN_NO_HT40MINUS; /* Set up driver's info for lower half */ - iwl_set_fat_chan_info(priv, ieeeband, + iwl_set_ht40_chan_info(priv, ieeeband, eeprom_ch_index[ch], &(eeprom_ch_info[ch]), - fat_extension_chan); + ht40_extension_chan); /* Set up driver's info for upper half */ - iwl_set_fat_chan_info(priv, ieeeband, + iwl_set_ht40_chan_info(priv, ieeeband, (eeprom_ch_index[ch] + 4), &(eeprom_ch_info[ch]), IEEE80211_CHAN_NO_HT40PLUS); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 195b4ef..05d4fc4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -88,10 +88,10 @@ struct iwl_priv; * requirement for establishing a new network for legal operation on channels * requiring RADAR detection or restricting ACTIVE scanning. * - * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels. - * It only indicates that 20 MHz channel use is supported; FAT channel + * NOTE: "WIDE" flag does not indicate anything about "HT40" 40 MHz channels. + * It only indicates that 20 MHz channel use is supported; HT40 channel * usage is indicated by a separate set of regulatory flags for each - * FAT channel pair. + * HT40 channel pair. * * NOTE: Using a channel inappropriately will result in a uCode error! */ @@ -112,7 +112,7 @@ enum { #define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) /* *regulatory* channel data format in eeprom, one for each channel. - * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */ + * There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */ struct iwl_eeprom_channel { u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ @@ -170,9 +170,9 @@ struct iwl_eeprom_channel { | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ #define EEPROM_5000_REG_BAND_5_CHANNELS ((0x74)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 12 bytes */ -#define EEPROM_5000_REG_BAND_24_FAT_CHANNELS ((0x82)\ +#define EEPROM_5000_REG_BAND_24_HT40_CHANNELS ((0x82)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */ -#define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\ +#define EEPROM_5000_REG_BAND_52_HT40_CHANNELS ((0x92)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ /* 5050 Specific */ @@ -313,7 +313,7 @@ struct iwl_eeprom_calib_info { * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory * txpower (MSB). * - * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) + * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) * channels (only for 4965, not supported by 3945) appear later in the EEPROM. * * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 @@ -352,29 +352,29 @@ struct iwl_eeprom_calib_info { #define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ /* - * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) + * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) * * The channel listed is the center of the lower 20 MHz half of the channel. * The overall center frequency is actually 2 channels (10 MHz) above that, - * and the upper half of each FAT channel is centered 4 channels (20 MHz) away - * from the lower half; e.g. the upper half of FAT channel 1 is channel 5, - * and the overall FAT channel width centers on channel 3. + * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away + * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5, + * and the overall HT40 channel width centers on channel 3. * * NOTE: The RXON command uses 20 MHz channel numbers to specify the * control channel to which to tune. RXON also specifies whether the - * control channel is the upper or lower half of a FAT channel. + * control channel is the upper or lower half of a HT40 channel. * - * NOTE: 4965 does not support FAT channels on 2.4 GHz. + * NOTE: 4965 does not support HT40 channels on 2.4 GHz. */ -#define EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ +#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */ /* - * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64), + * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64), * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) */ -#define EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ +#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */ -#define EEPROM_REGULATORY_BAND_NO_FAT (0) +#define EEPROM_REGULATORY_BAND_NO_HT40 (0) struct iwl_eeprom_ops { const u32 regulatory_bands[7]; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 00937b3..594b5c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -583,7 +583,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) /* disable HT */ rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | - RXON_FLG_FAT_PROT_MSK | + RXON_FLG_HT40_PROT_MSK | RXON_FLG_HT_PROT_MSK); else { /* check HT capability and set diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 98f0142..9e63f9d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -544,8 +544,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, change = ((priv->statistics.general.temperature != pkt->u.stats.general.temperature) || ((priv->statistics.flag & - STATISTICS_REPLY_FLG_FAT_MODE_MSK) != - (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK))); + STATISTICS_REPLY_FLG_HT40_MODE_MSK) != + (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index def1254..c6633fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -214,10 +214,10 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, sta_flags |= cpu_to_le32( (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); - if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) - sta_flags |= STA_FLG_FAT_EN_MSK; + if (iwl_is_ht40_tx_allowed(priv, sta_ht_inf)) + sta_flags |= STA_FLG_HT40_EN_MSK; else - sta_flags &= ~STA_FLG_FAT_EN_MSK; + sta_flags &= ~STA_FLG_HT40_EN_MSK; priv->stations[index].sta.station_flags = sta_flags; done: -- cgit v0.10.2 From 20594eb0daa67f7a0cc19d74a1bafceb1bb09f4a Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:39 -0700 Subject: iwlwifi: new debugging feature for dumping data traffic The traffic buffer will only beallocated and used if either bit 23 (IWL_DX_TX) or bit 24 (IWL_DL_RX) of "debug" is set; example: "debug=0x800000" - log tx data traffic "debug=0x1000000" - log rx data traffic "debug=0x1800000" - log both tx and rx traffic The traffic log will store the beginning portion (64 bytes) of the latest 256 of tx and rx packets in the round-robbin buffer for debugging, user can examine the log through debugfs file. How to display the current logged tx/rx traffic and txfifo and rxfifo read/write point: "cat traffic_log" in /sys/kernel/debug/ieee80211/phy0/iwlagn/debug directory By echo "0" to traffic_log file will empty the traffic log buffer and reset both tx and rx taffic log index to 0. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 9e33507..bfd509f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -679,6 +679,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, /* Set "1" to report good data frames in groups of 100 */ iwl3945_dbg_report_frame(priv, pkt, header, 1); + iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header); if (network_packet) { priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 24c1ae6..c9a1aac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2476,9 +2476,12 @@ static ssize_t store_debug_level(struct device *d, ret = strict_strtoul(buf, 0, &val); if (ret) IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); - else + else { priv->debug_level = val; - + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, + "Not enough memory to generate traffic log\n"); + } return strnlen(buf, count); } @@ -2819,6 +2822,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef CONFIG_IWLWIFI_DEBUG atomic_set(&priv->restrict_refcnt, 0); #endif + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, "Not enough memory to generate traffic log\n"); /************************** * 2. Initializing PCI bus @@ -3003,6 +3008,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_disable_device(pdev); out_ieee80211_free_hw: ieee80211_free_hw(priv->hw); + iwl_free_traffic_mem(priv); out: return err; } @@ -3061,6 +3067,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) * until now... */ destroy_workqueue(priv->workqueue); priv->workqueue = NULL; + iwl_free_traffic_mem(priv); free_irq(priv->pci_dev->irq, priv); pci_disable_msi(priv->pci_dev); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5315d34..1ae2ce3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2953,6 +2953,106 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) } EXPORT_SYMBOL(iwl_mac_reset_tsf); +#ifdef CONFIG_IWLWIFI_DEBUGFS + +#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES) + +void iwl_reset_traffic_log(struct iwl_priv *priv) +{ + priv->tx_traffic_idx = 0; + priv->rx_traffic_idx = 0; + if (priv->tx_traffic) + memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); + if (priv->rx_traffic) + memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); +} + +int iwl_alloc_traffic_mem(struct iwl_priv *priv) +{ + u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE; + + if (iwl_debug_level & IWL_DL_TX) { + if (!priv->tx_traffic) { + priv->tx_traffic = + kzalloc(traffic_size, GFP_KERNEL); + if (!priv->tx_traffic) + return -ENOMEM; + } + } + if (iwl_debug_level & IWL_DL_RX) { + if (!priv->rx_traffic) { + priv->rx_traffic = + kzalloc(traffic_size, GFP_KERNEL); + if (!priv->rx_traffic) + return -ENOMEM; + } + } + iwl_reset_traffic_log(priv); + return 0; +} +EXPORT_SYMBOL(iwl_alloc_traffic_mem); + +void iwl_free_traffic_mem(struct iwl_priv *priv) +{ + kfree(priv->tx_traffic); + priv->tx_traffic = NULL; + + kfree(priv->rx_traffic); + priv->rx_traffic = NULL; +} +EXPORT_SYMBOL(iwl_free_traffic_mem); + +void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ + __le16 fc; + u16 len; + + if (likely(!(iwl_debug_level & IWL_DL_TX))) + return; + + if (!priv->tx_traffic) + return; + + fc = header->frame_control; + if (ieee80211_is_data(fc)) { + len = (length > IWL_TRAFFIC_ENTRY_SIZE) + ? IWL_TRAFFIC_ENTRY_SIZE : length; + memcpy((priv->tx_traffic + + (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), + header, len); + priv->tx_traffic_idx = + (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; + } +} +EXPORT_SYMBOL(iwl_dbg_log_tx_data_frame); + +void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ + __le16 fc; + u16 len; + + if (likely(!(iwl_debug_level & IWL_DL_RX))) + return; + + if (!priv->rx_traffic) + return; + + fc = header->frame_control; + if (ieee80211_is_data(fc)) { + len = (length > IWL_TRAFFIC_ENTRY_SIZE) + ? IWL_TRAFFIC_ENTRY_SIZE : length; + memcpy((priv->rx_traffic + + (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), + header, len); + priv->rx_traffic_idx = + (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; + } +} +EXPORT_SYMBOL(iwl_dbg_log_rx_data_frame); +#endif + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index dd66148..40a9167 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -300,7 +300,35 @@ void iwl_config_ap(struct iwl_priv *priv); int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); void iwl_mac_reset_tsf(struct ieee80211_hw *hw); +#ifdef CONFIG_IWLWIFI_DEBUGFS +int iwl_alloc_traffic_mem(struct iwl_priv *priv); +void iwl_free_traffic_mem(struct iwl_priv *priv); +void iwl_reset_traffic_log(struct iwl_priv *priv); +void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header); +void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header); +#else +static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv) +{ + return 0; +} +static inline void iwl_free_traffic_mem(struct iwl_priv *priv) +{ +} +static inline void iwl_reset_traffic_log(struct iwl_priv *priv) +{ +} +static inline void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ +} +static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ +} +#endif /***************************************************** * RX handlers. * **************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 09af046..335ff5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -72,6 +72,7 @@ struct iwl_debugfs { const char *name; struct dentry *dir_drv; struct dentry *dir_data; + struct dentry *dir_debug; struct dentry *dir_rf; struct dir_data_files { struct dentry *file_sram; @@ -95,6 +96,9 @@ struct iwl_debugfs { struct dentry *file_disable_chain_noise; struct dentry *file_disable_tx_power; } dbgfs_rf_files; + struct dir_debug_files { + struct dentry *file_traffic_log; + } dbgfs_debug_files; u32 sram_offset; u32 sram_len; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 6748a3f..031538c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -712,6 +712,104 @@ DEBUGFS_READ_FILE_OPS(led); DEBUGFS_READ_FILE_OPS(thermal_throttling); DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); +static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + int pos = 0, ofs = 0; + int cnt = 0, entry; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + struct iwl_rx_queue *rxq = &priv->rxq; + char *buf; + int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) + + (IWL_MAX_NUM_QUEUES * 32 * 8) + 400; + const u8 *ptr; + ssize_t ret; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate buffer\n"); + return -ENOMEM; + } + pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n"); + for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { + txq = &priv->txq[cnt]; + q = &txq->q; + pos += scnprintf(buf + pos, bufsz - pos, + "q[%d]: read_ptr: %u, write_ptr: %u\n", + cnt, q->read_ptr, q->write_ptr); + } + if (priv->tx_traffic && (iwl_debug_level & IWL_DL_TX)) { + ptr = priv->tx_traffic; + pos += scnprintf(buf + pos, bufsz - pos, + "Tx Traffic idx: %u\n", priv->tx_traffic_idx); + for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { + for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; + entry++, ofs += 16) { + pos += scnprintf(buf + pos, bufsz - pos, + "0x%.4x ", ofs); + hex_dump_to_buffer(ptr + ofs, 16, 16, 2, + buf + pos, bufsz - pos, 0); + pos += strlen(buf); + if (bufsz - pos > 0) + buf[pos++] = '\n'; + } + } + } + + pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "read: %u, write: %u\n", + rxq->read, rxq->write); + + if (priv->rx_traffic && (iwl_debug_level & IWL_DL_RX)) { + ptr = priv->rx_traffic; + pos += scnprintf(buf + pos, bufsz - pos, + "Rx Traffic idx: %u\n", priv->rx_traffic_idx); + for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { + for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; + entry++, ofs += 16) { + pos += scnprintf(buf + pos, bufsz - pos, + "0x%.4x ", ofs); + hex_dump_to_buffer(ptr + ofs, 16, 16, 2, + buf + pos, bufsz - pos, 0); + pos += strlen(buf); + if (bufsz - pos > 0) + buf[pos++] = '\n'; + } + } + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_traffic_log_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int traffic_log; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &traffic_log) != 1) + return -EFAULT; + if (traffic_log == 0) + iwl_reset_traffic_log(priv); + + return count; +} + +DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); + /* * Create the debugfs files and directories * @@ -738,6 +836,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); + DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv); DEBUGFS_ADD_FILE(nvm, data); DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(log_event, data); @@ -753,6 +852,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) #endif DEBUGFS_ADD_FILE(thermal_throttling, data); DEBUGFS_ADD_FILE(disable_ht40, data); + DEBUGFS_ADD_FILE(traffic_log, debug); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -794,6 +894,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); DEBUGFS_REMOVE(priv->dbgfs->dir_data); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); + DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 624656a..899b75f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -877,6 +877,8 @@ struct iwl_chain_noise_data { #define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ #define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ +#define IWL_TRAFFIC_ENTRIES (256) +#define IWL_TRAFFIC_ENTRY_SIZE (64) enum { MEASUREMENT_READY = (1 << 0), @@ -1182,6 +1184,10 @@ struct iwl_priv { bool disable_ht40; #ifdef CONFIG_IWLWIFI_DEBUGFS /* debugfs */ + u16 tx_traffic_idx; + u16 rx_traffic_idx; + u8 *tx_traffic; + u8 *rx_traffic; struct iwl_debugfs *dbgfs; #endif /* CONFIG_IWLWIFI_DEBUGFS */ #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 9e63f9d..5586003 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1063,6 +1063,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) iwl_dbg_report_frame(priv, rx_start, len, header, 1); #endif + iwl_dbg_log_rx_data_frame(priv, len, header); IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", rx_status.signal, rx_status.noise, rx_status.qual, (unsigned long long)rx_status.mactime); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 0cac06c..c85e54c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -808,6 +808,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* TODO need this for burst mode later on */ iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id); + iwl_dbg_log_tx_data_frame(priv, len, hdr); /* set is_hcca to 0; it probably will never be implemented */ iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0babce2..4f5a3d03 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -598,7 +598,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) len = (u16)skb->len; tx->len = cpu_to_le16(len); - + iwl_dbg_log_tx_data_frame(priv, len, hdr); tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; @@ -3332,9 +3332,12 @@ static ssize_t store_debug_level(struct device *d, ret = strict_strtoul(buf, 0, &val); if (ret) IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf); - else + else { priv->debug_level = val; - + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, + "Not enough memory to generate traffic log\n"); + } return strnlen(buf, count); } @@ -3976,6 +3979,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e #ifdef CONFIG_IWLWIFI_DEBUG atomic_set(&priv->restrict_refcnt, 0); #endif + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, "Not enough memory to generate traffic log\n"); /*************************** * 2. Initializing PCI bus @@ -4138,6 +4143,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_disable_device(pdev); out_ieee80211_free_hw: ieee80211_free_hw(priv->hw); + iwl_free_traffic_mem(priv); out: return err; } @@ -4193,6 +4199,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) * until now... */ destroy_workqueue(priv->workqueue); priv->workqueue = NULL; + iwl_free_traffic_mem(priv); free_irq(pdev->irq, priv); pci_disable_msi(pdev); -- cgit v0.10.2 From 22fdf3c9e19dce6d66bcfdbed547a5aa52b89933 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:40 -0700 Subject: iwlwifi: Traffic type and counter for debugFs Break down the traffic type and counter for both Tx and Rx. Enhance the tx_statistics and rx_statistics debugfs function and move to /sys/kernel/debug/ieee80211/phy0/iwlagn/debug directory to help better debugging both driver and uCode related problems. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index bfd509f..ae7f163 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -577,6 +577,8 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, if (ieee80211_is_data(hdr->frame_control)) priv->rxtxpackets += len; #endif + iwl_update_stats(priv, false, hdr->frame_control, len); + memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); ieee80211_rx_irqsafe(priv->hw, rxb->skb); rxb->skb = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1ae2ce3..202bc39 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -3051,6 +3051,164 @@ void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, } } EXPORT_SYMBOL(iwl_dbg_log_rx_data_frame); + +const char *get_mgmt_string(int cmd) +{ + switch (cmd) { + IWL_CMD(MANAGEMENT_ASSOC_REQ); + IWL_CMD(MANAGEMENT_ASSOC_RESP); + IWL_CMD(MANAGEMENT_REASSOC_REQ); + IWL_CMD(MANAGEMENT_REASSOC_RESP); + IWL_CMD(MANAGEMENT_PROBE_REQ); + IWL_CMD(MANAGEMENT_PROBE_RESP); + IWL_CMD(MANAGEMENT_BEACON); + IWL_CMD(MANAGEMENT_ATIM); + IWL_CMD(MANAGEMENT_DISASSOC); + IWL_CMD(MANAGEMENT_AUTH); + IWL_CMD(MANAGEMENT_DEAUTH); + IWL_CMD(MANAGEMENT_ACTION); + default: + return "UNKNOWN"; + + } +} + +const char *get_ctrl_string(int cmd) +{ + switch (cmd) { + IWL_CMD(CONTROL_BACK_REQ); + IWL_CMD(CONTROL_BACK); + IWL_CMD(CONTROL_PSPOLL); + IWL_CMD(CONTROL_RTS); + IWL_CMD(CONTROL_CTS); + IWL_CMD(CONTROL_ACK); + IWL_CMD(CONTROL_CFEND); + IWL_CMD(CONTROL_CFENDACK); + default: + return "UNKNOWN"; + + } +} + +void iwl_clear_tx_stats(struct iwl_priv *priv) +{ + memset(&priv->tx_stats, 0, sizeof(struct traffic_stats)); + +} + +void iwl_clear_rx_stats(struct iwl_priv *priv) +{ + memset(&priv->rx_stats, 0, sizeof(struct traffic_stats)); +} + +/* + * if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will + * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass. + * Use debugFs to display the rx/rx_statistics + * if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL + * information will be recorded, but DATA pkt still will be recorded + * for the reason of iwl_led.c need to control the led blinking based on + * number of tx and rx data. + * + */ +void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) +{ + struct traffic_stats *stats; + + if (is_tx) + stats = &priv->tx_stats; + else + stats = &priv->rx_stats; + + if (ieee80211_is_mgmt(fc)) { + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): + stats->mgmt[MANAGEMENT_ASSOC_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): + stats->mgmt[MANAGEMENT_ASSOC_RESP]++; + break; + case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): + stats->mgmt[MANAGEMENT_REASSOC_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): + stats->mgmt[MANAGEMENT_REASSOC_RESP]++; + break; + case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): + stats->mgmt[MANAGEMENT_PROBE_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): + stats->mgmt[MANAGEMENT_PROBE_RESP]++; + break; + case cpu_to_le16(IEEE80211_STYPE_BEACON): + stats->mgmt[MANAGEMENT_BEACON]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ATIM): + stats->mgmt[MANAGEMENT_ATIM]++; + break; + case cpu_to_le16(IEEE80211_STYPE_DISASSOC): + stats->mgmt[MANAGEMENT_DISASSOC]++; + break; + case cpu_to_le16(IEEE80211_STYPE_AUTH): + stats->mgmt[MANAGEMENT_AUTH]++; + break; + case cpu_to_le16(IEEE80211_STYPE_DEAUTH): + stats->mgmt[MANAGEMENT_DEAUTH]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ACTION): + stats->mgmt[MANAGEMENT_ACTION]++; + break; + } + } else if (ieee80211_is_ctl(fc)) { + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_BACK_REQ): + stats->ctrl[CONTROL_BACK_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_BACK): + stats->ctrl[CONTROL_BACK]++; + break; + case cpu_to_le16(IEEE80211_STYPE_PSPOLL): + stats->ctrl[CONTROL_PSPOLL]++; + break; + case cpu_to_le16(IEEE80211_STYPE_RTS): + stats->ctrl[CONTROL_RTS]++; + break; + case cpu_to_le16(IEEE80211_STYPE_CTS): + stats->ctrl[CONTROL_CTS]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ACK): + stats->ctrl[CONTROL_ACK]++; + break; + case cpu_to_le16(IEEE80211_STYPE_CFEND): + stats->ctrl[CONTROL_CFEND]++; + break; + case cpu_to_le16(IEEE80211_STYPE_CFENDACK): + stats->ctrl[CONTROL_CFENDACK]++; + break; + } + } else { + /* data */ + stats->data_cnt++; + stats->data_bytes += len; + } +} +EXPORT_SYMBOL(iwl_update_stats); + +#else +void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) +{ + struct traffic_stats *stats; + + if (is_tx) + stats = &priv->tx_stats; + else + stats = &priv->rx_stats; + + if (ieee80211_is_data(fc)) { + /* data */ + stats->data_bytes += len; + } +} #endif #ifdef CONFIG_PM diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 40a9167..fc096b9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -83,6 +83,8 @@ struct iwl_cmd; #define IWL_SKU_A 0x2 #define IWL_SKU_N 0x8 +#define IWL_CMD(x) case x: return #x + struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); int (*commit_rxon)(struct iwl_priv *priv); @@ -308,7 +310,10 @@ void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, u16 length, struct ieee80211_hdr *header); void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, u16 length, struct ieee80211_hdr *header); - +const char *get_mgmt_string(int cmd); +const char *get_ctrl_string(int cmd); +void iwl_clear_tx_stats(struct iwl_priv *priv); +void iwl_clear_rx_stats(struct iwl_priv *priv); #else static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv) { @@ -329,6 +334,8 @@ static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, { } #endif +void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, + u16 len); /***************************************************** * RX handlers. * **************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 335ff5c..4ac06ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -78,8 +78,6 @@ struct iwl_debugfs { struct dentry *file_sram; struct dentry *file_nvm; struct dentry *file_stations; - struct dentry *file_rx_statistics; - struct dentry *file_tx_statistics; struct dentry *file_log_event; struct dentry *file_channels; struct dentry *file_status; @@ -97,6 +95,8 @@ struct iwl_debugfs { struct dentry *file_disable_tx_power; } dbgfs_rf_files; struct dir_debug_files { + struct dentry *file_rx_statistics; + struct dentry *file_tx_statistics; struct dentry *file_traffic_log; } dbgfs_debug_files; u32 sram_offset; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 031538c..a0e5063 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -126,18 +126,58 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - char buf[256]; + char *buf; int pos = 0; - const size_t bufsz = sizeof(buf); - pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n", - priv->tx_stats[0].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n", - priv->tx_stats[1].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n", - priv->tx_stats[2].cnt); + int cnt; + ssize_t ret; + const size_t bufsz = 100 + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); + for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_mgmt_string(cnt), + priv->tx_stats.mgmt[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Control\n"); + for (cnt = 0; cnt < CONTROL_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_ctrl_string(cnt), + priv->tx_stats.ctrl[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Data:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n", + priv->tx_stats.data_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n", + priv->tx_stats.data_bytes); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + u32 clear_flag; + char buf[8]; + int buf_size; - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%x", &clear_flag) != 1) + return -EFAULT; + if (clear_flag == 1) + iwl_clear_tx_stats(priv); + + return count; } static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, @@ -145,18 +185,59 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - char buf[256]; + char *buf; int pos = 0; - const size_t bufsz = sizeof(buf); + int cnt; + ssize_t ret; + const size_t bufsz = 100 + + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; - pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n", - priv->rx_stats[0].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n", - priv->rx_stats[1].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n", - priv->rx_stats[2].cnt); + pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); + for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_mgmt_string(cnt), + priv->rx_stats.mgmt[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Control:\n"); + for (cnt = 0; cnt < CONTROL_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_ctrl_string(cnt), + priv->rx_stats.ctrl[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Data:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n", + priv->rx_stats.data_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n", + priv->rx_stats.data_bytes); - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_rx_statistics_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + u32 clear_flag; + char buf[8]; + int buf_size; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%x", &clear_flag) != 1) + return -EFAULT; + if (clear_flag == 1) + iwl_clear_rx_stats(priv); + return count; } #define BYTE1_MASK 0x000000ff; @@ -700,8 +781,6 @@ DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); DEBUGFS_READ_FILE_OPS(stations); -DEBUGFS_READ_FILE_OPS(rx_statistics); -DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_WRITE_FILE_OPS(interrupt); @@ -808,6 +887,8 @@ static ssize_t iwl_dbgfs_traffic_log_write(struct file *file, return count; } +DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); +DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); /* @@ -841,8 +922,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(log_event, data); DEBUGFS_ADD_FILE(stations, data); - DEBUGFS_ADD_FILE(rx_statistics, data); - DEBUGFS_ADD_FILE(tx_statistics, data); DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_FILE(status, data); DEBUGFS_ADD_FILE(interrupt, data); @@ -852,6 +931,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) #endif DEBUGFS_ADD_FILE(thermal_throttling, data); DEBUGFS_ADD_FILE(disable_ht40, data); + DEBUGFS_ADD_FILE(rx_statistics, debug); + DEBUGFS_ADD_FILE(tx_statistics, debug); DEBUGFS_ADD_FILE(traffic_log, debug); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, @@ -879,8 +960,6 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) return; DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); @@ -894,6 +973,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); DEBUGFS_REMOVE(priv->dbgfs->dir_data); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 899b75f..dcf9d57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -919,6 +919,48 @@ struct isr_statistics { u32 unhandled; }; +#ifdef CONFIG_IWLWIFI_DEBUGFS +/* management statistics */ +enum iwl_mgmt_stats { + MANAGEMENT_ASSOC_REQ = 0, + MANAGEMENT_ASSOC_RESP, + MANAGEMENT_REASSOC_REQ, + MANAGEMENT_REASSOC_RESP, + MANAGEMENT_PROBE_REQ, + MANAGEMENT_PROBE_RESP, + MANAGEMENT_BEACON, + MANAGEMENT_ATIM, + MANAGEMENT_DISASSOC, + MANAGEMENT_AUTH, + MANAGEMENT_DEAUTH, + MANAGEMENT_ACTION, + MANAGEMENT_MAX, +}; +/* control statistics */ +enum iwl_ctrl_stats { + CONTROL_BACK_REQ = 0, + CONTROL_BACK, + CONTROL_PSPOLL, + CONTROL_RTS, + CONTROL_CTS, + CONTROL_ACK, + CONTROL_CFEND, + CONTROL_CFENDACK, + CONTROL_MAX, +}; + +struct traffic_stats { + u32 mgmt[MANAGEMENT_MAX]; + u32 ctrl[CONTROL_MAX]; + u32 data_cnt; + u64 data_bytes; +}; +#else +struct traffic_stats { + u64 data_bytes; +}; +#endif + #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ struct iwl_priv { @@ -1064,10 +1106,8 @@ struct iwl_priv { int last_rx_noise; /* From beacon statistics */ /* counts mgmt, ctl, and data packets */ - struct traffic_stats { - u32 cnt; - u64 bytes; - } tx_stats[3], rx_stats[3]; + struct traffic_stats tx_stats; + struct traffic_stats rx_stats; /* counts interrupts */ struct isr_statistics isr_stats; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index b82ad15..532c8d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -36,8 +36,6 @@ #include "iwl-core.h" -#define IWL_CMD(x) case x: return #x - const char *get_cmd_string(u8 cmd) { switch (cmd) { diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 3d61cb4..f420c99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -272,7 +272,8 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) /* count both tx and rx traffic to be able to * handle traffic in either direction */ - u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes; + u64 current_tpt = priv->tx_stats.data_bytes + + priv->rx_stats.data_bytes; s64 tpt = current_tpt - priv->led_tpt; if (tpt < 0) /* wraparound */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 5586003..43b2fce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -745,14 +745,6 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, } #endif -static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->rx_stats[idx].cnt++; - priv->rx_stats[idx].bytes += len; -} - /* * returns non-zero if packet should be dropped */ @@ -930,7 +922,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; - iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); + iwl_update_stats(priv, false, hdr->frame_control, len); memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); ieee80211_rx_irqsafe(priv->hw, rxb->skb); priv->alloc_rxb_skb--; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index c85e54c..9b76bd4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -668,14 +668,6 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, } } -static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->tx_stats[idx].cnt++; - priv->tx_stats[idx].bytes += len; -} - /* * start REPLY_TX command process */ @@ -813,8 +805,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* set is_hcca to 0; it probably will never be implemented */ iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); - iwl_update_tx_stats(priv, le16_to_cpu(fc), len); - + iwl_update_stats(priv, true, fc, len); /* * Use the first empty entry in this queue's command buffer array * to contain the Tx command and MAC header concatenated together diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4f5a3d03..e5fa672 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -599,6 +599,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) tx->len = cpu_to_le16(len); iwl_dbg_log_tx_data_frame(priv, len, hdr); + iwl_update_stats(priv, true, fc, len); tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; -- cgit v0.10.2 From 141b03e07a54af68fc099459bf780a182b240b45 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:41 -0700 Subject: iwlwifi: tx/rx queue pointer information Adding debugfs function to show current TxFifo/RxFifo read/write pointer, plus the current tx queue status (wake/stop) for both real and virtual queue. This is part of debug feature set to help debugging driver/uCode. use tx_queue and rx_queue in /sys/kernel/debug/ieee80211/phy0/iwlagn/debug directory to show the current read/write pointer for both TxFifo and RxFifo queue Signed-off-by: Wey-Yi Guy Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 4ac06ad..cad5e27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -98,6 +98,8 @@ struct iwl_debugfs { struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; struct dentry *file_traffic_log; + struct dentry *file_rx_queue; + struct dentry *file_tx_queue; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index a0e5063..d4109cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -887,9 +887,74 @@ static ssize_t iwl_dbgfs_traffic_log_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + char *buf; + int pos = 0; + int cnt; + int ret; + const size_t bufsz = sizeof(char) * 60 * IWL_MAX_NUM_QUEUES; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { + txq = &priv->txq[cnt]; + q = &txq->q; + pos += scnprintf(buf + pos, bufsz - pos, + "hwq %.2d: read=%u write=%u stop=%d" + " swq_id=%#.2x (ac %d/hwq %d)\n", + cnt, q->read_ptr, q->write_ptr, + !!test_bit(cnt, priv->queue_stopped), + txq->swq_id, + txq->swq_id & 0x80 ? txq->swq_id & 3 : + txq->swq_id, + txq->swq_id & 0x80 ? (txq->swq_id >> 2) & + 0x1f : txq->swq_id); + if (cnt >= 4) + continue; + /* for the ACs, display the stop count too */ + pos += scnprintf(buf + pos, bufsz - pos, + " stop-count: %d\n", + atomic_read(&priv->queue_stop_count[cnt])); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_rx_queue *rxq = &priv->rxq; + char buf[256]; + int pos = 0; + const size_t bufsz = sizeof(buf); + + pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n", + rxq->read); + pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", + rxq->write); + pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n", + rxq->free_count); + pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n", + le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); +DEBUGFS_READ_FILE_OPS(rx_queue); +DEBUGFS_READ_FILE_OPS(tx_queue); /* * Create the debugfs files and directories @@ -934,6 +999,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(rx_statistics, debug); DEBUGFS_ADD_FILE(tx_statistics, debug); DEBUGFS_ADD_FILE(traffic_log, debug); + DEBUGFS_ADD_FILE(rx_queue, debug); + DEBUGFS_ADD_FILE(tx_queue, debug); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -976,6 +1043,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); -- cgit v0.10.2 From e8fe59aecb9020b06305be4f8c67d73cbf49cbd2 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:42 -0700 Subject: iwlwifi: uCode statistics notification counter Display statistics notification information The information break down into uCode_tx_stats uCode_rx_stats uCode_general_stats and can be found in /sys/kernel/debug/ieee80211/phy0/iwlagn/debug directory The statistic information display in debugFs is based on the last statistics notification from uCode; it might not reflect the current uCode activity. Using "watch" command to monitor the uCode activity should give up-to-date statistics provided by uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index cad5e27..18b8cf7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -100,6 +100,9 @@ struct iwl_debugfs { struct dentry *file_traffic_log; struct dentry *file_rx_queue; struct dentry *file_tx_queue; + struct dentry *file_ucode_rx_stats; + struct dentry *file_ucode_tx_stats; + struct dentry *file_ucode_general_stats; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index d4109cb..20e4edb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -950,11 +950,410 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0) +#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1) +#define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2) + +static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, + int bufsz) +{ + int p = 0; + + p += scnprintf(buf + p, bufsz - p, + "Statistics Flag(0x%X):\n", + le32_to_cpu(priv->statistics.flag)); + if (le32_to_cpu(priv->statistics.flag) & UCODE_STATISTICS_CLEAR_MSK) + p += scnprintf(buf + p, bufsz - p, + "\tStatistics have been cleared\n"); + p += scnprintf(buf + p, bufsz - p, + "\tOperational Frequency: %s\n", + (le32_to_cpu(priv->statistics.flag) & + UCODE_STATISTICS_FREQUENCY_MSK) + ? "2.4 GHz" : "5.2 GHz"); + p += scnprintf(buf + p, bufsz - p, + "\tTGj Narrow Band: %s\n", + (le32_to_cpu(priv->statistics.flag) & + UCODE_STATISTICS_NARROW_BAND_MSK) + ? "enabled" : "disabled"); + return p; +} + + +static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_rx_phy) * 20 + + sizeof(struct statistics_rx_non_phy) * 20 + + sizeof(struct statistics_rx_ht_phy) * 20 + 400; + ssize_t ret; + struct statistics_rx_phy *ofdm; + struct statistics_rx_phy *cck; + struct statistics_rx_non_phy *general; + struct statistics_rx_ht_phy *ht; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + ofdm = &priv->statistics.rx.ofdm; + cck = &priv->statistics.rx.cck; + general = &priv->statistics.rx.general; + ht = &priv->statistics.rx.ofdm_ht; + pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n", + le32_to_cpu(ofdm->ina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n", + le32_to_cpu(ofdm->fina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", + le32_to_cpu(ofdm->plcp_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", + le32_to_cpu(ofdm->crc32_err)); + pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", + le32_to_cpu(ofdm->overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", + le32_to_cpu(ofdm->early_overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", + le32_to_cpu(ofdm->crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n", + le32_to_cpu(ofdm->false_alarm_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n", + le32_to_cpu(ofdm->fina_sync_err_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n", + le32_to_cpu(ofdm->sfd_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n", + le32_to_cpu(ofdm->fina_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n", + le32_to_cpu(ofdm->unresponded_rts)); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_limit_overrun: %u\n", + le32_to_cpu(ofdm->rxe_frame_limit_overrun)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", + le32_to_cpu(ofdm->sent_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", + le32_to_cpu(ofdm->sent_cts_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", + le32_to_cpu(ofdm->sent_ba_rsp_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", + le32_to_cpu(ofdm->dsp_self_kill)); + pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", + le32_to_cpu(ofdm->mh_format_err)); + pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", + le32_to_cpu(ofdm->re_acq_main_rssi_sum)); + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n", + le32_to_cpu(cck->ina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n", + le32_to_cpu(cck->fina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", + le32_to_cpu(cck->plcp_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", + le32_to_cpu(cck->crc32_err)); + pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", + le32_to_cpu(cck->overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", + le32_to_cpu(cck->early_overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", + le32_to_cpu(cck->crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n", + le32_to_cpu(cck->false_alarm_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n", + le32_to_cpu(cck->fina_sync_err_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n", + le32_to_cpu(cck->sfd_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n", + le32_to_cpu(cck->fina_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n", + le32_to_cpu(cck->unresponded_rts)); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_limit_overrun: %u\n", + le32_to_cpu(cck->rxe_frame_limit_overrun)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", + le32_to_cpu(cck->sent_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", + le32_to_cpu(cck->sent_cts_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", + le32_to_cpu(cck->sent_ba_rsp_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", + le32_to_cpu(cck->dsp_self_kill)); + pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", + le32_to_cpu(cck->mh_format_err)); + pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", + le32_to_cpu(cck->re_acq_main_rssi_sum)); + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts: %u\n", + le32_to_cpu(general->bogus_cts)); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack: %u\n", + le32_to_cpu(general->bogus_ack)); + pos += scnprintf(buf + pos, bufsz - pos, "non_bssid_frames: %u\n", + le32_to_cpu(general->non_bssid_frames)); + pos += scnprintf(buf + pos, bufsz - pos, "filtered_frames: %u\n", + le32_to_cpu(general->filtered_frames)); + pos += scnprintf(buf + pos, bufsz - pos, "non_channel_beacons: %u\n", + le32_to_cpu(general->non_channel_beacons)); + pos += scnprintf(buf + pos, bufsz - pos, "channel_beacons: %u\n", + le32_to_cpu(general->channel_beacons)); + pos += scnprintf(buf + pos, bufsz - pos, "num_missed_bcon: %u\n", + le32_to_cpu(general->num_missed_bcon)); + pos += scnprintf(buf + pos, bufsz - pos, + "adc_rx_saturation_time: %u\n", + le32_to_cpu(general->adc_rx_saturation_time)); + pos += scnprintf(buf + pos, bufsz - pos, + "ina_detection_search_time: %u\n", + le32_to_cpu(general->ina_detection_search_time)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_a: %u\n", + le32_to_cpu(general->beacon_silence_rssi_a)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_b: %u\n", + le32_to_cpu(general->beacon_silence_rssi_b)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_c: %u\n", + le32_to_cpu(general->beacon_silence_rssi_c)); + pos += scnprintf(buf + pos, bufsz - pos, + "interference_data_flag: %u\n", + le32_to_cpu(general->interference_data_flag)); + pos += scnprintf(buf + pos, bufsz - pos, "channel_load: %u\n", + le32_to_cpu(general->channel_load)); + pos += scnprintf(buf + pos, bufsz - pos, "dsp_false_alarms: %u\n", + le32_to_cpu(general->dsp_false_alarms)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_a: %u\n", + le32_to_cpu(general->beacon_rssi_a)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_b: %u\n", + le32_to_cpu(general->beacon_rssi_b)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_c: %u\n", + le32_to_cpu(general->beacon_rssi_c)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_a: %u\n", + le32_to_cpu(general->beacon_energy_a)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_b: %u\n", + le32_to_cpu(general->beacon_energy_b)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_c: %u\n", + le32_to_cpu(general->beacon_energy_c)); + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", + le32_to_cpu(ht->plcp_err)); + pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", + le32_to_cpu(ht->overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", + le32_to_cpu(ht->early_overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", + le32_to_cpu(ht->crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", + le32_to_cpu(ht->crc32_err)); + pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", + le32_to_cpu(ht->mh_format_err)); + pos += scnprintf(buf + pos, bufsz - pos, "agg_crc32_good: %u\n", + le32_to_cpu(ht->agg_crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "agg_mpdu_cnt: %u\n", + le32_to_cpu(ht->agg_mpdu_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt: %u\n", + le32_to_cpu(ht->agg_cnt)); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = (sizeof(struct statistics_tx) * 24) + 250; + ssize_t ret; + struct statistics_tx *tx; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + tx = &priv->statistics.tx; + pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "preamble: %u\n", + le32_to_cpu(tx->preamble_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "rx_detected_cnt: %u\n", + le32_to_cpu(tx->rx_detected_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_defer_cnt: %u\n", + le32_to_cpu(tx->bt_prio_defer_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_kill_cnt: %u\n", + le32_to_cpu(tx->bt_prio_kill_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "few_bytes_cnt: %u\n", + le32_to_cpu(tx->few_bytes_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout: %u\n", + le32_to_cpu(tx->cts_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "ack_timeout: %u\n", + le32_to_cpu(tx->ack_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "expected_ack_cnt: %u\n", + le32_to_cpu(tx->expected_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "actual_ack_cnt: %u\n", + le32_to_cpu(tx->actual_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "dump_msdu_cnt: %u\n", + le32_to_cpu(tx->dump_msdu_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, + "burst_abort_next_frame_mismatch_cnt: %u\n", + le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, + "burst_abort_missing_next_frame_cnt: %u\n", + le32_to_cpu(tx->burst_abort_missing_next_frame_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout_collision: %u\n", + le32_to_cpu(tx->cts_timeout_collision)); + pos += scnprintf(buf + pos, bufsz - pos, + "ack_or_ba_timeout_collision: %u\n", + le32_to_cpu(tx->ack_or_ba_timeout_collision)); + pos += scnprintf(buf + pos, bufsz - pos, "agg ba_timeout: %u\n", + le32_to_cpu(tx->agg.ba_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, + "agg ba_reschedule_frames: %u\n", + le32_to_cpu(tx->agg.ba_reschedule_frames)); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_agg_frame_cnt: %u\n", + le32_to_cpu(tx->agg.scd_query_agg_frame_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_no_agg: %u\n", + le32_to_cpu(tx->agg.scd_query_no_agg)); + pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_agg: %u\n", + le32_to_cpu(tx->agg.scd_query_agg)); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_mismatch: %u\n", + le32_to_cpu(tx->agg.scd_query_mismatch)); + pos += scnprintf(buf + pos, bufsz - pos, "agg frame_not_ready: %u\n", + le32_to_cpu(tx->agg.frame_not_ready)); + pos += scnprintf(buf + pos, bufsz - pos, "agg underrun: %u\n", + le32_to_cpu(tx->agg.underrun)); + pos += scnprintf(buf + pos, bufsz - pos, "agg bt_prio_kill: %u\n", + le32_to_cpu(tx->agg.bt_prio_kill)); + pos += scnprintf(buf + pos, bufsz - pos, "agg rx_ba_rsp_cnt: %u\n", + le32_to_cpu(tx->agg.rx_ba_rsp_cnt)); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_general) * 4 + 250; + ssize_t ret; + struct statistics_general *general; + struct statistics_dbg *dbg; + struct statistics_div *div; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + general = &priv->statistics.general; + dbg = &priv->statistics.general.dbg; + div = &priv->statistics.general.div; + pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "temperature: %u\n", + le32_to_cpu(general->temperature)); + pos += scnprintf(buf + pos, bufsz - pos, "temperature_m: %u\n", + le32_to_cpu(general->temperature_m)); + pos += scnprintf(buf + pos, bufsz - pos, "burst_check: %u\n", + le32_to_cpu(dbg->burst_check)); + pos += scnprintf(buf + pos, bufsz - pos, "burst_count: %u\n", + le32_to_cpu(dbg->burst_count)); + pos += scnprintf(buf + pos, bufsz - pos, "sleep_time: %u\n", + le32_to_cpu(general->sleep_time)); + pos += scnprintf(buf + pos, bufsz - pos, "slots_out: %u\n", + le32_to_cpu(general->slots_out)); + pos += scnprintf(buf + pos, bufsz - pos, "slots_idle: %u\n", + le32_to_cpu(general->slots_idle)); + pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp: %u\n", + le32_to_cpu(general->ttl_timestamp)); + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a: %u\n", + le32_to_cpu(div->tx_on_a)); + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b: %u\n", + le32_to_cpu(div->tx_on_b)); + pos += scnprintf(buf + pos, bufsz - pos, "exec_time: %u\n", + le32_to_cpu(div->exec_time)); + pos += scnprintf(buf + pos, bufsz - pos, "probe_time: %u\n", + le32_to_cpu(div->probe_time)); + pos += scnprintf(buf + pos, bufsz - pos, "rx_enable_counter: %u\n", + le32_to_cpu(general->rx_enable_counter)); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); DEBUGFS_READ_FILE_OPS(rx_queue); DEBUGFS_READ_FILE_OPS(tx_queue); +DEBUGFS_READ_FILE_OPS(ucode_rx_stats); +DEBUGFS_READ_FILE_OPS(ucode_tx_stats); +DEBUGFS_READ_FILE_OPS(ucode_general_stats); /* * Create the debugfs files and directories @@ -1001,6 +1400,11 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(traffic_log, debug); DEBUGFS_ADD_FILE(rx_queue, debug); DEBUGFS_ADD_FILE(tx_queue, debug); + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { + DEBUGFS_ADD_FILE(ucode_rx_stats, debug); + DEBUGFS_ADD_FILE(ucode_tx_stats, debug); + DEBUGFS_ADD_FILE(ucode_general_stats, debug); + } DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -1045,6 +1449,14 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_rx_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_tx_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_general_stats); + } DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); -- cgit v0.10.2 From 5225935b53ce1eafb222c644230d03ad6011d357 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:43 -0700 Subject: iwlwifi: Display sensitivity and chain noise information Display sensitivity and chain noise data to help understand the current environment and RF condition. The data is feeded by statistics notification and Beacon from uCode; then used by sensitivity calibration and chain noise calibration to determine how DSP should react to the environment changes Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 18b8cf7..82befb7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -103,6 +103,8 @@ struct iwl_debugfs { struct dentry *file_ucode_rx_stats; struct dentry *file_ucode_tx_stats; struct dentry *file_ucode_general_stats; + struct dentry *file_sensitivity; + struct dentry *file_chain_noise; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 20e4edb..1ad4ff6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -38,7 +38,7 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" - +#include "iwl-calib.h" /* create and remove of files */ #define DEBUGFS_ADD_DIR(name, parent) do { \ @@ -1346,6 +1346,145 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + int cnt = 0; + char *buf; + int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100; + ssize_t ret; + struct iwl_sensitivity_data *data; + + data = &priv->sensitivity_data; + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n", + data->auto_corr_ofdm); + pos += scnprintf(buf + pos, bufsz - pos, + "auto_corr_ofdm_mrc:\t\t %u\n", + data->auto_corr_ofdm_mrc); + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n", + data->auto_corr_ofdm_x1); + pos += scnprintf(buf + pos, bufsz - pos, + "auto_corr_ofdm_mrc_x1:\t\t %u\n", + data->auto_corr_ofdm_mrc_x1); + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n", + data->auto_corr_cck); + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n", + data->auto_corr_cck_mrc); + pos += scnprintf(buf + pos, bufsz - pos, + "last_bad_plcp_cnt_ofdm:\t\t %u\n", + data->last_bad_plcp_cnt_ofdm); + pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n", + data->last_fa_cnt_ofdm); + pos += scnprintf(buf + pos, bufsz - pos, + "last_bad_plcp_cnt_cck:\t\t %u\n", + data->last_bad_plcp_cnt_cck); + pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n", + data->last_fa_cnt_cck); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n", + data->nrg_curr_state); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n", + data->nrg_prev_state); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t"); + for (cnt = 0; cnt < 10; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->nrg_value[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t"); + for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->nrg_silence_rssi[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n", + data->nrg_silence_ref); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n", + data->nrg_energy_idx); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n", + data->nrg_silence_idx); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n", + data->nrg_th_cck); + pos += scnprintf(buf + pos, bufsz - pos, + "nrg_auto_corr_silence_diff:\t %u\n", + data->nrg_auto_corr_silence_diff); + pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n", + data->num_in_cck_no_fa); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n", + data->nrg_th_ofdm); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + + +static ssize_t iwl_dbgfs_chain_noise_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + int cnt = 0; + char *buf; + int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100; + ssize_t ret; + struct iwl_chain_noise_data *data; + + data = &priv->chain_noise_data; + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n", + data->active_chains); + pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n", + data->chain_noise_a); + pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n", + data->chain_noise_b); + pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n", + data->chain_noise_c); + pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n", + data->chain_signal_a); + pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n", + data->chain_signal_b); + pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n", + data->chain_signal_c); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n", + data->beacon_count); + + pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t"); + for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->disconn_array[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t"); + for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->delta_gain_code[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n", + data->radio_write); + pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n", + data->state); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1354,6 +1493,8 @@ DEBUGFS_READ_FILE_OPS(tx_queue); DEBUGFS_READ_FILE_OPS(ucode_rx_stats); DEBUGFS_READ_FILE_OPS(ucode_tx_stats); DEBUGFS_READ_FILE_OPS(ucode_general_stats); +DEBUGFS_READ_FILE_OPS(sensitivity); +DEBUGFS_READ_FILE_OPS(chain_noise); /* * Create the debugfs files and directories @@ -1404,6 +1545,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(ucode_rx_stats, debug); DEBUGFS_ADD_FILE(ucode_tx_stats, debug); DEBUGFS_ADD_FILE(ucode_general_stats, debug); + DEBUGFS_ADD_FILE(sensitivity, debug); + DEBUGFS_ADD_FILE(chain_noise, debug); } DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, @@ -1456,6 +1599,10 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) file_ucode_tx_stats); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_general_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_sensitivity); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_chain_noise); } DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); -- cgit v0.10.2 From c03ea16285bf142172f9816b8a1f5c43bb4b4405 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 7 Aug 2009 15:41:44 -0700 Subject: iwlwifi: revert uCode Alive notification with timeout commit "iwlwifi: uCode Alive notification with timeout" introduced a more reliable mechanism for ucode loading. Unfortunately we hit a problem with it frequently enough to make a 4965 unusable. The problem can be seen in debug log below. What this code attempts is to set runtime ucode up to load, start a timer to wait for the alive response from runtime ucode, and if it times out it tries again. As can be seen below we receive the alive response and wake the waiting task _before_ the tasks starts waiting. The task thus times out as the alive response is not received while it is waiting for it and it restarts the device. This starts the cycle all over again. [29739.000819] ieee80211 phy0: U iwl_mac_start enter [29739.005751] ieee80211 phy0: U iwl_prepare_card_hw iwl_prepare_card_hw enter [29739.012798] ieee80211 phy0: U iwl_set_hw_ready hardware ready [29739.057200] ieee80211 phy0: U iwl4965_load_bsm Begin load bsm [29739.063366] ieee80211 phy0: U iwl4965_verify_bsm Begin verify bsm [29739.072485] ieee80211 phy0: U iwl4965_verify_bsm BSM bootstrap uCode image OK [29739.079671] ieee80211 phy0: U iwl4965_load_bsm BSM write complete, poll 0 iterations [29739.257019] ieee80211 phy0: I iwl_rx_reply_alive Alive ucode status 0x00000001 revision 0x1 0x9 [29739.260964] ieee80211 phy0: I iwl_rx_reply_alive Initialization Alive received. [29739.260964] ieee80211 phy0: U __iwl_up iwlagn is coming up [29739.278571] ieee80211 phy0: U iwl_mac_start Start UP work done. [29739.284509] ieee80211 phy0: U iwlcore_verify_inst_sparse ucode inst image size is 788 [29739.292432] ieee80211 phy0: U iwlcore_verify_inst_sparse ucode inst image size is 10312 [29739.302004] ieee80211 phy0: U iwl_verify_ucode Initialize uCode is good in inst SRAM [29739.309746] ieee80211 phy0: U iwl4965_hw_get_temperature Running temperature calibration [29739.317833] ieee80211 phy0: U iwl4965_hw_get_temperature Calib values R[1-3]: -36 13522 -13496 R4: -2726 [29739.327337] ieee80211 phy0: U iwl4965_hw_get_temperature Calibrated temperature: 310K, 37C [29739.335598] ieee80211 phy0: U iwl4965_init_alive_start Initialization Alive received. [29739.343477] ieee80211 phy0: U iwl4965_set_ucode_ptrs Runtime uCode pointers are set. [29739.351283] ieee80211 phy0: I iwl_rx_reply_alive Alive ucode status 0x00000001 revision 0x1 0x0 [29739.355210] ieee80211 phy0: I iwl_rx_reply_alive Runtime Alive received. [29739.366731] iwlagn 0000:03:00.0: Runtime uCode already alive? Waiting for alive anyway [29743.284110] iwlagn 0000:03:00.0: START_ALIVE timeout after 4000ms. [29743.290337] ieee80211 phy0: U iwl_mac_add_interface enter: type 2 [29744.364089] iwlagn 0000:03:00.0: Runtime timeout after 5000ms [29744.370882] ieee80211 phy0: U iwl_alive_start Runtime Alive received. [29744.377347] ieee80211 phy0: U iwlcore_verify_inst_sparse ucode inst image size is 788 [29744.385287] ieee80211 phy0: U iwlcore_verify_inst_sparse ucode inst image size is 10312 [29744.393397] ieee80211 phy0: U iwlcore_verify_inst_sparse ucode inst image size is 94720 [29744.415835] ieee80211 phy0: U iwl_verify_ucode Runtime uCode is good in inst SRAM Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f02023e..e427a89 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Begin load bsm\n"); - priv->ucode_type = UCODE_INIT; + priv->ucode_type = UCODE_RT; /* make sure bootstrap program is no larger than BSM's SRAM size */ if (len > IWL49_MAX_BSM_SIZE) @@ -256,8 +256,6 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) */ static void iwl4965_init_alive_start(struct iwl_priv *priv) { - int ret; - /* Check alive response for "valid" sign from uCode */ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { /* We had an error bringing up the hardware, so take it @@ -289,28 +287,6 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n"); goto restart; } - priv->ucode_type = UCODE_RT; - if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { - IWL_WARN(priv, "Runtime uCode already alive? " - "Waiting for alive anyway\n"); - clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status); - } - ret = wait_event_interruptible_timeout( - priv->wait_command_queue, - test_bit(STATUS_RT_UCODE_ALIVE, &priv->status), - UCODE_ALIVE_TIMEOUT); - if (!ret) { - /* FIXME: if STATUS_RT_UCODE_ALIVE timeout - * go back to restart the download Init uCode again - * this might cause to trap in the restart loop - */ - priv->ucode_type = UCODE_NONE; - if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { - IWL_ERR(priv, "Runtime timeout after %dms\n", - jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); - goto restart; - } - } return; restart: diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c9a1aac..319df4a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -533,16 +533,12 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, if (palive->ver_subtype == INITIALIZE_SUBTYPE) { IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); memcpy(&priv->card_alive_init, &pkt->u.alive_frame, sizeof(struct iwl_init_alive_resp)); pwork = &priv->init_alive_start; } else { IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - set_bit(STATUS_RT_UCODE_ALIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); memcpy(&priv->card_alive, &pkt->u.alive_frame, sizeof(struct iwl_alive_resp)); pwork = &priv->alive_start; @@ -1784,7 +1780,6 @@ static int __iwl_up(struct iwl_priv *priv) { int i; int ret; - unsigned long status; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); @@ -1862,51 +1857,6 @@ static int __iwl_up(struct iwl_priv *priv) /* start card; "initialize" will load runtime ucode */ iwl_nic_start(priv); - /* Just finish download Init or Runtime uCode image to device - * now we wait here for uCode send REPLY_ALIVE notification - * to indicate uCode is ready. - * 1) For Init uCode image, all iwlagn devices should wait here - * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before - * receive the REPLY_ALIVE notification, go back and try to - * download the Init uCode image again. - * 2) For Runtime uCode image, all iwlagn devices except 4965 - * wait here on STATUS_RT_UCODE_ALIVE status bit; if - * timeout before receive the REPLY_ALIVE notification, go back - * and download the Runtime uCode image again. - * 3) For 4965 Runtime uCode, it will not go through this path, - * need to wait for STATUS_RT_UCODE_ALIVE status bit in - * iwl4965_init_alive_start() function; if timeout, need to - * restart and download Init uCode image. - */ - if (priv->ucode_type == UCODE_INIT) - status = STATUS_INIT_UCODE_ALIVE; - else - status = STATUS_RT_UCODE_ALIVE; - if (test_bit(status, &priv->status)) { - IWL_WARN(priv, - "%s uCode already alive? " - "Waiting for alive anyway\n", - (status == STATUS_INIT_UCODE_ALIVE) - ? "INIT" : "Runtime"); - clear_bit(status, &priv->status); - } - ret = wait_event_interruptible_timeout( - priv->wait_command_queue, - test_bit(status, &priv->status), - UCODE_ALIVE_TIMEOUT); - if (!ret) { - if (!test_bit(status, &priv->status)) { - priv->ucode_type = - (status == STATUS_INIT_UCODE_ALIVE) - ? UCODE_NONE : UCODE_INIT; - IWL_ERR(priv, - "%s timeout after %dms\n", - (status == STATUS_INIT_UCODE_ALIVE) - ? "INIT" : "Runtime", - jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); - continue; - } - } IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 202bc39..79170a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1343,17 +1343,10 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; - switch (priv->ucode_type) { - case UCODE_RT: - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); - break; - case UCODE_INIT: + if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - break; - default: - IWL_ERR(priv, "uCode image not available\n"); - return; - } + else + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); @@ -1405,17 +1398,10 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, if (num_events == 0) return; - switch (priv->ucode_type) { - case UCODE_RT: - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - break; - case UCODE_INIT: + if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - break; - default: - IWL_ERR(priv, "uCode image not available\n"); - return; - } + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (mode == 0) event_size = 2 * sizeof(u32); @@ -1452,17 +1438,10 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ - switch (priv->ucode_type) { - case UCODE_RT: - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - break; - case UCODE_INIT: + if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - break; - default: - IWL_ERR(priv, "uCode image not available\n"); - return; - } + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index fc096b9..ea8748d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -547,8 +547,6 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 #define STATUS_MODE_PENDING 18 -#define STATUS_INIT_UCODE_ALIVE 19 -#define STATUS_RT_UCODE_ALIVE 20 static inline int iwl_is_ready(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index dcf9d57..61f9523 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -823,8 +823,6 @@ struct iwl_calib_result { size_t buf_len; }; -#define UCODE_ALIVE_TIMEOUT (5 * HZ) - enum ucode_type { UCODE_NONE = 0, UCODE_INIT, -- cgit v0.10.2 From a28027cd7f169edc399fe4b76d3a33b0203049a1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:45 -0700 Subject: iwlwifi: fix thermal throttling locking problem Move all the thermal throttling functions to background task to make sure do not change power and rx chain in interrupt handler. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 61f9523..35d07a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1197,6 +1197,9 @@ struct iwl_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; + struct work_struct tt_work; + struct work_struct ct_enter; + struct work_struct ct_exit; struct tasklet_struct irq_tasklet; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 594b5c2..9c05af7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -481,6 +481,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) tt->tt_power_mode = IWL_POWER_INDEX_5; break; } + mutex_lock(&priv->mutex); if (iwl_power_update_mode(priv, true)) { /* TT state not updated * try again during next temperature read @@ -499,6 +500,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) IWL_DEBUG_POWER(priv, "Power Index change to %u\n", tt->tt_power_mode); } + mutex_unlock(&priv->mutex); } } @@ -609,6 +611,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) * in case get disabled before */ iwl_set_rxon_ht(priv, &priv->current_ht_config); } + mutex_lock(&priv->mutex); if (iwl_power_update_mode(priv, true)) { /* TT state not updated * try again during next temperature read @@ -631,6 +634,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) iwl_perform_ct_kill_task(priv, false); } } + mutex_unlock(&priv->mutex); } } @@ -644,13 +648,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) * for advance mode * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state */ -void iwl_tt_enter_ct_kill(struct iwl_priv *priv) +static void iwl_bg_ct_enter(struct work_struct *work) { + struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter); struct iwl_tt_mgmt *tt = &priv->power_data.tt; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + if (!iwl_is_ready(priv)) + return; + if (tt->state != IWL_TI_CT_KILL) { IWL_ERR(priv, "Device reached critical temperature " "- ucode going to sleep!\n"); @@ -662,20 +670,23 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) CT_KILL_THRESHOLD + 1); } } -EXPORT_SYMBOL(iwl_tt_enter_ct_kill); /* Card State Notification indicated out of critical temperature * since Card State Notification will not provide any temperature reading * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state */ -void iwl_tt_exit_ct_kill(struct iwl_priv *priv) +static void iwl_bg_ct_exit(struct work_struct *work) { + struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit); struct iwl_tt_mgmt *tt = &priv->power_data.tt; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + if (!iwl_is_ready(priv)) + return; + /* stop ct_kill_exit_tm timer */ del_timer_sync(&priv->power_data.ct_kill_exit_tm); @@ -690,10 +701,30 @@ void iwl_tt_exit_ct_kill(struct iwl_priv *priv) iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); } } + +void iwl_tt_enter_ct_kill(struct iwl_priv *priv) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n"); + queue_work(priv->workqueue, &priv->ct_enter); +} +EXPORT_SYMBOL(iwl_tt_enter_ct_kill); + +void iwl_tt_exit_ct_kill(struct iwl_priv *priv) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n"); + queue_work(priv->workqueue, &priv->ct_exit); +} EXPORT_SYMBOL(iwl_tt_exit_ct_kill); -void iwl_tt_handler(struct iwl_priv *priv) +static void iwl_bg_tt_work(struct work_struct *work) { + struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work); s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -707,6 +738,15 @@ void iwl_tt_handler(struct iwl_priv *priv) else iwl_advance_tt_handler(priv, temp); } + +void iwl_tt_handler(struct iwl_priv *priv) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n"); + queue_work(priv->workqueue, &priv->tt_work); +} EXPORT_SYMBOL(iwl_tt_handler); /* Thermal throttling initialization @@ -731,6 +771,12 @@ void iwl_tt_initialize(struct iwl_priv *priv) init_timer(&priv->power_data.ct_kill_exit_tm); priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; + + /* setup deferred ct kill work */ + INIT_WORK(&priv->tt_work, iwl_bg_tt_work); + INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); + INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_6x00: case CSR_HW_REV_TYPE_6x50: @@ -782,6 +828,9 @@ void iwl_tt_exit(struct iwl_priv *priv) /* stop ct_kill_exit_tm timer if activated */ del_timer_sync(&priv->power_data.ct_kill_exit_tm); + cancel_work_sync(&priv->tt_work); + cancel_work_sync(&priv->ct_enter); + cancel_work_sync(&priv->ct_exit); if (priv->power_data.adv_tt) { /* free advance thermal throttling memory */ -- cgit v0.10.2 From ee9f29894fc3819c1bd639fc3a886326bb809266 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:46 -0700 Subject: iwlwifi: fix legacy thermal throttling power index For legacy thermal throttling, set the new Thermal Throttling state and change power index when thermal throttling manager detects temperature changed. The current implementation sets the state to the previous Thermal Throttling state, which causes system to enter wrong power index. The worse case, it will trying to set the lower power index when device reach critical temperature, it will cuase issue for both system and the device. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 9c05af7..bd97a0d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -425,7 +425,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) { struct iwl_tt_mgmt *tt = &priv->power_data.tt; - enum iwl_tt_state new_state; + enum iwl_tt_state old_state; struct iwl_power_mgr *setting = &priv->power_data; #ifdef CONFIG_IWLWIFI_DEBUG @@ -438,26 +438,27 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) (temp - tt->tt_previous_temp)); } #endif + old_state = tt->state; /* in Celsius */ if (temp >= IWL_MINIMAL_POWER_THRESHOLD) - new_state = IWL_TI_CT_KILL; + tt->state = IWL_TI_CT_KILL; else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2) - new_state = IWL_TI_2; + tt->state = IWL_TI_2; else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1) - new_state = IWL_TI_1; + tt->state = IWL_TI_1; else - new_state = IWL_TI_0; + tt->state = IWL_TI_0; #ifdef CONFIG_IWLWIFI_DEBUG tt->tt_previous_temp = temp; #endif - if (tt->state != new_state) { - if (tt->state == IWL_TI_0) { + if (tt->state != old_state) { + if (old_state == IWL_TI_0) { tt->sys_power_mode = setting->power_mode; IWL_DEBUG_POWER(priv, "current power mode: %u\n", setting->power_mode); } - switch (new_state) { + switch (tt->state) { case IWL_TI_0: /* when system ready to go back to IWL_TI_0 state * using system power mode instead of TT power mode @@ -486,15 +487,15 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) /* TT state not updated * try again during next temperature read */ + tt->state = old_state; IWL_ERR(priv, "Cannot update power mode, " "TT state not updated\n"); } else { - if (new_state == IWL_TI_CT_KILL) + if (tt->state == IWL_TI_CT_KILL) iwl_perform_ct_kill_task(priv, true); - else if (tt->state == IWL_TI_CT_KILL && - new_state != IWL_TI_CT_KILL) + else if (old_state == IWL_TI_CT_KILL && + tt->state != IWL_TI_CT_KILL) iwl_perform_ct_kill_task(priv, false); - tt->state = new_state; IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", tt->state); IWL_DEBUG_POWER(priv, "Power Index change to %u\n", -- cgit v0.10.2 From 3a780d25428a0a391a8ba6c888cf4e89ac3fdbb1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:47 -0700 Subject: iwlwifi: handle the case when set power fail Modify the power update function, when driver fail to set the power, it should not continue move forward and try to change the rx chain configuration. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index bd97a0d..9e8916d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -282,18 +282,21 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) cmd.flags |= IWL_POWER_FAST_PD; ret = iwl_set_power(priv, &cmd); - - if (final_mode == IWL_POWER_MODE_CAM) - clear_bit(STATUS_POWER_PMI, &priv->status); - - if (priv->cfg->ops->lib->update_chain_flags && update_chains) - priv->cfg->ops->lib->update_chain_flags(priv); - else - IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise " + if (!ret) { + if (final_mode == IWL_POWER_MODE_CAM) + clear_bit(STATUS_POWER_PMI, &priv->status); + + if (priv->cfg->ops->lib->update_chain_flags && + update_chains) + priv->cfg->ops->lib->update_chain_flags(priv); + else + IWL_DEBUG_POWER(priv, + "Cannot update the power, chain noise " "calibration running: %d\n", priv->chain_noise_data.state); - if (!ret) setting->power_mode = final_mode; + } else + IWL_ERR(priv, "set power fail, ret = %d", ret); } return ret; -- cgit v0.10.2 From 3ad3b92a5517c043ef30e4b95c4c39a35bbc36be Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 15:41:48 -0700 Subject: iwlwifi: refactor some thermal throttle code Some of the thermal throttle data structures and code are really very intermingled with the sleep (power) control code. They really do belong together in a way since the thermal throttle code uses powersaving to achieve its goal, but it's making it hard to work on the powersave code. Split this up to make that easier. I've also changed the antenna defines to an enum and used the same enum for RX and TX. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 0c3ed23..2133155 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1401,7 +1401,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, if (!iwl_ht_enabled(priv)) /* stay in Legacy */ tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; - else if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && + else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE && tbl->action > IWL_LEGACY_SWITCH_SISO) tbl->action = IWL_LEGACY_SWITCH_SISO; for (; ;) { @@ -1535,7 +1535,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, u8 update_search_tbl_counter = 0; int ret; - if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && + if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE && tbl->action > IWL_SISO_SWITCH_ANTENNA2) { /* stay in SISO */ tbl->action = IWL_SISO_SWITCH_ANTENNA1; @@ -1674,7 +1674,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, u8 update_search_tbl_counter = 0; int ret; - if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && + if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) && (tbl->action < IWL_MIMO2_SWITCH_SISO_A || tbl->action > IWL_MIMO2_SWITCH_SISO_C)) { /* switch in SISO */ @@ -1816,7 +1816,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, int ret; u8 update_search_tbl_counter = 0; - if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && + if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) && (tbl->action < IWL_MIMO3_SWITCH_SISO_A || tbl->action > IWL_MIMO3_SWITCH_SISO_C)) { /* switch in SISO */ @@ -2202,7 +2202,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* If we are searching for better modulation mode, check success. */ if (lq_sta->search_better_tbl && - (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI)) { + (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI)) { /* If good success, continue using the "search" mode; * no need to send new link quality command, since we're * continuing to use the setup that we've been trying. */ @@ -2332,7 +2332,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, scale_action = 0; if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type)) scale_action = -1; - if (iwl_tx_ant_restriction(priv) != IWL_TX_MULTI && + if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI && (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) scale_action = -1; switch (scale_action) { @@ -2368,7 +2368,7 @@ lq_update: rate = rs_update_rate_tbl(priv, lq_sta, tbl, index, is_green); - if (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI) { + if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) { /* Should we stay with this modulation mode, * or search for a new one? */ rs_stay_in_table(lq_sta); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 79170a9..22961e9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2214,7 +2214,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); - priv->power_data.ct_kill_toggle = false; + priv->thermal_throttle.ct_kill_toggle = false; switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_1000: diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 1ad4ff6..7b578d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -704,7 +704,7 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; char buf[100]; int pos = 0; @@ -713,12 +713,11 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, "Thermal Throttling Mode: %s\n", - (priv->power_data.adv_tt) - ? "Advance" : "Legacy"); + tt->advanced_tt ? "Advance" : "Legacy"); pos += scnprintf(buf + pos, bufsz - pos, "Thermal Throttling State: %d\n", tt->state); - if (priv->power_data.adv_tt) { + if (tt->advanced_tt) { restriction = tt->restriction + tt->state; pos += scnprintf(buf + pos, bufsz - pos, "Tx mode: %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 35d07a8..1aa2ae6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1111,6 +1111,7 @@ struct iwl_priv { struct isr_statistics isr_stats; struct iwl_power_mgr power_data; + struct iwl_tt_mgmt thermal_throttle; struct iwl_notif_statistics statistics; unsigned long last_statistics_time; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 9e8916d..27ad59d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -132,10 +132,10 @@ static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = { /* Advance Thermal Throttling default restriction table */ static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { - {IWL_TX_MULTI, true, IWL_RX_MULTI}, - {IWL_TX_SINGLE, true, IWL_RX_MULTI}, - {IWL_TX_SINGLE, false, IWL_RX_SINGLE}, - {IWL_TX_NONE, false, IWL_RX_NONE} + {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true }, + {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true }, + {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false }, + {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false } }; /* set card power command */ @@ -251,7 +251,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) { struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; u16 uninitialized_var(final_mode); bool update_chains; @@ -317,35 +317,35 @@ EXPORT_SYMBOL(iwl_power_set_user_mode); bool iwl_ht_enabled(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) return true; restriction = tt->restriction + tt->state; return restriction->is_ht; } EXPORT_SYMBOL(iwl_ht_enabled); -u8 iwl_tx_ant_restriction(struct iwl_priv *priv) +enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; - if (!priv->power_data.adv_tt) - return IWL_TX_MULTI; + if (!priv->thermal_throttle.advanced_tt) + return IWL_ANT_OK_MULTI; restriction = tt->restriction + tt->state; return restriction->tx_stream; } EXPORT_SYMBOL(iwl_tx_ant_restriction); -u8 iwl_rx_ant_restriction(struct iwl_priv *priv) +enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; - if (!priv->power_data.adv_tt) - return IWL_RX_MULTI; + if (!priv->thermal_throttle.advanced_tt) + return IWL_ANT_OK_MULTI; restriction = tt->restriction + tt->state; return restriction->rx_stream; } @@ -364,21 +364,21 @@ EXPORT_SYMBOL(iwl_rx_ant_restriction); static void iwl_tt_check_exit_ct_kill(unsigned long data) { struct iwl_priv *priv = (struct iwl_priv *)data; - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; unsigned long flags; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; if (tt->state == IWL_TI_CT_KILL) { - if (priv->power_data.ct_kill_toggle) { + if (priv->thermal_throttle.ct_kill_toggle) { iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - priv->power_data.ct_kill_toggle = false; + priv->thermal_throttle.ct_kill_toggle = false; } else { iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - priv->power_data.ct_kill_toggle = true; + priv->thermal_throttle.ct_kill_toggle = true; } iwl_read32(priv, CSR_UCODE_DRV_GP1); spin_lock_irqsave(&priv->reg_lock, flags); @@ -389,7 +389,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) /* Reschedule the ct_kill timer to occur in * CT_KILL_EXIT_DURATION seconds to ensure we get a * thermal update */ - mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + + mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + CT_KILL_EXIT_DURATION * HZ); } } @@ -403,7 +403,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, ieee80211_stop_queues(priv->hw); IWL_DEBUG_POWER(priv, "Schedule 5 seconds CT_KILL Timer\n"); - mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + + mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + CT_KILL_EXIT_DURATION * HZ); } else { IWL_DEBUG_POWER(priv, "Wake all queues\n"); @@ -427,7 +427,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, */ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; enum iwl_tt_state old_state; struct iwl_power_mgr *setting = &priv->power_data; @@ -531,7 +531,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) */ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; int i; bool changed = false; enum iwl_tt_state old_state; @@ -655,7 +655,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) static void iwl_bg_ct_enter(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter); - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -666,7 +666,7 @@ static void iwl_bg_ct_enter(struct work_struct *work) if (tt->state != IWL_TI_CT_KILL) { IWL_ERR(priv, "Device reached critical temperature " "- ucode going to sleep!\n"); - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, IWL_MINIMAL_POWER_THRESHOLD); else @@ -683,7 +683,7 @@ static void iwl_bg_ct_enter(struct work_struct *work) static void iwl_bg_ct_exit(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit); - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -692,13 +692,13 @@ static void iwl_bg_ct_exit(struct work_struct *work) return; /* stop ct_kill_exit_tm timer */ - del_timer_sync(&priv->power_data.ct_kill_exit_tm); + del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); if (tt->state == IWL_TI_CT_KILL) { IWL_ERR(priv, "Device temperature below critical" "- ucode awake!\n"); - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, IWL_REDUCED_PERFORMANCE_THRESHOLD_2); else @@ -737,7 +737,7 @@ static void iwl_bg_tt_work(struct work_struct *work) if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) temp = KELVIN_TO_CELSIUS(priv->temperature); - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, temp); else iwl_advance_tt_handler(priv, temp); @@ -760,7 +760,7 @@ EXPORT_SYMBOL(iwl_tt_handler); */ void iwl_tt_initialize(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_power_mgr *setting = &priv->power_data; int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); struct iwl_tt_trans *transaction; @@ -772,9 +772,9 @@ void iwl_tt_initialize(struct iwl_priv *priv) tt->state = IWL_TI_0; tt->sys_power_mode = setting->power_mode; tt->tt_power_mode = tt->sys_power_mode; - init_timer(&priv->power_data.ct_kill_exit_tm); - priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; - priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; + init_timer(&priv->thermal_throttle.ct_kill_exit_tm); + priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; + priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; /* setup deferred ct kill work */ INIT_WORK(&priv->tt_work, iwl_bg_tt_work); @@ -792,7 +792,7 @@ void iwl_tt_initialize(struct iwl_priv *priv) GFP_KERNEL); if (!tt->restriction || !tt->transaction) { IWL_ERR(priv, "Fallback to Legacy Throttling\n"); - priv->power_data.adv_tt = false; + priv->thermal_throttle.advanced_tt = false; kfree(tt->restriction); tt->restriction = NULL; kfree(tt->transaction); @@ -814,12 +814,12 @@ void iwl_tt_initialize(struct iwl_priv *priv) IWL_TI_STATE_MAX; memcpy(tt->restriction, &restriction_range[0], size); - priv->power_data.adv_tt = true; + priv->thermal_throttle.advanced_tt = true; } break; default: IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); - priv->power_data.adv_tt = false; + priv->thermal_throttle.advanced_tt = false; break; } } @@ -828,15 +828,15 @@ EXPORT_SYMBOL(iwl_tt_initialize); /* cleanup thermal throttling management related memory and timer */ void iwl_tt_exit(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; /* stop ct_kill_exit_tm timer if activated */ - del_timer_sync(&priv->power_data.ct_kill_exit_tm); + del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); cancel_work_sync(&priv->tt_work); cancel_work_sync(&priv->ct_enter); cancel_work_sync(&priv->ct_exit); - if (priv->power_data.adv_tt) { + if (priv->thermal_throttle.advanced_tt) { /* free advance thermal throttling memory */ kfree(tt->restriction); tt->restriction = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 3d49b7a..15e3eab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -37,13 +37,11 @@ struct iwl_priv; #define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 -/* Tx/Rx restrictions */ -#define IWL_TX_MULTI 0x02 -#define IWL_TX_SINGLE 0x01 -#define IWL_TX_NONE 0x00 -#define IWL_RX_MULTI 0x02 -#define IWL_RX_SINGLE 0x01 -#define IWL_RX_NONE 0x00 +enum iwl_antenna_ok { + IWL_ANT_OK_NONE, + IWL_ANT_OK_SINGLE, + IWL_ANT_OK_MULTI, +}; /* Thermal Throttling State Machine states */ enum iwl_tt_state { @@ -55,27 +53,30 @@ enum iwl_tt_state { }; /** - * struct iwl_tt_restriction - Thermal Throttling restriction table used - * by advance thermal throttling management - * based on the current thermal throttling state, determine - * number of tx/rx streams; and the status of HT operation + * struct iwl_tt_restriction - Thermal Throttling restriction table * @tx_stream: number of tx stream allowed * @is_ht: ht enable/disable * @rx_stream: number of rx stream allowed + * + * This table is used by advance thermal throttling management + * based on the current thermal throttling state, and determines + * the number of tx/rx streams and the status of HT operation. */ struct iwl_tt_restriction { - u8 tx_stream; + enum iwl_antenna_ok tx_stream; + enum iwl_antenna_ok rx_stream; bool is_ht; - u8 rx_stream; }; /** - * struct iwl_tt_trans - Thermal Throttling transaction table; used by - * advance thermal throttling algorithm to determine next - * thermal state to go based on the current temperature + * struct iwl_tt_trans - Thermal Throttling transaction table * @next_state: next thermal throttling mode * @tt_low: low temperature threshold to change state * @tt_high: high temperature threshold to change state + * + * This is used by the advanced thermal throttling algorithm + * to determine the next thermal state to go based on the + * current temperature. */ struct iwl_tt_trans { enum iwl_tt_state next_state; @@ -85,6 +86,7 @@ struct iwl_tt_trans { /** * struct iwl_tt_mgnt - Thermal Throttling Management structure + * @advanced_tt: advanced thermal throttle required * @state: current Thermal Throttling state * @tt_power_mode: Thermal Throttling power mode index * being used to set power level when @@ -99,16 +101,21 @@ struct iwl_tt_trans { * should be used in tt state; and can HT be enabled or not * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling * state transaction + * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature + * @ct_kill_exit_tm: timer to exit thermal kill */ struct iwl_tt_mgmt { enum iwl_tt_state state; + bool advanced_tt; u8 tt_power_mode; u8 sys_power_mode; + bool ct_kill_toggle; #ifdef CONFIG_IWLWIFI_DEBUG s32 tt_previous_temp; #endif struct iwl_tt_restriction *restriction; struct iwl_tt_trans *transaction; + struct timer_list ct_kill_exit_tm; }; enum { @@ -137,20 +144,13 @@ struct iwl_power_mgr { u8 power_mode; u8 user_power_setting; /* set by user through sysfs */ u8 power_disabled; /* set by mac80211's CONF_PS */ - struct iwl_tt_mgmt tt; /* Thermal Throttling Management */ - bool adv_tt; /* false: legacy mode */ - /* true: advance mode */ - bool ct_kill_toggle; /* use to toggle the CSR bit when - * checking uCode temperature - */ - struct timer_list ct_kill_exit_tm; }; int iwl_power_update_mode(struct iwl_priv *priv, bool force); int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); bool iwl_ht_enabled(struct iwl_priv *priv); -u8 iwl_tx_ant_restriction(struct iwl_priv *priv); -u8 iwl_rx_ant_restriction(struct iwl_priv *priv); +enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv); +enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv); void iwl_tt_enter_ct_kill(struct iwl_priv *priv); void iwl_tt_exit_ct_kill(struct iwl_priv *priv); void iwl_tt_handler(struct iwl_priv *priv); -- cgit v0.10.2 From 450ccb36b4d8a18c34643335d3305ec1a781e717 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 7 Aug 2009 15:41:49 -0700 Subject: iwlwifi: fix missing EXPORT_SYMBOL When compiling without CONFIG_IWLWIFI_DEBUGFS there is a missing iwl_update_stats symbol. This is fixed by making this function an inline in the case when CONFIG_IWLWIFI_DEBUGFS is not set due to the hot path in which it is used. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 22961e9..44d01a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -3172,22 +3172,6 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) } } EXPORT_SYMBOL(iwl_update_stats); - -#else -void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) -{ - struct traffic_stats *stats; - - if (is_tx) - stats = &priv->tx_stats; - else - stats = &priv->rx_stats; - - if (ieee80211_is_data(fc)) { - /* data */ - stats->data_bytes += len; - } -} #endif #ifdef CONFIG_PM diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ea8748d..32750f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -314,6 +314,8 @@ const char *get_mgmt_string(int cmd); const char *get_ctrl_string(int cmd); void iwl_clear_tx_stats(struct iwl_priv *priv); void iwl_clear_rx_stats(struct iwl_priv *priv); +void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, + u16 len); #else static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv) { @@ -333,9 +335,22 @@ static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, u16 length, struct ieee80211_hdr *header) { } +static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx, + __le16 fc, u16 len) +{ + struct traffic_stats *stats; + + if (is_tx) + stats = &priv->tx_stats; + else + stats = &priv->rx_stats; + + if (ieee80211_is_data(fc)) { + /* data */ + stats->data_bytes += len; + } +} #endif -void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, - u16 len); /***************************************************** * RX handlers. * **************************************************/ -- cgit v0.10.2 From d91b1ba37744bc7fb7524516be855c9fa81142e2 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:50 -0700 Subject: iwlwifi: display correct critical temperature infomation Do not send CT KILL config command twice and correct critical temperature informatiom in dmesg Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 44d01a2..36c6e16 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2227,6 +2227,15 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(adv_cmd), &adv_cmd); + if (ret) + IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); + else + IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " + "succeeded, " + "critical temperature enter is %d," + "exit is %d\n", + priv->hw_params.ct_kill_threshold, + priv->hw_params.ct_kill_exit_threshold); break; default: cmd.critical_temperature_R = @@ -2234,16 +2243,15 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); + if (ret) + IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); + else + IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " + "succeeded, " + "critical temperature is %d\n", + priv->hw_params.ct_kill_threshold); break; } - ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); - else - IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD succeeded, " - "critical temperature is %d\n", - cmd.critical_temperature_R); } EXPORT_SYMBOL(iwl_rf_kill_ct_config); -- cgit v0.10.2 From e312c24cf8229f9b6e76dbfd5d99eefe21f4ac0a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 15:41:51 -0700 Subject: iwlwifi: automatically adjust sleep level Depending on required latency requested by pm_qos (via mac80211) we can automatically adjust the sleep state. Also, mac80211 has a user-visible dynamic sleep feature where we are supposed to stay awake after sending/receiving frames to better receive response frames to our packets, this can be integrated into the sleep command. Currently, and this patch doesn't change that yet, we default to using sleep level 1 if PS is enabled. With a module parameter to iwlcore, automatic adjustment to changing network latency requirements can be enabled -- this isn't yet the default due to requiring more testing. The goal is to enable automatic adjustment and then go into the deepest possible sleep state possible depending on the networking latency requirements. This patch does, however, enable IEEE80211_HW_SUPPORTS_DYNAMIC_PS to avoid the double-timer (one in software and one in the device) when transmitting -- the exact timeout may be ignored but that is not of big concern. Note also that we keep the hard-coded power indices around for thermal throttling -- the specification of that calls for using the specified power levels. Those can also be selected in debugfs to allow easier testing of such parameters. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 319df4a..2232b17 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1606,7 +1606,7 @@ static void iwl_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); - iwl_power_update_mode(priv, 1); + iwl_power_update_mode(priv, true); /* reassociate for ADHOC mode */ if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { @@ -2075,7 +2075,7 @@ void iwl_post_associate(struct iwl_priv *priv) * If chain noise has already been run, then we need to enable * power management here */ if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) - iwl_power_update_mode(priv, 0); + iwl_power_update_mode(priv, false); /* Enable Rx differential gain and sensitivity calibrations */ iwl_chain_noise_reset(priv); @@ -2565,47 +2565,6 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -static ssize_t store_power_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int ret; - unsigned long mode; - - - mutex_lock(&priv->mutex); - - ret = strict_strtoul(buf, 10, &mode); - if (ret) - goto out; - - ret = iwl_power_set_user_mode(priv, mode); - if (ret) { - IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n"); - goto out; - } - ret = count; - - out: - mutex_unlock(&priv->mutex); - return ret; -} - -static ssize_t show_power_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int level = priv->power_data.power_mode; - char *p = buf; - - p += sprintf(p, "%d\n", level); - return p - buf + 1; -} - -static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, - store_power_level); - static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) @@ -2698,7 +2657,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) static struct attribute *iwl_sysfs_entries[] = { &dev_attr_flags.attr, &dev_attr_filter_flags.attr, - &dev_attr_power_level.attr, &dev_attr_statistics.attr, &dev_attr_temperature.attr, &dev_attr_tx_power.attr, diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 13180d6..c4b565a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -852,7 +852,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, priv->cfg->ops->lib->update_chain_flags(priv); data->state = IWL_CHAIN_NOISE_DONE; - iwl_power_update_mode(priv, 0); + iwl_power_update_mode(priv, false); } EXPORT_SYMBOL(iwl_chain_noise_calibration); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6188c54..68d7719 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2313,15 +2313,22 @@ struct iwl_spectrum_notification { * PM allow: * bit 0 - '0' Driver not allow power management * '1' Driver allow PM (use rest of parameters) + * * uCode send sleep notifications: * bit 1 - '0' Don't send sleep notification * '1' send sleep notification (SEND_PM_NOTIFICATION) + * * Sleep over DTIM * bit 2 - '0' PM have to walk up every DTIM * '1' PM could sleep over DTIM till listen Interval. + * * PCI power managed * bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1) * '1' !(PCI_CFG_LINK_CTRL & 0x1) + * + * Fast PD + * bit 4 - '1' Put radio to sleep when receiving frame for others + * * Force sleep Modes * bit 31/30- '00' use both mac/xtal sleeps * '01' force Mac sleep diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 36c6e16..af73512 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1568,7 +1568,8 @@ int iwl_setup_mac(struct iwl_priv *priv) IEEE80211_HW_NOISE_DBM | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_SUPPORTS_PS; + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); @@ -1663,8 +1664,6 @@ int iwl_init_drv(struct iwl_priv *priv) priv->qos_data.qos_cap.val = 0; priv->rates_mask = IWL_RATES_MASK; - /* If power management is turned on, default to CAM mode */ - priv->power_mode = IWL_POWER_MODE_CAM; priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; ret = iwl_init_channel_map(priv); @@ -2551,7 +2550,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, if (bss_conf->assoc) { priv->assoc_id = bss_conf->aid; priv->beacon_int = bss_conf->beacon_int; - priv->power_data.dtim_period = bss_conf->dtim_period; priv->timestamp = bss_conf->timestamp; priv->assoc_capability = bss_conf->assoc_capability; @@ -2801,13 +2799,10 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) iwl_set_rate(priv); } - if (changed & IEEE80211_CONF_CHANGE_PS && - priv->iw_mode == NL80211_IFTYPE_STATION) { - priv->power_data.power_disabled = - !(conf->flags & IEEE80211_CONF_PS); - ret = iwl_power_update_mode(priv, 0); + if (changed & IEEE80211_CONF_CHANGE_PS) { + ret = iwl_power_update_mode(priv, false); if (ret) - IWL_DEBUG_MAC80211(priv, "Error setting power level\n"); + IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); } if (changed & IEEE80211_CONF_CHANGE_POWER) { diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 82befb7..723f38a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -88,6 +88,8 @@ struct iwl_debugfs { struct dentry *file_led; #endif struct dentry *file_disable_ht40; + struct dentry *file_sleep_level_override; + struct dentry *file_current_sleep_command; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 7b578d4..f68fb47 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -776,6 +776,83 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int value; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + if (sscanf(buf, "%d", &value) != 1) + return -EINVAL; + + /* + * Our users expect 0 to be "CAM", but 0 isn't actually + * valid here. However, let's not confuse them and present + * IWL_POWER_INDEX_1 as "1", not "0". + */ + if (value > 0) + value -= 1; + + if (value != -1 && (value < 0 || value >= IWL_POWER_NUM)) + return -EINVAL; + + priv->power_data.debug_sleep_level_override = value; + + iwl_power_update_mode(priv, false); + + return count; +} + +static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[10]; + int pos, value; + const size_t bufsz = sizeof(buf); + + /* see the write function */ + value = priv->power_data.debug_sleep_level_override; + if (value >= 0) + value += 1; + + pos = scnprintf(buf, bufsz, "%d\n", value); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[200]; + int pos = 0, i; + const size_t bufsz = sizeof(buf); + struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd; + + pos += scnprintf(buf + pos, bufsz - pos, + "flags: %#.2x\n", le16_to_cpu(cmd->flags)); + pos += scnprintf(buf + pos, bufsz - pos, + "RX/TX timeout: %d/%d usec\n", + le32_to_cpu(cmd->rx_data_timeout), + le32_to_cpu(cmd->tx_data_timeout)); + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "sleep_interval[%d]: %d\n", i, + le32_to_cpu(cmd->sleep_interval[i])); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); @@ -789,6 +866,8 @@ DEBUGFS_READ_FILE_OPS(led); #endif DEBUGFS_READ_FILE_OPS(thermal_throttling); DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); +DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); +DEBUGFS_READ_FILE_OPS(current_sleep_command); static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, char __user *user_buf, @@ -1533,6 +1612,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) #ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_ADD_FILE(led, data); #endif + DEBUGFS_ADD_FILE(sleep_level_override, data); + DEBUGFS_ADD_FILE(current_sleep_command, data); DEBUGFS_ADD_FILE(thermal_throttling, data); DEBUGFS_ADD_FILE(disable_ht40, data); DEBUGFS_ADD_FILE(rx_statistics, debug); @@ -1572,6 +1653,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) if (!priv->dbgfs) return; + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sleep_level_override); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_current_sleep_command); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1aa2ae6..b96c3c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1119,7 +1119,6 @@ struct iwl_priv { /* context information */ u16 rates_mask; - u32 power_mode; u8 bssid[ETH_ALEN]; u16 rts_threshold; u8 mac_addr[ETH_ALEN]; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 27ad59d..0b16841 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -42,20 +42,35 @@ #include "iwl-power.h" /* - * Setting power level allow the card to go to sleep when not busy. + * Setting power level allows the card to go to sleep when not busy. * - * The power level is set to INDEX_1 (the least deep state) by - * default, and will, in the future, be the deepest state unless - * otherwise required by pm_qos network latency requirements. - * - * Using INDEX_1 without pm_qos is ok because mac80211 will disable - * PS when even checking every beacon for the TIM bit would exceed - * the required latency. + * We calculate a sleep command based on the required latency, which + * we get from mac80211. In order to handle thermal throttling, we can + * also use pre-defined power levels. */ -#define IWL_POWER_RANGE_0_MAX (2) -#define IWL_POWER_RANGE_1_MAX (10) +/* + * For now, keep using power level 1 instead of automatically + * adjusting ... + */ +bool no_sleep_autoadjust = true; +module_param(no_sleep_autoadjust, bool, S_IRUGO); +MODULE_PARM_DESC(no_sleep_autoadjust, + "don't automatically adjust sleep level " + "according to maximum network latency"); +/* + * This defines the old power levels. They are still used by default + * (level 1) and for thermal throttle (levels 3 through 5) + */ + +struct iwl_power_vec_entry { + struct iwl_powertable_cmd cmd; + u8 no_dtim; +}; + +#define IWL_DTIM_RANGE_0_MAX 2 +#define IWL_DTIM_RANGE_1_MAX 10 #define NOSLP cpu_to_le16(0), 0, 0 #define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 @@ -67,9 +82,8 @@ cpu_to_le32(X3), \ cpu_to_le32(X4)} /* default power management (not Tx power) table values */ -/* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */ +/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { - {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, @@ -78,9 +92,8 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { }; -/* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */ +/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { - {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, @@ -88,9 +101,8 @@ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} }; -/* for DTIM period > IWL_POWER_RANGE_1_MAX */ +/* for DTIM period > IWL_DTIM_RANGE_1_MAX */ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { - {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, @@ -98,6 +110,56 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} }; +static void iwl_static_sleep_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd, + enum iwl_power_level lvl, int period) +{ + const struct iwl_power_vec_entry *table; + int max_sleep, i; + bool skip; + + table = range_2; + if (period < IWL_DTIM_RANGE_1_MAX) + table = range_1; + if (period < IWL_DTIM_RANGE_0_MAX) + table = range_0; + + BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); + + *cmd = table[lvl].cmd; + + if (period == 0) { + skip = false; + period = 1; + } else { + skip = !!table[lvl].no_dtim; + } + + if (skip) { + __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; + max_sleep = le32_to_cpu(slp_itrvl); + if (max_sleep == 0xFF) + max_sleep = period * (skip + 1); + else if (max_sleep > period) + max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; + cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; + } else { + max_sleep = period; + cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; + } + + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) + if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) + cmd->sleep_interval[i] = cpu_to_le32(max_sleep); + + if (priv->power_data.pci_pm) + cmd->flags |= IWL_POWER_PCI_PM_MSK; + else + cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + + IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1); +} + /* default Thermal Throttling transaction table * Current state | Throttling Down | Throttling Up *============================================================================= @@ -138,98 +200,44 @@ static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false } }; -/* set card power command */ -static int iwl_set_power(struct iwl_priv *priv, void *cmd) -{ - return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, - sizeof(struct iwl_powertable_cmd), cmd); -} -/* initialize to default */ -static void iwl_power_init_handle(struct iwl_priv *priv) +static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd) { - struct iwl_power_mgr *pow_data; - int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM; - struct iwl_powertable_cmd *cmd; - int i; - u16 lctl; - - IWL_DEBUG_POWER(priv, "Initialize power \n"); - - pow_data = &priv->power_data; - - memset(pow_data, 0, sizeof(*pow_data)); - - memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); - memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); - memcpy(&pow_data->pwr_range_2[0], &range_2[0], size); - - lctl = iwl_pcie_link_ctl(priv); + memset(cmd, 0, sizeof(*cmd)); - IWL_DEBUG_POWER(priv, "adjust power command flags\n"); + if (priv->power_data.pci_pm) + cmd->flags |= IWL_POWER_PCI_PM_MSK; - for (i = 0; i < IWL_POWER_NUM; i++) { - cmd = &pow_data->pwr_range_0[i].cmd; - - if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN) - cmd->flags &= ~IWL_POWER_PCI_PM_MSK; - else - cmd->flags |= IWL_POWER_PCI_PM_MSK; - } + IWL_DEBUG_POWER(priv, "Sleep command for CAM\n"); } -/* adjust power command according to DTIM period and power level*/ -static int iwl_update_power_cmd(struct iwl_priv *priv, - struct iwl_powertable_cmd *cmd, u16 mode) +static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd, + int dynps_ms, int wakeup_period) { - struct iwl_power_vec_entry *range; - struct iwl_power_mgr *pow_data; int i; - u32 max_sleep = 0; - u8 period; - bool skip; - if (mode > IWL_POWER_INDEX_5) { - IWL_DEBUG_POWER(priv, "Error invalid power mode \n"); - return -EINVAL; - } + memset(cmd, 0, sizeof(*cmd)); - pow_data = &priv->power_data; + cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK | + IWL_POWER_FAST_PD; /* no use seeing frames for others */ - if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX) - range = &pow_data->pwr_range_0[0]; - else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX) - range = &pow_data->pwr_range_1[0]; - else - range = &pow_data->pwr_range_2[0]; + if (priv->power_data.pci_pm) + cmd->flags |= IWL_POWER_PCI_PM_MSK; - period = pow_data->dtim_period; - memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); - - if (period == 0) { - period = 1; - skip = false; - } else { - skip = !!range[mode].no_dtim; - } - - if (skip) { - __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; - max_sleep = le32_to_cpu(slp_itrvl); - if (max_sleep == 0xFF) - max_sleep = period * (skip + 1); - else if (max_sleep > period) - max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; - cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; - } else { - max_sleep = period; - cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; - } + cmd->rx_data_timeout = cpu_to_le32(1000 * dynps_ms); + cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms); for (i = 0; i < IWL_POWER_VEC_SIZE; i++) - if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) - cmd->sleep_interval[i] = cpu_to_le32(max_sleep); + cmd->sleep_interval[i] = cpu_to_le32(wakeup_period); + + IWL_DEBUG_POWER(priv, "Automatic sleep command\n"); +} +static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd) +{ + IWL_DEBUG_POWER(priv, "Sending power/sleep command\n"); IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags); IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); @@ -240,50 +248,54 @@ static int iwl_update_power_cmd(struct iwl_priv *priv, le32_to_cpu(cmd->sleep_interval[3]), le32_to_cpu(cmd->sleep_interval[4])); - return 0; + return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, + sizeof(struct iwl_powertable_cmd), cmd); } -/* - * compute the final power mode index - */ int iwl_power_update_mode(struct iwl_priv *priv, bool force) { - struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; struct iwl_tt_mgmt *tt = &priv->thermal_throttle; - u16 uninitialized_var(final_mode); + bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) && + (priv->hw->conf.flags & IEEE80211_CONF_PS); bool update_chains; + struct iwl_powertable_cmd cmd; + int dtimper; /* Don't update the RX chain when chain noise calibration is running */ update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; - final_mode = priv->power_data.user_power_setting; - - if (setting->power_disabled) - final_mode = IWL_POWER_MODE_CAM; + if (priv->vif) + dtimper = priv->vif->bss_conf.dtim_period; + else + dtimper = 1; + + /* TT power setting overwrites everything */ + if (tt->state >= IWL_TI_1) + iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper); + else if (!enabled) + iwl_power_sleep_cam_cmd(priv, &cmd); + else if (priv->power_data.debug_sleep_level_override >= 0) + iwl_static_sleep_cmd(priv, &cmd, + priv->power_data.debug_sleep_level_override, + dtimper); + else if (no_sleep_autoadjust) + iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper); + else + iwl_power_fill_sleep_cmd(priv, &cmd, + priv->hw->conf.dynamic_ps_timeout, + priv->hw->conf.max_sleep_period); - if (tt->state >= IWL_TI_1) { - /* TT power setting overwrite user & system power setting */ - final_mode = tt->tt_power_mode; - } if (iwl_is_ready_rf(priv) && - ((setting->power_mode != final_mode) || force)) { - struct iwl_powertable_cmd cmd; - - if (final_mode != IWL_POWER_MODE_CAM) + (memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) { + if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) set_bit(STATUS_POWER_PMI, &priv->status); - iwl_update_power_cmd(priv, &cmd, final_mode); - cmd.keep_alive_beacons = 0; - - if (final_mode == IWL_POWER_INDEX_5) - cmd.flags |= IWL_POWER_FAST_PD; - ret = iwl_set_power(priv, &cmd); if (!ret) { - if (final_mode == IWL_POWER_MODE_CAM) + if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) clear_bit(STATUS_POWER_PMI, &priv->status); if (priv->cfg->ops->lib->update_chain_flags && @@ -294,7 +306,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) "Cannot update the power, chain noise " "calibration running: %d\n", priv->chain_noise_data.state); - setting->power_mode = final_mode; + memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)); } else IWL_ERR(priv, "set power fail, ret = %d", ret); } @@ -303,18 +315,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) } EXPORT_SYMBOL(iwl_power_update_mode); -/* set user_power_setting */ -int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) -{ - if (mode >= IWL_POWER_NUM) - return -EINVAL; - - priv->power_data.user_power_setting = mode; - - return iwl_power_update_mode(priv, 0); -} -EXPORT_SYMBOL(iwl_power_set_user_mode); - bool iwl_ht_enabled(struct iwl_priv *priv) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; @@ -349,7 +349,6 @@ enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv) restriction = tt->restriction + tt->state; return restriction->rx_stream; } -EXPORT_SYMBOL(iwl_rx_ant_restriction); #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ @@ -429,7 +428,6 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; enum iwl_tt_state old_state; - struct iwl_power_mgr *setting = &priv->power_data; #ifdef CONFIG_IWLWIFI_DEBUG if ((tt->tt_previous_temp) && @@ -456,24 +454,13 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) tt->tt_previous_temp = temp; #endif if (tt->state != old_state) { - if (old_state == IWL_TI_0) { - tt->sys_power_mode = setting->power_mode; - IWL_DEBUG_POWER(priv, "current power mode: %u\n", - setting->power_mode); - } switch (tt->state) { case IWL_TI_0: - /* when system ready to go back to IWL_TI_0 state - * using system power mode instead of TT power mode - * revert back to the orginal power mode which was saved - * before enter Thermal Throttling state - * update priv->power_data.user_power_setting to the - * required power mode to make sure - * iwl_power_update_mode() will update power correctly. + /* + * When the system is ready to go back to IWL_TI_0 + * we only have to call iwl_power_update_mode() to + * do so. */ - priv->power_data.user_power_setting = - tt->sys_power_mode; - tt->tt_power_mode = tt->sys_power_mode; break; case IWL_TI_1: tt->tt_power_mode = IWL_POWER_INDEX_3; @@ -576,13 +563,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) } if (changed) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - struct iwl_power_mgr *setting = &priv->power_data; if (tt->state >= IWL_TI_1) { - /* if switching from IWL_TI_0 to other TT state - * save previous power setting in tt->sys_power_mode */ - if (old_state == IWL_TI_0) - tt->sys_power_mode = setting->power_mode; /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */ tt->tt_power_mode = IWL_POWER_INDEX_5; if (!iwl_ht_enabled(priv)) @@ -599,17 +581,11 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) } } else { - /* restore system power setting */ - /* the previous power mode was saved in - * tt->sys_power_mode when system move into - * Thermal Throttling state - * set power_data.user_power_setting to the previous - * system power mode to make sure power will get - * updated correctly + /* + * restore system power setting -- it will be + * recalculated automatically. */ - priv->power_data.user_power_setting = - tt->sys_power_mode; - tt->tt_power_mode = tt->sys_power_mode; + /* check HT capability and set * according to the system HT capability * in case get disabled before */ @@ -761,7 +737,6 @@ EXPORT_SYMBOL(iwl_tt_handler); void iwl_tt_initialize(struct iwl_priv *priv) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; - struct iwl_power_mgr *setting = &priv->power_data; int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); struct iwl_tt_trans *transaction; @@ -770,8 +745,6 @@ void iwl_tt_initialize(struct iwl_priv *priv) memset(tt, 0, sizeof(struct iwl_tt_mgmt)); tt->state = IWL_TI_0; - tt->sys_power_mode = setting->power_mode; - tt->tt_power_mode = tt->sys_power_mode; init_timer(&priv->thermal_throttle.ct_kill_exit_tm); priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; @@ -849,9 +822,13 @@ EXPORT_SYMBOL(iwl_tt_exit); /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { - iwl_power_init_handle(priv); - priv->power_data.user_power_setting = IWL_POWER_INDEX_1; - /* default to disabled until mac80211 says otherwise */ - priv->power_data.power_disabled = 1; + u16 lctl = iwl_pcie_link_ctl(priv); + + priv->power_data.pci_pm = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN); + + priv->power_data.debug_sleep_level_override = -1; + + memset(&priv->power_data.sleep_cmd, 0, + sizeof(priv->power_data.sleep_cmd)); } EXPORT_SYMBOL(iwl_power_initialize); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 15e3eab..df6f6a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -28,11 +28,8 @@ #ifndef __iwl_power_setting_h__ #define __iwl_power_setting_h__ -#include #include "iwl-commands.h" -struct iwl_priv; - #define IWL_ABSOLUTE_ZERO 0 #define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 @@ -93,8 +90,6 @@ struct iwl_tt_trans { * when thermal throttling state != IWL_TI_0 * the tt_power_mode should set to different * power mode based on the current tt state - * @sys_power_mode: previous system power mode - * before transition into TT state * @tt_previous_temperature: last measured temperature * @iwl_tt_restriction: ptr to restriction tbl, used by advance * thermal throttling to determine how many tx/rx streams @@ -108,7 +103,6 @@ struct iwl_tt_mgmt { enum iwl_tt_state state; bool advanced_tt; u8 tt_power_mode; - u8 sys_power_mode; bool ct_kill_toggle; #ifdef CONFIG_IWLWIFI_DEBUG s32 tt_previous_temp; @@ -118,8 +112,7 @@ struct iwl_tt_mgmt { struct timer_list ct_kill_exit_tm; }; -enum { - IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */ +enum iwl_power_level { IWL_POWER_INDEX_1, IWL_POWER_INDEX_2, IWL_POWER_INDEX_3, @@ -128,26 +121,13 @@ enum { IWL_POWER_NUM }; -/* Power management (not Tx power) structures */ - -struct iwl_power_vec_entry { - struct iwl_powertable_cmd cmd; - u8 no_dtim; -}; - struct iwl_power_mgr { - struct iwl_power_vec_entry pwr_range_0[IWL_POWER_NUM]; - struct iwl_power_vec_entry pwr_range_1[IWL_POWER_NUM]; - struct iwl_power_vec_entry pwr_range_2[IWL_POWER_NUM]; - u32 dtim_period; - /* final power level that used to calculate final power command */ - u8 power_mode; - u8 user_power_setting; /* set by user through sysfs */ - u8 power_disabled; /* set by mac80211's CONF_PS */ + struct iwl_powertable_cmd sleep_cmd; + int debug_sleep_level_override; + bool pci_pm; }; int iwl_power_update_mode(struct iwl_priv *priv, bool force); -int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); bool iwl_ht_enabled(struct iwl_priv *priv); enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv); enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv); @@ -158,4 +138,6 @@ void iwl_tt_initialize(struct iwl_priv *priv); void iwl_tt_exit(struct iwl_priv *priv); void iwl_power_initialize(struct iwl_priv *priv); +extern bool no_sleep_autoadjust; + #endif /* __iwl_power_setting_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e5fa672..e617411 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3554,65 +3554,6 @@ static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, store_retry_rate); -static ssize_t store_power_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int ret; - unsigned long mode; - - - mutex_lock(&priv->mutex); - - ret = strict_strtoul(buf, 10, &mode); - if (ret) - goto out; - - ret = iwl_power_set_user_mode(priv, mode); - if (ret) { - IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n"); - goto out; - } - ret = count; - - out: - mutex_unlock(&priv->mutex); - return ret; -} - -static ssize_t show_power_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int level = priv->power_data.power_mode; - char *p = buf; - - p += sprintf(p, "%d\n", level); - return p - buf + 1; -} - -static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, - show_power_level, store_power_level); - -#define MAX_WX_STRING 80 - -/* Values are in microsecond */ -static const s32 timeout_duration[] = { - 350000, - 250000, - 75000, - 37000, - 25000, -}; -static const s32 period_duration[] = { - 400000, - 700000, - 1000000, - 1000000, - 1000000 -}; - static ssize_t show_channels(struct device *d, struct device_attribute *attr, char *buf) { @@ -3789,7 +3730,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT &dev_attr_measurement.attr, #endif - &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, @@ -3854,8 +3794,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->qos_data.qos_cap.val = 0; priv->rates_mask = IWL_RATES_MASK; - /* If power management is turned on, default to CAM mode */ - priv->power_mode = IWL_POWER_MODE_CAM; priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { @@ -3902,7 +3840,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | - IEEE80211_HW_SPECTRUM_MGMT; + IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | -- cgit v0.10.2 From 4b181144e6c1c25aaba9b9fc7cc70c95495ecb92 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 8 Aug 2009 11:03:58 +0200 Subject: cfg80211: fix locking for SIWFREQ "cfg80211: validate channel settings across interfaces" contained a locking bug -- in the managed-mode SIWFREQ call it would end up running into a lock recursion. This fixes it by not checking that particular interface for a channel that it needs to stay on, which is as it should be as that's the interface we're setting the channel for. Reported-by: Reinette Chatre Reported-by: Kalle Valo Signed-off-by: Johannes Berg Tested-by: Kalle Valo Tested-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/net/wireless/chan.c b/net/wireless/chan.c index bc00c9a..a46ac6c 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -42,13 +42,14 @@ rdev_fixed_channel(struct cfg80211_registered_device *rdev, } int rdev_set_freq(struct cfg80211_registered_device *rdev, + struct wireless_dev *for_wdev, int freq, enum nl80211_channel_type channel_type) { struct ieee80211_channel *chan; struct ieee80211_sta_ht_cap *ht_cap; int result; - if (rdev_fixed_channel(rdev, NULL)) + if (rdev_fixed_channel(rdev, for_wdev)) return -EBUSY; if (!rdev->ops->set_channel) diff --git a/net/wireless/core.h b/net/wireless/core.h index 639db52..f7be3a9 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -374,6 +374,7 @@ struct ieee80211_channel * rdev_fixed_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *for_wdev); int rdev_set_freq(struct cfg80211_registered_device *rdev, + struct wireless_dev *for_wdev, int freq, enum nl80211_channel_type channel_type); #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 667a87d..a8aaade 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -721,7 +721,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); mutex_lock(&rdev->devlist_mtx); - result = rdev_set_freq(rdev, freq, channel_type); + result = rdev_set_freq(rdev, NULL, freq, channel_type); mutex_unlock(&rdev->devlist_mtx); if (result) goto bad_res; diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 17648dc..c449174 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -766,7 +766,7 @@ int cfg80211_wext_siwfreq(struct net_device *dev, if (freq == 0) return -EINVAL; mutex_lock(&rdev->devlist_mtx); - err = rdev_set_freq(rdev, freq, NL80211_CHAN_NO_HT); + err = rdev_set_freq(rdev, NULL, freq, NL80211_CHAN_NO_HT); mutex_unlock(&rdev->devlist_mtx); return err; } diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 9074700..d16cd9e 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -106,7 +106,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, /* SSID is not set, we just want to switch channel */ if (chan && !wdev->wext.connect.ssid_len) { - err = rdev_set_freq(rdev, freq, NL80211_CHAN_NO_HT); + err = rdev_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT); goto out; } -- cgit v0.10.2 From 4d30d309a3be84dfb01743ceb4652405204a80a0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 8 Aug 2009 15:22:26 +0200 Subject: drivers/net/wireless/ath/ath5k: Change constant name Elsewhere, the tqi_type field is compared to constants having a name beginning with AR5K_TX_QUEUE, rather than AR5K_TX_QUEUE_ID. I have thus converted AR5K_TX_QUEUE_ID_CAB to AR5K_TX_QUEUE_CAB. This does, however, change the value, so perhaps something else was wanted. Signed-off-by: Julia Lawall Acked-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 6d5aaf0..eeebb9a 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -362,7 +362,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) } if (tq->tqi_ready_time && - (tq->tqi_type != AR5K_TX_QUEUE_ID_CAB)) + (tq->tqi_type != AR5K_TX_QUEUE_CAB)) ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, AR5K_QCU_RDYTIMECFG_INTVAL) | AR5K_QCU_RDYTIMECFG_ENABLE, -- cgit v0.10.2 From bdfa500b8b8ca87dfe7a311f569fe8b39746c299 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 8 Aug 2009 23:53:04 +0200 Subject: rt2x00: Remove usage of deprecated radio_enabled & IEEE80211_CONF_CHANGE_RADIO_ENABLED In the config() callback function the fields radio_enabled and the change flag IEEE80211_CONF_CHANGE_RADIO_ENABLED have been deprecated. This removes the usage of those fields by improving antenna change detection in the antenna configuration function. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 3845316..3501788 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -124,8 +124,9 @@ enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, } void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup ant) + struct antenna_setup config) { + struct link_ant *ant = &rt2x00dev->link.ant; struct antenna_setup *def = &rt2x00dev->default_ant; struct antenna_setup *active = &rt2x00dev->link.ant.active; @@ -134,14 +135,23 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * ANTENNA_SW_DIVERSITY state to the driver. * If that happens, fallback to hardware defaults, * or our own default. + * If diversity handling is active for a particular antenna, + * we shouldn't overwrite that antenna. * The calls to rt2x00lib_config_antenna_check() * might have caused that we restore back to the already * active setting. If that has happened we can quit. */ - ant.rx = rt2x00lib_config_antenna_check(ant.rx, def->rx); - ant.tx = rt2x00lib_config_antenna_check(ant.tx, def->tx); + if (!(ant->flags & ANTENNA_RX_DIVERSITY)) + config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx); + else + config.rx = active->rx; - if (ant.rx == active->rx && ant.tx == active->tx) + if (!(ant->flags & ANTENNA_TX_DIVERSITY)) + config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx); + else + config.tx = active->tx; + + if (config.rx == active->rx && config.tx == active->tx) return; /* @@ -156,11 +166,11 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * The latter is required since we need to recalibrate the * noise-sensitivity ratio for the new setup. */ - rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant); + rt2x00dev->ops->lib->config_ant(rt2x00dev, &config); rt2x00link_reset_tuner(rt2x00dev, true); - memcpy(active, &ant, sizeof(ant)); + memcpy(active, &config, sizeof(config)); if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index db54fcc..e0348cc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -785,6 +785,13 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; + /* Enable the radio */ + retval = rt2x00lib_enable_radio(rt2x00dev); + if (retval) { + rt2x00queue_uninitialize(rt2x00dev); + return retval; + } + set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 9178316..fe951dc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -219,6 +219,7 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) { struct link_ant *ant = &rt2x00dev->link.ant; + unsigned int flags = ant->flags; /* * Determine if software diversity is enabled for @@ -226,13 +227,13 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) * Always perform this check since within the link * tuner interval the configuration might have changed. */ - ant->flags &= ~ANTENNA_RX_DIVERSITY; - ant->flags &= ~ANTENNA_TX_DIVERSITY; + flags &= ~ANTENNA_RX_DIVERSITY; + flags &= ~ANTENNA_TX_DIVERSITY; if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) - ant->flags |= ANTENNA_RX_DIVERSITY; + flags |= ANTENNA_RX_DIVERSITY; if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) - ant->flags |= ANTENNA_TX_DIVERSITY; + flags |= ANTENNA_TX_DIVERSITY; if (!(ant->flags & ANTENNA_RX_DIVERSITY) && !(ant->flags & ANTENNA_TX_DIVERSITY)) { @@ -240,6 +241,9 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) return; } + /* Update flags */ + ant->flags = flags; + /* * If we have only sampled the data over the last period * we should now harvest the data. Otherwise just evaluate diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 81febdf..4164fce 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -338,7 +338,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) { struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_conf *conf = &hw->conf; - int status; /* * mac80211 might be calling this function while we are trying @@ -348,44 +347,29 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) return 0; /* - * Only change device state when the radio is enabled. It does not - * matter what parameters we have configured when the radio is disabled - * because we won't be able to send or receive anyway. Also note that - * some configuration parameters (e.g. channel and antenna values) can - * only be set when the radio is enabled. + * Some configuration parameters (e.g. channel and antenna values) can + * only be set when the radio is enabled, but do require the RX to + * be off. */ - if (conf->radio_enabled) { - /* For programming the values, we have to turn RX off */ - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); - /* Enable the radio */ - status = rt2x00lib_enable_radio(rt2x00dev); - if (unlikely(status)) - return status; + /* + * When we've just turned on the radio, we want to reprogram + * everything to ensure a consistent state + */ + rt2x00lib_config(rt2x00dev, conf, changed); - /* - * When we've just turned on the radio, we want to reprogram - * everything to ensure a consistent state - */ - rt2x00lib_config(rt2x00dev, conf, changed); + /* + * After the radio has been enabled we need to configure + * the antenna to the default settings. rt2x00lib_config_antenna() + * should determine if any action should be taken based on + * checking if diversity has been enabled or no antenna changes + * have been made since the last configuration change. + */ + rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant); - /* - * The radio was enabled, configure the antenna to the - * default settings, the link tuner will later start - * continue configuring the antenna based on the software - * diversity. But for non-diversity configurations, we need - * to have configured the correct state now. - */ - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) - rt2x00lib_config_antenna(rt2x00dev, - rt2x00dev->default_ant); - - /* Turn RX back on */ - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); - } else { - /* Disable the radio */ - rt2x00lib_disable_radio(rt2x00dev); - } + /* Turn RX back on */ + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); return 0; } -- cgit v0.10.2 From 267e898755d7fc6249e26208e7ce97f415fd8c31 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 8 Aug 2009 23:53:26 +0200 Subject: rt2x00: Use IEEE80211_TX_CTL_MORE_FRAMES flag Check the IEEE80211_TX_CTL_MORE_FRAMES flag to help determining if the DMA queue should be kicked. At the moment this is combined with the ieee80211_has_morefrags() but we might remove that later. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 44e5b32..65435c9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -324,7 +324,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Check if more fragments are pending */ - if (ieee80211_has_morefrags(hdr->frame_control)) { + if (ieee80211_has_morefrags(hdr->frame_control) || + (tx_info->flags & IEEE80211_TX_CTL_MORE_FRAMES)) { __set_bit(ENTRY_TXD_BURST, &txdesc->flags); __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags); } -- cgit v0.10.2 From 93354cbbcbfca920495377158c0f61c36be79e13 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 8 Aug 2009 23:53:47 +0200 Subject: rt2x00: Align ieee80211 header to 4-byte boundary for PCI devices Some hardware require the ieee80211 header to be aligned to a 4-byte boundary before mapping it to the DMA. Otherwise some frames (like beacons) will not be send out correctly by the device. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 65435c9..e67e339 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -453,9 +453,21 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) rt2x00crypto_tx_remove_iv(skb, &txdesc); } + /* + * When DMA allocation is required we should guarentee to the + * driver that the DMA is aligned to a 4-byte boundary. + * Aligning the header to this boundary can be done by calling + * rt2x00queue_payload_align with the header length of 0. + * However some drivers require L2 padding to pad the payload + * rather then the header. This could be a requirement for + * PCI and USB devices, while header alignment only is valid + * for PCI devices. + */ if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) rt2x00queue_payload_align(entry->skb, true, txdesc.header_length); + else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) + rt2x00queue_payload_align(entry->skb, false, 0); /* * It could be possible that the queue was corrupted and this -- cgit v0.10.2 From 193df183b15cda78f6b2373f576e243327ea0d8f Mon Sep 17 00:00:00 2001 From: Lars Ericsson Date: Sat, 8 Aug 2009 23:54:24 +0200 Subject: rt2x00: Fix quality houskeeping for software diversity Antanna quality statistics is not handled correctly, which leads to software diversity being shutdown completly. The main problem is that during antenna diversity statistics can be reset resulting in loosing the signal strength just before evaluation. rssi history is not updated correctly leading to incorrect comparison material for basing antenna switching on. Signed-off-by: Lars Ericsson Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index cbec91e..704e944 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -245,14 +245,11 @@ struct link_ant { struct antenna_setup active; /* - * RSSI information for the different antennas. - * These statistics are used to determine when - * to switch antenna when using software diversity. - * - * rssi[0] -> Antenna A RSSI - * rssi[1] -> Antenna B RSSI + * RSSI history information for the antenna. + * Used to determine when to switch antenna + * when using software diversity. */ - int rssi_history[2]; + int rssi_history; /* * Current RSSI average of the currently active antenna. diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index fe951dc..dd68f3a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -103,39 +103,21 @@ static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) return DEFAULT_RSSI; } -static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev, - enum antenna antenna) +static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev) { struct link_ant *ant = &rt2x00dev->link.ant; - if (ant->rssi_history[antenna - ANTENNA_A]) - return ant->rssi_history[antenna - ANTENNA_A]; + if (ant->rssi_history) + return ant->rssi_history; return DEFAULT_RSSI; } -/* Small wrapper for rt2x00link_antenna_get_rssi_history() */ -#define rt2x00link_antenna_get_rssi_rx_history(__dev) \ - rt2x00link_antenna_get_rssi_history((__dev), \ - (__dev)->link.ant.active.rx) -#define rt2x00link_antenna_get_rssi_tx_history(__dev) \ - rt2x00link_antenna_get_rssi_history((__dev), \ - (__dev)->link.ant.active.tx) static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev, - enum antenna antenna, int rssi) { struct link_ant *ant = &rt2x00dev->link.ant; - ant->rssi_history[ant->active.rx - ANTENNA_A] = rssi; + ant->rssi_history = rssi; } -/* Small wrapper for rt2x00link_antenna_get_rssi_history() */ -#define rt2x00link_antenna_update_rssi_rx_history(__dev, __rssi) \ - rt2x00link_antenna_update_rssi_history((__dev), \ - (__dev)->link.ant.active.rx, \ - (__rssi)) -#define rt2x00link_antenna_update_rssi_tx_history(__dev, __rssi) \ - rt2x00link_antenna_update_rssi_history((__dev), \ - (__dev)->link.ant.active.tx, \ - (__rssi)) static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) { @@ -146,8 +128,10 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) { struct link_ant *ant = &rt2x00dev->link.ant; struct antenna_setup new_ant; - int sample_a = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_A); - int sample_b = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_B); + int other_antenna; + + int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev); + int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev); memcpy(&new_ant, &ant->active, sizeof(new_ant)); @@ -161,17 +145,22 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) * from both antennas. It now is time to determine * which antenna demonstrated the best performance. * When we are already on the antenna with the best - * performance, then there really is nothing for us - * left to do. + * performance, just create a good starting point + * for the history and we are done. */ - if (sample_a == sample_b) + if (sample_current >= sample_other) { + rt2x00link_antenna_update_rssi_history(rt2x00dev, + sample_current); return; + } + + other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; if (ant->flags & ANTENNA_RX_DIVERSITY) - new_ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; + new_ant.rx = other_antenna; if (ant->flags & ANTENNA_TX_DIVERSITY) - new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; + new_ant.tx = other_antenna; rt2x00lib_config_antenna(rt2x00dev, new_ant); } @@ -190,8 +179,8 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) * after that update the history with the current value. */ rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev); - rssi_old = rt2x00link_antenna_get_rssi_rx_history(rt2x00dev); - rt2x00link_antenna_update_rssi_rx_history(rt2x00dev, rssi_curr); + rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev); + rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr); /* * Legacy driver indicates that we should swap antenna's @@ -216,7 +205,7 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) rt2x00lib_config_antenna(rt2x00dev, new_ant); } -static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) +static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) { struct link_ant *ant = &rt2x00dev->link.ant; unsigned int flags = ant->flags; @@ -238,7 +227,7 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) if (!(ant->flags & ANTENNA_RX_DIVERSITY) && !(ant->flags & ANTENNA_TX_DIVERSITY)) { ant->flags = 0; - return; + return true; } /* Update flags */ @@ -250,10 +239,15 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) * the data. The latter should only be performed once * every 2 seconds. */ - if (ant->flags & ANTENNA_MODE_SAMPLE) + if (ant->flags & ANTENNA_MODE_SAMPLE) { rt2x00lib_antenna_diversity_sample(rt2x00dev); - else if (rt2x00dev->link.count & 1) + return true; + } else if (rt2x00dev->link.count & 1) { rt2x00lib_antenna_diversity_eval(rt2x00dev); + return true; + } + + return false; } void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, @@ -451,15 +445,12 @@ static void rt2x00link_tuner(struct work_struct *work) rt2x00leds_led_quality(rt2x00dev, link->avg_rssi); /* - * Evaluate antenna setup, make this the last step since this could - * possibly reset some statistics. - */ - rt2x00lib_antenna_diversity(rt2x00dev); - - /* - * Reset the quality counters which recounted during each period. + * Evaluate antenna setup, make this the last step when + * rt2x00lib_antenna_diversity made changes the quality + * statistics will be reset. */ - rt2x00link_reset_qual(rt2x00dev); + if (rt2x00lib_antenna_diversity(rt2x00dev)) + rt2x00link_reset_qual(rt2x00dev); /* * Increase tuner counter, and reschedule the next link tuner run. -- cgit v0.10.2 From 66679a65efffffb62dc2650960b3aff758d575f9 Mon Sep 17 00:00:00 2001 From: Lars Ericsson Date: Sat, 8 Aug 2009 23:54:51 +0200 Subject: rt2x00: Fix rounding errors in RSSI average calculation Small changes in signal level was not detected up by the MOVING_AVERAGE() due to a rounding error, using 'int' type. rt2x00lib_antenna_diversity_eval: rssi: -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 rssi_avg: -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 The signal level reported back could be significantly (5dBm) different from the actual value. A level +3dBm is the same as double the AP output power. Signed-off-by: Lars Ericsson Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 704e944..e6e73be 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -134,6 +134,17 @@ GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) /* + * Structure for average calculation + * The avg field contains the actual average value, + * but avg_weight is internally used during calculations + * to prevent rounding errors. + */ +struct avg_val { + int avg; + int avg_weight; +}; + +/* * Chipset identification * The chipset on the device is composed of a RT and RF chip. * The chipset combination is important for determining device capabilities. @@ -256,7 +267,7 @@ struct link_ant { * Similar to the avg_rssi in the link_qual structure * this value is updated by using the walking average. */ - int rssi_ant; + struct avg_val rssi_ant; }; /* @@ -285,7 +296,7 @@ struct link { /* * Currently active average RSSI value */ - int avg_rssi; + struct avg_val avg_rssi; /* * Currently precalculated percentages of successful diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index dd68f3a..c64db0b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -46,7 +46,15 @@ #define DEFAULT_PERCENTAGE 50 /* - * Small helper macro to work with moving/walking averages. + * Small helper macro for percentage calculation + * This is a very simple macro with the only catch that it will + * produce a default value in case no total value was provided. + */ +#define PERCENTAGE(__value, __total) \ + ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) ) + +/* + * Helper struct and macro to work with moving/walking averages. * When adding a value to the average value the following calculation * is needed: * @@ -60,18 +68,28 @@ * for a few minutes but when the device is moved away from the AP * the average will not decrease fast enough to compensate. * The walking average compensates this and will move towards - * the new values correctly allowing a effective link tuning. + * the new values correctly allowing a effective link tuning, + * the speed of the average moving towards other values depends + * on the value for the number of samples. The higher the number + * of samples, the slower the average will move. + * We use two variables to keep track of the average value to + * compensate for the rounding errors. This can be a significant + * error (>5dBm) if the factor is too low. */ -#define MOVING_AVERAGE(__avg, __val, __samples) \ - ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) ) - -/* - * Small helper macro for percentage calculation - * This is a very simple macro with the only catch that it will - * produce a default value in case no total value was provided. - */ -#define PERCENTAGE(__value, __total) \ - ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) ) +#define AVG_SAMPLES 8 +#define AVG_FACTOR 1000 +#define MOVING_AVERAGE(__avg, __val) \ +({ \ + struct avg_val __new; \ + __new.avg_weight = \ + (__avg).avg_weight ? \ + ((((__avg).avg_weight * ((AVG_SAMPLES) - 1)) + \ + ((__val) * (AVG_FACTOR))) / \ + (AVG_SAMPLES) ) : \ + ((__val) * (AVG_FACTOR)); \ + __new.avg = __new.avg_weight / (AVG_FACTOR); \ + __new; \ +}) /* * For calculating the Signal quality we have determined @@ -98,8 +116,8 @@ static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) { struct link_ant *ant = &rt2x00dev->link.ant; - if (ant->rssi_ant && rt2x00dev->link.qual.rx_success) - return ant->rssi_ant; + if (ant->rssi_ant.avg && rt2x00dev->link.qual.rx_success) + return ant->rssi_ant.avg; return DEFAULT_RSSI; } @@ -121,7 +139,8 @@ static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev, static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) { - rt2x00dev->link.ant.rssi_ant = 0; + rt2x00dev->link.ant.rssi_ant.avg = 0; + rt2x00dev->link.ant.rssi_ant.avg_weight = 0; } static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) @@ -258,8 +277,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual = &rt2x00dev->link.qual; struct link_ant *ant = &rt2x00dev->link.ant; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - int avg_rssi = rxdesc->rssi; - int ant_rssi = rxdesc->rssi; /* * Frame was received successfully since non-succesfull @@ -279,16 +296,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, /* * Update global RSSI */ - if (link->avg_rssi) - avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi, 8); - link->avg_rssi = avg_rssi; + link->avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi); /* * Update antenna RSSI */ - if (ant->rssi_ant) - ant_rssi = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi, 8); - ant->rssi_ant = ant_rssi; + ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi); } static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev) @@ -421,10 +434,10 @@ static void rt2x00link_tuner(struct work_struct *work) * collect the RSSI data we could use this. Otherwise we * must fallback to the default RSSI value. */ - if (!link->avg_rssi || !qual->rx_success) + if (!link->avg_rssi.avg || !qual->rx_success) qual->rssi = DEFAULT_RSSI; else - qual->rssi = link->avg_rssi; + qual->rssi = link->avg_rssi.avg; /* * Only perform the link tuning when Link tuning @@ -442,7 +455,7 @@ static void rt2x00link_tuner(struct work_struct *work) /* * Send a signal to the led to update the led signal strength. */ - rt2x00leds_led_quality(rt2x00dev, link->avg_rssi); + rt2x00leds_led_quality(rt2x00dev, qual->rssi); /* * Evaluate antenna setup, make this the last step when -- cgit v0.10.2 From 17512dc3b7fc9ff1a60d3748ce87c323df507c3d Mon Sep 17 00:00:00 2001 From: Igor Perminov Date: Sat, 8 Aug 2009 23:55:18 +0200 Subject: rt2x00: Fix for race condition while update beacon The patch "Implement set_tim callback for all drivers" can cause kernel oops in rt73usb_write_beacon. The oops is caused by one of the following race conditions: * In case of two near calls to set_tim: rt2x00lib_beacondone_iter is cleaning the beacon skb, whereas rt73usb_write_beacon is still using it. * In case of two near updates of beacon: first as the result of set_tim and second as the result of a call from an application (e.g. hostapd). This patch fixes the race condition by rearranging the update logic and guarding rt2x00_intf->beacon->skb with a mutex. Signed-off-by: Igor Perminov Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index e6e73be..7c74c4e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -334,6 +334,11 @@ struct rt2x00_intf { u8 bssid[ETH_ALEN]; /* + * beacon->skb must be protected with the mutex. + */ + struct mutex beacon_skb_mutex; + + /* * Entry in the beacon queue which belongs to * this interface. Each interface has its own * dedicated beacon entry. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e0348cc..b6676c6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -186,7 +186,6 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) static void rt2x00lib_beacondone_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); if (vif->type != NL80211_IFTYPE_AP && @@ -195,12 +194,6 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac, vif->type != NL80211_IFTYPE_WDS) return; - /* - * Clean up the beacon skb. - */ - rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb); - intf->beacon->skb = NULL; - spin_lock(&intf->lock); intf->delayed_flags |= DELAYED_UPDATE_BEACON; spin_unlock(&intf->lock); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 4164fce..74451f9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -274,6 +274,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, spin_lock_init(&intf->lock); spin_lock_init(&intf->seqlock); + mutex_init(&intf->beacon_skb_mutex); intf->beacon = entry; if (conf->type == NL80211_IFTYPE_AP) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index e67e339..06af823 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -503,14 +503,25 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, if (unlikely(!intf->beacon)) return -ENOBUFS; + mutex_lock(&intf->beacon_skb_mutex); + + /* + * Clean up the beacon skb. + */ + rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb); + intf->beacon->skb = NULL; + if (!enable_beacon) { rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON); + mutex_unlock(&intf->beacon_skb_mutex); return 0; } intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif); - if (!intf->beacon->skb) + if (!intf->beacon->skb) { + mutex_unlock(&intf->beacon_skb_mutex); return -ENOMEM; + } /* * Copy all TX descriptor information into txdesc, @@ -548,6 +559,8 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, rt2x00dev->ops->lib->write_beacon(intf->beacon); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); + mutex_unlock(&intf->beacon_skb_mutex); + return 0; } -- cgit v0.10.2 From 1afcfd54fdf913017c07fa1ee497141a7958991d Mon Sep 17 00:00:00 2001 From: Igor Perminov Date: Sat, 8 Aug 2009 23:55:55 +0200 Subject: rt2x00: FIF_PSPOLL filter flag support This patch implements FIF_PSPOLL filter flag support in rt2x00 drivers, which has been introduced in mac80211 (see http://marc.info/?l=linux-wireless&m=124897986330807&w=2). Signed-off-by: Igor Perminov Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 9efb417..2de0389 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -518,7 +518,7 @@ static void rt2800usb_config_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, !(filter_flags & FIF_CONTROL)); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, - !(filter_flags & FIF_CONTROL)); + !(filter_flags & FIF_PSPOLL)); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, @@ -2624,6 +2624,13 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) return retval; /* + * This device has multiple filters for control frames + * and has a separate filter for PS Poll frames. + */ + __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); + __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags); + + /* * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 7c74c4e..5bc100d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -624,6 +624,8 @@ enum rt2x00_flags { */ CONFIG_SUPPORT_HW_BUTTON, CONFIG_SUPPORT_HW_CRYPTO, + DRIVER_SUPPORT_CONTROL_FILTERS, + DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, /* * Driver configuration diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 74451f9..cb7b6d4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -392,6 +392,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, FIF_FCSFAIL | FIF_PLCPFAIL | FIF_CONTROL | + FIF_PSPOLL | FIF_OTHER_BSS | FIF_PROMISC_IN_BSS; @@ -407,6 +408,22 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; /* + * If the device has a single filter for all control frames, + * FIF_CONTROL and FIF_PSPOLL flags imply each other. + * And if the device has more than one filter for control frames + * of different types, but has no a separate filter for PS Poll frames, + * FIF_CONTROL flag implies FIF_PSPOLL. + */ + if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags)) { + if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL) + *total_flags |= FIF_CONTROL | FIF_PSPOLL; + } + if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags)) { + if (*total_flags & FIF_CONTROL) + *total_flags |= FIF_PSPOLL; + } + + /* * Check if there is any work left for us. */ if (rt2x00dev->packet_filter == *total_flags) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index e20dd74..3447997 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -530,7 +530,7 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, !(filter_flags & FIF_PLCPFAIL)); rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, - !(filter_flags & FIF_CONTROL)); + !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !(filter_flags & FIF_PROMISC_IN_BSS)); rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, @@ -2624,6 +2624,12 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) return retval; /* + * This device has multiple filters for control frames, + * but has no a separate filter for PS Poll frames. + */ + __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); + + /* * This device requires firmware and DMA mapped skbs. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4f9b177..4b9955b 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -493,7 +493,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, !(filter_flags & FIF_PLCPFAIL)); rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, - !(filter_flags & FIF_CONTROL)); + !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !(filter_flags & FIF_PROMISC_IN_BSS)); rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, @@ -2144,6 +2144,12 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) return retval; /* + * This device has multiple filters for control frames, + * but has no a separate filter for PS Poll frames. + */ + __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); + + /* * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); -- cgit v0.10.2 From d5b96a6f39a8aaa7534069b3db71048df44f023b Mon Sep 17 00:00:00 2001 From: Pat Erley Date: Sat, 8 Aug 2009 17:53:19 -0400 Subject: mac80211: remove max_bandwidth This removes the max_bandwidth attribute. It is only ever written to, and is duplicated by max_bandwidth_khz in the regulatory code. Signed-off-by: Pat Erley Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d5756c9..2239134 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -80,7 +80,6 @@ enum ieee80211_channel_flags { * with cfg80211. * * @center_freq: center frequency in MHz - * @max_bandwidth: maximum allowed bandwidth for this channel, in MHz * @hw_value: hardware-specific value for the channel * @flags: channel flags from &enum ieee80211_channel_flags. * @orig_flags: channel flags at registration time, used by regulatory @@ -97,7 +96,6 @@ enum ieee80211_channel_flags { struct ieee80211_channel { enum ieee80211_band band; u16 center_freq; - u8 max_bandwidth; u16 hw_value; u32 flags; int max_antenna_gain; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0f61ae6..fc7a484 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1018,7 +1018,6 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, map_regdom_flags(reg_rule->flags) | bw_flags; chan->max_antenna_gain = chan->orig_mag = (int) MBI_TO_DBI(power_rule->max_antenna_gain); - chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); chan->max_power = chan->orig_mpwr = (int) MBM_TO_DBM(power_rule->max_eirp); return; @@ -1027,7 +1026,6 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); chan->max_antenna_gain = min(chan->orig_mag, (int) MBI_TO_DBI(power_rule->max_antenna_gain)); - chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); if (chan->orig_mpwr) chan->max_power = min(chan->orig_mpwr, (int) MBM_TO_DBM(power_rule->max_eirp)); @@ -1329,7 +1327,6 @@ static void handle_channel_custom(struct wiphy *wiphy, chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); - chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); } -- cgit v0.10.2 From af6a3fc7e728eb4cd14653c8cfc1ee81432cfd5d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 8 Aug 2009 21:55:16 -0400 Subject: ath9k: Fix regression on receiving PS poll frames In the the patch: ath9k: use new FIF_PSPOLL configure filter I forgot to add the new FIF_PSPOLL to the supported mask. Without this we mask out the FIF_PSPOLL flag therefore we'd ignore it from mac80211. Cc: Jouni Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a9e43f7..efe2e85 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2380,6 +2380,7 @@ skip_chan_change: (FIF_PROMISC_IN_BSS | \ FIF_ALLMULTI | \ FIF_CONTROL | \ + FIF_PSPOLL | \ FIF_OTHER_BSS | \ FIF_BCN_PRBRESP_PROMISC | \ FIF_FCSFAIL) -- cgit v0.10.2 From aee83eaff859694642b323553f93b9eb59141144 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 9 Aug 2009 11:51:29 +0200 Subject: cfg80211: add missing device list locking When calling into the wext code from the NETDEV_UP notifier, we need to hold the devlist_mtx mutex as the wext code ends up calling into channel checks. Reported-by: Kalle Valo Signed-off-by: Johannes Berg Tested-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 62e1ac0..e630648 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -710,6 +710,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, case NETDEV_UP: #ifdef CONFIG_WIRELESS_EXT cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: @@ -722,6 +723,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; } wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); #endif break; -- cgit v0.10.2 From 3ecee182d68621d1f9a813f15153883ca221dd0b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 9 Aug 2009 17:57:30 +0200 Subject: rtl818x: Add some documentation to the TX desc flags Add some TX desc flags docs. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h index 34a5555..562222e 100644 --- a/drivers/net/wireless/rtl818x/rtl818x.h +++ b/drivers/net/wireless/rtl818x/rtl818x.h @@ -194,8 +194,18 @@ struct rtl818x_rf_ops { void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *); }; -/* Tx/Rx flags are common between RTL818X chips */ - +/** + * enum rtl818x_tx_desc_flags - Tx/Rx flags are common between RTL818X chips + * + * @RTL818X_TX_DESC_FLAG_NO_ENC: Disable hardware based encryption. + * @RTL818X_TX_DESC_FLAG_TX_OK: TX frame was ACKed. + * @RTL818X_TX_DESC_FLAG_SPLCP: Use short preamble. + * @RTL818X_TX_DESC_FLAG_MOREFRAG: More fragments follow. + * @RTL818X_TX_DESC_FLAG_CTS: Use CTS-to-self protection. + * @RTL818X_TX_DESC_FLAG_RTS: Use RTS/CTS protection. + * @RTL818X_TX_DESC_FLAG_LS: Last segment of the frame. + * @RTL818X_TX_DESC_FLAG_FS: First segment of the frame. + */ enum rtl818x_tx_desc_flags { RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15), RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15), -- cgit v0.10.2 From 3281d95d0535909e28ff16c38a678102e10f0312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Sun, 9 Aug 2009 20:15:09 +0200 Subject: b43: LP-PHY: Implement STX synchronization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v2+ radio init (B2063) is now complete, modulo BCM4325 support. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index ed3a528..e68644d 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -346,9 +346,60 @@ static void lpphy_2063_init(struct b43_wldev *dev) b43_radio_write(dev, B2063_PA_SP2, 0x18); } +struct lpphy_stx_table_entry { + u16 phy_offset; + u16 phy_shift; + u16 rf_addr; + u16 rf_shift; + u16 mask; +}; + +static const struct lpphy_stx_table_entry lpphy_stx_table[] = { + { .phy_offset = 2, .phy_shift = 6, .rf_addr = 0x3d, .rf_shift = 3, .mask = 0x01, }, + { .phy_offset = 1, .phy_shift = 12, .rf_addr = 0x4c, .rf_shift = 1, .mask = 0x01, }, + { .phy_offset = 1, .phy_shift = 8, .rf_addr = 0x50, .rf_shift = 0, .mask = 0x7f, }, + { .phy_offset = 0, .phy_shift = 8, .rf_addr = 0x44, .rf_shift = 0, .mask = 0xff, }, + { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4a, .rf_shift = 0, .mask = 0xff, }, + { .phy_offset = 0, .phy_shift = 4, .rf_addr = 0x4d, .rf_shift = 0, .mask = 0xff, }, + { .phy_offset = 1, .phy_shift = 4, .rf_addr = 0x4e, .rf_shift = 0, .mask = 0xff, }, + { .phy_offset = 0, .phy_shift = 12, .rf_addr = 0x4f, .rf_shift = 0, .mask = 0x0f, }, + { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4f, .rf_shift = 4, .mask = 0x0f, }, + { .phy_offset = 3, .phy_shift = 0, .rf_addr = 0x49, .rf_shift = 0, .mask = 0x0f, }, + { .phy_offset = 4, .phy_shift = 3, .rf_addr = 0x46, .rf_shift = 4, .mask = 0x07, }, + { .phy_offset = 3, .phy_shift = 15, .rf_addr = 0x46, .rf_shift = 0, .mask = 0x01, }, + { .phy_offset = 4, .phy_shift = 0, .rf_addr = 0x46, .rf_shift = 1, .mask = 0x07, }, + { .phy_offset = 3, .phy_shift = 8, .rf_addr = 0x48, .rf_shift = 4, .mask = 0x07, }, + { .phy_offset = 3, .phy_shift = 11, .rf_addr = 0x48, .rf_shift = 0, .mask = 0x0f, }, + { .phy_offset = 3, .phy_shift = 4, .rf_addr = 0x49, .rf_shift = 4, .mask = 0x0f, }, + { .phy_offset = 2, .phy_shift = 15, .rf_addr = 0x45, .rf_shift = 0, .mask = 0x01, }, + { .phy_offset = 5, .phy_shift = 13, .rf_addr = 0x52, .rf_shift = 4, .mask = 0x07, }, + { .phy_offset = 6, .phy_shift = 0, .rf_addr = 0x52, .rf_shift = 7, .mask = 0x01, }, + { .phy_offset = 5, .phy_shift = 3, .rf_addr = 0x41, .rf_shift = 5, .mask = 0x07, }, + { .phy_offset = 5, .phy_shift = 6, .rf_addr = 0x41, .rf_shift = 0, .mask = 0x0f, }, + { .phy_offset = 5, .phy_shift = 10, .rf_addr = 0x42, .rf_shift = 5, .mask = 0x07, }, + { .phy_offset = 4, .phy_shift = 15, .rf_addr = 0x42, .rf_shift = 0, .mask = 0x01, }, + { .phy_offset = 5, .phy_shift = 0, .rf_addr = 0x42, .rf_shift = 1, .mask = 0x07, }, + { .phy_offset = 4, .phy_shift = 11, .rf_addr = 0x43, .rf_shift = 4, .mask = 0x0f, }, + { .phy_offset = 4, .phy_shift = 7, .rf_addr = 0x43, .rf_shift = 0, .mask = 0x0f, }, + { .phy_offset = 4, .phy_shift = 6, .rf_addr = 0x45, .rf_shift = 1, .mask = 0x01, }, + { .phy_offset = 2, .phy_shift = 7, .rf_addr = 0x40, .rf_shift = 4, .mask = 0x0f, }, + { .phy_offset = 2, .phy_shift = 11, .rf_addr = 0x40, .rf_shift = 0, .mask = 0x0f, }, +}; + static void lpphy_sync_stx(struct b43_wldev *dev) { - //TODO + const struct lpphy_stx_table_entry *e; + unsigned int i; + u16 tmp; + + for (i = 0; i < ARRAY_SIZE(lpphy_stx_table); i++) { + e = &lpphy_stx_table[i]; + tmp = b43_radio_read(dev, e->rf_addr); + tmp >>= e->rf_shift; + tmp <<= e->phy_shift; + b43_phy_maskset(dev, B43_PHY_OFDM(0xF2 + e->phy_offset), + e->mask << e->phy_shift, tmp); + } } static void lpphy_radio_init(struct b43_wldev *dev) @@ -366,7 +417,9 @@ static void lpphy_radio_init(struct b43_wldev *dev) lpphy_sync_stx(dev); b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80); b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0); - //TODO Do something on the backplane + if (dev->dev->bus->chip_id == 0x4325) { + // TODO SSB PMU recalibration + } } } -- cgit v0.10.2 From d6756d0dc220c3d12e2c4c06ca97d1dbcb5edf4e Mon Sep 17 00:00:00 2001 From: Igor Perminov Date: Mon, 10 Aug 2009 00:58:54 +0200 Subject: rt2x00: Fix beacon de-synchronization while update beacon When beacon is being updated to refresh TIM (AP mode), beacon frames are de-synchronizing (i.e. two neighbor beacon frames - before and after update - are being transmitted with a wrong time interval). That is because xxx_write_beacon should disable beacon generation only while beacon data are being uploaded to the device, but it should not disable the beacon clock. Signed-off-by: Igor Perminov Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 30185ad..164df93 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1069,8 +1069,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); - rt2x00_set_field32(®, CSR14_TBCN, 0); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 3b31715..4186582 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1227,8 +1227,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); - rt2x00_set_field32(®, CSR14_TBCN, 0); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index de48c5c..09a5894 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1238,8 +1238,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); - rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0); - rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); @@ -1287,7 +1285,7 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry) static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue) { - u16 reg; + u16 reg, reg0; if (queue != QID_BEACON) { rt2x00usb_kick_tx_queue(rt2x00dev, queue); @@ -1298,16 +1296,19 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) { rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); + reg0 = reg; rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 1); /* * Beacon generation will fail initially. - * To prevent this we need to register the TXRX_CSR19 - * register several times. + * To prevent this we need to change the TXRX_CSR19 + * register several times (reg0 is the same as reg + * except for TXRX_CSR19_BEACON_GEN, which is 0 in reg0 + * and 1 in reg). */ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); - rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); - rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } } diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 2de0389..3856f06 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2050,8 +2050,6 @@ static void rt2800usb_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 3447997..f4b4b86 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1855,8 +1855,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4b9955b..4d94b65 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1527,8 +1527,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); -- cgit v0.10.2 From c38e7a9348f725be0ea2493454db9e6d44fb7e0c Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 10 Aug 2009 03:26:55 +0300 Subject: ath5k: Check EEPROM before tweaking SERDES * Read PCI-E infos offset from EEPROM and if it points to serdes section (0x40), enable serdes programming (further tweaking of serdes values during attach). This follows Legacy and Sam's HAL sources. Signed-off-by: Nick Kossifidis Acked-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 9a84d94..6263065 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -253,28 +253,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) } /* - * Write PCI-E power save settings - */ - if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { - ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES); - ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES); - /* Shut off RX when elecidle is asserted */ - ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES); - ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES); - /* TODO: EEPROM work */ - ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES); - /* Shut off PLL and CLKREQ active in L1 */ - ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES); - /* Preserce other settings */ - ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES); - ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES); - ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES); - /* Reset SERDES to load new settings */ - ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); - mdelay(1); - } - - /* * POST */ ret = ath5k_hw_post(ah); @@ -295,6 +273,40 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; } + /* + * Write PCI-E power save settings + */ + if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + + ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES); + + /* Shut off RX when elecidle is asserted */ + ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES); + + /* If serdes programing is enabled, increase PCI-E + * tx power for systems with long trace from host + * to minicard connector. */ + if (ee->ee_serdes) + ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES); + else + ath5k_hw_reg_write(ah, 0xf6800579, AR5K_PCIE_SERDES); + + /* Shut off PLL and CLKREQ active in L1 */ + ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES); + + /* Preserve other settings */ + ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES); + + /* Reset SERDES to load new settings */ + ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); + mdelay(1); + } + /* Get misc capabilities */ ret = ath5k_hw_set_capabilities(ah); if (ret) { diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index c56b494..8af477d 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -167,6 +167,16 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL); ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? true : false; + /* Check if PCIE_OFFSET points to PCIE_SERDES_SECTION + * and enable serdes programming if needed. + * + * XXX: Serdes values seem to be fixed so + * no need to read them here, we write them + * during ath5k_hw_attach */ + AR5K_EEPROM_READ(AR5K_EEPROM_PCIE_OFFSET, val); + ee->ee_serdes = (val == AR5K_EEPROM_PCIE_SERDES_SECTION) ? + true : false; + return 0; } diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 64be73a..0123f35 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -19,6 +19,9 @@ /* * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE) */ +#define AR5K_EEPROM_PCIE_OFFSET 0x02 /* Contains offset to PCI-E infos */ +#define AR5K_EEPROM_PCIE_SERDES_SECTION 0x40 /* PCIE_OFFSET points here when + * SERDES infos are present */ #define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */ #define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */ #define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */ @@ -391,6 +394,7 @@ struct ath5k_eeprom_info { u8 ee_rfkill_pin; bool ee_rfkill_pol; bool ee_is_hb63; + bool ee_serdes; u16 ee_misc0; u16 ee_misc1; u16 ee_misc2; -- cgit v0.10.2 From d1cb0bdac180a4afdd3c001acb2618d2a62d9abe Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 10 Aug 2009 03:27:59 +0300 Subject: ath5k: Linear PCDAC code fixes * Set correct xpd curve indices for high/low gain curves during rfbuffer setup on RF5112B with both calibration curves available. * Don't return zero min power when we have the same pcdac value twice because it breaks interpolation. Instead return the right x barrier as we do when we have equal power levels for 2 different pcdac values. Signed-off-by: Nick Kossifidis Acked-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 2075ba9..6afba98 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -740,13 +740,22 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, AR5K_RF_XPD_GAIN, true); } else { - /* TODO: Set high and low gain bits */ - ath5k_hw_rfb_op(ah, rf_regs, - ee->ee_x_gain[ee_mode], + u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode]; + if (ee->ee_pd_gains[ee_mode] > 1) { + ath5k_hw_rfb_op(ah, rf_regs, + pdg_curve_to_idx[0], AR5K_RF_PD_GAIN_LO, true); - ath5k_hw_rfb_op(ah, rf_regs, - ee->ee_x_gain[ee_mode], + ath5k_hw_rfb_op(ah, rf_regs, + pdg_curve_to_idx[1], AR5K_RF_PD_GAIN_HI, true); + } else { + ath5k_hw_rfb_op(ah, rf_regs, + pdg_curve_to_idx[0], + AR5K_RF_PD_GAIN_LO, true); + ath5k_hw_rfb_op(ah, rf_regs, + pdg_curve_to_idx[0], + AR5K_RF_PD_GAIN_HI, true); + } /* Lower synth voltage on Rev 2 */ ath5k_hw_rfb_op(ah, rf_regs, 2, @@ -1896,8 +1905,9 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, s16 min_pwrL, min_pwrR; s16 pwr_i; - if (WARN_ON(stepL[0] == stepL[1] || stepR[0] == stepR[1])) - return 0; + /* Some vendors write the same pcdac value twice !!! */ + if (stepL[0] == stepL[1] || stepR[0] == stepR[1]) + return max(pwrL[0], pwrR[0]); if (pwrL[0] == pwrL[1]) min_pwrL = pwrL[0]; -- cgit v0.10.2 From edd7fc7003f31da48d06e215a93ea966a22c2a03 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 10 Aug 2009 03:29:02 +0300 Subject: ath5k: Wakeup fixes * Don't put chip to full sleep because there are problems during wakeup. Instead hold MAC/Baseband on warm reset state via a new function ath5k_hw_on_hold. * Minor cleanups Signed-off-by: Nick Kossifidis Tested-by: Ben Greear Tested-by: Johannes Stezenbach Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 9137511..1047a6c 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1157,6 +1157,7 @@ extern void ath5k_unregister_leds(struct ath5k_softc *sc); /* Reset Functions */ extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); +extern int ath5k_hw_on_hold(struct ath5k_hw *ah); extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel); /* Power management functions */ extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 6263065..238eeb7 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -145,7 +145,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; /* Bring device out of sleep and reset it's units */ - ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true); + ret = ath5k_hw_nic_wakeup(ah, 0, true); if (ret) goto err_free; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 5d50285..0370cba 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2446,27 +2446,29 @@ ath5k_stop_hw(struct ath5k_softc *sc) ret = ath5k_stop_locked(sc); if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { /* - * Set the chip in full sleep mode. Note that we are - * careful to do this only when bringing the interface - * completely to a stop. When the chip is in this state - * it must be carefully woken up or references to - * registers in the PCI clock domain may freeze the bus - * (and system). This varies by chip and is mostly an - * issue with newer parts that go to sleep more quickly. - */ - if (sc->ah->ah_mac_srev >= 0x78) { - /* - * XXX - * don't put newer MAC revisions > 7.8 to sleep because - * of the above mentioned problems - */ - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, " - "not putting device to sleep\n"); - } else { - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, - "putting device to full sleep\n"); - ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0); - } + * Don't set the card in full sleep mode! + * + * a) When the device is in this state it must be carefully + * woken up or references to registers in the PCI clock + * domain may freeze the bus (and system). This varies + * by chip and is mostly an issue with newer parts + * (madwifi sources mentioned srev >= 0x78) that go to + * sleep more quickly. + * + * b) On older chips full sleep results a weird behaviour + * during wakeup. I tested various cards with srev < 0x78 + * and they don't wake up after module reload, a second + * module reload is needed to bring the card up again. + * + * Until we figure out what's going on don't enable + * full chip reset on any chip (this is what Legacy HAL + * and Sam's HAL do anyway). Instead Perform a full reset + * on the device (same as initial state after attach) and + * leave it idle (keep MAC/BB on warm reset) */ + ret = ath5k_hw_on_hold(sc->ah); + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "putting device to sleep\n"); } ath5k_txbuf_free(sc, sc->bbuf); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 86733fd..34e13c7 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -258,29 +258,35 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, if (!set_chip) goto commit; - /* Preserve sleep duration */ data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL); + + /* If card is down we 'll get 0xffff... so we + * need to clean this up before we write the register + */ if (data & 0xffc00000) data = 0; else - data = data & 0xfffcffff; + /* Preserve sleep duration etc */ + data = data & ~AR5K_SLEEP_CTL_SLE; - ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); + ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, + AR5K_SLEEP_CTL); udelay(15); - for (i = 50; i > 0; i--) { + for (i = 200; i > 0; i--) { /* Check if the chip did wake up */ if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_SPWR_DN) == 0) break; /* Wait a bit and retry */ - udelay(200); - ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); + udelay(50); + ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, + AR5K_SLEEP_CTL); } /* Fail if the chip didn't wake up */ - if (i <= 0) + if (i == 0) return -EIO; break; @@ -296,6 +302,64 @@ commit: } /* + * Put device on hold + * + * Put MAC and Baseband on warm reset and + * keep that state (don't clean sleep control + * register). After this MAC and Baseband are + * disabled and a full reset is needed to come + * back. This way we save as much power as possible + * without puting the card on full sleep. + */ +int ath5k_hw_on_hold(struct ath5k_hw *ah) +{ + struct pci_dev *pdev = ah->ah_sc->pdev; + u32 bus_flags; + int ret; + + /* Make sure device is awake */ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n"); + return ret; + } + + /* + * Put chipset on warm reset... + * + * Note: puting PCI core on warm reset on PCI-E cards + * results card to hang and always return 0xffff... so + * we ingore that flag for PCI-E cards. On PCI cards + * this flag gets cleared after 64 PCI clocks. + */ + bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; + + if (ah->ah_version == AR5K_AR5210) { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | + AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); + mdelay(2); + } else { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_BASEBAND | bus_flags); + } + + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to put device on warm reset\n"); + return -EIO; + } + + /* ...wakeup again!*/ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to put device on hold\n"); + return ret; + } + + return ret; +} + +/* * Bring up MAC + PHY Chips and program PLL * TODO: Half/Quarter rate support */ @@ -318,6 +382,50 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) return ret; } + /* + * Put chipset on warm reset... + * + * Note: puting PCI core on warm reset on PCI-E cards + * results card to hang and always return 0xffff... so + * we ingore that flag for PCI-E cards. On PCI cards + * this flag gets cleared after 64 PCI clocks. + */ + bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; + + if (ah->ah_version == AR5K_AR5210) { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | + AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); + mdelay(2); + } else { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_BASEBAND | bus_flags); + } + + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); + return -EIO; + } + + /* ...wakeup again!...*/ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); + return ret; + } + + /* ...clear reset control register and pull device out of + * warm reset */ + if (ath5k_hw_nic_reset(ah, 0)) { + ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); + return -EIO; + } + + /* On initialization skip PLL programming since we don't have + * a channel / mode set yet */ + if (initial) + return 0; + if (ah->ah_version != AR5K_AR5210) { /* * Get channel mode flags @@ -383,39 +491,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) AR5K_PHY_TURBO); } - /* reseting PCI on PCI-E cards results card to hang - * and always return 0xffff... so we ingore that flag - * for PCI-E cards */ - bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; - - /* Reset chipset */ - if (ah->ah_version == AR5K_AR5210) { - ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | - AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | - AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); - mdelay(2); - } else { - ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | - AR5K_RESET_CTL_BASEBAND | bus_flags); - } - if (ret) { - ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); - return -EIO; - } - - /* ...wakeup again!*/ - ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); - if (ret) { - ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); - return ret; - } - - /* ...final warm reset */ - if (ath5k_hw_nic_reset(ah, 0)) { - ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); - return -EIO; - } - if (ah->ah_version != AR5K_AR5210) { /* ...update PLL if needed */ -- cgit v0.10.2 From b55a5de114dcdc03f2f18c3bd98bbabb13ee53ef Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 10 Aug 2009 03:30:32 +0300 Subject: ath5k: Preserve pcicfg bits during attach * During attach preserve pcicfg bits when enabling pci core sw retry fix. Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 238eeb7..65d438b 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -261,7 +261,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) /* Enable pci core retry fix on Hainan (5213A) and later chips */ if (srev >= AR5K_SREV_AR5213A) - ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG); + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_RETRY_FIX); /* * Get card capabilities, calibration values etc -- cgit v0.10.2 From 6e220662bf9a2ba284e88a8c8867340c9f6da27e Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 10 Aug 2009 03:31:31 +0300 Subject: ath5k: Use SWI to trigger calibration * Get rid of calibration timer, instead use a software interrupt to schedule the calibration tasklet. a) We don't need a timer for this, there is no need for accuracy even with round_jiffies i think this is a waste of resources. Also we don't need to run calibration if we are idle (no interrupts). b) When we add ANI support we 'll just extend the poll function and calibration tasklet and handle all periodic phy calibration on one place (much cleaner). c) Having calibration on a tasklet is better since during calibration we can't transmit or receive (antennas are detached to measure noise floor), previously calibration could run in parallel with tx/rx and interfere (packet loss). v2: kill tasklet on stop_hw, stop/wake queues v3: use time_is_before_eq_jiffies to compare timestamp with current time Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 1047a6c..c09402e 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -919,6 +919,12 @@ enum ath5k_int { AR5K_INT_NOCARD = 0xffffffff }; +/* Software interrupts used for calibration */ +enum ath5k_software_interrupt { + AR5K_SWI_FULL_CALIBRATION = 0x01, + AR5K_SWI_SHORT_CALIBRATION = 0x02, +}; + /* * Power management */ @@ -1123,6 +1129,15 @@ struct ath5k_hw { /* noise floor from last periodic calibration */ s32 ah_noise_floor; + /* Calibration timestamp */ + unsigned long ah_cal_tstamp; + + /* Calibration interval (secs) */ + u8 ah_cal_intval; + + /* Software interrupt mask */ + u8 ah_swi_mask; + /* * Function pointers */ @@ -1276,6 +1291,7 @@ extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *chann /* PHY calibration */ extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); +extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah); /* Spur mitigation */ bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, struct ieee80211_channel *channel); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 0370cba..acbcfc2 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -59,7 +59,7 @@ #include "reg.h" #include "debug.h" -static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ +static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); @@ -376,7 +376,7 @@ static int ath5k_stop_hw(struct ath5k_softc *sc); static irqreturn_t ath5k_intr(int irq, void *dev_id); static void ath5k_tasklet_reset(unsigned long data); -static void ath5k_calibrate(unsigned long data); +static void ath5k_tasklet_calibrate(unsigned long data); /* * Module init/exit functions @@ -799,8 +799,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); + tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc); tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); - setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); ret = ath5k_eeprom_read_mac(ah, mac); if (ret) { @@ -2364,7 +2364,7 @@ ath5k_init(struct ath5k_softc *sc) sc->curband = &sc->sbands[sc->curchan->band]; sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | - AR5K_INT_FATAL | AR5K_INT_GLOBAL; + AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI; ret = ath5k_reset(sc, NULL); if (ret) goto done; @@ -2381,8 +2381,8 @@ ath5k_init(struct ath5k_softc *sc) /* Set ack to be sent at low bit-rates */ ath5k_hw_set_ack_bitrate_high(ah, false); - mod_timer(&sc->calib_tim, round_jiffies(jiffies + - msecs_to_jiffies(ath5k_calinterval * 1000))); + /* Set PHY calibration inteval */ + ah->ah_cal_intval = ath5k_calinterval; ret = 0; done: @@ -2475,10 +2475,10 @@ ath5k_stop_hw(struct ath5k_softc *sc) mmiowb(); mutex_unlock(&sc->lock); - del_timer_sync(&sc->calib_tim); tasklet_kill(&sc->rxtq); tasklet_kill(&sc->txtq); tasklet_kill(&sc->restq); + tasklet_kill(&sc->calib); tasklet_kill(&sc->beacontq); ath5k_rfkill_hw_stop(sc->ah); @@ -2534,6 +2534,9 @@ ath5k_intr(int irq, void *dev_id) if (status & AR5K_INT_BMISS) { /* TODO */ } + if (status & AR5K_INT_SWI) { + tasklet_schedule(&sc->calib); + } if (status & AR5K_INT_MIB) { /* * These stats are also used for ANI i think @@ -2550,6 +2553,8 @@ ath5k_intr(int irq, void *dev_id) if (unlikely(!counter)) ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); + ath5k_hw_calibration_poll(ah); + return IRQ_HANDLED; } @@ -2566,11 +2571,19 @@ ath5k_tasklet_reset(unsigned long data) * for temperature/environment changes. */ static void -ath5k_calibrate(unsigned long data) +ath5k_tasklet_calibrate(unsigned long data) { struct ath5k_softc *sc = (void *)data; struct ath5k_hw *ah = sc->ah; + /* Only full calibration for now */ + if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION) + return; + + /* Stop queues so that calibration + * doesn't interfere with tx */ + ieee80211_stop_queues(sc->hw); + ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", ieee80211_frequency_to_channel(sc->curchan->center_freq), sc->curchan->hw_value); @@ -2588,8 +2601,11 @@ ath5k_calibrate(unsigned long data) ieee80211_frequency_to_channel( sc->curchan->center_freq)); - mod_timer(&sc->calib_tim, round_jiffies(jiffies + - msecs_to_jiffies(ath5k_calinterval * 1000))); + ah->ah_swi_mask = 0; + + /* Wake queues */ + ieee80211_wake_queues(sc->hw); + } diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 778e422..667bd9d 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -177,6 +177,8 @@ struct ath5k_softc { struct ath5k_rfkill rf_kill; + struct tasklet_struct calib; /* calibration tasklet */ + spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ struct ath5k_buf *bbuf; /* beacon buffer */ @@ -187,7 +189,6 @@ struct ath5k_softc { unsigned int nexttbtt; /* next beacon time in TU */ struct ath5k_txq *cabq; /* content after beacon */ - struct timer_list calib_tim; /* calibration timer */ int power_level; /* Requested tx power in dbm */ bool assoc; /* assocate state */ bool enable_beacon; /* true if beacons are on */ diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 6afba98..298fcf0 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1104,6 +1104,29 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) PHY calibration \*****************/ +void +ath5k_hw_calibration_poll(struct ath5k_hw *ah) +{ + /* Calibration interval in jiffies */ + unsigned long cal_intval; + + cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000); + + /* Initialize timestamp if needed */ + if (!ah->ah_cal_tstamp) + ah->ah_cal_tstamp = jiffies; + + /* For now we always do full calibration + * Mark software interrupt mask and fire software + * interrupt (bit gets auto-cleared) */ + if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) { + ah->ah_cal_tstamp = jiffies; + ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION; + AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); + } + +} + /** * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration * -- cgit v0.10.2 From 5e68ff6563ef79d87296c70f8eb2bee454d3fe75 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 10 Aug 2009 11:15:13 +0300 Subject: MAINTAINERS: add information for wl1271 wireless driver Add maintainer information section for the wl1271 wireless driver and fix the information for wl1271. Signed-off-by: Luciano Coelho Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index 7b10f42..866253d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5580,7 +5580,16 @@ L: linux-wireless@vger.kernel.org W: http://wireless.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git S: Maintained -F: drivers/net/wireless/wl12xx/wl1251* +F: drivers/net/wireless/wl12xx/* +X: drivers/net/wireless/wl12xx/wl1271* + +WL1271 WIRELESS DRIVER +M: Luciano Coelho +L: linux-wireless@vger.kernel.org +W: http://wireless.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git +S: Maintained +F: drivers/net/wireless/wl12xx/wl1271* WL3501 WIRELESS PCMCIA CARD DRIVER M: Arnaldo Carvalho de Melo -- cgit v0.10.2 From feff1f2fea3fc7ee055e46d0fbdb2d25ad2b14c4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Aug 2009 16:01:54 +0200 Subject: mac80211: take statistics before encryption When encryption is used, the number of bytes sent to the peer increases by the IV and ICV. This is accounted if software encryption is used, but not if the devices does hardware encryption. To make the numbers comparable, never account for that overhead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7f2e4cd..588c18a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -844,6 +844,23 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) } static ieee80211_tx_result debug_noinline +ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) +{ + struct sk_buff *skb = tx->skb; + + if (!tx->sta) + return TX_CONTINUE; + + tx->sta->tx_packets++; + do { + tx->sta->tx_fragments++; + tx->sta->tx_bytes += skb->len; + } while ((skb = skb->next)); + + return TX_CONTINUE; +} + +static ieee80211_tx_result debug_noinline ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) { if (!tx->key) @@ -887,23 +904,6 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) return TX_CONTINUE; } -static ieee80211_tx_result debug_noinline -ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) -{ - struct sk_buff *skb = tx->skb; - - if (!tx->sta) - return TX_CONTINUE; - - tx->sta->tx_packets++; - do { - tx->sta->tx_fragments++; - tx->sta->tx_bytes += skb->len; - } while ((skb = skb->next)); - - return TX_CONTINUE; -} - /* actual transmit path */ /* @@ -1213,9 +1213,9 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) CALL_TXH(ieee80211_tx_h_sequence) CALL_TXH(ieee80211_tx_h_fragment) /* handlers after fragment must be aware of tx info fragmentation! */ + CALL_TXH(ieee80211_tx_h_stats) CALL_TXH(ieee80211_tx_h_encrypt) CALL_TXH(ieee80211_tx_h_calculate_duration) - CALL_TXH(ieee80211_tx_h_stats) #undef CALL_TXH txh_done: -- cgit v0.10.2 From d0b69609dc50b6bf2637cf74e6f97c251adc65ed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Aug 2009 16:02:40 +0200 Subject: mac80211: sequence number micro-optimisation There's no need to mask the variable with 0xFFF0 since we ever only use it as a u16 and the lowest four bits can't ever be non-zero. The compiler cannot infer the latter, and therefore has to emit code to do the masking. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 588c18a..0c24a4b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -700,7 +700,6 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) /* for pure STA mode without beacons, we can do it */ hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); tx->sdata->sequence_number += 0x10; - tx->sdata->sequence_number &= IEEE80211_SCTL_SEQ; return TX_CONTINUE; } -- cgit v0.10.2 From 62b1208e146af048e90a32bc4fe5fba85e4fa51e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Aug 2009 16:04:15 +0200 Subject: mac80211: small tx code cleanup It's really easier to read if it's not indented as much, so invert the condition and rearrange the code so the smaller chunk is indented instead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0c24a4b..3244298 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -317,30 +317,30 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) if (!atomic_read(&tx->sdata->bss->num_sta_ps)) return TX_CONTINUE; + /* buffered in hardware */ + if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) { + info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; + + return TX_CONTINUE; + } + /* buffered in mac80211 */ - if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) { - if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) - purge_old_ps_buffers(tx->local); - if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= - AP_MAX_BC_BUFFER) { + if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) + purge_old_ps_buffers(tx->local); + + if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: BC TX buffer full - " - "dropping the oldest frame\n", - tx->dev->name); - } + if (net_ratelimit()) + printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n", + tx->dev->name); #endif - dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); - } else - tx->local->total_ps_buffered++; - skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); - return TX_QUEUED; - } + dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); + } else + tx->local->total_ps_buffered++; - /* buffered in hardware */ - info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; + skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); - return TX_CONTINUE; + return TX_QUEUED; } static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, -- cgit v0.10.2 From c65d6fbf91517a0a955de7ce029940bc63ea8203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Mon, 10 Aug 2009 20:39:47 +0200 Subject: b43: Implement LP-PHY baseband table initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement LP-PHY baseband table init for all revisions. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index e68644d..79039c3 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -59,9 +59,43 @@ static void b43_lpphy_op_free(struct b43_wldev *dev) dev->phy.lp = NULL; } +static void lpphy_adjust_gain_table(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + u32 freq = dev->wl->hw->conf.channel->center_freq; + u16 temp[3]; + u16 isolation; + + B43_WARN_ON(dev->phy.rev >= 2); + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + isolation = lpphy->tx_isolation_med_band; + else if (freq <= 5320) + isolation = lpphy->tx_isolation_low_band; + else if (freq <= 5700) + isolation = lpphy->tx_isolation_med_band; + else + isolation = lpphy->tx_isolation_hi_band; + + temp[0] = ((isolation - 26) / 12) << 12; + temp[1] = temp[0] + 0x1000; + temp[2] = temp[0] + 0x2000; + + b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp); + b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp); +} + static void lpphy_table_init(struct b43_wldev *dev) { - //TODO + if (dev->phy.rev < 2) + lpphy_rev0_1_table_init(dev); + else + lpphy_rev2plus_table_init(dev); + + lpphy_init_tx_gain_table(dev); + + if (dev->phy.rev < 2) + lpphy_adjust_gain_table(dev); } static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) @@ -596,13 +630,13 @@ static void lpphy_tx_pctl_init(struct b43_wldev *dev) static int b43_lpphy_op_init(struct b43_wldev *dev) { /* TODO: band SPROM */ - /* TODO: tables init */ lpphy_baseband_init(dev); lpphy_radio_init(dev); //TODO calibrate RC //TODO set channel lpphy_tx_pctl_init(dev); - //TODO full calib + lpphy_calibration(dev); + //TODO ACI init return 0; } @@ -680,7 +714,6 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev, return B43_TXPWR_RES_DONE; } - const struct b43_phy_operations b43_phyops_lp = { .allocate = b43_lpphy_op_allocate, .free = b43_lpphy_op_free, diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index cadfe81..b056811 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -710,3 +710,1719 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, offset++; } } + +static const u8 lpphy_min_sig_sq_table[] = { + 0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd, + 0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd, + 0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, +}; + +static const u16 lpphy_rev01_noise_scale_table[] = { + 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, + 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, + 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0x00a4, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4c00, 0x2d36, + 0x0000, 0x0000, 0x4c00, 0x2d36, +}; + +static const u16 lpphy_rev2plus_noise_scale_table[] = { + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x0000, + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, + 0x00a4, +}; + +static const u16 lpphy_crs_gain_nft_table[] = { + 0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f, 0x036f, + 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381, 0x0374, 0x0381, + 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f, 0x0040, 0x005e, 0x007f, + 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d, 0x013d, +}; + +static const u16 lpphy_rev01_filter_control_table[] = { + 0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077, 0xff53, + 0x0127, +}; + +static const u32 lpphy_rev2plus_filter_control_table[] = { + 0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27, 0x0000217f, + 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f, +}; + +static const u32 lpphy_rev01_ps_control_table[] = { + 0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101, 0x00000080, + 0x08080101, 0x00000040, 0x08080101, 0x000000c0, 0x08a81501, 0x000000c0, + 0x0fe8fd01, 0x000000c0, 0x08300105, 0x000000c0, 0x08080201, 0x000000c0, + 0x08280205, 0x000000c0, 0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, + 0x08080202, 0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0, + 0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106, 0x000000c0, + 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0, +}; + +static const u32 lpphy_rev2plus_ps_control_table[] = { + 0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000, 0x00002080, + 0x00006180, 0x00003002, 0x00000040, 0x00002042, 0x00180047, 0x00080043, + 0x00000041, 0x000020c1, 0x00046006, 0x00042002, 0x00040000, 0x00002003, + 0x00180006, 0x00080002, +}; + +static const u8 lpphy_pll_fraction_table[] = { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +}; + +static const u16 lpphy_iq_local_table[] = { + 0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, + 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600, + 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, + 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, +}; + +static const u16 lpphy_ofdm_cck_gain_table[] = { + 0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001, 0x5001, + 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075, + 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d, 0x135d, 0x055d, 0x155d, + 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d, 0x755d, +}; + +static const u16 lpphy_gain_delta_table[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const u32 lpphy_tx_power_control_table[] = { + 0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c, 0x0000004b, + 0x0000004a, 0x00000049, 0x00000048, 0x00000047, 0x00000046, 0x00000045, + 0x00000044, 0x00000043, 0x00000042, 0x00000041, 0x00000040, 0x0000003f, + 0x0000003e, 0x0000003d, 0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, + 0x00000038, 0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033, + 0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e, 0x0000002d, + 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029, 0x00000028, 0x00000027, + 0x00000026, 0x00000025, 0x00000024, 0x00000023, 0x00000022, 0x00000021, + 0x00000020, 0x0000001f, 0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, + 0x0000001a, 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015, + 0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x000075a0, 0x000075a0, 0x000075a1, 0x000075a1, 0x000075a2, 0x000075a2, + 0x000075a3, 0x000075a3, 0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, + 0x000074b2, 0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20, + 0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23, 0x00006d23, + 0x00004660, 0x00004660, 0x00004661, 0x00004661, 0x00004662, 0x00004662, + 0x00004663, 0x00004663, 0x00003e60, 0x00003e60, 0x00003e61, 0x00003e61, + 0x00003e62, 0x00003e62, 0x00003e63, 0x00003e63, 0x00003660, 0x00003660, + 0x00003661, 0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663, + 0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62, 0x00002e62, + 0x00002e63, 0x00002e63, 0x00002660, 0x00002660, 0x00002661, 0x00002661, + 0x00002662, 0x00002662, 0x00002663, 0x00002663, 0x000025e0, 0x000025e0, + 0x000025e1, 0x000025e1, 0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, + 0x00001de0, 0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2, + 0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61, 0x00001d61, + 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63, 0x00001560, 0x00001560, + 0x00001561, 0x00001561, 0x00001562, 0x00001562, 0x00001563, 0x00001563, + 0x00000d60, 0x00000d60, 0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, + 0x00000d63, 0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1, + 0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10, 0x00000e10, + 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12, 0x00000e13, 0x00000e13, + 0x00000bf0, 0x00000bf0, 0x00000bf1, 0x00000bf1, 0x00000bf2, 0x00000bf2, + 0x00000bf3, 0x00000bf3, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc, + 0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04, 0x0000fcff, + 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006, 0x0000ff03, 0x000007fc, + 0x0000fc08, 0x00000203, 0x0000fffb, 0x00000600, 0x0000fa01, 0x0000fc03, + 0x0000fe06, 0x0000fe00, 0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, + 0x000004fd, 0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500, + 0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa, 0x00000700, + 0x00000305, 0x000004ff, 0x00000801, 0x00000503, 0x000005f9, 0x00000404, + 0x0000fb08, 0x000005fd, 0x00000501, 0x00000405, 0x0000fb03, 0x000007fc, + 0x00000403, 0x00000303, 0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, + 0x0000fe01, 0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe, + 0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa, 0x000003fe, + 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06, 0x000008fc, 0x00000701, + 0x00000504, 0x0000fdfe, 0x0000fdfc, 0x000003fe, 0x00000704, 0x000002fc, + 0x000004f9, 0x0000fdfd, 0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, + 0x000004f9, 0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05, + 0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa, 0x00000305, + 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc, 0x0000fe03, 0x00000701, + 0x000001fb, 0x000001f9, 0x00000206, 0x000006fd, 0x00000508, 0x00000700, + 0x00000304, 0x000005fe, 0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, + 0x000007f9, 0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08, + 0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb, 0x00000702, +}; + +static const u32 lpphy_gain_idx_table[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x10000001, 0x00000000, 0x20000082, 0x00000000, 0x40000104, 0x00000000, + 0x60004207, 0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001, + 0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000, + 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711, 0x00000001, + 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010, 0x11630915, 0x00000011, + 0x31c3ca1b, 0x00000011, 0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, + 0x22468e21, 0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, + 0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a, + 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c, 0x0000001a, + 0x64ca55ad, 0x0000001a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082, 0x00000000, + 0x40000104, 0x00000000, 0x60004207, 0x00000001, 0x7000838a, 0x00000001, + 0xd021050d, 0x00000001, 0xe041c683, 0x00000001, 0x50828805, 0x00000000, + 0x80e34288, 0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, + 0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010, + 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c, 0x00000018, + 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019, 0x4286d023, 0x00000019, + 0xa347d0a4, 0x00000019, 0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, + 0x0408d329, 0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, + 0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, +}; + +static const u16 lpphy_aux_gain_idx_table[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0016, +}; + +static const u32 lpphy_gain_value_table[] = { + 0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb, 0x00000004, + 0x00000008, 0x0000000d, 0x00000001, 0x00000004, 0x00000007, 0x0000000a, + 0x0000000d, 0x00000010, 0x00000012, 0x00000015, 0x00000000, 0x00000006, + 0x0000000c, 0x00000000, 0x00000000, 0x00000000, 0x00000012, 0x00000000, + 0x00000000, 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000001e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000003, 0x00000006, 0x00000009, 0x0000000c, 0x0000000f, + 0x00000012, 0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009, 0x000000f1, + 0x00000000, 0x00000000, +}; + +static const u16 lpphy_gain_table[] = { + 0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808, 0x080a, + 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813, 0x0814, 0x0816, + 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824, 0x0830, 0x0834, 0x0837, + 0x083b, 0x083f, 0x0840, 0x0844, 0x0857, 0x085b, 0x085f, 0x08d7, 0x08db, + 0x08df, 0x0957, 0x095b, 0x095f, 0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, + 0x175f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const u32 lpphy_a0_gain_idx_table[] = { + 0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060, 0x00511065, + 0x004c806b, 0x0047d072, 0x00444078, 0x00400080, 0x003ca087, 0x0039408f, + 0x0035e098, 0x0032e0a1, 0x003030aa, 0x002d80b4, 0x002ae0bf, 0x002880ca, + 0x002640d6, 0x002410e3, 0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, + 0x001b012f, 0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193, + 0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a, 0x000e523a, + 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd, 0x000ac2f8, 0x000a2325, + 0x00099355, 0x00091387, 0x000883bd, 0x000813f5, 0x0007a432, 0x00073471, + 0x0006c4b5, 0x000664fc, 0x00061547, 0x0005b598, 0x000565ec, 0x00051646, + 0x0004d6a5, 0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd, + 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28, +}; + +static const u16 lpphy_a0_aux_gain_idx_table[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0014, +}; + +static const u32 lpphy_a0_gain_value_table[] = { + 0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb, 0x00000004, + 0x00000008, 0x0000000d, 0x00000001, 0x00000004, 0x00000007, 0x0000000a, + 0x0000000d, 0x00000010, 0x00000012, 0x00000015, 0x00000000, 0x00000006, + 0x0000000c, 0x00000000, 0x00000000, 0x00000000, 0x00000012, 0x00000000, + 0x00000000, 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000001e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000003, 0x00000006, 0x00000009, 0x0000000c, 0x0000000f, + 0x00000012, 0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0x000000f7, + 0x00000000, 0x00000000, +}; + +static const u16 lpphy_a0_gain_table[] = { + 0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, + 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016, 0x0017, 0x001a, + 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034, 0x0037, 0x003b, 0x003f, + 0x0040, 0x0044, 0x0057, 0x005b, 0x005f, 0x00d7, 0x00db, 0x00df, 0x0157, + 0x015b, 0x015f, 0x0357, 0x035b, 0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const u16 lpphy_sw_control_table[] = { + 0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028, 0x0128, + 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028, 0x0009, 0x0009, + 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0128, 0x0128, 0x0009, 0x0009, + 0x0028, 0x0028, 0x0028, 0x0028, 0x0128, 0x0128, 0x0009, 0x0009, 0x0028, + 0x0028, 0x0028, 0x0028, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, + 0x0009, 0x0009, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, +}; + +static const u8 lpphy_hf_table[] = { + 0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48, + 0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17, +}; + +static const u32 lpphy_papd_eps_table[] = { + 0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9, 0x00021fdf, + 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7, 0x0004efc2, 0x00055fb5, + 0x0005cfb0, 0x00063fa8, 0x00068fa3, 0x00071f98, 0x0007ef92, 0x00084f8b, + 0x0008df82, 0x00097f77, 0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, + 0x000bff41, 0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16, + 0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15, 0x00143f1c, + 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f, 0x001e6f7e, 0x0021cfa4, + 0x0025bfd2, 0x002a2008, 0x002fb047, 0x00360090, 0x003d40e0, 0x0045c135, + 0x004fb189, 0x005ae1d7, 0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, + 0x007ff2e3, 0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356, + 0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506, +}; + +static const u32 lpphy_papd_mult_table[] = { + 0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060, 0x00511065, + 0x004c806b, 0x0047d072, 0x00444078, 0x00400080, 0x003ca087, 0x0039408f, + 0x0035e098, 0x0032e0a1, 0x003030aa, 0x002d80b4, 0x002ae0bf, 0x002880ca, + 0x002640d6, 0x002410e3, 0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, + 0x001b012f, 0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193, + 0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a, 0x000e523a, + 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd, 0x000ac2f8, 0x000a2325, + 0x00099355, 0x00091387, 0x000883bd, 0x000813f5, 0x0007a432, 0x00073471, + 0x0006c4b5, 0x000664fc, 0x00061547, 0x0005b598, 0x000565ec, 0x00051646, + 0x0004d6a5, 0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd, + 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28, +}; + +struct lpphy_tx_gain_table_entry { + u8 gm, pga, pad, dac, bb_mult; +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev0_nopa_tx_gain_table[] = { + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 152, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 147, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 143, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 139, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 135, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 131, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 128, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 124, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 121, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 117, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 114, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 111, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 107, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 104, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 101, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 99, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 96, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 93, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 90, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 88, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 85, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 83, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 81, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 78, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 76, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 74, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev0_2ghz_tx_gain_table[] = { + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 58, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 58, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 57, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 83, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 81, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 78, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 76, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 74, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 72, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev0_5ghz_tx_gain_table[] = { + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 99, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 96, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 93, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 90, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 88, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 85, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 83, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 81, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 78, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 76, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 74, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 55, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 55, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev1_nopa_tx_gain_table[] = { + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 152, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 147, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 143, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 139, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 135, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 131, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 128, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 124, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 121, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 117, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 114, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 111, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 107, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 104, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 101, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 99, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 96, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 93, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 90, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 88, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 85, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 83, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 81, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 78, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 76, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 74, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev1_2ghz_tx_gain_table[] = { + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 85, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 81, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 78, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 76, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 74, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 58, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 58, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 62, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev1_5ghz_tx_gain_table[] = { + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 99, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 96, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 93, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 90, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 88, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 85, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 83, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 81, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 78, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 76, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 74, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 55, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 55, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev2_nopa_tx_gain_table[] = { + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 152, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 147, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 143, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 139, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 135, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 131, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 128, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 124, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 121, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 117, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 114, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 111, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 107, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 104, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 101, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 99, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 96, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 93, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 90, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 88, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 85, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 83, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 81, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 78, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 76, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 74, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 72, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 70, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 68, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 66, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 192, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 176, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 171, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 157, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 144, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 140, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 136, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 128, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 124, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 121, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 117, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 114, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 111, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 108, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 105, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 102, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 99, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 96, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 93, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 91, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 88, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 86, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 83, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 81, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 79, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 76, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 74, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 72, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 70, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 68, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 66, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 248, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 248, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 241, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 241, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 234, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 234, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 227, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 227, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 221, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 221, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 215, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 215, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 208, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 208, .pad = 52, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 203, .pad = 52, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 203, .pad = 51, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 197, .pad = 51, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 197, .pad = 49, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 191, .pad = 49, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 191, .pad = 48, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 186, .pad = 48, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 186, .pad = 47, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 181, .pad = 47, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 181, .pad = 45, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 175, .pad = 45, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 175, .pad = 44, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 170, .pad = 44, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 170, .pad = 43, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 166, .pad = 43, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 166, .pad = 42, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 161, .pad = 42, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 161, .pad = 40, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 156, .pad = 40, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 156, .pad = 39, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 152, .pad = 39, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 152, .pad = 38, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 148, .pad = 38, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 148, .pad = 37, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 143, .pad = 37, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 143, .pad = 36, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 139, .pad = 36, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 139, .pad = 35, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 135, .pad = 35, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 135, .pad = 34, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 132, .pad = 34, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 132, .pad = 33, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 128, .pad = 33, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 128, .pad = 32, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 124, .pad = 32, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 124, .pad = 31, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 121, .pad = 31, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 121, .pad = 30, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 117, .pad = 30, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 117, .pad = 29, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 114, .pad = 29, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 114, .pad = 29, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 111, .pad = 29, .dac = 0, .bb_mult = 64, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev2_2ghz_tx_gain_table[] = { + { .gm = 7, .pga = 99, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 96, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 93, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 90, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 88, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 85, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 83, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 81, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 78, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 76, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 74, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 72, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 70, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 68, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 66, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 62, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 62, .pad = 248, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 60, .pad = 248, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 60, .pad = 241, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 59, .pad = 241, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 59, .pad = 234, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 57, .pad = 234, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 57, .pad = 227, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 55, .pad = 227, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 55, .pad = 221, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 54, .pad = 221, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 54, .pad = 215, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 52, .pad = 215, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 52, .pad = 208, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 51, .pad = 208, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 51, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 49, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 49, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 48, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 48, .pad = 191, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 47, .pad = 191, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 47, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 45, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 45, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 44, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 44, .pad = 175, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 43, .pad = 175, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 43, .pad = 170, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 42, .pad = 170, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 42, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 40, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 40, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 39, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 39, .pad = 156, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 38, .pad = 156, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 38, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 37, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 37, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 36, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 36, .pad = 143, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 35, .pad = 143, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 35, .pad = 139, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 34, .pad = 139, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 34, .pad = 135, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 33, .pad = 135, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 33, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 32, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 32, .pad = 128, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 31, .pad = 128, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 31, .pad = 124, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 30, .pad = 124, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 30, .pad = 121, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 29, .pad = 121, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 29, .pad = 117, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 29, .pad = 117, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 29, .pad = 114, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 28, .pad = 114, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 28, .pad = 111, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 27, .pad = 111, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 27, .pad = 108, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 26, .pad = 108, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 26, .pad = 104, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 25, .pad = 104, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 25, .pad = 102, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 25, .pad = 102, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 25, .pad = 99, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 24, .pad = 99, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 24, .pad = 96, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 23, .pad = 96, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 23, .pad = 93, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 23, .pad = 93, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 23, .pad = 90, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 22, .pad = 90, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 22, .pad = 88, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 21, .pad = 88, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 21, .pad = 85, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 21, .pad = 85, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 21, .pad = 83, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 20, .pad = 83, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 20, .pad = 81, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 20, .pad = 81, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 20, .pad = 78, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 19, .pad = 78, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 19, .pad = 76, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 19, .pad = 76, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 19, .pad = 74, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 18, .pad = 74, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 18, .pad = 72, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 18, .pad = 72, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 18, .pad = 70, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 17, .pad = 70, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 17, .pad = 68, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 17, .pad = 68, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 17, .pad = 66, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 16, .pad = 66, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 16, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 16, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 16, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 52, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 52, .dac = 0, .bb_mult = 64, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev2_5ghz_tx_gain_table[] = { + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 152, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 147, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 143, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 139, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 135, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 131, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 128, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 124, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 121, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 117, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 114, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 111, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 107, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 104, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 101, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 99, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 96, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 93, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 90, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 88, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 85, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 83, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 81, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 78, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 76, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 74, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 72, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 70, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 68, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 66, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 248, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 241, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 234, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 227, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 221, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 215, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 208, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 203, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 197, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 191, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 186, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 181, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 175, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 170, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 166, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 161, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 156, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 152, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 148, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 143, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 139, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 135, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 132, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 128, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 124, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 121, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 117, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 114, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 111, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 108, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 104, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 102, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 99, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 96, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 93, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 90, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 88, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 85, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 83, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 81, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 78, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 76, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 74, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 72, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 70, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 68, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 66, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 62, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 62, .pad = 248, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 60, .pad = 248, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 60, .pad = 241, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 59, .pad = 241, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 59, .pad = 234, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 57, .pad = 234, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 57, .pad = 227, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 55, .pad = 227, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 55, .pad = 221, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 54, .pad = 221, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 54, .pad = 215, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 52, .pad = 215, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 52, .pad = 208, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 51, .pad = 208, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 51, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 49, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 49, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 48, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 48, .pad = 191, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 47, .pad = 191, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 47, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 45, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 45, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 44, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 44, .pad = 175, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 43, .pad = 175, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 43, .pad = 170, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 42, .pad = 170, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 42, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 40, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 40, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 39, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 39, .pad = 156, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 38, .pad = 156, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 38, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 37, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 37, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 36, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 36, .pad = 143, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 35, .pad = 143, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 35, .pad = 139, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 34, .pad = 139, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 34, .pad = 135, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 33, .pad = 135, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 33, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 32, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 32, .pad = 128, .dac = 0, .bb_mult = 64, }, +}; + +void lpphy_rev0_1_table_init(struct b43_wldev *dev) +{ + B43_WARN_ON(dev->phy.rev >= 2); + + b43_lptab_write_bulk(dev, B43_LPTAB8(2, 0), + ARRAY_SIZE(lpphy_min_sig_sq_table), lpphy_min_sig_sq_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(1, 0), + ARRAY_SIZE(lpphy_rev01_noise_scale_table), lpphy_rev01_noise_scale_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0), + ARRAY_SIZE(lpphy_crs_gain_nft_table), lpphy_crs_gain_nft_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(8, 0), + ARRAY_SIZE(lpphy_rev01_filter_control_table), lpphy_rev01_filter_control_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(9, 0), + ARRAY_SIZE(lpphy_rev01_ps_control_table), lpphy_rev01_ps_control_table); + b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0), + ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0), + ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), + ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), + ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(15, 0), + ARRAY_SIZE(lpphy_gain_delta_table), lpphy_gain_delta_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0), + ARRAY_SIZE(lpphy_tx_power_control_table), lpphy_tx_power_control_table); +} + +void lpphy_rev2plus_table_init(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + int i; + + B43_WARN_ON(dev->phy.rev < 2); + + /* + * FIXME This code follows the specs, but it looks wrong: + * In each pass, it writes 4 bytes to an offset in table ID 7, + * then increments the offset by 1 for the next pass. This results + * in the first 3 bytes of each pass except the first one getting + * written to a location that has already been zeroed in the previous + * pass. + * This is what the vendor driver does, but it still looks suspicious. + * + * This should probably suffice: + * + * for (i = 0; i < 704; i+=4) + * b43_lptab_write(dev, B43_LPTAB32(7, i), 0) + * + * This should be tested once the code is functional. + */ + for (i = 0; i < 704; i++) + b43_lptab_write(dev, B43_LPTAB32(7, i), 0); + + b43_lptab_write_bulk(dev, B43_LPTAB8(2, 0), + ARRAY_SIZE(lpphy_min_sig_sq_table), lpphy_min_sig_sq_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(1, 0), + ARRAY_SIZE(lpphy_rev2plus_noise_scale_table), lpphy_rev2plus_noise_scale_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(11, 0), + ARRAY_SIZE(lpphy_rev2plus_filter_control_table), lpphy_rev2plus_filter_control_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(12, 0), + ARRAY_SIZE(lpphy_rev2plus_ps_control_table), lpphy_rev2plus_ps_control_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(13, 0), + ARRAY_SIZE(lpphy_gain_idx_table), lpphy_gain_idx_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0), + ARRAY_SIZE(lpphy_aux_gain_idx_table), lpphy_aux_gain_idx_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(15, 0), + ARRAY_SIZE(lpphy_sw_control_table), lpphy_sw_control_table); + b43_lptab_write_bulk(dev, B43_LPTAB8(16, 0), + ARRAY_SIZE(lpphy_hf_table), lpphy_hf_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(17, 0), + ARRAY_SIZE(lpphy_gain_value_table), lpphy_gain_value_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(18, 0), + ARRAY_SIZE(lpphy_gain_table), lpphy_gain_table); + b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0), + ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0), + ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(9, 0), + ARRAY_SIZE(lpphy_papd_eps_table), lpphy_papd_eps_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0), + ARRAY_SIZE(lpphy_papd_mult_table), lpphy_papd_mult_table); + + if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { + b43_lptab_write_bulk(dev, B43_LPTAB32(13, 0), + ARRAY_SIZE(lpphy_a0_gain_idx_table), lpphy_a0_gain_idx_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0), + ARRAY_SIZE(lpphy_a0_aux_gain_idx_table), lpphy_a0_aux_gain_idx_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(17, 0), + ARRAY_SIZE(lpphy_a0_gain_value_table), lpphy_a0_gain_value_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(18, 0), + ARRAY_SIZE(lpphy_a0_gain_table), lpphy_a0_gain_table); + } +} + + +static void lpphy_rev0_1_write_gain_table(struct b43_wldev *dev, + struct lpphy_tx_gain_table_entry *table) +{ + int i; + u32 tmp; + + B43_WARN_ON(dev->phy.rev >= 2); + + for (i = 0; i < 128; i++) { + tmp = table[i].pad << 11; + tmp |= table[i].pga << 7; + tmp |= table[i].gm << 4; + tmp |= table[i].dac; + b43_lptab_write(dev, B43_LPTAB32(10, 0xC0 + i), tmp); + tmp = table[i].bb_mult << 20; + b43_lptab_write(dev, B43_LPTAB32(10, 0x140 + i), tmp); + } +} + +static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, + struct lpphy_tx_gain_table_entry *table) +{ + int i; + u32 tmp; + + B43_WARN_ON(dev->phy.rev < 2); + + for (i = 0; i < 128; i++) { + tmp = table[i].pad << 16; + tmp |= table[i].pga << 8; + tmp |= table[i].gm; + tmp |= 0x7f000000; + b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + i), tmp); + tmp = table[i].bb_mult << 20; + tmp |= table[i].dac << 28; + b43_lptab_write(dev, B43_LPTAB32(7, 0x140 + i), tmp); + } +} + +void lpphy_init_tx_gain_table(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + + switch (dev->phy.rev) { + case 0: + if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || + (bus->sprom.boardflags_lo & B43_BFL_HGPA)) + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev0_nopa_tx_gain_table); + else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev0_2ghz_tx_gain_table); + else + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev0_5ghz_tx_gain_table); + break; + case 1: + if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || + (bus->sprom.boardflags_lo & B43_BFL_HGPA)) + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev1_nopa_tx_gain_table); + else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev1_2ghz_tx_gain_table); + else + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev1_5ghz_tx_gain_table); + break; + default: + if (bus->sprom.boardflags_hi & B43_BFH_NOPA) + lpphy_rev2plus_write_gain_table(dev, + lpphy_rev2_nopa_tx_gain_table); + else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + lpphy_rev2plus_write_gain_table(dev, + lpphy_rev2_2ghz_tx_gain_table); + else + lpphy_rev2plus_write_gain_table(dev, + lpphy_rev2_5ghz_tx_gain_table); + } +} diff --git a/drivers/net/wireless/b43/tables_lpphy.h b/drivers/net/wireless/b43/tables_lpphy.h index 52ce32f..b5024b6 100644 --- a/drivers/net/wireless/b43/tables_lpphy.h +++ b/drivers/net/wireless/b43/tables_lpphy.h @@ -28,5 +28,8 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, void b2062_upload_init_table(struct b43_wldev *dev); void b2063_upload_init_table(struct b43_wldev *dev); +void lpphy_rev0_1_table_init(struct b43_wldev *dev); +void lpphy_rev2plus_table_init(struct b43_wldev *dev); +void lpphy_init_tx_gain_table(struct b43_wldev *dev); #endif /* B43_TABLES_LPPHY_H_ */ -- cgit v0.10.2 From a3e14f3d2a55fa1268f64ec8a839b6dfa4ff9ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Mon, 10 Aug 2009 20:57:06 +0200 Subject: b43: Update LP-PHY rev2+ baseband init to match the specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rev2+ BB init spec has changed behind us, and thus the code is no longer up to date. Update the code to match the current specs. Also implement save/restore dig filt state, as required by the new specification. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 79039c3..6b19894 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -195,6 +195,56 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) } } +static void lpphy_save_dig_flt_state(struct b43_wldev *dev) +{ + static const u16 addr[] = { + B43_PHY_OFDM(0xC1), + B43_PHY_OFDM(0xC2), + B43_PHY_OFDM(0xC3), + B43_PHY_OFDM(0xC4), + B43_PHY_OFDM(0xC5), + B43_PHY_OFDM(0xC6), + B43_PHY_OFDM(0xC7), + B43_PHY_OFDM(0xC8), + B43_PHY_OFDM(0xCF), + }; + + static const u16 coefs[] = { + 0xDE5E, 0xE832, 0xE331, 0x4D26, + 0x0026, 0x1420, 0x0020, 0xFE08, + 0x0008, + }; + + struct b43_phy_lp *lpphy = dev->phy.lp; + int i; + + for (i = 0; i < ARRAY_SIZE(addr); i++) { + lpphy->dig_flt_state[i] = b43_phy_read(dev, addr[i]); + b43_phy_write(dev, addr[i], coefs[i]); + } +} + +static void lpphy_restore_dig_flt_state(struct b43_wldev *dev) +{ + static const u16 addr[] = { + B43_PHY_OFDM(0xC1), + B43_PHY_OFDM(0xC2), + B43_PHY_OFDM(0xC3), + B43_PHY_OFDM(0xC4), + B43_PHY_OFDM(0xC5), + B43_PHY_OFDM(0xC6), + B43_PHY_OFDM(0xC7), + B43_PHY_OFDM(0xC8), + B43_PHY_OFDM(0xCF), + }; + + struct b43_phy_lp *lpphy = dev->phy.lp; + int i; + + for (i = 0; i < ARRAY_SIZE(addr); i++) + b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]); +} + static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; @@ -209,7 +259,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_OFDM(0xF9), 0); b43_phy_write(dev, B43_LPPHY_TR_LOOKUP_1, 0); b43_phy_set(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x10); - b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x78); + b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0xB4); b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xF8FF, 0x200); b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xFF00, 0x7F); b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFF0F, 0x40); @@ -217,7 +267,12 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x4000); b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x2000); b43_phy_set(dev, B43_PHY_OFDM(0x10A), 0x1); - b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10); + if (bus->boardinfo.rev >= 0x18) { + b43_lptab_write(dev, B43_LPTAB32(17, 65), 0xEC); + b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x14); + } else { + b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10); + } b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0xFF00, 0xF4); b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0x00FF, 0xF100); b43_phy_write(dev, B43_LPPHY_CLIPTHRESH, 0x48); @@ -247,8 +302,10 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12); b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000); - b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0); - b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40); + if ((bus->chip_id == 0x4325) && (bus->chip_rev == 1)) { + b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0); + b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40); + } if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x40); @@ -268,6 +325,14 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0x2000 | ((u16)lpphy->rssi_gs << 10) | ((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf); + + if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { + b43_phy_set(dev, B43_LPPHY_AFE_ADC_CTL_0, 0x1C); + b43_phy_maskset(dev, B43_LPPHY_AFE_CTL, 0x00FF, 0x8800); + b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_1, 0xFC3C, 0x0400); + } + + lpphy_save_dig_flt_state(dev); } static void lpphy_baseband_init(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 829b2bb..13d89ea 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -865,6 +865,9 @@ struct b43_phy_lp { /* Transmit iqlocal best coeffs */ bool tx_iqloc_best_coeffs_valid; u8 tx_iqloc_best_coeffs[11]; + + /* Used for "Save/Restore Dig Filt State" */ + u16 dig_flt_state[9]; }; -- cgit v0.10.2 From fe58343461def0d376908a80cebd087b746a1483 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:46 -0700 Subject: mac80211: Improve dequeing from mpath frame queue. Also, fix typo in comment. Signed-off-by: Javier Cardona Tested-by: Andrey Yurovsky Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index ce53881..6aaf1ec 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -61,7 +61,7 @@ enum mesh_path_flags { * retry * @discovery_retries: number of discovery retries * @flags: mesh path flags, as specified on &enum mesh_path_flags - * @state_lock: mesh pat state lock + * @state_lock: mesh path state lock * * * The combination of dst and sdata is unique in the mesh path table. Since the diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index e1a763e..b54c21c 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -810,10 +810,8 @@ int mesh_nexthop_lookup(struct sk_buff *skb, } if (skb_queue_len(&mpath->frame_queue) >= - MESH_FRAME_QUEUE_LEN) { - skb_to_free = mpath->frame_queue.next; - skb_unlink(skb_to_free, &mpath->frame_queue); - } + MESH_FRAME_QUEUE_LEN) + skb_to_free = skb_dequeue(&mpath->frame_queue); info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; skb_queue_tail(&mpath->frame_queue, skb); -- cgit v0.10.2 From a9e3091bf08ddea35f172549a8a21d5bd6ee6129 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Mon, 10 Aug 2009 12:15:47 -0700 Subject: mac80211: Use correct sign for mesh active path refresh. On locally originated traffic, we refresh active paths after a timeout. The decision to do this was using the wrong sign and therefore the refresh timer was triggered for every frame. Signed-off-by: Andrey Yurovsky Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index b54c21c..1cd1e727 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -791,7 +791,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, } if (mpath->flags & MESH_PATH_ACTIVE) { - if (time_after(jiffies, mpath->exp_time - + if (time_after(jiffies, mpath->exp_time + msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) && !memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) -- cgit v0.10.2 From 3c5772a5279de9eadfff7adb5ddea08106495fff Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:48 -0700 Subject: mac80211: Use 3-address format for mesh broadcast frames. The 11s task group recently changed the frame mesh multicast/broadcast frame format to use 3-address. This was done to avoid interactions with widely deployed lazy-WDS access points. This patch changes the format of group addressed frames, both mesh-originated and proxied, to use the data format defined in draft D2.08 and forward. The address fields used for group addressed frames is: In 802.11 header ToDS:0 FromDS:1 addr1: DA (broadcast/multicast address) addr2: TA addr3: Mesh SA In address extension header: addr4: SA (only present if frame was proxied) Note that this change breaks backward compatibility with earlier mesh stack versions. Signed-off-by: Andrey Yurovsky Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 8c068e2..10d9338 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -399,21 +399,75 @@ endgrow: } /** + * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame + * @hdr: 802.11 frame header + * @fc: frame control field + * @meshda: destination address in the mesh + * @meshsa: source address address in the mesh. Same as TA, as frame is + * locally originated. + * + * Return the length of the 802.11 (does not include a mesh control header) + */ +int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char + *meshda, char *meshsa) { + if (is_multicast_ether_addr(meshda)) { + *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); + /* DA TA SA */ + memcpy(hdr->addr1, meshda, ETH_ALEN); + memcpy(hdr->addr2, meshsa, ETH_ALEN); + memcpy(hdr->addr3, meshsa, ETH_ALEN); + return 24; + } else { + *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | + IEEE80211_FCTL_TODS); + /* RA TA DA SA */ + memset(hdr->addr1, 0, ETH_ALEN); /* RA is resolved later */ + memcpy(hdr->addr2, meshsa, ETH_ALEN); + memcpy(hdr->addr3, meshda, ETH_ALEN); + memcpy(hdr->addr4, meshsa, ETH_ALEN); + return 30; + } +} + +/** * ieee80211_new_mesh_header - create a new mesh header * @meshhdr: uninitialized mesh header * @sdata: mesh interface to be used + * @addr4: addr4 of the mesh frame (1st in ae header) + * may be NULL + * @addr5: addr5 of the mesh frame (1st or 2nd in ae header) + * may be NULL unless addr6 is present + * @addr6: addr6 of the mesh frame (2nd or 3rd in ae header) + * may be NULL unless addr5 is present * * Return the header length. */ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata, char *addr4, + char *addr5, char *addr6) { - meshhdr->flags = 0; + int aelen = 0; + memset(meshhdr, 0, sizeof(meshhdr)); meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); sdata->u.mesh.mesh_seqnum++; - - return 6; + if (addr4) { + meshhdr->flags |= MESH_FLAGS_AE_A4; + aelen += ETH_ALEN; + memcpy(meshhdr->eaddr1, addr4, ETH_ALEN); + } + if (addr5 && addr6) { + meshhdr->flags |= MESH_FLAGS_AE_A5_A6; + aelen += 2 * ETH_ALEN; + if (!addr4) { + memcpy(meshhdr->eaddr1, addr5, ETH_ALEN); + memcpy(meshhdr->eaddr2, addr6, ETH_ALEN); + } else { + memcpy(meshhdr->eaddr2, addr5, ETH_ALEN); + memcpy(meshhdr->eaddr3, addr6, ETH_ALEN); + } + } + return 6 + aelen; } static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 6aaf1ec..2ebd74c 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -193,8 +193,11 @@ struct mesh_rmc { /* Public interfaces */ /* Various */ +int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, + char *da, char *sa); int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, - struct ieee80211_sub_if_data *sdata); + struct ieee80211_sub_if_data *sdata, char *addr4, + char *addr5, char *addr6); int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, struct ieee80211_sub_if_data *sdata); bool mesh_matches_local(struct ieee802_11_elems *ie, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 25a669c..4cd9e45 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -489,12 +489,21 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); + char *dev_addr = rx->dev->dev_addr; if (ieee80211_is_data(hdr->frame_control)) { - if (!ieee80211_has_a4(hdr->frame_control)) - return RX_DROP_MONITOR; - if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0) - return RX_DROP_MONITOR; + if (is_multicast_ether_addr(hdr->addr1)) { + if (ieee80211_has_tods(hdr->frame_control) || + !ieee80211_has_fromds(hdr->frame_control)) + return RX_DROP_MONITOR; + if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0) + return RX_DROP_MONITOR; + } else { + if (!ieee80211_has_a4(hdr->frame_control)) + return RX_DROP_MONITOR; + if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0) + return RX_DROP_MONITOR; + } } /* If there is not an established peer link and this is not a peer link @@ -527,7 +536,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) if (ieee80211_is_data(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1) && - mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->sdata)) + mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata)) return RX_DROP_MONITOR; #undef msh_h_get @@ -1495,7 +1504,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) /* illegal frame */ return RX_DROP_MONITOR; - if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){ + if (!is_multicast_ether_addr(hdr->addr1) && + (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6)) { struct mesh_path *mppath; rcu_read_lock(); @@ -1512,7 +1522,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) rcu_read_unlock(); } - if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) + /* Frame has reached destination. Don't forward */ + if (!is_multicast_ether_addr(hdr->addr1) && + compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) return RX_CONTINUE; mesh_hdr->ttl--; @@ -1532,22 +1544,21 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) rx->dev->name); fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; - /* - * Save TA to addr1 to send TA a path error if a - * suitable next hop is not found - */ - memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN); memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN); info = IEEE80211_SKB_CB(fwd_skb); memset(info, 0, sizeof(*info)); info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->control.vif = &rx->sdata->vif; ieee80211_select_queue(local, fwd_skb); - if (is_multicast_ether_addr(fwd_hdr->addr3)) - memcpy(fwd_hdr->addr1, fwd_hdr->addr3, + if (!is_multicast_ether_addr(fwd_hdr->addr1)) { + int err; + /* + * Save TA to addr1 to send TA a path error if a + * suitable next hop is not found + */ + memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN); - else { - int err = mesh_nexthop_lookup(fwd_skb, sdata); + err = mesh_nexthop_lookup(fwd_skb, sdata); /* Failed to immediately resolve next hop: * fwded frame was dropped or will be added * later to the pending skb queue. */ @@ -1560,7 +1571,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) } } - if (is_multicast_ether_addr(hdr->addr3) || + if (is_multicast_ether_addr(hdr->addr1) || rx->dev->flags & IFF_PROMISC) return RX_CONTINUE; else diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3244298..ee8aa76 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1414,9 +1414,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, if (ieee80211_vif_is_mesh(&sdata->vif) && ieee80211_is_data(hdr->frame_control)) { - if (is_multicast_ether_addr(hdr->addr3)) - memcpy(hdr->addr1, hdr->addr3, ETH_ALEN); - else + if (!is_multicast_ether_addr(hdr->addr1)) if (mesh_nexthop_lookup(skb, sdata)) { dev_put(sdata->dev); return; @@ -1619,52 +1617,58 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, break; #ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: - fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { /* Do not send frames with mesh_ttl == 0 */ sdata->u.mesh.mshstats.dropped_frames_ttl++; ret = NETDEV_TX_OK; goto fail; } - memset(&mesh_hdr, 0, sizeof(mesh_hdr)); if (compare_ether_addr(dev->dev_addr, skb->data + ETH_ALEN) == 0) { - /* RA TA DA SA */ - memset(hdr.addr1, 0, ETH_ALEN); - memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); - memcpy(hdr.addr3, skb->data, ETH_ALEN); - memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); - meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata); + hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, + skb->data, skb->data + ETH_ALEN); + meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, + sdata, NULL, NULL, NULL); } else { /* packet from other interface */ struct mesh_path *mppath; + int is_mesh_mcast = 1; + char *mesh_da; - memset(hdr.addr1, 0, ETH_ALEN); - memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); - memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN); - + rcu_read_lock(); if (is_multicast_ether_addr(skb->data)) - memcpy(hdr.addr3, skb->data, ETH_ALEN); + /* DA TA mSA AE:SA */ + mesh_da = skb->data; else { - rcu_read_lock(); mppath = mpp_path_lookup(skb->data, sdata); - if (mppath) - memcpy(hdr.addr3, mppath->mpp, ETH_ALEN); - else - memset(hdr.addr3, 0xff, ETH_ALEN); - rcu_read_unlock(); + if (mppath) { + /* RA TA mDA mSA AE:DA SA */ + mesh_da = mppath->mpp; + is_mesh_mcast = 0; + } else + /* DA TA mSA AE:SA */ + mesh_da = dev->broadcast; } + hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, + mesh_da, dev->dev_addr); + rcu_read_unlock(); + if (is_mesh_mcast) + meshhdrlen = + ieee80211_new_mesh_header(&mesh_hdr, + sdata, + skb->data + ETH_ALEN, + NULL, + NULL); + else + meshhdrlen = + ieee80211_new_mesh_header(&mesh_hdr, + sdata, + NULL, + skb->data, + skb->data + ETH_ALEN); - mesh_hdr.flags |= MESH_FLAGS_AE_A5_A6; - mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; - put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum); - memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN); - memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN); - sdata->u.mesh.mesh_seqnum++; - meshhdrlen = 18; } - hdrlen = 30; break; #endif case NL80211_IFTYPE_STATION: diff --git a/net/wireless/util.c b/net/wireless/util.c index ba387d8..693275a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -274,11 +274,11 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) switch (ae) { case 0: return 6; - case 1: + case MESH_FLAGS_AE_A4: return 12; - case 2: + case MESH_FLAGS_AE_A5_A6: return 18; - case 3: + case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6): return 24; default: return 6; @@ -333,10 +333,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, } break; case cpu_to_le16(IEEE80211_FCTL_FROMDS): - if (iftype != NL80211_IFTYPE_STATION || + if ((iftype != NL80211_IFTYPE_STATION && + iftype != NL80211_IFTYPE_MESH_POINT) || (is_multicast_ether_addr(dst) && !compare_ether_addr(src, addr))) return -1; + if (iftype == NL80211_IFTYPE_MESH_POINT) { + struct ieee80211s_hdr *meshdr = + (struct ieee80211s_hdr *) (skb->data + hdrlen); + hdrlen += ieee80211_get_mesh_hdrlen(meshdr); + if (meshdr->flags & MESH_FLAGS_AE_A4) + memcpy(src, meshdr->eaddr1, ETH_ALEN); + } break; case cpu_to_le16(0): if (iftype != NL80211_IFTYPE_ADHOC) -- cgit v0.10.2 From d403a1c66ea1fb47ae61921eac278d4154f7ca8a Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:49 -0700 Subject: mac80211: Update the station failed frames average when minstrel is used. The fail_avg value is used to compute the mesh metric, and was only being set by the pid rate control module. This fixes the mesh path selection mechanism for cards that use mistrel for rate control. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 7c51429..3ea9740 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -155,12 +155,16 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, struct sk_buff *skb) { struct minstrel_sta_info *mi = priv_sta; + struct minstrel_priv *mp = (struct minstrel_priv *)priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *ar = info->status.rates; + struct ieee80211_local *local = hw_to_local(mp->hw); + struct sta_info *si; int i, ndx; int success; success = !!(info->flags & IEEE80211_TX_STAT_ACK); + si = sta_info_get(local, sta->addr); for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { if (ar[i].idx < 0) @@ -172,8 +176,12 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, mi->r[ndx].attempts += ar[i].count; - if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) + if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) { mi->r[ndx].success += success; + if (si) + si->fail_avg = (18050 - mi->r[ndx].probability) + / 180; + } } if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) -- cgit v0.10.2 From 5815814bfad5b3f88ff58ab90aaf09dd69ab8da2 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:50 -0700 Subject: mac80211: Early detection of broken mesh paths when using minstrel. This change triggers a path discovery as soon as the link quality degrades below a certain threshold. This results in a faster path recovery time than by simply relying on the periodic path refresh mechanism to detect broken links. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 3ea9740..0071649 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -51,6 +51,7 @@ #include #include #include +#include "mesh.h" #include "rate.h" #include "rc80211_minstrel.h" @@ -178,9 +179,14 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) { mi->r[ndx].success += success; - if (si) + if (si) { si->fail_avg = (18050 - mi->r[ndx].probability) / 180; + WARN_ON(si->fail_avg > 100); + if (si->fail_avg == 100 && + ieee80211_vif_is_mesh(&si->sdata->vif)) + mesh_plink_broken(si); + } } } -- cgit v0.10.2 From 5b365834255d7c90fc724b032c814dfa297aacf9 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:51 -0700 Subject: mac80211: Assign a default mesh beaconing interval. The mesh stack was enabling beaconing without specifying an interval. This patch defines a default beaconing interval of 1s. Incidentally, this fixes mesh beaconing in mac80211_hwsim devices. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 10d9338..25d0065 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -525,9 +525,11 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; ifmsh->housekeeping = true; - ieee80211_queue_work(&local->hw, &ifmsh->work); + queue_work(local->hw, &ifmsh->work); + sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | - BSS_CHANGED_BEACON_ENABLED); + BSS_CHANGED_BEACON_ENABLED | + BSS_CHANGED_BEACON_INT); } void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2ebd74c..4241925 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -174,6 +174,7 @@ struct mesh_rmc { */ #define MESH_PATH_REFRESH_TIME 1000 #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) +#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ #define MESH_MAX_PREQ_RETRIES 4 #define MESH_PATH_EXPIRE (600 * HZ) -- cgit v0.10.2 From 18889231e4527dfe23145efe318e74744794a95d Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:52 -0700 Subject: mac80211: Move mpath and mpp growth to mesh workqueue. This prevents calling rcu_synchronize from within the tx path by moving the table growth code to the mesh workqueue. Move mesh_table_free and mesh_table_grow from mesh.c to mesh_pathtbl.c and declare them static. Also, re-enable mesh in Kconfig and update the configuration description. Signed-off-by: Javier Cardona Tested-by: Andrey Yurovsky Signed-off-by: John W. Linville diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 7dd77b6..9db4ff8 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -66,12 +66,12 @@ endmenu config MAC80211_MESH bool "Enable mac80211 mesh networking (pre-802.11s) support" depends on MAC80211 && EXPERIMENTAL - depends on BROKEN ---help--- This options enables support of Draft 802.11s mesh networking. - The implementation is based on Draft 1.08 of the Mesh Networking - amendment. For more information visit http://o11s.org/. - + The implementation is based on Draft 2.08 of the Mesh Networking + amendment. However, no compliance with that draft is claimed or even + possible, as drafts leave a number of identifiers to be defined after + ratification. For more information visit http://o11s.org/. config MAC80211_LEDS bool "Enable LED triggers" diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d6bd7dd..a6abc7d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -355,7 +355,7 @@ struct ieee80211_if_mesh { unsigned long timers_running; - bool housekeeping; + unsigned long wrkq_flags; u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; size_t mesh_id_len; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 25d0065..3185e18 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -47,7 +47,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - ifmsh->housekeeping = true; + ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; if (local->quiescing) { set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); @@ -320,30 +320,6 @@ struct mesh_table *mesh_table_alloc(int size_order) return newtbl; } -static void __mesh_table_free(struct mesh_table *tbl) -{ - kfree(tbl->hash_buckets); - kfree(tbl->hashwlock); - kfree(tbl); -} - -void mesh_table_free(struct mesh_table *tbl, bool free_leafs) -{ - struct hlist_head *mesh_hash; - struct hlist_node *p, *q; - int i; - - mesh_hash = tbl->hash_buckets; - for (i = 0; i <= tbl->hash_mask; i++) { - spin_lock(&tbl->hashwlock[i]); - hlist_for_each_safe(p, q, &mesh_hash[i]) { - tbl->free_node(p, free_leafs); - atomic_dec(&tbl->entries); - } - spin_unlock(&tbl->hashwlock[i]); - } - __mesh_table_free(tbl); -} static void ieee80211_mesh_path_timer(unsigned long data) { @@ -360,44 +336,6 @@ static void ieee80211_mesh_path_timer(unsigned long data) ieee80211_queue_work(&local->hw, &ifmsh->work); } -struct mesh_table *mesh_table_grow(struct mesh_table *tbl) -{ - struct mesh_table *newtbl; - struct hlist_head *oldhash; - struct hlist_node *p, *q; - int i; - - if (atomic_read(&tbl->entries) - < tbl->mean_chain_len * (tbl->hash_mask + 1)) - goto endgrow; - - newtbl = mesh_table_alloc(tbl->size_order + 1); - if (!newtbl) - goto endgrow; - - newtbl->free_node = tbl->free_node; - newtbl->mean_chain_len = tbl->mean_chain_len; - newtbl->copy_node = tbl->copy_node; - atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); - - oldhash = tbl->hash_buckets; - for (i = 0; i <= tbl->hash_mask; i++) - hlist_for_each(p, &oldhash[i]) - if (tbl->copy_node(p, newtbl) < 0) - goto errcopy; - - return newtbl; - -errcopy: - for (i = 0; i <= newtbl->hash_mask; i++) { - hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) - tbl->free_node(p, 0); - } - __mesh_table_free(newtbl); -endgrow: - return NULL; -} - /** * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame * @hdr: 802.11 frame header @@ -487,7 +425,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, if (free_plinks != sdata->u.mesh.accepting_plinks) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); - ifmsh->housekeeping = false; mod_timer(&ifmsh->housekeeping_timer, round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); } @@ -524,8 +461,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; - ifmsh->housekeeping = true; - queue_work(local->hw, &ifmsh->work); + ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; + ieee80211_queue_work(&local->hw, &ifmsh->work); sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | @@ -664,7 +601,13 @@ static void ieee80211_mesh_work(struct work_struct *work) ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) mesh_path_start_discovery(sdata); - if (ifmsh->housekeeping) + if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags)) + mesh_mpath_table_grow(); + + if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags)) + mesh_mpp_table_grow(); + + if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) ieee80211_mesh_housekeeping(sdata, ifmsh); } diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 4241925..eb23fc6 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -44,6 +44,23 @@ enum mesh_path_flags { }; /** + * enum mesh_deferred_task_flags - mac80211 mesh deferred tasks + * + * + * + * @MESH_WORK_HOUSEKEEPING: run the periodic mesh housekeeping tasks + * @MESH_WORK_GROW_MPATH_TABLE: the mesh path table is full and needs + * to grow. + * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to + * grow + */ +enum mesh_deferred_task_flags { + MESH_WORK_HOUSEKEEPING, + MESH_WORK_GROW_MPATH_TABLE, + MESH_WORK_GROW_MPP_TABLE, +}; + +/** * struct mesh_path - mac80211 mesh path structure * * @dst: mesh path destination mac address @@ -250,7 +267,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, /* Mesh tables */ struct mesh_table *mesh_table_alloc(int size_order); void mesh_table_free(struct mesh_table *tbl, bool free_leafs); -struct mesh_table *mesh_table_grow(struct mesh_table *tbl); +void mesh_mpath_table_grow(void); +void mesh_mpp_table_grow(void); u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl); /* Mesh paths */ diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 431865a..751c4d0 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -39,6 +39,69 @@ static struct mesh_table *mesh_paths; static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ int mesh_paths_generation; +static void __mesh_table_free(struct mesh_table *tbl) +{ + kfree(tbl->hash_buckets); + kfree(tbl->hashwlock); + kfree(tbl); +} + +void mesh_table_free(struct mesh_table *tbl, bool free_leafs) +{ + struct hlist_head *mesh_hash; + struct hlist_node *p, *q; + int i; + + mesh_hash = tbl->hash_buckets; + for (i = 0; i <= tbl->hash_mask; i++) { + spin_lock(&tbl->hashwlock[i]); + hlist_for_each_safe(p, q, &mesh_hash[i]) { + tbl->free_node(p, free_leafs); + atomic_dec(&tbl->entries); + } + spin_unlock(&tbl->hashwlock[i]); + } + __mesh_table_free(tbl); +} + +static struct mesh_table *mesh_table_grow(struct mesh_table *tbl) +{ + struct mesh_table *newtbl; + struct hlist_head *oldhash; + struct hlist_node *p, *q; + int i; + + if (atomic_read(&tbl->entries) + < tbl->mean_chain_len * (tbl->hash_mask + 1)) + goto endgrow; + + newtbl = mesh_table_alloc(tbl->size_order + 1); + if (!newtbl) + goto endgrow; + + newtbl->free_node = tbl->free_node; + newtbl->mean_chain_len = tbl->mean_chain_len; + newtbl->copy_node = tbl->copy_node; + atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); + + oldhash = tbl->hash_buckets; + for (i = 0; i <= tbl->hash_mask; i++) + hlist_for_each(p, &oldhash[i]) + if (tbl->copy_node(p, newtbl) < 0) + goto errcopy; + + return newtbl; + +errcopy: + for (i = 0; i <= newtbl->hash_mask; i++) { + hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) + tbl->free_node(p, 0); + } + __mesh_table_free(newtbl); +endgrow: + return NULL; +} + /* This lock will have the grow table function as writer and add / delete nodes * as readers. When reading the table (i.e. doing lookups) we are well protected @@ -187,6 +250,8 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data */ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + struct ieee80211_local *local = sdata->local; struct mesh_path *mpath, *new_mpath; struct mpath_node *node, *new_node; struct hlist_head *bucket; @@ -195,8 +260,6 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; - might_sleep(); - if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -208,11 +271,11 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) return -ENOSPC; err = -ENOMEM; - new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); + new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); if (!new_mpath) goto err_path_alloc; - new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); + new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); if (!new_node) goto err_node_alloc; @@ -250,20 +313,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) spin_unlock(&mesh_paths->hashwlock[hash_idx]); read_unlock(&pathtbl_resize_lock); if (grow) { - struct mesh_table *oldtbl, *newtbl; - - write_lock(&pathtbl_resize_lock); - oldtbl = mesh_paths; - newtbl = mesh_table_grow(mesh_paths); - if (!newtbl) { - write_unlock(&pathtbl_resize_lock); - return 0; - } - rcu_assign_pointer(mesh_paths, newtbl); - write_unlock(&pathtbl_resize_lock); - - synchronize_rcu(); - mesh_table_free(oldtbl, false); + set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); + ieee80211_queue_work(&local->hw, &ifmsh->work); } return 0; @@ -278,9 +329,46 @@ err_path_alloc: return err; } +void mesh_mpath_table_grow(void) +{ + struct mesh_table *oldtbl, *newtbl; + + write_lock(&pathtbl_resize_lock); + oldtbl = mesh_paths; + newtbl = mesh_table_grow(mesh_paths); + if (!newtbl) { + write_unlock(&pathtbl_resize_lock); + return; + } + rcu_assign_pointer(mesh_paths, newtbl); + write_unlock(&pathtbl_resize_lock); + + synchronize_rcu(); + mesh_table_free(oldtbl, false); +} + +void mesh_mpp_table_grow(void) +{ + struct mesh_table *oldtbl, *newtbl; + + write_lock(&pathtbl_resize_lock); + oldtbl = mpp_paths; + newtbl = mesh_table_grow(mpp_paths); + if (!newtbl) { + write_unlock(&pathtbl_resize_lock); + return; + } + rcu_assign_pointer(mpp_paths, newtbl); + write_unlock(&pathtbl_resize_lock); + + synchronize_rcu(); + mesh_table_free(oldtbl, false); +} int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + struct ieee80211_local *local = sdata->local; struct mesh_path *mpath, *new_mpath; struct mpath_node *node, *new_node; struct hlist_head *bucket; @@ -289,8 +377,6 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; - might_sleep(); - if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -299,11 +385,11 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) return -ENOTSUPP; err = -ENOMEM; - new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); + new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); if (!new_mpath) goto err_path_alloc; - new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); + new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); if (!new_node) goto err_node_alloc; @@ -337,20 +423,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) spin_unlock(&mpp_paths->hashwlock[hash_idx]); read_unlock(&pathtbl_resize_lock); if (grow) { - struct mesh_table *oldtbl, *newtbl; - - write_lock(&pathtbl_resize_lock); - oldtbl = mpp_paths; - newtbl = mesh_table_grow(mpp_paths); - if (!newtbl) { - write_unlock(&pathtbl_resize_lock); - return 0; - } - rcu_assign_pointer(mpp_paths, newtbl); - write_unlock(&pathtbl_resize_lock); - - synchronize_rcu(); - mesh_table_free(oldtbl, false); + set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); + ieee80211_queue_work(&local->hw, &ifmsh->work); } return 0; -- cgit v0.10.2 From f679056b2fdd4e9b7c8eb42ba447cd9646236305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Mon, 10 Aug 2009 21:23:08 +0200 Subject: ssb: Implement the remaining rev.8 SPROM vars needed for LP-PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also add a "SPEX32" macro for extracting 32-bit SPROM variables. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 40ea417..593fc61 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -169,8 +169,14 @@ err_pci: /* Get the word-offset for a SSB_SPROM_XXX define. */ #define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16)) /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */ -#define SPEX(_outvar, _offset, _mask, _shift) \ +#define SPEX16(_outvar, _offset, _mask, _shift) \ out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) +#define SPEX32(_outvar, _offset, _mask, _shift) \ + out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \ + in[SPOFF(_offset)]) & (_mask)) >> (_shift)) +#define SPEX(_outvar, _offset, _mask, _shift) \ + SPEX16(_outvar, _offset, _mask, _shift) + static inline u8 ssb_crc8(u8 crc, u8 data) { @@ -480,6 +486,8 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0); SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); + SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); + SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0); SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, SSB_SPROM8_ANTAVAIL_A_SHIFT); SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, @@ -490,12 +498,55 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, SSB_SPROM8_ITSSI_A_SHIFT); + SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); + SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, + SSB_SPROM8_MAXP_AL_SHIFT); SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, SSB_SPROM8_GPIOA_P1_SHIFT); SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, SSB_SPROM8_GPIOB_P3_SHIFT); + SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); + SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, + SSB_SPROM8_TRI5G_SHIFT); + SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); + SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, + SSB_SPROM8_TRI5GH_SHIFT); + SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0); + SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, + SSB_SPROM8_RXPO5G_SHIFT); + SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); + SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, + SSB_SPROM8_RSSISMC2G_SHIFT); + SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, + SSB_SPROM8_RSSISAV2G_SHIFT); + SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, + SSB_SPROM8_BXA2G_SHIFT); + SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); + SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, + SSB_SPROM8_RSSISMC5G_SHIFT); + SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, + SSB_SPROM8_RSSISAV5G_SHIFT); + SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, + SSB_SPROM8_BXA5G_SHIFT); + SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0); + SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0); + SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0); + SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0); + SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0); + SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0); + SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0); + SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0); + SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0); + SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0); + SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0); + SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0); + SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0); + SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0); + SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0); + SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0); + SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0); /* Extract the antenna gain values. */ SPEX(antenna_gain.ghz24.a0, SSB_SPROM8_AGAIN01, diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 5ae8fa2..17ffc1f 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -27,24 +27,54 @@ struct ssb_sprom { u8 et1mdcport; /* MDIO for enet1 */ u8 board_rev; /* Board revision number from SPROM. */ u8 country_code; /* Country Code */ - u8 ant_available_a; /* A-PHY antenna available bits (up to 4) */ - u8 ant_available_bg; /* B/G-PHY antenna available bits (up to 4) */ + u8 ant_available_a; /* 2GHz antenna available bits (up to 4) */ + u8 ant_available_bg; /* 5GHz antenna available bits (up to 4) */ u16 pa0b0; u16 pa0b1; u16 pa0b2; u16 pa1b0; u16 pa1b1; u16 pa1b2; + u16 pa1lob0; + u16 pa1lob1; + u16 pa1lob2; + u16 pa1hib0; + u16 pa1hib1; + u16 pa1hib2; u8 gpio0; /* GPIO pin 0 */ u8 gpio1; /* GPIO pin 1 */ u8 gpio2; /* GPIO pin 2 */ u8 gpio3; /* GPIO pin 3 */ - u16 maxpwr_a; /* A-PHY Amplifier Max Power (in dBm Q5.2) */ - u16 maxpwr_bg; /* B/G-PHY Amplifier Max Power (in dBm Q5.2) */ + u16 maxpwr_bg; /* 2.4GHz Amplifier Max Power (in dBm Q5.2) */ + u16 maxpwr_al; /* 5.2GHz Amplifier Max Power (in dBm Q5.2) */ + u16 maxpwr_a; /* 5.3GHz Amplifier Max Power (in dBm Q5.2) */ + u16 maxpwr_ah; /* 5.8GHz Amplifier Max Power (in dBm Q5.2) */ u8 itssi_a; /* Idle TSSI Target for A-PHY */ u8 itssi_bg; /* Idle TSSI Target for B/G-PHY */ - u16 boardflags_lo; /* Boardflags (low 16 bits) */ - u16 boardflags_hi; /* Boardflags (high 16 bits) */ + u8 tri2g; /* 2.4GHz TX isolation */ + u8 tri5gl; /* 5.2GHz TX isolation */ + u8 tri5g; /* 5.3GHz TX isolation */ + u8 tri5gh; /* 5.8GHz TX isolation */ + u8 rxpo2g; /* 2GHz RX power offset */ + u8 rxpo5g; /* 5GHz RX power offset */ + u8 rssisav2g; /* 2GHz RSSI params */ + u8 rssismc2g; + u8 rssismf2g; + u8 bxa2g; /* 2GHz BX arch */ + u8 rssisav5g; /* 5GHz RSSI params */ + u8 rssismc5g; + u8 rssismf5g; + u8 bxa5g; /* 5GHz BX arch */ + u16 cck2gpo; /* CCK power offset */ + u32 ofdm2gpo; /* 2.4GHz OFDM power offset */ + u32 ofdm5glpo; /* 5.2GHz OFDM power offset */ + u32 ofdm5gpo; /* 5.3GHz OFDM power offset */ + u32 ofdm5ghpo; /* 5.8GHz OFDM power offset */ + u16 boardflags_lo; /* Board flags (bits 0-15) */ + u16 boardflags_hi; /* Board flags (bits 16-31) */ + u16 boardflags2_lo; /* Board flags (bits 32-47) */ + u16 boardflags2_hi; /* Board flags (bits 48-63) */ + /* TODO store board flags in a single u64 */ /* Antenna gain values for up to 4 antennas * on each band. Values in dBm/4 (Q5.2). Negative gain means the @@ -58,7 +88,7 @@ struct ssb_sprom { } ghz5; /* 5GHz band */ } antenna_gain; - /* TODO - add any parameters needed from rev 2, 3, or 4 SPROMs */ + /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */ }; /* Information about the PCB the circuitry is soldered on. */ diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index a01b982..9ae9082 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -162,7 +162,7 @@ /* SPROM shadow area. If not otherwise noted, fields are * two bytes wide. Note that the SPROM can _only_ be read - * in two-byte quantinies. + * in two-byte quantities. */ #define SSB_SPROMSIZE_WORDS 64 #define SSB_SPROMSIZE_BYTES (SSB_SPROMSIZE_WORDS * sizeof(u16)) @@ -327,8 +327,11 @@ #define SSB_SPROM5_GPIOB_P3_SHIFT 8 /* SPROM Revision 8 */ -#define SSB_SPROM8_BFLLO 0x1084 /* Boardflags (low 16 bits) */ -#define SSB_SPROM8_BFLHI 0x1086 /* Boardflags Hi */ +#define SSB_SPROM8_BOARDREV 0x1082 /* Board revision */ +#define SSB_SPROM8_BFLLO 0x1084 /* Board flags (bits 0-15) */ +#define SSB_SPROM8_BFLHI 0x1086 /* Board flags (bits 16-31) */ +#define SSB_SPROM8_BFL2LO 0x1088 /* Board flags (bits 32-47) */ +#define SSB_SPROM8_BFL2HI 0x108A /* Board flags (bits 48-63) */ #define SSB_SPROM8_IL0MAC 0x108C /* 6 byte MAC address */ #define SSB_SPROM8_CCODE 0x1092 /* 2 byte country code */ #define SSB_SPROM8_ANTAVAIL 0x109C /* Antenna available bitfields*/ @@ -354,14 +357,63 @@ #define SSB_SPROM8_GPIOB_P2 0x00FF /* Pin 2 */ #define SSB_SPROM8_GPIOB_P3 0xFF00 /* Pin 3 */ #define SSB_SPROM8_GPIOB_P3_SHIFT 8 -#define SSB_SPROM8_MAXP_BG 0x10C0 /* Max Power BG in path 1 */ -#define SSB_SPROM8_MAXP_BG_MASK 0x00FF /* Mask for Max Power BG */ +#define SSB_SPROM8_RSSIPARM2G 0x10A4 /* RSSI params for 2GHz */ +#define SSB_SPROM8_RSSISMF2G 0x000F +#define SSB_SPROM8_RSSISMC2G 0x00F0 +#define SSB_SPROM8_RSSISMC2G_SHIFT 4 +#define SSB_SPROM8_RSSISAV2G 0x0700 +#define SSB_SPROM8_RSSISAV2G_SHIFT 8 +#define SSB_SPROM8_BXA2G 0x1800 +#define SSB_SPROM8_BXA2G_SHIFT 11 +#define SSB_SPROM8_RSSIPARM5G 0x10A6 /* RSSI params for 5GHz */ +#define SSB_SPROM8_RSSISMF5G 0x000F +#define SSB_SPROM8_RSSISMC5G 0x00F0 +#define SSB_SPROM8_RSSISMC5G_SHIFT 4 +#define SSB_SPROM8_RSSISAV5G 0x0700 +#define SSB_SPROM8_RSSISAV5G_SHIFT 8 +#define SSB_SPROM8_BXA5G 0x1800 +#define SSB_SPROM8_BXA5G_SHIFT 11 +#define SSB_SPROM8_TRI25G 0x10A8 /* TX isolation 2.4&5.3GHz */ +#define SSB_SPROM8_TRI2G 0x00FF /* TX isolation 2.4GHz */ +#define SSB_SPROM8_TRI5G 0xFF00 /* TX isolation 5.3GHz */ +#define SSB_SPROM8_TRI5G_SHIFT 8 +#define SSB_SPROM8_TRI5GHL 0x10AA /* TX isolation 5.2/5.8GHz */ +#define SSB_SPROM8_TRI5GL 0x00FF /* TX isolation 5.2GHz */ +#define SSB_SPROM8_TRI5GH 0xFF00 /* TX isolation 5.8GHz */ +#define SSB_SPROM8_TRI5GH_SHIFT 8 +#define SSB_SPROM8_RXPO 0x10AC /* RX power offsets */ +#define SSB_SPROM8_RXPO2G 0x00FF /* 2GHz RX power offset */ +#define SSB_SPROM8_RXPO5G 0xFF00 /* 5GHz RX power offset */ +#define SSB_SPROM8_RXPO5G_SHIFT 8 +#define SSB_SPROM8_MAXP_BG 0x10C0 /* Max Power 2GHz in path 1 */ +#define SSB_SPROM8_MAXP_BG_MASK 0x00FF /* Mask for Max Power 2GHz */ #define SSB_SPROM8_ITSSI_BG 0xFF00 /* Mask for path 1 itssi_bg */ #define SSB_SPROM8_ITSSI_BG_SHIFT 8 -#define SSB_SPROM8_MAXP_A 0x10C8 /* Max Power A in path 1 */ -#define SSB_SPROM8_MAXP_A_MASK 0x00FF /* Mask for Max Power A */ +#define SSB_SPROM8_PA0B0 0x10C2 /* 2GHz power amp settings */ +#define SSB_SPROM8_PA0B1 0x10C4 +#define SSB_SPROM8_PA0B2 0x10C6 +#define SSB_SPROM8_MAXP_A 0x10C8 /* Max Power 5.3GHz */ +#define SSB_SPROM8_MAXP_A_MASK 0x00FF /* Mask for Max Power 5.3GHz */ #define SSB_SPROM8_ITSSI_A 0xFF00 /* Mask for path 1 itssi_a */ #define SSB_SPROM8_ITSSI_A_SHIFT 8 +#define SSB_SPROM8_MAXP_AHL 0x10CA /* Max Power 5.2/5.8GHz */ +#define SSB_SPROM8_MAXP_AH_MASK 0x00FF /* Mask for Max Power 5.8GHz */ +#define SSB_SPROM8_MAXP_AL_MASK 0xFF00 /* Mask for Max Power 5.2GHz */ +#define SSB_SPROM8_MAXP_AL_SHIFT 8 +#define SSB_SPROM8_PA1B0 0x10CC /* 5.3GHz power amp settings */ +#define SSB_SPROM8_PA1B1 0x10CE +#define SSB_SPROM8_PA1B2 0x10D0 +#define SSB_SPROM8_PA1LOB0 0x10D2 /* 5.2GHz power amp settings */ +#define SSB_SPROM8_PA1LOB1 0x10D4 +#define SSB_SPROM8_PA1LOB2 0x10D6 +#define SSB_SPROM8_PA1HIB0 0x10D8 /* 5.8GHz power amp settings */ +#define SSB_SPROM8_PA1HIB1 0x10DA +#define SSB_SPROM8_PA1HIB2 0x10DC +#define SSB_SPROM8_CCK2GPO 0x1140 /* CCK power offset */ +#define SSB_SPROM8_OFDM2GPO 0x1142 /* 2.4GHz OFDM power offset */ +#define SSB_SPROM8_OFDM5GPO 0x1146 /* 5.3GHz OFDM power offset */ +#define SSB_SPROM8_OFDM5GLPO 0x114A /* 5.2GHz OFDM power offset */ +#define SSB_SPROM8_OFDM5GHPO 0x114E /* 5.8GHz OFDM power offset */ /* Values for SSB_SPROM1_BINF_CCODE */ enum { -- cgit v0.10.2 From d44517f235c5baa943fc8cac7e56bd291ffc077e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Tue, 11 Aug 2009 00:54:26 +0200 Subject: b43: Fix a typo in the sync_stx routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I completely missed the "one's complement" instruction from the specs. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 6b19894..95e15e6 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -497,7 +497,7 @@ static void lpphy_sync_stx(struct b43_wldev *dev) tmp >>= e->rf_shift; tmp <<= e->phy_shift; b43_phy_maskset(dev, B43_PHY_OFDM(0xF2 + e->phy_offset), - e->mask << e->phy_shift, tmp); + ~(e->mask << e->phy_shift), tmp); } } -- cgit v0.10.2 From 73d0a13c8583cd9a84c1333cf9b45d1d894e52b3 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 11 Aug 2009 11:58:27 +0300 Subject: wl1271: fix compiler warnings on 64 bit archs There were a few warnings when compiling the wl1271 driver on 64 bit architectures. This was due to size mismatch of integers. This commit fixes the following warnings: drivers/net/wireless/wl12xx/wl1271_main.c: In function 'wl1271_irq_work': drivers/net/wireless/wl12xx/wl1271_main.c:184: warning: large integer implicitly truncated to unsigned type drivers/net/wireless/wl12xx/wl1271_boot.c: In function 'wl1271_boot_upload_firmware_chunk': drivers/net/wireless/wl12xx/wl1271_boot.c:103: warning: format '%d' expects type 'int', but argument 2 has type 'size_t' drivers/net/wireless/wl12xx/wl1271_boot.c:150: warning: format '%d' expects type 'int', but argument 2 has type 'size_t' drivers/net/wireless/wl12xx/wl1271_boot.c: In function 'wl1271_boot_enable_interrupts': drivers/net/wireless/wl12xx/wl1271_boot.c:278: warning: large integer implicitly truncated to unsigned type Reported-by: Stephen Rothwell Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index 4c22f25..8228ef4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -100,8 +100,8 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, wl1271_debug(DEBUG_BOOT, "starting firmware upload"); - wl1271_debug(DEBUG_BOOT, "fw_data_len %d chunk_size %d", fw_data_len, - CHUNK_SIZE); + wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d", + fw_data_len, CHUNK_SIZE); if ((fw_data_len % 4) != 0) { @@ -147,7 +147,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, /* 10.4 upload the last chunk */ addr = dest + chunk_num * CHUNK_SIZE; p = buf + chunk_num * CHUNK_SIZE; - wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%d B) 0x%p to 0x%x", + wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); @@ -275,7 +275,8 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) static void wl1271_boot_enable_interrupts(struct wl1271 *wl) { enable_irq(wl->irq); - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(WL1271_INTR_MASK)); + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); } diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 3bb45ce..4102d59 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -181,7 +181,8 @@ static void wl1271_irq_work(struct work_struct *work) } while (intr && --ctr); out_sleep: - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(WL1271_INTR_MASK)); + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); wl1271_ps_elp_sleep(wl); out: -- cgit v0.10.2 From 1fe90b033e04d7402b3deb392420fe2ff57986a5 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Tue, 11 Aug 2009 11:18:42 -0300 Subject: trivial: remove duplicate "different" from comment Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index fc7a484..f256dff 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1424,7 +1424,7 @@ static int ignore_request(struct wiphy *wiphy, if (last_wiphy != wiphy) { /* * Two cards with two APs claiming different - * different Country IE alpha2s. We could + * Country IE alpha2s. We could * intersect them, but that seems unlikely * to be correct. Reject second one for now. */ -- cgit v0.10.2 From cca89496a8afe4ad12ce1e468e60cef1e27e4eee Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 17:29:29 -0700 Subject: mac80211: Fix unresolved mesh frames queued without valid control.vif Mesh frames that could not be immediately resolved were queued with a NULL info->control.vif. This patch moves the call to mesh_nexthop_lookup closer to the point where it is handed over to ieee80211_tx(). This ensures that the unresolved frames are ready to be sent once the path is resolved. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ee8aa76..0c08d1e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1412,14 +1412,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - if (ieee80211_vif_is_mesh(&sdata->vif) && - ieee80211_is_data(hdr->frame_control)) { - if (!is_multicast_ether_addr(hdr->addr1)) - if (mesh_nexthop_lookup(skb, sdata)) { - dev_put(sdata->dev); - return; - } - } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { + if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { int hdrlen; u16 len_rthdr; @@ -1476,6 +1469,15 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, info->control.vif = &sdata->vif; + if (ieee80211_vif_is_mesh(&sdata->vif) && + ieee80211_is_data(hdr->frame_control) && + !is_multicast_ether_addr(hdr->addr1)) + if (mesh_nexthop_lookup(skb, sdata)) { + /* skb queued: don't free */ + dev_put(sdata->dev); + return; + } + ieee80211_select_queue(local, skb); ieee80211_tx(sdata, skb, false); dev_put(sdata->dev); -- cgit v0.10.2 From c00552c60840c32456ca9e45de758ac03e3d3c4f Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 11 Aug 2009 16:09:34 +0200 Subject: libertas: name the network device wlan%d Devices created by the libertas driver are currently called eth%d. Which is wrong, because the device does not at all have anything to do with Ethernet. And it is also confusing when used on devices with more than one network device. Fix this by calling it wlan%d. Signed-off-by: Daniel Mack Cc: Roel Kluin Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 89575e4..8df1cfd 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1176,7 +1176,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) /* Allocate an Ethernet device and register it */ dev = alloc_etherdev(sizeof(struct lbs_private)); if (!dev) { - lbs_pr_err("init ethX device failed\n"); + lbs_pr_err("init wlanX device failed\n"); goto done; } priv = netdev_priv(dev); @@ -1204,6 +1204,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) SET_NETDEV_DEV(dev, dmdev); priv->rtap_net_dev = NULL; + strcpy(dev->name, "wlan%d"); lbs_deb_thread("Starting main thread...\n"); init_waitqueue_head(&priv->waitq); -- cgit v0.10.2 From 84ec167d327b42414285f22eb037a5bdee486ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Tue, 11 Aug 2009 21:47:00 +0200 Subject: b43: LP-PHY: Implement reading band SPROM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the new variables in b43_phy_lp appear to be dead code in the vendor driver; they will be removed if they remain unused when LP-PHY implementation is finished. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 95e15e6..2bec791 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -59,6 +59,89 @@ static void b43_lpphy_op_free(struct b43_wldev *dev) dev->phy.lp = NULL; } +static void lpphy_read_band_sprom(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + struct ssb_bus *bus = dev->dev->bus; + u16 cckpo, maxpwr; + u32 ofdmpo; + int i; + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + lpphy->tx_isolation_med_band = bus->sprom.tri2g; + lpphy->bx_arch = bus->sprom.bxa2g; + lpphy->rx_pwr_offset = bus->sprom.rxpo2g; + lpphy->rssi_vf = bus->sprom.rssismf2g; + lpphy->rssi_vc = bus->sprom.rssismc2g; + lpphy->rssi_gs = bus->sprom.rssisav2g; + lpphy->txpa[0] = bus->sprom.pa0b0; + lpphy->txpa[1] = bus->sprom.pa0b1; + lpphy->txpa[2] = bus->sprom.pa0b2; + maxpwr = bus->sprom.maxpwr_bg; + lpphy->max_tx_pwr_med_band = maxpwr; + cckpo = bus->sprom.cck2gpo; + ofdmpo = bus->sprom.ofdm2gpo; + if (cckpo) { + for (i = 0; i < 4; i++) { + lpphy->tx_max_rate[i] = + maxpwr - (ofdmpo & 0xF) * 2; + ofdmpo >>= 4; + } + ofdmpo = bus->sprom.ofdm2gpo; + for (i = 4; i < 15; i++) { + lpphy->tx_max_rate[i] = + maxpwr - (ofdmpo & 0xF) * 2; + ofdmpo >>= 4; + } + } else { + ofdmpo &= 0xFF; + for (i = 0; i < 4; i++) + lpphy->tx_max_rate[i] = maxpwr; + for (i = 4; i < 15; i++) + lpphy->tx_max_rate[i] = maxpwr - ofdmpo; + } + } else { /* 5GHz */ + lpphy->tx_isolation_low_band = bus->sprom.tri5gl; + lpphy->tx_isolation_med_band = bus->sprom.tri5g; + lpphy->tx_isolation_hi_band = bus->sprom.tri5gh; + lpphy->bx_arch = bus->sprom.bxa5g; + lpphy->rx_pwr_offset = bus->sprom.rxpo5g; + lpphy->rssi_vf = bus->sprom.rssismf5g; + lpphy->rssi_vc = bus->sprom.rssismc5g; + lpphy->rssi_gs = bus->sprom.rssisav5g; + lpphy->txpa[0] = bus->sprom.pa1b0; + lpphy->txpa[1] = bus->sprom.pa1b1; + lpphy->txpa[2] = bus->sprom.pa1b2; + lpphy->txpal[0] = bus->sprom.pa1lob0; + lpphy->txpal[1] = bus->sprom.pa1lob1; + lpphy->txpal[2] = bus->sprom.pa1lob2; + lpphy->txpah[0] = bus->sprom.pa1hib0; + lpphy->txpah[1] = bus->sprom.pa1hib1; + lpphy->txpah[2] = bus->sprom.pa1hib2; + maxpwr = bus->sprom.maxpwr_al; + ofdmpo = bus->sprom.ofdm5glpo; + lpphy->max_tx_pwr_low_band = maxpwr; + for (i = 4; i < 12; i++) { + lpphy->tx_max_ratel[i] = maxpwr - (ofdmpo & 0xF) * 2; + ofdmpo >>= 4; + } + maxpwr = bus->sprom.maxpwr_a; + ofdmpo = bus->sprom.ofdm5gpo; + lpphy->max_tx_pwr_med_band = maxpwr; + for (i = 4; i < 12; i++) { + lpphy->tx_max_rate[i] = maxpwr - (ofdmpo & 0xF) * 2; + ofdmpo >>= 4; + } + maxpwr = bus->sprom.maxpwr_ah; + ofdmpo = bus->sprom.ofdm5ghpo; + lpphy->max_tx_pwr_hi_band = maxpwr; + for (i = 4; i < 12; i++) { + lpphy->tx_max_rateh[i] = maxpwr - (ofdmpo & 0xF) * 2; + ofdmpo >>= 4; + } + } +} + static void lpphy_adjust_gain_table(struct b43_wldev *dev) { struct b43_phy_lp *lpphy = dev->phy.lp; @@ -694,7 +777,7 @@ static void lpphy_tx_pctl_init(struct b43_wldev *dev) static int b43_lpphy_op_init(struct b43_wldev *dev) { - /* TODO: band SPROM */ + lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? lpphy_baseband_init(dev); lpphy_radio_init(dev); //TODO calibrate RC diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 13d89ea..0461d5b 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -831,6 +831,22 @@ struct b43_phy_lp { /* Transmit isolation high band */ u8 tx_isolation_hi_band; /* FIXME initial value? */ + /* Max transmit power medium band */ + u16 max_tx_pwr_med_band; + /* Max transmit power low band */ + u16 max_tx_pwr_low_band; + /* Max transmit power high band */ + u16 max_tx_pwr_hi_band; + + /* FIXME What are these used for? */ + /* FIXME Is 15 the correct array size? */ + u16 tx_max_rate[15]; + u16 tx_max_ratel[15]; + u16 tx_max_rateh[15]; + + /* Transmit power arrays */ + s16 txpa[3], txpal[3], txpah[3]; + /* Receive power offset */ u8 rx_pwr_offset; /* FIXME initial value? */ -- cgit v0.10.2 From d4de9532fd0b50d486259ace17650a58bbb751c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Tue, 11 Aug 2009 21:53:06 +0200 Subject: b43: Implement RC calibration for rev.2+ LP PHYs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 2bec791..296e209 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -605,6 +605,90 @@ static void lpphy_radio_init(struct b43_wldev *dev) } } +static void lpphy_set_rc_cap(struct b43_wldev *dev) +{ + u8 rc_cap = dev->phy.lp->rc_cap; + + b43_radio_write(dev, B2062_N_RXBB_CALIB2, max_t(u8, rc_cap-4, 0x80)); + b43_radio_write(dev, B2062_N_TX_CTL_A, ((rc_cap & 0x1F) >> 1) | 0x80); + b43_radio_write(dev, B2062_S_RXG_CNT16, ((rc_cap & 0x1F) >> 2) | 0x80); +} + +static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) +{ + //TODO and SPEC FIXME +} + +static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; + u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF; + int i; + + b43_radio_write(dev, B2063_RX_BB_SP8, 0x0); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); + b43_radio_mask(dev, B2063_PLL_SP1, 0xF7); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); + b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15); + b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70); + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D); + + for (i = 0; i < 10000; i++) { + if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) + break; + msleep(1); + } + + if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) + b43_radio_write(dev, B2063_RX_BB_SP8, tmp); + + tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF; + + b43_radio_write(dev, B2063_TX_BB_SP3, 0x0); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); + b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55); + b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76); + + if (crystal_freq == 24000000) { + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0); + } else { + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); + } + + b43_radio_write(dev, B2063_PA_SP7, 0x7D); + + for (i = 0; i < 10000; i++) { + if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) + break; + msleep(1); + } + + if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) + b43_radio_write(dev, B2063_TX_BB_SP3, tmp); + + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); +} + +static void lpphy_calibrate_rc(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + + if (dev->phy.rev >= 2) { + lpphy_rev2plus_rc_calib(dev); + } else if (!lpphy->rc_cap) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + lpphy_rev0_1_rc_calib(dev); + } else { + lpphy_set_rc_cap(dev); + } +} + /* Read the TX power control mode from hardware. */ static void lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev *dev) { @@ -780,7 +864,7 @@ static int b43_lpphy_op_init(struct b43_wldev *dev) lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? lpphy_baseband_init(dev); lpphy_radio_init(dev); - //TODO calibrate RC + lpphy_calibrate_rc(dev); //TODO set channel lpphy_tx_pctl_init(dev); lpphy_calibration(dev); -- cgit v0.10.2 From 7834ddbcc7a097443761b0722e8c9fb8511b95b1 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 11 Aug 2009 22:57:16 +0300 Subject: usbnet: add rx queue pausing Add rx queue pausing to usbnet. This is needed by rndis_wlan so that it can control rx queue and prevent received packets from being send forward before rndis_wlan receives and handles 'media connect'-indication. Without this establishing WPA connections is hard and fail often. [v2] - removed unneeded use of skb_clone Cc: David Brownell Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index af1fe46..7d471fc 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -233,6 +233,11 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) { int status; + if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { + skb_queue_tail(&dev->rxq_pause, skb); + return; + } + skb->protocol = eth_type_trans (skb, dev->net); dev->net->stats.rx_packets++; dev->net->stats.rx_bytes += skb->len; @@ -526,6 +531,41 @@ static void intr_complete (struct urb *urb) } /*-------------------------------------------------------------------------*/ +void usbnet_pause_rx(struct usbnet *dev) +{ + set_bit(EVENT_RX_PAUSED, &dev->flags); + + if (netif_msg_rx_status(dev)) + devdbg(dev, "paused rx queue enabled"); +} +EXPORT_SYMBOL_GPL(usbnet_pause_rx); + +void usbnet_resume_rx(struct usbnet *dev) +{ + struct sk_buff *skb; + int num = 0; + + clear_bit(EVENT_RX_PAUSED, &dev->flags); + + while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) { + usbnet_skb_return(dev, skb); + num++; + } + + tasklet_schedule(&dev->bh); + + if (netif_msg_rx_status(dev)) + devdbg(dev, "paused rx queue disabled, %d skbs requeued", num); +} +EXPORT_SYMBOL_GPL(usbnet_resume_rx); + +void usbnet_purge_paused_rxq(struct usbnet *dev) +{ + skb_queue_purge(&dev->rxq_pause); +} +EXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq); + +/*-------------------------------------------------------------------------*/ // unlink pending rx/tx; completion handlers do all other cleanup @@ -623,6 +663,8 @@ int usbnet_stop (struct net_device *net) usb_kill_urb(dev->interrupt); + usbnet_purge_paused_rxq(dev); + /* deferred work (task, timer, softirq) must also stop. * can't flush_scheduled_work() until we drop rtnl (later), * else workers could deadlock; so make workers a NOP. @@ -1113,7 +1155,6 @@ static void usbnet_bh (unsigned long param) } - /*------------------------------------------------------------------------- * * USB Device Driver support @@ -1210,6 +1251,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) skb_queue_head_init (&dev->rxq); skb_queue_head_init (&dev->txq); skb_queue_head_init (&dev->done); + skb_queue_head_init(&dev->rxq_pause); dev->bh.func = usbnet_bh; dev->bh.data = (unsigned long) dev; INIT_WORK (&dev->kevent, kevent); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 828dc18..d42692d 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1764,8 +1764,15 @@ static int rndis_iw_set_essid(struct net_device *dev, if (!wrqu->essid.flags || length == 0) return disassociate(usbdev, 1); - else + else { + /* Pause and purge rx queue, so we don't pass packets before + * 'media connect'-indication. + */ + usbnet_pause_rx(usbdev); + usbnet_purge_paused_rxq(usbdev); + return set_essid(usbdev, &ssid); + } } @@ -2328,6 +2335,8 @@ get_bssid: memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); } + + usbnet_resume_rx(usbdev); } if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) { @@ -2541,6 +2550,8 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) switch (msg->status) { case RNDIS_STATUS_MEDIA_CONNECT: + usbnet_pause_rx(usbdev); + devinfo(usbdev, "media connect"); /* queue work to avoid recursive calls into rndis_command */ diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index de8b4b1..0951425 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -53,6 +53,7 @@ struct usbnet { struct sk_buff_head rxq; struct sk_buff_head txq; struct sk_buff_head done; + struct sk_buff_head rxq_pause; struct urb *interrupt; struct tasklet_struct bh; @@ -63,6 +64,7 @@ struct usbnet { # define EVENT_RX_MEMORY 2 # define EVENT_STS_SPLIT 3 # define EVENT_LINK_RESET 4 +# define EVENT_RX_PAUSED 5 }; static inline struct usb_driver *driver_of(struct usb_interface *intf) @@ -190,6 +192,10 @@ extern void usbnet_defer_kevent (struct usbnet *, int); extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); extern void usbnet_unlink_rx_urbs(struct usbnet *); +extern void usbnet_pause_rx(struct usbnet *); +extern void usbnet_resume_rx(struct usbnet *); +extern void usbnet_purge_paused_rxq(struct usbnet *); + extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd); extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd); extern u32 usbnet_get_link (struct net_device *net); -- cgit v0.10.2 From 47583154767886a97a82452c8aca63bf0336337a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Tue, 11 Aug 2009 22:24:22 +0200 Subject: b43: LP-PHY: Refactor TX gain table I/O MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make it possible to write individual gain table entries. Allow gain table entries to be written outside gain table init. Add version-agnostic helpers for writing gain tables. Use the new TX gain table helpers during table init. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index b056811..2721310 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -1058,10 +1058,6 @@ static const u32 lpphy_papd_mult_table[] = { 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28, }; -struct lpphy_tx_gain_table_entry { - u8 gm, pga, pad, dac, bb_mult; -}; - static struct lpphy_tx_gain_table_entry lpphy_rev0_nopa_tx_gain_table[] = { { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 152, }, { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 147, }, @@ -2345,44 +2341,55 @@ void lpphy_rev2plus_table_init(struct b43_wldev *dev) } } - -static void lpphy_rev0_1_write_gain_table(struct b43_wldev *dev, - struct lpphy_tx_gain_table_entry *table) +static void lpphy_rev0_1_write_gain_table(struct b43_wldev *dev, int offset, + struct lpphy_tx_gain_table_entry data) { - int i; u32 tmp; B43_WARN_ON(dev->phy.rev >= 2); - for (i = 0; i < 128; i++) { - tmp = table[i].pad << 11; - tmp |= table[i].pga << 7; - tmp |= table[i].gm << 4; - tmp |= table[i].dac; - b43_lptab_write(dev, B43_LPTAB32(10, 0xC0 + i), tmp); - tmp = table[i].bb_mult << 20; - b43_lptab_write(dev, B43_LPTAB32(10, 0x140 + i), tmp); - } + tmp = data.pad << 11; + tmp |= data.pga << 7; + tmp |= data.gm << 4; + tmp |= data.dac; + b43_lptab_write(dev, B43_LPTAB32(10, 0xC0 + offset), tmp); + tmp = data.bb_mult << 20; + b43_lptab_write(dev, B43_LPTAB32(10, 0x140 + offset), tmp); } -static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, - struct lpphy_tx_gain_table_entry *table) +static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, int offset, + struct lpphy_tx_gain_table_entry data) { - int i; u32 tmp; B43_WARN_ON(dev->phy.rev < 2); - for (i = 0; i < 128; i++) { - tmp = table[i].pad << 16; - tmp |= table[i].pga << 8; - tmp |= table[i].gm; - tmp |= 0x7f000000; - b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + i), tmp); - tmp = table[i].bb_mult << 20; - tmp |= table[i].dac << 28; - b43_lptab_write(dev, B43_LPTAB32(7, 0x140 + i), tmp); - } + tmp = data.pad << 16; + tmp |= data.pga << 8; + tmp |= data.gm; + tmp |= 0x7f000000; + b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + offset), tmp); + tmp = data.bb_mult << 20; + tmp |= data.dac << 28; + b43_lptab_write(dev, B43_LPTAB32(7, 0x140 + offset), tmp); +} + +void lpphy_write_gain_table(struct b43_wldev *dev, int offset, + struct lpphy_tx_gain_table_entry data) +{ + if (dev->phy.rev >= 2) + lpphy_rev2plus_write_gain_table(dev, offset, data); + else + lpphy_rev0_1_write_gain_table(dev, offset, data); +} + +void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count, + struct lpphy_tx_gain_table_entry *table) +{ + int i; + + for (i = offset; i < count; i++) + lpphy_write_gain_table(dev, i, table[i]); } void lpphy_init_tx_gain_table(struct b43_wldev *dev) @@ -2393,36 +2400,36 @@ void lpphy_init_tx_gain_table(struct b43_wldev *dev) case 0: if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || (bus->sprom.boardflags_lo & B43_BFL_HGPA)) - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev0_nopa_tx_gain_table); else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev0_2ghz_tx_gain_table); else - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev0_5ghz_tx_gain_table); break; case 1: if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || (bus->sprom.boardflags_lo & B43_BFL_HGPA)) - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev1_nopa_tx_gain_table); else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev1_2ghz_tx_gain_table); else - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev1_5ghz_tx_gain_table); break; default: if (bus->sprom.boardflags_hi & B43_BFH_NOPA) - lpphy_rev2plus_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev2_nopa_tx_gain_table); else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - lpphy_rev2plus_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev2_2ghz_tx_gain_table); else - lpphy_rev2plus_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev2_5ghz_tx_gain_table); } } diff --git a/drivers/net/wireless/b43/tables_lpphy.h b/drivers/net/wireless/b43/tables_lpphy.h index b5024b6..84f1d26 100644 --- a/drivers/net/wireless/b43/tables_lpphy.h +++ b/drivers/net/wireless/b43/tables_lpphy.h @@ -28,6 +28,15 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, void b2062_upload_init_table(struct b43_wldev *dev); void b2063_upload_init_table(struct b43_wldev *dev); +struct lpphy_tx_gain_table_entry { + u8 gm, pga, pad, dac, bb_mult; +}; + +void lpphy_write_gain_table(struct b43_wldev *dev, int offset, + struct lpphy_tx_gain_table_entry data); +void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count, + struct lpphy_tx_gain_table_entry *table); + void lpphy_rev0_1_table_init(struct b43_wldev *dev); void lpphy_rev2plus_table_init(struct b43_wldev *dev); void lpphy_init_tx_gain_table(struct b43_wldev *dev); -- cgit v0.10.2 From aae79e648d93bc9d6b3581ab4eb88e2ac44f5c46 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 12 Aug 2009 14:07:27 +0300 Subject: iwl3945: fix compilation error in iwl3945_pass_packet_to_mac80211() Commit "iwlwifi: Traffic type and counter for debugFs" broke iwl3945 in a case when CONFIG_IWLWIFI_LEDS is disabled: drivers/net/wireless/iwlwifi/iwl-3945.c:580: error: 'hdr' undeclared (first use in this function) Fix it by removing the ifdef check for hdr variable. Signed-off-by: Kalle Valo Acked-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index ae7f163..ba5ef83 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -544,9 +544,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, struct ieee80211_rx_status *stats) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; -#ifdef CONFIG_IWLWIFI_LEDS struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); -#endif struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); short len = le16_to_cpu(rx_hdr->len); -- cgit v0.10.2 From 11aa6e2398f54712b1e1bdeb9d8bf3b452c5a5d5 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 12 Aug 2009 14:42:51 +0300 Subject: wl1251: remove wl1251_ops.c Commit "wl1251: remove wl1251_ops" originally removed file wl1251_ops.c, but while I rebased the patch the removal got lost. Now remote the file for real. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c deleted file mode 100644 index 758280a..0000000 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ /dev/null @@ -1,729 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * 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 published by the Free Software Foundation. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "wl1251_ops.h" -#include "reg.h" -#include "wl1251_io.h" -#include "wl1251_spi.h" -#include "wl1251_boot.h" -#include "wl1251_event.h" -#include "wl1251_acx.h" -#include "wl1251_tx.h" -#include "wl1251_rx.h" -#include "wl1251_ps.h" -#include "wl1251_init.h" - -static struct wl1251_partition_set wl1251_part_table[PART_TABLE_LEN] = { - [PART_DOWN] = { - .mem = { - .start = 0x00000000, - .size = 0x00016800 - }, - .reg = { - .start = REGISTERS_BASE, - .size = REGISTERS_DOWN_SIZE - }, - }, - - [PART_WORK] = { - .mem = { - .start = 0x00028000, - .size = 0x00014000 - }, - .reg = { - .start = REGISTERS_BASE, - .size = REGISTERS_WORK_SIZE - }, - }, - - /* WL1251 doesn't use the DRPW partition, so we don't set it here */ -}; - -static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { - [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), - [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), - [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), - [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), - [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), - [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), - [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), - [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), - [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), - [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), - [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) -}; - -static int wl1251_upload_firmware(struct wl1251 *wl) -{ - struct wl1251_partition_set *p_table = wl->chip.p_table; - int addr, chunk_num, partition_limit; - size_t fw_data_len; - u8 *p; - - /* whal_FwCtrl_LoadFwImageSm() */ - - wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", - wl1251_reg_read32(wl, CHIP_ID_B)); - - /* 10.0 check firmware length and set partition */ - fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | - (wl->fw[6] << 8) | (wl->fw[7]); - - wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, - CHUNK_SIZE); - - if ((fw_data_len % 4) != 0) { - wl1251_error("firmware length not multiple of four"); - return -EIO; - } - - wl1251_set_partition(wl, - p_table[PART_DOWN].mem.start, - p_table[PART_DOWN].mem.size, - p_table[PART_DOWN].reg.start, - p_table[PART_DOWN].reg.size); - - /* 10.1 set partition limit and chunk num */ - chunk_num = 0; - partition_limit = p_table[PART_DOWN].mem.size; - - while (chunk_num < fw_data_len / CHUNK_SIZE) { - /* 10.2 update partition, if needed */ - addr = p_table[PART_DOWN].mem.start + - (chunk_num + 2) * CHUNK_SIZE; - if (addr > partition_limit) { - addr = p_table[PART_DOWN].mem.start + - chunk_num * CHUNK_SIZE; - partition_limit = chunk_num * CHUNK_SIZE + - p_table[PART_DOWN].mem.size; - wl1251_set_partition(wl, - addr, - p_table[PART_DOWN].mem.size, - p_table[PART_DOWN].reg.start, - p_table[PART_DOWN].reg.size); - } - - /* 10.3 upload the chunk */ - addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", - p, addr); - wl1251_mem_write(wl, addr, p, CHUNK_SIZE); - - chunk_num++; - } - - /* 10.4 upload the last chunk */ - addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", - fw_data_len % CHUNK_SIZE, p, addr); - wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); - - return 0; -} - -static int wl1251_upload_nvs(struct wl1251 *wl) -{ - size_t nvs_len, nvs_bytes_written, burst_len; - int nvs_start, i; - u32 dest_addr, val; - u8 *nvs_ptr, *nvs; - - nvs = wl->nvs; - if (nvs == NULL) - return -ENODEV; - - nvs_ptr = nvs; - - nvs_len = wl->nvs_len; - nvs_start = wl->fw_len; - - /* - * Layout before the actual NVS tables: - * 1 byte : burst length. - * 2 bytes: destination address. - * n bytes: data to burst copy. - * - * This is ended by a 0 length, then the NVS tables. - */ - - while (nvs_ptr[0]) { - burst_len = nvs_ptr[0]; - dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); - - /* We move our pointer to the data */ - nvs_ptr += 3; - - for (i = 0; i < burst_len; i++) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - wl1251_debug(DEBUG_BOOT, - "nvs burst write 0x%x: 0x%x", - dest_addr, val); - wl1251_mem_write32(wl, dest_addr, val); - - nvs_ptr += 4; - dest_addr += 4; - } - } - - /* - * We've reached the first zero length, the first NVS table - * is 7 bytes further. - */ - nvs_ptr += 7; - nvs_len -= nvs_ptr - nvs; - nvs_len = ALIGN(nvs_len, 4); - - /* Now we must set the partition correctly */ - wl1251_set_partition(wl, nvs_start, - wl->chip.p_table[PART_DOWN].mem.size, - wl->chip.p_table[PART_DOWN].reg.start, - wl->chip.p_table[PART_DOWN].reg.size); - - /* And finally we upload the NVS tables */ - nvs_bytes_written = 0; - while (nvs_bytes_written < nvs_len) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - val = cpu_to_le32(val); - - wl1251_debug(DEBUG_BOOT, - "nvs write table 0x%x: 0x%x", - nvs_start, val); - wl1251_mem_write32(wl, nvs_start, val); - - nvs_ptr += 4; - nvs_bytes_written += 4; - nvs_start += 4; - } - - return 0; -} - -static int wl1251_boot(struct wl1251 *wl) -{ - int ret = 0, minor_minor_e2_ver; - u32 tmp, boot_data; - - ret = wl1251_boot_soft_reset(wl); - if (ret < 0) - goto out; - - /* 2. start processing NVS file */ - ret = wl->chip.op_upload_nvs(wl); - if (ret < 0) - goto out; - - /* write firmware's last address (ie. it's length) to - * ACX_EEPROMLESS_IND_REG */ - wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); - - /* 6. read the EEPROM parameters */ - tmp = wl1251_reg_read32(wl, SCR_PAD2); - - /* 7. read bootdata */ - wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; - wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; - tmp = wl1251_reg_read32(wl, SCR_PAD3); - - /* 8. check bootdata and call restart sequence */ - wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; - minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; - - wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " - "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", - wl->boot_attr.radio_type, wl->boot_attr.major, - wl->boot_attr.minor, minor_minor_e2_ver); - - ret = wl1251_boot_init_seq(wl); - if (ret < 0) - goto out; - - /* 9. NVS processing done */ - boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); - - /* 10. check that ECPU_CONTROL_HALT bits are set in - * pWhalBus->uBootData and start uploading firmware - */ - if ((boot_data & ECPU_CONTROL_HALT) == 0) { - wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); - ret = -EIO; - goto out; - } - - ret = wl->chip.op_upload_fw(wl); - if (ret < 0) - goto out; - - /* 10.5 start firmware */ - ret = wl1251_boot_run_firmware(wl); - if (ret < 0) - goto out; - -out: - return ret; -} - -static int wl1251_mem_cfg(struct wl1251 *wl) -{ - struct wl1251_acx_config_memory *mem_conf; - int ret, i; - - wl1251_debug(DEBUG_ACX, "wl1251 mem cfg"); - - mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); - if (!mem_conf) { - ret = -ENOMEM; - goto out; - } - - /* memory config */ - mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); - mem_conf->mem_config.rx_mem_block_num = 35; - mem_conf->mem_config.tx_min_mem_block_num = 64; - mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; - mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; - mem_conf->mem_config.num_ssid_profiles = 1; - mem_conf->mem_config.debug_buffer_size = - cpu_to_le16(TRACE_BUFFER_MAX_SIZE); - - /* RX queue config */ - mem_conf->rx_queue_config.dma_address = 0; - mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; - mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; - mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; - - /* TX queue config */ - for (i = 0; i < MAX_TX_QUEUES; i++) { - mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; - mem_conf->tx_queue_config[i].attributes = i; - } - - ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, - sizeof(*mem_conf)); - if (ret < 0) { - wl1251_warning("wl1251 mem config failed: %d", ret); - goto out; - } - -out: - kfree(mem_conf); - return ret; -} - -static int wl1251_hw_init_mem_config(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_mem_cfg(wl); - if (ret < 0) - return ret; - - wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), - GFP_KERNEL); - if (!wl->target_mem_map) { - wl1251_error("couldn't allocate target memory map"); - return -ENOMEM; - } - - /* we now ask for the firmware built memory map */ - ret = wl1251_acx_mem_map(wl, wl->target_mem_map, - sizeof(struct wl1251_acx_mem_map)); - if (ret < 0) { - wl1251_error("couldn't retrieve firmware memory map"); - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - return ret; - } - - return 0; -} - -static void wl1251_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) -{ - u32 cpu_ctrl; - - /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - /* 10.5.1 run the firmware (II) */ - cpu_ctrl &= ~flag; - wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); -} - -static void wl1251_target_enable_interrupts(struct wl1251 *wl) -{ - /* Enable target's interrupts */ - wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | - WL1251_ACX_INTR_RX1_DATA | - WL1251_ACX_INTR_TX_RESULT | - WL1251_ACX_INTR_EVENT_A | - WL1251_ACX_INTR_EVENT_B | - WL1251_ACX_INTR_INIT_COMPLETE; - wl1251_boot_target_enable_interrupts(wl); -} - -static void wl1251_fw_version(struct wl1251 *wl) -{ - wl1251_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); -} - -static void wl1251_irq_work(struct work_struct *work) -{ - u32 intr; - struct wl1251 *wl = - container_of(work, struct wl1251, irq_work); - int ret; - - mutex_lock(&wl->mutex); - - wl1251_debug(DEBUG_IRQ, "IRQ work"); - - if (wl->state == WL1251_STATE_OFF) - goto out; - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); - - intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); - - if (wl->data_path) { - wl->rx_counter = - wl1251_mem_read32(wl, wl->data_path->rx_control_addr); - - /* We handle a firmware bug here */ - switch ((wl->rx_counter - wl->rx_handled) & 0xf) { - case 0: - wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); - intr &= ~WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 1: - wl1251_debug(DEBUG_IRQ, "RX: FW +1"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 2: - wl1251_debug(DEBUG_IRQ, "RX: FW +2"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr |= WL1251_ACX_INTR_RX1_DATA; - break; - default: - wl1251_warning("RX: FW and host out of sync: %d", - wl->rx_counter - wl->rx_handled); - break; - } - - wl->rx_handled = wl->rx_counter; - - - wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); - } - - intr &= wl->intr_mask; - - if (intr == 0) { - wl1251_debug(DEBUG_IRQ, "INTR is 0"); - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, - ~(wl->intr_mask)); - - goto out_sleep; - } - - if (intr & WL1251_ACX_INTR_RX0_DATA) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); - wl1251_rx(wl); - } - - if (intr & WL1251_ACX_INTR_RX1_DATA) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); - wl1251_rx(wl); - } - - if (intr & WL1251_ACX_INTR_TX_RESULT) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); - wl1251_tx_complete(wl); - } - - if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); - if (intr & WL1251_ACX_INTR_EVENT_A) - wl1251_event_handle(wl, 0); - else - wl1251_event_handle(wl, 1); - } - - if (intr & WL1251_ACX_INTR_INIT_COMPLETE) - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); - - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1251_hw_init_txq_fill(u8 qid, - struct acx_tx_queue_qos_config *config, - u32 num_blocks) -{ - config->qid = qid; - - switch (qid) { - case QOS_AC_BE: - config->high_threshold = - (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BE_DEF * num_blocks) / 100; - break; - case QOS_AC_BK: - config->high_threshold = - (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BK_DEF * num_blocks) / 100; - break; - case QOS_AC_VI: - config->high_threshold = - (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VI_DEF * num_blocks) / 100; - break; - case QOS_AC_VO: - config->high_threshold = - (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VO_DEF * num_blocks) / 100; - break; - default: - wl1251_error("Invalid TX queue id: %d", qid); - return -EINVAL; - } - - return 0; -} - -static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) -{ - struct acx_tx_queue_qos_config *config; - struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; - int ret, i; - - wl1251_debug(DEBUG_ACX, "acx tx queue config"); - - config = kzalloc(sizeof(*config), GFP_KERNEL); - if (!config) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < MAX_NUM_OF_AC; i++) { - ret = wl1251_hw_init_txq_fill(i, config, - wl_mem_map->num_tx_mem_blocks); - if (ret < 0) - goto out; - - ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, - config, sizeof(*config)); - if (ret < 0) - goto out; - } - -out: - kfree(config); - return ret; -} - -static int wl1251_hw_init_data_path_config(struct wl1251 *wl) -{ - int ret; - - /* asking for the data path parameters */ - wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), - GFP_KERNEL); - if (!wl->data_path) { - wl1251_error("Couldn't allocate data path parameters"); - return -ENOMEM; - } - - ret = wl1251_acx_data_path_params(wl, wl->data_path); - if (ret < 0) { - kfree(wl->data_path); - wl->data_path = NULL; - return ret; - } - - return 0; -} - -static int wl1251_hw_init(struct wl1251 *wl) -{ - struct wl1251_acx_mem_map *wl_mem_map; - int ret; - - ret = wl1251_hw_init_hwenc_config(wl); - if (ret < 0) - return ret; - - /* Template settings */ - ret = wl1251_hw_init_templates_config(wl); - if (ret < 0) - return ret; - - /* Default memory configuration */ - ret = wl1251_hw_init_mem_config(wl); - if (ret < 0) - return ret; - - /* Default data path configuration */ - ret = wl1251_hw_init_data_path_config(wl); - if (ret < 0) - goto out_free_memmap; - - /* RX config */ - ret = wl1251_hw_init_rx_config(wl, - RX_CFG_PROMISCUOUS | RX_CFG_TSF, - RX_FILTER_OPTION_DEF); - /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, - RX_FILTER_OPTION_FILTER_ALL); */ - if (ret < 0) - goto out_free_data_path; - - /* TX queues config */ - ret = wl1251_hw_init_tx_queue_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* PHY layer config */ - ret = wl1251_hw_init_phy_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacon filtering */ - ret = wl1251_hw_init_beacon_filter(wl); - if (ret < 0) - goto out_free_data_path; - - /* Bluetooth WLAN coexistence */ - ret = wl1251_hw_init_pta(wl); - if (ret < 0) - goto out_free_data_path; - - /* Energy detection */ - ret = wl1251_hw_init_energy_detection(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacons and boradcast settings */ - ret = wl1251_hw_init_beacon_broadcast(wl); - if (ret < 0) - goto out_free_data_path; - - /* Enable data path */ - ret = wl1251_cmd_data_path(wl, wl->channel, 1); - if (ret < 0) - goto out_free_data_path; - - /* Default power state */ - ret = wl1251_hw_init_power_auth(wl); - if (ret < 0) - goto out_free_data_path; - - wl_mem_map = wl->target_mem_map; - wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", - wl_mem_map->num_tx_mem_blocks, - wl->data_path->tx_control_addr, - wl_mem_map->num_rx_mem_blocks, - wl->data_path->rx_control_addr); - - return 0; - - out_free_data_path: - kfree(wl->data_path); - - out_free_memmap: - kfree(wl->target_mem_map); - - return ret; -} - -static int wl1251_plt_init(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_hw_init_mem_config(wl); - if (ret < 0) - return ret; - - ret = wl1251_cmd_data_path(wl, wl->channel, 1); - if (ret < 0) - return ret; - - return 0; -} - -void wl1251_setup(struct wl1251 *wl) -{ - /* FIXME: Is it better to use strncpy here or is this ok? */ - wl->chip.fw_filename = WL1251_FW_NAME; - wl->chip.nvs_filename = WL1251_NVS_NAME; - - /* Now we know what chip we're using, so adjust the power on sleep - * time accordingly */ - wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; - - wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; - wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; - - wl->chip.op_upload_nvs = wl1251_upload_nvs; - wl->chip.op_upload_fw = wl1251_upload_firmware; - wl->chip.op_boot = wl1251_boot; - wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; - wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; - wl->chip.op_hw_init = wl1251_hw_init; - wl->chip.op_plt_init = wl1251_plt_init; - wl->chip.op_fw_version = wl1251_fw_version; - wl->chip.op_tx_flush = wl1251_tx_flush; - wl->chip.op_cmd_join = wl1251_cmd_join; - - wl->chip.p_table = wl1251_part_table; - wl->chip.acx_reg_table = wl1251_acx_reg_table; - - INIT_WORK(&wl->irq_work, wl1251_irq_work); - INIT_WORK(&wl->tx_work, wl1251_tx_work); - -} -- cgit v0.10.2 From 5ef5da0ff2fc4f04c856f4ce9a757e318a02ad06 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 12 Aug 2009 14:42:59 +0300 Subject: wl1251: remove unused definitions from wl1251_reg.h Luis reported that IRQ_MASK conflicts with include/pcmcia/cs.h on compat-wireless. Remove that and a bunch of other unused defines from wl1251_reg.h. Reported-by: Luis R. Rodriguez Signed-off-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h index 2de47cc..bdd5610 100644 --- a/drivers/net/wireless/wl12xx/wl1251_reg.h +++ b/drivers/net/wireless/wl12xx/wl1251_reg.h @@ -42,70 +42,6 @@ /* ELP WLAN_READY bit */ #define ELPCTRL_WLAN_READY 0x2 -/* - * Interrupt registers. - * 64 bit interrupt sources registers ws ced. - * sme interupts were removed and new ones were added. - * Order was changed. - */ -#define FIQ_MASK (REGISTERS_BASE + 0x0400) -#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) -#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) -#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) -#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) -#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) -#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) -#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) -#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) -#define IRQ_MASK (REGISTERS_BASE + 0x0418) -#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) -#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) -#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) -#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) -#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) -#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) -#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) -#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) -#define ECPU_MASK (REGISTERS_BASE + 0x0448) -#define FIQ_STS_L (REGISTERS_BASE + 0x044C) -#define FIQ_STS_H (REGISTERS_BASE + 0x0450) -#define IRQ_STS_L (REGISTERS_BASE + 0x0454) -#define IRQ_STS_H (REGISTERS_BASE + 0x0458) -#define INT_STS_ND (REGISTERS_BASE + 0x0464) -#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) -#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) -#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) -#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) -#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) -#define INT_ACK (REGISTERS_BASE + 0x046C) -#define INT_ACK_L (REGISTERS_BASE + 0x046C) -#define INT_ACK_H (REGISTERS_BASE + 0x0470) -#define INT_TRIG (REGISTERS_BASE + 0x0474) -#define INT_TRIG_L (REGISTERS_BASE + 0x0474) -#define INT_TRIG_H (REGISTERS_BASE + 0x0478) -#define HOST_STS_L (REGISTERS_BASE + 0x045C) -#define HOST_STS_H (REGISTERS_BASE + 0x0460) -#define HOST_MASK (REGISTERS_BASE + 0x0430) -#define HOST_MASK_L (REGISTERS_BASE + 0x0430) -#define HOST_MASK_H (REGISTERS_BASE + 0x0434) -#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) -#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) -#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) -#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) -#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) -#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) - -/* Host Interrupts*/ -#define HINT_MASK (REGISTERS_BASE + 0x0494) -#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) -#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) -#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) -/*1150 spec calls this HINT_STS_RAW*/ -#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) -#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) -#define HINT_ACK (REGISTERS_BASE + 0x04A8) -#define HINT_TRIG (REGISTERS_BASE + 0x04AC) - /* Device Configuration registers*/ #define SOR_CFG (REGISTERS_BASE + 0x0800) #define ECPU_CTRL (REGISTERS_BASE + 0x0804) @@ -420,16 +356,6 @@ enum wl12xx_acx_int_reg { /*=============================================== - Phy regs - ===============================================*/ -#define ACX_PHY_ADDR_REG SBB_ADDR -#define ACX_PHY_DATA_REG SBB_DATA -#define ACX_PHY_CTRL_REG SBB_CTL -#define ACX_PHY_REG_WR_MASK 0x00000001ul -#define ACX_PHY_REG_RD_MASK 0x00000002ul - - -/*=============================================== EEPROM Read/Write Request 32bit RW ------------------------------------------ 1 EE_READ - EEPROM Read Request 1 - Setting this bit @@ -498,28 +424,6 @@ enum wl12xx_acx_int_reg { #define ACX_CONT_WIND_MIN_MASK 0x0000007f #define ACX_CONT_WIND_MAX 0x03ff0000 -/* - * Indirect slave register/memory registers - * ---------------------------------------- - */ -#define HW_SLAVE_REG_ADDR_REG 0x00000004 -#define HW_SLAVE_REG_DATA_REG 0x00000008 -#define HW_SLAVE_REG_CTRL_REG 0x0000000c - -#define SLAVE_AUTO_INC 0x00010000 -#define SLAVE_NO_AUTO_INC 0x00000000 -#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 - -#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR -#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA -#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL -#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL - -#define HW_FUNC_EVENT_INT_EN 0x8000 -#define HW_FUNC_EVENT_MASK_REG 0x00000034 - -#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) - /*=============================================== HI_CFG Interface Configuration Register Values ------------------------------------------ @@ -678,10 +582,6 @@ b12-b0 - Supported Rate indicator bits as defined below. ******************************************************************************/ -#define TNETW1251_CHIP_ID_PG1_0 0x07010101 -#define TNETW1251_CHIP_ID_PG1_1 0x07020101 -#define TNETW1251_CHIP_ID_PG1_2 0x07030101 - /************************************************************************* Interrupt Trigger Register (Host -> WiLink) -- cgit v0.10.2 From d15dd3e5d74186a3b0a4db271b440bbdc0f6da36 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 12 Aug 2009 09:56:59 -0700 Subject: ath: add common ath_rxbuf_alloc() and make ath9k use it Turns out ath5k and ath9k can share the same helper to allocates RX skbs. We allocate skbs aligned to the cache line size. This requirement seems to have come from AR5210; when this was not done it seems sometimes we'd get bogus data. I'm also told it may have been a performance enhancement consideration. In the end I can't be sure we can remove this on new hardware so just keep this and start sharing it through ath.ko. Make ath9k start using this, ath5k is next. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 253b95a..11ded15 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -5,9 +5,7 @@ menuconfig ATH_COMMON ---help--- This will enable the support for the Atheros wireless drivers. ath5k, ath9k and ar9170 drivers share some common code, this option - enables the common ath.ko module which currently shares just common - regulatory EEPROM helpers but will likely be extended later to share - more between modules. + enables the common ath.ko module which shares common helpers. For more information and documentation on this module you can visit: diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h new file mode 100644 index 0000000..e284cd3 --- /dev/null +++ b/drivers/net/wireless/ath/ath.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ATH_H +#define ATH_H + +#include + +struct ath_common { + u16 cachelsz; +}; + +struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, + u32 len, + gfp_t gfp_mask); + +#endif /* ATH_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7a5a157..2fd663c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -25,6 +25,7 @@ #include "hw.h" #include "rc.h" #include "debug.h" +#include "../ath.h" struct ath_node; @@ -532,6 +533,8 @@ struct ath_softc { struct ieee80211_hw *hw; struct device *dev; + struct ath_common common; + spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */ struct ath_wiphy *pri_wiphy; struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may @@ -564,7 +567,6 @@ struct ath_softc { u32 sc_flags; /* SC_OP_* */ u16 curtxpow; u16 curaid; - u16 cachelsz; u8 nbcnvifs; u16 nvifs; u8 tx_chainmask; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index efe2e85..b29d0ff 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1327,7 +1327,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) */ ath_read_cachesize(sc, &csz); /* XXX assert csz is non-zero */ - sc->cachelsz = csz << 2; /* convert to bytes */ + sc->common.cachelsz = csz << 2; /* convert to bytes */ ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); if (!ah) { diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 1a08c69..61dbdd2 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -100,38 +100,6 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) return (tsf & ~0x7fff) | rstamp; } -static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len, gfp_t gfp_mask) -{ - struct sk_buff *skb; - u32 off; - - /* - * Cache-line-align. This is important (for the - * 5210 at least) as not doing so causes bogus data - * in rx'd frames. - */ - - /* Note: the kernel can allocate a value greater than - * what we ask it to give us. We really only need 4 KB as that - * is this hardware supports and in fact we need at least 3849 - * as that is the MAX AMSDU size this hardware supports. - * Unfortunately this means we may get 8 KB here from the - * kernel... and that is actually what is observed on some - * systems :( */ - skb = __dev_alloc_skb(len + sc->cachelsz - 1, gfp_mask); - if (skb != NULL) { - off = ((unsigned long) skb->data) % sc->cachelsz; - if (off != 0) - skb_reserve(skb, sc->cachelsz - off); - } else { - DPRINTF(sc, ATH_DBG_FATAL, - "skbuff alloc of size %u failed\n", len); - return NULL; - } - - return skb; -} - /* * For Decrypt or Demic errors, we only mark packet status here and always push * up the frame up to let mac80211 handle the actual error case, be it no @@ -336,10 +304,10 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) spin_lock_init(&sc->rx.rxbuflock); sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, - min(sc->cachelsz, (u16)64)); + min(sc->common.cachelsz, (u16)64)); DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", - sc->cachelsz, sc->rx.bufsize); + sc->common.cachelsz, sc->rx.bufsize); /* Initialize rx descriptors */ @@ -352,7 +320,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) } list_for_each_entry(bf, &sc->rx.rxbuf, list) { - skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL); + skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_KERNEL); if (skb == NULL) { error = -ENOMEM; goto err; @@ -777,7 +745,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) /* Ensure we always have an skb to requeue once we are done * processing the current buffer's skb */ - requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_ATOMIC); + requeue_skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_ATOMIC); /* If there is no memory we ignore the current RX'd frame, * tell hardware it can give us a new frame using the old diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c index 9949b11..487193f 100644 --- a/drivers/net/wireless/ath/main.c +++ b/drivers/net/wireless/ath/main.c @@ -17,6 +17,42 @@ #include #include +#include "ath.h" + MODULE_AUTHOR("Atheros Communications"); MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards."); MODULE_LICENSE("Dual BSD/GPL"); + +struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, + u32 len, + gfp_t gfp_mask) +{ + struct sk_buff *skb; + u32 off; + + /* + * Cache-line-align. This is important (for the + * 5210 at least) as not doing so causes bogus data + * in rx'd frames. + */ + + /* Note: the kernel can allocate a value greater than + * what we ask it to give us. We really only need 4 KB as that + * is this hardware supports and in fact we need at least 3849 + * as that is the MAX AMSDU size this hardware supports. + * Unfortunately this means we may get 8 KB here from the + * kernel... and that is actually what is observed on some + * systems :( */ + skb = __dev_alloc_skb(len + common->cachelsz - 1, gfp_mask); + if (skb != NULL) { + off = ((unsigned long) skb->data) % common->cachelsz; + if (off != 0) + skb_reserve(skb, common->cachelsz - off); + } else { + printk(KERN_ERR "skbuff alloc of size %u failed\n", len); + return NULL; + } + + return skb; +} +EXPORT_SYMBOL(ath_rxbuf_alloc); -- cgit v0.10.2 From aeb63cfd4ccc813c204a0d81ad6c5a90c33d8f61 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 12 Aug 2009 09:57:00 -0700 Subject: ath5k: use common ath.ko ath_rxbuf_alloc() Now that its shared we can remove ath5k's own implementation. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index acbcfc2..63c2b57 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -544,7 +544,7 @@ ath5k_pci_probe(struct pci_dev *pdev, __set_bit(ATH_STAT_INVALID, sc->status); sc->iobase = mem; /* So we can unmap it on detach */ - sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ + sc->common.cachelsz = csz * sizeof(u32); /* convert to bytes */ sc->opmode = NL80211_IFTYPE_STATION; sc->bintval = 1000; mutex_init(&sc->lock); @@ -1151,27 +1151,20 @@ static struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) { struct sk_buff *skb; - unsigned int off; /* * Allocate buffer with headroom_needed space for the * fake physical layer header at the start. */ - skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1); + skb = ath_rxbuf_alloc(&sc->common, + sc->rxbufsize + sc->common.cachelsz - 1, + GFP_ATOMIC); if (!skb) { ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", - sc->rxbufsize + sc->cachelsz - 1); + sc->rxbufsize + sc->common.cachelsz - 1); return NULL; } - /* - * Cache-line-align. This is important (for the - * 5210 at least) as not doing so causes bogus data - * in rx'd frames. - */ - off = ((unsigned long)skb->data) % sc->cachelsz; - if (off != 0) - skb_reserve(skb, sc->cachelsz - off); *skb_addr = pci_map_single(sc->pdev, skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); @@ -1613,10 +1606,10 @@ ath5k_rx_start(struct ath5k_softc *sc) struct ath5k_buf *bf; int ret; - sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz); + sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz); ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", - sc->cachelsz, sc->rxbufsize); + sc->common.cachelsz, sc->rxbufsize); spin_lock_bh(&sc->rxbuflock); sc->rxlink = NULL; diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 667bd9d..25a72a8 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -50,6 +50,7 @@ #include "ath5k.h" #include "debug.h" +#include "../ath.h" #define ATH_RXBUF 40 /* number of RX buffers */ #define ATH_TXBUF 200 /* number of TX buffers */ @@ -112,6 +113,7 @@ struct ath5k_rfkill { * associated with an instance of a device */ struct ath5k_softc { struct pci_dev *pdev; /* for dma mapping */ + struct ath_common common; void __iomem *iobase; /* address of the device */ struct mutex lock; /* dev-level lock */ struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES]; @@ -134,7 +136,6 @@ struct ath5k_softc { struct ath5k_desc *desc; /* TX/RX descriptors */ dma_addr_t desc_daddr; /* DMA (physical) address */ size_t desc_len; /* size of TX/RX descriptors */ - u16 cachelsz; /* cache line size */ DECLARE_BITMAP(status, 5); #define ATH_STAT_INVALID 0 /* disable hardware accesses */ -- cgit v0.10.2 From 13311b00117ed1bf903cf8870432504631a7ce77 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 12 Aug 2009 09:57:01 -0700 Subject: ath5k: use bit shift operators for cache line size This matches ath9k, providing consistency when reading both drivers. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 63c2b57..2b3cf39 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -471,7 +471,7 @@ ath5k_pci_probe(struct pci_dev *pdev, * DMA to work so force a reasonable value here if it * comes up zero. */ - csz = L1_CACHE_BYTES / sizeof(u32); + csz = L1_CACHE_BYTES >> 2; pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); } /* @@ -544,7 +544,7 @@ ath5k_pci_probe(struct pci_dev *pdev, __set_bit(ATH_STAT_INVALID, sc->status); sc->iobase = mem; /* So we can unmap it on detach */ - sc->common.cachelsz = csz * sizeof(u32); /* convert to bytes */ + sc->common.cachelsz = csz << 2; /* convert to bytes */ sc->opmode = NL80211_IFTYPE_STATION; sc->bintval = 1000; mutex_init(&sc->lock); -- cgit v0.10.2 From 57ef5ddb456649667438e023f67dd3a3ff3fbed8 Mon Sep 17 00:00:00 2001 From: David Woo Date: Wed, 12 Aug 2009 11:03:43 -0700 Subject: mac80211: Mark a destination sequence number as valid when a PREQ is received. If a PREQ frame is received giving us a fresher DSN than what we have, record the new dsn and mark it as valid. This patch fixes a bug in the setting of the MESH_PATH_DSN_VALID flag. Also, minor fix to coding style on that file. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 1cd1e727..ef1efd3 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -397,7 +397,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, - u8 *preq_elem, u32 metric) { + u8 *preq_elem, u32 metric) +{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; u8 *dst_addr, *orig_addr; @@ -430,7 +431,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || DSN_LT(mpath->dsn, dst_dsn)) { mpath->dsn = dst_dsn; - mpath->flags &= MESH_PATH_DSN_VALID; + mpath->flags |= MESH_PATH_DSN_VALID; } else if ((!(dst_flags & MP_F_DO)) && (mpath->flags & MESH_PATH_ACTIVE)) { reply = true; -- cgit v0.10.2 From 70bdb6b275d789ddf05c3a858e6b57715539394b Mon Sep 17 00:00:00 2001 From: David Woo Date: Wed, 12 Aug 2009 11:03:44 -0700 Subject: mac80211: Fix invalid length passed to IE parser for PLINK CONFIRM frames The length of the fixed portion of plink confirm frames is 4 bytes longer than the other plink_action frames. This path corrects an error in the length adjustment done for these type of frames. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index cb14253..ffcbad7 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -409,7 +409,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) { baseaddr += 4; - baselen -= 4; + baselen += 4; } ieee802_11_parse_elems(baseaddr, len - baselen, &elems); if (!elems.peer_link) { -- cgit v0.10.2 From 36e6fea84905512ea776707e82b5b435220efc17 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 12 Aug 2009 22:21:21 +0200 Subject: cfg80211: check for and abort dangling scan requests If you trigger a scan request on an interface and then take it down, or rmmod the module or unplug the device the driver might "forget" to cancel the scan request. That is a bug in the driver, but the current behaviour is that we just hang endlessly waiting for the netdev refcount to become 0 which it never will. To improve robustness, check for this situation in cfg80211, warn about it and clean up behind the driver. I don't just clean up silently because it's likely that the driver also has some internal state it has now leaked. Additionally, this fixes a locking bug, clearing the scan_req pointer should be done under the rdev lock. Finally, we also need to _wait_ for the scan work and not just abort it since it might be pending and wanting to do a cleanup. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index e630648..35d83be 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -601,8 +601,8 @@ void wiphy_unregister(struct wiphy *wiphy) mutex_unlock(&cfg80211_mutex); + flush_work(&rdev->scan_done_wk); cancel_work_sync(&rdev->conn_work); - cancel_work_sync(&rdev->scan_done_wk); kfree(rdev->scan_req); flush_work(&rdev->event_work); } @@ -728,6 +728,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, #endif break; case NETDEV_UNREGISTER: + cfg80211_lock_rdev(rdev); + + if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) { + rdev->scan_req->aborted = true; + ___cfg80211_scan_done(rdev); + } + mutex_lock(&rdev->devlist_mtx); /* * It is possible to get NETDEV_UNREGISTER @@ -746,6 +753,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, #endif } mutex_unlock(&rdev->devlist_mtx); + cfg80211_unlock_rdev(rdev); break; case NETDEV_PRE_UP: if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) diff --git a/net/wireless/core.h b/net/wireless/core.h index f7be3a9..c603f52 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -368,6 +368,7 @@ void cfg80211_sme_scan_done(struct net_device *dev); void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); void cfg80211_sme_disassoc(struct net_device *dev, int idx); void __cfg80211_scan_done(struct work_struct *wk); +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); void cfg80211_upload_connect_keys(struct wireless_dev *wdev); struct ieee80211_channel * diff --git a/net/wireless/scan.c b/net/wireless/scan.c index e6c1f11..fe575a2 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -18,19 +18,14 @@ #define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) -void __cfg80211_scan_done(struct work_struct *wk) +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) { - struct cfg80211_registered_device *rdev; struct cfg80211_scan_request *request; struct net_device *dev; #ifdef CONFIG_WIRELESS_EXT union iwreq_data wrqu; #endif - rdev = container_of(wk, struct cfg80211_registered_device, - scan_done_wk); - - mutex_lock(&rdev->mtx); request = rdev->scan_req; dev = request->dev; @@ -43,9 +38,9 @@ void __cfg80211_scan_done(struct work_struct *wk) cfg80211_sme_scan_done(dev); if (request->aborted) - nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); + nl80211_send_scan_aborted(rdev, dev); else - nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); + nl80211_send_scan_done(rdev, dev); #ifdef CONFIG_WIRELESS_EXT if (!request->aborted) { @@ -57,11 +52,22 @@ void __cfg80211_scan_done(struct work_struct *wk) dev_put(dev); - cfg80211_unlock_rdev(rdev); - wiphy_to_dev(request->wiphy)->scan_req = NULL; + rdev->scan_req = NULL; kfree(request); } +void __cfg80211_scan_done(struct work_struct *wk) +{ + struct cfg80211_registered_device *rdev; + + rdev = container_of(wk, struct cfg80211_registered_device, + scan_done_wk); + + cfg80211_lock_rdev(rdev); + ___cfg80211_scan_done(rdev); + cfg80211_unlock_rdev(rdev); +} + void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) { WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); -- cgit v0.10.2 From 16cb9d42b68b339852e8914f2538ca9a2aec616c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 12 Aug 2009 23:33:20 +0200 Subject: cfg80211: allow driver to override PS default Sometimes drivers might have a good reason to override the PS default, like iwlwifi right now where it affects RX performance significantly at this point. This will allow them to override the default, if desired, in a way that users can still change it according to their trade-off choices, not the driver's, like would happen if the driver just disabled PS completely then. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2239134..0b146bb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1108,6 +1108,9 @@ struct cfg80211_ops { * @net: the network namespace this wiphy currently lives in * @netnsok: if set to false, do not allow changing the netns of this * wiphy at all + * @ps_default: default for powersave, will be set depending on the + * kernel's default on wiphy_new(), but can be changed by the + * driver if it has a good reason to override the default */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -1123,6 +1126,7 @@ struct wiphy { bool disable_beacon_hints; bool netnsok; + bool ps_default; enum cfg80211_signal_type signal_type; diff --git a/net/wireless/core.c b/net/wireless/core.c index 35d83be..bc99e4e 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -412,6 +412,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) rdev->wiphy.dev.class = &ieee80211_class; rdev->wiphy.dev.platform_data = rdev; + rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE; + wiphy_net_set(&rdev->wiphy, &init_net); rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; @@ -674,7 +676,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev->wext.default_key = -1; wdev->wext.default_mgmt_key = -1; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; - wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE; + wdev->wext.ps = wdev->wiphy->ps_default; wdev->wext.ps_timeout = 100; if (rdev->ops->set_power_mgmt) if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, -- cgit v0.10.2 From 2a219eb26793fc4c47b3ad7b84bded7b66f6e2c4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 12 Aug 2009 14:45:16 -0700 Subject: ath9k: update kconfig to indicate support for AR9002 family ath9k supports the AR9002 family of chipsets. This includes the AR9285 and the miniPCI AR9223 and AR9220 (which themselves have AR9280+AR5133). We now refer people to the wiki page as it seems this is not as popular as we would have hoped. Reported-by: JD Cc: Dakota Lee Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 2cb72f8..ef5f59c 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -6,7 +6,13 @@ config ATH9K select NEW_LEDS ---help--- This module adds support for wireless adapters based on - Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets. + Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family + of chipsets. For a specific list of supported external + cards, laptops that already ship with these cards and + APs that come with these cards refer to to ath9k wiki + products page: + + http://wireless.kernel.org/en/users/Drivers/ath9k/products If you choose to build a module, it'll be called ath9k. -- cgit v0.10.2 From 1aa8e84736fb1a584c679f2893245826583a0526 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 13 Aug 2009 09:34:25 +0530 Subject: ath9k: Remove has_hw_phycounters PHY counters are available in all chipsets supported by ath9k. Remove the check. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index b709312..f264097 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -236,36 +236,35 @@ static void ath9k_ani_restart(struct ath_hw *ah) return; aniState = ah->curani; - aniState->listenTime = 0; - if (ah->has_hw_phycounters) { - if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { - aniState->ofdmPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "OFDM Trigger is too high for hw counters\n"); - } else { - aniState->ofdmPhyErrBase = - AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; - } - if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { - aniState->cckPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "CCK Trigger is too high for hw counters\n"); - } else { - aniState->cckPhyErrBase = - AR_PHY_COUNTMAX - aniState->cckTrigHigh; - } + + if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { + aniState->ofdmPhyErrBase = 0; DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Writing ofdmbase=%u cckbase=%u\n", - aniState->ofdmPhyErrBase, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); + "OFDM Trigger is too high for hw counters\n"); + } else { + aniState->ofdmPhyErrBase = + AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; + } + if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { + aniState->cckPhyErrBase = 0; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "CCK Trigger is too high for hw counters\n"); + } else { + aniState->cckPhyErrBase = + AR_PHY_COUNTMAX - aniState->cckTrigHigh; } + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Writing ofdmbase=%u cckbase=%u\n", + aniState->ofdmPhyErrBase, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); + aniState->ofdmPhyErrCount = 0; aniState->cckPhyErrCount = 0; } @@ -530,18 +529,12 @@ void ath9k_ani_reset(struct ath_hw *ah) if (aniState->firstepLevel != 0) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel); - if (ah->has_hw_phycounters) { - ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & - ~ATH9K_RX_FILTER_PHYERR); - ath9k_ani_restart(ah); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - } else { - ath9k_ani_restart(ah); - ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - } + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & + ~ATH9K_RX_FILTER_PHYERR); + ath9k_ani_restart(ah); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); } void ath9k_hw_ani_monitor(struct ath_hw *ah, @@ -550,6 +543,8 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, { struct ar5416AniState *aniState; int32_t listenTime; + u32 phyCnt1, phyCnt2; + u32 ofdmPhyErrCnt, cckPhyErrCnt; if (!DO_ANI(ah)) return; @@ -566,50 +561,45 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, aniState->listenTime += listenTime; - if (ah->has_hw_phycounters) { - u32 phyCnt1, phyCnt2; - u32 ofdmPhyErrCnt, cckPhyErrCnt; + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - - if (phyCnt1 < aniState->ofdmPhyErrBase || - phyCnt2 < aniState->cckPhyErrBase) { - if (phyCnt1 < aniState->ofdmPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "phyCnt1 0x%x, resetting " - "counter value to 0x%x\n", - phyCnt1, aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, - AR_PHY_ERR_OFDM_TIMING); - } - if (phyCnt2 < aniState->cckPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "phyCnt2 0x%x, resetting " - "counter value to 0x%x\n", - phyCnt2, aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, - AR_PHY_ERR_CCK_TIMING); - } - return; + phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); + phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); + + if (phyCnt1 < aniState->ofdmPhyErrBase || + phyCnt2 < aniState->cckPhyErrBase) { + if (phyCnt1 < aniState->ofdmPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "phyCnt1 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt1, aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, + aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, + AR_PHY_ERR_OFDM_TIMING); + } + if (phyCnt2 < aniState->cckPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "phyCnt2 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt2, aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, + AR_PHY_ERR_CCK_TIMING); } + return; + } - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ah->stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ah->stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ah->stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; - } + cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + ah->stats.ast_ani_cckerrs += + cckPhyErrCnt - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = cckPhyErrCnt; if (aniState->listenTime > 5 * ah->aniperiod) { if (aniState->ofdmPhyErrCount <= aniState->listenTime * @@ -632,11 +622,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, } } -bool ath9k_hw_phycounters(struct ath_hw *ah) -{ - return ah->has_hw_phycounters ? true : false; -} - void ath9k_enable_mib_counters(struct ath_hw *ah) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); @@ -781,9 +766,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah) { int i; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n"); - - ah->has_hw_phycounters = 1; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Initialize ANI\n"); memset(ah->ani, 0, sizeof(ah->ani)); for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { @@ -799,24 +782,22 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ATH9K_ANI_CCK_WEAK_SIG_THR; ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; - if (ah->has_hw_phycounters) { - ah->ani[i].ofdmPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; - ah->ani[i].cckPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; - } - } - if (ah->has_hw_phycounters) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Setting OfdmErrBase = 0x%08x\n", - ah->ani[0].ofdmPhyErrBase); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", - ah->ani[0].cckPhyErrBase); - - REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); - ath9k_enable_mib_counters(ah); + ah->ani[i].ofdmPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; + ah->ani[i].cckPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; } + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Setting OfdmErrBase = 0x%08x\n", + ah->ani[0].ofdmPhyErrBase); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", + ah->ani[0].cckPhyErrBase); + + REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); + ath9k_enable_mib_counters(ah); + ah->aniperiod = ATH9K_ANI_PERIOD; if (ah->config.enable_ani) ah->proc_phyerr |= HAL_PROCESS_ANI; @@ -826,9 +807,7 @@ void ath9k_hw_ani_disable(struct ath_hw *ah) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n"); - if (ah->has_hw_phycounters) { - ath9k_hw_disable_mib_counters(ah); - REG_WRITE(ah, AR_PHY_ERR_1, 0); - REG_WRITE(ah, AR_PHY_ERR_2, 0); - } + ath9k_hw_disable_mib_counters(ah); + REG_WRITE(ah, AR_PHY_ERR_1, 0); + REG_WRITE(ah, AR_PHY_ERR_2, 0); } diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index a36b7bb..1199245 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -124,7 +124,6 @@ void ath9k_ani_reset(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, const struct ath9k_node_stats *stats, struct ath9k_channel *chan); -bool ath9k_hw_phycounters(struct ath_hw *ah); void ath9k_enable_mib_counters(struct ath_hw *ah); void ath9k_hw_disable_mib_counters(struct ath_hw *ah); u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e83e900..0e65873 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -507,7 +507,6 @@ struct ath_hw { /* ANI */ u32 proc_phyerr; - bool has_hw_phycounters; u32 aniperiod; struct ar5416AniState *curani; struct ar5416AniState ani[255]; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b29d0ff..3eb6dc0 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2214,8 +2214,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, if ((conf->type == NL80211_IFTYPE_STATION) || (conf->type == NL80211_IFTYPE_ADHOC) || (conf->type == NL80211_IFTYPE_MESH_POINT)) { - if (ath9k_hw_phycounters(sc->sc_ah)) - sc->imask |= ATH9K_INT_MIB; + sc->imask |= ATH9K_INT_MIB; sc->imask |= ATH9K_INT_TSFOOR; } -- cgit v0.10.2 From 1cf6873a191388ff7d06bbd70f68bbffe1d70019 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 13 Aug 2009 09:34:32 +0530 Subject: ath9k: Remove duplicate variables diversity_control and antenna_switch_swap are already present in ath9k_ops_config. Remove duplicate occurrences in ath_hw. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6514dc7..9f1b34d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -407,7 +407,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.cck_trig_high = 200; ah->config.cck_trig_low = 100; ah->config.enable_ani = 1; - ah->config.diversity_control = 0; + ah->config.diversity_control = ATH9K_ANT_VARIABLE; ah->config.antenna_switch_swap = 0; for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { @@ -452,9 +452,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->regulatory.power_limit = MAX_RATE_POWER; ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX; ah->atim_window = 0; - ah->diversity_control = ah->config.diversity_control; - ah->antenna_switch_swap = - ah->config.antenna_switch_swap; ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE; ah->beacon_interval = 100; ah->enable_32kHz_clock = DONT_USE_32KHZ; @@ -3891,7 +3888,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah, break; } } else { - ah->diversity_control = settings; + ah->config.diversity_control = settings; } return true; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 0e65873..0336981 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -127,6 +127,12 @@ enum wireless_mode { ATH9K_MODE_MAX, }; +enum ath9k_ant_setting { + ATH9K_ANT_VARIABLE = 0, + ATH9K_ANT_FIXED_A, + ATH9K_ANT_FIXED_B +}; + enum ath9k_hw_caps { ATH9K_HW_CAP_MIC_AESCCM = BIT(0), ATH9K_HW_CAP_MIC_CKIP = BIT(1), @@ -191,7 +197,7 @@ struct ath9k_ops_config { u32 cck_trig_high; u32 cck_trig_low; u32 enable_ani; - u16 diversity_control; + enum ath9k_ant_setting diversity_control; u16 antenna_switch_swap; int serialize_regmode; bool intr_mitigation; @@ -330,12 +336,6 @@ enum ath9k_power_mode { ATH9K_PM_UNDEFINED }; -enum ath9k_ant_setting { - ATH9K_ANT_VARIABLE = 0, - ATH9K_ANT_FIXED_A, - ATH9K_ANT_FIXED_B -}; - enum ath9k_tp_scale { ATH9K_TP_SCALE_MAX = 0, ATH9K_TP_SCALE_50, @@ -437,8 +437,6 @@ struct ath_hw { u32 txurn_interrupt_mask; bool chip_fullsleep; u32 atim_window; - u16 antenna_switch_swap; - enum ath9k_ant_setting diversity_control; /* Calibration */ enum ath9k_cal_types supp_cals; diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 59bb3ce..63bf9a3 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -353,18 +353,16 @@ ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) u32 bank6SelMask; u32 *bank6Temp = ah->bank6Temp; - switch (ah->diversity_control) { + switch (ah->config.diversity_control) { case ATH9K_ANT_FIXED_A: bank6SelMask = - (ah-> - antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 : - REDUCE_CHAIN_1; + (ah->config.antenna_switch_swap & ANTSWAP_AB) ? + REDUCE_CHAIN_0 : REDUCE_CHAIN_1; break; case ATH9K_ANT_FIXED_B: bank6SelMask = - (ah-> - antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 : - REDUCE_CHAIN_0; + (ah->config.antenna_switch_swap & ANTSWAP_AB) ? + REDUCE_CHAIN_1 : REDUCE_CHAIN_0; break; case ATH9K_ANT_VARIABLE: return; -- cgit v0.10.2 From 523c36fc9cf75ccf605d9acf68ae9eb857de3f58 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 13 Aug 2009 09:34:35 +0530 Subject: ath9k: Fix bug in PCI resume This patch fixes a bug where the device was enabled before restoring the PCI state. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 3546504..616bdff 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -253,10 +253,12 @@ static int ath_pci_resume(struct pci_dev *pdev) u32 val; int err; + pci_restore_state(pdev); + err = pci_enable_device(pdev); if (err) return err; - pci_restore_state(pdev); + /* * Suspend/Resume resets the PCI configuration space, so we have to * re-disable the RETRY_TIMEOUT register (0x41) to keep -- cgit v0.10.2 From eff563cf10e2f24e3b025d352c3aa174cf0111b3 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 13 Aug 2009 09:34:37 +0530 Subject: ath9k: Set HW state properly This patch fixes a bug in ath9k_stop() where the HW was not put into FULL_SLEEP state. Not doing so will cause issues in suspend-resume and the HW will not respond to chip resets. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3eb6dc0..fa4c6e7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2140,6 +2140,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); ath9k_hw_configpcipowersave(sc->sc_ah, 1); + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); sc->sc_flags |= SC_OP_INVALID; -- cgit v0.10.2 From 560ad81b6c90e0fddc4d6c280f16ddf18d47eeb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 13 Aug 2009 14:19:02 +0200 Subject: b43: Implement RC calibration for rev.0/1 LP-PHYs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also implement get/set BB mult, get/set TX gain, set RX gain, disable/restore CRS, run/stop DDFS, RX IQ est and QDIV roundup in the process. Signed-off-by: Gábor Stefanik Acked-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 296e209..cfb8337 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -605,6 +605,8 @@ static void lpphy_radio_init(struct b43_wldev *dev) } } +struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; }; + static void lpphy_set_rc_cap(struct b43_wldev *dev) { u8 rc_cap = dev->phy.lp->rc_cap; @@ -614,79 +616,326 @@ static void lpphy_set_rc_cap(struct b43_wldev *dev) b43_radio_write(dev, B2062_S_RXG_CNT16, ((rc_cap & 0x1F) >> 2) | 0x80); } -static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) +static u8 lpphy_get_bb_mult(struct b43_wldev *dev) { - //TODO and SPEC FIXME + return (b43_lptab_read(dev, B43_LPTAB16(0, 87)) & 0xFF00) >> 8; } -static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev) +static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult) { - struct ssb_bus *bus = dev->dev->bus; - u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; - u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF; - int i; + b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8); +} - b43_radio_write(dev, B2063_RX_BB_SP8, 0x0); - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); - b43_radio_mask(dev, B2063_PLL_SP1, 0xF7); - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); - b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15); - b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70); - b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52); - b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D); +static void lpphy_disable_crs(struct b43_wldev *dev) +{ + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFDF); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFBF); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x7); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x38); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x100); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFDFF); + b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL0, 0); + b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL1, 1); + b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL2, 0x20); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xF7FF); + b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0); + b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45AF); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF); +} - for (i = 0; i < 10000; i++) { - if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) - break; - msleep(1); +static void lpphy_restore_crs(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x60); + else + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x20); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00); +} + +struct lpphy_tx_gains { u16 gm, pga, pad, dac; }; + +static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev) +{ + struct lpphy_tx_gains gains; + u16 tmp; + + gains.dac = (b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0x380) >> 7; + if (dev->phy.rev < 2) { + tmp = b43_phy_read(dev, + B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7FF; + gains.gm = tmp & 0x0007; + gains.pga = (tmp & 0x0078) >> 3; + gains.pad = (tmp & 0x780) >> 7; + } else { + tmp = b43_phy_read(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL); + gains.pad = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0xFF; + gains.gm = tmp & 0xFF; + gains.pga = (tmp >> 8) & 0xFF; } - if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) - b43_radio_write(dev, B2063_RX_BB_SP8, tmp); + return gains; +} - tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF; +static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac) +{ + u16 ctl = b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0xC7F; + ctl |= dac << 7; + b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl); +} - b43_radio_write(dev, B2063_TX_BB_SP3, 0x0); - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); - b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55); - b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76); +static void lpphy_set_tx_gains(struct b43_wldev *dev, + struct lpphy_tx_gains gains) +{ + u16 rf_gain, pa_gain; - if (crystal_freq == 24000000) { - b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC); - b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0); + if (dev->phy.rev < 2) { + rf_gain = (gains.pad << 7) | (gains.pga << 3) | gains.gm; + b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, + 0xF800, rf_gain); } else { - b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13); - b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); + pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F00; + b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, + (gains.pga << 8) | gains.gm); + b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, + 0x8000, gains.pad | pa_gain); + b43_phy_write(dev, B43_PHY_OFDM(0xFC), + (gains.pga << 8) | gains.gm); + b43_phy_maskset(dev, B43_PHY_OFDM(0xFD), + 0x8000, gains.pad | pa_gain); } + lpphy_set_dac_gain(dev, gains.dac); + if (dev->phy.rev < 2) { + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF, 1 << 8); + } else { + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14); + } + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 4); +} - b43_radio_write(dev, B2063_PA_SP7, 0x7D); +static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain) +{ + u16 trsw = gain & 0x1; + u16 lna = (gain & 0xFFFC) | ((gain & 0xC) >> 2); + u16 ext_lna = (gain & 2) >> 1; + + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, + 0xFBFF, ext_lna << 10); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, + 0xF7FF, ext_lna << 11); + b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, lna); +} - for (i = 0; i < 10000; i++) { - if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) +static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain) +{ + u16 low_gain = gain & 0xFFFF; + u16 high_gain = (gain >> 16) & 0xF; + u16 ext_lna = (gain >> 21) & 0x1; + u16 trsw = ~(gain >> 20) & 0x1; + u16 tmp; + + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, + 0xFDFF, ext_lna << 9); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, + 0xFBFF, ext_lna << 10); + b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF0, high_gain); + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + tmp = (gain >> 2) & 0x3; + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, + 0xE7FF, tmp<<11); + b43_phy_maskset(dev, B43_PHY_OFDM(0xE6), 0xFFE7, tmp << 3); + } +} + +static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) +{ + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF); + if (dev->phy.rev >= 2) { + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF); + if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) + return; + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFF7); + } else { + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF); + } +} + +static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) +{ + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40); + if (dev->phy.rev >= 2) { + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100); + if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) + return; + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x8); + } else { + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200); + } +} + +static void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain) +{ + if (dev->phy.rev < 2) + lpphy_rev0_1_set_rx_gain(dev, gain); + else + lpphy_rev2plus_set_rx_gain(dev, gain); + lpphy_enable_rx_gain_override(dev); +} + +static void lpphy_set_rx_gain_by_index(struct b43_wldev *dev, u16 idx) +{ + u32 gain = b43_lptab_read(dev, B43_LPTAB16(12, idx)); + lpphy_set_rx_gain(dev, gain); +} + +static void lpphy_stop_ddfs(struct b43_wldev *dev) +{ + b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFD); + b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xFFDF); +} + +static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on, + int incr1, int incr2, int scale_idx) +{ + lpphy_stop_ddfs(dev); + b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0xFF80); + b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0x80FF); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0xFF80, incr1); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0x80FF, incr2 << 8); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF7, i_on << 3); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFEF, q_on << 4); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5); + b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB); + b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2); + b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x20); +} + +static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time, + struct lpphy_iq_est *iq_est) +{ + int i; + + b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFF7); + b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples); + b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time); + b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF); + b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFDFF); + + for (i = 0; i < 500; i++) { + if (!(b43_phy_read(dev, + B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) break; msleep(1); } - if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) - b43_radio_write(dev, B2063_TX_BB_SP3, tmp); + if ((b43_phy_read(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) { + b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8); + return false; + } - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); + iq_est->iq_prod = b43_phy_read(dev, B43_LPPHY_IQ_ACC_HI_ADDR); + iq_est->iq_prod <<= 16; + iq_est->iq_prod |= b43_phy_read(dev, B43_LPPHY_IQ_ACC_LO_ADDR); + + iq_est->i_pwr = b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_HI_ADDR); + iq_est->i_pwr <<= 16; + iq_est->i_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_LO_ADDR); + + iq_est->q_pwr = b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_HI_ADDR); + iq_est->q_pwr <<= 16; + iq_est->q_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_LO_ADDR); + + b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8); + return true; } -static void lpphy_calibrate_rc(struct b43_wldev *dev) +static int lpphy_loopback(struct b43_wldev *dev) { - struct b43_phy_lp *lpphy = dev->phy.lp; + struct lpphy_iq_est iq_est; + int i, index = -1; + u32 tmp; + + memset(&iq_est, 0, sizeof(iq_est)); + + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x3); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); + b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x8); + b43_radio_write(dev, B2062_N_TX_CTL_A, 0x80); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x80); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x80); + for (i = 0; i < 32; i++) { + lpphy_set_rx_gain_by_index(dev, i); + lpphy_run_ddfs(dev, 1, 1, 5, 5, 0); + if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est))) + continue; + tmp = (iq_est.i_pwr + iq_est.q_pwr) / 1000; + if ((tmp > 4000) && (tmp < 10000)) { + index = i; + break; + } + } + lpphy_stop_ddfs(dev); + return index; +} - if (dev->phy.rev >= 2) { - lpphy_rev2plus_rc_calib(dev); - } else if (!lpphy->rc_cap) { - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - lpphy_rev0_1_rc_calib(dev); +static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) +{ + u32 quotient, remainder, rbit, roundup, tmp; + + if (divisor == 0) { + quotient = 0; + remainder = 0; } else { - lpphy_set_rc_cap(dev); + quotient = dividend / divisor; + remainder = dividend % divisor; } + + rbit = divisor & 0x1; + roundup = (divisor >> 1) + rbit; + precision--; + + while (precision != 0xFF) { + tmp = remainder - roundup; + quotient <<= 1; + remainder <<= 1; + if (remainder >= roundup) { + remainder = (tmp << 1) + rbit; + quotient--; + } + precision--; + } + + if (remainder >= roundup) + quotient++; + + return quotient; } /* Read the TX power control mode from hardware. */ @@ -773,6 +1022,170 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev, lpphy_write_tx_pctl_mode_to_hardware(dev); } +static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + struct lpphy_iq_est iq_est; + struct lpphy_tx_gains tx_gains; + static const u32 ideal_pwr_table[22] = { + 0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64, + 0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35, + 0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088, + 0x0004c, 0x0002c, 0x0001a, 0xc0006, + }; + bool old_txg_ovr; + u8 old_bbmult; + u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval, + old_rf2_ovr, old_rf2_ovrval, old_phy_ctl, old_txpctl; + u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0; + int loopback, i, j, inner_sum; + + memset(&iq_est, 0, sizeof(iq_est)); + + b43_switch_channel(dev, 7); + old_txg_ovr = (b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) >> 6) & 1; + old_bbmult = lpphy_get_bb_mult(dev); + if (old_txg_ovr) + tx_gains = lpphy_get_tx_gains(dev); + old_rf_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_0); + old_rf_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_VAL_0); + old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR); + old_afe_ovrval = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVRVAL); + old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2); + old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL); + old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL); + old_txpctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD) & + B43_LPPHY_TX_PWR_CTL_CMD_MODE; + + lpphy_set_tx_power_control(dev, B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF); + lpphy_disable_crs(dev); + loopback = lpphy_loopback(dev); + if (loopback == -1) + goto finish; + lpphy_set_rx_gain_by_index(dev, loopback); + b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFFBF, 0x40); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFF8, 0x1); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFC7, 0x8); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F, 0xC0); + for (i = 128; i <= 159; i++) { + b43_radio_write(dev, B2062_N_RXBB_CALIB2, i); + inner_sum = 0; + for (j = 5; j <= 25; j++) { + lpphy_run_ddfs(dev, 1, 1, j, j, 0); + if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est))) + goto finish; + mean_sq_pwr = iq_est.i_pwr + iq_est.q_pwr; + if (j == 5) + tmp = mean_sq_pwr; + ideal_pwr = ((ideal_pwr_table[j-5] >> 3) + 1) >> 1; + normal_pwr = lpphy_qdiv_roundup(mean_sq_pwr, tmp, 12); + mean_sq_pwr = ideal_pwr - normal_pwr; + mean_sq_pwr *= mean_sq_pwr; + inner_sum += mean_sq_pwr; + if ((i = 128) || (inner_sum < mean_sq_pwr_min)) { + lpphy->rc_cap = i; + mean_sq_pwr_min = inner_sum; + } + } + } + lpphy_stop_ddfs(dev); + +finish: + lpphy_restore_crs(dev); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr); + b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval); + b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, old_afe_ovr); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, old_rf2_ovrval); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, old_rf2_ovr); + b43_phy_write(dev, B43_LPPHY_LP_PHY_CTL, old_phy_ctl); + + lpphy_set_bb_mult(dev, old_bbmult); + if (old_txg_ovr) { + /* + * SPEC FIXME: The specs say "get_tx_gains" here, which is + * illogical. According to lwfinger, vendor driver v4.150.10.5 + * has a Set here, while v4.174.64.19 has a Get - regression in + * the vendor driver? This should be tested this once the code + * is testable. + */ + lpphy_set_tx_gains(dev, tx_gains); + } + lpphy_set_tx_power_control(dev, old_txpctl); + if (lpphy->rc_cap) + lpphy_set_rc_cap(dev); +} + +static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; + u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF; + int i; + + b43_radio_write(dev, B2063_RX_BB_SP8, 0x0); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); + b43_radio_mask(dev, B2063_PLL_SP1, 0xF7); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); + b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15); + b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70); + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D); + + for (i = 0; i < 10000; i++) { + if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) + break; + msleep(1); + } + + if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) + b43_radio_write(dev, B2063_RX_BB_SP8, tmp); + + tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF; + + b43_radio_write(dev, B2063_TX_BB_SP3, 0x0); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); + b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55); + b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76); + + if (crystal_freq == 24000000) { + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0); + } else { + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); + } + + b43_radio_write(dev, B2063_PA_SP7, 0x7D); + + for (i = 0; i < 10000; i++) { + if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) + break; + msleep(1); + } + + if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) + b43_radio_write(dev, B2063_TX_BB_SP3, tmp); + + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); +} + +static void lpphy_calibrate_rc(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + + if (dev->phy.rev >= 2) { + lpphy_rev2plus_rc_calib(dev); + } else if (!lpphy->rc_cap) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + lpphy_rev0_1_rc_calib(dev); + } else { + lpphy_set_rc_cap(dev); + } +} + static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index) { struct b43_phy_lp *lpphy = dev->phy.lp; -- cgit v0.10.2 From 9028935d752ede57b086ab1bfe2420d4cba80127 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 14 Aug 2009 08:44:00 +0300 Subject: ASoC: TWL4030: Fix for capture mixer strings Change the strings related to capture in order to be interpreted correctly by alsamixer and possible other UI based mixer applications. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 1a65004..4df7c6c 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -399,16 +399,20 @@ SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum); /* Left analog microphone selection */ static const struct snd_kcontrol_new twl4030_dapm_analoglmic_controls[] = { - SOC_DAPM_SINGLE("Main mic", TWL4030_REG_ANAMICL, 0, 1, 0), - SOC_DAPM_SINGLE("Headset mic", TWL4030_REG_ANAMICL, 1, 1, 0), - SOC_DAPM_SINGLE("AUXL", TWL4030_REG_ANAMICL, 2, 1, 0), - SOC_DAPM_SINGLE("Carkit mic", TWL4030_REG_ANAMICL, 3, 1, 0), + SOC_DAPM_SINGLE("Main Mic Capture Switch", + TWL4030_REG_ANAMICL, 0, 1, 0), + SOC_DAPM_SINGLE("Headset Mic Capture Switch", + TWL4030_REG_ANAMICL, 1, 1, 0), + SOC_DAPM_SINGLE("AUXL Capture Switch", + TWL4030_REG_ANAMICL, 2, 1, 0), + SOC_DAPM_SINGLE("Carkit Mic Capture Switch", + TWL4030_REG_ANAMICL, 3, 1, 0), }; /* Right analog microphone selection */ static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = { - SOC_DAPM_SINGLE("Sub mic", TWL4030_REG_ANAMICR, 0, 1, 0), - SOC_DAPM_SINGLE("AUXR", TWL4030_REG_ANAMICR, 2, 1, 0), + SOC_DAPM_SINGLE("Sub Mic Capture Switch", TWL4030_REG_ANAMICR, 0, 1, 0), + SOC_DAPM_SINGLE("AUXR Capture Switch", TWL4030_REG_ANAMICR, 2, 1, 0), }; /* TX1 L/R Analog/Digital microphone selection */ @@ -1333,11 +1337,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_POST_REG), /* Analog input mixers for the capture amplifiers */ - SND_SOC_DAPM_MIXER("Analog Left Capture Route", + SND_SOC_DAPM_MIXER("Analog Left", TWL4030_REG_ANAMICL, 4, 0, &twl4030_dapm_analoglmic_controls[0], ARRAY_SIZE(twl4030_dapm_analoglmic_controls)), - SND_SOC_DAPM_MIXER("Analog Right Capture Route", + SND_SOC_DAPM_MIXER("Analog Right", TWL4030_REG_ANAMICR, 4, 0, &twl4030_dapm_analogrmic_controls[0], ARRAY_SIZE(twl4030_dapm_analogrmic_controls)), @@ -1446,16 +1450,16 @@ static const struct snd_soc_dapm_route intercon[] = { {"VIBRA", NULL, "Vibra Route"}, /* Capture path */ - {"Analog Left Capture Route", "Main mic", "MAINMIC"}, - {"Analog Left Capture Route", "Headset mic", "HSMIC"}, - {"Analog Left Capture Route", "AUXL", "AUXL"}, - {"Analog Left Capture Route", "Carkit mic", "CARKITMIC"}, + {"Analog Left", "Main Mic Capture Switch", "MAINMIC"}, + {"Analog Left", "Headset Mic Capture Switch", "HSMIC"}, + {"Analog Left", "AUXL Capture Switch", "AUXL"}, + {"Analog Left", "Carkit Mic Capture Switch", "CARKITMIC"}, - {"Analog Right Capture Route", "Sub mic", "SUBMIC"}, - {"Analog Right Capture Route", "AUXR", "AUXR"}, + {"Analog Right", "Sub Mic Capture Switch", "SUBMIC"}, + {"Analog Right", "AUXR Capture Switch", "AUXR"}, - {"ADC Physical Left", NULL, "Analog Left Capture Route"}, - {"ADC Physical Right", NULL, "Analog Right Capture Route"}, + {"ADC Physical Left", NULL, "Analog Left"}, + {"ADC Physical Right", NULL, "Analog Right"}, {"Digimic0 Enable", NULL, "DIGIMIC0"}, {"Digimic1 Enable", NULL, "DIGIMIC1"}, @@ -1479,11 +1483,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"ADC Virtual Right2", NULL, "TX2 Capture Route"}, /* Analog bypass routes */ - {"Right1 Analog Loopback", "Switch", "Analog Right Capture Route"}, - {"Left1 Analog Loopback", "Switch", "Analog Left Capture Route"}, - {"Right2 Analog Loopback", "Switch", "Analog Right Capture Route"}, - {"Left2 Analog Loopback", "Switch", "Analog Left Capture Route"}, - {"Voice Analog Loopback", "Switch", "Analog Left Capture Route"}, + {"Right1 Analog Loopback", "Switch", "Analog Right"}, + {"Left1 Analog Loopback", "Switch", "Analog Left"}, + {"Right2 Analog Loopback", "Switch", "Analog Right"}, + {"Left2 Analog Loopback", "Switch", "Analog Left"}, + {"Voice Analog Loopback", "Switch", "Analog Left"}, {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"}, {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"}, -- cgit v0.10.2 From 2a708137fd7d3e0928f27157aaed8aba404b11c9 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Fri, 14 Aug 2009 12:06:38 +0800 Subject: ASoC: delete -spi suffix in ad1938 and free private data while registers fail Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 051f68c..e62b277 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -456,7 +456,7 @@ static int __devexit ad1938_spi_remove(struct spi_device *spi) static struct spi_driver ad1938_spi_driver = { .driver = { - .name = "ad1938-spi", + .name = "ad1938", .bus = &spi_bus_type, .owner = THIS_MODULE, }, @@ -543,6 +543,7 @@ static int ad1938_register(struct ad1938_priv *ad1938) ret = snd_soc_register_codec(codec); if (ret != 0) { dev_err(codec->dev, "Failed to register codec: %d\n", ret); + kfree(ad1938); return ret; } @@ -550,6 +551,7 @@ static int ad1938_register(struct ad1938_priv *ad1938) if (ret != 0) { dev_err(codec->dev, "Failed to register DAI: %d\n", ret); snd_soc_unregister_codec(codec); + kfree(ad1938); return ret; } -- cgit v0.10.2 From 9f162d2a810b4db48f7b8d7e734d0932c81ec2a1 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:18:44 +0300 Subject: sunrpc: hton -> cpu_to_be* htonl is already defined as cpu_to_be32. cpu_to_be64 has architecture specific optimized implementations. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index b99c625..f94bbdc 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -117,9 +117,8 @@ static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int le static inline __be32 * xdr_encode_hyper(__be32 *p, __u64 val) { - *p++ = htonl(val >> 32); - *p++ = htonl(val & 0xFFFFFFFF); - return p; + *(__be64 *)p = cpu_to_be64(val); + return p + 2; } static inline __be32 * diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 406e26d..0d05d25 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -24,7 +24,7 @@ xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj) unsigned int quadlen = XDR_QUADLEN(obj->len); p[quadlen] = 0; /* zero trailing bytes */ - *p++ = htonl(obj->len); + *p++ = cpu_to_be32(obj->len); memcpy(p, obj->data, obj->len); return p + XDR_QUADLEN(obj->len); } @@ -83,7 +83,7 @@ EXPORT_SYMBOL_GPL(xdr_encode_opaque_fixed); */ __be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int nbytes) { - *p++ = htonl(nbytes); + *p++ = cpu_to_be32(nbytes); return xdr_encode_opaque_fixed(p, ptr, nbytes); } EXPORT_SYMBOL_GPL(xdr_encode_opaque); @@ -779,7 +779,7 @@ EXPORT_SYMBOL_GPL(xdr_decode_word); int xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj) { - __be32 raw = htonl(obj); + __be32 raw = cpu_to_be32(obj); return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj)); } -- cgit v0.10.2 From 98866b5abe1513cdacc011874ca045d40002eccd Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:18:49 +0300 Subject: sunrpc: ntoh -> be*_to_cpu ntohl is already defined as be32_to_cpu. be64_to_cpu has architecture specific optimized implementations. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index f94bbdc..7da466b 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -124,9 +124,8 @@ xdr_encode_hyper(__be32 *p, __u64 val) static inline __be32 * xdr_decode_hyper(__be32 *p, __u64 *valp) { - *valp = ((__u64) ntohl(*p++)) << 32; - *valp |= ntohl(*p++); - return p; + *valp = be64_to_cpup((__be64 *)p); + return p + 2; } /* diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 0d05d25..8bd690c 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -35,7 +35,7 @@ xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj) { unsigned int len; - if ((len = ntohl(*p++)) > XDR_MAX_NETOBJ) + if ((len = be32_to_cpu(*p++)) > XDR_MAX_NETOBJ) return NULL; obj->len = len; obj->data = (u8 *) p; @@ -101,7 +101,7 @@ xdr_decode_string_inplace(__be32 *p, char **sp, { u32 len; - len = ntohl(*p++); + len = be32_to_cpu(*p++); if (len > maxlen) return NULL; *lenp = len; @@ -771,7 +771,7 @@ xdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj) status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj)); if (status) return status; - *obj = ntohl(raw); + *obj = be32_to_cpu(raw); return 0; } EXPORT_SYMBOL_GPL(xdr_decode_word); -- cgit v0.10.2 From e75bc1c89e0c7dda0b140408ddee2ffaef7ba6d4 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:18:54 +0300 Subject: nfs: nfs4xdr: get rid of WRITE32 s/WRITE32/*p++ = cpu_to_be32/ Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 617273e..9a03b24 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -712,7 +712,6 @@ struct compound_hdr { * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define WRITE32(n) *p++ = htonl(n) #define WRITE64(n) do { \ *p++ = htonl((uint32_t)((n) >> 32)); \ *p++ = htonl((uint32_t)(n)); \ @@ -750,11 +749,11 @@ static void encode_compound_hdr(struct xdr_stream *xdr, dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); - WRITE32(hdr->taglen); + *p++ = cpu_to_be32(hdr->taglen); WRITEMEM(hdr->tag, hdr->taglen); - WRITE32(hdr->minorversion); + *p++ = cpu_to_be32(hdr->minorversion); hdr->nops_p = p; - WRITE32(hdr->nops); + *p++ = cpu_to_be32(hdr->nops); } static void encode_nops(struct compound_hdr *hdr) @@ -835,7 +834,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const * We write the bitmap length now, but leave the bitmap and the attribute * buffer length to be backfilled at the end of this routine. */ - WRITE32(2); + *p++ = cpu_to_be32(2); q = p; p += 3; @@ -845,39 +844,39 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const } if (iap->ia_valid & ATTR_MODE) { bmval1 |= FATTR4_WORD1_MODE; - WRITE32(iap->ia_mode & S_IALLUGO); + *p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO); } if (iap->ia_valid & ATTR_UID) { bmval1 |= FATTR4_WORD1_OWNER; - WRITE32(owner_namelen); + *p++ = cpu_to_be32(owner_namelen); WRITEMEM(owner_name, owner_namelen); } if (iap->ia_valid & ATTR_GID) { bmval1 |= FATTR4_WORD1_OWNER_GROUP; - WRITE32(owner_grouplen); + *p++ = cpu_to_be32(owner_grouplen); WRITEMEM(owner_group, owner_grouplen); } if (iap->ia_valid & ATTR_ATIME_SET) { bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; - WRITE32(NFS4_SET_TO_CLIENT_TIME); - WRITE32(0); - WRITE32(iap->ia_mtime.tv_sec); - WRITE32(iap->ia_mtime.tv_nsec); + *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); + *p++ = cpu_to_be32(0); + *p++ = cpu_to_be32(iap->ia_mtime.tv_sec); + *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec); } else if (iap->ia_valid & ATTR_ATIME) { bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; - WRITE32(NFS4_SET_TO_SERVER_TIME); + *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME); } if (iap->ia_valid & ATTR_MTIME_SET) { bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; - WRITE32(NFS4_SET_TO_CLIENT_TIME); - WRITE32(0); - WRITE32(iap->ia_mtime.tv_sec); - WRITE32(iap->ia_mtime.tv_nsec); + *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); + *p++ = cpu_to_be32(0); + *p++ = cpu_to_be32(iap->ia_mtime.tv_sec); + *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec); } else if (iap->ia_valid & ATTR_MTIME) { bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; - WRITE32(NFS4_SET_TO_SERVER_TIME); + *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME); } /* @@ -901,8 +900,8 @@ static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hd __be32 *p; RESERVE_SPACE(8); - WRITE32(OP_ACCESS); - WRITE32(access); + *p++ = cpu_to_be32(OP_ACCESS); + *p++ = cpu_to_be32(access); hdr->nops++; hdr->replen += decode_access_maxsz; } @@ -912,8 +911,8 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg __be32 *p; RESERVE_SPACE(8+NFS4_STATEID_SIZE); - WRITE32(OP_CLOSE); - WRITE32(arg->seqid->sequence->counter); + *p++ = cpu_to_be32(OP_CLOSE); + *p++ = cpu_to_be32(arg->seqid->sequence->counter); WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); hdr->nops++; hdr->replen += decode_close_maxsz; @@ -924,9 +923,9 @@ static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *ar __be32 *p; RESERVE_SPACE(16); - WRITE32(OP_COMMIT); + *p++ = cpu_to_be32(OP_COMMIT); WRITE64(args->offset); - WRITE32(args->count); + *p++ = cpu_to_be32(args->count); hdr->nops++; hdr->replen += decode_commit_maxsz; } @@ -936,20 +935,20 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * __be32 *p; RESERVE_SPACE(8); - WRITE32(OP_CREATE); - WRITE32(create->ftype); + *p++ = cpu_to_be32(OP_CREATE); + *p++ = cpu_to_be32(create->ftype); switch (create->ftype) { case NF4LNK: RESERVE_SPACE(4); - WRITE32(create->u.symlink.len); + *p++ = cpu_to_be32(create->u.symlink.len); xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len); break; case NF4BLK: case NF4CHR: RESERVE_SPACE(8); - WRITE32(create->u.device.specdata1); - WRITE32(create->u.device.specdata2); + *p++ = cpu_to_be32(create->u.device.specdata1); + *p++ = cpu_to_be32(create->u.device.specdata2); break; default: @@ -957,7 +956,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * } RESERVE_SPACE(4 + create->name->len); - WRITE32(create->name->len); + *p++ = cpu_to_be32(create->name->len); WRITEMEM(create->name->name, create->name->len); hdr->nops++; hdr->replen += decode_create_maxsz; @@ -970,9 +969,9 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c __be32 *p; RESERVE_SPACE(12); - WRITE32(OP_GETATTR); - WRITE32(1); - WRITE32(bitmap); + *p++ = cpu_to_be32(OP_GETATTR); + *p++ = cpu_to_be32(1); + *p++ = cpu_to_be32(bitmap); hdr->nops++; hdr->replen += decode_getattr_maxsz; } @@ -982,10 +981,10 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm __be32 *p; RESERVE_SPACE(16); - WRITE32(OP_GETATTR); - WRITE32(2); - WRITE32(bm0); - WRITE32(bm1); + *p++ = cpu_to_be32(OP_GETATTR); + *p++ = cpu_to_be32(2); + *p++ = cpu_to_be32(bm0); + *p++ = cpu_to_be32(bm1); hdr->nops++; hdr->replen += decode_getattr_maxsz; } @@ -1013,7 +1012,7 @@ static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) __be32 *p; RESERVE_SPACE(4); - WRITE32(OP_GETFH); + *p++ = cpu_to_be32(OP_GETFH); hdr->nops++; hdr->replen += decode_getfh_maxsz; } @@ -1023,8 +1022,8 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct __be32 *p; RESERVE_SPACE(8 + name->len); - WRITE32(OP_LINK); - WRITE32(name->len); + *p++ = cpu_to_be32(OP_LINK); + *p++ = cpu_to_be32(name->len); WRITEMEM(name->name, name->len); hdr->nops++; hdr->replen += decode_link_maxsz; @@ -1053,26 +1052,26 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args __be32 *p; RESERVE_SPACE(32); - WRITE32(OP_LOCK); - WRITE32(nfs4_lock_type(args->fl, args->block)); - WRITE32(args->reclaim); + *p++ = cpu_to_be32(OP_LOCK); + *p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block)); + *p++ = cpu_to_be32(args->reclaim); WRITE64(args->fl->fl_start); WRITE64(nfs4_lock_length(args->fl)); - WRITE32(args->new_lock_owner); + *p++ = cpu_to_be32(args->new_lock_owner); if (args->new_lock_owner){ RESERVE_SPACE(4+NFS4_STATEID_SIZE+32); - WRITE32(args->open_seqid->sequence->counter); + *p++ = cpu_to_be32(args->open_seqid->sequence->counter); WRITEMEM(args->open_stateid->data, NFS4_STATEID_SIZE); - WRITE32(args->lock_seqid->sequence->counter); + *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); WRITE64(args->lock_owner.clientid); - WRITE32(16); + *p++ = cpu_to_be32(16); WRITEMEM("lock id:", 8); WRITE64(args->lock_owner.id); } else { RESERVE_SPACE(NFS4_STATEID_SIZE+4); WRITEMEM(args->lock_stateid->data, NFS4_STATEID_SIZE); - WRITE32(args->lock_seqid->sequence->counter); + *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); } hdr->nops++; hdr->replen += decode_lock_maxsz; @@ -1083,12 +1082,12 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar __be32 *p; RESERVE_SPACE(52); - WRITE32(OP_LOCKT); - WRITE32(nfs4_lock_type(args->fl, 0)); + *p++ = cpu_to_be32(OP_LOCKT); + *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); WRITE64(args->fl->fl_start); WRITE64(nfs4_lock_length(args->fl)); WRITE64(args->lock_owner.clientid); - WRITE32(16); + *p++ = cpu_to_be32(16); WRITEMEM("lock id:", 8); WRITE64(args->lock_owner.id); hdr->nops++; @@ -1100,9 +1099,9 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar __be32 *p; RESERVE_SPACE(12+NFS4_STATEID_SIZE+16); - WRITE32(OP_LOCKU); - WRITE32(nfs4_lock_type(args->fl, 0)); - WRITE32(args->seqid->sequence->counter); + *p++ = cpu_to_be32(OP_LOCKU); + *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); + *p++ = cpu_to_be32(args->seqid->sequence->counter); WRITEMEM(args->stateid->data, NFS4_STATEID_SIZE); WRITE64(args->fl->fl_start); WRITE64(nfs4_lock_length(args->fl)); @@ -1116,8 +1115,8 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc __be32 *p; RESERVE_SPACE(8 + len); - WRITE32(OP_LOOKUP); - WRITE32(len); + *p++ = cpu_to_be32(OP_LOOKUP); + *p++ = cpu_to_be32(len); WRITEMEM(name->name, len); hdr->nops++; hdr->replen += decode_lookup_maxsz; @@ -1130,18 +1129,18 @@ static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) RESERVE_SPACE(8); switch (fmode & (FMODE_READ|FMODE_WRITE)) { case FMODE_READ: - WRITE32(NFS4_SHARE_ACCESS_READ); + *p++ = cpu_to_be32(NFS4_SHARE_ACCESS_READ); break; case FMODE_WRITE: - WRITE32(NFS4_SHARE_ACCESS_WRITE); + *p++ = cpu_to_be32(NFS4_SHARE_ACCESS_WRITE); break; case FMODE_READ|FMODE_WRITE: - WRITE32(NFS4_SHARE_ACCESS_BOTH); + *p++ = cpu_to_be32(NFS4_SHARE_ACCESS_BOTH); break; default: - WRITE32(0); + *p++ = cpu_to_be32(0); } - WRITE32(0); /* for linux, share_deny = 0 always */ + *p++ = cpu_to_be32(0); /* for linux, share_deny = 0 always */ } static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg) @@ -1152,12 +1151,12 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena * owner 4 = 32 */ RESERVE_SPACE(8); - WRITE32(OP_OPEN); - WRITE32(arg->seqid->sequence->counter); + *p++ = cpu_to_be32(OP_OPEN); + *p++ = cpu_to_be32(arg->seqid->sequence->counter); encode_share_access(xdr, arg->fmode); RESERVE_SPACE(28); WRITE64(arg->clientid); - WRITE32(16); + *p++ = cpu_to_be32(16); WRITEMEM("open id:", 8); WRITE64(arg->id); } @@ -1169,11 +1168,11 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op RESERVE_SPACE(4); switch(arg->open_flags & O_EXCL) { case 0: - WRITE32(NFS4_CREATE_UNCHECKED); + *p++ = cpu_to_be32(NFS4_CREATE_UNCHECKED); encode_attrs(xdr, arg->u.attrs, arg->server); break; default: - WRITE32(NFS4_CREATE_EXCLUSIVE); + *p++ = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); encode_nfs4_verifier(xdr, &arg->u.verifier); } } @@ -1185,11 +1184,11 @@ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *a RESERVE_SPACE(4); switch (arg->open_flags & O_CREAT) { case 0: - WRITE32(NFS4_OPEN_NOCREATE); + *p++ = cpu_to_be32(NFS4_OPEN_NOCREATE); break; default: BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL); - WRITE32(NFS4_OPEN_CREATE); + *p++ = cpu_to_be32(NFS4_OPEN_CREATE); encode_createmode(xdr, arg); } } @@ -1201,13 +1200,13 @@ static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delega RESERVE_SPACE(4); switch (delegation_type) { case 0: - WRITE32(NFS4_OPEN_DELEGATE_NONE); + *p++ = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE); break; case FMODE_READ: - WRITE32(NFS4_OPEN_DELEGATE_READ); + *p++ = cpu_to_be32(NFS4_OPEN_DELEGATE_READ); break; case FMODE_WRITE|FMODE_READ: - WRITE32(NFS4_OPEN_DELEGATE_WRITE); + *p++ = cpu_to_be32(NFS4_OPEN_DELEGATE_WRITE); break; default: BUG(); @@ -1219,7 +1218,7 @@ static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr * __be32 *p; RESERVE_SPACE(4); - WRITE32(NFS4_OPEN_CLAIM_NULL); + *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_NULL); encode_string(xdr, name->len, name->name); } @@ -1228,7 +1227,7 @@ static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type) __be32 *p; RESERVE_SPACE(4); - WRITE32(NFS4_OPEN_CLAIM_PREVIOUS); + *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS); encode_delegation_type(xdr, type); } @@ -1237,7 +1236,7 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc __be32 *p; RESERVE_SPACE(4+NFS4_STATEID_SIZE); - WRITE32(NFS4_OPEN_CLAIM_DELEGATE_CUR); + *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR); WRITEMEM(stateid->data, NFS4_STATEID_SIZE); encode_string(xdr, name->len, name->name); } @@ -1268,9 +1267,9 @@ static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_co __be32 *p; RESERVE_SPACE(4+NFS4_STATEID_SIZE+4); - WRITE32(OP_OPEN_CONFIRM); + *p++ = cpu_to_be32(OP_OPEN_CONFIRM); WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); - WRITE32(arg->seqid->sequence->counter); + *p++ = cpu_to_be32(arg->seqid->sequence->counter); hdr->nops++; hdr->replen += decode_open_confirm_maxsz; } @@ -1280,9 +1279,9 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close __be32 *p; RESERVE_SPACE(4+NFS4_STATEID_SIZE+4); - WRITE32(OP_OPEN_DOWNGRADE); + *p++ = cpu_to_be32(OP_OPEN_DOWNGRADE); WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); - WRITE32(arg->seqid->sequence->counter); + *p++ = cpu_to_be32(arg->seqid->sequence->counter); encode_share_access(xdr, arg->fmode); hdr->nops++; hdr->replen += decode_open_downgrade_maxsz; @@ -1295,8 +1294,8 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd __be32 *p; RESERVE_SPACE(8 + len); - WRITE32(OP_PUTFH); - WRITE32(len); + *p++ = cpu_to_be32(OP_PUTFH); + *p++ = cpu_to_be32(len); WRITEMEM(fh->data, len); hdr->nops++; hdr->replen += decode_putfh_maxsz; @@ -1307,7 +1306,7 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) __be32 *p; RESERVE_SPACE(4); - WRITE32(OP_PUTROOTFH); + *p++ = cpu_to_be32(OP_PUTROOTFH); hdr->nops++; hdr->replen += decode_putrootfh_maxsz; } @@ -1330,13 +1329,13 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, __be32 *p; RESERVE_SPACE(4); - WRITE32(OP_READ); + *p++ = cpu_to_be32(OP_READ); encode_stateid(xdr, args->context); RESERVE_SPACE(12); WRITE64(args->offset); - WRITE32(args->count); + *p++ = cpu_to_be32(args->count); hdr->nops++; hdr->replen += decode_read_maxsz; } @@ -1350,19 +1349,19 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg __be32 *p; RESERVE_SPACE(12+NFS4_VERIFIER_SIZE+20); - WRITE32(OP_READDIR); + *p++ = cpu_to_be32(OP_READDIR); WRITE64(readdir->cookie); WRITEMEM(readdir->verifier.data, NFS4_VERIFIER_SIZE); - WRITE32(readdir->count >> 1); /* We're not doing readdirplus */ - WRITE32(readdir->count); - WRITE32(2); + *p++ = cpu_to_be32(readdir->count >> 1); /* We're not doing readdirplus */ + *p++ = cpu_to_be32(readdir->count); + *p++ = cpu_to_be32(2); /* Switch to mounted_on_fileid if the server supports it */ if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) attrs[0] &= ~FATTR4_WORD0_FILEID; else attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; - WRITE32(attrs[0] & readdir->bitmask[0]); - WRITE32(attrs[1] & readdir->bitmask[1]); + *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); + *p++ = cpu_to_be32(attrs[1] & readdir->bitmask[1]); hdr->nops++; hdr->replen += decode_readdir_maxsz; dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", @@ -1379,7 +1378,7 @@ static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink * __be32 *p; RESERVE_SPACE(4); - WRITE32(OP_READLINK); + *p++ = cpu_to_be32(OP_READLINK); hdr->nops++; hdr->replen += decode_readlink_maxsz; } @@ -1389,8 +1388,8 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc __be32 *p; RESERVE_SPACE(8 + name->len); - WRITE32(OP_REMOVE); - WRITE32(name->len); + *p++ = cpu_to_be32(OP_REMOVE); + *p++ = cpu_to_be32(name->len); WRITEMEM(name->name, name->len); hdr->nops++; hdr->replen += decode_remove_maxsz; @@ -1401,12 +1400,12 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co __be32 *p; RESERVE_SPACE(8 + oldname->len); - WRITE32(OP_RENAME); - WRITE32(oldname->len); + *p++ = cpu_to_be32(OP_RENAME); + *p++ = cpu_to_be32(oldname->len); WRITEMEM(oldname->name, oldname->len); RESERVE_SPACE(4 + newname->len); - WRITE32(newname->len); + *p++ = cpu_to_be32(newname->len); WRITEMEM(newname->name, newname->len); hdr->nops++; hdr->replen += decode_rename_maxsz; @@ -1417,7 +1416,7 @@ static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client __be32 *p; RESERVE_SPACE(12); - WRITE32(OP_RENEW); + *p++ = cpu_to_be32(OP_RENEW); WRITE64(client_stateid->cl_clientid); hdr->nops++; hdr->replen += decode_renew_maxsz; @@ -1429,7 +1428,7 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) __be32 *p; RESERVE_SPACE(4); - WRITE32(OP_RESTOREFH); + *p++ = cpu_to_be32(OP_RESTOREFH); hdr->nops++; hdr->replen += decode_restorefh_maxsz; } @@ -1440,15 +1439,15 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun __be32 *p; RESERVE_SPACE(4+NFS4_STATEID_SIZE); - WRITE32(OP_SETATTR); + *p++ = cpu_to_be32(OP_SETATTR); WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE); RESERVE_SPACE(2*4); - WRITE32(1); - WRITE32(FATTR4_WORD0_ACL); + *p++ = cpu_to_be32(1); + *p++ = cpu_to_be32(FATTR4_WORD0_ACL); if (arg->acl_len % 4) return -EINVAL; RESERVE_SPACE(4); - WRITE32(arg->acl_len); + *p++ = cpu_to_be32(arg->acl_len); xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); hdr->nops++; hdr->replen += decode_setacl_maxsz; @@ -1461,7 +1460,7 @@ encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) __be32 *p; RESERVE_SPACE(4); - WRITE32(OP_SAVEFH); + *p++ = cpu_to_be32(OP_SAVEFH); hdr->nops++; hdr->replen += decode_savefh_maxsz; } @@ -1471,7 +1470,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs __be32 *p; RESERVE_SPACE(4+NFS4_STATEID_SIZE); - WRITE32(OP_SETATTR); + *p++ = cpu_to_be32(OP_SETATTR); WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); hdr->nops++; hdr->replen += decode_setattr_maxsz; @@ -1483,16 +1482,16 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie __be32 *p; RESERVE_SPACE(4 + NFS4_VERIFIER_SIZE); - WRITE32(OP_SETCLIENTID); + *p++ = cpu_to_be32(OP_SETCLIENTID); WRITEMEM(setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE); encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); RESERVE_SPACE(4); - WRITE32(setclientid->sc_prog); + *p++ = cpu_to_be32(setclientid->sc_prog); encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid); encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr); RESERVE_SPACE(4); - WRITE32(setclientid->sc_cb_ident); + *p++ = cpu_to_be32(setclientid->sc_cb_ident); hdr->nops++; hdr->replen += decode_setclientid_maxsz; } @@ -1502,7 +1501,7 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_ __be32 *p; RESERVE_SPACE(12 + NFS4_VERIFIER_SIZE); - WRITE32(OP_SETCLIENTID_CONFIRM); + *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); WRITE64(client_state->cl_clientid); WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); hdr->nops++; @@ -1514,14 +1513,14 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg __be32 *p; RESERVE_SPACE(4); - WRITE32(OP_WRITE); + *p++ = cpu_to_be32(OP_WRITE); encode_stateid(xdr, args->context); RESERVE_SPACE(16); WRITE64(args->offset); - WRITE32(args->stable); - WRITE32(args->count); + *p++ = cpu_to_be32(args->stable); + *p++ = cpu_to_be32(args->count); xdr_write_pages(xdr, args->pages, args->pgbase, args->count); hdr->nops++; @@ -1534,7 +1533,7 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state RESERVE_SPACE(4+NFS4_STATEID_SIZE); - WRITE32(OP_DELEGRETURN); + *p++ = cpu_to_be32(OP_DELEGRETURN); WRITEMEM(stateid->data, NFS4_STATEID_SIZE); hdr->nops++; hdr->replen += decode_delegreturn_maxsz; @@ -1549,15 +1548,15 @@ static void encode_exchange_id(struct xdr_stream *xdr, __be32 *p; RESERVE_SPACE(4 + sizeof(args->verifier->data)); - WRITE32(OP_EXCHANGE_ID); + *p++ = cpu_to_be32(OP_EXCHANGE_ID); WRITEMEM(args->verifier->data, sizeof(args->verifier->data)); encode_string(xdr, args->id_len, args->id); RESERVE_SPACE(12); - WRITE32(args->flags); - WRITE32(0); /* zero length state_protect4_a */ - WRITE32(0); /* zero length implementation id array */ + *p++ = cpu_to_be32(args->flags); + *p++ = cpu_to_be32(0); /* zero length state_protect4_a */ + *p++ = cpu_to_be32(0); /* zero length implementation id array */ hdr->nops++; hdr->replen += decode_exchange_id_maxsz; } @@ -1572,54 +1571,54 @@ static void encode_create_session(struct xdr_stream *xdr, struct nfs_client *clp = args->client; RESERVE_SPACE(4); - WRITE32(OP_CREATE_SESSION); + *p++ = cpu_to_be32(OP_CREATE_SESSION); RESERVE_SPACE(8); WRITE64(clp->cl_ex_clid); RESERVE_SPACE(8); - WRITE32(clp->cl_seqid); /*Sequence id */ - WRITE32(args->flags); /*flags */ + *p++ = cpu_to_be32(clp->cl_seqid); /*Sequence id */ + *p++ = cpu_to_be32(args->flags); /*flags */ RESERVE_SPACE(2*28); /* 2 channel_attrs */ /* Fore Channel */ - WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ - WRITE32(args->fc_attrs.max_rqst_sz); /* max req size */ - WRITE32(args->fc_attrs.max_resp_sz); /* max resp size */ - WRITE32(args->fc_attrs.max_resp_sz_cached); /* Max resp sz cached */ - WRITE32(args->fc_attrs.max_ops); /* max operations */ - WRITE32(args->fc_attrs.max_reqs); /* max requests */ - WRITE32(0); /* rdmachannel_attrs */ + *p++ = cpu_to_be32(args->fc_attrs.headerpadsz); /* header padding size */ + *p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz); /* max req size */ + *p++ = cpu_to_be32(args->fc_attrs.max_resp_sz); /* max resp size */ + *p++ = cpu_to_be32(args->fc_attrs.max_resp_sz_cached); /* Max resp sz cached */ + *p++ = cpu_to_be32(args->fc_attrs.max_ops); /* max operations */ + *p++ = cpu_to_be32(args->fc_attrs.max_reqs); /* max requests */ + *p++ = cpu_to_be32(0); /* rdmachannel_attrs */ /* Back Channel */ - WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ - WRITE32(args->bc_attrs.max_rqst_sz); /* max req size */ - WRITE32(args->bc_attrs.max_resp_sz); /* max resp size */ - WRITE32(args->bc_attrs.max_resp_sz_cached); /* Max resp sz cached */ - WRITE32(args->bc_attrs.max_ops); /* max operations */ - WRITE32(args->bc_attrs.max_reqs); /* max requests */ - WRITE32(0); /* rdmachannel_attrs */ + *p++ = cpu_to_be32(args->fc_attrs.headerpadsz); /* header padding size */ + *p++ = cpu_to_be32(args->bc_attrs.max_rqst_sz); /* max req size */ + *p++ = cpu_to_be32(args->bc_attrs.max_resp_sz); /* max resp size */ + *p++ = cpu_to_be32(args->bc_attrs.max_resp_sz_cached); /* Max resp sz cached */ + *p++ = cpu_to_be32(args->bc_attrs.max_ops); /* max operations */ + *p++ = cpu_to_be32(args->bc_attrs.max_reqs); /* max requests */ + *p++ = cpu_to_be32(0); /* rdmachannel_attrs */ RESERVE_SPACE(4); - WRITE32(args->cb_program); /* cb_program */ + *p++ = cpu_to_be32(args->cb_program); /* cb_program */ RESERVE_SPACE(4); /* # of security flavors */ - WRITE32(1); + *p++ = cpu_to_be32(1); RESERVE_SPACE(4); - WRITE32(RPC_AUTH_UNIX); /* auth_sys */ + *p++ = cpu_to_be32(RPC_AUTH_UNIX); /* auth_sys */ /* authsys_parms rfc1831 */ RESERVE_SPACE(4); - WRITE32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ + *p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ len = scnprintf(machine_name, sizeof(machine_name), "%s", clp->cl_ipaddr); RESERVE_SPACE(16 + len); - WRITE32(len); + *p++ = cpu_to_be32(len); WRITEMEM(machine_name, len); - WRITE32(0); /* UID */ - WRITE32(0); /* GID */ - WRITE32(0); /* No more gids */ + *p++ = cpu_to_be32(0); /* UID */ + *p++ = cpu_to_be32(0); /* GID */ + *p++ = cpu_to_be32(0); /* No more gids */ hdr->nops++; hdr->replen += decode_create_session_maxsz; } @@ -1630,7 +1629,7 @@ static void encode_destroy_session(struct xdr_stream *xdr, { __be32 *p; RESERVE_SPACE(4 + NFS4_MAX_SESSIONID_LEN); - WRITE32(OP_DESTROY_SESSION); + *p++ = cpu_to_be32(OP_DESTROY_SESSION); WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); hdr->nops++; hdr->replen += decode_destroy_session_maxsz; @@ -1656,7 +1655,7 @@ static void encode_sequence(struct xdr_stream *xdr, slot = tp->slots + args->sa_slotid; RESERVE_SPACE(4); - WRITE32(OP_SEQUENCE); + *p++ = cpu_to_be32(OP_SEQUENCE); /* * Sessionid + seqid + slotid + max slotid + cache_this @@ -1672,10 +1671,10 @@ static void encode_sequence(struct xdr_stream *xdr, tp->highest_used_slotid, args->sa_cache_this); RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 16); WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); - WRITE32(slot->seq_nr); - WRITE32(args->sa_slotid); - WRITE32(tp->highest_used_slotid); - WRITE32(args->sa_cache_this); + *p++ = cpu_to_be32(slot->seq_nr); + *p++ = cpu_to_be32(args->sa_slotid); + *p++ = cpu_to_be32(tp->highest_used_slotid); + *p++ = cpu_to_be32(args->sa_cache_this); hdr->nops++; hdr->replen += decode_sequence_maxsz; #endif /* CONFIG_NFS_V4_1 */ -- cgit v0.10.2 From b95be5a976848febff82edb21d5b4351b3997bf6 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:01 +0300 Subject: nfs: nfs4xdr: get rid of WRITE64 s/WRITE64/p = xdr_encode_hyper(p, / Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 9a03b24..5d80766 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -712,10 +712,6 @@ struct compound_hdr { * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define WRITE64(n) do { \ - *p++ = htonl((uint32_t)((n) >> 32)); \ - *p++ = htonl((uint32_t)(n)); \ -} while (0) #define WRITEMEM(ptr,nbytes) do { \ p = xdr_encode_opaque_fixed(p, ptr, nbytes); \ } while (0) @@ -840,7 +836,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const if (iap->ia_valid & ATTR_SIZE) { bmval0 |= FATTR4_WORD0_SIZE; - WRITE64(iap->ia_size); + p = xdr_encode_hyper(p, iap->ia_size); } if (iap->ia_valid & ATTR_MODE) { bmval1 |= FATTR4_WORD1_MODE; @@ -924,7 +920,7 @@ static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *ar RESERVE_SPACE(16); *p++ = cpu_to_be32(OP_COMMIT); - WRITE64(args->offset); + p = xdr_encode_hyper(p, args->offset); *p++ = cpu_to_be32(args->count); hdr->nops++; hdr->replen += decode_commit_maxsz; @@ -1055,18 +1051,18 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args *p++ = cpu_to_be32(OP_LOCK); *p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block)); *p++ = cpu_to_be32(args->reclaim); - WRITE64(args->fl->fl_start); - WRITE64(nfs4_lock_length(args->fl)); + p = xdr_encode_hyper(p, args->fl->fl_start); + p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); *p++ = cpu_to_be32(args->new_lock_owner); if (args->new_lock_owner){ RESERVE_SPACE(4+NFS4_STATEID_SIZE+32); *p++ = cpu_to_be32(args->open_seqid->sequence->counter); WRITEMEM(args->open_stateid->data, NFS4_STATEID_SIZE); *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); - WRITE64(args->lock_owner.clientid); + p = xdr_encode_hyper(p, args->lock_owner.clientid); *p++ = cpu_to_be32(16); WRITEMEM("lock id:", 8); - WRITE64(args->lock_owner.id); + p = xdr_encode_hyper(p, args->lock_owner.id); } else { RESERVE_SPACE(NFS4_STATEID_SIZE+4); @@ -1084,12 +1080,12 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar RESERVE_SPACE(52); *p++ = cpu_to_be32(OP_LOCKT); *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); - WRITE64(args->fl->fl_start); - WRITE64(nfs4_lock_length(args->fl)); - WRITE64(args->lock_owner.clientid); + p = xdr_encode_hyper(p, args->fl->fl_start); + p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); + p = xdr_encode_hyper(p, args->lock_owner.clientid); *p++ = cpu_to_be32(16); WRITEMEM("lock id:", 8); - WRITE64(args->lock_owner.id); + p = xdr_encode_hyper(p, args->lock_owner.id); hdr->nops++; hdr->replen += decode_lockt_maxsz; } @@ -1103,8 +1099,8 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); *p++ = cpu_to_be32(args->seqid->sequence->counter); WRITEMEM(args->stateid->data, NFS4_STATEID_SIZE); - WRITE64(args->fl->fl_start); - WRITE64(nfs4_lock_length(args->fl)); + p = xdr_encode_hyper(p, args->fl->fl_start); + p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); hdr->nops++; hdr->replen += decode_locku_maxsz; } @@ -1155,10 +1151,10 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena *p++ = cpu_to_be32(arg->seqid->sequence->counter); encode_share_access(xdr, arg->fmode); RESERVE_SPACE(28); - WRITE64(arg->clientid); + p = xdr_encode_hyper(p, arg->clientid); *p++ = cpu_to_be32(16); WRITEMEM("open id:", 8); - WRITE64(arg->id); + p = xdr_encode_hyper(p, arg->id); } static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) @@ -1334,7 +1330,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, encode_stateid(xdr, args->context); RESERVE_SPACE(12); - WRITE64(args->offset); + p = xdr_encode_hyper(p, args->offset); *p++ = cpu_to_be32(args->count); hdr->nops++; hdr->replen += decode_read_maxsz; @@ -1350,7 +1346,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg RESERVE_SPACE(12+NFS4_VERIFIER_SIZE+20); *p++ = cpu_to_be32(OP_READDIR); - WRITE64(readdir->cookie); + p = xdr_encode_hyper(p, readdir->cookie); WRITEMEM(readdir->verifier.data, NFS4_VERIFIER_SIZE); *p++ = cpu_to_be32(readdir->count >> 1); /* We're not doing readdirplus */ *p++ = cpu_to_be32(readdir->count); @@ -1417,7 +1413,7 @@ static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client RESERVE_SPACE(12); *p++ = cpu_to_be32(OP_RENEW); - WRITE64(client_stateid->cl_clientid); + p = xdr_encode_hyper(p, client_stateid->cl_clientid); hdr->nops++; hdr->replen += decode_renew_maxsz; } @@ -1502,7 +1498,7 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_ RESERVE_SPACE(12 + NFS4_VERIFIER_SIZE); *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); - WRITE64(client_state->cl_clientid); + p = xdr_encode_hyper(p, client_state->cl_clientid); WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); hdr->nops++; hdr->replen += decode_setclientid_confirm_maxsz; @@ -1518,7 +1514,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg encode_stateid(xdr, args->context); RESERVE_SPACE(16); - WRITE64(args->offset); + p = xdr_encode_hyper(p, args->offset); *p++ = cpu_to_be32(args->stable); *p++ = cpu_to_be32(args->count); @@ -1574,7 +1570,7 @@ static void encode_create_session(struct xdr_stream *xdr, *p++ = cpu_to_be32(OP_CREATE_SESSION); RESERVE_SPACE(8); - WRITE64(clp->cl_ex_clid); + p = xdr_encode_hyper(p, clp->cl_ex_clid); RESERVE_SPACE(8); *p++ = cpu_to_be32(clp->cl_seqid); /*Sequence id */ -- cgit v0.10.2 From 93f0cf25944695e1229fe90a2897af0211fbd425 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:06 +0300 Subject: nfs: nfs4xdr: get rid of WRITEMEM s/WRITEMEM(/p = xdr_encode_opaque_fixed(p, / Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5d80766..17915c8 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -712,10 +712,6 @@ struct compound_hdr { * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define WRITEMEM(ptr,nbytes) do { \ - p = xdr_encode_opaque_fixed(p, ptr, nbytes); \ -} while (0) - #define RESERVE_SPACE(nbytes) do { \ p = xdr_reserve_space(xdr, nbytes); \ BUG_ON(!p); \ @@ -746,7 +742,7 @@ static void encode_compound_hdr(struct xdr_stream *xdr, BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); *p++ = cpu_to_be32(hdr->taglen); - WRITEMEM(hdr->tag, hdr->taglen); + p = xdr_encode_opaque_fixed(p, hdr->tag, hdr->taglen); *p++ = cpu_to_be32(hdr->minorversion); hdr->nops_p = p; *p++ = cpu_to_be32(hdr->nops); @@ -845,12 +841,12 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const if (iap->ia_valid & ATTR_UID) { bmval1 |= FATTR4_WORD1_OWNER; *p++ = cpu_to_be32(owner_namelen); - WRITEMEM(owner_name, owner_namelen); + p = xdr_encode_opaque_fixed(p, owner_name, owner_namelen); } if (iap->ia_valid & ATTR_GID) { bmval1 |= FATTR4_WORD1_OWNER_GROUP; *p++ = cpu_to_be32(owner_grouplen); - WRITEMEM(owner_group, owner_grouplen); + p = xdr_encode_opaque_fixed(p, owner_group, owner_grouplen); } if (iap->ia_valid & ATTR_ATIME_SET) { bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; @@ -909,7 +905,7 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg RESERVE_SPACE(8+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_CLOSE); *p++ = cpu_to_be32(arg->seqid->sequence->counter); - WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); hdr->nops++; hdr->replen += decode_close_maxsz; } @@ -953,7 +949,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * RESERVE_SPACE(4 + create->name->len); *p++ = cpu_to_be32(create->name->len); - WRITEMEM(create->name->name, create->name->len); + p = xdr_encode_opaque_fixed(p, create->name->name, create->name->len); hdr->nops++; hdr->replen += decode_create_maxsz; @@ -1020,7 +1016,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct RESERVE_SPACE(8 + name->len); *p++ = cpu_to_be32(OP_LINK); *p++ = cpu_to_be32(name->len); - WRITEMEM(name->name, name->len); + p = xdr_encode_opaque_fixed(p, name->name, name->len); hdr->nops++; hdr->replen += decode_link_maxsz; } @@ -1057,16 +1053,16 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args if (args->new_lock_owner){ RESERVE_SPACE(4+NFS4_STATEID_SIZE+32); *p++ = cpu_to_be32(args->open_seqid->sequence->counter); - WRITEMEM(args->open_stateid->data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE); *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); p = xdr_encode_hyper(p, args->lock_owner.clientid); *p++ = cpu_to_be32(16); - WRITEMEM("lock id:", 8); + p = xdr_encode_opaque_fixed(p, "lock id:", 8); p = xdr_encode_hyper(p, args->lock_owner.id); } else { RESERVE_SPACE(NFS4_STATEID_SIZE+4); - WRITEMEM(args->lock_stateid->data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE); *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); } hdr->nops++; @@ -1084,7 +1080,7 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); p = xdr_encode_hyper(p, args->lock_owner.clientid); *p++ = cpu_to_be32(16); - WRITEMEM("lock id:", 8); + p = xdr_encode_opaque_fixed(p, "lock id:", 8); p = xdr_encode_hyper(p, args->lock_owner.id); hdr->nops++; hdr->replen += decode_lockt_maxsz; @@ -1098,7 +1094,7 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar *p++ = cpu_to_be32(OP_LOCKU); *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); *p++ = cpu_to_be32(args->seqid->sequence->counter); - WRITEMEM(args->stateid->data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE); p = xdr_encode_hyper(p, args->fl->fl_start); p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); hdr->nops++; @@ -1113,7 +1109,7 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc RESERVE_SPACE(8 + len); *p++ = cpu_to_be32(OP_LOOKUP); *p++ = cpu_to_be32(len); - WRITEMEM(name->name, len); + p = xdr_encode_opaque_fixed(p, name->name, len); hdr->nops++; hdr->replen += decode_lookup_maxsz; } @@ -1153,7 +1149,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena RESERVE_SPACE(28); p = xdr_encode_hyper(p, arg->clientid); *p++ = cpu_to_be32(16); - WRITEMEM("open id:", 8); + p = xdr_encode_opaque_fixed(p, "open id:", 8); p = xdr_encode_hyper(p, arg->id); } @@ -1233,7 +1229,7 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc RESERVE_SPACE(4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR); - WRITEMEM(stateid->data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); encode_string(xdr, name->len, name->name); } @@ -1264,7 +1260,7 @@ static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_co RESERVE_SPACE(4+NFS4_STATEID_SIZE+4); *p++ = cpu_to_be32(OP_OPEN_CONFIRM); - WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); *p++ = cpu_to_be32(arg->seqid->sequence->counter); hdr->nops++; hdr->replen += decode_open_confirm_maxsz; @@ -1276,7 +1272,7 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close RESERVE_SPACE(4+NFS4_STATEID_SIZE+4); *p++ = cpu_to_be32(OP_OPEN_DOWNGRADE); - WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); *p++ = cpu_to_be32(arg->seqid->sequence->counter); encode_share_access(xdr, arg->fmode); hdr->nops++; @@ -1292,7 +1288,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd RESERVE_SPACE(8 + len); *p++ = cpu_to_be32(OP_PUTFH); *p++ = cpu_to_be32(len); - WRITEMEM(fh->data, len); + p = xdr_encode_opaque_fixed(p, fh->data, len); hdr->nops++; hdr->replen += decode_putfh_maxsz; } @@ -1315,9 +1311,9 @@ static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context RESERVE_SPACE(NFS4_STATEID_SIZE); if (ctx->state != NULL) { nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner); - WRITEMEM(stateid.data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE); } else - WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); } static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr) @@ -1347,7 +1343,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg RESERVE_SPACE(12+NFS4_VERIFIER_SIZE+20); *p++ = cpu_to_be32(OP_READDIR); p = xdr_encode_hyper(p, readdir->cookie); - WRITEMEM(readdir->verifier.data, NFS4_VERIFIER_SIZE); + p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE); *p++ = cpu_to_be32(readdir->count >> 1); /* We're not doing readdirplus */ *p++ = cpu_to_be32(readdir->count); *p++ = cpu_to_be32(2); @@ -1386,7 +1382,7 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc RESERVE_SPACE(8 + name->len); *p++ = cpu_to_be32(OP_REMOVE); *p++ = cpu_to_be32(name->len); - WRITEMEM(name->name, name->len); + p = xdr_encode_opaque_fixed(p, name->name, name->len); hdr->nops++; hdr->replen += decode_remove_maxsz; } @@ -1398,11 +1394,11 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co RESERVE_SPACE(8 + oldname->len); *p++ = cpu_to_be32(OP_RENAME); *p++ = cpu_to_be32(oldname->len); - WRITEMEM(oldname->name, oldname->len); + p = xdr_encode_opaque_fixed(p, oldname->name, oldname->len); RESERVE_SPACE(4 + newname->len); *p++ = cpu_to_be32(newname->len); - WRITEMEM(newname->name, newname->len); + p = xdr_encode_opaque_fixed(p, newname->name, newname->len); hdr->nops++; hdr->replen += decode_rename_maxsz; } @@ -1436,7 +1432,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun RESERVE_SPACE(4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_SETATTR); - WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); RESERVE_SPACE(2*4); *p++ = cpu_to_be32(1); *p++ = cpu_to_be32(FATTR4_WORD0_ACL); @@ -1467,7 +1463,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs RESERVE_SPACE(4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_SETATTR); - WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE); hdr->nops++; hdr->replen += decode_setattr_maxsz; encode_attrs(xdr, arg->iap, server); @@ -1479,7 +1475,7 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie RESERVE_SPACE(4 + NFS4_VERIFIER_SIZE); *p++ = cpu_to_be32(OP_SETCLIENTID); - WRITEMEM(setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE); + p = xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE); encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); RESERVE_SPACE(4); @@ -1499,7 +1495,7 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_ RESERVE_SPACE(12 + NFS4_VERIFIER_SIZE); *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); p = xdr_encode_hyper(p, client_state->cl_clientid); - WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); + p = xdr_encode_opaque_fixed(p, client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); hdr->nops++; hdr->replen += decode_setclientid_confirm_maxsz; } @@ -1530,7 +1526,7 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state RESERVE_SPACE(4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_DELEGRETURN); - WRITEMEM(stateid->data, NFS4_STATEID_SIZE); + p = xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); hdr->nops++; hdr->replen += decode_delegreturn_maxsz; } @@ -1545,7 +1541,7 @@ static void encode_exchange_id(struct xdr_stream *xdr, RESERVE_SPACE(4 + sizeof(args->verifier->data)); *p++ = cpu_to_be32(OP_EXCHANGE_ID); - WRITEMEM(args->verifier->data, sizeof(args->verifier->data)); + p = xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data)); encode_string(xdr, args->id_len, args->id); @@ -1611,7 +1607,7 @@ static void encode_create_session(struct xdr_stream *xdr, clp->cl_ipaddr); RESERVE_SPACE(16 + len); *p++ = cpu_to_be32(len); - WRITEMEM(machine_name, len); + p = xdr_encode_opaque_fixed(p, machine_name, len); *p++ = cpu_to_be32(0); /* UID */ *p++ = cpu_to_be32(0); /* GID */ *p++ = cpu_to_be32(0); /* No more gids */ @@ -1626,7 +1622,7 @@ static void encode_destroy_session(struct xdr_stream *xdr, __be32 *p; RESERVE_SPACE(4 + NFS4_MAX_SESSIONID_LEN); *p++ = cpu_to_be32(OP_DESTROY_SESSION); - WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); + p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); hdr->nops++; hdr->replen += decode_destroy_session_maxsz; } @@ -1666,7 +1662,7 @@ static void encode_sequence(struct xdr_stream *xdr, slot->seq_nr, args->sa_slotid, tp->highest_used_slotid, args->sa_cache_this); RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 16); - WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); + p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); *p++ = cpu_to_be32(slot->seq_nr); *p++ = cpu_to_be32(args->sa_slotid); *p++ = cpu_to_be32(tp->highest_used_slotid); -- cgit v0.10.2 From 42edd698125b76a38bd9999015202db036dfbc76 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:13 +0300 Subject: nfs: nfs4xdr: optimize RESERVE_SPACE in encode_create_session and encode_sequence Coalesce multilpe constant RESERVE_SPACEs into one Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 17915c8..d460d81 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1562,17 +1562,15 @@ static void encode_create_session(struct xdr_stream *xdr, uint32_t len; struct nfs_client *clp = args->client; - RESERVE_SPACE(4); - *p++ = cpu_to_be32(OP_CREATE_SESSION); + len = scnprintf(machine_name, sizeof(machine_name), "%s", + clp->cl_ipaddr); - RESERVE_SPACE(8); + RESERVE_SPACE(20 + 2*28 + 20 + len + 12); + *p++ = cpu_to_be32(OP_CREATE_SESSION); p = xdr_encode_hyper(p, clp->cl_ex_clid); - - RESERVE_SPACE(8); *p++ = cpu_to_be32(clp->cl_seqid); /*Sequence id */ *p++ = cpu_to_be32(args->flags); /*flags */ - RESERVE_SPACE(2*28); /* 2 channel_attrs */ /* Fore Channel */ *p++ = cpu_to_be32(args->fc_attrs.headerpadsz); /* header padding size */ *p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz); /* max req size */ @@ -1591,21 +1589,12 @@ static void encode_create_session(struct xdr_stream *xdr, *p++ = cpu_to_be32(args->bc_attrs.max_reqs); /* max requests */ *p++ = cpu_to_be32(0); /* rdmachannel_attrs */ - RESERVE_SPACE(4); *p++ = cpu_to_be32(args->cb_program); /* cb_program */ - - RESERVE_SPACE(4); /* # of security flavors */ *p++ = cpu_to_be32(1); - - RESERVE_SPACE(4); *p++ = cpu_to_be32(RPC_AUTH_UNIX); /* auth_sys */ /* authsys_parms rfc1831 */ - RESERVE_SPACE(4); *p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ - len = scnprintf(machine_name, sizeof(machine_name), "%s", - clp->cl_ipaddr); - RESERVE_SPACE(16 + len); *p++ = cpu_to_be32(len); p = xdr_encode_opaque_fixed(p, machine_name, len); *p++ = cpu_to_be32(0); /* UID */ @@ -1646,7 +1635,7 @@ static void encode_sequence(struct xdr_stream *xdr, WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); slot = tp->slots + args->sa_slotid; - RESERVE_SPACE(4); + RESERVE_SPACE(4 + NFS4_MAX_SESSIONID_LEN + 16); *p++ = cpu_to_be32(OP_SEQUENCE); /* @@ -1661,7 +1650,6 @@ static void encode_sequence(struct xdr_stream *xdr, ((u32 *)session->sess_id.data)[3], slot->seq_nr, args->sa_slotid, tp->highest_used_slotid, args->sa_cache_this); - RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 16); p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); *p++ = cpu_to_be32(slot->seq_nr); *p++ = cpu_to_be32(args->sa_slotid); -- cgit v0.10.2 From 2220f13a8b90d2259f3094cb54cf4de67d8eee2d Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:18 +0300 Subject: nfs: nfs4xdr: encode_compound_hdr does not have to round up reserved bytes This is already done by xdr_reserve_space and since encode_compound_hdr is adding a byte count to "12" which is already word aligned, the xdr level rounding will work just as well. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index d460d81..7c2b162 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -740,7 +740,7 @@ static void encode_compound_hdr(struct xdr_stream *xdr, dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); - RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); + RESERVE_SPACE(12 + hdr->taglen); *p++ = cpu_to_be32(hdr->taglen); p = xdr_encode_opaque_fixed(p, hdr->tag, hdr->taglen); *p++ = cpu_to_be32(hdr->minorversion); -- cgit v0.10.2 From 13c65ce90006badccd5663e558e3c85869ae5ce6 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:25 +0300 Subject: nfs: nfs4xdr: change RESERVE_SPACE macro into a static helper In order to open code and expose the result pointer assignment. Alternatively, we can open code the call to xdr_reserve_space and do the BUG_ON an the error case at the call site. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 7c2b162..3bcde49 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -702,20 +702,12 @@ struct compound_hdr { u32 minorversion; }; -/* - * START OF "GENERIC" ENCODE ROUTINES. - * These may look a little ugly since they are imported from a "generic" - * set of XDR encode/decode routines which are intended to be shared by - * all of our NFSv4 implementations (OpenBSD, MacOS X...). - * - * If the pain of reading these is too great, it should be a straightforward - * task to translate them into Linux-specific versions which are more - * consistent with the style used in NFSv2/v3... - */ -#define RESERVE_SPACE(nbytes) do { \ - p = xdr_reserve_space(xdr, nbytes); \ - BUG_ON(!p); \ -} while (0) +static __be32 *reserve_space(struct xdr_stream *xdr, size_t nbytes) +{ + __be32 *p = xdr_reserve_space(xdr, nbytes); + BUG_ON(!p); + return p; +} static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) { @@ -740,7 +732,7 @@ static void encode_compound_hdr(struct xdr_stream *xdr, dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); - RESERVE_SPACE(12 + hdr->taglen); + p = reserve_space(xdr, 12 + hdr->taglen); *p++ = cpu_to_be32(hdr->taglen); p = xdr_encode_opaque_fixed(p, hdr->tag, hdr->taglen); *p++ = cpu_to_be32(hdr->minorversion); @@ -820,7 +812,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const len += 16; else if (iap->ia_valid & ATTR_MTIME) len += 4; - RESERVE_SPACE(len); + p = reserve_space(xdr, len); /* * We write the bitmap length now, but leave the bitmap and the attribute @@ -891,7 +883,7 @@ static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hd { __be32 *p; - RESERVE_SPACE(8); + p = reserve_space(xdr, 8); *p++ = cpu_to_be32(OP_ACCESS); *p++ = cpu_to_be32(access); hdr->nops++; @@ -902,7 +894,7 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg { __be32 *p; - RESERVE_SPACE(8+NFS4_STATEID_SIZE); + p = reserve_space(xdr, 8+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_CLOSE); *p++ = cpu_to_be32(arg->seqid->sequence->counter); p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); @@ -914,7 +906,7 @@ static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *ar { __be32 *p; - RESERVE_SPACE(16); + p = reserve_space(xdr, 16); *p++ = cpu_to_be32(OP_COMMIT); p = xdr_encode_hyper(p, args->offset); *p++ = cpu_to_be32(args->count); @@ -926,19 +918,19 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * { __be32 *p; - RESERVE_SPACE(8); + p = reserve_space(xdr, 8); *p++ = cpu_to_be32(OP_CREATE); *p++ = cpu_to_be32(create->ftype); switch (create->ftype) { case NF4LNK: - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(create->u.symlink.len); xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len); break; case NF4BLK: case NF4CHR: - RESERVE_SPACE(8); + p = reserve_space(xdr, 8); *p++ = cpu_to_be32(create->u.device.specdata1); *p++ = cpu_to_be32(create->u.device.specdata2); break; @@ -947,7 +939,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * break; } - RESERVE_SPACE(4 + create->name->len); + p = reserve_space(xdr, 4 + create->name->len); *p++ = cpu_to_be32(create->name->len); p = xdr_encode_opaque_fixed(p, create->name->name, create->name->len); hdr->nops++; @@ -960,7 +952,7 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c { __be32 *p; - RESERVE_SPACE(12); + p = reserve_space(xdr, 12); *p++ = cpu_to_be32(OP_GETATTR); *p++ = cpu_to_be32(1); *p++ = cpu_to_be32(bitmap); @@ -972,7 +964,7 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm { __be32 *p; - RESERVE_SPACE(16); + p = reserve_space(xdr, 16); *p++ = cpu_to_be32(OP_GETATTR); *p++ = cpu_to_be32(2); *p++ = cpu_to_be32(bm0); @@ -1003,7 +995,7 @@ static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(OP_GETFH); hdr->nops++; hdr->replen += decode_getfh_maxsz; @@ -1013,7 +1005,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct { __be32 *p; - RESERVE_SPACE(8 + name->len); + p = reserve_space(xdr, 8 + name->len); *p++ = cpu_to_be32(OP_LINK); *p++ = cpu_to_be32(name->len); p = xdr_encode_opaque_fixed(p, name->name, name->len); @@ -1043,7 +1035,7 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args { __be32 *p; - RESERVE_SPACE(32); + p = reserve_space(xdr, 32); *p++ = cpu_to_be32(OP_LOCK); *p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block)); *p++ = cpu_to_be32(args->reclaim); @@ -1051,7 +1043,7 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); *p++ = cpu_to_be32(args->new_lock_owner); if (args->new_lock_owner){ - RESERVE_SPACE(4+NFS4_STATEID_SIZE+32); + p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+32); *p++ = cpu_to_be32(args->open_seqid->sequence->counter); p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE); *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); @@ -1061,7 +1053,7 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args p = xdr_encode_hyper(p, args->lock_owner.id); } else { - RESERVE_SPACE(NFS4_STATEID_SIZE+4); + p = reserve_space(xdr, NFS4_STATEID_SIZE+4); p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE); *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); } @@ -1073,7 +1065,7 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar { __be32 *p; - RESERVE_SPACE(52); + p = reserve_space(xdr, 52); *p++ = cpu_to_be32(OP_LOCKT); *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); p = xdr_encode_hyper(p, args->fl->fl_start); @@ -1090,7 +1082,7 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar { __be32 *p; - RESERVE_SPACE(12+NFS4_STATEID_SIZE+16); + p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16); *p++ = cpu_to_be32(OP_LOCKU); *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); *p++ = cpu_to_be32(args->seqid->sequence->counter); @@ -1106,7 +1098,7 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc int len = name->len; __be32 *p; - RESERVE_SPACE(8 + len); + p = reserve_space(xdr, 8 + len); *p++ = cpu_to_be32(OP_LOOKUP); *p++ = cpu_to_be32(len); p = xdr_encode_opaque_fixed(p, name->name, len); @@ -1118,7 +1110,7 @@ static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) { __be32 *p; - RESERVE_SPACE(8); + p = reserve_space(xdr, 8); switch (fmode & (FMODE_READ|FMODE_WRITE)) { case FMODE_READ: *p++ = cpu_to_be32(NFS4_SHARE_ACCESS_READ); @@ -1142,11 +1134,11 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4, * owner 4 = 32 */ - RESERVE_SPACE(8); + p = reserve_space(xdr, 8); *p++ = cpu_to_be32(OP_OPEN); *p++ = cpu_to_be32(arg->seqid->sequence->counter); encode_share_access(xdr, arg->fmode); - RESERVE_SPACE(28); + p = reserve_space(xdr, 28); p = xdr_encode_hyper(p, arg->clientid); *p++ = cpu_to_be32(16); p = xdr_encode_opaque_fixed(p, "open id:", 8); @@ -1157,7 +1149,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); switch(arg->open_flags & O_EXCL) { case 0: *p++ = cpu_to_be32(NFS4_CREATE_UNCHECKED); @@ -1173,7 +1165,7 @@ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *a { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); switch (arg->open_flags & O_CREAT) { case 0: *p++ = cpu_to_be32(NFS4_OPEN_NOCREATE); @@ -1189,7 +1181,7 @@ static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delega { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); switch (delegation_type) { case 0: *p++ = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE); @@ -1209,7 +1201,7 @@ static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr * { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_NULL); encode_string(xdr, name->len, name->name); } @@ -1218,7 +1210,7 @@ static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type) { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS); encode_delegation_type(xdr, type); } @@ -1227,7 +1219,7 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc { __be32 *p; - RESERVE_SPACE(4+NFS4_STATEID_SIZE); + p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR); p = xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); encode_string(xdr, name->len, name->name); @@ -1258,7 +1250,7 @@ static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_co { __be32 *p; - RESERVE_SPACE(4+NFS4_STATEID_SIZE+4); + p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4); *p++ = cpu_to_be32(OP_OPEN_CONFIRM); p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); *p++ = cpu_to_be32(arg->seqid->sequence->counter); @@ -1270,7 +1262,7 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close { __be32 *p; - RESERVE_SPACE(4+NFS4_STATEID_SIZE+4); + p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4); *p++ = cpu_to_be32(OP_OPEN_DOWNGRADE); p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); *p++ = cpu_to_be32(arg->seqid->sequence->counter); @@ -1285,7 +1277,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd int len = fh->size; __be32 *p; - RESERVE_SPACE(8 + len); + p = reserve_space(xdr, 8 + len); *p++ = cpu_to_be32(OP_PUTFH); *p++ = cpu_to_be32(len); p = xdr_encode_opaque_fixed(p, fh->data, len); @@ -1297,7 +1289,7 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(OP_PUTROOTFH); hdr->nops++; hdr->replen += decode_putrootfh_maxsz; @@ -1308,7 +1300,7 @@ static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context nfs4_stateid stateid; __be32 *p; - RESERVE_SPACE(NFS4_STATEID_SIZE); + p = reserve_space(xdr, NFS4_STATEID_SIZE); if (ctx->state != NULL) { nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner); p = xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE); @@ -1320,12 +1312,12 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(OP_READ); encode_stateid(xdr, args->context); - RESERVE_SPACE(12); + p = reserve_space(xdr, 12); p = xdr_encode_hyper(p, args->offset); *p++ = cpu_to_be32(args->count); hdr->nops++; @@ -1340,7 +1332,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg }; __be32 *p; - RESERVE_SPACE(12+NFS4_VERIFIER_SIZE+20); + p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); *p++ = cpu_to_be32(OP_READDIR); p = xdr_encode_hyper(p, readdir->cookie); p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE); @@ -1369,7 +1361,7 @@ static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink * { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(OP_READLINK); hdr->nops++; hdr->replen += decode_readlink_maxsz; @@ -1379,7 +1371,7 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc { __be32 *p; - RESERVE_SPACE(8 + name->len); + p = reserve_space(xdr, 8 + name->len); *p++ = cpu_to_be32(OP_REMOVE); *p++ = cpu_to_be32(name->len); p = xdr_encode_opaque_fixed(p, name->name, name->len); @@ -1391,12 +1383,12 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co { __be32 *p; - RESERVE_SPACE(8 + oldname->len); + p = reserve_space(xdr, 8 + oldname->len); *p++ = cpu_to_be32(OP_RENAME); *p++ = cpu_to_be32(oldname->len); p = xdr_encode_opaque_fixed(p, oldname->name, oldname->len); - RESERVE_SPACE(4 + newname->len); + p = reserve_space(xdr, 4 + newname->len); *p++ = cpu_to_be32(newname->len); p = xdr_encode_opaque_fixed(p, newname->name, newname->len); hdr->nops++; @@ -1407,7 +1399,7 @@ static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client { __be32 *p; - RESERVE_SPACE(12); + p = reserve_space(xdr, 12); *p++ = cpu_to_be32(OP_RENEW); p = xdr_encode_hyper(p, client_stateid->cl_clientid); hdr->nops++; @@ -1419,7 +1411,7 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(OP_RESTOREFH); hdr->nops++; hdr->replen += decode_restorefh_maxsz; @@ -1430,15 +1422,15 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun { __be32 *p; - RESERVE_SPACE(4+NFS4_STATEID_SIZE); + p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_SETATTR); p = xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); - RESERVE_SPACE(2*4); + p = reserve_space(xdr, 2*4); *p++ = cpu_to_be32(1); *p++ = cpu_to_be32(FATTR4_WORD0_ACL); if (arg->acl_len % 4) return -EINVAL; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(arg->acl_len); xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); hdr->nops++; @@ -1451,7 +1443,7 @@ encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(OP_SAVEFH); hdr->nops++; hdr->replen += decode_savefh_maxsz; @@ -1461,7 +1453,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs { __be32 *p; - RESERVE_SPACE(4+NFS4_STATEID_SIZE); + p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_SETATTR); p = xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE); hdr->nops++; @@ -1473,16 +1465,16 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie { __be32 *p; - RESERVE_SPACE(4 + NFS4_VERIFIER_SIZE); + p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE); *p++ = cpu_to_be32(OP_SETCLIENTID); p = xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE); encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(setclientid->sc_prog); encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid); encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr); - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(setclientid->sc_cb_ident); hdr->nops++; hdr->replen += decode_setclientid_maxsz; @@ -1492,7 +1484,7 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_ { __be32 *p; - RESERVE_SPACE(12 + NFS4_VERIFIER_SIZE); + p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE); *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); p = xdr_encode_hyper(p, client_state->cl_clientid); p = xdr_encode_opaque_fixed(p, client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); @@ -1504,12 +1496,12 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg { __be32 *p; - RESERVE_SPACE(4); + p = reserve_space(xdr, 4); *p++ = cpu_to_be32(OP_WRITE); encode_stateid(xdr, args->context); - RESERVE_SPACE(16); + p = reserve_space(xdr, 16); p = xdr_encode_hyper(p, args->offset); *p++ = cpu_to_be32(args->stable); *p++ = cpu_to_be32(args->count); @@ -1523,7 +1515,7 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state { __be32 *p; - RESERVE_SPACE(4+NFS4_STATEID_SIZE); + p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_DELEGRETURN); p = xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); @@ -1539,13 +1531,13 @@ static void encode_exchange_id(struct xdr_stream *xdr, { __be32 *p; - RESERVE_SPACE(4 + sizeof(args->verifier->data)); + p = reserve_space(xdr, 4 + sizeof(args->verifier->data)); *p++ = cpu_to_be32(OP_EXCHANGE_ID); p = xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data)); encode_string(xdr, args->id_len, args->id); - RESERVE_SPACE(12); + p = reserve_space(xdr, 12); *p++ = cpu_to_be32(args->flags); *p++ = cpu_to_be32(0); /* zero length state_protect4_a */ *p++ = cpu_to_be32(0); /* zero length implementation id array */ @@ -1565,7 +1557,7 @@ static void encode_create_session(struct xdr_stream *xdr, len = scnprintf(machine_name, sizeof(machine_name), "%s", clp->cl_ipaddr); - RESERVE_SPACE(20 + 2*28 + 20 + len + 12); + p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12); *p++ = cpu_to_be32(OP_CREATE_SESSION); p = xdr_encode_hyper(p, clp->cl_ex_clid); *p++ = cpu_to_be32(clp->cl_seqid); /*Sequence id */ @@ -1609,7 +1601,7 @@ static void encode_destroy_session(struct xdr_stream *xdr, struct compound_hdr *hdr) { __be32 *p; - RESERVE_SPACE(4 + NFS4_MAX_SESSIONID_LEN); + p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN); *p++ = cpu_to_be32(OP_DESTROY_SESSION); p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); hdr->nops++; @@ -1635,7 +1627,7 @@ static void encode_sequence(struct xdr_stream *xdr, WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); slot = tp->slots + args->sa_slotid; - RESERVE_SPACE(4 + NFS4_MAX_SESSIONID_LEN + 16); + p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16); *p++ = cpu_to_be32(OP_SEQUENCE); /* -- cgit v0.10.2 From 345585132a204859fbb7d8b662e9b6e5b563c6dc Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:30 +0300 Subject: nfs: nfs4xdr: optimize low level encoding do not increment encoding ptr if not needed. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 3bcde49..d75f821 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -737,7 +737,7 @@ static void encode_compound_hdr(struct xdr_stream *xdr, p = xdr_encode_opaque_fixed(p, hdr->tag, hdr->taglen); *p++ = cpu_to_be32(hdr->minorversion); hdr->nops_p = p; - *p++ = cpu_to_be32(hdr->nops); + *p = cpu_to_be32(hdr->nops); } static void encode_nops(struct compound_hdr *hdr) @@ -874,7 +874,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const len = (char *)p - (char *)q - 12; *q++ = htonl(bmval0); *q++ = htonl(bmval1); - *q++ = htonl(len); + *q = htonl(len); /* out: */ } @@ -885,7 +885,7 @@ static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hd p = reserve_space(xdr, 8); *p++ = cpu_to_be32(OP_ACCESS); - *p++ = cpu_to_be32(access); + *p = cpu_to_be32(access); hdr->nops++; hdr->replen += decode_access_maxsz; } @@ -897,7 +897,7 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg p = reserve_space(xdr, 8+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_CLOSE); *p++ = cpu_to_be32(arg->seqid->sequence->counter); - p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); + xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); hdr->nops++; hdr->replen += decode_close_maxsz; } @@ -909,7 +909,7 @@ static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *ar p = reserve_space(xdr, 16); *p++ = cpu_to_be32(OP_COMMIT); p = xdr_encode_hyper(p, args->offset); - *p++ = cpu_to_be32(args->count); + *p = cpu_to_be32(args->count); hdr->nops++; hdr->replen += decode_commit_maxsz; } @@ -920,19 +920,19 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * p = reserve_space(xdr, 8); *p++ = cpu_to_be32(OP_CREATE); - *p++ = cpu_to_be32(create->ftype); + *p = cpu_to_be32(create->ftype); switch (create->ftype) { case NF4LNK: p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(create->u.symlink.len); + *p = cpu_to_be32(create->u.symlink.len); xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len); break; case NF4BLK: case NF4CHR: p = reserve_space(xdr, 8); *p++ = cpu_to_be32(create->u.device.specdata1); - *p++ = cpu_to_be32(create->u.device.specdata2); + *p = cpu_to_be32(create->u.device.specdata2); break; default: @@ -941,7 +941,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * p = reserve_space(xdr, 4 + create->name->len); *p++ = cpu_to_be32(create->name->len); - p = xdr_encode_opaque_fixed(p, create->name->name, create->name->len); + xdr_encode_opaque_fixed(p, create->name->name, create->name->len); hdr->nops++; hdr->replen += decode_create_maxsz; @@ -955,7 +955,7 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c p = reserve_space(xdr, 12); *p++ = cpu_to_be32(OP_GETATTR); *p++ = cpu_to_be32(1); - *p++ = cpu_to_be32(bitmap); + *p = cpu_to_be32(bitmap); hdr->nops++; hdr->replen += decode_getattr_maxsz; } @@ -968,7 +968,7 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm *p++ = cpu_to_be32(OP_GETATTR); *p++ = cpu_to_be32(2); *p++ = cpu_to_be32(bm0); - *p++ = cpu_to_be32(bm1); + *p = cpu_to_be32(bm1); hdr->nops++; hdr->replen += decode_getattr_maxsz; } @@ -996,7 +996,7 @@ static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) __be32 *p; p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(OP_GETFH); + *p = cpu_to_be32(OP_GETFH); hdr->nops++; hdr->replen += decode_getfh_maxsz; } @@ -1008,7 +1008,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct p = reserve_space(xdr, 8 + name->len); *p++ = cpu_to_be32(OP_LINK); *p++ = cpu_to_be32(name->len); - p = xdr_encode_opaque_fixed(p, name->name, name->len); + xdr_encode_opaque_fixed(p, name->name, name->len); hdr->nops++; hdr->replen += decode_link_maxsz; } @@ -1041,7 +1041,7 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args *p++ = cpu_to_be32(args->reclaim); p = xdr_encode_hyper(p, args->fl->fl_start); p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); - *p++ = cpu_to_be32(args->new_lock_owner); + *p = cpu_to_be32(args->new_lock_owner); if (args->new_lock_owner){ p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+32); *p++ = cpu_to_be32(args->open_seqid->sequence->counter); @@ -1050,12 +1050,12 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args p = xdr_encode_hyper(p, args->lock_owner.clientid); *p++ = cpu_to_be32(16); p = xdr_encode_opaque_fixed(p, "lock id:", 8); - p = xdr_encode_hyper(p, args->lock_owner.id); + xdr_encode_hyper(p, args->lock_owner.id); } else { p = reserve_space(xdr, NFS4_STATEID_SIZE+4); p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE); - *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); + *p = cpu_to_be32(args->lock_seqid->sequence->counter); } hdr->nops++; hdr->replen += decode_lock_maxsz; @@ -1073,7 +1073,7 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar p = xdr_encode_hyper(p, args->lock_owner.clientid); *p++ = cpu_to_be32(16); p = xdr_encode_opaque_fixed(p, "lock id:", 8); - p = xdr_encode_hyper(p, args->lock_owner.id); + xdr_encode_hyper(p, args->lock_owner.id); hdr->nops++; hdr->replen += decode_lockt_maxsz; } @@ -1088,7 +1088,7 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar *p++ = cpu_to_be32(args->seqid->sequence->counter); p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE); p = xdr_encode_hyper(p, args->fl->fl_start); - p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); + xdr_encode_hyper(p, nfs4_lock_length(args->fl)); hdr->nops++; hdr->replen += decode_locku_maxsz; } @@ -1101,7 +1101,7 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc p = reserve_space(xdr, 8 + len); *p++ = cpu_to_be32(OP_LOOKUP); *p++ = cpu_to_be32(len); - p = xdr_encode_opaque_fixed(p, name->name, len); + xdr_encode_opaque_fixed(p, name->name, len); hdr->nops++; hdr->replen += decode_lookup_maxsz; } @@ -1124,7 +1124,7 @@ static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) default: *p++ = cpu_to_be32(0); } - *p++ = cpu_to_be32(0); /* for linux, share_deny = 0 always */ + *p = cpu_to_be32(0); /* for linux, share_deny = 0 always */ } static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg) @@ -1136,13 +1136,13 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena */ p = reserve_space(xdr, 8); *p++ = cpu_to_be32(OP_OPEN); - *p++ = cpu_to_be32(arg->seqid->sequence->counter); + *p = cpu_to_be32(arg->seqid->sequence->counter); encode_share_access(xdr, arg->fmode); p = reserve_space(xdr, 28); p = xdr_encode_hyper(p, arg->clientid); *p++ = cpu_to_be32(16); p = xdr_encode_opaque_fixed(p, "open id:", 8); - p = xdr_encode_hyper(p, arg->id); + xdr_encode_hyper(p, arg->id); } static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) @@ -1152,11 +1152,11 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op p = reserve_space(xdr, 4); switch(arg->open_flags & O_EXCL) { case 0: - *p++ = cpu_to_be32(NFS4_CREATE_UNCHECKED); + *p = cpu_to_be32(NFS4_CREATE_UNCHECKED); encode_attrs(xdr, arg->u.attrs, arg->server); break; default: - *p++ = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); + *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); encode_nfs4_verifier(xdr, &arg->u.verifier); } } @@ -1168,11 +1168,11 @@ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *a p = reserve_space(xdr, 4); switch (arg->open_flags & O_CREAT) { case 0: - *p++ = cpu_to_be32(NFS4_OPEN_NOCREATE); + *p = cpu_to_be32(NFS4_OPEN_NOCREATE); break; default: BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL); - *p++ = cpu_to_be32(NFS4_OPEN_CREATE); + *p = cpu_to_be32(NFS4_OPEN_CREATE); encode_createmode(xdr, arg); } } @@ -1184,13 +1184,13 @@ static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delega p = reserve_space(xdr, 4); switch (delegation_type) { case 0: - *p++ = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE); + *p = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE); break; case FMODE_READ: - *p++ = cpu_to_be32(NFS4_OPEN_DELEGATE_READ); + *p = cpu_to_be32(NFS4_OPEN_DELEGATE_READ); break; case FMODE_WRITE|FMODE_READ: - *p++ = cpu_to_be32(NFS4_OPEN_DELEGATE_WRITE); + *p = cpu_to_be32(NFS4_OPEN_DELEGATE_WRITE); break; default: BUG(); @@ -1202,7 +1202,7 @@ static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr * __be32 *p; p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_NULL); + *p = cpu_to_be32(NFS4_OPEN_CLAIM_NULL); encode_string(xdr, name->len, name->name); } @@ -1211,7 +1211,7 @@ static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type) __be32 *p; p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS); + *p = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS); encode_delegation_type(xdr, type); } @@ -1221,7 +1221,7 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR); - p = xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); + xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); encode_string(xdr, name->len, name->name); } @@ -1253,7 +1253,7 @@ static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_co p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4); *p++ = cpu_to_be32(OP_OPEN_CONFIRM); p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); - *p++ = cpu_to_be32(arg->seqid->sequence->counter); + *p = cpu_to_be32(arg->seqid->sequence->counter); hdr->nops++; hdr->replen += decode_open_confirm_maxsz; } @@ -1265,7 +1265,7 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4); *p++ = cpu_to_be32(OP_OPEN_DOWNGRADE); p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); - *p++ = cpu_to_be32(arg->seqid->sequence->counter); + *p = cpu_to_be32(arg->seqid->sequence->counter); encode_share_access(xdr, arg->fmode); hdr->nops++; hdr->replen += decode_open_downgrade_maxsz; @@ -1280,7 +1280,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd p = reserve_space(xdr, 8 + len); *p++ = cpu_to_be32(OP_PUTFH); *p++ = cpu_to_be32(len); - p = xdr_encode_opaque_fixed(p, fh->data, len); + xdr_encode_opaque_fixed(p, fh->data, len); hdr->nops++; hdr->replen += decode_putfh_maxsz; } @@ -1290,7 +1290,7 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) __be32 *p; p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(OP_PUTROOTFH); + *p = cpu_to_be32(OP_PUTROOTFH); hdr->nops++; hdr->replen += decode_putrootfh_maxsz; } @@ -1303,9 +1303,9 @@ static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context p = reserve_space(xdr, NFS4_STATEID_SIZE); if (ctx->state != NULL) { nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner); - p = xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE); + xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE); } else - p = xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); + xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); } static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr) @@ -1313,13 +1313,13 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, __be32 *p; p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(OP_READ); + *p = cpu_to_be32(OP_READ); encode_stateid(xdr, args->context); p = reserve_space(xdr, 12); p = xdr_encode_hyper(p, args->offset); - *p++ = cpu_to_be32(args->count); + *p = cpu_to_be32(args->count); hdr->nops++; hdr->replen += decode_read_maxsz; } @@ -1345,7 +1345,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg else attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); - *p++ = cpu_to_be32(attrs[1] & readdir->bitmask[1]); + *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); hdr->nops++; hdr->replen += decode_readdir_maxsz; dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", @@ -1362,7 +1362,7 @@ static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink * __be32 *p; p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(OP_READLINK); + *p = cpu_to_be32(OP_READLINK); hdr->nops++; hdr->replen += decode_readlink_maxsz; } @@ -1374,7 +1374,7 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc p = reserve_space(xdr, 8 + name->len); *p++ = cpu_to_be32(OP_REMOVE); *p++ = cpu_to_be32(name->len); - p = xdr_encode_opaque_fixed(p, name->name, name->len); + xdr_encode_opaque_fixed(p, name->name, name->len); hdr->nops++; hdr->replen += decode_remove_maxsz; } @@ -1386,11 +1386,11 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co p = reserve_space(xdr, 8 + oldname->len); *p++ = cpu_to_be32(OP_RENAME); *p++ = cpu_to_be32(oldname->len); - p = xdr_encode_opaque_fixed(p, oldname->name, oldname->len); + xdr_encode_opaque_fixed(p, oldname->name, oldname->len); p = reserve_space(xdr, 4 + newname->len); *p++ = cpu_to_be32(newname->len); - p = xdr_encode_opaque_fixed(p, newname->name, newname->len); + xdr_encode_opaque_fixed(p, newname->name, newname->len); hdr->nops++; hdr->replen += decode_rename_maxsz; } @@ -1401,7 +1401,7 @@ static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client p = reserve_space(xdr, 12); *p++ = cpu_to_be32(OP_RENEW); - p = xdr_encode_hyper(p, client_stateid->cl_clientid); + xdr_encode_hyper(p, client_stateid->cl_clientid); hdr->nops++; hdr->replen += decode_renew_maxsz; } @@ -1412,7 +1412,7 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) __be32 *p; p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(OP_RESTOREFH); + *p = cpu_to_be32(OP_RESTOREFH); hdr->nops++; hdr->replen += decode_restorefh_maxsz; } @@ -1424,14 +1424,14 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_SETATTR); - p = xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); + xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); p = reserve_space(xdr, 2*4); *p++ = cpu_to_be32(1); - *p++ = cpu_to_be32(FATTR4_WORD0_ACL); + *p = cpu_to_be32(FATTR4_WORD0_ACL); if (arg->acl_len % 4) return -EINVAL; p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(arg->acl_len); + *p = cpu_to_be32(arg->acl_len); xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); hdr->nops++; hdr->replen += decode_setacl_maxsz; @@ -1444,7 +1444,7 @@ encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) __be32 *p; p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(OP_SAVEFH); + *p = cpu_to_be32(OP_SAVEFH); hdr->nops++; hdr->replen += decode_savefh_maxsz; } @@ -1455,7 +1455,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_SETATTR); - p = xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE); + xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE); hdr->nops++; hdr->replen += decode_setattr_maxsz; encode_attrs(xdr, arg->iap, server); @@ -1467,15 +1467,15 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE); *p++ = cpu_to_be32(OP_SETCLIENTID); - p = xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE); + xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE); encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(setclientid->sc_prog); + *p = cpu_to_be32(setclientid->sc_prog); encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid); encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr); p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(setclientid->sc_cb_ident); + *p = cpu_to_be32(setclientid->sc_cb_ident); hdr->nops++; hdr->replen += decode_setclientid_maxsz; } @@ -1487,7 +1487,7 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_ p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE); *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); p = xdr_encode_hyper(p, client_state->cl_clientid); - p = xdr_encode_opaque_fixed(p, client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); + xdr_encode_opaque_fixed(p, client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); hdr->nops++; hdr->replen += decode_setclientid_confirm_maxsz; } @@ -1497,14 +1497,14 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg __be32 *p; p = reserve_space(xdr, 4); - *p++ = cpu_to_be32(OP_WRITE); + *p = cpu_to_be32(OP_WRITE); encode_stateid(xdr, args->context); p = reserve_space(xdr, 16); p = xdr_encode_hyper(p, args->offset); *p++ = cpu_to_be32(args->stable); - *p++ = cpu_to_be32(args->count); + *p = cpu_to_be32(args->count); xdr_write_pages(xdr, args->pages, args->pgbase, args->count); hdr->nops++; @@ -1518,7 +1518,7 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); *p++ = cpu_to_be32(OP_DELEGRETURN); - p = xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); + xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); hdr->nops++; hdr->replen += decode_delegreturn_maxsz; } @@ -1533,14 +1533,14 @@ static void encode_exchange_id(struct xdr_stream *xdr, p = reserve_space(xdr, 4 + sizeof(args->verifier->data)); *p++ = cpu_to_be32(OP_EXCHANGE_ID); - p = xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data)); + xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data)); encode_string(xdr, args->id_len, args->id); p = reserve_space(xdr, 12); *p++ = cpu_to_be32(args->flags); *p++ = cpu_to_be32(0); /* zero length state_protect4_a */ - *p++ = cpu_to_be32(0); /* zero length implementation id array */ + *p = cpu_to_be32(0); /* zero length implementation id array */ hdr->nops++; hdr->replen += decode_exchange_id_maxsz; } @@ -1591,7 +1591,7 @@ static void encode_create_session(struct xdr_stream *xdr, p = xdr_encode_opaque_fixed(p, machine_name, len); *p++ = cpu_to_be32(0); /* UID */ *p++ = cpu_to_be32(0); /* GID */ - *p++ = cpu_to_be32(0); /* No more gids */ + *p = cpu_to_be32(0); /* No more gids */ hdr->nops++; hdr->replen += decode_create_session_maxsz; } @@ -1603,7 +1603,7 @@ static void encode_destroy_session(struct xdr_stream *xdr, __be32 *p; p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN); *p++ = cpu_to_be32(OP_DESTROY_SESSION); - p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); + xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); hdr->nops++; hdr->replen += decode_destroy_session_maxsz; } @@ -1646,7 +1646,7 @@ static void encode_sequence(struct xdr_stream *xdr, *p++ = cpu_to_be32(slot->seq_nr); *p++ = cpu_to_be32(args->sa_slotid); *p++ = cpu_to_be32(tp->highest_used_slotid); - *p++ = cpu_to_be32(args->sa_cache_this); + *p = cpu_to_be32(args->sa_cache_this); hdr->nops++; hdr->replen += decode_sequence_maxsz; #endif /* CONFIG_NFS_V4_1 */ -- cgit v0.10.2 From 811652bd6edd66dd35bf9caacdfe96d19f75a47e Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:34 +0300 Subject: nfs: nfs4xdr: merge xdr_encode_int+xdr_encode_opaque_fixed into xdr_encode_opaque use encode_string where appropriate. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index d75f821..efa78ad 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -732,9 +732,8 @@ static void encode_compound_hdr(struct xdr_stream *xdr, dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); - p = reserve_space(xdr, 12 + hdr->taglen); - *p++ = cpu_to_be32(hdr->taglen); - p = xdr_encode_opaque_fixed(p, hdr->tag, hdr->taglen); + p = reserve_space(xdr, 4 + hdr->taglen + 8); + p = xdr_encode_opaque(p, hdr->tag, hdr->taglen); *p++ = cpu_to_be32(hdr->minorversion); hdr->nops_p = p; *p = cpu_to_be32(hdr->nops); @@ -832,13 +831,11 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const } if (iap->ia_valid & ATTR_UID) { bmval1 |= FATTR4_WORD1_OWNER; - *p++ = cpu_to_be32(owner_namelen); - p = xdr_encode_opaque_fixed(p, owner_name, owner_namelen); + p = xdr_encode_opaque(p, owner_name, owner_namelen); } if (iap->ia_valid & ATTR_GID) { bmval1 |= FATTR4_WORD1_OWNER_GROUP; - *p++ = cpu_to_be32(owner_grouplen); - p = xdr_encode_opaque_fixed(p, owner_group, owner_grouplen); + p = xdr_encode_opaque(p, owner_group, owner_grouplen); } if (iap->ia_valid & ATTR_ATIME_SET) { bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; @@ -939,9 +936,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * break; } - p = reserve_space(xdr, 4 + create->name->len); - *p++ = cpu_to_be32(create->name->len); - xdr_encode_opaque_fixed(p, create->name->name, create->name->len); + encode_string(xdr, create->name->len, create->name->name); hdr->nops++; hdr->replen += decode_create_maxsz; @@ -1007,8 +1002,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct p = reserve_space(xdr, 8 + name->len); *p++ = cpu_to_be32(OP_LINK); - *p++ = cpu_to_be32(name->len); - xdr_encode_opaque_fixed(p, name->name, name->len); + xdr_encode_opaque(p, name->name, name->len); hdr->nops++; hdr->replen += decode_link_maxsz; } @@ -1100,8 +1094,7 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc p = reserve_space(xdr, 8 + len); *p++ = cpu_to_be32(OP_LOOKUP); - *p++ = cpu_to_be32(len); - xdr_encode_opaque_fixed(p, name->name, len); + xdr_encode_opaque(p, name->name, len); hdr->nops++; hdr->replen += decode_lookup_maxsz; } @@ -1279,8 +1272,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd p = reserve_space(xdr, 8 + len); *p++ = cpu_to_be32(OP_PUTFH); - *p++ = cpu_to_be32(len); - xdr_encode_opaque_fixed(p, fh->data, len); + xdr_encode_opaque(p, fh->data, len); hdr->nops++; hdr->replen += decode_putfh_maxsz; } @@ -1373,8 +1365,7 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc p = reserve_space(xdr, 8 + name->len); *p++ = cpu_to_be32(OP_REMOVE); - *p++ = cpu_to_be32(name->len); - xdr_encode_opaque_fixed(p, name->name, name->len); + xdr_encode_opaque(p, name->name, name->len); hdr->nops++; hdr->replen += decode_remove_maxsz; } @@ -1383,14 +1374,10 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co { __be32 *p; - p = reserve_space(xdr, 8 + oldname->len); - *p++ = cpu_to_be32(OP_RENAME); - *p++ = cpu_to_be32(oldname->len); - xdr_encode_opaque_fixed(p, oldname->name, oldname->len); - - p = reserve_space(xdr, 4 + newname->len); - *p++ = cpu_to_be32(newname->len); - xdr_encode_opaque_fixed(p, newname->name, newname->len); + p = reserve_space(xdr, 4); + *p = cpu_to_be32(OP_RENAME); + encode_string(xdr, oldname->len, oldname->name); + encode_string(xdr, newname->len, newname->name); hdr->nops++; hdr->replen += decode_rename_maxsz; } @@ -1587,8 +1574,7 @@ static void encode_create_session(struct xdr_stream *xdr, /* authsys_parms rfc1831 */ *p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ - *p++ = cpu_to_be32(len); - p = xdr_encode_opaque_fixed(p, machine_name, len); + p = xdr_encode_opaque(p, machine_name, len); *p++ = cpu_to_be32(0); /* UID */ *p++ = cpu_to_be32(0); /* GID */ *p = cpu_to_be32(0); /* No more gids */ -- cgit v0.10.2 From 6f723f7710024bb151ca8c5277ce8c71beec4db8 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:37 +0300 Subject: nfs: nfs4xdr: get rid of READ32 s/READ32\((.*)\)/\1 = be32_to_cpup(p++)/ Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index efa78ad..5f6b46f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2433,7 +2433,6 @@ static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define READ32(x) (x) = ntohl(*p++) #define READ64(x) do { \ (x) = (u64)ntohl(*p++) << 32; \ (x) |= ntohl(*p++); \ @@ -2464,7 +2463,7 @@ static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char __be32 *p; READ_BUF(4); - READ32(*len); + *len = be32_to_cpup(p++); READ_BUF(*len); *string = (char *)p; return 0; @@ -2475,13 +2474,13 @@ static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) __be32 *p; READ_BUF(8); - READ32(hdr->status); - READ32(hdr->taglen); + hdr->status = be32_to_cpup(p++); + hdr->taglen = be32_to_cpup(p++); READ_BUF(hdr->taglen + 4); hdr->tag = (char *)p; p += XDR_QUADLEN(hdr->taglen); - READ32(hdr->nops); + hdr->nops = be32_to_cpup(p++); if (unlikely(hdr->nops < 1)) return nfs4_stat_to_errno(hdr->status); return 0; @@ -2494,14 +2493,14 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) int32_t nfserr; READ_BUF(8); - READ32(opnum); + opnum = be32_to_cpup(p++); if (opnum != expected) { dprintk("nfs: Server returned operation" " %d but we issued a request for %d\n", opnum, expected); return -EIO; } - READ32(nfserr); + nfserr = be32_to_cpup(p++); if (nfserr != NFS_OK) return nfs4_stat_to_errno(nfserr); return 0; @@ -2524,14 +2523,14 @@ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) __be32 *p; READ_BUF(4); - READ32(bmlen); + bmlen = be32_to_cpup(p++); bitmap[0] = bitmap[1] = 0; READ_BUF((bmlen << 2)); if (bmlen > 0) { - READ32(bitmap[0]); + bitmap[0] = be32_to_cpup(p++); if (bmlen > 1) - READ32(bitmap[1]); + bitmap[1] = be32_to_cpup(p++); } return 0; } @@ -2541,7 +2540,7 @@ static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 *p; READ_BUF(4); - READ32(*attrlen); + *attrlen = be32_to_cpup(p++); *savep = xdr->p; return 0; } @@ -2567,7 +2566,7 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t * return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) { READ_BUF(4); - READ32(*type); + *type = be32_to_cpup(p++); if (*type < NF4REG || *type > NF4NAMEDATTR) { dprintk("%s: bad type %d\n", __func__, *type); return -EIO; @@ -2625,7 +2624,7 @@ static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, ui return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) { READ_BUF(4); - READ32(*res); + *res = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT; } dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true"); @@ -2641,7 +2640,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) { READ_BUF(4); - READ32(*res); + *res = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT; } dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true"); @@ -2679,7 +2678,7 @@ static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) { READ_BUF(4); - READ32(*res); + *res = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME; } dprintk("%s: file size=%u\n", __func__, (unsigned int)*res); @@ -2695,7 +2694,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) { READ_BUF(4); - READ32(*res); + *res = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT; } dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res); @@ -2796,7 +2795,7 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) int status = 0; READ_BUF(4); - READ32(n); + n = be32_to_cpup(p++); if (n == 0) goto root_path; dprintk("path "); @@ -2848,7 +2847,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st if (unlikely(status != 0)) goto out; READ_BUF(4); - READ32(n); + n = be32_to_cpup(p++); if (n <= 0) goto out_eio; res->nlocations = 0; @@ -2857,7 +2856,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st struct nfs4_fs_location *loc = &res->locations[res->nlocations]; READ_BUF(4); - READ32(m); + m = be32_to_cpup(p++); loc->nservers = 0; dprintk("%s: servers ", __func__); @@ -2928,7 +2927,7 @@ static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) { READ_BUF(4); - READ32(*maxlink); + *maxlink = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_MAXLINK; } dprintk("%s: maxlink=%u\n", __func__, *maxlink); @@ -2945,7 +2944,7 @@ static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) { READ_BUF(4); - READ32(*maxname); + *maxname = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_MAXNAME; } dprintk("%s: maxname=%u\n", __func__, *maxname); @@ -3005,7 +3004,7 @@ static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *m return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_MODE)) { READ_BUF(4); - READ32(tmp); + tmp = be32_to_cpup(p++); *mode = tmp & ~S_IFMT; bitmap[1] &= ~FATTR4_WORD1_MODE; ret = NFS_ATTR_FATTR_MODE; @@ -3024,7 +3023,7 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) { READ_BUF(4); - READ32(*nlink); + *nlink = be32_to_cpup(p++); bitmap[1] &= ~FATTR4_WORD1_NUMLINKS; ret = NFS_ATTR_FATTR_NLINK; } @@ -3043,7 +3042,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) { READ_BUF(4); - READ32(len); + len = be32_to_cpup(p++); READ_BUF(len); if (len < XDR_MAX_NETOBJ) { if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0) @@ -3071,7 +3070,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) { READ_BUF(4); - READ32(len); + len = be32_to_cpup(p++); READ_BUF(len); if (len < XDR_MAX_NETOBJ) { if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0) @@ -3101,8 +3100,8 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde dev_t tmp; READ_BUF(8); - READ32(major); - READ32(minor); + major = be32_to_cpup(p++); + minor = be32_to_cpup(p++); tmp = MKDEV(major, minor); if (MAJOR(tmp) == major && MINOR(tmp) == minor) *rdev = tmp; @@ -3191,7 +3190,7 @@ static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time) READ_BUF(12); READ64(sec); - READ32(nsec); + nsec = be32_to_cpup(p++); time->tv_sec = (time_t)sec; time->tv_nsec = (long)nsec; return 0; @@ -3273,7 +3272,7 @@ static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *c __be32 *p; READ_BUF(20); - READ32(cinfo->atomic); + cinfo->atomic = be32_to_cpup(p++); READ64(cinfo->before); READ64(cinfo->after); return 0; @@ -3289,8 +3288,8 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) if (status) return status; READ_BUF(8); - READ32(supp); - READ32(acc); + supp = be32_to_cpup(p++); + acc = be32_to_cpup(p++); access->supported = supp; access->access = acc; return 0; @@ -3336,7 +3335,7 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) if ((status = decode_change_info(xdr, cinfo))) return status; READ_BUF(4); - READ32(bmlen); + bmlen = be32_to_cpup(p++); READ_BUF(bmlen << 2); return 0; } @@ -3591,7 +3590,7 @@ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) return status; READ_BUF(4); - READ32(len); + len = be32_to_cpup(p++); if (len > NFS4_FHSIZE) return -EIO; fh->size = len; @@ -3622,7 +3621,7 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) READ_BUF(32); READ64(offset); READ64(length); - READ32(type); + type = be32_to_cpup(p++); if (fl != NULL) { fl->fl_start = (loff_t)offset; fl->fl_end = fl->fl_start + (loff_t)length - 1; @@ -3634,7 +3633,7 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) fl->fl_pid = 0; } READ64(clientid); - READ32(namelen); + namelen = be32_to_cpup(p++); READ_BUF(namelen); return -NFS4ERR_DENIED; } @@ -3695,14 +3694,14 @@ static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize) uint32_t limit_type, nblocks, blocksize; READ_BUF(12); - READ32(limit_type); + limit_type = be32_to_cpup(p++); switch (limit_type) { case 1: READ64(*maxsize); break; case 2: - READ32(nblocks); - READ32(blocksize); + nblocks = be32_to_cpup(p++); + blocksize = be32_to_cpup(p++); *maxsize = (uint64_t)nblocks * (uint64_t)blocksize; } return 0; @@ -3714,14 +3713,14 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) uint32_t delegation_type; READ_BUF(4); - READ32(delegation_type); + delegation_type = be32_to_cpup(p++); if (delegation_type == NFS4_OPEN_DELEGATE_NONE) { res->delegation_type = 0; return 0; } READ_BUF(NFS4_STATEID_SIZE+4); COPYMEM(res->delegation.data, NFS4_STATEID_SIZE); - READ32(res->do_recall); + res->do_recall = be32_to_cpup(p++); switch (delegation_type) { case NFS4_OPEN_DELEGATE_READ: @@ -3752,15 +3751,15 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) decode_change_info(xdr, &res->cinfo); READ_BUF(8); - READ32(res->rflags); - READ32(bmlen); + res->rflags = be32_to_cpup(p++); + bmlen = be32_to_cpup(p++); if (bmlen > 10) goto xdr_error; READ_BUF(bmlen << 2); savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE); for (i = 0; i < savewords; ++i) - READ32(res->attrset[i]); + res->attrset[i] = be32_to_cpup(p++); for (; i < NFS4_BITMAP_SIZE; i++) res->attrset[i] = 0; @@ -3821,8 +3820,8 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_ if (status) return status; READ_BUF(8); - READ32(eof); - READ32(count); + eof = be32_to_cpup(p++); + count = be32_to_cpup(p++); hdrlen = (u8 *) p - (u8 *) iov->iov_base; recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { @@ -3948,7 +3947,7 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) /* Convert length of symlink */ READ_BUF(4); - READ32(len); + len = be32_to_cpup(p++); if (len >= rcvbuf->page_len || len <= 0) { dprintk("nfs: server returned giant symlink!\n"); return -ENAMETOOLONG; @@ -4070,7 +4069,7 @@ static int decode_setattr(struct xdr_stream *xdr) if (status) return status; READ_BUF(4); - READ32(bmlen); + bmlen = be32_to_cpup(p++); READ_BUF(bmlen << 2); return 0; } @@ -4082,13 +4081,13 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) int32_t nfserr; READ_BUF(8); - READ32(opnum); + opnum = be32_to_cpup(p++); if (opnum != OP_SETCLIENTID) { dprintk("nfs: decode_setclientid: Server returned operation" " %d\n", opnum); return -EIO; } - READ32(nfserr); + nfserr = be32_to_cpup(p++); if (nfserr == NFS_OK) { READ_BUF(8 + NFS4_VERIFIER_SIZE); READ64(clp->cl_clientid); @@ -4098,12 +4097,12 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) /* skip netid string */ READ_BUF(4); - READ32(len); + len = be32_to_cpup(p++); READ_BUF(len); /* skip uaddr string */ READ_BUF(4); - READ32(len); + len = be32_to_cpup(p++); READ_BUF(len); return -NFSERR_CLID_INUSE; } else @@ -4127,8 +4126,8 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) return status; READ_BUF(16); - READ32(res->count); - READ32(res->verf->committed); + res->count = be32_to_cpup(p++); + res->verf->committed = be32_to_cpup(p++); COPYMEM(res->verf->verifier, 8); return 0; } @@ -4154,11 +4153,11 @@ static int decode_exchange_id(struct xdr_stream *xdr, READ_BUF(8); READ64(clp->cl_ex_clid); READ_BUF(12); - READ32(clp->cl_seqid); - READ32(clp->cl_exchange_flags); + clp->cl_seqid = be32_to_cpup(p++); + clp->cl_exchange_flags = be32_to_cpup(p++); /* We ask for SP4_NONE */ - READ32(dummy); + dummy = be32_to_cpup(p++); if (dummy != SP4_NONE) return -EIO; @@ -4167,17 +4166,17 @@ static int decode_exchange_id(struct xdr_stream *xdr, /* Throw away Major id */ READ_BUF(4); - READ32(dummy); + dummy = be32_to_cpup(p++); READ_BUF(dummy); /* Throw away server_scope */ READ_BUF(4); - READ32(dummy); + dummy = be32_to_cpup(p++); READ_BUF(dummy); /* Throw away Implementation id array */ READ_BUF(4); - READ32(dummy); + dummy = be32_to_cpup(p++); READ_BUF(dummy); return 0; @@ -4190,13 +4189,13 @@ static int decode_chan_attrs(struct xdr_stream *xdr, u32 nr_attrs; READ_BUF(28); - READ32(attrs->headerpadsz); - READ32(attrs->max_rqst_sz); - READ32(attrs->max_resp_sz); - READ32(attrs->max_resp_sz_cached); - READ32(attrs->max_ops); - READ32(attrs->max_reqs); - READ32(nr_attrs); + attrs->headerpadsz = be32_to_cpup(p++); + attrs->max_rqst_sz = be32_to_cpup(p++); + attrs->max_resp_sz = be32_to_cpup(p++); + attrs->max_resp_sz_cached = be32_to_cpup(p++); + attrs->max_ops = be32_to_cpup(p++); + attrs->max_reqs = be32_to_cpup(p++); + nr_attrs = be32_to_cpup(p++); if (unlikely(nr_attrs > 1)) { printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n", __func__, nr_attrs); @@ -4226,8 +4225,8 @@ static int decode_create_session(struct xdr_stream *xdr, /* seqid, flags */ READ_BUF(8); - READ32(clp->cl_seqid); - READ32(session->flags); + clp->cl_seqid = be32_to_cpup(p++); + session->flags = be32_to_cpup(p++); /* Channel attributes */ status = decode_chan_attrs(xdr, &session->fc_attrs); @@ -4275,23 +4274,23 @@ static int decode_sequence(struct xdr_stream *xdr, goto out_err; } /* seqid */ - READ32(dummy); + dummy = be32_to_cpup(p++); if (dummy != slot->seq_nr) { dprintk("%s Invalid sequence number\n", __func__); goto out_err; } /* slot id */ - READ32(dummy); + dummy = be32_to_cpup(p++); if (dummy != res->sr_slotid) { dprintk("%s Invalid slot id\n", __func__); goto out_err; } /* highest slot id - currently not processed */ - READ32(dummy); + dummy = be32_to_cpup(p++); /* target highest slot id - currently not processed */ - READ32(dummy); + dummy = be32_to_cpup(p++); /* result flags - currently not processed */ - READ32(dummy); + dummy = be32_to_cpup(p++); status = 0; out_err: res->sr_status = status; -- cgit v0.10.2 From 3ceb4dbb993fdab6a6fafc69db36686278871134 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:41 +0300 Subject: nfs: nfs4xdr: get rid of READ64 s/READ64\(\*(.*)\)/p = xdr_decode_hyper(p, \1)/ s/READ64\((.*)\)/p = xdr_decode_hyper(p, &\1)/ Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5f6b46f..238189c 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2433,10 +2433,6 @@ static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define READ64(x) do { \ - (x) = (u64)ntohl(*p++) << 32; \ - (x) |= ntohl(*p++); \ -} while (0) #define READTIME(x) do { \ p++; \ (x.tv_sec) = ntohl(*p++); \ @@ -2588,7 +2584,7 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) { READ_BUF(8); - READ64(*change); + p = xdr_decode_hyper(p, change); bitmap[0] &= ~FATTR4_WORD0_CHANGE; ret = NFS_ATTR_FATTR_CHANGE; } @@ -2607,7 +2603,7 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t * return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) { READ_BUF(8); - READ64(*size); + p = xdr_decode_hyper(p, size); bitmap[0] &= ~FATTR4_WORD0_SIZE; ret = NFS_ATTR_FATTR_SIZE; } @@ -2658,8 +2654,8 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_FSID)) { READ_BUF(16); - READ64(fsid->major); - READ64(fsid->minor); + p = xdr_decode_hyper(p, &fsid->major); + p = xdr_decode_hyper(p, &fsid->minor); bitmap[0] &= ~FATTR4_WORD0_FSID; ret = NFS_ATTR_FATTR_FSID; } @@ -2711,7 +2707,7 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) { READ_BUF(8); - READ64(*fileid); + p = xdr_decode_hyper(p, fileid); bitmap[0] &= ~FATTR4_WORD0_FILEID; ret = NFS_ATTR_FATTR_FILEID; } @@ -2729,7 +2725,7 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) { READ_BUF(8); - READ64(*fileid); + p = xdr_decode_hyper(p, fileid); bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; ret = NFS_ATTR_FATTR_FILEID; } @@ -2747,7 +2743,7 @@ static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) { READ_BUF(8); - READ64(*res); + p = xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL; } dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res); @@ -2764,7 +2760,7 @@ static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) { READ_BUF(8); - READ64(*res); + p = xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_FILES_FREE; } dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res); @@ -2781,7 +2777,7 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) { READ_BUF(8); - READ64(*res); + p = xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL; } dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res); @@ -2910,7 +2906,7 @@ static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uin return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) { READ_BUF(8); - READ64(*res); + p = xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE; } dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res); @@ -2962,7 +2958,7 @@ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) { uint64_t maxread; READ_BUF(8); - READ64(maxread); + p = xdr_decode_hyper(p, &maxread); if (maxread > 0x7FFFFFFF) maxread = 0x7FFFFFFF; *res = (uint32_t)maxread; @@ -2983,7 +2979,7 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32 if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) { uint64_t maxwrite; READ_BUF(8); - READ64(maxwrite); + p = xdr_decode_hyper(p, &maxwrite); if (maxwrite > 0x7FFFFFFF) maxwrite = 0x7FFFFFFF; *res = (uint32_t)maxwrite; @@ -3122,7 +3118,7 @@ static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) { READ_BUF(8); - READ64(*res); + p = xdr_decode_hyper(p, res); bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL; } dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res); @@ -3139,7 +3135,7 @@ static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) { READ_BUF(8); - READ64(*res); + p = xdr_decode_hyper(p, res); bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE; } dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res); @@ -3156,7 +3152,7 @@ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uin return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) { READ_BUF(8); - READ64(*res); + p = xdr_decode_hyper(p, res); bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL; } dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res); @@ -3173,7 +3169,7 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) { READ_BUF(8); - READ64(*used); + p = xdr_decode_hyper(p, used); bitmap[1] &= ~FATTR4_WORD1_SPACE_USED; ret = NFS_ATTR_FATTR_SPACE_USED; } @@ -3189,7 +3185,7 @@ static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time) uint32_t nsec; READ_BUF(12); - READ64(sec); + p = xdr_decode_hyper(p, &sec); nsec = be32_to_cpup(p++); time->tv_sec = (time_t)sec; time->tv_nsec = (long)nsec; @@ -3273,8 +3269,8 @@ static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *c READ_BUF(20); cinfo->atomic = be32_to_cpup(p++); - READ64(cinfo->before); - READ64(cinfo->after); + p = xdr_decode_hyper(p, &cinfo->before); + p = xdr_decode_hyper(p, &cinfo->after); return 0; } @@ -3619,8 +3615,8 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) uint32_t namelen, type; READ_BUF(32); - READ64(offset); - READ64(length); + p = xdr_decode_hyper(p, &offset); + p = xdr_decode_hyper(p, &length); type = be32_to_cpup(p++); if (fl != NULL) { fl->fl_start = (loff_t)offset; @@ -3632,7 +3628,7 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) fl->fl_type = F_RDLCK; fl->fl_pid = 0; } - READ64(clientid); + p = xdr_decode_hyper(p, &clientid); namelen = be32_to_cpup(p++); READ_BUF(namelen); return -NFS4ERR_DENIED; @@ -3697,7 +3693,7 @@ static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize) limit_type = be32_to_cpup(p++); switch (limit_type) { case 1: - READ64(*maxsize); + p = xdr_decode_hyper(p, maxsize); break; case 2: nblocks = be32_to_cpup(p++); @@ -4090,7 +4086,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) nfserr = be32_to_cpup(p++); if (nfserr == NFS_OK) { READ_BUF(8 + NFS4_VERIFIER_SIZE); - READ64(clp->cl_clientid); + p = xdr_decode_hyper(p, &clp->cl_clientid); COPYMEM(clp->cl_confirm.data, NFS4_VERIFIER_SIZE); } else if (nfserr == NFSERR_CLID_INUSE) { uint32_t len; @@ -4151,7 +4147,7 @@ static int decode_exchange_id(struct xdr_stream *xdr, return status; READ_BUF(8); - READ64(clp->cl_ex_clid); + p = xdr_decode_hyper(p, &clp->cl_ex_clid); READ_BUF(12); clp->cl_seqid = be32_to_cpup(p++); clp->cl_exchange_flags = be32_to_cpup(p++); -- cgit v0.10.2 From c816fd3406462702dee2e3859e70132c3aab7c10 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:44 +0300 Subject: nfs: nfs4xdr: get rid of READTIME It has no users. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 238189c..0c26bb2 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2433,11 +2433,6 @@ static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define READTIME(x) do { \ - p++; \ - (x.tv_sec) = ntohl(*p++); \ - (x.tv_nsec) = ntohl(*p++); \ -} while (0) #define COPYMEM(x,nbytes) do { \ memcpy((x), p, nbytes); \ p += XDR_QUADLEN(nbytes); \ -- cgit v0.10.2 From 686841b3cc3a71918b45ed148be7a01a4f10e3f8 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:48 +0300 Subject: nfs: nfs4xdr: introduce print_overflow_msg Part fo the nfs4xdr cleanup. READ_BUF will go away. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 0c26bb2..8255ec7 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2441,14 +2441,18 @@ static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, #define READ_BUF(nbytes) do { \ p = xdr_inline_decode(xdr, nbytes); \ if (unlikely(!p)) { \ - dprintk("nfs: %s: prematurely hit end of receive" \ - " buffer\n", __func__); \ - dprintk("nfs: %s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \ - __func__, xdr->p, nbytes, xdr->end); \ + print_overflow_msg(__func__, xdr); \ return -EIO; \ } \ } while (0) +static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) +{ + dprintk("nfs: %s: prematurely hit end of receive buffer. " + "Remaining buffer length is %tu words.\n", + func, xdr->end - xdr->p); +} + static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string) { __be32 *p; -- cgit v0.10.2 From 07d30434cfe2f1a1553143c6b20f1fe68d2ef80a Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:52 +0300 Subject: nfs: nfs4xdr: introduce decode_opaque_fixed and decode_stateid helpers Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 8255ec7..86e6983 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -3290,19 +3290,34 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) return 0; } -static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) +static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len) { __be32 *p; + + p = xdr_inline_decode(xdr, len); + if (likely(p)) { + memcpy(buf, p, len); + return 0; + } + print_overflow_msg(__func__, xdr); + return -EIO; +} + +static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) +{ + return decode_opaque_fixed(xdr, stateid->data, NFS4_STATEID_SIZE); +} + +static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) +{ int status; status = decode_op_hdr(xdr, OP_CLOSE); if (status != -EIO) nfs_increment_open_seqid(status, res->seqid); - if (status) - return status; - READ_BUF(NFS4_STATEID_SIZE); - COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); - return 0; + if (!status) + status = decode_stateid(xdr, &res->stateid); + return status; } static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) @@ -3635,15 +3650,15 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res) { - __be32 *p; int status; status = decode_op_hdr(xdr, OP_LOCK); if (status == -EIO) goto out; if (status == 0) { - READ_BUF(NFS4_STATEID_SIZE); - COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); + status = decode_stateid(xdr, &res->stateid); + if (unlikely(status)) + goto out; } else if (status == -NFS4ERR_DENIED) status = decode_lock_denied(xdr, NULL); if (res->open_seqid != NULL) @@ -3664,16 +3679,13 @@ static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res) static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res) { - __be32 *p; int status; status = decode_op_hdr(xdr, OP_LOCKU); if (status != -EIO) nfs_increment_lock_seqid(status, res->seqid); - if (status == 0) { - READ_BUF(NFS4_STATEID_SIZE); - COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); - } + if (status == 0) + status = decode_stateid(xdr, &res->stateid); return status; } @@ -3706,6 +3718,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) { __be32 *p; uint32_t delegation_type; + int status; READ_BUF(4); delegation_type = be32_to_cpup(p++); @@ -3713,8 +3726,10 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) res->delegation_type = 0; return 0; } - READ_BUF(NFS4_STATEID_SIZE+4); - COPYMEM(res->delegation.data, NFS4_STATEID_SIZE); + status = decode_stateid(xdr, &res->delegation); + if (unlikely(status)) + return status; + READ_BUF(4); res->do_recall = be32_to_cpup(p++); switch (delegation_type) { @@ -3738,10 +3753,10 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) status = decode_op_hdr(xdr, OP_OPEN); if (status != -EIO) nfs_increment_open_seqid(status, res->seqid); - if (status) + if (!status) + status = decode_stateid(xdr, &res->stateid); + if (unlikely(status)) return status; - READ_BUF(NFS4_STATEID_SIZE); - COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); decode_change_info(xdr, &res->cinfo); @@ -3766,32 +3781,26 @@ xdr_error: static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) { - __be32 *p; int status; status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); if (status != -EIO) nfs_increment_open_seqid(status, res->seqid); - if (status) - return status; - READ_BUF(NFS4_STATEID_SIZE); - COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); - return 0; + if (!status) + status = decode_stateid(xdr, &res->stateid); + return status; } static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res) { - __be32 *p; int status; status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE); if (status != -EIO) nfs_increment_open_seqid(status, res->seqid); - if (status) - return status; - READ_BUF(NFS4_STATEID_SIZE); - COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); - return 0; + if (!status) + status = decode_stateid(xdr, &res->stateid); + return status; } static int decode_putfh(struct xdr_stream *xdr) -- cgit v0.10.2 From db942bbd09563e169cc5d9004c32c1de33220fd1 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:19:56 +0300 Subject: nfs: nfs4xdr: introduce decode_verifier helper Signed-off-by: Benny Halevy [Trond: Fixed up an 'uninitialised variable' issue in decode_readdir] Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 86e6983..404f2e6 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -3320,17 +3320,19 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) return status; } +static int decode_verifier(struct xdr_stream *xdr, void *verifier) +{ + return decode_opaque_fixed(xdr, verifier, 8); +} + static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) { - __be32 *p; int status; status = decode_op_hdr(xdr, OP_COMMIT); - if (status) - return status; - READ_BUF(8); - COPYMEM(res->verf->verifier, 8); - return 0; + if (!status) + status = decode_verifier(xdr, res->verf->verifier); + return status; } static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) @@ -3852,17 +3854,17 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n int status; status = decode_op_hdr(xdr, OP_READDIR); - if (status) + if (!status) + status = decode_verifier(xdr, readdir->verifier.data); + if (unlikely(status)) return status; - READ_BUF(8); - COPYMEM(readdir->verifier.data, 8); dprintk("%s: verifier = %08x:%08x\n", __func__, ((u32 *)readdir->verifier.data)[0], ((u32 *)readdir->verifier.data)[1]); - hdrlen = (char *) p - (char *) iov->iov_base; + hdrlen = (char *) xdr->p - (char *) iov->iov_base; recvd = rcvbuf->len - hdrlen; if (pglen > recvd) pglen = recvd; -- cgit v0.10.2 From e78291e4e07520348b0634095cf19ed3bc868965 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:20:00 +0300 Subject: nfs: nfs4xdr: introduce decode_sessionid helper Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 404f2e6..00630f4 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4212,6 +4212,11 @@ static int decode_chan_attrs(struct xdr_stream *xdr, return 0; } +static int decode_sessionid(struct xdr_stream *xdr, struct nfs4_sessionid *sid) +{ + return decode_opaque_fixed(xdr, sid->data, NFS4_MAX_SESSIONID_LEN); +} + static int decode_create_session(struct xdr_stream *xdr, struct nfs41_create_session_res *res) { @@ -4221,14 +4226,11 @@ static int decode_create_session(struct xdr_stream *xdr, struct nfs4_session *session = clp->cl_session; status = decode_op_hdr(xdr, OP_CREATE_SESSION); - - if (status) + if (!status) + status = decode_sessionid(xdr, &session->sess_id); + if (unlikely(status)) return status; - /* sessionid */ - READ_BUF(NFS4_MAX_SESSIONID_LEN); - COPYMEM(&session->sess_id, NFS4_MAX_SESSIONID_LEN); - /* seqid, flags */ READ_BUF(8); clp->cl_seqid = be32_to_cpup(p++); @@ -4262,7 +4264,9 @@ static int decode_sequence(struct xdr_stream *xdr, return 0; status = decode_op_hdr(xdr, OP_SEQUENCE); - if (status) + if (!status) + status = decode_sessionid(xdr, &id); + if (unlikely(status)) goto out_err; /* @@ -4271,15 +4275,16 @@ static int decode_sequence(struct xdr_stream *xdr, */ status = -ESERVERFAULT; - slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; - READ_BUF(NFS4_MAX_SESSIONID_LEN + 20); - COPYMEM(id.data, NFS4_MAX_SESSIONID_LEN); if (memcmp(id.data, res->sr_session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) { dprintk("%s Invalid session id\n", __func__); goto out_err; } + + READ_BUF(20); + /* seqid */ + slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; dummy = be32_to_cpup(p++); if (dummy != slot->seq_nr) { dprintk("%s Invalid sequence number\n", __func__); -- cgit v0.10.2 From 99398d0655ada44ae464a1c93d13cd438a306ecd Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:20:05 +0300 Subject: nfs: nfs4xdr: get rid of COPYMEM Just directly call memcpy. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 00630f4..f69aafc 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2433,11 +2433,6 @@ static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */ -#define COPYMEM(x,nbytes) do { \ - memcpy((x), p, nbytes); \ - p += XDR_QUADLEN(nbytes); \ -} while (0) - #define READ_BUF(nbytes) do { \ p = xdr_inline_decode(xdr, nbytes); \ if (unlikely(!p)) { \ @@ -3607,7 +3602,7 @@ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) return -EIO; fh->size = len; READ_BUF(len); - COPYMEM(fh->data, len); + memcpy(fh->data, p, len); return 0; } @@ -4097,7 +4092,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) if (nfserr == NFS_OK) { READ_BUF(8 + NFS4_VERIFIER_SIZE); p = xdr_decode_hyper(p, &clp->cl_clientid); - COPYMEM(clp->cl_confirm.data, NFS4_VERIFIER_SIZE); + memcpy(clp->cl_confirm.data, p, NFS4_VERIFIER_SIZE); } else if (nfserr == NFSERR_CLID_INUSE) { uint32_t len; @@ -4134,7 +4129,7 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) READ_BUF(16); res->count = be32_to_cpup(p++); res->verf->committed = be32_to_cpup(p++); - COPYMEM(res->verf->verifier, 8); + memcpy(res->verf->verifier, p, 8); return 0; } -- cgit v0.10.2 From 2460ba57c49c36dfef0b62c929461de09240fe17 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:20:10 +0300 Subject: nfs: nfs4xdr: simplify decode_exchange_id by reusing decode_opaque_inline Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index f69aafc..3f49da0 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4144,6 +4144,7 @@ static int decode_exchange_id(struct xdr_stream *xdr, { __be32 *p; uint32_t dummy; + char *dummy_str; int status; struct nfs_client *clp = res->client; @@ -4166,19 +4167,19 @@ static int decode_exchange_id(struct xdr_stream *xdr, READ_BUF(8); /* Throw away Major id */ - READ_BUF(4); - dummy = be32_to_cpup(p++); - READ_BUF(dummy); + status = decode_opaque_inline(xdr, &dummy, &dummy_str); + if (unlikely(status)) + return status; /* Throw away server_scope */ - READ_BUF(4); - dummy = be32_to_cpup(p++); - READ_BUF(dummy); + status = decode_opaque_inline(xdr, &dummy, &dummy_str); + if (unlikely(status)) + return status; /* Throw away Implementation id array */ - READ_BUF(4); - dummy = be32_to_cpup(p++); - READ_BUF(dummy); + status = decode_opaque_inline(xdr, &dummy, &dummy_str); + if (unlikely(status)) + return status; return 0; } -- cgit v0.10.2 From c0eae66ece40bdb8cd88c5106834b71a1c9f421c Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:20:14 +0300 Subject: nfs: nfs4xdr: get rid of READ_BUF Use xdr_inline_decode instead. Open code debug printout and error return. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 3f49da0..b0d690c 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2423,24 +2423,6 @@ static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, } #endif /* CONFIG_NFS_V4_1 */ -/* - * START OF "GENERIC" DECODE ROUTINES. - * These may look a little ugly since they are imported from a "generic" - * set of XDR encode/decode routines which are intended to be shared by - * all of our NFSv4 implementations (OpenBSD, MacOS X...). - * - * If the pain of reading these is too great, it should be a straightforward - * task to translate them into Linux-specific versions which are more - * consistent with the style used in NFSv2/v3... - */ -#define READ_BUF(nbytes) do { \ - p = xdr_inline_decode(xdr, nbytes); \ - if (unlikely(!p)) { \ - print_overflow_msg(__func__, xdr); \ - return -EIO; \ - } \ -} while (0) - static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) { dprintk("nfs: %s: prematurely hit end of receive buffer. " @@ -2452,28 +2434,42 @@ static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char { __be32 *p; - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; *len = be32_to_cpup(p++); - READ_BUF(*len); + p = xdr_inline_decode(xdr, *len); + if (unlikely(!p)) + goto out_overflow; *string = (char *)p; return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { __be32 *p; - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; hdr->status = be32_to_cpup(p++); hdr->taglen = be32_to_cpup(p++); - READ_BUF(hdr->taglen + 4); + p = xdr_inline_decode(xdr, hdr->taglen + 4); + if (unlikely(!p)) + goto out_overflow; hdr->tag = (char *)p; p += XDR_QUADLEN(hdr->taglen); hdr->nops = be32_to_cpup(p++); if (unlikely(hdr->nops < 1)) return nfs4_stat_to_errno(hdr->status); return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) @@ -2482,7 +2478,9 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) uint32_t opnum; int32_t nfserr; - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; opnum = be32_to_cpup(p++); if (opnum != expected) { dprintk("nfs: Server returned operation" @@ -2494,6 +2492,9 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) if (nfserr != NFS_OK) return nfs4_stat_to_errno(nfserr); return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } /* Dummy routine */ @@ -2503,8 +2504,11 @@ static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp) unsigned int strlen; char *str; - READ_BUF(12); - return decode_opaque_inline(xdr, &strlen, &str); + p = xdr_inline_decode(xdr, 12); + if (likely(p)) + return decode_opaque_inline(xdr, &strlen, &str); + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) @@ -2512,27 +2516,39 @@ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) uint32_t bmlen; __be32 *p; - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; bmlen = be32_to_cpup(p++); bitmap[0] = bitmap[1] = 0; - READ_BUF((bmlen << 2)); + p = xdr_inline_decode(xdr, (bmlen << 2)); + if (unlikely(!p)) + goto out_overflow; if (bmlen > 0) { bitmap[0] = be32_to_cpup(p++); if (bmlen > 1) bitmap[1] = be32_to_cpup(p++); } return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep) { __be32 *p; - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; *attrlen = be32_to_cpup(p++); *savep = xdr->p; return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask) @@ -2555,7 +2571,9 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t * if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) { - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; *type = be32_to_cpup(p++); if (*type < NF4REG || *type > NF4NAMEDATTR) { dprintk("%s: bad type %d\n", __func__, *type); @@ -2566,6 +2584,9 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t * } dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change) @@ -2577,7 +2598,9 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, change); bitmap[0] &= ~FATTR4_WORD0_CHANGE; ret = NFS_ATTR_FATTR_CHANGE; @@ -2585,6 +2608,9 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t dprintk("%s: change attribute=%Lu\n", __func__, (unsigned long long)*change); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size) @@ -2596,13 +2622,18 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t * if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, size); bitmap[0] &= ~FATTR4_WORD0_SIZE; ret = NFS_ATTR_FATTR_SIZE; } dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) @@ -2613,12 +2644,17 @@ static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, ui if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) { - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; *res = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT; } dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true"); return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) @@ -2629,12 +2665,17 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) { - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; *res = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT; } dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true"); return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid) @@ -2647,7 +2688,9 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_FSID)) { - READ_BUF(16); + p = xdr_inline_decode(xdr, 16); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, &fsid->major); p = xdr_decode_hyper(p, &fsid->minor); bitmap[0] &= ~FATTR4_WORD0_FSID; @@ -2657,6 +2700,9 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs (unsigned long long)fsid->major, (unsigned long long)fsid->minor); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) @@ -2667,12 +2713,17 @@ static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) { - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; *res = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME; } dprintk("%s: file size=%u\n", __func__, (unsigned int)*res); return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) @@ -2683,12 +2734,17 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) { - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; *res = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT; } dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res); return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) @@ -2700,13 +2756,18 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, fileid); bitmap[0] &= ~FATTR4_WORD0_FILEID; ret = NFS_ATTR_FATTR_FILEID; } dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid) @@ -2718,13 +2779,18 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U))) return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, fileid); bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; ret = NFS_ATTR_FATTR_FILEID; } dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) @@ -2736,12 +2802,17 @@ static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL; } dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) @@ -2753,12 +2824,17 @@ static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_FILES_FREE; } dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) @@ -2770,12 +2846,17 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL; } dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) @@ -2784,7 +2865,9 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) __be32 *p; int status = 0; - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; n = be32_to_cpup(p++); if (n == 0) goto root_path; @@ -2819,6 +2902,9 @@ out_eio: dprintk(" status %d", status); status = -EIO; goto out; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res) @@ -2836,7 +2922,9 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st status = decode_pathname(xdr, &res->fs_path); if (unlikely(status != 0)) goto out; - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; n = be32_to_cpup(p++); if (n <= 0) goto out_eio; @@ -2845,7 +2933,9 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st u32 m; struct nfs4_fs_location *loc = &res->locations[res->nlocations]; - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; m = be32_to_cpup(p++); loc->nservers = 0; @@ -2885,6 +2975,8 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st out: dprintk("%s: fs_locations done, error = %d\n", __func__, status); return status; +out_overflow: + print_overflow_msg(__func__, xdr); out_eio: status = -EIO; goto out; @@ -2899,12 +2991,17 @@ static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uin if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE; } dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink) @@ -2916,12 +3013,17 @@ static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) { - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; *maxlink = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_MAXLINK; } dprintk("%s: maxlink=%u\n", __func__, *maxlink); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname) @@ -2933,12 +3035,17 @@ static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U))) return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) { - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; *maxname = be32_to_cpup(p++); bitmap[0] &= ~FATTR4_WORD0_MAXNAME; } dprintk("%s: maxname=%u\n", __func__, *maxname); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) @@ -2951,7 +3058,9 @@ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) { uint64_t maxread; - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, &maxread); if (maxread > 0x7FFFFFFF) maxread = 0x7FFFFFFF; @@ -2960,6 +3069,9 @@ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ } dprintk("%s: maxread=%lu\n", __func__, (unsigned long)*res); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) @@ -2972,7 +3084,9 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32 return -EIO; if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) { uint64_t maxwrite; - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, &maxwrite); if (maxwrite > 0x7FFFFFFF) maxwrite = 0x7FFFFFFF; @@ -2981,6 +3095,9 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32 } dprintk("%s: maxwrite=%lu\n", __func__, (unsigned long)*res); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode) @@ -2993,7 +3110,9 @@ static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *m if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U))) return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_MODE)) { - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; tmp = be32_to_cpup(p++); *mode = tmp & ~S_IFMT; bitmap[1] &= ~FATTR4_WORD1_MODE; @@ -3001,6 +3120,9 @@ static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *m } dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink) @@ -3012,13 +3134,18 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U))) return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) { - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; *nlink = be32_to_cpup(p++); bitmap[1] &= ~FATTR4_WORD1_NUMLINKS; ret = NFS_ATTR_FATTR_NLINK; } dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *uid) @@ -3031,9 +3158,13 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U))) return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) { - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; len = be32_to_cpup(p++); - READ_BUF(len); + p = xdr_inline_decode(xdr, len); + if (unlikely(!p)) + goto out_overflow; if (len < XDR_MAX_NETOBJ) { if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0) ret = NFS_ATTR_FATTR_OWNER; @@ -3047,6 +3178,9 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf } dprintk("%s: uid=%d\n", __func__, (int)*uid); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *gid) @@ -3059,9 +3193,13 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U))) return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) { - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; len = be32_to_cpup(p++); - READ_BUF(len); + p = xdr_inline_decode(xdr, len); + if (unlikely(!p)) + goto out_overflow; if (len < XDR_MAX_NETOBJ) { if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0) ret = NFS_ATTR_FATTR_GROUP; @@ -3075,6 +3213,9 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf } dprintk("%s: gid=%d\n", __func__, (int)*gid); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev) @@ -3089,7 +3230,9 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) { dev_t tmp; - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; major = be32_to_cpup(p++); minor = be32_to_cpup(p++); tmp = MKDEV(major, minor); @@ -3100,6 +3243,9 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde } dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) @@ -3111,12 +3257,17 @@ static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U))) return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, res); bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL; } dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) @@ -3128,12 +3279,17 @@ static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U))) return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, res); bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE; } dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res) @@ -3145,12 +3301,17 @@ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uin if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U))) return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, res); bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL; } dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used) @@ -3162,7 +3323,9 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U))) return -EIO; if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) { - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, used); bitmap[1] &= ~FATTR4_WORD1_SPACE_USED; ret = NFS_ATTR_FATTR_SPACE_USED; @@ -3170,6 +3333,9 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint dprintk("%s: space used=%Lu\n", __func__, (unsigned long long)*used); return ret; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time) @@ -3178,12 +3344,17 @@ static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time) uint64_t sec; uint32_t nsec; - READ_BUF(12); + p = xdr_inline_decode(xdr, 12); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, &sec); nsec = be32_to_cpup(p++); time->tv_sec = (time_t)sec; time->tv_nsec = (long)nsec; return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) @@ -3261,11 +3432,16 @@ static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *c { __be32 *p; - READ_BUF(20); + p = xdr_inline_decode(xdr, 20); + if (unlikely(!p)) + goto out_overflow; cinfo->atomic = be32_to_cpup(p++); p = xdr_decode_hyper(p, &cinfo->before); p = xdr_decode_hyper(p, &cinfo->after); return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) @@ -3277,12 +3453,17 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) status = decode_op_hdr(xdr, OP_ACCESS); if (status) return status; - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; supp = be32_to_cpup(p++); acc = be32_to_cpup(p++); access->supported = supp; access->access = acc; return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len) @@ -3341,10 +3522,16 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) return status; if ((status = decode_change_info(xdr, cinfo))) return status; - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; bmlen = be32_to_cpup(p++); - READ_BUF(bmlen << 2); - return 0; + p = xdr_inline_decode(xdr, bmlen << 2); + if (likely(p)) + return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res) @@ -3596,14 +3783,21 @@ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) if (status) return status; - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; len = be32_to_cpup(p++); if (len > NFS4_FHSIZE) return -EIO; fh->size = len; - READ_BUF(len); + p = xdr_inline_decode(xdr, len); + if (unlikely(!p)) + goto out_overflow; memcpy(fh->data, p, len); return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) @@ -3625,7 +3819,9 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) __be32 *p; uint32_t namelen, type; - READ_BUF(32); + p = xdr_inline_decode(xdr, 32); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, &offset); p = xdr_decode_hyper(p, &length); type = be32_to_cpup(p++); @@ -3641,8 +3837,12 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) } p = xdr_decode_hyper(p, &clientid); namelen = be32_to_cpup(p++); - READ_BUF(namelen); - return -NFS4ERR_DENIED; + p = xdr_inline_decode(xdr, namelen); + if (likely(p)) + return -NFS4ERR_DENIED; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res) @@ -3697,7 +3897,9 @@ static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize) __be32 *p; uint32_t limit_type, nblocks, blocksize; - READ_BUF(12); + p = xdr_inline_decode(xdr, 12); + if (unlikely(!p)) + goto out_overflow; limit_type = be32_to_cpup(p++); switch (limit_type) { case 1: @@ -3709,6 +3911,9 @@ static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize) *maxsize = (uint64_t)nblocks * (uint64_t)blocksize; } return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) @@ -3717,7 +3922,9 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) uint32_t delegation_type; int status; - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; delegation_type = be32_to_cpup(p++); if (delegation_type == NFS4_OPEN_DELEGATE_NONE) { res->delegation_type = 0; @@ -3726,7 +3933,9 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) status = decode_stateid(xdr, &res->delegation); if (unlikely(status)) return status; - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; res->do_recall = be32_to_cpup(p++); switch (delegation_type) { @@ -3739,6 +3948,9 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) return -EIO; } return decode_ace(xdr, NULL, res->server->nfs_client); +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) @@ -3757,13 +3969,17 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) decode_change_info(xdr, &res->cinfo); - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; res->rflags = be32_to_cpup(p++); bmlen = be32_to_cpup(p++); if (bmlen > 10) goto xdr_error; - READ_BUF(bmlen << 2); + p = xdr_inline_decode(xdr, bmlen << 2); + if (unlikely(!p)) + goto out_overflow; savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE); for (i = 0; i < savewords; ++i) res->attrset[i] = be32_to_cpup(p++); @@ -3774,6 +3990,9 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) xdr_error: dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen); return -EIO; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) @@ -3820,7 +4039,9 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_ status = decode_op_hdr(xdr, OP_READ); if (status) return status; - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; eof = be32_to_cpup(p++); count = be32_to_cpup(p++); hdrlen = (u8 *) p - (u8 *) iov->iov_base; @@ -3835,6 +4056,9 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_ res->eof = eof; res->count = count; return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) @@ -3947,7 +4171,9 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) return status; /* Convert length of symlink */ - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; len = be32_to_cpup(p++); if (len >= rcvbuf->page_len || len <= 0) { dprintk("nfs: server returned giant symlink!\n"); @@ -3972,6 +4198,9 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) kaddr[len+rcvbuf->page_base] = '\0'; kunmap_atomic(kaddr, KM_USER0); return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) @@ -4069,10 +4298,16 @@ static int decode_setattr(struct xdr_stream *xdr) status = decode_op_hdr(xdr, OP_SETATTR); if (status) return status; - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; bmlen = be32_to_cpup(p++); - READ_BUF(bmlen << 2); - return 0; + p = xdr_inline_decode(xdr, bmlen << 2); + if (likely(p)) + return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) @@ -4081,7 +4316,9 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) uint32_t opnum; int32_t nfserr; - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; opnum = be32_to_cpup(p++); if (opnum != OP_SETCLIENTID) { dprintk("nfs: decode_setclientid: Server returned operation" @@ -4090,26 +4327,39 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) } nfserr = be32_to_cpup(p++); if (nfserr == NFS_OK) { - READ_BUF(8 + NFS4_VERIFIER_SIZE); + p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, &clp->cl_clientid); memcpy(clp->cl_confirm.data, p, NFS4_VERIFIER_SIZE); } else if (nfserr == NFSERR_CLID_INUSE) { uint32_t len; /* skip netid string */ - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; len = be32_to_cpup(p++); - READ_BUF(len); + p = xdr_inline_decode(xdr, len); + if (unlikely(!p)) + goto out_overflow; /* skip uaddr string */ - READ_BUF(4); + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; len = be32_to_cpup(p++); - READ_BUF(len); + p = xdr_inline_decode(xdr, len); + if (unlikely(!p)) + goto out_overflow; return -NFSERR_CLID_INUSE; } else return nfs4_stat_to_errno(nfserr); return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_setclientid_confirm(struct xdr_stream *xdr) @@ -4126,11 +4376,16 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) if (status) return status; - READ_BUF(16); + p = xdr_inline_decode(xdr, 16); + if (unlikely(!p)) + goto out_overflow; res->count = be32_to_cpup(p++); res->verf->committed = be32_to_cpup(p++); memcpy(res->verf->verifier, p, 8); return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_delegreturn(struct xdr_stream *xdr) @@ -4152,9 +4407,13 @@ static int decode_exchange_id(struct xdr_stream *xdr, if (status) return status; - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; p = xdr_decode_hyper(p, &clp->cl_ex_clid); - READ_BUF(12); + p = xdr_inline_decode(xdr, 12); + if (unlikely(!p)) + goto out_overflow; clp->cl_seqid = be32_to_cpup(p++); clp->cl_exchange_flags = be32_to_cpup(p++); @@ -4164,7 +4423,9 @@ static int decode_exchange_id(struct xdr_stream *xdr, return -EIO; /* Throw away minor_id */ - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; /* Throw away Major id */ status = decode_opaque_inline(xdr, &dummy, &dummy_str); @@ -4182,6 +4443,9 @@ static int decode_exchange_id(struct xdr_stream *xdr, return status; return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_chan_attrs(struct xdr_stream *xdr, @@ -4190,7 +4454,9 @@ static int decode_chan_attrs(struct xdr_stream *xdr, __be32 *p; u32 nr_attrs; - READ_BUF(28); + p = xdr_inline_decode(xdr, 28); + if (unlikely(!p)) + goto out_overflow; attrs->headerpadsz = be32_to_cpup(p++); attrs->max_rqst_sz = be32_to_cpup(p++); attrs->max_resp_sz = be32_to_cpup(p++); @@ -4203,9 +4469,15 @@ static int decode_chan_attrs(struct xdr_stream *xdr, __func__, nr_attrs); return -EINVAL; } - if (nr_attrs == 1) - READ_BUF(4); /* skip rdma_attrs */ + if (nr_attrs == 1) { + p = xdr_inline_decode(xdr, 4); /* skip rdma_attrs */ + if (unlikely(!p)) + goto out_overflow; + } return 0; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_sessionid(struct xdr_stream *xdr, struct nfs4_sessionid *sid) @@ -4228,7 +4500,9 @@ static int decode_create_session(struct xdr_stream *xdr, return status; /* seqid, flags */ - READ_BUF(8); + p = xdr_inline_decode(xdr, 8); + if (unlikely(!p)) + goto out_overflow; clp->cl_seqid = be32_to_cpup(p++); session->flags = be32_to_cpup(p++); @@ -4237,6 +4511,9 @@ static int decode_create_session(struct xdr_stream *xdr, if (!status) status = decode_chan_attrs(xdr, &session->bc_attrs); return status; +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; } static int decode_destroy_session(struct xdr_stream *xdr, void *dummy) @@ -4277,7 +4554,9 @@ static int decode_sequence(struct xdr_stream *xdr, goto out_err; } - READ_BUF(20); + p = xdr_inline_decode(xdr, 20); + if (unlikely(!p)) + goto out_overflow; /* seqid */ slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; @@ -4302,6 +4581,10 @@ static int decode_sequence(struct xdr_stream *xdr, out_err: res->sr_status = status; return status; +out_overflow: + print_overflow_msg(__func__, xdr); + status = -EIO; + goto out_err; #else /* CONFIG_NFS_V4_1 */ return 0; #endif /* CONFIG_NFS_V4_1 */ -- cgit v0.10.2 From cccddf4f5580131c9b963900e1d3400655e633cc Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Fri, 14 Aug 2009 17:20:19 +0300 Subject: nfs: nfs4xdr: optimize low level decoding do not increment decoding ptr if not needed. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index b0d690c..14b6f51 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2437,7 +2437,7 @@ static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - *len = be32_to_cpup(p++); + *len = be32_to_cpup(p); p = xdr_inline_decode(xdr, *len); if (unlikely(!p)) goto out_overflow; @@ -2456,14 +2456,14 @@ static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) if (unlikely(!p)) goto out_overflow; hdr->status = be32_to_cpup(p++); - hdr->taglen = be32_to_cpup(p++); + hdr->taglen = be32_to_cpup(p); p = xdr_inline_decode(xdr, hdr->taglen + 4); if (unlikely(!p)) goto out_overflow; hdr->tag = (char *)p; p += XDR_QUADLEN(hdr->taglen); - hdr->nops = be32_to_cpup(p++); + hdr->nops = be32_to_cpup(p); if (unlikely(hdr->nops < 1)) return nfs4_stat_to_errno(hdr->status); return 0; @@ -2488,7 +2488,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) opnum, expected); return -EIO; } - nfserr = be32_to_cpup(p++); + nfserr = be32_to_cpup(p); if (nfserr != NFS_OK) return nfs4_stat_to_errno(nfserr); return 0; @@ -2519,7 +2519,7 @@ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - bmlen = be32_to_cpup(p++); + bmlen = be32_to_cpup(p); bitmap[0] = bitmap[1] = 0; p = xdr_inline_decode(xdr, (bmlen << 2)); @@ -2528,7 +2528,7 @@ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) if (bmlen > 0) { bitmap[0] = be32_to_cpup(p++); if (bmlen > 1) - bitmap[1] = be32_to_cpup(p++); + bitmap[1] = be32_to_cpup(p); } return 0; out_overflow: @@ -2543,7 +2543,7 @@ static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - *attrlen = be32_to_cpup(p++); + *attrlen = be32_to_cpup(p); *savep = xdr->p; return 0; out_overflow: @@ -2574,7 +2574,7 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t * p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - *type = be32_to_cpup(p++); + *type = be32_to_cpup(p); if (*type < NF4REG || *type > NF4NAMEDATTR) { dprintk("%s: bad type %d\n", __func__, *type); return -EIO; @@ -2601,7 +2601,7 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, change); + xdr_decode_hyper(p, change); bitmap[0] &= ~FATTR4_WORD0_CHANGE; ret = NFS_ATTR_FATTR_CHANGE; } @@ -2625,7 +2625,7 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t * p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, size); + xdr_decode_hyper(p, size); bitmap[0] &= ~FATTR4_WORD0_SIZE; ret = NFS_ATTR_FATTR_SIZE; } @@ -2647,7 +2647,7 @@ static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, ui p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - *res = be32_to_cpup(p++); + *res = be32_to_cpup(p); bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT; } dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true"); @@ -2668,7 +2668,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - *res = be32_to_cpup(p++); + *res = be32_to_cpup(p); bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT; } dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true"); @@ -2692,7 +2692,7 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs if (unlikely(!p)) goto out_overflow; p = xdr_decode_hyper(p, &fsid->major); - p = xdr_decode_hyper(p, &fsid->minor); + xdr_decode_hyper(p, &fsid->minor); bitmap[0] &= ~FATTR4_WORD0_FSID; ret = NFS_ATTR_FATTR_FSID; } @@ -2716,7 +2716,7 @@ static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - *res = be32_to_cpup(p++); + *res = be32_to_cpup(p); bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME; } dprintk("%s: file size=%u\n", __func__, (unsigned int)*res); @@ -2737,7 +2737,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - *res = be32_to_cpup(p++); + *res = be32_to_cpup(p); bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT; } dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res); @@ -2759,7 +2759,7 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, fileid); + xdr_decode_hyper(p, fileid); bitmap[0] &= ~FATTR4_WORD0_FILEID; ret = NFS_ATTR_FATTR_FILEID; } @@ -2782,7 +2782,7 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, fileid); + xdr_decode_hyper(p, fileid); bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; ret = NFS_ATTR_FATTR_FILEID; } @@ -2805,7 +2805,7 @@ static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, res); + xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL; } dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res); @@ -2827,7 +2827,7 @@ static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, res); + xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_FILES_FREE; } dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res); @@ -2849,7 +2849,7 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, res); + xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL; } dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res); @@ -2868,7 +2868,7 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - n = be32_to_cpup(p++); + n = be32_to_cpup(p); if (n == 0) goto root_path; dprintk("path "); @@ -2925,7 +2925,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - n = be32_to_cpup(p++); + n = be32_to_cpup(p); if (n <= 0) goto out_eio; res->nlocations = 0; @@ -2936,7 +2936,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - m = be32_to_cpup(p++); + m = be32_to_cpup(p); loc->nservers = 0; dprintk("%s: servers ", __func__); @@ -2994,7 +2994,7 @@ static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uin p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, res); + xdr_decode_hyper(p, res); bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE; } dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res); @@ -3016,7 +3016,7 @@ static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - *maxlink = be32_to_cpup(p++); + *maxlink = be32_to_cpup(p); bitmap[0] &= ~FATTR4_WORD0_MAXLINK; } dprintk("%s: maxlink=%u\n", __func__, *maxlink); @@ -3038,7 +3038,7 @@ static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - *maxname = be32_to_cpup(p++); + *maxname = be32_to_cpup(p); bitmap[0] &= ~FATTR4_WORD0_MAXNAME; } dprintk("%s: maxname=%u\n", __func__, *maxname); @@ -3061,7 +3061,7 @@ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_ p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, &maxread); + xdr_decode_hyper(p, &maxread); if (maxread > 0x7FFFFFFF) maxread = 0x7FFFFFFF; *res = (uint32_t)maxread; @@ -3087,7 +3087,7 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32 p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, &maxwrite); + xdr_decode_hyper(p, &maxwrite); if (maxwrite > 0x7FFFFFFF) maxwrite = 0x7FFFFFFF; *res = (uint32_t)maxwrite; @@ -3113,7 +3113,7 @@ static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *m p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - tmp = be32_to_cpup(p++); + tmp = be32_to_cpup(p); *mode = tmp & ~S_IFMT; bitmap[1] &= ~FATTR4_WORD1_MODE; ret = NFS_ATTR_FATTR_MODE; @@ -3137,7 +3137,7 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - *nlink = be32_to_cpup(p++); + *nlink = be32_to_cpup(p); bitmap[1] &= ~FATTR4_WORD1_NUMLINKS; ret = NFS_ATTR_FATTR_NLINK; } @@ -3161,7 +3161,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - len = be32_to_cpup(p++); + len = be32_to_cpup(p); p = xdr_inline_decode(xdr, len); if (unlikely(!p)) goto out_overflow; @@ -3196,7 +3196,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - len = be32_to_cpup(p++); + len = be32_to_cpup(p); p = xdr_inline_decode(xdr, len); if (unlikely(!p)) goto out_overflow; @@ -3234,7 +3234,7 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde if (unlikely(!p)) goto out_overflow; major = be32_to_cpup(p++); - minor = be32_to_cpup(p++); + minor = be32_to_cpup(p); tmp = MKDEV(major, minor); if (MAJOR(tmp) == major && MINOR(tmp) == minor) *rdev = tmp; @@ -3260,7 +3260,7 @@ static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, res); + xdr_decode_hyper(p, res); bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL; } dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res); @@ -3282,7 +3282,7 @@ static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, res); + xdr_decode_hyper(p, res); bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE; } dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res); @@ -3304,7 +3304,7 @@ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uin p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, res); + xdr_decode_hyper(p, res); bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL; } dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res); @@ -3326,7 +3326,7 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, used); + xdr_decode_hyper(p, used); bitmap[1] &= ~FATTR4_WORD1_SPACE_USED; ret = NFS_ATTR_FATTR_SPACE_USED; } @@ -3348,7 +3348,7 @@ static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time) if (unlikely(!p)) goto out_overflow; p = xdr_decode_hyper(p, &sec); - nsec = be32_to_cpup(p++); + nsec = be32_to_cpup(p); time->tv_sec = (time_t)sec; time->tv_nsec = (long)nsec; return 0; @@ -3437,7 +3437,7 @@ static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *c goto out_overflow; cinfo->atomic = be32_to_cpup(p++); p = xdr_decode_hyper(p, &cinfo->before); - p = xdr_decode_hyper(p, &cinfo->after); + xdr_decode_hyper(p, &cinfo->after); return 0; out_overflow: print_overflow_msg(__func__, xdr); @@ -3457,7 +3457,7 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) if (unlikely(!p)) goto out_overflow; supp = be32_to_cpup(p++); - acc = be32_to_cpup(p++); + acc = be32_to_cpup(p); access->supported = supp; access->access = acc; return 0; @@ -3525,7 +3525,7 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - bmlen = be32_to_cpup(p++); + bmlen = be32_to_cpup(p); p = xdr_inline_decode(xdr, bmlen << 2); if (likely(p)) return 0; @@ -3786,7 +3786,7 @@ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - len = be32_to_cpup(p++); + len = be32_to_cpup(p); if (len > NFS4_FHSIZE) return -EIO; fh->size = len; @@ -3836,7 +3836,7 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) fl->fl_pid = 0; } p = xdr_decode_hyper(p, &clientid); - namelen = be32_to_cpup(p++); + namelen = be32_to_cpup(p); p = xdr_inline_decode(xdr, namelen); if (likely(p)) return -NFS4ERR_DENIED; @@ -3903,11 +3903,11 @@ static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize) limit_type = be32_to_cpup(p++); switch (limit_type) { case 1: - p = xdr_decode_hyper(p, maxsize); + xdr_decode_hyper(p, maxsize); break; case 2: nblocks = be32_to_cpup(p++); - blocksize = be32_to_cpup(p++); + blocksize = be32_to_cpup(p); *maxsize = (uint64_t)nblocks * (uint64_t)blocksize; } return 0; @@ -3925,7 +3925,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - delegation_type = be32_to_cpup(p++); + delegation_type = be32_to_cpup(p); if (delegation_type == NFS4_OPEN_DELEGATE_NONE) { res->delegation_type = 0; return 0; @@ -3936,7 +3936,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - res->do_recall = be32_to_cpup(p++); + res->do_recall = be32_to_cpup(p); switch (delegation_type) { case NFS4_OPEN_DELEGATE_READ: @@ -3973,7 +3973,7 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) if (unlikely(!p)) goto out_overflow; res->rflags = be32_to_cpup(p++); - bmlen = be32_to_cpup(p++); + bmlen = be32_to_cpup(p); if (bmlen > 10) goto xdr_error; @@ -4043,7 +4043,7 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_ if (unlikely(!p)) goto out_overflow; eof = be32_to_cpup(p++); - count = be32_to_cpup(p++); + count = be32_to_cpup(p); hdrlen = (u8 *) p - (u8 *) iov->iov_base; recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { @@ -4174,7 +4174,7 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - len = be32_to_cpup(p++); + len = be32_to_cpup(p); if (len >= rcvbuf->page_len || len <= 0) { dprintk("nfs: server returned giant symlink!\n"); return -ENAMETOOLONG; @@ -4301,7 +4301,7 @@ static int decode_setattr(struct xdr_stream *xdr) p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - bmlen = be32_to_cpup(p++); + bmlen = be32_to_cpup(p); p = xdr_inline_decode(xdr, bmlen << 2); if (likely(p)) return 0; @@ -4325,7 +4325,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) " %d\n", opnum); return -EIO; } - nfserr = be32_to_cpup(p++); + nfserr = be32_to_cpup(p); if (nfserr == NFS_OK) { p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE); if (unlikely(!p)) @@ -4339,7 +4339,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - len = be32_to_cpup(p++); + len = be32_to_cpup(p); p = xdr_inline_decode(xdr, len); if (unlikely(!p)) goto out_overflow; @@ -4348,7 +4348,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - len = be32_to_cpup(p++); + len = be32_to_cpup(p); p = xdr_inline_decode(xdr, len); if (unlikely(!p)) goto out_overflow; @@ -4410,7 +4410,7 @@ static int decode_exchange_id(struct xdr_stream *xdr, p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; - p = xdr_decode_hyper(p, &clp->cl_ex_clid); + xdr_decode_hyper(p, &clp->cl_ex_clid); p = xdr_inline_decode(xdr, 12); if (unlikely(!p)) goto out_overflow; @@ -4418,7 +4418,7 @@ static int decode_exchange_id(struct xdr_stream *xdr, clp->cl_exchange_flags = be32_to_cpup(p++); /* We ask for SP4_NONE */ - dummy = be32_to_cpup(p++); + dummy = be32_to_cpup(p); if (dummy != SP4_NONE) return -EIO; @@ -4463,7 +4463,7 @@ static int decode_chan_attrs(struct xdr_stream *xdr, attrs->max_resp_sz_cached = be32_to_cpup(p++); attrs->max_ops = be32_to_cpup(p++); attrs->max_reqs = be32_to_cpup(p++); - nr_attrs = be32_to_cpup(p++); + nr_attrs = be32_to_cpup(p); if (unlikely(nr_attrs > 1)) { printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n", __func__, nr_attrs); @@ -4504,7 +4504,7 @@ static int decode_create_session(struct xdr_stream *xdr, if (unlikely(!p)) goto out_overflow; clp->cl_seqid = be32_to_cpup(p++); - session->flags = be32_to_cpup(p++); + session->flags = be32_to_cpup(p); /* Channel attributes */ status = decode_chan_attrs(xdr, &session->fc_attrs); @@ -4576,7 +4576,7 @@ static int decode_sequence(struct xdr_stream *xdr, /* target highest slot id - currently not processed */ dummy = be32_to_cpup(p++); /* result flags - currently not processed */ - dummy = be32_to_cpup(p++); + dummy = be32_to_cpup(p); status = 0; out_err: res->sr_status = status; -- cgit v0.10.2 From 9b289c3374d2891aac6c12de58e49a16cfbcb6b1 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 14 Aug 2009 05:15:12 +0000 Subject: sky2: Avoid rewinding sky2->tx_prod Keep sky2->tx_prod consistent since int might be examined by an softirq poll or restart. Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1415a83..a52b863 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -989,11 +989,11 @@ static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr, sky2_read32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL)); } -static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2) +static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot) { - struct sky2_tx_le *le = sky2->tx_le + sky2->tx_prod; + struct sky2_tx_le *le = sky2->tx_le + *slot; - sky2->tx_prod = RING_NEXT(sky2->tx_prod, TX_RING_SIZE); + *slot = RING_NEXT(*slot, TX_RING_SIZE); le->ctrl = 0; return le; } @@ -1006,7 +1006,7 @@ static void tx_init(struct sky2_port *sky2) sky2->tx_tcpsum = 0; sky2->tx_last_mss = 0; - le = get_tx_le(sky2); + le = get_tx_le(sky2, &sky2->tx_prod); le->addr = 0; le->opcode = OP_ADDR64 | HW_OWNER; } @@ -1572,7 +1572,8 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) struct sky2_hw *hw = sky2->hw; struct sky2_tx_le *le = NULL; struct tx_ring_info *re; - unsigned i, len, first_slot; + unsigned i, len; + u16 slot; dma_addr_t mapping; u16 mss; u8 ctrl; @@ -1586,14 +1587,14 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) if (pci_dma_mapping_error(hw->pdev, mapping)) goto mapping_error; - first_slot = sky2->tx_prod; + slot = sky2->tx_prod; if (unlikely(netif_msg_tx_queued(sky2))) printk(KERN_DEBUG "%s: tx queued, slot %u, len %d\n", - dev->name, first_slot, skb->len); + dev->name, slot, skb->len); /* Send high bits if needed */ if (sizeof(dma_addr_t) > sizeof(u32)) { - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(upper_32_bits(mapping)); le->opcode = OP_ADDR64 | HW_OWNER; } @@ -1606,7 +1607,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb); if (mss != sky2->tx_last_mss) { - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(mss); if (hw->flags & SKY2_HW_NEW_LE) @@ -1622,7 +1623,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */ if (sky2->vlgrp && vlan_tx_tag_present(skb)) { if (!le) { - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = 0; le->opcode = OP_VLAN|HW_OWNER; } else @@ -1651,7 +1652,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) if (tcpsum != sky2->tx_tcpsum) { sky2->tx_tcpsum = tcpsum; - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(tcpsum); le->length = 0; /* initial checksum value */ le->ctrl = 1; /* one packet */ @@ -1660,7 +1661,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) } } - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32((u32) mapping); le->length = cpu_to_le16(len); le->ctrl = ctrl; @@ -1681,13 +1682,13 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) goto mapping_unwind; if (sizeof(dma_addr_t) > sizeof(u32)) { - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(upper_32_bits(mapping)); le->ctrl = 0; le->opcode = OP_ADDR64 | HW_OWNER; } - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32((u32) mapping); le->length = cpu_to_le16(frag->size); le->ctrl = ctrl; @@ -1701,6 +1702,8 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) le->ctrl |= EOP; + sky2->tx_prod = slot; + if (tx_avail(sky2) <= MAX_SKB_TX_LE) netif_stop_queue(dev); @@ -1709,7 +1712,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; mapping_unwind: - for (i = first_slot; i != sky2->tx_prod; i = RING_NEXT(i, TX_RING_SIZE)) { + for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, TX_RING_SIZE)) { le = sky2->tx_le + i; re = sky2->tx_ring + i; @@ -1729,7 +1732,6 @@ mapping_unwind: } } - sky2->tx_prod = first_slot; mapping_error: if (net_ratelimit()) dev_warn(&hw->pdev->dev, "%s: tx mapping error\n", dev->name); -- cgit v0.10.2 From a510996bea68eec2feb7818e9a440bd840613a25 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 14 Aug 2009 05:15:13 +0000 Subject: sky2: Move tx reset functionality to sky2_tx_reset() This is pure refactoring. Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a52b863..768ed47 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1811,6 +1811,31 @@ static void sky2_tx_clean(struct net_device *dev) netif_tx_unlock_bh(dev); } +static void sky2_tx_reset(struct sky2_port* sky2) +{ + unsigned port = sky2->port; + struct sky2_hw *hw = sky2->hw; + + /* Disable Force Sync bit and Enable Alloc bit */ + sky2_write8(hw, SK_REG(port, TXA_CTRL), + TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); + + /* Stop Interval Timer and Limit Counter of Tx Arbiter */ + sky2_write32(hw, SK_REG(port, TXA_ITI_INI), 0L); + sky2_write32(hw, SK_REG(port, TXA_LIM_INI), 0L); + + /* Reset the PCI FIFO of the async Tx queue */ + sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), + BMU_RST_SET | BMU_FIFO_RST); + + /* Reset the Tx prefetch units */ + sky2_write32(hw, Y2_QADDR(txqaddr[port], PREF_UNIT_CTRL), + PREF_UNIT_RST_SET); + + sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET); + sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); +} + /* Network shutdown */ static int sky2_down(struct net_device *dev) { @@ -1852,26 +1877,9 @@ static int sky2_down(struct net_device *dev) && port == 0 && hw->dev[1] && netif_running(hw->dev[1]))) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); - /* Disable Force Sync bit and Enable Alloc bit */ - sky2_write8(hw, SK_REG(port, TXA_CTRL), - TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); - - /* Stop Interval Timer and Limit Counter of Tx Arbiter */ - sky2_write32(hw, SK_REG(port, TXA_ITI_INI), 0L); - sky2_write32(hw, SK_REG(port, TXA_LIM_INI), 0L); - - /* Reset the PCI FIFO of the async Tx queue */ - sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), - BMU_RST_SET | BMU_FIFO_RST); - - /* Reset the Tx prefetch units */ - sky2_write32(hw, Y2_QADDR(txqaddr[port], PREF_UNIT_CTRL), - PREF_UNIT_RST_SET); - - sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET); + sky2_tx_reset(sky2); sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); - sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); /* Force any delayed status interrrupt and NAPI */ sky2_write32(hw, STAT_LEV_TIMER_CNT, 0); -- cgit v0.10.2 From 264bb4fab1a0952b4eef4df5b9e90bc050a2d1e6 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 14 Aug 2009 05:15:14 +0000 Subject: sky2: Reset tx train after interrupts disabled. Reseting the tx chain too soon results in invalid tx queue positions being delivered in the status queue. This also makes sure there's no overlap between the cleanup done by sky2_tx_clean() and sky2_tx_done(). Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 768ed47..b75b48e 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1811,11 +1811,8 @@ static void sky2_tx_clean(struct net_device *dev) netif_tx_unlock_bh(dev); } -static void sky2_tx_reset(struct sky2_port* sky2) +static void sky2_tx_reset(struct sky2_hw *hw, unsigned port) { - unsigned port = sky2->port; - struct sky2_hw *hw = sky2->hw; - /* Disable Force Sync bit and Enable Alloc bit */ sky2_write8(hw, SK_REG(port, TXA_CTRL), TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); @@ -1877,8 +1874,6 @@ static int sky2_down(struct net_device *dev) && port == 0 && hw->dev[1] && netif_running(hw->dev[1]))) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); - sky2_tx_reset(sky2); - sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); /* Force any delayed status interrrupt and NAPI */ @@ -1903,6 +1898,8 @@ static int sky2_down(struct net_device *dev) /* turn off LED's */ sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); + sky2_tx_reset(hw, port); + sky2_tx_clean(dev); sky2_rx_clean(sky2); -- cgit v0.10.2 From 0da6d7b331f391d3c0ce52fb5289f7edeb94e280 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 05:15:15 +0000 Subject: sky2: hold spinlock around phy_power_down Avoid any possible problems with accessing PHY registers on shutdown. This is a purely theoretical issue and is not related to any of the outstanding bug reports. Since receiver and transmitter are already shutdown and phy interrupts for this device are already disabled, there should already be enough protection. Suggested by Mike McCormack. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index b75b48e..1d3ee03 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1893,7 +1893,9 @@ static int sky2_down(struct net_device *dev) synchronize_irq(hw->pdev->irq); napi_synchronize(&hw->napi); + spin_lock_bh(&sky2->phy_lock); sky2_phy_power_down(hw, port); + spin_unlock_bh(&sky2->phy_lock); /* turn off LED's */ sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); -- cgit v0.10.2 From 19720737187aaee006afb20e63be5e9eddc505a8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 05:15:16 +0000 Subject: sky2: hold RTNL when doing suspend/shutdown operations The suspend and shutdown code plays with shared state. Use consistent locking, for extra protection. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1d3ee03..3ae4b42 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -4643,6 +4643,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) del_timer_sync(&hw->watchdog_timer); cancel_work_sync(&hw->restart_work); + rtnl_lock(); for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; struct sky2_port *sky2 = netdev_priv(dev); @@ -4660,6 +4661,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) sky2_write32(hw, B0_IMSK, 0); napi_disable(&hw->napi); sky2_power_aux(hw); + rtnl_unlock(); pci_save_state(pdev); pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); @@ -4729,6 +4731,7 @@ static void sky2_shutdown(struct pci_dev *pdev) if (!hw) return; + rtnl_lock(); del_timer_sync(&hw->watchdog_timer); for (i = 0; i < hw->ports; i++) { @@ -4743,6 +4746,7 @@ static void sky2_shutdown(struct pci_dev *pdev) if (wol) sky2_power_aux(hw); + rtnl_unlock(); pci_enable_wake(pdev, PCI_D3hot, wol); pci_enable_wake(pdev, PCI_D3cold, wol); -- cgit v0.10.2 From af18d8b89930aecc742982634adaf97dfb43ed3b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 15:31:25 -0700 Subject: sky2: cleanup restart operations This unifies the places that bounce the device (suspend/resume and restart). And makes the operations have the same semantics as normal dev_open/dev_stop. This also avoids setting the multicast addresses twice when device is brought up. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3ae4b42..301f8a6 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1500,13 +1500,12 @@ static int sky2_up(struct net_device *dev) sky2_write32(hw, B0_IMSK, imask); sky2_read32(hw, B0_IMSK); - sky2_set_multicast(dev); - /* wake queue incase we are restarting */ netif_wake_queue(dev); if (netif_msg_ifup(sky2)) printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); + return 0; err_out: @@ -3087,18 +3086,46 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); } +/* Take device down (offline). + * Equivalent to doing dev_stop() but this does not + * inform upper layers of the transistion. + */ +static void sky2_detach(struct net_device *dev) +{ + if (netif_running(dev)) { + netif_device_detach(dev); /* stop txq */ + sky2_down(dev); + } +} + +/* Bring device back after doing sky2_detach */ +static int sky2_reattach(struct net_device *dev) +{ + int err = 0; + + if (netif_running(dev)) { + err = sky2_up(dev); + if (err) { + printk(KERN_INFO PFX "%s: could not restart %d\n", + dev->name, err); + dev_close(dev); + } else { + netif_device_attach(dev); + sky2_set_multicast(dev); + } + } + + return err; +} + static void sky2_restart(struct work_struct *work) { struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work); - struct net_device *dev; - int i, err; + int i; rtnl_lock(); - for (i = 0; i < hw->ports; i++) { - dev = hw->dev[i]; - if (netif_running(dev)) - sky2_down(dev); - } + for (i = 0; i < hw->ports; i++) + sky2_detach(hw->dev[i]); napi_disable(&hw->napi); sky2_write32(hw, B0_IMSK, 0); @@ -3106,17 +3133,8 @@ static void sky2_restart(struct work_struct *work) sky2_write32(hw, B0_IMSK, Y2_IS_BASE); napi_enable(&hw->napi); - for (i = 0; i < hw->ports; i++) { - dev = hw->dev[i]; - if (netif_running(dev)) { - err = sky2_up(dev); - if (err) { - printk(KERN_INFO PFX "%s: could not restart %d\n", - dev->name, err); - dev_close(dev); - } - } - } + for (i = 0; i < hw->ports; i++) + sky2_reattach(hw->dev[i]); rtnl_unlock(); } @@ -3705,7 +3723,6 @@ static int sky2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { struct sky2_port *sky2 = netdev_priv(dev); - int err = 0; if (ering->rx_pending > RX_MAX_PENDING || ering->rx_pending < 8 || @@ -3713,19 +3730,12 @@ static int sky2_set_ringparam(struct net_device *dev, ering->tx_pending > TX_RING_SIZE - 1) return -EINVAL; - if (netif_running(dev)) - sky2_down(dev); + sky2_detach(dev); sky2->rx_pending = ering->rx_pending; sky2->tx_pending = ering->tx_pending; - if (netif_running(dev)) { - err = sky2_up(dev); - if (err) - dev_close(dev); - } - - return err; + return sky2_reattach(dev); } static int sky2_get_regs_len(struct net_device *dev) @@ -4648,9 +4658,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) struct net_device *dev = hw->dev[i]; struct sky2_port *sky2 = netdev_priv(dev); - netif_device_detach(dev); - if (netif_running(dev)) - sky2_down(dev); + sky2_detach(dev); if (sky2->wol) sky2_wol_init(sky2); @@ -4698,25 +4706,18 @@ static int sky2_resume(struct pci_dev *pdev) sky2_write32(hw, B0_IMSK, Y2_IS_BASE); napi_enable(&hw->napi); + rtnl_lock(); for (i = 0; i < hw->ports; i++) { - struct net_device *dev = hw->dev[i]; - - netif_device_attach(dev); - if (netif_running(dev)) { - err = sky2_up(dev); - if (err) { - printk(KERN_ERR PFX "%s: could not up: %d\n", - dev->name, err); - rtnl_lock(); - dev_close(dev); - rtnl_unlock(); - goto out; - } - } + err = sky2_reattach(hw->dev[i]); + if (err) + goto out; } + rtnl_unlock(); return 0; out: + rtnl_unlock(); + dev_err(&pdev->dev, "resume failed (%d)\n", err); pci_disable_device(pdev); return err; -- cgit v0.10.2 From 481cea4a4d72aabe76dbb86b1a64f4e8931eca25 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 15:33:19 -0700 Subject: sky2: lock less transmit completion Transmit completion can safely run lockless against transmit start. In the normal case, completion is done from NAPI and only looks at elements that are at the tail of the ring. When doing shutdown or reset, the transmiter should be completely block by NAPI disable and blocking of transmit queue. Based on earlier work by Mike McCormack. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 301f8a6..4944fcc 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1741,8 +1741,12 @@ mapping_error: /* * Free ring elements from starting at tx_cons until "done" * - * NB: the hardware will tell us about partial completion of multi-part + * NB: + * 1. The hardware will tell us about partial completion of multi-part * buffers so make sure not to free skb to early. + * 2. This may run in parallel start_xmit because the it only + * looks at the tail of the queue of FIFO (tx_cons), not + * the head (tx_prod) */ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) { @@ -1800,16 +1804,6 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) netif_wake_queue(dev); } -/* Cleanup all untransmitted buffers, assume transmitter not running */ -static void sky2_tx_clean(struct net_device *dev) -{ - struct sky2_port *sky2 = netdev_priv(dev); - - netif_tx_lock_bh(dev); - sky2_tx_complete(sky2, sky2->tx_prod); - netif_tx_unlock_bh(dev); -} - static void sky2_tx_reset(struct sky2_hw *hw, unsigned port) { /* Disable Force Sync bit and Enable Alloc bit */ @@ -1901,7 +1895,9 @@ static int sky2_down(struct net_device *dev) sky2_tx_reset(hw, port); - sky2_tx_clean(dev); + /* Free any pending frames stuck in HW queue */ + sky2_tx_complete(sky2, sky2->tx_prod); + sky2_rx_clean(sky2); pci_free_consistent(hw->pdev, RX_LE_BYTES, @@ -2378,11 +2374,8 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) { struct sky2_port *sky2 = netdev_priv(dev); - if (likely(netif_running(dev) && !sky2->restarting)) { - netif_tx_lock(dev); + if (likely(netif_running(dev) && !sky2->restarting)) sky2_tx_complete(sky2, last); - netif_tx_unlock(dev); - } } static inline void sky2_skb_rx(const struct sky2_port *sky2, -- cgit v0.10.2 From 0ea065e52eb6a0f029b5fa5ed2f142be1b66a153 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 15:36:41 -0700 Subject: sky2: fix pause negotiation The sky2 driver combines auto speed negotiation with automatic negotiation of pause parameters; but the ethtool interface expects them to be split. This patch allows autonegotiation to be used for speed, but manually disable flow control. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4944fcc..6788a91 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -321,7 +321,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) struct sky2_port *sky2 = netdev_priv(hw->dev[port]); u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg; - if (sky2->autoneg == AUTONEG_ENABLE && + if ( (sky2->flags & SKY2_FLAG_AUTO_SPEED) && !(hw->flags & SKY2_HW_NEWER_PHY)) { u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); @@ -363,7 +363,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO); /* downshift on PHY 88E1112 and 88E1149 is changed */ - if (sky2->autoneg == AUTONEG_ENABLE + if ( (sky2->flags & SKY2_FLAG_AUTO_SPEED) && (hw->flags & SKY2_HW_NEWER_PHY)) { /* set downshift counter to 3x and enable downshift */ ctrl &= ~PHY_M_PC_DSC_MSK; @@ -408,7 +408,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) adv = PHY_AN_CSMA; reg = 0; - if (sky2->autoneg == AUTONEG_ENABLE) { + if (sky2->flags & SKY2_FLAG_AUTO_SPEED) { if (sky2_is_copper(hw)) { if (sky2->advertising & ADVERTISED_1000baseT_Full) ct1000 |= PHY_M_1000C_AFD; @@ -423,14 +423,11 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) if (sky2->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; - adv |= copper_fc_adv[sky2->flow_mode]; } else { /* special defines for FIBER (88E1040S only) */ if (sky2->advertising & ADVERTISED_1000baseT_Full) adv |= PHY_M_AN_1000X_AFD; if (sky2->advertising & ADVERTISED_1000baseT_Half) adv |= PHY_M_AN_1000X_AHD; - - adv |= fiber_fc_adv[sky2->flow_mode]; } /* Restart Auto-negotiation */ @@ -439,8 +436,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* forced speed/duplex settings */ ct1000 = PHY_M_1000C_MSE; - /* Disable auto update for duplex flow control and speed */ - reg |= GM_GPCR_AU_ALL_DIS; + /* Disable auto update for duplex flow control and duplex */ + reg |= GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_SPD_DIS; switch (sky2->speed) { case SPEED_1000: @@ -458,8 +455,15 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ctrl |= PHY_CT_DUP_MD; } else if (sky2->speed < SPEED_1000) sky2->flow_mode = FC_NONE; + } - + if (sky2->flags & SKY2_FLAG_AUTO_PAUSE) { + if (sky2_is_copper(hw)) + adv |= copper_fc_adv[sky2->flow_mode]; + else + adv |= fiber_fc_adv[sky2->flow_mode]; + } else { + reg |= GM_GPCR_AU_FCT_DIS; reg |= gm_fc_disable[sky2->flow_mode]; /* Forward pause packets to GMAC? */ @@ -594,7 +598,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* no effect on Yukon-XL */ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); - if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { + if ( !(sky2->flags & SKY2_FLAG_AUTO_SPEED) + || sky2->speed == SPEED_100) { /* turn on 100 Mbps LED (LED_LINK100) */ ledover |= PHY_M_LED_MO_100(MO_LED_ON); } @@ -605,7 +610,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) } /* Enable phy interrupt on auto-negotiation complete (or link up) */ - if (sky2->autoneg == AUTONEG_ENABLE) + if (sky2->flags & SKY2_FLAG_AUTO_SPEED) gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); else gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); @@ -661,7 +666,9 @@ static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port) /* setup General Purpose Control Register */ gma_write16(hw, port, GM_GP_CTRL, - GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS); + GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | + GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS | + GM_GPCR_AU_SPD_DIS); if (hw->chip_id != CHIP_ID_YUKON_EC) { if (hw->chip_id == CHIP_ID_YUKON_EC_U) { @@ -1117,7 +1124,8 @@ static void rx_set_checksum(struct sky2_port *sky2) sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), - sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); + (sky2->flags & SKY2_FLAG_RX_CHECKSUM) + ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } /* @@ -2087,7 +2095,7 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port) printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n", sky2->netdev->name, istatus, phystat); - if (sky2->autoneg == AUTONEG_ENABLE && (istatus & PHY_M_IS_AN_COMPL)) { + if (istatus & PHY_M_IS_AN_COMPL) { if (sky2_autoneg_done(sky2, phystat) == 0) sky2_link_up(sky2); goto out; @@ -2453,7 +2461,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) /* This chip reports checksum status differently */ if (hw->flags & SKY2_HW_NEW_LE) { - if (sky2->rx_csum && + if ((sky2->flags & SKY2_FLAG_RX_CHECKSUM) && (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) && (le->css & CSS_TCPUDPCSOK)) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2480,7 +2488,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) /* fall through */ #endif case OP_RXCHKS: - if (!sky2->rx_csum) + if (!(sky2->flags & SKY2_FLAG_RX_CHECKSUM)) break; /* If this happens then driver assuming wrong format */ @@ -2505,7 +2513,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) printk(KERN_NOTICE PFX "%s: hardware receive " "checksum problem (status = %#x)\n", dev->name, status); - sky2->rx_csum = 0; + sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; + sky2_write32(sky2->hw, Q_ADDR(rxqaddr[port], Q_CSR), BMU_DIS_RX_CHKSUM); @@ -3206,7 +3215,8 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } ecmd->advertising = sky2->advertising; - ecmd->autoneg = sky2->autoneg; + ecmd->autoneg = (sky2->flags & SKY2_FLAG_AUTO_SPEED) + ? AUTONEG_ENABLE : AUTONEG_DISABLE; ecmd->duplex = sky2->duplex; return 0; } @@ -3218,6 +3228,7 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) u32 supported = sky2_supported_modes(hw); if (ecmd->autoneg == AUTONEG_ENABLE) { + sky2->flags |= SKY2_FLAG_AUTO_SPEED; ecmd->advertising = supported; sky2->duplex = -1; sky2->speed = -1; @@ -3259,9 +3270,9 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) sky2->speed = ecmd->speed; sky2->duplex = ecmd->duplex; + sky2->flags &= ~SKY2_FLAG_AUTO_SPEED; } - sky2->autoneg = ecmd->autoneg; sky2->advertising = ecmd->advertising; if (netif_running(dev)) { @@ -3331,14 +3342,17 @@ static u32 sky2_get_rx_csum(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); - return sky2->rx_csum; + return !!(sky2->flags & SKY2_FLAG_RX_CHECKSUM); } static int sky2_set_rx_csum(struct net_device *dev, u32 data) { struct sky2_port *sky2 = netdev_priv(dev); - sky2->rx_csum = data; + if (data) + sky2->flags |= SKY2_FLAG_RX_CHECKSUM; + else + sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); @@ -3356,7 +3370,7 @@ static int sky2_nway_reset(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); - if (!netif_running(dev) || sky2->autoneg != AUTONEG_ENABLE) + if (!netif_running(dev) || !(sky2->flags & SKY2_FLAG_AUTO_SPEED)) return -EINVAL; sky2_phy_reinit(sky2); @@ -3596,7 +3610,8 @@ static void sky2_get_pauseparam(struct net_device *dev, ecmd->tx_pause = ecmd->rx_pause = 1; } - ecmd->autoneg = sky2->autoneg; + ecmd->autoneg = (sky2->flags & SKY2_FLAG_AUTO_PAUSE) + ? AUTONEG_ENABLE : AUTONEG_DISABLE; } static int sky2_set_pauseparam(struct net_device *dev, @@ -3604,7 +3619,11 @@ static int sky2_set_pauseparam(struct net_device *dev, { struct sky2_port *sky2 = netdev_priv(dev); - sky2->autoneg = ecmd->autoneg; + if (ecmd->autoneg == AUTONEG_ENABLE) + sky2->flags |= SKY2_FLAG_AUTO_PAUSE; + else + sky2->flags &= ~SKY2_FLAG_AUTO_PAUSE; + sky2->flow_mode = sky2_flow(ecmd->rx_pause, ecmd->tx_pause); if (netif_running(dev)) @@ -4294,13 +4313,15 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->msg_enable = netif_msg_init(debug, default_msg); /* Auto speed and flow control */ - sky2->autoneg = AUTONEG_ENABLE; + sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE; + if (hw->chip_id != CHIP_ID_YUKON_XL) + sky2->flags |= SKY2_FLAG_RX_CHECKSUM; + sky2->flow_mode = FC_BOTH; sky2->duplex = -1; sky2->speed = -1; sky2->advertising = sky2_supported_modes(hw); - sky2->rx_csum = (hw->chip_id != CHIP_ID_YUKON_XL); sky2->wol = wol; spin_lock_init(&sky2->phy_lock); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 4486b06..c9548d6 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1583,7 +1583,6 @@ enum { }; #define GM_GPCR_SPEED_1000 (GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100) -#define GM_GPCR_AU_ALL_DIS (GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS|GM_GPCR_AU_SPD_DIS) /* GM_TX_CTRL 16 bit r/w Transmit Control Register */ enum { @@ -2042,15 +2041,18 @@ struct sky2_port { u8 fifo_lev; } check; - dma_addr_t rx_le_map; dma_addr_t tx_le_map; + u16 advertising; /* ADVERTISED_ bits */ - u16 speed; /* SPEED_1000, SPEED_100, ... */ - u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ - u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ - u8 rx_csum; - u8 wol; + u16 speed; /* SPEED_1000, SPEED_100, ... */ + u8 wol; /* WAKE_ bits */ + u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ + u16 flags; +#define SKY2_FLAG_RX_CHECKSUM 0x0001 +#define SKY2_FLAG_AUTO_SPEED 0x0002 +#define SKY2_FLAG_AUTO_PAUSE 0x0004 + u8 restarting; enum flow_control flow_mode; enum flow_control flow_status; -- cgit v0.10.2 From deeb16dc24b68cbdca72dc717ae82178a6644801 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 05:15:20 +0000 Subject: sky2: version 1.24 Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 6788a91..bac1870 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -50,7 +50,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.23" +#define DRV_VERSION "1.24" #define PFX DRV_NAME " " /* -- cgit v0.10.2 From b85daa5324a3c9e560a4351c17d18f49c647eb5c Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Fri, 14 Aug 2009 12:41:07 +0000 Subject: vlan: adds fcoe offload related net_device_ops and updates fcoe_ddp_xid field Adds fcoe offload related net_device_ops functions vlan_dev_fcoe_ddp_setup and vlan_dev_fcoe_ddp_done, their implementation simply calls real eth device net_device_ops for FCoE DDP setup and done operations. Updates VLAN netdev field value for fcoe_ddp_xid from real eth device netdev. Above changes are required for fcoe DDP offload working on a VLAN interface. Signed-off-by: Vasu Dev Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index a1f1630..e814794 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -391,6 +391,9 @@ static void vlan_transfer_features(struct net_device *dev, vlandev->features &= ~dev->vlan_features; vlandev->features |= dev->features & dev->vlan_features; vlandev->gso_max_size = dev->gso_max_size; +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) + vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid; +#endif if (old_features != vlandev->features) netdev_features_change(vlandev); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 96bad8f..6e695ac 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -561,6 +561,33 @@ static int vlan_dev_neigh_setup(struct net_device *dev, struct neigh_parms *pa) return err; } +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) +static int vlan_dev_fcoe_ddp_setup(struct net_device *dev, u16 xid, + struct scatterlist *sgl, unsigned int sgc) +{ + struct net_device *real_dev = vlan_dev_info(dev)->real_dev; + const struct net_device_ops *ops = real_dev->netdev_ops; + int rc = 0; + + if (ops->ndo_fcoe_ddp_setup) + rc = ops->ndo_fcoe_ddp_setup(real_dev, xid, sgl, sgc); + + return rc; +} + +static int vlan_dev_fcoe_ddp_done(struct net_device *dev, u16 xid) +{ + struct net_device *real_dev = vlan_dev_info(dev)->real_dev; + const struct net_device_ops *ops = real_dev->netdev_ops; + int len = 0; + + if (ops->ndo_fcoe_ddp_done) + len = ops->ndo_fcoe_ddp_done(real_dev, xid); + + return len; +} +#endif + static void vlan_dev_change_rx_flags(struct net_device *dev, int change) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; @@ -635,6 +662,10 @@ static int vlan_dev_init(struct net_device *dev) if (is_zero_ether_addr(dev->broadcast)) memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len); +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) + dev->fcoe_ddp_xid = real_dev->fcoe_ddp_xid; +#endif + if (real_dev->features & NETIF_F_HW_VLAN_TX) { dev->header_ops = real_dev->header_ops; dev->hard_header_len = real_dev->hard_header_len; @@ -715,6 +746,10 @@ static const struct net_device_ops vlan_netdev_ops = { .ndo_change_rx_flags = vlan_dev_change_rx_flags, .ndo_do_ioctl = vlan_dev_ioctl, .ndo_neigh_setup = vlan_dev_neigh_setup, +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) + .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, + .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, +#endif }; static const struct net_device_ops vlan_netdev_accel_ops = { @@ -731,6 +766,10 @@ static const struct net_device_ops vlan_netdev_accel_ops = { .ndo_change_rx_flags = vlan_dev_change_rx_flags, .ndo_do_ioctl = vlan_dev_ioctl, .ndo_neigh_setup = vlan_dev_neigh_setup, +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) + .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, + .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, +#endif }; void vlan_setup(struct net_device *dev) -- cgit v0.10.2 From 36a82236314b5ebd6e3e1eb8bb7b850c83e53c3a Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Fri, 14 Aug 2009 12:41:28 +0000 Subject: ixgbe: updates vlan feature flags to enable FCoE offloads on vlan interface Updates netdev->vlan_features for NETIF_F_FCOE_CRC and NETIF_F_FSO, so that FCoE CRC and GSO offloads will get used for FCoE over ixgbe based vlan interface. Signed-off-by: Vasu Dev Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 1c72657..116f12c 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -148,7 +148,10 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) IXGBE_FCRETA_SIZE; netdev->features |= NETIF_F_FCOE_CRC; netdev->features |= NETIF_F_FSO; + netdev->vlan_features |= NETIF_F_FCOE_CRC; + netdev->vlan_features |= NETIF_F_FSO; netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; + netdev_features_change(netdev); } #endif /* IXGBE_FCOE */ ixgbe_init_interrupt_scheme(adapter); @@ -177,7 +180,10 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) adapter->ring_feature[RING_F_FCOE].indices = 0; netdev->features &= ~NETIF_F_FCOE_CRC; netdev->features &= ~NETIF_F_FSO; + netdev->vlan_features &= ~NETIF_F_FCOE_CRC; + netdev->vlan_features &= ~NETIF_F_FSO; netdev->fcoe_ddp_xid = 0; + netdev_features_change(netdev); } #endif /* IXGBE_FCOE */ ixgbe_init_interrupt_scheme(adapter); -- cgit v0.10.2 From bb2af4f54ffa8245d5ce278cae9c66198bc14d8b Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Fri, 14 Aug 2009 12:41:57 +0000 Subject: net: Add NETIF_F_FCOE_MTU to indicate support for a different MTU for FCoE Add NETIF_F_FCOE_MTU to indicate that the NIC can support a secondary MTU for converged traffic of LAN and Fiber Channel over Ethernet (FCoE). The MTU for FCoE is 2158 = 14 (FCoE header) + 24 (FC header) + 2112 (FC max payload) + 4 (FC CRC) + 4 (FCoE trailer). Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9f25ab2..9192cdf 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -701,6 +701,7 @@ struct net_device /* the GSO_MASK reserves bits 16 through 23 */ #define NETIF_F_FCOE_CRC (1 << 24) /* FCoE CRC32 */ #define NETIF_F_SCTP_CSUM (1 << 25) /* SCTP checksum offload */ +#define NETIF_F_FCOE_MTU (1 << 26) /* Supports max FCoE MTU, 2158 bytes*/ /* Segmentation offload features */ #define NETIF_F_GSO_SHIFT 16 -- cgit v0.10.2 From f34c5c828439cedbc222030d7e45af69f947384d Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Fri, 14 Aug 2009 12:42:17 +0000 Subject: ixgbe: Add support for NETIF_F_FCOE_MTU to 82599 devices Enable netdev feature flag bit NETIF_F_FCOE_MTU for 82599 devices and enable jumbo frame correspondingly when NETIF_F_FCOE_MTU is set. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 116f12c..34bca45 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -148,8 +148,10 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) IXGBE_FCRETA_SIZE; netdev->features |= NETIF_F_FCOE_CRC; netdev->features |= NETIF_F_FSO; + netdev->features |= NETIF_F_FCOE_MTU; netdev->vlan_features |= NETIF_F_FCOE_CRC; netdev->vlan_features |= NETIF_F_FSO; + netdev->vlan_features |= NETIF_F_FCOE_MTU; netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; netdev_features_change(netdev); } @@ -180,8 +182,10 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) adapter->ring_feature[RING_F_FCOE].indices = 0; netdev->features &= ~NETIF_F_FCOE_CRC; netdev->features &= ~NETIF_F_FSO; + netdev->features &= ~NETIF_F_FCOE_MTU; netdev->vlan_features &= ~NETIF_F_FCOE_CRC; netdev->vlan_features &= ~NETIF_F_FSO; + netdev->vlan_features &= ~NETIF_F_FCOE_MTU; netdev->fcoe_ddp_xid = 0; netdev_features_change(netdev); } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 8a8518d..d69d277 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2026,7 +2026,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) else hlreg0 |= IXGBE_HLREG0_JUMBOEN; #ifdef IXGBE_FCOE - if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + if (netdev->features & NETIF_F_FCOE_MTU) hlreg0 |= IXGBE_HLREG0_JUMBOEN; #endif IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); @@ -2057,7 +2057,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) rx_ring->flags |= IXGBE_RING_RX_PS_ENABLED; #ifdef IXGBE_FCOE - if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + if (netdev->features & NETIF_F_FCOE_MTU) { struct ixgbe_ring_feature *f; f = &adapter->ring_feature[RING_F_FCOE]; if ((i >= f->mask) && (i < f->mask + f->indices)) { @@ -2609,7 +2609,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) #ifdef IXGBE_FCOE /* adjust max frame to be able to do baby jumbo for FCoE */ - if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && + if ((netdev->features & NETIF_F_FCOE_MTU) && (max_frame < IXGBE_FCOE_JUMBO_FRAME_SIZE)) max_frame = IXGBE_FCOE_JUMBO_FRAME_SIZE; -- cgit v0.10.2 From 49d4b8ba97034469b941d00d5ca1e3b897394e35 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 13:33:17 +0000 Subject: sky2: remove restarting workaround flag The whole restarting flag was introduced by Mike McCormack and was a temporary duct tape patch around issues with transmits inflight during restart. The problems it was covering are now fixed and the code should have been reverted. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index bac1870..8a763f8 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1496,8 +1496,6 @@ static int sky2_up(struct net_device *dev) sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL); #endif - sky2->restarting = 0; - err = sky2_rx_start(sky2); if (err) goto err_out; @@ -1508,9 +1506,6 @@ static int sky2_up(struct net_device *dev) sky2_write32(hw, B0_IMSK, imask); sky2_read32(hw, B0_IMSK); - /* wake queue incase we are restarting */ - netif_wake_queue(dev); - if (netif_msg_ifup(sky2)) printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); @@ -1545,8 +1540,6 @@ static inline int tx_dist(unsigned tail, unsigned head) /* Number of list elements available for next tx */ static inline int tx_avail(const struct sky2_port *sky2) { - if (unlikely(sky2->restarting)) - return 0; return sky2->tx_pending - tx_dist(sky2->tx_cons, sky2->tx_prod); } @@ -1850,10 +1843,6 @@ static int sky2_down(struct net_device *dev) if (netif_msg_ifdown(sky2)) printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); - /* explicitly shut off tx incase we're restarting */ - sky2->restarting = 1; - netif_tx_disable(dev); - /* Force flow control off */ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); @@ -2382,7 +2371,7 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) { struct sky2_port *sky2 = netdev_priv(dev); - if (likely(netif_running(dev) && !sky2->restarting)) + if (netif_running(dev)) sky2_tx_complete(sky2, last); } @@ -4327,7 +4316,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, spin_lock_init(&sky2->phy_lock); sky2->tx_pending = TX_DEF_PENDING; sky2->rx_pending = RX_DEF_PENDING; - sky2->restarting = 0; hw->dev[port] = dev; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index c9548d6..65b94c3 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2053,7 +2053,6 @@ struct sky2_port { #define SKY2_FLAG_AUTO_SPEED 0x0002 #define SKY2_FLAG_AUTO_PAUSE 0x0004 - u8 restarting; enum flow_control flow_mode; enum flow_control flow_status; -- cgit v0.10.2 From 1758c0947605211ef953cc91d6bbdf847a21b822 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Thu, 13 Aug 2009 22:54:25 +0000 Subject: can: Use WARN_ONCE() instead of BUG_ON() for sanity check in receive path To ensure a proper handling of CAN frames transported in skbuffs some checks need to be performed at receive time. As stated by Michael Olbrich and Luotao Fu BUG_ON() might be to restrictive. This is right as we can just drop the non conform skbuff and the Kernel can continue working. This patch replaces the BUG_ON() with a WARN_ONCE() so that the system remains healthy but we made the problem visible (once). Signed-off-by: Oliver Hartkopp Signed-off-by: Urs Thuermann CC: Michael Olbrich CC: Luotao Fu Signed-off-by: David S. Miller diff --git a/net/can/af_can.c b/net/can/af_can.c index e733725..f9c027b 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -651,12 +651,16 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, struct can_frame *cf = (struct can_frame *)skb->data; int matches; - if (dev->type != ARPHRD_CAN || !net_eq(dev_net(dev), &init_net)) { - kfree_skb(skb); - return 0; - } + if (!net_eq(dev_net(dev), &init_net)) + goto drop; - BUG_ON(skb->len != sizeof(struct can_frame) || cf->can_dlc > 8); + if (WARN_ONCE(dev->type != ARPHRD_CAN || + skb->len != sizeof(struct can_frame) || + cf->can_dlc > 8, + "PF_CAN: dropped non conform skbuf: " + "dev type %d, len %d, can_dlc %d\n", + dev->type, skb->len, cf->can_dlc)) + goto drop; /* update statistics */ can_stats.rx_frames++; @@ -683,6 +687,10 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, } return 0; + +drop: + kfree_skb(skb); + return 0; } /* -- cgit v0.10.2 From 7570ef18349d4f3a9336397952b05ec3e95ec4b7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 15 Aug 2009 11:57:53 +0200 Subject: ALSA: hda - Add missing num_adc_nids definition for IDT92HD8xxx The previous fix removed the definition of num_adc_nids wrongly, and this resulted in the missing input-source control. Now readded again. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7d33e0a..eb9ca6f 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5297,6 +5297,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->mux_nids = stac92hd83xxx_mux_nids; spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids); spec->adc_nids = stac92hd83xxx_adc_nids; + spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); spec->pwr_nids = stac92hd83xxx_pwr_nids; spec->pwr_mapping = stac92hd83xxx_pwr_mapping; spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); -- cgit v0.10.2 From 18408ddc01136f505ae357c03f0d8e50b10e0db6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 13 Aug 2009 11:47:55 +0200 Subject: perf tools: Add some comments to the event definitions Just to make it clear that these are _not_ generic event structures but do rely on the counter configuration. Signed-off-by: Peter Zijlstra Cc: Corey J Ashford Cc: Paul Mackerras Cc: stephane eranian LKML-Reference: <20090813103655.334194326@chello.nl> Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index d26dc88..fa7c50b 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -4,6 +4,9 @@ #include "util.h" #include +/* + * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * + */ struct ip_event { struct perf_event_header header; u64 ip; @@ -38,6 +41,9 @@ struct lost_event { u64 lost; }; +/* + * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID + */ struct read_event { struct perf_event_header header; u32 pid,tid; -- cgit v0.10.2 From a2d512a978ceda557a456d39d88cfc1eb60194e9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 15 Aug 2009 11:36:20 +0100 Subject: ASoC: Remove unneeded i.MX dependency on SND Signed-off-by: Mark Brown diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index 565e327..a700562 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -1,6 +1,6 @@ config SND_MX1_MX2_SOC tristate "SoC Audio for Freecale i.MX1x i.MX2x CPUs" - depends on (ARCH_MX2 || ARCH_MX1) && SND + depends on ARCH_MX2 || ARCH_MX1 select SND_PCM help Say Y or M if you want to add support for codecs attached to -- cgit v0.10.2 From d555a552aeeef45d097f1d3ea2c6dcce6839f1dd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 15 Aug 2009 11:36:49 +0100 Subject: ASoC: Staticise unexported variables Signed-off-by: Mark Brown diff --git a/sound/soc/imx/mx1_mx2-pcm.c b/sound/soc/imx/mx1_mx2-pcm.c index 16efd8a..b838665 100644 --- a/sound/soc/imx/mx1_mx2-pcm.c +++ b/sound/soc/imx/mx1_mx2-pcm.c @@ -376,7 +376,7 @@ static int mx1_mx2_pcm_mmap(struct snd_pcm_substream *substream, runtime->dma_bytes); } -struct snd_pcm_ops mx1_mx2_pcm_ops = { +static struct snd_pcm_ops mx1_mx2_pcm_ops = { .open = mx1_mx2_pcm_open, .close = mx1_mx2_pcm_close, .ioctl = snd_pcm_lib_ioctl, @@ -434,7 +434,7 @@ static void mx1_mx2_pcm_free_dma_buffers(struct snd_pcm *pcm) } } -int mx1_mx2_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, +static int mx1_mx2_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { int ret = 0; -- cgit v0.10.2 From 29e02cb3ffda6ef48a50fea880f63ac8178308bb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 15 Aug 2009 11:37:30 +0100 Subject: ASoC: Hook i.MX into build Signed-off-by: Mark Brown diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index d3e786a..b1749bc 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -29,6 +29,7 @@ source "sound/soc/au1x/Kconfig" source "sound/soc/blackfin/Kconfig" source "sound/soc/davinci/Kconfig" source "sound/soc/fsl/Kconfig" +source "sound/soc/imx/Kconfig" source "sound/soc/omap/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" -- cgit v0.10.2 From 1e97f50b7023cda00cb720e53b9e59c250cb4ed7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 15 Aug 2009 12:15:10 +0100 Subject: ASoC: Factor out cache I/O from WM8974 Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 5104c8a..d8a013a 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -57,55 +57,7 @@ struct wm8974_priv { static struct snd_soc_codec *wm8974_codec; -/* - * read wm8974 register cache - */ -static inline unsigned int wm8974_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg == WM8974_RESET) - return 0; - if (reg >= WM8974_CACHEREGNUM) - return -1; - return cache[reg]; -} - -/* - * write wm8974 register cache - */ -static inline void wm8974_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg >= WM8974_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * write to the WM8974 register space - */ -static int wm8974_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8974 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8974_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define wm8974_reset(c) wm8974_write(c, WM8974_RESET, 0) +#define wm8974_reset(c) snd_soc_write(c, WM8974_RESET, 0) static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" }; static const char *wm8974_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" }; @@ -385,27 +337,27 @@ static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, if (freq_in == 0 || freq_out == 0) { /* Clock CODEC directly from MCLK */ - reg = wm8974_read_reg_cache(codec, WM8974_CLOCK); - wm8974_write(codec, WM8974_CLOCK, reg & 0x0ff); + reg = snd_soc_read(codec, WM8974_CLOCK); + snd_soc_write(codec, WM8974_CLOCK, reg & 0x0ff); /* Turn off PLL */ - reg = wm8974_read_reg_cache(codec, WM8974_POWER1); - wm8974_write(codec, WM8974_POWER1, reg & 0x1df); + reg = snd_soc_read(codec, WM8974_POWER1); + snd_soc_write(codec, WM8974_POWER1, reg & 0x1df); return 0; } pll_factors(freq_out*4, freq_in); - wm8974_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n); - wm8974_write(codec, WM8974_PLLK1, pll_div.k >> 18); - wm8974_write(codec, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff); - wm8974_write(codec, WM8974_PLLK3, pll_div.k & 0x1ff); - reg = wm8974_read_reg_cache(codec, WM8974_POWER1); - wm8974_write(codec, WM8974_POWER1, reg | 0x020); + snd_soc_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n); + snd_soc_write(codec, WM8974_PLLK1, pll_div.k >> 18); + snd_soc_write(codec, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff); + snd_soc_write(codec, WM8974_PLLK3, pll_div.k & 0x1ff); + reg = snd_soc_read(codec, WM8974_POWER1); + snd_soc_write(codec, WM8974_POWER1, reg | 0x020); /* Run CODEC from PLL instead of MCLK */ - reg = wm8974_read_reg_cache(codec, WM8974_CLOCK); - wm8974_write(codec, WM8974_CLOCK, reg | 0x100); + reg = snd_soc_read(codec, WM8974_CLOCK); + snd_soc_write(codec, WM8974_CLOCK, reg | 0x100); return 0; } @@ -421,24 +373,24 @@ static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8974_OPCLKDIV: - reg = wm8974_read_reg_cache(codec, WM8974_GPIO) & 0x1cf; - wm8974_write(codec, WM8974_GPIO, reg | div); + reg = snd_soc_read(codec, WM8974_GPIO) & 0x1cf; + snd_soc_write(codec, WM8974_GPIO, reg | div); break; case WM8974_MCLKDIV: - reg = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x11f; - wm8974_write(codec, WM8974_CLOCK, reg | div); + reg = snd_soc_read(codec, WM8974_CLOCK) & 0x11f; + snd_soc_write(codec, WM8974_CLOCK, reg | div); break; case WM8974_ADCCLK: - reg = wm8974_read_reg_cache(codec, WM8974_ADC) & 0x1f7; - wm8974_write(codec, WM8974_ADC, reg | div); + reg = snd_soc_read(codec, WM8974_ADC) & 0x1f7; + snd_soc_write(codec, WM8974_ADC, reg | div); break; case WM8974_DACCLK: - reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0x1f7; - wm8974_write(codec, WM8974_DAC, reg | div); + reg = snd_soc_read(codec, WM8974_DAC) & 0x1f7; + snd_soc_write(codec, WM8974_DAC, reg | div); break; case WM8974_BCLKDIV: - reg = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x1e3; - wm8974_write(codec, WM8974_CLOCK, reg | div); + reg = snd_soc_read(codec, WM8974_CLOCK) & 0x1e3; + snd_soc_write(codec, WM8974_CLOCK, reg | div); break; default: return -EINVAL; @@ -452,7 +404,7 @@ static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; u16 iface = 0; - u16 clk = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x1fe; + u16 clk = snd_soc_read(codec, WM8974_CLOCK) & 0x1fe; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -499,8 +451,8 @@ static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - wm8974_write(codec, WM8974_IFACE, iface); - wm8974_write(codec, WM8974_CLOCK, clk); + snd_soc_write(codec, WM8974_IFACE, iface); + snd_soc_write(codec, WM8974_CLOCK, clk); return 0; } @@ -509,8 +461,8 @@ static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - u16 iface = wm8974_read_reg_cache(codec, WM8974_IFACE) & 0x19f; - u16 adn = wm8974_read_reg_cache(codec, WM8974_ADD) & 0x1f1; + u16 iface = snd_soc_read(codec, WM8974_IFACE) & 0x19f; + u16 adn = snd_soc_read(codec, WM8974_ADD) & 0x1f1; /* bit size */ switch (params_format(params)) { @@ -549,20 +501,20 @@ static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream, break; } - wm8974_write(codec, WM8974_IFACE, iface); - wm8974_write(codec, WM8974_ADD, adn); + snd_soc_write(codec, WM8974_IFACE, iface); + snd_soc_write(codec, WM8974_ADD, adn); return 0; } static int wm8974_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf; + u16 mute_reg = snd_soc_read(codec, WM8974_DAC) & 0xffbf; if (mute) - wm8974_write(codec, WM8974_DAC, mute_reg | 0x40); + snd_soc_write(codec, WM8974_DAC, mute_reg | 0x40); else - wm8974_write(codec, WM8974_DAC, mute_reg); + snd_soc_write(codec, WM8974_DAC, mute_reg); return 0; } @@ -570,13 +522,13 @@ static int wm8974_mute(struct snd_soc_dai *dai, int mute) static int wm8974_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 power1 = wm8974_read_reg_cache(codec, WM8974_POWER1) & ~0x3; + u16 power1 = snd_soc_read(codec, WM8974_POWER1) & ~0x3; switch (level) { case SND_SOC_BIAS_ON: case SND_SOC_BIAS_PREPARE: power1 |= 0x1; /* VMID 50k */ - wm8974_write(codec, WM8974_POWER1, power1); + snd_soc_write(codec, WM8974_POWER1, power1); break; case SND_SOC_BIAS_STANDBY: @@ -584,18 +536,18 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec, if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Initial cap charge at VMID 5k */ - wm8974_write(codec, WM8974_POWER1, power1 | 0x3); + snd_soc_write(codec, WM8974_POWER1, power1 | 0x3); mdelay(100); } power1 |= 0x2; /* VMID 500k */ - wm8974_write(codec, WM8974_POWER1, power1); + snd_soc_write(codec, WM8974_POWER1, power1); break; case SND_SOC_BIAS_OFF: - wm8974_write(codec, WM8974_POWER1, 0); - wm8974_write(codec, WM8974_POWER2, 0); - wm8974_write(codec, WM8974_POWER3, 0); + snd_soc_write(codec, WM8974_POWER1, 0); + snd_soc_write(codec, WM8974_POWER2, 0); + snd_soc_write(codec, WM8974_POWER3, 0); break; } @@ -738,8 +690,6 @@ static __devinit int wm8974_register(struct wm8974_priv *wm8974) codec->private_data = wm8974; codec->name = "WM8974"; codec->owner = THIS_MODULE; - codec->read = wm8974_read_reg_cache; - codec->write = wm8974_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8974_set_bias_level; codec->dai = &wm8974_dai; @@ -747,12 +697,18 @@ static __devinit int wm8974_register(struct wm8974_priv *wm8974) codec->reg_cache_size = WM8974_CACHEREGNUM; codec->reg_cache = &wm8974->reg_cache; + ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + memcpy(codec->reg_cache, wm8974_reg, sizeof(wm8974_reg)); ret = wm8974_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset\n"); - return ret; + goto err; } wm8974_dai.dev = codec->dev; @@ -764,17 +720,22 @@ static __devinit int wm8974_register(struct wm8974_priv *wm8974) ret = snd_soc_register_codec(codec); if (ret != 0) { dev_err(codec->dev, "Failed to register codec: %d\n", ret); - return ret; + goto err; } ret = snd_soc_register_dai(&wm8974_dai); if (ret != 0) { dev_err(codec->dev, "Failed to register DAI: %d\n", ret); - snd_soc_unregister_codec(codec); - return ret; + goto err_codec; } return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(wm8974); + return ret; } static __devexit void wm8974_unregister(struct wm8974_priv *wm8974) -- cgit v0.10.2 From 6baa0a5ae0954fb2486c480a20556a9f1aee0965 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 14 Aug 2009 12:21:53 +0200 Subject: perf tools: Factorize the thread code in a dedicated file Factorize the thread management code used by perf-annotate and perf-report in dedicated source and header files. v2: pass last_match by address so that it can actually be modified. Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1250245313-6995-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 68218cf..0056405 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -341,6 +341,7 @@ LIB_OBJS += util/callchain.o LIB_OBJS += util/values.o LIB_OBJS += util/debug.o LIB_OBJS += util/map.o +LIB_OBJS += util/thread.o BUILTIN_OBJS += builtin-annotate.o BUILTIN_OBJS += builtin-help.o diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 543c452..3bedaa5 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -20,6 +20,7 @@ #include "util/parse-options.h" #include "util/parse-events.h" +#include "util/thread.h" #define SHOW_KERNEL 1 #define SHOW_USER 2 @@ -44,6 +45,9 @@ static int print_line; static unsigned long page_size; static unsigned long mmap_window = 32; +static struct rb_root threads; +static struct thread *last_match; + struct sym_ext { struct rb_node node; @@ -51,154 +55,6 @@ struct sym_ext { char *path; }; - -struct thread { - struct rb_node rb_node; - struct list_head maps; - pid_t pid; - char *comm; -}; - -static struct thread *thread__new(pid_t pid) -{ - struct thread *self = malloc(sizeof(*self)); - - if (self != NULL) { - self->pid = pid; - self->comm = malloc(32); - if (self->comm) - snprintf(self->comm, 32, ":%d", self->pid); - INIT_LIST_HEAD(&self->maps); - } - - return self; -} - -static int thread__set_comm(struct thread *self, const char *comm) -{ - if (self->comm) - free(self->comm); - self->comm = strdup(comm); - return self->comm ? 0 : -ENOMEM; -} - -static size_t thread__fprintf(struct thread *self, FILE *fp) -{ - struct map *pos; - size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); - - list_for_each_entry(pos, &self->maps, node) - ret += map__fprintf(pos, fp); - - return ret; -} - - -static struct rb_root threads; -static struct thread *last_match; - -static struct thread *threads__findnew(pid_t pid) -{ - struct rb_node **p = &threads.rb_node; - struct rb_node *parent = NULL; - struct thread *th; - - /* - * Font-end cache - PID lookups come in blocks, - * so most of the time we dont have to look up - * the full rbtree: - */ - if (last_match && last_match->pid == pid) - return last_match; - - while (*p != NULL) { - parent = *p; - th = rb_entry(parent, struct thread, rb_node); - - if (th->pid == pid) { - last_match = th; - return th; - } - - if (pid < th->pid) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - th = thread__new(pid); - if (th != NULL) { - rb_link_node(&th->rb_node, parent, p); - rb_insert_color(&th->rb_node, &threads); - last_match = th; - } - - return th; -} - -static void thread__insert_map(struct thread *self, struct map *map) -{ - struct map *pos, *tmp; - - list_for_each_entry_safe(pos, tmp, &self->maps, node) { - if (map__overlap(pos, map)) { - list_del_init(&pos->node); - /* XXX leaks dsos */ - free(pos); - } - } - - list_add_tail(&map->node, &self->maps); -} - -static int thread__fork(struct thread *self, struct thread *parent) -{ - struct map *map; - - if (self->comm) - free(self->comm); - self->comm = strdup(parent->comm); - if (!self->comm) - return -ENOMEM; - - list_for_each_entry(map, &parent->maps, node) { - struct map *new = map__clone(map); - if (!new) - return -ENOMEM; - thread__insert_map(self, new); - } - - return 0; -} - -static struct map *thread__find_map(struct thread *self, u64 ip) -{ - struct map *pos; - - if (self == NULL) - return NULL; - - list_for_each_entry(pos, &self->maps, node) - if (ip >= pos->start && ip <= pos->end) - return pos; - - return NULL; -} - -static size_t threads__fprintf(FILE *fp) -{ - size_t ret = 0; - struct rb_node *nd; - - for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { - struct thread *pos = rb_entry(nd, struct thread, rb_node); - - ret += thread__fprintf(pos, fp); - } - - return ret; -} - /* * histogram, sorted on item, collects counts */ @@ -624,7 +480,7 @@ static void output__resort(void) static void register_idle_thread(void) { - struct thread *thread = threads__findnew(0); + struct thread *thread = threads__findnew(0, &threads, &last_match); if (thread == NULL || thread__set_comm(thread, "[idle]")) { @@ -645,10 +501,12 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) char level; int show = 0; struct dso *dso = NULL; - struct thread *thread = threads__findnew(event->ip.pid); + struct thread *thread; u64 ip = event->ip.ip; struct map *map = NULL; + thread = threads__findnew(event->ip.pid, &threads, &last_match); + dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -719,9 +577,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->mmap.pid); + struct thread *thread; struct map *map = map__new(&event->mmap, NULL, 0); + thread = threads__findnew(event->mmap.pid, &threads, &last_match); + dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -745,8 +605,9 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->comm.pid); + struct thread *thread; + thread = threads__findnew(event->comm.pid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -765,9 +626,11 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) static int process_fork_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->fork.pid); - struct thread *parent = threads__findnew(event->fork.ppid); + struct thread *thread; + struct thread *parent; + thread = threads__findnew(event->fork.pid, &threads, &last_match); + parent = threads__findnew(event->fork.ppid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -1202,7 +1065,7 @@ more: return 0; if (verbose >= 3) - threads__fprintf(stdout); + threads__fprintf(stdout, &threads); if (verbose >= 2) dsos__fprintf(stdout); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 6321951..298f26b 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -25,6 +25,8 @@ #include "util/parse-options.h" #include "util/parse-events.h" +#include "util/thread.h" + #define SHOW_KERNEL 1 #define SHOW_USER 2 #define SHOW_HV 4 @@ -71,6 +73,9 @@ static char __cwd[PATH_MAX]; static char *cwd = __cwd; static int cwdlen; +static struct rb_root threads; +static struct thread *last_match; + static struct callchain_param callchain_param = { .mode = CHAIN_GRAPH_REL, @@ -106,187 +111,10 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...) return n; } -struct thread { - struct rb_node rb_node; - struct list_head maps; - pid_t pid; - char *comm; -}; - -static struct thread *thread__new(pid_t pid) -{ - struct thread *self = malloc(sizeof(*self)); - - if (self != NULL) { - self->pid = pid; - self->comm = malloc(32); - if (self->comm) - snprintf(self->comm, 32, ":%d", self->pid); - INIT_LIST_HEAD(&self->maps); - } - - return self; -} - static unsigned int dsos__col_width, comms__col_width, threads__col_width; -static int thread__set_comm(struct thread *self, const char *comm) -{ - if (self->comm) - free(self->comm); - self->comm = strdup(comm); - if (!self->comm) - return -ENOMEM; - - if (!col_width_list_str && !field_sep && - (!comm_list || strlist__has_entry(comm_list, comm))) { - unsigned int slen = strlen(comm); - if (slen > comms__col_width) { - comms__col_width = slen; - threads__col_width = slen + 6; - } - } - - return 0; -} - -static size_t thread__fprintf(struct thread *self, FILE *fp) -{ - struct map *pos; - size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); - - list_for_each_entry(pos, &self->maps, node) - ret += map__fprintf(pos, fp); - - return ret; -} - - -static struct rb_root threads; -static struct thread *last_match; - -static struct thread *threads__findnew(pid_t pid) -{ - struct rb_node **p = &threads.rb_node; - struct rb_node *parent = NULL; - struct thread *th; - - /* - * Font-end cache - PID lookups come in blocks, - * so most of the time we dont have to look up - * the full rbtree: - */ - if (last_match && last_match->pid == pid) - return last_match; - - while (*p != NULL) { - parent = *p; - th = rb_entry(parent, struct thread, rb_node); - - if (th->pid == pid) { - last_match = th; - return th; - } - - if (pid < th->pid) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - th = thread__new(pid); - if (th != NULL) { - rb_link_node(&th->rb_node, parent, p); - rb_insert_color(&th->rb_node, &threads); - last_match = th; - } - - return th; -} - -static void thread__insert_map(struct thread *self, struct map *map) -{ - struct map *pos, *tmp; - - list_for_each_entry_safe(pos, tmp, &self->maps, node) { - if (map__overlap(pos, map)) { - if (verbose >= 2) { - printf("overlapping maps:\n"); - map__fprintf(map, stdout); - map__fprintf(pos, stdout); - } - - if (map->start <= pos->start && map->end > pos->start) - pos->start = map->end; - - if (map->end >= pos->end && map->start < pos->end) - pos->end = map->start; - - if (verbose >= 2) { - printf("after collision:\n"); - map__fprintf(pos, stdout); - } - - if (pos->start >= pos->end) { - list_del_init(&pos->node); - free(pos); - } - } - } - - list_add_tail(&map->node, &self->maps); -} - -static int thread__fork(struct thread *self, struct thread *parent) -{ - struct map *map; - - if (self->comm) - free(self->comm); - self->comm = strdup(parent->comm); - if (!self->comm) - return -ENOMEM; - - list_for_each_entry(map, &parent->maps, node) { - struct map *new = map__clone(map); - if (!new) - return -ENOMEM; - thread__insert_map(self, new); - } - - return 0; -} - -static struct map *thread__find_map(struct thread *self, u64 ip) -{ - struct map *pos; - - if (self == NULL) - return NULL; - - list_for_each_entry(pos, &self->maps, node) - if (ip >= pos->start && ip <= pos->end) - return pos; - - return NULL; -} - -static size_t threads__fprintf(FILE *fp) -{ - size_t ret = 0; - struct rb_node *nd; - - for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { - struct thread *pos = rb_entry(nd, struct thread, rb_node); - - ret += thread__fprintf(pos, fp); - } - - return ret; -} - /* * histogram, sorted on item, collects counts */ @@ -1228,7 +1056,7 @@ print_entries: static void register_idle_thread(void) { - struct thread *thread = threads__findnew(0); + struct thread *thread = threads__findnew(0, &threads, &last_match); if (thread == NULL || thread__set_comm(thread, "[idle]")) { @@ -1263,7 +1091,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) char level; int show = 0; struct dso *dso = NULL; - struct thread *thread = threads__findnew(event->ip.pid); + struct thread *thread; u64 ip = event->ip.ip; u64 period = 1; struct map *map = NULL; @@ -1271,6 +1099,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) struct ip_callchain *chain = NULL; int cpumode; + thread = threads__findnew(event->ip.pid, &threads, &last_match); + if (sample_type & PERF_SAMPLE_PERIOD) { period = *(u64 *)more_data; more_data += sizeof(u64); @@ -1360,9 +1190,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->mmap.pid); + struct thread *thread; struct map *map = map__new(&event->mmap, cwd, cwdlen); + thread = threads__findnew(event->mmap.pid, &threads, &last_match); + dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -1387,7 +1219,9 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->comm.pid); + struct thread *thread; + + thread = threads__findnew(event->comm.pid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", (void *)(offset + head), @@ -1407,8 +1241,11 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) static int process_task_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread = threads__findnew(event->fork.pid); - struct thread *parent = threads__findnew(event->fork.ppid); + struct thread *thread; + struct thread *parent; + + thread = threads__findnew(event->fork.pid, &threads, &last_match); + parent = threads__findnew(event->fork.ppid, &threads, &last_match); dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n", (void *)(offset + head), @@ -1749,7 +1586,7 @@ done: return 0; if (verbose >= 3) - threads__fprintf(stdout); + threads__fprintf(stdout, &threads); if (verbose >= 2) dsos__fprintf(stdout); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c new file mode 100644 index 0000000..00c14b9 --- /dev/null +++ b/tools/perf/util/thread.c @@ -0,0 +1,143 @@ +#include "../perf.h" +#include +#include +#include +#include "thread.h" +#include "util.h" + +static struct thread *thread__new(pid_t pid) +{ + struct thread *self = malloc(sizeof(*self)); + + if (self != NULL) { + self->pid = pid; + self->comm = malloc(32); + if (self->comm) + snprintf(self->comm, 32, ":%d", self->pid); + INIT_LIST_HEAD(&self->maps); + } + + return self; +} + +int thread__set_comm(struct thread *self, const char *comm) +{ + if (self->comm) + free(self->comm); + self->comm = strdup(comm); + return self->comm ? 0 : -ENOMEM; +} + +static size_t thread__fprintf(struct thread *self, FILE *fp) +{ + struct map *pos; + size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); + + list_for_each_entry(pos, &self->maps, node) + ret += map__fprintf(pos, fp); + + return ret; +} + +struct thread * +threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) +{ + struct rb_node **p = &threads->rb_node; + struct rb_node *parent = NULL; + struct thread *th; + + /* + * Font-end cache - PID lookups come in blocks, + * so most of the time we dont have to look up + * the full rbtree: + */ + if (*last_match && (*last_match)->pid == pid) + return *last_match; + + while (*p != NULL) { + parent = *p; + th = rb_entry(parent, struct thread, rb_node); + + if (th->pid == pid) { + *last_match = th; + return th; + } + + if (pid < th->pid) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + th = thread__new(pid); + if (th != NULL) { + rb_link_node(&th->rb_node, parent, p); + rb_insert_color(&th->rb_node, threads); + *last_match = th; + } + + return th; +} + +void thread__insert_map(struct thread *self, struct map *map) +{ + struct map *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, &self->maps, node) { + if (map__overlap(pos, map)) { + list_del_init(&pos->node); + /* XXX leaks dsos */ + free(pos); + } + } + + list_add_tail(&map->node, &self->maps); +} + +int thread__fork(struct thread *self, struct thread *parent) +{ + struct map *map; + + if (self->comm) + free(self->comm); + self->comm = strdup(parent->comm); + if (!self->comm) + return -ENOMEM; + + list_for_each_entry(map, &parent->maps, node) { + struct map *new = map__clone(map); + if (!new) + return -ENOMEM; + thread__insert_map(self, new); + } + + return 0; +} + +struct map *thread__find_map(struct thread *self, u64 ip) +{ + struct map *pos; + + if (self == NULL) + return NULL; + + list_for_each_entry(pos, &self->maps, node) + if (ip >= pos->start && ip <= pos->end) + return pos; + + return NULL; +} + +size_t threads__fprintf(FILE *fp, struct rb_root *threads) +{ + size_t ret = 0; + struct rb_node *nd; + + for (nd = rb_first(threads); nd; nd = rb_next(nd)) { + struct thread *pos = rb_entry(nd, struct thread, rb_node); + + ret += thread__fprintf(pos, fp); + } + + return ret; +} diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h new file mode 100644 index 0000000..b1c6671 --- /dev/null +++ b/tools/perf/util/thread.h @@ -0,0 +1,19 @@ +#include +#include +#include +#include "symbol.h" + +struct thread { + struct rb_node rb_node; + struct list_head maps; + pid_t pid; + char *comm; +}; + +int thread__set_comm(struct thread *self, const char *comm); +struct thread * +threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); +void thread__insert_map(struct thread *self, struct map *map); +int thread__fork(struct thread *self, struct thread *parent); +struct map *thread__find_map(struct thread *self, u64 ip); +size_t threads__fprintf(FILE *fp, struct rb_root *threads); -- cgit v0.10.2 From 27569620c748ec13f801b4683b448a2ac2adaae4 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 15 Aug 2009 09:53:46 -0700 Subject: rcu: Split hierarchical RCU initialization into boot-time and CPU-online pieces This patch divides the rcutree initialization into boot-time and hotplug-time components, so that the tree data structures are guaranteed to be fully linked at boot time regardless of what might happen in CPU hotplug operations. This makes RCU more resilient against CPU hotplug misbehavior (and vice versa), but more importantly, does a better job of compartmentalizing the code. Reported-by: Ingo Molnar Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: josht@linux.vnet.ibm.com Cc: akpm@linux-foundation.org Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: hugh.dickins@tiscali.co.uk Cc: benh@kernel.crashing.org LKML-Reference: <1250355231152-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 7717b95..f3e4327 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1325,22 +1325,40 @@ int rcu_needs_cpu(int cpu) } /* - * Initialize a CPU's per-CPU RCU data. We take this "scorched earth" - * approach so that we don't have to worry about how long the CPU has - * been gone, or whether it ever was online previously. We do trust the - * ->mynode field, as it is constant for a given struct rcu_data and - * initialized during early boot. - * - * Note that only one online or offline event can be happening at a given - * time. Note also that we can accept some slop in the rsp->completed - * access due to the fact that this CPU cannot possibly have any RCU - * callbacks in flight yet. + * Do boot-time initialization of a CPU's per-CPU RCU data. + */ +static void __init +rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp) +{ + unsigned long flags; + int i; + struct rcu_data *rdp = rsp->rda[cpu]; + struct rcu_node *rnp = rcu_get_root(rsp); + + /* Set up local state, ensuring consistent view of global state. */ + spin_lock_irqsave(&rnp->lock, flags); + rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo); + rdp->nxtlist = NULL; + for (i = 0; i < RCU_NEXT_SIZE; i++) + rdp->nxttail[i] = &rdp->nxtlist; + rdp->qlen = 0; +#ifdef CONFIG_NO_HZ + rdp->dynticks = &per_cpu(rcu_dynticks, cpu); +#endif /* #ifdef CONFIG_NO_HZ */ + rdp->cpu = cpu; + spin_unlock_irqrestore(&rnp->lock, flags); +} + +/* + * Initialize a CPU's per-CPU RCU data. Note that only one online or + * offline event can be happening at a given time. Note also that we + * can accept some slop in the rsp->completed access due to the fact + * that this CPU cannot possibly have any RCU callbacks in flight yet. */ static void __cpuinit rcu_init_percpu_data(int cpu, struct rcu_state *rsp) { unsigned long flags; - int i; long lastcomp; unsigned long mask; struct rcu_data *rdp = rsp->rda[cpu]; @@ -1355,16 +1373,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp) rdp->qs_pending = 1; /* so set up to respond to current GP. */ rdp->beenonline = 1; /* We have now been online. */ rdp->passed_quiesc_completed = lastcomp - 1; - rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo); - rdp->nxtlist = NULL; - for (i = 0; i < RCU_NEXT_SIZE; i++) - rdp->nxttail[i] = &rdp->nxtlist; - rdp->qlen = 0; rdp->blimit = blimit; -#ifdef CONFIG_NO_HZ - rdp->dynticks = &per_cpu(rcu_dynticks, cpu); -#endif /* #ifdef CONFIG_NO_HZ */ - rdp->cpu = cpu; spin_unlock(&rnp->lock); /* irqs remain disabled. */ /* @@ -1539,8 +1548,12 @@ void __init __rcu_init(void) #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ rcu_init_one(&rcu_state); RCU_DATA_PTR_INIT(&rcu_state, rcu_data); + for_each_possible_cpu(i) + rcu_boot_init_percpu_data(i, &rcu_state); rcu_init_one(&rcu_bh_state); RCU_DATA_PTR_INIT(&rcu_bh_state, rcu_bh_data); + for_each_possible_cpu(i) + rcu_boot_init_percpu_data(i, &rcu_bh_state); for_each_online_cpu(i) rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long)i); -- cgit v0.10.2 From 799e64f05f4bfaad2bb3165cab95c8c992a1c296 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 15 Aug 2009 09:53:47 -0700 Subject: cpu hotplug: Introduce cpu_notifier() to handle !HOTPLUG_CPU case This patch introduces a new cpu_notifier() API that is similar to hotcpu_notifier(), but which also notifies of CPUs coming online during boot in the !HOTPLUG_CPU case. Reported-by: Ingo Molnar Reported-by: Hugh Dickins Tested-by: Hugh Dickins Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: josht@linux.vnet.ibm.com Cc: akpm@linux-foundation.org Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: benh@kernel.crashing.org LKML-Reference: <12503552312611-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 4d668e0..4753619 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -48,6 +48,15 @@ struct notifier_block; #ifdef CONFIG_SMP /* Need to know about CPUs going up/down? */ +#if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) +#define cpu_notifier(fn, pri) { \ + static struct notifier_block fn##_nb __cpuinitdata = \ + { .notifier_call = fn, .priority = pri }; \ + register_cpu_notifier(&fn##_nb); \ +} +#else /* #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */ +#define cpu_notifier(fn, pri) do { (void)(fn); } while (0) +#endif /* #else #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */ #ifdef CONFIG_HOTPLUG_CPU extern int register_cpu_notifier(struct notifier_block *nb); extern void unregister_cpu_notifier(struct notifier_block *nb); @@ -74,6 +83,8 @@ extern void cpu_maps_update_done(void); #else /* CONFIG_SMP */ +#define cpu_notifier(fn, pri) do { (void)(fn); } while (0) + static inline int register_cpu_notifier(struct notifier_block *nb) { return 0; @@ -99,11 +110,7 @@ extern struct sysdev_class cpu_sysdev_class; extern void get_online_cpus(void); extern void put_online_cpus(void); -#define hotcpu_notifier(fn, pri) { \ - static struct notifier_block fn##_nb __cpuinitdata = \ - { .notifier_call = fn, .priority = pri }; \ - register_cpu_notifier(&fn##_nb); \ -} +#define hotcpu_notifier(fn, pri) cpu_notifier(fn, pri) #define register_hotcpu_notifier(nb) register_cpu_notifier(nb) #define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb) int cpu_down(unsigned int cpu); -- cgit v0.10.2 From 2e597558086dec36d5c33521a36e0f6b1bc3f3a7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 15 Aug 2009 09:53:48 -0700 Subject: rcu: Simplify RCU CPU-hotplug notification Use the new cpu_notifier() API to simplify RCU's CPU-hotplug notifiers, collapsing down to a single such notifier. This makes it trivial to provide the notifier-ordering guarantee that rcu_barrier() depends on. Also remove redundant open_softirq() calls from Hierarchical RCU notifier. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: josht@linux.vnet.ibm.com Cc: akpm@linux-foundation.org Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: hugh.dickins@tiscali.co.uk Cc: benh@kernel.crashing.org LKML-Reference: <12503552312510-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index eae29c2..8df1156 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -217,9 +217,13 @@ static void rcu_migrate_callback(struct rcu_head *notused) wake_up(&rcu_migrate_wq); } +extern int rcu_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu); + static int __cpuinit rcu_barrier_cpu_hotplug(struct notifier_block *self, unsigned long action, void *hcpu) { + rcu_cpu_notify(self, action, hcpu); if (action == CPU_DYING) { /* * preempt_disable() in on_each_cpu() prevents stop_machine(), @@ -244,8 +248,18 @@ static int __cpuinit rcu_barrier_cpu_hotplug(struct notifier_block *self, void __init rcu_init(void) { + int i; + __rcu_init(); - hotcpu_notifier(rcu_barrier_cpu_hotplug, 0); + cpu_notifier(rcu_barrier_cpu_hotplug, 0); + + /* + * We don't need protection against CPU-hotplug here because + * this is called early in boot, before either interrupts + * or the scheduler are operational. + */ + for_each_online_cpu(i) + rcu_barrier_cpu_hotplug(NULL, CPU_UP_PREPARE, (void *)(long)i); } void rcu_scheduler_starting(void) diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c index beb0e65..9b87f51 100644 --- a/kernel/rcupreempt.c +++ b/kernel/rcupreempt.c @@ -1417,8 +1417,8 @@ int rcu_pending(int cpu) return 0; } -static int __cpuinit rcu_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) +int __cpuinit rcu_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) { long cpu = (long)hcpu; @@ -1439,10 +1439,6 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } -static struct notifier_block __cpuinitdata rcu_nb = { - .notifier_call = rcu_cpu_notify, -}; - void __init __rcu_init(void) { int cpu; @@ -1471,23 +1467,6 @@ void __init __rcu_init(void) rdp->waitschedtail = &rdp->waitschedlist; rdp->rcu_sched_sleeping = 0; } - register_cpu_notifier(&rcu_nb); - - /* - * We don't need protection against CPU-Hotplug here - * since - * a) If a CPU comes online while we are iterating over the - * cpu_online_mask below, we would only end up making a - * duplicate call to rcu_online_cpu() which sets the corresponding - * CPU's mask in the rcu_cpu_online_map. - * - * b) A CPU cannot go offline at this point in time since the user - * does not have access to the sysfs interface, nor do we - * suspend the system. - */ - for_each_online_cpu(cpu) - rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long) cpu); - open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); } diff --git a/kernel/rcutree.c b/kernel/rcutree.c index f3e4327..75762cd 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1132,6 +1132,8 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp) { unsigned long flags; + WARN_ON_ONCE(rdp->beenonline == 0); + /* * If an RCU GP has gone long enough, go check for dyntick * idle CPUs and, if needed, send resched IPIs. @@ -1416,14 +1418,13 @@ static void __cpuinit rcu_online_cpu(int cpu) { rcu_init_percpu_data(cpu, &rcu_state); rcu_init_percpu_data(cpu, &rcu_bh_state); - open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); } /* * Handle CPU online/offline notifcation events. */ -static int __cpuinit rcu_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) +int __cpuinit rcu_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) { long cpu = (long)hcpu; @@ -1532,10 +1533,6 @@ do { \ } \ } while (0) -static struct notifier_block __cpuinitdata rcu_nb = { - .notifier_call = rcu_cpu_notify, -}; - void __init __rcu_init(void) { int i; /* All used by RCU_DATA_PTR_INIT(). */ @@ -1554,11 +1551,7 @@ void __init __rcu_init(void) RCU_DATA_PTR_INIT(&rcu_bh_state, rcu_bh_data); for_each_possible_cpu(i) rcu_boot_init_percpu_data(i, &rcu_bh_state); - - for_each_online_cpu(i) - rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long)i); - /* Register notifier for non-boot CPUs */ - register_cpu_notifier(&rcu_nb); + open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); } module_param(blimit, int, 0); -- cgit v0.10.2 From 8064d54929f23613e649dc7e14f7a94454487d58 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 15 Aug 2009 09:53:49 -0700 Subject: rcu: Make preemptable RCU scan all CPUs when summing RCU counters This patch eliminates the counter-moving during CPU-offline notifiers, eliminating potential confusion if counters are scanned during counter-movement process. This confusion could result in premature ending of an RCU grace period. For example, if there are two tasks in RCU read-side critical sections (so that the sum of the counters is two), and the counter for the CPU going offline is -2, then moving the count to another CPU can result in the sum momentarily appearing to be zero. Since there are no memory barriers in either case, many more such scenarios are possible. So just don't move the counts!!! Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: josht@linux.vnet.ibm.com Cc: akpm@linux-foundation.org Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: hugh.dickins@tiscali.co.uk Cc: benh@kernel.crashing.org LKML-Reference: <12503552312863-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c index 9b87f51..2748b89 100644 --- a/kernel/rcupreempt.c +++ b/kernel/rcupreempt.c @@ -849,7 +849,7 @@ rcu_try_flip_waitzero(void) /* Check to see if the sum of the "last" counters is zero. */ RCU_TRACE_ME(rcupreempt_trace_try_flip_z1); - for_each_cpu(cpu, to_cpumask(rcu_cpu_online_map)) + for_each_possible_cpu(cpu) sum += RCU_DATA_CPU(cpu)->rcu_flipctr[lastidx]; if (sum != 0) { RCU_TRACE_ME(rcupreempt_trace_try_flip_ze1); @@ -1067,12 +1067,6 @@ void rcu_offline_cpu(int cpu) /* seen -after- acknowledgement. */ } - RCU_DATA_ME()->rcu_flipctr[0] += RCU_DATA_CPU(cpu)->rcu_flipctr[0]; - RCU_DATA_ME()->rcu_flipctr[1] += RCU_DATA_CPU(cpu)->rcu_flipctr[1]; - - RCU_DATA_CPU(cpu)->rcu_flipctr[0] = 0; - RCU_DATA_CPU(cpu)->rcu_flipctr[1] = 0; - cpumask_clear_cpu(cpu, to_cpumask(rcu_cpu_online_map)); spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags); -- cgit v0.10.2 From b612ba804b8a656333013ad2ee96fb2377df5dbb Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 15 Aug 2009 09:53:50 -0700 Subject: rcu: Make rcupreempt_trace.c look at offline CPUs Given that offline CPUs can now have non-zero counters, we need to dump counters for offline CPUs as well as for online CPUs. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: josht@linux.vnet.ibm.com Cc: akpm@linux-foundation.org Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: hugh.dickins@tiscali.co.uk Cc: benh@kernel.crashing.org LKML-Reference: <12503552313921-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/kernel/rcupreempt_trace.c b/kernel/rcupreempt_trace.c index 7c2665c..1164034 100644 --- a/kernel/rcupreempt_trace.c +++ b/kernel/rcupreempt_trace.c @@ -236,12 +236,13 @@ static ssize_t rcuctrs_read(struct file *filp, char __user *buffer, cnt += snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE, "CPU last cur F M\n"); - for_each_online_cpu(cpu) { + for_each_possible_cpu(cpu) { long *flipctr = rcupreempt_flipctr(cpu); cnt += snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt, - "%3d %4ld %3ld %d %d\n", + "%3d%c %4ld %3ld %d %d\n", cpu, + cpu_is_offline(cpu) ? '!' : ' ', flipctr[!f], flipctr[f], rcupreempt_flip_flag(cpu), -- cgit v0.10.2 From 684ca5cc9a772532bc893cdc994bd89bf0773719 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 15 Aug 2009 09:53:51 -0700 Subject: rcu: Fix typo in rcu_irq_exit() comment header Signed-off-by: Josh Triplett Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: josht@linux.vnet.ibm.com Cc: akpm@linux-foundation.org Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: hugh.dickins@tiscali.co.uk Cc: benh@kernel.crashing.org LKML-Reference: <1250355231169-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c index 2748b89..510898a 100644 --- a/kernel/rcupreempt.c +++ b/kernel/rcupreempt.c @@ -548,7 +548,7 @@ void rcu_irq_enter(void) * 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 put let the RCU handling be + * 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) -- cgit v0.10.2 From 83a0944fa919fb2ebcfc1f8933d86e437b597ca6 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sat, 15 Aug 2009 12:26:57 +0200 Subject: perf: Enable more compiler warnings Related to a shadowed variable bug fix Valdis Kletnieks noticed that perf does not get built with -Wshadow, which could have helped us avoid the bug. So enable -Wshadow and also enable the following warnings on perf builds, in addition to the already enabled -Wall -Wextra -std=gnu99 warnings: -Wcast-align -Wformat=2 -Wshadow -Winit-self -Wpacked -Wredundant-decls -Wstack-protector -Wstrict-aliasing=3 -Wswitch-default -Wswitch-enum -Wno-system-headers -Wundef -Wvolatile-register-var -Wwrite-strings -Wbad-function-cast -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wstrict-prototypes -Wdeclaration-after-statement And change/fix the perf code to build cleanly under GCC 4.3.2. The list of warnings enablement is rather arbitrary: it's based on my (quick) reading of the GCC manpages and trying them on perf. I categorized the warnings based on individually enabling them and looking whether they trigger something in the perf build. If i liked those warnings (i.e. if they trigger for something that arguably could be improved) i enabled the warning. If the warnings seemed to come from language laywers spamming the build with tons of nuisance warnings i generally kept them off. Most of the sign conversion related warnings were in this category. (A second patch enabling some of the sign warnings might be welcome - sign bugs can be nasty.) I also kept warnings that seem to make sense from their manpage description and which produced no actual warnings on our code base. These warnings might still be turned off if they end up being a nuisance. I also left out a few warnings that are not supported in older compilers. [ Note that these changes might break the build on older compilers i did not test, or on non-x86 architectures that produce different warnings, so more testing would be welcome. ] Reported-by: Valdis.Kletnieks@vt.edu Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 0056405..8608c06 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -166,7 +166,12 @@ endif # CFLAGS and LDFLAGS are for the users to override from the command line. -CFLAGS = $(M64) -ggdb3 -Wall -Wextra -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6 +# +# Include saner warnings here, which can catch bugs: +# +EXTRA_WARNINGS = -Wcast-align -Wformat=2 -Wshadow -Winit-self -Wpacked -Wredundant-decls -Wstack-protector -Wstrict-aliasing=3 -Wswitch-default -Wswitch-enum -Wno-system-headers -Wundef -Wvolatile-register-var -Wwrite-strings -Wbad-function-cast -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wstrict-prototypes -Wdeclaration-after-statement + +CFLAGS = $(M64) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 $(EXTRA_WARNINGS) LDFLAGS = -lpthread -lrt -lelf -lm ALL_CFLAGS = $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 3bedaa5..32ff983 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -81,7 +81,7 @@ struct hist_entry { struct sort_entry { struct list_head list; - char *header; + const char *header; int64_t (*cmp)(struct hist_entry *, struct hist_entry *); int64_t (*collapse)(struct hist_entry *, struct hist_entry *); @@ -225,7 +225,7 @@ static struct sort_entry sort_sym = { static int sort__need_collapse = 0; struct sort_dimension { - char *name; + const char *name; struct sort_entry *entry; int taken; }; @@ -723,7 +723,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) const char *path = NULL; unsigned int hits = 0; double percent = 0.0; - char *color; + const char *color; struct sym_ext *sym_ext = sym->priv; offset = line_ip - start; @@ -805,7 +805,7 @@ static void free_source_line(struct symbol *sym, int len) /* Get the filename:line for the colored entries */ static void -get_source_line(struct symbol *sym, u64 start, int len, char *filename) +get_source_line(struct symbol *sym, u64 start, int len, const char *filename) { int i; char cmd[PATH_MAX * 2]; @@ -851,7 +851,7 @@ get_source_line(struct symbol *sym, u64 start, int len, char *filename) } } -static void print_summary(char *filename) +static void print_summary(const char *filename) { struct sym_ext *sym_ext; struct rb_node *node; @@ -867,7 +867,7 @@ static void print_summary(char *filename) node = rb_first(&root_sym_ext); while (node) { double percent; - char *color; + const char *color; char *path; sym_ext = rb_entry(node, struct sym_ext, node); @@ -882,7 +882,7 @@ static void print_summary(char *filename) static void annotate_sym(struct dso *dso, struct symbol *sym) { - char *filename = dso->name, *d_filename; + const char *filename = dso->name, *d_filename; u64 start, end, len; char command[PATH_MAX*2]; FILE *file; @@ -892,7 +892,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) if (sym->module) filename = sym->module->path; else if (dso == kernel_dso) - filename = vmlinux; + filename = vmlinux_name; start = sym->obj_start; if (!start) @@ -964,7 +964,7 @@ static int __cmd_annotate(void) int ret, rc = EXIT_FAILURE; unsigned long offset = 0; unsigned long head = 0; - struct stat stat; + struct stat input_stat; event_t *event; uint32_t size; char *buf; @@ -977,13 +977,13 @@ static int __cmd_annotate(void) exit(-1); } - ret = fstat(input, &stat); + ret = fstat(input, &input_stat); if (ret < 0) { perror("failed to stat file"); exit(-1); } - if (!stat.st_size) { + if (!input_stat.st_size) { fprintf(stderr, "zero-sized file, nothing to do!\n"); exit(0); } @@ -1010,10 +1010,10 @@ more: if (head + event->header.size >= page_size * mmap_window) { unsigned long shift = page_size * (head / page_size); - int ret; + int munmap_ret; - ret = munmap(buf, page_size * mmap_window); - assert(ret == 0); + munmap_ret = munmap(buf, page_size * mmap_window); + assert(munmap_ret == 0); offset += shift; head -= shift; @@ -1049,7 +1049,7 @@ more: head += size; - if (offset + head < (unsigned long)stat.st_size) + if (offset + head < (unsigned long)input_stat.st_size) goto more; rc = EXIT_SUCCESS; @@ -1092,7 +1092,7 @@ static const struct option options[] = { "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), - OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), + OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), OPT_BOOLEAN('m', "modules", &modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('l', "print-line", &print_line, diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 2599d86..4fb8734 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -456,6 +456,7 @@ int cmd_help(int argc, const char **argv, const char *prefix __used) break; case HELP_FORMAT_WEB: show_html_page(argv[0]); + default: break; } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 298f26b..3b9d24d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -97,6 +97,7 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...) n = vasprintf(&bf, fmt, ap); if (n > 0) { char *sep = bf; + while (1) { sep = strchr(sep, *field_sep); if (sep == NULL) @@ -144,7 +145,7 @@ struct hist_entry { struct sort_entry { struct list_head list; - char *header; + const char *header; int64_t (*cmp)(struct hist_entry *, struct hist_entry *); int64_t (*collapse)(struct hist_entry *, struct hist_entry *); @@ -328,7 +329,7 @@ static int sort__need_collapse = 0; static int sort__has_parent = 0; struct sort_dimension { - char *name; + const char *name; struct sort_entry *entry; int taken; }; @@ -343,7 +344,7 @@ static struct sort_dimension sort_dimensions[] = { static LIST_HEAD(hist_entry__sort_list); -static int sort_dimension__add(char *tok) +static int sort_dimension__add(const char *tok) { unsigned int i; @@ -602,6 +603,7 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, case CHAIN_GRAPH_REL: ret += callchain__fprintf_graph(fp, chain, total_samples, 1, 1); + case CHAIN_NONE: default: break; } @@ -1290,7 +1292,7 @@ process_lost_event(event_t *event, unsigned long offset, unsigned long head) static void trace_event(event_t *event) { unsigned char *raw_event = (void *)event; - char *color = PERF_COLOR_BLUE; + const char *color = PERF_COLOR_BLUE; int i, j; if (!dump_trace) @@ -1348,7 +1350,7 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head) struct perf_counter_attr *attr = perf_header__find_attr(event->read.id); if (show_threads) { - char *name = attr ? __event_name(attr->type, attr->config) + const char *name = attr ? __event_name(attr->type, attr->config) : "unknown"; perf_read_values_add_value(&show_threads_values, event->read.pid, event->read.tid, @@ -1411,19 +1413,19 @@ process_event(event_t *event, unsigned long offset, unsigned long head) static u64 perf_header__sample_type(void) { - u64 sample_type = 0; + u64 type = 0; int i; for (i = 0; i < header->attrs; i++) { struct perf_header_attr *attr = header->attr[i]; - if (!sample_type) - sample_type = attr->attr.sample_type; - else if (sample_type != attr->attr.sample_type) + if (!type) + type = attr->attr.sample_type; + else if (type != attr->attr.sample_type) die("non matching sample_type"); } - return sample_type; + return type; } static int __cmd_report(void) @@ -1431,7 +1433,7 @@ static int __cmd_report(void) int ret, rc = EXIT_FAILURE; unsigned long offset = 0; unsigned long head, shift; - struct stat stat; + struct stat input_stat; event_t *event; uint32_t size; char *buf; @@ -1450,13 +1452,13 @@ static int __cmd_report(void) exit(-1); } - ret = fstat(input, &stat); + ret = fstat(input, &input_stat); if (ret < 0) { perror("failed to stat file"); exit(-1); } - if (!stat.st_size) { + if (!input_stat.st_size) { fprintf(stderr, "zero-sized file, nothing to do!\n"); exit(0); } @@ -1524,12 +1526,12 @@ more: size = 8; if (head + event->header.size >= page_size * mmap_window) { - int ret; + int munmap_ret; shift = page_size * (head / page_size); - ret = munmap(buf, page_size * mmap_window); - assert(ret == 0); + munmap_ret = munmap(buf, page_size * mmap_window); + assert(munmap_ret == 0); offset += shift; head -= shift; @@ -1568,7 +1570,7 @@ more: if (offset + head >= header->data_offset + header->data_size) goto done; - if (offset + head < (unsigned long)stat.st_size) + if (offset + head < (unsigned long)input_stat.st_size) goto more; done: @@ -1666,7 +1668,7 @@ static const struct option options[] = { "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), - OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), + OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), OPT_BOOLEAN('m', "modules", &modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 9a6dbbf..06f763e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -120,7 +120,8 @@ static void parse_source(struct sym_entry *syme) struct module *module; struct section *section = NULL; FILE *file; - char command[PATH_MAX*2], *path = vmlinux; + char command[PATH_MAX*2]; + const char *path = vmlinux_name; u64 start, end, len; if (!syme) @@ -487,10 +488,12 @@ static void print_sym_table(void) ); for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { - struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node); - struct symbol *sym = (struct symbol *)(syme + 1); + struct symbol *sym; double pcnt; + syme = rb_entry(nd, struct sym_entry, rb_node); + sym = (struct symbol *)(syme + 1); + if (++printed > print_entries || (int)syme->snap_count < count_filter) continue; @@ -609,7 +612,7 @@ static void print_mapped_keys(void) fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); - if (vmlinux) { + if (vmlinux_name) { fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); fprintf(stdout, "\t[S] stop annotation.\n"); @@ -638,7 +641,9 @@ static int key_mapped(int c) case 'F': case 's': case 'S': - return vmlinux ? 1 : 0; + return vmlinux_name ? 1 : 0; + default: + break; } return 0; @@ -724,6 +729,8 @@ static void handle_keypress(int c) case 'z': zero = ~zero; break; + default: + break; } } @@ -812,13 +819,13 @@ static int parse_symbols(void) { struct rb_node *node; struct symbol *sym; - int modules = vmlinux ? 1 : 0; + int use_modules = vmlinux_name ? 1 : 0; kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); if (kernel_dso == NULL) return -1; - if (dso__load_kernel(kernel_dso, vmlinux, symbol_filter, verbose, modules) <= 0) + if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0) goto out_delete_dso; node = rb_first(&kernel_dso->syms); @@ -1114,7 +1121,7 @@ static const struct option options[] = { "system-wide collection from all CPUs"), OPT_INTEGER('C', "CPU", &profile_cpu, "CPU to profile on"), - OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), + OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), OPT_INTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), OPT_INTEGER('r', "realtime", &realtime_prio, diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c index 61d33b8..a791dd4 100644 --- a/tools/perf/util/abspath.c +++ b/tools/perf/util/abspath.c @@ -50,7 +50,8 @@ const char *make_absolute_path(const char *path) die ("Could not get current working directory"); if (last_elem) { - int len = strlen(buf); + len = strlen(buf); + if (len + strlen(last_elem) + 2 > PATH_MAX) die ("Too long path name: '%s/%s'", buf, last_elem); diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 4b50c41..6f8ea9d 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -52,7 +52,6 @@ extern const char *perf_mailmap_file; extern void maybe_flush_or_die(FILE *, const char *); extern int copy_fd(int ifd, int ofd); extern int copy_file(const char *dst, const char *src, int mode); -extern ssize_t read_in_full(int fd, void *buf, size_t count); extern ssize_t write_in_full(int fd, const void *buf, size_t count); extern void write_or_die(int fd, const void *buf, size_t count); extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg); diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 0114734..3b8380f 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -50,6 +50,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, else p = &(*p)->rb_right; break; + case CHAIN_NONE: default: break; } @@ -143,6 +144,7 @@ int register_callchain_param(struct callchain_param *param) case CHAIN_FLAT: param->sort = sort_chain_flat; break; + case CHAIN_NONE: default: return -1; } diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 90a044d..e47fdeb 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c @@ -242,9 +242,9 @@ int color_fwrite_lines(FILE *fp, const char *color, return 0; } -char *get_percent_color(double percent) +const char *get_percent_color(double percent) { - char *color = PERF_COLOR_NORMAL; + const char *color = PERF_COLOR_NORMAL; /* * We color high-overhead entries in red, mid-overhead @@ -263,7 +263,7 @@ char *get_percent_color(double percent) int percent_color_fprintf(FILE *fp, const char *fmt, double percent) { int r; - char *color; + const char *color; color = get_percent_color(percent); r = color_fprintf(fp, color, fmt, percent); diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h index 706cec5..43d0d1b 100644 --- a/tools/perf/util/color.h +++ b/tools/perf/util/color.h @@ -36,6 +36,6 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); int percent_color_fprintf(FILE *fp, const char *fmt, double percent); -char *get_percent_color(double percent); +const char *get_percent_color(double percent); #endif /* COLOR_H */ diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 780df54..8784649 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -160,17 +160,18 @@ static int get_extended_base_var(char *name, int baselen, int c) name[baselen++] = '.'; for (;;) { - int c = get_next_char(); - if (c == '\n') + int ch = get_next_char(); + + if (ch == '\n') return -1; - if (c == '"') + if (ch == '"') break; - if (c == '\\') { - c = get_next_char(); - if (c == '\n') + if (ch == '\\') { + ch = get_next_char(); + if (ch == '\n') return -1; } - name[baselen++] = c; + name[baselen++] = ch; if (baselen > MAXNAME / 2) return -1; } @@ -530,6 +531,8 @@ static int store_aux(const char* key, const char* value, void *cb __used) store.offset[store.seen] = ftell(config_file); } } + default: + break; } return 0; } @@ -619,6 +622,7 @@ contline: switch (contents[offset]) { case '=': equal_offset = offset; break; case ']': bracket_offset = offset; break; + default: break; } if (offset > 0 && contents[offset-1] == '\\') { offset_ = offset; @@ -742,9 +746,9 @@ int perf_config_set_multivar(const char* key, const char* value, goto write_err_out; } else { struct stat st; - char* contents; + char *contents; ssize_t contents_sz, copy_begin, copy_end; - int i, new_line = 0; + int new_line = 0; if (value_regex == NULL) store.value_regex = NULL; diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c index 34a3528..2745605 100644 --- a/tools/perf/util/exec_cmd.c +++ b/tools/perf/util/exec_cmd.c @@ -6,7 +6,6 @@ #define MAX_ARGS 32 -extern char **environ; static const char *argv_exec_path; static const char *argv0_path; diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c index ddabe92..3d567fe 100644 --- a/tools/perf/util/module.c +++ b/tools/perf/util/module.c @@ -436,9 +436,9 @@ static int mod_dso__load_module_paths(struct mod_dso *self) goto out_failure; while (!feof(file)) { - char *path, *name, *tmp; + char *name, *tmp; struct module *module; - int line_len, len; + int line_len; line_len = getline(&line, &n, file); if (line_len < 0) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 0441784..1cda97b 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -14,10 +14,10 @@ int nr_counters; struct perf_counter_attr attrs[MAX_COUNTERS]; struct event_symbol { - u8 type; - u64 config; - char *symbol; - char *alias; + u8 type; + u64 config; + const char *symbol; + const char *alias; }; char debugfs_path[MAXPATHLEN]; @@ -51,7 +51,7 @@ static struct event_symbol event_symbols[] = { #define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE) #define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT) -static char *hw_event_names[] = { +static const char *hw_event_names[] = { "cycles", "instructions", "cache-references", @@ -61,7 +61,7 @@ static char *hw_event_names[] = { "bus-cycles", }; -static char *sw_event_names[] = { +static const char *sw_event_names[] = { "cpu-clock-msecs", "task-clock-msecs", "page-faults", @@ -73,7 +73,7 @@ static char *sw_event_names[] = { #define MAX_ALIASES 8 -static char *hw_cache[][MAX_ALIASES] = { +static const char *hw_cache[][MAX_ALIASES] = { { "L1-dcache", "l1-d", "l1d", "L1-data", }, { "L1-icache", "l1-i", "l1i", "L1-instruction", }, { "LLC", "L2" }, @@ -82,13 +82,13 @@ static char *hw_cache[][MAX_ALIASES] = { { "branch", "branches", "bpu", "btb", "bpc", }, }; -static char *hw_cache_op[][MAX_ALIASES] = { +static const char *hw_cache_op[][MAX_ALIASES] = { { "load", "loads", "read", }, { "store", "stores", "write", }, { "prefetch", "prefetches", "speculative-read", "speculative-load", }, }; -static char *hw_cache_result[][MAX_ALIASES] = { +static const char *hw_cache_result[][MAX_ALIASES] = { { "refs", "Reference", "ops", "access", }, { "misses", "miss", }, }; @@ -158,7 +158,7 @@ int valid_debugfs_mount(const char *debugfs) return 0; } -static char *tracepoint_id_to_name(u64 config) +static const char *tracepoint_id_to_name(u64 config) { static char tracepoint_name[2 * MAX_EVENT_LENGTH]; DIR *sys_dir, *evt_dir; @@ -235,7 +235,7 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result) return name; } -char *event_name(int counter) +const char *event_name(int counter) { u64 config = attrs[counter].config; int type = attrs[counter].type; @@ -243,7 +243,7 @@ char *event_name(int counter) return __event_name(type, config); } -char *__event_name(int type, u64 config) +const char *__event_name(int type, u64 config) { static char buf[32]; @@ -294,7 +294,7 @@ char *__event_name(int type, u64 config) return "unknown"; } -static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size) +static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size) { int i, j; int n, longest = -1; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 192a962..9b1aeea 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -9,8 +9,8 @@ extern int nr_counters; extern struct perf_counter_attr attrs[MAX_COUNTERS]; -extern char *event_name(int ctr); -extern char *__event_name(int type, u64 config); +extern const char *event_name(int ctr); +extern const char *__event_name(int type, u64 config); extern int parse_events(const struct option *opt, const char *str, int unset); diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 1bf6719..6d8af48 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -53,6 +53,12 @@ static int get_value(struct parse_opt_ctx_t *p, case OPTION_SET_INT: case OPTION_SET_PTR: return opterror(opt, "takes no value", flags); + case OPTION_END: + case OPTION_ARGUMENT: + case OPTION_GROUP: + case OPTION_STRING: + case OPTION_INTEGER: + case OPTION_LONG: default: break; } @@ -130,6 +136,9 @@ static int get_value(struct parse_opt_ctx_t *p, return opterror(opt, "expects a numerical value", flags); return 0; + case OPTION_END: + case OPTION_ARGUMENT: + case OPTION_GROUP: default: die("should not happen, someone must be hit on the forehead"); } @@ -296,6 +305,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, return parse_options_usage(usagestr, options); case -2: goto unknown; + default: + break; } if (ctx->opt) check_typos(arg + 1, options); @@ -314,6 +325,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, ctx->argv[0] = strdup(ctx->opt - 1); *(char *)ctx->argv[0] = '-'; goto unknown; + default: + break; } } continue; @@ -336,6 +349,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, return parse_options_usage(usagestr, options); case -2: goto unknown; + default: + break; } continue; unknown: @@ -456,6 +471,13 @@ int usage_with_options_internal(const char * const *usagestr, } break; default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */ + case OPTION_END: + case OPTION_GROUP: + case OPTION_BIT: + case OPTION_BOOLEAN: + case OPTION_SET_INT: + case OPTION_SET_PTR: + case OPTION_LONG: break; } diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c index a501a40..fd1f2fa 100644 --- a/tools/perf/util/path.c +++ b/tools/perf/util/path.c @@ -17,7 +17,7 @@ static char bad_path[] = "/bad-path/"; * Two hacks: */ -static char *get_perf_dir(void) +static const char *get_perf_dir(void) { return "."; } @@ -38,8 +38,9 @@ size_t strlcpy(char *dest, const char *src, size_t size) static char *get_pathname(void) { static char pathname_array[4][PATH_MAX]; - static int index; - return pathname_array[3 & ++index]; + static int idx; + + return pathname_array[3 & ++idx]; } static char *cleanup_path(char *path) @@ -161,20 +162,24 @@ int perf_mkstemp(char *path, size_t len, const char *template) } -const char *make_relative_path(const char *abs, const char *base) +const char *make_relative_path(const char *abs_path, const char *base) { static char buf[PATH_MAX + 1]; int baselen; + if (!base) - return abs; + return abs_path; + baselen = strlen(base); - if (prefixcmp(abs, base)) - return abs; - if (abs[baselen] == '/') + if (prefixcmp(abs_path, base)) + return abs_path; + if (abs_path[baselen] == '/') baselen++; else if (base[baselen - 1] != '/') - return abs; - strcpy(buf, abs + baselen); + return abs_path; + + strcpy(buf, abs_path + baselen); + return buf; } diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c index a393534..2b615ac 100644 --- a/tools/perf/util/run-command.c +++ b/tools/perf/util/run-command.c @@ -262,7 +262,7 @@ int run_hook(const char *index_file, const char *name, ...) { struct child_process hook; const char **argv = NULL, *env[2]; - char index[PATH_MAX]; + char idx[PATH_MAX]; va_list args; int ret; size_t i = 0, alloc = 0; @@ -284,8 +284,8 @@ int run_hook(const char *index_file, const char *name, ...) hook.no_stdin = 1; hook.stdout_to_stderr = 1; if (index_file) { - snprintf(index, sizeof(index), "PERF_INDEX_FILE=%s", index_file); - env[0] = index; + snprintf(idx, sizeof(idx), "PERF_INDEX_FILE=%s", index_file); + env[0] = idx; env[1] = NULL; hook.env = env; } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 0b98623..3159d47 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -21,7 +21,7 @@ enum dso_origin { static struct symbol *symbol__new(u64 start, u64 len, const char *name, unsigned int priv_size, - u64 obj_start, int verbose) + u64 obj_start, int v) { size_t namelen = strlen(name) + 1; struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); @@ -29,7 +29,7 @@ static struct symbol *symbol__new(u64 start, u64 len, if (!self) return NULL; - if (verbose >= 2) + if (v >= 2) printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); @@ -156,7 +156,7 @@ size_t dso__fprintf(struct dso *self, FILE *fp) return ret; } -static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose) +static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) { struct rb_node *nd, *prevnd; char *line = NULL; @@ -198,7 +198,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb * Well fix up the end later, when we have all sorted. */ sym = symbol__new(start, 0xdead, line + len + 2, - self->sym_priv_size, 0, verbose); + self->sym_priv_size, 0, v); if (sym == NULL) goto out_delete_line; @@ -239,7 +239,7 @@ out_failure: return -1; } -static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose) +static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) { char *line = NULL; size_t n; @@ -277,7 +277,7 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verb continue; sym = symbol__new(start, size, line + len, - self->sym_priv_size, start, verbose); + self->sym_priv_size, start, v); if (sym == NULL) goto out_delete_line; @@ -305,13 +305,13 @@ out_failure: * elf_symtab__for_each_symbol - iterate thru all the symbols * * @self: struct elf_symtab instance to iterate - * @index: uint32_t index + * @idx: uint32_t idx * @sym: GElf_Sym iterator */ -#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \ - for (index = 0, gelf_getsym(syms, index, &sym);\ - index < nr_syms; \ - index++, gelf_getsym(syms, index, &sym)) +#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ + for (idx = 0, gelf_getsym(syms, idx, &sym);\ + idx < nr_syms; \ + idx++, gelf_getsym(syms, idx, &sym)) static inline uint8_t elf_sym__type(const GElf_Sym *sym) { @@ -354,7 +354,7 @@ static inline const char *elf_sym__name(const GElf_Sym *sym, static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, GElf_Shdr *shp, const char *name, - size_t *index) + size_t *idx) { Elf_Scn *sec = NULL; size_t cnt = 1; @@ -365,8 +365,8 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, gelf_getshdr(sec, shp); str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); if (!strcmp(name, str)) { - if (index) - *index = cnt; + if (idx) + *idx = cnt; break; } ++cnt; @@ -392,7 +392,7 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, * And always look at the original dso, not at debuginfo packages, that * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). */ -static int dso__synthesize_plt_symbols(struct dso *self, int verbose) +static int dso__synthesize_plt_symbols(struct dso *self, int v) { uint32_t nr_rel_entries, idx; GElf_Sym sym; @@ -442,7 +442,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int verbose) goto out_elf_end; /* - * Fetch the relocation section to find the indexes to the GOT + * Fetch the relocation section to find the idxes to the GOT * and the symbols in the .dynsym they refer to. */ reldata = elf_getdata(scn_plt_rel, NULL); @@ -476,7 +476,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int verbose) "%s@plt", elf_sym__name(&sym, symstrs)); f = symbol__new(plt_offset, shdr_plt.sh_entsize, - sympltname, self->sym_priv_size, 0, verbose); + sympltname, self->sym_priv_size, 0, v); if (!f) goto out_elf_end; @@ -494,7 +494,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int verbose) "%s@plt", elf_sym__name(&sym, symstrs)); f = symbol__new(plt_offset, shdr_plt.sh_entsize, - sympltname, self->sym_priv_size, 0, verbose); + sympltname, self->sym_priv_size, 0, v); if (!f) goto out_elf_end; @@ -518,12 +518,12 @@ out: } static int dso__load_sym(struct dso *self, int fd, const char *name, - symbol_filter_t filter, int verbose, struct module *mod) + symbol_filter_t filter, int v, struct module *mod) { Elf_Data *symstrs, *secstrs; uint32_t nr_syms; int err = -1; - uint32_t index; + uint32_t idx; GElf_Ehdr ehdr; GElf_Shdr shdr; Elf_Data *syms; @@ -534,14 +534,14 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); if (elf == NULL) { - if (verbose) + if (v) fprintf(stderr, "%s: cannot read %s ELF file.\n", __func__, name); goto out_close; } if (gelf_getehdr(elf, &ehdr) == NULL) { - if (verbose) + if (v) fprintf(stderr, "%s: cannot get elf header.\n", __func__); goto out_elf_end; } @@ -583,9 +583,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, NULL) != NULL); } else self->adjust_symbols = 0; - elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { + elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { struct symbol *f; - const char *name; + const char *elf_name; char *demangled; u64 obj_start; struct section *section = NULL; @@ -608,7 +608,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, obj_start = sym.st_value; if (self->adjust_symbols) { - if (verbose >= 2) + if (v >= 2) printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); @@ -630,13 +630,13 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, * DWARF DW_compile_unit has this, but we don't always have access * to it... */ - name = elf_sym__name(&sym, symstrs); - demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI); + elf_name = elf_sym__name(&sym, symstrs); + demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); if (demangled != NULL) - name = demangled; + elf_name = demangled; - f = symbol__new(sym.st_value, sym.st_size, name, - self->sym_priv_size, obj_start, verbose); + f = symbol__new(sym.st_value, sym.st_size, elf_name, + self->sym_priv_size, obj_start, v); free(demangled); if (!f) goto out_elf_end; @@ -659,7 +659,7 @@ out_close: #define BUILD_ID_SIZE 128 -static char *dso__read_build_id(struct dso *self, int verbose) +static char *dso__read_build_id(struct dso *self, int v) { int i; GElf_Ehdr ehdr; @@ -676,14 +676,14 @@ static char *dso__read_build_id(struct dso *self, int verbose) elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); if (elf == NULL) { - if (verbose) + if (v) fprintf(stderr, "%s: cannot read %s ELF file.\n", __func__, self->name); goto out_close; } if (gelf_getehdr(elf, &ehdr) == NULL) { - if (verbose) + if (v) fprintf(stderr, "%s: cannot get elf header.\n", __func__); goto out_elf_end; } @@ -706,7 +706,7 @@ static char *dso__read_build_id(struct dso *self, int verbose) ++raw; bid += 2; } - if (verbose >= 2) + if (v >= 2) printf("%s(%s): %s\n", __func__, self->name, build_id); out_elf_end: elf_end(elf); @@ -732,7 +732,7 @@ char dso__symtab_origin(const struct dso *self) return origin[self->origin]; } -int dso__load(struct dso *self, symbol_filter_t filter, int verbose) +int dso__load(struct dso *self, symbol_filter_t filter, int v) { int size = PATH_MAX; char *name = malloc(size), *build_id = NULL; @@ -745,7 +745,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose) self->adjust_symbols = 0; if (strncmp(self->name, "/tmp/perf-", 10) == 0) { - ret = dso__load_perf_map(self, filter, verbose); + ret = dso__load_perf_map(self, filter, v); self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : DSO__ORIG_NOT_FOUND; return ret; @@ -764,7 +764,7 @@ more: snprintf(name, size, "/usr/lib/debug%s", self->name); break; case DSO__ORIG_BUILDID: - build_id = dso__read_build_id(self, verbose); + build_id = dso__read_build_id(self, v); if (build_id != NULL) { snprintf(name, size, "/usr/lib/debug/.build-id/%.2s/%s.debug", @@ -785,7 +785,7 @@ more: fd = open(name, O_RDONLY); } while (fd < 0); - ret = dso__load_sym(self, fd, name, filter, verbose, NULL); + ret = dso__load_sym(self, fd, name, filter, v, NULL); close(fd); /* @@ -795,7 +795,7 @@ more: goto more; if (ret > 0) { - int nr_plt = dso__synthesize_plt_symbols(self, verbose); + int nr_plt = dso__synthesize_plt_symbols(self, v); if (nr_plt > 0) ret += nr_plt; } @@ -807,7 +807,7 @@ out: } static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, - symbol_filter_t filter, int verbose) + symbol_filter_t filter, int v) { struct module *mod = mod_dso__find_module(mods, name); int err = 0, fd; @@ -820,13 +820,13 @@ static int dso__load_module(struct dso *self, struct mod_dso *mods, const char * if (fd < 0) return err; - err = dso__load_sym(self, fd, name, filter, verbose, mod); + err = dso__load_sym(self, fd, name, filter, v, mod); close(fd); return err; } -int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose) +int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) { struct mod_dso *mods = mod_dso__new_dso("modules"); struct module *pos; @@ -844,7 +844,7 @@ int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose) next = rb_first(&mods->mods); while (next) { pos = rb_entry(next, struct module, rb_node); - err = dso__load_module(self, mods, pos->name, filter, verbose); + err = dso__load_module(self, mods, pos->name, filter, v); if (err < 0) break; @@ -887,14 +887,14 @@ static inline void dso__fill_symbol_holes(struct dso *self) } static int dso__load_vmlinux(struct dso *self, const char *vmlinux, - symbol_filter_t filter, int verbose) + symbol_filter_t filter, int v) { int err, fd = open(vmlinux, O_RDONLY); if (fd < 0) return -1; - err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL); + err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); if (err > 0) dso__fill_symbol_holes(self); @@ -905,18 +905,18 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux, } int dso__load_kernel(struct dso *self, const char *vmlinux, - symbol_filter_t filter, int verbose, int modules) + symbol_filter_t filter, int v, int use_modules) { int err = -1; if (vmlinux) { - err = dso__load_vmlinux(self, vmlinux, filter, verbose); - if (err > 0 && modules) - err = dso__load_modules(self, filter, verbose); + err = dso__load_vmlinux(self, vmlinux, filter, v); + if (err > 0 && use_modules) + err = dso__load_modules(self, filter, v); } if (err <= 0) - err = dso__load_kallsyms(self, filter, verbose); + err = dso__load_kallsyms(self, filter, v); if (err > 0) self->origin = DSO__ORIG_KERNEL; @@ -929,7 +929,7 @@ struct dso *kernel_dso; struct dso *vdso; struct dso *hypervisor_dso; -char *vmlinux = "vmlinux"; +const char *vmlinux_name = "vmlinux"; int modules; static void dsos__add(struct dso *dso) @@ -997,7 +997,7 @@ int load_kernel(void) if (!kernel_dso) return -1; - err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules); + err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); if (err <= 0) { dso__delete(kernel_dso); kernel_dso = NULL; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 48b8e57..6e84907 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -55,7 +55,7 @@ struct dso { char name[0]; }; -const char *sym_hist_filter; +extern const char *sym_hist_filter; typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym); @@ -87,6 +87,6 @@ extern struct list_head dsos; extern struct dso *kernel_dso; extern struct dso *vdso; extern struct dso *hypervisor_dso; -extern char *vmlinux; +extern const char *vmlinux_name; extern int modules; #endif /* _PERF_SYMBOL_ */ diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c index 614cfaf..1c15e39 100644 --- a/tools/perf/util/values.c +++ b/tools/perf/util/values.c @@ -96,7 +96,7 @@ static void perf_read_values__enlarge_counters(struct perf_read_values *values) } static int perf_read_values__findnew_counter(struct perf_read_values *values, - u64 rawid, char *name) + u64 rawid, const char *name) { int i; @@ -116,7 +116,7 @@ static int perf_read_values__findnew_counter(struct perf_read_values *values, void perf_read_values_add_value(struct perf_read_values *values, u32 pid, u32 tid, - u64 rawid, char *name, u64 value) + u64 rawid, const char *name, u64 value) { int tindex, cindex; @@ -221,8 +221,7 @@ static void perf_read_values__display_raw(FILE *fp, countwidth, values->value[i][j]); } -void perf_read_values_display(FILE *fp, struct perf_read_values *values, - int raw) +void perf_read_values_display(FILE *fp, struct perf_read_values *values, int raw) { if (raw) perf_read_values__display_raw(fp, values); diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h index f8960fd..cadf8cf 100644 --- a/tools/perf/util/values.h +++ b/tools/perf/util/values.h @@ -19,7 +19,7 @@ void perf_read_values_destroy(struct perf_read_values *values); void perf_read_values_add_value(struct perf_read_values *values, u32 pid, u32 tid, - u64 rawid, char *name, u64 value); + u64 rawid, const char *name, u64 value); void perf_read_values_display(FILE *fp, struct perf_read_values *values, int raw); -- cgit v0.10.2 From 84bc4af59081ee974dd80210e694ab59ebe51ce8 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Thu, 13 Aug 2009 17:36:53 -0700 Subject: futex: Detect mismatched requeue targets There is currently no check to ensure that userspace uses the same futex requeue target (uaddr2) in futex_requeue() that the waiter used in futex_wait_requeue_pi(). A mismatch here could very unexpected results as the waiter assumes it either wakes on uaddr1 or uaddr2. We could detect this on wakeup in the waiter, but the cleanup is more intense after the improper requeue has occured. This patch stores the waiter's expected requeue target in a new requeue_pi_key pointer in the futex_q which futex_requeue() checks prior to attempting to do a proxy lock acquistion or a requeue when requeue_pi=1. If they don't match, return -EINVAL from futex_requeue, aborting the requeue of any remaining waiters. Signed-off-by: Darren Hart Cc: Peter Zijlstra Cc: Eric Dumazet Cc: John Kacur Cc: Dinakar Guniguntala Cc: John Stultz LKML-Reference: <20090814003650.14634.63916.stgit@Aeon> Signed-off-by: Thomas Gleixner diff --git a/kernel/futex.c b/kernel/futex.c index d077201..f0dea28 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -115,6 +115,9 @@ struct futex_q { /* rt_waiter storage for requeue_pi: */ struct rt_mutex_waiter *rt_waiter; + /* The expected requeue pi target futex key: */ + union futex_key *requeue_pi_key; + /* Bitset for the optional bitmasked wakeup */ u32 bitset; }; @@ -1080,6 +1083,10 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex, if (!top_waiter) return 0; + /* Ensure we requeue to the expected futex. */ + if (!match_futex(top_waiter->requeue_pi_key, key2)) + return -EINVAL; + /* * Try to take the lock for top_waiter. Set the FUTEX_WAITERS bit in * the contended case or if set_waiters is 1. The pi_state is returned @@ -1260,6 +1267,12 @@ retry_private: continue; } + /* Ensure we requeue to the expected futex for requeue_pi. */ + if (requeue_pi && !match_futex(this->requeue_pi_key, &key2)) { + ret = -EINVAL; + break; + } + /* * Requeue nr_requeue waiters and possibly one more in the case * of requeue_pi if we couldn't acquire the lock atomically. @@ -1735,6 +1748,7 @@ static int futex_wait(u32 __user *uaddr, int fshared, q.pi_state = NULL; q.bitset = bitset; q.rt_waiter = NULL; + q.requeue_pi_key = NULL; if (abs_time) { to = &timeout; @@ -1842,6 +1856,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared, q.pi_state = NULL; q.rt_waiter = NULL; + q.requeue_pi_key = NULL; retry: q.key = FUTEX_KEY_INIT; ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE); @@ -2153,15 +2168,16 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, debug_rt_mutex_init_waiter(&rt_waiter); rt_waiter.task = NULL; - q.pi_state = NULL; - q.bitset = bitset; - q.rt_waiter = &rt_waiter; - key2 = FUTEX_KEY_INIT; ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE); if (unlikely(ret != 0)) goto out; + q.pi_state = NULL; + q.bitset = bitset; + q.rt_waiter = &rt_waiter; + q.requeue_pi_key = &key2; + /* Prepare to wait on uaddr. */ ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); if (ret) -- cgit v0.10.2 From 35ba15b737e2cd1d780943189f2138519f81fd42 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 16 Aug 2009 11:09:21 +0200 Subject: perf: Build with stack-protector and with -D_FORTIFY_SOURCE=2 Up our defences a bit. Suggested-by: Arjan van de Ven Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 8608c06..d637aea 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -171,7 +171,7 @@ endif # EXTRA_WARNINGS = -Wcast-align -Wformat=2 -Wshadow -Winit-self -Wpacked -Wredundant-decls -Wstack-protector -Wstrict-aliasing=3 -Wswitch-default -Wswitch-enum -Wno-system-headers -Wundef -Wvolatile-register-var -Wwrite-strings -Wbad-function-cast -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wstrict-prototypes -Wdeclaration-after-statement -CFLAGS = $(M64) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 $(EXTRA_WARNINGS) +CFLAGS = $(M64) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) LDFLAGS = -lpthread -lrt -lelf -lm ALL_CFLAGS = $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) -- cgit v0.10.2 From 0d31b82dd5c54a0b1e1d789427abdcc180bc4602 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 16 Aug 2009 17:52:07 +0200 Subject: perf tools: Substract -Wformat-nonliteral from Wformat=2 in extra flags The soon coming perf trace needs to use printf with dynamically built formats. But we are using -Wformat=2 which is a shortcut for the following set: -Wformat -Wformat-security -Wformat-y2k -Wformat-nonliteral -Wformat-nonliteral warns when it can't check formats because they are not builtin constant strings, but we want to feature dynamic formats. What we want instead is Wformat=2 minus -Wformat-nonliteral, which is what this patch does. Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1250437927-25490-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/Makefile b/tools/perf/Makefile index d637aea..5d54ddb 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -169,7 +169,7 @@ endif # # Include saner warnings here, which can catch bugs: # -EXTRA_WARNINGS = -Wcast-align -Wformat=2 -Wshadow -Winit-self -Wpacked -Wredundant-decls -Wstack-protector -Wstrict-aliasing=3 -Wswitch-default -Wswitch-enum -Wno-system-headers -Wundef -Wvolatile-register-var -Wwrite-strings -Wbad-function-cast -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wstrict-prototypes -Wdeclaration-after-statement +EXTRA_WARNINGS = -Wcast-align -Wformat -Wformat-security -Wformat-y2k -Wshadow -Winit-self -Wpacked -Wredundant-decls -Wstack-protector -Wstrict-aliasing=3 -Wswitch-default -Wswitch-enum -Wno-system-headers -Wundef -Wvolatile-register-var -Wwrite-strings -Wbad-function-cast -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wstrict-prototypes -Wdeclaration-after-statement CFLAGS = $(M64) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) LDFLAGS = -lpthread -lrt -lelf -lm -- cgit v0.10.2 From 2cec19d9d0716f8d68f1c5a87667d0387d4d252d Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 16 Aug 2009 19:24:21 +0200 Subject: perf tools: Factorize the dprintf definition We have two users of dprintf: report and annotate. Another one is coming with perf trace. Then factorize it into the debug file. While at it, rename dprintf() to dump_printf() so that it doesn't conflicts with its libc homograph. Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1250443461-28130-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 32ff983..820e7cc 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -34,10 +34,6 @@ static char *sort_order = default_sort_order; static int input; static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; -static int dump_trace = 0; -#define dprintf(x...) do { if (dump_trace) printf(x); } while (0) - - static int full_paths; static int print_line; @@ -507,14 +503,14 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) thread = threads__findnew(event->ip.pid, &threads, &last_match); - dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", + dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", (void *)(offset + head), (void *)(long)(event->header.size), event->header.misc, event->ip.pid, (void *)(long)ip); - dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); + dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); if (thread == NULL) { fprintf(stderr, "problem processing %d event, skipping it.\n", @@ -528,7 +524,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) dso = kernel_dso; - dprintf(" ...... dso: %s\n", dso->name); + dump_printf(" ...... dso: %s\n", dso->name); } else if (event->header.misc & PERF_EVENT_MISC_USER) { @@ -549,12 +545,12 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if ((long long)ip < 0) dso = kernel_dso; } - dprintf(" ...... dso: %s\n", dso ? dso->name : ""); + dump_printf(" ...... dso: %s\n", dso ? dso->name : ""); } else { show = SHOW_HV; level = 'H'; - dprintf(" ...... dso: [hypervisor]\n"); + dump_printf(" ...... dso: [hypervisor]\n"); } if (show & show_mask) { @@ -582,7 +578,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) thread = threads__findnew(event->mmap.pid, &threads, &last_match); - dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", + dump_printf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), (void *)(long)(event->header.size), event->mmap.pid, @@ -592,7 +588,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) event->mmap.filename); if (thread == NULL || map == NULL) { - dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n"); + dump_printf("problem processing PERF_EVENT_MMAP, skipping event.\n"); return 0; } @@ -608,14 +604,14 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) struct thread *thread; thread = threads__findnew(event->comm.pid, &threads, &last_match); - dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", + dump_printf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), event->comm.comm, event->comm.pid); if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { - dprintf("problem processing PERF_EVENT_COMM, skipping event.\n"); + dump_printf("problem processing PERF_EVENT_COMM, skipping event.\n"); return -1; } total_comm++; @@ -631,13 +627,13 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head) thread = threads__findnew(event->fork.pid, &threads, &last_match); parent = threads__findnew(event->fork.ppid, &threads, &last_match); - dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", + dump_printf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), event->fork.pid, event->fork.ppid); if (!thread || !parent || thread__fork(thread, parent)) { - dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); + dump_printf("problem processing PERF_EVENT_FORK, skipping event.\n"); return -1; } total_fork++; @@ -1022,14 +1018,14 @@ more: size = event->header.size; - dprintf("%p [%p]: event: %d\n", + dump_printf("%p [%p]: event: %d\n", (void *)(offset + head), (void *)(long)event->header.size, event->header.type); if (!size || process_event(event, offset, head) < 0) { - dprintf("%p [%p]: skipping unknown header type: %d\n", + dump_printf("%p [%p]: skipping unknown header type: %d\n", (void *)(offset + head), (void *)(long)(event->header.size), event->header.type); @@ -1055,11 +1051,11 @@ more: rc = EXIT_SUCCESS; close(input); - dprintf(" IP events: %10ld\n", total); - dprintf(" mmap events: %10ld\n", total_mmap); - dprintf(" comm events: %10ld\n", total_comm); - dprintf(" fork events: %10ld\n", total_fork); - dprintf(" unknown events: %10ld\n", total_unknown); + dump_printf(" IP events: %10ld\n", total); + dump_printf(" mmap events: %10ld\n", total_mmap); + dump_printf(" comm events: %10ld\n", total_comm); + dump_printf(" fork events: %10ld\n", total_fork); + dump_printf(" unknown events: %10ld\n", total_unknown); if (dump_trace) return 0; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3b9d24d..e104ed3 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -43,8 +43,6 @@ static char *field_sep; static int input; static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; -static int dump_trace = 0; -#define dprintf(x...) do { if (dump_trace) printf(x); } while (0) #define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0) static int full_paths; @@ -713,8 +711,8 @@ got_map: if ((long long)ip < 0) dso = kernel_dso; } - dprintf(" ...... dso: %s\n", dso ? dso->name : ""); - dprintf(" ...... map: %Lx -> %Lx\n", *ipp, ip); + dump_printf(" ...... dso: %s\n", dso ? dso->name : ""); + dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); *ipp = ip; if (dsop) @@ -1108,7 +1106,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) more_data += sizeof(u64); } - dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", + dump_printf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", (void *)(offset + head), (void *)(long)(event->header.size), event->header.misc, @@ -1121,7 +1119,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) chain = (void *)more_data; - dprintf("... chain: nr:%Lu\n", chain->nr); + dump_printf("... chain: nr:%Lu\n", chain->nr); if (validate_chain(chain, event) < 0) { eprintf("call-chain problem with event, skipping it.\n"); @@ -1130,11 +1128,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if (dump_trace) { for (i = 0; i < chain->nr; i++) - dprintf("..... %2d: %016Lx\n", i, chain->ips[i]); + dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]); } } - dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); + dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); if (thread == NULL) { eprintf("problem processing %d event, skipping it.\n", @@ -1153,7 +1151,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) dso = kernel_dso; - dprintf(" ...... dso: %s\n", dso->name); + dump_printf(" ...... dso: %s\n", dso->name); } else if (cpumode == PERF_EVENT_MISC_USER) { @@ -1166,7 +1164,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) dso = hypervisor_dso; - dprintf(" ...... dso: [hypervisor]\n"); + dump_printf(" ...... dso: [hypervisor]\n"); } if (show & show_mask) { @@ -1197,7 +1195,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) thread = threads__findnew(event->mmap.pid, &threads, &last_match); - dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n", + dump_printf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), (void *)(long)(event->header.size), event->mmap.pid, @@ -1208,7 +1206,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) event->mmap.filename); if (thread == NULL || map == NULL) { - dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n"); + dump_printf("problem processing PERF_EVENT_MMAP, skipping event.\n"); return 0; } @@ -1225,14 +1223,14 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) thread = threads__findnew(event->comm.pid, &threads, &last_match); - dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", + dump_printf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), event->comm.comm, event->comm.pid); if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { - dprintf("problem processing PERF_EVENT_COMM, skipping event.\n"); + dump_printf("problem processing PERF_EVENT_COMM, skipping event.\n"); return -1; } total_comm++; @@ -1249,7 +1247,7 @@ process_task_event(event_t *event, unsigned long offset, unsigned long head) thread = threads__findnew(event->fork.pid, &threads, &last_match); parent = threads__findnew(event->fork.ppid, &threads, &last_match); - dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n", + dump_printf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n", (void *)(offset + head), (void *)(long)(event->header.size), event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT", @@ -1267,7 +1265,7 @@ process_task_event(event_t *event, unsigned long offset, unsigned long head) return 0; if (!thread || !parent || thread__fork(thread, parent)) { - dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); + dump_printf("problem processing PERF_EVENT_FORK, skipping event.\n"); return -1; } total_fork++; @@ -1278,7 +1276,7 @@ process_task_event(event_t *event, unsigned long offset, unsigned long head) static int process_lost_event(event_t *event, unsigned long offset, unsigned long head) { - dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", + dump_printf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", (void *)(offset + head), (void *)(long)(event->header.size), event->lost.id, @@ -1298,12 +1296,12 @@ static void trace_event(event_t *event) if (!dump_trace) return; - dprintf("."); + dump_printf("."); cdprintf("\n. ... raw event: size %d bytes\n", event->header.size); for (i = 0; i < event->header.size; i++) { if ((i & 15) == 0) { - dprintf("."); + dump_printf("."); cdprintf(" %04x: ", i); } @@ -1322,7 +1320,7 @@ static void trace_event(event_t *event) cdprintf("\n"); } } - dprintf(".\n"); + dump_printf(".\n"); } static struct perf_header *header; @@ -1359,7 +1357,7 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head) event->read.value); } - dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n", + dump_printf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n", (void *)(offset + head), (void *)(long)(event->header.size), event->read.pid, @@ -1540,14 +1538,14 @@ more: size = event->header.size; - dprintf("\n%p [%p]: event: %d\n", + dump_printf("\n%p [%p]: event: %d\n", (void *)(offset + head), (void *)(long)event->header.size, event->header.type); if (!size || process_event(event, offset, head) < 0) { - dprintf("%p [%p]: skipping unknown header type: %d\n", + dump_printf("%p [%p]: skipping unknown header type: %d\n", (void *)(offset + head), (void *)(long)(event->header.size), event->header.type); @@ -1577,12 +1575,12 @@ done: rc = EXIT_SUCCESS; close(input); - dprintf(" IP events: %10ld\n", total); - dprintf(" mmap events: %10ld\n", total_mmap); - dprintf(" comm events: %10ld\n", total_comm); - dprintf(" fork events: %10ld\n", total_fork); - dprintf(" lost events: %10ld\n", total_lost); - dprintf(" unknown events: %10ld\n", total_unknown); + dump_printf(" IP events: %10ld\n", total); + dump_printf(" mmap events: %10ld\n", total_mmap); + dump_printf(" comm events: %10ld\n", total_comm); + dump_printf(" fork events: %10ld\n", total_fork); + dump_printf(" lost events: %10ld\n", total_lost); + dump_printf(" unknown events: %10ld\n", total_unknown); if (dump_trace) return 0; diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 7cb8464..8318fdee 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -6,6 +6,7 @@ #include int verbose = 0; +int dump_trace = 0; int eprintf(const char *fmt, ...) { @@ -20,3 +21,17 @@ int eprintf(const char *fmt, ...) return ret; } + +int dump_printf(const char *fmt, ...) +{ + va_list args; + int ret = 0; + + if (dump_trace) { + va_start(args, fmt); + ret = vprintf(fmt, args); + va_end(args); + } + + return ret; +} diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 2ae9090..a683bd5 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -1,5 +1,7 @@ /* For debugging general purposes */ extern int verbose; +extern int dump_trace; int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); -- cgit v0.10.2 From 0f25bfc8d8b31a4ac8e4ff6cbc3911fb7092a4a7 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 16 Aug 2009 19:56:54 +0200 Subject: perf tools: Put the show mode into the event headers files Annotate and report share the same flags to filter events considering their context (kernel, user, hypervisor). Both tools have their own definitions of these flags. Factorize them out into the event headers file. Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1250445414-29237-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 820e7cc..6d75151 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -22,10 +22,6 @@ #include "util/parse-events.h" #include "util/thread.h" -#define SHOW_KERNEL 1 -#define SHOW_USER 2 -#define SHOW_HV 4 - static char const *input_name = "perf.data"; static char default_sort_order[] = "comm,symbol"; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index e104ed3..05d52ff 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -27,10 +27,6 @@ #include "util/thread.h" -#define SHOW_KERNEL 1 -#define SHOW_USER 2 -#define SHOW_HV 4 - static char const *input_name = "perf.data"; static char default_sort_order[] = "comm,dso,symbol"; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index fa7c50b..fa2d4e9 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -4,6 +4,12 @@ #include "util.h" #include +enum { + SHOW_KERNEL = 1, + SHOW_USER = 2, + SHOW_HV = 4, +}; + /* * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * */ -- cgit v0.10.2 From 0d3a5c885971de1e3124d85bfadf818abac9ba12 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 16 Aug 2009 20:56:37 +0200 Subject: perf tools: Librarize sample type and attr finding from headers Librarize the sample type and attr fetching from perf data file headers so that we can also use it from perf trace. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1250448997-30715-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 05d52ff..c6326de 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -70,6 +70,8 @@ static int cwdlen; static struct rb_root threads; static struct thread *last_match; +static struct perf_header *header; + static struct callchain_param callchain_param = { .mode = CHAIN_GRAPH_REL, @@ -1319,29 +1321,12 @@ static void trace_event(event_t *event) dump_printf(".\n"); } -static struct perf_header *header; - -static struct perf_counter_attr *perf_header__find_attr(u64 id) -{ - int i; - - for (i = 0; i < header->attrs; i++) { - struct perf_header_attr *attr = header->attr[i]; - int j; - - for (j = 0; j < attr->ids; j++) { - if (attr->id[j] == id) - return &attr->attr; - } - } - - return NULL; -} - static int process_read_event(event_t *event, unsigned long offset, unsigned long head) { - struct perf_counter_attr *attr = perf_header__find_attr(event->read.id); + struct perf_counter_attr *attr; + + attr = perf_header__find_attr(event->read.id, header); if (show_threads) { const char *name = attr ? __event_name(attr->type, attr->config) @@ -1405,23 +1390,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head) return 0; } -static u64 perf_header__sample_type(void) -{ - u64 type = 0; - int i; - - for (i = 0; i < header->attrs; i++) { - struct perf_header_attr *attr = header->attr[i]; - - if (!type) - type = attr->attr.sample_type; - else if (type != attr->attr.sample_type) - die("non matching sample_type"); - } - - return type; -} - static int __cmd_report(void) { int ret, rc = EXIT_FAILURE; @@ -1460,7 +1428,7 @@ static int __cmd_report(void) header = perf_header__read(input); head = header->data_offset; - sample_type = perf_header__sample_type(); + sample_type = perf_header__sample_type(header); if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) { if (sort__has_parent) { diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b92a457..a37a222 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -243,3 +243,38 @@ struct perf_header *perf_header__read(int fd) return self; } + +u64 perf_header__sample_type(struct perf_header *header) +{ + u64 type = 0; + int i; + + for (i = 0; i < header->attrs; i++) { + struct perf_header_attr *attr = header->attr[i]; + + if (!type) + type = attr->attr.sample_type; + else if (type != attr->attr.sample_type) + die("non matching sample_type"); + } + + return type; +} + +struct perf_counter_attr * +perf_header__find_attr(u64 id, struct perf_header *header) +{ + int i; + + for (i = 0; i < header->attrs; i++) { + struct perf_header_attr *attr = header->attr[i]; + int j; + + for (j = 0; j < attr->ids; j++) { + if (attr->id[j] == id) + return &attr->attr; + } + } + + return NULL; +} diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index bf28044..5d0a72e 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -31,6 +31,10 @@ struct perf_header_attr * perf_header_attr__new(struct perf_counter_attr *attr); void perf_header_attr__add_id(struct perf_header_attr *self, u64 id); +u64 perf_header__sample_type(struct perf_header *header); +struct perf_counter_attr * +perf_header__find_attr(u64 id, struct perf_header *header); + struct perf_header *perf_header__new(void); -- cgit v0.10.2 From 8f28827a162fd1e8da4e96bed69b06d2606e8322 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 16 Aug 2009 22:05:48 +0200 Subject: perf tools: Librarize trace_event() helper Librarize trace_event() helper so that perf trace can use it too. Also clean up the debug.h includes a bit. It's not good to have it included in perf.h because it doesn't make it flexible against other headers it may need (headers that can also depend on perf.h and then create a recursive header dependency). Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1250453149-664-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 6d75151..96d421f 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -17,6 +17,7 @@ #include "util/string.h" #include "perf.h" +#include "util/debug.h" #include "util/parse-options.h" #include "util/parse-events.h" diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 65b4115..6a5db675e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -16,6 +16,7 @@ #include "util/header.h" #include "util/event.h" +#include "util/debug.h" #include #include diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index c6326de..1e3ad22 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -20,6 +20,7 @@ #include "util/values.h" #include "perf.h" +#include "util/debug.h" #include "util/header.h" #include "util/parse-options.h" @@ -39,8 +40,6 @@ static char *field_sep; static int input; static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; -#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0) - static int full_paths; static int show_nr_samples; @@ -1285,42 +1284,6 @@ process_lost_event(event_t *event, unsigned long offset, unsigned long head) return 0; } -static void trace_event(event_t *event) -{ - unsigned char *raw_event = (void *)event; - const char *color = PERF_COLOR_BLUE; - int i, j; - - if (!dump_trace) - return; - - dump_printf("."); - cdprintf("\n. ... raw event: size %d bytes\n", event->header.size); - - for (i = 0; i < event->header.size; i++) { - if ((i & 15) == 0) { - dump_printf("."); - cdprintf(" %04x: ", i); - } - - cdprintf(" %02x", raw_event[i]); - - if (((i & 15) == 15) || i == event->header.size-1) { - cdprintf(" "); - for (j = 0; j < 15-(i & 15); j++) - cdprintf(" "); - for (j = 0; j < (i & 15); j++) { - if (isprint(raw_event[i-15+j])) - cdprintf("%c", raw_event[i-15+j]); - else - cdprintf("."); - } - cdprintf("\n"); - } - } - dump_printf(".\n"); -} - static int process_read_event(event_t *event, unsigned long offset, unsigned long head) { diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 4b9dd4a..1a26262 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -42,6 +42,8 @@ #include "util/util.h" #include "util/parse-options.h" #include "util/parse-events.h" +#include "util/event.h" +#include "util/debug.h" #include #include diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 06f763e..62b55ec 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -27,6 +27,8 @@ #include "util/parse-options.h" #include "util/parse-events.h" +#include "util/debug.h" + #include #include diff --git a/tools/perf/perf.h b/tools/perf/perf.h index f550921..e5148e2 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -48,7 +48,6 @@ #include "../../include/linux/perf_counter.h" #include "util/types.h" -#include "util/debug.h" /* * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index e47fdeb..e88bca5 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c @@ -166,7 +166,7 @@ int perf_color_default_config(const char *var, const char *value, void *cb) return perf_default_config(var, value, cb); } -static int color_vfprintf(FILE *fp, const char *color, const char *fmt, +static int __color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args, const char *trail) { int r = 0; @@ -191,6 +191,10 @@ static int color_vfprintf(FILE *fp, const char *color, const char *fmt, return r; } +int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args) +{ + return __color_vfprintf(fp, color, fmt, args, NULL); +} int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) @@ -199,7 +203,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) int r; va_start(args, fmt); - r = color_vfprintf(fp, color, fmt, args, NULL); + r = color_vfprintf(fp, color, fmt, args); va_end(args); return r; } @@ -209,7 +213,7 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...) va_list args; int r; va_start(args, fmt); - r = color_vfprintf(fp, color, fmt, args, "\n"); + r = __color_vfprintf(fp, color, fmt, args, "\n"); va_end(args); return r; } diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h index 43d0d1b..58d5975 100644 --- a/tools/perf/util/color.h +++ b/tools/perf/util/color.h @@ -32,6 +32,7 @@ int perf_color_default_config(const char *var, const char *value, void *cb); int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); void color_parse(const char *value, const char *var, char *dst); void color_parse_mem(const char *value, int len, const char *var, char *dst); +int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args); int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 8318fdee..e8ca98f 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -1,10 +1,15 @@ /* For general debugging purposes */ #include "../perf.h" + #include #include #include +#include "color.h" +#include "event.h" +#include "debug.h" + int verbose = 0; int dump_trace = 0; @@ -35,3 +40,56 @@ int dump_printf(const char *fmt, ...) return ret; } + +static int dump_printf_color(const char *fmt, const char *color, ...) +{ + va_list args; + int ret = 0; + + if (dump_trace) { + va_start(args, color); + ret = color_vfprintf(stdout, color, fmt, args); + va_end(args); + } + + return ret; +} + + +void trace_event(event_t *event) +{ + unsigned char *raw_event = (void *)event; + const char *color = PERF_COLOR_BLUE; + int i, j; + + if (!dump_trace) + return; + + dump_printf("."); + dump_printf_color("\n. ... raw event: size %d bytes\n", color, + event->header.size); + + for (i = 0; i < event->header.size; i++) { + if ((i & 15) == 0) { + dump_printf("."); + dump_printf_color(" %04x: ", color, i); + } + + dump_printf_color(" %02x", color, raw_event[i]); + + if (((i & 15) == 15) || i == event->header.size-1) { + dump_printf_color(" ", color); + for (j = 0; j < 15-(i & 15); j++) + dump_printf_color(" ", color); + for (j = 0; j < (i & 15); j++) { + if (isprint(raw_event[i-15+j])) + dump_printf_color("%c", color, + raw_event[i-15+j]); + else + dump_printf_color(".", color); + } + dump_printf_color("\n", color); + } + } + dump_printf(".\n"); +} diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index a683bd5..437eea5 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -5,3 +5,4 @@ extern int dump_trace; int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +void trace_event(event_t *event); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 3159d47..fd3d9c8 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -3,6 +3,8 @@ #include "string.h" #include "symbol.h" +#include "debug.h" + #include #include #include -- cgit v0.10.2 From 2bf49690325b62480a42f7afed5e9f164173c570 Mon Sep 17 00:00:00 2001 From: Thomas Liu Date: Tue, 14 Jul 2009 12:14:09 -0400 Subject: SELinux: Convert avc_audit to use lsm_audit.h Convert avc_audit in security/selinux/avc.c to use lsm_audit.h, for better maintainability. - changed selinux to use common_audit_data instead of avc_audit_data - eliminated code in avc.c and used code from lsm_audit.h instead. Had to add a LSM_AUDIT_NO_AUDIT to lsm_audit.h so that avc_audit can call common_lsm_audit and do the pre and post callbacks without doing the actual dump. This makes it so that the patched version behaves the same way as the unpatched version. Also added a denied field to the selinux_audit_data private space, once again to make it so that the patched version behaves like the unpatched. I've tested and confirmed that AVCs look the same before and after this patch. Signed-off-by: Thomas Liu Acked-by: Stephen Smalley Signed-off-by: James Morris diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index a5514a3..190c378 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -33,6 +33,7 @@ struct common_audit_data { #define LSM_AUDIT_DATA_IPC 4 #define LSM_AUDIT_DATA_TASK 5 #define LSM_AUDIT_DATA_KEY 6 +#define LSM_AUDIT_NO_AUDIT 7 struct task_struct *tsk; union { struct { @@ -86,6 +87,7 @@ struct common_audit_data { u16 tclass; u32 requested; u32 audited; + u32 denied; struct av_decision *avd; int result; } selinux_audit_data; diff --git a/security/Makefile b/security/Makefile index b56e7f9..95ecc06 100644 --- a/security/Makefile +++ b/security/Makefile @@ -16,9 +16,7 @@ obj-$(CONFIG_SECURITYFS) += inode.o # Must precede capability.o in order to stack properly. obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o -ifeq ($(CONFIG_AUDIT),y) -obj-$(CONFIG_SECURITY_SMACK) += lsm_audit.o -endif +obj-$(CONFIG_AUDIT) += lsm_audit.o obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 94b8684..500aad0 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -220,6 +220,8 @@ static void dump_common_audit_data(struct audit_buffer *ab, } switch (a->type) { + case LSM_AUDIT_NO_AUDIT: + return; case LSM_AUDIT_DATA_IPC: audit_log_format(ab, " key=%d ", a->u.ipc_id); break; diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 236aaa2..e3d1901 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -492,23 +492,35 @@ out: return node; } -static inline void avc_print_ipv6_addr(struct audit_buffer *ab, - struct in6_addr *addr, __be16 port, - char *name1, char *name2) +/** + * avc_audit_pre_callback - SELinux specific information + * will be called by generic audit code + * @ab: the audit buffer + * @a: audit_data + */ +static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) { - if (!ipv6_addr_any(addr)) - audit_log_format(ab, " %s=%pI6", name1, addr); - if (port) - audit_log_format(ab, " %s=%d", name2, ntohs(port)); + struct common_audit_data *ad = a; + audit_log_format(ab, "avc: %s ", + ad->selinux_audit_data.denied ? "denied" : "granted"); + avc_dump_av(ab, ad->selinux_audit_data.tclass, + ad->selinux_audit_data.audited); + audit_log_format(ab, " for "); } -static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, - __be16 port, char *name1, char *name2) +/** + * avc_audit_post_callback - SELinux specific information + * will be called by generic audit code + * @ab: the audit buffer + * @a: audit_data + */ +static void avc_audit_post_callback(struct audit_buffer *ab, void *a) { - if (addr) - audit_log_format(ab, " %s=%pI4", name1, &addr); - if (port) - audit_log_format(ab, " %s=%d", name2, ntohs(port)); + struct common_audit_data *ad = a; + audit_log_format(ab, " "); + avc_dump_query(ab, ad->selinux_audit_data.ssid, + ad->selinux_audit_data.tsid, + ad->selinux_audit_data.tclass); } /** @@ -532,13 +544,10 @@ static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, */ void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct av_decision *avd, int result, struct avc_audit_data *a) + struct av_decision *avd, int result, struct common_audit_data *a) { - struct task_struct *tsk = current; - struct inode *inode = NULL; + struct common_audit_data stack_data; u32 denied, audited; - struct audit_buffer *ab; - denied = requested & ~avd->allowed; if (denied) { audited = denied; @@ -551,144 +560,20 @@ void avc_audit(u32 ssid, u32 tsid, if (!(audited & avd->auditallow)) return; } - - ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); - if (!ab) - return; /* audit_panic has been called */ - audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); - avc_dump_av(ab, tclass, audited); - audit_log_format(ab, " for "); - if (a && a->tsk) - tsk = a->tsk; - if (tsk && tsk->pid) { - audit_log_format(ab, " pid=%d comm=", tsk->pid); - audit_log_untrustedstring(ab, tsk->comm); - } - if (a) { - switch (a->type) { - case AVC_AUDIT_DATA_IPC: - audit_log_format(ab, " key=%d", a->u.ipc_id); - break; - case AVC_AUDIT_DATA_CAP: - audit_log_format(ab, " capability=%d", a->u.cap); - break; - case AVC_AUDIT_DATA_FS: - if (a->u.fs.path.dentry) { - struct dentry *dentry = a->u.fs.path.dentry; - if (a->u.fs.path.mnt) { - audit_log_d_path(ab, "path=", - &a->u.fs.path); - } else { - audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, dentry->d_name.name); - } - inode = dentry->d_inode; - } else if (a->u.fs.inode) { - struct dentry *dentry; - inode = a->u.fs.inode; - dentry = d_find_alias(inode); - if (dentry) { - audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, dentry->d_name.name); - dput(dentry); - } - } - if (inode) - audit_log_format(ab, " dev=%s ino=%lu", - inode->i_sb->s_id, - inode->i_ino); - break; - case AVC_AUDIT_DATA_NET: - if (a->u.net.sk) { - struct sock *sk = a->u.net.sk; - struct unix_sock *u; - int len = 0; - char *p = NULL; - - switch (sk->sk_family) { - case AF_INET: { - struct inet_sock *inet = inet_sk(sk); - - avc_print_ipv4_addr(ab, inet->rcv_saddr, - inet->sport, - "laddr", "lport"); - avc_print_ipv4_addr(ab, inet->daddr, - inet->dport, - "faddr", "fport"); - break; - } - case AF_INET6: { - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *inet6 = inet6_sk(sk); - - avc_print_ipv6_addr(ab, &inet6->rcv_saddr, - inet->sport, - "laddr", "lport"); - avc_print_ipv6_addr(ab, &inet6->daddr, - inet->dport, - "faddr", "fport"); - break; - } - case AF_UNIX: - u = unix_sk(sk); - if (u->dentry) { - struct path path = { - .dentry = u->dentry, - .mnt = u->mnt - }; - audit_log_d_path(ab, "path=", - &path); - break; - } - if (!u->addr) - break; - len = u->addr->len-sizeof(short); - p = &u->addr->name->sun_path[0]; - audit_log_format(ab, " path="); - if (*p) - audit_log_untrustedstring(ab, p); - else - audit_log_n_hex(ab, p, len); - break; - } - } - - switch (a->u.net.family) { - case AF_INET: - avc_print_ipv4_addr(ab, a->u.net.v4info.saddr, - a->u.net.sport, - "saddr", "src"); - avc_print_ipv4_addr(ab, a->u.net.v4info.daddr, - a->u.net.dport, - "daddr", "dest"); - break; - case AF_INET6: - avc_print_ipv6_addr(ab, &a->u.net.v6info.saddr, - a->u.net.sport, - "saddr", "src"); - avc_print_ipv6_addr(ab, &a->u.net.v6info.daddr, - a->u.net.dport, - "daddr", "dest"); - break; - } - if (a->u.net.netif > 0) { - struct net_device *dev; - - /* NOTE: we always use init's namespace */ - dev = dev_get_by_index(&init_net, - a->u.net.netif); - if (dev) { - audit_log_format(ab, " netif=%s", - dev->name); - dev_put(dev); - } - } - break; - } + if (!a) { + a = &stack_data; + memset(a, 0, sizeof(*a)); + a->type = LSM_AUDIT_NO_AUDIT; } - audit_log_format(ab, " "); - avc_dump_query(ab, ssid, tsid, tclass); - audit_log_end(ab); + a->selinux_audit_data.tclass = tclass; + a->selinux_audit_data.requested = requested; + a->selinux_audit_data.ssid = ssid; + a->selinux_audit_data.tsid = tsid; + a->selinux_audit_data.audited = audited; + a->selinux_audit_data.denied = denied; + a->lsm_pre_audit = avc_audit_pre_callback; + a->lsm_post_audit = avc_audit_post_callback; + common_lsm_audit(a); } /** @@ -956,7 +841,7 @@ out: * another -errno upon other errors. */ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, - u32 requested, struct avc_audit_data *auditdata) + u32 requested, struct common_audit_data *auditdata) { struct av_decision avd; int rc; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5aa45b1..254b798 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1478,14 +1478,14 @@ static int task_has_capability(struct task_struct *tsk, const struct cred *cred, int cap, int audit) { - struct avc_audit_data ad; + struct common_audit_data ad; struct av_decision avd; u16 sclass; u32 sid = cred_sid(cred); u32 av = CAP_TO_MASK(cap); int rc; - AVC_AUDIT_DATA_INIT(&ad, CAP); + COMMON_AUDIT_DATA_INIT(&ad, CAP); ad.tsk = tsk; ad.u.cap = cap; @@ -1524,10 +1524,10 @@ static int task_has_system(struct task_struct *tsk, static int inode_has_perm(const struct cred *cred, struct inode *inode, u32 perms, - struct avc_audit_data *adp) + struct common_audit_data *adp) { struct inode_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid; if (unlikely(IS_PRIVATE(inode))) @@ -1538,7 +1538,7 @@ static int inode_has_perm(const struct cred *cred, if (!adp) { adp = &ad; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.inode = inode; } @@ -1554,9 +1554,9 @@ static inline int dentry_has_perm(const struct cred *cred, u32 av) { struct inode *inode = dentry->d_inode; - struct avc_audit_data ad; + struct common_audit_data ad; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.mnt = mnt; ad.u.fs.path.dentry = dentry; return inode_has_perm(cred, inode, av, &ad); @@ -1576,11 +1576,11 @@ static int file_has_perm(const struct cred *cred, { struct file_security_struct *fsec = file->f_security; struct inode *inode = file->f_path.dentry->d_inode; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = cred_sid(cred); int rc; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path = file->f_path; if (sid != fsec->sid) { @@ -1611,7 +1611,7 @@ static int may_create(struct inode *dir, struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; u32 sid, newsid; - struct avc_audit_data ad; + struct common_audit_data ad; int rc; dsec = dir->i_security; @@ -1620,7 +1620,7 @@ static int may_create(struct inode *dir, sid = tsec->sid; newsid = tsec->create_sid; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, @@ -1664,7 +1664,7 @@ static int may_link(struct inode *dir, { struct inode_security_struct *dsec, *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); u32 av; int rc; @@ -1672,7 +1672,7 @@ static int may_link(struct inode *dir, dsec = dir->i_security; isec = dentry->d_inode->i_security; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; av = DIR__SEARCH; @@ -1707,7 +1707,7 @@ static inline int may_rename(struct inode *old_dir, struct dentry *new_dentry) { struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); u32 av; int old_is_dir, new_is_dir; @@ -1718,7 +1718,7 @@ static inline int may_rename(struct inode *old_dir, old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); new_dsec = new_dir->i_security; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = old_dentry; rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, @@ -1760,7 +1760,7 @@ static inline int may_rename(struct inode *old_dir, static int superblock_has_perm(const struct cred *cred, struct super_block *sb, u32 perms, - struct avc_audit_data *ad) + struct common_audit_data *ad) { struct superblock_security_struct *sbsec; u32 sid = cred_sid(cred); @@ -2100,7 +2100,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) const struct task_security_struct *old_tsec; struct task_security_struct *new_tsec; struct inode_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; struct inode *inode = bprm->file->f_path.dentry->d_inode; int rc; @@ -2138,7 +2138,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) return rc; } - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path = bprm->file->f_path; if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) @@ -2231,7 +2231,7 @@ extern struct dentry *selinux_null; static inline void flush_unauthorized_files(const struct cred *cred, struct files_struct *files) { - struct avc_audit_data ad; + struct common_audit_data ad; struct file *file, *devnull = NULL; struct tty_struct *tty; struct fdtable *fdt; @@ -2265,7 +2265,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, /* Revalidate access to inherited open files. */ - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); spin_lock(&files->file_lock); for (;;) { @@ -2514,7 +2514,7 @@ out: static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) { const struct cred *cred = current_cred(); - struct avc_audit_data ad; + struct common_audit_data ad; int rc; rc = superblock_doinit(sb, data); @@ -2525,7 +2525,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) if (flags & MS_KERNMOUNT) return 0; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = sb->s_root; return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); } @@ -2533,9 +2533,9 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) static int selinux_sb_statfs(struct dentry *dentry) { const struct cred *cred = current_cred(); - struct avc_audit_data ad; + struct common_audit_data ad; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry->d_sb->s_root; return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); } @@ -2755,7 +2755,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, struct inode *inode = dentry->d_inode; struct inode_security_struct *isec = inode->i_security; struct superblock_security_struct *sbsec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 newsid, sid = current_sid(); int rc = 0; @@ -2769,7 +2769,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, if (!is_owner_or_cap(inode)) return -EPERM; - AVC_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; rc = avc_has_perm(sid, isec->sid, isec->sclass, @@ -3418,7 +3418,7 @@ static void selinux_task_to_inode(struct task_struct *p, /* Returns error only if unable to parse addresses */ static int selinux_parse_skb_ipv4(struct sk_buff *skb, - struct avc_audit_data *ad, u8 *proto) + struct common_audit_data *ad, u8 *proto) { int offset, ihlen, ret = -EINVAL; struct iphdr _iph, *ih; @@ -3499,7 +3499,7 @@ out: /* Returns error only if unable to parse addresses */ static int selinux_parse_skb_ipv6(struct sk_buff *skb, - struct avc_audit_data *ad, u8 *proto) + struct common_audit_data *ad, u8 *proto) { u8 nexthdr; int ret = -EINVAL, offset; @@ -3570,7 +3570,7 @@ out: #endif /* IPV6 */ -static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, +static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad, char **_addrp, int src, u8 *proto) { char *addrp; @@ -3652,7 +3652,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, u32 perms) { struct inode_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid; int err = 0; @@ -3662,7 +3662,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, goto out; sid = task_sid(task); - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = sock->sk; err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); @@ -3749,7 +3749,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in if (family == PF_INET || family == PF_INET6) { char *addrp; struct inode_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; struct sockaddr_in *addr4 = NULL; struct sockaddr_in6 *addr6 = NULL; unsigned short snum; @@ -3778,7 +3778,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in snum, &sid); if (err) goto out; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sport = htons(snum); ad.u.net.family = family; err = avc_has_perm(isec->sid, sid, @@ -3811,7 +3811,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in if (err) goto out; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sport = htons(snum); ad.u.net.family = family; @@ -3845,7 +3845,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, isec = SOCK_INODE(sock)->i_security; if (isec->sclass == SECCLASS_TCP_SOCKET || isec->sclass == SECCLASS_DCCP_SOCKET) { - struct avc_audit_data ad; + struct common_audit_data ad; struct sockaddr_in *addr4 = NULL; struct sockaddr_in6 *addr6 = NULL; unsigned short snum; @@ -3870,7 +3870,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, perm = (isec->sclass == SECCLASS_TCP_SOCKET) ? TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.dport = htons(snum); ad.u.net.family = sk->sk_family; err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad); @@ -3960,13 +3960,13 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, struct sk_security_struct *ssec; struct inode_security_struct *isec; struct inode_security_struct *other_isec; - struct avc_audit_data ad; + struct common_audit_data ad; int err; isec = SOCK_INODE(sock)->i_security; other_isec = SOCK_INODE(other)->i_security; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = other->sk; err = avc_has_perm(isec->sid, other_isec->sid, @@ -3992,13 +3992,13 @@ static int selinux_socket_unix_may_send(struct socket *sock, { struct inode_security_struct *isec; struct inode_security_struct *other_isec; - struct avc_audit_data ad; + struct common_audit_data ad; int err; isec = SOCK_INODE(sock)->i_security; other_isec = SOCK_INODE(other)->i_security; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = other->sk; err = avc_has_perm(isec->sid, other_isec->sid, @@ -4011,7 +4011,7 @@ static int selinux_socket_unix_may_send(struct socket *sock, static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, u32 peer_sid, - struct avc_audit_data *ad) + struct common_audit_data *ad) { int err; u32 if_sid; @@ -4039,10 +4039,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, struct sk_security_struct *sksec = sk->sk_security; u32 peer_sid; u32 sk_sid = sksec->sid; - struct avc_audit_data ad; + struct common_audit_data ad; char *addrp; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = skb->iif; ad.u.net.family = family; err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); @@ -4080,7 +4080,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) struct sk_security_struct *sksec = sk->sk_security; u16 family = sk->sk_family; u32 sk_sid = sksec->sid; - struct avc_audit_data ad; + struct common_audit_data ad; char *addrp; u8 secmark_active; u8 peerlbl_active; @@ -4104,7 +4104,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) if (!secmark_active && !peerlbl_active) return 0; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = skb->iif; ad.u.net.family = family; err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); @@ -4362,7 +4362,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, int err; char *addrp; u32 peer_sid; - struct avc_audit_data ad; + struct common_audit_data ad; u8 secmark_active; u8 netlbl_active; u8 peerlbl_active; @@ -4379,7 +4379,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) return NF_DROP; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = ifindex; ad.u.net.family = family; if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) @@ -4467,7 +4467,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, { struct sock *sk = skb->sk; struct sk_security_struct *sksec; - struct avc_audit_data ad; + struct common_audit_data ad; char *addrp; u8 proto; @@ -4475,7 +4475,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, return NF_ACCEPT; sksec = sk->sk_security; - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = ifindex; ad.u.net.family = family; if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) @@ -4499,7 +4499,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, u32 secmark_perm; u32 peer_sid; struct sock *sk; - struct avc_audit_data ad; + struct common_audit_data ad; char *addrp; u8 secmark_active; u8 peerlbl_active; @@ -4558,7 +4558,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, secmark_perm = PACKET__SEND; } - AVC_AUDIT_DATA_INIT(&ad, NET); + COMMON_AUDIT_DATA_INIT(&ad, NET); ad.u.net.netif = ifindex; ad.u.net.family = family; if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) @@ -4628,13 +4628,13 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) static int selinux_netlink_recv(struct sk_buff *skb, int capability) { int err; - struct avc_audit_data ad; + struct common_audit_data ad; err = cap_netlink_recv(skb, capability); if (err) return err; - AVC_AUDIT_DATA_INIT(&ad, CAP); + COMMON_AUDIT_DATA_INIT(&ad, CAP); ad.u.cap = capability; return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, @@ -4693,12 +4693,12 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, u32 perms) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); isec = ipc_perms->security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = ipc_perms->key; return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); @@ -4718,7 +4718,7 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg) static int selinux_msg_queue_alloc_security(struct msg_queue *msq) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); int rc; @@ -4728,7 +4728,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) isec = msq->q_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, @@ -4748,12 +4748,12 @@ static void selinux_msg_queue_free_security(struct msg_queue *msq) static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); isec = msq->q_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, @@ -4792,7 +4792,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, { struct ipc_security_struct *isec; struct msg_security_struct *msec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); int rc; @@ -4813,7 +4813,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, return rc; } - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; /* Can this process write to the queue? */ @@ -4837,14 +4837,14 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, { struct ipc_security_struct *isec; struct msg_security_struct *msec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = task_sid(target); int rc; isec = msq->q_perm.security; msec = msg->security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; rc = avc_has_perm(sid, isec->sid, @@ -4859,7 +4859,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, static int selinux_shm_alloc_security(struct shmid_kernel *shp) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); int rc; @@ -4869,7 +4869,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) isec = shp->shm_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = shp->shm_perm.key; rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, @@ -4889,12 +4889,12 @@ static void selinux_shm_free_security(struct shmid_kernel *shp) static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); isec = shp->shm_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = shp->shm_perm.key; return avc_has_perm(sid, isec->sid, SECCLASS_SHM, @@ -4951,7 +4951,7 @@ static int selinux_shm_shmat(struct shmid_kernel *shp, static int selinux_sem_alloc_security(struct sem_array *sma) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); int rc; @@ -4961,7 +4961,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) isec = sma->sem_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = sma->sem_perm.key; rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, @@ -4981,12 +4981,12 @@ static void selinux_sem_free_security(struct sem_array *sma) static int selinux_sem_associate(struct sem_array *sma, int semflg) { struct ipc_security_struct *isec; - struct avc_audit_data ad; + struct common_audit_data ad; u32 sid = current_sid(); isec = sma->sem_perm.security; - AVC_AUDIT_DATA_INIT(&ad, IPC); + COMMON_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = sma->sem_perm.key; return avc_has_perm(sid, isec->sid, SECCLASS_SEM, diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index ae4c3a0..e94e82f 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -36,48 +37,6 @@ struct inode; struct sock; struct sk_buff; -/* Auxiliary data to use in generating the audit record. */ -struct avc_audit_data { - char type; -#define AVC_AUDIT_DATA_FS 1 -#define AVC_AUDIT_DATA_NET 2 -#define AVC_AUDIT_DATA_CAP 3 -#define AVC_AUDIT_DATA_IPC 4 - struct task_struct *tsk; - union { - struct { - struct path path; - struct inode *inode; - } fs; - struct { - int netif; - struct sock *sk; - u16 family; - __be16 dport; - __be16 sport; - union { - struct { - __be32 daddr; - __be32 saddr; - } v4; - struct { - struct in6_addr daddr; - struct in6_addr saddr; - } v6; - } fam; - } net; - int cap; - int ipc_id; - } u; -}; - -#define v4info fam.v4 -#define v6info fam.v6 - -/* Initialize an AVC audit data structure. */ -#define AVC_AUDIT_DATA_INIT(_d,_t) \ - { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; } - /* * AVC statistics */ @@ -98,7 +57,9 @@ void __init avc_init(void); void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct av_decision *avd, int result, struct avc_audit_data *auditdata); + struct av_decision *avd, + int result, + struct common_audit_data *a); #define AVC_STRICT 1 /* Ignore permissive mode. */ int avc_has_perm_noaudit(u32 ssid, u32 tsid, @@ -108,7 +69,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct avc_audit_data *auditdata); + struct common_audit_data *auditdata); u32 avc_policy_seqno(void); diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index b4b5b9b..8d73842 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h @@ -59,7 +59,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, struct sk_buff *skb, u16 family, - struct avc_audit_data *ad); + struct common_audit_data *ad); int selinux_netlbl_socket_setsockopt(struct socket *sock, int level, int optname); @@ -129,7 +129,7 @@ static inline int selinux_netlbl_socket_post_create(struct sock *sk, static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, struct sk_buff *skb, u16 family, - struct avc_audit_data *ad) + struct common_audit_data *ad) { return 0; } diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 289e24b..13128f9 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -41,9 +41,9 @@ static inline int selinux_xfrm_enabled(void) } int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, - struct avc_audit_data *ad); + struct common_audit_data *ad); int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad, u8 proto); + struct common_audit_data *ad, u8 proto); int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); static inline void selinux_xfrm_notify_policyload(void) @@ -57,13 +57,13 @@ static inline int selinux_xfrm_enabled(void) } static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad) + struct common_audit_data *ad) { return 0; } static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad, u8 proto) + struct common_audit_data *ad, u8 proto) { return 0; } diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 2e98441..e688237 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -342,7 +342,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family) int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, struct sk_buff *skb, u16 family, - struct avc_audit_data *ad) + struct common_audit_data *ad) { int rc; u32 nlbl_sid; diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 72b1845..f3cb9ed 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -401,7 +401,7 @@ int selinux_xfrm_state_delete(struct xfrm_state *x) * gone thru the IPSec process. */ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad) + struct common_audit_data *ad) { int i, rc = 0; struct sec_path *sp; @@ -442,7 +442,7 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, * checked in the selinux_xfrm_state_pol_flow_match hook above. */ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, - struct avc_audit_data *ad, u8 proto) + struct common_audit_data *ad, u8 proto) { struct dst_entry *dst; int rc = 0; -- cgit v0.10.2 From 48e46b7b311c54525712c28004f0a59f2c931d30 Mon Sep 17 00:00:00 2001 From: Jurij Smakov Date: Sun, 16 Aug 2009 18:21:47 -0700 Subject: sparc64: build compressed image (zImage) by default Besides creating the uncompressed vmlinux image for sparc64, also create a compressed zImage. This is more consistent with other architectures and required to make the 'deb-pkg' target work. Signed-off-by: Jurij Smakov Signed-off-by: Frans Pop Signed-off-by: David S. Miller diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index 2003ded..467221d 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -38,10 +38,6 @@ CPPFLAGS_vmlinux.lds += -m32 # Actual linking is done with "make image". LDFLAGS_vmlinux = -r -# Default target -all: zImage - - else ##### # sparc64 @@ -91,6 +87,9 @@ endif boot := arch/sparc/boot +# Default target +all: zImage + image zImage tftpboot.img vmlinux.aout: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ @@ -109,8 +108,9 @@ define archhelp endef else define archhelp - echo '* vmlinux - Standard sparc64 kernel' - echo ' vmlinux.aout - a.out kernel for sparc64' + echo '* vmlinux - standard sparc64 kernel' + echo '* zImage - stripped and compressed sparc64 kernel ($(boot)/zImage)' + echo ' vmlinux.aout - a.out kernel for sparc64' echo ' tftpboot.img - image prepared for tftp' endef endif diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile index 1ff0fd9..97e3feb 100644 --- a/arch/sparc/boot/Makefile +++ b/arch/sparc/boot/Makefile @@ -79,6 +79,9 @@ $(obj)/image: vmlinux FORCE $(call if_changed,strip) @echo ' kernel: $@ is ready' +$(obj)/zImage: $(obj)/image + $(call if_changed,gzip) + $(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback_64 System.map $(ROOT_IMG) FORCE $(call if_changed,elftoaout) $(call if_changed,piggy) -- cgit v0.10.2 From 3f389635102e0dd2f85ebfe7fd549942b5bbc33b Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Wed, 12 Aug 2009 22:49:47 +0000 Subject: SPARC: fix duplicate declaration Only difference for 32 and 64 bit version is dma64_addr_t and rest is same. Also fixed the following 'make includecheck' warning: arch/sparc/include/asm/types.h: asm-generic/int-ll64.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/types.h b/arch/sparc/include/asm/types.h index de671d7..09c79a9 100644 --- a/arch/sparc/include/asm/types.h +++ b/arch/sparc/include/asm/types.h @@ -8,9 +8,8 @@ * need to be careful to avoid a name clashes. */ -#if defined(__sparc__) && defined(__arch64__) +#if defined(__sparc__) -/*** SPARC 64 bit ***/ #include #ifndef __ASSEMBLY__ @@ -26,33 +25,21 @@ typedef unsigned short umode_t; /* Dma addresses come in generic and 64-bit flavours. */ typedef u32 dma_addr_t; -typedef u64 dma64_addr_t; -#endif /* __ASSEMBLY__ */ +#if defined(__arch64__) -#endif /* __KERNEL__ */ +/*** SPARC 64 bit ***/ +typedef u64 dma64_addr_t; #else - /*** SPARC 32 bit ***/ -#include - -#ifndef __ASSEMBLY__ - -typedef unsigned short umode_t; - -#endif /* __ASSEMBLY__ */ - -#ifdef __KERNEL__ - -#ifndef __ASSEMBLY__ - -typedef u32 dma_addr_t; typedef u32 dma64_addr_t; +#endif /* defined(__arch64__) */ + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ -#endif /* defined(__sparc__) && defined(__arch64__) */ +#endif /* defined(__sparc__) */ #endif /* defined(_SPARC_TYPES_H) */ -- cgit v0.10.2 From 8abf9196008a7f06841b10769d1aed3f28c1d314 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 13 Aug 2009 10:05:43 +0000 Subject: sparc64: cheaper asm/uaccess.h inclusion sched.h inclusion is definitely not needed like in 32-bit version, remove it, fixup compilation. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h index a38c032..9ea271e 100644 --- a/arch/sparc/include/asm/uaccess_64.h +++ b/arch/sparc/include/asm/uaccess_64.h @@ -7,8 +7,8 @@ #ifdef __KERNEL__ #include -#include #include +#include #include #include #include diff --git a/arch/sparc/kernel/sysfs.c b/arch/sparc/kernel/sysfs.c index d28f496..ca39c60 100644 --- a/arch/sparc/kernel/sysfs.c +++ b/arch/sparc/kernel/sysfs.c @@ -2,6 +2,7 @@ * * Copyright (C) 2007 David S. Miller */ +#include #include #include #include diff --git a/samples/kprobes/kretprobe_example.c b/samples/kprobes/kretprobe_example.c index 4e764b3..1041b67 100644 --- a/samples/kprobes/kretprobe_example.c +++ b/samples/kprobes/kretprobe_example.c @@ -23,6 +23,7 @@ #include #include #include +#include static char func_name[NAME_MAX] = "do_fork"; module_param_string(func, func_name, NAME_MAX, S_IRUGO); -- cgit v0.10.2 From 212274347fc4d2a7c56bf6c953b02c809e7e0be1 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 17 Aug 2009 13:39:33 +0800 Subject: lockdep: Fix missing entry in /proc/lock_stat One entry is missing in the output of /proc/lock_stat. The cause is, when ls_start() is called the 2nd time, we should start from stats[@pos-1] but not stats[@pos], because pos == 0 is the header. Signed-off-by: Li Zefan Cc: Peter Zijlstra LKML-Reference: <4A88ED15.20800@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index fba81f1..5dbe30b 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c @@ -634,7 +634,7 @@ static void *ls_start(struct seq_file *m, loff_t *pos) if (*pos == 0) return SEQ_START_TOKEN; - data->iter = data->stats + *pos; + data->iter = data->stats + (*pos - 1); if (data->iter >= data->iter_end) data->iter = NULL; -- cgit v0.10.2 From e9d65725bdf5954283625ca4d770bfc34f2ae56a Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 17 Aug 2009 13:39:49 +0800 Subject: lockdep: Fix missing entries in /proc/lock_chains Two entries are missing in the output of /proc/lock_chains. One is chains[1]. When lc_next() is called the 1st time, chains[0] is returned. And when it's called the 2nd time, chains[2] is returned. The other missing ons is, when lc_start() is called the 2nd time, we should start from chains[@pos-1] but not chains[@pos], because pos == 0 is the header. Signed-off-by: Li Zefan Cc: Peter Zijlstra LKML-Reference: <4A88ED25.2040306@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index 5dbe30b..9a7996e 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c @@ -160,8 +160,8 @@ static void *lc_next(struct seq_file *m, void *v, loff_t *pos) else { chain = v; - if (*pos < nr_lock_chains) - chain = lock_chains + *pos; + if (*pos - 1 < nr_lock_chains) + chain = lock_chains + (*pos - 1); else chain = NULL; } @@ -174,8 +174,8 @@ static void *lc_start(struct seq_file *m, loff_t *pos) if (*pos == 0) return SEQ_START_TOKEN; - if (*pos < nr_lock_chains) - return lock_chains + *pos; + if (*pos - 1 < nr_lock_chains) + return lock_chains + (*pos - 1); return NULL; } -- cgit v0.10.2 From 8109e1de8502421f9efff1359f2779b1adcc0724 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 17 Aug 2009 13:40:17 +0800 Subject: lockdep: Simplify lockdep seqfile code Use seq_list_start_head() and seq_list_next(). Signed-off-by: Li Zefan Cc: Peter Zijlstra LKML-Reference: <4A88ED41.5000000@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index 9a7996e..05fb5fd 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c @@ -25,38 +25,12 @@ static void *l_next(struct seq_file *m, void *v, loff_t *pos) { - struct lock_class *class; - - (*pos)++; - - if (v == SEQ_START_TOKEN) - class = m->private; - else { - class = v; - - if (class->lock_entry.next != &all_lock_classes) - class = list_entry(class->lock_entry.next, - struct lock_class, lock_entry); - else - class = NULL; - } - - return class; + return seq_list_next(v, &all_lock_classes, pos); } static void *l_start(struct seq_file *m, loff_t *pos) { - struct lock_class *class; - loff_t i = 0; - - if (*pos == 0) - return SEQ_START_TOKEN; - - list_for_each_entry(class, &all_lock_classes, lock_entry) { - if (++i == *pos) - return class; - } - return NULL; + return seq_list_start_head(&all_lock_classes, *pos); } static void l_stop(struct seq_file *m, void *v) @@ -82,11 +56,11 @@ static void print_name(struct seq_file *m, struct lock_class *class) static int l_show(struct seq_file *m, void *v) { - struct lock_class *class = v; + struct lock_class *class = list_entry(v, struct lock_class, lock_entry); struct lock_list *entry; char usage[LOCK_USAGE_CHARS]; - if (v == SEQ_START_TOKEN) { + if (v == &all_lock_classes) { seq_printf(m, "all lock classes:\n"); return 0; } @@ -128,17 +102,7 @@ static const struct seq_operations lockdep_ops = { static int lockdep_open(struct inode *inode, struct file *file) { - int res = seq_open(file, &lockdep_ops); - if (!res) { - struct seq_file *m = file->private_data; - - if (!list_empty(&all_lock_classes)) - m->private = list_entry(all_lock_classes.next, - struct lock_class, lock_entry); - else - m->private = NULL; - } - return res; + return seq_open(file, &lockdep_ops); } static const struct file_operations proc_lockdep_operations = { -- cgit v0.10.2 From 12aac19d4ba41019a1748f49d3c5d259b1bfb26d Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 17 Aug 2009 13:40:39 +0800 Subject: lockdep: Simplify lockdep_chains seqfile code - make lc_next() call lc_start() - use lock_chains directly instead of storing it in m->private Signed-off-by: Li Zefan Cc: Peter Zijlstra LKML-Reference: <4A88ED57.5060609@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index 05fb5fd..2bbe25f 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c @@ -113,26 +113,6 @@ static const struct file_operations proc_lockdep_operations = { }; #ifdef CONFIG_PROVE_LOCKING -static void *lc_next(struct seq_file *m, void *v, loff_t *pos) -{ - struct lock_chain *chain; - - (*pos)++; - - if (v == SEQ_START_TOKEN) - chain = m->private; - else { - chain = v; - - if (*pos - 1 < nr_lock_chains) - chain = lock_chains + (*pos - 1); - else - chain = NULL; - } - - return chain; -} - static void *lc_start(struct seq_file *m, loff_t *pos) { if (*pos == 0) @@ -144,6 +124,12 @@ static void *lc_start(struct seq_file *m, loff_t *pos) return NULL; } +static void *lc_next(struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + return lc_start(m, pos); +} + static void lc_stop(struct seq_file *m, void *v) { } @@ -184,16 +170,7 @@ static const struct seq_operations lockdep_chains_ops = { static int lockdep_chains_open(struct inode *inode, struct file *file) { - int res = seq_open(file, &lockdep_chains_ops); - if (!res) { - struct seq_file *m = file->private_data; - - if (nr_lock_chains) - m->private = lock_chains; - else - m->private = NULL; - } - return res; + return seq_open(file, &lockdep_chains_ops); } static const struct file_operations proc_lockdep_chains_operations = { -- cgit v0.10.2 From 96004bb2a1e4ccad2b1eeb92e51031d1e8e609e3 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 17 Aug 2009 13:40:59 +0800 Subject: lockdep: Simplify lock_stat seqfile code - make ls_next() call ls_start() - remove redundant code in lock_stat_release() Signed-off-by: Li Zefan Cc: Peter Zijlstra LKML-Reference: <4A88ED6B.6030602@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index 2bbe25f..8dac840 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c @@ -383,7 +383,6 @@ struct lock_stat_data { }; struct lock_stat_seq { - struct lock_stat_data *iter; struct lock_stat_data *iter_end; struct lock_stat_data stats[MAX_LOCKDEP_KEYS]; }; @@ -571,34 +570,22 @@ static void seq_header(struct seq_file *m) static void *ls_start(struct seq_file *m, loff_t *pos) { struct lock_stat_seq *data = m->private; + struct lock_stat_data *iter; if (*pos == 0) return SEQ_START_TOKEN; - data->iter = data->stats + (*pos - 1); - if (data->iter >= data->iter_end) - data->iter = NULL; + iter = data->stats + (*pos - 1); + if (iter >= data->iter_end) + iter = NULL; - return data->iter; + return iter; } static void *ls_next(struct seq_file *m, void *v, loff_t *pos) { - struct lock_stat_seq *data = m->private; - (*pos)++; - - if (v == SEQ_START_TOKEN) - data->iter = data->stats; - else { - data->iter = v; - data->iter++; - } - - if (data->iter == data->iter_end) - data->iter = NULL; - - return data->iter; + return ls_start(m, pos); } static void ls_stop(struct seq_file *m, void *v) @@ -636,7 +623,6 @@ static int lock_stat_open(struct inode *inode, struct file *file) struct lock_stat_data *iter = data->stats; struct seq_file *m = file->private_data; - data->iter = iter; list_for_each_entry(class, &all_lock_classes, lock_entry) { iter->class = class; iter->stats = lock_stats(class); @@ -644,7 +630,7 @@ static int lock_stat_open(struct inode *inode, struct file *file) } data->iter_end = iter; - sort(data->stats, data->iter_end - data->iter, + sort(data->stats, data->iter_end - data->stats, sizeof(struct lock_stat_data), lock_stat_cmp, NULL); @@ -679,7 +665,6 @@ static int lock_stat_release(struct inode *inode, struct file *file) struct seq_file *seq = file->private_data; vfree(seq->private); - seq->private = NULL; return seq_release(inode, file); } -- cgit v0.10.2 From b25c340c195447afb1860da580fe2a85a6b652c5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 13 Aug 2009 12:17:22 +0200 Subject: genirq: Add oneshot support For threaded interrupt handlers we expect the hard interrupt handler part to mask the interrupt on the originating device. The interrupt line itself is reenabled after the hard interrupt handler has executed. This requires access to the originating device from hard interrupt context which is not always possible. There are devices which can only be accessed via a bus (i2c, spi, ...). The bus access requires thread context. For such devices we need to keep the interrupt line masked until the threaded handler has executed. Add a new flag IRQF_ONESHOT which allows drivers to request that the interrupt is not unmasked after the hard interrupt context handler has been executed and the thread has been woken. The interrupt line is unmasked after the thread handler function has been executed. Note that for now IRQF_ONESHOT cannot be used with IRQF_SHARED to avoid complex accounting mechanisms. For oneshot interrupts the primary handler simply returns IRQ_WAKE_THREAD and does nothing else. A generic implementation irq_default_primary_handler() is provided to avoid useless copies all over the place. It is automatically installed when request_threaded_irq() is called with handler=NULL and thread_fn!=NULL. Signed-off-by: Thomas Gleixner Cc: Mark Brown Cc: Dmitry Torokhov Cc: Trilok Soni Cc: Pavel Machek Cc: Brian Swetland Cc: Joonyoung Shim Cc: m.szyprowski@samsung.com Cc: t.fujak@samsung.com Cc: kyungmin.park@samsung.com, Cc: David Brownell Cc: Daniel Ribeiro Cc: arve@android.com Cc: Barry Song <21cnbao@gmail.com> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 35e7df1..1ac57e5 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -50,6 +50,9 @@ * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is * registered first in an shared interrupt is considered for * performance reasons) + * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished. + * Used by threaded interrupts which need to keep the + * irq line disabled until the threaded handler has been run. */ #define IRQF_DISABLED 0x00000020 #define IRQF_SAMPLE_RANDOM 0x00000040 @@ -59,6 +62,7 @@ #define IRQF_PERCPU 0x00000400 #define IRQF_NOBALANCING 0x00000800 #define IRQF_IRQPOLL 0x00001000 +#define IRQF_ONESHOT 0x00002000 /* * Bits used by threaded handlers: diff --git a/include/linux/irq.h b/include/linux/irq.h index cb2e77a..5e7c6ee 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -69,6 +69,7 @@ typedef void (*irq_flow_handler_t)(unsigned int irq, #define IRQ_MOVE_PCNTXT 0x01000000 /* IRQ migration from process context */ #define IRQ_AFFINITY_SET 0x02000000 /* IRQ affinity was set from userspace*/ #define IRQ_SUSPENDED 0x04000000 /* IRQ has gone through suspend sequence */ +#define IRQ_ONESHOT 0x08000000 /* IRQ is not unmasked after hardirq */ #ifdef CONFIG_IRQ_PER_CPU # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 13c68e7..b08c0d2 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -382,7 +382,10 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) spin_lock(&desc->lock); desc->status &= ~IRQ_INPROGRESS; - if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) + + if (unlikely(desc->status & IRQ_ONESHOT)) + desc->status |= IRQ_MASKED; + else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) desc->chip->unmask(irq); out_unlock: spin_unlock(&desc->lock); @@ -478,8 +481,13 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) kstat_incr_irqs_this_cpu(irq, desc); /* Start handling the irq */ - if (desc->chip->ack) - desc->chip->ack(irq); + if (unlikely(desc->status & IRQ_ONESHOT)) { + desc->status |= IRQ_MASKED; + mask_ack_irq(desc, irq); + } else { + if (desc->chip->ack) + desc->chip->ack(irq); + } /* Mark the IRQ currently in progress.*/ desc->status |= IRQ_INPROGRESS; diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index d222515..d7f7b5f 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -436,6 +436,16 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, return ret; } +/* + * Default primary interrupt handler for threaded interrupts. Is + * assigned as primary handler when request_threaded_irq is called + * with handler == NULL. Useful for oneshot interrupts. + */ +static irqreturn_t irq_default_primary_handler(int irq, void *dev_id) +{ + return IRQ_WAKE_THREAD; +} + static int irq_wait_for_interrupt(struct irqaction *action) { while (!kthread_should_stop()) { @@ -451,6 +461,21 @@ static int irq_wait_for_interrupt(struct irqaction *action) return -1; } +/* + * Oneshot interrupts keep the irq line masked until the threaded + * handler finished. unmask if the interrupt has not been disabled and + * is marked MASKED. + */ +static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) +{ + spin_lock_irq(&desc->lock); + if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { + desc->status &= ~IRQ_MASKED; + desc->chip->unmask(irq); + } + spin_unlock_irq(&desc->lock); +} + #ifdef CONFIG_SMP /* * Check whether we need to change the affinity of the interrupt thread. @@ -492,7 +517,7 @@ static int irq_thread(void *data) struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, }; struct irqaction *action = data; struct irq_desc *desc = irq_to_desc(action->irq); - int wake; + int wake, oneshot = desc->status & IRQ_ONESHOT; sched_setscheduler(current, SCHED_FIFO, ¶m); current->irqaction = action; @@ -518,6 +543,9 @@ static int irq_thread(void *data) spin_unlock_irq(&desc->lock); action->thread_fn(action->irq, action->dev_id); + + if (oneshot) + irq_finalize_oneshot(action->irq, desc); } wake = atomic_dec_and_test(&desc->threads_active); @@ -590,6 +618,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) rand_initialize_irq(irq); } + /* Oneshot interrupts are not allowed with shared */ + if ((new->flags & IRQF_ONESHOT) && (new->flags & IRQF_SHARED)) + return -EINVAL; + /* * Threaded handler ? */ @@ -663,9 +695,12 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) desc->status |= IRQ_PER_CPU; #endif - desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | + desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_ONESHOT | IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); + if (new->flags & IRQF_ONESHOT) + desc->status |= IRQ_ONESHOT; + if (!(desc->status & IRQ_NOAUTOEN)) { desc->depth = 0; desc->status &= ~IRQ_DISABLED; @@ -878,6 +913,8 @@ EXPORT_SYMBOL(free_irq); * @irq: Interrupt line to allocate * @handler: Function to be called when the IRQ occurs. * Primary handler for threaded interrupts + * If NULL and thread_fn != NULL the default + * primary handler is installed * @thread_fn: Function called from the irq handler thread * If NULL, no irq thread is created * @irqflags: Interrupt type flags @@ -957,8 +994,12 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, if (desc->status & IRQ_NOREQUEST) return -EINVAL; - if (!handler) - return -EINVAL; + + if (!handler) { + if (!thread_fn) + return -EINVAL; + handler = irq_default_primary_handler; + } action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); if (!action) -- cgit v0.10.2 From 70aedd24d20e75198f5a0b11750faabbb56924e2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 13 Aug 2009 12:17:48 +0200 Subject: genirq: Add buslock support Some interrupt chips are connected to a "slow" bus (i2c, spi ...). The bus access needs to sleep and therefor cannot be called in atomic contexts. Some of the generic interrupt management functions like disable_irq(), enable_irq() ... call interrupt chip functions with the irq_desc->lock held and interrupts disabled. This does not work for such devices. Provide a separate synchronization mechanism for such interrupt chips. The irq_chip structure is extended by two optional functions (bus_lock and bus_sync_and_unlock). The idea is to serialize the bus access for those operations in the core code so that drivers which are behind that bus operated interrupt controller do not have to worry about it and just can use the normal interfaces. To achieve this we add two function pointers to the irq_chip: bus_lock and bus_sync_unlock. bus_lock() is called to serialize access to the interrupt controller bus. Now the core code can issue chip->mask/unmask ... commands without changing the fast path code at all. The chip implementation merily stores that information in a chip private data structure and returns. No bus interaction as these functions are called from atomic context. After that bus_sync_unlock() is called outside the atomic context. Now the chip implementation issues the bus commands, waits for completion and unlocks the interrupt controller bus. The irq_chip implementation as pseudo code: struct irq_chip_data { struct mutex mutex; unsigned int irq_offset; unsigned long mask; unsigned long mask_status; } static void bus_lock(unsigned int irq) { struct irq_chip_data *data = get_irq_desc_chip_data(irq); mutex_lock(&data->mutex); } static void mask(unsigned int irq) { struct irq_chip_data *data = get_irq_desc_chip_data(irq); irq -= data->irq_offset; data->mask |= (1 << irq); } static void unmask(unsigned int irq) { struct irq_chip_data *data = get_irq_desc_chip_data(irq); irq -= data->irq_offset; data->mask &= ~(1 << irq); } static void bus_sync_unlock(unsigned int irq) { struct irq_chip_data *data = get_irq_desc_chip_data(irq); if (data->mask != data->mask_status) { do_bus_magic_to_set_mask(data->mask); data->mask_status = data->mask; } mutex_unlock(&data->mutex); } The device drivers can use request_threaded_irq, free_irq, disable_irq and enable_irq as usual with the only restriction that the calls need to come from non atomic context. Signed-off-by: Thomas Gleixner Cc: Mark Brown Cc: Dmitry Torokhov Cc: Trilok Soni Cc: Pavel Machek Cc: Brian Swetland Cc: Joonyoung Shim Cc: m.szyprowski@samsung.com Cc: t.fujak@samsung.com Cc: kyungmin.park@samsung.com, Cc: David Brownell Cc: Daniel Ribeiro Cc: arve@android.com Cc: Barry Song <21cnbao@gmail.com> diff --git a/include/linux/irq.h b/include/linux/irq.h index 5e7c6ee..ce8171b 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -101,6 +101,9 @@ struct msi_desc; * @set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ * @set_wake: enable/disable power-management wake-on of an IRQ * + * @bus_lock: function to lock access to slow bus (i2c) chips + * @bus_sync_unlock: function to sync and unlock slow bus (i2c) chips + * * @release: release function solely used by UML * @typename: obsoleted by name, kept as migration helper */ @@ -124,6 +127,9 @@ struct irq_chip { int (*set_type)(unsigned int irq, unsigned int flow_type); int (*set_wake)(unsigned int irq, unsigned int on); + void (*bus_lock)(unsigned int irq); + void (*bus_sync_unlock)(unsigned int irq); + /* Currently used only by UML, might disappear one day.*/ #ifdef CONFIG_IRQ_RELEASE_METHOD void (*release)(unsigned int irq, void *dev_id); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index b08c0d2..f856330 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -580,6 +580,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, desc->chip = &dummy_irq_chip; } + chip_bus_lock(irq, desc); spin_lock_irqsave(&desc->lock, flags); /* Uninstall? */ @@ -599,6 +600,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, desc->chip->startup(irq); } spin_unlock_irqrestore(&desc->lock, flags); + chip_bus_sync_unlock(irq, desc); } EXPORT_SYMBOL_GPL(__set_irq_handler); diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index e70ed55..1b5d742 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -44,6 +44,19 @@ extern int irq_select_affinity_usr(unsigned int irq); extern void irq_set_thread_affinity(struct irq_desc *desc); +/* Inline functions for support of irq chips on slow busses */ +static inline void chip_bus_lock(unsigned int irq, struct irq_desc *desc) +{ + if (unlikely(desc->chip->bus_lock)) + desc->chip->bus_lock(irq); +} + +static inline void chip_bus_sync_unlock(unsigned int irq, struct irq_desc *desc) +{ + if (unlikely(desc->chip->bus_sync_unlock)) + desc->chip->bus_sync_unlock(irq); +} + /* * Debugging printout: */ diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index d7f7b5f..0a3fd5b 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -230,9 +230,11 @@ void disable_irq_nosync(unsigned int irq) if (!desc) return; + chip_bus_lock(irq, desc); spin_lock_irqsave(&desc->lock, flags); __disable_irq(desc, irq, false); spin_unlock_irqrestore(&desc->lock, flags); + chip_bus_sync_unlock(irq, desc); } EXPORT_SYMBOL(disable_irq_nosync); @@ -294,7 +296,8 @@ void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume) * matches the last disable, processing of interrupts on this * IRQ line is re-enabled. * - * This function may be called from IRQ context. + * This function may be called from IRQ context only when + * desc->chip->bus_lock and desc->chip->bus_sync_unlock are NULL ! */ void enable_irq(unsigned int irq) { @@ -304,9 +307,11 @@ void enable_irq(unsigned int irq) if (!desc) return; + chip_bus_lock(irq, desc); spin_lock_irqsave(&desc->lock, flags); __enable_irq(desc, irq, false); spin_unlock_irqrestore(&desc->lock, flags); + chip_bus_sync_unlock(irq, desc); } EXPORT_SYMBOL(enable_irq); @@ -468,12 +473,14 @@ static int irq_wait_for_interrupt(struct irqaction *action) */ static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) { + chip_bus_lock(irq, desc); spin_lock_irq(&desc->lock); if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { desc->status &= ~IRQ_MASKED; desc->chip->unmask(irq); } spin_unlock_irq(&desc->lock); + chip_bus_sync_unlock(irq, desc); } #ifdef CONFIG_SMP @@ -904,7 +911,14 @@ EXPORT_SYMBOL_GPL(remove_irq); */ void free_irq(unsigned int irq, void *dev_id) { + struct irq_desc *desc = irq_to_desc(irq); + + if (!desc) + return; + + chip_bus_lock(irq, desc); kfree(__free_irq(irq, dev_id)); + chip_bus_sync_unlock(irq, desc); } EXPORT_SYMBOL(free_irq); @@ -1011,7 +1025,10 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, action->name = devname; action->dev_id = dev_id; + chip_bus_lock(irq, desc); retval = __setup_irq(irq, desc, action); + chip_bus_sync_unlock(irq, desc); + if (retval) kfree(action); -- cgit v0.10.2 From 399b5da29b9f851eb7b96e2882097127f003e87c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 13 Aug 2009 13:21:38 +0200 Subject: genirq: Support nested threaded irq handling Interrupt chips which are behind a slow bus (i2c, spi ...) and demultiplex other interrupt sources need to run their interrupt handler in a thread. The demultiplexed interrupt handlers need to run in thread context as well and need to finish before the demux handler thread can reenable the interrupt line. So the easiest way is to run the sub device handlers in the context of the demultiplexing handler thread. To avoid that a separate thread is created for the subdevices the function set_nested_irq_thread() is provided which sets the IRQ_NESTED_THREAD flag in the interrupt descriptor. A driver which calls request_threaded_irq() must not be aware of the fact that the threaded handler is called in the context of the demultiplexing handler thread. The setup code checks the IRQ_NESTED_THREAD flag which was set from the irq chip setup code and does not setup a separate thread for the interrupt. The primary function which is provided by the device driver is replaced by an internal dummy function which warns when it is called. For the demultiplexing handler a helper function handle_nested_irq() is provided which calls the demux interrupt thread function in the context of the caller and does the proper interrupt accounting and takes the interrupt disabled status of the demultiplexed subdevice into account. Signed-off-by: Thomas Gleixner Cc: Mark Brown Cc: Dmitry Torokhov Cc: Trilok Soni Cc: Pavel Machek Cc: Brian Swetland Cc: Joonyoung Shim Cc: m.szyprowski@samsung.com Cc: t.fujak@samsung.com Cc: kyungmin.park@samsung.com, Cc: David Brownell Cc: Daniel Ribeiro Cc: arve@android.com Cc: Barry Song <21cnbao@gmail.com> diff --git a/include/linux/irq.h b/include/linux/irq.h index ce8171b..8778ee9 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -70,6 +70,7 @@ typedef void (*irq_flow_handler_t)(unsigned int irq, #define IRQ_AFFINITY_SET 0x02000000 /* IRQ affinity was set from userspace*/ #define IRQ_SUSPENDED 0x04000000 /* IRQ has gone through suspend sequence */ #define IRQ_ONESHOT 0x08000000 /* IRQ is not unmasked after hardirq */ +#define IRQ_NESTED_THREAD 0x10000000 /* IRQ is nested into another, no own handler thread */ #ifdef CONFIG_IRQ_PER_CPU # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) @@ -386,6 +387,8 @@ set_irq_chained_handler(unsigned int irq, __set_irq_handler(irq, handle, 1, NULL); } +extern void set_irq_nested_thread(unsigned int irq, int nest); + extern void set_irq_noprobe(unsigned int irq); extern void set_irq_probe(unsigned int irq); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index f856330..5765aad 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -222,6 +222,34 @@ int set_irq_chip_data(unsigned int irq, void *data) } EXPORT_SYMBOL(set_irq_chip_data); +/** + * set_irq_nested_thread - Set/Reset the IRQ_NESTED_THREAD flag of an irq + * + * @irq: Interrupt number + * @nest: 0 to clear / 1 to set the IRQ_NESTED_THREAD flag + * + * The IRQ_NESTED_THREAD flag indicates that on + * request_threaded_irq() no separate interrupt thread should be + * created for the irq as the handler are called nested in the + * context of a demultiplexing interrupt handler thread. + */ +void set_irq_nested_thread(unsigned int irq, int nest) +{ + struct irq_desc *desc = irq_to_desc(irq); + unsigned long flags; + + if (!desc) + return; + + spin_lock_irqsave(&desc->lock, flags); + if (nest) + desc->status |= IRQ_NESTED_THREAD; + else + desc->status &= ~IRQ_NESTED_THREAD; + spin_unlock_irqrestore(&desc->lock, flags); +} +EXPORT_SYMBOL_GPL(set_irq_nested_thread); + /* * default enable function */ @@ -299,6 +327,45 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq) } } +/* + * handle_nested_irq - Handle a nested irq from a irq thread + * @irq: the interrupt number + * + * Handle interrupts which are nested into a threaded interrupt + * handler. The handler function is called inside the calling + * threads context. + */ +void handle_nested_irq(unsigned int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + struct irqaction *action; + irqreturn_t action_ret; + + might_sleep(); + + spin_lock_irq(&desc->lock); + + kstat_incr_irqs_this_cpu(irq, desc); + + action = desc->action; + if (unlikely(!action || (desc->status & IRQ_DISABLED))) + goto out_unlock; + + desc->status |= IRQ_INPROGRESS; + spin_unlock_irq(&desc->lock); + + action_ret = action->thread_fn(action->irq, action->dev_id); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); + + spin_lock_irq(&desc->lock); + desc->status &= ~IRQ_INPROGRESS; + +out_unlock: + spin_unlock_irq(&desc->lock); +} +EXPORT_SYMBOL_GPL(handle_nested_irq); + /** * handle_simple_irq - Simple and software-decoded IRQs. * @irq: the interrupt number diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0a3fd5b..e485cea0 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -451,6 +451,16 @@ static irqreturn_t irq_default_primary_handler(int irq, void *dev_id) return IRQ_WAKE_THREAD; } +/* + * Primary handler for nested threaded interrupts. Should never be + * called. + */ +static irqreturn_t irq_nested_primary_handler(int irq, void *dev_id) +{ + WARN(1, "Primary handler called for nested irq %d\n", irq); + return IRQ_NONE; +} + static int irq_wait_for_interrupt(struct irqaction *action) { while (!kthread_should_stop()) { @@ -600,7 +610,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) struct irqaction *old, **old_ptr; const char *old_name = NULL; unsigned long flags; - int shared = 0; + int nested, shared = 0; int ret; if (!desc) @@ -630,9 +640,27 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) return -EINVAL; /* - * Threaded handler ? + * Check whether the interrupt nests into another interrupt + * thread. + */ + nested = desc->status & IRQ_NESTED_THREAD; + if (nested) { + if (!new->thread_fn) + return -EINVAL; + /* + * Replace the primary handler which was provided from + * the driver for non nested interrupt handling by the + * dummy function which warns when called. + */ + new->handler = irq_nested_primary_handler; + } + + /* + * Create a handler thread when a thread function is supplied + * and the interrupt does not nest into another interrupt + * thread. */ - if (new->thread_fn) { + if (new->thread_fn && !nested) { struct task_struct *t; t = kthread_create(irq_thread, new, "irq/%d-%s", irq, -- cgit v0.10.2 From 7ead8b8313d92b3a69a1a61b0dcbc4cd66c960dc Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 17 Aug 2009 16:56:28 +0800 Subject: tracing/events: Add module tracepoints Add trace points to trace module_load, module_free, module_get, module_put and module_request, and use trace_event facility to get the trace output. Here's the sample output: TASK-PID CPU# TIMESTAMP FUNCTION | | | | | <...>-42 [000] 1.758380: module_request: fb0 wait=1 call_site=fb_open ... <...>-60 [000] 3.269403: module_load: scsi_wait_scan <...>-60 [000] 3.269432: module_put: scsi_wait_scan call_site=sys_init_module refcnt=0 <...>-61 [001] 3.273168: module_free: scsi_wait_scan ... <...>-1021 [000] 13.836081: module_load: sunrpc <...>-1021 [000] 13.840589: module_put: sunrpc call_site=sys_init_module refcnt=-1 <...>-1027 [000] 13.848098: module_get: sunrpc call_site=try_module_get refcnt=0 <...>-1027 [000] 13.848308: module_get: sunrpc call_site=get_filesystem refcnt=1 <...>-1027 [000] 13.848692: module_put: sunrpc call_site=put_filesystem refcnt=0 ... modprobe-2587 [001] 1088.437213: module_load: trace_events_sample F modprobe-2587 [001] 1088.437786: module_put: trace_events_sample call_site=sys_init_module refcnt=0 Note: - the taints flag can be 'F', 'C' and/or 'P' if mod->taints != 0 - the module refcnt is percpu, so it can be negative in a specific cpu Signed-off-by: Li Zefan Acked-by: Rusty Russell Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Rusty Russell LKML-Reference: <4A891B3C.5030608@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/module.h b/include/linux/module.h index 098bdb7..f8f92d0 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -17,10 +17,12 @@ #include #include #include -#include +#include #include +#include + /* Not Yet Implemented */ #define MODULE_SUPPORTED_DEVICE(name) @@ -462,7 +464,10 @@ static inline local_t *__module_ref_addr(struct module *mod, int cpu) static inline void __module_get(struct module *module) { if (module) { - local_inc(__module_ref_addr(module, get_cpu())); + unsigned int cpu = get_cpu(); + local_inc(__module_ref_addr(module, cpu)); + trace_module_get(module, _THIS_IP_, + local_read(__module_ref_addr(module, cpu))); put_cpu(); } } @@ -473,8 +478,11 @@ static inline int try_module_get(struct module *module) if (module) { unsigned int cpu = get_cpu(); - if (likely(module_is_live(module))) + if (likely(module_is_live(module))) { local_inc(__module_ref_addr(module, cpu)); + trace_module_get(module, _THIS_IP_, + local_read(__module_ref_addr(module, cpu))); + } else ret = 0; put_cpu(); diff --git a/include/trace/events/module.h b/include/trace/events/module.h new file mode 100644 index 0000000..84160fb --- /dev/null +++ b/include/trace/events/module.h @@ -0,0 +1,126 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM module + +#if !defined(_TRACE_MODULE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_MODULE_H + +#include + +#ifdef CONFIG_MODULES + +struct module; + +#define show_module_flags(flags) __print_flags(flags, "", \ + { (1UL << TAINT_PROPRIETARY_MODULE), "P" }, \ + { (1UL << TAINT_FORCED_MODULE), "F" }, \ + { (1UL << TAINT_CRAP), "C" }) + +TRACE_EVENT(module_load, + + TP_PROTO(struct module *mod), + + TP_ARGS(mod), + + TP_STRUCT__entry( + __field( unsigned int, taints ) + __string( name, mod->name ) + ), + + TP_fast_assign( + __entry->taints = mod->taints; + __assign_str(name, mod->name); + ), + + TP_printk("%s %s", __get_str(name), show_module_flags(__entry->taints)) +); + +TRACE_EVENT(module_free, + + TP_PROTO(struct module *mod), + + TP_ARGS(mod), + + TP_STRUCT__entry( + __string( name, mod->name ) + ), + + TP_fast_assign( + __assign_str(name, mod->name); + ), + + TP_printk("%s", __get_str(name)) +); + +TRACE_EVENT(module_get, + + TP_PROTO(struct module *mod, unsigned long ip, int refcnt), + + TP_ARGS(mod, ip, refcnt), + + TP_STRUCT__entry( + __field( unsigned long, ip ) + __field( int, refcnt ) + __string( name, mod->name ) + ), + + TP_fast_assign( + __entry->ip = ip; + __entry->refcnt = refcnt; + __assign_str(name, mod->name); + ), + + TP_printk("%s call_site=%pf refcnt=%d", + __get_str(name), (void *)__entry->ip, __entry->refcnt) +); + +TRACE_EVENT(module_put, + + TP_PROTO(struct module *mod, unsigned long ip, int refcnt), + + TP_ARGS(mod, ip, refcnt), + + TP_STRUCT__entry( + __field( unsigned long, ip ) + __field( int, refcnt ) + __string( name, mod->name ) + ), + + TP_fast_assign( + __entry->ip = ip; + __entry->refcnt = refcnt; + __assign_str(name, mod->name); + ), + + TP_printk("%s call_site=%pf refcnt=%d", + __get_str(name), (void *)__entry->ip, __entry->refcnt) +); + +TRACE_EVENT(module_request, + + TP_PROTO(char *name, bool wait, unsigned long ip), + + TP_ARGS(name, wait, ip), + + TP_STRUCT__entry( + __field( bool, wait ) + __field( unsigned long, ip ) + __string( name, name ) + ), + + TP_fast_assign( + __entry->wait = wait; + __entry->ip = ip; + __assign_str(name, name); + ), + + TP_printk("%s wait=%d call_site=%pf", + __get_str(name), (int)__entry->wait, (void *)__entry->ip) +); + +#endif /* CONFIG_MODULES */ + +#endif /* _TRACE_MODULE_H */ + +/* This part must be outside protection */ +#include + diff --git a/kernel/kmod.c b/kernel/kmod.c index 385c31a..a922808 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -37,6 +37,8 @@ #include #include +#include + extern int max_threads; static struct workqueue_struct *khelper_wq; @@ -108,6 +110,8 @@ int __request_module(bool wait, const char *fmt, ...) return -ENOMEM; } + trace_module_request(module_name, wait, _RET_IP_); + ret = call_usermodehelper(modprobe_path, argv, envp, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC); atomic_dec(&kmod_concurrent); diff --git a/kernel/module.c b/kernel/module.c index fd14114..b182143 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -55,6 +55,11 @@ #include #include +#define CREATE_TRACE_POINTS +#include + +EXPORT_TRACEPOINT_SYMBOL(module_get); + #if 0 #define DEBUGP printk #else @@ -940,6 +945,8 @@ void module_put(struct module *module) if (module) { unsigned int cpu = get_cpu(); local_dec(__module_ref_addr(module, cpu)); + trace_module_put(module, _RET_IP_, + local_read(__module_ref_addr(module, cpu))); /* Maybe they're waiting for us to drop reference? */ if (unlikely(!module_is_live(module))) wake_up_process(module->waiter); @@ -1491,6 +1498,8 @@ static int __unlink_module(void *_mod) /* Free a module, remove from lists, etc (must hold module_mutex). */ static void free_module(struct module *mod) { + trace_module_free(mod); + /* Delete from various lists */ stop_machine(__unlink_module, mod, NULL); remove_notes_attrs(mod); @@ -2358,6 +2367,8 @@ static noinline struct module *load_module(void __user *umod, /* Get rid of temporary copy */ vfree(hdr); + trace_module_load(mod); + /* Done! */ return mod; -- cgit v0.10.2 From ba8b3a40ba7e06d00c27508f090803af90e8dbbf Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 17 Aug 2009 16:55:18 +0800 Subject: tracing/syscalls: Fix to print parameter types When syscall tracing was implemented as a tracer, "syscall_arg_type" trace option could be set to enable the display of syscall parameter types. Now this option is gone since it's no longer a tracer, but the code is still there but dead. So we remove dead code and re-enable the printing of paramete types via the verbose option: # echo verbose > trace_options # echo syscalls > set_event # cat trace ... bash-3331 [000] 95.348937: sys_fcntl64 -> 0x1 bash-3331 [000] 95.348942: sys_close(unsigned int fd: a) ... Signed-off-by: Li Zefan Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Jason Baron LKML-Reference: <4A891AF6.5050102@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index f837ccc..f130dac 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -13,21 +13,6 @@ static int sys_refcount_exit; static DECLARE_BITMAP(enabled_enter_syscalls, FTRACE_SYSCALL_MAX); static DECLARE_BITMAP(enabled_exit_syscalls, FTRACE_SYSCALL_MAX); -/* Option to display the parameters types */ -enum { - TRACE_SYSCALLS_OPT_TYPES = 0x1, -}; - -static struct tracer_opt syscalls_opts[] = { - { TRACER_OPT(syscall_arg_type, TRACE_SYSCALLS_OPT_TYPES) }, - { } -}; - -static struct tracer_flags syscalls_flags = { - .val = 0, /* By default: no parameters types */ - .opts = syscalls_opts -}; - enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags) { @@ -55,7 +40,7 @@ print_syscall_enter(struct trace_iterator *iter, int flags) for (i = 0; i < entry->nb_args; i++) { /* parameter types */ - if (syscalls_flags.val & TRACE_SYSCALLS_OPT_TYPES) { + if (trace_flags & TRACE_ITER_VERBOSE) { ret = trace_seq_printf(s, "%s ", entry->types[i]); if (!ret) return TRACE_TYPE_PARTIAL_LINE; -- cgit v0.10.2 From 97d53202a5670a08b79c8ef2e4fff1c1ee21317c Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 17 Aug 2009 16:52:53 +0800 Subject: trace_stat: Fix missing entry in stat file One entry is missing in the output of a stat file. The cause is, when stat_seq_start() is called the 2nd time, we should start from the (pos-1)th elem in the rbtree but not pos, because pos == 0 is the header. Signed-off-by: Li Zefan Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4A891A65.70009@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c index 07c60b0..a4bb239 100644 --- a/kernel/trace/trace_stat.c +++ b/kernel/trace/trace_stat.c @@ -203,17 +203,21 @@ static void *stat_seq_start(struct seq_file *s, loff_t *pos) { struct stat_session *session = s->private; struct rb_node *node; + int n = *pos; int i; /* Prevent from tracer switch or rbtree modification */ mutex_lock(&session->stat_mutex); /* If we are in the beginning of the file, print the headers */ - if (!*pos && session->ts->stat_headers) - return SEQ_START_TOKEN; + if (session->ts->stat_headers) { + if (n == 0) + return SEQ_START_TOKEN; + n--; + } node = rb_first(&session->stat_root); - for (i = 0; node && i < *pos; i++) + for (i = 0; node && i < n; i++) node = rb_next(node); return node; -- cgit v0.10.2 From 2fc5f0cff4cf1c4cd336d0f61f11bca6eeee1d84 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 17 Aug 2009 16:53:37 +0800 Subject: trace_stack: Simplify seqfile code Extract duplicate code in t_start() and t_next(). Signed-off-by: Li Zefan Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4A891A91.4030602@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 0da1cff..0f6facb 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -186,43 +186,33 @@ static const struct file_operations stack_max_size_fops = { }; static void * -t_next(struct seq_file *m, void *v, loff_t *pos) +__next(struct seq_file *m, loff_t *pos) { - long i; + long n = *pos - 1; - (*pos)++; - - if (v == SEQ_START_TOKEN) - i = 0; - else { - i = *(long *)v; - i++; - } - - if (i >= max_stack_trace.nr_entries || - stack_dump_trace[i] == ULONG_MAX) + if (n >= max_stack_trace.nr_entries || stack_dump_trace[n] == ULONG_MAX) return NULL; - m->private = (void *)i; - + m->private = (void *)n; return &m->private; } -static void *t_start(struct seq_file *m, loff_t *pos) +static void * +t_next(struct seq_file *m, void *v, loff_t *pos) { - void *t = SEQ_START_TOKEN; - loff_t l = 0; + (*pos)++; + return __next(m, pos); +} +static void *t_start(struct seq_file *m, loff_t *pos) +{ local_irq_disable(); __raw_spin_lock(&max_stack_lock); if (*pos == 0) return SEQ_START_TOKEN; - for (; t && l < *pos; t = t_next(m, t, &l)) - ; - - return t; + return __next(m, pos); } static void t_stop(struct seq_file *m, void *p) -- cgit v0.10.2 From 3be04b471b95b870bd129a138463756629e86f3f Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 17 Aug 2009 16:54:03 +0800 Subject: ftrace: Simplify seqfile code Use seq_release_private(). Signed-off-by: Li Zefan Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Li Zefan LKML-Reference: <4A891AAB.8090701@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 0948634..1993b71 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1556,17 +1556,6 @@ ftrace_avail_open(struct inode *inode, struct file *file) return ret; } -int ftrace_avail_release(struct inode *inode, struct file *file) -{ - struct seq_file *m = (struct seq_file *)file->private_data; - struct ftrace_iterator *iter = m->private; - - seq_release(inode, file); - kfree(iter); - - return 0; -} - static int ftrace_failures_open(struct inode *inode, struct file *file) { @@ -2427,14 +2416,14 @@ static const struct file_operations ftrace_avail_fops = { .open = ftrace_avail_open, .read = seq_read, .llseek = seq_lseek, - .release = ftrace_avail_release, + .release = seq_release_private, }; static const struct file_operations ftrace_failures_fops = { .open = ftrace_failures_open, .read = seq_read, .llseek = seq_lseek, - .release = ftrace_avail_release, + .release = seq_release_private, }; static const struct file_operations ftrace_filter_fops = { -- cgit v0.10.2 From 64844a6ac8ddd586cb832fea7cf2e93e5e7e03f4 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Mon, 10 Aug 2009 10:50:04 +0200 Subject: ASoC: OMAP: Make use of DMA channel self linking on OMAP1510 Use newly implemented DMA channel self linking on OMAP1510 like on other OMAP models. Remove unnecessary DMA transfer restart from interrupt handler routine. The interrupt routine used to maintain a period index, originally needed for counting up periods up to a full buffer in order to restart the DMA transfer. For some time, this counter is also used as a replacement for hardware DMA progress counter that has been found unusable on OMAP1510 in case of playback. Thus, the period index calculation cannot be omitted completely. However, the accuracy of this counter can still suffer from missing DMA interrupts. In order to work correctly, it requires patch 1 from this series also applied: [RFC][PATCH 1/3] ARM: OMAP: DMA: Add support for DMA channel self linking on OMAP1510 Created against linux-2.6.31-rc5. Tested on Amstrad Delta. Signed-off-by: Janusz Krzysztofik Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index c3c931d..3e3a9d4 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -59,16 +59,18 @@ static void omap_pcm_dma_irq(int ch, u16 stat, void *data) struct omap_runtime_data *prtd = runtime->private_data; unsigned long flags; - if (cpu_is_omap1510()) { + if ((cpu_is_omap1510()) && + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) { /* - * OMAP1510 doesn't support DMA chaining so have to restart - * the transfer after all periods are transferred + * OMAP1510 doesn't fully support DMA progress counter + * and there is no software emulation implemented yet, + * so have to maintain our own playback progress counter + * that can be used by omap_pcm_pointer() instead. */ spin_lock_irqsave(&prtd->lock, flags); if (prtd->period_index >= 0) { if (++prtd->period_index == runtime->periods) { prtd->period_index = 0; - omap_start_dma(prtd->dma_ch); } } spin_unlock_irqrestore(&prtd->lock, flags); @@ -100,7 +102,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, prtd->dma_data = dma_data; err = omap_request_dma(dma_data->dma_req, dma_data->name, omap_pcm_dma_irq, substream, &prtd->dma_ch); - if (!err && !cpu_is_omap1510()) { + if (!err) { /* * Link channel with itself so DMA doesn't need any * reprogramming while looping the buffer @@ -119,8 +121,7 @@ static int omap_pcm_hw_free(struct snd_pcm_substream *substream) if (prtd->dma_data == NULL) return 0; - if (!cpu_is_omap1510()) - omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch); + omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch); omap_free_dma(prtd->dma_ch); prtd->dma_data = NULL; -- cgit v0.10.2 From 471e3dec3abe2d41e8c742046353fcb01bc2459e Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Tue, 11 Aug 2009 21:44:29 +0200 Subject: ASoC: OMAP: Enhance OMAP1510 DMA progress software counter Enhance period_index accuracy, particularly just before buffer rewind, by making use of DMA interrupt status flags in addition to simply counting up interrupts. Created against linux-2.6.31-rc5. Tested on Amstrad Delta. Signed-off-by: Janusz Krzysztofik Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 3e3a9d4..12e14c0 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -68,8 +68,21 @@ static void omap_pcm_dma_irq(int ch, u16 stat, void *data) * that can be used by omap_pcm_pointer() instead. */ spin_lock_irqsave(&prtd->lock, flags); + if ((stat == OMAP_DMA_LAST_IRQ) && + (prtd->period_index == runtime->periods - 1)) { + /* we are in sync, do nothing */ + spin_unlock_irqrestore(&prtd->lock, flags); + return; + } if (prtd->period_index >= 0) { - if (++prtd->period_index == runtime->periods) { + if (stat & OMAP_DMA_BLOCK_IRQ) { + /* end of buffer reached, loop back */ + prtd->period_index = 0; + } else if (stat & OMAP_DMA_LAST_IRQ) { + /* update the counter for the last period */ + prtd->period_index = runtime->periods - 1; + } else if (++prtd->period_index >= runtime->periods) { + /* end of buffer missed? loop back */ prtd->period_index = 0; } } @@ -175,7 +188,12 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) dma_params.frame_count = runtime->periods; omap_set_dma_params(prtd->dma_ch, &dma_params); - omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); + if ((cpu_is_omap1510()) && + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) + omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ | + OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ); + else + omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); return 0; } -- cgit v0.10.2 From 2a031aedf7f574a01eb725507cb303d4d7b8b23a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 17 Aug 2009 12:25:52 +0200 Subject: sound: snd_ctl_elem_add: fix value count check Make sure that no user element that has no values can be added. The check for count>1024 is not needed because the count is checked later for the individual control types. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/core/control.c b/sound/core/control.c index 17b8d47..66d6aaf 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -951,7 +951,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (card->user_ctl_count >= MAX_USER_CONTROLS) return -ENOMEM; - if (info->count > 1024) + if (info->count < 1) return -EINVAL; access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| -- cgit v0.10.2 From 317b80817fcaeac7ae7e062fcccef0d2aba38a78 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 17 Aug 2009 12:26:34 +0200 Subject: sound: snd_ctl_remove_unlocked_id: simplify error paths Use a common exit path to release the mutex and to return a possible error. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/core/control.c b/sound/core/control.c index 66d6aaf..9d91f77 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -433,15 +433,16 @@ static int snd_ctl_remove_unlocked_id(struct snd_ctl_file * file, down_write(&card->controls_rwsem); kctl = snd_ctl_find_id(card, id); if (kctl == NULL) { - up_write(&card->controls_rwsem); - return -ENOENT; + ret = -ENOENT; + goto error; } for (idx = 0; idx < kctl->count; idx++) if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) { - up_write(&card->controls_rwsem); - return -EBUSY; + ret = -EBUSY; + goto error; } ret = snd_ctl_remove(card, kctl); +error: up_write(&card->controls_rwsem); return ret; } -- cgit v0.10.2 From f217ac59b6dd73105abc13da3fe656391fa6d135 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 17 Aug 2009 12:27:22 +0200 Subject: sound: snd_ctl_remove_unlocked_id: simplify user control counting Move the decrementing of the user controls counter from snd_ctl_elem_remove to snd_ctl_remove_unlocked_id; this saves the separate locking of the controls semaphore, and therefore removes a harmless race. Since the purpose of the function is to operate on user controls (the control being unlocked is just a prerequisite), rename it to snd_ctl_remove_user_ctl. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/core/control.c b/sound/core/control.c index 9d91f77..bc64b72 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -414,7 +414,7 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id) EXPORT_SYMBOL(snd_ctl_remove_id); /** - * snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it + * snd_ctl_remove_user_ctl - remove and release the unlocked user control * @file: active control handle * @id: the control id to remove * @@ -423,8 +423,8 @@ EXPORT_SYMBOL(snd_ctl_remove_id); * * Returns 0 if successful, or a negative error code on failure. */ -static int snd_ctl_remove_unlocked_id(struct snd_ctl_file * file, - struct snd_ctl_elem_id *id) +static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, + struct snd_ctl_elem_id *id) { struct snd_card *card = file->card; struct snd_kcontrol *kctl; @@ -442,6 +442,9 @@ static int snd_ctl_remove_unlocked_id(struct snd_ctl_file * file, goto error; } ret = snd_ctl_remove(card, kctl); + if (ret < 0) + goto error; + card->user_ctl_count--; error: up_write(&card->controls_rwsem); return ret; @@ -1053,18 +1056,10 @@ static int snd_ctl_elem_remove(struct snd_ctl_file *file, struct snd_ctl_elem_id __user *_id) { struct snd_ctl_elem_id id; - int err; if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; - err = snd_ctl_remove_unlocked_id(file, &id); - if (! err) { - struct snd_card *card = file->card; - down_write(&card->controls_rwsem); - card->user_ctl_count--; - up_write(&card->controls_rwsem); - } - return err; + return snd_ctl_remove_user_ctl(file, &id); } static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr) -- cgit v0.10.2 From 18dd0aa5afea7dc33953aa87de696e39074bbf78 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 17 Aug 2009 12:28:09 +0200 Subject: sound: snd_ctl_remove_user_ctl: prevent removal of kernel controls Ensure that userspace can remove only user controls. Controls created by kernel drivers must not be removed because they might be referenced in calls to snd_ctl_notify(). Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/core/control.c b/sound/core/control.c index bc64b72..a8b7fab 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -436,6 +436,10 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, ret = -ENOENT; goto error; } + if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) { + ret = -EINVAL; + goto error; + } for (idx = 0; idx < kctl->count; idx++) if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) { ret = -EBUSY; -- cgit v0.10.2 From 0c093fb5421a648fae46fce17277bdb358fe017b Mon Sep 17 00:00:00 2001 From: Shine Liu Date: Mon, 17 Aug 2009 18:52:01 +0800 Subject: ASoC: UDA134X: Fix mistaken mute/unmute code There is a mistake in current uda134x_mute function: mute_reg has been changed in line 162 or line 164, so uda134x_write should write "mute_reg" but not "mute_reg & ~(1<<2)" to UDA134X_DATA010. Signed-off-by: Shine Liu Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 269b108..c33b92e 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -163,7 +163,7 @@ static int uda134x_mute(struct snd_soc_dai *dai, int mute) else mute_reg &= ~(1<<2); - uda134x_write(codec, UDA134X_DATA010, mute_reg & ~(1<<2)); + uda134x_write(codec, UDA134X_DATA010, mute_reg); return 0; } -- cgit v0.10.2 From b14b76a56e49946488637ee68926c5180c39fdb1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Aug 2009 11:55:38 +0100 Subject: ASoC: Fix handling of bias levels for non-DAPM codecs If the system doesn't have any DAPM widgets then we can't use their state to check if the bias level for the codec should be up. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c68c204..8997fb3 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -966,6 +966,22 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) } } + /* If there are no DAPM widgets then try to figure out power from the + * event type. + */ + if (list_empty(&codec->dapm_widgets)) { + switch (event) { + case SND_SOC_DAPM_STREAM_START: + case SND_SOC_DAPM_STREAM_RESUME: + sys_power = 1; + break; + case SND_SOC_DAPM_STREAM_NOP: + sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY; + default: + break; + } + } + /* If we're changing to all on or all off then prepare */ if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { -- cgit v0.10.2 From 520509436417901f30106e021e037c75dfe5386c Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 17 Aug 2009 16:18:05 +0200 Subject: perf tools: Add trace event debugfs IO handler Add util/trace-event-info.c which handles ftrace file IO from debugfs and provides general helpers to fetch/save ftrace events informations. This file is a rename of the trace-cmd.c file from the trace-cmd tools, written by Steven Rostedt and Josh Triplett, originated from the git tree: git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git This is a perf tools integration. For now, ftrace events information is saved in a separate file than the standard perf.data [fweisbec@gmail.com: various changes for perf tools integration] Signed-off-by: Steven Rostedt Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: "Luis Claudio R. Goncalves" Cc: Clark Williams Cc: Jon Masters Cc: Mathieu Desnoyers Cc: Christoph Hellwig Cc: Xiao Guangrong Cc: Zhaolei Cc: Li Zefan Cc: Lai Jiangshan Cc: Masami Hiramatsu Cc: Tom Zanussi Cc: "Frank Ch. Eigler" Cc: Roland McGrath Cc: Jason Baron Cc: Paul Mackerras Cc: Jiaying Zhang Cc: Anton Blanchard LKML-Reference: <1250518688-7207-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c new file mode 100644 index 0000000..78adff1 --- /dev/null +++ b/tools/perf/util/trace-event-info.c @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2008,2009, Steven Rostedt + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License (not later!) + * + * 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 _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "trace-event.h" + + +#define VERSION "0.5" + +#define _STR(x) #x +#define STR(x) _STR(x) +#define MAX_PATH 256 + +#define TRACE_CTRL "tracing_on" +#define TRACE "trace" +#define AVAILABLE "available_tracers" +#define CURRENT "current_tracer" +#define ITER_CTRL "trace_options" +#define MAX_LATENCY "tracing_max_latency" + +unsigned int page_size; + +static const char *output_file = "trace.info"; +static int output_fd; + +struct event_list { + struct event_list *next; + const char *event; +}; + +struct events { + struct events *sibling; + struct events *children; + struct events *next; + char *name; +}; + + + +static void die(const char *fmt, ...) +{ + va_list ap; + int ret = errno; + + if (errno) + perror("trace-cmd"); + else + ret = -1; + + va_start(ap, fmt); + fprintf(stderr, " "); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, "\n"); + exit(ret); +} + +void *malloc_or_die(unsigned int size) +{ + void *data; + + data = malloc(size); + if (!data) + die("malloc"); + return data; +} + +static const char *find_debugfs(void) +{ + static char debugfs[MAX_PATH+1]; + static int debugfs_found; + char type[100]; + FILE *fp; + + if (debugfs_found) + return debugfs; + + if ((fp = fopen("/proc/mounts","r")) == NULL) + die("Can't open /proc/mounts for read"); + + while (fscanf(fp, "%*s %" + STR(MAX_PATH) + "s %99s %*s %*d %*d\n", + debugfs, type) == 2) { + if (strcmp(type, "debugfs") == 0) + break; + } + fclose(fp); + + if (strcmp(type, "debugfs") != 0) + die("debugfs not mounted, please mount"); + + debugfs_found = 1; + + return debugfs; +} + +/* + * Finds the path to the debugfs/tracing + * Allocates the string and stores it. + */ +static const char *find_tracing_dir(void) +{ + static char *tracing; + static int tracing_found; + const char *debugfs; + + if (tracing_found) + return tracing; + + debugfs = find_debugfs(); + + tracing = malloc_or_die(strlen(debugfs) + 9); + + sprintf(tracing, "%s/tracing", debugfs); + + tracing_found = 1; + return tracing; +} + +static char *get_tracing_file(const char *name) +{ + const char *tracing; + char *file; + + tracing = find_tracing_dir(); + if (!tracing) + return NULL; + + file = malloc_or_die(strlen(tracing) + strlen(name) + 2); + + sprintf(file, "%s/%s", tracing, name); + return file; +} + +static void put_tracing_file(char *file) +{ + free(file); +} + +static ssize_t write_or_die(const void *buf, size_t len) +{ + int ret; + + ret = write(output_fd, buf, len); + if (ret < 0) + die("writing to '%s'", output_file); + + return ret; +} + +int bigendian(void) +{ + unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; + unsigned int *ptr; + + ptr = (unsigned int *)str; + return *ptr == 0x01020304; +} + +static unsigned long long copy_file_fd(int fd) +{ + unsigned long long size = 0; + char buf[BUFSIZ]; + int r; + + do { + r = read(fd, buf, BUFSIZ); + if (r > 0) { + size += r; + write_or_die(buf, r); + } + } while (r > 0); + + return size; +} + +static unsigned long long copy_file(const char *file) +{ + unsigned long long size = 0; + int fd; + + fd = open(file, O_RDONLY); + if (fd < 0) + die("Can't read '%s'", file); + size = copy_file_fd(fd); + close(fd); + + return size; +} + +static unsigned long get_size_fd(int fd) +{ + unsigned long long size = 0; + char buf[BUFSIZ]; + int r; + + do { + r = read(fd, buf, BUFSIZ); + if (r > 0) + size += r; + } while (r > 0); + + lseek(fd, 0, SEEK_SET); + + return size; +} + +static unsigned long get_size(const char *file) +{ + unsigned long long size = 0; + int fd; + + fd = open(file, O_RDONLY); + if (fd < 0) + die("Can't read '%s'", file); + size = get_size_fd(fd); + close(fd); + + return size; +} + +static void read_header_files(void) +{ + unsigned long long size, check_size; + char *path; + int fd; + + path = get_tracing_file("events/header_page"); + fd = open(path, O_RDONLY); + if (fd < 0) + die("can't read '%s'", path); + + /* unfortunately, you can not stat debugfs files for size */ + size = get_size_fd(fd); + + write_or_die("header_page", 12); + write_or_die(&size, 8); + check_size = copy_file_fd(fd); + if (size != check_size) + die("wrong size for '%s' size=%lld read=%lld", + path, size, check_size); + put_tracing_file(path); + + path = get_tracing_file("events/header_event"); + fd = open(path, O_RDONLY); + if (fd < 0) + die("can't read '%s'", path); + + size = get_size_fd(fd); + + write_or_die("header_event", 13); + write_or_die(&size, 8); + check_size = copy_file_fd(fd); + if (size != check_size) + die("wrong size for '%s'", path); + put_tracing_file(path); +} + +static void copy_event_system(const char *sys) +{ + unsigned long long size, check_size; + struct dirent *dent; + struct stat st; + char *format; + DIR *dir; + int count = 0; + int ret; + + dir = opendir(sys); + if (!dir) + die("can't read directory '%s'", sys); + + while ((dent = readdir(dir))) { + if (strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0) + continue; + format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); + sprintf(format, "%s/%s/format", sys, dent->d_name); + ret = stat(format, &st); + free(format); + if (ret < 0) + continue; + count++; + } + + write_or_die(&count, 4); + + rewinddir(dir); + while ((dent = readdir(dir))) { + if (strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0) + continue; + format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); + sprintf(format, "%s/%s/format", sys, dent->d_name); + ret = stat(format, &st); + + if (ret >= 0) { + /* unfortunately, you can not stat debugfs files for size */ + size = get_size(format); + write_or_die(&size, 8); + check_size = copy_file(format); + if (size != check_size) + die("error in size of file '%s'", format); + } + + free(format); + } +} + +static void read_ftrace_files(void) +{ + char *path; + + path = get_tracing_file("events/ftrace"); + + copy_event_system(path); + + put_tracing_file(path); +} + +static void read_event_files(void) +{ + struct dirent *dent; + struct stat st; + char *path; + char *sys; + DIR *dir; + int count = 0; + int ret; + + path = get_tracing_file("events"); + + dir = opendir(path); + if (!dir) + die("can't read directory '%s'", path); + + while ((dent = readdir(dir))) { + if (strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0 || + strcmp(dent->d_name, "ftrace") == 0) + continue; + sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); + sprintf(sys, "%s/%s", path, dent->d_name); + ret = stat(sys, &st); + free(sys); + if (ret < 0) + continue; + if (S_ISDIR(st.st_mode)) + count++; + } + + write_or_die(&count, 4); + + rewinddir(dir); + while ((dent = readdir(dir))) { + if (strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0 || + strcmp(dent->d_name, "ftrace") == 0) + continue; + sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); + sprintf(sys, "%s/%s", path, dent->d_name); + ret = stat(sys, &st); + if (ret >= 0) { + if (S_ISDIR(st.st_mode)) { + write_or_die(dent->d_name, strlen(dent->d_name) + 1); + copy_event_system(sys); + } + } + free(sys); + } + + put_tracing_file(path); +} + +static void read_proc_kallsyms(void) +{ + unsigned int size, check_size; + const char *path = "/proc/kallsyms"; + struct stat st; + int ret; + + ret = stat(path, &st); + if (ret < 0) { + /* not found */ + size = 0; + write_or_die(&size, 4); + return; + } + size = get_size(path); + write_or_die(&size, 4); + check_size = copy_file(path); + if (size != check_size) + die("error in size of file '%s'", path); + +} + +static void read_ftrace_printk(void) +{ + unsigned int size, check_size; + const char *path; + struct stat st; + int ret; + + path = get_tracing_file("printk_formats"); + ret = stat(path, &st); + if (ret < 0) { + /* not found */ + size = 0; + write_or_die(&size, 4); + return; + } + size = get_size(path); + write_or_die(&size, 4); + check_size = copy_file(path); + if (size != check_size) + die("error in size of file '%s'", path); + +} + +void read_tracing_data(void) +{ + char buf[BUFSIZ]; + + output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); + if (output_fd < 0) + die("creating file '%s'", output_file); + + buf[0] = 23; + buf[1] = 8; + buf[2] = 68; + memcpy(buf + 3, "tracing", 7); + + write_or_die(buf, 10); + + write_or_die(VERSION, strlen(VERSION) + 1); + + /* save endian */ + if (bigendian()) + buf[0] = 1; + else + buf[0] = 0; + + write_or_die(buf, 1); + + /* save size of long */ + buf[0] = sizeof(long); + write_or_die(buf, 1); + + /* save page_size */ + page_size = getpagesize(); + write_or_die(&page_size, 4); + + read_header_files(); + read_ftrace_files(); + read_event_files(); + read_proc_kallsyms(); + read_ftrace_printk(); +} diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h new file mode 100644 index 0000000..3ddb894 --- /dev/null +++ b/tools/perf/util/trace-event.h @@ -0,0 +1,238 @@ +#ifndef _PARSE_EVENTS_H +#define _PARSE_EVENTS_H + + +#define __unused __attribute__((unused)) + + +#ifndef PAGE_MASK +#define PAGE_MASK (page_size - 1) +#endif + +enum { + RINGBUF_TYPE_PADDING = 29, + RINGBUF_TYPE_TIME_EXTEND = 30, + RINGBUF_TYPE_TIME_STAMP = 31, +}; + +#ifndef TS_SHIFT +#define TS_SHIFT 27 +#endif + +#define NSECS_PER_SEC 1000000000ULL +#define NSECS_PER_USEC 1000ULL + +enum format_flags { + FIELD_IS_ARRAY = 1, + FIELD_IS_POINTER = 2, +}; + +struct format_field { + struct format_field *next; + char *type; + char *name; + int offset; + int size; + unsigned long flags; +}; + +struct format { + int nr_common; + int nr_fields; + struct format_field *common_fields; + struct format_field *fields; +}; + +struct print_arg_atom { + char *atom; +}; + +struct print_arg_string { + char *string; +}; + +struct print_arg_field { + char *name; + struct format_field *field; +}; + +struct print_flag_sym { + struct print_flag_sym *next; + char *value; + char *str; +}; + +struct print_arg_typecast { + char *type; + struct print_arg *item; +}; + +struct print_arg_flags { + struct print_arg *field; + char *delim; + struct print_flag_sym *flags; +}; + +struct print_arg_symbol { + struct print_arg *field; + struct print_flag_sym *symbols; +}; + +struct print_arg; + +struct print_arg_op { + char *op; + int prio; + struct print_arg *left; + struct print_arg *right; +}; + +struct print_arg_func { + char *name; + struct print_arg *args; +}; + +enum print_arg_type { + PRINT_NULL, + PRINT_ATOM, + PRINT_FIELD, + PRINT_FLAGS, + PRINT_SYMBOL, + PRINT_TYPE, + PRINT_STRING, + PRINT_OP, +}; + +struct print_arg { + struct print_arg *next; + enum print_arg_type type; + union { + struct print_arg_atom atom; + struct print_arg_field field; + struct print_arg_typecast typecast; + struct print_arg_flags flags; + struct print_arg_symbol symbol; + struct print_arg_func func; + struct print_arg_string string; + struct print_arg_op op; + }; +}; + +struct print_fmt { + char *format; + struct print_arg *args; +}; + +struct event { + struct event *next; + char *name; + int id; + int flags; + struct format format; + struct print_fmt print_fmt; +}; + +enum { + EVENT_FL_ISFTRACE = 1, + EVENT_FL_ISPRINT = 2, + EVENT_FL_ISBPRINT = 4, + EVENT_FL_ISFUNC = 8, + EVENT_FL_ISFUNCENT = 16, + EVENT_FL_ISFUNCRET = 32, +}; + +struct record { + unsigned long long ts; + int size; + void *data; +}; + +struct record *trace_peek_data(int cpu); +struct record *trace_read_data(int cpu); + +void parse_set_info(int nr_cpus, int long_sz); + +void trace_report(void); + +void *malloc_or_die(unsigned int size); + +void parse_cmdlines(char *file, int size); +void parse_proc_kallsyms(char *file, unsigned int size); +void parse_ftrace_printk(char *file, unsigned int size); + +void print_funcs(void); +void print_printk(void); + +int parse_ftrace_file(char *buf, unsigned long size); +int parse_event_file(char *buf, unsigned long size, char *system); +void print_event(int cpu, void *data, int size, unsigned long long nsecs, + char *comm); + +extern int file_bigendian; +extern int host_bigendian; + +int bigendian(void); + +static inline unsigned short __data2host2(unsigned short data) +{ + unsigned short swap; + + if (host_bigendian == file_bigendian) + return data; + + swap = ((data & 0xffULL) << 8) | + ((data & (0xffULL << 8)) >> 8); + + return swap; +} + +static inline unsigned int __data2host4(unsigned int data) +{ + unsigned int swap; + + if (host_bigendian == file_bigendian) + return data; + + swap = ((data & 0xffULL) << 24) | + ((data & (0xffULL << 8)) << 8) | + ((data & (0xffULL << 16)) >> 8) | + ((data & (0xffULL << 24)) >> 24); + + return swap; +} + +static inline unsigned long long __data2host8(unsigned long long data) +{ + unsigned long long swap; + + if (host_bigendian == file_bigendian) + return data; + + swap = ((data & 0xffULL) << 56) | + ((data & (0xffULL << 8)) << 40) | + ((data & (0xffULL << 16)) << 24) | + ((data & (0xffULL << 24)) << 8) | + ((data & (0xffULL << 32)) >> 8) | + ((data & (0xffULL << 40)) >> 24) | + ((data & (0xffULL << 48)) >> 40) | + ((data & (0xffULL << 56)) >> 56); + + return swap; +} + +#define data2host2(ptr) __data2host2(*(unsigned short *)ptr) +#define data2host4(ptr) __data2host4(*(unsigned int *)ptr) +#define data2host8(ptr) __data2host8(*(unsigned long long *)ptr) + +extern int header_page_ts_offset; +extern int header_page_ts_size; +extern int header_page_size_offset; +extern int header_page_size_size; +extern int header_page_data_offset; +extern int header_page_data_size; + +int parse_header_page(char *buf, unsigned long size); + +void read_tracing_data(void); + +#endif /* _PARSE_EVENTS_H */ -- cgit v0.10.2 From 538bafb5cc92a86d97b427421231f185574fe3db Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 17 Aug 2009 16:18:06 +0200 Subject: perf tools: Add trace event debugfs stream reader Add util/trace-event-read.c which handles trace events informations reading. This file is a rename of the trace-read.c file from the trace-cmd tools, written by Steven Rostedt and Josh Triplett, originated from the git tree: git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git This is its perf tools integration. [ fweisbec@gmail.com: various changes for perf tools integration. ] Signed-off-by: Steven Rostedt Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: "Luis Claudio R. Goncalves" Cc: Clark Williams Cc: Jon Masters Cc: Mathieu Desnoyers Cc: Christoph Hellwig Cc: Xiao Guangrong Cc: Zhaolei Cc: Li Zefan Cc: Lai Jiangshan Cc: Masami Hiramatsu Cc: Tom Zanussi Cc: "Frank Ch. Eigler" Cc: Roland McGrath Cc: Jason Baron Cc: Paul Mackerras Cc: Jiaying Zhang Cc: Anton Blanchard LKML-Reference: <1250518688-7207-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c new file mode 100644 index 0000000..1dac301 --- /dev/null +++ b/tools/perf/util/trace-event-read.c @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2009, Steven Rostedt + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License (not later!) + * + * 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 _LARGEFILE64_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "trace-event.h" + +static int input_fd; + +static int read_page; + +int file_bigendian; +int host_bigendian; +static int long_size; + +static unsigned long page_size; + +static int read_or_die(void *data, int size) +{ + int r; + + r = read(input_fd, data, size); + if (r != size) + die("reading input file (size expected=%d received=%d)", + size, r); + return r; +} + +static unsigned int read4(void) +{ + unsigned int data; + + read_or_die(&data, 4); + return __data2host4(data); +} + +static unsigned long long read8(void) +{ + unsigned long long data; + + read_or_die(&data, 8); + return __data2host8(data); +} + +static char *read_string(void) +{ + char buf[BUFSIZ]; + char *str = NULL; + int size = 0; + int i; + int r; + + for (;;) { + r = read(input_fd, buf, BUFSIZ); + if (r < 0) + die("reading input file"); + + if (!r) + die("no data"); + + for (i = 0; i < r; i++) { + if (!buf[i]) + break; + } + if (i < r) + break; + + if (str) { + size += BUFSIZ; + str = realloc(str, size); + if (!str) + die("malloc of size %d", size); + memcpy(str + (size - BUFSIZ), buf, BUFSIZ); + } else { + size = BUFSIZ; + str = malloc_or_die(size); + memcpy(str, buf, size); + } + } + + /* move the file descriptor to the end of the string */ + r = lseek(input_fd, -(r - (i+1)), SEEK_CUR); + if (r < 0) + die("lseek"); + + if (str) { + size += i; + str = realloc(str, size); + if (!str) + die("malloc of size %d", size); + memcpy(str + (size - i), buf, i); + } else { + size = i; + str = malloc_or_die(i); + memcpy(str, buf, i); + } + + return str; +} + +static void read_proc_kallsyms(void) +{ + unsigned int size; + char *buf; + + size = read4(); + if (!size) + return; + + buf = malloc_or_die(size); + read_or_die(buf, size); + + parse_proc_kallsyms(buf, size); + + free(buf); +} + +static void read_ftrace_printk(void) +{ + unsigned int size; + char *buf; + + size = read4(); + if (!size) + return; + + buf = malloc_or_die(size); + read_or_die(buf, size); + + parse_ftrace_printk(buf, size); + + free(buf); +} + +static void read_header_files(void) +{ + unsigned long long size; + char *header_page; + char *header_event; + char buf[BUFSIZ]; + + read_or_die(buf, 12); + + if (memcmp(buf, "header_page", 12) != 0) + die("did not read header page"); + + size = read8(); + header_page = malloc_or_die(size); + read_or_die(header_page, size); + parse_header_page(header_page, size); + free(header_page); + + /* + * The size field in the page is of type long, + * use that instead, since it represents the kernel. + */ + long_size = header_page_size_size; + + read_or_die(buf, 13); + if (memcmp(buf, "header_event", 13) != 0) + die("did not read header event"); + + size = read8(); + header_event = malloc_or_die(size); + read_or_die(header_event, size); + free(header_event); +} + +static void read_ftrace_file(unsigned long long size) +{ + char *buf; + + buf = malloc_or_die(size); + read_or_die(buf, size); + parse_ftrace_file(buf, size); + free(buf); +} + +static void read_event_file(char *sys, unsigned long long size) +{ + char *buf; + + buf = malloc_or_die(size); + read_or_die(buf, size); + parse_event_file(buf, size, sys); + free(buf); +} + +static void read_ftrace_files(void) +{ + unsigned long long size; + int count; + int i; + + count = read4(); + + for (i = 0; i < count; i++) { + size = read8(); + read_ftrace_file(size); + } +} + +static void read_event_files(void) +{ + unsigned long long size; + char *sys; + int systems; + int count; + int i,x; + + systems = read4(); + + for (i = 0; i < systems; i++) { + sys = read_string(); + + count = read4(); + for (x=0; x < count; x++) { + size = read8(); + read_event_file(sys, size); + } + } +} + +struct cpu_data { + unsigned long long offset; + unsigned long long size; + unsigned long long timestamp; + struct record *next; + char *page; + int cpu; + int index; + int page_size; +}; + +static struct cpu_data *cpu_data; + +static void update_cpu_data_index(int cpu) +{ + cpu_data[cpu].offset += page_size; + cpu_data[cpu].size -= page_size; + cpu_data[cpu].index = 0; +} + +static void get_next_page(int cpu) +{ + off64_t save_seek; + off64_t ret; + + if (!cpu_data[cpu].page) + return; + + if (read_page) { + if (cpu_data[cpu].size <= page_size) { + free(cpu_data[cpu].page); + cpu_data[cpu].page = NULL; + return; + } + + update_cpu_data_index(cpu); + + /* other parts of the code may expect the pointer to not move */ + save_seek = lseek64(input_fd, 0, SEEK_CUR); + + ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET); + if (ret < 0) + die("failed to lseek"); + ret = read(input_fd, cpu_data[cpu].page, page_size); + if (ret < 0) + die("failed to read page"); + + /* reset the file pointer back */ + lseek64(input_fd, save_seek, SEEK_SET); + + return; + } + + munmap(cpu_data[cpu].page, page_size); + cpu_data[cpu].page = NULL; + + if (cpu_data[cpu].size <= page_size) + return; + + update_cpu_data_index(cpu); + + cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, + input_fd, cpu_data[cpu].offset); + if (cpu_data[cpu].page == MAP_FAILED) + die("failed to mmap cpu %d at offset 0x%llx", + cpu, cpu_data[cpu].offset); +} + +static unsigned int type_len4host(unsigned int type_len_ts) +{ + if (file_bigendian) + return (type_len_ts >> 27) & ((1 << 5) - 1); + else + return type_len_ts & ((1 << 5) - 1); +} + +static unsigned int ts4host(unsigned int type_len_ts) +{ + if (file_bigendian) + return type_len_ts & ((1 << 27) - 1); + else + return type_len_ts >> 5; +} + +static int calc_index(void *ptr, int cpu) +{ + return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; +} + +struct record *trace_peek_data(int cpu) +{ + struct record *data; + void *page = cpu_data[cpu].page; + int idx = cpu_data[cpu].index; + void *ptr = page + idx; + unsigned long long extend; + unsigned int type_len_ts; + unsigned int type_len; + unsigned int delta; + unsigned int length = 0; + + if (cpu_data[cpu].next) + return cpu_data[cpu].next; + + if (!page) + return NULL; + + if (!idx) { + /* FIXME: handle header page */ + if (header_page_ts_size != 8) + die("expected a long long type for timestamp"); + cpu_data[cpu].timestamp = data2host8(ptr); + ptr += 8; + switch (header_page_size_size) { + case 4: + cpu_data[cpu].page_size = data2host4(ptr); + ptr += 4; + break; + case 8: + cpu_data[cpu].page_size = data2host8(ptr); + ptr += 8; + break; + default: + die("bad long size"); + } + ptr = cpu_data[cpu].page + header_page_data_offset; + } + +read_again: + idx = calc_index(ptr, cpu); + + if (idx >= cpu_data[cpu].page_size) { + get_next_page(cpu); + return trace_peek_data(cpu); + } + + type_len_ts = data2host4(ptr); + ptr += 4; + + type_len = type_len4host(type_len_ts); + delta = ts4host(type_len_ts); + + switch (type_len) { + case RINGBUF_TYPE_PADDING: + if (!delta) + die("error, hit unexpected end of page"); + length = data2host4(ptr); + ptr += 4; + length *= 4; + ptr += length; + goto read_again; + + case RINGBUF_TYPE_TIME_EXTEND: + extend = data2host4(ptr); + ptr += 4; + extend <<= TS_SHIFT; + extend += delta; + cpu_data[cpu].timestamp += extend; + goto read_again; + + case RINGBUF_TYPE_TIME_STAMP: + ptr += 12; + break; + case 0: + length = data2host4(ptr); + ptr += 4; + die("here! length=%d", length); + break; + default: + length = type_len * 4; + break; + } + + cpu_data[cpu].timestamp += delta; + + data = malloc_or_die(sizeof(*data)); + memset(data, 0, sizeof(*data)); + + data->ts = cpu_data[cpu].timestamp; + data->size = length; + data->data = ptr; + ptr += length; + + cpu_data[cpu].index = calc_index(ptr, cpu); + cpu_data[cpu].next = data; + + return data; +} + +struct record *trace_read_data(int cpu) +{ + struct record *data; + + data = trace_peek_data(cpu); + cpu_data[cpu].next = NULL; + + return data; +} + +void trace_report (void) +{ + const char *input_file = "trace.info"; + char buf[BUFSIZ]; + char test[] = { 23, 8, 68 }; + char *version; + int show_funcs = 0; + int show_printk = 0; + + input_fd = open(input_file, O_RDONLY); + if (input_fd < 0) + die("opening '%s'\n", input_file); + + read_or_die(buf, 3); + if (memcmp(buf, test, 3) != 0) + die("not an trace data file"); + + read_or_die(buf, 7); + if (memcmp(buf, "tracing", 7) != 0) + die("not a trace file (missing tracing)"); + + version = read_string(); + printf("version = %s\n", version); + free(version); + + read_or_die(buf, 1); + file_bigendian = buf[0]; + host_bigendian = bigendian(); + + read_or_die(buf, 1); + long_size = buf[0]; + + page_size = read4(); + + read_header_files(); + + read_ftrace_files(); + read_event_files(); + read_proc_kallsyms(); + read_ftrace_printk(); + + if (show_funcs) { + print_funcs(); + return; + } + if (show_printk) { + print_printk(); + return; + } + + return; +} -- cgit v0.10.2 From ea4010d1363699770a9894493bafe556a59a144c Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 17 Aug 2009 16:18:07 +0200 Subject: perf tools: Add trace event information parser Add util/trace-event-parse.c which provides the handlers to parse the ftrace events info from the stream and handles the ftrace perf samples event printing. This file is a rename of the parse-events.c file from the trace-cmd tools, written by Steven Rostedt and Josh Triplett, originated from the git tree: git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git This is a perf tools integration. [ fweisbec@gmail.com: various changes for perf tools integration. ] Signed-off-by: Steven Rostedt Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: "Luis Claudio R. Goncalves" Cc: Clark Williams Cc: Jon Masters Cc: Mathieu Desnoyers Cc: Christoph Hellwig Cc: Xiao Guangrong Cc: Zhaolei Cc: Li Zefan Cc: Lai Jiangshan Cc: Masami Hiramatsu Cc: Tom Zanussi Cc: "Frank Ch. Eigler" Cc: Roland McGrath Cc: Jason Baron Cc: Paul Mackerras Cc: Jiaying Zhang Cc: Anton Blanchard LKML-Reference: <1250518688-7207-3-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c new file mode 100644 index 0000000..ead6a9a --- /dev/null +++ b/tools/perf/util/trace-event-parse.c @@ -0,0 +1,2905 @@ +/* + * Copyright (C) 2009, Steven Rostedt + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License (not later!) + * + * 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 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * The parts for function graph printing was taken and modified from the + * Linux Kernel that were written by Frederic Weisbecker. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#undef _GNU_SOURCE +#include "util.h" +#include "trace-event.h" + +int header_page_ts_offset; +int header_page_ts_size; +int header_page_size_offset; +int header_page_size_size; +int header_page_data_offset; +int header_page_data_size; + +static char *input_buf; +static unsigned long long input_buf_ptr; +static unsigned long long input_buf_siz; + +static int cpus; +static int long_size; + +static void init_input_buf(char *buf, unsigned long long size) +{ + input_buf = buf; + input_buf_siz = size; + input_buf_ptr = 0; +} + +struct cmdline { + char *comm; + int pid; +}; + +static struct cmdline *cmdlines; +static int cmdline_count; + +static int cmdline_cmp(const void *a, const void *b) +{ + const struct cmdline *ca = a; + const struct cmdline *cb = b; + + if (ca->pid < cb->pid) + return -1; + if (ca->pid > cb->pid) + return 1; + + return 0; +} + +void parse_cmdlines(char *file, int size __unused) +{ + struct cmdline_list { + struct cmdline_list *next; + char *comm; + int pid; + } *list = NULL, *item; + char *line; + char *next = NULL; + int i; + + line = strtok_r(file, "\n", &next); + while (line) { + item = malloc_or_die(sizeof(*item)); + sscanf(line, "%d %as", &item->pid, + (float *)&item->comm); /* workaround gcc warning */ + item->next = list; + list = item; + line = strtok_r(NULL, "\n", &next); + cmdline_count++; + } + + cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count); + + i = 0; + while (list) { + cmdlines[i].pid = list->pid; + cmdlines[i].comm = list->comm; + i++; + item = list; + list = list->next; + free(item); + } + + qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp); +} + +static struct func_map { + unsigned long long addr; + char *func; + char *mod; +} *func_list; +static unsigned int func_count; + +static int func_cmp(const void *a, const void *b) +{ + const struct func_map *fa = a; + const struct func_map *fb = b; + + if (fa->addr < fb->addr) + return -1; + if (fa->addr > fb->addr) + return 1; + + return 0; +} + +void parse_proc_kallsyms(char *file, unsigned int size __unused) +{ + struct func_list { + struct func_list *next; + unsigned long long addr; + char *func; + char *mod; + } *list = NULL, *item; + char *line; + char *next = NULL; + char *addr_str; + char ch; + int ret; + int i; + + line = strtok_r(file, "\n", &next); + while (line) { + item = malloc_or_die(sizeof(*item)); + item->mod = NULL; + ret = sscanf(line, "%as %c %as\t[%as", + (float *)&addr_str, /* workaround gcc warning */ + &ch, + (float *)&item->func, + (float *)&item->mod); + item->addr = strtoull(addr_str, NULL, 16); + free(addr_str); + + /* truncate the extra ']' */ + if (item->mod) + item->mod[strlen(item->mod) - 1] = 0; + + + item->next = list; + list = item; + line = strtok_r(NULL, "\n", &next); + func_count++; + } + + func_list = malloc_or_die(sizeof(*func_list) * func_count + 1); + + i = 0; + while (list) { + func_list[i].func = list->func; + func_list[i].addr = list->addr; + func_list[i].mod = list->mod; + i++; + item = list; + list = list->next; + free(item); + } + + qsort(func_list, func_count, sizeof(*func_list), func_cmp); + + /* + * Add a special record at the end. + */ + func_list[func_count].func = NULL; + func_list[func_count].addr = 0; + func_list[func_count].mod = NULL; +} + +/* + * We are searching for a record in between, not an exact + * match. + */ +static int func_bcmp(const void *a, const void *b) +{ + const struct func_map *fa = a; + const struct func_map *fb = b; + + if ((fa->addr == fb->addr) || + + (fa->addr > fb->addr && + fa->addr < (fb+1)->addr)) + return 0; + + if (fa->addr < fb->addr) + return -1; + + return 1; +} + +static struct func_map *find_func(unsigned long long addr) +{ + struct func_map *func; + struct func_map key; + + key.addr = addr; + + func = bsearch(&key, func_list, func_count, sizeof(*func_list), + func_bcmp); + + return func; +} + +void print_funcs(void) +{ + int i; + + for (i = 0; i < (int)func_count; i++) { + printf("%016llx %s", + func_list[i].addr, + func_list[i].func); + if (func_list[i].mod) + printf(" [%s]\n", func_list[i].mod); + else + printf("\n"); + } +} + +static struct printk_map { + unsigned long long addr; + char *printk; +} *printk_list; +static unsigned int printk_count; + +static int printk_cmp(const void *a, const void *b) +{ + const struct func_map *fa = a; + const struct func_map *fb = b; + + if (fa->addr < fb->addr) + return -1; + if (fa->addr > fb->addr) + return 1; + + return 0; +} + +static struct printk_map *find_printk(unsigned long long addr) +{ + struct printk_map *printk; + struct printk_map key; + + key.addr = addr; + + printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list), + printk_cmp); + + return printk; +} + +void parse_ftrace_printk(char *file, unsigned int size __unused) +{ + struct printk_list { + struct printk_list *next; + unsigned long long addr; + char *printk; + } *list = NULL, *item; + char *line; + char *next = NULL; + char *addr_str; + int ret; + int i; + + line = strtok_r(file, "\n", &next); + while (line) { + item = malloc_or_die(sizeof(*item)); + ret = sscanf(line, "%as : %as", + (float *)&addr_str, /* workaround gcc warning */ + (float *)&item->printk); + item->addr = strtoull(addr_str, NULL, 16); + free(addr_str); + + item->next = list; + list = item; + line = strtok_r(NULL, "\n", &next); + printk_count++; + } + + printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1); + + i = 0; + while (list) { + printk_list[i].printk = list->printk; + printk_list[i].addr = list->addr; + i++; + item = list; + list = list->next; + free(item); + } + + qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp); +} + +void print_printk(void) +{ + int i; + + for (i = 0; i < (int)printk_count; i++) { + printf("%016llx %s\n", + printk_list[i].addr, + printk_list[i].printk); + } +} + +static struct event *alloc_event(void) +{ + struct event *event; + + event = malloc_or_die(sizeof(*event)); + memset(event, 0, sizeof(*event)); + + return event; +} + +enum event_type { + EVENT_ERROR, + EVENT_NONE, + EVENT_SPACE, + EVENT_NEWLINE, + EVENT_OP, + EVENT_DELIM, + EVENT_ITEM, + EVENT_DQUOTE, + EVENT_SQUOTE, +}; + +static struct event *event_list; + +static void add_event(struct event *event) +{ + event->next = event_list; + event_list = event; +} + +static int event_item_type(enum event_type type) +{ + switch (type) { + case EVENT_ITEM ... EVENT_SQUOTE: + return 1; + case EVENT_ERROR ... EVENT_DELIM: + default: + return 0; + } +} + +static void free_arg(struct print_arg *arg) +{ + if (!arg) + return; + + switch (arg->type) { + case PRINT_ATOM: + if (arg->atom.atom) + free(arg->atom.atom); + break; + case PRINT_NULL: + case PRINT_FIELD ... PRINT_OP: + default: + /* todo */ + break; + } + + free(arg); +} + +static enum event_type get_type(int ch) +{ + if (ch == '\n') + return EVENT_NEWLINE; + if (isspace(ch)) + return EVENT_SPACE; + if (isalnum(ch) || ch == '_') + return EVENT_ITEM; + if (ch == '\'') + return EVENT_SQUOTE; + if (ch == '"') + return EVENT_DQUOTE; + if (!isprint(ch)) + return EVENT_NONE; + if (ch == '(' || ch == ')' || ch == ',') + return EVENT_DELIM; + + return EVENT_OP; +} + +static int __read_char(void) +{ + if (input_buf_ptr >= input_buf_siz) + return -1; + + return input_buf[input_buf_ptr++]; +} + +static int __peek_char(void) +{ + if (input_buf_ptr >= input_buf_siz) + return -1; + + return input_buf[input_buf_ptr]; +} + +static enum event_type __read_token(char **tok) +{ + char buf[BUFSIZ]; + int ch, last_ch, quote_ch, next_ch; + int i = 0; + int tok_size = 0; + enum event_type type; + + *tok = NULL; + + + ch = __read_char(); + if (ch < 0) + return EVENT_NONE; + + type = get_type(ch); + if (type == EVENT_NONE) + return type; + + buf[i++] = ch; + + switch (type) { + case EVENT_NEWLINE: + case EVENT_DELIM: + *tok = malloc_or_die(2); + (*tok)[0] = ch; + (*tok)[1] = 0; + return type; + + case EVENT_OP: + switch (ch) { + case '-': + next_ch = __peek_char(); + if (next_ch == '>') { + buf[i++] = __read_char(); + break; + } + /* fall through */ + case '+': + case '|': + case '&': + case '>': + case '<': + last_ch = ch; + ch = __peek_char(); + if (ch != last_ch) + goto test_equal; + buf[i++] = __read_char(); + switch (last_ch) { + case '>': + case '<': + goto test_equal; + default: + break; + } + break; + case '!': + case '=': + goto test_equal; + default: /* what should we do instead? */ + break; + } + buf[i] = 0; + *tok = strdup(buf); + return type; + + test_equal: + ch = __peek_char(); + if (ch == '=') + buf[i++] = __read_char(); + break; + + case EVENT_DQUOTE: + case EVENT_SQUOTE: + /* don't keep quotes */ + i--; + quote_ch = ch; + last_ch = 0; + do { + if (i == (BUFSIZ - 1)) { + buf[i] = 0; + if (*tok) { + *tok = realloc(*tok, tok_size + BUFSIZ); + if (!*tok) + return EVENT_NONE; + strcat(*tok, buf); + } else + *tok = strdup(buf); + + if (!*tok) + return EVENT_NONE; + tok_size += BUFSIZ; + i = 0; + } + last_ch = ch; + ch = __read_char(); + buf[i++] = ch; + } while (ch != quote_ch && last_ch != '\\'); + /* remove the last quote */ + i--; + goto out; + + case EVENT_ERROR ... EVENT_SPACE: + case EVENT_ITEM: + default: + break; + } + + while (get_type(__peek_char()) == type) { + if (i == (BUFSIZ - 1)) { + buf[i] = 0; + if (*tok) { + *tok = realloc(*tok, tok_size + BUFSIZ); + if (!*tok) + return EVENT_NONE; + strcat(*tok, buf); + } else + *tok = strdup(buf); + + if (!*tok) + return EVENT_NONE; + tok_size += BUFSIZ; + i = 0; + } + ch = __read_char(); + buf[i++] = ch; + } + + out: + buf[i] = 0; + if (*tok) { + *tok = realloc(*tok, tok_size + i); + if (!*tok) + return EVENT_NONE; + strcat(*tok, buf); + } else + *tok = strdup(buf); + if (!*tok) + return EVENT_NONE; + + return type; +} + +static void free_token(char *tok) +{ + if (tok) + free(tok); +} + +static enum event_type read_token(char **tok) +{ + enum event_type type; + + for (;;) { + type = __read_token(tok); + if (type != EVENT_SPACE) + return type; + + free_token(*tok); + } + + /* not reached */ + return EVENT_NONE; +} + +/* no newline */ +static enum event_type read_token_item(char **tok) +{ + enum event_type type; + + for (;;) { + type = __read_token(tok); + if (type != EVENT_SPACE && type != EVENT_NEWLINE) + return type; + + free_token(*tok); + } + + /* not reached */ + return EVENT_NONE; +} + +static int test_type(enum event_type type, enum event_type expect) +{ + if (type != expect) { + die("Error: expected type %d but read %d", + expect, type); + return -1; + } + return 0; +} + +static int test_type_token(enum event_type type, char *token, + enum event_type expect, char *expect_tok) +{ + if (type != expect) { + die("Error: expected type %d but read %d", + expect, type); + return -1; + } + + if (strcmp(token, expect_tok) != 0) { + die("Error: expected '%s' but read '%s'", + expect_tok, token); + return -1; + } + return 0; +} + +static int __read_expect_type(enum event_type expect, char **tok, int newline_ok) +{ + enum event_type type; + + if (newline_ok) + type = read_token(tok); + else + type = read_token_item(tok); + return test_type(type, expect); +} + +static int read_expect_type(enum event_type expect, char **tok) +{ + return __read_expect_type(expect, tok, 1); +} + +static int __read_expected(enum event_type expect, char *str, int newline_ok) +{ + enum event_type type; + char *token; + int ret; + + if (newline_ok) + type = read_token(&token); + else + type = read_token_item(&token); + + ret = test_type_token(type, token, expect, str); + + free_token(token); + + return 0; +} + +static int read_expected(enum event_type expect, char *str) +{ + return __read_expected(expect, str, 1); +} + +static int read_expected_item(enum event_type expect, char *str) +{ + return __read_expected(expect, str, 0); +} + +static char *event_read_name(void) +{ + char *token; + + if (read_expected(EVENT_ITEM, (char *)"name") < 0) + return NULL; + + if (read_expected(EVENT_OP, (char *)":") < 0) + return NULL; + + if (read_expect_type(EVENT_ITEM, &token) < 0) + goto fail; + + return token; + + fail: + free_token(token); + return NULL; +} + +static int event_read_id(void) +{ + char *token; + int id; + + if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0) + return -1; + + if (read_expected(EVENT_OP, (char *)":") < 0) + return -1; + + if (read_expect_type(EVENT_ITEM, &token) < 0) + goto fail; + + id = strtoul(token, NULL, 0); + free_token(token); + return id; + + fail: + free_token(token); + return -1; +} + +static int event_read_fields(struct event *event, struct format_field **fields) +{ + struct format_field *field = NULL; + enum event_type type; + char *token; + char *last_token; + int count = 0; + + do { + type = read_token(&token); + if (type == EVENT_NEWLINE) { + free_token(token); + return count; + } + + count++; + + if (test_type_token(type, token, EVENT_ITEM, (char *)"field")) + goto fail; + free_token(token); + + type = read_token(&token); + /* + * The ftrace fields may still use the "special" name. + * Just ignore it. + */ + if (event->flags & EVENT_FL_ISFTRACE && + type == EVENT_ITEM && strcmp(token, "special") == 0) { + free_token(token); + type = read_token(&token); + } + + if (test_type_token(type, token, EVENT_OP, (char *)":") < 0) + return -1; + + if (read_expect_type(EVENT_ITEM, &token) < 0) + goto fail; + + last_token = token; + + field = malloc_or_die(sizeof(*field)); + memset(field, 0, sizeof(*field)); + + /* read the rest of the type */ + for (;;) { + type = read_token(&token); + if (type == EVENT_ITEM || + (type == EVENT_OP && strcmp(token, "*") == 0) || + /* + * Some of the ftrace fields are broken and have + * an illegal "." in them. + */ + (event->flags & EVENT_FL_ISFTRACE && + type == EVENT_OP && strcmp(token, ".") == 0)) { + + if (strcmp(token, "*") == 0) + field->flags |= FIELD_IS_POINTER; + + if (field->type) { + field->type = realloc(field->type, + strlen(field->type) + + strlen(last_token) + 2); + strcat(field->type, " "); + strcat(field->type, last_token); + } else + field->type = last_token; + last_token = token; + continue; + } + + break; + } + + if (!field->type) { + die("no type found"); + goto fail; + } + field->name = last_token; + + if (test_type(type, EVENT_OP)) + goto fail; + + if (strcmp(token, "[") == 0) { + enum event_type last_type = type; + char *brackets = token; + int len; + + field->flags |= FIELD_IS_ARRAY; + + type = read_token(&token); + while (strcmp(token, "]") != 0) { + if (last_type == EVENT_ITEM && + type == EVENT_ITEM) + len = 2; + else + len = 1; + last_type = type; + + brackets = realloc(brackets, + strlen(brackets) + + strlen(token) + len); + if (len == 2) + strcat(brackets, " "); + strcat(brackets, token); + free_token(token); + type = read_token(&token); + if (type == EVENT_NONE) { + die("failed to find token"); + goto fail; + } + } + + free_token(token); + + brackets = realloc(brackets, strlen(brackets) + 2); + strcat(brackets, "]"); + + /* add brackets to type */ + + type = read_token(&token); + /* + * If the next token is not an OP, then it is of + * the format: type [] item; + */ + if (type == EVENT_ITEM) { + field->type = realloc(field->type, + strlen(field->type) + + strlen(field->name) + + strlen(brackets) + 2); + strcat(field->type, " "); + strcat(field->type, field->name); + free_token(field->name); + strcat(field->type, brackets); + field->name = token; + type = read_token(&token); + } else { + field->type = realloc(field->type, + strlen(field->type) + + strlen(brackets) + 1); + strcat(field->type, brackets); + } + free(brackets); + } + + if (test_type_token(type, token, EVENT_OP, (char *)";")) + goto fail; + free_token(token); + + if (read_expected(EVENT_ITEM, (char *)"offset") < 0) + goto fail_expect; + + if (read_expected(EVENT_OP, (char *)":") < 0) + goto fail_expect; + + if (read_expect_type(EVENT_ITEM, &token)) + goto fail; + field->offset = strtoul(token, NULL, 0); + free_token(token); + + if (read_expected(EVENT_OP, (char *)";") < 0) + goto fail_expect; + + if (read_expected(EVENT_ITEM, (char *)"size") < 0) + goto fail_expect; + + if (read_expected(EVENT_OP, (char *)":") < 0) + goto fail_expect; + + if (read_expect_type(EVENT_ITEM, &token)) + goto fail; + field->size = strtoul(token, NULL, 0); + free_token(token); + + if (read_expected(EVENT_OP, (char *)";") < 0) + goto fail_expect; + + if (read_expect_type(EVENT_NEWLINE, &token) < 0) + goto fail; + free_token(token); + + *fields = field; + fields = &field->next; + + } while (1); + + return 0; + +fail: + free_token(token); +fail_expect: + if (field) + free(field); + return -1; +} + +static int event_read_format(struct event *event) +{ + char *token; + int ret; + + if (read_expected_item(EVENT_ITEM, (char *)"format") < 0) + return -1; + + if (read_expected(EVENT_OP, (char *)":") < 0) + return -1; + + if (read_expect_type(EVENT_NEWLINE, &token)) + goto fail; + free_token(token); + + ret = event_read_fields(event, &event->format.common_fields); + if (ret < 0) + return ret; + event->format.nr_common = ret; + + ret = event_read_fields(event, &event->format.fields); + if (ret < 0) + return ret; + event->format.nr_fields = ret; + + return 0; + + fail: + free_token(token); + return -1; +} + +enum event_type +process_arg_token(struct event *event, struct print_arg *arg, + char **tok, enum event_type type); + +static enum event_type +process_arg(struct event *event, struct print_arg *arg, char **tok) +{ + enum event_type type; + char *token; + + type = read_token(&token); + *tok = token; + + return process_arg_token(event, arg, tok, type); +} + +static enum event_type +process_cond(struct event *event, struct print_arg *top, char **tok) +{ + struct print_arg *arg, *left, *right; + enum event_type type; + char *token = NULL; + + arg = malloc_or_die(sizeof(*arg)); + memset(arg, 0, sizeof(*arg)); + + left = malloc_or_die(sizeof(*left)); + + right = malloc_or_die(sizeof(*right)); + + arg->type = PRINT_OP; + arg->op.left = left; + arg->op.right = right; + + *tok = NULL; + type = process_arg(event, left, &token); + if (test_type_token(type, token, EVENT_OP, (char *)":")) + goto out_free; + + arg->op.op = token; + + type = process_arg(event, right, &token); + + top->op.right = arg; + + *tok = token; + return type; + +out_free: + free_token(*tok); + free(right); + free(left); + free_arg(arg); + return EVENT_ERROR; +} + +static int get_op_prio(char *op) +{ + if (!op[1]) { + switch (op[0]) { + case '*': + case '/': + case '%': + return 6; + case '+': + case '-': + return 7; + /* '>>' and '<<' are 8 */ + case '<': + case '>': + return 9; + /* '==' and '!=' are 10 */ + case '&': + return 11; + case '^': + return 12; + case '|': + return 13; + case '?': + return 16; + default: + die("unknown op '%c'", op[0]); + return -1; + } + } else { + if (strcmp(op, "++") == 0 || + strcmp(op, "--") == 0) { + return 3; + } else if (strcmp(op, ">>") == 0 || + strcmp(op, "<<") == 0) { + return 8; + } else if (strcmp(op, ">=") == 0 || + strcmp(op, "<=") == 0) { + return 9; + } else if (strcmp(op, "==") == 0 || + strcmp(op, "!=") == 0) { + return 10; + } else if (strcmp(op, "&&") == 0) { + return 14; + } else if (strcmp(op, "||") == 0) { + return 15; + } else { + die("unknown op '%s'", op); + return -1; + } + } +} + +static void set_op_prio(struct print_arg *arg) +{ + + /* single ops are the greatest */ + if (!arg->op.left || arg->op.left->type == PRINT_NULL) { + arg->op.prio = 0; + return; + } + + arg->op.prio = get_op_prio(arg->op.op); +} + +static enum event_type +process_op(struct event *event, struct print_arg *arg, char **tok) +{ + struct print_arg *left, *right = NULL; + enum event_type type; + char *token; + + /* the op is passed in via tok */ + token = *tok; + + if (arg->type == PRINT_OP && !arg->op.left) { + /* handle single op */ + if (token[1]) { + die("bad op token %s", token); + return EVENT_ERROR; + } + switch (token[0]) { + case '!': + case '+': + case '-': + break; + default: + die("bad op token %s", token); + return EVENT_ERROR; + } + + /* make an empty left */ + left = malloc_or_die(sizeof(*left)); + left->type = PRINT_NULL; + arg->op.left = left; + + right = malloc_or_die(sizeof(*right)); + arg->op.right = right; + + type = process_arg(event, right, tok); + + } else if (strcmp(token, "?") == 0) { + + left = malloc_or_die(sizeof(*left)); + /* copy the top arg to the left */ + *left = *arg; + + arg->type = PRINT_OP; + arg->op.op = token; + arg->op.left = left; + arg->op.prio = 0; + + type = process_cond(event, arg, tok); + + } else if (strcmp(token, ">>") == 0 || + strcmp(token, "<<") == 0 || + strcmp(token, "&") == 0 || + strcmp(token, "|") == 0 || + strcmp(token, "&&") == 0 || + strcmp(token, "||") == 0 || + strcmp(token, "-") == 0 || + strcmp(token, "+") == 0 || + strcmp(token, "*") == 0 || + strcmp(token, "^") == 0 || + strcmp(token, "/") == 0 || + strcmp(token, "==") == 0 || + strcmp(token, "!=") == 0) { + + left = malloc_or_die(sizeof(*left)); + + /* copy the top arg to the left */ + *left = *arg; + + arg->type = PRINT_OP; + arg->op.op = token; + arg->op.left = left; + + set_op_prio(arg); + + right = malloc_or_die(sizeof(*right)); + + type = process_arg(event, right, tok); + + arg->op.right = right; + + } else { + die("unknown op '%s'", token); + /* the arg is now the left side */ + return EVENT_NONE; + } + + + if (type == EVENT_OP) { + int prio; + + /* higher prios need to be closer to the root */ + prio = get_op_prio(*tok); + + if (prio > arg->op.prio) + return process_op(event, arg, tok); + + return process_op(event, right, tok); + } + + return type; +} + +static enum event_type +process_entry(struct event *event __unused, struct print_arg *arg, + char **tok) +{ + enum event_type type; + char *field; + char *token; + + if (read_expected(EVENT_OP, (char *)"->") < 0) + return EVENT_ERROR; + + if (read_expect_type(EVENT_ITEM, &token) < 0) + goto fail; + field = token; + + arg->type = PRINT_FIELD; + arg->field.name = field; + + type = read_token(&token); + *tok = token; + + return type; + +fail: + free_token(token); + return EVENT_ERROR; +} + +static char *arg_eval (struct print_arg *arg); + +static long long arg_num_eval(struct print_arg *arg) +{ + long long left, right; + long long val = 0; + + switch (arg->type) { + case PRINT_ATOM: + val = strtoll(arg->atom.atom, NULL, 0); + break; + case PRINT_TYPE: + val = arg_num_eval(arg->typecast.item); + break; + case PRINT_OP: + switch (arg->op.op[0]) { + case '|': + left = arg_num_eval(arg->op.left); + right = arg_num_eval(arg->op.right); + if (arg->op.op[1]) + val = left || right; + else + val = left | right; + break; + case '&': + left = arg_num_eval(arg->op.left); + right = arg_num_eval(arg->op.right); + if (arg->op.op[1]) + val = left && right; + else + val = left & right; + break; + case '<': + left = arg_num_eval(arg->op.left); + right = arg_num_eval(arg->op.right); + switch (arg->op.op[1]) { + case 0: + val = left < right; + break; + case '<': + val = left << right; + break; + case '=': + val = left <= right; + break; + default: + die("unknown op '%s'", arg->op.op); + } + break; + case '>': + left = arg_num_eval(arg->op.left); + right = arg_num_eval(arg->op.right); + switch (arg->op.op[1]) { + case 0: + val = left > right; + break; + case '>': + val = left >> right; + break; + case '=': + val = left >= right; + break; + default: + die("unknown op '%s'", arg->op.op); + } + break; + case '=': + left = arg_num_eval(arg->op.left); + right = arg_num_eval(arg->op.right); + + if (arg->op.op[1] != '=') + die("unknown op '%s'", arg->op.op); + + val = left == right; + break; + case '!': + left = arg_num_eval(arg->op.left); + right = arg_num_eval(arg->op.right); + + switch (arg->op.op[1]) { + case '=': + val = left != right; + break; + default: + die("unknown op '%s'", arg->op.op); + } + break; + default: + die("unknown op '%s'", arg->op.op); + } + break; + + case PRINT_NULL: + case PRINT_FIELD ... PRINT_SYMBOL: + case PRINT_STRING: + default: + die("invalid eval type %d", arg->type); + + } + return val; +} + +static char *arg_eval (struct print_arg *arg) +{ + long long val; + static char buf[20]; + + switch (arg->type) { + case PRINT_ATOM: + return arg->atom.atom; + case PRINT_TYPE: + return arg_eval(arg->typecast.item); + case PRINT_OP: + val = arg_num_eval(arg); + sprintf(buf, "%lld", val); + return buf; + + case PRINT_NULL: + case PRINT_FIELD ... PRINT_SYMBOL: + case PRINT_STRING: + default: + die("invalid eval type %d", arg->type); + break; + } + + return NULL; +} + +static enum event_type +process_fields(struct event *event, struct print_flag_sym **list, char **tok) +{ + enum event_type type; + struct print_arg *arg = NULL; + struct print_flag_sym *field; + char *token = NULL; + char *value; + + do { + free_token(token); + type = read_token_item(&token); + if (test_type_token(type, token, EVENT_OP, (char *)"{")) + break; + + arg = malloc_or_die(sizeof(*arg)); + + free_token(token); + type = process_arg(event, arg, &token); + if (test_type_token(type, token, EVENT_DELIM, (char *)",")) + goto out_free; + + field = malloc_or_die(sizeof(*field)); + memset(field, 0, sizeof(field)); + + value = arg_eval(arg); + field->value = strdup(value); + + free_token(token); + type = process_arg(event, arg, &token); + if (test_type_token(type, token, EVENT_OP, (char *)"}")) + goto out_free; + + value = arg_eval(arg); + field->str = strdup(value); + free_arg(arg); + arg = NULL; + + *list = field; + list = &field->next; + + free_token(token); + type = read_token_item(&token); + } while (type == EVENT_DELIM && strcmp(token, ",") == 0); + + *tok = token; + return type; + +out_free: + free_arg(arg); + free_token(token); + + return EVENT_ERROR; +} + +static enum event_type +process_flags(struct event *event, struct print_arg *arg, char **tok) +{ + struct print_arg *field; + enum event_type type; + char *token; + + memset(arg, 0, sizeof(*arg)); + arg->type = PRINT_FLAGS; + + if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) + return EVENT_ERROR; + + field = malloc_or_die(sizeof(*field)); + + type = process_arg(event, field, &token); + if (test_type_token(type, token, EVENT_DELIM, (char *)",")) + goto out_free; + + arg->flags.field = field; + + type = read_token_item(&token); + if (event_item_type(type)) { + arg->flags.delim = token; + type = read_token_item(&token); + } + + if (test_type_token(type, token, EVENT_DELIM, (char *)",")) + goto out_free; + + type = process_fields(event, &arg->flags.flags, &token); + if (test_type_token(type, token, EVENT_DELIM, (char *)")")) + goto out_free; + + free_token(token); + type = read_token_item(tok); + return type; + +out_free: + free_token(token); + return EVENT_ERROR; +} + +static enum event_type +process_symbols(struct event *event, struct print_arg *arg, char **tok) +{ + struct print_arg *field; + enum event_type type; + char *token; + + memset(arg, 0, sizeof(*arg)); + arg->type = PRINT_SYMBOL; + + if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) + return EVENT_ERROR; + + field = malloc_or_die(sizeof(*field)); + + type = process_arg(event, field, &token); + if (test_type_token(type, token, EVENT_DELIM, (char *)",")) + goto out_free; + + arg->symbol.field = field; + + type = process_fields(event, &arg->symbol.symbols, &token); + if (test_type_token(type, token, EVENT_DELIM, (char *)")")) + goto out_free; + + free_token(token); + type = read_token_item(tok); + return type; + +out_free: + free_token(token); + return EVENT_ERROR; +} + +static enum event_type +process_paren(struct event *event, struct print_arg *arg, char **tok) +{ + struct print_arg *item_arg; + enum event_type type; + char *token; + + type = process_arg(event, arg, &token); + + if (type == EVENT_ERROR) + return EVENT_ERROR; + + if (type == EVENT_OP) + type = process_op(event, arg, &token); + + if (type == EVENT_ERROR) + return EVENT_ERROR; + + if (test_type_token(type, token, EVENT_DELIM, (char *)")")) { + free_token(token); + return EVENT_ERROR; + } + + free_token(token); + type = read_token_item(&token); + + /* + * If the next token is an item or another open paren, then + * this was a typecast. + */ + if (event_item_type(type) || + (type == EVENT_DELIM && strcmp(token, "(") == 0)) { + + /* make this a typecast and contine */ + + /* prevous must be an atom */ + if (arg->type != PRINT_ATOM) + die("previous needed to be PRINT_ATOM"); + + item_arg = malloc_or_die(sizeof(*item_arg)); + + arg->type = PRINT_TYPE; + arg->typecast.type = arg->atom.atom; + arg->typecast.item = item_arg; + type = process_arg_token(event, item_arg, &token, type); + + } + + *tok = token; + return type; +} + + +static enum event_type +process_str(struct event *event __unused, struct print_arg *arg, char **tok) +{ + enum event_type type; + char *token; + + if (read_expected(EVENT_DELIM, (char *)"(") < 0) + return EVENT_ERROR; + + if (read_expect_type(EVENT_ITEM, &token) < 0) + goto fail; + + arg->type = PRINT_STRING; + arg->string.string = token; + + if (read_expected(EVENT_DELIM, (char *)")") < 0) + return EVENT_ERROR; + + type = read_token(&token); + *tok = token; + + return type; +fail: + free_token(token); + return EVENT_ERROR; +} + +enum event_type +process_arg_token(struct event *event, struct print_arg *arg, + char **tok, enum event_type type) +{ + char *token; + char *atom; + + token = *tok; + + switch (type) { + case EVENT_ITEM: + if (strcmp(token, "REC") == 0) { + free_token(token); + type = process_entry(event, arg, &token); + } else if (strcmp(token, "__print_flags") == 0) { + free_token(token); + type = process_flags(event, arg, &token); + } else if (strcmp(token, "__print_symbolic") == 0) { + free_token(token); + type = process_symbols(event, arg, &token); + } else if (strcmp(token, "__get_str") == 0) { + free_token(token); + type = process_str(event, arg, &token); + } else { + atom = token; + /* test the next token */ + type = read_token_item(&token); + + /* atoms can be more than one token long */ + while (type == EVENT_ITEM) { + atom = realloc(atom, strlen(atom) + strlen(token) + 2); + strcat(atom, " "); + strcat(atom, token); + free_token(token); + type = read_token_item(&token); + } + + /* todo, test for function */ + + arg->type = PRINT_ATOM; + arg->atom.atom = atom; + } + break; + case EVENT_DQUOTE: + case EVENT_SQUOTE: + arg->type = PRINT_ATOM; + arg->atom.atom = token; + type = read_token_item(&token); + break; + case EVENT_DELIM: + if (strcmp(token, "(") == 0) { + free_token(token); + type = process_paren(event, arg, &token); + break; + } + case EVENT_OP: + /* handle single ops */ + arg->type = PRINT_OP; + arg->op.op = token; + arg->op.left = NULL; + type = process_op(event, arg, &token); + + break; + + case EVENT_ERROR ... EVENT_NEWLINE: + default: + die("unexpected type %d", type); + } + *tok = token; + + return type; +} + +static int event_read_print_args(struct event *event, struct print_arg **list) +{ + enum event_type type; + struct print_arg *arg; + char *token; + int args = 0; + + do { + arg = malloc_or_die(sizeof(*arg)); + memset(arg, 0, sizeof(*arg)); + + type = process_arg(event, arg, &token); + + if (type == EVENT_ERROR) { + free_arg(arg); + return -1; + } + + *list = arg; + args++; + + if (type == EVENT_OP) { + type = process_op(event, arg, &token); + list = &arg->next; + continue; + } + + if (type == EVENT_DELIM && strcmp(token, ",") == 0) { + free_token(token); + *list = arg; + list = &arg->next; + continue; + } + break; + } while (type != EVENT_NONE); + + if (type != EVENT_NONE) + free_token(token); + + return args; +} + +static int event_read_print(struct event *event) +{ + enum event_type type; + char *token; + int ret; + + if (read_expected_item(EVENT_ITEM, (char *)"print") < 0) + return -1; + + if (read_expected(EVENT_ITEM, (char *)"fmt") < 0) + return -1; + + if (read_expected(EVENT_OP, (char *)":") < 0) + return -1; + + if (read_expect_type(EVENT_DQUOTE, &token) < 0) + goto fail; + + event->print_fmt.format = token; + event->print_fmt.args = NULL; + + /* ok to have no arg */ + type = read_token_item(&token); + + if (type == EVENT_NONE) + return 0; + + if (test_type_token(type, token, EVENT_DELIM, (char *)",")) + goto fail; + + free_token(token); + + ret = event_read_print_args(event, &event->print_fmt.args); + if (ret < 0) + return -1; + + return 0; + + fail: + free_token(token); + return -1; +} + +static struct format_field * +find_common_field(struct event *event, const char *name) +{ + struct format_field *format; + + for (format = event->format.common_fields; + format; format = format->next) { + if (strcmp(format->name, name) == 0) + break; + } + + return format; +} + +static struct format_field * +find_field(struct event *event, const char *name) +{ + struct format_field *format; + + for (format = event->format.fields; + format; format = format->next) { + if (strcmp(format->name, name) == 0) + break; + } + + return format; +} + +static struct format_field * +find_any_field(struct event *event, const char *name) +{ + struct format_field *format; + + format = find_common_field(event, name); + if (format) + return format; + return find_field(event, name); +} + +static unsigned long long read_size(void *ptr, int size) +{ + switch (size) { + case 1: + return *(unsigned char *)ptr; + case 2: + return data2host2(ptr); + case 4: + return data2host4(ptr); + case 8: + return data2host8(ptr); + default: + /* BUG! */ + return 0; + } +} + +static int get_common_info(const char *type, int *offset, int *size) +{ + struct event *event; + struct format_field *field; + + /* + * All events should have the same common elements. + * Pick any event to find where the type is; + */ + if (!event_list) + die("no event_list!"); + + event = event_list; + field = find_common_field(event, type); + if (!field) + die("field '%s' not found", type); + + *offset = field->offset; + *size = field->size; + + return 0; +} + +static int parse_common_type(void *data) +{ + static int type_offset; + static int type_size; + int ret; + + if (!type_size) { + ret = get_common_info("common_type", + &type_offset, + &type_size); + if (ret < 0) + return ret; + } + return read_size(data + type_offset, type_size); +} + +static int parse_common_pid(void *data) +{ + static int pid_offset; + static int pid_size; + int ret; + + if (!pid_size) { + ret = get_common_info("common_pid", + &pid_offset, + &pid_size); + if (ret < 0) + return ret; + } + + return read_size(data + pid_offset, pid_size); +} + +static struct event *find_event(int id) +{ + struct event *event; + + for (event = event_list; event; event = event->next) { + if (event->id == id) + break; + } + return event; +} + +static unsigned long long eval_num_arg(void *data, int size, + struct event *event, struct print_arg *arg) +{ + unsigned long long val = 0; + unsigned long long left, right; + + switch (arg->type) { + case PRINT_NULL: + /* ?? */ + return 0; + case PRINT_ATOM: + return strtoull(arg->atom.atom, NULL, 0); + case PRINT_FIELD: + if (!arg->field.field) { + arg->field.field = find_any_field(event, arg->field.name); + if (!arg->field.field) + die("field %s not found", arg->field.name); + } + /* must be a number */ + val = read_size(data + arg->field.field->offset, + arg->field.field->size); + break; + case PRINT_FLAGS: + case PRINT_SYMBOL: + break; + case PRINT_TYPE: + return eval_num_arg(data, size, event, arg->typecast.item); + case PRINT_STRING: + return 0; + break; + case PRINT_OP: + left = eval_num_arg(data, size, event, arg->op.left); + right = eval_num_arg(data, size, event, arg->op.right); + switch (arg->op.op[0]) { + case '|': + if (arg->op.op[1]) + val = left || right; + else + val = left | right; + break; + case '&': + if (arg->op.op[1]) + val = left && right; + else + val = left & right; + break; + case '<': + switch (arg->op.op[1]) { + case 0: + val = left < right; + break; + case '<': + val = left << right; + break; + case '=': + val = left <= right; + break; + default: + die("unknown op '%s'", arg->op.op); + } + break; + case '>': + switch (arg->op.op[1]) { + case 0: + val = left > right; + break; + case '>': + val = left >> right; + break; + case '=': + val = left >= right; + break; + default: + die("unknown op '%s'", arg->op.op); + } + break; + case '=': + if (arg->op.op[1] != '=') + die("unknown op '%s'", arg->op.op); + val = left == right; + break; + default: + die("unknown op '%s'", arg->op.op); + } + break; + default: /* not sure what to do there */ + return 0; + } + return val; +} + +struct flag { + const char *name; + unsigned long long value; +}; + +static const struct flag flags[] = { + { "HI_SOFTIRQ", 0 }, + { "TIMER_SOFTIRQ", 1 }, + { "NET_TX_SOFTIRQ", 2 }, + { "NET_RX_SOFTIRQ", 3 }, + { "BLOCK_SOFTIRQ", 4 }, + { "TASKLET_SOFTIRQ", 5 }, + { "SCHED_SOFTIRQ", 6 }, + { "HRTIMER_SOFTIRQ", 7 }, + { "RCU_SOFTIRQ", 8 }, + + { "HRTIMER_NORESTART", 0 }, + { "HRTIMER_RESTART", 1 }, +}; + +static unsigned long long eval_flag(const char *flag) +{ + int i; + + /* + * Some flags in the format files do not get converted. + * If the flag is not numeric, see if it is something that + * we already know about. + */ + if (isdigit(flag[0])) + return strtoull(flag, NULL, 0); + + for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) + if (strcmp(flags[i].name, flag) == 0) + return flags[i].value; + + return 0; +} + +static void print_str_arg(void *data, int size, + struct event *event, struct print_arg *arg) +{ + struct print_flag_sym *flag; + unsigned long long val, fval; + char *str; + int print; + + switch (arg->type) { + case PRINT_NULL: + /* ?? */ + return; + case PRINT_ATOM: + printf("%s", arg->atom.atom); + return; + case PRINT_FIELD: + if (!arg->field.field) { + arg->field.field = find_any_field(event, arg->field.name); + if (!arg->field.field) + die("field %s not found", arg->field.name); + } + str = malloc_or_die(arg->field.field->size + 1); + memcpy(str, data + arg->field.field->offset, + arg->field.field->size); + str[arg->field.field->size] = 0; + free(str); + break; + case PRINT_FLAGS: + val = eval_num_arg(data, size, event, arg->flags.field); + print = 0; + for (flag = arg->flags.flags; flag; flag = flag->next) { + fval = eval_flag(flag->value); + if (!val && !fval) { + printf("%s", flag->str); + break; + } + if (fval && (val & fval) == fval) { + if (print && arg->flags.delim) + printf("%s", arg->flags.delim); + printf("%s", flag->str); + print = 1; + val &= ~fval; + } + } + break; + case PRINT_SYMBOL: + val = eval_num_arg(data, size, event, arg->symbol.field); + for (flag = arg->symbol.symbols; flag; flag = flag->next) { + fval = eval_flag(flag->value); + if (val == fval) { + printf("%s", flag->str); + break; + } + } + break; + + case PRINT_TYPE: + break; + case PRINT_STRING: + printf("%s", arg->string.string); + break; + case PRINT_OP: + /* + * The only op for string should be ? : + */ + if (arg->op.op[0] != '?') + return; + val = eval_num_arg(data, size, event, arg->op.left); + if (val) + print_str_arg(data, size, event, arg->op.right->op.left); + else + print_str_arg(data, size, event, arg->op.right->op.right); + break; + default: + /* well... */ + break; + } +} + +static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event) +{ + static struct format_field *field, *ip_field; + struct print_arg *args, *arg, **next; + unsigned long long ip, val; + char *ptr; + void *bptr; + + if (!field) { + field = find_field(event, "buf"); + if (!field) + die("can't find buffer field for binary printk"); + ip_field = find_field(event, "ip"); + if (!ip_field) + die("can't find ip field for binary printk"); + } + + ip = read_size(data + ip_field->offset, ip_field->size); + + /* + * The first arg is the IP pointer. + */ + args = malloc_or_die(sizeof(*args)); + arg = args; + arg->next = NULL; + next = &arg->next; + + arg->type = PRINT_ATOM; + arg->atom.atom = malloc_or_die(32); + sprintf(arg->atom.atom, "%lld", ip); + + /* skip the first "%pf : " */ + for (ptr = fmt + 6, bptr = data + field->offset; + bptr < data + size && *ptr; ptr++) { + int ls = 0; + + if (*ptr == '%') { + process_again: + ptr++; + switch (*ptr) { + case '%': + break; + case 'l': + ls++; + goto process_again; + case 'L': + ls = 2; + goto process_again; + case '0' ... '9': + goto process_again; + case 'p': + ls = 1; + /* fall through */ + case 'd': + case 'u': + case 'x': + case 'i': + bptr = (void *)(((unsigned long)bptr + (long_size - 1)) & + ~(long_size - 1)); + switch (ls) { + case 0: + case 1: + ls = long_size; + break; + case 2: + ls = 8; + default: + break; + } + val = read_size(bptr, ls); + bptr += ls; + arg = malloc_or_die(sizeof(*arg)); + arg->next = NULL; + arg->type = PRINT_ATOM; + arg->atom.atom = malloc_or_die(32); + sprintf(arg->atom.atom, "%lld", val); + *next = arg; + next = &arg->next; + break; + case 's': + arg = malloc_or_die(sizeof(*arg)); + arg->next = NULL; + arg->type = PRINT_STRING; + arg->string.string = strdup(bptr); + bptr += strlen(bptr) + 1; + *next = arg; + next = &arg->next; + default: + break; + } + } + } + + return args; +} + +static void free_args(struct print_arg *args) +{ + struct print_arg *next; + + while (args) { + next = args->next; + + if (args->type == PRINT_ATOM) + free(args->atom.atom); + else + free(args->string.string); + free(args); + args = next; + } +} + +static char *get_bprint_format(void *data, int size __unused, struct event *event) +{ + unsigned long long addr; + static struct format_field *field; + struct printk_map *printk; + char *format; + char *p; + + if (!field) { + field = find_field(event, "fmt"); + if (!field) + die("can't find format field for binary printk"); + printf("field->offset = %d size=%d\n", field->offset, field->size); + } + + addr = read_size(data + field->offset, field->size); + + printk = find_printk(addr); + if (!printk) { + format = malloc_or_die(45); + sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n", + addr); + return format; + } + + p = printk->printk; + /* Remove any quotes. */ + if (*p == '"') + p++; + format = malloc_or_die(strlen(p) + 10); + sprintf(format, "%s : %s", "%pf", p); + /* remove ending quotes and new line since we will add one too */ + p = format + strlen(format) - 1; + if (*p == '"') + *p = 0; + + p -= 2; + if (strcmp(p, "\\n") == 0) + *p = 0; + + return format; +} + +static void pretty_print(void *data, int size, struct event *event) +{ + struct print_fmt *print_fmt = &event->print_fmt; + struct print_arg *arg = print_fmt->args; + struct print_arg *args = NULL; + const char *ptr = print_fmt->format; + unsigned long long val; + struct func_map *func; + const char *saveptr; + char *bprint_fmt = NULL; + char format[32]; + int show_func; + int len; + int ls; + + if (event->flags & EVENT_FL_ISFUNC) + ptr = " %pF <-- %pF"; + + if (event->flags & EVENT_FL_ISBPRINT) { + bprint_fmt = get_bprint_format(data, size, event); + args = make_bprint_args(bprint_fmt, data, size, event); + arg = args; + ptr = bprint_fmt; + } + + for (; *ptr; ptr++) { + ls = 0; + if (*ptr == '%') { + saveptr = ptr; + show_func = 0; + cont_process: + ptr++; + switch (*ptr) { + case '%': + printf("%%"); + break; + case 'l': + ls++; + goto cont_process; + case 'L': + ls = 2; + goto cont_process; + case 'z': + case 'Z': + case '0' ... '9': + goto cont_process; + case 'p': + if (long_size == 4) + ls = 1; + else + ls = 2; + + if (*(ptr+1) == 'F' || + *(ptr+1) == 'f') { + ptr++; + show_func = *ptr; + } + + /* fall through */ + case 'd': + case 'i': + case 'x': + case 'X': + case 'u': + if (!arg) + die("no argument match"); + + len = ((unsigned long)ptr + 1) - + (unsigned long)saveptr; + + /* should never happen */ + if (len > 32) + die("bad format!"); + + memcpy(format, saveptr, len); + format[len] = 0; + + val = eval_num_arg(data, size, event, arg); + arg = arg->next; + + if (show_func) { + func = find_func(val); + if (func) { + printf("%s", func->func); + if (show_func == 'F') + printf("+0x%llx", + val - func->addr); + break; + } + } + switch (ls) { + case 0: + printf(format, (int)val); + break; + case 1: + printf(format, (long)val); + break; + case 2: + printf(format, (long long)val); + break; + default: + die("bad count (%d)", ls); + } + break; + case 's': + if (!arg) + die("no matching argument"); + + print_str_arg(data, size, event, arg); + arg = arg->next; + break; + default: + printf(">%c<", *ptr); + + } + } else + printf("%c", *ptr); + } + + if (args) { + free_args(args); + free(bprint_fmt); + } +} + +static inline int log10_cpu(int nb) +{ + if (nb / 100) + return 3; + if (nb / 10) + return 2; + return 1; +} + +/* taken from Linux, written by Frederic Weisbecker */ +static void print_graph_cpu(int cpu) +{ + int i; + int log10_this = log10_cpu(cpu); + int log10_all = log10_cpu(cpus); + + + /* + * Start with a space character - to make it stand out + * to the right a bit when trace output is pasted into + * email: + */ + printf(" "); + + /* + * Tricky - we space the CPU field according to the max + * number of online CPUs. On a 2-cpu system it would take + * a maximum of 1 digit - on a 128 cpu system it would + * take up to 3 digits: + */ + for (i = 0; i < log10_all - log10_this; i++) + printf(" "); + + printf("%d) ", cpu); +} + +#define TRACE_GRAPH_PROCINFO_LENGTH 14 +#define TRACE_GRAPH_INDENT 2 + +static void print_graph_proc(int pid, const char *comm) +{ + /* sign + log10(MAX_INT) + '\0' */ + char pid_str[11]; + int spaces = 0; + int len; + int i; + + sprintf(pid_str, "%d", pid); + + /* 1 stands for the "-" character */ + len = strlen(comm) + strlen(pid_str) + 1; + + if (len < TRACE_GRAPH_PROCINFO_LENGTH) + spaces = TRACE_GRAPH_PROCINFO_LENGTH - len; + + /* First spaces to align center */ + for (i = 0; i < spaces / 2; i++) + printf(" "); + + printf("%s-%s", comm, pid_str); + + /* Last spaces to align center */ + for (i = 0; i < spaces - (spaces / 2); i++) + printf(" "); +} + +static struct record * +get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func, + struct record *next) +{ + struct format_field *field; + struct event *event; + unsigned long val; + int type; + int pid; + + type = parse_common_type(next->data); + event = find_event(type); + if (!event) + return NULL; + + if (!(event->flags & EVENT_FL_ISFUNCRET)) + return NULL; + + pid = parse_common_pid(next->data); + field = find_field(event, "func"); + if (!field) + die("function return does not have field func"); + + val = read_size(next->data + field->offset, field->size); + + if (cur_pid != pid || cur_func != val) + return NULL; + + /* this is a leaf, now advance the iterator */ + return trace_read_data(cpu); +} + +/* Signal a overhead of time execution to the output */ +static void print_graph_overhead(unsigned long long duration) +{ + /* Non nested entry or return */ + if (duration == ~0ULL) + return (void)printf(" "); + + /* Duration exceeded 100 msecs */ + if (duration > 100000ULL) + return (void)printf("! "); + + /* Duration exceeded 10 msecs */ + if (duration > 10000ULL) + return (void)printf("+ "); + + printf(" "); +} + +static void print_graph_duration(unsigned long long duration) +{ + unsigned long usecs = duration / 1000; + unsigned long nsecs_rem = duration % 1000; + /* log10(ULONG_MAX) + '\0' */ + char msecs_str[21]; + char nsecs_str[5]; + int len; + int i; + + sprintf(msecs_str, "%lu", usecs); + + /* Print msecs */ + len = printf("%lu", usecs); + + /* Print nsecs (we don't want to exceed 7 numbers) */ + if (len < 7) { + snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem); + len += printf(".%s", nsecs_str); + } + + printf(" us "); + + /* Print remaining spaces to fit the row's width */ + for (i = len; i < 7; i++) + printf(" "); + + printf("| "); +} + +static void +print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec) +{ + unsigned long long rettime, calltime; + unsigned long long duration, depth; + unsigned long long val; + struct format_field *field; + struct func_map *func; + struct event *ret_event; + int type; + int i; + + type = parse_common_type(ret_rec->data); + ret_event = find_event(type); + + field = find_field(ret_event, "rettime"); + if (!field) + die("can't find rettime in return graph"); + rettime = read_size(ret_rec->data + field->offset, field->size); + + field = find_field(ret_event, "calltime"); + if (!field) + die("can't find rettime in return graph"); + calltime = read_size(ret_rec->data + field->offset, field->size); + + duration = rettime - calltime; + + /* Overhead */ + print_graph_overhead(duration); + + /* Duration */ + print_graph_duration(duration); + + field = find_field(event, "depth"); + if (!field) + die("can't find depth in entry graph"); + depth = read_size(data + field->offset, field->size); + + /* Function */ + for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++) + printf(" "); + + field = find_field(event, "func"); + if (!field) + die("can't find func in entry graph"); + val = read_size(data + field->offset, field->size); + func = find_func(val); + + if (func) + printf("%s();", func->func); + else + printf("%llx();", val); +} + +static void print_graph_nested(struct event *event, void *data) +{ + struct format_field *field; + unsigned long long depth; + unsigned long long val; + struct func_map *func; + int i; + + /* No overhead */ + print_graph_overhead(-1); + + /* No time */ + printf(" | "); + + field = find_field(event, "depth"); + if (!field) + die("can't find depth in entry graph"); + depth = read_size(data + field->offset, field->size); + + /* Function */ + for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++) + printf(" "); + + field = find_field(event, "func"); + if (!field) + die("can't find func in entry graph"); + val = read_size(data + field->offset, field->size); + func = find_func(val); + + if (func) + printf("%s() {", func->func); + else + printf("%llx() {", val); +} + +static void +pretty_print_func_ent(void *data, int size, struct event *event, + int cpu, int pid, const char *comm, + unsigned long secs, unsigned long usecs) +{ + struct format_field *field; + struct record *rec; + void *copy_data; + unsigned long val; + + printf("%5lu.%06lu | ", secs, usecs); + + print_graph_cpu(cpu); + print_graph_proc(pid, comm); + + printf(" | "); + + field = find_field(event, "func"); + if (!field) + die("function entry does not have func field"); + + val = read_size(data + field->offset, field->size); + + /* + * peek_data may unmap the data pointer. Copy it first. + */ + copy_data = malloc_or_die(size); + memcpy(copy_data, data, size); + data = copy_data; + + rec = trace_peek_data(cpu); + if (rec) { + rec = get_return_for_leaf(cpu, pid, val, rec); + if (rec) { + print_graph_entry_leaf(event, data, rec); + goto out_free; + } + } + print_graph_nested(event, data); +out_free: + free(data); +} + +static void +pretty_print_func_ret(void *data, int size __unused, struct event *event, + int cpu, int pid, const char *comm, + unsigned long secs, unsigned long usecs) +{ + unsigned long long rettime, calltime; + unsigned long long duration, depth; + struct format_field *field; + int i; + + printf("%5lu.%06lu | ", secs, usecs); + + print_graph_cpu(cpu); + print_graph_proc(pid, comm); + + printf(" | "); + + field = find_field(event, "rettime"); + if (!field) + die("can't find rettime in return graph"); + rettime = read_size(data + field->offset, field->size); + + field = find_field(event, "calltime"); + if (!field) + die("can't find calltime in return graph"); + calltime = read_size(data + field->offset, field->size); + + duration = rettime - calltime; + + /* Overhead */ + print_graph_overhead(duration); + + /* Duration */ + print_graph_duration(duration); + + field = find_field(event, "depth"); + if (!field) + die("can't find depth in entry graph"); + depth = read_size(data + field->offset, field->size); + + /* Function */ + for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++) + printf(" "); + + printf("}"); +} + +static void +pretty_print_func_graph(void *data, int size, struct event *event, + int cpu, int pid, const char *comm, + unsigned long secs, unsigned long usecs) +{ + if (event->flags & EVENT_FL_ISFUNCENT) + pretty_print_func_ent(data, size, event, + cpu, pid, comm, secs, usecs); + else if (event->flags & EVENT_FL_ISFUNCRET) + pretty_print_func_ret(data, size, event, + cpu, pid, comm, secs, usecs); + printf("\n"); +} + +void print_event(int cpu, void *data, int size, unsigned long long nsecs, + char *comm) +{ + struct event *event; + unsigned long secs; + unsigned long usecs; + int type; + int pid; + + secs = nsecs / NSECS_PER_SEC; + nsecs -= secs * NSECS_PER_SEC; + usecs = nsecs / NSECS_PER_USEC; + + type = parse_common_type(data); + + event = find_event(type); + if (!event) + die("ug! no event found for type %d", type); + + pid = parse_common_pid(data); + + if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET)) + return pretty_print_func_graph(data, size, event, cpu, + pid, comm, secs, usecs); + + printf("%16s-%-5d [%03d] %5lu.%06lu: %s: ", + comm, pid, cpu, + secs, usecs, event->name); + + pretty_print(data, size, event); + printf("\n"); +} + +static void print_fields(struct print_flag_sym *field) +{ + printf("{ %s, %s }", field->value, field->str); + if (field->next) { + printf(", "); + print_fields(field->next); + } +} + +static void print_args(struct print_arg *args) +{ + int print_paren = 1; + + switch (args->type) { + case PRINT_NULL: + printf("null"); + break; + case PRINT_ATOM: + printf("%s", args->atom.atom); + break; + case PRINT_FIELD: + printf("REC->%s", args->field.name); + break; + case PRINT_FLAGS: + printf("__print_flags("); + print_args(args->flags.field); + printf(", %s, ", args->flags.delim); + print_fields(args->flags.flags); + printf(")"); + break; + case PRINT_SYMBOL: + printf("__print_symbolic("); + print_args(args->symbol.field); + printf(", "); + print_fields(args->symbol.symbols); + printf(")"); + break; + case PRINT_STRING: + printf("__get_str(%s)", args->string.string); + break; + case PRINT_TYPE: + printf("(%s)", args->typecast.type); + print_args(args->typecast.item); + break; + case PRINT_OP: + if (strcmp(args->op.op, ":") == 0) + print_paren = 0; + if (print_paren) + printf("("); + print_args(args->op.left); + printf(" %s ", args->op.op); + print_args(args->op.right); + if (print_paren) + printf(")"); + break; + default: + /* we should warn... */ + return; + } + if (args->next) { + printf("\n"); + print_args(args->next); + } +} + +static void parse_header_field(char *type, + int *offset, int *size) +{ + char *token; + + if (read_expected(EVENT_ITEM, (char *)"field") < 0) + return; + if (read_expected(EVENT_OP, (char *)":") < 0) + return; + /* type */ + if (read_expect_type(EVENT_ITEM, &token) < 0) + return; + free_token(token); + + if (read_expected(EVENT_ITEM, type) < 0) + return; + if (read_expected(EVENT_OP, (char *)";") < 0) + return; + if (read_expected(EVENT_ITEM, (char *)"offset") < 0) + return; + if (read_expected(EVENT_OP, (char *)":") < 0) + return; + if (read_expect_type(EVENT_ITEM, &token) < 0) + return; + *offset = atoi(token); + free_token(token); + if (read_expected(EVENT_OP, (char *)";") < 0) + return; + if (read_expected(EVENT_ITEM, (char *)"size") < 0) + return; + if (read_expected(EVENT_OP, (char *)":") < 0) + return; + if (read_expect_type(EVENT_ITEM, &token) < 0) + return; + *size = atoi(token); + free_token(token); + if (read_expected(EVENT_OP, (char *)";") < 0) + return; + if (read_expect_type(EVENT_NEWLINE, &token) < 0) + return; + free_token(token); +} + +int parse_header_page(char *buf, unsigned long size) +{ + init_input_buf(buf, size); + + parse_header_field((char *)"timestamp", &header_page_ts_offset, + &header_page_ts_size); + parse_header_field((char *)"commit", &header_page_size_offset, + &header_page_size_size); + parse_header_field((char *)"data", &header_page_data_offset, + &header_page_data_size); + + return 0; +} + +int parse_ftrace_file(char *buf, unsigned long size) +{ + struct format_field *field; + struct print_arg *arg, **list; + struct event *event; + int ret; + + init_input_buf(buf, size); + + event = alloc_event(); + if (!event) + return -ENOMEM; + + event->flags |= EVENT_FL_ISFTRACE; + + event->name = event_read_name(); + if (!event->name) + die("failed to read ftrace event name"); + + if (strcmp(event->name, "function") == 0) + event->flags |= EVENT_FL_ISFUNC; + + else if (strcmp(event->name, "funcgraph_entry") == 0) + event->flags |= EVENT_FL_ISFUNCENT; + + else if (strcmp(event->name, "funcgraph_exit") == 0) + event->flags |= EVENT_FL_ISFUNCRET; + + else if (strcmp(event->name, "bprint") == 0) + event->flags |= EVENT_FL_ISBPRINT; + + event->id = event_read_id(); + if (event->id < 0) + die("failed to read ftrace event id"); + + add_event(event); + + ret = event_read_format(event); + if (ret < 0) + die("failed to read ftrace event format"); + + ret = event_read_print(event); + if (ret < 0) + die("failed to read ftrace event print fmt"); + + /* + * The arguments for ftrace files are parsed by the fields. + * Set up the fields as their arguments. + */ + list = &event->print_fmt.args; + for (field = event->format.fields; field; field = field->next) { + arg = malloc_or_die(sizeof(*arg)); + memset(arg, 0, sizeof(*arg)); + *list = arg; + list = &arg->next; + arg->type = PRINT_FIELD; + arg->field.name = field->name; + arg->field.field = field; + } + return 0; +} + +int parse_event_file(char *buf, unsigned long size, char *system__unused __unused) +{ + struct event *event; + int ret; + + init_input_buf(buf, size); + + event = alloc_event(); + if (!event) + return -ENOMEM; + + event->name = event_read_name(); + if (!event->name) + die("failed to read event name"); + + event->id = event_read_id(); + if (event->id < 0) + die("failed to read event id"); + + ret = event_read_format(event); + if (ret < 0) + die("failed to read event format"); + + ret = event_read_print(event); + if (ret < 0) + die("failed to read event print fmt"); + +#define PRINT_ARGS 0 + if (PRINT_ARGS && event->print_fmt.args) + print_args(event->print_fmt.args); + + add_event(event); + return 0; +} + +void parse_set_info(int nr_cpus, int long_sz) +{ + cpus = nr_cpus; + long_size = long_sz; +} -- cgit v0.10.2 From 5f9c39dca52d3e639ac899e169f408c6fd8396cc Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 17 Aug 2009 16:18:08 +0200 Subject: perf tools: Add perf trace This adds perf trace into the set of perf tools. It is written to fetch the tracepoint samples from perf events and display them, according to the events information given by the debugfs files through the util/trace* tools. It is a rough first shot and doesn't yet handle the cpu, timestamps fields and some other things. Example: perf record -f -e workqueue:workqueue_execution:record -F 1 -a perf trace kblockd/0-236 [000] 0.000000: workqueue_execution: thread=:236 func=cfq_kick_queue+0x0 kondemand/0-360 [000] 0.000000: workqueue_execution: thread=:360 func=do_dbs_timer+0x0 kondemand/0-360 [000] 0.000000: workqueue_execution: thread=:360 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 kondemand/1-361 [000] 0.000000: workqueue_execution: thread=:361 func=do_dbs_timer+0x0 Todo: - A lot of things! Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: "Luis Claudio R. Goncalves" Cc: Clark Williams Cc: Jon Masters Cc: Mathieu Desnoyers Cc: Christoph Hellwig Cc: Xiao Guangrong Cc: Zhaolei Cc: Li Zefan Cc: Lai Jiangshan Cc: Masami Hiramatsu Cc: Tom Zanussi Cc: "Frank Ch. Eigler" Cc: Roland McGrath Cc: Jason Baron Cc: Paul Mackerras Cc: Jiaying Zhang Cc: Anton Blanchard LKML-Reference: <1250518688-7207-4-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 5d54ddb..c481a51 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -347,6 +347,9 @@ LIB_OBJS += util/values.o LIB_OBJS += util/debug.o LIB_OBJS += util/map.o LIB_OBJS += util/thread.o +LIB_OBJS += util/trace-event-parse.o +LIB_OBJS += util/trace-event-read.o +LIB_OBJS += util/trace-event-info.o BUILTIN_OBJS += builtin-annotate.o BUILTIN_OBJS += builtin-help.o @@ -355,6 +358,7 @@ BUILTIN_OBJS += builtin-record.o BUILTIN_OBJS += builtin-report.o BUILTIN_OBJS += builtin-stat.o BUILTIN_OBJS += builtin-top.o +BUILTIN_OBJS += builtin-trace.o PERFLIBS = $(LIB_FILE) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6a5db675e..3ce2f03 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -17,6 +17,7 @@ #include "util/header.h" #include "util/event.h" #include "util/debug.h" +#include "util/trace-event.h" #include #include @@ -519,6 +520,9 @@ static int __cmd_record(int argc, const char **argv) signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); + if (raw_samples) + read_tracing_data(); + if (!stat(output_name, &st) && st.st_size) { if (!force && !append_file) { fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c new file mode 100644 index 0000000..b160a9f --- /dev/null +++ b/tools/perf/builtin-trace.c @@ -0,0 +1,277 @@ +#include "builtin.h" + +#include "util/util.h" +#include "util/cache.h" +#include "util/symbol.h" +#include "util/thread.h" +#include "util/header.h" + +#include "util/parse-options.h" + +#include "perf.h" +#include "util/debug.h" + +#include "util/trace-event.h" + +static char const *input_name = "perf.data"; +static int input; +static unsigned long page_size; +static unsigned long mmap_window = 32; + +static unsigned long total = 0; +static unsigned long total_comm = 0; + +static struct rb_root threads; +static struct thread *last_match; + +static struct perf_header *header; +static u64 sample_type; + + +static int +process_comm_event(event_t *event, unsigned long offset, unsigned long head) +{ + struct thread *thread; + + thread = threads__findnew(event->comm.pid, &threads, &last_match); + + dump_printf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->comm.comm, event->comm.pid); + + if (thread == NULL || + thread__set_comm(thread, event->comm.comm)) { + dump_printf("problem processing PERF_EVENT_COMM, skipping event.\n"); + return -1; + } + total_comm++; + + return 0; +} + +static int +process_sample_event(event_t *event, unsigned long offset, unsigned long head) +{ + char level; + int show = 0; + struct dso *dso = NULL; + struct thread *thread; + u64 ip = event->ip.ip; + u64 period = 1; + void *more_data = event->ip.__more_data; + int cpumode; + + thread = threads__findnew(event->ip.pid, &threads, &last_match); + + if (sample_type & PERF_SAMPLE_PERIOD) { + period = *(u64 *)more_data; + more_data += sizeof(u64); + } + + dump_printf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->header.misc, + event->ip.pid, event->ip.tid, + (void *)(long)ip, + (long long)period); + + dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); + + if (thread == NULL) { + eprintf("problem processing %d event, skipping it.\n", + event->header.type); + return -1; + } + + cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK; + + if (cpumode == PERF_EVENT_MISC_KERNEL) { + show = SHOW_KERNEL; + level = 'k'; + + dso = kernel_dso; + + dump_printf(" ...... dso: %s\n", dso->name); + + } else if (cpumode == PERF_EVENT_MISC_USER) { + + show = SHOW_USER; + level = '.'; + + } else { + show = SHOW_HV; + level = 'H'; + + dso = hypervisor_dso; + + dump_printf(" ...... dso: [hypervisor]\n"); + } + + if (sample_type & PERF_SAMPLE_RAW) { + struct { + u32 size; + char data[0]; + } *raw = more_data; + + /* + * FIXME: better resolve from pid from the struct trace_entry + * field, although it should be the same than this perf + * event pid + */ + print_event(0, raw->data, raw->size, 0, thread->comm); + } + total += period; + + return 0; +} + +static int +process_event(event_t *event, unsigned long offset, unsigned long head) +{ + trace_event(event); + + switch (event->header.type) { + case PERF_EVENT_MMAP ... PERF_EVENT_LOST: + return 0; + + case PERF_EVENT_COMM: + return process_comm_event(event, offset, head); + + case PERF_EVENT_EXIT ... PERF_EVENT_READ: + return 0; + + case PERF_EVENT_SAMPLE: + return process_sample_event(event, offset, head); + + case PERF_EVENT_MAX: + default: + return -1; + } + + return 0; +} + +static int __cmd_trace(void) +{ + int ret, rc = EXIT_FAILURE; + unsigned long offset = 0; + unsigned long head = 0; + struct stat perf_stat; + event_t *event; + uint32_t size; + char *buf; + + trace_report(); + + input = open(input_name, O_RDONLY); + if (input < 0) { + perror("failed to open file"); + exit(-1); + } + + ret = fstat(input, &perf_stat); + if (ret < 0) { + perror("failed to stat file"); + exit(-1); + } + + if (!perf_stat.st_size) { + fprintf(stderr, "zero-sized file, nothing to do!\n"); + exit(0); + } + header = perf_header__read(input); + sample_type = perf_header__sample_type(header); + + if (load_kernel() < 0) { + perror("failed to load kernel symbols"); + return EXIT_FAILURE; + } + +remap: + buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, + MAP_SHARED, input, offset); + if (buf == MAP_FAILED) { + perror("failed to mmap file"); + exit(-1); + } + +more: + event = (event_t *)(buf + head); + + size = event->header.size; + if (!size) + size = 8; + + if (head + event->header.size >= page_size * mmap_window) { + unsigned long shift = page_size * (head / page_size); + int res; + + res = munmap(buf, page_size * mmap_window); + assert(res == 0); + + offset += shift; + head -= shift; + goto remap; + } + + size = event->header.size; + + + if (!size || process_event(event, offset, head) < 0) { + + /* + * assume we lost track of the stream, check alignment, and + * increment a single u64 in the hope to catch on again 'soon'. + */ + + if (unlikely(head & 7)) + head &= ~7ULL; + + size = 8; + } + + head += size; + + if (offset + head < (unsigned long)perf_stat.st_size) + goto more; + + rc = EXIT_SUCCESS; + close(input); + + return rc; +} + +static const char * const annotate_usage[] = { + "perf trace [] ", + NULL +}; + +static const struct option options[] = { + OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, + "dump raw trace in ASCII"), + OPT_BOOLEAN('v', "verbose", &verbose, + "be more verbose (show symbol address, etc)"), +}; + +int cmd_trace(int argc, const char **argv, const char *prefix __used) +{ + symbol__init(); + page_size = getpagesize(); + + argc = parse_options(argc, argv, options, annotate_usage, 0); + if (argc) { + /* + * Special case: if there's an argument left then assume tha + * it's a symbol filter: + */ + if (argc > 1) + usage_with_options(annotate_usage, options); + } + + + setup_pager(); + + return __cmd_trace(); +} diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 31982ad..fe4589d 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -292,6 +292,7 @@ static void handle_internal_command(int argc, const char **argv) { "top", cmd_top, 0 }, { "annotate", cmd_annotate, 0 }, { "version", cmd_version, 0 }, + { "trace", cmd_trace, 0 }, }; unsigned int i; static const char ext[] = STRIP_EXTENSION; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index d61a6f0..c62ef97 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -311,6 +311,7 @@ static inline int has_extension(const char *filename, const char *ext) #undef isspace #undef isdigit #undef isalpha +#undef isprint #undef isalnum #undef tolower #undef toupper -- cgit v0.10.2 From 1ca04065c3569beb42b9376952df8c96f430f753 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Aug 2009 16:26:59 +0100 Subject: ASoC: Power speakers and headphones simultaneously Speaker and headphone outputs do not need to be handled separately since they can't be part of the same path. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8997fb3..8846131 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -64,15 +64,15 @@ static int dapm_up_seq[] = { [snd_soc_dapm_pga] = 7, [snd_soc_dapm_adc] = 8, [snd_soc_dapm_hp] = 9, - [snd_soc_dapm_spk] = 10, - [snd_soc_dapm_post] = 11, + [snd_soc_dapm_spk] = 9, + [snd_soc_dapm_post] = 10, }; static int dapm_down_seq[] = { [snd_soc_dapm_pre] = 0, [snd_soc_dapm_adc] = 1, [snd_soc_dapm_hp] = 2, - [snd_soc_dapm_spk] = 3, + [snd_soc_dapm_spk] = 2, [snd_soc_dapm_pga] = 4, [snd_soc_dapm_mixer_named_ctl] = 5, [snd_soc_dapm_mixer] = 5, -- cgit v0.10.2 From 0182dcc52c759d005cc3e65deadee9f166cdd7d0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Aug 2009 18:51:44 +0100 Subject: ASoC: Fix WM8993 MCLK configuration for high frequency MCLKs When used without the PLL we were accidentally clearing the MCLK/2 divider, resulting in a double rate SYSCLK when the divider should have been used. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index cd15669..f9119a6 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -519,7 +519,7 @@ static int configure_clock(struct snd_soc_codec *codec) dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8993->mclk_rate); reg = wm8993_read(codec, WM8993_CLOCKING_2); - reg &= ~WM8993_SYSCLK_SRC; + reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC); if (wm8993->mclk_rate > 13500000) { reg |= WM8993_MCLK_DIV; wm8993->sysclk_rate = wm8993->mclk_rate / 2; @@ -527,8 +527,6 @@ static int configure_clock(struct snd_soc_codec *codec) reg &= ~WM8993_MCLK_DIV; wm8993->sysclk_rate = wm8993->mclk_rate; } - reg &= ~WM8993_MCLK_DIV; - reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC); wm8993_write(codec, WM8993_CLOCKING_2, reg); break; -- cgit v0.10.2 From d3c9e9a1390f8a34da8b69e09fa1afa90f5067f4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Aug 2009 18:52:47 +0100 Subject: ASoC: Implement TDM configuration for WM8993 Note that the number of slots used internally is specified in terms of stereo slots while the external API works with mono slots. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index f9119a6..13befa3 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -218,6 +218,8 @@ struct wm8993_priv { struct snd_soc_codec codec; int master; int sysclk_source; + int tdm_slots; + int tdm_width; unsigned int mclk_rate; unsigned int sysclk_rate; unsigned int fs; @@ -1107,24 +1109,30 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream, /* What BCLK do we need? */ wm8993->fs = params_rate(params); wm8993->bclk = 2 * wm8993->fs; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - wm8993->bclk *= 16; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - wm8993->bclk *= 20; - aif1 |= 0x8; - break; - case SNDRV_PCM_FORMAT_S24_LE: - wm8993->bclk *= 24; - aif1 |= 0x10; - break; - case SNDRV_PCM_FORMAT_S32_LE: - wm8993->bclk *= 32; - aif1 |= 0x18; - break; - default: - return -EINVAL; + if (wm8993->tdm_slots) { + dev_dbg(codec->dev, "Configuring for %d %d bit TDM slots\n", + wm8993->tdm_slots, wm8993->tdm_width); + wm8993->bclk *= wm8993->tdm_width * wm8993->tdm_slots; + } else { + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + wm8993->bclk *= 16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + wm8993->bclk *= 20; + aif1 |= 0x8; + break; + case SNDRV_PCM_FORMAT_S24_LE: + wm8993->bclk *= 24; + aif1 |= 0x10; + break; + case SNDRV_PCM_FORMAT_S32_LE: + wm8993->bclk *= 32; + aif1 |= 0x18; + break; + default: + return -EINVAL; + } } dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8993->bclk); @@ -1243,12 +1251,67 @@ static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute) return 0; } +static int wm8993_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8993_priv *wm8993 = codec->private_data; + int aif1 = 0; + int aif2 = 0; + + /* Don't need to validate anything if we're turning off TDM */ + if (slots == 0) { + wm8993->tdm_slots = 0; + goto out; + } + + /* Note that we allow configurations we can't handle ourselves - + * for example, we can generate clocks for slots 2 and up even if + * we can't use those slots ourselves. + */ + aif1 |= WM8993_AIFADC_TDM; + aif2 |= WM8993_AIFDAC_TDM; + + switch (rx_mask) { + case 3: + break; + case 0xc: + aif1 |= WM8993_AIFADC_TDM_CHAN; + break; + default: + return -EINVAL; + } + + + switch (tx_mask) { + case 3: + break; + case 0xc: + aif2 |= WM8993_AIFDAC_TDM_CHAN; + break; + default: + return -EINVAL; + } + +out: + wm8993->tdm_width = slot_width; + wm8993->tdm_slots = slots / 2; + + snd_soc_update_bits(codec, WM8993_AUDIO_INTERFACE_1, + WM8993_AIFADC_TDM | WM8993_AIFADC_TDM_CHAN, aif1); + snd_soc_update_bits(codec, WM8993_AUDIO_INTERFACE_2, + WM8993_AIFDAC_TDM | WM8993_AIFDAC_TDM_CHAN, aif2); + + return 0; +} + static struct snd_soc_dai_ops wm8993_ops = { .set_sysclk = wm8993_set_sysclk, .set_fmt = wm8993_set_dai_fmt, .hw_params = wm8993_hw_params, .digital_mute = wm8993_digital_mute, .set_pll = wm8993_set_fll, + .set_tdm_slot = wm8993_set_tdm_slot, }; #define WM8993_RATES SNDRV_PCM_RATE_8000_48000 -- cgit v0.10.2 From b7f42ab2e237f08a5bbcefa17473e80eb05e725c Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 17 Aug 2009 11:19:40 -0700 Subject: x86, apic: Move dmar_table_init() out of enable_IR() On an x2apic system, we got: [ 1.818072] ------------[ cut here ]------------ [ 1.820376] WARNING: at kernel/lockdep.c:2461 lockdep_trace_alloc+0xa5/0xe9() [ 1.835282] Hardware name: ASSY, [ 1.839006] Modules linked in: [ 1.841253] Pid: 1, comm: swapper Not tainted 2.6.31-rc5-tip-03926-g39aaa80-dirty #510 [ 1.858056] Call Trace: [ 1.859913] [] ? lockdep_trace_alloc+0xa5/0xe9 [ 1.876270] [] warn_slowpath_common+0x8d/0xd0 [ 1.879132] [] warn_slowpath_null+0x27/0x3d [ 1.896823] [] lockdep_trace_alloc+0xa5/0xe9 [ 1.900659] [] ? lock_release_holdtime+0x2f/0x199 [ 1.917188] [] kmem_cache_alloc_notrace+0x42/0x111 [ 1.922320] [] ? reserve_memtype+0x152/0x518 [ 1.938137] [] ? pat_pagerange_is_ram+0x4a/0x91 [ 1.941730] [] reserve_memtype+0x152/0x518 [ 1.958115] [] __ioremap_caller+0x1dd/0x30f [ 1.975507] [] ? acpi_os_map_memory+0x2a/0x47 [ 1.978987] [] ioremap_nocache+0x2a/0x40 [ 2.031400] [] ? trace_hardirqs_off+0x20/0x36 [ 2.036096] [] acpi_os_map_memory+0x2a/0x47 [ 2.046263] [] acpi_tb_verify_table+0x3d/0x85 [ 2.050349] [] ? _spin_unlock_irqrestore+0x50/0x76 [ 2.067327] [] acpi_get_table_with_size+0x64/0xd9 [ 2.070860] [] ? _spin_unlock_irqrestore+0x50/0x76 [ 2.088000] [] dmar_table_detect+0x33/0x70 [ 2.092047] [] dmar_table_init+0x43/0x428 [ 2.106854] [] enable_IR+0x1c/0x8d [ 2.110256] [] enable_IR_x2apic+0x7c/0x19e [ 2.127139] [] native_smp_prepare_cpus+0x139/0x3b8 [ 2.145175] [] kernel_init+0x71/0x1da [ 2.148913] [] child_rip+0xa/0x20 [ 2.152349] [] ? restore_args+0x0/0x30 [ 2.167931] [] ? kernel_init+0x0/0x1da [ 2.171671] [] ? child_rip+0x0/0x20 [ 2.187607] ---[ end trace a7919e7f17c0a725 ]--- Venkatesh Pallipadi said: | Looks like the problem started with this commit | | commit ce69a784504222c3ab6f1b3c357d09ec5772127a | Author: Gleb Natapov | Date: Mon Jul 20 15:24:17 2009 +0300 | | x86/apic: Enable x2APIC without interrupt remapping under KVM | | Before this commit, dmar_table_init() was getting called | with interrupts enabled and after this commit, it is getting | called with interrupts disabled. so try to move out dmar_table_init out of that function. Analyzed-by: Venkatesh Pallipadi Signed-off-by: Yinghai Lu Cc: Peter Zijlstra Cc: Gleb Natapov Cc: Suresh Siddha Cc: "Pallipadi, Venkatesh" LKML-Reference: <4A899F3C.2050104@kernel.org> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index de039fc..3fc3a6c 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1365,14 +1365,6 @@ void enable_x2apic(void) int __init enable_IR(void) { #ifdef CONFIG_INTR_REMAP - int ret; - - ret = dmar_table_init(); - if (ret) { - pr_debug("dmar_table_init() failed with %d:\n", ret); - return 0; - } - if (!intr_remapping_supported()) { pr_debug("intr-remapping not supported\n"); return 0; @@ -1400,6 +1392,14 @@ void __init enable_IR_x2apic(void) unsigned long flags; struct IO_APIC_route_entry **ioapic_entries = NULL; int ret, x2apic_enabled = 0; + int dmar_table_init_ret = 0; + +#ifdef CONFIG_INTR_REMAP + dmar_table_init_ret = dmar_table_init(); + if (dmar_table_init_ret) + pr_debug("dmar_table_init() failed with %d:\n", + dmar_table_init_ret); +#endif ioapic_entries = alloc_ioapic_entries(); if (!ioapic_entries) { @@ -1417,7 +1417,11 @@ void __init enable_IR_x2apic(void) mask_8259A(); mask_IO_APIC_setup(ioapic_entries); - ret = enable_IR(); + if (dmar_table_init_ret) + ret = 0; + else + ret = enable_IR(); + if (!ret) { /* IR is required if there is APIC ID > 255 even when running * under KVM -- cgit v0.10.2 From 6ede59c412579303a25c11f93d4d262e100fc7e6 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 17 Aug 2009 23:07:48 +0200 Subject: perf tools: Fix spelling mistake in callchain error While running perf report -g in a perf.data file that hasn't been recorded in callchain mode, the error reported has a spelling issue: ./perf report -g selected -c but no callchain data. Did you call perf record without -g? Fix it. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Steven Rostedt LKML-Reference: <1250543271-8383-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1e3ad22..ed1fdab 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1401,7 +1401,7 @@ static int __cmd_report(void) exit(-1); } if (callchain) { - fprintf(stderr, "selected -c but no callchain data." + fprintf(stderr, "selected -g but no callchain data." " Did you call perf record without" " -g?\n"); exit(-1); -- cgit v0.10.2 From 4bf2364a951d3c043e132e4451d90c7bc74dee83 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 17 Aug 2009 23:07:49 +0200 Subject: perf tools: Warn while running perf trace without sample When a user runs perf trace using an input with logged counters without PERF_SAMPLE_RAW attribute, warn by giving a nice tip. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Steven Rostedt LKML-Reference: <1250543271-8383-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index b160a9f..88eef71 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -184,6 +184,10 @@ static int __cmd_trace(void) header = perf_header__read(input); sample_type = perf_header__sample_type(header); + if (!(sample_type & PERF_SAMPLE_RAW)) + die("No trace sample to read. Did you call perf record " + "without -R?"); + if (load_kernel() < 0) { perror("failed to load kernel symbols"); return EXIT_FAILURE; -- cgit v0.10.2 From 9df37ddd81f54dd41dc4958055c3a3c9b6840aef Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 17 Aug 2009 23:07:50 +0200 Subject: perf tools: Record events info also when :record suffix is used. You can enable a counter's PERF_SAMPLE_RAW attribute in two fashions: - using the -R option (every counters get PERF_SAMPLE_RAW) - using the :record suffix in a trace event counter name Currently we record the events info in a trace.info file from perf record when the former method is used but we omit it with the latter. Check both situations. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Steven Rostedt LKML-Reference: <1250543271-8383-3-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 3ce2f03..acbe594 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -520,9 +520,6 @@ static int __cmd_record(int argc, const char **argv) signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); - if (raw_samples) - read_tracing_data(); - if (!stat(output_name, &st) && st.st_size) { if (!force && !append_file) { fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", @@ -550,6 +547,17 @@ static int __cmd_record(int argc, const char **argv) else header = perf_header__new(); + + if (raw_samples) { + read_tracing_data(); + } else { + for (i = 0; i < nr_counters; i++) { + if (attrs[i].sample_type & PERF_SAMPLE_RAW) { + read_tracing_data(); + break; + } + } + } atexit(atexit_header); if (!system_wide) { -- cgit v0.10.2 From 3f9edc2382d5f7c97c693838abb207a9d6bab1fa Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 17 Aug 2009 23:07:51 +0200 Subject: perf tools: Make trace event format parser aware of cast to pointers The ftrace event format parser handles the usual casts but not the cast to pointers. Such casts have been introduced recently with the module trace events and raise the following parsing error: Fatal: bad op token ) This is because it considers the "*" character as a binary operator. Make it then aware of casts to pointers. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Steven Rostedt LKML-Reference: <1250543271-8383-4-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index ead6a9a..b53b27f 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1462,6 +1462,7 @@ process_paren(struct event *event, struct print_arg *arg, char **tok) { struct print_arg *item_arg; enum event_type type; + int ptr_cast = 0; char *token; type = process_arg(event, arg, &token); @@ -1469,11 +1470,26 @@ process_paren(struct event *event, struct print_arg *arg, char **tok) if (type == EVENT_ERROR) return EVENT_ERROR; - if (type == EVENT_OP) - type = process_op(event, arg, &token); + if (type == EVENT_OP) { + /* handle the ptr casts */ + if (!strcmp(token, "*")) { + /* + * FIXME: should we zapp whitespaces before ')' ? + * (may require a peek_token_item()) + */ + if (__peek_char() == ')') { + ptr_cast = 1; + free_token(token); + type = read_token_item(&token); + } + } + if (!ptr_cast) { + type = process_op(event, arg, &token); - if (type == EVENT_ERROR) - return EVENT_ERROR; + if (type == EVENT_ERROR) + return EVENT_ERROR; + } + } if (test_type_token(type, token, EVENT_DELIM, (char *)")")) { free_token(token); @@ -1499,6 +1515,13 @@ process_paren(struct event *event, struct print_arg *arg, char **tok) item_arg = malloc_or_die(sizeof(*item_arg)); arg->type = PRINT_TYPE; + if (ptr_cast) { + char *old = arg->atom.atom; + + arg->atom.atom = malloc_or_die(strlen(old + 3)); + sprintf(arg->atom.atom, "%s *", old); + free(old); + } arg->typecast.type = arg->atom.atom; arg->typecast.item = item_arg; type = process_arg_token(event, item_arg, &token, type); -- cgit v0.10.2 From 3a5209e3b26386fd174820ee6e8e27479b24869a Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 17 Aug 2009 16:00:30 -0700 Subject: trace_skb: fix build when CONFIG_NET is not enabled Fix trace_skb_sources build when CONFIG_NET is not enabled: kernel/built-in.o: In function `probe_skb_dequeue': trace_skb_sources.c:(.text+0xd9152): undefined reference to `init_net' trace_skb_sources.c:(.text+0xd9188): undefined reference to `dev_get_by_index' Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index f09d763..9a2f19b 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -236,6 +236,7 @@ config BOOT_TRACER config SKB_SOURCES_TRACER bool "Trace skb source information" + depends on NET select GENERIC_TRACER help This tracer helps developers/sysadmins correlate skb allocation and -- cgit v0.10.2 From ae6e2aef6c03ccb06c6baaa1b77cc0e0ae226faf Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 17 Aug 2009 10:35:49 +0000 Subject: phonet: fix build when PROC_FS is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix phonet build when PROC_FS is not enabled: net/built-in.o: In function `pn_sock_open': socket.c:(.text+0x23c649): undefined reference to `seq_open_net' net/built-in.o:(.rodata+0x21018): undefined reference to `seq_release_net' Signed-off-by: Randy Dunlap Acked-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/net/phonet/socket.c b/net/phonet/socket.c index 5f26c37..7a4ee39 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -413,6 +413,7 @@ found: } EXPORT_SYMBOL(pn_sock_get_port); +#ifdef CONFIG_PROC_FS static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos) { struct net *net = seq_file_net(seq); @@ -509,3 +510,4 @@ const struct file_operations pn_sock_seq_fops = { .llseek = seq_lseek, .release = seq_release_net, }; +#endif -- cgit v0.10.2 From a65027e4d80ece5a5a3bd4fc4808a83208430929 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 17 Aug 2009 00:58:04 +0000 Subject: be2net: Set mac addr in hw regardless of netif_running() be_mac_addr_set() currently is broken when netif_running() is false. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 45507d8..3623460 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -117,23 +117,18 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped) iowrite32(val, adapter->db + DB_CQ_OFFSET); } - static int be_mac_addr_set(struct net_device *netdev, void *p) { struct be_adapter *adapter = netdev_priv(netdev); struct sockaddr *addr = p; int status = 0; - if (netif_running(netdev)) { - status = be_cmd_pmac_del(adapter, adapter->if_handle, - adapter->pmac_id); - if (status) - return status; - - status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, - adapter->if_handle, &adapter->pmac_id); - } + status = be_cmd_pmac_del(adapter, adapter->if_handle, adapter->pmac_id); + if (status) + return status; + status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, + adapter->if_handle, &adapter->pmac_id); if (!status) memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); -- cgit v0.10.2 From b628bde2b5390776efc30837798d016ec1aa3ebe Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 17 Aug 2009 00:58:26 +0000 Subject: be2net: refactor be_msix_(un)register() code. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 3623460..010175f 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1303,6 +1303,12 @@ rx_eq_free: return rc; } +/* There are 8 evt ids per func. Retruns the evt id's bit number */ +static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id) +{ + return eq_id - 8 * be_pci_func(adapter); +} + static irqreturn_t be_intx(int irq, void *dev) { struct be_adapter *adapter = dev; @@ -1476,31 +1482,44 @@ static void be_msix_enable(struct be_adapter *adapter) static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id) { - return adapter->msix_entries[eq_id - 8 * be_pci_func(adapter)].vector; + return adapter->msix_entries[ + be_evt_bit_get(adapter, eq_id)].vector; } -static int be_msix_register(struct be_adapter *adapter) +static int be_request_irq(struct be_adapter *adapter, + struct be_eq_obj *eq_obj, + void *handler, char *desc) { struct net_device *netdev = adapter->netdev; - struct be_eq_obj *tx_eq = &adapter->tx_eq; - struct be_eq_obj *rx_eq = &adapter->rx_eq; - int status, vec; + int vec; + + sprintf(eq_obj->desc, "%s-%s", netdev->name, desc); + vec = be_msix_vec_get(adapter, eq_obj->q.id); + return request_irq(vec, handler, 0, eq_obj->desc, adapter); +} + +static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj) +{ + int vec = be_msix_vec_get(adapter, eq_obj->q.id); + free_irq(vec, adapter); +} - sprintf(tx_eq->desc, "%s-tx", netdev->name); - vec = be_msix_vec_get(adapter, tx_eq->q.id); - status = request_irq(vec, be_msix_tx_mcc, 0, tx_eq->desc, adapter); +static int be_msix_register(struct be_adapter *adapter) +{ + int status; + + status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx"); if (status) goto err; - sprintf(rx_eq->desc, "%s-rx", netdev->name); - vec = be_msix_vec_get(adapter, rx_eq->q.id); - status = request_irq(vec, be_msix_rx, 0, rx_eq->desc, adapter); - if (status) { /* Free TX IRQ */ - vec = be_msix_vec_get(adapter, tx_eq->q.id); - free_irq(vec, adapter); - goto err; - } + status = be_request_irq(adapter, &adapter->rx_eq, be_msix_rx, "rx"); + if (status) + goto free_tx_irq; + return 0; + +free_tx_irq: + be_free_irq(adapter, &adapter->tx_eq); err: dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n", status); @@ -1537,7 +1556,6 @@ done: static void be_irq_unregister(struct be_adapter *adapter) { struct net_device *netdev = adapter->netdev; - int vec; if (!adapter->isr_registered) return; @@ -1549,10 +1567,8 @@ static void be_irq_unregister(struct be_adapter *adapter) } /* MSIx */ - vec = be_msix_vec_get(adapter, adapter->tx_eq.q.id); - free_irq(vec, adapter); - vec = be_msix_vec_get(adapter, adapter->rx_eq.q.id); - free_irq(vec, adapter); + be_free_irq(adapter, &adapter->tx_eq); + be_free_irq(adapter, &adapter->rx_eq); done: adapter->isr_registered = false; return; -- cgit v0.10.2 From 1a8887d81ac4bbee6153b4bc9b9f9e099fb5f07e Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 17 Aug 2009 00:58:41 +0000 Subject: be2net: destroy mcc queue before tx queues As mcc queue uses the tx event queue. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 010175f..7b9efee 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1655,12 +1655,12 @@ do_none: static int be_clear(struct be_adapter *adapter) { + be_mcc_queues_destroy(adapter); be_rx_queues_destroy(adapter); be_tx_queues_destroy(adapter); be_cmd_if_destroy(adapter, adapter->if_handle); - be_mcc_queues_destroy(adapter); return 0; } -- cgit v0.10.2 From 5213a780295895630530aebacdd19217a5379c9a Mon Sep 17 00:00:00 2001 From: Konrad Eisele Date: Mon, 17 Aug 2009 00:13:29 +0000 Subject: sparc,leon: CONFIG_SPARC_LEON option and leon specific files. The macro CONFIG_SPARC_LEON will shield, if undefined, the sun-sparc code from LEON specific code. In particular include/asm/leon.h will get empty through #ifdef and leon_kernel.c and leon_mm.c will not be compiled. Signed-off-by: Konrad Eisele Reviewed-by: Sam Ravnborg Signed-off-by: David S. Miller diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 3f8b6a9..b847f88 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -437,6 +437,17 @@ config SERIAL_CONSOLE If unsure, say N. +config SPARC_LEON + bool "Sparc Leon processor family" + depends on SPARC32 + ---help--- + If you say Y here if you are running on a SPARC-LEON processor. + The LEON processor is a synthesizable VHDL model of the + SPARC-v8 standard. LEON is part of the GRLIB collection of + IP cores that are distributed under GPL. GRLIB can be downloaded + from www.gaisler.com. You can download a sparc-linux cross-compilation + toolchain at www.gaisler.com. + endmenu menu "Bus options (PCI etc.)" diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h new file mode 100644 index 0000000..28a42b7 --- /dev/null +++ b/arch/sparc/include/asm/leon.h @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2004 Konrad Eisele (eiselekd@web.de,konrad@gaisler.com) Gaisler Research + * Copyright (C) 2004 Stefan Holst (mail@s-holst.de) Uni-Stuttgart + * Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com) Aeroflex Gaisler AB + * Copyright (C) 2009 Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB + */ + +#ifndef LEON_H_INCLUDE +#define LEON_H_INCLUDE + +#ifdef CONFIG_SPARC_LEON + +#define ASI_LEON_NOCACHE 0x01 + +#define ASI_LEON_DCACHE_MISS 0x1 + +#define ASI_LEON_CACHEREGS 0x02 +#define ASI_LEON_IFLUSH 0x10 +#define ASI_LEON_DFLUSH 0x11 + +#define ASI_LEON_MMUFLUSH 0x18 +#define ASI_LEON_MMUREGS 0x19 +#define ASI_LEON_BYPASS 0x1c +#define ASI_LEON_FLUSH_PAGE 0x10 + +/* mmu register access, ASI_LEON_MMUREGS */ +#define LEON_CNR_CTRL 0x000 +#define LEON_CNR_CTXP 0x100 +#define LEON_CNR_CTX 0x200 +#define LEON_CNR_F 0x300 +#define LEON_CNR_FADDR 0x400 + +#define LEON_CNR_CTX_NCTX 256 /*number of MMU ctx */ + +#define LEON_CNR_CTRL_TLBDIS 0x80000000 + +#define LEON_MMUTLB_ENT_MAX 64 + +/* + * diagnostic access from mmutlb.vhd: + * 0: pte address + * 4: pte + * 8: additional flags + */ +#define LEON_DIAGF_LVL 0x3 +#define LEON_DIAGF_WR 0x8 +#define LEON_DIAGF_WR_SHIFT 3 +#define LEON_DIAGF_HIT 0x10 +#define LEON_DIAGF_HIT_SHIFT 4 +#define LEON_DIAGF_CTX 0x1fe0 +#define LEON_DIAGF_CTX_SHIFT 5 +#define LEON_DIAGF_VALID 0x2000 +#define LEON_DIAGF_VALID_SHIFT 13 + +/* + * Interrupt Sources + * + * The interrupt source numbers directly map to the trap type and to + * the bits used in the Interrupt Clear, Interrupt Force, Interrupt Mask, + * and the Interrupt Pending Registers. + */ +#define LEON_INTERRUPT_CORRECTABLE_MEMORY_ERROR 1 +#define LEON_INTERRUPT_UART_1_RX_TX 2 +#define LEON_INTERRUPT_UART_0_RX_TX 3 +#define LEON_INTERRUPT_EXTERNAL_0 4 +#define LEON_INTERRUPT_EXTERNAL_1 5 +#define LEON_INTERRUPT_EXTERNAL_2 6 +#define LEON_INTERRUPT_EXTERNAL_3 7 +#define LEON_INTERRUPT_TIMER1 8 +#define LEON_INTERRUPT_TIMER2 9 +#define LEON_INTERRUPT_EMPTY1 10 +#define LEON_INTERRUPT_EMPTY2 11 +#define LEON_INTERRUPT_OPEN_ETH 12 +#define LEON_INTERRUPT_EMPTY4 13 +#define LEON_INTERRUPT_EMPTY5 14 +#define LEON_INTERRUPT_EMPTY6 15 + +/* irq masks */ +#define LEON_HARD_INT(x) (1 << (x)) /* irq 0-15 */ +#define LEON_IRQMASK_R 0x0000fffe /* bit 15- 1 of lregs.irqmask */ +#define LEON_IRQPRIO_R 0xfffe0000 /* bit 31-17 of lregs.irqmask */ + +/* leon uart register definitions */ +#define LEON_OFF_UDATA 0x0 +#define LEON_OFF_USTAT 0x4 +#define LEON_OFF_UCTRL 0x8 +#define LEON_OFF_USCAL 0xc + +#define LEON_UCTRL_RE 0x01 +#define LEON_UCTRL_TE 0x02 +#define LEON_UCTRL_RI 0x04 +#define LEON_UCTRL_TI 0x08 +#define LEON_UCTRL_PS 0x10 +#define LEON_UCTRL_PE 0x20 +#define LEON_UCTRL_FL 0x40 +#define LEON_UCTRL_LB 0x80 + +#define LEON_USTAT_DR 0x01 +#define LEON_USTAT_TS 0x02 +#define LEON_USTAT_TH 0x04 +#define LEON_USTAT_BR 0x08 +#define LEON_USTAT_OV 0x10 +#define LEON_USTAT_PE 0x20 +#define LEON_USTAT_FE 0x40 + +#define LEON_MCFG2_SRAMDIS 0x00002000 +#define LEON_MCFG2_SDRAMEN 0x00004000 +#define LEON_MCFG2_SRAMBANKSZ 0x00001e00 /* [12-9] */ +#define LEON_MCFG2_SRAMBANKSZ_SHIFT 9 +#define LEON_MCFG2_SDRAMBANKSZ 0x03800000 /* [25-23] */ +#define LEON_MCFG2_SDRAMBANKSZ_SHIFT 23 + +#define LEON_TCNT0_MASK 0x7fffff + +#define LEON_USTAT_ERROR (LEON_USTAT_OV | LEON_USTAT_PE | LEON_USTAT_FE) +/* no break yet */ + +#define ASI_LEON3_SYSCTRL 0x02 +#define ASI_LEON3_SYSCTRL_ICFG 0x08 +#define ASI_LEON3_SYSCTRL_DCFG 0x0c +#define ASI_LEON3_SYSCTRL_CFG_SNOOPING (1 << 27) +#define ASI_LEON3_SYSCTRL_CFG_SSIZE(c) (1 << ((c >> 20) & 0xf)) + +#ifndef __ASSEMBLY__ + +/* do a virtual address read without cache */ +static inline unsigned long leon_readnobuffer_reg(unsigned long paddr) +{ + unsigned long retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r"(retval) : "r"(paddr), "i"(ASI_LEON_NOCACHE)); + return retval; +} + +/* do a physical address bypass write, i.e. for 0x80000000 */ +static inline void leon_store_reg(unsigned long paddr, unsigned long value) +{ + __asm__ __volatile__("sta %0, [%1] %2\n\t" : : "r"(value), "r"(paddr), + "i"(ASI_LEON_BYPASS) : "memory"); +} + +/* do a physical address bypass load, i.e. for 0x80000000 */ +static inline unsigned long leon_load_reg(unsigned long paddr) +{ + unsigned long retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r"(retval) : "r"(paddr), "i"(ASI_LEON_BYPASS)); + return retval; +} + +extern inline void leon_srmmu_disabletlb(void) +{ + unsigned int retval; + __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0), + "i"(ASI_LEON_MMUREGS)); + retval |= LEON_CNR_CTRL_TLBDIS; + __asm__ __volatile__("sta %0, [%%g0] %2\n\t" : : "r"(retval), "r"(0), + "i"(ASI_LEON_MMUREGS) : "memory"); +} + +extern inline void leon_srmmu_enabletlb(void) +{ + unsigned int retval; + __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0), + "i"(ASI_LEON_MMUREGS)); + retval = retval & ~LEON_CNR_CTRL_TLBDIS; + __asm__ __volatile__("sta %0, [%%g0] %2\n\t" : : "r"(retval), "r"(0), + "i"(ASI_LEON_MMUREGS) : "memory"); +} + +/* macro access for leon_load_reg() and leon_store_reg() */ +#define LEON3_BYPASS_LOAD_PA(x) (leon_load_reg((unsigned long)(x))) +#define LEON3_BYPASS_STORE_PA(x, v) (leon_store_reg((unsigned long)(x), (unsigned long)(v))) +#define LEON3_BYPASS_ANDIN_PA(x, v) LEON3_BYPASS_STORE_PA(x, LEON3_BYPASS_LOAD_PA(x) & v) +#define LEON3_BYPASS_ORIN_PA(x, v) LEON3_BYPASS_STORE_PA(x, LEON3_BYPASS_LOAD_PA(x) | v) +#define LEON_BYPASS_LOAD_PA(x) leon_load_reg((unsigned long)(x)) +#define LEON_BYPASS_STORE_PA(x, v) leon_store_reg((unsigned long)(x), (unsigned long)(v)) +#define LEON_REGLOAD_PA(x) leon_load_reg((unsigned long)(x)+LEON_PREGS) +#define LEON_REGSTORE_PA(x, v) leon_store_reg((unsigned long)(x)+LEON_PREGS, (unsigned long)(v)) +#define LEON_REGSTORE_OR_PA(x, v) LEON_REGSTORE_PA(x, LEON_REGLOAD_PA(x) | (unsigned long)(v)) +#define LEON_REGSTORE_AND_PA(x, v) LEON_REGSTORE_PA(x, LEON_REGLOAD_PA(x) & (unsigned long)(v)) + +/* macro access for leon_readnobuffer_reg() */ +#define LEON_BYPASSCACHE_LOAD_VA(x) leon_readnobuffer_reg((unsigned long)(x)) + +extern void sparc_leon_eirq_register(int eirq); +extern void leon_init(void); +extern void leon_switch_mm(void); +extern void leon_init_IRQ(void); + +extern unsigned long last_valid_pfn; + +extern inline unsigned long sparc_leon3_get_dcachecfg(void) +{ + unsigned int retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r"(retval) : + "r"(ASI_LEON3_SYSCTRL_DCFG), + "i"(ASI_LEON3_SYSCTRL)); + return retval; +} + +/* enable snooping */ +extern inline void sparc_leon3_enable_snooping(void) +{ + __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t" + "set 0x800000, %%l2\n\t" + "or %%l2, %%l1, %%l2\n\t" + "sta %%l2, [%%g0] 2\n\t" : : : "l1", "l2"); +}; + +extern inline void sparc_leon3_disable_cache(void) +{ + __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t" + "set 0x00000f, %%l2\n\t" + "andn %%l2, %%l1, %%l2\n\t" + "sta %%l2, [%%g0] 2\n\t" : : : "l1", "l2"); +}; + +#endif /*!__ASSEMBLY__*/ + +#ifdef CONFIG_SMP +# define LEON3_IRQ_RESCHEDULE 13 +# define LEON3_IRQ_TICKER (leon_percpu_timer_dev[0].irq) +# define LEON3_IRQ_CROSS_CALL 15 +#endif + +#if defined(PAGE_SIZE_LEON_8K) +#define LEON_PAGE_SIZE_LEON 1 +#elif defined(PAGE_SIZE_LEON_16K) +#define LEON_PAGE_SIZE_LEON 2) +#else +#define LEON_PAGE_SIZE_LEON 0 +#endif + +#if LEON_PAGE_SIZE_LEON == 0 +/* [ 8, 6, 6 ] + 12 */ +#define LEON_PGD_SH 24 +#define LEON_PGD_M 0xff +#define LEON_PMD_SH 18 +#define LEON_PMD_SH_V (LEON_PGD_SH-2) +#define LEON_PMD_M 0x3f +#define LEON_PTE_SH 12 +#define LEON_PTE_M 0x3f +#elif LEON_PAGE_SIZE_LEON == 1 +/* [ 7, 6, 6 ] + 13 */ +#define LEON_PGD_SH 25 +#define LEON_PGD_M 0x7f +#define LEON_PMD_SH 19 +#define LEON_PMD_SH_V (LEON_PGD_SH-1) +#define LEON_PMD_M 0x3f +#define LEON_PTE_SH 13 +#define LEON_PTE_M 0x3f +#elif LEON_PAGE_SIZE_LEON == 2 +/* [ 6, 6, 6 ] + 14 */ +#define LEON_PGD_SH 26 +#define LEON_PGD_M 0x3f +#define LEON_PMD_SH 20 +#define LEON_PMD_SH_V (LEON_PGD_SH-0) +#define LEON_PMD_M 0x3f +#define LEON_PTE_SH 14 +#define LEON_PTE_M 0x3f +#elif LEON_PAGE_SIZE_LEON == 3 +/* [ 4, 7, 6 ] + 15 */ +#define LEON_PGD_SH 28 +#define LEON_PGD_M 0x0f +#define LEON_PMD_SH 21 +#define LEON_PMD_SH_V (LEON_PGD_SH-0) +#define LEON_PMD_M 0x7f +#define LEON_PTE_SH 15 +#define LEON_PTE_M 0x3f +#else +#error cannot determine LEON_PAGE_SIZE_LEON +#endif + +#define PAGE_MIN_SHIFT (12) +#define PAGE_MIN_SIZE (1UL << PAGE_MIN_SHIFT) + +#define LEON3_XCCR_SETS_MASK 0x07000000UL +#define LEON3_XCCR_SSIZE_MASK 0x00f00000UL + +#define LEON2_CCR_DSETS_MASK 0x03000000UL +#define LEON2_CFG_SSIZE_MASK 0x00007000UL + +#ifndef __ASSEMBLY__ +extern unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr); +extern void leon_flush_icache_all(void); +extern void leon_flush_dcache_all(void); +extern void leon_flush_cache_all(void); +extern void leon_flush_tlb_all(void); +extern int leon_flush_during_switch; +extern int leon_flush_needed(void); + +struct vm_area_struct; +extern void leon_flush_icache_all(void); +extern void leon_flush_dcache_all(void); +extern void leon_flush_pcache_all(struct vm_area_struct *vma, unsigned long page); +extern void leon_flush_cache_all(void); +extern void leon_flush_tlb_all(void); +extern int leon_flush_during_switch; +extern int leon_flush_needed(void); +extern void leon_flush_pcache_all(struct vm_area_struct *vma, unsigned long page); + +/* struct that hold LEON3 cache configuration registers */ +struct leon3_cacheregs { + unsigned long ccr; /* 0x00 - Cache Control Register */ + unsigned long iccr; /* 0x08 - Instruction Cache Configuration Register */ + unsigned long dccr; /* 0x0c - Data Cache Configuration Register */ +}; + +/* struct that hold LEON2 cache configuration register + * & configuration register + */ +struct leon2_cacheregs { + unsigned long ccr, cfg; +}; + +#ifdef __KERNEL__ + +#include + +struct device_node; +extern int sparc_leon_eirq_get(int eirq, int cpu); +extern irqreturn_t sparc_leon_eirq_isr(int dummy, void *dev_id); +extern void sparc_leon_eirq_register(int eirq); +extern void leon_clear_clock_irq(void); +extern void leon_load_profile_irq(int cpu, unsigned int limit); +extern void leon_init_timers(irq_handler_t counter_fn); +extern void leon_clear_clock_irq(void); +extern void leon_load_profile_irq(int cpu, unsigned int limit); +extern void leon_trans_init(struct device_node *dp); +extern void leon_node_init(struct device_node *dp, struct device_node ***nextp); +extern void leon_init_IRQ(void); +extern void leon_init(void); +extern unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr); +extern void init_leon(void); +extern void poke_leonsparc(void); +extern void leon3_getCacheRegs(struct leon3_cacheregs *regs); +extern int leon_flush_needed(void); +extern void leon_switch_mm(void); +extern int srmmu_swprobe_trace; + +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ + +/* macros used in leon_mm.c */ +#define PFN(x) ((x) >> PAGE_SHIFT) +#define _pfn_valid(pfn) ((pfn < last_valid_pfn) && (pfn >= PFN(phys_base))) +#define _SRMMU_PTE_PMASK_LEON 0xffffffff + +#else /* defined(CONFIG_SPARC_LEON) */ + +/* nop definitions for !LEON case */ +#define leon_init() do {} while (0) +#define leon_switch_mm() do {} while (0) +#define leon_init_IRQ() do {} while (0) +#define init_leon() do {} while (0) + +#endif /* !defined(CONFIG_SPARC_LEON) */ + +#endif diff --git a/arch/sparc/include/asm/leon_amba.h b/arch/sparc/include/asm/leon_amba.h new file mode 100644 index 0000000..618e888 --- /dev/null +++ b/arch/sparc/include/asm/leon_amba.h @@ -0,0 +1,263 @@ +/* +*Copyright (C) 2004 Konrad Eisele (eiselekd@web.de,konrad@gaisler.com), Gaisler Research +*Copyright (C) 2004 Stefan Holst (mail@s-holst.de), Uni-Stuttgart +*Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com),Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB +*/ + +#ifndef LEON_AMBA_H_INCLUDE +#define LEON_AMBA_H_INCLUDE + +#ifndef __ASSEMBLY__ + +struct amba_prom_registers { + unsigned int phys_addr; /* The physical address of this register */ + unsigned int reg_size; /* How many bytes does this register take up? */ +}; + +#endif + +/* + * The following defines the bits in the LEON UART Status Registers. + */ + +#define LEON_REG_UART_STATUS_DR 0x00000001 /* Data Ready */ +#define LEON_REG_UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */ +#define LEON_REG_UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */ +#define LEON_REG_UART_STATUS_BR 0x00000008 /* Break Error */ +#define LEON_REG_UART_STATUS_OE 0x00000010 /* RX Overrun Error */ +#define LEON_REG_UART_STATUS_PE 0x00000020 /* RX Parity Error */ +#define LEON_REG_UART_STATUS_FE 0x00000040 /* RX Framing Error */ +#define LEON_REG_UART_STATUS_ERR 0x00000078 /* Error Mask */ + +/* + * The following defines the bits in the LEON UART Ctrl Registers. + */ + +#define LEON_REG_UART_CTRL_RE 0x00000001 /* Receiver enable */ +#define LEON_REG_UART_CTRL_TE 0x00000002 /* Transmitter enable */ +#define LEON_REG_UART_CTRL_RI 0x00000004 /* Receiver interrupt enable */ +#define LEON_REG_UART_CTRL_TI 0x00000008 /* Transmitter irq */ +#define LEON_REG_UART_CTRL_PS 0x00000010 /* Parity select */ +#define LEON_REG_UART_CTRL_PE 0x00000020 /* Parity enable */ +#define LEON_REG_UART_CTRL_FL 0x00000040 /* Flow control enable */ +#define LEON_REG_UART_CTRL_LB 0x00000080 /* Loop Back enable */ + +#define LEON3_GPTIMER_EN 1 +#define LEON3_GPTIMER_RL 2 +#define LEON3_GPTIMER_LD 4 +#define LEON3_GPTIMER_IRQEN 8 +#define LEON3_GPTIMER_SEPIRQ 8 + +#define LEON23_REG_TIMER_CONTROL_EN 0x00000001 /* 1 = enable counting */ +/* 0 = hold scalar and counter */ +#define LEON23_REG_TIMER_CONTROL_RL 0x00000002 /* 1 = reload at 0 */ + /* 0 = stop at 0 */ +#define LEON23_REG_TIMER_CONTROL_LD 0x00000004 /* 1 = load counter */ + /* 0 = no function */ +#define LEON23_REG_TIMER_CONTROL_IQ 0x00000008 /* 1 = irq enable */ + /* 0 = no function */ + +/* + * The following defines the bits in the LEON PS/2 Status Registers. + */ + +#define LEON_REG_PS2_STATUS_DR 0x00000001 /* Data Ready */ +#define LEON_REG_PS2_STATUS_PE 0x00000002 /* Parity error */ +#define LEON_REG_PS2_STATUS_FE 0x00000004 /* Framing error */ +#define LEON_REG_PS2_STATUS_KI 0x00000008 /* Keyboard inhibit */ +#define LEON_REG_PS2_STATUS_RF 0x00000010 /* RX buffer full */ +#define LEON_REG_PS2_STATUS_TF 0x00000020 /* TX buffer full */ + +/* + * The following defines the bits in the LEON PS/2 Ctrl Registers. + */ + +#define LEON_REG_PS2_CTRL_RE 0x00000001 /* Receiver enable */ +#define LEON_REG_PS2_CTRL_TE 0x00000002 /* Transmitter enable */ +#define LEON_REG_PS2_CTRL_RI 0x00000004 /* Keyboard receive irq */ +#define LEON_REG_PS2_CTRL_TI 0x00000008 /* Keyboard transmit irq */ + +#define LEON3_IRQMPSTATUS_CPUNR 28 +#define LEON3_IRQMPSTATUS_BROADCAST 27 + +#define GPTIMER_CONFIG_IRQNT(a) (((a) >> 3) & 0x1f) +#define GPTIMER_CONFIG_ISSEP(a) ((a) & (1 << 8)) +#define GPTIMER_CONFIG_NTIMERS(a) ((a) & (0x7)) +#define LEON3_GPTIMER_CTRL_PENDING 0x10 +#define LEON3_GPTIMER_CONFIG_NRTIMERS(c) ((c)->config & 0x7) +#define LEON3_GPTIMER_CTRL_ISPENDING(r) (((r)&LEON3_GPTIMER_CTRL_PENDING) ? 1 : 0) + +#ifdef CONFIG_SPARC_LEON + +#ifndef __ASSEMBLY__ + +struct leon3_irqctrl_regs_map { + u32 ilevel; + u32 ipend; + u32 iforce; + u32 iclear; + u32 mpstatus; + u32 mpbroadcast; + u32 notused02; + u32 notused03; + u32 notused10; + u32 notused11; + u32 notused12; + u32 notused13; + u32 notused20; + u32 notused21; + u32 notused22; + u32 notused23; + u32 mask[16]; + u32 force[16]; + /* Extended IRQ registers */ + u32 intid[16]; /* 0xc0 */ +}; + +struct leon3_apbuart_regs_map { + u32 data; + u32 status; + u32 ctrl; + u32 scaler; +}; + +struct leon3_gptimerelem_regs_map { + u32 val; + u32 rld; + u32 ctrl; + u32 unused; +}; + +struct leon3_gptimer_regs_map { + u32 scalar; + u32 scalar_reload; + u32 config; + u32 unused; + struct leon3_gptimerelem_regs_map e[8]; +}; + +/* + * Types and structure used for AMBA Plug & Play bus scanning + */ + +#define AMBA_MAXAPB_DEVS 64 +#define AMBA_MAXAPB_DEVS_PERBUS 16 + +struct amba_device_table { + int devnr; /* number of devices on AHB or APB bus */ + unsigned int *addr[16]; /* addresses to the devices configuration tables */ + unsigned int allocbits[1]; /* 0=unallocated, 1=allocated driver */ +}; + +struct amba_apbslv_device_table { + int devnr; /* number of devices on AHB or APB bus */ + unsigned int *addr[AMBA_MAXAPB_DEVS]; /* addresses to the devices configuration tables */ + unsigned int apbmst[AMBA_MAXAPB_DEVS]; /* apb master if a entry is a apb slave */ + unsigned int apbmstidx[AMBA_MAXAPB_DEVS]; /* apb master idx if a entry is a apb slave */ + unsigned int allocbits[4]; /* 0=unallocated, 1=allocated driver */ +}; + +struct amba_confarea_type { + struct amba_confarea_type *next;/* next bus in chain */ + struct amba_device_table ahbmst; + struct amba_device_table ahbslv; + struct amba_apbslv_device_table apbslv; + unsigned int apbmst; +}; + +/* collect apb slaves */ +struct amba_apb_device { + unsigned int start, irq, bus_id; + struct amba_confarea_type *bus; +}; + +/* collect ahb slaves */ +struct amba_ahb_device { + unsigned int start[4], irq, bus_id; + struct amba_confarea_type *bus; +}; + +struct device_node; +void _amba_init(struct device_node *dp, struct device_node ***nextp); + +extern struct leon3_irqctrl_regs_map *leon3_irqctrl_regs; +extern struct leon3_gptimer_regs_map *leon3_gptimer_regs; +extern struct amba_apb_device leon_percpu_timer_dev[16]; +extern int leondebug_irq_disable; +extern int leon_debug_irqout; +extern unsigned long leon3_gptimer_irq; +extern unsigned int sparc_leon_eirq; + +#endif /* __ASSEMBLY__ */ + +#define LEON3_IO_AREA 0xfff00000 +#define LEON3_CONF_AREA 0xff000 +#define LEON3_AHB_SLAVE_CONF_AREA (1 << 11) + +#define LEON3_AHB_CONF_WORDS 8 +#define LEON3_APB_CONF_WORDS 2 +#define LEON3_AHB_MASTERS 16 +#define LEON3_AHB_SLAVES 16 +#define LEON3_APB_SLAVES 16 +#define LEON3_APBUARTS 8 + +/* Vendor codes */ +#define VENDOR_GAISLER 1 +#define VENDOR_PENDER 2 +#define VENDOR_ESA 4 +#define VENDOR_OPENCORES 8 + +/* Gaisler Research device id's */ +#define GAISLER_LEON3 0x003 +#define GAISLER_LEON3DSU 0x004 +#define GAISLER_ETHAHB 0x005 +#define GAISLER_APBMST 0x006 +#define GAISLER_AHBUART 0x007 +#define GAISLER_SRCTRL 0x008 +#define GAISLER_SDCTRL 0x009 +#define GAISLER_APBUART 0x00C +#define GAISLER_IRQMP 0x00D +#define GAISLER_AHBRAM 0x00E +#define GAISLER_GPTIMER 0x011 +#define GAISLER_PCITRG 0x012 +#define GAISLER_PCISBRG 0x013 +#define GAISLER_PCIFBRG 0x014 +#define GAISLER_PCITRACE 0x015 +#define GAISLER_PCIDMA 0x016 +#define GAISLER_AHBTRACE 0x017 +#define GAISLER_ETHDSU 0x018 +#define GAISLER_PIOPORT 0x01A +#define GAISLER_GRGPIO 0x01A +#define GAISLER_AHBJTAG 0x01c +#define GAISLER_ETHMAC 0x01D +#define GAISLER_AHB2AHB 0x020 +#define GAISLER_USBDC 0x021 +#define GAISLER_ATACTRL 0x024 +#define GAISLER_DDRSPA 0x025 +#define GAISLER_USBEHC 0x026 +#define GAISLER_USBUHC 0x027 +#define GAISLER_I2CMST 0x028 +#define GAISLER_SPICTRL 0x02D +#define GAISLER_DDR2SPA 0x02E +#define GAISLER_SPIMCTRL 0x045 +#define GAISLER_LEON4 0x048 +#define GAISLER_LEON4DSU 0x049 +#define GAISLER_AHBSTAT 0x052 +#define GAISLER_FTMCTRL 0x054 +#define GAISLER_KBD 0x060 +#define GAISLER_VGA 0x061 +#define GAISLER_SVGA 0x063 +#define GAISLER_GRSYSMON 0x066 +#define GAISLER_GRACECTRL 0x067 + +#define GAISLER_L2TIME 0xffd /* internal device: leon2 timer */ +#define GAISLER_L2C 0xffe /* internal device: leon2compat */ +#define GAISLER_PLUGPLAY 0xfff /* internal device: plug & play configarea */ + +#define amba_vendor(x) (((x) >> 24) & 0xff) + +#define amba_device(x) (((x) >> 12) & 0xfff) + +#endif /* !defined(CONFIG_SPARC_LEON) */ + +#endif diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c new file mode 100644 index 0000000..54d8a5b --- /dev/null +++ b/arch/sparc/kernel/leon_kernel.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com) Aeroflex Gaisler AB + * Copyright (C) 2009 Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "prom.h" +#include "irq.h" + +struct leon3_irqctrl_regs_map *leon3_irqctrl_regs; /* interrupt controller base address, initialized by amba_init() */ +struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base address, initialized by amba_init() */ +struct amba_apb_device leon_percpu_timer_dev[16]; + +int leondebug_irq_disable; +int leon_debug_irqout; +static int dummy_master_l10_counter; + +unsigned long leon3_gptimer_irq; /* interrupt controller irq number, initialized by amba_init() */ +unsigned int sparc_leon_eirq; +#define LEON_IMASK ((&leon3_irqctrl_regs->mask[0])) + +/* Return the IRQ of the pending IRQ on the extended IRQ controller */ +int sparc_leon_eirq_get(int eirq, int cpu) +{ + return LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->intid[cpu]) & 0x1f; +} + +irqreturn_t sparc_leon_eirq_isr(int dummy, void *dev_id) +{ + printk(KERN_ERR "sparc_leon_eirq_isr: ERROR EXTENDED IRQ\n"); + return IRQ_HANDLED; +} + +/* The extended IRQ controller has been found, this function registers it */ +void sparc_leon_eirq_register(int eirq) +{ + int irq; + + /* Register a "BAD" handler for this interrupt, it should never happen */ + irq = request_irq(eirq, sparc_leon_eirq_isr, + (IRQF_DISABLED | SA_STATIC_ALLOC), "extirq", NULL); + + if (irq) { + printk(KERN_ERR + "sparc_leon_eirq_register: unable to attach IRQ%d\n", + eirq); + } else { + sparc_leon_eirq = eirq; + } + +} + +static inline unsigned long get_irqmask(unsigned int irq) +{ + unsigned long mask; + + if (!irq || ((irq > 0xf) && !sparc_leon_eirq) + || ((irq > 0x1f) && sparc_leon_eirq)) { + printk(KERN_ERR + "leon_get_irqmask: false irq number: %d\n", irq); + mask = 0; + } else { + mask = LEON_HARD_INT(irq); + } + return mask; +} + +static void leon_enable_irq(unsigned int irq_nr) +{ + unsigned long mask, flags; + mask = get_irqmask(irq_nr); + local_irq_save(flags); + LEON3_BYPASS_STORE_PA(LEON_IMASK, + (LEON3_BYPASS_LOAD_PA(LEON_IMASK) | (mask))); + local_irq_restore(flags); +} + +static void leon_disable_irq(unsigned int irq_nr) +{ + unsigned long mask, flags; + mask = get_irqmask(irq_nr); + local_irq_save(flags); + LEON3_BYPASS_STORE_PA(LEON_IMASK, + (LEON3_BYPASS_LOAD_PA(LEON_IMASK) & ~(mask))); + local_irq_restore(flags); + +} + +void __init leon_init_timers(irq_handler_t counter_fn) +{ + int irq; + + leondebug_irq_disable = 0; + leon_debug_irqout = 0; + master_l10_counter = (unsigned int *)&dummy_master_l10_counter; + dummy_master_l10_counter = 0; + + if (leon3_gptimer_regs && leon3_irqctrl_regs) { + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].val, 0); + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].rld, + (((1000000 / 100) - 1))); + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0); + + } else { + printk(KERN_ERR "No Timer/irqctrl found\n"); + BUG(); + } + + irq = request_irq(leon3_gptimer_irq, + counter_fn, + (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); + + if (irq) { + printk(KERN_ERR "leon_time_init: unable to attach IRQ%d\n", + LEON_INTERRUPT_TIMER1); + prom_halt(); + } + + if (leon3_gptimer_regs) { + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, + LEON3_GPTIMER_EN | + LEON3_GPTIMER_RL | + LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); + } +} + +void leon_clear_clock_irq(void) +{ +} + +void leon_load_profile_irq(int cpu, unsigned int limit) +{ + BUG(); +} + + + + +void __init leon_trans_init(struct device_node *dp) +{ + if (strcmp(dp->type, "cpu") == 0 && strcmp(dp->name, "") == 0) { + struct property *p; + p = of_find_property(dp, "mid", (void *)0); + if (p) { + int mid; + dp->name = prom_early_alloc(5 + 1); + memcpy(&mid, p->value, p->length); + sprintf((char *)dp->name, "cpu%.2d", mid); + } + } +} + +void __initdata (*prom_amba_init)(struct device_node *dp, struct device_node ***nextp) = 0; + +void __init leon_node_init(struct device_node *dp, struct device_node ***nextp) +{ + if (prom_amba_init && + strcmp(dp->type, "ambapp") == 0 && + strcmp(dp->name, "ambapp0") == 0) { + prom_amba_init(dp, nextp); + } +} + +void __init leon_init_IRQ(void) +{ + sparc_init_timers = leon_init_timers; + + BTFIXUPSET_CALL(enable_irq, leon_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_irq, leon_disable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(enable_pil_irq, leon_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_pil_irq, leon_disable_irq, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq, + BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(load_profile_irq, leon_load_profile_irq, + BTFIXUPCALL_NOP); + +#ifdef CONFIG_SMP + BTFIXUPSET_CALL(set_cpu_int, leon_set_cpu_int, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(clear_cpu_int, leon_clear_ipi, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(set_irq_udt, leon_set_udt, BTFIXUPCALL_NORM); +#endif + +} + +void __init leon_init(void) +{ + prom_build_more = &leon_node_init; +} diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c new file mode 100644 index 0000000..c0e0129 --- /dev/null +++ b/arch/sparc/mm/leon_mm.c @@ -0,0 +1,260 @@ +/* + * linux/arch/sparc/mm/leon_m.c + * + * Copyright (C) 2004 Konrad Eisele (eiselekd@web.de, konrad@gaisler.com) Gaisler Research + * Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com) Aeroflex Gaisler AB + * Copyright (C) 2009 Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB + * + * do srmmu probe in software + * + */ + +#include +#include +#include +#include +#include + +int leon_flush_during_switch = 1; +int srmmu_swprobe_trace; + +unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr) +{ + + unsigned int ctxtbl; + unsigned int pgd, pmd, ped; + unsigned int ptr; + unsigned int lvl, pte, paddrbase; + unsigned int ctx; + unsigned int paddr_calc; + + paddrbase = 0; + + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: trace on\n"); + + ctxtbl = srmmu_get_ctable_ptr(); + if (!(ctxtbl)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: srmmu_get_ctable_ptr returned 0=>0\n"); + return 0; + } + if (!_pfn_valid(PFN(ctxtbl))) { + if (srmmu_swprobe_trace) + printk(KERN_INFO + "swprobe: !_pfn_valid(%x)=>0\n", + PFN(ctxtbl)); + return 0; + } + + ctx = srmmu_get_context(); + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: --- ctx (%x) ---\n", ctx); + + pgd = LEON_BYPASS_LOAD_PA(ctxtbl + (ctx * 4)); + + if (((pgd & SRMMU_ET_MASK) == SRMMU_ET_PTE)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: pgd is entry level 3\n"); + lvl = 3; + pte = pgd; + paddrbase = pgd & _SRMMU_PTE_PMASK_LEON; + goto ready; + } + if (((pgd & SRMMU_ET_MASK) != SRMMU_ET_PTD)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: pgd is invalid => 0\n"); + return 0; + } + + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: --- pgd (%x) ---\n", pgd); + + ptr = (pgd & SRMMU_PTD_PMASK) << 4; + ptr += ((((vaddr) >> LEON_PGD_SH) & LEON_PGD_M) * 4); + if (!_pfn_valid(PFN(ptr))) + return 0; + + pmd = LEON_BYPASS_LOAD_PA(ptr); + if (((pmd & SRMMU_ET_MASK) == SRMMU_ET_PTE)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: pmd is entry level 2\n"); + lvl = 2; + pte = pmd; + paddrbase = pmd & _SRMMU_PTE_PMASK_LEON; + goto ready; + } + if (((pmd & SRMMU_ET_MASK) != SRMMU_ET_PTD)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: pmd is invalid => 0\n"); + return 0; + } + + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: --- pmd (%x) ---\n", pmd); + + ptr = (pmd & SRMMU_PTD_PMASK) << 4; + ptr += (((vaddr >> LEON_PMD_SH) & LEON_PMD_M) * 4); + if (!_pfn_valid(PFN(ptr))) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: !_pfn_valid(%x)=>0\n", + PFN(ptr)); + return 0; + } + + ped = LEON_BYPASS_LOAD_PA(ptr); + + if (((ped & SRMMU_ET_MASK) == SRMMU_ET_PTE)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: ped is entry level 1\n"); + lvl = 1; + pte = ped; + paddrbase = ped & _SRMMU_PTE_PMASK_LEON; + goto ready; + } + if (((ped & SRMMU_ET_MASK) != SRMMU_ET_PTD)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: ped is invalid => 0\n"); + return 0; + } + + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: --- ped (%x) ---\n", ped); + + ptr = (ped & SRMMU_PTD_PMASK) << 4; + ptr += (((vaddr >> LEON_PTE_SH) & LEON_PTE_M) * 4); + if (!_pfn_valid(PFN(ptr))) + return 0; + + ptr = LEON_BYPASS_LOAD_PA(ptr); + if (((ptr & SRMMU_ET_MASK) == SRMMU_ET_PTE)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: ptr is entry level 0\n"); + lvl = 0; + pte = ptr; + paddrbase = ptr & _SRMMU_PTE_PMASK_LEON; + goto ready; + } + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: ptr is invalid => 0\n"); + return 0; + +ready: + switch (lvl) { + case 0: + paddr_calc = + (vaddr & ~(-1 << LEON_PTE_SH)) | ((pte & ~0xff) << 4); + break; + case 1: + paddr_calc = + (vaddr & ~(-1 << LEON_PMD_SH)) | ((pte & ~0xff) << 4); + break; + case 2: + paddr_calc = + (vaddr & ~(-1 << LEON_PGD_SH)) | ((pte & ~0xff) << 4); + break; + default: + case 3: + paddr_calc = vaddr; + break; + } + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: padde %x\n", paddr_calc); + if (paddr) + *paddr = paddr_calc; + return paddrbase; +} + +void leon_flush_icache_all(void) +{ + __asm__ __volatile__(" flush "); /*iflush*/ +} + +void leon_flush_dcache_all(void) +{ + __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : : + "i"(ASI_LEON_DFLUSH) : "memory"); +} + +void leon_flush_pcache_all(struct vm_area_struct *vma, unsigned long page) +{ + if (vma->vm_flags & VM_EXEC) + leon_flush_icache_all(); + leon_flush_dcache_all(); +} + +void leon_flush_cache_all(void) +{ + __asm__ __volatile__(" flush "); /*iflush*/ + __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : : + "i"(ASI_LEON_DFLUSH) : "memory"); +} + +void leon_flush_tlb_all(void) +{ + leon_flush_cache_all(); + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : "r"(0x400), + "i"(ASI_LEON_MMUFLUSH) : "memory"); +} + +/* get all cache regs */ +void leon3_getCacheRegs(struct leon3_cacheregs *regs) +{ + unsigned long ccr, iccr, dccr; + + if (!regs) + return; + /* Get Cache regs from "Cache ASI" address 0x0, 0x8 and 0xC */ + __asm__ __volatile__("lda [%%g0] %3, %0\n\t" + "mov 0x08, %%g1\n\t" + "lda [%%g1] %3, %1\n\t" + "mov 0x0c, %%g1\n\t" + "lda [%%g1] %3, %2\n\t" + : "=r"(ccr), "=r"(iccr), "=r"(dccr) + /* output */ + : "i"(ASI_LEON_CACHEREGS) /* input */ + : "g1" /* clobber list */ + ); + regs->ccr = ccr; + regs->iccr = iccr; + regs->dccr = dccr; +} + +/* Due to virtual cache we need to check cache configuration if + * it is possible to skip flushing in some cases. + * + * Leon2 and Leon3 differ in their way of telling cache information + * + */ +int leon_flush_needed(void) +{ + int flush_needed = -1; + unsigned int ssize, sets; + char *setStr[4] = + { "direct mapped", "2-way associative", "3-way associative", + "4-way associative" + }; + /* leon 3 */ + struct leon3_cacheregs cregs; + leon3_getCacheRegs(&cregs); + sets = (cregs.dccr & LEON3_XCCR_SETS_MASK) >> 24; + /* (ssize=>realsize) 0=>1k, 1=>2k, 2=>4k, 3=>8k ... */ + ssize = 1 << ((cregs.dccr & LEON3_XCCR_SSIZE_MASK) >> 20); + + printk(KERN_INFO "CACHE: %s cache, set size %dk\n", + sets > 3 ? "unknown" : setStr[sets], ssize); + if ((ssize <= (PAGE_SIZE / 1024)) && (sets == 0)) { + /* Set Size <= Page size ==> + flush on every context switch not needed. */ + flush_needed = 0; + printk(KERN_INFO "CACHE: not flushing on every context switch\n"); + } + return flush_needed; +} + +void leon_switch_mm(void) +{ + flush_tlb_mm((void *)0); + if (leon_flush_during_switch) + leon_flush_cache_all(); +} -- cgit v0.10.2 From 97fb58fa9bb509b49090a1c62ed1b660d518c66b Mon Sep 17 00:00:00 2001 From: Konrad Eisele Date: Mon, 17 Aug 2009 00:13:30 +0000 Subject: sparc,leon: Redefine MMU register access asi if CONFIG_LEON SPARC-LEON has a different ASI for mmu register accesses. Signed-off-by: Konrad Eisele Reviewed-by: Sam Ravnborg Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/asi.h b/arch/sparc/include/asm/asi.h index 74703c5..b2e3db6 100644 --- a/arch/sparc/include/asm/asi.h +++ b/arch/sparc/include/asm/asi.h @@ -40,7 +40,11 @@ #define ASI_M_UNA01 0x01 /* Same here... */ #define ASI_M_MXCC 0x02 /* Access to TI VIKING MXCC registers */ #define ASI_M_FLUSH_PROBE 0x03 /* Reference MMU Flush/Probe; rw, ss */ +#ifndef CONFIG_SPARC_LEON #define ASI_M_MMUREGS 0x04 /* MMU Registers; rw, ss */ +#else +#define ASI_M_MMUREGS 0x19 +#endif /* CONFIG_SPARC_LEON */ #define ASI_M_TLBDIAG 0x05 /* MMU TLB only Diagnostics */ #define ASI_M_DIAGS 0x06 /* Reference MMU Diagnostics */ #define ASI_M_IODIAG 0x07 /* MMU I/O TLB only Diagnostics */ -- cgit v0.10.2 From 0fd7ef1fe0e6e70c7851ce65a2eb8a8d3f49147e Mon Sep 17 00:00:00 2001 From: Konrad Eisele Date: Mon, 17 Aug 2009 00:13:31 +0000 Subject: sparc,leon: Introduce the sparc-leon CPU type. Add sparc_leon enum, M_LEON|M_LEON3_SOC machine. Add compilation of leon.c in mm and kernel if CONFIG_SPARC_LEON is defined. Add sparc_leon dependent initialization to switch statements + head.S. Signed-off-by: Konrad Eisele Reviewed-by: Sam Ravnborg Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/machines.h b/arch/sparc/include/asm/machines.h index c28c2f2..cd9c099 100644 --- a/arch/sparc/include/asm/machines.h +++ b/arch/sparc/include/asm/machines.h @@ -15,7 +15,7 @@ struct Sun_Machine_Models { /* Current number of machines we know about that has an IDPROM * machtype entry including one entry for the 0x80 OBP machines. */ -#define NUM_SUN_MACHINES 15 +#define NUM_SUN_MACHINES 16 /* The machine type in the idprom area looks like this: * @@ -30,6 +30,7 @@ struct Sun_Machine_Models { #define SM_ARCH_MASK 0xf0 #define SM_SUN4 0x20 +#define M_LEON 0x30 #define SM_SUN4C 0x50 #define SM_SUN4M 0x70 #define SM_SUN4M_OBP 0x80 @@ -41,6 +42,9 @@ struct Sun_Machine_Models { #define SM_4_330 0x03 /* Sun 4/300 series */ #define SM_4_470 0x04 /* Sun 4/400 series */ +/* Leon machines */ +#define M_LEON3_SOC 0x02 /* Leon3 SoC */ + /* Sun4c machines Full Name - PROM NAME */ #define SM_4C_SS1 0x01 /* Sun4c SparcStation 1 - Sun 4/60 */ #define SM_4C_IPC 0x02 /* Sun4c SparcStation IPC - Sun 4/40 */ diff --git a/arch/sparc/include/asm/pgtsrmmu.h b/arch/sparc/include/asm/pgtsrmmu.h index 808555f..1407c07 100644 --- a/arch/sparc/include/asm/pgtsrmmu.h +++ b/arch/sparc/include/asm/pgtsrmmu.h @@ -267,6 +267,7 @@ static inline void srmmu_flush_tlb_page(unsigned long page) } +#ifndef CONFIG_SPARC_LEON static inline unsigned long srmmu_hwprobe(unsigned long vaddr) { unsigned long retval; @@ -278,6 +279,9 @@ static inline unsigned long srmmu_hwprobe(unsigned long vaddr) return retval; } +#else +#define srmmu_hwprobe(addr) (srmmu_swprobe(addr, 0) & SRMMU_PTE_PMASK) +#endif static inline int srmmu_get_pte (unsigned long addr) diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index be8d7aa..82a190d 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -118,5 +118,8 @@ extern struct device_node *of_console_device; extern char *of_console_path; extern char *of_console_options; +extern void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp); +extern char *build_full_name(struct device_node *dp); + #endif /* __KERNEL__ */ #endif /* _SPARC_PROM_H */ diff --git a/arch/sparc/include/asm/system_32.h b/arch/sparc/include/asm/system_32.h index 751c8c1..890036b 100644 --- a/arch/sparc/include/asm/system_32.h +++ b/arch/sparc/include/asm/system_32.h @@ -32,6 +32,7 @@ enum sparc_cpu { sun4u = 0x05, /* V8 ploos ploos */ sun_unknown = 0x06, ap1000 = 0x07, /* almost a sun4m */ + sparc_leon = 0x08, /* Leon SoC */ }; /* Really, userland should not be looking at any of this... */ diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 475ce46..b004175 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -41,6 +41,8 @@ obj-y += of_device_common.o obj-y += of_device_$(BITS).o obj-$(CONFIG_SPARC64) += prom_irqtrans.o +obj-$(CONFIG_SPARC_LEON)+= leon_kernel.o + obj-$(CONFIG_SPARC64) += reboot.o obj-$(CONFIG_SPARC64) += sysfs.o obj-$(CONFIG_SPARC64) += iommu.o diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c index d85c3dc..1446df9 100644 --- a/arch/sparc/kernel/cpu.c +++ b/arch/sparc/kernel/cpu.c @@ -312,7 +312,12 @@ void __cpuinit cpu_probe(void) psr = get_psr(); put_psr(psr | PSR_EF); +#ifdef CONFIG_SPARC_LEON + fpu_vers = 7; +#else fpu_vers = ((get_fsr() >> 17) & 0x7); +#endif + put_psr(psr); set_cpu_and_fpu(psr_impl, psr_vers, fpu_vers); diff --git a/arch/sparc/kernel/head_32.S b/arch/sparc/kernel/head_32.S index 6b4d8ac..439d82a 100644 --- a/arch/sparc/kernel/head_32.S +++ b/arch/sparc/kernel/head_32.S @@ -809,6 +809,11 @@ found_version: nop got_prop: +#ifdef CONFIG_SPARC_LEON + /* no cpu-type check is needed, it is a SPARC-LEON */ + ba sun4c_continue_boot + nop +#endif set cputypval, %o2 ldub [%o2 + 0x4], %l1 diff --git a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c index 57922f6..52a15fe 100644 --- a/arch/sparc/kernel/idprom.c +++ b/arch/sparc/kernel/idprom.c @@ -31,6 +31,8 @@ static struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = { { .name = "Sun 4/200 Series", .id_machtype = (SM_SUN4 | SM_4_260) }, { .name = "Sun 4/300 Series", .id_machtype = (SM_SUN4 | SM_4_330) }, { .name = "Sun 4/400 Series", .id_machtype = (SM_SUN4 | SM_4_470) }, +/* Now Leon */ +{ .name = "Leon3 System-on-a-Chip", .id_machtype = (M_LEON | M_LEON3_SOC) }, /* Now, Sun4c's */ { .name = "Sun4c SparcStation 1", .id_machtype = (SM_SUN4C | SM_4C_SS1) }, { .name = "Sun4c SparcStation IPC", .id_machtype = (SM_SUN4C | SM_4C_IPC) }, diff --git a/arch/sparc/kernel/irq_32.c b/arch/sparc/kernel/irq_32.c index ad800b8..e1af437 100644 --- a/arch/sparc/kernel/irq_32.c +++ b/arch/sparc/kernel/irq_32.c @@ -45,6 +45,7 @@ #include #include #include +#include #include "kernel.h" #include "irq.h" @@ -661,6 +662,10 @@ void __init init_IRQ(void) sun4d_init_IRQ(); break; + case sparc_leon: + leon_init_IRQ(); + break; + default: prom_printf("Cannot initialize IRQs on this Sun machine..."); break; diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index 998cadb..16a47ff 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c @@ -235,6 +235,8 @@ void __init setup_arch(char **cmdline_p) sparc_cpu_model = sun4e; if (!strcmp(&cputypval,"sun4u")) sparc_cpu_model = sun4u; + if (!strncmp(&cputypval, "leon" , 4)) + sparc_cpu_model = sparc_leon; printk("ARCH: "); switch(sparc_cpu_model) { @@ -256,6 +258,9 @@ void __init setup_arch(char **cmdline_p) case sun4u: printk("SUN4U\n"); break; + case sparc_leon: + printk("LEON\n"); + break; default: printk("UNKNOWN!\n"); break; diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile index 681abe0..79836a7 100644 --- a/arch/sparc/mm/Makefile +++ b/arch/sparc/mm/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SPARC32) += loadmmu.o obj-y += generic_$(BITS).o obj-$(CONFIG_SPARC32) += extable.o btfixup.o srmmu.o iommu.o io-unit.o obj-$(CONFIG_SPARC32) += hypersparc.o viking.o tsunami.o swift.o +obj-$(CONFIG_SPARC_LEON)+= leon_mm.o # Only used by sparc64 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c index 26bb391..54114ad 100644 --- a/arch/sparc/mm/init_32.c +++ b/arch/sparc/mm/init_32.c @@ -34,6 +34,7 @@ #include /* bug in asm-generic/tlb.h: check_pgt_cache */ #include #include +#include DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); @@ -326,6 +327,9 @@ void __init paging_init(void) sparc_unmapped_base = 0xe0000000; BTFIXUPSET_SETHI(sparc_unmapped_base, 0xe0000000); break; + case sparc_leon: + leon_init(); + /* fall through */ case sun4m: case sun4d: srmmu_paging_init(); diff --git a/arch/sparc/mm/loadmmu.c b/arch/sparc/mm/loadmmu.c index 652be05..82ec8f6 100644 --- a/arch/sparc/mm/loadmmu.c +++ b/arch/sparc/mm/loadmmu.c @@ -33,6 +33,7 @@ void __init load_mmu(void) break; case sun4m: case sun4d: + case sparc_leon: ld_mmu_srmmu(); break; default: -- cgit v0.10.2 From e63829de3d03f92cea2b26119e0aa9a7043b9913 Mon Sep 17 00:00:00 2001 From: Konrad Eisele Date: Mon, 17 Aug 2009 00:13:32 +0000 Subject: sparc,leon: Added support for AMBAPP bus. The device is a AMBA bus if it is a child of prom node "ambapp" (AMBA plug and play). Two functions leon_trans_init() and leon_node_init() (defined in sparc/kernel/leon_kernel.c) are called in the prom_build_tree() path if CONFIG_SPARC_LEON is defined. leon_node_init() will build up the device tree using AMBA plug and play. Also: a extra check was addes to prom_common.c:build_one_prop() in case a rom-node is undefined which can happen for SPARC-LEON because it creates only a minimum nodes to emulate sparc behaviour. Signed-off-by: Konrad Eisele Reviewed-by: Sam Ravnborg Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/of_device_32.c b/arch/sparc/kernel/of_device_32.c index 9039670..4c26eb5 100644 --- a/arch/sparc/kernel/of_device_32.c +++ b/arch/sparc/kernel/of_device_32.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "of_device_common.h" @@ -97,6 +99,35 @@ static unsigned long of_bus_sbus_get_flags(const u32 *addr, unsigned long flags) return IORESOURCE_MEM; } + /* + * AMBAPP bus specific translator + */ + +static int of_bus_ambapp_match(struct device_node *np) +{ + return !strcmp(np->name, "ambapp"); +} + +static void of_bus_ambapp_count_cells(struct device_node *child, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 1; + if (sizec) + *sizec = 1; +} + +static int of_bus_ambapp_map(u32 *addr, const u32 *range, + int na, int ns, int pna) +{ + return of_bus_default_map(addr, range, na, ns, pna); +} + +static unsigned long of_bus_ambapp_get_flags(const u32 *addr, + unsigned long flags) +{ + return IORESOURCE_MEM; +} /* * Array of bus specific translators @@ -121,6 +152,15 @@ static struct of_bus of_busses[] = { .map = of_bus_default_map, .get_flags = of_bus_sbus_get_flags, }, + /* AMBA */ + { + .name = "ambapp", + .addr_prop_name = "reg", + .match = of_bus_ambapp_match, + .count_cells = of_bus_ambapp_count_cells, + .map = of_bus_ambapp_map, + .get_flags = of_bus_ambapp_get_flags, + }, /* Default */ { .name = "default", diff --git a/arch/sparc/kernel/prom_32.c b/arch/sparc/kernel/prom_32.c index fe43e80..0a37e8c 100644 --- a/arch/sparc/kernel/prom_32.c +++ b/arch/sparc/kernel/prom_32.c @@ -24,6 +24,8 @@ #include #include +#include +#include #include "prom.h" @@ -131,6 +133,35 @@ static void __init ebus_path_component(struct device_node *dp, char *tmp_buf) regs->which_io, regs->phys_addr); } +/* "name:vendor:device@irq,addrlo" */ +static void __init ambapp_path_component(struct device_node *dp, char *tmp_buf) +{ + struct amba_prom_registers *regs; unsigned int *intr; + unsigned int *device, *vendor; + struct property *prop; + + prop = of_find_property(dp, "reg", NULL); + if (!prop) + return; + regs = prop->value; + prop = of_find_property(dp, "interrupts", NULL); + if (!prop) + return; + intr = prop->value; + prop = of_find_property(dp, "vendor", NULL); + if (!prop) + return; + vendor = prop->value; + prop = of_find_property(dp, "device", NULL); + if (!prop) + return; + device = prop->value; + + sprintf(tmp_buf, "%s:%d:%d@%x,%x", + dp->name, *vendor, *device, + *intr, regs->phys_addr); +} + static void __init __build_path_component(struct device_node *dp, char *tmp_buf) { struct device_node *parent = dp->parent; @@ -143,6 +174,8 @@ static void __init __build_path_component(struct device_node *dp, char *tmp_buf) return sbus_path_component(dp, tmp_buf); if (!strcmp(parent->type, "ebus")) return ebus_path_component(dp, tmp_buf); + if (!strcmp(parent->type, "ambapp")) + return ambapp_path_component(dp, tmp_buf); /* "isa" is handled with platform naming */ } diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c index 0fb5789..138910c 100644 --- a/arch/sparc/kernel/prom_common.c +++ b/arch/sparc/kernel/prom_common.c @@ -22,9 +22,12 @@ #include #include #include +#include #include "prom.h" +void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp); + struct device_node *of_console_device; EXPORT_SYMBOL(of_console_device); @@ -161,7 +164,7 @@ static struct property * __init build_one_prop(phandle node, char *prev, name = prom_nextprop(node, prev, p->name); } - if (strlen(name) == 0) { + if (!name || strlen(name) == 0) { tmp = p; return NULL; } @@ -242,7 +245,7 @@ static struct device_node * __init prom_create_node(phandle node, return dp; } -static char * __init build_full_name(struct device_node *dp) +char * __init build_full_name(struct device_node *dp) { int len, ourlen, plen; char *n; @@ -289,6 +292,9 @@ static struct device_node * __init prom_build_tree(struct device_node *parent, dp->child = prom_build_tree(dp, prom_getchild(node), nextp); + if (prom_build_more) + prom_build_more(dp, nextp); + node = prom_getsibling(node); } -- cgit v0.10.2 From 75d9e34698540e96b422293e1d76ab02cc7faefb Mon Sep 17 00:00:00 2001 From: Konrad Eisele Date: Mon, 17 Aug 2009 00:13:33 +0000 Subject: sparc, leon: sparc-leon specific SRMMU initialization and bootup fixes. The sparc-leon caches are virtually tagged so a flush is needed on ctx switch. Signed-off-by: Konrad Eisele Reviewed-by: Sam Ravnborg Signed-off-by: David S. Miller diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index ade4eb3..509b1ff 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -569,6 +570,9 @@ static void srmmu_switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, srmmu_ctxd_set(&srmmu_context_table[mm->context], mm->pgd); } + if (sparc_cpu_model == sparc_leon) + leon_switch_mm(); + if (is_hypersparc) hyper_flush_whole_icache(); @@ -1977,6 +1981,45 @@ static void __init init_viking(void) poke_srmmu = poke_viking; } +#ifdef CONFIG_SPARC_LEON + +void __init poke_leonsparc(void) +{ +} + +void __init init_leon(void) +{ + + srmmu_name = "Leon"; + + BTFIXUPSET_CALL(flush_cache_all, leon_flush_cache_all, + BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_mm, leon_flush_cache_all, + BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_page, leon_flush_pcache_all, + BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_range, leon_flush_cache_all, + BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_page_for_dma, leon_flush_dcache_all, + BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(flush_tlb_all, leon_flush_tlb_all, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_mm, leon_flush_tlb_all, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_page, leon_flush_tlb_all, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_range, leon_flush_tlb_all, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(__flush_page_to_ram, leon_flush_cache_all, + BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(flush_sig_insns, leon_flush_cache_all, BTFIXUPCALL_NOP); + + poke_srmmu = poke_leonsparc; + + srmmu_cache_pagetables = 0; + + leon_flush_during_switch = leon_flush_needed(); +} +#endif + /* Probe for the srmmu chip version. */ static void __init get_srmmu_type(void) { @@ -1992,7 +2035,15 @@ static void __init get_srmmu_type(void) psr_typ = (psr >> 28) & 0xf; psr_vers = (psr >> 24) & 0xf; - /* First, check for HyperSparc or Cypress. */ + /* First, check for sparc-leon. */ + if (sparc_cpu_model == sparc_leon) { + psr_typ = 0xf; /* hardcoded ids for older models/simulators */ + psr_vers = 2; + init_leon(); + return; + } + + /* Second, check for HyperSparc or Cypress. */ if(mod_typ == 1) { switch(mod_rev) { case 7: -- cgit v0.10.2 From 1660e9d3d04b6c636b7171bf6c08ac7b82a7de79 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 17 Aug 2009 14:36:32 +1000 Subject: powerpc/32: Always order writes to halves of 64-bit PTEs On 32-bit systems with 64-bit PTEs, the PTEs have to be written in two 32-bit halves. On SMP we write the higher-order half and then the lower-order half, with a write barrier between the two halves, but on UP there was no particular ordering of the writes to the two halves. This extends the ordering that we already do on SMP to the UP case as well. The reason is that with the perf_counter subsystem potentially accessing user memory at interrupt time to get stack traces, we have to be careful not to create an incorrect but apparently valid PTE even on UP. Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index eb17da7..2a5da06 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -104,8 +104,8 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, else pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte)); -#elif defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP) - /* Second case is 32-bit with 64-bit PTE in SMP mode. In this case, we +#elif defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT) + /* Second case is 32-bit with 64-bit PTE. In this case, we * can just store as long as we do the two halves in the right order * with a barrier in between. This is possible because we take care, * in the hash code, to pre-invalidate if the PTE was already hashed, @@ -140,7 +140,7 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, #else /* Anything else just stores the PTE normally. That covers all 64-bit - * cases, and 32-bit non-hash with 64-bit PTEs in UP mode + * cases, and 32-bit non-hash with 32-bit PTEs. */ *ptep = pte; #endif -- cgit v0.10.2 From 9c1e105238c474d19905af504f2e7f42d4f71f9e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 17 Aug 2009 15:17:54 +1000 Subject: powerpc: Allow perf_counters to access user memory at interrupt time This provides a mechanism to allow the perf_counters code to access user memory in a PMU interrupt routine. Such an access can cause various kinds of interrupt: SLB miss, MMU hash table miss, segment table miss, or TLB miss, depending on the processor. This commit only deals with 64-bit classic/server processors, which use an MMU hash table. 32-bit processors are already able to access user memory at interrupt time. Since we don't soft-disable on 32-bit, we avoid the possibility of reentering hash_page or the TLB miss handlers, since they run with interrupts disabled. On 64-bit processors, an SLB miss interrupt on a user address will update the slb_cache and slb_cache_ptr fields in the paca. This is OK except in the case where a PMU interrupt occurs in switch_slb, which also accesses those fields. To prevent this, we hard-disable interrupts in switch_slb. Interrupts are already soft-disabled at this point, and will get hard-enabled when they get soft-enabled later. This also reworks slb_flush_and_rebolt: to avoid hard-disabling twice, and to make sure that it clears the slb_cache_ptr when called from other callers than switch_slb, the existing routine is renamed to __slb_flush_and_rebolt, which is called by switch_slb and the new version of slb_flush_and_rebolt. Similarly, switch_stab (used on POWER3 and RS64 processors) gets a hard_irq_disable() to protect the per-cpu variables used there and in ste_allocate. If a MMU hashtable miss interrupt occurs, normally we would call hash_page to look up the Linux PTE for the address and create a HPTE. However, hash_page is fairly complex and takes some locks, so to avoid the possibility of deadlock, we check the preemption count to see if we are in a (pseudo-)NMI handler, and if so, we don't call hash_page but instead treat it like a bad access that will get reported up through the exception table mechanism. An interrupt whose handler runs even though the interrupt occurred when soft-disabled (such as the PMU interrupt) is considered a pseudo-NMI handler, which should use nmi_enter()/nmi_exit() rather than irq_enter()/irq_exit(). Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 561b646..197b156 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -67,6 +67,8 @@ int main(void) DEFINE(MMCONTEXTID, offsetof(struct mm_struct, context.id)); #ifdef CONFIG_PPC64 DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); + DEFINE(SIGSEGV, SIGSEGV); + DEFINE(NMI_MASK, NMI_MASK); #else DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index eb89811..8ac85e0 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -729,6 +729,11 @@ BEGIN_FTR_SECTION bne- do_ste_alloc /* If so handle it */ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) + clrrdi r11,r1,THREAD_SHIFT + lwz r0,TI_PREEMPT(r11) /* If we're in an "NMI" */ + andis. r0,r0,NMI_MASK@h /* (i.e. an irq when soft-disabled) */ + bne 77f /* then don't call hash_page now */ + /* * On iSeries, we soft-disable interrupts here, then * hard-enable interrupts so that the hash_page code can spin on @@ -833,6 +838,20 @@ handle_page_fault: bl .low_hash_fault b .ret_from_except +/* + * We come here as a result of a DSI at a point where we don't want + * to call hash_page, such as when we are accessing memory (possibly + * user memory) inside a PMU interrupt that occurred while interrupts + * were soft-disabled. We want to invoke the exception handler for + * the access, or panic if there isn't a handler. + */ +77: bl .save_nvgprs + mr r4,r3 + addi r3,r1,STACK_FRAME_OVERHEAD + li r5,SIGSEGV + bl .bad_page_fault + b .ret_from_except + /* here we have a segment miss */ do_ste_alloc: bl .ste_allocate /* try to insert stab entry */ diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 5b7038f..a685652 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -92,15 +92,13 @@ static inline void create_shadowed_slbe(unsigned long ea, int ssize, : "memory" ); } -void slb_flush_and_rebolt(void) +static void __slb_flush_and_rebolt(void) { /* If you change this make sure you change SLB_NUM_BOLTED * appropriately too. */ unsigned long linear_llp, vmalloc_llp, lflags, vflags; unsigned long ksp_esid_data, ksp_vsid_data; - WARN_ON(!irqs_disabled()); - linear_llp = mmu_psize_defs[mmu_linear_psize].sllp; vmalloc_llp = mmu_psize_defs[mmu_vmalloc_psize].sllp; lflags = SLB_VSID_KERNEL | linear_llp; @@ -117,12 +115,6 @@ void slb_flush_and_rebolt(void) ksp_vsid_data = get_slb_shadow()->save_area[2].vsid; } - /* - * We can't take a PMU exception in the following code, so hard - * disable interrupts. - */ - hard_irq_disable(); - /* We need to do this all in asm, so we're sure we don't touch * the stack between the slbia and rebolting it. */ asm volatile("isync\n" @@ -139,6 +131,21 @@ void slb_flush_and_rebolt(void) : "memory"); } +void slb_flush_and_rebolt(void) +{ + + WARN_ON(!irqs_disabled()); + + /* + * We can't take a PMU exception in the following code, so hard + * disable interrupts. + */ + hard_irq_disable(); + + __slb_flush_and_rebolt(); + get_paca()->slb_cache_ptr = 0; +} + void slb_vmalloc_update(void) { unsigned long vflags; @@ -180,12 +187,20 @@ static inline int esids_match(unsigned long addr1, unsigned long addr2) /* Flush all user entries from the segment table of the current processor. */ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) { - unsigned long offset = get_paca()->slb_cache_ptr; + unsigned long offset; unsigned long slbie_data = 0; unsigned long pc = KSTK_EIP(tsk); unsigned long stack = KSTK_ESP(tsk); unsigned long unmapped_base; + /* + * We need interrupts hard-disabled here, not just soft-disabled, + * so that a PMU interrupt can't occur, which might try to access + * user memory (to get a stack trace) and possible cause an SLB miss + * which would update the slb_cache/slb_cache_ptr fields in the PACA. + */ + hard_irq_disable(); + offset = get_paca()->slb_cache_ptr; if (!cpu_has_feature(CPU_FTR_NO_SLBIE_B) && offset <= SLB_CACHE_ENTRIES) { int i; @@ -200,7 +215,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) } asm volatile("isync" : : : "memory"); } else { - slb_flush_and_rebolt(); + __slb_flush_and_rebolt(); } /* Workaround POWER5 < DD2.1 issue */ diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 98cd1dc..ab5fb48 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -164,7 +164,7 @@ void switch_stab(struct task_struct *tsk, struct mm_struct *mm) { struct stab_entry *stab = (struct stab_entry *) get_paca()->stab_addr; struct stab_entry *ste; - unsigned long offset = __get_cpu_var(stab_cache_ptr); + unsigned long offset; unsigned long pc = KSTK_EIP(tsk); unsigned long stack = KSTK_ESP(tsk); unsigned long unmapped_base; @@ -172,6 +172,15 @@ void switch_stab(struct task_struct *tsk, struct mm_struct *mm) /* Force previous translations to complete. DRENG */ asm volatile("isync" : : : "memory"); + /* + * We need interrupts hard-disabled here, not just soft-disabled, + * so that a PMU interrupt can't occur, which might try to access + * user memory (to get a stack trace) and possible cause an STAB miss + * which would update the stab_cache/stab_cache_ptr per-cpu variables. + */ + hard_irq_disable(); + + offset = __get_cpu_var(stab_cache_ptr); if (offset <= NR_STAB_CACHE_ENTRIES) { int i; -- cgit v0.10.2 From 20002ded4d937ca87aca6253b874920a96a763c4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 18 Aug 2009 08:25:32 +1000 Subject: perf_counter: powerpc: Add callchain support This adds support for tracing callchains for powerpc, both 32-bit and 64-bit, and both in the kernel and userspace, from PMU interrupt context. The first three entries stored for each callchain are the NIP (next instruction pointer), LR (link register), and the contents of the LR save area in the second stack frame (the first is ignored because the ABI convention on powerpc is that functions save their return address in their caller's stack frame). Because leaf functions don't have to save their return address (LR value) and don't have to establish a stack frame, it's possible for either or both of LR and the second stack frame's LR save area to have valid return addresses in them. This is basically impossible to disambiguate without either reading the code or looking at auxiliary information such as CFI tables. Since we don't want to do either of those things at interrupt time, we store both LR and the second stack frame's LR save area. Once we get past the second stack frame, there is no ambiguity; all return addresses we get are reliable. For kernel traces, we check whether they are valid kernel instruction addresses and store zero instead if they are not (rather than omitting them, which would make it impossible for userspace to know which was which). We also store zero instead of the second stack frame's LR save area value if it is the same as LR. For kernel traces, we check for interrupt frames, and for user traces, we check for signal frames. In each case, since we're starting a new trace, we store a PERF_CONTEXT_KERNEL/USER marker so that userspace knows that the next three entries are NIP, LR and the second stack frame for the interrupted context. We read user memory with __get_user_inatomic. On 64-bit, if this PMU interrupt occurred while interrupts are soft-disabled, and there is no MMU hash table entry for the page, we will get an -EFAULT return from __get_user_inatomic even if there is a valid Linux PTE for the page, since hash_page isn't reentrant. Thus we have code here to read the Linux PTE and access the page via the kernel linear mapping. Since 64-bit doesn't use (or need) highmem there is no need to do kmap_atomic. On 32-bit, we don't do soft interrupt disabling, so this complication doesn't occur and there is no need to fall back to reading the Linux PTE, since hash_page (or the TLB miss handler) will get called automatically if necessary. Note that we cannot get PMU interrupts in the interval during context switch between switch_mm (which switches the user address space) and switch_to (which actually changes current to the new process). On 64-bit this is because interrupts are hard-disabled in switch_mm and stay hard-disabled until they are soft-enabled later, after switch_to has returned. So there is no possibility of trying to do a user stack trace when the user address space is not current's address space. Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index b73396b..9619285 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -97,7 +97,7 @@ obj64-$(CONFIG_AUDIT) += compat_audit.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o -obj-$(CONFIG_PPC_PERF_CTRS) += perf_counter.o +obj-$(CONFIG_PPC_PERF_CTRS) += perf_counter.o perf_callchain.o obj64-$(CONFIG_PPC_PERF_CTRS) += power4-pmu.o ppc970-pmu.o power5-pmu.o \ power5+-pmu.o power6-pmu.o power7-pmu.o obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o diff --git a/arch/powerpc/kernel/perf_callchain.c b/arch/powerpc/kernel/perf_callchain.c new file mode 100644 index 0000000..f74b62c --- /dev/null +++ b/arch/powerpc/kernel/perf_callchain.c @@ -0,0 +1,527 @@ +/* + * Performance counter callchain support - powerpc architecture code + * + * Copyright © 2009 Paul Mackerras, IBM 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PPC64 +#include "ppc32.h" +#endif + +/* + * Store another value in a callchain_entry. + */ +static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip) +{ + unsigned int nr = entry->nr; + + if (nr < PERF_MAX_STACK_DEPTH) { + entry->ip[nr] = ip; + entry->nr = nr + 1; + } +} + +/* + * Is sp valid as the address of the next kernel stack frame after prev_sp? + * The next frame may be in a different stack area but should not go + * back down in the same stack area. + */ +static int valid_next_sp(unsigned long sp, unsigned long prev_sp) +{ + if (sp & 0xf) + return 0; /* must be 16-byte aligned */ + if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD)) + return 0; + if (sp >= prev_sp + STACK_FRAME_OVERHEAD) + return 1; + /* + * sp could decrease when we jump off an interrupt stack + * back to the regular process stack. + */ + if ((sp & ~(THREAD_SIZE - 1)) != (prev_sp & ~(THREAD_SIZE - 1))) + return 1; + return 0; +} + +static void perf_callchain_kernel(struct pt_regs *regs, + struct perf_callchain_entry *entry) +{ + unsigned long sp, next_sp; + unsigned long next_ip; + unsigned long lr; + long level = 0; + unsigned long *fp; + + lr = regs->link; + sp = regs->gpr[1]; + callchain_store(entry, PERF_CONTEXT_KERNEL); + callchain_store(entry, regs->nip); + + if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD)) + return; + + for (;;) { + fp = (unsigned long *) sp; + next_sp = fp[0]; + + if (next_sp == sp + STACK_INT_FRAME_SIZE && + fp[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) { + /* + * This looks like an interrupt frame for an + * interrupt that occurred in the kernel + */ + regs = (struct pt_regs *)(sp + STACK_FRAME_OVERHEAD); + next_ip = regs->nip; + lr = regs->link; + level = 0; + callchain_store(entry, PERF_CONTEXT_KERNEL); + + } else { + if (level == 0) + next_ip = lr; + else + next_ip = fp[STACK_FRAME_LR_SAVE]; + + /* + * We can't tell which of the first two addresses + * we get are valid, but we can filter out the + * obviously bogus ones here. We replace them + * with 0 rather than removing them entirely so + * that userspace can tell which is which. + */ + if ((level == 1 && next_ip == lr) || + (level <= 1 && !kernel_text_address(next_ip))) + next_ip = 0; + + ++level; + } + + callchain_store(entry, next_ip); + if (!valid_next_sp(next_sp, sp)) + return; + sp = next_sp; + } +} + +#ifdef CONFIG_PPC64 + +#ifdef CONFIG_HUGETLB_PAGE +#define is_huge_psize(pagesize) (HPAGE_SHIFT && mmu_huge_psizes[pagesize]) +#else +#define is_huge_psize(pagesize) 0 +#endif + +/* + * On 64-bit we don't want to invoke hash_page on user addresses from + * interrupt context, so if the access faults, we read the page tables + * to find which page (if any) is mapped and access it directly. + */ +static int read_user_stack_slow(void __user *ptr, void *ret, int nb) +{ + pgd_t *pgdir; + pte_t *ptep, pte; + int pagesize; + unsigned long addr = (unsigned long) ptr; + unsigned long offset; + unsigned long pfn; + void *kaddr; + + pgdir = current->mm->pgd; + if (!pgdir) + return -EFAULT; + + pagesize = get_slice_psize(current->mm, addr); + + /* align address to page boundary */ + offset = addr & ((1ul << mmu_psize_defs[pagesize].shift) - 1); + addr -= offset; + + if (is_huge_psize(pagesize)) + ptep = huge_pte_offset(current->mm, addr); + else + ptep = find_linux_pte(pgdir, addr); + + if (ptep == NULL) + return -EFAULT; + pte = *ptep; + if (!pte_present(pte) || !(pte_val(pte) & _PAGE_USER)) + return -EFAULT; + pfn = pte_pfn(pte); + if (!page_is_ram(pfn)) + return -EFAULT; + + /* no highmem to worry about here */ + kaddr = pfn_to_kaddr(pfn); + memcpy(ret, kaddr + offset, nb); + return 0; +} + +static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret) +{ + if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned long) || + ((unsigned long)ptr & 7)) + return -EFAULT; + + if (!__get_user_inatomic(*ret, ptr)) + return 0; + + return read_user_stack_slow(ptr, ret, 8); +} + +static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret) +{ + if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) || + ((unsigned long)ptr & 3)) + return -EFAULT; + + if (!__get_user_inatomic(*ret, ptr)) + return 0; + + return read_user_stack_slow(ptr, ret, 4); +} + +static inline int valid_user_sp(unsigned long sp, int is_64) +{ + if (!sp || (sp & 7) || sp > (is_64 ? TASK_SIZE : 0x100000000UL) - 32) + return 0; + return 1; +} + +/* + * 64-bit user processes use the same stack frame for RT and non-RT signals. + */ +struct signal_frame_64 { + char dummy[__SIGNAL_FRAMESIZE]; + struct ucontext uc; + unsigned long unused[2]; + unsigned int tramp[6]; + struct siginfo *pinfo; + void *puc; + struct siginfo info; + char abigap[288]; +}; + +static int is_sigreturn_64_address(unsigned long nip, unsigned long fp) +{ + if (nip == fp + offsetof(struct signal_frame_64, tramp)) + return 1; + if (vdso64_rt_sigtramp && current->mm->context.vdso_base && + nip == current->mm->context.vdso_base + vdso64_rt_sigtramp) + return 1; + return 0; +} + +/* + * Do some sanity checking on the signal frame pointed to by sp. + * We check the pinfo and puc pointers in the frame. + */ +static int sane_signal_64_frame(unsigned long sp) +{ + struct signal_frame_64 __user *sf; + unsigned long pinfo, puc; + + sf = (struct signal_frame_64 __user *) sp; + if (read_user_stack_64((unsigned long __user *) &sf->pinfo, &pinfo) || + read_user_stack_64((unsigned long __user *) &sf->puc, &puc)) + return 0; + return pinfo == (unsigned long) &sf->info && + puc == (unsigned long) &sf->uc; +} + +static void perf_callchain_user_64(struct pt_regs *regs, + struct perf_callchain_entry *entry) +{ + unsigned long sp, next_sp; + unsigned long next_ip; + unsigned long lr; + long level = 0; + struct signal_frame_64 __user *sigframe; + unsigned long __user *fp, *uregs; + + next_ip = regs->nip; + lr = regs->link; + sp = regs->gpr[1]; + callchain_store(entry, PERF_CONTEXT_USER); + callchain_store(entry, next_ip); + + for (;;) { + fp = (unsigned long __user *) sp; + if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp)) + return; + if (level > 0 && read_user_stack_64(&fp[2], &next_ip)) + return; + + /* + * Note: the next_sp - sp >= signal frame size check + * is true when next_sp < sp, which can happen when + * transitioning from an alternate signal stack to the + * normal stack. + */ + if (next_sp - sp >= sizeof(struct signal_frame_64) && + (is_sigreturn_64_address(next_ip, sp) || + (level <= 1 && is_sigreturn_64_address(lr, sp))) && + sane_signal_64_frame(sp)) { + /* + * This looks like an signal frame + */ + sigframe = (struct signal_frame_64 __user *) sp; + uregs = sigframe->uc.uc_mcontext.gp_regs; + if (read_user_stack_64(&uregs[PT_NIP], &next_ip) || + read_user_stack_64(&uregs[PT_LNK], &lr) || + read_user_stack_64(&uregs[PT_R1], &sp)) + return; + level = 0; + callchain_store(entry, PERF_CONTEXT_USER); + callchain_store(entry, next_ip); + continue; + } + + if (level == 0) + next_ip = lr; + callchain_store(entry, next_ip); + ++level; + sp = next_sp; + } +} + +static inline int current_is_64bit(void) +{ + /* + * We can't use test_thread_flag() here because we may be on an + * interrupt stack, and the thread flags don't get copied over + * from the thread_info on the main stack to the interrupt stack. + */ + return !test_ti_thread_flag(task_thread_info(current), TIF_32BIT); +} + +#else /* CONFIG_PPC64 */ +/* + * On 32-bit we just access the address and let hash_page create a + * HPTE if necessary, so there is no need to fall back to reading + * the page tables. Since this is called at interrupt level, + * do_page_fault() won't treat a DSI as a page fault. + */ +static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret) +{ + if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) || + ((unsigned long)ptr & 3)) + return -EFAULT; + + return __get_user_inatomic(*ret, ptr); +} + +static inline void perf_callchain_user_64(struct pt_regs *regs, + struct perf_callchain_entry *entry) +{ +} + +static inline int current_is_64bit(void) +{ + return 0; +} + +static inline int valid_user_sp(unsigned long sp, int is_64) +{ + if (!sp || (sp & 7) || sp > TASK_SIZE - 32) + return 0; + return 1; +} + +#define __SIGNAL_FRAMESIZE32 __SIGNAL_FRAMESIZE +#define sigcontext32 sigcontext +#define mcontext32 mcontext +#define ucontext32 ucontext +#define compat_siginfo_t struct siginfo + +#endif /* CONFIG_PPC64 */ + +/* + * Layout for non-RT signal frames + */ +struct signal_frame_32 { + char dummy[__SIGNAL_FRAMESIZE32]; + struct sigcontext32 sctx; + struct mcontext32 mctx; + int abigap[56]; +}; + +/* + * Layout for RT signal frames + */ +struct rt_signal_frame_32 { + char dummy[__SIGNAL_FRAMESIZE32 + 16]; + compat_siginfo_t info; + struct ucontext32 uc; + int abigap[56]; +}; + +static int is_sigreturn_32_address(unsigned int nip, unsigned int fp) +{ + if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad)) + return 1; + if (vdso32_sigtramp && current->mm->context.vdso_base && + nip == current->mm->context.vdso_base + vdso32_sigtramp) + return 1; + return 0; +} + +static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp) +{ + if (nip == fp + offsetof(struct rt_signal_frame_32, + uc.uc_mcontext.mc_pad)) + return 1; + if (vdso32_rt_sigtramp && current->mm->context.vdso_base && + nip == current->mm->context.vdso_base + vdso32_rt_sigtramp) + return 1; + return 0; +} + +static int sane_signal_32_frame(unsigned int sp) +{ + struct signal_frame_32 __user *sf; + unsigned int regs; + + sf = (struct signal_frame_32 __user *) (unsigned long) sp; + if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, ®s)) + return 0; + return regs == (unsigned long) &sf->mctx; +} + +static int sane_rt_signal_32_frame(unsigned int sp) +{ + struct rt_signal_frame_32 __user *sf; + unsigned int regs; + + sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp; + if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, ®s)) + return 0; + return regs == (unsigned long) &sf->uc.uc_mcontext; +} + +static unsigned int __user *signal_frame_32_regs(unsigned int sp, + unsigned int next_sp, unsigned int next_ip) +{ + struct mcontext32 __user *mctx = NULL; + struct signal_frame_32 __user *sf; + struct rt_signal_frame_32 __user *rt_sf; + + /* + * Note: the next_sp - sp >= signal frame size check + * is true when next_sp < sp, for example, when + * transitioning from an alternate signal stack to the + * normal stack. + */ + if (next_sp - sp >= sizeof(struct signal_frame_32) && + is_sigreturn_32_address(next_ip, sp) && + sane_signal_32_frame(sp)) { + sf = (struct signal_frame_32 __user *) (unsigned long) sp; + mctx = &sf->mctx; + } + + if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) && + is_rt_sigreturn_32_address(next_ip, sp) && + sane_rt_signal_32_frame(sp)) { + rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp; + mctx = &rt_sf->uc.uc_mcontext; + } + + if (!mctx) + return NULL; + return mctx->mc_gregs; +} + +static void perf_callchain_user_32(struct pt_regs *regs, + struct perf_callchain_entry *entry) +{ + unsigned int sp, next_sp; + unsigned int next_ip; + unsigned int lr; + long level = 0; + unsigned int __user *fp, *uregs; + + next_ip = regs->nip; + lr = regs->link; + sp = regs->gpr[1]; + callchain_store(entry, PERF_CONTEXT_USER); + callchain_store(entry, next_ip); + + while (entry->nr < PERF_MAX_STACK_DEPTH) { + fp = (unsigned int __user *) (unsigned long) sp; + if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp)) + return; + if (level > 0 && read_user_stack_32(&fp[1], &next_ip)) + return; + + uregs = signal_frame_32_regs(sp, next_sp, next_ip); + if (!uregs && level <= 1) + uregs = signal_frame_32_regs(sp, next_sp, lr); + if (uregs) { + /* + * This looks like an signal frame, so restart + * the stack trace with the values in it. + */ + if (read_user_stack_32(&uregs[PT_NIP], &next_ip) || + read_user_stack_32(&uregs[PT_LNK], &lr) || + read_user_stack_32(&uregs[PT_R1], &sp)) + return; + level = 0; + callchain_store(entry, PERF_CONTEXT_USER); + callchain_store(entry, next_ip); + continue; + } + + if (level == 0) + next_ip = lr; + callchain_store(entry, next_ip); + ++level; + sp = next_sp; + } +} + +/* + * Since we can't get PMU interrupts inside a PMU interrupt handler, + * we don't need separate irq and nmi entries here. + */ +static DEFINE_PER_CPU(struct perf_callchain_entry, callchain); + +struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) +{ + struct perf_callchain_entry *entry = &__get_cpu_var(callchain); + + entry->nr = 0; + + if (current->pid == 0) /* idle task? */ + return entry; + + if (!user_mode(regs)) { + perf_callchain_kernel(regs, entry); + if (current->mm) + regs = task_pt_regs(current); + else + regs = NULL; + } + + if (regs) { + if (current_is_64bit()) + perf_callchain_user_64(regs, entry); + else + perf_callchain_user_32(regs, entry); + } + + return entry; +} -- cgit v0.10.2 From 1f18345bdfd489fde1085bc85839d5d3645cf511 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 18 Aug 2009 10:59:47 +0200 Subject: perf tools: Remove obsolete defines The _XOPEN_SOURCE* defines are not really needed on Linux and it's not like we'll port this to AIX ;-) The define also broke the build with gcc 4.4.1: CC util/trace-event-parse.o In file included from util/trace-event-parse.c:32: util/util.h:43:1: error: "_XOPEN_SOURCE" redefined So remove them. Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index d61a6f0..15004d2 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -39,10 +39,6 @@ /* Approximation of the length of the decimal representation of this type. */ #define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) -#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX) -#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */ -#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */ -#endif #define _ALL_SOURCE 1 #define _GNU_SOURCE 1 #define _BSD_SOURCE 1 -- cgit v0.10.2 From 1314562a9ae5f39f6f595656023c1baf970831ef Mon Sep 17 00:00:00 2001 From: Hiroshi Shimamoto Date: Tue, 18 Aug 2009 15:06:02 +0900 Subject: sched, task_struct: stack_canary is not needed without CC_STACKPROTECTOR The field stack_canary is only used with CC_STACKPROTECTOR. This patch reduces task_struct size without CC_STACKPROTECTOR. Signed-off-by: Hiroshi Shimamoto LKML-Reference: <4A8A44CA.2020701@ct.jp.nec.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 195d72d..7bc2d92 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1237,8 +1237,10 @@ struct task_struct { pid_t pid; pid_t tgid; +#ifdef CONFIG_CC_STACKPROTECTOR /* Canary value for the -fstack-protector gcc feature */ unsigned long stack_canary; +#endif /* * pointers to (original) parent process, youngest child, younger sibling, -- cgit v0.10.2 From 4273b005875c34beda4a11c9d4a9132d80378036 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Tue, 18 Aug 2009 16:03:46 +0200 Subject: perf tools: Fix comm column adjusting The librarization of the thread helpers between annotate and report lost some perf report specifics. This patch fixes the thread comm column adjusting that has been omitted during this export. Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1250604226-6852-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1e3ad22..3fc0d47 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -665,6 +665,27 @@ static void dso__calc_col_width(struct dso *self) self->slen_calculated = 1; } +static int thread__set_comm_adjust(struct thread *self, const char *comm) +{ + int ret = thread__set_comm(self, comm); + + if (ret) + return ret; + + if (!col_width_list_str && !field_sep && + (!comm_list || strlist__has_entry(comm_list, comm))) { + unsigned int slen = strlen(comm); + + if (slen > comms__col_width) { + comms__col_width = slen; + threads__col_width = slen + 6; + } + } + + return 0; +} + + static struct symbol * resolve_symbol(struct thread *thread, struct map **mapp, struct dso **dsop, u64 *ipp) @@ -1056,7 +1077,7 @@ static void register_idle_thread(void) struct thread *thread = threads__findnew(0, &threads, &last_match); if (thread == NULL || - thread__set_comm(thread, "[idle]")) { + thread__set_comm_adjust(thread, "[idle]")) { fprintf(stderr, "problem inserting idle task.\n"); exit(-1); } @@ -1226,7 +1247,7 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) event->comm.comm, event->comm.pid); if (thread == NULL || - thread__set_comm(thread, event->comm.comm)) { + thread__set_comm_adjust(thread, event->comm.comm)) { dump_printf("problem processing PERF_EVENT_COMM, skipping event.\n"); return -1; } -- cgit v0.10.2 From 0914b93f4f36d1a0233bd64da9a35e37e72304ec Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 18 Aug 2009 21:56:19 +0900 Subject: ASoC: Fix data format configuration for S3C64XX IISv2 The data format configuration for S3C64xx IISv2 was hardcoded for IISMOD register. This patch changes to the defined values it. And instead of bits 9 and 10 of IISMOD we should clear bits 13 and 14. Signed-off-by: Joonyoung Shim Signed-off-by: Mark Brown diff --git a/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h b/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h index 0fad757..07659da 100644 --- a/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h +++ b/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h @@ -33,6 +33,11 @@ #define S3C2412_IISCON_RXDMA_ACTIVE (1 << 1) #define S3C2412_IISCON_IIS_ACTIVE (1 << 0) +#define S3C64XX_IISMOD_BLC_16BIT (0 << 13) +#define S3C64XX_IISMOD_BLC_8BIT (1 << 13) +#define S3C64XX_IISMOD_BLC_24BIT (2 << 13) +#define S3C64XX_IISMOD_BLC_MASK (3 << 13) + #define S3C64XX_IISMOD_IMS_PCLK (0 << 10) #define S3C64XX_IISMOD_IMS_SYSMUX (1 << 10) diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 1a28317..ebfb2f6 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -357,19 +357,19 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, #endif #ifdef CONFIG_PLAT_S3C64XX - iismod &= ~0x606; + iismod &= ~(S3C64XX_IISMOD_BLC_MASK | S3C2412_IISMOD_BCLK_MASK); /* Sample size */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: /* 8 bit sample, 16fs BCLK */ - iismod |= 0x2004; + iismod |= (S3C64XX_IISMOD_BLC_8BIT | S3C2412_IISMOD_BCLK_16FS); break; case SNDRV_PCM_FORMAT_S16_LE: /* 16 bit sample, 32fs BCLK */ break; case SNDRV_PCM_FORMAT_S24_LE: /* 24 bit sample, 48fs BCLK */ - iismod |= 0x4002; + iismod |= (S3C64XX_IISMOD_BLC_24BIT | S3C2412_IISMOD_BCLK_48FS); break; } #endif -- cgit v0.10.2 From b2472b1d4cda3968383a9439bf09fe04114faed3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Aug 2009 16:02:59 +0100 Subject: ASoC: Reenable S3C64xx I2S support Joonyoung Shim reports that S3C64xx I2S is working on the NCP boards so allow it to be selected in Kconfig. Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 808de5c..2987239 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -1,6 +1,6 @@ config SND_S3C24XX_SOC tristate "SoC Audio for the Samsung S3CXXXX chips" - depends on ARCH_S3C2410 + depends on ARCH_S3C2410 || ARCH_S3C64XX help Say Y or M if you want to add support for codecs attached to the S3C24XX AC97 or I2S interfaces. You will also need to -- cgit v0.10.2 From d1a5e44b89b35c88f8908f2b1774201704460f36 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Aug 2009 15:24:05 +0100 Subject: ASoC: Remove duplicate ADC/DAC widgets from wm_hubs.c These need to be in the CODEC since the DAIs supported by the CODECs aren't static. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index e8fc474..6be47e8 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -474,12 +474,6 @@ SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0, SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0, mixinr, ARRAY_SIZE(mixinr)), -SND_SOC_DAPM_ADC("ADCL", "Capture", WM8993_POWER_MANAGEMENT_2, 1, 0), -SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0), - -SND_SOC_DAPM_DAC("DACL", "Playback", WM8993_POWER_MANAGEMENT_3, 1, 0), -SND_SOC_DAPM_DAC("DACR", "Playback", WM8993_POWER_MANAGEMENT_3, 0, 0), - SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0, left_output_mixer, ARRAY_SIZE(left_output_mixer)), SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0, -- cgit v0.10.2 From 010ff262269c6ad84acba98eab2d7843919c7ccf Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Aug 2009 17:39:22 +0100 Subject: ASoC: Add input and output AIF widgets Currently DAPM interfaces with the audio streams to and from the processor at the DAC and ADC widgets. As the digital capabilities of parts increases this is becoming a less and less able to meet the needs of parts. To meet the needs of these devices create new widgets interfacing with the TDM bus but not integrated into any other functionality. Audio can then be routed to and from these widgets using existing routing widgets. A slot number is provided in the definition but this is currently not used yet. This is intended to support devices which can use more than one TDM slot on a single interface. Signed-off-by: Mark Brown diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 35814ce..3388405 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -137,6 +137,12 @@ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} /* stream domain */ +#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \ +{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ + .reg = wreg, .shift = wshift, .invert = winvert } +#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \ +{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ + .reg = wreg, .shift = wshift, .invert = winvert } #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \ .shift = wshift, .invert = winvert} @@ -312,6 +318,8 @@ enum snd_soc_dapm_type { snd_soc_dapm_pre, /* machine specific pre widget - exec first */ snd_soc_dapm_post, /* machine specific post widget - exec last */ snd_soc_dapm_supply, /* power/clock supply */ + snd_soc_dapm_aif_in, /* audio interface input */ + snd_soc_dapm_aif_out, /* audio interface output */ }; /* diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8846131..a225e5a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -55,17 +55,19 @@ static int dapm_up_seq[] = { [snd_soc_dapm_pre] = 0, [snd_soc_dapm_supply] = 1, [snd_soc_dapm_micbias] = 2, - [snd_soc_dapm_mic] = 3, - [snd_soc_dapm_mux] = 4, - [snd_soc_dapm_value_mux] = 4, - [snd_soc_dapm_dac] = 5, - [snd_soc_dapm_mixer] = 6, - [snd_soc_dapm_mixer_named_ctl] = 6, - [snd_soc_dapm_pga] = 7, - [snd_soc_dapm_adc] = 8, - [snd_soc_dapm_hp] = 9, - [snd_soc_dapm_spk] = 9, - [snd_soc_dapm_post] = 10, + [snd_soc_dapm_aif_in] = 3, + [snd_soc_dapm_aif_out] = 3, + [snd_soc_dapm_mic] = 4, + [snd_soc_dapm_mux] = 5, + [snd_soc_dapm_value_mux] = 5, + [snd_soc_dapm_dac] = 6, + [snd_soc_dapm_mixer] = 7, + [snd_soc_dapm_mixer_named_ctl] = 7, + [snd_soc_dapm_pga] = 8, + [snd_soc_dapm_adc] = 9, + [snd_soc_dapm_hp] = 10, + [snd_soc_dapm_spk] = 10, + [snd_soc_dapm_post] = 11, }; static int dapm_down_seq[] = { @@ -81,8 +83,10 @@ static int dapm_down_seq[] = { [snd_soc_dapm_micbias] = 8, [snd_soc_dapm_mux] = 9, [snd_soc_dapm_value_mux] = 9, - [snd_soc_dapm_supply] = 10, - [snd_soc_dapm_post] = 11, + [snd_soc_dapm_aif_in] = 10, + [snd_soc_dapm_aif_out] = 10, + [snd_soc_dapm_supply] = 11, + [snd_soc_dapm_post] = 12, }; static void pop_wait(u32 pop_time) @@ -224,6 +228,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, case snd_soc_dapm_micbias: case snd_soc_dapm_vmid: case snd_soc_dapm_supply: + case snd_soc_dapm_aif_in: + case snd_soc_dapm_aif_out: p->connect = 1; break; /* does effect routing - dynamically connected */ @@ -497,8 +503,14 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) if (widget->id == snd_soc_dapm_supply) return 0; - if (widget->id == snd_soc_dapm_adc && widget->active) - return 1; + switch (widget->id) { + case snd_soc_dapm_adc: + case snd_soc_dapm_aif_out: + if (widget->active) + return 1; + default: + break; + } if (widget->connected) { /* connected pin ? */ @@ -537,8 +549,14 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) return 0; /* active stream ? */ - if (widget->id == snd_soc_dapm_dac && widget->active) - return 1; + switch (widget->id) { + case snd_soc_dapm_dac: + case snd_soc_dapm_aif_in: + if (widget->active) + return 1; + default: + break; + } if (widget->connected) { /* connected pin ? */ @@ -1052,6 +1070,8 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: case snd_soc_dapm_supply: + case snd_soc_dapm_aif_in: + case snd_soc_dapm_aif_out: if (w->name) { in = is_connected_input_ep(w); dapm_clear_walk(w->codec); @@ -1342,6 +1362,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, case snd_soc_dapm_pre: case snd_soc_dapm_post: case snd_soc_dapm_supply: + case snd_soc_dapm_aif_in: + case snd_soc_dapm_aif_out: list_add(&path->list, &codec->dapm_paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); @@ -1444,9 +1466,11 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) dapm_new_mux(codec, w); break; case snd_soc_dapm_adc: + case snd_soc_dapm_aif_out: w->power_check = dapm_adc_check_power; break; case snd_soc_dapm_dac: + case snd_soc_dapm_aif_in: w->power_check = dapm_dac_check_power; break; case snd_soc_dapm_pga: -- cgit v0.10.2 From 59ae07a58012a96cfbc9b4c0f3a07ad07d2a2208 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Aug 2009 16:01:57 +0100 Subject: ASoC: WM8993 digital mixing support The WM8993 provides digital sidetone paths and also allows each channel on the audio interface to be routed separtately to the DACs and ADCs. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index cd15669..ff9b63b 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -846,18 +846,76 @@ SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 2, 1, 0), SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 0, 1, 0), }; +static const char *aif_text[] = { + "Left", "Right" +}; + +static const struct soc_enum aifoutl_enum = + SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 15, 2, aif_text); + +static const struct snd_kcontrol_new aifoutl_mux = + SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); + +static const struct soc_enum aifoutr_enum = + SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 14, 2, aif_text); + +static const struct snd_kcontrol_new aifoutr_mux = + SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); + +static const struct soc_enum aifinl_enum = + SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 15, 2, aif_text); + +static const struct snd_kcontrol_new aifinl_mux = + SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); + +static const struct soc_enum aifinr_enum = + SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 14, 2, aif_text); + +static const struct snd_kcontrol_new aifinr_mux = + SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); + +static const char *sidetone_text[] = { + "None", "Left", "Right" +}; + +static const struct soc_enum sidetonel_enum = + SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 2, 3, sidetone_text); + +static const struct snd_kcontrol_new sidetonel_mux = + SOC_DAPM_ENUM("Left Sidetone", sidetonel_enum); + +static const struct soc_enum sidetoner_enum = + SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 0, 3, sidetone_text); + +static const struct snd_kcontrol_new sidetoner_mux = + SOC_DAPM_ENUM("Right Sidetone", sidetoner_enum); + static const struct snd_soc_dapm_widget wm8993_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8993_BUS_CONTROL_1, 1, 0, clk_sys_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("TOCLK", WM8993_CLOCKING_1, 14, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8993_CLOCKING_3, 0, 0, NULL, 0), +SND_SOC_DAPM_ADC("ADCL", NULL, WM8993_POWER_MANAGEMENT_2, 1, 0), +SND_SOC_DAPM_ADC("ADCR", NULL, WM8993_POWER_MANAGEMENT_2, 0, 0), + +SND_SOC_DAPM_MUX("AIFOUTL Mux", SND_SOC_NOPM, 0, 0, &aifoutl_mux), +SND_SOC_DAPM_MUX("AIFOUTR Mux", SND_SOC_NOPM, 0, 0, &aifoutr_mux), + +SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_ADC("ADCL", "Capture", WM8993_POWER_MANAGEMENT_2, 1, 0), -SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0), +SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_DAC("DACL", "Playback", WM8993_POWER_MANAGEMENT_3, 1, 0), -SND_SOC_DAPM_DAC("DACR", "Playback", WM8993_POWER_MANAGEMENT_3, 0, 0), +SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &aifinl_mux), +SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &aifinr_mux), + +SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &sidetonel_mux), +SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &sidetoner_mux), + +SND_SOC_DAPM_DAC("DACL", NULL, WM8993_POWER_MANAGEMENT_3, 1, 0), +SND_SOC_DAPM_DAC("DACR", NULL, WM8993_POWER_MANAGEMENT_3, 0, 0), SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), @@ -875,10 +933,32 @@ static const struct snd_soc_dapm_route routes[] = { { "ADCR", NULL, "CLK_SYS" }, { "ADCR", NULL, "CLK_DSP" }, + { "AIFOUTL Mux", "Left", "ADCL" }, + { "AIFOUTL Mux", "Right", "ADCR" }, + { "AIFOUTR Mux", "Left", "ADCL" }, + { "AIFOUTR Mux", "Right", "ADCR" }, + + { "AIFOUTL", NULL, "AIFOUTL Mux" }, + { "AIFOUTR", NULL, "AIFOUTR Mux" }, + + { "DACL Mux", "Left", "AIFINL" }, + { "DACL Mux", "Right", "AIFINR" }, + { "DACR Mux", "Left", "AIFINL" }, + { "DACR Mux", "Right", "AIFINR" }, + + { "DACL Sidetone", "Left", "ADCL" }, + { "DACL Sidetone", "Right", "ADCR" }, + { "DACR Sidetone", "Left", "ADCL" }, + { "DACR Sidetone", "Right", "ADCR" }, + { "DACL", NULL, "CLK_SYS" }, { "DACL", NULL, "CLK_DSP" }, + { "DACL", NULL, "DACL Mux" }, + { "DACL", NULL, "DACL Sidetone" }, { "DACR", NULL, "CLK_SYS" }, { "DACR", NULL, "CLK_DSP" }, + { "DACR", NULL, "DACR Mux" }, + { "DACR", NULL, "DACR Sidetone" }, { "Left Output Mixer", "DAC Switch", "DACL" }, -- cgit v0.10.2 From 6e086437f35ad9fda448711732c4ce0f82aad569 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Tue, 18 Aug 2009 17:04:03 +0200 Subject: perf tools: Save partial non-overlapping map The librarization of the thread helpers between annotate and report lost some perf report specifics. thread__insert_map() had its most uptodate version in perf report which cared about partial map overlapping. In case of overlap between two maps, perf annotate's version removes the whole old map without considering if it partially or absolutely overlaps the new map. We exported the odd version, change it by using the perf report version. Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith LKML-Reference: <1250607843-7395-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 00c14b9..f98032c 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -4,6 +4,7 @@ #include #include "thread.h" #include "util.h" +#include "debug.h" static struct thread *thread__new(pid_t pid) { @@ -85,9 +86,27 @@ void thread__insert_map(struct thread *self, struct map *map) list_for_each_entry_safe(pos, tmp, &self->maps, node) { if (map__overlap(pos, map)) { - list_del_init(&pos->node); - /* XXX leaks dsos */ - free(pos); + if (verbose >= 2) { + printf("overlapping maps:\n"); + map__fprintf(map, stdout); + map__fprintf(pos, stdout); + } + + if (map->start <= pos->start && map->end > pos->start) + pos->start = map->end; + + if (map->end >= pos->end && map->start < pos->end) + pos->end = map->start; + + if (verbose >= 2) { + printf("after collision:\n"); + map__fprintf(pos, stdout); + } + + if (pos->start >= pos->end) { + list_del_init(&pos->node); + free(pos); + } } } -- cgit v0.10.2 From 49a02c514d967921a908ac64e9c0ec0f0fc17fd8 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 12:51:52 +0200 Subject: sched: Use structure to store local data in __build_sched_domains Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818105152.GB29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 1b59e26..565ff77 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8091,6 +8091,22 @@ struct static_sched_domain { DECLARE_BITMAP(span, CONFIG_NR_CPUS); }; +struct s_data { +#ifdef CONFIG_NUMA + int sd_allnodes; + cpumask_var_t domainspan; + cpumask_var_t covered; + cpumask_var_t notcovered; +#endif + cpumask_var_t nodemask; + cpumask_var_t this_sibling_map; + cpumask_var_t this_core_map; + cpumask_var_t send_covered; + cpumask_var_t tmpmask; + struct sched_group **sched_group_nodes; + struct root_domain *rd; +}; + /* * SMT sched-domains: */ @@ -8385,54 +8401,49 @@ static void set_domain_attribute(struct sched_domain *sd, static int __build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *attr) { + struct s_data d; int i, err = -ENOMEM; - struct root_domain *rd; - cpumask_var_t nodemask, this_sibling_map, this_core_map, send_covered, - tmpmask; #ifdef CONFIG_NUMA - cpumask_var_t domainspan, covered, notcovered; - struct sched_group **sched_group_nodes = NULL; - int sd_allnodes = 0; - - if (!alloc_cpumask_var(&domainspan, GFP_KERNEL)) + d.sd_allnodes = 0; + if (!alloc_cpumask_var(&d.domainspan, GFP_KERNEL)) goto out; - if (!alloc_cpumask_var(&covered, GFP_KERNEL)) + if (!alloc_cpumask_var(&d.covered, GFP_KERNEL)) goto free_domainspan; - if (!alloc_cpumask_var(¬covered, GFP_KERNEL)) + if (!alloc_cpumask_var(&d.notcovered, GFP_KERNEL)) goto free_covered; #endif - if (!alloc_cpumask_var(&nodemask, GFP_KERNEL)) + if (!alloc_cpumask_var(&d.nodemask, GFP_KERNEL)) goto free_notcovered; - if (!alloc_cpumask_var(&this_sibling_map, GFP_KERNEL)) + if (!alloc_cpumask_var(&d.this_sibling_map, GFP_KERNEL)) goto free_nodemask; - if (!alloc_cpumask_var(&this_core_map, GFP_KERNEL)) + if (!alloc_cpumask_var(&d.this_core_map, GFP_KERNEL)) goto free_this_sibling_map; - if (!alloc_cpumask_var(&send_covered, GFP_KERNEL)) + if (!alloc_cpumask_var(&d.send_covered, GFP_KERNEL)) goto free_this_core_map; - if (!alloc_cpumask_var(&tmpmask, GFP_KERNEL)) + if (!alloc_cpumask_var(&d.tmpmask, GFP_KERNEL)) goto free_send_covered; #ifdef CONFIG_NUMA /* * Allocate the per-node list of sched groups */ - sched_group_nodes = kcalloc(nr_node_ids, sizeof(struct sched_group *), - GFP_KERNEL); - if (!sched_group_nodes) { + d.sched_group_nodes = kcalloc(nr_node_ids, sizeof(struct sched_group *), + GFP_KERNEL); + if (!d.sched_group_nodes) { printk(KERN_WARNING "Can not alloc sched group node list\n"); goto free_tmpmask; } #endif - rd = alloc_rootdomain(); - if (!rd) { + d.rd = alloc_rootdomain(); + if (!d.rd) { printk(KERN_WARNING "Cannot alloc root domain\n"); goto free_sched_groups; } #ifdef CONFIG_NUMA - sched_group_nodes_bycpu[cpumask_first(cpu_map)] = sched_group_nodes; + sched_group_nodes_bycpu[cpumask_first(cpu_map)] = d.sched_group_nodes; #endif /* @@ -8441,18 +8452,20 @@ static int __build_sched_domains(const struct cpumask *cpu_map, for_each_cpu(i, cpu_map) { struct sched_domain *sd = NULL, *p; - cpumask_and(nodemask, cpumask_of_node(cpu_to_node(i)), cpu_map); + cpumask_and(d.nodemask, cpumask_of_node(cpu_to_node(i)), + cpu_map); #ifdef CONFIG_NUMA if (cpumask_weight(cpu_map) > - SD_NODES_PER_DOMAIN*cpumask_weight(nodemask)) { + SD_NODES_PER_DOMAIN*cpumask_weight(d.nodemask)) { sd = &per_cpu(allnodes_domains, i).sd; SD_INIT(sd, ALLNODES); set_domain_attribute(sd, attr); cpumask_copy(sched_domain_span(sd), cpu_map); - cpu_to_allnodes_group(i, cpu_map, &sd->groups, tmpmask); + cpu_to_allnodes_group(i, cpu_map, &sd->groups, + d.tmpmask); p = sd; - sd_allnodes = 1; + d.sd_allnodes = 1; } else p = NULL; @@ -8471,11 +8484,11 @@ static int __build_sched_domains(const struct cpumask *cpu_map, sd = &per_cpu(phys_domains, i).sd; SD_INIT(sd, CPU); set_domain_attribute(sd, attr); - cpumask_copy(sched_domain_span(sd), nodemask); + cpumask_copy(sched_domain_span(sd), d.nodemask); sd->parent = p; if (p) p->child = sd; - cpu_to_phys_group(i, cpu_map, &sd->groups, tmpmask); + cpu_to_phys_group(i, cpu_map, &sd->groups, d.tmpmask); #ifdef CONFIG_SCHED_MC p = sd; @@ -8486,7 +8499,7 @@ static int __build_sched_domains(const struct cpumask *cpu_map, cpu_coregroup_mask(i)); sd->parent = p; p->child = sd; - cpu_to_core_group(i, cpu_map, &sd->groups, tmpmask); + cpu_to_core_group(i, cpu_map, &sd->groups, d.tmpmask); #endif #ifdef CONFIG_SCHED_SMT @@ -8498,54 +8511,54 @@ static int __build_sched_domains(const struct cpumask *cpu_map, topology_thread_cpumask(i), cpu_map); sd->parent = p; p->child = sd; - cpu_to_cpu_group(i, cpu_map, &sd->groups, tmpmask); + cpu_to_cpu_group(i, cpu_map, &sd->groups, d.tmpmask); #endif } #ifdef CONFIG_SCHED_SMT /* Set up CPU (sibling) groups */ for_each_cpu(i, cpu_map) { - cpumask_and(this_sibling_map, + cpumask_and(d.this_sibling_map, topology_thread_cpumask(i), cpu_map); - if (i != cpumask_first(this_sibling_map)) + if (i != cpumask_first(d.this_sibling_map)) continue; - init_sched_build_groups(this_sibling_map, cpu_map, + init_sched_build_groups(d.this_sibling_map, cpu_map, &cpu_to_cpu_group, - send_covered, tmpmask); + d.send_covered, d.tmpmask); } #endif #ifdef CONFIG_SCHED_MC /* Set up multi-core groups */ for_each_cpu(i, cpu_map) { - cpumask_and(this_core_map, cpu_coregroup_mask(i), cpu_map); - if (i != cpumask_first(this_core_map)) + cpumask_and(d.this_core_map, cpu_coregroup_mask(i), cpu_map); + if (i != cpumask_first(d.this_core_map)) continue; - init_sched_build_groups(this_core_map, cpu_map, + init_sched_build_groups(d.this_core_map, cpu_map, &cpu_to_core_group, - send_covered, tmpmask); + d.send_covered, d.tmpmask); } #endif /* Set up physical groups */ for (i = 0; i < nr_node_ids; i++) { - cpumask_and(nodemask, cpumask_of_node(i), cpu_map); - if (cpumask_empty(nodemask)) + cpumask_and(d.nodemask, cpumask_of_node(i), cpu_map); + if (cpumask_empty(d.nodemask)) continue; - init_sched_build_groups(nodemask, cpu_map, + init_sched_build_groups(d.nodemask, cpu_map, &cpu_to_phys_group, - send_covered, tmpmask); + d.send_covered, d.tmpmask); } #ifdef CONFIG_NUMA /* Set up node groups */ - if (sd_allnodes) { + if (d.sd_allnodes) { init_sched_build_groups(cpu_map, cpu_map, &cpu_to_allnodes_group, - send_covered, tmpmask); + d.send_covered, d.tmpmask); } for (i = 0; i < nr_node_ids; i++) { @@ -8553,15 +8566,15 @@ static int __build_sched_domains(const struct cpumask *cpu_map, struct sched_group *sg, *prev; int j; - cpumask_clear(covered); - cpumask_and(nodemask, cpumask_of_node(i), cpu_map); - if (cpumask_empty(nodemask)) { - sched_group_nodes[i] = NULL; + cpumask_clear(d.covered); + cpumask_and(d.nodemask, cpumask_of_node(i), cpu_map); + if (cpumask_empty(d.nodemask)) { + d.sched_group_nodes[i] = NULL; continue; } - sched_domain_node_span(i, domainspan); - cpumask_and(domainspan, domainspan, cpu_map); + sched_domain_node_span(i, d.domainspan); + cpumask_and(d.domainspan, d.domainspan, cpu_map); sg = kmalloc_node(sizeof(struct sched_group) + cpumask_size(), GFP_KERNEL, i); @@ -8570,30 +8583,30 @@ static int __build_sched_domains(const struct cpumask *cpu_map, "node %d\n", i); goto error; } - sched_group_nodes[i] = sg; - for_each_cpu(j, nodemask) { + d.sched_group_nodes[i] = sg; + for_each_cpu(j, d.nodemask) { struct sched_domain *sd; sd = &per_cpu(node_domains, j).sd; sd->groups = sg; } sg->__cpu_power = 0; - cpumask_copy(sched_group_cpus(sg), nodemask); + cpumask_copy(sched_group_cpus(sg), d.nodemask); sg->next = sg; - cpumask_or(covered, covered, nodemask); + cpumask_or(d.covered, d.covered, d.nodemask); prev = sg; for (j = 0; j < nr_node_ids; j++) { int n = (i + j) % nr_node_ids; - cpumask_complement(notcovered, covered); - cpumask_and(tmpmask, notcovered, cpu_map); - cpumask_and(tmpmask, tmpmask, domainspan); - if (cpumask_empty(tmpmask)) + cpumask_complement(d.notcovered, d.covered); + cpumask_and(d.tmpmask, d.notcovered, cpu_map); + cpumask_and(d.tmpmask, d.tmpmask, d.domainspan); + if (cpumask_empty(d.tmpmask)) break; - cpumask_and(tmpmask, tmpmask, cpumask_of_node(n)); - if (cpumask_empty(tmpmask)) + cpumask_and(d.tmpmask, d.tmpmask, cpumask_of_node(n)); + if (cpumask_empty(d.tmpmask)) continue; sg = kmalloc_node(sizeof(struct sched_group) + @@ -8605,9 +8618,9 @@ static int __build_sched_domains(const struct cpumask *cpu_map, goto error; } sg->__cpu_power = 0; - cpumask_copy(sched_group_cpus(sg), tmpmask); + cpumask_copy(sched_group_cpus(sg), d.tmpmask); sg->next = prev->next; - cpumask_or(covered, covered, tmpmask); + cpumask_or(d.covered, d.covered, d.tmpmask); prev->next = sg; prev = sg; } @@ -8638,13 +8651,13 @@ static int __build_sched_domains(const struct cpumask *cpu_map, #ifdef CONFIG_NUMA for (i = 0; i < nr_node_ids; i++) - init_numa_sched_groups_power(sched_group_nodes[i]); + init_numa_sched_groups_power(d.sched_group_nodes[i]); - if (sd_allnodes) { + if (d.sd_allnodes) { struct sched_group *sg; cpu_to_allnodes_group(cpumask_first(cpu_map), cpu_map, &sg, - tmpmask); + d.tmpmask); init_numa_sched_groups_power(sg); } #endif @@ -8659,42 +8672,42 @@ static int __build_sched_domains(const struct cpumask *cpu_map, #else sd = &per_cpu(phys_domains, i).sd; #endif - cpu_attach_domain(sd, rd, i); + cpu_attach_domain(sd, d.rd, i); } err = 0; free_tmpmask: - free_cpumask_var(tmpmask); + free_cpumask_var(d.tmpmask); free_send_covered: - free_cpumask_var(send_covered); + free_cpumask_var(d.send_covered); free_this_core_map: - free_cpumask_var(this_core_map); + free_cpumask_var(d.this_core_map); free_this_sibling_map: - free_cpumask_var(this_sibling_map); + free_cpumask_var(d.this_sibling_map); free_nodemask: - free_cpumask_var(nodemask); + free_cpumask_var(d.nodemask); free_notcovered: #ifdef CONFIG_NUMA - free_cpumask_var(notcovered); + free_cpumask_var(d.notcovered); free_covered: - free_cpumask_var(covered); + free_cpumask_var(d.covered); free_domainspan: - free_cpumask_var(domainspan); + free_cpumask_var(d.domainspan); out: #endif return err; free_sched_groups: #ifdef CONFIG_NUMA - kfree(sched_group_nodes); + kfree(d.sched_group_nodes); #endif goto free_tmpmask; #ifdef CONFIG_NUMA error: - free_sched_groups(cpu_map, tmpmask); - free_rootdomain(rd); + free_sched_groups(cpu_map, d.tmpmask); + free_rootdomain(d.rd); goto free_tmpmask; #endif } -- cgit v0.10.2 From 2109b99ee192764b407dc7f52babb74740eea6f9 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 12:53:00 +0200 Subject: sched: Separate out allocation/free/goto-hell from __build_sched_domains Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818105300.GC29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 565ff77..c5d1fee 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8107,6 +8107,23 @@ struct s_data { struct root_domain *rd; }; +enum s_alloc { + sa_sched_groups = 0, + sa_rootdomain, + sa_tmpmask, + sa_send_covered, + sa_this_core_map, + sa_this_sibling_map, + sa_nodemask, + sa_sched_group_nodes, +#ifdef CONFIG_NUMA + sa_notcovered, + sa_covered, + sa_domainspan, +#endif + sa_none, +}; + /* * SMT sched-domains: */ @@ -8394,6 +8411,77 @@ static void set_domain_attribute(struct sched_domain *sd, } } +static void __free_domain_allocs(struct s_data *d, enum s_alloc what, + const struct cpumask *cpu_map) +{ + switch (what) { + case sa_sched_groups: + free_sched_groups(cpu_map, d->tmpmask); /* fall through */ + d->sched_group_nodes = NULL; + case sa_rootdomain: + free_rootdomain(d->rd); /* fall through */ + case sa_tmpmask: + free_cpumask_var(d->tmpmask); /* fall through */ + case sa_send_covered: + free_cpumask_var(d->send_covered); /* fall through */ + case sa_this_core_map: + free_cpumask_var(d->this_core_map); /* fall through */ + case sa_this_sibling_map: + free_cpumask_var(d->this_sibling_map); /* fall through */ + case sa_nodemask: + free_cpumask_var(d->nodemask); /* fall through */ + case sa_sched_group_nodes: +#ifdef CONFIG_NUMA + kfree(d->sched_group_nodes); /* fall through */ + case sa_notcovered: + free_cpumask_var(d->notcovered); /* fall through */ + case sa_covered: + free_cpumask_var(d->covered); /* fall through */ + case sa_domainspan: + free_cpumask_var(d->domainspan); /* fall through */ +#endif + case sa_none: + break; + } +} + +static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, + const struct cpumask *cpu_map) +{ +#ifdef CONFIG_NUMA + if (!alloc_cpumask_var(&d->domainspan, GFP_KERNEL)) + return sa_none; + if (!alloc_cpumask_var(&d->covered, GFP_KERNEL)) + return sa_domainspan; + if (!alloc_cpumask_var(&d->notcovered, GFP_KERNEL)) + return sa_covered; + /* Allocate the per-node list of sched groups */ + d->sched_group_nodes = kcalloc(nr_node_ids, + sizeof(struct sched_group *), GFP_KERNEL); + if (!d->sched_group_nodes) { + printk(KERN_WARNING "Can not alloc sched group node list\n"); + return sa_notcovered; + } + sched_group_nodes_bycpu[cpumask_first(cpu_map)] = d->sched_group_nodes; +#endif + if (!alloc_cpumask_var(&d->nodemask, GFP_KERNEL)) + return sa_sched_group_nodes; + if (!alloc_cpumask_var(&d->this_sibling_map, GFP_KERNEL)) + return sa_nodemask; + if (!alloc_cpumask_var(&d->this_core_map, GFP_KERNEL)) + return sa_this_sibling_map; + if (!alloc_cpumask_var(&d->send_covered, GFP_KERNEL)) + return sa_this_core_map; + if (!alloc_cpumask_var(&d->tmpmask, GFP_KERNEL)) + return sa_send_covered; + d->rd = alloc_rootdomain(); + if (!d->rd) { + printk(KERN_WARNING "Cannot alloc root domain\n"); + return sa_tmpmask; + } + return sa_rootdomain; +} + /* * Build sched domains for a given set of cpus and attach the sched domains * to the individual cpus @@ -8401,50 +8489,17 @@ static void set_domain_attribute(struct sched_domain *sd, static int __build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *attr) { + enum s_alloc alloc_state = sa_none; struct s_data d; - int i, err = -ENOMEM; + int i; #ifdef CONFIG_NUMA d.sd_allnodes = 0; - if (!alloc_cpumask_var(&d.domainspan, GFP_KERNEL)) - goto out; - if (!alloc_cpumask_var(&d.covered, GFP_KERNEL)) - goto free_domainspan; - if (!alloc_cpumask_var(&d.notcovered, GFP_KERNEL)) - goto free_covered; -#endif - - if (!alloc_cpumask_var(&d.nodemask, GFP_KERNEL)) - goto free_notcovered; - if (!alloc_cpumask_var(&d.this_sibling_map, GFP_KERNEL)) - goto free_nodemask; - if (!alloc_cpumask_var(&d.this_core_map, GFP_KERNEL)) - goto free_this_sibling_map; - if (!alloc_cpumask_var(&d.send_covered, GFP_KERNEL)) - goto free_this_core_map; - if (!alloc_cpumask_var(&d.tmpmask, GFP_KERNEL)) - goto free_send_covered; - -#ifdef CONFIG_NUMA - /* - * Allocate the per-node list of sched groups - */ - d.sched_group_nodes = kcalloc(nr_node_ids, sizeof(struct sched_group *), - GFP_KERNEL); - if (!d.sched_group_nodes) { - printk(KERN_WARNING "Can not alloc sched group node list\n"); - goto free_tmpmask; - } #endif - d.rd = alloc_rootdomain(); - if (!d.rd) { - printk(KERN_WARNING "Cannot alloc root domain\n"); - goto free_sched_groups; - } - -#ifdef CONFIG_NUMA - sched_group_nodes_bycpu[cpumask_first(cpu_map)] = d.sched_group_nodes; -#endif + alloc_state = __visit_domain_allocation_hell(&d, cpu_map); + if (alloc_state != sa_rootdomain) + goto error; + alloc_state = sa_sched_groups; /* * Set up domains for cpus specified by the cpu_map. @@ -8675,41 +8730,13 @@ static int __build_sched_domains(const struct cpumask *cpu_map, cpu_attach_domain(sd, d.rd, i); } - err = 0; - -free_tmpmask: - free_cpumask_var(d.tmpmask); -free_send_covered: - free_cpumask_var(d.send_covered); -free_this_core_map: - free_cpumask_var(d.this_core_map); -free_this_sibling_map: - free_cpumask_var(d.this_sibling_map); -free_nodemask: - free_cpumask_var(d.nodemask); -free_notcovered: -#ifdef CONFIG_NUMA - free_cpumask_var(d.notcovered); -free_covered: - free_cpumask_var(d.covered); -free_domainspan: - free_cpumask_var(d.domainspan); -out: -#endif - return err; - -free_sched_groups: -#ifdef CONFIG_NUMA - kfree(d.sched_group_nodes); -#endif - goto free_tmpmask; + d.sched_group_nodes = NULL; /* don't free this we still need it */ + __free_domain_allocs(&d, sa_tmpmask, cpu_map); + return 0; -#ifdef CONFIG_NUMA error: - free_sched_groups(cpu_map, d.tmpmask); - free_rootdomain(d.rd); - goto free_tmpmask; -#endif + __free_domain_allocs(&d, alloc_state, cpu_map); + return -ENOMEM; } static int build_sched_domains(const struct cpumask *cpu_map) -- cgit v0.10.2 From 7f4588f3aa395632fec9ba2e15a1920f0682fda0 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 12:54:06 +0200 Subject: sched: Separate out build of NUMA sched domain from __build_sched_domains ... to further strip down __build_sched_domains(). Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818105406.GD29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index c5d1fee..dd95a47 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8482,6 +8482,37 @@ static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, return sa_rootdomain; } +static struct sched_domain *__build_numa_sched_domains(struct s_data *d, + const struct cpumask *cpu_map, struct sched_domain_attr *attr, int i) +{ + struct sched_domain *sd = NULL; +#ifdef CONFIG_NUMA + struct sched_domain *parent; + + d->sd_allnodes = 0; + if (cpumask_weight(cpu_map) > + SD_NODES_PER_DOMAIN * cpumask_weight(d->nodemask)) { + sd = &per_cpu(allnodes_domains, i).sd; + SD_INIT(sd, ALLNODES); + set_domain_attribute(sd, attr); + cpumask_copy(sched_domain_span(sd), cpu_map); + cpu_to_allnodes_group(i, cpu_map, &sd->groups, d->tmpmask); + d->sd_allnodes = 1; + } + parent = sd; + + sd = &per_cpu(node_domains, i).sd; + SD_INIT(sd, NODE); + set_domain_attribute(sd, attr); + sched_domain_node_span(cpu_to_node(i), sched_domain_span(sd)); + sd->parent = parent; + if (parent) + parent->child = sd; + cpumask_and(sched_domain_span(sd), sched_domain_span(sd), cpu_map); +#endif + return sd; +} + /* * Build sched domains for a given set of cpus and attach the sched domains * to the individual cpus @@ -8510,31 +8541,7 @@ static int __build_sched_domains(const struct cpumask *cpu_map, cpumask_and(d.nodemask, cpumask_of_node(cpu_to_node(i)), cpu_map); -#ifdef CONFIG_NUMA - if (cpumask_weight(cpu_map) > - SD_NODES_PER_DOMAIN*cpumask_weight(d.nodemask)) { - sd = &per_cpu(allnodes_domains, i).sd; - SD_INIT(sd, ALLNODES); - set_domain_attribute(sd, attr); - cpumask_copy(sched_domain_span(sd), cpu_map); - cpu_to_allnodes_group(i, cpu_map, &sd->groups, - d.tmpmask); - p = sd; - d.sd_allnodes = 1; - } else - p = NULL; - - sd = &per_cpu(node_domains, i).sd; - SD_INIT(sd, NODE); - set_domain_attribute(sd, attr); - sched_domain_node_span(cpu_to_node(i), sched_domain_span(sd)); - sd->parent = p; - if (p) - p->child = sd; - cpumask_and(sched_domain_span(sd), - sched_domain_span(sd), cpu_map); -#endif - + sd = __build_numa_sched_domains(&d, cpu_map, attr, i); p = sd; sd = &per_cpu(phys_domains, i).sd; SD_INIT(sd, CPU); -- cgit v0.10.2 From 87cce6622c2ab2f0e96ecc2a37133378a7db3177 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 12:54:55 +0200 Subject: sched: Separate out build of CPU sched domain from __build_sched_domains ... to further strip down __build_sched_domains(). Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818105455.GE29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index dd95a47..3d0666c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8513,6 +8513,22 @@ static struct sched_domain *__build_numa_sched_domains(struct s_data *d, return sd; } +static struct sched_domain *__build_cpu_sched_domain(struct s_data *d, + const struct cpumask *cpu_map, struct sched_domain_attr *attr, + struct sched_domain *parent, int i) +{ + struct sched_domain *sd; + sd = &per_cpu(phys_domains, i).sd; + SD_INIT(sd, CPU); + set_domain_attribute(sd, attr); + cpumask_copy(sched_domain_span(sd), d->nodemask); + sd->parent = parent; + if (parent) + parent->child = sd; + cpu_to_phys_group(i, cpu_map, &sd->groups, d->tmpmask); + return sd; +} + /* * Build sched domains for a given set of cpus and attach the sched domains * to the individual cpus @@ -8542,15 +8558,7 @@ static int __build_sched_domains(const struct cpumask *cpu_map, cpu_map); sd = __build_numa_sched_domains(&d, cpu_map, attr, i); - p = sd; - sd = &per_cpu(phys_domains, i).sd; - SD_INIT(sd, CPU); - set_domain_attribute(sd, attr); - cpumask_copy(sched_domain_span(sd), d.nodemask); - sd->parent = p; - if (p) - p->child = sd; - cpu_to_phys_group(i, cpu_map, &sd->groups, d.tmpmask); + sd = __build_cpu_sched_domain(&d, cpu_map, attr, sd, i); #ifdef CONFIG_SCHED_MC p = sd; -- cgit v0.10.2 From 410c408108bb85f32fe132aaf448388af0b6da64 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 12:56:14 +0200 Subject: sched: Separate out build of MC sched domain from __build_sched_domains ... to further strip down __build_sched_domains(). Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818105614.GF29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 3d0666c..5c829d4 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8529,6 +8529,23 @@ static struct sched_domain *__build_cpu_sched_domain(struct s_data *d, return sd; } +static struct sched_domain *__build_mc_sched_domain(struct s_data *d, + const struct cpumask *cpu_map, struct sched_domain_attr *attr, + struct sched_domain *parent, int i) +{ + struct sched_domain *sd = parent; +#ifdef CONFIG_SCHED_MC + sd = &per_cpu(core_domains, i).sd; + SD_INIT(sd, MC); + set_domain_attribute(sd, attr); + cpumask_and(sched_domain_span(sd), cpu_map, cpu_coregroup_mask(i)); + sd->parent = parent; + parent->child = sd; + cpu_to_core_group(i, cpu_map, &sd->groups, d->tmpmask); +#endif + return sd; +} + /* * Build sched domains for a given set of cpus and attach the sched domains * to the individual cpus @@ -8559,18 +8576,7 @@ static int __build_sched_domains(const struct cpumask *cpu_map, sd = __build_numa_sched_domains(&d, cpu_map, attr, i); sd = __build_cpu_sched_domain(&d, cpu_map, attr, sd, i); - -#ifdef CONFIG_SCHED_MC - p = sd; - sd = &per_cpu(core_domains, i).sd; - SD_INIT(sd, MC); - set_domain_attribute(sd, attr); - cpumask_and(sched_domain_span(sd), cpu_map, - cpu_coregroup_mask(i)); - sd->parent = p; - p->child = sd; - cpu_to_core_group(i, cpu_map, &sd->groups, d.tmpmask); -#endif + sd = __build_mc_sched_domain(&d, cpu_map, attr, sd, i); #ifdef CONFIG_SCHED_SMT p = sd; -- cgit v0.10.2 From d81735355533cd4b2bce9508d86fcad24a38cf47 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 12:57:03 +0200 Subject: sched: Separate out build of SMT sched domain from __build_sched_domains ... to further strip down __build_sched_domains(). Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818105703.GG29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 5c829d4..2ecec06 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8546,6 +8546,23 @@ static struct sched_domain *__build_mc_sched_domain(struct s_data *d, return sd; } +static struct sched_domain *__build_smt_sched_domain(struct s_data *d, + const struct cpumask *cpu_map, struct sched_domain_attr *attr, + struct sched_domain *parent, int i) +{ + struct sched_domain *sd = parent; +#ifdef CONFIG_SCHED_SMT + sd = &per_cpu(cpu_domains, i).sd; + SD_INIT(sd, SIBLING); + set_domain_attribute(sd, attr); + cpumask_and(sched_domain_span(sd), cpu_map, topology_thread_cpumask(i)); + sd->parent = parent; + parent->child = sd; + cpu_to_cpu_group(i, cpu_map, &sd->groups, d->tmpmask); +#endif + return sd; +} + /* * Build sched domains for a given set of cpus and attach the sched domains * to the individual cpus @@ -8569,7 +8586,7 @@ static int __build_sched_domains(const struct cpumask *cpu_map, * Set up domains for cpus specified by the cpu_map. */ for_each_cpu(i, cpu_map) { - struct sched_domain *sd = NULL, *p; + struct sched_domain *sd; cpumask_and(d.nodemask, cpumask_of_node(cpu_to_node(i)), cpu_map); @@ -8577,18 +8594,7 @@ static int __build_sched_domains(const struct cpumask *cpu_map, sd = __build_numa_sched_domains(&d, cpu_map, attr, i); sd = __build_cpu_sched_domain(&d, cpu_map, attr, sd, i); sd = __build_mc_sched_domain(&d, cpu_map, attr, sd, i); - -#ifdef CONFIG_SCHED_SMT - p = sd; - sd = &per_cpu(cpu_domains, i).sd; - SD_INIT(sd, SIBLING); - set_domain_attribute(sd, attr); - cpumask_and(sched_domain_span(sd), - topology_thread_cpumask(i), cpu_map); - sd->parent = p; - p->child = sd; - cpu_to_cpu_group(i, cpu_map, &sd->groups, d.tmpmask); -#endif + sd = __build_smt_sched_domain(&d, cpu_map, attr, sd, i); } #ifdef CONFIG_SCHED_SMT -- cgit v0.10.2 From 0e8e85c941d8f1b43bcc2e3b8b7026cdae476c53 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 12:57:51 +0200 Subject: sched: Separate out build of SMT sched groups from __build_sched_domains ... to further strip down __build_sched_domains(). Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818105751.GH29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 2ecec06..43cfc6e5 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8563,6 +8563,25 @@ static struct sched_domain *__build_smt_sched_domain(struct s_data *d, return sd; } +static void build_sched_groups(struct s_data *d, enum sched_domain_level l, + const struct cpumask *cpu_map, int cpu) +{ + switch (l) { +#ifdef CONFIG_SCHED_SMT + case SD_LV_SIBLING: /* set up CPU (sibling) groups */ + cpumask_and(d->this_sibling_map, cpu_map, + topology_thread_cpumask(cpu)); + if (cpu == cpumask_first(d->this_sibling_map)) + init_sched_build_groups(d->this_sibling_map, cpu_map, + &cpu_to_cpu_group, + d->send_covered, d->tmpmask); + break; +#endif + default: + break; + } +} + /* * Build sched domains for a given set of cpus and attach the sched domains * to the individual cpus @@ -8597,19 +8616,9 @@ static int __build_sched_domains(const struct cpumask *cpu_map, sd = __build_smt_sched_domain(&d, cpu_map, attr, sd, i); } -#ifdef CONFIG_SCHED_SMT - /* Set up CPU (sibling) groups */ for_each_cpu(i, cpu_map) { - cpumask_and(d.this_sibling_map, - topology_thread_cpumask(i), cpu_map); - if (i != cpumask_first(d.this_sibling_map)) - continue; - - init_sched_build_groups(d.this_sibling_map, cpu_map, - &cpu_to_cpu_group, - d.send_covered, d.tmpmask); + build_sched_groups(&d, SD_LV_SIBLING, cpu_map, i); } -#endif #ifdef CONFIG_SCHED_MC /* Set up multi-core groups */ -- cgit v0.10.2 From a2af04cdbb748158043e31799b28c48272081600 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 12:58:38 +0200 Subject: sched: Separate out build of MC sched groups from __build_sched_domains ... to further strip down __build_sched_domains(). Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818105838.GI29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 43cfc6e5..f2c202f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8577,6 +8577,15 @@ static void build_sched_groups(struct s_data *d, enum sched_domain_level l, d->send_covered, d->tmpmask); break; #endif +#ifdef CONFIG_SCHED_MC + case SD_LV_MC: /* set up multi-core groups */ + cpumask_and(d->this_core_map, cpu_map, cpu_coregroup_mask(cpu)); + if (cpu == cpumask_first(d->this_core_map)) + init_sched_build_groups(d->this_core_map, cpu_map, + &cpu_to_core_group, + d->send_covered, d->tmpmask); + break; +#endif default: break; } @@ -8618,21 +8627,9 @@ static int __build_sched_domains(const struct cpumask *cpu_map, for_each_cpu(i, cpu_map) { build_sched_groups(&d, SD_LV_SIBLING, cpu_map, i); + build_sched_groups(&d, SD_LV_MC, cpu_map, i); } -#ifdef CONFIG_SCHED_MC - /* Set up multi-core groups */ - for_each_cpu(i, cpu_map) { - cpumask_and(d.this_core_map, cpu_coregroup_mask(i), cpu_map); - if (i != cpumask_first(d.this_core_map)) - continue; - - init_sched_build_groups(d.this_core_map, cpu_map, - &cpu_to_core_group, - d.send_covered, d.tmpmask); - } -#endif - /* Set up physical groups */ for (i = 0; i < nr_node_ids; i++) { cpumask_and(d.nodemask, cpumask_of_node(i), cpu_map); -- cgit v0.10.2 From 86548096f252bfe2065f1ea2d301e7319a16375d Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 12:59:28 +0200 Subject: sched: Separate out build of CPU sched groups from __build_sched_domains ... to further strip down __build_sched_domains(). Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818105928.GJ29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index f2c202f..b09a41c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8586,6 +8586,13 @@ static void build_sched_groups(struct s_data *d, enum sched_domain_level l, d->send_covered, d->tmpmask); break; #endif + case SD_LV_CPU: /* set up physical groups */ + cpumask_and(d->nodemask, cpumask_of_node(cpu), cpu_map); + if (!cpumask_empty(d->nodemask)) + init_sched_build_groups(d->nodemask, cpu_map, + &cpu_to_phys_group, + d->send_covered, d->tmpmask); + break; default: break; } @@ -8631,15 +8638,8 @@ static int __build_sched_domains(const struct cpumask *cpu_map, } /* Set up physical groups */ - for (i = 0; i < nr_node_ids; i++) { - cpumask_and(d.nodemask, cpumask_of_node(i), cpu_map); - if (cpumask_empty(d.nodemask)) - continue; - - init_sched_build_groups(d.nodemask, cpu_map, - &cpu_to_phys_group, - d.send_covered, d.tmpmask); - } + for (i = 0; i < nr_node_ids; i++) + build_sched_groups(&d, SD_LV_CPU, cpu_map, i); #ifdef CONFIG_NUMA /* Set up node groups */ -- cgit v0.10.2 From de616e36c700dc312d9021dd75f769c463f85122 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 13:00:13 +0200 Subject: sched: Separate out build of ALLNODES sched groups from __build_sched_domains For the sake of completeness. Now all calls to init_sched_build_groups() are contained in build_sched_groups(). Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818110013.GK29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index b09a41c..52c1953 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8593,6 +8593,12 @@ static void build_sched_groups(struct s_data *d, enum sched_domain_level l, &cpu_to_phys_group, d->send_covered, d->tmpmask); break; +#ifdef CONFIG_NUMA + case SD_LV_ALLNODES: + init_sched_build_groups(cpu_map, cpu_map, &cpu_to_allnodes_group, + d->send_covered, d->tmpmask); + break; +#endif default: break; } @@ -8643,11 +8649,8 @@ static int __build_sched_domains(const struct cpumask *cpu_map, #ifdef CONFIG_NUMA /* Set up node groups */ - if (d.sd_allnodes) { - init_sched_build_groups(cpu_map, cpu_map, - &cpu_to_allnodes_group, - d.send_covered, d.tmpmask); - } + if (d.sd_allnodes) + build_sched_groups(&d, SD_LV_ALLNODES, cpu_map, 0); for (i = 0; i < nr_node_ids; i++) { /* Set up node groups */ -- cgit v0.10.2 From 0601a88d8fa4508eaa49a6d96c6685e1dece38e3 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 13:01:11 +0200 Subject: sched: Separate out build of NUMA sched groups from __build_sched_domains ... to further strip down __build_sched_domains(). Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818110111.GL29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 52c1953..c1ce884 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8246,6 +8246,71 @@ static void init_numa_sched_groups_power(struct sched_group *group_head) sg = sg->next; } while (sg != group_head); } + +static int build_numa_sched_groups(struct s_data *d, + const struct cpumask *cpu_map, int num) +{ + struct sched_domain *sd; + struct sched_group *sg, *prev; + int n, j; + + cpumask_clear(d->covered); + cpumask_and(d->nodemask, cpumask_of_node(num), cpu_map); + if (cpumask_empty(d->nodemask)) { + d->sched_group_nodes[num] = NULL; + goto out; + } + + sched_domain_node_span(num, d->domainspan); + cpumask_and(d->domainspan, d->domainspan, cpu_map); + + sg = kmalloc_node(sizeof(struct sched_group) + cpumask_size(), + GFP_KERNEL, num); + if (!sg) { + printk(KERN_WARNING "Can not alloc domain group for node %d\n", + num); + return -ENOMEM; + } + d->sched_group_nodes[num] = sg; + + for_each_cpu(j, d->nodemask) { + sd = &per_cpu(node_domains, j).sd; + sd->groups = sg; + } + + sg->__cpu_power = 0; + cpumask_copy(sched_group_cpus(sg), d->nodemask); + sg->next = sg; + cpumask_or(d->covered, d->covered, d->nodemask); + + prev = sg; + for (j = 0; j < nr_node_ids; j++) { + n = (num + j) % nr_node_ids; + cpumask_complement(d->notcovered, d->covered); + cpumask_and(d->tmpmask, d->notcovered, cpu_map); + cpumask_and(d->tmpmask, d->tmpmask, d->domainspan); + if (cpumask_empty(d->tmpmask)) + break; + cpumask_and(d->tmpmask, d->tmpmask, cpumask_of_node(n)); + if (cpumask_empty(d->tmpmask)) + continue; + sg = kmalloc_node(sizeof(struct sched_group) + cpumask_size(), + GFP_KERNEL, num); + if (!sg) { + printk(KERN_WARNING + "Can not alloc domain group for node %d\n", j); + return -ENOMEM; + } + sg->__cpu_power = 0; + cpumask_copy(sched_group_cpus(sg), d->tmpmask); + sg->next = prev->next; + cpumask_or(d->covered, d->covered, d->tmpmask); + prev->next = sg; + prev = sg; + } +out: + return 0; +} #endif /* CONFIG_NUMA */ #ifdef CONFIG_NUMA @@ -8652,70 +8717,9 @@ static int __build_sched_domains(const struct cpumask *cpu_map, if (d.sd_allnodes) build_sched_groups(&d, SD_LV_ALLNODES, cpu_map, 0); - for (i = 0; i < nr_node_ids; i++) { - /* Set up node groups */ - struct sched_group *sg, *prev; - int j; - - cpumask_clear(d.covered); - cpumask_and(d.nodemask, cpumask_of_node(i), cpu_map); - if (cpumask_empty(d.nodemask)) { - d.sched_group_nodes[i] = NULL; - continue; - } - - sched_domain_node_span(i, d.domainspan); - cpumask_and(d.domainspan, d.domainspan, cpu_map); - - sg = kmalloc_node(sizeof(struct sched_group) + cpumask_size(), - GFP_KERNEL, i); - if (!sg) { - printk(KERN_WARNING "Can not alloc domain group for " - "node %d\n", i); + for (i = 0; i < nr_node_ids; i++) + if (build_numa_sched_groups(&d, cpu_map, i)) goto error; - } - d.sched_group_nodes[i] = sg; - for_each_cpu(j, d.nodemask) { - struct sched_domain *sd; - - sd = &per_cpu(node_domains, j).sd; - sd->groups = sg; - } - sg->__cpu_power = 0; - cpumask_copy(sched_group_cpus(sg), d.nodemask); - sg->next = sg; - cpumask_or(d.covered, d.covered, d.nodemask); - prev = sg; - - for (j = 0; j < nr_node_ids; j++) { - int n = (i + j) % nr_node_ids; - - cpumask_complement(d.notcovered, d.covered); - cpumask_and(d.tmpmask, d.notcovered, cpu_map); - cpumask_and(d.tmpmask, d.tmpmask, d.domainspan); - if (cpumask_empty(d.tmpmask)) - break; - - cpumask_and(d.tmpmask, d.tmpmask, cpumask_of_node(n)); - if (cpumask_empty(d.tmpmask)) - continue; - - sg = kmalloc_node(sizeof(struct sched_group) + - cpumask_size(), - GFP_KERNEL, i); - if (!sg) { - printk(KERN_WARNING - "Can not alloc domain group for node %d\n", j); - goto error; - } - sg->__cpu_power = 0; - cpumask_copy(sched_group_cpus(sg), d.tmpmask); - sg->next = prev->next; - cpumask_or(d.covered, d.covered, d.tmpmask); - prev->next = sg; - prev = sg; - } - } #endif /* Calculate CPU power for physical packages and nodes */ -- cgit v0.10.2 From 294b0c9619a0469a3b385b6fc47e79f64222a692 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 18 Aug 2009 13:02:29 +0200 Subject: sched: Consolidate definition of variable sd in __build_sched_domains Signed-off-by: Andreas Herrmann Cc: Peter Zijlstra LKML-Reference: <20090818110229.GM29515@alberich.amd.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index c1ce884..cf4c953 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8678,6 +8678,7 @@ static int __build_sched_domains(const struct cpumask *cpu_map, { enum s_alloc alloc_state = sa_none; struct s_data d; + struct sched_domain *sd; int i; #ifdef CONFIG_NUMA d.sd_allnodes = 0; @@ -8692,8 +8693,6 @@ static int __build_sched_domains(const struct cpumask *cpu_map, * Set up domains for cpus specified by the cpu_map. */ for_each_cpu(i, cpu_map) { - struct sched_domain *sd; - cpumask_and(d.nodemask, cpumask_of_node(cpu_to_node(i)), cpu_map); @@ -8725,22 +8724,19 @@ static int __build_sched_domains(const struct cpumask *cpu_map, /* Calculate CPU power for physical packages and nodes */ #ifdef CONFIG_SCHED_SMT for_each_cpu(i, cpu_map) { - struct sched_domain *sd = &per_cpu(cpu_domains, i).sd; - + sd = &per_cpu(cpu_domains, i).sd; init_sched_groups_power(i, sd); } #endif #ifdef CONFIG_SCHED_MC for_each_cpu(i, cpu_map) { - struct sched_domain *sd = &per_cpu(core_domains, i).sd; - + sd = &per_cpu(core_domains, i).sd; init_sched_groups_power(i, sd); } #endif for_each_cpu(i, cpu_map) { - struct sched_domain *sd = &per_cpu(phys_domains, i).sd; - + sd = &per_cpu(phys_domains, i).sd; init_sched_groups_power(i, sd); } @@ -8759,7 +8755,6 @@ static int __build_sched_domains(const struct cpumask *cpu_map, /* Attach the domains */ for_each_cpu(i, cpu_map) { - struct sched_domain *sd; #ifdef CONFIG_SCHED_SMT sd = &per_cpu(cpu_domains, i).sd; #elif defined(CONFIG_SCHED_MC) -- cgit v0.10.2 From b08dc3eba0c34027010caeda258f495074ae3a54 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Tue, 18 Aug 2009 21:57:13 +0800 Subject: Security/SELinux: remove duplicated #include Remove duplicated #include('s) in kernel/sysctl.c Signed-off-by: Huang Weiyi Acked-by: Eric Paris Signed-off-by: James Morris diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 58be760..71d8dc7 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 From fdbc66266c21976027938642f60e0f047149a61a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 19 Aug 2009 00:18:10 +0200 Subject: ALSA: hda - Fix invalid capture mixers with some ALC268 models The auto-mic clean-up patches caused regressions on some ALC268 models that have no proper input_mux but with "Input Source" mixer elements. Such a combination results in Oops when accessed. [A reason why set_capture_mixer() isn't used in patch_alc268() is that ALC268 codec have HDA_OUTPUT direction for capture volumes unlike other codecs. Thus it needs own definitions of capture elements.] This patch fixes the issues: - Add a capture mixer definition without input-source - Use the new capture mixer appropriately Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7ff2934..efb92c8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -12018,21 +12018,16 @@ static struct hda_verb alc268_volume_init_verbs[] = { { } }; +static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), + { } /* end */ +}; + static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, + _DEFINE_CAPSRC(1), { } /* end */ }; @@ -12041,18 +12036,7 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = { HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, + _DEFINE_CAPSRC(2), { } /* end */ }; @@ -12434,7 +12418,8 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { static struct alc_config_preset alc268_presets[] = { [ALC267_QUANTA_IL1] = { - .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer }, + .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer, + alc268_capture_nosrc_mixer }, .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, alc267_quanta_il1_verbs }, .num_dacs = ARRAY_SIZE(alc268_dac_nids), @@ -12444,7 +12429,6 @@ static struct alc_config_preset alc268_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, - .input_mux = &alc268_capture_source, .unsol_event = alc_sku_unsol_event, .setup = alc267_quanta_il1_setup, .init_hook = alc_inithook, @@ -12483,7 +12467,7 @@ static struct alc_config_preset alc268_presets[] = { .init_hook = alc268_toshiba_automute, }, [ALC268_ACER] = { - .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, + .mixers = { alc268_acer_mixer, alc268_capture_nosrc_mixer, alc268_beep_mixer }, .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, alc268_acer_verbs }, @@ -12519,7 +12503,7 @@ static struct alc_config_preset alc268_presets[] = { [ALC268_ACER_ASPIRE_ONE] = { .mixers = { alc268_acer_aspire_one_mixer, alc268_beep_mixer, - alc268_capture_alt_mixer }, + alc268_capture_nosrc_mixer }, .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, alc268_acer_aspire_one_verbs }, .num_dacs = ARRAY_SIZE(alc268_dac_nids), @@ -12535,11 +12519,15 @@ static struct alc_config_preset alc268_presets[] = { .init_hook = alc268_acer_lc_init_hook, }, [ALC268_DELL] = { - .mixers = { alc268_dell_mixer, alc268_beep_mixer }, + .mixers = { alc268_dell_mixer, alc268_beep_mixer, + alc268_capture_nosrc_mixer }, .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, alc268_dell_verbs }, .num_dacs = ARRAY_SIZE(alc268_dac_nids), .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, .hp_nid = 0x02, .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, @@ -12659,10 +12647,14 @@ static int patch_alc268(struct hda_codec *codec) /* get type */ wcap = get_wcaps_type(wcap); - if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { + if (spec->auto_mic || + wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { spec->adc_nids = alc268_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt); - add_mixer(spec, alc268_capture_alt_mixer); + if (spec->auto_mic || spec->input_mux->num_items == 1) + add_mixer(spec, alc268_capture_nosrc_mixer); + else + add_mixer(spec, alc268_capture_alt_mixer); } else { spec->adc_nids = alc268_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids); -- cgit v0.10.2 From 23428e6b4649adfbdaa6a0c93fc6d652bf5f9d44 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 18 Aug 2009 20:13:03 -0700 Subject: mdio: mdio_if_info::mmds should not be __bitwise I misunderstood the meaning of __bitwise. In practice it makes sparse warn about every use of mmds which is certainly not what we want. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/include/linux/mdio.h b/include/linux/mdio.h index cfdf1df..c779b49 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -304,7 +304,7 @@ static inline __u16 mdio_phy_id_devad(int phy_id) */ struct mdio_if_info { int prtad; - u32 __bitwise mmds; + u32 mmds; unsigned mode_support; struct net_device *dev; -- cgit v0.10.2 From d6e74b6b7eda3584a403eebae27f9591a1d9c9ff Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:05 +0000 Subject: sky2: use upper/lower 32 bits Use the existing macros to show where DMA address is being broken apart. This is cosmetic only. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 8a763f8..fb841c8 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -984,12 +984,12 @@ static void sky2_qset(struct sky2_hw *hw, u16 q) * hardware and driver list elements */ static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr, - u64 addr, u32 last) + dma_addr_t addr, u32 last) { sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_RST_CLR); - sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_HI), addr >> 32); - sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_LO), (u32) addr); + sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_HI), upper_32_bits(addr)); + sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_LO), lower_32_bits(addr)); sky2_write16(hw, Y2_QADDR(qaddr, PREF_UNIT_LAST_IDX), last); sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_OP_ON); @@ -1057,7 +1057,7 @@ static void sky2_rx_add(struct sky2_port *sky2, u8 op, } le = sky2_next_rx(sky2); - le->addr = cpu_to_le32((u32) map); + le->addr = cpu_to_le32(lower_32_bits(map)); le->length = cpu_to_le16(len); le->opcode = op | HW_OWNER; } @@ -1662,7 +1662,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) } le = get_tx_le(sky2, &slot); - le->addr = cpu_to_le32((u32) mapping); + le->addr = cpu_to_le32(lower_32_bits(mapping)); le->length = cpu_to_le16(len); le->ctrl = ctrl; le->opcode = mss ? (OP_LARGESEND | HW_OWNER) : (OP_PACKET | HW_OWNER); @@ -1689,7 +1689,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) } le = get_tx_le(sky2, &slot); - le->addr = cpu_to_le32((u32) mapping); + le->addr = cpu_to_le32(lower_32_bits(mapping)); le->length = cpu_to_le16(frag->size); le->ctrl = ctrl; le->opcode = OP_BUFFER | HW_OWNER; -- cgit v0.10.2 From 5dce95e5687a5a335202b03d133c1b4411ef7ce3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:06 +0000 Subject: sky2: transmit ring 64 bit conservation This patch saves elements on transmit ring by only updating the upper 64 bit address when it changes. With many workloads skb's are located in same region, so it saves space. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index fb841c8..88041e5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1016,6 +1016,7 @@ static void tx_init(struct sky2_port *sky2) le = get_tx_le(sky2, &sky2->tx_prod); le->addr = 0; le->opcode = OP_ADDR64 | HW_OWNER; + sky2->tx_last_upper = 0; } static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2, @@ -1573,8 +1574,9 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) struct sky2_tx_le *le = NULL; struct tx_ring_info *re; unsigned i, len; - u16 slot; dma_addr_t mapping; + u32 upper; + u16 slot; u16 mss; u8 ctrl; @@ -1593,9 +1595,11 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) dev->name, slot, skb->len); /* Send high bits if needed */ - if (sizeof(dma_addr_t) > sizeof(u32)) { + upper = upper_32_bits(mapping); + if (upper != sky2->tx_last_upper) { le = get_tx_le(sky2, &slot); - le->addr = cpu_to_le32(upper_32_bits(mapping)); + le->addr = cpu_to_le32(upper); + sky2->tx_last_upper = upper; le->opcode = OP_ADDR64 | HW_OWNER; } @@ -1681,10 +1685,11 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) if (pci_dma_mapping_error(hw->pdev, mapping)) goto mapping_unwind; - if (sizeof(dma_addr_t) > sizeof(u32)) { + upper = upper_32_bits(mapping); + if (upper != sky2->tx_last_upper) { le = get_tx_le(sky2, &slot); - le->addr = cpu_to_le32(upper_32_bits(mapping)); - le->ctrl = 0; + le->addr = cpu_to_le32(upper); + sky2->tx_last_upper = upper; le->opcode = OP_ADDR64 | HW_OWNER; } diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 65b94c3..feb3204 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2017,6 +2017,7 @@ struct sky2_port { u16 tx_pending; u16 tx_last_mss; + u32 tx_last_upper; u32 tx_tcpsum; struct rx_ring_info *rx_ring ____cacheline_aligned_in_smp; -- cgit v0.10.2 From c119731d6606ae25d787740d60706e2732454637 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:07 +0000 Subject: sky2: simplify list element error The code for list element error (which should only happen on hardware errors) should be cleaner and safer. Gets rid of unused ring_size argument, which makes next patch easier. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 88041e5..58d3521 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2661,19 +2661,15 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port) } /* This should never happen it is a bug. */ -static void sky2_le_error(struct sky2_hw *hw, unsigned port, - u16 q, unsigned ring_size) +static void sky2_le_error(struct sky2_hw *hw, unsigned port, u16 q) { struct net_device *dev = hw->dev[port]; - struct sky2_port *sky2 = netdev_priv(dev); - unsigned idx; - const u64 *le = (q == Q_R1 || q == Q_R2) - ? (u64 *) sky2->rx_le : (u64 *) sky2->tx_le; + u16 idx = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX)); - idx = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX)); - printk(KERN_ERR PFX "%s: descriptor error q=%#x get=%u [%llx] put=%u\n", - dev->name, (unsigned) q, idx, (unsigned long long) le[idx], - (unsigned) sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX))); + dev_err(&hw->pdev->dev, PFX + "%s: descriptor error q=%#x get=%u put=%u\n", + dev->name, (unsigned) q, (unsigned) idx, + (unsigned) sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX))); sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_IRQ_CHK); } @@ -2759,16 +2755,16 @@ static void sky2_err_intr(struct sky2_hw *hw, u32 status) sky2_mac_intr(hw, 1); if (status & Y2_IS_CHK_RX1) - sky2_le_error(hw, 0, Q_R1, RX_LE_SIZE); + sky2_le_error(hw, 0, Q_R1); if (status & Y2_IS_CHK_RX2) - sky2_le_error(hw, 1, Q_R2, RX_LE_SIZE); + sky2_le_error(hw, 1, Q_R2); if (status & Y2_IS_CHK_TXA1) - sky2_le_error(hw, 0, Q_XA1, TX_RING_SIZE); + sky2_le_error(hw, 0, Q_XA1); if (status & Y2_IS_CHK_TXA2) - sky2_le_error(hw, 1, Q_XA2, TX_RING_SIZE); + sky2_le_error(hw, 1, Q_XA2); } static int sky2_poll(struct napi_struct *napi, int work_limit) -- cgit v0.10.2 From ee5f68fea27b53b16c265b1f9ed8aa3bc9024c96 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:08 +0000 Subject: sky2: dynamic size transmit ring Allocate and size transmit ring based on parameters. Saves excess space and allows configuring larger rings for testing. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 58d3521..7c1880d 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -64,10 +64,12 @@ #define RX_MAX_PENDING (RX_LE_SIZE/6 - 2) #define RX_DEF_PENDING RX_MAX_PENDING -#define TX_RING_SIZE 512 -#define TX_DEF_PENDING 128 -#define MAX_SKB_TX_LE (4 + (sizeof(dma_addr_t)/sizeof(u32))*MAX_SKB_FRAGS) +/* This is the worst case number of transmit list elements for a single skb: + VLAN + TSO + CKSUM + Data + skb_frags * DMA */ +#define MAX_SKB_TX_LE (4 + (sizeof(dma_addr_t)/sizeof(u32))*MAX_SKB_FRAGS) #define TX_MIN_PENDING (MAX_SKB_TX_LE+1) +#define TX_MAX_PENDING 4096 +#define TX_DEF_PENDING 127 #define STATUS_RING_SIZE 2048 /* 2 ports * (TX + 2*RX) */ #define STATUS_LE_BYTES (STATUS_RING_SIZE*sizeof(struct sky2_status_le)) @@ -1000,7 +1002,7 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot) { struct sky2_tx_le *le = sky2->tx_le + *slot; - *slot = RING_NEXT(*slot, TX_RING_SIZE); + *slot = RING_NEXT(*slot, sky2->tx_ring_size); le->ctrl = 0; return le; } @@ -1433,13 +1435,13 @@ static int sky2_up(struct net_device *dev) /* must be power of 2 */ sky2->tx_le = pci_alloc_consistent(hw->pdev, - TX_RING_SIZE * + sky2->tx_ring_size * sizeof(struct sky2_tx_le), &sky2->tx_le_map); if (!sky2->tx_le) goto err_out; - sky2->tx_ring = kcalloc(TX_RING_SIZE, sizeof(struct tx_ring_info), + sky2->tx_ring = kcalloc(sky2->tx_ring_size, sizeof(struct tx_ring_info), GFP_KERNEL); if (!sky2->tx_ring) goto err_out; @@ -1491,7 +1493,7 @@ static int sky2_up(struct net_device *dev) sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), ECU_TXFF_LEV); sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, - TX_RING_SIZE - 1); + sky2->tx_ring_size - 1); #ifdef SKY2_VLAN_TAG_USED sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL); @@ -1520,7 +1522,7 @@ err_out: } if (sky2->tx_le) { pci_free_consistent(hw->pdev, - TX_RING_SIZE * sizeof(struct sky2_tx_le), + sky2->tx_ring_size * sizeof(struct sky2_tx_le), sky2->tx_le, sky2->tx_le_map); sky2->tx_le = NULL; } @@ -1533,15 +1535,15 @@ err_out: } /* Modular subtraction in ring */ -static inline int tx_dist(unsigned tail, unsigned head) +static inline int tx_inuse(const struct sky2_port *sky2) { - return (head - tail) & (TX_RING_SIZE - 1); + return (sky2->tx_prod - sky2->tx_cons) & (sky2->tx_ring_size - 1); } /* Number of list elements available for next tx */ static inline int tx_avail(const struct sky2_port *sky2) { - return sky2->tx_pending - tx_dist(sky2->tx_cons, sky2->tx_prod); + return sky2->tx_pending - tx_inuse(sky2); } /* Estimate of number of transmit list elements required */ @@ -1717,7 +1719,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; mapping_unwind: - for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, TX_RING_SIZE)) { + for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, sky2->tx_ring_size)) { le = sky2->tx_le + i; re = sky2->tx_ring + i; @@ -1760,10 +1762,10 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) struct pci_dev *pdev = sky2->hw->pdev; unsigned idx; - BUG_ON(done >= TX_RING_SIZE); + BUG_ON(done >= sky2->tx_ring_size); for (idx = sky2->tx_cons; idx != done; - idx = RING_NEXT(idx, TX_RING_SIZE)) { + idx = RING_NEXT(idx, sky2->tx_ring_size)) { struct sky2_tx_le *le = sky2->tx_le + idx; struct tx_ring_info *re = sky2->tx_ring + idx; @@ -1799,7 +1801,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) else dev_kfree_skb_any(skb); - sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE); + sky2->tx_next = RING_NEXT(idx, sky2->tx_ring_size); } } @@ -1907,7 +1909,7 @@ static int sky2_down(struct net_device *dev) kfree(sky2->rx_ring); pci_free_consistent(hw->pdev, - TX_RING_SIZE * sizeof(struct sky2_tx_le), + sky2->tx_ring_size * sizeof(struct sky2_tx_le), sky2->tx_le, sky2->tx_le_map); kfree(sky2->tx_ring); @@ -2517,7 +2519,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) case OP_TXINDEXLE: /* TX index reports status for both ports */ - BUILD_BUG_ON(TX_RING_SIZE > 0x1000); sky2_tx_done(hw->dev[0], status & 0xfff); if (hw->dev[1]) sky2_tx_done(hw->dev[1], @@ -3669,7 +3670,7 @@ static int sky2_set_coalesce(struct net_device *dev, ecmd->rx_coalesce_usecs_irq > tmax) return -EINVAL; - if (ecmd->tx_max_coalesced_frames >= TX_RING_SIZE-1) + if (ecmd->tx_max_coalesced_frames >= sky2->tx_ring_size-1) return -EINVAL; if (ecmd->rx_max_coalesced_frames > RX_MAX_PENDING) return -EINVAL; @@ -3713,7 +3714,7 @@ static void sky2_get_ringparam(struct net_device *dev, ering->rx_max_pending = RX_MAX_PENDING; ering->rx_mini_max_pending = 0; ering->rx_jumbo_max_pending = 0; - ering->tx_max_pending = TX_RING_SIZE - 1; + ering->tx_max_pending = TX_MAX_PENDING; ering->rx_pending = sky2->rx_pending; ering->rx_mini_pending = 0; @@ -3728,14 +3729,15 @@ static int sky2_set_ringparam(struct net_device *dev, if (ering->rx_pending > RX_MAX_PENDING || ering->rx_pending < 8 || - ering->tx_pending < MAX_SKB_TX_LE || - ering->tx_pending > TX_RING_SIZE - 1) + ering->tx_pending < TX_MIN_PENDING || + ering->tx_pending > TX_MAX_PENDING) return -EINVAL; sky2_detach(dev); sky2->rx_pending = ering->rx_pending; sky2->tx_pending = ering->tx_pending; + sky2->tx_ring_size = roundup_pow_of_two(sky2->tx_pending+1); return sky2_reattach(dev); } @@ -4105,8 +4107,8 @@ static int sky2_debug_show(struct seq_file *seq, void *v) /* Dump contents of tx ring */ sop = 1; - for (idx = sky2->tx_next; idx != sky2->tx_prod && idx < TX_RING_SIZE; - idx = RING_NEXT(idx, TX_RING_SIZE)) { + for (idx = sky2->tx_next; idx != sky2->tx_prod && idx < sky2->tx_ring_size; + idx = RING_NEXT(idx, sky2->tx_ring_size)) { const struct sky2_tx_le *le = sky2->tx_le + idx; u32 a = le32_to_cpu(le->addr); @@ -4315,7 +4317,9 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->wol = wol; spin_lock_init(&sky2->phy_lock); + sky2->tx_pending = TX_DEF_PENDING; + sky2->tx_ring_size = roundup_pow_of_two(TX_DEF_PENDING+1); sky2->rx_pending = RX_DEF_PENDING; hw->dev[port] = dev; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index feb3204..2c262f7 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2011,6 +2011,7 @@ struct sky2_port { struct tx_ring_info *tx_ring; struct sky2_tx_le *tx_le; + u16 tx_ring_size; u16 tx_cons; /* next le to check */ u16 tx_prod; /* next le to use */ u16 tx_next; /* debug only */ -- cgit v0.10.2 From 6b84dacadbdc3dab6a5b313d20d5a93b0d998641 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:09 +0000 Subject: sky2: optimize transmit completion Don't reference the list element in hardware transmit ring on transmit completion. The list element is updated by hardware, therefore it causes a cache miss. Do book keeping in software structure. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 7c1880d..a3e40d7 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1001,8 +1001,11 @@ static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr, static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot) { struct sky2_tx_le *le = sky2->tx_le + *slot; + struct tx_ring_info *re = sky2->tx_ring + *slot; *slot = RING_NEXT(*slot, sky2->tx_ring_size); + re->flags = 0; + re->skb = NULL; le->ctrl = 0; return le; } @@ -1021,12 +1024,6 @@ static void tx_init(struct sky2_port *sky2) sky2->tx_last_upper = 0; } -static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2, - struct sky2_tx_le *le) -{ - return sky2->tx_ring + (le - sky2->tx_le); -} - /* Update chip's next pointer */ static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx) { @@ -1563,6 +1560,19 @@ static unsigned tx_le_req(const struct sk_buff *skb) return count; } +static void sky2_tx_unmap(struct pci_dev *pdev, + const struct tx_ring_info *re) +{ + if (re->flags & TX_MAP_SINGLE) + pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr), + pci_unmap_len(re, maplen), + PCI_DMA_TODEVICE); + else if (re->flags & TX_MAP_PAGE) + pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr), + pci_unmap_len(re, maplen), + PCI_DMA_TODEVICE); +} + /* * Put one packet in ring for transmit. * A single packet can generate multiple list elements, and @@ -1667,16 +1677,17 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) } } + re = sky2->tx_ring + slot; + re->flags = TX_MAP_SINGLE; + pci_unmap_addr_set(re, mapaddr, mapping); + pci_unmap_len_set(re, maplen, len); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(lower_32_bits(mapping)); le->length = cpu_to_le16(len); le->ctrl = ctrl; le->opcode = mss ? (OP_LARGESEND | HW_OWNER) : (OP_PACKET | HW_OWNER); - re = tx_le_re(sky2, le); - re->skb = skb; - pci_unmap_addr_set(re, mapaddr, mapping); - pci_unmap_len_set(re, maplen, len); for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; @@ -1695,18 +1706,19 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) le->opcode = OP_ADDR64 | HW_OWNER; } + re = sky2->tx_ring + slot; + re->flags = TX_MAP_PAGE; + pci_unmap_addr_set(re, mapaddr, mapping); + pci_unmap_len_set(re, maplen, frag->size); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(lower_32_bits(mapping)); le->length = cpu_to_le16(frag->size); le->ctrl = ctrl; le->opcode = OP_BUFFER | HW_OWNER; - - re = tx_le_re(sky2, le); - re->skb = skb; - pci_unmap_addr_set(re, mapaddr, mapping); - pci_unmap_len_set(re, maplen, frag->size); } + re->skb = skb; le->ctrl |= EOP; sky2->tx_prod = slot; @@ -1720,23 +1732,9 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) mapping_unwind: for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, sky2->tx_ring_size)) { - le = sky2->tx_le + i; re = sky2->tx_ring + i; - switch(le->opcode & ~HW_OWNER) { - case OP_LARGESEND: - case OP_PACKET: - pci_unmap_single(hw->pdev, - pci_unmap_addr(re, mapaddr), - pci_unmap_len(re, maplen), - PCI_DMA_TODEVICE); - break; - case OP_BUFFER: - pci_unmap_page(hw->pdev, pci_unmap_addr(re, mapaddr), - pci_unmap_len(re, maplen), - PCI_DMA_TODEVICE); - break; - } + sky2_tx_unmap(hw->pdev, re); } mapping_error: @@ -1759,34 +1757,18 @@ mapping_error: static void sky2_tx_complete(struct sky2_port *sky2, u16 done) { struct net_device *dev = sky2->netdev; - struct pci_dev *pdev = sky2->hw->pdev; unsigned idx; BUG_ON(done >= sky2->tx_ring_size); for (idx = sky2->tx_cons; idx != done; idx = RING_NEXT(idx, sky2->tx_ring_size)) { - struct sky2_tx_le *le = sky2->tx_le + idx; struct tx_ring_info *re = sky2->tx_ring + idx; + struct sk_buff *skb = re->skb; - switch(le->opcode & ~HW_OWNER) { - case OP_LARGESEND: - case OP_PACKET: - pci_unmap_single(pdev, - pci_unmap_addr(re, mapaddr), - pci_unmap_len(re, maplen), - PCI_DMA_TODEVICE); - break; - case OP_BUFFER: - pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr), - pci_unmap_len(re, maplen), - PCI_DMA_TODEVICE); - break; - } - - if (le->ctrl & EOP) { - struct sk_buff *skb = re->skb; + sky2_tx_unmap(sky2->hw->pdev, re); + if (skb) { if (unlikely(netif_msg_tx_done(sky2))) printk(KERN_DEBUG "%s: tx done %u\n", dev->name, idx); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 2c262f7..9d07a46 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1984,6 +1984,9 @@ struct sky2_status_le { struct tx_ring_info { struct sk_buff *skb; + unsigned long flags; +#define TX_MAP_SINGLE 0x0001 +#define TX_MAP_PAGE 000002 DECLARE_PCI_UNMAP_ADDR(mapaddr); DECLARE_PCI_UNMAP_LEN(maplen); }; -- cgit v0.10.2 From 724b694225e711f95e6265afdbc304c9e7eb3721 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:10 +0000 Subject: sky2: no recycling Recycling turns out to be a bad idea! For most use cases, the packet can not be reused: TCP packets are cloned. Even for the ideal case of forwarding, it hurts performance because of CPU ping/pong. On a multi-core system forwarding of 64 byte packets is worse much worse: recycling = 24% forwarded vs no recycling = 42% forwarded Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a3e40d7..1b79d33 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1177,7 +1177,6 @@ static void sky2_rx_clean(struct sky2_port *sky2) re->skb = NULL; } } - skb_queue_purge(&sky2->rx_recycle); } /* Basic MII support */ @@ -1269,10 +1268,8 @@ static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2) struct sk_buff *skb; int i; - skb = __skb_dequeue(&sky2->rx_recycle); - if (!skb) - skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size - + sky2_rx_pad(sky2->hw)); + skb = netdev_alloc_skb(sky2->netdev, + sky2->rx_data_size + sky2_rx_pad(sky2->hw)); if (!skb) goto nomem; @@ -1364,8 +1361,6 @@ static int sky2_rx_start(struct sky2_port *sky2) sky2->rx_data_size = size; - skb_queue_head_init(&sky2->rx_recycle); - /* Fill Rx ring */ for (i = 0; i < sky2->rx_pending; i++) { re = sky2->rx_ring + i; @@ -1776,12 +1771,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; - if (skb_queue_len(&sky2->rx_recycle) < sky2->rx_pending - && skb_recycle_check(skb, sky2->rx_data_size - + sky2_rx_pad(sky2->hw))) - __skb_queue_head(&sky2->rx_recycle, skb); - else - dev_kfree_skb_any(skb); + dev_kfree_skb_any(skb); sky2->tx_next = RING_NEXT(idx, sky2->tx_ring_size); } diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 9d07a46..73c9547 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2032,7 +2032,6 @@ struct sky2_port { u16 rx_pending; u16 rx_data_size; u16 rx_nfrags; - struct sk_buff_head rx_recycle; #ifdef SKY2_VLAN_TAG_USED u16 rx_tag; -- cgit v0.10.2 From 0c3f450b8b345dafa79f1cc69eda702e0293b0cc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:11 +0000 Subject: sky2: version 1.25 Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1b79d33..dd630cf 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -50,7 +50,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.24" +#define DRV_VERSION "1.25" #define PFX DRV_NAME " " /* -- cgit v0.10.2 From 1423cc033df017c762a9155eec470da77a460141 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 18 Aug 2009 23:06:14 -0700 Subject: rcu: Delay rcu_barrier() wait until beginning of next CPU-hotunplug operation. Ingo Molnar reported this lockup: [ 200.380003] Hangcheck: hangcheck value past margin! [ 248.192003] INFO: task S99local:2974 blocked for more than 120 seconds. [ 248.194532] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 248.202330] S99local D 0000000c 6256 2974 2687 0x00000000 [ 248.208929] 9c7ebe90 00000086 6b67ef8b 0000000c 9f25a610 81a69869 00000001 820b6990 [ 248.216123] 820b6990 820b6990 9c6e4c20 9c6e4eb4 82c78990 00000000 6b993559 0000000c [ 248.220616] 9c7ebe90 8105f22a 9c6e4eb4 9c6e4c20 00000001 9c7ebe98 9c7ebeb4 81a65cb3 [ 248.229990] Call Trace: [ 248.234049] [<81a69869>] ? _spin_unlock_irqrestore+0x22/0x37 [ 248.239769] [<8105f22a>] ? prepare_to_wait+0x48/0x4e [ 248.244796] [<81a65cb3>] rcu_barrier_cpu_hotplug+0xaa/0xc9 [ 248.250343] [<8105f029>] ? autoremove_wake_function+0x0/0x38 [ 248.256063] [<81062cf2>] notifier_call_chain+0x49/0x71 [ 248.261263] [<81062da0>] raw_notifier_call_chain+0x11/0x13 [ 248.266809] [<81a0b475>] _cpu_down+0x272/0x288 [ 248.271316] [<81a0b4d5>] cpu_down+0x4a/0xa2 [ 248.275563] [<81a0c48a>] store_online+0x2a/0x5e [ 248.280156] [<81a0c460>] ? store_online+0x0/0x5e [ 248.284836] [<814ddc35>] sysdev_store+0x20/0x28 [ 248.289429] [<8112e403>] sysfs_write_file+0xb8/0xe3 [ 248.294369] [<8112e34b>] ? sysfs_write_file+0x0/0xe3 [ 248.299396] [<810e4c8f>] vfs_write+0x91/0x120 [ 248.303817] [<810e4dc1>] sys_write+0x40/0x65 [ 248.308150] [<81002d73>] sysenter_do_call+0x12/0x28 This change moves an RCU grace period delay off of the critical path for CPU-hotunplug operations. Since RCU callback migration is only performed on CPU-hotunplug operations, and since the rcu_barrier() race is provoked only by consecutive CPU-hotunplug operations, it is not necessary to delay the end of a given CPU-hotunplug operation. We can instead choose to delay the beginning of the next CPU-hotunplug operation. Reported-by: Ingo Molnar Signed-off-by: Paul E. McKenney Cc: Josh Triplett Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: akpm@linux-foundation.org Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: hugh.dickins@tiscali.co.uk Cc: benh@kernel.crashing.org LKML-Reference: <20090819060614.GA14383@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 8df1156..bd5d5c8 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -238,7 +238,8 @@ static int __cpuinit rcu_barrier_cpu_hotplug(struct notifier_block *self, call_rcu_bh(rcu_migrate_head, rcu_migrate_callback); call_rcu_sched(rcu_migrate_head + 1, rcu_migrate_callback); call_rcu(rcu_migrate_head + 2, rcu_migrate_callback); - } else if (action == CPU_POST_DEAD) { + } else if (action == CPU_DOWN_PREPARE) { + /* Don't need to wait until next removal operation. */ /* rcu_migrate_head is protected by cpu_add_remove_lock */ wait_migrated_callbacks(); } -- cgit v0.10.2 From 5e9ad7df9fd056f1071af8aa91034a1c3170257d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 18 Aug 2009 10:41:57 +0200 Subject: [S390] ftrace: update system call tracer support Commit fb34a08c3 ("tracing: Add trace events for each syscall entry/exit") changed the lowlevel API to ftrace syscall tracing but did not update s390 which started making use of it recently. This broke the s390 build, as reported by Paul Mundt. Update the callbacks with the syscall number and the syscall return code values. This allows per syscall tracepoints, syscall argument enumeration /debug/tracing/events/syscalls/ and perfcounters support and integration on s390 too. Reported-by: Paul Mundt Acked-by: Martin Schwidefsky Cc: Heiko Carstens Cc: Jason Baron Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 43acd73..c5e87d8 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -51,6 +51,9 @@ #include "compat_ptrace.h" #endif +DEFINE_TRACE(syscall_enter); +DEFINE_TRACE(syscall_exit); + enum s390_regset { REGSET_GENERAL, REGSET_FP, @@ -662,7 +665,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) } if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) - ftrace_syscall_enter(regs); + trace_syscall_enter(regs, regs->gprs[2]); if (unlikely(current->audit_context)) audit_syscall_entry(is_compat_task() ? @@ -680,7 +683,7 @@ asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) regs->gprs[2]); if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) - ftrace_syscall_exit(regs); + trace_syscall_exit(regs, regs->gprs[2]); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, 0); -- cgit v0.10.2 From e6971969c331caa5c3c88cbd1be4f465b3355452 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Wed, 19 Aug 2009 15:52:25 +0800 Subject: tracing/syscalls: Fix fields format for enter events The "format" file of a trace event is originally for parsers to parse ftrace binary output. But the "format" file of a syscall event can only be used by perfcounter, because it describes the format of struct syscall_enter_record not struct syscall_trace_enter. To fix this, we remove struct syscall_enter_record, and then struct syscall_trace_enter will be used by both perf profile and ftrace. Signed-off-by: Li Zefan Cc: Jason Baron Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4A8BAF39.1030404@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index f130dac..d10daf0 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -90,26 +90,39 @@ print_syscall_exit(struct trace_iterator *iter, int flags) return TRACE_TYPE_HANDLED; } +extern char *__bad_type_size(void); + +#define SYSCALL_FIELD(type, name) \ + sizeof(type) != sizeof(trace.name) ? \ + __bad_type_size() : \ + #type, #name, offsetof(typeof(trace), name), sizeof(trace.name) + int ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s) { int i; int nr; - int ret = 0; + int ret; struct syscall_metadata *entry; - int offset = sizeof(struct trace_entry); + struct syscall_trace_enter trace; + int offset = offsetof(struct syscall_trace_enter, args); - nr = syscall_name_to_nr((char *)call->data); + nr = syscall_name_to_nr(call->data); entry = syscall_nr_to_meta(nr); if (!entry) - return ret; + return 0; + + ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n", + SYSCALL_FIELD(int, nr)); + if (!ret) + return 0; for (i = 0; i < entry->nb_args; i++) { ret = trace_seq_printf(s, "\tfield:%s %s;", entry->types[i], entry->args[i]); if (!ret) return 0; - ret = trace_seq_printf(s, "\toffset:%d;\tsize:%lu;\n", offset, + ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;\n", offset, sizeof(unsigned long)); if (!ret) return 0; @@ -118,7 +131,7 @@ int ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s) trace_seq_printf(s, "\nprint fmt: \""); for (i = 0; i < entry->nb_args; i++) { - ret = trace_seq_printf(s, "%s: 0x%%0%lulx%s", entry->args[i], + ret = trace_seq_printf(s, "%s: 0x%%0%zulx%s", entry->args[i], sizeof(unsigned long), i == entry->nb_args - 1 ? "\", " : ", "); if (!ret) @@ -287,16 +300,6 @@ struct trace_event event_syscall_exit = { #ifdef CONFIG_EVENT_PROFILE -struct syscall_enter_record { - struct trace_entry entry; - unsigned long args[0]; -}; - -struct syscall_exit_record { - struct trace_entry entry; - unsigned long ret; -}; - static DECLARE_BITMAP(enabled_prof_enter_syscalls, FTRACE_SYSCALL_MAX); static DECLARE_BITMAP(enabled_prof_exit_syscalls, FTRACE_SYSCALL_MAX); static int sys_prof_refcount_enter; @@ -304,7 +307,7 @@ static int sys_prof_refcount_exit; static void prof_syscall_enter(struct pt_regs *regs, long id) { - struct syscall_enter_record *rec; + struct syscall_trace_enter *rec; struct syscall_metadata *sys_data; int syscall_nr; int size; @@ -328,9 +331,10 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) /* zero the dead bytes from align to not leak stack to user */ *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; - rec = (struct syscall_enter_record *) raw_data; - tracing_generic_entry_update(&rec->entry, 0, 0); - rec->entry.type = sys_data->enter_id; + rec = (struct syscall_trace_enter *) raw_data; + tracing_generic_entry_update(&rec->ent, 0, 0); + rec->ent.type = sys_data->enter_id; + rec->nr = syscall_nr; syscall_get_arguments(current, regs, 0, sys_data->nb_args, (unsigned long *)&rec->args); perf_tpcounter_event(sys_data->enter_id, 0, 1, rec, size); @@ -379,7 +383,7 @@ void unreg_prof_syscall_enter(char *name) static void prof_syscall_exit(struct pt_regs *regs, long ret) { struct syscall_metadata *sys_data; - struct syscall_exit_record rec; + struct syscall_trace_exit rec; int syscall_nr; syscall_nr = syscall_get_nr(current, regs); @@ -390,8 +394,9 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) if (!sys_data) return; - tracing_generic_entry_update(&rec.entry, 0, 0); - rec.entry.type = sys_data->exit_id; + tracing_generic_entry_update(&rec.ent, 0, 0); + rec.ent.type = sys_data->exit_id; + rec.nr = syscall_nr; rec.ret = syscall_get_return_value(current, regs); perf_tpcounter_event(sys_data->exit_id, 0, 1, &rec, sizeof(rec)); -- cgit v0.10.2 From 10a5b66f625904ad5a2867cf7a28073e1236ff32 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Wed, 19 Aug 2009 15:53:05 +0800 Subject: tracing/syscalls: Add fields format for exit events Add "format" file for syscall exit events: # cat events/syscalls/sys_exit_open/format name: sys_exit_open ID: 344 format: field:unsigned short common_type; offset:0; size:2; field:unsigned char common_flags; offset:2; size:1; field:unsigned char common_preempt_count; offset:3; size:1; field:int common_pid; offset:4; size:4; field:int common_tgid; offset:8; size:4; field:int nr; offset:12; size:4; field:unsigned long ret; offset:16; size:4; Signed-off-by: Li Zefan Cc: Jason Baron Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4A8BAF61.3060307@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 87d06c1..8d57f77 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -189,7 +189,7 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \ .system = "syscalls", \ .event = &event_syscall_enter, \ .raw_init = init_enter_##sname, \ - .show_format = ftrace_format_syscall, \ + .show_format = syscall_enter_format, \ .regfunc = reg_event_syscall_enter, \ .unregfunc = unreg_event_syscall_enter, \ .data = "sys"#sname, \ @@ -225,6 +225,7 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \ .system = "syscalls", \ .event = &event_syscall_exit, \ .raw_init = init_exit_##sname, \ + .show_format = syscall_exit_format, \ .regfunc = reg_event_syscall_exit, \ .unregfunc = unreg_event_syscall_exit, \ .data = "sys"#sname, \ diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 0cb0362..5ce85d7 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -55,8 +55,10 @@ extern int reg_event_syscall_enter(void *ptr); extern void unreg_event_syscall_enter(void *ptr); extern int reg_event_syscall_exit(void *ptr); extern void unreg_event_syscall_exit(void *ptr); -extern int -ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s); +extern int syscall_enter_format(struct ftrace_event_call *call, + struct trace_seq *s); +extern int syscall_exit_format(struct ftrace_event_call *call, + struct trace_seq *s); enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags); enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags); #endif diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index d10daf0..7336b6c 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -97,7 +97,7 @@ extern char *__bad_type_size(void); __bad_type_size() : \ #type, #name, offsetof(typeof(trace), name), sizeof(trace.name) -int ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s) +int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) { int i; int nr; @@ -149,6 +149,22 @@ int ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s) return ret; } +int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s) +{ + int ret; + struct syscall_trace_exit trace; + + ret = trace_seq_printf(s, + "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" + "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n", + SYSCALL_FIELD(int, nr), + SYSCALL_FIELD(unsigned long, ret)); + if (!ret) + return 0; + + return trace_seq_printf(s, "\nprint fmt: \"0x%%lx\", REC->ret\n"); +} + void ftrace_syscall_enter(struct pt_regs *regs, long id) { struct syscall_trace_enter *entry; -- cgit v0.10.2 From 14be96c9716cb8c46dca94bd890defd7856e0734 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Wed, 19 Aug 2009 15:53:52 +0800 Subject: tracing/events: Add ftrace_event_call param to define_fields() This parameter is needed by syscall events to add define_fields() handler. Signed-off-by: Li Zefan Cc: Jason Baron Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4A8BAF90.6060801@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 189806b..35b3a4a 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -118,7 +118,7 @@ struct ftrace_event_call { int (*raw_init)(void); int (*show_format)(struct ftrace_event_call *call, struct trace_seq *s); - int (*define_fields)(void); + int (*define_fields)(struct ftrace_event_call *); struct list_head fields; int filter_active; struct event_filter *filter; diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index b250b06..4e81c9b 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -294,10 +294,9 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ #undef TRACE_EVENT #define TRACE_EVENT(call, proto, args, tstruct, func, print) \ int \ -ftrace_define_fields_##call(void) \ +ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ { \ struct ftrace_raw_##call field; \ - struct ftrace_event_call *event_call = &event_##call; \ int ret; \ \ __common_field(int, type, 1); \ diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index b568ade..af8fb8e 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -941,7 +941,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, id); if (call->define_fields) { - ret = call->define_fields(); + ret = call->define_fields(call); if (ret < 0) { pr_warning("Could not initialize trace point" " events/%s\n", call->name); diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index 956d4bc..cf2c752 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c @@ -119,7 +119,7 @@ ftrace_format_##call(struct ftrace_event_call *unused, \ #undef TRACE_EVENT_FORMAT #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ -int ftrace_define_fields_##call(void); \ +int ftrace_define_fields_##call(struct ftrace_event_call *event_call); \ static int ftrace_raw_init_event_##call(void); \ \ struct ftrace_event_call __used \ @@ -184,9 +184,8 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ #undef TRACE_EVENT_FORMAT #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ int \ -ftrace_define_fields_##call(void) \ +ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ { \ - struct ftrace_event_call *event_call = &event_##call; \ struct args field; \ int ret; \ \ -- cgit v0.10.2 From e647d6b314266adb904d4b84973eda0afa856946 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Wed, 19 Aug 2009 15:54:32 +0800 Subject: tracing/events: Add trace_define_common_fields() Extract duplicate code. Also prepare for the later patch. Signed-off-by: Li Zefan Cc: Jason Baron Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4A8BAFB8.1010304@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 35b3a4a..427cbae 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -142,6 +142,7 @@ extern int filter_current_check_discard(struct ftrace_event_call *call, extern int trace_define_field(struct ftrace_event_call *call, char *type, char *name, int offset, int size, int is_signed); +extern int trace_define_common_fields(struct ftrace_event_call *call); #define is_signed_type(type) (((type)(-1)) < 0) @@ -166,11 +167,4 @@ do { \ __trace_printk(ip, fmt, ##args); \ } while (0) -#define __common_field(type, item, is_signed) \ - ret = trace_define_field(event_call, #type, "common_" #item, \ - offsetof(typeof(field.ent), item), \ - sizeof(field.ent.item), is_signed); \ - if (ret) \ - return ret; - #endif /* _LINUX_FTRACE_EVENT_H */ diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 4e81c9b..1274002 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -299,11 +299,9 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ struct ftrace_raw_##call field; \ int ret; \ \ - __common_field(int, type, 1); \ - __common_field(unsigned char, flags, 0); \ - __common_field(unsigned char, preempt_count, 0); \ - __common_field(int, pid, 1); \ - __common_field(int, tgid, 1); \ + ret = trace_define_common_fields(event_call); \ + if (ret) \ + return ret; \ \ tstruct; \ \ diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index af8fb8e..9c7ecfb 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -62,6 +62,28 @@ err: } EXPORT_SYMBOL_GPL(trace_define_field); +#define __common_field(type, item) \ + ret = trace_define_field(call, #type, "common_" #item, \ + offsetof(typeof(ent), item), \ + sizeof(ent.item), \ + is_signed_type(type)); \ + if (ret) \ + return ret; + +int trace_define_common_fields(struct ftrace_event_call *call) +{ + int ret; + struct trace_entry ent; + + __common_field(unsigned short, type); + __common_field(unsigned char, flags); + __common_field(unsigned char, preempt_count); + __common_field(int, pid); + __common_field(int, tgid); + + return ret; +} + #ifdef CONFIG_MODULES static void trace_destroy_fields(struct ftrace_event_call *call) diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index cf2c752..7087530 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c @@ -189,11 +189,9 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ struct args field; \ int ret; \ \ - __common_field(unsigned char, type, 0); \ - __common_field(unsigned char, flags, 0); \ - __common_field(unsigned char, preempt_count, 0); \ - __common_field(int, pid, 1); \ - __common_field(int, tgid, 1); \ + ret = trace_define_common_fields(event_call); \ + if (ret) \ + return ret; \ \ tstruct; \ \ -- cgit v0.10.2 From 540b7b8d65575c80162f2a0f38e1d313c92a6042 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Wed, 19 Aug 2009 15:54:51 +0800 Subject: tracing/syscalls: Add filtering support Add filtering support for syscall events: # echo 'mode == 0666' > events/syscalls/sys_enter_open # echo 'ret == 0' > events/syscalls/sys_exit_open # echo 1 > events/syscalls/sys_enter_open # echo 1 > events/syscalls/sys_exit_open # cat trace ... modprobe-3084 [001] 117.463140: sys_open(filename: 917d3e8, flags: 0, mode: 1b6) modprobe-3084 [001] 117.463176: sys_open -> 0x0 less-3086 [001] 117.510455: sys_open(filename: 9c6bdb8, flags: 8000, mode: 1b6) sendmail-2574 [001] 122.145840: sys_open(filename: b807a365, flags: 0, mode: 1b6) ... Signed-off-by: Li Zefan Cc: Jason Baron Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4A8BAFCB.1040006@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 427cbae..df5b085 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -140,8 +140,9 @@ extern int filter_current_check_discard(struct ftrace_event_call *call, void *rec, struct ring_buffer_event *event); -extern int trace_define_field(struct ftrace_event_call *call, char *type, - char *name, int offset, int size, int is_signed); +extern int trace_define_field(struct ftrace_event_call *call, + const char *type, const char *name, + int offset, int size, int is_signed); extern int trace_define_common_fields(struct ftrace_event_call *call); #define is_signed_type(type) (((type)(-1)) < 0) diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 8d57f77..f124c89 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -190,6 +190,7 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \ .event = &event_syscall_enter, \ .raw_init = init_enter_##sname, \ .show_format = syscall_enter_format, \ + .define_fields = syscall_enter_define_fields, \ .regfunc = reg_event_syscall_enter, \ .unregfunc = unreg_event_syscall_enter, \ .data = "sys"#sname, \ @@ -226,6 +227,7 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \ .event = &event_syscall_exit, \ .raw_init = init_exit_##sname, \ .show_format = syscall_exit_format, \ + .define_fields = syscall_exit_define_fields, \ .regfunc = reg_event_syscall_exit, \ .unregfunc = unreg_event_syscall_exit, \ .data = "sys"#sname, \ @@ -233,6 +235,8 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \ } #define SYSCALL_METADATA(sname, nb) \ + SYSCALL_TRACE_ENTER_EVENT(sname); \ + SYSCALL_TRACE_EXIT_EVENT(sname); \ static const struct syscall_metadata __used \ __attribute__((__aligned__(4))) \ __attribute__((section("__syscalls_metadata"))) \ @@ -241,20 +245,22 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \ .nb_args = nb, \ .types = types_##sname, \ .args = args_##sname, \ - }; \ - SYSCALL_TRACE_ENTER_EVENT(sname); \ - SYSCALL_TRACE_EXIT_EVENT(sname); + .enter_event = &event_enter_##sname, \ + .exit_event = &event_exit_##sname, \ + }; #define SYSCALL_DEFINE0(sname) \ + SYSCALL_TRACE_ENTER_EVENT(_##sname); \ + SYSCALL_TRACE_EXIT_EVENT(_##sname); \ static const struct syscall_metadata __used \ __attribute__((__aligned__(4))) \ __attribute__((section("__syscalls_metadata"))) \ __syscall_meta_##sname = { \ .name = "sys_"#sname, \ .nb_args = 0, \ + .enter_event = &event_enter__##sname, \ + .exit_event = &event_exit__##sname, \ }; \ - SYSCALL_TRACE_ENTER_EVENT(_##sname); \ - SYSCALL_TRACE_EXIT_EVENT(_##sname); \ asmlinkage long sys_##sname(void) #else #define SYSCALL_DEFINE0(name) asmlinkage long sys_##name(void) diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 5ce85d7..9661dd4 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -34,6 +34,8 @@ DECLARE_TRACE_WITH_CALLBACK(syscall_exit, * @args: list of args as strings (args[i] matches types[i]) * @enter_id: associated ftrace enter event id * @exit_id: associated ftrace exit event id + * @enter_event: associated syscall_enter trace event + * @exit_event: associated syscall_exit trace event */ struct syscall_metadata { const char *name; @@ -42,6 +44,9 @@ struct syscall_metadata { const char **args; int enter_id; int exit_id; + + struct ftrace_event_call *enter_event; + struct ftrace_event_call *exit_event; }; #ifdef CONFIG_FTRACE_SYSCALLS @@ -59,6 +64,8 @@ extern int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s); extern int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s); +extern int syscall_enter_define_fields(struct ftrace_event_call *call); +extern int syscall_exit_define_fields(struct ftrace_event_call *call); enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags); enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags); #endif diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 9c7ecfb..79d3520 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -27,8 +27,8 @@ DEFINE_MUTEX(event_mutex); LIST_HEAD(ftrace_events); -int trace_define_field(struct ftrace_event_call *call, char *type, - char *name, int offset, int size, int is_signed) +int trace_define_field(struct ftrace_event_call *call, const char *type, + const char *name, int offset, int size, int is_signed) { struct ftrace_event_field *field; @@ -83,6 +83,7 @@ int trace_define_common_fields(struct ftrace_event_call *call) return ret; } +EXPORT_SYMBOL_GPL(trace_define_common_fields); #ifdef CONFIG_MODULES diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 7336b6c..28e4dae 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -165,6 +165,49 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s) return trace_seq_printf(s, "\nprint fmt: \"0x%%lx\", REC->ret\n"); } +int syscall_enter_define_fields(struct ftrace_event_call *call) +{ + struct syscall_trace_enter trace; + struct syscall_metadata *meta; + int ret; + int nr; + int i; + int offset = offsetof(typeof(trace), args); + + nr = syscall_name_to_nr(call->data); + meta = syscall_nr_to_meta(nr); + + if (!meta) + return 0; + + ret = trace_define_common_fields(call); + if (ret) + return ret; + + for (i = 0; i < meta->nb_args; i++) { + ret = trace_define_field(call, meta->types[i], + meta->args[i], offset, + sizeof(unsigned long), 0); + offset += sizeof(unsigned long); + } + + return ret; +} + +int syscall_exit_define_fields(struct ftrace_event_call *call) +{ + struct syscall_trace_exit trace; + int ret; + + ret = trace_define_common_fields(call); + if (ret) + return ret; + + ret = trace_define_field(call, SYSCALL_FIELD(unsigned long, ret), 0); + + return ret; +} + void ftrace_syscall_enter(struct pt_regs *regs, long id) { struct syscall_trace_enter *entry; @@ -192,8 +235,8 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id) entry->nr = syscall_nr; syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args); - trace_current_buffer_unlock_commit(event, 0, 0); - trace_wake_up(); + if (!filter_current_check_discard(sys_data->enter_event, entry, event)) + trace_current_buffer_unlock_commit(event, 0, 0); } void ftrace_syscall_exit(struct pt_regs *regs, long ret) @@ -220,8 +263,8 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret) entry->nr = syscall_nr; entry->ret = syscall_get_return_value(current, regs); - trace_current_buffer_unlock_commit(event, 0, 0); - trace_wake_up(); + if (!filter_current_check_discard(sys_data->exit_event, entry, event)) + trace_current_buffer_unlock_commit(event, 0, 0); } int reg_event_syscall_enter(void *ptr) -- cgit v0.10.2 From 474e09ca017bd0f6e9bf41af643364a21bc27f43 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 19 Aug 2009 14:18:53 +0100 Subject: ASoC: Provide default set_bias_level() implementation If the CODEC does not provide a set_bias_level() then update the bias_level variable for it since other parts of the system expect that to be maintained. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8846131..5cfc909 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -148,8 +148,12 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, if (card->set_bias_level) ret = card->set_bias_level(card, level); - if (ret == 0 && codec->set_bias_level) - ret = codec->set_bias_level(codec, level); + if (ret == 0) { + if (codec->set_bias_level) + ret = codec->set_bias_level(codec, level); + else + codec->bias_level = level; + } return ret; } -- cgit v0.10.2 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 diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt index 1c0c82c..23c995e 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 v0.10.2 From 2bfb1070ba1fdb8cbc2b0b9ff61a3b0701ab40de Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Fri, 14 Aug 2009 16:13:12 +0400 Subject: ieee802154: add a sysfs representation of WPAN master devices Add a sysfs/in-kernel representation of LR-WPAN master devices. Signed-off-by: Dmitry Eremin-Solenikov diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h new file mode 100644 index 0000000..547b1e2 --- /dev/null +++ b/include/net/wpan-phy.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007, 2008, 2009 Siemens AG + * + * 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 published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Dmitry Eremin-Solenikov + */ + +#ifndef WPAN_PHY_H +#define WPAN_PHY_H + +#include +#include + +struct wpan_phy { + struct mutex pib_lock; + + /* + * This is a PIB acording to 802.15.4-2006. + * We do not provide timing-related variables, as they + * aren't used outside of driver + */ + u8 current_channel; + u8 current_page; + u32 channels_supported; + u8 transmit_power; + u8 cca_mode; + + struct device dev; + int idx; + + char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); +}; + +struct wpan_phy *wpan_phy_alloc(size_t priv_size); +int wpan_phy_register(struct device *parent, struct wpan_phy *phy); +void wpan_phy_unregister(struct wpan_phy *phy); +void wpan_phy_free(struct wpan_phy *phy); + +static inline void *wpan_phy_priv(struct wpan_phy *phy) +{ + BUG_ON(!phy); + return &phy->priv; +} + +struct wpan_phy *wpan_phy_find(const char *str); +static inline const char *wpan_phy_name(struct wpan_phy *phy) +{ + return dev_name(&phy->dev); +} +#endif diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index f99338a..4068a9f 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o +obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o wpan-class.o nl802154-y := netlink.o nl_policy.o af_802154-y := af_ieee802154.o raw.o dgram.o diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c new file mode 100644 index 0000000..f306604 --- /dev/null +++ b/net/ieee802154/wpan-class.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2007, 2008, 2009 Siemens AG + * + * 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 published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include + +#include + +#define MASTER_SHOW_COMPLEX(name, format_string, args...) \ +static ssize_t name ## _show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); \ + int ret; \ + \ + mutex_lock(&phy->pib_lock); \ + ret = sprintf(buf, format_string "\n", args); \ + mutex_unlock(&phy->pib_lock); \ + return ret; \ +} + +#define MASTER_SHOW(field, format_string) \ + MASTER_SHOW_COMPLEX(field, format_string, phy->field) + +MASTER_SHOW(current_channel, "%d"); +MASTER_SHOW(current_page, "%d"); +MASTER_SHOW(channels_supported, "%#x"); +MASTER_SHOW_COMPLEX(transmit_power, "%d +- %d dB", + ((signed char) (phy->transmit_power << 2)) >> 2, + (phy->transmit_power >> 6) ? (phy->transmit_power >> 6) * 3 : 1 ); +MASTER_SHOW(cca_mode, "%d"); + +static struct device_attribute pmib_attrs[] = { + __ATTR_RO(current_channel), + __ATTR_RO(current_page), + __ATTR_RO(channels_supported), + __ATTR_RO(transmit_power), + __ATTR_RO(cca_mode), + {}, +}; + +static void wpan_phy_release(struct device *d) +{ + struct wpan_phy *phy = container_of(d, struct wpan_phy, dev); + kfree(phy); +} + +static struct class wpan_phy_class = { + .name = "ieee802154", + .dev_release = wpan_phy_release, + .dev_attrs = pmib_attrs, +}; + +static DEFINE_MUTEX(wpan_phy_mutex); +static int wpan_phy_idx; + +static int wpan_phy_match(struct device *dev, void *data) +{ + return !strcmp(dev_name(dev), (const char *)data); +} + +struct wpan_phy *wpan_phy_find(const char *str) +{ + struct device *dev; + + if (WARN_ON(!str)) + return NULL; + + dev = class_find_device(&wpan_phy_class, NULL, + (void *)str, wpan_phy_match); + if (!dev) + return NULL; + + return container_of(dev, struct wpan_phy, dev); +} +EXPORT_SYMBOL(wpan_phy_find); + +static int wpan_phy_idx_valid(int idx) +{ + return idx >= 0; +} + +struct wpan_phy *wpan_phy_alloc(size_t priv_size) +{ + struct wpan_phy *phy = kzalloc(sizeof(*phy) + priv_size, + GFP_KERNEL); + + mutex_lock(&wpan_phy_mutex); + phy->idx = wpan_phy_idx++; + if (unlikely(!wpan_phy_idx_valid(phy->idx))) { + wpan_phy_idx--; + mutex_unlock(&wpan_phy_mutex); + kfree(phy); + return NULL; + } + mutex_unlock(&wpan_phy_mutex); + + mutex_init(&phy->pib_lock); + + device_initialize(&phy->dev); + dev_set_name(&phy->dev, "wpan-phy%d", phy->idx); + + phy->dev.class = &wpan_phy_class; + + return phy; +} +EXPORT_SYMBOL(wpan_phy_alloc); + +int wpan_phy_register(struct device *parent, struct wpan_phy *phy) +{ + phy->dev.parent = parent; + + return device_add(&phy->dev); +} +EXPORT_SYMBOL(wpan_phy_register); + +void wpan_phy_unregister(struct wpan_phy *phy) +{ + device_del(&phy->dev); +} +EXPORT_SYMBOL(wpan_phy_unregister); + +void wpan_phy_free(struct wpan_phy *phy) +{ + put_device(&phy->dev); +} +EXPORT_SYMBOL(wpan_phy_free); + +static int __init wpan_phy_class_init(void) +{ + return class_register(&wpan_phy_class); +} +subsys_initcall(wpan_phy_class_init); + +static void __exit wpan_phy_class_exit(void) +{ + class_unregister(&wpan_phy_class); +} +module_exit(wpan_phy_class_exit); + +MODULE_DESCRIPTION("IEEE 802.15.4 device class"); +MODULE_LICENSE("GPL v2"); + -- cgit v0.10.2 From 81f9510381ee43205564063f2e8650672b11d453 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 19 Aug 2009 18:56:57 +0400 Subject: fakehard: add binding to wpan-phy device Make fakehard create and maintain wpan-phy node, thus representing it's phy in the sysfs. Signed-off-by: Dmitry Eremin-Solenikov diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 262536f..22a93bc 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -30,6 +30,12 @@ #include #include #include +#include + +struct wpan_phy *net_to_phy(struct net_device *dev) +{ + return container_of(dev->dev.parent, struct wpan_phy, dev); +} /** * fake_get_pan_id - Retrieve the PAN ID of the device. @@ -115,6 +121,12 @@ static u8 fake_get_bsn(struct net_device *dev) static int fake_assoc_req(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 cap) { + struct wpan_phy *phy = net_to_phy(dev); + + mutex_lock(&phy->pib_lock); + phy->current_channel = channel; + mutex_unlock(&phy->pib_lock); + /* We simply emulate it here */ return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev), IEEE802154_SUCCESS); @@ -183,6 +195,12 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 coord_realign) { + struct wpan_phy *phy = net_to_phy(dev); + + mutex_lock(&phy->pib_lock); + phy->current_channel = channel; + mutex_unlock(&phy->pib_lock); + /* We don't emulate beacons here at all, so START should fail */ ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER); return 0; @@ -290,6 +308,14 @@ static const struct net_device_ops fake_ops = { .ndo_set_mac_address = ieee802154_fake_mac_addr, }; +static void ieee802154_fake_destruct(struct net_device *dev) +{ + struct wpan_phy *phy = net_to_phy(dev); + + wpan_phy_unregister(phy); + free_netdev(dev); + wpan_phy_free(phy); +} static void ieee802154_fake_setup(struct net_device *dev) { @@ -302,22 +328,34 @@ static void ieee802154_fake_setup(struct net_device *dev) dev->type = ARPHRD_IEEE802154; dev->flags = IFF_NOARP | IFF_BROADCAST; dev->watchdog_timeo = 0; + dev->destructor = ieee802154_fake_destruct; } static int __devinit ieee802154fake_probe(struct platform_device *pdev) { - struct net_device *dev = - alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup); + struct net_device *dev; + struct wpan_phy *phy = wpan_phy_alloc(0); int err; - if (!dev) + if (!phy) + return -ENOMEM; + + dev = alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup); + if (!dev) { + wpan_phy_free(phy); return -ENOMEM; + } + + phy->dev.platform_data = dev; memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef", dev->addr_len); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + phy->channels_supported = (1 << 27) - 1; + phy->transmit_power = 0xbf; + dev->netdev_ops = &fake_ops; dev->ml_priv = &fake_mlme; @@ -331,15 +369,18 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev) goto out; } - SET_NETDEV_DEV(dev, &pdev->dev); + SET_NETDEV_DEV(dev, &phy->dev); platform_set_drvdata(pdev, dev); + err = wpan_phy_register(&pdev->dev, phy); + if (err) + goto out; + err = register_netdev(dev); if (err < 0) goto out; - dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n"); return 0; @@ -352,7 +393,6 @@ static int __devexit ieee802154fake_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); unregister_netdev(dev); - free_netdev(dev); return 0; } -- cgit v0.10.2 From 16eea493da563b5a3356a77c6d8776dffc29d3b6 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 19 Aug 2009 19:32:24 +0400 Subject: ieee802154: add support for channel pages from IEEE 802.15.4-2006 IEEE 802.15.4-2006 adds new concept: channel pages, which can contain several channels. Add support for channel pages in the API and in the fakehard driver. Signed-off-by: Dmitry Eremin-Solenikov diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 22a93bc..c1c9697 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -119,12 +119,13 @@ static u8 fake_get_bsn(struct net_device *dev) * 802.15.4-2006 document. */ static int fake_assoc_req(struct net_device *dev, - struct ieee802154_addr *addr, u8 channel, u8 cap) + struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap) { struct wpan_phy *phy = net_to_phy(dev); mutex_lock(&phy->pib_lock); phy->current_channel = channel; + phy->current_page = page; mutex_unlock(&phy->pib_lock); /* We simply emulate it here */ @@ -191,7 +192,7 @@ static int fake_disassoc_req(struct net_device *dev, * document, with 7.3.8 describing coordinator realignment. */ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, - u8 channel, + u8 channel, u8 page, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 coord_realign) { @@ -199,6 +200,7 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, mutex_lock(&phy->pib_lock); phy->current_channel = channel; + phy->current_page = page; mutex_unlock(&phy->pib_lock); /* We don't emulate beacons here at all, so START should fail */ @@ -222,11 +224,11 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document. */ static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, - u8 duration) + u8 page, u8 duration) { u8 edl[27] = {}; return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type, - channels, + channels, page, type == IEEE802154_MAC_SCAN_ED ? edl : NULL); } diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h index 9a1af5f..b7d9435 100644 --- a/include/linux/nl802154.h +++ b/include/linux/nl802154.h @@ -64,6 +64,8 @@ enum { IEEE802154_ATTR_COORD_REALIGN, IEEE802154_ATTR_SEC, + IEEE802154_ATTR_PAGE, + __IEEE802154_ATTR_MAX, }; diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index e2506af..5dc6a61 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -80,7 +80,7 @@ static inline int mac_cb_type(struct sk_buff *skb) struct ieee802154_mlme_ops { int (*assoc_req)(struct net_device *dev, struct ieee802154_addr *addr, - u8 channel, u8 cap); + u8 channel, u8 page, u8 cap); int (*assoc_resp)(struct net_device *dev, struct ieee802154_addr *addr, u16 short_addr, u8 status); @@ -89,10 +89,10 @@ struct ieee802154_mlme_ops { u8 reason); int (*start_req)(struct net_device *dev, struct ieee802154_addr *addr, - u8 channel, u8 bcn_ord, u8 sf_ord, + u8 channel, u8 page, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 coord_realign); int (*scan_req)(struct net_device *dev, - u8 type, u32 channels, u8 duration); + u8 type, u32 channels, u8 page, u8 duration); /* * FIXME: these should become the part of PIB/MIB interface. diff --git a/include/net/nl802154.h b/include/net/nl802154.h index e554ecd..99d2ba1 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -95,7 +95,7 @@ int ieee802154_nl_disassoc_confirm(struct net_device *dev, * Note: This API does not permit the return of an active scan result. */ int ieee802154_nl_scan_confirm(struct net_device *dev, - u8 status, u8 scan_type, u32 unscanned, + u8 status, u8 scan_type, u32 unscanned, u8 page, u8 *edl/*, struct list_head *pan_desc_list */); /** diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index cd0567f..2106ecb 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -232,7 +232,7 @@ nla_put_failure: EXPORT_SYMBOL(ieee802154_nl_beacon_indic); int ieee802154_nl_scan_confirm(struct net_device *dev, - u8 status, u8 scan_type, u32 unscanned, + u8 status, u8 scan_type, u32 unscanned, u8 page, u8 *edl/* , struct list_head *pan_desc_list */) { struct sk_buff *msg; @@ -251,6 +251,7 @@ int ieee802154_nl_scan_confirm(struct net_device *dev, NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type); NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned); + NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page); if (edl) NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); @@ -349,6 +350,7 @@ static int ieee802154_associate_req(struct sk_buff *skb, { struct net_device *dev; struct ieee802154_addr addr; + u8 page; int ret = -EINVAL; if (!info->attrs[IEEE802154_ATTR_CHANNEL] || @@ -374,8 +376,14 @@ static int ieee802154_associate_req(struct sk_buff *skb, } addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); + if (info->attrs[IEEE802154_ATTR_PAGE]) + page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); + else + page = 0; + ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), + page, nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); dev_put(dev); @@ -458,6 +466,7 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) struct ieee802154_addr addr; u8 channel, bcn_ord, sf_ord; + u8 page; int pan_coord, blx, coord_realign; int ret; @@ -488,13 +497,19 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); + if (info->attrs[IEEE802154_ATTR_PAGE]) + page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); + else + page = 0; + + if (addr.short_addr == IEEE802154_ADDR_BROADCAST) { ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS); dev_put(dev); return -EINVAL; } - ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, + ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page, bcn_ord, sf_ord, pan_coord, blx, coord_realign); dev_put(dev); @@ -508,6 +523,7 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) u8 type; u32 channels; u8 duration; + u8 page; if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || !info->attrs[IEEE802154_ATTR_CHANNELS] || @@ -522,7 +538,13 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); - ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, + if (info->attrs[IEEE802154_ATTR_PAGE]) + page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); + else + page = 0; + + + ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page, duration); dev_put(dev); diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c index 83cb4cc..2363ebe 100644 --- a/net/ieee802154/nl_policy.c +++ b/net/ieee802154/nl_policy.c @@ -33,6 +33,7 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { [IEEE802154_ATTR_HW_ADDR] = { .type = NLA_HW_ADDR, }, [IEEE802154_ATTR_PAN_ID] = { .type = NLA_U16, }, [IEEE802154_ATTR_CHANNEL] = { .type = NLA_U8, }, + [IEEE802154_ATTR_PAGE] = { .type = NLA_U8, }, [IEEE802154_ATTR_COORD_SHORT_ADDR] = { .type = NLA_U16, }, [IEEE802154_ATTR_COORD_HW_ADDR] = { .type = NLA_HW_ADDR, }, [IEEE802154_ATTR_COORD_PAN_ID] = { .type = NLA_U16, }, -- cgit v0.10.2 From 929122cdd5d4c344e59f9b55f870a8fcf7aa0d27 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Fri, 14 Aug 2009 20:00:20 +0400 Subject: Drop ARPHRD_IEEE802154_PHY There are not maste devices in mac802154 anymore, so drop ARPHRD_IEEE802154_PHY definition. Signed-off-by: Dmitry Eremin-Solenikov diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index b554300..282eb37 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -87,7 +87,6 @@ #define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ #define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ #define ARPHRD_IEEE802154 804 -#define ARPHRD_IEEE802154_PHY 805 #define ARPHRD_PHONET 820 /* PhoNet media type */ #define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */ diff --git a/net/core/dev.c b/net/core/dev.c index 09fb03f..4b83789 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -269,7 +269,7 @@ static const unsigned short netdev_lock_type[] = ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, - ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154, ARPHRD_IEEE802154_PHY, + ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154, ARPHRD_VOID, ARPHRD_NONE}; static const char *const netdev_lock_name[] = @@ -287,7 +287,7 @@ static const char *const netdev_lock_name[] = "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211", "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", - "_xmit_PHONET_PIPE", "_xmit_IEEE802154", "_xmit_IEEE802154_PHY", + "_xmit_PHONET_PIPE", "_xmit_IEEE802154", "_xmit_VOID", "_xmit_NONE"}; static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index d504c34..cd949d5 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c @@ -147,9 +147,7 @@ static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg, dev_load(sock_net(sk), ifr.ifr_name); dev = dev_get_by_name(sock_net(sk), ifr.ifr_name); - if ((dev->type == ARPHRD_IEEE802154 || - dev->type == ARPHRD_IEEE802154_PHY) && - dev->netdev_ops->ndo_do_ioctl) + if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl) ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd); if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq))) diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index 60dee69..4681501 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c @@ -74,8 +74,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len) goto out; } - if (dev->type != ARPHRD_IEEE802154_PHY && - dev->type != ARPHRD_IEEE802154) { + if (dev->type != ARPHRD_IEEE802154) { err = -ENODEV; goto out_put; } -- cgit v0.10.2 From f8bae4caaaf56c391f3e2380dd7105e765414178 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 19 Aug 2009 19:31:46 +0100 Subject: ALSA: Restore support for DMAless DAIs on PXA Used for applications such as direct bluetooth connections on smartphones which don't go via the CPU. This used to be supported before the refactoring to share code but this check was removed during that move. Signed-off-by: Mark Brown diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c index 6205f37..743ac6a 100644 --- a/sound/arm/pxa2xx-pcm-lib.c +++ b/sound/arm/pxa2xx-pcm-lib.c @@ -136,6 +136,9 @@ int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) { struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; + if (!prtd || !prtd->params) + return 0; + DCSR(prtd->dma_ch) &= ~DCSR_RUN; DCSR(prtd->dma_ch) = 0; DCMD(prtd->dma_ch) = 0; -- cgit v0.10.2 From 886f9fe68310168358f55028a03553ae154dfeb6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 19 Aug 2009 13:55:55 -0700 Subject: ppp_generic: Help GCC see that 'flen' is always initialized. It's too stupid to see that we always set flen to something before we use it in ppp_mp_explode(): drivers/net/ppp_generic.c: In function 'ppp_push': drivers/net/ppp_generic.c:1314: warning: 'flen' may be used uninitialized in this function drivers/net/ppp_generic.c:1314: note: 'flen' was declared here This started warning after commit a53a8b56827cc429c6d9f861ad558beeb5f6103f ("ppp: fix lost fragments in ppp_mp_explode() (resubmit)") So just put an explicit unconditional initialization there to hush it up. Signed-off-by: David S. Miller diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 7dd0868..35be2e8 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1431,6 +1431,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) *otherwise divide it according to the speed *of the channel we are going to transmit on */ + flen = len; if (nfree > 0) { if (pch->speed == 0) { flen = totlen/nfree ; -- cgit v0.10.2 From 96c61cbd0f30496bfa57ed80f7131a57aea3e4de Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 19 Aug 2009 18:12:21 -0400 Subject: SUNRPC: Fix a typo in cache_pipefs_files We want the channel to be a regular file, so that we don't need to supply rpc_pipe_ops. Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 8dd8153..3fdacaf 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -887,7 +887,7 @@ static const struct rpc_filelist cache_pipefs_files[3] = { [0] = { .name = "channel", .i_fop = &cache_file_operations_pipefs, - .mode = S_IFIFO|S_IRUSR|S_IWUSR, + .mode = S_IFREG|S_IRUSR|S_IWUSR, }, [1] = { .name = "content", -- cgit v0.10.2 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 diff --git a/Documentation/filesystems/nfs.txt b/Documentation/filesystems/nfs.txt new file mode 100644 index 0000000..f50f26c --- /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 c08813d..ce88537 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 8451598..da7fda6 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 0000000..b4ffd01 --- /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 0000000..76f856e --- /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 0000000..f4d54ba --- /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 0000000..a3f0938 --- /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 fe5a8b4..060022b 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 3fdacaf..7f676bd 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 v0.10.2 From 7d7ea882898f23989209d0359691b356f73240dc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 19 Aug 2009 18:12:34 -0400 Subject: NFS: Use the DNS resolver in the mount code. In the referral code, use it to look up the new server's ip address if the fs_locations attribute contains a hostname. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index ef22ee8..2636c26 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -17,6 +17,7 @@ #include #include "internal.h" #include "nfs4_fs.h" +#include "dns_resolve.h" #define NFSDBG_FACILITY NFSDBG_VFS @@ -95,6 +96,20 @@ static int nfs4_validate_fspath(const struct vfsmount *mnt_parent, return 0; } +static size_t nfs_parse_server_name(char *string, size_t len, + struct sockaddr *sa, size_t salen) +{ + ssize_t ret; + + ret = rpc_pton(string, len, sa, salen); + if (ret == 0) { + ret = nfs_dns_resolve_name(string, len, sa, salen); + if (ret < 0) + ret = 0; + } + return ret; +} + static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, char *page, char *page2, const struct nfs4_fs_location *location) @@ -121,7 +136,8 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) continue; - mountdata->addrlen = rpc_pton(buf->data, buf->len, + mountdata->addrlen = nfs_parse_server_name(buf->data, + buf->len, mountdata->addr, mountdata->addrlen); if (mountdata->addrlen == 0) continue; -- cgit v0.10.2 From f7e86ab92f2198d30828a1a327ad2085e4a7ff7d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 19 Aug 2009 18:13:00 -0400 Subject: SUNRPC: cache must take a reference to the cache detail's module on open() Otherwise we Oops if the module containing the cache detail is removed before all cache readers have closed the file. Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index db7720e..45cdaff 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -836,6 +836,8 @@ static int cache_open(struct inode *inode, struct file *filp, { struct cache_reader *rp = NULL; + if (!cd || !try_module_get(cd->owner)) + return -EACCES; nonseekable_open(inode, filp); if (filp->f_mode & FMODE_READ) { rp = kmalloc(sizeof(*rp), GFP_KERNEL); @@ -879,6 +881,7 @@ static int cache_release(struct inode *inode, struct file *filp, cd->last_close = get_seconds(); atomic_dec(&cd->readers); } + module_put(cd->owner); return 0; } @@ -1215,6 +1218,8 @@ static int content_open(struct inode *inode, struct file *file, { struct handle *han; + if (!cd || !try_module_get(cd->owner)) + return -EACCES; han = __seq_open_private(file, &cache_content_op, sizeof(*han)); if (han == NULL) return -ENOMEM; @@ -1223,6 +1228,29 @@ static int content_open(struct inode *inode, struct file *file, return 0; } +static int content_release(struct inode *inode, struct file *file, + struct cache_detail *cd) +{ + int ret = seq_release_private(inode, file); + module_put(cd->owner); + return ret; +} + +static int open_flush(struct inode *inode, struct file *file, + struct cache_detail *cd) +{ + if (!cd || !try_module_get(cd->owner)) + return -EACCES; + return nonseekable_open(inode, file); +} + +static int release_flush(struct inode *inode, struct file *file, + struct cache_detail *cd) +{ + module_put(cd->owner); + return 0; +} + static ssize_t read_flush(struct file *file, char __user *buf, size_t count, loff_t *ppos, struct cache_detail *cd) @@ -1331,13 +1359,34 @@ static int content_open_procfs(struct inode *inode, struct file *filp) return content_open(inode, filp, cd); } +static int content_release_procfs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = PDE(inode)->data; + + return content_release(inode, filp, cd); +} + static const struct file_operations content_file_operations_procfs = { .open = content_open_procfs, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = content_release_procfs, }; +static int open_flush_procfs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = PDE(inode)->data; + + return open_flush(inode, filp, cd); +} + +static int release_flush_procfs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = PDE(inode)->data; + + return release_flush(inode, filp, cd); +} + static ssize_t read_flush_procfs(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { @@ -1356,9 +1405,10 @@ static ssize_t write_flush_procfs(struct file *filp, } static const struct file_operations cache_flush_operations_procfs = { - .open = nonseekable_open, + .open = open_flush_procfs, .read = read_flush_procfs, .write = write_flush_procfs, + .release = release_flush_procfs, }; static void remove_cache_proc_entries(struct cache_detail *cd) @@ -1503,13 +1553,34 @@ static int content_open_pipefs(struct inode *inode, struct file *filp) return content_open(inode, filp, cd); } +static int content_release_pipefs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = RPC_I(inode)->private; + + return content_release(inode, filp, cd); +} + const struct file_operations content_file_operations_pipefs = { .open = content_open_pipefs, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = content_release_pipefs, }; +static int open_flush_pipefs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = RPC_I(inode)->private; + + return open_flush(inode, filp, cd); +} + +static int release_flush_pipefs(struct inode *inode, struct file *filp) +{ + struct cache_detail *cd = RPC_I(inode)->private; + + return release_flush(inode, filp, cd); +} + static ssize_t read_flush_pipefs(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { @@ -1528,9 +1599,10 @@ static ssize_t write_flush_pipefs(struct file *filp, } const struct file_operations cache_flush_operations_pipefs = { - .open = nonseekable_open, + .open = open_flush_pipefs, .read = read_flush_pipefs, .write = write_flush_pipefs, + .release = release_flush_pipefs, }; int sunrpc_cache_register_pipefs(struct dentry *parent, -- cgit v0.10.2 From e1af88a1ad8f4dea3a2d6c5637d94a3fc3c62994 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 19 Aug 2009 18:04:43 +0200 Subject: nfs: Remove reference to generic_osync_inode from a comment generic_file_direct_write() no longer calls generic_osync_inode() so remove the comment. CC: linux-nfs@vger.kernel.org CC: Neil Brown CC: "J. Bruce Fields" Signed-off-by: Jan Kara Signed-off-by: Trond Myklebust diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index e4e089a..6c32100 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -934,9 +934,6 @@ out: * back into its cache. We let the server do generic write * parameter checking and report problems. * - * We also avoid an unnecessary invocation of generic_osync_inode(), - * as it is fairly meaningless to sync the metadata of an NFS file. - * * We eliminate local atime updates, see direct read above. * * We avoid unnecessary page cache invalidations for normal cached -- cgit v0.10.2 From 4e4ed83be6a64c8c9fe69c77f37a26bb62ed21f7 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 20 Aug 2009 17:54:16 +1000 Subject: crypto: fips - Depend on ansi_cprng What about something like this? It defaults the CPRNG to m and makes FIPS dependent on the CPRNG. That way you get a module build by default, but you can change it to y manually during config and still satisfy the dependency, and if you select N it disables FIPS as well. I rather like that better than making FIPS a tristate. I just tested it out here and it seems to work well. Let me know what you think Signed-off-by: Neil Horman Signed-off-by: Herbert Xu diff --git a/crypto/Kconfig b/crypto/Kconfig index 1db0995..7623442 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -23,11 +23,13 @@ comment "Crypto core or helper" config CRYPTO_FIPS bool "FIPS 200 compliance" + depends on CRYPTO_ANSI_CPRNG help This options enables the fips boot option which is required if you want to system to operate in a FIPS 200 certification. You should say no unless you know what - this is. + this is. Note that CRYPTO_ANSI_CPRNG is requred if this + option is selected config CRYPTO_ALGAPI tristate @@ -787,12 +789,14 @@ comment "Random Number Generation" config CRYPTO_ANSI_CPRNG tristate "Pseudo Random Number Generation for Cryptographic modules" + default m select CRYPTO_AES select CRYPTO_RNG help This option enables the generic pseudo random number generator for cryptographic modules. Uses the Algorithm specified in - ANSI X9.31 A.2.4 + ANSI X9.31 A.2.4. Not this option must be enabled if CRYPTO_FIPS + is selected source "drivers/crypto/Kconfig" -- cgit v0.10.2 From 36f87a4a29cb8cd291169483079fde34bad4ef16 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Thu, 20 Aug 2009 17:58:04 +1000 Subject: crypto: xcbc - Fix alignment calculation of xcbc_tfm_ctx The alignment calculation of xcbc_tfm_ctx uses alg->cra_alignmask and not alg->cra_alignmask + 1 as it should. This led to frequent crashes during the selftest of xcbc(aes-asm) on x86_64 machines. This patch fixes this. Also we use the alignmask of xcbc and not the alignmask of the underlying algorithm for the alignmnent calculation in xcbc_create now. Signed-off-by: Steffen Klassert Signed-off-by: Herbert Xu diff --git a/crypto/xcbc.c b/crypto/xcbc.c index 1e30b31..bb7b67f 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c @@ -199,6 +199,7 @@ static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb) { struct shash_instance *inst; struct crypto_alg *alg; + unsigned long alignmask; int err; err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH); @@ -228,19 +229,20 @@ static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb) if (err) goto out_free_inst; + alignmask = alg->cra_alignmask | 3; + inst->alg.base.cra_alignmask = alignmask; inst->alg.base.cra_priority = alg->cra_priority; inst->alg.base.cra_blocksize = alg->cra_blocksize; - inst->alg.base.cra_alignmask = alg->cra_alignmask | 3; inst->alg.digestsize = alg->cra_blocksize; inst->alg.descsize = ALIGN(sizeof(struct xcbc_desc_ctx), crypto_tfm_ctx_alignment()) + - (alg->cra_alignmask & + (alignmask & ~(crypto_tfm_ctx_alignment() - 1)) + alg->cra_blocksize * 2; inst->alg.base.cra_ctxsize = ALIGN(sizeof(struct xcbc_tfm_ctx), - alg->cra_alignmask) + + alignmask + 1) + alg->cra_blocksize * 2; inst->alg.base.cra_init = xcbc_init_tfm; inst->alg.base.cra_exit = xcbc_exit_tfm; -- cgit v0.10.2 From bb81b2ddfa194b6d12761a350b5b5985cecae0a9 Mon Sep 17 00:00:00 2001 From: John Linn Date: Thu, 20 Aug 2009 02:52:16 -0700 Subject: net: add Xilinx emac lite device driver This patch adds support for the Xilinx Ethernet Lite device. The soft logic core from Xilinx is typically used on Virtex and Spartan designs attached to either a PowerPC or a Microblaze processor. Signed-off-by: Sadanand M Signed-off-by: John Linn Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 29935a9..bbe77a0 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1926,6 +1926,12 @@ config ATL2 To compile this driver as a module, choose M here. The module will be called atl2. +config XILINX_EMACLITE + tristate "Xilinx 10/100 Ethernet Lite support" + depends on PPC32 || MICROBLAZE + help + This driver supports the 10/100 Ethernet Lite from Xilinx. + source "drivers/net/fs_enet/Kconfig" endif # NET_ETHERNET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index ead8cab..99ae6d7 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -142,6 +142,7 @@ obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o ll_temac-objs := ll_temac_main.o ll_temac_mdio.o obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o +obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o obj-$(CONFIG_QLA3XXX) += qla3xxx.o obj-$(CONFIG_QLGE) += qlge/ diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c new file mode 100755 index 0000000..7e05b40 --- /dev/null +++ b/drivers/net/xilinx_emaclite.c @@ -0,0 +1,1041 @@ +/* + * Xilinx EmacLite Linux driver for the Xilinx Ethernet MAC Lite device. + * + * This is a new flat driver which is based on the original emac_lite + * driver from John Williams . + * + * 2007-2009 (c) Xilinx, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "xilinx_emaclite" + +/* Register offsets for the EmacLite Core */ +#define XEL_TXBUFF_OFFSET 0x0 /* Transmit Buffer */ +#define XEL_GIER_OFFSET 0x07F8 /* GIE Register */ +#define XEL_TSR_OFFSET 0x07FC /* Tx status */ +#define XEL_TPLR_OFFSET 0x07F4 /* Tx packet length */ + +#define XEL_RXBUFF_OFFSET 0x1000 /* Receive Buffer */ +#define XEL_RPLR_OFFSET 0x100C /* Rx packet length */ +#define XEL_RSR_OFFSET 0x17FC /* Rx status */ + +#define XEL_BUFFER_OFFSET 0x0800 /* Next Tx/Rx buffer's offset */ + +/* Global Interrupt Enable Register (GIER) Bit Masks */ +#define XEL_GIER_GIE_MASK 0x80000000 /* Global Enable */ + +/* Transmit Status Register (TSR) Bit Masks */ +#define XEL_TSR_XMIT_BUSY_MASK 0x00000001 /* Tx complete */ +#define XEL_TSR_PROGRAM_MASK 0x00000002 /* Program the MAC address */ +#define XEL_TSR_XMIT_IE_MASK 0x00000008 /* Tx interrupt enable bit */ +#define XEL_TSR_XMIT_ACTIVE_MASK 0x80000000 /* Buffer is active, SW bit + * only. This is not documented + * in the HW spec */ + +/* Define for programming the MAC address into the EmacLite */ +#define XEL_TSR_PROG_MAC_ADDR (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_PROGRAM_MASK) + +/* Receive Status Register (RSR) */ +#define XEL_RSR_RECV_DONE_MASK 0x00000001 /* Rx complete */ +#define XEL_RSR_RECV_IE_MASK 0x00000008 /* Rx interrupt enable bit */ + +/* Transmit Packet Length Register (TPLR) */ +#define XEL_TPLR_LENGTH_MASK 0x0000FFFF /* Tx packet length */ + +/* Receive Packet Length Register (RPLR) */ +#define XEL_RPLR_LENGTH_MASK 0x0000FFFF /* Rx packet length */ + +#define XEL_HEADER_OFFSET 12 /* Offset to length field */ +#define XEL_HEADER_SHIFT 16 /* Shift value for length */ + +/* General Ethernet Definitions */ +#define XEL_ARP_PACKET_SIZE 28 /* Max ARP packet size */ +#define XEL_HEADER_IP_LENGTH_OFFSET 16 /* IP Length Offset */ + + + +#define TX_TIMEOUT (60*HZ) /* Tx timeout is 60 seconds. */ +#define ALIGNMENT 4 + +/* BUFFER_ALIGN(adr) calculates the number of bytes to the next alignment. */ +#define BUFFER_ALIGN(adr) ((ALIGNMENT - ((u32) adr)) % ALIGNMENT) + +/** + * struct net_local - Our private per device data + * @ndev: instance of the network device + * @tx_ping_pong: indicates whether Tx Pong buffer is configured in HW + * @rx_ping_pong: indicates whether Rx Pong buffer is configured in HW + * @next_tx_buf_to_use: next Tx buffer to write to + * @next_rx_buf_to_use: next Rx buffer to read from + * @base_addr: base address of the Emaclite device + * @reset_lock: lock used for synchronization + * @deferred_skb: holds an skb (for transmission at a later time) when the + * Tx buffer is not free + */ +struct net_local { + + struct net_device *ndev; + + bool tx_ping_pong; + bool rx_ping_pong; + u32 next_tx_buf_to_use; + u32 next_rx_buf_to_use; + void __iomem *base_addr; + + spinlock_t reset_lock; + struct sk_buff *deferred_skb; +}; + + +/*************************/ +/* EmacLite driver calls */ +/*************************/ + +/** + * xemaclite_enable_interrupts - Enable the interrupts for the EmacLite device + * @drvdata: Pointer to the Emaclite device private data + * + * This function enables the Tx and Rx interrupts for the Emaclite device along + * with the Global Interrupt Enable. + */ +static void xemaclite_enable_interrupts(struct net_local *drvdata) +{ + u32 reg_data; + + /* Enable the Tx interrupts for the first Buffer */ + reg_data = in_be32(drvdata->base_addr + XEL_TSR_OFFSET); + out_be32(drvdata->base_addr + XEL_TSR_OFFSET, + reg_data | XEL_TSR_XMIT_IE_MASK); + + /* Enable the Tx interrupts for the second Buffer if + * configured in HW */ + if (drvdata->tx_ping_pong != 0) { + reg_data = in_be32(drvdata->base_addr + + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); + out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_TSR_OFFSET, + reg_data | XEL_TSR_XMIT_IE_MASK); + } + + /* Enable the Rx interrupts for the first buffer */ + reg_data = in_be32(drvdata->base_addr + XEL_RSR_OFFSET); + out_be32(drvdata->base_addr + XEL_RSR_OFFSET, + reg_data | XEL_RSR_RECV_IE_MASK); + + /* Enable the Rx interrupts for the second Buffer if + * configured in HW */ + if (drvdata->rx_ping_pong != 0) { + reg_data = in_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_RSR_OFFSET); + out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_RSR_OFFSET, + reg_data | XEL_RSR_RECV_IE_MASK); + } + + /* Enable the Global Interrupt Enable */ + out_be32(drvdata->base_addr + XEL_GIER_OFFSET, XEL_GIER_GIE_MASK); +} + +/** + * xemaclite_disable_interrupts - Disable the interrupts for the EmacLite device + * @drvdata: Pointer to the Emaclite device private data + * + * This function disables the Tx and Rx interrupts for the Emaclite device, + * along with the Global Interrupt Enable. + */ +static void xemaclite_disable_interrupts(struct net_local *drvdata) +{ + u32 reg_data; + + /* Disable the Global Interrupt Enable */ + out_be32(drvdata->base_addr + XEL_GIER_OFFSET, XEL_GIER_GIE_MASK); + + /* Disable the Tx interrupts for the first buffer */ + reg_data = in_be32(drvdata->base_addr + XEL_TSR_OFFSET); + out_be32(drvdata->base_addr + XEL_TSR_OFFSET, + reg_data & (~XEL_TSR_XMIT_IE_MASK)); + + /* Disable the Tx interrupts for the second Buffer + * if configured in HW */ + if (drvdata->tx_ping_pong != 0) { + reg_data = in_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_TSR_OFFSET); + out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_TSR_OFFSET, + reg_data & (~XEL_TSR_XMIT_IE_MASK)); + } + + /* Disable the Rx interrupts for the first buffer */ + reg_data = in_be32(drvdata->base_addr + XEL_RSR_OFFSET); + out_be32(drvdata->base_addr + XEL_RSR_OFFSET, + reg_data & (~XEL_RSR_RECV_IE_MASK)); + + /* Disable the Rx interrupts for the second buffer + * if configured in HW */ + if (drvdata->rx_ping_pong != 0) { + + reg_data = in_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_RSR_OFFSET); + out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_RSR_OFFSET, + reg_data & (~XEL_RSR_RECV_IE_MASK)); + } +} + +/** + * xemaclite_aligned_write - Write from 16-bit aligned to 32-bit aligned address + * @src_ptr: Void pointer to the 16-bit aligned source address + * @dest_ptr: Pointer to the 32-bit aligned destination address + * @length: Number bytes to write from source to destination + * + * This function writes data from a 16-bit aligned buffer to a 32-bit aligned + * address in the EmacLite device. + */ +static void xemaclite_aligned_write(void *src_ptr, u32 *dest_ptr, + unsigned length) +{ + u32 align_buffer; + u32 *to_u32_ptr; + u16 *from_u16_ptr, *to_u16_ptr; + + to_u32_ptr = dest_ptr; + from_u16_ptr = (u16 *) src_ptr; + align_buffer = 0; + + for (; length > 3; length -= 4) { + to_u16_ptr = (u16 *) ((void *) &align_buffer); + *to_u16_ptr++ = *from_u16_ptr++; + *to_u16_ptr++ = *from_u16_ptr++; + + /* Output a word */ + *to_u32_ptr++ = align_buffer; + } + if (length) { + u8 *from_u8_ptr, *to_u8_ptr; + + /* Set up to output the remaining data */ + align_buffer = 0; + to_u8_ptr = (u8 *) &align_buffer; + from_u8_ptr = (u8 *) from_u16_ptr; + + /* Output the remaining data */ + for (; length > 0; length--) + *to_u8_ptr++ = *from_u8_ptr++; + + *to_u32_ptr = align_buffer; + } +} + +/** + * xemaclite_aligned_read - Read from 32-bit aligned to 16-bit aligned buffer + * @src_ptr: Pointer to the 32-bit aligned source address + * @dest_ptr: Pointer to the 16-bit aligned destination address + * @length: Number bytes to read from source to destination + * + * This function reads data from a 32-bit aligned address in the EmacLite device + * to a 16-bit aligned buffer. + */ +static void xemaclite_aligned_read(u32 *src_ptr, u8 *dest_ptr, + unsigned length) +{ + u16 *to_u16_ptr, *from_u16_ptr; + u32 *from_u32_ptr; + u32 align_buffer; + + from_u32_ptr = src_ptr; + to_u16_ptr = (u16 *) dest_ptr; + + for (; length > 3; length -= 4) { + /* Copy each word into the temporary buffer */ + align_buffer = *from_u32_ptr++; + from_u16_ptr = (u16 *)&align_buffer; + + /* Read data from source */ + *to_u16_ptr++ = *from_u16_ptr++; + *to_u16_ptr++ = *from_u16_ptr++; + } + + if (length) { + u8 *to_u8_ptr, *from_u8_ptr; + + /* Set up to read the remaining data */ + to_u8_ptr = (u8 *) to_u16_ptr; + align_buffer = *from_u32_ptr++; + from_u8_ptr = (u8 *) &align_buffer; + + /* Read the remaining data */ + for (; length > 0; length--) + *to_u8_ptr = *from_u8_ptr; + } +} + +/** + * xemaclite_send_data - Send an Ethernet frame + * @drvdata: Pointer to the Emaclite device private data + * @data: Pointer to the data to be sent + * @byte_count: Total frame size, including header + * + * This function checks if the Tx buffer of the Emaclite device is free to send + * data. If so, it fills the Tx buffer with data for transmission. Otherwise, it + * returns an error. + * + * Return: 0 upon success or -1 if the buffer(s) are full. + * + * Note: The maximum Tx packet size can not be more than Ethernet header + * (14 Bytes) + Maximum MTU (1500 bytes). This is excluding FCS. + */ +static int xemaclite_send_data(struct net_local *drvdata, u8 *data, + unsigned int byte_count) +{ + u32 reg_data; + void __iomem *addr; + + /* Determine the expected Tx buffer address */ + addr = drvdata->base_addr + drvdata->next_tx_buf_to_use; + + /* If the length is too large, truncate it */ + if (byte_count > ETH_FRAME_LEN) + byte_count = ETH_FRAME_LEN; + + /* Check if the expected buffer is available */ + reg_data = in_be32(addr + XEL_TSR_OFFSET); + if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK | + XEL_TSR_XMIT_ACTIVE_MASK)) == 0) { + + /* Switch to next buffer if configured */ + if (drvdata->tx_ping_pong != 0) + drvdata->next_tx_buf_to_use ^= XEL_BUFFER_OFFSET; + } else if (drvdata->tx_ping_pong != 0) { + /* If the expected buffer is full, try the other buffer, + * if it is configured in HW */ + + addr = (void __iomem __force *)((u32 __force)addr ^ + XEL_BUFFER_OFFSET); + reg_data = in_be32(addr + XEL_TSR_OFFSET); + + if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK | + XEL_TSR_XMIT_ACTIVE_MASK)) != 0) + return -1; /* Buffers were full, return failure */ + } else + return -1; /* Buffer was full, return failure */ + + /* Write the frame to the buffer */ + xemaclite_aligned_write(data, (u32 __force *) addr, byte_count); + + out_be32(addr + XEL_TPLR_OFFSET, (byte_count & XEL_TPLR_LENGTH_MASK)); + + /* Update the Tx Status Register to indicate that there is a + * frame to send. Set the XEL_TSR_XMIT_ACTIVE_MASK flag which + * is used by the interrupt handler to check whether a frame + * has been transmitted */ + reg_data = in_be32(addr + XEL_TSR_OFFSET); + reg_data |= (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_XMIT_ACTIVE_MASK); + out_be32(addr + XEL_TSR_OFFSET, reg_data); + + return 0; +} + +/** + * xemaclite_recv_data - Receive a frame + * @drvdata: Pointer to the Emaclite device private data + * @data: Address where the data is to be received + * + * This function is intended to be called from the interrupt context or + * with a wrapper which waits for the receive frame to be available. + * + * Return: Total number of bytes received + */ +static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data) +{ + void __iomem *addr; + u16 length, proto_type; + u32 reg_data; + + /* Determine the expected buffer address */ + addr = (drvdata->base_addr + drvdata->next_rx_buf_to_use); + + /* Verify which buffer has valid data */ + reg_data = in_be32(addr + XEL_RSR_OFFSET); + + if ((reg_data & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { + if (drvdata->rx_ping_pong != 0) + drvdata->next_rx_buf_to_use ^= XEL_BUFFER_OFFSET; + } else { + /* The instance is out of sync, try other buffer if other + * buffer is configured, return 0 otherwise. If the instance is + * out of sync, do not update the 'next_rx_buf_to_use' since it + * will correct on subsequent calls */ + if (drvdata->rx_ping_pong != 0) + addr = (void __iomem __force *)((u32 __force)addr ^ + XEL_BUFFER_OFFSET); + else + return 0; /* No data was available */ + + /* Verify that buffer has valid data */ + reg_data = in_be32(addr + XEL_RSR_OFFSET); + if ((reg_data & XEL_RSR_RECV_DONE_MASK) != + XEL_RSR_RECV_DONE_MASK) + return 0; /* No data was available */ + } + + /* Get the protocol type of the ethernet frame that arrived */ + proto_type = ((in_be32(addr + XEL_HEADER_OFFSET + + XEL_RXBUFF_OFFSET) >> XEL_HEADER_SHIFT) & + XEL_RPLR_LENGTH_MASK); + + /* Check if received ethernet frame is a raw ethernet frame + * or an IP packet or an ARP packet */ + if (proto_type > (ETH_FRAME_LEN + ETH_FCS_LEN)) { + + if (proto_type == ETH_P_IP) { + length = ((in_be32(addr + + XEL_HEADER_IP_LENGTH_OFFSET + + XEL_RXBUFF_OFFSET) >> + XEL_HEADER_SHIFT) & + XEL_RPLR_LENGTH_MASK); + length += ETH_HLEN + ETH_FCS_LEN; + + } else if (proto_type == ETH_P_ARP) + length = XEL_ARP_PACKET_SIZE + ETH_HLEN + ETH_FCS_LEN; + else + /* Field contains type other than IP or ARP, use max + * frame size and let user parse it */ + length = ETH_FRAME_LEN + ETH_FCS_LEN; + } else + /* Use the length in the frame, plus the header and trailer */ + length = proto_type + ETH_HLEN + ETH_FCS_LEN; + + /* Read from the EmacLite device */ + xemaclite_aligned_read((u32 __force *) (addr + XEL_RXBUFF_OFFSET), + data, length); + + /* Acknowledge the frame */ + reg_data = in_be32(addr + XEL_RSR_OFFSET); + reg_data &= ~XEL_RSR_RECV_DONE_MASK; + out_be32(addr + XEL_RSR_OFFSET, reg_data); + + return length; +} + +/** + * xemaclite_set_mac_address - Set the MAC address for this device + * @drvdata: Pointer to the Emaclite device private data + * @address_ptr:Pointer to the MAC address (MAC address is a 48-bit value) + * + * Tx must be idle and Rx should be idle for deterministic results. + * It is recommended that this function should be called after the + * initialization and before transmission of any packets from the device. + * The MAC address can be programmed using any of the two transmit + * buffers (if configured). + */ +static void xemaclite_set_mac_address(struct net_local *drvdata, + u8 *address_ptr) +{ + void __iomem *addr; + u32 reg_data; + + /* Determine the expected Tx buffer address */ + addr = drvdata->base_addr + drvdata->next_tx_buf_to_use; + + xemaclite_aligned_write(address_ptr, (u32 __force *) addr, ETH_ALEN); + + out_be32(addr + XEL_TPLR_OFFSET, ETH_ALEN); + + /* Update the MAC address in the EmacLite */ + reg_data = in_be32(addr + XEL_TSR_OFFSET); + out_be32(addr + XEL_TSR_OFFSET, reg_data | XEL_TSR_PROG_MAC_ADDR); + + /* Wait for EmacLite to finish with the MAC address update */ + while ((in_be32(addr + XEL_TSR_OFFSET) & + XEL_TSR_PROG_MAC_ADDR) != 0) + ; +} + +/** + * xemaclite_tx_timeout - Callback for Tx Timeout + * @dev: Pointer to the network device + * + * This function is called when Tx time out occurs for Emaclite device. + */ +static void xemaclite_tx_timeout(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + unsigned long flags; + + dev_err(&lp->ndev->dev, "Exceeded transmit timeout of %lu ms\n", + TX_TIMEOUT * 1000UL / HZ); + + dev->stats.tx_errors++; + + /* Reset the device */ + spin_lock_irqsave(&lp->reset_lock, flags); + + /* Shouldn't really be necessary, but shouldn't hurt */ + netif_stop_queue(dev); + + xemaclite_disable_interrupts(lp); + xemaclite_enable_interrupts(lp); + + if (lp->deferred_skb) { + dev_kfree_skb(lp->deferred_skb); + lp->deferred_skb = NULL; + dev->stats.tx_errors++; + } + + /* To exclude tx timeout */ + dev->trans_start = 0xffffffff - TX_TIMEOUT - TX_TIMEOUT; + + /* We're all ready to go. Start the queue */ + netif_wake_queue(dev); + spin_unlock_irqrestore(&lp->reset_lock, flags); +} + +/**********************/ +/* Interrupt Handlers */ +/**********************/ + +/** + * xemaclite_tx_handler - Interrupt handler for frames sent + * @dev: Pointer to the network device + * + * This function updates the number of packets transmitted and handles the + * deferred skb, if there is one. + */ +static void xemaclite_tx_handler(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + + dev->stats.tx_packets++; + if (lp->deferred_skb) { + if (xemaclite_send_data(lp, + (u8 *) lp->deferred_skb->data, + lp->deferred_skb->len) != 0) + return; + else { + dev->stats.tx_bytes += lp->deferred_skb->len; + dev_kfree_skb_irq(lp->deferred_skb); + lp->deferred_skb = NULL; + dev->trans_start = jiffies; + netif_wake_queue(dev); + } + } +} + +/** + * xemaclite_rx_handler- Interrupt handler for frames received + * @dev: Pointer to the network device + * + * This function allocates memory for a socket buffer, fills it with data + * received and hands it over to the TCP/IP stack. + */ +static void xemaclite_rx_handler(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + struct sk_buff *skb; + unsigned int align; + u32 len; + + len = ETH_FRAME_LEN + ETH_FCS_LEN; + skb = dev_alloc_skb(len + ALIGNMENT); + if (!skb) { + /* Couldn't get memory. */ + dev->stats.rx_dropped++; + dev_err(&lp->ndev->dev, "Could not allocate receive buffer\n"); + return; + } + + /* + * A new skb should have the data halfword aligned, but this code is + * here just in case that isn't true. Calculate how many + * bytes we should reserve to get the data to start on a word + * boundary */ + align = BUFFER_ALIGN(skb->data); + if (align) + skb_reserve(skb, align); + + skb_reserve(skb, 2); + + len = xemaclite_recv_data(lp, (u8 *) skb->data); + + if (!len) { + dev->stats.rx_errors++; + dev_kfree_skb_irq(skb); + return; + } + + skb_put(skb, len); /* Tell the skb how much data we got */ + skb->dev = dev; /* Fill out required meta-data */ + + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; + dev->last_rx = jiffies; + + netif_rx(skb); /* Send the packet upstream */ +} + +/** + * xemaclite_interrupt - Interrupt handler for this driver + * @irq: Irq of the Emaclite device + * @dev_id: Void pointer to the network device instance used as callback + * reference + * + * This function handles the Tx and Rx interrupts of the EmacLite device. + */ +static irqreturn_t xemaclite_interrupt(int irq, void *dev_id) +{ + bool tx_complete = 0; + struct net_device *dev = dev_id; + struct net_local *lp = (struct net_local *) netdev_priv(dev); + void __iomem *base_addr = lp->base_addr; + u32 tx_status; + + /* Check if there is Rx Data available */ + if ((in_be32(base_addr + XEL_RSR_OFFSET) & XEL_RSR_RECV_DONE_MASK) || + (in_be32(base_addr + XEL_BUFFER_OFFSET + XEL_RSR_OFFSET) + & XEL_RSR_RECV_DONE_MASK)) + + xemaclite_rx_handler(dev); + + /* Check if the Transmission for the first buffer is completed */ + tx_status = in_be32(base_addr + XEL_TSR_OFFSET); + if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) && + (tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) { + + tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK; + out_be32(base_addr + XEL_TSR_OFFSET, tx_status); + + tx_complete = 1; + } + + /* Check if the Transmission for the second buffer is completed */ + tx_status = in_be32(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); + if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) && + (tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) { + + tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK; + out_be32(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, + tx_status); + + tx_complete = 1; + } + + /* If there was a Tx interrupt, call the Tx Handler */ + if (tx_complete != 0) + xemaclite_tx_handler(dev); + + return IRQ_HANDLED; +} + +/** + * xemaclite_open - Open the network device + * @dev: Pointer to the network device + * + * This function sets the MAC address, requests an IRQ and enables interrupts + * for the Emaclite device and starts the Tx queue. + */ +static int xemaclite_open(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + int retval; + + /* Just to be safe, stop the device first */ + xemaclite_disable_interrupts(lp); + + /* Set the MAC address each time opened */ + xemaclite_set_mac_address(lp, dev->dev_addr); + + /* Grab the IRQ */ + retval = request_irq(dev->irq, &xemaclite_interrupt, 0, dev->name, dev); + if (retval) { + dev_err(&lp->ndev->dev, "Could not allocate interrupt %d\n", + dev->irq); + return retval; + } + + /* Enable Interrupts */ + xemaclite_enable_interrupts(lp); + + /* We're ready to go */ + netif_start_queue(dev); + + return 0; +} + +/** + * xemaclite_close - Close the network device + * @dev: Pointer to the network device + * + * This function stops the Tx queue, disables interrupts and frees the IRQ for + * the Emaclite device. + */ +static int xemaclite_close(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + + netif_stop_queue(dev); + xemaclite_disable_interrupts(lp); + free_irq(dev->irq, dev); + + return 0; +} + +/** + * xemaclite_get_stats - Get the stats for the net_device + * @dev: Pointer to the network device + * + * This function returns the address of the 'net_device_stats' structure for the + * given network device. This structure holds usage statistics for the network + * device. + * + * Return: Pointer to the net_device_stats structure. + */ +static struct net_device_stats *xemaclite_get_stats(struct net_device *dev) +{ + return &dev->stats; +} + +/** + * xemaclite_send - Transmit a frame + * @orig_skb: Pointer to the socket buffer to be transmitted + * @dev: Pointer to the network device + * + * This function checks if the Tx buffer of the Emaclite device is free to send + * data. If so, it fills the Tx buffer with data from socket buffer data, + * updates the stats and frees the socket buffer. The Tx completion is signaled + * by an interrupt. If the Tx buffer isn't free, then the socket buffer is + * deferred and the Tx queue is stopped so that the deferred socket buffer can + * be transmitted when the Emaclite device is free to transmit data. + * + * Return: 0, always. + */ +static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + struct sk_buff *new_skb; + unsigned int len; + unsigned long flags; + + len = orig_skb->len; + + new_skb = orig_skb; + + spin_lock_irqsave(&lp->reset_lock, flags); + if (xemaclite_send_data(lp, (u8 *) new_skb->data, len) != 0) { + /* If the Emaclite Tx buffer is busy, stop the Tx queue and + * defer the skb for transmission at a later point when the + * current transmission is complete */ + netif_stop_queue(dev); + lp->deferred_skb = new_skb; + spin_unlock_irqrestore(&lp->reset_lock, flags); + return 0; + } + spin_unlock_irqrestore(&lp->reset_lock, flags); + + dev->stats.tx_bytes += len; + dev_kfree_skb(new_skb); + dev->trans_start = jiffies; + + return 0; +} + +/** + * xemaclite_ioctl - Perform IO Control operations on the network device + * @dev: Pointer to the network device + * @rq: Pointer to the interface request structure + * @cmd: IOCTL command + * + * The only IOCTL operation supported by this function is setting the MAC + * address. An error is reported if any other operations are requested. + * + * Return: 0 to indicate success, or a negative error for failure. + */ +static int xemaclite_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + struct hw_addr_data *hw_addr = (struct hw_addr_data *) &rq->ifr_hwaddr; + + switch (cmd) { + case SIOCETHTOOL: + return -EIO; + + case SIOCSIFHWADDR: + dev_err(&lp->ndev->dev, "SIOCSIFHWADDR\n"); + + /* Copy MAC address in from user space */ + copy_from_user((void __force *) dev->dev_addr, + (void __user __force *) hw_addr, + IFHWADDRLEN); + xemaclite_set_mac_address(lp, dev->dev_addr); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +/** + * xemaclite_remove_ndev - Free the network device + * @ndev: Pointer to the network device to be freed + * + * This function un maps the IO region of the Emaclite device and frees the net + * device. + */ +static void xemaclite_remove_ndev(struct net_device *ndev) +{ + if (ndev) { + struct net_local *lp = (struct net_local *) netdev_priv(ndev); + + if (lp->base_addr) + iounmap((void __iomem __force *) (lp->base_addr)); + free_netdev(ndev); + } +} + +/** + * get_bool - Get a parameter from the OF device + * @ofdev: Pointer to OF device structure + * @s: Property to be retrieved + * + * This function looks for a property in the device node and returns the value + * of the property if its found or 0 if the property is not found. + * + * Return: Value of the parameter if the parameter is found, or 0 otherwise + */ +static bool get_bool(struct of_device *ofdev, const char *s) +{ + u32 *p = (u32 *)of_get_property(ofdev->node, s, NULL); + + if (p) { + return (bool)*p; + } else { + dev_warn(&ofdev->dev, "Parameter %s not found," + "defaulting to false\n", s); + return 0; + } +} + +static struct net_device_ops xemaclite_netdev_ops; + +/** + * xemaclite_of_probe - Probe method for the Emaclite device. + * @ofdev: Pointer to OF device structure + * @match: Pointer to the structure used for matching a device + * + * This function probes for the Emaclite device in the device tree. + * It initializes the driver data structure and the hardware, sets the MAC + * address and registers the network device. + * + * Return: 0, if the driver is bound to the Emaclite device, or + * a negative error if there is failure. + */ +static int __devinit xemaclite_of_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct resource r_irq; /* Interrupt resources */ + struct resource r_mem; /* IO mem resources */ + struct net_device *ndev = NULL; + struct net_local *lp = NULL; + struct device *dev = &ofdev->dev; + const void *mac_address; + + int rc = 0; + + dev_info(dev, "Device Tree Probing\n"); + + /* Get iospace for the device */ + rc = of_address_to_resource(ofdev->node, 0, &r_mem); + if (rc) { + dev_err(dev, "invalid address\n"); + return rc; + } + + /* Get IRQ for the device */ + rc = of_irq_to_resource(ofdev->node, 0, &r_irq); + if (rc == NO_IRQ) { + dev_err(dev, "no IRQ found\n"); + return rc; + } + + /* Create an ethernet device instance */ + ndev = alloc_etherdev(sizeof(struct net_local)); + if (!ndev) { + dev_err(dev, "Could not allocate network device\n"); + return -ENOMEM; + } + + dev_set_drvdata(dev, ndev); + + ndev->irq = r_irq.start; + ndev->mem_start = r_mem.start; + ndev->mem_end = r_mem.end; + + lp = netdev_priv(ndev); + lp->ndev = ndev; + + if (!request_mem_region(ndev->mem_start, + ndev->mem_end - ndev->mem_start + 1, + DRIVER_NAME)) { + dev_err(dev, "Couldn't lock memory region at %p\n", + (void *)ndev->mem_start); + rc = -EBUSY; + goto error2; + } + + /* Get the virtual base address for the device */ + lp->base_addr = ioremap(r_mem.start, r_mem.end - r_mem.start + 1); + if (NULL == lp->base_addr) { + dev_err(dev, "EmacLite: Could not allocate iomem\n"); + rc = -EIO; + goto error1; + } + + spin_lock_init(&lp->reset_lock); + lp->next_tx_buf_to_use = 0x0; + lp->next_rx_buf_to_use = 0x0; + lp->tx_ping_pong = get_bool(ofdev, "xlnx,tx-ping-pong"); + lp->rx_ping_pong = get_bool(ofdev, "xlnx,rx-ping-pong"); + mac_address = of_get_mac_address(ofdev->node); + + if (mac_address) + /* Set the MAC address. */ + memcpy(ndev->dev_addr, mac_address, 6); + else + dev_warn(dev, "No MAC address found\n"); + + /* Clear the Tx CSR's in case this is a restart */ + out_be32(lp->base_addr + XEL_TSR_OFFSET, 0); + out_be32(lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, 0); + + /* Set the MAC address in the EmacLite device */ + xemaclite_set_mac_address(lp, ndev->dev_addr); + + dev_info(dev, + "MAC address is now %2x:%2x:%2x:%2x:%2x:%2x\n", + ndev->dev_addr[0], ndev->dev_addr[1], + ndev->dev_addr[2], ndev->dev_addr[3], + ndev->dev_addr[4], ndev->dev_addr[5]); + + ndev->netdev_ops = &xemaclite_netdev_ops; + ndev->flags &= ~IFF_MULTICAST; + ndev->watchdog_timeo = TX_TIMEOUT; + + /* Finally, register the device */ + rc = register_netdev(ndev); + if (rc) { + dev_err(dev, + "Cannot register network device, aborting\n"); + goto error1; + } + + dev_info(dev, + "Xilinx EmacLite at 0x%08X mapped to 0x%08X, irq=%d\n", + (unsigned int __force)ndev->mem_start, + (unsigned int __force)lp->base_addr, ndev->irq); + return 0; + +error1: + release_mem_region(ndev->mem_start, r_mem.end - r_mem.start + 1); + +error2: + xemaclite_remove_ndev(ndev); + return rc; +} + +/** + * xemaclite_of_remove - Unbind the driver from the Emaclite device. + * @of_dev: Pointer to OF device structure + * + * This function is called if a device is physically removed from the system or + * if the driver module is being unloaded. It frees any resources allocated to + * the device. + * + * Return: 0, always. + */ +static int __devexit xemaclite_of_remove(struct of_device *of_dev) +{ + struct device *dev = &of_dev->dev; + struct net_device *ndev = dev_get_drvdata(dev); + + unregister_netdev(ndev); + + release_mem_region(ndev->mem_start, ndev->mem_end-ndev->mem_start + 1); + + xemaclite_remove_ndev(ndev); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +static struct net_device_ops xemaclite_netdev_ops = { + .ndo_open = xemaclite_open, + .ndo_stop = xemaclite_close, + .ndo_start_xmit = xemaclite_send, + .ndo_do_ioctl = xemaclite_ioctl, + .ndo_tx_timeout = xemaclite_tx_timeout, + .ndo_get_stats = xemaclite_get_stats, +}; + +/* Match table for OF platform binding */ +static struct of_device_id xemaclite_of_match[] __devinitdata = { + { .compatible = "xlnx,opb-ethernetlite-1.01.a", }, + { .compatible = "xlnx,opb-ethernetlite-1.01.b", }, + { .compatible = "xlnx,xps-ethernetlite-1.00.a", }, + { .compatible = "xlnx,xps-ethernetlite-2.00.a", }, + { .compatible = "xlnx,xps-ethernetlite-2.01.a", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, xemaclite_of_match); + +static struct of_platform_driver xemaclite_of_driver = { + .name = DRIVER_NAME, + .match_table = xemaclite_of_match, + .probe = xemaclite_of_probe, + .remove = __devexit_p(xemaclite_of_remove), +}; + +/** + * xgpiopss_init - Initial driver registration call + * + * Return: 0 upon success, or a negative error upon failure. + */ +static int __init xemaclite_init(void) +{ + /* No kernel boot options used, we just need to register the driver */ + return of_register_platform_driver(&xemaclite_of_driver); +} + +/** + * xemaclite_cleanup - Driver un-registration call + */ +static void __exit xemaclite_cleanup(void) +{ + of_unregister_platform_driver(&xemaclite_of_driver); +} + +module_init(xemaclite_init); +module_exit(xemaclite_cleanup); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx Ethernet MAC Lite driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 4539f07701b3f743580d19dc5d655fb8d21b0a3c Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Thu, 20 Aug 2009 16:13:35 +0800 Subject: tracing/syscalls: Fix the output of syscalls with no arguments Before: # echo 1 > events/syscalls/sys_enter_sync/enable # cat events/syscalls/sys_enter_sync/format ... field:int nr; offset:12; size:4; print fmt: "# sync # cat trace ... sync-8950 [000] 2366.087670: sys_sync( After: # echo 1 > events/syscalls/sys_enter_sync/enable # cat events/syscalls/sys_enter_sync/format ... field:int nr; offset:12; size:4; print fmt: "" # sync # cat trace sync-2134 [001] 136.780735: sys_sync() Reported-by: Masami Hiramatsu Signed-off-by: Li Zefan Cc: Frederic Weisbecker Cc: Steven Rostedt Cc: Jason Baron Cc: Masami Hiramatsu LKML-Reference: <4A8D05AF.20103@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 28e4dae..46c1b977a 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -46,15 +46,22 @@ print_syscall_enter(struct trace_iterator *iter, int flags) return TRACE_TYPE_PARTIAL_LINE; } /* parameter values */ - ret = trace_seq_printf(s, "%s: %lx%s ", entry->args[i], + ret = trace_seq_printf(s, "%s: %lx%s", entry->args[i], trace->args[i], - i == entry->nb_args - 1 ? ")" : ","); + i == entry->nb_args - 1 ? "" : ", "); if (!ret) return TRACE_TYPE_PARTIAL_LINE; } + ret = trace_seq_putc(s, ')'); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + end: - trace_seq_printf(s, "\n"); + ret = trace_seq_putc(s, '\n'); + if (!ret) + return TRACE_TYPE_PARTIAL_LINE; + return TRACE_TYPE_HANDLED; } @@ -129,24 +136,24 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) offset += sizeof(unsigned long); } - trace_seq_printf(s, "\nprint fmt: \""); + trace_seq_puts(s, "\nprint fmt: \""); for (i = 0; i < entry->nb_args; i++) { ret = trace_seq_printf(s, "%s: 0x%%0%zulx%s", entry->args[i], sizeof(unsigned long), - i == entry->nb_args - 1 ? "\", " : ", "); + i == entry->nb_args - 1 ? "" : ", "); if (!ret) return 0; } + trace_seq_putc(s, '"'); for (i = 0; i < entry->nb_args; i++) { - ret = trace_seq_printf(s, "((unsigned long)(REC->%s))%s", - entry->args[i], - i == entry->nb_args - 1 ? "\n" : ", "); + ret = trace_seq_printf(s, ", ((unsigned long)(REC->%s))", + entry->args[i]); if (!ret) return 0; } - return ret; + return trace_seq_putc(s, '\n'); } int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s) -- cgit v0.10.2 From cde7e5ca4e329a157108769d1f752d191cbb71c6 Mon Sep 17 00:00:00 2001 From: Hiroshi Shimamoto Date: Tue, 18 Aug 2009 13:01:01 +0900 Subject: sched: Use for_each_class macro in move_one_task() Replace for loop with the macro for_each_class to cleanup. Signed-off-by: Hiroshi Shimamoto LKML-Reference: <4A8A277D.4090304@ct.jp.nec.com> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 7f83be3..1b529ef 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3461,9 +3461,10 @@ static int move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest, { const struct sched_class *class; - for (class = sched_class_highest; class; class = class->next) + for_each_class(class) { if (class->move_one_task(this_rq, this_cpu, busiest, sd, idle)) return 1; + } return 0; } -- cgit v0.10.2 From 4cdc115fd38b54642e8536a5c2389483bcb9b2e9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Aug 2009 16:40:16 +0200 Subject: ALSA: pcm - Fix drain behavior in non-blocking mode The current PCM core has the following problems regarding PCM draining in non-blocking mode: - the current f_flags isn't checked in snd_pcm_drain(), thus changing the mode dynamically via snd_pcm_nonblock() after open doesn't work. - calling drain in non-blocking mode just return -EAGAIN error, but doesn't provide any way to sync with draining. This patch fixes these issues. - check file->f_flags in snd_pcm_drain() properly - when O_NONBLOCK is set, PCM core sets the stream(s) to DRAIN state but quits ioctl immediately without waiting the whole drain; the caller can sync the drain manually via poll() Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 72cfd47..e3e78c7 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -197,12 +197,16 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, avail = snd_pcm_capture_avail(runtime); if (avail > runtime->avail_max) runtime->avail_max = avail; - if (avail >= runtime->stop_threshold) { - if (substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING) + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { + if (avail >= runtime->buffer_size) { snd_pcm_drain_done(substream); - else + return -EPIPE; + } + } else { + if (avail >= runtime->stop_threshold) { xrun(substream); - return -EPIPE; + return -EPIPE; + } } if (avail >= runtime->control->avail_min) wake_up(&runtime->sleep); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ac2150e..b08898c 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1343,8 +1343,6 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream, static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) { - if (substream->f_flags & O_NONBLOCK) - return -EAGAIN; substream->runtime->trigger_master = substream; return 0; } @@ -1392,7 +1390,6 @@ static struct action_ops snd_pcm_action_drain_init = { struct drain_rec { struct snd_pcm_substream *substream; wait_queue_t wait; - snd_pcm_uframes_t stop_threshold; }; static int snd_pcm_drop(struct snd_pcm_substream *substream); @@ -1404,13 +1401,15 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream); * After this call, all streams are supposed to be either SETUP or DRAINING * (capture only) state. */ -static int snd_pcm_drain(struct snd_pcm_substream *substream) +static int snd_pcm_drain(struct snd_pcm_substream *substream, + struct file *file) { struct snd_card *card; struct snd_pcm_runtime *runtime; struct snd_pcm_substream *s; int result = 0; int i, num_drecs; + int nonblock = 0; struct drain_rec *drec, drec_tmp, *d; card = substream->pcm->card; @@ -1428,6 +1427,15 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream) } } + if (file) { + if (file->f_flags & O_NONBLOCK) + nonblock = 1; + } else if (substream->f_flags & O_NONBLOCK) + nonblock = 1; + + if (nonblock) + goto lock; /* no need to allocate waitqueues */ + /* allocate temporary record for drain sync */ down_read(&snd_pcm_link_rwsem); if (snd_pcm_stream_linked(substream)) { @@ -1449,16 +1457,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream) d->substream = s; init_waitqueue_entry(&d->wait, current); add_wait_queue(&runtime->sleep, &d->wait); - /* stop_threshold fixup to avoid endless loop when - * stop_threshold > buffer_size - */ - d->stop_threshold = runtime->stop_threshold; - if (runtime->stop_threshold > runtime->buffer_size) - runtime->stop_threshold = runtime->buffer_size; } } up_read(&snd_pcm_link_rwsem); + lock: snd_pcm_stream_lock_irq(substream); /* resume pause */ if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED) @@ -1466,9 +1469,12 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream) /* pre-start/stop - all running streams are changed to DRAINING state */ result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); - if (result < 0) { - snd_pcm_stream_unlock_irq(substream); - goto _error; + if (result < 0) + goto unlock; + /* in non-blocking, we don't wait in ioctl but let caller poll */ + if (nonblock) { + result = -EAGAIN; + goto unlock; } for (;;) { @@ -1504,18 +1510,18 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream) } } + unlock: snd_pcm_stream_unlock_irq(substream); - _error: - for (i = 0; i < num_drecs; i++) { - d = &drec[i]; - runtime = d->substream->runtime; - remove_wait_queue(&runtime->sleep, &d->wait); - runtime->stop_threshold = d->stop_threshold; + if (!nonblock) { + for (i = 0; i < num_drecs; i++) { + d = &drec[i]; + runtime = d->substream->runtime; + remove_wait_queue(&runtime->sleep, &d->wait); + } + if (drec != &drec_tmp) + kfree(drec); } - - if (drec != &drec_tmp) - kfree(drec); snd_power_unlock(card); return result; @@ -2544,7 +2550,7 @@ static int snd_pcm_common_ioctl1(struct file *file, return snd_pcm_hw_params_old_user(substream, arg); #endif case SNDRV_PCM_IOCTL_DRAIN: - return snd_pcm_drain(substream); + return snd_pcm_drain(substream, file); case SNDRV_PCM_IOCTL_DROP: return snd_pcm_drop(substream); case SNDRV_PCM_IOCTL_PAUSE: -- cgit v0.10.2 From 2f19c287fecb958eb68b1c2199b4dd6e00ba4276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 13 Aug 2009 16:51:51 +0200 Subject: b43: Update dummy transmission to match V4 specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The V4 dummy transmission has two extra bools in its prototype, so update all callers with the 2 bools. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 22d0fbd..976104f 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -477,7 +477,7 @@ static void lo_measure_setup(struct b43_wldev *dev, } else b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802); if (phy->rev >= 2) - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); b43_gphy_channel_switch(dev, 6, 0); b43_radio_read16(dev, 0x51); /* dummy read */ if (phy->type == B43_PHYTYPE_G) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 950beef..f6d039e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -691,9 +691,9 @@ static void b43_synchronize_irq(struct b43_wldev *dev) } /* DummyTransmission function, as documented on - * http://bcm-specs.sipsolutions.net/DummyTransmission + * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission */ -void b43_dummy_transmission(struct b43_wldev *dev) +void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) { struct b43_wl *wl = dev->wl; struct b43_phy *phy = &dev->phy; @@ -707,19 +707,12 @@ void b43_dummy_transmission(struct b43_wldev *dev) 0x00000000, }; - switch (phy->type) { - case B43_PHYTYPE_A: + if (ofdm) { max_loop = 0x1E; buffer[0] = 0x000201CC; - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: + } else { max_loop = 0xFA; buffer[0] = 0x000B846E; - break; - default: - B43_WARN_ON(1); - return; } spin_lock_irq(&wl->irq_lock); @@ -728,20 +721,35 @@ void b43_dummy_transmission(struct b43_wldev *dev) for (i = 0; i < 5; i++) b43_ram_write(dev, i * 4, buffer[i]); - /* Commit writes */ - b43_read32(dev, B43_MMIO_MACCTL); - b43_write16(dev, 0x0568, 0x0000); - b43_write16(dev, 0x07C0, 0x0000); - value = ((phy->type == B43_PHYTYPE_A) ? 1 : 0); + if (dev->dev->id.revision < 11) + b43_write16(dev, 0x07C0, 0x0000); + else + b43_write16(dev, 0x07C0, 0x0100); + value = (ofdm ? 0x41 : 0x40); b43_write16(dev, 0x050C, value); + if ((phy->type == B43_PHYTYPE_N) || (phy->type == B43_PHYTYPE_LP)) + b43_write16(dev, 0x0514, 0x1A02); b43_write16(dev, 0x0508, 0x0000); b43_write16(dev, 0x050A, 0x0000); b43_write16(dev, 0x054C, 0x0000); b43_write16(dev, 0x056A, 0x0014); b43_write16(dev, 0x0568, 0x0826); b43_write16(dev, 0x0500, 0x0000); - b43_write16(dev, 0x0502, 0x0030); + if (!pa_on && (phy->type == B43_PHYTYPE_N)) { + //SPEC TODO + } + + switch (phy->type) { + case B43_PHYTYPE_N: + b43_write16(dev, 0x0502, 0x00D0); + break; + case B43_PHYTYPE_LP: + b43_write16(dev, 0x0502, 0x0050); + break; + default: + b43_write16(dev, 0x0502, 0x0030); + } if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) b43_radio_write16(dev, 0x0051, 0x0017); diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 950fb1b..0406e06 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -123,7 +123,7 @@ void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value u64 b43_hf_read(struct b43_wldev *dev); void b43_hf_write(struct b43_wldev *dev, u64 value); -void b43_dummy_transmission(struct b43_wldev *dev); +void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on); void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags); diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 5300232..e471312 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -333,7 +333,7 @@ static void b43_set_all_gains(struct b43_wldev *dev, b43_phy_maskset(dev, 0x04A1, 0xBFBF, tmp); b43_phy_maskset(dev, 0x04A2, 0xBFBF, tmp); } - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); } static void b43_set_original_gains(struct b43_wldev *dev) @@ -365,7 +365,7 @@ static void b43_set_original_gains(struct b43_wldev *dev) b43_phy_maskset(dev, 0x04A0, 0xBFBF, 0x4040); b43_phy_maskset(dev, 0x04A1, 0xBFBF, 0x4040); b43_phy_maskset(dev, 0x04A2, 0xBFBF, 0x4000); - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ @@ -1964,7 +1964,7 @@ static void b43_phy_init_pctl(struct b43_wldev *dev) } b43_set_txpower_g(dev, &bbatt, &rfatt, 0); } - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); gphy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI); if (B43_DEBUG) { /* Current-Idle-TSSI sanity check. */ diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index e1e20f6..73e97fa 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c @@ -37,7 +37,7 @@ static void b43_wa_papd(struct b43_wldev *dev) backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0); b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7); b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0); - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, true, true); b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup); } -- cgit v0.10.2 From 7021f62a46d4866fecd7b31cbc359d742876bb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 13 Aug 2009 17:27:31 +0200 Subject: b43: LP-PHY: Initialize TX power control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HW TX power control init still needs work. The SW init is complete according to the specs. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index cfb8337..996b7ec 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1257,18 +1257,109 @@ static void lpphy_calibration(struct b43_wldev *dev) b43_mac_enable(dev); } +static void lpphy_set_tssi_mux(struct b43_wldev *dev, enum tssi_mux_mode mode) +{ + if (mode != TSSI_MUX_EXT) { + b43_radio_set(dev, B2063_PA_SP1, 0x2); + b43_phy_set(dev, B43_PHY_OFDM(0xF3), 0x1000); + b43_radio_write(dev, B2063_PA_CTL10, 0x51); + if (mode == TSSI_MUX_POSTPA) { + b43_radio_mask(dev, B2063_PA_SP1, 0xFFFE); + b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFC7); + } else { + b43_radio_maskset(dev, B2063_PA_SP1, 0xFFFE, 0x1); + b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVRVAL, + 0xFFC7, 0x20); + } + } else { + B43_WARN_ON(1); + } +} + +static void lpphy_tx_pctl_init_hw(struct b43_wldev *dev) +{ + u16 tmp; + int i; + + //SPEC TODO Call LP PHY Clear TX Power offsets + for (i = 0; i < 64; i++) { + if (dev->phy.rev >= 2) + b43_lptab_write(dev, B43_LPTAB32(7, i + 1), i); + else + b43_lptab_write(dev, B43_LPTAB32(10, i + 1), i); + } + + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xFF00, 0xFF); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0x8FFF, 0x5000); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0xFFC0, 0x1F); + if (dev->phy.rev < 2) { + b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xEFFF); + b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xDFFF, 0x2000); + } else { + b43_phy_mask(dev, B43_PHY_OFDM(0x103), 0xFFFE); + b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFFB, 0x4); + b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFEF, 0x10); + b43_radio_maskset(dev, B2063_IQ_CALIB_CTL2, 0xF3, 0x1); + lpphy_set_tssi_mux(dev, TSSI_MUX_POSTPA); + } + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0x7FFF, 0x8000); + b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xFF); + b43_phy_write(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xA); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD, + (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, + B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF); + b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xF8FF); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD, + (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, + B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW); + + if (dev->phy.rev < 2) { + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF, 0x1000); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xEFFF); + } else { + lpphy_set_tx_power_by_index(dev, 0x7F); + } + + b43_dummy_transmission(dev, true, true); + + tmp = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_STAT); + if (tmp & 0x8000) { + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, + 0xFFC0, (tmp & 0xFF) - 32); + } + + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF); + + // (SPEC?) TODO Set "Target TX frequency" variable to 0 + // SPEC FIXME "Set BB Multiplier to 0xE000" impossible - bb_mult is u8! +} + +static void lpphy_tx_pctl_init_sw(struct b43_wldev *dev) +{ + struct lpphy_tx_gains gains; + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + gains.gm = 4; + gains.pad = 12; + gains.pga = 12; + gains.dac = 0; + } else { + gains.gm = 7; + gains.pad = 14; + gains.pga = 15; + gains.dac = 0; + } + lpphy_set_tx_gains(dev, gains); + lpphy_set_bb_mult(dev, 150); +} + /* Initialize TX power control */ static void lpphy_tx_pctl_init(struct b43_wldev *dev) { if (0/*FIXME HWPCTL capable */) { - //TODO + lpphy_tx_pctl_init_hw(dev); } else { /* This device is only software TX power control capable. */ - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - //TODO - } else { - //TODO - } - //TODO set BB multiplier to 0x0096 + lpphy_tx_pctl_init_sw(dev); } } diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 0461d5b..4eab760 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -886,6 +886,11 @@ struct b43_phy_lp { u16 dig_flt_state[9]; }; +enum tssi_mux_mode { + TSSI_MUX_PREPA, + TSSI_MUX_POSTPA, + TSSI_MUX_EXT, +}; struct b43_phy_operations; extern const struct b43_phy_operations b43_phyops_lp; -- cgit v0.10.2 From a8b875e7dc80ff442698d8cf4f45ccce400a6a66 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 13 Aug 2009 20:39:31 +0300 Subject: cfg80211: export cfg80211_wext_siwfreq cfg80211_wext_siwfreq() should be exported with EXPORT_SYMBOL_GPL. Signed-off-by: Jussi Kivilinna Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index c449174..c12029b 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -771,6 +771,7 @@ int cfg80211_wext_siwfreq(struct net_device *dev, return err; } } +EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); int cfg80211_wext_giwfreq(struct net_device *dev, struct iw_request_info *info, -- cgit v0.10.2 From e6a6cf4c42e0dc3541a63b5f0f88299f982d6704 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 13 Aug 2009 13:30:50 -0700 Subject: iwlwifi: prevent read outside array bounds With EDCA and HCCA we have 16 potential tid values. This is accommodated by mac80211, but iwlwifi only supports EDCA. With this implementation it is thus possible for mac80211 to request a tid that will cause iwlwifi to read outside array bounds. A similar problem exists if traffic is received in an unsupported category. We add error checking to catch these situations. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 2133155..1bd7cd4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -332,6 +332,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, } else return MAX_TID_COUNT; + if (unlikely(tid >= TID_MAX_LOAD_COUNT)) + return MAX_TID_COUNT; + tl = &lq_data->load[tid]; curr_time -= curr_time % TID_ROUND_VALUE; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9b76bd4..7686fc7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -745,6 +745,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + if (unlikely(tid >= MAX_TID_COUNT)) + goto drop_unlock; seq_number = priv->stations[sta_id].tid[tid].seq_number; seq_number &= IEEE80211_SCTL_SEQ; hdr->seq_ctrl = hdr->seq_ctrl & @@ -1238,6 +1240,9 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) return -EINVAL; } + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) tx_fifo_id = default_tid_to_tx_fifo[tid]; else diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e617411..f339c5b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -544,6 +544,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + if (unlikely(tid >= MAX_TID_COUNT)) + goto drop; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | -- cgit v0.10.2 From be2527654fab254beda8612cbd6bc927dc98fbee Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:51 -0700 Subject: iwlwifi: remove unused HT configuration entry tx_chan_width The tx_chan_width entry is never used, supported_chan_width is used instead. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index af73512..479b7e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2423,7 +2423,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); - iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; iwl_conf->ht_protection = bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; iwl_conf->non_GF_STA_present = diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b96c3c9..c34f9d7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -515,7 +515,6 @@ struct iwl_ht_info { struct ieee80211_mcs_info mcs; /* BSS related data */ u8 extension_chan_offset; - u8 tx_chan_width; u8 ht_protection; u8 non_GF_STA_present; }; -- cgit v0.10.2 From 7869b0eaed0447a989d8672eed27a358aa5dde0c Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:52 -0700 Subject: iwlwifi: include HT configuration when adding stations through rs_rate_init Driver's first notification of a new station from mac80211 can be through rate selection API. This patch fixes a bug where, in this code path, the HT capabilities of the new station were ignored. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 1bd7cd4..551c4ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2522,6 +2522,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_supported_band *sband = txrc->sband; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = priv_sta; @@ -2554,7 +2555,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", hdr->addr1); sta_id = iwl_add_station(priv, hdr->addr1, - false, CMD_ASYNC, NULL); + false, CMD_ASYNC, ht_cap); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2623,6 +2624,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, int i, j; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct iwl_lq_sta *lq_sta = priv_sta; u16 mask_bit = 0; int count; @@ -2651,7 +2653,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); sta_id = iwl_add_station(priv, sta->addr, false, - CMD_ASYNC, NULL); + CMD_ASYNC, ht_cap); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2672,19 +2674,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), * supp_rates[] does not; shift to convert format, force 9 MBits off. */ - lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1; - lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1; + lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; + lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; lq_sta->active_siso_rate &= ~((u16)0x2); lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; /* Same here */ - lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1; - lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1; + lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; + lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; lq_sta->active_mimo2_rate &= ~((u16)0x2); lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1; - lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1; + lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1; + lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1; lq_sta->active_mimo3_rate &= ~((u16)0x2); lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; -- cgit v0.10.2 From 3b24716fc978db9c27c4a069e5201460479340a4 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 13 Aug 2009 13:30:53 -0700 Subject: iwlwifi: cleanup HT40 extension channels setup The patch cleans up the HT40 extension channels setup for EEPROM band 6 and 7 to make it more readable. Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 78c4a32..ded6332 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -484,14 +484,14 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, ? # x " " : "") /** - * iwl_set_ht40_chan_info - Copy ht40 channel info into driver's priv. + * iwl_mod_ht40_chan_info - Copy ht40 channel info into driver's priv. * * Does not set up a command, or touch hardware. */ -static int iwl_set_ht40_chan_info(struct iwl_priv *priv, +static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, const struct iwl_eeprom_channel *eeprom_ch, - u8 ht40_extension_channel) + u8 clear_ht40_extension_channel) { struct iwl_channel_info *ch_info; @@ -523,7 +523,7 @@ static int iwl_set_ht40_chan_info(struct iwl_priv *priv, ch_info->ht40_min_power = 0; ch_info->ht40_scan_power = eeprom_ch->max_power_avg; ch_info->ht40_flags = eeprom_ch->flags; - ch_info->ht40_extension_channel = ht40_extension_channel; + ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; return 0; } @@ -592,8 +592,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* First write that ht40 is not enabled, and then enable * one by one */ ch_info->ht40_extension_channel = - (IEEE80211_CHAN_NO_HT40PLUS | - IEEE80211_CHAN_NO_HT40MINUS); + IEEE80211_CHAN_NO_HT40; if (!(is_channel_valid(ch_info))) { IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - " @@ -652,7 +651,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */ for (band = 6; band <= 7; band++) { enum ieee80211_band ieeeband; - u8 ht40_extension_chan; iwl_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); @@ -663,28 +661,17 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { - - if ((band == 6) && - ((eeprom_ch_index[ch] == 5) || - (eeprom_ch_index[ch] == 6) || - (eeprom_ch_index[ch] == 7))) - /* both are allowed: above and below */ - ht40_extension_chan = 0; - else - ht40_extension_chan = - IEEE80211_CHAN_NO_HT40MINUS; - /* Set up driver's info for lower half */ - iwl_set_ht40_chan_info(priv, ieeeband, + iwl_mod_ht40_chan_info(priv, ieeeband, eeprom_ch_index[ch], - &(eeprom_ch_info[ch]), - ht40_extension_chan); + &eeprom_ch_info[ch], + IEEE80211_CHAN_NO_HT40PLUS); /* Set up driver's info for upper half */ - iwl_set_ht40_chan_info(priv, ieeeband, - (eeprom_ch_index[ch] + 4), - &(eeprom_ch_info[ch]), - IEEE80211_CHAN_NO_HT40PLUS); + iwl_mod_ht40_chan_info(priv, ieeeband, + eeprom_ch_index[ch] + 4, + &eeprom_ch_info[ch], + IEEE80211_CHAN_NO_HT40MINUS); } } -- cgit v0.10.2 From 415e49936b4b29b34c2fb561eeab867d41fc43a6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 13 Aug 2009 13:30:54 -0700 Subject: iwlwifi: traverse linklist to find the valid OTP block For devices using OTP memory, EEPROM image can start from any one of the OTP blocks. If shadow RAM is disabled, we need to traverse link list to find the last valid block, then start the EEPROM image reading. If OTP is not full, the valid block is the block _before_ the last block on the link list; the last block on the link list is the empty block ready for next OTP refresh/update. If OTP is full, then the last block is the valid block to be used for configure the device. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 191718a..9bb6a28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -149,12 +149,14 @@ struct iwl_cfg iwl1000_bgn_cfg = { .ucode_api_min = IWL1000_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, .ops = &iwl1000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .max_ll_items = OTP_MAX_LL_ITEMS_1000, + .shadow_ram_support = false, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c3ec6c2..0b731fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -161,7 +161,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -169,6 +169,8 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = false, .pa_type = IWL_PA_HYBRID, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, }; /* @@ -181,7 +183,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -189,6 +191,8 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .valid_rx_ant = ANT_BC, .need_pll_cfg = false, .pa_type = IWL_PA_INTERNAL, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -198,7 +202,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -206,6 +210,8 @@ struct iwl_cfg iwl6050_2agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -215,7 +221,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -223,6 +229,8 @@ struct iwl_cfg iwl6000_3agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -232,7 +240,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -240,6 +248,8 @@ struct iwl_cfg iwl6050_3agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 32750f4..5096834 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -209,6 +209,8 @@ struct iwl_mod_params { * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. * @pa_type: used by 6000 series only to identify the type of Power Amplifier + * @max_ll_items: max number of OTP blocks + * @shadow_ram_support: shadow support for OTP memory * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -247,6 +249,8 @@ struct iwl_cfg { bool need_pll_cfg; bool use_isr_legacy; enum iwl_pa_type pa_type; + const u16 max_ll_items; + const bool shadow_ram_support; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c34f9d7..0b19a6f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -887,6 +887,17 @@ enum iwl_nvm_type { NVM_DEVICE_TYPE_OTP, }; +/* + * Two types of OTP memory access modes + * IWL_OTP_ACCESS_ABSOLUTE - absolute address mode, + * based on physical memory addressing + * IWL_OTP_ACCESS_RELATIVE - relative address mode, + * based on logical memory addressing + */ +enum iwl_access_mode { + IWL_OTP_ACCESS_ABSOLUTE, + IWL_OTP_ACCESS_RELATIVE, +}; /** * enum iwl_pa_type - Power Amplifier type diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index ded6332..01b95e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -152,6 +152,19 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); +static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) +{ + u32 otpgp; + + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (mode == IWL_OTP_ACCESS_ABSOLUTE) + iwl_clear_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_OTP_ACCESS_MODE); + else + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_OTP_ACCESS_MODE); +} + static int iwlcore_get_nvm_type(struct iwl_priv *priv) { u32 otpgp; @@ -252,6 +265,124 @@ static int iwl_init_otp_access(struct iwl_priv *priv) return ret; } +static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) +{ + int ret = 0; + u32 r; + u32 otpgp; + + _iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { + IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + return ret; + } + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + /* check for ECC errors: */ + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { + /* stop in this case */ + /* set the uncorrectable OTP ECC bit for acknowledgement */ + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); + IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n"); + return -EINVAL; + } + if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { + /* continue in this case */ + /* set the correctable OTP ECC bit for acknowledgement */ + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); + IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); + } + *eeprom_data = le16_to_cpu((__force __le16)(r >> 16)); + return 0; +} + +/* + * iwl_is_otp_empty: check for empty OTP + */ +static bool iwl_is_otp_empty(struct iwl_priv *priv) +{ + u16 next_link_addr = 0, link_value; + bool is_empty = false; + + /* locate the beginning of OTP link list */ + if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) { + if (!link_value) { + IWL_ERR(priv, "OTP is empty\n"); + is_empty = true; + } + } else { + IWL_ERR(priv, "Unable to read first block of OTP list.\n"); + is_empty = true; + } + + return is_empty; +} + + +/* + * iwl_find_otp_image: find EEPROM image in OTP + * finding the OTP block that contains the EEPROM image. + * the last valid block on the link list (the block _before_ the last block) + * is the block we should read and used to configure the device. + * If all the available OTP blocks are full, the last block will be the block + * we should read and used to configure the device. + * only perform this operation if shadow RAM is disabled + */ +static int iwl_find_otp_image(struct iwl_priv *priv, + u16 *validblockaddr) +{ + u16 next_link_addr = 0, link_value = 0, valid_addr; + int ret = 0; + int usedblocks = 0; + + /* set addressing mode to absolute to traverse the link list */ + iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE); + + /* checking for empty OTP or error */ + if (iwl_is_otp_empty(priv)) + return -EINVAL; + + /* + * start traverse link list + * until reach the max number of OTP blocks + * different devices have different number of OTP blocks + */ + do { + /* save current valid block address + * check for more block on the link list + */ + valid_addr = next_link_addr; + next_link_addr = link_value; + IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n", + usedblocks, next_link_addr); + if (iwl_read_otp_word(priv, next_link_addr, &link_value)) + return -EINVAL; + if (!link_value) { + /* + * reach the end of link list, + * set address point to the starting address + * of the image + */ + goto done; + } + /* more in the link list, continue */ + usedblocks++; + } while (usedblocks < priv->cfg->max_ll_items); + /* OTP full, use last block */ + IWL_DEBUG_INFO(priv, "OTP is full, use last block\n"); +done: + *validblockaddr = valid_addr; + /* skip first 2 bytes (link list pointer) */ + *validblockaddr += 2; + return ret; +} + /** * iwl_eeprom_init - read EEPROM contents * @@ -266,15 +397,14 @@ int iwl_eeprom_init(struct iwl_priv *priv) int sz; int ret; u16 addr; - u32 otpgp; + u16 validblockaddr = 0; + u16 cache_addr = 0; priv->nvm_device_type = iwlcore_get_nvm_type(priv); if (priv->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ - if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) - priv->cfg->eeprom_size = - OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL; + IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size); sz = priv->cfg->eeprom_size; priv->eeprom = kzalloc(sz, GFP_KERNEL); if (!priv->eeprom) { @@ -302,46 +432,31 @@ int iwl_eeprom_init(struct iwl_priv *priv) if (ret) { IWL_ERR(priv, "Failed to initialize OTP access.\n"); ret = -ENOENT; - goto err; + goto done; } _iwl_write32(priv, CSR_EEPROM_GP, iwl_read32(priv, CSR_EEPROM_GP) & ~CSR_EEPROM_GP_IF_OWNER_MSK); - /* clear */ - _iwl_write32(priv, CSR_OTP_GP_REG, - iwl_read32(priv, CSR_OTP_GP_REG) | + + iwl_set_bit(priv, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); - - for (addr = 0; addr < sz; addr += sizeof(u16)) { - u32 r; - - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - - ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); - if (ret < 0) { - IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + /* traversing the linked list if no shadow ram supported */ + if (!priv->cfg->shadow_ram_support) { + if (iwl_find_otp_image(priv, &validblockaddr)) { + ret = -ENOENT; goto done; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); - /* check for ECC errors: */ - otpgp = iwl_read32(priv, CSR_OTP_GP_REG); - if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { - /* stop in this case */ - IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n"); + } + for (addr = validblockaddr; addr < validblockaddr + sz; + addr += sizeof(u16)) { + u16 eeprom_data; + + ret = iwl_read_otp_word(priv, addr, &eeprom_data); + if (ret) goto done; - } - if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { - /* continue in this case */ - _iwl_write32(priv, CSR_OTP_GP_REG, - iwl_read32(priv, CSR_OTP_GP_REG) | - CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); - IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); - } - e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); + e[cache_addr / 2] = eeprom_data; + cache_addr += sizeof(u16); } } else { /* eeprom is an array of 16bit values */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 05d4fc4..ca7920a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -180,8 +180,14 @@ struct iwl_eeprom_channel { #define EEPROM_5050_EEPROM_VERSION (0x21E) /* OTP */ -#define OTP_LOWER_BLOCKS_TOTAL (3) -#define OTP_BLOCK_SIZE (0x400) +/* lower blocks contain EEPROM image and calibration data */ +#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ +/* high blocks contain PAPD data */ +#define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16)) /* 6 KB */ +#define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16)) /* 1024 bytes */ +#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */ +#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */ +#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */ /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; -- cgit v0.10.2 From 367ca28da433ed9639468be851e1f33468e3485e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 13 Aug 2009 13:30:55 -0700 Subject: iwlwifi: remove unused members of iwl_ht_info Some members of iwl_ht_info are unused, and one of them is write-only, so we can remove these three: max_amsdu_size, ampdu_factor and mpdu_density. Signed-off-by: Johannes Berg Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 479b7e1..08345b9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2397,8 +2397,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, iwl_conf->sgf |= HT_SHORT_GI_40MHZ; iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->max_amsdu_size = - !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); iwl_conf->supported_chan_width = !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0b19a6f..db74534 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -509,9 +509,6 @@ struct iwl_ht_info { u8 sm_ps; u8 is_green_field; u8 sgf; /* HT_SHORT_GI_* short guard interval */ - u8 max_amsdu_size; - u8 ampdu_factor; - u8 mpdu_density; struct ieee80211_mcs_info mcs; /* BSS related data */ u8 extension_chan_offset; -- cgit v0.10.2 From 9f30e04e041cf9943940f71fd76094dd5a237018 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:56 -0700 Subject: iwlwifi: refactor packet reception code This patch fixes a number of issues in iwl_rx_reply_rx and iwl_pass_packet_to_mac80211. These issues stem from the complexities of managing two different types of packet commands for different hardware. - Unify code handling rx_phy_res in SKB or cached to eliminate redundancy and remove potential NULL pointer accesses - Replace magic number with proper constant - Optimize functions by moving early exit conditions before computation - Comment code and improve some variable names - Remove redundant computation in iwl_pass_packet_to_mac80211 by passing in the correct, already-computed arguments. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 68d7719..9398ad7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1156,6 +1156,7 @@ struct iwl_wep_cmd { #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) #define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0) +#define RX_RES_PHY_FLAGS_ANTENNA_POS 4 #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 43b2fce..092d327 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -853,61 +853,12 @@ static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) } static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, - int include_phy, - struct iwl_rx_mem_buffer *rxb, - struct ieee80211_rx_status *stats) + struct ieee80211_hdr *hdr, + u16 len, + u32 ampdu_status, + struct iwl_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl_rx_phy_res *rx_start = (include_phy) ? - (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : NULL; - struct ieee80211_hdr *hdr; - u16 len; - __le32 *rx_end; - unsigned int skblen; - u32 ampdu_status; - u32 ampdu_status_legacy; - - if (!include_phy && priv->last_phy_res[0]) - rx_start = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; - - if (!rx_start) { - IWL_ERR(priv, "MPDU frame without a PHY data\n"); - return; - } - if (include_phy) { - hdr = (struct ieee80211_hdr *)((u8 *) &rx_start[1] + - rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - - rx_end = (__le32 *)((u8 *) &pkt->u.raw[0] + - sizeof(struct iwl_rx_phy_res) + - rx_start->cfg_phy_cnt + len); - - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - hdr = (struct ieee80211_hdr *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_start->byte_count = amsdu->byte_count; - rx_end = (__le32 *) (((u8 *) hdr) + len); - } - - ampdu_status = le32_to_cpu(*rx_end); - skblen = ((u8 *) rx_end - (u8 *) &pkt->u.raw[0]) + sizeof(u32); - - if (!include_phy) { - /* New status scheme, need to translate */ - ampdu_status_legacy = ampdu_status; - ampdu_status = iwl_translate_rx_status(priv, ampdu_status); - } - - /* start from MAC */ - skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); - skb_put(rxb->skb, len); /* end where data ends */ - /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { IWL_DEBUG_DROP_LIMIT(priv, @@ -915,13 +866,15 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, return; } - hdr = (struct ieee80211_hdr *)rxb->skb->data; - - /* in case of HW accelerated crypto and bad decryption, drop */ + /* In case of HW accelerated crypto and bad decryption, drop */ if (!priv->cfg->mod_params->sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; + /* Resize SKB from mac header to end of packet */ + skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data); + skb_put(rxb->skb, len); + iwl_update_stats(priv, false, hdr->frame_control, len); memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); ieee80211_rx_irqsafe(priv->hw, rxb->skb); @@ -955,25 +908,66 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status; struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - /* Use phy data (Rx signal strength, etc.) contained within - * this rx packet for legacy frames, - * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ - int include_phy = (pkt->hdr.cmd == REPLY_RX); - struct iwl_rx_phy_res *rx_start = (include_phy) ? - (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : - (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; - __le32 *rx_end; - unsigned int len = 0; + struct iwl_rx_phy_res *phy_res; + __le32 rx_pkt_status; + struct iwl4965_rx_mpdu_res_start *amsdu; + u32 len; + u32 ampdu_status; u16 fc; - u8 network_packet; - rx_status.mactime = le64_to_cpu(rx_start->timestamp); + /** + * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. + * REPLY_RX: physical layer info is in this buffer + * REPLY_RX_MPDU_CMD: physical layer info was sent in separate + * command and cached in priv->last_phy_res + * + * Here we set up local variables depending on which command is + * received. + */ + if (pkt->hdr.cmd == REPLY_RX) { + phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; + header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) + + phy_res->cfg_phy_cnt); + + len = le16_to_cpu(phy_res->byte_count); + rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + + phy_res->cfg_phy_cnt + len); + ampdu_status = le32_to_cpu(rx_pkt_status); + } else { + if (!priv->last_phy_res[0]) { + IWL_ERR(priv, "MPDU frame without cached PHY data\n"); + return; + } + phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; + amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; + header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); + len = le16_to_cpu(amsdu->byte_count); + rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); + ampdu_status = iwl_translate_rx_status(priv, + le32_to_cpu(rx_pkt_status)); + } + + if ((unlikely(phy_res->cfg_phy_cnt > 20))) { + IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", + phy_res->cfg_phy_cnt); + return; + } + + if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || + !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { + IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", + le32_to_cpu(rx_pkt_status)); + return; + } + + /* rx_status carries information about the packet to mac80211 */ + rx_status.mactime = le64_to_cpu(phy_res->timestamp); rx_status.freq = - ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); - rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel)); + rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; rx_status.rate_idx = - iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); + iwl_hwrate_to_plcp_idx(le32_to_cpu(phy_res->rate_n_flags)); if (rx_status.band == IEEE80211_BAND_5GHZ) rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; @@ -983,54 +977,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, * this W/A doesn't propagate it to the mac80211 */ /*rx_status.flag |= RX_FLAG_TSFT;*/ - if ((unlikely(rx_start->cfg_phy_cnt > 20))) { - IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", - rx_start->cfg_phy_cnt); - return; - } - - if (!include_phy) { - if (priv->last_phy_res[0]) - rx_start = (struct iwl_rx_phy_res *) - &priv->last_phy_res[1]; - else - rx_start = NULL; - } - - if (!rx_start) { - IWL_ERR(priv, "MPDU frame without a PHY data\n"); - return; - } - - if (include_phy) { - header = (struct ieee80211_hdr *)((u8 *) &rx_start[1] - + rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + - sizeof(struct iwl_rx_phy_res) + len); - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - header = (void *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_end = (__le32 *) (pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start) + len); - } - - if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || - !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { - IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", - le32_to_cpu(*rx_end)); - return; - } - - priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); + priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.signal = iwl_calc_rssi(priv, rx_start); + rx_status.signal = iwl_calc_rssi(priv, phy_res); /* Meaningful noise values are available only from beacon statistics, * which are gathered only when associated, and indicate noise @@ -1050,10 +1000,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (!iwl_is_associated(priv)) priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - /* Set "1" to report good data frames in groups of 100 */ #ifdef CONFIG_IWLWIFI_DEBUG + /* Set "1" to report good data frames in groups of 100 */ if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) - iwl_dbg_report_frame(priv, rx_start, len, header, 1); + iwl_dbg_report_frame(priv, phy_res, len, header, 1); #endif iwl_dbg_log_rx_data_frame(priv, len, header); IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", @@ -1073,18 +1023,18 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, * new 802.11n radiotap field "RX chains" that is defined * as a bitmask. */ - rx_status.antenna = le16_to_cpu(rx_start->phy_flags & - RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + rx_status.antenna = + le16_to_cpu(phy_res->phy_flags & RX_RES_PHY_FLAGS_ANTENNA_MSK) + >> RX_RES_PHY_FLAGS_ANTENNA_POS; /* set the preamble flag if appropriate */ - if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) rx_status.flag |= RX_FLAG_SHORTPRE; - network_packet = iwl_is_network_packet(priv, header); - if (network_packet) { + if (iwl_is_network_packet(priv, header)) { priv->last_rx_rssi = rx_status.signal; priv->last_beacon_time = priv->ucode_beacon_time; - priv->last_tsf = le64_to_cpu(rx_start->timestamp); + priv->last_tsf = le64_to_cpu(phy_res->timestamp); } fc = le16_to_cpu(header->frame_control); @@ -1096,8 +1046,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, header->addr2); /* fall through */ default: - iwl_pass_packet_to_mac80211(priv, include_phy, rxb, - &rx_status); + iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, + rxb, &rx_status); break; } -- cgit v0.10.2 From 28bd723bbaddba4e145d25117649bb6da5fafad7 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:57 -0700 Subject: iwlwifi: configure HT40 channels in iwl_mac_config As indicated by note in iwl_ht_conf, some HT parameters are set on association (e.g., channel width) and some vary over time (HT protection mode) and per station (e.g., short GI support). The global parameters should be set in iwl_mac_config and the local/varying parameters in iwl_ht_conf. This patch moves the channel width configuration from iwl_ht_conf to iwl_mac_config, and defers further cleanup of the local/global conflation for a later patch. This fixes a bug in using HT40 channels in some modes. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 08345b9..104fd95 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2398,25 +2398,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->supported_chan_width = - !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); - - /* - * XXX: The HT configuration needs to be moved into iwl_mac_config() - * to be done there correctly. - */ - - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; - if (conf_is_ht40_minus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; - else if (conf_is_ht40_plus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - - /* If no above or below channel supplied disable HT40 channel */ - if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && - iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) - iwl_conf->supported_chan_width = 0; - iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); @@ -2733,6 +2714,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; struct ieee80211_conf *conf = &hw->conf; + struct iwl_ht_info *ht_conf = &priv->current_ht_config; unsigned long flags = 0; int ret = 0; u16 ch; @@ -2774,10 +2756,32 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) goto set_ch_out; } - priv->current_ht_config.is_ht = conf_is_ht(conf); - spin_lock_irqsave(&priv->lock, flags); + /* Configure HT40 channels */ + ht_conf->is_ht = conf_is_ht(conf); + if (ht_conf->is_ht) { + if (conf_is_ht40_minus(conf)) { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_40MHZ; + } else if (conf_is_ht40_plus(conf)) { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_40MHZ; + } else { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_20MHZ; + } + } else + ht_conf->supported_chan_width = IWL_CHANNEL_WIDTH_20MHZ; + /* Default to no protection. Protection mode will later be set + * from BSS config in iwl_ht_conf */ + ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; /* if we are switching from ht to 2.4 clear flags * from any ht related info since 2.4 does not -- cgit v0.10.2 From 28e6f48953f44f7eb615383efe6e7f17624a11bb Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:58 -0700 Subject: iwlwifi: check short GI support per-station rather than globally Short guard interval support is a local per-station parameter not a global per-NIC parameter. (mac80211 will correctly remove SGI support from station capabilities if the BSS does not permit it). This patch removes the short GI support bitfield from the global iwl_ht_info struct and properly uses per-station HT capabilities during rate selection. Signed-off-by: Daniel C Halperin Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 551c4ba..3b1bbc3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1225,18 +1225,6 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, else tbl->is_ht40 = 0; - /* FIXME: - don't toggle SGI here - if (tbl->is_ht40) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ - rs_set_expected_tpt_table(lq_sta, tbl); rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); @@ -1291,18 +1279,6 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, else tbl->is_ht40 = 0; - /* FIXME: - don't toggle SGI here - if (tbl->is_ht40) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ - rs_set_expected_tpt_table(lq_sta, tbl); rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); @@ -1350,18 +1326,6 @@ static int rs_switch_to_siso(struct iwl_priv *priv, else tbl->is_ht40 = 0; - /* FIXME: - don't toggle SGI here - if (tbl->is_ht40) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ - if (is_green) tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ @@ -1530,6 +1494,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); struct iwl_rate_scale_data *window = &(tbl->win[index]); + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; @@ -1589,13 +1554,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, goto out; break; case IWL_SISO_SWITCH_GI: - if (!tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: SISO toggle SGI/NGI\n"); @@ -1669,6 +1632,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); struct iwl_rate_scale_data *window = &(tbl->win[index]); + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; @@ -1729,13 +1693,11 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, break; case IWL_MIMO2_SWITCH_GI: - if (!tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n"); @@ -1811,6 +1773,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); struct iwl_rate_scale_data *window = &(tbl->win[index]); + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; @@ -1893,13 +1856,11 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, break; case IWL_MIMO3_SWITCH_GI: - if (!tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 104fd95..b845cf3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2391,11 +2391,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, } ht_conf = &sta->ht_cap; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) - iwl_conf->sgf |= HT_SHORT_GI_20MHZ; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) - iwl_conf->sgf |= HT_SHORT_GI_40MHZ; - iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index db74534..e6a1c6f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -508,7 +508,6 @@ struct iwl_ht_info { u8 supported_chan_width; u8 sm_ps; u8 is_green_field; - u8 sgf; /* HT_SHORT_GI_* short guard interval */ struct ieee80211_mcs_info mcs; /* BSS related data */ u8 extension_chan_offset; @@ -728,9 +727,6 @@ struct iwl_dma_ptr { size_t size; }; -#define HT_SHORT_GI_20MHZ (1 << 0) -#define HT_SHORT_GI_40MHZ (1 << 1) - #define IWL_CHANNEL_WIDTH_20MHZ 0 #define IWL_CHANNEL_WIDTH_40MHZ 1 -- cgit v0.10.2 From b261793da587160d12ce6d63db60493342ddce20 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:59 -0700 Subject: iwlwifi: use station HT capabilities and BSS operating mode for Green-field Green-field mode should be configured in the HT station table. This patch uses both the per-station GF support flag as well as the current BSS HT operation mode (non-GF stations present flag). Added the "ht_greenfield_support" field to struct iwl_cfg to replace the device-specific check in rs_use_green(). That check has been moved to iwlcore_init_ht_hw_capab(). Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 9bb6a28..a95caa0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -158,5 +158,6 @@ struct iwl_cfg iwl1000_bgn_cfg = { .need_pll_cfg = true, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, + .ht_greenfield_support = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index ba5ef83..b5a4d2e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2889,7 +2889,8 @@ static struct iwl_cfg iwl3945_bg_cfg = { .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2902,7 +2903,8 @@ static struct iwl_cfg iwl3945_abg_cfg = { .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; struct pci_device_id iwl3945_hw_card_ids[] = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e427a89..6a13bfb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2344,7 +2344,8 @@ struct iwl_cfg iwl4965_agn_cfg = { .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 755c184..e1e862e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1652,6 +1652,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_bg_cfg = { @@ -1668,6 +1669,7 @@ struct iwl_cfg iwl5100_bg_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -1684,6 +1686,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -1700,6 +1703,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1716,6 +1720,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1732,6 +1737,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 0b731fd..383177d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -171,6 +171,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, + .ht_greenfield_support = true, }; /* @@ -193,6 +194,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -212,6 +214,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -231,6 +234,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -250,6 +254,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, + .ht_greenfield_support = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 3b1bbc3..fee110d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -657,19 +657,15 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, return 1; } -/* in 4965 we don't use greenfield at all */ -static inline u8 rs_use_green(struct iwl_priv *priv, - struct ieee80211_conf *conf) +/** + * Green-field mode is valid if the station supports it and + * there are no non-GF stations present in the BSS. + */ +static inline u8 rs_use_green(struct ieee80211_sta *sta, + struct iwl_ht_info *ht_conf) { - u8 is_green; - - if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) - is_green = 0; - else - is_green = (conf_is_ht(conf) && - priv->current_ht_config.is_green_field && - !priv->current_ht_config.non_GF_STA_present); - return is_green; + return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && + !(ht_conf->non_GF_STA_present); } /** @@ -2072,7 +2068,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (is_legacy(tbl->lq_type)) lq_sta->is_green = 0; else - lq_sta->is_green = rs_use_green(priv, conf); + lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config); is_green = lq_sta->is_green; /* current tx rate */ @@ -2430,7 +2426,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, int rate_idx; int i; u32 rate; - u8 use_green = rs_use_green(priv, conf); + u8 use_green = rs_use_green(sta, &priv->current_ht_config); u8 active_tbl = 0; u8 valid_tx_ant; @@ -2627,7 +2623,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->is_dup = 0; lq_sta->max_rate_idx = -1; lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; - lq_sta->is_green = rs_use_green(priv, conf); + lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config); lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); lq_sta->active_rate_basic = priv->active_rate_basic; lq_sta->band = priv->band; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b845cf3..62aa87b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -394,7 +394,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->ht_supported = true; - ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + if (priv->cfg->ht_greenfield_support) + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= IEEE80211_HT_CAP_SGI_20; ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & (WLAN_HT_CAP_SM_PS_DISABLED << 2)); @@ -2391,8 +2392,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, } ht_conf = &sta->ht_cap; - iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 5096834..4ca025a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -251,6 +251,7 @@ struct iwl_cfg { enum iwl_pa_type pa_type; const u16 max_ll_items; const bool shadow_ram_support; + const bool ht_greenfield_support; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e6a1c6f..0178734 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -507,7 +507,6 @@ struct iwl_ht_info { u8 is_ht; u8 supported_chan_width; u8 sm_ps; - u8 is_green_field; struct ieee80211_mcs_info mcs; /* BSS related data */ u8 extension_chan_offset; -- cgit v0.10.2 From 15993e08ac027b64b6f3400d32754966b4cac7b0 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 13 Aug 2009 13:31:00 -0700 Subject: iwlwifi: add thermal throttling support to 5150 Adding legacy thermal throttling management support to 5150 NIC Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index e1e862e..720d234 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1411,6 +1411,7 @@ static void iwl5150_temperature(struct iwl_priv *priv) vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; /* now vt hold the temperature in Kelvin */ priv->temperature = KELVIN_TO_CELSIUS(vt); + iwl_tt_handler(priv); } /* Calc max signal level (dBm) among 3 possible receivers */ -- cgit v0.10.2 From 396887a2b2ad1ef5e5526fec34dec582baf39b81 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:31:01 -0700 Subject: iwlwifi: fix erroneous use of iwl_rx_packet.len as a length The field called 'len' in struct iwl_rx_packet is in fact not just a length field but also includes some flags from the flow handler. In several places throughout the driver, this causes incorrect values to be interpreted as lengths when the field is improperly masked. In most situations the improper use is for debugging output, and simply results in an erroneous message, such as: [551933.070224] ieee80211 phy0: I iwl_rx_statistics Statistics notification received (480 vs -1367342620). which should read '(480 vs 484)'. In at least one case this could case bad things to happen: void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " "notification for %s:\n", le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len) ); } EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); Given the rampant misuse of this field without proper masking throughout the driver (every use but one), this patch renames the field from 'len' to 'len_n_flags' to reduce confusion. It also adds the proper masking when this field is used as a length value. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index b5a4d2e..e9a685d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -349,12 +349,13 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv, * *****************************************************************************/ -void iwl3945_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +void iwl3945_hw_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (void *)rxb->skb->data; IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(struct iwl3945_notif_statistics), - le32_to_cpu(pkt->len)); + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39)); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 720d234..1d539e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -494,7 +494,7 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, { struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; - int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; + int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; int index; /* reduce the size of the length field itself */ diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 9398ad7..f430384 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3482,7 +3482,7 @@ struct iwl_wimax_coex_cmd { *****************************************************************************/ struct iwl_rx_packet { - __le32 len; + __le32 len_n_flags; struct iwl_cmd_header hdr; union { struct iwl3945_rx_frame rx_frame; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 62aa87b..f4c2431 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2294,10 +2294,11 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " - "notification for %s:\n", - le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + "notification for %s:\n", len, + get_cmd_string(pkt->hdr.cmd)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len); } EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 092d327..353d9a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -539,7 +539,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", - (int)sizeof(priv->statistics), pkt->len); + (int)sizeof(priv->statistics), + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); change = ((priv->statistics.general.temperature != pkt->u.stats.general.temperature) || -- cgit v0.10.2 From b23da49e6db341f4721476394dd8b95e0be2d179 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 13 Aug 2009 13:31:02 -0700 Subject: iwlwifi: disable PS by default Unfortunately, PS currently affects RX performance significantly enough to warrant disabling it by default, but give the user the choice to enable it again with iwconfig. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index f4c2431..c0efa66 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1580,6 +1580,12 @@ int iwl_setup_mac(struct iwl_priv *priv) /* Firmware does not support this */ hw->wiphy->disable_beacon_hints = true; + /* + * For now, disable PS by default because it affects + * RX performance significantly. + */ + hw->wiphy->ps_default = false; + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; /* we create the 802.11 header and a zero-length SSID element */ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; -- cgit v0.10.2 From 6f632d57f35303118685b88c139f3da73df077e2 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Thu, 13 Aug 2009 17:34:40 -0700 Subject: libertas: don't use dynamic-sized array sparse complains about a bad constant expression due to the use of a dynamic-sized array in get_common_rates(). Allocate and free the array instead. Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 385b50f..81f86ef 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -45,9 +45,14 @@ static int get_common_rates(struct lbs_private *priv, u8 *card_rates = lbs_bg_rates; size_t num_card_rates = sizeof(lbs_bg_rates); int ret = 0, i, j; - u8 tmp[30]; + u8 *tmp; size_t tmp_size = 0; + tmp = kzalloc((ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1), + GFP_KERNEL); + if (!tmp) + return -1; + /* For each rate in card_rates that exists in rate1, copy to tmp */ for (i = 0; card_rates[i] && (i < num_card_rates); i++) { for (j = 0; rates[j] && (j < *rates_size); j++) { @@ -77,6 +82,7 @@ done: memset(rates, 0, *rates_size); *rates_size = min_t(int, tmp_size, *rates_size); memcpy(rates, tmp, *rates_size); + kfree(tmp); return ret; } -- cgit v0.10.2 From 588f8377c5470fab611c14ead768f7f9af87da94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 13 Aug 2009 22:46:30 +0200 Subject: b43: LP-PHY: Implement channel switching for rev2+/B2063 radio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rev.2+/B2063 will now hopefully show some signs of life, though it won't work at full performance, as calibration is still missing. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 996b7ec..86da828 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -29,6 +29,25 @@ #include "tables_lpphy.h" +static inline u16 channel2freq_lp(u8 channel) +{ + if (channel < 14) + return (2407 + 5 * channel); + else if (channel == 14) + return 2484; + else if (channel < 184) + return (5000 + 5 * channel); + else + return (4000 + 5 * channel); +} + +static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + return 1; + return 36; +} + static int b43_lpphy_op_allocate(struct b43_wldev *dev) { struct b43_phy_lp *lpphy; @@ -142,10 +161,9 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev) } } -static void lpphy_adjust_gain_table(struct b43_wldev *dev) +static void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq) { struct b43_phy_lp *lpphy = dev->phy.lp; - u32 freq = dev->wl->hw->conf.channel->center_freq; u16 temp[3]; u16 isolation; @@ -170,6 +188,8 @@ static void lpphy_adjust_gain_table(struct b43_wldev *dev) static void lpphy_table_init(struct b43_wldev *dev) { + u32 freq = channel2freq_lp(b43_lpphy_op_get_default_chan(dev)); + if (dev->phy.rev < 2) lpphy_rev0_1_table_init(dev); else @@ -178,7 +198,7 @@ static void lpphy_table_init(struct b43_wldev *dev) lpphy_init_tx_gain_table(dev); if (dev->phy.rev < 2) - lpphy_adjust_gain_table(dev); + lpphy_adjust_gain_table(dev, freq); } static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) @@ -1363,20 +1383,6 @@ static void lpphy_tx_pctl_init(struct b43_wldev *dev) } } -static int b43_lpphy_op_init(struct b43_wldev *dev) -{ - lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? - lpphy_baseband_init(dev); - lpphy_radio_init(dev); - lpphy_calibrate_rc(dev); - //TODO set channel - lpphy_tx_pctl_init(dev); - lpphy_calibration(dev); - //TODO ACI init - - return 0; -} - static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) { b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); @@ -1419,18 +1425,392 @@ static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, //TODO } +struct b206x_channel { + u8 channel; + u16 freq; + u8 data[12]; +}; + +static const struct b206x_channel b2063_chantbl[] = { + { .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C, + .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 2, .freq = 2417, .data[0] = 0x6F, .data[1] = 0x3C, + .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 3, .freq = 2422, .data[0] = 0x6F, .data[1] = 0x3C, + .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 4, .freq = 2427, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 5, .freq = 2432, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 6, .freq = 2437, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 7, .freq = 2442, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 8, .freq = 2447, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 9, .freq = 2452, .data[0] = 0x6F, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 10, .freq = 2457, .data[0] = 0x6F, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 11, .freq = 2462, .data[0] = 0x6E, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 12, .freq = 2467, .data[0] = 0x6E, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 13, .freq = 2472, .data[0] = 0x6E, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 14, .freq = 2484, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 34, .freq = 5170, .data[0] = 0x6A, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x02, .data[5] = 0x05, + .data[6] = 0x0D, .data[7] = 0x0D, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 36, .freq = 5180, .data[0] = 0x6A, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x05, + .data[6] = 0x0D, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 38, .freq = 5190, .data[0] = 0x6A, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04, + .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 40, .freq = 5200, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04, + .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 42, .freq = 5210, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04, + .data[6] = 0x0B, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 44, .freq = 5220, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x04, + .data[6] = 0x0B, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 46, .freq = 5230, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03, + .data[6] = 0x0A, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 48, .freq = 5240, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03, + .data[6] = 0x0A, .data[7] = 0x0A, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 52, .freq = 5260, .data[0] = 0x68, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x02, + .data[6] = 0x09, .data[7] = 0x09, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 56, .freq = 5280, .data[0] = 0x68, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01, + .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50, + .data[10] = 0x10, .data[11] = 0x00, }, + { .channel = 60, .freq = 5300, .data[0] = 0x68, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01, + .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50, + .data[10] = 0x10, .data[11] = 0x00, }, + { .channel = 64, .freq = 5320, .data[0] = 0x67, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50, + .data[10] = 0x10, .data[11] = 0x00, }, + { .channel = 100, .freq = 5500, .data[0] = 0x64, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x02, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 104, .freq = 5520, .data[0] = 0x64, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x01, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 108, .freq = 5540, .data[0] = 0x63, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x01, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 112, .freq = 5560, .data[0] = 0x63, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 116, .freq = 5580, .data[0] = 0x62, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 120, .freq = 5600, .data[0] = 0x62, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 124, .freq = 5620, .data[0] = 0x62, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 128, .freq = 5640, .data[0] = 0x61, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 132, .freq = 5660, .data[0] = 0x61, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 136, .freq = 5680, .data[0] = 0x61, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 140, .freq = 5700, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 149, .freq = 5745, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 153, .freq = 5765, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 157, .freq = 5785, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 161, .freq = 5805, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 165, .freq = 5825, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 184, .freq = 4920, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0E, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xC0, + .data[10] = 0x50, .data[11] = 0x00, }, + { .channel = 188, .freq = 4940, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0D, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0, + .data[10] = 0x50, .data[11] = 0x00, }, + { .channel = 192, .freq = 4960, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0, + .data[10] = 0x50, .data[11] = 0x00, }, + { .channel = 196, .freq = 4980, .data[0] = 0x6D, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 200, .freq = 5000, .data[0] = 0x6D, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0B, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 204, .freq = 5020, .data[0] = 0x6D, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0A, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 208, .freq = 5040, .data[0] = 0x6C, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x07, .data[5] = 0x09, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 212, .freq = 5060, .data[0] = 0x6C, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x06, .data[5] = 0x08, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 216, .freq = 5080, .data[0] = 0x6C, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x05, .data[5] = 0x08, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90, + .data[10] = 0x40, .data[11] = 0x00, }, +}; + +static void lpphy_b2062_tune(struct b43_wldev *dev, + unsigned int channel) +{ + //TODO +} + +static void lpphy_b2063_vco_calib(struct b43_wldev *dev) +{ + u16 tmp; + + b43_phy_mask(dev, B2063_PLL_SP1, ~0x40); + tmp = b43_phy_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8; + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp); + udelay(1); + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4); + udelay(1); + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6); + udelay(1); + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7); + udelay(300); + b43_phy_set(dev, B2063_PLL_SP1, 0x40); +} + +static void lpphy_b2063_tune(struct b43_wldev *dev, + unsigned int channel) +{ + struct ssb_bus *bus = dev->dev->bus; + + static const struct b206x_channel *chandata = NULL; + u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; + u32 freqref, vco_freq, val1, val2, val3, timeout, timeoutref, count; + u16 old_comm15, scale; + u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + int i, div = (crystal_freq <= 26000000 ? 1 : 2); + + for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) { + if (b2063_chantbl[i].channel == channel) { + chandata = &b2063_chantbl[i]; + break; + } + } + + if (B43_WARN_ON(!chandata)) + return; + + b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]); + b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]); + b43_radio_write(dev, B2063_LOGEN_BUF2, chandata->data[2]); + b43_radio_write(dev, B2063_LOGEN_RCCR1, chandata->data[3]); + b43_radio_write(dev, B2063_A_RX_1ST3, chandata->data[4]); + b43_radio_write(dev, B2063_A_RX_2ND1, chandata->data[5]); + b43_radio_write(dev, B2063_A_RX_2ND4, chandata->data[6]); + b43_radio_write(dev, B2063_A_RX_2ND7, chandata->data[7]); + b43_radio_write(dev, B2063_A_RX_PS6, chandata->data[8]); + b43_radio_write(dev, B2063_TX_RF_CTL2, chandata->data[9]); + b43_radio_write(dev, B2063_TX_RF_CTL5, chandata->data[10]); + b43_radio_write(dev, B2063_PA_CTL11, chandata->data[11]); + + old_comm15 = b43_radio_read(dev, B2063_COMM15); + b43_radio_set(dev, B2063_COMM15, 0x1E); + + if (chandata->freq > 4000) /* spec says 2484, but 4000 is safer */ + vco_freq = chandata->freq << 1; + else + vco_freq = chandata->freq << 2; + + freqref = crystal_freq * 3; + val1 = lpphy_qdiv_roundup(crystal_freq, 1000000, 16); + val2 = lpphy_qdiv_roundup(crystal_freq, 1000000 * div, 16); + val3 = lpphy_qdiv_roundup(vco_freq, 3, 16); + timeout = ((((8 * crystal_freq) / (div * 5000000)) + 1) >> 1) - 1; + b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB3, 0x2); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB6, + 0xFFF8, timeout >> 2); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7, + 0xFF9F,timeout << 5); + + timeoutref = ((((8 * crystal_freq) / (div * (timeout + 1))) + + 999999) / 1000000) + 1; + b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB5, timeoutref); + + count = lpphy_qdiv_roundup(val3, val2 + 16, 16); + count *= (timeout + 1) * (timeoutref + 1); + count--; + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7, + 0xF0, count >> 8); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB8, count & 0xFF); + + tmp1 = ((val3 * 62500) / freqref) << 4; + tmp2 = ((val3 * 62500) % freqref) << 4; + while (tmp2 >= freqref) { + tmp1++; + tmp2 -= freqref; + } + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG1, 0xFFE0, tmp1 >> 4); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFE0F, tmp1 << 4); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFFF0, tmp1 >> 16); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG3, (tmp2 >> 8) & 0xFF); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG4, tmp2 & 0xFF); + + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF1, 0xB9); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF2, 0x88); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF3, 0x28); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF4, 0x63); + + tmp3 = ((41 * (val3 - 3000)) /1200) + 27; + tmp4 = lpphy_qdiv_roundup(132000 * tmp1, 8451, 16); + + if ((tmp4 + tmp3 - 1) / tmp3 > 60) { + scale = 1; + tmp5 = ((tmp4 + tmp3) / (tmp3 << 1)) - 8; + } else { + scale = 0; + tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8; + } + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5); + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6); + + tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16); + tmp6 *= (tmp5 * 8) * (scale + 1); + if (tmp6 > 150) + tmp6 = 0; + + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6); + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5); + + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4); + if (crystal_freq > 26000000) + b43_phy_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2); + else + b43_phy_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD); + + if (val1 == 45) + b43_phy_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2); + else + b43_phy_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD); + + b43_phy_set(dev, B2063_PLL_SP2, 0x3); + udelay(1); + b43_phy_mask(dev, B2063_PLL_SP2, 0xFFFC); + lpphy_b2063_vco_calib(dev); + b43_radio_write(dev, B2063_COMM15, old_comm15); +} + static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { - //TODO + b43_write16(dev, B43_MMIO_CHANNEL, new_channel); + + if (dev->phy.radio_ver == 0x2063) { + lpphy_b2063_tune(dev, new_channel); + } else { + lpphy_b2062_tune(dev, new_channel); + //TODO Japan filter + } + + lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); + return 0; } -static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) +static int b43_lpphy_op_init(struct b43_wldev *dev) { - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - return 1; - return 36; + lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? + lpphy_baseband_init(dev); + lpphy_radio_init(dev); + lpphy_calibrate_rc(dev); + b43_lpphy_op_switch_channel(dev, b43_lpphy_op_get_default_chan(dev)); + lpphy_tx_pctl_init(dev); + lpphy_calibration(dev); + //TODO ACI init + + return 0; } static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) -- cgit v0.10.2 From 1e711bee566e26f03e51d5a754e7c8a57e489f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 14 Aug 2009 00:15:17 +0200 Subject: b43: LP-PHY: Implement channel switching for rev0/1/B2062 radio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Move pdiv from lpphy_2062_init to struct b43_phy_lp. -Add channel table for the B2062 radio. -Add code for tuning the B2062 radio to channel. -Add error handling to op_switch_channel, and use it for both radios. Rev0/1/B2062 will now hopefully show some signs of life, though it won't work at full performance, as calibration is still missing. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 86da828..e010268 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -455,8 +455,9 @@ struct b2062_freqdata { /* Initialize the 2062 radio. */ static void lpphy_2062_init(struct b43_wldev *dev) { + struct b43_phy_lp *lpphy = dev->phy.lp; struct ssb_bus *bus = dev->dev->bus; - u32 crystalfreq, pdiv, tmp, ref; + u32 crystalfreq, tmp, ref; unsigned int i; const struct b2062_freqdata *fd = NULL; @@ -496,22 +497,24 @@ static void lpphy_2062_init(struct b43_wldev *dev) B43_WARN_ON(crystalfreq == 0); if (crystalfreq >= 30000000) { - pdiv = 1; + lpphy->pdiv = 1; b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB); } else { - pdiv = 2; + lpphy->pdiv = 2; b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4); } - tmp = (800000000 * pdiv + crystalfreq) / (32000000 * pdiv); + tmp = (800000000 * lpphy->pdiv + crystalfreq) / + (32000000 * lpphy->pdiv); tmp = (tmp - 1) & 0xFF; b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp); - tmp = (2 * crystalfreq + 1000000 * pdiv) / (2000000 * pdiv); + tmp = (2 * crystalfreq + 1000000 * lpphy->pdiv) / + (2000000 * lpphy->pdiv); tmp = ((tmp & 0xFF) - 1) & 0xFFFF; b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp); - ref = (1000 * pdiv + 2 * crystalfreq) / (2000 * pdiv); + ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv); ref &= 0xFFFF; for (i = 0; i < ARRAY_SIZE(freqdata_tab); i++) { if (ref < freqdata_tab[i].freq) { @@ -1431,6 +1434,162 @@ struct b206x_channel { u8 data[12]; }; +static const struct b206x_channel b2062_chantbl[] = { + { .channel = 1, .freq = 2412, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 2, .freq = 2417, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 3, .freq = 2422, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 4, .freq = 2427, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 5, .freq = 2432, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 6, .freq = 2437, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 7, .freq = 2442, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 8, .freq = 2447, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 9, .freq = 2452, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 10, .freq = 2457, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 11, .freq = 2462, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 12, .freq = 2467, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 13, .freq = 2472, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 14, .freq = 2484, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 34, .freq = 5170, .data[0] = 0x00, .data[1] = 0x22, + .data[2] = 0x20, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 38, .freq = 5190, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 42, .freq = 5210, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 46, .freq = 5230, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 36, .freq = 5180, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x20, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 40, .freq = 5200, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x10, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 44, .freq = 5220, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 48, .freq = 5240, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 52, .freq = 5260, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 56, .freq = 5280, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 60, .freq = 5300, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x63, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 64, .freq = 5320, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x62, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 100, .freq = 5500, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x30, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 104, .freq = 5520, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 108, .freq = 5540, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 112, .freq = 5560, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 116, .freq = 5580, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x10, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 120, .freq = 5600, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 124, .freq = 5620, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 128, .freq = 5640, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 132, .freq = 5660, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 136, .freq = 5680, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 140, .freq = 5700, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 149, .freq = 5745, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 153, .freq = 5765, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 157, .freq = 5785, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 161, .freq = 5805, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 165, .freq = 5825, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 184, .freq = 4920, .data[0] = 0x55, .data[1] = 0x77, + .data[2] = 0x90, .data[3] = 0xF7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 188, .freq = 4940, .data[0] = 0x44, .data[1] = 0x77, + .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 192, .freq = 4960, .data[0] = 0x44, .data[1] = 0x66, + .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 196, .freq = 4980, .data[0] = 0x33, .data[1] = 0x66, + .data[2] = 0x70, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 200, .freq = 5000, .data[0] = 0x22, .data[1] = 0x55, + .data[2] = 0x60, .data[3] = 0xD7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 204, .freq = 5020, .data[0] = 0x22, .data[1] = 0x55, + .data[2] = 0x60, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 208, .freq = 5040, .data[0] = 0x22, .data[1] = 0x44, + .data[2] = 0x50, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 212, .freq = 5060, .data[0] = 0x11, .data[1] = 0x44, + .data[2] = 0x50, .data[3] = 0xA5, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 216, .freq = 5080, .data[0] = 0x00, .data[1] = 0x44, + .data[2] = 0x40, .data[3] = 0xB6, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, +}; + static const struct b206x_channel b2063_chantbl[] = { { .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C, .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, @@ -1638,10 +1797,110 @@ static const struct b206x_channel b2063_chantbl[] = { .data[10] = 0x40, .data[11] = 0x00, }, }; -static void lpphy_b2062_tune(struct b43_wldev *dev, - unsigned int channel) +static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev) { - //TODO + struct ssb_bus *bus = dev->dev->bus; + + b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF); + udelay(20); + if (bus->chip_id == 0x5354) { + b43_radio_write(dev, B2062_N_COMM1, 4); + b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4); + } else { + b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0); + } + udelay(5); +} + +static void lpphy_b2062_vco_calib(struct b43_wldev *dev) +{ + b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x42); + b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x62); + udelay(200); +} + +static int lpphy_b2062_tune(struct b43_wldev *dev, + unsigned int channel) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + struct ssb_bus *bus = dev->dev->bus; + static const struct b206x_channel *chandata = NULL; + u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; + u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; + int i, err = 0; + + for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) { + if (b2063_chantbl[i].channel == channel) { + chandata = &b2063_chantbl[i]; + break; + } + } + + if (B43_WARN_ON(!chandata)) + return -EINVAL; + + b43_radio_set(dev, B2062_S_RFPLL_CTL14, 0x04); + b43_radio_write(dev, B2062_N_LGENA_TUNE0, chandata->data[0]); + b43_radio_write(dev, B2062_N_LGENA_TUNE2, chandata->data[1]); + b43_radio_write(dev, B2062_N_LGENA_TUNE3, chandata->data[2]); + b43_radio_write(dev, B2062_N_TX_TUNE, chandata->data[3]); + b43_radio_write(dev, B2062_S_LGENG_CTL1, chandata->data[4]); + b43_radio_write(dev, B2062_N_LGENA_CTL5, chandata->data[5]); + b43_radio_write(dev, B2062_N_LGENA_CTL6, chandata->data[6]); + b43_radio_write(dev, B2062_N_TX_PGA, chandata->data[7]); + b43_radio_write(dev, B2062_N_TX_PAD, chandata->data[8]); + + tmp1 = crystal_freq / 1000; + tmp2 = lpphy->pdiv * 1000; + b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xCC); + b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0x07); + lpphy_b2062_reset_pll_bias(dev); + tmp3 = tmp2 * channel2freq_lp(channel); + if (channel2freq_lp(channel) < 4000) + tmp3 *= 2; + tmp4 = 48 * tmp1; + tmp6 = tmp3 / tmp4; + tmp7 = tmp3 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL26, tmp6); + tmp5 = tmp7 * 0x100; + tmp6 = tmp5 / tmp4; + tmp7 = tmp5 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6); + tmp5 = tmp7 * 0x100; + tmp6 = tmp5 / tmp4; + tmp7 = tmp5 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4)); + tmp8 = b43_phy_read(dev, B2062_S_RFPLL_CTL19); + tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1); + b43_radio_write(dev, B2062_S_RFPLL_CTL23, tmp9 >> 8); + b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF); + + lpphy_b2062_vco_calib(dev); + if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) { + b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xFC); + b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0); + lpphy_b2062_reset_pll_bias(dev); + lpphy_b2062_vco_calib(dev); + if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) + err = -EINVAL; + } + + b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04); + return err; +} + +static void lpphy_japan_filter(struct b43_wldev *dev, int channel) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter! + + if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific? + b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9); + if ((dev->phy.rev == 1) && (lpphy->rc_cap)) + lpphy_set_rc_cap(dev); + } else { + b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F); + } } static void lpphy_b2063_vco_calib(struct b43_wldev *dev) @@ -1661,8 +1920,8 @@ static void lpphy_b2063_vco_calib(struct b43_wldev *dev) b43_phy_set(dev, B2063_PLL_SP1, 0x40); } -static void lpphy_b2063_tune(struct b43_wldev *dev, - unsigned int channel) +static int lpphy_b2063_tune(struct b43_wldev *dev, + unsigned int channel) { struct ssb_bus *bus = dev->dev->bus; @@ -1681,7 +1940,7 @@ static void lpphy_b2063_tune(struct b43_wldev *dev, } if (B43_WARN_ON(!chandata)) - return; + return -EINVAL; b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]); b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]); @@ -1780,18 +2039,26 @@ static void lpphy_b2063_tune(struct b43_wldev *dev, b43_phy_mask(dev, B2063_PLL_SP2, 0xFFFC); lpphy_b2063_vco_calib(dev); b43_radio_write(dev, B2063_COMM15, old_comm15); + + return 0; } static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { + int err; + b43_write16(dev, B43_MMIO_CHANNEL, new_channel); if (dev->phy.radio_ver == 0x2063) { - lpphy_b2063_tune(dev, new_channel); + err = lpphy_b2063_tune(dev, new_channel); + if (err) + return err; } else { - lpphy_b2062_tune(dev, new_channel); - //TODO Japan filter + err = lpphy_b2062_tune(dev, new_channel); + if (err) + return err; + lpphy_japan_filter(dev, new_channel); } lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 4eab760..99cb038 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -884,6 +884,8 @@ struct b43_phy_lp { /* Used for "Save/Restore Dig Filt State" */ u16 dig_flt_state[9]; + + unsigned int pdiv; }; enum tssi_mux_mode { -- cgit v0.10.2 From db91f2e4d410bf3011b3649b9257e5b3c60b25ff Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 14 Aug 2009 11:27:16 +0530 Subject: ath9k: Add open loop power control support for AR9287. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 26d8752..20f74b5 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -729,26 +729,42 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) static void ath9k_olc_temp_compensation(struct ath_hw *ah) { u32 rddata, i; - int delta, currPDADC, regval; + int delta, currPDADC, regval, slope; rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); - currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); - if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) - delta = (currPDADC - ah->initPDADC + 4) / 8; - else - delta = (currPDADC - ah->initPDADC + 5) / 10; - if (delta != ah->PDADCdelta) { - ah->PDADCdelta = delta; - for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { - regval = ah->originalGain[i] - delta; - if (regval < 0) - regval = 0; + if (OLC_FOR_AR9287_10_LATER) { + if (ah->initPDADC == 0 || currPDADC == 0) { + return; + } else { + slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE); + if (slope == 0) + delta = 0; + else + delta = ((currPDADC - ah->initPDADC)*4) / slope; + REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, + AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); + REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, + AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); + } + } else { + if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) + delta = (currPDADC - ah->initPDADC + 4) / 8; + else + delta = (currPDADC - ah->initPDADC + 5) / 10; + + if (delta != ah->PDADCdelta) { + ah->PDADCdelta = delta; + for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { + regval = ah->originalGain[i] - delta; + if (regval < 0) + regval = 0; - REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, - AR_PHY_TX_GAIN, regval); + REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, + AR_PHY_TX_GAIN, regval); + } } } } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9f1b34d..125e689 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1332,11 +1332,21 @@ static void ath9k_olc_init(struct ath_hw *ah) { u32 i; - for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) - ah->originalGain[i] = - MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), - AR_PHY_TX_GAIN); - ah->PDADCdelta = 0; + if (OLC_FOR_AR9287_10_LATER) { + REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9, + AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TXPC0, + AR9287_AN_TXPC0_TXPCMODE, + AR9287_AN_TXPC0_TXPCMODE_S, + AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE); + udelay(100); + } else { + for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) + ah->originalGain[i] = + MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), + AR_PHY_TX_GAIN); + ah->PDADCdelta = 0; + } } static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index e83cd4a..dfda6f4 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -490,11 +490,18 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_TX_PWRCTRL9 0xa27C #define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 #define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 +#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000 +#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31 #define AR_PHY_TX_GAIN_TBL1 0xa300 #define AR_PHY_TX_GAIN 0x0007F000 #define AR_PHY_TX_GAIN_S 12 +#define AR_PHY_CH0_TX_PWRCTRL11 0xa398 +#define AR_PHY_CH1_TX_PWRCTRL11 0xb398 +#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00 +#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10 + #define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 #define AR_PHY_MASK2_M_31_45 0xa3a4 #define AR_PHY_MASK2_M_16_30 0xa3a8 -- cgit v0.10.2 From d340b1f0e5e374fc902a020cb6ef9ebd7fb9f368 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 14 Aug 2009 11:29:27 +0530 Subject: ath9k: Set AR_WA for AR9287 as it improves consistency in throughput. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 125e689..9a139dc 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3073,7 +3073,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) if (ah->config.pcie_waen) { REG_WRITE(ah, AR_WA, ah->config.pcie_waen); } else { - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); /* * On AR9280 chips bit 22 of 0x4004 needs to be set to -- cgit v0.10.2 From 08fc5c1ba026de0904aeeba9785f95f6603d58f7 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 14 Aug 2009 11:30:52 +0530 Subject: ath9k: Enable LEDs for AR9287 chipsets. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2fd663c..2c9f662 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -454,7 +454,8 @@ struct ath_ani { /* LED Control */ /********************/ -#define ATH_LED_PIN 1 +#define ATH_LED_PIN_DEF 1 +#define ATH_LED_PIN_9287 8 #define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ #define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 0336981..de31a15 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -522,6 +522,7 @@ struct ath_hw { u32 originalGain[22]; int initPDADC; int PDADCdelta; + u8 led_pin; struct ar5416IniArray iniModes; struct ar5416IniArray iniCommon; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index fa4c6e7..3e09b9a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -968,9 +968,9 @@ static void ath_led_blink_work(struct work_struct *work) if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); else - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); ieee80211_queue_delayed_work(sc->hw, @@ -1002,7 +1002,7 @@ static void ath_led_brightness(struct led_classdev *led_cdev, case LED_OFF: if (led->led_type == ATH_LED_ASSOC || led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (led->led_type == ATH_LED_RADIO)); sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; if (led->led_type == ATH_LED_RADIO) @@ -1017,7 +1017,7 @@ static void ath_led_brightness(struct led_classdev *led_cdev, ieee80211_queue_delayed_work(sc->hw, &sc->ath_led_blink_work, 0); } else if (led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); sc->sc_flags |= SC_OP_LED_ON; } else { sc->led_on_cnt++; @@ -1062,7 +1062,7 @@ static void ath_deinit_leds(struct ath_softc *sc) ath_unregister_led(&sc->tx_led); ath_unregister_led(&sc->rx_led); ath_unregister_led(&sc->radio_led); - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); } static void ath_init_leds(struct ath_softc *sc) @@ -1070,11 +1070,16 @@ static void ath_init_leds(struct ath_softc *sc) char *trigger; int ret; + if (AR_SREV_9287(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9287; + else + sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + /* Configure gpio 1 for output */ - ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); /* LED off, active low */ - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); @@ -1153,9 +1158,9 @@ void ath_radio_enable(struct ath_softc *sc) ath9k_hw_set_interrupts(ah, sc->imask); /* Enable LED */ - ath9k_hw_cfg_output(ah, ATH_LED_PIN, + ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0); + ath9k_hw_set_gpio(ah, ah->led_pin, 0); ieee80211_wake_queues(sc->hw); ath9k_ps_restore(sc); @@ -1171,8 +1176,8 @@ void ath_radio_disable(struct ath_softc *sc) ieee80211_stop_queues(sc->hw); /* Disable LED */ - ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1); - ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN); + ath9k_hw_set_gpio(ah, ah->led_pin, 1); + ath9k_hw_cfg_gpio_input(ah, ah->led_pin); /* Disable interrupts */ ath9k_hw_set_interrupts(ah, 0); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 616bdff..685a8ce 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -236,7 +236,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); pci_save_state(pdev); pci_disable_device(pdev); @@ -269,9 +269,9 @@ static int ath_pci_resume(struct pci_dev *pdev) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); /* Enable LED */ - ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); return 0; } -- cgit v0.10.2 From d4fe5afa006bf308962877c4768c4e60d37a3da2 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 14 Aug 2009 11:32:04 +0530 Subject: ath9k: Fix ref power interpolation logic for AR9287 chipsets. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index aeb7f48..9590979 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -374,7 +374,6 @@ static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, u8 *pCalChans, u16 availPiers, int8_t *pPwr) { - u8 pcdac, i = 0; u16 idxL = 0, idxR = 0, numPiers; bool match; struct chan_centers centers; @@ -392,17 +391,12 @@ static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, &idxL, &idxR); if (match) { - pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; - *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; + *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0]; } else { - pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; - *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + - pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; + *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] + + (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; } - while ((pcdac > ah->originalGain[i]) && - (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) - i++; } static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, -- cgit v0.10.2 From 326bebbcb51d3ce9761f616b8b9a35827fd9c697 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 14 Aug 2009 11:33:36 +0530 Subject: ath9k: Updates for AR9287_12 version of chipset. Enable AsyncFIFO and AGGWEP for AR9287_12 and later revisions only. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9a139dc..df62113 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2392,7 +2392,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9280_10_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); - if (AR_SREV_9287_10_OR_LATER(ah)) { + if (AR_SREV_9287_12_OR_LATER(ah)) { /* Enable ASYNC FIFO */ REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL); @@ -2478,7 +2478,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_init_user_settings(ah); - if (AR_SREV_9287_10_OR_LATER(ah)) { + if (AR_SREV_9287_12_OR_LATER(ah)) { REG_WRITE(ah, AR_D_GBL_IFS_SIFS, AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR); REG_WRITE(ah, AR_D_GBL_IFS_SLOT, @@ -2494,7 +2494,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN, AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL); } - if (AR_SREV_9287_10_OR_LATER(ah)) { + if (AR_SREV_9287_12_OR_LATER(ah)) { REG_SET_BIT(ah, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_ENABLE_AGGWEP); } diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 13fd658..c9e1ac9 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -744,6 +744,7 @@ #define AR_SREV_VERSION_9287 0x180 #define AR_SREV_REVISION_9287_10 0 #define AR_SREV_REVISION_9287_11 1 +#define AR_SREV_REVISION_9287_12 2 #define AR_SREV_VERSION_9271 0x140 #define AR_SREV_REVISION_9271_10 0 #define AR_SREV_REVISION_9271_11 1 @@ -817,7 +818,13 @@ (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11))) - +#define AR_SREV_9287_12(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_12)) +#define AR_SREV_9287_12_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_12))) #define AR_SREV_9271(_ah) \ (((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271) #define AR_SREV_9271_10(_ah) \ -- cgit v0.10.2 From c46aaba74f37448f0a1a3e911230834b7ebe514f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 14 Aug 2009 13:23:05 +0200 Subject: p54: disable PS by default Johannes kindly pointed out that I completely missed a hunk in his patch: "[PATCH] cfg80211: allow driver to override PS default". The driver must explicitly set ps_default to false, as the setting is pre-filled with the kconfig default. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 4a741df..77203e3 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -575,6 +575,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 + sizeof(struct p54_tx_data); + /* + * For now, disable PS by default because it affects + * link stability significantly. + */ + dev->wiphy->ps_default = false; + mutex_init(&priv->conf_mutex); mutex_init(&priv->eeprom_mutex); init_completion(&priv->eeprom_comp); -- cgit v0.10.2 From f0ea6ce14ae2a72a353ddf8ab370c09ba403d897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 14 Aug 2009 14:11:53 +0200 Subject: ssb: Fix typo in the rev8 SPROM extraction routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No comment. :-) Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 593fc61..f853d56 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -480,7 +480,7 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) /* extract the MAC address */ for (i = 0; i < 3; i++) { - v = in[SPOFF(SSB_SPROM1_IL0MAC) + i]; + v = in[SPOFF(SSB_SPROM8_IL0MAC) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0); -- cgit v0.10.2 From 759b973bb2d24adecaa526957435eabb00f02725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 14 Aug 2009 14:39:53 +0200 Subject: b43: Add LP-PHY firmware loading support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for loading LP-PHY firmware to b43_try_request_fw. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index f6d039e..2a75beb 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1955,8 +1955,12 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) filename = "ucode5"; else if ((rev >= 11) && (rev <= 12)) filename = "ucode11"; - else if (rev >= 13) + else if (rev == 13) filename = "ucode13"; + else if (rev == 14) + filename = "ucode14"; + else if (rev >= 15) + filename = "ucode15"; else goto err_no_ucode; err = b43_do_request_fw(ctx, filename, &fw->ucode); @@ -2004,6 +2008,16 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) else goto err_no_initvals; break; + case B43_PHYTYPE_LP: + if (rev == 13) + filename = "lp0initvals13"; + else if (rev == 14) + filename = "lp0initvals14"; + else if (rev >= 15) + filename = "lp0initvals15"; + else + goto err_no_initvals; + break; default: goto err_no_initvals; } @@ -2038,6 +2052,16 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) else goto err_no_initvals; break; + case B43_PHYTYPE_LP: + if (rev == 13) + filename = "lp0bsinitvals13"; + else if (rev == 14) + filename = "lp0bsinitvals14"; + else if (rev >= 15) + filename = "lp0bsinitvals15"; + else + goto err_no_initvals; + break; default: goto err_no_initvals; } -- cgit v0.10.2 From 9d86a2d531c722feb0046e5a0b81809efb10422a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 14 Aug 2009 14:54:46 +0200 Subject: b43: Make LP-PHY testable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Enable rate memory init for LP-PHY (same as G and N-PHY). -Mark rev.2 LP-PHYs with the B2063 radio as supported. -Allow using the 5GHz band on LP-PHYs. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2a75beb..99b41ce 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2589,6 +2589,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev) case B43_PHYTYPE_A: case B43_PHYTYPE_G: case B43_PHYTYPE_N: + case B43_PHYTYPE_LP: b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1); @@ -3817,7 +3818,7 @@ static int b43_phy_versioning(struct b43_wldev *dev) #endif #ifdef CONFIG_B43_PHY_LP case B43_PHYTYPE_LP: - if (phy_rev > 1) + if (phy_rev > 2) unsupported = 1; break; #endif @@ -3874,7 +3875,7 @@ static int b43_phy_versioning(struct b43_wldev *dev) unsupported = 1; break; case B43_PHYTYPE_LP: - if (radio_ver != 0x2062) + if (radio_ver != 0x2062 && radio_ver != 0x2063) unsupported = 1; break; default: @@ -4512,9 +4513,10 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) case B43_PHYTYPE_A: have_5ghz_phy = 1; break; + case B43_PHYTYPE_LP: //FIXME not always! + have_5ghz_phy = 1; case B43_PHYTYPE_G: case B43_PHYTYPE_N: - case B43_PHYTYPE_LP: have_2ghz_phy = 1; break; default: @@ -4529,7 +4531,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) } if (1 /* disable A-PHY */) { /* FIXME: For now we disable the A-PHY on multi-PHY devices. */ - if (dev->phy.type != B43_PHYTYPE_N) { + if (dev->phy.type != B43_PHYTYPE_N && + dev->phy.type != B43_PHYTYPE_LP) { have_2ghz_phy = 1; have_5ghz_phy = 0; } -- cgit v0.10.2 From 0c61bb9a410de6ef36b4a473ced34f983a87db35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 14 Aug 2009 21:11:59 +0200 Subject: b43: LP-PHY: Don't adjust gain table for rev2+ when setting channel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rev2+ never needs to have gain tables adjusted according to the spec. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index e010268..ce81920 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -2059,10 +2059,9 @@ static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, if (err) return err; lpphy_japan_filter(dev, new_channel); + lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); } - lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); - return 0; } -- cgit v0.10.2 From 16373f652523705aa07bf78b4f388d96feb8f9d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 14 Aug 2009 22:10:34 +0200 Subject: b43: LP-PHY: Update TX gain override for a spec typo fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index ce81920..18d517c 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -747,7 +747,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev, b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7); b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14); } - b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 4); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 6); } static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain) -- cgit v0.10.2 From 1245684c631844d52079fb3fa1fcb57cc1213e5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 14 Aug 2009 23:00:32 +0200 Subject: b43: LP-PHY: Fix another TX power control abuse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should fix the remaining WARN_ON. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 18d517c..038a59d 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1059,7 +1059,8 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) bool old_txg_ovr; u8 old_bbmult; u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval, - old_rf2_ovr, old_rf2_ovrval, old_phy_ctl, old_txpctl; + old_rf2_ovr, old_rf2_ovrval, old_phy_ctl; + enum b43_lpphy_txpctl_mode old_txpctl; u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0; int loopback, i, j, inner_sum; @@ -1077,8 +1078,8 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2); old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL); old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL); - old_txpctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD) & - B43_LPPHY_TX_PWR_CTL_CMD_MODE; + lpphy_read_tx_pctl_mode_from_hardware(dev); + old_txpctl = lpphy->txpctl_mode; lpphy_set_tx_power_control(dev, B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF); lpphy_disable_crs(dev); -- cgit v0.10.2 From 826ee70664c658a022d999f7eb4d3cd9448895dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Sat, 15 Aug 2009 00:52:02 +0200 Subject: b43: Handle B43_PHYTYPE_LP in RX path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't drop all packets received from an LP-PHY with WARN_ON. Also update a comment with LP-specific information. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index 73e97fa..97c7916 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c @@ -628,7 +628,7 @@ void b43_wa_all(struct b43_wldev *dev) B43_WARN_ON(1); } b43_wa_boards_g(dev); - } else { /* No N PHY support so far */ + } else { /* No N PHY support so far, LP PHY is in phy_lp.c */ B43_WARN_ON(1); } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 5280ebc..be1c53e 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -655,6 +655,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) status.freq = chanid + 2400; break; case B43_PHYTYPE_N: + case B43_PHYTYPE_LP: /* chanid is the SHM channel cookie. Which is the plain * channel number in b43. */ if (chanstat & B43_RX_CHAN_5GHZ) { -- cgit v0.10.2 From 96909e97716de1d86e6e24d6aabce09980372771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Sun, 16 Aug 2009 01:15:49 +0200 Subject: b43: LP-PHY: Update baseband init for recent spec changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spec had some nasty typos, and a large part of the rev0/1 BB init procedure was also missing. Fix these. Also make the init-time channel switch debuggable. (The change from -EINVAL to -EIO is simply to make it possible to distinguish the PLL charge pump error from a channel-not-found error.) Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 038a59d..85af82a 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -204,8 +204,62 @@ static void lpphy_table_init(struct b43_wldev *dev) static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; + struct b43_phy_lp *lpphy = dev->phy.lp; u16 tmp, tmp2; + b43_phy_mask(dev, B43_LPPHY_AFE_DAC_CTL, 0xF7FF); + b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0); + b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0); + b43_phy_set(dev, B43_LPPHY_AFE_DAC_CTL, 0x0004); + b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x0078); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800); + b43_phy_write(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x0016); + b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_0, 0xFFF8, 0x0004); + b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5400); + b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2400); + b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100); + b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006); + b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC10, 0x0180); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3800); + b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005); + b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A); + b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3); + b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00); + b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB, + 0xFF00, lpphy->rx_pwr_offset); + if ((bus->sprom.boardflags_lo & B43_BFL_FEM) && + ((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) || + (bus->sprom.boardflags_hi & B43_BFH_PAREF))) { + /* TODO: + * Set the LDO voltage to 0x0028 - FIXME: What is this? + * Call sb_pmu_set_ldo_voltage with 4 and the LDO voltage + * as arguments + * Call sb_pmu_paref_ldo_enable with argument TRUE + */ + if (dev->phy.rev == 0) { + b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT, + 0xFFCF, 0x0010); + } + b43_lptab_write(dev, B43_LPTAB16(11, 7), 60); + } else { + //TODO: Call ssb_pmu_paref_ldo_enable with argument FALSE + b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT, + 0xFFCF, 0x0020); + b43_lptab_write(dev, B43_LPTAB16(11, 7), 100); + } + tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000; + b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, tmp); + if (bus->sprom.boardflags_hi & B43_BFH_RSSIINV) + b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA); + else + b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA); + b43_lptab_write(dev, B43_LPTAB16(11, 1), 24); + b43_phy_maskset(dev, B43_LPPHY_RX_RADIO_CTL, + 0xFFF9, (lpphy->bx_arch << 1)); if (dev->phy.rev == 1 && (bus->sprom.boardflags_hi & B43_BFH_FEM_BT)) { b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A); @@ -255,7 +309,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700); } - if (dev->phy.rev == 1) { + if (dev->phy.rev == 1 && (bus->sprom.boardflags_hi & B43_BFH_PAREF)) { b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1); b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2); b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3); @@ -267,6 +321,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006); b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005); b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF); + //FIXME the Broadcom driver caches & delays this HF write! b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W); } if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { @@ -384,7 +439,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_PWR_THRESH1, 0xFFF0, 0x9); b43_phy_mask(dev, B43_LPPHY_GAINDIRECTMISMATCH, ~0xF); b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5500); - b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xF81F, 0xA0); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0xA0); b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xE0FF, 0x300); b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2A00); if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { @@ -405,7 +460,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12); b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000); - if ((bus->chip_id == 0x4325) && (bus->chip_rev == 1)) { + if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0); b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40); } @@ -416,6 +471,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x6); b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0x9D00); b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0xFF00, 0xA1); + b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF); } else /* 5GHz */ b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x40); @@ -1883,7 +1939,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, lpphy_b2062_reset_pll_bias(dev); lpphy_b2062_vco_calib(dev); if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) - err = -EINVAL; + err = -EIO; } b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04); @@ -2068,11 +2124,18 @@ static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, static int b43_lpphy_op_init(struct b43_wldev *dev) { + int err; + lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? lpphy_baseband_init(dev); lpphy_radio_init(dev); lpphy_calibrate_rc(dev); - b43_lpphy_op_switch_channel(dev, b43_lpphy_op_get_default_chan(dev)); + err = b43_lpphy_op_switch_channel(dev, + b43_lpphy_op_get_default_chan(dev)); + if (err) { + b43dbg(dev->wl, "Switch to init channel failed, error = %d.\n", + err); + } lpphy_tx_pctl_init(dev); lpphy_calibration(dev); //TODO ACI init -- cgit v0.10.2 From 0ff6ce7b36199f67f709c750e9a2a66659a4babe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Aug 2009 12:25:37 +0200 Subject: cfg80211: fix deadlock When removing an interface with nl80211, cfg80211 will deadlock in the netdev notifier because we're already holding rdev->mtx and try to acquire it again to verify the scan has been done. This bug was introduced by my patch "cfg80211: check for and abort dangling scan requests". To fix this, move the dangling scan request check into wiphy_unregister(). This will not be able to catch all cases right away, but if the scan problem happens with a manual ifdown or so it will be possible to remedy it by removing the module/device. Additionally, add comments about the deadlock scenario. Reported-by: Christian Lamparter Signed-off-by: Johannes Berg Tested-by: Christian Lamparter Tested-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index bc99e4e..69a185b 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -586,9 +586,14 @@ void wiphy_unregister(struct wiphy *wiphy) * get to lock contention here if userspace issues a command * that identified the hardware by wiphy index. */ - mutex_lock(&rdev->mtx); - /* unlock again before freeing */ - mutex_unlock(&rdev->mtx); + cfg80211_lock_rdev(rdev); + + if (WARN_ON(rdev->scan_req)) { + rdev->scan_req->aborted = true; + ___cfg80211_scan_done(rdev); + } + + cfg80211_unlock_rdev(rdev); cfg80211_debugfs_rdev_del(rdev); @@ -605,7 +610,6 @@ void wiphy_unregister(struct wiphy *wiphy) flush_work(&rdev->scan_done_wk); cancel_work_sync(&rdev->conn_work); - kfree(rdev->scan_req); flush_work(&rdev->event_work); } EXPORT_SYMBOL(wiphy_unregister); @@ -653,6 +657,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, switch (state) { case NETDEV_REGISTER: + /* + * NB: cannot take rdev->mtx here because this may be + * called within code protected by it when interfaces + * are added with nl80211. + */ mutex_init(&wdev->mtx); INIT_LIST_HEAD(&wdev->event_list); spin_lock_init(&wdev->event_lock); @@ -730,13 +739,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, #endif break; case NETDEV_UNREGISTER: - cfg80211_lock_rdev(rdev); - - if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) { - rdev->scan_req->aborted = true; - ___cfg80211_scan_done(rdev); - } - + /* + * NB: cannot take rdev->mtx here because this may be + * called within code protected by it when interfaces + * are removed with nl80211. + */ mutex_lock(&rdev->devlist_mtx); /* * It is possible to get NETDEV_UNREGISTER @@ -755,7 +762,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, #endif } mutex_unlock(&rdev->devlist_mtx); - cfg80211_unlock_rdev(rdev); break; case NETDEV_PRE_UP: if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) -- cgit v0.10.2 From 055114a38804947554065194d50ded4bc7d7c4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Sun, 16 Aug 2009 15:32:40 +0200 Subject: b43: LP-PHY: Fix a spec error in the B2062 channel switch routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The channel switch routine had a whole instruction missing. Add it. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 85af82a..cb6c18d 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1922,6 +1922,10 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, tmp5 = tmp7 * 0x100; tmp6 = tmp5 / tmp4; tmp7 = tmp5 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL27, tmp6); + tmp5 = tmp7 * 0x100; + tmp6 = tmp5 / tmp4; + tmp7 = tmp5 % tmp4; b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6); tmp5 = tmp7 * 0x100; tmp6 = tmp5 / tmp4; -- cgit v0.10.2 From 5269102ec9c1584ccfab71affd1d7600d59f9096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Sun, 16 Aug 2009 18:05:09 +0200 Subject: b43: LP-PHY: Update code for spec fixes, and fix a few typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few typos have been discovered in both the specs and the code. This patch fixes them. Also use lpphy_op_switch_channel consistently, and make all users of it print its return value for easier debugging. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index cb6c18d..4d14102 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -552,7 +552,7 @@ static void lpphy_2062_init(struct b43_wldev *dev) B43_WARN_ON(!(bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)); B43_WARN_ON(crystalfreq == 0); - if (crystalfreq >= 30000000) { + if (crystalfreq <= 30000000) { lpphy->pdiv = 1; b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB); } else { @@ -560,14 +560,16 @@ static void lpphy_2062_init(struct b43_wldev *dev) b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4); } - tmp = (800000000 * lpphy->pdiv + crystalfreq) / - (32000000 * lpphy->pdiv); - tmp = (tmp - 1) & 0xFF; + tmp = (((800000000 * lpphy->pdiv + crystalfreq) / + (2 * crystalfreq)) - 8) & 0xFF; + b43_radio_write(dev, B2062_S_RFPLL_CTL7, tmp); + + tmp = (((100 * crystalfreq + 16000000 * lpphy->pdiv) / + (32000000 * lpphy->pdiv)) - 1) & 0xFF; b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp); - tmp = (2 * crystalfreq + 1000000 * lpphy->pdiv) / - (2000000 * lpphy->pdiv); - tmp = ((tmp & 0xFF) - 1) & 0xFFFF; + tmp = (((2 * crystalfreq + 1000000 * lpphy->pdiv) / + (2000000 * lpphy->pdiv)) - 1) & 0xFF; b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp); ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv); @@ -671,7 +673,7 @@ static void lpphy_radio_init(struct b43_wldev *dev) b43_phy_mask(dev, B43_LPPHY_FOURWIRE_CTL, 0xFFFD); udelay(1); - if (dev->phy.rev < 2) { + if (dev->phy.radio_ver == 0x2062) { lpphy_2062_init(dev); } else { lpphy_2063_init(dev); @@ -688,11 +690,18 @@ struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; }; static void lpphy_set_rc_cap(struct b43_wldev *dev) { - u8 rc_cap = dev->phy.lp->rc_cap; + struct b43_phy_lp *lpphy = dev->phy.lp; + + u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1; - b43_radio_write(dev, B2062_N_RXBB_CALIB2, max_t(u8, rc_cap-4, 0x80)); - b43_radio_write(dev, B2062_N_TX_CTL_A, ((rc_cap & 0x1F) >> 1) | 0x80); - b43_radio_write(dev, B2062_S_RXG_CNT16, ((rc_cap & 0x1F) >> 2) | 0x80); + if (dev->phy.rev == 1) //FIXME check channel 14! + rc_cap = max_t(u8, rc_cap + 5, 15); + + b43_radio_write(dev, B2062_N_RXBB_CALIB2, + max_t(u8, lpphy->rc_cap - 4, 0x80)); + b43_radio_write(dev, B2062_N_TX_CTL_A, rc_cap | 0x80); + b43_radio_write(dev, B2062_S_RXG_CNT16, + ((lpphy->rc_cap & 0x1F) >> 2) | 0x80); } static u8 lpphy_get_bb_mult(struct b43_wldev *dev) @@ -1101,6 +1110,9 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev, lpphy_write_tx_pctl_mode_to_hardware(dev); } +static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel); + static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) { struct b43_phy_lp *lpphy = dev->phy.lp; @@ -1118,11 +1130,16 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) old_rf2_ovr, old_rf2_ovrval, old_phy_ctl; enum b43_lpphy_txpctl_mode old_txpctl; u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0; - int loopback, i, j, inner_sum; + int loopback, i, j, inner_sum, err; memset(&iq_est, 0, sizeof(iq_est)); - b43_switch_channel(dev, 7); + err = b43_lpphy_op_switch_channel(dev, 7); + if (err) { + b43dbg(dev->wl, + "RC calib: Failed to switch to channel 7, error = %d", + err); + } old_txg_ovr = (b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) >> 6) & 1; old_bbmult = lpphy_get_bb_mult(dev); if (old_txg_ovr) @@ -1881,14 +1898,14 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, { struct b43_phy_lp *lpphy = dev->phy.lp; struct ssb_bus *bus = dev->dev->bus; - static const struct b206x_channel *chandata = NULL; + const struct b206x_channel *chandata = NULL; u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; int i, err = 0; - for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) { - if (b2063_chantbl[i].channel == channel) { - chandata = &b2063_chantbl[i]; + for (i = 0; i < ARRAY_SIZE(b2062_chantbl); i++) { + if (b2062_chantbl[i].channel == channel) { + chandata = &b2062_chantbl[i]; break; } } -- cgit v0.10.2 From ed07c4b3af341bad3fa29558f08b166220014ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Sun, 16 Aug 2009 18:40:09 +0200 Subject: b43: LP-PHY: Fix a bug in the B2062 channel tune path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I missed the "+16" part of the instruction in the specs. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 4d14102..4553e40 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1950,7 +1950,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4)); tmp8 = b43_phy_read(dev, B2062_S_RFPLL_CTL19); tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1); - b43_radio_write(dev, B2062_S_RFPLL_CTL23, tmp9 >> 8); + b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16); b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF); lpphy_b2062_vco_calib(dev); -- cgit v0.10.2 From 7e4d8529921004014bef21a2031b6c3478339a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Sun, 16 Aug 2009 20:08:13 +0200 Subject: b43: LP-PHY: Update B2062 radio init with recent spec changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spec for initializing the B2062 radio have changed recently, update the code to match the changes. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 4553e40..faca56f 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -537,10 +537,15 @@ static void lpphy_2062_init(struct b43_wldev *dev) b43_radio_write(dev, B2062_N_TX_CTL3, 0); b43_radio_write(dev, B2062_N_TX_CTL4, 0); b43_radio_write(dev, B2062_N_TX_CTL5, 0); + b43_radio_write(dev, B2062_N_TX_CTL6, 0); b43_radio_write(dev, B2062_N_PDN_CTL0, 0x40); b43_radio_write(dev, B2062_N_PDN_CTL0, 0); b43_radio_write(dev, B2062_N_CALIB_TS, 0x10); b43_radio_write(dev, B2062_N_CALIB_TS, 0); + if (dev->phy.rev > 0) { + b43_radio_write(dev, B2062_S_BG_CTL1, + (b43_radio_read(dev, B2062_N_COMM2) >> 1) | 0x80); + } if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) b43_radio_set(dev, B2062_N_TSSI_CTL0, 0x1); else -- cgit v0.10.2 From 86b2892a22a433e56e39e33bf353adc6cc4eabb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Sun, 16 Aug 2009 20:22:41 +0200 Subject: b43: LP-PHY: Remove BROKEN from B43_PHY_LP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Larry has reported success getting scan data with an LP-PHY device, so it's probably time to release LP-PHY support for testing. Also disable 802.11a support for now, as 802.11a currently causes the driver to panic on startup (NULL pointer dereference). Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 67f564e..237b1aa 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -80,16 +80,16 @@ config B43_NPHY SAY N. config B43_PHY_LP - bool "IEEE 802.11g LP-PHY support (BROKEN)" - depends on B43 && EXPERIMENTAL && BROKEN + bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)" + depends on B43 && EXPERIMENTAL ---help--- Support for the LP-PHY. - The LP-PHY is an IEEE 802.11g based PHY built into some notebooks - and embedded devices. - - THIS IS BROKEN AND DOES NOT WORK YET. + The LP-PHY is a low-power PHY built into some notebooks + and embedded devices. It supports 802.11a/g + (802.11a support is optional, and currently disabled). - SAY N. + This is heavily experimental, and probably will not work for you. + Say N unless you want to help debug the driver. # This config option automatically enables b43 LEDS support, # if it's possible. diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 99b41ce..c5bece0 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4514,7 +4514,9 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) have_5ghz_phy = 1; break; case B43_PHYTYPE_LP: //FIXME not always! +#if 0 //FIXME enabling 5GHz causes a NULL pointer dereference have_5ghz_phy = 1; +#endif case B43_PHYTYPE_G: case B43_PHYTYPE_N: have_2ghz_phy = 1; -- cgit v0.10.2 From ea416a793d2b611f22b42ba094fd2e5bd30fff43 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Aug 2009 12:22:14 +0200 Subject: cfg80211: report userspace SME connected event properly Instead of hacking the event reporting into the __cfg80211_connect_result() function which is also invoked by others, set up things correctly and then invoke that function, so that it can do more sanity checking. Also, it is currently not possible to get a ROAMED event from the userspace SME anyway since we send out a DISCONNECTED event when it disassociates and then a new CONNECTED event on the next association. Thanks to Zhu Yi for pointing out that the code is somewhat convoluted and doesn't warn when it should. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index da64071..79d2eec 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -96,6 +96,15 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) WARN_ON(!bss); } + if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { + /* + * This is for the userspace SME, the CONNECTING + * state will be changed to CONNECTED by + * __cfg80211_connect_result() below. + */ + wdev->sme_state = CFG80211_SME_CONNECTING; + } + /* this consumes one bss reference (unless bss is NULL) */ __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, status_code, diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 8e2ef54..6fb6a70 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -351,15 +351,13 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; - if (wdev->sme_state == CFG80211_SME_CONNECTED) - nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, + if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING)) + return; + + nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, bssid, req_ie, req_ie_len, - resp_ie, resp_ie_len, GFP_KERNEL); - else - nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, - bssid, req_ie, req_ie_len, - resp_ie, resp_ie_len, - status, GFP_KERNEL); + resp_ie, resp_ie_len, + status, GFP_KERNEL); #ifdef CONFIG_WIRELESS_EXT if (wextev) { @@ -392,13 +390,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, wdev->current_bss = NULL; } - if (status == WLAN_STATUS_SUCCESS && - wdev->sme_state == CFG80211_SME_IDLE) - goto success; - - if (wdev->sme_state != CFG80211_SME_CONNECTING) - return; - if (wdev->conn) wdev->conn->state = CFG80211_CONN_IDLE; @@ -412,7 +403,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, return; } - success: if (!bss) bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, wdev->ssid, wdev->ssid_len, -- cgit v0.10.2 From 3ac64beecd27400d12cc7afb4108eef26c499f6a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Aug 2009 16:16:53 +0200 Subject: mac80211: allow configure_filter callback to sleep Over time, a whole bunch of drivers have come up with their own scheme to delay the configure_filter operation to a workqueue. To be able to simplify things, allow configure_filter to sleep, and add a new prepare_multicast callback that drivers that need the multicast address list implement. This new callback must be atomic, but most drivers either don't care or just calculate a hash which can be done atomically and then uploaded to the hardware non-atomically. A cursory look suggests that at76c50x-usb, ar9170, mwl8k (which is actually very broken now), rt2x00, wl1251, wl1271 and zd1211 should make use of this new capability. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 5695911..b80f514 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1328,16 +1328,39 @@ static void adm8211_bss_info_changed(struct ieee80211_hw *dev, } } +static u64 adm8211_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + unsigned int bit_nr, i; + u32 mc_filter[2]; + + mc_filter[1] = mc_filter[0] = 0; + + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + + bit_nr &= 0x3F; + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + mclist = mclist->next; + } + + return mc_filter[0] | ((u64)(mc_filter[1]) << 32); +} + static void adm8211_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; struct adm8211_priv *priv = dev->priv; - unsigned int bit_nr, new_flags; + unsigned int new_flags; u32 mc_filter[2]; - int i; + + mc_filter[0] = multicast; + mc_filter[1] = multicast >> 32; new_flags = 0; @@ -1346,23 +1369,13 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev, priv->nar |= ADM8211_NAR_PR; priv->nar &= ~ADM8211_NAR_MM; mc_filter[1] = mc_filter[0] = ~0; - } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { + } else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) { new_flags |= FIF_ALLMULTI; priv->nar &= ~ADM8211_NAR_PR; priv->nar |= ADM8211_NAR_MM; mc_filter[1] = mc_filter[0] = ~0; } else { priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR); - mc_filter[1] = mc_filter[0] = 0; - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - - bit_nr &= 0x3F; - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); - mclist = mclist->next; - } } ADM8211_IDLE_RX(); @@ -1757,6 +1770,7 @@ static const struct ieee80211_ops adm8211_ops = { .remove_interface = adm8211_remove_interface, .config = adm8211_config, .bss_info_changed = adm8211_bss_info_changed, + .prepare_multicast = adm8211_prepare_multicast, .configure_filter = adm8211_configure_filter, .get_stats = adm8211_get_stats, .get_tx_stats = adm8211_get_tx_stats, diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 7218dba..a6e1954 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1997,15 +1997,14 @@ static void at76_bss_info_changed(struct ieee80211_hw *hw, /* must be atomic */ static void at76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total_flags, u64 multicast) { struct at76_priv *priv = hw->priv; int flags; at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x " - "total_flags=0x%08x mc_count=%d", - __func__, changed_flags, *total_flags, mc_count); + "total_flags=0x%08x", + __func__, changed_flags, *total_flags); flags = changed_flags & AT76_SUPPORTED_FILTERS; *total_flags = AT76_SUPPORTED_FILTERS; diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index ea8c941..6a9462e 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2100,10 +2100,29 @@ unlock: mutex_unlock(&ar->mutex); } +static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, + struct dev_addr_list *mclist) +{ + u64 mchash; + int i; + + /* always get broadcast frames */ + mchash = 1ULL << (0xff >> 2); + + for (i = 0; i < mc_count; i++) { + if (WARN_ON(!mclist)) + break; + mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); + mclist = mclist->next; + } + + return mchash; +} + static void ar9170_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct ar9170 *ar = hw->priv; @@ -2116,24 +2135,11 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, * then checking the error flags, later. */ - if (changed_flags & FIF_ALLMULTI) { - if (*new_flags & FIF_ALLMULTI) { - ar->want_mc_hash = ~0ULL; - } else { - u64 mchash; - int i; - - /* always get broadcast frames */ - mchash = 1ULL << (0xff >> 2); + if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) + multicast = ~0ULL; - for (i = 0; i < mc_count; i++) { - if (WARN_ON(!mclist)) - break; - mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); - mclist = mclist->next; - } - ar->want_mc_hash = mchash; - } + if (multicast != ar->want_mc_hash) { + ar->want_mc_hash = multicast; set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed); } @@ -2543,6 +2549,7 @@ static const struct ieee80211_ops ar9170_ops = { .add_interface = ar9170_op_add_interface, .remove_interface = ar9170_op_remove_interface, .config = ar9170_op_config, + .prepare_multicast = ar9170_op_prepare_multicast, .configure_filter = ar9170_op_configure_filter, .conf_tx = ar9170_conf_tx, .bss_info_changed = ar9170_op_bss_info_changed, diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 2b3cf39..3951b5b 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -229,10 +229,12 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, static void ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); static int ath5k_config(struct ieee80211_hw *hw, u32 changed); +static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mc_list); static void ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist); + u64 multicast); static int ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -260,6 +262,7 @@ static const struct ieee80211_ops ath5k_hw_ops = { .add_interface = ath5k_add_interface, .remove_interface = ath5k_remove_interface, .config = ath5k_config, + .prepare_multicast = ath5k_prepare_multicast, .configure_filter = ath5k_configure_filter, .set_key = ath5k_set_key, .get_stats = ath5k_get_stats, @@ -2853,6 +2856,37 @@ unlock: return ret; } +static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + u32 mfilt[2], val; + int i; + u8 pos; + + mfilt[0] = 0; + mfilt[1] = 1; + + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + /* calculate XOR of eight 6-bit values */ + val = get_unaligned_le32(mclist->dmi_addr + 0); + pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + val = get_unaligned_le32(mclist->dmi_addr + 3); + pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + pos &= 0x3f; + mfilt[pos / 32] |= (1 << (pos % 32)); + /* XXX: we might be able to just do this instead, + * but not sure, needs testing, if we do use this we'd + * neet to inform below to not reset the mcast */ + /* ath5k_hw_set_mcast_filterindex(ah, + * mclist->dmi_addr[5]); */ + mclist = mclist->next; + } + + return ((u64)(mfilt[1]) << 32) | mfilt[0]; +} + #define SUPPORTED_FIF_FLAGS \ FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ @@ -2878,16 +2912,14 @@ unlock: static void ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; - u32 mfilt[2], val, rfilt; - u8 pos; - int i; + u32 mfilt[2], rfilt; - mfilt[0] = 0; - mfilt[1] = 0; + mfilt[0] = multicast; + mfilt[1] = multicast >> 32; /* Only deal with supported flags */ changed_flags &= SUPPORTED_FIF_FLAGS; @@ -2913,24 +2945,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, if (*new_flags & FIF_ALLMULTI) { mfilt[0] = ~0; mfilt[1] = ~0; - } else { - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - /* calculate XOR of eight 6-bit values */ - val = get_unaligned_le32(mclist->dmi_addr + 0); - pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - val = get_unaligned_le32(mclist->dmi_addr + 3); - pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - pos &= 0x3f; - mfilt[pos / 32] |= (1 << (pos % 32)); - /* XXX: we might be able to just do this instead, - * but not sure, needs testing, if we do use this we'd - * neet to inform below to not reset the mcast */ - /* ath5k_hw_set_mcast_filterindex(ah, - * mclist->dmi_addr[5]); */ - mclist = mclist->next; - } } /* This is the best we can do */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3e09b9a..2f9c149 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2394,8 +2394,7 @@ skip_chan_change: static void ath9k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, - struct dev_mc_list *mclist) + u64 multicast) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index c5bece0..78ddbc7 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3679,7 +3679,7 @@ out_unlock: static void b43_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, unsigned int *fflags, - int mc_count, struct dev_addr_list *mc_list) + u64 multicast) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index b143559..b166a6f 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2836,9 +2836,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *fflags, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *fflags,u64 multicast) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c0efa66..f1f6dab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1514,7 +1514,7 @@ EXPORT_SYMBOL(iwl_irq_handle_error); void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list) + u64 multicast) { struct iwl_priv *priv = hw->priv; __le32 *filter_flags = &priv->staging_rxon.filter_flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4ca025a..62d9036 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -282,8 +282,7 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv, void iwl_irq_handle_error(struct iwl_priv *priv); void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list); + unsigned int *total_flags, u64 multicast); int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 4872345..019431d 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -366,15 +366,35 @@ static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed) return 0; } +static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + struct lbtf_private *priv = hw->priv; + int i; + + if (!mc_count || mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) + return mc_count; + + priv->nr_of_multicastmacaddr = mc_count; + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + memcpy(&priv->multicastlist[i], mclist->da_addr, + ETH_ALEN); + mclist = mclist->next; + } + + return mc_count; +} + #define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI) static void lbtf_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct lbtf_private *priv = hw->priv; int old_mac_control = priv->mac_control; - int i; changed_flags &= SUPPORTED_FIF_FLAGS; *new_flags &= SUPPORTED_FIF_FLAGS; @@ -386,20 +406,12 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw, else priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; if (*new_flags & (FIF_ALLMULTI) || - mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { + multicast > MRVDRV_MAX_MULTICAST_LIST_SIZE) { priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; - } else if (mc_count) { + } else if (multicast) { priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - priv->nr_of_multicastmacaddr = mc_count; - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - memcpy(&priv->multicastlist[i], mclist->da_addr, - ETH_ALEN); - mclist = mclist->next; - } lbtf_cmd_set_mac_multicast_addr(priv); } else { priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE | @@ -461,6 +473,7 @@ static const struct ieee80211_ops lbtf_ops = { .add_interface = lbtf_op_add_interface, .remove_interface = lbtf_op_remove_interface, .config = lbtf_op_config, + .prepare_multicast = lbtf_op_prepare_multicast, .configure_filter = lbtf_op_configure_filter, .bss_info_changed = lbtf_op_bss_info_changed, }; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 930f5c7..6f6cd43 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -582,9 +582,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total_flags,u64 multicast) { struct mac80211_hwsim_data *data = hw->priv; diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8a6d3af..f843870 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3251,31 +3251,50 @@ mwl8k_configure_filter_exit: return rc; } +static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + struct mwl8k_configure_filter_worker *worker; + + worker = kzalloc(sizeof(*worker), GFP_ATOMIC); + + if (!worker) + return 0; + + /* + * XXX: This is _HORRIBLY_ broken!! + * + * No locking, the mclist pointer might be invalid as soon as this + * function returns, something in the list might be invalidated + * once we get to the worker, etc... + */ + worker->mc_count = mc_count; + worker->mclist = mclist; + + return (u64)worker; +} + static void mwl8k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mclist) + u64 multicast) { - struct mwl8k_configure_filter_worker *worker; + struct mwl8k_configure_filter_worker *worker = (void *)multicast; struct mwl8k_priv *priv = hw->priv; /* Clear unsupported feature flags */ *total_flags &= MWL8K_SUPPORTED_IF_FLAGS; - if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS) && !mc_count) + if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS)) return; - worker = kzalloc(sizeof(*worker), GFP_ATOMIC); if (worker == NULL) return; worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY; worker->changed_flags = changed_flags; worker->total_flags = total_flags; - worker->mc_count = mc_count; - worker->mclist = mclist; mwl8k_queue_work(hw, &worker->header, priv->config_wq, mwl8k_configure_filter_wt); @@ -3441,6 +3460,7 @@ static const struct ieee80211_ops mwl8k_ops = { .remove_interface = mwl8k_remove_interface, .config = mwl8k_config, .bss_info_changed = mwl8k_bss_info_changed, + .prepare_multicast = mwl8k_prepare_multicast, .configure_filter = mwl8k_configure_filter, .set_rts_threshold = mwl8k_set_rts_threshold, .conf_tx = mwl8k_conf_tx, diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 77203e3..4d486bf 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -302,7 +302,7 @@ out: static void p54_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 99e8959..39d7d9b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -978,7 +978,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list); + u64 multicast); int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); #ifdef CONFIG_RT2X00_LIB_CRYPTO diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index cb7b6d4..602f126 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -379,7 +379,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_config); void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list) + u64 multicast) { struct rt2x00_dev *rt2x00dev = hw->priv; diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 09f46ab..16429c4 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -728,10 +728,16 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, priv->rf->conf_erp(dev, info); } +static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count, + struct dev_addr_list *mc_list) +{ + return mc_count; +} + static void rtl8180_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mclist) + u64 multicast) { struct rtl8180_priv *priv = dev->priv; @@ -741,7 +747,7 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev, priv->rx_conf ^= RTL818X_RX_CONF_CTRL; if (changed_flags & FIF_OTHER_BSS) priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; - if (*total_flags & FIF_ALLMULTI || mc_count > 0) + if (*total_flags & FIF_ALLMULTI || multicast > 0) priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; else priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; @@ -768,6 +774,7 @@ static const struct ieee80211_ops rtl8180_ops = { .remove_interface = rtl8180_remove_interface, .config = rtl8180_config, .bss_info_changed = rtl8180_bss_info_changed, + .prepare_multicast = rtl8180_prepare_multicast, .configure_filter = rtl8180_configure_filter, }; diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 53f57dc..90f3835 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1192,10 +1192,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, info->use_short_preamble); } +static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev, + int mc_count, struct dev_addr_list *mc_list) +{ + return mc_count; +} + static void rtl8187_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mclist) + u64 multicast) { struct rtl8187_priv *priv = dev->priv; @@ -1205,7 +1211,7 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev, priv->rx_conf ^= RTL818X_RX_CONF_CTRL; if (changed_flags & FIF_OTHER_BSS) priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; - if (*total_flags & FIF_ALLMULTI || mc_count > 0) + if (*total_flags & FIF_ALLMULTI || multicast > 0) priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; else priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; @@ -1268,6 +1274,7 @@ static const struct ieee80211_ops rtl8187_ops = { .remove_interface = rtl8187_remove_interface, .config = rtl8187_config, .bss_info_changed = rtl8187_bss_info_changed, + .prepare_multicast = rtl8187_prepare_multicast, .configure_filter = rtl8187_configure_filter, .conf_tx = rtl8187_conf_tx }; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 7148934..5809ef5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -652,9 +652,7 @@ out: static void wl1251_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *total, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total,u64 multicast) { struct wl1251 *wl = hw->priv; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 4102d59..754be81 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -793,9 +793,7 @@ out: static void wl1271_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *total, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total,u64 multicast) { struct wl1271 *wl = hw->priv; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 55b7fbd..6d66635 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -796,18 +796,40 @@ static void set_rx_filter_handler(struct work_struct *work) dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r); } +static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + struct zd_mac *mac = zd_hw_mac(hw); + struct zd_mc_hash hash; + int i; + + zd_mc_clear(&hash); + + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", mclist->dmi_addr); + zd_mc_add_addr(&hash, mclist->dmi_addr); + mclist = mclist->next; + } + + return hash.low | ((u64)hash.high << 32); +} + #define SUPPORTED_FIF_FLAGS \ (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \ FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC) static void zd_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { - struct zd_mc_hash hash; + struct zd_mc_hash hash = { + .low = multicast, + .high = multicast >> 32, + }; struct zd_mac *mac = zd_hw_mac(hw); unsigned long flags; - int i; /* Only deal with supported flags */ changed_flags &= SUPPORTED_FIF_FLAGS; @@ -819,25 +841,16 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, if (!changed_flags) return; - if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) { + if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) zd_mc_add_all(&hash); - } else { - zd_mc_clear(&hash); - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", - mclist->dmi_addr); - zd_mc_add_addr(&hash, mclist->dmi_addr); - mclist = mclist->next; - } - } spin_lock_irqsave(&mac->lock, flags); mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL); mac->pass_ctrl = !!(*new_flags & FIF_CONTROL); mac->multicast_hash = hash; spin_unlock_irqrestore(&mac->lock, flags); + + /* XXX: these can be called here now, can sleep now! */ queue_work(zd_workqueue, &mac->set_multicast_hash_work); if (changed_flags & FIF_CONTROL) @@ -940,6 +953,7 @@ static const struct ieee80211_ops zd_ops = { .add_interface = zd_op_add_interface, .remove_interface = zd_op_remove_interface, .config = zd_op_config, + .prepare_multicast = zd_op_prepare_multicast, .configure_filter = zd_op_configure_filter, .bss_info_changed = zd_op_bss_info_changed, .get_tsf = zd_op_get_tsf, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 76d43e1..bc86520 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1219,10 +1219,13 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * the driver's configure_filter() function which frames should be * passed to mac80211 and which should be filtered out. * - * The configure_filter() callback is invoked with the parameters - * @mc_count and @mc_list for the combined multicast address list - * of all virtual interfaces, @changed_flags telling which flags - * were changed and @total_flags with the new flag states. + * Before configure_filter() is invoked, the prepare_multicast() + * callback is invoked with the parameters @mc_count and @mc_list + * for the combined multicast address list of all virtual interfaces. + * It's use is optional, and it returns a u64 that is passed to + * configure_filter(). Additionally, configure_filter() has the + * arguments @changed_flags telling which flags were changed and + * @total_flags with the new flag states. * * If your device has no multicast address filters your driver will * need to check both the %FIF_ALLMULTI flag and the @mc_count @@ -1375,9 +1378,13 @@ enum ieee80211_ampdu_mlme_action { * for association indication. The @changed parameter indicates which * of the bss parameters has changed when a call is made. * + * @prepare_multicast: Prepare for multicast filter configuration. + * This callback is optional, and its return value is passed + * to configure_filter(). This callback must be atomic. + * * @configure_filter: Configure the device's RX filter. * See the section "Frame filtering" for more information. - * This callback must be implemented and atomic. + * This callback must be implemented. * * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit * must be set or cleared for a given STA. Must be atomic. @@ -1479,10 +1486,12 @@ struct ieee80211_ops { struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed); + u64 (*prepare_multicast)(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mc_list); void (*configure_filter)(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list); + u64 multicast); int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4100c36..d231c93 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -55,16 +55,32 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, trace_drv_bss_info_changed(local, vif, info, changed); } +static inline u64 drv_prepare_multicast(struct ieee80211_local *local, + int mc_count, + struct dev_addr_list *mc_list) +{ + u64 ret = 0; + + if (local->ops->prepare_multicast) + ret = local->ops->prepare_multicast(&local->hw, mc_count, + mc_list); + + trace_drv_prepare_multicast(local, mc_count, ret); + + return ret; +} + static inline void drv_configure_filter(struct ieee80211_local *local, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mc_list) + u64 multicast) { + might_sleep(); + local->ops->configure_filter(&local->hw, changed_flags, total_flags, - mc_count, mc_list); + multicast); trace_drv_configure_filter(local, changed_flags, total_flags, - mc_count); + multicast); } static inline int drv_set_tim(struct ieee80211_local *local, diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 5a10da2..37b9051 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -191,31 +191,55 @@ TRACE_EVENT(drv_bss_info_changed, ) ); +TRACE_EVENT(drv_prepare_multicast, + TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret), + + TP_ARGS(local, mc_count, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, mc_count) + __field(u64, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->mc_count = mc_count; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " prepare mc (%d): %llx", + LOCAL_PR_ARG, __entry->mc_count, + (unsigned long long) __entry->ret + ) +); + TRACE_EVENT(drv_configure_filter, TP_PROTO(struct ieee80211_local *local, unsigned int changed_flags, unsigned int *total_flags, - int mc_count), + u64 multicast), - TP_ARGS(local, changed_flags, total_flags, mc_count), + TP_ARGS(local, changed_flags, total_flags, multicast), TP_STRUCT__entry( LOCAL_ENTRY __field(unsigned int, changed) __field(unsigned int, total) - __field(int, mc) + __field(u64, multicast) ), TP_fast_assign( LOCAL_ASSIGN; __entry->changed = changed_flags; __entry->total = *total_flags; - __entry->mc = mc_count; + __entry->multicast = multicast; ), TP_printk( - LOCAL_PR_FMT " changed:%#x total:%#x mc:%d", - LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc + LOCAL_PR_FMT " changed:%#x total:%#x", + LOCAL_PR_ARG, __entry->changed, __entry->total ) ); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a6abc7d..a07f017 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -636,6 +636,9 @@ struct ieee80211_local { /* protects the aggregated multicast list and filter calls */ spinlock_t filter_lock; + /* used for uploading changed mc list */ + struct work_struct reconfig_filter; + /* aggregated multicast list */ struct dev_addr_list *mc_list; int mc_count; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index e8fb03b..b161301 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -227,9 +227,7 @@ static int ieee80211_open(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss++; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); break; default: conf.vif = &sdata->vif; @@ -241,17 +239,13 @@ static int ieee80211_open(struct net_device *dev) if (ieee80211_vif_is_mesh(&sdata->vif)) { local->fif_other_bss++; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); ieee80211_start_mesh(sdata); } else if (sdata->vif.type == NL80211_IFTYPE_AP) { local->fif_pspoll++; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); } changed |= ieee80211_reset_erp_info(sdata); @@ -404,10 +398,11 @@ static int ieee80211_stop(struct net_device *dev) spin_lock_bh(&local->filter_lock); __dev_addr_unsync(&local->mc_list, &local->mc_count, &dev->mc_list, &dev->mc_count); - ieee80211_configure_filter(local); spin_unlock_bh(&local->filter_lock); netif_addr_unlock_bh(dev); + ieee80211_configure_filter(local); + del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); @@ -458,9 +453,7 @@ static int ieee80211_stop(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss--; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); break; case NL80211_IFTYPE_STATION: del_timer_sync(&sdata->u.mgd.chswitch_timer); @@ -503,9 +496,7 @@ static int ieee80211_stop(struct net_device *dev) local->fif_other_bss--; atomic_dec(&local->iff_allmultis); - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); ieee80211_stop_mesh(sdata); } @@ -622,8 +613,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev) spin_lock_bh(&local->filter_lock); __dev_addr_sync(&local->mc_list, &local->mc_count, &dev->mc_list, &dev->mc_count); - ieee80211_configure_filter(local); spin_unlock_bh(&local->filter_lock); + ieee80211_queue_work(&local->hw, &local->reconfig_filter); } /* diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b03fd84..05f9235 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -50,9 +50,9 @@ struct ieee80211_tx_status_rtap_hdr { } __attribute__ ((packed)); -/* must be called under mdev tx lock */ void ieee80211_configure_filter(struct ieee80211_local *local) { + u64 mc; unsigned int changed_flags; unsigned int new_flags = 0; @@ -62,7 +62,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (atomic_read(&local->iff_allmultis)) new_flags |= FIF_ALLMULTI; - if (local->monitors) + if (local->monitors || local->scanning) new_flags |= FIF_BCN_PRBRESP_PROMISC; if (local->fif_fcsfail) @@ -80,20 +80,30 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (local->fif_pspoll) new_flags |= FIF_PSPOLL; + spin_lock_bh(&local->filter_lock); changed_flags = local->filter_flags ^ new_flags; + mc = drv_prepare_multicast(local, local->mc_count, local->mc_list); + spin_unlock_bh(&local->filter_lock); + /* be a bit nasty */ new_flags |= (1<<31); - drv_configure_filter(local, changed_flags, &new_flags, - local->mc_count, - local->mc_list); + drv_configure_filter(local, changed_flags, &new_flags, mc); WARN_ON(new_flags & (1<<31)); local->filter_flags = new_flags & ~(1<<31); } +static void ieee80211_reconfig_filter(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, reconfig_filter); + + ieee80211_configure_filter(local); +} + int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { struct ieee80211_channel *chan, *scan_chan; @@ -692,6 +702,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_WORK(&local->restart_work, ieee80211_restart_work); + INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); + INIT_WORK(&local->dynamic_ps_enable_work, ieee80211_dynamic_ps_enable_work); INIT_WORK(&local->dynamic_ps_disable_work, @@ -946,6 +958,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) rtnl_unlock(); + cancel_work_sync(&local->reconfig_filter); + ieee80211_clear_tx_pending(local); sta_info_stop(local); rate_control_deinitialize(local); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index e091cbc..1e04be6 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -292,13 +292,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (was_hw_scan) goto done; - spin_lock_bh(&local->filter_lock); - local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; - drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mc_count, - local->mc_list); - spin_unlock_bh(&local->filter_lock); + ieee80211_configure_filter(local); drv_sw_scan_complete(local); @@ -376,13 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) local->next_scan_state = SCAN_DECISION; local->scan_channel_idx = 0; - spin_lock_bh(&local->filter_lock); - local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; - drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mc_count, - local->mc_list); - spin_unlock_bh(&local->filter_lock); + ieee80211_configure_filter(local); /* TODO: start scan as soon as all nullfunc frames are ACKed */ ieee80211_queue_delayed_work(&local->hw, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e55d57f..5eb3063 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1076,9 +1076,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* reconfigure hardware */ ieee80211_hw_config(local, ~0); - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { -- cgit v0.10.2 From f424afa17899408cbd267a4c4534ca6fc9d8f71c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Aug 2009 16:18:07 +0200 Subject: mac80211: remove deprecated API All but two drivers have now stopped using the two deprecated members radio_enabled and beacon_int, so it's about time to remove them for good. Signed-off-by: Johannes Berg Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index a6e1954..8e1a55d 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1950,9 +1950,8 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed) { struct at76_priv *priv = hw->priv; - at76_dbg(DBG_MAC80211, "%s(): channel %d radio %d", - __func__, hw->conf.channel->hw_value, - hw->conf.radio_enabled); + at76_dbg(DBG_MAC80211, "%s(): channel %d", + __func__, hw->conf.channel->hw_value); at76_dbg_dump(DBG_MAC80211, priv->bssid, ETH_ALEN, "bssid:"); mutex_lock(&priv->mtx); diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index f843870..c32e93c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3031,13 +3031,6 @@ static int mwl8k_config_wt(struct work_struct *wt) struct mwl8k_priv *priv = hw->priv; int rc = 0; - if (!conf->radio_enabled) { - mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE); - priv->current_channel = NULL; - rc = 0; - goto mwl8k_config_exit; - } - if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) { rc = -EINVAL; goto mwl8k_config_exit; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index bc86520..aac84d7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -583,7 +583,6 @@ enum ieee80211_conf_flags { /** * enum ieee80211_conf_changed - denotes which configuration changed * - * @_IEEE80211_CONF_CHANGE_RADIO_ENABLED: DEPRECATED * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed @@ -593,7 +592,6 @@ enum ieee80211_conf_flags { * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed */ enum ieee80211_conf_changed { - _IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), IEEE80211_CONF_CHANGE_PS = BIT(4), @@ -603,14 +601,6 @@ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_IDLE = BIT(8), }; -static inline __deprecated enum ieee80211_conf_changed -__IEEE80211_CONF_CHANGE_RADIO_ENABLED(void) -{ - return _IEEE80211_CONF_CHANGE_RADIO_ENABLED; -} -#define IEEE80211_CONF_CHANGE_RADIO_ENABLED \ - __IEEE80211_CONF_CHANGE_RADIO_ENABLED() - /** * struct ieee80211_conf - configuration of the device * @@ -618,9 +608,6 @@ __IEEE80211_CONF_CHANGE_RADIO_ENABLED(void) * * @flags: configuration flags defined above * - * @radio_enabled: when zero, driver is required to switch off the radio. - * @beacon_int: DEPRECATED, DO NOT USE - * * @listen_interval: listen interval in units of beacon interval * @max_sleep_period: the maximum number of beacon intervals to sleep for * before checking the beacon for a TIM bit (managed mode only); this @@ -644,13 +631,11 @@ __IEEE80211_CONF_CHANGE_RADIO_ENABLED(void) * number of transmissions not the number of retries */ struct ieee80211_conf { - int __deprecated beacon_int; u32 flags; int power_level, dynamic_ps_timeout; int max_sleep_period; u16 listen_interval; - bool __deprecated radio_enabled; u8 long_frame_max_tx_count, short_frame_max_tx_count; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 05f9235..3302df9 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -241,9 +241,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, drv_bss_info_changed(local, &sdata->vif, &sdata->vif.bss_conf, changed); - - /* DEPRECATED */ - local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) @@ -687,7 +684,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.max_rates = 1; local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; - local->hw.conf.radio_enabled = true; local->user_power_level = -1; INIT_LIST_HEAD(&local->interfaces); -- cgit v0.10.2 From 1de6f73c34fb9a74454a5b519cefd635b5e8ceb6 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 17 Aug 2009 11:18:14 -0400 Subject: wl1251: correct definitions for 0th bit defines ACX_SLV_SOFT_RESET_BIT and ACX_REG_EEPROM_START_BIT are both defined as "1" in the vendor driver code, but they were defined to be BIT(1) ("2") here. The SOFT_RESET typo ensures that wl1251_boot_soft_reset() doesn't; as a result the device hangs when trying to reprogram the PLL registers while running. Signed-off-by: Bob Copeland Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h index bdd5610..06e1bd9 100644 --- a/drivers/net/wireless/wl12xx/wl1251_reg.h +++ b/drivers/net/wireless/wl12xx/wl1251_reg.h @@ -245,8 +245,8 @@ enum wl12xx_acx_int_reg { ACX_REG_TABLE_LEN }; -#define ACX_SLV_SOFT_RESET_BIT BIT(1) -#define ACX_REG_EEPROM_START_BIT BIT(1) +#define ACX_SLV_SOFT_RESET_BIT BIT(0) +#define ACX_REG_EEPROM_START_BIT BIT(0) /* Command/Information Mailbox Pointers */ -- cgit v0.10.2 From 12d4bba0fd7ac50ca20d9ac1247a0de851850bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 14 Aug 2009 20:29:47 +0200 Subject: b43: LP-PHY: Fix reading old mode in the set TX power control routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the mode the hardware is in, not the mode we used the last time. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index faca56f..ca52fd5 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1085,9 +1085,9 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev, struct b43_phy_lp *lpphy = dev->phy.lp; enum b43_lpphy_txpctl_mode oldmode; - oldmode = lpphy->txpctl_mode; lpphy_read_tx_pctl_mode_from_hardware(dev); - if (lpphy->txpctl_mode == mode) + oldmode = lpphy->txpctl_mode; + if (oldmode == mode) return; lpphy->txpctl_mode = mode; -- cgit v0.10.2 From 5f1c07d924d3e670044911487aca057bb39b4e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 14 Aug 2009 21:19:58 +0200 Subject: b43: LP-PHY: Fix setting TX power control mode during RC calibration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call set_tx_power_control with a LPPHY_TXPCTL rather than an LPPHY_TX_PWR_CTL_CMD_MODE. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index ca52fd5..9402383 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1159,7 +1159,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) lpphy_read_tx_pctl_mode_from_hardware(dev); old_txpctl = lpphy->txpctl_mode; - lpphy_set_tx_power_control(dev, B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF); + lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF); lpphy_disable_crs(dev); loopback = lpphy_loopback(dev); if (loopback == -1) -- cgit v0.10.2 From 73077c85458739169cdaf893a375b8bb3939d35a Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:53:24 +0200 Subject: rt2x00: Fix RFKILL polling The rfkill_poll callback function in the drivers check a bit to see if the RFKILL key has been pressed. However when the bit is set it means the radio is active and the device can be used. The wiphy_rfkill_set_hw_state() function expects the inversed, so '1' must be send when the radio must be disabled. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 602f126..3011aea 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -704,8 +704,8 @@ EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - bool blocked = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); + bool active = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); - wiphy_rfkill_set_hw_state(hw->wiphy, blocked); + wiphy_rfkill_set_hw_state(hw->wiphy, !active); } EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll); -- cgit v0.10.2 From 1738c9e42a9bb3705a3b03dde854f3db269e7bdd Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:53:57 +0200 Subject: rt2x00: Fix for rt2800usb for SHARED_KEY_TABLE initializations Fixed comments about SHARED_KEY_TABLE_BASE and SHARED_KEY_MODE_BASE. Fixed initialization loop for SHARED_KEY_MODE_ENTRY. Based on a patch for rt2800pci from Benoit. Signed-off-by: Benoit PAPILLAULT Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3856f06..c82474e 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1463,6 +1463,10 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) /* * ASIC will keep garbage value after boot, clear encryption keys. */ + for (i = 0; i < 4; i++) + rt2x00usb_register_write(rt2x00dev, + SHARED_KEY_MODE_ENTRY(i), 0); + for (i = 0; i < 256; i++) { u32 wcid[2] = { 0xffffffff, 0x00ffffff }; rt2x00usb_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), @@ -1472,10 +1476,6 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); } - for (i = 0; i < 16; i++) - rt2x00usb_register_write(rt2x00dev, - SHARED_KEY_MODE_ENTRY(i), 0); - /* * Clear all beacons * For the Beacon base registers we only need to clear diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 2d9dc37..a79a6d9 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -1300,8 +1300,8 @@ * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry - * SHARED_KEY_TABLE_BASE: 32-byte * 16-entry - * SHARED_KEY_MODE_BASE: 4-byte * 16-entry + * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry + * SHARED_KEY_MODE_BASE: 4 bits * 32-entry */ #define MAC_WCID_BASE 0x1800 #define PAIRWISE_KEY_TABLE_BASE 0x4000 -- cgit v0.10.2 From 05a32730f16e7b91e9fd2d11f26db152e5c9a68d Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:54:47 +0200 Subject: rt2x00: Add new RF chip defines Add new defines for RF chipsets which can be found by the driver. We don't have to check for these chips specifically yet, but it is better to have the defines in now. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index a79a6d9..4d9991c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -36,6 +36,9 @@ * RF2750 2.4G/5G 1T2R * RF3020 2.4G 1T1R * RF2020 2.4G B/G + * RF3021 2.4G 1T2R + * RF3022 2.4G 2T2R + * RF3052 2.4G 2T2R */ #define RF2820 0x0001 #define RF2850 0x0002 @@ -43,6 +46,9 @@ #define RF2750 0x0004 #define RF3020 0x0005 #define RF2020 0x0006 +#define RF3021 0x0007 +#define RF3022 0x0008 +#define RF3052 0x0009 /* * RT2870 version -- cgit v0.10.2 From 0fefe0fda4376eff97be965a41714da38fe4a36d Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:54:50 +0200 Subject: rt2x00: Set SKBDESC_L2_PADDED in RX path When the RX descriptor indicates the frame was L2 padded, the SKBDESC_L2_PADDED flag should be set to make sure the L2 padding is removed before it is send to mac80211. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index c82474e..6de2eda 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2163,8 +2163,10 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; - if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) + if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) { rxdesc->dev_flags |= RXDONE_L2PAD; + skbdesc->flags |= SKBDESC_L2_PADDED; + } if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) rxdesc->flags |= RX_FLAG_SHORT_GI; -- cgit v0.10.2 From 534aff0288f49a2366b7e6fbb67ff035dea814d3 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:55:15 +0200 Subject: rt2x00: wireless CLI ID and packet ID must not be 0 In the TX descriptor the Packet ID must not be 0, so add 1 to the ID. The wireless CLI ID is not allowed to be 0 either, but also must be initialized with the wcid value rather then keyid. Based on a patch for rt2800pci from Benoit Signed-off-by: Benoit PAPILLAULT Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 6de2eda..3633e58 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1995,11 +1995,11 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size); rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? - txdesc->key_idx : 0xff); + (skbdesc->entry->entry_idx + 1) : 0xff); rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, skb->len - txdesc->l2pad); rt2x00_set_field32(&word, TXWI_W1_PACKETID, - skbdesc->entry->entry_idx); + skbdesc->entry->queue->qid + 1); rt2x00_desc_write(txwi, 1, word); /* -- cgit v0.10.2 From cd80b684a08655e7dcc7a1c96d4b7e7ffa753017 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:55:40 +0200 Subject: rt2x00: Fix MCS register intialization According to the original Ralink driver, LG_FBK_CFG0_OFDMMCS2FBK should be initialized to 9 rather then 3. Based on a patch for rt2800pci from Benoit Signed-off-by: Benoit PAPILLAULT Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3633e58..45e02f1 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1520,7 +1520,7 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG0, ®); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 3); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 9); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 10); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 11); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); -- cgit v0.10.2 From 92ed48e5230e8f5906dda0cc31715b3b7e3fe303 Mon Sep 17 00:00:00 2001 From: Benoit PAPILLAULT Date: Mon, 17 Aug 2009 18:56:10 +0200 Subject: rt2x00: Add support for retry rates rt2800pci can handle different retry rates, it will always step 1 rate down after a failed transmission so creating the retry rate list for mac80211 is quite simple. Signed-off-by: Benoit PAPILLAULT Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b6676c6..9ab70e4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -220,7 +220,8 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - u8 rate_idx, rate_flags; + u8 rate_idx, rate_flags, retry_rates; + unsigned int i; /* * Unmap the skb. @@ -259,16 +260,27 @@ void rt2x00lib_txdone(struct queue_entry *entry, rate_idx = skbdesc->tx_rate_idx; rate_flags = skbdesc->tx_rate_flags; + retry_rates = test_bit(TXDONE_FALLBACK, &txdesc->flags) ? + (txdesc->retry + 1) : 1; /* * Initialize TX status */ memset(&tx_info->status, 0, sizeof(tx_info->status)); tx_info->status.ack_signal = 0; - tx_info->status.rates[0].idx = rate_idx; - tx_info->status.rates[0].flags = rate_flags; - tx_info->status.rates[0].count = txdesc->retry + 1; - tx_info->status.rates[1].idx = -1; /* terminate */ + + /* + * Frame was send with retries, hardware tried + * different rates to send out the frame, at each + * retry it lowered the rate 1 step. + */ + for (i = 0; i < retry_rates && i < IEEE80211_TX_MAX_RATES; i++) { + tx_info->status.rates[i].idx = rate_idx - i; + tx_info->status.rates[i].flags = rate_flags; + tx_info->status.rates[i].count = 1; + } + if (i < (IEEE80211_TX_MAX_RATES -1)) + tx_info->status.rates[i].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 47d175a..a5591fb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -214,6 +214,7 @@ struct rxdone_entry_desc { * * @TXDONE_UNKNOWN: Hardware could not determine success of transmission. * @TXDONE_SUCCESS: Frame was successfully send + * @TXDONE_FALLBACK: Frame was successfully send using a fallback rate. * @TXDONE_FAILURE: Frame was not successfully send * @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the * frame transmission failed due to excessive retries. @@ -221,6 +222,7 @@ struct rxdone_entry_desc { enum txdone_entry_desc_flags { TXDONE_UNKNOWN, TXDONE_SUCCESS, + TXDONE_FALLBACK, TXDONE_FAILURE, TXDONE_EXCESSIVE_RETRY, }; -- cgit v0.10.2 From bfc32e6a9559d3e30925929cd9a9df7498f325db Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 17 Aug 2009 17:15:55 -0700 Subject: mac80211: Decouple fail_avg stats used by mesh from rate control algorithm. Mesh uses the tx failure average to compute the (m)path metric. This used to be done inside the rate control module. This patch breaks the dependency between the mesh stack and the rate control algorithm. Mesh will now work independently of the chosen rate control algorithm. The mesh stack keeps a moving average of the average transmission losses for each mesh peer station. If the fail average exceeds a certain threshold, the peer link is marked as broken. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 3302df9..f80efd7 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -482,6 +482,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) } rate_control_tx_status(local, sband, sta, skb); + if (ieee80211_vif_is_mesh(&sta->sdata->vif)) + ieee80211s_update_metric(local, sta, skb); } rcu_read_unlock(); diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index eb23fc6..dd1c193 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -226,6 +226,8 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); void ieee80211s_init(void); +void ieee80211s_update_metric(struct ieee80211_local *local, + struct sta_info *stainfo, struct sk_buff *skb); void ieee80211s_stop(void); void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index ef1efd3..7aeba00 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -201,6 +201,24 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, return 0; } +void ieee80211s_update_metric(struct ieee80211_local *local, + struct sta_info *stainfo, struct sk_buff *skb) +{ + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + int failed; + + if (!ieee80211_is_data(hdr->frame_control)) + return; + + failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); + + /* moving average, scaled to 100 */ + stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed); + if (stainfo->fail_avg > 95) + mesh_plink_broken(stainfo); +} + static u32 airtime_link_metric_get(struct ieee80211_local *local, struct sta_info *sta) { diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 0071649..7c51429 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -51,7 +51,6 @@ #include #include #include -#include "mesh.h" #include "rate.h" #include "rc80211_minstrel.h" @@ -156,16 +155,12 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, struct sk_buff *skb) { struct minstrel_sta_info *mi = priv_sta; - struct minstrel_priv *mp = (struct minstrel_priv *)priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *ar = info->status.rates; - struct ieee80211_local *local = hw_to_local(mp->hw); - struct sta_info *si; int i, ndx; int success; success = !!(info->flags & IEEE80211_TX_STAT_ACK); - si = sta_info_get(local, sta->addr); for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { if (ar[i].idx < 0) @@ -177,17 +172,8 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, mi->r[ndx].attempts += ar[i].count; - if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) { + if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) mi->r[ndx].success += success; - if (si) { - si->fail_avg = (18050 - mi->r[ndx].probability) - / 180; - WARN_ON(si->fail_avg > 100); - if (si->fail_avg == 100 && - ieee80211_vif_is_mesh(&si->sdata->vif)) - mesh_plink_broken(si); - } - } } if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 8c053be..f6e25d7 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -169,19 +169,9 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, * still a good measurement and copy it. */ if (unlikely(spinfo->tx_num_xmit == 0)) pf = spinfo->last_pf; - else { - /* XXX: BAD HACK!!! */ - struct sta_info *si = container_of(sta, struct sta_info, sta); - + else pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; - if (ieee80211_vif_is_mesh(&si->sdata->vif) && pf == 100) - mesh_plink_broken(si); - pf <<= RC_PID_ARITH_SHIFT; - si->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9) - >> RC_PID_ARITH_SHIFT; - } - spinfo->tx_num_xmit = 0; spinfo->tx_num_failed = 0; @@ -348,9 +338,6 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, } spinfo->txrate_idx = rate_lowest_index(sband, sta); - /* HACK */ - si = container_of(sta, struct sta_info, sta); - si->fail_avg = 0; } static void *rate_control_pid_alloc(struct ieee80211_hw *hw, -- cgit v0.10.2 From bcd64e0c20eafe6a3976c248833d5d8bcccdf0d9 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 17 Aug 2009 23:33:56 -0400 Subject: wl1251: halt the embedded CPU before loading firmware After initial power-up, the embedded cpu is usually halted. However, if we down the interface and only do a soft reset before bringing the interface back up, it will still be running and the firmware loading code will bail out. This change halts the CPU before loading the firmware, enabling a second call to wl1251_boot() to succeed without a hard reset. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 592c3b5..452d748 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -465,6 +465,9 @@ int wl1251_boot(struct wl1251 *wl) int ret = 0, minor_minor_e2_ver; u32 tmp, boot_data; + /* halt embedded ARM CPU while loading firmware */ + wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, ECPU_CONTROL_HALT); + ret = wl1251_boot_soft_reset(wl); if (ret < 0) goto out; -- cgit v0.10.2 From 4c48381786159ba3f3d8a33d967aeb049341a220 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Aug 2009 10:51:52 +0530 Subject: ath9k: Fix TX poll cancelling In ath9k_stop(), tx_complete_work was being cancelled twice. This patch fixes it. Also, locking sc->mutex should be done at the beginning. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2f9c149..fddda20 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2105,6 +2105,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + mutex_lock(&sc->mutex); + aphy->state = ATH_WIPHY_INACTIVE; cancel_delayed_work_sync(&sc->ath_led_blink_work); @@ -2117,13 +2119,10 @@ static void ath9k_stop(struct ieee80211_hw *hw) if (sc->sc_flags & SC_OP_INVALID) { DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); + mutex_unlock(&sc->mutex); return; } - mutex_lock(&sc->mutex); - - cancel_delayed_work_sync(&sc->tx_complete_work); - if (ath9k_wiphy_started(sc)) { mutex_unlock(&sc->mutex); return; /* another wiphy still in use */ -- cgit v0.10.2 From 608b88cb34b0e70a538ee1fc334cc833ef691836 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 17 Aug 2009 18:07:23 -0700 Subject: ath: move regulatory info into shared common structure This moves the shared regulatory structure into the common structure. We will use this ongoing for common data. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index e6c3ee3..95f8256 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -157,6 +157,7 @@ struct ar9170_sta_tid { struct ar9170 { struct ieee80211_hw *hw; + struct ath_common common; struct mutex mutex; enum ar9170_device_state state; unsigned long bad_hw_nagger; @@ -222,7 +223,6 @@ struct ar9170 { /* EEPROM */ struct ar9170_eeprom eeprom; - struct ath_regulatory regulatory; /* tx queues - as seen by hw - */ struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 6a9462e..d30f33d 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2641,6 +2641,7 @@ static int ar9170_read_eeprom(struct ar9170 *ar) { #define RW 8 /* number of words to read at once */ #define RB (sizeof(u32) * RW) + struct ath_regulatory *regulatory = &ar->common.regulatory; u8 *eeprom = (void *)&ar->eeprom; u8 *addr = ar->eeprom.mac_address; __le32 offsets[RW]; @@ -2707,8 +2708,8 @@ static int ar9170_read_eeprom(struct ar9170 *ar) else ar->hw->channel_change_time = 80 * 1000; - ar->regulatory.current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); - ar->regulatory.current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); + regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); + regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); /* second part of wiphy init */ SET_IEEE80211_PERM_ADDR(ar->hw, addr); @@ -2722,11 +2723,12 @@ static int ar9170_reg_notifier(struct wiphy *wiphy, struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ar9170 *ar = hw->priv; - return ath_reg_notifier_apply(wiphy, request, &ar->regulatory); + return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory); } int ar9170_register(struct ar9170 *ar, struct device *pdev) { + struct ath_regulatory *regulatory = &ar->common.regulatory; int err; /* try to read EEPROM, init MAC addr */ @@ -2734,7 +2736,7 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) if (err) goto err_out; - err = ath_regd_init(&ar->regulatory, ar->hw->wiphy, + err = ath_regd_init(regulatory, ar->hw->wiphy, ar9170_reg_notifier); if (err) goto err_out; @@ -2743,8 +2745,8 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) if (err) goto err_out; - if (!ath_is_world_regd(&ar->regulatory)) - regulatory_hint(ar->hw->wiphy, ar->regulatory.alpha2); + if (!ath_is_world_regd(regulatory)) + regulatory_hint(ar->hw->wiphy, regulatory->alpha2); err = ar9170_init_leds(ar); if (err) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index e284cd3..a63e90c 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -19,8 +19,26 @@ #include +struct reg_dmn_pair_mapping { + u16 regDmnEnum; + u16 reg_5ghz_ctl; + u16 reg_2ghz_ctl; +}; + +struct ath_regulatory { + char alpha2[2]; + u16 country_code; + u16 max_power_level; + u32 tp_scale; + u16 current_rd; + u16 current_rd_ext; + int16_t power_limit; + struct reg_dmn_pair_mapping *regpair; +}; + struct ath_common { u16 cachelsz; + struct ath_regulatory regulatory; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index c09402e..862762ce 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -27,8 +27,6 @@ #include #include -#include "../regd.h" - /* RX/TX descriptor hw structs * TODO: Driver part should only see sw structs */ #include "desc.h" @@ -1077,7 +1075,6 @@ struct ath5k_hw { int ah_gpio_npins; - struct ath_regulatory ah_regulatory; struct ath5k_capabilities ah_capabilities; struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES]; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 3951b5b..5056410 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -718,9 +718,9 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath5k_softc *sc = hw->priv; - struct ath_regulatory *reg = &sc->ah->ah_regulatory; + struct ath_regulatory *regulatory = &sc->common.regulatory; - return ath_reg_notifier_apply(wiphy, request, reg); + return ath_reg_notifier_apply(wiphy, request, regulatory); } static int @@ -728,6 +728,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; + struct ath_regulatory *regulatory = &sc->common.regulatory; u8 mac[ETH_ALEN] = {}; int ret; @@ -817,9 +818,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) memset(sc->bssidmask, 0xff, ETH_ALEN); ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); - ah->ah_regulatory.current_rd = - ah->ah_capabilities.cap_eeprom.ee_regdomain; - ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier); + regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; + ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); if (ret) { ATH5K_ERR(sc, "can't initialize regulatory system\n"); goto err_queues; @@ -831,8 +831,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) goto err_queues; } - if (!ath_is_world_regd(&sc->ah->ah_regulatory)) - regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2); + if (!ath_is_world_regd(regulatory)) + regulatory_hint(hw->wiphy, regulatory->alpha2); ath5k_init_leds(sc); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 25a72a8..a28c42f 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -50,6 +50,8 @@ #include "ath5k.h" #include "debug.h" + +#include "../regd.h" #include "../ath.h" #define ATH_RXBUF 40 /* number of RX buffers */ @@ -200,4 +202,15 @@ struct ath5k_softc { #define ath5k_hw_hasveol(_ah) \ (ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0) +static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah) +{ + return &ah->ah_sc->common; +} + +static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah) +{ + return &(ath5k_hw_common(ah)->regulatory); + +} + #endif diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 298fcf0..1a039f2 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -2198,6 +2198,7 @@ static void ath5k_get_max_ctl_power(struct ath5k_hw *ah, struct ieee80211_channel *channel) { + struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; struct ath5k_edge_power *rep = ee->ee_ctl_pwr; u8 *ctl_val = ee->ee_ctl; @@ -2208,7 +2209,7 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah, u8 ctl_idx = 0xFF; u32 target = channel->center_freq; - ctl_mode = ath_regd_get_band_ctl(&ah->ah_regulatory, channel->band); + ctl_mode = ath_regd_get_band_ctl(regulatory, channel->band); switch (channel->hw_value & CHANNEL_MODES) { case CHANNEL_A: diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2c9f662..0e444a6 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -631,6 +631,16 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); int ath_cabq_update(struct ath_softc *); +static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) +{ + return &ah->ah_sc->common; +} + +static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) +{ + return &(ath9k_hw_common(ah)->regulatory); +} + static inline void ath_read_cachesize(struct ath_softc *sc, int *csz) { sc->bus_ops->read_cachesize(sc, csz); diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index d34dd23..b8eca7b 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -508,6 +508,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL)) + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); int i; int16_t twiceLargestAntenna; u16 twiceMinEdgePower; @@ -541,9 +542,9 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, twiceLargestAntenna, 0); maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) { maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + (tpScaleReductionTable[(regulatory->tp_scale)] * 2); } scaledPower = min(powerLimit, maxRegAllowedPower); @@ -707,6 +708,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, u8 twiceMaxRegulatoryPower, u8 powerLimit) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; struct modal_eep_4k_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; @@ -744,7 +746,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, else if (IS_CHAN_HT20(chan)) i = rateHt20_0; - ah->regulatory.max_power_level = ratesArray[i]; + regulatory->max_power_level = ratesArray[i]; if (AR_SREV_9280_10_OR_LATER(ah)) { for (i = 0; i < Ar5416RateSize; i++) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 9590979..c20c21a 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -599,7 +599,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, { #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 - + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; @@ -632,9 +632,9 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, twiceLargestAntenna, 0); maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) + if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + (tpScaleReductionTable[(regulatory->tp_scale)] * 2); scaledPower = min(powerLimit, maxRegAllowedPower); @@ -831,7 +831,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, { #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 - + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; @@ -949,20 +949,20 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, i = rate6mb; if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = + regulatory->max_power_level = ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; else - ah->regulatory.max_power_level = ratesArray[i]; + regulatory->max_power_level = ratesArray[i]; switch (ar5416_get_ntxchains(ah->txchainmask)) { case 1: break; case 2: - ah->regulatory.max_power_level += + regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; break; case 3: - ah->regulatory.max_power_level += + regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 5211ad9..ae7fb5d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -904,6 +904,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; static const u16 tpScaleReductionTable[5] = @@ -953,9 +954,9 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) { maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + (tpScaleReductionTable[(regulatory->tp_scale)] * 2); } scaledPower = min(powerLimit, maxRegAllowedPower); @@ -1163,6 +1164,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, u8 powerLimit) { #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; struct modal_eep_header *pModal = &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); @@ -1292,19 +1294,19 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, i = rateHt20_0; if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = + regulatory->max_power_level = ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; else - ah->regulatory.max_power_level = ratesArray[i]; + regulatory->max_power_level = ratesArray[i]; switch(ar5416_get_ntxchains(ah->txchainmask)) { case 1: break; case 2: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; + regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; break; case 3: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; + regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index df62113..4f3d5ea 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -439,8 +439,13 @@ static void ath9k_hw_init_config(struct ath_hw *ah) static void ath9k_hw_init_defaults(struct ath_hw *ah) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + + regulatory->country_code = CTRY_DEFAULT; + regulatory->power_limit = MAX_RATE_POWER; + regulatory->tp_scale = ATH9K_TP_SCALE_MAX; + ah->hw_version.magic = AR5416_MAGIC; - ah->regulatory.country_code = CTRY_DEFAULT; ah->hw_version.subvendorid = 0; ah->ah_flags = 0; @@ -449,8 +454,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) if (!AR_SREV_9100(ah)) ah->ah_flags = AH_USE_EEPROM; - ah->regulatory.power_limit = MAX_RATE_POWER; - ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX; ah->atim_window = 0; ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE; ah->beacon_interval = 100; @@ -1368,6 +1371,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); int i, regWrites = 0; struct ieee80211_channel *channel = chan->chan; u32 modesIndex, freqIndex; @@ -1474,11 +1478,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, ath9k_olc_init(ah); ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), + ath9k_regd_get_ctl(regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); + (u32) regulatory->power_limit)); if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, @@ -1796,6 +1800,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ieee80211_channel *channel = chan->chan; u32 synthDelay, qnum; @@ -1828,11 +1833,11 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, } ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), + ath9k_regd_get_ctl(regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); + (u32) regulatory->power_limit)); synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IS_CHAN_B(chan)) @@ -3480,27 +3485,29 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, void ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + u16 capField = 0, eeval; eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); - ah->regulatory.current_rd = eeval; + regulatory->current_rd = eeval; eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1); if (AR_SREV_9285_10_OR_LATER(ah)) eeval |= AR9285_RDEXT_DEFAULT; - ah->regulatory.current_rd_ext = eeval; + regulatory->current_rd_ext = eeval; capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); if (ah->opmode != NL80211_IFTYPE_AP && ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) { - if (ah->regulatory.current_rd == 0x64 || - ah->regulatory.current_rd == 0x65) - ah->regulatory.current_rd += 5; - else if (ah->regulatory.current_rd == 0x41) - ah->regulatory.current_rd = 0x43; + if (regulatory->current_rd == 0x64 || + regulatory->current_rd == 0x65) + regulatory->current_rd += 5; + else if (regulatory->current_rd == 0x41) + regulatory->current_rd = 0x43; DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "regdomain mapped to 0x%x\n", ah->regulatory.current_rd); + "regdomain mapped to 0x%x\n", regulatory->current_rd); } eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE); @@ -3635,7 +3642,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - if (ah->regulatory.current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { + if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { pCap->reg_cap = AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | @@ -3664,6 +3671,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 *result) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); switch (type) { case ATH9K_CAP_CIPHER: switch (capability) { @@ -3712,13 +3720,13 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, case 0: return 0; case 1: - *result = ah->regulatory.power_limit; + *result = regulatory->power_limit; return 0; case 2: - *result = ah->regulatory.max_power_level; + *result = regulatory->max_power_level; return 0; case 3: - *result = ah->regulatory.tp_scale; + *result = regulatory->tp_scale; return 0; } return false; @@ -3956,17 +3964,18 @@ bool ath9k_hw_disable(struct ath_hw *ah) void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath9k_channel *chan = ah->curchan; struct ieee80211_channel *channel = chan->chan; - ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER); + regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER); ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), + ath9k_regd_get_ctl(regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); + (u32) regulatory->power_limit)); } void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index de31a15..24b3063 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -396,7 +396,6 @@ struct ath_hw { struct ath9k_hw_version hw_version; struct ath9k_ops_config config; struct ath9k_hw_capabilities caps; - struct ath_regulatory regulatory; struct ath9k_channel channels[38]; struct ath9k_channel *curchan; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index fddda20..de19711 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1293,7 +1293,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_regulatory *reg = &sc->sc_ah->regulatory; + struct ath_regulatory *reg = &sc->common.regulatory; return ath_reg_notifier_apply(wiphy, request, reg); } @@ -1586,12 +1586,12 @@ int ath_init_device(u16 devid, struct ath_softc *sc) ath_set_hw_capab(sc, hw); - error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, + error = ath_regd_init(&sc->common.regulatory, sc->hw->wiphy, ath9k_reg_notifier); if (error) return error; - reg = &sc->sc_ah->regulatory; + reg = &sc->common.regulatory; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 07291cc..4d3c536 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -18,9 +18,10 @@ #define REGD_H #include - #include +#include "ath.h" + #define NO_CTL 0xff #define SD_NO_CTL 0xE0 #define NO_CTL 0xff @@ -47,29 +48,12 @@ #define CHANNEL_HALF_BW 10 #define CHANNEL_QUARTER_BW 5 -struct reg_dmn_pair_mapping { - u16 regDmnEnum; - u16 reg_5ghz_ctl; - u16 reg_2ghz_ctl; -}; - struct country_code_to_enum_rd { u16 countryCode; u16 regDmnEnum; const char *isoName; }; -struct ath_regulatory { - char alpha2[2]; - u16 country_code; - u16 max_power_level; - u32 tp_scale; - u16 current_rd; - u16 current_rd_ext; - int16_t power_limit; - struct reg_dmn_pair_mapping *regpair; -}; - enum CountryCode { CTRY_ALBANIA = 8, CTRY_ALGERIA = 12, -- cgit v0.10.2 From 29508d122a5228c2a68d1e9a39251d3991b3cfef Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Aug 2009 10:46:42 -0400 Subject: rc80211_pid_algo.c: remove unused variable declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] net/mac80211/rc80211_pid_algo.o net/mac80211/rc80211_pid_algo.c: In function ‘rate_control_pid_rate_init’: net/mac80211/rc80211_pid_algo.c:304: warning: unused variable ‘si’ Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index f6e25d7..699d3ed 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -301,7 +301,6 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, struct rc_pid_sta_info *spinfo = priv_sta; struct rc_pid_info *pinfo = priv; struct rc_pid_rateinfo *rinfo = pinfo->rinfo; - struct sta_info *si; int i, j, tmp; bool s; -- cgit v0.10.2 From e5539bcbf64fdb16af73b5c8caff9255307490b5 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Aug 2009 10:50:34 -0400 Subject: wl1271: remove print_mac usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/wl12xx/wl1271_main.o drivers/net/wireless/wl12xx/wl1271_main.c: In function ‘wl1271_op_add_interface’: drivers/net/wireless/wl12xx/wl1271_main.c:611: warning: ‘print_mac’ is deprecated (declared at include/linux/if_ether.h:142) Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 754be81..d9169b4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -605,11 +605,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct wl1271 *wl = hw->priv; - DECLARE_MAC_BUF(mac); int ret = 0; - wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", - conf->type, print_mac(mac, conf->mac_addr)); + wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", + conf->type, conf->mac_addr); mutex_lock(&wl->mutex); -- cgit v0.10.2 From c8a61a7d33350eeec668fc6230ad55f5fa93209b Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 18 Aug 2009 10:59:00 -0700 Subject: mac80211: New stat counters for multicast and unicast forwarded frames This expands on the current fwded_frames stat counter which should be equal to the total of these two new counters. The new counters are called "fwded_mcast" and "fwded_unicast". Signed-off-by: Daniel Walker Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index e9ec6ca..61234e7 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -116,6 +116,8 @@ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); #ifdef CONFIG_MAC80211_MESH /* Mesh stats attributes */ +IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC); +IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC); IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC); IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC); IEEE80211_IF_FILE(dropped_frames_no_route, @@ -205,6 +207,8 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) { sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats", sdata->debugfsdir); + MESHSTATS_ADD(fwded_mcast); + MESHSTATS_ADD(fwded_unicast); MESHSTATS_ADD(fwded_frames); MESHSTATS_ADD(dropped_frames_ttl); MESHSTATS_ADD(dropped_frames_no_route); @@ -327,6 +331,8 @@ static void del_monitor_files(struct ieee80211_sub_if_data *sdata) static void del_mesh_stats(struct ieee80211_sub_if_data *sdata) { + MESHSTATS_DEL(fwded_mcast); + MESHSTATS_DEL(fwded_unicast); MESHSTATS_DEL(fwded_frames); MESHSTATS_DEL(dropped_frames_ttl); MESHSTATS_DEL(dropped_frames_no_route); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a07f017..93e618a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -212,7 +212,9 @@ struct ieee80211_if_vlan { }; struct mesh_stats { - __u32 fwded_frames; /* Mesh forwarded frames */ + __u32 fwded_mcast; /* Mesh forwarded multicast frames */ + __u32 fwded_unicast; /* Mesh forwarded unicast frames */ + __u32 fwded_frames; /* Mesh total forwarded frames */ __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ __u32 dropped_frames_no_route; /* Not transmitted, no route found */ atomic_t estab_plinks; @@ -506,6 +508,8 @@ struct ieee80211_sub_if_data { #ifdef CONFIG_MAC80211_MESH struct dentry *mesh_stats_dir; struct { + struct dentry *fwded_mcast; + struct dentry *fwded_unicast; struct dentry *fwded_frames; struct dentry *dropped_frames_ttl; struct dentry *dropped_frames_no_route; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 7aeba00..e12a786 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -497,6 +497,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), cpu_to_le32(preq_id), sdata); + ifmsh->mshstats.fwded_mcast++; ifmsh->mshstats.fwded_frames++; } } @@ -555,6 +556,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); rcu_read_unlock(); + + sdata->u.mesh.mshstats.fwded_unicast++; sdata->u.mesh.mshstats.fwded_frames++; return; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4cd9e45..7065fd7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1550,7 +1550,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->control.vif = &rx->sdata->vif; ieee80211_select_queue(local, fwd_skb); - if (!is_multicast_ether_addr(fwd_hdr->addr1)) { + if (is_multicast_ether_addr(fwd_hdr->addr1)) + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, + fwded_mcast); + else { int err; /* * Save TA to addr1 to send TA a path error if a @@ -1564,6 +1567,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) * later to the pending skb queue. */ if (err) return RX_DROP_MONITOR; + + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, + fwded_unicast); } IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, fwded_frames); -- cgit v0.10.2 From 21f8a73f829797eb7ebc12202b4c68e10e751ddb Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Tue, 18 Aug 2009 10:25:05 -0700 Subject: ipw2x00: fix sparse warnings This fixes: CHECK drivers/net/wireless/ipw2x00/ipw2100.c drivers/net/wireless/ipw2x00/ipw2100.c:7888:22: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:188:12: originally declared here drivers/net/wireless/ipw2x00/ipw2100.c:7952:18: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:188:12: originally declared here drivers/net/wireless/ipw2x00/ipw2100.c:8000:18: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:188:12: originally declared here drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: originally declared here drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: originally declared here drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: originally declared here CC [M] drivers/net/wireless/ipw2x00/ipw2100.o CHECK drivers/net/wireless/ipw2x00/ipw2200.c drivers/net/wireless/ipw2x00/ipw2200.c:847:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:891:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:935:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:980:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:1016:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:1051:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:1823:13: warning: symbol 'channel' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:86:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:6228:28: warning: symbol 'channel' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:86:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:6369:20: warning: symbol 'channel' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:86:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:6857:12: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:87:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:7964:13: warning: symbol 'channel' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:86:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:8720:12: warning: symbol 'channel' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:86:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:9662:13: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:87:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:9720:13: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:87:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:9826:13: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:87:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:10318:21: warning: symbol 'remaining_bytes' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:10184:13: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:8338:45: warning: cast to restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:4414:21: warning: incorrect type in assignment (different base types) drivers/net/wireless/ipw2x00/ipw2200.c:4414:21: expected restricted __le16 [usertype] size drivers/net/wireless/ipw2x00/ipw2200.c:4414:21: got unsigned short [unsigned] [usertype] drivers/net/wireless/ipw2x00/ipw2200.c:6105:33: warning: incorrect type in initializer (different base types) drivers/net/wireless/ipw2x00/ipw2200.c:6105:33: expected restricted __le16 [usertype] tx_rates drivers/net/wireless/ipw2x00/ipw2200.c:6105:33: got unsigned short [unsigned] [usertype] rates_mask drivers/net/wireless/ipw2x00/ipw2200.c:6124:29: warning: bad assignment (>>=) to restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:6130:31: warning: restricted __le16 degrades to integer drivers/net/wireless/ipw2x00/ipw2200.c:6140:23: warning: restricted __le16 degrades to integer drivers/net/wireless/ipw2x00/ipw2200.c:6149:54: warning: restricted __le16 degrades to integer drivers/net/wireless/ipw2x00/ipw2200.c:6151:37: warning: invalid assignment: &= drivers/net/wireless/ipw2x00/ipw2200.c:6151:37: left side has type restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:6151:37: right side has type int drivers/net/wireless/ipw2x00/ipw2200.c:6154:54: warning: restricted __le16 degrades to integer drivers/net/wireless/ipw2x00/ipw2200.c:6156:37: warning: invalid assignment: &= drivers/net/wireless/ipw2x00/ipw2200.c:6156:37: left side has type restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:6156:37: right side has type int drivers/net/wireless/ipw2x00/ipw2200.c:6159:55: warning: restricted __le16 degrades to integer drivers/net/wireless/ipw2x00/ipw2200.c:6161:37: warning: invalid assignment: &= drivers/net/wireless/ipw2x00/ipw2200.c:6161:37: left side has type restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:6161:37: right side has type int drivers/net/wireless/ipw2x00/ipw2200.c:6164:29: warning: invalid assignment: |= drivers/net/wireless/ipw2x00/ipw2200.c:6164:29: left side has type restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:6164:29: right side has type unsigned short drivers/net/wireless/ipw2x00/ipw2200.c:7853:29: warning: incorrect type in assignment (different base types) drivers/net/wireless/ipw2x00/ipw2200.c:7853:29: expected signed char [signed] [usertype] [explicitly-signed] rt_dbmnoise drivers/net/wireless/ipw2x00/ipw2200.c:7853:29: got restricted __le16 [usertype] noise drivers/net/wireless/ipw2x00/ipw2200.c:7967:25: warning: incorrect type in initializer (different base types) drivers/net/wireless/ipw2x00/ipw2200.c:7967:25: expected signed char [signed] [usertype] [explicitly-signed] noise drivers/net/wireless/ipw2x00/ipw2200.c:7967:25: got restricted __le16 [usertype] noise Signed-off-by: Reinette Chatre Cc: Zhu Yi Acked-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 7424323..dee50ed 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -185,7 +185,7 @@ MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); static int debug = 0; -static int mode = 0; +static int network_mode = 0; static int channel = 0; static int associate = 0; static int disable = 0; @@ -195,7 +195,7 @@ static struct ipw2100_fw ipw2100_firmware; #include module_param(debug, int, 0444); -module_param(mode, int, 0444); +module_param_named(mode, network_mode, int, 0444); module_param(channel, int, 0444); module_param(associate, int, 0444); module_param(disable, int, 0444); @@ -2844,7 +2844,7 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv) #ifdef CONFIG_IPW2100_DEBUG { - int i = txq->oldest; + i = txq->oldest; IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i, &txq->drv[i], (u32) (txq->nic + i * sizeof(struct ipw2100_bd)), @@ -6076,7 +6076,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, priv->ieee->ieee802_1x = 1; /* Set module parameters */ - switch (mode) { + switch (network_mode) { case 1: priv->ieee->iw_mode = IW_MODE_ADHOC; break; @@ -8179,10 +8179,11 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) int rssi_qual; int tx_qual; int beacon_qual; + int quality; struct ipw2100_priv *priv = ieee80211_priv(dev); struct iw_statistics *wstats; - u32 rssi, quality, tx_retries, missed_beacons, tx_failures; + u32 rssi, tx_retries, missed_beacons, tx_failures; u32 ord_len = sizeof(u32); if (!priv) @@ -8265,7 +8266,8 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) beacon_qual = (20 - missed_beacons) * (PERFECT - VERY_GOOD) / 20 + VERY_GOOD; - quality = min(beacon_qual, min(tx_qual, rssi_qual)); + quality = min(tx_qual, rssi_qual); + quality = min(beacon_qual, quality); #ifdef CONFIG_IPW2100_DEBUG if (beacon_qual == quality) diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 07f171c..8e18d53 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -83,13 +83,13 @@ MODULE_LICENSE("GPL"); static int cmdlog = 0; static int debug = 0; -static int channel = 0; -static int mode = 0; +static int default_channel = 0; +static int network_mode = 0; static u32 ipw_debug_level; static int associate; static int auto_create = 1; -static int led = 0; +static int led_support = 0; static int disable = 0; static int bt_coexist = 0; static int hwcrypto = 0; @@ -4265,9 +4265,10 @@ static void ipw_gather_stats(struct ipw_priv *priv) IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", signal_quality, rssi); - quality = min(beacon_quality, - min(rate_quality, - min(tx_quality, min(rx_quality, signal_quality)))); + quality = min(rx_quality, signal_quality); + quality = min(tx_quality, quality); + quality = min(rate_quality, quality); + quality = min(beacon_quality, quality); if (quality == beacon_quality) IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n", quality); @@ -4411,7 +4412,6 @@ static void ipw_rx_notification(struct ipw_priv *priv, { DECLARE_SSID_BUF(ssid); u16 size = le16_to_cpu(notif->size); - notif->size = le16_to_cpu(notif->size); IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size); @@ -6101,11 +6101,10 @@ static void ipw_debug_config(struct ipw_priv *priv) static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) { /* TODO: Verify that this works... */ - struct ipw_fixed_rate fr = { - .tx_rates = priv->rates_mask - }; + struct ipw_fixed_rate fr; u32 reg; u16 mask = 0; + u16 new_tx_rates = priv->rates_mask; /* Identify 'current FW band' and match it with the fixed * Tx rates */ @@ -6117,54 +6116,56 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; + new_tx_rates = 0; break; } - fr.tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A; + new_tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A; break; default: /* 2.4Ghz or Mixed */ /* IEEE_B */ if (mode == IEEE_B) { - if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) { + if (new_tx_rates & ~IEEE80211_CCK_RATES_MASK) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; + new_tx_rates = 0; } break; } /* IEEE_G */ - if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK | + if (new_tx_rates & ~(IEEE80211_CCK_RATES_MASK | IEEE80211_OFDM_RATES_MASK)) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; + new_tx_rates = 0; break; } - if (IEEE80211_OFDM_RATE_6MB_MASK & fr.tx_rates) { + if (IEEE80211_OFDM_RATE_6MB_MASK & new_tx_rates) { mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK; + new_tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK; } - if (IEEE80211_OFDM_RATE_9MB_MASK & fr.tx_rates) { + if (IEEE80211_OFDM_RATE_9MB_MASK & new_tx_rates) { mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK; + new_tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK; } - if (IEEE80211_OFDM_RATE_12MB_MASK & fr.tx_rates) { + if (IEEE80211_OFDM_RATE_12MB_MASK & new_tx_rates) { mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK; + new_tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK; } - fr.tx_rates |= mask; + new_tx_rates |= mask; break; } + fr.tx_rates = cpu_to_le16(new_tx_rates); + reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE); ipw_write_reg32(priv, reg, *(u32 *) & fr); } @@ -7850,7 +7851,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, /* Convert signal to DBM */ ipw_rt->rt_dbmsignal = antsignal; - ipw_rt->rt_dbmnoise = frame->noise; + ipw_rt->rt_dbmnoise = (s8) le16_to_cpu(frame->noise); /* Convert the channel data and set the flags */ ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel)); @@ -7964,7 +7965,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, u16 channel = frame->received_channel; u8 phy_flags = frame->antennaAndPhy; s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM; - s8 noise = frame->noise; + s8 noise = (s8) le16_to_cpu(frame->noise); u8 rate = frame->rate; short len = le16_to_cpu(pkt->u.frame.length); struct sk_buff *skb; @@ -8335,7 +8336,7 @@ static void ipw_rx(struct ipw_priv *priv) .rssi = pkt->u.frame.rssi_dbm - IPW_RSSI_TO_DBM, .signal = - le16_to_cpu(pkt->u.frame.rssi_dbm) - + pkt->u.frame.rssi_dbm - IPW_RSSI_TO_DBM + 0x100, .noise = le16_to_cpu(pkt->u.frame.noise), @@ -8517,7 +8518,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) /* We default to disabling the LED code as right now it causes * too many systems to lock up... */ - if (!led) + if (!led_support) priv->config |= CFG_NO_LED; if (associate) @@ -8539,10 +8540,10 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) IPW_DEBUG_INFO("Radio disabled.\n"); } - if (channel != 0) { + if (default_channel != 0) { priv->config |= CFG_STATIC_CHANNEL; - priv->channel = channel; - IPW_DEBUG_INFO("Bind to static channel %d\n", channel); + priv->channel = default_channel; + IPW_DEBUG_INFO("Bind to static channel %d\n", default_channel); /* TODO: Validate that provided channel is in range */ } #ifdef CONFIG_IPW2200_QOS @@ -8550,7 +8551,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) burst_duration_CCK, burst_duration_OFDM); #endif /* CONFIG_IPW2200_QOS */ - switch (mode) { + switch (network_mode) { case 1: priv->ieee->iw_mode = IW_MODE_ADHOC; priv->net_dev->type = ARPHRD_ETHER; @@ -10181,7 +10182,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, #endif struct clx2_queue *q = &txq->q; u8 id, hdr_len, unicast; - u16 remaining_bytes; int fc; if (!(priv->status & STATUS_ASSOCIATED)) @@ -10220,7 +10220,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, tfd->u.data.cmd_id = DINO_CMD_TX; tfd->u.data.len = cpu_to_le16(txb->payload_size); - remaining_bytes = txb->payload_size; if (priv->assoc_request.ieee_mode == IPW_B_MODE) tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK; @@ -11946,13 +11945,13 @@ MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); module_param(auto_create, int, 0444); MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); -module_param(led, int, 0444); +module_param_named(led, led_support, int, 0444); MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)"); module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); -module_param(channel, int, 0444); +module_param_named(channel, default_channel, int, 0444); MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); #ifdef CONFIG_IPW2200_PROMISCUOUS @@ -11978,10 +11977,10 @@ MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value"); #endif /* CONFIG_IPW2200_QOS */ #ifdef CONFIG_IPW2200_MONITOR -module_param(mode, int, 0444); +module_param_named(mode, network_mode, int, 0444); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); #else -module_param(mode, int, 0444); +module_param_named(mode, network_mode, int, 0444); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)"); #endif -- cgit v0.10.2 From ad002395fd230528281083f4be71855ed7e35b04 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Aug 2009 19:51:57 +0200 Subject: cfg80211: fix dangling scan request checking My patch "cfg80211: fix deadlock" broke the code it was supposed to fix, the scan request checking. But it's not trivial to put it back the way it was, since the original patch had a deadlock. Now do it in a completely new way: queue the check off to a work struct, where we can freely lock. But that has some more complications, like needing to wait for it to be done before the wiphy/rdev can be destroyed, so some code is required to handle that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0b146bb..3d874c6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1325,6 +1325,8 @@ struct wireless_dev { struct mutex mtx; + struct work_struct cleanup_work; + /* currently used for IBSS and SME - might be rearranged later */ u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; diff --git a/net/wireless/core.c b/net/wireless/core.c index 69a185b..c150071 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -430,6 +430,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) INIT_WORK(&rdev->conn_work, cfg80211_conn_work); INIT_WORK(&rdev->event_work, cfg80211_event_work); + init_waitqueue_head(&rdev->dev_wait); + /* * Initialize wiphy parameters to IEEE 802.11 MIB default values. * Fragmentation and RTS threshold are disabled by default with the @@ -574,7 +576,23 @@ void wiphy_unregister(struct wiphy *wiphy) /* protect the device list */ mutex_lock(&cfg80211_mutex); + wait_event(rdev->dev_wait, ({ + int __count; + mutex_lock(&rdev->devlist_mtx); + __count = rdev->opencount; + mutex_unlock(&rdev->devlist_mtx); + __count == 0;})); + + mutex_lock(&rdev->devlist_mtx); BUG_ON(!list_empty(&rdev->netdev_list)); + mutex_unlock(&rdev->devlist_mtx); + + /* + * First remove the hardware from everywhere, this makes + * it impossible to find from userspace. + */ + cfg80211_debugfs_rdev_del(rdev); + list_del(&rdev->list); /* * Try to grab rdev->mtx. If a command is still in progress, @@ -582,26 +600,18 @@ void wiphy_unregister(struct wiphy *wiphy) * down the device already. We wait for this command to complete * before unlinking the item from the list. * Note: as codified by the BUG_ON above we cannot get here if - * a virtual interface is still associated. Hence, we can only - * get to lock contention here if userspace issues a command - * that identified the hardware by wiphy index. + * a virtual interface is still present. Hence, we can only get + * to lock contention here if userspace issues a command that + * identified the hardware by wiphy index. */ cfg80211_lock_rdev(rdev); - - if (WARN_ON(rdev->scan_req)) { - rdev->scan_req->aborted = true; - ___cfg80211_scan_done(rdev); - } - + /* nothing */ cfg80211_unlock_rdev(rdev); - cfg80211_debugfs_rdev_del(rdev); - /* If this device got a regulatory hint tell core its * free to listen now to a new shiny device regulatory hint */ reg_device_remove(wiphy); - list_del(&rdev->list); cfg80211_rdev_list_generation++; device_del(&rdev->wiphy.dev); debugfs_remove(rdev->wiphy.debugfsdir); @@ -640,6 +650,31 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) } EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); +static void wdev_cleanup_work(struct work_struct *work) +{ + struct wireless_dev *wdev; + struct cfg80211_registered_device *rdev; + + wdev = container_of(work, struct wireless_dev, cleanup_work); + rdev = wiphy_to_dev(wdev->wiphy); + + cfg80211_lock_rdev(rdev); + + if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { + rdev->scan_req->aborted = true; + ___cfg80211_scan_done(rdev); + } + + cfg80211_unlock_rdev(rdev); + + mutex_lock(&rdev->devlist_mtx); + rdev->opencount--; + mutex_unlock(&rdev->devlist_mtx); + wake_up(&rdev->dev_wait); + + dev_put(wdev->netdev); +} + static int cfg80211_netdev_notifier_call(struct notifier_block * nb, unsigned long state, void *ndev) @@ -663,6 +698,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, * are added with nl80211. */ mutex_init(&wdev->mtx); + INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); INIT_LIST_HEAD(&wdev->event_list); spin_lock_init(&wdev->event_lock); mutex_lock(&rdev->devlist_mtx); @@ -717,8 +753,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, default: break; } + dev_hold(dev); + schedule_work(&wdev->cleanup_work); break; case NETDEV_UP: + /* + * If we have a really quick DOWN/UP succession we may + * have this work still pending ... cancel it and see + * if it was pending, in which case we need to account + * for some of the work it would have done. + */ + if (cancel_work_sync(&wdev->cleanup_work)) { + mutex_lock(&rdev->devlist_mtx); + rdev->opencount--; + mutex_unlock(&rdev->devlist_mtx); + dev_put(dev); + } #ifdef CONFIG_WIRELESS_EXT cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); @@ -734,6 +784,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; } wdev_unlock(wdev); + rdev->opencount++; mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); #endif @@ -756,7 +807,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, sysfs_remove_link(&dev->dev.kobj, "phy80211"); list_del_init(&wdev->list); rdev->devlist_generation++; - mutex_destroy(&wdev->mtx); #ifdef CONFIG_WIRELESS_EXT kfree(wdev->wext.keys); #endif diff --git a/net/wireless/core.h b/net/wireless/core.h index c603f52..f565432 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -50,6 +50,8 @@ struct cfg80211_registered_device { struct mutex devlist_mtx; struct list_head netdev_list; int devlist_generation; + int opencount; /* also protected by devlist_mtx */ + wait_queue_head_t dev_wait; /* BSSes/scanning */ spinlock_t bss_lock; -- cgit v0.10.2 From afa620429ac6a636246f85d97cf205d6533e7fcb Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 18 Aug 2009 19:54:23 +0200 Subject: rt2x00: configure_filter() callback is allowed to sleep The configure_filter() callback function no longer needs to be atomic. Remove the scheduled work structure and call into the driver configure_filter() directly. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 39d7d9b..ad70946 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -826,7 +826,6 @@ struct rt2x00_dev { * due to RTNL locking requirements. */ struct work_struct intf_work; - struct work_struct filter_work; /* * Data queue arrays for RX, TX and Beacon. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9ab70e4..16b560a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -118,14 +118,6 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) rt2x00link_start_tuner(rt2x00dev); } -static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) -{ - struct rt2x00_dev *rt2x00dev = - container_of(work, struct rt2x00_dev, filter_work); - - rt2x00dev->ops->lib->config_filter(rt2x00dev, rt2x00dev->packet_filter); -} - static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -859,7 +851,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) * Initialize configuration work. */ INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); - INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); /* * Allocate queue array. @@ -907,7 +898,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) /* * Stop all work. */ - cancel_work_sync(&rt2x00dev->filter_work); cancel_work_sync(&rt2x00dev->intf_work); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 3011aea..967d3b5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -430,10 +430,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, return; rt2x00dev->packet_filter = *total_flags; - if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) - rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); - else - ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->filter_work); + rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); -- cgit v0.10.2 From d904dc17495581254442b7fd054e267f2605c8ec Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 18 Aug 2009 20:33:12 +0200 Subject: rt2x00: bss_info_changed() callback is allowed to sleep The bss_info_changed() callback function no longer needs to be atomic. Remove the scheduled work structure and call into the driver directly. Additionaly this makes the DRIVER_REQUIRE_SCHEDULED flag redundant so it can be removed. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 09a5894..b04f59b 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1874,7 +1874,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) */ __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); if (!modparam_nohwcrypt) { __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 45e02f1..639dc6c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2634,7 +2634,6 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index ad70946..555a777 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -350,8 +350,6 @@ struct rt2x00_intf { */ unsigned int delayed_flags; #define DELAYED_UPDATE_BEACON 0x00000001 -#define DELAYED_CONFIG_ERP 0x00000002 -#define DELAYED_LED_ASSOC 0x00000004 /* * Software sequence counter, this is only required @@ -614,7 +612,6 @@ enum rt2x00_flags { DRIVER_REQUIRE_FIRMWARE, DRIVER_REQUIRE_BEACON_GUARD, DRIVER_REQUIRE_ATIM_QUEUE, - DRIVER_REQUIRE_SCHEDULED, DRIVER_REQUIRE_DMA, DRIVER_REQUIRE_COPY_IV, DRIVER_REQUIRE_L2PAD, diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 16b560a..3f8c70e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -123,7 +123,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, { struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); - struct ieee80211_bss_conf conf; int delayed_flags; /* @@ -133,7 +132,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, */ spin_lock(&intf->lock); - memcpy(&conf, &vif->bss_conf, sizeof(conf)); delayed_flags = intf->delayed_flags; intf->delayed_flags = 0; @@ -150,12 +148,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, if (delayed_flags & DELAYED_UPDATE_BEACON) rt2x00queue_update_beacon(rt2x00dev, vif, true); - - if (delayed_flags & DELAYED_CONFIG_ERP) - rt2x00lib_config_erp(rt2x00dev, intf, &conf); - - if (delayed_flags & DELAYED_LED_ASSOC) - rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); } static void rt2x00lib_intf_scheduled(struct work_struct *work) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 967d3b5..a91f316 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -636,23 +636,15 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, else rt2x00dev->intf_associated--; - if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) - rt2x00leds_led_assoc(rt2x00dev, - !!rt2x00dev->intf_associated); - else - delayed |= DELAYED_LED_ASSOC; + rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); } /* * When the erp information has changed, we should perform * additional configuration steps. For all other changes we are done. */ - if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { - if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) - rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); - else - delayed |= DELAYED_CONFIG_ERP; - } + if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) + rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); spin_lock(&intf->lock); if (delayed) { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4d94b65..90e1172 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2151,7 +2151,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); -- cgit v0.10.2 From 5791ce18aa660df7d1dafebf6bd89d5aa05bd742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Tue, 18 Aug 2009 22:08:31 +0200 Subject: b43: LP-PHY: Two small spec updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The specs are beginning to support rev3 LP-PHYs - implement one of the changes needed for rev3 support. Also, in the new MIPS driver, the "Japan TX filter" was renamed to "analog TX filter init" - however, calling it "init" is confusing, so name it "set analog filter", with a comment for easier future identification. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 9402383..37ba177 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -609,9 +609,14 @@ static void lpphy_2063_init(struct b43_wldev *dev) b43_radio_write(dev, B2063_PA_SP7, 0); b43_radio_write(dev, B2063_TX_RF_SP6, 0x20); b43_radio_write(dev, B2063_TX_RF_SP9, 0x40); - b43_radio_write(dev, B2063_PA_SP3, 0xa0); - b43_radio_write(dev, B2063_PA_SP4, 0xa0); - b43_radio_write(dev, B2063_PA_SP2, 0x18); + if (dev->phy.rev == 2) { + b43_radio_write(dev, B2063_PA_SP3, 0xa0); + b43_radio_write(dev, B2063_PA_SP4, 0xa0); + b43_radio_write(dev, B2063_PA_SP2, 0x18); + } else { + b43_radio_write(dev, B2063_PA_SP3, 0x20); + b43_radio_write(dev, B2063_PA_SP2, 0x20); + } } struct lpphy_stx_table_entry { @@ -1972,7 +1977,9 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, return err; } -static void lpphy_japan_filter(struct b43_wldev *dev, int channel) + +/* This was previously called lpphy_japan_filter */ +static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel) { struct b43_phy_lp *lpphy = dev->phy.lp; u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter! @@ -2141,7 +2148,7 @@ static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, err = lpphy_b2062_tune(dev, new_channel); if (err) return err; - lpphy_japan_filter(dev, new_channel); + lpphy_set_analog_filter(dev, new_channel); lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); } -- cgit v0.10.2 From eeef41854deae30ea304544f18684df70ae3f87b Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 19 Aug 2009 12:43:47 +0200 Subject: ar9170: refactor configure_filter Thanks to "mac80211: allow configure_filter callback to sleep", we no longer have to defer the work to the workqueue. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 95f8256..ce40724 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -185,10 +185,8 @@ struct ar9170 { bool disable_offload; /* filter settings */ - struct work_struct filter_config_work; - u64 cur_mc_hash, want_mc_hash; - u32 cur_filter, want_filter; - unsigned long filter_changed; + u64 cur_mc_hash; + u32 cur_filter; unsigned int filter_state; bool sniffer_enabled; @@ -261,10 +259,6 @@ struct ar9170_tx_info { #define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) #define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) -#define AR9170_FILTER_CHANGED_MODE BIT(0) -#define AR9170_FILTER_CHANGED_MULTICAST BIT(1) -#define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2) - /* exported interface */ void *ar9170_alloc(size_t priv_size); int ar9170_register(struct ar9170 *ar, struct device *pdev); @@ -278,8 +272,8 @@ int ar9170_nag_limiter(struct ar9170 *ar); int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); int ar9170_init_mac(struct ar9170 *ar); int ar9170_set_qos(struct ar9170 *ar); -int ar9170_update_multicast(struct ar9170 *ar); -int ar9170_update_frame_filter(struct ar9170 *ar); +int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast); +int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter); int ar9170_set_operating_mode(struct ar9170 *ar); int ar9170_set_beacon_timers(struct ar9170 *ar); int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index d9f1f46..6004936 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -238,39 +238,31 @@ static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) return ar9170_regwrite_result(); } -int ar9170_update_multicast(struct ar9170 *ar) +int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash) { int err; ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, - ar->want_mc_hash >> 32); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, - ar->want_mc_hash); - + ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32); + ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash); ar9170_regwrite_finish(); err = ar9170_regwrite_result(); - if (err) return err; - ar->cur_mc_hash = ar->want_mc_hash; - + ar->cur_mc_hash = mc_hash; return 0; } -int ar9170_update_frame_filter(struct ar9170 *ar) +int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter) { int err; - err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, - ar->want_filter); - + err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter); if (err) return err; - ar->cur_filter = ar->want_filter; - + ar->cur_filter = filter; return 0; } diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index d30f33d..658b323 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1232,8 +1232,6 @@ static int ar9170_op_start(struct ieee80211_hw *hw) mutex_lock(&ar->mutex); - ar->filter_changed = 0; - /* reinitialize queues statistics */ memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); for (i = 0; i < __AR9170_NUM_TXQ; i++) @@ -1296,7 +1294,6 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) #ifdef CONFIG_AR9170_LEDS cancel_delayed_work_sync(&ar->led_work); #endif - cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); mutex_lock(&ar->mutex); @@ -1973,8 +1970,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw, } ar->cur_filter = 0; - ar->want_filter = AR9170_MAC_REG_FTF_DEFAULTS; - err = ar9170_update_frame_filter(ar); + err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS); if (err) goto unlock; @@ -1992,8 +1988,7 @@ static void ar9170_op_remove_interface(struct ieee80211_hw *hw, mutex_lock(&ar->mutex); ar->vif = NULL; - ar->want_filter = 0; - ar9170_update_frame_filter(ar); + ar9170_update_frame_filter(ar, 0); ar9170_set_beacon_timers(ar); dev_kfree_skb(ar->beacon); ar->beacon = NULL; @@ -2065,41 +2060,6 @@ out: return err; } -static void ar9170_set_filters(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, - filter_config_work); - int err; - - if (unlikely(!IS_STARTED(ar))) - return ; - - mutex_lock(&ar->mutex); - if (test_and_clear_bit(AR9170_FILTER_CHANGED_MODE, - &ar->filter_changed)) { - err = ar9170_set_operating_mode(ar); - if (err) - goto unlock; - } - - if (test_and_clear_bit(AR9170_FILTER_CHANGED_MULTICAST, - &ar->filter_changed)) { - err = ar9170_update_multicast(ar); - if (err) - goto unlock; - } - - if (test_and_clear_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, - &ar->filter_changed)) { - err = ar9170_update_frame_filter(ar); - if (err) - goto unlock; - } - -unlock: - mutex_unlock(&ar->mutex); -} - static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mclist) { @@ -2126,6 +2086,11 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, { struct ar9170 *ar = hw->priv; + if (unlikely(!IS_ACCEPTING_CMD(ar))) + return ; + + mutex_lock(&ar->mutex); + /* mask supported flags */ *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL; @@ -2136,12 +2101,10 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, */ if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) - multicast = ~0ULL; + multicast = ~0ULL; - if (multicast != ar->want_mc_hash) { - ar->want_mc_hash = multicast; - set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed); - } + if (multicast != ar->cur_mc_hash) + ar9170_update_multicast(ar, multicast); if (changed_flags & FIF_CONTROL) { u32 filter = AR9170_MAC_REG_FTF_PSPOLL | @@ -2152,24 +2115,22 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, AR9170_MAC_REG_FTF_CFE_ACK; if (*new_flags & FIF_CONTROL) - ar->want_filter = ar->cur_filter | filter; + filter |= ar->cur_filter; else - ar->want_filter = ar->cur_filter & ~filter; + filter &= (~ar->cur_filter); - set_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, - &ar->filter_changed); + ar9170_update_frame_filter(ar, filter); } if (changed_flags & FIF_PROMISC_IN_BSS) { ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; - set_bit(AR9170_FILTER_CHANGED_MODE, - &ar->filter_changed); + ar9170_set_operating_mode(ar); } - if (likely(IS_STARTED(ar))) - ieee80211_queue_work(ar->hw, &ar->filter_config_work); + mutex_unlock(&ar->mutex); } + static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -2423,9 +2384,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, default: break; } - - if (IS_STARTED(ar) && ar->filter_changed) - ieee80211_queue_work(ar->hw, &ar->filter_config_work); } static int ar9170_get_stats(struct ieee80211_hw *hw, @@ -2596,7 +2554,6 @@ void *ar9170_alloc(size_t priv_size) skb_queue_head_init(&ar->tx_pending[i]); } ar9170_rx_reset_rx_mpdu(ar); - INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->beacon_work, ar9170_new_beacon); INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); INIT_LIST_HEAD(&ar->tx_ampdu_list); -- cgit v0.10.2 From 415ad1efae1d5fe00d739e612d262eabda90f5e8 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 19 Aug 2009 00:43:31 +0100 Subject: cfg80211: fix leaks of wdev->conn->ie This only occurs in the following error situations: - driver calls connect_result with failure - error scheduling authentication on connect - error initiating scan (to get BSSID and channel) on connect - userspace calls disconnect while in the SCANNING or SCAN_AGAIN states Signed-off-by: David Kilroy Reviewed-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 6fb6a70..9ddc00e 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -395,6 +395,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (status != WLAN_STATUS_SUCCESS) { wdev->sme_state = CFG80211_SME_IDLE; + if (wdev->conn) + kfree(wdev->conn->ie); kfree(wdev->conn); wdev->conn = NULL; kfree(wdev->connect_keys); @@ -779,6 +781,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, } } if (err) { + kfree(wdev->conn->ie); kfree(wdev->conn); wdev->conn = NULL; wdev->sme_state = CFG80211_SME_IDLE; @@ -848,6 +851,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, (wdev->conn->state == CFG80211_CONN_SCANNING || wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { wdev->sme_state = CFG80211_SME_IDLE; + kfree(wdev->conn->ie); kfree(wdev->conn); wdev->conn = NULL; wdev->ssid_len = 0; -- cgit v0.10.2 From 30fab9e0aecf15ca79bb194bb603203f5e1fde66 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 19 Aug 2009 00:44:43 +0100 Subject: orinoco: remove spare whitespace Signed-off-by: David Kilroy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 3e56f76..7698fdd 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -1291,7 +1291,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, if (orinoco_lock(priv, &flags) != 0) return -EBUSY; - priv->ibss_port = val ; + priv->ibss_port = val; /* Actually update the mode we are using */ set_port_type(priv); -- cgit v0.10.2 From 16a832e785820aa199641c77b2d6f4a443d2ec46 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 19 Aug 2009 16:08:22 +0800 Subject: cfg80211: allow cfg80211_connect_result with bssid == NULL In case of connection failure, the bssid info is not a must have. Signed-off-by: Zhu Yi Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index c150071..154e1e2 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -309,7 +310,8 @@ static void cfg80211_process_events(struct wireless_dev *wdev) switch (ev->type) { case EVENT_CONNECT_RESULT: __cfg80211_connect_result( - wdev->netdev, ev->cr.bssid, + wdev->netdev, is_zero_ether_addr(ev->cr.bssid) ? + NULL : ev->cr.bssid, ev->cr.req_ie, ev->cr.req_ie_len, ev->cr.resp_ie, ev->cr.resp_ie_len, ev->cr.status, diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 9ddc00e..4a8289f9 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -450,7 +450,8 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, return; ev->type = EVENT_CONNECT_RESULT; - memcpy(ev->cr.bssid, bssid, ETH_ALEN); + if (bssid) + memcpy(ev->cr.bssid, bssid, ETH_ALEN); ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev); ev->cr.req_ie_len = req_ie_len; memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len); -- cgit v0.10.2 From 5904d2067680e9bb73a4816fa6b9eec49355c9c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Tue, 18 Aug 2009 19:18:13 +0200 Subject: b43: LP-PHY: Implement spec updates and remove resolved FIXMEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Larry has started re-checking all current routines against a new version of the Broadcom MIPS driver. This patch implements the first round of changes he documented on the specs wiki. Also remove a few FIXMEs regarding missing initial values for variables with dynamic initial values where reading the values has been implemented. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 37ba177..2d3a5d8 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -724,9 +724,39 @@ static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult) b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8); } -static void lpphy_disable_crs(struct b43_wldev *dev) +static void lpphy_set_deaf(struct b43_wldev *dev, bool user) { + struct b43_phy_lp *lpphy = dev->phy.lp; + + if (user) + lpphy->crs_usr_disable = 1; + else + lpphy->crs_sys_disable = 1; b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80); +} + +static void lpphy_clear_deaf(struct b43_wldev *dev, bool user) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + + if (user) + lpphy->crs_usr_disable = 0; + else + lpphy->crs_sys_disable = 0; + + if (!lpphy->crs_usr_disable && !lpphy->crs_sys_disable) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, + 0xFF1F, 0x60); + else + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, + 0xFF1F, 0x20); + } +} + +static void lpphy_disable_crs(struct b43_wldev *dev, bool user) +{ + lpphy_set_deaf(dev, user); b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB); @@ -754,12 +784,9 @@ static void lpphy_disable_crs(struct b43_wldev *dev) b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF); } -static void lpphy_restore_crs(struct b43_wldev *dev) +static void lpphy_restore_crs(struct b43_wldev *dev, bool user) { - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x60); - else - b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x20); + lpphy_clear_deaf(dev, user); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00); } @@ -805,10 +832,11 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev, b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xF800, rf_gain); } else { - pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F00; + pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x1FC0; + pa_gain <<= 2; b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, (gains.pga << 8) | gains.gm); - b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, + b43_phy_maskset(dev, B43_PHY_OFDM(0xFB), 0x8000, gains.pad | pa_gain); b43_phy_write(dev, B43_PHY_OFDM(0xFC), (gains.pga << 8) | gains.gm); @@ -822,7 +850,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev, b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7); b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14); } - b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 6); + b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF, 1 << 6); } static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain) @@ -862,33 +890,33 @@ static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain) } } -static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) +static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) { b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF); if (dev->phy.rev >= 2) { b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF); - if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) - return; - b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF); - b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFF7); + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF); + b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7); + } } else { b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF); } } -static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) +static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) { b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40); if (dev->phy.rev >= 2) { b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100); - if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) - return; - b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400); - b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x8); + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400); + b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8); + } } else { b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200); } @@ -1007,26 +1035,22 @@ static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) { u32 quotient, remainder, rbit, roundup, tmp; - if (divisor == 0) { - quotient = 0; - remainder = 0; - } else { - quotient = dividend / divisor; - remainder = dividend % divisor; - } + if (divisor == 0) + return 0; + + quotient = dividend / divisor; + remainder = dividend % divisor; rbit = divisor & 0x1; roundup = (divisor >> 1) + rbit; - precision--; - while (precision != 0xFF) { + while (precision != 0) { tmp = remainder - roundup; quotient <<= 1; - remainder <<= 1; - if (remainder >= roundup) { + if (remainder >= roundup) remainder = (tmp << 1) + rbit; - quotient--; - } + else + remainder <<= 1; precision--; } @@ -1128,11 +1152,11 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) struct b43_phy_lp *lpphy = dev->phy.lp; struct lpphy_iq_est iq_est; struct lpphy_tx_gains tx_gains; - static const u32 ideal_pwr_table[22] = { + static const u32 ideal_pwr_table[21] = { 0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64, 0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35, 0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088, - 0x0004c, 0x0002c, 0x0001a, 0xc0006, + 0x0004c, 0x0002c, 0x0001a, }; bool old_txg_ovr; u8 old_bbmult; @@ -1150,7 +1174,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) "RC calib: Failed to switch to channel 7, error = %d", err); } - old_txg_ovr = (b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) >> 6) & 1; + old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40); old_bbmult = lpphy_get_bb_mult(dev); if (old_txg_ovr) tx_gains = lpphy_get_tx_gains(dev); @@ -1165,7 +1189,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) old_txpctl = lpphy->txpctl_mode; lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF); - lpphy_disable_crs(dev); + lpphy_disable_crs(dev, true); loopback = lpphy_loopback(dev); if (loopback == -1) goto finish; @@ -1198,7 +1222,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) lpphy_stop_ddfs(dev); finish: - lpphy_restore_crs(dev); + lpphy_restore_crs(dev, true); b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval); b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr); b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval); diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 99cb038..e158d1f 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -825,11 +825,11 @@ struct b43_phy_lp { enum b43_lpphy_txpctl_mode txpctl_mode; /* Transmit isolation medium band */ - u8 tx_isolation_med_band; /* FIXME initial value? */ + u8 tx_isolation_med_band; /* Transmit isolation low band */ - u8 tx_isolation_low_band; /* FIXME initial value? */ + u8 tx_isolation_low_band; /* Transmit isolation high band */ - u8 tx_isolation_hi_band; /* FIXME initial value? */ + u8 tx_isolation_hi_band; /* Max transmit power medium band */ u16 max_tx_pwr_med_band; @@ -848,7 +848,7 @@ struct b43_phy_lp { s16 txpa[3], txpal[3], txpah[3]; /* Receive power offset */ - u8 rx_pwr_offset; /* FIXME initial value? */ + u8 rx_pwr_offset; /* TSSI transmit count */ u16 tssi_tx_count; @@ -864,16 +864,16 @@ struct b43_phy_lp { s8 tx_pwr_idx_over; /* FIXME initial value? */ /* RSSI vf */ - u8 rssi_vf; /* FIXME initial value? */ + u8 rssi_vf; /* RSSI vc */ - u8 rssi_vc; /* FIXME initial value? */ + u8 rssi_vc; /* RSSI gs */ - u8 rssi_gs; /* FIXME initial value? */ + u8 rssi_gs; /* RC cap */ u8 rc_cap; /* FIXME initial value? */ /* BX arch */ - u8 bx_arch; /* FIXME initial value? */ + u8 bx_arch; /* Full calibration channel */ u8 full_calib_chan; /* FIXME initial value? */ @@ -885,6 +885,8 @@ struct b43_phy_lp { /* Used for "Save/Restore Dig Filt State" */ u16 dig_flt_state[9]; + bool crs_usr_disable, crs_sys_disable; + unsigned int pdiv; }; diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index 2721310..60d472f 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -2367,7 +2367,17 @@ static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, int offset, tmp = data.pad << 16; tmp |= data.pga << 8; tmp |= data.gm; - tmp |= 0x7f000000; + if (dev->phy.rev >= 3) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + tmp |= 0x10 << 24; + else + tmp |= 0x70 << 24; + } else { + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + tmp |= 0x14 << 24; + else + tmp |= 0x7F << 24; + } b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + offset), tmp); tmp = data.bb_mult << 20; tmp |= data.dac << 28; -- cgit v0.10.2 From 11ba964d4f936609a04e8b9f2051f6027ef761ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Aug 2009 19:45:50 +0200 Subject: mac80211: fix register_hw error path "cfg80211: fix alignment problem in scan request" introduced a bug into the error path, because now we allocate the entire scan request and not just the channel list (the channel list is allocated together with the scan request) -- on errors we thus also need to free the entire scan request. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f80efd7..dd3b081 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -930,7 +930,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) fail_workqueue: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: - kfree(local->int_scan_req->channels); + kfree(local->int_scan_req); return result; } EXPORT_SYMBOL(ieee80211_register_hw); -- cgit v0.10.2 From 035d0243ebbdbd5f8f07d6ce378c9a9b36415bc9 Mon Sep 17 00:00:00 2001 From: gregor kowski Date: Wed, 19 Aug 2009 22:35:45 +0200 Subject: b43: add hardware tkip This add hardware tkip for b43. Signed-off-by: Gregor Kowski Acked-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 41a0e9c..289aaf6 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1188,7 +1188,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]); cookie = generate_cookie(ring, slot); err = b43_generate_txhdr(ring->dev, header, - skb->data, skb->len, info, cookie); + skb, info, cookie); if (unlikely(err)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 78ddbc7..f5bdf1c 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -80,6 +80,10 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +static int modparam_hwtkip; +module_param_named(hwtkip, modparam_hwtkip, int, 0444); +MODULE_PARM_DESC(hwtkip, "Enable hardware tkip."); + static int modparam_qos = 1; module_param_named(qos, modparam_qos, int, 0444); MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); @@ -834,6 +838,85 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) (index * 2) + 1, addrtmp[1]); } +/* The ucode will use phase1 key with TEK key to decrypt rx packets. + * When a packet is received, the iv32 is checked. + * - if it doesn't the packet is returned without modification (and software + * decryption can be done). That's what happen when iv16 wrap. + * - if it does, the rc4 key is computed, and decryption is tried. + * Either it will success and B43_RX_MAC_DEC is returned, + * either it fails and B43_RX_MAC_DEC|B43_RX_MAC_DECERR is returned + * and the packet is not usable (it got modified by the ucode). + * So in order to never have B43_RX_MAC_DECERR, we should provide + * a iv32 and phase1key that match. Because we drop packets in case of + * B43_RX_MAC_DECERR, if we have a correct iv32 but a wrong phase1key, all + * packets will be lost without higher layer knowing (ie no resync possible + * until next wrap). + * + * NOTE : this should support 50 key like RCMTA because + * (B43_SHM_SH_KEYIDXBLOCK - B43_SHM_SH_TKIPTSCTTAK)/14 = 50 + */ +static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32, + u16 *phase1key) +{ + unsigned int i; + u32 offset; + u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2; + + if (!modparam_hwtkip) + return; + + if (b43_new_kidx_api(dev)) + pairwise_keys_start = B43_NR_GROUP_KEYS; + + B43_WARN_ON(index < pairwise_keys_start); + /* We have four default TX keys and possibly four default RX keys. + * Physical mac 0 is mapped to physical key 4 or 8, depending + * on the firmware version. + * So we must adjust the index here. + */ + index -= pairwise_keys_start; + B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS); + + if (b43_debug(dev, B43_DBG_KEYS)) { + b43dbg(dev->wl, "rx_tkip_phase1_write : idx 0x%x, iv32 0x%x\n", + index, iv32); + } + /* Write the key to the RX tkip shared mem */ + offset = B43_SHM_SH_TKIPTSCTTAK + index * (10 + 4); + for (i = 0; i < 10; i += 2) { + b43_shm_write16(dev, B43_SHM_SHARED, offset + i, + phase1key ? phase1key[i / 2] : 0); + } + b43_shm_write16(dev, B43_SHM_SHARED, offset + i, iv32); + b43_shm_write16(dev, B43_SHM_SHARED, offset + i + 2, iv32 >> 16); +} + +static void b43_op_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_key_conf *keyconf, const u8 *addr, + u32 iv32, u16 *phase1key) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + int index = keyconf->hw_key_idx; + + if (B43_WARN_ON(!modparam_hwtkip)) + return; + + mutex_lock(&wl->mutex); + + dev = wl->current_dev; + if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) + goto out_unlock; + + keymac_write(dev, index, NULL); /* First zero out mac to avoid race */ + + rx_tkip_phase1_write(dev, index, iv32, phase1key); + keymac_write(dev, index, addr); + +out_unlock: + mutex_unlock(&wl->mutex); +} + static void do_key_write(struct b43_wldev *dev, u8 index, u8 algorithm, const u8 *key, size_t key_len, const u8 *mac_addr) @@ -849,6 +932,19 @@ static void do_key_write(struct b43_wldev *dev, if (index >= pairwise_keys_start) keymac_write(dev, index, NULL); /* First zero out mac. */ + if (algorithm == B43_SEC_ALGO_TKIP) { + /* + * We should provide an initial iv32, phase1key pair. + * We could start with iv32=0 and compute the corresponding + * phase1key, but this means calling ieee80211_get_tkip_key + * with a fake skb (or export other tkip function). + * Because we are lazy we hope iv32 won't start with + * 0xffffffff and let's b43_op_update_tkip_key provide a + * correct pair. + */ + rx_tkip_phase1_write(dev, index, 0xffffffff, (u16*)buf); + } else if (index >= pairwise_keys_start) /* clear it */ + rx_tkip_phase1_write(dev, index, 0, NULL); if (key) memcpy(buf, key, key_len); key_write(dev, index, algorithm, buf); @@ -867,6 +963,15 @@ static int b43_key_write(struct b43_wldev *dev, int i; int pairwise_keys_start; + /* For ALG_TKIP the key is encoded as a 256-bit (32 byte) data block: + * - Temporal Encryption Key (128 bits) + * - Temporal Authenticator Tx MIC Key (64 bits) + * - Temporal Authenticator Rx MIC Key (64 bits) + * + * Hardware only store TEK + */ + if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32) + key_len = 16; if (key_len > B43_SEC_KEYSIZE) return -EINVAL; for (i = 0; i < ARRAY_SIZE(dev->key); i++) { @@ -973,6 +1078,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev) printk(" Algo: %04X/%02X", algo, key->algorithm); if (index >= pairwise_keys_start) { + if (key->algorithm == B43_SEC_ALGO_TKIP) { + printk(" TKIP: "); + offset = B43_SHM_SH_TKIPTSCTTAK + (index - 4) * (10 + 4); + for (i = 0; i < 14; i += 2) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i); + printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF)); + } + } rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, ((index - pairwise_keys_start) * 2) + 0); rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, @@ -3620,8 +3733,10 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (cmd) { case SET_KEY: - if (algorithm == B43_SEC_ALGO_TKIP) { - /* FIXME: No TKIP hardware encryption for now. */ + if (algorithm == B43_SEC_ALGO_TKIP && + (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) || + !modparam_hwtkip)) { + /* We support only pairwise key */ err = -EOPNOTSUPP; goto out_unlock; } @@ -3651,6 +3766,8 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, b43_hf_read(dev) & ~B43_HF_USEDEFKEYS); } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + if (algorithm == B43_SEC_ALGO_TKIP) + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; break; case DISABLE_KEY: { err = b43_key_clear(dev, key->hw_key_idx); @@ -4378,6 +4495,7 @@ static const struct ieee80211_ops b43_hw_ops = { .bss_info_changed = b43_op_bss_info_changed, .configure_filter = b43_op_configure_filter, .set_key = b43_op_set_key, + .update_tkip_key = b43_op_update_tkip_key, .get_stats = b43_op_get_stats, .get_tx_stats = b43_op_get_tx_stats, .get_tsf = b43_op_get_tsf, diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 73c047d..3fd653c 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -461,8 +461,8 @@ static int pio_tx_frame(struct b43_pio_txqueue *q, cookie = generate_cookie(q, pack); hdrlen = b43_txhdr_size(q->dev); - err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, - skb->len, info, cookie); + err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb, + info, cookie); if (err) return err; diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index be1c53e..e7075d2 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -180,11 +180,12 @@ static u8 b43_calc_fallback_rate(u8 bitrate) /* Generate a TX data header. */ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, + struct sk_buff *skb_frag, struct ieee80211_tx_info *info, u16 cookie) { + const unsigned char *fragment_data = skb_frag->data; + unsigned int fragment_len = skb_frag->len; struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = @@ -258,9 +259,26 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & B43_TXH_MAC_KEYALG; wlhdr_len = ieee80211_hdrlen(fctl); - iv_len = min((size_t) info->control.hw_key->iv_len, - ARRAY_SIZE(txhdr->iv)); - memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); + if (key->algorithm == B43_SEC_ALGO_TKIP) { + u16 phase1key[5]; + int i; + /* we give the phase1key and iv16 here, the key is stored in + * shm. With that the hardware can do phase 2 and encryption. + */ + ieee80211_get_tkip_key(info->control.hw_key, skb_frag, + IEEE80211_TKIP_P1_KEY, (u8*)phase1key); + /* phase1key is in host endian */ + for (i = 0; i < 5; i++) + phase1key[i] = cpu_to_le16(phase1key[i]); + + memcpy(txhdr->iv, phase1key, 10); + /* iv16 */ + memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3); + } else { + iv_len = min((size_t) info->control.hw_key->iv_len, + ARRAY_SIZE(txhdr->iv)); + memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); + } } if (b43_is_old_txhdr_format(dev)) { b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 4fb2a19..3530de8 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -176,8 +176,7 @@ size_t b43_txhdr_size(struct b43_wldev *dev) int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, + struct sk_buff *skb_frag, struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */ -- cgit v0.10.2 From ff36041652fcb9f5c17bdbeb081414f69521f1af Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 20 Aug 2009 13:41:14 +0530 Subject: ath9k: Fix bug in retrieving average beacon rssi Currently the beacon rssi that LPF gives is divided and rounded up by ATH_RSSI_EP_MULTIPLIER twice. This will leave the incorrect rssi in ANI. Having correct rssi in ANI fixes the connection stability at < 30dB rssi range. This patch removes the unncessary computation of average rssi over already valid average rssi. Also removes the redundant macros to find average rssi. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 1199245..6273fd0 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -18,15 +18,10 @@ #define ANI_H #define HAL_PROCESS_ANI 0x00000001 -#define ATH9K_RSSI_EP_MULTIPLIER (1<<7) #define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI)) -#define HAL_EP_RND(x, mul) \ - ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) -#define BEACON_RSSI(ahp) \ - HAL_EP_RND(ahp->stats.ast_nodestats.ns_avgbrssi, \ - ATH9K_RSSI_EP_MULTIPLIER) +#define BEACON_RSSI(ahp) (ahp->stats.ast_nodestats.ns_avgbrssi) #define ATH9K_ANI_OFDM_TRIG_HIGH 500 #define ATH9K_ANI_OFDM_TRIG_LOW 200 -- cgit v0.10.2 From 22e66a4c15b063aee5d03991c4b9629a3b0c4556 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 19 Aug 2009 16:23:40 +0530 Subject: ath9k: Nuke struct ath9k_node_stats Other than ns_avgbrssi (Average beacon rssi) no data of ath9k_node_stats is being used anywhere. Nuke this structure and move its only useful member to ar5416Anistate. Also cleanup this redundant data in ath_softc. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index f264097..a7cbb07 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -538,7 +538,6 @@ void ath9k_ani_reset(struct ath_hw *ah) } void ath9k_hw_ani_monitor(struct ath_hw *ah, - const struct ath9k_node_stats *stats, struct ath9k_channel *chan) { struct ar5416AniState *aniState; @@ -550,7 +549,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, return; aniState = ah->curani; - ah->stats.ast_nodestats = *stats; listenTime = ath9k_hw_ani_get_listen_time(ah); if (listenTime < 0) { @@ -693,8 +691,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, * any of the MIB counters overflow/trigger so don't assume we're * here because a PHY error counter triggered. */ -void ath9k_hw_procmibevent(struct ath_hw *ah, - const struct ath9k_node_stats *stats) +void ath9k_hw_procmibevent(struct ath_hw *ah) { u32 phyCnt1, phyCnt2; @@ -706,7 +703,6 @@ void ath9k_hw_procmibevent(struct ath_hw *ah, /* Clear the mib counters and save them in the stats */ ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - ah->stats.ast_nodestats = *stats; if (!DO_ANI(ah)) return; diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 6273fd0..4e1ab94 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -21,7 +21,7 @@ #define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI)) -#define BEACON_RSSI(ahp) (ahp->stats.ast_nodestats.ns_avgbrssi) +#define BEACON_RSSI(ahp) (ahp->stats.avgbrssi) #define ATH9K_ANI_OFDM_TRIG_HIGH 500 #define ATH9K_ANI_OFDM_TRIG_LOW 200 @@ -60,13 +60,6 @@ struct ath9k_mib_stats { u32 beacons; }; -struct ath9k_node_stats { - u32 ns_avgbrssi; - u32 ns_avgrssi; - u32 ns_avgtxrssi; - u32 ns_avgtxrate; -}; - struct ar5416AniState { struct ath9k_channel *c; u8 noiseImmunityLevel; @@ -110,21 +103,19 @@ struct ar5416Stats { u32 ast_ani_reset; u32 ast_ani_lzero; u32 ast_ani_lneg; + u32 avgbrssi; struct ath9k_mib_stats ast_mibstats; - struct ath9k_node_stats ast_nodestats; }; #define ah_mibStats stats.ast_mibstats void ath9k_ani_reset(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, - const struct ath9k_node_stats *stats, struct ath9k_channel *chan); void ath9k_enable_mib_counters(struct ath_hw *ah); void ath9k_hw_disable_mib_counters(struct ath_hw *ah); u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, u32 *rxf_pcnt, u32 *txf_pcnt); -void ath9k_hw_procmibevent(struct ath_hw *ah, - const struct ath9k_node_stats *stats); +void ath9k_hw_procmibevent(struct ath_hw *ah); void ath9k_hw_ani_setup(struct ath_hw *ah); void ath9k_hw_ani_init(struct ath_hw *ah); void ath9k_hw_ani_disable(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0e444a6..7705da1 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -603,7 +603,6 @@ struct ath_softc { int beacon_interval; struct ath_ani ani; - struct ath9k_node_stats nodestats; #ifdef CONFIG_ATH9K_DEBUG struct ath9k_debug debug; #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index de19711..9b9b4e8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -384,7 +384,7 @@ static void ath_ani_calibrate(unsigned long data) if (longcal || shortcal || aniflag) { /* Call ANI routine if necessary */ if (aniflag) - ath9k_hw_ani_monitor(ah, &sc->nodestats, ah->curchan); + ath9k_hw_ani_monitor(ah, ah->curchan); /* Perform calibration if necessary */ if (longcal || shortcal) { @@ -589,7 +589,7 @@ irqreturn_t ath_isr(int irq, void *dev) * it will clear whatever condition caused * the interrupt. */ - ath9k_hw_procmibevent(ah, &sc->nodestats); + ath9k_hw_procmibevent(ah); ath9k_hw_set_interrupts(ah, sc->imask); } @@ -940,10 +940,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_beacon_config(sc, vif); /* Reset rssi stats */ - sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; ath_start_ani(sc); } else { diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 61dbdd2..7b62c22 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -222,7 +222,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, /* Update Beacon RSSI, this is used by ANI. */ if (ieee80211_is_beacon(fc)) - sc->nodestats.ns_avgbrssi = ds->ds_rxstat.rs_rssi; + sc->sc_ah->stats.avgbrssi = ds->ds_rxstat.rs_rssi; rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); rx_status->band = hw->conf.channel->band; -- cgit v0.10.2 From c23b5a699471ea2ef9d146eae80e64836cfbf001 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 13:49:55 +0200 Subject: mwl8k: remove various unused struct members and defines Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index c32e93c..91b7062 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -58,7 +58,6 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); #define MWL8K_HIU_H2A_INTERRUPT_STATUS_MASK 0x00000c28 #define MWL8K_H2A_INT_DUMMY (1 << 20) #define MWL8K_H2A_INT_RESET (1 << 15) -#define MWL8K_H2A_INT_PS (1 << 2) #define MWL8K_H2A_INT_DOORBELL (1 << 1) #define MWL8K_H2A_INT_PPA_READY (1 << 0) @@ -161,10 +160,8 @@ struct mwl8k_priv { /* lock held over TX and TX reap */ spinlock_t tx_lock; - u32 int_mask; struct ieee80211_vif *vif; - struct list_head vif_list; struct ieee80211_channel *current_channel; @@ -173,10 +170,8 @@ struct mwl8k_priv { dma_addr_t cookie_dma; u16 num_mcaddrs; - u16 region_code; u8 hw_rev; __le32 fw_rev; - u32 wep_enabled; /* * Running count of TX packets in flight, to avoid @@ -226,8 +221,6 @@ struct mwl8k_priv { /* Per interface specific private data */ struct mwl8k_vif { - struct list_head node; - /* backpointer to parent config block */ struct mwl8k_priv *priv; @@ -247,18 +240,11 @@ struct mwl8k_vif { /* number of supported legacy rates */ u8 legacy_nrates; - /* Number of supported MCS rates. Work in progress */ - u8 mcs_nrates; - /* Index into station database.Returned by update_sta_db call */ u8 peer_id; /* Non AMPDU sequence number assigned by driver */ u16 seqno; - - /* Note:There is no channel info, - * refer to the master channel info in priv - */ }; #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) @@ -681,11 +667,9 @@ struct ewc_ht_info { /* Peer Entry flags - used to define the type of the peer node */ #define MWL8K_PEER_TYPE_ACCESSPOINT 2 -#define MWL8K_PEER_TYPE_ADHOC_STATION 4 #define MWL8K_IEEE_LEGACY_DATA_RATES 12 #define MWL8K_MCS_BITMAP_SIZE 16 -#define pad_size 16 struct peer_capability_info { /* Peer type - AP vs. STA. */ @@ -707,7 +691,7 @@ struct peer_capability_info { /* HT rate table. Intersection of our rates and peer rates. */ __u8 ht_rates[MWL8K_MCS_BITMAP_SIZE]; - __u8 pad[pad_size]; + __u8 pad[16]; /* If set, interoperability mode, no proprietary extensions. */ __u8 interop; @@ -717,15 +701,6 @@ struct peer_capability_info { } __attribute__((packed)); /* Inline functions to manipulate QoS field in data descriptor. */ -static inline u16 mwl8k_qos_setbit_tid(u16 qos, u8 tid) -{ - u16 val_mask = 0x000f; - u16 qos_mask = ~val_mask; - - /* TID bits 0-3 */ - return (qos & qos_mask) | (tid & val_mask); -} - static inline u16 mwl8k_qos_setbit_eosp(u16 qos) { u16 val_mask = 1 << 4; @@ -826,9 +801,7 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) /* * Packet reception. */ -#define MWL8K_RX_CTRL_KEY_INDEX_MASK 0x30 #define MWL8K_RX_CTRL_OWNED_BY_HOST 0x02 -#define MWL8K_RX_CTRL_AMPDU 0x01 struct mwl8k_rx_desc { __le16 pkt_len; @@ -1073,8 +1046,6 @@ enum { /* Transmit packet ACK policy */ #define MWL8K_TXD_ACK_POLICY_NORMAL 0 -#define MWL8K_TXD_ACK_POLICY_NONE 1 -#define MWL8K_TXD_ACK_POLICY_NO_EXPLICIT 2 #define MWL8K_TXD_ACK_POLICY_BLOCKACK 3 #define GET_TXQ(_ac) (\ @@ -1083,20 +1054,11 @@ enum { ((_ac) == WME_AC_BK) ? MWL8K_WME_AC_BK : \ MWL8K_WME_AC_BE) -#define MWL8K_TXD_STATUS_IDLE 0x00000000 -#define MWL8K_TXD_STATUS_USED 0x00000001 #define MWL8K_TXD_STATUS_OK 0x00000001 #define MWL8K_TXD_STATUS_OK_RETRY 0x00000002 #define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004 #define MWL8K_TXD_STATUS_MULTICAST_TX 0x00000008 -#define MWL8K_TXD_STATUS_BROADCAST_TX 0x00000010 -#define MWL8K_TXD_STATUS_FAILED_LINK_ERROR 0x00000020 -#define MWL8K_TXD_STATUS_FAILED_EXCEED_LIMIT 0x00000040 -#define MWL8K_TXD_STATUS_FAILED_AGING 0x00000080 -#define MWL8K_TXD_STATUS_HOST_CMD 0x40000000 #define MWL8K_TXD_STATUS_FW_OWNED 0x80000000 -#define MWL8K_TXD_SOFTSTALE 0x80 -#define MWL8K_TXD_SOFTSTALE_MGMT_RETRY 0x01 struct mwl8k_tx_desc { __le32 status; @@ -1279,12 +1241,10 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) return 0; } -#define MWL8K_TXD_OK (MWL8K_TXD_STATUS_OK | \ - MWL8K_TXD_STATUS_OK_RETRY | \ - MWL8K_TXD_STATUS_OK_MORE_RETRY) -#define MWL8K_TXD_SUCCESS(stat) ((stat) & MWL8K_TXD_OK) -#define MWL8K_TXD_FAIL_RETRY(stat) \ - ((stat) & (MWL8K_TXD_STATUS_FAILED_EXCEED_LIMIT)) +#define MWL8K_TXD_SUCCESS(status) \ + ((status) & (MWL8K_TXD_STATUS_OK | \ + MWL8K_TXD_STATUS_OK_RETRY | \ + MWL8K_TXD_STATUS_OK_MORE_RETRY)) static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) { @@ -1671,7 +1631,6 @@ static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; - priv->region_code = le16_to_cpu(cmd->region_code); } kfree(cmd); @@ -2150,7 +2109,6 @@ struct mwl8k_cmd_set_edca_params { __u8 txq; } __attribute__((packed)); -#define MWL8K_GET_EDCA_ALL 0 #define MWL8K_SET_EDCA_CW 0x01 #define MWL8K_SET_EDCA_TXOP 0x02 #define MWL8K_SET_EDCA_AIFS 0x04 @@ -2323,18 +2281,12 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, /* * CMD_SET_AID. */ -#define IEEE80211_OPMODE_DISABLED 0x00 -#define IEEE80211_OPMODE_NON_MEMBER_PROT_MODE 0x01 -#define IEEE80211_OPMODE_ONE_20MHZ_STA_PROT_MODE 0x02 -#define IEEE80211_OPMODE_HTMIXED_PROT_MODE 0x03 - #define MWL8K_RATE_INDEX_MAX_ARRAY 14 #define MWL8K_FRAME_PROT_DISABLED 0x00 #define MWL8K_FRAME_PROT_11G 0x07 #define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02 #define MWL8K_FRAME_PROT_11N_HT_ALL 0x06 -#define MWL8K_FRAME_PROT_MASK 0x07 struct mwl8k_cmd_update_set_aid { struct mwl8k_cmd_pkt header; @@ -2439,10 +2391,6 @@ static int mwl8k_update_rateset(struct ieee80211_hw *hw, */ #define MWL8K_RATE_TABLE_SIZE 8 #define MWL8K_UCAST_RATE 0 -#define MWL8K_MCAST_RATE 1 -#define MWL8K_BCAST_RATE 2 - -#define MWL8K_USE_FIXED_RATE 0x0001 #define MWL8K_USE_AUTO_RATE 0x0002 struct mwl8k_rate_entry { @@ -2535,7 +2483,6 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - status &= priv->int_mask; if (!status) return IRQ_NONE; @@ -2873,7 +2820,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) } /* Enable interrupts */ - iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); worker = kzalloc(sizeof(*worker), GFP_KERNEL); if (worker == NULL) { @@ -3532,7 +3479,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->hostcmd_wait = NULL; priv->tx_wait = NULL; priv->inconfig = false; - priv->wep_enabled = 0; priv->wmm_mode = false; priv->pending_tx_pkts = 0; strncpy(priv->name, MWL8K_NAME, sizeof(priv->name)); @@ -3614,8 +3560,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - priv->int_mask = 0; - iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); @@ -3652,9 +3597,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, * commands use interrupts and avoids polling. Disable * interrupts when done. */ - priv->int_mask |= MWL8K_A2H_EVENTS; - - iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); /* Get config data, mac addrs etc */ rc = mwl8k_cmd_get_hw_spec(hw); -- cgit v0.10.2 From d89173f25228b8795af2d4b53e985cc44c729332 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 09:54:27 +0200 Subject: mwl8k: s/IEEE80211_ADDR_LEN/ETH_ALEN/g Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 91b7062..e8febab 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -38,8 +38,6 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_table) = { }; MODULE_DEVICE_TABLE(pci, mwl8k_table); -#define IEEE80211_ADDR_LEN ETH_ALEN - /* Register definitions */ #define MWL8K_HIU_GEN_PTR 0x00000c10 #define MWL8K_MODE_STA 0x0000005a @@ -199,7 +197,7 @@ struct mwl8k_priv { /* XXX need to convert this to handle multiple interfaces */ bool capture_beacon; - u8 capture_bssid[IEEE80211_ADDR_LEN]; + u8 capture_bssid[ETH_ALEN]; struct sk_buff *beacon_skb; /* @@ -228,8 +226,8 @@ struct mwl8k_vif { struct ieee80211_bss_conf bss_info; /* BSSID of AP or IBSS */ - u8 bssid[IEEE80211_ADDR_LEN]; - u8 mac_addr[IEEE80211_ADDR_LEN]; + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; /* * Subset of supported legacy rates. @@ -785,7 +783,7 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) memmove(&tr->wh, wh, hdrlen); /* Clear addr4 */ - memset(tr->wh.addr4, 0, IEEE80211_ADDR_LEN); + memset(tr->wh.addr4, 0, ETH_ALEN); /* * Firmware length is the length of the fully formed "802.11 @@ -952,7 +950,7 @@ static inline void mwl8k_save_beacon(struct mwl8k_priv *priv, struct sk_buff *skb) { priv->capture_beacon = false; - memset(priv->capture_bssid, 0, IEEE80211_ADDR_LEN); + memset(priv->capture_bssid, 0, ETH_ALEN); /* * Use GFP_ATOMIC as rxq_process is called from @@ -1067,7 +1065,7 @@ struct mwl8k_tx_desc { __le16 qos_control; __le32 pkt_phys_addr; __le16 pkt_len; - __u8 dest_MAC_addr[IEEE80211_ADDR_LEN]; + __u8 dest_MAC_addr[ETH_ALEN]; __le32 next_tx_desc_phys_addr; __le32 reserved; __le16 rate_info; @@ -1587,7 +1585,7 @@ struct mwl8k_cmd_get_hw_spec { __u8 hw_rev; __u8 host_interface; __le16 num_mcaddrs; - __u8 perm_addr[IEEE80211_ADDR_LEN]; + __u8 perm_addr[ETH_ALEN]; __le16 region_code; __le32 fw_rev; __le32 ps_cookie; @@ -1644,7 +1642,7 @@ struct mwl8k_cmd_mac_multicast_adr { struct mwl8k_cmd_pkt header; __le16 action; __le16 numaddr; - __u8 addr[1][IEEE80211_ADDR_LEN]; + __u8 addr[1][ETH_ALEN]; }; #define MWL8K_ENABLE_RX_MULTICAST 0x000F @@ -1655,7 +1653,7 @@ static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, struct mwl8k_cmd_mac_multicast_adr *cmd; int index = 0; int rc; - int size = sizeof(*cmd) + ((mc_count - 1) * IEEE80211_ADDR_LEN); + int size = sizeof(*cmd) + ((mc_count - 1) * ETH_ALEN); cmd = kzalloc(size, GFP_KERNEL); if (cmd == NULL) return -ENOMEM; @@ -1665,11 +1663,11 @@ static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); cmd->numaddr = cpu_to_le16(mc_count); while ((index < mc_count) && mclist) { - if (mclist->da_addrlen != IEEE80211_ADDR_LEN) { + if (mclist->da_addrlen != ETH_ALEN) { rc = -EINVAL; goto mwl8k_cmd_mac_multicast_adr_exit; } - memcpy(cmd->addr[index], mclist->da_addr, IEEE80211_ADDR_LEN); + memcpy(cmd->addr[index], mclist->da_addr, ETH_ALEN); index++; mclist = mclist->next; } @@ -1848,11 +1846,11 @@ static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw) struct mwl8k_cmd_set_post_scan { struct mwl8k_cmd_pkt header; __le32 isibss; - __u8 bssid[IEEE80211_ADDR_LEN]; + __u8 bssid[ETH_ALEN]; } __attribute__((packed)); static int -mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[IEEE80211_ADDR_LEN]) +mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[ETH_ALEN]) { struct mwl8k_cmd_set_post_scan *cmd; int rc; @@ -1864,7 +1862,7 @@ mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[IEEE80211_ADDR_LEN]) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_POST_SCAN); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->isibss = 0; - memcpy(cmd->bssid, mac, IEEE80211_ADDR_LEN); + memcpy(cmd->bssid, mac, ETH_ALEN); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2216,7 +2214,7 @@ struct mwl8k_cmd_update_sta_db { __le32 action; /* Peer MAC address */ - __u8 peer_addr[IEEE80211_ADDR_LEN]; + __u8 peer_addr[ETH_ALEN]; __le32 reserved; @@ -2244,7 +2242,7 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, cmd->action = cpu_to_le32(action); peer_info = &cmd->peer_info; - memcpy(cmd->peer_addr, mv_vif->bssid, IEEE80211_ADDR_LEN); + memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN); switch (action) { case MWL8K_STA_DB_ADD_ENTRY: @@ -2293,7 +2291,7 @@ struct mwl8k_cmd_update_set_aid { __le16 aid; /* AP's MAC address (BSSID) */ - __u8 bssid[IEEE80211_ADDR_LEN]; + __u8 bssid[ETH_ALEN]; __le16 protection_mode; __u8 supp_rates[MWL8K_RATE_INDEX_MAX_ARRAY]; } __attribute__((packed)); @@ -2317,7 +2315,7 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->aid = cpu_to_le16(info->aid); - memcpy(cmd->bssid, mv_vif->bssid, IEEE80211_ADDR_LEN); + memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN); prot_mode = MWL8K_FRAME_PROT_DISABLED; @@ -2934,7 +2932,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); /* Save the mac address */ - memcpy(mwl8k_vif->mac_addr, conf->mac_addr, IEEE80211_ADDR_LEN); + memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN); /* Back pointer to parent config block */ mwl8k_vif->priv = priv; @@ -3091,14 +3089,13 @@ static int mwl8k_bss_info_changed_wt(struct work_struct *wt) * Finalize the join. Tell rx handler to process * next beacon from our BSSID. */ - memcpy(priv->capture_bssid, - mwl8k_vif->bssid, IEEE80211_ADDR_LEN); + memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN); priv->capture_beacon = true; } else { mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY); memset(&mwl8k_vif->bss_info, 0, sizeof(struct ieee80211_bss_conf)); - memset(mwl8k_vif->bssid, 0, IEEE80211_ADDR_LEN); + memset(mwl8k_vif->bssid, 0, ETH_ALEN); } mwl8k_bss_info_changed_exit: @@ -3117,7 +3114,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, int rc; if (changed & BSS_CHANGED_BSSID) - memcpy(mv_vif->bssid, info->bssid, IEEE80211_ADDR_LEN); + memcpy(mv_vif->bssid, info->bssid, ETH_ALEN); if ((changed & BSS_CHANGED_ASSOC) == 0) return; -- cgit v0.10.2 From ff45fc60ad583f45ecf10a41f7dbecf78519bcc1 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 11:50:36 +0200 Subject: mwl8k: sort firmware command list by opcode, and trim unused commands Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index e8febab..682b820 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -307,25 +307,23 @@ static const struct ieee80211_rate mwl8k_rates[] = { #define MWL8K_CMD_GET_HW_SPEC 0x0003 #define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010 #define MWL8K_CMD_GET_STAT 0x0014 -#define MWL8K_CMD_RADIO_CONTROL 0x001C -#define MWL8K_CMD_RF_TX_POWER 0x001E +#define MWL8K_CMD_RADIO_CONTROL 0x001c +#define MWL8K_CMD_RF_TX_POWER 0x001e #define MWL8K_CMD_SET_PRE_SCAN 0x0107 #define MWL8K_CMD_SET_POST_SCAN 0x0108 -#define MWL8K_CMD_SET_RF_CHANNEL 0x010A +#define MWL8K_CMD_SET_RF_CHANNEL 0x010a +#define MWL8K_CMD_SET_AID 0x010d +#define MWL8K_CMD_SET_RATE 0x0110 +#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111 +#define MWL8K_CMD_RTS_THRESHOLD 0x0113 #define MWL8K_CMD_SET_SLOT 0x0114 +#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115 +#define MWL8K_CMD_SET_WMM_MODE 0x0123 #define MWL8K_CMD_MIMO_CONFIG 0x0125 +#define MWL8K_CMD_USE_FIXED_RATE 0x0126 #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 -#define MWL8K_CMD_SET_WMM_MODE 0x0123 -#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115 -#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111 -#define MWL8K_CMD_UPDATE_STADB 0x1123 #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 -#define MWL8K_CMD_SET_LINKADAPT_MODE 0x0129 -#define MWL8K_CMD_SET_AID 0x010d -#define MWL8K_CMD_SET_RATE 0x0110 -#define MWL8K_CMD_USE_FIXED_RATE 0x0126 -#define MWL8K_CMD_RTS_THRESHOLD 0x0113 -#define MWL8K_CMD_ENCRYPTION 0x1122 +#define MWL8K_CMD_UPDATE_STADB 0x1123 static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) { @@ -343,20 +341,18 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(SET_PRE_SCAN); MWL8K_CMDNAME(SET_POST_SCAN); MWL8K_CMDNAME(SET_RF_CHANNEL); + MWL8K_CMDNAME(SET_AID); + MWL8K_CMDNAME(SET_RATE); + MWL8K_CMDNAME(SET_FINALIZE_JOIN); + MWL8K_CMDNAME(RTS_THRESHOLD); MWL8K_CMDNAME(SET_SLOT); + MWL8K_CMDNAME(SET_EDCA_PARAMS); + MWL8K_CMDNAME(SET_WMM_MODE); MWL8K_CMDNAME(MIMO_CONFIG); + MWL8K_CMDNAME(USE_FIXED_RATE); MWL8K_CMDNAME(ENABLE_SNIFFER); - MWL8K_CMDNAME(SET_WMM_MODE); - MWL8K_CMDNAME(SET_EDCA_PARAMS); - MWL8K_CMDNAME(SET_FINALIZE_JOIN); - MWL8K_CMDNAME(UPDATE_STADB); MWL8K_CMDNAME(SET_RATEADAPT_MODE); - MWL8K_CMDNAME(SET_LINKADAPT_MODE); - MWL8K_CMDNAME(SET_AID); - MWL8K_CMDNAME(SET_RATE); - MWL8K_CMDNAME(USE_FIXED_RATE); - MWL8K_CMDNAME(RTS_THRESHOLD); - MWL8K_CMDNAME(ENCRYPTION); + MWL8K_CMDNAME(UPDATE_STADB); default: snprintf(buf, bufsize, "0x%x", cmd); } -- cgit v0.10.2 From ce9e2e1b8433c8795459a259ee87bc4e424e7c50 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 14:00:45 +0200 Subject: mwl8k: various coding style cleanups Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 682b820..a2eeba1 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1,5 +1,6 @@ /* - * drivers/net/wireless/mwl8k.c driver for Marvell TOPDOG 802.11 Wireless cards + * drivers/net/wireless/mwl8k.c + * Driver for Marvell TOPDOG 802.11 Wireless cards * * Copyright (C) 2008 Marvell Semiconductor Inc. * @@ -40,12 +41,12 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); /* Register definitions */ #define MWL8K_HIU_GEN_PTR 0x00000c10 -#define MWL8K_MODE_STA 0x0000005a -#define MWL8K_MODE_AP 0x000000a5 +#define MWL8K_MODE_STA 0x0000005a +#define MWL8K_MODE_AP 0x000000a5 #define MWL8K_HIU_INT_CODE 0x00000c14 -#define MWL8K_FWSTA_READY 0xf0f1f2f4 -#define MWL8K_FWAP_READY 0xf1f2f4a5 -#define MWL8K_INT_CODE_CMD_FINISHED 0x00000005 +#define MWL8K_FWSTA_READY 0xf0f1f2f4 +#define MWL8K_FWAP_READY 0xf1f2f4a5 +#define MWL8K_INT_CODE_CMD_FINISHED 0x00000005 #define MWL8K_HIU_SCRATCH 0x00000c40 /* Host->device communications */ @@ -54,10 +55,10 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); #define MWL8K_HIU_H2A_INTERRUPT_MASK 0x00000c20 #define MWL8K_HIU_H2A_INTERRUPT_CLEAR_SEL 0x00000c24 #define MWL8K_HIU_H2A_INTERRUPT_STATUS_MASK 0x00000c28 -#define MWL8K_H2A_INT_DUMMY (1 << 20) -#define MWL8K_H2A_INT_RESET (1 << 15) -#define MWL8K_H2A_INT_DOORBELL (1 << 1) -#define MWL8K_H2A_INT_PPA_READY (1 << 0) +#define MWL8K_H2A_INT_DUMMY (1 << 20) +#define MWL8K_H2A_INT_RESET (1 << 15) +#define MWL8K_H2A_INT_DOORBELL (1 << 1) +#define MWL8K_H2A_INT_PPA_READY (1 << 0) /* Device->host communications */ #define MWL8K_HIU_A2H_INTERRUPT_EVENTS 0x00000c2c @@ -65,16 +66,16 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); #define MWL8K_HIU_A2H_INTERRUPT_MASK 0x00000c34 #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c -#define MWL8K_A2H_INT_DUMMY (1 << 20) -#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) -#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) -#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) -#define MWL8K_A2H_INT_RADIO_ON (1 << 6) -#define MWL8K_A2H_INT_RADIO_OFF (1 << 5) -#define MWL8K_A2H_INT_MAC_EVENT (1 << 3) -#define MWL8K_A2H_INT_OPC_DONE (1 << 2) -#define MWL8K_A2H_INT_RX_READY (1 << 1) -#define MWL8K_A2H_INT_TX_DONE (1 << 0) +#define MWL8K_A2H_INT_DUMMY (1 << 20) +#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) +#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) +#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) +#define MWL8K_A2H_INT_RADIO_ON (1 << 6) +#define MWL8K_A2H_INT_RADIO_OFF (1 << 5) +#define MWL8K_A2H_INT_MAC_EVENT (1 << 3) +#define MWL8K_A2H_INT_OPC_DONE (1 << 2) +#define MWL8K_A2H_INT_RX_READY (1 << 1) +#define MWL8K_A2H_INT_TX_DONE (1 << 0) #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ MWL8K_A2H_INT_CHNL_SWITCHED | \ @@ -331,7 +332,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) snprintf(buf, bufsize, "%s", #x);\ return buf;\ } while (0) - switch (cmd & (~0x8000)) { + switch (cmd & ~0x8000) { MWL8K_CMDNAME(CODE_DNLD); MWL8K_CMDNAME(GET_HW_SPEC); MWL8K_CMDNAME(MAC_MULTICAST_ADR); @@ -1078,8 +1079,7 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) int size; int i; - memset(&txq->tx_stats, 0, - sizeof(struct ieee80211_tx_queue_stats)); + memset(&txq->tx_stats, 0, sizeof(struct ieee80211_tx_queue_stats)); txq->tx_stats.limit = MWL8K_TX_DESCS; txq->tx_head = 0; txq->tx_tail = 0; @@ -1181,10 +1181,10 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) { - u32 count = 0; - unsigned long timeout = 0; struct mwl8k_priv *priv = hw->priv; DECLARE_COMPLETION_ONSTACK(cmd_wait); + u32 count; + unsigned long timeout; might_sleep(); @@ -1219,7 +1219,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) __func__, __LINE__, delay_ms, count, newcount); mwl8k_scan_tx_ring(priv, txinfo, 4); - for (index = 0 ; index < 4; index++) + for (index = 0; index < 4; index++) printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u DRV:%u U:%u\n", index, @@ -1229,6 +1229,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) txinfo[index].fw_owned, txinfo[index].drv_owned, txinfo[index].unused); + return -ETIMEDOUT; } @@ -1251,7 +1252,7 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) int rc; struct mwl8k_tx_desc *tx_desc; unsigned long addr; - size_t size; + int size; struct sk_buff *skb; struct ieee80211_tx_info *info; u32 status; @@ -1275,7 +1276,7 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) priv->pending_tx_pkts--; addr = le32_to_cpu(tx_desc->pkt_phys_addr); - size = (u32)(le16_to_cpu(tx_desc->pkt_len)); + size = le16_to_cpu(tx_desc->pkt_len); skb = txq->tx_skb[tx].skb; txq->tx_skb[tx].skb = NULL; @@ -1312,12 +1313,8 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) info = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); - - /* Convert firmware status stuff into tx_status */ - if (MWL8K_TXD_SUCCESS(status)) { - /* Transmit OK */ + if (MWL8K_TXD_SUCCESS(status)) info->flags |= IEEE80211_TX_STAT_ACK; - } ieee80211_tx_status_irqsafe(hw, skb); @@ -1522,7 +1519,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) dma_addr_t dma_addr; unsigned int dma_size; int rc; - u16 __iomem *result; unsigned long timeout = 0; u8 buf[32]; @@ -1551,7 +1547,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) pci_unmap_single(priv->pdev, dma_addr, dma_size, PCI_DMA_BIDIRECTIONAL); - result = &cmd->result; if (!timeout) { spin_lock_irq(&priv->fw_lock); priv->hostcmd_wait = NULL; @@ -1562,12 +1557,12 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) MWL8K_CMD_TIMEOUT_MS); rc = -ETIMEDOUT; } else { - rc = *result ? -EINVAL : 0; + rc = cmd->result ? -EINVAL : 0; if (rc) printk(KERN_ERR "%s: Command %s error 0x%x\n", priv->name, mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), - *result); + cmd->result); } return rc; @@ -1638,10 +1633,11 @@ struct mwl8k_cmd_mac_multicast_adr { struct mwl8k_cmd_pkt header; __le16 action; __le16 numaddr; - __u8 addr[1][ETH_ALEN]; + __u8 addr[0][ETH_ALEN]; }; #define MWL8K_ENABLE_RX_MULTICAST 0x000F + static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mclist) @@ -1649,7 +1645,8 @@ static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, struct mwl8k_cmd_mac_multicast_adr *cmd; int index = 0; int rc; - int size = sizeof(*cmd) + ((mc_count - 1) * ETH_ALEN); + int size = sizeof(*cmd) + mc_count * ETH_ALEN; + cmd = kzalloc(size, GFP_KERNEL); if (cmd == NULL) return -ENOMEM; @@ -1658,13 +1655,13 @@ static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, cmd->header.length = cpu_to_le16(size); cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); cmd->numaddr = cpu_to_le16(mc_count); - while ((index < mc_count) && mclist) { + + while (index < mc_count && mclist) { if (mclist->da_addrlen != ETH_ALEN) { rc = -EINVAL; goto mwl8k_cmd_mac_multicast_adr_exit; } - memcpy(cmd->addr[index], mclist->da_addr, ETH_ALEN); - index++; + memcpy(cmd->addr[index++], mclist->da_addr, ETH_ALEN); mclist = mclist->next; } @@ -1846,7 +1843,7 @@ struct mwl8k_cmd_set_post_scan { } __attribute__((packed)); static int -mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[ETH_ALEN]) +mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 *mac) { struct mwl8k_cmd_set_post_scan *cmd; int rc; @@ -1980,7 +1977,7 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = enable ? cpu_to_le32((u32)MWL8K_CMD_SET) : 0; + cmd->action = cpu_to_le32(!!enable); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -1989,7 +1986,7 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) } /* - * CMD_SET_RATE_ADAPT_MODE. + * CMD_SET_RATEADAPT_MODE. */ struct mwl8k_cmd_set_rate_adapt_mode { struct mwl8k_cmd_pkt header; @@ -2117,22 +2114,18 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, __u8 aifs, __u16 txop) { struct mwl8k_cmd_set_edca_params *cmd; - u32 log_cw_min, log_cw_max; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - log_cw_min = ilog2(cw_min+1); - log_cw_max = ilog2(cw_max+1); cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); cmd->txop = cpu_to_le16(txop); - cmd->log_cw_max = (u8)log_cw_max; - cmd->log_cw_min = (u8)log_cw_min; + cmd->log_cw_max = (u8)ilog2(cw_max + 1); + cmd->log_cw_min = (u8)ilog2(cw_min + 1); cmd->aifs = aifs; cmd->txq = qnum; @@ -2173,11 +2166,7 @@ static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame, cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - - if (dtim) - cmd->sleep_interval = cpu_to_le32(dtim); - else - cmd->sleep_interval = cpu_to_le32(1); + cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1); hdrlen = ieee80211_hdrlen(payload->frame_control); @@ -2189,8 +2178,8 @@ static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame, "sent to firmware. Sz=%u MAX=%u\n", __func__, payload_len, MWL8K_FJ_BEACON_MAXLEN); - payload_len = payload_len > MWL8K_FJ_BEACON_MAXLEN ? - MWL8K_FJ_BEACON_MAXLEN : payload_len; + if (payload_len > MWL8K_FJ_BEACON_MAXLEN) + payload_len = MWL8K_FJ_BEACON_MAXLEN; if (payload && payload_len) memcpy(cmd->beacon_data, &payload->u.beacon, payload_len); @@ -2250,7 +2239,7 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, peer_info->amsdu_enabled = 0; rates = peer_info->legacy_rates; - for (count = 0 ; count < mv_vif->legacy_nrates; count++) + for (count = 0; count < mv_vif->legacy_nrates; count++) rates[count] = bitrates[count].hw_value; rc = mwl8k_post_cmd(hw, &cmd->header); @@ -2313,8 +2302,6 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN); - prot_mode = MWL8K_FRAME_PROT_DISABLED; - if (info->use_cts_prot) { prot_mode = MWL8K_FRAME_PROT_11G; } else { @@ -2331,7 +2318,6 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, break; } } - cmd->protection_mode = cpu_to_le16(prot_mode); for (count = 0; count < mv_vif->legacy_nrates; count++) @@ -2934,7 +2920,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, mwl8k_vif->priv = priv; /* Setup initial PHY parameters */ - memcpy(mwl8k_vif->legacy_rates , + memcpy(mwl8k_vif->legacy_rates, priv->rates, sizeof(mwl8k_vif->legacy_rates)); mwl8k_vif->legacy_nrates = ARRAY_SIZE(priv->rates); @@ -3171,8 +3157,9 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt) if (rc) goto mwl8k_configure_filter_exit; if (mc_count) { - mc_count = mc_count < priv->num_mcaddrs ? - mc_count : priv->num_mcaddrs; + if (mc_count > priv->num_mcaddrs) + mc_count = priv->num_mcaddrs; + rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist); if (rc) printk(KERN_ERR @@ -3411,12 +3398,9 @@ static void mwl8k_tx_reclaim_handler(unsigned long data) for (i = 0; i < MWL8K_TX_QUEUES; i++) mwl8k_txq_reclaim(hw, i, 0); - if (priv->tx_wait != NULL) { - int count = mwl8k_txq_busy(priv); - if (count == 0) { - complete(priv->tx_wait); - priv->tx_wait = NULL; - } + if (priv->tx_wait != NULL && mwl8k_txq_busy(priv) == 0) { + complete(priv->tx_wait); + priv->tx_wait = NULL; } spin_unlock_bh(&priv->tx_lock); } @@ -3426,7 +3410,7 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) struct mwl8k_priv *priv = container_of(work, struct mwl8k_priv, finalize_join_worker); struct sk_buff *skb = priv->beacon_skb; - u8 dtim = (MWL8K_VIF(priv->vif))->bss_info.dtim_period; + u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period; mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim); dev_kfree_skb(skb); @@ -3513,7 +3497,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_MONITOR); /* Set rssi and noise values to dBm */ - hw->flags |= (IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM); + hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; hw->vif_data_size = sizeof(struct mwl8k_vif); priv->vif = NULL; -- cgit v0.10.2 From c46563b714b09d44eec4d1fd8a0f53e79ddaa3aa Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 12:14:58 +0200 Subject: mwl8k: remove MWL8K_RADIO_* defines Instead of passing a flag bitmask to mwl8k_cmd_802_11_radio_control, pass the 'enable' and 'force' arguments as separate parameters, and introduce wrappers for the common cases of enabling and disabling without forcing. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a2eeba1..78183c8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -186,9 +186,10 @@ struct mwl8k_priv { struct ieee80211_channel channels[14]; struct ieee80211_rate rates[12]; + bool radio_on; + /* RF preamble: Short, Long or Auto */ u8 radio_preamble; - u8 radio_state; /* WMM MODE 1 for enabled; 0 for disabled */ bool wmm_mode; @@ -278,9 +279,6 @@ static const struct ieee80211_rate mwl8k_rates[] = { }; /* Radio settings */ -#define MWL8K_RADIO_FORCE 0x2 -#define MWL8K_RADIO_ENABLE 0x1 -#define MWL8K_RADIO_DISABLE 0x0 #define MWL8K_RADIO_AUTO_PREAMBLE 0x0005 #define MWL8K_RADIO_SHORT_PREAMBLE 0x0003 #define MWL8K_RADIO_LONG_PREAMBLE 0x0001 @@ -1195,7 +1193,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) count = mwl8k_txq_busy(priv); if (count) { priv->tx_wait = &cmd_wait; - if (priv->radio_state) + if (priv->radio_on) mwl8k_tx_start(priv); } spin_unlock_bh(&priv->tx_lock); @@ -1318,7 +1316,7 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) ieee80211_tx_status_irqsafe(hw, skb); - wake = !priv->inconfig && priv->radio_state; + wake = !priv->inconfig && priv->radio_on; } if (wake) @@ -1726,18 +1724,16 @@ struct mwl8k_cmd_802_11_radio_control { __le16 radio_on; } __attribute__((packed)); -static int mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, int enable) +static int +mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_802_11_radio_control *cmd; int rc; - if (((enable & MWL8K_RADIO_ENABLE) == priv->radio_state) && - !(enable & MWL8K_RADIO_FORCE)) + if (enable == priv->radio_on && !force) return 0; - enable &= MWL8K_RADIO_ENABLE; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; @@ -1752,11 +1748,21 @@ static int mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, int enable) kfree(cmd); if (!rc) - priv->radio_state = enable; + priv->radio_on = enable; return rc; } +static int mwl8k_cmd_802_11_radio_disable(struct ieee80211_hw *hw) +{ + return mwl8k_cmd_802_11_radio_control(hw, 0, 0); +} + +static int mwl8k_cmd_802_11_radio_enable(struct ieee80211_hw *hw) +{ + return mwl8k_cmd_802_11_radio_control(hw, 1, 0); +} + static int mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) { @@ -1770,8 +1776,7 @@ mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) MWL8K_RADIO_SHORT_PREAMBLE : MWL8K_RADIO_LONG_PREAMBLE); - return mwl8k_cmd_802_11_radio_control(hw, - MWL8K_RADIO_ENABLE | MWL8K_RADIO_FORCE); + return mwl8k_cmd_802_11_radio_control(hw, 1, 1); } /* @@ -2483,7 +2488,7 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { if (!priv->inconfig && - priv->radio_state && + priv->radio_on && mwl8k_txq_busy(priv)) mwl8k_tx_start(priv); } @@ -2661,7 +2666,7 @@ static void mwl8k_config_thread(struct work_struct *wt) spin_lock_irq(&priv->tx_lock); priv->inconfig = false; - if (priv->pending_tx_pkts && priv->radio_state) + if (priv->pending_tx_pkts && priv->radio_on) mwl8k_tx_start(priv); spin_unlock_irq(&priv->tx_lock); ieee80211_wake_queues(hw); @@ -2745,7 +2750,7 @@ static int mwl8k_start_wt(struct work_struct *wt) } /* Turn on radio */ - if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) { + if (mwl8k_cmd_802_11_radio_enable(hw)) { rc = -EIO; goto mwl8k_start_exit; } @@ -2839,11 +2844,8 @@ static int mwl8k_stop_wt(struct work_struct *wt) { struct mwl8k_stop_worker *worker = (struct mwl8k_stop_worker *)wt; struct ieee80211_hw *hw = worker->header.hw; - int rc; - - rc = mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE); - return rc; + return mwl8k_cmd_802_11_radio_disable(hw); } static void mwl8k_stop(struct ieee80211_hw *hw) @@ -2958,7 +2960,7 @@ static int mwl8k_config_wt(struct work_struct *wt) struct mwl8k_priv *priv = hw->priv; int rc = 0; - if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) { + if (mwl8k_cmd_802_11_radio_enable(hw)) { rc = -EINVAL; goto mwl8k_config_exit; } @@ -3503,7 +3505,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Set default radio state and preamble */ priv->radio_preamble = MWL8K_RADIO_DEFAULT_PREAMBLE; - priv->radio_state = MWL8K_RADIO_DISABLE; + priv->radio_on = 0; /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); @@ -3584,7 +3586,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } /* Turn radio off */ - rc = mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE); + rc = mwl8k_cmd_802_11_radio_disable(hw); if (rc) { printk(KERN_ERR "%s: Cannot disable\n", priv->name); goto err_stop_firmware; -- cgit v0.10.2 From 68ce38845c23443b15e374fb7362916c1231278e Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 12:26:57 +0200 Subject: mwl8k: remove MWL8K_RADIO_*_PREAMBLE defines Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 78183c8..22500bf 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -187,9 +187,7 @@ struct mwl8k_priv { struct ieee80211_rate rates[12]; bool radio_on; - - /* RF preamble: Short, Long or Auto */ - u8 radio_preamble; + bool radio_short_preamble; /* WMM MODE 1 for enabled; 0 for disabled */ bool wmm_mode; @@ -278,17 +276,10 @@ static const struct ieee80211_rate mwl8k_rates[] = { { .bitrate = 540, .hw_value = 108, }, }; -/* Radio settings */ -#define MWL8K_RADIO_AUTO_PREAMBLE 0x0005 -#define MWL8K_RADIO_SHORT_PREAMBLE 0x0003 -#define MWL8K_RADIO_LONG_PREAMBLE 0x0001 - /* WMM */ #define MWL8K_WMM_ENABLE 1 #define MWL8K_WMM_DISABLE 0 -#define MWL8K_RADIO_DEFAULT_PREAMBLE MWL8K_RADIO_LONG_PREAMBLE - /* Slot time */ /* Short Slot: 9us slot time */ @@ -1741,7 +1732,7 @@ mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force) cmd->header.code = cpu_to_le16(MWL8K_CMD_RADIO_CONTROL); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_CMD_SET); - cmd->control = cpu_to_le16(priv->radio_preamble); + cmd->control = cpu_to_le16(priv->radio_short_preamble ? 3 : 1); cmd->radio_on = cpu_to_le16(enable ? 0x0001 : 0x0000); rc = mwl8k_post_cmd(hw, &cmd->header); @@ -1772,9 +1763,7 @@ mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) return -EINVAL; priv = hw->priv; - priv->radio_preamble = (short_preamble ? - MWL8K_RADIO_SHORT_PREAMBLE : - MWL8K_RADIO_LONG_PREAMBLE); + priv->radio_short_preamble = short_preamble; return mwl8k_cmd_802_11_radio_control(hw, 1, 1); } @@ -3051,8 +3040,7 @@ static int mwl8k_bss_info_changed_wt(struct work_struct *wt) goto mwl8k_bss_info_changed_exit; /* Set radio preamble */ - if (mwl8k_set_radio_preamble(hw, - info->use_short_preamble)) + if (mwl8k_set_radio_preamble(hw, info->use_short_preamble)) goto mwl8k_bss_info_changed_exit; /* Set slot time */ @@ -3504,8 +3492,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->vif = NULL; /* Set default radio state and preamble */ - priv->radio_preamble = MWL8K_RADIO_DEFAULT_PREAMBLE; priv->radio_on = 0; + priv->radio_short_preamble = 0; /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); -- cgit v0.10.2 From 0439b1f55646ea944b0d58337f5065b79a1c1be0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 12:34:02 +0200 Subject: mwl8k: remove MWL8K_WMM_* defines Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 22500bf..33d7ab5 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -188,9 +188,7 @@ struct mwl8k_priv { bool radio_on; bool radio_short_preamble; - - /* WMM MODE 1 for enabled; 0 for disabled */ - bool wmm_mode; + bool wmm_enabled; /* Set if PHY config is in progress */ bool inconfig; @@ -276,10 +274,6 @@ static const struct ieee80211_rate mwl8k_rates[] = { { .bitrate = 540, .hw_value = 108, }, }; -/* WMM */ -#define MWL8K_WMM_ENABLE 1 -#define MWL8K_WMM_DISABLE 0 - /* Slot time */ /* Short Slot: 9us slot time */ @@ -2028,13 +2022,13 @@ static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = enable ? cpu_to_le16(MWL8K_CMD_SET) : 0; + cmd->action = cpu_to_le16(!!enable); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); if (!rc) - priv->wmm_mode = enable; + priv->wmm_enabled = enable; return rc; } @@ -2762,7 +2756,7 @@ static int mwl8k_start_wt(struct work_struct *wt) } /* Disable WMM. WMM gets enabled when stack sends WMM parms */ - if (mwl8k_set_wmm(hw, MWL8K_WMM_DISABLE)) { + if (mwl8k_set_wmm(hw, 0)) { rc = -EIO; goto mwl8k_start_exit; } @@ -3272,10 +3266,11 @@ static int mwl8k_conf_tx_wt(struct work_struct *wt) struct mwl8k_priv *priv = hw->priv; int rc = 0; - if (priv->wmm_mode == MWL8K_WMM_DISABLE) - if (mwl8k_set_wmm(hw, MWL8K_WMM_ENABLE)) { + if (!priv->wmm_enabled) { + if (mwl8k_set_wmm(hw, 1)) { rc = -EINVAL; goto mwl8k_conf_tx_exit; + } } if (mwl8k_set_edca_params(hw, GET_TXQ(queue), params->cw_min, @@ -3446,7 +3441,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->hostcmd_wait = NULL; priv->tx_wait = NULL; priv->inconfig = false; - priv->wmm_mode = false; + priv->wmm_enabled = false; priv->pending_tx_pkts = 0; strncpy(priv->name, MWL8K_NAME, sizeof(priv->name)); -- cgit v0.10.2 From 5539bb51295f2c9300a6e467a29bb62bcfe9f4bc Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 16:06:53 +0200 Subject: mwl8k: remove MWL8K_*_SLOTTIME defines Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 33d7ab5..a40434b 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -274,14 +274,6 @@ static const struct ieee80211_rate mwl8k_rates[] = { { .bitrate = 540, .hw_value = 108, }, }; -/* Slot time */ - -/* Short Slot: 9us slot time */ -#define MWL8K_SHORT_SLOTTIME 1 - -/* Long slot: 20us slot time */ -#define MWL8K_LONG_SLOTTIME 0 - /* Set or get info from Firmware */ #define MWL8K_CMD_SET 0x0001 #define MWL8K_CMD_GET 0x0000 @@ -1895,7 +1887,7 @@ struct mwl8k_cmd_set_slot { __u8 short_slot; } __attribute__((packed)); -static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, int slot_time) +static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time) { struct mwl8k_cmd_set_slot *cmd; int rc; @@ -1907,7 +1899,7 @@ static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, int slot_time) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_CMD_SET); - cmd->short_slot = slot_time == MWL8K_SHORT_SLOTTIME ? 1 : 0; + cmd->short_slot = short_slot_time; rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -3038,8 +3030,7 @@ static int mwl8k_bss_info_changed_wt(struct work_struct *wt) goto mwl8k_bss_info_changed_exit; /* Set slot time */ - if (mwl8k_cmd_set_slot(hw, info->use_short_slot ? - MWL8K_SHORT_SLOTTIME : MWL8K_LONG_SLOTTIME)) + if (mwl8k_cmd_set_slot(hw, info->use_short_slot)) goto mwl8k_bss_info_changed_exit; /* Update peer rate info */ -- cgit v0.10.2 From e81cd2d664fe5b75a0db9bb24b43c0dfbde32319 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 03:55:42 +0200 Subject: mwl8k: fix mwl8k_configure_filter() parameter lifetime issue mwl8k_configure_filter() passes pointers to total_flags and the multicast address list to a workqueue function, while there is no guarantee that those pointers will still be valid by the time the workqueue function runs. Solve this by passing total_flags by value, and by passing an already built multicast address setup command packet to the workqueue function so that we don't have to look at the multicast address list itself outside of mwl8k_configure_filter(). Also, since ->configure_filter() can sleep now, wait synchronously for the worker to finish. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a40434b..a961b69 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1613,38 +1613,39 @@ struct mwl8k_cmd_mac_multicast_adr { #define MWL8K_ENABLE_RX_MULTICAST 0x000F -static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, - int mc_count, - struct dev_addr_list *mclist) +static struct mwl8k_cmd_pkt * +__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) { + struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_mac_multicast_adr *cmd; - int index = 0; - int rc; - int size = sizeof(*cmd) + mc_count * ETH_ALEN; + int size; + int i; + + if (mc_count > priv->num_mcaddrs) + mc_count = priv->num_mcaddrs; + + size = sizeof(*cmd) + mc_count * ETH_ALEN; - cmd = kzalloc(size, GFP_KERNEL); + cmd = kzalloc(size, GFP_ATOMIC); if (cmd == NULL) - return -ENOMEM; + return NULL; cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR); cmd->header.length = cpu_to_le16(size); cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); cmd->numaddr = cpu_to_le16(mc_count); - while (index < mc_count && mclist) { + for (i = 0; i < mc_count && mclist; i++) { if (mclist->da_addrlen != ETH_ALEN) { - rc = -EINVAL; - goto mwl8k_cmd_mac_multicast_adr_exit; + kfree(cmd); + return NULL; } - memcpy(cmd->addr[index++], mclist->da_addr, ETH_ALEN); + memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN); mclist = mclist->next; } - rc = mwl8k_post_cmd(hw, &cmd->header); - -mwl8k_cmd_mac_multicast_adr_exit: - kfree(cmd); - return rc; + return &cmd->header; } /* @@ -3091,12 +3092,21 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, printk(KERN_ERR "%s() timed out\n", __func__); } +static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + struct mwl8k_cmd_pkt *cmd; + + cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist); + + return (unsigned long)cmd; +} + struct mwl8k_configure_filter_worker { struct mwl8k_work_struct header; unsigned int changed_flags; - unsigned int *total_flags; - int mc_count; - struct dev_addr_list *mclist; + unsigned int total_flags; + struct mwl8k_cmd_pkt *multicast_adr_cmd; }; #define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC @@ -3105,18 +3115,12 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt) { struct mwl8k_configure_filter_worker *worker = (struct mwl8k_configure_filter_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - unsigned int changed_flags = worker->changed_flags; - unsigned int *total_flags = worker->total_flags; - int mc_count = worker->mc_count; - struct dev_addr_list *mclist = worker->mclist; - struct mwl8k_priv *priv = hw->priv; int rc = 0; - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + if (worker->changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (worker->total_flags & FIF_BCN_PRBRESP_PROMISC) rc = mwl8k_cmd_set_pre_scan(hw); else { u8 *bssid; @@ -3129,54 +3133,20 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt) } } - if (rc) - goto mwl8k_configure_filter_exit; - if (mc_count) { - if (mc_count > priv->num_mcaddrs) - mc_count = priv->num_mcaddrs; - - rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist); - if (rc) - printk(KERN_ERR - "%s()Error setting multicast addresses\n", - __func__); - } + if (!rc && worker->multicast_adr_cmd != NULL) + rc = mwl8k_post_cmd(hw, worker->multicast_adr_cmd); + kfree(worker->multicast_adr_cmd); -mwl8k_configure_filter_exit: return rc; } -static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, - int mc_count, struct dev_addr_list *mclist) -{ - struct mwl8k_configure_filter_worker *worker; - - worker = kzalloc(sizeof(*worker), GFP_ATOMIC); - - if (!worker) - return 0; - - /* - * XXX: This is _HORRIBLY_ broken!! - * - * No locking, the mclist pointer might be invalid as soon as this - * function returns, something in the list might be invalidated - * once we get to the worker, etc... - */ - worker->mc_count = mc_count; - worker->mclist = mclist; - - return (u64)worker; -} - static void mwl8k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) { - - struct mwl8k_configure_filter_worker *worker = (void *)multicast; struct mwl8k_priv *priv = hw->priv; + struct mwl8k_configure_filter_worker *worker; /* Clear unsupported feature flags */ *total_flags &= MWL8K_SUPPORTED_IF_FLAGS; @@ -3184,12 +3154,13 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS)) return; + worker = kzalloc(sizeof(*worker), GFP_ATOMIC); if (worker == NULL) return; - worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY; worker->changed_flags = changed_flags; - worker->total_flags = total_flags; + worker->total_flags = *total_flags; + worker->multicast_adr_cmd = (void *)(unsigned long)multicast; mwl8k_queue_work(hw, &worker->header, priv->config_wq, mwl8k_configure_filter_wt); -- cgit v0.10.2 From 240e86efd60e6bc232a072273a7f7794bcb035e0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 14:15:44 +0200 Subject: mwl8k: ->add_interface() is not called for monitor interfaces There is no need to check for NL80211_IFTYPE_MONITOR in ->add_interface(), as this function is never called for monitor interfaces. Also, there is no need to advertise this bit in our wiphy's ->interface_modes. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a961b69..301d2a2 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2883,8 +2883,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, /* * We only support managed interfaces for now. */ - if (conf->type != NL80211_IFTYPE_STATION && - conf->type != NL80211_IFTYPE_MONITOR) + if (conf->type != NL80211_IFTYPE_STATION) return -EINVAL; /* Clean out driver private area */ @@ -3440,8 +3439,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, hw->queues = MWL8K_TX_QUEUES; - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_MONITOR); + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); /* Set rssi and noise values to dBm */ hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; -- cgit v0.10.2 From 76266b2ad38c33fb2c1475cfeb35ed070adaba2b Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 11:07:09 +0200 Subject: mwl8k: dma header manipulations can't fail Adding and removing the DMA header that the mwl8k hardware requires on tx and provides on rx can never fail, since we are guaranteed to have enough headroom on the tx path to expand the packet, and we only ever shrink the packet on the rx path. (And on both paths we are guaranteed to be the only user of the skb we are handling.) This allows removing all of the skb clone handling in the tx and tx reclaim paths, and eliminates error checks in both the tx and rx paths, simplifying the code a bit more. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 301d2a2..5aa8042 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -111,17 +111,6 @@ struct mwl8k_rx_queue { struct sk_buff **rx_skb; }; -struct mwl8k_skb { - /* - * The DMA engine requires a modification to the payload. - * If the skbuff is shared/cloned, it needs to be unshared. - * This method is used to ensure the stack always gets back - * the skbuff it sent for transmission. - */ - struct sk_buff *clone; - struct sk_buff *skb; -}; - struct mwl8k_tx_queue { /* hw transmits here */ int tx_head; @@ -132,7 +121,7 @@ struct mwl8k_tx_queue { struct ieee80211_tx_queue_stats tx_stats; struct mwl8k_tx_desc *tx_desc_area; dma_addr_t tx_desc_dma; - struct mwl8k_skb *tx_skb; + struct sk_buff **tx_skb; }; /* Pointers to the firmware data and meta information about it. */ @@ -714,12 +703,11 @@ struct mwl8k_dma_data { } __attribute__((packed)); /* Routines to add/remove DMA header from skb. */ -static inline int mwl8k_remove_dma_header(struct sk_buff *skb) +static inline void mwl8k_remove_dma_header(struct sk_buff *skb) { - struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)(skb->data); + struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)skb->data; void *dst, *src = &tr->wh; - __le16 fc = tr->wh.frame_control; - int hdrlen = ieee80211_hdrlen(fc); + int hdrlen = ieee80211_hdrlen(tr->wh.frame_control); u16 space = sizeof(struct mwl8k_dma_data) - hdrlen; dst = (void *)tr + space; @@ -727,11 +715,9 @@ static inline int mwl8k_remove_dma_header(struct sk_buff *skb) memmove(dst, src, hdrlen); skb_pull(skb, space); } - - return 0; } -static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) +static inline void mwl8k_add_dma_header(struct sk_buff *skb) { struct ieee80211_hdr *wh; u32 hdrlen, pktlen; @@ -763,8 +749,6 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) * This includes all crypto material including the MIC. */ tr->fwlen = cpu_to_le16(pktlen - hdrlen); - - return skb; } @@ -967,10 +951,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); skb_put(skb, le16_to_cpu(rx_desc->pkt_len)); - if (mwl8k_remove_dma_header(skb)) { - dev_kfree_skb(skb); - continue; - } + mwl8k_remove_dma_header(skb); wh = (struct ieee80211_hdr *)skb->data; @@ -1224,7 +1205,6 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) while (txq->tx_stats.len > 0) { int tx; - int rc; struct mwl8k_tx_desc *tx_desc; unsigned long addr; int size; @@ -1232,7 +1212,6 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) struct ieee80211_tx_info *info; u32 status; - rc = 0; tx = txq->tx_head; tx_desc = txq->tx_desc_area + tx; @@ -1252,40 +1231,18 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) addr = le32_to_cpu(tx_desc->pkt_phys_addr); size = le16_to_cpu(tx_desc->pkt_len); - skb = txq->tx_skb[tx].skb; - txq->tx_skb[tx].skb = NULL; + skb = txq->tx_skb[tx]; + txq->tx_skb[tx] = NULL; BUG_ON(skb == NULL); pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE); - rc = mwl8k_remove_dma_header(skb); + mwl8k_remove_dma_header(skb); /* Mark descriptor as unused */ tx_desc->pkt_phys_addr = 0; tx_desc->pkt_len = 0; - if (txq->tx_skb[tx].clone) { - /* Replace with original skb - * before returning to stack - * as buffer has been cloned - */ - dev_kfree_skb(skb); - skb = txq->tx_skb[tx].clone; - txq->tx_skb[tx].clone = NULL; - } - - if (rc) { - /* Something has gone wrong here. - * Failed to remove DMA header. - * Print error message and drop packet. - */ - printk(KERN_ERR "%s: Error removing DMA header from " - "tx skb 0x%p.\n", priv->name, skb); - - dev_kfree_skb(skb); - continue; - } - info = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); if (MWL8K_TXD_SUCCESS(status)) @@ -1327,7 +1284,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) struct mwl8k_tx_desc *tx; struct mwl8k_dma_data *tr; struct mwl8k_vif *mwl8k_vif; - struct sk_buff *org_skb = skb; dma_addr_t dma; u16 qos = 0; bool qosframe = false, ampduframe = false; @@ -1338,21 +1294,12 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) txq = priv->txq + index; tx = txq->tx_desc_area + txq->tx_tail; - BUG_ON(txq->tx_skb[txq->tx_tail].skb != NULL); + BUG_ON(txq->tx_skb[txq->tx_tail] != NULL); /* - * Append HW DMA header to start of packet. Drop packet if - * there is not enough space or a failure to unshare/unclone - * the skb. + * Append HW DMA header to start of packet. */ - skb = mwl8k_add_dma_header(skb); - - if (skb == NULL) { - printk(KERN_DEBUG "%s: failed to prepend HW DMA " - "header, dropping TX frame.\n", priv->name); - dev_kfree_skb(org_skb); - return NETDEV_TX_OK; - } + mwl8k_add_dma_header(skb); tx_info = IEEE80211_SKB_CB(skb); mwl8k_vif = MWL8K_VIF(tx_info->control.vif); @@ -1380,8 +1327,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) printk(KERN_DEBUG "%s: failed to dma map skb, " "dropping TX frame.\n", priv->name); - if (org_skb != NULL) - dev_kfree_skb(org_skb); if (skb != NULL) dev_kfree_skb(skb); return NETDEV_TX_OK; @@ -1437,9 +1382,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) tx->pkt_phys_addr = cpu_to_le32(dma); tx->pkt_len = cpu_to_le16(skb->len); - txq->tx_skb[txq->tx_tail].skb = skb; - txq->tx_skb[txq->tx_tail].clone = - skb == org_skb ? NULL : org_skb; + txq->tx_skb[txq->tx_tail] = skb; spin_lock_bh(&priv->tx_lock); -- cgit v0.10.2 From d4b7057052236e81ab0788cc8df306dc02b0e7be Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 12:44:45 +0200 Subject: mwl8k: don't touch 'command done' interrupt during firmware load Since firmware load commands don't generate 'command done' interrupts like normal commands do, polling for command done interrupts just unnecessarily slows down the firmware load process. Removing this bit of code speeds up loading a typical firmware image from 840 msec to 180 msec. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 5aa8042..cc0aa80 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -411,7 +411,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) { void __iomem *regs = priv->regs; dma_addr_t dma_addr; - int rc; int loops; dma_addr = pci_map_single(priv->pdev, data, length, PCI_DMA_TODEVICE); @@ -425,7 +424,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) iowrite32(MWL8K_H2A_INT_DUMMY, regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); - rc = -ETIMEDOUT; loops = 1000; do { u32 int_code; @@ -433,7 +431,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) int_code = ioread32(regs + MWL8K_HIU_INT_CODE); if (int_code == MWL8K_INT_CODE_CMD_FINISHED) { iowrite32(0, regs + MWL8K_HIU_INT_CODE); - rc = 0; break; } @@ -442,26 +439,7 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) pci_unmap_single(priv->pdev, dma_addr, length, PCI_DMA_TODEVICE); - /* - * Clear 'command done' interrupt bit. - */ - loops = 1000; - do { - u32 status; - - status = ioread32(priv->regs + - MWL8K_HIU_A2H_INTERRUPT_STATUS); - if (status & MWL8K_A2H_INT_OPC_DONE) { - iowrite32(~MWL8K_A2H_INT_OPC_DONE, - priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - break; - } - - udelay(1); - } while (--loops); - - return rc; + return loops ? 0 : -ETIMEDOUT; } static int mwl8k_load_fw_image(struct mwl8k_priv *priv, -- cgit v0.10.2 From c3f967d301a76b7053d16817c34191964c457566 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 04:15:22 +0200 Subject: mwl8k: don't hardcode the number of transmit queues Use MWL8K_TX_QUEUES instead of a hardcoded "4" in a couple of places. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index cc0aa80..0281e70 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1080,17 +1080,17 @@ struct mwl8k_txq_info { }; static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, - struct mwl8k_txq_info txinfo[], - u32 num_queues) + struct mwl8k_txq_info *txinfo) { int count, desc, status; struct mwl8k_tx_queue *txq; struct mwl8k_tx_desc *tx_desc; int ndescs = 0; - memset(txinfo, 0, num_queues * sizeof(struct mwl8k_txq_info)); + memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info)); + spin_lock_bh(&priv->tx_lock); - for (count = 0; count < num_queues; count++) { + for (count = 0; count < MWL8K_TX_QUEUES; count++) { txq = priv->txq + count; txinfo[count].len = txq->tx_stats.len; txinfo[count].head = txq->tx_head; @@ -1135,7 +1135,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) spin_unlock_bh(&priv->tx_lock); if (count) { - struct mwl8k_txq_info txinfo[4]; + struct mwl8k_txq_info txinfo[MWL8K_TX_QUEUES]; int index; int newcount; @@ -1152,8 +1152,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) printk(KERN_ERR "%s(%u) TIMEDOUT:%ums Pend:%u-->%u\n", __func__, __LINE__, delay_ms, count, newcount); - mwl8k_scan_tx_ring(priv, txinfo, 4); - for (index = 0; index < 4; index++) + mwl8k_scan_tx_ring(priv, txinfo); + for (index = 0; index < MWL8K_TX_QUEUES; index++) printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u DRV:%u U:%u\n", index, -- cgit v0.10.2 From 361c55cfaddaa36f0997c5a96948ba5888bfb992 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 04:19:00 +0200 Subject: mwl8k: no need to hold ->tx_lock while setting the hardware interrupt mask Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 0281e70..177d92f 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2768,9 +2768,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) printk(KERN_ERR "%s() timed out\n", __func__); /* Disable interrupts */ - spin_lock_irq(&priv->tx_lock); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); free_irq(priv->pdev->irq, hw); /* Stop finalize join worker */ @@ -3457,9 +3455,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } /* Disable interrupts */ - spin_lock_irq(&priv->tx_lock); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); free_irq(priv->pdev->irq, hw); rc = ieee80211_register_hw(hw); @@ -3483,9 +3479,7 @@ err_stop_firmware: mwl8k_release_firmware(priv); err_free_irq: - spin_lock_irq(&priv->tx_lock); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); free_irq(priv->pdev->irq, hw); err_free_queues: -- cgit v0.10.2 From 7595d67a06466cc00e3aae1b86544278b57481ee Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 17 Aug 2009 23:59:40 +0200 Subject: mwl8k: implement idle mode Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 177d92f..65eefe8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2854,6 +2854,12 @@ static int mwl8k_config_wt(struct work_struct *wt) struct mwl8k_priv *priv = hw->priv; int rc = 0; + if (conf->flags & IEEE80211_CONF_IDLE) { + mwl8k_cmd_802_11_radio_disable(hw); + priv->current_channel = NULL; + goto mwl8k_config_exit; + } + if (mwl8k_cmd_802_11_radio_enable(hw)) { rc = -EINVAL; goto mwl8k_config_exit; -- cgit v0.10.2 From 23b339062f247e0be84eaabb15e17b403c4388b6 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 05:21:04 +0200 Subject: mwl8k: mwl8k_txq_xmit() rework Various mwl8k_txq_xmit changes: - Extract the QoS field before adding the DMA header. - Only write to tx->status once, and only after all the other descriptor fields have been set. - Do all tx state manipulation under the tx spinlock. - Remove the priv->inconfig check, as all transmit queues will be frozen during config cycles, so we won't ever be asked to transmit if a config cycle is running. - Remove some more dead code. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 65eefe8..88ba52e 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1257,46 +1257,60 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) { struct mwl8k_priv *priv = hw->priv; struct ieee80211_tx_info *tx_info; + struct mwl8k_vif *mwl8k_vif; struct ieee80211_hdr *wh; struct mwl8k_tx_queue *txq; struct mwl8k_tx_desc *tx; - struct mwl8k_dma_data *tr; - struct mwl8k_vif *mwl8k_vif; dma_addr_t dma; - u16 qos = 0; - bool qosframe = false, ampduframe = false; - bool mcframe = false, eapolframe = false; - bool amsduframe = false; - __le16 fc; + u32 txstatus; + u8 txdatarate; + u16 qos; - txq = priv->txq + index; - tx = txq->tx_desc_area + txq->tx_tail; - - BUG_ON(txq->tx_skb[txq->tx_tail] != NULL); + wh = (struct ieee80211_hdr *)skb->data; + if (ieee80211_is_data_qos(wh->frame_control)) + qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh))); + else + qos = 0; - /* - * Append HW DMA header to start of packet. - */ mwl8k_add_dma_header(skb); + wh = &((struct mwl8k_dma_data *)skb->data)->wh; tx_info = IEEE80211_SKB_CB(skb); mwl8k_vif = MWL8K_VIF(tx_info->control.vif); - tr = (struct mwl8k_dma_data *)skb->data; - wh = &tr->wh; - fc = wh->frame_control; - qosframe = ieee80211_is_data_qos(fc); - mcframe = is_multicast_ether_addr(wh->addr1); - ampduframe = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { u16 seqno = mwl8k_vif->seqno; + wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); wh->seq_ctrl |= cpu_to_le16(seqno << 4); mwl8k_vif->seqno = seqno++ % 4096; } - if (qosframe) - qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh))); + /* Setup firmware control bit fields for each frame type. */ + txstatus = 0; + txdatarate = 0; + if (ieee80211_is_mgmt(wh->frame_control) || + ieee80211_is_ctl(wh->frame_control)) { + txdatarate = 0; + qos = mwl8k_qos_setbit_eosp(qos); + /* Set Queue size to unspecified */ + qos = mwl8k_qos_setbit_qlen(qos, 0xff); + } else if (ieee80211_is_data(wh->frame_control)) { + txdatarate = 1; + if (is_multicast_ether_addr(wh->addr1)) + txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX; + + /* Send pkt in an aggregate if AMPDU frame. */ + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + qos = mwl8k_qos_setbit_ack(qos, + MWL8K_TXD_ACK_POLICY_BLOCKACK); + else + qos = mwl8k_qos_setbit_ack(qos, + MWL8K_TXD_ACK_POLICY_NORMAL); + + if (qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + qos = mwl8k_qos_setbit_amsdu(qos); + } dma = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); @@ -1304,95 +1318,40 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (pci_dma_mapping_error(priv->pdev, dma)) { printk(KERN_DEBUG "%s: failed to dma map skb, " "dropping TX frame.\n", priv->name); - - if (skb != NULL) - dev_kfree_skb(skb); + dev_kfree_skb(skb); return NETDEV_TX_OK; } - /* Set desc header, cpu bit order. */ - tx->status = 0; - tx->data_rate = 0; - tx->tx_priority = index; - tx->qos_control = 0; - tx->rate_info = 0; - tx->peer_id = mwl8k_vif->peer_id; - - amsduframe = !!(qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT); - - /* Setup firmware control bit fields for each frame type. */ - if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) { - tx->data_rate = 0; - qos = mwl8k_qos_setbit_eosp(qos); - /* Set Queue size to unspecified */ - qos = mwl8k_qos_setbit_qlen(qos, 0xff); - } else if (ieee80211_is_data(fc)) { - tx->data_rate = 1; - if (mcframe) - tx->status |= MWL8K_TXD_STATUS_MULTICAST_TX; + spin_lock_bh(&priv->tx_lock); - /* - * Tell firmware to not send EAPOL pkts in an - * aggregate. Verify against mac80211 tx path. If - * stack turns off AMPDU for an EAPOL frame this - * check will be removed. - */ - if (eapolframe) { - qos = mwl8k_qos_setbit_ack(qos, - MWL8K_TXD_ACK_POLICY_NORMAL); - } else { - /* Send pkt in an aggregate if AMPDU frame. */ - if (ampduframe) - qos = mwl8k_qos_setbit_ack(qos, - MWL8K_TXD_ACK_POLICY_BLOCKACK); - else - qos = mwl8k_qos_setbit_ack(qos, - MWL8K_TXD_ACK_POLICY_NORMAL); + txq = priv->txq + index; - if (amsduframe) - qos = mwl8k_qos_setbit_amsdu(qos); - } - } + BUG_ON(txq->tx_skb[txq->tx_tail] != NULL); + txq->tx_skb[txq->tx_tail] = skb; - /* Convert to little endian */ + tx = txq->tx_desc_area + txq->tx_tail; + tx->data_rate = txdatarate; + tx->tx_priority = index; tx->qos_control = cpu_to_le16(qos); - tx->status = cpu_to_le32(tx->status); tx->pkt_phys_addr = cpu_to_le32(dma); tx->pkt_len = cpu_to_le16(skb->len); - - txq->tx_skb[txq->tx_tail] = skb; - - spin_lock_bh(&priv->tx_lock); - - tx->status = cpu_to_le32(MWL8K_TXD_STATUS_OK | - MWL8K_TXD_STATUS_FW_OWNED); + tx->rate_info = 0; + tx->peer_id = mwl8k_vif->peer_id; wmb(); + tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); + + txq->tx_stats.count++; txq->tx_stats.len++; priv->pending_tx_pkts++; - txq->tx_stats.count++; - txq->tx_tail++; + txq->tx_tail++; if (txq->tx_tail == MWL8K_TX_DESCS) txq->tx_tail = 0; + if (txq->tx_head == txq->tx_tail) ieee80211_stop_queue(hw, index); - if (priv->inconfig) { - /* - * Silently queue packet when we are in the middle of - * a config cycle. Notify firmware only if we are - * waiting for TXQs to empty. If a packet is sent - * before .config() is complete, perhaps it is better - * to drop the packet, as the channel is being changed - * and the packet will end up on the wrong channel. - */ - printk(KERN_ERR "%s(): WARNING TX activity while " - "in config\n", __func__); - - if (priv->tx_wait != NULL) - mwl8k_tx_start(priv); - } else - mwl8k_tx_start(priv); + mwl8k_tx_start(priv); spin_unlock_bh(&priv->tx_lock); -- cgit v0.10.2 From 950d5b0191dc3e71017f336017f75f6189f39f08 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 01:48:41 +0200 Subject: mwl8k: mwl8k_queue_work() cleanup Delete most of the mwl8k_work_struct fields and options, since most of them are unused or never changed from their defaults: - We always use priv->config_wq, so delete the wqueue argument from mwl8k_queue_work(). - MWL8K_WQ_SPIN and MWL8K_WQ_POST_REQUEST are never used, as all callers sleep for request completion, so sleep unconditionally. - MWL8K_WQ_FREE_WORKSTRUCT is never used. - MWL8K_WQ_TX_WAIT_EMPTY is always set, so assume it unconditionally. - timeout_ms/txwait_attempts/tx_timeout_ms are never changed from their defaults, so just hardcode these in the workqueue worker. - step is never used. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 88ba52e..7bbdca4 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1113,7 +1113,7 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, return ndescs; } -static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) +static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; DECLARE_COMPLETION_ONSTACK(cmd_wait); @@ -1140,7 +1140,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) int newcount; timeout = wait_for_completion_timeout(&cmd_wait, - msecs_to_jiffies(delay_ms)); + msecs_to_jiffies(1000)); if (timeout) return 0; @@ -1149,8 +1149,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) newcount = mwl8k_txq_busy(priv); spin_unlock_bh(&priv->tx_lock); - printk(KERN_ERR "%s(%u) TIMEDOUT:%ums Pend:%u-->%u\n", - __func__, __LINE__, delay_ms, count, newcount); + printk(KERN_ERR "%s(%u) TIMEDOUT:1000ms Pend:%u-->%u\n", + __func__, __LINE__, count, newcount); mwl8k_scan_tx_ring(priv, txinfo); for (index = 0; index < MWL8K_TX_QUEUES; index++) @@ -2389,84 +2389,15 @@ struct mwl8k_work_struct { /* Result code. */ int rc; - - /* - * Optional field. Refer to explanation of MWL8K_WQ_XXX_XXX - * flags for explanation. Defaults to MWL8K_WQ_DEFAULT_OPTIONS. - */ - u32 options; - - /* Optional field. Defaults to MWL8K_CONFIG_TIMEOUT_MS. */ - unsigned long timeout_ms; - - /* Optional field. Defaults to MWL8K_WQ_TXWAIT_ATTEMPTS. */ - u32 txwait_attempts; - - /* Optional field. Defaults to MWL8K_TXWAIT_MS. */ - u32 tx_timeout_ms; - u32 step; }; -/* Flags controlling behavior of config queue requests */ - -/* Caller spins while waiting for completion. */ -#define MWL8K_WQ_SPIN 0x00000001 - -/* Wait for TX queues to empty before proceeding with configuration. */ -#define MWL8K_WQ_TX_WAIT_EMPTY 0x00000002 - -/* Queue request and return immediately. */ -#define MWL8K_WQ_POST_REQUEST 0x00000004 - -/* - * Caller sleeps and waits for task complete notification. - * Do not use in atomic context. - */ -#define MWL8K_WQ_SLEEP 0x00000008 - -/* Free work struct when task is done. */ -#define MWL8K_WQ_FREE_WORKSTRUCT 0x00000010 - -/* - * Config request is queued and returns to caller imediately. Use - * this in atomic context. Work struct is freed by mwl8k_queue_work() - * when this flag is set. - */ -#define MWL8K_WQ_QUEUE_ONLY (MWL8K_WQ_POST_REQUEST | \ - MWL8K_WQ_FREE_WORKSTRUCT) - -/* Default work queue behavior is to sleep and wait for tx completion. */ -#define MWL8K_WQ_DEFAULT_OPTIONS (MWL8K_WQ_SLEEP | MWL8K_WQ_TX_WAIT_EMPTY) - -/* - * Default config request timeout. Add adjustments to make sure the - * config thread waits long enough for both tx wait and cmd wait before - * timing out. - */ - -/* Time to wait for all TXQs to drain. TX Doorbell is pressed each time. */ -#define MWL8K_TXWAIT_TIMEOUT_MS 1000 - -/* Default number of TX wait attempts. */ -#define MWL8K_WQ_TXWAIT_ATTEMPTS 4 - -/* Total time to wait for TXQ to drain. */ -#define MWL8K_TXWAIT_MS (MWL8K_TXWAIT_TIMEOUT_MS * \ - MWL8K_WQ_TXWAIT_ATTEMPTS) - -/* Scheduling slop. */ -#define MWL8K_OS_SCHEDULE_OVERHEAD_MS 200 - -#define MWL8K_CONFIG_TIMEOUT_MS (MWL8K_CMD_TIMEOUT_MS + \ - MWL8K_TXWAIT_MS + \ - MWL8K_OS_SCHEDULE_OVERHEAD_MS) - static void mwl8k_config_thread(struct work_struct *wt) { struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt; struct ieee80211_hw *hw = worker->hw; struct mwl8k_priv *priv = hw->priv; int rc = 0; + int iter; spin_lock_irq(&priv->tx_lock); priv->inconfig = true; @@ -2479,44 +2410,16 @@ static void mwl8k_config_thread(struct work_struct *wt) * reconfiguration. This avoids interrupting any in-flight * DMA transfers to the hardware. */ - if (worker->options & MWL8K_WQ_TX_WAIT_EMPTY) { - u32 timeout; - u32 time_remaining; - u32 iter; - u32 tx_wait_attempts = worker->txwait_attempts; - - time_remaining = worker->tx_timeout_ms; - if (!tx_wait_attempts) - tx_wait_attempts = 1; - - timeout = worker->tx_timeout_ms/tx_wait_attempts; - if (!timeout) - timeout = 1; - - iter = tx_wait_attempts; - do { - int wait_time; - - if (time_remaining > timeout) { - time_remaining -= timeout; - wait_time = timeout; - } else - wait_time = time_remaining; - - if (!wait_time) - wait_time = 1; - - rc = mwl8k_tx_wait_empty(hw, wait_time); - if (rc) - printk(KERN_ERR "%s() txwait timeout=%ums " - "Retry:%u/%u\n", __func__, timeout, - tx_wait_attempts - iter + 1, - tx_wait_attempts); + iter = 4; + do { + rc = mwl8k_tx_wait_empty(hw); + if (rc) + printk(KERN_ERR "%s() txwait timeout=1000ms " + "Retry:%u/%u\n", __func__, 4 - iter + 1, 4); + } while (rc && --iter); - } while (rc && --iter); + rc = iter ? 0 : -ETIMEDOUT; - rc = iter ? 0 : -ETIMEDOUT; - } if (!rc) rc = worker->wfunc(wt); @@ -2525,65 +2428,39 @@ static void mwl8k_config_thread(struct work_struct *wt) if (priv->pending_tx_pkts && priv->radio_on) mwl8k_tx_start(priv); spin_unlock_irq(&priv->tx_lock); + ieee80211_wake_queues(hw); worker->rc = rc; - if (worker->options & MWL8K_WQ_SLEEP) - complete(worker->cmd_wait); - - if (worker->options & MWL8K_WQ_FREE_WORKSTRUCT) - kfree(wt); + complete(worker->cmd_wait); } static int mwl8k_queue_work(struct ieee80211_hw *hw, struct mwl8k_work_struct *worker, - struct workqueue_struct *wqueue, int (*wfunc)(struct work_struct *w)) { + struct mwl8k_priv *priv = hw->priv; unsigned long timeout = 0; int rc = 0; DECLARE_COMPLETION_ONSTACK(cmd_wait); - if (!worker->timeout_ms) - worker->timeout_ms = MWL8K_CONFIG_TIMEOUT_MS; - - if (!worker->options) - worker->options = MWL8K_WQ_DEFAULT_OPTIONS; - - if (!worker->txwait_attempts) - worker->txwait_attempts = MWL8K_WQ_TXWAIT_ATTEMPTS; - - if (!worker->tx_timeout_ms) - worker->tx_timeout_ms = MWL8K_TXWAIT_MS; - worker->hw = hw; worker->cmd_wait = &cmd_wait; worker->rc = 1; worker->wfunc = wfunc; INIT_WORK(&worker->wt, mwl8k_config_thread); - queue_work(wqueue, &worker->wt); + queue_work(priv->config_wq, &worker->wt); - if (worker->options & MWL8K_WQ_POST_REQUEST) { - rc = 0; - } else { - if (worker->options & MWL8K_WQ_SPIN) { - timeout = worker->timeout_ms; - while (timeout && (worker->rc > 0)) { - mdelay(1); - timeout--; - } - } else if (worker->options & MWL8K_WQ_SLEEP) - timeout = wait_for_completion_timeout(&cmd_wait, - msecs_to_jiffies(worker->timeout_ms)); + timeout = wait_for_completion_timeout(&cmd_wait, + msecs_to_jiffies(10000)); - if (timeout) - rc = worker->rc; - else { - cancel_work_sync(&worker->wt); - rc = -ETIMEDOUT; - } + if (timeout) + rc = worker->rc; + else { + cancel_work_sync(&worker->wt); + rc = -ETIMEDOUT; } return rc; @@ -2669,8 +2546,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) goto mwl8k_start_disable_irq; } - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_start_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_start_wt); kfree(worker); if (!rc) return rc; @@ -2720,8 +2596,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) if (worker == NULL) return; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_stop_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_stop_wt); kfree(worker); if (rc == -ETIMEDOUT) printk(KERN_ERR "%s() timed out\n", __func__); @@ -2849,15 +2724,14 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) { int rc = 0; struct mwl8k_config_worker *worker; - struct mwl8k_priv *priv = hw->priv; worker = kzalloc(sizeof(*worker), GFP_KERNEL); if (worker == NULL) return -ENOMEM; worker->changed = changed; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_config_wt); + + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_config_wt); if (rc == -ETIMEDOUT) { printk(KERN_ERR "%s() timed out.\n", __func__); rc = -EINVAL; @@ -2950,7 +2824,6 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { struct mwl8k_bss_info_changed_worker *worker; - struct mwl8k_priv *priv = hw->priv; struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); int rc; @@ -2967,9 +2840,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, worker->vif = vif; worker->info = info; worker->changed = changed; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, - mwl8k_bss_info_changed_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_bss_info_changed_wt); kfree(worker); if (rc == -ETIMEDOUT) printk(KERN_ERR "%s() timed out\n", __func__); @@ -3028,7 +2899,6 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { - struct mwl8k_priv *priv = hw->priv; struct mwl8k_configure_filter_worker *worker; /* Clear unsupported feature flags */ @@ -3045,8 +2915,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, worker->total_flags = *total_flags; worker->multicast_adr_cmd = (void *)(unsigned long)multicast; - mwl8k_queue_work(hw, &worker->header, priv->config_wq, - mwl8k_configure_filter_wt); + mwl8k_queue_work(hw, &worker->header, mwl8k_configure_filter_wt); } struct mwl8k_set_rts_threshold_worker { @@ -3072,7 +2941,6 @@ static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { int rc; struct mwl8k_set_rts_threshold_worker *worker; - struct mwl8k_priv *priv = hw->priv; worker = kzalloc(sizeof(*worker), GFP_KERNEL); if (worker == NULL) @@ -3080,9 +2948,7 @@ static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) worker->value = value; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, - mwl8k_set_rts_threshold_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_set_rts_threshold_wt); kfree(worker); if (rc == -ETIMEDOUT) { @@ -3130,7 +2996,6 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, { int rc; struct mwl8k_conf_tx_worker *worker; - struct mwl8k_priv *priv = hw->priv; worker = kzalloc(sizeof(*worker), GFP_KERNEL); if (worker == NULL) @@ -3138,8 +3003,7 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, worker->queue = queue; worker->params = params; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_conf_tx_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_conf_tx_wt); kfree(worker); if (rc == -ETIMEDOUT) { printk(KERN_ERR "%s() timed out\n", __func__); @@ -3183,15 +3047,13 @@ static int mwl8k_get_stats(struct ieee80211_hw *hw, { int rc; struct mwl8k_get_stats_worker *worker; - struct mwl8k_priv *priv = hw->priv; worker = kzalloc(sizeof(*worker), GFP_KERNEL); if (worker == NULL) return -ENOMEM; worker->stats = stats; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_get_stats_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_get_stats_wt); kfree(worker); if (rc == -ETIMEDOUT) { -- cgit v0.10.2 From 618952a7b19b796fce98364fb26551cbe3e16a75 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 03:18:01 +0200 Subject: mwl8k: fix firmware command serialisation The current mwl8k_priv->fw_lock spinlock doesn't actually protect against multiple commands being submitted at once, as it is not kept held over the entire firmware command submission. And since waiting for command completion sleeps, we can't use a spinlock anyway. To fix mwl8k firmware command serialisation properly, we have the following requirements: - Some commands require that the packet transmit path is idle when the command is issued. (For simplicity, we'll just quiesce the transmit path for every command.) - There are certain sequences of commands that need to be issued to the hardware sequentially, with no other intervening commands. This leads to an implementation of a "firmware lock" as a mutex that can be taken recursively, and which is taken by both the low-level command submission function (mwl8k_post_cmd) as well as any users of that function that require issuing of an atomic sequence of commands, and quiesces the transmit path whenever it's taken. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 7bbdca4..93b9268 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -139,13 +139,18 @@ struct mwl8k_priv { struct pci_dev *pdev; u8 name[16]; - /* firmware access lock */ - spinlock_t fw_lock; /* firmware files and meta data */ struct mwl8k_firmware fw; u32 part_num; + /* firmware access */ + struct mutex fw_mutex; + struct task_struct *fw_mutex_owner; + int fw_mutex_depth; + struct completion *tx_wait; + struct completion *hostcmd_wait; + /* lock held over TX and TX reap */ spinlock_t tx_lock; @@ -179,9 +184,6 @@ struct mwl8k_priv { bool radio_short_preamble; bool wmm_enabled; - /* Set if PHY config is in progress */ - bool inconfig; - /* XXX need to convert this to handle multiple interfaces */ bool capture_beacon; u8 capture_bssid[ETH_ALEN]; @@ -200,8 +202,6 @@ struct mwl8k_priv { /* Work thread to serialize configuration requests */ struct workqueue_struct *config_wq; - struct completion *hostcmd_wait; - struct completion *tx_wait; }; /* Per interface specific private data */ @@ -1113,6 +1113,9 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, return ndescs; } +/* + * Must be called with hw->fw_mutex held and tx queues stopped. + */ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; @@ -1122,9 +1125,6 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) might_sleep(); - if (priv->tx_wait != NULL) - printk(KERN_ERR "WARNING Previous TXWaitEmpty instance\n"); - spin_lock_bh(&priv->tx_lock); count = mwl8k_txq_busy(priv); if (count) { @@ -1140,7 +1140,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) int newcount; timeout = wait_for_completion_timeout(&cmd_wait, - msecs_to_jiffies(1000)); + msecs_to_jiffies(5000)); if (timeout) return 0; @@ -1149,7 +1149,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) newcount = mwl8k_txq_busy(priv); spin_unlock_bh(&priv->tx_lock); - printk(KERN_ERR "%s(%u) TIMEDOUT:1000ms Pend:%u-->%u\n", + printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n", __func__, __LINE__, count, newcount); mwl8k_scan_tx_ring(priv, txinfo); @@ -1228,10 +1228,10 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) ieee80211_tx_status_irqsafe(hw, skb); - wake = !priv->inconfig && priv->radio_on; + wake = 1; } - if (wake) + if (wake && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) ieee80211_wake_queue(hw, index); } @@ -1360,6 +1360,60 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) /* + * Firmware access. + * + * We have the following requirements for issuing firmware commands: + * - Some commands require that the packet transmit path is idle when + * the command is issued. (For simplicity, we'll just quiesce the + * transmit path for every command.) + * - There are certain sequences of commands that need to be issued to + * the hardware sequentially, with no other intervening commands. + * + * This leads to an implementation of a "firmware lock" as a mutex that + * can be taken recursively, and which is taken by both the low-level + * command submission function (mwl8k_post_cmd) as well as any users of + * that function that require issuing of an atomic sequence of commands, + * and quiesces the transmit path whenever it's taken. + */ +static int mwl8k_fw_lock(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + + if (priv->fw_mutex_owner != current) { + int rc; + + mutex_lock(&priv->fw_mutex); + ieee80211_stop_queues(hw); + + rc = mwl8k_tx_wait_empty(hw); + if (rc) { + ieee80211_wake_queues(hw); + mutex_unlock(&priv->fw_mutex); + + return rc; + } + + priv->fw_mutex_owner = current; + } + + priv->fw_mutex_depth++; + + return 0; +} + +static void mwl8k_fw_unlock(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + + if (!--priv->fw_mutex_depth) { + ieee80211_wake_queues(hw); + priv->fw_mutex_owner = NULL; + mutex_unlock(&priv->fw_mutex); + } +} + + +/* * Command processing. */ @@ -1384,28 +1438,28 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) if (pci_dma_mapping_error(priv->pdev, dma_addr)) return -ENOMEM; - if (priv->hostcmd_wait != NULL) - printk(KERN_ERR "WARNING host command in progress\n"); + rc = mwl8k_fw_lock(hw); + if (rc) + return rc; - spin_lock_irq(&priv->fw_lock); priv->hostcmd_wait = &cmd_wait; iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); iowrite32(MWL8K_H2A_INT_DOORBELL, regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); iowrite32(MWL8K_H2A_INT_DUMMY, regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); - spin_unlock_irq(&priv->fw_lock); timeout = wait_for_completion_timeout(&cmd_wait, msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS)); + priv->hostcmd_wait = NULL; + + mwl8k_fw_unlock(hw); + pci_unmap_single(priv->pdev, dma_addr, dma_size, PCI_DMA_BIDIRECTIONAL); if (!timeout) { - spin_lock_irq(&priv->fw_lock); - priv->hostcmd_wait = NULL; - spin_unlock_irq(&priv->fw_lock); printk(KERN_ERR "%s: Command %s timeout after %u ms\n", priv->name, mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), @@ -2336,17 +2390,14 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) } if (status & MWL8K_A2H_INT_OPC_DONE) { - if (priv->hostcmd_wait != NULL) { + if (priv->hostcmd_wait != NULL) complete(priv->hostcmd_wait); - priv->hostcmd_wait = NULL; - } } if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { - if (!priv->inconfig && - priv->radio_on && - mwl8k_txq_busy(priv)) - mwl8k_tx_start(priv); + if (!mutex_is_locked(&priv->fw_mutex) && + priv->radio_on && mwl8k_txq_busy(priv)) + mwl8k_tx_start(priv); } return IRQ_HANDLED; @@ -2395,41 +2446,13 @@ static void mwl8k_config_thread(struct work_struct *wt) { struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt; struct ieee80211_hw *hw = worker->hw; - struct mwl8k_priv *priv = hw->priv; int rc = 0; - int iter; - spin_lock_irq(&priv->tx_lock); - priv->inconfig = true; - spin_unlock_irq(&priv->tx_lock); - - ieee80211_stop_queues(hw); - - /* - * Wait for host queues to drain before doing PHY - * reconfiguration. This avoids interrupting any in-flight - * DMA transfers to the hardware. - */ - iter = 4; - do { - rc = mwl8k_tx_wait_empty(hw); - if (rc) - printk(KERN_ERR "%s() txwait timeout=1000ms " - "Retry:%u/%u\n", __func__, 4 - iter + 1, 4); - } while (rc && --iter); - - rc = iter ? 0 : -ETIMEDOUT; - - if (!rc) + rc = mwl8k_fw_lock(hw); + if (!rc) { rc = worker->wfunc(wt); - - spin_lock_irq(&priv->tx_lock); - priv->inconfig = false; - if (priv->pending_tx_pkts && priv->radio_on) - mwl8k_tx_start(priv); - spin_unlock_irq(&priv->tx_lock); - - ieee80211_wake_queues(hw); + mwl8k_fw_unlock(hw); + } worker->rc = rc; complete(worker->cmd_wait); @@ -3145,15 +3168,10 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv = hw->priv; priv->hw = hw; priv->pdev = pdev; - priv->hostcmd_wait = NULL; - priv->tx_wait = NULL; - priv->inconfig = false; priv->wmm_enabled = false; priv->pending_tx_pkts = 0; strncpy(priv->name, MWL8K_NAME, sizeof(priv->name)); - spin_lock_init(&priv->fw_lock); - SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); @@ -3219,6 +3237,12 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_iounmap; rxq_refill(hw, 0, INT_MAX); + mutex_init(&priv->fw_mutex); + priv->fw_mutex_owner = NULL; + priv->fw_mutex_depth = 0; + priv->tx_wait = NULL; + priv->hostcmd_wait = NULL; + spin_lock_init(&priv->tx_lock); for (i = 0; i < MWL8K_TX_QUEUES; i++) { -- cgit v0.10.2 From 2ec610cb6d57032cdab89781e37ed3e442c73367 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:11:37 +0200 Subject: mwl8k: get rid of mwl8k_start() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 93b9268..7b7007d 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2489,104 +2489,53 @@ static int mwl8k_queue_work(struct ieee80211_hw *hw, return rc; } -struct mwl8k_start_worker { - struct mwl8k_work_struct header; -}; - -static int mwl8k_start_wt(struct work_struct *wt) -{ - struct mwl8k_start_worker *worker = (struct mwl8k_start_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - struct mwl8k_priv *priv = hw->priv; - int rc = 0; - - if (priv->vif != NULL) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Turn on radio */ - if (mwl8k_cmd_802_11_radio_enable(hw)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Purge TX/RX HW queues */ - if (mwl8k_cmd_set_pre_scan(hw)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - if (mwl8k_cmd_set_post_scan(hw, "\x00\x00\x00\x00\x00\x00")) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Enable firmware rate adaptation */ - if (mwl8k_cmd_setrateadaptmode(hw, 0)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Disable WMM. WMM gets enabled when stack sends WMM parms */ - if (mwl8k_set_wmm(hw, 0)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Disable sniffer mode */ - if (mwl8k_enable_sniffer(hw, 0)) - rc = -EIO; - -mwl8k_start_exit: - return rc; -} - static int mwl8k_start(struct ieee80211_hw *hw) { - struct mwl8k_start_worker *worker; struct mwl8k_priv *priv = hw->priv; int rc; - /* Enable tx reclaim tasklet */ - tasklet_enable(&priv->tx_reclaim_task); - rc = request_irq(priv->pdev->irq, &mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { printk(KERN_ERR "%s: failed to register IRQ handler\n", priv->name); - rc = -EIO; - goto mwl8k_start_disable_tasklet; + return -EIO; } + /* Enable tx reclaim tasklet */ + tasklet_enable(&priv->tx_reclaim_task); + /* Enable interrupts */ iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) { - rc = -ENOMEM; - goto mwl8k_start_disable_irq; - } + rc = mwl8k_fw_lock(hw); + if (!rc) { + rc = mwl8k_cmd_802_11_radio_enable(hw); - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_start_wt); - kfree(worker); - if (!rc) - return rc; + if (!rc) + rc = mwl8k_cmd_set_pre_scan(hw); - if (rc == -ETIMEDOUT) - printk(KERN_ERR "%s() timed out\n", __func__); + if (!rc) + rc = mwl8k_cmd_set_post_scan(hw, + "\x00\x00\x00\x00\x00\x00"); - rc = -EIO; + if (!rc) + rc = mwl8k_cmd_setrateadaptmode(hw, 0); -mwl8k_start_disable_irq: - spin_lock_irq(&priv->tx_lock); - iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); - free_irq(priv->pdev->irq, hw); + if (!rc) + rc = mwl8k_set_wmm(hw, 0); -mwl8k_start_disable_tasklet: - tasklet_disable(&priv->tx_reclaim_task); + if (!rc) + rc = mwl8k_enable_sniffer(hw, 0); + + mwl8k_fw_unlock(hw); + } + + if (rc) { + iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + free_irq(priv->pdev->irq, hw); + tasklet_disable(&priv->tx_reclaim_task); + } return rc; } -- cgit v0.10.2 From d3cea0b85a31a98630c6fcf7373d486db9612a10 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:15:49 +0200 Subject: mwl8k: get rid of mwl8k_stop() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 7b7007d..b88b1e0 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2540,39 +2540,15 @@ static int mwl8k_start(struct ieee80211_hw *hw) return rc; } -struct mwl8k_stop_worker { - struct mwl8k_work_struct header; -}; - -static int mwl8k_stop_wt(struct work_struct *wt) -{ - struct mwl8k_stop_worker *worker = (struct mwl8k_stop_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - - return mwl8k_cmd_802_11_radio_disable(hw); -} - static void mwl8k_stop(struct ieee80211_hw *hw) { - int rc; - struct mwl8k_stop_worker *worker; struct mwl8k_priv *priv = hw->priv; int i; - if (priv->vif != NULL) - return; + mwl8k_cmd_802_11_radio_disable(hw); ieee80211_stop_queues(hw); - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return; - - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_stop_wt); - kfree(worker); - if (rc == -ETIMEDOUT) - printk(KERN_ERR "%s() timed out\n", __func__); - /* Disable interrupts */ iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); -- cgit v0.10.2 From ee03a93241eb954d669fb795b4e5c0eec92eef22 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:19:37 +0200 Subject: mwl8k: get rid of mwl8k_config() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b88b1e0..77e280a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2622,77 +2622,45 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, priv->vif = NULL; } -struct mwl8k_config_worker { - struct mwl8k_work_struct header; - u32 changed; -}; - -static int mwl8k_config_wt(struct work_struct *wt) +static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) { - struct mwl8k_config_worker *worker = - (struct mwl8k_config_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; struct ieee80211_conf *conf = &hw->conf; struct mwl8k_priv *priv = hw->priv; - int rc = 0; + int rc; if (conf->flags & IEEE80211_CONF_IDLE) { mwl8k_cmd_802_11_radio_disable(hw); priv->current_channel = NULL; - goto mwl8k_config_exit; + return 0; } - if (mwl8k_cmd_802_11_radio_enable(hw)) { - rc = -EINVAL; - goto mwl8k_config_exit; - } + rc = mwl8k_fw_lock(hw); + if (rc) + return rc; - priv->current_channel = conf->channel; + rc = mwl8k_cmd_802_11_radio_enable(hw); + if (rc) + goto out; - if (mwl8k_cmd_set_rf_channel(hw, conf->channel)) { - rc = -EINVAL; - goto mwl8k_config_exit; - } + rc = mwl8k_cmd_set_rf_channel(hw, conf->channel); + if (rc) + goto out; + + priv->current_channel = conf->channel; if (conf->power_level > 18) conf->power_level = 18; - if (mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level)) { - rc = -EINVAL; - goto mwl8k_config_exit; - } + rc = mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level); + if (rc) + goto out; if (mwl8k_cmd_mimo_config(hw, 0x7, 0x7)) rc = -EINVAL; -mwl8k_config_exit: - return rc; -} - -static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) -{ - int rc = 0; - struct mwl8k_config_worker *worker; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; - - worker->changed = changed; - - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_config_wt); - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out.\n", __func__); - rc = -EINVAL; - } - - kfree(worker); +out: + mwl8k_fw_unlock(hw); - /* - * mac80211 will crash on anything other than -EINVAL on - * error. Looks like wireless extensions which calls mac80211 - * may be the actual culprit... - */ - return rc ? -EINVAL : 0; + return rc; } struct mwl8k_bss_info_changed_worker { -- cgit v0.10.2 From 3a980d0a505161b99fc936827cb28ec8eb853284 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:21:46 +0200 Subject: mwl8k: get rid of mwl8k_bss_info_changed() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 77e280a..d5a46a9 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2663,58 +2663,62 @@ out: return rc; } -struct mwl8k_bss_info_changed_worker { - struct mwl8k_work_struct header; - struct ieee80211_vif *vif; - struct ieee80211_bss_conf *info; - u32 changed; -}; - -static int mwl8k_bss_info_changed_wt(struct work_struct *wt) +static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) { - struct mwl8k_bss_info_changed_worker *worker = - (struct mwl8k_bss_info_changed_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - struct ieee80211_vif *vif = worker->vif; - struct ieee80211_bss_conf *info = worker->info; - u32 changed; - int rc; - struct mwl8k_priv *priv = hw->priv; struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); + int rc; + + if (changed & BSS_CHANGED_BSSID) + memcpy(mwl8k_vif->bssid, info->bssid, ETH_ALEN); + + if ((changed & BSS_CHANGED_ASSOC) == 0) + return; - changed = worker->changed; priv->capture_beacon = false; + rc = mwl8k_fw_lock(hw); + if (!rc) + return; + if (info->assoc) { memcpy(&mwl8k_vif->bss_info, info, sizeof(struct ieee80211_bss_conf)); /* Install rates */ - if (mwl8k_update_rateset(hw, vif)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_update_rateset(hw, vif); + if (rc) + goto out; /* Turn on rate adaptation */ - if (mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE, - MWL8K_UCAST_RATE, NULL)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE, + MWL8K_UCAST_RATE, NULL); + if (rc) + goto out; /* Set radio preamble */ - if (mwl8k_set_radio_preamble(hw, info->use_short_preamble)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_set_radio_preamble(hw, info->use_short_preamble); + if (rc) + goto out; /* Set slot time */ - if (mwl8k_cmd_set_slot(hw, info->use_short_slot)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_set_slot(hw, info->use_short_slot); + if (rc) + goto out; /* Update peer rate info */ - if (mwl8k_cmd_update_sta_db(hw, vif, - MWL8K_STA_DB_MODIFY_ENTRY)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_update_sta_db(hw, vif, + MWL8K_STA_DB_MODIFY_ENTRY); + if (rc) + goto out; /* Set AID */ - if (mwl8k_cmd_set_aid(hw, vif)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_set_aid(hw, vif); + if (rc) + goto out; /* * Finalize the join. Tell rx handler to process @@ -2723,43 +2727,14 @@ static int mwl8k_bss_info_changed_wt(struct work_struct *wt) memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN); priv->capture_beacon = true; } else { - mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY); + rc = mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY); memset(&mwl8k_vif->bss_info, 0, sizeof(struct ieee80211_bss_conf)); memset(mwl8k_vif->bssid, 0, ETH_ALEN); } -mwl8k_bss_info_changed_exit: - rc = 0; - return rc; -} - -static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u32 changed) -{ - struct mwl8k_bss_info_changed_worker *worker; - struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); - int rc; - - if (changed & BSS_CHANGED_BSSID) - memcpy(mv_vif->bssid, info->bssid, ETH_ALEN); - - if ((changed & BSS_CHANGED_ASSOC) == 0) - return; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return; - - worker->vif = vif; - worker->info = info; - worker->changed = changed; - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_bss_info_changed_wt); - kfree(worker); - if (rc == -ETIMEDOUT) - printk(KERN_ERR "%s() timed out\n", __func__); +out: + mwl8k_fw_unlock(hw); } static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, -- cgit v0.10.2 From 733d3067d3fb168fbbd008cb0ebf5ad2027030f3 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:24:15 +0200 Subject: mwl8k: get rid of mwl8k_set_rts_threshold() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index d5a46a9..3129c57 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1970,7 +1970,7 @@ struct mwl8k_cmd_rts_threshold { } __attribute__((packed)); static int mwl8k_rts_threshold(struct ieee80211_hw *hw, - u16 action, u16 *threshold) + u16 action, u16 threshold) { struct mwl8k_cmd_rts_threshold *cmd; int rc; @@ -1982,7 +1982,7 @@ static int mwl8k_rts_threshold(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(action); - cmd->threshold = cpu_to_le16(*threshold); + cmd->threshold = cpu_to_le16(threshold); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2809,45 +2809,9 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, mwl8k_queue_work(hw, &worker->header, mwl8k_configure_filter_wt); } -struct mwl8k_set_rts_threshold_worker { - struct mwl8k_work_struct header; - u32 value; -}; - -static int mwl8k_set_rts_threshold_wt(struct work_struct *wt) -{ - struct mwl8k_set_rts_threshold_worker *worker = - (struct mwl8k_set_rts_threshold_worker *)wt; - - struct ieee80211_hw *hw = worker->header.hw; - u16 threshold = (u16)(worker->value); - int rc; - - rc = mwl8k_rts_threshold(hw, MWL8K_CMD_SET, &threshold); - - return rc; -} - static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - int rc; - struct mwl8k_set_rts_threshold_worker *worker; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; - - worker->value = value; - - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_set_rts_threshold_wt); - kfree(worker); - - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out\n", __func__); - rc = -EINVAL; - } - - return rc; + return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value); } struct mwl8k_conf_tx_worker { -- cgit v0.10.2 From 3e4f542cfbf5a60f2295b2de9a31bdd14beb7b4a Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:25:59 +0200 Subject: mwl8k: get rid of mwl8k_conf_tx() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 3129c57..5ce2d36 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2814,56 +2814,27 @@ static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value); } -struct mwl8k_conf_tx_worker { - struct mwl8k_work_struct header; - u16 queue; - const struct ieee80211_tx_queue_params *params; -}; - -static int mwl8k_conf_tx_wt(struct work_struct *wt) -{ - struct mwl8k_conf_tx_worker *worker = - (struct mwl8k_conf_tx_worker *)wt; - - struct ieee80211_hw *hw = worker->header.hw; - u16 queue = worker->queue; - const struct ieee80211_tx_queue_params *params = worker->params; - - struct mwl8k_priv *priv = hw->priv; - int rc = 0; - - if (!priv->wmm_enabled) { - if (mwl8k_set_wmm(hw, 1)) { - rc = -EINVAL; - goto mwl8k_conf_tx_exit; - } - } - - if (mwl8k_set_edca_params(hw, GET_TXQ(queue), params->cw_min, - params->cw_max, params->aifs, params->txop)) - rc = -EINVAL; -mwl8k_conf_tx_exit: - return rc; -} - static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { + struct mwl8k_priv *priv = hw->priv; int rc; - struct mwl8k_conf_tx_worker *worker; - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; + rc = mwl8k_fw_lock(hw); + if (!rc) { + if (!priv->wmm_enabled) + rc = mwl8k_set_wmm(hw, 1); - worker->queue = queue; - worker->params = params; - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_conf_tx_wt); - kfree(worker); - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out\n", __func__); - rc = -EINVAL; + if (!rc) + rc = mwl8k_set_edca_params(hw, queue, + params->cw_min, + params->cw_max, + params->aifs, + params->txop); + + mwl8k_fw_unlock(hw); } + return rc; } -- cgit v0.10.2 From 954ef509cc7d795ccd69fa2e01539297e9a003a0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:26:27 +0200 Subject: mwl8k: get rid of mwl8k_get_stats() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 5ce2d36..29712bd 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2852,42 +2852,14 @@ static int mwl8k_get_tx_stats(struct ieee80211_hw *hw, sizeof(struct ieee80211_tx_queue_stats)); } spin_unlock_bh(&priv->tx_lock); - return 0; -} - -struct mwl8k_get_stats_worker { - struct mwl8k_work_struct header; - struct ieee80211_low_level_stats *stats; -}; -static int mwl8k_get_stats_wt(struct work_struct *wt) -{ - struct mwl8k_get_stats_worker *worker = - (struct mwl8k_get_stats_worker *)wt; - - return mwl8k_cmd_802_11_get_stat(worker->header.hw, worker->stats); + return 0; } static int mwl8k_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { - int rc; - struct mwl8k_get_stats_worker *worker; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; - - worker->stats = stats; - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_get_stats_wt); - - kfree(worker); - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out\n", __func__); - rc = -EINVAL; - } - - return rc; + return mwl8k_cmd_802_11_get_stat(hw, stats); } static const struct ieee80211_ops mwl8k_ops = { -- cgit v0.10.2 From e6935ea10485f34b82d16f8dff9aa2bdf32ab4bf Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 04:06:20 +0200 Subject: mwl8k: get rid of mwl8k_configure_filter() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 29712bd..43e5dd1 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2747,26 +2747,23 @@ static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, return (unsigned long)cmd; } -struct mwl8k_configure_filter_worker { - struct mwl8k_work_struct header; - unsigned int changed_flags; - unsigned int total_flags; +static void mwl8k_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_pkt *multicast_adr_cmd; -}; -#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC + /* Clear unsupported feature flags */ + *total_flags &= FIF_BCN_PRBRESP_PROMISC; -static int mwl8k_configure_filter_wt(struct work_struct *wt) -{ - struct mwl8k_configure_filter_worker *worker = - (struct mwl8k_configure_filter_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - struct mwl8k_priv *priv = hw->priv; - int rc = 0; + if (mwl8k_fw_lock(hw)) + return; - if (worker->changed_flags & FIF_BCN_PRBRESP_PROMISC) { - if (worker->total_flags & FIF_BCN_PRBRESP_PROMISC) - rc = mwl8k_cmd_set_pre_scan(hw); + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + mwl8k_cmd_set_pre_scan(hw); else { u8 *bssid; @@ -2774,39 +2771,17 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt) if (priv->vif != NULL) bssid = MWL8K_VIF(priv->vif)->bssid; - rc = mwl8k_cmd_set_post_scan(hw, bssid); + mwl8k_cmd_set_post_scan(hw, bssid); } } - if (!rc && worker->multicast_adr_cmd != NULL) - rc = mwl8k_post_cmd(hw, worker->multicast_adr_cmd); - kfree(worker->multicast_adr_cmd); - - return rc; -} - -static void mwl8k_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) -{ - struct mwl8k_configure_filter_worker *worker; - - /* Clear unsupported feature flags */ - *total_flags &= MWL8K_SUPPORTED_IF_FLAGS; - - if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS)) - return; - - worker = kzalloc(sizeof(*worker), GFP_ATOMIC); - if (worker == NULL) - return; - - worker->changed_flags = changed_flags; - worker->total_flags = *total_flags; - worker->multicast_adr_cmd = (void *)(unsigned long)multicast; + multicast_adr_cmd = (void *)(unsigned long)multicast; + if (multicast_adr_cmd != NULL) { + mwl8k_post_cmd(hw, multicast_adr_cmd); + kfree(multicast_adr_cmd); + } - mwl8k_queue_work(hw, &worker->header, mwl8k_configure_filter_wt); + mwl8k_fw_unlock(hw); } static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -- cgit v0.10.2 From ab565790cb5ca3d00db0af9c2a8eb95e16054c29 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 04:08:01 +0200 Subject: mwl8k: remove mwl8k_queue_work() Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 43e5dd1..a634b56 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2425,70 +2425,6 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return rc; } -struct mwl8k_work_struct { - /* Initialized by mwl8k_queue_work(). */ - struct work_struct wt; - - /* Required field passed in to mwl8k_queue_work(). */ - struct ieee80211_hw *hw; - - /* Required field passed in to mwl8k_queue_work(). */ - int (*wfunc)(struct work_struct *w); - - /* Initialized by mwl8k_queue_work(). */ - struct completion *cmd_wait; - - /* Result code. */ - int rc; -}; - -static void mwl8k_config_thread(struct work_struct *wt) -{ - struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt; - struct ieee80211_hw *hw = worker->hw; - int rc = 0; - - rc = mwl8k_fw_lock(hw); - if (!rc) { - rc = worker->wfunc(wt); - mwl8k_fw_unlock(hw); - } - - worker->rc = rc; - complete(worker->cmd_wait); -} - -static int mwl8k_queue_work(struct ieee80211_hw *hw, - struct mwl8k_work_struct *worker, - int (*wfunc)(struct work_struct *w)) -{ - struct mwl8k_priv *priv = hw->priv; - unsigned long timeout = 0; - int rc = 0; - - DECLARE_COMPLETION_ONSTACK(cmd_wait); - - worker->hw = hw; - worker->cmd_wait = &cmd_wait; - worker->rc = 1; - worker->wfunc = wfunc; - - INIT_WORK(&worker->wt, mwl8k_config_thread); - queue_work(priv->config_wq, &worker->wt); - - timeout = wait_for_completion_timeout(&cmd_wait, - msecs_to_jiffies(10000)); - - if (timeout) - rc = worker->rc; - else { - cancel_work_sync(&worker->wt); - rc = -ETIMEDOUT; - } - - return rc; -} - static int mwl8k_start(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; -- cgit v0.10.2 From a145d575833ff47330125364cb49304db7308825 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 04:34:26 +0200 Subject: mwl8k: update copyright and version number Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a634b56..41a708c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2,7 +2,7 @@ * drivers/net/wireless/mwl8k.c * Driver for Marvell TOPDOG 802.11 Wireless cards * - * Copyright (C) 2008 Marvell Semiconductor Inc. + * Copyright (C) 2008-2009 Marvell Semiconductor Inc. * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -25,7 +25,7 @@ #define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver" #define MWL8K_NAME KBUILD_MODNAME -#define MWL8K_VERSION "0.9.1" +#define MWL8K_VERSION "0.10" MODULE_DESCRIPTION(MWL8K_DESC); MODULE_VERSION(MWL8K_VERSION); -- cgit v0.10.2 From a2c3f6567c9ac327f1ef1272551f3a7595ec885e Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 05:13:48 +0200 Subject: MAINTAINERS: add information for mwl8k wireless driver Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index 866253d..9b55c66 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3272,6 +3272,12 @@ S: Supported F: drivers/net/mv643xx_eth.* F: include/linux/mv643xx.h +MARVELL MWL8K WIRELESS DRIVER +M: Lennert Buytenhek +L: linux-wireless@vger.kernel.org +S: Supported +F: drivers/net/wireless/mwl8k.c + MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER M: Nicolas Pitre S: Maintained -- cgit v0.10.2 From f61c890ec631884c5b7cd8723cd8ae1917dca544 Mon Sep 17 00:00:00 2001 From: Shine Liu Date: Thu, 20 Aug 2009 23:02:23 +0800 Subject: ASoC: S3C24XX : Align the peroid size to the buffer size > Then it's a driver bug. If unaligned period size is allowed, it means > that the irq is really generated in that period, not at the buffer > boundary. Otherwise, it must have a proper hw-constraint to align the > period size to the buffer size. This patch will fix the bug metioned in the above mail. Force the peroid size to be aligned with the buffer size. Based and tested on linux-2.6.31-rc6. Signed-off-by: Shine Liu Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index eecfa5e..8a93196 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -318,6 +318,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) pr_debug("Entered %s\n", __func__); + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); -- cgit v0.10.2 From a4d7d550a9cfdfbc615383a08e9afa39d5a6d875 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Aug 2009 21:01:05 +0900 Subject: ASoC: Add SuperH FSI driver support for ALSA This driver is very simple. It support playback only now. This patch is tested by ms7724se board. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h new file mode 100644 index 0000000..c022736 --- /dev/null +++ b/include/sound/sh_fsi.h @@ -0,0 +1,83 @@ +#ifndef __SOUND_FSI_H +#define __SOUND_FSI_H + +/* + * Fifo-attached Serial Interface (FSI) support for SH7724 + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto + * + * 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 + * published by the Free Software Foundation. + */ + +/* flags format + + * 0xABCDEEFF + * + * A: channel size for TDM (input) + * B: channel size for TDM (ooutput) + * C: inversion + * D: mode + * E: input format + * F: output format + */ + +#include +#include + +/* TDM channel */ +#define SH_FSI_SET_CH_I(x) ((x & 0xF) << 28) +#define SH_FSI_SET_CH_O(x) ((x & 0xF) << 24) + +#define SH_FSI_CH_IMASK 0xF0000000 +#define SH_FSI_CH_OMASK 0x0F000000 +#define SH_FSI_GET_CH_I(x) ((x & SH_FSI_CH_IMASK) >> 28) +#define SH_FSI_GET_CH_O(x) ((x & SH_FSI_CH_OMASK) >> 24) + +/* clock inversion */ +#define SH_FSI_INVERSION_MASK 0x00F00000 +#define SH_FSI_LRM_INV (1 << 20) +#define SH_FSI_BRM_INV (1 << 21) +#define SH_FSI_LRS_INV (1 << 22) +#define SH_FSI_BRS_INV (1 << 23) + +/* mode */ +#define SH_FSI_MODE_MASK 0x000F0000 +#define SH_FSI_IN_SLAVE_MODE (1 << 16) /* default master mode */ +#define SH_FSI_OUT_SLAVE_MODE (1 << 17) /* default master mode */ + +/* DI format */ +#define SH_FSI_FMT_MASK 0x000000FF +#define SH_FSI_IFMT(x) (((SH_FSI_FMT_ ## x) & SH_FSI_FMT_MASK) << 8) +#define SH_FSI_OFMT(x) (((SH_FSI_FMT_ ## x) & SH_FSI_FMT_MASK) << 0) +#define SH_FSI_GET_IFMT(x) ((x >> 8) & SH_FSI_FMT_MASK) +#define SH_FSI_GET_OFMT(x) ((x >> 0) & SH_FSI_FMT_MASK) + +#define SH_FSI_FMT_MONO (1 << 0) +#define SH_FSI_FMT_MONO_DELAY (1 << 1) +#define SH_FSI_FMT_PCM (1 << 2) +#define SH_FSI_FMT_I2S (1 << 3) +#define SH_FSI_FMT_TDM (1 << 4) +#define SH_FSI_FMT_TDM_DELAY (1 << 5) + +#define SH_FSI_IFMT_TDM_CH(x) \ + (SH_FSI_IFMT(TDM) | SH_FSI_SET_CH_I(x)) +#define SH_FSI_IFMT_TDM_DELAY_CH(x) \ + (SH_FSI_IFMT(TDM_DELAY) | SH_FSI_SET_CH_I(x)) + +#define SH_FSI_OFMT_TDM_CH(x) \ + (SH_FSI_OFMT(TDM) | SH_FSI_SET_CH_O(x)) +#define SH_FSI_OFMT_TDM_DELAY_CH(x) \ + (SH_FSI_OFMT(TDM_DELAY) | SH_FSI_SET_CH_O(x)) + +struct sh_fsi_platform_info { + unsigned long porta_flags; + unsigned long portb_flags; +}; + +extern struct snd_soc_dai fsi_soc_dai[2]; +extern struct snd_soc_platform fsi_soc_platform; + +#endif /* __SOUND_FSI_H */ diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 54bd604..01943a1 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -20,7 +20,12 @@ config SND_SOC_SH4_HAC config SND_SOC_SH4_SSI tristate - +config SND_SOC_SH4_FSI + tristate "SH4 FSI support" + depends on CPU_SUBTYPE_SH7724 + select SH_DMA + help + This option enables FSI sound support ## ## Boards diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile index a8e8ab8..9fbcc4a 100644 --- a/sound/soc/sh/Makefile +++ b/sound/soc/sh/Makefile @@ -5,8 +5,10 @@ obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o ## audio units found on some SH-4 snd-soc-hac-objs := hac.o snd-soc-ssi-objs := ssi.o +snd-soc-fsi-objs := fsi.o obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o +obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o ## boards snd-soc-sh7760-ac97-objs := sh7760-ac97.o diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c new file mode 100644 index 0000000..4412324 --- /dev/null +++ b/sound/soc/sh/fsi.c @@ -0,0 +1,1004 @@ +/* + * Fifo-attached Serial Interface (FSI) support for SH7724 + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto + * + * Based on ssi.c + * Copyright (c) 2007 Manuel Lauss + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DO_FMT 0x0000 +#define DOFF_CTL 0x0004 +#define DOFF_ST 0x0008 +#define DI_FMT 0x000C +#define DIFF_CTL 0x0010 +#define DIFF_ST 0x0014 +#define CKG1 0x0018 +#define CKG2 0x001C +#define DIDT 0x0020 +#define DODT 0x0024 +#define MUTE_ST 0x0028 +#define REG_END MUTE_ST + +#define INT_ST 0x0200 +#define IEMSK 0x0204 +#define IMSK 0x0208 +#define MUTE 0x020C +#define CLK_RST 0x0210 +#define SOFT_RST 0x0214 +#define MREG_START INT_ST +#define MREG_END SOFT_RST + +/* DO_FMT */ +/* DI_FMT */ +#define CR_FMT(param) ((param) << 4) +# define CR_MONO 0x0 +# define CR_MONO_D 0x1 +# define CR_PCM 0x2 +# define CR_I2S 0x3 +# define CR_TDM 0x4 +# define CR_TDM_D 0x5 + +/* DOFF_CTL */ +/* DIFF_CTL */ +#define IRQ_HALF 0x00100000 +#define FIFO_CLR 0x00000001 + +/* DOFF_ST */ +#define ERR_OVER 0x00000010 +#define ERR_UNDER 0x00000001 + +/* CLK_RST */ +#define B_CLK 0x00000010 +#define A_CLK 0x00000001 + +/* INT_ST */ +#define INT_B_IN (1 << 12) +#define INT_B_OUT (1 << 8) +#define INT_A_IN (1 << 4) +#define INT_A_OUT (1 << 0) + +#define FSI_RATES SNDRV_PCM_RATE_8000_96000 + +#define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) + +/************************************************************************ + + + struct + + +************************************************************************/ +struct fsi_priv { + void __iomem *base; + struct snd_pcm_substream *substream; + + int fifo_max; + int chan; + int dma_chan; + + int byte_offset; + int period_len; + int buffer_len; + int periods; +}; + +struct fsi_master { + void __iomem *base; + int irq; + struct clk *clk; + struct fsi_priv fsia; + struct fsi_priv fsib; + struct sh_fsi_platform_info *info; +}; + +static struct fsi_master *master; + +/************************************************************************ + + + basic read write function + + +************************************************************************/ +static int __fsi_reg_write(u32 reg, u32 data) +{ + /* valid data area is 24bit */ + data &= 0x00ffffff; + + return ctrl_outl(data, reg); +} + +static u32 __fsi_reg_read(u32 reg) +{ + return ctrl_inl(reg); +} + +static int __fsi_reg_mask_set(u32 reg, u32 mask, u32 data) +{ + u32 val = __fsi_reg_read(reg); + + val &= ~mask; + val |= data & mask; + + return __fsi_reg_write(reg, val); +} + +static int fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) +{ + if (reg > REG_END) + return -1; + + return __fsi_reg_write((u32)(fsi->base + reg), data); +} + +static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) +{ + if (reg > REG_END) + return 0; + + return __fsi_reg_read((u32)(fsi->base + reg)); +} + +static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) +{ + if (reg > REG_END) + return -1; + + return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); +} + +static int fsi_master_write(u32 reg, u32 data) +{ + if ((reg < MREG_START) || + (reg > MREG_END)) + return -1; + + return __fsi_reg_write((u32)(master->base + reg), data); +} + +static u32 fsi_master_read(u32 reg) +{ + if ((reg < MREG_START) || + (reg > MREG_END)) + return 0; + + return __fsi_reg_read((u32)(master->base + reg)); +} + +static int fsi_master_mask_set(u32 reg, u32 mask, u32 data) +{ + if ((reg < MREG_START) || + (reg > MREG_END)) + return -1; + + return __fsi_reg_mask_set((u32)(master->base + reg), mask, data); +} + +/************************************************************************ + + + basic function + + +************************************************************************/ +static struct fsi_priv *fsi_get(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd; + struct fsi_priv *fsi = NULL; + + if (!substream || !master) + return NULL; + + rtd = substream->private_data; + switch (rtd->dai->cpu_dai->id) { + case 0: + fsi = &master->fsia; + break; + case 1: + fsi = &master->fsib; + break; + } + + return fsi; +} + +static int fsi_is_port_a(struct fsi_priv *fsi) +{ + /* return + * 1 : port a + * 0 : port b + */ + + if (fsi == &master->fsia) + return 1; + + return 0; +} + +static u32 fsi_get_info_flags(struct fsi_priv *fsi) +{ + int is_porta = fsi_is_port_a(fsi); + + return is_porta ? master->info->porta_flags : + master->info->portb_flags; +} + +static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play) +{ + u32 mode; + u32 flags = fsi_get_info_flags(fsi); + + mode = is_play ? SH_FSI_OUT_SLAVE_MODE : SH_FSI_IN_SLAVE_MODE; + + /* return + * 1 : master mode + * 0 : slave mode + */ + + return (mode & flags) != mode; +} + +static u32 fsi_port_ab_io_bit(struct fsi_priv *fsi, int is_play) +{ + int is_porta = fsi_is_port_a(fsi); + u32 data; + + if (is_porta) + data = is_play ? (1 << 0) : (1 << 4); + else + data = is_play ? (1 << 8) : (1 << 12); + + return data; +} + +static void fsi_stream_push(struct fsi_priv *fsi, + struct snd_pcm_substream *substream, + u32 buffer_len, + u32 period_len) +{ + fsi->substream = substream; + fsi->buffer_len = buffer_len; + fsi->period_len = period_len; + fsi->byte_offset = 0; + fsi->periods = 0; +} + +static void fsi_stream_pop(struct fsi_priv *fsi) +{ + fsi->substream = NULL; + fsi->buffer_len = 0; + fsi->period_len = 0; + fsi->byte_offset = 0; + fsi->periods = 0; +} + +static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play) +{ + u32 status; + u32 reg = is_play ? DOFF_ST : DIFF_ST; + int residue; + + status = fsi_reg_read(fsi, reg); + residue = 0x1ff & (status >> 8); + residue *= fsi->chan; + + return residue; +} + +static int fsi_get_residue(struct fsi_priv *fsi, int is_play) +{ + int residue; + int width; + struct snd_pcm_runtime *runtime; + + runtime = fsi->substream->runtime; + + /* get 1 channel data width */ + width = frames_to_bytes(runtime, 1) / fsi->chan; + + if (2 == width) + residue = fsi_get_fifo_residue(fsi, is_play); + else + residue = get_dma_residue(fsi->dma_chan); + + return residue; +} + +/************************************************************************ + + + basic dma function + + +************************************************************************/ +#define PORTA_DMA 0 +#define PORTB_DMA 1 + +static int fsi_get_dma_chan(void) +{ + if (0 != request_dma(PORTA_DMA, "fsia")) + return -EIO; + + if (0 != request_dma(PORTB_DMA, "fsib")) { + free_dma(PORTA_DMA); + return -EIO; + } + + master->fsia.dma_chan = PORTA_DMA; + master->fsib.dma_chan = PORTB_DMA; + + return 0; +} + +static void fsi_free_dma_chan(void) +{ + dma_wait_for_completion(PORTA_DMA); + dma_wait_for_completion(PORTB_DMA); + free_dma(PORTA_DMA); + free_dma(PORTB_DMA); + + master->fsia.dma_chan = -1; + master->fsib.dma_chan = -1; +} + +/************************************************************************ + + + ctrl function + + +************************************************************************/ +static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) +{ + u32 data = fsi_port_ab_io_bit(fsi, is_play); + + fsi_master_mask_set(IMSK, data, data); + fsi_master_mask_set(IEMSK, data, data); +} + +static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) +{ + u32 data = fsi_port_ab_io_bit(fsi, is_play); + + fsi_master_mask_set(IMSK, data, 0); + fsi_master_mask_set(IEMSK, data, 0); +} + +static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) +{ + u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); + + if (enable) + fsi_master_mask_set(CLK_RST, val, val); + else + fsi_master_mask_set(CLK_RST, val, 0); +} + +static void fsi_irq_init(struct fsi_priv *fsi, int is_play) +{ + u32 data; + u32 ctrl; + + data = fsi_port_ab_io_bit(fsi, is_play); + ctrl = is_play ? DOFF_CTL : DIFF_CTL; + + /* set IMSK */ + fsi_irq_disable(fsi, is_play); + + /* set interrupt generation factor */ + fsi_reg_write(fsi, ctrl, IRQ_HALF); + + /* clear FIFO */ + fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR); + + /* clear interrupt factor */ + fsi_master_mask_set(INT_ST, data, 0); +} + +static void fsi_soft_all_reset(void) +{ + u32 status = fsi_master_read(SOFT_RST); + + /* port AB reset */ + status &= 0x000000ff; + fsi_master_write(SOFT_RST, status); + mdelay(10); + + /* soft reset */ + status &= 0x000000f0; + fsi_master_write(SOFT_RST, status); + status |= 0x00000001; + fsi_master_write(SOFT_RST, status); + mdelay(10); +} + +static void fsi_16data_push(struct fsi_priv *fsi, + struct snd_pcm_runtime *runtime, + int send) +{ + u16 *dma_start; + u32 snd; + int i; + + /* get dma start position for FSI */ + dma_start = (u16 *)runtime->dma_area; + dma_start += fsi->byte_offset / 2; + + /* + * soft dma + * FSI can not use DMA when 16bpp + */ + for (i = 0; i < send; i++) { + snd = (u32)dma_start[i]; + fsi_reg_write(fsi, DODT, snd << 8); + } +} + +static void fsi_32data_push(struct fsi_priv *fsi, + struct snd_pcm_runtime *runtime, + int send) +{ + u32 *dma_start; + + /* get dma start position for FSI */ + dma_start = (u32 *)runtime->dma_area; + dma_start += fsi->byte_offset / 4; + + dma_wait_for_completion(fsi->dma_chan); + dma_configure_channel(fsi->dma_chan, (SM_INC|0x400|TS_32|TM_BUR)); + dma_write(fsi->dma_chan, (u32)dma_start, + (u32)(fsi->base + DODT), send * 4); +} + +/* playback interrupt */ +static int fsi_data_push(struct fsi_priv *fsi) +{ + struct snd_pcm_runtime *runtime; + struct snd_pcm_substream *substream = NULL; + int send; + int fifo_free; + int width; + + if (!fsi || + !fsi->substream || + !fsi->substream->runtime) + return -EINVAL; + + runtime = fsi->substream->runtime; + + /* FSI FIFO has limit. + * So, this driver can not send periods data at a time + */ + if (fsi->byte_offset >= + fsi->period_len * (fsi->periods + 1)) { + + substream = fsi->substream; + fsi->periods = (fsi->periods + 1) % runtime->periods; + + if (0 == fsi->periods) + fsi->byte_offset = 0; + } + + /* get 1 channel data width */ + width = frames_to_bytes(runtime, 1) / fsi->chan; + + /* get send size for alsa */ + send = (fsi->buffer_len - fsi->byte_offset) / width; + + /* get FIFO free size */ + fifo_free = (fsi->fifo_max * fsi->chan) - fsi_get_fifo_residue(fsi, 1); + + /* size check */ + if (fifo_free < send) + send = fifo_free; + + if (2 == width) + fsi_16data_push(fsi, runtime, send); + else if (4 == width) + fsi_32data_push(fsi, runtime, send); + else + return -EINVAL; + + fsi->byte_offset += send * width; + + fsi_irq_enable(fsi, 1); + + if (substream) + snd_pcm_period_elapsed(substream); + + return 0; +} + +static irqreturn_t fsi_interrupt(int irq, void *data) +{ + u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; + u32 int_st = fsi_master_read(INT_ST); + + /* clear irq status */ + fsi_master_write(SOFT_RST, status); + fsi_master_write(SOFT_RST, status | 0x00000010); + + if (int_st & INT_A_OUT) + fsi_data_push(&master->fsia); + if (int_st & INT_B_OUT) + fsi_data_push(&master->fsib); + + fsi_master_write(INT_ST, 0x0000000); + + return IRQ_HANDLED; +} + +/************************************************************************ + + + dai ops + + +************************************************************************/ +static int fsi_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsi_priv *fsi = fsi_get(substream); + const char *msg; + u32 flags = fsi_get_info_flags(fsi); + u32 fmt; + u32 reg; + u32 data; + int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + int is_master; + int ret = 0; + + clk_enable(master->clk); + + /* CKG1 */ + data = is_play ? (1 << 0) : (1 << 4); + is_master = fsi_is_master_mode(fsi, is_play); + if (is_master) + fsi_reg_mask_set(fsi, CKG1, data, data); + else + fsi_reg_mask_set(fsi, CKG1, data, 0); + + /* clock inversion (CKG2) */ + data = 0; + switch (SH_FSI_INVERSION_MASK & flags) { + case SH_FSI_LRM_INV: + data = 1 << 12; + break; + case SH_FSI_BRM_INV: + data = 1 << 8; + break; + case SH_FSI_LRS_INV: + data = 1 << 4; + break; + case SH_FSI_BRS_INV: + data = 1 << 0; + break; + } + fsi_reg_write(fsi, CKG2, data); + + /* do fmt, di fmt */ + data = 0; + reg = is_play ? DO_FMT : DI_FMT; + fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags); + switch (fmt) { + case SH_FSI_FMT_MONO: + msg = "MONO"; + data = CR_FMT(CR_MONO); + fsi->chan = 1; + break; + case SH_FSI_FMT_MONO_DELAY: + msg = "MONO Delay"; + data = CR_FMT(CR_MONO_D); + fsi->chan = 1; + break; + case SH_FSI_FMT_PCM: + msg = "PCM"; + data = CR_FMT(CR_PCM); + fsi->chan = 2; + break; + case SH_FSI_FMT_I2S: + msg = "I2S"; + data = CR_FMT(CR_I2S); + fsi->chan = 2; + break; + case SH_FSI_FMT_TDM: + msg = "TDM"; + data = CR_FMT(CR_TDM) | (fsi->chan - 1); + fsi->chan = is_play ? + SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); + break; + case SH_FSI_FMT_TDM_DELAY: + msg = "TDM Delay"; + data = CR_FMT(CR_TDM_D) | (fsi->chan - 1); + fsi->chan = is_play ? + SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); + break; + default: + dev_err(dai->dev, "unknown format.\n"); + return -EINVAL; + } + + switch (fsi->chan) { + case 1: + fsi->fifo_max = 256; + break; + case 2: + fsi->fifo_max = 128; + break; + case 3: + case 4: + fsi->fifo_max = 64; + break; + case 5: + case 6: + case 7: + case 8: + fsi->fifo_max = 32; + break; + default: + dev_err(dai->dev, "channel size error.\n"); + return -EINVAL; + } + + fsi_reg_write(fsi, reg, data); + dev_dbg(dai->dev, "use %s format (%d channel) use %d DMAC\n", + msg, fsi->chan, fsi->dma_chan); + + /* + * clear clk reset if master mode + */ + if (is_master) + fsi_clk_ctrl(fsi, 1); + + /* irq setting */ + fsi_irq_init(fsi, is_play); + + return ret; +} + +static void fsi_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsi_priv *fsi = fsi_get(substream); + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + + fsi_irq_disable(fsi, is_play); + fsi_clk_ctrl(fsi, 0); + + clk_disable(master->clk); +} + +static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct fsi_priv *fsi = fsi_get(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + int ret = 0; + + /* capture not supported */ + if (!is_play) + return -ENODEV; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + fsi_stream_push(fsi, substream, + frames_to_bytes(runtime, runtime->buffer_size), + frames_to_bytes(runtime, runtime->period_size)); + ret = fsi_data_push(fsi); + break; + case SNDRV_PCM_TRIGGER_STOP: + fsi_irq_disable(fsi, is_play); + fsi_stream_pop(fsi); + break; + } + + return ret; +} + +static struct snd_soc_dai_ops fsi_dai_ops = { + .startup = fsi_dai_startup, + .shutdown = fsi_dai_shutdown, + .trigger = fsi_dai_trigger, +}; + +/************************************************************************ + + + pcm ops + + +************************************************************************/ +static struct snd_pcm_hardware fsi_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE, + .formats = FSI_FMTS, + .rates = FSI_RATES, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = 64 * 1024, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 32, + .fifo_size = 256, +}; + +static int fsi_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &fsi_pcm_hardware); + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + + return ret; +} + +static int fsi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +} + +static int fsi_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsi_priv *fsi = fsi_get(substream); + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + long location; + + location = (fsi->byte_offset - 1) - fsi_get_residue(fsi, is_play); + if (location < 0) + location = 0; + + return bytes_to_frames(runtime, location); +} + +static struct snd_pcm_ops fsi_pcm_ops = { + .open = fsi_pcm_open, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = fsi_hw_params, + .hw_free = fsi_hw_free, + .pointer = fsi_pointer, +}; + +/************************************************************************ + + + snd_soc_platform + + +************************************************************************/ +#define PREALLOC_BUFFER (32 * 1024) +#define PREALLOC_BUFFER_MAX (32 * 1024) + +static void fsi_pcm_free(struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static int fsi_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + /* + * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel + * in MMAP mode (i.e. aplay -M) + */ + return snd_pcm_lib_preallocate_pages_for_all( + pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); +} + +/************************************************************************ + + + alsa struct + + +************************************************************************/ +struct snd_soc_dai fsi_soc_dai[] = { + { + .name = "FSIA", + .id = 0, + .playback = { + .rates = FSI_RATES, + .formats = FSI_FMTS, + .channels_min = 1, + .channels_max = 8, + }, + /* capture not supported */ + .ops = &fsi_dai_ops, + }, + { + .name = "FSIB", + .id = 1, + .playback = { + .rates = FSI_RATES, + .formats = FSI_FMTS, + .channels_min = 1, + .channels_max = 8, + }, + /* capture not supported */ + .ops = &fsi_dai_ops, + }, +}; +EXPORT_SYMBOL_GPL(fsi_soc_dai); + +struct snd_soc_platform fsi_soc_platform = { + .name = "fsi-pcm", + .pcm_ops = &fsi_pcm_ops, + .pcm_new = fsi_pcm_new, + .pcm_free = fsi_pcm_free, +}; +EXPORT_SYMBOL_GPL(fsi_soc_platform); + +/************************************************************************ + + + platform function + + +************************************************************************/ +static int fsi_probe(struct platform_device *pdev) +{ + struct resource *res; + char clk_name[8]; + unsigned int irq; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!res || !irq) { + dev_err(&pdev->dev, "Not enough FSI platform resources.\n"); + ret = -ENODEV; + goto exit; + } + + master = kzalloc(sizeof(*master), GFP_KERNEL); + if (!master) { + dev_err(&pdev->dev, "Could not allocate master\n"); + ret = -ENOMEM; + goto exit; + } + + master->base = ioremap_nocache(res->start, resource_size(res)); + if (!master->base) { + ret = -ENXIO; + dev_err(&pdev->dev, "Unable to ioremap FSI registers.\n"); + goto exit_kfree; + } + + master->irq = irq; + master->info = pdev->dev.platform_data; + master->fsia.base = master->base; + master->fsib.base = master->base + 0x40; + + master->fsia.dma_chan = -1; + master->fsib.dma_chan = -1; + + ret = fsi_get_dma_chan(); + if (ret < 0) { + dev_err(&pdev->dev, "cannot get dma api\n"); + goto exit_iounmap; + } + + /* FSI is based on SPU mstp */ + snprintf(clk_name, sizeof(clk_name), "spu%d", pdev->id); + master->clk = clk_get(NULL, clk_name); + if (IS_ERR(master->clk)) { + dev_err(&pdev->dev, "cannot get %s mstp\n", clk_name); + ret = -EIO; + goto exit_free_dma; + } + + fsi_soc_dai[0].dev = &pdev->dev; + fsi_soc_dai[1].dev = &pdev->dev; + + fsi_soft_all_reset(); + + ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); + if (ret) { + dev_err(&pdev->dev, "irq request err\n"); + goto exit_free_dma; + } + + ret = snd_soc_register_platform(&fsi_soc_platform); + if (ret < 0) { + dev_err(&pdev->dev, "cannot snd soc register\n"); + goto exit_free_irq; + } + + return snd_soc_register_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); + +exit_free_irq: + free_irq(irq, master); +exit_free_dma: + fsi_free_dma_chan(); +exit_iounmap: + iounmap(master->base); +exit_kfree: + kfree(master); + master = NULL; +exit: + return ret; +} + +static int fsi_remove(struct platform_device *pdev) +{ + snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); + snd_soc_unregister_platform(&fsi_soc_platform); + + clk_put(master->clk); + + fsi_free_dma_chan(); + + free_irq(master->irq, master); + + iounmap(master->base); + kfree(master); + master = NULL; + return 0; +} + +static struct platform_driver fsi_driver = { + .driver = { + .name = "sh_fsi", + }, + .probe = fsi_probe, + .remove = fsi_remove, +}; + +static int __init fsi_mobile_init(void) +{ + return platform_driver_register(&fsi_driver); +} + +static void __exit fsi_mobile_exit(void) +{ + platform_driver_unregister(&fsi_driver); +} +module_init(fsi_mobile_init); +module_exit(fsi_mobile_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SuperH onchip FSI audio driver"); +MODULE_AUTHOR("Kuninori Morimoto "); -- cgit v0.10.2 From 9abea08e43c6cfc18399e42cbc6028d111532f61 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 20 Aug 2009 16:18:07 +0300 Subject: OMAP: McBSP: Provide functions for ASoC frame syncronization ASoC has an annoying bug letting either L or R channel to be played on L channel. In other words, L and R channels can switch at random. This provides McBSP funtionality that may be used to fix this feature. Signed-off-by: Eero Nurkkala Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index 57249bb..b85e6e6 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -389,6 +389,8 @@ int omap_mcbsp_request(unsigned int id); void omap_mcbsp_free(unsigned int id); void omap_mcbsp_start(unsigned int id, int tx, int rx); void omap_mcbsp_stop(unsigned int id, int tx, int rx); +void omap_mcbsp_xmit_enable(unsigned int id, u8 enable); +void omap_mcbsp_recv_enable(unsigned int id, u8 enable); void omap_mcbsp_xmit_word(unsigned int id, u32 word); u32 omap_mcbsp_recv_word(unsigned int id); diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index a3d2313..0aa2524 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -412,6 +412,58 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx) } EXPORT_SYMBOL(omap_mcbsp_stop); +void omap_mcbsp_xmit_enable(unsigned int id, u8 enable) +{ + struct omap_mcbsp *mcbsp; + void __iomem *io_base; + u16 w; + + if (!(cpu_is_omap2430() || cpu_is_omap34xx())) + return; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return; + } + + mcbsp = id_to_mcbsp_ptr(id); + io_base = mcbsp->io_base; + + w = OMAP_MCBSP_READ(io_base, XCCR); + + if (enable) + OMAP_MCBSP_WRITE(io_base, XCCR, w & ~(XDISABLE)); + else + OMAP_MCBSP_WRITE(io_base, XCCR, w | XDISABLE); +} +EXPORT_SYMBOL(omap_mcbsp_xmit_enable); + +void omap_mcbsp_recv_enable(unsigned int id, u8 enable) +{ + struct omap_mcbsp *mcbsp; + void __iomem *io_base; + u16 w; + + if (!(cpu_is_omap2430() || cpu_is_omap34xx())) + return; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return; + } + + mcbsp = id_to_mcbsp_ptr(id); + io_base = mcbsp->io_base; + + w = OMAP_MCBSP_READ(io_base, RCCR); + + if (enable) + OMAP_MCBSP_WRITE(io_base, RCCR, w & ~(RDISABLE)); + else + OMAP_MCBSP_WRITE(io_base, RCCR, w | RDISABLE); +} +EXPORT_SYMBOL(omap_mcbsp_recv_enable); + /* polled mcbsp i/o operations */ int omap_mcbsp_pollwrite(unsigned int id, u16 buf) { -- cgit v0.10.2 From 946a49a95dabc9dd10344ae9ab4db9f14c5ad502 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:08 +0300 Subject: OMAP: McBSP: Add IRQEN, IRQSTATUS, THRESHOLD2 and THRESHOLD1 registers. Adding McBSP register definition for IRQEN, IRQSTATUS, THRESHOLD2 and THRESHOLD1 registers. Signed-off-by: Eduardo Valentin Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index b85e6e6..ceaf9ee 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -134,6 +134,10 @@ #define OMAP_MCBSP_REG_XCERG 0x74 #define OMAP_MCBSP_REG_XCERH 0x78 #define OMAP_MCBSP_REG_SYSCON 0x8C +#define OMAP_MCBSP_REG_THRSH2 0x90 +#define OMAP_MCBSP_REG_THRSH1 0x94 +#define OMAP_MCBSP_REG_IRQST 0xA0 +#define OMAP_MCBSP_REG_IRQEN 0xA4 #define OMAP_MCBSP_REG_XCCR 0xAC #define OMAP_MCBSP_REG_RCCR 0xB0 -- cgit v0.10.2 From 44a6311c0a83f682bcf18fae389a1b270df29314 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:09 +0300 Subject: OMAP: McBSP: Use appropriate value for startup delay Increasing startup delay value as worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec Although, 100us may give enough time for two CLKSRG, due to some unknown PM related, clock gating etc. reason, this patch increases it to 500us. Signed-off-by: Eduardo Valentin Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 0aa2524..e9dd703 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -365,7 +365,13 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) w = OMAP_MCBSP_READ(io_base, SPCR1); OMAP_MCBSP_WRITE(io_base, SPCR1, w | (rx & 1)); - udelay(100); + /* + * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec + * REVISIT: 100us may give enough time for two CLKSRG, however + * due to some unknown PM related, clock gating etc. reason it + * is now at 500us. + */ + udelay(500); if (idle) { /* Start frame sync */ -- cgit v0.10.2 From 7aa9ff56cae7a6a4fa2e1a503cc5f8bbd887d6e3 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:10 +0300 Subject: OMAP: McBSP: Add transmit/receive threshold handler This patch adds a way to handle transmit/receive threshold. It export to mcbsp users a callback registration procedure. Signed-off-by: Eduardo Valentin Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index ceaf9ee..2544aa5 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -389,6 +389,15 @@ int omap_mcbsp_init(void); void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config, int size); void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config); +#ifdef CONFIG_ARCH_OMAP34XX +void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold); +void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold); +#else +static inline void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold) +{ } +static inline void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) +{ } +#endif int omap_mcbsp_request(unsigned int id); void omap_mcbsp_free(unsigned int id); void omap_mcbsp_start(unsigned int id, int tx, int rx); diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index e9dd703..081f2ea 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -198,6 +198,56 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config) } EXPORT_SYMBOL(omap_mcbsp_config); +#ifdef CONFIG_ARCH_OMAP34XX +/* + * omap_mcbsp_set_tx_threshold configures how to deal + * with transmit threshold. the threshold value and handler can be + * configure in here. + */ +void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold) +{ + struct omap_mcbsp *mcbsp; + void __iomem *io_base; + + if (!cpu_is_omap34xx()) + return; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return; + } + mcbsp = id_to_mcbsp_ptr(id); + io_base = mcbsp->io_base; + + OMAP_MCBSP_WRITE(io_base, THRSH2, threshold); +} +EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold); + +/* + * omap_mcbsp_set_rx_threshold configures how to deal + * with receive threshold. the threshold value and handler can be + * configure in here. + */ +void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) +{ + struct omap_mcbsp *mcbsp; + void __iomem *io_base; + + if (!cpu_is_omap34xx()) + return; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return; + } + mcbsp = id_to_mcbsp_ptr(id); + io_base = mcbsp->io_base; + + OMAP_MCBSP_WRITE(io_base, THRSH1, threshold); +} +EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold); +#endif + /* * We can choose between IRQ based or polled IO. * This needs to be called before omap_mcbsp_request(). -- cgit v0.10.2 From a1a56f5faa41327116bf960a8e79f21a8ea35dce Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:11 +0300 Subject: OMAP: McBSP: Create and export max_(r|t)x_thres property This patch export through sysfs two properties to configure maximum threshold for transmission and reception on each mcbsp instance. Also, it exports two helper functions to allow mcbsp users to read this values. Signed-off-by: Eduardo Valentin Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index a5c0f04..f837114 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -129,6 +129,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP1_IRQ_RX, .tx_irq = INT_24XX_MCBSP1_IRQ_TX, .ops = &omap2_mcbsp_ops, + .buffer_size = 0x7F, }, { .phys_base = OMAP34XX_MCBSP2_BASE, @@ -137,6 +138,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP2_IRQ_RX, .tx_irq = INT_24XX_MCBSP2_IRQ_TX, .ops = &omap2_mcbsp_ops, + .buffer_size = 0x3FF, }, { .phys_base = OMAP34XX_MCBSP3_BASE, @@ -145,6 +147,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP3_IRQ_RX, .tx_irq = INT_24XX_MCBSP3_IRQ_TX, .ops = &omap2_mcbsp_ops, + .buffer_size = 0x7F, }, { .phys_base = OMAP34XX_MCBSP4_BASE, @@ -153,6 +156,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP4_IRQ_RX, .tx_irq = INT_24XX_MCBSP4_IRQ_TX, .ops = &omap2_mcbsp_ops, + .buffer_size = 0x7F, }, { .phys_base = OMAP34XX_MCBSP5_BASE, @@ -161,6 +165,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP5_IRQ_RX, .tx_irq = INT_24XX_MCBSP5_IRQ_TX, .ops = &omap2_mcbsp_ops, + .buffer_size = 0x7F, }, }; #define OMAP34XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap34xx_mcbsp_pdata) diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index 2544aa5..832330d 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -348,6 +348,9 @@ struct omap_mcbsp_platform_data { u8 dma_rx_sync, dma_tx_sync; u16 rx_irq, tx_irq; struct omap_mcbsp_ops *ops; +#ifdef CONFIG_ARCH_OMAP34XX + u16 buffer_size; +#endif }; struct omap_mcbsp { @@ -381,6 +384,10 @@ struct omap_mcbsp { struct omap_mcbsp_platform_data *pdata; struct clk *iclk; struct clk *fclk; +#ifdef CONFIG_ARCH_OMAP34XX + u16 max_tx_thres; + u16 max_rx_thres; +#endif }; extern struct omap_mcbsp **mcbsp_ptr; extern int omap_mcbsp_count; @@ -392,11 +399,15 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config #ifdef CONFIG_ARCH_OMAP34XX void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold); void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold); +u16 omap_mcbsp_get_max_tx_threshold(unsigned int id); +u16 omap_mcbsp_get_max_rx_threshold(unsigned int id); #else static inline void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold) { } static inline void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) { } +static inline u16 omap_mcbsp_get_max_tx_threshold(unsigned int id) { return 0; } +static inline u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) { return 0; } #endif int omap_mcbsp_request(unsigned int id); void omap_mcbsp_free(unsigned int id); diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 081f2ea..0bbc912 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -246,6 +246,42 @@ void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) OMAP_MCBSP_WRITE(io_base, THRSH1, threshold); } EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold); + +/* + * omap_mcbsp_get_max_tx_thres just return the current configured + * maximum threshold for transmission + */ +u16 omap_mcbsp_get_max_tx_threshold(unsigned int id) +{ + struct omap_mcbsp *mcbsp; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + mcbsp = id_to_mcbsp_ptr(id); + + return mcbsp->max_tx_thres; +} +EXPORT_SYMBOL(omap_mcbsp_get_max_tx_threshold); + +/* + * omap_mcbsp_get_max_rx_thres just return the current configured + * maximum threshold for reception + */ +u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) +{ + struct omap_mcbsp *mcbsp; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + mcbsp = id_to_mcbsp_ptr(id); + + return mcbsp->max_rx_thres; +} +EXPORT_SYMBOL(omap_mcbsp_get_max_rx_threshold); #endif /* @@ -1005,6 +1041,86 @@ void omap_mcbsp_set_spi_mode(unsigned int id, } EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); +#ifdef CONFIG_ARCH_OMAP34XX +#define max_thres(m) (mcbsp->pdata->buffer_size) +#define valid_threshold(m, val) ((val) <= max_thres(m)) +#define THRESHOLD_PROP_BUILDER(prop) \ +static ssize_t prop##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ + \ + return sprintf(buf, "%u\n", mcbsp->prop); \ +} \ + \ +static ssize_t prop##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t size) \ +{ \ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ + unsigned long val; \ + int status; \ + \ + status = strict_strtoul(buf, 0, &val); \ + if (status) \ + return status; \ + \ + if (!valid_threshold(mcbsp, val)) \ + return -EDOM; \ + \ + mcbsp->prop = val; \ + return size; \ +} \ + \ +static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store); + +THRESHOLD_PROP_BUILDER(max_tx_thres); +THRESHOLD_PROP_BUILDER(max_rx_thres); + +static const struct attribute *threshold_attrs[] = { + &dev_attr_max_tx_thres.attr, + &dev_attr_max_rx_thres.attr, + NULL, +}; + +static const struct attribute_group threshold_attr_group = { + .attrs = (struct attribute **)threshold_attrs, +}; + +static inline int __devinit omap_thres_add(struct device *dev) +{ + return sysfs_create_group(&dev->kobj, &threshold_attr_group); +} + +static inline void __devexit omap_thres_remove(struct device *dev) +{ + sysfs_remove_group(&dev->kobj, &threshold_attr_group); +} + +static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) +{ + if (cpu_is_omap34xx()) { + mcbsp->max_tx_thres = max_thres(mcbsp); + mcbsp->max_rx_thres = max_thres(mcbsp); + if (omap_thres_add(mcbsp->dev)) + dev_warn(mcbsp->dev, + "Unable to create threshold controls\n"); + } else { + mcbsp->max_tx_thres = -EINVAL; + mcbsp->max_rx_thres = -EINVAL; + } +} + +static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) +{ + if (cpu_is_omap34xx()) + omap_thres_remove(mcbsp->dev); +} +#else +static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {} +static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) {} +#endif /* CONFIG_ARCH_OMAP34XX */ + /* * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. * 730 has only 2 McBSP, and both of them are MPU peripherals. @@ -1075,6 +1191,10 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev) mcbsp->dev = &pdev->dev; mcbsp_ptr[id] = mcbsp; platform_set_drvdata(pdev, mcbsp); + + /* Initialize mcbsp properties for OMAP34XX if needed / applicable */ + omap34xx_device_init(mcbsp); + return 0; err_fclk: @@ -1098,6 +1218,8 @@ static int __devexit omap_mcbsp_remove(struct platform_device *pdev) mcbsp->pdata->ops->free) mcbsp->pdata->ops->free(mcbsp->id); + omap34xx_device_exit(mcbsp); + clk_disable(mcbsp->fclk); clk_disable(mcbsp->iclk); clk_put(mcbsp->fclk); -- cgit v0.10.2 From 7e4f943b725008272d5c50e676a89d642232a4e3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 20 Aug 2009 16:18:12 +0300 Subject: OMAP3: McBSP: Lower the maximum buffersize for McBSP1, 3, 4, 5 Do not allow applications to use the full buffer found on McBSP1,3,4,5. Using the full buffer in threshold mode causes the McBSP buffer to run dry, which can be observed as channels are switching (in reality the channels are shifting). Signed-off-by: Peter Ujfalusi Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index f837114..7d22caf 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -129,7 +129,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP1_IRQ_RX, .tx_irq = INT_24XX_MCBSP1_IRQ_TX, .ops = &omap2_mcbsp_ops, - .buffer_size = 0x7F, + .buffer_size = 0x6F, }, { .phys_base = OMAP34XX_MCBSP2_BASE, @@ -147,7 +147,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP3_IRQ_RX, .tx_irq = INT_24XX_MCBSP3_IRQ_TX, .ops = &omap2_mcbsp_ops, - .buffer_size = 0x7F, + .buffer_size = 0x6F, }, { .phys_base = OMAP34XX_MCBSP4_BASE, @@ -156,7 +156,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP4_IRQ_RX, .tx_irq = INT_24XX_MCBSP4_IRQ_TX, .ops = &omap2_mcbsp_ops, - .buffer_size = 0x7F, + .buffer_size = 0x6F, }, { .phys_base = OMAP34XX_MCBSP5_BASE, @@ -165,7 +165,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP5_IRQ_RX, .tx_irq = INT_24XX_MCBSP5_IRQ_TX, .ops = &omap2_mcbsp_ops, - .buffer_size = 0x7F, + .buffer_size = 0x6F, }, }; #define OMAP34XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap34xx_mcbsp_pdata) -- cgit v0.10.2 From 4c8200aeb04b8aeaf8c7425f49caf761e2cda95a Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:13 +0300 Subject: OMAP: McBSP: Rename thres sysfs symbols This patch renames the symbols that handles threshold sysfs properties. This way we can add more sysfs properties to them. Signed-off-by: Eduardo Valentin Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 0bbc912..ccaa9ae 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -1077,24 +1077,24 @@ static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store); THRESHOLD_PROP_BUILDER(max_tx_thres); THRESHOLD_PROP_BUILDER(max_rx_thres); -static const struct attribute *threshold_attrs[] = { +static const struct attribute *additional_attrs[] = { &dev_attr_max_tx_thres.attr, &dev_attr_max_rx_thres.attr, NULL, }; -static const struct attribute_group threshold_attr_group = { - .attrs = (struct attribute **)threshold_attrs, +static const struct attribute_group additional_attr_group = { + .attrs = (struct attribute **)additional_attrs, }; -static inline int __devinit omap_thres_add(struct device *dev) +static inline int __devinit omap_additional_add(struct device *dev) { - return sysfs_create_group(&dev->kobj, &threshold_attr_group); + return sysfs_create_group(&dev->kobj, &additional_attr_group); } -static inline void __devexit omap_thres_remove(struct device *dev) +static inline void __devexit omap_additional_remove(struct device *dev) { - sysfs_remove_group(&dev->kobj, &threshold_attr_group); + sysfs_remove_group(&dev->kobj, &additional_attr_group); } static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) @@ -1102,9 +1102,9 @@ static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) if (cpu_is_omap34xx()) { mcbsp->max_tx_thres = max_thres(mcbsp); mcbsp->max_rx_thres = max_thres(mcbsp); - if (omap_thres_add(mcbsp->dev)) + if (omap_additional_add(mcbsp->dev)) dev_warn(mcbsp->dev, - "Unable to create threshold controls\n"); + "Unable to create additional controls\n"); } else { mcbsp->max_tx_thres = -EINVAL; mcbsp->max_rx_thres = -EINVAL; @@ -1114,7 +1114,7 @@ static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) { if (cpu_is_omap34xx()) - omap_thres_remove(mcbsp->dev); + omap_additional_remove(mcbsp->dev); } #else static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {} -- cgit v0.10.2 From 98cb20e88957faf9c99e194242caac7f55dd47e4 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 20 Aug 2009 16:18:14 +0300 Subject: OMAP: McBSP: Add link DMA mode selection It adds a new sysfs file, where the user can configure the mcbsp mode to use. If the mcbsp channel is in use, it does not allow the change. Than in omap_pcm_open we can call the omap_mcbsp_get_opmode to get the mode, store it, than use it to implement the different modes. Signed-off-by: Peter Ujfalusi Signed-off-by: Eduardo Valentin Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index 832330d..bd5b759 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -255,6 +255,11 @@ /********************** McBSP SYSCONFIG bit definitions ********************/ #define SOFTRST 0x0002 +/********************** McBSP DMA operating modes **************************/ +#define MCBSP_DMA_MODE_ELEMENT 0 +#define MCBSP_DMA_MODE_THRESHOLD 1 +#define MCBSP_DMA_MODE_FRAME 2 + /* we don't do multichannel for now */ struct omap_mcbsp_reg_cfg { u16 spcr2; @@ -385,6 +390,7 @@ struct omap_mcbsp { struct clk *iclk; struct clk *fclk; #ifdef CONFIG_ARCH_OMAP34XX + int dma_op_mode; u16 max_tx_thres; u16 max_rx_thres; #endif @@ -401,6 +407,7 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold); void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold); u16 omap_mcbsp_get_max_tx_threshold(unsigned int id); u16 omap_mcbsp_get_max_rx_threshold(unsigned int id); +int omap_mcbsp_get_dma_op_mode(unsigned int id); #else static inline void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold) { } @@ -408,6 +415,7 @@ static inline void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) { } static inline u16 omap_mcbsp_get_max_tx_threshold(unsigned int id) { return 0; } static inline u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) { return 0; } +static inline int omap_mcbsp_get_dma_op_mode(unsigned int id) { return 0; } #endif int omap_mcbsp_request(unsigned int id); void omap_mcbsp_free(unsigned int id); diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index ccaa9ae..9e69994 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -282,6 +282,29 @@ u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) return mcbsp->max_rx_thres; } EXPORT_SYMBOL(omap_mcbsp_get_max_rx_threshold); + +/* + * omap_mcbsp_get_dma_op_mode just return the current configured + * operating mode for the mcbsp channel + */ +int omap_mcbsp_get_dma_op_mode(unsigned int id) +{ + struct omap_mcbsp *mcbsp; + int dma_op_mode; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%u)\n", __func__, id + 1); + return -ENODEV; + } + mcbsp = id_to_mcbsp_ptr(id); + + spin_lock_irq(&mcbsp->lock); + dma_op_mode = mcbsp->dma_op_mode; + spin_unlock_irq(&mcbsp->lock); + + return dma_op_mode; +} +EXPORT_SYMBOL(omap_mcbsp_get_dma_op_mode); #endif /* @@ -1077,9 +1100,65 @@ static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store); THRESHOLD_PROP_BUILDER(max_tx_thres); THRESHOLD_PROP_BUILDER(max_rx_thres); +static ssize_t dma_op_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); + int dma_op_mode; + + spin_lock_irq(&mcbsp->lock); + dma_op_mode = mcbsp->dma_op_mode; + spin_unlock_irq(&mcbsp->lock); + + return sprintf(buf, "current mode: %d\n" + "possible mode values are:\n" + "%d - %s\n" + "%d - %s\n" + "%d - %s\n", + dma_op_mode, + MCBSP_DMA_MODE_ELEMENT, "element mode", + MCBSP_DMA_MODE_THRESHOLD, "threshold mode", + MCBSP_DMA_MODE_FRAME, "frame mode"); +} + +static ssize_t dma_op_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); + unsigned long val; + int status; + + status = strict_strtoul(buf, 0, &val); + if (status) + return status; + + spin_lock_irq(&mcbsp->lock); + + if (!mcbsp->free) { + size = -EBUSY; + goto unlock; + } + + if (val > MCBSP_DMA_MODE_FRAME || val < MCBSP_DMA_MODE_ELEMENT) { + size = -EINVAL; + goto unlock; + } + + mcbsp->dma_op_mode = val; + +unlock: + spin_unlock_irq(&mcbsp->lock); + + return size; +} + +static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store); + static const struct attribute *additional_attrs[] = { &dev_attr_max_tx_thres.attr, &dev_attr_max_rx_thres.attr, + &dev_attr_dma_op_mode.attr, NULL, }; @@ -1099,9 +1178,14 @@ static inline void __devexit omap_additional_remove(struct device *dev) static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) { + mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT; if (cpu_is_omap34xx()) { mcbsp->max_tx_thres = max_thres(mcbsp); mcbsp->max_rx_thres = max_thres(mcbsp); + /* + * REVISIT: Set dmap_op_mode to THRESHOLD as default + * for mcbsp2 instances. + */ if (omap_additional_add(mcbsp->dev)) dev_warn(mcbsp->dev, "Unable to create additional controls\n"); -- cgit v0.10.2 From 2122fdc629f05634537e796c0630028e4db76953 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 20 Aug 2009 16:18:15 +0300 Subject: OMAP: McBSP: Wakeups utilized This patch enables the smart idle mode while McBPS is being utilized. Once it's done, force idle mode is taken instead. Apart of it, it also configures what signals will wake mcbsp up. Signed-off-by: Eero Nurkkala Signed-off-by: Eduardo Valentin Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index bd5b759..333061d 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -138,6 +138,7 @@ #define OMAP_MCBSP_REG_THRSH1 0x94 #define OMAP_MCBSP_REG_IRQST 0xA0 #define OMAP_MCBSP_REG_IRQEN 0xA4 +#define OMAP_MCBSP_REG_WAKEUPEN 0xA8 #define OMAP_MCBSP_REG_XCCR 0xAC #define OMAP_MCBSP_REG_RCCR 0xB0 @@ -253,6 +254,8 @@ #define RDISABLE 0x0001 /********************** McBSP SYSCONFIG bit definitions ********************/ +#define SIDLEMODE(value) ((value)<<3) +#define ENAWAKEUP 0x0004 #define SOFTRST 0x0002 /********************** McBSP DMA operating modes **************************/ @@ -260,6 +263,20 @@ #define MCBSP_DMA_MODE_THRESHOLD 1 #define MCBSP_DMA_MODE_FRAME 2 +/********************** McBSP WAKEUPEN bit definitions *********************/ +#define XEMPTYEOFEN 0x4000 +#define XRDYEN 0x0400 +#define XEOFEN 0x0200 +#define XFSXEN 0x0100 +#define XSYNCERREN 0x0080 +#define RRDYEN 0x0008 +#define REOFEN 0x0004 +#define RFSREN 0x0002 +#define RSYNCERREN 0x0001 +#define WAKEUPEN_ALL (XEMPTYEOFEN | XRDYEN | XEOFEN | XFSXEN | \ + XSYNCERREN | RRDYEN | REOFEN | RFSREN | \ + RSYNCERREN) + /* we don't do multichannel for now */ struct omap_mcbsp_reg_cfg { u16 spcr2; diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 9e69994..136f8c5 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -305,6 +305,46 @@ int omap_mcbsp_get_dma_op_mode(unsigned int id) return dma_op_mode; } EXPORT_SYMBOL(omap_mcbsp_get_dma_op_mode); + +static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) +{ + /* + * Enable wakup behavior, smart idle and all wakeups + * REVISIT: some wakeups may be unnecessary + */ + if (cpu_is_omap34xx()) { + u16 syscon; + + syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); + syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03)); + syscon |= (ENAWAKEUP | SIDLEMODE(0x02)); + OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); + + OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, WAKEUPEN_ALL); + } +} + +static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) +{ + /* + * Disable wakup behavior, smart idle and all wakeups + */ + if (cpu_is_omap34xx()) { + u16 syscon; + u16 wakeupen; + + syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); + syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03)); + OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); + + wakeupen = OMAP_MCBSP_READ(mcbsp->io_base, WAKEUPEN); + wakeupen &= ~WAKEUPEN_ALL; + OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, wakeupen); + } +} +#else +static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) {} +static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) {} #endif /* @@ -366,6 +406,9 @@ int omap_mcbsp_request(unsigned int id) clk_enable(mcbsp->iclk); clk_enable(mcbsp->fclk); + /* Do procedure specific to omap34xx arch, if applicable */ + omap34xx_mcbsp_request(mcbsp); + /* * Make sure that transmitter, receiver and sample-rate generator are * not running before activating IRQs. @@ -414,6 +457,9 @@ void omap_mcbsp_free(unsigned int id) if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) mcbsp->pdata->ops->free(id); + /* Do procedure specific to omap34xx arch, if applicable */ + omap34xx_mcbsp_free(mcbsp); + clk_disable(mcbsp->fclk); clk_disable(mcbsp->iclk); -- cgit v0.10.2 From d9a9b3f5f7d4736cfe6fae95b9d63b07faeb702e Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:16 +0300 Subject: OMAP: McBSP: Change wakeup signals Configure only XRDYEN and RRDYEN wakeup signals in order to get better power consumption. Signed-off-by: Eduardo Valentin Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index 333061d..fe10ae8 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -273,9 +273,6 @@ #define REOFEN 0x0004 #define RFSREN 0x0002 #define RSYNCERREN 0x0001 -#define WAKEUPEN_ALL (XEMPTYEOFEN | XRDYEN | XEOFEN | XFSXEN | \ - XSYNCERREN | RRDYEN | REOFEN | RFSREN | \ - RSYNCERREN) /* we don't do multichannel for now */ struct omap_mcbsp_reg_cfg { diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 136f8c5..86bfad8 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -320,7 +320,7 @@ static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) syscon |= (ENAWAKEUP | SIDLEMODE(0x02)); OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); - OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, WAKEUPEN_ALL); + OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, XRDYEN | RRDYEN); } } @@ -331,15 +331,12 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) */ if (cpu_is_omap34xx()) { u16 syscon; - u16 wakeupen; syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03)); OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); - wakeupen = OMAP_MCBSP_READ(mcbsp->io_base, WAKEUPEN); - wakeupen &= ~WAKEUPEN_ALL; - OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, wakeupen); + OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, 0); } } #else -- cgit v0.10.2 From 2ba93f8fa77c0140de163e8a31bb9c09b5ded74c Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 20 Aug 2009 16:18:17 +0300 Subject: OMAP: McBSP: Retain McBSP FCLK clockactivity FCLK may get autogated so that it prevents the McBSP to work properly. It is the bit 9 that must be set for maintaining the McBSP FCLK. Signed-off-by: Eero Nurkkala Signed-off-by: Eduardo Valentin Acked-by: Jarkko Nikula Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index fe10ae8..70e950e 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -254,6 +254,7 @@ #define RDISABLE 0x0001 /********************** McBSP SYSCONFIG bit definitions ********************/ +#define CLOCKACTIVITY(value) ((value)<<8) #define SIDLEMODE(value) ((value)<<3) #define ENAWAKEUP 0x0004 #define SOFTRST 0x0002 diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 86bfad8..2c274e6 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -316,8 +316,8 @@ static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) u16 syscon; syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); - syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03)); - syscon |= (ENAWAKEUP | SIDLEMODE(0x02)); + syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03)); + syscon |= (ENAWAKEUP | SIDLEMODE(0x02) | CLOCKACTIVITY(0x02)); OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, XRDYEN | RRDYEN); @@ -333,7 +333,7 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) u16 syscon; syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); - syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03)); + syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03)); OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, 0); -- cgit v0.10.2 From d99a7454e57d3dc9d04d6a77292a056f430a9ece Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:18 +0300 Subject: OMAP: McBSP: Configure NO IDLE mode for DMA mode different of threshold Use dma mode property to configure NO IDLE or SMART IDLE of McBSPs. Signed-off-by: Eduardo Valentin Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 2c274e6..85176a5 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -317,7 +317,15 @@ static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03)); - syscon |= (ENAWAKEUP | SIDLEMODE(0x02) | CLOCKACTIVITY(0x02)); + + spin_lock_irq(&mcbsp->lock); + if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) + syscon |= SIDLEMODE(0x02); + else + syscon |= SIDLEMODE(0x01); + spin_unlock_irq(&mcbsp->lock); + + syscon |= (ENAWAKEUP | CLOCKACTIVITY(0x02)); OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, XRDYEN | RRDYEN); -- cgit v0.10.2 From fa3935ba34667ffd35fbb33958cd1d67035fdf82 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 20 Aug 2009 16:18:19 +0300 Subject: OMAP: McBSP: Do not enable wakeups for no-idle mode When no-idle mode is taken, wakeups need not to be enabled. Moreover, CLOCKACTIVITY bits are unnecessary with this mode also. Signed-off-by: Eero Nurkkala Acked-by: Eduardo Valentin Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 85176a5..56a5688 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -319,16 +319,17 @@ static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03)); spin_lock_irq(&mcbsp->lock); - if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) - syscon |= SIDLEMODE(0x02); - else + if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { + syscon |= (ENAWAKEUP | SIDLEMODE(0x02) | + CLOCKACTIVITY(0x02)); + OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, + XRDYEN | RRDYEN); + } else { syscon |= SIDLEMODE(0x01); + } spin_unlock_irq(&mcbsp->lock); - syscon |= (ENAWAKEUP | CLOCKACTIVITY(0x02)); OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); - - OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, XRDYEN | RRDYEN); } } -- cgit v0.10.2 From 72cc6d715d5b018e2cff4adb68966855850d4e77 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 20 Aug 2009 16:18:20 +0300 Subject: OMAP: McBSP: Let element DMA mode hit retention also The device no longer hits retention if element DMA mode is taken for at least the duration of the serial console timeout. Force element DMA mode to shut down through smartidle. Signed-off-by: Eero Nurkkala Acked-by: Eduardo Valentin Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 56a5688..b63a720 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -343,6 +343,15 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03)); + /* + * HW bug workaround - If no_idle mode is taken, we need to + * go to smart_idle before going to always_idle, or the + * device will not hit retention anymore. + */ + syscon |= SIDLEMODE(0x02); + OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); + + syscon &= ~(SIDLEMODE(0x03)); OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, 0); -- cgit v0.10.2 From 9599d485cb0b5ea093414654d723f3ab03c95038 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:21 +0300 Subject: ASoC: OMAP: Enable DMA burst mode Improve DMA transfers by enabling Burst transaction. Signed-off-by: Eduardo Valentin Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 12e14c0..7cae7c4 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -195,6 +195,9 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) else omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); + omap_set_dma_src_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); + omap_set_dma_dest_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); + return 0; } -- cgit v0.10.2 From a152ff24b9784ddfd347953f23c53f0b890ebca8 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:22 +0300 Subject: ASoC: OMAP: Make DMA 64 aligned Align DMA address to DMA burst transaction sizes. Signed-off-by: Eduardo Valentin Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 7cae7c4..b9633d5 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -310,7 +310,7 @@ static struct snd_pcm_ops omap_pcm_ops = { .mmap = omap_pcm_mmap, }; -static u64 omap_pcm_dmamask = DMA_BIT_MASK(32); +static u64 omap_pcm_dmamask = DMA_BIT_MASK(64); static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) @@ -360,7 +360,7 @@ static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, if (!card->dev->dma_mask) card->dev->dma_mask = &omap_pcm_dmamask; if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = DMA_BIT_MASK(32); + card->dev->coherent_dma_mask = DMA_BIT_MASK(64); if (dai->playback.channels_min) { ret = omap_pcm_preallocate_dma_buffer(pcm, -- cgit v0.10.2 From c721bbdad71d2928e8b5015e9b462fbeb35427c6 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 20 Aug 2009 16:18:23 +0300 Subject: ASoC: Add runtime check for RFIG and XFIG This is, no RFIG or XFIG (Not defined in 34xx), correct initiliazation of rccr and xccr. Signed-off-by: Eero Nurkkala Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 6a837ff..a7b0961 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -321,8 +321,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, /* Generic McBSP register settings */ regs->spcr2 |= XINTM(3) | FREE; regs->spcr1 |= RINTM(3); - regs->rcr2 |= RFIG; - regs->xcr2 |= XFIG; + /* RFIG and XFIG are not defined in 34xx */ + if (!cpu_is_omap34xx()) { + regs->rcr2 |= RFIG; + regs->xcr2 |= XFIG; + } if (cpu_is_omap2430() || cpu_is_omap34xx()) { regs->xccr = DXENDLY(1) | XDMAEN; regs->rccr = RFULL_CYCLE | RDMAEN; -- cgit v0.10.2 From ca6e2ce08679c094878d7f39a0349a7db1d13675 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 20 Aug 2009 16:18:24 +0300 Subject: ASoC: Always syncronize audio transfers on frames All these steps are required for ASoC to behave correctly. rccr and xccr are format dependent, for example TDM audio has different values than I2S or DSP_A. Also the omap_mcbsp_xmit_enable and/or omap_mcbsp_recv_enable must be called right after the DMA has started. This provides no longer L and R channels switching at random. Signed-off-by: Eero Nurkkala Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index a7b0961..6e85508 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -191,6 +191,11 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: mcbsp_data->active++; omap_mcbsp_start(mcbsp_data->bus_id, play, !play); + /* Make sure data transfer is frame synchronized */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_mcbsp_xmit_enable(mcbsp_data->bus_id, 1); + else + omap_mcbsp_recv_enable(mcbsp_data->bus_id, 1); break; case SNDRV_PCM_TRIGGER_STOP: @@ -336,11 +341,15 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, /* 1-bit data delay */ regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); + regs->rccr |= RFULL_CYCLE | RDMAEN | RDISABLE; + regs->xccr |= (DXENDLY(1) | XDMAEN | XDISABLE); break; case SND_SOC_DAIFMT_DSP_A: /* 1-bit data delay */ regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); + regs->rccr |= RFULL_CYCLE | RDMAEN | RDISABLE; + regs->xccr |= (DXENDLY(1) | XDMAEN | XDISABLE); /* Invert FS polarity configuration */ temp_fmt ^= SND_SOC_DAIFMT_NB_IF; break; -- cgit v0.10.2 From caebc0cb3ba1e88f5311fbe7aa58b8dff18dd763 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:25 +0300 Subject: ASoC: OMAP: Use McBSP threshold to playback and capture This patch changes the way DMA is done in omap-pcm.c in order to reduce power consumption. There is no need to have so much SW control in order to have DMA in idle state during audio streaming. Configuring McBSP threshold value and DMA to FRAME_SYNC are sufficient. Signed-off-by: Eduardo Valentin Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 6e85508..580de5a 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -139,28 +139,59 @@ static const unsigned long omap34xx_mcbsp_port[][2] = { static const unsigned long omap34xx_mcbsp_port[][2] = {}; #endif +static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); + int samples = snd_pcm_lib_period_bytes(substream) >> 1; + + /* Configure McBSP internal buffer usage */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, samples - 1); + else + omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, samples - 1); +} + static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); + int bus_id = mcbsp_data->bus_id; int err = 0; - if (cpu_is_omap343x() && mcbsp_data->bus_id == 1) { + if (!cpu_dai->active) + err = omap_mcbsp_request(bus_id); + + if (cpu_is_omap343x()) { + int max_period; + /* * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer. * Set constraint for minimum buffer size to the same than FIFO * size in order to avoid underruns in playback startup because * HW is keeping the DMA request active until FIFO is filled. */ + if (bus_id == 1) + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + 4096, UINT_MAX); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + max_period = omap_mcbsp_get_max_tx_threshold(bus_id); + else + max_period = omap_mcbsp_get_max_rx_threshold(bus_id); + + max_period++; + max_period <<= 1; + snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4096, UINT_MAX); + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + 32, max_period); } - if (!cpu_dai->active) - err = omap_mcbsp_request(mcbsp_data->bus_id); - return err; } @@ -220,7 +251,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; - int wlen, channels, wpf; + int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; unsigned long port; unsigned int format; @@ -236,6 +267,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, } else if (cpu_is_omap343x()) { dma = omap24xx_dma_reqs[bus_id][substream->stream]; port = omap34xx_mcbsp_port[bus_id][substream->stream]; + omap_mcbsp_dai_dma_params[id][substream->stream].set_threshold = + omap_mcbsp_set_threshold; + sync_mode = OMAP_DMA_SYNC_FRAME; } else { return -ENODEV; } @@ -243,6 +277,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, substream->stream ? "Audio Capture" : "Audio Playback"; omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; + omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; if (mcbsp_data->configured) { diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index b9633d5..5735945 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -162,7 +162,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) */ dma_params.data_type = OMAP_DMA_DATA_TYPE_S16; dma_params.trigger = dma_data->dma_req; - dma_params.sync_mode = OMAP_DMA_SYNC_ELEMENT; + dma_params.sync_mode = dma_data->sync_mode; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dma_params.src_amode = OMAP_DMA_AMODE_POST_INC; dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT; @@ -205,6 +205,7 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct omap_runtime_data *prtd = runtime->private_data; + struct omap_pcm_dma_data *dma_data = prtd->dma_data; unsigned long flags; int ret = 0; @@ -214,6 +215,10 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: prtd->period_index = 0; + /* Configure McBSP internal buffer usage */ + if (dma_data->set_threshold) + dma_data->set_threshold(substream); + omap_start_dma(prtd->dma_ch); break; diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h index 8d9d269..38a821d 100644 --- a/sound/soc/omap/omap-pcm.h +++ b/sound/soc/omap/omap-pcm.h @@ -29,6 +29,8 @@ struct omap_pcm_dma_data { char *name; /* stream identifier */ int dma_req; /* DMA request line */ unsigned long port_addr; /* transmit/receive register */ + int sync_mode; /* DMA sync mode */ + void (*set_threshold)(struct snd_pcm_substream *substream); }; extern struct snd_soc_platform omap_soc_platform; -- cgit v0.10.2 From a0a499c5792b8656cd51e11d5e0db9fb21640f58 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 20 Aug 2009 16:18:26 +0300 Subject: ASoC: OMAP: Use DMA operating mode of McBSP Configures DMA sync mode depending on McBSP operating mode value. The value is configurable by McBSP instance. So, depending on McBSP operating mode, the DMA sync mode is passed from omap-mcbsp to omap-pcm. Besides that, it also configures McBSP threshold value depending on which McBSP mode is activated. Signed-off-by: Eduardo Valentin Acked-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 580de5a..f5387d9 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -144,7 +144,14 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); - int samples = snd_pcm_lib_period_bytes(substream) >> 1; + int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); + int samples; + + /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ + if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) + samples = snd_pcm_lib_period_bytes(substream) >> 1; + else + samples = 1; /* Configure McBSP internal buffer usage */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -166,6 +173,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, err = omap_mcbsp_request(bus_id); if (cpu_is_omap343x()) { + int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id); int max_period; /* @@ -187,7 +195,8 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, max_period++; max_period <<= 1; - snd_pcm_hw_constraint_minmax(substream->runtime, + if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) + snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32, max_period); } @@ -269,7 +278,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, port = omap34xx_mcbsp_port[bus_id][substream->stream]; omap_mcbsp_dai_dma_params[id][substream->stream].set_threshold = omap_mcbsp_set_threshold; - sync_mode = OMAP_DMA_SYNC_FRAME; + /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ + if (omap_mcbsp_get_dma_op_mode(bus_id) == + MCBSP_DMA_MODE_THRESHOLD) + sync_mode = OMAP_DMA_SYNC_FRAME; } else { return -ENODEV; } -- cgit v0.10.2 From 4dceef96756b667360741712a8e37490f8458516 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 20 Aug 2009 17:08:39 -0400 Subject: nfs: fix compile error in rpc_pipefs.h This include is needed for the definition of delayed_work. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index a92571a..cf14db9 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -3,6 +3,8 @@ #ifdef __KERNEL__ +#include + struct rpc_pipe_msg { struct list_head list; void *data; -- cgit v0.10.2 From bc6a6008e5e3c7a30191a7f19ab19e85b14b1705 Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Thu, 20 Aug 2009 19:29:02 -0700 Subject: selinux: adjust rules for ATTR_FORCE As suggested by OGAWA Hirofumi in thread: http://lkml.org/lkml/2009/8/7/132, we should let selinux_inode_setattr() to match our ATTR_* rules. ATTR_FORCE should not force things like ATTR_SIZE. [hirofumi@mail.parknet.co.jp: tweaks] Signed-off-by: WANG Cong Signed-off-by: OGAWA Hirofumi Acked-by: Stephen Smalley Acked-by: Eric Paris Cc: Eugene Teo Cc: Al Viro Cc: Christoph Hellwig Acked-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: James Morris diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6d0b1cc..ac79f9e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2711,12 +2711,18 @@ static int selinux_inode_permission(struct inode *inode, int mask) static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) { const struct cred *cred = current_cred(); + unsigned int ia_valid = iattr->ia_valid; + + /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ + if (ia_valid & ATTR_FORCE) { + ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE | + ATTR_FORCE); + if (!ia_valid) + return 0; + } - if (iattr->ia_valid & ATTR_FORCE) - return 0; - - if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | - ATTR_ATIME_SET | ATTR_MTIME_SET)) + if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | + ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); return dentry_has_perm(cred, NULL, dentry, FILE__WRITE); -- cgit v0.10.2 From 939a9421eb53d3ea83188ae13802779041caefdb Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Thu, 20 Aug 2009 19:29:03 -0700 Subject: vfs: allow file truncations when both suid and write permissions set When suid is set and the non-owner user has write permission, any writing into this file should be allowed and suid should be removed after that. However, current kernel only allows writing without truncations, when we do truncations on that file, we get EPERM. This is a bug. Steps to reproduce this bug: % ls -l rootdir/file1 -rwsrwsrwx 1 root root 3 Jun 25 15:42 rootdir/file1 % echo h > rootdir/file1 zsh: operation not permitted: rootdir/file1 % ls -l rootdir/file1 -rwsrwsrwx 1 root root 3 Jun 25 15:42 rootdir/file1 % echo h >> rootdir/file1 % ls -l rootdir/file1 -rwxrwxrwx 1 root root 5 Jun 25 16:34 rootdir/file1 Signed-off-by: WANG Cong Cc: Eric Sandeen Acked-by: Eric Paris Cc: Eugene Teo Cc: Al Viro Cc: OGAWA Hirofumi Cc: Christoph Hellwig Cc: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: James Morris diff --git a/fs/open.c b/fs/open.c index dd98e80..40d1fa2 100644 --- a/fs/open.c +++ b/fs/open.c @@ -199,7 +199,7 @@ out: int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, struct file *filp) { - int err; + int ret; struct iattr newattrs; /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ @@ -214,12 +214,14 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, } /* Remove suid/sgid on truncate too */ - newattrs.ia_valid |= should_remove_suid(dentry); + ret = should_remove_suid(dentry); + if (ret) + newattrs.ia_valid |= ret | ATTR_FORCE; mutex_lock(&dentry->d_inode->i_mutex); - err = notify_change(dentry, &newattrs); + ret = notify_change(dentry, &newattrs); mutex_unlock(&dentry->d_inode->i_mutex); - return err; + return ret; } static long do_sys_truncate(const char __user *pathname, loff_t length) -- cgit v0.10.2 From c7084b35eb1a4d3353a501508baf9d3d82822c93 Mon Sep 17 00:00:00 2001 From: Casey Dahlin Date: Thu, 20 Aug 2009 16:27:56 -0700 Subject: lib/swiotlb.c: Fix strange panic message selection logic when swiotlb fills up swiotlb_full() in lib/swiotlb.c throws one of two panic messages based on whether the direction of transfer is from the device or to the device. The logic around this is somewhat weird in the case of bidirectional transfers. It appears to want to throw both in succession, but since its a panic only the first makes it. This patch adds a third, separate error for DMA_BIDIRECTIONAL to make things a bit clearer. Signed-off-by: Casey Dahlin Cc: FUJITA Tomonori Cc: Becky Bruce [ further fixed the error message ] Signed-off-by: Andrew Morton LKML-Reference: <200908202327.n7KNRuqK001504@imap1.linux-foundation.org> Signed-off-by: Ingo Molnar diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 9e2fe3e..ac25cd2 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -581,12 +581,15 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic) printk(KERN_ERR "DMA: Out of SW-IOMMU space for %zu bytes at " "device %s\n", size, dev ? dev_name(dev) : "?"); - if (size > io_tlb_overflow && do_panic) { - if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) - panic("DMA: Memory would be corrupted\n"); - if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) - panic("DMA: Random memory would be DMAed\n"); - } + if (size <= io_tlb_overflow || !do_panic) + return; + + if (dir == DMA_BIDIRECTIONAL) + panic("DMA: Random memory could be DMA accessed\n"); + if (dir == DMA_FROM_DEVICE) + panic("DMA: Random memory could be DMA written\n"); + if (dir == DMA_TO_DEVICE) + panic("DMA: Random memory could be DMA read\n"); } /* -- cgit v0.10.2 From 14412acde5b57450b8afb3d4b03132419b6abebf Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 20 Aug 2009 22:50:40 +0100 Subject: ASoC: S3C24XX: Add audio core and tlv320aic23 for Simtec boards Add core support for the range of S3C24XX Simtec boards with TLV320AIC23 CODECs on them. Since there are also boards with similar IIS routing the AMP and the configuration code is placed in a core file for re-use with other CODEC bindings. Signed-off-by: Ben Dooks Signed-off-by: Mark Brown diff --git a/arch/arm/plat-s3c/include/plat/audio-simtec.h b/arch/arm/plat-s3c/include/plat/audio-simtec.h new file mode 100644 index 0000000..0f440b9 --- /dev/null +++ b/arch/arm/plat-s3c/include/plat/audio-simtec.h @@ -0,0 +1,37 @@ +/* arch/arm/plat-s3c/include/plat/audio-simtec.h + * + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * 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 + * published by the Free Software Foundation. + * + * Simtec Audio support. +*/ + +/** + * struct s3c24xx_audio_simtec_pdata - platform data for simtec audio + * @use_mpllin: Select codec clock from MPLLin + * @output_cdclk: Need to output CDCLK to the codec + * @have_mic: Set if we have a MIC socket + * @have_lout: Set if we have a LineOut socket + * @amp_gpio: GPIO pin to enable the AMP + * @amp_gain: Option GPIO to control AMP gain + */ +struct s3c24xx_audio_simtec_pdata { + unsigned int use_mpllin:1; + unsigned int output_cdclk:1; + + unsigned int have_mic:1; + unsigned int have_lout:1; + + int amp_gpio; + int amp_gain[2]; + + void (*startup)(void); +}; + +extern int simtec_audio_add(const char *codec_name, + struct s3c24xx_audio_simtec_pdata *pdata); diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 2987239..78cfd8d 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -79,3 +79,15 @@ config SND_S3C24XX_SOC_S3C24XX_UDA134X select SND_S3C24XX_SOC_I2S select SND_SOC_L3 select SND_SOC_UDA134X + +config SND_S3C24XX_SOC_SIMTEC + tristate + help + Internal node for common S3C24XX/Simtec suppor + +config SND_S3C24XX_SOC_SIMTEC_TLV320AIC23 + tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" + depends on SND_S3C24XX_SOC + select SND_S3C24XX_SOC_I2S + select SND_SOC_TLV320AIC23 + select SND_S3C24XX_SOC_SIMTEC diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index eb219b0..1ccbb87 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -20,6 +20,8 @@ snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o +snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o +snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o @@ -27,3 +29,5 @@ obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm87 obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o +obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o +obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c new file mode 100644 index 0000000..1966e0d --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec.c @@ -0,0 +1,394 @@ +/* sound/soc/s3c24xx/s3c24xx_simtec.c + * + * Copyright 2009 Simtec Electronics + * + * 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 + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "s3c24xx-pcm.h" +#include "s3c24xx-i2s.h" +#include "s3c24xx_simtec.h" + +static struct s3c24xx_audio_simtec_pdata *pdata; +static struct clk *xtal_clk; + +static int spk_gain; +static int spk_unmute; + +/** + * speaker_gain_get - read the speaker gain setting. + * @kcontrol: The control for the speaker gain. + * @ucontrol: The value that needs to be updated. + * + * Read the value for the AMP gain control. + */ +static int speaker_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = spk_gain; + return 0; +} + +/** + * speaker_gain_set - set the value of the speaker amp gain + * @value: The value to write. + */ +static void speaker_gain_set(int value) +{ + gpio_set_value_cansleep(pdata->amp_gain[0], value & 1); + gpio_set_value_cansleep(pdata->amp_gain[1], value >> 1); +} + +/** + * speaker_gain_put - set the speaker gain setting. + * @kcontrol: The control for the speaker gain. + * @ucontrol: The value that needs to be set. + * + * Set the value of the speaker gain from the specified + * @ucontrol setting. + * + * Note, if the speaker amp is muted, then we do not set a gain value + * as at-least one of the ICs that is fitted will try and power up even + * if the main control is set to off. + */ +static int speaker_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int value = ucontrol->value.integer.value[0]; + + spk_gain = value; + + if (!spk_unmute) + speaker_gain_set(value); + + return 0; +} + +static const struct snd_kcontrol_new amp_gain_controls[] = { + SOC_SINGLE_EXT("Speaker Gain", 0, 0, 3, 0, + speaker_gain_get, speaker_gain_put), +}; + +/** + * spk_unmute_state - set the unmute state of the speaker + * @to: zero to unmute, non-zero to ununmute. + */ +static void spk_unmute_state(int to) +{ + pr_debug("%s: to=%d\n", __func__, to); + + spk_unmute = to; + gpio_set_value(pdata->amp_gpio, to); + + /* if we're umuting, also re-set the gain */ + if (to && pdata->amp_gain[0] > 0) + speaker_gain_set(spk_gain); +} + +/** + * speaker_unmute_get - read the speaker unmute setting. + * @kcontrol: The control for the speaker gain. + * @ucontrol: The value that needs to be updated. + * + * Read the value for the AMP gain control. + */ +static int speaker_unmute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = spk_unmute; + return 0; +} + +/** + * speaker_unmute_put - set the speaker unmute setting. + * @kcontrol: The control for the speaker gain. + * @ucontrol: The value that needs to be set. + * + * Set the value of the speaker gain from the specified + * @ucontrol setting. + */ +static int speaker_unmute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + spk_unmute_state(ucontrol->value.integer.value[0]); + return 0; +} + +/* This is added as a manual control as the speaker amps create clicks + * when their power state is changed, which are far more noticeable than + * anything produced by the CODEC itself. + */ +static const struct snd_kcontrol_new amp_unmute_controls[] = { + SOC_SINGLE_EXT("Speaker Switch", 0, 0, 1, 0, + speaker_unmute_get, speaker_unmute_put), +}; + +void simtec_audio_init(struct snd_soc_codec *codec) +{ + if (pdata->amp_gpio > 0) { + pr_debug("%s: adding amp routes\n", __func__); + + snd_soc_add_controls(codec, amp_unmute_controls, + ARRAY_SIZE(amp_unmute_controls)); + } + + if (pdata->amp_gain[0] > 0) { + pr_debug("%s: adding amp controls\n", __func__); + snd_soc_add_controls(codec, amp_gain_controls, + ARRAY_SIZE(amp_gain_controls)); + } +} +EXPORT_SYMBOL_GPL(simtec_audio_init); + +#define CODEC_CLOCK 12000000 + +/** + * simtec_hw_params - update hardware parameters + * @substream: The audio substream instance. + * @params: The parameters requested. + * + * Update the codec data routing and configuration settings + * from the supplied data. + */ +static int simtec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set the CODEC as the bus clock master, I2S */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret) { + pr_err("%s: failed set cpu dai format\n", __func__); + return ret; + } + + /* Set the CODEC as the bus clock master */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret) { + pr_err("%s: failed set codec dai format\n", __func__); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, + CODEC_CLOCK, SND_SOC_CLOCK_IN); + if (ret) { + pr_err( "%s: failed setting codec sysclk\n", __func__); + return ret; + } + + if (pdata->use_mpllin) { + ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_MPLL, + 0, SND_SOC_CLOCK_OUT); + + if (ret) { + pr_err("%s: failed to set MPLLin as clksrc\n", + __func__); + return ret; + } + } + + if (pdata->output_cdclk) { + int cdclk_scale; + + cdclk_scale = clk_get_rate(xtal_clk) / CODEC_CLOCK; + cdclk_scale--; + + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, + cdclk_scale); + } + + return 0; +} + +static int simtec_call_startup(struct s3c24xx_audio_simtec_pdata *pd) +{ + /* call any board supplied startup code, this currently only + * covers the bast/vr1000 which have a CPLD in the way of the + * LRCLK */ + if (pd->startup) + pd->startup(); + + return 0; +} + +static struct snd_soc_ops simtec_snd_ops = { + .hw_params = simtec_hw_params, +}; + +/** + * attach_gpio_amp - get and configure the necessary gpios + * @dev: The device we're probing. + * @pd: The platform data supplied by the board. + * + * If there is a GPIO based amplifier attached to the board, claim + * the necessary GPIO lines for it, and set default values. + */ +static int attach_gpio_amp(struct device *dev, + struct s3c24xx_audio_simtec_pdata *pd) +{ + int ret; + + /* attach gpio amp gain (if any) */ + if (pdata->amp_gain[0] > 0) { + ret = gpio_request(pd->amp_gain[0], "gpio-amp-gain0"); + if (ret) { + dev_err(dev, "cannot get amp gpio gain0\n"); + return ret; + } + + ret = gpio_request(pd->amp_gain[1], "gpio-amp-gain1"); + if (ret) { + dev_err(dev, "cannot get amp gpio gain1\n"); + gpio_free(pdata->amp_gain[0]); + return ret; + } + + gpio_direction_output(pd->amp_gain[0], 0); + gpio_direction_output(pd->amp_gain[1], 0); + } + + /* note, curently we assume GPA0 isn't valid amp */ + if (pdata->amp_gpio > 0) { + ret = gpio_request(pd->amp_gpio, "gpio-amp"); + if (ret) { + dev_err(dev, "cannot get amp gpio %d (%d)\n", + pd->amp_gpio, ret); + goto err_amp; + } + + /* set the amp off at startup */ + spk_unmute_state(0); + } + + return 0; + +err_amp: + if (pd->amp_gain[0] > 0) { + gpio_free(pd->amp_gain[0]); + gpio_free(pd->amp_gain[1]); + } + + return ret; +} + +static void detach_gpio_amp(struct s3c24xx_audio_simtec_pdata *pd) +{ + if (pd->amp_gain[0] > 0) { + gpio_free(pd->amp_gain[0]); + gpio_free(pd->amp_gain[1]); + } + + if (pd->amp_gpio > 0) + gpio_free(pd->amp_gpio); +} + +#ifdef CONFIG_PM +int simtec_audio_resume(struct device *dev) +{ + simtec_call_startup(pdata); + return 0; +} + +struct dev_pm_ops simtec_audio_pmops = { + .resume = simtec_audio_resume, +}; +EXPORT_SYMBOL_GPL(simtec_audio_pmops); +#endif + +int __devinit simtec_audio_core_probe(struct platform_device *pdev, + struct snd_soc_device *socdev) +{ + struct platform_device *snd_dev; + int ret; + + socdev->card->dai_link->ops = &simtec_snd_ops; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "no platform data supplied\n"); + return -EINVAL; + } + + simtec_call_startup(pdata); + + xtal_clk = clk_get(&pdev->dev, "xtal"); + if (IS_ERR(xtal_clk)) { + dev_err(&pdev->dev, "could not get clkout0\n"); + return -EINVAL; + } + + dev_info(&pdev->dev, "xtal rate is %ld\n", clk_get_rate(xtal_clk)); + + ret = attach_gpio_amp(&pdev->dev, pdata); + if (ret) + goto err_clk; + + snd_dev = platform_device_alloc("soc-audio", -1); + if (!snd_dev) { + dev_err(&pdev->dev, "failed to alloc soc-audio devicec\n"); + ret = -ENOMEM; + goto err_gpio; + } + + platform_set_drvdata(snd_dev, socdev); + socdev->dev = &snd_dev->dev; + + ret = platform_device_add(snd_dev); + if (ret) { + dev_err(&pdev->dev, "failed to add soc-audio dev\n"); + goto err_pdev; + } + + platform_set_drvdata(pdev, snd_dev); + return 0; + +err_pdev: + platform_device_put(snd_dev); + +err_gpio: + detach_gpio_amp(pdata); + +err_clk: + clk_put(xtal_clk); + return ret; +} +EXPORT_SYMBOL_GPL(simtec_audio_core_probe); + +int __devexit simtec_audio_remove(struct platform_device *pdev) +{ + struct platform_device *snd_dev = platform_get_drvdata(pdev); + + platform_device_unregister(snd_dev); + + detach_gpio_amp(pdata); + clk_put(xtal_clk); + return 0; +} +EXPORT_SYMBOL_GPL(simtec_audio_remove); + +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("ALSA SoC Simtec Audio common support"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.h b/sound/soc/s3c24xx/s3c24xx_simtec.h new file mode 100644 index 0000000..2714203 --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec.h @@ -0,0 +1,22 @@ +/* sound/soc/s3c24xx/s3c24xx_simtec.h + * + * Copyright 2009 Simtec Electronics + * + * 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 + * published by the Free Software Foundation. +*/ + +extern void simtec_audio_init(struct snd_soc_codec *codec); + +extern int simtec_audio_core_probe(struct platform_device *pdev, + struct snd_soc_device *socdev); + +extern int simtec_audio_remove(struct platform_device *pdev); + +#ifdef CONFIG_PM +extern struct dev_pm_ops simtec_audio_pmops; +#define simtec_audio_pm &simtec_audio_pmops +#else +#define simtec_audio_pm NULL +#endif diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c new file mode 100644 index 0000000..25797e0 --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c @@ -0,0 +1,137 @@ +/* sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c + * + * Copyright 2009 Simtec Electronics + * + * 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 + * published by the Free Software Foundation. +*/ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "s3c24xx-pcm.h" +#include "s3c24xx-i2s.h" +#include "s3c24xx_simtec.h" + +#include "../codecs/tlv320aic23.h" + +/* supported machines: + * + * Machine Connections AMP + * ------- ----------- --- + * BAST MIC, HPOUT, LOUT, LIN TPA2001D1 (HPOUTL,R) (gain hardwired) + * VR1000 HPOUT, LIN None + * VR2000 LIN, LOUT, MIC, HP LM4871 (HPOUTL,R) + * DePicture LIN, LOUT, MIC, HP LM4871 (HPOUTL,R) + * Anubis LIN, LOUT, MIC, HP TPA2001D1 (HPOUTL,R) + */ + +static const struct snd_soc_dapm_widget dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), +}; + +static const struct snd_soc_dapm_route base_map[] = { + { "Headphone Jack", NULL, "LHPOUT"}, + { "Headphone Jack", NULL, "RHPOUT"}, + + { "Line Out", NULL, "LOUT" }, + { "Line Out", NULL, "ROUT" }, + + { "LLINEIN", NULL, "Line In"}, + { "RLINEIN", NULL, "Line In"}, + + { "MICIN", NULL, "Mic Jack"}, +}; + +/** + * simtec_tlv320aic23_init - initialise and add controls + * @codec; The codec instance to attach to. + * + * Attach our controls and configure the necessary codec + * mappings for our sound card instance. +*/ +static int simtec_tlv320aic23_init(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, dapm_widgets, + ARRAY_SIZE(dapm_widgets)); + + snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map)); + + snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + snd_soc_dapm_enable_pin(codec, "Line In"); + snd_soc_dapm_enable_pin(codec, "Line Out"); + snd_soc_dapm_enable_pin(codec, "Mic Jack"); + + simtec_audio_init(codec); + snd_soc_dapm_sync(codec); + + return 0; +} + +static struct snd_soc_dai_link simtec_dai_aic23 = { + .name = "tlv320aic23", + .stream_name = "TLV320AIC23", + .cpu_dai = &s3c24xx_i2s_dai, + .codec_dai = &tlv320aic23_dai, + .init = simtec_tlv320aic23_init, +}; + +/* simtec audio machine driver */ +static struct snd_soc_card snd_soc_machine_simtec_aic23 = { + .name = "Simtec", + .platform = &s3c24xx_soc_platform, + .dai_link = &simtec_dai_aic23, + .num_links = 1, +}; + +/* simtec audio subsystem */ +static struct snd_soc_device simtec_snd_devdata_aic23 = { + .card = &snd_soc_machine_simtec_aic23, + .codec_dev = &soc_codec_dev_tlv320aic23, +}; + +static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd) +{ + return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic23); +} + +static struct platform_driver simtec_audio_tlv320aic23_platdrv = { + .driver = { + .owner = THIS_MODULE, + .name = "s3c24xx-simtec-tlv320aic23", + .pm = simtec_audio_pm, + }, + .probe = simtec_audio_tlv320aic23_probe, + .remove = __devexit_p(simtec_audio_remove), +}; + +MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23"); + +static int __init simtec_tlv320aic23_modinit(void) +{ + return platform_driver_register(&simtec_audio_tlv320aic23_platdrv); +} + +static void __exit simtec_tlv320aic23_modexit(void) +{ + platform_driver_unregister(&simtec_audio_tlv320aic23_platdrv); +} + +module_init(simtec_tlv320aic23_modinit); +module_exit(simtec_tlv320aic23_modexit); + +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("ALSA SoC Simtec Audio support"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From cb3826f524728a90a47f2f831c3d61851c8091b2 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 20 Aug 2009 22:50:41 +0100 Subject: ASoC: tlv320aic3x: Change to use device model The tlv320aic3x driver managed its own i2c device, instead of an extant one created by the board support code. Change the code to make it so that the driver binds to an extant (in this case i2c) device. Add explict tlv320aic33 as well as tlv320aic3x to the supported device table and remove the old driver bindings from the users of this code. Signed-off-by: Ben Dooks Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 126b15b..5d54767 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -53,6 +53,7 @@ /* codec private data */ struct aic3x_priv { + struct snd_soc_codec codec; unsigned int sysclk; int master; }; @@ -1156,11 +1157,13 @@ static int aic3x_resume(struct platform_device *pdev) * initialise the AIC3X driver * register the mixer and dsp interfaces with the kernel */ -static int aic3x_init(struct snd_soc_device *socdev) +static int aic3x_init(struct snd_soc_codec *codec) { - struct snd_soc_codec *codec = socdev->card->codec; - struct aic3x_setup_data *setup = socdev->codec_data; - int reg, ret = 0; + int reg; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); codec->name = "tlv320aic3x"; codec->owner = THIS_MODULE; @@ -1177,13 +1180,6 @@ static int aic3x_init(struct snd_soc_device *socdev) aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); aic3x_write(codec, AIC3X_RESET, SOFT_RESET); - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "aic3x: failed to create pcms\n"); - goto pcm_err; - } - /* DAC default volume and mute */ aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); @@ -1250,30 +1246,51 @@ static int aic3x_init(struct snd_soc_device *socdev) /* off, with power on */ aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* setup GPIO functions */ - aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); - aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); + return 0; +} - snd_soc_add_controls(codec, aic3x_snd_controls, - ARRAY_SIZE(aic3x_snd_controls)); - aic3x_add_widgets(codec); - ret = snd_soc_init_card(socdev); +static struct snd_soc_codec *aic3x_codec; + +static int aic3x_register(struct snd_soc_codec *codec) +{ + int ret; + + ret = aic3x_init(codec); if (ret < 0) { - printk(KERN_ERR "aic3x: failed to register card\n"); - goto card_err; + dev_err(codec->dev, "Failed to initialise device\n"); + return ret; } - return ret; + aic3x_codec = codec; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - return ret; + ret = snd_soc_register_codec(codec); + if (ret) { + dev_err(codec->dev, "Failed to register codec\n"); + return ret; + } + + ret = snd_soc_register_dai(&aic3x_dai); + if (ret) { + dev_err(codec->dev, "Failed to register dai\n"); + snd_soc_unregister_codec(codec); + return ret; + } + + return 0; } -static struct snd_soc_device *aic3x_socdev; +static int aic3x_unregister(struct aic3x_priv *aic3x) +{ + aic3x_set_bias_level(&aic3x->codec, SND_SOC_BIAS_OFF); + + snd_soc_unregister_dai(&aic3x_dai); + snd_soc_unregister_codec(&aic3x->codec); + + kfree(aic3x); + aic3x_codec = NULL; + + return 0; +} #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) /* @@ -1288,28 +1305,36 @@ static struct snd_soc_device *aic3x_socdev; static int aic3x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct snd_soc_device *socdev = aic3x_socdev; - struct snd_soc_codec *codec = socdev->card->codec; - int ret; + struct snd_soc_codec *codec; + struct aic3x_priv *aic3x; - i2c_set_clientdata(i2c, codec); + aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); + if (aic3x == NULL) { + dev_err(&i2c->dev, "failed to create private data\n"); + return -ENOMEM; + } + + codec = &aic3x->codec; + codec->dev = &i2c->dev; + codec->private_data = aic3x; codec->control_data = i2c; + codec->hw_write = (hw_write_t) i2c_master_send; - ret = aic3x_init(socdev); - if (ret < 0) - printk(KERN_ERR "aic3x: failed to initialise AIC3X\n"); - return ret; + i2c_set_clientdata(i2c, aic3x); + + return aic3x_register(codec); } static int aic3x_i2c_remove(struct i2c_client *client) { - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); - return 0; + struct aic3x_priv *aic3x = i2c_get_clientdata(client); + + return aic3x_unregister(aic3x); } static const struct i2c_device_id aic3x_i2c_id[] = { { "tlv320aic3x", 0 }, + { "tlv320aic33", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); @@ -1320,50 +1345,28 @@ static struct i2c_driver aic3x_i2c_driver = { .name = "aic3x I2C Codec", .owner = THIS_MODULE, }, - .probe = aic3x_i2c_probe, + .probe = aic3x_i2c_probe, .remove = aic3x_i2c_remove, .id_table = aic3x_i2c_id, }; -static int aic3x_add_i2c_device(struct platform_device *pdev, - const struct aic3x_setup_data *setup) +static inline void aic3x_i2c_init(void) { - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; int ret; ret = i2c_add_driver(&aic3x_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = setup->i2c_address; - strlcpy(info.type, "tlv320aic3x", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "can't get i2c adapter %d\n", - setup->i2c_bus); - goto err_driver; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - goto err_driver; - } - - return 0; + if (ret) + printk(KERN_ERR "%s: error regsitering i2c driver, %d\n", + __func__, ret); +} -err_driver: +static inline void aic3x_i2c_exit(void) +{ i2c_del_driver(&aic3x_i2c_driver); - return -ENODEV; } +#else +static inline void aic3x_i2c_init(void) { } +static inline void aic3x_i2c_exit(void) { } #endif static int aic3x_probe(struct platform_device *pdev) @@ -1371,42 +1374,52 @@ static int aic3x_probe(struct platform_device *pdev) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct aic3x_setup_data *setup; struct snd_soc_codec *codec; - struct aic3x_priv *aic3x; int ret = 0; - printk(KERN_INFO "AIC3X Audio Codec %s\n", AIC3X_VERSION); + codec = aic3x_codec; + if (!codec) { + dev_err(&pdev->dev, "Codec not registered\n"); + return -ENODEV; + } + socdev->card->codec = codec; setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); - if (aic3x == NULL) { - kfree(codec); - return -ENOMEM; + if (!setup) { + dev_err(&pdev->dev, "No setup data supplied\n"); + return -EINVAL; } - codec->private_data = aic3x; - socdev->card->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); + /* setup GPIO functions */ + aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); + aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); - aic3x_socdev = socdev; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - codec->hw_write = (hw_write_t) i2c_master_send; - ret = aic3x_add_i2c_device(pdev, setup); + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "aic3x: failed to create pcms\n"); + goto pcm_err; } -#else - /* Add other interfaces here */ -#endif - if (ret != 0) { - kfree(codec->private_data); - kfree(codec); + snd_soc_add_controls(codec, aic3x_snd_controls, + ARRAY_SIZE(aic3x_snd_controls)); + + aic3x_add_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + printk(KERN_ERR "aic3x: failed to register card\n"); + goto card_err; } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + +pcm_err: + kfree(codec->reg_cache); return ret; } @@ -1421,12 +1434,8 @@ static int aic3x_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_unregister_device(codec->control_data); - i2c_del_driver(&aic3x_i2c_driver); -#endif - kfree(codec->private_data); - kfree(codec); + + kfree(codec->reg_cache); return 0; } @@ -1441,13 +1450,15 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); static int __init aic3x_modinit(void) { - return snd_soc_register_dai(&aic3x_dai); + aic3x_i2c_init(); + + return 0; } module_init(aic3x_modinit); static void __exit aic3x_exit(void) { - snd_soc_unregister_dai(&aic3x_dai); + aic3x_i2c_exit(); } module_exit(aic3x_exit); diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index ac827e5..9af1c88 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -282,8 +282,6 @@ int aic3x_headset_detected(struct snd_soc_codec *codec); int aic3x_button_pressed(struct snd_soc_codec *codec); struct aic3x_setup_data { - int i2c_bus; - unsigned short i2c_address; unsigned int gpio_func[2]; }; diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 46c1b0c..396d777 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -207,8 +207,6 @@ static struct snd_soc_card da850_snd_soc_card = { /* evm audio private data */ static struct aic3x_setup_data evm_aic3x_setup = { - .i2c_bus = 1, - .i2c_address = 0x1b, }; /* dm6467 evm audio private data */ diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index b60b1df..4d3aec2 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -322,8 +322,6 @@ static struct snd_soc_card snd_soc_n810 = { /* Audio private data */ static struct aic3x_setup_data n810_aic33_setup = { - .i2c_bus = 2, - .i2c_address = 0x18, .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED, .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT, }; diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c index b5f95f9..082215d 100644 --- a/sound/soc/s6000/s6105-ipcam.c +++ b/sound/soc/s6000/s6105-ipcam.c @@ -189,8 +189,6 @@ static struct snd_soc_card snd_soc_card_s6105 = { /* s6105 audio private data */ static struct aic3x_setup_data s6105_aic3x_setup = { - .i2c_bus = 0, - .i2c_address = 0x18, }; /* s6105 audio subsystem */ -- cgit v0.10.2 From aa6b904e66d5f484bd52763d63259b9a16f6e107 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 20 Aug 2009 22:50:42 +0100 Subject: ASoC: tlv320aic3x: fixup board device changes Fixup the device changes by modifying the files that we just removed the explicit device creation from with i2c_register_board_info() until this can be moved into the relevant board files. Signed-off-by: Ben Dooks Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 396d777..0190c1b 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -249,6 +250,13 @@ static struct snd_soc_device da850_evm_snd_devdata = { static struct platform_device *evm_snd_device; +/* temporary i2c device creation until this can be moved into the machine + * support file. +*/ +static struct i2c_board_info i2c_device[] = { + { I2C_BOARD_INFO("tlv320aic33", 0x1b), } +}; + static int __init evm_init(void) { struct snd_soc_device *evm_snd_dev_data; @@ -273,6 +281,8 @@ static int __init evm_init(void) } else return -EINVAL; + i2c_register_board_info(1, i2c_device, ARRAY_SIZE(i2c_device)); + evm_snd_device = platform_device_alloc("soc-audio", index); if (!evm_snd_device) return -ENOMEM; diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 4d3aec2..0a50593 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -335,6 +336,13 @@ static struct snd_soc_device n810_snd_devdata = { static struct platform_device *n810_snd_device; +/* temporary i2c device creation until this can be moved into the machine + * support file. +*/ +static struct i2c_board_info i2c_device[] = { + { I2C_BOARD_INFO("tlv320aic3x", 0x1b), } +}; + static int __init n810_soc_init(void) { int err; @@ -343,6 +351,8 @@ static int __init n810_soc_init(void) if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax())) return -ENODEV; + i2c_register_board_info(1, i2c_device, ARRAY_SIZE(i2c_device)); + n810_snd_device = platform_device_alloc("soc-audio", -1); if (!n810_snd_device) return -ENOMEM; diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c index 082215d..c1b40ac 100644 --- a/sound/soc/s6000/s6105-ipcam.c +++ b/sound/soc/s6000/s6105-ipcam.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -209,10 +210,19 @@ static struct s6000_snd_platform_data __initdata s6105_snd_data = { static struct platform_device *s6105_snd_device; +/* temporary i2c device creation until this can be moved into the machine + * support file. +*/ +static struct i2c_board_info i2c_device[] = { + { I2C_BOARD_INFO("tlv320aic33", 0x18), } +}; + static int __init s6105_init(void) { int ret; + i2c_register_board_info(0, i2c_device, ARRAY_SIZE(i2c_device)); + s6105_snd_device = platform_device_alloc("soc-audio", -1); if (!s6105_snd_device) return -ENOMEM; -- cgit v0.10.2 From b2ec22e2633996727f4f2abcd806aaeb0506dd6a Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 20 Aug 2009 22:50:43 +0100 Subject: ASoC: S3C24XX: Support for Simtec Hermes boards Add support for the tlv320aic3x CODEC on the Simtec Hermes board. Signed-off-by: Ben Dooks Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 78cfd8d..f8e0fff 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -91,3 +91,10 @@ config SND_S3C24XX_SOC_SIMTEC_TLV320AIC23 select SND_S3C24XX_SOC_I2S select SND_SOC_TLV320AIC23 select SND_S3C24XX_SOC_SIMTEC + +config SND_S3C24XX_SOC_SIMTEC_HERMES + tristate "SoC I2S Audio support for Simtec Hermes board" + depends on SND_S3C24XX_SOC + select SND_S3C24XX_SOC_I2S + select SND_SOC_TLV320AIC3X + select SND_S3C24XX_SOC_SIMTEC diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 1ccbb87..99f5a7d 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -21,6 +21,7 @@ snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o +snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o @@ -30,4 +31,6 @@ obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o +obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o + diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c new file mode 100644 index 0000000..8346bd9 --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c @@ -0,0 +1,153 @@ +/* sound/soc/s3c24xx/s3c24xx_simtec_hermes.c + * + * Copyright 2009 Simtec Electronics + * + * 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 + * published by the Free Software Foundation. +*/ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "s3c24xx-pcm.h" +#include "s3c24xx-i2s.h" +#include "s3c24xx_simtec.h" + +#include "../codecs/tlv320aic3x.h" + +static const struct snd_soc_dapm_widget dapm_widgets[] = { + SND_SOC_DAPM_LINE("GSM Out", NULL), + SND_SOC_DAPM_LINE("GSM In", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_LINE("ZV", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), +}; + +static const struct snd_soc_dapm_route base_map[] = { + /* Headphone connected to HP{L,R}OUT and HP{L,R}COM */ + + { "Headphone Jack", NULL, "HPLOUT" }, + { "Headphone Jack", NULL, "HPLCOM" }, + { "Headphone Jack", NULL, "HPROUT" }, + { "Headphone Jack", NULL, "HPRCOM" }, + + /* ZV connected to Line1 */ + + { "LINE1L", NULL, "ZV" }, + { "LINE1R", NULL, "ZV" }, + + /* Line In connected to Line2 */ + + { "LINE2L", NULL, "Line In" }, + { "LINE2R", NULL, "Line In" }, + + /* Microphone connected to MIC3R and MIC_BIAS */ + + { "MIC3L", NULL, "Mic Jack" }, + + /* GSM connected to MONO_LOUT and MIC3L (in) */ + + { "GSM Out", NULL, "MONO_LOUT" }, + { "MIC3L", NULL, "GSM In" }, + + /* Speaker is connected to LINEOUT{LN,LP,RN,RP}, however we are + * not using the DAPM to power it up and down as there it makes + * a click when powering up. */ +}; + +/** + * simtec_hermes_init - initialise and add controls + * @codec; The codec instance to attach to. + * + * Attach our controls and configure the necessary codec + * mappings for our sound card instance. +*/ +static int simtec_hermes_init(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, dapm_widgets, + ARRAY_SIZE(dapm_widgets)); + + snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map)); + + snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + snd_soc_dapm_enable_pin(codec, "Line In"); + snd_soc_dapm_enable_pin(codec, "Line Out"); + snd_soc_dapm_enable_pin(codec, "Mic Jack"); + + simtec_audio_init(codec); + snd_soc_dapm_sync(codec); + + return 0; +} + +static struct aic3x_setup_data codec_setup = { +}; + +static struct snd_soc_dai_link simtec_dai_aic33 = { + .name = "tlv320aic33", + .stream_name = "TLV320AIC33", + .cpu_dai = &s3c24xx_i2s_dai, + .codec_dai = &aic3x_dai, + .init = simtec_hermes_init, +}; + +/* simtec audio machine driver */ +static struct snd_soc_card snd_soc_machine_simtec_aic33 = { + .name = "Simtec-Hermes", + .platform = &s3c24xx_soc_platform, + .dai_link = &simtec_dai_aic33, + .num_links = 1, +}; + +/* simtec audio subsystem */ +static struct snd_soc_device simtec_snd_devdata_aic33 = { + .card = &snd_soc_machine_simtec_aic33, + .codec_dev = &soc_codec_dev_aic3x, + .codec_data = &codec_setup, +}; + +static int __devinit simtec_audio_hermes_probe(struct platform_device *pd) +{ + dev_info(&pd->dev, "probing....\n"); + return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic33); +} + +static struct platform_driver simtec_audio_hermes_platdrv = { + .driver = { + .owner = THIS_MODULE, + .name = "s3c24xx-simtec-hermes-snd", + .pm = simtec_audio_pm, + }, + .probe = simtec_audio_hermes_probe, + .remove = __devexit_p(simtec_audio_remove), +}; + +MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd"); + +static int __init simtec_hermes_modinit(void) +{ + return platform_driver_register(&simtec_audio_hermes_platdrv); +} + +static void __exit simtec_hermes_modexit(void) +{ + platform_driver_unregister(&simtec_audio_hermes_platdrv); +} + +module_init(simtec_hermes_modinit); +module_exit(simtec_hermes_modexit); + +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("ALSA SoC Simtec Audio support"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From a3a83d9a7cb0ce3b1d100060d5ad777e7480b4f2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 21 Aug 2009 10:23:41 +0900 Subject: ASoC: Add ak4642/ak4643 codec support This is very simple driver for ALSA It supprt headphone output and stereo input only This patch is tested by ms7724se Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 167a5ce..0edca93 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -18,6 +18,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AD73311 if I2C select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C + select SND_SOC_AK4642 if I2C select SND_SOC_CS4270 if I2C select SND_SOC_MAX9877 if I2C select SND_SOC_PCM3008 @@ -92,6 +93,9 @@ config SND_SOC_AK4104 config SND_SOC_AK4535 tristate +config SND_SOC_AK4642 + tristate + # Cirrus Logic CS4270 Codec config SND_SOC_CS4270 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fbab43b..fb4af28 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -5,6 +5,7 @@ snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o +snd-soc-ak4642-objs := ak4642.o snd-soc-cs4270-objs := cs4270.o snd-soc-cx20442-objs := cx20442.o snd-soc-l3-objs := l3.o @@ -54,6 +55,7 @@ obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o +obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c new file mode 100644 index 0000000..e057c7b --- /dev/null +++ b/sound/soc/codecs/ak4642.c @@ -0,0 +1,502 @@ +/* + * ak4642.c -- AK4642/AK4643 ALSA Soc Audio driver + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto + * + * Based on wm8731.c by Richard Purdie + * Based on ak4535.c by Richard Purdie + * Based on wm8753.c by Liam Girdwood + * + * 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 + * published by the Free Software Foundation. + */ + +/* ** CAUTION ** + * + * This is very simple driver. + * It can use headphone output / stereo input only + * + * AK4642 is not tested. + * AK4643 is tested. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ak4642.h" + +#define AK4642_VERSION "0.0.1" + +#define PW_MGMT1 0x00 +#define PW_MGMT2 0x01 +#define SG_SL1 0x02 +#define SG_SL2 0x03 +#define MD_CTL1 0x04 +#define MD_CTL2 0x05 +#define TIMER 0x06 +#define ALC_CTL1 0x07 +#define ALC_CTL2 0x08 +#define L_IVC 0x09 +#define L_DVC 0x0a +#define ALC_CTL3 0x0b +#define R_IVC 0x0c +#define R_DVC 0x0d +#define MD_CTL3 0x0e +#define MD_CTL4 0x0f +#define PW_MGMT3 0x10 +#define DF_S 0x11 +#define FIL3_0 0x12 +#define FIL3_1 0x13 +#define FIL3_2 0x14 +#define FIL3_3 0x15 +#define EQ_0 0x16 +#define EQ_1 0x17 +#define EQ_2 0x18 +#define EQ_3 0x19 +#define EQ_4 0x1a +#define EQ_5 0x1b +#define FIL1_0 0x1c +#define FIL1_1 0x1d +#define FIL1_2 0x1e +#define FIL1_3 0x1f +#define PW_MGMT4 0x20 +#define MD_CTL5 0x21 +#define LO_MS 0x22 +#define HP_MS 0x23 +#define SPK_MS 0x24 + +#define AK4642_CACHEREGNUM 0x25 + +struct snd_soc_codec_device soc_codec_dev_ak4642; + +/* codec private data */ +struct ak4642_priv { + struct snd_soc_codec codec; + unsigned int sysclk; +}; + +static struct snd_soc_codec *ak4642_codec; + +/* + * ak4642 register cache + */ +static const u16 ak4642_reg[AK4642_CACHEREGNUM] = { + 0x0000, 0x0000, 0x0001, 0x0000, + 0x0002, 0x0000, 0x0000, 0x0000, + 0x00e1, 0x00e1, 0x0018, 0x0000, + 0x00e1, 0x0018, 0x0011, 0x0008, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, +}; + +/* + * read ak4642 register cache + */ +static inline unsigned int ak4642_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg >= AK4642_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write ak4642 register cache + */ +static inline void ak4642_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= AK4642_CACHEREGNUM) + return; + + cache[reg] = value; +} + +/* + * write to the AK4642 register space + */ +static int ak4642_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D8 AK4642 register offset + * D7...D0 register data + */ + data[0] = reg & 0xff; + data[1] = value & 0xff; + + if (codec->hw_write(codec->control_data, data, 2) == 2) { + ak4642_write_reg_cache(codec, reg, value); + return 0; + } else + return -EIO; +} + +static int ak4642_sync(struct snd_soc_codec *codec) +{ + u16 *cache = codec->reg_cache; + int i, r = 0; + + for (i = 0; i < AK4642_CACHEREGNUM; i++) + r |= ak4642_write(codec, i, cache[i]); + + return r; +}; + +static int ak4642_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct snd_soc_codec *codec = dai->codec; + + if (is_play) { + /* + * start headphone output + * + * PLL, Master Mode + * Audio I/F Format :MSB justified (ADC & DAC) + * Sampling Frequency: 44.1kHz + * Digital Volume: −8dB + * Bass Boost Level : Middle + * + * This operation came from example code of + * "ASAHI KASEI AK4642" (japanese) manual p97. + * + * Example code use 0x39, 0x79 value for 0x01 address, + * But we need MCKO (0x02) bit now + */ + ak4642_write(codec, 0x05, 0x27); + ak4642_write(codec, 0x0f, 0x09); + ak4642_write(codec, 0x0e, 0x19); + ak4642_write(codec, 0x09, 0x91); + ak4642_write(codec, 0x0c, 0x91); + ak4642_write(codec, 0x0a, 0x28); + ak4642_write(codec, 0x0d, 0x28); + ak4642_write(codec, 0x00, 0x64); + ak4642_write(codec, 0x01, 0x3b); /* + MCKO bit */ + ak4642_write(codec, 0x01, 0x7b); /* + MCKO bit */ + } else { + /* + * start stereo input + * + * PLL Master Mode + * Audio I/F Format:MSB justified (ADC & DAC) + * Sampling Frequency:44.1kHz + * Pre MIC AMP:+20dB + * MIC Power On + * ALC setting:Refer to Table 35 + * ALC bit=“1” + * + * This operation came from example code of + * "ASAHI KASEI AK4642" (japanese) manual p94. + */ + ak4642_write(codec, 0x05, 0x27); + ak4642_write(codec, 0x02, 0x05); + ak4642_write(codec, 0x06, 0x3c); + ak4642_write(codec, 0x08, 0xe1); + ak4642_write(codec, 0x0b, 0x00); + ak4642_write(codec, 0x07, 0x21); + ak4642_write(codec, 0x00, 0x41); + ak4642_write(codec, 0x10, 0x01); + } + + return 0; +} + +static void ak4642_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct snd_soc_codec *codec = dai->codec; + + if (is_play) { + /* stop headphone output */ + ak4642_write(codec, 0x01, 0x3b); + ak4642_write(codec, 0x01, 0x0b); + ak4642_write(codec, 0x00, 0x40); + ak4642_write(codec, 0x0e, 0x11); + ak4642_write(codec, 0x0f, 0x08); + } else { + /* stop stereo input */ + ak4642_write(codec, 0x00, 0x40); + ak4642_write(codec, 0x10, 0x00); + ak4642_write(codec, 0x07, 0x01); + } +} + +static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct ak4642_priv *ak4642 = codec->private_data; + + ak4642->sysclk = freq; + return 0; +} + +static struct snd_soc_dai_ops ak4642_dai_ops = { + .startup = ak4642_dai_startup, + .shutdown = ak4642_dai_shutdown, + .set_sysclk = ak4642_dai_set_sysclk, +}; + +struct snd_soc_dai ak4642_dai = { + .name = "AK4642", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE }, + .ops = &ak4642_dai_ops, +}; +EXPORT_SYMBOL_GPL(ak4642_dai); + +static int ak4642_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + ak4642_sync(codec); + return 0; +} + +/* + * initialise the AK4642 driver + * register the mixer and dsp interfaces with the kernel + */ +static int ak4642_init(struct ak4642_priv *ak4642) +{ + struct snd_soc_codec *codec = &ak4642->codec; + int ret = 0; + + if (ak4642_codec) { + dev_err(codec->dev, "Another ak4642 is registered\n"); + return -EINVAL; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = ak4642; + codec->name = "AK4642"; + codec->owner = THIS_MODULE; + codec->read = ak4642_read_reg_cache; + codec->write = ak4642_write; + codec->dai = &ak4642_dai; + codec->num_dai = 1; + codec->hw_write = (hw_write_t)i2c_master_send; + codec->reg_cache_size = ARRAY_SIZE(ak4642_reg); + codec->reg_cache = kmemdup(ak4642_reg, + sizeof(ak4642_reg), GFP_KERNEL); + + if (!codec->reg_cache) + return -ENOMEM; + + ak4642_dai.dev = codec->dev; + ak4642_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + goto reg_cache_err; + } + + ret = snd_soc_register_dai(&ak4642_dai); + if (ret) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + goto reg_cache_err; + } + + /* + * clock setting + * + * Audio I/F Format: MSB justified (ADC & DAC) + * BICK frequency at Master Mode: 64fs + * Input Master Clock Select at PLL Mode: 11.2896MHz + * MCKO: Enable + * Sampling Frequency: 44.1kHz + * + * This operation came from example code of + * "ASAHI KASEI AK4642" (japanese) manual p89. + * + * please fix-me + */ + ak4642_write(codec, 0x01, 0x08); + ak4642_write(codec, 0x04, 0x4a); + ak4642_write(codec, 0x05, 0x27); + ak4642_write(codec, 0x00, 0x40); + ak4642_write(codec, 0x01, 0x0b); + + return ret; + +reg_cache_err: + kfree(codec->reg_cache); + codec->reg_cache = NULL; + + return ret; +} + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static int ak4642_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct ak4642_priv *ak4642; + struct snd_soc_codec *codec; + int ret; + + ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL); + if (!ak4642) + return -ENOMEM; + + codec = &ak4642->codec; + codec->dev = &i2c->dev; + + i2c_set_clientdata(i2c, ak4642); + codec->control_data = i2c; + + ret = ak4642_init(ak4642); + if (ret < 0) + printk(KERN_ERR "failed to initialise AK4642\n"); + + return ret; +} + +static int ak4642_i2c_remove(struct i2c_client *client) +{ + struct ak4642_priv *ak4642 = i2c_get_clientdata(client); + + snd_soc_unregister_dai(&ak4642_dai); + snd_soc_unregister_codec(&ak4642->codec); + kfree(ak4642->codec.reg_cache); + kfree(ak4642); + ak4642_codec = NULL; + + return 0; +} + +static const struct i2c_device_id ak4642_i2c_id[] = { + { "ak4642", 0 }, + { "ak4643", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id); + +static struct i2c_driver ak4642_i2c_driver = { + .driver = { + .name = "AK4642 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = ak4642_i2c_probe, + .remove = ak4642_i2c_remove, + .id_table = ak4642_i2c_id, +}; + +#endif + +static int ak4642_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + int ret; + + if (!ak4642_codec) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = ak4642_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "ak4642: failed to create pcms\n"); + goto pcm_err; + } + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + printk(KERN_ERR "ak4642: failed to register card\n"); + goto card_err; + } + + dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION); + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; + +} + +/* power down chip */ +static int ak4642_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_ak4642 = { + .probe = ak4642_probe, + .remove = ak4642_remove, + .resume = ak4642_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642); + +static int __init ak4642_modinit(void) +{ + int ret; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&ak4642_i2c_driver); +#endif + return ret; + +} +module_init(ak4642_modinit); + +static void __exit ak4642_exit(void) +{ +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&ak4642_i2c_driver); +#endif + +} +module_exit(ak4642_exit); + +MODULE_DESCRIPTION("Soc AK4642 driver"); +MODULE_AUTHOR("Kuninori Morimoto "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ak4642.h b/sound/soc/codecs/ak4642.h new file mode 100644 index 0000000..e476833 --- /dev/null +++ b/sound/soc/codecs/ak4642.h @@ -0,0 +1,20 @@ +/* + * ak4642.h -- AK4642 Soc Audio driver + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto + * + * Based on ak4535.c + * + * 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 + * published by the Free Software Foundation. + */ + +#ifndef _AK4642_H +#define _AK4642_H + +extern struct snd_soc_dai ak4642_dai; +extern struct snd_soc_codec_device soc_codec_dev_ak4642; + +#endif -- cgit v0.10.2 From b8e583f6012d618fb93bb38a302b63c3c6d2bfbc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 21 Aug 2009 09:42:59 +0900 Subject: ASoC: Add FSI-AK4642 sound support for SuperH This patch is tested by ms7724se Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 01943a1..9154b43 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -40,4 +40,12 @@ config SND_SH7760_AC97 This option enables generic sound support for the first AC97 unit of the SH7760. +config SND_FSI_AK4642 + bool "FSI-AK4642 sound support" + depends on SND_SOC_SH4_FSI + select SND_SOC_AK4642 + help + This option enables generic sound support for the + FSI - AK4642 unit + endmenu diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile index 9fbcc4a..a699787 100644 --- a/sound/soc/sh/Makefile +++ b/sound/soc/sh/Makefile @@ -12,5 +12,7 @@ obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o ## boards snd-soc-sh7760-ac97-objs := sh7760-ac97.o +snd-soc-fsi-ak4642-objs := fsi-ak4642.o obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o +obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c new file mode 100644 index 0000000..c7af097 --- /dev/null +++ b/sound/soc/sh/fsi-ak4642.c @@ -0,0 +1,107 @@ +/* + * FSI-AK464x sound support for ms7724se + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include <../sound/soc/codecs/ak4642.h> + +static struct snd_soc_dai_link fsi_dai_link = { + .name = "AK4642", + .stream_name = "AK4642", + .cpu_dai = &fsi_soc_dai[0], /* fsi */ + .codec_dai = &ak4642_dai, + .ops = NULL, +}; + +static struct snd_soc_card fsi_soc_card = { + .name = "FSI", + .platform = &fsi_soc_platform, + .dai_link = &fsi_dai_link, + .num_links = 1, +}; + +static struct snd_soc_device fsi_snd_devdata = { + .card = &fsi_soc_card, + .codec_dev = &soc_codec_dev_ak4642, +}; + +#define AK4642_BUS 0 +#define AK4642_ADR 0x12 +static int ak4642_add_i2c_device(void) +{ + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client; + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = AK4642_ADR; + strlcpy(info.type, "ak4642", I2C_NAME_SIZE); + + adapter = i2c_get_adapter(AK4642_BUS); + if (!adapter) { + printk(KERN_DEBUG "can't get i2c adapter\n"); + return -ENODEV; + } + + client = i2c_new_device(adapter, &info); + i2c_put_adapter(adapter); + if (!client) { + printk(KERN_DEBUG "can't add i2c device\n"); + return -ENODEV; + } + + return 0; +} + +static struct platform_device *fsi_snd_device; + +static int __init fsi_ak4642_init(void) +{ + int ret = -ENOMEM; + + ak4642_add_i2c_device(); + + fsi_snd_device = platform_device_alloc("soc-audio", -1); + if (!fsi_snd_device) + goto out; + + platform_set_drvdata(fsi_snd_device, + &fsi_snd_devdata); + fsi_snd_devdata.dev = &fsi_snd_device->dev; + ret = platform_device_add(fsi_snd_device); + + if (ret) + platform_device_put(fsi_snd_device); + +out: + return ret; +} + +static void __exit fsi_ak4642_exit(void) +{ + platform_device_unregister(fsi_snd_device); +} + +module_init(fsi_ak4642_init); +module_exit(fsi_ak4642_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic SH4 FSI-AK4642 sound card"); +MODULE_AUTHOR("Kuninori Morimoto "); -- cgit v0.10.2 From a8af7246c114bfd939e539f9566b872c06f6225c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 21 Aug 2009 13:58:54 +0200 Subject: sched: Avoid division by zero Patch a5004278f0525dcb9aa43703ef77bf371ea837cd (sched: Fix cgroup smp fairness) introduced the possibility of a divide-by-zero because load-balancing is not synchronized between sched_domains. This can cause the state of cpus to change between the first and second loop over the sched domain in tg_shares_up(). Reported-by: Yinghai Lu Signed-off-by: Peter Zijlstra Cc: Jes Sorensen Cc: Jens Axboe Cc: Linus Torvalds LKML-Reference: <1250855934.7538.30.camel@twins> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 1b529ef..8f8a98e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1522,7 +1522,8 @@ static void __set_se_shares(struct sched_entity *se, unsigned long shares); */ static void update_group_shares_cpu(struct task_group *tg, int cpu, - unsigned long sd_shares, unsigned long sd_rq_weight) + unsigned long sd_shares, unsigned long sd_rq_weight, + unsigned long sd_eff_weight) { unsigned long rq_weight; unsigned long shares; @@ -1535,13 +1536,15 @@ update_group_shares_cpu(struct task_group *tg, int cpu, if (!rq_weight) { boost = 1; rq_weight = NICE_0_LOAD; + if (sd_rq_weight == sd_eff_weight) + sd_eff_weight += NICE_0_LOAD; + sd_rq_weight = sd_eff_weight; } /* - * \Sum shares * rq_weight - * shares = ----------------------- - * \Sum rq_weight - * + * \Sum_j shares_j * rq_weight_i + * shares_i = ----------------------------- + * \Sum_j rq_weight_j */ shares = (sd_shares * rq_weight) / sd_rq_weight; shares = clamp_t(unsigned long, shares, MIN_SHARES, MAX_SHARES); @@ -1593,14 +1596,8 @@ static int tg_shares_up(struct task_group *tg, void *data) if (!sd->parent || !(sd->parent->flags & SD_LOAD_BALANCE)) shares = tg->shares; - for_each_cpu(i, sched_domain_span(sd)) { - unsigned long sd_rq_weight = rq_weight; - - if (!tg->cfs_rq[i]->rq_weight) - sd_rq_weight = eff_weight; - - update_group_shares_cpu(tg, i, shares, sd_rq_weight); - } + for_each_cpu(i, sched_domain_span(sd)) + update_group_shares_cpu(tg, i, shares, rq_weight, eff_weight); return 0; } -- cgit v0.10.2 From 405d8f8b1d936414da2093d4149ff790ff3f84a5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 21 Aug 2009 08:17:56 -0400 Subject: SUNRPC: Ensure that sunrpc gets initialised before nfs, lockd, etc... We can oops if rpc_pipefs isn't properly initialised before we start to set up objects that depend upon it. Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index adaa819..8cce921 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -69,5 +69,5 @@ cleanup_sunrpc(void) rcu_barrier(); /* Wait for completion of call_rcu()'s */ } MODULE_LICENSE("GPL"); -module_init(init_sunrpc); +fs_initcall(init_sunrpc); /* Ensure we're initialised before nfs */ module_exit(cleanup_sunrpc); -- cgit v0.10.2 From 79fb9387f88b6b44bbc46e19cae26d2c9fe3bb6a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Aug 2009 16:38:13 +0100 Subject: ASoC: Add DAPM widget power decision debugfs files Currently when built with DEBUG DAPM will dump information about the power state decisions it is taking for each widget to dmesg. This isn't an ideal way of getting the information - it requires a kernel build to turn it on and off and for large hub CODECs the volume of information is so large as to be illegible. When the output goes to the console it can also cause a noticable impact on performance simply to print it out. Improve the situation by adding a dapm directory to our debugfs tree containing a file per widget with the same information in it. This still requires a decision to build with debugfs support but is easier to navigate and much less intrusive. In addition to the previously displayed information active streams are also shown in these files. Signed-off-by: Mark Brown diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 35814ce..1673f0b 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -283,6 +283,7 @@ void snd_soc_dapm_shutdown(struct snd_soc_device *socdev); /* dapm sys fs - used by the core */ int snd_soc_dapm_sys_add(struct device *dev); +void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec); /* dapm audio pin control and status */ int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin); diff --git a/include/sound/soc.h b/include/sound/soc.h index dbb1702..0758a1b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -416,6 +416,7 @@ struct snd_soc_codec { #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_reg; struct dentry *debugfs_pop_time; + struct dentry *debugfs_dapm; #endif }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e984a17..7ff04ad 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1267,10 +1267,18 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) if (!codec->debugfs_pop_time) printk(KERN_WARNING "Failed to create pop time debugfs file\n"); + + codec->debugfs_dapm = debugfs_create_dir("dapm", debugfs_root); + if (!codec->debugfs_dapm) + printk(KERN_WARNING + "Failed to create DAPM debugfs directory\n"); + + snd_soc_dapm_debugfs_init(codec); } static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) { + debugfs_remove_recursive(codec->debugfs_dapm); debugfs_remove(codec->debugfs_pop_time); debugfs_remove(codec->debugfs_reg); } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 5cfc909..2f5295d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1081,6 +1081,92 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) } #endif +#ifdef CONFIG_DEBUG_FS +static int dapm_widget_power_open_file(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t dapm_widget_power_read_file(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct snd_soc_dapm_widget *w = file->private_data; + char *buf; + int in, out; + ssize_t ret; + struct snd_soc_dapm_path *p = NULL; + + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + in = is_connected_input_ep(w); + dapm_clear_walk(w->codec); + out = is_connected_output_ep(w); + dapm_clear_walk(w->codec); + + ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d\n", + w->name, w->power ? "On" : "Off", in, out); + + if (w->active && w->sname) + ret += snprintf(buf, PAGE_SIZE - ret, " stream %s active\n", + w->sname); + + list_for_each_entry(p, &w->sources, list_sink) { + if (p->connect) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + " in %s %s\n", + p->name ? p->name : "static", + p->source->name); + } + list_for_each_entry(p, &w->sinks, list_source) { + if (p->connect) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + " out %s %s\n", + p->name ? p->name : "static", + p->sink->name); + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); + + kfree(buf); + return ret; +} + +static const struct file_operations dapm_widget_power_fops = { + .open = dapm_widget_power_open_file, + .read = dapm_widget_power_read_file, +}; + +void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_widget *w; + struct dentry *d; + + if (!codec->debugfs_dapm) + return; + + list_for_each_entry(w, &codec->dapm_widgets, list) { + if (!w->name) + continue; + + d = debugfs_create_file(w->name, 0444, + codec->debugfs_dapm, w, + &dapm_widget_power_fops); + if (!d) + printk(KERN_WARNING + "ASoC: Failed to create %s debugfs file\n", + w->name); + } +} +#else +void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec) +{ +} +#endif + /* test and update the power status of a mux widget */ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kcontrol, int mask, -- cgit v0.10.2 From 1909629fb1ec9800cf2cb0091870d6a1c1ca665f Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 21 Aug 2009 14:56:03 -0400 Subject: perf trace: Add OPT_END to option array of perf-trace Add OPT_END to option array of perf-trace for fixing a SEGV bug when showing perf-trace help message. Without this patch; ./perf trace -h usage: perf trace [] -D, --dump-raw-trace dump raw trace in ASCII -v, --verbose be more verbose (show symbol address, etc) -f, Segmentation fault With this patch: ./perf trace -h usage: perf trace [] -D, --dump-raw-trace dump raw trace in ASCII -v, --verbose be more verbose (show symbol address, etc) Signed-off-by: Masami Hiramatsu Cc: systemtap Cc: DLE Cc: Masami Hiramatsu Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Xiao Guangrong Cc: Zhaolei Cc: Li Zefan Cc: Lai Jiangshan Cc: Tom Zanussi LKML-Reference: <20090821185603.11039.62109.stgit@localhost.localdomain> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 88eef71..dd3c2e7 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -257,6 +257,7 @@ static const struct option options[] = { "dump raw trace in ASCII"), OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), + OPT_END() }; int cmd_trace(int argc, const char **argv, const char *prefix __used) -- cgit v0.10.2 From 8b5a10fc6fd02289ea03480f93382b1a99006142 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Wed, 19 Aug 2009 08:40:48 +0100 Subject: x86: properly annotate alternatives.c Some of the NOPs tables aren't used on 64-bits, quite some code and data is needed post-init for module loading only, and a couple of functions aren't used outside that file (i.e. can be static, and don't need to be exported). The change to __INITDATA/__INITRODATA is needed to avoid an assembler warning. Signed-off-by: Jan Beulich LKML-Reference: <4A8BC8A00200007800010823@vpn.id2.novell.com> Acked-by: Sam Ravnborg Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 1a37bcd..c240efc 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -73,8 +73,6 @@ static inline void alternatives_smp_module_del(struct module *mod) {} static inline void alternatives_smp_switch(int smp) {} #endif /* CONFIG_SMP */ -const unsigned char *const *find_nop_table(void); - /* alternative assembly primitive: */ #define ALTERNATIVE(oldinstr, newinstr, feature) \ \ @@ -144,8 +142,6 @@ static inline void apply_paravirt(struct paravirt_patch_site *start, #define __parainstructions_end NULL #endif -extern void add_nops(void *insns, unsigned int len); - /* * Clear and restore the kernel write-protection flag on the local CPU. * Allows the kernel to edit read-only pages. @@ -161,10 +157,7 @@ extern void add_nops(void *insns, unsigned int len); * Intel's errata. * On the local CPU you need to be protected again NMI or MCE handlers seeing an * inconsistent instruction while you patch. - * The _early version expects the memory to already be RW. */ - extern void *text_poke(void *addr, const void *opcode, size_t len); -extern void *text_poke_early(void *addr, const void *opcode, size_t len); #endif /* _ASM_X86_ALTERNATIVE_H */ diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index f576587..4869351 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -32,7 +33,7 @@ __setup("smp-alt-boot", bootonly); #define smp_alt_once 1 #endif -static int debug_alternative; +static int __initdata_or_module debug_alternative; static int __init debug_alt(char *str) { @@ -51,7 +52,7 @@ static int __init setup_noreplace_smp(char *str) __setup("noreplace-smp", setup_noreplace_smp); #ifdef CONFIG_PARAVIRT -static int noreplace_paravirt = 0; +static int __initdata_or_module noreplace_paravirt = 0; static int __init setup_noreplace_paravirt(char *str) { @@ -64,16 +65,17 @@ __setup("noreplace-paravirt", setup_noreplace_paravirt); #define DPRINTK(fmt, args...) if (debug_alternative) \ printk(KERN_DEBUG fmt, args) -#ifdef GENERIC_NOP1 +#if defined(GENERIC_NOP1) && !defined(CONFIG_X86_64) /* Use inline assembly to define this because the nops are defined as inline assembly strings in the include files and we cannot get them easily into strings. */ -asm("\t.section .rodata, \"a\"\nintelnops: " +asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nintelnops: " GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6 GENERIC_NOP7 GENERIC_NOP8 "\t.previous"); extern const unsigned char intelnops[]; -static const unsigned char *const intel_nops[ASM_NOP_MAX+1] = { +static const unsigned char *const __initconst_or_module +intel_nops[ASM_NOP_MAX+1] = { NULL, intelnops, intelnops + 1, @@ -87,12 +89,13 @@ static const unsigned char *const intel_nops[ASM_NOP_MAX+1] = { #endif #ifdef K8_NOP1 -asm("\t.section .rodata, \"a\"\nk8nops: " +asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk8nops: " K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6 K8_NOP7 K8_NOP8 "\t.previous"); extern const unsigned char k8nops[]; -static const unsigned char *const k8_nops[ASM_NOP_MAX+1] = { +static const unsigned char *const __initconst_or_module +k8_nops[ASM_NOP_MAX+1] = { NULL, k8nops, k8nops + 1, @@ -105,13 +108,14 @@ static const unsigned char *const k8_nops[ASM_NOP_MAX+1] = { }; #endif -#ifdef K7_NOP1 -asm("\t.section .rodata, \"a\"\nk7nops: " +#if defined(K7_NOP1) && !defined(CONFIG_X86_64) +asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk7nops: " K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6 K7_NOP7 K7_NOP8 "\t.previous"); extern const unsigned char k7nops[]; -static const unsigned char *const k7_nops[ASM_NOP_MAX+1] = { +static const unsigned char *const __initconst_or_module +k7_nops[ASM_NOP_MAX+1] = { NULL, k7nops, k7nops + 1, @@ -125,12 +129,13 @@ static const unsigned char *const k7_nops[ASM_NOP_MAX+1] = { #endif #ifdef P6_NOP1 -asm("\t.section .rodata, \"a\"\np6nops: " +asm("\t" __stringify(__INITRODATA_OR_MODULE) "\np6nops: " P6_NOP1 P6_NOP2 P6_NOP3 P6_NOP4 P6_NOP5 P6_NOP6 P6_NOP7 P6_NOP8 "\t.previous"); extern const unsigned char p6nops[]; -static const unsigned char *const p6_nops[ASM_NOP_MAX+1] = { +static const unsigned char *const __initconst_or_module +p6_nops[ASM_NOP_MAX+1] = { NULL, p6nops, p6nops + 1, @@ -146,7 +151,7 @@ static const unsigned char *const p6_nops[ASM_NOP_MAX+1] = { #ifdef CONFIG_X86_64 extern char __vsyscall_0; -const unsigned char *const *find_nop_table(void) +static const unsigned char *const *__init_or_module find_nop_table(void) { if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && boot_cpu_has(X86_FEATURE_NOPL)) @@ -157,7 +162,7 @@ const unsigned char *const *find_nop_table(void) #else /* CONFIG_X86_64 */ -const unsigned char *const *find_nop_table(void) +static const unsigned char *const *__init_or_module find_nop_table(void) { if (boot_cpu_has(X86_FEATURE_K8)) return k8_nops; @@ -172,7 +177,7 @@ const unsigned char *const *find_nop_table(void) #endif /* CONFIG_X86_64 */ /* Use this to add nops to a buffer, then text_poke the whole buffer. */ -void add_nops(void *insns, unsigned int len) +static void __init_or_module add_nops(void *insns, unsigned int len) { const unsigned char *const *noptable = find_nop_table(); @@ -185,10 +190,10 @@ void add_nops(void *insns, unsigned int len) len -= noplen; } } -EXPORT_SYMBOL_GPL(add_nops); extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; extern u8 *__smp_locks[], *__smp_locks_end[]; +static void *text_poke_early(void *addr, const void *opcode, size_t len); /* Replace instructions with better alternatives for this CPU type. This runs before SMP is initialized to avoid SMP problems with @@ -196,7 +201,8 @@ extern u8 *__smp_locks[], *__smp_locks_end[]; APs have less capabilities than the boot processor are not handled. Tough. Make sure you disable such features by hand. */ -void apply_alternatives(struct alt_instr *start, struct alt_instr *end) +void __init_or_module apply_alternatives(struct alt_instr *start, + struct alt_instr *end) { struct alt_instr *a; char insnbuf[MAX_PATCH_LEN]; @@ -279,9 +285,10 @@ static LIST_HEAD(smp_alt_modules); static DEFINE_MUTEX(smp_alt); static int smp_mode = 1; /* protected by smp_alt */ -void alternatives_smp_module_add(struct module *mod, char *name, - void *locks, void *locks_end, - void *text, void *text_end) +void __init_or_module alternatives_smp_module_add(struct module *mod, + char *name, + void *locks, void *locks_end, + void *text, void *text_end) { struct smp_alt_module *smp; @@ -317,7 +324,7 @@ void alternatives_smp_module_add(struct module *mod, char *name, mutex_unlock(&smp_alt); } -void alternatives_smp_module_del(struct module *mod) +void __init_or_module alternatives_smp_module_del(struct module *mod) { struct smp_alt_module *item; @@ -386,8 +393,8 @@ void alternatives_smp_switch(int smp) #endif #ifdef CONFIG_PARAVIRT -void apply_paravirt(struct paravirt_patch_site *start, - struct paravirt_patch_site *end) +void __init_or_module apply_paravirt(struct paravirt_patch_site *start, + struct paravirt_patch_site *end) { struct paravirt_patch_site *p; char insnbuf[MAX_PATCH_LEN]; @@ -485,7 +492,8 @@ void __init alternative_instructions(void) * instructions. And on the local CPU you need to be protected again NMI or MCE * handlers seeing an inconsistent instruction while you patch. */ -void *text_poke_early(void *addr, const void *opcode, size_t len) +static void *__init_or_module text_poke_early(void *addr, const void *opcode, + size_t len) { unsigned long flags; local_irq_save(flags); diff --git a/include/linux/init.h b/include/linux/init.h index 13b633e..400adbb 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -103,8 +103,8 @@ #define __INIT .section ".init.text","ax" #define __FINIT .previous -#define __INITDATA .section ".init.data","aw" -#define __INITRODATA .section ".init.rodata","a" +#define __INITDATA .section ".init.data","aw",%progbits +#define __INITRODATA .section ".init.rodata","a",%progbits #define __FINITDATA .previous #define __DEVINIT .section ".devinit.text", "ax" @@ -305,9 +305,17 @@ void __init parse_early_options(char *cmdline); #ifdef CONFIG_MODULES #define __init_or_module #define __initdata_or_module +#define __initconst_or_module +#define __INIT_OR_MODULE .text +#define __INITDATA_OR_MODULE .data +#define __INITRODATA_OR_MODULE .section ".rodata","a",%progbits #else #define __init_or_module __init #define __initdata_or_module __initdata +#define __initconst_or_module __initconst +#define __INIT_OR_MODULE __INIT +#define __INITDATA_OR_MODULE __INITDATA +#define __INITRODATA_OR_MODULE __INITRODATA #endif /*CONFIG_MODULES*/ /* Functions marked as __devexit may be discarded at kernel link time, depending -- cgit v0.10.2 From b560d8ad8583803978aaaeba50ef29dc8e97a610 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 21 Aug 2009 22:08:51 -0700 Subject: rcu: Expunge lingering references to CONFIG_CLASSIC_RCU, optimize on !SMP A couple of references to CONFIG_CLASSIC_RCU have survived. Although these are harmless, it is past time for them to go. The one in hardirq.h is strictly a readability problem. The two in pagemap.h appear to disable a !SMP performance optimization (which this patch re-enables). This does raise the issue as to whether pagemap.h should really be referring to the CPU implementation. Long term, I intend to make the RCU implementation driven by CONFIG_PREEMPT, at which point these should change from defined(CONFIG_TREE_RCU) to !defined(CONFIG_PREEMPT). In the meantime, is there something else that could be done in pagemap.h? 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: <20090822050851.GA8414@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 8246c69..330cb31 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -132,7 +132,7 @@ static inline void account_system_vtime(struct task_struct *tsk) } #endif -#if defined(CONFIG_NO_HZ) && !defined(CONFIG_CLASSIC_RCU) +#if defined(CONFIG_NO_HZ) extern void rcu_irq_enter(void); extern void rcu_irq_exit(void); extern void rcu_nmi_enter(void); @@ -142,7 +142,7 @@ extern void rcu_nmi_exit(void); # define rcu_irq_exit() do { } while (0) # define rcu_nmi_enter() do { } while (0) # define rcu_nmi_exit() do { } while (0) -#endif /* #if defined(CONFIG_NO_HZ) && !defined(CONFIG_CLASSIC_RCU) */ +#endif /* #if defined(CONFIG_NO_HZ) */ /* * It is safe to do non-atomic ops on ->hardirq_context, diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index aec3252..ed5d750 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -132,7 +132,7 @@ static inline int page_cache_get_speculative(struct page *page) { VM_BUG_ON(in_interrupt()); -#if !defined(CONFIG_SMP) && defined(CONFIG_CLASSIC_RCU) +#if !defined(CONFIG_SMP) && defined(CONFIG_TREE_RCU) # ifdef CONFIG_PREEMPT VM_BUG_ON(!in_atomic()); # endif @@ -170,7 +170,7 @@ static inline int page_cache_add_speculative(struct page *page, int count) { VM_BUG_ON(in_interrupt()); -#if !defined(CONFIG_SMP) && defined(CONFIG_CLASSIC_RCU) +#if !defined(CONFIG_SMP) && defined(CONFIG_TREE_RCU) # ifdef CONFIG_PREEMPT VM_BUG_ON(!in_atomic()); # endif -- cgit v0.10.2 From fd0b3ff707dc1f7837079044bd4eca7ed505f70d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 16 Jun 2009 00:01:49 +0200 Subject: Bluetooth: Add proper shutdown support to SCO sockets The SCO sockets for Bluetooth audio setup and streaming are missing the shutdown implementation. This hasn't been a problem so far, but with a more deeper integration with PulseAudio it is important to shutdown SCO sockets properly. Also the Headset profile 1.2 has more detailed qualification tests that require that SCO and RFCOMM channels are terminated in the right order. A proper shutdown function is necessary for this. Based on a report by Johan Hedberg Signed-off-by: Marcel Holtmann Tested-by: Johan Hedberg diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 51ae0c3..13c27f1 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -359,20 +359,9 @@ static void sco_sock_kill(struct sock *sk) sock_put(sk); } -/* Close socket. - * Must be called on unlocked socket. - */ -static void sco_sock_close(struct sock *sk) +static void __sco_sock_close(struct sock *sk) { - struct sco_conn *conn; - - sco_sock_clear_timer(sk); - - lock_sock(sk); - - conn = sco_pi(sk)->conn; - - BT_DBG("sk %p state %d conn %p socket %p", sk, sk->sk_state, conn, sk->sk_socket); + BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); switch (sk->sk_state) { case BT_LISTEN: @@ -390,9 +379,15 @@ static void sco_sock_close(struct sock *sk) sock_set_flag(sk, SOCK_ZAPPED); break; } +} +/* Must be called on unlocked socket. */ +static void sco_sock_close(struct sock *sk) +{ + sco_sock_clear_timer(sk); + lock_sock(sk); + __sco_sock_close(sk); release_sock(sk); - sco_sock_kill(sk); } @@ -748,6 +743,30 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char return err; } +static int sco_sock_shutdown(struct socket *sock, int how) +{ + struct sock *sk = sock->sk; + int err = 0; + + BT_DBG("sock %p, sk %p", sock, sk); + + if (!sk) + return 0; + + lock_sock(sk); + if (!sk->sk_shutdown) { + sk->sk_shutdown = SHUTDOWN_MASK; + sco_sock_clear_timer(sk); + __sco_sock_close(sk); + + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + err = bt_sock_wait_state(sk, BT_CLOSED, + sk->sk_lingertime); + } + release_sock(sk); + return err; +} + static int sco_sock_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -969,7 +988,7 @@ static const struct proto_ops sco_sock_ops = { .ioctl = bt_sock_ioctl, .mmap = sock_no_mmap, .socketpair = sock_no_socketpair, - .shutdown = sock_no_shutdown, + .shutdown = sco_sock_shutdown, .setsockopt = sco_sock_setsockopt, .getsockopt = sco_sock_getsockopt }; -- cgit v0.10.2 From 981b1414d78a7a42cab48b97d4de54a62d61db88 Mon Sep 17 00:00:00 2001 From: Vikram Kandukuri Date: Wed, 1 Jul 2009 11:39:58 +0530 Subject: Bluetooth: Fix missing scheduling when VIRTUAL_CABLE_UNPLUG is received There is a test case in PTS tool; PTS will send the VIRTUAL_CABLE_UNPLUG command to IUT. Then IUT should disconnect the channel and kill the HID session when it receives the command. The VIRTUAL_CABLE_UNPLUG command is parsed by HID transport, but it is not scheduled to do so. Add a call to hidp_schedule() to kill the session. Signed-off-by: Jothikumar Mothilal Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index b186768..a9f7afb 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -374,6 +374,7 @@ static void hidp_process_hid_control(struct hidp_session *session, /* Kill session thread */ atomic_inc(&session->terminate); + hidp_schedule(session); } } -- cgit v0.10.2 From 290ba200815fdecb4d40dc942499c4ea6d0c4624 Mon Sep 17 00:00:00 2001 From: Vikram Kandukuri Date: Thu, 2 Jul 2009 14:31:59 +0530 Subject: Bluetooth: Improve USB driver throughput by increasing the frame size This patch increases the receive buffer size to HCI_MAX_FRAME_SIZE which improves the RX throughput considerably. Tested against BRM/Atheros/CSR USB Dongles with PAN profile using iperf and chariot. This gave significant (around 40%) increase in performance (increased from 0.8 to 1.5 Mb/s in Sheld room) Signed-off-by: Vikram Kandukuri Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e70c57e..124db8c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -301,7 +301,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) struct urb *urb; unsigned char *buf; unsigned int pipe; - int err, size; + int err, size = HCI_MAX_FRAME_SIZE; BT_DBG("%s", hdev->name); @@ -312,8 +312,6 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) if (!urb) return -ENOMEM; - size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize); - buf = kmalloc(size, mem_flags); if (!buf) { usb_free_urb(urb); -- cgit v0.10.2 From 364f63519d94442ed373ac7da79033c8282df46a Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 22 Aug 2009 14:15:53 -0700 Subject: Bluetooth: Disconnect HIDRAW devices on disconnect Currently the HID subsystem will create HIDRAW devices for the transport driver, but it will not disconnect them. Until the HID subsytem gets fixed, ensure that HIDRAW and HIDDEV devices are disconnected when the Bluetooth HID device gets removed. Based on a patch from Brian Rogers Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index a9f7afb..f912d65 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -574,6 +575,8 @@ static int hidp_session(void *arg) if (session->hid) { if (session->hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(session->hid); + if (session->hid->claimed & HID_CLAIMED_HIDRAW) + hidraw_disconnect(session->hid); hid_destroy_device(session->hid); } -- cgit v0.10.2 From 9eba32b86d17ef87131fa0bce43c614904ab5781 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 22 Aug 2009 14:19:26 -0700 Subject: Bluetooth: Add extra device reference counting for connections The device model itself has no real usable reference counting at the moment and this causes problems if parents are deleted before their children. The device model itself handles the memory details of this correctly, but the uevent order is not consistent. This causes various problems for systems like HAL or even X. So until device_put() does a proper cleanup, the device for Bluetooth connection will be protected with an extra reference counting to ensure the correct order of uevents when connections are terminated. This is not an automatic feature. Higher Bluetooth layers like HIDP or BNEP should grab this new reference to ensure that their uevents are send before the ones from the parent device. Based on a report by Brian Rogers Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c4ca422..25b8a03 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -187,6 +187,7 @@ struct hci_conn { struct work_struct work_del; struct device dev; + atomic_t devref; struct hci_dev *hdev; void *l2cap_data; @@ -339,6 +340,9 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role); void hci_conn_enter_active_mode(struct hci_conn *conn); void hci_conn_enter_sniff_mode(struct hci_conn *conn); +void hci_conn_hold_device(struct hci_conn *conn); +void hci_conn_put_device(struct hci_conn *conn); + static inline void hci_conn_hold(struct hci_conn *conn) { atomic_inc(&conn->refcnt); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index fa47d5d..a975098 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -246,6 +246,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); + atomic_set(&conn->devref, 0); + hci_conn_init_sysfs(conn); tasklet_enable(&hdev->tx_task); @@ -288,7 +290,7 @@ int hci_conn_del(struct hci_conn *conn) skb_queue_purge(&conn->data_q); - hci_conn_del_sysfs(conn); + hci_conn_put_device(conn); hci_dev_put(hdev); @@ -583,6 +585,19 @@ void hci_conn_check_pending(struct hci_dev *hdev) hci_dev_unlock(hdev); } +void hci_conn_hold_device(struct hci_conn *conn) +{ + atomic_inc(&conn->devref); +} +EXPORT_SYMBOL(hci_conn_hold_device); + +void hci_conn_put_device(struct hci_conn *conn) +{ + if (atomic_dec_and_test(&conn->devref)) + hci_conn_del_sysfs(conn); +} +EXPORT_SYMBOL(hci_conn_put_device); + int hci_get_conn_list(void __user *arg) { struct hci_conn_list_req req, *cl; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 184ba0a..e99fe38 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -887,6 +887,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s } else conn->state = BT_CONNECTED; + hci_conn_hold_device(conn); hci_conn_add_sysfs(conn); if (test_bit(HCI_AUTH, &hdev->flags)) @@ -1693,6 +1694,7 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu conn->handle = __le16_to_cpu(ev->handle); conn->state = BT_CONNECTED; + hci_conn_hold_device(conn); hci_conn_add_sysfs(conn); break; -- cgit v0.10.2 From edad63886993d18ab800c49f6587a93432ef8b35 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 22 Aug 2009 14:22:15 -0700 Subject: Bluetooth: Let HIDP grab the device reference for connections The core exports the hci_conn_hold_device() and hci_conn_put_device() functions for device reference of connections. Use this to ensure that the uevents from the parent are send after the child ones. Based on a report by Brian Rogers Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index f912d65..09bedeb 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -93,10 +93,14 @@ static void __hidp_link_session(struct hidp_session *session) { __module_get(THIS_MODULE); list_add(&session->list, &hidp_session_list); + + hci_conn_hold_device(session->conn); } static void __hidp_unlink_session(struct hidp_session *session) { + hci_conn_put_device(session->conn); + list_del(&session->list); module_put(THIS_MODULE); } @@ -577,7 +581,9 @@ static int hidp_session(void *arg) hidinput_disconnect(session->hid); if (session->hid->claimed & HID_CLAIMED_HIDRAW) hidraw_disconnect(session->hid); + hid_destroy_device(session->hid); + session->hid = NULL; } /* Wakeup user-space polling for socket errors */ @@ -605,25 +611,27 @@ static struct device *hidp_get_device(struct hidp_session *session) { bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src; bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst; + struct device *device = NULL; struct hci_dev *hdev; - struct hci_conn *conn; hdev = hci_get_route(dst, src); if (!hdev) return NULL; - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); + session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); + if (session->conn) + device = &session->conn->dev; hci_dev_put(hdev); - return conn ? &conn->dev : NULL; + return device; } static int hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req) { struct input_dev *input; - int i; + int err, i; input = input_allocate_device(); if (!input) @@ -670,7 +678,13 @@ static int hidp_setup_input(struct hidp_session *session, input->event = hidp_input_event; - return input_register_device(input); + err = input_register_device(input); + if (err < 0) { + hci_conn_put_device(session->conn); + return err; + } + + return 0; } static int hidp_open(struct hid_device *hid) @@ -752,13 +766,11 @@ static int hidp_setup_hid(struct hidp_session *session, { struct hid_device *hid; bdaddr_t src, dst; - int ret; + int err; hid = hid_allocate_device(); - if (IS_ERR(hid)) { - ret = PTR_ERR(session->hid); - goto err; - } + if (IS_ERR(hid)) + return PTR_ERR(session->hid); session->hid = hid; session->req = req; @@ -780,16 +792,17 @@ static int hidp_setup_hid(struct hidp_session *session, hid->dev.parent = hidp_get_device(session); hid->ll_driver = &hidp_hid_driver; - ret = hid_add_device(hid); - if (ret) - goto err_hid; + err = hid_add_device(hid); + if (err < 0) + goto failed; return 0; -err_hid: + +failed: hid_destroy_device(hid); session->hid = NULL; -err: - return ret; + + return err; } int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) @@ -839,13 +852,13 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, if (req->rd_size > 0) { err = hidp_setup_hid(session, req); if (err && err != -ENODEV) - goto err_skb; + goto purge; } if (!session->hid) { err = hidp_setup_input(session, req); if (err < 0) - goto err_skb; + goto purge; } __hidp_link_session(session); @@ -873,13 +886,20 @@ unlink: __hidp_unlink_session(session); - if (session->input) + if (session->input) { input_unregister_device(session->input); - if (session->hid) + session->input = NULL; + } + + if (session->hid) { hid_destroy_device(session->hid); -err_skb: + session->hid = NULL; + } + +purge: skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); + failed: up_write(&hidp_session_sem); diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index e503c89..faf3d74 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -126,6 +126,8 @@ int hidp_get_conninfo(struct hidp_conninfo *ci); struct hidp_session { struct list_head list; + struct hci_conn *conn; + struct socket *ctrl_sock; struct socket *intr_sock; -- cgit v0.10.2 From 132ff4e5fa8dfb71a7d99902f88043113947e972 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 2 Jun 2009 14:29:35 -0700 Subject: Bluetooth: Add btmrvl driver for Marvell Bluetooth devices This driver provides basic definitions and library functions to support Marvell Bluetooth enabled devices, such as 88W8688 WLAN/BT combo chip. 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 diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 1164837..b049a79 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -170,5 +170,17 @@ config BT_HCIVHCI Say Y here to compile support for virtual HCI devices into the kernel or say M to compile it as module (hci_vhci). +config BT_MRVL + tristate "Marvell Bluetooth driver support" + select FW_LOADER + help + The core driver to support Marvell Bluetooth devices. + + This driver is required if you want to support + Marvell Bluetooth devices, such as 8688. + + Say Y here to compile Marvell Bluetooth driver + into the kernel or say M to compile it as module. + endmenu diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 16930f9..3eff123 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -15,6 +15,9 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o +btmrvl-objs := btmrvl_main.o +obj-$(CONFIG_BT_MRVL) += btmrvl.o + hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h new file mode 100644 index 0000000..9ad71f4 --- /dev/null +++ b/drivers/bluetooth/btmrvl_drv.h @@ -0,0 +1,138 @@ +/* + * Marvell Bluetooth driver: global definitions & declarations + * + * Copyright (C) 2009, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +#ifndef _BTMRVL_DRV_H_ +#define _BTMRVL_DRV_H_ + +#include +#include +#include + +#define BTM_HEADER_LEN 4 +#define BTM_DEV_NAME_LEN 32 +#define BTM_UPLD_SIZE 2312 + +/* Time to wait until Host Sleep state change in millisecond */ +#define WAIT_UNTIL_HS_STATE_CHANGED 5000 +/* Time to wait for command response in millisecond */ +#define WAIT_UNTIL_CMD_RESP 5000 + +struct btmrvl_thread { + struct task_struct *task; + wait_queue_head_t wait_q; + void *priv; +}; + +struct btmrvl_device { + char name[BTM_DEV_NAME_LEN]; + void *card; + struct hci_dev *hcidev; + + u8 tx_dnld_rdy; + + u8 psmode; + u8 pscmd; + u8 hsmode; + u8 hscmd; + + /* Low byte is gap, high byte is GPIO */ + u16 gpio_gap; + + u8 hscfgcmd; + u8 sendcmdflag; +}; + +struct btmrvl_adapter { + u32 int_count; + struct sk_buff_head tx_queue; + u8 psmode; + u8 ps_state; + u8 hs_state; + u8 wakeup_tries; + wait_queue_head_t cmd_wait_q; + u8 cmd_complete; +}; + +struct btmrvl_private { + struct btmrvl_device btmrvl_dev; + struct btmrvl_adapter *adapter; + struct btmrvl_thread main_thread; + int (*hw_host_to_card) (struct btmrvl_private *priv, + u8 *payload, u16 nb); + int (*hw_wakeup_firmware) (struct btmrvl_private *priv); + spinlock_t driver_lock; /* spinlock used by driver */ +}; + +#define MRVL_VENDOR_PKT 0xFE + +/* Bluetooth commands */ +#define BT_CMD_AUTO_SLEEP_MODE 0x23 +#define BT_CMD_HOST_SLEEP_CONFIG 0x59 +#define BT_CMD_HOST_SLEEP_ENABLE 0x5A +#define BT_CMD_MODULE_CFG_REQ 0x5B + +/* Sub-commands: Module Bringup/Shutdown Request */ +#define MODULE_BRINGUP_REQ 0xF1 +#define MODULE_SHUTDOWN_REQ 0xF2 + +#define BT_EVENT_POWER_STATE 0x20 + +/* Bluetooth Power States */ +#define BT_PS_ENABLE 0x02 +#define BT_PS_DISABLE 0x03 +#define BT_PS_SLEEP 0x01 + +#define OGF 0x3F + +/* Host Sleep states */ +#define HS_ACTIVATED 0x01 +#define HS_DEACTIVATED 0x00 + +/* Power Save modes */ +#define PS_SLEEP 0x01 +#define PS_AWAKE 0x00 + +struct btmrvl_cmd { + __le16 ocf_ogf; + u8 length; + u8 data[4]; +} __attribute__ ((packed)); + +struct btmrvl_event { + u8 ec; /* event counter */ + u8 length; + u8 data[4]; +} __attribute__ ((packed)); + +/* Prototype of global function */ + +struct btmrvl_private *btmrvl_add_card(void *card); +int btmrvl_remove_card(struct btmrvl_private *priv); + +void btmrvl_interrupt(struct btmrvl_private *priv); + +void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb); +int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb); + +int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd); +int btmrvl_prepare_command(struct btmrvl_private *priv); + +#endif /* _BTMRVL_DRV_H_ */ diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c new file mode 100644 index 0000000..11c2f2c --- /dev/null +++ b/drivers/bluetooth/btmrvl_main.c @@ -0,0 +1,714 @@ +/** + * Marvell Bluetooth driver + * + * Copyright (C) 2009, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + **/ + +#include +#include + +#include "btmrvl_drv.h" + +#define VERSION "1.0" + +/* + * This function is called by interface specific interrupt handler. + * It updates Power Save & Host Sleep states, and wakes up the main + * thread. + */ +void btmrvl_interrupt(struct btmrvl_private *priv) +{ + BT_DBG("Enter"); + + priv->adapter->ps_state = PS_AWAKE; + + priv->adapter->wakeup_tries = 0; + + priv->adapter->int_count++; + + wake_up_interruptible(&priv->main_thread.wait_q); + + BT_DBG("Leave"); +} +EXPORT_SYMBOL_GPL(btmrvl_interrupt); + +void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) +{ + struct hci_event_hdr *hdr = (struct hci_event_hdr *)skb->data; + struct hci_ev_cmd_complete *ec; + u16 opcode, ocf; + + BT_DBG("Enter"); + + if (hdr->evt == HCI_EV_CMD_COMPLETE) { + ec = (struct hci_ev_cmd_complete *)(skb->data + + HCI_EVENT_HDR_SIZE); + opcode = __le16_to_cpu(ec->opcode); + ocf = hci_opcode_ocf(opcode); + if ((ocf == BT_CMD_MODULE_CFG_REQ) && + (priv->btmrvl_dev.sendcmdflag)) { + priv->btmrvl_dev.sendcmdflag = false; + priv->adapter->cmd_complete = true; + wake_up_interruptible(&priv->adapter->cmd_wait_q); + } + } + + BT_DBG("Leave"); +} +EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt); + +int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) +{ + struct btmrvl_adapter *adapter = priv->adapter; + u8 ret = 0; + struct btmrvl_event *event; + + BT_DBG("Enter"); + + event = (struct btmrvl_event *) skb->data; + if (event->ec != 0xff) { + BT_DBG("Not Marvell Event=%x", event->ec); + ret = -EINVAL; + goto exit; + } + + switch (event->data[0]) { + case BT_CMD_AUTO_SLEEP_MODE: + if (!event->data[2]) { + if (event->data[1] == BT_PS_ENABLE) + adapter->psmode = 1; + else + adapter->psmode = 0; + BT_DBG("PS Mode:%s", + (adapter->psmode) ? "Enable" : "Disable"); + } else { + BT_DBG("PS Mode command failed"); + } + break; + + case BT_CMD_HOST_SLEEP_CONFIG: + if (!event->data[3]) + BT_DBG("gpio=%x, gap=%x", event->data[1], + event->data[2]); + else + BT_DBG("HSCFG command failed"); + break; + + case BT_CMD_HOST_SLEEP_ENABLE: + if (!event->data[1]) { + adapter->hs_state = HS_ACTIVATED; + if (adapter->psmode) + adapter->ps_state = PS_SLEEP; + wake_up_interruptible(&adapter->cmd_wait_q); + BT_DBG("HS ACTIVATED!"); + } else { + BT_DBG("HS Enable failed"); + } + break; + + case BT_CMD_MODULE_CFG_REQ: + if ((priv->btmrvl_dev.sendcmdflag) && + (event->data[1] == MODULE_BRINGUP_REQ)) { + BT_DBG("EVENT:%s", (event->data[2]) ? + "Bring-up failed" : "Bring-up succeed"); + } else if ((priv->btmrvl_dev.sendcmdflag) && + (event->data[1] == MODULE_SHUTDOWN_REQ)) { + BT_DBG("EVENT:%s", (event->data[2]) ? + "Shutdown failed" : "Shutdown succeed"); + } else { + BT_DBG("BT_CMD_MODULE_CFG_REQ resp for APP"); + ret = -EINVAL; + } + break; + + case BT_EVENT_POWER_STATE: + if (event->data[1] == BT_PS_SLEEP) + adapter->ps_state = PS_SLEEP; + BT_DBG("EVENT:%s", + (adapter->ps_state) ? "PS_SLEEP" : "PS_AWAKE"); + break; + + default: + BT_DBG("Unknown Event=%d", event->data[0]); + ret = -EINVAL; + break; + } + +exit: + if (!ret) + kfree_skb(skb); + + BT_DBG("Leave"); + + return ret; +} +EXPORT_SYMBOL_GPL(btmrvl_process_event); + +int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) +{ + struct sk_buff *skb = NULL; + u8 ret = 0; + struct btmrvl_cmd *cmd; + + BT_DBG("Enter"); + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + ret = -ENOMEM; + goto exit; + } + + cmd = (struct btmrvl_cmd *) skb->tail; + cmd->ocf_ogf = cpu_to_le16((OGF << 10) | BT_CMD_MODULE_CFG_REQ); + cmd->length = 1; + cmd->data[0] = subcmd; + + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb_put(skb, sizeof(*cmd)); + skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + priv->btmrvl_dev.sendcmdflag = true; + + priv->adapter->cmd_complete = false; + + BT_DBG("Queue module cfg Command"); + + wake_up_interruptible(&priv->main_thread.wait_q); + + if (!wait_event_interruptible_timeout( + priv->adapter->cmd_wait_q, + priv->adapter->cmd_complete, + msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) { + ret = -ETIMEDOUT; + BT_ERR("module_cfg_cmd(%x): timeout: %d", + subcmd, priv->btmrvl_dev.sendcmdflag); + } + + BT_DBG("module cfg Command done"); + +exit: + BT_DBG("Leave"); + + return ret; +} +EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); + +static int btmrvl_enable_hs(struct btmrvl_private *priv) +{ + struct sk_buff *skb = NULL; + u8 ret = 0; + struct btmrvl_cmd *cmd; + + BT_DBG("Enter"); + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + ret = -ENOMEM; + goto exit; + } + + cmd = (struct btmrvl_cmd *) skb->tail; + cmd->ocf_ogf = cpu_to_le16((OGF << 10) | BT_CMD_HOST_SLEEP_ENABLE); + cmd->length = 0; + + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb_put(skb, sizeof(*cmd)); + skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + BT_DBG("Queue hs enable Command"); + + wake_up_interruptible(&priv->main_thread.wait_q); + + if (!wait_event_interruptible_timeout( + priv->adapter->cmd_wait_q, + priv->adapter->hs_state, + msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED))) { + ret = -ETIMEDOUT; + BT_ERR("timeout: %d, %d,%d", + priv->adapter->hs_state, + priv->adapter->ps_state, + priv->adapter->wakeup_tries); + } + +exit: + BT_DBG("Leave"); + + return ret; +} + +int btmrvl_prepare_command(struct btmrvl_private *priv) +{ + struct sk_buff *skb = NULL; + u8 ret = 0; + struct btmrvl_cmd *cmd; + + BT_DBG("Enter"); + + if (priv->btmrvl_dev.hscfgcmd) { + priv->btmrvl_dev.hscfgcmd = 0; + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + ret = -ENOMEM; + goto exit; + } + + cmd = (struct btmrvl_cmd *) skb->tail; + cmd->ocf_ogf = cpu_to_le16((OGF << 10) | + BT_CMD_HOST_SLEEP_CONFIG); + cmd->length = 2; + cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; + cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff); + + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb_put(skb, sizeof(*cmd)); + skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", + cmd->data[0], cmd->data[1]); + } + + if (priv->btmrvl_dev.pscmd) { + priv->btmrvl_dev.pscmd = 0; + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + ret = -ENOMEM; + goto exit; + } + + cmd = (struct btmrvl_cmd *) skb->tail; + cmd->ocf_ogf = cpu_to_le16((OGF << 10) | + BT_CMD_AUTO_SLEEP_MODE); + cmd->length = 1; + + if (priv->btmrvl_dev.psmode) + cmd->data[0] = BT_PS_ENABLE; + else + cmd->data[0] = BT_PS_DISABLE; + + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb_put(skb, sizeof(*cmd)); + skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + BT_DBG("Queue PSMODE Command:%d", cmd->data[0]); + } + + if (priv->btmrvl_dev.hscmd) { + priv->btmrvl_dev.hscmd = 0; + + if (priv->btmrvl_dev.hsmode) { + ret = btmrvl_enable_hs(priv); + } else { + ret = priv->hw_wakeup_firmware(priv); + priv->adapter->hs_state = HS_DEACTIVATED; + } + } + +exit: + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) +{ + u8 ret = 0; + + BT_DBG("Enter"); + + if (!skb || !skb->data) { + BT_DBG("Leave"); + return -EINVAL; + } + + if (!skb->len || ((skb->len + BTM_HEADER_LEN) > BTM_UPLD_SIZE)) { + BT_ERR("Tx Error: Bad skb length %d : %d", + skb->len, BTM_UPLD_SIZE); + BT_DBG("Leave"); + return -EINVAL; + } + + if (skb_headroom(skb) < BTM_HEADER_LEN) { + struct sk_buff *tmp = skb; + + skb = skb_realloc_headroom(skb, BTM_HEADER_LEN); + if (!skb) { + BT_ERR("Tx Error: realloc_headroom failed %d", + BTM_HEADER_LEN); + skb = tmp; + BT_DBG("Leave"); + return -EINVAL; + } + + kfree_skb(tmp); + } + + skb_push(skb, BTM_HEADER_LEN); + + /* header type: byte[3] + * HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor + * header length: byte[2][1][0] + */ + + skb->data[0] = (skb->len & 0x0000ff); + skb->data[1] = (skb->len & 0x00ff00) >> 8; + skb->data[2] = (skb->len & 0xff0000) >> 16; + skb->data[3] = bt_cb(skb)->pkt_type; + + if (priv->hw_host_to_card) + ret = priv->hw_host_to_card(priv, skb->data, skb->len); + + BT_DBG("Leave"); + + return ret; +} + +static void btmrvl_init_adapter(struct btmrvl_private *priv) +{ + BT_DBG("Enter"); + + skb_queue_head_init(&priv->adapter->tx_queue); + + priv->adapter->ps_state = PS_AWAKE; + + init_waitqueue_head(&priv->adapter->cmd_wait_q); + + BT_DBG("Leave"); +} + +static void btmrvl_free_adapter(struct btmrvl_private *priv) +{ + BT_DBG("Enter"); + + skb_queue_purge(&priv->adapter->tx_queue); + + kfree(priv->adapter); + + priv->adapter = NULL; + + BT_DBG("Leave"); +} + +static int +btmrvl_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) +{ + BT_DBG("Enter"); + + BT_DBG("Leave"); + + return -ENOIOCTLCMD; +} + +static void btmrvl_destruct(struct hci_dev *hdev) +{ + BT_DBG("Enter"); + + BT_DBG("Leave"); +} + +static int btmrvl_send_frame(struct sk_buff *skb) +{ + struct hci_dev *hdev = (struct hci_dev *)skb->dev; + struct btmrvl_private *priv = NULL; + + BT_DBG("Enter: type=%d, len=%d", skb->pkt_type, skb->len); + + if (!hdev || !hdev->driver_data) { + BT_ERR("Frame for unknown HCI device"); + BT_DBG("Leave"); + return -ENODEV; + } + + priv = (struct btmrvl_private *)hdev->driver_data; + if (!test_bit(HCI_RUNNING, &hdev->flags)) { + BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags); + print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET, + skb->data, skb->len); + BT_DBG("Leave"); + return -EBUSY; + } + + switch (bt_cb(skb)->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + break; + } + + skb_queue_tail(&priv->adapter->tx_queue, skb); + + wake_up_interruptible(&priv->main_thread.wait_q); + + BT_DBG("Leave"); + + return 0; +} + +static int btmrvl_flush(struct hci_dev *hdev) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) hdev->driver_data; + + BT_DBG("Enter"); + + skb_queue_purge(&priv->adapter->tx_queue); + + BT_DBG("Leave"); + + return 0; +} + +static int btmrvl_close(struct hci_dev *hdev) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) hdev->driver_data; + + BT_DBG("Enter"); + + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) { + BT_DBG("Leave"); + return 0; + } + + skb_queue_purge(&priv->adapter->tx_queue); + + BT_DBG("Leave"); + + return 0; +} + +static int btmrvl_open(struct hci_dev *hdev) +{ + BT_DBG("Enter"); + + set_bit(HCI_RUNNING, &hdev->flags); + + BT_DBG("Leave"); + + return 0; +} + +/* + * This function handles the event generated by firmware, rx data + * received from firmware, and tx data sent from kernel. + */ +static int btmrvl_service_main_thread(void *data) +{ + struct btmrvl_thread *thread = data; + struct btmrvl_private *priv = thread->priv; + struct btmrvl_adapter *adapter = priv->adapter; + wait_queue_t wait; + struct sk_buff *skb; + ulong flags; + + BT_DBG("Enter"); + + init_waitqueue_entry(&wait, current); + + current->flags |= PF_NOFREEZE; + + for (;;) { + add_wait_queue(&thread->wait_q, &wait); + + set_current_state(TASK_INTERRUPTIBLE); + + if (adapter->wakeup_tries || + ((!adapter->int_count) && + (!priv->btmrvl_dev.tx_dnld_rdy || + skb_queue_empty(&adapter->tx_queue)))) { + BT_DBG("main_thread is sleeping..."); + schedule(); + } + + set_current_state(TASK_RUNNING); + + remove_wait_queue(&thread->wait_q, &wait); + + BT_DBG("main_thread woke up"); + + if (kthread_should_stop()) { + BT_DBG("main_thread: break from main thread"); + break; + } + + spin_lock_irqsave(&priv->driver_lock, flags); + if (adapter->int_count) { + adapter->int_count = 0; + } else if ((adapter->ps_state == PS_SLEEP) && + !skb_queue_empty(&adapter->tx_queue)) { + spin_unlock_irqrestore(&priv->driver_lock, flags); + adapter->wakeup_tries++; + priv->hw_wakeup_firmware(priv); + continue; + } + spin_unlock_irqrestore(&priv->driver_lock, flags); + + if (adapter->ps_state == PS_SLEEP) + continue; + + if (!priv->btmrvl_dev.tx_dnld_rdy) + continue; + + skb = skb_dequeue(&adapter->tx_queue); + if (skb) { + if (btmrvl_tx_pkt(priv, skb)) + priv->btmrvl_dev.hcidev->stat.err_tx++; + else + priv->btmrvl_dev.hcidev->stat.byte_tx + += skb->len; + + kfree_skb(skb); + } + } + + BT_DBG("Leave"); + + return 0; +} + +struct btmrvl_private *btmrvl_add_card(void *card) +{ + struct hci_dev *hdev = NULL; + struct btmrvl_private *priv = NULL; + int ret; + + BT_DBG("Enter"); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + BT_ERR("Can not allocate priv"); + goto err_priv; + } + + priv->adapter = kzalloc(sizeof(*priv->adapter), GFP_KERNEL); + if (!priv->adapter) { + BT_ERR("Allocate buffer for btmrvl_adapter failed!"); + goto err_adapter; + } + + btmrvl_init_adapter(priv); + + hdev = hci_alloc_dev(); + if (!hdev) { + BT_ERR("Can not allocate HCI device"); + goto err_hdev; + } + + BT_DBG("Starting kthread..."); + priv->main_thread.priv = priv; + spin_lock_init(&priv->driver_lock); + + init_waitqueue_head(&priv->main_thread.wait_q); + priv->main_thread.task = kthread_run(btmrvl_service_main_thread, + &priv->main_thread, "btmrvl_main_service"); + + priv->btmrvl_dev.hcidev = hdev; + priv->btmrvl_dev.card = card; + + hdev->driver_data = priv; + + priv->btmrvl_dev.tx_dnld_rdy = true; + + hdev->type = HCI_SDIO; + hdev->open = btmrvl_open; + hdev->close = btmrvl_close; + hdev->flush = btmrvl_flush; + hdev->send = btmrvl_send_frame; + hdev->destruct = btmrvl_destruct; + hdev->ioctl = btmrvl_ioctl; + hdev->owner = THIS_MODULE; + + ret = hci_register_dev(hdev); + if (ret < 0) { + BT_ERR("Can not register HCI device"); + goto err_hci_register_dev; + } + + BT_DBG("Leave"); + return priv; + +err_hci_register_dev: + /* Stop the thread servicing the interrupts */ + kthread_stop(priv->main_thread.task); + + hci_free_dev(hdev); + +err_hdev: + btmrvl_free_adapter(priv); + +err_adapter: + kfree(priv); + +err_priv: + BT_DBG("Leave"); + + return NULL; +} +EXPORT_SYMBOL_GPL(btmrvl_add_card); + +int btmrvl_remove_card(struct btmrvl_private *priv) +{ + struct hci_dev *hdev; + + BT_DBG("Enter"); + + hdev = priv->btmrvl_dev.hcidev; + + wake_up_interruptible(&priv->adapter->cmd_wait_q); + + kthread_stop(priv->main_thread.task); + + hci_unregister_dev(hdev); + + hci_free_dev(hdev); + + priv->btmrvl_dev.hcidev = NULL; + + btmrvl_free_adapter(priv); + + kfree(priv); + + BT_DBG("Leave"); + + return 0; +} +EXPORT_SYMBOL_GPL(btmrvl_remove_card); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell Bluetooth Driver v" VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 789221ecc870117b77e354d488d5d29f15410de8 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 2 Jun 2009 14:29:36 -0700 Subject: Bluetooth: Add Marvell BT-over-SDIO driver This driver supports Marvell Bluetooth enabled devices with SDIO interface. Currently only SD8688 chip is supported. The helper/firmware images of SD8688 can be downloaded from this tree: git://git.infradead.org/users/dwmw2/linux-firmware.git 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 diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index b049a79..8c89bd4 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -182,5 +182,18 @@ config BT_MRVL Say Y here to compile Marvell Bluetooth driver into the kernel or say M to compile it as module. +config BT_MRVL_SDIO + tristate "Marvell BT-over-SDIO driver" + depends on BT_MRVL && MMC + help + The driver for Marvell Bluetooth chipsets with SDIO interface. + + This driver is required if you want to use Marvell Bluetooth + devices with SDIO interface. Currently only SD8688 chipset is + supported. + + Say Y here to compile support for Marvell BT-over-SDIO driver + into the kernel or say M to compile it as module. + endmenu diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 3eff123..2dc12e7 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o btmrvl-objs := btmrvl_main.o obj-$(CONFIG_BT_MRVL) += btmrvl.o +obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c new file mode 100644 index 0000000..8f13e7b --- /dev/null +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -0,0 +1,1128 @@ +/** + * Marvell BT-over-SDIO driver: SDIO interface related functions. + * + * Copyright (C) 2009, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + **/ + +#include + +#include +#include + +#include +#include + +#include "btmrvl_drv.h" +#include "btmrvl_sdio.h" + +#define VERSION "1.0" + +#ifndef SDIO_DEVICE_ID_MARVELL_8688BT +#define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105 +#endif + +/* The btmrvl_sdio_remove() callback function is called + * when user removes this module from kernel space or ejects + * the card from the slot. The driver handles these 2 cases + * differently. + * If the user is removing the module, a MODULE_SHUTDOWN_REQ + * command is sent to firmware and interrupt will be disabled. + * If the card is removed, there is no need to send command + * or disable interrupt. + * + * The variable 'user_rmmod' is used to distinguish these two + * scenarios. This flag is initialized as FALSE in case the card + * is removed, and will be set to TRUE for module removal when + * module_exit function is called. + */ +static u8 user_rmmod; + +static const struct sdio_device_id btmrvl_sdio_ids[] = { + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8688BT)}, + {0, 0, 0, 0} +}; + +MODULE_DEVICE_TABLE(sdio, btmrvl_sdio_ids); + +static struct btmrvl_sdio_device btmrvl_sdio_devices[] = { + { + .dev_id = SDIO_DEVICE_ID_MARVELL_8688BT, + .helper = "sd8688_helper.bin", + .firmware = "sd8688.bin", + }, +}; + +static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card) +{ + u8 reg; + int ret; + + BT_DBG("Enter"); + + reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret); + if (!ret) + card->rx_unit = reg; + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat) +{ + int ret; + u8 fws0, fws1; + + BT_DBG("Enter"); + + *dat = 0; + + fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret); + + if (!ret) + fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); + + if (ret) { + BT_DBG("Leave"); + return -EIO; + } + + *dat = (((u16) fws1) << 8) | fws0; + + BT_DBG("Leave"); + + return 0; +} + +static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat) +{ + int ret; + u8 reg; + + BT_DBG("Enter"); + + reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret); + if (!ret) + *dat = (u16) reg << card->rx_unit; + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card, + u8 mask) +{ + int ret; + + BT_DBG("Enter"); + + sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret); + if (ret) { + BT_ERR("Unable to enable the host interrupt!"); + ret = -EIO; + } + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card, + u8 mask) +{ + int ret; + u8 host_int_mask; + + BT_DBG("Enter"); + + host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret); + if (ret) { + ret = -EIO; + goto done; + } + + host_int_mask &= ~mask; + + sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret); + if (ret < 0) { + BT_ERR("Unable to disable the host interrupt!"); + ret = -EIO; + goto done; + } + + ret = 0; + +done: + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits) +{ + unsigned int tries; + int ret; + u8 status; + + BT_DBG("Enter"); + + for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) { + status = sdio_readb(card->func, CARD_STATUS_REG, &ret); + if (ret) + goto failed; + if ((status & bits) == bits) + goto done; + + udelay(1); + } + + ret = -ETIMEDOUT; + +failed: + BT_ERR("FAILED! ret=%d", ret); + +done: + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card, + int pollnum) +{ + int ret = -ETIMEDOUT; + u16 firmwarestat; + unsigned int tries; + + BT_DBG("Enter"); + + /* Wait for firmware to become ready */ + for (tries = 0; tries < pollnum; tries++) { + if (btmrvl_sdio_read_fw_status(card, &firmwarestat) < 0) + continue; + + if (firmwarestat == FIRMWARE_READY) { + ret = 0; + break; + } else { + msleep(10); + } + } + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) +{ + const struct firmware *fw_helper = NULL; + const u8 *helper = NULL; + int ret; + void *tmphlprbuf = NULL; + int tmphlprbufsz, hlprblknow, helperlen; + u8 *helperbuf; + u32 tx_len; + + BT_DBG("Enter"); + + ret = request_firmware(&fw_helper, card->helper, + &card->func->dev); + if ((ret < 0) || !fw_helper) { + BT_ERR("request_firmware(helper) failed, error code = %d", + ret); + ret = -ENOENT; + goto done; + } + + helper = fw_helper->data; + helperlen = fw_helper->size; + + BT_DBG("Downloading helper image (%d bytes), block size %d bytes", + helperlen, SDIO_BLOCK_SIZE); + + tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN); + + tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL); + if (!tmphlprbuf) { + BT_ERR("Unable to allocate buffer for helper." + " Terminating download"); + ret = -ENOMEM; + goto done; + } + + memset(tmphlprbuf, 0, tmphlprbufsz); + + helperbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, BTSDIO_DMA_ALIGN); + + /* Perform helper data transfer */ + tx_len = (FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE) + - SDIO_HEADER_LEN; + hlprblknow = 0; + + do { + ret = btmrvl_sdio_poll_card_status(card, + CARD_IO_READY | DN_LD_CARD_RDY); + if (ret < 0) { + BT_ERR("Helper download poll status timeout @ %d", + hlprblknow); + goto done; + } + + /* Check if there is more data? */ + if (hlprblknow >= helperlen) + break; + + if (helperlen - hlprblknow < tx_len) + tx_len = helperlen - hlprblknow; + + /* Little-endian */ + helperbuf[0] = ((tx_len & 0x000000ff) >> 0); + helperbuf[1] = ((tx_len & 0x0000ff00) >> 8); + helperbuf[2] = ((tx_len & 0x00ff0000) >> 16); + helperbuf[3] = ((tx_len & 0xff000000) >> 24); + + memcpy(&helperbuf[SDIO_HEADER_LEN], &helper[hlprblknow], + tx_len); + + /* Now send the data */ + ret = sdio_writesb(card->func, card->ioport, + helperbuf, + FIRMWARE_TRANSFER_NBLOCK * + SDIO_BLOCK_SIZE); + if (ret < 0) { + BT_ERR("IO error during helper download @ %d", + hlprblknow); + goto done; + } + + hlprblknow += tx_len; + } while (true); + + BT_DBG("Transferring helper image EOF block"); + + memset(helperbuf, 0x0, SDIO_BLOCK_SIZE); + + ret = sdio_writesb(card->func, card->ioport, helperbuf, + SDIO_BLOCK_SIZE); + if (ret < 0) { + BT_ERR("IO error in writing helper image EOF block"); + goto done; + } + + ret = 0; + +done: + kfree(tmphlprbuf); + if (fw_helper) + release_firmware(fw_helper); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) +{ + const struct firmware *fw_firmware = NULL; + const u8 *firmware = NULL; + int firmwarelen, tmpfwbufsz, ret; + unsigned int tries, offset; + u8 base0, base1; + void *tmpfwbuf = NULL; + u8 *fwbuf; + u16 len; + int txlen = 0, tx_blocks = 0, count = 0; + + BT_DBG("Enter"); + + ret = request_firmware(&fw_firmware, card->firmware, + &card->func->dev); + if ((ret < 0) || !fw_firmware) { + BT_ERR("request_firmware(firmware) failed, error code = %d", + ret); + ret = -ENOENT; + goto done; + } + + firmware = fw_firmware->data; + firmwarelen = fw_firmware->size; + + BT_DBG("Downloading FW image (%d bytes)", firmwarelen); + + tmpfwbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN); + tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL); + if (!tmpfwbuf) { + BT_ERR("Unable to allocate buffer for firmware." + " Terminating download"); + ret = -ENOMEM; + goto done; + } + + memset(tmpfwbuf, 0, tmpfwbufsz); + + /* Ensure aligned firmware buffer */ + fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, BTSDIO_DMA_ALIGN); + + /* Perform firmware data transfer */ + offset = 0; + do { + ret = btmrvl_sdio_poll_card_status(card, + CARD_IO_READY | DN_LD_CARD_RDY); + if (ret < 0) { + BT_ERR("FW download with helper poll status" + " timeout @ %d", offset); + goto done; + } + + /* Check if there is more data ? */ + if (offset >= firmwarelen) + break; + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + base0 = sdio_readb(card->func, + SQ_READ_BASE_ADDRESS_A0_REG, &ret); + if (ret) { + BT_ERR("BASE0 register read failed:" + " base0 = 0x%04X(%d)." + " Terminating download", + base0, base0); + ret = -EIO; + goto done; + } + base1 = sdio_readb(card->func, + SQ_READ_BASE_ADDRESS_A1_REG, &ret); + if (ret) { + BT_ERR("BASE1 register read failed:" + " base1 = 0x%04X(%d)." + " Terminating download", + base1, base1); + ret = -EIO; + goto done; + } + + len = (((u16) base1) << 8) | base0; + if (len) + break; + + udelay(10); + } + + if (!len) + break; + else if (len > BTM_UPLD_SIZE) { + BT_ERR("FW download failure @%d, invalid length %d", + offset, len); + ret = -EINVAL; + goto done; + } + + txlen = len; + + if (len & BIT(0)) { + count++; + if (count > MAX_WRITE_IOMEM_RETRY) { + BT_ERR("FW download failure @%d, " + "over max retry count", offset); + ret = -EIO; + goto done; + } + BT_ERR("FW CRC error indicated by the helper: " + "len = 0x%04X, txlen = %d", len, txlen); + len &= ~BIT(0); + /* Set txlen to 0 so as to resend from same offset */ + txlen = 0; + } else { + count = 0; + + /* Last block ? */ + if (firmwarelen - offset < txlen) + txlen = firmwarelen - offset; + + tx_blocks = + (txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE; + + memcpy(fwbuf, &firmware[offset], txlen); + } + + ret = sdio_writesb(card->func, card->ioport, fwbuf, + tx_blocks * SDIO_BLOCK_SIZE); + + if (ret < 0) { + BT_ERR("FW download, writesb(%d) failed @%d", + count, offset); + sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG, + &ret); + if (ret) + BT_ERR("writeb failed (CFG)"); + } + + offset += txlen; + } while (true); + + BT_DBG("FW download over, size %d bytes", offset); + + ret = 0; + +done: + kfree(tmpfwbuf); + + if (fw_firmware) + release_firmware(fw_firmware); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) +{ + u16 buf_len = 0; + int ret, buf_block_len, blksz; + struct sk_buff *skb = NULL; + u32 type; + u8 *payload = NULL; + struct hci_dev *hdev = priv->btmrvl_dev.hcidev; + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_ERR("card or function is NULL!"); + ret = -EINVAL; + goto exit; + } + + /* Read the length of data to be transferred */ + ret = btmrvl_sdio_read_rx_len(card, &buf_len); + if (ret < 0) { + BT_ERR("read rx_len failed"); + ret = -EIO; + goto exit; + } + + blksz = SDIO_BLOCK_SIZE; + buf_block_len = (buf_len + blksz - 1) / blksz; + + if (buf_len <= SDIO_HEADER_LEN + || (buf_block_len * blksz) > ALLOC_BUF_SIZE) { + BT_ERR("invalid packet length: %d", buf_len); + ret = -EINVAL; + goto exit; + } + + /* Allocate buffer */ + skb = bt_skb_alloc(buf_block_len * blksz + BTSDIO_DMA_ALIGN, + GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + goto exit; + } + + if ((u32) skb->data & (BTSDIO_DMA_ALIGN - 1)) { + skb_put(skb, (u32) skb->data & (BTSDIO_DMA_ALIGN - 1)); + skb_pull(skb, (u32) skb->data & (BTSDIO_DMA_ALIGN - 1)); + } + + payload = skb->tail; + + ret = sdio_readsb(card->func, payload, card->ioport, + buf_block_len * blksz); + if (ret < 0) { + BT_ERR("readsb failed: %d", ret); + ret = -EIO; + goto exit; + } + + /* This is SDIO specific header length: byte[2][1][0], type: byte[3] + * (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) + */ + + buf_len = payload[0]; + buf_len |= (u16) payload[1] << 8; + type = payload[3]; + + switch (type) { + case HCI_ACLDATA_PKT: + case HCI_SCODATA_PKT: + case HCI_EVENT_PKT: + bt_cb(skb)->pkt_type = type; + skb->dev = (void *)hdev; + skb_put(skb, buf_len); + skb_pull(skb, SDIO_HEADER_LEN); + + if (type == HCI_EVENT_PKT) + btmrvl_check_evtpkt(priv, skb); + + hci_recv_frame(skb); + hdev->stat.byte_rx += buf_len; + break; + + case MRVL_VENDOR_PKT: + bt_cb(skb)->pkt_type = HCI_VENDOR_PKT; + skb->dev = (void *)hdev; + skb_put(skb, buf_len); + skb_pull(skb, SDIO_HEADER_LEN); + + if (btmrvl_process_event(priv, skb)) + hci_recv_frame(skb); + + hdev->stat.byte_rx += buf_len; + break; + + default: + BT_ERR("Unknow packet type:%d", type); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload, + blksz * buf_block_len); + + kfree_skb(skb); + skb = NULL; + break; + } + +exit: + if (ret) { + hdev->stat.err_rx++; + if (skb) + kfree_skb(skb); + } + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg) +{ + int ret; + u8 sdio_ireg = 0; + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + + BT_DBG("Enter"); + + *ireg = 0; + + sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); + if (ret) { + BT_ERR("sdio_readb: read int status register failed"); + ret = -EIO; + goto done; + } + + if (sdio_ireg != 0) { + /* + * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS + * Clear the interrupt status register and re-enable the + * interrupt. + */ + BT_DBG("sdio_ireg = 0x%x", sdio_ireg); + + sdio_writeb(card->func, ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS | + UP_LD_HOST_INT_STATUS), + HOST_INTSTATUS_REG, &ret); + if (ret) { + BT_ERR("sdio_writeb: clear int status register " + "failed"); + ret = -EIO; + goto done; + } + } + + if (sdio_ireg & DN_LD_HOST_INT_STATUS) { + if (priv->btmrvl_dev.tx_dnld_rdy) + BT_DBG("tx_done already received: " + " int_status=0x%x", sdio_ireg); + else + priv->btmrvl_dev.tx_dnld_rdy = true; + } + + if (sdio_ireg & UP_LD_HOST_INT_STATUS) + btmrvl_sdio_card_to_host(priv); + + *ireg = sdio_ireg; + + ret = 0; + +done: + BT_DBG("Leave"); + + return ret; +} + +static void btmrvl_sdio_interrupt(struct sdio_func *func) +{ + struct btmrvl_private *priv; + struct hci_dev *hcidev; + struct btmrvl_sdio_card *card; + u8 ireg = 0; + + BT_DBG("Enter"); + + card = sdio_get_drvdata(func); + if (card && card->priv) { + priv = card->priv; + hcidev = priv->btmrvl_dev.hcidev; + + if (btmrvl_sdio_get_int_status(priv, &ireg)) + BT_ERR("reading HOST_INT_STATUS_REG failed"); + else + BT_DBG("HOST_INT_STATUS_REG %#x", ireg); + + btmrvl_interrupt(priv); + } + + BT_DBG("Leave"); +} + +static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) +{ + int ret = 0, i; + u8 reg; + struct sdio_func *func; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_ERR("Error: card or function is NULL!"); + ret = -EINVAL; + goto failed; + } + + func = card->func; + + for (i = 0; i < ARRAY_SIZE(btmrvl_sdio_devices); i++) { + if (func->device == btmrvl_sdio_devices[i].dev_id) + break; + } + + if (i == ARRAY_SIZE(btmrvl_sdio_devices)) { + BT_ERR("Error: unknown device id 0x%x", func->device); + ret = -EINVAL; + goto failed; + } + + card->helper = btmrvl_sdio_devices[i].helper; + card->firmware = btmrvl_sdio_devices[i].firmware; + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) { + BT_ERR("sdio_enable_func() failed: ret=%d", ret); + ret = -EIO; + goto release_host; + } + + ret = sdio_claim_irq(func, btmrvl_sdio_interrupt); + if (ret) { + BT_ERR("sdio_claim_irq failed: ret=%d", ret); + ret = -EIO; + goto disable_func; + } + + ret = sdio_set_block_size(card->func, SDIO_BLOCK_SIZE); + if (ret) { + BT_ERR("cannot set SDIO block size"); + ret = -EIO; + goto release_irq; + } + + reg = sdio_readb(func, IO_PORT_0_REG, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + card->ioport = reg; + + reg = sdio_readb(func, IO_PORT_1_REG, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + card->ioport |= (reg << 8); + + reg = sdio_readb(func, IO_PORT_2_REG, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + card->ioport |= (reg << 16); + + BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport); + + sdio_set_drvdata(func, card); + + sdio_release_host(func); + + BT_DBG("Leave"); + return 0; + +release_irq: + sdio_release_irq(func); + +disable_func: + sdio_disable_func(func); + +release_host: + sdio_release_host(func); + +failed: + BT_DBG("Leave"); + return ret; +} + +static int btmrvl_sdio_unregister_dev(struct btmrvl_sdio_card *card) +{ + BT_DBG("Enter"); + + if (card && card->func) { + sdio_claim_host(card->func); + sdio_release_irq(card->func); + sdio_disable_func(card->func); + sdio_release_host(card->func); + sdio_set_drvdata(card->func, NULL); + } + + BT_DBG("Leave"); + + return 0; +} + +static int btmrvl_sdio_enable_host_int(struct btmrvl_sdio_card *card) +{ + int ret; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_DBG("Leave"); + return -EINVAL; + } + + sdio_claim_host(card->func); + + ret = btmrvl_sdio_enable_host_int_mask(card, HIM_ENABLE); + + btmrvl_sdio_get_rx_unit(card); + + sdio_release_host(card->func); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_disable_host_int(struct btmrvl_sdio_card *card) +{ + int ret; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_DBG("Leave"); + return -EINVAL; + } + + sdio_claim_host(card->func); + + ret = btmrvl_sdio_disable_host_int_mask(card, HIM_DISABLE); + + sdio_release_host(card->func); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, + u8 *payload, u16 nb) +{ + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + int ret = 0; + int buf_block_len; + int blksz; + int i = 0; + u8 *buf = NULL; + void *tmpbuf = NULL; + int tmpbufsz; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_ERR("card or function is NULL!"); + BT_DBG("Leave"); + return -EINVAL; + } + + buf = payload; + if ((u32) payload & (BTSDIO_DMA_ALIGN - 1)) { + tmpbufsz = ALIGN_SZ(nb, BTSDIO_DMA_ALIGN); + tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL); + memset(tmpbuf, 0, tmpbufsz); + buf = (u8 *) ALIGN_ADDR(tmpbuf, BTSDIO_DMA_ALIGN); + memcpy(buf, payload, nb); + } + + blksz = SDIO_BLOCK_SIZE; + buf_block_len = (nb + blksz - 1) / blksz; + + sdio_claim_host(card->func); + + do { + /* Transfer data to card */ + ret = sdio_writesb(card->func, card->ioport, buf, + buf_block_len * blksz); + if (ret < 0) { + i++; + BT_ERR("i=%d writesb failed: %d", i, ret); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + payload, nb); + ret = -EIO; + if (i > MAX_WRITE_IOMEM_RETRY) + goto exit; + } + } while (ret); + + priv->btmrvl_dev.tx_dnld_rdy = false; + +exit: + sdio_release_host(card->func); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) +{ + int ret = 0; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_ERR("card or function is NULL!"); + BT_DBG("Leave"); + return -EINVAL; + } + sdio_claim_host(card->func); + + if (!btmrvl_sdio_verify_fw_download(card, 1)) { + BT_DBG("Firmware already downloaded!"); + goto done; + } + + ret = btmrvl_sdio_download_helper(card); + if (ret) { + BT_ERR("Failed to download helper!"); + ret = -EIO; + goto done; + } + + if (btmrvl_sdio_download_fw_w_helper(card)) { + BT_ERR("Failed to download firmware!"); + ret = -EIO; + goto done; + } + + if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) { + BT_ERR("FW failed to be active in time!"); + ret = -ETIMEDOUT; + goto done; + } + +done: + sdio_release_host(card->func); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv) +{ + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + int ret = 0; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_ERR("card or function is NULL!"); + BT_DBG("Leave"); + return -EINVAL; + } + + sdio_claim_host(card->func); + + sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret); + + sdio_release_host(card->func); + + BT_DBG("wake up firmware"); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret = 0; + struct btmrvl_private *priv = NULL; + struct btmrvl_sdio_card *card = NULL; + + BT_DBG("Enter"); + + BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d", + id->vendor, id->device, id->class, func->num); + + card = kzalloc(sizeof(*card), GFP_KERNEL); + if (!card) { + ret = -ENOMEM; + goto done; + } + + card->func = func; + + if (btmrvl_sdio_register_dev(card) < 0) { + BT_ERR("Failed to register BT device!"); + ret = -ENODEV; + goto free_card; + } + + /* Disable the interrupts on the card */ + btmrvl_sdio_disable_host_int(card); + + if (btmrvl_sdio_download_fw(card)) { + BT_ERR("Downloading firmware failed!"); + ret = -ENODEV; + goto unreg_dev; + } + + msleep(100); + + btmrvl_sdio_enable_host_int(card); + + priv = btmrvl_add_card(card); + if (!priv) { + BT_ERR("Initializing card failed!"); + ret = -ENODEV; + goto disable_host_int; + } + + card->priv = priv; + + /* Initialize the interface specific function pointers */ + priv->hw_host_to_card = btmrvl_sdio_host_to_card; + priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw; + + strncpy(priv->btmrvl_dev.name, "btmrvl_sdio0", + sizeof(priv->btmrvl_dev.name)); + + btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); + + BT_DBG("Leave"); + + return 0; + +disable_host_int: + btmrvl_sdio_disable_host_int(card); +unreg_dev: + btmrvl_sdio_unregister_dev(card); +free_card: + kfree(card); +done: + BT_DBG("Leave"); + + return ret; +} + +static void btmrvl_sdio_remove(struct sdio_func *func) +{ + struct btmrvl_sdio_card *card; + + BT_DBG("Enter"); + + if (func) { + card = sdio_get_drvdata(func); + if (card) { + /* Send SHUTDOWN command & disable interrupt + * if user removes the module. + */ + if (user_rmmod) { + btmrvl_send_module_cfg_cmd(card->priv, + MODULE_SHUTDOWN_REQ); + btmrvl_sdio_disable_host_int(card); + } + BT_DBG("unregester dev"); + btmrvl_sdio_unregister_dev(card); + btmrvl_remove_card(card->priv); + kfree(card); + } + } + + BT_DBG("Leave"); +} + +static struct sdio_driver bt_mrvl_sdio = { + .name = "btmrvl_sdio", + .id_table = btmrvl_sdio_ids, + .probe = btmrvl_sdio_probe, + .remove = btmrvl_sdio_remove, +}; + +static int btmrvl_sdio_init_module(void) +{ + BT_DBG("Enter"); + + if (sdio_register_driver(&bt_mrvl_sdio) != 0) { + BT_ERR("SDIO Driver Registration Failed"); + BT_DBG("Leave"); + return -ENODEV; + } + + /* Clear the flag in case user removes the card. */ + user_rmmod = 0; + + BT_DBG("Leave"); + + return 0; +} + +static void btmrvl_sdio_exit_module(void) +{ + BT_DBG("Enter"); + + /* Set the flag as user is removing this module. */ + user_rmmod = 1; + + sdio_unregister_driver(&bt_mrvl_sdio); + + BT_DBG("Leave"); +} + +module_init(btmrvl_sdio_init_module); +module_exit(btmrvl_sdio_exit_module); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell BT-over-SDIO Driver v" VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h new file mode 100644 index 0000000..08bef33 --- /dev/null +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -0,0 +1,113 @@ +/** + * Marvell BT-over-SDIO driver: SDIO interface related definitions + * + * Copyright (C) 2009, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + **/ + +#ifndef _BTMRVL_SDIO_H_ +#define _BTMRVL_SDIO_H_ + +#define SDIO_HEADER_LEN 4 + +/* SD block size can not bigger than 64 due to buf size limit in firmware */ +/* define SD block size for data Tx/Rx */ +#define SDIO_BLOCK_SIZE 64 + +/* Number of blocks for firmware transfer */ +#define FIRMWARE_TRANSFER_NBLOCK 2 + +/* This is for firmware specific length */ +#define FW_EXTRA_LEN 36 + +#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024) + +#define MRVDRV_BT_RX_PACKET_BUFFER_SIZE \ + (HCI_MAX_FRAME_SIZE + FW_EXTRA_LEN) + +#define ALLOC_BUF_SIZE (((max_t (int, MRVDRV_BT_RX_PACKET_BUFFER_SIZE, \ + MRVDRV_SIZE_OF_CMD_BUFFER) + SDIO_HEADER_LEN \ + + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE) \ + * SDIO_BLOCK_SIZE) + +/* The number of times to try when polling for status */ +#define MAX_POLL_TRIES 100 + +/* Max retry number of CMD53 write */ +#define MAX_WRITE_IOMEM_RETRY 2 + +/* Host Control Registers */ +#define IO_PORT_0_REG 0x00 +#define IO_PORT_1_REG 0x01 +#define IO_PORT_2_REG 0x02 + +#define CONFIG_REG 0x03 +#define HOST_POWER_UP BIT(1) +#define HOST_CMD53_FIN BIT(2) + +#define HOST_INT_MASK_REG 0x04 +#define HIM_DISABLE 0xff +#define HIM_ENABLE (BIT(0) | BIT(1)) + +#define HOST_INTSTATUS_REG 0x05 +#define UP_LD_HOST_INT_STATUS BIT(0) +#define DN_LD_HOST_INT_STATUS BIT(1) + +/* Card Control Registers */ +#define SQ_READ_BASE_ADDRESS_A0_REG 0x10 +#define SQ_READ_BASE_ADDRESS_A1_REG 0x11 + +#define CARD_STATUS_REG 0x20 +#define DN_LD_CARD_RDY BIT(0) +#define CARD_IO_READY BIT(3) + +#define CARD_FW_STATUS0_REG 0x40 +#define CARD_FW_STATUS1_REG 0x41 +#define FIRMWARE_READY 0xfedc + +#define CARD_RX_LEN_REG 0x42 +#define CARD_RX_UNIT_REG 0x43 + + +struct btmrvl_sdio_card { + struct sdio_func *func; + u32 ioport; + const char *helper; + const char *firmware; + u8 rx_unit; + struct btmrvl_private *priv; +}; + +struct btmrvl_sdio_device { + unsigned short dev_id; + const char *helper; + const char *firmware; +}; + + +/* Platform specific DMA alignment */ +#define BTSDIO_DMA_ALIGN 8 + +/* Macros for Data Alignment : size */ +#define ALIGN_SZ(p, a) \ + (((p) + ((a) - 1)) & ~((a) - 1)) + +/* Macros for Data Alignment : address */ +#define ALIGN_ADDR(p, a) \ + ((((u32)(p)) + (((u32)(a)) - 1)) & ~(((u32)(a)) - 1)) + +#endif /* _BTMRVL_SDIO_H_ */ -- cgit v0.10.2 From fb784f0508d5aa39a23e72879a8dfb517c6f6e7f Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 2 Jun 2009 14:29:37 -0700 Subject: Bluetooth: Add debugfs support to btmrvl driver /debug/btmrvl/config/ /debug/btmrvl/status/ See Documentation/btmrvl.txt for details. 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 diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 8c89bd4..5f04014 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -173,6 +173,7 @@ config BT_HCIVHCI config BT_MRVL tristate "Marvell Bluetooth driver support" select FW_LOADER + select DEBUG_FS help The core driver to support Marvell Bluetooth devices. diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 2dc12e7..75f70e0 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o -btmrvl-objs := btmrvl_main.o +btmrvl-objs := btmrvl_main.o btmrvl_debugfs.o obj-$(CONFIG_BT_MRVL) += btmrvl.o obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c new file mode 100644 index 0000000..747bb0c --- /dev/null +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -0,0 +1,469 @@ +/** + * Marvell Bluetooth driver: debugfs related functions + * + * Copyright (C) 2009, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + **/ + +#include + +#include +#include + +#include "btmrvl_drv.h" + +struct btmrvl_debugfs_data { + struct dentry *root_dir, *config_dir, *status_dir; + + /* config */ + struct dentry *drvdbg; + struct dentry *psmode; + struct dentry *pscmd; + struct dentry *hsmode; + struct dentry *hscmd; + struct dentry *gpiogap; + struct dentry *hscfgcmd; + + /* status */ + struct dentry *curpsmode; + struct dentry *hsstate; + struct dentry *psstate; + struct dentry *txdnldready; +}; + +static int btmrvl_open_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t btmrvl_hscfgcmd_write(struct file *file, + const char __user *ubuf, + size_t count, + loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 10, &result); + + priv->btmrvl_dev.hscfgcmd = result; + + if (priv->btmrvl_dev.hscfgcmd) { + btmrvl_prepare_command(priv); + wake_up_interruptible(&priv->main_thread.wait_q); + } + + return count; +} + +static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->btmrvl_dev.hscfgcmd); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_hscfgcmd_fops = { + .read = btmrvl_hscfgcmd_read, + .write = btmrvl_hscfgcmd_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 10, &result); + + priv->btmrvl_dev.psmode = result; + + return count; +} + +static ssize_t btmrvl_psmode_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->btmrvl_dev.psmode); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_psmode_fops = { + .read = btmrvl_psmode_read, + .write = btmrvl_psmode_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 10, &result); + + priv->btmrvl_dev.pscmd = result; + + if (priv->btmrvl_dev.pscmd) { + btmrvl_prepare_command(priv); + wake_up_interruptible(&priv->main_thread.wait_q); + } + + return count; + +} + +static ssize_t btmrvl_pscmd_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_pscmd_fops = { + .read = btmrvl_pscmd_read, + .write = btmrvl_pscmd_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 16, &result); + + priv->btmrvl_dev.gpio_gap = result; + + return count; +} + +static ssize_t btmrvl_gpiogap_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n", + priv->btmrvl_dev.gpio_gap); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_gpiogap_fops = { + .read = btmrvl_gpiogap_read, + .write = btmrvl_gpiogap_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 10, &result); + + priv->btmrvl_dev.hscmd = result; + if (priv->btmrvl_dev.hscmd) { + btmrvl_prepare_command(priv); + wake_up_interruptible(&priv->main_thread.wait_q); + } + + return count; +} + +static ssize_t btmrvl_hscmd_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_hscmd_fops = { + .read = btmrvl_hscmd_read, + .write = btmrvl_hscmd_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 10, &result); + + priv->btmrvl_dev.hsmode = result; + + return count; +} + +static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->btmrvl_dev.hsmode); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_hsmode_fops = { + .read = btmrvl_hsmode_read, + .write = btmrvl_hsmode_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_curpsmode_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_curpsmode_fops = { + .read = btmrvl_curpsmode_read, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->adapter->ps_state); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_psstate_fops = { + .read = btmrvl_psstate_read, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_hsstate_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->adapter->hs_state); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_hsstate_fops = { + .read = btmrvl_hsstate_read, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_txdnldready_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->btmrvl_dev.tx_dnld_rdy); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_txdnldready_fops = { + .read = btmrvl_txdnldready_read, + .open = btmrvl_open_generic, +}; + +void btmrvl_debugfs_init(struct hci_dev *hdev) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_debugfs_data *dbg; + + dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); + priv->debugfs_data = dbg; + + if (!dbg) { + BT_ERR("Can not allocate memory for btmrvl_debugfs_data."); + return; + } + + dbg->root_dir = debugfs_create_dir("btmrvl", NULL); + + dbg->config_dir = debugfs_create_dir("config", dbg->root_dir); + + dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, + hdev->driver_data, + &btmrvl_psmode_fops); + dbg->pscmd = + debugfs_create_file("pscmd", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_pscmd_fops); + dbg->gpiogap = + debugfs_create_file("gpiogap", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_gpiogap_fops); + dbg->hsmode = + debugfs_create_file("hsmode", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_hsmode_fops); + dbg->hscmd = + debugfs_create_file("hscmd", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_hscmd_fops); + dbg->hscfgcmd = + debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_hscfgcmd_fops); + + dbg->status_dir = debugfs_create_dir("status", dbg->root_dir); + dbg->curpsmode = debugfs_create_file("curpsmode", 0444, + dbg->status_dir, + hdev->driver_data, + &btmrvl_curpsmode_fops); + dbg->psstate = + debugfs_create_file("psstate", 0444, dbg->status_dir, + hdev->driver_data, &btmrvl_psstate_fops); + dbg->hsstate = + debugfs_create_file("hsstate", 0444, dbg->status_dir, + hdev->driver_data, &btmrvl_hsstate_fops); + dbg->txdnldready = + debugfs_create_file("txdnldready", 0444, dbg->status_dir, + hdev->driver_data, &btmrvl_txdnldready_fops); +} + +void btmrvl_debugfs_remove(struct hci_dev *hdev) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_debugfs_data *dbg = priv->debugfs_data; + + if (!dbg) + return; + + debugfs_remove(dbg->psmode); + debugfs_remove(dbg->pscmd); + debugfs_remove(dbg->gpiogap); + debugfs_remove(dbg->hsmode); + debugfs_remove(dbg->hscmd); + debugfs_remove(dbg->hscfgcmd); + debugfs_remove(dbg->config_dir); + + debugfs_remove(dbg->curpsmode); + debugfs_remove(dbg->psstate); + debugfs_remove(dbg->hsstate); + debugfs_remove(dbg->txdnldready); + debugfs_remove(dbg->status_dir); + + debugfs_remove(dbg->root_dir); + + kfree(dbg); +} diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 9ad71f4..7a12f68 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -79,6 +79,9 @@ struct btmrvl_private { u8 *payload, u16 nb); int (*hw_wakeup_firmware) (struct btmrvl_private *priv); spinlock_t driver_lock; /* spinlock used by driver */ +#ifdef CONFIG_DEBUG_FS + void *debugfs_data; +#endif }; #define MRVL_VENDOR_PKT 0xFE @@ -135,4 +138,9 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd); int btmrvl_prepare_command(struct btmrvl_private *priv); +#ifdef CONFIG_DEBUG_FS +void btmrvl_debugfs_init(struct hci_dev *hdev); +void btmrvl_debugfs_remove(struct hci_dev *hdev); +#endif + #endif /* _BTMRVL_DRV_H_ */ diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 11c2f2c..b4f4445 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -658,6 +658,10 @@ struct btmrvl_private *btmrvl_add_card(void *card) goto err_hci_register_dev; } +#ifdef CONFIG_DEBUG_FS + btmrvl_debugfs_init(hdev); +#endif + BT_DBG("Leave"); return priv; @@ -692,6 +696,10 @@ int btmrvl_remove_card(struct btmrvl_private *priv) kthread_stop(priv->main_thread.task); +#ifdef CONFIG_DEBUG_FS + btmrvl_debugfs_remove(hdev); +#endif + hci_unregister_dev(hdev); hci_free_dev(hdev); -- cgit v0.10.2 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 diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index d05737a..06b982a 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 0000000..34916a4 --- /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 v0.10.2 From e7a25f9839fd392ec2c96e7e2b3734501d761a24 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 13:42:54 +0200 Subject: Bluetooth: Fix Kconfig for Marvell Bluetooth driver The Marvell driver selects DEBUG_FS and FW_LOADER for its core driver and that is pointless. Don't select DEBUG_FS since it is either enabled or not and it is not for the driver to enable it. Also FW_LOADER is only used within the SDIO driver and so just have that one select the FW_LOADER option. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 5f04014..652367a 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -172,8 +172,6 @@ config BT_HCIVHCI config BT_MRVL tristate "Marvell Bluetooth driver support" - select FW_LOADER - select DEBUG_FS help The core driver to support Marvell Bluetooth devices. @@ -186,6 +184,7 @@ config BT_MRVL config BT_MRVL_SDIO tristate "Marvell BT-over-SDIO driver" depends on BT_MRVL && MMC + select FW_LOADER help The driver for Marvell Bluetooth chipsets with SDIO interface. -- cgit v0.10.2 From 08b0b0ce8c609b0e2284b134f0614e211374a038 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 15:44:03 +0200 Subject: Bluetooth: Fix compilation of Marvell driver without debugfs The Makefile entry for the Marvell driver is broken when it comes to handling the optional DEBUG_FS correctly. That must have been the reason why they were using select in Kconfig in the first place. Fix this and make it really optional. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 75f70e0..b3f57d2 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -15,10 +15,12 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o -btmrvl-objs := btmrvl_main.o btmrvl_debugfs.o obj-$(CONFIG_BT_MRVL) += btmrvl.o obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o +btmrvl-y := btmrvl_main.o +btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o + hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o -- cgit v0.10.2 From 944fe798c6a48336e82bbc0d4e280587325a4d95 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 15:46:07 +0200 Subject: Bluetooth: Remove pointless ifdef protection for Marvell header files Both header files of the Marvell Bluetooth driver are private anyway and if the driver happens to include them twice or they create a circular dependency then the driver needs fixing. So just remove both pointless ifdefs. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 7a12f68..5da3be4 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -19,9 +19,6 @@ * */ -#ifndef _BTMRVL_DRV_H_ -#define _BTMRVL_DRV_H_ - #include #include #include @@ -142,5 +139,3 @@ int btmrvl_prepare_command(struct btmrvl_private *priv); void btmrvl_debugfs_init(struct hci_dev *hdev); void btmrvl_debugfs_remove(struct hci_dev *hdev); #endif - -#endif /* _BTMRVL_DRV_H_ */ diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 08bef33..6beb340 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -19,9 +19,6 @@ * **/ -#ifndef _BTMRVL_SDIO_H_ -#define _BTMRVL_SDIO_H_ - #define SDIO_HEADER_LEN 4 /* SD block size can not bigger than 64 due to buf size limit in firmware */ @@ -109,5 +106,3 @@ struct btmrvl_sdio_device { /* Macros for Data Alignment : address */ #define ALIGN_ADDR(p, a) \ ((((u32)(p)) + (((u32)(a)) - 1)) & ~(((u32)(a)) - 1)) - -#endif /* _BTMRVL_SDIO_H_ */ -- cgit v0.10.2 From 542399037d0cb2b2e96dfb8ced35b07dfb1c3706 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 15:48:35 +0200 Subject: Bluetooth: Remove pointless casts from Marvell debugfs support The Marvell Bluetooth driver has debugfs support and they are casting like there is no tomorrow. Remove all of them and magically the code becomes more readable. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index 747bb0c..4617bd1 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -51,20 +51,15 @@ static int btmrvl_open_generic(struct inode *inode, struct file *file) } static ssize_t btmrvl_hscfgcmd_write(struct file *file, - const char __user *ubuf, - size_t count, - loff_t *ppos) + const char __user *ubuf, size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - - long result, ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); @@ -79,38 +74,35 @@ static ssize_t btmrvl_hscfgcmd_write(struct file *file, return count; } -static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->btmrvl_dev.hscfgcmd); + priv->btmrvl_dev.hscfgcmd); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hscfgcmd_fops = { - .read = btmrvl_hscfgcmd_read, - .write = btmrvl_hscfgcmd_write, - .open = btmrvl_open_generic, + .read = btmrvl_hscfgcmd_read, + .write = btmrvl_hscfgcmd_write, + .open = btmrvl_open_generic, }; static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - long result, ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); @@ -120,38 +112,35 @@ static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, return count; } -static ssize_t btmrvl_psmode_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->btmrvl_dev.psmode); + priv->btmrvl_dev.psmode); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_psmode_fops = { - .read = btmrvl_psmode_read, - .write = btmrvl_psmode_write, - .open = btmrvl_open_generic, + .read = btmrvl_psmode_read, + .write = btmrvl_psmode_write, + .open = btmrvl_open_generic, }; static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - long result, ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); @@ -167,13 +156,12 @@ static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, } -static ssize_t btmrvl_pscmd_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd); @@ -187,17 +175,15 @@ static const struct file_operations btmrvl_pscmd_fops = { }; static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - long result, ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 16, &result); @@ -207,38 +193,35 @@ static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, return count; } -static ssize_t btmrvl_gpiogap_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n", - priv->btmrvl_dev.gpio_gap); + priv->btmrvl_dev.gpio_gap); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_gpiogap_fops = { - .read = btmrvl_gpiogap_read, - .write = btmrvl_gpiogap_write, - .open = btmrvl_open_generic, + .read = btmrvl_gpiogap_read, + .write = btmrvl_gpiogap_write, + .open = btmrvl_open_generic, }; static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - long result, ret; + struct btmrvl_private *priv = (struct btmrvl_private *) file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); @@ -252,13 +235,12 @@ static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, return count; } -static ssize_t btmrvl_hscmd_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd); @@ -266,23 +248,21 @@ static ssize_t btmrvl_hscmd_read(struct file *file, char __user * userbuf, } static const struct file_operations btmrvl_hscmd_fops = { - .read = btmrvl_hscmd_read, - .write = btmrvl_hscmd_write, - .open = btmrvl_open_generic, + .read = btmrvl_hscmd_read, + .write = btmrvl_hscmd_write, + .open = btmrvl_open_generic, }; static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - long result, ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); @@ -293,32 +273,29 @@ static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, } static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->btmrvl_dev.hsmode); + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hsmode_fops = { - .read = btmrvl_hsmode_read, - .write = btmrvl_hsmode_write, - .open = btmrvl_open_generic, + .read = btmrvl_hsmode_read, + .write = btmrvl_hsmode_write, + .open = btmrvl_open_generic, }; -static ssize_t btmrvl_curpsmode_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode); @@ -326,71 +303,65 @@ static ssize_t btmrvl_curpsmode_read(struct file *file, char __user * userbuf, } static const struct file_operations btmrvl_curpsmode_fops = { - .read = btmrvl_curpsmode_read, - .open = btmrvl_open_generic, + .read = btmrvl_curpsmode_read, + .open = btmrvl_open_generic, }; static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->adapter->ps_state); + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_psstate_fops = { - .read = btmrvl_psstate_read, - .open = btmrvl_open_generic, + .read = btmrvl_psstate_read, + .open = btmrvl_open_generic, }; -static ssize_t btmrvl_hsstate_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->adapter->hs_state); + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hsstate_fops = { - .read = btmrvl_hsstate_read, - .open = btmrvl_open_generic, + .read = btmrvl_hsstate_read, + .open = btmrvl_open_generic, }; -static ssize_t btmrvl_txdnldready_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->btmrvl_dev.tx_dnld_rdy); + priv->btmrvl_dev.tx_dnld_rdy); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_txdnldready_fops = { - .read = btmrvl_txdnldready_read, - .open = btmrvl_open_generic, + .read = btmrvl_txdnldready_read, + .open = btmrvl_open_generic, }; void btmrvl_debugfs_init(struct hci_dev *hdev) { - struct btmrvl_private *priv = - (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_private *priv = hdev->driver_data; struct btmrvl_debugfs_data *dbg; dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); @@ -406,22 +377,16 @@ void btmrvl_debugfs_init(struct hci_dev *hdev) dbg->config_dir = debugfs_create_dir("config", dbg->root_dir); dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, - hdev->driver_data, - &btmrvl_psmode_fops); - dbg->pscmd = - debugfs_create_file("pscmd", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_psmode_fops); + dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_pscmd_fops); - dbg->gpiogap = - debugfs_create_file("gpiogap", 0644, dbg->config_dir, + dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_gpiogap_fops); - dbg->hsmode = - debugfs_create_file("hsmode", 0644, dbg->config_dir, + dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hsmode_fops); - dbg->hscmd = - debugfs_create_file("hscmd", 0644, dbg->config_dir, + dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hscmd_fops); - dbg->hscfgcmd = - debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, + dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hscfgcmd_fops); dbg->status_dir = debugfs_create_dir("status", dbg->root_dir); @@ -429,21 +394,19 @@ void btmrvl_debugfs_init(struct hci_dev *hdev) dbg->status_dir, hdev->driver_data, &btmrvl_curpsmode_fops); - dbg->psstate = - debugfs_create_file("psstate", 0444, dbg->status_dir, + dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_psstate_fops); - dbg->hsstate = - debugfs_create_file("hsstate", 0444, dbg->status_dir, + dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_hsstate_fops); - dbg->txdnldready = - debugfs_create_file("txdnldready", 0444, dbg->status_dir, - hdev->driver_data, &btmrvl_txdnldready_fops); + dbg->txdnldready = debugfs_create_file("txdnldready", 0444, + dbg->status_dir, + hdev->driver_data, + &btmrvl_txdnldready_fops); } void btmrvl_debugfs_remove(struct hci_dev *hdev) { - struct btmrvl_private *priv = - (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_private *priv = hdev->driver_data; struct btmrvl_debugfs_data *dbg = priv->debugfs_data; if (!dbg) -- cgit v0.10.2 From 4271e08d8b799171af18d7864908ec444282efe5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 16:00:22 +0200 Subject: Bluetooth: Some coding style cleanup for Marvell core driver The Marvell core Bluetooth driver has various weird casting and unneeded braces in its code that makes it hard to read. Remove all of these to make the code a little bit simpler. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index b4f4445..db4fdb1 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -48,19 +48,18 @@ EXPORT_SYMBOL_GPL(btmrvl_interrupt); void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) { - struct hci_event_hdr *hdr = (struct hci_event_hdr *)skb->data; + struct hci_event_hdr *hdr = (void *) skb->data; struct hci_ev_cmd_complete *ec; u16 opcode, ocf; BT_DBG("Enter"); if (hdr->evt == HCI_EV_CMD_COMPLETE) { - ec = (struct hci_ev_cmd_complete *)(skb->data + - HCI_EVENT_HDR_SIZE); + ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE); opcode = __le16_to_cpu(ec->opcode); ocf = hci_opcode_ocf(opcode); - if ((ocf == BT_CMD_MODULE_CFG_REQ) && - (priv->btmrvl_dev.sendcmdflag)) { + if (ocf == BT_CMD_MODULE_CFG_REQ && + priv->btmrvl_dev.sendcmdflag) { priv->btmrvl_dev.sendcmdflag = false; priv->adapter->cmd_complete = true; wake_up_interruptible(&priv->adapter->cmd_wait_q); @@ -74,8 +73,8 @@ EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt); int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) { struct btmrvl_adapter *adapter = priv->adapter; - u8 ret = 0; struct btmrvl_event *event; + u8 ret = 0; BT_DBG("Enter"); @@ -103,7 +102,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) case BT_CMD_HOST_SLEEP_CONFIG: if (!event->data[3]) BT_DBG("gpio=%x, gap=%x", event->data[1], - event->data[2]); + event->data[2]); else BT_DBG("HSCFG command failed"); break; @@ -121,12 +120,12 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) break; case BT_CMD_MODULE_CFG_REQ: - if ((priv->btmrvl_dev.sendcmdflag) && - (event->data[1] == MODULE_BRINGUP_REQ)) { + if (priv->btmrvl_dev.sendcmdflag && + event->data[1] == MODULE_BRINGUP_REQ) { BT_DBG("EVENT:%s", (event->data[2]) ? "Bring-up failed" : "Bring-up succeed"); - } else if ((priv->btmrvl_dev.sendcmdflag) && - (event->data[1] == MODULE_SHUTDOWN_REQ)) { + } else if (priv->btmrvl_dev.sendcmdflag && + event->data[1] == MODULE_SHUTDOWN_REQ) { BT_DBG("EVENT:%s", (event->data[2]) ? "Shutdown failed" : "Shutdown succeed"); } else { @@ -160,9 +159,9 @@ EXPORT_SYMBOL_GPL(btmrvl_process_event); int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) { - struct sk_buff *skb = NULL; - u8 ret = 0; + struct sk_buff *skb; struct btmrvl_cmd *cmd; + u8 ret = 0; BT_DBG("Enter"); @@ -181,7 +180,7 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; skb_put(skb, sizeof(*cmd)); - skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); priv->btmrvl_dev.sendcmdflag = true; @@ -192,13 +191,12 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) wake_up_interruptible(&priv->main_thread.wait_q); - if (!wait_event_interruptible_timeout( - priv->adapter->cmd_wait_q, - priv->adapter->cmd_complete, - msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) { + if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, + priv->adapter->cmd_complete, + msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) { ret = -ETIMEDOUT; BT_ERR("module_cfg_cmd(%x): timeout: %d", - subcmd, priv->btmrvl_dev.sendcmdflag); + subcmd, priv->btmrvl_dev.sendcmdflag); } BT_DBG("module cfg Command done"); @@ -212,9 +210,9 @@ EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); static int btmrvl_enable_hs(struct btmrvl_private *priv) { - struct sk_buff *skb = NULL; - u8 ret = 0; + struct sk_buff *skb; struct btmrvl_cmd *cmd; + u8 ret = 0; BT_DBG("Enter"); @@ -232,22 +230,20 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; skb_put(skb, sizeof(*cmd)); - skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); BT_DBG("Queue hs enable Command"); wake_up_interruptible(&priv->main_thread.wait_q); - if (!wait_event_interruptible_timeout( - priv->adapter->cmd_wait_q, + if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, priv->adapter->hs_state, msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED))) { ret = -ETIMEDOUT; - BT_ERR("timeout: %d, %d,%d", - priv->adapter->hs_state, - priv->adapter->ps_state, - priv->adapter->wakeup_tries); + BT_ERR("timeout: %d, %d,%d", priv->adapter->hs_state, + priv->adapter->ps_state, + priv->adapter->wakeup_tries); } exit: @@ -259,8 +255,8 @@ exit: int btmrvl_prepare_command(struct btmrvl_private *priv) { struct sk_buff *skb = NULL; - u8 ret = 0; struct btmrvl_cmd *cmd; + u8 ret = 0; BT_DBG("Enter"); @@ -284,11 +280,11 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; skb_put(skb, sizeof(*cmd)); - skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", - cmd->data[0], cmd->data[1]); + cmd->data[0], cmd->data[1]); } if (priv->btmrvl_dev.pscmd) { @@ -314,7 +310,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; skb_put(skb, sizeof(*cmd)); - skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); BT_DBG("Queue PSMODE Command:%d", cmd->data[0]); @@ -350,7 +346,7 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) if (!skb->len || ((skb->len + BTM_HEADER_LEN) > BTM_UPLD_SIZE)) { BT_ERR("Tx Error: Bad skb length %d : %d", - skb->len, BTM_UPLD_SIZE); + skb->len, BTM_UPLD_SIZE); BT_DBG("Leave"); return -EINVAL; } @@ -416,8 +412,8 @@ static void btmrvl_free_adapter(struct btmrvl_private *priv) BT_DBG("Leave"); } -static int -btmrvl_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) +static int btmrvl_ioctl(struct hci_dev *hdev, + unsigned int cmd, unsigned long arg) { BT_DBG("Enter"); @@ -435,7 +431,7 @@ static void btmrvl_destruct(struct hci_dev *hdev) static int btmrvl_send_frame(struct sk_buff *skb) { - struct hci_dev *hdev = (struct hci_dev *)skb->dev; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct btmrvl_private *priv = NULL; BT_DBG("Enter: type=%d, len=%d", skb->pkt_type, skb->len); @@ -446,11 +442,11 @@ static int btmrvl_send_frame(struct sk_buff *skb) return -ENODEV; } - priv = (struct btmrvl_private *)hdev->driver_data; + priv = (struct btmrvl_private *) hdev->driver_data; if (!test_bit(HCI_RUNNING, &hdev->flags)) { BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags); print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET, - skb->data, skb->len); + skb->data, skb->len); BT_DBG("Leave"); return -EBUSY; } @@ -480,8 +476,7 @@ static int btmrvl_send_frame(struct sk_buff *skb) static int btmrvl_flush(struct hci_dev *hdev) { - struct btmrvl_private *priv = - (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_private *priv = hdev->driver_data; BT_DBG("Enter"); @@ -494,8 +489,7 @@ static int btmrvl_flush(struct hci_dev *hdev) static int btmrvl_close(struct hci_dev *hdev) { - struct btmrvl_private *priv = - (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_private *priv = hdev->driver_data; BT_DBG("Enter"); @@ -547,9 +541,9 @@ static int btmrvl_service_main_thread(void *data) set_current_state(TASK_INTERRUPTIBLE); if (adapter->wakeup_tries || - ((!adapter->int_count) && - (!priv->btmrvl_dev.tx_dnld_rdy || - skb_queue_empty(&adapter->tx_queue)))) { + ((!adapter->int_count) && + (!priv->btmrvl_dev.tx_dnld_rdy || + skb_queue_empty(&adapter->tx_queue)))) { BT_DBG("main_thread is sleeping..."); schedule(); } @@ -568,8 +562,8 @@ static int btmrvl_service_main_thread(void *data) spin_lock_irqsave(&priv->driver_lock, flags); if (adapter->int_count) { adapter->int_count = 0; - } else if ((adapter->ps_state == PS_SLEEP) && - !skb_queue_empty(&adapter->tx_queue)) { + } else if (adapter->ps_state == PS_SLEEP && + !skb_queue_empty(&adapter->tx_queue)) { spin_unlock_irqrestore(&priv->driver_lock, flags); adapter->wakeup_tries++; priv->hw_wakeup_firmware(priv); @@ -588,8 +582,7 @@ static int btmrvl_service_main_thread(void *data) if (btmrvl_tx_pkt(priv, skb)) priv->btmrvl_dev.hcidev->stat.err_tx++; else - priv->btmrvl_dev.hcidev->stat.byte_tx - += skb->len; + priv->btmrvl_dev.hcidev->stat.byte_tx += skb->len; kfree_skb(skb); } @@ -603,7 +596,7 @@ static int btmrvl_service_main_thread(void *data) struct btmrvl_private *btmrvl_add_card(void *card) { struct hci_dev *hdev = NULL; - struct btmrvl_private *priv = NULL; + struct btmrvl_private *priv; int ret; BT_DBG("Enter"); @@ -634,7 +627,7 @@ struct btmrvl_private *btmrvl_add_card(void *card) init_waitqueue_head(&priv->main_thread.wait_q); priv->main_thread.task = kthread_run(btmrvl_service_main_thread, - &priv->main_thread, "btmrvl_main_service"); + &priv->main_thread, "btmrvl_main_service"); priv->btmrvl_dev.hcidev = hdev; priv->btmrvl_dev.card = card; @@ -717,6 +710,6 @@ int btmrvl_remove_card(struct btmrvl_private *priv) EXPORT_SYMBOL_GPL(btmrvl_remove_card); MODULE_AUTHOR("Marvell International Ltd."); -MODULE_DESCRIPTION("Marvell Bluetooth Driver v" VERSION); +MODULE_DESCRIPTION("Marvell Bluetooth Driver ver" VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From dcf47f3bc798888f9ea40b9f626d669dc62086bf Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 16:21:58 +0200 Subject: Bluetooth: Fix complicated assignment of firmware for Marvell devices The Marvell Bluetooth SDIO driver has a really complicated concept on how firmware names are assigned to specific device ids. Fix that by doing a proper structure and assign it to the module device table. And while at it fix various coding style weirdness that is still present in this driver. Signed-off-by: Marcel Holtman diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 8f13e7b..867ebe4 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -31,10 +31,6 @@ #define VERSION "1.0" -#ifndef SDIO_DEVICE_ID_MARVELL_8688BT -#define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105 -#endif - /* The btmrvl_sdio_remove() callback function is called * when user removes this module from kernel space or ejects * the card from the slot. The driver handles these 2 cases @@ -51,21 +47,21 @@ */ static u8 user_rmmod; -static const struct sdio_device_id btmrvl_sdio_ids[] = { - {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8688BT)}, - {0, 0, 0, 0} +static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = { + .helper = "sd8688_helper.bin", + .firmware = "sd8688.bin", }; -MODULE_DEVICE_TABLE(sdio, btmrvl_sdio_ids); +static const struct sdio_device_id btmrvl_sdio_ids[] = { + /* Marvell SD8688 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105), + .driver_data = (unsigned long) &btmrvl_sdio_sd6888 }, -static struct btmrvl_sdio_device btmrvl_sdio_devices[] = { - { - .dev_id = SDIO_DEVICE_ID_MARVELL_8688BT, - .helper = "sd8688_helper.bin", - .firmware = "sd8688.bin", - }, + { } /* Terminating entry */ }; +MODULE_DEVICE_TABLE(sdio, btmrvl_sdio_ids); + static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card) { u8 reg; @@ -125,7 +121,7 @@ static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat) } static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card, - u8 mask) + u8 mask) { int ret; @@ -143,7 +139,7 @@ static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card, } static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card, - u8 mask) + u8 mask) { int ret; u8 host_int_mask; @@ -203,7 +199,7 @@ done: } static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card, - int pollnum) + int pollnum) { int ret = -ETIMEDOUT; u16 firmwarestat; @@ -242,10 +238,10 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) BT_DBG("Enter"); ret = request_firmware(&fw_helper, card->helper, - &card->func->dev); + &card->func->dev); if ((ret < 0) || !fw_helper) { BT_ERR("request_firmware(helper) failed, error code = %d", - ret); + ret); ret = -ENOENT; goto done; } @@ -254,7 +250,7 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) helperlen = fw_helper->size; BT_DBG("Downloading helper image (%d bytes), block size %d bytes", - helperlen, SDIO_BLOCK_SIZE); + helperlen, SDIO_BLOCK_SIZE); tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN); @@ -301,10 +297,8 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) tx_len); /* Now send the data */ - ret = sdio_writesb(card->func, card->ioport, - helperbuf, - FIRMWARE_TRANSFER_NBLOCK * - SDIO_BLOCK_SIZE); + ret = sdio_writesb(card->func, card->ioport, helperbuf, + FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE); if (ret < 0) { BT_ERR("IO error during helper download @ %d", hlprblknow); @@ -319,7 +313,7 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) memset(helperbuf, 0x0, SDIO_BLOCK_SIZE); ret = sdio_writesb(card->func, card->ioport, helperbuf, - SDIO_BLOCK_SIZE); + SDIO_BLOCK_SIZE); if (ret < 0) { BT_ERR("IO error in writing helper image EOF block"); goto done; @@ -352,10 +346,10 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) BT_DBG("Enter"); ret = request_firmware(&fw_firmware, card->firmware, - &card->func->dev); + &card->func->dev); if ((ret < 0) || !fw_firmware) { BT_ERR("request_firmware(firmware) failed, error code = %d", - ret); + ret); ret = -ENOENT; goto done; } @@ -383,10 +377,10 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) offset = 0; do { ret = btmrvl_sdio_poll_card_status(card, - CARD_IO_READY | DN_LD_CARD_RDY); + CARD_IO_READY | DN_LD_CARD_RDY); if (ret < 0) { BT_ERR("FW download with helper poll status" - " timeout @ %d", offset); + " timeout @ %d", offset); goto done; } @@ -427,7 +421,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) break; else if (len > BTM_UPLD_SIZE) { BT_ERR("FW download failure @%d, invalid length %d", - offset, len); + offset, len); ret = -EINVAL; goto done; } @@ -465,9 +459,9 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) if (ret < 0) { BT_ERR("FW download, writesb(%d) failed @%d", - count, offset); + count, offset); sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG, - &ret); + &ret); if (ret) BT_ERR("writeb failed (CFG)"); } @@ -520,7 +514,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) buf_block_len = (buf_len + blksz - 1) / blksz; if (buf_len <= SDIO_HEADER_LEN - || (buf_block_len * blksz) > ALLOC_BUF_SIZE) { + || (buf_block_len * blksz) > ALLOC_BUF_SIZE) { BT_ERR("invalid packet length: %d", buf_len); ret = -EINVAL; goto exit; @@ -528,7 +522,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) /* Allocate buffer */ skb = bt_skb_alloc(buf_block_len * blksz + BTSDIO_DMA_ALIGN, - GFP_ATOMIC); + GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); goto exit; @@ -588,7 +582,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) default: BT_ERR("Unknow packet type:%d", type); print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload, - blksz * buf_block_len); + blksz * buf_block_len); kfree_skb(skb); skb = NULL; @@ -691,9 +685,9 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func) static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) { - int ret = 0, i; - u8 reg; struct sdio_func *func; + u8 reg; + int ret = 0; BT_DBG("Enter"); @@ -705,20 +699,6 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) func = card->func; - for (i = 0; i < ARRAY_SIZE(btmrvl_sdio_devices); i++) { - if (func->device == btmrvl_sdio_devices[i].dev_id) - break; - } - - if (i == ARRAY_SIZE(btmrvl_sdio_devices)) { - BT_ERR("Error: unknown device id 0x%x", func->device); - ret = -EINVAL; - goto failed; - } - - card->helper = btmrvl_sdio_devices[i].helper; - card->firmware = btmrvl_sdio_devices[i].firmware; - sdio_claim_host(func); ret = sdio_enable_func(func); @@ -983,7 +963,7 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv) } static int btmrvl_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) + const struct sdio_device_id *id) { int ret = 0; struct btmrvl_private *priv = NULL; @@ -1002,6 +982,12 @@ static int btmrvl_sdio_probe(struct sdio_func *func, card->func = func; + if (id->driver_data) { + struct btmrvl_sdio_device *data = (void *) id->driver_data; + card->helper = data->helper; + card->firmware = data->firmware; + } + if (btmrvl_sdio_register_dev(card) < 0) { BT_ERR("Failed to register BT device!"); ret = -ENODEV; diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 6beb340..2dd284e 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -90,7 +90,6 @@ struct btmrvl_sdio_card { }; struct btmrvl_sdio_device { - unsigned short dev_id; const char *helper; const char *firmware; }; -- cgit v0.10.2 From 9666fb356da78a5ec28403197d72e8cd6aa16424 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 21:45:04 +0200 Subject: Bluetooth: Fix module description strings for Marvell driver Make the module description entries for the core and also the Marvell SDIO driver match common practive inside the Bluetooth subsystem. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index db4fdb1..61168ec 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -710,6 +710,6 @@ int btmrvl_remove_card(struct btmrvl_private *priv) EXPORT_SYMBOL_GPL(btmrvl_remove_card); MODULE_AUTHOR("Marvell International Ltd."); -MODULE_DESCRIPTION("Marvell Bluetooth Driver ver" VERSION); +MODULE_DESCRIPTION("Marvell Bluetooth driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL v2"); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 867ebe4..0dea23e 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1109,6 +1109,6 @@ module_init(btmrvl_sdio_init_module); module_exit(btmrvl_sdio_exit_module); MODULE_AUTHOR("Marvell International Ltd."); -MODULE_DESCRIPTION("Marvell BT-over-SDIO Driver v" VERSION); +MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 60dee5ccd789ee8a380eee802b6cb24c52123428 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 10 Jun 2009 12:05:52 +0200 Subject: Bluetooth: Remove private device name of Marvell SDIO driver For some reason the btmrvl_device struct has a name field that the SDIO fills in, but then never ever uses again. That is totally pointless and so just remove it. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 5da3be4..411c7a7 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -24,7 +24,6 @@ #include #define BTM_HEADER_LEN 4 -#define BTM_DEV_NAME_LEN 32 #define BTM_UPLD_SIZE 2312 /* Time to wait until Host Sleep state change in millisecond */ @@ -39,7 +38,6 @@ struct btmrvl_thread { }; struct btmrvl_device { - char name[BTM_DEV_NAME_LEN]; void *card; struct hci_dev *hcidev; diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 0dea23e..7638f62 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1020,9 +1020,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, priv->hw_host_to_card = btmrvl_sdio_host_to_card; priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw; - strncpy(priv->btmrvl_dev.name, "btmrvl_sdio0", - sizeof(priv->btmrvl_dev.name)); - btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); BT_DBG("Leave"); -- cgit v0.10.2 From 91d697302b291205171840bfe84c1563e171acb2 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 10 Jun 2009 12:18:50 +0200 Subject: Bluetooth: Fix Marvell driver to use skb_put and hci_opcode_pack The Marvell driver has some weird quirks on how to construct proper SKBs with Bluetooth HCI commands. Fix it to use skb_put properly and also use hci_opcode_pack instead of self-crafted macro. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 61168ec..f5a3dc5 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -172,14 +172,13 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) goto exit; } - cmd = (struct btmrvl_cmd *) skb->tail; - cmd->ocf_ogf = cpu_to_le16((OGF << 10) | BT_CMD_MODULE_CFG_REQ); + cmd = skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_MODULE_CFG_REQ)); cmd->length = 1; cmd->data[0] = subcmd; bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; - skb_put(skb, sizeof(*cmd)); skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); @@ -223,13 +222,12 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) goto exit; } - cmd = (struct btmrvl_cmd *) skb->tail; - cmd->ocf_ogf = cpu_to_le16((OGF << 10) | BT_CMD_HOST_SLEEP_ENABLE); + cmd = skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_ENABLE)); cmd->length = 0; bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; - skb_put(skb, sizeof(*cmd)); skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); @@ -270,16 +268,14 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) goto exit; } - cmd = (struct btmrvl_cmd *) skb->tail; - cmd->ocf_ogf = cpu_to_le16((OGF << 10) | - BT_CMD_HOST_SLEEP_CONFIG); + cmd = skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_CONFIG)); cmd->length = 2; cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff); bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; - skb_put(skb, sizeof(*cmd)); skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); @@ -297,9 +293,8 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) goto exit; } - cmd = (struct btmrvl_cmd *) skb->tail; - cmd->ocf_ogf = cpu_to_le16((OGF << 10) | - BT_CMD_AUTO_SLEEP_MODE); + cmd = skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_AUTO_SLEEP_MODE)); cmd->length = 1; if (priv->btmrvl_dev.psmode) @@ -309,7 +304,6 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; - skb_put(skb, sizeof(*cmd)); skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); -- cgit v0.10.2 From e0721f99ba33d13a88746732be2d74ca805abf55 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 13 Jun 2009 07:27:19 +0200 Subject: Bluetooth: Fix last few compiler warning within Marvell core driver After fixing the driver to use skb_put properly for their HCI commands only a few compiler warnings are left. Add proper casting for them. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index f5a3dc5..bbc4446 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -172,7 +172,7 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) goto exit; } - cmd = skb_put(skb, sizeof(*cmd)); + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_MODULE_CFG_REQ)); cmd->length = 1; cmd->data[0] = subcmd; @@ -222,7 +222,7 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) goto exit; } - cmd = skb_put(skb, sizeof(*cmd)); + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_ENABLE)); cmd->length = 0; @@ -268,7 +268,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) goto exit; } - cmd = skb_put(skb, sizeof(*cmd)); + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_CONFIG)); cmd->length = 2; cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; @@ -293,7 +293,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) goto exit; } - cmd = skb_put(skb, sizeof(*cmd)); + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_AUTO_SLEEP_MODE)); cmd->length = 1; -- cgit v0.10.2 From 9374253ffe609f2d70dd5ae280182cb6f08fef08 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 13 Jun 2009 07:40:18 +0200 Subject: Bluetooth: Remove Enter/Leave debug statements from Marvell driver The Marvell Bluetooth driver is full of Enter/Leave debug statements and all of them are really pointless and only clutter the code. Seems to be some left-overs when they ported the driver from Windows. For the Linux driver lets remove these. Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index bbc4446..e605563b 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -32,8 +32,6 @@ */ void btmrvl_interrupt(struct btmrvl_private *priv) { - BT_DBG("Enter"); - priv->adapter->ps_state = PS_AWAKE; priv->adapter->wakeup_tries = 0; @@ -41,8 +39,6 @@ void btmrvl_interrupt(struct btmrvl_private *priv) priv->adapter->int_count++; wake_up_interruptible(&priv->main_thread.wait_q); - - BT_DBG("Leave"); } EXPORT_SYMBOL_GPL(btmrvl_interrupt); @@ -52,8 +48,6 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) struct hci_ev_cmd_complete *ec; u16 opcode, ocf; - BT_DBG("Enter"); - if (hdr->evt == HCI_EV_CMD_COMPLETE) { ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE); opcode = __le16_to_cpu(ec->opcode); @@ -65,8 +59,6 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) wake_up_interruptible(&priv->adapter->cmd_wait_q); } } - - BT_DBG("Leave"); } EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt); @@ -76,8 +68,6 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) struct btmrvl_event *event; u8 ret = 0; - BT_DBG("Enter"); - event = (struct btmrvl_event *) skb->data; if (event->ec != 0xff) { BT_DBG("Not Marvell Event=%x", event->ec); @@ -151,8 +141,6 @@ exit: if (!ret) kfree_skb(skb); - BT_DBG("Leave"); - return ret; } EXPORT_SYMBOL_GPL(btmrvl_process_event); @@ -161,15 +149,12 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) { struct sk_buff *skb; struct btmrvl_cmd *cmd; - u8 ret = 0; - - BT_DBG("Enter"); + int ret = 0; skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); - ret = -ENOMEM; - goto exit; + return -ENOMEM; } cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); @@ -200,9 +185,6 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) BT_DBG("module cfg Command done"); -exit: - BT_DBG("Leave"); - return ret; } EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); @@ -211,15 +193,12 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) { struct sk_buff *skb; struct btmrvl_cmd *cmd; - u8 ret = 0; - - BT_DBG("Enter"); + int ret = 0; skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); - ret = -ENOMEM; - goto exit; + return -ENOMEM; } cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); @@ -244,9 +223,6 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) priv->adapter->wakeup_tries); } -exit: - BT_DBG("Leave"); - return ret; } @@ -254,9 +230,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) { struct sk_buff *skb = NULL; struct btmrvl_cmd *cmd; - u8 ret = 0; - - BT_DBG("Enter"); + int ret = 0; if (priv->btmrvl_dev.hscfgcmd) { priv->btmrvl_dev.hscfgcmd = 0; @@ -264,8 +238,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); - ret = -ENOMEM; - goto exit; + return -ENOMEM; } cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); @@ -289,8 +262,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); - ret = -ENOMEM; - goto exit; + return -ENOMEM; } cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); @@ -321,27 +293,19 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) } } -exit: - BT_DBG("Leave"); - return ret; } static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) { - u8 ret = 0; + int ret = 0; - BT_DBG("Enter"); - - if (!skb || !skb->data) { - BT_DBG("Leave"); + if (!skb || !skb->data) return -EINVAL; - } if (!skb->len || ((skb->len + BTM_HEADER_LEN) > BTM_UPLD_SIZE)) { BT_ERR("Tx Error: Bad skb length %d : %d", skb->len, BTM_UPLD_SIZE); - BT_DBG("Leave"); return -EINVAL; } @@ -353,7 +317,6 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) BT_ERR("Tx Error: realloc_headroom failed %d", BTM_HEADER_LEN); skb = tmp; - BT_DBG("Leave"); return -EINVAL; } @@ -375,52 +338,35 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) if (priv->hw_host_to_card) ret = priv->hw_host_to_card(priv, skb->data, skb->len); - BT_DBG("Leave"); - return ret; } static void btmrvl_init_adapter(struct btmrvl_private *priv) { - BT_DBG("Enter"); - skb_queue_head_init(&priv->adapter->tx_queue); priv->adapter->ps_state = PS_AWAKE; init_waitqueue_head(&priv->adapter->cmd_wait_q); - - BT_DBG("Leave"); } static void btmrvl_free_adapter(struct btmrvl_private *priv) { - BT_DBG("Enter"); - skb_queue_purge(&priv->adapter->tx_queue); kfree(priv->adapter); priv->adapter = NULL; - - BT_DBG("Leave"); } static int btmrvl_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) { - BT_DBG("Enter"); - - BT_DBG("Leave"); - return -ENOIOCTLCMD; } static void btmrvl_destruct(struct hci_dev *hdev) { - BT_DBG("Enter"); - - BT_DBG("Leave"); } static int btmrvl_send_frame(struct sk_buff *skb) @@ -428,11 +374,10 @@ static int btmrvl_send_frame(struct sk_buff *skb) struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct btmrvl_private *priv = NULL; - BT_DBG("Enter: type=%d, len=%d", skb->pkt_type, skb->len); + BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len); if (!hdev || !hdev->driver_data) { BT_ERR("Frame for unknown HCI device"); - BT_DBG("Leave"); return -ENODEV; } @@ -441,7 +386,6 @@ static int btmrvl_send_frame(struct sk_buff *skb) BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags); print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET, skb->data, skb->len); - BT_DBG("Leave"); return -EBUSY; } @@ -463,8 +407,6 @@ static int btmrvl_send_frame(struct sk_buff *skb) wake_up_interruptible(&priv->main_thread.wait_q); - BT_DBG("Leave"); - return 0; } @@ -472,12 +414,8 @@ static int btmrvl_flush(struct hci_dev *hdev) { struct btmrvl_private *priv = hdev->driver_data; - BT_DBG("Enter"); - skb_queue_purge(&priv->adapter->tx_queue); - BT_DBG("Leave"); - return 0; } @@ -485,28 +423,18 @@ static int btmrvl_close(struct hci_dev *hdev) { struct btmrvl_private *priv = hdev->driver_data; - BT_DBG("Enter"); - - if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) { - BT_DBG("Leave"); + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) return 0; - } skb_queue_purge(&priv->adapter->tx_queue); - BT_DBG("Leave"); - return 0; } static int btmrvl_open(struct hci_dev *hdev) { - BT_DBG("Enter"); - set_bit(HCI_RUNNING, &hdev->flags); - BT_DBG("Leave"); - return 0; } @@ -523,8 +451,6 @@ static int btmrvl_service_main_thread(void *data) struct sk_buff *skb; ulong flags; - BT_DBG("Enter"); - init_waitqueue_entry(&wait, current); current->flags |= PF_NOFREEZE; @@ -582,8 +508,6 @@ static int btmrvl_service_main_thread(void *data) } } - BT_DBG("Leave"); - return 0; } @@ -593,8 +517,6 @@ struct btmrvl_private *btmrvl_add_card(void *card) struct btmrvl_private *priv; int ret; - BT_DBG("Enter"); - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { BT_ERR("Can not allocate priv"); @@ -649,7 +571,6 @@ struct btmrvl_private *btmrvl_add_card(void *card) btmrvl_debugfs_init(hdev); #endif - BT_DBG("Leave"); return priv; err_hci_register_dev: @@ -665,8 +586,6 @@ err_adapter: kfree(priv); err_priv: - BT_DBG("Leave"); - return NULL; } EXPORT_SYMBOL_GPL(btmrvl_add_card); @@ -675,8 +594,6 @@ int btmrvl_remove_card(struct btmrvl_private *priv) { struct hci_dev *hdev; - BT_DBG("Enter"); - hdev = priv->btmrvl_dev.hcidev; wake_up_interruptible(&priv->adapter->cmd_wait_q); @@ -697,8 +614,6 @@ int btmrvl_remove_card(struct btmrvl_private *priv) kfree(priv); - BT_DBG("Leave"); - return 0; } EXPORT_SYMBOL_GPL(btmrvl_remove_card); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 7638f62..224af53 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -67,23 +67,17 @@ static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card) u8 reg; int ret; - BT_DBG("Enter"); - reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret); if (!ret) card->rx_unit = reg; - BT_DBG("Leave"); - return ret; } static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat) { - int ret; u8 fws0, fws1; - - BT_DBG("Enter"); + int ret; *dat = 0; @@ -92,31 +86,23 @@ static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat) if (!ret) fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); - if (ret) { - BT_DBG("Leave"); + if (ret) return -EIO; - } *dat = (((u16) fws1) << 8) | fws0; - BT_DBG("Leave"); - return 0; } static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat) { - int ret; u8 reg; - - BT_DBG("Enter"); + int ret; reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret); if (!ret) *dat = (u16) reg << card->rx_unit; - BT_DBG("Leave"); - return ret; } @@ -125,64 +111,48 @@ static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card, { int ret; - BT_DBG("Enter"); - sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret); if (ret) { BT_ERR("Unable to enable the host interrupt!"); ret = -EIO; } - BT_DBG("Leave"); - return ret; } static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card, u8 mask) { - int ret; u8 host_int_mask; - - BT_DBG("Enter"); + int ret; host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret); - if (ret) { - ret = -EIO; - goto done; - } + if (ret) + return -EIO; host_int_mask &= ~mask; sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret); if (ret < 0) { BT_ERR("Unable to disable the host interrupt!"); - ret = -EIO; - goto done; + return -EIO; } - ret = 0; - -done: - BT_DBG("Leave"); - - return ret; + return 0; } static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits) { unsigned int tries; - int ret; u8 status; - - BT_DBG("Enter"); + int ret; for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) { status = sdio_readb(card->func, CARD_STATUS_REG, &ret); if (ret) goto failed; if ((status & bits) == bits) - goto done; + return ret; udelay(1); } @@ -192,9 +162,6 @@ static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits) failed: BT_ERR("FAILED! ret=%d", ret); -done: - BT_DBG("Leave"); - return ret; } @@ -205,8 +172,6 @@ static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card, u16 firmwarestat; unsigned int tries; - BT_DBG("Enter"); - /* Wait for firmware to become ready */ for (tries = 0; tries < pollnum; tries++) { if (btmrvl_sdio_read_fw_status(card, &firmwarestat) < 0) @@ -220,8 +185,6 @@ static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card, } } - BT_DBG("Leave"); - return ret; } @@ -235,8 +198,6 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) u8 *helperbuf; u32 tx_len; - BT_DBG("Enter"); - ret = request_firmware(&fw_helper, card->helper, &card->func->dev); if ((ret < 0) || !fw_helper) { @@ -326,8 +287,6 @@ done: if (fw_helper) release_firmware(fw_helper); - BT_DBG("Leave"); - return ret; } @@ -343,8 +302,6 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) u16 len; int txlen = 0, tx_blocks = 0, count = 0; - BT_DBG("Enter"); - ret = request_firmware(&fw_firmware, card->firmware, &card->func->dev); if ((ret < 0) || !fw_firmware) { @@ -479,8 +436,6 @@ done: if (fw_firmware) release_firmware(fw_firmware); - BT_DBG("Leave"); - return ret; } @@ -494,8 +449,6 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) struct hci_dev *hdev = priv->btmrvl_dev.hcidev; struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; - BT_DBG("Enter"); - if (!card || !card->func) { BT_ERR("card or function is NULL!"); ret = -EINVAL; @@ -596,8 +549,6 @@ exit: kfree_skb(skb); } - BT_DBG("Leave"); - return ret; } @@ -607,8 +558,6 @@ static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg) u8 sdio_ireg = 0; struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; - BT_DBG("Enter"); - *ireg = 0; sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); @@ -653,8 +602,6 @@ static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg) ret = 0; done: - BT_DBG("Leave"); - return ret; } @@ -665,8 +612,6 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func) struct btmrvl_sdio_card *card; u8 ireg = 0; - BT_DBG("Enter"); - card = sdio_get_drvdata(func); if (card && card->priv) { priv = card->priv; @@ -679,8 +624,6 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func) btmrvl_interrupt(priv); } - - BT_DBG("Leave"); } static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) @@ -689,8 +632,6 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) u8 reg; int ret = 0; - BT_DBG("Enter"); - if (!card || !card->func) { BT_ERR("Error: card or function is NULL!"); ret = -EINVAL; @@ -752,7 +693,6 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) sdio_release_host(func); - BT_DBG("Leave"); return 0; release_irq: @@ -765,14 +705,11 @@ release_host: sdio_release_host(func); failed: - BT_DBG("Leave"); return ret; } static int btmrvl_sdio_unregister_dev(struct btmrvl_sdio_card *card) { - BT_DBG("Enter"); - if (card && card->func) { sdio_claim_host(card->func); sdio_release_irq(card->func); @@ -781,8 +718,6 @@ static int btmrvl_sdio_unregister_dev(struct btmrvl_sdio_card *card) sdio_set_drvdata(card->func, NULL); } - BT_DBG("Leave"); - return 0; } @@ -790,12 +725,8 @@ static int btmrvl_sdio_enable_host_int(struct btmrvl_sdio_card *card) { int ret; - BT_DBG("Enter"); - - if (!card || !card->func) { - BT_DBG("Leave"); + if (!card || !card->func) return -EINVAL; - } sdio_claim_host(card->func); @@ -805,8 +736,6 @@ static int btmrvl_sdio_enable_host_int(struct btmrvl_sdio_card *card) sdio_release_host(card->func); - BT_DBG("Leave"); - return ret; } @@ -814,12 +743,8 @@ static int btmrvl_sdio_disable_host_int(struct btmrvl_sdio_card *card) { int ret; - BT_DBG("Enter"); - - if (!card || !card->func) { - BT_DBG("Leave"); + if (!card || !card->func) return -EINVAL; - } sdio_claim_host(card->func); @@ -827,8 +752,6 @@ static int btmrvl_sdio_disable_host_int(struct btmrvl_sdio_card *card) sdio_release_host(card->func); - BT_DBG("Leave"); - return ret; } @@ -844,11 +767,8 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, void *tmpbuf = NULL; int tmpbufsz; - BT_DBG("Enter"); - if (!card || !card->func) { BT_ERR("card or function is NULL!"); - BT_DBG("Leave"); return -EINVAL; } @@ -886,8 +806,6 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, exit: sdio_release_host(card->func); - BT_DBG("Leave"); - return ret; } @@ -895,11 +813,8 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) { int ret = 0; - BT_DBG("Enter"); - if (!card || !card->func) { BT_ERR("card or function is NULL!"); - BT_DBG("Leave"); return -EINVAL; } sdio_claim_host(card->func); @@ -931,8 +846,6 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) done: sdio_release_host(card->func); - BT_DBG("Leave"); - return ret; } @@ -941,11 +854,8 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv) struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; int ret = 0; - BT_DBG("Enter"); - if (!card || !card->func) { BT_ERR("card or function is NULL!"); - BT_DBG("Leave"); return -EINVAL; } @@ -957,8 +867,6 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv) BT_DBG("wake up firmware"); - BT_DBG("Leave"); - return ret; } @@ -969,8 +877,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, struct btmrvl_private *priv = NULL; struct btmrvl_sdio_card *card = NULL; - BT_DBG("Enter"); - BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d", id->vendor, id->device, id->class, func->num); @@ -1022,8 +928,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); - BT_DBG("Leave"); - return 0; disable_host_int: @@ -1033,8 +937,6 @@ unreg_dev: free_card: kfree(card); done: - BT_DBG("Leave"); - return ret; } @@ -1042,8 +944,6 @@ static void btmrvl_sdio_remove(struct sdio_func *func) { struct btmrvl_sdio_card *card; - BT_DBG("Enter"); - if (func) { card = sdio_get_drvdata(func); if (card) { @@ -1061,8 +961,6 @@ static void btmrvl_sdio_remove(struct sdio_func *func) kfree(card); } } - - BT_DBG("Leave"); } static struct sdio_driver bt_mrvl_sdio = { @@ -1074,32 +972,23 @@ static struct sdio_driver bt_mrvl_sdio = { static int btmrvl_sdio_init_module(void) { - BT_DBG("Enter"); - if (sdio_register_driver(&bt_mrvl_sdio) != 0) { BT_ERR("SDIO Driver Registration Failed"); - BT_DBG("Leave"); return -ENODEV; } /* Clear the flag in case user removes the card. */ user_rmmod = 0; - BT_DBG("Leave"); - return 0; } static void btmrvl_sdio_exit_module(void) { - BT_DBG("Enter"); - /* Set the flag as user is removing this module. */ user_rmmod = 1; sdio_unregister_driver(&bt_mrvl_sdio); - - BT_DBG("Leave"); } module_init(btmrvl_sdio_init_module); -- cgit v0.10.2 From 3318b2362bf0528be77123c480249663557dfbfc Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Wed, 8 Jul 2009 11:44:14 -0700 Subject: Bluetooth: Fix incorrect alignment in Marvell BT-over-SDIO driver The driver uses "u32" for alignment check and calculation which works only on 32-bit system. It will crash the 64-bit system. Replace "u32" with "unsigned long" to fix this issue. Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 224af53..1cfa8b4 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -481,12 +481,14 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) goto exit; } - if ((u32) skb->data & (BTSDIO_DMA_ALIGN - 1)) { - skb_put(skb, (u32) skb->data & (BTSDIO_DMA_ALIGN - 1)); - skb_pull(skb, (u32) skb->data & (BTSDIO_DMA_ALIGN - 1)); + if ((unsigned long) skb->data & (BTSDIO_DMA_ALIGN - 1)) { + skb_put(skb, (unsigned long) skb->data & + (BTSDIO_DMA_ALIGN - 1)); + skb_pull(skb, (unsigned long) skb->data & + (BTSDIO_DMA_ALIGN - 1)); } - payload = skb->tail; + payload = skb->data; ret = sdio_readsb(card->func, payload, card->ioport, buf_block_len * blksz); @@ -773,7 +775,7 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, } buf = payload; - if ((u32) payload & (BTSDIO_DMA_ALIGN - 1)) { + if ((unsigned long) payload & (BTSDIO_DMA_ALIGN - 1)) { tmpbufsz = ALIGN_SZ(nb, BTSDIO_DMA_ALIGN); tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL); memset(tmpbuf, 0, tmpbufsz); diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 2dd284e..27329f1 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -104,4 +104,5 @@ struct btmrvl_sdio_device { /* Macros for Data Alignment : address */ #define ALIGN_ADDR(p, a) \ - ((((u32)(p)) + (((u32)(a)) - 1)) & ~(((u32)(a)) - 1)) + ((((unsigned long)(p)) + (((unsigned long)(a)) - 1)) & \ + ~(((unsigned long)(a)) - 1)) -- cgit v0.10.2 From 5959809ded86e267c1a95fb44738a224c30d3434 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 6 Aug 2009 22:05:18 +0200 Subject: Bluetooth: Add missing kmalloc NULL tests to Marvell driver Check that the result of kmalloc is not NULL before dereferencing it. The patch also replaces kmalloc + memset by kzalloc. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression *x; identifier f; constant char *C; @@ x = \(kmalloc\|kcalloc\|kzalloc\)(...); ... when != x == NULL when != x != NULL when != (x || ...) ( kfree(x) | f(...,C,...,x,...) | *f(...,x,...) | *x->f ) // Signed-off-by: Julia Lawall Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 1cfa8b4..5b33b85 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -777,8 +777,9 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, buf = payload; if ((unsigned long) payload & (BTSDIO_DMA_ALIGN - 1)) { tmpbufsz = ALIGN_SZ(nb, BTSDIO_DMA_ALIGN); - tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL); - memset(tmpbuf, 0, tmpbufsz); + tmpbuf = kzalloc(tmpbufsz, GFP_KERNEL); + if (!tmpbuf) + return -ENOMEM; buf = (u8 *) ALIGN_ADDR(tmpbuf, BTSDIO_DMA_ALIGN); memcpy(buf, payload, nb); } -- cgit v0.10.2 From a6a67efd7088702fdbbb780c5a3f8e1a74e77b63 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 26 Jul 2009 08:18:19 +0000 Subject: Bluetooth: Convert hdev->req_lock to a mutex hdev->req_lock is used as mutex so make it a mutex. Signed-off-by: Thomas Gleixner Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 25b8a03..7b640ae 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -117,7 +117,7 @@ struct hci_dev { struct sk_buff *sent_cmd; struct sk_buff *reassembly[3]; - struct semaphore req_lock; + struct mutex req_lock; wait_queue_head_t req_wait_q; __u32 req_status; __u32 req_result; @@ -704,8 +704,8 @@ struct hci_sec_filter { #define HCI_REQ_PEND 1 #define HCI_REQ_CANCELED 2 -#define hci_req_lock(d) down(&d->req_lock) -#define hci_req_unlock(d) up(&d->req_lock) +#define hci_req_lock(d) mutex_lock(&d->req_lock) +#define hci_req_unlock(d) mutex_unlock(&d->req_lock) void hci_req_complete(struct hci_dev *hdev, int result); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 406ad07..e1da8f6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -911,7 +911,7 @@ int hci_register_dev(struct hci_dev *hdev) hdev->reassembly[i] = NULL; init_waitqueue_head(&hdev->req_wait_q); - init_MUTEX(&hdev->req_lock); + mutex_init(&hdev->req_lock); inquiry_cache_init(hdev); -- cgit v0.10.2 From 52d18347dfb61519aa0f58fe1759edd3ad8c4e36 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 22 Aug 2009 14:49:36 -0700 Subject: Bluetooth: Coding style cleanup from previous rfcomm_init bug fix The rfcomm_init bug fix went into the kernel premature before it got fully reviewed and acknowledged by the Bluetooth maintainer. So fix up the coding style now. Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 94b3388..26af485 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -2080,7 +2080,7 @@ static CLASS_ATTR(rfcomm_dlc, S_IRUGO, rfcomm_dlc_sysfs_show, NULL); /* ---- Initialization ---- */ static int __init rfcomm_init(void) { - int ret; + int err; l2cap_load(); @@ -2088,33 +2088,35 @@ static int __init rfcomm_init(void) rfcomm_thread = kthread_run(rfcomm_run, NULL, "krfcommd"); if (IS_ERR(rfcomm_thread)) { - ret = PTR_ERR(rfcomm_thread); - goto out_thread; + err = PTR_ERR(rfcomm_thread); + goto unregister; } if (class_create_file(bt_class, &class_attr_rfcomm_dlc) < 0) BT_ERR("Failed to create RFCOMM info file"); - ret = rfcomm_init_ttys(); - if (ret) - goto out_tty; + err = rfcomm_init_ttys(); + if (err < 0) + goto stop; - ret = rfcomm_init_sockets(); - if (ret) - goto out_sock; + err = rfcomm_init_sockets(); + if (err < 0) + goto cleanup; BT_INFO("RFCOMM ver %s", VERSION); return 0; -out_sock: +cleanup: rfcomm_cleanup_ttys(); -out_tty: + +stop: kthread_stop(rfcomm_thread); -out_thread: + +unregister: hci_unregister_cb(&rfcomm_cb); - return ret; + return err; } static void __exit rfcomm_exit(void) -- cgit v0.10.2 From 44dd46de325c4d47abfd1361e5d84a548edb8e42 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 2 May 2009 19:09:01 -0700 Subject: Bluetooth: Add module option to enable L2CAP ERTM support Since the Enhanced Retransmission mode for L2CAP is still under heavy development disable it by default and provide a module option to enable it manually for testing. Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index bd0a4c1..810a3c1 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -50,7 +50,9 @@ #include #include -#define VERSION "2.13" +#define VERSION "2.14" + +static int enable_ertm = 0; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u8 l2cap_fixed_chan[8] = { 0x02, }; @@ -2205,10 +2207,13 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm if (type == L2CAP_IT_FEAT_MASK) { u8 buf[8]; + u32 feat_mask = l2cap_feat_mask; struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf; rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK); rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); - put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data); + if (enable_ertm) + feat_mask |= L2CAP_FEAT_ERTM; + put_unaligned(cpu_to_le32(feat_mask), (__le32 *) rsp->data); l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf), buf); } else if (type == L2CAP_IT_FIXED_CHAN) { @@ -2828,6 +2833,9 @@ EXPORT_SYMBOL(l2cap_load); module_init(l2cap_init); module_exit(l2cap_exit); +module_param(enable_ertm, bool, 0644); +MODULE_PARM_DESC(enable_ertm, "Enable enhanced retransmission mode"); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION); MODULE_VERSION(VERSION); -- cgit v0.10.2 From c6b03cf986eab00e20d0dbc852b233bb83472138 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 2 May 2009 22:31:10 -0700 Subject: Bluetooth: Allow setting of L2CAP ERTM via socket option To enable Enhanced Retransmission mode it needs to be set via a socket option. A different mode can be set on a socket, but on listen() and connect() the mode is checked and ERTM is only allowed if it is enabled via the module parameter. Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index e919fca..06b072f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -190,7 +190,7 @@ struct l2cap_conf_rfc { #define L2CAP_MODE_RETRANS 0x01 #define L2CAP_MODE_FLOWCTL 0x02 #define L2CAP_MODE_ERTM 0x03 -#define L2CAP_MODE_STREAM 0x04 +#define L2CAP_MODE_STREAMING 0x04 struct l2cap_disconn_req { __le16 dcid; @@ -271,9 +271,11 @@ struct l2cap_pinfo { __u16 imtu; __u16 omtu; __u16 flush_to; - __u8 sec_level; + __u8 mode; + __u8 fcs; + __u8 sec_level; __u8 role_switch; - __u8 force_reliable; + __u8 force_reliable; __u8 conf_req[64]; __u8 conf_len; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 810a3c1..8a59e57 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -717,12 +717,16 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->imtu = l2cap_pi(parent)->imtu; pi->omtu = l2cap_pi(parent)->omtu; + pi->mode = l2cap_pi(parent)->mode; + pi->fcs = l2cap_pi(parent)->fcs; pi->sec_level = l2cap_pi(parent)->sec_level; pi->role_switch = l2cap_pi(parent)->role_switch; pi->force_reliable = l2cap_pi(parent)->force_reliable; } else { pi->imtu = L2CAP_DEFAULT_MTU; pi->omtu = 0; + pi->mode = L2CAP_MODE_BASIC; + pi->fcs = L2CAP_FCS_CRC16; pi->sec_level = BT_SECURITY_LOW; pi->role_switch = 0; pi->force_reliable = 0; @@ -958,6 +962,18 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al goto done; } + switch (l2cap_pi(sk)->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: + if (enable_ertm) + break; + /* fall through */ + default: + err = -ENOTSUPP; + goto done; + } + switch (sk->sk_state) { case BT_CONNECT: case BT_CONNECT2: @@ -1009,6 +1025,18 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) goto done; } + switch (l2cap_pi(sk)->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: + if (enable_ertm) + break; + /* fall through */ + default: + err = -ENOTSUPP; + goto done; + } + if (!l2cap_pi(sk)->psm) { bdaddr_t *src = &bt_sk(sk)->src; u16 psm; @@ -1259,7 +1287,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us opts.imtu = l2cap_pi(sk)->imtu; opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; - opts.mode = L2CAP_MODE_BASIC; + opts.mode = l2cap_pi(sk)->mode; len = min_t(unsigned int, sizeof(opts), optlen); if (copy_from_user((char *) &opts, optval, len)) { @@ -1267,8 +1295,9 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } - l2cap_pi(sk)->imtu = opts.imtu; - l2cap_pi(sk)->omtu = opts.omtu; + l2cap_pi(sk)->imtu = opts.imtu; + l2cap_pi(sk)->omtu = opts.omtu; + l2cap_pi(sk)->mode = opts.mode; break; case L2CAP_LM: @@ -1381,7 +1410,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us opts.imtu = l2cap_pi(sk)->imtu; opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; - opts.mode = L2CAP_MODE_BASIC; + opts.mode = l2cap_pi(sk)->mode; len = min_t(unsigned int, len, sizeof(opts)); if (copy_to_user(optval, (char *) &opts, len)) -- cgit v0.10.2 From 65c7c4918450f8c4545ccb02a9c7a3d77e073535 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 2 May 2009 23:07:53 -0700 Subject: Bluetooth: Add L2CAP RFC option if ERTM is enabled When trying to establish a connection with Enhanced Retransmission mode enabled, the RFC option needs to be added to the configuration. Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 8a59e57..7ce1a24 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1743,12 +1743,29 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) { struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_conf_req *req = data; + struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; void *ptr = req->data; BT_DBG("sk %p", sk); - if (pi->imtu != L2CAP_DEFAULT_MTU) - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); + switch (pi->mode) { + case L2CAP_MODE_BASIC: + if (pi->imtu != L2CAP_DEFAULT_MTU) + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); + break; + + case L2CAP_MODE_ERTM: + rfc.mode = L2CAP_MODE_ERTM; + rfc.txwin_size = L2CAP_DEFAULT_RX_WINDOW; + rfc.max_transmit = L2CAP_DEFAULT_MAX_RECEIVE; + rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); + rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); + rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_RX_APDU); + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + break; + } /* FIXME: Need actual value of the flush timeout */ //if (flush_to != L2CAP_DEFAULT_FLUSH_TO) @@ -1828,7 +1845,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) rfc.mode = L2CAP_MODE_BASIC; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, - sizeof(rfc), (unsigned long) &rfc); + sizeof(rfc), (unsigned long) &rfc); } } -- cgit v0.10.2 From f2fcfcd670257236ebf2088bbdf26f6a8ef459fe Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 4 Jul 2009 15:06:24 -0300 Subject: Bluetooth: Add configuration support for ERTM and Streaming mode Add support to config_req and config_rsp to configure ERTM and Streaming mode. If the remote device specifies ERTM or Streaming mode, then the same mode is proposed. Otherwise ERTM or Basic mode is used. And in case of a state 2 device, the remote device should propose the same mode. If not, then the channel gets disconnected. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 06b072f..6fc7698 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -27,8 +27,9 @@ /* L2CAP defaults */ #define L2CAP_DEFAULT_MTU 672 +#define L2CAP_DEFAULT_MIN_MTU 48 #define L2CAP_DEFAULT_FLUSH_TO 0xffff -#define L2CAP_DEFAULT_RX_WINDOW 1 +#define L2CAP_DEFAULT_TX_WINDOW 1 #define L2CAP_DEFAULT_MAX_RECEIVE 1 #define L2CAP_DEFAULT_RETRANS_TO 300 /* 300 milliseconds */ #define L2CAP_DEFAULT_MONITOR_TO 1000 /* 1 second */ @@ -272,6 +273,9 @@ struct l2cap_pinfo { __u16 omtu; __u16 flush_to; __u8 mode; + __u8 num_conf_req; + __u8 num_conf_rsp; + __u8 fcs; __u8 sec_level; __u8 role_switch; @@ -280,10 +284,15 @@ struct l2cap_pinfo { __u8 conf_req[64]; __u8 conf_len; __u8 conf_state; - __u8 conf_retry; __u8 ident; + __u8 remote_tx_win; + __u8 remote_max_tx; + __u16 retrans_timeout; + __u16 monitor_timeout; + __u16 max_pdu_size; + __le16 sport; struct l2cap_conn *conn; @@ -291,12 +300,17 @@ struct l2cap_pinfo { struct sock *prev_c; }; -#define L2CAP_CONF_REQ_SENT 0x01 -#define L2CAP_CONF_INPUT_DONE 0x02 -#define L2CAP_CONF_OUTPUT_DONE 0x04 -#define L2CAP_CONF_CONNECT_PEND 0x80 +#define L2CAP_CONF_REQ_SENT 0x01 +#define L2CAP_CONF_INPUT_DONE 0x02 +#define L2CAP_CONF_OUTPUT_DONE 0x04 +#define L2CAP_CONF_MTU_DONE 0x08 +#define L2CAP_CONF_MODE_DONE 0x10 +#define L2CAP_CONF_CONNECT_PEND 0x20 +#define L2CAP_CONF_STATE2_DEVICE 0x80 + +#define L2CAP_CONF_MAX_CONF_REQ 2 +#define L2CAP_CONF_MAX_CONF_RSP 2 -#define L2CAP_CONF_MAX_RETRIES 2 void l2cap_load(void); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 7ce1a24..af0fbf9 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -966,6 +966,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al case L2CAP_MODE_BASIC: break; case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: if (enable_ertm) break; /* fall through */ @@ -1029,6 +1030,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) case L2CAP_MODE_BASIC: break; case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: if (enable_ertm) break; /* fall through */ @@ -1739,15 +1741,65 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) *ptr += L2CAP_CONF_OPT_SIZE + len; } +static int l2cap_mode_supported(__u8 mode, __u32 feat_mask) +{ + u32 local_feat_mask = l2cap_feat_mask; + if (enable_ertm) + local_feat_mask |= L2CAP_FEAT_ERTM; + + switch (mode) { + case L2CAP_MODE_ERTM: + return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask; + case L2CAP_MODE_STREAMING: + return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask; + default: + return 0x00; + } +} + +static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) +{ + switch (mode) { + case L2CAP_MODE_STREAMING: + case L2CAP_MODE_ERTM: + if (l2cap_mode_supported(mode, remote_feat_mask)) + return mode; + /* fall through */ + default: + return L2CAP_MODE_BASIC; + } +} + static int l2cap_build_conf_req(struct sock *sk, void *data) { struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_conf_req *req = data; - struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; + struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_ERTM }; void *ptr = req->data; BT_DBG("sk %p", sk); + if (pi->num_conf_req || pi->num_conf_rsp) + goto done; + + switch (pi->mode) { + case L2CAP_MODE_STREAMING: + case L2CAP_MODE_ERTM: + pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; + if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) { + struct l2cap_disconn_req req; + req.dcid = cpu_to_le16(pi->dcid); + req.scid = cpu_to_le16(pi->scid); + l2cap_send_cmd(pi->conn, l2cap_get_ident(pi->conn), + L2CAP_DISCONN_REQ, sizeof(req), &req); + } + break; + default: + pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); + break; + } + +done: switch (pi->mode) { case L2CAP_MODE_BASIC: if (pi->imtu != L2CAP_DEFAULT_MTU) @@ -1756,10 +1808,22 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) case L2CAP_MODE_ERTM: rfc.mode = L2CAP_MODE_ERTM; - rfc.txwin_size = L2CAP_DEFAULT_RX_WINDOW; + rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; rfc.max_transmit = L2CAP_DEFAULT_MAX_RECEIVE; - rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); - rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); + rfc.retrans_timeout = 0; + rfc.monitor_timeout = 0; + rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_RX_APDU); + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + break; + + case L2CAP_MODE_STREAMING: + rfc.mode = L2CAP_MODE_STREAMING; + rfc.txwin_size = 0; + rfc.max_transmit = 0; + rfc.retrans_timeout = 0; + rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_RX_APDU); l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, @@ -1825,30 +1889,83 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) } } + if (pi->num_conf_rsp || pi->num_conf_req) + goto done; + + switch (pi->mode) { + case L2CAP_MODE_STREAMING: + case L2CAP_MODE_ERTM: + pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; + if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) + return -ECONNREFUSED; + break; + default: + pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); + break; + } + +done: + if (pi->mode != rfc.mode) { + result = L2CAP_CONF_UNACCEPT; + rfc.mode = pi->mode; + + if (pi->num_conf_rsp == 1) + return -ECONNREFUSED; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + } + + if (result == L2CAP_CONF_SUCCESS) { /* Configure output options and let the other side know * which ones we don't like. */ - if (rfc.mode == L2CAP_MODE_BASIC) { - if (mtu < pi->omtu) - result = L2CAP_CONF_UNACCEPT; - else { - pi->omtu = mtu; - pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; - } + if (mtu < L2CAP_DEFAULT_MIN_MTU) + result = L2CAP_CONF_UNACCEPT; + else { + pi->omtu = mtu; + pi->conf_state |= L2CAP_CONF_MTU_DONE; + } + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); - } else { + switch (rfc.mode) { + case L2CAP_MODE_BASIC: + pi->fcs = L2CAP_FCS_NONE; + pi->conf_state |= L2CAP_CONF_MODE_DONE; + break; + + case L2CAP_MODE_ERTM: + pi->remote_tx_win = rfc.txwin_size; + pi->remote_max_tx = rfc.max_transmit; + pi->max_pdu_size = rfc.max_pdu_size; + + rfc.retrans_timeout = L2CAP_DEFAULT_RETRANS_TO; + rfc.monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; + + pi->conf_state |= L2CAP_CONF_MODE_DONE; + break; + + case L2CAP_MODE_STREAMING: + pi->remote_tx_win = rfc.txwin_size; + pi->max_pdu_size = rfc.max_pdu_size; + + pi->conf_state |= L2CAP_CONF_MODE_DONE; + break; + + default: result = L2CAP_CONF_UNACCEPT; memset(&rfc, 0, sizeof(rfc)); - rfc.mode = L2CAP_MODE_BASIC; + rfc.mode = pi->mode; + } - l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); - } - } + if (result == L2CAP_CONF_SUCCESS) + pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; + } rsp->scid = cpu_to_le16(pi->dcid); rsp->result = cpu_to_le16(result); rsp->flags = cpu_to_le16(0x0000); @@ -1856,6 +1973,73 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) return ptr - data; } +static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, u16 *result) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_conf_req *req = data; + void *ptr = req->data; + int type, olen; + unsigned long val; + struct l2cap_conf_rfc rfc; + + BT_DBG("sk %p, rsp %p, len %d, req %p", sk, rsp, len, data); + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); + + switch (type) { + case L2CAP_CONF_MTU: + if (val < L2CAP_DEFAULT_MIN_MTU) { + *result = L2CAP_CONF_UNACCEPT; + pi->omtu = L2CAP_DEFAULT_MIN_MTU; + } else + pi->omtu = val; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); + break; + + case L2CAP_CONF_FLUSH_TO: + pi->flush_to = val; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, + 2, pi->flush_to); + break; + + case L2CAP_CONF_RFC: + if (olen == sizeof(rfc)) + memcpy(&rfc, (void *)val, olen); + + if ((pi->conf_state & L2CAP_CONF_STATE2_DEVICE) && + rfc.mode != pi->mode) + return -ECONNREFUSED; + + pi->mode = rfc.mode; + pi->fcs = 0; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + break; + } + } + + if (*result == L2CAP_CONF_SUCCESS) { + switch (rfc.mode) { + case L2CAP_MODE_ERTM: + pi->remote_tx_win = rfc.txwin_size; + pi->retrans_timeout = rfc.retrans_timeout; + pi->monitor_timeout = rfc.monitor_timeout; + pi->max_pdu_size = le16_to_cpu(rfc.max_pdu_size); + break; + case L2CAP_MODE_STREAMING: + pi->max_pdu_size = le16_to_cpu(rfc.max_pdu_size); + break; + } + } + + req->dcid = cpu_to_le16(pi->dcid); + req->flags = cpu_to_le16(0x0000); + + return ptr - data; +} + static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 flags) { struct l2cap_conf_rsp *rsp = data; @@ -2042,6 +2226,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); + l2cap_pi(sk)->num_conf_req++; break; case L2CAP_CR_PEND: @@ -2100,10 +2285,17 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Complete config. */ len = l2cap_parse_conf_req(sk, rsp); - if (len < 0) + if (len < 0) { + struct l2cap_disconn_req req; + req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + l2cap_send_cmd(conn, l2cap_get_ident(conn), + L2CAP_DISCONN_REQ, sizeof(req), &req); goto unlock; + } l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); + l2cap_pi(sk)->num_conf_rsp++; /* Reset config buffer. */ l2cap_pi(sk)->conf_len = 0; @@ -2121,6 +2313,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr u8 buf[64]; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(sk, buf), buf); + l2cap_pi(sk)->num_conf_req++; } unlock: @@ -2150,16 +2343,29 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr break; case L2CAP_CONF_UNACCEPT: - if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) { - char req[128]; - /* It does not make sense to adjust L2CAP parameters - * that are currently defined in the spec. We simply - * resend config request that we sent earlier. It is - * stupid, but it helps qualification testing which - * expects at least some response from us. */ - l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, req), req); - goto done; + if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) { + int len = cmd->len - sizeof(*rsp); + char req[64]; + + /* throw out any old stored conf requests */ + result = L2CAP_CONF_SUCCESS; + len = l2cap_parse_conf_rsp(sk, rsp->data, + len, req, &result); + if (len < 0) { + struct l2cap_disconn_req req; + req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + l2cap_send_cmd(conn, l2cap_get_ident(conn), + L2CAP_DISCONN_REQ, sizeof(req), &req); + goto done; + } + + l2cap_send_cmd(conn, l2cap_get_ident(conn), + L2CAP_CONF_REQ, len, req); + l2cap_pi(sk)->num_conf_req++; + if (result != L2CAP_CONF_SUCCESS) + goto done; + break; } default: -- cgit v0.10.2 From 22121fc9152ca8f25a2d790860832ccb6a414c4d Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 23 Jul 2009 10:27:23 -0300 Subject: Bluetooth: Create separate l2cap_send_disconn_req() function The code for sending a disconnect request was repeated several times within L2CAP source code. So move this into its own function. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index af0fbf9..c1b5620 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -366,6 +366,16 @@ static void l2cap_do_start(struct sock *sk) } } +static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk) +{ + struct l2cap_disconn_req req; + + req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + l2cap_send_cmd(conn, l2cap_get_ident(conn), + L2CAP_DISCONN_REQ, sizeof(req), &req); +} + /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) { @@ -650,15 +660,10 @@ static void __l2cap_sock_close(struct sock *sk, int reason) case BT_CONFIG: if (sk->sk_type == SOCK_SEQPACKET) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; - struct l2cap_disconn_req req; sk->sk_state = BT_DISCONN; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); - - req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - l2cap_send_cmd(conn, l2cap_get_ident(conn), - L2CAP_DISCONN_REQ, sizeof(req), &req); + l2cap_send_disconn_req(conn, sk); } else l2cap_chan_del(sk, reason); break; @@ -1786,13 +1791,8 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; - if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) { - struct l2cap_disconn_req req; - req.dcid = cpu_to_le16(pi->dcid); - req.scid = cpu_to_le16(pi->scid); - l2cap_send_cmd(pi->conn, l2cap_get_ident(pi->conn), - L2CAP_DISCONN_REQ, sizeof(req), &req); - } + if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) + l2cap_send_disconn_req(pi->conn, sk); break; default: pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); @@ -2286,11 +2286,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Complete config. */ len = l2cap_parse_conf_req(sk, rsp); if (len < 0) { - struct l2cap_disconn_req req; - req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - l2cap_send_cmd(conn, l2cap_get_ident(conn), - L2CAP_DISCONN_REQ, sizeof(req), &req); + l2cap_send_disconn_req(conn, sk); goto unlock; } @@ -2352,11 +2348,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr len = l2cap_parse_conf_rsp(sk, rsp->data, len, req, &result); if (len < 0) { - struct l2cap_disconn_req req; - req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - l2cap_send_cmd(conn, l2cap_get_ident(conn), - L2CAP_DISCONN_REQ, sizeof(req), &req); + l2cap_send_disconn_req(conn, sk); goto done; } @@ -2372,13 +2364,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr sk->sk_state = BT_DISCONN; sk->sk_err = ECONNRESET; l2cap_sock_set_timer(sk, HZ * 5); - { - struct l2cap_disconn_req req; - req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - l2cap_send_cmd(conn, l2cap_get_ident(conn), - L2CAP_DISCONN_REQ, sizeof(req), &req); - } + l2cap_send_disconn_req(conn, sk); goto done; } -- cgit v0.10.2 From 1c2acffb76d4bc5fd27c4ea55cc27ad8ead10f9a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 20 Aug 2009 22:25:57 -0300 Subject: Bluetooth: Add initial support for ERTM packets transfers This patch adds support for ERTM transfers, without retransmission, with txWindow up to 63 and with acknowledgement of packets received. Now the packets are queued before call l2cap_do_send(), so packets couldn't be sent at the time we call l2cap_sock_sendmsg(). They will be sent in an asynchronous way on later calls of l2cap_ertm_send(). Besides if an error occurs on calling l2cap_do_send() we disconnect the channel. Initially based on a patch from Nathan Holstein Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 968166a..65a5cf8 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -138,8 +138,9 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock); struct bt_skb_cb { __u8 pkt_type; __u8 incoming; + __u8 tx_seq; }; -#define bt_cb(skb) ((struct bt_skb_cb *)(skb->cb)) +#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how) { diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 6fc7698..9bbfbe7 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -29,7 +29,8 @@ #define L2CAP_DEFAULT_MTU 672 #define L2CAP_DEFAULT_MIN_MTU 48 #define L2CAP_DEFAULT_FLUSH_TO 0xffff -#define L2CAP_DEFAULT_TX_WINDOW 1 +#define L2CAP_DEFAULT_TX_WINDOW 63 +#define L2CAP_DEFAULT_NUM_TO_ACK (L2CAP_DEFAULT_TX_WINDOW/5) #define L2CAP_DEFAULT_MAX_RECEIVE 1 #define L2CAP_DEFAULT_RETRANS_TO 300 /* 300 milliseconds */ #define L2CAP_DEFAULT_MONITOR_TO 1000 /* 1 second */ @@ -94,6 +95,31 @@ struct l2cap_conninfo { #define L2CAP_FCS_NONE 0x00 #define L2CAP_FCS_CRC16 0x01 +/* L2CAP Control Field bit masks */ +#define L2CAP_CTRL_SAR 0xC000 +#define L2CAP_CTRL_REQSEQ 0x3F00 +#define L2CAP_CTRL_TXSEQ 0x007E +#define L2CAP_CTRL_RETRANS 0x0080 +#define L2CAP_CTRL_FINAL 0x0080 +#define L2CAP_CTRL_POLL 0x0010 +#define L2CAP_CTRL_SUPERVISE 0x000C +#define L2CAP_CTRL_FRAME_TYPE 0x0001 /* I- or S-Frame */ + +#define L2CAP_CTRL_TXSEQ_SHIFT 1 +#define L2CAP_CTRL_REQSEQ_SHIFT 8 + +/* L2CAP Supervisory Function */ +#define L2CAP_SUPER_RCV_READY 0x0000 +#define L2CAP_SUPER_REJECT 0x0004 +#define L2CAP_SUPER_RCV_NOT_READY 0x0008 +#define L2CAP_SUPER_SELECT_REJECT 0x000C + +/* L2CAP Segmentation and Reassembly */ +#define L2CAP_SDU_UNSEGMENTED 0x0000 +#define L2CAP_SDU_START 0x4000 +#define L2CAP_SDU_END 0x8000 +#define L2CAP_SDU_CONTINUE 0xC000 + /* L2CAP structures */ struct l2cap_hdr { __le16 len; @@ -262,6 +288,7 @@ struct l2cap_conn { /* ----- L2CAP channel and socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) +#define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) struct l2cap_pinfo { struct bt_sock bt; @@ -285,6 +312,13 @@ struct l2cap_pinfo { __u8 conf_len; __u8 conf_state; + __u8 next_tx_seq; + __u8 expected_ack_seq; + __u8 req_seq; + __u8 expected_tx_seq; + __u8 unacked_frames; + __u8 num_to_ack; + __u8 ident; __u8 remote_tx_win; @@ -295,6 +329,7 @@ struct l2cap_pinfo { __le16 sport; + struct sk_buff_head tx_queue; struct l2cap_conn *conn; struct sock *next_c; struct sock *prev_c; @@ -311,6 +346,23 @@ struct l2cap_pinfo { #define L2CAP_CONF_MAX_CONF_REQ 2 #define L2CAP_CONF_MAX_CONF_RSP 2 +static inline int l2cap_tx_window_full(struct sock *sk) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + int sub; + + sub = (pi->next_tx_seq - pi->expected_ack_seq) % 64; + + if (sub < 0) + sub += 64; + + return (sub == pi->remote_tx_win); +} + +#define __get_txseq(ctrl) ((ctrl) & L2CAP_CTRL_TXSEQ) >> 1 +#define __get_reqseq(ctrl) ((ctrl) & L2CAP_CTRL_REQSEQ) >> 8 +#define __is_iframe(ctrl) !((ctrl) & L2CAP_CTRL_FRAME_TYPE) +#define __is_sframe(ctrl) (ctrl) & L2CAP_CTRL_FRAME_TYPE void l2cap_load(void); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c1b5620..45b8697 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -333,6 +333,30 @@ static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 return hci_send_acl(conn->hcon, skb, 0); } +static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) +{ + struct sk_buff *skb; + struct l2cap_hdr *lh; + struct l2cap_conn *conn = pi->conn; + int count; + + BT_DBG("pi %p, control 0x%2.2x", pi, control); + + count = min_t(unsigned int, conn->mtu, L2CAP_HDR_SIZE + 2); + control |= L2CAP_CTRL_FRAME_TYPE; + + skb = bt_skb_alloc(count, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->len = cpu_to_le16(2); + lh->cid = cpu_to_le16(pi->dcid); + put_unaligned_le16(control, skb_put(skb, 2)); + + return hci_send_acl(pi->conn->hcon, skb, 0); +} + static void l2cap_do_start(struct sock *sk) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; @@ -1154,39 +1178,80 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l return 0; } -static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len) +static void l2cap_drop_acked_frames(struct sock *sk) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; - struct sk_buff *skb, **frag; - int err, hlen, count, sent = 0; - struct l2cap_hdr *lh; + struct sk_buff *skb; - BT_DBG("sk %p len %d", sk, len); + while ((skb = skb_peek(TX_QUEUE(sk)))) { + if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq) + break; - /* First fragment (with L2CAP header) */ - if (sk->sk_type == SOCK_DGRAM) - hlen = L2CAP_HDR_SIZE + 2; - else - hlen = L2CAP_HDR_SIZE; + skb = skb_dequeue(TX_QUEUE(sk)); + kfree_skb(skb); - count = min_t(unsigned int, (conn->mtu - hlen), len); + l2cap_pi(sk)->unacked_frames--; + } - skb = bt_skb_send_alloc(sk, hlen + count, - msg->msg_flags & MSG_DONTWAIT, &err); - if (!skb) - return err; + return; +} - /* Create L2CAP header */ - lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); - lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); +static inline int l2cap_do_send(struct sock *sk, struct sk_buff *skb) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + int err; + + BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len); + + err = hci_send_acl(pi->conn->hcon, skb, 0); + if (err < 0) + kfree_skb(skb); + + return err; +} + +static int l2cap_ertm_send(struct sock *sk) +{ + struct sk_buff *skb, *tx_skb; + struct l2cap_pinfo *pi = l2cap_pi(sk); + u16 control; + int err; + + while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) { + tx_skb = skb_clone(skb, GFP_ATOMIC); - if (sk->sk_type == SOCK_DGRAM) - put_unaligned(l2cap_pi(sk)->psm, (__le16 *) skb_put(skb, 2)); + control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + control |= (pi->req_seq << L2CAP_CTRL_REQSEQ_SHIFT) + | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); + put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + + err = l2cap_do_send(sk, tx_skb); + if (err < 0) { + l2cap_send_disconn_req(pi->conn, sk); + return err; + } + + bt_cb(skb)->tx_seq = pi->next_tx_seq; + pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; + + pi->unacked_frames++; + + if (skb_queue_is_last(TX_QUEUE(sk), skb)) + sk->sk_send_head = NULL; + else + sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); + } + + return 0; +} + +static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sk_buff **frag; + int err, sent = 0; if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { - err = -EFAULT; - goto fail; + return -EFAULT; } sent += count; @@ -1199,33 +1264,112 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len) *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err); if (!*frag) - goto fail; - - if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) { - err = -EFAULT; - goto fail; - } + return -EFAULT; + if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) + return -EFAULT; sent += count; len -= count; frag = &(*frag)->next; } - err = hci_send_acl(conn->hcon, skb, 0); - if (err < 0) - goto fail; return sent; +} -fail: - kfree_skb(skb); - return err; +static struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sk_buff *skb; + int err, count, hlen = L2CAP_HDR_SIZE + 2; + struct l2cap_hdr *lh; + + BT_DBG("sk %p len %d", sk, (int)len); + + count = min_t(unsigned int, (conn->mtu - hlen), len); + skb = bt_skb_send_alloc(sk, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) + return ERR_PTR(-ENOMEM); + + /* Create L2CAP header */ + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + put_unaligned_le16(l2cap_pi(sk)->psm, skb_put(skb, 2)); + + err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + if (unlikely(err < 0)) { + kfree_skb(skb); + return ERR_PTR(err); + } + return skb; +} + +static struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sk_buff *skb; + int err, count, hlen = L2CAP_HDR_SIZE; + struct l2cap_hdr *lh; + + BT_DBG("sk %p len %d", sk, (int)len); + + count = min_t(unsigned int, (conn->mtu - hlen), len); + skb = bt_skb_send_alloc(sk, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) + return ERR_PTR(-ENOMEM); + + /* Create L2CAP header */ + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + + err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + if (unlikely(err < 0)) { + kfree_skb(skb); + return ERR_PTR(err); + } + return skb; +} + +static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sk_buff *skb; + int err, count, hlen = L2CAP_HDR_SIZE + 2; + struct l2cap_hdr *lh; + + BT_DBG("sk %p len %d", sk, (int)len); + + count = min_t(unsigned int, (conn->mtu - hlen), len); + skb = bt_skb_send_alloc(sk, count + hlen, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) + return ERR_PTR(-ENOMEM); + + /* Create L2CAP header */ + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + put_unaligned_le16(control, skb_put(skb, 2)); + + err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); + if (unlikely(err < 0)) { + kfree_skb(skb); + return ERR_PTR(err); + } + return skb; } static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; - int err = 0; + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *skb; + u16 control; + int err; BT_DBG("sock %p, sk %p", sock, sk); @@ -1237,16 +1381,67 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms return -EOPNOTSUPP; /* Check outgoing MTU */ - if (sk->sk_type != SOCK_RAW && len > l2cap_pi(sk)->omtu) + if (sk->sk_type == SOCK_SEQPACKET && pi->mode == L2CAP_MODE_BASIC + && len > pi->omtu) return -EINVAL; lock_sock(sk); - if (sk->sk_state == BT_CONNECTED) - err = l2cap_do_send(sk, msg, len); - else + if (sk->sk_state != BT_CONNECTED) { err = -ENOTCONN; + goto done; + } + + /* Connectionless channel */ + if (sk->sk_type == SOCK_DGRAM) { + skb = l2cap_create_connless_pdu(sk, msg, len); + err = l2cap_do_send(sk, skb); + goto done; + } + switch (pi->mode) { + case L2CAP_MODE_BASIC: + /* Create a basic PDU */ + skb = l2cap_create_basic_pdu(sk, msg, len); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + goto done; + } + + err = l2cap_do_send(sk, skb); + if (!err) + err = len; + break; + + case L2CAP_MODE_ERTM: + /* Entire SDU fits into one PDU */ + if (len <= pi->omtu) { + control = L2CAP_SDU_UNSEGMENTED; + skb = l2cap_create_ertm_pdu(sk, msg, len, control); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + goto done; + } + } else { + /* FIXME: Segmentation will be added later */ + err = -EINVAL; + goto done; + } + __skb_queue_tail(TX_QUEUE(sk), skb); + if (sk->sk_send_head == NULL) + sk->sk_send_head = skb; + + err = l2cap_ertm_send(sk); + if (!err) + err = len; + break; + + default: + BT_DBG("bad state %1.1x", pi->mode); + err = -EINVAL; + } + +done: release_sock(sk); return err; } @@ -2301,6 +2496,10 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { sk->sk_state = BT_CONNECTED; + l2cap_pi(sk)->next_tx_seq = 0; + l2cap_pi(sk)->expected_ack_seq = 0; + l2cap_pi(sk)->unacked_frames = 0; + __skb_queue_head_init(TX_QUEUE(sk)); l2cap_chan_ready(sk); goto unlock; } @@ -2375,6 +2574,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { sk->sk_state = BT_CONNECTED; + l2cap_pi(sk)->expected_tx_seq = 0; + l2cap_pi(sk)->num_to_ack = 0; + __skb_queue_head_init(TX_QUEUE(sk)); l2cap_chan_ready(sk); } @@ -2405,6 +2607,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk->sk_shutdown = SHUTDOWN_MASK; + skb_queue_purge(TX_QUEUE(sk)); + l2cap_chan_del(sk, ECONNRESET); bh_unlock_sock(sk); @@ -2427,6 +2631,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd if (!sk) return 0; + skb_queue_purge(TX_QUEUE(sk)); + l2cap_chan_del(sk, 0); bh_unlock_sock(sk); @@ -2602,9 +2808,60 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk kfree_skb(skb); } +static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + u8 tx_seq = __get_txseq(rx_control); + u16 tx_control = 0; + int err = 0; + + BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + + if (tx_seq != pi->expected_tx_seq) + return -EINVAL; + + pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + err = sock_queue_rcv_skb(sk, skb); + if (err) + return err; + + pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; + if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { + tx_control |= L2CAP_CTRL_FRAME_TYPE; + tx_control |= L2CAP_SUPER_RCV_READY; + tx_control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + err = l2cap_send_sframe(pi, tx_control); + } + return err; +} + +static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + + BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + + switch (rx_control & L2CAP_CTRL_SUPERVISE) { + case L2CAP_SUPER_RCV_READY: + pi->expected_ack_seq = __get_reqseq(rx_control); + l2cap_drop_acked_frames(sk); + l2cap_ertm_send(sk); + break; + + case L2CAP_SUPER_RCV_NOT_READY: + case L2CAP_SUPER_REJECT: + case L2CAP_SUPER_SELECT_REJECT: + break; + } + + return 0; +} + static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { struct sock *sk; + u16 control; + int err; sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); if (!sk) { @@ -2617,16 +2874,40 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (sk->sk_state != BT_CONNECTED) goto drop; - if (l2cap_pi(sk)->imtu < skb->len) - goto drop; + switch (l2cap_pi(sk)->mode) { + case L2CAP_MODE_BASIC: + /* If socket recv buffers overflows we drop data here + * which is *bad* because L2CAP has to be reliable. + * But we don't have any other choice. L2CAP doesn't + * provide flow control mechanism. */ - /* If socket recv buffers overflows we drop data here - * which is *bad* because L2CAP has to be reliable. - * But we don't have any other choice. L2CAP doesn't - * provide flow control mechanism. */ + if (l2cap_pi(sk)->imtu < skb->len) + goto drop; - if (!sock_queue_rcv_skb(sk, skb)) - goto done; + if (!sock_queue_rcv_skb(sk, skb)) + goto done; + break; + + case L2CAP_MODE_ERTM: + control = get_unaligned_le16(skb->data); + skb_pull(skb, 2); + + if (l2cap_pi(sk)->imtu < skb->len) + goto drop; + + if (__is_iframe(control)) + err = l2cap_data_channel_iframe(sk, control, skb); + else + err = l2cap_data_channel_sframe(sk, control, skb); + + if (!err) + goto done; + break; + + default: + BT_DBG("sk %p: bad mode 0x%2.2x", sk, l2cap_pi(sk)->mode); + break; + } drop: kfree_skb(skb); @@ -2676,6 +2957,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) cid = __le16_to_cpu(lh->cid); len = __le16_to_cpu(lh->len); + if (len != skb->len) { + kfree_skb(skb); + return; + } + BT_DBG("len %d, cid 0x%4.4x", len, cid); switch (cid) { -- cgit v0.10.2 From c74e560cd0101455f1889515e1527e4c2e266113 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 20 Aug 2009 22:25:58 -0300 Subject: Bluetooth: Add support for Segmentation and Reassembly of SDUs ERTM should use Segmentation and Reassembly to break down a SDU in many PDUs on sending data to the other side. On sending packets we queue all 'segments' until end of segmentation and just the add them to the queue for sending. On receiving we create a new SKB with the SDU reassembled. Initially based on a patch from Nathan Holstein Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9bbfbe7..0afde8d 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -34,7 +34,7 @@ #define L2CAP_DEFAULT_MAX_RECEIVE 1 #define L2CAP_DEFAULT_RETRANS_TO 300 /* 300 milliseconds */ #define L2CAP_DEFAULT_MONITOR_TO 1000 /* 1 second */ -#define L2CAP_DEFAULT_MAX_RX_APDU 0xfff7 +#define L2CAP_DEFAULT_MAX_PDU_SIZE 672 #define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ #define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ @@ -311,6 +311,7 @@ struct l2cap_pinfo { __u8 conf_req[64]; __u8 conf_len; __u8 conf_state; + __u8 conn_state; __u8 next_tx_seq; __u8 expected_ack_seq; @@ -318,6 +319,9 @@ struct l2cap_pinfo { __u8 expected_tx_seq; __u8 unacked_frames; __u8 num_to_ack; + __u16 sdu_len; + __u16 partial_sdu_len; + struct sk_buff *sdu; __u8 ident; @@ -346,6 +350,8 @@ struct l2cap_pinfo { #define L2CAP_CONF_MAX_CONF_REQ 2 #define L2CAP_CONF_MAX_CONF_RSP 2 +#define L2CAP_CONN_SAR_SDU 0x01 + static inline int l2cap_tx_window_full(struct sock *sk) { struct l2cap_pinfo *pi = l2cap_pi(sk); @@ -363,6 +369,7 @@ static inline int l2cap_tx_window_full(struct sock *sk) #define __get_reqseq(ctrl) ((ctrl) & L2CAP_CTRL_REQSEQ) >> 8 #define __is_iframe(ctrl) !((ctrl) & L2CAP_CTRL_FRAME_TYPE) #define __is_sframe(ctrl) (ctrl) & L2CAP_CTRL_FRAME_TYPE +#define __is_sar_start(ctrl) ((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START void l2cap_load(void); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 45b8697..167e025 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1334,7 +1334,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *ms return skb; } -static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control) +static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb; @@ -1343,6 +1343,9 @@ static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg BT_DBG("sk %p len %d", sk, (int)len); + if (sdulen) + hlen += 2; + count = min_t(unsigned int, (conn->mtu - hlen), len); skb = bt_skb_send_alloc(sk, count + hlen, msg->msg_flags & MSG_DONTWAIT, &err); @@ -1354,6 +1357,8 @@ static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); put_unaligned_le16(control, skb_put(skb, 2)); + if (sdulen) + put_unaligned_le16(sdulen, skb_put(skb, 2)); err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); if (unlikely(err < 0)) { @@ -1363,6 +1368,54 @@ static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg return skb; } +static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *skb; + struct sk_buff_head sar_queue; + u16 control; + size_t size = 0; + + __skb_queue_head_init(&sar_queue); + control = L2CAP_SDU_START; + skb = l2cap_create_ertm_pdu(sk, msg, pi->max_pdu_size, control, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + __skb_queue_tail(&sar_queue, skb); + len -= pi->max_pdu_size; + size +=pi->max_pdu_size; + control = 0; + + while (len > 0) { + size_t buflen; + + if (len > pi->max_pdu_size) { + control |= L2CAP_SDU_CONTINUE; + buflen = pi->max_pdu_size; + } else { + control |= L2CAP_SDU_END; + buflen = len; + } + + skb = l2cap_create_ertm_pdu(sk, msg, buflen, control, 0); + if (IS_ERR(skb)) { + skb_queue_purge(&sar_queue); + return PTR_ERR(skb); + } + + __skb_queue_tail(&sar_queue, skb); + len -= buflen; + size += buflen; + control = 0; + } + skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk)); + if (sk->sk_send_head == NULL) + sk->sk_send_head = sar_queue.next; + + return size; +} + static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; @@ -1415,21 +1468,22 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms case L2CAP_MODE_ERTM: /* Entire SDU fits into one PDU */ - if (len <= pi->omtu) { + if (len <= pi->max_pdu_size) { control = L2CAP_SDU_UNSEGMENTED; - skb = l2cap_create_ertm_pdu(sk, msg, len, control); + skb = l2cap_create_ertm_pdu(sk, msg, len, control, 0); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; } + __skb_queue_tail(TX_QUEUE(sk), skb); + if (sk->sk_send_head == NULL) + sk->sk_send_head = skb; } else { - /* FIXME: Segmentation will be added later */ - err = -EINVAL; - goto done; + /* Segment SDU into multiples PDUs */ + err = l2cap_sar_segment_sdu(sk, msg, len); + if (err < 0) + goto done; } - __skb_queue_tail(TX_QUEUE(sk), skb); - if (sk->sk_send_head == NULL) - sk->sk_send_head = skb; err = l2cap_ertm_send(sk); if (!err) @@ -2007,7 +2061,7 @@ done: rfc.max_transmit = L2CAP_DEFAULT_MAX_RECEIVE; rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; - rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_RX_APDU); + rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -2019,7 +2073,7 @@ done: rfc.max_transmit = 0; rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; - rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_RX_APDU); + rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -2808,6 +2862,86 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk kfree_skb(skb); } +static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *_skb; + int err = -EINVAL; + + switch (control & L2CAP_CTRL_SAR) { + case L2CAP_SDU_UNSEGMENTED: + if (pi->conn_state & L2CAP_CONN_SAR_SDU) { + kfree_skb(pi->sdu); + break; + } + + err = sock_queue_rcv_skb(sk, skb); + if (!err) + return 0; + + break; + + case L2CAP_SDU_START: + if (pi->conn_state & L2CAP_CONN_SAR_SDU) { + kfree_skb(pi->sdu); + break; + } + + pi->sdu_len = get_unaligned_le16(skb->data); + skb_pull(skb, 2); + + pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); + if (!pi->sdu) { + err = -ENOMEM; + break; + } + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + + pi->conn_state |= L2CAP_CONN_SAR_SDU; + pi->partial_sdu_len = skb->len; + err = 0; + break; + + case L2CAP_SDU_CONTINUE: + if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + break; + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + + pi->partial_sdu_len += skb->len; + if (pi->partial_sdu_len > pi->sdu_len) + kfree_skb(pi->sdu); + else + err = 0; + + break; + + case L2CAP_SDU_END: + if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + break; + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + + pi->conn_state &= ~L2CAP_CONN_SAR_SDU; + pi->partial_sdu_len += skb->len; + + if (pi->partial_sdu_len == pi->sdu_len) { + _skb = skb_clone(pi->sdu, GFP_ATOMIC); + err = sock_queue_rcv_skb(sk, _skb); + if (err < 0) + kfree_skb(_skb); + } + kfree_skb(pi->sdu); + err = 0; + + break; + } + + kfree_skb(skb); + return err; +} + static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) { struct l2cap_pinfo *pi = l2cap_pi(sk); @@ -2820,11 +2954,11 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str if (tx_seq != pi->expected_tx_seq) return -EINVAL; - pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; - err = sock_queue_rcv_skb(sk, skb); - if (err) + err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); + if (err < 0) return err; + pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { tx_control |= L2CAP_CTRL_FRAME_TYPE; @@ -2860,7 +2994,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { struct sock *sk; - u16 control; + u16 control, len; int err; sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); @@ -2891,8 +3025,12 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk case L2CAP_MODE_ERTM: control = get_unaligned_le16(skb->data); skb_pull(skb, 2); + len = skb->len; - if (l2cap_pi(sk)->imtu < skb->len) + if (__is_sar_start(control)) + len -= 2; + + if (len > L2CAP_DEFAULT_MAX_PDU_SIZE) goto drop; if (__is_iframe(control)) -- cgit v0.10.2 From 30afb5b2aa83adf4f69e5090d48e1bb04b64c58a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 20 Aug 2009 22:25:59 -0300 Subject: Bluetooth: Initial support for retransmission of packets with REJ frames When receiving an I-frame with unexpected txSeq, receiver side start the recovery procedure by sending a REJ S-frame to the transmitter side. So the transmitter can re-send the lost I-frame. This patch just adds a basic support for retransmission, it doesn't mean that ERTM now has full support for packet retransmission. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 0afde8d..a1d8ec4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -351,6 +351,7 @@ struct l2cap_pinfo { #define L2CAP_CONF_MAX_CONF_RSP 2 #define L2CAP_CONN_SAR_SDU 0x01 +#define L2CAP_CONN_UNDER_REJ 0x02 static inline int l2cap_tx_window_full(struct sock *sk) { diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 167e025..35e9f5b 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2951,22 +2951,36 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); - if (tx_seq != pi->expected_tx_seq) - return -EINVAL; + if (tx_seq == pi->expected_tx_seq) { + if (pi->conn_state & L2CAP_CONN_UNDER_REJ) + pi->conn_state &= ~L2CAP_CONN_UNDER_REJ; - err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); - if (err < 0) - return err; + err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); + if (err < 0) + return err; + + pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; + if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { + tx_control |= L2CAP_SUPER_RCV_READY; + tx_control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + goto send; + } + } else { + /* Unexpected txSeq. Send a REJ S-frame */ + kfree_skb(skb); + if (!(pi->conn_state & L2CAP_CONN_UNDER_REJ)) { + tx_control |= L2CAP_SUPER_REJECT; + tx_control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + pi->conn_state |= L2CAP_CONN_UNDER_REJ; - pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; - pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; - if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { - tx_control |= L2CAP_CTRL_FRAME_TYPE; - tx_control |= L2CAP_SUPER_RCV_READY; - tx_control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; - err = l2cap_send_sframe(pi, tx_control); + goto send; + } } - return err; + return 0; + +send: + return l2cap_send_sframe(pi, tx_control); } static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) @@ -2982,8 +2996,18 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str l2cap_ertm_send(sk); break; - case L2CAP_SUPER_RCV_NOT_READY: case L2CAP_SUPER_REJECT: + pi->expected_ack_seq = __get_reqseq(rx_control); + l2cap_drop_acked_frames(sk); + + sk->sk_send_head = TX_QUEUE(sk)->next; + pi->next_tx_seq = pi->expected_ack_seq; + + l2cap_ertm_send(sk); + + break; + + case L2CAP_SUPER_RCV_NOT_READY: case L2CAP_SUPER_SELECT_REJECT: break; } @@ -3030,6 +3054,11 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (__is_sar_start(control)) len -= 2; + /* + * We can just drop the corrupted I-frame here. + * Receiver will miss it and start proper recovery + * procedures and ask retransmission. + */ if (len > L2CAP_DEFAULT_MAX_PDU_SIZE) goto drop; -- cgit v0.10.2 From e90bac061b17cd81bd0df30606c64f4543bf5ca0 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 20 Aug 2009 22:26:00 -0300 Subject: Bluetooth: Add support for Retransmission and Monitor Timers L2CAP uses retransmission and monitor timers to inquiry the other side about unacked I-frames. After sending each I-frame we (re)start the retransmission timer. If it expires, we start a monitor timer that send a S-frame with P bit set and wait for S-frame with F bit set. If monitor timer expires, try again, at a maximum of L2CAP_DEFAULT_MAX_TX. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 65a5cf8..b8b9a84 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -139,6 +139,7 @@ struct bt_skb_cb { __u8 pkt_type; __u8 incoming; __u8 tx_seq; + __u8 retries; }; #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a1d8ec4..2cf7003 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -31,9 +31,9 @@ #define L2CAP_DEFAULT_FLUSH_TO 0xffff #define L2CAP_DEFAULT_TX_WINDOW 63 #define L2CAP_DEFAULT_NUM_TO_ACK (L2CAP_DEFAULT_TX_WINDOW/5) -#define L2CAP_DEFAULT_MAX_RECEIVE 1 -#define L2CAP_DEFAULT_RETRANS_TO 300 /* 300 milliseconds */ -#define L2CAP_DEFAULT_MONITOR_TO 1000 /* 1 second */ +#define L2CAP_DEFAULT_MAX_TX 3 +#define L2CAP_DEFAULT_RETRANS_TO 1000 /* 1 second */ +#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ #define L2CAP_DEFAULT_MAX_PDU_SIZE 672 #define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ @@ -318,6 +318,7 @@ struct l2cap_pinfo { __u8 req_seq; __u8 expected_tx_seq; __u8 unacked_frames; + __u8 retry_count; __u8 num_to_ack; __u16 sdu_len; __u16 partial_sdu_len; @@ -333,6 +334,8 @@ struct l2cap_pinfo { __le16 sport; + struct timer_list retrans_timer; + struct timer_list monitor_timer; struct sk_buff_head tx_queue; struct l2cap_conn *conn; struct sock *next_c; @@ -352,6 +355,12 @@ struct l2cap_pinfo { #define L2CAP_CONN_SAR_SDU 0x01 #define L2CAP_CONN_UNDER_REJ 0x02 +#define L2CAP_CONN_WAIT_F 0x04 + +#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ + jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); +#define __mod_monitor_timer() mod_timer(&l2cap_pi(sk)->monitor_timer, \ + jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO)); static inline int l2cap_tx_window_full(struct sock *sk) { diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 35e9f5b..97172f7 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1178,6 +1178,39 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l return 0; } +static void l2cap_monitor_timeout(unsigned long arg) +{ + struct sock *sk = (void *) arg; + u16 control; + + if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { + l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk); + return; + } + + l2cap_pi(sk)->retry_count++; + __mod_monitor_timer(); + + control = L2CAP_CTRL_POLL; + control |= L2CAP_SUPER_RCV_READY; + l2cap_send_sframe(l2cap_pi(sk), control); +} + +static void l2cap_retrans_timeout(unsigned long arg) +{ + struct sock *sk = (void *) arg; + u16 control; + + l2cap_pi(sk)->retry_count = 1; + __mod_monitor_timer(); + + l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; + + control = L2CAP_CTRL_POLL; + control |= L2CAP_SUPER_RCV_READY; + l2cap_send_sframe(l2cap_pi(sk), control); +} + static void l2cap_drop_acked_frames(struct sock *sk) { struct sk_buff *skb; @@ -1192,6 +1225,9 @@ static void l2cap_drop_acked_frames(struct sock *sk) l2cap_pi(sk)->unacked_frames--; } + if (!l2cap_pi(sk)->unacked_frames) + del_timer(&l2cap_pi(sk)->retrans_timer); + return; } @@ -1216,19 +1252,32 @@ static int l2cap_ertm_send(struct sock *sk) u16 control; int err; + if (pi->conn_state & L2CAP_CONN_WAIT_F) + return 0; + while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) { tx_skb = skb_clone(skb, GFP_ATOMIC); + if (pi->remote_max_tx && + bt_cb(skb)->retries == pi->remote_max_tx) { + l2cap_send_disconn_req(pi->conn, sk); + break; + } + + bt_cb(skb)->retries++; + control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); control |= (pi->req_seq << L2CAP_CTRL_REQSEQ_SHIFT) | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + err = l2cap_do_send(sk, tx_skb); if (err < 0) { l2cap_send_disconn_req(pi->conn, sk); return err; } + __mod_retrans_timer(); bt_cb(skb)->tx_seq = pi->next_tx_seq; pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; @@ -1365,6 +1414,8 @@ static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg kfree_skb(skb); return ERR_PTR(err); } + + bt_cb(skb)->retries = 0; return skb; } @@ -2058,7 +2109,7 @@ done: case L2CAP_MODE_ERTM: rfc.mode = L2CAP_MODE_ERTM; rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; - rfc.max_transmit = L2CAP_DEFAULT_MAX_RECEIVE; + rfc.max_transmit = L2CAP_DEFAULT_MAX_TX; rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); @@ -2553,6 +2604,12 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->next_tx_seq = 0; l2cap_pi(sk)->expected_ack_seq = 0; l2cap_pi(sk)->unacked_frames = 0; + + setup_timer(&l2cap_pi(sk)->retrans_timer, + l2cap_retrans_timeout, (unsigned long) sk); + setup_timer(&l2cap_pi(sk)->monitor_timer, + l2cap_monitor_timeout, (unsigned long) sk); + __skb_queue_head_init(TX_QUEUE(sk)); l2cap_chan_ready(sk); goto unlock; @@ -2662,6 +2719,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk->sk_shutdown = SHUTDOWN_MASK; skb_queue_purge(TX_QUEUE(sk)); + del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&l2cap_pi(sk)->monitor_timer); l2cap_chan_del(sk, ECONNRESET); bh_unlock_sock(sk); @@ -2686,6 +2745,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd return 0; skb_queue_purge(TX_QUEUE(sk)); + del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&l2cap_pi(sk)->monitor_timer); l2cap_chan_del(sk, 0); bh_unlock_sock(sk); @@ -2991,9 +3052,26 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str switch (rx_control & L2CAP_CTRL_SUPERVISE) { case L2CAP_SUPER_RCV_READY: - pi->expected_ack_seq = __get_reqseq(rx_control); - l2cap_drop_acked_frames(sk); - l2cap_ertm_send(sk); + if (rx_control & L2CAP_CTRL_POLL) { + u16 control = L2CAP_CTRL_FINAL; + control |= L2CAP_SUPER_RCV_READY; + l2cap_send_sframe(l2cap_pi(sk), control); + } else if (rx_control & L2CAP_CTRL_FINAL) { + if (!(pi->conn_state & L2CAP_CONN_WAIT_F)) + break; + + pi->conn_state &= ~L2CAP_CONN_WAIT_F; + del_timer(&pi->monitor_timer); + + if (pi->unacked_frames > 0) + __mod_retrans_timer(); + } else { + pi->expected_ack_seq = __get_reqseq(rx_control); + l2cap_drop_acked_frames(sk); + if (pi->unacked_frames > 0) + __mod_retrans_timer(); + l2cap_ertm_send(sk); + } break; case L2CAP_SUPER_REJECT: -- cgit v0.10.2 From 6840ed0770d79b9bb0800e5e026a067040ef18f5 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 20 Aug 2009 22:26:01 -0300 Subject: Bluetooth: Enable Streaming Mode for L2CAP Streaming Mode is helpful for the Bluetooth streaming based profiles, such as A2DP. It doesn't have any error control or flow control. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 97172f7..7f835e7 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1245,6 +1245,39 @@ static inline int l2cap_do_send(struct sock *sk, struct sk_buff *skb) return err; } +static int l2cap_streaming_send(struct sock *sk) +{ + struct sk_buff *skb, *tx_skb; + struct l2cap_pinfo *pi = l2cap_pi(sk); + u16 control; + int err; + + while ((skb = sk->sk_send_head)) { + tx_skb = skb_clone(skb, GFP_ATOMIC); + + control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; + put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + + err = l2cap_do_send(sk, tx_skb); + if (err < 0) { + l2cap_send_disconn_req(pi->conn, sk); + return err; + } + + pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; + + if (skb_queue_is_last(TX_QUEUE(sk), skb)) + sk->sk_send_head = NULL; + else + sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); + + skb = skb_dequeue(TX_QUEUE(sk)); + kfree_skb(skb); + } + return 0; +} + static int l2cap_ertm_send(struct sock *sk) { struct sk_buff *skb, *tx_skb; @@ -1383,7 +1416,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *ms return skb; } -static struct sk_buff *l2cap_create_ertm_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen) +static struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb; @@ -1429,7 +1462,7 @@ static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, siz __skb_queue_head_init(&sar_queue); control = L2CAP_SDU_START; - skb = l2cap_create_ertm_pdu(sk, msg, pi->max_pdu_size, control, len); + skb = l2cap_create_iframe_pdu(sk, msg, pi->max_pdu_size, control, len); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1449,7 +1482,7 @@ static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, siz buflen = len; } - skb = l2cap_create_ertm_pdu(sk, msg, buflen, control, 0); + skb = l2cap_create_iframe_pdu(sk, msg, buflen, control, 0); if (IS_ERR(skb)) { skb_queue_purge(&sar_queue); return PTR_ERR(skb); @@ -1518,10 +1551,11 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms break; case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: /* Entire SDU fits into one PDU */ if (len <= pi->max_pdu_size) { control = L2CAP_SDU_UNSEGMENTED; - skb = l2cap_create_ertm_pdu(sk, msg, len, control, 0); + skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; @@ -1536,7 +1570,11 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms goto done; } - err = l2cap_ertm_send(sk); + if (pi->mode == L2CAP_MODE_STREAMING) + err = l2cap_streaming_send(sk); + else + err = l2cap_ertm_send(sk); + if (!err) err = len; break; @@ -2050,7 +2088,7 @@ static int l2cap_mode_supported(__u8 mode, __u32 feat_mask) { u32 local_feat_mask = l2cap_feat_mask; if (enable_ertm) - local_feat_mask |= L2CAP_FEAT_ERTM; + local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING; switch (mode) { case L2CAP_MODE_ERTM: @@ -2771,7 +2809,7 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK); rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); if (enable_ertm) - feat_mask |= L2CAP_FEAT_ERTM; + feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING; put_unaligned(cpu_to_le32(feat_mask), (__le32 *) rsp->data); l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf), buf); @@ -3096,7 +3134,9 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { struct sock *sk; + struct l2cap_pinfo *pi; u16 control, len; + u8 tx_seq; int err; sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); @@ -3105,19 +3145,21 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk goto drop; } + pi = l2cap_pi(sk); + BT_DBG("sk %p, len %d", sk, skb->len); if (sk->sk_state != BT_CONNECTED) goto drop; - switch (l2cap_pi(sk)->mode) { + switch (pi->mode) { case L2CAP_MODE_BASIC: /* If socket recv buffers overflows we drop data here * which is *bad* because L2CAP has to be reliable. * But we don't have any other choice. L2CAP doesn't * provide flow control mechanism. */ - if (l2cap_pi(sk)->imtu < skb->len) + if (pi->imtu < skb->len) goto drop; if (!sock_queue_rcv_skb(sk, skb)) @@ -3149,6 +3191,28 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk goto done; break; + case L2CAP_MODE_STREAMING: + control = get_unaligned_le16(skb->data); + skb_pull(skb, 2); + len = skb->len; + + if (__is_sar_start(control)) + len -= 2; + + if (len > L2CAP_DEFAULT_MAX_PDU_SIZE || __is_sframe(control)) + goto drop; + + tx_seq = __get_txseq(control); + + if (pi->expected_tx_seq == tx_seq) + pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + else + pi->expected_tx_seq = tx_seq + 1; + + err = l2cap_sar_reassembly_sdu(sk, skb, control); + + goto done; + default: BT_DBG("sk %p: bad mode 0x%2.2x", sk, l2cap_pi(sk)->mode); break; -- cgit v0.10.2 From fcc203c30d72dde82692f6b761a80e5ca5fdd8fa Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 20 Aug 2009 22:26:02 -0300 Subject: Bluetooth: Add support for FCS option to L2CAP Implement CRC16 check for L2CAP packets. FCS is used by Streaming Mode and Enhanced Retransmission Mode and is a extra check for the packet content. Using CRC16 is the default, L2CAP won't use FCS only when both side send a "No FCS" request. Initially based on a patch from Nathan Holstein Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 2cf7003..59b26bf 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -54,6 +54,7 @@ struct l2cap_options { __u16 imtu; __u16 flush_to; __u8 mode; + __u8 fcs; }; #define L2CAP_CONNINFO 0x02 @@ -348,6 +349,7 @@ struct l2cap_pinfo { #define L2CAP_CONF_MTU_DONE 0x08 #define L2CAP_CONF_MODE_DONE 0x10 #define L2CAP_CONF_CONNECT_PEND 0x20 +#define L2CAP_CONF_NO_FCS_RECV 0x40 #define L2CAP_CONF_STATE2_DEVICE 0x80 #define L2CAP_CONF_MAX_CONF_REQ 2 diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 7f835e7..4c31900 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -338,11 +339,14 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) struct sk_buff *skb; struct l2cap_hdr *lh; struct l2cap_conn *conn = pi->conn; - int count; + int count, hlen = L2CAP_HDR_SIZE + 2; + + if (pi->fcs == L2CAP_FCS_CRC16) + hlen += 2; BT_DBG("pi %p, control 0x%2.2x", pi, control); - count = min_t(unsigned int, conn->mtu, L2CAP_HDR_SIZE + 2); + count = min_t(unsigned int, conn->mtu, hlen); control |= L2CAP_CTRL_FRAME_TYPE; skb = bt_skb_alloc(count, GFP_ATOMIC); @@ -350,10 +354,15 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) return -ENOMEM; lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->len = cpu_to_le16(2); + lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(pi->dcid); put_unaligned_le16(control, skb_put(skb, 2)); + if (pi->fcs == L2CAP_FCS_CRC16) { + u16 fcs = crc16(0, (u8 *)lh, count - 2); + put_unaligned_le16(fcs, skb_put(skb, 2)); + } + return hci_send_acl(pi->conn->hcon, skb, 0); } @@ -1249,7 +1258,7 @@ static int l2cap_streaming_send(struct sock *sk) { struct sk_buff *skb, *tx_skb; struct l2cap_pinfo *pi = l2cap_pi(sk); - u16 control; + u16 control, fcs; int err; while ((skb = sk->sk_send_head)) { @@ -1259,6 +1268,11 @@ static int l2cap_streaming_send(struct sock *sk) control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) { + fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); + put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); + } + err = l2cap_do_send(sk, tx_skb); if (err < 0) { l2cap_send_disconn_req(pi->conn, sk); @@ -1282,7 +1296,7 @@ static int l2cap_ertm_send(struct sock *sk) { struct sk_buff *skb, *tx_skb; struct l2cap_pinfo *pi = l2cap_pi(sk); - u16 control; + u16 control, fcs; int err; if (pi->conn_state & L2CAP_CONN_WAIT_F) @@ -1305,6 +1319,11 @@ static int l2cap_ertm_send(struct sock *sk) put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) { + fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2); + put_unaligned_le16(fcs, skb->data + tx_skb->len - 2); + } + err = l2cap_do_send(sk, tx_skb); if (err < 0) { l2cap_send_disconn_req(pi->conn, sk); @@ -1428,6 +1447,9 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *m if (sdulen) hlen += 2; + if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) + hlen += 2; + count = min_t(unsigned int, (conn->mtu - hlen), len); skb = bt_skb_send_alloc(sk, count + hlen, msg->msg_flags & MSG_DONTWAIT, &err); @@ -1448,6 +1470,9 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *m return ERR_PTR(err); } + if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) + put_unaligned_le16(0, skb_put(skb, 2)); + bt_cb(skb)->retries = 0; return skb; } @@ -1633,6 +1658,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; + opts.fcs = l2cap_pi(sk)->fcs; len = min_t(unsigned int, sizeof(opts), optlen); if (copy_from_user((char *) &opts, optval, len)) { @@ -1643,6 +1669,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us l2cap_pi(sk)->imtu = opts.imtu; l2cap_pi(sk)->omtu = opts.omtu; l2cap_pi(sk)->mode = opts.mode; + l2cap_pi(sk)->fcs = opts.fcs; break; case L2CAP_LM: @@ -1756,6 +1783,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; + opts.fcs = l2cap_pi(sk)->fcs; len = min_t(unsigned int, len, sizeof(opts)); if (copy_to_user(optval, (char *) &opts, len)) @@ -2154,6 +2182,15 @@ done: l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); + + if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) + break; + + if (pi->fcs == L2CAP_FCS_NONE || + pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { + pi->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); + } break; case L2CAP_MODE_STREAMING: @@ -2166,6 +2203,15 @@ done: l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); + + if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) + break; + + if (pi->fcs == L2CAP_FCS_NONE || + pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { + pi->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); + } break; } @@ -2217,6 +2263,12 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) memcpy(&rfc, (void *) val, olen); break; + case L2CAP_CONF_FCS: + if (val == L2CAP_FCS_NONE) + pi->conf_state |= L2CAP_CONF_NO_FCS_RECV; + + break; + default: if (hint) break; @@ -2638,6 +2690,10 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr goto unlock; if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { + if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) + || l2cap_pi(sk)->fcs != L2CAP_FCS_NONE) + l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; + sk->sk_state = BT_CONNECTED; l2cap_pi(sk)->next_tx_seq = 0; l2cap_pi(sk)->expected_ack_seq = 0; @@ -2722,6 +2778,10 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { + if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) + || l2cap_pi(sk)->fcs != L2CAP_FCS_NONE) + l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; + sk->sk_state = BT_CONNECTED; l2cap_pi(sk)->expected_tx_seq = 0; l2cap_pi(sk)->num_to_ack = 0; @@ -2809,7 +2869,8 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK); rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); if (enable_ertm) - feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING; + feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING + | L2CAP_FEAT_FCS; put_unaligned(cpu_to_le32(feat_mask), (__le32 *) rsp->data); l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf), buf); @@ -2961,6 +3022,22 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk kfree_skb(skb); } +static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) +{ + u16 our_fcs, rcv_fcs; + int hdr_size = L2CAP_HDR_SIZE + 2; + + if (pi->fcs == L2CAP_FCS_CRC16) { + skb_trim(skb, skb->len - 2); + rcv_fcs = get_unaligned_le16(skb->data + skb->len); + our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size); + + if (our_fcs != rcv_fcs) + return -EINVAL; + } + return 0; +} + static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) { struct l2cap_pinfo *pi = l2cap_pi(sk); @@ -3174,6 +3251,9 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (__is_sar_start(control)) len -= 2; + if (pi->fcs == L2CAP_FCS_CRC16) + len -= 2; + /* * We can just drop the corrupted I-frame here. * Receiver will miss it and start proper recovery @@ -3182,6 +3262,9 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (len > L2CAP_DEFAULT_MAX_PDU_SIZE) goto drop; + if (l2cap_check_fcs(pi, skb)) + goto drop; + if (__is_iframe(control)) err = l2cap_data_channel_iframe(sk, control, skb); else @@ -3199,9 +3282,15 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (__is_sar_start(control)) len -= 2; + if (pi->fcs == L2CAP_FCS_CRC16) + len -= 2; + if (len > L2CAP_DEFAULT_MAX_PDU_SIZE || __is_sframe(control)) goto drop; + if (l2cap_check_fcs(pi, skb)) + goto drop; + tx_seq = __get_txseq(control); if (pi->expected_tx_seq == tx_seq) -- cgit v0.10.2 From 8f17154f1f70fcc6faa31ac82164fcf7f0599f38 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 20 Aug 2009 22:26:03 -0300 Subject: Bluetooth: Add support for L2CAP SREJ exception When L2CAP loses an I-frame we send a SREJ frame to the transmitter side requesting the lost packet. This patch implement all Recv I-frame events on SREJ_SENT state table except the ones that deal with SendRej (the REJ exception at receiver side is yet not implemented). Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index b8b9a84..718394e 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -140,6 +140,7 @@ struct bt_skb_cb { __u8 incoming; __u8 tx_seq; __u8 retries; + __u8 sar; }; #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 59b26bf..9f2126a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -108,6 +108,7 @@ struct l2cap_conninfo { #define L2CAP_CTRL_TXSEQ_SHIFT 1 #define L2CAP_CTRL_REQSEQ_SHIFT 8 +#define L2CAP_CTRL_SAR_SHIFT 14 /* L2CAP Supervisory Function */ #define L2CAP_SUPER_RCV_READY 0x0000 @@ -290,6 +291,13 @@ struct l2cap_conn { /* ----- L2CAP channel and socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) #define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) +#define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue) +#define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list) + +struct srej_list { + __u8 tx_seq; + struct list_head list; +}; struct l2cap_pinfo { struct bt_sock bt; @@ -318,6 +326,8 @@ struct l2cap_pinfo { __u8 expected_ack_seq; __u8 req_seq; __u8 expected_tx_seq; + __u8 buffer_seq; + __u8 buffer_seq_srej; __u8 unacked_frames; __u8 retry_count; __u8 num_to_ack; @@ -338,6 +348,8 @@ struct l2cap_pinfo { struct timer_list retrans_timer; struct timer_list monitor_timer; struct sk_buff_head tx_queue; + struct sk_buff_head srej_queue; + struct srej_list srej_l; struct l2cap_conn *conn; struct sock *next_c; struct sock *prev_c; @@ -356,7 +368,7 @@ struct l2cap_pinfo { #define L2CAP_CONF_MAX_CONF_RSP 2 #define L2CAP_CONN_SAR_SDU 0x01 -#define L2CAP_CONN_UNDER_REJ 0x02 +#define L2CAP_CONN_SREJ_SENT 0x02 #define L2CAP_CONN_WAIT_F 0x04 #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 4c31900..70aff92 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1292,6 +1292,50 @@ static int l2cap_streaming_send(struct sock *sk) return 0; } +static int l2cap_retransmit_frame(struct sock *sk, u8 tx_seq) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *skb, *tx_skb; + u16 control, fcs; + int err; + + skb = skb_peek(TX_QUEUE(sk)); + do { + if (bt_cb(skb)->tx_seq != tx_seq) { + if (skb_queue_is_last(TX_QUEUE(sk), skb)) + break; + skb = skb_queue_next(TX_QUEUE(sk), skb); + continue; + } + + if (pi->remote_max_tx && + bt_cb(skb)->retries == pi->remote_max_tx) { + l2cap_send_disconn_req(pi->conn, sk); + break; + } + + tx_skb = skb_clone(skb, GFP_ATOMIC); + bt_cb(skb)->retries++; + control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + control |= (pi->req_seq << L2CAP_CTRL_REQSEQ_SHIFT) + | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); + put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); + + if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) { + fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); + put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); + } + + err = l2cap_do_send(sk, tx_skb); + if (err < 0) { + l2cap_send_disconn_req(pi->conn, sk); + return err; + } + break; + } while(1); + return 0; +} + static int l2cap_ertm_send(struct sock *sk) { struct sk_buff *skb, *tx_skb; @@ -2705,6 +2749,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_monitor_timeout, (unsigned long) sk); __skb_queue_head_init(TX_QUEUE(sk)); + __skb_queue_head_init(SREJ_QUEUE(sk)); l2cap_chan_ready(sk); goto unlock; } @@ -2784,8 +2829,10 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr sk->sk_state = BT_CONNECTED; l2cap_pi(sk)->expected_tx_seq = 0; + l2cap_pi(sk)->buffer_seq = 0; l2cap_pi(sk)->num_to_ack = 0; __skb_queue_head_init(TX_QUEUE(sk)); + __skb_queue_head_init(SREJ_QUEUE(sk)); l2cap_chan_ready(sk); } @@ -2817,6 +2864,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk->sk_shutdown = SHUTDOWN_MASK; skb_queue_purge(TX_QUEUE(sk)); + skb_queue_purge(SREJ_QUEUE(sk)); del_timer(&l2cap_pi(sk)->retrans_timer); del_timer(&l2cap_pi(sk)->monitor_timer); @@ -2843,6 +2891,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd return 0; skb_queue_purge(TX_QUEUE(sk)); + skb_queue_purge(SREJ_QUEUE(sk)); del_timer(&l2cap_pi(sk)->retrans_timer); del_timer(&l2cap_pi(sk)->monitor_timer); @@ -3038,6 +3087,33 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) return 0; } +static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) +{ + struct sk_buff *next_skb; + + bt_cb(skb)->tx_seq = tx_seq; + bt_cb(skb)->sar = sar; + + next_skb = skb_peek(SREJ_QUEUE(sk)); + if (!next_skb) { + __skb_queue_tail(SREJ_QUEUE(sk), skb); + return; + } + + do { + if (bt_cb(next_skb)->tx_seq > tx_seq) { + __skb_queue_before(SREJ_QUEUE(sk), next_skb, skb); + return; + } + + if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb)) + break; + + } while((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb))); + + __skb_queue_tail(SREJ_QUEUE(sk), skb); +} + static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) { struct l2cap_pinfo *pi = l2cap_pi(sk); @@ -3118,50 +3194,143 @@ static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 co return err; } +static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) +{ + struct sk_buff *skb; + u16 control = 0; + + while((skb = skb_peek(SREJ_QUEUE(sk)))) { + if (bt_cb(skb)->tx_seq != tx_seq) + break; + + skb = skb_dequeue(SREJ_QUEUE(sk)); + control |= bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; + l2cap_sar_reassembly_sdu(sk, skb, control); + l2cap_pi(sk)->buffer_seq_srej = + (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; + tx_seq++; + } +} + +static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct srej_list *l, *tmp; + u16 control; + + list_for_each_entry_safe(l,tmp, SREJ_LIST(sk), list) { + if (l->tx_seq == tx_seq) { + list_del(&l->list); + kfree(l); + return; + } + control = L2CAP_SUPER_SELECT_REJECT; + control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + l2cap_send_sframe(pi, control); + list_del(&l->list); + list_add_tail(&l->list, SREJ_LIST(sk)); + } +} + +static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct srej_list *new; + u16 control; + + while (tx_seq != pi->expected_tx_seq) { + control = L2CAP_SUPER_SELECT_REJECT; + control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + l2cap_send_sframe(pi, control); + + new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); + new->tx_seq = pi->expected_tx_seq++; + list_add_tail(&new->list, SREJ_LIST(sk)); + } + pi->expected_tx_seq++; +} + static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) { struct l2cap_pinfo *pi = l2cap_pi(sk); u8 tx_seq = __get_txseq(rx_control); u16 tx_control = 0; + u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; int err = 0; BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); - if (tx_seq == pi->expected_tx_seq) { - if (pi->conn_state & L2CAP_CONN_UNDER_REJ) - pi->conn_state &= ~L2CAP_CONN_UNDER_REJ; + if (tx_seq == pi->expected_tx_seq) + goto expected; - err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); - if (err < 0) - return err; + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { + struct srej_list *first; - pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; - pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; - if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { - tx_control |= L2CAP_SUPER_RCV_READY; - tx_control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; - goto send; + first = list_first_entry(SREJ_LIST(sk), + struct srej_list, list); + if (tx_seq == first->tx_seq) { + l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + l2cap_check_srej_gap(sk, tx_seq); + + list_del(&first->list); + kfree(first); + + if (list_empty(SREJ_LIST(sk))) { + pi->buffer_seq = pi->buffer_seq_srej; + pi->conn_state &= ~L2CAP_CONN_SREJ_SENT; + } + } else { + struct srej_list *l; + l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + + list_for_each_entry(l, SREJ_LIST(sk), list) { + if (l->tx_seq == tx_seq) { + l2cap_resend_srejframe(sk, tx_seq); + return 0; + } + } + l2cap_send_srejframe(sk, tx_seq); } } else { - /* Unexpected txSeq. Send a REJ S-frame */ - kfree_skb(skb); - if (!(pi->conn_state & L2CAP_CONN_UNDER_REJ)) { - tx_control |= L2CAP_SUPER_REJECT; - tx_control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; - pi->conn_state |= L2CAP_CONN_UNDER_REJ; + pi->conn_state |= L2CAP_CONN_SREJ_SENT; - goto send; - } + INIT_LIST_HEAD(SREJ_LIST(sk)); + pi->buffer_seq_srej = pi->buffer_seq; + + __skb_queue_head_init(SREJ_QUEUE(sk)); + l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + + l2cap_send_srejframe(sk, tx_seq); } return 0; -send: - return l2cap_send_sframe(pi, tx_control); +expected: + pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { + l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + return 0; + } + + pi->buffer_seq = (pi->buffer_seq + 1) % 64; + + err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); + if (err < 0) + return err; + + pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; + if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { + tx_control |= L2CAP_SUPER_RCV_READY; + tx_control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + l2cap_send_sframe(pi, tx_control); + } + return 0; } static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) { struct l2cap_pinfo *pi = l2cap_pi(sk); + u8 tx_seq = __get_reqseq(rx_control); BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); @@ -3181,7 +3350,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str if (pi->unacked_frames > 0) __mod_retrans_timer(); } else { - pi->expected_ack_seq = __get_reqseq(rx_control); + pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); if (pi->unacked_frames > 0) __mod_retrans_timer(); @@ -3200,8 +3369,11 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str break; - case L2CAP_SUPER_RCV_NOT_READY: case L2CAP_SUPER_SELECT_REJECT: + l2cap_retransmit_frame(sk, tx_seq); + break; + + case L2CAP_SUPER_RCV_NOT_READY: break; } -- cgit v0.10.2 From ef54fd937fbd5ebaeb023818524565bd526a5f36 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 20 Aug 2009 22:26:04 -0300 Subject: Bluetooth: Full support for receiving L2CAP SREJ frames Support for receiving of SREJ frames as specified by the state table. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9f2126a..7ca614a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -328,6 +328,7 @@ struct l2cap_pinfo { __u8 expected_tx_seq; __u8 buffer_seq; __u8 buffer_seq_srej; + __u8 srej_save_reqseq; __u8 unacked_frames; __u8 retry_count; __u8 num_to_ack; @@ -370,6 +371,8 @@ struct l2cap_pinfo { #define L2CAP_CONN_SAR_SDU 0x01 #define L2CAP_CONN_SREJ_SENT 0x02 #define L2CAP_CONN_WAIT_F 0x04 +#define L2CAP_CONN_SREJ_ACT 0x08 +#define L2CAP_CONN_SEND_PBIT 0x10 #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 70aff92..c04526f 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3241,6 +3241,10 @@ static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) while (tx_seq != pi->expected_tx_seq) { control = L2CAP_SUPER_SELECT_REJECT; control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + if (pi->conn_state & L2CAP_CONN_SEND_PBIT) { + control |= L2CAP_CTRL_POLL; + pi->conn_state &= ~L2CAP_CONN_SEND_PBIT; + } l2cap_send_sframe(pi, control); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); @@ -3300,6 +3304,8 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str __skb_queue_head_init(SREJ_QUEUE(sk)); l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + pi->conn_state |= L2CAP_CONN_SEND_PBIT; + l2cap_send_srejframe(sk, tx_seq); } return 0; @@ -3370,7 +3376,29 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str break; case L2CAP_SUPER_SELECT_REJECT: - l2cap_retransmit_frame(sk, tx_seq); + if (rx_control & L2CAP_CTRL_POLL) { + l2cap_retransmit_frame(sk, tx_seq); + pi->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(sk); + l2cap_ertm_send(sk); + if (pi->conn_state & L2CAP_CONN_WAIT_F) { + pi->srej_save_reqseq = tx_seq; + pi->conn_state |= L2CAP_CONN_SREJ_ACT; + } + } else if (rx_control & L2CAP_CTRL_FINAL) { + if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && + pi->srej_save_reqseq == tx_seq) + pi->srej_save_reqseq &= ~L2CAP_CONN_SREJ_ACT; + else + l2cap_retransmit_frame(sk, tx_seq); + } + else { + l2cap_retransmit_frame(sk, tx_seq); + if (pi->conn_state & L2CAP_CONN_WAIT_F) { + pi->srej_save_reqseq = tx_seq; + pi->conn_state |= L2CAP_CONN_SREJ_ACT; + } + } break; case L2CAP_SUPER_RCV_NOT_READY: -- cgit v0.10.2 From 9e726b17422bade75fba94e625cd35fd1353e682 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 15 Jul 2009 13:50:58 -0300 Subject: Bluetooth: Fix rejected connection not disconnecting ACL link When using DEFER_SETUP on a RFCOMM socket, a SABM frame triggers authorization which when rejected send a DM response. This is fine according to the RFCOMM spec: the responding implementation may replace the "proper" response on the Multiplexer Control channel with a DM frame, sent on the referenced DLCI to indicate that the DLCI is not open, and that the responder would not grant a request to open it later either. But some stacks doesn't seems to cope with this leaving DLCI 0 open after receiving DM frame. To fix it properly a timer was introduced to rfcomm_session which is used to set a timeout when the last active DLC of a session is unlinked, this will give the remote stack some time to reply with a proper DISC frame on DLCI 0 avoiding both sides sending DISC to each other on stacks that follow the specification and taking care of those who don't by taking down DLCI 0. Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index c274993..921d7b3 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -29,6 +29,7 @@ #define RFCOMM_CONN_TIMEOUT (HZ * 30) #define RFCOMM_DISC_TIMEOUT (HZ * 20) #define RFCOMM_AUTH_TIMEOUT (HZ * 25) +#define RFCOMM_IDLE_TIMEOUT (HZ * 2) #define RFCOMM_DEFAULT_MTU 127 #define RFCOMM_DEFAULT_CREDITS 7 @@ -154,6 +155,7 @@ struct rfcomm_msc { struct rfcomm_session { struct list_head list; struct socket *sock; + struct timer_list timer; unsigned long state; unsigned long flags; atomic_t refcnt; diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 26af485..25692bc 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -244,6 +244,33 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d) auth_type); } +static void rfcomm_session_timeout(unsigned long arg) +{ + struct rfcomm_session *s = (void *) arg; + + BT_DBG("session %p state %ld", s, s->state); + + set_bit(RFCOMM_TIMED_OUT, &s->flags); + rfcomm_session_put(s); + rfcomm_schedule(RFCOMM_SCHED_TIMEO); +} + +static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout) +{ + BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout); + + if (!mod_timer(&s->timer, jiffies + timeout)) + rfcomm_session_hold(s); +} + +static void rfcomm_session_clear_timer(struct rfcomm_session *s) +{ + BT_DBG("session %p state %ld", s, s->state); + + if (timer_pending(&s->timer) && del_timer(&s->timer)) + rfcomm_session_put(s); +} + /* ---- RFCOMM DLCs ---- */ static void rfcomm_dlc_timeout(unsigned long arg) { @@ -320,6 +347,7 @@ static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d) rfcomm_session_hold(s); + rfcomm_session_clear_timer(s); rfcomm_dlc_hold(d); list_add(&d->list, &s->dlcs); d->session = s; @@ -335,6 +363,9 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d) d->session = NULL; rfcomm_dlc_put(d); + if (list_empty(&s->dlcs)) + rfcomm_session_set_timer(s, RFCOMM_IDLE_TIMEOUT); + rfcomm_session_put(s); } @@ -567,6 +598,8 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state) BT_DBG("session %p sock %p", s, sock); + setup_timer(&s->timer, rfcomm_session_timeout, (unsigned long) s); + INIT_LIST_HEAD(&s->dlcs); s->state = state; s->sock = sock; @@ -598,6 +631,7 @@ static void rfcomm_session_del(struct rfcomm_session *s) if (state == BT_CONNECTED) rfcomm_send_disc(s, 0); + rfcomm_session_clear_timer(s); sock_release(s->sock); kfree(s); @@ -639,6 +673,7 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err) __rfcomm_dlc_close(d, err); } + rfcomm_session_clear_timer(s); rfcomm_session_put(s); } @@ -1879,6 +1914,12 @@ static inline void rfcomm_process_sessions(void) struct rfcomm_session *s; s = list_entry(p, struct rfcomm_session, list); + if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) { + s->state = BT_DISCONN; + rfcomm_send_disc(s, 0); + continue; + } + if (s->state == BT_LISTEN) { rfcomm_accept_connection(s); continue; -- cgit v0.10.2 From 155d5561f570c5b3af7a178670061927d89209fb Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:43 +0000 Subject: bnx2: Zero out status block before chip reset. In case IRQs are shared, we will not mistakenly start processing the ring based on old status block indices. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 756d4b4..e75b6e9 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -4858,6 +4858,7 @@ bnx2_init_chip(struct bnx2 *bp) bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu)); bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu)); + memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size); for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) bp->bnx2_napi[i].last_status_idx = 0; -- cgit v0.10.2 From 3767546cc24de8f104e745d59a0a43a09d9267df Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:44 +0000 Subject: bnx2: Check if_running() before touching chip registers. Add this check to bnx2_netif_stop() and bnx2_vlan_rx_register() to prevent bus lockups on some systems when the chip is in low power state. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index e75b6e9..9cfd460 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -619,6 +619,9 @@ bnx2_disable_int_sync(struct bnx2 *bp) int i; atomic_inc(&bp->intr_sem); + if (!netif_running(bp->dev)) + return; + bnx2_disable_int(bp); for (i = 0; i < bp->irq_nvecs; i++) synchronize_irq(bp->irq_tbl[i].vector); @@ -6254,9 +6257,14 @@ bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp) { struct bnx2 *bp = netdev_priv(dev); - bnx2_netif_stop(bp); + if (netif_running(dev)) + bnx2_netif_stop(bp); bp->vlgrp = vlgrp; + + if (!netif_running(dev)) + return; + bnx2_set_rx_mode(dev); if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN) bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1); -- cgit v0.10.2 From 6fefb65e78f098c09d0ab877b2c70421e4c84116 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:45 +0000 Subject: bnx2: Close device if MTU change or ring size change fails. When unable to allocate memory for new MTU or new ring size, we need to close the device to prevent it from crashing. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 9cfd460..1d502e6 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6992,9 +6992,14 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx) int rc; rc = bnx2_alloc_mem(bp); - if (rc) + if (!rc) + rc = bnx2_init_nic(bp, 0); + + if (rc) { + bnx2_napi_enable(bp); + dev_close(bp->dev); return rc; - bnx2_init_nic(bp, 0); + } bnx2_netif_start(bp); } return 0; -- cgit v0.10.2 From 61d9e3fa7eacabfb7879e3da91709f1a5420c507 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:46 +0000 Subject: bnx2: Apply BROKEN_STATS workaround to 5706 and 5708. Add flag to expand the workaround to both chips. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 1d502e6..085c2dd 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -4900,7 +4900,7 @@ bnx2_init_chip(struct bnx2 *bp) REG_WR(bp, BNX2_HC_CMD_TICKS, (bp->cmd_ticks_int << 16) | bp->cmd_ticks); - if (CHIP_NUM(bp) == CHIP_NUM_5708) + if (bp->flags & BNX2_FLAG_BROKEN_STATS) REG_WR(bp, BNX2_HC_STATS_TICKS, 0); else REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks); @@ -6025,7 +6025,7 @@ bnx2_timer(unsigned long data) bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT); /* workaround occasional corrupted counters */ - if (CHIP_NUM(bp) == CHIP_NUM_5708 && bp->stats_ticks) + if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks) REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_STATS_NOW); @@ -6941,7 +6941,7 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) 0xff; bp->stats_ticks = coal->stats_block_coalesce_usecs; - if (CHIP_NUM(bp) == CHIP_NUM_5708) { + if (bp->flags & BNX2_FLAG_BROKEN_STATS) { if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC) bp->stats_ticks = USEC_PER_SEC; } @@ -7722,6 +7722,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) rc = -EIO; goto err_out_unmap; } + bp->flags |= BNX2_FLAG_BROKEN_STATS; } if (CHIP_NUM(bp) == CHIP_NUM_5709 && CHIP_REV(bp) != CHIP_REV_Ax) { diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index f1edfaa..3c004b44 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6718,6 +6718,7 @@ struct bnx2 { BNX2_FLAG_USING_MSIX) #define BNX2_FLAG_JUMBO_BROKEN 0x00000800 #define BNX2_FLAG_CAN_KEEP_VLAN 0x00001000 +#define BNX2_FLAG_BROKEN_STATS 0x00002000 struct bnx2_napi bnx2_napi[BNX2_MAX_MSIX_VEC]; -- cgit v0.10.2 From 790dab2f671cb477e6179322a6c48c898e311e72 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:47 +0000 Subject: bnx2: Report FTQ discard counter. Report this counter to ethtool -S and include it in netstat. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 085c2dd..e025833 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6485,7 +6485,8 @@ bnx2_get_stats(struct net_device *dev) stats_blk->stat_EtherStatsOverrsizePkts); net_stats->rx_over_errors = - (unsigned long) stats_blk->stat_IfInMBUFDiscards; + (unsigned long) (stats_blk->stat_IfInFTQDiscards + + stats_blk->stat_IfInMBUFDiscards); net_stats->rx_frame_errors = (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors; @@ -6518,8 +6519,8 @@ bnx2_get_stats(struct net_device *dev) net_stats->tx_carrier_errors; net_stats->rx_missed_errors = - (unsigned long) (stats_blk->stat_IfInMBUFDiscards + - stats_blk->stat_FwRxDrop); + (unsigned long) (stats_blk->stat_IfInFTQDiscards + + stats_blk->stat_IfInMBUFDiscards + stats_blk->stat_FwRxDrop); return net_stats; } @@ -7090,11 +7091,9 @@ bnx2_set_tso(struct net_device *dev, u32 data) return 0; } -#define BNX2_NUM_STATS 46 - static struct { char string[ETH_GSTRING_LEN]; -} bnx2_stats_str_arr[BNX2_NUM_STATS] = { +} bnx2_stats_str_arr[] = { { "rx_bytes" }, { "rx_error_bytes" }, { "tx_bytes" }, @@ -7139,10 +7138,14 @@ static struct { { "tx_xoff_frames" }, { "rx_mac_ctrl_frames" }, { "rx_filtered_packets" }, + { "rx_ftq_discards" }, { "rx_discards" }, { "rx_fw_discards" }, }; +#define BNX2_NUM_STATS (sizeof(bnx2_stats_str_arr)/\ + sizeof(bnx2_stats_str_arr[0])) + #define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4) static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = { @@ -7190,6 +7193,7 @@ static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = { STATS_OFFSET32(stat_OutXoffSent), STATS_OFFSET32(stat_MacControlFramesReceived), STATS_OFFSET32(stat_IfInFramesL2FilterDiscards), + STATS_OFFSET32(stat_IfInFTQDiscards), STATS_OFFSET32(stat_IfInMBUFDiscards), STATS_OFFSET32(stat_FwRxDrop), }; @@ -7202,7 +7206,7 @@ static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = { 4,0,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4, + 4,4,4,4,4,4,4, }; static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = { @@ -7210,7 +7214,7 @@ static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = { 4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4, + 4,4,4,4,4,4,4, }; #define BNX2_NUM_TESTS 6 -- cgit v0.10.2 From cf7474a6f4eda22603591b7d6253dffc224e4784 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:48 +0000 Subject: bnx2: Refine coalescing parameters. - Set the USE_INT_PARAM bit so the rx-frames-irq and tx-frames-irq will take effect on 5709. - Increase the default rx-frames to reduce interrupt count. - Decrease the default rx-frames-irq and tx-frames-irq to catch more events during NAPI poll. All these will reduce interrupts without affecting latency. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index e025833..ea6e6b7 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -4921,7 +4921,7 @@ bnx2_init_chip(struct bnx2 *bp) } if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI) - val |= BNX2_HC_CONFIG_ONE_SHOT; + val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM; REG_WR(bp, BNX2_HC_CONFIG, val); @@ -7858,13 +7858,13 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->rx_csum = 1; - bp->tx_quick_cons_trip_int = 20; + bp->tx_quick_cons_trip_int = 2; bp->tx_quick_cons_trip = 20; - bp->tx_ticks_int = 80; + bp->tx_ticks_int = 18; bp->tx_ticks = 80; - bp->rx_quick_cons_trip_int = 6; - bp->rx_quick_cons_trip = 6; + bp->rx_quick_cons_trip_int = 2; + bp->rx_quick_cons_trip = 12; bp->rx_ticks_int = 18; bp->rx_ticks = 18; -- cgit v0.10.2 From 0ced9d01d19795f913b95cebedd7d03986671379 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:49 +0000 Subject: bnx2: Use const on flash_table structure. The structure, once initialized, never changes. Signed-off-by: Benjamin Li Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index ea6e6b7..58ab3f4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -145,7 +145,7 @@ static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = { { 0, } }; -static struct flash_spec flash_table[] = +static const struct flash_spec flash_table[] = { #define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE) #define NONBUFFERED_FLAGS (BNX2_NV_WREN) @@ -234,7 +234,7 @@ static struct flash_spec flash_table[] = "Buffered flash (256kB)"}, }; -static struct flash_spec flash_5709 = { +static const struct flash_spec flash_5709 = { .flags = BNX2_NV_BUFFERED, .page_bits = BCM5709_FLASH_PAGE_BITS, .page_size = BCM5709_FLASH_PAGE_SIZE, @@ -4227,7 +4227,7 @@ bnx2_init_nvram(struct bnx2 *bp) { u32 val; int j, entry_count, rc = 0; - struct flash_spec *flash; + const struct flash_spec *flash; if (CHIP_NUM(bp) == CHIP_NUM_5709) { bp->flash_info = &flash_5709; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 3c004b44..7544188 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6889,7 +6889,7 @@ struct bnx2 { int pm_cap; int pcix_cap; - struct flash_spec *flash_info; + const struct flash_spec *flash_info; u32 flash_size; int status_stats_size; -- cgit v0.10.2 From 8fea0f0db87a4aaed41a93eed147af61cc5f9e3f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:50 +0000 Subject: bnx2: Update version to 2.0.2. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 58ab3f4..4450177 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -59,8 +59,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "2.0.1" -#define DRV_MODULE_RELDATE "May 6, 2009" +#define DRV_MODULE_VERSION "2.0.2" +#define DRV_MODULE_RELDATE "Aug 21, 2009" #define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-4.6.16.fw" #define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-4.6.16.fw" #define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-4.6.17.fw" -- cgit v0.10.2 From 9f77da9f40045253e91f55c12d4481254b513d2d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 22 Aug 2009 13:56:45 -0700 Subject: rcu: Move private definitions from include/linux/rcutree.h to kernel/rcutree.h Some information hiding that makes it easier to merge preemptability into rcutree without descending into #include hell. 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: <1250974613373-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index d4dfd24..e37d5e2 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -30,217 +30,6 @@ #ifndef __LINUX_RCUTREE_H #define __LINUX_RCUTREE_H -#include -#include -#include -#include -#include - -/* - * Define shape of hierarchy based on NR_CPUS and CONFIG_RCU_FANOUT. - * In theory, it should be possible to add more levels straightforwardly. - * In practice, this has not been tested, so there is probably some - * bug somewhere. - */ -#define MAX_RCU_LVLS 3 -#define RCU_FANOUT (CONFIG_RCU_FANOUT) -#define RCU_FANOUT_SQ (RCU_FANOUT * RCU_FANOUT) -#define RCU_FANOUT_CUBE (RCU_FANOUT_SQ * RCU_FANOUT) - -#if NR_CPUS <= RCU_FANOUT -# define NUM_RCU_LVLS 1 -# define NUM_RCU_LVL_0 1 -# define NUM_RCU_LVL_1 (NR_CPUS) -# define NUM_RCU_LVL_2 0 -# define NUM_RCU_LVL_3 0 -#elif NR_CPUS <= RCU_FANOUT_SQ -# define NUM_RCU_LVLS 2 -# define NUM_RCU_LVL_0 1 -# define NUM_RCU_LVL_1 (((NR_CPUS) + RCU_FANOUT - 1) / RCU_FANOUT) -# define NUM_RCU_LVL_2 (NR_CPUS) -# define NUM_RCU_LVL_3 0 -#elif NR_CPUS <= RCU_FANOUT_CUBE -# define NUM_RCU_LVLS 3 -# define NUM_RCU_LVL_0 1 -# define NUM_RCU_LVL_1 (((NR_CPUS) + RCU_FANOUT_SQ - 1) / RCU_FANOUT_SQ) -# define NUM_RCU_LVL_2 (((NR_CPUS) + (RCU_FANOUT) - 1) / (RCU_FANOUT)) -# define NUM_RCU_LVL_3 NR_CPUS -#else -# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS" -#endif /* #if (NR_CPUS) <= RCU_FANOUT */ - -#define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3) -#define NUM_RCU_NODES (RCU_SUM - NR_CPUS) - -/* - * Dynticks per-CPU state. - */ -struct rcu_dynticks { - int dynticks_nesting; /* Track nesting level, sort of. */ - int dynticks; /* Even value for dynticks-idle, else odd. */ - int dynticks_nmi; /* Even value for either dynticks-idle or */ - /* not in nmi handler, else odd. So this */ - /* remains even for nmi from irq handler. */ -}; - -/* - * Definition for node within the RCU grace-period-detection hierarchy. - */ -struct rcu_node { - spinlock_t lock; - unsigned long qsmask; /* CPUs or groups that need to switch in */ - /* order for current grace period to proceed.*/ - unsigned long qsmaskinit; - /* Per-GP initialization for qsmask. */ - unsigned long grpmask; /* Mask to apply to parent qsmask. */ - int grplo; /* lowest-numbered CPU or group here. */ - int grphi; /* highest-numbered CPU or group here. */ - u8 grpnum; /* CPU/group number for next level up. */ - u8 level; /* root is at level 0. */ - struct rcu_node *parent; -} ____cacheline_internodealigned_in_smp; - -/* Index values for nxttail array in struct rcu_data. */ -#define RCU_DONE_TAIL 0 /* Also RCU_WAIT head. */ -#define RCU_WAIT_TAIL 1 /* Also RCU_NEXT_READY head. */ -#define RCU_NEXT_READY_TAIL 2 /* Also RCU_NEXT head. */ -#define RCU_NEXT_TAIL 3 -#define RCU_NEXT_SIZE 4 - -/* Per-CPU data for read-copy update. */ -struct rcu_data { - /* 1) quiescent-state and grace-period handling : */ - long completed; /* Track rsp->completed gp number */ - /* in order to detect GP end. */ - long gpnum; /* Highest gp number that this CPU */ - /* is aware of having started. */ - long passed_quiesc_completed; - /* Value of completed at time of qs. */ - bool passed_quiesc; /* User-mode/idle loop etc. */ - bool qs_pending; /* Core waits for quiesc state. */ - bool beenonline; /* CPU online at least once. */ - struct rcu_node *mynode; /* This CPU's leaf of hierarchy */ - unsigned long grpmask; /* Mask to apply to leaf qsmask. */ - - /* 2) batch handling */ - /* - * If nxtlist is not NULL, it is partitioned as follows. - * Any of the partitions might be empty, in which case the - * pointer to that partition will be equal to the pointer for - * the following partition. When the list is empty, all of - * the nxttail elements point to nxtlist, which is NULL. - * - * [*nxttail[RCU_NEXT_READY_TAIL], NULL = *nxttail[RCU_NEXT_TAIL]): - * Entries that might have arrived after current GP ended - * [*nxttail[RCU_WAIT_TAIL], *nxttail[RCU_NEXT_READY_TAIL]): - * Entries known to have arrived before current GP ended - * [*nxttail[RCU_DONE_TAIL], *nxttail[RCU_WAIT_TAIL]): - * Entries that batch # <= ->completed - 1: waiting for current GP - * [nxtlist, *nxttail[RCU_DONE_TAIL]): - * Entries that batch # <= ->completed - * The grace period for these entries has completed, and - * the other grace-period-completed entries may be moved - * here temporarily in rcu_process_callbacks(). - */ - struct rcu_head *nxtlist; - struct rcu_head **nxttail[RCU_NEXT_SIZE]; - long qlen; /* # of queued callbacks */ - long blimit; /* Upper limit on a processed batch */ - -#ifdef CONFIG_NO_HZ - /* 3) dynticks interface. */ - struct rcu_dynticks *dynticks; /* Shared per-CPU dynticks state. */ - int dynticks_snap; /* Per-GP tracking for dynticks. */ - int dynticks_nmi_snap; /* Per-GP tracking for dynticks_nmi. */ -#endif /* #ifdef CONFIG_NO_HZ */ - - /* 4) reasons this CPU needed to be kicked by force_quiescent_state */ -#ifdef CONFIG_NO_HZ - unsigned long dynticks_fqs; /* Kicked due to dynticks idle. */ -#endif /* #ifdef CONFIG_NO_HZ */ - unsigned long offline_fqs; /* Kicked due to being offline. */ - unsigned long resched_ipi; /* Sent a resched IPI. */ - - /* 5) __rcu_pending() statistics. */ - long n_rcu_pending; /* rcu_pending() calls since boot. */ - long n_rp_qs_pending; - long n_rp_cb_ready; - long n_rp_cpu_needs_gp; - long n_rp_gp_completed; - long n_rp_gp_started; - long n_rp_need_fqs; - long n_rp_need_nothing; - - int cpu; -}; - -/* Values for signaled field in struct rcu_state. */ -#define RCU_GP_INIT 0 /* Grace period being initialized. */ -#define RCU_SAVE_DYNTICK 1 /* Need to scan dyntick state. */ -#define RCU_FORCE_QS 2 /* Need to force quiescent state. */ -#ifdef CONFIG_NO_HZ -#define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK -#else /* #ifdef CONFIG_NO_HZ */ -#define RCU_SIGNAL_INIT RCU_FORCE_QS -#endif /* #else #ifdef CONFIG_NO_HZ */ - -#define RCU_JIFFIES_TILL_FORCE_QS 3 /* for rsp->jiffies_force_qs */ -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR -#define RCU_SECONDS_TILL_STALL_CHECK (10 * HZ) /* for rsp->jiffies_stall */ -#define RCU_SECONDS_TILL_STALL_RECHECK (30 * HZ) /* for rsp->jiffies_stall */ -#define RCU_STALL_RAT_DELAY 2 /* Allow other CPUs time */ - /* to take at least one */ - /* scheduling clock irq */ - /* before ratting on them. */ - -#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ - -/* - * RCU global state, including node hierarchy. This hierarchy is - * represented in "heap" form in a dense array. The root (first level) - * of the hierarchy is in ->node[0] (referenced by ->level[0]), the second - * level in ->node[1] through ->node[m] (->node[1] referenced by ->level[1]), - * and the third level in ->node[m+1] and following (->node[m+1] referenced - * by ->level[2]). The number of levels is determined by the number of - * CPUs and by CONFIG_RCU_FANOUT. Small systems will have a "hierarchy" - * consisting of a single rcu_node. - */ -struct rcu_state { - struct rcu_node node[NUM_RCU_NODES]; /* Hierarchy. */ - struct rcu_node *level[NUM_RCU_LVLS]; /* Hierarchy levels. */ - u32 levelcnt[MAX_RCU_LVLS + 1]; /* # nodes in each level. */ - u8 levelspread[NUM_RCU_LVLS]; /* kids/node in each level. */ - struct rcu_data *rda[NR_CPUS]; /* array of rdp pointers. */ - - /* The following fields are guarded by the root rcu_node's lock. */ - - u8 signaled ____cacheline_internodealigned_in_smp; - /* Force QS state. */ - long gpnum; /* Current gp number. */ - long completed; /* # of last completed gp. */ - spinlock_t onofflock; /* exclude on/offline and */ - /* starting new GP. */ - spinlock_t fqslock; /* Only one task forcing */ - /* quiescent states. */ - unsigned long jiffies_force_qs; /* Time at which to invoke */ - /* force_quiescent_state(). */ - unsigned long n_force_qs; /* Number of calls to */ - /* force_quiescent_state(). */ - unsigned long n_force_qs_lh; /* ~Number of calls leaving */ - /* due to lock unavailable. */ - unsigned long n_force_qs_ngp; /* Number of calls leaving */ - /* due to no GP active. */ -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR - unsigned long gp_start; /* Time at which GP started, */ - /* but in jiffies. */ - unsigned long jiffies_stall; /* Time at which to check */ - /* for CPU stalls. */ -#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ -#ifdef CONFIG_NO_HZ - long dynticks_completed; /* Value of completed @ snap. */ -#endif /* #ifdef CONFIG_NO_HZ */ -}; - extern void rcu_qsctr_inc(int cpu); extern void rcu_bh_qsctr_inc(int cpu); diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 75762cd..a162f85 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -46,6 +46,8 @@ #include #include +#include "rcutree.h" + #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key rcu_lock_key; struct lockdep_map rcu_lock_map = diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 5e872bb..7cc830a 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -1,3 +1,239 @@ +/* + * Read-Copy Update mechanism for mutual exclusion (tree-based version) + * Internal non-public definitions. + * + * 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, 2008 + * + * Author: Ingo Molnar + * Paul E. McKenney + */ + +#include +#include +#include +#include +#include + +/* + * Define shape of hierarchy based on NR_CPUS and CONFIG_RCU_FANOUT. + * In theory, it should be possible to add more levels straightforwardly. + * In practice, this has not been tested, so there is probably some + * bug somewhere. + */ +#define MAX_RCU_LVLS 3 +#define RCU_FANOUT (CONFIG_RCU_FANOUT) +#define RCU_FANOUT_SQ (RCU_FANOUT * RCU_FANOUT) +#define RCU_FANOUT_CUBE (RCU_FANOUT_SQ * RCU_FANOUT) + +#if NR_CPUS <= RCU_FANOUT +# define NUM_RCU_LVLS 1 +# define NUM_RCU_LVL_0 1 +# define NUM_RCU_LVL_1 (NR_CPUS) +# define NUM_RCU_LVL_2 0 +# define NUM_RCU_LVL_3 0 +#elif NR_CPUS <= RCU_FANOUT_SQ +# define NUM_RCU_LVLS 2 +# define NUM_RCU_LVL_0 1 +# define NUM_RCU_LVL_1 (((NR_CPUS) + RCU_FANOUT - 1) / RCU_FANOUT) +# define NUM_RCU_LVL_2 (NR_CPUS) +# define NUM_RCU_LVL_3 0 +#elif NR_CPUS <= RCU_FANOUT_CUBE +# define NUM_RCU_LVLS 3 +# define NUM_RCU_LVL_0 1 +# define NUM_RCU_LVL_1 (((NR_CPUS) + RCU_FANOUT_SQ - 1) / RCU_FANOUT_SQ) +# define NUM_RCU_LVL_2 (((NR_CPUS) + (RCU_FANOUT) - 1) / (RCU_FANOUT)) +# define NUM_RCU_LVL_3 NR_CPUS +#else +# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS" +#endif /* #if (NR_CPUS) <= RCU_FANOUT */ + +#define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3) +#define NUM_RCU_NODES (RCU_SUM - NR_CPUS) + +/* + * Dynticks per-CPU state. + */ +struct rcu_dynticks { + int dynticks_nesting; /* Track nesting level, sort of. */ + int dynticks; /* Even value for dynticks-idle, else odd. */ + int dynticks_nmi; /* Even value for either dynticks-idle or */ + /* not in nmi handler, else odd. So this */ + /* remains even for nmi from irq handler. */ +}; + +/* + * Definition for node within the RCU grace-period-detection hierarchy. + */ +struct rcu_node { + spinlock_t lock; + unsigned long qsmask; /* CPUs or groups that need to switch in */ + /* order for current grace period to proceed.*/ + unsigned long qsmaskinit; + /* Per-GP initialization for qsmask. */ + unsigned long grpmask; /* Mask to apply to parent qsmask. */ + int grplo; /* lowest-numbered CPU or group here. */ + int grphi; /* highest-numbered CPU or group here. */ + u8 grpnum; /* CPU/group number for next level up. */ + u8 level; /* root is at level 0. */ + struct rcu_node *parent; +} ____cacheline_internodealigned_in_smp; + +/* Index values for nxttail array in struct rcu_data. */ +#define RCU_DONE_TAIL 0 /* Also RCU_WAIT head. */ +#define RCU_WAIT_TAIL 1 /* Also RCU_NEXT_READY head. */ +#define RCU_NEXT_READY_TAIL 2 /* Also RCU_NEXT head. */ +#define RCU_NEXT_TAIL 3 +#define RCU_NEXT_SIZE 4 + +/* Per-CPU data for read-copy update. */ +struct rcu_data { + /* 1) quiescent-state and grace-period handling : */ + long completed; /* Track rsp->completed gp number */ + /* in order to detect GP end. */ + long gpnum; /* Highest gp number that this CPU */ + /* is aware of having started. */ + long passed_quiesc_completed; + /* Value of completed at time of qs. */ + bool passed_quiesc; /* User-mode/idle loop etc. */ + bool qs_pending; /* Core waits for quiesc state. */ + bool beenonline; /* CPU online at least once. */ + struct rcu_node *mynode; /* This CPU's leaf of hierarchy */ + unsigned long grpmask; /* Mask to apply to leaf qsmask. */ + + /* 2) batch handling */ + /* + * If nxtlist is not NULL, it is partitioned as follows. + * Any of the partitions might be empty, in which case the + * pointer to that partition will be equal to the pointer for + * the following partition. When the list is empty, all of + * the nxttail elements point to nxtlist, which is NULL. + * + * [*nxttail[RCU_NEXT_READY_TAIL], NULL = *nxttail[RCU_NEXT_TAIL]): + * Entries that might have arrived after current GP ended + * [*nxttail[RCU_WAIT_TAIL], *nxttail[RCU_NEXT_READY_TAIL]): + * Entries known to have arrived before current GP ended + * [*nxttail[RCU_DONE_TAIL], *nxttail[RCU_WAIT_TAIL]): + * Entries that batch # <= ->completed - 1: waiting for current GP + * [nxtlist, *nxttail[RCU_DONE_TAIL]): + * Entries that batch # <= ->completed + * The grace period for these entries has completed, and + * the other grace-period-completed entries may be moved + * here temporarily in rcu_process_callbacks(). + */ + struct rcu_head *nxtlist; + struct rcu_head **nxttail[RCU_NEXT_SIZE]; + long qlen; /* # of queued callbacks */ + long blimit; /* Upper limit on a processed batch */ + +#ifdef CONFIG_NO_HZ + /* 3) dynticks interface. */ + struct rcu_dynticks *dynticks; /* Shared per-CPU dynticks state. */ + int dynticks_snap; /* Per-GP tracking for dynticks. */ + int dynticks_nmi_snap; /* Per-GP tracking for dynticks_nmi. */ +#endif /* #ifdef CONFIG_NO_HZ */ + + /* 4) reasons this CPU needed to be kicked by force_quiescent_state */ +#ifdef CONFIG_NO_HZ + unsigned long dynticks_fqs; /* Kicked due to dynticks idle. */ +#endif /* #ifdef CONFIG_NO_HZ */ + unsigned long offline_fqs; /* Kicked due to being offline. */ + unsigned long resched_ipi; /* Sent a resched IPI. */ + + /* 5) __rcu_pending() statistics. */ + long n_rcu_pending; /* rcu_pending() calls since boot. */ + long n_rp_qs_pending; + long n_rp_cb_ready; + long n_rp_cpu_needs_gp; + long n_rp_gp_completed; + long n_rp_gp_started; + long n_rp_need_fqs; + long n_rp_need_nothing; + + int cpu; +}; + +/* Values for signaled field in struct rcu_state. */ +#define RCU_GP_INIT 0 /* Grace period being initialized. */ +#define RCU_SAVE_DYNTICK 1 /* Need to scan dyntick state. */ +#define RCU_FORCE_QS 2 /* Need to force quiescent state. */ +#ifdef CONFIG_NO_HZ +#define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK +#else /* #ifdef CONFIG_NO_HZ */ +#define RCU_SIGNAL_INIT RCU_FORCE_QS +#endif /* #else #ifdef CONFIG_NO_HZ */ + +#define RCU_JIFFIES_TILL_FORCE_QS 3 /* for rsp->jiffies_force_qs */ +#ifdef CONFIG_RCU_CPU_STALL_DETECTOR +#define RCU_SECONDS_TILL_STALL_CHECK (10 * HZ) /* for rsp->jiffies_stall */ +#define RCU_SECONDS_TILL_STALL_RECHECK (30 * HZ) /* for rsp->jiffies_stall */ +#define RCU_STALL_RAT_DELAY 2 /* Allow other CPUs time */ + /* to take at least one */ + /* scheduling clock irq */ + /* before ratting on them. */ + +#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ + +/* + * RCU global state, including node hierarchy. This hierarchy is + * represented in "heap" form in a dense array. The root (first level) + * of the hierarchy is in ->node[0] (referenced by ->level[0]), the second + * level in ->node[1] through ->node[m] (->node[1] referenced by ->level[1]), + * and the third level in ->node[m+1] and following (->node[m+1] referenced + * by ->level[2]). The number of levels is determined by the number of + * CPUs and by CONFIG_RCU_FANOUT. Small systems will have a "hierarchy" + * consisting of a single rcu_node. + */ +struct rcu_state { + struct rcu_node node[NUM_RCU_NODES]; /* Hierarchy. */ + struct rcu_node *level[NUM_RCU_LVLS]; /* Hierarchy levels. */ + u32 levelcnt[MAX_RCU_LVLS + 1]; /* # nodes in each level. */ + u8 levelspread[NUM_RCU_LVLS]; /* kids/node in each level. */ + struct rcu_data *rda[NR_CPUS]; /* array of rdp pointers. */ + + /* The following fields are guarded by the root rcu_node's lock. */ + + u8 signaled ____cacheline_internodealigned_in_smp; + /* Force QS state. */ + long gpnum; /* Current gp number. */ + long completed; /* # of last completed gp. */ + spinlock_t onofflock; /* exclude on/offline and */ + /* starting new GP. */ + spinlock_t fqslock; /* Only one task forcing */ + /* quiescent states. */ + unsigned long jiffies_force_qs; /* Time at which to invoke */ + /* force_quiescent_state(). */ + unsigned long n_force_qs; /* Number of calls to */ + /* force_quiescent_state(). */ + unsigned long n_force_qs_lh; /* ~Number of calls leaving */ + /* due to lock unavailable. */ + unsigned long n_force_qs_ngp; /* Number of calls leaving */ + /* due to no GP active. */ +#ifdef CONFIG_RCU_CPU_STALL_DETECTOR + unsigned long gp_start; /* Time at which GP started, */ + /* but in jiffies. */ + unsigned long jiffies_stall; /* Time at which to check */ + /* for CPU stalls. */ +#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ +#ifdef CONFIG_NO_HZ + long dynticks_completed; /* Value of completed @ snap. */ +#endif /* #ifdef CONFIG_NO_HZ */ +}; + +#ifdef RCU_TREE_NONCORE /* * RCU implementation internal declarations: @@ -8,3 +244,5 @@ DECLARE_PER_CPU(struct rcu_data, rcu_data); extern struct rcu_state rcu_bh_state; DECLARE_PER_CPU(struct rcu_data, rcu_bh_data); +#endif /* #ifdef RCU_TREE_NONCORE */ + diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index fe1dcdb..0cb52b8 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -43,6 +43,7 @@ #include #include +#define RCU_TREE_NONCORE #include "rcutree.h" static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) -- cgit v0.10.2 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 diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 02cced1..187bbf1 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 3c89d6a..e920f0f 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 f164ac9..2963f08 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 e37d5e2..a0852d0 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 510898a..7d777c9 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 a162f85..4d71d4e 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; @@ -114,11 +113,21 @@ 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 7cc830a..0024e5d 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 0cb52b8..236c050 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 cda8b81..c9beca6 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 eb5e131..7db2506 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 v0.10.2 From bc33f24bdca8b6e97376e3a182ab69e6cdefa989 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 22 Aug 2009 13:56:47 -0700 Subject: rcu: Consolidate sparse and lockdep declarations in include/linux/rcupdate.h 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: <12509746132349-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index e920f0f..9d85ee1 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -80,6 +80,16 @@ extern int rcu_scheduler_active; (ptr)->next = NULL; (ptr)->func = NULL; \ } while (0) +#ifdef CONFIG_DEBUG_LOCK_ALLOC +extern struct lockdep_map rcu_lock_map; +# define rcu_read_acquire() \ + lock_acquire(&rcu_lock_map, 0, 0, 2, 1, NULL, _THIS_IP_) +# define rcu_read_release() lock_release(&rcu_lock_map, 1, _THIS_IP_) +#else +# define rcu_read_acquire() do { } while (0) +# define rcu_read_release() do { } while (0) +#endif + /** * rcu_read_lock - mark the beginning of an RCU read-side critical section. * @@ -109,7 +119,12 @@ extern int rcu_scheduler_active; * * It is illegal to block while in an RCU read-side critical section. */ -#define rcu_read_lock() __rcu_read_lock() +static inline void rcu_read_lock(void) +{ + __rcu_read_lock(); + __acquire(RCU); + rcu_read_acquire(); +} /** * rcu_read_unlock - marks the end of an RCU read-side critical section. @@ -126,7 +141,12 @@ extern int rcu_scheduler_active; * used as well. RCU does not care how the writers keep out of each * others' way, as long as they do so. */ -#define rcu_read_unlock() __rcu_read_unlock() +static inline void rcu_read_unlock(void) +{ + rcu_read_release(); + __release(RCU); + __rcu_read_unlock(); +} /** * rcu_read_lock_bh - mark the beginning of a softirq-only RCU critical section @@ -139,14 +159,24 @@ extern int rcu_scheduler_active; * can use just rcu_read_lock(). * */ -#define rcu_read_lock_bh() __rcu_read_lock_bh() +static inline void rcu_read_lock_bh(void) +{ + __rcu_read_lock_bh(); + __acquire(RCU_BH); + rcu_read_acquire(); +} /* * rcu_read_unlock_bh - marks the end of a softirq-only RCU critical section * * See rcu_read_lock_bh() for more information. */ -#define rcu_read_unlock_bh() __rcu_read_unlock_bh() +static inline void rcu_read_unlock_bh(void) +{ + rcu_read_release(); + __release(RCU_BH); + __rcu_read_unlock_bh(); +} /** * rcu_read_lock_sched - mark the beginning of a RCU-classic critical section @@ -160,10 +190,14 @@ extern int rcu_scheduler_active; static inline void rcu_read_lock_sched(void) { preempt_disable(); + __acquire(RCU_SCHED); + rcu_read_acquire(); } static inline void rcu_read_lock_sched_notrace(void) { preempt_disable_notrace(); + __acquire(RCU_SCHED); + rcu_read_acquire(); } /* @@ -173,10 +207,14 @@ static inline void rcu_read_lock_sched_notrace(void) */ static inline void rcu_read_unlock_sched(void) { + rcu_read_release(); + __release(RCU_SCHED); preempt_enable(); } static inline void rcu_read_unlock_sched_notrace(void) { + rcu_read_release(); + __release(RCU_SCHED); preempt_enable_notrace(); } diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h index 2963f08..6c9dd9c 100644 --- a/include/linux/rcupreempt.h +++ b/include/linux/rcupreempt.h @@ -64,8 +64,8 @@ static inline void rcu_bh_qs(int cpu) { } extern void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *head)); -extern void __rcu_read_lock(void) __acquires(RCU); -extern void __rcu_read_unlock(void) __releases(RCU); +extern void __rcu_read_lock(void); +extern void __rcu_read_unlock(void); extern int rcu_pending(int cpu); extern int rcu_needs_cpu(int cpu); diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index a0852d0..8a0222c 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -36,38 +36,20 @@ extern void rcu_bh_qs(int cpu); extern int rcu_pending(int cpu); extern int rcu_needs_cpu(int cpu); -#ifdef CONFIG_DEBUG_LOCK_ALLOC -extern struct lockdep_map rcu_lock_map; -# define rcu_read_acquire() \ - lock_acquire(&rcu_lock_map, 0, 0, 2, 1, NULL, _THIS_IP_) -# define rcu_read_release() lock_release(&rcu_lock_map, 1, _THIS_IP_) -#else -# define rcu_read_acquire() do { } while (0) -# define rcu_read_release() do { } while (0) -#endif - static inline void __rcu_read_lock(void) { preempt_disable(); - __acquire(RCU); - rcu_read_acquire(); } static inline void __rcu_read_unlock(void) { - rcu_read_release(); - __release(RCU); preempt_enable(); } static inline void __rcu_read_lock_bh(void) { local_bh_disable(); - __acquire(RCU_BH); - rcu_read_acquire(); } static inline void __rcu_read_unlock_bh(void) { - rcu_read_release(); - __release(RCU_BH); local_bh_enable(); } -- cgit v0.10.2 From 5699ed8fcb0c32ca699e2a27ad716eb70b367dbf Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 22 Aug 2009 13:56:48 -0700 Subject: rcu: Fix online/offline indication for rcudata.csv trace file The heading said "Online?", but the column had "Y" for offline CPUs and "N" for online CPUs. Swap the "Y" and "N" to match the heading. 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: <12509746132841-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 236c050..ea4a474 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -103,7 +103,7 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp) return; seq_printf(m, "%d,%s,%ld,%ld,%d,%ld,%d", rdp->cpu, - cpu_is_offline(rdp->cpu) ? "\"Y\"" : "\"N\"", + cpu_is_offline(rdp->cpu) ? "\"N\"" : "\"Y\"", rdp->completed, rdp->gpnum, rdp->passed_quiesc, rdp->passed_quiesc_completed, rdp->qs_pending); -- cgit v0.10.2 From 65cf8f866fc0fb40fa9daaded7e938a886d6f7c5 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 22 Aug 2009 13:56:49 -0700 Subject: rcu: Merge per-RCU-flavor initialization into pre-existing macro Rename the RCU_DATA_PTR_INIT() macro to RCU_INIT_FLAVOR() and make it do the rcu_init_one() and rcu_boot_init_percpu_data() calls. Merge the loop that was in the original macro with the loops that were in __rcu_init(). 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: <12509746133916-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 4d71d4e..7c51508 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1543,8 +1543,9 @@ static void __init rcu_init_one(struct rcu_state *rsp) * Helper macro for __rcu_init(). To be used nowhere else! * Assigns leaf node pointers into each CPU's rcu_data structure. */ -#define RCU_DATA_PTR_INIT(rsp, rcu_data) \ +#define RCU_INIT_FLAVOR(rsp, rcu_data) \ do { \ + rcu_init_one(rsp); \ rnp = (rsp)->level[NUM_RCU_LVLS - 1]; \ j = 0; \ for_each_possible_cpu(i) { \ @@ -1552,6 +1553,7 @@ do { \ j++; \ per_cpu(rcu_data, i).mynode = &rnp[j]; \ (rsp)->rda[i] = &per_cpu(rcu_data, i); \ + rcu_boot_init_percpu_data(i, rsp); \ } \ } while (0) @@ -1565,14 +1567,8 @@ 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_sched_state); - RCU_DATA_PTR_INIT(&rcu_sched_state, rcu_sched_data); - for_each_possible_cpu(i) - 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) - rcu_boot_init_percpu_data(i, &rcu_bh_state); + RCU_INIT_FLAVOR(&rcu_sched_state, rcu_sched_data); + RCU_INIT_FLAVOR(&rcu_bh_state, rcu_bh_data); open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); } -- cgit v0.10.2 From 22f00b69f6a7e1e18e821979a23e8307c2de9888 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 22 Aug 2009 13:56:50 -0700 Subject: rcu: Use debugfs_remove_recursive() simplify code. Suggested by Josh Triplett. 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 Cc: "Paul E. McKenney" LKML-Reference: <12509746132173-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index ea4a474..31af3a0 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -265,62 +265,47 @@ static struct file_operations rcu_pending_fops = { }; static struct dentry *rcudir; -static struct dentry *datadir; -static struct dentry *datadir_csv; -static struct dentry *gpdir; -static struct dentry *hierdir; -static struct dentry *rcu_pendingdir; static int __init rcuclassic_trace_init(void) { + struct dentry *retval; + rcudir = debugfs_create_dir("rcu", NULL); if (!rcudir) - goto out; + goto free_out; - datadir = debugfs_create_file("rcudata", 0444, rcudir, + retval = debugfs_create_file("rcudata", 0444, rcudir, NULL, &rcudata_fops); - if (!datadir) + if (!retval) goto free_out; - datadir_csv = debugfs_create_file("rcudata.csv", 0444, rcudir, + retval = debugfs_create_file("rcudata.csv", 0444, rcudir, NULL, &rcudata_csv_fops); - if (!datadir_csv) + if (!retval) goto free_out; - gpdir = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops); - if (!gpdir) + retval = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops); + if (!retval) goto free_out; - hierdir = debugfs_create_file("rcuhier", 0444, rcudir, + retval = debugfs_create_file("rcuhier", 0444, rcudir, NULL, &rcuhier_fops); - if (!hierdir) + if (!retval) goto free_out; - rcu_pendingdir = debugfs_create_file("rcu_pending", 0444, rcudir, + retval = debugfs_create_file("rcu_pending", 0444, rcudir, NULL, &rcu_pending_fops); - if (!rcu_pendingdir) + if (!retval) goto free_out; return 0; free_out: - if (datadir) - debugfs_remove(datadir); - if (datadir_csv) - debugfs_remove(datadir_csv); - if (gpdir) - debugfs_remove(gpdir); - debugfs_remove(rcudir); -out: + debugfs_remove_recursive(rcudir); return 1; } static void __exit rcuclassic_trace_cleanup(void) { - debugfs_remove(datadir); - debugfs_remove(datadir_csv); - debugfs_remove(gpdir); - debugfs_remove(hierdir); - debugfs_remove(rcu_pendingdir); - debugfs_remove(rcudir); + debugfs_remove_recursive(rcudir); } -- cgit v0.10.2 From a157229cabd6dd8cfa82525fc9bf730c94cc9ac2 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 22 Aug 2009 13:56:51 -0700 Subject: rcu: Simplify rcu_pending()/rcu_check_callbacks() API All calls from outside RCU are of the form: if (rcu_pending(cpu)) rcu_check_callbacks(cpu, user); This is silly, instead we put a call to rcu_pending() in rcu_check_callbacks(), and then make the outside calls be to rcu_check_callbacks(). This cuts down on the code a bit and also gives the compiler a better chance of optimizing. 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: <125097461311-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/arch/ia64/xen/time.c b/arch/ia64/xen/time.c index fb83326..dbeadb9 100644 --- a/arch/ia64/xen/time.c +++ b/arch/ia64/xen/time.c @@ -133,8 +133,7 @@ consider_steal_time(unsigned long new_itm) account_idle_ticks(blocked); run_local_timers(); - if (rcu_pending(cpu)) - rcu_check_callbacks(cpu, user_mode(get_irq_regs())); + rcu_check_callbacks(cpu, user_mode(get_irq_regs())); scheduler_tick(); run_posix_cpu_timers(p); diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h index 6c9dd9c..aff4772 100644 --- a/include/linux/rcupreempt.h +++ b/include/linux/rcupreempt.h @@ -66,7 +66,6 @@ extern void call_rcu_sched(struct rcu_head *head, extern void __rcu_read_lock(void); extern void __rcu_read_unlock(void); -extern int rcu_pending(int cpu); extern int rcu_needs_cpu(int cpu); #define __rcu_read_lock_bh() { rcu_read_lock(); local_bh_disable(); } diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 8a0222c..c739d90 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -33,7 +33,6 @@ 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); static inline void __rcu_read_lock(void) diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c index 7d777c9..0053ce5 100644 --- a/kernel/rcupreempt.c +++ b/kernel/rcupreempt.c @@ -159,6 +159,8 @@ 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); @@ -961,7 +963,10 @@ static void rcu_check_mb(int cpu) void rcu_check_callbacks(int cpu, int user) { unsigned long flags; - struct rcu_data *rdp = RCU_DATA_CPU(cpu); + 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 @@ -976,6 +981,7 @@ void rcu_check_callbacks(int cpu, int user) * CPUs to happen after any such write. */ + rdp = RCU_DATA_CPU(cpu); if (user || (idle_cpu(cpu) && !in_softirq() && hardirq_count() <= (1 << HARDIRQ_SHIFT))) { @@ -1382,7 +1388,7 @@ int rcu_needs_cpu(int cpu) rdp->waitschedlist != NULL); } -int rcu_pending(int cpu) +static int rcu_pending(int cpu) { struct rcu_data *rdp = RCU_DATA_CPU(cpu); diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 7c51508..4ce3adc 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -111,6 +111,7 @@ static int qhimark = 10000; /* If this many pending, ignore blimit. */ static int qlowmark = 100; /* Once only this many pending, use blimit. */ static void force_quiescent_state(struct rcu_state *rsp, int relaxed); +static int rcu_pending(int cpu); /* * Return the number of RCU-sched batches processed thus far for debug & stats. @@ -974,6 +975,8 @@ static void rcu_do_batch(struct rcu_data *rdp) */ void rcu_check_callbacks(int cpu, int user) { + if (!rcu_pending(cpu)) + return; /* if nothing for RCU to do. */ if (user || (idle_cpu(cpu) && rcu_scheduler_active && !in_softirq() && hardirq_count() <= (1 << HARDIRQ_SHIFT))) { @@ -1329,7 +1332,7 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) * by the current CPU, returning 1 if so. This function is part of the * RCU implementation; it is -not- an exported member of the RCU API. */ -int rcu_pending(int cpu) +static int rcu_pending(int cpu) { return __rcu_pending(&rcu_sched_state, &per_cpu(rcu_sched_data, cpu)) || __rcu_pending(&rcu_bh_state, &per_cpu(rcu_bh_data, cpu)); diff --git a/kernel/timer.c b/kernel/timer.c index a7f07d5..a3d25f415 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1156,8 +1156,7 @@ void update_process_times(int user_tick) /* Note: this timer irq context must be accounted for as well. */ account_process_tick(p, user_tick); run_local_timers(); - if (rcu_pending(cpu)) - rcu_check_callbacks(cpu, user_tick); + rcu_check_callbacks(cpu, user_tick); printk_tick(); scheduler_tick(); run_posix_cpu_timers(p); -- cgit v0.10.2 From f41d911f8c49a5d65c86504c19e8204bb605c4fd Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 22 Aug 2009 13:56:52 -0700 Subject: rcu: Merge preemptable-RCU functionality into hierarchical RCU Create a kernel/rcutree_plugin.h file that contains definitions for preemptable RCU (or, under the #else branch of the #ifdef, empty definitions for the classic non-preemptable semantics). These definitions fit into plugins defined in kernel/rcutree.c for this purpose. This variant of preemptable RCU uses a new algorithm whose read-side expense is roughly that of classic hierarchical RCU under CONFIG_PREEMPT. This new algorithm's update-side expense is similar to that of classic hierarchical RCU, and, in absence of read-side preemption or blocking, is exactly that of classic hierarchical RCU. Perhaps more important, this new algorithm has a much simpler implementation, saving well over 1,000 lines of code compared to mainline's implementation of preemptable RCU, which will hopefully be retired in favor of this new algorithm. The simplifications are obtained by maintaining per-task nesting state for running tasks, and using a simple lock-protected algorithm to handle accounting when tasks block within RCU read-side critical sections, making use of lessons learned while creating numerous user-level RCU implementations over the past 18 months. 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: <12509746134003-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 7fc01b1..971a968 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -94,6 +94,20 @@ 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) +#define INIT_TASK_RCU_PREEMPT(tsk) \ + .rcu_read_lock_nesting = 0, \ + .rcu_read_unlock_special = 0, \ + .rcu_blocked_cpu = -1, \ + .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry), +#else +#define INIT_TASK_RCU_PREEMPT(tsk) +#endif + extern struct cred init_cred; #ifdef CONFIG_PERF_COUNTERS @@ -173,6 +187,7 @@ extern struct cred init_cred; INIT_LOCKDEP \ INIT_FTRACE_GRAPH \ INIT_TRACE_RECURSION \ + INIT_TASK_RCU_PREEMPT(tsk) \ } diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 9d85ee1..26892f5 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -66,7 +66,7 @@ extern void rcu_scheduler_starting(void); extern int rcu_needs_cpu(int cpu); extern int rcu_scheduler_active; -#if defined(CONFIG_TREE_RCU) +#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) #include #elif defined(CONFIG_PREEMPT_RCU) #include diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h index aff4772..a42ab88 100644 --- a/include/linux/rcupreempt.h +++ b/include/linux/rcupreempt.h @@ -98,6 +98,10 @@ 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); diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index c739d90..a893077 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -35,14 +35,30 @@ extern void rcu_bh_qs(int cpu); extern int rcu_needs_cpu(int cpu); +#ifdef CONFIG_TREE_PREEMPT_RCU + +extern void __rcu_read_lock(void); +extern void __rcu_read_unlock(void); +extern void exit_rcu(void); + +#else /* #ifdef CONFIG_TREE_PREEMPT_RCU */ + static inline void __rcu_read_lock(void) { preempt_disable(); } + static inline void __rcu_read_unlock(void) { preempt_enable(); } + +static inline void exit_rcu(void) +{ +} + +#endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */ + static inline void __rcu_read_lock_bh(void) { local_bh_disable(); diff --git a/include/linux/sched.h b/include/linux/sched.h index 3ab08e4..d7f98f6 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1210,6 +1210,13 @@ struct task_struct { int rcu_flipctr_idx; #endif /* #ifdef CONFIG_PREEMPT_RCU */ +#ifdef CONFIG_TREE_PREEMPT_RCU + int rcu_read_lock_nesting; + char rcu_read_unlock_special; + int rcu_blocked_cpu; + struct list_head rcu_node_entry; +#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ + #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) struct sched_info sched_info; #endif @@ -1723,6 +1730,36 @@ extern cputime_t task_gtime(struct task_struct *p); #define tsk_used_math(p) ((p)->flags & PF_USED_MATH) #define used_math() tsk_used_math(current) +#ifdef CONFIG_TREE_PREEMPT_RCU + +#define RCU_READ_UNLOCK_BLOCKED (1 << 0) /* blocked while in RCU read-side. */ +#define RCU_READ_UNLOCK_NEED_QS (1 << 1) /* RCU core needs CPU response. */ +#define RCU_READ_UNLOCK_GOT_QS (1 << 2) /* CPU has responded to RCU core. */ + +static inline void rcu_copy_process(struct task_struct *p) +{ + p->rcu_read_lock_nesting = 0; + p->rcu_read_unlock_special = 0; + p->rcu_blocked_cpu = -1; + 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) +{ +} + +#endif + #ifdef CONFIG_SMP extern int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask); diff --git a/init/Kconfig b/init/Kconfig index 25373cf..f88da2d 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -335,11 +335,20 @@ config PREEMPT_RCU 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 + help + This option selects the RCU implementation that is + designed for very large SMP systems with hundreds or + thousands of CPUs, but for which real-time response + is also required. + endchoice config RCU_TRACE bool "Enable tracing for RCU" - depends on TREE_RCU || PREEMPT_RCU + depends on TREE_RCU || PREEMPT_RCU || TREE_PREEMPT_RCU help This option provides tracing in RCU which presents stats in debugfs for debugging RCU implementation. @@ -351,7 +360,7 @@ config RCU_FANOUT int "Tree-based hierarchical RCU fanout value" range 2 64 if 64BIT range 2 32 if !64BIT - depends on TREE_RCU + depends on TREE_RCU || TREE_PREEMPT_RCU default 64 if 64BIT default 32 if !64BIT help @@ -366,7 +375,7 @@ config RCU_FANOUT config RCU_FANOUT_EXACT bool "Disable tree-based hierarchical RCU auto-balancing" - depends on TREE_RCU + depends on TREE_RCU || TREE_PREEMPT_RCU default n help This option forces use of the exact RCU_FANOUT value specified, @@ -379,11 +388,12 @@ config RCU_FANOUT_EXACT Say N if unsure. config TREE_RCU_TRACE - def_bool RCU_TRACE && TREE_RCU + def_bool RCU_TRACE && ( TREE_RCU || TREE_PREEMPT_RCU ) select DEBUG_FS help - This option provides tracing for the TREE_RCU implementation, - permitting Makefile to trivially select kernel/rcutree_trace.c. + This option provides tracing for the TREE_RCU and + TREE_PREEMPT_RCU implementations, permitting Makefile to + trivially select kernel/rcutree_trace.c. config PREEMPT_RCU_TRACE def_bool RCU_TRACE && PREEMPT_RCU diff --git a/kernel/Makefile b/kernel/Makefile index 2419c9d..1a38b47 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -81,6 +81,7 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ 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 diff --git a/kernel/exit.c b/kernel/exit.c index 869dc22..263f95e 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1010,6 +1010,7 @@ NORET_TYPE void do_exit(long code) __free_pipe_info(tsk->splice_pipe); preempt_disable(); + exit_rcu(); /* causes final put_task_struct in finish_task_switch(). */ tsk->state = TASK_DEAD; schedule(); diff --git a/kernel/fork.c b/kernel/fork.c index 021e113..642e8b5 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1022,10 +1022,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, copy_flags(clone_flags, p); INIT_LIST_HEAD(&p->children); INIT_LIST_HEAD(&p->sibling); -#ifdef CONFIG_PREEMPT_RCU - p->rcu_read_lock_nesting = 0; - p->rcu_flipctr_idx = 0; -#endif /* #ifdef CONFIG_PREEMPT_RCU */ + rcu_copy_process(p); p->vfork_done = NULL; spin_lock_init(&p->alloc_lock); diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 4ce3adc..cc02557 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -80,6 +80,21 @@ 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); +extern long rcu_batches_completed_sched(void); +static void cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, + struct rcu_node *rnp, unsigned long flags); +static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags); +static void __rcu_process_callbacks(struct rcu_state *rsp, + struct rcu_data *rdp); +static void __call_rcu(struct rcu_head *head, + void (*func)(struct rcu_head *rcu), + struct rcu_state *rsp); +static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp); +static void __cpuinit rcu_init_percpu_data(int cpu, struct rcu_state *rsp, + int preemptable); + +#include "rcutree_plugin.h" + /* * Note a quiescent state. Because we do not need to know * how many quiescent states passed, just if there was at least @@ -87,16 +102,27 @@ DEFINE_PER_CPU(struct rcu_data, rcu_bh_data); */ void rcu_sched_qs(int cpu) { - struct rcu_data *rdp = &per_cpu(rcu_sched_data, cpu); + unsigned long flags; + struct rcu_data *rdp; + + local_irq_save(flags); + rdp = &per_cpu(rcu_sched_data, cpu); rdp->passed_quiesc = 1; rdp->passed_quiesc_completed = rdp->completed; + rcu_preempt_qs(cpu); + local_irq_restore(flags); } void rcu_bh_qs(int cpu) { - struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu); + unsigned long flags; + struct rcu_data *rdp; + + local_irq_save(flags); + rdp = &per_cpu(rcu_bh_data, cpu); rdp->passed_quiesc = 1; rdp->passed_quiesc_completed = rdp->completed; + local_irq_restore(flags); } #ifdef CONFIG_NO_HZ @@ -123,16 +149,6 @@ long rcu_batches_completed_sched(void) 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_batches_completed_sched(); -} -EXPORT_SYMBOL_GPL(rcu_batches_completed); - -/* * Return the number of RCU BH batches processed thus far for debug & stats. */ long rcu_batches_completed_bh(void) @@ -193,6 +209,10 @@ static int rcu_implicit_offline_qs(struct rcu_data *rdp) return 1; } + /* If preemptable RCU, no point in sending reschedule IPI. */ + if (rdp->preemptable) + return 0; + /* The CPU is online, so send it a reschedule IPI. */ if (rdp->cpu != smp_processor_id()) smp_send_reschedule(rdp->cpu); @@ -473,6 +493,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp) printk(KERN_ERR "INFO: RCU detected CPU stalls:"); for (; rnp_cur < rnp_end; rnp_cur++) { + rcu_print_task_stall(rnp); if (rnp_cur->qsmask == 0) continue; for (cpu = 0; cpu <= rnp_cur->grphi - rnp_cur->grplo; cpu++) @@ -686,6 +707,19 @@ rcu_process_gp_end(struct rcu_state *rsp, struct rcu_data *rdp) } /* + * Clean up after the prior grace period and let rcu_start_gp() start up + * the next grace period if one is needed. Note that the caller must + * hold rnp->lock, as required by rcu_start_gp(), which will release it. + */ +static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags) + __releases(rnp->lock) +{ + rsp->completed = rsp->gpnum; + rcu_process_gp_end(rsp, rsp->rda[smp_processor_id()]); + rcu_start_gp(rsp, flags); /* releases root node's rnp->lock. */ +} + +/* * Similar to cpu_quiet(), for which it is a helper function. Allows * a group of CPUs to be quieted at one go, though all the CPUs in the * group must be represented by the same leaf rcu_node structure. @@ -706,7 +740,7 @@ cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, struct rcu_node *rnp, return; } rnp->qsmask &= ~mask; - if (rnp->qsmask != 0) { + if (rnp->qsmask != 0 || rcu_preempted_readers(rnp)) { /* Other bits still set at this level, so done. */ spin_unlock_irqrestore(&rnp->lock, flags); @@ -726,14 +760,10 @@ cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, struct rcu_node *rnp, /* * Get here if we are the last CPU to pass through a quiescent - * state for this grace period. Clean up and let rcu_start_gp() - * start up the next grace period if one is needed. Note that - * we still hold rnp->lock, as required by rcu_start_gp(), which - * will release it. + * state for this grace period. Invoke cpu_quiet_msk_finish() + * to clean up and start the next grace period if one is needed. */ - rsp->completed = rsp->gpnum; - rcu_process_gp_end(rsp, rsp->rda[smp_processor_id()]); - rcu_start_gp(rsp, flags); /* releases rnp->lock. */ + cpu_quiet_msk_finish(rsp, flags); /* releases rnp->lock. */ } /* @@ -840,11 +870,11 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) spin_lock(&rnp->lock); /* irqs already disabled. */ rnp->qsmaskinit &= ~mask; if (rnp->qsmaskinit != 0) { - spin_unlock(&rnp->lock); /* irqs already disabled. */ + spin_unlock(&rnp->lock); /* irqs remain disabled. */ break; } mask = rnp->grpmask; - spin_unlock(&rnp->lock); /* irqs already disabled. */ + spin_unlock(&rnp->lock); /* irqs remain disabled. */ rnp = rnp->parent; } while (rnp != NULL); lastcomp = rsp->completed; @@ -1007,6 +1037,7 @@ void rcu_check_callbacks(int cpu, int user) rcu_bh_qs(cpu); } + rcu_preempt_check_callbacks(cpu); raise_softirq(RCU_SOFTIRQ); } @@ -1188,6 +1219,7 @@ static void rcu_process_callbacks(struct softirq_action *unused) __rcu_process_callbacks(&rcu_sched_state, &__get_cpu_var(rcu_sched_data)); __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data)); + rcu_preempt_process_callbacks(); /* * Memory references from any later RCU read-side critical sections @@ -1252,17 +1284,6 @@ void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) 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_sched(head, func); -} -EXPORT_SYMBOL_GPL(call_rcu); - - -/* * Queue an RCU for invocation after a quicker grace period. */ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) @@ -1335,7 +1356,8 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) static int rcu_pending(int cpu) { return __rcu_pending(&rcu_sched_state, &per_cpu(rcu_sched_data, cpu)) || - __rcu_pending(&rcu_bh_state, &per_cpu(rcu_bh_data, cpu)); + __rcu_pending(&rcu_bh_state, &per_cpu(rcu_bh_data, cpu)) || + rcu_preempt_pending(cpu); } /* @@ -1348,7 +1370,8 @@ int rcu_needs_cpu(int cpu) { /* RCU callbacks either ready or pending? */ return per_cpu(rcu_sched_data, cpu).nxtlist || - per_cpu(rcu_bh_data, cpu).nxtlist; + per_cpu(rcu_bh_data, cpu).nxtlist || + rcu_preempt_needs_cpu(cpu); } /* @@ -1383,7 +1406,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp) * that this CPU cannot possibly have any RCU callbacks in flight yet. */ static void __cpuinit -rcu_init_percpu_data(int cpu, struct rcu_state *rsp) +rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable) { unsigned long flags; long lastcomp; @@ -1399,6 +1422,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp) rdp->passed_quiesc = 0; /* We could be racing with new GP, */ rdp->qs_pending = 1; /* so set up to respond to current GP. */ rdp->beenonline = 1; /* We have now been online. */ + rdp->preemptable = preemptable; rdp->passed_quiesc_completed = lastcomp - 1; rdp->blimit = blimit; spin_unlock(&rnp->lock); /* irqs remain disabled. */ @@ -1441,12 +1465,13 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp) static void __cpuinit rcu_online_cpu(int cpu) { - rcu_init_percpu_data(cpu, &rcu_sched_state); - rcu_init_percpu_data(cpu, &rcu_bh_state); + rcu_init_percpu_data(cpu, &rcu_sched_state, 0); + rcu_init_percpu_data(cpu, &rcu_bh_state, 0); + rcu_preempt_init_percpu_data(cpu); } /* - * Handle CPU online/offline notifcation events. + * Handle CPU online/offline notification events. */ int __cpuinit rcu_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) @@ -1521,6 +1546,7 @@ static void __init rcu_init_one(struct rcu_state *rsp) rnp = rsp->level[i]; for (j = 0; j < rsp->levelcnt[i]; j++, rnp++) { spin_lock_init(&rnp->lock); + rnp->gpnum = 0; rnp->qsmask = 0; rnp->qsmaskinit = 0; rnp->grplo = j * cpustride; @@ -1538,13 +1564,16 @@ static void __init rcu_init_one(struct rcu_state *rsp) j / rsp->levelspread[i - 1]; } rnp->level = i; + INIT_LIST_HEAD(&rnp->blocked_tasks[0]); + INIT_LIST_HEAD(&rnp->blocked_tasks[1]); } } } /* - * Helper macro for __rcu_init(). To be used nowhere else! - * Assigns leaf node pointers into each CPU's rcu_data structure. + * Helper macro for __rcu_init() and __rcu_init_preempt(). To be used + * nowhere else! Assigns leaf node pointers into each CPU's rcu_data + * structure. */ #define RCU_INIT_FLAVOR(rsp, rcu_data) \ do { \ @@ -1560,18 +1589,38 @@ do { \ } \ } while (0) +#ifdef CONFIG_TREE_PREEMPT_RCU + +void __init __rcu_init_preempt(void) +{ + int i; /* All used by RCU_INIT_FLAVOR(). */ + int j; + struct rcu_node *rnp; + + RCU_INIT_FLAVOR(&rcu_preempt_state, rcu_preempt_data); +} + +#else /* #ifdef CONFIG_TREE_PREEMPT_RCU */ + +void __init __rcu_init_preempt(void) +{ +} + +#endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */ + void __init __rcu_init(void) { - int i; /* All used by RCU_DATA_PTR_INIT(). */ + int i; /* All used by RCU_INIT_FLAVOR(). */ int j; struct rcu_node *rnp; - printk(KERN_INFO "Hierarchical RCU implementation.\n"); + rcu_bootup_announce(); #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_FLAVOR(&rcu_sched_state, rcu_sched_data); RCU_INIT_FLAVOR(&rcu_bh_state, rcu_bh_data); + __rcu_init_preempt(); open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); } diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 0024e5d..ca56036 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -80,6 +80,7 @@ struct rcu_dynticks { */ struct rcu_node { spinlock_t lock; + long gpnum; /* Current grace period for this node. */ unsigned long qsmask; /* CPUs or groups that need to switch in */ /* order for current grace period to proceed.*/ unsigned long qsmaskinit; @@ -90,6 +91,8 @@ struct rcu_node { u8 grpnum; /* CPU/group number for next level up. */ u8 level; /* root is at level 0. */ struct rcu_node *parent; + struct list_head blocked_tasks[2]; + /* Tasks blocked in RCU read-side critsect. */ } ____cacheline_internodealigned_in_smp; /* Index values for nxttail array in struct rcu_data. */ @@ -111,6 +114,7 @@ struct rcu_data { bool passed_quiesc; /* User-mode/idle loop etc. */ bool qs_pending; /* Core waits for quiesc state. */ bool beenonline; /* CPU online at least once. */ + bool preemptable; /* Preemptable RCU? */ struct rcu_node *mynode; /* This CPU's leaf of hierarchy */ unsigned long grpmask; /* Mask to apply to leaf qsmask. */ @@ -244,5 +248,10 @@ 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); +#ifdef CONFIG_TREE_PREEMPT_RCU +extern struct rcu_state rcu_preempt_state; +DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data); +#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ + #endif /* #ifdef RCU_TREE_NONCORE */ diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h new file mode 100644 index 0000000..cd2ab67 --- /dev/null +++ b/kernel/rcutree_plugin.h @@ -0,0 +1,447 @@ +/* + * Read-Copy Update mechanism for mutual exclusion (tree-based version) + * Internal non-public definitions that provide either classic + * or preemptable semantics. + * + * 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 Red Hat, 2009 + * Copyright IBM Corporation, 2009 + * + * Author: Ingo Molnar + * Paul E. McKenney + */ + + +#ifdef CONFIG_TREE_PREEMPT_RCU + +struct rcu_state rcu_preempt_state = RCU_STATE_INITIALIZER(rcu_preempt_state); +DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data); + +/* + * Tell them what RCU they are running. + */ +static inline void rcu_bootup_announce(void) +{ + printk(KERN_INFO + "Experimental preemptable hierarchical RCU implementation.\n"); +} + +/* + * Return the number of RCU-preempt batches processed thus far + * for debug and statistics. + */ +long rcu_batches_completed_preempt(void) +{ + return rcu_preempt_state.completed; +} +EXPORT_SYMBOL_GPL(rcu_batches_completed_preempt); + +/* + * Return the number of RCU batches processed thus far for debug & stats. + */ +long rcu_batches_completed(void) +{ + return rcu_batches_completed_preempt(); +} +EXPORT_SYMBOL_GPL(rcu_batches_completed); + +/* + * Record a preemptable-RCU quiescent state for the specified CPU. Note + * that this just means that the task currently running on the CPU is + * not in a quiescent state. There might be any number of tasks blocked + * while in an RCU read-side critical section. + */ +static void rcu_preempt_qs_record(int cpu) +{ + struct rcu_data *rdp = &per_cpu(rcu_preempt_data, cpu); + rdp->passed_quiesc = 1; + rdp->passed_quiesc_completed = rdp->completed; +} + +/* + * We have entered the scheduler or are between softirqs in ksoftirqd. + * If we are in an RCU read-side critical section, we need to reflect + * that in the state of the rcu_node structure corresponding to this CPU. + * Caller must disable hardirqs. + */ +static void rcu_preempt_qs(int cpu) +{ + struct task_struct *t = current; + int phase; + struct rcu_data *rdp; + struct rcu_node *rnp; + + if (t->rcu_read_lock_nesting && + (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) { + + /* Possibly blocking in an RCU read-side critical section. */ + rdp = rcu_preempt_state.rda[cpu]; + rnp = rdp->mynode; + spin_lock(&rnp->lock); + t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED; + t->rcu_blocked_cpu = cpu; + + /* + * If this CPU has already checked in, then this task + * will hold up the next grace period rather than the + * current grace period. Queue the task accordingly. + * If the task is queued for the current grace period + * (i.e., this CPU has not yet passed through a quiescent + * state for the current grace period), then as long + * as that task remains queued, the current grace period + * cannot end. + */ + phase = !(rnp->qsmask & rdp->grpmask) ^ (rnp->gpnum & 0x1); + list_add(&t->rcu_node_entry, &rnp->blocked_tasks[phase]); + smp_mb(); /* Ensure later ctxt swtch seen after above. */ + spin_unlock(&rnp->lock); + } + + /* + * Either we were not in an RCU read-side critical section to + * begin with, or we have now recorded that critical section + * globally. Either way, we can now note a quiescent state + * for this CPU. Again, if we were in an RCU read-side critical + * section, and if that critical section was blocking the current + * grace period, then the fact that the task has been enqueued + * means that we continue to block the current grace period. + */ + rcu_preempt_qs_record(cpu); + t->rcu_read_unlock_special &= ~(RCU_READ_UNLOCK_NEED_QS | + RCU_READ_UNLOCK_GOT_QS); +} + +/* + * Tree-preemptable RCU implementation for rcu_read_lock(). + * Just increment ->rcu_read_lock_nesting, shared state will be updated + * if we block. + */ +void __rcu_read_lock(void) +{ + ACCESS_ONCE(current->rcu_read_lock_nesting)++; + barrier(); /* needed if we ever invoke rcu_read_lock in rcutree.c */ +} +EXPORT_SYMBOL_GPL(__rcu_read_lock); + +static void rcu_read_unlock_special(struct task_struct *t) +{ + int empty; + unsigned long flags; + unsigned long mask; + struct rcu_node *rnp; + int special; + + /* NMI handlers cannot block and cannot safely manipulate state. */ + if (in_nmi()) + return; + + local_irq_save(flags); + + /* + * If RCU core is waiting for this CPU to exit critical section, + * let it know that we have done so. + */ + special = t->rcu_read_unlock_special; + if (special & RCU_READ_UNLOCK_NEED_QS) { + t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_NEED_QS; + t->rcu_read_unlock_special |= RCU_READ_UNLOCK_GOT_QS; + } + + /* Hardware IRQ handlers cannot block. */ + if (in_irq()) { + local_irq_restore(flags); + return; + } + + /* Clean up if blocked during RCU read-side critical section. */ + if (special & RCU_READ_UNLOCK_BLOCKED) { + t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_BLOCKED; + + /* Remove this task from the list it blocked on. */ + rnp = rcu_preempt_state.rda[t->rcu_blocked_cpu]->mynode; + spin_lock(&rnp->lock); + empty = list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1]); + list_del_init(&t->rcu_node_entry); + t->rcu_blocked_cpu = -1; + + /* + * If this was the last task on the current list, and if + * we aren't waiting on any CPUs, report the quiescent state. + * Note that both cpu_quiet_msk_finish() and cpu_quiet_msk() + * drop rnp->lock and restore irq. + */ + if (!empty && rnp->qsmask == 0 && + list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1])) { + t->rcu_read_unlock_special &= + ~(RCU_READ_UNLOCK_NEED_QS | + RCU_READ_UNLOCK_GOT_QS); + if (rnp->parent == NULL) { + /* Only one rcu_node in the tree. */ + cpu_quiet_msk_finish(&rcu_preempt_state, flags); + return; + } + /* Report up the rest of the hierarchy. */ + mask = rnp->grpmask; + spin_unlock_irqrestore(&rnp->lock, flags); + rnp = rnp->parent; + spin_lock_irqsave(&rnp->lock, flags); + cpu_quiet_msk(mask, &rcu_preempt_state, rnp, flags); + return; + } + spin_unlock(&rnp->lock); + } + local_irq_restore(flags); +} + +/* + * Tree-preemptable RCU implementation for rcu_read_unlock(). + * Decrement ->rcu_read_lock_nesting. If the result is zero (outermost + * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then + * invoke rcu_read_unlock_special() to clean up after a context switch + * in an RCU read-side critical section and other special cases. + */ +void __rcu_read_unlock(void) +{ + struct task_struct *t = current; + + barrier(); /* needed if we ever invoke rcu_read_unlock in rcutree.c */ + if (--ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 && + unlikely(ACCESS_ONCE(t->rcu_read_unlock_special))) + rcu_read_unlock_special(t); +} +EXPORT_SYMBOL_GPL(__rcu_read_unlock); + +#ifdef CONFIG_RCU_CPU_STALL_DETECTOR + +/* + * Scan the current list of tasks blocked within RCU read-side critical + * sections, printing out the tid of each. + */ +static void rcu_print_task_stall(struct rcu_node *rnp) +{ + unsigned long flags; + struct list_head *lp; + int phase = rnp->gpnum & 0x1; + struct task_struct *t; + + if (!list_empty(&rnp->blocked_tasks[phase])) { + spin_lock_irqsave(&rnp->lock, flags); + phase = rnp->gpnum & 0x1; /* re-read under lock. */ + lp = &rnp->blocked_tasks[phase]; + list_for_each_entry(t, lp, rcu_node_entry) + printk(" P%d", t->pid); + spin_unlock_irqrestore(&rnp->lock, flags); + } +} + +#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ + +/* + * Check for preempted RCU readers for the specified rcu_node structure. + * If the caller needs a reliable answer, it must hold the rcu_node's + * >lock. + */ +static int rcu_preempted_readers(struct rcu_node *rnp) +{ + return !list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1]); +} + +/* + * Check for a quiescent state from the current CPU. When a task blocks, + * the task is recorded in the corresponding CPU's rcu_node structure, + * which is checked elsewhere. + * + * Caller must disable hard irqs. + */ +static void rcu_preempt_check_callbacks(int cpu) +{ + struct task_struct *t = current; + + if (t->rcu_read_lock_nesting == 0) { + t->rcu_read_unlock_special &= + ~(RCU_READ_UNLOCK_NEED_QS | RCU_READ_UNLOCK_GOT_QS); + rcu_preempt_qs_record(cpu); + return; + } + if (per_cpu(rcu_preempt_data, cpu).qs_pending) { + if (t->rcu_read_unlock_special & RCU_READ_UNLOCK_GOT_QS) { + rcu_preempt_qs_record(cpu); + t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_GOT_QS; + } else if (!(t->rcu_read_unlock_special & + RCU_READ_UNLOCK_NEED_QS)) { + t->rcu_read_unlock_special |= RCU_READ_UNLOCK_NEED_QS; + } + } +} + +/* + * Process callbacks for preemptable RCU. + */ +static void rcu_preempt_process_callbacks(void) +{ + __rcu_process_callbacks(&rcu_preempt_state, + &__get_cpu_var(rcu_preempt_data)); +} + +/* + * Queue a preemptable-RCU callback for invocation after a grace period. + */ +void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) +{ + __call_rcu(head, func, &rcu_preempt_state); +} +EXPORT_SYMBOL_GPL(call_rcu); + +/* + * Check to see if there is any immediate preemptable-RCU-related work + * to be done. + */ +static int rcu_preempt_pending(int cpu) +{ + return __rcu_pending(&rcu_preempt_state, + &per_cpu(rcu_preempt_data, cpu)); +} + +/* + * Does preemptable RCU need the CPU to stay out of dynticks mode? + */ +static int rcu_preempt_needs_cpu(int cpu) +{ + return !!per_cpu(rcu_preempt_data, cpu).nxtlist; +} + +/* + * Initialize preemptable RCU's per-CPU data. + */ +static void __cpuinit rcu_preempt_init_percpu_data(int cpu) +{ + rcu_init_percpu_data(cpu, &rcu_preempt_state, 1); +} + +/* + * Check for a task exiting while in a preemptable-RCU read-side + * critical section, clean up if so. No need to issue warnings, + * as debug_check_no_locks_held() already does this if lockdep + * is enabled. + */ +void exit_rcu(void) +{ + struct task_struct *t = current; + + if (t->rcu_read_lock_nesting == 0) + return; + t->rcu_read_lock_nesting = 1; + rcu_read_unlock(); +} + +#else /* #ifdef CONFIG_TREE_PREEMPT_RCU */ + +/* + * Tell them what RCU they are running. + */ +static inline void rcu_bootup_announce(void) +{ + printk(KERN_INFO "Hierarchical RCU implementation.\n"); +} + +/* + * Return the number of RCU batches processed thus far for debug & stats. + */ +long rcu_batches_completed(void) +{ + return rcu_batches_completed_sched(); +} +EXPORT_SYMBOL_GPL(rcu_batches_completed); + +/* + * Because preemptable RCU does not exist, we never have to check for + * CPUs being in quiescent states. + */ +static void rcu_preempt_qs(int cpu) +{ +} + +#ifdef CONFIG_RCU_CPU_STALL_DETECTOR + +/* + * Because preemptable RCU does not exist, we never have to check for + * tasks blocked within RCU read-side critical sections. + */ +static void rcu_print_task_stall(struct rcu_node *rnp) +{ +} + +#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ + +/* + * Because preemptable RCU does not exist, there are never any preempted + * RCU readers. + */ +static int rcu_preempted_readers(struct rcu_node *rnp) +{ + return 0; +} + +/* + * Because preemptable RCU does not exist, it never has any callbacks + * to check. + */ +void rcu_preempt_check_callbacks(int cpu) +{ +} + +/* + * Because preemptable RCU does not exist, it never has any callbacks + * to process. + */ +void rcu_preempt_process_callbacks(void) +{ +} + +/* + * In classic RCU, call_rcu() is just call_rcu_sched(). + */ +void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) +{ + call_rcu_sched(head, func); +} +EXPORT_SYMBOL_GPL(call_rcu); + +/* + * Because preemptable RCU does not exist, it never has any work to do. + */ +static int rcu_preempt_pending(int cpu) +{ + return 0; +} + +/* + * Because preemptable RCU does not exist, it never needs any CPU. + */ +static int rcu_preempt_needs_cpu(int cpu) +{ + return 0; +} + +/* + * Because preemptable RCU does not exist, there is no per-CPU + * data to initialize. + */ +static void __cpuinit rcu_preempt_init_percpu_data(int cpu) +{ +} + +#endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */ diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 31af3a0..0ea1bff 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -77,6 +77,10 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) static int show_rcudata(struct seq_file *m, void *unused) { +#ifdef CONFIG_TREE_PREEMPT_RCU + seq_puts(m, "rcu_preempt:\n"); + PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data, m); +#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ seq_puts(m, "rcu_sched:\n"); PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data, m); seq_puts(m, "rcu_bh:\n"); @@ -125,6 +129,10 @@ 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"); +#ifdef CONFIG_TREE_PREEMPT_RCU + seq_puts(m, "\"rcu_preempt:\"\n"); + PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data_csv, m); +#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ seq_puts(m, "\"rcu_sched:\"\n"); PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data_csv, m); seq_puts(m, "\"rcu_bh:\"\n"); @@ -172,6 +180,10 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) static int show_rcuhier(struct seq_file *m, void *unused) { +#ifdef CONFIG_TREE_PREEMPT_RCU + seq_puts(m, "rcu_preempt:\n"); + print_one_rcu_state(m, &rcu_preempt_state); +#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ seq_puts(m, "rcu_sched:\n"); print_one_rcu_state(m, &rcu_sched_state); seq_puts(m, "rcu_bh:\n"); @@ -194,6 +206,10 @@ static struct file_operations rcuhier_fops = { static int show_rcugp(struct seq_file *m, void *unused) { +#ifdef CONFIG_TREE_PREEMPT_RCU + seq_printf(m, "rcu_preempt: completed=%ld gpnum=%ld\n", + rcu_preempt_state.completed, rcu_preempt_state.gpnum); +#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ 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", @@ -244,6 +260,10 @@ static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp) static int show_rcu_pending(struct seq_file *m, void *unused) { +#ifdef CONFIG_TREE_PREEMPT_RCU + seq_puts(m, "rcu_preempt:\n"); + print_rcu_pendings(m, &rcu_preempt_state); +#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ seq_puts(m, "rcu_sched:\n"); print_rcu_pendings(m, &rcu_sched_state); seq_puts(m, "rcu_bh:\n"); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 12327b2..f87fb0c 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 + depends on CLASSIC_RCU || TREE_RCU || TREE_PREEMPT_RCU default n help This option causes RCU to printk information on which -- cgit v0.10.2 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 diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt index 7aa2002..2a23523 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 97ded24..e41a7fe 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 971a968..79d4bae 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 26892f5..ec90fc3 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 a42ab88..0000000 --- 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 b99ae07..0000000 --- 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 d7f98f6..bfca26d6 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 f88da2d..8e8b76d 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 1a38b47..b833bd5 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 0053ce5..0000000 --- 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 1164034..0000000 --- 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 f87fb0c..82fbc49 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 v0.10.2 From 366d19e181be873c70f4aafca3931d77d781ccd7 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Fri, 21 Aug 2009 23:06:23 +0200 Subject: x86: add specific support for Intel Atom architecture Add another option when selecting CPU family so the kernel can be optimized for Intel Atom CPUs. If GCC supports tuning options for Intel Atom they will be used. Signed-off-by: Tobias Doerffel Signed-off-by: H. Peter Anvin LKML-Reference: <1251018457-19157-1-git-send-email-tobias.doerffel@gmail.com> Signed-off-by: Ingo Molnar diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 8130334..527519b 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -262,6 +262,15 @@ config MCORE2 family in /proc/cpuinfo. Newer ones have 6 and older ones 15 (not a typo) +config MATOM + bool "Intel Atom" + ---help--- + + Select this for the Intel Atom platform. Intel Atom CPUs have an + in-order pipelining architecture and thus can benefit from + accordingly optimized code. Use a recent GCC with specific Atom + support in order to fully benefit from selecting this option. + config GENERIC_CPU bool "Generic-x86-64" depends on X86_64 @@ -295,7 +304,7 @@ config X86_CPU config X86_L1_CACHE_BYTES int default "128" if MPSC - default "64" if GENERIC_CPU || MK8 || MCORE2 || X86_32 + default "64" if GENERIC_CPU || MK8 || MCORE2 || MATOM || X86_32 config X86_INTERNODE_CACHE_BYTES int @@ -310,7 +319,7 @@ config X86_L1_CACHE_SHIFT default "7" if MPENTIUM4 || MPSC default "4" if X86_ELAN || M486 || M386 || MGEODEGX1 default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX - default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MVIAC7 || X86_GENERIC || GENERIC_CPU + default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU config X86_XADD def_bool y @@ -359,7 +368,7 @@ config X86_INTEL_USERCOPY config X86_USE_PPRO_CHECKSUM def_bool y - depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2 + depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM config X86_USE_3DNOW def_bool y @@ -387,7 +396,7 @@ config X86_P6_NOP config X86_TSC def_bool y - depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64 + depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) && !X86_NUMAQ) || X86_64 config X86_CMPXCHG64 def_bool y @@ -397,7 +406,7 @@ config X86_CMPXCHG64 # generates cmov. config X86_CMOV def_bool y - depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64) + depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM) config X86_MINIMUM_CPU_FAMILY int diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 1b68659..8a4c24c 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -55,6 +55,8 @@ else cflags-$(CONFIG_MCORE2) += \ $(call cc-option,-march=core2,$(call cc-option,-mtune=generic)) + cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom) \ + $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic)) cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic) KBUILD_CFLAGS += $(cflags-y) diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu index 80177ec..30e9a26 100644 --- a/arch/x86/Makefile_32.cpu +++ b/arch/x86/Makefile_32.cpu @@ -33,6 +33,8 @@ cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) $(align)-f cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686) cflags-$(CONFIG_MVIAC7) += -march=i686 cflags-$(CONFIG_MCORE2) += -march=i686 $(call tune,core2) +cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom,$(call cc-option,-march=core2,-march=i686)) \ + $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic)) # AMD Elan support cflags-$(CONFIG_X86_ELAN) += -march=i486 diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h index 47d6274..e959c4a 100644 --- a/arch/x86/include/asm/module.h +++ b/arch/x86/include/asm/module.h @@ -28,6 +28,8 @@ struct mod_arch_specific {}; #define MODULE_PROC_FAMILY "586MMX " #elif defined CONFIG_MCORE2 #define MODULE_PROC_FAMILY "CORE2 " +#elif defined CONFIG_MATOM +#define MODULE_PROC_FAMILY "ATOM " #elif defined CONFIG_M686 #define MODULE_PROC_FAMILY "686 " #elif defined CONFIG_MPENTIUMII -- cgit v0.10.2 From 821ebc86efd4b42aa120076562b0fd4f03ec3c0c Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sat, 22 Aug 2009 21:24:24 +0200 Subject: ASoC: free socdev if init_card() fails in wm9705_soc_probe() Free socdev if snd_soc_init_card() fails. Signed-off-by: Roel Kluin Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index fa88b46..e7d2840 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -406,7 +406,7 @@ static int wm9705_soc_probe(struct platform_device *pdev) ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm9705: failed to register card\n"); - goto pcm_err; + goto reset_err; } return 0; -- cgit v0.10.2 From 848bffef28454049549bfba113b932df7c6d243d Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 19 Aug 2009 22:09:55 +0200 Subject: ALSA: ali5451: remove dead code Remove code covered by #if/endif 0 and #ifdef/endif CODEC_RESET (CODEC_RESET is never defined). Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Takashi Iwai diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 76d76c0..b458d20 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -478,45 +478,6 @@ static int snd_ali_reset_5451(struct snd_ali *codec) return 0; } -#ifdef CODEC_RESET - -static int snd_ali_reset_codec(struct snd_ali *codec) -{ - struct pci_dev *pci_dev; - unsigned char bVal; - unsigned int dwVal; - unsigned short wCount, wReg; - - pci_dev = codec->pci_m1533; - - pci_read_config_dword(pci_dev, 0x7c, &dwVal); - pci_write_config_dword(pci_dev, 0x7c, dwVal | 0x08000000); - udelay(5000); - pci_read_config_dword(pci_dev, 0x7c, &dwVal); - pci_write_config_dword(pci_dev, 0x7c, dwVal & 0xf7ffffff); - udelay(5000); - - bVal = inb(ALI_REG(codec,ALI_SCTRL)); - bVal |= 0x02; - outb(ALI_REG(codec,ALI_SCTRL),bVal); - udelay(5000); - bVal = inb(ALI_REG(codec,ALI_SCTRL)); - bVal &= 0xfd; - outb(ALI_REG(codec,ALI_SCTRL),bVal); - udelay(15000); - - wCount = 200; - while (wCount--) { - wReg = snd_ali_codec_read(codec->ac97, AC97_POWERDOWN); - if ((wReg & 0x000f) == 0x000f) - return 0; - udelay(5000); - } - return -1; -} - -#endif - /* * ALI 5451 Controller */ @@ -561,22 +522,6 @@ static void snd_ali_disable_address_interrupt(struct snd_ali *codec) outl(gc, ALI_REG(codec, ALI_GC_CIR)); } -#if 0 /* not used */ -static void snd_ali_enable_voice_irq(struct snd_ali *codec, - unsigned int channel) -{ - unsigned int mask; - struct snd_ali_channel_control *pchregs = &(codec->chregs); - - snd_ali_printk("enable_voice_irq channel=%d\n",channel); - - mask = 1 << (channel & 0x1f); - pchregs->data.ainten = inl(ALI_REG(codec, pchregs->regs.ainten)); - pchregs->data.ainten |= mask; - outl(pchregs->data.ainten, ALI_REG(codec, pchregs->regs.ainten)); -} -#endif - static void snd_ali_disable_voice_irq(struct snd_ali *codec, unsigned int channel) { @@ -677,16 +622,6 @@ static void snd_ali_free_channel_pcm(struct snd_ali *codec, int channel) } } -#if 0 /* not used */ -static void snd_ali_start_voice(struct snd_ali *codec, unsigned int channel) -{ - unsigned int mask = 1 << (channel & 0x1f); - - snd_ali_printk("start_voice: channel=%d\n",channel); - outl(mask, ALI_REG(codec,codec->chregs.regs.start)); -} -#endif - static void snd_ali_stop_voice(struct snd_ali *codec, unsigned int channel) { unsigned int mask = 1 << (channel & 0x1f); -- cgit v0.10.2 From e2365bf313fb21b49b1e4c911033389564428d03 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 21 Aug 2009 20:02:52 +0200 Subject: ASoC: Pass correct platform data from pxa2xx-ac97 Signed-off-by: Marek Vasut Signed-off-by: Mark Brown diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 6c00ea4..757b480 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -207,8 +207,8 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) snprintf(card->longname, sizeof(card->longname), "%s (%s)", dev->dev.driver->name, card->mixername); - if (pdata && pdata->codec_data) - snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata); + if (pdata && pdata->codec_data[0]) + snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata[0]); snd_card_set_dev(card, &dev->dev); ret = snd_card_register(card); if (ret == 0) { diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 7330e5c..e9ae7b3 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -251,8 +251,8 @@ static int __devinit pxa2xx_ac97_dev_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++) { pxa_ac97_dai[i].dev = &pdev->dev; - if (pdata && pdata->codec_pdata) - pxa_ac97_dai[i].ac97_pdata = pdata->codec_pdata; + if (pdata && pdata->codec_pdata[0]) + pxa_ac97_dai[i].ac97_pdata = pdata->codec_pdata[0]; } /* Punt most of the init to the SoC probe; we may need the machine -- cgit v0.10.2 From d8e180dcd5bbbab9cd3ff2e779efcf70692ef541 Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Thu, 20 Aug 2009 14:39:52 -0700 Subject: bsdacct: switch credentials for writing to the accounting file When process accounting is enabled, every exiting process writes a log to the account file. In addition, every once in a while one of the exiting processes checks whether there's enough free space for the log. SELinux policy may or may not allow the exiting process to stat the fs. So unsuspecting processes start generating AVC denials just because someone enabled process accounting. For these filesystem operations, the exiting process's credentials should be temporarily switched to that of the process which enabled accounting, because it's really that process which wanted to have the accounting information logged. Signed-off-by: Michal Schmidt Acked-by: David Howells Acked-by: Serge Hallyn Signed-off-by: Andrew Morton Signed-off-by: James Morris diff --git a/kernel/acct.c b/kernel/acct.c index 9f33910..9a4715a 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -491,13 +491,17 @@ static void do_acct_process(struct bsd_acct_struct *acct, u64 run_time; struct timespec uptime; struct tty_struct *tty; + const struct cred *orig_cred; + + /* Perform file operations on behalf of whoever enabled accounting */ + orig_cred = override_creds(file->f_cred); /* * First check to see if there is enough free_space to continue * the process accounting system. */ if (!check_free_space(acct, file)) - return; + goto out; /* * Fill the accounting struct with the needed info as recorded @@ -578,6 +582,8 @@ static void do_acct_process(struct bsd_acct_struct *acct, sizeof(acct_t), &file->f_pos); current->signal->rlim[RLIMIT_FSIZE].rlim_cur = flim; set_fs(fs); +out: + revert_creds(orig_cred); } /** -- cgit v0.10.2 From 1bb482f8a46000f77577948ff1c350275bba7dc9 Mon Sep 17 00:00:00 2001 From: Narender Kumar Date: Sun, 23 Aug 2009 08:35:09 +0000 Subject: netxen: ethtool statistics and control for LRO Add ethtool -K knob to control LRO in firmware. LRO path is completely separated from GRO, LRO packets are still fed with netif_receive_skb(). Also fix ethtool statistics to include LRO packets. Also use correct message type while configuring interrupt coalescing. Signed-off-by: Narender Kumar Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 5abb41e..fa43aa0 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -576,7 +576,8 @@ struct netxen_adapter_stats { u64 rxdropped; u64 txdropped; u64 csummed; - u64 no_rcv; + u64 rx_pkts; + u64 lro_pkts; u64 rxbytes; u64 txbytes; }; @@ -958,7 +959,8 @@ typedef struct { #define NX_NIC_H2C_OPCODE_PROXY_STOP_DONE 20 #define NX_NIC_H2C_OPCODE_GET_LINKEVENT 21 #define NX_NIC_C2C_OPCODE 22 -#define NX_NIC_H2C_OPCODE_LAST 23 +#define NX_NIC_H2C_OPCODE_CONFIG_HW_LRO 24 +#define NX_NIC_H2C_OPCODE_LAST 25 /* * Firmware --> Driver @@ -984,6 +986,19 @@ typedef struct { #define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */ #define VPORT_MISS_MODE_ACCEPT_MULTI 2 /* accept unmatched multicast */ +#define NX_NIC_LRO_REQUEST_FIRST 0 +#define NX_NIC_LRO_REQUEST_ADD_FLOW 1 +#define NX_NIC_LRO_REQUEST_DELETE_FLOW 2 +#define NX_NIC_LRO_REQUEST_TIMER 3 +#define NX_NIC_LRO_REQUEST_CLEANUP 4 +#define NX_NIC_LRO_REQUEST_ADD_FLOW_SCHEDULED 5 +#define NX_TOE_LRO_REQUEST_ADD_FLOW 6 +#define NX_TOE_LRO_REQUEST_ADD_FLOW_RESPONSE 7 +#define NX_TOE_LRO_REQUEST_DELETE_FLOW 8 +#define NX_TOE_LRO_REQUEST_DELETE_FLOW_RESPONSE 9 +#define NX_TOE_LRO_REQUEST_TIMER 10 +#define NX_NIC_LRO_REQUEST_LAST 11 + #define NX_FW_CAPABILITY_LINK_NOTIFICATION (1 << 5) #define NX_FW_CAPABILITY_SWITCHING (1 << 6) #define NX_FW_CAPABILITY_PEXQ (1 << 7) @@ -1064,6 +1079,7 @@ typedef struct { #define NETXEN_NIC_MSI_ENABLED 0x02 #define NETXEN_NIC_MSIX_ENABLED 0x04 +#define NETXEN_NIC_LRO_ENABLED 0x08 #define NETXEN_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED)) @@ -1290,6 +1306,8 @@ void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup); int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu); int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu); +int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable); +int netxen_send_lro_cleanup(struct netxen_adapter *adapter); int netxen_nic_set_mac(struct net_device *netdev, void *p); struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 412d658..9e04696 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -203,8 +203,6 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter) cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN); cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS); - if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) - cap |= NX_CAP0_HW_LRO; prq->capabilities[0] = cpu_to_le32(cap); prq->host_int_crb_mode = diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 39a308c..db66e70 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -57,7 +57,8 @@ static const struct netxen_nic_stats netxen_nic_gstrings_stats[] = { {"rx_dropped", NETXEN_NIC_STAT(stats.rxdropped)}, {"tx_dropped", NETXEN_NIC_STAT(stats.txdropped)}, {"csummed", NETXEN_NIC_STAT(stats.csummed)}, - {"no_rcv", NETXEN_NIC_STAT(stats.no_rcv)}, + {"rx_pkts", NETXEN_NIC_STAT(stats.rx_pkts)}, + {"lro_pkts", NETXEN_NIC_STAT(stats.lro_pkts)}, {"rx_bytes", NETXEN_NIC_STAT(stats.rxbytes)}, {"tx_bytes", NETXEN_NIC_STAT(stats.txbytes)}, }; @@ -941,6 +942,28 @@ static int netxen_get_intr_coalesce(struct net_device *netdev, return 0; } +static int netxen_nic_set_flags(struct net_device *netdev, u32 data) +{ + struct netxen_adapter *adapter = netdev_priv(netdev); + int hw_lro; + + if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)) + return -EINVAL; + + ethtool_op_set_flags(netdev, data); + + hw_lro = (data & ETH_FLAG_LRO) ? NETXEN_NIC_LRO_ENABLED : 0; + + if (netxen_config_hw_lro(adapter, hw_lro)) + return -EIO; + + if ((hw_lro == 0) && netxen_send_lro_cleanup(adapter)) + return -EIO; + + + return 0; +} + struct ethtool_ops netxen_nic_ethtool_ops = { .get_settings = netxen_nic_get_settings, .set_settings = netxen_nic_set_settings, @@ -968,4 +991,6 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .set_rx_csum = netxen_nic_set_rx_csum, .get_coalesce = netxen_get_intr_coalesce, .set_coalesce = netxen_set_intr_coalesce, + .get_flags = ethtool_op_get_flags, + .set_flags = netxen_nic_set_flags, }; diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 673dcf5..965f783 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -643,7 +643,7 @@ int netxen_config_intr_coalesce(struct netxen_adapter *adapter) memset(&req, 0, sizeof(nx_nic_req_t)); - req.qhdr = cpu_to_le64(NX_NIC_REQUEST << 23); + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); word = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); req.req_hdr = cpu_to_le64(word); @@ -659,6 +659,35 @@ int netxen_config_intr_coalesce(struct netxen_adapter *adapter) return rv; } +int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable) +{ + nx_nic_req_t req; + u64 word; + int rv = 0; + + if ((adapter->flags & NETXEN_NIC_LRO_ENABLED) == enable) + return 0; + + memset(&req, 0, sizeof(nx_nic_req_t)); + + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); + + word = NX_NIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(enable); + + rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) { + printk(KERN_ERR "ERROR. Could not send " + "configure hw lro request\n"); + } + + adapter->flags ^= NETXEN_NIC_LRO_ENABLED; + + return rv; +} + #define RSS_HASHTYPE_IP_TCP 0x3 int netxen_config_rss(struct netxen_adapter *adapter, int enable) @@ -752,6 +781,29 @@ int netxen_linkevent_request(struct netxen_adapter *adapter, int enable) return rv; } +int netxen_send_lro_cleanup(struct netxen_adapter *adapter) +{ + nx_nic_req_t req; + u64 word; + int rv; + + memset(&req, 0, sizeof(nx_nic_req_t)); + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); + + word = NX_NIC_H2C_OPCODE_LRO_REQUEST | + ((u64)adapter->portnum << 16) | + ((u64)NX_NIC_LRO_REQUEST_CLEANUP << 56) ; + + req.req_hdr = cpu_to_le64(word); + + rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) { + printk(KERN_ERR "%s: could not cleanup lro flows\n", + adapter->netdev->name); + } + return rv; +} + /* * netxen_nic_change_mtu - Change the Maximum Transfer Unit * @returns 0 on success, negative on failure @@ -2066,6 +2118,8 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); + + adapter->flags &= ~NETXEN_NIC_LRO_ENABLED; } int diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index e8bdbf9..c3609e4 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1277,7 +1277,7 @@ netxen_process_rcv(struct netxen_adapter *adapter, napi_gro_receive(&sds_ring->napi, skb); - adapter->stats.no_rcv++; + adapter->stats.rx_pkts++; adapter->stats.rxbytes += length; return buffer; @@ -1350,8 +1350,13 @@ netxen_process_lro(struct netxen_adapter *adapter, th->psh = push; th->seq = htonl(seq_number); + length = skb->len; + netif_receive_skb(skb); + adapter->stats.lro_pkts++; + adapter->stats.rxbytes += length; + return buffer; } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 4e3fb30..de67e42 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -892,6 +892,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_config_intr_coalesce(adapter); + if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) + netxen_config_hw_lro(adapter, NETXEN_NIC_LRO_ENABLED); + netxen_napi_enable(adapter); if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION) @@ -1077,6 +1080,9 @@ netxen_setup_netdev(struct netxen_adapter *adapter, if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX) netdev->features |= (NETIF_F_HW_VLAN_TX); + if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) + netdev->features |= NETIF_F_LRO; + netdev->irq = adapter->msix_entries[0].vector; err = netxen_napi_add(adapter, netdev); @@ -1812,7 +1818,7 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) memset(stats, 0, sizeof(*stats)); - stats->rx_packets = adapter->stats.no_rcv; + stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts; stats->tx_packets = adapter->stats.xmitfinished; stats->rx_bytes = adapter->stats.rxbytes; stats->tx_bytes = adapter->stats.txbytes; -- cgit v0.10.2 From 1dbc84a7f6c2ebd8c69299e1adef22ee26db38c0 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 23 Aug 2009 08:35:10 +0000 Subject: netxen: fix firmware reset logic If netxen_need_fw_reset() return 0 [ implies firmware is up and running], still go through dma mask check, etc. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index de67e42..0086574 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -754,8 +754,10 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) netxen_request_firmware(adapter); err = netxen_need_fw_reset(adapter); - if (err <= 0) + if (err < 0) return err; + if (err == 0) + goto wait_init; if (first_boot != 0x55555555) { NXWR32(adapter, CRB_CMDPEG_STATE, 0); -- cgit v0.10.2 From ce644ed4db3ee1075ebd9f4acc403e1f9410db21 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 23 Aug 2009 08:35:11 +0000 Subject: netxen: refactor tx dma mapping code Move all tx skb mapping code into netxen_map_tx_skb(). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 0086574..f618e7c 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1518,22 +1518,52 @@ netxen_tso_check(struct net_device *netdev, barrier(); } -static void -netxen_clean_tx_dma_mapping(struct pci_dev *pdev, - struct netxen_cmd_buffer *pbuf, int last) +static int +netxen_map_tx_skb(struct pci_dev *pdev, + struct sk_buff *skb, struct netxen_cmd_buffer *pbuf) { - int k; - struct netxen_skb_frag *buffrag; + struct netxen_skb_frag *nf; + struct skb_frag_struct *frag; + int i, nr_frags; + dma_addr_t map; + + nr_frags = skb_shinfo(skb)->nr_frags; + nf = &pbuf->frag_array[0]; + + map = pci_map_single(pdev, skb->data, + skb_headlen(skb), PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, map)) + goto out_err; - buffrag = &pbuf->frag_array[0]; - pci_unmap_single(pdev, buffrag->dma, - buffrag->length, PCI_DMA_TODEVICE); + nf->dma = map; + nf->length = skb_headlen(skb); + + for (i = 0; i < nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + nf = &pbuf->frag_array[i+1]; + + map = pci_map_page(pdev, frag->page, frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, map)) + goto unwind; + + nf->dma = map; + nf->length = frag->size; + } + + return 0; - for (k = 1; k < last; k++) { - buffrag = &pbuf->frag_array[k]; - pci_unmap_page(pdev, buffrag->dma, - buffrag->length, PCI_DMA_TODEVICE); +unwind: + while (i > 0) { + nf = &pbuf->frag_array[i]; + pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); } + + nf = &pbuf->frag_array[0]; + pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE); + +out_err: + return -ENOMEM; } static inline void @@ -1548,17 +1578,14 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); struct nx_host_tx_ring *tx_ring = adapter->tx_ring; - struct skb_frag_struct *frag; struct netxen_cmd_buffer *pbuf; struct netxen_skb_frag *buffrag; struct cmd_desc_type0 *hwdesc, *first_desc; struct pci_dev *pdev; - dma_addr_t temp_dma; int i, k; - unsigned long offset; u32 producer; - int len, frag_count, no_of_desc; + int frag_count, no_of_desc; u32 num_txd = tx_ring->num_desc; frag_count = skb_shinfo(skb)->nr_frags + 1; @@ -1572,72 +1599,53 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } producer = tx_ring->producer; + pbuf = &tx_ring->cmd_buf_arr[producer]; pdev = adapter->pdev; - len = skb->len - skb->data_len; - temp_dma = pci_map_single(pdev, skb->data, len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(pdev, temp_dma)) + if (netxen_map_tx_skb(pdev, skb, pbuf)) goto drop_packet; - pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = skb; pbuf->frag_count = frag_count; - buffrag = &pbuf->frag_array[0]; - buffrag->dma = temp_dma; - buffrag->length = len; - first_desc = hwdesc = &tx_ring->desc_head[producer]; netxen_clear_cmddesc((u64 *)hwdesc); - netxen_set_tx_frags_len(hwdesc, frag_count, skb->len); - netxen_set_tx_port(hwdesc, adapter->portnum); - hwdesc->buffer_length[0] = cpu_to_le16(len); - hwdesc->addr_buffer1 = cpu_to_le64(temp_dma); + netxen_set_tx_frags_len(first_desc, frag_count, skb->len); + netxen_set_tx_port(first_desc, adapter->portnum); - for (i = 1, k = 1; i < frag_count; i++, k++) { + for (i = 0; i < frag_count; i++) { - /* move to next desc. if there is a need */ - if ((i & 0x3) == 0) { - k = 0; + k = i % 4; + + if ((k == 0) && (i > 0)) { + /* move to next desc.*/ producer = get_next_index(producer, num_txd); hwdesc = &tx_ring->desc_head[producer]; netxen_clear_cmddesc((u64 *)hwdesc); - pbuf = &tx_ring->cmd_buf_arr[producer]; - pbuf->skb = NULL; - } - buffrag = &pbuf->frag_array[i]; - frag = &skb_shinfo(skb)->frags[i - 1]; - len = frag->size; - offset = frag->page_offset; - - temp_dma = pci_map_page(pdev, frag->page, offset, - len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(pdev, temp_dma)) { - netxen_clean_tx_dma_mapping(pdev, pbuf, i); - goto drop_packet; + tx_ring->cmd_buf_arr[producer].skb = NULL; } - buffrag->dma = temp_dma; - buffrag->length = len; + buffrag = &pbuf->frag_array[i]; - hwdesc->buffer_length[k] = cpu_to_le16(len); + hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length); switch (k) { case 0: - hwdesc->addr_buffer1 = cpu_to_le64(temp_dma); + hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); break; case 1: - hwdesc->addr_buffer2 = cpu_to_le64(temp_dma); + hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma); break; case 2: - hwdesc->addr_buffer3 = cpu_to_le64(temp_dma); + hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma); break; case 3: - hwdesc->addr_buffer4 = cpu_to_le64(temp_dma); + hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma); break; } } + tx_ring->producer = get_next_index(producer, num_txd); netxen_tso_check(netdev, tx_ring, first_desc, skb); -- cgit v0.10.2 From 22b5794b5d58ea81e91d68d00e49357b66d5a559 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Sun, 23 Aug 2009 08:35:12 +0000 Subject: netxen: implement pci driver shutdown Implement pci driver shutdown functionality, this helps quiescing all PCI transaction before chipset is reset. Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index f618e7c..794c19b 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -922,6 +922,8 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_p3_free_mac_list(adapter); + adapter->set_promisc(adapter, NETXEN_NIU_NON_PROMISC_MODE); + netxen_napi_disable(adapter); netxen_release_tx_buffers(adapter); @@ -1288,14 +1290,11 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) free_netdev(netdev); } - -#ifdef CONFIG_PM -static int -netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) +static int __netxen_nic_shutdown(struct pci_dev *pdev) { - struct netxen_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; + int retval; netif_device_detach(netdev); @@ -1307,7 +1306,12 @@ netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) netxen_nic_detach(adapter); - pci_save_state(pdev); + if (adapter->portnum == 0) + netxen_free_dummy_dma(adapter); + + retval = pci_save_state(pdev); + if (retval) + return retval; if (netxen_nic_wol_supported(adapter)) { pci_enable_wake(pdev, PCI_D3cold, 1); @@ -1315,10 +1319,27 @@ netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) } pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } +static void netxen_nic_shutdown(struct pci_dev *pdev) +{ + if (__netxen_nic_shutdown(pdev)) + return; +} +#ifdef CONFIG_PM +static int +netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int retval; + + retval = __netxen_nic_shutdown(pdev); + if (retval) + return retval; + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} static int netxen_nic_resume(struct pci_dev *pdev) @@ -2068,8 +2089,9 @@ static struct pci_driver netxen_driver = { .remove = __devexit_p(netxen_nic_remove), #ifdef CONFIG_PM .suspend = netxen_nic_suspend, - .resume = netxen_nic_resume + .resume = netxen_nic_resume, #endif + .shutdown = netxen_nic_shutdown }; static int __init netxen_init_module(void) -- cgit v0.10.2 From 7d6fd5e7e97a2188d56441e4e96494c21c5994a7 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 23 Aug 2009 08:35:13 +0000 Subject: netxen: remove netxen_nic_phan_reg.h Consolidate register definitions in netxen_nic_hdr.h Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index fa43aa0..7a93f82 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -53,6 +53,7 @@ #include #include +#include "netxen_nic_hdr.h" #include "netxen_nic_hw.h" #define _NETXEN_NIC_LINUX_MAJOR 4 @@ -227,8 +228,6 @@ #define MPORT_SINGLE_FUNCTION_MODE 0x1111 #define MPORT_MULTI_FUNCTION_MODE 0x2222 -#include "netxen_nic_phan_reg.h" - /* * NetXen host-peg signal message structure * @@ -503,17 +502,11 @@ struct netxen_skb_frag { u64 length; }; -#define _netxen_set_bits(config_word, start, bits, val) {\ - unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start));\ - unsigned long long __tvalue = (val); \ - (config_word) &= ~__tmask; \ - (config_word) |= (((__tvalue) << (start)) & __tmask); \ -} - -#define _netxen_clear_bits(config_word, start, bits) {\ - unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start)); \ - (config_word) &= ~__tmask; \ -} +struct netxen_recv_crb { + u32 crb_rcv_producer[NUM_RCV_DESC_RINGS]; + u32 crb_sts_consumer[NUM_STS_DESC_RINGS]; + u32 sw_int_mask[NUM_STS_DESC_RINGS]; +}; /* Following defines are for the state of the buffers */ #define NETXEN_BUFFER_FREE 0 @@ -1194,6 +1187,18 @@ struct netxen_adapter { const struct firmware *fw; }; +/* Set promiscuous mode for a GbE interface */ +int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode); +int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, + u32 mode); +/* Generic enable for GbE ports. Will detect the speed of the link. */ +int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port); +int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port); + +/* Disable a GbE interface */ +int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter); +int netxen_niu_disable_xg_port(struct netxen_adapter *adapter); + int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 9e04696..3d676fe 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -30,7 +30,6 @@ #include "netxen_nic_hw.h" #include "netxen_nic.h" -#include "netxen_nic_phan_reg.h" #define NXHAL_VERSION 1 diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index db66e70..3886135 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -37,7 +37,6 @@ #include "netxen_nic.h" #include "netxen_nic_hw.h" -#include "netxen_nic_phan_reg.h" struct netxen_nic_stats { char stat_string[ETH_GSTRING_LEN]; diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index a732858..c4a4a8b 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -723,9 +723,92 @@ enum { #define NETXEN_FW_VERSION_MINOR (NETXEN_CAM_RAM(0x154)) #define NETXEN_FW_VERSION_SUB (NETXEN_CAM_RAM(0x158)) #define NETXEN_ROM_LOCK_ID (NETXEN_CAM_RAM(0x100)) +#define NETXEN_PHY_LOCK_ID (NETXEN_CAM_RAM(0x120)) #define NETXEN_CRB_WIN_LOCK_ID (NETXEN_CAM_RAM(0x124)) -#define NETXEN_PHY_LOCK_ID (NETXEN_CAM_RAM(0x120)) +#define NIC_CRB_BASE (NETXEN_CAM_RAM(0x200)) +#define NIC_CRB_BASE_2 (NETXEN_CAM_RAM(0x700)) +#define NETXEN_NIC_REG(X) (NIC_CRB_BASE+(X)) +#define NETXEN_NIC_REG_2(X) (NIC_CRB_BASE_2+(X)) + +#define NX_CDRP_CRB_OFFSET (NETXEN_NIC_REG(0x18)) +#define NX_ARG1_CRB_OFFSET (NETXEN_NIC_REG(0x1c)) +#define NX_ARG2_CRB_OFFSET (NETXEN_NIC_REG(0x20)) +#define NX_ARG3_CRB_OFFSET (NETXEN_NIC_REG(0x24)) +#define NX_SIGN_CRB_OFFSET (NETXEN_NIC_REG(0x28)) + +#define CRB_HOST_DUMMY_BUF_ADDR_HI (NETXEN_NIC_REG(0x3c)) +#define CRB_HOST_DUMMY_BUF_ADDR_LO (NETXEN_NIC_REG(0x40)) + +#define CRB_CMDPEG_STATE (NETXEN_NIC_REG(0x50)) +#define CRB_RCVPEG_STATE (NETXEN_NIC_REG(0x13c)) + +#define CRB_XG_STATE (NETXEN_NIC_REG(0x94)) +#define CRB_XG_STATE_P3 (NETXEN_NIC_REG(0x98)) +#define CRB_PF_LINK_SPEED_1 (NETXEN_NIC_REG(0xe8)) +#define CRB_PF_LINK_SPEED_2 (NETXEN_NIC_REG(0xec)) + +#define CRB_MPORT_MODE (NETXEN_NIC_REG(0xc4)) +#define CRB_DMA_SHIFT (NETXEN_NIC_REG(0xcc)) +#define CRB_INT_VECTOR (NETXEN_NIC_REG(0xd4)) + +#define CRB_CMD_PRODUCER_OFFSET (NETXEN_NIC_REG(0x08)) +#define CRB_CMD_CONSUMER_OFFSET (NETXEN_NIC_REG(0x0c)) +#define CRB_CMD_PRODUCER_OFFSET_1 (NETXEN_NIC_REG(0x1ac)) +#define CRB_CMD_CONSUMER_OFFSET_1 (NETXEN_NIC_REG(0x1b0)) +#define CRB_CMD_PRODUCER_OFFSET_2 (NETXEN_NIC_REG(0x1b8)) +#define CRB_CMD_CONSUMER_OFFSET_2 (NETXEN_NIC_REG(0x1bc)) +#define CRB_CMD_PRODUCER_OFFSET_3 (NETXEN_NIC_REG(0x1d0)) +#define CRB_CMD_CONSUMER_OFFSET_3 (NETXEN_NIC_REG(0x1d4)) +#define CRB_TEMP_STATE (NETXEN_NIC_REG(0x1b4)) + +#define CRB_V2P_0 (NETXEN_NIC_REG(0x290)) +#define CRB_V2P(port) (CRB_V2P_0+((port)*4)) +#define CRB_DRIVER_VERSION (NETXEN_NIC_REG(0x2a0)) + +#define CRB_SW_INT_MASK_0 (NETXEN_NIC_REG(0x1d8)) +#define CRB_SW_INT_MASK_1 (NETXEN_NIC_REG(0x1e0)) +#define CRB_SW_INT_MASK_2 (NETXEN_NIC_REG(0x1e4)) +#define CRB_SW_INT_MASK_3 (NETXEN_NIC_REG(0x1e8)) + +#define CRB_FW_CAPABILITIES_1 (NETXEN_CAM_RAM(0x128)) +#define CRB_MAC_BLOCK_START (NETXEN_CAM_RAM(0x1c0)) + +/* + * capabilities register, can be used to selectively enable/disable features + * for backward compability + */ +#define CRB_NIC_CAPABILITIES_HOST NETXEN_NIC_REG(0x1a8) +#define CRB_NIC_CAPABILITIES_FW NETXEN_NIC_REG(0x1dc) +#define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270) +#define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) + +#define INTR_SCHEME_PERPORT 0x1 +#define MSI_MODE_MULTIFUNC 0x1 + +/* used for ethtool tests */ +#define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280) + +/* + * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address + * which can be read by the Phantom host to get producer/consumer indexes from + * Phantom/Casper. If it is not HOST_SHARED_MEMORY, then the following + * registers will be used for the addresses of the ring's shared memory + * on the Phantom. + */ + +#define nx_get_temp_val(x) ((x) >> 16) +#define nx_get_temp_state(x) ((x) & 0xffff) +#define nx_encode_temp(val, state) (((val) << 16) | (state)) + +/* + * Temperature control. + */ +enum { + NX_TEMP_NORMAL = 0x1, /* Normal operating range */ + NX_TEMP_WARN, /* Sound alert, temperature getting high */ + NX_TEMP_PANIC /* Fatal error, hardware has shut down. */ +}; /* Lock IDs for PHY lock */ #define PHY_LOCK_DRIVER 0x44524956 diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 965f783..9138bbc 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -30,7 +30,6 @@ #include "netxen_nic.h" #include "netxen_nic_hw.h" -#include "netxen_nic_phan_reg.h" #include diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index d4e8333..fc0638f 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -31,8 +31,6 @@ #ifndef __NETXEN_NIC_HW_H_ #define __NETXEN_NIC_HW_H_ -#include "netxen_nic_hdr.h" - /* Hardware memory size of 128 meg */ #define NETXEN_MEMADDR_MAX (128 * 1024 * 1024) @@ -387,22 +385,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); #define netxen_xg_soft_reset(config_word) \ ((config_word) |= 1 << 4) -/* Set promiscuous mode for a GbE interface */ -int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, - u32 mode); -int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, - u32 mode); - -/* Generic enable for GbE ports. Will detect the speed of the link. */ -int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port); - -int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port); - -/* Disable a GbE interface */ -int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter); - -int netxen_niu_disable_xg_port(struct netxen_adapter *adapter); - typedef struct { unsigned valid; unsigned start_128M; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index c3609e4..474c568 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -32,7 +32,6 @@ #include #include "netxen_nic.h" #include "netxen_nic_hw.h" -#include "netxen_nic_phan_reg.h" struct crb_addr_pair { u32 addr; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 794c19b..bd4589f 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -33,7 +33,6 @@ #include "netxen_nic_hw.h" #include "netxen_nic.h" -#include "netxen_nic_phan_reg.h" #include #include diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h deleted file mode 100644 index b73a62c..0000000 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2003 - 2009 NetXen, Inc. - * All rights reserved. - * - * 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. - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE. - * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * - */ - -#ifndef __NIC_PHAN_REG_H_ -#define __NIC_PHAN_REG_H_ - -/* - * CRB Registers or queue message done only at initialization time. - */ -#define NIC_CRB_BASE NETXEN_CAM_RAM(0x200) -#define NETXEN_NIC_REG(X) (NIC_CRB_BASE+(X)) -#define NIC_CRB_BASE_2 NETXEN_CAM_RAM(0x700) -#define NETXEN_NIC_REG_2(X) (NIC_CRB_BASE_2+(X)) - -#define CRB_PHAN_CNTRL_LO_OFFSET NETXEN_NIC_REG(0x00) -#define CRB_PHAN_CNTRL_HI_OFFSET NETXEN_NIC_REG(0x04) -#define CRB_CMD_PRODUCER_OFFSET NETXEN_NIC_REG(0x08) -#define CRB_CMD_CONSUMER_OFFSET NETXEN_NIC_REG(0x0c) -#define CRB_PAUSE_ADDR_LO NETXEN_NIC_REG(0x10) -#define CRB_PAUSE_ADDR_HI NETXEN_NIC_REG(0x14) -#define NX_CDRP_CRB_OFFSET NETXEN_NIC_REG(0x18) -#define NX_ARG1_CRB_OFFSET NETXEN_NIC_REG(0x1c) -#define NX_ARG2_CRB_OFFSET NETXEN_NIC_REG(0x20) -#define NX_ARG3_CRB_OFFSET NETXEN_NIC_REG(0x24) -#define NX_SIGN_CRB_OFFSET NETXEN_NIC_REG(0x28) -#define CRB_CMD_INTR_LOOP NETXEN_NIC_REG(0x20) -#define CRB_CMD_DMA_LOOP NETXEN_NIC_REG(0x24) -#define CRB_RCV_INTR_LOOP NETXEN_NIC_REG(0x28) -#define CRB_RCV_DMA_LOOP NETXEN_NIC_REG(0x2c) -#define CRB_ENABLE_TX_INTR NETXEN_NIC_REG(0x30) -#define CRB_MMAP_ADDR_3 NETXEN_NIC_REG(0x34) -#define CRB_CMDPEG_CMDRING NETXEN_NIC_REG(0x38) -#define CRB_HOST_DUMMY_BUF_ADDR_HI NETXEN_NIC_REG(0x3c) -#define CRB_HOST_DUMMY_BUF_ADDR_LO NETXEN_NIC_REG(0x40) -#define CRB_MMAP_ADDR_0 NETXEN_NIC_REG(0x44) -#define CRB_MMAP_ADDR_1 NETXEN_NIC_REG(0x48) -#define CRB_MMAP_ADDR_2 NETXEN_NIC_REG(0x4c) -#define CRB_CMDPEG_STATE NETXEN_NIC_REG(0x50) -#define CRB_MMAP_SIZE_0 NETXEN_NIC_REG(0x54) -#define CRB_MMAP_SIZE_1 NETXEN_NIC_REG(0x58) -#define CRB_MMAP_SIZE_2 NETXEN_NIC_REG(0x5c) -#define CRB_MMAP_SIZE_3 NETXEN_NIC_REG(0x60) -#define CRB_GLOBAL_INT_COAL NETXEN_NIC_REG(0x64) -#define CRB_INT_COAL_MODE NETXEN_NIC_REG(0x68) -#define CRB_MAX_RCV_BUFS NETXEN_NIC_REG(0x6c) -#define CRB_TX_INT_THRESHOLD NETXEN_NIC_REG(0x70) -#define CRB_RX_PKT_TIMER NETXEN_NIC_REG(0x74) -#define CRB_TX_PKT_TIMER NETXEN_NIC_REG(0x78) -#define CRB_RX_PKT_CNT NETXEN_NIC_REG(0x7c) -#define CRB_RX_TMR_CNT NETXEN_NIC_REG(0x80) -#define CRB_RX_LRO_TIMER NETXEN_NIC_REG(0x84) -#define CRB_RX_LRO_MID_TIMER NETXEN_NIC_REG(0x88) -#define CRB_DMA_MAX_RCV_BUFS NETXEN_NIC_REG(0x8c) -#define CRB_MAX_DMA_ENTRIES NETXEN_NIC_REG(0x90) -#define CRB_XG_STATE NETXEN_NIC_REG(0x94) /* XG Link status */ -#define CRB_XG_STATE_P3 NETXEN_NIC_REG(0x98) /* XG PF Link status */ -#define CRB_AGENT_TX_SIZE NETXEN_NIC_REG(0x9c) -#define CRB_AGENT_TX_TYPE NETXEN_NIC_REG(0xa0) -#define CRB_AGENT_TX_ADDR NETXEN_NIC_REG(0xa4) -#define CRB_AGENT_TX_MSS NETXEN_NIC_REG(0xa8) -#define CRB_TX_STATE NETXEN_NIC_REG(0xac) -#define CRB_TX_COUNT NETXEN_NIC_REG(0xb0) -#define CRB_RX_STATE NETXEN_NIC_REG(0xb4) -#define CRB_RX_PERF_DEBUG_1 NETXEN_NIC_REG(0xb8) -#define CRB_RX_LRO_CONTROL NETXEN_NIC_REG(0xbc) -#define CRB_RX_LRO_START_NUM NETXEN_NIC_REG(0xc0) -#define CRB_MPORT_MODE NETXEN_NIC_REG(0xc4) -#define CRB_CMD_RING_SIZE NETXEN_NIC_REG(0xc8) -#define CRB_DMA_SHIFT NETXEN_NIC_REG(0xcc) -#define CRB_INT_VECTOR NETXEN_NIC_REG(0xd4) -#define CRB_CTX_RESET NETXEN_NIC_REG(0xd8) -#define CRB_HOST_STS_PROD NETXEN_NIC_REG(0xdc) -#define CRB_HOST_STS_CONS NETXEN_NIC_REG(0xe0) -#define CRB_PEG_CMD_PROD NETXEN_NIC_REG(0xe4) -#define CRB_PF_LINK_SPEED_1 NETXEN_NIC_REG(0xe8) -#define CRB_PF_LINK_SPEED_2 NETXEN_NIC_REG(0xec) -#define CRB_HOST_BUFFER_CONS NETXEN_NIC_REG(0xf0) -#define CRB_JUMBO_BUFFER_PROD NETXEN_NIC_REG(0xf4) -#define CRB_JUMBO_BUFFER_CONS NETXEN_NIC_REG(0xf8) -#define CRB_HOST_DUMMY_BUF NETXEN_NIC_REG(0xfc) - -#define CRB_RCVPEG_STATE NETXEN_NIC_REG(0x13c) -#define CRB_CMD_PRODUCER_OFFSET_1 NETXEN_NIC_REG(0x1ac) -#define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0) -#define CRB_CMD_PRODUCER_OFFSET_2 NETXEN_NIC_REG(0x1b8) -#define CRB_CMD_CONSUMER_OFFSET_2 NETXEN_NIC_REG(0x1bc) -#define CRB_CMD_PRODUCER_OFFSET_3 NETXEN_NIC_REG(0x1d0) -#define CRB_CMD_CONSUMER_OFFSET_3 NETXEN_NIC_REG(0x1d4) -#define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4) - -#define CRB_V2P_0 NETXEN_NIC_REG(0x290) -#define CRB_V2P_1 NETXEN_NIC_REG(0x294) -#define CRB_V2P_2 NETXEN_NIC_REG(0x298) -#define CRB_V2P_3 NETXEN_NIC_REG(0x29c) -#define CRB_V2P(port) (CRB_V2P_0+((port)*4)) -#define CRB_DRIVER_VERSION NETXEN_NIC_REG(0x2a0) -#define CRB_SW_INT_MASK_0 NETXEN_NIC_REG(0x1d8) -#define CRB_SW_INT_MASK_1 NETXEN_NIC_REG(0x1e0) -#define CRB_SW_INT_MASK_2 NETXEN_NIC_REG(0x1e4) -#define CRB_SW_INT_MASK_3 NETXEN_NIC_REG(0x1e8) - -#define CRB_FW_CAPABILITIES_1 NETXEN_CAM_RAM(0x128) -#define CRB_MAC_BLOCK_START NETXEN_CAM_RAM(0x1c0) - -/* - * capabilities register, can be used to selectively enable/disable features - * for backward compability - */ -#define CRB_NIC_CAPABILITIES_HOST NETXEN_NIC_REG(0x1a8) -#define CRB_NIC_CAPABILITIES_FW NETXEN_NIC_REG(0x1dc) -#define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270) -#define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) - -#define INTR_SCHEME_PERPORT 0x1 -#define MSI_MODE_MULTIFUNC 0x1 - -/* used for ethtool tests */ -#define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280) - -/* - * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address - * which can be read by the Phantom host to get producer/consumer indexes from - * Phantom/Casper. If it is not HOST_SHARED_MEMORY, then the following - * registers will be used for the addresses of the ring's shared memory - * on the Phantom. - */ - -#define nx_get_temp_val(x) ((x) >> 16) -#define nx_get_temp_state(x) ((x) & 0xffff) -#define nx_encode_temp(val, state) (((val) << 16) | (state)) - -/* - * CRB registers used by the receive peg logic. - */ - -struct netxen_recv_crb { - u32 crb_rcv_producer[NUM_RCV_DESC_RINGS]; - u32 crb_sts_consumer[NUM_STS_DESC_RINGS]; - u32 sw_int_mask[NUM_STS_DESC_RINGS]; -}; - -/* - * Temperature control. - */ -enum { - NX_TEMP_NORMAL = 0x1, /* Normal operating range */ - NX_TEMP_WARN, /* Sound alert, temperature getting high */ - NX_TEMP_PANIC /* Fatal error, hardware has shut down. */ -}; - -#endif /* __NIC_PHAN_REG_H_ */ -- cgit v0.10.2 From 70041088e3b976627ba9a183b812f39ef8a9ba0e Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 21 Aug 2009 12:28:31 +0000 Subject: RDS: Add TCP transport to RDS This code allows RDS to be tunneled over a TCP connection. RDMA operations are disabled when using TCP transport, but this frees RDS from the IB/RDMA stack dependency, and allows it to be used with standard Ethernet adapters, or in a VM. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/include/linux/rds.h b/include/linux/rds.h index d91dc91..89d46e1 100644 --- a/include/linux/rds.h +++ b/include/linux/rds.h @@ -147,6 +147,18 @@ struct rds_info_socket { u_int64_t inum; } __attribute__((packed)); +struct rds_info_tcp_socket { + __be32 local_addr; + __be16 local_port; + __be32 peer_addr; + __be16 peer_port; + u_int64_t hdr_rem; + u_int64_t data_rem; + u_int32_t last_sent_nxt; + u_int32_t last_expected_una; + u_int32_t last_seen_una; +} __attribute__((packed)); + #define RDS_IB_GID_LEN 16 struct rds_info_rdma_connection { __be32 src_addr; diff --git a/net/rds/tcp.c b/net/rds/tcp.c new file mode 100644 index 0000000..e0ac900 --- /dev/null +++ b/net/rds/tcp.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2006 Oracle. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include +#include +#include + +#include "rds.h" +#include "tcp.h" + +/* only for info exporting */ +static DEFINE_SPINLOCK(rds_tcp_tc_list_lock); +static LIST_HEAD(rds_tcp_tc_list); +unsigned int rds_tcp_tc_count; + +/* Track rds_tcp_connection structs so they can be cleaned up */ +static DEFINE_SPINLOCK(rds_tcp_conn_lock); +static LIST_HEAD(rds_tcp_conn_list); + +static struct kmem_cache *rds_tcp_conn_slab; + +#define RDS_TCP_DEFAULT_BUFSIZE (128 * 1024) + +/* doing it this way avoids calling tcp_sk() */ +void rds_tcp_nonagle(struct socket *sock) +{ + mm_segment_t oldfs = get_fs(); + int val = 1; + + set_fs(KERNEL_DS); + sock->ops->setsockopt(sock, SOL_TCP, TCP_NODELAY, (char __user *)&val, + sizeof(val)); + set_fs(oldfs); +} + +void rds_tcp_tune(struct socket *sock) +{ + struct sock *sk = sock->sk; + + rds_tcp_nonagle(sock); + + /* + * We're trying to saturate gigabit with the default, + * see svc_sock_setbufsize(). + */ + lock_sock(sk); + sk->sk_sndbuf = RDS_TCP_DEFAULT_BUFSIZE; + sk->sk_rcvbuf = RDS_TCP_DEFAULT_BUFSIZE; + sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; + release_sock(sk); +} + +u32 rds_tcp_snd_nxt(struct rds_tcp_connection *tc) +{ + return tcp_sk(tc->t_sock->sk)->snd_nxt; +} + +u32 rds_tcp_snd_una(struct rds_tcp_connection *tc) +{ + return tcp_sk(tc->t_sock->sk)->snd_una; +} + +void rds_tcp_restore_callbacks(struct socket *sock, + struct rds_tcp_connection *tc) +{ + rdsdebug("restoring sock %p callbacks from tc %p\n", sock, tc); + write_lock_bh(&sock->sk->sk_callback_lock); + + /* done under the callback_lock to serialize with write_space */ + spin_lock(&rds_tcp_tc_list_lock); + list_del_init(&tc->t_list_item); + rds_tcp_tc_count--; + spin_unlock(&rds_tcp_tc_list_lock); + + tc->t_sock = NULL; + + sock->sk->sk_write_space = tc->t_orig_write_space; + sock->sk->sk_data_ready = tc->t_orig_data_ready; + sock->sk->sk_state_change = tc->t_orig_state_change; + sock->sk->sk_user_data = NULL; + + write_unlock_bh(&sock->sk->sk_callback_lock); +} + +/* + * This is the only path that sets tc->t_sock. Send and receive trust that + * it is set. The RDS_CONN_CONNECTED bit protects those paths from being + * called while it isn't set. + */ +void rds_tcp_set_callbacks(struct socket *sock, struct rds_connection *conn) +{ + struct rds_tcp_connection *tc = conn->c_transport_data; + + rdsdebug("setting sock %p callbacks to tc %p\n", sock, tc); + write_lock_bh(&sock->sk->sk_callback_lock); + + /* done under the callback_lock to serialize with write_space */ + spin_lock(&rds_tcp_tc_list_lock); + list_add_tail(&tc->t_list_item, &rds_tcp_tc_list); + rds_tcp_tc_count++; + spin_unlock(&rds_tcp_tc_list_lock); + + /* accepted sockets need our listen data ready undone */ + if (sock->sk->sk_data_ready == rds_tcp_listen_data_ready) + sock->sk->sk_data_ready = sock->sk->sk_user_data; + + tc->t_sock = sock; + tc->conn = conn; + tc->t_orig_data_ready = sock->sk->sk_data_ready; + tc->t_orig_write_space = sock->sk->sk_write_space; + tc->t_orig_state_change = sock->sk->sk_state_change; + + sock->sk->sk_user_data = conn; + sock->sk->sk_data_ready = rds_tcp_data_ready; + sock->sk->sk_write_space = rds_tcp_write_space; + sock->sk->sk_state_change = rds_tcp_state_change; + + write_unlock_bh(&sock->sk->sk_callback_lock); +} + +static void rds_tcp_tc_info(struct socket *sock, unsigned int len, + struct rds_info_iterator *iter, + struct rds_info_lengths *lens) +{ + struct rds_info_tcp_socket tsinfo; + struct rds_tcp_connection *tc; + unsigned long flags; + struct sockaddr_in sin; + int sinlen; + + spin_lock_irqsave(&rds_tcp_tc_list_lock, flags); + + if (len / sizeof(tsinfo) < rds_tcp_tc_count) + goto out; + + list_for_each_entry(tc, &rds_tcp_tc_list, t_list_item) { + + sock->ops->getname(sock, (struct sockaddr *)&sin, &sinlen, 0); + tsinfo.local_addr = sin.sin_addr.s_addr; + tsinfo.local_port = sin.sin_port; + sock->ops->getname(sock, (struct sockaddr *)&sin, &sinlen, 1); + tsinfo.peer_addr = sin.sin_addr.s_addr; + tsinfo.peer_port = sin.sin_port; + + tsinfo.hdr_rem = tc->t_tinc_hdr_rem; + tsinfo.data_rem = tc->t_tinc_data_rem; + tsinfo.last_sent_nxt = tc->t_last_sent_nxt; + tsinfo.last_expected_una = tc->t_last_expected_una; + tsinfo.last_seen_una = tc->t_last_seen_una; + + rds_info_copy(iter, &tsinfo, sizeof(tsinfo)); + } + +out: + lens->nr = rds_tcp_tc_count; + lens->each = sizeof(tsinfo); + + spin_unlock_irqrestore(&rds_tcp_tc_list_lock, flags); +} + +static int rds_tcp_laddr_check(__be32 addr) +{ + if (inet_addr_type(&init_net, addr) == RTN_LOCAL) + return 0; + return -EADDRNOTAVAIL; +} + +static int rds_tcp_conn_alloc(struct rds_connection *conn, gfp_t gfp) +{ + struct rds_tcp_connection *tc; + + tc = kmem_cache_alloc(rds_tcp_conn_slab, gfp); + if (tc == NULL) + return -ENOMEM; + + tc->t_sock = NULL; + tc->t_tinc = NULL; + tc->t_tinc_hdr_rem = sizeof(struct rds_header); + tc->t_tinc_data_rem = 0; + + conn->c_transport_data = tc; + + spin_lock_irq(&rds_tcp_conn_lock); + list_add_tail(&tc->t_tcp_node, &rds_tcp_conn_list); + spin_unlock_irq(&rds_tcp_conn_lock); + + rdsdebug("alloced tc %p\n", conn->c_transport_data); + return 0; +} + +static void rds_tcp_conn_free(void *arg) +{ + struct rds_tcp_connection *tc = arg; + rdsdebug("freeing tc %p\n", tc); + kmem_cache_free(rds_tcp_conn_slab, tc); +} + +static void rds_tcp_destroy_conns(void) +{ + struct rds_tcp_connection *tc, *_tc; + LIST_HEAD(tmp_list); + + /* avoid calling conn_destroy with irqs off */ + spin_lock_irq(&rds_tcp_conn_lock); + list_splice(&rds_tcp_conn_list, &tmp_list); + INIT_LIST_HEAD(&rds_tcp_conn_list); + spin_unlock_irq(&rds_tcp_conn_lock); + + list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) { + if (tc->conn->c_passive) + rds_conn_destroy(tc->conn->c_passive); + rds_conn_destroy(tc->conn); + } +} + +void rds_tcp_exit(void) +{ + rds_info_deregister_func(RDS_INFO_TCP_SOCKETS, rds_tcp_tc_info); + rds_tcp_listen_stop(); + rds_tcp_destroy_conns(); + rds_trans_unregister(&rds_tcp_transport); + rds_tcp_recv_exit(); + kmem_cache_destroy(rds_tcp_conn_slab); +} +module_exit(rds_tcp_exit); + +struct rds_transport rds_tcp_transport = { + .laddr_check = rds_tcp_laddr_check, + .xmit_prepare = rds_tcp_xmit_prepare, + .xmit_complete = rds_tcp_xmit_complete, + .xmit_cong_map = rds_tcp_xmit_cong_map, + .xmit = rds_tcp_xmit, + .recv = rds_tcp_recv, + .conn_alloc = rds_tcp_conn_alloc, + .conn_free = rds_tcp_conn_free, + .conn_connect = rds_tcp_conn_connect, + .conn_shutdown = rds_tcp_conn_shutdown, + .inc_copy_to_user = rds_tcp_inc_copy_to_user, + .inc_purge = rds_tcp_inc_purge, + .inc_free = rds_tcp_inc_free, + .stats_info_copy = rds_tcp_stats_info_copy, + .exit = rds_tcp_exit, + .t_owner = THIS_MODULE, + .t_name = "tcp", + .t_prefer_loopback = 1, +}; + +int __init rds_tcp_init(void) +{ + int ret; + + rds_tcp_conn_slab = kmem_cache_create("rds_tcp_connection", + sizeof(struct rds_tcp_connection), + 0, 0, NULL); + if (rds_tcp_conn_slab == NULL) { + ret = -ENOMEM; + goto out; + } + + ret = rds_tcp_recv_init(); + if (ret) + goto out_slab; + + ret = rds_trans_register(&rds_tcp_transport); + if (ret) + goto out_recv; + + ret = rds_tcp_listen_init(); + if (ret) + goto out_register; + + rds_info_register_func(RDS_INFO_TCP_SOCKETS, rds_tcp_tc_info); + + goto out; + +out_register: + rds_trans_unregister(&rds_tcp_transport); +out_recv: + rds_tcp_recv_exit(); +out_slab: + kmem_cache_destroy(rds_tcp_conn_slab); +out: + return ret; +} +module_init(rds_tcp_init); + +MODULE_AUTHOR("Oracle Corporation "); +MODULE_DESCRIPTION("RDS: TCP transport"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/net/rds/tcp.h b/net/rds/tcp.h new file mode 100644 index 0000000..844fa6b --- /dev/null +++ b/net/rds/tcp.h @@ -0,0 +1,93 @@ +#ifndef _RDS_TCP_H +#define _RDS_TCP_H + +#define RDS_TCP_PORT 16385 + +struct rds_tcp_incoming { + struct rds_incoming ti_inc; + struct sk_buff_head ti_skb_list; +}; + +struct rds_tcp_connection { + + struct list_head t_tcp_node; + struct rds_connection *conn; + struct socket *t_sock; + void *t_orig_write_space; + void *t_orig_data_ready; + void *t_orig_state_change; + + struct rds_tcp_incoming *t_tinc; + size_t t_tinc_hdr_rem; + size_t t_tinc_data_rem; + + /* XXX error report? */ + struct work_struct t_conn_w; + struct work_struct t_send_w; + struct work_struct t_down_w; + struct work_struct t_recv_w; + + /* for info exporting only */ + struct list_head t_list_item; + u32 t_last_sent_nxt; + u32 t_last_expected_una; + u32 t_last_seen_una; +}; + +struct rds_tcp_statistics { + uint64_t s_tcp_data_ready_calls; + uint64_t s_tcp_write_space_calls; + uint64_t s_tcp_sndbuf_full; + uint64_t s_tcp_connect_raced; + uint64_t s_tcp_listen_closed_stale; +}; + +/* tcp.c */ +int __init rds_tcp_init(void); +void rds_tcp_exit(void); +void rds_tcp_tune(struct socket *sock); +void rds_tcp_nonagle(struct socket *sock); +void rds_tcp_set_callbacks(struct socket *sock, struct rds_connection *conn); +void rds_tcp_restore_callbacks(struct socket *sock, + struct rds_tcp_connection *tc); +u32 rds_tcp_snd_nxt(struct rds_tcp_connection *tc); +u32 rds_tcp_snd_una(struct rds_tcp_connection *tc); +u64 rds_tcp_map_seq(struct rds_tcp_connection *tc, u32 seq); +extern struct rds_transport rds_tcp_transport; + +/* tcp_connect.c */ +int rds_tcp_conn_connect(struct rds_connection *conn); +void rds_tcp_conn_shutdown(struct rds_connection *conn); +void rds_tcp_state_change(struct sock *sk); + +/* tcp_listen.c */ +int __init rds_tcp_listen_init(void); +void rds_tcp_listen_stop(void); +void rds_tcp_listen_data_ready(struct sock *sk, int bytes); + +/* tcp_recv.c */ +int __init rds_tcp_recv_init(void); +void rds_tcp_recv_exit(void); +void rds_tcp_data_ready(struct sock *sk, int bytes); +int rds_tcp_recv(struct rds_connection *conn); +void rds_tcp_inc_purge(struct rds_incoming *inc); +void rds_tcp_inc_free(struct rds_incoming *inc); +int rds_tcp_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov, + size_t size); + +/* tcp_send.c */ +void rds_tcp_xmit_prepare(struct rds_connection *conn); +void rds_tcp_xmit_complete(struct rds_connection *conn); +int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm, + unsigned int hdr_off, unsigned int sg, unsigned int off); +void rds_tcp_write_space(struct sock *sk); +int rds_tcp_xmit_cong_map(struct rds_connection *conn, + struct rds_cong_map *map, unsigned long offset); + +/* tcp_stats.c */ +DECLARE_PER_CPU(struct rds_tcp_statistics, rds_tcp_stats); +#define rds_tcp_stats_inc(member) rds_stats_inc_which(rds_tcp_stats, member) +unsigned int rds_tcp_stats_info_copy(struct rds_info_iterator *iter, + unsigned int avail); + +#endif diff --git a/net/rds/tcp_connect.c b/net/rds/tcp_connect.c new file mode 100644 index 0000000..211522f --- /dev/null +++ b/net/rds/tcp_connect.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2006 Oracle. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include +#include +#include + +#include "rds.h" +#include "tcp.h" + +void rds_tcp_state_change(struct sock *sk) +{ + void (*state_change)(struct sock *sk); + struct rds_connection *conn; + struct rds_tcp_connection *tc; + + read_lock(&sk->sk_callback_lock); + conn = sk->sk_user_data; + if (conn == NULL) { + state_change = sk->sk_state_change; + goto out; + } + tc = conn->c_transport_data; + state_change = tc->t_orig_state_change; + + rdsdebug("sock %p state_change to %d\n", tc->t_sock, sk->sk_state); + + switch(sk->sk_state) { + /* ignore connecting sockets as they make progress */ + case TCP_SYN_SENT: + case TCP_SYN_RECV: + break; + case TCP_ESTABLISHED: + rds_connect_complete(conn); + break; + case TCP_CLOSE: + rds_conn_drop(conn); + default: + break; + } +out: + read_unlock(&sk->sk_callback_lock); + state_change(sk); +} + +int rds_tcp_conn_connect(struct rds_connection *conn) +{ + struct socket *sock = NULL; + struct sockaddr_in src, dest; + int ret; + + ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); + if (ret < 0) + goto out; + + rds_tcp_tune(sock); + + src.sin_family = AF_INET; + src.sin_addr.s_addr = (__force u32)conn->c_laddr; + src.sin_port = (__force u16)htons(0); + + ret = sock->ops->bind(sock, (struct sockaddr *)&src, sizeof(src)); + if (ret) { + rdsdebug("bind failed with %d at address %u.%u.%u.%u\n", + ret, NIPQUAD(conn->c_laddr)); + goto out; + } + + dest.sin_family = AF_INET; + dest.sin_addr.s_addr = (__force u32)conn->c_faddr; + dest.sin_port = (__force u16)htons(RDS_TCP_PORT); + + /* + * once we call connect() we can start getting callbacks and they + * own the socket + */ + rds_tcp_set_callbacks(sock, conn); + ret = sock->ops->connect(sock, (struct sockaddr *)&dest, sizeof(dest), + O_NONBLOCK); + sock = NULL; + + rdsdebug("connect to address %u.%u.%u.%u returned %d\n", + NIPQUAD(conn->c_faddr), ret); + if (ret == -EINPROGRESS) + ret = 0; + +out: + if (sock) + sock_release(sock); + return ret; +} + +/* + * Before killing the tcp socket this needs to serialize with callbacks. The + * caller has already grabbed the sending sem so we're serialized with other + * senders. + * + * TCP calls the callbacks with the sock lock so we hold it while we reset the + * callbacks to those set by TCP. Our callbacks won't execute again once we + * hold the sock lock. + */ +void rds_tcp_conn_shutdown(struct rds_connection *conn) +{ + struct rds_tcp_connection *tc = conn->c_transport_data; + struct socket *sock = tc->t_sock; + + rdsdebug("shutting down conn %p tc %p sock %p\n", conn, tc, sock); + + if (sock) { + sock->ops->shutdown(sock, RCV_SHUTDOWN | SEND_SHUTDOWN); + lock_sock(sock->sk); + rds_tcp_restore_callbacks(sock, tc); /* tc->tc_sock = NULL */ + + release_sock(sock->sk); + sock_release(sock); + }; + + if (tc->t_tinc) { + rds_inc_put(&tc->t_tinc->ti_inc); + tc->t_tinc = NULL; + } + tc->t_tinc_hdr_rem = sizeof(struct rds_header); + tc->t_tinc_data_rem = 0; +} diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c new file mode 100644 index 0000000..24b743e --- /dev/null +++ b/net/rds/tcp_listen.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2006 Oracle. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include +#include +#include + +#include "rds.h" +#include "tcp.h" + +/* + * cheesy, but simple.. + */ +static void rds_tcp_accept_worker(struct work_struct *work); +static DECLARE_WORK(rds_tcp_listen_work, rds_tcp_accept_worker); +static struct socket *rds_tcp_listen_sock; + +static int rds_tcp_accept_one(struct socket *sock) +{ + struct socket *new_sock = NULL; + struct rds_connection *conn; + int ret; + struct inet_sock *inet; + + ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type, + sock->sk->sk_protocol, &new_sock); + if (ret) + goto out; + + new_sock->type = sock->type; + new_sock->ops = sock->ops; + ret = sock->ops->accept(sock, new_sock, O_NONBLOCK); + if (ret < 0) + goto out; + + rds_tcp_tune(new_sock); + + inet = inet_sk(new_sock->sk); + + rdsdebug("accepted tcp %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", + NIPQUAD(inet->saddr), ntohs(inet->sport), + NIPQUAD(inet->daddr), ntohs(inet->dport)); + + conn = rds_conn_create(inet->saddr, inet->daddr, &rds_tcp_transport, + GFP_KERNEL); + if (IS_ERR(conn)) { + ret = PTR_ERR(conn); + goto out; + } + + /* + * see the comment above rds_queue_delayed_reconnect() + */ + if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_CONNECTING)) { + if (rds_conn_state(conn) == RDS_CONN_UP) + rds_tcp_stats_inc(s_tcp_listen_closed_stale); + else + rds_tcp_stats_inc(s_tcp_connect_raced); + rds_conn_drop(conn); + ret = 0; + goto out; + } + + rds_tcp_set_callbacks(new_sock, conn); + rds_connect_complete(conn); + new_sock = NULL; + ret = 0; + +out: + if (new_sock) + sock_release(new_sock); + return ret; +} + +static void rds_tcp_accept_worker(struct work_struct *work) +{ + while (rds_tcp_accept_one(rds_tcp_listen_sock) == 0) + cond_resched(); +} + +void rds_tcp_listen_data_ready(struct sock *sk, int bytes) +{ + void (*ready)(struct sock *sk, int bytes); + + rdsdebug("listen data ready sk %p\n", sk); + + read_lock(&sk->sk_callback_lock); + ready = sk->sk_user_data; + if (ready == NULL) { /* check for teardown race */ + ready = sk->sk_data_ready; + goto out; + } + + /* + * ->sk_data_ready is also called for a newly established child socket + * before it has been accepted and the accepter has set up their + * data_ready.. we only want to queue listen work for our listening + * socket + */ + if (sk->sk_state == TCP_LISTEN) + queue_work(rds_wq, &rds_tcp_listen_work); + +out: + read_unlock(&sk->sk_callback_lock); + ready(sk, bytes); +} + +int __init rds_tcp_listen_init(void) +{ + struct sockaddr_in sin; + struct socket *sock = NULL; + int ret; + + ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); + if (ret < 0) + goto out; + + sock->sk->sk_reuse = 1; + rds_tcp_nonagle(sock); + + write_lock_bh(&sock->sk->sk_callback_lock); + sock->sk->sk_user_data = sock->sk->sk_data_ready; + sock->sk->sk_data_ready = rds_tcp_listen_data_ready; + write_unlock_bh(&sock->sk->sk_callback_lock); + + sin.sin_family = PF_INET, + sin.sin_addr.s_addr = (__force u32)htonl(INADDR_ANY); + sin.sin_port = (__force u16)htons(RDS_TCP_PORT); + + ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin)); + if (ret < 0) + goto out; + + ret = sock->ops->listen(sock, 64); + if (ret < 0) + goto out; + + rds_tcp_listen_sock = sock; + sock = NULL; +out: + if (sock) + sock_release(sock); + return ret; +} + +void rds_tcp_listen_stop(void) +{ + struct socket *sock = rds_tcp_listen_sock; + struct sock *sk; + + if (sock == NULL) + return; + + sk = sock->sk; + + /* serialize with and prevent further callbacks */ + lock_sock(sk); + write_lock_bh(&sk->sk_callback_lock); + if (sk->sk_user_data) { + sk->sk_data_ready = sk->sk_user_data; + sk->sk_user_data = NULL; + } + write_unlock_bh(&sk->sk_callback_lock); + release_sock(sk); + + /* wait for accepts to stop and close the socket */ + flush_workqueue(rds_wq); + sock_release(sock); + rds_tcp_listen_sock = NULL; +} diff --git a/net/rds/tcp_recv.c b/net/rds/tcp_recv.c new file mode 100644 index 0000000..c00daff --- /dev/null +++ b/net/rds/tcp_recv.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2006 Oracle. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include +#include + +#include "rds.h" +#include "tcp.h" + +static struct kmem_cache *rds_tcp_incoming_slab; + +void rds_tcp_inc_purge(struct rds_incoming *inc) +{ + struct rds_tcp_incoming *tinc; + tinc = container_of(inc, struct rds_tcp_incoming, ti_inc); + rdsdebug("purging tinc %p inc %p\n", tinc, inc); + skb_queue_purge(&tinc->ti_skb_list); +} + +void rds_tcp_inc_free(struct rds_incoming *inc) +{ + struct rds_tcp_incoming *tinc; + tinc = container_of(inc, struct rds_tcp_incoming, ti_inc); + rds_tcp_inc_purge(inc); + rdsdebug("freeing tinc %p inc %p\n", tinc, inc); + kmem_cache_free(rds_tcp_incoming_slab, tinc); +} + +/* + * this is pretty lame, but, whatever. + */ +int rds_tcp_inc_copy_to_user(struct rds_incoming *inc, struct iovec *first_iov, + size_t size) +{ + struct rds_tcp_incoming *tinc; + struct iovec *iov, tmp; + struct sk_buff *skb; + unsigned long to_copy, skb_off; + int ret = 0; + + if (size == 0) + goto out; + + tinc = container_of(inc, struct rds_tcp_incoming, ti_inc); + iov = first_iov; + tmp = *iov; + + skb_queue_walk(&tinc->ti_skb_list, skb) { + skb_off = 0; + while (skb_off < skb->len) { + while (tmp.iov_len == 0) { + iov++; + tmp = *iov; + } + + to_copy = min(tmp.iov_len, size); + to_copy = min(to_copy, skb->len - skb_off); + + rdsdebug("ret %d size %zu skb %p skb_off %lu " + "skblen %d iov_base %p iov_len %zu cpy %lu\n", + ret, size, skb, skb_off, skb->len, + tmp.iov_base, tmp.iov_len, to_copy); + + /* modifies tmp as it copies */ + if (skb_copy_datagram_iovec(skb, skb_off, &tmp, + to_copy)) { + ret = -EFAULT; + goto out; + } + + size -= to_copy; + ret += to_copy; + skb_off += to_copy; + if (size == 0) + goto out; + } + } +out: + return ret; +} + +/* + * We have a series of skbs that have fragmented pieces of the congestion + * bitmap. They must add up to the exact size of the congestion bitmap. We + * use the skb helpers to copy those into the pages that make up the in-memory + * congestion bitmap for the remote address of this connection. We then tell + * the congestion core that the bitmap has been changed so that it can wake up + * sleepers. + * + * This is racing with sending paths which are using test_bit to see if the + * bitmap indicates that their recipient is congested. + */ + +static void rds_tcp_cong_recv(struct rds_connection *conn, + struct rds_tcp_incoming *tinc) +{ + struct sk_buff *skb; + unsigned int to_copy, skb_off; + unsigned int map_off; + unsigned int map_page; + struct rds_cong_map *map; + int ret; + + /* catch completely corrupt packets */ + if (be32_to_cpu(tinc->ti_inc.i_hdr.h_len) != RDS_CONG_MAP_BYTES) + return; + + map_page = 0; + map_off = 0; + map = conn->c_fcong; + + skb_queue_walk(&tinc->ti_skb_list, skb) { + skb_off = 0; + while (skb_off < skb->len) { + to_copy = min_t(unsigned int, PAGE_SIZE - map_off, + skb->len - skb_off); + + BUG_ON(map_page >= RDS_CONG_MAP_PAGES); + + /* only returns 0 or -error */ + ret = skb_copy_bits(skb, skb_off, + (void *)map->m_page_addrs[map_page] + map_off, + to_copy); + BUG_ON(ret != 0); + + skb_off += to_copy; + map_off += to_copy; + if (map_off == PAGE_SIZE) { + map_off = 0; + map_page++; + } + } + } + + rds_cong_map_updated(map, ~(u64) 0); +} + +struct rds_tcp_desc_arg { + struct rds_connection *conn; + gfp_t gfp; + enum km_type km; +}; + +static int rds_tcp_data_recv(read_descriptor_t *desc, struct sk_buff *skb, + unsigned int offset, size_t len) +{ + struct rds_tcp_desc_arg *arg = desc->arg.data; + struct rds_connection *conn = arg->conn; + struct rds_tcp_connection *tc = conn->c_transport_data; + struct rds_tcp_incoming *tinc = tc->t_tinc; + struct sk_buff *clone; + size_t left = len, to_copy; + + rdsdebug("tcp data tc %p skb %p offset %u len %zu\n", tc, skb, offset, + len); + + /* + * tcp_read_sock() interprets partial progress as an indication to stop + * processing. + */ + while (left) { + if (tinc == NULL) { + tinc = kmem_cache_alloc(rds_tcp_incoming_slab, + arg->gfp); + if (tinc == NULL) { + desc->error = -ENOMEM; + goto out; + } + tc->t_tinc = tinc; + rdsdebug("alloced tinc %p\n", tinc); + rds_inc_init(&tinc->ti_inc, conn, conn->c_faddr); + /* + * XXX * we might be able to use the __ variants when + * we've already serialized at a higher level. + */ + skb_queue_head_init(&tinc->ti_skb_list); + } + + if (left && tc->t_tinc_hdr_rem) { + to_copy = min(tc->t_tinc_hdr_rem, left); + rdsdebug("copying %zu header from skb %p\n", to_copy, + skb); + skb_copy_bits(skb, offset, + (char *)&tinc->ti_inc.i_hdr + + sizeof(struct rds_header) - + tc->t_tinc_hdr_rem, + to_copy); + tc->t_tinc_hdr_rem -= to_copy; + left -= to_copy; + offset += to_copy; + + if (tc->t_tinc_hdr_rem == 0) { + /* could be 0 for a 0 len message */ + tc->t_tinc_data_rem = + be32_to_cpu(tinc->ti_inc.i_hdr.h_len); + } + } + + if (left && tc->t_tinc_data_rem) { + clone = skb_clone(skb, arg->gfp); + if (clone == NULL) { + desc->error = -ENOMEM; + goto out; + } + + to_copy = min(tc->t_tinc_data_rem, left); + pskb_pull(clone, offset); + pskb_trim(clone, to_copy); + skb_queue_tail(&tinc->ti_skb_list, clone); + + rdsdebug("skb %p data %p len %d off %u to_copy %zu -> " + "clone %p data %p len %d\n", + skb, skb->data, skb->len, offset, to_copy, + clone, clone->data, clone->len); + + tc->t_tinc_data_rem -= to_copy; + left -= to_copy; + offset += to_copy; + } + + if (tc->t_tinc_hdr_rem == 0 && tc->t_tinc_data_rem == 0) { + if (tinc->ti_inc.i_hdr.h_flags == RDS_FLAG_CONG_BITMAP) + rds_tcp_cong_recv(conn, tinc); + else + rds_recv_incoming(conn, conn->c_faddr, + conn->c_laddr, &tinc->ti_inc, + arg->gfp, arg->km); + + tc->t_tinc_hdr_rem = sizeof(struct rds_header); + tc->t_tinc_data_rem = 0; + tc->t_tinc = NULL; + rds_inc_put(&tinc->ti_inc); + tinc = NULL; + } + } +out: + rdsdebug("returning len %zu left %zu skb len %d rx queue depth %d\n", + len, left, skb->len, + skb_queue_len(&tc->t_sock->sk->sk_receive_queue)); + return len - left; +} + +/* the caller has to hold the sock lock */ +int rds_tcp_read_sock(struct rds_connection *conn, gfp_t gfp, enum km_type km) +{ + struct rds_tcp_connection *tc = conn->c_transport_data; + struct socket *sock = tc->t_sock; + read_descriptor_t desc; + struct rds_tcp_desc_arg arg; + + /* It's like glib in the kernel! */ + arg.conn = conn; + arg.gfp = gfp; + arg.km = km; + desc.arg.data = &arg; + desc.error = 0; + desc.count = 1; /* give more than one skb per call */ + + tcp_read_sock(sock->sk, &desc, rds_tcp_data_recv); + rdsdebug("tcp_read_sock for tc %p gfp 0x%x returned %d\n", tc, gfp, + desc.error); + + return desc.error; +} + +/* + * We hold the sock lock to serialize our rds_tcp_recv->tcp_read_sock from + * data_ready. + * + * if we fail to allocate we're in trouble.. blindly wait some time before + * trying again to see if the VM can free up something for us. + */ +int rds_tcp_recv(struct rds_connection *conn) +{ + struct rds_tcp_connection *tc = conn->c_transport_data; + struct socket *sock = tc->t_sock; + int ret = 0; + + rdsdebug("recv worker conn %p tc %p sock %p\n", conn, tc, sock); + + lock_sock(sock->sk); + ret = rds_tcp_read_sock(conn, GFP_KERNEL, KM_USER0); + release_sock(sock->sk); + + return ret; +} + +void rds_tcp_data_ready(struct sock *sk, int bytes) +{ + void (*ready)(struct sock *sk, int bytes); + struct rds_connection *conn; + struct rds_tcp_connection *tc; + + rdsdebug("data ready sk %p bytes %d\n", sk, bytes); + + read_lock(&sk->sk_callback_lock); + conn = sk->sk_user_data; + if (conn == NULL) { /* check for teardown race */ + ready = sk->sk_data_ready; + goto out; + } + + tc = conn->c_transport_data; + ready = tc->t_orig_data_ready; + rds_tcp_stats_inc(s_tcp_data_ready_calls); + + if (rds_tcp_read_sock(conn, GFP_ATOMIC, KM_SOFTIRQ0) == -ENOMEM) + queue_delayed_work(rds_wq, &conn->c_recv_w, 0); +out: + read_unlock(&sk->sk_callback_lock); + ready(sk, bytes); +} + +int __init rds_tcp_recv_init(void) +{ + rds_tcp_incoming_slab = kmem_cache_create("rds_tcp_incoming", + sizeof(struct rds_tcp_incoming), + 0, 0, NULL); + if (rds_tcp_incoming_slab == NULL) + return -ENOMEM; + return 0; +} + +void rds_tcp_recv_exit(void) +{ + kmem_cache_destroy(rds_tcp_incoming_slab); +} diff --git a/net/rds/tcp_send.c b/net/rds/tcp_send.c new file mode 100644 index 0000000..ab545e0 --- /dev/null +++ b/net/rds/tcp_send.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2006 Oracle. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include +#include +#include + +#include "rds.h" +#include "tcp.h" + +static void rds_tcp_cork(struct socket *sock, int val) +{ + mm_segment_t oldfs; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + sock->ops->setsockopt(sock, SOL_TCP, TCP_CORK, (char __user *)&val, + sizeof(val)); + set_fs(oldfs); +} + +void rds_tcp_xmit_prepare(struct rds_connection *conn) +{ + struct rds_tcp_connection *tc = conn->c_transport_data; + + rds_tcp_cork(tc->t_sock, 1); +} + +void rds_tcp_xmit_complete(struct rds_connection *conn) +{ + struct rds_tcp_connection *tc = conn->c_transport_data; + + rds_tcp_cork(tc->t_sock, 0); +} + +/* the core send_sem serializes this with other xmit and shutdown */ +int rds_tcp_sendmsg(struct socket *sock, void *data, unsigned int len) +{ + struct kvec vec = { + .iov_base = data, + .iov_len = len, + }; + struct msghdr msg = { + .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL, + }; + + return kernel_sendmsg(sock, &msg, &vec, 1, vec.iov_len); +} + +/* the core send_sem serializes this with other xmit and shutdown */ +int rds_tcp_xmit_cong_map(struct rds_connection *conn, + struct rds_cong_map *map, unsigned long offset) +{ + static struct rds_header rds_tcp_map_header = { + .h_flags = RDS_FLAG_CONG_BITMAP, + }; + struct rds_tcp_connection *tc = conn->c_transport_data; + unsigned long i; + int ret; + int copied = 0; + + /* Some problem claims cpu_to_be32(constant) isn't a constant. */ + rds_tcp_map_header.h_len = cpu_to_be32(RDS_CONG_MAP_BYTES); + + if (offset < sizeof(struct rds_header)) { + ret = rds_tcp_sendmsg(tc->t_sock, + (void *)&rds_tcp_map_header + offset, + sizeof(struct rds_header) - offset); + if (ret <= 0) + return ret; + offset += ret; + copied = ret; + if (offset < sizeof(struct rds_header)) + return ret; + } + + offset -= sizeof(struct rds_header); + i = offset / PAGE_SIZE; + offset = offset % PAGE_SIZE; + BUG_ON(i >= RDS_CONG_MAP_PAGES); + + do { + ret = tc->t_sock->ops->sendpage(tc->t_sock, + virt_to_page(map->m_page_addrs[i]), + offset, PAGE_SIZE - offset, + MSG_DONTWAIT); + if (ret <= 0) + break; + copied += ret; + offset += ret; + if (offset == PAGE_SIZE) { + offset = 0; + i++; + } + } while (i < RDS_CONG_MAP_PAGES); + + return copied ? copied : ret; +} + +/* the core send_sem serializes this with other xmit and shutdown */ +int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm, + unsigned int hdr_off, unsigned int sg, unsigned int off) +{ + struct rds_tcp_connection *tc = conn->c_transport_data; + int done = 0; + int ret = 0; + + if (hdr_off == 0) { + /* + * m_ack_seq is set to the sequence number of the last byte of + * header and data. see rds_tcp_is_acked(). + */ + tc->t_last_sent_nxt = rds_tcp_snd_nxt(tc); + rm->m_ack_seq = tc->t_last_sent_nxt + + sizeof(struct rds_header) + + be32_to_cpu(rm->m_inc.i_hdr.h_len) - 1; + smp_mb__before_clear_bit(); + set_bit(RDS_MSG_HAS_ACK_SEQ, &rm->m_flags); + tc->t_last_expected_una = rm->m_ack_seq + 1; + + rdsdebug("rm %p tcp nxt %u ack_seq %llu\n", + rm, rds_tcp_snd_nxt(tc), + (unsigned long long)rm->m_ack_seq); + } + + if (hdr_off < sizeof(struct rds_header)) { + /* see rds_tcp_write_space() */ + set_bit(SOCK_NOSPACE, &tc->t_sock->sk->sk_socket->flags); + + ret = rds_tcp_sendmsg(tc->t_sock, + (void *)&rm->m_inc.i_hdr + hdr_off, + sizeof(rm->m_inc.i_hdr) - hdr_off); + if (ret < 0) + goto out; + done += ret; + if (hdr_off + done != sizeof(struct rds_header)) + goto out; + } + + while (sg < rm->m_nents) { + ret = tc->t_sock->ops->sendpage(tc->t_sock, + sg_page(&rm->m_sg[sg]), + rm->m_sg[sg].offset + off, + rm->m_sg[sg].length - off, + MSG_DONTWAIT|MSG_NOSIGNAL); + rdsdebug("tcp sendpage %p:%u:%u ret %d\n", (void *)sg_page(&rm->m_sg[sg]), + rm->m_sg[sg].offset + off, rm->m_sg[sg].length - off, + ret); + if (ret <= 0) + break; + + off += ret; + done += ret; + if (off == rm->m_sg[sg].length) { + off = 0; + sg++; + } + } + +out: + if (ret <= 0) { + /* write_space will hit after EAGAIN, all else fatal */ + if (ret == -EAGAIN) { + rds_tcp_stats_inc(s_tcp_sndbuf_full); + ret = 0; + } else { + printk(KERN_WARNING "RDS/tcp: send to %u.%u.%u.%u " + "returned %d, disconnecting and reconnecting\n", + NIPQUAD(conn->c_faddr), ret); + rds_conn_drop(conn); + } + } + if (done == 0) + done = ret; + return done; +} + +/* + * rm->m_ack_seq is set to the tcp sequence number that corresponds to the + * last byte of the message, including the header. This means that the + * entire message has been received if rm->m_ack_seq is "before" the next + * unacked byte of the TCP sequence space. We have to do very careful + * wrapping 32bit comparisons here. + */ +static int rds_tcp_is_acked(struct rds_message *rm, uint64_t ack) +{ + if (!test_bit(RDS_MSG_HAS_ACK_SEQ, &rm->m_flags)) + return 0; + return (__s32)((u32)rm->m_ack_seq - (u32)ack) < 0; +} + +void rds_tcp_write_space(struct sock *sk) +{ + void (*write_space)(struct sock *sk); + struct rds_connection *conn; + struct rds_tcp_connection *tc; + + read_lock(&sk->sk_callback_lock); + conn = sk->sk_user_data; + if (conn == NULL) { + write_space = sk->sk_write_space; + goto out; + } + + tc = conn->c_transport_data; + rdsdebug("write_space for tc %p\n", tc); + write_space = tc->t_orig_write_space; + rds_tcp_stats_inc(s_tcp_write_space_calls); + + rdsdebug("tcp una %u\n", rds_tcp_snd_una(tc)); + tc->t_last_seen_una = rds_tcp_snd_una(tc); + rds_send_drop_acked(conn, rds_tcp_snd_una(tc), rds_tcp_is_acked); + + queue_delayed_work(rds_wq, &conn->c_send_w, 0); +out: + read_unlock(&sk->sk_callback_lock); + + /* + * write_space is only called when data leaves tcp's send queue if + * SOCK_NOSPACE is set. We set SOCK_NOSPACE every time we put + * data in tcp's send queue because we use write_space to parse the + * sequence numbers and notice that rds messages have been fully + * received. + * + * tcp's write_space clears SOCK_NOSPACE if the send queue has more + * than a certain amount of space. So we need to set it again *after* + * we call tcp's write_space or else we might only get called on the + * first of a series of incoming tcp acks. + */ + write_space(sk); + + if (sk->sk_socket) + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); +} diff --git a/net/rds/tcp_stats.c b/net/rds/tcp_stats.c new file mode 100644 index 0000000..d5898d0 --- /dev/null +++ b/net/rds/tcp_stats.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2006 Oracle. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include +#include +#include + +#include "rds.h" +#include "tcp.h" + +DEFINE_PER_CPU(struct rds_tcp_statistics, rds_tcp_stats) + ____cacheline_aligned; + +static const char const *rds_tcp_stat_names[] = { + "tcp_data_ready_calls", + "tcp_write_space_calls", + "tcp_sndbuf_full", + "tcp_connect_raced", + "tcp_listen_closed_stale", +}; + +unsigned int rds_tcp_stats_info_copy(struct rds_info_iterator *iter, + unsigned int avail) +{ + struct rds_tcp_statistics stats = {0, }; + uint64_t *src; + uint64_t *sum; + size_t i; + int cpu; + + if (avail < ARRAY_SIZE(rds_tcp_stat_names)) + goto out; + + for_each_online_cpu(cpu) { + src = (uint64_t *)&(per_cpu(rds_tcp_stats, cpu)); + sum = (uint64_t *)&stats; + for (i = 0; i < sizeof(stats) / sizeof(uint64_t); i++) + *(sum++) += *(src++); + } + + rds_stats_info_copy(iter, (uint64_t *)&stats, rds_tcp_stat_names, + ARRAY_SIZE(rds_tcp_stat_names)); +out: + return ARRAY_SIZE(rds_tcp_stat_names); +} -- cgit v0.10.2 From 616b757ae18fb8ec2dfe7ff9d3f589f82cb0eb9d Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 21 Aug 2009 12:28:32 +0000 Subject: RDS: Export symbols from core RDS Now that rdma and tcp transports will be modularized, we need to export a number of functions so they can call them. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/cong.c b/net/rds/cong.c index 710e459..dd2711d 100644 --- a/net/rds/cong.c +++ b/net/rds/cong.c @@ -254,6 +254,7 @@ void rds_cong_map_updated(struct rds_cong_map *map, uint64_t portmask) read_unlock_irqrestore(&rds_cong_monitor_lock, flags); } } +EXPORT_SYMBOL_GPL(rds_cong_map_updated); int rds_cong_updated_since(unsigned long *recent) { diff --git a/net/rds/connection.c b/net/rds/connection.c index b420a20..cc8b568 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -255,12 +255,14 @@ struct rds_connection *rds_conn_create(__be32 laddr, __be32 faddr, { return __rds_conn_create(laddr, faddr, trans, gfp, 0); } +EXPORT_SYMBOL_GPL(rds_conn_create); struct rds_connection *rds_conn_create_outgoing(__be32 laddr, __be32 faddr, struct rds_transport *trans, gfp_t gfp) { return __rds_conn_create(laddr, faddr, trans, gfp, 1); } +EXPORT_SYMBOL_GPL(rds_conn_create_outgoing); void rds_conn_destroy(struct rds_connection *conn) { @@ -303,6 +305,7 @@ void rds_conn_destroy(struct rds_connection *conn) rds_conn_count--; } +EXPORT_SYMBOL_GPL(rds_conn_destroy); static void rds_conn_message_info(struct socket *sock, unsigned int len, struct rds_info_iterator *iter, @@ -406,6 +409,7 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, spin_unlock_irqrestore(&rds_conn_lock, flags); } +EXPORT_SYMBOL_GPL(rds_for_each_conn_info); static int rds_conn_info_visitor(struct rds_connection *conn, void *buffer) @@ -481,6 +485,7 @@ void rds_conn_drop(struct rds_connection *conn) atomic_set(&conn->c_state, RDS_CONN_ERROR); queue_work(rds_wq, &conn->c_down_w); } +EXPORT_SYMBOL_GPL(rds_conn_drop); /* * An error occurred on the connection diff --git a/net/rds/info.c b/net/rds/info.c index 62aeef3..814a91a 100644 --- a/net/rds/info.c +++ b/net/rds/info.c @@ -79,6 +79,7 @@ void rds_info_register_func(int optname, rds_info_func func) rds_info_funcs[offset] = func; spin_unlock(&rds_info_lock); } +EXPORT_SYMBOL_GPL(rds_info_register_func); void rds_info_deregister_func(int optname, rds_info_func func) { @@ -91,6 +92,7 @@ void rds_info_deregister_func(int optname, rds_info_func func) rds_info_funcs[offset] = NULL; spin_unlock(&rds_info_lock); } +EXPORT_SYMBOL_GPL(rds_info_deregister_func); /* * Typically we hold an atomic kmap across multiple rds_info_copy() calls @@ -137,6 +139,7 @@ void rds_info_copy(struct rds_info_iterator *iter, void *data, } } } +EXPORT_SYMBOL_GPL(rds_info_copy); /* * @optval points to the userspace buffer that the information snapshot diff --git a/net/rds/message.c b/net/rds/message.c index 5a15dc8..ca50a8e 100644 --- a/net/rds/message.c +++ b/net/rds/message.c @@ -50,6 +50,7 @@ void rds_message_addref(struct rds_message *rm) rdsdebug("addref rm %p ref %d\n", rm, atomic_read(&rm->m_refcount)); atomic_inc(&rm->m_refcount); } +EXPORT_SYMBOL_GPL(rds_message_addref); /* * This relies on dma_map_sg() not touching sg[].page during merging. @@ -92,6 +93,7 @@ void rds_message_put(struct rds_message *rm) kfree(rm); } } +EXPORT_SYMBOL_GPL(rds_message_put); void rds_message_inc_free(struct rds_incoming *inc) { @@ -108,6 +110,7 @@ void rds_message_populate_header(struct rds_header *hdr, __be16 sport, hdr->h_sequence = cpu_to_be64(seq); hdr->h_exthdr[0] = RDS_EXTHDR_NONE; } +EXPORT_SYMBOL_GPL(rds_message_populate_header); int rds_message_add_extension(struct rds_header *hdr, unsigned int type, const void *data, unsigned int len) @@ -133,6 +136,7 @@ int rds_message_add_extension(struct rds_header *hdr, dst[len] = RDS_EXTHDR_NONE; return 1; } +EXPORT_SYMBOL_GPL(rds_message_add_extension); /* * If a message has extension headers, retrieve them here. @@ -208,6 +212,7 @@ int rds_message_add_rdma_dest_extension(struct rds_header *hdr, u32 r_key, u32 o ext_hdr.h_rdma_offset = cpu_to_be32(offset); return rds_message_add_extension(hdr, RDS_EXTHDR_RDMA_DEST, &ext_hdr, sizeof(ext_hdr)); } +EXPORT_SYMBOL_GPL(rds_message_add_rdma_dest_extension); struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp) { @@ -399,4 +404,5 @@ void rds_message_unmapped(struct rds_message *rm) if (waitqueue_active(&rds_message_flush_waitq)) wake_up(&rds_message_flush_waitq); } +EXPORT_SYMBOL_GPL(rds_message_unmapped); diff --git a/net/rds/page.c b/net/rds/page.c index c460743..55c21ef 100644 --- a/net/rds/page.c +++ b/net/rds/page.c @@ -81,6 +81,7 @@ int rds_page_copy_user(struct page *page, unsigned long offset, return 0; } +EXPORT_SYMBOL_GPL(rds_page_copy_user); /* * Message allocation uses this to build up regions of a message. diff --git a/net/rds/recv.c b/net/rds/recv.c index 86bc1a0..fdff33c 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -46,12 +46,14 @@ void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn, inc->i_saddr = saddr; inc->i_rdma_cookie = 0; } +EXPORT_SYMBOL_GPL(rds_inc_init); void rds_inc_addref(struct rds_incoming *inc) { rdsdebug("addref inc %p ref %d\n", inc, atomic_read(&inc->i_refcount)); atomic_inc(&inc->i_refcount); } +EXPORT_SYMBOL_GPL(rds_inc_addref); void rds_inc_put(struct rds_incoming *inc) { @@ -62,6 +64,7 @@ void rds_inc_put(struct rds_incoming *inc) inc->i_conn->c_trans->inc_free(inc); } } +EXPORT_SYMBOL_GPL(rds_inc_put); static void rds_recv_rcvbuf_delta(struct rds_sock *rs, struct sock *sk, struct rds_cong_map *map, @@ -237,6 +240,7 @@ out: if (rs) rds_sock_put(rs); } +EXPORT_SYMBOL_GPL(rds_recv_incoming); /* * be very careful here. This is being called as the condition in diff --git a/net/rds/send.c b/net/rds/send.c index a4a7f42..28c88ff 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -439,6 +439,7 @@ void rds_rdma_send_complete(struct rds_message *rm, int status) sock_put(rds_rs_to_sk(rs)); } } +EXPORT_SYMBOL_GPL(rds_rdma_send_complete); /* * This is the same as rds_rdma_send_complete except we @@ -494,6 +495,7 @@ out: return found; } +EXPORT_SYMBOL_GPL(rds_send_get_message); /* * This removes messages from the socket's list if they're on it. The list @@ -610,6 +612,7 @@ void rds_send_drop_acked(struct rds_connection *conn, u64 ack, /* now remove the messages from the sock list as needed */ rds_send_remove_from_sock(&list, RDS_RDMA_SUCCESS); } +EXPORT_SYMBOL_GPL(rds_send_drop_acked); void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest) { diff --git a/net/rds/stats.c b/net/rds/stats.c index 91d8c58..7598eb0 100644 --- a/net/rds/stats.c +++ b/net/rds/stats.c @@ -37,6 +37,7 @@ #include "rds.h" DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_statistics, rds_stats); +EXPORT_PER_CPU_SYMBOL_GPL(rds_stats); /* :.,$s/unsigned long\>.*\c_send_w, 0); queue_delayed_work(rds_wq, &conn->c_recv_w, 0); } +EXPORT_SYMBOL_GPL(rds_connect_complete); /* * This random exponential backoff is relied on to eventually resolve racing diff --git a/net/rds/transport.c b/net/rds/transport.c index 767da61..56a5309 100644 --- a/net/rds/transport.c +++ b/net/rds/transport.c @@ -53,6 +53,7 @@ int rds_trans_register(struct rds_transport *trans) return 0; } +EXPORT_SYMBOL_GPL(rds_trans_register); void rds_trans_unregister(struct rds_transport *trans) { @@ -63,6 +64,7 @@ void rds_trans_unregister(struct rds_transport *trans) up_write(&rds_trans_sem); } +EXPORT_SYMBOL_GPL(rds_trans_unregister); struct rds_transport *rds_trans_get_preferred(__be32 addr) { -- cgit v0.10.2 From 40d866095df3bb70ded1813f4852cab445ef678b Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 21 Aug 2009 12:28:33 +0000 Subject: RDS: Modularize RDMA and TCP transports Enable the building of transports as modules. Also, improve consistency of Kconfig messages in relation to other protocols, and move build dependency on IB from the RDS core code to the rds_rdma module. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/Kconfig b/net/rds/Kconfig index 796773b..ec753b3 100644 --- a/net/rds/Kconfig +++ b/net/rds/Kconfig @@ -1,14 +1,28 @@ config RDS - tristate "Reliable Datagram Sockets (RDS) (EXPERIMENTAL)" - depends on INET && INFINIBAND_IPOIB && EXPERIMENTAL - depends on INFINIBAND && INFINIBAND_ADDR_TRANS + tristate "The RDS Protocol (EXPERIMENTAL)" + depends on INET && EXPERIMENTAL ---help--- - RDS provides reliable, sequenced delivery of datagrams - over Infiniband. + The RDS (Reliable Datagram Sockets) protocol provides reliable, + sequenced delivery of datagrams over Infiniband, iWARP, + or TCP. + +config RDS_RDMA + tristate "RDS over Infiniband and iWARP" + depends on RDS && INFINIBAND && INFINIBAND_ADDR_TRANS + ---help--- + Allow RDS to use Infiniband and iWARP as a transport. + This transport supports RDMA operations. + +config RDS_TCP + tristate "RDS over TCP" + depends on RDS + ---help--- + Allow RDS to use TCP as a transport. + This transport does not support RDMA operations. config RDS_DEBUG - bool "Debugging messages" + bool "RDS debugging messages" depends on RDS default n diff --git a/net/rds/Makefile b/net/rds/Makefile index 51f2758..b46eca1 100644 --- a/net/rds/Makefile +++ b/net/rds/Makefile @@ -1,13 +1,20 @@ obj-$(CONFIG_RDS) += rds.o rds-y := af_rds.o bind.o cong.o connection.o info.o message.o \ recv.o send.o stats.o sysctl.o threads.o transport.o \ - loop.o page.o rdma.o \ - rdma_transport.o \ + loop.o page.o rdma.o + +obj-$(CONFIG_RDS_RDMA) += rds_rdma.o +rds_rdma-objs := rdma_transport.o \ ib.o ib_cm.o ib_recv.o ib_ring.o ib_send.o ib_stats.o \ ib_sysctl.o ib_rdma.o \ iw.o iw_cm.o iw_recv.o iw_ring.o iw_send.o iw_stats.o \ iw_sysctl.o iw_rdma.o + +obj-$(CONFIG_RDS_TCP) += rds_tcp.o +rds_tcp-objs := tcp.o tcp_connect.o tcp_listen.o tcp_recv.o \ + tcp_send.o tcp_stats.o + ifeq ($(CONFIG_RDS_DEBUG), y) EXTRA_CFLAGS += -DDEBUG endif diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index b11e7e5..108ed2e 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -39,7 +39,6 @@ #include "rds.h" #include "rdma.h" -#include "rdma_transport.h" /* this is just used for stats gathering :/ */ static DEFINE_SPINLOCK(rds_sock_lock); @@ -509,7 +508,6 @@ out: static void __exit rds_exit(void) { - rds_rdma_exit(); sock_unregister(rds_family_ops.family); proto_unregister(&rds_proto); rds_conn_exit(); @@ -549,14 +547,8 @@ static int __init rds_init(void) rds_info_register_func(RDS_INFO_SOCKETS, rds_sock_info); rds_info_register_func(RDS_INFO_RECV_MESSAGES, rds_sock_inc_info); - /* ib/iwarp transports currently compiled-in */ - ret = rds_rdma_init(); - if (ret) - goto out_sock; goto out; -out_sock: - sock_unregister(rds_family_ops.family); out_proto: proto_unregister(&rds_proto); out_stats: diff --git a/net/rds/rdma_transport.c b/net/rds/rdma_transport.c index 7a6c748..9ece910 100644 --- a/net/rds/rdma_transport.c +++ b/net/rds/rdma_transport.c @@ -203,6 +203,7 @@ err_iw_init: out: return ret; } +module_init(rds_rdma_init); void rds_rdma_exit(void) { @@ -211,4 +212,9 @@ void rds_rdma_exit(void) rds_ib_exit(); rds_iw_exit(); } +module_exit(rds_rdma_exit); + +MODULE_AUTHOR("Oracle Corporation "); +MODULE_DESCRIPTION("RDS: IB/iWARP transport"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v0.10.2 From 335776bd696a6bf95134baf8ad95847371e4d5f6 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 21 Aug 2009 12:28:34 +0000 Subject: RDS: Track transports via an array, not a list Now that transports can be loaded in arbitrary order, it is important for rds_trans_get_preferred() to look for them in a particular order, instead of walking the list until it finds a transport that works for a given address. Now, each transport registers for a specific transport slot, and these are ordered so that preferred transports come first, and then if they are not loaded, other transports are queried. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/ib.c b/net/rds/ib.c index 868559a..536ebe5 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -282,6 +282,7 @@ struct rds_transport rds_ib_transport = { .flush_mrs = rds_ib_flush_mrs, .t_owner = THIS_MODULE, .t_name = "infiniband", + .t_type = RDS_TRANS_IB }; int __init rds_ib_init(void) diff --git a/net/rds/iw.c b/net/rds/iw.c index f5e9a29..db224f7 100644 --- a/net/rds/iw.c +++ b/net/rds/iw.c @@ -284,6 +284,7 @@ struct rds_transport rds_iw_transport = { .flush_mrs = rds_iw_flush_mrs, .t_owner = THIS_MODULE, .t_name = "iwarp", + .t_type = RDS_TRANS_IWARP, .t_prefer_loopback = 1, }; diff --git a/net/rds/rds.h b/net/rds/rds.h index 290566c..85d6f89 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -311,11 +311,17 @@ struct rds_notifier { * flag and header. */ +#define RDS_TRANS_IB 0 +#define RDS_TRANS_IWARP 1 +#define RDS_TRANS_TCP 2 +#define RDS_TRANS_COUNT 3 + struct rds_transport { char t_name[TRANSNAMSIZ]; struct list_head t_item; struct module *t_owner; unsigned int t_prefer_loopback:1; + unsigned int t_type; int (*laddr_check)(__be32 addr); int (*conn_alloc)(struct rds_connection *conn, gfp_t gfp); diff --git a/net/rds/tcp.c b/net/rds/tcp.c index e0ac900..b5198ae 100644 --- a/net/rds/tcp.c +++ b/net/rds/tcp.c @@ -271,6 +271,7 @@ struct rds_transport rds_tcp_transport = { .exit = rds_tcp_exit, .t_owner = THIS_MODULE, .t_name = "tcp", + .t_type = RDS_TRANS_TCP, .t_prefer_loopback = 1, }; diff --git a/net/rds/transport.c b/net/rds/transport.c index 56a5309..7e10679 100644 --- a/net/rds/transport.c +++ b/net/rds/transport.c @@ -37,7 +37,7 @@ #include "rds.h" #include "loop.h" -static LIST_HEAD(rds_transports); +static struct rds_transport *transports[RDS_TRANS_COUNT]; static DECLARE_RWSEM(rds_trans_sem); int rds_trans_register(struct rds_transport *trans) @@ -46,8 +46,13 @@ int rds_trans_register(struct rds_transport *trans) down_write(&rds_trans_sem); - list_add_tail(&trans->t_item, &rds_transports); - printk(KERN_INFO "Registered RDS/%s transport\n", trans->t_name); + if (transports[trans->t_type]) + printk(KERN_ERR "RDS Transport type %d already registered\n", + trans->t_type); + else { + transports[trans->t_type] = trans; + printk(KERN_INFO "Registered RDS/%s transport\n", trans->t_name); + } up_write(&rds_trans_sem); @@ -59,7 +64,7 @@ void rds_trans_unregister(struct rds_transport *trans) { down_write(&rds_trans_sem); - list_del_init(&trans->t_item); + transports[trans->t_type] = NULL; printk(KERN_INFO "Unregistered RDS/%s transport\n", trans->t_name); up_write(&rds_trans_sem); @@ -68,16 +73,17 @@ EXPORT_SYMBOL_GPL(rds_trans_unregister); struct rds_transport *rds_trans_get_preferred(__be32 addr) { - struct rds_transport *trans; struct rds_transport *ret = NULL; + int i; if (IN_LOOPBACK(ntohl(addr))) return &rds_loop_transport; down_read(&rds_trans_sem); - list_for_each_entry(trans, &rds_transports, t_item) { - if (trans->laddr_check(addr) == 0) { - ret = trans; + for (i = 0; i < RDS_TRANS_COUNT; i++) + { + if (transports[i] && (transports[i]->laddr_check(addr) == 0)) { + ret = transports[i]; break; } } @@ -99,12 +105,15 @@ unsigned int rds_trans_stats_info_copy(struct rds_info_iterator *iter, struct rds_transport *trans; unsigned int total = 0; unsigned int part; + int i; rds_info_iter_unmap(iter); down_read(&rds_trans_sem); - list_for_each_entry(trans, &rds_transports, t_item) { - if (trans->stats_info_copy == NULL) + for (i = 0; i < RDS_TRANS_COUNT; i++) + { + trans = transports[i]; + if (!trans || !trans->stats_info_copy) continue; part = trans->stats_info_copy(iter, avail); -- cgit v0.10.2 From f2c449320d547bd5c281649eb1d99afb20765144 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 21 Aug 2009 12:28:35 +0000 Subject: RDS: Add a debug message suggesting to load transport modules Now that RDS transports are no longer compiled-in to RDS core, there is now the possibility that they will not be loaded. This adds a helpful suggestion when rds_bind() fails to find a transport. Signed-off-by: Andy Grover Signed-off-by: David S. Miller diff --git a/net/rds/bind.c b/net/rds/bind.c index c17cc39..5d95fc0 100644 --- a/net/rds/bind.c +++ b/net/rds/bind.c @@ -187,6 +187,9 @@ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (trans == NULL) { ret = -EADDRNOTAVAIL; rds_remove_bound(rs); + if (printk_ratelimit()) + printk(KERN_INFO "RDS: rds_bind() could not find a transport, " + "load rds_tcp or rds_rdma?\n"); goto out; } -- cgit v0.10.2 From d516478ff67b2abb2f3ecc998a598576d92b0b5e Mon Sep 17 00:00:00 2001 From: Mark Kelly Date: Thu, 20 Aug 2009 01:26:12 +0000 Subject: r6040: remove unused pioaddr variable This patch removes the unused pioaddr variable. Signed-off-by: Mark Kelly Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 840677f..60bd010 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -1091,7 +1091,6 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, int err, io_size = R6040_IO_SIZE; static int card_idx = -1; int bar = 0; - long pioaddr; u16 *adrp; printk(KERN_INFO "%s\n", version); @@ -1121,7 +1120,6 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, goto err_out; } - pioaddr = pci_resource_start(pdev, bar); /* IO map base address */ pci_set_master(pdev); dev = alloc_etherdev(sizeof(struct r6040_private)); -- cgit v0.10.2 From e03f614af7811f9d089862a8700e683dcc6963c6 Mon Sep 17 00:00:00 2001 From: Mark Kelly Date: Thu, 20 Aug 2009 01:26:20 +0000 Subject: r6040: move down second PHY detection to r6040_init_one Instead of fully initializing an unusable second r6040 device, perform the PHY detection earlier and bail out in r6040_init_one when we could not read the PHY identifier. Signed-off-by: Mark Kelly Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 60bd010..7238a6f 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -750,14 +750,6 @@ static int r6040_up(struct net_device *dev) struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; int ret; - u16 val; - - /* Check presence of a second PHY */ - val = r6040_phy_read(ioaddr, lp->phy_addr, 2); - if (val == 0xFFFF) { - printk(KERN_ERR DRV_NAME " no second PHY attached\n"); - return -EIO; - } /* Initialise and alloc RX/TX buffers */ r6040_init_txbufs(dev); @@ -1194,6 +1186,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, lp->mii_if.phy_id_mask = 0x1f; lp->mii_if.reg_num_mask = 0x1f; + /* Check the vendor ID on the PHY, if 0xffff assume none attached */ + if (r6040_phy_read(ioaddr, lp->phy_addr, 2) == 0xffff) { + printk(KERN_ERR DRV_NAME ": Failed to detect an attached PHY\n"); + err = -ENODEV; + goto err_out_unmap; + } + /* Register net device. After this dev->name assign */ err = register_netdev(dev); if (err) { -- cgit v0.10.2 From 9818f660f433b58e770cfeb2ee9566f7b42ca0ae Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Aug 2009 01:26:23 +0000 Subject: r6040: bump to version 0.25 and 20 August 2009 release date Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 7238a6f..8068a07 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -49,8 +49,8 @@ #include #define DRV_NAME "r6040" -#define DRV_VERSION "0.24" -#define DRV_RELDATE "08Jul2009" +#define DRV_VERSION "0.25" +#define DRV_RELDATE "20Aug2009" /* PHY CHIP Address */ #define PHY1_ADDR 1 /* For MAC1 */ -- cgit v0.10.2 From 5eecfde615894dc1c2e3f85b515a96ae2e408fb5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 21 Aug 2009 17:50:30 -0400 Subject: NFS: Handle a zero-length auth flavor list Some releases of Linux rpc.mountd (nfs-utils 1.1.4 and later) return an empty auth flavor list if no sec= was specified for the export. This is notably broken server behavior. The new auth flavor list checking added in a recent commit rejects this case. The OpenSolaris client does too. The broken mountd implementation is already widely deployed. To avoid a behavioral regression, the kernel's mount client skips flavor checking (ie reverts to the pre-2.6.32 behavior) if mountd returns an empty flavor list. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 9c85cdb..f3a95df 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1338,6 +1338,16 @@ static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, unsigned int i, j, server_authlist_len = *(request->auth_flav_len); /* + * Certain releases of Linux's mountd return an empty + * flavor list. To prevent behavioral regression with + * these servers (ie. rejecting mounts that used to + * succeed), revert to pre-2.6.32 behavior (no checking) + * if the returned flavor list is empty. + */ + if (server_authlist_len == 0) + return 0; + + /* * We avoid sophisticated negotiating here, as there are * plenty of cases where we can get it wrong, providing * either too little or too much security. -- cgit v0.10.2 From 20496ff3783fc9d4cea2317ed2d4442561af64d9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 24 Aug 2009 09:40:34 +0200 Subject: ASoC: add missing inclusion of debugfs.h To fix compile errors. Signed-off-by: Takashi Iwai diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2f5295d..7b74547 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From c6ea2af76ab79b82a0bfed313e4c2b68b10c2bc1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 24 Aug 2009 09:41:32 +0200 Subject: ASoC: Remove unneeded inclusion of linux/regulator/consumer.h Signed-off-by: Takashi Iwai diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 6be47e8..41699bd 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From fd72d008465d45db63d7f8931eea6a04e05916d6 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Mon, 24 Aug 2009 09:50:46 +0800 Subject: ALSA: hda: move open coded tricks into get_wcaps_channels() Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index fa57cb9..5f1dcc5 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -410,6 +410,16 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) /* get the widget type from widget capability bits */ #define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT) +static inline unsigned int get_wcaps_channels(u32 wcaps) +{ + unsigned int chans; + + chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13; + chans = ((chans << 1) | 1) + 1; + + return chans; +} + u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index a721eb0..95f24e4 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -515,9 +515,7 @@ static void print_codec_info(struct snd_info_entry *entry, snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, get_wid_type_name(wid_type), wid_caps); if (wid_caps & AC_WCAP_STEREO) { - unsigned int chans; - chans = (wid_caps & AC_WCAP_CHAN_CNT_EXT) >> 13; - chans = ((chans << 1) | 1) + 1; + unsigned int chans = get_wcaps_channels(wid_caps); if (chans == 2) snd_iprintf(buffer, " Stereo"); else diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index 233e477..fb684f0 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c @@ -141,8 +141,7 @@ static int atihdmi_build_pcms(struct hda_codec *codec) /* FIXME: we must check ELD and change the PCM parameters dynamically */ chans = get_wcaps(codec, CVT_NID); - chans = (chans & AC_WCAP_CHAN_CNT_EXT) >> 13; - chans = ((chans << 1) | 1) + 1; + chans = get_wcaps_channels(chans); info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; return 0; -- cgit v0.10.2 From e686219a64fee9be9ce438dc3f040cd71ddd168a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 24 Aug 2009 00:45:19 -0300 Subject: Bluetooth: Add locking scheme to L2CAP timeout callbacks Avoid race conditions when accessing the L2CAP socket from within the timeout handlers. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c04526f..efac637 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1192,6 +1192,7 @@ static void l2cap_monitor_timeout(unsigned long arg) struct sock *sk = (void *) arg; u16 control; + bh_lock_sock(sk); if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk); return; @@ -1203,6 +1204,7 @@ static void l2cap_monitor_timeout(unsigned long arg) control = L2CAP_CTRL_POLL; control |= L2CAP_SUPER_RCV_READY; l2cap_send_sframe(l2cap_pi(sk), control); + bh_unlock_sock(sk); } static void l2cap_retrans_timeout(unsigned long arg) @@ -1210,6 +1212,7 @@ static void l2cap_retrans_timeout(unsigned long arg) struct sock *sk = (void *) arg; u16 control; + bh_lock_sock(sk); l2cap_pi(sk)->retry_count = 1; __mod_monitor_timer(); @@ -1218,6 +1221,7 @@ static void l2cap_retrans_timeout(unsigned long arg) control = L2CAP_CTRL_POLL; control |= L2CAP_SUPER_RCV_READY; l2cap_send_sframe(l2cap_pi(sk), control); + bh_unlock_sock(sk); } static void l2cap_drop_acked_frames(struct sock *sk) -- cgit v0.10.2 From 1b7bf4edca0fdbad70c44e139f4cfebd6759de81 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 24 Aug 2009 00:45:20 -0300 Subject: Bluetooth: Use proper *_unaligned_le{16,32} helpers for L2CAP Simplify more conversions to the right endian with the proper helpers. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index efac637..e5847c5 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2924,7 +2924,7 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm if (enable_ertm) feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING | L2CAP_FEAT_FCS; - put_unaligned(cpu_to_le32(feat_mask), (__le32 *) rsp->data); + put_unaligned_le32(feat_mask, rsp->data); l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf), buf); } else if (type == L2CAP_IT_FIXED_CHAN) { @@ -3572,7 +3572,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) break; case L2CAP_CID_CONN_LESS: - psm = get_unaligned((__le16 *) skb->data); + psm = get_unaligned_le16(skb->data); skb_pull(skb, 2); l2cap_conless_channel(conn, psm, skb); break; -- cgit v0.10.2 From 10f02d1168585edf66229bb2ec90a42f32667a78 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 23 Aug 2009 23:17:27 +0400 Subject: x86: uv: Clean up uv_ptc_init(), use proc_create() create_proc_entry() is getting duhprecated. Signed-off-by: Alexey Dobriyan Cc: cpw@sgi.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/tlb_uv.c b/arch/x86/kernel/tlb_uv.c index 77b9689..503c1f2 100644 --- a/arch/x86/kernel/tlb_uv.c +++ b/arch/x86/kernel/tlb_uv.c @@ -640,13 +640,13 @@ static int __init uv_ptc_init(void) if (!is_uv_system()) return 0; - proc_uv_ptc = create_proc_entry(UV_PTC_BASENAME, 0444, NULL); + proc_uv_ptc = proc_create(UV_PTC_BASENAME, 0444, NULL, + &proc_uv_ptc_operations); if (!proc_uv_ptc) { printk(KERN_ERR "unable to create %s proc entry\n", UV_PTC_BASENAME); return -EINVAL; } - proc_uv_ptc->proc_fops = &proc_uv_ptc_operations; return 0; } -- cgit v0.10.2 From 9d0b71b1cf7b7ff856d200841de3f3d7c64eb170 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 24 Aug 2009 14:10:30 +0200 Subject: ALSA: hda - Reuse ALC268 parser for ALC269 Reuse a part of the code of ALC268 parser for ALC269. This will change the default output volume either to Front or Speaker depending on the pin configuration. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 084e291..dd25db9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -13086,87 +13086,8 @@ static struct hda_verb alc269_init_verbs[] = { { } }; -/* add playback controls from the parsed DAC table */ -static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - hda_nid_t nid; - int err; - - spec->multiout.num_dacs = 1; /* only use one dac */ - spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.dac_nids[0] = 2; - - nid = cfg->line_out_pins[0]; - if (nid) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Front Playback Volume", - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Front Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - - nid = cfg->speaker_pins[0]; - if (nid) { - if (!cfg->line_out_pins[0]) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Speaker Playback Volume", - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } - if (nid == 0x16) { - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Speaker Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } else { - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Speaker Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } - } - nid = cfg->hp_pins[0]; - if (nid) { - /* spec->multiout.hp_nid = 2; */ - if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Headphone Playback Volume", - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } - if (nid == 0x16) { - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Headphone Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } else { - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Headphone Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } - } - return 0; -} - +#define alc269_auto_create_multi_out_ctls \ + alc268_auto_create_multi_out_ctls #define alc269_auto_create_analog_input_ctls \ alc262_auto_create_analog_input_ctls -- cgit v0.10.2 From 35aad0ffdf548617940ca1e78be1f2e0bafc4496 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 24 Aug 2009 14:56:30 +0200 Subject: netfilter: xtables: mark initial tables constant The inputted table is never modified, so should be considered const. Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 4fa6e4c..812cb15 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -407,7 +407,7 @@ extern int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto, bool inv_proto); extern struct xt_table *xt_register_table(struct net *net, - struct xt_table *table, + const struct xt_table *table, struct xt_table_info *bootstrap, struct xt_table_info *newinfo); extern void *xt_unregister_table(struct xt_table *table); diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 590ac3d..6fe3e6a 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -265,7 +265,7 @@ struct arpt_error } extern struct xt_table *arpt_register_table(struct net *net, - struct xt_table *table, + const struct xt_table *table, const struct arpt_replace *repl); extern void arpt_unregister_table(struct xt_table *table); extern unsigned int arpt_do_table(struct sk_buff *skb, diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index e40ddb9..ea281e6 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -301,7 +301,7 @@ struct ebt_table #define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \ ~(__alignof__(struct ebt_replace)-1)) extern struct ebt_table *ebt_register_table(struct net *net, - struct ebt_table *table); + const struct ebt_table *table); extern void ebt_unregister_table(struct ebt_table *table); extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 092bd50..61fafc8 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -245,7 +245,7 @@ ipt_get_target(struct ipt_entry *e) extern void ipt_init(void) __init; extern struct xt_table *ipt_register_table(struct net *net, - struct xt_table *table, + const struct xt_table *table, const struct ipt_replace *repl); extern void ipt_unregister_table(struct xt_table *table); diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 1089e33..a64e145 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -306,7 +306,7 @@ ip6t_get_target(struct ip6t_entry *e) extern void ip6t_init(void) __init; extern struct xt_table *ip6t_register_table(struct net *net, - struct xt_table *table, + const struct xt_table *table, const struct ip6t_replace *repl); extern void ip6t_unregister_table(struct xt_table *table); extern unsigned int ip6t_do_table(struct sk_buff *skb, diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index c751111..d32ab13 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c @@ -41,7 +41,7 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks) return 0; } -static struct ebt_table broute_table = +static const struct ebt_table broute_table = { .name = "broute", .table = &initial_table, diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index 4b988db..60b1a6c 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c @@ -50,7 +50,7 @@ static int check(const struct ebt_table_info *info, unsigned int valid_hooks) return 0; } -static struct ebt_table frame_filter = +static const struct ebt_table frame_filter = { .name = "filter", .table = &initial_table, diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 37928d5..bd1c654 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1103,23 +1103,24 @@ free_newinfo: return ret; } -struct ebt_table *ebt_register_table(struct net *net, struct ebt_table *table) +struct ebt_table * +ebt_register_table(struct net *net, const struct ebt_table *input_table) { struct ebt_table_info *newinfo; - struct ebt_table *t; + struct ebt_table *t, *table; struct ebt_replace_kernel *repl; int ret, i, countersize; void *p; - if (!table || !(repl = table->table) || !repl->entries || - repl->entries_size == 0 || - repl->counters || table->private) { + if (input_table == NULL || (repl = input_table->table) == NULL || + repl->entries == 0 || repl->entries_size == 0 || + repl->counters != NULL || input_table->private != NULL) { BUGPRINT("Bad table data for ebt_register_table!!!\n"); return ERR_PTR(-EINVAL); } /* Don't add one table to multiple lists. */ - table = kmemdup(table, sizeof(struct ebt_table), GFP_KERNEL); + table = kmemdup(input_table, sizeof(struct ebt_table), GFP_KERNEL); if (!table) { ret = -ENOMEM; goto out; diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 7bc11ff..27774c9 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -1778,7 +1778,8 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len return ret; } -struct xt_table *arpt_register_table(struct net *net, struct xt_table *table, +struct xt_table *arpt_register_table(struct net *net, + const struct xt_table *table, const struct arpt_replace *repl) { int ret; diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index 6ecfdae..9733760 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -15,7 +15,7 @@ MODULE_DESCRIPTION("arptables filter table"); #define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \ (1 << NF_ARP_FORWARD)) -static struct +static const struct { struct arpt_replace repl; struct arpt_standard entries[3]; @@ -45,7 +45,7 @@ static struct .term = ARPT_ERROR_INIT, }; -static struct xt_table packet_filter = { +static const struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, .me = THIS_MODULE, diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 0b43fd7..cde755d 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -2065,7 +2065,8 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) return ret; } -struct xt_table *ipt_register_table(struct net *net, struct xt_table *table, +struct xt_table *ipt_register_table(struct net *net, + const struct xt_table *table, const struct ipt_replace *repl) { int ret; diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 97dbd94..df566cb 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -53,7 +53,7 @@ static struct .term = IPT_ERROR_INIT, /* ERROR */ }; -static struct xt_table packet_filter = { +static const struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, .me = THIS_MODULE, diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 28647f1..036047f 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -28,7 +28,7 @@ MODULE_DESCRIPTION("iptables mangle table"); (1 << NF_INET_POST_ROUTING)) /* Ouch - five different hooks? Maybe this should be a config option..... -- BC */ -static struct +static const struct { struct ipt_replace repl; struct ipt_standard entries[5]; @@ -64,7 +64,7 @@ static struct .term = IPT_ERROR_INIT, /* ERROR */ }; -static struct xt_table packet_mangler = { +static const struct xt_table packet_mangler = { .name = "mangle", .valid_hooks = MANGLE_VALID_HOOKS, .me = THIS_MODULE, diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 494784c..993edc2 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -9,7 +9,7 @@ #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) -static struct +static const struct { struct ipt_replace repl; struct ipt_standard entries[2]; @@ -36,7 +36,7 @@ static struct .term = IPT_ERROR_INIT, /* ERROR */ }; -static struct xt_table packet_raw = { +static const struct xt_table packet_raw = { .name = "raw", .valid_hooks = RAW_VALID_HOOKS, .me = THIS_MODULE, diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index 8804e1a..99eb76c6 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -27,7 +27,7 @@ MODULE_DESCRIPTION("iptables security table, for MAC rules"); (1 << NF_INET_FORWARD) | \ (1 << NF_INET_LOCAL_OUT) -static struct +static const struct { struct ipt_replace repl; struct ipt_standard entries[3]; @@ -57,7 +57,7 @@ static struct .term = IPT_ERROR_INIT, /* ERROR */ }; -static struct xt_table security_table = { +static const struct xt_table security_table = { .name = "security", .valid_hooks = SECURITY_VALID_HOOKS, .me = THIS_MODULE, diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index 6448a9b..9e81e0d 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -28,7 +28,7 @@ (1 << NF_INET_POST_ROUTING) | \ (1 << NF_INET_LOCAL_OUT)) -static struct +static const struct { struct ipt_replace repl; struct ipt_standard entries[3]; @@ -58,7 +58,7 @@ static struct .term = IPT_ERROR_INIT, /* ERROR */ }; -static struct xt_table nat_table = { +static const struct xt_table nat_table = { .name = "nat", .valid_hooks = NAT_VALID_HOOKS, .me = THIS_MODULE, diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index a5d0c27..cc9f8ef 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -2100,7 +2100,8 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) return ret; } -struct xt_table *ip6t_register_table(struct net *net, struct xt_table *table, +struct xt_table *ip6t_register_table(struct net *net, + const struct xt_table *table, const struct ip6t_replace *repl) { int ret; diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 0a3ae48..6f4383a 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -51,7 +51,7 @@ static struct .term = IP6T_ERROR_INIT, /* ERROR */ }; -static struct xt_table packet_filter = { +static const struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, .me = THIS_MODULE, diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 0f49e00..0ad9143 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -21,7 +21,7 @@ MODULE_DESCRIPTION("ip6tables mangle table"); (1 << NF_INET_LOCAL_OUT) | \ (1 << NF_INET_POST_ROUTING)) -static struct +static const struct { struct ip6t_replace repl; struct ip6t_standard entries[5]; @@ -57,7 +57,7 @@ static struct .term = IP6T_ERROR_INIT, /* ERROR */ }; -static struct xt_table packet_mangler = { +static const struct xt_table packet_mangler = { .name = "mangle", .valid_hooks = MANGLE_VALID_HOOKS, .me = THIS_MODULE, diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 679865e..ed1a118 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -8,7 +8,7 @@ #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) -static struct +static const struct { struct ip6t_replace repl; struct ip6t_standard entries[2]; @@ -35,7 +35,7 @@ static struct .term = IP6T_ERROR_INIT, /* ERROR */ }; -static struct xt_table packet_raw = { +static const struct xt_table packet_raw = { .name = "raw", .valid_hooks = RAW_VALID_HOOKS, .me = THIS_MODULE, diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index 822afab..41b444c 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c @@ -26,7 +26,7 @@ MODULE_DESCRIPTION("ip6tables security table, for MAC rules"); (1 << NF_INET_FORWARD) | \ (1 << NF_INET_LOCAL_OUT) -static struct +static const struct { struct ip6t_replace repl; struct ip6t_standard entries[3]; @@ -56,7 +56,7 @@ static struct .term = IP6T_ERROR_INIT, /* ERROR */ }; -static struct xt_table security_table = { +static const struct xt_table security_table = { .name = "security", .valid_hooks = SECURITY_VALID_HOOKS, .me = THIS_MODULE, diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 025d1a0..a6ac83a 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -736,16 +736,17 @@ xt_replace_table(struct xt_table *table, } EXPORT_SYMBOL_GPL(xt_replace_table); -struct xt_table *xt_register_table(struct net *net, struct xt_table *table, +struct xt_table *xt_register_table(struct net *net, + const struct xt_table *input_table, struct xt_table_info *bootstrap, struct xt_table_info *newinfo) { int ret; struct xt_table_info *private; - struct xt_table *t; + struct xt_table *t, *table; /* Don't add one object to multiple lists. */ - table = kmemdup(table, sizeof(struct xt_table), GFP_KERNEL); + table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL); if (!table) { ret = -ENOMEM; goto out; -- cgit v0.10.2 From cce5a5c3029f731b5ea17a8a9a953ff742abf0d6 Mon Sep 17 00:00:00 2001 From: Maximilian Engelhardt Date: Mon, 24 Aug 2009 19:24:54 +0200 Subject: netfilter: nf_nat: fix inverted logic for persistent NAT mappings Kernel 2.6.30 introduced a patch [1] for the persistent option in the netfilter SNAT target. This is exactly what we need here so I had a quick look at the code and noticed that the patch is wrong. The logic is simply inverted. The patch below fixes this. Also note that because of this the default behavior of the SNAT target has changed since kernel 2.6.30 as it now ignores the destination IP in choosing the source IP for nating (which should only be the case if the persistent option is set). [1] http://git.eu.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=98d500d66cb7940747b424b245fc6a51ecfbf005 Signed-off-by: Maximilian Engelhardt Signed-off-by: Patrick McHardy diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 3229e0a..b6ddd56 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -212,7 +212,7 @@ find_best_ips_proto(struct nf_conntrack_tuple *tuple, maxip = ntohl(range->max_ip); j = jhash_2words((__force u32)tuple->src.u3.ip, range->flags & IP_NAT_RANGE_PERSISTENT ? - (__force u32)tuple->dst.u3.ip : 0, 0); + 0 : (__force u32)tuple->dst.u3.ip, 0); j = ((u64)j * (maxip - minip + 1)) >> 32; *var_ipp = htonl(minip + j); } -- cgit v0.10.2 From f3abc9b963e004b8c96cd7fbee6fd905f2bfd620 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 24 Aug 2009 19:35:38 +0200 Subject: netfilter: bridge: refcount fix commit f216f082b2b37c4943f1e7c393e2786648d48f6f ([NETFILTER]: bridge netfilter: deal with martians correctly) added a refcount leak on in_dev. Instead of using in_dev_get(), we can use __in_dev_get_rcu(), as netfilter hooks are running under rcu_read_lock(), as pointed by Patrick. Signed-off-by: Eric Dumazet Signed-off-by: Patrick McHardy diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 4fde742..907a82e 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -359,7 +359,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) }, .proto = 0, }; - struct in_device *in_dev = in_dev_get(dev); + struct in_device *in_dev = __in_dev_get_rcu(dev); /* If err equals -EHOSTUNREACH the error is due to a * martian destination or due to the fact that -- cgit v0.10.2 From 7c614d6461399acca5c0ba444f5db49cb332fc08 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 24 Aug 2009 09:42:00 -0700 Subject: rcu: Add "notrace" to RCU function headers used by ftrace Both rcu_read_lock_sched_notrace() and rcu_read_unlock_sched_notrace() are used by ftrace, and thus need to be marked "notrace". Unfortunately, my naive assumption that gcc would see the inner "notrace" does not hold. Kudos to Lai Jiangshan for noting this. Reported-by: Ingo Molnar Bug-spotted-by: Lai Jiangshan 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: <12511321213243-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index ec90fc3..8b4422c 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -191,7 +191,7 @@ static inline void rcu_read_lock_sched(void) __acquire(RCU_SCHED); rcu_read_acquire(); } -static inline void rcu_read_lock_sched_notrace(void) +static inline notrace void rcu_read_lock_sched_notrace(void) { preempt_disable_notrace(); __acquire(RCU_SCHED); @@ -209,7 +209,7 @@ static inline void rcu_read_unlock_sched(void) __release(RCU_SCHED); preempt_enable(); } -static inline void rcu_read_unlock_sched_notrace(void) +static inline notrace void rcu_read_unlock_sched_notrace(void) { rcu_read_release(); __release(RCU_SCHED); -- cgit v0.10.2 From 33f76148ced0e0618062e302d2a9614efdbd4a06 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 24 Aug 2009 09:42:01 -0700 Subject: rcu: Add CPU-offline processing for single-node configurations Add preemptable-RCU plugin to handle the CPU-offline processing. An additional plugin is forthcoming to handle multinode RCU trees, but this current plugin works for configurations up to 32 CPUs (64 CPUs for 64-bit kernels). 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: <12511321213336-git-send-email-> Signed-off-by: Ingo Molnar diff --git a/kernel/rcutree.c b/kernel/rcutree.c index cc02557..000b076 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -84,6 +84,7 @@ extern long rcu_batches_completed_sched(void); static void cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, struct rcu_node *rnp, unsigned long flags); static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags); +static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp); static void __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp); static void __call_rcu(struct rcu_head *head, @@ -920,6 +921,7 @@ static void rcu_offline_cpu(int cpu) { __rcu_offline_cpu(cpu, &rcu_sched_state); __rcu_offline_cpu(cpu, &rcu_bh_state); + rcu_preempt_offline_cpu(cpu); } #else /* #ifdef CONFIG_HOTPLUG_CPU */ diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index cd2ab67..201334c 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -259,6 +259,18 @@ static int rcu_preempted_readers(struct rcu_node *rnp) return !list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1]); } +#ifdef CONFIG_HOTPLUG_CPU + +/* + * Do CPU-offline processing for preemptable RCU. + */ +static void rcu_preempt_offline_cpu(int cpu) +{ + __rcu_offline_cpu(cpu, &rcu_preempt_state); +} + +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ + /* * Check for a quiescent state from the current CPU. When a task blocks, * the task is recorded in the corresponding CPU's rcu_node structure, @@ -395,6 +407,18 @@ static int rcu_preempted_readers(struct rcu_node *rnp) return 0; } +#ifdef CONFIG_HOTPLUG_CPU + +/* + * Because preemptable RCU does not exist, it never needs CPU-offline + * processing. + */ +static void rcu_preempt_offline_cpu(int cpu) +{ +} + +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ + /* * Because preemptable RCU does not exist, it never has any callbacks * to check. -- cgit v0.10.2 From 239a22aaa9d4d574d397b852652684ac610d1e1b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Aug 2009 20:21:51 +0100 Subject: ASoC: Select core DMA when building for S3C64xx Ensure that the core DMA support is available when building for S3C64xx. Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index f8e0fff..68fef00 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -1,6 +1,7 @@ config SND_S3C24XX_SOC tristate "SoC Audio for the Samsung S3CXXXX chips" depends on ARCH_S3C2410 || ARCH_S3C64XX + select S3C64XX_DMA if ARCH_S3C64XX help Say Y or M if you want to add support for codecs attached to the S3C24XX AC97 or I2S interfaces. You will also need to -- cgit v0.10.2 From d2e353f7c3c5fbb3add0341c10ae167ee745d23b Mon Sep 17 00:00:00 2001 From: Wending Weng Date: Mon, 24 Aug 2009 16:05:17 -0400 Subject: Bluetooth: Fix false errors from bcsp_pkt_cull function The error message "Removed only %u out of %u pkts" is printed when multiple to be acked packets are queued. if (i++ >= pkts_to_be_removed) break; This will break out of the loop and increase the counter i when i==pkts_to_be_removed and the loop ends up with i=pkts_to_be_removed+1. The following line if (i != pkts_to_be_removed) { BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed); } will then display the false message. The counter i must not increase on the same statement. Signed-off-by: Wending Weng Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 894b2cb..40aec0f 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -373,8 +373,9 @@ static void bcsp_pkt_cull(struct bcsp_struct *bcsp) i = 0; skb_queue_walk_safe(&bcsp->unack, skb, tmp) { - if (i++ >= pkts_to_be_removed) + if (i >= pkts_to_be_removed) break; + i++; __skb_unlink(skb, &bcsp->unack); kfree_skb(skb); -- cgit v0.10.2 From 9f0f4ae570a148c76be6e86c959c8d4ed912fb1f Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Sun, 23 Aug 2009 17:56:12 +0200 Subject: ARM: OMAP: DMA: Add support for DMA channel self linking on OMAP1510 Implement DMA channel self linking on OMAP1510 using AUTO_INIT and REPEAT flags of the DMA CCR register. Created against linux-2.6.31-rc5. Tested on Amstrad Delta. Signed-off-by: Janusz Krzysztofik Acked-by: Tony Lindgren Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index def14ec..da4cc52 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -1125,6 +1125,11 @@ int omap_dma_running(void) void omap_dma_link_lch(int lch_head, int lch_queue) { if (omap_dma_in_1510_mode()) { + if (lch_head == lch_queue) { + dma_write(dma_read(CCR(lch_head)) | (3 << 8), + CCR(lch_head)); + return; + } printk(KERN_ERR "DMA linking is not supported in 1510 mode\n"); BUG(); return; @@ -1147,6 +1152,11 @@ EXPORT_SYMBOL(omap_dma_link_lch); void omap_dma_unlink_lch(int lch_head, int lch_queue) { if (omap_dma_in_1510_mode()) { + if (lch_head == lch_queue) { + dma_write(dma_read(CCR(lch_head)) & ~(3 << 8), + CCR(lch_head)); + return; + } printk(KERN_ERR "DMA linking is not supported in 1510 mode\n"); BUG(); return; -- cgit v0.10.2 From 7bee549e197c9c0e92b89857a409675c1d5e9dff Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 24 Aug 2009 23:44:59 +0200 Subject: Bluetooth: Add USB autosuspend support to btusb driver This patch adds support of USB autosuspend to the btusb driver. If the device doesn't support remote wakeup, simple support based on up/down is provided. If the device supports remote wakeup, additional support for autosuspend while the interface is up is provided. This is done by queueing URBs in an anchor structure and waking the device up from a work queue on sending. Reception triggers remote wakeup. The last busy facility of the USB autosuspend code is used. To close a race between autosuspend and transmission, a counter of ongoing transmissions is maintained. Add #ifdefs for CONFIG_PM as necessary. Signed-off-by: Oliver Neukum Tested-by: Sarah Sharp Signed-off-by: Marcel Holtmann diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 124db8c..7ba91aa 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -35,7 +35,7 @@ #include #include -#define VERSION "0.5" +#define VERSION "0.6" static int ignore_dga; static int ignore_csr; @@ -145,6 +145,7 @@ static struct usb_device_id blacklist_table[] = { #define BTUSB_INTR_RUNNING 0 #define BTUSB_BULK_RUNNING 1 #define BTUSB_ISOC_RUNNING 2 +#define BTUSB_SUSPENDING 3 struct btusb_data { struct hci_dev *hdev; @@ -157,11 +158,15 @@ struct btusb_data { unsigned long flags; struct work_struct work; + struct work_struct waker; struct usb_anchor tx_anchor; struct usb_anchor intr_anchor; struct usb_anchor bulk_anchor; struct usb_anchor isoc_anchor; + struct usb_anchor deferred; + int tx_in_flight; + spinlock_t txlock; struct usb_endpoint_descriptor *intr_ep; struct usb_endpoint_descriptor *bulk_tx_ep; @@ -174,8 +179,23 @@ struct btusb_data { unsigned int sco_num; int isoc_altsetting; int suspend_count; + int did_iso_resume:1; }; +static int inc_tx(struct btusb_data *data) +{ + unsigned long flags; + int rv; + + spin_lock_irqsave(&data->txlock, flags); + rv = test_bit(BTUSB_SUSPENDING, &data->flags); + if (!rv) + data->tx_in_flight++; + spin_unlock_irqrestore(&data->txlock, flags); + + return rv; +} + static void btusb_intr_complete(struct urb *urb) { struct hci_dev *hdev = urb->context; @@ -202,6 +222,7 @@ static void btusb_intr_complete(struct urb *urb) if (!test_bit(BTUSB_INTR_RUNNING, &data->flags)) return; + usb_mark_last_busy(data->udev); usb_anchor_urb(urb, &data->intr_anchor); err = usb_submit_urb(urb, GFP_ATOMIC); @@ -325,6 +346,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) urb->transfer_flags |= URB_FREE_BUFFER; + usb_mark_last_busy(data->udev); usb_anchor_urb(urb, &data->bulk_anchor); err = usb_submit_urb(urb, mem_flags); @@ -463,6 +485,33 @@ static void btusb_tx_complete(struct urb *urb) { struct sk_buff *skb = urb->context; struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct btusb_data *data = hdev->driver_data; + + BT_DBG("%s urb %p status %d count %d", hdev->name, + urb, urb->status, urb->actual_length); + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + goto done; + + if (!urb->status) + hdev->stat.byte_tx += urb->transfer_buffer_length; + else + hdev->stat.err_tx++; + +done: + spin_lock(&data->txlock); + data->tx_in_flight--; + spin_unlock(&data->txlock); + + kfree(urb->setup_packet); + + kfree_skb(skb); +} + +static void btusb_isoc_tx_complete(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, urb->actual_length); @@ -488,11 +537,17 @@ static int btusb_open(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + err = usb_autopm_get_interface(data->intf); + if (err < 0) + return err; + + data->intf->needs_remote_wakeup = 1; + if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) - return 0; + goto done; if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags)) - return 0; + goto done; err = btusb_submit_intr_urb(hdev, GFP_KERNEL); if (err < 0) @@ -507,17 +562,28 @@ static int btusb_open(struct hci_dev *hdev) set_bit(BTUSB_BULK_RUNNING, &data->flags); btusb_submit_bulk_urb(hdev, GFP_KERNEL); +done: + usb_autopm_put_interface(data->intf); return 0; failed: clear_bit(BTUSB_INTR_RUNNING, &data->flags); clear_bit(HCI_RUNNING, &hdev->flags); + usb_autopm_put_interface(data->intf); return err; } +static void btusb_stop_traffic(struct btusb_data *data) +{ + usb_kill_anchored_urbs(&data->intr_anchor); + usb_kill_anchored_urbs(&data->bulk_anchor); + usb_kill_anchored_urbs(&data->isoc_anchor); +} + static int btusb_close(struct hci_dev *hdev) { struct btusb_data *data = hdev->driver_data; + int err; BT_DBG("%s", hdev->name); @@ -527,13 +593,16 @@ static int btusb_close(struct hci_dev *hdev) cancel_work_sync(&data->work); clear_bit(BTUSB_ISOC_RUNNING, &data->flags); - usb_kill_anchored_urbs(&data->isoc_anchor); - clear_bit(BTUSB_BULK_RUNNING, &data->flags); - usb_kill_anchored_urbs(&data->bulk_anchor); - clear_bit(BTUSB_INTR_RUNNING, &data->flags); - usb_kill_anchored_urbs(&data->intr_anchor); + + btusb_stop_traffic(data); + err = usb_autopm_get_interface(data->intf); + if (err < 0) + return 0; + + data->intf->needs_remote_wakeup = 0; + usb_autopm_put_interface(data->intf); return 0; } @@ -620,7 +689,7 @@ static int btusb_send_frame(struct sk_buff *skb) urb->dev = data->udev; urb->pipe = pipe; urb->context = skb; - urb->complete = btusb_tx_complete; + urb->complete = btusb_isoc_tx_complete; urb->interval = data->isoc_tx_ep->bInterval; urb->transfer_flags = URB_ISO_ASAP; @@ -631,12 +700,21 @@ static int btusb_send_frame(struct sk_buff *skb) le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); hdev->stat.sco_tx++; - break; + goto skip_waking; default: return -EILSEQ; } + err = inc_tx(data); + if (err) { + usb_anchor_urb(urb, &data->deferred); + schedule_work(&data->waker); + err = 0; + goto done; + } + +skip_waking: usb_anchor_urb(urb, &data->tx_anchor); err = usb_submit_urb(urb, GFP_ATOMIC); @@ -644,10 +722,13 @@ static int btusb_send_frame(struct sk_buff *skb) BT_ERR("%s urb %p submission failed", hdev->name, urb); kfree(urb->setup_packet); usb_unanchor_urb(urb); + } else { + usb_mark_last_busy(data->udev); } usb_free_urb(urb); +done: return err; } @@ -719,8 +800,19 @@ static void btusb_work(struct work_struct *work) { struct btusb_data *data = container_of(work, struct btusb_data, work); struct hci_dev *hdev = data->hdev; + int err; if (hdev->conn_hash.sco_num > 0) { + if (!data->did_iso_resume) { + err = usb_autopm_get_interface(data->isoc); + if (err < 0) { + clear_bit(BTUSB_ISOC_RUNNING, &data->flags); + usb_kill_anchored_urbs(&data->isoc_anchor); + return; + } + + data->did_iso_resume = 1; + } if (data->isoc_altsetting != 2) { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->isoc_anchor); @@ -740,9 +832,25 @@ static void btusb_work(struct work_struct *work) usb_kill_anchored_urbs(&data->isoc_anchor); __set_isoc_interface(hdev, 0); + if (data->did_iso_resume) { + data->did_iso_resume = 0; + usb_autopm_put_interface(data->isoc); + } } } +static void btusb_waker(struct work_struct *work) +{ + struct btusb_data *data = container_of(work, struct btusb_data, waker); + int err; + + err = usb_autopm_get_interface(data->intf); + if (err < 0) + return; + + usb_autopm_put_interface(data->intf); +} + static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -812,11 +920,14 @@ static int btusb_probe(struct usb_interface *intf, spin_lock_init(&data->lock); INIT_WORK(&data->work, btusb_work); + INIT_WORK(&data->waker, btusb_waker); + spin_lock_init(&data->txlock); init_usb_anchor(&data->tx_anchor); init_usb_anchor(&data->intr_anchor); init_usb_anchor(&data->bulk_anchor); init_usb_anchor(&data->isoc_anchor); + init_usb_anchor(&data->deferred); hdev = hci_alloc_dev(); if (!hdev) { @@ -941,6 +1052,7 @@ static void btusb_disconnect(struct usb_interface *intf) hci_free_dev(hdev); } +#ifdef CONFIG_PM static int btusb_suspend(struct usb_interface *intf, pm_message_t message) { struct btusb_data *data = usb_get_intfdata(intf); @@ -950,22 +1062,44 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message) if (data->suspend_count++) return 0; + spin_lock_irq(&data->txlock); + if (!(interface_to_usbdev(intf)->auto_pm && data->tx_in_flight)) { + set_bit(BTUSB_SUSPENDING, &data->flags); + spin_unlock_irq(&data->txlock); + } else { + spin_unlock_irq(&data->txlock); + data->suspend_count--; + return -EBUSY; + } + cancel_work_sync(&data->work); + btusb_stop_traffic(data); usb_kill_anchored_urbs(&data->tx_anchor); - usb_kill_anchored_urbs(&data->isoc_anchor); - usb_kill_anchored_urbs(&data->bulk_anchor); - usb_kill_anchored_urbs(&data->intr_anchor); - return 0; } +static void play_deferred(struct btusb_data *data) +{ + struct urb *urb; + int err; + + while ((urb = usb_get_from_anchor(&data->deferred))) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err < 0) + break; + + data->tx_in_flight++; + } + usb_scuttle_anchored_urbs(&data->deferred); +} + static int btusb_resume(struct usb_interface *intf) { struct btusb_data *data = usb_get_intfdata(intf); struct hci_dev *hdev = data->hdev; - int err; + int err = 0; BT_DBG("intf %p", intf); @@ -973,13 +1107,13 @@ static int btusb_resume(struct usb_interface *intf) return 0; if (!test_bit(HCI_RUNNING, &hdev->flags)) - return 0; + goto done; if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) { err = btusb_submit_intr_urb(hdev, GFP_NOIO); if (err < 0) { clear_bit(BTUSB_INTR_RUNNING, &data->flags); - return err; + goto failed; } } @@ -987,9 +1121,10 @@ static int btusb_resume(struct usb_interface *intf) err = btusb_submit_bulk_urb(hdev, GFP_NOIO); if (err < 0) { clear_bit(BTUSB_BULK_RUNNING, &data->flags); - return err; - } else - btusb_submit_bulk_urb(hdev, GFP_NOIO); + goto failed; + } + + btusb_submit_bulk_urb(hdev, GFP_NOIO); } if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) { @@ -999,16 +1134,35 @@ static int btusb_resume(struct usb_interface *intf) btusb_submit_isoc_urb(hdev, GFP_NOIO); } + spin_lock_irq(&data->txlock); + play_deferred(data); + clear_bit(BTUSB_SUSPENDING, &data->flags); + spin_unlock_irq(&data->txlock); + schedule_work(&data->work); + return 0; + +failed: + usb_scuttle_anchored_urbs(&data->deferred); +done: + spin_lock_irq(&data->txlock); + clear_bit(BTUSB_SUSPENDING, &data->flags); + spin_unlock_irq(&data->txlock); + + return err; } +#endif static struct usb_driver btusb_driver = { .name = "btusb", .probe = btusb_probe, .disconnect = btusb_disconnect, +#ifdef CONFIG_PM .suspend = btusb_suspend, .resume = btusb_resume, +#endif .id_table = btusb_table, + .supports_autosuspend = 1, }; static int __init btusb_init(void) -- cgit v0.10.2 From cbe86b98a6aceefe943ada1471eb52fd9ac4c504 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 24 Aug 2009 16:32:50 -0700 Subject: Bluetooth: Add missing selection of CONFIG_CRC16 for L2CAP layer Fix net/bluetooth/l2cap.c build errors: l2cap.c:(.text+0x126035): undefined reference to `crc16' l2cap.c:(.text+0x126323): undefined reference to `crc16' l2cap.c:(.text+0x12668e): undefined reference to `crc16' l2cap.c:(.text+0x12683b): undefined reference to `crc16' l2cap.c:(.text+0x126956): undefined reference to `crc16' net/built-in.o:l2cap.c:(.text+0x129041): more undefined references to `crc16' follow Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 59fdb1d..ed37168 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -34,6 +34,7 @@ menuconfig BT config BT_L2CAP tristate "L2CAP protocol support" depends on BT + select CRC16 help L2CAP (Logical Link Control and Adaptation Protocol) provides connection oriented and connection-less data transport. L2CAP -- cgit v0.10.2 From fa289beca9de9119c7760bd984f3640da21bc94c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 25 Aug 2009 15:17:20 +1000 Subject: perf_counter: Start counting time enabled when group leader gets enabled Currently, if a group is created where the group leader is initially disabled but a non-leader member is initially enabled, and then the leader is subsequently enabled some time later, the time_enabled for the non-leader member will reflect the whole time since it was created, not just the time since the leader was enabled. This is incorrect, because all of the members are effectively disabled while the leader is disabled, since none of the members can go on the PMU if the leader can't. Thus we have to update the ->tstamp_enabled for all the enabled group members when a group leader is enabled, so that the time_enabled computation only counts the time since the leader was enabled. Similarly, when disabling a group leader we have to update the time_enabled and time_running for all of the group members. Also, in update_counter_times, we have to treat a counter whose group leader is disabled as being disabled. Reported-by: Stephane Eranian Signed-off-by: Paul Mackerras Acked-by: Peter Zijlstra Cc: LKML-Reference: <19091.29664.342227.445006@drongo.ozlabs.ibm.com> Signed-off-by: Ingo Molnar diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index f274e19..06bf6a4 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -469,7 +469,8 @@ static void update_counter_times(struct perf_counter *counter) struct perf_counter_context *ctx = counter->ctx; u64 run_end; - if (counter->state < PERF_COUNTER_STATE_INACTIVE) + if (counter->state < PERF_COUNTER_STATE_INACTIVE || + counter->group_leader->state < PERF_COUNTER_STATE_INACTIVE) return; counter->total_time_enabled = ctx->time - counter->tstamp_enabled; @@ -518,7 +519,7 @@ static void __perf_counter_disable(void *info) */ if (counter->state >= PERF_COUNTER_STATE_INACTIVE) { update_context_time(ctx); - update_counter_times(counter); + update_group_times(counter); if (counter == counter->group_leader) group_sched_out(counter, cpuctx, ctx); else @@ -573,7 +574,7 @@ static void perf_counter_disable(struct perf_counter *counter) * in, so we can change the state safely. */ if (counter->state == PERF_COUNTER_STATE_INACTIVE) { - update_counter_times(counter); + update_group_times(counter); counter->state = PERF_COUNTER_STATE_OFF; } @@ -851,6 +852,27 @@ retry: } /* + * Put a counter into inactive state and update time fields. + * Enabling the leader of a group effectively enables all + * the group members that aren't explicitly disabled, so we + * have to update their ->tstamp_enabled also. + * Note: this works for group members as well as group leaders + * since the non-leader members' sibling_lists will be empty. + */ +static void __perf_counter_mark_enabled(struct perf_counter *counter, + struct perf_counter_context *ctx) +{ + struct perf_counter *sub; + + counter->state = PERF_COUNTER_STATE_INACTIVE; + counter->tstamp_enabled = ctx->time - counter->total_time_enabled; + list_for_each_entry(sub, &counter->sibling_list, list_entry) + if (sub->state >= PERF_COUNTER_STATE_INACTIVE) + sub->tstamp_enabled = + ctx->time - sub->total_time_enabled; +} + +/* * Cross CPU call to enable a performance counter */ static void __perf_counter_enable(void *info) @@ -877,8 +899,7 @@ static void __perf_counter_enable(void *info) if (counter->state >= PERF_COUNTER_STATE_INACTIVE) goto unlock; - counter->state = PERF_COUNTER_STATE_INACTIVE; - counter->tstamp_enabled = ctx->time - counter->total_time_enabled; + __perf_counter_mark_enabled(counter, ctx); /* * If the counter is in a group and isn't the group leader, @@ -971,11 +992,9 @@ static void perf_counter_enable(struct perf_counter *counter) * Since we have the lock this context can't be scheduled * in, so we can change the state safely. */ - if (counter->state == PERF_COUNTER_STATE_OFF) { - counter->state = PERF_COUNTER_STATE_INACTIVE; - counter->tstamp_enabled = - ctx->time - counter->total_time_enabled; - } + if (counter->state == PERF_COUNTER_STATE_OFF) + __perf_counter_mark_enabled(counter, ctx); + out: spin_unlock_irq(&ctx->lock); } @@ -1479,9 +1498,7 @@ static void perf_counter_enable_on_exec(struct task_struct *task) counter->attr.enable_on_exec = 0; if (counter->state >= PERF_COUNTER_STATE_INACTIVE) continue; - counter->state = PERF_COUNTER_STATE_INACTIVE; - counter->tstamp_enabled = - ctx->time - counter->total_time_enabled; + __perf_counter_mark_enabled(counter, ctx); enabled = 1; } -- cgit v0.10.2 From a4be7c2778d1fd8e0a8a5607bec91fa221ab2c91 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 19 Aug 2009 11:18:27 +0200 Subject: perf_counter: Allow sharing of output channels Provide the ability to configure a counter to send its output to another (already existing) counter's output stream. Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: stephane eranian Cc: Paul Mackerras LKML-Reference: <20090819092023.980284148@chello.nl> Signed-off-by: Ingo Molnar diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index b53f700..e022b84 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h @@ -216,6 +216,7 @@ struct perf_counter_attr { #define PERF_COUNTER_IOC_REFRESH _IO ('$', 2) #define PERF_COUNTER_IOC_RESET _IO ('$', 3) #define PERF_COUNTER_IOC_PERIOD _IOW('$', 4, u64) +#define PERF_COUNTER_IOC_SET_OUTPUT _IO ('$', 5) enum perf_counter_ioc_flags { PERF_IOC_FLAG_GROUP = 1U << 0, @@ -415,6 +416,9 @@ enum perf_callchain_context { PERF_CONTEXT_MAX = (__u64)-4095, }; +#define PERF_FLAG_FD_NO_GROUP (1U << 0) +#define PERF_FLAG_FD_OUTPUT (1U << 1) + #ifdef __KERNEL__ /* * Kernel-internal data types and definitions: @@ -536,6 +540,7 @@ struct perf_counter { struct list_head sibling_list; int nr_siblings; struct perf_counter *group_leader; + struct perf_counter *output; const struct pmu *pmu; enum perf_counter_active_state state; diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 06bf6a4..53abcbe 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -1692,6 +1692,11 @@ static void free_counter(struct perf_counter *counter) atomic_dec(&nr_task_counters); } + if (counter->output) { + fput(counter->output->filp); + counter->output = NULL; + } + if (counter->destroy) counter->destroy(counter); @@ -1977,6 +1982,8 @@ unlock: return ret; } +int perf_counter_set_output(struct perf_counter *counter, int output_fd); + static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct perf_counter *counter = file->private_data; @@ -2000,6 +2007,9 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case PERF_COUNTER_IOC_PERIOD: return perf_counter_period(counter, (u64 __user *)arg); + case PERF_COUNTER_IOC_SET_OUTPUT: + return perf_counter_set_output(counter, arg); + default: return -ENOTTY; } @@ -2270,6 +2280,11 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) WARN_ON_ONCE(counter->ctx->parent_ctx); mutex_lock(&counter->mmap_mutex); + if (counter->output) { + ret = -EINVAL; + goto unlock; + } + if (atomic_inc_not_zero(&counter->mmap_count)) { if (nr_pages != counter->data->nr_pages) ret = -EINVAL; @@ -2655,6 +2670,7 @@ static int perf_output_begin(struct perf_output_handle *handle, struct perf_counter *counter, unsigned int size, int nmi, int sample) { + struct perf_counter *output_counter; struct perf_mmap_data *data; unsigned int offset, head; int have_lost; @@ -2664,13 +2680,17 @@ static int perf_output_begin(struct perf_output_handle *handle, u64 lost; } lost_event; + rcu_read_lock(); /* * For inherited counters we send all the output towards the parent. */ if (counter->parent) counter = counter->parent; - rcu_read_lock(); + output_counter = rcu_dereference(counter->output); + if (output_counter) + counter = output_counter; + data = rcu_dereference(counter->data); if (!data) goto out; @@ -4218,6 +4238,57 @@ err_size: goto out; } +int perf_counter_set_output(struct perf_counter *counter, int output_fd) +{ + struct perf_counter *output_counter = NULL; + struct file *output_file = NULL; + struct perf_counter *old_output; + int fput_needed = 0; + int ret = -EINVAL; + + if (!output_fd) + goto set; + + output_file = fget_light(output_fd, &fput_needed); + if (!output_file) + return -EBADF; + + if (output_file->f_op != &perf_fops) + goto out; + + output_counter = output_file->private_data; + + /* Don't chain output fds */ + if (output_counter->output) + goto out; + + /* Don't set an output fd when we already have an output channel */ + if (counter->data) + goto out; + + atomic_long_inc(&output_file->f_count); + +set: + mutex_lock(&counter->mmap_mutex); + old_output = counter->output; + rcu_assign_pointer(counter->output, output_counter); + mutex_unlock(&counter->mmap_mutex); + + if (old_output) { + /* + * we need to make sure no existing perf_output_*() + * is still referencing this counter. + */ + synchronize_rcu(); + fput(old_output->filp); + } + + ret = 0; +out: + fput_light(output_file, fput_needed); + return ret; +} + /** * sys_perf_counter_open - open a performance counter, associate it to a task/cpu * @@ -4240,7 +4311,7 @@ SYSCALL_DEFINE5(perf_counter_open, int ret; /* for future expandability... */ - if (flags) + if (flags & ~(PERF_FLAG_FD_NO_GROUP | PERF_FLAG_FD_OUTPUT)) return -EINVAL; ret = perf_copy_attr(attr_uptr, &attr); @@ -4268,7 +4339,7 @@ SYSCALL_DEFINE5(perf_counter_open, * Look up the group leader (we will attach this counter to it): */ group_leader = NULL; - if (group_fd != -1) { + if (group_fd != -1 && !(flags & PERF_FLAG_FD_NO_GROUP)) { ret = -EINVAL; group_file = fget_light(group_fd, &fput_needed); if (!group_file) @@ -4310,6 +4381,12 @@ SYSCALL_DEFINE5(perf_counter_open, if (!counter_file) goto err_free_put_context; + if (flags & PERF_FLAG_FD_OUTPUT) { + ret = perf_counter_set_output(counter, group_fd); + if (ret) + goto err_free_put_context; + } + counter->filp = counter_file; WARN_ON_ONCE(ctx->parent_ctx); mutex_lock(&ctx->mutex); -- cgit v0.10.2 From 31b47cf7609288893a10706c648faa932c7aef90 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Aug 2009 20:28:04 +0100 Subject: genirq: Add prototype for handle_nested_irq() The function is supposed to be called from the primary IRQ handler for a demultiplexing chip so make a protype visible for them. Signed-off-by: Mark Brown Cc: Mark Brown LKML-Reference: <1251142084-9852-1-git-send-email-broonie@opensource.wolfsonmicro.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/irq.h b/include/linux/irq.h index 6956df9..9e9eb76 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -282,6 +282,7 @@ extern void handle_edge_irq(unsigned int irq, struct irq_desc *desc); extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc); extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc); extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc); +extern void handle_nested_irq(unsigned int irq); /* * Monolithic do_IRQ implementation. -- cgit v0.10.2 From 9b30050908fad96968497e73b88626056ea33c96 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 24 Aug 2009 17:45:50 +0300 Subject: OMAP: McBSP: Use textual values in DMA operating mode sysfs files Use more descriptive than numerical value when showing and storing the McBSP DMA operating mode. Show function is using similar syntax than e.g. the led triggers so that all possible values for store function are printed but with current value surrounded with square brackets. Signed-off-by: Jarkko Nikula Cc: Peter Ujfalusi Acked-by: Eduardo Valentin Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index b63a720..ee60ab6 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -1161,25 +1161,31 @@ static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store); THRESHOLD_PROP_BUILDER(max_tx_thres); THRESHOLD_PROP_BUILDER(max_rx_thres); +static const char *dma_op_modes[] = { + "element", "threshold", "frame", +}; + static ssize_t dma_op_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); - int dma_op_mode; + int dma_op_mode, i = 0; + ssize_t len = 0; + const char * const *s; spin_lock_irq(&mcbsp->lock); dma_op_mode = mcbsp->dma_op_mode; spin_unlock_irq(&mcbsp->lock); - return sprintf(buf, "current mode: %d\n" - "possible mode values are:\n" - "%d - %s\n" - "%d - %s\n" - "%d - %s\n", - dma_op_mode, - MCBSP_DMA_MODE_ELEMENT, "element mode", - MCBSP_DMA_MODE_THRESHOLD, "threshold mode", - MCBSP_DMA_MODE_FRAME, "frame mode"); + for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) { + if (dma_op_mode == i) + len += sprintf(buf + len, "[%s] ", *s); + else + len += sprintf(buf + len, "%s ", *s); + } + len += sprintf(buf + len, "\n"); + + return len; } static ssize_t dma_op_mode_store(struct device *dev, @@ -1187,26 +1193,22 @@ static ssize_t dma_op_mode_store(struct device *dev, const char *buf, size_t size) { struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); - unsigned long val; - int status; + const char * const *s; + int i = 0; - status = strict_strtoul(buf, 0, &val); - if (status) - return status; + for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) + if (sysfs_streq(buf, *s)) + break; - spin_lock_irq(&mcbsp->lock); + if (i == ARRAY_SIZE(dma_op_modes)) + return -EINVAL; + spin_lock_irq(&mcbsp->lock); if (!mcbsp->free) { size = -EBUSY; goto unlock; } - - if (val > MCBSP_DMA_MODE_FRAME || val < MCBSP_DMA_MODE_ELEMENT) { - size = -EINVAL; - goto unlock; - } - - mcbsp->dma_op_mode = val; + mcbsp->dma_op_mode = i; unlock: spin_unlock_irq(&mcbsp->lock); -- cgit v0.10.2 From 32080af7a612e8c56131d6bdcd268cd9e8b0add1 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sun, 23 Aug 2009 12:24:26 +0300 Subject: ASoC: OMAP: Fix setup of XCCR and RCCR registers in McBSP DAI Commit ca6e2ce08679c094878d7f39a0349a7db1d13675 is setting up few XCCR and RCCR bits for I2S and DPS_A formats. Part of the bits are already set for all formats and I believe that XDISABLE and RDISABLE bits are format independent. As XCCR and RCCR are found only from OMAP2430 and OMAP34xx, I move setup of XDISABLE and RDISABLE to where those cpu's are tested and remove format dependent part for simplicity. Signed-off-by: Jarkko Nikula Acked-by: Eero Nurkkala Cc: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index f5387d9..89e8bce 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -379,8 +379,8 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, regs->xcr2 |= XFIG; } if (cpu_is_omap2430() || cpu_is_omap34xx()) { - regs->xccr = DXENDLY(1) | XDMAEN; - regs->rccr = RFULL_CYCLE | RDMAEN; + regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE; + regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE; } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -388,15 +388,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, /* 1-bit data delay */ regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); - regs->rccr |= RFULL_CYCLE | RDMAEN | RDISABLE; - regs->xccr |= (DXENDLY(1) | XDMAEN | XDISABLE); break; case SND_SOC_DAIFMT_DSP_A: /* 1-bit data delay */ regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); - regs->rccr |= RFULL_CYCLE | RDMAEN | RDISABLE; - regs->xccr |= (DXENDLY(1) | XDMAEN | XDISABLE); /* Invert FS polarity configuration */ temp_fmt ^= SND_SOC_DAIFMT_NB_IF; break; -- cgit v0.10.2 From d09a2afc9359407114b7062519101f1ee2d05388 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sun, 23 Aug 2009 12:24:27 +0300 Subject: ARM: OMAP: McBSP: Merge two functions into omap_mcbsp_start/_stop Functionality of functions omap_mcbsp_xmit_enable and omap_mcbsp_recv_enable can be merged into omap_mcbsp_start and omap_mcbsp_stop since API of those omap_mcbsp_start and omap_mcbsp_stop was changed recently allowing to start and stop individually the transmitter and receiver. This cleans up the code in arch/arm/plat-omap/mcbsp.c and in sound/soc/omap/omap-mcbsp.c which was the only user for those removed functions. Signed-off-by: Jarkko Nikula Acked-by: Eero Nurkkala Cc: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index 70e950e..63a3f25 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h @@ -436,8 +436,6 @@ int omap_mcbsp_request(unsigned int id); void omap_mcbsp_free(unsigned int id); void omap_mcbsp_start(unsigned int id, int tx, int rx); void omap_mcbsp_stop(unsigned int id, int tx, int rx); -void omap_mcbsp_xmit_enable(unsigned int id, u8 enable); -void omap_mcbsp_recv_enable(unsigned int id, u8 enable); void omap_mcbsp_xmit_word(unsigned int id, u32 word); u32 omap_mcbsp_recv_word(unsigned int id); diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index ee60ab6..8dc7927 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -529,11 +529,13 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) } /* Enable transmitter and receiver */ + tx &= 1; w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | (tx & 1)); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | tx); + rx &= 1; w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w | (rx & 1)); + OMAP_MCBSP_WRITE(io_base, SPCR1, w | rx); /* * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec @@ -549,6 +551,16 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); } + if (cpu_is_omap2430() || cpu_is_omap34xx()) { + /* Release the transmitter and receiver */ + w = OMAP_MCBSP_READ(io_base, XCCR); + w &= ~(tx ? XDISABLE : 0); + OMAP_MCBSP_WRITE(io_base, XCCR, w); + w = OMAP_MCBSP_READ(io_base, RCCR); + w &= ~(rx ? RDISABLE : 0); + OMAP_MCBSP_WRITE(io_base, RCCR, w); + } + /* Dump McBSP Regs */ omap_mcbsp_dump_reg(id); } @@ -570,12 +582,24 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx) io_base = mcbsp->io_base; /* Reset transmitter */ + tx &= 1; + if (cpu_is_omap2430() || cpu_is_omap34xx()) { + w = OMAP_MCBSP_READ(io_base, XCCR); + w |= (tx ? XDISABLE : 0); + OMAP_MCBSP_WRITE(io_base, XCCR, w); + } w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(tx & 1)); + OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~tx); /* Reset receiver */ + rx &= 1; + if (cpu_is_omap2430() || cpu_is_omap34xx()) { + w = OMAP_MCBSP_READ(io_base, RCCR); + w |= (tx ? RDISABLE : 0); + OMAP_MCBSP_WRITE(io_base, RCCR, w); + } w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(rx & 1)); + OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~rx); idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | OMAP_MCBSP_READ(io_base, SPCR1)) & 1); @@ -588,58 +612,6 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx) } EXPORT_SYMBOL(omap_mcbsp_stop); -void omap_mcbsp_xmit_enable(unsigned int id, u8 enable) -{ - struct omap_mcbsp *mcbsp; - void __iomem *io_base; - u16 w; - - if (!(cpu_is_omap2430() || cpu_is_omap34xx())) - return; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return; - } - - mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; - - w = OMAP_MCBSP_READ(io_base, XCCR); - - if (enable) - OMAP_MCBSP_WRITE(io_base, XCCR, w & ~(XDISABLE)); - else - OMAP_MCBSP_WRITE(io_base, XCCR, w | XDISABLE); -} -EXPORT_SYMBOL(omap_mcbsp_xmit_enable); - -void omap_mcbsp_recv_enable(unsigned int id, u8 enable) -{ - struct omap_mcbsp *mcbsp; - void __iomem *io_base; - u16 w; - - if (!(cpu_is_omap2430() || cpu_is_omap34xx())) - return; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return; - } - - mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; - - w = OMAP_MCBSP_READ(io_base, RCCR); - - if (enable) - OMAP_MCBSP_WRITE(io_base, RCCR, w & ~(RDISABLE)); - else - OMAP_MCBSP_WRITE(io_base, RCCR, w | RDISABLE); -} -EXPORT_SYMBOL(omap_mcbsp_recv_enable); - /* polled mcbsp i/o operations */ int omap_mcbsp_pollwrite(unsigned int id, u16 buf) { diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 89e8bce..0e173e7 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -231,11 +231,6 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: mcbsp_data->active++; omap_mcbsp_start(mcbsp_data->bus_id, play, !play); - /* Make sure data transfer is frame synchronized */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - omap_mcbsp_xmit_enable(mcbsp_data->bus_id, 1); - else - omap_mcbsp_recv_enable(mcbsp_data->bus_id, 1); break; case SNDRV_PCM_TRIGGER_STOP: -- cgit v0.10.2 From 05f5f477082f0b192dab5ac25ccc5d468d98ecbd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Aug 2009 13:10:18 +0200 Subject: ALSA: hda - Generalize input pin parsing in patch_realtek.c Provide a standard parser for input pins to create the input mixer and input source controls instead of having a difference one for each Realtek codec. The new helper parses the codec connections dynamically isntead of fixed indicies. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index dd25db9..3c8773a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4311,8 +4311,6 @@ static int add_control(struct alc_spec *spec, int type, const char *name, #define alc880_fixed_pin_idx(nid) ((nid) - 0x14) #define alc880_is_multi_pin(nid) ((nid) >= 0x18) #define alc880_multi_pin_idx(nid) ((nid) - 0x18) -#define alc880_is_input_pin(nid) ((nid) >= 0x18) -#define alc880_input_pin_idx(nid) ((nid) - 0x18) #define alc880_idx_to_dac(nid) ((nid) + 0x02) #define alc880_dac_to_idx(nid) ((nid) - 0x02) #define alc880_idx_to_mixer(nid) ((nid) + 0x0c) @@ -4480,31 +4478,61 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, return 0; } +static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int pincap = snd_hda_query_pin_caps(codec, nid); + return (pincap & AC_PINCAP_IN) != 0; +} + /* create playback/capture controls for input pins */ -static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) +static int alc_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + hda_nid_t mixer, + hda_nid_t cap1, hda_nid_t cap2) { + struct alc_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx; for (i = 0; i < AUTO_PIN_LAST; i++) { - if (alc880_is_input_pin(cfg->input_pins[i])) { - idx = alc880_input_pin_idx(cfg->input_pins[i]); - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], - idx, 0x0b); - if (err < 0) - return err; + hda_nid_t pin; + + pin = cfg->input_pins[i]; + if (!alc_is_input_pin(codec, pin)) + continue; + + if (mixer) { + idx = get_connection_index(codec, mixer, pin); + if (idx >= 0) { + err = new_analog_input(spec, pin, + auto_pin_cfg_labels[i], + idx, mixer); + if (err < 0) + return err; + } + } + + if (!cap1) + continue; + idx = get_connection_index(codec, cap1, pin); + if (idx < 0 && cap2) + idx = get_connection_index(codec, cap2, pin); + if (idx >= 0) { imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = - alc880_input_pin_idx(cfg->input_pins[i]); + imux->items[imux->num_items].index = idx; imux->num_items++; } } return 0; } +static int alc880_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09); +} + static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_type) { @@ -4570,7 +4598,7 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; - if (alc880_is_input_pin(nid)) { + if (alc_is_input_pin(codec, nid)) { alc_set_input_pin(codec, nid, i); if (nid != ALC880_PIN_CD_NID && (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) @@ -4613,7 +4641,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec) "Headphone"); if (err < 0) return err; - err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = alc880_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -6006,39 +6034,10 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, } /* create playback/capture controls for input pins */ -static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec, +static int alc260_auto_create_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (cfg->input_pins[i] >= 0x12) { - idx = cfg->input_pins[i] - 0x12; - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], idx, - 0x07); - if (err < 0) - return err; - imux->items[imux->num_items].label = - auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } - if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){ - idx = cfg->input_pins[i] - 0x09; - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], idx, - 0x07); - if (err < 0) - return err; - imux->items[imux->num_items].label = - auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } - } - return 0; + return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05); } static void alc260_auto_set_output_and_unmute(struct hda_codec *codec, @@ -6152,7 +6151,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec) return err; if (!spec->kctls.list) return 0; /* can't find valid BIOS pin config */ - err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = alc260_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -9464,6 +9463,12 @@ static struct snd_pci_quirk alc882_pinfix_tbl[] = { /* * BIOS auto configuration */ +static int alc882_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22); +} + static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, int dac_idx) @@ -9604,44 +9609,73 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) static int alc882_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *autocfg = &spec->autocfg; - unsigned int wcap; - int i; - int err = alc880_parse_auto_config(codec); + static hda_nid_t alc882_ignore[] = { 0x1d, 0 }; + int i, err; + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + alc882_ignore); if (err < 0) return err; - else if (!err) - return 0; /* no config found */ + if (!spec->autocfg.line_outs) + return 0; /* can't find valid BIOS pin config */ - err = alc_auto_add_mic_boost(codec); + err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = alc880_auto_create_extra_out(spec, + spec->autocfg.speaker_pins[0], + "Speaker"); + if (err < 0) + return err; + err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], + "Headphone"); + if (err < 0) + return err; + err = alc882_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; - /* hack - override the init verbs */ - spec->init_verbs[0] = alc883_auto_init_verbs; + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + /* check multiple SPDIF-out (for recent codecs) */ + for (i = 0; i < spec->autocfg.dig_outs; i++) { + hda_nid_t dig_nid; + err = snd_hda_get_connections(codec, + spec->autocfg.dig_out_pins[i], + &dig_nid, 1); + if (err < 0) + continue; + if (!i) + spec->multiout.dig_out_nid = dig_nid; + else { + spec->multiout.slave_dig_outs = spec->slave_dig_outs; + spec->slave_dig_outs[i - 1] = dig_nid; + if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1) + break; + } + } + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = ALC880_DIGIN_NID; + + if (spec->kctls.list) + add_mixer(spec, spec->kctls.list); + + add_verb(spec, alc883_auto_init_verbs); /* if ADC 0x07 is available, initialize it, too */ - wcap = get_wcaps(codec, 0x07); - wcap = get_wcaps_type(wcap); - if (wcap == AC_WID_AUD_IN) + if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN) add_verb(spec, alc882_adc1_init_verbs); - /* 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; - } + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux[0]; + + alc_ssid_check(codec, 0x15, 0x1b, 0x14); + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; return 1; /* config found */ } @@ -10820,27 +10854,8 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, return 0; } -static int alc262_auto_create_analog_input_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - int err; - - err = alc880_auto_create_analog_input_ctls(spec, cfg); - if (err < 0) - return err; - /* 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]; - imux->items[imux->num_items].label = "Int Mic"; - imux->items[imux->num_items].index = 0x09; - imux->num_items++; - } - return 0; -} - +#define alc262_auto_create_input_ctls \ + alc880_auto_create_input_ctls /* * generic initialization of ADC, input mixers and output mixers @@ -11158,7 +11173,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec) err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; - err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = alc262_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -12212,46 +12227,10 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, } /* create playback/capture controls for input pins */ -static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec, +static int alc268_auto_create_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, idx1, dmic_nid; - - dmic_nid = 0x12; - while (dmic_nid <= 0x13) { - for (i = 0; i < AUTO_PIN_LAST; i++) { - switch (cfg->input_pins[i]) { - case 0x18: - idx1 = 0; /* Mic 1 */ - break; - case 0x19: - idx1 = 1; /* Mic 2 */ - break; - case 0x1a: - idx1 = 2; /* Line In */ - break; - case 0x1c: - idx1 = 3; /* CD */ - break; - case 0x12: - case 0x13: - if (cfg->input_pins[i] != dmic_nid) - continue; - idx1 = 6; /* digital mics */ - break; - default: - continue; - } - imux->items[imux->num_items].label = - auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = idx1; - imux->num_items++; - } - imux++; - dmic_nid++; - } - return 0; + return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24); } static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) @@ -12328,7 +12307,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; - err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = alc268_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -13088,8 +13067,8 @@ static struct hda_verb alc269_init_verbs[] = { #define alc269_auto_create_multi_out_ctls \ alc268_auto_create_multi_out_ctls -#define alc269_auto_create_analog_input_ctls \ - alc262_auto_create_analog_input_ctls +#define alc269_auto_create_input_ctls \ + alc268_auto_create_input_ctls #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc269_loopbacks alc880_loopbacks @@ -13139,7 +13118,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; - err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = alc269_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -14120,49 +14099,10 @@ static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) } /* create playback/capture controls for input pins */ -static int alc861_auto_create_analog_input_ctls(struct hda_codec *codec, +static int alc861_auto_create_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - struct alc_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx, idx1; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - switch (cfg->input_pins[i]) { - case 0x0c: - idx1 = 1; - idx = 2; /* Line In */ - break; - case 0x0f: - idx1 = 2; - idx = 2; /* Line In */ - break; - case 0x0d: - idx1 = 0; - idx = 1; /* Mic In */ - break; - case 0x10: - idx1 = 3; - idx = 1; /* Mic In */ - break; - case 0x11: - idx1 = 4; - idx = 0; /* CD */ - break; - default: - continue; - } - - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], idx, 0x15); - if (err < 0) - return err; - - imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = idx1; - imux->num_items++; - } - return 0; + return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0); } static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, @@ -14259,7 +14199,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = alc861_auto_create_analog_input_ctls(codec, &spec->autocfg); + err = alc861_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -15140,6 +15080,13 @@ static struct alc_config_preset alc861vd_presets[] = { /* * BIOS auto configuration */ +static int alc861vd_auto_create_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0); +} + + static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, int dac_idx) { @@ -15174,7 +15121,6 @@ static void alc861vd_auto_init_hp_out(struct hda_codec *codec) alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); } -#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid) #define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID static void alc861vd_auto_init_analog_input(struct hda_codec *codec) @@ -15184,7 +15130,7 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; - if (alc861vd_is_input_pin(nid)) { + if (alc_is_input_pin(codec, nid)) { alc_set_input_pin(codec, nid, i); if (nid != ALC861VD_PIN_CD_NID && (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) @@ -15347,7 +15293,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) "Headphone"); if (err < 0) return err; - err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -17089,43 +17035,9 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, return 0; } -static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int pincap = snd_hda_query_pin_caps(codec, nid); - return (pincap & AC_PINCAP_IN) != 0; -} - /* create playback/capture controls for input pins */ -static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct alc_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (alc662_is_input_pin(codec, cfg->input_pins[i])) { - idx = get_connection_index(codec, 0x0b, - cfg->input_pins[i]); - if (idx >= 0) { - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], - idx, 0x0b); - if (err < 0) - return err; - } - idx = get_connection_index(codec, 0x22, - cfg->input_pins[i]); - if (idx >= 0) { - imux->items[imux->num_items].label = - auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } - } - } - return 0; -} +#define alc662_auto_create_input_ctls \ + alc880_auto_create_input_ctls static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, @@ -17179,7 +17091,7 @@ static void alc662_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; - if (alc662_is_input_pin(codec, nid)) { + if (alc_is_input_pin(codec, nid)) { alc_set_input_pin(codec, nid, i); if (nid != ALC662_PIN_CD_NID && (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) @@ -17220,7 +17132,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec) "Headphone"); if (err < 0) return err; - err = alc662_auto_create_analog_input_ctls(codec, &spec->autocfg); + err = alc662_auto_create_input_ctls(codec, &spec->autocfg); if (err < 0) return err; -- cgit v0.10.2 From faf907c7ba3d7df6266366556817f2ef7314640a Mon Sep 17 00:00:00 2001 From: Shine Liu Date: Tue, 25 Aug 2009 20:05:50 +0800 Subject: ASoC: S3C platform: Fix s3c2410_dma_started() called at improper time s3c24xx dma has the auto reload feature, when the the trnasfer is done, CURR_TC(DSTAT[19:0], current value of transfer count) reaches 0, and DMA ACK becomes 1, and then, TC(DCON[19:0]) will be loaded into CURR_TC. So the transmission is repeated. IRQ is issued while auto reload occurs. We change the DISRC and DCON[19:0] in the ISR, but at this time, the auto reload has been performed already. The first block is being re-transmitted by the DMA. So we need rewrite the DISRC and DCON[19:0] for the next block immediatly after the this block has been started to be transported. The function s3c2410_dma_started() is for this perpose, which is called in the form of "s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STARTED);" in s3c24xx_pcm_trigger(). But it is not correct. DMA transmission won't start until DMA REQ signal arrived, it is the time s3c24xx_snd_txctrl(1) or s3c24xx_snd_rxctrl(1) is called in s3c24xx_i2s_trigger(). In the current framework, s3c24xx_pcm_trigger() is always called before s3c24xx_pcm_trigger(). So the s3c2410_dma_started() should be called in s3c24xx_pcm_trigger() after s3c24xx_snd_txctrl(1) or s3c24xx_snd_rxctrl(1) is called in this function. However, s3c2410_dma_started() is dma related, to call this function we should provide the channel number, which is given by substream->runtime->private_data->params->channel. The private_data points to a struct s3c24xx_runtime_data object, which is define in s3c24xx_pcm.c, so s3c2410_dma_started() can't be called in s3c24xx_i2s.c Fix this by moving the call to signal the DMA started to the DAI drivers. Signed-off-by: Shine Liu Signed-off-by: Shine Liu Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index ebfb2f6..11d8717 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -387,6 +387,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); unsigned long irqs; int ret = 0; + int channel = ((struct s3c24xx_pcm_dma_params *) + rtd->dai->cpu_dai->dma_data)->channel; pr_debug("Entered %s\n", __func__); @@ -416,6 +418,14 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, s3c2412_snd_txctrl(i2s, 1); local_irq_restore(irqs); + + /* + * Load the next buffer to DMA to meet the reqirement + * of the auto reload mechanism of S3C24XX. + * This call won't bother S3C64XX. + */ + s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); + break; case SNDRV_PCM_TRIGGER_STOP: diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index bf16f20..fc1beb0 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -290,6 +290,9 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { u32 ac_glbctrl; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int channel = ((struct s3c24xx_pcm_dma_params *) + rtd->dai->cpu_dai->dma_data)->channel; ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); switch (cmd) { @@ -312,6 +315,8 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, } writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); + s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); + return 0; } @@ -334,6 +339,9 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { u32 ac_glbctrl; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int channel = ((struct s3c24xx_pcm_dma_params *) + rtd->dai->cpu_dai->dma_data)->channel; ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); switch (cmd) { @@ -349,6 +357,8 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, } writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); + s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); + return 0; } diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 556e35f..40e2c47 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -279,6 +279,9 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int channel = ((struct s3c24xx_pcm_dma_params *) + rtd->dai->cpu_dai->dma_data)->channel; pr_debug("Entered %s\n", __func__); @@ -296,6 +299,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, s3c24xx_snd_rxctrl(1); else s3c24xx_snd_txctrl(1); + + s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 8a93196..5cbbdc8 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -255,7 +255,6 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: prtd->state |= ST_RUNNING; s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); - s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STARTED); break; case SNDRV_PCM_TRIGGER_STOP: -- cgit v0.10.2 From 74f7a6552c8d76ffc5e11eb8d9d6c07238b9ae77 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Aug 2009 15:33:08 +0200 Subject: netfilter: nf_conntrack: log packets dropped by helpers Log packets dropped by helpers using the netfilter logging API. This is useful in combination with nfnetlink_log to analyze those packets in userspace for debugging. Signed-off-by: Patrick McHardy diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 9ac2fdc..aa95bb8 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -26,6 +26,7 @@ #include #include #include +#include int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, struct nf_conn *ct, @@ -113,8 +114,11 @@ static unsigned int ipv4_confirm(unsigned int hooknum, ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), ct, ctinfo); - if (ret != NF_ACCEPT) + if (ret != NF_ACCEPT) { + nf_log_packet(NFPROTO_IPV4, hooknum, skb, in, out, NULL, + "nf_ct_%s: dropping packet", helper->name); return ret; + } if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { typeof(nf_nat_seq_adjust_hook) seq_adjust; diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index a7f4cd6..5f2ec20 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -27,6 +27,7 @@ #include #include #include +#include static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, struct nf_conntrack_tuple *tuple) @@ -176,8 +177,11 @@ static unsigned int ipv6_confirm(unsigned int hooknum, } ret = helper->help(skb, protoff, ct, ctinfo); - if (ret != NF_ACCEPT) + if (ret != NF_ACCEPT) { + nf_log_packet(NFPROTO_IPV6, hooknum, skb, in, out, NULL, + "nf_ct_%s: dropping packet", helper->name); return ret; + } out: /* We've seen it coming out the other side: confirm it */ return nf_conntrack_confirm(skb); -- cgit v0.10.2 From 005155b1f626d2b2d7932e4afdf4fead168c6888 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 25 Aug 2009 15:35:12 +0200 Subject: x86: Fix x86_model test in es7000_apic_is_cluster() For the x86_model to be greater than 6 or less than 12 is logically always true. Signed-off-by: Roel Kluin Cc: Andrew Morton Cc: Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c index 69328ac..420f95d 100644 --- a/arch/x86/kernel/apic/es7000_32.c +++ b/arch/x86/kernel/apic/es7000_32.c @@ -167,7 +167,7 @@ static int es7000_apic_is_cluster(void) { /* MPENTIUMIII */ if (boot_cpu_data.x86 == 6 && - (boot_cpu_data.x86_model >= 7 || boot_cpu_data.x86_model <= 11)) + (boot_cpu_data.x86_model >= 7 && boot_cpu_data.x86_model <= 11)) return 1; return 0; -- cgit v0.10.2 From cb162b6bf2f445d67a45f5485d4ce32addaf8fe0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Aug 2009 16:05:03 +0200 Subject: ALSA: hda - Improve auto-cfg mixer name for ALC880 When there is only one DAC is used for ALC880, try to assign a better name, either Speaker or Front, depending on the output pin type. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3c8773a..07fbf7d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4398,13 +4398,19 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, if (err < 0) return err; } else { - sprintf(name, "%s Playback Volume", chname[i]); + const char *pfx; + if (cfg->line_outs == 1 && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + pfx = "Speaker"; + else + pfx = chname[i]; + sprintf(name, "%s Playback Volume", pfx); err = add_control(spec, ALC_CTL_WIDGET_VOL, name, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - sprintf(name, "%s Playback Switch", chname[i]); + sprintf(name, "%s Playback Switch", pfx); err = add_control(spec, ALC_CTL_BIND_MUTE, name, HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); -- cgit v0.10.2 From 23112d6d2d9b265c959ecb671366c7c3b9c83611 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Aug 2009 16:07:08 +0200 Subject: ALSA: hda - Improve auto-cfg mixer name for ALC260 Instead of fixed "Front" mixer name, try to assign a better name, e.g. "Master" or "Speaker" fot the primary output volume controls of ALC260 codec. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 07fbf7d..00ed126 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6017,7 +6017,14 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, nid = cfg->line_out_pins[0]; if (nid) { - err = alc260_add_playback_controls(spec, nid, "Front", &vols); + const char *pfx; + if (!cfg->speaker_pins[0] && !cfg->hp_pins[0]) + pfx = "Master"; + else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + pfx = "Speaker"; + else + pfx = "Front"; + err = alc260_add_playback_controls(spec, nid, pfx, &vols); if (err < 0) return err; } -- cgit v0.10.2 From 3a6c2b419b7768703cfb2cabdb894517c5065e33 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Aug 2009 16:07:40 +0200 Subject: netlink: constify nlmsghdr arguments Consitfy nlmsghdr arguments to a couple of functions as preparation for the next patch, which will constify the netlink message data in all nfnetlink users. Signed-off-by: Patrick McHardy diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 5ba398e..0fbecbb 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -217,12 +217,13 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb); struct netlink_callback { - struct sk_buff *skb; - struct nlmsghdr *nlh; - int (*dump)(struct sk_buff * skb, struct netlink_callback *cb); - int (*done)(struct netlink_callback *cb); - int family; - long args[6]; + struct sk_buff *skb; + const struct nlmsghdr *nlh; + int (*dump)(struct sk_buff * skb, + struct netlink_callback *cb); + int (*done)(struct netlink_callback *cb); + int family; + long args[6]; }; struct netlink_notify @@ -258,7 +259,7 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) NLMSG_NEW(skb, pid, seq, type, len, 0) extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - struct nlmsghdr *nlh, + const struct nlmsghdr *nlh, int (*dump)(struct sk_buff *skb, struct netlink_callback*), int (*done)(struct netlink_callback*)); diff --git a/include/net/netlink.h b/include/net/netlink.h index 007bdb0..a63b219 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -365,7 +365,7 @@ static inline struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining) * * See nla_parse() */ -static inline int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, +static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy) { @@ -414,7 +414,7 @@ static inline int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, * * Returns 1 if a report back to the application is requested. */ -static inline int nlmsg_report(struct nlmsghdr *nlh) +static inline int nlmsg_report(const struct nlmsghdr *nlh) { return !!(nlh->nlmsg_flags & NLM_F_ECHO); } diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 3c1895e..85ba560 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -14,7 +14,7 @@ extern void rtnl_register(int protocol, int msgtype, extern int rtnl_unregister(int protocol, int msgtype); extern void rtnl_unregister_all(int protocol); -static inline int rtnl_msg_family(struct nlmsghdr *nlh) +static inline int rtnl_msg_family(const struct nlmsghdr *nlh) { if (nlmsg_len(nlh) >= sizeof(struct rtgenmsg)) return ((struct rtgenmsg *) nlmsg_data(nlh))->rtgen_family; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index da3163d..d0ff382 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1705,7 +1705,7 @@ errout: } int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - struct nlmsghdr *nlh, + const struct nlmsghdr *nlh, int (*dump)(struct sk_buff *skb, struct netlink_callback *), int (*done)(struct netlink_callback *)) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 9d03cc3..2dfb3e7 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1011,7 +1011,7 @@ replay: } static struct nlattr * -find_dump_kind(struct nlmsghdr *n) +find_dump_kind(const struct nlmsghdr *n) { struct nlattr *tb1, *tb2[TCA_ACT_MAX+1]; struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; -- cgit v0.10.2 From 3993832464dd4e14a4c926583a11f0fa92c1f0f0 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Aug 2009 16:07:58 +0200 Subject: netfilter: nfnetlink: constify message attributes and headers Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index bff4d57..9f00da2 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -58,7 +58,8 @@ struct nfgenmsg { struct nfnl_callback { int (*call)(struct sock *nl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *cda[]); + const struct nlmsghdr *nlh, + const struct nlattr * const cda[]); const struct nla_policy *policy; /* netlink attribute policy */ const u_int16_t attr_count; /* number of nlattr's */ }; diff --git a/include/net/netfilter/nf_nat_core.h b/include/net/netfilter/nf_nat_core.h index 5868406..33602ab 100644 --- a/include/net/netfilter/nf_nat_core.h +++ b/include/net/netfilter/nf_nat_core.h @@ -31,6 +31,6 @@ struct nlattr; extern int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, enum nf_nat_manip_type manip, - struct nlattr *attr); + const struct nlattr *attr); #endif /* _NF_NAT_CORE_H */ diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index b6ddd56..68afc6e 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -620,7 +620,7 @@ static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = { }; static int -nfnetlink_parse_nat(struct nlattr *nat, +nfnetlink_parse_nat(const struct nlattr *nat, const struct nf_conn *ct, struct nf_nat_range *range) { struct nlattr *tb[CTA_NAT_MAX+1]; @@ -656,7 +656,7 @@ nfnetlink_parse_nat(struct nlattr *nat, static int nfnetlink_parse_nat_setup(struct nf_conn *ct, enum nf_nat_manip_type manip, - struct nlattr *attr) + const struct nlattr *attr) { struct nf_nat_range range; @@ -671,7 +671,7 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct, static int nfnetlink_parse_nat_setup(struct nf_conn *ct, enum nf_nat_manip_type manip, - struct nlattr *attr) + const struct nlattr *attr) { return -EOPNOTSUPP; } diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index b5869b9..565c3a8 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -47,7 +47,7 @@ int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, enum nf_nat_manip_type manip, - struct nlattr *attr) __read_mostly; + const struct nlattr *attr) __read_mostly; EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); DEFINE_SPINLOCK(nf_conntrack_lock); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 49479d1..59d8064 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -704,7 +704,8 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, } static int -ctnetlink_parse_tuple(struct nlattr *cda[], struct nf_conntrack_tuple *tuple, +ctnetlink_parse_tuple(const struct nlattr * const cda[], + struct nf_conntrack_tuple *tuple, enum ctattr_tuple type, u_int8_t l3num) { struct nlattr *tb[CTA_TUPLE_MAX+1]; @@ -740,7 +741,7 @@ ctnetlink_parse_tuple(struct nlattr *cda[], struct nf_conntrack_tuple *tuple, } static inline int -ctnetlink_parse_help(struct nlattr *attr, char **helper_name) +ctnetlink_parse_help(const struct nlattr *attr, char **helper_name) { struct nlattr *tb[CTA_HELP_MAX+1]; @@ -764,7 +765,8 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { static int ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *cda[]) + const struct nlmsghdr *nlh, + const struct nlattr * const cda[]) { struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple tuple; @@ -823,7 +825,8 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, static int ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *cda[]) + const struct nlmsghdr *nlh, + const struct nlattr * const cda[]) { struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple tuple; @@ -884,7 +887,7 @@ out: static int ctnetlink_parse_nat_setup(struct nf_conn *ct, enum nf_nat_manip_type manip, - struct nlattr *attr) + const struct nlattr *attr) { typeof(nfnetlink_parse_nat_setup_hook) parse_nat_setup; @@ -914,7 +917,7 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct, #endif static int -ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[]) +ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[]) { unsigned long d; unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS])); @@ -940,7 +943,7 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[]) } static int -ctnetlink_change_nat(struct nf_conn *ct, struct nlattr *cda[]) +ctnetlink_change_nat(struct nf_conn *ct, const struct nlattr * const cda[]) { #ifdef CONFIG_NF_NAT_NEEDED int ret; @@ -966,7 +969,7 @@ ctnetlink_change_nat(struct nf_conn *ct, struct nlattr *cda[]) } static inline int -ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[]) +ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[]) { struct nf_conntrack_helper *helper; struct nf_conn_help *help = nfct_help(ct); @@ -1028,7 +1031,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[]) } static inline int -ctnetlink_change_timeout(struct nf_conn *ct, struct nlattr *cda[]) +ctnetlink_change_timeout(struct nf_conn *ct, const struct nlattr * const cda[]) { u_int32_t timeout = ntohl(nla_get_be32(cda[CTA_TIMEOUT])); @@ -1042,9 +1045,10 @@ ctnetlink_change_timeout(struct nf_conn *ct, struct nlattr *cda[]) } static inline int -ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[]) +ctnetlink_change_protoinfo(struct nf_conn *ct, const struct nlattr * const cda[]) { - struct nlattr *tb[CTA_PROTOINFO_MAX+1], *attr = cda[CTA_PROTOINFO]; + const struct nlattr *attr = cda[CTA_PROTOINFO]; + struct nlattr *tb[CTA_PROTOINFO_MAX+1]; struct nf_conntrack_l4proto *l4proto; int err = 0; @@ -1061,7 +1065,7 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[]) #ifdef CONFIG_NF_NAT_NEEDED static inline int -change_nat_seq_adj(struct nf_nat_seq *natseq, struct nlattr *attr) +change_nat_seq_adj(struct nf_nat_seq *natseq, const struct nlattr * const attr) { struct nlattr *cda[CTA_NAT_SEQ_MAX+1]; @@ -1089,7 +1093,8 @@ change_nat_seq_adj(struct nf_nat_seq *natseq, struct nlattr *attr) } static int -ctnetlink_change_nat_seq_adj(struct nf_conn *ct, struct nlattr *cda[]) +ctnetlink_change_nat_seq_adj(struct nf_conn *ct, + const struct nlattr * const cda[]) { int ret = 0; struct nf_conn_nat *nat = nfct_nat(ct); @@ -1120,7 +1125,8 @@ ctnetlink_change_nat_seq_adj(struct nf_conn *ct, struct nlattr *cda[]) #endif static int -ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) +ctnetlink_change_conntrack(struct nf_conn *ct, + const struct nlattr * const cda[]) { int err; @@ -1169,7 +1175,7 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) } static struct nf_conn * -ctnetlink_create_conntrack(struct nlattr *cda[], +ctnetlink_create_conntrack(const struct nlattr * const cda[], struct nf_conntrack_tuple *otuple, struct nf_conntrack_tuple *rtuple, u8 u3) @@ -1304,7 +1310,8 @@ err1: static int ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *cda[]) + const struct nlmsghdr *nlh, + const struct nlattr * const cda[]) { struct nf_conntrack_tuple otuple, rtuple; struct nf_conntrack_tuple_hash *h = NULL; @@ -1629,7 +1636,8 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { static int ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *cda[]) + const struct nlmsghdr *nlh, + const struct nlattr * const cda[]) { struct nf_conntrack_tuple tuple; struct nf_conntrack_expect *exp; @@ -1689,7 +1697,8 @@ out: static int ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *cda[]) + const struct nlmsghdr *nlh, + const struct nlattr * const cda[]) { struct nf_conntrack_expect *exp; struct nf_conntrack_tuple tuple; @@ -1767,13 +1776,15 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return 0; } static int -ctnetlink_change_expect(struct nf_conntrack_expect *x, struct nlattr *cda[]) +ctnetlink_change_expect(struct nf_conntrack_expect *x, + const struct nlattr * const cda[]) { return -EOPNOTSUPP; } static int -ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3, u32 pid, int report) +ctnetlink_create_expect(const struct nlattr * const cda[], u_int8_t u3, + u32 pid, int report) { struct nf_conntrack_tuple tuple, mask, master_tuple; struct nf_conntrack_tuple_hash *h = NULL; @@ -1831,7 +1842,8 @@ out: static int ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *cda[]) + const struct nlmsghdr *nlh, + const struct nlattr * const cda[]) { struct nf_conntrack_tuple tuple; struct nf_conntrack_expect *exp; diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 92761a9..eedc0c1 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -170,7 +170,7 @@ replay: if (err < 0) return err; - err = nc->call(nfnl, skb, nlh, cda); + err = nc->call(nfnl, skb, nlh, (const struct nlattr **)cda); if (err == -EAGAIN) goto replay; return err; diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 66a6dd5..f900dc3 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -694,7 +694,8 @@ static struct notifier_block nfulnl_rtnl_notifier = { static int nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *nfqa[]) + const struct nlmsghdr *nlh, + const struct nlattr * const nfqa[]) { return -ENOTSUPP; } @@ -716,7 +717,8 @@ static const struct nla_policy nfula_cfg_policy[NFULA_CFG_MAX+1] = { static int nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *nfula[]) + const struct nlmsghdr *nlh, + const struct nlattr * const nfula[]) { struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); u_int16_t group_num = ntohs(nfmsg->res_id); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 71daa09..7a9dec9 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -608,7 +608,8 @@ static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = { static int nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *nfqa[]) + const struct nlmsghdr *nlh, + const struct nlattr * const nfqa[]) { struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); u_int16_t queue_num = ntohs(nfmsg->res_id); @@ -670,7 +671,8 @@ err_out_unlock: static int nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *nfqa[]) + const struct nlmsghdr *nlh, + const struct nlattr * const nfqa[]) { return -ENOTSUPP; } @@ -687,7 +689,8 @@ static const struct nf_queue_handler nfqh = { static int nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *nfqa[]) + const struct nlmsghdr *nlh, + const struct nlattr * const nfqa[]) { struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); u_int16_t queue_num = ntohs(nfmsg->res_id); diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 0f482e2..63e1905 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -70,7 +70,8 @@ static void xt_osf_finger_free_rcu(struct rcu_head *rcu_head) } static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *osf_attrs[]) + const struct nlmsghdr *nlh, + const struct nlattr * const osf_attrs[]) { struct xt_osf_user_finger *f; struct xt_osf_finger *kf = NULL, *sf; @@ -112,7 +113,8 @@ static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb, } static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb, - struct nlmsghdr *nlh, struct nlattr *osf_attrs[]) + const struct nlmsghdr *nlh, + const struct nlattr * const osf_attrs[]) { struct xt_osf_user_finger *f; struct xt_osf_finger *sf; -- cgit v0.10.2 From c3fc1f502a1f1a751c891d3b757a24dc76943539 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Aug 2009 16:08:47 +0200 Subject: ALSA: hda - Improve auto-cfg mixer name for ALC262 Similar improvements for ALC262 codec like previous two commits: assign a better name, either Master or Speaker, for the primary output controls. However, in the case of ALC262 codec, the necessary changes are larger than others because we need to check the possibility of different mixer amps depending on the pins. The pin 0x16 is mono, and bound with the dedicated mixer 0x0e while other pins are bound with 0x0c. Thus, there are two possible volumes. When only one of them is used, we can name it as "Master". OTOH, when both are used at the same time, they have to be named uniquely. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 00ed126..4074759 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10790,80 +10790,106 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { { } /* end */ }; +/* We use two mixers depending on the output pin; 0x16 is a mono output + * and thus it's bound with a different mixer. + * This function returns which mixer amp should be used. + */ +static int alc262_check_volbit(hda_nid_t nid) +{ + if (!nid) + return 0; + else if (nid == 0x16) + return 2; + else + return 1; +} + +static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid, + const char *pfx, int *vbits) +{ + char name[32]; + unsigned long val; + int vbit; + + vbit = alc262_check_volbit(nid); + if (!vbit) + return 0; + if (*vbits & vbit) /* a volume control for this mixer already there */ + return 0; + *vbits |= vbit; + snprintf(name, sizeof(name), "%s Playback Volume", pfx); + if (vbit == 2) + val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT); + else + val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT); + return add_control(spec, ALC_CTL_WIDGET_VOL, name, val); +} + +static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid, + const char *pfx) +{ + char name[32]; + unsigned long val; + + if (!nid) + return 0; + snprintf(name, sizeof(name), "%s Playback Switch", pfx); + if (nid == 0x16) + val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); + else + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + return add_control(spec, ALC_CTL_WIDGET_MUTE, name, val); +} + /* add playback controls from the parsed DAC table */ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { - hda_nid_t nid; + const char *pfx; + int vbits; int err; spec->multiout.num_dacs = 1; /* only use one dac */ spec->multiout.dac_nids = spec->private_dac_nids; spec->multiout.dac_nids[0] = 2; - nid = cfg->line_out_pins[0]; - if (nid) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Front Playback Volume", - HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Front Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } + if (!cfg->speaker_pins[0] && !cfg->hp_pins[0]) + pfx = "Master"; + else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + pfx = "Speaker"; + else + pfx = "Front"; + err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx); + if (err < 0) + return err; + err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker"); + if (err < 0) + return err; + err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone"); + if (err < 0) + return err; - nid = cfg->speaker_pins[0]; - if (nid) { - if (nid == 0x16) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Speaker Playback Volume", - HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Speaker Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } else { - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Speaker Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } - } - nid = cfg->hp_pins[0]; - if (nid) { - /* spec->multiout.hp_nid = 2; */ - if (nid == 0x16) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Headphone Playback Volume", - HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Headphone Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } else { - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Headphone Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, - HDA_OUTPUT)); - if (err < 0) - return err; - } - } + vbits = alc262_check_volbit(cfg->line_out_pins[0]) | + alc262_check_volbit(cfg->speaker_pins[0]) | + alc262_check_volbit(cfg->hp_pins[0]); + if (vbits == 1 || vbits == 2) + pfx = "Master"; /* only one mixer is used */ + else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + pfx = "Speaker"; + else + pfx = "Front"; + vbits = 0; + err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits); + if (err < 0) + return err; + err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker", + &vbits); + if (err < 0) + return err; + err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone", + &vbits); + if (err < 0) + return err; return 0; } -- cgit v0.10.2 From a4fcd491098603356e7600b021bdb6acbb53adb4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Aug 2009 16:12:15 +0200 Subject: ALSA: hda - Improve auto-cfg mixer name for ALC861-VD One more patch to give a better name for the primary output controls, this time for ALC861-VD codec. The change is simple, just checking the pin connection whether it's a speaker-out. When both speaker and HP are assigned, we name the volume as "PCM" as this influences on both outputs. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4074759..206fcb9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -15233,13 +15233,25 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, if (err < 0) return err; } else { - sprintf(name, "%s Playback Volume", chname[i]); + const char *pfx; + if (cfg->line_outs == 1 && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { + if (!cfg->hp_pins) + pfx = "Speaker"; + else + pfx = "PCM"; + } else + pfx = chname[i]; + sprintf(name, "%s Playback Volume", pfx); err = add_control(spec, ALC_CTL_WIDGET_VOL, name, HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - sprintf(name, "%s Playback Switch", chname[i]); + if (cfg->line_outs == 1 && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + pfx = "Speaker"; + sprintf(name, "%s Playback Switch", pfx); err = add_control(spec, ALC_CTL_BIND_MUTE, name, HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT)); -- cgit v0.10.2 From 0d884cb936e8e36c47bc7ee86eb6750261bd5438 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Aug 2009 16:14:35 +0200 Subject: ALSA: hda - Improve auto-cfg mixer name for ALC662 The last patch in this series is for ALC662; pretty similar as the previous patch for ALC861-VD. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 206fcb9..ce098b2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -17018,13 +17018,25 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, if (err < 0) return err; } else { - sprintf(name, "%s Playback Volume", chname[i]); + const char *pfx; + if (cfg->line_outs == 1 && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { + if (!cfg->hp_pins) + pfx = "Speaker"; + else + pfx = "PCM"; + } else + pfx = chname[i]; + sprintf(name, "%s Playback Volume", pfx); err = add_control(spec, ALC_CTL_WIDGET_VOL, name, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - sprintf(name, "%s Playback Switch", chname[i]); + if (cfg->line_outs == 1 && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + pfx = "Speaker"; + sprintf(name, "%s Playback Switch", pfx); err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i), 3, 0, HDA_INPUT)); -- cgit v0.10.2 From d88cb582325830698de5071fa8b8c9e933dbbcad Mon Sep 17 00:00:00 2001 From: Anirban Sinha Date: Tue, 25 Aug 2009 07:00:02 -0700 Subject: tracing: Eliminate code duplication in kernel/tracepoint.c Signed-off-by: Anirban Sinha Reviewed-by: Li Zefan Cc: "Oleg Nesterov" LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 35dd27a..06f165a 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -555,9 +555,6 @@ int tracepoint_module_notify(struct notifier_block *self, switch (val) { case MODULE_STATE_COMING: - tracepoint_update_probe_range(mod->tracepoints, - mod->tracepoints + mod->num_tracepoints); - break; case MODULE_STATE_GOING: tracepoint_update_probe_range(mod->tracepoints, mod->tracepoints + mod->num_tracepoints); -- cgit v0.10.2 From fc86f95415d14c74fd71f5e70173a4def7da68f6 Mon Sep 17 00:00:00 2001 From: Denis Kuplyakov Date: Tue, 25 Aug 2009 18:15:59 +0200 Subject: ALSA: hda - Add full audio support on Acer Aspire 7730G notebook 1) Added support of internal subwoofer (it sounds!!!) 2) Auto muting front speakers and internal subwoofer on headphones plug. 3) Internal mic works. 4) 3 channel mods (jack maps): black pink blue 2ch: front ext mic line in 4ch: front ext mic surround 6ch: front CLFE surround Can be changed in mixer. 5) Sound can be recorded from: Internal mic Ext mic Cd Line in 6) 2 separate capture channels. Signed-off-by: Denis Kuplyakov Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ce098b2..d572db6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -220,6 +220,7 @@ enum { ALC888_ACER_ASPIRE_4930G, ALC888_ACER_ASPIRE_6530G, ALC888_ACER_ASPIRE_8930G, + ALC888_ACER_ASPIRE_7730G, ALC883_MEDION, ALC883_MEDION_MD2, ALC883_LAPTOP_EAPD, @@ -8484,6 +8485,13 @@ static struct hda_verb alc883_acer_eapd_verbs[] = { { } }; +static struct hda_verb alc888_acer_aspire_7730G_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + static void alc888_6st_dell_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -8645,6 +8653,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g", [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g", + [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g", [ALC883_MEDION] = "medion", [ALC883_MEDION_MD2] = "medion-md2", [ALC883_LAPTOP_EAPD] = "laptop-eapd", @@ -8691,6 +8700,8 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { ALC888_ACER_ASPIRE_6530G), SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", ALC888_ACER_ASPIRE_6530G), + SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", + ALC888_ACER_ASPIRE_7730G), /* default Acer -- disabled as it causes more problems. * model=auto should work fine now */ @@ -9192,6 +9203,26 @@ static struct alc_config_preset alc882_presets[] = { .setup = alc889_acer_aspire_8930g_setup, .init_hook = alc_automute_amp, }, + [ALC888_ACER_ASPIRE_7730G] = { + .mixers = { alc883_3ST_6ch_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc888_acer_aspire_7730G_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .const_channel_count = 6, + .input_mux = &alc883_capture_source, + .unsol_event = alc_automute_amp_unsol_event, + .setup = alc888_acer_aspire_6530g_setup, + .init_hook = alc_automute_amp, + }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, alc883_chmode_mixer }, -- cgit v0.10.2 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 diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 775beea..abffd41 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 v0.10.2 From c935a331c8f569c7903ed26a3994a70cbea1802e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 25 Aug 2009 08:40:25 -0700 Subject: rcu: Add #ifdef to suppress __rcu_offline_cpu() warning in !HOTPLUG_CPU builds 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 Cc: Paul Mundt LKML-Reference: <20090825154025.GD6616@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 000b076..fee6316 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -84,7 +84,9 @@ extern long rcu_batches_completed_sched(void); static void cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, struct rcu_node *rnp, unsigned long flags); static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags); +#ifdef CONFIG_HOTPLUG_CPU static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp); +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ static void __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp); static void __call_rcu(struct rcu_head *head, -- cgit v0.10.2 From 30cd0c4ad57f45e257758edad537cc5f6554e711 Mon Sep 17 00:00:00 2001 From: "Candelaria Villareal, Jorge" Date: Tue, 25 Aug 2009 10:13:25 -0500 Subject: ASoC: SDP3430: Fix TWL GPIO6 pin mux request Fix the write to PMBR1 register through I2C. Also, the constant which holds the value to write is now called TWL4030_GPIO6_PWM0_MUTE. This name is based on TRM to avoid confusion. Signed-off-by: Jorge Eduardo Candelaria Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index f7e5b74..4a3f62d 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -40,8 +40,10 @@ #include "omap-pcm.h" #include "../codecs/twl4030.h" -#define TWL4030_INTBR_PMBR1 0x0D -#define EXTMUTE(value) (value << 2) +/* TWL4030 PMBR1 Register */ +#define TWL4030_INTBR_PMBR1 0x0D +/* TWL4030 PMBR1 Register GPIO6 mux bit */ +#define TWL4030_GPIO6_PWM0_MUTE(value) (value << 2) static struct snd_soc_card snd_soc_sdp3430; @@ -299,6 +301,7 @@ static struct platform_device *sdp3430_snd_device; static int __init sdp3430_soc_init(void) { int ret; + u8 pin_mux; if (!machine_is_omap_3430sdp()) { pr_debug("Not SDP3430!\n"); @@ -318,8 +321,12 @@ static int __init sdp3430_soc_init(void) *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */ /* Set TWL4030 GPIO6 as EXTMUTE signal */ - twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, EXTMUTE(0x02), - TWL4030_MODULE_INTBR); + twl4030_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux, + TWL4030_INTBR_PMBR1); + pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03); + pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02); + twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux, + TWL4030_INTBR_PMBR1); ret = platform_device_add(sdp3430_snd_device); if (ret) -- cgit v0.10.2 From 667000011927b4fcc359beac4a2447889db6d349 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 24 Aug 2009 14:43:11 -0700 Subject: tracing: Rename FTRACE_SYSCALLS for tracepoints s/HAVE_FTRACE_SYSCALLS/HAVE_SYSCALL_TRACEPOINTS/g s/TIF_SYSCALL_FTRACE/TIF_SYSCALL_TRACEPOINT/g The syscall enter/exit tracing is no longer specific to just ftrace, so they now have names that reflect their tie to tracepoints instead. Signed-off-by: Josh Stone Cc: Jason Baron Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Li Zefan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Lai Jiangshan Cc: Paul Mundt Cc: Martin Schwidefsky Cc: Heiko Carstens LKML-Reference: <1251150194-1713-2-git-send-email-jistone@redhat.com> Signed-off-by: Frederic Weisbecker diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 2ae5d72..7238ef4 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -84,7 +84,7 @@ config S390 select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_FTRACE_MCOUNT_RECORD - select HAVE_FTRACE_SYSCALLS + select HAVE_SYSCALL_TRACEPOINTS select HAVE_DYNAMIC_FTRACE select HAVE_FUNCTION_GRAPH_TRACER select HAVE_DEFAULT_NO_SPIN_MUTEXES diff --git a/arch/s390/defconfig b/arch/s390/defconfig index fcba206..4e91a25 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -900,7 +900,7 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y CONFIG_HAVE_DYNAMIC_FTRACE=y CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FTRACE_SYSCALLS=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y CONFIG_TRACING_SUPPORT=y CONFIG_FTRACE=y # CONFIG_FUNCTION_TRACER is not set diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index ba1cab9..07eb61b 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h @@ -92,7 +92,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SYSCALL_TRACE 8 /* syscall trace active */ #define TIF_SYSCALL_AUDIT 9 /* syscall auditing active */ #define TIF_SECCOMP 10 /* secure computing */ -#define TIF_SYSCALL_FTRACE 11 /* ftrace syscall instrumentation */ +#define TIF_SYSCALL_TRACEPOINT 11 /* syscall tracepoint instrumentation */ #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ @@ -111,7 +111,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_TRACE (1<>8 | _TIF_SYSCALL_AUDIT>>8 | \ - _TIF_SECCOMP>>8 | _TIF_SYSCALL_FTRACE>>8) + _TIF_SECCOMP>>8 | _TIF_SYSCALL_TRACEPOINT>>8) STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER STACK_SIZE = 1 << STACK_SHIFT diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index f6618e9..3ceb53c 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -57,7 +57,7 @@ _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ _TIF_MCCK_PENDING) _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ - _TIF_SECCOMP>>8 | _TIF_SYSCALL_FTRACE>>8) + _TIF_SECCOMP>>8 | _TIF_SYSCALL_TRACEPOINT>>8) #define BASED(name) name-system_call(%r13) diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index c5e87d8..9d3dcfa 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -664,7 +664,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) ret = -1; } - if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) + if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_syscall_enter(regs, regs->gprs[2]); if (unlikely(current->audit_context)) @@ -682,7 +682,7 @@ asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]); - if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) + if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_syscall_exit(regs, regs->gprs[2]); if (test_thread_flag(TIF_SYSCALL_TRACE)) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 738bdc6..d59cbf7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -37,7 +37,7 @@ config X86 select HAVE_FUNCTION_GRAPH_FP_TEST select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE - select HAVE_FTRACE_SYSCALLS + select HAVE_SYSCALL_TRACEPOINTS select HAVE_KVM select HAVE_ARCH_KGDB select HAVE_ARCH_TRACEHOOK diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index edb992e..d28fad1 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig @@ -2355,7 +2355,7 @@ CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y CONFIG_HAVE_DYNAMIC_FTRACE=y CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_HW_BRANCH_TRACER=y -CONFIG_HAVE_FTRACE_SYSCALLS=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y CONFIG_RING_BUFFER=y CONFIG_TRACING=y CONFIG_TRACING_SUPPORT=y diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig index cee1dd2..6c86acd 100644 --- a/arch/x86/configs/x86_64_defconfig +++ b/arch/x86/configs/x86_64_defconfig @@ -2329,7 +2329,7 @@ CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y CONFIG_HAVE_DYNAMIC_FTRACE=y CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_HW_BRANCH_TRACER=y -CONFIG_HAVE_FTRACE_SYSCALLS=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y CONFIG_RING_BUFFER=y CONFIG_TRACING=y CONFIG_TRACING_SUPPORT=y diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index fad7d40..6f7786a 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -95,7 +95,7 @@ struct thread_info { #define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */ #define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */ #define TIF_LAZY_MMU_UPDATES 27 /* task is updating the mmu lazily */ -#define TIF_SYSCALL_FTRACE 28 /* for ftrace syscall instrumentation */ +#define TIF_SYSCALL_TRACEPOINT 28 /* syscall tracepoint instrumentation */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) @@ -118,17 +118,17 @@ struct thread_info { #define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR) #define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR) #define _TIF_LAZY_MMU_UPDATES (1 << TIF_LAZY_MMU_UPDATES) -#define _TIF_SYSCALL_FTRACE (1 << TIF_SYSCALL_FTRACE) +#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) /* work to do in syscall_trace_enter() */ #define _TIF_WORK_SYSCALL_ENTRY \ - (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_FTRACE | \ - _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | _TIF_SINGLESTEP) + (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT | \ + _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT) /* work to do in syscall_trace_leave() */ #define _TIF_WORK_SYSCALL_EXIT \ (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP | \ - _TIF_SYSCALL_FTRACE) + _TIF_SYSCALL_TRACEPOINT) /* work to do on interrupt/exception return */ #define _TIF_WORK_MASK \ @@ -137,7 +137,8 @@ struct thread_info { _TIF_SINGLESTEP|_TIF_SECCOMP|_TIF_SYSCALL_EMU)) /* work to do on any return to user space */ -#define _TIF_ALLWORK_MASK ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_FTRACE) +#define _TIF_ALLWORK_MASK \ + ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT) /* Only used for 64 bit */ #define _TIF_DO_NOTIFY_MASK \ diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 34dd6f1..a909afe 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -1500,7 +1500,7 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs) tracehook_report_syscall_entry(regs)) ret = -1L; - if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) + if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_syscall_enter(regs, regs->orig_ax); if (unlikely(current->audit_context)) { @@ -1526,7 +1526,7 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs) if (unlikely(current->audit_context)) audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); - if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) + if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_syscall_exit(regs, regs->ax); if (test_thread_flag(TIF_SYSCALL_TRACE)) diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 019f380..06be85a 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -41,7 +41,7 @@ config HAVE_FTRACE_MCOUNT_RECORD config HAVE_HW_BRANCH_TRACER bool -config HAVE_FTRACE_SYSCALLS +config HAVE_SYSCALL_TRACEPOINTS bool config TRACER_MAX_TRACE @@ -211,7 +211,7 @@ config ENABLE_DEFAULT_TRACERS config FTRACE_SYSCALLS bool "Trace syscalls" - depends on HAVE_FTRACE_SYSCALLS + depends on HAVE_SYSCALL_TRACEPOINTS select GENERIC_TRACER select KALLSYMS help diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 06f165a..be86b9a 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -590,7 +590,7 @@ void syscall_regfunc(void) if (!sys_tracepoint_refcount) { read_lock_irqsave(&tasklist_lock, flags); do_each_thread(g, t) { - set_tsk_thread_flag(t, TIF_SYSCALL_FTRACE); + set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); } while_each_thread(g, t); read_unlock_irqrestore(&tasklist_lock, flags); } @@ -608,7 +608,7 @@ void syscall_unregfunc(void) if (!sys_tracepoint_refcount) { read_lock_irqsave(&tasklist_lock, flags); do_each_thread(g, t) { - clear_tsk_thread_flag(t, TIF_SYSCALL_FTRACE); + clear_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); } while_each_thread(g, t); read_unlock_irqrestore(&tasklist_lock, flags); } -- cgit v0.10.2 From 3d27d8cb34fc156beb86de2338ca4029873a5cc6 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 24 Aug 2009 14:43:12 -0700 Subject: tracing: Make syscall tracepoints conditional The syscall enter/exit tracepoints are only supported on archs that HAVE_SYSCALL_TRACEPOINTS, so the declarations should be #ifdef'ed. Also, the definition of syscall_regfunc and syscall_unregfunc should depend on this same config, rather than the ftrace-specific one. Signed-off-by: Josh Stone Cc: Jason Baron Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Li Zefan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Lai Jiangshan LKML-Reference: <1251150194-1713-3-git-send-email-jistone@redhat.com> Signed-off-by: Frederic Weisbecker diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 9661dd4..5dcb7e3 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -8,6 +8,8 @@ #include +#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS + extern void syscall_regfunc(void); extern void syscall_unregfunc(void); @@ -25,6 +27,8 @@ DECLARE_TRACE_WITH_CALLBACK(syscall_exit, syscall_unregfunc ); +#endif + /* * A syscall entry in the ftrace syscalls array. * diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index be86b9a..9e0a36f 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -576,7 +576,7 @@ __initcall(init_tracepoints); #endif /* CONFIG_MODULES */ -#ifdef CONFIG_FTRACE_SYSCALLS +#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS static DEFINE_MUTEX(regfunc_mutex); static int sys_tracepoint_refcount; -- cgit v0.10.2 From 97419875865859fd2403e66266c02ce028e2f5ab Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 24 Aug 2009 14:43:13 -0700 Subject: tracing: Move tracepoint callbacks from declaration to definition It's not strictly correct for the tracepoint reg/unreg callbacks to occur when a client is hooking up, because the actual tracepoint may not be present yet. This happens to be fine for syscall, since that's in the core kernel, but it would cause problems for tracepoints defined in a module that hasn't been loaded yet. It also means the reg/unreg has to be EXPORTed for any modules to use the tracepoint (as in SystemTap). This patch removes DECLARE_TRACE_WITH_CALLBACK, and instead introduces DEFINE_TRACE_FN which stores the callbacks in struct tracepoint. The callbacks are used now when the active state of the tracepoint changes in set_tracepoint & disable_tracepoint. This also introduces TRACE_EVENT_FN, so ftrace events can also provide registration callbacks if needed. Signed-off-by: Josh Stone Cc: Jason Baron Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Li Zefan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Lai Jiangshan Cc: Paul Mundt Cc: Martin Schwidefsky Cc: Heiko Carstens LKML-Reference: <1251150194-1713-4-git-send-email-jistone@redhat.com> Signed-off-by: Frederic Weisbecker diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 9d3dcfa..c05b44b 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -51,8 +51,8 @@ #include "compat_ptrace.h" #endif -DEFINE_TRACE(syscall_enter); -DEFINE_TRACE(syscall_exit); +DEFINE_TRACE_FN(syscall_enter, syscall_regfunc, syscall_unregfunc); +DEFINE_TRACE_FN(syscall_exit, syscall_regfunc, syscall_unregfunc); enum s390_regset { REGSET_GENERAL, diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index a909afe..31e9b97 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -37,8 +37,8 @@ #include -DEFINE_TRACE(syscall_enter); -DEFINE_TRACE(syscall_exit); +DEFINE_TRACE_FN(syscall_enter, syscall_regfunc, syscall_unregfunc); +DEFINE_TRACE_FN(syscall_exit, syscall_regfunc, syscall_unregfunc); #include "tls.h" diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 5984ed0..846a4ae 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -23,6 +23,8 @@ struct tracepoint; struct tracepoint { const char *name; /* Tracepoint name */ int state; /* State. */ + void (*regfunc)(void); + void (*unregfunc)(void); void **funcs; } __attribute__((aligned(32))); /* * Aligned on 32 bytes because it is @@ -60,10 +62,8 @@ struct tracepoint { * Make sure the alignment of the structure in the __tracepoints section will * not add unwanted padding between the beginning of the section and the * structure. Force alignment to the same alignment as the section start. - * An optional set of (un)registration functions can be passed to perform any - * additional (un)registration work. */ -#define DECLARE_TRACE_WITH_CALLBACK(name, proto, args, reg, unreg) \ +#define DECLARE_TRACE(name, proto, args) \ extern struct tracepoint __tracepoint_##name; \ static inline void trace_##name(proto) \ { \ @@ -73,36 +73,23 @@ struct tracepoint { } \ static inline int register_trace_##name(void (*probe)(proto)) \ { \ - int ret; \ - void (*func)(void) = reg; \ - \ - ret = tracepoint_probe_register(#name, (void *)probe); \ - if (func && !ret) \ - func(); \ - return ret; \ + return tracepoint_probe_register(#name, (void *)probe); \ } \ static inline int unregister_trace_##name(void (*probe)(proto)) \ { \ - int ret; \ - void (*func)(void) = unreg; \ - \ - ret = tracepoint_probe_unregister(#name, (void *)probe);\ - if (func && !ret) \ - func(); \ - return ret; \ + return tracepoint_probe_unregister(#name, (void *)probe);\ } -#define DECLARE_TRACE(name, proto, args) \ - DECLARE_TRACE_WITH_CALLBACK(name, TP_PROTO(proto), TP_ARGS(args),\ - NULL, NULL); - -#define DEFINE_TRACE(name) \ +#define DEFINE_TRACE_FN(name, reg, unreg) \ static const char __tpstrtab_##name[] \ __attribute__((section("__tracepoints_strings"))) = #name; \ struct tracepoint __tracepoint_##name \ __attribute__((section("__tracepoints"), aligned(32))) = \ - { __tpstrtab_##name, 0, NULL } + { __tpstrtab_##name, 0, reg, unreg, NULL } + +#define DEFINE_TRACE(name) \ + DEFINE_TRACE_FN(name, NULL, NULL); #define EXPORT_TRACEPOINT_SYMBOL_GPL(name) \ EXPORT_SYMBOL_GPL(__tracepoint_##name) @@ -113,7 +100,7 @@ extern void tracepoint_update_probe_range(struct tracepoint *begin, struct tracepoint *end); #else /* !CONFIG_TRACEPOINTS */ -#define DECLARE_TRACE_WITH_CALLBACK(name, proto, args, reg, unreg) \ +#define DECLARE_TRACE(name, proto, args) \ static inline void _do_trace_##name(struct tracepoint *tp, proto) \ { } \ static inline void trace_##name(proto) \ @@ -127,10 +114,7 @@ extern void tracepoint_update_probe_range(struct tracepoint *begin, return -ENOSYS; \ } -#define DECLARE_TRACE(name, proto, args) \ - DECLARE_TRACE_WITH_CALLBACK(name, TP_PROTO(proto), TP_ARGS(args),\ - NULL, NULL); - +#define DEFINE_TRACE_FN(name, reg, unreg) #define DEFINE_TRACE(name) #define EXPORT_TRACEPOINT_SYMBOL_GPL(name) #define EXPORT_TRACEPOINT_SYMBOL(name) @@ -282,10 +266,16 @@ static inline void tracepoint_synchronize_unregister(void) * can also by used by generic instrumentation like SystemTap), and * it is also used to expose a structured trace record in * /sys/kernel/debug/tracing/events/. + * + * A set of (un)registration functions can be passed to the variant + * TRACE_EVENT_FN to perform any (un)registration work. */ #define TRACE_EVENT(name, proto, args, struct, assign, print) \ DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) +#define TRACE_EVENT_FN(name, proto, args, struct, \ + assign, print, reg, unreg) \ + DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) #endif #endif diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h index f7a7ae1..2a96985 100644 --- a/include/trace/define_trace.h +++ b/include/trace/define_trace.h @@ -26,6 +26,11 @@ #define TRACE_EVENT(name, proto, args, tstruct, assign, print) \ DEFINE_TRACE(name) +#undef TRACE_EVENT_FN +#define TRACE_EVENT_FN(name, proto, args, tstruct, \ + assign, print, reg, unreg) \ + DEFINE_TRACE_FN(name, reg, unreg) + #undef DECLARE_TRACE #define DECLARE_TRACE(name, proto, args) \ DEFINE_TRACE(name) diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 1274002..3a0b44b 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -42,6 +42,15 @@ }; \ static struct ftrace_event_call event_##name +/* Callbacks are meaningless to ftrace. */ +#undef TRACE_EVENT_FN +#define TRACE_EVENT_FN(name, proto, args, tstruct, \ + assign, print, reg, unreg) \ + TRACE_EVENT(name, TP_PROTO(proto), TP_ARGS(args), \ + TP_STRUCT__entry(tstruct), \ + TP_fast_assign(assign), \ + TP_printk(print)) + #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 5dcb7e3..4e19430 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -13,18 +13,14 @@ extern void syscall_regfunc(void); extern void syscall_unregfunc(void); -DECLARE_TRACE_WITH_CALLBACK(syscall_enter, +DECLARE_TRACE(syscall_enter, TP_PROTO(struct pt_regs *regs, long id), - TP_ARGS(regs, id), - syscall_regfunc, - syscall_unregfunc + TP_ARGS(regs, id) ); -DECLARE_TRACE_WITH_CALLBACK(syscall_exit, +DECLARE_TRACE(syscall_exit, TP_PROTO(struct pt_regs *regs, long ret), - TP_ARGS(regs, ret), - syscall_regfunc, - syscall_unregfunc + TP_ARGS(regs, ret) ); #endif diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 9e0a36f..1a6a453 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -243,6 +243,11 @@ static void set_tracepoint(struct tracepoint_entry **entry, { WARN_ON(strcmp((*entry)->name, elem->name) != 0); + if (elem->regfunc && !elem->state && active) + elem->regfunc(); + else if (elem->unregfunc && elem->state && !active) + elem->unregfunc(); + /* * rcu_assign_pointer has a smp_wmb() which makes sure that the new * probe callbacks array is consistent before setting a pointer to it. @@ -262,6 +267,9 @@ static void set_tracepoint(struct tracepoint_entry **entry, */ static void disable_tracepoint(struct tracepoint *elem) { + if (elem->unregfunc && elem->state) + elem->unregfunc(); + elem->state = 0; rcu_assign_pointer(elem->funcs, NULL); } @@ -578,7 +586,7 @@ __initcall(init_tracepoints); #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS -static DEFINE_MUTEX(regfunc_mutex); +/* NB: reg/unreg are called while guarded with the tracepoints_mutex */ static int sys_tracepoint_refcount; void syscall_regfunc(void) @@ -586,7 +594,6 @@ void syscall_regfunc(void) unsigned long flags; struct task_struct *g, *t; - mutex_lock(®func_mutex); if (!sys_tracepoint_refcount) { read_lock_irqsave(&tasklist_lock, flags); do_each_thread(g, t) { @@ -595,7 +602,6 @@ void syscall_regfunc(void) read_unlock_irqrestore(&tasklist_lock, flags); } sys_tracepoint_refcount++; - mutex_unlock(®func_mutex); } void syscall_unregfunc(void) @@ -603,7 +609,6 @@ void syscall_unregfunc(void) unsigned long flags; struct task_struct *g, *t; - mutex_lock(®func_mutex); sys_tracepoint_refcount--; if (!sys_tracepoint_refcount) { read_lock_irqsave(&tasklist_lock, flags); @@ -612,6 +617,5 @@ void syscall_unregfunc(void) } while_each_thread(g, t); read_unlock_irqrestore(&tasklist_lock, flags); } - mutex_unlock(®func_mutex); } #endif -- cgit v0.10.2 From 1c569f0264ea629c10bbab471dd0626ce4d3f19f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 24 Aug 2009 14:43:14 -0700 Subject: tracing: Create generic syscall TRACE_EVENTs This converts the syscall_enter/exit tracepoints into TRACE_EVENTs, so you can have generic ftrace events that capture all system calls with arguments and return values. These generic events are also renamed to sys_enter/exit, so they're more closely aligned to the specific sys_enter_foo events. Signed-off-by: Josh Stone Cc: Jason Baron Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Li Zefan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Lai Jiangshan Cc: Paul Mundt Cc: Martin Schwidefsky Cc: Heiko Carstens LKML-Reference: <1251150194-1713-5-git-send-email-jistone@redhat.com> Signed-off-by: Frederic Weisbecker diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index c05b44b..f3ddd7a 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -51,8 +51,8 @@ #include "compat_ptrace.h" #endif -DEFINE_TRACE_FN(syscall_enter, syscall_regfunc, syscall_unregfunc); -DEFINE_TRACE_FN(syscall_exit, syscall_regfunc, syscall_unregfunc); +#define CREATE_TRACE_POINTS +#include enum s390_regset { REGSET_GENERAL, @@ -665,7 +665,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) } if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) - trace_syscall_enter(regs, regs->gprs[2]); + trace_sys_enter(regs, regs->gprs[2]); if (unlikely(current->audit_context)) audit_syscall_entry(is_compat_task() ? @@ -683,7 +683,7 @@ asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) regs->gprs[2]); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) - trace_syscall_exit(regs, regs->gprs[2]); + trace_sys_exit(regs, regs->gprs[2]); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, 0); diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 31e9b97..8d7d5c9 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -35,13 +35,11 @@ #include #include -#include - -DEFINE_TRACE_FN(syscall_enter, syscall_regfunc, syscall_unregfunc); -DEFINE_TRACE_FN(syscall_exit, syscall_regfunc, syscall_unregfunc); - #include "tls.h" +#define CREATE_TRACE_POINTS +#include + enum x86_regset { REGSET_GENERAL, REGSET_FP, @@ -1501,7 +1499,7 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs) ret = -1L; if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) - trace_syscall_enter(regs, regs->orig_ax); + trace_sys_enter(regs, regs->orig_ax); if (unlikely(current->audit_context)) { if (IS_IA32) @@ -1527,7 +1525,7 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs) audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) - trace_syscall_exit(regs, regs->ax); + trace_sys_exit(regs, regs->ax); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, 0); diff --git a/include/trace/events/syscalls.h b/include/trace/events/syscalls.h new file mode 100644 index 0000000..397dff2 --- /dev/null +++ b/include/trace/events/syscalls.h @@ -0,0 +1,70 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM syscalls + +#if !defined(_TRACE_EVENTS_SYSCALLS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_EVENTS_SYSCALLS_H + +#include + +#include +#include + + +#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS + +extern void syscall_regfunc(void); +extern void syscall_unregfunc(void); + +TRACE_EVENT_FN(sys_enter, + + TP_PROTO(struct pt_regs *regs, long id), + + TP_ARGS(regs, id), + + TP_STRUCT__entry( + __field( long, id ) + __array( unsigned long, args, 6 ) + ), + + TP_fast_assign( + __entry->id = id; + syscall_get_arguments(current, regs, 0, 6, __entry->args); + ), + + TP_printk("NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)", + __entry->id, + __entry->args[0], __entry->args[1], __entry->args[2], + __entry->args[3], __entry->args[4], __entry->args[5]), + + syscall_regfunc, syscall_unregfunc +); + +TRACE_EVENT_FN(sys_exit, + + TP_PROTO(struct pt_regs *regs, long ret), + + TP_ARGS(regs, ret), + + TP_STRUCT__entry( + __field( long, id ) + __field( long, ret ) + ), + + TP_fast_assign( + __entry->id = syscall_get_nr(current, regs); + __entry->ret = ret; + ), + + TP_printk("NR %ld = %ld", + __entry->id, __entry->ret), + + syscall_regfunc, syscall_unregfunc +); + +#endif /* CONFIG_HAVE_SYSCALL_TRACEPOINTS */ + +#endif /* _TRACE_EVENTS_SYSCALLS_H */ + +/* This part must be outside protection */ +#include + diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 4e19430..5dc283b 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -8,23 +8,6 @@ #include -#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS - -extern void syscall_regfunc(void); -extern void syscall_unregfunc(void); - -DECLARE_TRACE(syscall_enter, - TP_PROTO(struct pt_regs *regs, long id), - TP_ARGS(regs, id) -); - -DECLARE_TRACE(syscall_exit, - TP_PROTO(struct pt_regs *regs, long ret), - TP_ARGS(regs, ret) -); - -#endif - /* * A syscall entry in the ftrace syscalls array. * diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 46c1b977a..2698fe4 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -286,7 +287,7 @@ int reg_event_syscall_enter(void *ptr) return -ENOSYS; mutex_lock(&syscall_trace_lock); if (!sys_refcount_enter) - ret = register_trace_syscall_enter(ftrace_syscall_enter); + ret = register_trace_sys_enter(ftrace_syscall_enter); if (ret) { pr_info("event trace: Could not activate" "syscall entry trace point"); @@ -311,7 +312,7 @@ void unreg_event_syscall_enter(void *ptr) sys_refcount_enter--; clear_bit(num, enabled_enter_syscalls); if (!sys_refcount_enter) - unregister_trace_syscall_enter(ftrace_syscall_enter); + unregister_trace_sys_enter(ftrace_syscall_enter); mutex_unlock(&syscall_trace_lock); } @@ -327,7 +328,7 @@ int reg_event_syscall_exit(void *ptr) return -ENOSYS; mutex_lock(&syscall_trace_lock); if (!sys_refcount_exit) - ret = register_trace_syscall_exit(ftrace_syscall_exit); + ret = register_trace_sys_exit(ftrace_syscall_exit); if (ret) { pr_info("event trace: Could not activate" "syscall exit trace point"); @@ -352,7 +353,7 @@ void unreg_event_syscall_exit(void *ptr) sys_refcount_exit--; clear_bit(num, enabled_exit_syscalls); if (!sys_refcount_exit) - unregister_trace_syscall_exit(ftrace_syscall_exit); + unregister_trace_sys_exit(ftrace_syscall_exit); mutex_unlock(&syscall_trace_lock); } @@ -418,7 +419,7 @@ int reg_prof_syscall_enter(char *name) mutex_lock(&syscall_trace_lock); if (!sys_prof_refcount_enter) - ret = register_trace_syscall_enter(prof_syscall_enter); + ret = register_trace_sys_enter(prof_syscall_enter); if (ret) { pr_info("event trace: Could not activate" "syscall entry trace point"); @@ -442,7 +443,7 @@ void unreg_prof_syscall_enter(char *name) sys_prof_refcount_enter--; clear_bit(num, enabled_prof_enter_syscalls); if (!sys_prof_refcount_enter) - unregister_trace_syscall_enter(prof_syscall_enter); + unregister_trace_sys_enter(prof_syscall_enter); mutex_unlock(&syscall_trace_lock); } @@ -479,7 +480,7 @@ int reg_prof_syscall_exit(char *name) mutex_lock(&syscall_trace_lock); if (!sys_prof_refcount_exit) - ret = register_trace_syscall_exit(prof_syscall_exit); + ret = register_trace_sys_exit(prof_syscall_exit); if (ret) { pr_info("event trace: Could not activate" "syscall entry trace point"); @@ -503,7 +504,7 @@ void unreg_prof_syscall_exit(char *name) sys_prof_refcount_exit--; clear_bit(num, enabled_prof_exit_syscalls); if (!sys_prof_refcount_exit) - unregister_trace_syscall_exit(prof_syscall_exit); + unregister_trace_sys_exit(prof_syscall_exit); mutex_unlock(&syscall_trace_lock); } -- cgit v0.10.2 From ab94fcf528d127fcb490175512a8910f37e5b346 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 25 Aug 2009 16:47:16 -0700 Subject: x86: allow "=rm" in native_save_fl() This is a partial revert of f1f029c7bfbf4ee1918b90a431ab823bed812504. "=rm" is allowed in this context, because "pop" is explicitly defined to adjust the stack pointer *before* it evaluates its effective address, if it has one. Thus, we do end up writing to the correct address even if we use an on-stack memory argument. The original reporter for f1f029c7bfbf4ee1918b90a431ab823bed812504 was apparently using a broken x86 simulator. [ Impact: performance ] Signed-off-by: H. Peter Anvin Cc: Gabe Black diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index c6ccbe7..9e2b952 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h @@ -13,14 +13,13 @@ static inline unsigned long native_save_fl(void) unsigned long flags; /* - * Note: this needs to be "=r" not "=rm", because we have the - * stack offset from what gcc expects at the time the "pop" is - * executed, and so a memory reference with respect to the stack - * would end up using the wrong address. + * "=rm" is safe here, because "pop" adjusts the stack before + * it evaluates its effective address -- this is part of the + * documented behavior of the "pop" instruction. */ asm volatile("# __raw_save_flags\n\t" "pushf ; pop %0" - : "=r" (flags) + : "=rm" (flags) : /* no input */ : "memory"); -- cgit v0.10.2 From f0693c8bd5c50380b299e19d19e7640024640b42 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 6 Aug 2009 14:59:32 -0400 Subject: tracing/sched: show CPU task wakes up on in trace event While debugging the scheduler push / pull algorithm, I found it very annoying that the sched wake up events did not show the CPU that the task was waking on. In order to analyze the scheduler, I needed that information. This patch adds recording of the CPU that a task is waking up on. Signed-off-by: Steven Rostedt diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 8949bb7..a581ef2 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -94,6 +94,7 @@ TRACE_EVENT(sched_wakeup, __field( pid_t, pid ) __field( int, prio ) __field( int, success ) + __field( int, cpu ) ), TP_fast_assign( @@ -101,11 +102,12 @@ TRACE_EVENT(sched_wakeup, __entry->pid = p->pid; __entry->prio = p->prio; __entry->success = success; + __entry->cpu = task_cpu(p); ), - TP_printk("task %s:%d [%d] success=%d", + TP_printk("task %s:%d [%d] success=%d [%03d]", __entry->comm, __entry->pid, __entry->prio, - __entry->success) + __entry->success, __entry->cpu) ); /* @@ -125,6 +127,7 @@ TRACE_EVENT(sched_wakeup_new, __field( pid_t, pid ) __field( int, prio ) __field( int, success ) + __field( int, cpu ) ), TP_fast_assign( @@ -132,11 +135,12 @@ TRACE_EVENT(sched_wakeup_new, __entry->pid = p->pid; __entry->prio = p->prio; __entry->success = success; + __entry->cpu = task_cpu(p); ), - TP_printk("task %s:%d [%d] success=%d", + TP_printk("task %s:%d [%d] success=%d [%03d]", __entry->comm, __entry->pid, __entry->prio, - __entry->success) + __entry->success, __entry->cpu) ); /* -- cgit v0.10.2 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 diff --git a/Documentation/trace/function-graph-fold.vim b/Documentation/trace/function-graph-fold.vim new file mode 100644 index 0000000..0544b50 --- /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 v0.10.2 From aa38e9fc3ea804290efd3a39316d7f7e6c945800 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Fri, 7 Aug 2009 10:33:02 +0800 Subject: tracing/filters: Add filter_type to struct ftrace_event_field The type of a field is stored as a string in @type, and here we add @filter_type which is an enum value. This prepares for later patches, so we can specifically assign different @filter_type for the same @type. For example normally a "char *" field is treated as a ptr, but we may want it to be treated as a string when doing filting. Signed-off-by: Li Zefan LKML-Reference: <4A7B925E.9030605@cn.fujitsu.com> Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 300ef78..64dda57 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -755,6 +755,7 @@ struct ftrace_event_field { struct list_head link; char *name; char *type; + int filter_type; int offset; int size; int is_signed; @@ -800,6 +801,7 @@ extern int apply_subsystem_event_filter(struct event_subsystem *system, char *filter_string); extern void print_subsystem_event_filter(struct event_subsystem *system, struct trace_seq *s); +extern int filter_assign_type(const char *type); static inline int filter_check_discard(struct ftrace_event_call *call, void *rec, diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 79d3520..5740e90 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -44,9 +44,11 @@ int trace_define_field(struct ftrace_event_call *call, const char *type, if (!field->type) goto err; + field->filter_type = filter_assign_type(type); field->offset = offset; field->size = size; field->is_signed = is_signed; + list_add(&field->link, &call->fields); return 0; diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 490337a..22e6d82 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -476,11 +476,12 @@ static int filter_add_pred_fn(struct filter_parse_state *ps, } enum { - FILTER_STATIC_STRING = 1, - FILTER_DYN_STRING + FILTER_OTHER = 0, + FILTER_STATIC_STRING, + FILTER_DYN_STRING, }; -static int is_string_field(const char *type) +int filter_assign_type(const char *type) { if (strstr(type, "__data_loc") && strstr(type, "char")) return FILTER_DYN_STRING; @@ -488,12 +489,18 @@ static int is_string_field(const char *type) if (strchr(type, '[') && strstr(type, "char")) return FILTER_STATIC_STRING; - return 0; + return FILTER_OTHER; +} + +static bool is_string_field(struct ftrace_event_field *field) +{ + return field->filter_type == FILTER_DYN_STRING || + field->filter_type == FILTER_STATIC_STRING; } static int is_legal_op(struct ftrace_event_field *field, int op) { - if (is_string_field(field->type) && (op != OP_EQ && op != OP_NE)) + if (is_string_field(field) && (op != OP_EQ && op != OP_NE)) return 0; return 1; @@ -550,7 +557,6 @@ static int filter_add_pred(struct filter_parse_state *ps, struct ftrace_event_field *field; filter_pred_fn_t fn; unsigned long long val; - int string_type; int ret; pred->fn = filter_pred_none; @@ -578,9 +584,8 @@ static int filter_add_pred(struct filter_parse_state *ps, return -EINVAL; } - string_type = is_string_field(field->type); - if (string_type) { - if (string_type == FILTER_STATIC_STRING) + if (is_string_field(field)) { + if (field->filter_type == FILTER_STATIC_STRING) fn = filter_pred_string; else fn = filter_pred_strloc; -- cgit v0.10.2 From 43b51ead3f752a3935116e5b1a94254b8573734f Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Fri, 7 Aug 2009 10:33:22 +0800 Subject: tracing/filters: Add __field_ext() to TRACE_EVENT Add __field_ext(), so a field can be assigned to a specific filter_type, which matches a corresponding filter function. For example, a later patch will allow this: __field_ext(const char *, str, FILTER_PTR_STR); Signed-off-by: Li Zefan LKML-Reference: <4A7B9272.6050709@cn.fujitsu.com> [ Fixed a -1 to FILTER_OTHER Forward ported to latest kernel. ] Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index df5b085..0440bea 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -140,9 +140,16 @@ extern int filter_current_check_discard(struct ftrace_event_call *call, void *rec, struct ring_buffer_event *event); +enum { + FILTER_OTHER = 0, + FILTER_STATIC_STRING, + FILTER_DYN_STRING, +}; + extern int trace_define_field(struct ftrace_event_call *call, const char *type, const char *name, - int offset, int size, int is_signed); + int offset, int size, int is_signed, + int filter_type); extern int trace_define_common_fields(struct ftrace_event_call *call); #define is_signed_type(type) (((type)(-1)) < 0) diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 1274002..1b1f742 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -21,6 +21,9 @@ #undef __field #define __field(type, item) type item; +#undef __field_ext +#define __field_ext(type, item, filter_type) type item; + #undef __array #define __array(type, item, len) type item[len]; @@ -62,7 +65,10 @@ */ #undef __field -#define __field(type, item); +#define __field(type, item) + +#undef __field_ext +#define __field_ext(type, item, filter_type) #undef __array #define __array(type, item, len) @@ -110,6 +116,9 @@ if (!ret) \ return 0; +#undef __field_ext +#define __field_ext(type, item, filter_type) __field(type, item) + #undef __array #define __array(type, item, len) \ ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ @@ -265,28 +274,33 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) -#undef __field -#define __field(type, item) \ +#undef __field_ext +#define __field_ext(type, item, filter_type) \ ret = trace_define_field(event_call, #type, #item, \ offsetof(typeof(field), item), \ - sizeof(field.item), is_signed_type(type)); \ + sizeof(field.item), \ + is_signed_type(type), filter_type); \ if (ret) \ return ret; +#undef __field +#define __field(type, item) __field_ext(type, item, FILTER_OTHER) + #undef __array #define __array(type, item, len) \ BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \ ret = trace_define_field(event_call, #type "[" #len "]", #item, \ offsetof(typeof(field), item), \ - sizeof(field.item), 0); \ + sizeof(field.item), 0, FILTER_OTHER); \ if (ret) \ return ret; #undef __dynamic_array #define __dynamic_array(type, item, len) \ ret = trace_define_field(event_call, "__data_loc " #type "[]", #item, \ - offsetof(typeof(field), __data_loc_##item), \ - sizeof(field.__data_loc_##item), 0); + offsetof(typeof(field), __data_loc_##item), \ + sizeof(field.__data_loc_##item), 0, \ + FILTER_OTHER); #undef __string #define __string(item, src) __dynamic_array(char, item, -1) @@ -320,6 +334,9 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ #undef __field #define __field(type, item) +#undef __field_ext +#define __field_ext(type, item, filter_type) + #undef __array #define __array(type, item, len) diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 5740e90..d33bcde 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -28,7 +28,8 @@ DEFINE_MUTEX(event_mutex); LIST_HEAD(ftrace_events); int trace_define_field(struct ftrace_event_call *call, const char *type, - const char *name, int offset, int size, int is_signed) + const char *name, int offset, int size, int is_signed, + int filter_type) { struct ftrace_event_field *field; @@ -44,7 +45,11 @@ int trace_define_field(struct ftrace_event_call *call, const char *type, if (!field->type) goto err; - field->filter_type = filter_assign_type(type); + if (filter_type == FILTER_OTHER) + field->filter_type = filter_assign_type(type); + else + field->filter_type = filter_type; + field->offset = offset; field->size = size; field->is_signed = is_signed; @@ -68,7 +73,7 @@ EXPORT_SYMBOL_GPL(trace_define_field); ret = trace_define_field(call, #type, "common_" #item, \ offsetof(typeof(ent), item), \ sizeof(ent.item), \ - is_signed_type(type)); \ + is_signed_type(type), FILTER_OTHER); \ if (ret) \ return ret; diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 22e6d82..8a8e576 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -475,12 +475,6 @@ static int filter_add_pred_fn(struct filter_parse_state *ps, return 0; } -enum { - FILTER_OTHER = 0, - FILTER_STATIC_STRING, - FILTER_DYN_STRING, -}; - int filter_assign_type(const char *type) { if (strstr(type, "__data_loc") && strstr(type, "char")) diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index 7087530..029a91f 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c @@ -158,7 +158,8 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ #define TRACE_FIELD(type, item, assign) \ ret = trace_define_field(event_call, #type, #item, \ offsetof(typeof(field), item), \ - sizeof(field.item), is_signed_type(type)); \ + sizeof(field.item), \ + is_signed_type(type), FILTER_OTHER); \ if (ret) \ return ret; @@ -166,7 +167,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ #define TRACE_FIELD_SPECIAL(type, item, len, cmd) \ ret = trace_define_field(event_call, #type "[" #len "]", #item, \ offsetof(typeof(field), item), \ - sizeof(field.item), 0); \ + sizeof(field.item), 0, FILTER_OTHER); \ if (ret) \ return ret; @@ -174,7 +175,8 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ #define TRACE_FIELD_SIGN(type, item, assign, is_signed) \ ret = trace_define_field(event_call, #type, #item, \ offsetof(typeof(field), item), \ - sizeof(field.item), is_signed); \ + sizeof(field.item), is_signed, \ + FILTER_OTHER); \ if (ret) \ return ret; diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 46c1b977a..97a2454 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -194,7 +194,8 @@ int syscall_enter_define_fields(struct ftrace_event_call *call) for (i = 0; i < meta->nb_args; i++) { ret = trace_define_field(call, meta->types[i], meta->args[i], offset, - sizeof(unsigned long), 0); + sizeof(unsigned long), 0, + FILTER_OTHER); offset += sizeof(unsigned long); } @@ -210,7 +211,8 @@ int syscall_exit_define_fields(struct ftrace_event_call *call) if (ret) return ret; - ret = trace_define_field(call, SYSCALL_FIELD(unsigned long, ret), 0); + ret = trace_define_field(call, SYSCALL_FIELD(unsigned long, ret), 0, + FILTER_OTHER); return ret; } -- cgit v0.10.2 From 87a342f5db69d53ea70493bb1ec69c9047677038 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Fri, 7 Aug 2009 10:33:43 +0800 Subject: tracing/filters: Support filtering for char * strings Usually, char * entries are dangerous in traces because the string can be released whereas a pointer to it can still wait to be read from the ring buffer. But sometimes we can assume it's safe, like in case of RO data (eg: __file__ or __line__, used in bkl trace event). If these RO data are in a module and so is the call to the trace event, then it's safe, because the ring buffer will be flushed once this module get unloaded. To allow char * to be treated as a string: TRACE_EVENT(..., TP_STRUCT__entry( __field_ext(const char *, name, FILTER_PTR_STRING) ... ) ... ); The filtering will not dereference "char *" unless the developer explicitly sets FILTER_PTR_STR in __field_ext. Signed-off-by: Li Zefan LKML-Reference: <4A7B9287.90205@cn.fujitsu.com> Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 0440bea..ace2da9 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -144,6 +144,7 @@ enum { FILTER_OTHER = 0, FILTER_STATIC_STRING, FILTER_DYN_STRING, + FILTER_PTR_STRING, }; extern int trace_define_field(struct ftrace_event_call *call, diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 8a8e576..9f03082 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -163,6 +163,20 @@ static int filter_pred_string(struct filter_pred *pred, void *event, return match; } +/* Filter predicate for char * pointers */ +static int filter_pred_pchar(struct filter_pred *pred, void *event, + int val1, int val2) +{ + char **addr = (char **)(event + pred->offset); + int cmp, match; + + cmp = strncmp(*addr, pred->str_val, pred->str_len); + + match = (!cmp) ^ pred->not; + + return match; +} + /* * Filter predicate for dynamic sized arrays of characters. * These are implemented through a list of strings at the end @@ -489,7 +503,8 @@ int filter_assign_type(const char *type) static bool is_string_field(struct ftrace_event_field *field) { return field->filter_type == FILTER_DYN_STRING || - field->filter_type == FILTER_STATIC_STRING; + field->filter_type == FILTER_STATIC_STRING || + field->filter_type == FILTER_PTR_STRING; } static int is_legal_op(struct ftrace_event_field *field, int op) @@ -579,11 +594,16 @@ static int filter_add_pred(struct filter_parse_state *ps, } if (is_string_field(field)) { + pred->str_len = field->size; + if (field->filter_type == FILTER_STATIC_STRING) fn = filter_pred_string; - else + else if (field->filter_type == FILTER_DYN_STRING) fn = filter_pred_strloc; - pred->str_len = field->size; + else { + fn = filter_pred_pchar; + pred->str_len = strlen(pred->str_val); + } } else { if (field->is_signed) ret = strict_strtoll(pred->str_val, 0, &val); -- cgit v0.10.2 From 5079f3261ffd7fe4a537679af695f2328943a245 Mon Sep 17 00:00:00 2001 From: Zhaolei Date: Tue, 25 Aug 2009 16:12:56 +0800 Subject: ftrace: Move setting of clock-source out of options There are many clock sources for the tracing system but we can only enable/disable one at a time with the trace/options file. We can move the setting of clock-source out of options and add a separate file for it: # cat trace_clock [local] global # echo global > trace_clock # cat trace_clock local [global] Signed-off-by: Zhao Lei LKML-Reference: <4A939D08.6050604@cn.fujitsu.com> Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 8ac2043..63dbc7f 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -323,12 +323,21 @@ static const char *trace_options[] = { "printk-msg-only", "context-info", "latency-format", - "global-clock", "sleep-time", "graph-time", NULL }; +static struct { + u64 (*func)(void); + const char *name; +} trace_clocks[] = { + { trace_clock_local, "local" }, + { trace_clock_global, "global" }, +}; + +int trace_clock_id; + /* * ftrace_max_lock is used to protect the swapping of buffers * when taking a max snapshot. The buffers themselves are @@ -2159,22 +2168,6 @@ static void set_tracer_flags(unsigned int mask, int enabled) trace_flags |= mask; else trace_flags &= ~mask; - - if (mask == TRACE_ITER_GLOBAL_CLK) { - u64 (*func)(void); - - if (enabled) - func = trace_clock_global; - else - func = trace_clock_local; - - mutex_lock(&trace_types_lock); - ring_buffer_set_clock(global_trace.buffer, func); - - if (max_tr.buffer) - ring_buffer_set_clock(max_tr.buffer, func); - mutex_unlock(&trace_types_lock); - } } static ssize_t @@ -3142,6 +3135,62 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, return cnt; } +static ssize_t tracing_clock_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char buf[64]; + int bufiter = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(trace_clocks); i++) + bufiter += snprintf(buf + bufiter, sizeof(buf) - bufiter, + "%s%s%s%s", i ? " " : "", + i == trace_clock_id ? "[" : "", trace_clocks[i].name, + i == trace_clock_id ? "]" : ""); + bufiter += snprintf(buf + bufiter, sizeof(buf) - bufiter, "\n"); + + return simple_read_from_buffer(ubuf, cnt, ppos, buf, bufiter); +} + +static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *fpos) +{ + char buf[64]; + const char *clockstr; + int i; + + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + clockstr = strstrip(buf); + + for (i = 0; i < ARRAY_SIZE(trace_clocks); i++) { + if (strcmp(trace_clocks[i].name, clockstr) == 0) + break; + } + if (i == ARRAY_SIZE(trace_clocks)) + return -EINVAL; + + trace_clock_id = i; + + mutex_lock(&trace_types_lock); + + ring_buffer_set_clock(global_trace.buffer, trace_clocks[i].func); + if (max_tr.buffer) + ring_buffer_set_clock(max_tr.buffer, trace_clocks[i].func); + + mutex_unlock(&trace_types_lock); + + *fpos += cnt; + + return cnt; +} + static const struct file_operations tracing_max_lat_fops = { .open = tracing_open_generic, .read = tracing_max_lat_read, @@ -3179,6 +3228,12 @@ static const struct file_operations tracing_mark_fops = { .write = tracing_mark_write, }; +static const struct file_operations trace_clock_fops = { + .open = tracing_open_generic, + .read = tracing_clock_read, + .write = tracing_clock_write, +}; + struct ftrace_buffer_info { struct trace_array *tr; void *spare; @@ -3918,6 +3973,9 @@ static __init int tracer_init_debugfs(void) trace_create_file("saved_cmdlines", 0444, d_tracer, NULL, &tracing_saved_cmdlines_fops); + trace_create_file("trace_clock", 0644, d_tracer, NULL, + &trace_clock_fops); + #ifdef CONFIG_DYNAMIC_FTRACE trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, &ftrace_update_tot_cnt, &tracing_dyn_info_fops); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 64dda57..654fd65 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -568,6 +568,8 @@ trace_vprintk(unsigned long ip, const char *fmt, va_list args); extern unsigned long trace_flags; +extern int trace_clock_id; + /* Standard output formatting function used for function return traces */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER extern enum print_line_t print_graph_function(struct trace_iterator *iter); @@ -656,9 +658,8 @@ enum trace_iterator_flags { TRACE_ITER_PRINTK_MSGONLY = 0x10000, TRACE_ITER_CONTEXT_INFO = 0x20000, /* Print pid/cpu/time */ TRACE_ITER_LATENCY_FMT = 0x40000, - TRACE_ITER_GLOBAL_CLK = 0x80000, - TRACE_ITER_SLEEP_TIME = 0x100000, - TRACE_ITER_GRAPH_TIME = 0x200000, + TRACE_ITER_SLEEP_TIME = 0x80000, + TRACE_ITER_GRAPH_TIME = 0x100000, }; /* -- cgit v0.10.2 From 5ac35daa9343936038a3c9c4f4d6d3fe6a2a7bd8 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Tue, 25 Aug 2009 14:06:22 +0800 Subject: tracing/events: fix the include file dependencies The TRACE_EVENT depends on the include/linux/tracepoint.h first and include/trace/ftrace.h later, if we include the ftrace.h early, a building error will occur. Both define TRACE_EVENT in trace_a.h and trace_b.h, if we include those in .c file, like this: #define CREATE_TRACE_POINTS include include The above will not work, because the TRACE_EVENT was re-defined by the previous .h file. Reported-by: Wei Yongjun Signed-off-by: Xiao Guangrong LKML-Reference: <4A937F5E.3020802@cn.fujitsu.com> Signed-off-by: Steven Rostedt diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 5984ed0..8170985 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -180,6 +180,7 @@ static inline void tracepoint_synchronize_unregister(void) } #define PARAMS(args...) args +#endif #ifndef TRACE_EVENT /* @@ -287,5 +288,3 @@ static inline void tracepoint_synchronize_unregister(void) #define TRACE_EVENT(name, proto, args, struct, assign, print) \ DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) #endif - -#endif diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h index f7a7ae1..cd150b9 100644 --- a/include/trace/define_trace.h +++ b/include/trace/define_trace.h @@ -56,6 +56,7 @@ #include #endif +#undef TRACE_EVENT #undef TRACE_HEADER_MULTI_READ /* Only undef what we defined in this file */ -- cgit v0.10.2 From 7cb2e3ee2aeec5b83ecadba929a2dc575dd4008f Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 26 Aug 2009 00:32:37 -0400 Subject: tracing: add comments to explain TRACE_EVENT out of protection The commit: commit 5ac35daa9343936038a3c9c4f4d6d3fe6a2a7bd8 Author: Xiao Guangrong tracing/events: fix the include file dependencies Moved the TRACE_EVENT out of the ifdef protection of tracepoints.h but uses the define of TRACE_EVENT itself as protection. This patch adds comments to explain why. Signed-off-by: Steven Rostedt diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 8170985..0341f2e 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -180,7 +180,15 @@ static inline void tracepoint_synchronize_unregister(void) } #define PARAMS(args...) args -#endif + +#endif /* _LINUX_TRACEPOINT_H */ + +/* + * Note: we keep the TRACE_EVENT outside the include file ifdef protection. + * This is due to the way trace events work. If a file includes two + * trace event headers under one "CREATE_TRACE_POINTS" the first include + * will override the TRACE_EVENT and break the second include. + */ #ifndef TRACE_EVENT /* @@ -287,4 +295,5 @@ static inline void tracepoint_synchronize_unregister(void) #define TRACE_EVENT(name, proto, args, struct, assign, print) \ DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) -#endif + +#endif /* ifdef TRACE_EVENT (see note above) */ -- cgit v0.10.2 From 8f3e1df48baf728bbb0f242c9dff9c9d7108218a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 24 Aug 2009 21:53:36 +0400 Subject: x86, ioapic: Define IO_APIC_DEFAULT_PHYS_BASE constant We already have APIC_DEFAULT_PHYS_BASE so just to be consistent. Signed-off-by: Cyrill Gorcunov LKML-Reference: <20090824175550.927946757@openvz.org> Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/apicdef.h b/arch/x86/include/asm/apicdef.h index 7ddb36a..7386bfa 100644 --- a/arch/x86/include/asm/apicdef.h +++ b/arch/x86/include/asm/apicdef.h @@ -8,7 +8,8 @@ * Ingo Molnar , 1999, 2000 */ -#define APIC_DEFAULT_PHYS_BASE 0xfee00000 +#define IO_APIC_DEFAULT_PHYS_BASE 0xfec00000 +#define APIC_DEFAULT_PHYS_BASE 0xfee00000 #define APIC_ID 0x20 diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 651c93b..fcd513b 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -482,11 +482,11 @@ static void __init construct_ioapic_table(int mpc_default_type) MP_bus_info(&bus); } - ioapic.type = MP_IOAPIC; - ioapic.apicid = 2; - ioapic.apicver = mpc_default_type > 4 ? 0x10 : 0x01; - ioapic.flags = MPC_APIC_USABLE; - ioapic.apicaddr = 0xFEC00000; + ioapic.type = MP_IOAPIC; + ioapic.apicid = 2; + ioapic.apicver = mpc_default_type > 4 ? 0x10 : 0x01; + ioapic.flags = MPC_APIC_USABLE; + ioapic.apicaddr = IO_APIC_DEFAULT_PHYS_BASE; MP_ioapic_info(&ioapic); /* -- cgit v0.10.2 From ffc438366c2660a6a811b94ba33229bf217f8254 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 24 Aug 2009 21:53:39 +0400 Subject: x86, ioapic: Get rid of needless check and simplify ioapic_setup_resources() alloc_bootmem() already panics on allocation failure. There is no need to check the result. Also there is a way to unbind global variable from its body and use it as a parameter which allow us to simplify ioapic_init_mappings as well -- "for" cycle already uses nr_ioapics as a conditional variable and there is no need to check if ioapic_setup_resources was returning NULL again. Signed-off-by: Cyrill Gorcunov Cc: Yinghai Lu LKML-Reference: <20090824175551.493629148@openvz.org> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 2999f3d..d836b4d 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -4053,7 +4053,7 @@ void __init setup_ioapic_dest(void) static struct resource *ioapic_resources; -static struct resource * __init ioapic_setup_resources(void) +static struct resource * __init ioapic_setup_resources(int nr_ioapics) { unsigned long n; struct resource *res; @@ -4069,15 +4069,13 @@ static struct resource * __init ioapic_setup_resources(void) mem = alloc_bootmem(n); res = (void *)mem; - if (mem != NULL) { - mem += sizeof(struct resource) * nr_ioapics; + mem += sizeof(struct resource) * nr_ioapics; - for (i = 0; i < nr_ioapics; i++) { - res[i].name = mem; - res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY; - sprintf(mem, "IOAPIC %u", i); - mem += IOAPIC_RESOURCE_NAME_SIZE; - } + for (i = 0; i < nr_ioapics; i++) { + res[i].name = mem; + res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY; + sprintf(mem, "IOAPIC %u", i); + mem += IOAPIC_RESOURCE_NAME_SIZE; } ioapic_resources = res; @@ -4091,7 +4089,7 @@ void __init ioapic_init_mappings(void) struct resource *ioapic_res; int i; - ioapic_res = ioapic_setup_resources(); + ioapic_res = ioapic_setup_resources(nr_ioapics); for (i = 0; i < nr_ioapics; i++) { if (smp_found_config) { ioapic_phys = mp_ioapics[i].apicaddr; @@ -4120,11 +4118,9 @@ fake_ioapic_page: __fix_to_virt(idx), ioapic_phys); idx++; - if (ioapic_res != NULL) { - ioapic_res->start = ioapic_phys; - ioapic_res->end = ioapic_phys + (4 * 1024) - 1; - ioapic_res++; - } + ioapic_res->start = ioapic_phys; + ioapic_res->end = ioapic_phys + (4 * 1024) - 1; + ioapic_res++; } } -- cgit v0.10.2 From 5051fd69773d2d044734b78516317a04d3774871 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 24 Aug 2009 21:53:37 +0400 Subject: x86, e820: Guard against array overflowed in __e820_add_region() Better to be paranoid against unpredicted nr_map modifications. Signed-off-by: Cyrill Gorcunov LKML-Reference: <20090824175551.146070377@openvz.org> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 7271fa3..2e5e0fa 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -115,7 +115,7 @@ static void __init __e820_add_region(struct e820map *e820x, u64 start, u64 size, { int x = e820x->nr_map; - if (x == ARRAY_SIZE(e820x->map)) { + if (x >= ARRAY_SIZE(e820x->map)) { printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); return; } -- cgit v0.10.2 From ca42a613c92d131ff02d5714419d58c36c3459f3 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 26 Aug 2009 04:04:01 -0300 Subject: Bluetooth: Acknowledge L2CAP packets when receiving RR-frames (F-bit=1) Implement the Recv ReqSeqAndFBit event when a RR frame with F bit set is received. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index e5847c5..0a36c61 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3348,9 +3348,13 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str case L2CAP_SUPER_RCV_READY: if (rx_control & L2CAP_CTRL_POLL) { u16 control = L2CAP_CTRL_FINAL; - control |= L2CAP_SUPER_RCV_READY; + control |= L2CAP_SUPER_RCV_READY | + (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT); l2cap_send_sframe(l2cap_pi(sk), control); } else if (rx_control & L2CAP_CTRL_FINAL) { + pi->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(sk); + if (!(pi->conn_state & L2CAP_CONN_WAIT_F)) break; -- cgit v0.10.2 From 2246b2f1b43f3fbd128e72b129dcbbd3202cc592 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 26 Aug 2009 04:04:02 -0300 Subject: Bluetooth: Handle L2CAP case when the remote receiver is busy Implement all issues related to RemoteBusy in the RECV state table. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7ca614a..9516f4b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -373,6 +373,8 @@ struct l2cap_pinfo { #define L2CAP_CONN_WAIT_F 0x04 #define L2CAP_CONN_SREJ_ACT 0x08 #define L2CAP_CONN_SEND_PBIT 0x10 +#define L2CAP_CONN_REMOTE_BUSY 0x20 +#define L2CAP_CONN_LOCAL_BUSY 0x40 #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 0a36c61..40fbf5c 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1350,7 +1350,8 @@ static int l2cap_ertm_send(struct sock *sk) if (pi->conn_state & L2CAP_CONN_WAIT_F) return 0; - while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) { + while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk)) + && !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) { tx_skb = skb_clone(skb, GFP_ATOMIC); if (pi->remote_max_tx && @@ -3351,7 +3352,10 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str control |= L2CAP_SUPER_RCV_READY | (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT); l2cap_send_sframe(l2cap_pi(sk), control); + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + } else if (rx_control & L2CAP_CTRL_FINAL) { + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); @@ -3366,13 +3370,19 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str } else { pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); - if (pi->unacked_frames > 0) + + if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) + && (pi->unacked_frames > 0)) __mod_retrans_timer(); + l2cap_ertm_send(sk); + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; } break; case L2CAP_SUPER_REJECT: + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + pi->expected_ack_seq = __get_reqseq(rx_control); l2cap_drop_acked_frames(sk); @@ -3384,6 +3394,8 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str break; case L2CAP_SUPER_SELECT_REJECT: + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + if (rx_control & L2CAP_CTRL_POLL) { l2cap_retransmit_frame(sk, tx_seq); pi->expected_ack_seq = tx_seq; @@ -3410,6 +3422,15 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str break; case L2CAP_SUPER_RCV_NOT_READY: + pi->conn_state |= L2CAP_CONN_REMOTE_BUSY; + pi->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(sk); + + del_timer(&l2cap_pi(sk)->retrans_timer); + if (rx_control & L2CAP_CTRL_POLL) { + u16 control = L2CAP_CTRL_FINAL | L2CAP_SUPER_RCV_READY; + l2cap_send_sframe(l2cap_pi(sk), control); + } break; } -- cgit v0.10.2 From 7e7430908c3ccaf71f0851050c8ccaf9ecfb3b56 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 26 Aug 2009 04:04:03 -0300 Subject: Bluetooth: Add support for L2CAP 'Send RRorRNR' action When called, 'Send RRorRNR' should send a RNR frame if local device is busy or a RR frame otherwise. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 40fbf5c..b030125 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -366,6 +366,16 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) return hci_send_acl(pi->conn->hcon, skb, 0); } +static inline int l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) +{ + if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) + control |= L2CAP_SUPER_RCV_NOT_READY; + else + control |= L2CAP_SUPER_RCV_READY; + + return l2cap_send_sframe(pi, control); +} + static void l2cap_do_start(struct sock *sk) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; @@ -1202,8 +1212,7 @@ static void l2cap_monitor_timeout(unsigned long arg) __mod_monitor_timer(); control = L2CAP_CTRL_POLL; - control |= L2CAP_SUPER_RCV_READY; - l2cap_send_sframe(l2cap_pi(sk), control); + l2cap_send_rr_or_rnr(l2cap_pi(sk), control); bh_unlock_sock(sk); } @@ -1219,8 +1228,7 @@ static void l2cap_retrans_timeout(unsigned long arg) l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; control = L2CAP_CTRL_POLL; - control |= L2CAP_SUPER_RCV_READY; - l2cap_send_sframe(l2cap_pi(sk), control); + l2cap_send_rr_or_rnr(l2cap_pi(sk), control); bh_unlock_sock(sk); } @@ -3428,8 +3436,8 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str del_timer(&l2cap_pi(sk)->retrans_timer); if (rx_control & L2CAP_CTRL_POLL) { - u16 control = L2CAP_CTRL_FINAL | L2CAP_SUPER_RCV_READY; - l2cap_send_sframe(l2cap_pi(sk), control); + u16 control = L2CAP_CTRL_FINAL; + l2cap_send_rr_or_rnr(l2cap_pi(sk), control); } break; } -- cgit v0.10.2 From 06e799764eb7c2e4640888d438c3524d756613e1 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 25 Aug 2009 18:53:37 -0700 Subject: rcu: Remove lockdep annotations from RCU's _notrace() API members The lockdep annotations rcu_read_acquire() and rcu_read_release() might lead to infinite looping if called from lockdep. So this patch removes them. Formal repost of http://lkml.org/lkml/2009/8/25/309 on the strength of Lai Jiangshan's review. Suggested-by: Lai Jiangshan Suggested-by: Mathieu Desnoyers Reviewed-by: Lai Jiangshan Signed-off-by: Paul E. McKenney Cc: dipankar@in.ibm.com Cc: akpm@linux-foundation.org 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: <20090826015337.GA18904@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 8b4422c..95e0615 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -195,7 +195,6 @@ static inline notrace void rcu_read_lock_sched_notrace(void) { preempt_disable_notrace(); __acquire(RCU_SCHED); - rcu_read_acquire(); } /* @@ -211,7 +210,6 @@ static inline void rcu_read_unlock_sched(void) } static inline notrace void rcu_read_unlock_sched_notrace(void) { - rcu_read_release(); __release(RCU_SCHED); preempt_enable_notrace(); } -- cgit v0.10.2 From f1d269bac24e5ddb3a0650aaeb4117aa806b99f1 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Wed, 26 Aug 2009 12:01:20 +0200 Subject: sound: vwsnd: Fix setting of cfgval and ctlval in li_setup_dma() Since !LI_CCFG_* evaluates to 0, this did not change anything to cfgval and ctlval. Signed-off-by: Roel Kluin Signed-off-by: Takashi Iwai diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c index 187f727..6713110 100644 --- a/sound/oss/vwsnd.c +++ b/sound/oss/vwsnd.c @@ -628,7 +628,7 @@ static void li_setup_dma(dma_chan_t *chan, ASSERT(!(buffer_paddr & 0xFF)); chan->baseval = (buffer_paddr >> 8) | 1 << (37 - 8); - chan->cfgval = (!LI_CCFG_LOCK | + chan->cfgval = ((chan->cfgval & ~LI_CCFG_LOCK) | SHIFT_FIELD(desc->ad1843_slot, LI_CCFG_SLOT) | desc->direction | mode | @@ -638,9 +638,9 @@ static void li_setup_dma(dma_chan_t *chan, tmask = 13 - fragshift; /* See Lithium DMA Notes above. */ ASSERT(size >= 2 && size <= 7); ASSERT(tmask >= 1 && tmask <= 7); - chan->ctlval = (!LI_CCTL_RESET | + chan->ctlval = ((chan->ctlval & ~LI_CCTL_RESET) | SHIFT_FIELD(size, LI_CCTL_SIZE) | - !LI_CCTL_DMA_ENABLE | + (chan->ctlval & ~LI_CCTL_DMA_ENABLE) | SHIFT_FIELD(tmask, LI_CCTL_TMASK) | SHIFT_FIELD(0, LI_CCTL_TPTR)); -- cgit v0.10.2 From bc36681fdc3276b9da4047c277349291c4cbad09 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 25 Aug 2009 15:53:41 +0100 Subject: ASoC: Add S3C24xx dependencies for Simtec machines No point in building them for S3C64xx, certainly no sense in running into build issues there. Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 68fef00..923428f 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -88,14 +88,14 @@ config SND_S3C24XX_SOC_SIMTEC config SND_S3C24XX_SOC_SIMTEC_TLV320AIC23 tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" - depends on SND_S3C24XX_SOC + depends on SND_S3C24XX_SOC && ARCH_S3C2410 select SND_S3C24XX_SOC_I2S select SND_SOC_TLV320AIC23 select SND_S3C24XX_SOC_SIMTEC config SND_S3C24XX_SOC_SIMTEC_HERMES tristate "SoC I2S Audio support for Simtec Hermes board" - depends on SND_S3C24XX_SOC + depends on SND_S3C24XX_SOC && ARCH_S3C2410 select SND_S3C24XX_SOC_I2S select SND_SOC_TLV320AIC3X select SND_S3C24XX_SOC_SIMTEC -- cgit v0.10.2 From 977d49e00d18d500d0bfe77500053d9df9c3db77 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 26 Aug 2009 13:05:14 +0100 Subject: ASoC: Make platform data optional for TLV320AIC3x Now that we don't need the I2C address for the device the platform data is redundant so allow it to be omitted. Signed-off-by: Mark Brown Tested-by: Chaithrika U S diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 5d54767..3395cf9 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1385,15 +1385,14 @@ static int aic3x_probe(struct platform_device *pdev) socdev->card->codec = codec; setup = socdev->codec_data; - if (!setup) { - dev_err(&pdev->dev, "No setup data supplied\n"); - return -EINVAL; + if (setup) { + /* setup GPIO functions */ + aic3x_write(codec, AIC3X_GPIO1_REG, + (setup->gpio_func[0] & 0xf) << 4); + aic3x_write(codec, AIC3X_GPIO2_REG, + (setup->gpio_func[1] & 0xf) << 4); } - /* setup GPIO functions */ - aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); - aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); - /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { -- cgit v0.10.2 From 5dc0748182037e3fea35a96d615a3c2610b8e4b0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 26 Aug 2009 14:17:23 +0100 Subject: ASoC: Fix s3c-i2s-v2 build We now need the PCM header to kick the DMA. Signed-off-by: Mark Brown diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 11d8717..aa7af0b 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -36,6 +36,7 @@ #include #include "s3c-i2s-v2.h" +#include "s3c24xx-pcm.h" #undef S3C_IIS_V2_SUPPORTED -- cgit v0.10.2 From f1e887de2d24d50286709912ddc4a91ead21ff81 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 26 Aug 2009 14:14:51 +0100 Subject: ASoC: Don't reconfigure WM8350 FLL if not needed If the requested FLL configuration is the one we're currently running in it's at best pointless to reconfigure the FLL. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 4ded0e3..71c9c4b 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -63,6 +63,8 @@ struct wm8350_data { struct wm8350_jack_data hpl; struct wm8350_jack_data hpr; struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; + int fll_freq_out; + int fll_freq_in; }; static unsigned int wm8350_codec_cache_read(struct snd_soc_codec *codec, @@ -1104,10 +1106,14 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; struct wm8350 *wm8350 = codec->control_data; + struct wm8350_data *priv = codec->private_data; struct _fll_div fll_div; int ret = 0; u16 fll_1, fll_4; + if (freq_in == priv->fll_freq_in && freq_out == priv->fll_freq_out) + return 0; + /* power down FLL - we need to do this for reconfiguration */ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA | WM8350_FLL_OSC_ENA); @@ -1142,6 +1148,9 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai, wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA); wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA); + priv->fll_freq_out = freq_out; + priv->fll_freq_in = freq_in; + return 0; } -- cgit v0.10.2 From 7ced156bb8bb6363b6ed541871bf19a90273f910 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 26 Aug 2009 11:51:26 -0300 Subject: perf top: Show RIP only in verbose mode Signed-off-by: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Frederic Weisbecker LKML-Reference: <20090826145126.GA5255@ghostprotocols.net> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 62b55ec..4002ccb 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -483,11 +483,16 @@ static void print_sym_table(void) if (nr_counters == 1) printf(" samples pcnt"); else - printf(" weight samples pcnt"); + printf(" weight samples pcnt"); - printf(" RIP kernel function\n" - " ______ _______ _____ ________________ _______________\n\n" - ); + if (verbose) + printf(" RIP "); + printf(" kernel function\n"); + printf(" %s _______ _____", + nr_counters == 1 ? " " : "______"); + if (verbose) + printf(" ________________"); + printf(" _______________\n\n"); for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { struct symbol *sym; @@ -508,7 +513,9 @@ static void print_sym_table(void) printf("%9.1f %10ld - ", syme->weight, syme->snap_count); percent_color_fprintf(stdout, "%4.1f%%", pcnt); - printf(" - %016llx : %s", sym->start, sym->name); + if (verbose) + printf(" - %016llx", sym->start); + printf(" : %s", sym->name); if (sym->module) printf("\t[%s]", sym->module->name); printf("\n"); -- cgit v0.10.2 From d3a247bfb2c26f5b67367d58af7ad8c2efbbc6c1 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 26 Aug 2009 21:13:24 +0400 Subject: x86, apic: Slim down stack usage in early_init_lapic_mapping() As far as I see there is no external poking of mp_lapic_addr in this procedure which could lead to unpredited changes and require local storage unit for it. Lets use it plain forward. Signed-off-by: Cyrill Gorcunov Cc: Yinghai Lu LKML-Reference: <20090826171324.GC4548@lenovo> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 3fc3a6c..159740d 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1562,8 +1562,6 @@ no_apic: #ifdef CONFIG_X86_64 void __init early_init_lapic_mapping(void) { - unsigned long phys_addr; - /* * If no local APIC can be found then go out * : it means there is no mpatable and MADT @@ -1571,11 +1569,9 @@ void __init early_init_lapic_mapping(void) if (!smp_found_config) return; - phys_addr = mp_lapic_addr; - - set_fixmap_nocache(FIX_APIC_BASE, phys_addr); + set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr); apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n", - APIC_BASE, phys_addr); + APIC_BASE, mp_lapic_addr); /* * Fetch the APIC ID of the BSP in case we have a -- cgit v0.10.2 From 7515bf59f87f19b2a17972b74230d2f91756fe3c Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Tue, 25 Aug 2009 14:31:11 +0200 Subject: tracing: Add syscall tracepoints - s390 arch update This patch includes s390 arch updates to synchronize with latest core changes in the syscalls tracing area. - tracing: Map syscall name to number (syscall_name_to_nr()) - tracing: Call arch_init_ftrace_syscalls at boot - tracing: add support tracepoint ids (set_syscall_{enter,exit}_id()) Signed-off-by: Hendrik Brueckner Cc: Jason Baron Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Martin Schwidefsky Cc: Paul Mundt LKML-Reference: <20090825123111.GD4639@cetus.boeblingen.de.ibm.com> Signed-off-by: Frederic Weisbecker diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 3e298e6..57bdcb1 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -220,6 +220,29 @@ struct syscall_metadata *syscall_nr_to_meta(int nr) return syscalls_metadata[nr]; } +int syscall_name_to_nr(char *name) +{ + int i; + + if (!syscalls_metadata) + return -1; + for (i = 0; i < NR_syscalls; i++) + if (syscalls_metadata[i]) + if (!strcmp(syscalls_metadata[i]->name, name)) + return i; + return -1; +} + +void set_syscall_enter_id(int num, int id) +{ + syscalls_metadata[num]->enter_id = id; +} + +void set_syscall_exit_id(int num, int id) +{ + syscalls_metadata[num]->exit_id = id; +} + static struct syscall_metadata *find_syscall_meta(unsigned long syscall) { struct syscall_metadata *start; @@ -237,24 +260,19 @@ static struct syscall_metadata *find_syscall_meta(unsigned long syscall) return NULL; } -void arch_init_ftrace_syscalls(void) +static int __init arch_init_ftrace_syscalls(void) { struct syscall_metadata *meta; int i; - static atomic_t refs; - - if (atomic_inc_return(&refs) != 1) - goto out; syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * NR_syscalls, GFP_KERNEL); if (!syscalls_metadata) - goto out; + return -ENOMEM; for (i = 0; i < NR_syscalls; i++) { meta = find_syscall_meta((unsigned long)sys_call_table[i]); syscalls_metadata[i] = meta; } - return; -out: - atomic_dec(&refs); + return 0; } +arch_initcall(arch_init_ftrace_syscalls); #endif -- cgit v0.10.2 From cd0980fc8add25e8ab12fcf1051c0f20cbc7c0c0 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Tue, 25 Aug 2009 14:50:27 +0200 Subject: tracing: Check invalid syscall nr while tracing syscalls Most arch syscall_get_nr() implementations returns -1 if the syscall number is not valid. Accessing the bit field without a check might result in a kernel oops (at least I saw it on s390 for ftrace selftest). Before this change, this problem did not occur, because the invalid syscall number (-1) caused syscall_nr_to_meta() to return NULL. There are at least two scenarios where syscall_get_nr() can return -1: 1. For example, ptrace stores an invalid syscall number, and thus, tracing code resets it. (see do_syscall_trace_enter in arch/s390/kernel/ptrace.c) 2. The syscall_regfunc() (kernel/tracepoint.c) sets the TIF_SYSCALL_FTRACE (now: TIF_SYSCALL_TRACEPOINT) flag for all threads which include kernel threads. However, the ftrace selftest triggers a kernel oops when testing syscall trace points: - The kernel thread is started as ususal (do_fork()), - tracing code sets TIF_SYSCALL_FTRACE, - the ret_from_fork() function is triggered and starts ftrace_syscall_exit() with an invalid syscall number. To avoid these scenarios, I suggest to check the syscall_nr. For instance, the ftrace selftest fails for s390 (with config option CONFIG_FTRACE_SYSCALLS set) and produces the following kernel oops. Unable to handle kernel pointer dereference at virtual kernel address 2000000000 Oops: 0038 [#1] PREEMPT SMP Modules linked in: CPU: 0 Not tainted 2.6.31-rc6-next-20090819-dirty #18 Process kthreadd (pid: 818, task: 000000003ea207e8, ksp: 000000003e813eb8) Krnl PSW : 0704100180000000 00000000000ea54c (ftrace_syscall_exit+0x58/0xdc) R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:0 CC:1 PM:0 EA:3 Krnl GPRS: 0000000000000000 00000000000e0000 ffffffffffffffff 20000000008c2650 0000000000000007 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 ffffffffffffffff 000000003e813d78 000000003e813f58 0000000000505ba8 000000003e813e18 000000003e813d78 Krnl Code: 00000000000ea540: e330d0000008 ag %r3,0(%r13) 00000000000ea546: a7480007 lhi %r4,7 00000000000ea54a: 1442 nr %r4,%r2 >00000000000ea54c: e31030000090 llgc %r1,0(%r3) 00000000000ea552: 5410d008 n %r1,8(%r13) 00000000000ea556: 8a104000 sra %r1,0(%r4) 00000000000ea55a: 5410d00c n %r1,12(%r13) 00000000000ea55e: 1211 ltr %r1,%r1 Call Trace: ([<0000000000000000>] 0x0) [<000000000001fa22>] do_syscall_trace_exit+0x132/0x18c [<000000000002d0c4>] sysc_return+0x0/0x8 [<000000000001c738>] kernel_thread_starter+0x0/0xc Last Breaking-Event-Address: [<00000000000ea51e>] ftrace_syscall_exit+0x2a/0xdc Signed-off-by: Hendrik Brueckner Acked-by: Heiko Carstens Cc: Jason Baron Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Martin Schwidefsky Cc: Paul Mundt LKML-Reference: <20090825125027.GE4639@cetus.boeblingen.de.ibm.com> Signed-off-by: Frederic Weisbecker diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 85291c4..cb7f600 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -227,6 +227,8 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id) int syscall_nr; syscall_nr = syscall_get_nr(current, regs); + if (syscall_nr < 0) + return; if (!test_bit(syscall_nr, enabled_enter_syscalls)) return; @@ -257,6 +259,8 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret) int syscall_nr; syscall_nr = syscall_get_nr(current, regs); + if (syscall_nr < 0) + return; if (!test_bit(syscall_nr, enabled_exit_syscalls)) return; -- cgit v0.10.2 From cc3b13c11c567c69a6356be98d0c03ff11541d5c Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Tue, 25 Aug 2009 18:02:37 +0200 Subject: tracing: Don't trace kernel thread syscalls Kernel threads don't call syscalls using the sysenter/sysexit path. Instead they directly call the sys_* or do_* functions that implement the syscalls inside the kernel. The current syscall tracepoints only bind the sysenter/sysexit path, then it has no effect to trace the kernel thread calls to syscalls in that path. Setting the TIF_SYSCALL_TRACEPOINT flag is then useless for these. Actually there is only one case when a kernel thread can reach the usual syscall exit tracing path: when we create a kernel thread, the child comes to ret_from_fork and is the fork() return is then traced. But this information alone is useless, then we don't want to set the TIF flags for these threads. Kernel threads have task_struct->mm set to NULL. (Thanks to Heiko for that hint ;-) The idea is then to check the mm field in syscall_regfunc() and set the flag accordingly. Signed-off-by: Hendrik Brueckner Cc: Jason Baron Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Martin Schwidefsky Cc: Paul Mundt Cc: Heiko Carstens Cc: Hendrik Brueckner LKML-Reference: <20090825160237.GG4639@cetus.boeblingen.de.ibm.com> Signed-off-by: Frederic Weisbecker diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 1a6a453..9489a0a 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -597,7 +597,9 @@ void syscall_regfunc(void) if (!sys_tracepoint_refcount) { read_lock_irqsave(&tasklist_lock, flags); do_each_thread(g, t) { - set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); + /* Skip kernel threads. */ + if (t->mm) + set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); } while_each_thread(g, t); read_unlock_irqrestore(&tasklist_lock, flags); } -- cgit v0.10.2 From dd86dda24cc1dc70031a7d9250dc3c0c430a50e2 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 24 Aug 2009 17:40:14 -0400 Subject: tracing: Define NR_syscalls for x86 (32) Add a NR_syscalls #define for x86. This is used in the syscall events tracing code. Todo: make it dynamic like x86_64. NR_syscalls is the usual name used to determine the number of syscalls supported by the current arch. We want to unify the use of this number across archs that support the syscall tracing. This also prepare to move some of the arch code to core code in the syscall tracing area. Signed-off-by: Jason Baron Cc: Paul Mundt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Josh Stone Cc: Thomas Gleixner Cc: H. Peter Anwin Cc: Hendrik Brueckner Cc: Heiko Carstens LKML-Reference: <0f33c0f96d198fccc3ddd9ff7f5334ff5cb42706.1251146513.git.jbaron@redhat.com> Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h index 732a3070..8deaada 100644 --- a/arch/x86/include/asm/unistd_32.h +++ b/arch/x86/include/asm/unistd_32.h @@ -345,6 +345,8 @@ #ifdef __KERNEL__ +#define NR_syscalls 337 + #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT -- cgit v0.10.2 From a5a2f8e2acb991327952c45a13f5441fc09dffd6 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Wed, 26 Aug 2009 12:09:10 -0400 Subject: tracing: Define NR_syscalls for x86_64 Express the available number of syscalls in a standard way by defining NR_syscalls. The common way to define it is to place its definition in asm/unistd.h However, the number of syscalls is defined using __NR_syscall_max in x86-64 after building a dynamic header file "asm-offsets.h" The source file that generates this header, asm-offsets-64.c includes unistd.h, then if we want to express NR_syscalls from __NR_syscall_max in unistd.h only after generating the dynamic header file, we need a watchguard. If unistd.h is included from asm-offsets-64.c, then we are generating asm-offset.h which defines __NR_syscall_max. At this time, we don't want to (we can't) define NR_syscalls, then we do nothing. Otherwise we define NR_syscalls because we know asm-offsets.h has been generated. Signed-off-by: Jason Baron Acked-by: Steven Rostedt Cc: Paul Mundt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Lai Jiangshan Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Josh Stone Cc: Thomas Gleixner Cc: H. Peter Anwin Cc: Hendrik Brueckner Cc: Heiko Carstens LKML-Reference: <20090826160910.GB2658@redhat.com> Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h index 900e161..b9f3c60 100644 --- a/arch/x86/include/asm/unistd_64.h +++ b/arch/x86/include/asm/unistd_64.h @@ -688,6 +688,12 @@ __SYSCALL(__NR_perf_counter_open, sys_perf_counter_open) #endif /* __NO_STUBS */ #ifdef __KERNEL__ + +#ifndef COMPILE_OFFSETS +#include +#define NR_syscalls (__NR_syscall_max + 1) +#endif + /* * "Conditional" syscalls * diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c index 898ecc4..4a6aeed 100644 --- a/arch/x86/kernel/asm-offsets_64.c +++ b/arch/x86/kernel/asm-offsets_64.c @@ -3,6 +3,7 @@ * This code generates raw asm output which is post-processed to extract * and format the required data. */ +#define COMPILE_OFFSETS #include #include -- cgit v0.10.2 From 57421dbbdc932d65f0e6a41ebb027a2bfe3d0669 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 24 Aug 2009 17:40:22 -0400 Subject: tracing: Convert event tracing code to use NR_syscalls Convert the syscalls event tracing code to use NR_syscalls, instead of FTRACE_SYSCALL_MAX. NR_syscalls is standard accross most arches, and reduces code confusion/complexity. Signed-off-by: Jason Baron Cc: Paul Mundt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Josh Stone Cc: Thomas Gleixner Cc: H. Peter Anwin Cc: Hendrik Brueckner Cc: Heiko Carstens LKML-Reference: <9b4f1a84ecae57cc6599412772efa36f0d2b815b.1251146513.git.jbaron@redhat.com> Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 3cff121..9dbb527 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -494,7 +494,7 @@ static struct syscall_metadata *find_syscall_meta(unsigned long *syscall) struct syscall_metadata *syscall_nr_to_meta(int nr) { - if (!syscalls_metadata || nr >= FTRACE_SYSCALL_MAX || nr < 0) + if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) return NULL; return syscalls_metadata[nr]; @@ -507,7 +507,7 @@ int syscall_name_to_nr(char *name) if (!syscalls_metadata) return -1; - for (i = 0; i < FTRACE_SYSCALL_MAX; i++) { + for (i = 0; i < NR_syscalls; i++) { if (syscalls_metadata[i]) { if (!strcmp(syscalls_metadata[i]->name, name)) return i; @@ -533,13 +533,13 @@ static int __init arch_init_ftrace_syscalls(void) unsigned long **psys_syscall_table = &sys_call_table; syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * - FTRACE_SYSCALL_MAX, GFP_KERNEL); + NR_syscalls, GFP_KERNEL); if (!syscalls_metadata) { WARN_ON(1); return -ENOMEM; } - for (i = 0; i < FTRACE_SYSCALL_MAX; i++) { + for (i = 0; i < NR_syscalls; i++) { meta = find_syscall_meta(psys_syscall_table[i]); syscalls_metadata[i] = meta; } diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index cb7f600..4f5fae6 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -11,8 +11,8 @@ static DEFINE_MUTEX(syscall_trace_lock); static int sys_refcount_enter; static int sys_refcount_exit; -static DECLARE_BITMAP(enabled_enter_syscalls, FTRACE_SYSCALL_MAX); -static DECLARE_BITMAP(enabled_exit_syscalls, FTRACE_SYSCALL_MAX); +static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); +static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags) @@ -289,7 +289,7 @@ int reg_event_syscall_enter(void *ptr) name = (char *)ptr; num = syscall_name_to_nr(name); - if (num < 0 || num >= FTRACE_SYSCALL_MAX) + if (num < 0 || num >= NR_syscalls) return -ENOSYS; mutex_lock(&syscall_trace_lock); if (!sys_refcount_enter) @@ -312,7 +312,7 @@ void unreg_event_syscall_enter(void *ptr) name = (char *)ptr; num = syscall_name_to_nr(name); - if (num < 0 || num >= FTRACE_SYSCALL_MAX) + if (num < 0 || num >= NR_syscalls) return; mutex_lock(&syscall_trace_lock); sys_refcount_enter--; @@ -330,7 +330,7 @@ int reg_event_syscall_exit(void *ptr) name = (char *)ptr; num = syscall_name_to_nr(name); - if (num < 0 || num >= FTRACE_SYSCALL_MAX) + if (num < 0 || num >= NR_syscalls) return -ENOSYS; mutex_lock(&syscall_trace_lock); if (!sys_refcount_exit) @@ -353,7 +353,7 @@ void unreg_event_syscall_exit(void *ptr) name = (char *)ptr; num = syscall_name_to_nr(name); - if (num < 0 || num >= FTRACE_SYSCALL_MAX) + if (num < 0 || num >= NR_syscalls) return; mutex_lock(&syscall_trace_lock); sys_refcount_exit--; @@ -373,8 +373,8 @@ struct trace_event event_syscall_exit = { #ifdef CONFIG_EVENT_PROFILE -static DECLARE_BITMAP(enabled_prof_enter_syscalls, FTRACE_SYSCALL_MAX); -static DECLARE_BITMAP(enabled_prof_exit_syscalls, FTRACE_SYSCALL_MAX); +static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls); +static DECLARE_BITMAP(enabled_prof_exit_syscalls, NR_syscalls); static int sys_prof_refcount_enter; static int sys_prof_refcount_exit; @@ -420,7 +420,7 @@ int reg_prof_syscall_enter(char *name) int num; num = syscall_name_to_nr(name); - if (num < 0 || num >= FTRACE_SYSCALL_MAX) + if (num < 0 || num >= NR_syscalls) return -ENOSYS; mutex_lock(&syscall_trace_lock); @@ -442,7 +442,7 @@ void unreg_prof_syscall_enter(char *name) int num; num = syscall_name_to_nr(name); - if (num < 0 || num >= FTRACE_SYSCALL_MAX) + if (num < 0 || num >= NR_syscalls) return; mutex_lock(&syscall_trace_lock); @@ -481,7 +481,7 @@ int reg_prof_syscall_exit(char *name) int num; num = syscall_name_to_nr(name); - if (num < 0 || num >= FTRACE_SYSCALL_MAX) + if (num < 0 || num >= NR_syscalls) return -ENOSYS; mutex_lock(&syscall_trace_lock); @@ -503,7 +503,7 @@ void unreg_prof_syscall_exit(char *name) int num; num = syscall_name_to_nr(name); - if (num < 0 || num >= FTRACE_SYSCALL_MAX) + if (num < 0 || num >= NR_syscalls) return; mutex_lock(&syscall_trace_lock); -- cgit v0.10.2 From 117226d15850387b55fd01675917ee4fcb9699e8 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 24 Aug 2009 17:40:26 -0400 Subject: tracing: Remove FTRACE_SYSCALL_MAX definitions Remove the FTRACE_SYSCALL_MAX definitions now that we have converted the syscall event tracing code to use NR_syscalls. Signed-off-by: Jason Baron Cc: Paul Mundt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Lai Jiangshan Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mathieu Desnoyers Cc: Jiaying Zhang Cc: Martin Bligh Cc: Li Zefan Cc: Josh Stone Cc: Thomas Gleixner Cc: H. Peter Anwin Cc: Hendrik Brueckner Cc: Heiko Carstens LKML-Reference: Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h index 7113654..db24c22 100644 --- a/arch/x86/include/asm/ftrace.h +++ b/arch/x86/include/asm/ftrace.h @@ -28,13 +28,6 @@ #endif -/* FIXME: I don't want to stay hardcoded */ -#ifdef CONFIG_X86_64 -# define FTRACE_SYSCALL_MAX 299 -#else -# define FTRACE_SYSCALL_MAX 337 -#endif - #ifdef CONFIG_FUNCTION_TRACER #define MCOUNT_ADDR ((long)(mcount)) #define MCOUNT_INSN_SIZE 5 /* sizeof mcount call */ -- cgit v0.10.2 From cb7e4b6e37144f5d131ee09296be3c21c41f28d8 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Mon, 24 Aug 2009 19:23:25 +0000 Subject: netxen: remove unused code Remove code for phy access on unreleased NX2031 based quad-gig board. NX3031 based production quad-gig boards do not require direct phy access by driver. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 7a93f82..74ccef5 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1148,8 +1148,6 @@ struct netxen_adapter { struct netxen_recv_context recv_ctx; struct nx_host_tx_ring *tx_ring; - int (*enable_phy_interrupts) (struct netxen_adapter *); - int (*disable_phy_interrupts) (struct netxen_adapter *); int (*macaddr_set) (struct netxen_adapter *, u8 *); int (*set_mtu) (struct netxen_adapter *, int); int (*set_promisc) (struct netxen_adapter *, u32); @@ -1187,22 +1185,11 @@ struct netxen_adapter { const struct firmware *fw; }; -/* Set promiscuous mode for a GbE interface */ -int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode); int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode); -/* Generic enable for GbE ports. Will detect the speed of the link. */ -int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port); int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port); - -/* Disable a GbE interface */ -int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter); int netxen_niu_disable_xg_port(struct netxen_adapter *adapter); -int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, __u32 * readval); int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index fc0638f..98e4b95 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -61,10 +61,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); * Bit 31: soft_reset => 1:reset the MAC and the SERDES, 0:no-op */ -#define netxen_gb_enable_tx(config_word) \ - ((config_word) |= 1 << 0) -#define netxen_gb_enable_rx(config_word) \ - ((config_word) |= 1 << 2) #define netxen_gb_tx_flowctl(config_word) \ ((config_word) |= 1 << 4) #define netxen_gb_rx_flowctl(config_word) \ @@ -77,8 +73,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); ((config_word) |= 1 << 18) #define netxen_gb_rx_reset_mac(config_word) \ ((config_word) |= 1 << 19) -#define netxen_gb_soft_reset(config_word) \ - ((config_word) |= 1 << 31) #define netxen_gb_unset_tx_flowctl(config_word) \ ((config_word) &= ~(1 << 4)) @@ -240,7 +234,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); * Bits 14-15 : speed => 0:10Mb/s, 1:100Mb/s, 2:1000Mb/s, 3:rsvd */ -#define netxen_get_phy_cablelen(config_word) (((config_word) >> 7) & 0x07) #define netxen_get_phy_speed(config_word) (((config_word) >> 14) & 0x03) #define netxen_set_phy_speed(config_word, val) \ @@ -250,85 +243,12 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); #define netxen_clear_phy_duplex(config_word) \ ((config_word) &= ~(1 << 13)) -#define netxen_get_phy_jabber(config_word) \ - _netxen_crb_get_bit(config_word, 0) -#define netxen_get_phy_polarity(config_word) \ - _netxen_crb_get_bit(config_word, 1) -#define netxen_get_phy_recvpause(config_word) \ - _netxen_crb_get_bit(config_word, 2) -#define netxen_get_phy_xmitpause(config_word) \ - _netxen_crb_get_bit(config_word, 3) -#define netxen_get_phy_energydetect(config_word) \ - _netxen_crb_get_bit(config_word, 4) -#define netxen_get_phy_downshift(config_word) \ - _netxen_crb_get_bit(config_word, 5) -#define netxen_get_phy_crossover(config_word) \ - _netxen_crb_get_bit(config_word, 6) #define netxen_get_phy_link(config_word) \ _netxen_crb_get_bit(config_word, 10) -#define netxen_get_phy_resolved(config_word) \ - _netxen_crb_get_bit(config_word, 11) -#define netxen_get_phy_pagercvd(config_word) \ - _netxen_crb_get_bit(config_word, 12) #define netxen_get_phy_duplex(config_word) \ _netxen_crb_get_bit(config_word, 13) /* - * Interrupt Register definition - * This definition applies to registers 18 and 19 (int enable and int status). - * Bit 0 : jabber - * Bit 1 : polarity_changed - * Bit 4 : energy_detect - * Bit 5 : downshift - * Bit 6 : mdi_xover_changed - * Bit 7 : fifo_over_underflow - * Bit 8 : false_carrier - * Bit 9 : symbol_error - * Bit 10: link_status_changed - * Bit 11: autoneg_completed - * Bit 12: page_received - * Bit 13: duplex_changed - * Bit 14: speed_changed - * Bit 15: autoneg_error - */ - -#define netxen_get_phy_int_jabber(config_word) \ - _netxen_crb_get_bit(config_word, 0) -#define netxen_get_phy_int_polarity_changed(config_word) \ - _netxen_crb_get_bit(config_word, 1) -#define netxen_get_phy_int_energy_detect(config_word) \ - _netxen_crb_get_bit(config_word, 4) -#define netxen_get_phy_int_downshift(config_word) \ - _netxen_crb_get_bit(config_word, 5) -#define netxen_get_phy_int_mdi_xover_changed(config_word) \ - _netxen_crb_get_bit(config_word, 6) -#define netxen_get_phy_int_fifo_over_underflow(config_word) \ - _netxen_crb_get_bit(config_word, 7) -#define netxen_get_phy_int_false_carrier(config_word) \ - _netxen_crb_get_bit(config_word, 8) -#define netxen_get_phy_int_symbol_error(config_word) \ - _netxen_crb_get_bit(config_word, 9) -#define netxen_get_phy_int_link_status_changed(config_word) \ - _netxen_crb_get_bit(config_word, 10) -#define netxen_get_phy_int_autoneg_completed(config_word) \ - _netxen_crb_get_bit(config_word, 11) -#define netxen_get_phy_int_page_received(config_word) \ - _netxen_crb_get_bit(config_word, 12) -#define netxen_get_phy_int_duplex_changed(config_word) \ - _netxen_crb_get_bit(config_word, 13) -#define netxen_get_phy_int_speed_changed(config_word) \ - _netxen_crb_get_bit(config_word, 14) -#define netxen_get_phy_int_autoneg_error(config_word) \ - _netxen_crb_get_bit(config_word, 15) - -#define netxen_set_phy_int_link_status_changed(config_word) \ - ((config_word) |= 1 << 10) -#define netxen_set_phy_int_autoneg_completed(config_word) \ - ((config_word) |= 1 << 11) -#define netxen_set_phy_int_speed_changed(config_word) \ - ((config_word) |= 1 << 14) - -/* * NIU Mode Register. * Bit 0 : enable FibreChannel * Bit 1 : enable 10/100/1000 Ethernet @@ -343,33 +263,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); #define NETXEN_NIU_ALLMULTI_MODE 2 /* - * NIU GB Drop CRC Register - * - * Bit 0 : drop_gb0 => 1:drop pkts with bad CRCs, 0:pass them on - * Bit 1 : drop_gb1 => 1:drop pkts with bad CRCs, 0:pass them on - * Bit 2 : drop_gb2 => 1:drop pkts with bad CRCs, 0:pass them on - * Bit 3 : drop_gb3 => 1:drop pkts with bad CRCs, 0:pass them on - */ - -#define netxen_set_gb_drop_gb0(config_word) \ - ((config_word) |= 1 << 0) -#define netxen_set_gb_drop_gb1(config_word) \ - ((config_word) |= 1 << 1) -#define netxen_set_gb_drop_gb2(config_word) \ - ((config_word) |= 1 << 2) -#define netxen_set_gb_drop_gb3(config_word) \ - ((config_word) |= 1 << 3) - -#define netxen_clear_gb_drop_gb0(config_word) \ - ((config_word) &= ~(1 << 0)) -#define netxen_clear_gb_drop_gb1(config_word) \ - ((config_word) &= ~(1 << 1)) -#define netxen_clear_gb_drop_gb2(config_word) \ - ((config_word) &= ~(1 << 2)) -#define netxen_clear_gb_drop_gb3(config_word) \ - ((config_word) &= ~(1 << 3)) - -/* * NIU XG MAC Config Register * * Bit 0 : tx_enable => 1:enable frame xmit, 0:disable diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 474c568..f5807da 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -321,44 +321,25 @@ err_out: void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) { - adapter->macaddr_set = netxen_p2_nic_set_mac_addr; - adapter->set_multi = netxen_p2_nic_set_multi; - - switch (adapter->ahw.port_type) { - case NETXEN_NIC_GBE: - adapter->enable_phy_interrupts = - netxen_niu_gbe_enable_phy_interrupts; - adapter->disable_phy_interrupts = - netxen_niu_gbe_disable_phy_interrupts; - adapter->set_mtu = netxen_nic_set_mtu_gb; - adapter->set_promisc = netxen_niu_set_promiscuous_mode; - adapter->phy_read = netxen_niu_gbe_phy_read; - adapter->phy_write = netxen_niu_gbe_phy_write; - adapter->init_port = netxen_niu_gbe_init_port; - adapter->stop_port = netxen_niu_disable_gbe_port; - break; + adapter->init_port = netxen_niu_xg_init_port; + adapter->stop_port = netxen_niu_disable_xg_port; - case NETXEN_NIC_XGBE: - adapter->enable_phy_interrupts = - netxen_niu_xgbe_enable_phy_interrupts; - adapter->disable_phy_interrupts = - netxen_niu_xgbe_disable_phy_interrupts; + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + adapter->macaddr_set = netxen_p2_nic_set_mac_addr; + adapter->set_multi = netxen_p2_nic_set_multi; adapter->set_mtu = netxen_nic_set_mtu_xgb; - adapter->init_port = netxen_niu_xg_init_port; adapter->set_promisc = netxen_niu_xg_set_promiscuous_mode; - adapter->stop_port = netxen_niu_disable_xg_port; - break; - - default: - break; - } - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + } else { adapter->set_mtu = nx_fw_cmd_set_mtu; adapter->set_promisc = netxen_p3_nic_set_promisc; adapter->macaddr_set = netxen_p3_nic_set_mac_addr; adapter->set_multi = netxen_p3_nic_set_multi; } + + if (adapter->ahw.port_type == NETXEN_NIC_GBE) { + adapter->phy_read = netxen_niu_gbe_phy_read; + adapter->phy_write = netxen_niu_gbe_phy_write; + } } /* diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 5941c79..8b7cd9e 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -30,11 +30,6 @@ #include "netxen_nic.h" -#define NETXEN_GB_MAC_SOFT_RESET 0x80000000 -#define NETXEN_GB_MAC_RESET_PROT_BLK 0x000F0000 -#define NETXEN_GB_MAC_ENABLE_TX_RX 0x00000005 -#define NETXEN_GB_MAC_PAUSED_FRMS 0x00000020 - static long phy_lock_timeout = 100000000; static int phy_lock(struct netxen_adapter *adapter) @@ -227,171 +222,6 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, return result; } -int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter) -{ - NXWR32(adapter, NETXEN_NIU_INT_MASK, 0x3f); - return 0; -} - -int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter) -{ - int result = 0; - __u32 enable = 0; - netxen_set_phy_int_link_status_changed(enable); - netxen_set_phy_int_autoneg_completed(enable); - netxen_set_phy_int_speed_changed(enable); - - if (0 != - netxen_niu_gbe_phy_write(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, - enable)) - result = -EIO; - - return result; -} - -int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter) -{ - NXWR32(adapter, NETXEN_NIU_INT_MASK, 0x7f); - return 0; -} - -int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter) -{ - int result = 0; - if (0 != - netxen_niu_gbe_phy_write(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0)) - result = -EIO; - - return result; -} - -static int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter) -{ - int result = 0; - if (0 != - netxen_niu_gbe_phy_write(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, - -EIO)) - result = -EIO; - - return result; -} - -/* - * netxen_niu_gbe_set_mii_mode- Set 10/100 Mbit Mode for GbE MAC - * - */ -static void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, - int port, long enable) -{ - NXWR32(adapter, NETXEN_NIU_MODE, 0x2); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x80000000); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x0000f0025); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), 0xf1ff); - NXWR32(adapter, NETXEN_NIU_GB0_GMII_MODE + (port << 3), 0); - NXWR32(adapter, NETXEN_NIU_GB0_MII_MODE + (port << 3), 1); - NXWR32(adapter, (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); - NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); - - if (enable) { - /* - * Do NOT enable flow control until a suitable solution for - * shutting down pause frames is found. - */ - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x5); - } - - if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR "ERROR enabling PHY interrupts\n"); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR "ERROR clearing PHY interrupts\n"); -} - -/* - * netxen_niu_gbe_set_gmii_mode- Set GbE Mode for GbE MAC - */ -static void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, - int port, long enable) -{ - NXWR32(adapter, NETXEN_NIU_MODE, 0x2); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x80000000); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x0000f0025); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), 0xf2ff); - NXWR32(adapter, NETXEN_NIU_GB0_MII_MODE + (port << 3), 0); - NXWR32(adapter, NETXEN_NIU_GB0_GMII_MODE + (port << 3), 1); - NXWR32(adapter, (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); - NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); - - if (enable) { - /* - * Do NOT enable flow control until a suitable solution for - * shutting down pause frames is found. - */ - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x5); - } - - if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR "ERROR enabling PHY interrupts\n"); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR "ERROR clearing PHY interrupts\n"); -} - -int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) -{ - int result = 0; - __u32 status; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return 0; - - if (adapter->disable_phy_interrupts) - adapter->disable_phy_interrupts(adapter); - mdelay(2); - - if (0 == netxen_niu_gbe_phy_read(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, &status)) { - if (netxen_get_phy_link(status)) { - if (netxen_get_phy_speed(status) == 2) { - netxen_niu_gbe_set_gmii_mode(adapter, port, 1); - } else if ((netxen_get_phy_speed(status) == 1) - || (netxen_get_phy_speed(status) == 0)) { - netxen_niu_gbe_set_mii_mode(adapter, port, 1); - } else { - result = -1; - } - - } else { - /* - * We don't have link. Cable must be unconnected. - * Enable phy interrupts so we take action when - * plugged in. - */ - - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - NETXEN_GB_MAC_SOFT_RESET); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - NETXEN_GB_MAC_RESET_PROT_BLK | - NETXEN_GB_MAC_ENABLE_TX_RX | - NETXEN_GB_MAC_PAUSED_FRMS); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR - "ERROR clearing PHY interrupts\n"); - if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR - "ERROR enabling PHY interrupts\n"); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR - "ERROR clearing PHY interrupts\n"); - result = -1; - } - } else { - result = -EIO; - } - return result; -} - int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) { if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { @@ -402,24 +232,6 @@ int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) return 0; } -/* Disable a GbE interface */ -int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) -{ - __u32 mac_cfg0; - u32 port = adapter->physical_port; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return 0; - - if (port > NETXEN_NIU_MAX_GBE_PORTS) - return -EINVAL; - mac_cfg0 = 0; - netxen_gb_soft_reset(mac_cfg0); - if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), mac_cfg0)) - return -EIO; - return 0; -} - /* Disable an XG interface */ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) { @@ -439,58 +251,6 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) return 0; } -/* Set promiscuous mode for a GbE interface */ -int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, - u32 mode) -{ - __u32 reg; - u32 port = adapter->physical_port; - - if (port > NETXEN_NIU_MAX_GBE_PORTS) - return -EINVAL; - - /* save previous contents */ - reg = NXRD32(adapter, NETXEN_NIU_GB_DROP_WRONGADDR); - if (mode == NETXEN_NIU_PROMISC_MODE) { - switch (port) { - case 0: - netxen_clear_gb_drop_gb0(reg); - break; - case 1: - netxen_clear_gb_drop_gb1(reg); - break; - case 2: - netxen_clear_gb_drop_gb2(reg); - break; - case 3: - netxen_clear_gb_drop_gb3(reg); - break; - default: - return -EIO; - } - } else { - switch (port) { - case 0: - netxen_set_gb_drop_gb0(reg); - break; - case 1: - netxen_set_gb_drop_gb1(reg); - break; - case 2: - netxen_set_gb_drop_gb2(reg); - break; - case 3: - netxen_set_gb_drop_gb3(reg); - break; - default: - return -EIO; - } - } - if (NXWR32(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, reg)) - return -EIO; - return 0; -} - int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode) { -- cgit v0.10.2 From c9517e5893db03ca8bd32b8783b39af58176947c Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Mon, 24 Aug 2009 19:23:26 +0000 Subject: netxen: implement generic pcie semaphore functions Implement common function for locking/unlocking 8 hardware semaphores used for serializing access to shared resouces on a NIC board by different PCI functions. As by definition, callers of these semaphore API can be put to sleep till the semaphore is locked. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 74ccef5..061e8aa 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1207,6 +1207,30 @@ int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr); #define NXWR32(adapter, off, val) \ (adapter->hw_write_wx(adapter, off, val)) +int netxen_pcie_sem_lock(struct netxen_adapter *, int, u32); +void netxen_pcie_sem_unlock(struct netxen_adapter *, int); + +#define netxen_rom_lock(a) \ + netxen_pcie_sem_lock((a), 2, NETXEN_ROM_LOCK_ID) +#define netxen_rom_unlock(a) \ + netxen_pcie_sem_unlock((a), 2) +#define netxen_phy_lock(a) \ + netxen_pcie_sem_lock((a), 3, NETXEN_PHY_LOCK_ID) +#define netxen_phy_unlock(a) \ + netxen_pcie_sem_unlock((a), 3) +#define netxen_api_lock(a) \ + netxen_pcie_sem_lock((a), 5, 0) +#define netxen_api_unlock(a) \ + netxen_pcie_sem_unlock((a), 5) +#define netxen_sw_lock(a) \ + netxen_pcie_sem_lock((a), 6, 0) +#define netxen_sw_unlock(a) \ + netxen_pcie_sem_unlock((a), 6) +#define crb_win_lock(a) \ + netxen_pcie_sem_lock((a), 7, NETXEN_CRB_WIN_LOCK_ID) +#define crb_win_unlock(a) \ + netxen_pcie_sem_unlock((a), 7) + int netxen_nic_get_board_info(struct netxen_adapter *adapter); void netxen_nic_get_firmware_info(struct netxen_adapter *adapter); int netxen_nic_wol_supported(struct netxen_adapter *adapter); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 3d676fe..ef846b4 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -33,41 +33,6 @@ #define NXHAL_VERSION 1 -static int -netxen_api_lock(struct netxen_adapter *adapter) -{ - u32 done = 0, timeout = 0; - - for (;;) { - /* Acquire PCIE HW semaphore5 */ - done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM5_LOCK)); - - if (done == 1) - break; - - if (++timeout >= NX_OS_CRB_RETRY_COUNT) { - printk(KERN_ERR "%s: lock timeout.\n", __func__); - return -1; - } - - msleep(1); - } - -#if 0 - NXWR32(adapter, - NETXEN_API_LOCK_ID, NX_OS_API_LOCK_DRIVER); -#endif - return 0; -} - -static int -netxen_api_unlock(struct netxen_adapter *adapter) -{ - /* Release PCIE HW semaphore5 */ - NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM5_UNLOCK)); - return 0; -} - static u32 netxen_poll_rsp(struct netxen_adapter *adapter) { diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index c4a4a8b..92f5970 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -899,16 +899,24 @@ enum { #define PCIE_DCR 0x00d8 +#define PCIE_SEM0_LOCK (0x1c000) +#define PCIE_SEM0_UNLOCK (0x1c004) +#define PCIE_SEM1_LOCK (0x1c008) +#define PCIE_SEM1_UNLOCK (0x1c00c) #define PCIE_SEM2_LOCK (0x1c010) /* Flash lock */ #define PCIE_SEM2_UNLOCK (0x1c014) /* Flash unlock */ #define PCIE_SEM3_LOCK (0x1c018) /* Phy lock */ #define PCIE_SEM3_UNLOCK (0x1c01c) /* Phy unlock */ +#define PCIE_SEM4_LOCK (0x1c020) +#define PCIE_SEM4_UNLOCK (0x1c024) #define PCIE_SEM5_LOCK (0x1c028) /* API lock */ #define PCIE_SEM5_UNLOCK (0x1c02c) /* API unlock */ #define PCIE_SEM6_LOCK (0x1c030) /* sw lock */ #define PCIE_SEM6_UNLOCK (0x1c034) /* sw unlock */ #define PCIE_SEM7_LOCK (0x1c038) /* crb win lock */ #define PCIE_SEM7_UNLOCK (0x1c03c) /* crbwin unlock*/ +#define PCIE_SEM_LOCK(N) (PCIE_SEM0_LOCK + 8*(N)) +#define PCIE_SEM_UNLOCK(N) (PCIE_SEM0_UNLOCK + 8*(N)) #define PCIE_SETUP_FUNCTION (0x12040) #define PCIE_SETUP_FUNCTION2 (0x12048) diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 9138bbc..cbfe44c 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -86,7 +86,6 @@ static void __iomem *pci_base_offset(struct netxen_adapter *adapter, return NULL; } -#define CRB_WIN_LOCK_TIMEOUT 100000000 static crb_128M_2M_block_map_t crb_128M_2M_map[64] __cacheline_aligned_in_smp = { {{{0, 0, 0, 0} } }, /* 0: PCI */ @@ -320,6 +319,35 @@ static unsigned crb_hub_agt[64] = #define NETXEN_WINDOW_ONE 0x2000000 /*CRB Window: bit 25 of CRB address */ +#define NETXEN_PCIE_SEM_TIMEOUT 10000 + +int +netxen_pcie_sem_lock(struct netxen_adapter *adapter, int sem, u32 id_reg) +{ + int done = 0, timeout = 0; + + while (!done) { + done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM_LOCK(sem))); + if (done == 1) + break; + if (++timeout >= NETXEN_PCIE_SEM_TIMEOUT) + return -1; + msleep(1); + } + + if (id_reg) + NXWR32(adapter, id_reg, adapter->portnum); + + return 0; +} + +void +netxen_pcie_sem_unlock(struct netxen_adapter *adapter, int sem) +{ + int val; + val = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM_UNLOCK(sem))); +} + #define NETXEN_UNICAST_ADDR(port, index) \ (NETXEN_UNICAST_ADDR_BASE+(port*32)+(index*8)) #define NETXEN_MCAST_ADDR(port, index) \ @@ -906,33 +934,6 @@ int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac) return 0; } -#define CRB_WIN_LOCK_TIMEOUT 100000000 - -static int crb_win_lock(struct netxen_adapter *adapter) -{ - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore3 from PCI HW block */ - done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM7_LOCK)); - if (done == 1) - break; - if (timeout >= CRB_WIN_LOCK_TIMEOUT) - return -1; - timeout++; - udelay(1); - } - NXWR32(adapter, NETXEN_CRB_WIN_LOCK_ID, adapter->portnum); - return 0; -} - -static void crb_win_unlock(struct netxen_adapter *adapter) -{ - int val; - - val = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM7_UNLOCK)); -} - /* * Changes the CRB window to the specified window. */ diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index f5807da..313cd26 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -369,37 +369,7 @@ static u32 netxen_decode_crb_addr(u32 addr) return (pci_base + offset); } -static long rom_max_timeout = 100; -static long rom_lock_timeout = 10000; - -static int rom_lock(struct netxen_adapter *adapter) -{ - int iter; - u32 done = 0; - int timeout = 0; - - while (!done) { - /* acquire semaphore2 from PCI HW block */ - done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM2_LOCK)); - if (done == 1) - break; - if (timeout >= rom_lock_timeout) - return -EIO; - - timeout++; - /* - * Yield CPU - */ - if (!in_atomic()) - schedule(); - else { - for (iter = 0; iter < 20; iter++) - cpu_relax(); /*This a nop instr on i386 */ - } - } - NXWR32(adapter, NETXEN_ROM_LOCK_ID, ROM_LOCK_DRIVER); - return 0; -} +#define NETXEN_MAX_ROM_WAIT_USEC 100 static int netxen_wait_rom_done(struct netxen_adapter *adapter) { @@ -411,22 +381,16 @@ static int netxen_wait_rom_done(struct netxen_adapter *adapter) while (done == 0) { done = NXRD32(adapter, NETXEN_ROMUSB_GLB_STATUS); done &= 2; - timeout++; - if (timeout >= rom_max_timeout) { - printk("Timeout reached waiting for rom done"); + if (++timeout >= NETXEN_MAX_ROM_WAIT_USEC) { + dev_err(&adapter->pdev->dev, + "Timeout reached waiting for rom done"); return -EIO; } + udelay(1); } return 0; } -static void netxen_rom_unlock(struct netxen_adapter *adapter) -{ - /* release semaphore2 */ - NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM2_UNLOCK)); - -} - static int do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) { @@ -471,7 +435,7 @@ netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, { int ret; - ret = rom_lock(adapter); + ret = netxen_rom_lock(adapter); if (ret < 0) return ret; @@ -485,7 +449,7 @@ int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) { int ret; - if (rom_lock(adapter) != 0) + if (netxen_rom_lock(adapter) != 0) return -EIO; ret = do_rom_fast_read(adapter, addr, valp); @@ -506,7 +470,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) u32 off; /* resetall */ - rom_lock(adapter); + netxen_rom_lock(adapter); NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0xffffffff); netxen_rom_unlock(adapter); diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 8b7cd9e..1392e89 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -30,40 +30,6 @@ #include "netxen_nic.h" -static long phy_lock_timeout = 100000000; - -static int phy_lock(struct netxen_adapter *adapter) -{ - int i; - int done = 0, timeout = 0; - - while (!done) { - done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM3_LOCK)); - if (done == 1) - break; - if (timeout >= phy_lock_timeout) { - return -1; - } - timeout++; - if (!in_atomic()) - schedule(); - else { - for (i = 0; i < 20; i++) - cpu_relax(); - } - } - - NXWR32(adapter, NETXEN_PHY_LOCK_ID, PHY_LOCK_DRIVER); - return 0; -} - -static int phy_unlock(struct netxen_adapter *adapter) -{ - adapter->pci_read_immediate(adapter, NETXEN_PCIE_REG(PCIE_SEM3_UNLOCK)); - - return 0; -} - /* * netxen_niu_gbe_phy_read - read a register from the GbE PHY via * mii management interface. @@ -89,9 +55,8 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, __u32 status; __u32 mac_cfg0; - if (phy_lock(adapter) != 0) { + if (netxen_phy_lock(adapter) != 0) return -1; - } /* * MII mgmt all goes through port 0 MAC interface, @@ -141,7 +106,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, if (restore) if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) return -EIO; - phy_unlock(adapter); + netxen_phy_unlock(adapter); return result; } -- cgit v0.10.2 From 3ad4467ca43e7a2556e26e4e304faf3385048834 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Mon, 24 Aug 2009 19:23:27 +0000 Subject: netxen: remove netxen_nic_niu.c Consolidate all MAC/PHY access functions into netxen_nic_hw.c Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/Makefile b/drivers/net/netxen/Makefile index cf01a91..a70b682 100644 --- a/drivers/net/netxen/Makefile +++ b/drivers/net/netxen/Makefile @@ -31,4 +31,4 @@ obj-$(CONFIG_NETXEN_NIC) := netxen_nic.o netxen_nic-y := netxen_nic_hw.o netxen_nic_main.o netxen_nic_init.o \ - netxen_nic_ethtool.o netxen_nic_niu.o netxen_nic_ctx.o + netxen_nic_ethtool.o netxen_nic_ctx.o diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 061e8aa..63e2f79 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -684,7 +684,19 @@ struct netxen_recv_context { #define NX_CDRP_CMD_GET_STATISTICS 0x0000000f #define NX_CDRP_CMD_DELETE_STATISTICS 0x00000010 #define NX_CDRP_CMD_SET_MTU 0x00000012 -#define NX_CDRP_CMD_MAX 0x00000013 +#define NX_CDRP_CMD_READ_PHY 0x00000013 +#define NX_CDRP_CMD_WRITE_PHY 0x00000014 +#define NX_CDRP_CMD_READ_HW_REG 0x00000015 +#define NX_CDRP_CMD_GET_FLOW_CTL 0x00000016 +#define NX_CDRP_CMD_SET_FLOW_CTL 0x00000017 +#define NX_CDRP_CMD_READ_MAX_MTU 0x00000018 +#define NX_CDRP_CMD_READ_MAX_LRO 0x00000019 +#define NX_CDRP_CMD_CONFIGURE_TOE 0x0000001a +#define NX_CDRP_CMD_FUNC_ATTRIB 0x0000001b +#define NX_CDRP_CMD_READ_PEXQ_PARAMETERS 0x0000001c +#define NX_CDRP_CMD_GET_LIC_CAPABILITIES 0x0000001d +#define NX_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e +#define NX_CDRP_CMD_MAX 0x0000001f #define NX_RCODE_SUCCESS 0 #define NX_RCODE_NO_HOST_MEM 1 @@ -1152,8 +1164,8 @@ struct netxen_adapter { int (*set_mtu) (struct netxen_adapter *, int); int (*set_promisc) (struct netxen_adapter *, u32); void (*set_multi) (struct net_device *); - int (*phy_read) (struct netxen_adapter *, long reg, u32 *); - int (*phy_write) (struct netxen_adapter *, long reg, u32 val); + int (*phy_read) (struct netxen_adapter *, u32 reg, u32 *); + int (*phy_write) (struct netxen_adapter *, u32 reg, u32 val); int (*init_port) (struct netxen_adapter *, int); int (*stop_port) (struct netxen_adapter *); @@ -1185,15 +1197,11 @@ struct netxen_adapter { const struct firmware *fw; }; -int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, - u32 mode); int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port); int netxen_niu_disable_xg_port(struct netxen_adapter *adapter); -int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, - __u32 * readval); -int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, - long reg, __u32 val); +int nx_fw_cmd_query_phy(struct netxen_adapter *adapter, u32 reg, u32 *val); +int nx_fw_cmd_set_phy(struct netxen_adapter *adapter, u32 reg, u32 val); /* Functions available from netxen_nic_hw.c */ int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu); @@ -1313,6 +1321,7 @@ int netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max); void netxen_p2_nic_set_multi(struct net_device *netdev); void netxen_p3_nic_set_multi(struct net_device *netdev); void netxen_p3_free_mac_list(struct netxen_adapter *adapter); +int netxen_p2_nic_set_promisc(struct netxen_adapter *adapter, u32 mode); int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32); int netxen_config_intr_coalesce(struct netxen_adapter *adapter); int netxen_config_rss(struct netxen_adapter *adapter, int enable); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index ef846b4..0f42ab9 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -380,6 +380,44 @@ nx_fw_cmd_destroy_tx_ctx(struct netxen_adapter *adapter) } } +int +nx_fw_cmd_query_phy(struct netxen_adapter *adapter, u32 reg, u32 *val) +{ + u32 rcode; + + rcode = netxen_issue_cmd(adapter, + adapter->ahw.pci_func, + NXHAL_VERSION, + reg, + 0, + 0, + NX_CDRP_CMD_READ_PHY); + + if (rcode != NX_RCODE_SUCCESS) + return -EIO; + + return NXRD32(adapter, NX_ARG1_CRB_OFFSET); +} + +int +nx_fw_cmd_set_phy(struct netxen_adapter *adapter, u32 reg, u32 val) +{ + u32 rcode; + + rcode = netxen_issue_cmd(adapter, + adapter->ahw.pci_func, + NXHAL_VERSION, + reg, + val, + 0, + NX_CDRP_CMD_WRITE_PHY); + + if (rcode != NX_RCODE_SUCCESS) + return -EIO; + + return 0; +} + static u64 ctx_addr_sig_regs[][3] = { {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)}, {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)}, diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index cbfe44c..1a8ad62 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -348,6 +348,35 @@ netxen_pcie_sem_unlock(struct netxen_adapter *adapter, int sem) val = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM_UNLOCK(sem))); } +int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) +{ + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1+(0x10000*port), 0x1447); + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_0+(0x10000*port), 0x5); + } + + return 0; +} + +/* Disable an XG interface */ +int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) +{ + __u32 mac_cfg; + u32 port = adapter->physical_port; + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + return 0; + + if (port > NETXEN_NIU_MAX_XG_PORTS) + return -EINVAL; + + mac_cfg = 0; + if (NXWR32(adapter, + NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), mac_cfg)) + return -EIO; + return 0; +} + #define NETXEN_UNICAST_ADDR(port, index) \ (NETXEN_UNICAST_ADDR_BASE+(port*32)+(index*8)) #define NETXEN_MCAST_ADDR(port, index) \ @@ -357,6 +386,56 @@ netxen_pcie_sem_unlock(struct netxen_adapter *adapter, int sem) #define MAC_LO(addr) \ ((addr[5] << 16) | (addr[4] << 8) | (addr[3])) +int netxen_p2_nic_set_promisc(struct netxen_adapter *adapter, u32 mode) +{ + __u32 reg; + u32 port = adapter->physical_port; + + if (port > NETXEN_NIU_MAX_XG_PORTS) + return -EINVAL; + + reg = NXRD32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port)); + if (mode == NETXEN_NIU_PROMISC_MODE) + reg = (reg | 0x2000UL); + else + reg = (reg & ~0x2000UL); + + if (mode == NETXEN_NIU_ALLMULTI_MODE) + reg = (reg | 0x1000UL); + else + reg = (reg & ~0x1000UL); + + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); + + return 0; +} + +int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr) +{ + u32 mac_hi, mac_lo; + u32 reg_hi, reg_lo; + + u8 phy = adapter->physical_port; + + if (phy >= NETXEN_NIU_MAX_XG_PORTS) + return -EINVAL; + + mac_lo = ((u32)addr[0] << 16) | ((u32)addr[1] << 24); + mac_hi = addr[2] | ((u32)addr[3] << 8) | + ((u32)addr[4] << 16) | ((u32)addr[5] << 24); + + reg_lo = NETXEN_NIU_XGE_STATION_ADDR_0_1 + (0x10000 * phy); + reg_hi = NETXEN_NIU_XGE_STATION_ADDR_0_HI + (0x10000 * phy); + + /* write twice to flush */ + if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) + return -EIO; + if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) + return -EIO; + + return 0; +} + static int netxen_nic_enable_mcast_filter(struct netxen_adapter *adapter) { diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 313cd26..8d4aa6f 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -328,17 +328,17 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) adapter->macaddr_set = netxen_p2_nic_set_mac_addr; adapter->set_multi = netxen_p2_nic_set_multi; adapter->set_mtu = netxen_nic_set_mtu_xgb; - adapter->set_promisc = netxen_niu_xg_set_promiscuous_mode; + adapter->set_promisc = netxen_p2_nic_set_promisc; } else { adapter->set_mtu = nx_fw_cmd_set_mtu; adapter->set_promisc = netxen_p3_nic_set_promisc; adapter->macaddr_set = netxen_p3_nic_set_mac_addr; adapter->set_multi = netxen_p3_nic_set_multi; - } - if (adapter->ahw.port_type == NETXEN_NIC_GBE) { - adapter->phy_read = netxen_niu_gbe_phy_read; - adapter->phy_write = netxen_niu_gbe_phy_write; + if (adapter->ahw.port_type == NETXEN_NIC_GBE) { + adapter->phy_read = nx_fw_cmd_query_phy; + adapter->phy_write = nx_fw_cmd_set_phy; + } } } diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c deleted file mode 100644 index 1392e89..0000000 --- a/drivers/net/netxen/netxen_nic_niu.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2003 - 2009 NetXen, Inc. - * All rights reserved. - * - * 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. - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE. - * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * - */ - -#include "netxen_nic.h" - -/* - * netxen_niu_gbe_phy_read - read a register from the GbE PHY via - * mii management interface. - * - * Note: The MII management interface goes through port 0. - * Individual phys are addressed as follows: - * @param phy [15:8] phy id - * @param reg [7:0] register number - * - * @returns 0 on success - * -1 on error - * - */ -int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, - __u32 * readval) -{ - long timeout = 0; - long result = 0; - long restore = 0; - long phy = adapter->physical_port; - __u32 address; - __u32 command; - __u32 status; - __u32 mac_cfg0; - - if (netxen_phy_lock(adapter) != 0) - return -1; - - /* - * MII mgmt all goes through port 0 MAC interface, - * so it cannot be in reset - */ - - mac_cfg0 = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); - if (netxen_gb_get_soft_reset(mac_cfg0)) { - __u32 temp; - temp = 0; - netxen_gb_tx_reset_pb(temp); - netxen_gb_rx_reset_pb(temp); - netxen_gb_tx_reset_mac(temp); - netxen_gb_rx_reset_mac(temp); - if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) - return -EIO; - restore = 1; - } - - address = 0; - netxen_gb_mii_mgmt_reg_addr(address, reg); - netxen_gb_mii_mgmt_phy_addr(address, phy); - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) - return -EIO; - command = 0; /* turn off any prior activity */ - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) - return -EIO; - /* send read command */ - netxen_gb_mii_mgmt_set_read_cycle(command); - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) - return -EIO; - - status = 0; - do { - status = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); - timeout++; - } while ((netxen_get_gb_mii_mgmt_busy(status) - || netxen_get_gb_mii_mgmt_notvalid(status)) - && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); - - if (timeout < NETXEN_NIU_PHY_WAITMAX) { - *readval = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_STATUS(0)); - result = 0; - } else - result = -1; - - if (restore) - if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) - return -EIO; - netxen_phy_unlock(adapter); - return result; -} - -/* - * netxen_niu_gbe_phy_write - write a register to the GbE PHY via - * mii management interface. - * - * Note: The MII management interface goes through port 0. - * Individual phys are addressed as follows: - * @param phy [15:8] phy id - * @param reg [7:0] register number - * - * @returns 0 on success - * -1 on error - * - */ -int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, - __u32 val) -{ - long timeout = 0; - long result = 0; - long restore = 0; - long phy = adapter->physical_port; - __u32 address; - __u32 command; - __u32 status; - __u32 mac_cfg0; - - /* - * MII mgmt all goes through port 0 MAC interface, so it - * cannot be in reset - */ - - mac_cfg0 = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); - if (netxen_gb_get_soft_reset(mac_cfg0)) { - __u32 temp; - temp = 0; - netxen_gb_tx_reset_pb(temp); - netxen_gb_rx_reset_pb(temp); - netxen_gb_tx_reset_mac(temp); - netxen_gb_rx_reset_mac(temp); - - if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) - return -EIO; - restore = 1; - } - - command = 0; /* turn off any prior activity */ - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) - return -EIO; - - address = 0; - netxen_gb_mii_mgmt_reg_addr(address, reg); - netxen_gb_mii_mgmt_phy_addr(address, phy); - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) - return -EIO; - - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CTRL(0), val)) - return -EIO; - - status = 0; - do { - status = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); - timeout++; - } while ((netxen_get_gb_mii_mgmt_busy(status)) - && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); - - if (timeout < NETXEN_NIU_PHY_WAITMAX) - result = 0; - else - result = -EIO; - - /* restore the state of port 0 MAC in case we tampered with it */ - if (restore) - if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) - return -EIO; - - return result; -} - -int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) -{ - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1+(0x10000*port), 0x1447); - NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_0+(0x10000*port), 0x5); - } - - return 0; -} - -/* Disable an XG interface */ -int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) -{ - __u32 mac_cfg; - u32 port = adapter->physical_port; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return 0; - - if (port > NETXEN_NIU_MAX_XG_PORTS) - return -EINVAL; - - mac_cfg = 0; - if (NXWR32(adapter, - NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), mac_cfg)) - return -EIO; - return 0; -} - -int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, - u32 mode) -{ - __u32 reg; - u32 port = adapter->physical_port; - - if (port > NETXEN_NIU_MAX_XG_PORTS) - return -EINVAL; - - reg = NXRD32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port)); - if (mode == NETXEN_NIU_PROMISC_MODE) - reg = (reg | 0x2000UL); - else - reg = (reg & ~0x2000UL); - - if (mode == NETXEN_NIU_ALLMULTI_MODE) - reg = (reg | 0x1000UL); - else - reg = (reg & ~0x1000UL); - - NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); - - return 0; -} - -int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr) -{ - u32 mac_hi, mac_lo; - u32 reg_hi, reg_lo; - - u8 phy = adapter->physical_port; - u8 phy_count = (adapter->ahw.port_type == NETXEN_NIC_XGBE) ? - NETXEN_NIU_MAX_XG_PORTS : NETXEN_NIU_MAX_GBE_PORTS; - - if (phy >= phy_count) - return -EINVAL; - - mac_lo = ((u32)addr[0] << 16) | ((u32)addr[1] << 24); - mac_hi = addr[2] | ((u32)addr[3] << 8) | - ((u32)addr[4] << 16) | ((u32)addr[5] << 24); - - if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { - reg_lo = NETXEN_NIU_XGE_STATION_ADDR_0_1 + (0x10000 * phy); - reg_hi = NETXEN_NIU_XGE_STATION_ADDR_0_HI + (0x10000 * phy); - } else { - reg_lo = NETXEN_NIU_GB_STATION_ADDR_1(phy); - reg_hi = NETXEN_NIU_GB_STATION_ADDR_0(phy); - } - - /* write twice to flush */ - if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) - return -EIO; - if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) - return -EIO; - - return 0; -} -- cgit v0.10.2 From fa3ce355c1bf1a83b843420228202fd6f8023ad3 Mon Sep 17 00:00:00 2001 From: Narender Kumar Date: Mon, 24 Aug 2009 19:23:28 +0000 Subject: netxen: bridged mode optimizations When the interface is put in bridged mode, destination mac addresses are unknown to firmware. So packets take a slow path (lower priority) in firmware reducing performance. Firmware can cache limited number of remote unicast mac addresses for certain interval, if "dynamic mac learning" mode is enabled. Driver needs to enable this "mac learning" mode in firmware. Currently this is done through net device class sysfs entry, possibly this can also be done upon netlink notifications to from bridge. Signed-off-by: Narender Kumar Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 63e2f79..449d351 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -964,6 +964,7 @@ typedef struct { #define NX_NIC_H2C_OPCODE_PROXY_STOP_DONE 20 #define NX_NIC_H2C_OPCODE_GET_LINKEVENT 21 #define NX_NIC_C2C_OPCODE 22 +#define NX_NIC_H2C_OPCODE_CONFIG_BRIDGING 23 #define NX_NIC_H2C_OPCODE_CONFIG_HW_LRO 24 #define NX_NIC_H2C_OPCODE_LAST 25 @@ -1085,6 +1086,7 @@ typedef struct { #define NETXEN_NIC_MSI_ENABLED 0x02 #define NETXEN_NIC_MSIX_ENABLED 0x04 #define NETXEN_NIC_LRO_ENABLED 0x08 +#define NETXEN_NIC_BRIDGE_ENABLED 0X10 #define NETXEN_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED)) @@ -1332,6 +1334,7 @@ void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup); int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu); int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu); int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable); +int netxen_config_bridged_mode(struct netxen_adapter *adapter, int enable); int netxen_send_lro_cleanup(struct netxen_adapter *adapter); int netxen_nic_set_mac(struct net_device *netdev, void *p); diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 1a8ad62..db510ce 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -794,6 +794,37 @@ int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable) return rv; } +int netxen_config_bridged_mode(struct netxen_adapter *adapter, int enable) +{ + nx_nic_req_t req; + u64 word; + int rv = 0; + + if (!!(adapter->flags & NETXEN_NIC_BRIDGE_ENABLED) == enable) + return rv; + + memset(&req, 0, sizeof(nx_nic_req_t)); + + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); + + word = NX_NIC_H2C_OPCODE_CONFIG_BRIDGING | + ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(enable); + + rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) { + printk(KERN_ERR "ERROR. Could not send " + "configure bridge mode request\n"); + } + + adapter->flags ^= NETXEN_NIC_BRIDGE_ENABLED; + + return rv; +} + + #define RSS_HASHTYPE_IP_TCP 0x3 int netxen_config_rss(struct netxen_adapter *adapter, int enable) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index bd4589f..fab51d1 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -71,6 +71,10 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void netxen_nic_poll_controller(struct net_device *netdev); #endif + +static void netxen_create_sysfs_entries(struct netxen_adapter *adapter); +static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter); + static irqreturn_t netxen_intr(int irq, void *data); static irqreturn_t netxen_msi_intr(int irq, void *data); static irqreturn_t netxen_msix_intr(int irq, void *data); @@ -94,8 +98,6 @@ static struct pci_device_id netxen_pci_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci, netxen_pci_tbl); -static void netxen_watchdog(unsigned long); - static uint32_t crb_cmd_producer[4] = { CRB_CMD_PRODUCER_OFFSET, CRB_CMD_PRODUCER_OFFSET_1, CRB_CMD_PRODUCER_OFFSET_2, CRB_CMD_PRODUCER_OFFSET_3 @@ -995,6 +997,8 @@ netxen_nic_attach(struct netxen_adapter *adapter) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_nic_init_coalesce_defaults(adapter); + netxen_create_sysfs_entries(adapter); + adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; return 0; @@ -1012,6 +1016,8 @@ netxen_nic_detach(struct netxen_adapter *adapter) if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) return; + netxen_remove_sysfs_entries(adapter); + netxen_free_hw_resources(adapter); netxen_release_rx_buffers(adapter); netxen_nic_free_irq(adapter); @@ -1959,6 +1965,80 @@ static void netxen_nic_poll_controller(struct net_device *netdev) } #endif +static ssize_t +netxen_store_bridged_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct net_device *net = to_net_dev(dev); + struct netxen_adapter *adapter = netdev_priv(net); + unsigned long new; + int ret = -EINVAL; + + if (!(adapter->capabilities & NX_FW_CAPABILITY_BDG)) + goto err_out; + + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + goto err_out; + + if (strict_strtoul(buf, 2, &new)) + goto err_out; + + if (!netxen_config_bridged_mode(adapter, !!new)) + ret = len; + +err_out: + return ret; +} + +static ssize_t +netxen_show_bridged_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *net = to_net_dev(dev); + struct netxen_adapter *adapter; + int bridged_mode = 0; + + adapter = netdev_priv(net); + + if (adapter->capabilities & NX_FW_CAPABILITY_BDG) + bridged_mode = !!(adapter->flags & NETXEN_NIC_BRIDGE_ENABLED); + + return sprintf(buf, "%d\n", bridged_mode); +} + +static struct device_attribute dev_attr_bridged_mode = { + .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)}, + .show = netxen_show_bridged_mode, + .store = netxen_store_bridged_mode, +}; + +static void +netxen_create_sysfs_entries(struct netxen_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct device *dev = &netdev->dev; + + if (adapter->capabilities & NX_FW_CAPABILITY_BDG) { + /* bridged_mode control */ + if (device_create_file(dev, &dev_attr_bridged_mode)) { + dev_warn(&netdev->dev, + "failed to create bridged_mode sysfs entry\n"); + } + } +} + +static void +netxen_remove_sysfs_entries(struct netxen_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct device *dev = &netdev->dev; + + if (adapter->capabilities & NX_FW_CAPABILITY_BDG) + device_remove_file(dev, &dev_attr_bridged_mode); +} + +static void netxen_watchdog(unsigned long); + #ifdef CONFIG_INET #define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops) -- cgit v0.10.2 From 46a72b35144769d1e9c23c3a9a26c1776ef7d8f6 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 25 Aug 2009 04:47:11 +0000 Subject: ixgbe: Fix isues while reporting 8259x backplane link capabilities Fix ethtool get_settings logic to report 10G & 1G advertised and supported link modes in all 8259x 10G backplane connection types except for 82598EB BX network connection type. Signed-off-by: Mallikarjuna R Chilakala Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index dd221bb..1444ec5 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -169,23 +169,20 @@ static int ixgbe_get_settings(struct net_device *netdev, } } else if (hw->phy.media_type == ixgbe_media_type_backplane) { /* Set as FIBRE until SERDES defined in kernel */ - switch (hw->device_id) { - case IXGBE_DEV_ID_82598: - ecmd->supported |= (SUPPORTED_1000baseT_Full | - SUPPORTED_FIBRE); - ecmd->advertising = (ADVERTISED_10000baseT_Full | - ADVERTISED_1000baseT_Full | - ADVERTISED_FIBRE); - ecmd->port = PORT_FIBRE; - break; - case IXGBE_DEV_ID_82598_BX: + if (hw->device_id == IXGBE_DEV_ID_82598_BX) { ecmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE); ecmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE); ecmd->port = PORT_FIBRE; ecmd->autoneg = AUTONEG_DISABLE; - break; + } else { + ecmd->supported |= (SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE); + ecmd->advertising = (ADVERTISED_10000baseT_Full | + ADVERTISED_1000baseT_Full | + ADVERTISED_FIBRE); + ecmd->port = PORT_FIBRE; } } else { ecmd->supported |= SUPPORTED_FIBRE; -- cgit v0.10.2 From 7b25cdbafd757b1255725d4ffb5b1081714b4256 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Tue, 25 Aug 2009 04:47:32 +0000 Subject: ixgbe: cleanup functions that should have been defined static We have some ~40 functions that were being called out with 'make namespacecheck'. This patch changes these functions to be static. Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 8f1f8ba..c983c89 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -424,55 +424,20 @@ extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc); extern s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, struct ixgbe_atr_input *input, u8 queue); -extern s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, - struct ixgbe_atr_input *input, - u16 soft_id, - u8 queue); -extern u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *input, u32 key); extern s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan_id); extern s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr); extern s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr); -extern s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, - u32 src_addr_1, u32 src_addr_2, - u32 src_addr_3, u32 src_addr_4); -extern s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, - u32 dst_addr_1, u32 dst_addr_2, - u32 dst_addr_3, u32 dst_addr_4); extern s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port); extern s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, u16 dst_port); extern s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte); -extern s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, - u8 vm_pool); extern s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type); -extern s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, - u16 *vlan_id); -extern s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, - u32 *src_addr); -extern s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, - u32 *dst_addr); -extern s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, - u32 *src_addr_1, u32 *src_addr_2, - u32 *src_addr_3, u32 *src_addr_4); -extern s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, - u32 *dst_addr_1, u32 *dst_addr_2, - u32 *dst_addr_3, u32 *dst_addr_4); -extern s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, - u16 *src_port); -extern s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, - u16 *dst_port); -extern s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, - u16 *flex_byte); -extern s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, - u8 *vm_pool); -extern s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, - u8 *l4type); #ifdef IXGBE_FCOE extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter); extern int ixgbe_fso(struct ixgbe_adapter *adapter, diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 1c227b0..916430f 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -59,7 +59,7 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, * increase the value to either 10ms to 250ms for capability version 1 config, * or 16ms to 55ms for version 2. **/ -void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw) +static void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw) { struct ixgbe_adapter *adapter = hw->back; u32 gcr = IXGBE_READ_REG(hw, IXGBE_GCR); @@ -143,7 +143,7 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) * not known. Perform the SFP init if necessary. * **/ -s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) +static s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; @@ -204,7 +204,7 @@ out: * Starts the hardware using the generic start_hw function. * Then set pcie completion timeout **/ -s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) +static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) { s32 ret_val = 0; diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 1984cab..364b6d2 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -38,22 +38,15 @@ #define IXGBE_82599_MC_TBL_SIZE 128 #define IXGBE_82599_VFT_TBL_SIZE 128 -s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, - ixgbe_link_speed *speed, - bool *autoneg); -enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw); -s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw); -s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, +static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw); +static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete); -s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw); -s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, - ixgbe_link_speed *speed, - bool *link_up, bool link_up_wait_to_complete); -s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete); +static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw); +static s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg); @@ -62,21 +55,9 @@ static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete); -s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw); -s32 ixgbe_set_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq); -s32 ixgbe_clear_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq); -s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, - u32 vind, bool vlan_on); -s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw); -s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw); -s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val); -s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val); -s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw); -s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw); -u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw); static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); -void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) +static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; if (hw->phy.multispeed_fiber) { @@ -93,7 +74,7 @@ void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) } } -s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) +static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) { s32 ret_val = 0; u16 list_offset, data_offset, data_value; @@ -143,7 +124,7 @@ setup_sfp_out: * Read PCIe configuration space, and get the MSI-X vector count from * the capabilities table. **/ -u32 ixgbe_get_pcie_msix_count_82599(struct ixgbe_hw *hw) +static u32 ixgbe_get_pcie_msix_count_82599(struct ixgbe_hw *hw) { struct ixgbe_adapter *adapter = hw->back; u16 msix_count; @@ -182,7 +163,7 @@ static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw) * not known. Perform the SFP init if necessary. * **/ -s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) +static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; @@ -225,9 +206,9 @@ s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) * * Determines the link capabilities by reading the AUTOC register. **/ -s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, - ixgbe_link_speed *speed, - bool *negotiation) +static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *negotiation) { s32 status = 0; u32 autoc = 0; @@ -344,7 +325,7 @@ static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw, * * Returns the media type (fiber, copper, backplane) **/ -enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) +static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) { enum ixgbe_media_type media_type; @@ -379,7 +360,7 @@ out: * Configures link settings based on values in the ixgbe_hw struct. * Restarts the link. Performs autonegotiation if needed. **/ -s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) +static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) { u32 autoc_reg; u32 links_reg; @@ -428,7 +409,7 @@ s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) * fails at 10G. * Performs autonegotiation if needed. **/ -s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw) +static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw) { s32 status = 0; ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_82599_AUTONEG; @@ -446,7 +427,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw) * * Set the link speed in the AUTOC register and restarts link. **/ -s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, +static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete) @@ -613,8 +594,10 @@ out: * * Reads the links register to determine if link is up and the current speed **/ -s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, - bool *link_up, bool link_up_wait_to_complete) +static s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *link_up, + bool link_up_wait_to_complete) { u32 links_reg; u32 i; @@ -665,9 +648,10 @@ s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, * * Set the link speed in the AUTOC register and restarts link. **/ -s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, - bool autoneg_wait_to_complete) +static s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete) { s32 status = 0; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); @@ -818,7 +802,7 @@ static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw, * and clears all interrupts, perform a PHY reset, and perform a link (MAC) * reset. **/ -s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) +static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) { s32 status = 0; u32 ctrl, ctrl_ext; @@ -943,7 +927,7 @@ reset_hw_out: * @rar: receive address register index to disassociate * @vmdq: VMDq pool index to remove from the rar **/ -s32 ixgbe_clear_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +static s32 ixgbe_clear_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq) { u32 mpsar_lo, mpsar_hi; u32 rar_entries = hw->mac.num_rar_entries; @@ -989,7 +973,7 @@ done: * @rar: receive address register index to associate with a VMDq index * @vmdq: VMDq pool index **/ -s32 ixgbe_set_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +static s32 ixgbe_set_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq) { u32 mpsar; u32 rar_entries = hw->mac.num_rar_entries; @@ -1019,8 +1003,8 @@ s32 ixgbe_set_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq) * * Turn on/off specified VLAN in the VLAN filter table. **/ -s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind, - bool vlan_on) +static s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on) { u32 regindex; u32 bitindex; @@ -1133,7 +1117,7 @@ out: * * Clears the VLAN filer table, and the VMDq index associated with the filter **/ -s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw) +static s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw) { u32 offset; @@ -1153,7 +1137,7 @@ s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw) * ixgbe_init_uta_tables_82599 - Initialize the Unicast Table Array * @hw: pointer to hardware structure **/ -s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw) +static s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw) { int i; hw_dbg(hw, " Clearing UTA\n"); @@ -1430,7 +1414,8 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) * @stream: input bitstream to compute the hash on * @key: 32-bit hash key **/ -u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input, u32 key) +static u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input, + u32 key) { /* * The algorithm is as follows: @@ -1602,8 +1587,8 @@ s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr) * @src_addr_4: the fourth 4 bytes of the IP address to load **/ s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, - u32 src_addr_1, u32 src_addr_2, - u32 src_addr_3, u32 src_addr_4) + u32 src_addr_1, u32 src_addr_2, + u32 src_addr_3, u32 src_addr_4) { input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET] = src_addr_4 & 0xff; input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] = @@ -1645,8 +1630,8 @@ s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, * @dst_addr_4: the fourth 4 bytes of the IP address to load **/ s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, - u32 dst_addr_1, u32 dst_addr_2, - u32 dst_addr_3, u32 dst_addr_4) + u32 dst_addr_1, u32 dst_addr_2, + u32 dst_addr_3, u32 dst_addr_4) { input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET] = dst_addr_4 & 0xff; input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] = @@ -1723,7 +1708,8 @@ s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte) * @input: input stream to modify * @vm_pool: the Virtual Machine pool to load **/ -s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, u8 vm_pool) +s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, + u8 vm_pool) { input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET] = vm_pool; @@ -1747,7 +1733,8 @@ s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type) * @input: input stream to search * @vlan: the VLAN id to load **/ -s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan) +static s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, + u16 *vlan) { *vlan = input->byte_stream[IXGBE_ATR_VLAN_OFFSET]; *vlan |= input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] << 8; @@ -1760,7 +1747,8 @@ s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan) * @input: input stream to search * @src_addr: the IP address to load **/ -s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, u32 *src_addr) +static s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, + u32 *src_addr) { *src_addr = input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET]; *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] << 8; @@ -1775,7 +1763,8 @@ s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, u32 *src_addr) * @input: input stream to search * @dst_addr: the IP address to load **/ -s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 *dst_addr) +static s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, + u32 *dst_addr) { *dst_addr = input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET]; *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] << 8; @@ -1793,9 +1782,9 @@ s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 *dst_addr) * @src_addr_3: the third 4 bytes of the IP address to load * @src_addr_4: the fourth 4 bytes of the IP address to load **/ -s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, - u32 *src_addr_1, u32 *src_addr_2, - u32 *src_addr_3, u32 *src_addr_4) +static s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 *src_addr_1, u32 *src_addr_2, + u32 *src_addr_3, u32 *src_addr_4) { *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12]; *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] << 8; @@ -1829,8 +1818,8 @@ s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, * @dst_addr_4: the fourth 4 bytes of the IP address to load **/ s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, - u32 *dst_addr_1, u32 *dst_addr_2, - u32 *dst_addr_3, u32 *dst_addr_4) + u32 *dst_addr_1, u32 *dst_addr_2, + u32 *dst_addr_3, u32 *dst_addr_4) { *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12]; *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] << 8; @@ -1865,7 +1854,8 @@ s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, * endianness when retrieving the data. This can be confusing since the * internal hash engine expects it to be big-endian. **/ -s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, u16 *src_port) +static s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, + u16 *src_port) { *src_port = input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] << 8; *src_port |= input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1]; @@ -1883,7 +1873,8 @@ s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, u16 *src_port) * endianness when retrieving the data. This can be confusing since the * internal hash engine expects it to be big-endian. **/ -s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, u16 *dst_port) +static s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, + u16 *dst_port) { *dst_port = input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] << 8; *dst_port |= input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1]; @@ -1896,7 +1887,8 @@ s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, u16 *dst_port) * @input: input stream to modify * @flex_bytes: the flexible bytes to load **/ -s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, u16 *flex_byte) +static s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, + u16 *flex_byte) { *flex_byte = input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET]; *flex_byte |= input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] << 8; @@ -1909,7 +1901,8 @@ s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, u16 *flex_byte) * @input: input stream to modify * @vm_pool: the Virtual Machine pool to load **/ -s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, u8 *vm_pool) +s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, + u8 *vm_pool) { *vm_pool = input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET]; @@ -1921,7 +1914,8 @@ s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, u8 *vm_pool) * @input: input stream to modify * @l4type: the layer 4 type value to load **/ -s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, u8 *l4type) +static s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, + u8 *l4type) { *l4type = input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET]; @@ -2002,9 +1996,9 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, * hardware writes must be protected from one another. **/ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, - struct ixgbe_atr_input *input, - u16 soft_id, - u8 queue) + struct ixgbe_atr_input *input, + u16 soft_id, + u8 queue) { u32 fdircmd = 0; u32 fdirhash; @@ -2097,7 +2091,7 @@ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, * * Performs read operation to Omer analog register specified. **/ -s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val) +static s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val) { u32 core_ctl; @@ -2119,7 +2113,7 @@ s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val) * * Performs write operation to Omer analog register specified. **/ -s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) +static s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) { u32 core_ctl; @@ -2139,7 +2133,7 @@ s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) * Then performs device-specific: * Clears the rate limiter registers. **/ -s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) +static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) { u32 q_num; s32 ret_val; @@ -2168,7 +2162,7 @@ s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) * * Determines the physical layer module found on the current adapter. **/ -s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) +static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) { s32 status = IXGBE_ERR_PHY_ADDR_INVALID; status = ixgbe_identify_phy_generic(hw); @@ -2183,7 +2177,7 @@ s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) * * Determines physical layer capabilities of the current configuration. **/ -u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) +static u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) { u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); @@ -2290,7 +2284,7 @@ out: * * Enables the Rx DMA unit for 82599 **/ -s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) +static s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) { #define IXGBE_MAX_SECRX_POLL 30 int i; @@ -2335,7 +2329,7 @@ s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) * This function will read the EEPROM location for the device capabilities, * and return the word through device_caps. **/ -s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) +static s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) { hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); @@ -2351,8 +2345,8 @@ s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) * pointer, and returns the value at that location. This is used in both * get and set mac_addr routines. **/ -s32 ixgbe_get_san_mac_addr_offset_82599(struct ixgbe_hw *hw, - u16 *san_mac_offset) +static s32 ixgbe_get_san_mac_addr_offset_82599(struct ixgbe_hw *hw, + u16 *san_mac_offset) { /* * First read the EEPROM pointer to see if the MAC addresses are @@ -2373,7 +2367,7 @@ s32 ixgbe_get_san_mac_addr_offset_82599(struct ixgbe_hw *hw, * set_lan_id() is called by identify_sfp(), but this cannot be relied * upon for non-SFP connections, so we must call it here. **/ -s32 ixgbe_get_san_mac_addr_82599(struct ixgbe_hw *hw, u8 *san_mac_addr) +static s32 ixgbe_get_san_mac_addr_82599(struct ixgbe_hw *hw, u8 *san_mac_addr) { u16 san_mac_data, san_mac_offset; u8 i; diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 96a1859..6621e17 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -53,6 +53,7 @@ static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index); static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index); static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr); static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq); +static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); /** * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx @@ -1815,7 +1816,7 @@ out: * * Called at init time to set up flow control. **/ -s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) +static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) { s32 ret_val = 0; u32 reg; diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index 0d34d4d..27f3214 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -64,7 +64,6 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval); -s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packtetbuf_num); s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index d69d277..3f17706 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3615,7 +3615,7 @@ static void ixgbe_free_q_vectors(struct ixgbe_adapter *adapter) } } -void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) +static void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) { if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; -- cgit v0.10.2 From cd1da503847a28775f60b959cb7b0123cee2a1a3 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 25 Aug 2009 04:47:50 +0000 Subject: igb/ixgbe: add IPV6_CSUM support to vlan_features We were already exporting TSO6 to the vlan, but we weren't exporting the checksum support for IPV6 which was causing warning messages to be displayed when doing IPv6 TSO over a vlan. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index fb32735..cef4289 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1380,6 +1380,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; netdev->vlan_features |= NETIF_F_IP_CSUM; + netdev->vlan_features |= NETIF_F_IPV6_CSUM; netdev->vlan_features |= NETIF_F_SG; if (pci_using_dac) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 3f17706..0bea096 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5575,6 +5575,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; netdev->vlan_features |= NETIF_F_IP_CSUM; + netdev->vlan_features |= NETIF_F_IPV6_CSUM; netdev->vlan_features |= NETIF_F_SG; if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) -- cgit v0.10.2 From c46b59b241ec52ffaf92ece8d8ab726621d580fb Mon Sep 17 00:00:00 2001 From: "Graham, David" Date: Tue, 25 Aug 2009 04:43:17 +0000 Subject: e1000: Remove unused function e1000_mta_set. Remove function e1000_mta_set, as it is no longer called Signed-off-by: Dave Graham Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 1e5ae11..cda6b39 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -5759,52 +5759,6 @@ u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) } /****************************************************************************** - * Sets the bit in the multicast table corresponding to the hash value. - * - * hw - Struct containing variables accessed by shared code - * hash_value - Multicast address hash value - *****************************************************************************/ -void e1000_mta_set(struct e1000_hw *hw, u32 hash_value) -{ - u32 hash_bit, hash_reg; - u32 mta; - u32 temp; - - /* The MTA is a register array of 128 32-bit registers. - * It is treated like an array of 4096 bits. We want to set - * bit BitArray[hash_value]. So we figure out what register - * the bit is in, read it, OR in the new bit, then write - * back the new value. The register is determined by the - * upper 7 bits of the hash value and the bit within that - * register are determined by the lower 5 bits of the value. - */ - hash_reg = (hash_value >> 5) & 0x7F; - if (hw->mac_type == e1000_ich8lan) - hash_reg &= 0x1F; - - hash_bit = hash_value & 0x1F; - - mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg); - - mta |= (1 << hash_bit); - - /* If we are on an 82544 and we are trying to write an odd offset - * in the MTA, save off the previous entry before writing and - * restore the old value after writing. - */ - if ((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) { - temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1)); - E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta); - E1000_WRITE_FLUSH(); - E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp); - E1000_WRITE_FLUSH(); - } else { - E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta); - E1000_WRITE_FLUSH(); - } -} - -/****************************************************************************** * Puts an ethernet address into a receive address register. * * hw - Struct containing variables accessed by shared code -- cgit v0.10.2 From 521e6b90dd3f0392062845d7ef13e6e41bb99d8a Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:06:01 +0000 Subject: tg3: Fix 57780 asic rev PCIe link receiver errors This patch fixes some PCIe link receiver errors by decreasing the internal electrical idle timeout. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 46a3f86..e8def28 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6719,6 +6719,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) val |= PCIE_PWR_MGMT_EXT_ASPM_TMR_EN | PCIE_PWR_MGMT_L1_THRESH_4MS; tw32(PCIE_PWR_MGMT_THRESH, val); + + val = tr32(TG3_PCIE_EIDLE_DELAY) & ~TG3_PCIE_EIDLE_DELAY_MASK; + tw32(TG3_PCIE_EIDLE_DELAY, val | TG3_PCIE_EIDLE_DELAY_13_CLKS); + + tw32(TG3_CORR_ERR_STAT, TG3_CORR_ERR_STAT_CLEAR); } /* This works around an issue with Athlon chipsets on diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index b3347c4..c613cbb 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -214,9 +214,11 @@ #define DUAL_MAC_CTRL_ID 0x00000004 #define TG3PCI_PRODID_ASICREV 0x000000bc #define PROD_ID_ASIC_REV_MASK 0x0fffffff -/* 0xc0 --> 0x100 unused */ +/* 0xc0 --> 0x110 unused */ -/* 0x100 --> 0x200 unused */ +#define TG3_CORR_ERR_STAT 0x00000110 +#define TG3_CORR_ERR_STAT_CLEAR 0xffffffff +/* 0x114 --> 0x200 unused */ /* Mailbox registers */ #define MAILBOX_INTERRUPT_0 0x00000200 /* 64-bit */ @@ -1696,11 +1698,18 @@ #define PCIE_TRANSACTION_CFG 0x00007c04 #define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000 #define PCIE_TRANS_CFG_LOM 0x00000020 +/* 0x7c08 --> 0x7d28 unused */ #define PCIE_PWR_MGMT_THRESH 0x00007d28 #define PCIE_PWR_MGMT_L1_THRESH_MSK 0x0000ff00 #define PCIE_PWR_MGMT_L1_THRESH_4MS 0x0000ff00 #define PCIE_PWR_MGMT_EXT_ASPM_TMR_EN 0x01000000 +/* 0x7d2c --> 0x7e70 unused */ + +#define TG3_PCIE_EIDLE_DELAY 0x00007e70 +#define TG3_PCIE_EIDLE_DELAY_MASK 0x0000001f +#define TG3_PCIE_EIDLE_DELAY_13_CLKS 0x0000000c +/* 0x7e74 --> 0x8000 unused */ /* OTP bit definitions */ -- cgit v0.10.2 From 255ca311b650caece3ec4f78b88ef298664d561f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:07:27 +0000 Subject: tg3: Prevent tx BD corruption This patch prevents a tx BD corruption bug by preventing the device from powering down the PLL from L1 if the link speed is 10Mbps or 100Mbps. The same bits are also used to prevent a system hang during chip reset resulting from a complicated set of events that ultimately leads to PCIe block register corruption. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e8def28..595ddf2 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3167,6 +3167,15 @@ relink: pci_write_config_word(tp->pdev, tp->pcie_cap + PCI_EXP_LNKCTL, newlnkctl); + } else if (tp->tg3_flags3 & TG3_FLG3_TOGGLE_10_100_L1PLLPD) { + u32 newreg, oldreg = tr32(TG3_PCIE_LNKCTL); + if (tp->link_config.active_speed == SPEED_100 || + tp->link_config.active_speed == SPEED_10) + newreg = oldreg & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN; + else + newreg = oldreg | TG3_PCIE_LNKCTL_L1_PLL_PD_EN; + if (newreg != oldreg) + tw32(TG3_PCIE_LNKCTL, newreg); } if (current_link_up != netif_carrier_ok(tp->dev)) { @@ -6160,6 +6169,11 @@ static int tg3_chip_reset(struct tg3 *tp) smp_mb(); synchronize_irq(tp->pdev->irq); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) { + val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN; + tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS); + } + /* do the reset */ val = GRC_MISC_CFG_CORECLK_RESET; @@ -6726,6 +6740,15 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(TG3_CORR_ERR_STAT, TG3_CORR_ERR_STAT_CLEAR); } + if (tp->tg3_flags3 & TG3_FLG3_TOGGLE_10_100_L1PLLPD) { + val = tr32(TG3_PCIE_LNKCTL); + if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) + val |= TG3_PCIE_LNKCTL_L1_PLL_PD_DIS; + else + val &= ~TG3_PCIE_LNKCTL_L1_PLL_PD_DIS; + tw32(TG3_PCIE_LNKCTL, val); + } + /* This works around an issue with Athlon chipsets on * B3 tigon3 silicon. This bit has no effect on any * other revision. But do not set this on PCI Express @@ -12274,6 +12297,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB; + if ((tp->pci_chip_rev_id == CHIPREV_ID_57780_A1 && + tr32(RCVLPC_STATS_ENABLE) & RCVLPC_STATSENAB_ASF_FIX) || + tp->pci_chip_rev_id == CHIPREV_ID_57780_A0) + tp->tg3_flags3 |= TG3_FLG3_TOGGLE_10_100_L1PLLPD; + err = tg3_mdio_init(tp); if (err) return err; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index c613cbb..bb8591e 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -866,6 +866,7 @@ #define RCVLPC_STATSCTRL_ENABLE 0x00000001 #define RCVLPC_STATSCTRL_FASTUPD 0x00000002 #define RCVLPC_STATS_ENABLE 0x00002018 +#define RCVLPC_STATSENAB_ASF_FIX 0x00000002 #define RCVLPC_STATSENAB_DACK_FIX 0x00040000 #define RCVLPC_STATSENAB_LNGBRST_RFIX 0x00400000 #define RCVLPC_STATS_INCMASK 0x0000201c @@ -1704,7 +1705,12 @@ #define PCIE_PWR_MGMT_L1_THRESH_MSK 0x0000ff00 #define PCIE_PWR_MGMT_L1_THRESH_4MS 0x0000ff00 #define PCIE_PWR_MGMT_EXT_ASPM_TMR_EN 0x01000000 -/* 0x7d2c --> 0x7e70 unused */ +/* 0x7d2c --> 0x7d54 unused */ + +#define TG3_PCIE_LNKCTL 0x00007d54 +#define TG3_PCIE_LNKCTL_L1_PLL_PD_EN 0x00000008 +#define TG3_PCIE_LNKCTL_L1_PLL_PD_DIS 0x00000080 +/* 0x7d58 --> 0x7e70 unused */ #define TG3_PCIE_EIDLE_DELAY 0x00007e70 #define TG3_PCIE_EIDLE_DELAY_MASK 0x0000001f @@ -2650,6 +2656,7 @@ struct tg3 { #define TG3_FLG3_PHY_ENABLE_APD 0x00001000 #define TG3_FLG3_5755_PLUS 0x00002000 #define TG3_FLG3_NO_NVRAM 0x00004000 +#define TG3_FLG3_TOGGLE_10_100_L1PLLPD 0x00008000 struct timer_list timer; u16 timer_counter; -- cgit v0.10.2 From 29ea095fb727ac48228ff2d1af484c27bf1dcbd4 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:07:54 +0000 Subject: tg3: Fix TSO test against wrong flags var Julia Lawall discovered that the TG3_FLG2_TSO_CAPABLE flag was being compared against the wrong flags device member. This patch implements the fix. Signed-off-by: Julia Lawall Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 595ddf2..ca3052d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7192,7 +7192,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { - if ((tp->tg3_flags & TG3_FLG2_TSO_CAPABLE) && + if ((tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) { /* nothing */ -- cgit v0.10.2 From e7126997342560533317d8467e8516119ebcbd21 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:08:16 +0000 Subject: tg3: Preserve PCIe MPS setting for new devs Most older tg3 devices only supported a PCIe maximum payload size of 128 bytes. More recent devices bump this limit up to 256 bytes though. This patch modifies the code so that the MPS limit is only enforced on those devices that only allow the 128 byte setting. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ca3052d..356b5d0 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6226,6 +6226,8 @@ static int tg3_chip_reset(struct tg3 *tp) udelay(120); if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pcie_cap) { + u16 val16; + if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) { int i; u32 cfg_val; @@ -6239,12 +6241,22 @@ static int tg3_chip_reset(struct tg3 *tp) cfg_val | (1 << 15)); } - /* Set PCIE max payload size to 128 bytes and - * clear the "no snoop" and "relaxed ordering" bits. + /* Clear the "no snoop" and "relaxed ordering" bits. */ + pci_read_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_DEVCTL, + &val16); + val16 &= ~(PCI_EXP_DEVCTL_RELAX_EN | + PCI_EXP_DEVCTL_NOSNOOP_EN); + /* + * Older PCIe devices only support the 128 byte + * MPS setting. Enforce the restriction. */ + if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)) + val16 &= ~PCI_EXP_DEVCTL_PAYLOAD; pci_write_config_word(tp->pdev, tp->pcie_cap + PCI_EXP_DEVCTL, - 0); + val16); pcie_set_readrq(tp->pdev, 4096); -- cgit v0.10.2 From 5e7ccf2003e6a9c35b5aa24953ba5009a1a8b653 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:08:42 +0000 Subject: tg3: Add 57788, remove 57720 This patch adds support for the 57788 and removes support for the 57720 which was never released. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 356b5d0..9ae3320 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -223,7 +223,7 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57760)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790)}, - {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57720)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57788)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -11525,6 +11525,9 @@ out_not_found: else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 && tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790) strcpy(tp->board_part_number, "BCM57790"); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 && + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57788) + strcpy(tp->board_part_number, "BCM57788"); else strcpy(tp->board_part_number, "none"); } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index bb8591e..636008c 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -43,7 +43,7 @@ #define TG3PCI_DEVICE_TIGON3_57780 0x1692 #define TG3PCI_DEVICE_TIGON3_57760 0x1690 #define TG3PCI_DEVICE_TIGON3_57790 0x1694 -#define TG3PCI_DEVICE_TIGON3_57720 0x168c +#define TG3PCI_DEVICE_TIGON3_57788 0x1691 /* 0x04 --> 0x64 unused */ #define TG3PCI_MSI_DATA 0x00000064 /* 0x66 --> 0x68 unused */ -- cgit v0.10.2 From bb85fbb6a98d8edab81599913559c7ff0a963984 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:09:07 +0000 Subject: tg3: Tune 5785 clock switching This patch tunes the timeouts the CPMU uses to decide when to switch from the clocks output by the PHY to internal clock sources. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9ae3320..41e0d40 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -917,7 +917,9 @@ static void tg3_mdio_config_5785(struct tg3 *tp) tw32(MAC_PHYCFG2, val); val = tr32(MAC_PHYCFG1); - val &= ~MAC_PHYCFG1_RGMII_INT; + val &= ~(MAC_PHYCFG1_RGMII_INT | + MAC_PHYCFG1_RXCLK_TO_MASK | MAC_PHYCFG1_TXCLK_TO_MASK); + val |= MAC_PHYCFG1_RXCLK_TIMEOUT | MAC_PHYCFG1_TXCLK_TIMEOUT; tw32(MAC_PHYCFG1, val); return; @@ -933,15 +935,18 @@ static void tg3_mdio_config_5785(struct tg3 *tp) tw32(MAC_PHYCFG2, val); - val = tr32(MAC_PHYCFG1) & ~(MAC_PHYCFG1_RGMII_EXT_RX_DEC | - MAC_PHYCFG1_RGMII_SND_STAT_EN); - if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) { + val = tr32(MAC_PHYCFG1); + val &= ~(MAC_PHYCFG1_RXCLK_TO_MASK | MAC_PHYCFG1_TXCLK_TO_MASK | + MAC_PHYCFG1_RGMII_EXT_RX_DEC | MAC_PHYCFG1_RGMII_SND_STAT_EN); + if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) { if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC; if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) val |= MAC_PHYCFG1_RGMII_SND_STAT_EN; } - tw32(MAC_PHYCFG1, val | MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV); + val |= MAC_PHYCFG1_RXCLK_TIMEOUT | MAC_PHYCFG1_TXCLK_TIMEOUT | + MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV; + tw32(MAC_PHYCFG1, val); val = tr32(MAC_EXT_RGMII_MODE); val &= ~(MAC_RGMII_MODE_RX_INT_B | diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 636008c..d096e10 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -524,6 +524,10 @@ /* 0x598 --> 0x5a0 unused */ #define MAC_PHYCFG1 0x000005a0 #define MAC_PHYCFG1_RGMII_INT 0x00000001 +#define MAC_PHYCFG1_RXCLK_TO_MASK 0x00001ff0 +#define MAC_PHYCFG1_RXCLK_TIMEOUT 0x00001000 +#define MAC_PHYCFG1_TXCLK_TO_MASK 0x01ff0000 +#define MAC_PHYCFG1_TXCLK_TIMEOUT 0x01000000 #define MAC_PHYCFG1_RGMII_EXT_RX_DEC 0x02000000 #define MAC_PHYCFG1_RGMII_SND_STAT_EN 0x04000000 #define MAC_PHYCFG1_TXC_DRV 0x20000000 -- cgit v0.10.2 From 535ef6e1124d445efbcc13b7126561dc544b0b64 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:09:36 +0000 Subject: tg3: Create MII_TG3_FET namespace Broadcom's phys come in two distinctly different register layouts. For the lack of an official term to distinguish between the two formats, we can loosely categorize them by their fast ethernet or gigabit ethernet transceiver description. This patch creates the (driver-internal) Fast Ethernet Transceiver (FET) namespace and converts the 5906 EPHY definitions over. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 41e0d40..800f980 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1514,17 +1514,19 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { u32 ephy; - if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &ephy)) { - tg3_writephy(tp, MII_TG3_EPHY_TEST, - ephy | MII_TG3_EPHY_SHADOW_EN); - if (!tg3_readphy(tp, MII_TG3_EPHYTST_MISCCTRL, &phy)) { + if (!tg3_readphy(tp, MII_TG3_FET_TEST, &ephy)) { + u32 reg = MII_TG3_FET_SHDW_MISCCTRL; + + tg3_writephy(tp, MII_TG3_FET_TEST, + ephy | MII_TG3_FET_SHADOW_EN); + if (!tg3_readphy(tp, reg, &phy)) { if (enable) - phy |= MII_TG3_EPHYTST_MISCCTRL_MDIX; + phy |= MII_TG3_FET_SHDW_MISCCTRL_MDIX; else - phy &= ~MII_TG3_EPHYTST_MISCCTRL_MDIX; - tg3_writephy(tp, MII_TG3_EPHYTST_MISCCTRL, phy); + phy &= ~MII_TG3_FET_SHDW_MISCCTRL_MDIX; + tg3_writephy(tp, reg, phy); } - tg3_writephy(tp, MII_TG3_EPHY_TEST, ephy); + tg3_writephy(tp, MII_TG3_FET_TEST, ephy); } } else { phy = MII_TG3_AUXCTL_MISC_RDSEL_MISC | @@ -1915,7 +1917,7 @@ out: if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { /* adjust output voltage */ - tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x12); + tg3_writephy(tp, MII_TG3_FET_PTEST, 0x12); } tg3_phy_toggle_automdix(tp, 1); @@ -9747,14 +9749,16 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { u32 phytest; - if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &phytest)) { - u32 phy; + if (!tg3_readphy(tp, MII_TG3_FET_TEST, &phytest)) { + u32 phy, reg = MII_TG3_FET_SHDW_AUXSTAT2; - tg3_writephy(tp, MII_TG3_EPHY_TEST, - phytest | MII_TG3_EPHY_SHADOW_EN); - if (!tg3_readphy(tp, 0x1b, &phy)) - tg3_writephy(tp, 0x1b, phy & ~0x20); - tg3_writephy(tp, MII_TG3_EPHY_TEST, phytest); + tg3_writephy(tp, MII_TG3_FET_TEST, + phytest | MII_TG3_FET_SHADOW_EN); + if (!tg3_readphy(tp, reg, &phy)) { + phy &= ~MII_TG3_FET_SHDW_AUXSTAT2_APD; + tg3_writephy(tp, reg, phy); + } + tg3_writephy(tp, MII_TG3_FET_TEST, phytest); } val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100; } else @@ -9767,7 +9771,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) mac_mode = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x1800); + tg3_writephy(tp, MII_TG3_FET_PTEST, 0x1800); mac_mode |= MAC_MODE_PORT_MODE_MII; } else mac_mode |= MAC_MODE_PORT_MODE_GMII; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d096e10..b8339c9 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1909,7 +1909,6 @@ #define MII_TG3_DSP_RW_PORT 0x15 /* DSP coefficient read/write port */ -#define MII_TG3_EPHY_PTEST 0x17 /* 5906 PHY register */ #define MII_TG3_DSP_ADDRESS 0x17 /* DSP address register */ #define MII_TG3_DSP_TAP1 0x0001 @@ -1976,17 +1975,23 @@ #define MII_TG3_MISC_SHDW_SCR5_LPED 0x0010 #define MII_TG3_MISC_SHDW_SCR5_SEL 0x1400 - -#define MII_TG3_EPHY_TEST 0x1f /* 5906 PHY register */ -#define MII_TG3_EPHY_SHADOW_EN 0x80 - -#define MII_TG3_EPHYTST_MISCCTRL 0x10 /* 5906 EPHY misc ctrl shadow register */ -#define MII_TG3_EPHYTST_MISCCTRL_MDIX 0x4000 - #define MII_TG3_TEST1 0x1e #define MII_TG3_TEST1_TRIM_EN 0x0010 #define MII_TG3_TEST1_CRC_EN 0x8000 + +/* Fast Ethernet Tranceiver definitions */ +#define MII_TG3_FET_PTEST 0x17 +#define MII_TG3_FET_TEST 0x1f +#define MII_TG3_FET_SHADOW_EN 0x0080 + +#define MII_TG3_FET_SHDW_MISCCTRL 0x10 +#define MII_TG3_FET_SHDW_MISCCTRL_MDIX 0x4000 + +#define MII_TG3_FET_SHDW_AUXSTAT2 0x1b +#define MII_TG3_FET_SHDW_AUXSTAT2_APD 0x0020 + + /* APE registers. Accessible through BAR1 */ #define TG3_APE_EVENT 0x000c #define APE_EVENT_1 0x00000001 -- cgit v0.10.2 From 7f97a4bd47291e4ec9b9eaf63d7275ddfb498cb3 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:10:03 +0000 Subject: tg3: Convert code to use PHY_IS_FET This patch converts the code to use the PHY_IS_FET flag rather than the ASIC revision to decide whether or not to use FET paths. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 800f980..2808152 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -784,7 +784,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) unsigned int loops; int ret; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 && + if ((tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) && (reg == MII_TG3_CTRL || reg == MII_TG3_AUX_CTRL)) return 0; @@ -1069,6 +1069,7 @@ static int tg3_mdio_init(struct tg3 *tp) case TG3_PHY_ID_RTL8201E: case TG3_PHY_ID_BCMAC131: phydev->interface = PHY_INTERFACE_MODE_MII; + tp->tg3_flags3 |= TG3_FLG3_PHY_IS_FET; break; } @@ -1474,13 +1475,37 @@ static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val); } +static void tg3_phy_fet_toggle_apd(struct tg3 *tp, bool enable) +{ + u32 phytest; + + if (!tg3_readphy(tp, MII_TG3_FET_TEST, &phytest)) { + u32 phy; + + tg3_writephy(tp, MII_TG3_FET_TEST, + phytest | MII_TG3_FET_SHADOW_EN); + if (!tg3_readphy(tp, MII_TG3_FET_SHDW_AUXSTAT2, &phy)) { + if (enable) + phy |= MII_TG3_FET_SHDW_AUXSTAT2_APD; + else + phy &= ~MII_TG3_FET_SHDW_AUXSTAT2_APD; + tg3_writephy(tp, MII_TG3_FET_SHDW_AUXSTAT2, phy); + } + tg3_writephy(tp, MII_TG3_FET_TEST, phytest); + } +} + static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable) { u32 reg; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + return; + + if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { + tg3_phy_fet_toggle_apd(tp, enable); return; + } reg = MII_TG3_MISC_SHDW_WREN | MII_TG3_MISC_SHDW_SCR5_SEL | @@ -1511,7 +1536,7 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) return; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { u32 ephy; if (!tg3_readphy(tp, MII_TG3_FET_TEST, &ephy)) { @@ -2662,7 +2687,7 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 break; default: - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { *speed = (val & MII_TG3_AUX_STAT_100) ? SPEED_100 : SPEED_10; *duplex = (val & MII_TG3_AUX_STAT_FULL) ? DUPLEX_FULL : @@ -2997,7 +3022,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG); - else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) + else if (!(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET)) tg3_writephy(tp, MII_TG3_IMASK, ~0); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || @@ -3107,7 +3132,9 @@ relink: tp->mac_mode |= MAC_MODE_PORT_MODE_MII; else tp->mac_mode |= MAC_MODE_PORT_MODE_GMII; - } else + } else if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) + tp->mac_mode |= MAC_MODE_PORT_MODE_MII; + else tp->mac_mode |= MAC_MODE_PORT_MODE_GMII; tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX; @@ -7349,7 +7376,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return err; if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) { + !(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET)) { u32 tmp; /* Clear CRC stats. */ @@ -9746,20 +9773,8 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) } else if (loopback_mode == TG3_PHY_LOOPBACK) { u32 val; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - u32 phytest; - - if (!tg3_readphy(tp, MII_TG3_FET_TEST, &phytest)) { - u32 phy, reg = MII_TG3_FET_SHDW_AUXSTAT2; - - tg3_writephy(tp, MII_TG3_FET_TEST, - phytest | MII_TG3_FET_SHADOW_EN); - if (!tg3_readphy(tp, reg, &phy)) { - phy &= ~MII_TG3_FET_SHDW_AUXSTAT2_APD; - tg3_writephy(tp, reg, phy); - } - tg3_writephy(tp, MII_TG3_FET_TEST, phytest); - } + if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { + tg3_phy_fet_toggle_apd(tp, false); val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100; } else val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED1000; @@ -9770,8 +9785,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) udelay(40); mac_mode = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - tg3_writephy(tp, MII_TG3_FET_PTEST, 0x1800); + if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + tg3_writephy(tp, MII_TG3_FET_PTEST, 0x1800); mac_mode |= MAC_MODE_PORT_MODE_MII; } else mac_mode |= MAC_MODE_PORT_MODE_GMII; @@ -12268,12 +12284,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags |= TG3_FLAG_WOL_SPEED_100MB; } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + tp->tg3_flags3 |= TG3_FLG3_PHY_IS_FET; + /* A few boards don't want Ethernet@WireSpeed phy feature */ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) || ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) && (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) && (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) || + (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) || (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED; @@ -12284,7 +12303,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG; if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 && + !(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || @@ -12409,7 +12428,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F || tp->pdev->device == PCI_DEVICE_ID_TIGON3_5787F)) || tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET)) tp->tg3_flags |= TG3_FLAG_10_100_ONLY; err = tg3_phy_probe(tp); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index b8339c9..60b12ab 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2666,6 +2666,7 @@ struct tg3 { #define TG3_FLG3_5755_PLUS 0x00002000 #define TG3_FLG3_NO_NVRAM 0x00004000 #define TG3_FLG3_TOGGLE_10_100_L1PLLPD 0x00008000 +#define TG3_FLG3_PHY_IS_FET 0x00010000 struct timer_list timer; u16 timer_counter; -- cgit v0.10.2 From 4f4598fd0a87f39955e71bcb7447f403dafc20ba Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:10:30 +0000 Subject: broadcom: Add BCM50610M support This patch adds support for the BCM50610M phy ID. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 190efc3..dec4dec 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -18,6 +18,7 @@ #include #define PHY_ID_BCM50610 0x0143bd60 +#define PHY_ID_BCM50610M 0x0143bd70 #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ @@ -447,7 +448,7 @@ static struct phy_driver bcm5411_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm5421_driver = { @@ -462,7 +463,7 @@ static struct phy_driver bcm5421_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm5461_driver = { @@ -477,7 +478,7 @@ static struct phy_driver bcm5461_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm5464_driver = { @@ -492,7 +493,7 @@ static struct phy_driver bcm5464_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm5481_driver = { @@ -507,7 +508,7 @@ static struct phy_driver bcm5481_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm5482_driver = { @@ -522,7 +523,7 @@ static struct phy_driver bcm5482_driver = { .read_status = bcm5482_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm50610_driver = { @@ -537,7 +538,22 @@ static struct phy_driver bcm50610_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, +}; + +static struct phy_driver bcm50610m_driver = { + .phy_id = PHY_ID_BCM50610M, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM50610M", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = bcm54xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm54xx_ack_interrupt, + .config_intr = bcm54xx_config_intr, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm57780_driver = { @@ -552,7 +568,7 @@ static struct phy_driver bcm57780_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static int __init broadcom_init(void) @@ -580,12 +596,17 @@ static int __init broadcom_init(void) ret = phy_driver_register(&bcm50610_driver); if (ret) goto out_50610; + ret = phy_driver_register(&bcm50610m_driver); + if (ret) + goto out_50610m; ret = phy_driver_register(&bcm57780_driver); if (ret) goto out_57780; return ret; out_57780: + phy_driver_unregister(&bcm50610m_driver); +out_50610m: phy_driver_unregister(&bcm50610_driver); out_50610: phy_driver_unregister(&bcm5482_driver); @@ -606,6 +627,7 @@ out_5411: static void __exit broadcom_exit(void) { phy_driver_unregister(&bcm57780_driver); + phy_driver_unregister(&bcm50610m_driver); phy_driver_unregister(&bcm50610_driver); phy_driver_unregister(&bcm5482_driver); phy_driver_unregister(&bcm5481_driver); -- cgit v0.10.2 From d7a2ed9248a3c3ec6afe3be0c351bd1ca9e981f3 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:10:58 +0000 Subject: broadcom: Add AC131 phy support This patch adds support for the AC131 fast ethernet transceiver. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index dec4dec..3262a24 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -142,6 +142,35 @@ #define PHY_BCM_FLAGS_MODE_1000BX 0x00000002 #define PHY_BCM_FLAGS_MODE_COPPER 0x00000001 + +/*****************************************************************************/ +/* Fast Ethernet Transceiver definitions. */ +/*****************************************************************************/ + +#define MII_BRCM_FET_INTREG 0x1a /* Interrupt register */ +#define MII_BRCM_FET_IR_MASK 0x0100 /* Mask all interrupts */ +#define MII_BRCM_FET_IR_LINK_EN 0x0200 /* Link status change enable */ +#define MII_BRCM_FET_IR_SPEED_EN 0x0400 /* Link speed change enable */ +#define MII_BRCM_FET_IR_DUPLEX_EN 0x0800 /* Duplex mode change enable */ +#define MII_BRCM_FET_IR_ENABLE 0x4000 /* Interrupt enable */ + +#define MII_BRCM_FET_BRCMTEST 0x1f /* Brcm test register */ +#define MII_BRCM_FET_BT_SRE 0x0080 /* Shadow register enable */ + + +/*** Shadow register definitions ***/ + +#define MII_BRCM_FET_SHDW_MISCCTRL 0x10 /* Shadow misc ctrl */ +#define MII_BRCM_FET_SHDW_MC_FAME 0x4000 /* Force Auto MDIX enable */ + +#define MII_BRCM_FET_SHDW_AUXMODE4 0x1a /* Auxiliary mode 4 */ +#define MII_BRCM_FET_SHDW_AM4_LED_MASK 0x0003 +#define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001 + +#define MII_BRCM_FET_SHDW_AUXSTAT2 0x1b /* Auxiliary status 2 */ +#define MII_BRCM_FET_SHDW_AS2_APDE 0x0020 /* Auto power down enable */ + + MODULE_DESCRIPTION("Broadcom PHY driver"); MODULE_AUTHOR("Maciej W. Rozycki"); MODULE_LICENSE("GPL"); @@ -436,6 +465,114 @@ static int bcm5481_config_aneg(struct phy_device *phydev) return ret; } +static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) +{ + int val; + + val = phy_read(phydev, reg); + if (val < 0) + return val; + + return phy_write(phydev, reg, val | set); +} + +static int brcm_fet_config_init(struct phy_device *phydev) +{ + int reg, err, err2, brcmtest; + + /* Reset the PHY to bring it to a known state. */ + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + + reg = phy_read(phydev, MII_BRCM_FET_INTREG); + if (reg < 0) + return reg; + + /* Unmask events we are interested in and mask interrupts globally. */ + reg = MII_BRCM_FET_IR_DUPLEX_EN | + MII_BRCM_FET_IR_SPEED_EN | + MII_BRCM_FET_IR_LINK_EN | + MII_BRCM_FET_IR_ENABLE | + MII_BRCM_FET_IR_MASK; + + err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); + if (err < 0) + return err; + + /* Enable shadow register access */ + brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST); + if (brcmtest < 0) + return brcmtest; + + reg = brcmtest | MII_BRCM_FET_BT_SRE; + + err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg); + if (err < 0) + return err; + + /* Set the LED mode */ + reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4); + if (reg < 0) { + err = reg; + goto done; + } + + reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK; + reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1; + + err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg); + if (err < 0) + goto done; + + /* Enable auto MDIX */ + err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, + MII_BRCM_FET_SHDW_MC_FAME); + if (err < 0) + goto done; + + /* Enable auto power down */ + err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, + MII_BRCM_FET_SHDW_AS2_APDE); + +done: + /* Disable shadow register access */ + err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest); + if (!err) + err = err2; + + return err; +} + +static int brcm_fet_ack_interrupt(struct phy_device *phydev) +{ + int reg; + + /* Clear pending interrupts. */ + reg = phy_read(phydev, MII_BRCM_FET_INTREG); + if (reg < 0) + return reg; + + return 0; +} + +static int brcm_fet_config_intr(struct phy_device *phydev) +{ + int reg, err; + + reg = phy_read(phydev, MII_BRCM_FET_INTREG); + if (reg < 0) + return reg; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + reg &= ~MII_BRCM_FET_IR_MASK; + else + reg |= MII_BRCM_FET_IR_MASK; + + err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); + return err; +} + static struct phy_driver bcm5411_driver = { .phy_id = 0x00206070, .phy_id_mask = 0xfffffff0, @@ -571,6 +708,21 @@ static struct phy_driver bcm57780_driver = { .driver = { .owner = THIS_MODULE }, }; +static struct phy_driver bcmac131_driver = { + .phy_id = 0x0143bc70, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCMAC131", + .features = PHY_BASIC_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = brcm_fet_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = brcm_fet_ack_interrupt, + .config_intr = brcm_fet_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + static int __init broadcom_init(void) { int ret; @@ -602,8 +754,13 @@ static int __init broadcom_init(void) ret = phy_driver_register(&bcm57780_driver); if (ret) goto out_57780; + ret = phy_driver_register(&bcmac131_driver); + if (ret) + goto out_ac131; return ret; +out_ac131: + phy_driver_unregister(&bcm57780_driver); out_57780: phy_driver_unregister(&bcm50610m_driver); out_50610m: @@ -626,6 +783,7 @@ out_5411: static void __exit broadcom_exit(void) { + phy_driver_unregister(&bcmac131_driver); phy_driver_unregister(&bcm57780_driver); phy_driver_unregister(&bcm50610m_driver); phy_driver_unregister(&bcm50610_driver); -- cgit v0.10.2 From d9221e66002a7f24fb71b73132aa46c40079745f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:11:26 +0000 Subject: broadcom: Make the 57780 IEEE compliant This brings the 57780's phy into IEEE compliance by suppressing the common mode oscillation. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 3262a24..f81e532 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -19,6 +19,11 @@ #define PHY_ID_BCM50610 0x0143bd60 #define PHY_ID_BCM50610M 0x0143bd70 +#define PHY_ID_BCM57780 0x03625d90 + +#define BRCM_PHY_MODEL(phydev) \ + ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) + #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ @@ -118,6 +123,7 @@ #define MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE 0x0200 #define MII_BCM54XX_EXP_EXP75 0x0f75 #define MII_BCM54XX_EXP_EXP75_VDACCTRL 0x003c +#define MII_BCM54XX_EXP_EXP75_CM_OSC 0x0001 #define MII_BCM54XX_EXP_EXP96 0x0f96 #define MII_BCM54XX_EXP_EXP96_MYST 0x0010 #define MII_BCM54XX_EXP_EXP97 0x0f97 @@ -194,7 +200,7 @@ static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val) } /* Indirect register access functions for the Expansion Registers */ -static int bcm54xx_exp_read(struct phy_device *phydev, u8 regnum) +static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum) { int val; @@ -308,6 +314,33 @@ static int bcm54xx_config_init(struct phy_device *phydev) return err; } + if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) { + int err2; + + err = bcm54xx_auxctl_write(phydev, + MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, + MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | + MII_BCM54XX_AUXCTL_ACTL_TX_6DB); + if (err < 0) + return err; + + reg = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75); + if (reg < 0) + goto error; + + reg |= MII_BCM54XX_EXP_EXP75_CM_OSC; + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, reg); + +error: + err2 = bcm54xx_auxctl_write(phydev, + MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, + MII_BCM54XX_AUXCTL_ACTL_TX_6DB); + if (err) + return err; + if (err2) + return err2; + } + return 0; } @@ -694,7 +727,7 @@ static struct phy_driver bcm50610m_driver = { }; static struct phy_driver bcm57780_driver = { - .phy_id = 0x03625d90, + .phy_id = PHY_ID_BCM57780, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM57780", .features = PHY_GBIT_FEATURES | -- cgit v0.10.2 From f656f39801b00c3c2aa26cefbdee2775d6706d45 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:11:55 +0000 Subject: tg3: Update version to 3.100 This patch updates the tg3 version to 3.100. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2808152..8af2cdf 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.99" -#define DRV_MODULE_RELDATE "April 20, 2009" +#define DRV_MODULE_VERSION "3.100" +#define DRV_MODULE_RELDATE "August 25, 2009" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v0.10.2 From 31ffe249e5426d2648d68568fa00a7b66666a5db Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 26 Aug 2009 16:32:37 -0700 Subject: net: Temporarily backout SKB sources tracer. Steven Rostedt has suggested that Neil work with the tracing folks, trying to use TRACE_EVENT as the mechanism for implementation. And if that doesn't workout we can investigate other solutions such as that one which was tried here. This reverts the following 2 commits: 5a165657bef7c47e5ff4cd138f7758ef6278e87b ("net: skb ftracer - Add config option to enable new ftracer (v3)") 9ec04da7489d2c9ae01ea6e9b5fa313ccf3d35fb ("net: skb ftracer - Add actual ftrace code to kernel (v3)") Signed-off-by: David S. Miller diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 9a2f19b..019f380 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -234,17 +234,6 @@ config BOOT_TRACER You must pass in initcall_debug and ftrace=initcall to the kernel command line to enable this on bootup. -config SKB_SOURCES_TRACER - bool "Trace skb source information" - depends on NET - select GENERIC_TRACER - help - This tracer helps developers/sysadmins correlate skb allocation and - consumption. The idea being that some processes will primarily consume data - that was allocated on certain numa nodes. By being able to visualize which - nodes the data was allocated on, a sysadmin or developer can optimize the - scheduling of those processes to cut back on cross node chatter. - config TRACE_BRANCH_PROFILING bool select GENERIC_TRACER diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index ee5e5b1..844164d 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile @@ -49,7 +49,6 @@ obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o ifeq ($(CONFIG_BLOCK),y) obj-$(CONFIG_EVENT_TRACING) += blktrace.o endif -obj-$(CONFIG_SKB_SOURCES_TRACER) += trace_skb_sources.o obj-$(CONFIG_EVENT_TRACING) += trace_events.o obj-$(CONFIG_EVENT_TRACING) += trace_export.o obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 8a6281b..8b9f4f6 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -41,7 +40,6 @@ enum trace_type { TRACE_KMEM_FREE, TRACE_POWER, TRACE_BLK, - TRACE_SKB_SOURCE, __TRACE_LAST_TYPE, }; @@ -173,21 +171,6 @@ struct trace_power { struct power_trace state_data; }; -struct skb_record { - pid_t pid; /* pid of the copying process */ - int anid; /* node where skb was allocated */ - int cnid; /* node to which skb was copied in userspace */ - char ifname[IFNAMSIZ]; /* Name of the receiving interface */ - int rx_queue; /* The rx queue the skb was received on */ - int ccpu; /* Cpu the application got this frame from */ - int len; /* length of the data copied */ -}; - -struct trace_skb_event { - struct trace_entry ent; - struct skb_record event_data; -}; - enum kmemtrace_type_id { KMEMTRACE_TYPE_KMALLOC = 0, /* kmalloc() or kfree(). */ KMEMTRACE_TYPE_CACHE, /* kmem_cache_*(). */ @@ -340,8 +323,6 @@ extern void __ftrace_bad_type(void); TRACE_SYSCALL_ENTER); \ IF_ASSIGN(var, ent, struct syscall_trace_exit, \ TRACE_SYSCALL_EXIT); \ - IF_ASSIGN(var, ent, struct trace_skb_event, \ - TRACE_SKB_SOURCE); \ __ftrace_bad_type(); \ } while (0) diff --git a/kernel/trace/trace_skb_sources.c b/kernel/trace/trace_skb_sources.c deleted file mode 100644 index 40eb071..0000000 --- a/kernel/trace/trace_skb_sources.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * ring buffer based tracer for analyzing per-socket skb sources - * - * Neil Horman - * Copyright (C) 2009 - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "trace.h" -#include "trace_output.h" - -EXPORT_TRACEPOINT_SYMBOL_GPL(skb_copy_datagram_iovec); - -static struct trace_array *skb_trace; -static int __read_mostly trace_skb_source_enabled; - -static void probe_skb_dequeue(const struct sk_buff *skb, int len) -{ - struct ring_buffer_event *event; - struct trace_skb_event *entry; - struct trace_array *tr = skb_trace; - struct net_device *dev; - - if (!trace_skb_source_enabled) - return; - - if (in_interrupt()) - return; - - event = trace_buffer_lock_reserve(tr, TRACE_SKB_SOURCE, - sizeof(*entry), 0, 0); - if (!event) - return; - entry = ring_buffer_event_data(event); - - entry->event_data.pid = current->pid; - entry->event_data.anid = page_to_nid(virt_to_page(skb->data)); - entry->event_data.cnid = cpu_to_node(smp_processor_id()); - entry->event_data.len = len; - entry->event_data.rx_queue = skb->queue_mapping; - entry->event_data.ccpu = smp_processor_id(); - - dev = dev_get_by_index(sock_net(skb->sk), skb->iif); - if (dev) { - memcpy(entry->event_data.ifname, dev->name, IFNAMSIZ); - dev_put(dev); - } else { - strcpy(entry->event_data.ifname, "Unknown"); - } - - trace_buffer_unlock_commit(tr, event, 0, 0); -} - -static int tracing_skb_source_register(void) -{ - int ret; - - ret = register_trace_skb_copy_datagram_iovec(probe_skb_dequeue); - if (ret) - pr_info("skb source trace: Couldn't activate dequeue tracepoint"); - - return ret; -} - -static void start_skb_source_trace(struct trace_array *tr) -{ - trace_skb_source_enabled = 1; -} - -static void stop_skb_source_trace(struct trace_array *tr) -{ - trace_skb_source_enabled = 0; -} - -static void skb_source_trace_reset(struct trace_array *tr) -{ - trace_skb_source_enabled = 0; - unregister_trace_skb_copy_datagram_iovec(probe_skb_dequeue); -} - - -static int skb_source_trace_init(struct trace_array *tr) -{ - int cpu; - skb_trace = tr; - - trace_skb_source_enabled = 1; - tracing_skb_source_register(); - - for_each_cpu(cpu, cpu_possible_mask) - tracing_reset(tr, cpu); - return 0; -} - -static enum print_line_t skb_source_print_line(struct trace_iterator *iter) -{ - int ret = 0; - struct trace_entry *entry = iter->ent; - struct trace_skb_event *event; - struct skb_record *record; - struct trace_seq *s = &iter->seq; - - trace_assign_type(event, entry); - record = &event->event_data; - if (entry->type != TRACE_SKB_SOURCE) - return TRACE_TYPE_UNHANDLED; - - ret = trace_seq_printf(s, " %d %d %d %s %d %d %d\n", - record->pid, - record->anid, - record->cnid, - record->ifname, - record->rx_queue, - record->ccpu, - record->len); - - if (!ret) - return TRACE_TYPE_PARTIAL_LINE; - - return TRACE_TYPE_HANDLED; -} - -static void skb_source_print_header(struct seq_file *s) -{ - seq_puts(s, "# PID ANID CNID IFC RXQ CCPU LEN\n"); - seq_puts(s, "# | | | | | | |\n"); -} - -static struct tracer skb_source_tracer __read_mostly = -{ - .name = "skb_sources", - .init = skb_source_trace_init, - .start = start_skb_source_trace, - .stop = stop_skb_source_trace, - .reset = skb_source_trace_reset, - .print_line = skb_source_print_line, - .print_header = skb_source_print_header, -}; - -static int init_skb_source_trace(void) -{ - return register_tracer(&skb_source_tracer); -} -device_initcall(init_skb_source_trace); -- cgit v0.10.2 From 58490f18071de525f42b6ed264a87116ec49ef0f Mon Sep 17 00:00:00 2001 From: Klaus-Dieter Wacker Date: Wed, 26 Aug 2009 02:01:06 +0000 Subject: qeth: HiperSockets SIGA retry support on CC=2. Qeth HiperSockets support now retries sending of packets when the IBM System z signals a temporary resource shortage (e.g. target buffer full). The packet is enqueued into the device queue. After 3 times of unsuccessful send the packet is dropped. Signed-off-by: Klaus-Dieter Wacker Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 447e1d1..03161e6 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -435,6 +435,7 @@ struct qeth_qdio_out_q { * index of buffer to be filled by driver; state EMPTY or PACKING */ int next_buf_to_fill; + int sync_iqdio_error; /* * number of buffers that are currently filled (PRIMED) * -> these buffers are hardware-owned @@ -685,6 +686,14 @@ struct qeth_mc_mac { int is_vmac; }; +struct qeth_skb_data { + __u32 magic; + int count; +}; + +#define QETH_SKB_MAGIC 0x71657468 +#define QETH_SIGA_CC2_RETRIES 3 + struct qeth_card { struct list_head list; enum qeth_card_states state; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index d53621c..ac7270d 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -927,8 +927,8 @@ out: return; } -static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, - struct qeth_qdio_out_buffer *buf) +static void __qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, + struct qeth_qdio_out_buffer *buf, unsigned int qeth_skip_skb) { int i; struct sk_buff *skb; @@ -937,11 +937,13 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, if (buf->buffer->element[0].flags & 0x40) atomic_dec(&queue->set_pci_flags_count); - skb = skb_dequeue(&buf->skb_list); - while (skb) { - atomic_dec(&skb->users); - dev_kfree_skb_any(skb); + if (!qeth_skip_skb) { skb = skb_dequeue(&buf->skb_list); + while (skb) { + atomic_dec(&skb->users); + dev_kfree_skb_any(skb); + skb = skb_dequeue(&buf->skb_list); + } } for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { if (buf->buffer->element[i].addr && buf->is_header[i]) @@ -957,6 +959,12 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); } +static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, + struct qeth_qdio_out_buffer *buf) +{ + __qeth_clear_output_buffer(queue, buf, 0); +} + void qeth_clear_qdio_buffers(struct qeth_card *card) { int i, j; @@ -2685,6 +2693,13 @@ static int qeth_handle_send_error(struct qeth_card *card, int sbalf15 = buffer->buffer->element[15].flags & 0xff; QETH_DBF_TEXT(TRACE, 6, "hdsnderr"); + if (card->info.type == QETH_CARD_TYPE_IQD) { + if (sbalf15 == 0) { + qdio_err = 0; + } else { + qdio_err = 1; + } + } qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); if (!qdio_err) @@ -2817,6 +2832,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, } } + queue->sync_iqdio_error = 0; queue->card->dev->trans_start = jiffies; if (queue->card->options.performance_stats) { queue->card->perf_stats.outbound_do_qdio_cnt++; @@ -2832,6 +2848,10 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() - queue->card->perf_stats.outbound_do_qdio_start_time; + if (rc > 0) { + if (!(rc & QDIO_ERROR_SIGA_BUSY)) + queue->sync_iqdio_error = rc & 3; + } if (rc) { queue->card->stats.tx_errors += count; /* ignore temporary SIGA errors without busy condition */ @@ -2899,6 +2919,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, struct qeth_qdio_out_q *queue = card->qdio.out_qs[__queue]; struct qeth_qdio_out_buffer *buffer; int i; + unsigned qeth_send_err; QETH_DBF_TEXT(TRACE, 6, "qdouhdl"); if (qdio_error & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) { @@ -2915,8 +2936,9 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, } for (i = first_element; i < (first_element + count); ++i) { buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; - qeth_handle_send_error(card, buffer, qdio_error); - qeth_clear_output_buffer(queue, buffer); + qeth_send_err = qeth_handle_send_error(card, buffer, qdio_error); + __qeth_clear_output_buffer(queue, buffer, + (qeth_send_err == QETH_SEND_ERROR_RETRY) ? 1 : 0); } atomic_sub(count, &queue->used_buffers); /* check if we need to do something on this outbound queue */ @@ -3159,7 +3181,10 @@ int qeth_do_send_packet_fast(struct qeth_card *card, int offset, int hd_len) { struct qeth_qdio_out_buffer *buffer; + struct sk_buff *skb1; + struct qeth_skb_data *retry_ctrl; int index; + int rc; /* spin until we get the queue ... */ while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED, @@ -3178,6 +3203,25 @@ int qeth_do_send_packet_fast(struct qeth_card *card, atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); qeth_flush_buffers(queue, index, 1); + if (queue->sync_iqdio_error == 2) { + skb1 = skb_dequeue(&buffer->skb_list); + while (skb1) { + atomic_dec(&skb1->users); + skb1 = skb_dequeue(&buffer->skb_list); + } + retry_ctrl = (struct qeth_skb_data *) &skb->cb[16]; + if (retry_ctrl->magic != QETH_SKB_MAGIC) { + retry_ctrl->magic = QETH_SKB_MAGIC; + retry_ctrl->count = 0; + } + if (retry_ctrl->count < QETH_SIGA_CC2_RETRIES) { + retry_ctrl->count++; + rc = dev_queue_xmit(skb); + } else { + dev_kfree_skb_any(skb); + QETH_DBF_TEXT(QERR, 2, "qrdrop"); + } + } return 0; out: atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); -- cgit v0.10.2 From e806904057253e4f7651a8594456e68857c24e1b Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Wed, 26 Aug 2009 02:01:07 +0000 Subject: qeth: scheduling while atomic during ifconfig online sequence In case the IP address list contains entries (not removed when the device was set offline) this entries should be registered next time the device is brought online. In the past this was done implicitly with the device open call but since we wait in the set IPv4 IPA and the device open common code holds various locks this does not work any longer. Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 048defa..77e04b7 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3180,6 +3180,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) netif_carrier_on(card->dev); qeth_set_allowed_threads(card, 0xffffffff, 0); + qeth_l3_set_ip_addr_list(card); if (recover_flag == CARD_STATE_RECOVER) { if (recovery_mode) qeth_l3_open(card->dev); -- cgit v0.10.2 From ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324 Mon Sep 17 00:00:00 2001 From: Klaus-Dieter Wacker Date: Wed, 26 Aug 2009 02:01:08 +0000 Subject: qeth: Cleanup for cast-type determination. Clear separation of cast-type determination (send path) for layer-2 resp. layer-3. Allowing to have inline functions for qeth layer- discipline. Signed-off-by: Klaus-Dieter Wacker Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 03161e6..31a2b4e 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -843,7 +843,6 @@ int qeth_default_setadapterparms_cb(struct qeth_card *, struct qeth_reply *, int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *, int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long), void *reply_param); -int qeth_get_cast_type(struct qeth_card *, struct sk_buff *); int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index ac7270d..1560bb6 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2952,55 +2952,6 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, } EXPORT_SYMBOL_GPL(qeth_qdio_output_handler); -int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) -{ - int cast_type = RTN_UNSPEC; - - if (card->info.type == QETH_CARD_TYPE_OSN) - return cast_type; - - if (skb_dst(skb) && skb_dst(skb)->neighbour) { - cast_type = skb_dst(skb)->neighbour->type; - if ((cast_type == RTN_BROADCAST) || - (cast_type == RTN_MULTICAST) || - (cast_type == RTN_ANYCAST)) - return cast_type; - else - return RTN_UNSPEC; - } - /* try something else */ - if (skb->protocol == ETH_P_IPV6) - return (skb_network_header(skb)[24] == 0xff) ? - RTN_MULTICAST : 0; - else if (skb->protocol == ETH_P_IP) - return ((skb_network_header(skb)[16] & 0xf0) == 0xe0) ? - RTN_MULTICAST : 0; - /* ... */ - if (!memcmp(skb->data, skb->dev->broadcast, 6)) - return RTN_BROADCAST; - else { - u16 hdr_mac; - - hdr_mac = *((u16 *)skb->data); - /* tr multicast? */ - switch (card->info.link_type) { - case QETH_LINK_TYPE_HSTR: - case QETH_LINK_TYPE_LANE_TR: - if ((hdr_mac == QETH_TR_MAC_NC) || - (hdr_mac == QETH_TR_MAC_C)) - return RTN_MULTICAST; - break; - /* eth or so multicast? */ - default: - if ((hdr_mac == QETH_ETH_MAC_V4) || - (hdr_mac == QETH_ETH_MAC_V6)) - return RTN_MULTICAST; - } - } - return cast_type; -} -EXPORT_SYMBOL_GPL(qeth_get_cast_type); - int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, int ipv, int cast_type) { diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 2cfc338..12ee7a3 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -216,36 +216,16 @@ static void qeth_l2_del_all_mc(struct qeth_card *card) spin_unlock_bh(&card->mclock); } -static void qeth_l2_get_packet_type(struct qeth_card *card, - struct qeth_hdr *hdr, struct sk_buff *skb) +static inline int qeth_l2_get_cast_type(struct qeth_card *card, + struct sk_buff *skb) { - __u16 hdr_mac; - - if (!memcmp(skb->data + QETH_HEADER_SIZE, - skb->dev->broadcast, 6)) { - /* broadcast? */ - hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_BROADCAST; - return; - } - hdr_mac = *((__u16 *)skb->data); - /* tr multicast? */ - switch (card->info.link_type) { - case QETH_LINK_TYPE_HSTR: - case QETH_LINK_TYPE_LANE_TR: - if ((hdr_mac == QETH_TR_MAC_NC) || - (hdr_mac == QETH_TR_MAC_C)) - hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_MULTICAST; - else - hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_UNICAST; - break; - /* eth or so multicast? */ - default: - if ((hdr_mac == QETH_ETH_MAC_V4) || - (hdr_mac == QETH_ETH_MAC_V6)) - hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_MULTICAST; - else - hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_UNICAST; - } + if (card->info.type == QETH_CARD_TYPE_OSN) + return RTN_UNSPEC; + if (is_broadcast_ether_addr(skb->data)) + return RTN_BROADCAST; + if (is_multicast_ether_addr(skb->data)) + return RTN_MULTICAST; + return RTN_UNSPEC; } static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, @@ -262,7 +242,7 @@ static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, else if (cast_type == RTN_BROADCAST) hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_BROADCAST; else - qeth_l2_get_packet_type(card, hdr, skb); + hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_UNICAST; hdr->hdr.l2.pkt_length = skb->len-QETH_HEADER_SIZE; /* VSWITCH relies on the VLAN @@ -672,7 +652,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct qeth_card *card = dev->ml_priv; struct sk_buff *new_skb = skb; int ipv = qeth_get_ip_version(skb); - int cast_type = qeth_get_cast_type(card, skb); + int cast_type = qeth_l2_get_cast_type(card, skb); struct qeth_qdio_out_q *queue = card->qdio.out_qs [qeth_get_priority_queue(card, skb, ipv, cast_type)]; int tx_bytes = skb->len; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 77e04b7..d9fabe3 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2525,6 +2525,51 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return rc; } +int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb) +{ + int cast_type = RTN_UNSPEC; + + if (skb_dst(skb) && skb_dst(skb)->neighbour) { + cast_type = skb_dst(skb)->neighbour->type; + if ((cast_type == RTN_BROADCAST) || + (cast_type == RTN_MULTICAST) || + (cast_type == RTN_ANYCAST)) + return cast_type; + else + return RTN_UNSPEC; + } + /* try something else */ + if (skb->protocol == ETH_P_IPV6) + return (skb_network_header(skb)[24] == 0xff) ? + RTN_MULTICAST : 0; + else if (skb->protocol == ETH_P_IP) + return ((skb_network_header(skb)[16] & 0xf0) == 0xe0) ? + RTN_MULTICAST : 0; + /* ... */ + if (!memcmp(skb->data, skb->dev->broadcast, 6)) + return RTN_BROADCAST; + else { + u16 hdr_mac; + + hdr_mac = *((u16 *)skb->data); + /* tr multicast? */ + switch (card->info.link_type) { + case QETH_LINK_TYPE_HSTR: + case QETH_LINK_TYPE_LANE_TR: + if ((hdr_mac == QETH_TR_MAC_NC) || + (hdr_mac == QETH_TR_MAC_C)) + return RTN_MULTICAST; + break; + /* eth or so multicast? */ + default: + if ((hdr_mac == QETH_ETH_MAC_V4) || + (hdr_mac == QETH_ETH_MAC_V6)) + return RTN_MULTICAST; + } + } + return cast_type; +} + static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int ipv, int cast_type) { @@ -2650,7 +2695,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct qeth_card *card = dev->ml_priv; struct sk_buff *new_skb = NULL; int ipv = qeth_get_ip_version(skb); - int cast_type = qeth_get_cast_type(card, skb); + int cast_type = qeth_l3_get_cast_type(card, skb); struct qeth_qdio_out_q *queue = card->qdio.out_qs [qeth_get_priority_queue(card, skb, ipv, cast_type)]; int tx_bytes = skb->len; -- cgit v0.10.2 From 0d788c7d285a91ef72a7b436dbe753d117856b3d Mon Sep 17 00:00:00 2001 From: Klaus-Dieter Wacker Date: Wed, 26 Aug 2009 02:01:09 +0000 Subject: qeth: display service_level info only when valid. qeth displayed an entry in /proc/service_level even when no valid MCL-string was available (the MCL info is blank). The change is to create an entry in /proc/service_level only when MCL-string is non-zero. Signed-off-by: Klaus-Dieter Wacker Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 1560bb6..c4a42d9 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1160,8 +1160,9 @@ static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr) { struct qeth_card *card = container_of(slr, struct qeth_card, qeth_service_level); - seq_printf(m, "qeth: %s firmware level %s\n", CARD_BUS_ID(card), - card->info.mcl_level); + if (card->info.mcl_level[0]) + seq_printf(m, "qeth: %s firmware level %s\n", + CARD_BUS_ID(card), card->info.mcl_level); } static struct qeth_card *qeth_alloc_card(void) -- cgit v0.10.2 From 7c6a3ed5bd61ec981c8a0d0111cfd435adf3f2b7 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Wed, 26 Aug 2009 02:01:10 +0000 Subject: qeth: display "undefined" value of sysfs-attribute "layer2" If nothing has been written into the qeth sysfs-attribute layer2, its value is "-1" meaning "not yet defined". But the value is displayed as "1" meaning "layer2 selected". The patch changes the reading of this "-1"-value to "-1" to make clear the layer2-attribute has not yet been defined. Signed-off-by: Ursula Braun Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 568465d..33505c2 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -364,7 +364,7 @@ static ssize_t qeth_dev_layer2_show(struct device *dev, if (!card) return -EINVAL; - return sprintf(buf, "%i\n", card->options.layer2 ? 1:0); + return sprintf(buf, "%i\n", card->options.layer2); } static ssize_t qeth_dev_layer2_store(struct device *dev, -- cgit v0.10.2 From aed0628dae0c26b47d40d65f942abe30279b52a5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:16:27 +0000 Subject: sfc: Fix ordering of device registration and initial netif_carrier_off() We must call netif_carrier_off() after the device is registered, not before, to set the operational state and user-space IFF_RUNNING flag correctly. Since we don't want observers to see an intermediate state, open-code register_netdev() and add efx_update_name() and netif_carrier_off() into the locked region. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 343e8da..d4dc920 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1614,21 +1614,24 @@ static int efx_register_netdev(struct efx_nic *efx) SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev); SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops); - /* Always start with carrier off; PHY events will detect the link */ - netif_carrier_off(efx->net_dev); - /* Clear MAC statistics */ efx->mac_op->update_stats(efx); memset(&efx->mac_stats, 0, sizeof(efx->mac_stats)); - rc = register_netdev(net_dev); - if (rc) { - EFX_ERR(efx, "could not register net dev\n"); - return rc; - } - rtnl_lock(); + + rc = dev_alloc_name(net_dev, net_dev->name); + if (rc < 0) + goto fail_locked; efx_update_name(efx); + + rc = register_netdevice(net_dev); + if (rc) + goto fail_locked; + + /* Always start with carrier off; PHY events will detect the link */ + netif_carrier_off(efx->net_dev); + rtnl_unlock(); rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type); @@ -1639,6 +1642,11 @@ static int efx_register_netdev(struct efx_nic *efx) return 0; +fail_locked: + rtnl_unlock(); + EFX_ERR(efx, "could not register net dev\n"); + return rc; + fail_registered: unregister_netdev(net_dev); return rc; -- cgit v0.10.2 From d4ec09acdb15cdb5afdb5cd03f6bceb5c3c690a5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:16:46 +0000 Subject: sfc: Do not reinitialise XAUI serdes before it has completed reset falcon_reset_xaui() waits for XGXS reset to complete, but the XAUI serdes reset may take longer. It needs to check both reset active bits. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h index 375e2a5..2d22611 100644 --- a/drivers/net/sfc/falcon_hwdefs.h +++ b/drivers/net/sfc/falcon_hwdefs.h @@ -700,6 +700,8 @@ /* XGXS/XAUI powerdown/reset register */ #define XX_PWR_RST_REG 0x1300 +#define XX_SD_RST_ACT_LBN 16 +#define XX_SD_RST_ACT_WIDTH 1 #define XX_PWRDND_EN_LBN 15 #define XX_PWRDND_EN_WIDTH 1 #define XX_PWRDNC_EN_LBN 14 diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 2b3269c..bec52ca 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -64,13 +64,15 @@ int falcon_reset_xaui(struct efx_nic *efx) efx_oword_t reg; int count; + /* Start reset sequence */ EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1); falcon_write(efx, ®, XX_PWR_RST_REG); - /* Give some time for the link to establish */ - for (count = 0; count < 1000; count++) { /* wait upto 10ms */ + /* Wait up to 10 ms for completion, then reinitialise */ + for (count = 0; count < 1000; count++) { falcon_read(efx, ®, XX_PWR_RST_REG); - if (EFX_OWORD_FIELD(reg, XX_RST_XX_EN) == 0) { + if (EFX_OWORD_FIELD(reg, XX_RST_XX_EN) == 0 && + EFX_OWORD_FIELD(reg, XX_SD_RST_ACT) == 0) { falcon_setup_xaui(efx); return 0; } -- cgit v0.10.2 From 771046d7b1def64c00a5a47ca48526cbbacd7fe3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:16:58 +0000 Subject: mdio: Check MDIO_STAT1_FAULT in mdio45_links_ok() Some PHYs will report that the link is up even though there is a fault condition. Therefore, check the fault flag too. We must also read STAT2 to reset this flag. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index 6851bdb..7d2e610 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -109,13 +109,20 @@ int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmd_mask) if (mmd_mask & (1 << devad)) { mmd_mask &= ~(1 << devad); - /* Read twice because link state is latched and a - * read moves the current state into the register */ + /* Reset the latched status and fault flags */ mdio->mdio_read(mdio->dev, mdio->prtad, devad, MDIO_STAT1); + if (devad == MDIO_MMD_PMAPMD || devad == MDIO_MMD_PCS || + devad == MDIO_MMD_PHYXS || devad == MDIO_MMD_DTEXS) + mdio->mdio_read(mdio->dev, mdio->prtad, + devad, MDIO_STAT2); + + /* Check the current status and fault flags */ reg = mdio->mdio_read(mdio->dev, mdio->prtad, devad, MDIO_STAT1); - if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) + if (reg < 0 || + (reg & (MDIO_STAT1_FAULT | MDIO_STAT1_LSTATUS)) != + MDIO_STAT1_LSTATUS) return false; } } -- cgit v0.10.2 From 5afaa753d681c437419e3dd9b532c2712dd1d2ea Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:17:19 +0000 Subject: sfc: QT2025C: Use hard reset only At probe time, falcon_reset_hw() performs a hard reset of the PHY along with Falcon. There is no need to perform a soft reset later, and any access to standard MDIO registers before the PHY firmware has booted can interrupt the boot process, making the port unusable. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c index bb2e6af..e6b3d5e 100644 --- a/drivers/net/sfc/xfp_phy.c +++ b/drivers/net/sfc/xfp_phy.c @@ -97,23 +97,24 @@ static int qt2025c_wait_reset(struct efx_nic *efx) return 0; } -/* Reset the PHYXS MMD. This is documented (for the Quake PHYs) as doing - * a complete soft reset. - */ static int xfp_reset_phy(struct efx_nic *efx) { int rc; - rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS, - XFP_MAX_RESET_TIME / XFP_RESET_WAIT, - XFP_RESET_WAIT); - if (rc < 0) - goto fail; - if (efx->phy_type == PHY_TYPE_QT2025C) { + /* Wait for the reset triggered by falcon_reset_hw() + * to complete */ rc = qt2025c_wait_reset(efx); if (rc < 0) goto fail; + } else { + /* Reset the PHYXS MMD. This is documented as doing + * a complete soft reset. */ + rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS, + XFP_MAX_RESET_TIME / XFP_RESET_WAIT, + XFP_RESET_WAIT); + if (rc < 0) + goto fail; } /* Wait 250ms for the PHY to complete bootup */ -- cgit v0.10.2 From cc11763b3510e4942bfece052ccf329a7b086a32 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:17:59 +0000 Subject: sfc: Work around XMAC bug causing packet loss with some peers Received frames must be re-clocked by the local XGXS to the 156.25 MHz (DDR) clock of the XGMII. If the remote clock is slightly faster this can reduce a minimum IPG of 64 bit-times (1 cycle) to 32 bit-times (half a cycle). If the XMAC detects that a frame has reached the maximum RX frame length in the same cycle that it receives one of these reduced IPGs, it may miss the IPG, causing two valid frames to be treated as a single invalid frame (over-length with bad CRC). We work around this by increasing the maximum RX frame length so that peers with matched MTU will not provoke this bug. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 5eabede..298566d 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -984,9 +984,14 @@ static inline void clear_bit_le(unsigned nr, unsigned char *addr) * * The 10G MAC used in Falcon requires 8-byte alignment on the frame * length, so we round up to the nearest 8. + * + * Re-clocking by the XGXS on RX can reduce an IPG to 32 bits (half an + * XGMII cycle). If the frame length reaches the maximum value in the + * same cycle, the XMAC can miss the IPG altogether. We work around + * this by adding a further 16 bytes. */ #define EFX_MAX_FRAME_LEN(mtu) \ - ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */) + 7) & ~7) + ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */ + 7) & ~7) + 16) #endif /* EFX_NET_DRIVER_H */ -- cgit v0.10.2 From 5c8af3b9aa4d19fba7f5a9224636fc70e476eb4f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:18:13 +0000 Subject: sfc: Improve reliability of RX queue flushing Reconfiguring the port requires us to flush all DMA queues. In repeated testing we have found that RX flushes would sometimes fail because the RX DMA engine was not properly isolated from the MACs. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index d4dc920..07a7e4b 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1179,6 +1179,8 @@ static void efx_stop_all(struct efx_nic *efx) /* Isolate the MAC from the TX and RX engines, so that queue * flushes will complete in a timely fashion. */ + falcon_deconfigure_mac_wrapper(efx); + msleep(10); /* Let the Rx FIFO drain */ falcon_drain_tx_fifo(efx); /* Stop the kernel transmit interface late, so the watchdog -- cgit v0.10.2 From c06f51eab8e652abebb698b1ead4c5585f820ef9 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 26 Aug 2009 08:47:47 +0000 Subject: MAINTAINERS: update information for sfc network driver Based upon a patch by Ben Hutchings. Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index 9b55c66..baa0aa8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4527,9 +4527,10 @@ S: Supported F: drivers/net/benet/ SFC NETWORK DRIVER -P: Steve Hodgson -P: Ben Hutchings -M: Robert Stonehouse +M: Solarflare linux maintainers +M: Steve Hodgson +M: Ben Hutchings +L: netdev@vger.kernel.org S: Supported F: drivers/net/sfc/ -- cgit v0.10.2 From 4dbc9ca219b0f294332e734528f7b82211700170 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 27 Aug 2009 09:38:49 +0200 Subject: genirq: Do not mask oneshot edge type interrupts Masking oneshot edge type interrupts is wrong as we might lose an interrupt which is issued when the threaded handler is handling the device. We can keep the irq unmasked safely as with edge type interrupts there is no danger of interrupt floods. If the threaded handler has not yet finished then IRQTF_RUNTHREAD is set which will keep the handler thread active. Debugged and verified in preempt-rt. Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 5765aad..c166019 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -548,13 +548,8 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) kstat_incr_irqs_this_cpu(irq, desc); /* Start handling the irq */ - if (unlikely(desc->status & IRQ_ONESHOT)) { - desc->status |= IRQ_MASKED; - mask_ack_irq(desc, irq); - } else { - if (desc->chip->ack) - desc->chip->ack(irq); - } + if (desc->chip->ack) + desc->chip->ack(irq); /* Mark the IRQ currently in progress.*/ desc->status |= IRQ_INPROGRESS; -- cgit v0.10.2 From 1b0053a0f0893e6bbaaee0d28f5f6269459d8d14 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Aug 2009 12:34:54 +0200 Subject: ALSA: core - strip too long file names in snd_print*() When modules are built with M= option, they pass long file paths to __FILE__. This results in ugly outputs of snd_print*() when CONFIG_SND_VERBOSE_PRINTK is set. This patch adds a check of the path and strips the leading path dirs if the file name is an absolute path to improve the readability of logs. Signed-off-by: Takashi Iwai diff --git a/sound/core/misc.c b/sound/core/misc.c index a9710e0..1d29e67 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -35,8 +35,17 @@ void release_and_free_resource(struct resource *res) EXPORT_SYMBOL(release_and_free_resource); #ifdef CONFIG_SND_VERBOSE_PRINTK -void snd_verbose_printk(const char *file, int line, const char *format, ...) +static const char *sanity_file_name(const char *path) { + if (*path == '/') + return strrchr(path, '/') + 1; + else + return path; +} + +void snd_verbose_printk(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] == '>') { @@ -56,8 +65,9 @@ EXPORT_SYMBOL(snd_verbose_printk); #endif #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK) -void snd_verbose_printd(const char *file, int line, const char *format, ...) +void snd_verbose_printd(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] == '>') { -- cgit v0.10.2 From 286f5875ca5c4e58432e3e6ca386ea4294275d84 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Aug 2009 14:37:51 +0200 Subject: ALSA: hda - Add more quirk for HP laptops with AD1984A More entries for HP laptops to get them working properly. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 41ec0f8..f22c3c0 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -4009,6 +4009,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = { SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP), SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP), SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), + SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE), SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), {} }; -- cgit v0.10.2 From af98603dad87e393d2fc57117fe8a2aa6d620a0c Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 27 Aug 2009 14:29:12 +0100 Subject: kmemleak: Allow rescheduling during an object scanning If the object size is bigger than a predefined value (4K in this case), release the object lock during scanning and call cond_resched(). Re-acquire the lock after rescheduling and test whether the object is still valid. Signed-off-by: Catalin Marinas diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 4872673..6debe0d 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -107,6 +107,7 @@ #define SECS_FIRST_SCAN 60 /* delay before the first scan */ #define SECS_SCAN_WAIT 600 /* subsequent auto scanning delay */ #define GRAY_LIST_PASSES 25 /* maximum number of gray list scans */ +#define MAX_SCAN_SIZE 4096 /* maximum size of a scanned block */ #define BYTES_PER_POINTER sizeof(void *) @@ -642,6 +643,7 @@ static void make_black_object(unsigned long ptr) spin_lock_irqsave(&object->lock, flags); object->min_count = -1; + object->flags |= OBJECT_NO_SCAN; spin_unlock_irqrestore(&object->lock, flags); put_object(object); } @@ -949,10 +951,21 @@ static void scan_object(struct kmemleak_object *object) if (!(object->flags & OBJECT_ALLOCATED)) /* already freed object */ goto out; - if (hlist_empty(&object->area_list)) - scan_block((void *)object->pointer, - (void *)(object->pointer + object->size), object, 0); - else + if (hlist_empty(&object->area_list)) { + void *start = (void *)object->pointer; + void *end = (void *)(object->pointer + object->size); + + while (start < end && (object->flags & OBJECT_ALLOCATED) && + !(object->flags & OBJECT_NO_SCAN)) { + scan_block(start, min(start + MAX_SCAN_SIZE, end), + object, 0); + start += MAX_SCAN_SIZE; + + spin_unlock_irqrestore(&object->lock, flags); + cond_resched(); + spin_lock_irqsave(&object->lock, flags); + } + } else hlist_for_each_entry(area, elem, &object->area_list, node) scan_block((void *)(object->pointer + area->offset), (void *)(object->pointer + area->offset -- cgit v0.10.2 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 diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt index 8906803..c223785 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 6debe0d..c977f7a 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 v0.10.2 From a6186d89c913b176e7339f37a4ec6ccb38b2c5c0 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 27 Aug 2009 14:29:16 +0100 Subject: kmemleak: Mark the early log buffer as __initdata This buffer isn't needed after kmemleak was initialised so it can be freed together with the .init.data section. This patch also marks functions conditionally accessing the early log variables with __ref. Signed-off-by: Catalin Marinas diff --git a/include/linux/kmemleak.h b/include/linux/kmemleak.h index 6a63807..3c7497d 100644 --- a/include/linux/kmemleak.h +++ b/include/linux/kmemleak.h @@ -23,18 +23,18 @@ #ifdef CONFIG_DEBUG_KMEMLEAK -extern void kmemleak_init(void); +extern void kmemleak_init(void) __ref; extern void kmemleak_alloc(const void *ptr, size_t size, int min_count, - gfp_t gfp); -extern void kmemleak_free(const void *ptr); -extern void kmemleak_free_part(const void *ptr, size_t size); + gfp_t gfp) __ref; +extern void kmemleak_free(const void *ptr) __ref; +extern void kmemleak_free_part(const void *ptr, size_t size) __ref; extern void kmemleak_padding(const void *ptr, unsigned long offset, - size_t size); -extern void kmemleak_not_leak(const void *ptr); -extern void kmemleak_ignore(const void *ptr); + size_t size) __ref; +extern void kmemleak_not_leak(const void *ptr) __ref; +extern void kmemleak_ignore(const void *ptr) __ref; extern void kmemleak_scan_area(const void *ptr, unsigned long offset, - size_t length, gfp_t gfp); -extern void kmemleak_no_scan(const void *ptr); + size_t length, gfp_t gfp) __ref; +extern void kmemleak_no_scan(const void *ptr) __ref; static inline void kmemleak_alloc_recursive(const void *ptr, size_t size, int min_count, unsigned long flags, diff --git a/mm/kmemleak.c b/mm/kmemleak.c index c977f7a..576c0a4 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -232,8 +232,9 @@ struct early_log { }; /* early logging buffer and current position */ -static struct early_log early_log[CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE]; -static int crt_early_log; +static struct early_log + early_log[CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE] __initdata; +static int crt_early_log __initdata; static void kmemleak_disable(void); @@ -718,8 +719,8 @@ static void object_no_scan(unsigned long ptr) * Log an early kmemleak_* call to the early_log buffer. These calls will be * processed later once kmemleak is fully initialized. */ -static void log_early(int op_type, const void *ptr, size_t size, - int min_count, unsigned long offset, size_t length) +static void __init log_early(int op_type, const void *ptr, size_t size, + int min_count, unsigned long offset, size_t length) { unsigned long flags; struct early_log *log; @@ -751,7 +752,8 @@ static void log_early(int op_type, const void *ptr, size_t size, * kernel allocators when a new block is allocated (kmem_cache_alloc, kmalloc, * vmalloc etc.). */ -void kmemleak_alloc(const void *ptr, size_t size, int min_count, gfp_t gfp) +void __ref kmemleak_alloc(const void *ptr, size_t size, int min_count, + gfp_t gfp) { pr_debug("%s(0x%p, %zu, %d)\n", __func__, ptr, size, min_count); @@ -766,7 +768,7 @@ EXPORT_SYMBOL_GPL(kmemleak_alloc); * Memory freeing function callback. This function is called from the kernel * allocators when a block is freed (kmem_cache_free, kfree, vfree etc.). */ -void kmemleak_free(const void *ptr) +void __ref kmemleak_free(const void *ptr) { pr_debug("%s(0x%p)\n", __func__, ptr); @@ -781,7 +783,7 @@ EXPORT_SYMBOL_GPL(kmemleak_free); * Partial memory freeing function callback. This function is usually called * from bootmem allocator when (part of) a memory block is freed. */ -void kmemleak_free_part(const void *ptr, size_t size) +void __ref kmemleak_free_part(const void *ptr, size_t size) { pr_debug("%s(0x%p)\n", __func__, ptr); @@ -796,7 +798,7 @@ EXPORT_SYMBOL_GPL(kmemleak_free_part); * Mark an already allocated memory block as a false positive. This will cause * the block to no longer be reported as leak and always be scanned. */ -void kmemleak_not_leak(const void *ptr) +void __ref kmemleak_not_leak(const void *ptr) { pr_debug("%s(0x%p)\n", __func__, ptr); @@ -812,7 +814,7 @@ EXPORT_SYMBOL(kmemleak_not_leak); * corresponding block is not a leak and does not contain any references to * other allocated memory blocks. */ -void kmemleak_ignore(const void *ptr) +void __ref kmemleak_ignore(const void *ptr) { pr_debug("%s(0x%p)\n", __func__, ptr); @@ -826,8 +828,8 @@ EXPORT_SYMBOL(kmemleak_ignore); /* * Limit the range to be scanned in an allocated memory block. */ -void kmemleak_scan_area(const void *ptr, unsigned long offset, size_t length, - gfp_t gfp) +void __ref kmemleak_scan_area(const void *ptr, unsigned long offset, + size_t length, gfp_t gfp) { pr_debug("%s(0x%p)\n", __func__, ptr); @@ -841,7 +843,7 @@ EXPORT_SYMBOL(kmemleak_scan_area); /* * Inform kmemleak not to scan the given memory block. */ -void kmemleak_no_scan(const void *ptr) +void __ref kmemleak_no_scan(const void *ptr) { pr_debug("%s(0x%p)\n", __func__, ptr); -- cgit v0.10.2 From fd6789675ebfb9185cb4fb68dc51010b4e95d952 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 27 Aug 2009 14:29:17 +0100 Subject: kmemleak: Save the stack trace for early allocations Before slab is initialised, kmemleak save the allocations in an early log buffer. They are later recorded as normal memory allocations. This patch adds the stack trace saving to the early log buffer, otherwise the information shown for such objects only refers to the kmemleak_init() function. Signed-off-by: Catalin Marinas diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 576c0a4..8172154 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -229,6 +229,8 @@ struct early_log { int min_count; /* minimum reference count */ unsigned long offset; /* scan area offset */ size_t length; /* scan area length */ + unsigned long trace[MAX_TRACE]; /* stack trace */ + unsigned int trace_len; /* stack trace length */ }; /* early logging buffer and current position */ @@ -437,21 +439,36 @@ static struct kmemleak_object *find_and_get_object(unsigned long ptr, int alias) } /* + * Save stack trace to the given array of MAX_TRACE size. + */ +static int __save_stack_trace(unsigned long *trace) +{ + struct stack_trace stack_trace; + + stack_trace.max_entries = MAX_TRACE; + stack_trace.nr_entries = 0; + stack_trace.entries = trace; + stack_trace.skip = 2; + save_stack_trace(&stack_trace); + + return stack_trace.nr_entries; +} + +/* * Create the metadata (struct kmemleak_object) corresponding to an allocated * memory block and add it to the object_list and object_tree_root. */ -static void create_object(unsigned long ptr, size_t size, int min_count, - gfp_t gfp) +static struct kmemleak_object *create_object(unsigned long ptr, size_t size, + int min_count, gfp_t gfp) { unsigned long flags; struct kmemleak_object *object; struct prio_tree_node *node; - struct stack_trace trace; object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK); if (!object) { kmemleak_stop("Cannot allocate a kmemleak_object structure\n"); - return; + return NULL; } INIT_LIST_HEAD(&object->object_list); @@ -485,12 +502,7 @@ static void create_object(unsigned long ptr, size_t size, int min_count, } /* kernel backtrace */ - trace.max_entries = MAX_TRACE; - trace.nr_entries = 0; - trace.entries = object->trace; - trace.skip = 1; - save_stack_trace(&trace); - object->trace_len = trace.nr_entries; + object->trace_len = __save_stack_trace(object->trace); INIT_PRIO_TREE_NODE(&object->tree_node); object->tree_node.start = ptr; @@ -521,6 +533,7 @@ static void create_object(unsigned long ptr, size_t size, int min_count, list_add_tail_rcu(&object->object_list, &object_list); out: write_unlock_irqrestore(&kmemleak_lock, flags); + return object; } /* @@ -743,11 +756,39 @@ static void __init log_early(int op_type, const void *ptr, size_t size, log->min_count = min_count; log->offset = offset; log->length = length; + if (op_type == KMEMLEAK_ALLOC) + log->trace_len = __save_stack_trace(log->trace); crt_early_log++; local_irq_restore(flags); } /* + * Log an early allocated block and populate the stack trace. + */ +static void early_alloc(struct early_log *log) +{ + struct kmemleak_object *object; + unsigned long flags; + int i; + + if (!atomic_read(&kmemleak_enabled) || !log->ptr || IS_ERR(log->ptr)) + return; + + /* + * RCU locking needed to ensure object is not freed via put_object(). + */ + rcu_read_lock(); + object = create_object((unsigned long)log->ptr, log->size, + log->min_count, GFP_KERNEL); + spin_lock_irqsave(&object->lock, flags); + for (i = 0; i < log->trace_len; i++) + object->trace[i] = log->trace[i]; + object->trace_len = log->trace_len; + spin_unlock_irqrestore(&object->lock, flags); + rcu_read_unlock(); +} + +/* * Memory allocation function callback. This function is called from the * kernel allocators when a new block is allocated (kmem_cache_alloc, kmalloc, * vmalloc etc.). @@ -1509,8 +1550,7 @@ void __init kmemleak_init(void) switch (log->op_type) { case KMEMLEAK_ALLOC: - kmemleak_alloc(log->ptr, log->size, log->min_count, - GFP_KERNEL); + early_alloc(log); break; case KMEMLEAK_FREE: kmemleak_free(log->ptr); -- cgit v0.10.2 From 008139d9146f9afee0e58df4b7422d0c9921f8ce Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 27 Aug 2009 14:29:17 +0100 Subject: kmemleak: Do not report alloc_bootmem blocks as leaks This patch sets the min_count for alloc_bootmem objects to 0 so that they are never reported as leaks. This is because many of these blocks are only referred via the physical address which is not looked up by kmemleak. Signed-off-by: Catalin Marinas Cc: Pekka Enberg diff --git a/mm/bootmem.c b/mm/bootmem.c index 701740c..555d5d2 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -521,7 +521,11 @@ find_block: region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) + start_off); memset(region, 0, size); - kmemleak_alloc(region, size, 1, 0); + /* + * The min_count is set to 0 so that bootmem allocated blocks + * are never reported as leaks. + */ + kmemleak_alloc(region, size, 0, 0); return region; } -- cgit v0.10.2 From 0494e08281d08f0a3dc442eb5e5cecc125b53b27 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 27 Aug 2009 14:29:18 +0100 Subject: kmemleak: Printing of the objects hex dump Introducing printing of the objects hex dump to the seq file. The number of lines to be printed is limited to HEX_MAX_LINES to prevent seq file spamming. The actual number of printed bytes is less than or equal to (HEX_MAX_LINES * HEX_ROW_SIZE). (slight adjustments by Catalin Marinas) Signed-off-by: Sergey Senozhatsky Signed-off-by: Catalin Marinas diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 8172154..1d7645b 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -162,6 +162,15 @@ struct kmemleak_object { /* flag set on newly allocated objects */ #define OBJECT_NEW (1 << 3) +/* number of bytes to print per line; must be 16 or 32 */ +#define HEX_ROW_SIZE 16 +/* number of bytes to print at a time (1, 2, 4, 8) */ +#define HEX_GROUP_SIZE 1 +/* include ASCII after the hex output */ +#define HEX_ASCII 1 +/* max number of lines to be printed */ +#define HEX_MAX_LINES 2 + /* the list of all allocated objects */ static LIST_HEAD(object_list); /* the list of gray-colored objects (see color_gray comment below) */ @@ -259,6 +268,35 @@ static void kmemleak_disable(void); } while (0) /* + * Printing of the objects hex dump to the seq file. The number of lines to be + * printed is limited to HEX_MAX_LINES to prevent seq file spamming. The + * actual number of printed bytes depends on HEX_ROW_SIZE. It must be called + * with the object->lock held. + */ +static void hex_dump_object(struct seq_file *seq, + struct kmemleak_object *object) +{ + const u8 *ptr = (const u8 *)object->pointer; + int i, len, remaining; + unsigned char linebuf[HEX_ROW_SIZE * 5]; + + /* limit the number of lines to HEX_MAX_LINES */ + remaining = len = + min(object->size, (size_t)(HEX_MAX_LINES * HEX_ROW_SIZE)); + + seq_printf(seq, " hex dump (first %d bytes):\n", len); + for (i = 0; i < len; i += HEX_ROW_SIZE) { + int linelen = min(remaining, HEX_ROW_SIZE); + + remaining -= HEX_ROW_SIZE; + hex_dump_to_buffer(ptr + i, linelen, HEX_ROW_SIZE, + HEX_GROUP_SIZE, linebuf, sizeof(linebuf), + HEX_ASCII); + seq_printf(seq, " %s\n", linebuf); + } +} + +/* * Object colors, encoded with count and min_count: * - white - orphan object, not enough references to it (count < min_count) * - gray - not orphan, not marked as false positive (min_count == 0) or @@ -308,6 +346,7 @@ static void print_unreferenced(struct seq_file *seq, object->pointer, object->size); seq_printf(seq, " comm \"%s\", pid %d, jiffies %lu\n", object->comm, object->pid, object->jiffies); + hex_dump_object(seq, object); seq_printf(seq, " backtrace:\n"); for (i = 0; i < object->trace_len; i++) { -- cgit v0.10.2 From fa84e9eecfff478df2d00e94deb3fc40fe4634ad Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 21 Aug 2009 22:01:12 +0200 Subject: init: Move sched_clock_init after late_time_init Some architectures initialize clocks and timers in late_time_init and x86 wants to do the same to avoid FIXMAP hackery for calibrating the TSC. That would result in undefined sched_clock readout and wreckaged printk timestamps again. We probably have those already on archs which do all their time/clock setup in late_time_init. There is no harm to move that after late_time_init except that a few more boot timestamps are stale. The scheduler is not active at that point so no real wreckage is expected. Signed-off-by: Thomas Gleixner LKML-Reference: Cc: linux-arch@vger.kernel.org diff --git a/init/main.c b/init/main.c index 11f4f14..0ec75ce 100644 --- a/init/main.c +++ b/init/main.c @@ -631,7 +631,6 @@ asmlinkage void __init start_kernel(void) softirq_init(); timekeeping_init(); time_init(); - sched_clock_init(); profile_init(); if (!irqs_disabled()) printk(KERN_CRIT "start_kernel(): bug: interrupts were " @@ -682,6 +681,7 @@ asmlinkage void __init start_kernel(void) numa_policy_init(); if (late_time_init) late_time_init(); + sched_clock_init(); calibrate_delay(); pidmap_init(); anon_vma_init(); -- cgit v0.10.2 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 diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 4252697..8e5b348 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 309cb96..a89728d 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 1d29e67..23a032c 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 v0.10.2 From 6c347d43eea29221a8ebab9ff9cbe7a00cddac98 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 27 Aug 2009 18:17:34 +0200 Subject: tracing: Undef TRACE_EVENT_FN between trace events headers inclusion The recent commit: tracing/events: fix the include file dependencies fixed a file dependency problem while including more than one trace event header file. This fix undefined TRACE_EVENT after an event header macro preprocessing in order to make tracepoint.h able to correctly declare the tracepoints necessary for the next event header file. But now we also need to undefine TRACE_EVENT_FN at the end of an event header file preprocessing for the same reason. This fixes the following build error: In file included from include/trace/events/napi.h:5, from net/core/net-traces.c:28: include/linux/tracepoint.h:285:1: warning: "TRACE_EVENT_FN" redefined In file included from include/trace/define_trace.h:61, from include/trace/events/skb.h:40, from net/core/net-traces.c:27: include/trace/ftrace.h:50:1: warning: this is the location of the previous definition In file included from include/trace/events/napi.h:5, from net/core/net-traces.c:28: include/linux/tracepoint.h:285:1: warning: "TRACE_EVENT_FN" redefined In file included from include/trace/define_trace.h:61, from include/trace/events/skb.h:40, from net/core/net-traces.c:27: include/trace/ftrace.h:50:1: warning: this is the location of the previous definition Reported-by: Ingo Molnar Signed-off-by: Frederic Weisbecker Cc: Masami Hiramatsu Cc: Xiao Guangrong Cc: Steven Rostedt Cc: Li Zefan LKML-Reference: <20090827161732.GA7618@nowhere> Signed-off-by: Ingo Molnar diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h index a89ed59..2a4b3bf 100644 --- a/include/trace/define_trace.h +++ b/include/trace/define_trace.h @@ -62,6 +62,7 @@ #endif #undef TRACE_EVENT +#undef TRACE_EVENT_FN #undef TRACE_HEADER_MULTI_READ /* Only undef what we defined in this file */ -- cgit v0.10.2 From 5a53a7640a7af7acf904ed805c6fd1bf9fea829c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Aug 2009 21:04:12 +0200 Subject: ALSA: pcm - Increase protocol version Increase the PCM protocol version to indicate the drain ioctl behavior change. Signed-off-by: Takashi Iwai diff --git a/include/sound/asound.h b/include/sound/asound.h index 82aed3f..1f57bb9 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -138,7 +138,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; -- cgit v0.10.2 From c0729be99cb2b9d9749256254f1c40a801835896 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 26 Aug 2009 22:23:52 -0400 Subject: tracing: remove legacy select of MARKERS by context switch tracing The context switch tracer was made before tracepoints were mature, and the original version used markers. This is no longer true and this patch removes the select. Reported-by: Thomas Gleixner Signed-off-by: Steven Rostedt diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 06be85a..163fbfc 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -60,7 +60,6 @@ config EVENT_TRACING bool config CONTEXT_SWITCH_TRACER - select MARKERS bool # All tracer options should select GENERIC_TRACER. For those options that are -- cgit v0.10.2 From 5d4a9dba2d7fbab69f00dedd430d1788834a055a Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 27 Aug 2009 16:52:21 -0400 Subject: tracing: only show tracing_max_latency when latency tracer configured The tracing_max_latency file should only be present when one of the latency tracers ({preempt|irqs}off, wakeup*) are enabled. This patch also removes tracing_thresh when latency tracers are not enabled, as well as compiles out code that is only used for latency tracers. Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 63dbc7f..0f08816 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -43,9 +43,6 @@ #define TRACE_BUFFER_FLAGS (RB_FL_OVERWRITE) -unsigned long __read_mostly tracing_max_latency; -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. @@ -338,45 +335,6 @@ static struct { int trace_clock_id; -/* - * ftrace_max_lock is used to protect the swapping of buffers - * when taking a max snapshot. The buffers themselves are - * protected by per_cpu spinlocks. But the action of the swap - * needs its own lock. - * - * This is defined as a raw_spinlock_t in order to help - * with performance when lockdep debugging is enabled. - */ -static raw_spinlock_t ftrace_max_lock = - (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; - -/* - * Copy the new maximum trace into the separate maximum-trace - * structure. (this way the maximum trace is permanently saved, - * for later retrieval via /sys/kernel/debug/tracing/latency_trace) - */ -static void -__update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) -{ - struct trace_array_cpu *data = tr->data[cpu]; - - max_tr.cpu = cpu; - max_tr.time_start = data->preempt_timestamp; - - data = max_tr.data[cpu]; - data->saved_latency = tracing_max_latency; - - memcpy(data->comm, tsk->comm, TASK_COMM_LEN); - data->pid = tsk->pid; - data->uid = task_uid(tsk); - data->nice = tsk->static_prio - 20 - MAX_RT_PRIO; - data->policy = tsk->policy; - data->rt_priority = tsk->rt_priority; - - /* record this tasks comm */ - tracing_record_cmdline(tsk); -} - ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) { int len; @@ -420,6 +378,53 @@ static ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt) return cnt; } +/* + * ftrace_max_lock is used to protect the swapping of buffers + * when taking a max snapshot. The buffers themselves are + * protected by per_cpu spinlocks. But the action of the swap + * needs its own lock. + * + * This is defined as a raw_spinlock_t in order to help + * with performance when lockdep debugging is enabled. + * + * It is also used in other places outside the update_max_tr + * so it needs to be defined outside of the + * CONFIG_TRACER_MAX_TRACE. + */ +static raw_spinlock_t ftrace_max_lock = + (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; + +#ifdef CONFIG_TRACER_MAX_TRACE +unsigned long __read_mostly tracing_max_latency; +unsigned long __read_mostly tracing_thresh; + +/* + * Copy the new maximum trace into the separate maximum-trace + * structure. (this way the maximum trace is permanently saved, + * for later retrieval via /sys/kernel/debug/tracing/latency_trace) + */ +static void +__update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) +{ + struct trace_array_cpu *data = tr->data[cpu]; + + max_tr.cpu = cpu; + max_tr.time_start = data->preempt_timestamp; + + data = max_tr.data[cpu]; + data->saved_latency = tracing_max_latency; + + memcpy(data->comm, tsk->comm, TASK_COMM_LEN); + data->pid = tsk->pid; + data->uid = task_uid(tsk); + data->nice = tsk->static_prio - 20 - MAX_RT_PRIO; + data->policy = tsk->policy; + data->rt_priority = tsk->rt_priority; + + /* record this tasks comm */ + tracing_record_cmdline(tsk); +} + /** * update_max_tr - snapshot all trace buffers from global_trace to max_tr * @tr: tracer @@ -476,6 +481,7 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu) __update_max_tr(tr, tsk, cpu); __raw_spin_unlock(&ftrace_max_lock); } +#endif /* CONFIG_TRACER_MAX_TRACE */ /** * register_tracer - register a tracer with the ftrace system. @@ -3952,11 +3958,13 @@ static __init int tracer_init_debugfs(void) trace_create_file("current_tracer", 0644, d_tracer, &global_trace, &set_tracer_fops); +#ifdef CONFIG_TRACER_MAX_TRACE trace_create_file("tracing_max_latency", 0644, d_tracer, &tracing_max_latency, &tracing_max_lat_fops); trace_create_file("tracing_thresh", 0644, d_tracer, &tracing_thresh, &tracing_max_lat_fops); +#endif trace_create_file("README", 0444, d_tracer, NULL, &tracing_readme_fops); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 654fd65..e2c06b2 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -473,12 +473,14 @@ void unregister_tracer(struct tracer *type); extern unsigned long nsecs_to_usecs(unsigned long nsecs); +#ifdef CONFIG_TRACER_MAX_TRACE extern unsigned long tracing_max_latency; extern unsigned long tracing_thresh; void update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu); void update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu); +#endif /* CONFIG_TRACER_MAX_TRACE */ #ifdef CONFIG_STACKTRACE void ftrace_trace_stack(struct trace_array *tr, unsigned long flags, -- cgit v0.10.2 From cf0baf16c3a3b3dd67ea3df346479032ab10e988 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Aug 2009 07:22:05 +0200 Subject: ALSA: Fixed a typo of printk() Fixed a silly typo of printk() included in the previous patch... Signed-off-by: Takashi Iwai diff --git a/include/sound/core.h b/include/sound/core.h index a89728d..1ec992b 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -348,7 +348,7 @@ void __snd_printk(unsigned int level, const char *file, int line, __attribute__ ((format (printf, 4, 5))); #else #define __snd_printk(level, file, line, format, args...) \ - prinkt(format, ##args) + printk(format, ##args) #endif /** -- cgit v0.10.2 From 1ef2ed1066ae9f8080cd96cba11c2d41118b8792 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 28 Aug 2009 03:09:58 +0200 Subject: perf tools: Only save the event formats we need While opening a trace event counter, every events are saved in the trace.info file. But we only want to save the specifications of the events we are using. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Steven Rostedt LKML-Reference: <1251421798-9101-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index acbe594..add514d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -549,11 +549,11 @@ static int __cmd_record(int argc, const char **argv) if (raw_samples) { - read_tracing_data(); + read_tracing_data(attrs, nr_counters); } else { for (i = 0; i < nr_counters; i++) { if (attrs[i].sample_type & PERF_SAMPLE_RAW) { - read_tracing_data(); + read_tracing_data(attrs, nr_counters); break; } } diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 1cda97b..89d46c9 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -158,9 +158,9 @@ int valid_debugfs_mount(const char *debugfs) return 0; } -static const char *tracepoint_id_to_name(u64 config) +struct tracepoint_path *tracepoint_id_to_path(u64 config) { - static char tracepoint_name[2 * MAX_EVENT_LENGTH]; + struct tracepoint_path *path = NULL; DIR *sys_dir, *evt_dir; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; struct stat st; @@ -170,7 +170,7 @@ static const char *tracepoint_id_to_name(u64 config) char evt_path[MAXPATHLEN]; if (valid_debugfs_mount(debugfs_path)) - return "unkown"; + return NULL; sys_dir = opendir(debugfs_path); if (!sys_dir) @@ -197,10 +197,23 @@ static const char *tracepoint_id_to_name(u64 config) if (id == config) { closedir(evt_dir); closedir(sys_dir); - snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH, - "%s:%s", sys_dirent.d_name, - evt_dirent.d_name); - return tracepoint_name; + path = calloc(1, sizeof(path)); + path->system = malloc(MAX_EVENT_LENGTH); + if (!path->system) { + free(path); + return NULL; + } + path->name = malloc(MAX_EVENT_LENGTH); + if (!path->name) { + free(path->system); + free(path); + return NULL; + } + strncpy(path->system, sys_dirent.d_name, + MAX_EVENT_LENGTH); + strncpy(path->name, evt_dirent.d_name, + MAX_EVENT_LENGTH); + return path; } } closedir(evt_dir); @@ -208,7 +221,25 @@ static const char *tracepoint_id_to_name(u64 config) cleanup: closedir(sys_dir); - return "unkown"; + return NULL; +} + +#define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1) +static const char *tracepoint_id_to_name(u64 config) +{ + static char buf[TP_PATH_LEN]; + struct tracepoint_path *path; + + path = tracepoint_id_to_path(config); + if (path) { + snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name); + free(path->name); + free(path->system); + free(path); + } else + snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown"); + + return buf; } static int is_cache_op_valid(u8 cache_type, u8 cache_op) diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 9b1aeea..60704c1 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -1,10 +1,19 @@ - +#ifndef _PARSE_EVENTS_H +#define _PARSE_EVENTS_H /* * Parse symbolic events/counts passed in as options: */ struct option; +struct tracepoint_path { + char *system; + char *name; + struct tracepoint_path *next; +}; + +extern struct tracepoint_path *tracepoint_id_to_path(u64 config); + extern int nr_counters; extern struct perf_counter_attr attrs[MAX_COUNTERS]; @@ -21,3 +30,5 @@ extern void print_events(void); extern char debugfs_path[]; extern int valid_debugfs_mount(const char *debugfs); + +#endif /* _PARSE_EVENTS_H */ diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 78adff1..8161527 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -32,7 +32,9 @@ #include #include #include +#include +#include "../perf.h" #include "trace-event.h" @@ -289,7 +291,18 @@ static void read_header_files(void) put_tracing_file(path); } -static void copy_event_system(const char *sys) +static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) +{ + while (tps) { + if (!strcmp(sys, tps->name)) + return true; + tps = tps->next; + } + + return false; +} + +static void copy_event_system(const char *sys, struct tracepoint_path *tps) { unsigned long long size, check_size; struct dirent *dent; @@ -305,7 +318,8 @@ static void copy_event_system(const char *sys) while ((dent = readdir(dir))) { if (strcmp(dent->d_name, ".") == 0 || - strcmp(dent->d_name, "..") == 0) + strcmp(dent->d_name, "..") == 0 || + !name_in_tp_list(dent->d_name, tps)) continue; format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); sprintf(format, "%s/%s/format", sys, dent->d_name); @@ -321,7 +335,8 @@ static void copy_event_system(const char *sys) rewinddir(dir); while ((dent = readdir(dir))) { if (strcmp(dent->d_name, ".") == 0 || - strcmp(dent->d_name, "..") == 0) + strcmp(dent->d_name, "..") == 0 || + !name_in_tp_list(dent->d_name, tps)) continue; format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); sprintf(format, "%s/%s/format", sys, dent->d_name); @@ -340,18 +355,29 @@ static void copy_event_system(const char *sys) } } -static void read_ftrace_files(void) +static void read_ftrace_files(struct tracepoint_path *tps) { char *path; path = get_tracing_file("events/ftrace"); - copy_event_system(path); + copy_event_system(path, tps); put_tracing_file(path); } -static void read_event_files(void) +static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) +{ + while (tps) { + if (!strcmp(sys, tps->system)) + return true; + tps = tps->next; + } + + return false; +} + +static void read_event_files(struct tracepoint_path *tps) { struct dirent *dent; struct stat st; @@ -370,7 +396,8 @@ static void read_event_files(void) while ((dent = readdir(dir))) { if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0 || - strcmp(dent->d_name, "ftrace") == 0) + strcmp(dent->d_name, "ftrace") == 0 || + !system_in_tp_list(dent->d_name, tps)) continue; sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); sprintf(sys, "%s/%s", path, dent->d_name); @@ -388,7 +415,8 @@ static void read_event_files(void) while ((dent = readdir(dir))) { if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0 || - strcmp(dent->d_name, "ftrace") == 0) + strcmp(dent->d_name, "ftrace") == 0 || + !system_in_tp_list(dent->d_name, tps)) continue; sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); sprintf(sys, "%s/%s", path, dent->d_name); @@ -396,7 +424,7 @@ static void read_event_files(void) if (ret >= 0) { if (S_ISDIR(st.st_mode)) { write_or_die(dent->d_name, strlen(dent->d_name) + 1); - copy_event_system(sys); + copy_event_system(sys, tps); } } free(sys); @@ -450,9 +478,27 @@ static void read_ftrace_printk(void) } -void read_tracing_data(void) +static struct tracepoint_path * +get_tracepoints_path(struct perf_counter_attr *pattrs, int nb_counters) +{ + struct tracepoint_path path, *ppath = &path; + int i; + + for (i = 0; i < nb_counters; i++) { + if (pattrs[i].type != PERF_TYPE_TRACEPOINT) + continue; + ppath->next = tracepoint_id_to_path(pattrs[i].config); + if (!ppath->next) + die("%s\n", "No memory to alloc tracepoints list"); + ppath = ppath->next; + } + + return path.next; +} +void read_tracing_data(struct perf_counter_attr *pattrs, int nb_counters) { char buf[BUFSIZ]; + struct tracepoint_path *tps; output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); if (output_fd < 0) @@ -483,9 +529,11 @@ void read_tracing_data(void) page_size = getpagesize(); write_or_die(&page_size, 4); + tps = get_tracepoints_path(pattrs, nb_counters); + read_header_files(); - read_ftrace_files(); - read_event_files(); + read_ftrace_files(tps); + read_event_files(tps); read_proc_kallsyms(); read_ftrace_printk(); } diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index b53b27f..a6577cd 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -29,6 +29,7 @@ #include #undef _GNU_SOURCE +#include "../perf.h" #include "util.h" #include "trace-event.h" diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 1dac301..b12e490 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -36,6 +36,7 @@ #include #include +#include "../perf.h" #include "util.h" #include "trace-event.h" diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 3ddb894..051fcf3 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -1,6 +1,7 @@ -#ifndef _PARSE_EVENTS_H -#define _PARSE_EVENTS_H +#ifndef _TRACE_EVENTS_H +#define _TRACE_EVENTS_H +#include "parse-events.h" #define __unused __attribute__((unused)) @@ -233,6 +234,6 @@ extern int header_page_data_size; int parse_header_page(char *buf, unsigned long size); -void read_tracing_data(void); +void read_tracing_data(struct perf_counter_attr *pattrs, int nb_counters); -#endif /* _PARSE_EVENTS_H */ +#endif /* _TRACE_EVENTS_H */ -- cgit v0.10.2 From d498bc1f6261dd6f655440eb2f1c7fa25694d3ba Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 28 Aug 2009 04:46:07 +0200 Subject: perf tools: Fix missing string field printing in perf trace Some string fields are not printed because of a missing printf in the post-processing. Before: perf-10070 [000] 0.000000: sched_switch: task :10070 [120] (R) ==> :5720 [120] geany-5720 [000] 0.000000: sched_switch: task :5720 [120] (S) ==> :10070 [120] perf-10070 [000] 0.000000: sched_switch: task :10070 [120] (R) ==> :5720 [120] geany-5720 [000] 0.000000: sched_switch: task :5720 [120] (S) ==> :10070 [120] -0 [000] 0.000000: sched_switch: task :0 [140] (R) ==> :361 [115] After: perf-10070 [000] 0.000000: sched_switch: task perf:10070 [120] (R) ==> geany:5720 [120] geany-5720 [000] 0.000000: sched_switch: task geany:5720 [120] (S) ==> perf:10070 [120] perf-10070 [000] 0.000000: sched_switch: task perf:10070 [120] (R) ==> geany:5720 [120] geany-5720 [000] 0.000000: sched_switch: task geany:5720 [120] (S) ==> perf:10070 [120] -0 [000] 0.000000: sched_switch: task swapper:0 [140] (R) ==> kondemand/1:361 [115] Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Steven Rostedt LKML-Reference: <1251427567-10551-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index a6577cd..96c5e97 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1997,6 +1997,7 @@ static void print_str_arg(void *data, int size, memcpy(str, data + arg->field.field->offset, arg->field.field->size); str[arg->field.field->size] = 0; + printf("%s", str); free(str); break; case PRINT_FLAGS: -- cgit v0.10.2 From 34d76c41554a05425613d16efebb3069c4c545f0 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 27 Aug 2009 13:08:56 +0200 Subject: sched: Fix division by zero - really When re-computing the shares for each task group's cpu representation we need the ratio of weight on each cpu vs the total weight of the sched domain. Since load-balancing is loosely (read not) synchronized, the weight of individual cpus can change between doing the sum and calculating the ratio. The previous patch dealt with only one of the race scenarios, this patch side steps them all by saving a snapshot of all the individual cpu weights, thereby always working on a consistent set. Signed-off-by: Peter Zijlstra Cc: torvalds@linux-foundation.org Cc: jes@sgi.com Cc: jens.axboe@oracle.com Cc: Balbir Singh Cc: Arjan van de Ven Cc: Yinghai Lu LKML-Reference: <1251371336.18584.77.camel@twins> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 8f8a98e..523e20a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1515,30 +1515,29 @@ static unsigned long cpu_avg_load_per_task(int cpu) #ifdef CONFIG_FAIR_GROUP_SCHED +struct update_shares_data { + unsigned long rq_weight[NR_CPUS]; +}; + +static DEFINE_PER_CPU(struct update_shares_data, update_shares_data); + static void __set_se_shares(struct sched_entity *se, unsigned long shares); /* * Calculate and set the cpu's group shares. */ -static void -update_group_shares_cpu(struct task_group *tg, int cpu, - unsigned long sd_shares, unsigned long sd_rq_weight, - unsigned long sd_eff_weight) +static void update_group_shares_cpu(struct task_group *tg, int cpu, + unsigned long sd_shares, + unsigned long sd_rq_weight, + struct update_shares_data *usd) { - unsigned long rq_weight; - unsigned long shares; + unsigned long shares, rq_weight; int boost = 0; - if (!tg->se[cpu]) - return; - - rq_weight = tg->cfs_rq[cpu]->rq_weight; + rq_weight = usd->rq_weight[cpu]; if (!rq_weight) { boost = 1; rq_weight = NICE_0_LOAD; - if (sd_rq_weight == sd_eff_weight) - sd_eff_weight += NICE_0_LOAD; - sd_rq_weight = sd_eff_weight; } /* @@ -1555,6 +1554,7 @@ update_group_shares_cpu(struct task_group *tg, int cpu, unsigned long flags; spin_lock_irqsave(&rq->lock, flags); + tg->cfs_rq[cpu]->rq_weight = boost ? 0 : rq_weight; tg->cfs_rq[cpu]->shares = boost ? 0 : shares; __set_se_shares(tg->se[cpu], shares); spin_unlock_irqrestore(&rq->lock, flags); @@ -1568,25 +1568,31 @@ update_group_shares_cpu(struct task_group *tg, int cpu, */ static int tg_shares_up(struct task_group *tg, void *data) { - unsigned long weight, rq_weight = 0, eff_weight = 0; - unsigned long shares = 0; + unsigned long weight, rq_weight = 0, shares = 0; + struct update_shares_data *usd; struct sched_domain *sd = data; + unsigned long flags; int i; + if (!tg->se[0]) + return 0; + + local_irq_save(flags); + usd = &__get_cpu_var(update_shares_data); + for_each_cpu(i, sched_domain_span(sd)) { + weight = tg->cfs_rq[i]->load.weight; + usd->rq_weight[i] = weight; + /* * If there are currently no tasks on the cpu pretend there * is one of average load so that when a new task gets to * run here it will not get delayed by group starvation. */ - weight = tg->cfs_rq[i]->load.weight; - tg->cfs_rq[i]->rq_weight = weight; - rq_weight += weight; - if (!weight) weight = NICE_0_LOAD; - eff_weight += weight; + rq_weight += weight; shares += tg->cfs_rq[i]->shares; } @@ -1597,7 +1603,9 @@ static int tg_shares_up(struct task_group *tg, void *data) shares = tg->shares; for_each_cpu(i, sched_domain_span(sd)) - update_group_shares_cpu(tg, i, shares, rq_weight, eff_weight); + update_group_shares_cpu(tg, i, shares, rq_weight, usd); + + local_irq_restore(flags); return 0; } -- cgit v0.10.2 From f4890b5c04b6301ef9c3c44ecbfe9955efdbaa17 Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Tue, 25 Aug 2009 15:22:21 +0300 Subject: ASoC: davinci: i2c device creation moved into board files Also, the codec setup data structure has to remain for successful probe. Signed-off-by: Chaithrika U S Signed-off-by: Kevin Hilman Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 0190c1b..67414f6 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -206,57 +206,37 @@ static struct snd_soc_card da850_snd_soc_card = { .num_links = 1, }; -/* evm audio private data */ -static struct aic3x_setup_data evm_aic3x_setup = { -}; - -/* dm6467 evm audio private data */ -static struct aic3x_setup_data dm6467_evm_aic3x_setup = { - .i2c_bus = 1, - .i2c_address = 0x18, -}; - -static struct aic3x_setup_data da8xx_evm_aic3x_setup = { - .i2c_bus = 1, - .i2c_address = 0x18, -}; +static struct aic3x_setup_data aic3x_setup; /* evm audio subsystem */ static struct snd_soc_device evm_snd_devdata = { .card = &snd_soc_card_evm, .codec_dev = &soc_codec_dev_aic3x, - .codec_data = &evm_aic3x_setup, + .codec_data = &aic3x_setup, }; /* evm audio subsystem */ static struct snd_soc_device dm6467_evm_snd_devdata = { .card = &dm6467_snd_soc_card_evm, .codec_dev = &soc_codec_dev_aic3x, - .codec_data = &dm6467_evm_aic3x_setup, + .codec_data = &aic3x_setup, }; /* evm audio subsystem */ static struct snd_soc_device da830_evm_snd_devdata = { .card = &da830_snd_soc_card, .codec_dev = &soc_codec_dev_aic3x, - .codec_data = &da8xx_evm_aic3x_setup, + .codec_data = &aic3x_setup, }; static struct snd_soc_device da850_evm_snd_devdata = { .card = &da850_snd_soc_card, .codec_dev = &soc_codec_dev_aic3x, - .codec_data = &da8xx_evm_aic3x_setup, + .codec_data = &aic3x_setup, }; static struct platform_device *evm_snd_device; -/* temporary i2c device creation until this can be moved into the machine - * support file. -*/ -static struct i2c_board_info i2c_device[] = { - { I2C_BOARD_INFO("tlv320aic33", 0x1b), } -}; - static int __init evm_init(void) { struct snd_soc_device *evm_snd_dev_data; @@ -281,8 +261,6 @@ static int __init evm_init(void) } else return -EINVAL; - i2c_register_board_info(1, i2c_device, ARRAY_SIZE(i2c_device)); - evm_snd_device = platform_device_alloc("soc-audio", index); if (!evm_snd_device) return -ENOMEM; -- cgit v0.10.2 From 119e7a22bb70d84849384e5113792cd45afa4f85 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 27 Aug 2009 09:59:02 +0200 Subject: perf tools: do not complain if root is owning perf.data This improves patch fa6963b24 so that perf.data stuff that has been dumped as root can be read (annotate/report) by a user without the use of the --force. Rationale is that root has plenty of ways to screw us (usually) that do not require twisted schemes involving specially crafting a perf.data. Signed-off-by: Pierre Habouzit Cc: Paul Mackerras Cc: Peter Zijlstra Cc: LKML-Reference: <20090827075902.GF19653@laphroaig.corp> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 4ac618b..4c7bc44 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -984,8 +984,8 @@ static int __cmd_annotate(void) exit(-1); } - if (!force && (input_stat.st_uid != geteuid())) { - fprintf(stderr, "file: %s not owned by current user\n", input_name); + if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { + fprintf(stderr, "file: %s not owned by current user or root\n", input_name); exit(-1); } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index d2e2882..ea6328a 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1405,8 +1405,8 @@ static int __cmd_report(void) exit(-1); } - if (!force && (input_stat.st_uid != geteuid())) { - fprintf(stderr, "file: %s not owned by current user\n", input_name); + if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { + fprintf(stderr, "file: %s not owned by current user or root\n", input_name); exit(-1); } -- cgit v0.10.2 From 0dd7b74787eaf7858c6c573353a83c3e2766e674 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 28 Aug 2009 00:50:06 +0200 Subject: tracing: Fix double CPP substitution in TRACE_EVENT_FN TRACE_EVENT_FN relays on TRACE_EVENT by reprocessing its parameters into the ftrace events CPP macro. This leads to a double substitution in some cases. For example, a bad consequence is a format always prefixed by "%s, %s\n" for every TRACE_EVENT_FN based events. Eg: cat /debug/tracing/events/syscalls/sys_enter/format [...] print fmt: "%s, %s\n", "\"NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)\"",\ "REC->id, REC->args[0], REC->args[1], REC->args[2], REC->args[3],\ REC->args[4], REC->args[5]" This creates a failure in post-processing tools such as perf trace or trace-cmd. Then drop this double substitution and replace it by a new __cpparg() macro that relays CPP arguments containing commas. Signed-off-by: Frederic Weisbecker Cc: Josh Stone Cc: Li Zefan Cc: Steven Rostedt Cc: Jason Baron LKML-Reference: <1251413406-6704-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 360a77a..57c56a9 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -45,14 +45,15 @@ }; \ static struct ftrace_event_call event_##name +#undef __cpparg +#define __cpparg(arg...) arg + /* Callbacks are meaningless to ftrace. */ #undef TRACE_EVENT_FN -#define TRACE_EVENT_FN(name, proto, args, tstruct, \ - assign, print, reg, unreg) \ - TRACE_EVENT(name, TP_PROTO(proto), TP_ARGS(args), \ - TP_STRUCT__entry(tstruct), \ - TP_fast_assign(assign), \ - TP_printk(print)) +#define TRACE_EVENT_FN(name, proto, args, tstruct, \ + assign, print, reg, unreg) \ + TRACE_EVENT(name, __cpparg(proto), __cpparg(args), \ + __cpparg(tstruct), __cpparg(assign), __cpparg(print)) \ #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) -- cgit v0.10.2 From d2c0bdaa9362c4b2ab7416420d034a0a2d1ec979 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 28 Aug 2009 15:35:35 +0300 Subject: ASoC: OMAP: Add functionality to set CLKR and FSR sources in McBSP DAI The McBSP1 port in OMAP3 processors (I believe OMAP2 too but I don't have specifications to check it) have additional CLKR and FSR pins for McBSP1 receiver. Reset default is that receiver is using bit clock and frame sync signal from those pins but it is possible to configure to use also CLKX and FSX pins as well. In fact, other McBSP ports are doing that internally that transmitter and receiver share the CLKX and FSX. Add functionaly that machine drivers can set the CLKR and FSR sources by using the snd_soc_dai_set_sysclk. Thanks to "Aggarwal, Anuj" for reporting the issue. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 0e173e7..3341f49 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -512,6 +512,40 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, return 0; } +static int omap_mcbsp_dai_set_rcvr_src(struct omap_mcbsp_data *mcbsp_data, + int clk_id) +{ + int sel_bit, set = 0; + u16 reg = OMAP2_CONTROL_DEVCONF0; + + if (cpu_class_is_omap1()) + return -EINVAL; /* TODO: Can this be implemented for OMAP1? */ + if (mcbsp_data->bus_id != 0) + return -EINVAL; + + switch (clk_id) { + case OMAP_MCBSP_CLKR_SRC_CLKX: + set = 1; + case OMAP_MCBSP_CLKR_SRC_CLKR: + sel_bit = 3; + break; + case OMAP_MCBSP_FSR_SRC_FSX: + set = 1; + case OMAP_MCBSP_FSR_SRC_FSR: + sel_bit = 4; + break; + default: + return -EINVAL; + } + + if (set) + omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg); + else + omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg); + + return 0; +} + static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) @@ -534,6 +568,13 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, case OMAP_MCBSP_SYSCLK_CLKR_EXT: regs->pcr0 |= SCLKME; break; + + case OMAP_MCBSP_CLKR_SRC_CLKR: + case OMAP_MCBSP_CLKR_SRC_CLKX: + case OMAP_MCBSP_FSR_SRC_FSR: + case OMAP_MCBSP_FSR_SRC_FSX: + err = omap_mcbsp_dai_set_rcvr_src(mcbsp_data, clk_id); + break; default: err = -ENODEV; } diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index c8147aa..647d2f9 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h @@ -32,6 +32,10 @@ enum omap_mcbsp_clksrg_clk { OMAP_MCBSP_SYSCLK_CLK, /* Internal ICLK */ OMAP_MCBSP_SYSCLK_CLKX_EXT, /* External CLKX pin */ OMAP_MCBSP_SYSCLK_CLKR_EXT, /* External CLKR pin */ + OMAP_MCBSP_CLKR_SRC_CLKR, /* CLKR from CLKR pin */ + OMAP_MCBSP_CLKR_SRC_CLKX, /* CLKR from CLKX pin */ + OMAP_MCBSP_FSR_SRC_FSR, /* FSR from FSR pin */ + OMAP_MCBSP_FSR_SRC_FSX, /* FSR from FSX pin */ }; /* McBSP dividers */ -- cgit v0.10.2 From 90d6f92828a081a86cb4f9644b6eef6207855050 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 20 Aug 2009 20:22:01 +0200 Subject: p54: fix broadcast buffering in AP mode The patch "mac80211: fix PS-poll response race" somehow broke broadcast buffering in a funny way. During normal operation - stations are awake - the firmware refused to transmit broadcast frames and reported P54_TX_PSM_CANCELLED. But everything worked as soon as one station entered PSM. The reason: The stack sets IEEE80211_TX_CTL_SEND_AFTER_DTIM for outgoing broadcast frames as soon as a station is marked as sleeping. This flag triggers a path which will reroute these frames into p54's "content after beacon" queue, which is designed to cope with the demands for psm. This patch restores the old behavior. IEEE80211_TX_CTL_CLEAR_PS_FILT will once again be used to signalize the firmware to ignore the ps canceling for certain frames. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 6fc0b61..b6dda2b 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -623,6 +623,9 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE) *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; + if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) + *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; + *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA; switch (priv->mode) { -- cgit v0.10.2 From 9e03fdfd05e733e1136d431973625b174029c5e6 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 20 Aug 2009 09:21:45 -0700 Subject: mac80211: Update mesh config IE to 11s draft 3.02 The mesh config information element has changed significantly since draft 1.08 This patch brings it up to date. Thanks to Sam Leffler and Rui Paulo for identifying this. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 21556a2..52e15e0 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -115,7 +115,7 @@ #define IEEE80211_MAX_SSID_LEN 32 #define IEEE80211_MAX_MESH_ID_LEN 32 -#define IEEE80211_MESH_CONFIG_LEN 19 +#define IEEE80211_MESH_CONFIG_LEN 24 #define IEEE80211_QOS_CTL_LEN 2 #define IEEE80211_QOS_CTL_TID_MASK 0x000F diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 93e618a..455cc7a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -367,6 +367,10 @@ struct ieee80211_if_mesh { u8 mesh_pm_id[4]; /* Congestion Control Mode Identifier */ u8 mesh_cc_id[4]; + /* Synchronization Protocol Identifier */ + u8 mesh_sp_id[4]; + /* Authentication Protocol Identifier */ + u8 mesh_auth_id[4]; /* Local mesh Destination Sequence Number */ u32 dsn; /* Last used PREQ ID */ diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 3185e18..f7364e5 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -18,8 +18,11 @@ #define PP_OFFSET 1 /* Path Selection Protocol */ #define PM_OFFSET 5 /* Path Selection Metric */ #define CC_OFFSET 9 /* Congestion Control Mode */ -#define CAPAB_OFFSET 17 -#define ACCEPT_PLINKS 0x80 +#define SP_OFFSET 13 /* Synchronization Protocol */ +#define AUTH_OFFSET 17 /* Authentication Protocol */ +#define CAPAB_OFFSET 22 +#define CAPAB_ACCEPT_PLINKS 0x80 +#define CAPAB_FORWARDING 0x10 #define TMR_RUNNING_HK 0 #define TMR_RUNNING_MP 1 @@ -84,7 +87,9 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && memcmp(ifmsh->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && - memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0) + memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0 && + memcmp(ifmsh->mesh_sp_id, ie->mesh_config + SP_OFFSET, 4) == 0 && + memcmp(ifmsh->mesh_auth_id, ie->mesh_config + AUTH_OFFSET, 4) == 0) return true; return false; @@ -97,7 +102,7 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat */ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) { - return (*(ie->mesh_config + CAPAB_OFFSET) & ACCEPT_PLINKS) != 0; + return (*(ie->mesh_config + CAPAB_OFFSET) & CAPAB_ACCEPT_PLINKS) != 0; } /** @@ -123,11 +128,18 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) void mesh_ids_set_default(struct ieee80211_if_mesh *sta) { - u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff}; - - memcpy(sta->mesh_pp_id, def_id, 4); - memcpy(sta->mesh_pm_id, def_id, 4); - memcpy(sta->mesh_cc_id, def_id, 4); + u8 oui[3] = {0x00, 0x0F, 0xAC}; + + memcpy(sta->mesh_pp_id, oui, sizeof(oui)); + memcpy(sta->mesh_pm_id, oui, sizeof(oui)); + memcpy(sta->mesh_cc_id, oui, sizeof(oui)); + memcpy(sta->mesh_sp_id, oui, sizeof(oui)); + memcpy(sta->mesh_auth_id, oui, sizeof(oui)); + sta->mesh_pp_id[sizeof(oui)] = 0; + sta->mesh_pm_id[sizeof(oui)] = 0; + sta->mesh_cc_id[sizeof(oui)] = 0xff; + sta->mesh_sp_id[sizeof(oui)] = 0xff; + sta->mesh_auth_id[sizeof(oui)] = 0x0; } int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) @@ -245,7 +257,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) if (sdata->u.mesh.mesh_id_len) memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len); - pos = skb_put(skb, 21); + pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); *pos++ = WLAN_EID_MESH_CONFIG; *pos++ = IEEE80211_MESH_CONFIG_LEN; /* Version */ @@ -263,15 +275,22 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) memcpy(pos, sdata->u.mesh.mesh_cc_id, 4); pos += 4; - /* Channel precedence: - * Not running simple channel unification protocol - */ - memset(pos, 0x00, 4); + /* Synchronization protocol identifier */ + memcpy(pos, sdata->u.mesh.mesh_sp_id, 4); pos += 4; + /* Authentication Protocol identifier */ + memcpy(pos, sdata->u.mesh.mesh_auth_id, 4); + pos += 4; + + /* Mesh Formation Info */ + memset(pos, 0x00, 1); + pos += 1; + /* Mesh capability */ sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); - *pos++ = sdata->u.mesh.accepting_plinks ? ACCEPT_PLINKS : 0x00; + *pos = CAPAB_FORWARDING; + *pos++ |= sdata->u.mesh.accepting_plinks ? CAPAB_ACCEPT_PLINKS : 0x00; *pos++ = 0x00; return; -- cgit v0.10.2 From 5eb6ba83aa326e2f2cf9109d20df5d6a497b36bb Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 20 Aug 2009 19:12:07 -0700 Subject: ath9k: Add support FIF_OTHER_BSS filtering mode. Support for FIF_OTHER_BSS was missing. This patch adds support for this filtering mode which in turn resolves a problem where mesh interfaces would not receive broadcast traffic. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 7b62c22..52e62da 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -423,11 +423,12 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->rx.rxfilter & FIF_PSPOLL) rfilt |= ATH9K_RX_FILTER_PSPOLL; - if (sc->sec_wiphy) { + if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) { /* TODO: only needed if more than one BSSID is in use in * station/adhoc mode */ - /* TODO: for older chips, may need to add ATH9K_RX_FILTER_PROM - */ + /* The following may also be needed for other older chips */ + if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160) + rfilt |= ATH9K_RX_FILTER_PROM; rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; } -- cgit v0.10.2 From 84f6a01ce05fa671f7745b6e041e698a2d1f1341 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 20 Aug 2009 20:02:20 +0200 Subject: mac80211: fix configure_filter invocation after stop Since configure_filter can sleep now, any multicast configuration needed to be postponed to a work struct. This, however, lead to a problem that we could queue the work, stop the device and then afterwards invoke configure_filter which may lead to driver hangs and is a bug. To fix this, we can just cancel the filter work since it's unnecessary to do after stopping the hw. Since there are various places that call drv_stop, and two of them do very similar things, the code for them can be put into a shared function at the same time. Signed-off-by: Johannes Berg Reported-by: Lennert Buytenhek Tested-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 455cc7a..fa930e0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1086,6 +1086,7 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, /* Suspend/resume and hw reconfiguration */ int ieee80211_reconfig(struct ieee80211_local *local); +void ieee80211_stop_device(struct ieee80211_local *local); #ifdef CONFIG_PM int __ieee80211_suspend(struct ieee80211_hw *hw); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b161301..5940e69 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -552,11 +552,7 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_recalc_ps(local, -1); if (local->open_count == 0) { - drv_stop(local); - - ieee80211_led_radio(local, false); - - flush_workqueue(local->workqueue); + ieee80211_stop_device(local); tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index a5d2f1f..e535f1c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -107,17 +107,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) } /* stop hardware - this must stop RX */ - if (local->open_count) { - ieee80211_led_radio(local, false); - drv_stop(local); - } - - /* - * flush again, in case driver queued work -- it - * shouldn't be doing (or cancel everything in the - * stop callback) that but better safe than sorry. - */ - flush_workqueue(local->workqueue); + if (local->open_count) + ieee80211_stop_device(local); local->suspended = true; /* need suspended to be visible before quiescing is false */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5eb3063..dd65643 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1007,6 +1007,16 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, return supp_rates; } +void ieee80211_stop_device(struct ieee80211_local *local) +{ + ieee80211_led_radio(local, false); + + cancel_work_sync(&local->reconfig_filter); + drv_stop(local); + + flush_workqueue(local->workqueue); +} + int ieee80211_reconfig(struct ieee80211_local *local) { struct ieee80211_hw *hw = &local->hw; -- cgit v0.10.2 From 40ba60ddfeff8ef42fb33c0bdacfbb5f83e96b32 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 20 Aug 2009 21:00:34 +0300 Subject: rndis_wlan: fix broken logic in add_wep_key() add_wep_key() tries to check if key length is not 5 AND not 13 but uses (key_len != 5 || key_len != 13) instead. Fix this. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index d42692d..c5b921b 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1214,7 +1214,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) struct ndis_80211_wep_key ndis_key; int cipher, ret; - if ((key_len != 5 || key_len != 13) || index < 0 || index > 3) + if ((key_len != 5 && key_len != 13) || index < 0 || index > 3) return -EINVAL; if (key_len == 5) -- cgit v0.10.2 From 01a0ac417ce9b4f1216a266f2fd454cffefc5aee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 20 Aug 2009 21:36:16 +0200 Subject: cfg80211: check lost scans later, fix bug When we lose a scan, cfg80211 tries to clean up after the driver. However, it currently does this too early, it does this in GOING_DOWN already instead of DOWN, so it may happen with mac80211. Besides fixing this, also make it more robust by leaking the scan request so if the driver later actually finishes the scan, it won't crash. Also check in ___cfg80211_scan_done whether a scan request is still pending and exit if not. Reported-by: Felix Fietkau Signed-off-by: Johannes Berg Tested-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 154e1e2..9b157ca 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -664,7 +664,7 @@ static void wdev_cleanup_work(struct work_struct *work) if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { rdev->scan_req->aborted = true; - ___cfg80211_scan_done(rdev); + ___cfg80211_scan_done(rdev, true); } cfg80211_unlock_rdev(rdev); @@ -755,6 +755,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, default: break; } + break; + case NETDEV_DOWN: dev_hold(dev); schedule_work(&wdev->cleanup_work); break; diff --git a/net/wireless/core.h b/net/wireless/core.h index f565432..68eaf34 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -370,7 +370,7 @@ void cfg80211_sme_scan_done(struct net_device *dev); void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); void cfg80211_sme_disassoc(struct net_device *dev, int idx); void __cfg80211_scan_done(struct work_struct *wk); -void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); void cfg80211_upload_connect_keys(struct wireless_dev *wdev); struct ieee80211_channel * diff --git a/net/wireless/scan.c b/net/wireless/scan.c index fe575a2..7043de6 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -18,7 +18,7 @@ #define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) -void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) { struct cfg80211_scan_request *request; struct net_device *dev; @@ -26,8 +26,13 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) union iwreq_data wrqu; #endif + ASSERT_RDEV_LOCK(rdev); + request = rdev->scan_req; + if (!request) + return; + dev = request->dev; /* @@ -53,7 +58,17 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) dev_put(dev); rdev->scan_req = NULL; - kfree(request); + + /* + * OK. If this is invoked with "leak" then we can't + * free this ... but we've cleaned it up anyway. The + * driver failed to call the scan_done callback, so + * all bets are off, it might still be trying to use + * the scan request or not ... if it accesses the dev + * in there (it shouldn't anyway) then it may crash. + */ + if (!leak) + kfree(request); } void __cfg80211_scan_done(struct work_struct *wk) @@ -64,7 +79,7 @@ void __cfg80211_scan_done(struct work_struct *wk) scan_done_wk); cfg80211_lock_rdev(rdev); - ___cfg80211_scan_done(rdev); + ___cfg80211_scan_done(rdev, false); cfg80211_unlock_rdev(rdev); } -- cgit v0.10.2 From b0a4e7d8a291de63f35b04464de9ab4a83d38a7c Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 20 Aug 2009 14:48:03 -0400 Subject: libipw: switch from ieee80211_* to libipw_* naming policy This eliminates the dual definition of ieee80211_channel (and possibly others), further clarifying who defines what and paving the way for inclusion of cfg80211.h. Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/ieee80211.h b/drivers/net/wireless/ipw2x00/ieee80211.h deleted file mode 100644 index 70755c1..0000000 --- a/drivers/net/wireless/ipw2x00/ieee80211.h +++ /dev/null @@ -1,1087 +0,0 @@ -/* - * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 - * remains copyright by the original authors - * - * Portions of the merged code are based on Host AP (software wireless - * LAN access point) driver for Intersil Prism2/2.5/3. - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2003, Jouni Malinen - * - * Adaption to a generic IEEE 802.11 stack by James Ketrenos - * - * Copyright (c) 2004-2005, Intel Corporation - * - * 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 - * published by the Free Software Foundation. See README and COPYING for - * more details. - * - * API Version History - * 1.0.x -- Initial version - * 1.1.x -- Added radiotap, QoS, TIM, ieee80211_geo APIs, - * various structure changes, and crypto API init method - */ -#ifndef IEEE80211_H -#define IEEE80211_H -#include /* ETH_ALEN */ -#include /* ARRAY_SIZE */ -#include -#include - -#include - -#define IEEE80211_VERSION "git-1.1.13" - -#define IEEE80211_DATA_LEN 2304 -/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section - 6.2.1.1.2. - - The figure in section 7.1.2 suggests a body size of up to 2312 - bytes is allowed, which is a bit confusing, I suspect this - represents the 2304 bytes of real data, plus a possible 8 bytes of - WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ - -#define IEEE80211_1ADDR_LEN 10 -#define IEEE80211_2ADDR_LEN 16 -#define IEEE80211_3ADDR_LEN 24 -#define IEEE80211_4ADDR_LEN 30 -#define IEEE80211_FCS_LEN 4 -#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) -#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) - -#define MIN_FRAG_THRESHOLD 256U -#define MAX_FRAG_THRESHOLD 2346U - -/* QOS control */ -#define IEEE80211_QCTL_TID 0x000F - -/* debug macros */ - -#ifdef CONFIG_LIBIPW_DEBUG -extern u32 ieee80211_debug_level; -#define IEEE80211_DEBUG(level, fmt, args...) \ -do { if (ieee80211_debug_level & (level)) \ - printk(KERN_DEBUG "ieee80211: %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) -static inline bool ieee80211_ratelimit_debug(u32 level) -{ - return (ieee80211_debug_level & level) && net_ratelimit(); -} -#else -#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) -static inline bool ieee80211_ratelimit_debug(u32 level) -{ - return false; -} -#endif /* CONFIG_LIBIPW_DEBUG */ - -/* - * To use the debug system: - * - * If you are defining a new debug classification, simply add it to the #define - * list here in the form of: - * - * #define IEEE80211_DL_xxxx VALUE - * - * shifting value to the left one bit from the previous entry. xxxx should be - * the name of the classification (for example, WEP) - * - * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your - * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want - * to send output to that classification. - * - * To add your debug level to the list of levels seen when you perform - * - * % cat /proc/net/ieee80211/debug_level - * - * you simply need to add your entry to the ieee80211_debug_level array. - * - * If you do not see debug_level in /proc/net/ieee80211 then you do not have - * CONFIG_LIBIPW_DEBUG defined in your kernel configuration - * - */ - -#define IEEE80211_DL_INFO (1<<0) -#define IEEE80211_DL_WX (1<<1) -#define IEEE80211_DL_SCAN (1<<2) -#define IEEE80211_DL_STATE (1<<3) -#define IEEE80211_DL_MGMT (1<<4) -#define IEEE80211_DL_FRAG (1<<5) -#define IEEE80211_DL_DROP (1<<7) - -#define IEEE80211_DL_TX (1<<8) -#define IEEE80211_DL_RX (1<<9) -#define IEEE80211_DL_QOS (1<<31) - -#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) -#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) -#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) - -#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) -#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) -#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) -#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) -#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) -#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) -#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) -#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) -#define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a) -#include -#include /* ARPHRD_ETHER */ - -#ifndef WIRELESS_SPY -#define WIRELESS_SPY /* enable iwspy support */ -#endif -#include /* new driver API */ - -#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ - -#ifndef ETH_P_80211_RAW -#define ETH_P_80211_RAW (ETH_P_ECONET + 1) -#endif - -/* IEEE 802.11 defines */ - -#define P80211_OUI_LEN 3 - -struct ieee80211_snap_hdr { - - u8 dsap; /* always 0xAA */ - u8 ssap; /* always 0xAA */ - u8 ctrl; /* always 0x03 */ - u8 oui[P80211_OUI_LEN]; /* organizational universal id */ - -} __attribute__ ((packed)); - -#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) - -#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS) -#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) -#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) - -#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) -#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) - -#define IEEE80211_STATMASK_SIGNAL (1<<0) -#define IEEE80211_STATMASK_RSSI (1<<1) -#define IEEE80211_STATMASK_NOISE (1<<2) -#define IEEE80211_STATMASK_RATE (1<<3) -#define IEEE80211_STATMASK_WEMASK 0x7 - -#define IEEE80211_CCK_MODULATION (1<<0) -#define IEEE80211_OFDM_MODULATION (1<<1) - -#define IEEE80211_24GHZ_BAND (1<<0) -#define IEEE80211_52GHZ_BAND (1<<1) - -#define IEEE80211_CCK_RATE_1MB 0x02 -#define IEEE80211_CCK_RATE_2MB 0x04 -#define IEEE80211_CCK_RATE_5MB 0x0B -#define IEEE80211_CCK_RATE_11MB 0x16 -#define IEEE80211_OFDM_RATE_6MB 0x0C -#define IEEE80211_OFDM_RATE_9MB 0x12 -#define IEEE80211_OFDM_RATE_12MB 0x18 -#define IEEE80211_OFDM_RATE_18MB 0x24 -#define IEEE80211_OFDM_RATE_24MB 0x30 -#define IEEE80211_OFDM_RATE_36MB 0x48 -#define IEEE80211_OFDM_RATE_48MB 0x60 -#define IEEE80211_OFDM_RATE_54MB 0x6C -#define IEEE80211_BASIC_RATE_MASK 0x80 - -#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) -#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) -#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) -#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) -#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) -#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) -#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) -#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) -#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) -#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) -#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) -#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) - -#define IEEE80211_CCK_RATES_MASK 0x0000000F -#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ - IEEE80211_CCK_RATE_2MB_MASK) -#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ - IEEE80211_CCK_RATE_5MB_MASK | \ - IEEE80211_CCK_RATE_11MB_MASK) - -#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 -#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ - IEEE80211_OFDM_RATE_12MB_MASK | \ - IEEE80211_OFDM_RATE_24MB_MASK) -#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ - IEEE80211_OFDM_RATE_9MB_MASK | \ - IEEE80211_OFDM_RATE_18MB_MASK | \ - IEEE80211_OFDM_RATE_36MB_MASK | \ - IEEE80211_OFDM_RATE_48MB_MASK | \ - IEEE80211_OFDM_RATE_54MB_MASK) -#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ - IEEE80211_CCK_DEFAULT_RATES_MASK) - -#define IEEE80211_NUM_OFDM_RATES 8 -#define IEEE80211_NUM_CCK_RATES 4 -#define IEEE80211_OFDM_SHIFT_MASK_A 4 - -/* NOTE: This data is for statistical purposes; not all hardware provides this - * information for frames received. - * For ieee80211_rx_mgt, you need to set at least the 'len' parameter. - */ -struct ieee80211_rx_stats { - u32 mac_time; - s8 rssi; - u8 signal; - u8 noise; - u16 rate; /* in 100 kbps */ - u8 received_channel; - u8 control; - u8 mask; - u8 freq; - u16 len; - u64 tsf; - u32 beacon_time; -}; - -/* IEEE 802.11 requires that STA supports concurrent reception of at least - * three fragmented frames. This define can be increased to support more - * concurrent frames, but it should be noted that each entry can consume about - * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ -#define IEEE80211_FRAG_CACHE_LEN 4 - -struct ieee80211_frag_entry { - unsigned long first_frag_time; - unsigned int seq; - unsigned int last_frag; - struct sk_buff *skb; - u8 src_addr[ETH_ALEN]; - u8 dst_addr[ETH_ALEN]; -}; - -struct ieee80211_stats { - unsigned int tx_unicast_frames; - unsigned int tx_multicast_frames; - unsigned int tx_fragments; - unsigned int tx_unicast_octets; - unsigned int tx_multicast_octets; - unsigned int tx_deferred_transmissions; - unsigned int tx_single_retry_frames; - unsigned int tx_multiple_retry_frames; - unsigned int tx_retry_limit_exceeded; - unsigned int tx_discards; - unsigned int rx_unicast_frames; - unsigned int rx_multicast_frames; - unsigned int rx_fragments; - unsigned int rx_unicast_octets; - unsigned int rx_multicast_octets; - unsigned int rx_fcs_errors; - unsigned int rx_discards_no_buffer; - unsigned int tx_discards_wrong_sa; - unsigned int rx_discards_undecryptable; - unsigned int rx_message_in_msg_fragments; - unsigned int rx_message_in_bad_msg_fragments; -}; - -struct ieee80211_device; - -#define SEC_KEY_1 (1<<0) -#define SEC_KEY_2 (1<<1) -#define SEC_KEY_3 (1<<2) -#define SEC_KEY_4 (1<<3) -#define SEC_ACTIVE_KEY (1<<4) -#define SEC_AUTH_MODE (1<<5) -#define SEC_UNICAST_GROUP (1<<6) -#define SEC_LEVEL (1<<7) -#define SEC_ENABLED (1<<8) -#define SEC_ENCRYPT (1<<9) - -#define SEC_LEVEL_0 0 /* None */ -#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ -#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ -#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ -#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ - -#define SEC_ALG_NONE 0 -#define SEC_ALG_WEP 1 -#define SEC_ALG_TKIP 2 -#define SEC_ALG_CCMP 3 - -#define WEP_KEYS 4 -#define WEP_KEY_LEN 13 -#define SCM_KEY_LEN 32 -#define SCM_TEMPORAL_KEY_LENGTH 16 - -struct ieee80211_security { - u16 active_key:2, enabled:1, unicast_uses_group:1, encrypt:1; - u8 auth_mode; - u8 encode_alg[WEP_KEYS]; - u8 key_sizes[WEP_KEYS]; - u8 keys[WEP_KEYS][SCM_KEY_LEN]; - u8 level; - u16 flags; -} __attribute__ ((packed)); - -/* - - 802.11 data frame from AP - - ,-------------------------------------------------------------------. -Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | - |------|------|---------|---------|---------|------|---------|------| -Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | - | | tion | (BSSID) | | | ence | data | | - `-------------------------------------------------------------------' - -Total: 28-2340 bytes - -*/ - -#define BEACON_PROBE_SSID_ID_POSITION 12 - -struct ieee80211_hdr_1addr { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 payload[0]; -} __attribute__ ((packed)); - -struct ieee80211_hdr_2addr { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 payload[0]; -} __attribute__ ((packed)); - -struct ieee80211_hdr_3addr { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 payload[0]; -} __attribute__ ((packed)); - -struct ieee80211_hdr_4addr { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 addr4[ETH_ALEN]; - u8 payload[0]; -} __attribute__ ((packed)); - -struct ieee80211_hdr_3addrqos { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 payload[0]; - __le16 qos_ctl; -} __attribute__ ((packed)); - -struct ieee80211_info_element { - u8 id; - u8 len; - u8 data[0]; -} __attribute__ ((packed)); - -/* - * These are the data types that can make up management packets - * - u16 auth_algorithm; - u16 auth_sequence; - u16 beacon_interval; - u16 capability; - u8 current_ap[ETH_ALEN]; - u16 listen_interval; - struct { - u16 association_id:14, reserved:2; - } __attribute__ ((packed)); - u32 time_stamp[2]; - u16 reason; - u16 status; -*/ - -struct ieee80211_auth { - struct ieee80211_hdr_3addr header; - __le16 algorithm; - __le16 transaction; - __le16 status; - /* challenge */ - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -struct ieee80211_channel_switch { - u8 id; - u8 len; - u8 mode; - u8 channel; - u8 count; -} __attribute__ ((packed)); - -struct ieee80211_action { - struct ieee80211_hdr_3addr header; - u8 category; - u8 action; - union { - struct ieee80211_action_exchange { - u8 token; - struct ieee80211_info_element info_element[0]; - } exchange; - struct ieee80211_channel_switch channel_switch; - - } format; -} __attribute__ ((packed)); - -struct ieee80211_disassoc { - struct ieee80211_hdr_3addr header; - __le16 reason; -} __attribute__ ((packed)); - -/* Alias deauth for disassoc */ -#define ieee80211_deauth ieee80211_disassoc - -struct ieee80211_probe_request { - struct ieee80211_hdr_3addr header; - /* SSID, supported rates */ - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -struct ieee80211_probe_response { - struct ieee80211_hdr_3addr header; - __le32 time_stamp[2]; - __le16 beacon_interval; - __le16 capability; - /* SSID, supported rates, FH params, DS params, - * CF params, IBSS params, TIM (if beacon), RSN */ - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -/* Alias beacon for probe_response */ -#define ieee80211_beacon ieee80211_probe_response - -struct ieee80211_assoc_request { - struct ieee80211_hdr_3addr header; - __le16 capability; - __le16 listen_interval; - /* SSID, supported rates, RSN */ - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -struct ieee80211_reassoc_request { - struct ieee80211_hdr_3addr header; - __le16 capability; - __le16 listen_interval; - u8 current_ap[ETH_ALEN]; - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -struct ieee80211_assoc_response { - struct ieee80211_hdr_3addr header; - __le16 capability; - __le16 status; - __le16 aid; - /* supported rates */ - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -struct ieee80211_txb { - u8 nr_frags; - u8 encrypted; - u8 rts_included; - u8 reserved; - u16 frag_size; - u16 payload_size; - struct sk_buff *fragments[0]; -}; - -/* SWEEP TABLE ENTRIES NUMBER */ -#define MAX_SWEEP_TAB_ENTRIES 42 -#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 -/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs - * only use 8, and then use extended rates for the remaining supported - * rates. Other APs, however, stick all of their supported rates on the - * main rates information element... */ -#define MAX_RATES_LENGTH ((u8)12) -#define MAX_RATES_EX_LENGTH ((u8)16) -#define MAX_NETWORK_COUNT 128 - -#define CRC_LENGTH 4U - -#define MAX_WPA_IE_LEN 64 - -#define NETWORK_HAS_OFDM (1<<1) -#define NETWORK_HAS_CCK (1<<2) - -/* QoS structure */ -#define NETWORK_HAS_QOS_PARAMETERS (1<<3) -#define NETWORK_HAS_QOS_INFORMATION (1<<4) -#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \ - NETWORK_HAS_QOS_INFORMATION) - -/* 802.11h */ -#define NETWORK_HAS_POWER_CONSTRAINT (1<<5) -#define NETWORK_HAS_CSA (1<<6) -#define NETWORK_HAS_QUIET (1<<7) -#define NETWORK_HAS_IBSS_DFS (1<<8) -#define NETWORK_HAS_TPC_REPORT (1<<9) - -#define NETWORK_HAS_ERP_VALUE (1<<10) - -#define QOS_QUEUE_NUM 4 -#define QOS_OUI_LEN 3 -#define QOS_OUI_TYPE 2 -#define QOS_ELEMENT_ID 221 -#define QOS_OUI_INFO_SUB_TYPE 0 -#define QOS_OUI_PARAM_SUB_TYPE 1 -#define QOS_VERSION_1 1 -#define QOS_AIFSN_MIN_VALUE 2 - -struct ieee80211_qos_information_element { - u8 elementID; - u8 length; - u8 qui[QOS_OUI_LEN]; - u8 qui_type; - u8 qui_subtype; - u8 version; - u8 ac_info; -} __attribute__ ((packed)); - -struct ieee80211_qos_ac_parameter { - u8 aci_aifsn; - u8 ecw_min_max; - __le16 tx_op_limit; -} __attribute__ ((packed)); - -struct ieee80211_qos_parameter_info { - struct ieee80211_qos_information_element info_element; - u8 reserved; - struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; -} __attribute__ ((packed)); - -struct ieee80211_qos_parameters { - __le16 cw_min[QOS_QUEUE_NUM]; - __le16 cw_max[QOS_QUEUE_NUM]; - u8 aifs[QOS_QUEUE_NUM]; - u8 flag[QOS_QUEUE_NUM]; - __le16 tx_op_limit[QOS_QUEUE_NUM]; -} __attribute__ ((packed)); - -struct ieee80211_qos_data { - struct ieee80211_qos_parameters parameters; - int active; - int supported; - u8 param_count; - u8 old_param_count; -}; - -struct ieee80211_tim_parameters { - u8 tim_count; - u8 tim_period; -} __attribute__ ((packed)); - -/*******************************************************/ - -enum { /* ieee80211_basic_report.map */ - IEEE80211_BASIC_MAP_BSS = (1 << 0), - IEEE80211_BASIC_MAP_OFDM = (1 << 1), - IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2), - IEEE80211_BASIC_MAP_RADAR = (1 << 3), - IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4), - /* Bits 5-7 are reserved */ - -}; -struct ieee80211_basic_report { - u8 channel; - __le64 start_time; - __le16 duration; - u8 map; -} __attribute__ ((packed)); - -enum { /* ieee80211_measurement_request.mode */ - /* Bit 0 is reserved */ - IEEE80211_MEASUREMENT_ENABLE = (1 << 1), - IEEE80211_MEASUREMENT_REQUEST = (1 << 2), - IEEE80211_MEASUREMENT_REPORT = (1 << 3), - /* Bits 4-7 are reserved */ -}; - -enum { - IEEE80211_REPORT_BASIC = 0, /* required */ - IEEE80211_REPORT_CCA = 1, /* optional */ - IEEE80211_REPORT_RPI = 2, /* optional */ - /* 3-255 reserved */ -}; - -struct ieee80211_measurement_params { - u8 channel; - __le64 start_time; - __le16 duration; -} __attribute__ ((packed)); - -struct ieee80211_measurement_request { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - struct ieee80211_measurement_params params[0]; -} __attribute__ ((packed)); - -struct ieee80211_measurement_report { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - union { - struct ieee80211_basic_report basic[0]; - } u; -} __attribute__ ((packed)); - -struct ieee80211_tpc_report { - u8 transmit_power; - u8 link_margin; -} __attribute__ ((packed)); - -struct ieee80211_channel_map { - u8 channel; - u8 map; -} __attribute__ ((packed)); - -struct ieee80211_ibss_dfs { - struct ieee80211_info_element ie; - u8 owner[ETH_ALEN]; - u8 recovery_interval; - struct ieee80211_channel_map channel_map[0]; -}; - -struct ieee80211_csa { - u8 mode; - u8 channel; - u8 count; -} __attribute__ ((packed)); - -struct ieee80211_quiet { - u8 count; - u8 period; - u8 duration; - u8 offset; -} __attribute__ ((packed)); - -struct ieee80211_network { - /* These entries are used to identify a unique network */ - u8 bssid[ETH_ALEN]; - u8 channel; - /* Ensure null-terminated for any debug msgs */ - u8 ssid[IW_ESSID_MAX_SIZE + 1]; - u8 ssid_len; - - struct ieee80211_qos_data qos_data; - - /* These are network statistics */ - struct ieee80211_rx_stats stats; - u16 capability; - u8 rates[MAX_RATES_LENGTH]; - u8 rates_len; - u8 rates_ex[MAX_RATES_EX_LENGTH]; - u8 rates_ex_len; - unsigned long last_scanned; - u8 mode; - u32 flags; - u32 last_associate; - u32 time_stamp[2]; - u16 beacon_interval; - u16 listen_interval; - u16 atim_window; - u8 erp_value; - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - u8 rsn_ie[MAX_WPA_IE_LEN]; - size_t rsn_ie_len; - struct ieee80211_tim_parameters tim; - - /* 802.11h info */ - - /* Power Constraint - mandatory if spctrm mgmt required */ - u8 power_constraint; - - /* TPC Report - mandatory if spctrm mgmt required */ - struct ieee80211_tpc_report tpc_report; - - /* IBSS DFS - mandatory if spctrm mgmt required and IBSS - * NOTE: This is variable length and so must be allocated dynamically */ - struct ieee80211_ibss_dfs *ibss_dfs; - - /* Channel Switch Announcement - optional if spctrm mgmt required */ - struct ieee80211_csa csa; - - /* Quiet - optional if spctrm mgmt required */ - struct ieee80211_quiet quiet; - - struct list_head list; -}; - -enum ieee80211_state { - IEEE80211_UNINITIALIZED = 0, - IEEE80211_INITIALIZED, - IEEE80211_ASSOCIATING, - IEEE80211_ASSOCIATED, - IEEE80211_AUTHENTICATING, - IEEE80211_AUTHENTICATED, - IEEE80211_SHUTDOWN -}; - -#define DEFAULT_MAX_SCAN_AGE (15 * HZ) -#define DEFAULT_FTS 2346 - -#define CFG_IEEE80211_RESERVE_FCS (1<<0) -#define CFG_IEEE80211_COMPUTE_FCS (1<<1) -#define CFG_IEEE80211_RTS (1<<2) - -#define IEEE80211_24GHZ_MIN_CHANNEL 1 -#define IEEE80211_24GHZ_MAX_CHANNEL 14 -#define IEEE80211_24GHZ_CHANNELS (IEEE80211_24GHZ_MAX_CHANNEL - \ - IEEE80211_24GHZ_MIN_CHANNEL + 1) - -#define IEEE80211_52GHZ_MIN_CHANNEL 34 -#define IEEE80211_52GHZ_MAX_CHANNEL 165 -#define IEEE80211_52GHZ_CHANNELS (IEEE80211_52GHZ_MAX_CHANNEL - \ - IEEE80211_52GHZ_MIN_CHANNEL + 1) - -enum { - IEEE80211_CH_PASSIVE_ONLY = (1 << 0), - IEEE80211_CH_80211H_RULES = (1 << 1), - IEEE80211_CH_B_ONLY = (1 << 2), - IEEE80211_CH_NO_IBSS = (1 << 3), - IEEE80211_CH_UNIFORM_SPREADING = (1 << 4), - IEEE80211_CH_RADAR_DETECT = (1 << 5), - IEEE80211_CH_INVALID = (1 << 6), -}; - -struct ieee80211_channel { - u32 freq; /* in MHz */ - u8 channel; - u8 flags; - u8 max_power; /* in dBm */ -}; - -struct ieee80211_geo { - u8 name[4]; - u8 bg_channels; - u8 a_channels; - struct ieee80211_channel bg[IEEE80211_24GHZ_CHANNELS]; - struct ieee80211_channel a[IEEE80211_52GHZ_CHANNELS]; -}; - -struct ieee80211_device { - struct net_device *dev; - struct ieee80211_security sec; - - /* Bookkeeping structures */ - struct ieee80211_stats ieee_stats; - - struct ieee80211_geo geo; - - /* Probe / Beacon management */ - struct list_head network_free_list; - struct list_head network_list; - struct ieee80211_network *networks; - int scans; - int scan_age; - - int iw_mode; /* operating mode (IW_MODE_*) */ - struct iw_spy_data spy_data; /* iwspy support */ - - spinlock_t lock; - - int tx_headroom; /* Set to size of any additional room needed at front - * of allocated Tx SKBs */ - u32 config; - - /* WEP and other encryption related settings at the device level */ - int open_wep; /* Set to 1 to allow unencrypted frames */ - - int reset_on_keychange; /* Set to 1 if the HW needs to be reset on - * WEP key changes */ - - /* If the host performs {en,de}cryption, then set to 1 */ - int host_encrypt; - int host_encrypt_msdu; - int host_decrypt; - /* host performs multicast decryption */ - int host_mc_decrypt; - - /* host should strip IV and ICV from protected frames */ - /* meaningful only when hardware decryption is being used */ - int host_strip_iv_icv; - - int host_open_frag; - int host_build_iv; - int ieee802_1x; /* is IEEE 802.1X used */ - - /* WPA data */ - int wpa_enabled; - int drop_unencrypted; - int privacy_invoked; - size_t wpa_ie_len; - u8 *wpa_ie; - - struct lib80211_crypt_info crypt_info; - - int bcrx_sta_key; /* use individual keys to override default keys even - * with RX of broad/multicast frames */ - - /* Fragmentation structures */ - struct ieee80211_frag_entry frag_cache[IEEE80211_FRAG_CACHE_LEN]; - unsigned int frag_next_idx; - u16 fts; /* Fragmentation Threshold */ - u16 rts; /* RTS threshold */ - - /* Association info */ - u8 bssid[ETH_ALEN]; - - enum ieee80211_state state; - - int mode; /* A, B, G */ - int modulation; /* CCK, OFDM */ - int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ - int abg_true; /* ABG flag */ - - int perfect_rssi; - int worst_rssi; - - u16 prev_seq_ctl; /* used to drop duplicate frames */ - - /* Callback functions */ - void (*set_security) (struct net_device * dev, - struct ieee80211_security * sec); - int (*hard_start_xmit) (struct ieee80211_txb * txb, - struct net_device * dev, int pri); - int (*reset_port) (struct net_device * dev); - int (*is_queue_full) (struct net_device * dev, int pri); - - int (*handle_management) (struct net_device * dev, - struct ieee80211_network * network, u16 type); - int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb); - - /* Typical STA methods */ - int (*handle_auth) (struct net_device * dev, - struct ieee80211_auth * auth); - int (*handle_deauth) (struct net_device * dev, - struct ieee80211_deauth * auth); - int (*handle_action) (struct net_device * dev, - struct ieee80211_action * action, - struct ieee80211_rx_stats * stats); - int (*handle_disassoc) (struct net_device * dev, - struct ieee80211_disassoc * assoc); - int (*handle_beacon) (struct net_device * dev, - struct ieee80211_beacon * beacon, - struct ieee80211_network * network); - int (*handle_probe_response) (struct net_device * dev, - struct ieee80211_probe_response * resp, - struct ieee80211_network * network); - int (*handle_probe_request) (struct net_device * dev, - struct ieee80211_probe_request * req, - struct ieee80211_rx_stats * stats); - int (*handle_assoc_response) (struct net_device * dev, - struct ieee80211_assoc_response * resp, - struct ieee80211_network * network); - - /* Typical AP methods */ - int (*handle_assoc_request) (struct net_device * dev); - int (*handle_reassoc_request) (struct net_device * dev, - struct ieee80211_reassoc_request * req); - - /* This must be the last item so that it points to the data - * allocated beyond this structure by alloc_ieee80211 */ - u8 priv[0]; -}; - -#define IEEE_A (1<<0) -#define IEEE_B (1<<1) -#define IEEE_G (1<<2) -#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) - -static inline void *ieee80211_priv(struct net_device *dev) -{ - return ((struct ieee80211_device *)netdev_priv(dev))->priv; -} - -static inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, - int mode) -{ - /* - * It is possible for both access points and our device to support - * combinations of modes, so as long as there is one valid combination - * of ap/device supported modes, then return success - * - */ - if ((mode & IEEE_A) && - (ieee->modulation & IEEE80211_OFDM_MODULATION) && - (ieee->freq_band & IEEE80211_52GHZ_BAND)) - return 1; - - if ((mode & IEEE_G) && - (ieee->modulation & IEEE80211_OFDM_MODULATION) && - (ieee->freq_band & IEEE80211_24GHZ_BAND)) - return 1; - - if ((mode & IEEE_B) && - (ieee->modulation & IEEE80211_CCK_MODULATION) && - (ieee->freq_band & IEEE80211_24GHZ_BAND)) - return 1; - - return 0; -} - -static inline int ieee80211_get_hdrlen(u16 fc) -{ - int hdrlen = IEEE80211_3ADDR_LEN; - u16 stype = WLAN_FC_GET_STYPE(fc); - - switch (WLAN_FC_GET_TYPE(fc)) { - case IEEE80211_FTYPE_DATA: - if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) - hdrlen = IEEE80211_4ADDR_LEN; - if (stype & IEEE80211_STYPE_QOS_DATA) - hdrlen += 2; - break; - case IEEE80211_FTYPE_CTL: - switch (WLAN_FC_GET_STYPE(fc)) { - case IEEE80211_STYPE_CTS: - case IEEE80211_STYPE_ACK: - hdrlen = IEEE80211_1ADDR_LEN; - break; - default: - hdrlen = IEEE80211_2ADDR_LEN; - break; - } - break; - } - - return hdrlen; -} - -static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr) -{ - switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control))) { - case IEEE80211_1ADDR_LEN: - return ((struct ieee80211_hdr_1addr *)hdr)->payload; - case IEEE80211_2ADDR_LEN: - return ((struct ieee80211_hdr_2addr *)hdr)->payload; - case IEEE80211_3ADDR_LEN: - return ((struct ieee80211_hdr_3addr *)hdr)->payload; - case IEEE80211_4ADDR_LEN: - return ((struct ieee80211_hdr_4addr *)hdr)->payload; - } - return NULL; -} - -static inline int ieee80211_is_ofdm_rate(u8 rate) -{ - switch (rate & ~IEEE80211_BASIC_RATE_MASK) { - case IEEE80211_OFDM_RATE_6MB: - case IEEE80211_OFDM_RATE_9MB: - case IEEE80211_OFDM_RATE_12MB: - case IEEE80211_OFDM_RATE_18MB: - case IEEE80211_OFDM_RATE_24MB: - case IEEE80211_OFDM_RATE_36MB: - case IEEE80211_OFDM_RATE_48MB: - case IEEE80211_OFDM_RATE_54MB: - return 1; - } - return 0; -} - -static inline int ieee80211_is_cck_rate(u8 rate) -{ - switch (rate & ~IEEE80211_BASIC_RATE_MASK) { - case IEEE80211_CCK_RATE_1MB: - case IEEE80211_CCK_RATE_2MB: - case IEEE80211_CCK_RATE_5MB: - case IEEE80211_CCK_RATE_11MB: - return 1; - } - return 0; -} - -/* ieee80211.c */ -extern void free_ieee80211(struct net_device *dev); -extern struct net_device *alloc_ieee80211(int sizeof_priv); -extern int ieee80211_change_mtu(struct net_device *dev, int new_mtu); - -extern void ieee80211_networks_age(struct ieee80211_device *ieee, - unsigned long age_secs); - -extern int ieee80211_set_encryption(struct ieee80211_device *ieee); - -/* ieee80211_tx.c */ -extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev); -extern void ieee80211_txb_free(struct ieee80211_txb *); - -/* ieee80211_rx.c */ -extern void ieee80211_rx_any(struct ieee80211_device *ieee, - struct sk_buff *skb, struct ieee80211_rx_stats *stats); -extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats); -/* make sure to set stats->len */ -extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *header, - struct ieee80211_rx_stats *stats); -extern void ieee80211_network_reset(struct ieee80211_network *network); - -/* ieee80211_geo.c */ -extern const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device - *ieee); -extern int ieee80211_set_geo(struct ieee80211_device *ieee, - const struct ieee80211_geo *geo); - -extern int ieee80211_is_valid_channel(struct ieee80211_device *ieee, - u8 channel); -extern int ieee80211_channel_to_index(struct ieee80211_device *ieee, - u8 channel); -extern u8 ieee80211_freq_to_channel(struct ieee80211_device *ieee, u32 freq); -extern u8 ieee80211_get_channel_flags(struct ieee80211_device *ieee, - u8 channel); -extern const struct ieee80211_channel *ieee80211_get_channel(struct - ieee80211_device - *ieee, u8 channel); -extern u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, - u8 channel); - -/* ieee80211_wx.c */ -extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -extern int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); -extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -static inline void ieee80211_increment_scans(struct ieee80211_device *ieee) -{ - ieee->scans++; -} - -static inline int ieee80211_get_scans(struct ieee80211_device *ieee) -{ - return ieee->scans; -} - -#endif /* IEEE80211_H */ diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index dee50ed..33bdb20 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -1673,7 +1673,7 @@ static int ipw2100_start_scan(struct ipw2100_priv *priv) return err; } -static const struct ieee80211_geo ipw_geos[] = { +static const struct libipw_geo ipw_geos[] = { { /* Restricted */ "---", .bg_channels = 14, @@ -1694,7 +1694,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) /* Age scan list entries found before suspend */ if (priv->suspend_time) { - ieee80211_networks_age(priv->ieee, priv->suspend_time); + libipw_networks_age(priv->ieee, priv->suspend_time); priv->suspend_time = 0; } @@ -1752,11 +1752,11 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) } /* Initialize the geo */ - if (ieee80211_set_geo(priv->ieee, &ipw_geos[0])) { + if (libipw_set_geo(priv->ieee, &ipw_geos[0])) { printk(KERN_WARNING DRV_NAME "Could not set geo\n"); return 0; } - priv->ieee->freq_band = IEEE80211_24GHZ_BAND; + priv->ieee->freq_band = LIBIPW_24GHZ_BAND; lock = LOCK_NONE; if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) { @@ -1817,7 +1817,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) /* Called by register_netdev() */ static int ipw2100_net_init(struct net_device *dev) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); return ipw2100_up(priv, 1); } @@ -2340,8 +2340,8 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf, * * When packet is provided by the firmware, it contains the following: * - * . ieee80211_hdr - * . ieee80211_snap_hdr + * . libipw_hdr + * . libipw_snap_hdr * * The size of the constructed ethernet * @@ -2396,7 +2396,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i) } static void isr_rx(struct ipw2100_priv *priv, int i, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct net_device *dev = priv->net_dev; struct ipw2100_status *status = &priv->status_queue.drv[i]; @@ -2435,13 +2435,13 @@ static void isr_rx(struct ipw2100_priv *priv, int i, #ifdef IPW2100_RX_DEBUG /* Make a copy of the frame so we can dump it to the logs if - * ieee80211_rx fails */ + * libipw_rx fails */ skb_copy_from_linear_data(packet->skb, packet_data, min_t(u32, status->frame_size, IPW_RX_NIC_BUFFER_LENGTH)); #endif - if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { + if (!libipw_rx(priv->ieee, packet->skb, stats)) { #ifdef IPW2100_RX_DEBUG IPW_DEBUG_DROP("%s: Non consumed packet:\n", dev->name); @@ -2449,7 +2449,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i, #endif dev->stats.rx_errors++; - /* ieee80211_rx failed, so it didn't free the SKB */ + /* libipw_rx failed, so it didn't free the SKB */ dev_kfree_skb_any(packet->skb); packet->skb = NULL; } @@ -2470,7 +2470,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i, #ifdef CONFIG_IPW2100_MONITOR static void isr_rx_monitor(struct ipw2100_priv *priv, int i, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct net_device *dev = priv->net_dev; struct ipw2100_status *status = &priv->status_queue.drv[i]; @@ -2528,10 +2528,10 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i, skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr)); - if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { + if (!libipw_rx(priv->ieee, packet->skb, stats)) { dev->stats.rx_errors++; - /* ieee80211_rx failed, so it didn't free the SKB */ + /* libipw_rx failed, so it didn't free the SKB */ dev_kfree_skb_any(packet->skb); packet->skb = NULL; } @@ -2615,7 +2615,7 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) u16 frame_type; u32 r, w, i, s; struct ipw2100_rx *u; - struct ieee80211_rx_stats stats = { + struct libipw_rx_stats stats = { .mac_time = jiffies, }; @@ -2661,8 +2661,8 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) stats.mask = 0; if (stats.rssi != 0) - stats.mask |= IEEE80211_STATMASK_RSSI; - stats.freq = IEEE80211_24GHZ_BAND; + stats.mask |= LIBIPW_STATMASK_RSSI; + stats.freq = LIBIPW_24GHZ_BAND; IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n", priv->net_dev->name, frame_types[frame_type], @@ -2686,11 +2686,11 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) break; } #endif - if (stats.len < sizeof(struct ieee80211_hdr_3addr)) + if (stats.len < sizeof(struct libipw_hdr_3addr)) break; switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) { case IEEE80211_FTYPE_MGMT: - ieee80211_rx_mgt(priv->ieee, + libipw_rx_mgt(priv->ieee, &u->rx_data.header, &stats); break; @@ -2884,7 +2884,7 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv) tbd->buf_length, PCI_DMA_TODEVICE); } - ieee80211_txb_free(packet->info.d_struct.txb); + libipw_txb_free(packet->info.d_struct.txb); packet->info.d_struct.txb = NULL; list_add_tail(element, &priv->tx_free_list); @@ -3028,7 +3028,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) int next = txq->next; int i = 0; struct ipw2100_data_header *ipw_hdr; - struct ieee80211_hdr_3addr *hdr; + struct libipw_hdr_3addr *hdr; while (!list_empty(&priv->tx_pend_list)) { /* if there isn't enough space in TBD queue, then @@ -3062,7 +3062,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) packet->index = txq->next; ipw_hdr = packet->info.d_struct.data; - hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb-> + hdr = (struct libipw_hdr_3addr *)packet->info.d_struct.txb-> fragments[0]->data; if (priv->ieee->iw_mode == IW_MODE_INFRA) { @@ -3086,7 +3086,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) if (packet->info.d_struct.txb->nr_frags > 1) ipw_hdr->fragment_size = packet->info.d_struct.txb->frag_size - - IEEE80211_3ADDR_LEN; + LIBIPW_3ADDR_LEN; else ipw_hdr->fragment_size = 0; @@ -3119,13 +3119,13 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; tbd->buf_length = packet->info.d_struct.txb-> - fragments[i]->len - IEEE80211_3ADDR_LEN; + fragments[i]->len - LIBIPW_3ADDR_LEN; tbd->host_addr = pci_map_single(priv->pci_dev, packet->info.d_struct. txb->fragments[i]-> data + - IEEE80211_3ADDR_LEN, + LIBIPW_3ADDR_LEN, tbd->buf_length, PCI_DMA_TODEVICE); @@ -3330,10 +3330,10 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data) return IRQ_NONE; } -static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev, +static int ipw2100_tx(struct libipw_txb *txb, struct net_device *dev, int pri) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct list_head *element; struct ipw2100_tx_packet *packet; unsigned long flags; @@ -4488,7 +4488,7 @@ static void ipw2100_tx_initialize(struct ipw2100_priv *priv) /* We simply drop any SKBs that have been queued for * transmit */ if (priv->tx_buffers[i].info.d_struct.txb) { - ieee80211_txb_free(priv->tx_buffers[i].info.d_struct. + libipw_txb_free(priv->tx_buffers[i].info.d_struct. txb); priv->tx_buffers[i].info.d_struct.txb = NULL; } @@ -4527,7 +4527,7 @@ static void ipw2100_tx_free(struct ipw2100_priv *priv) for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { if (priv->tx_buffers[i].info.d_struct.txb) { - ieee80211_txb_free(priv->tx_buffers[i].info.d_struct. + libipw_txb_free(priv->tx_buffers[i].info.d_struct. txb); priv->tx_buffers[i].info.d_struct.txb = NULL; } @@ -5558,9 +5558,9 @@ static void ipw2100_security_work(struct work_struct *work) } static void shim__set_security(struct net_device *dev, - struct ieee80211_security *sec) + struct libipw_security *sec) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int i, force_update = 0; mutex_lock(&priv->action_mutex); @@ -5753,7 +5753,7 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv) * method as well) to talk to the firmware */ static int ipw2100_set_address(struct net_device *dev, void *p) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct sockaddr *addr = p; int err = 0; @@ -5781,7 +5781,7 @@ static int ipw2100_set_address(struct net_device *dev, void *p) static int ipw2100_open(struct net_device *dev) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); unsigned long flags; IPW_DEBUG_INFO("dev->open\n"); @@ -5797,7 +5797,7 @@ static int ipw2100_open(struct net_device *dev) static int ipw2100_close(struct net_device *dev) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); unsigned long flags; struct list_head *element; struct ipw2100_tx_packet *packet; @@ -5818,7 +5818,7 @@ static int ipw2100_close(struct net_device *dev) list_del(element); DEC_STAT(&priv->tx_pend_stat); - ieee80211_txb_free(packet->info.d_struct.txb); + libipw_txb_free(packet->info.d_struct.txb); packet->info.d_struct.txb = NULL; list_add_tail(element, &priv->tx_free_list); @@ -5836,7 +5836,7 @@ static int ipw2100_close(struct net_device *dev) */ static void ipw2100_tx_timeout(struct net_device *dev) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); dev->stats.tx_errors++; @@ -5861,8 +5861,8 @@ static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value) static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value) { - struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_security sec = { + struct libipw_device *ieee = priv->ieee; + struct libipw_security sec = { .flags = SEC_AUTH_MODE, }; int ret = 0; @@ -5907,7 +5907,7 @@ static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, static void ipw_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); char fw_ver[64], ucode_ver[64]; strcpy(info->driver, DRV_NAME); @@ -5924,7 +5924,7 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev, static u32 ipw2100_ethtool_get_link(struct net_device *dev) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); return (priv->status & STATUS_ASSOCIATED) ? 1 : 0; } @@ -6011,8 +6011,8 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv); static const struct net_device_ops ipw2100_netdev_ops = { .ndo_open = ipw2100_open, .ndo_stop = ipw2100_close, - .ndo_start_xmit = ieee80211_xmit, - .ndo_change_mtu = ieee80211_change_mtu, + .ndo_start_xmit = libipw_xmit, + .ndo_change_mtu = libipw_change_mtu, .ndo_init = ipw2100_net_init, .ndo_tx_timeout = ipw2100_tx_timeout, .ndo_set_mac_address = ipw2100_set_address, @@ -6032,7 +6032,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, dev = alloc_ieee80211(sizeof(struct ipw2100_priv)); if (!dev) return NULL; - priv = ieee80211_priv(dev); + priv = libipw_priv(dev); priv->ieee = netdev_priv(dev); priv->pci_dev = pci_dev; priv->net_dev = dev; @@ -6046,7 +6046,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, dev->netdev_ops = &ipw2100_netdev_ops; dev->ethtool_ops = &ipw2100_ethtool_ops; dev->wireless_handlers = &ipw2100_wx_handler_def; - priv->wireless_data.ieee80211 = priv->ieee; + priv->wireless_data.libipw = priv->ieee; dev->wireless_data = &priv->wireless_data; dev->watchdog_timeo = 3 * HZ; dev->irq = 0; @@ -6202,7 +6202,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, return err; } - priv = ieee80211_priv(dev); + priv = libipw_priv(dev); pci_set_master(pci_dev); pci_set_drvdata(pci_dev, priv); @@ -6629,7 +6629,7 @@ static int ipw2100_wx_get_name(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (!(priv->status & STATUS_ASSOCIATED)) strcpy(wrqu->name, "unassociated"); else @@ -6643,7 +6643,7 @@ static int ipw2100_wx_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct iw_freq *fwrq = &wrqu->freq; int err = 0; @@ -6693,7 +6693,7 @@ static int ipw2100_wx_get_freq(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->freq.e = 0; @@ -6714,7 +6714,7 @@ static int ipw2100_wx_set_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0; IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode); @@ -6757,7 +6757,7 @@ static int ipw2100_wx_get_mode(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->mode = priv->ieee->iw_mode; IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode); @@ -6792,7 +6792,7 @@ static int ipw2100_wx_get_range(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct iw_range *range = (struct iw_range *)extra; u16 val; int i, level; @@ -6913,7 +6913,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0; static const unsigned char any[] = { @@ -6962,7 +6962,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -6980,7 +6980,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); char *essid = ""; /* ANY */ int length = 0; int err = 0; @@ -7035,7 +7035,7 @@ static int ipw2100_wx_get_essid(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); DECLARE_SSID_BUF(ssid); /* If we are associated, trying to associate, or have a statically @@ -7063,7 +7063,7 @@ static int ipw2100_wx_set_nick(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (wrqu->data.length > IW_ESSID_MAX_SIZE) return -E2BIG; @@ -7085,7 +7085,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->data.length = strlen(priv->nick); memcpy(extra, priv->nick, wrqu->data.length); @@ -7100,7 +7100,7 @@ static int ipw2100_wx_set_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); u32 target_rate = wrqu->bitrate.value; u32 rate; int err = 0; @@ -7140,7 +7140,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int val; unsigned int len = sizeof(val); int err = 0; @@ -7192,7 +7192,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int value, err; /* Auto RTS not yet supported */ @@ -7231,7 +7231,7 @@ static int ipw2100_wx_get_rts(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED; wrqu->rts.fixed = 1; /* no auto select */ @@ -7248,7 +7248,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0, value; if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled)) @@ -7293,7 +7293,7 @@ static int ipw2100_wx_get_txpow(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; @@ -7320,7 +7320,7 @@ static int ipw2100_wx_set_frag(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (!wrqu->frag.fixed) return -EINVAL; @@ -7350,7 +7350,7 @@ static int ipw2100_wx_get_frag(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED; wrqu->frag.fixed = 0; /* no auto select */ wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0; @@ -7364,7 +7364,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0; if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled) @@ -7412,7 +7412,7 @@ static int ipw2100_wx_get_retry(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->retry.disabled = 0; /* can't be disabled */ @@ -7440,7 +7440,7 @@ static int ipw2100_wx_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0; mutex_lock(&priv->action_mutex); @@ -7472,8 +7472,8 @@ static int ipw2100_wx_get_scan(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra); + struct ipw2100_priv *priv = libipw_priv(dev); + return libipw_wx_get_scan(priv->ieee, info, wrqu, extra); } /* @@ -7487,8 +7487,8 @@ static int ipw2100_wx_set_encode(struct net_device *dev, * No check of STATUS_INITIALIZED required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); + struct ipw2100_priv *priv = libipw_priv(dev); + return libipw_wx_set_encode(priv->ieee, info, wrqu, key); } static int ipw2100_wx_get_encode(struct net_device *dev, @@ -7499,15 +7499,15 @@ static int ipw2100_wx_get_encode(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key); + struct ipw2100_priv *priv = libipw_priv(dev); + return libipw_wx_get_encode(priv->ieee, info, wrqu, key); } static int ipw2100_wx_set_power(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0; mutex_lock(&priv->action_mutex); @@ -7556,7 +7556,7 @@ static int ipw2100_wx_get_power(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (!(priv->power_mode & IPW_POWER_ENABLED)) wrqu->power.disabled = 1; @@ -7580,8 +7580,8 @@ static int ipw2100_wx_set_genie(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw2100_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; u8 *buf; if (!ieee->wpa_enabled) @@ -7615,8 +7615,8 @@ static int ipw2100_wx_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw2100_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { wrqu->data.length = 0; @@ -7637,8 +7637,8 @@ static int ipw2100_wx_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw2100_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; struct lib80211_crypt_data *crypt; unsigned long flags; @@ -7682,7 +7682,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev, * can use this to determine if the CAP_PRIVACY_ON bit should * be set. */ - struct ieee80211_security sec = { + struct libipw_security sec = { .flags = SEC_ENABLED, .enabled = param->value, }; @@ -7730,8 +7730,8 @@ static int ipw2100_wx_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw2100_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; int ret = 0; @@ -7792,8 +7792,8 @@ static int ipw2100_wx_set_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra); + struct ipw2100_priv *priv = libipw_priv(dev); + return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra); } /* SIOCGIWENCODEEXT */ @@ -7801,8 +7801,8 @@ static int ipw2100_wx_get_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra); + struct ipw2100_priv *priv = libipw_priv(dev); + return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra); } /* SIOCSIWMLME */ @@ -7810,7 +7810,7 @@ static int ipw2100_wx_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct iw_mlme *mlme = (struct iw_mlme *)extra; __le16 reason; @@ -7841,7 +7841,7 @@ static int ipw2100_wx_set_promisc(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int *parms = (int *)extra; int enable = (parms[0] > 0); int err = 0; @@ -7872,7 +7872,7 @@ static int ipw2100_wx_reset(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (priv->status & STATUS_INITIALIZED) schedule_reset(priv); return 0; @@ -7884,7 +7884,7 @@ static int ipw2100_wx_set_powermode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0, mode = *(int *)extra; mutex_lock(&priv->action_mutex); @@ -7912,7 +7912,7 @@ static int ipw2100_wx_get_powermode(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int level = IPW_POWER_LEVEL(priv->power_mode); s32 timeout, period; @@ -7948,7 +7948,7 @@ static int ipw2100_wx_set_preamble(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err, mode = *(int *)extra; mutex_lock(&priv->action_mutex); @@ -7981,7 +7981,7 @@ static int ipw2100_wx_get_preamble(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (priv->config & CFG_LONG_PREAMBLE) snprintf(wrqu->name, IFNAMSIZ, "long (1)"); @@ -7996,7 +7996,7 @@ static int ipw2100_wx_set_crc_check(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err, mode = *(int *)extra; mutex_lock(&priv->action_mutex); @@ -8028,7 +8028,7 @@ static int ipw2100_wx_get_crc_check(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (priv->config & CFG_CRC_CHECK) snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)"); @@ -8181,7 +8181,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) int beacon_qual; int quality; - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct iw_statistics *wstats; u32 rssi, tx_retries, missed_beacons, tx_failures; u32 ord_len = sizeof(u32); diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h index f183d95..af175bd 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/ipw2x00/ipw2100.h @@ -46,7 +46,7 @@ #include #include -#include "ieee80211.h" +#include "libipw.h" struct ipw2100_priv; struct ipw2100_tx_packet; @@ -343,7 +343,7 @@ struct ipw2100_tx_packet { struct { /* DATA */ struct ipw2100_data_header *data; dma_addr_t data_phys; - struct ieee80211_txb *txb; + struct libipw_txb *txb; } d_struct; } info; int jiffy_start; @@ -492,7 +492,7 @@ struct ipw2100_priv { int stop_hang_check; /* Set 1 when shutting down to kill hang_check */ int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */ - struct ieee80211_device *ieee; + struct libipw_device *ieee; unsigned long status; unsigned long config; unsigned long capability; @@ -788,7 +788,7 @@ struct ipw2100_priv { #define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli #define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli -#define IPW_HEADER_802_11_SIZE sizeof(struct ieee80211_hdr_3addr) +#define IPW_HEADER_802_11_SIZE sizeof(struct libipw_hdr_3addr) #define IPW_MAX_80211_PAYLOAD_SIZE 2304U #define IPW_MAX_802_11_PAYLOAD_LENGTH 2312 #define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH 1536 @@ -803,13 +803,13 @@ struct ipw2100_priv { IPW_802_11_FCS_LENGTH) #define IPW_802_11_PAYLOAD_OFFSET \ - (sizeof(struct ieee80211_hdr_3addr) + \ - sizeof(struct ieee80211_snap_hdr)) + (sizeof(struct libipw_hdr_3addr) + \ + sizeof(struct libipw_snap_hdr)) struct ipw2100_rx { union { unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH]; - struct ieee80211_hdr_4addr header; + struct libipw_hdr_4addr header; u32 status; struct ipw2100_notification notification; struct ipw2100_cmd_header command; diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 8e18d53..3617e3c 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -111,7 +111,7 @@ static int qos_no_ack_mask = 0; static int burst_duration_CCK = 0; static int burst_duration_OFDM = 0; -static struct ieee80211_qos_parameters def_qos_parameters_OFDM = { +static struct libipw_qos_parameters def_qos_parameters_OFDM = { {QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM, QOS_TX3_CW_MIN_OFDM}, {QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM, @@ -122,7 +122,7 @@ static struct ieee80211_qos_parameters def_qos_parameters_OFDM = { QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM} }; -static struct ieee80211_qos_parameters def_qos_parameters_CCK = { +static struct libipw_qos_parameters def_qos_parameters_CCK = { {QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK, QOS_TX3_CW_MIN_CCK}, {QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK, @@ -133,7 +133,7 @@ static struct ieee80211_qos_parameters def_qos_parameters_CCK = { QOS_TX3_TXOP_LIMIT_CCK} }; -static struct ieee80211_qos_parameters def_parameters_OFDM = { +static struct libipw_qos_parameters def_parameters_OFDM = { {DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM, DEF_TX3_CW_MIN_OFDM}, {DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM, @@ -144,7 +144,7 @@ static struct ieee80211_qos_parameters def_parameters_OFDM = { DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM} }; -static struct ieee80211_qos_parameters def_parameters_CCK = { +static struct libipw_qos_parameters def_parameters_CCK = { {DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK, DEF_TX3_CW_MIN_CCK}, {DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK, @@ -164,9 +164,9 @@ static int from_priority_to_tx_queue[] = { static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv); -static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters +static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters *qos_param); -static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element +static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element *qos_param); #endif /* CONFIG_IPW2200_QOS */ @@ -1830,7 +1830,7 @@ static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, break; } - if (ieee80211_is_valid_channel(priv->ieee, channel)) + if (libipw_is_valid_channel(priv->ieee, channel)) priv->speed_scan[pos++] = channel; else IPW_WARNING("Skipping invalid channel request: %d\n", @@ -1882,7 +1882,7 @@ static ssize_t show_channels(struct device *d, char *buf) { struct ipw_priv *priv = dev_get_drvdata(d); - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); int len = 0, i; len = sprintf(&buf[len], @@ -1892,14 +1892,14 @@ static ssize_t show_channels(struct device *d, for (i = 0; i < geo->bg_channels; i++) { len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n", geo->bg[i].channel, - geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ? + geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT ? " (radar spectrum)" : "", - ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) || - (geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT)) + ((geo->bg[i].flags & LIBIPW_CH_NO_IBSS) || + (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)) ? "" : ", IBSS", - geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ? + geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY ? "passive only" : "active/passive", - geo->bg[i].flags & IEEE80211_CH_B_ONLY ? + geo->bg[i].flags & LIBIPW_CH_B_ONLY ? "B" : "B/G"); } @@ -1909,12 +1909,12 @@ static ssize_t show_channels(struct device *d, for (i = 0; i < geo->a_channels; i++) { len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n", geo->a[i].channel, - geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ? + geo->a[i].flags & LIBIPW_CH_RADAR_DETECT ? " (radar spectrum)" : "", - ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) || - (geo->a[i].flags & IEEE80211_CH_RADAR_DETECT)) + ((geo->a[i].flags & LIBIPW_CH_NO_IBSS) || + (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)) ? "" : ", IBSS", - geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ? + geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY ? "passive only" : "active/passive"); } @@ -2429,7 +2429,7 @@ static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) static int ipw_set_tx_power(struct ipw_priv *priv) { - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); struct ipw_tx_power tx_power; s8 max_power; int i; @@ -2960,12 +2960,12 @@ static int ipw_fw_dma_wait(struct ipw_priv *priv) static void ipw_remove_current_network(struct ipw_priv *priv) { struct list_head *element, *safe; - struct ieee80211_network *network = NULL; + struct libipw_network *network = NULL; unsigned long flags; spin_lock_irqsave(&priv->ieee->lock, flags); list_for_each_safe(element, safe, &priv->ieee->network_list) { - network = list_entry(element, struct ieee80211_network, list); + network = list_entry(element, struct libipw_network, list); if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { list_del(element); list_add_tail(&network->list, @@ -3751,7 +3751,7 @@ static void ipw_queue_tx_free_tfd(struct ipw_priv *priv, le16_to_cpu(bd->u.data.chunk_len[i]), PCI_DMA_TODEVICE); if (txq->txb[txq->q.last_used]) { - ieee80211_txb_free(txq->txb[txq->q.last_used]); + libipw_txb_free(txq->txb[txq->q.last_used]); txq->txb[txq->q.last_used] = NULL; } } @@ -4070,7 +4070,7 @@ static u32 ipw_get_max_rate(struct ipw_priv *priv) /* If currently associated in B mode, restrict the maximum * rate match to B rates */ if (priv->assoc_request.ieee_mode == IPW_B_MODE) - mask &= IEEE80211_CCK_RATES_MASK; + mask &= LIBIPW_CCK_RATES_MASK; /* TODO: Verify that the rate is supported by the current rates * list. */ @@ -4078,29 +4078,29 @@ static u32 ipw_get_max_rate(struct ipw_priv *priv) while (i && !(mask & i)) i >>= 1; switch (i) { - case IEEE80211_CCK_RATE_1MB_MASK: + case LIBIPW_CCK_RATE_1MB_MASK: return 1000000; - case IEEE80211_CCK_RATE_2MB_MASK: + case LIBIPW_CCK_RATE_2MB_MASK: return 2000000; - case IEEE80211_CCK_RATE_5MB_MASK: + case LIBIPW_CCK_RATE_5MB_MASK: return 5500000; - case IEEE80211_OFDM_RATE_6MB_MASK: + case LIBIPW_OFDM_RATE_6MB_MASK: return 6000000; - case IEEE80211_OFDM_RATE_9MB_MASK: + case LIBIPW_OFDM_RATE_9MB_MASK: return 9000000; - case IEEE80211_CCK_RATE_11MB_MASK: + case LIBIPW_CCK_RATE_11MB_MASK: return 11000000; - case IEEE80211_OFDM_RATE_12MB_MASK: + case LIBIPW_OFDM_RATE_12MB_MASK: return 12000000; - case IEEE80211_OFDM_RATE_18MB_MASK: + case LIBIPW_OFDM_RATE_18MB_MASK: return 18000000; - case IEEE80211_OFDM_RATE_24MB_MASK: + case LIBIPW_OFDM_RATE_24MB_MASK: return 24000000; - case IEEE80211_OFDM_RATE_36MB_MASK: + case LIBIPW_OFDM_RATE_36MB_MASK: return 36000000; - case IEEE80211_OFDM_RATE_48MB_MASK: + case LIBIPW_OFDM_RATE_48MB_MASK: return 48000000; - case IEEE80211_OFDM_RATE_54MB_MASK: + case LIBIPW_OFDM_RATE_54MB_MASK: return 54000000; } @@ -4466,11 +4466,11 @@ static void ipw_rx_notification(struct ipw_priv *priv, == IEEE80211_STYPE_ASSOC_RESP)) { if ((sizeof (struct - ieee80211_assoc_response) + libipw_assoc_response) <= size) && (size <= 2314)) { struct - ieee80211_rx_stats + libipw_rx_stats stats = { .len = size - 1, }; @@ -4478,10 +4478,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG_QOS ("QoS Associate " "size %d\n", size); - ieee80211_rx_mgt(priv-> + libipw_rx_mgt(priv-> ieee, (struct - ieee80211_hdr_4addr + libipw_hdr_4addr *) ¬if->u.raw, &stats); } @@ -4537,11 +4537,11 @@ static void ipw_rx_notification(struct ipw_priv *priv, case CMAS_INIT:{ if (priv->status & STATUS_AUTH) { struct - ieee80211_assoc_response + libipw_assoc_response *resp; resp = (struct - ieee80211_assoc_response + libipw_assoc_response *)¬if->u.raw; IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | @@ -5227,33 +5227,33 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv) static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate) { - rate &= ~IEEE80211_BASIC_RATE_MASK; + rate &= ~LIBIPW_BASIC_RATE_MASK; if (ieee_mode == IEEE_A) { switch (rate) { - case IEEE80211_OFDM_RATE_6MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? + case LIBIPW_OFDM_RATE_6MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_9MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? + case LIBIPW_OFDM_RATE_9MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_12MB: + case LIBIPW_OFDM_RATE_12MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_18MB: + rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_18MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_24MB: + rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_24MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_36MB: + rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_36MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_48MB: + rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_48MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_54MB: + rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_54MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0; + rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0; default: return 0; } @@ -5261,14 +5261,14 @@ static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate) /* B and G mixed */ switch (rate) { - case IEEE80211_CCK_RATE_1MB: - return priv->rates_mask & IEEE80211_CCK_RATE_1MB_MASK ? 1 : 0; - case IEEE80211_CCK_RATE_2MB: - return priv->rates_mask & IEEE80211_CCK_RATE_2MB_MASK ? 1 : 0; - case IEEE80211_CCK_RATE_5MB: - return priv->rates_mask & IEEE80211_CCK_RATE_5MB_MASK ? 1 : 0; - case IEEE80211_CCK_RATE_11MB: - return priv->rates_mask & IEEE80211_CCK_RATE_11MB_MASK ? 1 : 0; + case LIBIPW_CCK_RATE_1MB: + return priv->rates_mask & LIBIPW_CCK_RATE_1MB_MASK ? 1 : 0; + case LIBIPW_CCK_RATE_2MB: + return priv->rates_mask & LIBIPW_CCK_RATE_2MB_MASK ? 1 : 0; + case LIBIPW_CCK_RATE_5MB: + return priv->rates_mask & LIBIPW_CCK_RATE_5MB_MASK ? 1 : 0; + case LIBIPW_CCK_RATE_11MB: + return priv->rates_mask & LIBIPW_CCK_RATE_11MB_MASK ? 1 : 0; } /* If we are limited to B modulations, bail at this point */ @@ -5277,29 +5277,29 @@ static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate) /* G */ switch (rate) { - case IEEE80211_OFDM_RATE_6MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_9MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_12MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_18MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_24MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_36MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_48MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_54MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_6MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_9MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_12MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_18MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_24MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_36MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_48MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_54MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0; } return 0; } static int ipw_compatible_rates(struct ipw_priv *priv, - const struct ieee80211_network *network, + const struct libipw_network *network, struct ipw_supported_rates *rates) { int num_rates, i; @@ -5311,7 +5311,7 @@ static int ipw_compatible_rates(struct ipw_priv *priv, if (!ipw_is_rate_in_mask(priv, network->mode, network->rates[i])) { - if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) { + if (network->rates[i] & LIBIPW_BASIC_RATE_MASK) { IPW_DEBUG_SCAN("Adding masked mandatory " "rate %02X\n", network->rates[i]); @@ -5333,7 +5333,7 @@ static int ipw_compatible_rates(struct ipw_priv *priv, for (i = 0; i < num_rates; i++) { if (!ipw_is_rate_in_mask(priv, network->mode, network->rates_ex[i])) { - if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) { + if (network->rates_ex[i] & LIBIPW_BASIC_RATE_MASK) { IPW_DEBUG_SCAN("Adding masked mandatory " "rate %02X\n", network->rates_ex[i]); @@ -5369,73 +5369,73 @@ static void ipw_copy_rates(struct ipw_supported_rates *dest, static void ipw_add_cck_scan_rates(struct ipw_supported_rates *rates, u8 modulation, u32 rate_mask) { - u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ? - IEEE80211_BASIC_RATE_MASK : 0; + u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ? + LIBIPW_BASIC_RATE_MASK : 0; - if (rate_mask & IEEE80211_CCK_RATE_1MB_MASK) + if (rate_mask & LIBIPW_CCK_RATE_1MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_1MB; - if (rate_mask & IEEE80211_CCK_RATE_2MB_MASK) + if (rate_mask & LIBIPW_CCK_RATE_2MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_2MB; - if (rate_mask & IEEE80211_CCK_RATE_5MB_MASK) + if (rate_mask & LIBIPW_CCK_RATE_5MB_MASK) rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_CCK_RATE_5MB; + LIBIPW_CCK_RATE_5MB; - if (rate_mask & IEEE80211_CCK_RATE_11MB_MASK) + if (rate_mask & LIBIPW_CCK_RATE_11MB_MASK) rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_CCK_RATE_11MB; + LIBIPW_CCK_RATE_11MB; } static void ipw_add_ofdm_scan_rates(struct ipw_supported_rates *rates, u8 modulation, u32 rate_mask) { - u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ? - IEEE80211_BASIC_RATE_MASK : 0; + u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ? + LIBIPW_BASIC_RATE_MASK : 0; - if (rate_mask & IEEE80211_OFDM_RATE_6MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_6MB_MASK) rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_OFDM_RATE_6MB; + LIBIPW_OFDM_RATE_6MB; - if (rate_mask & IEEE80211_OFDM_RATE_9MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_9MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_9MB; + LIBIPW_OFDM_RATE_9MB; - if (rate_mask & IEEE80211_OFDM_RATE_12MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_12MB_MASK) rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_OFDM_RATE_12MB; + LIBIPW_OFDM_RATE_12MB; - if (rate_mask & IEEE80211_OFDM_RATE_18MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_18MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_18MB; + LIBIPW_OFDM_RATE_18MB; - if (rate_mask & IEEE80211_OFDM_RATE_24MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_24MB_MASK) rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_OFDM_RATE_24MB; + LIBIPW_OFDM_RATE_24MB; - if (rate_mask & IEEE80211_OFDM_RATE_36MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_36MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_36MB; + LIBIPW_OFDM_RATE_36MB; - if (rate_mask & IEEE80211_OFDM_RATE_48MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_48MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_48MB; + LIBIPW_OFDM_RATE_48MB; - if (rate_mask & IEEE80211_OFDM_RATE_54MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_54MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_54MB; + LIBIPW_OFDM_RATE_54MB; } struct ipw_network_match { - struct ieee80211_network *network; + struct libipw_network *network; struct ipw_supported_rates rates; }; static int ipw_find_adhoc_network(struct ipw_priv *priv, struct ipw_network_match *match, - struct ieee80211_network *network, + struct libipw_network *network, int roaming) { struct ipw_supported_rates rates; @@ -5556,7 +5556,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, } /* Filter out any incompatible freq / mode combinations */ - if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { + if (!libipw_is_valid_mode(priv->ieee, network->mode)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", @@ -5606,7 +5606,7 @@ static void ipw_merge_adhoc_network(struct work_struct *work) DECLARE_SSID_BUF(ssid); struct ipw_priv *priv = container_of(work, struct ipw_priv, merge_networks); - struct ieee80211_network *network = NULL; + struct libipw_network *network = NULL; struct ipw_network_match match = { .network = priv->assoc_network }; @@ -5648,7 +5648,7 @@ static void ipw_merge_adhoc_network(struct work_struct *work) static int ipw_best_network(struct ipw_priv *priv, struct ipw_network_match *match, - struct ieee80211_network *network, int roaming) + struct libipw_network *network, int roaming) { struct ipw_supported_rates rates; DECLARE_SSID_BUF(ssid); @@ -5782,7 +5782,7 @@ static int ipw_best_network(struct ipw_priv *priv, } /* Filter out any incompatible freq / mode combinations */ - if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { + if (!libipw_is_valid_mode(priv->ieee, network->mode)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", @@ -5793,7 +5793,7 @@ static int ipw_best_network(struct ipw_priv *priv, } /* Filter out invalid channel in current GEO */ - if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { + if (!libipw_is_valid_channel(priv->ieee, network->channel)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid channel in current GEO\n", print_ssid(ssid, network->ssid, @@ -5839,9 +5839,9 @@ static int ipw_best_network(struct ipw_priv *priv, } static void ipw_adhoc_create(struct ipw_priv *priv, - struct ieee80211_network *network) + struct libipw_network *network) { - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); int i; /* @@ -5856,25 +5856,25 @@ static void ipw_adhoc_create(struct ipw_priv *priv, * FW fatal error. * */ - switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { - case IEEE80211_52GHZ_BAND: + switch (libipw_is_valid_channel(priv->ieee, priv->channel)) { + case LIBIPW_52GHZ_BAND: network->mode = IEEE_A; - i = ieee80211_channel_to_index(priv->ieee, priv->channel); + i = libipw_channel_to_index(priv->ieee, priv->channel); BUG_ON(i == -1); - if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { + if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) { IPW_WARNING("Overriding invalid channel\n"); priv->channel = geo->a[0].channel; } break; - case IEEE80211_24GHZ_BAND: + case LIBIPW_24GHZ_BAND: if (priv->ieee->mode & IEEE_G) network->mode = IEEE_G; else network->mode = IEEE_B; - i = ieee80211_channel_to_index(priv->ieee, priv->channel); + i = libipw_channel_to_index(priv->ieee, priv->channel); BUG_ON(i == -1); - if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) { + if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) { IPW_WARNING("Overriding invalid channel\n"); priv->channel = geo->bg[0].channel; } @@ -6110,9 +6110,9 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) * Tx rates */ switch (priv->ieee->freq_band) { - case IEEE80211_52GHZ_BAND: /* A only */ + case LIBIPW_52GHZ_BAND: /* A only */ /* IEEE_A */ - if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) { + if (priv->rates_mask & ~LIBIPW_OFDM_RATES_MASK) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); @@ -6120,13 +6120,13 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) break; } - new_tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A; + new_tx_rates >>= LIBIPW_OFDM_SHIFT_MASK_A; break; default: /* 2.4Ghz or Mixed */ /* IEEE_B */ if (mode == IEEE_B) { - if (new_tx_rates & ~IEEE80211_CCK_RATES_MASK) { + if (new_tx_rates & ~LIBIPW_CCK_RATES_MASK) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); @@ -6136,8 +6136,8 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) } /* IEEE_G */ - if (new_tx_rates & ~(IEEE80211_CCK_RATES_MASK | - IEEE80211_OFDM_RATES_MASK)) { + if (new_tx_rates & ~(LIBIPW_CCK_RATES_MASK | + LIBIPW_OFDM_RATES_MASK)) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); @@ -6145,19 +6145,19 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) break; } - if (IEEE80211_OFDM_RATE_6MB_MASK & new_tx_rates) { - mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1); - new_tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK; + if (LIBIPW_OFDM_RATE_6MB_MASK & new_tx_rates) { + mask |= (LIBIPW_OFDM_RATE_6MB_MASK >> 1); + new_tx_rates &= ~LIBIPW_OFDM_RATE_6MB_MASK; } - if (IEEE80211_OFDM_RATE_9MB_MASK & new_tx_rates) { - mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1); - new_tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK; + if (LIBIPW_OFDM_RATE_9MB_MASK & new_tx_rates) { + mask |= (LIBIPW_OFDM_RATE_9MB_MASK >> 1); + new_tx_rates &= ~LIBIPW_OFDM_RATE_9MB_MASK; } - if (IEEE80211_OFDM_RATE_12MB_MASK & new_tx_rates) { - mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1); - new_tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK; + if (LIBIPW_OFDM_RATE_12MB_MASK & new_tx_rates) { + mask |= (LIBIPW_OFDM_RATE_12MB_MASK >> 1); + new_tx_rates &= ~LIBIPW_OFDM_RATE_12MB_MASK; } new_tx_rates |= mask; @@ -6190,12 +6190,12 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, int scan_type) { int channel_index = 0; - const struct ieee80211_geo *geo; + const struct libipw_geo *geo; int i; - geo = ieee80211_get_geo(priv->ieee); + geo = libipw_get_geo(priv->ieee); - if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { + if (priv->ieee->freq_band & LIBIPW_52GHZ_BAND) { int start = channel_index; for (i = 0; i < geo->a_channels; i++) { if ((priv->status & STATUS_ASSOCIATED) && @@ -6205,7 +6205,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, scan->channels_list[channel_index] = geo->a[i].channel; ipw_set_scan_type(scan, channel_index, geo->a[i]. - flags & IEEE80211_CH_PASSIVE_ONLY ? + flags & LIBIPW_CH_PASSIVE_ONLY ? IPW_SCAN_PASSIVE_FULL_DWELL_SCAN : scan_type); } @@ -6217,11 +6217,11 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, } } - if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { + if (priv->ieee->freq_band & LIBIPW_24GHZ_BAND) { int start = channel_index; if (priv->config & CFG_SPEED_SCAN) { int index; - u8 channels[IEEE80211_24GHZ_CHANNELS] = { + u8 channels[LIBIPW_24GHZ_CHANNELS] = { /* nop out the list */ [0] = 0 }; @@ -6253,11 +6253,11 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, channel_index++; scan->channels_list[channel_index] = channel; index = - ieee80211_channel_to_index(priv->ieee, channel); + libipw_channel_to_index(priv->ieee, channel); ipw_set_scan_type(scan, channel_index, geo->bg[index]. flags & - IEEE80211_CH_PASSIVE_ONLY ? + LIBIPW_CH_PASSIVE_ONLY ? IPW_SCAN_PASSIVE_FULL_DWELL_SCAN : scan_type); } @@ -6272,7 +6272,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, ipw_set_scan_type(scan, channel_index, geo->bg[i]. flags & - IEEE80211_CH_PASSIVE_ONLY ? + LIBIPW_CH_PASSIVE_ONLY ? IPW_SCAN_PASSIVE_FULL_DWELL_SCAN : scan_type); } @@ -6339,7 +6339,7 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) } memset(&scan, 0, sizeof(scan)); - scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); + scan.full_scan_index = cpu_to_le32(libipw_get_scans(priv->ieee)); if (type == IW_SCAN_TYPE_PASSIVE) { IPW_DEBUG_WX("use passive scanning\n"); @@ -6370,13 +6370,13 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) u8 channel; u8 band = 0; - switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { - case IEEE80211_52GHZ_BAND: + switch (libipw_is_valid_channel(priv->ieee, priv->channel)) { + case LIBIPW_52GHZ_BAND: band = (u8) (IPW_A_MODE << 6) | 1; channel = priv->channel; break; - case IEEE80211_24GHZ_BAND: + case LIBIPW_24GHZ_BAND: band = (u8) (IPW_B_MODE << 6) | 1; channel = priv->channel; break; @@ -6497,8 +6497,8 @@ static int ipw_wpa_enable(struct ipw_priv *priv, int value) static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) { - struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_security sec = { + struct libipw_device *ieee = priv->ieee; + struct libipw_security sec = { .flags = SEC_AUTH_MODE, }; int ret = 0; @@ -6548,8 +6548,8 @@ static int ipw_wx_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; u8 *buf; int err = 0; @@ -6584,8 +6584,8 @@ static int ipw_wx_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; int err = 0; if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { @@ -6627,8 +6627,8 @@ static int ipw_wx_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; struct lib80211_crypt_data *crypt; unsigned long flags; @@ -6679,7 +6679,7 @@ static int ipw_wx_set_auth(struct net_device *dev, * can use this to determine if the CAP_PRIVACY_ON bit should * be set. */ - struct ieee80211_security sec = { + struct libipw_security sec = { .flags = SEC_ENABLED, .enabled = param->value, }; @@ -6727,8 +6727,8 @@ static int ipw_wx_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; int ret = 0; @@ -6786,7 +6786,7 @@ static int ipw_wx_set_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; if (hwcrypto) { @@ -6808,7 +6808,7 @@ static int ipw_wx_set_encodeext(struct net_device *dev, } } - return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra); + return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra); } /* SIOCGIWENCODEEXT */ @@ -6816,8 +6816,8 @@ static int ipw_wx_get_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra); + struct ipw_priv *priv = libipw_priv(dev); + return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra); } /* SIOCSIWMLME */ @@ -6825,7 +6825,7 @@ static int ipw_wx_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct iw_mlme *mlme = (struct iw_mlme *)extra; __le16 reason; @@ -6875,9 +6875,9 @@ static u8 ipw_qos_current_mode(struct ipw_priv * priv) */ static int ipw_qos_handle_probe_response(struct ipw_priv *priv, int active_network, - struct ieee80211_network *network) + struct libipw_network *network) { - u32 size = sizeof(struct ieee80211_qos_parameters); + u32 size = sizeof(struct libipw_qos_parameters); if (network->capability & WLAN_CAPABILITY_IBSS) network->qos_data.active = network->qos_data.supported; @@ -6935,12 +6935,12 @@ static int ipw_qos_handle_probe_response(struct ipw_priv *priv, * IPW_CMD_QOS_PARAMETERS and IPW_CMD_WME_INFO */ static int ipw_qos_activate(struct ipw_priv *priv, - struct ieee80211_qos_data *qos_network_data) + struct libipw_qos_data *qos_network_data) { int err; - struct ieee80211_qos_parameters qos_parameters[QOS_QOS_SETS]; - struct ieee80211_qos_parameters *active_one = NULL; - u32 size = sizeof(struct ieee80211_qos_parameters); + struct libipw_qos_parameters qos_parameters[QOS_QOS_SETS]; + struct libipw_qos_parameters *active_one = NULL; + u32 size = sizeof(struct libipw_qos_parameters); u32 burst_duration; int i; u8 type; @@ -7001,7 +7001,7 @@ static int ipw_qos_activate(struct ipw_priv *priv, IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n"); err = ipw_send_qos_params_command(priv, - (struct ieee80211_qos_parameters *) + (struct libipw_qos_parameters *) &(qos_parameters[0])); if (err) IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n"); @@ -7015,13 +7015,13 @@ static int ipw_qos_activate(struct ipw_priv *priv, static int ipw_qos_set_info_element(struct ipw_priv *priv) { int ret = 0; - struct ieee80211_qos_information_element qos_info; + struct libipw_qos_information_element qos_info; if (priv == NULL) return -1; qos_info.elementID = QOS_ELEMENT_ID; - qos_info.length = sizeof(struct ieee80211_qos_information_element) - 2; + qos_info.length = sizeof(struct libipw_qos_information_element) - 2; qos_info.version = QOS_VERSION_1; qos_info.ac_info = 0; @@ -7041,11 +7041,11 @@ static int ipw_qos_set_info_element(struct ipw_priv *priv) * Set the QoS parameter with the association request structure */ static int ipw_qos_association(struct ipw_priv *priv, - struct ieee80211_network *network) + struct libipw_network *network) { int err = 0; - struct ieee80211_qos_data *qos_data = NULL; - struct ieee80211_qos_data ibss_data = { + struct libipw_qos_data *qos_data = NULL; + struct libipw_qos_data ibss_data = { .supported = 1, .active = 1, }; @@ -7087,11 +7087,11 @@ static int ipw_qos_association(struct ipw_priv *priv, * setting */ static int ipw_qos_association_resp(struct ipw_priv *priv, - struct ieee80211_network *network) + struct libipw_network *network) { int ret = 0; unsigned long flags; - u32 size = sizeof(struct ieee80211_qos_parameters); + u32 size = sizeof(struct libipw_qos_parameters); int set_qos_param = 0; if ((priv == NULL) || (network == NULL) || @@ -7107,7 +7107,7 @@ static int ipw_qos_association_resp(struct ipw_priv *priv, spin_lock_irqsave(&priv->ieee->lock, flags); if (network->flags & NETWORK_HAS_QOS_PARAMETERS) { memcpy(&priv->assoc_network->qos_data, &network->qos_data, - sizeof(struct ieee80211_qos_data)); + sizeof(struct libipw_qos_data)); priv->assoc_network->qos_data.active = 1; if ((network->qos_data.old_param_count != network->qos_data.param_count)) { @@ -7143,7 +7143,7 @@ static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv) if ((priv == NULL)) return 0; - if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION)) + if (!(priv->ieee->modulation & LIBIPW_OFDM_MODULATION)) ret = priv->qos_data.burst_duration_CCK; else ret = priv->qos_data.burst_duration_OFDM; @@ -7195,8 +7195,8 @@ static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority) static int ipw_is_qos_active(struct net_device *dev, struct sk_buff *skb) { - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_qos_data *qos_data = NULL; + struct ipw_priv *priv = libipw_priv(dev); + struct libipw_qos_data *qos_data = NULL; int active, supported; u8 *daddr = skb->data + ETH_ALEN; int unicast = !is_multicast_ether_addr(daddr); @@ -7260,10 +7260,10 @@ static void ipw_bg_qos_activate(struct work_struct *work) } static int ipw_handle_probe_response(struct net_device *dev, - struct ieee80211_probe_response *resp, - struct ieee80211_network *network) + struct libipw_probe_response *resp, + struct libipw_network *network) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int active_network = ((priv->status & STATUS_ASSOCIATED) && (network == priv->assoc_network)); @@ -7273,10 +7273,10 @@ static int ipw_handle_probe_response(struct net_device *dev, } static int ipw_handle_beacon(struct net_device *dev, - struct ieee80211_beacon *resp, - struct ieee80211_network *network) + struct libipw_beacon *resp, + struct libipw_network *network) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int active_network = ((priv->status & STATUS_ASSOCIATED) && (network == priv->assoc_network)); @@ -7286,22 +7286,22 @@ static int ipw_handle_beacon(struct net_device *dev, } static int ipw_handle_assoc_response(struct net_device *dev, - struct ieee80211_assoc_response *resp, - struct ieee80211_network *network) + struct libipw_assoc_response *resp, + struct libipw_network *network) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); ipw_qos_association_resp(priv, network); return 0; } -static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters +static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters *qos_param) { return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS, sizeof(*qos_param) * 3, qos_param); } -static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element +static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element *qos_param) { return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, sizeof(*qos_param), @@ -7311,7 +7311,7 @@ static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos #endif /* CONFIG_IPW2200_QOS */ static int ipw_associate_network(struct ipw_priv *priv, - struct ieee80211_network *network, + struct libipw_network *network, struct ipw_supported_rates *rates, int roaming) { int err; @@ -7493,7 +7493,7 @@ static int ipw_associate_network(struct ipw_priv *priv, static void ipw_roam(void *data) { struct ipw_priv *priv = data; - struct ieee80211_network *network = NULL; + struct libipw_network *network = NULL; struct ipw_network_match match = { .network = priv->assoc_network }; @@ -7568,7 +7568,7 @@ static int ipw_associate(void *data) { struct ipw_priv *priv = data; - struct ieee80211_network *network = NULL; + struct libipw_network *network = NULL; struct ipw_network_match match = { .network = NULL }; @@ -7622,8 +7622,8 @@ static int ipw_associate(void *data) priv->config & CFG_STATIC_CHANNEL) { /* Use oldest network if the free list is empty */ if (list_empty(&priv->ieee->network_free_list)) { - struct ieee80211_network *oldest = NULL; - struct ieee80211_network *target; + struct libipw_network *oldest = NULL; + struct libipw_network *target; list_for_each_entry(target, &priv->ieee->network_list, list) { if ((oldest == NULL) || @@ -7644,7 +7644,7 @@ static int ipw_associate(void *data) } element = priv->ieee->network_free_list.next; - network = list_entry(element, struct ieee80211_network, list); + network = list_entry(element, struct libipw_network, list); ipw_adhoc_create(priv, network); rates = &priv->rates; list_del(element); @@ -7700,18 +7700,18 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, switch (priv->ieee->sec.level) { case SEC_LEVEL_3: /* Remove CCMP HDR */ - memmove(skb->data + IEEE80211_3ADDR_LEN, - skb->data + IEEE80211_3ADDR_LEN + 8, - skb->len - IEEE80211_3ADDR_LEN - 8); + memmove(skb->data + LIBIPW_3ADDR_LEN, + skb->data + LIBIPW_3ADDR_LEN + 8, + skb->len - LIBIPW_3ADDR_LEN - 8); skb_trim(skb, skb->len - 16); /* CCMP_HDR_LEN + CCMP_MIC_LEN */ break; case SEC_LEVEL_2: break; case SEC_LEVEL_1: /* Remove IV */ - memmove(skb->data + IEEE80211_3ADDR_LEN, - skb->data + IEEE80211_3ADDR_LEN + 4, - skb->len - IEEE80211_3ADDR_LEN - 4); + memmove(skb->data + LIBIPW_3ADDR_LEN, + skb->data + LIBIPW_3ADDR_LEN + 4, + skb->len - LIBIPW_3ADDR_LEN - 4); skb_trim(skb, skb->len - 8); /* IV + ICV */ break; case SEC_LEVEL_0: @@ -7725,10 +7725,10 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, static void ipw_handle_data_packet(struct ipw_priv *priv, struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct net_device *dev = priv->net_dev; - struct ieee80211_hdr_4addr *hdr; + struct libipw_hdr_4addr *hdr; struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; /* We received data from the HW, so stop the watchdog */ @@ -7758,15 +7758,15 @@ static void ipw_handle_data_packet(struct ipw_priv *priv, IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */ - hdr = (struct ieee80211_hdr_4addr *)rxb->skb->data; + hdr = (struct libipw_hdr_4addr *)rxb->skb->data; if (priv->ieee->iw_mode != IW_MODE_MONITOR && (is_multicast_ether_addr(hdr->addr1) ? !priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt)) ipw_rebuild_decrypted_skb(priv, rxb->skb); - if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) + if (!libipw_rx(priv->ieee, rxb->skb, stats)) dev->stats.rx_errors++; - else { /* ieee80211_rx succeeded, so it now owns the SKB */ + else { /* libipw_rx succeeded, so it now owns the SKB */ rxb->skb = NULL; __ipw_led_activity_on(priv); } @@ -7775,7 +7775,7 @@ static void ipw_handle_data_packet(struct ipw_priv *priv, #ifdef CONFIG_IPW2200_RADIOTAP static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct net_device *dev = priv->net_dev; struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; @@ -7921,9 +7921,9 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); - if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) + if (!libipw_rx(priv->ieee, rxb->skb, stats)) dev->stats.rx_errors++; - else { /* ieee80211_rx succeeded, so it now owns the SKB */ + else { /* libipw_rx succeeded, so it now owns the SKB */ rxb->skb = NULL; /* no LED during capture */ } @@ -7931,28 +7931,28 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, #endif #ifdef CONFIG_IPW2200_PROMISCUOUS -#define ieee80211_is_probe_response(fc) \ +#define libipw_is_probe_response(fc) \ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && \ (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP ) -#define ieee80211_is_management(fc) \ +#define libipw_is_management(fc) \ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) -#define ieee80211_is_control(fc) \ +#define libipw_is_control(fc) \ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) -#define ieee80211_is_data(fc) \ +#define libipw_is_data(fc) \ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) -#define ieee80211_is_assoc_request(fc) \ +#define libipw_is_assoc_request(fc) \ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ) -#define ieee80211_is_reassoc_request(fc) \ +#define libipw_is_reassoc_request(fc) \ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct net_device *dev = priv->prom_net_dev; struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; @@ -8002,17 +8002,17 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, } hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { + if (libipw_is_management(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_MGMT) return; if (filter & IPW_PROM_MGMT_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { + } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_CTL) return; if (filter & IPW_PROM_CTL_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { + } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_DATA) return; if (filter & IPW_PROM_DATA_HEADER_ONLY) @@ -8030,7 +8030,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, ipw_rt = (void *)skb->data; if (hdr_only) - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control)); memcpy(ipw_rt->payload, hdr, len); @@ -8127,7 +8127,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len); - if (!ieee80211_rx(priv->prom_priv->ieee, skb, stats)) { + if (!libipw_rx(priv->prom_priv->ieee, skb, stats)) { dev->stats.rx_errors++; dev_kfree_skb_any(skb); } @@ -8135,7 +8135,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, #endif static int is_network_packet(struct ipw_priv *priv, - struct ieee80211_hdr_4addr *header) + struct libipw_hdr_4addr *header) { /* Filter incoming packets to determine if they are targetted toward * this network, discarding packets coming from ourselves */ @@ -8173,7 +8173,7 @@ static int is_network_packet(struct ipw_priv *priv, #define IPW_PACKET_RETRY_TIME HZ static int is_duplicate_packet(struct ipw_priv *priv, - struct ieee80211_hdr_4addr *header) + struct libipw_hdr_4addr *header) { u16 sc = le16_to_cpu(header->seq_ctl); u16 seq = WLAN_GET_SEQ_SEQ(sc); @@ -8247,14 +8247,14 @@ static int is_duplicate_packet(struct ipw_priv *priv, static void ipw_handle_mgmt_packet(struct ipw_priv *priv, struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct sk_buff *skb = rxb->skb; struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)skb->data; - struct ieee80211_hdr_4addr *header = (struct ieee80211_hdr_4addr *) + struct libipw_hdr_4addr *header = (struct libipw_hdr_4addr *) (skb->data + IPW_RX_FRAME_SIZE); - ieee80211_rx_mgt(priv->ieee, header, stats); + libipw_rx_mgt(priv->ieee, header, stats); if (priv->ieee->iw_mode == IW_MODE_ADHOC && ((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) == @@ -8276,12 +8276,12 @@ static void ipw_handle_mgmt_packet(struct ipw_priv *priv, /* Advance past the ipw packet header to the 802.11 frame */ skb_pull(skb, IPW_RX_FRAME_SIZE); - /* Push the ieee80211_rx_stats before the 802.11 frame */ + /* Push the libipw_rx_stats before the 802.11 frame */ memcpy(skb_push(skb, sizeof(*stats)), stats, sizeof(*stats)); skb->dev = priv->ieee->dev; - /* Point raw at the ieee80211_stats */ + /* Point raw at the libipw_stats */ skb_reset_mac_header(skb); skb->pkt_type = PACKET_OTHERHOST; @@ -8301,7 +8301,7 @@ static void ipw_rx(struct ipw_priv *priv) { struct ipw_rx_mem_buffer *rxb; struct ipw_rx_packet *pkt; - struct ieee80211_hdr_4addr *header; + struct libipw_hdr_4addr *header; u32 r, w, i; u8 network_packet; u8 fill_rx = 0; @@ -8332,7 +8332,7 @@ static void ipw_rx(struct ipw_priv *priv) switch (pkt->header.message_type) { case RX_FRAME_TYPE: /* 802.11 frame */ { - struct ieee80211_rx_stats stats = { + struct libipw_rx_stats stats = { .rssi = pkt->u.frame.rssi_dbm - IPW_RSSI_TO_DBM, .signal = @@ -8347,19 +8347,19 @@ static void ipw_rx(struct ipw_priv *priv) .freq = (pkt->u.frame. control & (1 << 0)) ? - IEEE80211_24GHZ_BAND : - IEEE80211_52GHZ_BAND, + LIBIPW_24GHZ_BAND : + LIBIPW_52GHZ_BAND, .len = le16_to_cpu(pkt->u.frame.length), }; if (stats.rssi != 0) - stats.mask |= IEEE80211_STATMASK_RSSI; + stats.mask |= LIBIPW_STATMASK_RSSI; if (stats.signal != 0) - stats.mask |= IEEE80211_STATMASK_SIGNAL; + stats.mask |= LIBIPW_STATMASK_SIGNAL; if (stats.noise != 0) - stats.mask |= IEEE80211_STATMASK_NOISE; + stats.mask |= LIBIPW_STATMASK_NOISE; if (stats.rate != 0) - stats.mask |= IEEE80211_STATMASK_RATE; + stats.mask |= LIBIPW_STATMASK_RATE; priv->rx_packets++; @@ -8384,7 +8384,7 @@ static void ipw_rx(struct ipw_priv *priv) #endif header = - (struct ieee80211_hdr_4addr *)(rxb->skb-> + (struct libipw_hdr_4addr *)(rxb->skb-> data + IPW_RX_FRAME_SIZE); /* TODO: Check Ad-Hoc dest/source and make sure @@ -8407,7 +8407,7 @@ static void ipw_rx(struct ipw_priv *priv) le16_to_cpu(pkt->u.frame.length)); if (le16_to_cpu(pkt->u.frame.length) < - ieee80211_get_hdrlen(le16_to_cpu( + libipw_get_hdrlen(le16_to_cpu( header->frame_ctl))) { IPW_DEBUG_DROP ("Received packet is too small. " @@ -8592,9 +8592,9 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) ": Detected Intel PRO/Wireless 2915ABG Network " "Connection\n"); priv->ieee->abg_true = 1; - band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; - modulation = IEEE80211_OFDM_MODULATION | - IEEE80211_CCK_MODULATION; + band = LIBIPW_52GHZ_BAND | LIBIPW_24GHZ_BAND; + modulation = LIBIPW_OFDM_MODULATION | + LIBIPW_CCK_MODULATION; priv->adapter = IPW_2915ABG; priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; } else { @@ -8604,9 +8604,9 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) "Connection\n"); priv->ieee->abg_true = 0; - band = IEEE80211_24GHZ_BAND; - modulation = IEEE80211_OFDM_MODULATION | - IEEE80211_CCK_MODULATION; + band = LIBIPW_24GHZ_BAND; + modulation = LIBIPW_OFDM_MODULATION | + LIBIPW_CCK_MODULATION; priv->adapter = IPW_2200BG; priv->ieee->mode = IEEE_G | IEEE_B; } @@ -8614,7 +8614,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) priv->ieee->freq_band = band; priv->ieee->modulation = modulation; - priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK; + priv->rates_mask = LIBIPW_DEFAULT_RATES_MASK; priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; @@ -8644,7 +8644,7 @@ static int ipw_wx_get_name(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (priv->status & STATUS_RF_KILL_MASK) strcpy(wrqu->name, "radio off"); @@ -8714,8 +8714,8 @@ static int ipw_wx_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + struct ipw_priv *priv = libipw_priv(dev); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); struct iw_freq *fwrq = &wrqu->freq; int ret = 0, i; u8 channel, flags; @@ -8730,23 +8730,23 @@ static int ipw_wx_set_freq(struct net_device *dev, } /* if setting by freq convert to channel */ if (fwrq->e == 1) { - channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m); + channel = libipw_freq_to_channel(priv->ieee, fwrq->m); if (channel == 0) return -EINVAL; } else channel = fwrq->m; - if (!(band = ieee80211_is_valid_channel(priv->ieee, channel))) + if (!(band = libipw_is_valid_channel(priv->ieee, channel))) return -EINVAL; if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - i = ieee80211_channel_to_index(priv->ieee, channel); + i = libipw_channel_to_index(priv->ieee, channel); if (i == -1) return -EINVAL; - flags = (band == IEEE80211_24GHZ_BAND) ? + flags = (band == LIBIPW_24GHZ_BAND) ? geo->bg[i].flags : geo->a[i].flags; - if (flags & IEEE80211_CH_PASSIVE_ONLY) { + if (flags & LIBIPW_CH_PASSIVE_ONLY) { IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n"); return -EINVAL; } @@ -8763,7 +8763,7 @@ static int ipw_wx_get_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); wrqu->freq.e = 0; @@ -8774,16 +8774,16 @@ static int ipw_wx_get_freq(struct net_device *dev, priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) { int i; - i = ieee80211_channel_to_index(priv->ieee, priv->channel); + i = libipw_channel_to_index(priv->ieee, priv->channel); BUG_ON(i == -1); wrqu->freq.e = 1; - switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { - case IEEE80211_52GHZ_BAND: + switch (libipw_is_valid_channel(priv->ieee, priv->channel)) { + case LIBIPW_52GHZ_BAND: wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000; break; - case IEEE80211_24GHZ_BAND: + case LIBIPW_24GHZ_BAND: wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000; break; @@ -8802,7 +8802,7 @@ static int ipw_wx_set_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int err = 0; IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode); @@ -8854,7 +8854,7 @@ static int ipw_wx_get_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->mode = priv->ieee->iw_mode; IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode); @@ -8883,9 +8883,9 @@ static int ipw_wx_get_range(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct iw_range *range = (struct iw_range *)extra; - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); int i = 0, j; wrqu->data.length = sizeof(*range); @@ -8929,7 +8929,7 @@ static int ipw_wx_get_range(struct net_device *dev, if (priv->ieee->mode & (IEEE_B | IEEE_G)) { for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; j++) { if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && - (geo->bg[j].flags & IEEE80211_CH_PASSIVE_ONLY)) + (geo->bg[j].flags & LIBIPW_CH_PASSIVE_ONLY)) continue; range->freq[i].i = geo->bg[j].channel; @@ -8942,7 +8942,7 @@ static int ipw_wx_get_range(struct net_device *dev, if (priv->ieee->mode & IEEE_A) { for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; j++) { if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && - (geo->a[j].flags & IEEE80211_CH_PASSIVE_ONLY)) + (geo->a[j].flags & LIBIPW_CH_PASSIVE_ONLY)) continue; range->freq[i].i = geo->a[j].channel; @@ -8977,7 +8977,7 @@ static int ipw_wx_set_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); static const unsigned char any[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff @@ -9026,7 +9026,7 @@ static int ipw_wx_get_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -9048,7 +9048,7 @@ static int ipw_wx_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int length; DECLARE_SSID_BUF(ssid); @@ -9094,7 +9094,7 @@ static int ipw_wx_get_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); DECLARE_SSID_BUF(ssid); /* If we are associated, trying to associate, or have a statically @@ -9120,7 +9120,7 @@ static int ipw_wx_set_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); IPW_DEBUG_WX("Setting nick to '%s'\n", extra); if (wrqu->data.length > IW_ESSID_MAX_SIZE) @@ -9139,7 +9139,7 @@ static int ipw_wx_get_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); IPW_DEBUG_WX("Getting nick\n"); mutex_lock(&priv->mutex); wrqu->data.length = strlen(priv->nick); @@ -9153,7 +9153,7 @@ static int ipw_wx_set_sens(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int err = 0; IPW_DEBUG_WX("Setting roaming threshold to %d\n", wrqu->sens.value); @@ -9183,7 +9183,7 @@ static int ipw_wx_get_sens(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->sens.fixed = 1; wrqu->sens.value = priv->roaming_threshold; @@ -9200,7 +9200,7 @@ static int ipw_wx_set_rate(struct net_device *dev, union iwreq_data *wrqu, char *extra) { /* TODO: We should use semaphores or locks for access to priv */ - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); u32 target_rate = wrqu->bitrate.value; u32 fixed, mask; @@ -9210,7 +9210,7 @@ static int ipw_wx_set_rate(struct net_device *dev, if (target_rate == -1) { fixed = 0; - mask = IEEE80211_DEFAULT_RATES_MASK; + mask = LIBIPW_DEFAULT_RATES_MASK; /* Now we should reassociate */ goto apply; } @@ -9219,62 +9219,62 @@ static int ipw_wx_set_rate(struct net_device *dev, fixed = wrqu->bitrate.fixed; if (target_rate == 1000000 || !fixed) - mask |= IEEE80211_CCK_RATE_1MB_MASK; + mask |= LIBIPW_CCK_RATE_1MB_MASK; if (target_rate == 1000000) goto apply; if (target_rate == 2000000 || !fixed) - mask |= IEEE80211_CCK_RATE_2MB_MASK; + mask |= LIBIPW_CCK_RATE_2MB_MASK; if (target_rate == 2000000) goto apply; if (target_rate == 5500000 || !fixed) - mask |= IEEE80211_CCK_RATE_5MB_MASK; + mask |= LIBIPW_CCK_RATE_5MB_MASK; if (target_rate == 5500000) goto apply; if (target_rate == 6000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_6MB_MASK; + mask |= LIBIPW_OFDM_RATE_6MB_MASK; if (target_rate == 6000000) goto apply; if (target_rate == 9000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_9MB_MASK; + mask |= LIBIPW_OFDM_RATE_9MB_MASK; if (target_rate == 9000000) goto apply; if (target_rate == 11000000 || !fixed) - mask |= IEEE80211_CCK_RATE_11MB_MASK; + mask |= LIBIPW_CCK_RATE_11MB_MASK; if (target_rate == 11000000) goto apply; if (target_rate == 12000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_12MB_MASK; + mask |= LIBIPW_OFDM_RATE_12MB_MASK; if (target_rate == 12000000) goto apply; if (target_rate == 18000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_18MB_MASK; + mask |= LIBIPW_OFDM_RATE_18MB_MASK; if (target_rate == 18000000) goto apply; if (target_rate == 24000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_24MB_MASK; + mask |= LIBIPW_OFDM_RATE_24MB_MASK; if (target_rate == 24000000) goto apply; if (target_rate == 36000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_36MB_MASK; + mask |= LIBIPW_OFDM_RATE_36MB_MASK; if (target_rate == 36000000) goto apply; if (target_rate == 48000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_48MB_MASK; + mask |= LIBIPW_OFDM_RATE_48MB_MASK; if (target_rate == 48000000) goto apply; if (target_rate == 54000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_54MB_MASK; + mask |= LIBIPW_OFDM_RATE_54MB_MASK; if (target_rate == 54000000) goto apply; @@ -9285,7 +9285,7 @@ static int ipw_wx_set_rate(struct net_device *dev, IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", mask, fixed ? "fixed" : "sub-rates"); mutex_lock(&priv->mutex); - if (mask == IEEE80211_DEFAULT_RATES_MASK) { + if (mask == LIBIPW_DEFAULT_RATES_MASK) { priv->config &= ~CFG_FIXED_RATE; ipw_set_fixed_rate(priv, priv->ieee->mode); } else @@ -9312,7 +9312,7 @@ static int ipw_wx_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->bitrate.value = priv->last_rate; wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0; @@ -9325,7 +9325,7 @@ static int ipw_wx_set_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (wrqu->rts.disabled || !wrqu->rts.fixed) priv->rts_threshold = DEFAULT_RTS_THRESHOLD; @@ -9348,7 +9348,7 @@ static int ipw_wx_get_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->rts.value = priv->rts_threshold; wrqu->rts.fixed = 0; /* no auto select */ @@ -9362,7 +9362,7 @@ static int ipw_wx_set_txpow(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int err = 0; mutex_lock(&priv->mutex); @@ -9396,7 +9396,7 @@ static int ipw_wx_get_txpow(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->power.value = priv->tx_power; wrqu->power.fixed = 1; @@ -9414,7 +9414,7 @@ static int ipw_wx_set_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (wrqu->frag.disabled || !wrqu->frag.fixed) priv->ieee->fts = DEFAULT_FTS; @@ -9438,7 +9438,7 @@ static int ipw_wx_get_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->frag.value = priv->ieee->fts; wrqu->frag.fixed = 0; /* no auto select */ @@ -9453,7 +9453,7 @@ static int ipw_wx_set_retry(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled) return -EINVAL; @@ -9486,7 +9486,7 @@ static int ipw_wx_get_retry(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->retry.disabled = 0; @@ -9517,7 +9517,7 @@ static int ipw_wx_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct iw_scan_req *req = (struct iw_scan_req *)extra; struct delayed_work *work = NULL; @@ -9553,20 +9553,20 @@ static int ipw_wx_get_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra); + struct ipw_priv *priv = libipw_priv(dev); + return libipw_wx_get_scan(priv->ieee, info, wrqu, extra); } static int ipw_wx_set_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *key) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int ret; u32 cap = priv->capability; mutex_lock(&priv->mutex); - ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); + ret = libipw_wx_set_encode(priv->ieee, info, wrqu, key); /* In IBSS mode, we need to notify the firmware to update * the beacon info after we changed the capability. */ @@ -9583,15 +9583,15 @@ static int ipw_wx_get_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *key) { - struct ipw_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key); + struct ipw_priv *priv = libipw_priv(dev); + return libipw_wx_get_encode(priv->ieee, info, wrqu, key); } static int ipw_wx_set_power(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int err; mutex_lock(&priv->mutex); if (wrqu->power.disabled) { @@ -9642,7 +9642,7 @@ static int ipw_wx_get_power(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (!(priv->power_mode & IPW_POWER_ENABLED)) wrqu->power.disabled = 1; @@ -9659,7 +9659,7 @@ static int ipw_wx_set_powermode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int mode = *(int *)extra; int err; @@ -9685,7 +9685,7 @@ static int ipw_wx_get_powermode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int level = IPW_POWER_LEVEL(priv->power_mode); char *p = extra; @@ -9717,7 +9717,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int mode = *(int *)extra; u8 band = 0, modulation = 0; @@ -9729,8 +9729,8 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, if (priv->adapter == IPW_2915ABG) { priv->ieee->abg_true = 1; if (mode & IEEE_A) { - band |= IEEE80211_52GHZ_BAND; - modulation |= IEEE80211_OFDM_MODULATION; + band |= LIBIPW_52GHZ_BAND; + modulation |= LIBIPW_OFDM_MODULATION; } else priv->ieee->abg_true = 0; } else { @@ -9745,14 +9745,14 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, } if (mode & IEEE_B) { - band |= IEEE80211_24GHZ_BAND; - modulation |= IEEE80211_CCK_MODULATION; + band |= LIBIPW_24GHZ_BAND; + modulation |= LIBIPW_CCK_MODULATION; } else priv->ieee->abg_true = 0; if (mode & IEEE_G) { - band |= IEEE80211_24GHZ_BAND; - modulation |= IEEE80211_OFDM_MODULATION; + band |= LIBIPW_24GHZ_BAND; + modulation |= LIBIPW_OFDM_MODULATION; } else priv->ieee->abg_true = 0; @@ -9782,7 +9782,7 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); switch (priv->ieee->mode) { case IEEE_A: @@ -9823,7 +9823,7 @@ static int ipw_wx_set_preamble(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int mode = *(int *)extra; mutex_lock(&priv->mutex); /* Switching from SHORT -> LONG requires a disassociation */ @@ -9856,7 +9856,7 @@ static int ipw_wx_get_preamble(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (priv->config & CFG_PREAMBLE_LONG) snprintf(wrqu->name, IFNAMSIZ, "long (1)"); @@ -9871,7 +9871,7 @@ static int ipw_wx_set_monitor(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int *parms = (int *)extra; int enable = (parms[0] > 0); mutex_lock(&priv->mutex); @@ -9905,7 +9905,7 @@ static int ipw_wx_reset(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); IPW_DEBUG_WX("RESET\n"); queue_work(priv->workqueue, &priv->adapter_restart); return 0; @@ -9915,7 +9915,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); union iwreq_data wrqu_sec = { .encoding = { .flags = IW_ENCODE_DISABLED, @@ -9938,7 +9938,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW); mutex_unlock(&priv->mutex); - ieee80211_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL); + libipw_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL); mutex_lock(&priv->mutex); if (!(priv->status & STATUS_RF_KILL_MASK)) { @@ -10083,7 +10083,7 @@ static struct iw_handler_def ipw_wx_handler_def = { */ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct iw_statistics *wstats; wstats = &priv->wstats; @@ -10164,13 +10164,13 @@ static int ipw_net_stop(struct net_device *dev) todo: modify to send one tfd per fragment instead of using chunking. otherwise -we need to heavily modify the ieee80211_skb_to_txb. +we need to heavily modify the libipw_skb_to_txb. */ -static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, +static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb, int pri) { - struct ieee80211_hdr_3addrqos *hdr = (struct ieee80211_hdr_3addrqos *) + struct libipw_hdr_3addrqos *hdr = (struct libipw_hdr_3addrqos *) txb->fragments[0]->data; int i = 0; struct tfd_frame *tfd; @@ -10187,7 +10187,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, if (!(priv->status & STATUS_ASSOCIATED)) goto drop; - hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + hdr_len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: unicast = !is_multicast_ether_addr(hdr->addr1); @@ -10356,13 +10356,13 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, drop: IPW_DEBUG_DROP("Silently dropping Tx packet.\n"); - ieee80211_txb_free(txb); + libipw_txb_free(txb); return NETDEV_TX_OK; } static int ipw_net_is_queue_full(struct net_device *dev, int pri) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); #ifdef CONFIG_IPW2200_QOS int tx_id = ipw_get_tx_queue_number(priv, pri); struct clx2_tx_queue *txq = &priv->txq[tx_id]; @@ -10378,9 +10378,9 @@ static int ipw_net_is_queue_full(struct net_device *dev, int pri) #ifdef CONFIG_IPW2200_PROMISCUOUS static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, - struct ieee80211_txb *txb) + struct libipw_txb *txb) { - struct ieee80211_rx_stats dummystats; + struct libipw_rx_stats dummystats; struct ieee80211_hdr *hdr; u8 n; u16 filter = priv->prom_priv->filter; @@ -10393,17 +10393,17 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, /* Filtering of fragment chains is done agains the first fragment */ hdr = (void *)txb->fragments[0]->data; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { + if (libipw_is_management(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_MGMT) return; if (filter & IPW_PROM_MGMT_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { + } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_CTL) return; if (filter & IPW_PROM_CTL_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { + } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_DATA) return; if (filter & IPW_PROM_DATA_HEADER_ONLY) @@ -10418,7 +10418,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, if (hdr_only) { hdr = (void *)src->data; - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control)); } else len = src->len; @@ -10452,16 +10452,16 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, skb_copy_from_linear_data(src, skb_put(dst, len), len); - if (!ieee80211_rx(priv->prom_priv->ieee, dst, &dummystats)) + if (!libipw_rx(priv->prom_priv->ieee, dst, &dummystats)) dev_kfree_skb_any(dst); } } #endif -static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, +static int ipw_net_hard_start_xmit(struct libipw_txb *txb, struct net_device *dev, int pri) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); unsigned long flags; int ret; @@ -10488,7 +10488,7 @@ static void ipw_net_set_multicast_list(struct net_device *dev) static int ipw_net_set_mac_address(struct net_device *dev, void *p) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) @@ -10506,7 +10506,7 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) static void ipw_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct ipw_priv *p = ieee80211_priv(dev); + struct ipw_priv *p = libipw_priv(dev); char vers[64]; char date[32]; u32 len; @@ -10527,7 +10527,7 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev, static u32 ipw_ethtool_get_link(struct net_device *dev) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); return (priv->status & STATUS_ASSOCIATED) != 0; } @@ -10539,7 +10539,7 @@ static int ipw_ethtool_get_eeprom_len(struct net_device *dev) static int ipw_ethtool_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { - struct ipw_priv *p = ieee80211_priv(dev); + struct ipw_priv *p = libipw_priv(dev); if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) return -EINVAL; @@ -10552,7 +10552,7 @@ static int ipw_ethtool_get_eeprom(struct net_device *dev, static int ipw_ethtool_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { - struct ipw_priv *p = ieee80211_priv(dev); + struct ipw_priv *p = libipw_priv(dev); int i; if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) @@ -10768,9 +10768,9 @@ static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv) } static void shim__set_security(struct net_device *dev, - struct ieee80211_security *sec) + struct libipw_security *sec) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int i; for (i = 0; i < 4; i++) { if (sec->flags & (1 << i)) { @@ -10855,21 +10855,21 @@ static int init_supported_rates(struct ipw_priv *priv, memset(rates, 0, sizeof(*rates)); /* configure supported rates */ switch (priv->ieee->freq_band) { - case IEEE80211_52GHZ_BAND: + case LIBIPW_52GHZ_BAND: rates->ieee_mode = IPW_A_MODE; rates->purpose = IPW_RATE_CAPABILITIES; - ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION, - IEEE80211_OFDM_DEFAULT_RATES_MASK); + ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION, + LIBIPW_OFDM_DEFAULT_RATES_MASK); break; default: /* Mixed or 2.4Ghz */ rates->ieee_mode = IPW_G_MODE; rates->purpose = IPW_RATE_CAPABILITIES; - ipw_add_cck_scan_rates(rates, IEEE80211_CCK_MODULATION, - IEEE80211_CCK_DEFAULT_RATES_MASK); - if (priv->ieee->modulation & IEEE80211_OFDM_MODULATION) { - ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION, - IEEE80211_OFDM_DEFAULT_RATES_MASK); + ipw_add_cck_scan_rates(rates, LIBIPW_CCK_MODULATION, + LIBIPW_CCK_DEFAULT_RATES_MASK); + if (priv->ieee->modulation & LIBIPW_OFDM_MODULATION) { + ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION, + LIBIPW_OFDM_DEFAULT_RATES_MASK); } break; } @@ -10975,7 +10975,7 @@ static int ipw_config(struct ipw_priv *priv) * table. * */ -static const struct ieee80211_geo ipw_geos[] = { +static const struct libipw_geo ipw_geos[] = { { /* Restricted */ "---", .bg_channels = 11, @@ -10997,10 +10997,10 @@ static const struct ieee80211_geo ipw_geos[] = { {5200, 40}, {5220, 44}, {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}}, }, { /* Rest of World */ @@ -11025,10 +11025,10 @@ static const struct ieee80211_geo ipw_geos[] = { {5200, 40}, {5220, 44}, {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}, {5745, 149}, {5765, 153}, {5785, 157}, @@ -11048,15 +11048,15 @@ static const struct ieee80211_geo ipw_geos[] = { {5200, 40}, {5220, 44}, {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, - {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, - {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, - {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, - {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}, + {5745, 149, LIBIPW_CH_PASSIVE_ONLY}, + {5765, 153, LIBIPW_CH_PASSIVE_ONLY}, + {5785, 157, LIBIPW_CH_PASSIVE_ONLY}, + {5805, 161, LIBIPW_CH_PASSIVE_ONLY}, + {5825, 165, LIBIPW_CH_PASSIVE_ONLY}}, }, { /* Custom Japan */ @@ -11093,21 +11093,21 @@ static const struct ieee80211_geo ipw_geos[] = { {5200, 40}, {5220, 44}, {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5500, 100, IEEE80211_CH_PASSIVE_ONLY}, - {5520, 104, IEEE80211_CH_PASSIVE_ONLY}, - {5540, 108, IEEE80211_CH_PASSIVE_ONLY}, - {5560, 112, IEEE80211_CH_PASSIVE_ONLY}, - {5580, 116, IEEE80211_CH_PASSIVE_ONLY}, - {5600, 120, IEEE80211_CH_PASSIVE_ONLY}, - {5620, 124, IEEE80211_CH_PASSIVE_ONLY}, - {5640, 128, IEEE80211_CH_PASSIVE_ONLY}, - {5660, 132, IEEE80211_CH_PASSIVE_ONLY}, - {5680, 136, IEEE80211_CH_PASSIVE_ONLY}, - {5700, 140, IEEE80211_CH_PASSIVE_ONLY}}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}, + {5500, 100, LIBIPW_CH_PASSIVE_ONLY}, + {5520, 104, LIBIPW_CH_PASSIVE_ONLY}, + {5540, 108, LIBIPW_CH_PASSIVE_ONLY}, + {5560, 112, LIBIPW_CH_PASSIVE_ONLY}, + {5580, 116, LIBIPW_CH_PASSIVE_ONLY}, + {5600, 120, LIBIPW_CH_PASSIVE_ONLY}, + {5620, 124, LIBIPW_CH_PASSIVE_ONLY}, + {5640, 128, LIBIPW_CH_PASSIVE_ONLY}, + {5660, 132, LIBIPW_CH_PASSIVE_ONLY}, + {5680, 136, LIBIPW_CH_PASSIVE_ONLY}, + {5700, 140, LIBIPW_CH_PASSIVE_ONLY}}, }, { /* Custom Japan */ @@ -11117,7 +11117,7 @@ static const struct ieee80211_geo ipw_geos[] = { {2427, 4}, {2432, 5}, {2437, 6}, {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}, {2467, 12}, - {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY}}, + {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY}}, .a_channels = 4, .a = {{5170, 34}, {5190, 38}, {5210, 42}, {5230, 46}}, @@ -11130,8 +11130,8 @@ static const struct ieee80211_geo ipw_geos[] = { {2427, 4}, {2432, 5}, {2437, 6}, {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}, {2467, 12}, - {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY | - IEEE80211_CH_PASSIVE_ONLY}}, + {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY | + LIBIPW_CH_PASSIVE_ONLY}}, }, { /* High Band */ @@ -11141,8 +11141,8 @@ static const struct ieee80211_geo ipw_geos[] = { {2427, 4}, {2432, 5}, {2437, 6}, {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}, - {2467, 12, IEEE80211_CH_PASSIVE_ONLY}, - {2472, 13, IEEE80211_CH_PASSIVE_ONLY}}, + {2467, 12, LIBIPW_CH_PASSIVE_ONLY}, + {2472, 13, LIBIPW_CH_PASSIVE_ONLY}}, .a_channels = 4, .a = {{5745, 149}, {5765, 153}, {5785, 157}, {5805, 161}}, @@ -11168,33 +11168,33 @@ static const struct ieee80211_geo ipw_geos[] = { {2427, 4}, {2432, 5}, {2437, 6}, {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}, - {2467, 12, IEEE80211_CH_PASSIVE_ONLY}, - {2472, 13, IEEE80211_CH_PASSIVE_ONLY}}, + {2467, 12, LIBIPW_CH_PASSIVE_ONLY}, + {2472, 13, LIBIPW_CH_PASSIVE_ONLY}}, .a_channels = 24, - .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY}, - {5200, 40, IEEE80211_CH_PASSIVE_ONLY}, - {5220, 44, IEEE80211_CH_PASSIVE_ONLY}, - {5240, 48, IEEE80211_CH_PASSIVE_ONLY}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5500, 100, IEEE80211_CH_PASSIVE_ONLY}, - {5520, 104, IEEE80211_CH_PASSIVE_ONLY}, - {5540, 108, IEEE80211_CH_PASSIVE_ONLY}, - {5560, 112, IEEE80211_CH_PASSIVE_ONLY}, - {5580, 116, IEEE80211_CH_PASSIVE_ONLY}, - {5600, 120, IEEE80211_CH_PASSIVE_ONLY}, - {5620, 124, IEEE80211_CH_PASSIVE_ONLY}, - {5640, 128, IEEE80211_CH_PASSIVE_ONLY}, - {5660, 132, IEEE80211_CH_PASSIVE_ONLY}, - {5680, 136, IEEE80211_CH_PASSIVE_ONLY}, - {5700, 140, IEEE80211_CH_PASSIVE_ONLY}, - {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, - {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, - {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, - {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, - {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY}, + {5200, 40, LIBIPW_CH_PASSIVE_ONLY}, + {5220, 44, LIBIPW_CH_PASSIVE_ONLY}, + {5240, 48, LIBIPW_CH_PASSIVE_ONLY}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}, + {5500, 100, LIBIPW_CH_PASSIVE_ONLY}, + {5520, 104, LIBIPW_CH_PASSIVE_ONLY}, + {5540, 108, LIBIPW_CH_PASSIVE_ONLY}, + {5560, 112, LIBIPW_CH_PASSIVE_ONLY}, + {5580, 116, LIBIPW_CH_PASSIVE_ONLY}, + {5600, 120, LIBIPW_CH_PASSIVE_ONLY}, + {5620, 124, LIBIPW_CH_PASSIVE_ONLY}, + {5640, 128, LIBIPW_CH_PASSIVE_ONLY}, + {5660, 132, LIBIPW_CH_PASSIVE_ONLY}, + {5680, 136, LIBIPW_CH_PASSIVE_ONLY}, + {5700, 140, LIBIPW_CH_PASSIVE_ONLY}, + {5745, 149, LIBIPW_CH_PASSIVE_ONLY}, + {5765, 153, LIBIPW_CH_PASSIVE_ONLY}, + {5785, 157, LIBIPW_CH_PASSIVE_ONLY}, + {5805, 161, LIBIPW_CH_PASSIVE_ONLY}, + {5825, 165, LIBIPW_CH_PASSIVE_ONLY}}, }, { /* Europe */ @@ -11205,19 +11205,19 @@ static const struct ieee80211_geo ipw_geos[] = { {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}}, .a_channels = 13, - .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY}, - {5200, 40, IEEE80211_CH_PASSIVE_ONLY}, - {5220, 44, IEEE80211_CH_PASSIVE_ONLY}, - {5240, 48, IEEE80211_CH_PASSIVE_ONLY}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, - {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, - {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, - {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, - {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY}, + {5200, 40, LIBIPW_CH_PASSIVE_ONLY}, + {5220, 44, LIBIPW_CH_PASSIVE_ONLY}, + {5240, 48, LIBIPW_CH_PASSIVE_ONLY}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}, + {5745, 149, LIBIPW_CH_PASSIVE_ONLY}, + {5765, 153, LIBIPW_CH_PASSIVE_ONLY}, + {5785, 157, LIBIPW_CH_PASSIVE_ONLY}, + {5805, 161, LIBIPW_CH_PASSIVE_ONLY}, + {5825, 165, LIBIPW_CH_PASSIVE_ONLY}}, } }; @@ -11228,7 +11228,7 @@ static int ipw_up(struct ipw_priv *priv) /* Age scan list entries found before suspend */ if (priv->suspend_time) { - ieee80211_networks_age(priv->ieee, priv->suspend_time); + libipw_networks_age(priv->ieee, priv->suspend_time); priv->suspend_time = 0; } @@ -11273,7 +11273,7 @@ static int ipw_up(struct ipw_priv *priv) priv->eeprom[EEPROM_COUNTRY_CODE + 2]); j = 0; } - if (ieee80211_set_geo(priv->ieee, &ipw_geos[j])) { + if (libipw_set_geo(priv->ieee, &ipw_geos[j])) { IPW_WARNING("Could not set geography."); return 0; } @@ -11401,7 +11401,7 @@ static void ipw_bg_down(struct work_struct *work) /* Called by register_netdev() */ static int ipw_net_init(struct net_device *dev) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (ipw_up(priv)) { @@ -11480,7 +11480,7 @@ static struct attribute_group ipw_attribute_group = { #ifdef CONFIG_IPW2200_PROMISCUOUS static int ipw_prom_open(struct net_device *dev) { - struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); + struct ipw_prom_priv *prom_priv = libipw_priv(dev); struct ipw_priv *priv = prom_priv->priv; IPW_DEBUG_INFO("prom dev->open\n"); @@ -11500,7 +11500,7 @@ static int ipw_prom_open(struct net_device *dev) static int ipw_prom_stop(struct net_device *dev) { - struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); + struct ipw_prom_priv *prom_priv = libipw_priv(dev); struct ipw_priv *priv = prom_priv->priv; IPW_DEBUG_INFO("prom dev->stop\n"); @@ -11528,7 +11528,7 @@ static const struct net_device_ops ipw_prom_netdev_ops = { .ndo_open = ipw_prom_open, .ndo_stop = ipw_prom_stop, .ndo_start_xmit = ipw_prom_hard_start_xmit, - .ndo_change_mtu = ieee80211_change_mtu, + .ndo_change_mtu = libipw_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, }; @@ -11544,7 +11544,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv) if (priv->prom_net_dev == NULL) return -ENOMEM; - priv->prom_priv = ieee80211_priv(priv->prom_net_dev); + priv->prom_priv = libipw_priv(priv->prom_net_dev); priv->prom_priv->ieee = netdev_priv(priv->prom_net_dev); priv->prom_priv->priv = priv; @@ -11586,8 +11586,8 @@ static const struct net_device_ops ipw_netdev_ops = { .ndo_stop = ipw_net_stop, .ndo_set_multicast_list = ipw_net_set_multicast_list, .ndo_set_mac_address = ipw_net_set_mac_address, - .ndo_start_xmit = ieee80211_xmit, - .ndo_change_mtu = ieee80211_change_mtu, + .ndo_start_xmit = libipw_xmit, + .ndo_change_mtu = libipw_change_mtu, .ndo_validate_addr = eth_validate_addr, }; @@ -11607,7 +11607,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, goto out; } - priv = ieee80211_priv(net_dev); + priv = libipw_priv(net_dev); priv->ieee = netdev_priv(net_dev); priv->net_dev = net_dev; diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h index 05e8ccf..4448bad 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/ipw2x00/ipw2200.h @@ -55,7 +55,7 @@ #include -#include "ieee80211.h" +#include "libipw.h" /* Authentication and Association States */ enum connection_manager_assoc_states { @@ -365,8 +365,8 @@ enum connection_manager_assoc_states { /* QoS sturctures */ struct ipw_qos_info { int qos_enable; - struct ieee80211_qos_parameters *def_qos_parm_OFDM; - struct ieee80211_qos_parameters *def_qos_parm_CCK; + struct libipw_qos_parameters *def_qos_parm_OFDM; + struct libipw_qos_parameters *def_qos_parm_CCK; u32 burst_duration_CCK; u32 burst_duration_OFDM; u16 qos_no_ack_mask; @@ -534,7 +534,7 @@ typedef void destructor_func(const void *); struct clx2_tx_queue { struct clx2_queue q; struct tfd_frame *bd; - struct ieee80211_txb **txb; + struct libipw_txb **txb; }; /* @@ -1144,7 +1144,7 @@ enum ipw_prom_filter { struct ipw_priv; struct ipw_prom_priv { struct ipw_priv *priv; - struct ieee80211_device *ieee; + struct libipw_device *ieee; enum ipw_prom_filter filter; int tx_packets; int rx_packets; @@ -1175,7 +1175,7 @@ struct ipw_rt_hdr { struct ipw_priv { /* ieee device used by generic ieee processing code */ - struct ieee80211_device *ieee; + struct libipw_device *ieee; spinlock_t lock; spinlock_t irq_lock; @@ -1222,7 +1222,7 @@ struct ipw_priv { u32 roaming_threshold; struct ipw_associate assoc_request; - struct ieee80211_network *assoc_network; + struct libipw_network *assoc_network; unsigned long ts_scan_abort; struct ipw_supported_rates rates; diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h new file mode 100644 index 0000000..cefb942 --- /dev/null +++ b/drivers/net/wireless/ipw2x00/libipw.h @@ -0,0 +1,1087 @@ +/* + * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 + * remains copyright by the original authors + * + * Portions of the merged code are based on Host AP (software wireless + * LAN access point) driver for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * + * Copyright (c) 2004-2005, Intel Corporation + * + * 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 + * published by the Free Software Foundation. See README and COPYING for + * more details. + * + * API Version History + * 1.0.x -- Initial version + * 1.1.x -- Added radiotap, QoS, TIM, libipw_geo APIs, + * various structure changes, and crypto API init method + */ +#ifndef LIBIPW_H +#define LIBIPW_H +#include /* ETH_ALEN */ +#include /* ARRAY_SIZE */ +#include +#include + +#include + +#define LIBIPW_VERSION "git-1.1.13" + +#define LIBIPW_DATA_LEN 2304 +/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section + 6.2.1.1.2. + + The figure in section 7.1.2 suggests a body size of up to 2312 + bytes is allowed, which is a bit confusing, I suspect this + represents the 2304 bytes of real data, plus a possible 8 bytes of + WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ + +#define LIBIPW_1ADDR_LEN 10 +#define LIBIPW_2ADDR_LEN 16 +#define LIBIPW_3ADDR_LEN 24 +#define LIBIPW_4ADDR_LEN 30 +#define LIBIPW_FCS_LEN 4 +#define LIBIPW_HLEN (LIBIPW_4ADDR_LEN) +#define LIBIPW_FRAME_LEN (LIBIPW_DATA_LEN + LIBIPW_HLEN) + +#define MIN_FRAG_THRESHOLD 256U +#define MAX_FRAG_THRESHOLD 2346U + +/* QOS control */ +#define LIBIPW_QCTL_TID 0x000F + +/* debug macros */ + +#ifdef CONFIG_LIBIPW_DEBUG +extern u32 libipw_debug_level; +#define LIBIPW_DEBUG(level, fmt, args...) \ +do { if (libipw_debug_level & (level)) \ + printk(KERN_DEBUG "ieee80211: %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) +static inline bool libipw_ratelimit_debug(u32 level) +{ + return (libipw_debug_level & level) && net_ratelimit(); +} +#else +#define LIBIPW_DEBUG(level, fmt, args...) do {} while (0) +static inline bool libipw_ratelimit_debug(u32 level) +{ + return false; +} +#endif /* CONFIG_LIBIPW_DEBUG */ + +/* + * To use the debug system: + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define LIBIPW_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a LIBIPW_xxxx_DEBUG() macro definition for your + * classification, or use LIBIPW_DEBUG(LIBIPW_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/ieee80211/debug_level + * + * you simply need to add your entry to the libipw_debug_level array. + * + * If you do not see debug_level in /proc/net/ieee80211 then you do not have + * CONFIG_LIBIPW_DEBUG defined in your kernel configuration + * + */ + +#define LIBIPW_DL_INFO (1<<0) +#define LIBIPW_DL_WX (1<<1) +#define LIBIPW_DL_SCAN (1<<2) +#define LIBIPW_DL_STATE (1<<3) +#define LIBIPW_DL_MGMT (1<<4) +#define LIBIPW_DL_FRAG (1<<5) +#define LIBIPW_DL_DROP (1<<7) + +#define LIBIPW_DL_TX (1<<8) +#define LIBIPW_DL_RX (1<<9) +#define LIBIPW_DL_QOS (1<<31) + +#define LIBIPW_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) +#define LIBIPW_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) +#define LIBIPW_DEBUG_INFO(f, a...) LIBIPW_DEBUG(LIBIPW_DL_INFO, f, ## a) + +#define LIBIPW_DEBUG_WX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_WX, f, ## a) +#define LIBIPW_DEBUG_SCAN(f, a...) LIBIPW_DEBUG(LIBIPW_DL_SCAN, f, ## a) +#define LIBIPW_DEBUG_STATE(f, a...) LIBIPW_DEBUG(LIBIPW_DL_STATE, f, ## a) +#define LIBIPW_DEBUG_MGMT(f, a...) LIBIPW_DEBUG(LIBIPW_DL_MGMT, f, ## a) +#define LIBIPW_DEBUG_FRAG(f, a...) LIBIPW_DEBUG(LIBIPW_DL_FRAG, f, ## a) +#define LIBIPW_DEBUG_DROP(f, a...) LIBIPW_DEBUG(LIBIPW_DL_DROP, f, ## a) +#define LIBIPW_DEBUG_TX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_TX, f, ## a) +#define LIBIPW_DEBUG_RX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_RX, f, ## a) +#define LIBIPW_DEBUG_QOS(f, a...) LIBIPW_DEBUG(LIBIPW_DL_QOS, f, ## a) +#include +#include /* ARPHRD_ETHER */ + +#ifndef WIRELESS_SPY +#define WIRELESS_SPY /* enable iwspy support */ +#endif +#include /* new driver API */ + +#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ + +#ifndef ETH_P_80211_RAW +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) +#endif + +/* IEEE 802.11 defines */ + +#define P80211_OUI_LEN 3 + +struct libipw_snap_hdr { + + u8 dsap; /* always 0xAA */ + u8 ssap; /* always 0xAA */ + u8 ctrl; /* always 0x03 */ + u8 oui[P80211_OUI_LEN]; /* organizational universal id */ + +} __attribute__ ((packed)); + +#define SNAP_SIZE sizeof(struct libipw_snap_hdr) + +#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS) +#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) + +#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) +#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) + +#define LIBIPW_STATMASK_SIGNAL (1<<0) +#define LIBIPW_STATMASK_RSSI (1<<1) +#define LIBIPW_STATMASK_NOISE (1<<2) +#define LIBIPW_STATMASK_RATE (1<<3) +#define LIBIPW_STATMASK_WEMASK 0x7 + +#define LIBIPW_CCK_MODULATION (1<<0) +#define LIBIPW_OFDM_MODULATION (1<<1) + +#define LIBIPW_24GHZ_BAND (1<<0) +#define LIBIPW_52GHZ_BAND (1<<1) + +#define LIBIPW_CCK_RATE_1MB 0x02 +#define LIBIPW_CCK_RATE_2MB 0x04 +#define LIBIPW_CCK_RATE_5MB 0x0B +#define LIBIPW_CCK_RATE_11MB 0x16 +#define LIBIPW_OFDM_RATE_6MB 0x0C +#define LIBIPW_OFDM_RATE_9MB 0x12 +#define LIBIPW_OFDM_RATE_12MB 0x18 +#define LIBIPW_OFDM_RATE_18MB 0x24 +#define LIBIPW_OFDM_RATE_24MB 0x30 +#define LIBIPW_OFDM_RATE_36MB 0x48 +#define LIBIPW_OFDM_RATE_48MB 0x60 +#define LIBIPW_OFDM_RATE_54MB 0x6C +#define LIBIPW_BASIC_RATE_MASK 0x80 + +#define LIBIPW_CCK_RATE_1MB_MASK (1<<0) +#define LIBIPW_CCK_RATE_2MB_MASK (1<<1) +#define LIBIPW_CCK_RATE_5MB_MASK (1<<2) +#define LIBIPW_CCK_RATE_11MB_MASK (1<<3) +#define LIBIPW_OFDM_RATE_6MB_MASK (1<<4) +#define LIBIPW_OFDM_RATE_9MB_MASK (1<<5) +#define LIBIPW_OFDM_RATE_12MB_MASK (1<<6) +#define LIBIPW_OFDM_RATE_18MB_MASK (1<<7) +#define LIBIPW_OFDM_RATE_24MB_MASK (1<<8) +#define LIBIPW_OFDM_RATE_36MB_MASK (1<<9) +#define LIBIPW_OFDM_RATE_48MB_MASK (1<<10) +#define LIBIPW_OFDM_RATE_54MB_MASK (1<<11) + +#define LIBIPW_CCK_RATES_MASK 0x0000000F +#define LIBIPW_CCK_BASIC_RATES_MASK (LIBIPW_CCK_RATE_1MB_MASK | \ + LIBIPW_CCK_RATE_2MB_MASK) +#define LIBIPW_CCK_DEFAULT_RATES_MASK (LIBIPW_CCK_BASIC_RATES_MASK | \ + LIBIPW_CCK_RATE_5MB_MASK | \ + LIBIPW_CCK_RATE_11MB_MASK) + +#define LIBIPW_OFDM_RATES_MASK 0x00000FF0 +#define LIBIPW_OFDM_BASIC_RATES_MASK (LIBIPW_OFDM_RATE_6MB_MASK | \ + LIBIPW_OFDM_RATE_12MB_MASK | \ + LIBIPW_OFDM_RATE_24MB_MASK) +#define LIBIPW_OFDM_DEFAULT_RATES_MASK (LIBIPW_OFDM_BASIC_RATES_MASK | \ + LIBIPW_OFDM_RATE_9MB_MASK | \ + LIBIPW_OFDM_RATE_18MB_MASK | \ + LIBIPW_OFDM_RATE_36MB_MASK | \ + LIBIPW_OFDM_RATE_48MB_MASK | \ + LIBIPW_OFDM_RATE_54MB_MASK) +#define LIBIPW_DEFAULT_RATES_MASK (LIBIPW_OFDM_DEFAULT_RATES_MASK | \ + LIBIPW_CCK_DEFAULT_RATES_MASK) + +#define LIBIPW_NUM_OFDM_RATES 8 +#define LIBIPW_NUM_CCK_RATES 4 +#define LIBIPW_OFDM_SHIFT_MASK_A 4 + +/* NOTE: This data is for statistical purposes; not all hardware provides this + * information for frames received. + * For libipw_rx_mgt, you need to set at least the 'len' parameter. + */ +struct libipw_rx_stats { + u32 mac_time; + s8 rssi; + u8 signal; + u8 noise; + u16 rate; /* in 100 kbps */ + u8 received_channel; + u8 control; + u8 mask; + u8 freq; + u16 len; + u64 tsf; + u32 beacon_time; +}; + +/* IEEE 802.11 requires that STA supports concurrent reception of at least + * three fragmented frames. This define can be increased to support more + * concurrent frames, but it should be noted that each entry can consume about + * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ +#define LIBIPW_FRAG_CACHE_LEN 4 + +struct libipw_frag_entry { + unsigned long first_frag_time; + unsigned int seq; + unsigned int last_frag; + struct sk_buff *skb; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; +}; + +struct libipw_stats { + unsigned int tx_unicast_frames; + unsigned int tx_multicast_frames; + unsigned int tx_fragments; + unsigned int tx_unicast_octets; + unsigned int tx_multicast_octets; + unsigned int tx_deferred_transmissions; + unsigned int tx_single_retry_frames; + unsigned int tx_multiple_retry_frames; + unsigned int tx_retry_limit_exceeded; + unsigned int tx_discards; + unsigned int rx_unicast_frames; + unsigned int rx_multicast_frames; + unsigned int rx_fragments; + unsigned int rx_unicast_octets; + unsigned int rx_multicast_octets; + unsigned int rx_fcs_errors; + unsigned int rx_discards_no_buffer; + unsigned int tx_discards_wrong_sa; + unsigned int rx_discards_undecryptable; + unsigned int rx_message_in_msg_fragments; + unsigned int rx_message_in_bad_msg_fragments; +}; + +struct libipw_device; + +#define SEC_KEY_1 (1<<0) +#define SEC_KEY_2 (1<<1) +#define SEC_KEY_3 (1<<2) +#define SEC_KEY_4 (1<<3) +#define SEC_ACTIVE_KEY (1<<4) +#define SEC_AUTH_MODE (1<<5) +#define SEC_UNICAST_GROUP (1<<6) +#define SEC_LEVEL (1<<7) +#define SEC_ENABLED (1<<8) +#define SEC_ENCRYPT (1<<9) + +#define SEC_LEVEL_0 0 /* None */ +#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ +#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ +#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ +#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ + +#define SEC_ALG_NONE 0 +#define SEC_ALG_WEP 1 +#define SEC_ALG_TKIP 2 +#define SEC_ALG_CCMP 3 + +#define WEP_KEYS 4 +#define WEP_KEY_LEN 13 +#define SCM_KEY_LEN 32 +#define SCM_TEMPORAL_KEY_LENGTH 16 + +struct libipw_security { + u16 active_key:2, enabled:1, unicast_uses_group:1, encrypt:1; + u8 auth_mode; + u8 encode_alg[WEP_KEYS]; + u8 key_sizes[WEP_KEYS]; + u8 keys[WEP_KEYS][SCM_KEY_LEN]; + u8 level; + u16 flags; +} __attribute__ ((packed)); + +/* + + 802.11 data frame from AP + + ,-------------------------------------------------------------------. +Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | + |------|------|---------|---------|---------|------|---------|------| +Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | + | | tion | (BSSID) | | | ence | data | | + `-------------------------------------------------------------------' + +Total: 28-2340 bytes + +*/ + +#define BEACON_PROBE_SSID_ID_POSITION 12 + +struct libipw_hdr_1addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct libipw_hdr_2addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct libipw_hdr_3addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __attribute__ ((packed)); + +struct libipw_hdr_4addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 addr4[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct libipw_hdr_3addrqos { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; + __le16 qos_ctl; +} __attribute__ ((packed)); + +struct libipw_info_element { + u8 id; + u8 len; + u8 data[0]; +} __attribute__ ((packed)); + +/* + * These are the data types that can make up management packets + * + u16 auth_algorithm; + u16 auth_sequence; + u16 beacon_interval; + u16 capability; + u8 current_ap[ETH_ALEN]; + u16 listen_interval; + struct { + u16 association_id:14, reserved:2; + } __attribute__ ((packed)); + u32 time_stamp[2]; + u16 reason; + u16 status; +*/ + +struct libipw_auth { + struct libipw_hdr_3addr header; + __le16 algorithm; + __le16 transaction; + __le16 status; + /* challenge */ + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +struct libipw_channel_switch { + u8 id; + u8 len; + u8 mode; + u8 channel; + u8 count; +} __attribute__ ((packed)); + +struct libipw_action { + struct libipw_hdr_3addr header; + u8 category; + u8 action; + union { + struct libipw_action_exchange { + u8 token; + struct libipw_info_element info_element[0]; + } exchange; + struct libipw_channel_switch channel_switch; + + } format; +} __attribute__ ((packed)); + +struct libipw_disassoc { + struct libipw_hdr_3addr header; + __le16 reason; +} __attribute__ ((packed)); + +/* Alias deauth for disassoc */ +#define libipw_deauth libipw_disassoc + +struct libipw_probe_request { + struct libipw_hdr_3addr header; + /* SSID, supported rates */ + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +struct libipw_probe_response { + struct libipw_hdr_3addr header; + __le32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + /* SSID, supported rates, FH params, DS params, + * CF params, IBSS params, TIM (if beacon), RSN */ + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +/* Alias beacon for probe_response */ +#define libipw_beacon libipw_probe_response + +struct libipw_assoc_request { + struct libipw_hdr_3addr header; + __le16 capability; + __le16 listen_interval; + /* SSID, supported rates, RSN */ + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +struct libipw_reassoc_request { + struct libipw_hdr_3addr header; + __le16 capability; + __le16 listen_interval; + u8 current_ap[ETH_ALEN]; + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +struct libipw_assoc_response { + struct libipw_hdr_3addr header; + __le16 capability; + __le16 status; + __le16 aid; + /* supported rates */ + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +struct libipw_txb { + u8 nr_frags; + u8 encrypted; + u8 rts_included; + u8 reserved; + u16 frag_size; + u16 payload_size; + struct sk_buff *fragments[0]; +}; + +/* SWEEP TABLE ENTRIES NUMBER */ +#define MAX_SWEEP_TAB_ENTRIES 42 +#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 +/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs + * only use 8, and then use extended rates for the remaining supported + * rates. Other APs, however, stick all of their supported rates on the + * main rates information element... */ +#define MAX_RATES_LENGTH ((u8)12) +#define MAX_RATES_EX_LENGTH ((u8)16) +#define MAX_NETWORK_COUNT 128 + +#define CRC_LENGTH 4U + +#define MAX_WPA_IE_LEN 64 + +#define NETWORK_HAS_OFDM (1<<1) +#define NETWORK_HAS_CCK (1<<2) + +/* QoS structure */ +#define NETWORK_HAS_QOS_PARAMETERS (1<<3) +#define NETWORK_HAS_QOS_INFORMATION (1<<4) +#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \ + NETWORK_HAS_QOS_INFORMATION) + +/* 802.11h */ +#define NETWORK_HAS_POWER_CONSTRAINT (1<<5) +#define NETWORK_HAS_CSA (1<<6) +#define NETWORK_HAS_QUIET (1<<7) +#define NETWORK_HAS_IBSS_DFS (1<<8) +#define NETWORK_HAS_TPC_REPORT (1<<9) + +#define NETWORK_HAS_ERP_VALUE (1<<10) + +#define QOS_QUEUE_NUM 4 +#define QOS_OUI_LEN 3 +#define QOS_OUI_TYPE 2 +#define QOS_ELEMENT_ID 221 +#define QOS_OUI_INFO_SUB_TYPE 0 +#define QOS_OUI_PARAM_SUB_TYPE 1 +#define QOS_VERSION_1 1 +#define QOS_AIFSN_MIN_VALUE 2 + +struct libipw_qos_information_element { + u8 elementID; + u8 length; + u8 qui[QOS_OUI_LEN]; + u8 qui_type; + u8 qui_subtype; + u8 version; + u8 ac_info; +} __attribute__ ((packed)); + +struct libipw_qos_ac_parameter { + u8 aci_aifsn; + u8 ecw_min_max; + __le16 tx_op_limit; +} __attribute__ ((packed)); + +struct libipw_qos_parameter_info { + struct libipw_qos_information_element info_element; + u8 reserved; + struct libipw_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; +} __attribute__ ((packed)); + +struct libipw_qos_parameters { + __le16 cw_min[QOS_QUEUE_NUM]; + __le16 cw_max[QOS_QUEUE_NUM]; + u8 aifs[QOS_QUEUE_NUM]; + u8 flag[QOS_QUEUE_NUM]; + __le16 tx_op_limit[QOS_QUEUE_NUM]; +} __attribute__ ((packed)); + +struct libipw_qos_data { + struct libipw_qos_parameters parameters; + int active; + int supported; + u8 param_count; + u8 old_param_count; +}; + +struct libipw_tim_parameters { + u8 tim_count; + u8 tim_period; +} __attribute__ ((packed)); + +/*******************************************************/ + +enum { /* libipw_basic_report.map */ + LIBIPW_BASIC_MAP_BSS = (1 << 0), + LIBIPW_BASIC_MAP_OFDM = (1 << 1), + LIBIPW_BASIC_MAP_UNIDENTIFIED = (1 << 2), + LIBIPW_BASIC_MAP_RADAR = (1 << 3), + LIBIPW_BASIC_MAP_UNMEASURED = (1 << 4), + /* Bits 5-7 are reserved */ + +}; +struct libipw_basic_report { + u8 channel; + __le64 start_time; + __le16 duration; + u8 map; +} __attribute__ ((packed)); + +enum { /* libipw_measurement_request.mode */ + /* Bit 0 is reserved */ + LIBIPW_MEASUREMENT_ENABLE = (1 << 1), + LIBIPW_MEASUREMENT_REQUEST = (1 << 2), + LIBIPW_MEASUREMENT_REPORT = (1 << 3), + /* Bits 4-7 are reserved */ +}; + +enum { + LIBIPW_REPORT_BASIC = 0, /* required */ + LIBIPW_REPORT_CCA = 1, /* optional */ + LIBIPW_REPORT_RPI = 2, /* optional */ + /* 3-255 reserved */ +}; + +struct libipw_measurement_params { + u8 channel; + __le64 start_time; + __le16 duration; +} __attribute__ ((packed)); + +struct libipw_measurement_request { + struct libipw_info_element ie; + u8 token; + u8 mode; + u8 type; + struct libipw_measurement_params params[0]; +} __attribute__ ((packed)); + +struct libipw_measurement_report { + struct libipw_info_element ie; + u8 token; + u8 mode; + u8 type; + union { + struct libipw_basic_report basic[0]; + } u; +} __attribute__ ((packed)); + +struct libipw_tpc_report { + u8 transmit_power; + u8 link_margin; +} __attribute__ ((packed)); + +struct libipw_channel_map { + u8 channel; + u8 map; +} __attribute__ ((packed)); + +struct libipw_ibss_dfs { + struct libipw_info_element ie; + u8 owner[ETH_ALEN]; + u8 recovery_interval; + struct libipw_channel_map channel_map[0]; +}; + +struct libipw_csa { + u8 mode; + u8 channel; + u8 count; +} __attribute__ ((packed)); + +struct libipw_quiet { + u8 count; + u8 period; + u8 duration; + u8 offset; +} __attribute__ ((packed)); + +struct libipw_network { + /* These entries are used to identify a unique network */ + u8 bssid[ETH_ALEN]; + u8 channel; + /* Ensure null-terminated for any debug msgs */ + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + + struct libipw_qos_data qos_data; + + /* These are network statistics */ + struct libipw_rx_stats stats; + u16 capability; + u8 rates[MAX_RATES_LENGTH]; + u8 rates_len; + u8 rates_ex[MAX_RATES_EX_LENGTH]; + u8 rates_ex_len; + unsigned long last_scanned; + u8 mode; + u32 flags; + u32 last_associate; + u32 time_stamp[2]; + u16 beacon_interval; + u16 listen_interval; + u16 atim_window; + u8 erp_value; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + u8 rsn_ie[MAX_WPA_IE_LEN]; + size_t rsn_ie_len; + struct libipw_tim_parameters tim; + + /* 802.11h info */ + + /* Power Constraint - mandatory if spctrm mgmt required */ + u8 power_constraint; + + /* TPC Report - mandatory if spctrm mgmt required */ + struct libipw_tpc_report tpc_report; + + /* IBSS DFS - mandatory if spctrm mgmt required and IBSS + * NOTE: This is variable length and so must be allocated dynamically */ + struct libipw_ibss_dfs *ibss_dfs; + + /* Channel Switch Announcement - optional if spctrm mgmt required */ + struct libipw_csa csa; + + /* Quiet - optional if spctrm mgmt required */ + struct libipw_quiet quiet; + + struct list_head list; +}; + +enum libipw_state { + LIBIPW_UNINITIALIZED = 0, + LIBIPW_INITIALIZED, + LIBIPW_ASSOCIATING, + LIBIPW_ASSOCIATED, + LIBIPW_AUTHENTICATING, + LIBIPW_AUTHENTICATED, + LIBIPW_SHUTDOWN +}; + +#define DEFAULT_MAX_SCAN_AGE (15 * HZ) +#define DEFAULT_FTS 2346 + +#define CFG_LIBIPW_RESERVE_FCS (1<<0) +#define CFG_LIBIPW_COMPUTE_FCS (1<<1) +#define CFG_LIBIPW_RTS (1<<2) + +#define LIBIPW_24GHZ_MIN_CHANNEL 1 +#define LIBIPW_24GHZ_MAX_CHANNEL 14 +#define LIBIPW_24GHZ_CHANNELS (LIBIPW_24GHZ_MAX_CHANNEL - \ + LIBIPW_24GHZ_MIN_CHANNEL + 1) + +#define LIBIPW_52GHZ_MIN_CHANNEL 34 +#define LIBIPW_52GHZ_MAX_CHANNEL 165 +#define LIBIPW_52GHZ_CHANNELS (LIBIPW_52GHZ_MAX_CHANNEL - \ + LIBIPW_52GHZ_MIN_CHANNEL + 1) + +enum { + LIBIPW_CH_PASSIVE_ONLY = (1 << 0), + LIBIPW_CH_80211H_RULES = (1 << 1), + LIBIPW_CH_B_ONLY = (1 << 2), + LIBIPW_CH_NO_IBSS = (1 << 3), + LIBIPW_CH_UNIFORM_SPREADING = (1 << 4), + LIBIPW_CH_RADAR_DETECT = (1 << 5), + LIBIPW_CH_INVALID = (1 << 6), +}; + +struct libipw_channel { + u32 freq; /* in MHz */ + u8 channel; + u8 flags; + u8 max_power; /* in dBm */ +}; + +struct libipw_geo { + u8 name[4]; + u8 bg_channels; + u8 a_channels; + struct libipw_channel bg[LIBIPW_24GHZ_CHANNELS]; + struct libipw_channel a[LIBIPW_52GHZ_CHANNELS]; +}; + +struct libipw_device { + struct net_device *dev; + struct libipw_security sec; + + /* Bookkeeping structures */ + struct libipw_stats ieee_stats; + + struct libipw_geo geo; + + /* Probe / Beacon management */ + struct list_head network_free_list; + struct list_head network_list; + struct libipw_network *networks; + int scans; + int scan_age; + + int iw_mode; /* operating mode (IW_MODE_*) */ + struct iw_spy_data spy_data; /* iwspy support */ + + spinlock_t lock; + + int tx_headroom; /* Set to size of any additional room needed at front + * of allocated Tx SKBs */ + u32 config; + + /* WEP and other encryption related settings at the device level */ + int open_wep; /* Set to 1 to allow unencrypted frames */ + + int reset_on_keychange; /* Set to 1 if the HW needs to be reset on + * WEP key changes */ + + /* If the host performs {en,de}cryption, then set to 1 */ + int host_encrypt; + int host_encrypt_msdu; + int host_decrypt; + /* host performs multicast decryption */ + int host_mc_decrypt; + + /* host should strip IV and ICV from protected frames */ + /* meaningful only when hardware decryption is being used */ + int host_strip_iv_icv; + + int host_open_frag; + int host_build_iv; + int ieee802_1x; /* is IEEE 802.1X used */ + + /* WPA data */ + int wpa_enabled; + int drop_unencrypted; + int privacy_invoked; + size_t wpa_ie_len; + u8 *wpa_ie; + + struct lib80211_crypt_info crypt_info; + + int bcrx_sta_key; /* use individual keys to override default keys even + * with RX of broad/multicast frames */ + + /* Fragmentation structures */ + struct libipw_frag_entry frag_cache[LIBIPW_FRAG_CACHE_LEN]; + unsigned int frag_next_idx; + u16 fts; /* Fragmentation Threshold */ + u16 rts; /* RTS threshold */ + + /* Association info */ + u8 bssid[ETH_ALEN]; + + enum libipw_state state; + + int mode; /* A, B, G */ + int modulation; /* CCK, OFDM */ + int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ + int abg_true; /* ABG flag */ + + int perfect_rssi; + int worst_rssi; + + u16 prev_seq_ctl; /* used to drop duplicate frames */ + + /* Callback functions */ + void (*set_security) (struct net_device * dev, + struct libipw_security * sec); + int (*hard_start_xmit) (struct libipw_txb * txb, + struct net_device * dev, int pri); + int (*reset_port) (struct net_device * dev); + int (*is_queue_full) (struct net_device * dev, int pri); + + int (*handle_management) (struct net_device * dev, + struct libipw_network * network, u16 type); + int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb); + + /* Typical STA methods */ + int (*handle_auth) (struct net_device * dev, + struct libipw_auth * auth); + int (*handle_deauth) (struct net_device * dev, + struct libipw_deauth * auth); + int (*handle_action) (struct net_device * dev, + struct libipw_action * action, + struct libipw_rx_stats * stats); + int (*handle_disassoc) (struct net_device * dev, + struct libipw_disassoc * assoc); + int (*handle_beacon) (struct net_device * dev, + struct libipw_beacon * beacon, + struct libipw_network * network); + int (*handle_probe_response) (struct net_device * dev, + struct libipw_probe_response * resp, + struct libipw_network * network); + int (*handle_probe_request) (struct net_device * dev, + struct libipw_probe_request * req, + struct libipw_rx_stats * stats); + int (*handle_assoc_response) (struct net_device * dev, + struct libipw_assoc_response * resp, + struct libipw_network * network); + + /* Typical AP methods */ + int (*handle_assoc_request) (struct net_device * dev); + int (*handle_reassoc_request) (struct net_device * dev, + struct libipw_reassoc_request * req); + + /* This must be the last item so that it points to the data + * allocated beyond this structure by alloc_ieee80211 */ + u8 priv[0]; +}; + +#define IEEE_A (1<<0) +#define IEEE_B (1<<1) +#define IEEE_G (1<<2) +#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) + +static inline void *libipw_priv(struct net_device *dev) +{ + return ((struct libipw_device *)netdev_priv(dev))->priv; +} + +static inline int libipw_is_valid_mode(struct libipw_device *ieee, + int mode) +{ + /* + * It is possible for both access points and our device to support + * combinations of modes, so as long as there is one valid combination + * of ap/device supported modes, then return success + * + */ + if ((mode & IEEE_A) && + (ieee->modulation & LIBIPW_OFDM_MODULATION) && + (ieee->freq_band & LIBIPW_52GHZ_BAND)) + return 1; + + if ((mode & IEEE_G) && + (ieee->modulation & LIBIPW_OFDM_MODULATION) && + (ieee->freq_band & LIBIPW_24GHZ_BAND)) + return 1; + + if ((mode & IEEE_B) && + (ieee->modulation & LIBIPW_CCK_MODULATION) && + (ieee->freq_band & LIBIPW_24GHZ_BAND)) + return 1; + + return 0; +} + +static inline int libipw_get_hdrlen(u16 fc) +{ + int hdrlen = LIBIPW_3ADDR_LEN; + u16 stype = WLAN_FC_GET_STYPE(fc); + + switch (WLAN_FC_GET_TYPE(fc)) { + case IEEE80211_FTYPE_DATA: + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) + hdrlen = LIBIPW_4ADDR_LEN; + if (stype & IEEE80211_STYPE_QOS_DATA) + hdrlen += 2; + break; + case IEEE80211_FTYPE_CTL: + switch (WLAN_FC_GET_STYPE(fc)) { + case IEEE80211_STYPE_CTS: + case IEEE80211_STYPE_ACK: + hdrlen = LIBIPW_1ADDR_LEN; + break; + default: + hdrlen = LIBIPW_2ADDR_LEN; + break; + } + break; + } + + return hdrlen; +} + +static inline u8 *libipw_get_payload(struct ieee80211_hdr *hdr) +{ + switch (libipw_get_hdrlen(le16_to_cpu(hdr->frame_control))) { + case LIBIPW_1ADDR_LEN: + return ((struct libipw_hdr_1addr *)hdr)->payload; + case LIBIPW_2ADDR_LEN: + return ((struct libipw_hdr_2addr *)hdr)->payload; + case LIBIPW_3ADDR_LEN: + return ((struct libipw_hdr_3addr *)hdr)->payload; + case LIBIPW_4ADDR_LEN: + return ((struct libipw_hdr_4addr *)hdr)->payload; + } + return NULL; +} + +static inline int libipw_is_ofdm_rate(u8 rate) +{ + switch (rate & ~LIBIPW_BASIC_RATE_MASK) { + case LIBIPW_OFDM_RATE_6MB: + case LIBIPW_OFDM_RATE_9MB: + case LIBIPW_OFDM_RATE_12MB: + case LIBIPW_OFDM_RATE_18MB: + case LIBIPW_OFDM_RATE_24MB: + case LIBIPW_OFDM_RATE_36MB: + case LIBIPW_OFDM_RATE_48MB: + case LIBIPW_OFDM_RATE_54MB: + return 1; + } + return 0; +} + +static inline int libipw_is_cck_rate(u8 rate) +{ + switch (rate & ~LIBIPW_BASIC_RATE_MASK) { + case LIBIPW_CCK_RATE_1MB: + case LIBIPW_CCK_RATE_2MB: + case LIBIPW_CCK_RATE_5MB: + case LIBIPW_CCK_RATE_11MB: + return 1; + } + return 0; +} + +/* ieee80211.c */ +extern void free_ieee80211(struct net_device *dev); +extern struct net_device *alloc_ieee80211(int sizeof_priv); +extern int libipw_change_mtu(struct net_device *dev, int new_mtu); + +extern void libipw_networks_age(struct libipw_device *ieee, + unsigned long age_secs); + +extern int libipw_set_encryption(struct libipw_device *ieee); + +/* libipw_tx.c */ +extern int libipw_xmit(struct sk_buff *skb, struct net_device *dev); +extern void libipw_txb_free(struct libipw_txb *); + +/* libipw_rx.c */ +extern void libipw_rx_any(struct libipw_device *ieee, + struct sk_buff *skb, struct libipw_rx_stats *stats); +extern int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb, + struct libipw_rx_stats *rx_stats); +/* make sure to set stats->len */ +extern void libipw_rx_mgt(struct libipw_device *ieee, + struct libipw_hdr_4addr *header, + struct libipw_rx_stats *stats); +extern void libipw_network_reset(struct libipw_network *network); + +/* libipw_geo.c */ +extern const struct libipw_geo *libipw_get_geo(struct libipw_device + *ieee); +extern int libipw_set_geo(struct libipw_device *ieee, + const struct libipw_geo *geo); + +extern int libipw_is_valid_channel(struct libipw_device *ieee, + u8 channel); +extern int libipw_channel_to_index(struct libipw_device *ieee, + u8 channel); +extern u8 libipw_freq_to_channel(struct libipw_device *ieee, u32 freq); +extern u8 libipw_get_channel_flags(struct libipw_device *ieee, + u8 channel); +extern const struct libipw_channel *libipw_get_channel(struct + libipw_device + *ieee, u8 channel); +extern u32 libipw_channel_to_freq(struct libipw_device * ieee, + u8 channel); + +/* libipw_wx.c */ +extern int libipw_wx_get_scan(struct libipw_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int libipw_wx_set_encode(struct libipw_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int libipw_wx_get_encode(struct libipw_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int libipw_wx_set_encodeext(struct libipw_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +extern int libipw_wx_get_encodeext(struct libipw_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +static inline void libipw_increment_scans(struct libipw_device *ieee) +{ + ieee->scans++; +} + +static inline int libipw_get_scans(struct libipw_device *ieee) +{ + return ieee->scans; +} + +#endif /* LIBIPW_H */ diff --git a/drivers/net/wireless/ipw2x00/libipw_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c index 9dfbb87..d04979b 100644 --- a/drivers/net/wireless/ipw2x00/libipw_geo.c +++ b/drivers/net/wireless/ipw2x00/libipw_geo.c @@ -41,9 +41,9 @@ #include #include -#include "ieee80211.h" +#include "libipw.h" -int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel) +int libipw_is_valid_channel(struct libipw_device *ieee, u8 channel) { int i; @@ -52,27 +52,27 @@ int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel) if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) return 0; - if (ieee->freq_band & IEEE80211_24GHZ_BAND) + if (ieee->freq_band & LIBIPW_24GHZ_BAND) for (i = 0; i < ieee->geo.bg_channels; i++) /* NOTE: If G mode is currently supported but * this is a B only channel, we don't see it * as valid. */ if ((ieee->geo.bg[i].channel == channel) && - !(ieee->geo.bg[i].flags & IEEE80211_CH_INVALID) && + !(ieee->geo.bg[i].flags & LIBIPW_CH_INVALID) && (!(ieee->mode & IEEE_G) || - !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY))) - return IEEE80211_24GHZ_BAND; + !(ieee->geo.bg[i].flags & LIBIPW_CH_B_ONLY))) + return LIBIPW_24GHZ_BAND; - if (ieee->freq_band & IEEE80211_52GHZ_BAND) + if (ieee->freq_band & LIBIPW_52GHZ_BAND) for (i = 0; i < ieee->geo.a_channels; i++) if ((ieee->geo.a[i].channel == channel) && - !(ieee->geo.a[i].flags & IEEE80211_CH_INVALID)) - return IEEE80211_52GHZ_BAND; + !(ieee->geo.a[i].flags & LIBIPW_CH_INVALID)) + return LIBIPW_52GHZ_BAND; return 0; } -int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel) +int libipw_channel_to_index(struct libipw_device *ieee, u8 channel) { int i; @@ -81,12 +81,12 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel) if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) return -1; - if (ieee->freq_band & IEEE80211_24GHZ_BAND) + if (ieee->freq_band & LIBIPW_24GHZ_BAND) for (i = 0; i < ieee->geo.bg_channels; i++) if (ieee->geo.bg[i].channel == channel) return i; - if (ieee->freq_band & IEEE80211_52GHZ_BAND) + if (ieee->freq_band & LIBIPW_52GHZ_BAND) for (i = 0; i < ieee->geo.a_channels; i++) if (ieee->geo.a[i].channel == channel) return i; @@ -94,22 +94,22 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel) return -1; } -u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel) +u32 libipw_channel_to_freq(struct libipw_device * ieee, u8 channel) { - const struct ieee80211_channel * ch; + const struct libipw_channel * ch; /* Driver needs to initialize the geography map before using * these helper functions */ if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) return 0; - ch = ieee80211_get_channel(ieee, channel); + ch = libipw_get_channel(ieee, channel); if (!ch->channel) return 0; return ch->freq; } -u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq) +u8 libipw_freq_to_channel(struct libipw_device * ieee, u32 freq) { int i; @@ -120,12 +120,12 @@ u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq) freq /= 100000; - if (ieee->freq_band & IEEE80211_24GHZ_BAND) + if (ieee->freq_band & LIBIPW_24GHZ_BAND) for (i = 0; i < ieee->geo.bg_channels; i++) if (ieee->geo.bg[i].freq == freq) return ieee->geo.bg[i].channel; - if (ieee->freq_band & IEEE80211_52GHZ_BAND) + if (ieee->freq_band & LIBIPW_52GHZ_BAND) for (i = 0; i < ieee->geo.a_channels; i++) if (ieee->geo.a[i].freq == freq) return ieee->geo.a[i].channel; @@ -133,63 +133,63 @@ u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq) return 0; } -int ieee80211_set_geo(struct ieee80211_device *ieee, - const struct ieee80211_geo *geo) +int libipw_set_geo(struct libipw_device *ieee, + const struct libipw_geo *geo) { memcpy(ieee->geo.name, geo->name, 3); ieee->geo.name[3] = '\0'; ieee->geo.bg_channels = geo->bg_channels; ieee->geo.a_channels = geo->a_channels; memcpy(ieee->geo.bg, geo->bg, geo->bg_channels * - sizeof(struct ieee80211_channel)); + sizeof(struct libipw_channel)); memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels * - sizeof(struct ieee80211_channel)); + sizeof(struct libipw_channel)); return 0; } -const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device *ieee) +const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee) { return &ieee->geo; } -u8 ieee80211_get_channel_flags(struct ieee80211_device * ieee, u8 channel) +u8 libipw_get_channel_flags(struct libipw_device * ieee, u8 channel) { - int index = ieee80211_channel_to_index(ieee, channel); + int index = libipw_channel_to_index(ieee, channel); if (index == -1) - return IEEE80211_CH_INVALID; + return LIBIPW_CH_INVALID; - if (channel <= IEEE80211_24GHZ_CHANNELS) + if (channel <= LIBIPW_24GHZ_CHANNELS) return ieee->geo.bg[index].flags; return ieee->geo.a[index].flags; } -static const struct ieee80211_channel bad_channel = { +static const struct libipw_channel bad_channel = { .channel = 0, - .flags = IEEE80211_CH_INVALID, + .flags = LIBIPW_CH_INVALID, .max_power = 0, }; -const struct ieee80211_channel *ieee80211_get_channel(struct ieee80211_device +const struct libipw_channel *libipw_get_channel(struct libipw_device *ieee, u8 channel) { - int index = ieee80211_channel_to_index(ieee, channel); + int index = libipw_channel_to_index(ieee, channel); if (index == -1) return &bad_channel; - if (channel <= IEEE80211_24GHZ_CHANNELS) + if (channel <= LIBIPW_24GHZ_CHANNELS) return &ieee->geo.bg[index]; return &ieee->geo.a[index]; } -EXPORT_SYMBOL(ieee80211_get_channel); -EXPORT_SYMBOL(ieee80211_get_channel_flags); -EXPORT_SYMBOL(ieee80211_is_valid_channel); -EXPORT_SYMBOL(ieee80211_freq_to_channel); -EXPORT_SYMBOL(ieee80211_channel_to_freq); -EXPORT_SYMBOL(ieee80211_channel_to_index); -EXPORT_SYMBOL(ieee80211_set_geo); -EXPORT_SYMBOL(ieee80211_get_geo); +EXPORT_SYMBOL(libipw_get_channel); +EXPORT_SYMBOL(libipw_get_channel_flags); +EXPORT_SYMBOL(libipw_is_valid_channel); +EXPORT_SYMBOL(libipw_freq_to_channel); +EXPORT_SYMBOL(libipw_channel_to_freq); +EXPORT_SYMBOL(libipw_channel_to_index); +EXPORT_SYMBOL(libipw_set_geo); +EXPORT_SYMBOL(libipw_get_geo); diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index 8ce6e96..00c3640 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -50,11 +50,11 @@ #include #include -#include "ieee80211.h" +#include "libipw.h" #define DRV_DESCRIPTION "802.11 data/management/control stack" #define DRV_NAME "ieee80211" -#define DRV_VERSION IEEE80211_VERSION +#define DRV_VERSION LIBIPW_VERSION #define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation " MODULE_VERSION(DRV_VERSION); @@ -62,13 +62,13 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -static int ieee80211_networks_allocate(struct ieee80211_device *ieee) +static int libipw_networks_allocate(struct libipw_device *ieee) { if (ieee->networks) return 0; ieee->networks = - kzalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network), + kzalloc(MAX_NETWORK_COUNT * sizeof(struct libipw_network), GFP_KERNEL); if (!ieee->networks) { printk(KERN_WARNING "%s: Out of memory allocating beacons\n", @@ -79,7 +79,7 @@ static int ieee80211_networks_allocate(struct ieee80211_device *ieee) return 0; } -void ieee80211_network_reset(struct ieee80211_network *network) +void libipw_network_reset(struct libipw_network *network) { if (!network) return; @@ -90,7 +90,7 @@ void ieee80211_network_reset(struct ieee80211_network *network) } } -static inline void ieee80211_networks_free(struct ieee80211_device *ieee) +static inline void libipw_networks_free(struct libipw_device *ieee) { int i; @@ -105,10 +105,10 @@ static inline void ieee80211_networks_free(struct ieee80211_device *ieee) ieee->networks = NULL; } -void ieee80211_networks_age(struct ieee80211_device *ieee, +void libipw_networks_age(struct libipw_device *ieee, unsigned long age_secs) { - struct ieee80211_network *network = NULL; + struct libipw_network *network = NULL; unsigned long flags; unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); @@ -118,9 +118,9 @@ void ieee80211_networks_age(struct ieee80211_device *ieee, } spin_unlock_irqrestore(&ieee->lock, flags); } -EXPORT_SYMBOL(ieee80211_networks_age); +EXPORT_SYMBOL(libipw_networks_age); -static void ieee80211_networks_initialize(struct ieee80211_device *ieee) +static void libipw_networks_initialize(struct libipw_device *ieee) { int i; @@ -131,38 +131,38 @@ static void ieee80211_networks_initialize(struct ieee80211_device *ieee) &ieee->network_free_list); } -int ieee80211_change_mtu(struct net_device *dev, int new_mtu) +int libipw_change_mtu(struct net_device *dev, int new_mtu) { - if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN)) + if ((new_mtu < 68) || (new_mtu > LIBIPW_DATA_LEN)) return -EINVAL; dev->mtu = new_mtu; return 0; } -EXPORT_SYMBOL(ieee80211_change_mtu); +EXPORT_SYMBOL(libipw_change_mtu); struct net_device *alloc_ieee80211(int sizeof_priv) { - struct ieee80211_device *ieee; + struct libipw_device *ieee; struct net_device *dev; int err; - IEEE80211_DEBUG_INFO("Initializing...\n"); + LIBIPW_DEBUG_INFO("Initializing...\n"); - dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv); + dev = alloc_etherdev(sizeof(struct libipw_device) + sizeof_priv); if (!dev) { - IEEE80211_ERROR("Unable to allocate network device.\n"); + LIBIPW_ERROR("Unable to allocate network device.\n"); goto failed; } ieee = netdev_priv(dev); ieee->dev = dev; - err = ieee80211_networks_allocate(ieee); + err = libipw_networks_allocate(ieee); if (err) { - IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err); + LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err); goto failed_free_netdev; } - ieee80211_networks_initialize(ieee); + libipw_networks_initialize(ieee); /* Default fragmentation threshold is maximum payload size */ ieee->fts = DEFAULT_FTS; @@ -201,25 +201,25 @@ failed: void free_ieee80211(struct net_device *dev) { - struct ieee80211_device *ieee = netdev_priv(dev); + struct libipw_device *ieee = netdev_priv(dev); lib80211_crypt_info_free(&ieee->crypt_info); - ieee80211_networks_free(ieee); + libipw_networks_free(ieee); free_netdev(dev); } #ifdef CONFIG_LIBIPW_DEBUG static int debug = 0; -u32 ieee80211_debug_level = 0; -EXPORT_SYMBOL_GPL(ieee80211_debug_level); -static struct proc_dir_entry *ieee80211_proc = NULL; +u32 libipw_debug_level = 0; +EXPORT_SYMBOL_GPL(libipw_debug_level); +static struct proc_dir_entry *libipw_proc = NULL; static int show_debug_level(char *page, char **start, off_t offset, int count, int *eof, void *data) { - return snprintf(page, count, "0x%08X\n", ieee80211_debug_level); + return snprintf(page, count, "0x%08X\n", libipw_debug_level); } static int store_debug_level(struct file *file, const char __user * buffer, @@ -236,29 +236,29 @@ static int store_debug_level(struct file *file, const char __user * buffer, printk(KERN_INFO DRV_NAME ": %s is not in hex or decimal form.\n", buf); else - ieee80211_debug_level = val; + libipw_debug_level = val; return strnlen(buf, len); } #endif /* CONFIG_LIBIPW_DEBUG */ -static int __init ieee80211_init(void) +static int __init libipw_init(void) { #ifdef CONFIG_LIBIPW_DEBUG struct proc_dir_entry *e; - ieee80211_debug_level = debug; - ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net); - if (ieee80211_proc == NULL) { - IEEE80211_ERROR("Unable to create " DRV_NAME + libipw_debug_level = debug; + libipw_proc = proc_mkdir(DRV_NAME, init_net.proc_net); + if (libipw_proc == NULL) { + LIBIPW_ERROR("Unable to create " DRV_NAME " proc directory\n"); return -EIO; } e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, - ieee80211_proc); + libipw_proc); if (!e) { remove_proc_entry(DRV_NAME, init_net.proc_net); - ieee80211_proc = NULL; + libipw_proc = NULL; return -EIO; } e->read_proc = show_debug_level; @@ -272,13 +272,13 @@ static int __init ieee80211_init(void) return 0; } -static void __exit ieee80211_exit(void) +static void __exit libipw_exit(void) { #ifdef CONFIG_LIBIPW_DEBUG - if (ieee80211_proc) { - remove_proc_entry("debug_level", ieee80211_proc); + if (libipw_proc) { + remove_proc_entry("debug_level", libipw_proc); remove_proc_entry(DRV_NAME, init_net.proc_net); - ieee80211_proc = NULL; + libipw_proc = NULL; } #endif /* CONFIG_LIBIPW_DEBUG */ } @@ -289,8 +289,8 @@ module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); #endif /* CONFIG_LIBIPW_DEBUG */ -module_exit(ieee80211_exit); -module_init(ieee80211_init); +module_exit(libipw_exit); +module_init(libipw_init); EXPORT_SYMBOL(alloc_ieee80211); EXPORT_SYMBOL(free_ieee80211); diff --git a/drivers/net/wireless/ipw2x00/libipw_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c index dae4b8e..282b1f7 100644 --- a/drivers/net/wireless/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/ipw2x00/libipw_rx.c @@ -34,18 +34,18 @@ #include -#include "ieee80211.h" +#include "libipw.h" -static void ieee80211_monitor_rx(struct ieee80211_device *ieee, +static void libipw_monitor_rx(struct libipw_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats) + struct libipw_rx_stats *rx_stats) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; u16 fc = le16_to_cpu(hdr->frame_control); skb->dev = ieee->dev; skb_reset_mac_header(skb); - skb_pull(skb, ieee80211_get_hdrlen(fc)); + skb_pull(skb, libipw_get_hdrlen(fc)); skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_80211_RAW); memset(skb->cb, 0, sizeof(skb->cb)); @@ -53,22 +53,22 @@ static void ieee80211_monitor_rx(struct ieee80211_device *ieee, } /* Called only as a tasklet (software IRQ) */ -static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct - ieee80211_device +static struct libipw_frag_entry *libipw_frag_cache_find(struct + libipw_device *ieee, unsigned int seq, unsigned int frag, u8 * src, u8 * dst) { - struct ieee80211_frag_entry *entry; + struct libipw_frag_entry *entry; int i; - for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) { + for (i = 0; i < LIBIPW_FRAG_CACHE_LEN; i++) { entry = &ieee->frag_cache[i]; if (entry->skb != NULL && time_after(jiffies, entry->first_frag_time + 2 * HZ)) { - IEEE80211_DEBUG_FRAG("expiring fragment cache entry " + LIBIPW_DEBUG_FRAG("expiring fragment cache entry " "seq=%u last_frag=%u\n", entry->seq, entry->last_frag); dev_kfree_skb_any(entry->skb); @@ -86,13 +86,13 @@ static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct } /* Called only as a tasklet (software IRQ) */ -static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *hdr) +static struct sk_buff *libipw_frag_cache_get(struct libipw_device *ieee, + struct libipw_hdr_4addr *hdr) { struct sk_buff *skb = NULL; u16 sc; unsigned int frag, seq; - struct ieee80211_frag_entry *entry; + struct libipw_frag_entry *entry; sc = le16_to_cpu(hdr->seq_ctl); frag = WLAN_GET_SEQ_FRAG(sc); @@ -101,7 +101,7 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, if (frag == 0) { /* Reserve enough space to fit maximum frame length */ skb = dev_alloc_skb(ieee->dev->mtu + - sizeof(struct ieee80211_hdr_4addr) + + sizeof(struct libipw_hdr_4addr) + 8 /* LLC */ + 2 /* alignment */ + 8 /* WEP */ + ETH_ALEN /* WDS */ ); @@ -110,7 +110,7 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, entry = &ieee->frag_cache[ieee->frag_next_idx]; ieee->frag_next_idx++; - if (ieee->frag_next_idx >= IEEE80211_FRAG_CACHE_LEN) + if (ieee->frag_next_idx >= LIBIPW_FRAG_CACHE_LEN) ieee->frag_next_idx = 0; if (entry->skb != NULL) @@ -125,7 +125,7 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, } else { /* received a fragment of a frame for which the head fragment * should have already been received */ - entry = ieee80211_frag_cache_find(ieee, seq, frag, hdr->addr2, + entry = libipw_frag_cache_find(ieee, seq, frag, hdr->addr2, hdr->addr1); if (entry != NULL) { entry->last_frag = frag; @@ -137,21 +137,21 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, } /* Called only as a tasklet (software IRQ) */ -static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *hdr) +static int libipw_frag_cache_invalidate(struct libipw_device *ieee, + struct libipw_hdr_4addr *hdr) { u16 sc; unsigned int seq; - struct ieee80211_frag_entry *entry; + struct libipw_frag_entry *entry; sc = le16_to_cpu(hdr->seq_ctl); seq = WLAN_GET_SEQ_SEQ(sc); - entry = ieee80211_frag_cache_find(ieee, seq, -1, hdr->addr2, + entry = libipw_frag_cache_find(ieee, seq, -1, hdr->addr2, hdr->addr1); if (entry == NULL) { - IEEE80211_DEBUG_FRAG("could not invalidate fragment cache " + LIBIPW_DEBUG_FRAG("could not invalidate fragment cache " "entry (seq=%u)\n", seq); return -1; } @@ -161,14 +161,14 @@ static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, } #ifdef NOT_YET -/* ieee80211_rx_frame_mgtmt +/* libipw_rx_frame_mgtmt * * Responsible for handling management control frames * - * Called by ieee80211_rx */ + * Called by libipw_rx */ static int -ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats, u16 type, +libipw_rx_frame_mgmt(struct libipw_device *ieee, struct sk_buff *skb, + struct libipw_rx_stats *rx_stats, u16 type, u16 stype) { if (ieee->iw_mode == IW_MODE_MASTER) { @@ -176,7 +176,7 @@ ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, ieee->dev->name); return 0; /* - hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr_4addr *) + hostap_update_sta_ps(ieee, (struct hostap_libipw_hdr_4addr *) skb->data);*/ } @@ -219,26 +219,27 @@ ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; +static unsigned char libipw_rfc1042_header[] = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char bridge_tunnel_header[] = +static unsigned char libipw_bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; /* No encapsulation header if EtherType < 0x600 (=length) */ -/* Called by ieee80211_rx_frame_decrypt */ -static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, +/* Called by libipw_rx_frame_decrypt */ +static int libipw_is_eapol_frame(struct libipw_device *ieee, struct sk_buff *skb) { struct net_device *dev = ieee->dev; u16 fc, ethertype; - struct ieee80211_hdr_3addr *hdr; + struct libipw_hdr_3addr *hdr; u8 *pos; if (skb->len < 24) return 0; - hdr = (struct ieee80211_hdr_3addr *)skb->data; + hdr = (struct libipw_hdr_3addr *)skb->data; fc = le16_to_cpu(hdr->frame_ctl); /* check that the frame is unicast frame to us */ @@ -266,28 +267,28 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, return 0; } -/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +/* Called only as a tasklet (software IRQ), by libipw_rx */ static int -ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, +libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb, struct lib80211_crypt_data *crypt) { - struct ieee80211_hdr_3addr *hdr; + struct libipw_hdr_3addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) return 0; - hdr = (struct ieee80211_hdr_3addr *)skb->data; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + hdr = (struct libipw_hdr_3addr *)skb->data; + hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); atomic_inc(&crypt->refcnt); res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { - IEEE80211_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n", + LIBIPW_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n", hdr->addr2, res); if (res == -2) - IEEE80211_DEBUG_DROP("Decryption failed ICV " + LIBIPW_DEBUG_DROP("Decryption failed ICV " "mismatch (key %d)\n", skb->data[hdrlen + 3] >> 6); ieee->ieee_stats.rx_discards_undecryptable++; @@ -297,20 +298,20 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, return res; } -/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +/* Called only as a tasklet (software IRQ), by libipw_rx */ static int -ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, +libipw_rx_frame_decrypt_msdu(struct libipw_device *ieee, struct sk_buff *skb, int keyidx, struct lib80211_crypt_data *crypt) { - struct ieee80211_hdr_3addr *hdr; + struct libipw_hdr_3addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; - hdr = (struct ieee80211_hdr_3addr *)skb->data; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + hdr = (struct libipw_hdr_3addr *)skb->data; + hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); atomic_inc(&crypt->refcnt); res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); @@ -328,11 +329,11 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, /* All received frames are sent to this function. @skb contains the frame in * IEEE 802.11 format, i.e., in the format it was sent over air. * This function is called only as a tasklet (software IRQ). */ -int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats) +int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb, + struct libipw_rx_stats *rx_stats) { struct net_device *dev = ieee->dev; - struct ieee80211_hdr_4addr *hdr; + struct libipw_hdr_4addr *hdr; size_t hdrlen; u16 fc, type, stype, sc; unsigned int frag; @@ -352,7 +353,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, int keyidx = 0; int can_be_decrypted = 0; - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct libipw_hdr_4addr *)skb->data; if (skb->len < 10) { printk(KERN_INFO "%s: SKB length < 10\n", dev->name); goto rx_dropped; @@ -363,7 +364,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, stype = WLAN_FC_GET_STYPE(fc); sc = le16_to_cpu(hdr->seq_ctl); frag = WLAN_GET_SEQ_FRAG(sc); - hdrlen = ieee80211_get_hdrlen(fc); + hdrlen = libipw_get_hdrlen(fc); if (skb->len < hdrlen) { printk(KERN_INFO "%s: invalid SKB length %d\n", @@ -380,19 +381,19 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct iw_quality wstats; wstats.updated = 0; - if (rx_stats->mask & IEEE80211_STATMASK_RSSI) { + if (rx_stats->mask & LIBIPW_STATMASK_RSSI) { wstats.level = rx_stats->signal; wstats.updated |= IW_QUAL_LEVEL_UPDATED; } else wstats.updated |= IW_QUAL_LEVEL_INVALID; - if (rx_stats->mask & IEEE80211_STATMASK_NOISE) { + if (rx_stats->mask & LIBIPW_STATMASK_NOISE) { wstats.noise = rx_stats->noise; wstats.updated |= IW_QUAL_NOISE_UPDATED; } else wstats.updated |= IW_QUAL_NOISE_INVALID; - if (rx_stats->mask & IEEE80211_STATMASK_SIGNAL) { + if (rx_stats->mask & LIBIPW_STATMASK_SIGNAL) { wstats.qual = rx_stats->signal; wstats.updated |= IW_QUAL_QUAL_UPDATED; } else @@ -411,7 +412,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, if (ieee->iw_mode == IW_MODE_MONITOR) { dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; - ieee80211_monitor_rx(ieee, skb, rx_stats); + libipw_monitor_rx(ieee, skb, rx_stats); return 1; } @@ -457,7 +458,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * frames from other than current BSS, so just drop the * frames silently instead of filling system log with * these reports. */ - IEEE80211_DEBUG_DROP("Decryption failed (not set)" + LIBIPW_DEBUG_DROP("Decryption failed (not set)" " (SA=%pM)\n", hdr->addr2); ieee->ieee_stats.rx_discards_undecryptable++; goto rx_dropped; @@ -475,7 +476,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, goto rx_dropped; } - if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) + if (libipw_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) goto rx_dropped; else goto rx_exit; @@ -488,7 +489,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, ieee->prev_seq_ctl = sc; /* Data frame - extract src/dst addresses */ - if (skb->len < IEEE80211_3ADDR_LEN) + if (skb->len < LIBIPW_3ADDR_LEN) goto rx_dropped; switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { @@ -501,7 +502,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, memcpy(src, hdr->addr2, ETH_ALEN); break; case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: - if (skb->len < IEEE80211_4ADDR_LEN) + if (skb->len < LIBIPW_4ADDR_LEN) goto rx_dropped; memcpy(dst, hdr->addr3, ETH_ALEN); memcpy(src, hdr->addr4, ETH_ALEN); @@ -560,7 +561,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, stype != IEEE80211_STYPE_DATA_CFPOLL && stype != IEEE80211_STYPE_DATA_CFACKPOLL) { if (stype != IEEE80211_STYPE_NULLFUNC) - IEEE80211_DEBUG_DROP("RX: dropped data frame " + LIBIPW_DEBUG_DROP("RX: dropped data frame " "with no data (type=0x%02x, " "subtype=0x%02x, len=%d)\n", type, stype, skb->len); @@ -570,21 +571,21 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted && - (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) + (keyidx = libipw_rx_frame_decrypt(ieee, skb, crypt)) < 0) goto rx_dropped; - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct libipw_hdr_4addr *)skb->data; /* skb: hdr + (possibly fragmented) plaintext payload */ // PR: FIXME: hostap has additional conditions in the "if" below: // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) { int flen; - struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr); - IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); + struct sk_buff *frag_skb = libipw_frag_cache_get(ieee, hdr); + LIBIPW_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); if (!frag_skb) { - IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG, + LIBIPW_DEBUG(LIBIPW_DL_RX | LIBIPW_DL_FRAG, "Rx cannot get skb from fragment " "cache (morefrag=%d seq=%u frag=%u)\n", (fc & IEEE80211_FCTL_MOREFRAGS) != 0, @@ -600,7 +601,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, printk(KERN_WARNING "%s: host decrypted and " "reassembled frame did not fit skb\n", dev->name); - ieee80211_frag_cache_invalidate(ieee, hdr); + libipw_frag_cache_invalidate(ieee, hdr); goto rx_dropped; } @@ -627,24 +628,24 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* this was the last fragment and the frame will be * delivered, so remove skb from fragment cache */ skb = frag_skb; - hdr = (struct ieee80211_hdr_4addr *)skb->data; - ieee80211_frag_cache_invalidate(ieee, hdr); + hdr = (struct libipw_hdr_4addr *)skb->data; + libipw_frag_cache_invalidate(ieee, hdr); } /* skb: hdr + (possible reassembled) full MSDU payload; possibly still * encrypted/authenticated */ if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted && - ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) + libipw_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) goto rx_dropped; - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct libipw_hdr_4addr *)skb->data; if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) { if ( /*ieee->ieee802_1x && */ - ieee80211_is_eapol_frame(ieee, skb)) { + libipw_is_eapol_frame(ieee, skb)) { /* pass unencrypted EAPOL frames even if encryption is * configured */ } else { - IEEE80211_DEBUG_DROP("encryption configured, but RX " + LIBIPW_DEBUG_DROP("encryption configured, but RX " "frame not encrypted (SA=%pM)\n", hdr->addr2); goto rx_dropped; @@ -652,8 +653,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, } if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep && - !ieee80211_is_eapol_frame(ieee, skb)) { - IEEE80211_DEBUG_DROP("dropped unencrypted RX data " + !libipw_is_eapol_frame(ieee, skb)) { + LIBIPW_DEBUG_DROP("dropped unencrypted RX data " "frame from %pM (drop_unencrypted=1)\n", hdr->addr2); goto rx_dropped; @@ -736,9 +737,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* convert hdr + possible LLC headers into Ethernet header */ if (skb->len - hdrlen >= 8 && - ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && + ((memcmp(payload, libipw_rfc1042_header, SNAP_SIZE) == 0 && ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { + memcmp(payload, libipw_bridge_tunnel_header, SNAP_SIZE) == 0)) { /* remove RFC1042 or Bridge-Tunnel encapsulation and * replace EtherType */ skb_pull(skb, hdrlen + SNAP_SIZE); @@ -807,7 +808,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* netif_rx always succeeds, but it might drop * the packet. If it drops the packet, we log that * in our stats. */ - IEEE80211_DEBUG_DROP + LIBIPW_DEBUG_DROP ("RX: netif_rx dropped the packet\n"); dev->stats.rx_dropped++; } @@ -829,18 +830,18 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, return 0; } -/* Filter out unrelated packets, call ieee80211_rx[_mgt] +/* Filter out unrelated packets, call libipw_rx[_mgt] * This function takes over the skb, it should not be used again after calling * this function. */ -void ieee80211_rx_any(struct ieee80211_device *ieee, - struct sk_buff *skb, struct ieee80211_rx_stats *stats) +void libipw_rx_any(struct libipw_device *ieee, + struct sk_buff *skb, struct libipw_rx_stats *stats) { - struct ieee80211_hdr_4addr *hdr; + struct libipw_hdr_4addr *hdr; int is_packet_for_us; u16 fc; if (ieee->iw_mode == IW_MODE_MONITOR) { - if (!ieee80211_rx(ieee, skb, stats)) + if (!libipw_rx(ieee, skb, stats)) dev_kfree_skb_irq(skb); return; } @@ -848,7 +849,7 @@ void ieee80211_rx_any(struct ieee80211_device *ieee, if (skb->len < sizeof(struct ieee80211_hdr)) goto drop_free; - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct libipw_hdr_4addr *)skb->data; fc = le16_to_cpu(hdr->frame_ctl); if ((fc & IEEE80211_FCTL_VERS) != 0) @@ -856,9 +857,9 @@ void ieee80211_rx_any(struct ieee80211_device *ieee, switch (fc & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_MGMT: - if (skb->len < sizeof(struct ieee80211_hdr_3addr)) + if (skb->len < sizeof(struct libipw_hdr_3addr)) goto drop_free; - ieee80211_rx_mgt(ieee, hdr, stats); + libipw_rx_mgt(ieee, hdr, stats); dev_kfree_skb_irq(skb); return; case IEEE80211_FTYPE_DATA: @@ -910,7 +911,7 @@ void ieee80211_rx_any(struct ieee80211_device *ieee, } if (is_packet_for_us) - if (!ieee80211_rx(ieee, skb, stats)) + if (!libipw_rx(ieee, skb, stats)) dev_kfree_skb_irq(skb); return; @@ -928,7 +929,7 @@ static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; * Make ther structure we read from the beacon packet has * the right values */ -static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element +static int libipw_verify_qos_info(struct libipw_qos_information_element *info_element, int sub_type) { @@ -947,12 +948,12 @@ static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element /* * Parse a QoS parameter element */ -static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info - *element_param, struct ieee80211_info_element +static int libipw_read_qos_param_element(struct libipw_qos_parameter_info + *element_param, struct libipw_info_element *info_element) { int ret = 0; - u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2; + u16 size = sizeof(struct libipw_qos_parameter_info) - 2; if ((info_element == NULL) || (element_param == NULL)) return -1; @@ -965,7 +966,7 @@ static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info } else ret = -1; if (ret == 0) - ret = ieee80211_verify_qos_info(&element_param->info_element, + ret = libipw_verify_qos_info(&element_param->info_element, QOS_OUI_PARAM_SUB_TYPE); return ret; } @@ -973,13 +974,13 @@ static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info /* * Parse a QoS information element */ -static int ieee80211_read_qos_info_element(struct - ieee80211_qos_information_element - *element_info, struct ieee80211_info_element +static int libipw_read_qos_info_element(struct + libipw_qos_information_element + *element_info, struct libipw_info_element *info_element) { int ret = 0; - u16 size = sizeof(struct ieee80211_qos_information_element) - 2; + u16 size = sizeof(struct libipw_qos_information_element) - 2; if (element_info == NULL) return -1; @@ -995,7 +996,7 @@ static int ieee80211_read_qos_info_element(struct ret = -1; if (ret == 0) - ret = ieee80211_verify_qos_info(element_info, + ret = libipw_verify_qos_info(element_info, QOS_OUI_INFO_SUB_TYPE); return ret; } @@ -1003,15 +1004,15 @@ static int ieee80211_read_qos_info_element(struct /* * Write QoS parameters from the ac parameters. */ -static int ieee80211_qos_convert_ac_to_parameters(struct - ieee80211_qos_parameter_info +static int libipw_qos_convert_ac_to_parameters(struct + libipw_qos_parameter_info *param_elm, struct - ieee80211_qos_parameters + libipw_qos_parameters *qos_param) { int rc = 0; int i; - struct ieee80211_qos_ac_parameter *ac_params; + struct libipw_qos_ac_parameter *ac_params; u32 txop; u8 cw_min; u8 cw_max; @@ -1042,27 +1043,27 @@ static int ieee80211_qos_convert_ac_to_parameters(struct * parameters element. check the information element length to decide * which type to read */ -static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element +static int libipw_parse_qos_info_param_IE(struct libipw_info_element *info_element, - struct ieee80211_network *network) + struct libipw_network *network) { int rc = 0; - struct ieee80211_qos_parameters *qos_param = NULL; - struct ieee80211_qos_information_element qos_info_element; + struct libipw_qos_parameters *qos_param = NULL; + struct libipw_qos_information_element qos_info_element; - rc = ieee80211_read_qos_info_element(&qos_info_element, info_element); + rc = libipw_read_qos_info_element(&qos_info_element, info_element); if (rc == 0) { network->qos_data.param_count = qos_info_element.ac_info & 0x0F; network->flags |= NETWORK_HAS_QOS_INFORMATION; } else { - struct ieee80211_qos_parameter_info param_element; + struct libipw_qos_parameter_info param_element; - rc = ieee80211_read_qos_param_element(¶m_element, + rc = libipw_read_qos_param_element(¶m_element, info_element); if (rc == 0) { qos_param = &(network->qos_data.parameters); - ieee80211_qos_convert_ac_to_parameters(¶m_element, + libipw_qos_convert_ac_to_parameters(¶m_element, qos_param); network->flags |= NETWORK_HAS_QOS_PARAMETERS; network->qos_data.param_count = @@ -1071,7 +1072,7 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element } if (rc == 0) { - IEEE80211_DEBUG_QOS("QoS is supported\n"); + LIBIPW_DEBUG_QOS("QoS is supported\n"); network->qos_data.supported = 1; } return rc; @@ -1116,9 +1117,9 @@ static const char *get_info_element_string(u16 id) } #endif -static int ieee80211_parse_info_param(struct ieee80211_info_element +static int libipw_parse_info_param(struct libipw_info_element *info_element, u16 length, - struct ieee80211_network *network) + struct libipw_network *network) { DECLARE_SSID_BUF(ssid); u8 i; @@ -1129,7 +1130,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element while (length >= sizeof(*info_element)) { if (sizeof(*info_element) + info_element->len > length) { - IEEE80211_DEBUG_MGMT("Info elem: parse failed: " + LIBIPW_DEBUG_MGMT("Info elem: parse failed: " "info_element->len + 2 > left : " "info_element->len+2=%zd left=%d, id=%d.\n", info_element->len + @@ -1151,7 +1152,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element memset(network->ssid + network->ssid_len, 0, IW_ESSID_MAX_SIZE - network->ssid_len); - IEEE80211_DEBUG_MGMT("WLAN_EID_SSID: '%s' len=%d.\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%s' len=%d.\n", print_ssid(ssid, network->ssid, network->ssid_len), network->ssid_len); @@ -1170,17 +1171,17 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element (p - rates_str), "%02X ", network->rates[i]); #endif - if (ieee80211_is_ofdm_rate + if (libipw_is_ofdm_rate (info_element->data[i])) { network->flags |= NETWORK_HAS_OFDM; if (info_element->data[i] & - IEEE80211_BASIC_RATE_MASK) + LIBIPW_BASIC_RATE_MASK) network->flags &= ~NETWORK_HAS_CCK; } } - IEEE80211_DEBUG_MGMT("WLAN_EID_SUPP_RATES: '%s' (%d)\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_SUPP_RATES: '%s' (%d)\n", rates_str, network->rates_len); break; @@ -1197,61 +1198,61 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element (p - rates_str), "%02X ", network->rates[i]); #endif - if (ieee80211_is_ofdm_rate + if (libipw_is_ofdm_rate (info_element->data[i])) { network->flags |= NETWORK_HAS_OFDM; if (info_element->data[i] & - IEEE80211_BASIC_RATE_MASK) + LIBIPW_BASIC_RATE_MASK) network->flags &= ~NETWORK_HAS_CCK; } } - IEEE80211_DEBUG_MGMT("WLAN_EID_EXT_SUPP_RATES: '%s' (%d)\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_EXT_SUPP_RATES: '%s' (%d)\n", rates_str, network->rates_ex_len); break; case WLAN_EID_DS_PARAMS: - IEEE80211_DEBUG_MGMT("WLAN_EID_DS_PARAMS: %d\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_DS_PARAMS: %d\n", info_element->data[0]); network->channel = info_element->data[0]; break; case WLAN_EID_FH_PARAMS: - IEEE80211_DEBUG_MGMT("WLAN_EID_FH_PARAMS: ignored\n"); + LIBIPW_DEBUG_MGMT("WLAN_EID_FH_PARAMS: ignored\n"); break; case WLAN_EID_CF_PARAMS: - IEEE80211_DEBUG_MGMT("WLAN_EID_CF_PARAMS: ignored\n"); + LIBIPW_DEBUG_MGMT("WLAN_EID_CF_PARAMS: ignored\n"); break; case WLAN_EID_TIM: network->tim.tim_count = info_element->data[0]; network->tim.tim_period = info_element->data[1]; - IEEE80211_DEBUG_MGMT("WLAN_EID_TIM: partially ignored\n"); + LIBIPW_DEBUG_MGMT("WLAN_EID_TIM: partially ignored\n"); break; case WLAN_EID_ERP_INFO: network->erp_value = info_element->data[0]; network->flags |= NETWORK_HAS_ERP_VALUE; - IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n", + LIBIPW_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n", network->erp_value); break; case WLAN_EID_IBSS_PARAMS: network->atim_window = info_element->data[0]; - IEEE80211_DEBUG_MGMT("WLAN_EID_IBSS_PARAMS: %d\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_IBSS_PARAMS: %d\n", network->atim_window); break; case WLAN_EID_CHALLENGE: - IEEE80211_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n"); + LIBIPW_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n"); break; case WLAN_EID_GENERIC: - IEEE80211_DEBUG_MGMT("WLAN_EID_GENERIC: %d bytes\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_GENERIC: %d bytes\n", info_element->len); - if (!ieee80211_parse_qos_info_param_IE(info_element, + if (!libipw_parse_qos_info_param_IE(info_element, network)) break; @@ -1268,7 +1269,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element break; case WLAN_EID_RSN: - IEEE80211_DEBUG_MGMT("WLAN_EID_RSN: %d bytes\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_RSN: %d bytes\n", info_element->len); network->rsn_ie_len = min(info_element->len + 2, MAX_WPA_IE_LEN); @@ -1318,7 +1319,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element break; default: - IEEE80211_DEBUG_MGMT + LIBIPW_DEBUG_MGMT ("Unsupported info element: %s (%d)\n", get_info_element_string(info_element->id), info_element->id); @@ -1327,20 +1328,20 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element length -= sizeof(*info_element) + info_element->len; info_element = - (struct ieee80211_info_element *)&info_element-> + (struct libipw_info_element *)&info_element-> data[info_element->len]; } return 0; } -static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response - *frame, struct ieee80211_rx_stats *stats) +static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_assoc_response + *frame, struct libipw_rx_stats *stats) { - struct ieee80211_network network_resp = { + struct libipw_network network_resp = { .ibss_dfs = NULL, }; - struct ieee80211_network *network = &network_resp; + struct libipw_network *network = &network_resp; struct net_device *dev = ieee->dev; network->flags = 0; @@ -1361,7 +1362,7 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0; - if (stats->freq == IEEE80211_52GHZ_BAND) { + if (stats->freq == LIBIPW_52GHZ_BAND) { /* for A band (No DS info) */ network->channel = stats->received_channel; } else @@ -1370,12 +1371,12 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee network->wpa_ie_len = 0; network->rsn_ie_len = 0; - if (ieee80211_parse_info_param + if (libipw_parse_info_param (frame->info_element, stats->len - sizeof(*frame), network)) return 1; network->mode = 0; - if (stats->freq == IEEE80211_52GHZ_BAND) + if (stats->freq == LIBIPW_52GHZ_BAND) network->mode = IEEE_A; else { if (network->flags & NETWORK_HAS_OFDM) @@ -1394,10 +1395,10 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee /***************************************************/ -static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response +static int libipw_network_init(struct libipw_device *ieee, struct libipw_probe_response *beacon, - struct ieee80211_network *network, - struct ieee80211_rx_stats *stats) + struct libipw_network *network, + struct libipw_rx_stats *stats) { DECLARE_SSID_BUF(ssid); @@ -1423,7 +1424,7 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0; - if (stats->freq == IEEE80211_52GHZ_BAND) { + if (stats->freq == LIBIPW_52GHZ_BAND) { /* for A band (No DS info) */ network->channel = stats->received_channel; } else @@ -1432,12 +1433,12 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 network->wpa_ie_len = 0; network->rsn_ie_len = 0; - if (ieee80211_parse_info_param + if (libipw_parse_info_param (beacon->info_element, stats->len - sizeof(*beacon), network)) return 1; network->mode = 0; - if (stats->freq == IEEE80211_52GHZ_BAND) + if (stats->freq == LIBIPW_52GHZ_BAND) network->mode = IEEE_A; else { if (network->flags & NETWORK_HAS_OFDM) @@ -1447,7 +1448,7 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 } if (network->mode == 0) { - IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' " + LIBIPW_DEBUG_SCAN("Filtered out '%s (%pM)' " "network.\n", print_ssid(ssid, network->ssid, network->ssid_len), @@ -1460,8 +1461,8 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 return 0; } -static inline int is_same_network(struct ieee80211_network *src, - struct ieee80211_network *dst) +static inline int is_same_network(struct libipw_network *src, + struct libipw_network *dst) { /* A network is only a duplicate if the channel, BSSID, and ESSID * all match. We treat all with the same BSSID and channel @@ -1472,13 +1473,13 @@ static inline int is_same_network(struct ieee80211_network *src, !memcmp(src->ssid, dst->ssid, src->ssid_len)); } -static void update_network(struct ieee80211_network *dst, - struct ieee80211_network *src) +static void update_network(struct libipw_network *dst, + struct libipw_network *src) { int qos_active; u8 old_param; - ieee80211_network_reset(dst); + libipw_network_reset(dst); dst->ibss_dfs = src->ibss_dfs; /* We only update the statistics if they were created by receiving @@ -1488,9 +1489,9 @@ static void update_network(struct ieee80211_network *dst, * down the signal level of an AP. */ if (dst->channel == src->stats.received_channel) memcpy(&dst->stats, &src->stats, - sizeof(struct ieee80211_rx_stats)); + sizeof(struct libipw_rx_stats)); else - IEEE80211_DEBUG_SCAN("Network %pM info received " + LIBIPW_DEBUG_SCAN("Network %pM info received " "off channel (%d vs. %d)\n", src->bssid, dst->channel, src->stats.received_channel); @@ -1521,7 +1522,7 @@ static void update_network(struct ieee80211_network *dst, old_param = dst->qos_data.old_param_count; if (dst->flags & NETWORK_HAS_QOS_MASK) memcpy(&dst->qos_data, &src->qos_data, - sizeof(struct ieee80211_qos_data)); + sizeof(struct libipw_qos_data)); else { dst->qos_data.supported = src->qos_data.supported; dst->qos_data.param_count = src->qos_data.param_count; @@ -1529,11 +1530,11 @@ static void update_network(struct ieee80211_network *dst, if (dst->qos_data.supported == 1) { if (dst->ssid_len) - IEEE80211_DEBUG_QOS + LIBIPW_DEBUG_QOS ("QoS the network %s is QoS supported\n", dst->ssid); else - IEEE80211_DEBUG_QOS + LIBIPW_DEBUG_QOS ("QoS the network is QoS supported\n"); } dst->qos_data.active = qos_active; @@ -1547,25 +1548,25 @@ static inline int is_beacon(__le16 fc) return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON); } -static void ieee80211_process_probe_response(struct ieee80211_device +static void libipw_process_probe_response(struct libipw_device *ieee, struct - ieee80211_probe_response - *beacon, struct ieee80211_rx_stats + libipw_probe_response + *beacon, struct libipw_rx_stats *stats) { struct net_device *dev = ieee->dev; - struct ieee80211_network network = { + struct libipw_network network = { .ibss_dfs = NULL, }; - struct ieee80211_network *target; - struct ieee80211_network *oldest = NULL; + struct libipw_network *target; + struct libipw_network *oldest = NULL; #ifdef CONFIG_LIBIPW_DEBUG - struct ieee80211_info_element *info_element = beacon->info_element; + struct libipw_info_element *info_element = beacon->info_element; #endif unsigned long flags; DECLARE_SSID_BUF(ssid); - IEEE80211_DEBUG_SCAN("'%s' (%pM" + LIBIPW_DEBUG_SCAN("'%s' (%pM" "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", print_ssid(ssid, info_element->data, info_element->len), beacon->header.addr3, @@ -1586,8 +1587,8 @@ static void ieee80211_process_probe_response(struct ieee80211_device (beacon->capability & cpu_to_le16(1 << 0x1)) ? '1' : '0', (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0'); - if (ieee80211_network_init(ieee, beacon, &network, stats)) { - IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n", + if (libipw_network_init(ieee, beacon, &network, stats)) { + LIBIPW_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n", print_ssid(ssid, info_element->data, info_element->len), beacon->header.addr3, @@ -1624,21 +1625,21 @@ static void ieee80211_process_probe_response(struct ieee80211_device /* If there are no more slots, expire the oldest */ list_del(&oldest->list); target = oldest; - IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from " + LIBIPW_DEBUG_SCAN("Expired '%s' (%pM) from " "network list.\n", print_ssid(ssid, target->ssid, target->ssid_len), target->bssid); - ieee80211_network_reset(target); + libipw_network_reset(target); } else { /* Otherwise just pull from the free list */ target = list_entry(ieee->network_free_list.next, - struct ieee80211_network, list); + struct libipw_network, list); list_del(ieee->network_free_list.next); } #ifdef CONFIG_LIBIPW_DEBUG - IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n", + LIBIPW_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n", print_ssid(ssid, network.ssid, network.ssid_len), network.bssid, @@ -1649,7 +1650,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device network.ibss_dfs = NULL; list_add_tail(&target->list, &ieee->network_list); } else { - IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n", + LIBIPW_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n", print_ssid(ssid, target->ssid, target->ssid_len), target->bssid, @@ -1670,121 +1671,121 @@ static void ieee80211_process_probe_response(struct ieee80211_device } } -void ieee80211_rx_mgt(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *header, - struct ieee80211_rx_stats *stats) +void libipw_rx_mgt(struct libipw_device *ieee, + struct libipw_hdr_4addr *header, + struct libipw_rx_stats *stats) { switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) { case IEEE80211_STYPE_ASSOC_RESP: - IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n", + LIBIPW_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - ieee80211_handle_assoc_resp(ieee, - (struct ieee80211_assoc_response *) + libipw_handle_assoc_resp(ieee, + (struct libipw_assoc_response *) header, stats); break; case IEEE80211_STYPE_REASSOC_RESP: - IEEE80211_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n", + LIBIPW_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); break; case IEEE80211_STYPE_PROBE_REQ: - IEEE80211_DEBUG_MGMT("received auth (%d)\n", + LIBIPW_DEBUG_MGMT("received auth (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); if (ieee->handle_probe_request != NULL) ieee->handle_probe_request(ieee->dev, (struct - ieee80211_probe_request *) + libipw_probe_request *) header, stats); break; case IEEE80211_STYPE_PROBE_RESP: - IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", + LIBIPW_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - IEEE80211_DEBUG_SCAN("Probe response\n"); - ieee80211_process_probe_response(ieee, + LIBIPW_DEBUG_SCAN("Probe response\n"); + libipw_process_probe_response(ieee, (struct - ieee80211_probe_response *) + libipw_probe_response *) header, stats); break; case IEEE80211_STYPE_BEACON: - IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", + LIBIPW_DEBUG_MGMT("received BEACON (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - IEEE80211_DEBUG_SCAN("Beacon\n"); - ieee80211_process_probe_response(ieee, + LIBIPW_DEBUG_SCAN("Beacon\n"); + libipw_process_probe_response(ieee, (struct - ieee80211_probe_response *) + libipw_probe_response *) header, stats); break; case IEEE80211_STYPE_AUTH: - IEEE80211_DEBUG_MGMT("received auth (%d)\n", + LIBIPW_DEBUG_MGMT("received auth (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); if (ieee->handle_auth != NULL) ieee->handle_auth(ieee->dev, - (struct ieee80211_auth *)header); + (struct libipw_auth *)header); break; case IEEE80211_STYPE_DISASSOC: if (ieee->handle_disassoc != NULL) ieee->handle_disassoc(ieee->dev, - (struct ieee80211_disassoc *) + (struct libipw_disassoc *) header); break; case IEEE80211_STYPE_ACTION: - IEEE80211_DEBUG_MGMT("ACTION\n"); + LIBIPW_DEBUG_MGMT("ACTION\n"); if (ieee->handle_action) ieee->handle_action(ieee->dev, - (struct ieee80211_action *) + (struct libipw_action *) header, stats); break; case IEEE80211_STYPE_REASSOC_REQ: - IEEE80211_DEBUG_MGMT("received reassoc (%d)\n", + LIBIPW_DEBUG_MGMT("received reassoc (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - IEEE80211_DEBUG_MGMT("%s: IEEE80211_REASSOC_REQ received\n", + LIBIPW_DEBUG_MGMT("%s: LIBIPW_REASSOC_REQ received\n", ieee->dev->name); if (ieee->handle_reassoc_request != NULL) ieee->handle_reassoc_request(ieee->dev, - (struct ieee80211_reassoc_request *) + (struct libipw_reassoc_request *) header); break; case IEEE80211_STYPE_ASSOC_REQ: - IEEE80211_DEBUG_MGMT("received assoc (%d)\n", + LIBIPW_DEBUG_MGMT("received assoc (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - IEEE80211_DEBUG_MGMT("%s: IEEE80211_ASSOC_REQ received\n", + LIBIPW_DEBUG_MGMT("%s: LIBIPW_ASSOC_REQ received\n", ieee->dev->name); if (ieee->handle_assoc_request != NULL) ieee->handle_assoc_request(ieee->dev); break; case IEEE80211_STYPE_DEAUTH: - IEEE80211_DEBUG_MGMT("DEAUTH\n"); + LIBIPW_DEBUG_MGMT("DEAUTH\n"); if (ieee->handle_deauth != NULL) ieee->handle_deauth(ieee->dev, - (struct ieee80211_deauth *) + (struct libipw_deauth *) header); break; default: - IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", + LIBIPW_DEBUG_MGMT("received UNKNOWN (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - IEEE80211_DEBUG_MGMT("%s: Unknown management packet: %d\n", + LIBIPW_DEBUG_MGMT("%s: Unknown management packet: %d\n", ieee->dev->name, WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); @@ -1792,6 +1793,6 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, } } -EXPORT_SYMBOL_GPL(ieee80211_rx_any); -EXPORT_SYMBOL(ieee80211_rx_mgt); -EXPORT_SYMBOL(ieee80211_rx); +EXPORT_SYMBOL_GPL(libipw_rx_any); +EXPORT_SYMBOL(libipw_rx_mgt); +EXPORT_SYMBOL(libipw_rx); diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index 2e8f84f..ce1855f 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -41,7 +41,7 @@ #include #include -#include "ieee80211.h" +#include "libipw.h" /* @@ -126,12 +126,12 @@ payload of each frame is reduced to 492 bytes. static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; -static int ieee80211_copy_snap(u8 * data, __be16 h_proto) +static int libipw_copy_snap(u8 * data, __be16 h_proto) { - struct ieee80211_snap_hdr *snap; + struct libipw_snap_hdr *snap; u8 *oui; - snap = (struct ieee80211_snap_hdr *)data; + snap = (struct libipw_snap_hdr *)data; snap->dsap = 0xaa; snap->ssap = 0xaa; snap->ctrl = 0x03; @@ -149,7 +149,7 @@ static int ieee80211_copy_snap(u8 * data, __be16 h_proto) return SNAP_SIZE + sizeof(u16); } -static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, +static int libipw_encrypt_fragment(struct libipw_device *ieee, struct sk_buff *frag, int hdr_len) { struct lib80211_crypt_data *crypt = @@ -177,7 +177,7 @@ static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, return 0; } -void ieee80211_txb_free(struct ieee80211_txb *txb) +void libipw_txb_free(struct libipw_txb *txb) { int i; if (unlikely(!txb)) @@ -188,17 +188,17 @@ void ieee80211_txb_free(struct ieee80211_txb *txb) kfree(txb); } -static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, +static struct libipw_txb *libipw_alloc_txb(int nr_frags, int txb_size, int headroom, gfp_t gfp_mask) { - struct ieee80211_txb *txb; + struct libipw_txb *txb; int i; - txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags), + txb = kmalloc(sizeof(struct libipw_txb) + (sizeof(u8 *) * nr_frags), gfp_mask); if (!txb) return NULL; - memset(txb, 0, sizeof(struct ieee80211_txb)); + memset(txb, 0, sizeof(struct libipw_txb)); txb->nr_frags = nr_frags; txb->frag_size = txb_size; @@ -220,7 +220,7 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, return txb; } -static int ieee80211_classify(struct sk_buff *skb) +static int libipw_classify(struct sk_buff *skb) { struct ethhdr *eth; struct iphdr *ip; @@ -252,11 +252,11 @@ static int ieee80211_classify(struct sk_buff *skb) /* Incoming skb is converted to a txb which consists of * a block of 802.11 fragment packets (stored as skbs) */ -int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) +int libipw_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ieee80211_device *ieee = netdev_priv(dev); - struct ieee80211_txb *txb = NULL; - struct ieee80211_hdr_3addrqos *frag_hdr; + struct libipw_device *ieee = netdev_priv(dev); + struct libipw_txb *txb = NULL; + struct libipw_hdr_3addrqos *frag_hdr; int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size, rts_required; unsigned long flags; @@ -264,7 +264,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) __be16 ether_type; int bytes, fc, hdr_len; struct sk_buff *skb_frag; - struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */ + struct libipw_hdr_3addrqos header = {/* Ensure zero initialized */ .duration_id = 0, .seq_ctl = 0, .qos_ctl = 0 @@ -331,14 +331,14 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) memcpy(header.addr2, src, ETH_ALEN); memcpy(header.addr3, ieee->bssid, ETH_ALEN); } - hdr_len = IEEE80211_3ADDR_LEN; + hdr_len = LIBIPW_3ADDR_LEN; if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) { fc |= IEEE80211_STYPE_QOS_DATA; hdr_len += 2; - skb->priority = ieee80211_classify(skb); - header.qos_ctl |= cpu_to_le16(skb->priority & IEEE80211_QCTL_TID); + skb->priority = libipw_classify(skb); + header.qos_ctl |= cpu_to_le16(skb->priority & LIBIPW_QCTL_TID); } header.frame_ctl = cpu_to_le16(fc); @@ -362,12 +362,12 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len); memcpy(skb_put(skb_new, hdr_len), &header, hdr_len); snapped = 1; - ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)), + libipw_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)), ether_type); skb_copy_from_linear_data(skb, skb_put(skb_new, skb->len), skb->len); res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv); if (res < 0) { - IEEE80211_ERROR("msdu encryption failed\n"); + LIBIPW_ERROR("msdu encryption failed\n"); dev_kfree_skb_any(skb_new); goto failed; } @@ -393,8 +393,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) * for it when determining the amount of payload space. */ bytes_per_frag = frag_size - hdr_len; if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) - bytes_per_frag -= IEEE80211_FCS_LEN; + (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS)) + bytes_per_frag -= LIBIPW_FCS_LEN; /* Each fragment may need to have room for encryptiong * pre/postfix */ @@ -417,14 +417,14 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) } rts_required = (frag_size > ieee->rts - && ieee->config & CFG_IEEE80211_RTS); + && ieee->config & CFG_LIBIPW_RTS); if (rts_required) nr_frags++; /* When we allocate the TXB we allocate enough space for the reserve * and full fragment bytes (bytes_per_frag doesn't include prefix, * postfix, header, FCS, etc.) */ - txb = ieee80211_alloc_txb(nr_frags, frag_size, + txb = libipw_alloc_txb(nr_frags, frag_size, ieee->tx_headroom, GFP_ATOMIC); if (unlikely(!txb)) { printk(KERN_WARNING "%s: Could not allocate TXB\n", @@ -441,7 +441,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (rts_required) { skb_frag = txb->fragments[0]; frag_hdr = - (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); + (struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len); /* * Set header frame_ctl to the RTS. @@ -456,7 +456,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) header.frame_ctl = cpu_to_le16(fc); if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS)) skb_put(skb_frag, 4); txb->rts_included = 1; @@ -472,7 +472,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) crypt->ops->extra_mpdu_prefix_len); frag_hdr = - (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); + (struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len); memcpy(frag_hdr, &header, hdr_len); /* If this is not the last fragment, then add the MOREFRAGS @@ -487,7 +487,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) } if (i == 0 && !snapped) { - ieee80211_copy_snap(skb_put + libipw_copy_snap(skb_put (skb_frag, SNAP_SIZE + sizeof(u16)), ether_type); bytes -= SNAP_SIZE + sizeof(u16); @@ -501,7 +501,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) /* Encryption routine will move the header forward in order * to insert the IV between the header and the payload */ if (host_encrypt) - ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); + libipw_encrypt_fragment(ieee, skb_frag, hdr_len); else if (host_build_iv) { atomic_inc(&crypt->refcnt); if (crypt->ops->build_iv) @@ -513,7 +513,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) } if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS)) skb_put(skb_frag, 4); } @@ -530,7 +530,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - ieee80211_txb_free(txb); + libipw_txb_free(txb); } return NETDEV_TX_OK; @@ -541,6 +541,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_errors++; return NETDEV_TX_BUSY; } -EXPORT_SYMBOL(ieee80211_xmit); +EXPORT_SYMBOL(libipw_xmit); -EXPORT_SYMBOL(ieee80211_txb_free); +EXPORT_SYMBOL(libipw_txb_free); diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c index 3c0812d..f79ce57 100644 --- a/drivers/net/wireless/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c @@ -37,9 +37,9 @@ #include #include -#include "ieee80211.h" +#include "libipw.h" -static const char *ieee80211_modes[] = { +static const char *libipw_modes[] = { "?", "a", "b", "ab", "g", "ag", "bg", "abg" }; @@ -54,9 +54,9 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start) } #define MAX_CUSTOM_LEN 64 -static char *ieee80211_translate_scan(struct ieee80211_device *ieee, +static char *libipw_translate_scan(struct libipw_device *ieee, char *start, char *stop, - struct ieee80211_network *network, + struct libipw_network *network, struct iw_request_info *info) { char custom[MAX_CUSTOM_LEN]; @@ -84,7 +84,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", - ieee80211_modes[network->mode]); + libipw_modes[network->mode]); start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); /* Add mode */ @@ -102,7 +102,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, /* Add channel and frequency */ /* Note : userspace automatically computes channel using iwrange */ iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel); + iwe.u.freq.m = libipw_channel_to_freq(ieee, network->channel); iwe.u.freq.e = 6; iwe.u.freq.i = 0; start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); @@ -155,7 +155,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED; - if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) { + if (!(network->stats.mask & LIBIPW_STATMASK_RSSI)) { iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; iwe.u.qual.qual = 0; @@ -180,14 +180,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, iwe.u.qual.qual = 0; } - if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) { + if (!(network->stats.mask & LIBIPW_STATMASK_NOISE)) { iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; iwe.u.qual.noise = 0; } else { iwe.u.qual.noise = network->stats.noise; } - if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) { + if (!(network->stats.mask & LIBIPW_STATMASK_SIGNAL)) { iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; iwe.u.qual.level = 0; } else { @@ -237,14 +237,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, p = custom; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: "); - if (ieee80211_get_channel_flags(ieee, network->channel) & - IEEE80211_CH_INVALID) { + if (libipw_get_channel_flags(ieee, network->channel) & + LIBIPW_CH_INVALID) { iwe.cmd = IWEVCUSTOM; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID "); } - if (ieee80211_get_channel_flags(ieee, network->channel) & - IEEE80211_CH_RADAR_DETECT) { + if (libipw_get_channel_flags(ieee, network->channel) & + LIBIPW_CH_RADAR_DETECT) { iwe.cmd = IWEVCUSTOM; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS "); } @@ -259,11 +259,11 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, #define SCAN_ITEM_SIZE 128 -int ieee80211_wx_get_scan(struct ieee80211_device *ieee, +int libipw_wx_get_scan(struct libipw_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ieee80211_network *network; + struct libipw_network *network; unsigned long flags; int err = 0; @@ -272,7 +272,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, int i = 0; DECLARE_SSID_BUF(ssid); - IEEE80211_DEBUG_WX("Getting scan\n"); + LIBIPW_DEBUG_WX("Getting scan\n"); spin_lock_irqsave(&ieee->lock, flags); @@ -285,10 +285,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, if (ieee->scan_age == 0 || time_after(network->last_scanned + ieee->scan_age, jiffies)) - ev = ieee80211_translate_scan(ieee, ev, stop, network, + ev = libipw_translate_scan(ieee, ev, stop, network, info); else { - IEEE80211_DEBUG_SCAN("Not showing network '%s (" + LIBIPW_DEBUG_SCAN("Not showing network '%s (" "%pM)' due to age (%ums).\n", print_ssid(ssid, network->ssid, network->ssid_len), @@ -303,18 +303,18 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, wrqu->data.length = ev - extra; wrqu->data.flags = 0; - IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); + LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i); return err; } -int ieee80211_wx_set_encode(struct ieee80211_device *ieee, +int libipw_wx_set_encode(struct libipw_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *keybuf) { struct iw_point *erq = &(wrqu->encoding); struct net_device *dev = ieee->dev; - struct ieee80211_security sec = { + struct libipw_security sec = { .flags = 0 }; int i, key, key_provided, len; @@ -322,7 +322,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv; DECLARE_SSID_BUF(ssid); - IEEE80211_DEBUG_WX("SET_ENCODE\n"); + LIBIPW_DEBUG_WX("SET_ENCODE\n"); key = erq->flags & IW_ENCODE_INDEX; if (key) { @@ -335,18 +335,18 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, key = ieee->crypt_info.tx_keyidx; } - IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? + LIBIPW_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? "provided" : "default"); crypt = &ieee->crypt_info.crypt[key]; if (erq->flags & IW_ENCODE_DISABLED) { if (key_provided && *crypt) { - IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", + LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n", key); lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); } else - IEEE80211_DEBUG_WX("Disabling encryption.\n"); + LIBIPW_DEBUG_WX("Disabling encryption.\n"); /* Check all the keys to see if any are still configured, * and if no key index was provided, de-init them all */ @@ -410,7 +410,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, /* If a new key was provided, set it up */ if (erq->length > 0) { -#ifdef CONFIG_IEEE80211_DEBUG +#ifdef CONFIG_LIBIPW_DEBUG DECLARE_SSID_BUF(ssid); #endif @@ -419,7 +419,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, if (len > erq->length) memset(sec.keys[key] + erq->length, 0, len - erq->length); - IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", + LIBIPW_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", key, print_ssid(ssid, sec.keys[key], len), erq->length, len); sec.key_sizes[key] = len; @@ -438,7 +438,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, NULL, (*crypt)->priv); if (len == 0) { /* Set a default key of all 0 */ - IEEE80211_DEBUG_WX("Setting key %d to all " + LIBIPW_DEBUG_WX("Setting key %d to all " "zero.\n", key); memset(sec.keys[key], 0, 13); (*crypt)->ops->set_key(sec.keys[key], 13, NULL, @@ -449,7 +449,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, } /* No key data - just set the default TX key index */ if (key_provided) { - IEEE80211_DEBUG_WX("Setting key %d to default Tx " + LIBIPW_DEBUG_WX("Setting key %d to default Tx " "key.\n", key); ieee->crypt_info.tx_keyidx = key; sec.active_key = key; @@ -461,7 +461,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; sec.flags |= SEC_AUTH_MODE; - IEEE80211_DEBUG_WX("Auth: %s\n", + LIBIPW_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? "OPEN" : "SHARED KEY"); } @@ -490,16 +490,16 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, return 0; } -int ieee80211_wx_get_encode(struct ieee80211_device *ieee, +int libipw_wx_get_encode(struct libipw_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *keybuf) { struct iw_point *erq = &(wrqu->encoding); int len, key; struct lib80211_crypt_data *crypt; - struct ieee80211_security *sec = &ieee->sec; + struct libipw_security *sec = &ieee->sec; - IEEE80211_DEBUG_WX("GET_ENCODE\n"); + LIBIPW_DEBUG_WX("GET_ENCODE\n"); key = erq->flags & IW_ENCODE_INDEX; if (key) { @@ -532,7 +532,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, return 0; } -int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, +int libipw_wx_set_encodeext(struct libipw_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -545,7 +545,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, struct lib80211_crypto_ops *ops; struct lib80211_crypt_data **crypt; - struct ieee80211_security sec = { + struct libipw_security sec = { .flags = 0, }; @@ -611,7 +611,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, module = "lib80211_crypt_ccmp"; break; default: - IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n", dev->name, ext->alg); ret = -EINVAL; goto done; @@ -623,7 +623,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, ops = lib80211_get_crypto_ops(alg); } if (ops == NULL) { - IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n", dev->name, ext->alg); ret = -EINVAL; goto done; @@ -653,7 +653,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, if (ext->key_len > 0 && (*crypt)->ops->set_key && (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, (*crypt)->priv) < 0) { - IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); + LIBIPW_DEBUG_WX("%s: key setting failed\n", dev->name); ret = -EINVAL; goto done; } @@ -700,20 +700,20 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, if (ieee->reset_on_keychange && ieee->iw_mode != IW_MODE_INFRA && ieee->reset_port && ieee->reset_port(dev)) { - IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); + LIBIPW_DEBUG_WX("%s: reset_port failed\n", dev->name); return -EINVAL; } return ret; } -int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, +int libipw_wx_get_encodeext(struct libipw_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - struct ieee80211_security *sec = &ieee->sec; + struct libipw_security *sec = &ieee->sec; int idx, max_key_len; max_key_len = encoding->length - sizeof(*ext); @@ -763,9 +763,9 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, return 0; } -EXPORT_SYMBOL(ieee80211_wx_set_encodeext); -EXPORT_SYMBOL(ieee80211_wx_get_encodeext); +EXPORT_SYMBOL(libipw_wx_set_encodeext); +EXPORT_SYMBOL(libipw_wx_get_encodeext); -EXPORT_SYMBOL(ieee80211_wx_get_scan); -EXPORT_SYMBOL(ieee80211_wx_set_encode); -EXPORT_SYMBOL(ieee80211_wx_get_encode); +EXPORT_SYMBOL(libipw_wx_get_scan); +EXPORT_SYMBOL(libipw_wx_set_encode); +EXPORT_SYMBOL(libipw_wx_get_encode); diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h index 2b3fbbb..e9054a2 100644 --- a/include/net/iw_handler.h +++ b/include/net/iw_handler.h @@ -416,13 +416,13 @@ struct iw_spy_data * data (i.e. valid as long as struct net_device exist, same locking rules). */ /* Forward declaration */ -struct ieee80211_device; +struct libipw_device; /* The struct */ struct iw_public_data { /* Driver enhanced spy support */ struct iw_spy_data * spy_data; - /* Structure managed by the in-kernel IEEE 802.11 layer */ - struct ieee80211_device * ieee80211; + /* Legacy structure managed by the ipw2x00-specific IEEE 802.11 layer */ + struct libipw_device * libipw; }; /**************************** PROTOTYPES ****************************/ -- cgit v0.10.2 From 103bf9f7d35849bce52ad412e4da5063b0716969 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 20 Aug 2009 16:34:15 -0400 Subject: mac80211: remove ieee80211_rx namespace hack With the libipw naming scheme change, it is no longer necessary for mac80211 to avoid the ieee80211_rx name clash. Reported-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index aac84d7..466859b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1657,12 +1657,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw); */ void ieee80211_restart_hw(struct ieee80211_hw *hw); -/* - * trick to avoid symbol clashes with the ieee80211 subsystem, - * use the inline below instead - */ -void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb); - /** * ieee80211_rx - receive frame * @@ -1678,10 +1672,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb); * @hw: the hardware this frame came in on * @skb: the buffer to receive, owned by mac80211 after this call */ -static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - __ieee80211_rx(hw, skb); -} +void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb); /** * ieee80211_rx_irqsafe - receive frame diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7065fd7..dff2239 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2440,7 +2440,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, * This is the receive path handler. It is called by a low level driver when an * 802.11 MPDU is received from the hardware. */ -void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) +void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate = NULL; @@ -2523,7 +2523,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) rcu_read_unlock(); } -EXPORT_SYMBOL(__ieee80211_rx); +EXPORT_SYMBOL(ieee80211_rx); /* This is a version of the rx handler that can be called from hard irq * context. Post the skb on the queue and schedule the tasklet */ -- cgit v0.10.2 From 3d832611d794b3d312d26a4b251ac5285206f90d Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 21 Aug 2009 12:00:28 +0530 Subject: ath9k: Fix chainmask selection during scanning The TX/RX chainmasks were set to 1x1 during scanning. Configure them properly with the values retrieved from the EEPROM. Also, this requires scan_start/scan_end callbacks to be locked with sc->mutex. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9b9b4e8..eb8d673 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -439,7 +439,7 @@ static void ath_start_ani(struct ath_softc *sc) */ void ath_update_chainmask(struct ath_softc *sc, int is_ht) { - if (is_ht || + if ((sc->sc_flags & SC_OP_SCANNING) || is_ht || (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) { sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask; @@ -2713,6 +2713,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + mutex_lock(&sc->mutex); if (ath9k_wiphy_scanning(sc)) { printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the " "same time\n"); @@ -2720,6 +2721,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) * Do not allow the concurrent scanning state for now. This * could be improved with scanning control moved into ath9k. */ + mutex_unlock(&sc->mutex); return; } @@ -2729,6 +2731,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) spin_lock_bh(&sc->ani_lock); sc->sc_flags |= SC_OP_SCANNING; spin_unlock_bh(&sc->ani_lock); + mutex_unlock(&sc->mutex); } static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) @@ -2736,11 +2739,13 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + mutex_lock(&sc->mutex); spin_lock_bh(&sc->ani_lock); aphy->state = ATH_WIPHY_ACTIVE; sc->sc_flags &= ~SC_OP_SCANNING; sc->sc_flags |= SC_OP_FULL_RESET; spin_unlock_bh(&sc->ani_lock); + mutex_unlock(&sc->mutex); } struct ieee80211_ops ath9k_ops = { -- cgit v0.10.2 From f7969969f416e593bcc7dc24abf3f9fd6c27136d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 21 Aug 2009 12:23:49 +0200 Subject: cfg80211: make spurious warnings less likely, configurable Bob reported that he got warnings in IBSS mode about the ssid_len being zero on a joined event, but only when kmemcheck was enabled. This appears to be due to a race condition between drivers and userspace, when the driver reports joined but the user in the meantime decided to leave the IBSS again, the warning would trigger. This was made more likely by kmemcheck delaying the code that does the check and sends the event. So first, make the warning trigger closer to the driver, which means it's not locked, but since only the warning depends on it that's ok. And secondly, users will not want to have spurious warnings at all, so make those that are known to be racy in such a way configurable. Reported-by: Bob Copeland Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index c6031d5..aea7e68 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -17,6 +17,23 @@ config NL80211_TESTMODE Say N. +config CFG80211_DEVELOPER_WARNINGS + bool "enable developer warnings" + depends on CFG80211 + default n + help + This option enables some additional warnings that help + cfg80211 developers and driver developers, but that can + trigger due to races with userspace. + + For example, when a driver reports that it was disconnected + from the AP, but the user disconnects manually at the same + time, the warning might trigger spuriously due to races. + + Say Y only if you are developing cfg80211 or a driver based + on it (or mac80211). + + config CFG80211_REG_DEBUG bool "cfg80211 regulatory debugging" depends on CFG80211 diff --git a/net/wireless/core.h b/net/wireless/core.h index 68eaf34..d262d42 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -380,4 +380,15 @@ int rdev_set_freq(struct cfg80211_registered_device *rdev, struct wireless_dev *for_wdev, int freq, enum nl80211_channel_type channel_type); +#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS +#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) +#else +/* + * Trick to enable using it as a condition, + * and also not give a warning when it's + * not used that way. + */ +#define CFG80211_DEV_WARN_ON(cond) ({bool __r = (cond); __r; }) +#endif + #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 42840a0..c883389 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -22,7 +22,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) return; - if (WARN_ON(!wdev->ssid_len)) + if (!wdev->ssid_len) return; bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, @@ -58,6 +58,8 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) struct cfg80211_event *ev; unsigned long flags; + CFG80211_DEV_WARN_ON(!wdev->ssid_len); + ev = kzalloc(sizeof(*ev), gfp); if (!ev) return; diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 4a8289f9..6830788 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -351,7 +351,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; - if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING)) + if (wdev->sme_state != CFG80211_SME_CONNECTING) return; nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, @@ -445,6 +445,8 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, struct cfg80211_event *ev; unsigned long flags; + CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING); + ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); if (!ev) return; @@ -481,7 +483,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; - if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED)) + if (wdev->sme_state != CFG80211_SME_CONNECTED) return; /* internal error -- how did we get to CONNECTED w/o BSS? */ @@ -540,6 +542,8 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, struct cfg80211_event *ev; unsigned long flags; + CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED); + ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); if (!ev) return; @@ -575,7 +579,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; - if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED)) + if (wdev->sme_state != CFG80211_SME_CONNECTED) return; if (wdev->current_bss) { @@ -639,6 +643,8 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, struct cfg80211_event *ev; unsigned long flags; + CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED); + ev = kzalloc(sizeof(*ev) + ie_len, gfp); if (!ev) return; -- cgit v0.10.2 From 3d54d25515838543e56889aa7e48f40d00719368 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 21 Aug 2009 14:51:05 +0200 Subject: cfg80211: clean up properly on interface type change When the interface type changes while connected, and the driver does not require the interface to be down for a type change, it is currently possible to get very strange results unless the driver takes special care, which it shouldn't have to. To fix this, take care to disconnect/leave IBSS when changing the interface type -- even if the driver may fail the call. Also process all events that may be pending to avoid running into a situation where an event is reported but only processed after the type has already changed, which would lead to missing events and warnings. A side effect of this is that you will have disconnected or left the IBSS even if the mode change ultimately fails, but since the intention was to change it and thus leave or disconnect, this is not a problem. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/core.c b/net/wireless/core.c index 9b157ca..45b2be3 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -294,69 +294,17 @@ static void cfg80211_rfkill_sync_work(struct work_struct *work) cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill)); } -static void cfg80211_process_events(struct wireless_dev *wdev) -{ - struct cfg80211_event *ev; - unsigned long flags; - - spin_lock_irqsave(&wdev->event_lock, flags); - while (!list_empty(&wdev->event_list)) { - ev = list_first_entry(&wdev->event_list, - struct cfg80211_event, list); - list_del(&ev->list); - spin_unlock_irqrestore(&wdev->event_lock, flags); - - wdev_lock(wdev); - switch (ev->type) { - case EVENT_CONNECT_RESULT: - __cfg80211_connect_result( - wdev->netdev, is_zero_ether_addr(ev->cr.bssid) ? - NULL : ev->cr.bssid, - ev->cr.req_ie, ev->cr.req_ie_len, - ev->cr.resp_ie, ev->cr.resp_ie_len, - ev->cr.status, - ev->cr.status == WLAN_STATUS_SUCCESS, - NULL); - break; - case EVENT_ROAMED: - __cfg80211_roamed(wdev, ev->rm.bssid, - ev->rm.req_ie, ev->rm.req_ie_len, - ev->rm.resp_ie, ev->rm.resp_ie_len); - break; - case EVENT_DISCONNECTED: - __cfg80211_disconnected(wdev->netdev, - ev->dc.ie, ev->dc.ie_len, - ev->dc.reason, true); - break; - case EVENT_IBSS_JOINED: - __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); - break; - } - wdev_unlock(wdev); - - kfree(ev); - - spin_lock_irqsave(&wdev->event_lock, flags); - } - spin_unlock_irqrestore(&wdev->event_lock, flags); -} - static void cfg80211_event_work(struct work_struct *work) { struct cfg80211_registered_device *rdev; - struct wireless_dev *wdev; rdev = container_of(work, struct cfg80211_registered_device, event_work); rtnl_lock(); cfg80211_lock_rdev(rdev); - mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) - cfg80211_process_events(wdev); - - mutex_unlock(&rdev->devlist_mtx); + cfg80211_process_rdev_events(rdev); cfg80211_unlock_rdev(rdev); rtnl_unlock(); } diff --git a/net/wireless/core.h b/net/wireless/core.h index d262d42..2a33d8b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -372,6 +372,10 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx); void __cfg80211_scan_done(struct work_struct *wk); void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); void cfg80211_upload_connect_keys(struct wireless_dev *wdev); +int cfg80211_change_iface(struct cfg80211_registered_device *rdev, + struct net_device *dev, enum nl80211_iftype ntype, + u32 *flags, struct vif_params *params); +void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); struct ieee80211_channel * rdev_fixed_channel(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a8aaade..71bfc04 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -977,12 +977,6 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } } - if (!rdev->ops->change_virtual_intf || - !(rdev->wiphy.interface_modes & (1 << ntype))) { - err = -EOPNOTSUPP; - goto unlock; - } - if (info->attrs[NL80211_ATTR_MESH_ID]) { if (ntype != NL80211_IFTYPE_MESH_POINT) { err = -EINVAL; @@ -1008,18 +1002,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } if (change) - err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, - ntype, flags, ¶ms); + err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms); else err = 0; - WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); - - if (!err && (ntype != otype)) { - if (otype == NL80211_IFTYPE_ADHOC) - cfg80211_clear_ibss(dev, false); - } - unlock: dev_put(dev); cfg80211_unlock_rdev(rdev); diff --git a/net/wireless/util.c b/net/wireless/util.c index 693275a..3fc2df8 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -574,3 +574,111 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) kfree(wdev->connect_keys); wdev->connect_keys = NULL; } + +static void cfg80211_process_wdev_events(struct wireless_dev *wdev) +{ + struct cfg80211_event *ev; + unsigned long flags; + const u8 *bssid = NULL; + + spin_lock_irqsave(&wdev->event_lock, flags); + while (!list_empty(&wdev->event_list)) { + ev = list_first_entry(&wdev->event_list, + struct cfg80211_event, list); + list_del(&ev->list); + spin_unlock_irqrestore(&wdev->event_lock, flags); + + wdev_lock(wdev); + switch (ev->type) { + case EVENT_CONNECT_RESULT: + if (!is_zero_ether_addr(ev->cr.bssid)) + bssid = ev->cr.bssid; + __cfg80211_connect_result( + wdev->netdev, bssid, + ev->cr.req_ie, ev->cr.req_ie_len, + ev->cr.resp_ie, ev->cr.resp_ie_len, + ev->cr.status, + ev->cr.status == WLAN_STATUS_SUCCESS, + NULL); + break; + case EVENT_ROAMED: + __cfg80211_roamed(wdev, ev->rm.bssid, + ev->rm.req_ie, ev->rm.req_ie_len, + ev->rm.resp_ie, ev->rm.resp_ie_len); + break; + case EVENT_DISCONNECTED: + __cfg80211_disconnected(wdev->netdev, + ev->dc.ie, ev->dc.ie_len, + ev->dc.reason, true); + break; + case EVENT_IBSS_JOINED: + __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); + break; + } + wdev_unlock(wdev); + + kfree(ev); + + spin_lock_irqsave(&wdev->event_lock, flags); + } + spin_unlock_irqrestore(&wdev->event_lock, flags); +} + +void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) +{ + struct wireless_dev *wdev; + + ASSERT_RTNL(); + ASSERT_RDEV_LOCK(rdev); + + mutex_lock(&rdev->devlist_mtx); + + list_for_each_entry(wdev, &rdev->netdev_list, list) + cfg80211_process_wdev_events(wdev); + + mutex_unlock(&rdev->devlist_mtx); +} + +int cfg80211_change_iface(struct cfg80211_registered_device *rdev, + struct net_device *dev, enum nl80211_iftype ntype, + u32 *flags, struct vif_params *params) +{ + int err; + enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; + + ASSERT_RDEV_LOCK(rdev); + + /* don't support changing VLANs, you just re-create them */ + if (otype == NL80211_IFTYPE_AP_VLAN) + return -EOPNOTSUPP; + + if (!rdev->ops->change_virtual_intf || + !(rdev->wiphy.interface_modes & (1 << ntype))) + return -EOPNOTSUPP; + + if (ntype != otype) { + switch (otype) { + case NL80211_IFTYPE_ADHOC: + cfg80211_leave_ibss(rdev, dev, false); + break; + case NL80211_IFTYPE_STATION: + cfg80211_disconnect(rdev, dev, + WLAN_REASON_DEAUTH_LEAVING, true); + break; + case NL80211_IFTYPE_MESH_POINT: + /* mesh should be handled? */ + break; + default: + break; + } + + cfg80211_process_rdev_events(rdev); + } + + err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, + ntype, flags, params); + + WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); + + return err; +} diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index c12029b..429dd06 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -70,18 +70,8 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, enum nl80211_iftype type; int ret; - if (!wdev) - return -EOPNOTSUPP; - rdev = wiphy_to_dev(wdev->wiphy); - if (!rdev->ops->change_virtual_intf) - return -EOPNOTSUPP; - - /* don't support changing VLANs, you just re-create them */ - if (wdev->iftype == NL80211_IFTYPE_AP_VLAN) - return -EOPNOTSUPP; - switch (*mode) { case IW_MODE_INFRA: type = NL80211_IFTYPE_STATION; @@ -104,9 +94,9 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, memset(&vifparams, 0, sizeof(vifparams)); - ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev, type, - NULL, &vifparams); - WARN_ON(!ret && wdev->iftype != type); + cfg80211_lock_rdev(rdev); + ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); + cfg80211_unlock_rdev(rdev); return ret; } -- cgit v0.10.2 From ea77f12f2cc0f31168f2e0259e65a22202ac4dc2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 21 Aug 2009 14:44:45 +0200 Subject: mac80211: remove tasklet enable/disable Due to the way the tasklets work in mac80211 there's no need to ever disable them. However, we need to clear the pending packets when taking down the last interface because otherwise the tx_pending_tasklet might be queued if the driver mucks with the queues (which it shouldn't). I've had a situation occasionally with ar9170 in which ksoftirq was using 100% CPU time because a disabled tasklet was scheduled, and I think that was due to ar9170 receiving a packet while the tasklet was disabled. That's strange and it really should not do that for other reasons, but there's no need to waste that much CPU time over it, it should just warn instead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index d231c93..020a94a 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -12,7 +12,11 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb) static inline int drv_start(struct ieee80211_local *local) { - int ret = local->ops->start(&local->hw); + int ret; + + local->started = true; + smp_mb(); + ret = local->ops->start(&local->hw); trace_drv_start(local, ret); return ret; } @@ -21,6 +25,14 @@ static inline void drv_stop(struct ieee80211_local *local) { local->ops->stop(&local->hw); trace_drv_stop(local); + + /* sync away all work on the tasklet before clearing started */ + tasklet_disable(&local->tasklet); + tasklet_enable(&local->tasklet); + + barrier(); + + local->started = false; } static inline int drv_add_interface(struct ieee80211_local *local, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index fa930e0..dbd8411 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -667,6 +667,9 @@ struct ieee80211_local { */ bool quiescing; + /* device is started */ + bool started; + int tx_headroom; /* required headroom for hardware/radiotap */ /* Tasklet and skb queue to process calls from IRQ mode. All frames diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 5940e69..d134bd7 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -277,11 +277,6 @@ static int ieee80211_open(struct net_device *dev) } } - if (local->open_count == 0) { - tasklet_enable(&local->tx_pending_tasklet); - tasklet_enable(&local->tasklet); - } - /* * set_multicast_list will be invoked by the networking core * which will check whether any increments here were done in @@ -552,11 +547,9 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_recalc_ps(local, -1); if (local->open_count == 0) { + ieee80211_clear_tx_pending(local); ieee80211_stop_device(local); - tasklet_disable(&local->tx_pending_tasklet); - tasklet_disable(&local->tasklet); - /* no reconfiguring after stop! */ hw_reconf_flags = 0; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index dd3b081..797f539 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -715,12 +715,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, skb_queue_head_init(&local->pending[i]); tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); - tasklet_disable(&local->tx_pending_tasklet); tasklet_init(&local->tasklet, ieee80211_tasklet_handler, (unsigned long) local); - tasklet_disable(&local->tasklet); skb_queue_head_init(&local->skb_queue); skb_queue_head_init(&local->skb_queue_unreliable); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index dff2239..b98f1af 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2471,6 +2471,15 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) return; } + /* + * The same happens when we're not even started, + * but that's worth a warning. + */ + if (WARN_ON(!local->started)) { + kfree_skb(skb); + return; + } + if (status->flag & RX_FLAG_HT) { /* rate_idx is MCS index */ if (WARN_ON(status->rate_idx < 0 || -- cgit v0.10.2 From 1c4e9ab3f1cc458306b3b910000371ba4f71c4d2 Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Fri, 21 Aug 2009 16:11:30 +0200 Subject: mac80211: Remove unnused throughput field from minstrel_rate. I noticed that the throughput field of the minstrel_rate struct is never used, so remove it. Signed-off-by: Arnd Hannemann Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 869fe0e..38bf4168 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h @@ -33,7 +33,6 @@ struct minstrel_rate { /* per-rate throughput */ u32 cur_tp; - u32 throughput; u64 succ_hist; u64 att_hist; -- cgit v0.10.2 From 1e3d31c589a6bcb05cd7fccccf9657c27b0e3dd1 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sun, 2 Aug 2009 09:44:12 +0200 Subject: libertas: Read buffer overflow Check whether index is within bounds before testing the element. (also includes "Libertas: Association request to the driver failed" The size of the tmp buffer was too small, causing a regression rates->rates has an arraysize of 1, so a memcpy with MAX_RATES (14) was already causing reads out of bounds. In get_common_rates() the memset/memcpy can be moved upwards. -- JWL) Signed-off-by: Roel Kluin Tested-by: Daniel Mack Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 81f86ef..a9440a9 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -44,12 +44,11 @@ static int get_common_rates(struct lbs_private *priv, { u8 *card_rates = lbs_bg_rates; size_t num_card_rates = sizeof(lbs_bg_rates); - int ret = 0, i, j; + int i, j; u8 *tmp; size_t tmp_size = 0; - tmp = kzalloc((ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1), - GFP_KERNEL); + tmp = kzalloc(MAX_RATES * ARRAY_SIZE(lbs_bg_rates), GFP_KERNEL); if (!tmp) return -1; @@ -66,24 +65,24 @@ static int get_common_rates(struct lbs_private *priv, lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); + memset(rates, 0, *rates_size); + *rates_size = min_t(u16, tmp_size, *rates_size); + memcpy(rates, tmp, *rates_size); + if (!priv->enablehwauto) { for (i = 0; i < tmp_size; i++) { if (tmp[i] == priv->cur_rate) - goto done; + break; + } + if (i == tmp_size) { + lbs_pr_alert("Previously set fixed data rate %#x isn't " + "compatible with the network.\n", + priv->cur_rate); + return -1; } - lbs_pr_alert("Previously set fixed data rate %#x isn't " - "compatible with the network.\n", priv->cur_rate); - ret = -1; - goto done; } - ret = 0; - -done: - memset(rates, 0, *rates_size); - *rates_size = min_t(int, tmp_size, *rates_size); - memcpy(rates, tmp, *rates_size); kfree(tmp); - return ret; + return 0; } @@ -325,8 +324,8 @@ static int lbs_associate(struct lbs_private *priv, rates = (struct mrvl_ie_rates_param_set *) pos; rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - memcpy(&rates->rates, &bss->rates, MAX_RATES); tmplen = MAX_RATES; + memcpy(&rates->rates, &bss->rates, tmplen); if (get_common_rates(priv, rates->rates, &tmplen)) { ret = -1; goto done; -- cgit v0.10.2 From ca4fe30097d700c595c13362200083650759e104 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 21 Aug 2009 09:35:20 -0500 Subject: libertas: clean up and clarify get_common_rates Clarify what the heck the function is doing with better variable names and less indirection and better comments. Also ensure callers use the proper minimum size, even though all rates arrays should be size MAX_RATES anyway. Reverts part of Andrey's dynamic alloc patch since we don't really need it. Also leaves the passed-in rates array alone on errors. Signed-off-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index a9440a9..dd87326 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -34,7 +34,8 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = * * @param priv A pointer to struct lbs_private structure * @param rates the buffer which keeps input and output - * @param rates_size the size of rate1 buffer; new size of buffer on return + * @param rates_size the size of rates buffer; new size of buffer on return, + * which will be less than or equal to original rates_size * * @return 0 on success, or -1 on error */ @@ -42,46 +43,41 @@ static int get_common_rates(struct lbs_private *priv, u8 *rates, u16 *rates_size) { - u8 *card_rates = lbs_bg_rates; - size_t num_card_rates = sizeof(lbs_bg_rates); int i, j; - u8 *tmp; - size_t tmp_size = 0; + u8 intersection[MAX_RATES]; + u16 intersection_size; + u16 num_rates = 0; - tmp = kzalloc(MAX_RATES * ARRAY_SIZE(lbs_bg_rates), GFP_KERNEL); - if (!tmp) - return -1; + intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection)); - /* For each rate in card_rates that exists in rate1, copy to tmp */ - for (i = 0; card_rates[i] && (i < num_card_rates); i++) { - for (j = 0; rates[j] && (j < *rates_size); j++) { - if (rates[j] == card_rates[i]) - tmp[tmp_size++] = card_rates[i]; + /* Allow each rate from 'rates' that is supported by the hardware */ + for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) { + for (j = 0; j < intersection_size && rates[j]; j++) { + if (rates[j] == lbs_bg_rates[i]) + intersection[num_rates++] = rates[j]; } } lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); - lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); - lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); + lbs_deb_hex(LBS_DEB_JOIN, "card rates ", lbs_bg_rates, + ARRAY_SIZE(lbs_bg_rates)); + lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates); lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); - memset(rates, 0, *rates_size); - *rates_size = min_t(u16, tmp_size, *rates_size); - memcpy(rates, tmp, *rates_size); - if (!priv->enablehwauto) { - for (i = 0; i < tmp_size; i++) { - if (tmp[i] == priv->cur_rate) - break; - } - if (i == tmp_size) { - lbs_pr_alert("Previously set fixed data rate %#x isn't " - "compatible with the network.\n", - priv->cur_rate); - return -1; + for (i = 0; i < num_rates; i++) { + if (intersection[i] == priv->cur_rate) + goto done; } + lbs_pr_alert("Previously set fixed data rate %#x isn't " + "compatible with the network.\n", priv->cur_rate); + return -1; } - kfree(tmp); + +done: + memset(rates, 0, *rates_size); + *rates_size = num_rates; + memcpy(rates, intersection, num_rates); return 0; } @@ -324,7 +320,7 @@ static int lbs_associate(struct lbs_private *priv, rates = (struct mrvl_ie_rates_param_set *) pos; rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - tmplen = MAX_RATES; + tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES); memcpy(&rates->rates, &bss->rates, tmplen); if (get_common_rates(priv, rates->rates, &tmplen)) { ret = -1; @@ -599,7 +595,7 @@ static int lbs_adhoc_join(struct lbs_private *priv, /* Copy Data rates from the rates recorded in scan response */ memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates)); - ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES); + ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates)); memcpy(cmd.bss.rates, bss->rates, ratesize); if (get_common_rates(priv, cmd.bss.rates, &ratesize)) { lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n"); -- cgit v0.10.2 From 9d45368a3825349d8ba686bc36df589d16577dd4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 21 Aug 2009 04:08:16 +0200 Subject: libertas: Add support for Marvell Libertas CF8305 The CF8305 is a very old silicon running firmware version 3.0 . This card also needs some special treatment as it's so old it can't do unaligned register access. But since that happens only at one place, there were no changes made to the register access functions, but instead that particular place was fixed. Also, this card uses only one-stage firmware which is loaded the same way as helper firmware. The second-stage firmware isn't loaded on this card and doesn't therefore have to be supplied. Signed-off-by: Marek Vasut Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index f658fd6..6238176 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -59,6 +59,7 @@ struct if_cs_card { struct pcmcia_device *p_dev; struct lbs_private *priv; void __iomem *iobase; + bool align_regs; }; @@ -274,16 +275,25 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r #define IF_CS_PRODUCT_ID 0x0000001C #define IF_CS_CF8385_B1_REV 0x12 #define IF_CS_CF8381_B3_REV 0x04 +#define IF_CS_CF8305_B1_REV 0x03 /* * Used to detect other cards than CF8385 since their revisions of silicon * doesn't match those from CF8385, eg. CF8381 B3 works with this driver. */ +#define CF8305_MANFID 0x02db +#define CF8305_CARDID 0x8103 #define CF8381_MANFID 0x02db #define CF8381_CARDID 0x6064 #define CF8385_MANFID 0x02df #define CF8385_CARDID 0x8103 +static inline int if_cs_hw_is_cf8305(struct pcmcia_device *p_dev) +{ + return (p_dev->manf_id == CF8305_MANFID && + p_dev->card_id == CF8305_CARDID); +} + static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev) { return (p_dev->manf_id == CF8381_MANFID && @@ -556,7 +566,15 @@ static int if_cs_prog_helper(struct if_cs_card *card) lbs_deb_enter(LBS_DEB_CS); - scratch = if_cs_read8(card, IF_CS_SCRATCH); + /* + * This is the only place where an unaligned register access happens on + * the CF8305 card, therefore for the sake of speed of the driver, we do + * the alignment correction here. + */ + if (card->align_regs) + scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8; + else + scratch = if_cs_read8(card, IF_CS_SCRATCH); /* "If the value is 0x5a, the firmware is already * downloaded successfully" @@ -880,8 +898,24 @@ static int if_cs_probe(struct pcmcia_device *p_dev) p_dev->irq.AssignedIRQ, p_dev->io.BasePort1, p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1); + /* + * Most of the libertas cards can do unaligned register access, but some + * weird ones can not. That's especially true for the CF8305 card. + */ + card->align_regs = 0; + /* Check if we have a current silicon */ prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); + if (if_cs_hw_is_cf8305(p_dev)) { + card->align_regs = 1; + if (prod_id < IF_CS_CF8305_B1_REV) { + lbs_pr_err("old chips like 8305 rev B3 " + "aren't supported\n"); + ret = -ENODEV; + goto out2; + } + } + if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) { lbs_pr_err("old chips like 8381 rev B3 aren't supported\n"); ret = -ENODEV; @@ -896,7 +930,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) /* Load the firmware early, before calling into libertas.ko */ ret = if_cs_prog_helper(card); - if (ret == 0) + if (ret == 0 && !if_cs_hw_is_cf8305(p_dev)) ret = if_cs_prog_real(card); if (ret) goto out2; @@ -976,6 +1010,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev) /********************************************************************/ static struct pcmcia_device_id if_cs_ids[] = { + PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID), PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), PCMCIA_DEVICE_NULL, -- cgit v0.10.2 From aa065263ecb0b0df096ff4b02b2fb88060dd2d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 21 Aug 2009 20:44:09 +0200 Subject: iwlwifi: Make injection of non-broadcast frames work again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 1ccb84d87d04df3c76cd4352fe69786d8c7cf016 by Wey-Yi Guy ("iwlwifi: clean up unused NL80211_IFTYPE_MONITOR for Monitor mode") broke injection of non-broadcast frames to unassociated stations (causing a SYSASSERT for all such injected frames), due to injected frames no longer automatically getting a broadcast station ID assigned. This patch restores the old behavior, fixing the aforementioned regression. Also, consistently check for IEEE80211_TX_CTL_INJECTED instead of iwl_is_monitor_mode in the TX path, as TX_CTL_INJECTED specifically means that a given packet is coming from a monitor interface, while iwl_is_monitor_mode only shows whether a monitor interface exists on the device. Signed-off-by: Gábor Stefanik Acked-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 7686fc7..7bc9c00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -718,10 +718,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); #endif - /* drop all data frame if we are not associated */ + /* drop all non-injected data frame if we are not associated */ if (ieee80211_is_data(fc) && - (!iwl_is_monitor_mode(priv) || - !(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */ + !(info->flags & IEEE80211_TX_CTL_INJECTED) && (!iwl_is_associated(priv) || ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) || !priv->assoc_station_added)) { @@ -732,7 +731,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ - sta_id = iwl_get_sta_id(priv, hdr); + if (info->flags & IEEE80211_TX_CTL_INJECTED) + sta_id = priv->hw_params.bcast_sta_id; + else + sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", hdr->addr1); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f339c5b..3479041 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -518,9 +518,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); #endif - /* drop all data frame if we are not associated */ + /* drop all non-injected data frame if we are not associated */ if (ieee80211_is_data(fc) && - (!iwl_is_monitor_mode(priv)) && /* packet injection */ + !(info->flags & IEEE80211_TX_CTL_INJECTED) && (!iwl_is_associated(priv) || ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) { IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n"); @@ -532,7 +532,10 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ - sta_id = iwl_get_sta_id(priv, hdr); + if (info->flags & IEEE80211_TX_CTL_INJECTED) + sta_id = priv->hw_params.bcast_sta_id; + else + sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", hdr->addr1); -- cgit v0.10.2 From 02eec9c5a1d3e9a2bed5e6221970febef38fc080 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:14 -0700 Subject: iwlwifi: set default tx power user limit to minimal Set the tx_power_user_lmt to the lowest power level this value will get overwritten by channel's max power avg from eeprom Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index f1f6dab..43781dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1671,7 +1671,10 @@ int iwl_init_drv(struct iwl_priv *priv) priv->qos_data.qos_cap.val = 0; priv->rates_mask = IWL_RATES_MASK; - priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; + /* Set the tx_power_user_lmt to the lowest power level + * this value will get overwritten by channel max power avg + * from eeprom */ + priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MIN; ret = iwl_init_channel_map(priv); if (ret) { -- cgit v0.10.2 From 08f2d58d0e573d13a8eb0afbb6f3122da37b9ce3 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:15 -0700 Subject: iwlwifi: do not allow set tx power over channel power limit When setting tx power in sysfs, check against max channel tx power limit instead of IWL_TX_POWER_TARGET_POWER_MAX. Different devices have different max tx power limit; using IWL_TX_POWER_TARGET_POWER_MAX can excess the limitaion and give wrong information. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 43781dc..faafcae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1708,10 +1708,10 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) return -EINVAL; } - if (tx_power > IWL_TX_POWER_TARGET_POWER_MAX) { - IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n", - tx_power, - IWL_TX_POWER_TARGET_POWER_MAX); + if (tx_power > priv->tx_power_channel_lmt) { + IWL_WARN(priv, + "Requested user TXPOWER %d above upper limit %d.\n", + tx_power, priv->tx_power_channel_lmt); return -EINVAL; } -- cgit v0.10.2 From dc1b09733215e19f6a0f676be2744fe2f5471d85 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:16 -0700 Subject: iwlwifi: name changes from "tx_power_channel_lmt" to "tx_power_device_lmt" Changing the name from "tx_power_channel_lmt" to "tx_power_device_lmt"; to give idea that scope of limit is for overall device, not any individual channels Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index faafcae..82dadd0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -543,8 +543,8 @@ int iwlcore_init_geos(struct iwl_priv *priv) geo_ch->flags |= ch->ht40_extension_channel; - if (ch->max_power_avg > priv->tx_power_channel_lmt) - priv->tx_power_channel_lmt = ch->max_power_avg; + if (ch->max_power_avg > priv->tx_power_device_lmt) + priv->tx_power_device_lmt = ch->max_power_avg; } else { geo_ch->flags |= IEEE80211_CHAN_DISABLED; } @@ -1708,10 +1708,10 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) return -EINVAL; } - if (tx_power > priv->tx_power_channel_lmt) { + if (tx_power > priv->tx_power_device_lmt) { IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n", - tx_power, priv->tx_power_channel_lmt); + tx_power, priv->tx_power_device_lmt); return -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0178734..ccea2e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1215,7 +1215,7 @@ struct iwl_priv { /* TX Power */ s8 tx_power_user_lmt; - s8 tx_power_channel_lmt; + s8 tx_power_device_lmt; #ifdef CONFIG_IWLWIFI_DEBUG -- cgit v0.10.2 From 5eadd94bd4006aacf12052c447bcc997bf6ecd28 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:17 -0700 Subject: iwlwifi: error checking for setting tx_power in sysfs Perform error checking and report failure when setting tx power from sysfs. If fail to set the tx power, do not update the local copy, so user will not see the incorrect tx power in sysfs Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2232b17..533b393 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2477,10 +2477,15 @@ static ssize_t store_tx_power(struct device *d, ret = strict_strtoul(buf, 10, &val); if (ret) IWL_INFO(priv, "%s is not in decimal form.\n", buf); - else - iwl_set_tx_power(priv, val, false); - - return count; + else { + ret = iwl_set_tx_power(priv, val, false); + if (ret) + IWL_ERR(priv, "failed setting tx power (0x%d).\n", + ret); + else + ret = count; + } + return ret; } static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 82dadd0..c62c081 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1701,6 +1701,8 @@ EXPORT_SYMBOL(iwl_init_drv); int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret = 0; + s8 prev_tx_power = priv->tx_power_user_lmt; + if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) { IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n", tx_power, @@ -1718,15 +1720,27 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) if (priv->tx_power_user_lmt != tx_power) force = true; - priv->tx_power_user_lmt = tx_power; - /* if nic is not up don't send command */ - if (!iwl_is_ready_rf(priv)) - return ret; - - if (force && priv->cfg->ops->lib->send_tx_power) - ret = priv->cfg->ops->lib->send_tx_power(priv); + if (iwl_is_ready_rf(priv)) { + priv->tx_power_user_lmt = tx_power; + if (force && priv->cfg->ops->lib->send_tx_power) + ret = priv->cfg->ops->lib->send_tx_power(priv); + else if (!priv->cfg->ops->lib->send_tx_power) + ret = -EOPNOTSUPP; + /* + * if fail to set tx_power, restore the orig. tx power + */ + if (ret) + priv->tx_power_user_lmt = prev_tx_power; + } + /* + * Even this is an async host command, the command + * will always report success from uCode + * So once driver can placing the command into the queue + * successfully, driver can use priv->tx_power_user_lmt + * to reflect the current tx power + */ return ret; } EXPORT_SYMBOL(iwl_set_tx_power); -- cgit v0.10.2 From fcbaf8b06da385c73cb6218f079e9ddba9ee9f7c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:18 -0700 Subject: iwlwifi: change IWL6000_UCODE_API_MAX to v4 uCode version changed to v4 for 6000 series The additional parameter added to v4 is providing current tx power for each chain in tx statistics portion of "statistics notification" command. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 383177d..33ef736 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -46,8 +46,8 @@ #include "iwl-5000-hw.h" /* Highest firmware API version supported */ -#define IWL6000_UCODE_API_MAX 3 -#define IWL6050_UCODE_API_MAX 3 +#define IWL6000_UCODE_API_MAX 4 +#define IWL6050_UCODE_API_MAX 4 /* Lowest firmware API version supported */ #define IWL6000_UCODE_API_MIN 1 diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index f430384..6b82d4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2930,6 +2930,20 @@ struct statistics_rx { struct statistics_rx_ht_phy ofdm_ht; } __attribute__ ((packed)); +/** + * struct statistics_tx_power - current tx power + * + * @ant_a: current tx power on chain a in 1/2 dB step + * @ant_b: current tx power on chain b in 1/2 dB step + * @ant_c: current tx power on chain c in 1/2 dB step + */ +struct statistics_tx_power { + u8 ant_a; + u8 ant_b; + u8 ant_c; + u8 reserved; +} __attribute__ ((packed)); + struct statistics_tx_non_phy_agg { __le32 ba_timeout; __le32 ba_reschedule_frames; @@ -2941,8 +2955,6 @@ struct statistics_tx_non_phy_agg { __le32 underrun; __le32 bt_prio_kill; __le32 rx_ba_rsp_cnt; - __le32 reserved2; - __le32 reserved3; } __attribute__ ((packed)); struct statistics_tx { @@ -2961,6 +2973,8 @@ struct statistics_tx { __le32 cts_timeout_collision; __le32 ack_or_ba_timeout_collision; struct statistics_tx_non_phy_agg agg; + struct statistics_tx_power tx_power; + __le32 reserved1; } __attribute__ ((packed)); -- cgit v0.10.2 From f204b2487e5503ca4a9f3e69dcd63f6af979aaac Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:19 -0700 Subject: iwlwifi: show current tx power debugFs file show current tx power for all the transmit chains Adding "tx_power" file in /sys/kernal/debug/ieee80211/phy0/iwlagn/debug to display current tx power for all the active chains in 1/2 dB step. Show tx power information "Not available" if uCode can not provide the information or interface is down. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 723f38a..cbc6290 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -107,6 +107,7 @@ struct iwl_debugfs { struct dentry *file_ucode_general_stats; struct dentry *file_sensitivity; struct dentry *file_chain_noise; + struct dentry *file_tx_power; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index f68fb47..fb84485 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1563,6 +1563,57 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_tx_power_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[128]; + int pos = 0; + ssize_t ret; + const size_t bufsz = sizeof(buf); + struct statistics_tx *tx; + + if (!iwl_is_alive(priv)) + pos += scnprintf(buf + pos, bufsz - pos, "N/A\n"); + else { + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, "Error sending statistics request: %zd\n", + ret); + return -EAGAIN; + } + tx = &priv->statistics.tx; + if (tx->tx_power.ant_a || + tx->tx_power.ant_b || + tx->tx_power.ant_c) { + pos += scnprintf(buf + pos, bufsz - pos, + "tx power: (1/2 dB step)\n"); + if ((priv->cfg->valid_tx_ant & ANT_A) && + tx->tx_power.ant_a) + pos += scnprintf(buf + pos, bufsz - pos, + "\tantenna A: 0x%X\n", + tx->tx_power.ant_a); + if ((priv->cfg->valid_tx_ant & ANT_B) && + tx->tx_power.ant_b) + pos += scnprintf(buf + pos, bufsz - pos, + "\tantenna B: 0x%X\n", + tx->tx_power.ant_b); + if ((priv->cfg->valid_tx_ant & ANT_C) && + tx->tx_power.ant_c) + pos += scnprintf(buf + pos, bufsz - pos, + "\tantenna C: 0x%X\n", + tx->tx_power.ant_c); + } else + pos += scnprintf(buf + pos, bufsz - pos, "N/A\n"); + } + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1573,6 +1624,7 @@ DEBUGFS_READ_FILE_OPS(ucode_tx_stats); DEBUGFS_READ_FILE_OPS(ucode_general_stats); DEBUGFS_READ_FILE_OPS(sensitivity); DEBUGFS_READ_FILE_OPS(chain_noise); +DEBUGFS_READ_FILE_OPS(tx_power); /* * Create the debugfs files and directories @@ -1621,6 +1673,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(traffic_log, debug); DEBUGFS_ADD_FILE(rx_queue, debug); DEBUGFS_ADD_FILE(tx_queue, debug); + DEBUGFS_ADD_FILE(tx_power, debug); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_ADD_FILE(ucode_rx_stats, debug); DEBUGFS_ADD_FILE(ucode_tx_stats, debug); @@ -1674,6 +1727,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_rx_stats); -- cgit v0.10.2 From 7ebaeff8ae0ba14c086b117f451c5b40bea8a64b Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 21 Aug 2009 13:34:20 -0700 Subject: iwlwifi: clear rate control flags on non-HT packet Clear the flags (most importantly, the IEEE80211_TX_RC_MCS flag) when sending a non-HT packet so that the rate index can be properly treated. This fixes the reporting of legacy rates in wireless-extensions for packets sent after an HT packet. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index fee110d..26ec969 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2546,6 +2546,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, rate_idx = rate_lowest_index(sband, sta); else if (sband->band == IEEE80211_BAND_5GHZ) rate_idx -= IWL_FIRST_OFDM_RATE; + info->control.rates[0].flags = 0; } info->control.rates[0].idx = rate_idx; -- cgit v0.10.2 From c5f8cdb72e3940d647980358dec0aba945a3bb57 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 21 Aug 2009 13:34:21 -0700 Subject: iwlwifi: set HT flags in ieee80211_rx_status for received packets Add code to set the HT flags (HT, 40 MHz, Short guard interval) in the ieee80211_rx_status field passed to mac80211. This ensures that mac80211 processes these HT packets correctly. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 353d9a2..e34d3fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -915,6 +915,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, u32 len; u32 ampdu_status; u16 fc; + u32 rate_n_flags; /** * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. @@ -1032,6 +1033,15 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) rx_status.flag |= RX_FLAG_SHORTPRE; + /* Set up the HT phy flags */ + rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); + if (rate_n_flags & RATE_MCS_HT_MSK) + rx_status.flag |= RX_FLAG_HT; + if (rate_n_flags & RATE_MCS_HT40_MSK) + rx_status.flag |= RX_FLAG_40MHZ; + if (rate_n_flags & RATE_MCS_SGI_MSK) + rx_status.flag |= RX_FLAG_SHORT_GI; + if (iwl_is_network_packet(priv, header)) { priv->last_rx_rssi = rx_status.signal; priv->last_beacon_time = priv->ucode_beacon_time; -- cgit v0.10.2 From c4d9b50986b4264f32883d19ac260a11647860e1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:22 -0700 Subject: iwlwifi: remove duplicated define Remove duplicated define "STA_FLG_PWR_SAVE_MSK" Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6b82d4e..2c5c88f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -886,7 +886,6 @@ struct iwl_qosparam_cmd { #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2); #define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); -#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); #define STA_FLG_RTS_MIMO_PROT_MSK cpu_to_le32(1 << 17) #define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18) #define STA_FLG_MAX_AGG_SIZE_POS (19) -- cgit v0.10.2 From ab9fd1bf76ffebf6c3b3d5800092387edf1201b9 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:23 -0700 Subject: iwlwifi: read enhanced tx power info from EEPROM image For 6000 series and up, additional enhanced regulatory tx power limitation information is added to EEPROM image. In order to setup the tx power limitation per channel correctly. Read the enhanced tx power information from EEPROM image and update accordingly. The information is provided per SISO (a,b,c) chain based, it also has information for both MIMO2 and MIMO3. For tx power regulatory limitation, take the highest number from all the chains and update. Also update tx_power_user_lmt to the highest power supported by any channels and chains Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 33ef736..82b9c93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -126,6 +126,7 @@ static struct iwl_lib_ops iwl6000_lib = { .release_semaphore = iwlcore_eeprom_release_semaphore, .calib_version = iwl5000_eeprom_calib_version, .query_addr = iwl5000_eeprom_query_addr, + .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, .post_associate = iwl_post_associate, .isr = iwl_isr_ict, diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 01b95e8..3d2b93a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -135,6 +135,78 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 }; +/** + * struct iwl_txpwr_section: eeprom section information + * @offset: indirect address into eeprom image + * @count: number of "struct iwl_eeprom_enhanced_txpwr" in this section + * @band: band type for the section + * @is_common - true: common section, false: channel section + * @is_cck - true: cck section, false: not cck section + * @is_ht_40 - true: all channel in the section are HT40 channel, + * false: legacy or HT 20 MHz + * ignore if it is common section + * @iwl_eeprom_section_channel: channel array in the section, + * ignore if common section + */ +struct iwl_txpwr_section { + u32 offset; + u8 count; + enum ieee80211_band band; + bool is_common; + bool is_cck; + bool is_ht40; + u8 iwl_eeprom_section_channel[EEPROM_MAX_TXPOWER_SECTION_ELEMENTS]; +}; + +/** + * section 1 - 3 are regulatory tx power apply to all channels based on + * modulation: CCK, OFDM + * Band: 2.4GHz, 5.2GHz + * section 4 - 10 are regulatory tx power apply to specified channels + * For example: + * 1L - Channel 1 Legacy + * 1HT - Channel 1 HT + * (1,+1) - Channel 1 HT40 "_above_" + * + * Section 1: all CCK channels + * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40) channels + * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels + * Section 4: 2.4 GHz 20MHz channels: 1L, 1HT, 2L, 2HT, 10L, 10HT, 11L, 11HT + * Section 5: 2.4 GHz 40MHz channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) + * Section 6: 5.2 GHz 20MHz channels: 36L, 64L, 100L, 36HT, 64HT, 100HT + * Section 7: 5.2 GHz 40MHz channels: (36,+1) (60,+1) (100,+1) + * Section 8: 2.4 GHz channel: 13L, 13HT + * Section 9: 2.4 GHz channel: 140L, 140HT + * Section 10: 2.4 GHz 40MHz channels: (132,+1) (44,+1) + * + */ +static const struct iwl_txpwr_section enhinfo[] = { + { EEPROM_LB_CCK_20_COMMON, 1, IEEE80211_BAND_2GHZ, true, true, false }, + { EEPROM_LB_OFDM_COMMON, 3, IEEE80211_BAND_2GHZ, true, false, false }, + { EEPROM_HB_OFDM_COMMON, 3, IEEE80211_BAND_5GHZ, true, false, false }, + { EEPROM_LB_OFDM_20_BAND, 8, IEEE80211_BAND_2GHZ, + false, false, false, + {1, 1, 2, 2, 10, 10, 11, 11 } }, + { EEPROM_LB_OFDM_HT40_BAND, 5, IEEE80211_BAND_2GHZ, + false, false, true, + { 1, 2, 6, 7, 9 } }, + { EEPROM_HB_OFDM_20_BAND, 6, IEEE80211_BAND_5GHZ, + false, false, false, + { 36, 64, 100, 36, 64, 100 } }, + { EEPROM_HB_OFDM_HT40_BAND, 3, IEEE80211_BAND_5GHZ, + false, false, true, + { 36, 60, 100 } }, + { EEPROM_LB_OFDM_20_CHANNEL_13, 2, IEEE80211_BAND_2GHZ, + false, false, false, + { 13, 13 } }, + { EEPROM_HB_OFDM_20_CHANNEL_140, 2, IEEE80211_BAND_5GHZ, + false, false, false, + { 140, 140 } }, + { EEPROM_HB_OFDM_HT40_BAND_1, 2, IEEE80211_BAND_5GHZ, + false, false, true, + { 132, 44 } }, +}; + /****************************************************************************** * * EEPROM related functions @@ -643,6 +715,178 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, return 0; } +/** + * iwl_get_max_txpower_avg - get the highest tx power from all chains. + * find the highest tx power from all chains for the channel + */ +static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element) +{ + s8 max_txpower_avg = 0; /* (dBm) */ + + IWL_DEBUG_INFO(priv, "%d - " + "chain_a: %d dB chain_b: %d dB " + "chain_c: %d dB mimo2: %d dB mimo3: %d dB\n", + element, + enhanced_txpower[element].chain_a_max >> 1, + enhanced_txpower[element].chain_b_max >> 1, + enhanced_txpower[element].chain_c_max >> 1, + enhanced_txpower[element].mimo2_max >> 1, + enhanced_txpower[element].mimo3_max >> 1); + /* Take the highest tx power from any valid chains */ + if ((priv->cfg->valid_tx_ant & ANT_A) && + (enhanced_txpower[element].chain_a_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_a_max; + if ((priv->cfg->valid_tx_ant & ANT_B) && + (enhanced_txpower[element].chain_b_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_b_max; + if ((priv->cfg->valid_tx_ant & ANT_C) && + (enhanced_txpower[element].chain_c_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_c_max; + if (((priv->cfg->valid_tx_ant == ANT_AB) | + (priv->cfg->valid_tx_ant == ANT_BC) | + (priv->cfg->valid_tx_ant == ANT_AC)) && + (enhanced_txpower[element].mimo2_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].mimo2_max; + if ((priv->cfg->valid_tx_ant == ANT_ABC) && + (enhanced_txpower[element].mimo3_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].mimo3_max; + + /* max. tx power in EEPROM is in 1/2 dBm format + * convert from 1/2 dBm to dBm + */ + return max_txpower_avg >> 1; +} + +/** + * iwl_update_common_txpower: update channel tx power + * update tx power per band based on EEPROM enhanced tx power info. + */ +static s8 iwl_update_common_txpower(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int section, int element) +{ + struct iwl_channel_info *ch_info; + int ch; + bool is_ht40 = false; + s8 max_txpower_avg; /* (dBm) */ + + /* it is common section, contain all type (Legacy, HT and HT40) + * based on the element in the section to determine + * is it HT 40 or not + */ + if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) + is_ht40 = true; + max_txpower_avg = + iwl_get_max_txpower_avg(priv, enhanced_txpower, element); + ch_info = priv->channel_info; + + for (ch = 0; ch < priv->channel_count; ch++) { + /* find matching band and update tx power if needed */ + if ((ch_info->band == enhinfo[section].band) && + (ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) { + /* Update regulatory-based run-time data */ + ch_info->max_power_avg = ch_info->curr_txpow = + max_txpower_avg; + ch_info->scan_power = max_txpower_avg; + } + if ((ch_info->band == enhinfo[section].band) && is_ht40 && + ch_info->ht40_max_power_avg && + (ch_info->ht40_max_power_avg < max_txpower_avg)) { + /* Update regulatory-based run-time data */ + ch_info->ht40_max_power_avg = max_txpower_avg; + ch_info->ht40_curr_txpow = max_txpower_avg; + ch_info->ht40_scan_power = max_txpower_avg; + } + ch_info++; + } + return max_txpower_avg; +} + +/** + * iwl_update_channel_txpower: update channel tx power + * update channel tx power based on EEPROM enhanced tx power info. + */ +static s8 iwl_update_channel_txpower(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int section, int element) +{ + struct iwl_channel_info *ch_info; + int ch; + u8 channel; + s8 max_txpower_avg; /* (dBm) */ + + channel = enhinfo[section].iwl_eeprom_section_channel[element]; + max_txpower_avg = + iwl_get_max_txpower_avg(priv, enhanced_txpower, element); + + ch_info = priv->channel_info; + for (ch = 0; ch < priv->channel_count; ch++) { + /* find matching channel and update tx power if needed */ + if (ch_info->channel == channel) { + if ((ch_info->max_power_avg < max_txpower_avg) && + (!enhinfo[section].is_ht40)) { + /* Update regulatory-based run-time data */ + ch_info->max_power_avg = max_txpower_avg; + ch_info->curr_txpow = max_txpower_avg; + ch_info->scan_power = max_txpower_avg; + } + if ((enhinfo[section].is_ht40) && + (ch_info->ht40_max_power_avg) && + (ch_info->ht40_max_power_avg < max_txpower_avg)) { + /* Update regulatory-based run-time data */ + ch_info->ht40_max_power_avg = max_txpower_avg; + ch_info->ht40_curr_txpow = max_txpower_avg; + ch_info->ht40_scan_power = max_txpower_avg; + } + break; + } + ch_info++; + } + return max_txpower_avg; +} + +/** + * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info + */ +void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) +{ + int eeprom_section_count = 0; + int section, element; + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; + u32 offset; + s8 max_txpower_avg; /* (dBm) */ + + /* Loop through all the sections + * adjust bands and channel's max tx power + * Set the tx_power_user_lmt to the highest power + * supported by any channels and chains + */ + for (section = 0; section < ARRAY_SIZE(enhinfo); section++) { + eeprom_section_count = enhinfo[section].count; + offset = enhinfo[section].offset; + enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *) + iwl_eeprom_query_addr(priv, offset); + + for (element = 0; element < eeprom_section_count; element++) { + if (enhinfo[section].is_common) + max_txpower_avg = + iwl_update_common_txpower(priv, + enhanced_txpower, section, element); + else + max_txpower_avg = + iwl_update_channel_txpower(priv, + enhanced_txpower, section, element); + + /* Update the tx_power_user_lmt to the highest power + * supported by any channel */ + if (max_txpower_avg > priv->tx_power_user_lmt) + priv->tx_power_user_lmt = max_txpower_avg; + } + } +} +EXPORT_SYMBOL(iwlcore_eeprom_enhanced_txpower); + #define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ ? # x " " : "") @@ -790,6 +1034,14 @@ int iwl_init_channel_map(struct iwl_priv *priv) } } + /* for newer device (6000 series and up) + * EEPROM contain enhanced tx power information + * driver need to process addition information + * to determine the max channel tx power limits + */ + if (priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower) + priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower(priv); + return 0; } EXPORT_SYMBOL(iwl_init_channel_map); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index ca7920a..6b68db7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -118,6 +118,30 @@ struct iwl_eeprom_channel { s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ } __attribute__ ((packed)); +/** + * iwl_eeprom_enhanced_txpwr structure + * This structure presents the enhanced regulatory tx power limit layout + * in eeprom image + * Enhanced regulatory tx power portion of eeprom image can be broken down + * into individual structures; each one is 8 bytes in size and contain the + * following information + * @chain_a_max_pwr: chain a max power in 1/2 dBm + * @chain_b_max_pwr: chain b max power in 1/2 dBm + * @chain_c_max_pwr: chain c max power in 1/2 dBm + * @mimo2_max_pwr: mimo2 max power in 1/2 dBm + * @mimo3_max_pwr: mimo3 max power in 1/2 dBm + * + */ +struct iwl_eeprom_enhanced_txpwr { + u16 reserved; + s8 chain_a_max; + s8 chain_b_max; + s8 chain_c_max; + s8 reserved1; + s8 mimo2_max; + s8 mimo3_max; +} __attribute__ ((packed)); + /* 3945 Specific */ #define EEPROM_3945_EEPROM_VERSION (0x2f) @@ -175,6 +199,59 @@ struct iwl_eeprom_channel { #define EEPROM_5000_REG_BAND_52_HT40_CHANNELS ((0x92)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ +/* 6000 and up regulatory tx power - indirect access */ +/* max. elements per section */ +#define EEPROM_MAX_TXPOWER_SECTION_ELEMENTS (8) +#define EEPROM_TXPOWER_COMMON_HT40_INDEX (2) + +/** + * Partition the enhanced tx power portion of eeprom image into + * 10 sections based on band, modulation, frequency and channel + * + * Section 1: all CCK channels + * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40 ) channels + * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels + * Section 4: 2.4 GHz 20MHz channels: 1, 2, 10, 11. Both Legacy and HT + * Section 5: 2.4 GHz 40MHz channels: 1, 2, 6, 7, 9, (_above_) + * Section 6: 5.2 GHz 20MHz channels: 36, 64, 100, both Legacy and HT + * Section 7: 5.2 GHz 40MHz channels: 36, 60, 100 (_above_) + * Section 8: 2.4 GHz channel 13, Both Legacy and HT + * Section 9: 2.4 GHz channel 140, Both Legacy and HT + * Section 10: 2.4 GHz 40MHz channels: 132, 44 (_above_) + */ +/* 2.4 GHz band: CCK */ +#define EEPROM_LB_CCK_20_COMMON ((0xAA)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 8 bytes */ +/* 2.4 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */ +#define EEPROM_LB_OFDM_COMMON ((0xB2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */ +/* 5.2 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */ +#define EEPROM_HB_OFDM_COMMON ((0xCA)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */ +/* 2.4GHz band channels: + * 1Legacy, 1HT, 2Legacy, 2HT, 10Legacy, 10HT, 11Legacy, 11HT */ +#define EEPROM_LB_OFDM_20_BAND ((0xE2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 64 bytes */ +/* 2.4 GHz band HT40 channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) */ +#define EEPROM_LB_OFDM_HT40_BAND ((0x122)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 40 bytes */ +/* 5.2GHz band channels: 36Legacy, 36HT, 64Legacy, 64HT, 100Legacy, 100HT */ +#define EEPROM_HB_OFDM_20_BAND ((0x14A)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 48 bytes */ +/* 5.2 GHz band HT40 channels: (36,+1) (60,+1) (100,+1) */ +#define EEPROM_HB_OFDM_HT40_BAND ((0x17A)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */ +/* 2.4 GHz band, channnel 13: Legacy, HT */ +#define EEPROM_LB_OFDM_20_CHANNEL_13 ((0x192)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */ +/* 5.2 GHz band, channnel 140: Legacy, HT */ +#define EEPROM_HB_OFDM_20_CHANNEL_140 ((0x1A2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */ +/* 5.2 GHz band, HT40 channnels (132,+1) (44,+1) */ +#define EEPROM_HB_OFDM_HT40_BAND_1 ((0x1B2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */ + + /* 5050 Specific */ #define EEPROM_5050_TX_POWER_VERSION (4) #define EEPROM_5050_EEPROM_VERSION (0x21E) @@ -389,6 +466,7 @@ struct iwl_eeprom_ops { void (*release_semaphore) (struct iwl_priv *priv); u16 (*calib_version) (struct iwl_priv *priv); const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); + void (*update_enhanced_txpower) (struct iwl_priv *priv); }; @@ -403,7 +481,7 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); - +void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv); int iwl_init_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv); const struct iwl_channel_info *iwl_get_channel_info( -- cgit v0.10.2 From b2ccb4dbe77eaebb6b286402c31b4e2b1155660f Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 21 Aug 2009 13:34:24 -0700 Subject: iwlwifi: fix remove key error Fix following error by sending synchronous command and waiting for the command to complete. mac80211-phy0: failed to remove key (0, ff:ff:ff:ff:ff:ff) from hardware (-16). -16 is EBUSY error. The asynchronous command tests for STATUS_EXIT_PENDING while interface is getting down and it returns -EBUSY error if set. Changing the host command from asynchronous call to synchronous call enables command to be run while interface is going down. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index c6633fe..a2b9ec8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -520,7 +520,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) struct iwl_host_cmd cmd = { .id = REPLY_WEPKEY, .data = wep_cmd, - .flags = CMD_ASYNC, + .flags = CMD_SYNC, }; memset(wep_cmd, 0, cmd_size + -- cgit v0.10.2 From 5bddf54962bf68002816df710348ba197d6391bb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:25 -0700 Subject: iwlwifi: fix unloading driver while scanning If NetworkManager is busy scanning when user tries to unload the module, the driver can not be unloaded because HW still scanning. Make sure driver sends abort scan host command to uCode if it is in the middle of scanning during driver unload. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 533b393..00457bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2155,7 +2155,7 @@ static void iwl_mac_stop(struct ieee80211_hw *hw) priv->is_open = 0; - if (iwl_is_ready_rf(priv)) { + if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) { /* stop mac, cancel any scan request and clear * RXON_FILTER_ASSOC_MSK BIT */ diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index c4c916d..4f3a108 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -796,7 +796,8 @@ void iwl_bg_abort_scan(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); - if (!iwl_is_ready(priv)) + if (!test_bit(STATUS_READY, &priv->status) || + !test_bit(STATUS_GEO_CONFIGURED, &priv->status)) return; mutex_lock(&priv->mutex); -- cgit v0.10.2 From c1eb2c82e5ccc9b691f737c3150e746c9af3ffab Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 21 Aug 2009 13:34:26 -0700 Subject: ipw2x00: update contact information Intel Linux wireless folks can be reached via this address. Signed-off-by: Reinette Chatre Acked-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 33bdb20..8caa07a 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -19,7 +19,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 Portions of this file are based on the sample_* files provided by Wireless diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h index af175bd..1eab0d6 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/ipw2x00/ipw2100.h @@ -19,7 +19,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 3617e3c..0ccec9f 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -25,7 +25,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h index 4448bad..bf0eeb2 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/ipw2x00/ipw2200.h @@ -19,7 +19,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/libipw_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c index d04979b..65e8c17 100644 --- a/drivers/net/wireless/ipw2x00/libipw_geo.c +++ b/drivers/net/wireless/ipw2x00/libipw_geo.c @@ -19,7 +19,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index 00c3640..eb2b608 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -25,7 +25,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index ce1855f..46530ce 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -19,7 +19,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c index f79ce57..4d89f66 100644 --- a/drivers/net/wireless/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c @@ -25,7 +25,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ -- cgit v0.10.2 From a0bf797ff10cdbc15e8abe1309e7ab397f61691f Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 21 Aug 2009 14:03:51 -0700 Subject: MAINTAINERS: Update ipw2x00 and iwlwifi entries Update MAINTAINERS file to reflect current maintenance status of ipw2x00 drivers. We remove James's name as he is not involved with this project anymore. We also update the Status to "Odd Fixes". This has been true for a while now, we have to make it official. There is also a new email address with which all relevant people can be reached. The same email address should be used for iwlwifi. Signed-off-by: Reinette Chatre Cc: James Ketrenos Acked-by: James Ketrenos Acked-by: Zhu Yi Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index 9b55c66..8d3a91f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2653,25 +2653,21 @@ F: drivers/net/ixgbe/ INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT M: Zhu Yi -M: James Ketrenos M: Reinette Chatre +M: Intel Linux Wireless L: linux-wireless@vger.kernel.org -L: ipw2100-devel@lists.sourceforge.net -W: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel W: http://ipw2100.sourceforge.net -S: Supported +S: Odd Fixes F: Documentation/networking/README.ipw2100 F: drivers/net/wireless/ipw2x00/ipw2100.* INTEL PRO/WIRELESS 2915ABG NETWORK CONNECTION SUPPORT M: Zhu Yi -M: James Ketrenos M: Reinette Chatre +M: Intel Linux Wireless L: linux-wireless@vger.kernel.org -L: ipw2100-devel@lists.sourceforge.net -W: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel W: http://ipw2200.sourceforge.net -S: Supported +S: Odd Fixes F: Documentation/networking/README.ipw2200 F: drivers/net/wireless/ipw2x00/ipw2200.* @@ -2688,8 +2684,8 @@ F: include/linux/wimax/i2400m.h INTEL WIRELESS WIFI LINK (iwlwifi) M: Zhu Yi M: Reinette Chatre +M: Intel Linux Wireless L: linux-wireless@vger.kernel.org -L: ipw3945-devel@lists.sourceforge.net W: http://intellinuxwireless.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-2.6.git S: Supported -- cgit v0.10.2 From ea39d1a4027cca99cc75126f574633c3b72da04a Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Fri, 21 Aug 2009 23:25:07 +0200 Subject: ar9170: cleanup of bss_info_changed and beacon config Add beacon control by BSS_CHANGED_BEACON_ENABLED and bss_conf->enable_beacon from mac80211. Signed-off-by: Joerg Albert Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index ce40724..914e471 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -178,6 +178,7 @@ struct ar9170 { /* beaconing */ struct sk_buff *beacon; struct work_struct beacon_work; + bool enable_beacon; /* cryptographic engine */ u64 usedkeys; diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index 6004936..614e321 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -383,24 +383,26 @@ int ar9170_set_beacon_timers(struct ar9170 *ar) if (ar->vif) { v |= ar->vif->bss_conf.beacon_int; - switch (ar->vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_ADHOC: - v |= BIT(25); - break; - case NL80211_IFTYPE_AP: - v |= BIT(24); - pretbtt = (ar->vif->bss_conf.beacon_int - 6) << 16; - break; - default: + if (ar->enable_beacon) { + switch (ar->vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_ADHOC: + v |= BIT(25); + break; + case NL80211_IFTYPE_AP: + v |= BIT(24); + pretbtt = (ar->vif->bss_conf.beacon_int - 6) << + 16; + break; + default: break; + } } v |= ar->vif->bss_conf.dtim_period << 16; } ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt); ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v); ar9170_regwrite_finish(); diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 658b323..c0fc355 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2148,11 +2148,17 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, goto out; } - if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { + if (changed & BSS_CHANGED_BEACON_ENABLED) + ar->enable_beacon = bss_conf->enable_beacon; + + if (changed & BSS_CHANGED_BEACON) { err = ar9170_update_beacon(ar); if (err) goto out; + } + if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_INT)) { err = ar9170_set_beacon_timers(ar); if (err) goto out; @@ -2165,12 +2171,6 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, #endif /* CONFIG_AR9170_LEDS */ } - if (changed & BSS_CHANGED_BEACON_INT) { - err = ar9170_set_beacon_timers(ar); - if (err) - goto out; - } - if (changed & BSS_CHANGED_HT) { /* TODO */ err = 0; -- cgit v0.10.2 From 229a7ef7c2861f9ecb7e025f4bd4ea1167fbb0a7 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Fri, 21 Aug 2009 22:53:37 +0200 Subject: ar9170: remove unnecessary call to ar9170_set_beacon_timers Signed-off-by: Joerg Albert Acked-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index c0fc355..c1f8c69 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2031,12 +2031,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) goto out; } - if (changed & BSS_CHANGED_BEACON_INT) { - err = ar9170_set_beacon_timers(ar); - if (err) - goto out; - } - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { /* adjust slot time for 5 GHz */ -- cgit v0.10.2 From 0448b5fc032ea76096eb3cfbe3196b3c01b08b86 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sat, 22 Aug 2009 21:15:49 +0200 Subject: nl80211: jump to out_err upon unsupported iftype Jump to out_err when the iftype is not supported. Signed-off-by: Roel Kluin Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 71bfc04..eddab09 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2181,7 +2181,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { err = -EOPNOTSUPP; - goto out; + goto out_err; } while (1) { -- cgit v0.10.2 From 77a980dc6c4674fc7741d72b9775135669318d8d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 24 Aug 2009 11:46:30 +0200 Subject: mac80211: fix RX skb leaks In mac80211's RX path some of the warnings that warn about drivers passing invalid status values leak the skb, fix that by refactoring the code. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b98f1af..c01588f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2447,17 +2447,13 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_supported_band *sband; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - if (status->band < 0 || - status->band >= IEEE80211_NUM_BANDS) { - WARN_ON(1); - return; - } + if (WARN_ON(status->band < 0 || + status->band >= IEEE80211_NUM_BANDS)) + goto drop; sband = local->hw.wiphy->bands[status->band]; - if (!sband) { - WARN_ON(1); - return; - } + if (WARN_ON(!sband)) + goto drop; /* * If we're suspending, it is possible although not too likely @@ -2466,25 +2462,21 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) * that might, for example, cause stations to be added or other * driver callbacks be invoked. */ - if (unlikely(local->quiescing || local->suspended)) { - kfree_skb(skb); - return; - } + if (unlikely(local->quiescing || local->suspended)) + goto drop; /* * The same happens when we're not even started, * but that's worth a warning. */ - if (WARN_ON(!local->started)) { - kfree_skb(skb); - return; - } + if (WARN_ON(!local->started)) + goto drop; if (status->flag & RX_FLAG_HT) { /* rate_idx is MCS index */ if (WARN_ON(status->rate_idx < 0 || status->rate_idx >= 76)) - return; + goto drop; /* HT rates are not in the table - use the highest legacy rate * for now since other parts of mac80211 may not yet be fully * MCS aware. */ @@ -2492,7 +2484,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) } else { if (WARN_ON(status->rate_idx < 0 || status->rate_idx >= sband->n_bitrates)) - return; + goto drop; rate = &sband->bitrates[status->rate_idx]; } @@ -2531,6 +2523,10 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) __ieee80211_rx_handle_packet(hw, skb, rate); rcu_read_unlock(); + + return; + drop: + kfree_skb(skb); } EXPORT_SYMBOL(ieee80211_rx); -- cgit v0.10.2 From 942457d63fedd08ce7330b89fc2934be02c3fecc Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 24 Aug 2009 15:42:36 +0200 Subject: mwl8k: fix inverted error test in mwl8k_bss_info_changed() Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 41a708c..4d3353c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2617,7 +2617,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, priv->capture_beacon = false; rc = mwl8k_fw_lock(hw); - if (!rc) + if (rc) return; if (info->assoc) { -- cgit v0.10.2 From 39a1e42eb4d0a2bc3f1211e9012bd23734ab86db Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 24 Aug 2009 15:42:46 +0200 Subject: mwl8k: fix pci dma mapping leak in mwl8k_post_cmd() error path Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 4d3353c..a4336f4 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1439,8 +1439,11 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) return -ENOMEM; rc = mwl8k_fw_lock(hw); - if (rc) + if (rc) { + pci_unmap_single(priv->pdev, dma_addr, dma_size, + PCI_DMA_BIDIRECTIONAL); return rc; + } priv->hostcmd_wait = &cmd_wait; iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); -- cgit v0.10.2 From 76c962a204f8d36b762440aa941fcea3d44e2fd2 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 24 Aug 2009 15:42:56 +0200 Subject: mwl8k: missing endian conversion when printing firmware command result Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a4336f4..6e017db 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1474,7 +1474,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) printk(KERN_ERR "%s: Command %s error 0x%x\n", priv->name, mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), - cmd->result); + le16_to_cpu(cmd->result)); } return rc; -- cgit v0.10.2 From 2aa7b01fe4f2d0978115bfd40364f52d86003606 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 24 Aug 2009 15:48:07 +0200 Subject: mwl8k: separate driver and device info reporting during probe Only print the driver version once, and condense all per-PHY information to a single line. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 6e017db..746532e 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -164,7 +164,7 @@ struct mwl8k_priv { u16 num_mcaddrs; u8 hw_rev; - __le32 fw_rev; + u32 fw_rev; /* * Running count of TX packets in flight, to avoid @@ -2825,11 +2825,16 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) static int __devinit mwl8k_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + static int printed_version = 0; struct ieee80211_hw *hw; struct mwl8k_priv *priv; int rc; int i; - u8 *fw; + + if (!printed_version) { + printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION); + printed_version = 1; + } rc = pci_enable_device(pdev); if (rc) { @@ -3004,13 +3009,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_stop_firmware; } - fw = (u8 *)&priv->fw_rev; - printk(KERN_INFO "%s: 88W%u %s\n", priv->name, priv->part_num, - MWL8K_DESC); - printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n", - priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]); - printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name, - hw->wiphy->perm_addr); + printk(KERN_INFO "%s: 88w%u v%d, %pM, firmware version %u.%u.%u.%u\n", + wiphy_name(hw->wiphy), priv->part_num, priv->hw_rev, + hw->wiphy->perm_addr, + (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff, + (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff); return 0; -- cgit v0.10.2 From eadac6bf95e1945bb64e6f8f22d8509391645e2e Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Mon, 24 Aug 2009 20:51:46 +0200 Subject: mac80211: Fix output of minstrels rc_stats An integer overflow in the minstrel debug code prevented the throughput to be displayed correctly. This patch fixes that, by permutating operations like proposed by Pavel Roskin. Signed-off-by: Arnd Hannemann Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index 98f4807..3d72ec5 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c @@ -83,7 +83,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) p += sprintf(p, "%3u%s", mr->bitrate / 2, (mr->bitrate & 1 ? ".5" : " ")); - tp = ((mr->cur_tp * 96) / 18000) >> 10; + tp = mr->cur_tp / ((18000 << 10) / 96); prob = mr->cur_prob / 18; eprob = mr->probability / 18; -- cgit v0.10.2 From 56d1de0a21db28e41741cfa0a66e18bc8d920554 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 24 Aug 2009 23:00:30 -0400 Subject: ath5k: clean up filter flags setting The maze of if() statements in configure_filter is confusing. Reorganizing it as a switch statement makes it more apparent what is going on and reveals several suspicious settings. This has no functional changes, though it does remove some redundant flags that are set earlier. Also now that we can sleep, protect sc->filter_flags with the sc lock. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 5056410..c4adf98 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2918,6 +2918,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, struct ath5k_hw *ah = sc->ah; u32 mfilt[2], rfilt; + mutex_lock(&sc->lock); + mfilt[0] = multicast; mfilt[1] = multicast >> 32; @@ -2968,22 +2970,25 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */ - if (sc->opmode == NL80211_IFTYPE_MONITOR) - rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | - AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; - if (sc->opmode != NL80211_IFTYPE_STATION) - rfilt |= AR5K_RX_FILTER_PROBEREQ; - if (sc->opmode != NL80211_IFTYPE_AP && - sc->opmode != NL80211_IFTYPE_MESH_POINT && - test_bit(ATH_STAT_PROMISC, sc->status)) - rfilt |= AR5K_RX_FILTER_PROM; - if ((sc->opmode == NL80211_IFTYPE_STATION && sc->assoc) || - sc->opmode == NL80211_IFTYPE_ADHOC || - sc->opmode == NL80211_IFTYPE_AP) - rfilt |= AR5K_RX_FILTER_BEACON; - if (sc->opmode == NL80211_IFTYPE_MESH_POINT) - rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | - AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; + switch (sc->opmode) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_MONITOR: + rfilt |= AR5K_RX_FILTER_CONTROL | + AR5K_RX_FILTER_BEACON | + AR5K_RX_FILTER_PROBEREQ | + AR5K_RX_FILTER_PROM; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + rfilt |= AR5K_RX_FILTER_PROBEREQ | + AR5K_RX_FILTER_BEACON; + break; + case NL80211_IFTYPE_STATION: + if (sc->assoc) + rfilt |= AR5K_RX_FILTER_BEACON; + default: + break; + } /* Set filters */ ath5k_hw_set_rx_filter(ah, rfilt); @@ -2993,6 +2998,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, /* Set the cached hw filter flags, this will alter actually * be set in HW */ sc->filter_flags = rfilt; + + mutex_unlock(&sc->lock); } static int -- cgit v0.10.2 From 09c9bae26b0d3c9472cb6ae45010460a2cee8b8d Mon Sep 17 00:00:00 2001 From: Marcos Chaparro Date: Mon, 24 Aug 2009 23:00:31 -0400 Subject: ath5k: add led pin configuration for compaq c700 laptop With this patch, a compaq c700 can turn on the wifi led. The array of compatible devices now includes the hardware present in this computer, as well as the led pin and polarity. Signed-off-by: Marcos Chaparro Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index 876725f..b767c3b 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -69,6 +69,8 @@ static const struct pci_device_id ath5k_led_devices[] = { { ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) }, /* IBM ThinkPad AR5BXB6 (legovini@spiro.fisica.unipd.it) */ { ATH_SDEVICE(PCI_VENDOR_ID_IBM, 0x058a), ATH_LED(1, 0) }, + /* HP Compaq C700 (nitrousnrg@gmail.com) */ + { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) }, /* IBM-specific AR5212 (all others) */ { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) }, { } -- cgit v0.10.2 From 1c5256bb168faca5ce32a9c9511c8389f9fed31c Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 24 Aug 2009 23:00:32 -0400 Subject: ath5k: use the skb->cb directly for RX status Save a memcpy by just storing updates directly in the skb control block. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c4adf98..10bf015 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1741,7 +1741,7 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, static void ath5k_tasklet_rx(unsigned long data) { - struct ieee80211_rx_status rxs = {}; + struct ieee80211_rx_status *rxs; struct ath5k_rx_status rs = {}; struct sk_buff *skb, *next_skb; dma_addr_t next_skb_addr; @@ -1751,6 +1751,7 @@ ath5k_tasklet_rx(unsigned long data) int ret; int hdrlen; int padsize; + int rx_flag; spin_lock(&sc->rxbuflock); if (list_empty(&sc->rxbuf)) { @@ -1758,7 +1759,7 @@ ath5k_tasklet_rx(unsigned long data) goto unlock; } do { - rxs.flag = 0; + rx_flag = 0; bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); BUG_ON(bf->skb == NULL); @@ -1802,7 +1803,7 @@ ath5k_tasklet_rx(unsigned long data) goto accept; } if (rs.rs_status & AR5K_RXERR_MIC) { - rxs.flag |= RX_FLAG_MMIC_ERROR; + rx_flag |= RX_FLAG_MMIC_ERROR; goto accept; } @@ -1840,6 +1841,7 @@ accept: memmove(skb->data + padsize, skb->data, hdrlen); skb_pull(skb, padsize); } + rxs = IEEE80211_SKB_RXCB(skb); /* * always extend the mac timestamp, since this information is @@ -1861,41 +1863,40 @@ accept: * impossible to comply to that. This affects IBSS merge only * right now, so it's not too bad... */ - rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp); - rxs.flag |= RX_FLAG_TSFT; + rxs->mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp); + rxs->flag = rx_flag | RX_FLAG_TSFT; - rxs.freq = sc->curchan->center_freq; - rxs.band = sc->curband->band; + rxs->freq = sc->curchan->center_freq; + rxs->band = sc->curband->band; - rxs.noise = sc->ah->ah_noise_floor; - rxs.signal = rxs.noise + rs.rs_rssi; + rxs->noise = sc->ah->ah_noise_floor; + rxs->signal = rxs->noise + rs.rs_rssi; /* An rssi of 35 indicates you should be able use * 54 Mbps reliably. A more elaborate scheme can be used * here but it requires a map of SNR/throughput for each * possible mode used */ - rxs.qual = rs.rs_rssi * 100 / 35; + rxs->qual = rs.rs_rssi * 100 / 35; /* rssi can be more than 35 though, anything above that * should be considered at 100% */ - if (rxs.qual > 100) - rxs.qual = 100; + if (rxs->qual > 100) + rxs->qual = 100; - rxs.antenna = rs.rs_antenna; - rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); - rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); + rxs->antenna = rs.rs_antenna; + rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); + rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); - if (rxs.rate_idx >= 0 && rs.rs_rate == - sc->curband->bitrates[rxs.rate_idx].hw_value_short) - rxs.flag |= RX_FLAG_SHORTPRE; + if (rxs->rate_idx >= 0 && rs.rs_rate == + sc->curband->bitrates[rxs->rate_idx].hw_value_short) + rxs->flag |= RX_FLAG_SHORTPRE; ath5k_debug_dump_skb(sc, skb, "RX ", 0); /* check beacons in IBSS mode */ if (sc->opmode == NL80211_IFTYPE_ADHOC) - ath5k_check_ibss_tsf(sc, skb, &rxs); + ath5k_check_ibss_tsf(sc, skb, rxs); - memcpy(IEEE80211_SKB_RXCB(skb), &rxs, sizeof(rxs)); ieee80211_rx(sc->hw, skb); bf->skb = next_skb; -- cgit v0.10.2 From 1c81874078dc96b8158ce7b0dab54afe43c8d03e Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 24 Aug 2009 23:00:33 -0400 Subject: ath5k: add hardware CCMP encyption support Recent ath5k hardware is capable of doing CCMP acceleration. Enable it for the cards that support it. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 862762ce..cdc79cd 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1037,6 +1037,7 @@ struct ath5k_hw { bool ah_turbo; bool ah_calibration; bool ah_single_chip; + bool ah_aes_support; bool ah_combined_mic; enum ath5k_version ah_version; diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 65d438b..109ab7b 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -106,6 +106,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) { struct ath5k_hw *ah; struct pci_dev *pdev = sc->pdev; + struct ath5k_eeprom_info *ee; int ret; u32 srev; @@ -315,6 +316,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; } + /* Crypto settings */ + ee = &ah->ah_capabilities.cap_eeprom; + ah->ah_aes_support = + (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && + !AR5K_EEPROM_AES_DIS(ee->ee_misc5) && + (ah->ah_mac_version > (AR5K_SREV_AR5212 >> 4) || + (ah->ah_mac_version == (AR5K_SREV_AR5212 >> 4) && + ah->ah_mac_revision >= (AR5K_SREV_AR5211 >> 4)))); + if (srev >= AR5K_SREV_AR2414) { ah->ah_combined_mic = true; AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE, diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 10bf015..94d46fd 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -3022,6 +3022,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, case ALG_TKIP: break; case ALG_CCMP: + if (sc->ah->ah_aes_support) + break; + return -EOPNOTSUPP; default: WARN_ON(1); -- cgit v0.10.2 From 1e4c7ddc3c34b3e129ec34b3f90bd6359743a5bb Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Tue, 25 Aug 2009 15:28:45 +0530 Subject: PRISM54: fix compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/prism54/islpci_eth.o drivers/net/wireless/prism54/islpci_eth.c: In function ‘islpci_eth_cleanup_transmit’: drivers/net/wireless/prism54/islpci_eth.c:53: warning: cast from pointer to integer of different size drivers/net/wireless/prism54/islpci_eth.c: In function ‘islpci_eth_receive’: drivers/net/wireless/prism54/islpci_eth.c:453: warning: cast from pointer to integer of different size Signed-off-by: Jaswinder Singh Rajput Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index c255d9c..9b5ee34 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -50,7 +50,7 @@ islpci_eth_cleanup_transmit(islpci_private *priv, /* check for holes in the arrays caused by multi fragment frames * searching for the last fragment of a frame */ - if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) { + if (priv->pci_map_tx_address[index]) { /* entry is the last fragment of a frame * free the skb structure and unmap pci memory */ skb = priv->data_low_tx[index]; @@ -450,7 +450,7 @@ islpci_eth_receive(islpci_private *priv) pci_map_single(priv->pdev, (void *) skb->data, MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); - if (unlikely(priv->pci_map_rx_address[index] == (dma_addr_t) NULL)) { + if (unlikely(!priv->pci_map_rx_address[index])) { /* error mapping the buffer to device accessable memory address */ DEBUG(SHOW_ERROR_MESSAGES, "Error mapping DMA address\n"); -- cgit v0.10.2 From 6bd5f5208fac04d00325b458355e4a4abda76595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Tue, 25 Aug 2009 16:17:48 +0200 Subject: b43: LP-PHY: Fix a few typos in the RC calibration code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RC calibration code has some typos - fix them. Also, make the default channel 7, as channel 1 is still broken (only channels 7 and 8, and occasionally 9 work). Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 2d3a5d8..7e70c07 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -44,7 +44,7 @@ static inline u16 channel2freq_lp(u8 channel) static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) { if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - return 1; + return 7; //FIXME temporary - channel 1 is broken return 36; } @@ -705,7 +705,7 @@ static void lpphy_set_rc_cap(struct b43_wldev *dev) u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1; if (dev->phy.rev == 1) //FIXME check channel 14! - rc_cap = max_t(u8, rc_cap + 5, 15); + rc_cap = min_t(u8, rc_cap + 5, 15); b43_radio_write(dev, B2062_N_RXBB_CALIB2, max_t(u8, lpphy->rc_cap - 4, 0x80)); @@ -1008,6 +1008,7 @@ static int lpphy_loopback(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x3); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); + b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 1); b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800); @@ -1213,7 +1214,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) mean_sq_pwr = ideal_pwr - normal_pwr; mean_sq_pwr *= mean_sq_pwr; inner_sum += mean_sq_pwr; - if ((i = 128) || (inner_sum < mean_sq_pwr_min)) { + if ((i == 128) || (inner_sum < mean_sq_pwr_min)) { lpphy->rc_cap = i; mean_sq_pwr_min = inner_sum; } -- cgit v0.10.2 From 15db0b7fd872b0312033666d3a82e1214a227ec0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Aug 2009 16:33:47 +0200 Subject: mac80211: fix scan cancel on ifdown When an interface is taken down while a scan is pending -- i.e. a scan request was accepted but not yet acted upon due to other work being in progress -- we currently do not properly cancel that scan and end up getting stuck. Fix this by doing better checks when an interface is taken down. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d134bd7..f6005ad 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -497,30 +497,8 @@ static int ieee80211_stop(struct net_device *dev) } /* fall through */ default: - if (local->scan_sdata == sdata) { - if (!local->ops->hw_scan) - cancel_delayed_work_sync(&local->scan_work); - /* - * The software scan can no longer run now, so we can - * clear out the scan_sdata reference. However, the - * hardware scan may still be running. The complete - * function must be prepared to handle a NULL value. - */ - local->scan_sdata = NULL; - /* - * The memory barrier guarantees that another CPU - * that is hardware-scanning will now see the fact - * that this interface is gone. - */ - smp_mb(); - /* - * If software scanning, complete the scan but since - * the scan_sdata is NULL already don't send out a - * scan event to userspace -- the scan is incomplete. - */ - if (test_bit(SCAN_SW_SCANNING, &local->scanning)) - ieee80211_scan_completed(&local->hw, true); - } + if (local->scan_sdata == sdata) + ieee80211_scan_cancel(local); /* * Disable beaconing for AP and mesh, IBSS can't diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1e04be6..0399011 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -280,6 +280,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (local->scan_req != local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; + local->scan_sdata = NULL; was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); local->scanning = 0; @@ -660,6 +661,7 @@ void ieee80211_scan_work(struct work_struct *work) int rc; local->scan_req = NULL; + local->scan_sdata = NULL; rc = __ieee80211_start_scan(sdata, req); mutex_unlock(&local->scan_mtx); @@ -742,7 +744,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, void ieee80211_scan_cancel(struct ieee80211_local *local) { - bool swscan; + bool abortscan; cancel_delayed_work_sync(&local->scan_work); @@ -751,9 +753,10 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) * queued -- mostly at suspend under RTNL. */ mutex_lock(&local->scan_mtx); - swscan = test_bit(SCAN_SW_SCANNING, &local->scanning); + abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) || + (!local->scanning && local->scan_req); mutex_unlock(&local->scan_mtx); - if (swscan) + if (abortscan) ieee80211_scan_completed(&local->hw, true); } -- cgit v0.10.2 From 5bf6fcc2bbfb90d997f88c969f1ceee35d064a24 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 25 Aug 2009 17:44:28 +0300 Subject: mac80211: Check pending scan request after having processed mgd work When the queued management work items are processed in ieee80211_sta_work() an item could be removed. This could change the anybusy from true to false, so we better check whether we can start a new scan only after having processed the pending work first. Signed-off-by: Jouni Malinen Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c374d2d..97a278a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2123,25 +2123,9 @@ static void ieee80211_sta_work(struct work_struct *work) } } - list_for_each_entry(wk, &ifmgd->work_list, list) { - if (wk->state != IEEE80211_MGD_STATE_IDLE) { - anybusy = true; - break; - } - } ieee80211_recalc_idle(local); - if (!anybusy) { - mutex_unlock(&ifmgd->mtx); - - if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) - ieee80211_queue_delayed_work(&local->hw, - &local->scan_work, - round_jiffies_relative(0)); - return; - } - list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { if (time_is_after_jiffies(wk->timeout)) { /* @@ -2187,6 +2171,18 @@ static void ieee80211_sta_work(struct work_struct *work) } } + list_for_each_entry(wk, &ifmgd->work_list, list) { + if (wk->state != IEEE80211_MGD_STATE_IDLE) { + anybusy = true; + break; + } + } + if (!anybusy && + test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) + ieee80211_queue_delayed_work(&local->hw, + &local->scan_work, + round_jiffies_relative(0)); + mutex_unlock(&ifmgd->mtx); list_for_each_entry_safe(wk, tmp, &free_work, list) { -- cgit v0.10.2 From 73f57f8398ed6cba82f9856e20d94d71e6edb3e2 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 7 Aug 2009 23:50:00 +0200 Subject: ath9k: Fix read buffer overflow Prevent a read of powInfo[-1] in the first iteration. Signed-off-by: Roel Kluin Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 958948b..b6e52d0 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -143,10 +143,10 @@ void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, IS_CHAN_2GHZ(chan))) { matchIndex = i; break; - } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) && - (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, - IS_CHAN_2GHZ(chan)))) { + } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan)) && i > 0 && + freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan))) { lowIndex = i - 1; break; } @@ -198,10 +198,10 @@ void ath9k_hw_get_target_powers(struct ath_hw *ah, matchIndex = i; break; } else - if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) && - (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, - IS_CHAN_2GHZ(chan)))) { + if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan)) && i > 0 && + freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan))) { lowIndex = i - 1; break; } -- cgit v0.10.2 From b8ecd988b1670035a05035c553c08331214d6603 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 25 Aug 2009 14:12:25 -0400 Subject: libipw: initiate cfg80211 API conversion Initiate the conversion of libipw to the new cfg80211 configuration API. For now, leave CONFIG_IPW2200_PROMISCUOUS stuff alone. Eventually migrate it to cfg80211 when the add/del/change_virtual_intf methods are implemented. Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 8caa07a..7745738 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -6029,7 +6029,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, struct ipw2100_priv *priv; struct net_device *dev; - dev = alloc_ieee80211(sizeof(struct ipw2100_priv)); + dev = alloc_ieee80211(sizeof(struct ipw2100_priv), 0); if (!dev) return NULL; priv = libipw_priv(dev); @@ -6342,7 +6342,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); - free_ieee80211(dev); + free_ieee80211(dev, 0); pci_set_drvdata(pci_dev, NULL); } @@ -6400,7 +6400,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) if (dev->base_addr) iounmap((void __iomem *)dev->base_addr); - free_ieee80211(dev); + free_ieee80211(dev, 0); } pci_release_regions(pci_dev); diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 0ccec9f..3f8372d 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -103,6 +103,25 @@ static int antenna = CFG_SYS_ANTENNA_BOTH; static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */ #endif +static struct ieee80211_rate ipw2200_rates[] = { + { .bitrate = 10 }, + { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60 }, + { .bitrate = 90 }, + { .bitrate = 120 }, + { .bitrate = 180 }, + { .bitrate = 240 }, + { .bitrate = 360 }, + { .bitrate = 480 }, + { .bitrate = 540 } +}; + +#define ipw2200_a_rates (ipw2200_rates + 4) +#define ipw2200_num_a_rates 8 +#define ipw2200_bg_rates (ipw2200_rates + 0) +#define ipw2200_num_bg_rates 12 #ifdef CONFIG_IPW2200_QOS static int qos_enable = 0; @@ -8640,24 +8659,6 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) * */ -static int ipw_wx_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = libipw_priv(dev); - mutex_lock(&priv->mutex); - if (priv->status & STATUS_RF_KILL_MASK) - strcpy(wrqu->name, "radio off"); - else if (!(priv->status & STATUS_ASSOCIATED)) - strcpy(wrqu->name, "unassociated"); - else - snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", - ipw_modes[priv->assoc_request.ieee_mode]); - IPW_DEBUG_WX("Name: %s\n", wrqu->name); - mutex_unlock(&priv->mutex); - return 0; -} - static int ipw_set_channel(struct ipw_priv *priv, u8 channel) { if (channel == 0) { @@ -9957,7 +9958,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, /* Rebase the WE IOCTLs to zero for the handler array */ #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] static iw_handler ipw_wx_handlers[] = { - IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name, + IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq, IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, @@ -11401,16 +11402,100 @@ static void ipw_bg_down(struct work_struct *work) /* Called by register_netdev() */ static int ipw_net_init(struct net_device *dev) { + int i, rc = 0; struct ipw_priv *priv = libipw_priv(dev); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); + struct wireless_dev *wdev = &priv->ieee->wdev; mutex_lock(&priv->mutex); if (ipw_up(priv)) { - mutex_unlock(&priv->mutex); - return -EIO; + rc = -EIO; + goto out; } + memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN); + + /* fill-out priv->ieee->bg_band */ + if (geo->bg_channels) { + struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band; + + bg_band->band = IEEE80211_BAND_2GHZ; + bg_band->n_channels = geo->bg_channels; + bg_band->channels = + kzalloc(geo->bg_channels * + sizeof(struct ieee80211_channel), GFP_KERNEL); + /* translate geo->bg to bg_band.channels */ + for (i = 0; i < geo->bg_channels; i++) { + bg_band->channels[i].band = IEEE80211_BAND_2GHZ; + bg_band->channels[i].center_freq = geo->bg[i].freq; + bg_band->channels[i].hw_value = geo->bg[i].channel; + bg_band->channels[i].max_power = geo->bg[i].max_power; + if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) + bg_band->channels[i].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS) + bg_band->channels[i].flags |= + IEEE80211_CHAN_NO_IBSS; + if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT) + bg_band->channels[i].flags |= + IEEE80211_CHAN_RADAR; + /* No equivalent for LIBIPW_CH_80211H_RULES, + LIBIPW_CH_UNIFORM_SPREADING, or + LIBIPW_CH_B_ONLY... */ + } + /* point at bitrate info */ + bg_band->bitrates = ipw2200_bg_rates; + bg_band->n_bitrates = ipw2200_num_bg_rates; + + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band; + } + + /* fill-out priv->ieee->a_band */ + if (geo->a_channels) { + struct ieee80211_supported_band *a_band = &priv->ieee->a_band; + + a_band->band = IEEE80211_BAND_5GHZ; + a_band->n_channels = geo->a_channels; + a_band->channels = + kzalloc(geo->a_channels * + sizeof(struct ieee80211_channel), GFP_KERNEL); + /* translate geo->bg to a_band.channels */ + for (i = 0; i < geo->a_channels; i++) { + a_band->channels[i].band = IEEE80211_BAND_2GHZ; + a_band->channels[i].center_freq = geo->a[i].freq; + a_band->channels[i].hw_value = geo->a[i].channel; + a_band->channels[i].max_power = geo->a[i].max_power; + if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) + a_band->channels[i].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + if (geo->a[i].flags & LIBIPW_CH_NO_IBSS) + a_band->channels[i].flags |= + IEEE80211_CHAN_NO_IBSS; + if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT) + a_band->channels[i].flags |= + IEEE80211_CHAN_RADAR; + /* No equivalent for LIBIPW_CH_80211H_RULES, + LIBIPW_CH_UNIFORM_SPREADING, or + LIBIPW_CH_B_ONLY... */ + } + /* point at bitrate info */ + a_band->bitrates = ipw2200_a_rates; + a_band->n_bitrates = ipw2200_num_a_rates; + + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = a_band; + } + + set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); + + /* With that information in place, we can now register the wiphy... */ + if (wiphy_register(wdev->wiphy)) { + rc = -EIO; + goto out; + } + +out: mutex_unlock(&priv->mutex); - return 0; + return rc; } /* PCI driver stuff */ @@ -11540,7 +11625,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv) if (priv->prom_net_dev) return -EPERM; - priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv)); + priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv), 1); if (priv->prom_net_dev == NULL) return -ENOMEM; @@ -11559,7 +11644,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv) rc = register_netdev(priv->prom_net_dev); if (rc) { - free_ieee80211(priv->prom_net_dev); + free_ieee80211(priv->prom_net_dev, 1); priv->prom_net_dev = NULL; return rc; } @@ -11573,7 +11658,7 @@ static void ipw_prom_free(struct ipw_priv *priv) return; unregister_netdev(priv->prom_net_dev); - free_ieee80211(priv->prom_net_dev); + free_ieee80211(priv->prom_net_dev, 1); priv->prom_net_dev = NULL; } @@ -11601,7 +11686,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, struct ipw_priv *priv; int i; - net_dev = alloc_ieee80211(sizeof(struct ipw_priv)); + net_dev = alloc_ieee80211(sizeof(struct ipw_priv), 0); if (net_dev == NULL) { err = -ENOMEM; goto out; @@ -11749,7 +11834,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); out_free_ieee80211: - free_ieee80211(priv->net_dev); + free_ieee80211(priv->net_dev, 0); out: return err; } @@ -11816,7 +11901,7 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - free_ieee80211(priv->net_dev); + free_ieee80211(priv->net_dev, 0); free_firmware(); } diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h index cefb942..8f91d34 100644 --- a/drivers/net/wireless/ipw2x00/libipw.h +++ b/drivers/net/wireless/ipw2x00/libipw.h @@ -31,6 +31,7 @@ #include #include +#include #define LIBIPW_VERSION "git-1.1.13" @@ -783,12 +784,15 @@ struct libipw_geo { struct libipw_device { struct net_device *dev; + struct wireless_dev wdev; struct libipw_security sec; /* Bookkeeping structures */ struct libipw_stats ieee_stats; struct libipw_geo geo; + struct ieee80211_supported_band bg_band; + struct ieee80211_supported_band a_band; /* Probe / Beacon management */ struct list_head network_free_list; @@ -1014,8 +1018,8 @@ static inline int libipw_is_cck_rate(u8 rate) } /* ieee80211.c */ -extern void free_ieee80211(struct net_device *dev); -extern struct net_device *alloc_ieee80211(int sizeof_priv); +extern void free_ieee80211(struct net_device *dev, int monitor); +extern struct net_device *alloc_ieee80211(int sizeof_priv, int monitor); extern int libipw_change_mtu(struct net_device *dev, int new_mtu); extern void libipw_networks_age(struct libipw_device *ieee, diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index eb2b608..a0e9f6a 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -62,6 +62,9 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); +struct cfg80211_ops libipw_config_ops = { }; +void *libipw_wiphy_privid = &libipw_wiphy_privid; + static int libipw_networks_allocate(struct libipw_device *ieee) { if (ieee->networks) @@ -140,7 +143,7 @@ int libipw_change_mtu(struct net_device *dev, int new_mtu) } EXPORT_SYMBOL(libipw_change_mtu); -struct net_device *alloc_ieee80211(int sizeof_priv) +struct net_device *alloc_ieee80211(int sizeof_priv, int monitor) { struct libipw_device *ieee; struct net_device *dev; @@ -157,10 +160,31 @@ struct net_device *alloc_ieee80211(int sizeof_priv) ieee->dev = dev; + if (!monitor) { + ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0); + if (!ieee->wdev.wiphy) { + LIBIPW_ERROR("Unable to allocate wiphy.\n"); + goto failed_free_netdev; + } + + ieee->dev->ieee80211_ptr = &ieee->wdev; + ieee->wdev.iftype = NL80211_IFTYPE_STATION; + + /* Fill-out wiphy structure bits we know... Not enough info + here to call set_wiphy_dev or set MAC address or channel info + -- have to do that in ->ndo_init... */ + ieee->wdev.wiphy->privid = libipw_wiphy_privid; + + ieee->wdev.wiphy->max_scan_ssids = 1; + ieee->wdev.wiphy->max_scan_ie_len = 0; + ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC); + } + err = libipw_networks_allocate(ieee); if (err) { LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err); - goto failed_free_netdev; + goto failed_free_wiphy; } libipw_networks_initialize(ieee); @@ -193,19 +217,31 @@ struct net_device *alloc_ieee80211(int sizeof_priv) return dev; +failed_free_wiphy: + if (!monitor) + wiphy_free(ieee->wdev.wiphy); failed_free_netdev: free_netdev(dev); failed: return NULL; } -void free_ieee80211(struct net_device *dev) +void free_ieee80211(struct net_device *dev, int monitor) { struct libipw_device *ieee = netdev_priv(dev); lib80211_crypt_info_free(&ieee->crypt_info); libipw_networks_free(ieee); + + /* free cfg80211 resources */ + if (!monitor) { + wiphy_unregister(ieee->wdev.wiphy); + kfree(ieee->a_band.channels); + kfree(ieee->bg_band.channels); + wiphy_free(ieee->wdev.wiphy); + } + free_netdev(dev); } -- cgit v0.10.2 From a13883b0bfcc435e4b7fbbde6334339aac8b1dc4 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 26 Aug 2009 08:39:40 +0530 Subject: ath9k: Reduce the frequency of PA offset calibration PA calibration need not be done if the offset is not varying. The current logic does PA calibration even if the offset is the same. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 20f74b5..47a024d 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -861,7 +861,7 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah) REG_WRITE(ah, regList[i][0], regList[i][1]); } -static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) +static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) { u32 regVal; @@ -877,6 +877,8 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) { 0x7838, 0 }, }; + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); + if (AR_SREV_9285_11(ah)) { REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); udelay(10); @@ -936,6 +938,17 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) offs_6_1 = offset>>1; offs_0 = offset & 1; + if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) { + if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) + ah->pacal_info.max_skipcount = + 2 * ah->pacal_info.max_skipcount; + ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; + } else { + ah->pacal_info.max_skipcount = 1; + ah->pacal_info.skipcount = 0; + ah->pacal_info.prev_offset = offset; + } + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); @@ -982,8 +995,12 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, /* Do periodic PAOffset Cal */ if (AR_SREV_9271(ah)) ath9k_hw_9271_pa_cal(ah); - else if (AR_SREV_9285_11_OR_LATER(ah)) - ath9k_hw_9285_pa_cal(ah); + else if (AR_SREV_9285_11_OR_LATER(ah)) { + if (!ah->pacal_info.skipcount) + ath9k_hw_9285_pa_cal(ah, false); + else + ah->pacal_info.skipcount--; + } if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER) ath9k_olc_temp_compensation(ah); @@ -1081,7 +1098,7 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) /* Do PA Calibration */ if (AR_SREV_9285_11_OR_LATER(ah)) - ath9k_hw_9285_pa_cal(ah); + ath9k_hw_9285_pa_cal(ah, true); /* Do NF Calibration after DC offset and other calibrations */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 547e697..019bcbb 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -110,6 +110,13 @@ struct ath9k_nfcal_hist { u8 invalidNFcount; }; +#define MAX_PACAL_SKIPCOUNT 8 +struct ath9k_pacal_info{ + int32_t prev_offset; /* Previous value of PA offset value */ + int8_t max_skipcount; /* Max No. of times PACAL can be skipped */ + int8_t skipcount; /* No. of times the PACAL to be skipped */ +}; + bool ath9k_hw_reset_calvalid(struct ath_hw *ah); void ath9k_hw_start_nfcal(struct ath_hw *ah); void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 24b3063..b24150a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -424,6 +424,7 @@ struct ath_hw { enum ath9k_power_mode power_mode; struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; + struct ath9k_pacal_info pacal_info; struct ar5416Stats stats; struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES]; -- cgit v0.10.2 From 0abb0968795b55ecb102bf635a94a087bbb5aff5 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 26 Aug 2009 08:39:50 +0530 Subject: ath9k: Fix bugs in programming registers during PA CAL * First PA driver (PDPADRV1) was not powered down properly. * Compensation capacitor for dynamic PA was programmed incorrectly. Also, remove a stray REG_READ. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 47a024d..f9de16c 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -901,13 +901,13 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf); REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); udelay(30); @@ -919,7 +919,6 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) regVal |= (1 << (19 + i)); REG_WRITE(ah, 0x7834, regVal); udelay(1); - regVal = REG_READ(ah, 0x7834); regVal &= (~(0x1 << (19 + i))); reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); regVal |= (reg_field << (19 + i)); -- cgit v0.10.2 From 20caf0dd4131d030c2a4099e2c2766ec7a5e83ea Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 26 Aug 2009 08:39:52 +0530 Subject: ath9k: Handle PA cal usage properly PA Calibration is not needed for high power solutions. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index f9de16c..3234995 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -879,6 +879,11 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); + /* PA CAL is not needed for high power solution */ + if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == + AR5416_EEP_TXGAIN_HIGH_POWER) + return; + if (AR_SREV_9285_11(ah)) { REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); udelay(10); -- cgit v0.10.2 From b264c673a03329b5e5bab79b705b5bb5ab1fe965 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 26 Aug 2009 08:39:55 +0530 Subject: ath9k: Update INITVALs for AR9285 Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index 27a86bb..8622265 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -4133,7 +4133,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e }, { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, @@ -4158,7 +4158,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 }, + { 0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f }, { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, @@ -4601,7 +4601,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00008258, 0x00000000 }, { 0x0000825c, 0x400000ff }, { 0x00008260, 0x00080922 }, - { 0x00008264, 0xa8a00010 }, + { 0x00008264, 0x88a00010 }, { 0x00008270, 0x00000000 }, { 0x00008274, 0x40000000 }, { 0x00008278, 0x003e4180 }, @@ -4650,7 +4650,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00009954, 0x5f3ca3de }, { 0x00009958, 0x2108ecff }, { 0x00009968, 0x000003ce }, - { 0x00009970, 0x192bb515 }, + { 0x00009970, 0x192bb514 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, { 0x0000997c, 0x00000000 }, @@ -4728,7 +4728,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00007800, 0x00140000 }, { 0x00007804, 0x0e4548d8 }, { 0x00007808, 0x54214514 }, - { 0x0000780c, 0x02025820 }, + { 0x0000780c, 0x02025830 }, { 0x00007810, 0x71c0d388 }, { 0x00007814, 0x924934a8 }, { 0x0000781c, 0x00000000 }, -- cgit v0.10.2 From 7cf4a2e778ab18c66cd8dd4785aceb2800d49f79 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 26 Aug 2009 11:11:57 +0530 Subject: ath9k: Wrap DMA dump function with PS wakeup/restore When dumping register contents, HW has to be awake. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 9e36920..2be4c22 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -93,6 +93,8 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, int i, qcuOffset = 0, dcuOffset = 0; u32 *qcuBase = &val[0], *dcuBase = &val[4]; + ath9k_ps_wakeup(sc); + REG_WRITE(ah, AR_MACMISC, ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | (AR_MACMISC_MISC_OBS_BUS_1 << @@ -159,6 +161,8 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, len += snprintf(buf + len, sizeof(buf) - len, "AR_CR: 0x%x \n", REG_READ(ah, AR_CR)); + ath9k_ps_restore(sc); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -- cgit v0.10.2 From 4a7f13eef508012bd1b0ffbb24b807e3494f31cd Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 26 Aug 2009 15:53:02 +0300 Subject: rndis_wlan: set cipher suites for cfg80211 rndis_wlan does not set cipher suites list for cfg80211 which causes wext-compat-range to report rndis_wlan not supporting WPA. Patch adds cipher suites list and fixes NetworkManager not being able to connect to WPA encrypted APs. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c5b921b..f181b00 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -413,6 +413,13 @@ static const struct ieee80211_rate rndis_rates[] = { { .bitrate = 540 } }; +static const u32 rndis_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + struct rndis_wlan_encr_key { int len; int cipher; @@ -441,6 +448,7 @@ struct rndis_wlan_private { struct ieee80211_supported_band band; struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; + u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; struct iw_statistics iwstats; struct iw_statistics privstats; @@ -2892,7 +2900,7 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) | BIT(NL80211_IFTYPE_ADHOC); wiphy->max_scan_ssids = 1; - /* TODO: fill-out band information based on priv->caps */ + /* TODO: fill-out band/encr information based on priv->caps */ rndis_wlan_get_caps(usbdev); memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); @@ -2904,6 +2912,11 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; + memcpy(priv->cipher_suites, rndis_cipher_suites, + sizeof(rndis_cipher_suites)); + wiphy->cipher_suites = priv->cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(rndis_cipher_suites); + set_wiphy_dev(wiphy, &usbdev->udev->dev); if (wiphy_register(wiphy)) { -- cgit v0.10.2 From f985ad12b595094839fddaf757fcf5d853ed3d7f Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:43 +0530 Subject: ath9k: Split ath9k_hw_btcoex_enable() into two logical pieces This function currently does initialization + enable the btcoex support. Split it into two logical functions which does the above operations separately. Btcoex initialization is done during attach time and enabling this feature is done in start(). Also, add code to disable btcoex support in stop(). Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7705da1..0868800 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -521,6 +521,7 @@ struct ath_led { #define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17) #define SC_OP_WAIT_FOR_TX_ACK BIT(18) #define SC_OP_BEACON_SYNC BIT(19) +#define SC_OP_BTCOEX_ENABLED BIT(20) struct ath_bus_ops { void (*read_cachesize)(struct ath_softc *sc, int *csz); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4f3d5ea..d81e826 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4073,7 +4073,7 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode) /* Bluetooth Coexistence */ /***************************/ -void ath9k_hw_btcoex_enable(struct ath_hw *ah) +void ath9k_hw_btcoex_init(struct ath_hw *ah) { /* connect bt_active to baseband */ REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, @@ -4090,8 +4090,23 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) /* Configure the desired gpio port for input */ ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio); +} +void ath9k_hw_btcoex_enable(struct ath_hw *ah) +{ /* Configure the desired GPIO port for TX_FRAME output */ ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); + + ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; +} + +void ath9k_hw_btcoex_disable(struct ath_hw *ah) +{ + ath9k_hw_set_gpio(ah, ah->wlanactive_gpio, 0); + + ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + + ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index b24150a..e634cb4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -614,6 +614,8 @@ bool ath9k_hw_intrpend(struct ath_hw *ah); bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); +void ath9k_hw_btcoex_init(struct ath_hw *ah); void ath9k_hw_btcoex_enable(struct ath_hw *ah); +void ath9k_hw_btcoex_disable(struct ath_hw *ah); #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index eb8d673..878d3be 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1509,8 +1509,8 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) ARRAY_SIZE(ath9k_5ghz_chantable); } - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) - ath9k_hw_btcoex_enable(sc->sc_ah); + if (ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) + ath9k_hw_btcoex_init(ah); return 0; bad2: @@ -1992,6 +1992,10 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) && + !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) + ath9k_hw_btcoex_enable(sc->sc_ah); + mutex_unlock: mutex_unlock(&sc->mutex); @@ -2138,6 +2142,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) wiphy_rfkill_stop_polling(sc->hw->wiphy); + if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) + ath9k_hw_btcoex_disable(sc->sc_ah); + /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); ath9k_hw_configpcipowersave(sc->sc_ah, 1); -- cgit v0.10.2 From 17d50d1df48631ae868958032edada7aa920636b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:44 +0530 Subject: ath9k: Move btcoex stuff from hw.[ch] to new btcoex.[ch] Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 28443e0..ff2c9a2 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -12,7 +12,8 @@ ath9k-y += hw.o \ recv.o \ xmit.o \ virtual.o \ - rc.o + rc.o \ + btcoex.o ath9k-$(CONFIG_PCI) += pci.o ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0868800..1a8d679 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -26,6 +26,7 @@ #include "rc.h" #include "debug.h" #include "../ath.h" +#include "btcoex.h" struct ath_node; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c new file mode 100644 index 0000000..abaf92d --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +void ath9k_hw_btcoex_init(struct ath_hw *ah) +{ + /* connect bt_active to baseband */ + REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, + (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | + AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); + + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); + + /* Set input mux for bt_active to gpio pin */ + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + ah->btactive_gpio); + + /* Configure the desired gpio port for input */ + ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio); +} + +void ath9k_hw_btcoex_enable(struct ath_hw *ah) +{ + /* Configure the desired GPIO port for TX_FRAME output */ + ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); + + ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; +} + +void ath9k_hw_btcoex_disable(struct ath_hw *ah) +{ + ath9k_hw_set_gpio(ah, ah->wlanactive_gpio, 0); + + ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + + ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; +} diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h new file mode 100644 index 0000000..9954280 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef BTCOEX_H +#define BTCOEX_H + +void ath9k_hw_btcoex_init(struct ath_hw *ah); +void ath9k_hw_btcoex_enable(struct ath_hw *ah); +void ath9k_hw_btcoex_disable(struct ath_hw *ah); + +#endif diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index d81e826..c3ecc7e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4068,45 +4068,3 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode) REG_WRITE(ah, AR_2040_MODE, macmode); } - -/***************************/ -/* Bluetooth Coexistence */ -/***************************/ - -void ath9k_hw_btcoex_init(struct ath_hw *ah) -{ - /* connect bt_active to baseband */ - REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, - (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | - AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); - - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); - - /* Set input mux for bt_active to gpio pin */ - REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, - AR_GPIO_INPUT_MUX1_BT_ACTIVE, - ah->btactive_gpio); - - /* Configure the desired gpio port for input */ - ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio); -} - -void ath9k_hw_btcoex_enable(struct ath_hw *ah) -{ - /* Configure the desired GPIO port for TX_FRAME output */ - ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); - - ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; -} - -void ath9k_hw_btcoex_disable(struct ath_hw *ah) -{ - ath9k_hw_set_gpio(ah, ah->wlanactive_gpio, 0); - - ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - - ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; -} diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e634cb4..32f7c4b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -614,8 +614,4 @@ bool ath9k_hw_intrpend(struct ath_hw *ah); bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); -void ath9k_hw_btcoex_init(struct ath_hw *ah); -void ath9k_hw_btcoex_enable(struct ath_hw *ah); -void ath9k_hw_btcoex_disable(struct ath_hw *ah); - #endif -- cgit v0.10.2 From 42cc41edf24b75fc6c37c99aed6e85455687e080 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:45 +0530 Subject: ath9k: Configure btcoex register during every reset Make sure btcoex register configured with appropriate values after it is initialized with the default values from initvals.h during reset. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c3ecc7e..d7e03f9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2555,6 +2555,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, #endif } + if (ah->ah_sc->sc_flags & SC_OP_BTCOEX_ENABLED) + ath9k_hw_btcoex_enable(ah); + return 0; } -- cgit v0.10.2 From f14462c6661c6b9e91d436f7ab66b35ed52ea703 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:46 +0530 Subject: ath9k: Move btcoex related data to a separate struct Also define macros for wlanactive and btactive (5 & 6) gpios. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1a8d679..83f2c8f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -611,6 +611,7 @@ struct ath_softc { struct ath_bus_ops *bus_ops; struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; + struct ath_btcoex_info btcoex_info; }; struct ath_wiphy { diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index abaf92d..9f19cd1 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -18,6 +18,8 @@ void ath9k_hw_btcoex_init(struct ath_hw *ah) { + struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + /* connect bt_active to baseband */ REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | @@ -29,16 +31,18 @@ void ath9k_hw_btcoex_init(struct ath_hw *ah) /* Set input mux for bt_active to gpio pin */ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, AR_GPIO_INPUT_MUX1_BT_ACTIVE, - ah->btactive_gpio); + btcoex_info->btactive_gpio); /* Configure the desired gpio port for input */ - ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio); + ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); } void ath9k_hw_btcoex_enable(struct ath_hw *ah) { + struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + /* Configure the desired GPIO port for TX_FRAME output */ - ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; @@ -46,9 +50,11 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) void ath9k_hw_btcoex_disable(struct ath_hw *ah) { - ath9k_hw_set_gpio(ah, ah->wlanactive_gpio, 0); + struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + + ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0); - ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 9954280..c80492b 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -17,6 +17,14 @@ #ifndef BTCOEX_H #define BTCOEX_H +#define ATH_WLANACTIVE_GPIO 5 +#define ATH_BTACTIVE_GPIO 6 + +struct ath_btcoex_info { + u8 wlanactive_gpio; + u8 btactive_gpio; +}; + void ath9k_hw_btcoex_init(struct ath_hw *ah); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index d7e03f9..3bb6abd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3666,8 +3666,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX; - ah->btactive_gpio = 6; - ah->wlanactive_gpio = 5; + ah->ah_sc->btcoex_info.btactive_gpio = ATH_BTACTIVE_GPIO; + ah->ah_sc->btcoex_info.wlanactive_gpio = ATH_WLANACTIVE_GPIO; } } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 32f7c4b..259936c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -414,8 +414,6 @@ struct ath_hw { u16 rfsilent; u32 rfkill_gpio; u32 rfkill_polarity; - u32 btactive_gpio; - u32 wlanactive_gpio; u32 ah_flags; bool htc_reset_init; -- cgit v0.10.2 From 22f25d0d5e146112d4ec464564ebb49a5b8a547b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:47 +0530 Subject: ath9k: Determine btcoex scheme type based on chip version Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index c80492b..cdfa80d 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -20,7 +20,14 @@ #define ATH_WLANACTIVE_GPIO 5 #define ATH_BTACTIVE_GPIO 6 +enum ath_btcoex_scheme { + ATH_BTCOEX_CFG_NONE, + ATH_BTCOEX_CFG_2WIRE, + ATH_BTCOEX_CFG_3WIRE, +}; + struct ath_btcoex_info { + enum ath_btcoex_scheme btcoex_scheme; u8 wlanactive_gpio; u8 btactive_gpio; }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 3bb6abd..7b4bc8b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3489,6 +3489,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; u16 capField = 0, eeval; @@ -3666,8 +3667,15 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX; - ah->ah_sc->btcoex_info.btactive_gpio = ATH_BTACTIVE_GPIO; - ah->ah_sc->btcoex_info.wlanactive_gpio = ATH_WLANACTIVE_GPIO; + btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; + btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; + + if (AR_SREV_9285(ah)) + btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE; + else + btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE; + } else { + btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE; } } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 878d3be..8a2f000 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1509,7 +1509,8 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) ARRAY_SIZE(ath9k_5ghz_chantable); } - if (ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) + if ((ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) && + (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE)) ath9k_hw_btcoex_init(ah); return 0; @@ -1993,6 +1994,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) && + (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) && !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) ath9k_hw_btcoex_enable(sc->sc_ah); -- cgit v0.10.2 From 81fa16fbe06cb3a4d29cc5a6f925132554521c72 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:48 +0530 Subject: ath9k: Remove hw capability bit meant for btcoex We don't need a hw cap bit for btcoex anymore as btcoex scheme type is enough to do this. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7b4bc8b..c80be8c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3666,7 +3666,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { - pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX; btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 259936c..de10de8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -151,7 +151,6 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_ENHANCEDPM = BIT(14), ATH9K_HW_CAP_AUTOSLEEP = BIT(15), ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16), - ATH9K_HW_CAP_BT_COEX = BIT(17) }; enum ath9k_capability_type { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 8a2f000..215c672 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -440,7 +440,7 @@ static void ath_start_ani(struct ath_softc *sc) void ath_update_chainmask(struct ath_softc *sc, int is_ht) { if ((sc->sc_flags & SC_OP_SCANNING) || is_ht || - (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) { + (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE)) { sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask; } else { @@ -1509,8 +1509,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) ARRAY_SIZE(ath9k_5ghz_chantable); } - if ((ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) && - (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE)) + if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) ath9k_hw_btcoex_init(ah); return 0; @@ -1993,8 +1992,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) && - (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) && + if ((sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) && !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) ath9k_hw_btcoex_enable(sc->sc_ah); -- cgit v0.10.2 From ff155a45cea56ad7a90c3f5192db59a4c7812fde Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:49 +0530 Subject: ath9k: Add infrastructure for generic hw timers Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 5e56b79..ea0dd1e 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -30,6 +30,7 @@ enum ATH_DEBUG { ATH_DBG_CONFIG = 0x00000200, ATH_DBG_FATAL = 0x00000400, ATH_DBG_PS = 0x00000800, + ATH_DBG_HWTIMER = 0x00001000, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c80be8c..3afd7a9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3215,6 +3215,23 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) if (AR_SREV_9100(ah)) return true; + if (isr & AR_ISR_GENTMR) { + u32 s5_s; + + s5_s = REG_READ(ah, AR_ISR_S5_S); + if (isr & AR_ISR_GENTMR) { + ah->intr_gen_timer_trigger = + MS(s5_s, AR_ISR_S5_GENTIMER_TRIG); + + ah->intr_gen_timer_thresh = + MS(s5_s, AR_ISR_S5_GENTIMER_THRESH); + + if (ah->intr_gen_timer_trigger) + *masked |= ATH9K_INT_GENTIMER; + + } + } + if (sync_cause) { fatal_int = (sync_cause & @@ -4078,3 +4095,198 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode) REG_WRITE(ah, AR_2040_MODE, macmode); } + +/* HW Generic timers configuration */ + +static const struct ath_gen_timer_configuration gen_tmr_configuration[] = +{ + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP2_TIMER, AR_NDP2_PERIOD, AR_NDP2_TIMER_MODE, 0x0001}, + {AR_NEXT_NDP2_TIMER + 1*4, AR_NDP2_PERIOD + 1*4, + AR_NDP2_TIMER_MODE, 0x0002}, + {AR_NEXT_NDP2_TIMER + 2*4, AR_NDP2_PERIOD + 2*4, + AR_NDP2_TIMER_MODE, 0x0004}, + {AR_NEXT_NDP2_TIMER + 3*4, AR_NDP2_PERIOD + 3*4, + AR_NDP2_TIMER_MODE, 0x0008}, + {AR_NEXT_NDP2_TIMER + 4*4, AR_NDP2_PERIOD + 4*4, + AR_NDP2_TIMER_MODE, 0x0010}, + {AR_NEXT_NDP2_TIMER + 5*4, AR_NDP2_PERIOD + 5*4, + AR_NDP2_TIMER_MODE, 0x0020}, + {AR_NEXT_NDP2_TIMER + 6*4, AR_NDP2_PERIOD + 6*4, + AR_NDP2_TIMER_MODE, 0x0040}, + {AR_NEXT_NDP2_TIMER + 7*4, AR_NDP2_PERIOD + 7*4, + AR_NDP2_TIMER_MODE, 0x0080} +}; + +/* HW generic timer primitives */ + +/* compute and clear index of rightmost 1 */ +static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) +{ + u32 b; + + b = *mask; + b &= (0-b); + *mask &= ~b; + b *= debruijn32; + b >>= 27; + + return timer_table->gen_timer_index[b]; +} + +static u32 ath9k_hw_gettsf32(struct ath_hw *ah) +{ + return REG_READ(ah, AR_TSF_L32); +} + +struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, + void (*trigger)(void *), + void (*overflow)(void *), + void *arg, + u8 timer_index) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + struct ath_gen_timer *timer; + + timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL); + + if (timer == NULL) { + printk(KERN_DEBUG "Failed to allocate memory" + "for hw timer[%d]\n", timer_index); + return NULL; + } + + /* allocate a hardware generic timer slot */ + timer_table->timers[timer_index] = timer; + timer->index = timer_index; + timer->trigger = trigger; + timer->overflow = overflow; + timer->arg = arg; + + return timer; +} + +void ath_gen_timer_start(struct ath_hw *ah, + struct ath_gen_timer *timer, + u32 timer_next, u32 timer_period) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + u32 tsf; + + BUG_ON(!timer_period); + + set_bit(timer->index, &timer_table->timer_mask.timer_bits); + + tsf = ath9k_hw_gettsf32(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, "curent tsf %x period %x" + "timer_next %x\n", tsf, timer_period, timer_next); + + /* + * Pull timer_next forward if the current TSF already passed it + * because of software latency + */ + if (timer_next < tsf) + timer_next = tsf + timer_period; + + /* + * Program generic timer registers + */ + REG_WRITE(ah, gen_tmr_configuration[timer->index].next_addr, + timer_next); + REG_WRITE(ah, gen_tmr_configuration[timer->index].period_addr, + timer_period); + REG_SET_BIT(ah, gen_tmr_configuration[timer->index].mode_addr, + gen_tmr_configuration[timer->index].mode_mask); + + /* Enable both trigger and thresh interrupt masks */ + REG_SET_BIT(ah, AR_IMR_S5, + (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | + SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); + + if ((ah->ah_sc->imask & ATH9K_INT_GENTIMER) == 0) { + ath9k_hw_set_interrupts(ah, 0); + ah->ah_sc->imask |= ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, ah->ah_sc->imask); + } +} + +void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + + if ((timer->index < AR_FIRST_NDP_TIMER) || + (timer->index >= ATH_MAX_GEN_TIMER)) { + return; + } + + /* Clear generic timer enable bits. */ + REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr, + gen_tmr_configuration[timer->index].mode_mask); + + /* Disable both trigger and thresh interrupt masks */ + REG_CLR_BIT(ah, AR_IMR_S5, + (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | + SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); + + clear_bit(timer->index, &timer_table->timer_mask.timer_bits); + + /* if no timer is enabled, turn off interrupt mask */ + if (timer_table->timer_mask.val == 0) { + ath9k_hw_set_interrupts(ah, 0); + ah->ah_sc->imask &= ~ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, ah->ah_sc->imask); + } +} + +void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + + /* free the hardware generic timer slot */ + timer_table->timers[timer->index] = NULL; + kfree(timer); +} + +/* + * Generic Timer Interrupts handling + */ +void ath_gen_timer_isr(struct ath_hw *ah) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + struct ath_gen_timer *timer; + u32 trigger_mask, thresh_mask, index; + + /* get hardware generic timer interrupt status */ + trigger_mask = ah->intr_gen_timer_trigger; + thresh_mask = ah->intr_gen_timer_thresh; + trigger_mask &= timer_table->timer_mask.val; + thresh_mask &= timer_table->timer_mask.val; + + trigger_mask &= ~thresh_mask; + + while (thresh_mask) { + index = rightmost_index(timer_table, &thresh_mask); + timer = timer_table->timers[index]; + BUG_ON(!timer); + DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, + "TSF overflow for Gen timer %d\n", index); + timer->overflow(timer->arg); + } + + while (trigger_mask) { + index = rightmost_index(timer_table, &trigger_mask); + timer = timer_table->timers[index]; + BUG_ON(!timer); + DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, + "Gen timer[%d] trigger\n", index); + timer->trigger(timer->arg); + } +} diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index de10de8..052a9c4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -237,6 +237,7 @@ enum ath9k_int { ATH9K_INT_GPIO = 0x01000000, ATH9K_INT_CABEND = 0x02000000, ATH9K_INT_TSFOOR = 0x04000000, + ATH9K_INT_GENTIMER = 0x08000000, ATH9K_INT_CST = 0x10000000, ATH9K_INT_GTT = 0x20000000, ATH9K_INT_FATAL = 0x40000000, @@ -390,6 +391,41 @@ struct ath9k_hw_version { u16 analog2GhzRev; }; +/* Generic TSF timer definitions */ + +#define ATH_MAX_GEN_TIMER 16 + +#define AR_GENTMR_BIT(_index) (1 << (_index)) + +/* + * Using de Bruijin sequence to to look up 1's index in a 32 bit number + * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001 + */ +#define debruijn32 0x077CB531UL + +struct ath_gen_timer_configuration { + u32 next_addr; + u32 period_addr; + u32 mode_addr; + u32 mode_mask; +}; + +struct ath_gen_timer { + void (*trigger)(void *arg); + void (*overflow)(void *arg); + void *arg; + u8 index; +}; + +struct ath_gen_timer_table { + u32 gen_timer_index[32]; + struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER]; + union { + unsigned long timer_bits; + u16 val; + } timer_mask; +}; + struct ath_hw { struct ath_softc *ah_sc; struct ath9k_hw_version hw_version; @@ -536,6 +572,10 @@ struct ath_hw { struct ar5416IniArray iniModesAdditional; struct ar5416IniArray iniModesRxGain; struct ar5416IniArray iniModesTxGain; + + u32 intr_gen_timer_trigger; + u32 intr_gen_timer_thresh; + struct ath_gen_timer_table hw_gen_timers; }; /* Initialization, Detach, Reset */ @@ -611,4 +651,16 @@ bool ath9k_hw_intrpend(struct ath_hw *ah); bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); +/* Generic hw timer primitives */ +struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, + void (*trigger)(void *), + void (*overflow)(void *), + void *arg, + u8 timer_index); +void ath_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, + u32 timer_next, u32 timer_period); +void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer); +void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); +void ath_gen_timer_isr(struct ath_hw *hw); + #endif diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index c9e1ac9..1d8e0a8 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -234,7 +234,15 @@ #define AR_IMR_S5 0x00b8 #define AR_IMR_S5_TIM_TIMER 0x00000010 #define AR_IMR_S5_DTIM_TIMER 0x00000020 - +#define AR_ISR_S5_GENTIMER_TRIG 0x0000FF80 +#define AR_ISR_S5_GENTIMER_TRIG_S 0 +#define AR_ISR_S5_GENTIMER_THRESH 0xFF800000 +#define AR_ISR_S5_GENTIMER_THRESH_S 16 +#define AR_ISR_S5_S 0x00d8 +#define AR_IMR_S5_GENTIMER_TRIG 0x0000FF80 +#define AR_IMR_S5_GENTIMER_TRIG_S 0 +#define AR_IMR_S5_GENTIMER_THRESH 0xFF800000 +#define AR_IMR_S5_GENTIMER_THRESH_S 16 #define AR_IMR 0x00a0 #define AR_IMR_RXOK 0x00000001 @@ -1516,7 +1524,10 @@ enum { #define AR_TXOP_8_11 0x81f8 #define AR_TXOP_12_15 0x81fc - +#define AR_NEXT_NDP2_TIMER 0x8180 +#define AR_FIRST_NDP_TIMER 7 +#define AR_NDP2_PERIOD 0x81a0 +#define AR_NDP2_TIMER_MODE 0x81c0 #define AR_NEXT_TBTT_TIMER 0x8200 #define AR_NEXT_DMA_BEACON_ALERT 0x8204 #define AR_NEXT_SWBA 0x8208 -- cgit v0.10.2 From 1773912bd25196c2a3ca6c174574561363f43b2b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:50 +0530 Subject: ath9k: Add Bluetooth Coexistence 3-wire support This patch adds 3-wire bluetooth coex support for AR9285. This support can be enabled through btcoex_enable modparam. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 83f2c8f..1c68a9d 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -523,6 +523,7 @@ struct ath_led { #define SC_OP_WAIT_FOR_TX_ACK BIT(18) #define SC_OP_BEACON_SYNC BIT(19) #define SC_OP_BTCOEX_ENABLED BIT(20) +#define SC_OP_BT_PRIORITY_DETECTED BIT(21) struct ath_bus_ops { void (*read_cachesize)(struct ath_softc *sc, int *csz); @@ -708,4 +709,5 @@ bool ath9k_all_wiphys_idle(struct ath_softc *sc); void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val); unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset); +int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 9f19cd1..8fb3567 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -16,34 +16,251 @@ #include "ath9k.h" -void ath9k_hw_btcoex_init(struct ath_hw *ah) +static const struct ath_btcoex_config ath_bt_config = { 0, true, true, + ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true }; + + +/* + * Detects if there is any priority bt traffic + */ +static void ath_detect_bt_priority(struct ath_softc *sc) +{ + struct ath_btcoex_info *btinfo = &sc->btcoex_info; + + if (ath9k_hw_gpio_get(sc->sc_ah, btinfo->btpriority_gpio)) + btinfo->bt_priority_cnt++; + + if (time_after(jiffies, btinfo->bt_priority_time + + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { + if (btinfo->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { + DPRINTF(sc, ATH_DBG_BTCOEX, + "BT priority traffic detected"); + sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; + } else { + sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; + } + + btinfo->bt_priority_cnt = 0; + btinfo->bt_priority_time = jiffies; + } +} + +/* + * Configures appropriate weight based on stomp type. + */ +static void ath_btcoex_bt_stomp(struct ath_softc *sc, + struct ath_btcoex_info *btinfo, + int stomp_type) +{ + + switch (stomp_type) { + case ATH_BTCOEX_STOMP_ALL: + ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + AR_STOMP_ALL_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_LOW: + ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_NONE: + ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + AR_STOMP_NONE_WLAN_WGHT); + break; + default: + DPRINTF(sc, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); + break; + } + + ath9k_hw_btcoex_enable(sc->sc_ah); +} + +/* + * This is the master bt coex timer which runs for every + * 45ms, bt traffic will be given priority during 55% of this + * period while wlan gets remaining 45% + */ + +static void ath_btcoex_period_timer(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *) data; + struct ath_btcoex_info *btinfo = &sc->btcoex_info; + unsigned long flags; + + ath_detect_bt_priority(sc); + + spin_lock_irqsave(&btinfo->btcoex_lock, flags); + + ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); + + spin_unlock_irqrestore(&btinfo->btcoex_lock, flags); + + if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) { + if (btinfo->hw_timer_enabled) + ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); + + ath_gen_timer_start(sc->sc_ah, + btinfo->no_stomp_timer, + (ath9k_hw_gettsf32(sc->sc_ah) + + btinfo->btcoex_no_stomp), + btinfo->btcoex_no_stomp * 10); + btinfo->hw_timer_enabled = true; + } + + mod_timer(&btinfo->period_timer, jiffies + + msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); +} + +/* + * Generic tsf based hw timer which configures weight + * registers to time slice between wlan and bt traffic + */ + +static void ath_btcoex_no_stomp_timer(void *arg) +{ + struct ath_softc *sc = (struct ath_softc *)arg; + struct ath_btcoex_info *btinfo = &sc->btcoex_info; + unsigned long flags; + + DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n"); + + spin_lock_irqsave(&btinfo->btcoex_lock, flags); + + if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) + ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); + else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) + ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); + + spin_unlock_irqrestore(&btinfo->btcoex_lock, flags); +} + +static int ath_init_btcoex_info(struct ath_hw *hw, + struct ath_btcoex_info *btcoex_info) +{ + u32 i; + int qnum; + + qnum = ath_tx_get_qnum(hw->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); + + btcoex_info->bt_coex_mode = + (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) | + SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) | + SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) | + SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | + SM(ath_bt_config.bt_mode, AR_BT_MODE) | + SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) | + SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | + SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) | + SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | + SM(qnum, AR_BT_QCU_THRESH); + + btcoex_info->bt_coex_mode2 = + SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) | + SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | + AR_BT_DISABLE_BT_ANT; + + btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + + btcoex_info->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; + + btcoex_info->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * + btcoex_info->btcoex_period / 100; + + for (i = 0; i < 32; i++) + hw->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; + + setup_timer(&btcoex_info->period_timer, ath_btcoex_period_timer, + (unsigned long) hw->ah_sc); + + btcoex_info->no_stomp_timer = ath_gen_timer_alloc(hw, + ath_btcoex_no_stomp_timer, + ath_btcoex_no_stomp_timer, + (void *)hw->ah_sc, AR_FIRST_NDP_TIMER); + + if (btcoex_info->no_stomp_timer == NULL) + return -ENOMEM; + + spin_lock_init(&btcoex_info->btcoex_lock); + + return 0; +} + +int ath9k_hw_btcoex_init(struct ath_hw *ah) { struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + int ret = 0; + + if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { + /* connect bt_active to baseband */ + REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, + (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | + AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); + + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); + + /* Set input mux for bt_active to gpio pin */ + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + btcoex_info->btactive_gpio); - /* connect bt_active to baseband */ - REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, - (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | - AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); + /* Configure the desired gpio port for input */ + ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); + } else { + /* btcoex 3-wire */ + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB | + AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB)); - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); + /* Set input mux for bt_prority_async and + * bt_active_async to GPIO pins */ + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + btcoex_info->btactive_gpio); - /* Set input mux for bt_active to gpio pin */ - REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, - AR_GPIO_INPUT_MUX1_BT_ACTIVE, - btcoex_info->btactive_gpio); + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_PRIORITY, + btcoex_info->btpriority_gpio); - /* Configure the desired gpio port for input */ - ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); + /* Configure the desired GPIO ports for input */ + + ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); + ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio); + + ret = ath_init_btcoex_info(ah, btcoex_info); + } + + return ret; } void ath9k_hw_btcoex_enable(struct ath_hw *ah) { struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; - /* Configure the desired GPIO port for TX_FRAME output */ - ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); + if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { + /* Configure the desired GPIO port for TX_FRAME output */ + ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); + } else { + /* + * Program coex mode and weight registers to + * enable coex 3-wire + */ + REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode); + REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights); + REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2); + + REG_RMW_FIELD(ah, AR_QUIET1, + AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); + REG_RMW_FIELD(ah, AR_PCU_MISC, + AR_PCU_BT_ANT_PREVENT_RX, 0); + + ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL); + } + + REG_RMW(ah, AR_GPIO_PDPU, + (0x2 << (btcoex_info->btactive_gpio * 2)), + (0x3 << (btcoex_info->btactive_gpio * 2))); ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; } @@ -57,5 +274,46 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) { + REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); + REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); + REG_WRITE(ah, AR_BT_COEX_MODE2, 0); + } + ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; } + +/* + * Pause btcoex timer and bt duty cycle timer + */ +void ath_btcoex_timer_pause(struct ath_softc *sc, + struct ath_btcoex_info *btinfo) +{ + + del_timer_sync(&btinfo->period_timer); + + if (btinfo->hw_timer_enabled) + ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); + + btinfo->hw_timer_enabled = false; +} + +/* + * (Re)start btcoex timers + */ +void ath_btcoex_timer_resume(struct ath_softc *sc, + struct ath_btcoex_info *btinfo) +{ + + DPRINTF(sc, ATH_DBG_BTCOEX, "Starting btcoex timers"); + + /* make sure duty cycle timer is also stopped when resuming */ + if (btinfo->hw_timer_enabled) + ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); + + btinfo->bt_priority_cnt = 0; + btinfo->bt_priority_time = jiffies; + sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; + + mod_timer(&btinfo->period_timer, jiffies); +} diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index cdfa80d..4556819 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -20,20 +20,79 @@ #define ATH_WLANACTIVE_GPIO 5 #define ATH_BTACTIVE_GPIO 6 +#define ATH_BTCOEX_DEF_BT_PERIOD 45 +#define ATH_BTCOEX_DEF_DUTY_CYCLE 55 +#define ATH_BTCOEX_BMISS_THRESH 50 + +#define ATH_BT_PRIORITY_TIME_THRESHOLD 1000 /* ms */ +#define ATH_BT_CNT_THRESHOLD 3 + enum ath_btcoex_scheme { ATH_BTCOEX_CFG_NONE, ATH_BTCOEX_CFG_2WIRE, ATH_BTCOEX_CFG_3WIRE, }; +enum ath_stomp_type { + ATH_BTCOEX_NO_STOMP, + ATH_BTCOEX_STOMP_ALL, + ATH_BTCOEX_STOMP_LOW, + ATH_BTCOEX_STOMP_NONE +}; + +enum ath_bt_mode { + ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */ + ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */ + ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */ + ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */ +}; + +struct ath_btcoex_config { + u8 bt_time_extend; + bool bt_txstate_extend; + bool bt_txframe_extend; + enum ath_bt_mode bt_mode; /* coexistence mode */ + bool bt_quiet_collision; + bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/ + u8 bt_priority_time; + u8 bt_first_slot_time; + bool bt_hold_rx_clear; +}; + struct ath_btcoex_info { enum ath_btcoex_scheme btcoex_scheme; u8 wlanactive_gpio; u8 btactive_gpio; + u8 btpriority_gpio; + u8 bt_duty_cycle; /* BT duty cycle in percentage */ + int bt_stomp_type; /* Types of BT stomping */ + u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */ + u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */ + u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ + u32 btcoex_no_stomp; /* in usec */ + u32 btcoex_period; /* in usec */ + u32 bt_priority_cnt; + unsigned long bt_priority_time; + bool hw_timer_enabled; + spinlock_t btcoex_lock; + struct timer_list period_timer; /* Timer for BT period */ + struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/ }; -void ath9k_hw_btcoex_init(struct ath_hw *ah); +int ath9k_hw_btcoex_init(struct ath_hw *ah); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); +void ath_btcoex_timer_resume(struct ath_softc *sc, + struct ath_btcoex_info *btinfo); +void ath_btcoex_timer_pause(struct ath_softc *sc, + struct ath_btcoex_info *btinfo); + +static inline void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info, + u32 bt_weight, + u32 wlan_weight) +{ + btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | + SM(wlan_weight, AR_BTCOEX_WL_WGHT); +} #endif diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index ea0dd1e..7241f47 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -31,6 +31,7 @@ enum ATH_DEBUG { ATH_DBG_FATAL = 0x00000400, ATH_DBG_PS = 0x00000800, ATH_DBG_HWTIMER = 0x00001000, + ATH_DBG_BTCOEX = 0x00002000, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 3afd7a9..e340dac 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4141,7 +4141,7 @@ static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) return timer_table->gen_timer_index[b]; } -static u32 ath9k_hw_gettsf32(struct ath_hw *ah) +u32 ath9k_hw_gettsf32(struct ath_hw *ah) { return REG_READ(ah, AR_TSF_L32); } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 052a9c4..5ca6ffa7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -79,6 +79,7 @@ #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 #define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 #define AR_GPIO_OUTPUT_MUX_AS_TX_FRAME 3 +#define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL 4 #define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 #define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 @@ -662,5 +663,6 @@ void ath_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_isr(struct ath_hw *hw); +u32 ath9k_hw_gettsf32(struct ath_hw *ah); #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 215c672..4fae699 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -602,6 +602,10 @@ irqreturn_t ath_isr(int irq, void *dev) sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; } + if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + if (status & ATH9K_INT_GENTIMER) + ath_gen_timer_isr(ah); + chip_reset: ath_debug_stat_interrupt(sc, status); @@ -1279,6 +1283,10 @@ void ath_detach(struct ath_softc *sc) if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); + if ((sc->btcoex_info.no_stomp_timer) && + sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + ath_gen_timer_free(sc->sc_ah, sc->btcoex_info.no_stomp_timer); + ath9k_hw_detach(sc->sc_ah); sc->sc_ah = NULL; ath9k_exit_debug(sc); @@ -1509,8 +1517,11 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) ARRAY_SIZE(ath9k_5ghz_chantable); } - if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) - ath9k_hw_btcoex_init(ah); + if (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) { + r = ath9k_hw_btcoex_init(ah); + if (r) + goto bad2; + } return 0; bad2: @@ -1992,10 +2003,16 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); - if ((sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) && - !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) + if ((sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) && + !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) { + ath_btcoex_set_weight(&sc->btcoex_info, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); ath9k_hw_btcoex_enable(sc->sc_ah); + if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + ath_btcoex_timer_resume(sc, &sc->btcoex_info); + } + mutex_unlock: mutex_unlock(&sc->mutex); @@ -2129,6 +2146,12 @@ static void ath9k_stop(struct ieee80211_hw *hw) return; /* another wiphy still in use */ } + if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) { + ath9k_hw_btcoex_disable(sc->sc_ah); + if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + ath_btcoex_timer_pause(sc, &sc->btcoex_info); + } + /* make sure h/w will not generate any interrupt * before setting the invalid flag. */ ath9k_hw_set_interrupts(sc->sc_ah, 0); @@ -2142,9 +2165,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) wiphy_rfkill_stop_polling(sc->hw->wiphy); - if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) - ath9k_hw_btcoex_disable(sc->sc_ah); - /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); ath9k_hw_configpcipowersave(sc->sc_ah, 1); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 1d8e0a8..3ddb243 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -970,6 +970,8 @@ enum { #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7 #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000 #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00001000 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 1 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15 #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 @@ -978,6 +980,8 @@ enum { #define AR_GPIO_INPUT_MUX1 0x4058 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16 +#define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00 +#define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8 #define AR_GPIO_INPUT_MUX2 0x405c #define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f @@ -1003,6 +1007,8 @@ enum { #define AR_OBS 0x4080 +#define AR_GPIO_PDPU 0x4088 + #define AR_PCIE_MSI 0x4094 #define AR_PCIE_MSI_ENABLE 0x00000001 @@ -1436,6 +1442,7 @@ enum { #define AR_QUIET1_NEXT_QUIET_M 0x0000ffff #define AR_QUIET1_QUIET_ENABLE 0x00010000 #define AR_QUIET1_QUIET_ACK_CTS_ENABLE 0x00020000 +#define AR_QUIET1_QUIET_ACK_CTS_ENABLE_S 17 #define AR_QUIET2 0x8100 #define AR_QUIET2_QUIET_PERIOD_S 0 #define AR_QUIET2_QUIET_PERIOD_M 0x0000ffff @@ -1481,6 +1488,8 @@ enum { #define AR_PCU_CLEAR_VMF 0x01000000 #define AR_PCU_CLEAR_BA_VALID 0x04000000 +#define AR_PCU_BT_ANT_PREVENT_RX 0x00100000 +#define AR_PCU_BT_ANT_PREVENT_RX_S 20 #define AR_FILT_OFDM 0x8124 #define AR_FILT_OFDM_COUNT 0x00FFFFFF @@ -1508,6 +1517,46 @@ enum { #define AR_PHY_ERR_3_COUNT 0x00FFFFFF #define AR_PHY_ERR_MASK_3 0x816c +#define AR_BT_COEX_MODE 0x8170 +#define AR_BT_TIME_EXTEND 0x000000ff +#define AR_BT_TIME_EXTEND_S 0 +#define AR_BT_TXSTATE_EXTEND 0x00000100 +#define AR_BT_TXSTATE_EXTEND_S 8 +#define AR_BT_TX_FRAME_EXTEND 0x00000200 +#define AR_BT_TX_FRAME_EXTEND_S 9 +#define AR_BT_MODE 0x00000c00 +#define AR_BT_MODE_S 10 +#define AR_BT_QUIET 0x00001000 +#define AR_BT_QUIET_S 12 +#define AR_BT_QCU_THRESH 0x0001e000 +#define AR_BT_QCU_THRESH_S 13 +#define AR_BT_RX_CLEAR_POLARITY 0x00020000 +#define AR_BT_RX_CLEAR_POLARITY_S 17 +#define AR_BT_PRIORITY_TIME 0x00fc0000 +#define AR_BT_PRIORITY_TIME_S 18 +#define AR_BT_FIRST_SLOT_TIME 0xff000000 +#define AR_BT_FIRST_SLOT_TIME_S 24 + +#define AR_BT_COEX_WEIGHT 0x8174 +#define AR_BT_COEX_WGHT 0xff55 +#define AR_STOMP_ALL_WLAN_WGHT 0xffcc +#define AR_STOMP_LOW_WLAN_WGHT 0xaaa8 +#define AR_STOMP_NONE_WLAN_WGHT 0xaa00 +#define AR_BTCOEX_BT_WGHT 0x0000ffff +#define AR_BTCOEX_BT_WGHT_S 0 +#define AR_BTCOEX_WL_WGHT 0xffff0000 +#define AR_BTCOEX_WL_WGHT_S 16 + +#define AR_BT_COEX_MODE2 0x817c +#define AR_BT_BCN_MISS_THRESH 0x000000ff +#define AR_BT_BCN_MISS_THRESH_S 0 +#define AR_BT_BCN_MISS_CNT 0x0000ff00 +#define AR_BT_BCN_MISS_CNT_S 8 +#define AR_BT_HOLD_RX_CLEAR 0x00010000 +#define AR_BT_HOLD_RX_CLEAR_S 16 +#define AR_BT_DISABLE_BT_ANT 0x00100000 +#define AR_BT_DISABLE_BT_ANT_S 20 + #define AR_TXSIFS 0x81d0 #define AR_TXSIFS_TIME 0x000000FF #define AR_TXSIFS_TX_LATENCY 0x00000F00 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 87762da..42551a4 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -493,7 +493,12 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) return 0; - aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX); + if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED) + aggr_limit = min((max_4ms_framelen * 3) / 8, + (u32)ATH_AMPDU_LIMIT_MAX); + else + aggr_limit = min(max_4ms_framelen, + (u32)ATH_AMPDU_LIMIT_MAX); /* * h/w can accept aggregates upto 16 bit lengths (65535). @@ -872,7 +877,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) return &sc->tx.txq[qnum]; } -static int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) +int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) { int qnum; -- cgit v0.10.2 From 6a8171f261eec3577c2a5985e3a2b51377e48931 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Wed, 26 Aug 2009 13:54:08 -0300 Subject: rtl8187: fix circular locking (rtl8187_stop/rtl8187_work) Larry Finger reports following lockdep warning: [ INFO: possible circular locking dependency detected ] 2.6.31-rc6-wl #201 ------------------------------------------------------- rfkill/30578 is trying to acquire lock: (&(&priv->work)->work#2){+.+...}, at: [] __cancel_work_timer+0xd9/0x222 but task is already holding lock: (&priv->conf_mutex#2){+.+.+.}, at: [] rtl8187_stop+0x31/0x364 [rtl8187] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&priv->conf_mutex#2){+.+.+.}: [] __lock_acquire+0x12d0/0x1614 [] lock_acquire+0xb9/0xdd [] mutex_lock_nested+0x56/0x2a8 [] rtl8187_work+0x3b/0xf2 [rtl8187] [] worker_thread+0x1fa/0x30a [] kthread+0x8f/0x97 [] child_rip+0xa/0x20 [] 0xffffffffffffffff -> #0 (&(&priv->work)->work#2){+.+...}: [] __lock_acquire+0x1005/0x1614 [] lock_acquire+0xb9/0xdd [] __cancel_work_timer+0x112/0x222 [] cancel_delayed_work_sync+0xd/0xf [] rtl8187_stop+0x34c/0x364 [rtl8187] [] ieee80211_stop_device+0x29/0x61 [mac80211] [] ieee80211_stop+0x476/0x530 [mac80211] [] dev_close+0x8a/0xac [] cfg80211_rfkill_set_block+0x4a/0x7a [cfg80211] [] rfkill_set_block+0x84/0xd9 [rfkill] [] rfkill_fop_write+0xda/0x124 [rfkill] [] vfs_write+0xae/0x14a [] sys_write+0x47/0x6e [] system_call_fastpath+0x16/0x1b [] 0xffffffffffffffff The problem here is that rtl8187_stop, while helding priv->conf_mutex, runs cancel_delayed_work_sync on an workqueue that runs rtl8187_work, which also takes priv->conf_mutex lock. Move cancel_delayed_work_sync out of rtl8187_stop priv->conf_mutex locking region. Reported-by: Larry Finger Tested-by: Larry Finger Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 90f3835..5573e34 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1014,9 +1014,10 @@ static void rtl8187_stop(struct ieee80211_hw *dev) dev_kfree_skb_any(skb); usb_kill_anchored_urbs(&priv->anchored); + mutex_unlock(&priv->conf_mutex); + if (!priv->is_rtl8187b) cancel_delayed_work_sync(&priv->work); - mutex_unlock(&priv->conf_mutex); } static int rtl8187_add_interface(struct ieee80211_hw *dev, -- cgit v0.10.2 From ca9152e37f57259ca92486ca5753af16fd9155c6 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Wed, 26 Aug 2009 13:54:09 -0300 Subject: rtl8187: Implement rfkill support This change implements rfkill support for RTL8187B and RTL8187L devices, using new cfg80211 rfkill API. Acked-by: Larry Finger Tested-by: Hin-Tak Leung Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile index 37e3d4d..93cbfbe 100644 --- a/drivers/net/wireless/rtl818x/Makefile +++ b/drivers/net/wireless/rtl818x/Makefile @@ -1,5 +1,5 @@ rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o -rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o +rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o rtl8187_rfkill.o obj-$(CONFIG_RTL8180) += rtl8180.o obj-$(CONFIG_RTL8187) += rtl8187.o diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h index c09bfef..bf9175a 100644 --- a/drivers/net/wireless/rtl818x/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -133,6 +133,7 @@ struct rtl8187_priv { __le16 bits16; __le32 bits32; } *io_dmabuf; + bool rfkill_off; }; void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 5573e34..9679b29 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -32,6 +32,7 @@ #ifdef CONFIG_RTL8187_LEDS #include "rtl8187_leds.h" #endif +#include "rtl8187_rfkill.h" MODULE_AUTHOR("Michael Wu "); MODULE_AUTHOR("Andrea Merello "); @@ -648,10 +649,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) /* setup card */ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 0); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); - rtl818x_iowrite8(priv, &priv->map->GPIO, 1); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 1); rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); @@ -674,11 +675,11 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) /* host_usb_init */ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 0); reg = rtl818x_ioread8(priv, (u8 *)0xFE53); rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7)); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x20); rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80); @@ -907,12 +908,12 @@ static int rtl8187_start(struct ieee80211_hw *dev) u32 reg; int ret; + mutex_lock(&priv->conf_mutex); + ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) : rtl8187b_init_hw(dev); if (ret) - return ret; - - mutex_lock(&priv->conf_mutex); + goto rtl8187_start_exit; init_usb_anchor(&priv->anchored); priv->dev = dev; @@ -939,8 +940,7 @@ static int rtl8187_start(struct ieee80211_hw *dev) (7 << 21 /* MAX TX DMA */)); rtl8187_init_urbs(dev); rtl8187b_init_status_urb(dev); - mutex_unlock(&priv->conf_mutex); - return 0; + goto rtl8187_start_exit; } rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); @@ -984,9 +984,10 @@ static int rtl8187_start(struct ieee80211_hw *dev) reg |= RTL818X_CMD_RX_ENABLE; rtl818x_iowrite8(priv, &priv->map->CMD, reg); INIT_DELAYED_WORK(&priv->work, rtl8187_work); - mutex_unlock(&priv->conf_mutex); - return 0; +rtl8187_start_exit: + mutex_unlock(&priv->conf_mutex); + return ret; } static void rtl8187_stop(struct ieee80211_hw *dev) @@ -1277,7 +1278,8 @@ static const struct ieee80211_ops rtl8187_ops = { .bss_info_changed = rtl8187_bss_info_changed, .prepare_multicast = rtl8187_prepare_multicast, .configure_filter = rtl8187_configure_filter, - .conf_tx = rtl8187_conf_tx + .conf_tx = rtl8187_conf_tx, + .rfkill_poll = rtl8187_rfkill_poll }; static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) @@ -1517,6 +1519,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, reg &= 0xFF; rtl8187_leds_init(dev, reg); #endif + rtl8187_rfkill_init(dev); return 0; @@ -1540,6 +1543,7 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf) #ifdef CONFIG_RTL8187_LEDS rtl8187_leds_exit(dev); #endif + rtl8187_rfkill_exit(dev); ieee80211_unregister_hw(dev); priv = dev->priv; diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c index a6cfb7e..a1c670f 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_leds.c +++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c @@ -42,7 +42,7 @@ static void led_turn_on(struct work_struct *work) mutex_lock(&priv->conf_mutex); switch (led->ledpin) { case LED_PIN_GPIO0: - rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01); rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00); break; case LED_PIN_LED0: @@ -80,7 +80,7 @@ static void led_turn_off(struct work_struct *work) mutex_lock(&priv->conf_mutex); switch (led->ledpin) { case LED_PIN_GPIO0: - rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01); rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01); break; case LED_PIN_LED0: diff --git a/drivers/net/wireless/rtl818x/rtl8187_rfkill.c b/drivers/net/wireless/rtl818x/rtl8187_rfkill.c new file mode 100644 index 0000000..9fab13e --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_rfkill.c @@ -0,0 +1,63 @@ +/* + * Linux RFKILL support for RTL8187 + * + * Copyright (c) 2009 Herton Ronaldo Krzesinski + * + * Based on the RFKILL handling in the r8187 driver, which is: + * Copyright (c) Realtek Semiconductor Corp. All rights reserved. + * + * Thanks to Realtek for their support! + * + * 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include "rtl8187.h" + +static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) +{ + u8 gpio; + + gpio = rtl818x_ioread8(priv, &priv->map->GPIO0); + rtl818x_iowrite8(priv, &priv->map->GPIO0, gpio & ~0x02); + gpio = rtl818x_ioread8(priv, &priv->map->GPIO1); + + return gpio & 0x02; +} + +void rtl8187_rfkill_init(struct ieee80211_hw *hw) +{ + struct rtl8187_priv *priv = hw->priv; + + priv->rfkill_off = rtl8187_is_radio_enabled(priv); + printk(KERN_INFO "rtl8187: wireless switch is %s\n", + priv->rfkill_off ? "on" : "off"); + wiphy_rfkill_set_hw_state(hw->wiphy, !priv->rfkill_off); + wiphy_rfkill_start_polling(hw->wiphy); +} + +void rtl8187_rfkill_poll(struct ieee80211_hw *hw) +{ + bool enabled; + struct rtl8187_priv *priv = hw->priv; + + mutex_lock(&priv->conf_mutex); + enabled = rtl8187_is_radio_enabled(priv); + if (unlikely(enabled != priv->rfkill_off)) { + priv->rfkill_off = enabled; + printk(KERN_INFO "rtl8187: wireless radio switch turned %s\n", + enabled ? "on" : "off"); + wiphy_rfkill_set_hw_state(hw->wiphy, !enabled); + } + mutex_unlock(&priv->conf_mutex); +} + +void rtl8187_rfkill_exit(struct ieee80211_hw *hw) +{ + wiphy_rfkill_stop_polling(hw->wiphy); +} diff --git a/drivers/net/wireless/rtl818x/rtl8187_rfkill.h b/drivers/net/wireless/rtl818x/rtl8187_rfkill.h new file mode 100644 index 0000000..e12575e --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_rfkill.h @@ -0,0 +1,8 @@ +#ifndef RTL8187_RFKILL_H +#define RTL8187_RFKILL_H + +void rtl8187_rfkill_init(struct ieee80211_hw *hw); +void rtl8187_rfkill_poll(struct ieee80211_hw *hw); +void rtl8187_rfkill_exit(struct ieee80211_hw *hw); + +#endif /* RTL8187_RFKILL_H */ diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h index 562222e..8522490 100644 --- a/drivers/net/wireless/rtl818x/rtl818x.h +++ b/drivers/net/wireless/rtl818x/rtl818x.h @@ -138,8 +138,9 @@ struct rtl818x_csr { __le32 RF_PARA; __le32 RF_TIMING; u8 GP_ENABLE; - u8 GPIO; - u8 reserved_12[2]; + u8 GPIO0; + u8 GPIO1; + u8 reserved_12; __le32 HSSI_PARA; u8 reserved_13[4]; u8 TX_AGC_CTL; -- cgit v0.10.2 From d8fa338ee01e7de029d2441a8c2b9c5fbfeac82f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Wed, 26 Aug 2009 20:51:24 +0200 Subject: b43: LP-PHY: Fix and simplify Qdiv roundup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Qdiv roundup routine is essentially a fixed-point division algorithm, using only integer math. However, the version in the specs had a major error that has been recently fixed (a missing quotient++). Replace Qdiv roundup with a rewritten, simplified version. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 7e70c07..5306f2c 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1032,9 +1032,10 @@ static int lpphy_loopback(struct b43_wldev *dev) return index; } +/* Fixed-point division algorithm using only integer math. */ static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) { - u32 quotient, remainder, rbit, roundup, tmp; + u32 quotient, remainder; if (divisor == 0) return 0; @@ -1042,20 +1043,16 @@ static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) quotient = dividend / divisor; remainder = dividend % divisor; - rbit = divisor & 0x1; - roundup = (divisor >> 1) + rbit; - - while (precision != 0) { - tmp = remainder - roundup; + while (precision > 0) { quotient <<= 1; - if (remainder >= roundup) - remainder = (tmp << 1) + rbit; - else - remainder <<= 1; + if (remainder << 1 >= divisor) { + quotient++; + remainder = (remainder << 1) - divisor; + } precision--; } - if (remainder >= roundup) + if (remainder << 1 >= divisor) quotient++; return quotient; -- cgit v0.10.2 From 68ec53292c7f09056152efa9a6ee2591c794f08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Wed, 26 Aug 2009 20:51:25 +0200 Subject: b43: Fix and update LP-PHY code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Fix a few nasty typos (b43_phy_* operations instead of b43_radio_*) in the channel tune routines. -Fix some typos & spec errors found by MMIO tracing. -Optimize b43_phy_write & b43_phy_mask/set/maskset to use only the minimal number of MMIO accesses. (Write is possible using a single 32-bit MMIO write, while set/mask/maskset can be done in 3 16-bit MMIOs). -Set the default channel back to 1, as the bug forcing us to use channel 7 is now fixed. With this, the device comes up, scans, associates, transmits, receives, monitors and injects on all channels - in other words, it's fully functional. Sensitivity and TX power are still sub-optimal, due to the lack of calibration (that's next on my list). Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 51686ec..6e704be 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -249,20 +249,35 @@ void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg) void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) { - b43_phy_write(dev, offset, - b43_phy_read(dev, offset) & mask); + if (dev->phy.ops->phy_maskset) { + assert_mac_suspended(dev); + dev->phy.ops->phy_maskset(dev, offset, mask, 0); + } else { + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) & mask); + } } void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set) { - b43_phy_write(dev, offset, - b43_phy_read(dev, offset) | set); + if (dev->phy.ops->phy_maskset) { + assert_mac_suspended(dev); + dev->phy.ops->phy_maskset(dev, offset, 0xFFFF, set); + } else { + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) | set); + } } void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) { - b43_phy_write(dev, offset, - (b43_phy_read(dev, offset) & mask) | set); + if (dev->phy.ops->phy_maskset) { + assert_mac_suspended(dev); + dev->phy.ops->phy_maskset(dev, offset, mask, set); + } else { + b43_phy_write(dev, offset, + (b43_phy_read(dev, offset) & mask) | set); + } } int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel) diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 9f9f23c..b47a0f5 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -95,6 +95,8 @@ enum b43_txpwr_result { * Must not be NULL. * @phy_write: Write to a PHY register. * Must not be NULL. + * @phy_maskset: Maskset a PHY register, taking shortcuts. + * If it is NULL, a generic algorithm is used. * @radio_read: Read from a Radio register. * Must not be NULL. * @radio_write: Write to a Radio register. @@ -154,6 +156,7 @@ struct b43_phy_operations { /* Register access */ u16 (*phy_read)(struct b43_wldev *dev, u16 reg); void (*phy_write)(struct b43_wldev *dev, u16 reg, u16 value); + void (*phy_maskset)(struct b43_wldev *dev, u16 reg, u16 mask, u16 set); u16 (*radio_read)(struct b43_wldev *dev, u16 reg); void (*radio_write)(struct b43_wldev *dev, u16 reg, u16 value); diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 5306f2c..1a57d33 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -44,7 +44,7 @@ static inline u16 channel2freq_lp(u8 channel) static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) { if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - return 7; //FIXME temporary - channel 1 is broken + return 1; return 36; } @@ -182,8 +182,8 @@ static void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq) temp[1] = temp[0] + 0x1000; temp[2] = temp[0] + 0x2000; - b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp); b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp); + b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp); } static void lpphy_table_init(struct b43_wldev *dev) @@ -223,8 +223,8 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006); b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE); b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005); - b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC10, 0x0180); - b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3800); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0x0180); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3C00); b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005); b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A); b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3); @@ -237,7 +237,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) /* TODO: * Set the LDO voltage to 0x0028 - FIXME: What is this? * Call sb_pmu_set_ldo_voltage with 4 and the LDO voltage - * as arguments + * as arguments * Call sb_pmu_paref_ldo_enable with argument TRUE */ if (dev->phy.rev == 0) { @@ -340,11 +340,11 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) if (dev->phy.rev == 1) { tmp = b43_phy_read(dev, B43_LPPHY_CLIPCTRTHRESH); tmp2 = (tmp & 0x03E0) >> 5; - tmp2 |= tmp << 5; + tmp2 |= tmp2 << 5; b43_phy_write(dev, B43_LPPHY_4C3, tmp2); - tmp = b43_phy_read(dev, B43_LPPHY_OFDMSYNCTHRESH0); + tmp = b43_phy_read(dev, B43_LPPHY_GAINDIRECTMISMATCH); tmp2 = (tmp & 0x1F00) >> 8; - tmp2 |= tmp << 5; + tmp2 |= tmp2 << 5; b43_phy_write(dev, B43_LPPHY_4C4, tmp2); tmp = b43_phy_read(dev, B43_LPPHY_VERYLOWGAINDB); tmp2 = tmp & 0x00FF; @@ -761,7 +761,7 @@ static void lpphy_disable_crs(struct b43_wldev *dev, bool user) b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4); - b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFF7); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10); @@ -956,7 +956,7 @@ static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on, b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5); b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB); b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2); - b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x20); + b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x20); } static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time, @@ -968,7 +968,7 @@ static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time, b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples); b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time); b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF); - b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFDFF); + b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200); for (i = 0; i < 500; i++) { if (!(b43_phy_read(dev, @@ -1135,9 +1135,9 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev, } if (dev->phy.rev >= 2) { if (mode == B43_LPPHY_TXPCTL_HW) - b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0x2); + b43_phy_set(dev, B43_PHY_OFDM(0xD0), 0x2); else - b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0); + b43_phy_mask(dev, B43_PHY_OFDM(0xD0), 0xFFFD); } lpphy_write_tx_pctl_mode_to_hardware(dev); } @@ -1169,7 +1169,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) err = b43_lpphy_op_switch_channel(dev, 7); if (err) { b43dbg(dev->wl, - "RC calib: Failed to switch to channel 7, error = %d", + "RC calib: Failed to switch to channel 7, error = %d\n", err); } old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40); @@ -1500,8 +1500,15 @@ static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) { + b43_write32(dev, B43_MMIO_PHY_CONTROL, ((u32)value << 16) | reg); +} + +static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, + u16 set) +{ b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - b43_write16(dev, B43_MMIO_PHY_DATA, value); + b43_write16(dev, B43_MMIO_PHY_DATA, + (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set); } static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg) @@ -1920,8 +1927,8 @@ static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev) static void lpphy_b2062_vco_calib(struct b43_wldev *dev) { - b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x42); - b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x62); + b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x42); + b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x62); udelay(200); } @@ -1980,7 +1987,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, tmp6 = tmp5 / tmp4; tmp7 = tmp5 % tmp4; b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4)); - tmp8 = b43_phy_read(dev, B2062_S_RFPLL_CTL19); + tmp8 = b43_radio_read(dev, B2062_S_RFPLL_CTL19); tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1); b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16); b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF); @@ -2019,17 +2026,17 @@ static void lpphy_b2063_vco_calib(struct b43_wldev *dev) { u16 tmp; - b43_phy_mask(dev, B2063_PLL_SP1, ~0x40); - tmp = b43_phy_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8; - b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp); + b43_radio_mask(dev, B2063_PLL_SP1, ~0x40); + tmp = b43_radio_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8; + b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp); udelay(1); - b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4); + b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4); udelay(1); - b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6); + b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6); udelay(1); - b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7); + b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7); udelay(300); - b43_phy_set(dev, B2063_PLL_SP1, 0x40); + b43_radio_set(dev, B2063_PLL_SP1, 0x40); } static int lpphy_b2063_tune(struct b43_wldev *dev, @@ -2124,31 +2131,31 @@ static int lpphy_b2063_tune(struct b43_wldev *dev, scale = 0; tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8; } - b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5); - b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6); tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16); tmp6 *= (tmp5 * 8) * (scale + 1); if (tmp6 > 150) tmp6 = 0; - b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6); - b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5); - b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4); if (crystal_freq > 26000000) - b43_phy_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2); + b43_radio_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2); else - b43_phy_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD); + b43_radio_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD); if (val1 == 45) - b43_phy_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2); + b43_radio_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2); else - b43_phy_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD); + b43_radio_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD); - b43_phy_set(dev, B2063_PLL_SP2, 0x3); + b43_radio_set(dev, B2063_PLL_SP2, 0x3); udelay(1); - b43_phy_mask(dev, B2063_PLL_SP2, 0xFFFC); + b43_radio_mask(dev, B2063_PLL_SP2, 0xFFFC); lpphy_b2063_vco_calib(dev); b43_radio_write(dev, B2063_COMM15, old_comm15); @@ -2158,10 +2165,9 @@ static int lpphy_b2063_tune(struct b43_wldev *dev, static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { + struct b43_phy_lp *lpphy = dev->phy.lp; int err; - b43_write16(dev, B43_MMIO_CHANNEL, new_channel); - if (dev->phy.radio_ver == 0x2063) { err = lpphy_b2063_tune(dev, new_channel); if (err) @@ -2174,6 +2180,9 @@ static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); } + lpphy->channel = new_channel; + b43_write16(dev, B43_MMIO_CHANNEL, new_channel); + return 0; } @@ -2185,10 +2194,9 @@ static int b43_lpphy_op_init(struct b43_wldev *dev) lpphy_baseband_init(dev); lpphy_radio_init(dev); lpphy_calibrate_rc(dev); - err = b43_lpphy_op_switch_channel(dev, - b43_lpphy_op_get_default_chan(dev)); + err = b43_lpphy_op_switch_channel(dev, 7); if (err) { - b43dbg(dev->wl, "Switch to init channel failed, error = %d.\n", + b43dbg(dev->wl, "Switch to channel 7 failed, error = %d.\n", err); } lpphy_tx_pctl_init(dev); @@ -2222,6 +2230,7 @@ const struct b43_phy_operations b43_phyops_lp = { .init = b43_lpphy_op_init, .phy_read = b43_lpphy_op_read, .phy_write = b43_lpphy_op_write, + .phy_maskset = b43_lpphy_op_maskset, .radio_read = b43_lpphy_op_radio_read, .radio_write = b43_lpphy_op_radio_write, .software_rfkill = b43_lpphy_op_software_rfkill, diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index e158d1f..c3232c1 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -888,6 +888,9 @@ struct b43_phy_lp { bool crs_usr_disable, crs_sys_disable; unsigned int pdiv; + + /* The channel we are tuned to */ + u8 channel; }; enum tssi_mux_mode { diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index 60d472f..c784def 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -624,30 +624,35 @@ u32 b43_lptab_read(struct b43_wldev *dev, u32 offset) void b43_lptab_read_bulk(struct b43_wldev *dev, u32 offset, unsigned int nr_elements, void *_data) { - u32 type, value; + u32 type; u8 *data = _data; unsigned int i; type = offset & B43_LPTAB_TYPEMASK; + offset &= ~B43_LPTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + b43_phy_write(dev, B43_LPPHY_TABLE_ADDR, offset); + for (i = 0; i < nr_elements; i++) { - value = b43_lptab_read(dev, offset); switch (type) { case B43_LPTAB_8BIT: - *data = value; + *data = b43_phy_read(dev, B43_LPPHY_TABLEDATALO) & 0xFF; data++; break; case B43_LPTAB_16BIT: - *((u16 *)data) = value; + *((u16 *)data) = b43_phy_read(dev, B43_LPPHY_TABLEDATALO); data += 2; break; case B43_LPTAB_32BIT: - *((u32 *)data) = value; + *((u32 *)data) = b43_phy_read(dev, B43_LPPHY_TABLEDATAHI); + *((u32 *)data) <<= 16; + *((u32 *)data) |= b43_phy_read(dev, B43_LPPHY_TABLEDATALO); data += 4; break; default: B43_WARN_ON(1); } - offset++; } } @@ -688,26 +693,34 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, unsigned int i; type = offset & B43_LPTAB_TYPEMASK; + offset &= ~B43_LPTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + b43_phy_write(dev, B43_LPPHY_TABLE_ADDR, offset); + for (i = 0; i < nr_elements; i++) { switch (type) { case B43_LPTAB_8BIT: value = *data; data++; + B43_WARN_ON(value & ~0xFF); + b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value); break; case B43_LPTAB_16BIT: value = *((u16 *)data); data += 2; + B43_WARN_ON(value & ~0xFFFF); + b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value); break; case B43_LPTAB_32BIT: value = *((u32 *)data); data += 4; + b43_phy_write(dev, B43_LPPHY_TABLEDATAHI, value >> 16); + b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value); break; default: B43_WARN_ON(1); - value = 0; } - b43_lptab_write(dev, offset, value); - offset++; } } @@ -777,7 +790,7 @@ static const u8 lpphy_pll_fraction_table[] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, }; -static const u16 lpphy_iq_local_table[] = { +static const u16 lpphy_iqlo_cal_table[] = { 0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -789,10 +802,17 @@ static const u16 lpphy_iq_local_table[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; -static const u16 lpphy_ofdm_cck_gain_table[] = { +static const u16 lpphy_rev0_ofdm_cck_gain_table[] = { + 0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001, 0x5001, + 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075, + 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d, 0x135d, 0x055d, 0x155d, + 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d, 0x755d, +}; + +static const u16 lpphy_rev1_ofdm_cck_gain_table[] = { 0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001, 0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d, 0x135d, 0x055d, 0x155d, @@ -2263,11 +2283,18 @@ void lpphy_rev0_1_table_init(struct b43_wldev *dev) b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0), ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table); b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0), - ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table); - b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), - ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table); - b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), - ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table); + ARRAY_SIZE(lpphy_iqlo_cal_table), lpphy_iqlo_cal_table); + if (dev->phy.rev == 0) { + b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), + ARRAY_SIZE(lpphy_rev0_ofdm_cck_gain_table), lpphy_rev0_ofdm_cck_gain_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), + ARRAY_SIZE(lpphy_rev0_ofdm_cck_gain_table), lpphy_rev0_ofdm_cck_gain_table); + } else { + b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), + ARRAY_SIZE(lpphy_rev1_ofdm_cck_gain_table), lpphy_rev1_ofdm_cck_gain_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), + ARRAY_SIZE(lpphy_rev1_ofdm_cck_gain_table), lpphy_rev1_ofdm_cck_gain_table); +} b43_lptab_write_bulk(dev, B43_LPTAB16(15, 0), ARRAY_SIZE(lpphy_gain_delta_table), lpphy_gain_delta_table); b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0), @@ -2281,22 +2308,6 @@ void lpphy_rev2plus_table_init(struct b43_wldev *dev) B43_WARN_ON(dev->phy.rev < 2); - /* - * FIXME This code follows the specs, but it looks wrong: - * In each pass, it writes 4 bytes to an offset in table ID 7, - * then increments the offset by 1 for the next pass. This results - * in the first 3 bytes of each pass except the first one getting - * written to a location that has already been zeroed in the previous - * pass. - * This is what the vendor driver does, but it still looks suspicious. - * - * This should probably suffice: - * - * for (i = 0; i < 704; i+=4) - * b43_lptab_write(dev, B43_LPTAB32(7, i), 0) - * - * This should be tested once the code is functional. - */ for (i = 0; i < 704; i++) b43_lptab_write(dev, B43_LPTAB32(7, i), 0); @@ -2323,7 +2334,7 @@ void lpphy_rev2plus_table_init(struct b43_wldev *dev) b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0), ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table); b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0), - ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table); + ARRAY_SIZE(lpphy_iqlo_cal_table), lpphy_iqlo_cal_table); b43_lptab_write_bulk(dev, B43_LPTAB32(9, 0), ARRAY_SIZE(lpphy_papd_eps_table), lpphy_papd_eps_table); b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0), -- cgit v0.10.2 From 06e4da268c0e8f3b8408403d65e47d2885a78ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Wed, 26 Aug 2009 20:51:26 +0200 Subject: ssb: Implement PMU LDO control and use it in b43 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the "PMU LDO set voltage" and "PMU LDO PA ref enable" functions, and use them during LP-PHY baseband init in b43. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 1a57d33..80f245c 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -234,19 +234,15 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) if ((bus->sprom.boardflags_lo & B43_BFL_FEM) && ((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) || (bus->sprom.boardflags_hi & B43_BFH_PAREF))) { - /* TODO: - * Set the LDO voltage to 0x0028 - FIXME: What is this? - * Call sb_pmu_set_ldo_voltage with 4 and the LDO voltage - * as arguments - * Call sb_pmu_paref_ldo_enable with argument TRUE - */ + ssb_pmu_set_ldo_voltage(&bus->chipco, LDO_PAREF, 0x28); + ssb_pmu_set_ldo_paref(&bus->chipco, true); if (dev->phy.rev == 0) { b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT, 0xFFCF, 0x0010); } b43_lptab_write(dev, B43_LPTAB16(11, 7), 60); } else { - //TODO: Call ssb_pmu_paref_ldo_enable with argument FALSE + ssb_pmu_set_ldo_paref(&bus->chipco, false); b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT, 0xFFCF, 0x0020); b43_lptab_write(dev, B43_LPTAB16(11, 7), 100); diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index 4aaddee..64abd11 100644 --- a/drivers/ssb/driver_chipcommon_pmu.c +++ b/drivers/ssb/driver_chipcommon_pmu.c @@ -28,6 +28,21 @@ static void ssb_chipco_pll_write(struct ssb_chipcommon *cc, chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, value); } +static void ssb_chipco_regctl_maskset(struct ssb_chipcommon *cc, + u32 offset, u32 mask, u32 set) +{ + u32 value; + + chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR); + chipco_write32(cc, SSB_CHIPCO_REGCTL_ADDR, offset); + chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR); + value = chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA); + value &= mask; + value |= set; + chipco_write32(cc, SSB_CHIPCO_REGCTL_DATA, value); + chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA); +} + struct pmu0_plltab_entry { u16 freq; /* Crystal frequency in kHz.*/ u8 xf; /* Crystal frequency value for PMU control */ @@ -506,3 +521,82 @@ void ssb_pmu_init(struct ssb_chipcommon *cc) ssb_pmu_pll_init(cc); ssb_pmu_resources_init(cc); } + +void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc, + enum ssb_pmu_ldo_volt_id id, u32 voltage) +{ + struct ssb_bus *bus = cc->dev->bus; + u32 addr, shift, mask; + + switch (bus->chip_id) { + case 0x4328: + case 0x5354: + switch (id) { + case LDO_VOLT1: + addr = 2; + shift = 25; + mask = 0xF; + break; + case LDO_VOLT2: + addr = 3; + shift = 1; + mask = 0xF; + break; + case LDO_VOLT3: + addr = 3; + shift = 9; + mask = 0xF; + break; + case LDO_PAREF: + addr = 3; + shift = 17; + mask = 0x3F; + break; + default: + SSB_WARN_ON(1); + return; + } + break; + case 0x4312: + if (SSB_WARN_ON(id != LDO_PAREF)) + return; + addr = 0; + shift = 21; + mask = 0x3F; + break; + default: + return; + } + + ssb_chipco_regctl_maskset(cc, addr, ~(mask << shift), + (voltage & mask) << shift); +} + +void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on) +{ + struct ssb_bus *bus = cc->dev->bus; + int ldo; + + switch (bus->chip_id) { + case 0x4312: + ldo = SSB_PMURES_4312_PA_REF_LDO; + break; + case 0x4328: + ldo = SSB_PMURES_4328_PA_REF_LDO; + break; + case 0x5354: + ldo = SSB_PMURES_5354_PA_REF_LDO; + break; + default: + return; + } + + if (on) + chipco_set32(cc, SSB_CHIPCO_PMU_MINRES_MSK, 1 << ldo); + else + chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, ~(1 << ldo)); + chipco_read32(cc, SSB_CHIPCO_PMU_MINRES_MSK); //SPEC FIXME found via mmiotrace - dummy read? +} + +EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage); +EXPORT_SYMBOL(ssb_pmu_set_ldo_paref); diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index d3b1d18..4e27acf 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -629,5 +629,15 @@ extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc, /* PMU support */ extern void ssb_pmu_init(struct ssb_chipcommon *cc); +enum ssb_pmu_ldo_volt_id { + LDO_PAREF = 0, + LDO_VOLT1, + LDO_VOLT2, + LDO_VOLT3, +}; + +void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc, + enum ssb_pmu_ldo_volt_id id, u32 voltage); +void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on); #endif /* LINUX_SSB_CHIPCO_H_ */ -- cgit v0.10.2 From 924d6356b216e592f596595757db8e955391a489 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 26 Aug 2009 21:04:08 +0200 Subject: rt2x00: Cleanup rt2x00mac_bss_info_changed() Since patch "rt2x00: bss_info_changed() callback is allowed to sleep" the variable delayed wasn't used anymore. This means it can be removed along with the call to schedule_work which depended on that variable. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index a91f316..929b85f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -582,7 +582,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); - unsigned int delayed = 0; int update_bssid = 0; /* @@ -645,13 +644,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, */ if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); - - spin_lock(&intf->lock); - if (delayed) { - intf->delayed_flags |= delayed; - schedule_work(&rt2x00dev->intf_work); - } - spin_unlock(&intf->lock); } EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); -- cgit v0.10.2 From 1303dcfd0504565aef8ef63487443ab1f814c00f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Aug 2009 22:15:13 +0200 Subject: iwlwifi: fix ICT irq table endianness The ICT IRQ table is a set of __le32 values, not u32 values, so when reading it we need to take into account that it has to be converted to CPU endianness. This was causing a lot of trouble on my powerpc box where various things would simply not work for no apparent reason with 5xxx cards, but worked with 4965 -- which doesn't use the ICT table. Signed-off-by: Johannes Berg Acked-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c62c081..0bfd4e9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1823,7 +1823,7 @@ int iwl_reset_ict(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); iwl_disable_interrupts(priv); - memset(&priv->ict_tbl[0],0, sizeof(u32) * ICT_COUNT); + memset(&priv->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT); val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT; @@ -1901,13 +1901,13 @@ irqreturn_t iwl_isr_ict(int irq, void *data) /* read all entries that not 0 start with ict_index */ while (priv->ict_tbl[priv->ict_index]) { - val |= priv->ict_tbl[priv->ict_index]; + val |= le32_to_cpu(priv->ict_tbl[priv->ict_index]); IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n", - priv->ict_index, - priv->ict_tbl[priv->ict_index]); + priv->ict_index, + le32_to_cpu(priv->ict_tbl[priv->ict_index])); priv->ict_tbl[priv->ict_index] = 0; priv->ict_index = iwl_queue_inc_wrap(priv->ict_index, - ICT_COUNT); + ICT_COUNT); } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ccea2e4..028d505 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1170,7 +1170,7 @@ struct iwl_priv { struct iwl_hw_params hw_params; /* INT ICT Table */ - u32 *ict_tbl; + __le32 *ict_tbl; dma_addr_t ict_tbl_dma; dma_addr_t aligned_ict_tbl_dma; int ict_index; -- cgit v0.10.2 From 00fa928df428521793866ff6832569d99be7f3e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Wed, 26 Aug 2009 23:46:18 +0200 Subject: b43: LP-PHY: Revert to the original PHY register write routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After some discussion on IRC about the PHY register write change, I am not sure anymore if this is the right thing to do. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 80f245c..7d2a702 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1496,7 +1496,8 @@ static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) { - b43_write32(dev, B43_MMIO_PHY_CONTROL, ((u32)value << 16) | reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); } static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, -- cgit v0.10.2 From ca5efbe243dde7d269b6bbae7feaa5e4740db36e Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 27 Aug 2009 15:17:15 -0400 Subject: ath5k: clarify srev comparison for CCMP check As Pavel Roskin noted, the check for mac version as copied from legacy_hal made no sense. This replaces it with the equivalent and makes up a suitable #define for the mac version legacy_hal checked. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index cdc79cd..1275ba0 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -306,6 +306,7 @@ struct ath5k_srev_name { #define AR5K_SREV_AR5311B 0x30 /* Spirit */ #define AR5K_SREV_AR5211 0x40 /* Oahu */ #define AR5K_SREV_AR5212 0x50 /* Venice */ +#define AR5K_SREV_AR5212_V4 0x54 /* ??? */ #define AR5K_SREV_AR5213 0x55 /* ??? */ #define AR5K_SREV_AR5213A 0x59 /* Hainan */ #define AR5K_SREV_AR2413 0x78 /* Griffin lite */ diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 109ab7b..4819f39d 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -318,12 +318,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) /* Crypto settings */ ee = &ah->ah_capabilities.cap_eeprom; - ah->ah_aes_support = + ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 && (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && - !AR5K_EEPROM_AES_DIS(ee->ee_misc5) && - (ah->ah_mac_version > (AR5K_SREV_AR5212 >> 4) || - (ah->ah_mac_version == (AR5K_SREV_AR5212 >> 4) && - ah->ah_mac_revision >= (AR5K_SREV_AR5211 >> 4)))); + !AR5K_EEPROM_AES_DIS(ee->ee_misc5)); if (srev >= AR5K_SREV_AR2414) { ah->ah_combined_mic = true; -- cgit v0.10.2 From 3b3ee43da43aca1cbf4c3651379b2b1492e49dd6 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Wed, 26 Aug 2009 22:30:00 -0400 Subject: ath5k: fix uninitialized value use in ath5k_eeprom_read_turbo_modes() The `val' variable in ath5k_eeprom_read_turbo_modes() is used uninitialized. gcc 4.4.1 with -fno-inline-functions-called-once reports it: eeprom.c: In function 'ath5k_eeprom_read_turbo_modes': eeprom.c:441: warning: 'val' may be used uninitialized in this function Comparing the code to the Atheros HAL, it's clear that the split between ath5k_eeprom_read_modes() and ath5k_eeprom_read_turbo_modes() was incorrect. The Atheros HAL reads both turbo and non-turbo data from EEPROM in one function. Some turbo mode parameters are derived from the same EEPROM values as non-turbo parameters, just from different bits. Merge ath5k_eeprom_read_turbo_modes() into ath5k_eeprom_read_modes() to fix the warning. The actual values and offsets have been cross-checked against Atheros HAL. Signed-off-by: Pavel Roskin Acked-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 8af477d..644962a 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -414,27 +414,11 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, break; } -done: - /* return new offset */ - *offset = o; - - return 0; -} - -/* - * Read turbo mode information on newer EEPROM versions - */ -static int -ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah, - u32 *offset, unsigned int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u32 o = *offset; - u16 val; - int ret; - + /* + * Read turbo mode information on newer EEPROM versions + */ if (ee->ee_version < AR5K_EEPROM_VERSION_5_0) - return 0; + goto done; switch (mode){ case AR5K_EEPROM_MODE_11A: @@ -468,6 +452,7 @@ ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah, break; } +done: /* return new offset */ *offset = o; @@ -504,10 +489,6 @@ ath5k_eeprom_init_modes(struct ath5k_hw *ah) ret = ath5k_eeprom_read_modes(ah, &offset, mode); if (ret) return ret; - - ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode); - if (ret) - return ret; } /* override for older eeprom versions for better performance */ -- cgit v0.10.2 From 97a81f5c5033cb02ae56dd80ff9c38866c777bd8 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Wed, 26 Aug 2009 22:30:09 -0400 Subject: ath5k: don't use PCI ID to find the chip revision AR5K_SREV is available even if the chip has been put to sleep. Relying on the chip register allows binding non-standard PCI IDs by echo VENDOR_ID PRODUCT_ID >/sys/bus/pci/drivers/ath5k/new_id without having to specify the driver data as well. Signed-off-by: Pavel Roskin Acked-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 1275ba0..6cd5efc 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1160,7 +1160,7 @@ struct ath5k_hw { */ /* Attach/Detach Functions */ -extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version); +extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc); extern void ath5k_hw_detach(struct ath5k_hw *ah); /* LED functions */ diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 4819f39d..71a1bd25 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -95,14 +95,13 @@ static int ath5k_hw_post(struct ath5k_hw *ah) * ath5k_hw_attach - Check if hw is supported and init the needed structs * * @sc: The &struct ath5k_softc we got from the driver's attach function - * @mac_version: The mac version id (check out ath5k.h) based on pci id * * Check if the device is supported, perform a POST and initialize the needed * structs. Returns -ENOMEM if we don't have memory for the needed structs, * -ENODEV if the device is not supported or prints an error msg if something * else went wrong. */ -struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) +struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc) { struct ath5k_hw *ah; struct pci_dev *pdev = sc->pdev; @@ -136,9 +135,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) ah->ah_software_retry = false; /* - * Set the mac version based on the pci id + * Find the mac version */ - ah->ah_version = mac_version; + srev = ath5k_hw_reg_read(ah, AR5K_SREV); + if (srev < AR5K_SREV_AR5311) + ah->ah_version = AR5K_AR5210; + else if (srev < AR5K_SREV_AR5212) + ah->ah_version = AR5K_AR5211; + else + ah->ah_version = AR5K_AR5212; /*Fill the ath5k_hw struct with the needed functions*/ ret = ath5k_hw_init_desc_functions(ah); @@ -151,7 +156,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; /* Get MAC, PHY and RADIO revisions */ - srev = ath5k_hw_reg_read(ah, AR5K_SREV); ah->ah_mac_srev = srev; ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 94d46fd..9c6ab53 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -84,24 +84,24 @@ MODULE_VERSION("0.6.0 (EXPERIMENTAL)"); /* Known PCI ids */ static const struct pci_device_id ath5k_pci_id_table[] = { - { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */ - { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */ - { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/ - { PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */ - { PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */ - { PCI_VDEVICE(3COM_2, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */ - { PCI_VDEVICE(3COM, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */ - { PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */ - { PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */ - { PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */ - { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* PCI-E cards */ - { PCI_VDEVICE(ATHEROS, 0x001d), .driver_data = AR5K_AR5212 }, /* 2417 Nala */ + { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */ + { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */ + { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/ + { PCI_VDEVICE(ATHEROS, 0x0012) }, /* 5211 */ + { PCI_VDEVICE(ATHEROS, 0x0013) }, /* 5212 */ + { PCI_VDEVICE(3COM_2, 0x0013) }, /* 3com 5212 */ + { PCI_VDEVICE(3COM, 0x0013) }, /* 3com 3CRDAG675 5212 */ + { PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */ + { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */ + { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */ + { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */ + { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */ { 0 } }; MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table); @@ -566,7 +566,7 @@ ath5k_pci_probe(struct pci_dev *pdev, } /* Initialize device */ - sc->ah = ath5k_hw_attach(sc, id->driver_data); + sc->ah = ath5k_hw_attach(sc); if (IS_ERR(sc->ah)) { ret = PTR_ERR(sc->ah); goto err_irq; -- cgit v0.10.2 From 867b2efe68b6bb929e3bd1c6d699ba61ff2cf847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 27 Aug 2009 17:24:23 +0200 Subject: b43: Enable LP-PHY support by default and remove Kconfig warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The most common LP-PHY device, BCM4312, is now fully functional. So, no need to say "probably won't work for you" anymore. It's also not "for debuggers and developers only", as it is perfectly usable for end-users now (at least for BCM4312). Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 237b1aa..2af3b35 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -82,15 +82,13 @@ config B43_NPHY config B43_PHY_LP bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)" depends on B43 && EXPERIMENTAL + default y ---help--- Support for the LP-PHY. The LP-PHY is a low-power PHY built into some notebooks and embedded devices. It supports 802.11a/g (802.11a support is optional, and currently disabled). - This is heavily experimental, and probably will not work for you. - Say N unless you want to help debug the driver. - # This config option automatically enables b43 LEDS support, # if it's possible. config B43_LEDS -- cgit v0.10.2 From 64e368bf9c3690eebd4b3a5cc243f39e902ecdd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Thu, 27 Aug 2009 22:49:49 +0200 Subject: b43: Implement antenna diversity support for LP-PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The A/G-PHY changes are fallout fixes from the enum change, which in turn allows the LP-PHY code to be much simpler. The antenna_to_phyctl change is a fix for a potential existing bug that this patch may otherwise trigger. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index f5bdf1c..0f16844 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1456,7 +1456,8 @@ static u16 b43_antenna_to_phyctl(int antenna) return B43_TXH_PHY_ANT2; case B43_ANTENNA3: return B43_TXH_PHY_ANT3; - case B43_ANTENNA_AUTO: + case B43_ANTENNA_AUTO0: + case B43_ANTENNA_AUTO1: return B43_TXH_PHY_ANT01AUTO; } B43_WARN_ON(1); diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 816e028..809ec97 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -531,7 +531,7 @@ static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + tmp |= (autodiv ? B43_ANTENNA_AUTO1 : antenna) << B43_PHY_BBANDCFG_RXANT_SHIFT; b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index b47a0f5..28e3846 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -49,11 +49,11 @@ enum b43_interference_mitigation { /* Antenna identifiers */ enum { - B43_ANTENNA0, /* Antenna 0 */ - B43_ANTENNA1, /* Antenna 0 */ - B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ - B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ - B43_ANTENNA2, + B43_ANTENNA0 = 0, /* Antenna 0 */ + B43_ANTENNA1 = 1, /* Antenna 1 */ + B43_ANTENNA_AUTO0 = 2, /* Automatic, starting with antenna 0 */ + B43_ANTENNA_AUTO1 = 3, /* Automatic, starting with antenna 1 */ + B43_ANTENNA2 = 4, B43_ANTENNA3 = 8, B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index e471312..bdff9af 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2664,7 +2664,7 @@ static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + tmp |= (autodiv ? B43_ANTENNA_AUTO1 : antenna) << B43_PHY_BBANDCFG_RXANT_SHIFT; b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 7d2a702..1ab00b0 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -2205,7 +2205,14 @@ static int b43_lpphy_op_init(struct b43_wldev *dev) static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) { - //TODO + if (dev->phy.rev >= 2) + return; // rev2+ doesn't support antenna diversity + + if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1)) + return; + + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2); + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1); } static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev) -- cgit v0.10.2 From 5f81ff5a7a12a9281d03be103382971ce490268e Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:58:49 +0300 Subject: rndis_wlan: ignore OID_802_11_ADD_KEY triggered media connect indications Setting WPA keys with OID_802_11_ADD_KEY sometimes trigger instant media connect indication. These indications are extranous and should be ignored, as otherwise driver would send reassociation event to userspace which in this case is not needed. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index f181b00..612c2c7 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -470,6 +470,7 @@ struct rndis_wlan_private { int radio_on; int infra_mode; struct ndis_80211_ssid essid; + __le32 current_command_oid; /* encryption stuff */ int encr_tx_key_index; @@ -665,7 +666,9 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) u.get->msg_len = cpu_to_le32(sizeof *u.get); u.get->oid = oid; + priv->current_command_oid = oid; ret = rndis_command(dev, u.header, buflen); + priv->current_command_oid = 0; if (ret < 0) devdbg(dev, "rndis_query_oid(%s): rndis_command() failed, %d " "(%08x)", oid_to_string(oid), ret, @@ -725,7 +728,9 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) u.set->handle = cpu_to_le32(0); memcpy(u.buf + sizeof(*u.set), data, len); + priv->current_command_oid = oid; ret = rndis_command(dev, u.header, buflen); + priv->current_command_oid = 0; if (ret < 0) devdbg(dev, "rndis_set_oid(%s): rndis_command() failed, %d " "(%08x)", oid_to_string(oid), ret, @@ -760,6 +765,7 @@ static int rndis_reset(struct usbnet *usbdev) memset(reset, 0, sizeof(*reset)); reset->msg_type = RNDIS_MSG_RESET; reset->msg_len = cpu_to_le32(sizeof(*reset)); + priv->current_command_oid = 0; ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE); mutex_unlock(&priv->command_lock); @@ -2558,6 +2564,17 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) switch (msg->status) { case RNDIS_STATUS_MEDIA_CONNECT: + if (priv->current_command_oid == OID_802_11_ADD_KEY) { + /* OID_802_11_ADD_KEY causes sometimes extra + * "media connect" indications which confuses driver + * and userspace to think that device is + * roaming/reassociating when it isn't. + */ + devdbg(usbdev, "ignored OID_802_11_ADD_KEY triggered " + "'media connect'"); + return; + } + usbnet_pause_rx(usbdev); devinfo(usbdev, "media connect"); -- cgit v0.10.2 From db0dd396da45502e02c64c4153c5822ab5a59a5f Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:58:55 +0300 Subject: rndis_wlan: get bssid scan list before new scan OID_802_11_BSSID_LIST_SCAN clears device's bssid list, so retrieve current bssid list from device before issuing new scan. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 612c2c7..3779621 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -926,6 +926,7 @@ static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig) * common functions */ static void restore_keys(struct usbnet *usbdev); +static int rndis_check_bssid_list(struct usbnet *usbdev); static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { @@ -1616,6 +1617,11 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, devdbg(usbdev, "cfg80211.scan"); + /* Get current bssid list from device before new scan, as new scan + * clears internal bssid list. + */ + rndis_check_bssid_list(usbdev); + if (!request) return -EINVAL; -- cgit v0.10.2 From 5fd8f2503b0888ed0c8e0017264059a3f9dc51c0 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:00 +0300 Subject: rndis_wlan: resize bssid list if too small Buffer used for bssid list might be too small. Change rndis_query_oid() to return required buffer length to caller and make rndis_check_bssid_list() resize buffer when needed. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 3779621..2309ad2 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -676,7 +676,8 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) if (ret == 0) { ret = le32_to_cpu(u.get_c->len); - *len = (*len > ret) ? ret : *len; + if (ret > *len) + *len = ret; memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len); ret = rndis_error_status(u.get_c->status); @@ -1656,6 +1657,9 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, int ie_len, bssid_len; u8 *ie; + devdbg(usbdev, " found bssid: '%.32s' [%pM]", bssid->ssid.essid, + bssid->mac); + /* parse bssid structure */ bssid_len = le32_to_cpu(bssid->length); @@ -1695,10 +1699,12 @@ static int rndis_check_bssid_list(struct usbnet *usbdev) struct ndis_80211_bssid_list_ex *bssid_list; struct ndis_80211_bssid_ex *bssid; int ret = -EINVAL, len, count, bssid_len; + bool resized = false; devdbg(usbdev, "check_bssid_list"); len = CONTROL_BUFFER_SIZE; +resize_buf: buf = kmalloc(len, GFP_KERNEL); if (!buf) { ret = -ENOMEM; @@ -1709,11 +1715,18 @@ static int rndis_check_bssid_list(struct usbnet *usbdev) if (ret != 0) goto out; + if (!resized && len > CONTROL_BUFFER_SIZE) { + resized = true; + kfree(buf); + goto resize_buf; + } + bssid_list = buf; bssid = bssid_list->bssid; bssid_len = le32_to_cpu(bssid->length); count = le32_to_cpu(bssid_list->num_items); - devdbg(usbdev, "check_bssid_list: %d BSSIDs found", count); + devdbg(usbdev, "check_bssid_list: %d BSSIDs found (buflen: %d)", count, + len); while (count && ((void *)bssid + bssid_len) <= (buf + len)) { rndis_bss_info_update(usbdev, bssid); -- cgit v0.10.2 From b1d25a67647efacf2a9f2a1800f0c8195827f923 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:05 +0300 Subject: rndis_wlan: increase scan timer delay Increase scan delay from 1 sec to 6 sec. Spec says that scan by OID_802_11_BSSID_LIST_SCAN completes in 6 seconds. Before rfkill patch too short delay was not problem as device was always active (radio on) and performing background scanning. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2309ad2..cb362b0 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1607,7 +1607,7 @@ static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) } -#define SCAN_DELAY_JIFFIES (HZ) +#define SCAN_DELAY_JIFFIES (6 * HZ) static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) { -- cgit v0.10.2 From 0848e6c698237ba51c69eca10580d2f38a1179ad Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:10 +0300 Subject: rndis_wlan: move link up/down work to separate functions Move link up/down work to separate functions and use local array for allocating memory for info structure instead of kzmalloc. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index cb362b0..dc3083b 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2319,68 +2319,77 @@ static const struct iw_handler_def rndis_iw_handlers = { }; -static void rndis_wlan_worker(struct work_struct *work) +static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) { - struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, work); - struct usbnet *usbdev = priv->usbdev; - union iwreq_data evt; - unsigned char bssid[ETH_ALEN]; struct ndis_80211_assoc_info *info; - int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32; + union iwreq_data evt; + u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32]; + u8 bssid[ETH_ALEN]; int ret, offset; - if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) { - netif_carrier_on(usbdev->net); - - info = kzalloc(assoc_size, GFP_KERNEL); - if (!info) - goto get_bssid; - - /* Get association info IEs from device and send them back to - * userspace. */ - ret = get_association_info(usbdev, info, assoc_size); - if (!ret) { - evt.data.length = le32_to_cpu(info->req_ie_length); - if (evt.data.length > 0) { - offset = le32_to_cpu(info->offset_req_ies); - wireless_send_event(usbdev->net, - IWEVASSOCREQIE, &evt, - (char *)info + offset); - } - - evt.data.length = le32_to_cpu(info->resp_ie_length); - if (evt.data.length > 0) { - offset = le32_to_cpu(info->offset_resp_ies); - wireless_send_event(usbdev->net, - IWEVASSOCRESPIE, &evt, - (char *)info + offset); - } + memset(assoc_buf, 0, sizeof(assoc_buf)); + info = (void *)assoc_buf; + + netif_carrier_on(usbdev->net); + + /* Get association info IEs from device and send them back to + * userspace. */ + ret = get_association_info(usbdev, info, sizeof(assoc_buf)); + if (!ret) { + evt.data.length = le32_to_cpu(info->req_ie_length); + if (evt.data.length > 0) { + offset = le32_to_cpu(info->offset_req_ies); + wireless_send_event(usbdev->net, + IWEVASSOCREQIE, &evt, + (char *)info + offset); } - kfree(info); - -get_bssid: - ret = get_bssid(usbdev, bssid); - if (!ret) { - evt.data.flags = 0; - evt.data.length = 0; - memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); - wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); + evt.data.length = le32_to_cpu(info->resp_ie_length); + if (evt.data.length > 0) { + offset = le32_to_cpu(info->offset_resp_ies); + wireless_send_event(usbdev->net, + IWEVASSOCRESPIE, &evt, + (char *)info + offset); } usbnet_resume_rx(usbdev); } - if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) { - netif_carrier_off(usbdev->net); - + ret = get_bssid(usbdev, bssid); + if (!ret) { evt.data.flags = 0; evt.data.length = 0; - memset(evt.ap_addr.sa_data, 0, ETH_ALEN); + memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); } + usbnet_resume_rx(usbdev); +} + +static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) +{ + union iwreq_data evt; + + netif_carrier_off(usbdev->net); + + evt.data.flags = 0; + evt.data.length = 0; + memset(evt.ap_addr.sa_data, 0, ETH_ALEN); + wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); +} + +static void rndis_wlan_worker(struct work_struct *work) +{ + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, work); + struct usbnet *usbdev = priv->usbdev; + + if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) + rndis_wlan_do_link_up_work(usbdev); + + if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) + rndis_wlan_do_link_down_work(usbdev); + if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) set_multicast_list(usbdev); } -- cgit v0.10.2 From 7b1fff996a5408261ca458f82369d1f5b7aad2d4 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:15 +0300 Subject: rndis_wlan: use is_zero_ether_addr() and is_broadcast_ether_addr() Use is_zero_ether_addr() and is_broadcast_ether_addr() instead of memcmp against ffff_bssid/zero_bssid. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index dc3083b..c28fde5 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -514,11 +514,6 @@ static struct cfg80211_ops rndis_config_ops = { static void *rndis_wiphy_privid = &rndis_wiphy_privid; -static const unsigned char zero_bssid[ETH_ALEN] = {0,}; -static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff }; - - static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) { return (struct rndis_wlan_private *)dev->driver_priv; @@ -995,7 +990,7 @@ static int is_associated(struct usbnet *usbdev) ret = get_bssid(usbdev, bssid); - return(ret == 0 && memcmp(bssid, zero_bssid, ETH_ALEN) != 0); + return (ret == 0 && !is_zero_ether_addr(bssid)); } @@ -1293,8 +1288,8 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, devdbg(usbdev, "add_wpa_key: recv seq flag without buffer"); return -EINVAL; } - is_addr_ok = addr && memcmp(addr, zero_bssid, ETH_ALEN) != 0 && - memcmp(addr, ffff_bssid, ETH_ALEN) != 0; + is_addr_ok = addr && !is_zero_ether_addr(addr) && + !is_broadcast_ether_addr(addr); if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) { devdbg(usbdev, "add_wpa_key: pairwise but bssid invalid (%pM)", addr); @@ -1379,8 +1374,8 @@ static int restore_key(struct usbnet *usbdev, int key_idx) /*if (priv->encr_tx_key_index == key_idx) flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;*/ - if (memcmp(key.bssid, zero_bssid, ETH_ALEN) != 0 && - memcmp(key.bssid, ffff_bssid, ETH_ALEN) != 0) + if (!is_zero_ether_addr(key.bssid) && + !is_broadcast_ether_addr(key.bssid)) flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; return add_wpa_key(usbdev, key.material, key.len, key_idx, @@ -1430,7 +1425,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) remove_key.index = cpu_to_le32(index); if (bssid) { /* pairwise key */ - if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) + if (!is_broadcast_ether_addr(bssid)) remove_key.index |= NDIS_80211_ADDKEY_PAIRWISE_KEY; memcpy(remove_key.bssid, bssid, -- cgit v0.10.2 From 161391725eba1f07e98594369cfcb10c848ef352 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:21 +0300 Subject: rndis_wlan: set ieee80211_ptr->iftype in rndis_change_virtual_intf Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c28fde5..d117620 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1526,7 +1526,8 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct usbnet *usbdev = netdev_priv(dev); + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; int mode; switch (type) { @@ -1540,6 +1541,8 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, return -EINVAL; } + priv->wdev.iftype = type; + return set_infra_mode(usbdev, mode); } -- cgit v0.10.2 From 9f77ccab57534f45b0289ceae3a6b85478d14182 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:26 +0300 Subject: rndis_wlan: enable infrastructure before setting random essid Random essid must be set to turn on radio when not connected. If device is in ad-hoc mode, this results 'media connect' indications with the random essid which should be ignored. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index d117620..c5a674d 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -921,6 +921,7 @@ static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig) /* * common functions */ +static int set_infra_mode(struct usbnet *usbdev, int mode); static void restore_keys(struct usbnet *usbdev); static int rndis_check_bssid_list(struct usbnet *usbdev); @@ -1014,6 +1015,11 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) /* disassociate causes radio to be turned off; if reset_ssid * is given, set random ssid to enable radio */ if (reset_ssid) { + /* Set device to infrastructure mode so we don't get ad-hoc + * 'media connect' indications with the random ssid. + */ + set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); + ssid.length = cpu_to_le32(sizeof(ssid.essid)); get_random_bytes(&ssid.essid[2], sizeof(ssid.essid)-2); ssid.essid[0] = 0x1; -- cgit v0.10.2 From 5c52323e8c44a06183052986dbd028ce15622166 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:27:47 +0300 Subject: rndis_wlan: add cfg80211 connect, disconnect, join_ibss and leave_ibss Add cfg80211 connect functions for station and ad-hoc modes and convert wext to use theim. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c5a674d..c2af5be 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -358,13 +358,6 @@ struct ndis_80211_assoc_info { __le32 offset_resp_ies; } __attribute__((packed)); -/* these have to match what is in wpa_supplicant */ -enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP }; -enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, - CIPHER_WEP104 }; -enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, - KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE }; - /* * private data */ @@ -379,6 +372,15 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, #define WORK_LINK_DOWN (1<<1) #define WORK_SET_MULTICAST_LIST (1<<2) +#define RNDIS_WLAN_ALG_NONE 0 +#define RNDIS_WLAN_ALG_WEP (1<<0) +#define RNDIS_WLAN_ALG_TKIP (1<<1) +#define RNDIS_WLAN_ALG_CCMP (1<<2) + +#define RNDIS_WLAN_KEY_MGMT_NONE 0 +#define RNDIS_WLAN_KEY_MGMT_802_1X (1<<0) +#define RNDIS_WLAN_KEY_MGMT_PSK (1<<1) + #define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) static const struct ieee80211_channel rndis_channels[] = { @@ -469,15 +471,16 @@ struct rndis_wlan_private { /* hardware state */ int radio_on; int infra_mode; + bool connected; struct ndis_80211_ssid essid; __le32 current_command_oid; /* encryption stuff */ int encr_tx_key_index; struct rndis_wlan_encr_key encr_keys[4]; + enum nl80211_auth_type wpa_auth_type; int wpa_version; int wpa_keymgmt; - int wpa_authalg; int wpa_ie_len; u8 *wpa_ie; int wpa_cipher_pair; @@ -503,12 +506,27 @@ static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, int dbm); static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm); +static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme); + +static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code); + +static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params); + +static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, .set_wiphy_params = rndis_set_wiphy_params, .set_tx_power = rndis_set_tx_power, .get_tx_power = rndis_get_tx_power, + .connect = rndis_connect, + .disconnect = rndis_disconnect, + .join_ibss = rndis_join_ibss, + .leave_ibss = rndis_leave_ibss, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -545,6 +563,34 @@ static bool is_wpa_key(struct rndis_wlan_private *priv, int idx) } +static int rndis_cipher_to_alg(u32 cipher) +{ + switch (cipher) { + default: + return RNDIS_WLAN_ALG_NONE; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + return RNDIS_WLAN_ALG_WEP; + case WLAN_CIPHER_SUITE_TKIP: + return RNDIS_WLAN_ALG_TKIP; + case WLAN_CIPHER_SUITE_CCMP: + return RNDIS_WLAN_ALG_CCMP; + } +} + +static int rndis_akm_suite_to_key_mgmt(u32 akm_suite) +{ + switch (akm_suite) { + default: + return RNDIS_WLAN_KEY_MGMT_NONE; + case WLAN_AKM_SUITE_8021X: + return RNDIS_WLAN_KEY_MGMT_802_1X; + case WLAN_AKM_SUITE_PSK: + return RNDIS_WLAN_KEY_MGMT_PSK; + } +} + + #ifdef DEBUG static const char *oid_to_string(__le32 oid) { @@ -925,35 +971,16 @@ static int set_infra_mode(struct usbnet *usbdev, int mode); static void restore_keys(struct usbnet *usbdev); static int rndis_check_bssid_list(struct usbnet *usbdev); -static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) -{ - int ret, len; - - len = sizeof(*ssid); - ret = rndis_query_oid(usbdev, OID_802_11_SSID, ssid, &len); - - if (ret != 0) - ssid->length = 0; - -#ifdef DEBUG - { - unsigned char tmp[NDIS_802_11_LENGTH_SSID + 1]; - - memcpy(tmp, ssid->essid, le32_to_cpu(ssid->length)); - tmp[le32_to_cpu(ssid->length)] = 0; - devdbg(usbdev, "get_essid: '%s', ret: %d", tmp, ret); - } -#endif - return ret; -} - - static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid)); + if (ret < 0) { + devwarn(usbdev, "setting SSID failed (%08X)", ret); + return ret; + } if (ret == 0) { memcpy(&priv->essid, ssid, sizeof(priv->essid)); priv->radio_on = 1; @@ -963,6 +990,25 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) return ret; } +static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) +{ + int ret; + + ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN); + if (ret < 0) { + devwarn(usbdev, "setting BSSID[%pM] failed (%08X)", bssid, ret); + return ret; + } + + return ret; +} + +static int clear_bssid(struct usbnet *usbdev) +{ + u8 broadcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + return set_bssid(usbdev, broadcast_mac); +} static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) { @@ -984,11 +1030,15 @@ static int get_association_info(struct usbnet *usbdev, info, &len); } -static int is_associated(struct usbnet *usbdev) +static bool is_associated(struct usbnet *usbdev) { + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); u8 bssid[ETH_ALEN]; int ret; + if (!priv->radio_on) + return false; + ret = get_bssid(usbdev, bssid); return (ret == 0 && !is_zero_ether_addr(bssid)); @@ -1032,34 +1082,34 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) } -static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) +static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, + enum nl80211_auth_type auth_type, int keymgmt) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int auth_mode, ret; devdbg(usbdev, "set_auth_mode: wpa_version=0x%x authalg=0x%x " - "keymgmt=0x%x", wpa_version, authalg, priv->wpa_keymgmt); + "keymgmt=0x%x", wpa_version, auth_type, keymgmt); - if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { - if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) + if (wpa_version & NL80211_WPA_VERSION_2) { + if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) auth_mode = NDIS_80211_AUTH_WPA2; else auth_mode = NDIS_80211_AUTH_WPA2_PSK; - } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { - if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) + } else if (wpa_version & NL80211_WPA_VERSION_1) { + if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) auth_mode = NDIS_80211_AUTH_WPA; - else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK) + else if (keymgmt & RNDIS_WLAN_KEY_MGMT_PSK) auth_mode = NDIS_80211_AUTH_WPA_PSK; else auth_mode = NDIS_80211_AUTH_WPA_NONE; - } else if (authalg & IW_AUTH_ALG_SHARED_KEY) { - if (authalg & IW_AUTH_ALG_OPEN_SYSTEM) - auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; - else - auth_mode = NDIS_80211_AUTH_SHARED; - } else + } else if (auth_type == NL80211_AUTHTYPE_SHARED_KEY) + auth_mode = NDIS_80211_AUTH_SHARED; + else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) auth_mode = NDIS_80211_AUTH_OPEN; + else + return -ENOTSUPP; tmp = cpu_to_le32(auth_mode); ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp, @@ -1070,7 +1120,9 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) } priv->wpa_version = wpa_version; - priv->wpa_authalg = authalg; + priv->wpa_auth_type = auth_type; + priv->wpa_keymgmt = keymgmt; + return 0; } @@ -1082,8 +1134,8 @@ static int set_priv_filter(struct usbnet *usbdev) devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version); - if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 || - priv->wpa_version & IW_AUTH_WPA_VERSION_WPA) + if (priv->wpa_version & NL80211_WPA_VERSION_2 || + priv->wpa_version & NL80211_WPA_VERSION_1) tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP); else tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); @@ -1100,19 +1152,17 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) int encr_mode, ret; devdbg(usbdev, "set_encr_mode: cipher_pair=0x%x cipher_group=0x%x", - pairwise, - groupwise); + pairwise, groupwise); - if (pairwise & IW_AUTH_CIPHER_CCMP) + if (pairwise & RNDIS_WLAN_ALG_CCMP) encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; - else if (pairwise & IW_AUTH_CIPHER_TKIP) + else if (pairwise & RNDIS_WLAN_ALG_TKIP) encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; - else if (pairwise & - (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) + else if (pairwise & RNDIS_WLAN_ALG_WEP) encr_mode = NDIS_80211_ENCR_WEP_ENABLED; - else if (groupwise & IW_AUTH_CIPHER_CCMP) + else if (groupwise & RNDIS_WLAN_ALG_CCMP) encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; - else if (groupwise & IW_AUTH_CIPHER_TKIP) + else if (groupwise & RNDIS_WLAN_ALG_TKIP) encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; else encr_mode = NDIS_80211_ENCR_DISABLED; @@ -1131,18 +1181,6 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) } -static int set_assoc_params(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - set_auth_mode(usbdev, priv->wpa_version, priv->wpa_authalg); - set_priv_filter(usbdev); - set_encr_mode(usbdev, priv->wpa_cipher_pair, priv->wpa_cipher_group); - - return 0; -} - - static int set_infra_mode(struct usbnet *usbdev, int mode) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1201,16 +1239,11 @@ static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) static void set_default_iw_params(struct usbnet *usbdev) { - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - priv->wpa_keymgmt = 0; - priv->wpa_version = 0; - set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); - set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, - IW_AUTH_ALG_OPEN_SYSTEM); + set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, + RNDIS_WLAN_KEY_MGMT_NONE); set_priv_filter(usbdev); - set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE); + set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); } @@ -1224,8 +1257,40 @@ static int deauthenticate(struct usbnet *usbdev) } +static int set_channel(struct usbnet *usbdev, int channel) +{ + struct ndis_80211_conf config; + unsigned int dsconfig; + int len, ret; + + devdbg(usbdev, "set_channel(%d)", channel); + + /* this OID is valid only when not associated */ + if (is_associated(usbdev)) + return 0; + + dsconfig = ieee80211_dsss_chan_to_freq(channel) * 1000; + + len = sizeof(config); + ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); + if (ret < 0) { + devdbg(usbdev, "set_channel: querying configuration failed"); + return ret; + } + + config.ds_config = cpu_to_le32(dsconfig); + ret = rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config, + sizeof(config)); + + devdbg(usbdev, "set_channel: %d -> %d", channel, ret); + + return ret; +} + + /* index must be 0 - N, as per NDIS */ -static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) +static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, + int index) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_wep_key ndis_key; @@ -1248,8 +1313,8 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) if (index == priv->encr_tx_key_index) { ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY; - ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, - IW_AUTH_CIPHER_NONE); + ret = set_encr_mode(usbdev, RNDIS_WLAN_ALG_WEP, + RNDIS_WLAN_ALG_NONE); if (ret) devwarn(usbdev, "encryption couldn't be enabled (%08X)", ret); @@ -1458,7 +1523,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) /* if it is transmit key, disable encryption */ if (index == priv->encr_tx_key_index) - set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE); + set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); return 0; } @@ -1765,6 +1830,243 @@ static void rndis_get_scan_results(struct work_struct *work) priv->scan_request = NULL; } +static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + struct ieee80211_channel *channel = sme->channel; + struct ndis_80211_ssid ssid; + int pairwise = RNDIS_WLAN_ALG_NONE; + int groupwise = RNDIS_WLAN_ALG_NONE; + int keymgmt = RNDIS_WLAN_KEY_MGMT_NONE; + int length, i, ret, chan = -1; + + if (channel) + chan = ieee80211_frequency_to_channel(channel->center_freq); + + groupwise = rndis_cipher_to_alg(sme->crypto.cipher_group); + for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) + pairwise |= + rndis_cipher_to_alg(sme->crypto.ciphers_pairwise[i]); + + if (sme->crypto.n_ciphers_pairwise > 0 && + pairwise == RNDIS_WLAN_ALG_NONE) { + deverr(usbdev, "Unsupported pairwise cipher"); + return -ENOTSUPP; + } + + for (i = 0; i < sme->crypto.n_akm_suites; i++) + keymgmt |= + rndis_akm_suite_to_key_mgmt(sme->crypto.akm_suites[i]); + + if (sme->crypto.n_akm_suites > 0 && + keymgmt == RNDIS_WLAN_KEY_MGMT_NONE) { + deverr(usbdev, "Invalid keymgmt"); + return -ENOTSUPP; + } + + devdbg(usbdev, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:" + "0x%x]:0x%x)", sme->ssid, sme->bssid, chan, + sme->privacy, sme->crypto.wpa_versions, sme->auth_type, + groupwise, pairwise, keymgmt); + + if (is_associated(usbdev)) + disassociate(usbdev, false); + + ret = set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); + if (ret < 0) { + devdbg(usbdev, "connect: set_infra_mode failed, %d", ret); + goto err_turn_radio_on; + } + + ret = set_auth_mode(usbdev, sme->crypto.wpa_versions, sme->auth_type, + keymgmt); + if (ret < 0) { + devdbg(usbdev, "connect: set_auth_mode failed, %d", ret); + goto err_turn_radio_on; + } + + set_priv_filter(usbdev); + + ret = set_encr_mode(usbdev, pairwise, groupwise); + if (ret < 0) { + devdbg(usbdev, "connect: set_encr_mode failed, %d", ret); + goto err_turn_radio_on; + } + + if (channel) { + ret = set_channel(usbdev, chan); + if (ret < 0) { + devdbg(usbdev, "connect: set_channel failed, %d", ret); + goto err_turn_radio_on; + } + } + + if (sme->key && ((groupwise | pairwise) & RNDIS_WLAN_ALG_WEP)) { + priv->encr_tx_key_index = sme->key_idx; + ret = add_wep_key(usbdev, sme->key, sme->key_len, sme->key_idx); + if (ret < 0) { + devdbg(usbdev, "connect: add_wep_key failed, %d " + "(%d, %d)", ret, sme->key_len, sme->key_idx); + goto err_turn_radio_on; + } + } + + if (sme->bssid && !is_zero_ether_addr(sme->bssid) && + !is_broadcast_ether_addr(sme->bssid)) { + ret = set_bssid(usbdev, sme->bssid); + if (ret < 0) { + devdbg(usbdev, "connect: set_bssid failed, %d", ret); + goto err_turn_radio_on; + } + } else + clear_bssid(usbdev); + + length = sme->ssid_len; + if (length > NDIS_802_11_LENGTH_SSID) + length = NDIS_802_11_LENGTH_SSID; + + memset(&ssid, 0, sizeof(ssid)); + ssid.length = cpu_to_le32(length); + memcpy(ssid.essid, sme->ssid, length); + + /* Pause and purge rx queue, so we don't pass packets before + * 'media connect'-indication. + */ + usbnet_pause_rx(usbdev); + usbnet_purge_paused_rxq(usbdev); + + ret = set_essid(usbdev, &ssid); + if (ret < 0) + devdbg(usbdev, "connect: set_essid failed, %d", ret); + return ret; + +err_turn_radio_on: + disassociate(usbdev, 1); + + return ret; +} + +static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + devdbg(usbdev, "cfg80211.disconnect(%d)", reason_code); + + priv->connected = false; + + return deauthenticate(usbdev); +} + +static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + struct ieee80211_channel *channel = params->channel; + struct ndis_80211_ssid ssid; + enum nl80211_auth_type auth_type; + int ret, alg, length, chan = -1; + + if (channel) + chan = ieee80211_frequency_to_channel(channel->center_freq); + + /* TODO: How to handle ad-hoc encryption? + * connect() has *key, join_ibss() doesn't. RNDIS requires key to be + * pre-shared for encryption (open/shared/wpa), is key set before + * join_ibss? Which auth_type to use (not in params)? What about WPA? + */ + if (params->privacy) { + auth_type = NL80211_AUTHTYPE_SHARED_KEY; + alg = RNDIS_WLAN_ALG_WEP; + } else { + auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; + alg = RNDIS_WLAN_ALG_NONE; + } + + devdbg(usbdev, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)", params->ssid, + params->bssid, chan, params->privacy); + + if (is_associated(usbdev)) + disassociate(usbdev, false); + + ret = set_infra_mode(usbdev, NDIS_80211_INFRA_ADHOC); + if (ret < 0) { + devdbg(usbdev, "join_ibss: set_infra_mode failed, %d", ret); + goto err_turn_radio_on; + } + + ret = set_auth_mode(usbdev, 0, auth_type, RNDIS_WLAN_KEY_MGMT_NONE); + if (ret < 0) { + devdbg(usbdev, "join_ibss: set_auth_mode failed, %d", ret); + goto err_turn_radio_on; + } + + set_priv_filter(usbdev); + + ret = set_encr_mode(usbdev, alg, RNDIS_WLAN_ALG_NONE); + if (ret < 0) { + devdbg(usbdev, "join_ibss: set_encr_mode failed, %d", ret); + goto err_turn_radio_on; + } + + if (channel) { + ret = set_channel(usbdev, chan); + if (ret < 0) { + devdbg(usbdev, "join_ibss: set_channel failed, %d", + ret); + goto err_turn_radio_on; + } + } + + if (params->bssid && !is_zero_ether_addr(params->bssid) && + !is_broadcast_ether_addr(params->bssid)) { + ret = set_bssid(usbdev, params->bssid); + if (ret < 0) { + devdbg(usbdev, "join_ibss: set_bssid failed, %d", ret); + goto err_turn_radio_on; + } + } else + clear_bssid(usbdev); + + length = params->ssid_len; + if (length > NDIS_802_11_LENGTH_SSID) + length = NDIS_802_11_LENGTH_SSID; + + memset(&ssid, 0, sizeof(ssid)); + ssid.length = cpu_to_le32(length); + memcpy(ssid.essid, params->ssid, length); + + /* Don't need to pause rx queue for ad-hoc. */ + usbnet_purge_paused_rxq(usbdev); + usbnet_resume_rx(usbdev); + + ret = set_essid(usbdev, &ssid); + if (ret < 0) + devdbg(usbdev, "join_ibss: set_essid failed, %d", ret); + return ret; + +err_turn_radio_on: + disassociate(usbdev, 1); + + return ret; +} + +static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + devdbg(usbdev, "cfg80211.leave_ibss()"); + + priv->connected = false; + + return deauthenticate(usbdev); +} + /* * wireless extension handlers @@ -1777,7 +2079,10 @@ static int rndis_iw_commit(struct net_device *dev, return 0; } - +#if 0 +/* Commented code out instead of removing to have more sane patch for review. + * Will be removed later in the set. + */ static int rndis_iw_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *essid) { @@ -1990,6 +2295,7 @@ static int rndis_iw_get_auth(struct net_device *dev, } return 0; } +#endif static int rndis_iw_set_encode(struct net_device *dev, @@ -2024,11 +2330,11 @@ static int rndis_iw_set_encode(struct net_device *dev, /* global encryption state (for all keys) */ if (wrqu->data.flags & IW_ENCODE_OPEN) - ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, - IW_AUTH_ALG_OPEN_SYSTEM); + ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, + RNDIS_WLAN_KEY_MGMT_NONE); else /*if (wrqu->data.flags & IW_ENCODE_RESTRICTED)*/ - ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, - IW_AUTH_ALG_SHARED_KEY); + ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_SHARED_KEY, + RNDIS_WLAN_KEY_MGMT_NONE); if (ret != 0) return ret; @@ -2077,7 +2383,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, return -EINVAL; } - if (ext->alg == WPA_ALG_WEP) { + if (ext->alg == IW_ENCODE_ALG_WEP) { if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) priv->encr_tx_key_index = keyidx; return add_wep_key(usbdev, ext->key, ext->key_len, keyidx); @@ -2110,63 +2416,6 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, } -static int rndis_iw_set_genie(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int ret = 0; - -#ifdef DEBUG - int j; - u8 *gie = extra; - for (j = 0; j < wrqu->data.length; j += 8) - devdbg(usbdev, - "SIOCSIWGENIE %04x - " - "%02x %02x %02x %02x %02x %02x %02x %02x", j, - gie[j + 0], gie[j + 1], gie[j + 2], gie[j + 3], - gie[j + 4], gie[j + 5], gie[j + 6], gie[j + 7]); -#endif - /* clear existing IEs */ - if (priv->wpa_ie_len) { - kfree(priv->wpa_ie); - priv->wpa_ie_len = 0; - } - - /* set new IEs */ - priv->wpa_ie = kmalloc(wrqu->data.length, GFP_KERNEL); - if (priv->wpa_ie) { - priv->wpa_ie_len = wrqu->data.length; - memcpy(priv->wpa_ie, extra, priv->wpa_ie_len); - } else - ret = -ENOMEM; - return ret; -} - - -static int rndis_iw_get_genie(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - devdbg(usbdev, "SIOCGIWGENIE"); - - if (priv->wpa_ie_len == 0 || priv->wpa_ie == NULL) { - wrqu->data.length = 0; - return 0; - } - - if (wrqu->data.length < priv->wpa_ie_len) - return -E2BIG; - - wrqu->data.length = priv->wpa_ie_len; - memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); - - return 0; -} - - static int rndis_iw_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2233,32 +2482,6 @@ static int rndis_iw_get_rate(struct net_device *dev, } -static int rndis_iw_set_mlme(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct iw_mlme *mlme = (struct iw_mlme *)extra; - unsigned char bssid[ETH_ALEN]; - - get_bssid(usbdev, bssid); - - if (memcmp(bssid, mlme->addr.sa_data, ETH_ALEN)) - return -EINVAL; - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - return deauthenticate(usbdev); - case IW_MLME_DISASSOC: - return disassociate(usbdev, priv->radio_on); - default: - return -EOPNOTSUPP; - } - - return 0; -} - - static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) { struct usbnet *usbdev = netdev_priv(dev); @@ -2283,12 +2506,12 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, - IW_IOCTL(SIOCSIWAP) = rndis_iw_set_bssid, - IW_IOCTL(SIOCGIWAP) = rndis_iw_get_bssid, + IW_IOCTL(SIOCSIWAP) = (iw_handler) cfg80211_wext_siwap, + IW_IOCTL(SIOCGIWAP) = (iw_handler) cfg80211_wext_giwap, IW_IOCTL(SIOCSIWSCAN) = (iw_handler) cfg80211_wext_siwscan, IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, - IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid, - IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid, + IW_IOCTL(SIOCSIWESSID) = (iw_handler) cfg80211_wext_siwessid, + IW_IOCTL(SIOCGIWESSID) = (iw_handler) cfg80211_wext_giwessid, IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate, IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, @@ -2298,11 +2521,10 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower, IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode, IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext, - IW_IOCTL(SIOCSIWAUTH) = rndis_iw_set_auth, - IW_IOCTL(SIOCGIWAUTH) = rndis_iw_get_auth, - IW_IOCTL(SIOCSIWGENIE) = rndis_iw_set_genie, - IW_IOCTL(SIOCGIWGENIE) = rndis_iw_get_genie, - IW_IOCTL(SIOCSIWMLME) = rndis_iw_set_mlme, + IW_IOCTL(SIOCSIWAUTH) = (iw_handler) cfg80211_wext_siwauth, + IW_IOCTL(SIOCGIWAUTH) = (iw_handler) cfg80211_wext_giwauth, + IW_IOCTL(SIOCSIWGENIE) = (iw_handler) cfg80211_wext_siwgenie, + IW_IOCTL(SIOCSIWMLME) = (iw_handler) cfg80211_wext_siwmlme, }; static const iw_handler rndis_wlan_private_handler[] = { @@ -2325,49 +2547,78 @@ static const struct iw_handler_def rndis_iw_handlers = { static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) { + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_assoc_info *info; - union iwreq_data evt; u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32]; u8 bssid[ETH_ALEN]; + int resp_ie_len, req_ie_len; + u8 *req_ie, *resp_ie; int ret, offset; + bool roamed = false; + + if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) { + /* received media connect indication while connected, either + * device reassociated with same AP or roamed to new. */ + roamed = true; + } + + req_ie_len = 0; + resp_ie_len = 0; + req_ie = NULL; + resp_ie = NULL; + + if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { + memset(assoc_buf, 0, sizeof(assoc_buf)); + info = (void *)assoc_buf; + + /* Get association info IEs from device and send them back to + * userspace. */ + ret = get_association_info(usbdev, info, sizeof(assoc_buf)); + if (!ret) { + req_ie_len = le32_to_cpu(info->req_ie_length); + if (req_ie_len > 0) { + offset = le32_to_cpu(info->offset_req_ies); + req_ie = (u8 *)info + offset; + } - memset(assoc_buf, 0, sizeof(assoc_buf)); - info = (void *)assoc_buf; + resp_ie_len = le32_to_cpu(info->resp_ie_length); + if (resp_ie_len > 0) { + offset = le32_to_cpu(info->offset_resp_ies); + resp_ie = (u8 *)info + offset; + } + } + } else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC)) + return; - netif_carrier_on(usbdev->net); + ret = get_bssid(usbdev, bssid); + if (ret < 0) + memset(bssid, 0, sizeof(bssid)); - /* Get association info IEs from device and send them back to - * userspace. */ - ret = get_association_info(usbdev, info, sizeof(assoc_buf)); - if (!ret) { - evt.data.length = le32_to_cpu(info->req_ie_length); - if (evt.data.length > 0) { - offset = le32_to_cpu(info->offset_req_ies); - wireless_send_event(usbdev->net, - IWEVASSOCREQIE, &evt, - (char *)info + offset); - } + devdbg(usbdev, "link up work: [%pM] %s", bssid, roamed ? "roamed" : ""); - evt.data.length = le32_to_cpu(info->resp_ie_length); - if (evt.data.length > 0) { - offset = le32_to_cpu(info->offset_resp_ies); - wireless_send_event(usbdev->net, - IWEVASSOCRESPIE, &evt, - (char *)info + offset); - } + /* Internal bss list in device always contains at least the currently + * connected bss and we can get it to cfg80211 with + * rndis_check_bssid_list(). + * NOTE: This is true for Broadcom chip, but not mentioned in RNDIS + * spec. + */ + rndis_check_bssid_list(usbdev); - usbnet_resume_rx(usbdev); - } + if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { + if (!roamed) + cfg80211_connect_result(usbdev->net, bssid, req_ie, + req_ie_len, resp_ie, + resp_ie_len, 0, GFP_KERNEL); + else + cfg80211_roamed(usbdev->net, bssid, req_ie, req_ie_len, + resp_ie, resp_ie_len, GFP_KERNEL); + } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) + cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL); - ret = get_bssid(usbdev, bssid); - if (!ret) { - evt.data.flags = 0; - evt.data.length = 0; - memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); - wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); - } + priv->connected = true; usbnet_resume_rx(usbdev); + netif_carrier_on(usbdev->net); } static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) -- cgit v0.10.2 From 5554adbe0d366f6a5096e6f74b48dcad5698c528 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:27:53 +0300 Subject: rndis_wlan: add cfg80211 set_channel Add cfg80211 set_channel and convert wext to use it. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c2af5be..ffb195d 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -517,6 +517,9 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); +static int rndis_set_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, enum nl80211_channel_type channel_type); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, @@ -527,6 +530,7 @@ static struct cfg80211_ops rndis_config_ops = { .disconnect = rndis_disconnect, .join_ibss = rndis_join_ibss, .leave_ibss = rndis_leave_ibss, + .set_channel = rndis_set_channel, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -924,46 +928,6 @@ static int level_to_qual(int level) } -static void dsconfig_to_freq(unsigned int dsconfig, struct iw_freq *freq) -{ - freq->e = 0; - freq->i = 0; - freq->flags = 0; - - /* see comment in wireless.h above the "struct iw_freq" - * definition for an explanation of this if - * NOTE: 1000000 is due to the kHz - */ - if (dsconfig > 1000000) { - freq->m = dsconfig / 10; - freq->e = 1; - } else - freq->m = dsconfig; - - /* convert from kHz to Hz */ - freq->e += 3; -} - - -static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig) -{ - if (freq->m < 1000 && freq->e == 0) { - if (freq->m >= 1 && freq->m <= 14) - *dsconfig = ieee80211_dsss_chan_to_freq(freq->m) * 1000; - else - return -1; - } else { - int i; - *dsconfig = freq->m; - for (i = freq->e; i > 0; i--) - *dsconfig *= 10; - *dsconfig /= 1000; - } - - return 0; -} - - /* * common functions */ @@ -2067,6 +2031,15 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return deauthenticate(usbdev); } +static int rndis_set_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + return set_channel(usbdev, + ieee80211_frequency_to_channel(chan->center_freq)); +} /* * wireless extension handlers @@ -2416,54 +2389,6 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, } -static int rndis_iw_set_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct ndis_80211_conf config; - unsigned int dsconfig; - int len, ret; - - /* this OID is valid only when not associated */ - if (is_associated(usbdev)) - return 0; - - dsconfig = 0; - if (freq_to_dsconfig(&wrqu->freq, &dsconfig)) - return -EINVAL; - - len = sizeof(config); - ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); - if (ret != 0) { - devdbg(usbdev, "SIOCSIWFREQ: querying configuration failed"); - return 0; - } - - config.ds_config = cpu_to_le32(dsconfig); - - devdbg(usbdev, "SIOCSIWFREQ: %d * 10^%d", wrqu->freq.m, wrqu->freq.e); - return rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config, - sizeof(config)); -} - - -static int rndis_iw_get_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct ndis_80211_conf config; - int len, ret; - - len = sizeof(config); - ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); - if (ret == 0) - dsconfig_to_freq(le32_to_cpu(config.ds_config), &wrqu->freq); - - devdbg(usbdev, "SIOCGIWFREQ: %d", wrqu->freq.m); - return ret; -} - - static int rndis_iw_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2501,8 +2426,8 @@ static const iw_handler rndis_iw_handler[] = { IW_IOCTL(SIOCSIWCOMMIT) = rndis_iw_commit, IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, - IW_IOCTL(SIOCSIWFREQ) = rndis_iw_set_freq, - IW_IOCTL(SIOCGIWFREQ) = rndis_iw_get_freq, + IW_IOCTL(SIOCSIWFREQ) = (iw_handler) cfg80211_wext_siwfreq, + IW_IOCTL(SIOCGIWFREQ) = (iw_handler) cfg80211_wext_giwfreq, IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, -- cgit v0.10.2 From 84bf8400cee127be3b58a9d9b8cfa453dad999ab Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:27:58 +0300 Subject: rndis_wlan: add cfg80211 key handling Add cfg80211 add_key/del_key/set_default_key and convert wext to use theim. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index ffb195d..93b504b 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -424,7 +424,7 @@ static const u32 rndis_cipher_suites[] = { struct rndis_wlan_encr_key { int len; - int cipher; + u32 cipher; u8 material[32]; u8 bssid[ETH_ALEN]; bool pairwise; @@ -520,6 +520,16 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); static int rndis_set_channel(struct wiphy *wiphy, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type); +static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, const u8 *mac_addr, + struct key_params *params); + +static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, const u8 *mac_addr); + +static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, @@ -531,6 +541,9 @@ static struct cfg80211_ops rndis_config_ops = { .join_ibss = rndis_join_ibss, .leave_ibss = rndis_leave_ibss, .set_channel = rndis_set_channel, + .add_key = rndis_add_key, + .del_key = rndis_del_key, + .set_default_key = rndis_set_default_key, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -1258,7 +1271,10 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_wep_key ndis_key; - int cipher, ret; + u32 cipher; + int ret; + + devdbg(usbdev, "add_wep_key(idx: %d, len: %d)", index, key_len); if ((key_len != 5 && key_len != 13) || index < 0 || index > 3) return -EINVAL; @@ -1302,8 +1318,8 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, - int index, const u8 *addr, const u8 *rx_seq, int cipher, - int flags) + int index, const u8 *addr, const u8 *rx_seq, + int seq_len, u32 cipher, int flags) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_key ndis_key; @@ -1319,10 +1335,18 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, key_len); return -EINVAL; } - if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) { - devdbg(usbdev, "add_wpa_key: recv seq flag without buffer"); - return -EINVAL; + if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) { + if (!rx_seq || seq_len <= 0) { + devdbg(usbdev, "add_wpa_key: recv seq flag without" + "buffer"); + return -EINVAL; + } + if (rx_seq && seq_len > sizeof(ndis_key.rsc)) { + devdbg(usbdev, "add_wpa_key: too big recv seq buffer"); + return -EINVAL; + } } + is_addr_ok = addr && !is_zero_ether_addr(addr) && !is_broadcast_ether_addr(addr); if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) { @@ -1353,7 +1377,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, memcpy(ndis_key.material, key, key_len); if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) - memcpy(ndis_key.rsc, rx_seq, 6); + memcpy(ndis_key.rsc, rx_seq, seq_len); if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) { /* pairwise key */ @@ -1392,31 +1416,17 @@ static int restore_key(struct usbnet *usbdev, int key_idx) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct rndis_wlan_encr_key key; - int flags; + + if (is_wpa_key(priv, key_idx)) + return 0; key = priv->encr_keys[key_idx]; - devdbg(usbdev, "restore_key: %i:%s:%i", key_idx, - is_wpa_key(priv, key_idx) ? "wpa" : "wep", - key.len); + devdbg(usbdev, "restore_key: %i:%i", key_idx, key.len); if (key.len == 0) return 0; - if (is_wpa_key(priv, key_idx)) { - flags = 0; - - /*if (priv->encr_tx_key_index == key_idx) - flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;*/ - - if (!is_zero_ether_addr(key.bssid) && - !is_broadcast_ether_addr(key.bssid)) - flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; - - return add_wpa_key(usbdev, key.material, key.len, key_idx, - key.bssid, NULL, key.cipher, flags); - } - return add_wep_key(usbdev, key.material, key.len, key_idx); } @@ -1437,7 +1447,7 @@ static void clear_key(struct rndis_wlan_private *priv, int idx) /* remove_key is for both wep and wpa */ -static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) +static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_remove_key remove_key; @@ -2041,6 +2051,69 @@ static int rndis_set_channel(struct wiphy *wiphy, ieee80211_frequency_to_channel(chan->center_freq)); } +static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, const u8 *mac_addr, + struct key_params *params) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + int flags; + + devdbg(usbdev, "rndis_add_key(%i, %pM, %08x)", key_index, mac_addr, + params->cipher); + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + return add_wep_key(usbdev, params->key, params->key_len, + key_index); + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + flags = 0; + + if (params->seq && params->seq_len > 0) + flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; + if (mac_addr) + flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY | + NDIS_80211_ADDKEY_TRANSMIT_KEY; + + return add_wpa_key(usbdev, params->key, params->key_len, + key_index, mac_addr, params->seq, + params->seq_len, params->cipher, flags); + default: + devdbg(usbdev, "rndis_add_key: unsupported cipher %08x", + params->cipher); + return -ENOTSUPP; + } +} + +static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, const u8 *mac_addr) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + devdbg(usbdev, "rndis_del_key(%i, %pM)", key_index, mac_addr); + + return remove_key(usbdev, key_index, mac_addr); +} + +static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + struct rndis_wlan_encr_key key; + + devdbg(usbdev, "rndis_set_default_key(%i)", key_index); + + priv->encr_tx_key_index = key_index; + + key = priv->encr_keys[key_index]; + + return add_wep_key(usbdev, key.material, key.len, key_index); +} + /* * wireless extension handlers */ @@ -2268,7 +2341,6 @@ static int rndis_iw_get_auth(struct net_device *dev, } return 0; } -#endif static int rndis_iw_set_encode(struct net_device *dev, @@ -2387,6 +2459,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher, flags); } +#endif static int rndis_iw_get_rate(struct net_device *dev, @@ -2444,8 +2517,8 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag, IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) cfg80211_wext_siwtxpower, IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower, - IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode, - IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext, + IW_IOCTL(SIOCSIWENCODE) = (iw_handler) cfg80211_wext_siwencode, + IW_IOCTL(SIOCSIWENCODEEXT) = (iw_handler) cfg80211_wext_siwencodeext, IW_IOCTL(SIOCSIWAUTH) = (iw_handler) cfg80211_wext_siwauth, IW_IOCTL(SIOCGIWAUTH) = (iw_handler) cfg80211_wext_giwauth, IW_IOCTL(SIOCSIWGENIE) = (iw_handler) cfg80211_wext_siwgenie, -- cgit v0.10.2 From 8b89a2883be4b6bad8ac0c5928784febb2b34172 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:03 +0300 Subject: rndis_wlan: add cfg80211 get_station Add cfg80211 get_station and convert SIOCGIWRATE and get_wireless_stats to cfg80211. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 93b504b..061bfec 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -444,17 +444,14 @@ struct rndis_wlan_private { struct delayed_work scan_work; struct work_struct work; struct mutex command_lock; - spinlock_t stats_lock; unsigned long work_pending; + int last_qual; struct ieee80211_supported_band band; struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; - struct iw_statistics iwstats; - struct iw_statistics privstats; - int caps; int multicast_size; @@ -472,6 +469,7 @@ struct rndis_wlan_private { int radio_on; int infra_mode; bool connected; + u8 bssid[ETH_ALEN]; struct ndis_80211_ssid essid; __le32 current_command_oid; @@ -530,6 +528,9 @@ static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index); +static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, @@ -544,6 +545,7 @@ static struct cfg80211_ops rndis_config_ops = { .add_key = rndis_add_key, .del_key = rndis_del_key, .set_default_key = rndis_set_default_key, + .get_station = rndis_get_station, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -1931,6 +1933,7 @@ static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, devdbg(usbdev, "cfg80211.disconnect(%d)", reason_code); priv->connected = false; + memset(priv->bssid, 0, ETH_ALEN); return deauthenticate(usbdev); } @@ -2037,6 +2040,7 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) devdbg(usbdev, "cfg80211.leave_ibss()"); priv->connected = false; + memset(priv->bssid, 0, ETH_ALEN); return deauthenticate(usbdev); } @@ -2114,6 +2118,43 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, return add_wep_key(usbdev, key.material, key.len, key_index); } +static void rndis_fill_station_info(struct usbnet *usbdev, + struct station_info *sinfo) +{ + __le32 linkspeed, rssi; + int ret, len; + + memset(sinfo, 0, sizeof(*sinfo)); + + len = sizeof(linkspeed); + ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &linkspeed, &len); + if (ret == 0) { + sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000; + sinfo->filled |= STATION_INFO_TX_BITRATE; + } + + len = sizeof(rssi); + ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); + if (ret == 0) { + sinfo->signal = level_to_qual(le32_to_cpu(rssi)); + sinfo->filled |= STATION_INFO_SIGNAL; + } +} + +static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + if (compare_ether_addr(priv->bssid, mac)) + return -ENOENT; + + rndis_fill_station_info(usbdev, sinfo); + + return 0; +} + /* * wireless extension handlers */ @@ -2459,7 +2500,6 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher, flags); } -#endif static int rndis_iw_get_rate(struct net_device *dev, @@ -2492,6 +2532,7 @@ static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) return &priv->iwstats; } +#endif #define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT] @@ -2510,7 +2551,7 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, IW_IOCTL(SIOCSIWESSID) = (iw_handler) cfg80211_wext_siwessid, IW_IOCTL(SIOCGIWESSID) = (iw_handler) cfg80211_wext_giwessid, - IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate, + IW_IOCTL(SIOCGIWRATE) = (iw_handler) cfg80211_wext_giwrate, IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag, @@ -2539,7 +2580,7 @@ static const struct iw_handler_def rndis_iw_handlers = { .standard = (iw_handler *)rndis_iw_handler, .private = (iw_handler *)rndis_wlan_private_handler, .private_args = (struct iw_priv_args *)rndis_wlan_private_args, - .get_wireless_stats = rndis_get_wireless_stats, + .get_wireless_stats = cfg80211_wireless_stats, }; @@ -2614,6 +2655,7 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL); priv->connected = true; + memcpy(priv->bssid, bssid, ETH_ALEN); usbnet_resume_rx(usbdev); netif_carrier_on(usbdev->net); @@ -2928,64 +2970,30 @@ static void rndis_update_wireless_stats(struct work_struct *work) struct rndis_wlan_private *priv = container_of(work, struct rndis_wlan_private, stats_work.work); struct usbnet *usbdev = priv->usbdev; - struct iw_statistics iwstats; __le32 rssi, tmp; int len, ret, j; - unsigned long flags; int update_jiffies = STATS_UPDATE_JIFFIES; void *buf; - spin_lock_irqsave(&priv->stats_lock, flags); - memcpy(&iwstats, &priv->privstats, sizeof(iwstats)); - spin_unlock_irqrestore(&priv->stats_lock, flags); - - /* only update stats when connected */ - if (!is_associated(usbdev)) { - iwstats.qual.qual = 0; - iwstats.qual.level = 0; - iwstats.qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_INVALID - | IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_INVALID; + /* Only check/do workaround when connected. Calling is_associated() + * also polls device with rndis_command() and catches for media link + * indications. + */ + if (!is_associated(usbdev)) goto end; - } len = sizeof(rssi); ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); + if (ret == 0) + priv->last_qual = level_to_qual(le32_to_cpu(rssi)); devdbg(usbdev, "stats: OID_802_11_RSSI -> %d, rssi:%d", ret, le32_to_cpu(rssi)); - if (ret == 0) { - memset(&iwstats.qual, 0, sizeof(iwstats.qual)); - iwstats.qual.qual = level_to_qual(le32_to_cpu(rssi)); - iwstats.qual.level = level_to_qual(le32_to_cpu(rssi)); - iwstats.qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_INVALID; - } - - memset(&iwstats.discard, 0, sizeof(iwstats.discard)); - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_GEN_XMIT_ERROR, &tmp, &len); - if (ret == 0) - iwstats.discard.misc += le32_to_cpu(tmp); - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_GEN_RCV_ERROR, &tmp, &len); - if (ret == 0) - iwstats.discard.misc += le32_to_cpu(tmp); - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_GEN_RCV_NO_BUFFER, &tmp, &len); - if (ret == 0) - iwstats.discard.misc += le32_to_cpu(tmp); /* Workaround transfer stalls on poor quality links. * TODO: find right way to fix these stalls (as stalls do not happen * with ndiswrapper/windows driver). */ - if (iwstats.qual.qual <= 25) { + if (priv->last_qual <= 25) { /* Decrease stats worker interval to catch stalls. * faster. Faster than 400-500ms causes packet loss, * Slower doesn't catch stalls fast enough. @@ -3013,9 +3021,6 @@ static void rndis_update_wireless_stats(struct work_struct *work) kfree(buf); } end: - spin_lock_irqsave(&priv->stats_lock, flags); - memcpy(&priv->privstats, &iwstats, sizeof(iwstats)); - spin_unlock_irqrestore(&priv->stats_lock, flags); if (update_jiffies >= HZ) update_jiffies = round_jiffies_relative(update_jiffies); @@ -3146,7 +3151,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) priv->usbdev = usbdev; mutex_init(&priv->command_lock); - spin_lock_init(&priv->stats_lock); /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); @@ -3183,14 +3187,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) else usbdev->net->flags &= ~IFF_MULTICAST; - priv->iwstats.qual.qual = 0; - priv->iwstats.qual.level = 0; - priv->iwstats.qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_INVALID - | IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_INVALID; - /* fill-out wiphy structure and register w/ cfg80211 */ memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN); wiphy->privid = rndis_wiphy_privid; -- cgit v0.10.2 From d695df9049199bdeadd81c29104da8e2542062cf Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:09 +0300 Subject: rndis_wlan: add cfg80211 dump_station Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 061bfec..351affe 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -531,6 +531,9 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_info *sinfo); +static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, @@ -546,6 +549,7 @@ static struct cfg80211_ops rndis_config_ops = { .del_key = rndis_del_key, .set_default_key = rndis_set_default_key, .get_station = rndis_get_station, + .dump_station = rndis_dump_station, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -2155,6 +2159,22 @@ static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, return 0; } +static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + if (idx != 0) + return -ENOENT; + + memcpy(mac, priv->bssid, ETH_ALEN); + + rndis_fill_station_info(usbdev, sinfo); + + return 0; +} + /* * wireless extension handlers */ -- cgit v0.10.2 From 305e243e6868eb6cf898183a523455bb9264cd2c Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:14 +0300 Subject: rndis_wlan: rename wireless stats worker to device poller Stats worker no longer poll stats from device anymore. It's still needed to poll device control channel for connect/disconnect events, so rename stats worker as device poller. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 351affe..61a7693 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -440,7 +440,7 @@ struct rndis_wlan_private { struct cfg80211_scan_request *scan_request; struct workqueue_struct *workqueue; - struct delayed_work stats_work; + struct delayed_work dev_poller_work; struct delayed_work scan_work; struct work_struct work; struct mutex command_lock; @@ -2984,15 +2984,16 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev) } -#define STATS_UPDATE_JIFFIES (HZ) -static void rndis_update_wireless_stats(struct work_struct *work) +#define DEVICE_POLLER_JIFFIES (HZ) +static void rndis_device_poller(struct work_struct *work) { struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, stats_work.work); + container_of(work, struct rndis_wlan_private, + dev_poller_work.work); struct usbnet *usbdev = priv->usbdev; __le32 rssi, tmp; int len, ret, j; - int update_jiffies = STATS_UPDATE_JIFFIES; + int update_jiffies = DEVICE_POLLER_JIFFIES; void *buf; /* Only check/do workaround when connected. Calling is_associated() @@ -3007,8 +3008,8 @@ static void rndis_update_wireless_stats(struct work_struct *work) if (ret == 0) priv->last_qual = level_to_qual(le32_to_cpu(rssi)); - devdbg(usbdev, "stats: OID_802_11_RSSI -> %d, rssi:%d", ret, - le32_to_cpu(rssi)); + devdbg(usbdev, "dev-poller: OID_802_11_RSSI -> %d, rssi:%d, qual: %d", + ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi))); /* Workaround transfer stalls on poor quality links. * TODO: find right way to fix these stalls (as stalls do not happen @@ -3019,8 +3020,8 @@ static void rndis_update_wireless_stats(struct work_struct *work) * Slower doesn't catch stalls fast enough. */ j = msecs_to_jiffies(priv->param_workaround_interval); - if (j > STATS_UPDATE_JIFFIES) - j = STATS_UPDATE_JIFFIES; + if (j > DEVICE_POLLER_JIFFIES) + j = DEVICE_POLLER_JIFFIES; else if (j <= 0) j = 1; update_jiffies = j; @@ -3040,8 +3041,8 @@ static void rndis_update_wireless_stats(struct work_struct *work) rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len); kfree(buf); } -end: +end: if (update_jiffies >= HZ) update_jiffies = round_jiffies_relative(update_jiffies); else { @@ -3050,7 +3051,8 @@ end: update_jiffies = j; } - queue_delayed_work(priv->workqueue, &priv->stats_work, update_jiffies); + queue_delayed_work(priv->workqueue, &priv->dev_poller_work, + update_jiffies); } @@ -3175,7 +3177,7 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); INIT_WORK(&priv->work, rndis_wlan_worker); - INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats); + INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller); INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); /* try bind rndis_host */ @@ -3252,7 +3254,7 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) return 0; fail: - cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->dev_poller_work); cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); @@ -3270,7 +3272,7 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) /* turn radio off */ disassociate(usbdev, 0); - cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->dev_poller_work); cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); @@ -3301,8 +3303,8 @@ static int rndis_wlan_reset(struct usbnet *usbdev) (set_multicast_list() also turns on current packet filter) */ set_multicast_list(usbdev); - queue_delayed_work(priv->workqueue, &priv->stats_work, - round_jiffies_relative(STATS_UPDATE_JIFFIES)); + queue_delayed_work(priv->workqueue, &priv->dev_poller_work, + round_jiffies_relative(DEVICE_POLLER_JIFFIES)); return deauthenticate(usbdev); } @@ -3319,7 +3321,7 @@ static int rndis_wlan_stop(struct usbnet *usbdev) retval = disassociate(usbdev, 0); priv->work_pending = 0; - cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->dev_poller_work); cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); -- cgit v0.10.2 From 3334943cefa03a5384060e321e3dd9e686097caf Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:19 +0300 Subject: rndis_wlan: remove unneeded SIOCSIWCOMMIT Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 61a7693..9425b3c 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2179,13 +2179,6 @@ static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, * wireless extension handlers */ -static int rndis_iw_commit(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - /* dummy op */ - return 0; -} - #if 0 /* Commented code out instead of removing to have more sane patch for review. * Will be removed later in the set. @@ -2558,7 +2551,6 @@ static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) #define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT] static const iw_handler rndis_iw_handler[] = { - IW_IOCTL(SIOCSIWCOMMIT) = rndis_iw_commit, IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, IW_IOCTL(SIOCSIWFREQ) = (iw_handler) cfg80211_wext_siwfreq, IW_IOCTL(SIOCGIWFREQ) = (iw_handler) cfg80211_wext_giwfreq, -- cgit v0.10.2 From a0f9ce2ac35a0c57413dafd90e316c4048d1b43e Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:24 +0300 Subject: rndis_wlan: convert mic failure wireless event to cfg80211 Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9425b3c..c0c6d66 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2720,9 +2720,10 @@ static void rndis_wlan_auth_indication(struct usbnet *usbdev, { u8 *buf; const char *type; - int flags, buflen; + int flags, buflen, key_id; bool pairwise_error, group_error; struct ndis_80211_auth_request *auth_req; + enum nl80211_key_type key_type; /* must have at least one array entry */ if (len < offsetof(struct ndis_80211_status_indication, u) + @@ -2758,23 +2759,24 @@ static void rndis_wlan_auth_indication(struct usbnet *usbdev, devinfo(usbdev, "authentication indication: %s (0x%08x)", type, le32_to_cpu(auth_req->flags)); - if (pairwise_error || group_error) { - union iwreq_data wrqu; - struct iw_michaelmicfailure micfailure; + if (pairwise_error) { + key_type = NL80211_KEYTYPE_PAIRWISE; + key_id = -1; - memset(&micfailure, 0, sizeof(micfailure)); - if (pairwise_error) - micfailure.flags |= IW_MICFAILURE_PAIRWISE; - if (group_error) - micfailure.flags |= IW_MICFAILURE_GROUP; + cfg80211_michael_mic_failure(usbdev->net, + auth_req->bssid, + key_type, key_id, NULL, + GFP_KERNEL); + } - memcpy(micfailure.src_addr.sa_data, auth_req->bssid, - ETH_ALEN); + if (group_error) { + key_type = NL80211_KEYTYPE_GROUP; + key_id = -1; - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = sizeof(micfailure); - wireless_send_event(usbdev->net, IWEVMICHAELMICFAILURE, - &wrqu, (u8 *)&micfailure); + cfg80211_michael_mic_failure(usbdev->net, + auth_req->bssid, + key_type, key_id, NULL, + GFP_KERNEL); } buflen -= le32_to_cpu(auth_req->length); -- cgit v0.10.2 From 21ec2d8d0fee4f3bf0d2e25e5b63bf2637233b43 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:30 +0300 Subject: rndis_wlan: disable IWEVPMKIDCAND wireless event Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c0c6d66..9d9750d 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2821,14 +2821,16 @@ static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, return; for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) { - struct iw_pmkid_cand pcand; - union iwreq_data wrqu; struct ndis_80211_pmkid_candidate *cand = &cand_list->candidate_list[i]; devdbg(usbdev, "cand[%i]: flags: 0x%08x, bssid: %pM", i, le32_to_cpu(cand->flags), cand->bssid); +#if 0 + struct iw_pmkid_cand pcand; + union iwreq_data wrqu; + memset(&pcand, 0, sizeof(pcand)); if (le32_to_cpu(cand->flags) & 0x01) pcand.flags |= IW_PMKID_CAND_PREAUTH; @@ -2839,6 +2841,7 @@ static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, wrqu.data.length = sizeof(pcand); wireless_send_event(usbdev->net, IWEVPMKIDCAND, &wrqu, (u8 *)&pcand); +#endif } } -- cgit v0.10.2 From 04a6445f6f5e439ef775bd18cf3f485f84bbfb1b Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:35 +0300 Subject: rndis_wlan: use cfg80211_wext_handler Now that cfg80211 functions are added and wext converted to use wext-compat functions, remove wext structures and disabled code. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9d9750d..402d367 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2175,426 +2175,6 @@ static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, return 0; } -/* - * wireless extension handlers - */ - -#if 0 -/* Commented code out instead of removing to have more sane patch for review. - * Will be removed later in the set. - */ -static int rndis_iw_set_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct ndis_80211_ssid ssid; - int length = wrqu->essid.length; - struct usbnet *usbdev = netdev_priv(dev); - - devdbg(usbdev, "SIOCSIWESSID: [flags:%d,len:%d] '%.32s'", - wrqu->essid.flags, wrqu->essid.length, essid); - - if (length > NDIS_802_11_LENGTH_SSID) - length = NDIS_802_11_LENGTH_SSID; - - ssid.length = cpu_to_le32(length); - if (length > 0) - memcpy(ssid.essid, essid, length); - else - memset(ssid.essid, 0, NDIS_802_11_LENGTH_SSID); - - set_assoc_params(usbdev); - - if (!wrqu->essid.flags || length == 0) - return disassociate(usbdev, 1); - else { - /* Pause and purge rx queue, so we don't pass packets before - * 'media connect'-indication. - */ - usbnet_pause_rx(usbdev); - usbnet_purge_paused_rxq(usbdev); - - return set_essid(usbdev, &ssid); - } -} - - -static int rndis_iw_get_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct ndis_80211_ssid ssid; - struct usbnet *usbdev = netdev_priv(dev); - int ret; - - ret = get_essid(usbdev, &ssid); - - if (ret == 0 && le32_to_cpu(ssid.length) > 0) { - wrqu->essid.flags = 1; - wrqu->essid.length = le32_to_cpu(ssid.length); - memcpy(essid, ssid.essid, wrqu->essid.length); - essid[wrqu->essid.length] = 0; - } else { - memset(essid, 0, sizeof(NDIS_802_11_LENGTH_SSID)); - wrqu->essid.flags = 0; - wrqu->essid.length = 0; - } - devdbg(usbdev, "SIOCGIWESSID: %s", essid); - return ret; -} - - -static int rndis_iw_get_bssid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - unsigned char bssid[ETH_ALEN]; - int ret; - - ret = get_bssid(usbdev, bssid); - - if (ret == 0) - devdbg(usbdev, "SIOCGIWAP: %pM", bssid); - else - devdbg(usbdev, "SIOCGIWAP: "); - - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu->ap_addr.sa_data, bssid, ETH_ALEN); - - return ret; -} - - -static int rndis_iw_set_bssid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - u8 *bssid = (u8 *)wrqu->ap_addr.sa_data; - int ret; - - devdbg(usbdev, "SIOCSIWAP: %pM", bssid); - - ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN); - - /* user apps may set ap's mac address, which is not required; - * they may fail to work if this function fails, so return - * success */ - if (ret) - devwarn(usbdev, "setting AP mac address failed (%08X)", ret); - - return 0; -} - - -static int rndis_iw_set_auth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int ret = -ENOTSUPP; - - switch (p->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - devdbg(usbdev, "SIOCSIWAUTH: WPA_VERSION, %08x", p->value); - priv->wpa_version = p->value; - ret = 0; - break; - - case IW_AUTH_CIPHER_PAIRWISE: - devdbg(usbdev, "SIOCSIWAUTH: CIPHER_PAIRWISE, %08x", p->value); - priv->wpa_cipher_pair = p->value; - ret = 0; - break; - - case IW_AUTH_CIPHER_GROUP: - devdbg(usbdev, "SIOCSIWAUTH: CIPHER_GROUP, %08x", p->value); - priv->wpa_cipher_group = p->value; - ret = 0; - break; - - case IW_AUTH_KEY_MGMT: - devdbg(usbdev, "SIOCSIWAUTH: KEY_MGMT, %08x", p->value); - priv->wpa_keymgmt = p->value; - ret = 0; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - devdbg(usbdev, "SIOCSIWAUTH: TKIP_COUNTERMEASURES, %08x", - p->value); - ret = 0; - break; - - case IW_AUTH_DROP_UNENCRYPTED: - devdbg(usbdev, "SIOCSIWAUTH: DROP_UNENCRYPTED, %08x", p->value); - ret = 0; - break; - - case IW_AUTH_80211_AUTH_ALG: - devdbg(usbdev, "SIOCSIWAUTH: 80211_AUTH_ALG, %08x", p->value); - priv->wpa_authalg = p->value; - ret = 0; - break; - - case IW_AUTH_WPA_ENABLED: - devdbg(usbdev, "SIOCSIWAUTH: WPA_ENABLED, %08x", p->value); - if (wrqu->param.value) - deauthenticate(usbdev); - ret = 0; - break; - - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - devdbg(usbdev, "SIOCSIWAUTH: RX_UNENCRYPTED_EAPOL, %08x", - p->value); - ret = 0; - break; - - case IW_AUTH_ROAMING_CONTROL: - devdbg(usbdev, "SIOCSIWAUTH: ROAMING_CONTROL, %08x", p->value); - ret = 0; - break; - - case IW_AUTH_PRIVACY_INVOKED: - devdbg(usbdev, "SIOCSIWAUTH: invalid cmd %d", - wrqu->param.flags & IW_AUTH_INDEX); - return -EOPNOTSUPP; - - default: - devdbg(usbdev, "SIOCSIWAUTH: UNKNOWN %08x, %08x", - p->flags & IW_AUTH_INDEX, p->value); - } - return ret; -} - - -static int rndis_iw_get_auth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - switch (p->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - p->value = priv->wpa_version; - break; - case IW_AUTH_CIPHER_PAIRWISE: - p->value = priv->wpa_cipher_pair; - break; - case IW_AUTH_CIPHER_GROUP: - p->value = priv->wpa_cipher_group; - break; - case IW_AUTH_KEY_MGMT: - p->value = priv->wpa_keymgmt; - break; - case IW_AUTH_80211_AUTH_ALG: - p->value = priv->wpa_authalg; - break; - default: - devdbg(usbdev, "SIOCGIWAUTH: invalid cmd %d", - wrqu->param.flags & IW_AUTH_INDEX); - return -EOPNOTSUPP; - } - return 0; -} - - -static int rndis_iw_set_encode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_wlan_encr_key key; - int ret, index, key_len; - u8 *keybuf; - - index = (wrqu->encoding.flags & IW_ENCODE_INDEX); - - /* iwconfig gives index as 1 - N */ - if (index > 0) - index--; - else - index = priv->encr_tx_key_index; - - if (index < 0 || index >= 4) { - devwarn(usbdev, "encryption index out of range (%u)", index); - return -EINVAL; - } - - /* remove key if disabled */ - if (wrqu->data.flags & IW_ENCODE_DISABLED) { - if (remove_key(usbdev, index, NULL)) - return -EINVAL; - else - return 0; - } - - /* global encryption state (for all keys) */ - if (wrqu->data.flags & IW_ENCODE_OPEN) - ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, - RNDIS_WLAN_KEY_MGMT_NONE); - else /*if (wrqu->data.flags & IW_ENCODE_RESTRICTED)*/ - ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_SHARED_KEY, - RNDIS_WLAN_KEY_MGMT_NONE); - if (ret != 0) - return ret; - - if (wrqu->data.length > 0) { - key_len = wrqu->data.length; - keybuf = extra; - } else { - /* must be set as tx key */ - if (priv->encr_keys[index].len == 0) - return -EINVAL; - key = priv->encr_keys[index]; - key_len = key.len; - keybuf = key.material; - priv->encr_tx_key_index = index; - } - - if (add_wep_key(usbdev, keybuf, key_len, index) != 0) - return -EINVAL; - - if (index == priv->encr_tx_key_index) - /* ndis drivers want essid to be set after setting encr */ - set_essid(usbdev, &priv->essid); - - return 0; -} - - -static int rndis_iw_set_encode_ext(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int keyidx, flags, cipher; - - keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; - - /* iwconfig gives index as 1 - N */ - if (keyidx) - keyidx--; - else - keyidx = priv->encr_tx_key_index; - - if (keyidx < 0 || keyidx >= 4) { - devwarn(usbdev, "encryption index out of range (%u)", keyidx); - return -EINVAL; - } - - if (ext->alg == IW_ENCODE_ALG_WEP) { - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - priv->encr_tx_key_index = keyidx; - return add_wep_key(usbdev, ext->key, ext->key_len, keyidx); - } - - cipher = -1; - if (ext->alg == IW_ENCODE_ALG_TKIP) - cipher = WLAN_CIPHER_SUITE_TKIP; - else if (ext->alg == IW_ENCODE_ALG_CCMP) - cipher = WLAN_CIPHER_SUITE_CCMP; - - if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) || - ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) - return remove_key(usbdev, keyidx, NULL); - - if (cipher == -1) - return -EOPNOTSUPP; - - flags = 0; - if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; - if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) - flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY; - - return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, - (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher, - flags); -} - - -static int rndis_iw_get_rate(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - __le32 tmp; - int ret, len; - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &tmp, &len); - if (ret == 0) { - wrqu->bitrate.value = le32_to_cpu(tmp) * 100; - wrqu->bitrate.disabled = 0; - wrqu->bitrate.flags = 1; - } - return ret; -} - - -static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - unsigned long flags; - - spin_lock_irqsave(&priv->stats_lock, flags); - memcpy(&priv->iwstats, &priv->privstats, sizeof(priv->iwstats)); - spin_unlock_irqrestore(&priv->stats_lock, flags); - - return &priv->iwstats; -} -#endif - - -#define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT] -static const iw_handler rndis_iw_handler[] = -{ - IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, - IW_IOCTL(SIOCSIWFREQ) = (iw_handler) cfg80211_wext_siwfreq, - IW_IOCTL(SIOCGIWFREQ) = (iw_handler) cfg80211_wext_giwfreq, - IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, - IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, - IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, - IW_IOCTL(SIOCSIWAP) = (iw_handler) cfg80211_wext_siwap, - IW_IOCTL(SIOCGIWAP) = (iw_handler) cfg80211_wext_giwap, - IW_IOCTL(SIOCSIWSCAN) = (iw_handler) cfg80211_wext_siwscan, - IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, - IW_IOCTL(SIOCSIWESSID) = (iw_handler) cfg80211_wext_siwessid, - IW_IOCTL(SIOCGIWESSID) = (iw_handler) cfg80211_wext_giwessid, - IW_IOCTL(SIOCGIWRATE) = (iw_handler) cfg80211_wext_giwrate, - IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, - IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, - IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag, - IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag, - IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) cfg80211_wext_siwtxpower, - IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower, - IW_IOCTL(SIOCSIWENCODE) = (iw_handler) cfg80211_wext_siwencode, - IW_IOCTL(SIOCSIWENCODEEXT) = (iw_handler) cfg80211_wext_siwencodeext, - IW_IOCTL(SIOCSIWAUTH) = (iw_handler) cfg80211_wext_siwauth, - IW_IOCTL(SIOCGIWAUTH) = (iw_handler) cfg80211_wext_giwauth, - IW_IOCTL(SIOCSIWGENIE) = (iw_handler) cfg80211_wext_siwgenie, - IW_IOCTL(SIOCSIWMLME) = (iw_handler) cfg80211_wext_siwmlme, -}; - -static const iw_handler rndis_wlan_private_handler[] = { -}; - -static const struct iw_priv_args rndis_wlan_private_args[] = { -}; - - -static const struct iw_handler_def rndis_iw_handlers = { - .num_standard = ARRAY_SIZE(rndis_iw_handler), - .num_private = ARRAY_SIZE(rndis_wlan_private_handler), - .num_private_args = ARRAY_SIZE(rndis_wlan_private_args), - .standard = (iw_handler *)rndis_iw_handler, - .private = (iw_handler *)rndis_wlan_private_handler, - .private_args = (struct iw_priv_args *)rndis_wlan_private_args, - .get_wireless_stats = cfg80211_wireless_stats, -}; - static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) { @@ -3166,7 +2746,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) * Otherwise we'll be in big trouble in rndis_wlan_early_init(). */ usbdev->driver_priv = priv; - usbdev->net->wireless_handlers = &rndis_iw_handlers; priv->usbdev = usbdev; mutex_init(&priv->command_lock); -- cgit v0.10.2 From ad43f8bfb7b9a6a8b800cdad24c4a62180a5eb3d Mon Sep 17 00:00:00 2001 From: Kiran Divekar Date: Fri, 28 Aug 2009 17:47:59 +0530 Subject: libertas: add NULL check on return value of get_zeroed_page Most of the places in debugfs.c are missing a NULL check on the return value of get_zeroed_page API call. Added required NULL check at appropriate places. Signed-off-by: Kiran Divekar Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 811ffc3..893a55c 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -45,6 +45,8 @@ static ssize_t lbs_dev_info(struct file *file, char __user *userbuf, unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; ssize_t res; + if (!buf) + return -ENOMEM; pos += snprintf(buf+pos, len-pos, "state = %s\n", szStates[priv->connect_status]); @@ -68,6 +70,8 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, char *buf = (char *)addr; DECLARE_SSID_BUF(ssid); struct bss_descriptor * iter_bss; + if (!buf) + return -ENOMEM; pos += snprintf(buf+pos, len-pos, "# | ch | rssi | bssid | cap | Qual | SSID \n"); @@ -110,6 +114,8 @@ static ssize_t lbs_sleepparams_write(struct file *file, int p1, p2, p3, p4, p5, p6; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, user_buf, buf_size)) { @@ -148,6 +154,8 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf, struct sleep_params sp; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp); if (ret) @@ -433,6 +441,8 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; offval.offset = priv->mac_offset; offval.value = 0; @@ -457,6 +467,8 @@ static ssize_t lbs_rdmac_write(struct file *file, ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -481,6 +493,8 @@ static ssize_t lbs_wrmac_write(struct file *file, struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -515,6 +529,8 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf, int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; offval.offset = priv->bbp_offset; offval.value = 0; @@ -540,6 +556,8 @@ static ssize_t lbs_rdbbp_write(struct file *file, ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -564,6 +582,8 @@ static ssize_t lbs_wrbbp_write(struct file *file, struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -598,6 +618,8 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf, int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; offval.offset = priv->rf_offset; offval.value = 0; @@ -623,6 +645,8 @@ static ssize_t lbs_rdrf_write(struct file *file, ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -647,6 +671,8 @@ static ssize_t lbs_wrrf_write(struct file *file, struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -853,6 +879,8 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, struct debug_data *d; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; p = buf; -- cgit v0.10.2 From 96f845de89be6be12112d7b388cdf366dccfe12d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 29 Aug 2009 00:49:36 +0200 Subject: ALSA: hda - Create "Digital Mic Capture Volume" correctly for IDT codecs So far, the digital mic capture volume wasn't created. This is because IDT codecs have output amps for digital mics, not input amps, while input amps should be used for other analog pins. Thus the automatic capture volume creation should check both directions for digital mics. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 742b9c8..c878dfa 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3580,21 +3580,30 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, } /* create a volume assigned to the given pin (only if supported) */ +/* return 1 if the volume control is created */ static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid, - const char *label) + const char *label, int direction) { unsigned int caps, nums; char name[32]; + int err; - if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) + if (direction == HDA_OUTPUT) + caps = AC_WCAP_OUT_AMP; + else + caps = AC_WCAP_IN_AMP; + if (!(get_wcaps(codec, nid) & caps)) return 0; - caps = query_amp_caps(codec, nid, HDA_OUTPUT); + caps = query_amp_caps(codec, nid, direction); nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; if (!nums) return 0; snprintf(name, sizeof(name), "%s Capture Volume", label); - return stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + err = stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction)); + if (err < 0) + return err; + return 1; } /* create playback/capture controls for input pins on dmic capable codecs */ @@ -3643,9 +3652,15 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, else label = stac92xx_dmic_labels[dimux->num_items]; - err = create_elem_capture_vol(codec, nid, label); + err = create_elem_capture_vol(codec, nid, label, HDA_INPUT); if (err < 0) return err; + if (!err) { + err = create_elem_capture_vol(codec, nid, label, + HDA_OUTPUT); + if (err < 0) + return err; + } dimux->items[dimux->num_items].label = label; dimux->items[dimux->num_items].index = index; @@ -3766,7 +3781,8 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const continue; err = create_elem_capture_vol(codec, nid, - auto_pin_cfg_labels[i]); + auto_pin_cfg_labels[i], + HDA_INPUT); if (err < 0) return err; -- cgit v0.10.2 From 2a4ab640d3c28c2952967e5f63ea495555bf2a5f Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Tue, 7 Jul 2009 23:01:15 -0400 Subject: ACPI, x86: expose some IO-APIC routines when CONFIG_ACPI=n Some IO-APIC routines are ACPI specific now, but need to be exposed when CONFIG_ACPI=n for the benefit of SFI. Remove #ifdef ACPI around these routines: io_apic_get_unique_id(int ioapic, int apic_id); io_apic_get_version(int ioapic); io_apic_get_redir_entries(int ioapic); Move these routines from ACPI-specific boot.c to io_apic.c: uniq_ioapic_id(u8 id) mp_find_ioapic() mp_find_ioapic_pin() mp_register_ioapic() Also, since uniq_ioapic_id() is now no longer static, re-name it to io_apic_unique_id() for consistency with the other public io_apic routines. For simplicity, do not #ifdef the resulting code ACPI || SFI, thought that could be done in the future if it is important to optimize the !ACPI !SFI IO-APIC x86 kernel for size. Signed-off-by: Feng Tang Signed-off-by: Len Brown Cc: x86@kernel.org diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 330ee80..85232d3 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -150,11 +150,10 @@ extern int timer_through_8259; #define io_apic_assign_pci_irqs \ (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs) -#ifdef CONFIG_ACPI +extern u8 io_apic_unique_id(u8 id); extern int io_apic_get_unique_id(int ioapic, int apic_id); extern int io_apic_get_version(int ioapic); extern int io_apic_get_redir_entries(int ioapic); -#endif /* CONFIG_ACPI */ struct io_apic_irq_attr; extern int io_apic_set_pci_routing(struct device *dev, int irq, @@ -177,6 +176,16 @@ extern int setup_ioapic_entry(int apic, int irq, int polarity, int vector, int pin); extern void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e); + +struct mp_ioapic_gsi{ + int gsi_base; + int gsi_end; +}; +extern struct mp_ioapic_gsi mp_gsi_routing[]; +int mp_find_ioapic(int gsi); +int mp_find_ioapic_pin(int ioapic, int gsi); +void __init mp_register_ioapic(int id, u32 address, u32 gsi_base); + #else /* !CONFIG_X86_IO_APIC */ #define io_apic_assign_pci_irqs 0 static const int timer_through_8259 = 0; diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 6b8ca3a..7e62d1e 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -833,106 +833,6 @@ static int __init acpi_parse_madt_lapic_entries(void) extern int es7000_plat; #endif -static struct { - int gsi_base; - int gsi_end; -} mp_ioapic_routing[MAX_IO_APICS]; - -int mp_find_ioapic(int gsi) -{ - int i = 0; - - /* Find the IOAPIC that manages this GSI. */ - for (i = 0; i < nr_ioapics; i++) { - if ((gsi >= mp_ioapic_routing[i].gsi_base) - && (gsi <= mp_ioapic_routing[i].gsi_end)) - return i; - } - - printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi); - return -1; -} - -int mp_find_ioapic_pin(int ioapic, int gsi) -{ - if (WARN_ON(ioapic == -1)) - return -1; - if (WARN_ON(gsi > mp_ioapic_routing[ioapic].gsi_end)) - return -1; - - return gsi - mp_ioapic_routing[ioapic].gsi_base; -} - -static u8 __init uniq_ioapic_id(u8 id) -{ -#ifdef CONFIG_X86_32 - if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && - !APIC_XAPIC(apic_version[boot_cpu_physical_apicid])) - return io_apic_get_unique_id(nr_ioapics, id); - else - return id; -#else - int i; - DECLARE_BITMAP(used, 256); - bitmap_zero(used, 256); - for (i = 0; i < nr_ioapics; i++) { - struct mpc_ioapic *ia = &mp_ioapics[i]; - __set_bit(ia->apicid, used); - } - if (!test_bit(id, used)) - return id; - return find_first_zero_bit(used, 256); -#endif -} - -static int bad_ioapic(unsigned long address) -{ - if (nr_ioapics >= MAX_IO_APICS) { - printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded " - "(found %d)\n", MAX_IO_APICS, nr_ioapics); - panic("Recompile kernel with bigger MAX_IO_APICS!\n"); - } - if (!address) { - printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address" - " found in table, skipping!\n"); - return 1; - } - return 0; -} - -void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) -{ - int idx = 0; - - if (bad_ioapic(address)) - return; - - idx = nr_ioapics; - - mp_ioapics[idx].type = MP_IOAPIC; - mp_ioapics[idx].flags = MPC_APIC_USABLE; - mp_ioapics[idx].apicaddr = address; - - set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); - mp_ioapics[idx].apicid = uniq_ioapic_id(id); - mp_ioapics[idx].apicver = io_apic_get_version(idx); - - /* - * Build basic GSI lookup table to facilitate gsi->io_apic lookups - * and to prevent reprogramming of IOAPIC pins (PCI GSIs). - */ - mp_ioapic_routing[idx].gsi_base = gsi_base; - mp_ioapic_routing[idx].gsi_end = gsi_base + - io_apic_get_redir_entries(idx); - - printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, " - "GSI %d-%d\n", idx, mp_ioapics[idx].apicid, - mp_ioapics[idx].apicver, mp_ioapics[idx].apicaddr, - mp_ioapic_routing[idx].gsi_base, mp_ioapic_routing[idx].gsi_end); - - nr_ioapics++; -} - int __init acpi_probe_gsi(void) { int idx; @@ -947,7 +847,7 @@ int __init acpi_probe_gsi(void) max_gsi = 0; for (idx = 0; idx < nr_ioapics; idx++) { - gsi = mp_ioapic_routing[idx].gsi_end; + gsi = mp_gsi_routing[idx].gsi_end; if (gsi > max_gsi) max_gsi = gsi; diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index d2ed6c5..a8c0232 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -85,6 +85,9 @@ int nr_ioapic_registers[MAX_IO_APICS]; struct mpc_ioapic mp_ioapics[MAX_IO_APICS]; int nr_ioapics; +/* IO APIC gsi routing info */ +struct mp_ioapic_gsi mp_gsi_routing[MAX_IO_APICS]; + /* MP IRQ source entries */ struct mpc_intsrc mp_irqs[MAX_IRQ_SOURCES]; @@ -3941,11 +3944,28 @@ int io_apic_set_pci_routing(struct device *dev, int irq, return __io_apic_set_pci_routing(dev, irq, irq_attr); } -/* -------------------------------------------------------------------------- - ACPI-based IOAPIC Configuration - -------------------------------------------------------------------------- */ +u8 __init io_apic_unique_id(u8 id) +{ +#ifdef CONFIG_X86_32 + if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && + !APIC_XAPIC(apic_version[boot_cpu_physical_apicid])) + return io_apic_get_unique_id(nr_ioapics, id); + else + return id; +#else + int i; + DECLARE_BITMAP(used, 256); -#ifdef CONFIG_ACPI + bitmap_zero(used, 256); + for (i = 0; i < nr_ioapics; i++) { + struct mpc_ioapic *ia = &mp_ioapics[i]; + __set_bit(ia->apicid, used); + } + if (!test_bit(id, used)) + return id; + return find_first_zero_bit(used, 256); +#endif +} #ifdef CONFIG_X86_32 int __init io_apic_get_unique_id(int ioapic, int apic_id) @@ -4054,8 +4074,6 @@ int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity) return 0; } -#endif /* CONFIG_ACPI */ - /* * This function currently is only a helper for the i386 smp boot process where * we need to reprogram the ioredtbls to cater for the cpus which have come online @@ -4201,3 +4219,76 @@ void __init ioapic_insert_resources(void) r++; } } + +int mp_find_ioapic(int gsi) +{ + int i = 0; + + /* Find the IOAPIC that manages this GSI. */ + for (i = 0; i < nr_ioapics; i++) { + if ((gsi >= mp_gsi_routing[i].gsi_base) + && (gsi <= mp_gsi_routing[i].gsi_end)) + return i; + } + + printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi); + return -1; +} + +int mp_find_ioapic_pin(int ioapic, int gsi) +{ + if (WARN_ON(ioapic == -1)) + return -1; + if (WARN_ON(gsi > mp_gsi_routing[ioapic].gsi_end)) + return -1; + + return gsi - mp_gsi_routing[ioapic].gsi_base; +} + +static int bad_ioapic(unsigned long address) +{ + if (nr_ioapics >= MAX_IO_APICS) { + printk(KERN_WARNING "WARING: Max # of I/O APICs (%d) exceeded " + "(found %d), skipping\n", MAX_IO_APICS, nr_ioapics); + return 1; + } + if (!address) { + printk(KERN_WARNING "WARNING: Bogus (zero) I/O APIC address" + " found in table, skipping!\n"); + return 1; + } + return 0; +} + +void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) +{ + int idx = 0; + + if (bad_ioapic(address)) + return; + + idx = nr_ioapics; + + mp_ioapics[idx].type = MP_IOAPIC; + mp_ioapics[idx].flags = MPC_APIC_USABLE; + mp_ioapics[idx].apicaddr = address; + + set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); + mp_ioapics[idx].apicid = io_apic_unique_id(id); + mp_ioapics[idx].apicver = io_apic_get_version(idx); + + /* + * Build basic GSI lookup table to facilitate gsi->io_apic lookups + * and to prevent reprogramming of IOAPIC pins (PCI GSIs). + */ + mp_gsi_routing[idx].gsi_base = gsi_base; + mp_gsi_routing[idx].gsi_end = gsi_base + + io_apic_get_redir_entries(idx); + + printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, " + "GSI %d-%d\n", idx, mp_ioapics[idx].apicid, + mp_ioapics[idx].apicver, mp_ioapics[idx].apicaddr, + mp_gsi_routing[idx].gsi_base, mp_gsi_routing[idx].gsi_end); + + nr_ioapics++; +} -- cgit v0.10.2 From 278339a42a1bcef1fb448d275056d519307e6025 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Fri, 28 Aug 2009 12:05:12 +0000 Subject: bonding: propogate vlan_features to bonding master Propogate the vlan_features of the slave devices to the bonding master device, using the same logic as for regular features. Tested by Or Gerlitz , who also removed the debug logic from the original test patch. Signed-off-by: Or Gerlitz Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 4798d30..1aeb36c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1331,6 +1331,7 @@ static int bond_compute_features(struct bonding *bond) struct slave *slave; struct net_device *bond_dev = bond->dev; unsigned long features = bond_dev->features; + unsigned long vlan_features = 0; unsigned short max_hard_header_len = max((u16)ETH_HLEN, bond_dev->hard_header_len); int i; @@ -1343,10 +1344,14 @@ static int bond_compute_features(struct bonding *bond) features &= ~NETIF_F_ONE_FOR_ALL; + vlan_features = bond->first_slave->dev->vlan_features; bond_for_each_slave(bond, slave, i) { features = netdev_increment_features(features, slave->dev->features, NETIF_F_ONE_FOR_ALL); + vlan_features = netdev_increment_features(vlan_features, + slave->dev->vlan_features, + NETIF_F_ONE_FOR_ALL); if (slave->dev->hard_header_len > max_hard_header_len) max_hard_header_len = slave->dev->hard_header_len; } @@ -1354,6 +1359,7 @@ static int bond_compute_features(struct bonding *bond) done: features |= (bond_dev->features & BOND_VLAN_FEATURES); bond_dev->features = netdev_fix_features(features, NULL); + bond_dev->vlan_features = netdev_fix_features(vlan_features, NULL); bond_dev->hard_header_len = max_hard_header_len; return 0; -- cgit v0.10.2 From 89c76c62f191daa7ede3d1d0c510a5ccfbcae571 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 28 Aug 2009 12:05:13 +0000 Subject: bonding: use compare_ether_addr Bonding can use compare_ether_addr() in bond_release. Signed-off-by: Stephen Hemminger Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 1aeb36c..ed00ba9 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1796,7 +1796,6 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *oldcurrent; struct sockaddr addr; - int mac_addr_differ; /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || @@ -1820,9 +1819,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) } if (!bond->params.fail_over_mac) { - mac_addr_differ = memcmp(bond_dev->dev_addr, slave->perm_hwaddr, - ETH_ALEN); - if (!mac_addr_differ && (bond->slave_cnt > 1)) + if (!compare_ether_addr(bond_dev->dev_addr, slave->perm_hwaddr) + && bond->slave_cnt > 1) pr_warning(DRV_NAME ": %s: Warning: the permanent HWaddr of %s - " "%pM - is still in use by %s. " -- cgit v0.10.2 From f584130616dfae757b888b7ee472e7c824f59e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20de=20Peslo=C3=BCan?= Date: Fri, 28 Aug 2009 13:18:34 +0000 Subject: bonding: Fix useless test: int > INT_MAX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit max_bonds is of type int and cannot be greater than INT_MAX. Signed-off-by: Nicolas de Pesloüan Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ed00ba9..6b9f15b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4759,7 +4759,7 @@ static int bond_check_params(struct bond_params *params) params->ad_select = BOND_AD_STABLE; } - if (max_bonds < 0 || max_bonds > INT_MAX) { + if (max_bonds < 0) { pr_warning(DRV_NAME ": Warning: max_bonds (%d) not in range %d-%d, so it " "was reset to BOND_DEFAULT_MAX_BONDS (%d)\n", -- cgit v0.10.2 From 6c9888532bb540cb692f51f1d34fe9344eed5a0d Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Fri, 28 Aug 2009 12:05:15 +0000 Subject: bonding: Have bond_check_dev_link examine netif_running bonding: Have bond_check_dev_link examine netif_running Some network devices do not call netif_carrier_off when they are set administratively down. Have the bonding link check function also inspect the netif_running state. Ignore netif_running if the bond_check_dev_link function is called with "reporting" set, as in that case it's inspecting the capabilities of the non-netif_carrier device driver. Signed-off-by: Petri Gynther Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6b9f15b..7c0e0bd 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -695,6 +695,9 @@ static int bond_check_dev_link(struct bonding *bond, struct ifreq ifr; struct mii_ioctl_data *mii; + if (!reporting && !netif_running(slave_dev)) + return 0; + if (bond->params.use_carrier) return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; -- cgit v0.10.2 From b2014ff8ac314f58d6542ec4ea7b576a2de21c8b Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 27 Aug 2009 11:02:09 +0000 Subject: qlge: Get rid of 'default' rx_ring type. Currently we have three types of RX rings. 1) Default ring - services rx_ring for broadcast/multicast, handles firmware events, and errors. 2) TX completion ring - handles only outbound completions. 3) RSS ring - handles only inbound completions. This patch gets rid of the default ring type and moves it's functionality into the first RSS ring. This makes better use of MSIX vectors since they are a limited resource on some platforms. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 6ed5317..ed5dbca 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1287,7 +1287,7 @@ struct rx_ring { u32 sbq_free_cnt; /* free buffer desc cnt */ /* Misc. handler elements. */ - u32 type; /* Type of queue, tx, rx, or default. */ + u32 type; /* Type of queue, tx, rx. */ u32 irq; /* Which vector this ring is assigned. */ u32 cpu; /* Which CPU this should run on. */ char name[IFNAMSIZ + 5]; @@ -1486,11 +1486,9 @@ struct ql_adapter { struct intr_context intr_context[MAX_RX_RINGS]; int tx_ring_count; /* One per online CPU. */ - u32 rss_ring_first_cq_id;/* index of first inbound (rss) rx_ring */ u32 rss_ring_count; /* One per online CPU. */ /* * rx_ring_count = - * one default queue + * (CPU count * outbound completion rx_ring) + * (CPU count * inbound (RSS) completion rx_ring) */ diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 40a70c3..aa88cb3 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -418,8 +418,6 @@ void ql_dump_qdev(struct ql_adapter *qdev) printk(KERN_ERR PFX "qdev->intr_count = %d.\n", qdev->intr_count); printk(KERN_ERR PFX "qdev->tx_ring = %p.\n", qdev->tx_ring); - printk(KERN_ERR PFX "qdev->rss_ring_first_cq_id = %d.\n", - qdev->rss_ring_first_cq_id); printk(KERN_ERR PFX "qdev->rss_ring_count = %d.\n", qdev->rss_ring_count); printk(KERN_ERR PFX "qdev->rx_ring = %p.\n", qdev->rx_ring); diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index eb6a9ee..68f9bd2 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -49,10 +49,11 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev) /* Skip the default queue, and update the outbound handler * queues if they changed. */ - cqicb = (struct cqicb *)&qdev->rx_ring[1]; + cqicb = (struct cqicb *)&qdev->rx_ring[qdev->rss_ring_count]; if (le16_to_cpu(cqicb->irq_delay) != qdev->tx_coalesce_usecs || - le16_to_cpu(cqicb->pkt_delay) != qdev->tx_max_coalesced_frames) { - for (i = 1; i < qdev->rss_ring_first_cq_id; i++, rx_ring++) { + le16_to_cpu(cqicb->pkt_delay) != + qdev->tx_max_coalesced_frames) { + for (i = qdev->rss_ring_count; i < qdev->rx_ring_count; i++) { rx_ring = &qdev->rx_ring[i]; cqicb = (struct cqicb *)rx_ring; cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs); @@ -70,12 +71,11 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev) } /* Update the inbound (RSS) handler queues if they changed. */ - cqicb = (struct cqicb *)&qdev->rx_ring[qdev->rss_ring_first_cq_id]; + cqicb = (struct cqicb *)&qdev->rx_ring[0]; if (le16_to_cpu(cqicb->irq_delay) != qdev->rx_coalesce_usecs || - le16_to_cpu(cqicb->pkt_delay) != qdev->rx_max_coalesced_frames) { - for (i = qdev->rss_ring_first_cq_id; - i <= qdev->rss_ring_first_cq_id + qdev->rss_ring_count; - i++) { + le16_to_cpu(cqicb->pkt_delay) != + qdev->rx_max_coalesced_frames) { + for (i = 0; i < qdev->rss_ring_count; i++, rx_ring++) { rx_ring = &qdev->rx_ring[i]; cqicb = (struct cqicb *)rx_ring; cqicb->irq_delay = cpu_to_le16(qdev->rx_coalesce_usecs); diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 3a271af..89ea9c7 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -370,9 +370,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, cam_output = (CAM_OUT_ROUTE_NIC | (qdev-> func << CAM_OUT_FUNC_SHIFT) | - (qdev-> - rss_ring_first_cq_id << - CAM_OUT_CQ_ID_SHIFT)); + (0 << CAM_OUT_CQ_ID_SHIFT)); if (qdev->vlgrp) cam_output |= CAM_OUT_RV; /* route to NIC core */ @@ -1649,8 +1647,7 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, qdev->stats.rx_packets++; qdev->stats.rx_bytes += skb->len; - skb_record_rx_queue(skb, - rx_ring->cq_id - qdev->rss_ring_first_cq_id); + skb_record_rx_queue(skb, rx_ring->cq_id); if (skb->ip_summed == CHECKSUM_UNNECESSARY) { if (qdev->vlgrp && (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && @@ -2044,7 +2041,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) ql_disable_completion_interrupt(qdev, intr_context-> intr); - if (i < qdev->rss_ring_first_cq_id) + if (i >= qdev->rss_ring_count) queue_delayed_work_on(rx_ring->cpu, qdev->q_workqueue, &rx_ring->rx_work, @@ -2908,28 +2905,20 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) INTR_EN_TYPE_READ | INTR_EN_IHD_MASK | INTR_EN_IHD | i; - if (i == 0) { + if (i < qdev->rss_ring_count) { /* - * Default queue handles bcast/mcast plus - * async events. Needs buffers. + * Inbound queues handle unicast frames only. */ - intr_context->handler = qlge_isr; - sprintf(intr_context->name, "%s-default-queue", - qdev->ndev->name); - } else if (i < qdev->rss_ring_first_cq_id) { + intr_context->handler = qlge_msix_rx_isr; + sprintf(intr_context->name, "%s-rx-%d", + qdev->ndev->name, i); + } else { /* * Outbound queue is for outbound completions only. */ intr_context->handler = qlge_msix_tx_isr; sprintf(intr_context->name, "%s-tx-%d", qdev->ndev->name, i); - } else { - /* - * Inbound queues handle unicast frames only. - */ - intr_context->handler = qlge_msix_rx_isr; - sprintf(intr_context->name, "%s-rx-%d", - qdev->ndev->name, i); } } } else { @@ -3062,7 +3051,7 @@ static int ql_start_rss(struct ql_adapter *qdev) memset((void *)ricb, 0, sizeof(*ricb)); - ricb->base_cq = qdev->rss_ring_first_cq_id | RSS_L4K; + ricb->base_cq = RSS_L4K; ricb->flags = (RSS_L6K | RSS_LI | RSS_LB | RSS_LM | RSS_RI4 | RSS_RI6 | RSS_RT4 | RSS_RT6); @@ -3264,7 +3253,7 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) } /* Start NAPI for the RSS queues. */ - for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) { + for (i = 0; i < qdev->rss_ring_count; i++) { QPRINTK(qdev, IFUP, DEBUG, "Enabling NAPI for rx_ring[%d].\n", i); napi_enable(&qdev->rx_ring[i].napi); @@ -3355,7 +3344,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) * environment. Outbound completion processing * is done in interrupt context. */ - if (i >= qdev->rss_ring_first_cq_id) { + if (i <= qdev->rss_ring_count) { napi_disable(&rx_ring->napi); } else { cancel_delayed_work_sync(&rx_ring->rx_work); @@ -3370,7 +3359,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) /* Call netif_napi_del() from common point. */ - for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) + for (i = 0; i < qdev->rss_ring_count; i++) netif_napi_del(&qdev->rx_ring[i].napi); ql_free_rx_buffers(qdev); @@ -3476,8 +3465,6 @@ static int ql_configure_rings(struct ql_adapter *qdev) qdev->tx_ring_count = cpu_cnt; /* Allocate inbound completion (RSS) ring for each CPU. */ qdev->rss_ring_count = cpu_cnt; - /* cq_id for the first inbound ring handler. */ - qdev->rss_ring_first_cq_id = cpu_cnt + 1; /* * qdev->rx_ring_count: * Total number of rx_rings. This includes the one @@ -3485,7 +3472,7 @@ static int ql_configure_rings(struct ql_adapter *qdev) * handler rx_rings, and the number of inbound * completion handler rx_rings. */ - qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1; + qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count; for (i = 0; i < qdev->tx_ring_count; i++) { tx_ring = &qdev->tx_ring[i]; @@ -3500,7 +3487,7 @@ static int ql_configure_rings(struct ql_adapter *qdev) * The completion queue ID for the tx rings start * immediately after the default Q ID, which is zero. */ - tx_ring->cq_id = i + 1; + tx_ring->cq_id = i + qdev->rss_ring_count; } for (i = 0; i < qdev->rx_ring_count; i++) { @@ -3509,11 +3496,8 @@ static int ql_configure_rings(struct ql_adapter *qdev) rx_ring->qdev = qdev; rx_ring->cq_id = i; rx_ring->cpu = i % cpu_cnt; /* CPU to run handler on. */ - if (i == 0) { /* Default queue at index 0. */ - /* - * Default queue handles bcast/mcast plus - * async events. Needs buffers. - */ + if (i < qdev->rss_ring_count) { + /* Inbound completions (RSS) queues */ rx_ring->cq_len = qdev->rx_ring_size; rx_ring->cq_size = rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb); @@ -3525,8 +3509,8 @@ static int ql_configure_rings(struct ql_adapter *qdev) rx_ring->sbq_size = rx_ring->sbq_len * sizeof(__le64); rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2; - rx_ring->type = DEFAULT_Q; - } else if (i < qdev->rss_ring_first_cq_id) { + rx_ring->type = RX_Q; + } else { /* * Outbound queue handles outbound completions only. */ @@ -3541,22 +3525,6 @@ static int ql_configure_rings(struct ql_adapter *qdev) rx_ring->sbq_size = 0; rx_ring->sbq_buf_size = 0; rx_ring->type = TX_Q; - } else { /* Inbound completions (RSS) queues */ - /* - * Inbound queues handle unicast frames only. - */ - rx_ring->cq_len = qdev->rx_ring_size; - rx_ring->cq_size = - rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb); - rx_ring->lbq_len = NUM_LARGE_BUFFERS; - rx_ring->lbq_size = - rx_ring->lbq_len * sizeof(__le64); - rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE; - rx_ring->sbq_len = NUM_SMALL_BUFFERS; - rx_ring->sbq_size = - rx_ring->sbq_len * sizeof(__le64); - rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2; - rx_ring->type = RX_Q; } } return 0; -- cgit v0.10.2 From a4ab613717184138763c5fb4a4b4bbc354d5b0ee Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 27 Aug 2009 11:02:10 +0000 Subject: qlge: Allow running MSIx with fewer vectors. Currently we downshift to MSI/Legacy if we don't get enough vectors for cpu_count RSS rings plus cpu_count TX completion rings. This patch allows running MSIX with the vector count that the platform provides. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 89ea9c7..0cbda4d 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2815,17 +2815,20 @@ static void ql_disable_msix(struct ql_adapter *qdev) } } +/* We start by trying to get the number of vectors + * stored in qdev->intr_count. If we don't get that + * many then we reduce the count and try again. + */ static void ql_enable_msix(struct ql_adapter *qdev) { - int i; + int i, err; - qdev->intr_count = 1; /* Get the MSIX vectors. */ if (irq_type == MSIX_IRQ) { /* Try to alloc space for the msix struct, * if it fails then go to MSI/legacy. */ - qdev->msi_x_entry = kcalloc(qdev->rx_ring_count, + qdev->msi_x_entry = kcalloc(qdev->intr_count, sizeof(struct msix_entry), GFP_KERNEL); if (!qdev->msi_x_entry) { @@ -2833,26 +2836,36 @@ static void ql_enable_msix(struct ql_adapter *qdev) goto msi; } - for (i = 0; i < qdev->rx_ring_count; i++) + for (i = 0; i < qdev->intr_count; i++) qdev->msi_x_entry[i].entry = i; - if (!pci_enable_msix - (qdev->pdev, qdev->msi_x_entry, qdev->rx_ring_count)) { - set_bit(QL_MSIX_ENABLED, &qdev->flags); - qdev->intr_count = qdev->rx_ring_count; - QPRINTK(qdev, IFUP, DEBUG, - "MSI-X Enabled, got %d vectors.\n", - qdev->intr_count); - return; - } else { + /* Loop to get our vectors. We start with + * what we want and settle for what we get. + */ + do { + err = pci_enable_msix(qdev->pdev, + qdev->msi_x_entry, qdev->intr_count); + if (err > 0) + qdev->intr_count = err; + } while (err > 0); + + if (err < 0) { kfree(qdev->msi_x_entry); qdev->msi_x_entry = NULL; QPRINTK(qdev, IFUP, WARNING, "MSI-X Enable failed, trying MSI.\n"); + qdev->intr_count = 1; irq_type = MSI_IRQ; + } else if (err == 0) { + set_bit(QL_MSIX_ENABLED, &qdev->flags); + QPRINTK(qdev, IFUP, INFO, + "MSI-X Enabled, got %d vectors.\n", + qdev->intr_count); + return; } } msi: + qdev->intr_count = 1; if (irq_type == MSI_IRQ) { if (!pci_enable_msi(qdev->pdev)) { set_bit(QL_MSI_ENABLED, &qdev->flags); @@ -2876,8 +2889,6 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) int i = 0; struct intr_context *intr_context = &qdev->intr_context[0]; - ql_enable_msix(qdev); - if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) { /* Each rx_ring has it's * own intr_context since we have separate @@ -3438,40 +3449,20 @@ static int ql_configure_rings(struct ql_adapter *qdev) int i; struct rx_ring *rx_ring; struct tx_ring *tx_ring; - int cpu_cnt = num_online_cpus(); - - /* - * For each processor present we allocate one - * rx_ring for outbound completions, and one - * rx_ring for inbound completions. Plus there is - * always the one default queue. For the CPU - * counts we end up with the following rx_rings: - * rx_ring count = - * one default queue + - * (CPU count * outbound completion rx_ring) + - * (CPU count * inbound (RSS) completion rx_ring) - * To keep it simple we limit the total number of - * queues to < 32, so we truncate CPU to 8. - * This limitation can be removed when requested. + int cpu_cnt = min(MAX_CPUS, (int)num_online_cpus()); + + /* In a perfect world we have one RSS ring for each CPU + * and each has it's own vector. To do that we ask for + * cpu_cnt vectors. ql_enable_msix() will adjust the + * vector count to what we actually get. We then + * allocate an RSS ring for each. + * Essentially, we are doing min(cpu_count, msix_vector_count). */ - - if (cpu_cnt > MAX_CPUS) - cpu_cnt = MAX_CPUS; - - /* - * rx_ring[0] is always the default queue. - */ - /* Allocate outbound completion ring for each CPU. */ + qdev->intr_count = cpu_cnt; + ql_enable_msix(qdev); + /* Adjust the RSS ring count to the actual vector count. */ + qdev->rss_ring_count = qdev->intr_count; qdev->tx_ring_count = cpu_cnt; - /* Allocate inbound completion (RSS) ring for each CPU. */ - qdev->rss_ring_count = cpu_cnt; - /* - * qdev->rx_ring_count: - * Total number of rx_rings. This includes the one - * default queue, a number of outbound completion - * handler rx_rings, and the number of inbound - * completion handler rx_rings. - */ qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count; for (i = 0; i < qdev->tx_ring_count; i++) { -- cgit v0.10.2 From 39aa81659353becbe4ee34d72cf79e02182e858a Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 27 Aug 2009 11:02:11 +0000 Subject: qlge: Move TX completions from workqueue to NAPI. TX completions were running in a workqueue queued by the ISR. This patch moves the processing of TX completions to an existing RSS NAPI context. Now each irq vector runs NAPI for one RSS ring and one or more TX completion rings. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index ed5dbca..a9845a2 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1292,7 +1292,6 @@ struct rx_ring { u32 cpu; /* Which CPU this should run on. */ char name[IFNAMSIZ + 5]; struct napi_struct napi; - struct delayed_work rx_work; u8 reserved; struct ql_adapter *qdev; }; @@ -1366,6 +1365,7 @@ struct nic_stats { struct intr_context { struct ql_adapter *qdev; u32 intr; + u32 irq_mask; /* Mask of which rings the vector services. */ u32 hooked; u32 intr_en_mask; /* value/mask used to enable this intr */ u32 intr_dis_mask; /* value/mask used to disable this intr */ @@ -1486,11 +1486,11 @@ struct ql_adapter { struct intr_context intr_context[MAX_RX_RINGS]; int tx_ring_count; /* One per online CPU. */ - u32 rss_ring_count; /* One per online CPU. */ + u32 rss_ring_count; /* One per irq vector. */ /* * rx_ring_count = * (CPU count * outbound completion rx_ring) + - * (CPU count * inbound (RSS) completion rx_ring) + * (irq_vector_cnt * inbound (RSS) completion rx_ring) */ int rx_ring_count; int ring_mem_size; @@ -1517,7 +1517,6 @@ struct ql_adapter { union flash_params flash; struct net_device_stats stats; - struct workqueue_struct *q_workqueue; struct workqueue_struct *workqueue; struct delayed_work asic_reset_work; struct delayed_work mpi_reset_work; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 0cbda4d..8dd266b 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1859,11 +1859,41 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget) { struct rx_ring *rx_ring = container_of(napi, struct rx_ring, napi); struct ql_adapter *qdev = rx_ring->qdev; - int work_done = ql_clean_inbound_rx_ring(rx_ring, budget); + struct rx_ring *trx_ring; + int i, work_done = 0; + struct intr_context *ctx = &qdev->intr_context[rx_ring->cq_id]; QPRINTK(qdev, RX_STATUS, DEBUG, "Enter, NAPI POLL cq_id = %d.\n", rx_ring->cq_id); + /* Service the TX rings first. They start + * right after the RSS rings. */ + for (i = qdev->rss_ring_count; i < qdev->rx_ring_count; i++) { + trx_ring = &qdev->rx_ring[i]; + /* If this TX completion ring belongs to this vector and + * it's not empty then service it. + */ + if ((ctx->irq_mask & (1 << trx_ring->cq_id)) && + (ql_read_sh_reg(trx_ring->prod_idx_sh_reg) != + trx_ring->cnsmr_idx)) { + QPRINTK(qdev, INTR, DEBUG, + "%s: Servicing TX completion ring %d.\n", + __func__, trx_ring->cq_id); + ql_clean_outbound_rx_ring(trx_ring); + } + } + + /* + * Now service the RSS ring if it's active. + */ + if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != + rx_ring->cnsmr_idx) { + QPRINTK(qdev, INTR, DEBUG, + "%s: Servicing RX completion ring %d.\n", + __func__, rx_ring->cq_id); + work_done = ql_clean_inbound_rx_ring(rx_ring, budget); + } + if (work_done < budget) { napi_complete(napi); ql_enable_completion_interrupt(qdev, rx_ring->irq); @@ -1925,38 +1955,6 @@ static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid) } -/* Worker thread to process a given rx_ring that is dedicated - * to outbound completions. - */ -static void ql_tx_clean(struct work_struct *work) -{ - struct rx_ring *rx_ring = - container_of(work, struct rx_ring, rx_work.work); - ql_clean_outbound_rx_ring(rx_ring); - ql_enable_completion_interrupt(rx_ring->qdev, rx_ring->irq); - -} - -/* Worker thread to process a given rx_ring that is dedicated - * to inbound completions. - */ -static void ql_rx_clean(struct work_struct *work) -{ - struct rx_ring *rx_ring = - container_of(work, struct rx_ring, rx_work.work); - ql_clean_inbound_rx_ring(rx_ring, 64); - ql_enable_completion_interrupt(rx_ring->qdev, rx_ring->irq); -} - -/* MSI-X Multiple Vector Interrupt Handler for outbound completions. */ -static irqreturn_t qlge_msix_tx_isr(int irq, void *dev_id) -{ - struct rx_ring *rx_ring = dev_id; - queue_delayed_work_on(rx_ring->cpu, rx_ring->qdev->q_workqueue, - &rx_ring->rx_work, 0); - return IRQ_HANDLED; -} - /* MSI-X Multiple Vector Interrupt Handler for inbound completions. */ static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id) { @@ -1976,7 +1974,6 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) struct ql_adapter *qdev = rx_ring->qdev; struct intr_context *intr_context = &qdev->intr_context[0]; u32 var; - int i; int work_done = 0; spin_lock(&qdev->hw_lock); @@ -2017,41 +2014,18 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) } /* - * Check the default queue and wake handler if active. + * Get the bit-mask that shows the active queues for this + * pass. Compare it to the queues that this irq services + * and call napi if there's a match. */ - rx_ring = &qdev->rx_ring[0]; - if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) { - QPRINTK(qdev, INTR, INFO, "Waking handler for rx_ring[0].\n"); - ql_disable_completion_interrupt(qdev, intr_context->intr); - queue_delayed_work_on(smp_processor_id(), qdev->q_workqueue, - &rx_ring->rx_work, 0); - work_done++; - } - - if (!test_bit(QL_MSIX_ENABLED, &qdev->flags)) { - /* - * Start the DPC for each active queue. - */ - for (i = 1; i < qdev->rx_ring_count; i++) { - rx_ring = &qdev->rx_ring[i]; - if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != - rx_ring->cnsmr_idx) { + var = ql_read32(qdev, ISR1); + if (var & intr_context->irq_mask) { QPRINTK(qdev, INTR, INFO, - "Waking handler for rx_ring[%d].\n", i); - ql_disable_completion_interrupt(qdev, - intr_context-> - intr); - if (i >= qdev->rss_ring_count) - queue_delayed_work_on(rx_ring->cpu, - qdev->q_workqueue, - &rx_ring->rx_work, - 0); - else + "Waking handler for rx_ring[0].\n"); + ql_disable_completion_interrupt(qdev, intr_context->intr); napi_schedule(&rx_ring->napi); work_done++; } - } - } ql_enable_completion_interrupt(qdev, intr_context->intr); return work_done ? IRQ_HANDLED : IRQ_NONE; } @@ -2703,35 +2677,9 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) } switch (rx_ring->type) { case TX_Q: - /* If there's only one interrupt, then we use - * worker threads to process the outbound - * completion handling rx_rings. We do this so - * they can be run on multiple CPUs. There is - * room to play with this more where we would only - * run in a worker if there are more than x number - * of outbound completions on the queue and more - * than one queue active. Some threshold that - * would indicate a benefit in spite of the cost - * of a context switch. - * If there's more than one interrupt, then the - * outbound completions are processed in the ISR. - */ - if (!test_bit(QL_MSIX_ENABLED, &qdev->flags)) - INIT_DELAYED_WORK(&rx_ring->rx_work, ql_tx_clean); - else { - /* With all debug warnings on we see a WARN_ON message - * when we free the skb in the interrupt context. - */ - INIT_DELAYED_WORK(&rx_ring->rx_work, ql_tx_clean); - } cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs); cqicb->pkt_delay = cpu_to_le16(qdev->tx_max_coalesced_frames); break; - case DEFAULT_Q: - INIT_DELAYED_WORK(&rx_ring->rx_work, ql_rx_clean); - cqicb->irq_delay = 0; - cqicb->pkt_delay = 0; - break; case RX_Q: /* Inbound completion handling rx_rings run in * separate NAPI contexts. @@ -2878,6 +2826,71 @@ msi: QPRINTK(qdev, IFUP, DEBUG, "Running with legacy interrupts.\n"); } +/* Each vector services 1 RSS ring and and 1 or more + * TX completion rings. This function loops through + * the TX completion rings and assigns the vector that + * will service it. An example would be if there are + * 2 vectors (so 2 RSS rings) and 8 TX completion rings. + * This would mean that vector 0 would service RSS ring 0 + * and TX competion rings 0,1,2 and 3. Vector 1 would + * service RSS ring 1 and TX completion rings 4,5,6 and 7. + */ +static void ql_set_tx_vect(struct ql_adapter *qdev) +{ + int i, j, vect; + u32 tx_rings_per_vector = qdev->tx_ring_count / qdev->intr_count; + + if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) { + /* Assign irq vectors to TX rx_rings.*/ + for (vect = 0, j = 0, i = qdev->rss_ring_count; + i < qdev->rx_ring_count; i++) { + if (j == tx_rings_per_vector) { + vect++; + j = 0; + } + qdev->rx_ring[i].irq = vect; + j++; + } + } else { + /* For single vector all rings have an irq + * of zero. + */ + for (i = 0; i < qdev->rx_ring_count; i++) + qdev->rx_ring[i].irq = 0; + } +} + +/* Set the interrupt mask for this vector. Each vector + * will service 1 RSS ring and 1 or more TX completion + * rings. This function sets up a bit mask per vector + * that indicates which rings it services. + */ +static void ql_set_irq_mask(struct ql_adapter *qdev, struct intr_context *ctx) +{ + int j, vect = ctx->intr; + u32 tx_rings_per_vector = qdev->tx_ring_count / qdev->intr_count; + + if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) { + /* Add the RSS ring serviced by this vector + * to the mask. + */ + ctx->irq_mask = (1 << qdev->rx_ring[vect].cq_id); + /* Add the TX ring(s) serviced by this vector + * to the mask. */ + for (j = 0; j < tx_rings_per_vector; j++) { + ctx->irq_mask |= + (1 << qdev->rx_ring[qdev->rss_ring_count + + (vect * tx_rings_per_vector) + j].cq_id); + } + } else { + /* For single vector we just shift each queue's + * ID into the mask. + */ + for (j = 0; j < qdev->rx_ring_count; j++) + ctx->irq_mask |= (1 << qdev->rx_ring[j].cq_id); + } +} + /* * Here we build the intr_context structures based on * our rx_ring count and intr vector count. @@ -2893,12 +2906,15 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) /* Each rx_ring has it's * own intr_context since we have separate * vectors for each queue. - * This only true when MSI-X is enabled. */ for (i = 0; i < qdev->intr_count; i++, intr_context++) { qdev->rx_ring[i].irq = i; intr_context->intr = i; intr_context->qdev = qdev; + /* Set up this vector's bit-mask that indicates + * which queues it services. + */ + ql_set_irq_mask(qdev, intr_context); /* * We set up each vectors enable/disable/read bits so * there's no bit/mask calculations in the critical path. @@ -2915,20 +2931,21 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | INTR_EN_TYPE_READ | INTR_EN_IHD_MASK | INTR_EN_IHD | i; - - if (i < qdev->rss_ring_count) { - /* - * Inbound queues handle unicast frames only. + if (i == 0) { + /* The first vector/queue handles + * broadcast/multicast, fatal errors, + * and firmware events. This in addition + * to normal inbound NAPI processing. */ - intr_context->handler = qlge_msix_rx_isr; + intr_context->handler = qlge_isr; sprintf(intr_context->name, "%s-rx-%d", qdev->ndev->name, i); } else { /* - * Outbound queue is for outbound completions only. + * Inbound queues handle unicast frames only. */ - intr_context->handler = qlge_msix_tx_isr; - sprintf(intr_context->name, "%s-tx-%d", + intr_context->handler = qlge_msix_rx_isr; + sprintf(intr_context->name, "%s-rx-%d", qdev->ndev->name, i); } } @@ -2955,9 +2972,17 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) */ intr_context->handler = qlge_isr; sprintf(intr_context->name, "%s-single_irq", qdev->ndev->name); - for (i = 0; i < qdev->rx_ring_count; i++) - qdev->rx_ring[i].irq = 0; + /* Set up this vector's bit-mask that indicates + * which queues it services. In this case there is + * a single vector so it will service all RSS and + * TX completion rings. + */ + ql_set_irq_mask(qdev, intr_context); } + /* Tell the TX completion rings which MSIx vector + * they will be using. + */ + ql_set_tx_vect(qdev); } static void ql_free_irq(struct ql_adapter *qdev) @@ -3326,7 +3351,6 @@ static void ql_display_dev_info(struct net_device *ndev) static int ql_adapter_down(struct ql_adapter *qdev) { int i, status = 0; - struct rx_ring *rx_ring; ql_link_off(qdev); @@ -3340,27 +3364,8 @@ static int ql_adapter_down(struct ql_adapter *qdev) cancel_delayed_work_sync(&qdev->mpi_idc_work); cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); - /* The default queue at index 0 is always processed in - * a workqueue. - */ - cancel_delayed_work_sync(&qdev->rx_ring[0].rx_work); - - /* The rest of the rx_rings are processed in - * a workqueue only if it's a single interrupt - * environment (MSI/Legacy). - */ - for (i = 1; i < qdev->rx_ring_count; i++) { - rx_ring = &qdev->rx_ring[i]; - /* Only the RSS rings use NAPI on multi irq - * environment. Outbound completion processing - * is done in interrupt context. - */ - if (i <= qdev->rss_ring_count) { - napi_disable(&rx_ring->napi); - } else { - cancel_delayed_work_sync(&rx_ring->rx_work); - } - } + for (i = 0; i < qdev->rss_ring_count; i++) + napi_disable(&qdev->rx_ring[i].napi); clear_bit(QL_ADAPTER_UP, &qdev->flags); @@ -3476,9 +3481,9 @@ static int ql_configure_rings(struct ql_adapter *qdev) /* * The completion queue ID for the tx rings start - * immediately after the default Q ID, which is zero. + * immediately after the rss rings. */ - tx_ring->cq_id = i + qdev->rss_ring_count; + tx_ring->cq_id = qdev->rss_ring_count + i; } for (i = 0; i < qdev->rx_ring_count; i++) { @@ -3488,7 +3493,9 @@ static int ql_configure_rings(struct ql_adapter *qdev) rx_ring->cq_id = i; rx_ring->cpu = i % cpu_cnt; /* CPU to run handler on. */ if (i < qdev->rss_ring_count) { - /* Inbound completions (RSS) queues */ + /* + * Inbound (RSS) queues. + */ rx_ring->cq_len = qdev->rx_ring_size; rx_ring->cq_size = rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb); @@ -3804,10 +3811,7 @@ static void ql_release_all(struct pci_dev *pdev) destroy_workqueue(qdev->workqueue); qdev->workqueue = NULL; } - if (qdev->q_workqueue) { - destroy_workqueue(qdev->q_workqueue); - qdev->q_workqueue = NULL; - } + if (qdev->reg_base) iounmap(qdev->reg_base); if (qdev->doorbell_area) @@ -3920,8 +3924,6 @@ static int __devinit ql_init_device(struct pci_dev *pdev, * Set up the operating parameters. */ qdev->rx_csum = 1; - - qdev->q_workqueue = create_workqueue(ndev->name); qdev->workqueue = create_singlethread_workqueue(ndev->name); INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work); INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work); -- cgit v0.10.2 From 648fda7404630ba85ce462ee1279e1bc027ad915 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:07 +0000 Subject: pktgen: minor cleanup A couple of minor functions can be written more compactly. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 19b8c20..bb46313 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -509,7 +509,7 @@ static const struct file_operations pktgen_fops = { static int pktgen_if_show(struct seq_file *seq, void *v) { - struct pktgen_dev *pkt_dev = seq->private; + const struct pktgen_dev *pkt_dev = seq->private; __u64 sa; __u64 stopped; __u64 now = getCurUs(); @@ -1670,7 +1670,7 @@ static const struct file_operations pktgen_if_fops = { static int pktgen_thread_show(struct seq_file *seq, void *v) { struct pktgen_thread *t = seq->private; - struct pktgen_dev *pkt_dev; + const struct pktgen_dev *pkt_dev; BUG_ON(!t); @@ -2120,13 +2120,9 @@ static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); } -static inline int f_seen(struct pktgen_dev *pkt_dev, int flow) +static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow) { - - if (pkt_dev->flows[flow].flags & F_INIT) - return 1; - else - return 0; + return !!(pkt_dev->flows[flow].flags & F_INIT); } static inline int f_pick(struct pktgen_dev *pkt_dev) @@ -3101,17 +3097,14 @@ static void pktgen_stop_all_threads_ifs(void) mutex_unlock(&pktgen_thread_lock); } -static int thread_is_running(struct pktgen_thread *t) +static int thread_is_running(const struct pktgen_thread *t) { - struct pktgen_dev *pkt_dev; - int res = 0; + const struct pktgen_dev *pkt_dev; list_for_each_entry(pkt_dev, &t->if_list, list) - if (pkt_dev->running) { - res = 1; - break; - } - return res; + if (pkt_dev->running) + return 1; + return 0; } static int pktgen_wait_thread_run(struct pktgen_thread *t) -- cgit v0.10.2 From 475ac1e4099a005e1307c416df19f2100b7a838d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:08 +0000 Subject: pktgen: change inlining Don't force inlining where not needed. Gcc does better job of deciding to inline local functions. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index bb46313..f96e9f0 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2438,7 +2438,7 @@ error: return err; } -static inline void free_SAs(struct pktgen_dev *pkt_dev) +static void free_SAs(struct pktgen_dev *pkt_dev) { if (pkt_dev->cflows) { /* let go of the SAs if we have them */ @@ -2453,7 +2453,7 @@ static inline void free_SAs(struct pktgen_dev *pkt_dev) } } -static inline int process_ipsec(struct pktgen_dev *pkt_dev, +static int process_ipsec(struct pktgen_dev *pkt_dev, struct sk_buff *skb, __be16 protocol) { if (pkt_dev->flags & F_IPSEC_ON) { @@ -3029,8 +3029,8 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, return skb; } -static inline struct sk_buff *fill_packet(struct net_device *odev, - struct pktgen_dev *pkt_dev) +static struct sk_buff *fill_packet(struct net_device *odev, + struct pktgen_dev *pkt_dev) { if (pkt_dev->flags & F_IPV6) return fill_packet_ipv6(odev, pkt_dev); @@ -3341,13 +3341,12 @@ static void pktgen_rem_thread(struct pktgen_thread *t) mutex_unlock(&pktgen_thread_lock); } -static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) +static void pktgen_xmit(struct pktgen_dev *pkt_dev) { struct net_device *odev = pkt_dev->odev; int (*xmit)(struct sk_buff *, struct net_device *) = odev->netdev_ops->ndo_start_xmit; struct netdev_queue *txq; - __u64 idle_start = 0; u16 queue_map; int ret; @@ -3379,7 +3378,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) if (netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq) || need_resched()) { - idle_start = getCurUs(); + u64 idle_start = getCurUs(); if (!netif_running(odev)) { pktgen_stop_device(pkt_dev); @@ -3475,7 +3474,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) /* If pkt_dev->count is zero, then run forever */ if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { if (atomic_read(&(pkt_dev->skb->users)) != 1) { - idle_start = getCurUs(); + u64 idle_start = getCurUs(); while (atomic_read(&(pkt_dev->skb->users)) != 1) { if (signal_pending(current)) { break; -- cgit v0.10.2 From 65c5b786a37746302e225223c0d8b760d4c48a8b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:09 +0000 Subject: pktgen: mark read-only/mostly variables Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index f96e9f0..ccbc3a4 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -414,7 +414,7 @@ static __u64 getCurUs(void) /* old include end */ -static char version[] __initdata = VERSION; +static const char version[] __initconst = VERSION; static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); @@ -432,10 +432,10 @@ static unsigned int scan_ip6(const char *s, char ip[16]); static unsigned int fmt_ip6(char *s, const char ip[16]); /* Module parameters, defaults. */ -static int pg_count_d = 1000; /* 1000 pkts by default */ -static int pg_delay_d; -static int pg_clone_skb_d; -static int debug; +static int pg_count_d __read_mostly = 1000; +static int pg_delay_d __read_mostly; +static int pg_clone_skb_d __read_mostly; +static int debug __read_mostly; static DEFINE_MUTEX(pktgen_thread_lock); static LIST_HEAD(pktgen_threads); -- cgit v0.10.2 From 3bda06a3d7987bfeabb218ac2f17ce22c34f13b3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:10 +0000 Subject: pktgen: stop_device cleanup All the callers were freeing skb after stopping device. Remove unneeded forward decl. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index ccbc3a4..1b1f126 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -424,7 +424,7 @@ static int pktgen_device_event(struct notifier_block *, unsigned long, void *); static void pktgen_run_all_threads(void); static void pktgen_reset_all_threads(void); static void pktgen_stop_all_threads_ifs(void); -static int pktgen_stop_device(struct pktgen_dev *pkt_dev); + static void pktgen_stop(struct pktgen_thread *t); static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); @@ -3221,7 +3221,6 @@ static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) } /* Set stopped-at timer, remove from running list, do counters & statistics */ - static int pktgen_stop_device(struct pktgen_dev *pkt_dev) { int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; @@ -3232,6 +3231,8 @@ static int pktgen_stop_device(struct pktgen_dev *pkt_dev) return -EINVAL; } + kfree_skb(pkt_dev->skb); + pkt_dev->skb = NULL; pkt_dev->stopped_at = getCurUs(); pkt_dev->running = 0; @@ -3268,9 +3269,6 @@ static void pktgen_stop(struct pktgen_thread *t) list_for_each_entry(pkt_dev, &t->if_list, list) { pktgen_stop_device(pkt_dev); - kfree_skb(pkt_dev->skb); - - pkt_dev->skb = NULL; } if_unlock(t); @@ -3382,8 +3380,6 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) if (!netif_running(odev)) { pktgen_stop_device(pkt_dev); - kfree_skb(pkt_dev->skb); - pkt_dev->skb = NULL; goto out; } if (need_resched()) @@ -3486,8 +3482,6 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) /* Done with this */ pktgen_stop_device(pkt_dev); - kfree_skb(pkt_dev->skb); - pkt_dev->skb = NULL; } out:; } -- cgit v0.10.2 From 3791decb5aa0202d2a2473d6cf4947d98e846c7a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:11 +0000 Subject: pktgen: xmit logic reorganization Do some reorganization of transmit logic path: * move transmit queue full idle to separate routine * add a cpu_relax() * eliminate some of the uneeded goto's * if queue is still stopped, go back to main thread loop. * don't give up transmitting if quantum is exhausted (be greedy) Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 1b1f126..89fd232 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3339,6 +3339,18 @@ static void pktgen_rem_thread(struct pktgen_thread *t) mutex_unlock(&pktgen_thread_lock); } +static void idle(struct pktgen_dev *pkt_dev) +{ + u64 idle_start = getCurUs(); + + if (need_resched()) + schedule(); + else + cpu_relax(); + + pkt_dev->idle_acc += getCurUs() - idle_start; +} + static void pktgen_xmit(struct pktgen_dev *pkt_dev) { struct net_device *odev = pkt_dev->odev; @@ -3361,7 +3373,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) if (pkt_dev->delay_us == 0x7FFFFFFF) { pkt_dev->next_tx_us = getCurUs() + pkt_dev->delay_us; pkt_dev->next_tx_ns = pkt_dev->delay_ns; - goto out; + return; } } @@ -3373,26 +3385,14 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) } txq = netdev_get_tx_queue(odev, queue_map); - if (netif_tx_queue_stopped(txq) || - netif_tx_queue_frozen(txq) || - need_resched()) { - u64 idle_start = getCurUs(); - - if (!netif_running(odev)) { + /* Did we saturate the queue already? */ + if (netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq)) { + /* If device is down, then all queues are permnantly frozen */ + if (netif_running(odev)) + idle(pkt_dev); + else pktgen_stop_device(pkt_dev); - goto out; - } - if (need_resched()) - schedule(); - - pkt_dev->idle_acc += getCurUs() - idle_start; - - if (netif_tx_queue_stopped(txq) || - netif_tx_queue_frozen(txq)) { - pkt_dev->next_tx_us = getCurUs(); /* TODO */ - pkt_dev->next_tx_ns = 0; - goto out; /* Try the next interface */ - } + return; } if (pkt_dev->last_ok || !pkt_dev->skb) { @@ -3407,7 +3407,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) "allocate skb in fill_packet.\n"); schedule(); pkt_dev->clone_count--; /* back out increment, OOM */ - goto out; + return; } pkt_dev->allocated_skbs++; pkt_dev->clone_count = 0; /* reset counter */ @@ -3419,9 +3419,9 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) txq = netdev_get_tx_queue(odev, queue_map); __netif_tx_lock_bh(txq); - if (!netif_tx_queue_stopped(txq) && - !netif_tx_queue_frozen(txq)) { - + if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) + pkt_dev->last_ok = 0; + else { atomic_inc(&(pkt_dev->skb->users)); retry_now: ret = (*xmit)(pkt_dev->skb, odev); @@ -3458,13 +3458,6 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->next_tx_ns -= 1000; } } - - else { /* Retry it next time */ - pkt_dev->last_ok = 0; - pkt_dev->next_tx_us = getCurUs(); /* TODO */ - pkt_dev->next_tx_ns = 0; - } - __netif_tx_unlock_bh(txq); /* If pkt_dev->count is zero, then run forever */ -- cgit v0.10.2 From 7d7bb1cf0ea7434230b3e3de49c24ff68666a72e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:12 +0000 Subject: pktgen: cleanup clone count test The if statement to test for "should a new packet be used" can be simplified. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 89fd232..90d48cc 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3395,23 +3395,22 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) return; } - if (pkt_dev->last_ok || !pkt_dev->skb) { - if ((++pkt_dev->clone_count >= pkt_dev->clone_skb) - || (!pkt_dev->skb)) { - /* build a new pkt */ - kfree_skb(pkt_dev->skb); - - pkt_dev->skb = fill_packet(odev, pkt_dev); - if (pkt_dev->skb == NULL) { - printk(KERN_ERR "pktgen: ERROR: couldn't " - "allocate skb in fill_packet.\n"); - schedule(); - pkt_dev->clone_count--; /* back out increment, OOM */ - return; - } - pkt_dev->allocated_skbs++; - pkt_dev->clone_count = 0; /* reset counter */ + if (!pkt_dev->skb || (pkt_dev->last_ok && + ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { + /* build a new pkt */ + kfree_skb(pkt_dev->skb); + + pkt_dev->skb = fill_packet(odev, pkt_dev); + if (pkt_dev->skb == NULL) { + printk(KERN_ERR "pktgen: ERROR: couldn't " + "allocate skb in fill_packet.\n"); + schedule(); + pkt_dev->clone_count--; /* back out increment, OOM */ + return; } + + pkt_dev->allocated_skbs++; + pkt_dev->clone_count = 0; /* reset counter */ } /* fill_packet() might have changed the queue */ @@ -3476,7 +3475,6 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) /* Done with this */ pktgen_stop_device(pkt_dev); } -out:; } /* -- cgit v0.10.2 From e470757d6179eb8998881ac2706927d4d0cb0e54 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:13 +0000 Subject: pktgen: use netdev_alloc_skb netdev_alloc_skb is NUMA node aware. Also, don't exhaust atomic emergency pool. Don't want pktgen to cause OOM behaviour. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 90d48cc..2456bd5 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2539,8 +2539,9 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, mod_cur_headers(pkt_dev); datalen = (odev->hard_header_len + 16) & ~0xf; - skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen + - pkt_dev->pkt_overhead, GFP_ATOMIC); + skb = __netdev_alloc_skb(odev, + pkt_dev->cur_pkt_size + 64 + + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT); if (!skb) { sprintf(pkt_dev->result, "No memory"); return NULL; @@ -2878,8 +2879,9 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, queue_map = pkt_dev->cur_queue_map; mod_cur_headers(pkt_dev); - skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 + - pkt_dev->pkt_overhead, GFP_ATOMIC); + skb = __netdev_alloc_skb(odev, + pkt_dev->cur_pkt_size + 64 + + 16 + pkt_dev->pkt_overhead, GFP_NOWAIT); if (!skb) { sprintf(pkt_dev->result, "No memory"); return NULL; -- cgit v0.10.2 From 5b8db2f568c4ee2a436f0e1c1416153e2878f869 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:14 +0000 Subject: pktgen: reorganize transmit loop Handle standard (and non-standard) return values in a switch. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 2456bd5..bce9bf4 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3424,27 +3424,29 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->last_ok = 0; else { atomic_inc(&(pkt_dev->skb->users)); - retry_now: + + retry_now: ret = (*xmit)(pkt_dev->skb, odev); - if (likely(ret == NETDEV_TX_OK)) { + switch (ret) { + case NETDEV_TX_OK: txq_trans_update(txq); pkt_dev->last_ok = 1; pkt_dev->sofar++; pkt_dev->seq_num++; pkt_dev->tx_bytes += pkt_dev->cur_pkt_size; - - } else if (ret == NETDEV_TX_LOCKED - && (odev->features & NETIF_F_LLTX)) { + break; + case NETDEV_TX_LOCKED: cpu_relax(); goto retry_now; - } else { /* Retry it next time */ - - atomic_dec(&(pkt_dev->skb->users)); - - if (debug && net_ratelimit()) - printk(KERN_INFO "pktgen: Hard xmit error\n"); - + default: /* Drivers are not supposed to return other values! */ + if (net_ratelimit()) + pr_info("pktgen: %s xmit error: %d\n", + odev->name, ret); pkt_dev->errors++; + /* fallthru */ + case NETDEV_TX_BUSY: + /* Retry it next time */ + atomic_dec(&(pkt_dev->skb->users)); pkt_dev->last_ok = 0; } -- cgit v0.10.2 From 5c9d191c166233e723e632e79bcca2127a5fece9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:15 +0000 Subject: pktgen: avoid calling gettimeofday If not using delay then no need to update next_tx after each packet sent. This allows pktgen to send faster especially on systems with slower clock sources. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index bce9bf4..b7302e1 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3450,15 +3450,17 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->last_ok = 0; } - pkt_dev->next_tx_us = getCurUs(); - pkt_dev->next_tx_ns = 0; + if (pkt_dev->delay_us || pkt_dev->delay_ns) { + pkt_dev->next_tx_us = getCurUs(); + pkt_dev->next_tx_ns = 0; - pkt_dev->next_tx_us += pkt_dev->delay_us; - pkt_dev->next_tx_ns += pkt_dev->delay_ns; + pkt_dev->next_tx_us += pkt_dev->delay_us; + pkt_dev->next_tx_ns += pkt_dev->delay_ns; - if (pkt_dev->next_tx_ns > 1000) { - pkt_dev->next_tx_us++; - pkt_dev->next_tx_ns -= 1000; + if (pkt_dev->next_tx_ns > 1000) { + pkt_dev->next_tx_us++; + pkt_dev->next_tx_ns -= 1000; + } } } __netif_tx_unlock_bh(txq); -- cgit v0.10.2 From fd29cf72621071d1d5f9bae634a4505b05f0e58b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:16 +0000 Subject: pktgen: convert to use ktime_t The kernel ktime_t is a nice generic infrastructure for mananging high resolution times, as is done in pktgen. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index b7302e1..bede00b 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -246,16 +246,14 @@ struct pktgen_dev { int max_pkt_size; /* = ETH_ZLEN; */ int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ int nfrags; - __u32 delay_us; /* Default delay */ - __u32 delay_ns; + u64 delay; /* nano-seconds */ + __u64 count; /* Default No packets to send */ __u64 sofar; /* How many pkts we've sent so far */ __u64 tx_bytes; /* How many bytes we've transmitted */ __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */ /* runtime counters relating to clone_skb */ - __u64 next_tx_us; /* timestamp of when to tx next */ - __u32 next_tx_ns; __u64 allocated_skbs; __u32 clone_count; @@ -263,9 +261,11 @@ struct pktgen_dev { * Or a failed transmit of some sort? This will keep * sequence numbers in order, for example. */ - __u64 started_at; /* micro-seconds */ - __u64 stopped_at; /* micro-seconds */ - __u64 idle_acc; /* micro-seconds */ + ktime_t next_tx; + ktime_t started_at; + ktime_t stopped_at; + u64 idle_acc; /* nano-seconds */ + __u32 seq_num; int clone_skb; /* Use multiple SKBs during packet gen. If this number @@ -397,23 +397,20 @@ struct pktgen_thread { #define REMOVE 1 #define FIND 0 -/** Convert to micro-seconds */ -static inline __u64 tv_to_us(const struct timeval *tv) +static inline ktime_t ktime_now(void) { - __u64 us = tv->tv_usec; - us += (__u64) tv->tv_sec * (__u64) 1000000; - return us; + struct timespec ts; + ktime_get_ts(&ts); + + return timespec_to_ktime(ts); } -static __u64 getCurUs(void) +/* This works even if 32 bit because of careful byte order choice */ +static inline int ktime_lt(const ktime_t cmp1, const ktime_t cmp2) { - struct timeval tv; - do_gettimeofday(&tv); - return tv_to_us(&tv); + return cmp1.tv64 < cmp2.tv64; } -/* old include end */ - static const char version[] __initconst = VERSION; static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); @@ -510,9 +507,8 @@ static const struct file_operations pktgen_fops = { static int pktgen_if_show(struct seq_file *seq, void *v) { const struct pktgen_dev *pkt_dev = seq->private; - __u64 sa; - __u64 stopped; - __u64 now = getCurUs(); + ktime_t stopped; + u64 idle; seq_printf(seq, "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", @@ -520,9 +516,8 @@ static int pktgen_if_show(struct seq_file *seq, void *v) pkt_dev->max_pkt_size); seq_printf(seq, - " frags: %d delay: %u clone_skb: %d ifname: %s\n", - pkt_dev->nfrags, - 1000 * pkt_dev->delay_us + pkt_dev->delay_ns, + " frags: %d delay: %llu clone_skb: %d ifname: %s\n", + pkt_dev->nfrags, (unsigned long long) pkt_dev->delay, pkt_dev->clone_skb, pkt_dev->odev->name); seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, @@ -654,17 +649,21 @@ static int pktgen_if_show(struct seq_file *seq, void *v) seq_puts(seq, "\n"); - sa = pkt_dev->started_at; - stopped = pkt_dev->stopped_at; - if (pkt_dev->running) - stopped = now; /* not really stopped, more like last-running-at */ + /* not really stopped, more like last-running-at */ + stopped = pkt_dev->running ? ktime_now() : pkt_dev->stopped_at; + idle = pkt_dev->idle_acc; + do_div(idle, NSEC_PER_USEC); seq_printf(seq, - "Current:\n pkts-sofar: %llu errors: %llu\n started: %lluus stopped: %lluus idle: %lluus\n", + "Current:\n pkts-sofar: %llu errors: %llu\n", (unsigned long long)pkt_dev->sofar, - (unsigned long long)pkt_dev->errors, (unsigned long long)sa, - (unsigned long long)stopped, - (unsigned long long)pkt_dev->idle_acc); + (unsigned long long)pkt_dev->errors); + + seq_printf(seq, + " started: %lluus stopped: %lluus idle: %lluus\n", + (unsigned long long) ktime_to_us(pkt_dev->started_at), + (unsigned long long) ktime_to_us(stopped), + (unsigned long long) idle); seq_printf(seq, " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", @@ -950,15 +949,13 @@ static ssize_t pktgen_if_write(struct file *file, return len; } i += len; - if (value == 0x7FFFFFFF) { - pkt_dev->delay_us = 0x7FFFFFFF; - pkt_dev->delay_ns = 0; - } else { - pkt_dev->delay_us = value / 1000; - pkt_dev->delay_ns = value % 1000; - } - sprintf(pg_result, "OK: delay=%u", - 1000 * pkt_dev->delay_us + pkt_dev->delay_ns); + if (value == 0x7FFFFFFF) + pkt_dev->delay = ULLONG_MAX; + else + pkt_dev->delay = (u64)value * NSEC_PER_USEC; + + sprintf(pg_result, "OK: delay=%llu", + (unsigned long long) pkt_dev->delay); return count; } if (!strcmp(name, "udp_src_min")) { @@ -2089,27 +2086,33 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) pkt_dev->nflows = 0; } -static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us) +static inline s64 delta_ns(ktime_t a, ktime_t b) { - __u64 start; - __u64 now; + return ktime_to_ns(ktime_sub(a, b)); +} + +static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) +{ + ktime_t start, now; + s64 dt; + + start = now = ktime_now(); - start = now = getCurUs(); - while (now < spin_until_us) { + while ((dt = delta_ns(spin_until, now)) > 0) { /* TODO: optimize sleeping behavior */ - if (spin_until_us - now > jiffies_to_usecs(1) + 1) + if (dt > TICK_NSEC) schedule_timeout_interruptible(1); - else if (spin_until_us - now > 100) { + else if (dt > 100*NSEC_PER_USEC) { if (!pkt_dev->running) return; if (need_resched()) schedule(); } - now = getCurUs(); + now = ktime_now(); } - pkt_dev->idle_acc += now - start; + pkt_dev->idle_acc += ktime_to_ns(ktime_sub(now, start)); } static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) @@ -3070,9 +3073,9 @@ static void pktgen_run(struct pktgen_thread *t) pktgen_clear_counters(pkt_dev); pkt_dev->running = 1; /* Cranke yeself! */ pkt_dev->skb = NULL; - pkt_dev->started_at = getCurUs(); - pkt_dev->next_tx_us = getCurUs(); /* Transmit immediately */ - pkt_dev->next_tx_ns = 0; + pkt_dev->started_at = + pkt_dev->next_tx = ktime_now(); + set_pkt_overhead(pkt_dev); strcpy(pkt_dev->result, "Starting"); @@ -3188,28 +3191,21 @@ static void pktgen_reset_all_threads(void) static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) { - __u64 total_us, bps, mbps, pps, idle; + __u64 bps, mbps, pps; char *p = pkt_dev->result; - - total_us = pkt_dev->stopped_at - pkt_dev->started_at; - - idle = pkt_dev->idle_acc; - - p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n", - (unsigned long long)total_us, - (unsigned long long)(total_us - idle), - (unsigned long long)idle, + ktime_t elapsed = ktime_sub(pkt_dev->stopped_at, + pkt_dev->started_at); + ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); + + p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n", + (unsigned long long)ktime_to_us(elapsed), + (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), + (unsigned long long)ktime_to_us(idle), (unsigned long long)pkt_dev->sofar, pkt_dev->cur_pkt_size, nr_frags); - pps = pkt_dev->sofar * USEC_PER_SEC; - - while ((total_us >> 32) != 0) { - pps >>= 1; - total_us >>= 1; - } - - do_div(pps, total_us); + pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC, + ktime_to_ns(elapsed)); bps = pps * 8 * pkt_dev->cur_pkt_size; @@ -3235,7 +3231,7 @@ static int pktgen_stop_device(struct pktgen_dev *pkt_dev) kfree_skb(pkt_dev->skb); pkt_dev->skb = NULL; - pkt_dev->stopped_at = getCurUs(); + pkt_dev->stopped_at = ktime_now(); pkt_dev->running = 0; show_results(pkt_dev, nr_frags); @@ -3254,7 +3250,7 @@ static struct pktgen_dev *next_to_run(struct pktgen_thread *t) continue; if (best == NULL) best = pkt_dev; - else if (pkt_dev->next_tx_us < best->next_tx_us) + else if (ktime_lt(pkt_dev->next_tx, best->next_tx)) best = pkt_dev; } if_unlock(t); @@ -3343,16 +3339,17 @@ static void pktgen_rem_thread(struct pktgen_thread *t) static void idle(struct pktgen_dev *pkt_dev) { - u64 idle_start = getCurUs(); + ktime_t idle_start = ktime_now(); if (need_resched()) schedule(); else cpu_relax(); - pkt_dev->idle_acc += getCurUs() - idle_start; + pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start)); } + static void pktgen_xmit(struct pktgen_dev *pkt_dev) { struct net_device *odev = pkt_dev->odev; @@ -3362,19 +3359,15 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) u16 queue_map; int ret; - if (pkt_dev->delay_us || pkt_dev->delay_ns) { - u64 now; - - now = getCurUs(); - if (now < pkt_dev->next_tx_us) - spin(pkt_dev, pkt_dev->next_tx_us); + if (pkt_dev->delay) { + if (ktime_lt(ktime_now(), pkt_dev->next_tx)) + spin(pkt_dev, pkt_dev->next_tx); /* This is max DELAY, this has special meaning of * "never transmit" */ - if (pkt_dev->delay_us == 0x7FFFFFFF) { - pkt_dev->next_tx_us = getCurUs() + pkt_dev->delay_us; - pkt_dev->next_tx_ns = pkt_dev->delay_ns; + if (pkt_dev->delay == ULLONG_MAX) { + pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX); return; } } @@ -3450,32 +3443,24 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->last_ok = 0; } - if (pkt_dev->delay_us || pkt_dev->delay_ns) { - pkt_dev->next_tx_us = getCurUs(); - pkt_dev->next_tx_ns = 0; - - pkt_dev->next_tx_us += pkt_dev->delay_us; - pkt_dev->next_tx_ns += pkt_dev->delay_ns; - - if (pkt_dev->next_tx_ns > 1000) { - pkt_dev->next_tx_us++; - pkt_dev->next_tx_ns -= 1000; - } - } + if (pkt_dev->delay) + pkt_dev->next_tx = ktime_add_ns(ktime_now(), + pkt_dev->delay); } __netif_tx_unlock_bh(txq); /* If pkt_dev->count is zero, then run forever */ if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { if (atomic_read(&(pkt_dev->skb->users)) != 1) { - u64 idle_start = getCurUs(); + ktime_t idle_start = ktime_now(); while (atomic_read(&(pkt_dev->skb->users)) != 1) { if (signal_pending(current)) { break; } schedule(); } - pkt_dev->idle_acc += getCurUs() - idle_start; + pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), + idle_start)); } /* Done with this */ @@ -3634,8 +3619,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) pkt_dev->max_pkt_size = ETH_ZLEN; pkt_dev->nfrags = 0; pkt_dev->clone_skb = pg_clone_skb_d; - pkt_dev->delay_us = pg_delay_d / 1000; - pkt_dev->delay_ns = pg_delay_d % 1000; + pkt_dev->delay = pg_delay_d; pkt_dev->count = pg_count_d; pkt_dev->sofar = 0; pkt_dev->udp_src_min = 9; /* sink port */ -- cgit v0.10.2 From 2bc481cf433879f0e6cdd4d899fc21ee05dcea23 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 28 Aug 2009 23:41:29 -0700 Subject: pktgen: spin using hrtimer This changes how the pktgen thread spins/waits between packets if delay is configured. It uses a high res timer to wait for time to arrive. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 49da79a..05071bf 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -485,6 +485,7 @@ void hrtimer_init_on_stack(struct hrtimer *timer, clockid_t clock_id, debug_object_init_on_stack(timer, &hrtimer_debug_descr); __hrtimer_init(timer, clock_id, mode); } +EXPORT_SYMBOL_GPL(hrtimer_init_on_stack); void destroy_hrtimer_on_stack(struct hrtimer *timer) { @@ -1477,6 +1478,7 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task) sl->timer.function = hrtimer_wakeup; sl->task = task; } +EXPORT_SYMBOL_GPL(hrtimer_init_sleeper); static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode) { diff --git a/net/core/pktgen.c b/net/core/pktgen.c index bede00b..3045dd1 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -131,6 +131,7 @@ #include #include #include +#include #include #include #include @@ -2086,33 +2087,40 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) pkt_dev->nflows = 0; } -static inline s64 delta_ns(ktime_t a, ktime_t b) -{ - return ktime_to_ns(ktime_sub(a, b)); -} static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) { - ktime_t start, now; - s64 dt; + ktime_t start; + s32 remaining; + struct hrtimer_sleeper t; - start = now = ktime_now(); + hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + hrtimer_set_expires(&t.timer, spin_until); + + remaining = ktime_to_us(hrtimer_expires_remaining(&t.timer)); + if (remaining <= 0) + return; - while ((dt = delta_ns(spin_until, now)) > 0) { - /* TODO: optimize sleeping behavior */ - if (dt > TICK_NSEC) - schedule_timeout_interruptible(1); - else if (dt > 100*NSEC_PER_USEC) { - if (!pkt_dev->running) - return; - if (need_resched()) + start = ktime_now(); + if (remaining < 100) + udelay(remaining); /* really small just spin */ + else { + /* see do_nanosleep */ + hrtimer_init_sleeper(&t, current); + do { + set_current_state(TASK_INTERRUPTIBLE); + hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS); + if (!hrtimer_active(&t.timer)) + t.task = NULL; + + if (likely(t.task)) schedule(); - } - now = ktime_now(); + hrtimer_cancel(&t.timer); + } while (t.task && pkt_dev->running && !signal_pending(current)); + __set_current_state(TASK_RUNNING); } - - pkt_dev->idle_acc += ktime_to_ns(ktime_sub(now, start)); + pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), start)); } static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) @@ -3360,8 +3368,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) int ret; if (pkt_dev->delay) { - if (ktime_lt(ktime_now(), pkt_dev->next_tx)) - spin(pkt_dev, pkt_dev->next_tx); + spin(pkt_dev, pkt_dev->next_tx); /* This is max DELAY, this has special meaning of * "never transmit" -- cgit v0.10.2 From 64e8ff5ef2a798cae2e3bede75644173aae98e08 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:18 +0000 Subject: pktgen: use common idle routine Simpler to have one place that spins and accounts for delays, this will also make the last packet be detected faster for more repeatable timing. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 3045dd1..ad41f06 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3458,16 +3458,10 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) /* If pkt_dev->count is zero, then run forever */ if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { - if (atomic_read(&(pkt_dev->skb->users)) != 1) { - ktime_t idle_start = ktime_now(); - while (atomic_read(&(pkt_dev->skb->users)) != 1) { - if (signal_pending(current)) { - break; - } - schedule(); - } - pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), - idle_start)); + while (atomic_read(&(pkt_dev->skb->users)) != 1) { + if (signal_pending(current)) + break; + idle(pkt_dev); } /* Done with this */ -- cgit v0.10.2 From 63adc6fb8ac0dee0020d6ad73e0d44f4306e1e34 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:19 +0000 Subject: pktgen: cleanup checkpatch warnings Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index ad41f06..51b1e61 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -163,13 +163,14 @@ #include #include #include -#include +#include +#include +#include #include -#include #include /* do_div */ -#include -#define VERSION "pktgen v2.70: Packet Generator for packet performance testing.\n" +#define VERSION \ + "pktgen v2.70: Packet Generator for packet performance testing.\n" #define IP_NAME_SZ 32 #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */ @@ -207,7 +208,7 @@ #define PKTGEN_MAGIC 0xbe9be955 #define PG_PROC_DIR "pktgen" #define PGCTRL "pgctrl" -static struct proc_dir_entry *pg_proc_dir = NULL; +static struct proc_dir_entry *pg_proc_dir; #define MAX_CFLOWS 65536 @@ -232,9 +233,9 @@ struct pktgen_dev { */ struct proc_dir_entry *entry; /* proc file */ struct pktgen_thread *pg_thread;/* the owner */ - struct list_head list; /* Used for chaining in the thread's run-queue */ + struct list_head list; /* chaining in the thread's run-queue */ - int running; /* if this changes to false, the test will stop */ + int running; /* if false, the test will stop */ /* If min != max, then we will either do a linear iteration, or * we will do a random selection from within the range. @@ -252,15 +253,16 @@ struct pktgen_dev { __u64 count; /* Default No packets to send */ __u64 sofar; /* How many pkts we've sent so far */ __u64 tx_bytes; /* How many bytes we've transmitted */ - __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */ + __u64 errors; /* Errors when trying to transmit, + pkts will be re-sent */ /* runtime counters relating to clone_skb */ __u64 allocated_skbs; __u32 clone_count; int last_ok; /* Was last skb sent? - * Or a failed transmit of some sort? This will keep - * sequence numbers in order, for example. + * Or a failed transmit of some sort? + * This will keep sequence numbers in order */ ktime_t next_tx; ktime_t started_at; @@ -269,11 +271,14 @@ struct pktgen_dev { __u32 seq_num; - int clone_skb; /* Use multiple SKBs during packet gen. If this number - * is greater than 1, then that many copies of the same - * packet will be sent before a new packet is allocated. - * For instance, if you want to send 1024 identical packets - * before creating a new packet, set clone_skb to 1024. + int clone_skb; /* + * Use multiple SKBs during packet gen. + * If this number is greater than 1, then + * that many copies of the same packet will be + * sent before a new packet is allocated. + * If you want to send 1024 identical packets + * before creating a new packet, + * set clone_skb to 1024. */ char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ @@ -305,8 +310,10 @@ struct pktgen_dev { __u16 udp_dst_max; /* exclusive, dest UDP port */ /* DSCP + ECN */ - __u8 tos; /* six most significant bits of (former) IPv4 TOS are for dscp codepoint */ - __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 (see RFC 3260, sec. 4) */ + __u8 tos; /* six MSB of (former) IPv4 TOS + are for dscp codepoint */ + __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 + (see RFC 3260, sec. 4) */ /* MPLS */ unsigned nr_labels; /* Depth of stack, 0 = no MPLS */ @@ -347,15 +354,17 @@ struct pktgen_dev { */ __u16 pad; /* pad out the hh struct to an even 16 bytes */ - struct sk_buff *skb; /* skb we are to transmit next, mainly used for when we + struct sk_buff *skb; /* skb we are to transmit next, used for when we * are transmitting the same one multiple times */ - struct net_device *odev; /* The out-going device. Note that the device should - * have it's pg_info pointer pointing back to this - * device. This will be set when the user specifies - * the out-going device name (not when the inject is - * started as it used to do.) - */ + struct net_device *odev; /* The out-going device. + * Note that the device should have it's + * pg_info pointer pointing back to this + * device. + * Set when the user specifies the out-going + * device name (not when the inject is + * started as it used to do.) + */ struct flow_state *flows; unsigned cflows; /* Concurrent flows (config) */ unsigned lflow; /* Flow length (config) */ @@ -380,13 +389,14 @@ struct pktgen_hdr { }; struct pktgen_thread { - spinlock_t if_lock; + spinlock_t if_lock; /* for list of devices */ struct list_head if_list; /* All device here */ struct list_head th_list; struct task_struct *tsk; char result[512]; - /* Field for thread to receive "posted" events terminate, stop ifs etc. */ + /* Field for thread to receive "posted" events terminate, + stop ifs etc. */ u32 control; int cpu; @@ -453,8 +463,8 @@ static int pgctrl_show(struct seq_file *seq, void *v) return 0; } -static ssize_t pgctrl_write(struct file *file, const char __user * buf, - size_t count, loff_t * ppos) +static ssize_t pgctrl_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { int err = 0; char data[128]; @@ -545,11 +555,14 @@ static int pktgen_if_show(struct seq_file *seq, void *v) " daddr: %s min_daddr: %s max_daddr: %s\n", b1, b2, b3); - } else + } else { + seq_printf(seq, + " dst_min: %s dst_max: %s\n", + pkt_dev->dst_min, pkt_dev->dst_max); seq_printf(seq, - " dst_min: %s dst_max: %s\n src_min: %s src_max: %s\n", - pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min, - pkt_dev->src_max); + " src_min: %s src_max: %s\n", + pkt_dev->src_min, pkt_dev->src_max); + } seq_puts(seq, " src_mac: "); @@ -561,7 +574,8 @@ static int pktgen_if_show(struct seq_file *seq, void *v) seq_printf(seq, "%pM\n", pkt_dev->dst_mac); seq_printf(seq, - " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", + " udp_src_min: %d udp_src_max: %d" + " udp_dst_min: %d udp_dst_max: %d\n", pkt_dev->udp_src_min, pkt_dev->udp_src_max, pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); @@ -577,23 +591,21 @@ static int pktgen_if_show(struct seq_file *seq, void *v) i == pkt_dev->nr_labels-1 ? "\n" : ", "); } - if (pkt_dev->vlan_id != 0xffff) { + if (pkt_dev->vlan_id != 0xffff) seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", - pkt_dev->vlan_id, pkt_dev->vlan_p, pkt_dev->vlan_cfi); - } + pkt_dev->vlan_id, pkt_dev->vlan_p, + pkt_dev->vlan_cfi); - if (pkt_dev->svlan_id != 0xffff) { + if (pkt_dev->svlan_id != 0xffff) seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", - pkt_dev->svlan_id, pkt_dev->svlan_p, pkt_dev->svlan_cfi); - } + pkt_dev->svlan_id, pkt_dev->svlan_p, + pkt_dev->svlan_cfi); - if (pkt_dev->tos) { + if (pkt_dev->tos) seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos); - } - if (pkt_dev->traffic_class) { + if (pkt_dev->traffic_class) seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); - } seq_printf(seq, " Flags: "); @@ -696,7 +708,8 @@ static int pktgen_if_show(struct seq_file *seq, void *v) } -static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, __u32 *num) +static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, + __u32 *num) { int i = 0; *num = 0; @@ -846,9 +859,9 @@ static ssize_t pktgen_if_write(struct file *file, /* Read variable name */ len = strn_len(&user_buffer[i], sizeof(name) - 1); - if (len < 0) { + if (len < 0) return len; - } + memset(name, 0, sizeof(name)); if (copy_from_user(name, &user_buffer[i], len)) return -EFAULT; @@ -872,9 +885,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "min_pkt_size")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (value < 14 + 20 + 8) value = 14 + 20 + 8; @@ -889,9 +902,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "max_pkt_size")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (value < 14 + 20 + 8) value = 14 + 20 + 8; @@ -908,9 +921,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "pkt_size")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (value < 14 + 20 + 8) value = 14 + 20 + 8; @@ -925,9 +938,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "debug")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; debug = value; sprintf(pg_result, "OK: debug=%u", debug); @@ -936,9 +949,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "frags")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; pkt_dev->nfrags = value; sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags); @@ -946,9 +959,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "delay")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (value == 0x7FFFFFFF) pkt_dev->delay = ULLONG_MAX; @@ -961,9 +974,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "udp_src_min")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (value != pkt_dev->udp_src_min) { pkt_dev->udp_src_min = value; @@ -974,9 +987,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "udp_dst_min")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (value != pkt_dev->udp_dst_min) { pkt_dev->udp_dst_min = value; @@ -987,9 +1000,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "udp_src_max")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (value != pkt_dev->udp_src_max) { pkt_dev->udp_src_max = value; @@ -1000,9 +1013,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "udp_dst_max")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (value != pkt_dev->udp_dst_max) { pkt_dev->udp_dst_max = value; @@ -1013,9 +1026,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "clone_skb")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; pkt_dev->clone_skb = value; @@ -1024,9 +1037,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "count")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; pkt_dev->count = value; sprintf(pg_result, "OK: count=%llu", @@ -1035,9 +1048,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "src_mac_count")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (pkt_dev->src_mac_count != value) { pkt_dev->src_mac_count = value; @@ -1049,9 +1062,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "dst_mac_count")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (pkt_dev->dst_mac_count != value) { pkt_dev->dst_mac_count = value; @@ -1065,9 +1078,9 @@ static ssize_t pktgen_if_write(struct file *file, char f[32]; memset(f, 0, 32); len = strn_len(&user_buffer[i], sizeof(f) - 1); - if (len < 0) { + if (len < 0) return len; - } + if (copy_from_user(f, &user_buffer[i], len)) return -EFAULT; i += len; @@ -1166,9 +1179,8 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); - if (len < 0) { + if (len < 0) return len; - } if (copy_from_user(buf, &user_buffer[i], len)) return -EFAULT; @@ -1188,9 +1200,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "dst_max")) { len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); - if (len < 0) { + if (len < 0) return len; - } + if (copy_from_user(buf, &user_buffer[i], len)) return -EFAULT; @@ -1301,9 +1313,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "src_min")) { len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); - if (len < 0) { + if (len < 0) return len; - } + if (copy_from_user(buf, &user_buffer[i], len)) return -EFAULT; buf[len] = 0; @@ -1322,9 +1334,9 @@ static ssize_t pktgen_if_write(struct file *file, } if (!strcmp(name, "src_max")) { len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); - if (len < 0) { + if (len < 0) return len; - } + if (copy_from_user(buf, &user_buffer[i], len)) return -EFAULT; buf[len] = 0; @@ -1348,9 +1360,9 @@ static ssize_t pktgen_if_write(struct file *file, memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN); len = strn_len(&user_buffer[i], sizeof(valstr) - 1); - if (len < 0) { + if (len < 0) return len; - } + memset(valstr, 0, sizeof(valstr)); if (copy_from_user(valstr, &user_buffer[i], len)) return -EFAULT; @@ -1390,9 +1402,9 @@ static ssize_t pktgen_if_write(struct file *file, memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN); len = strn_len(&user_buffer[i], sizeof(valstr) - 1); - if (len < 0) { + if (len < 0) return len; - } + memset(valstr, 0, sizeof(valstr)); if (copy_from_user(valstr, &user_buffer[i], len)) return -EFAULT; @@ -1433,9 +1445,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "flows")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (value > MAX_CFLOWS) value = MAX_CFLOWS; @@ -1447,9 +1459,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "flowlen")) { len = num_arg(&user_buffer[i], 10, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; pkt_dev->lflow = value; sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); @@ -1458,9 +1470,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "queue_map_min")) { len = num_arg(&user_buffer[i], 5, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; pkt_dev->queue_map_min = value; sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min); @@ -1469,9 +1481,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "queue_map_max")) { len = num_arg(&user_buffer[i], 5, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; pkt_dev->queue_map_max = value; sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max); @@ -1503,9 +1515,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "vlan_id")) { len = num_arg(&user_buffer[i], 4, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (value <= 4095) { pkt_dev->vlan_id = value; /* turn on VLAN */ @@ -1530,9 +1542,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "vlan_p")) { len = num_arg(&user_buffer[i], 1, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { pkt_dev->vlan_p = value; @@ -1545,9 +1557,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "vlan_cfi")) { len = num_arg(&user_buffer[i], 1, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { pkt_dev->vlan_cfi = value; @@ -1560,9 +1572,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "svlan_id")) { len = num_arg(&user_buffer[i], 4, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { pkt_dev->svlan_id = value; /* turn on SVLAN */ @@ -1587,9 +1599,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "svlan_p")) { len = num_arg(&user_buffer[i], 1, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { pkt_dev->svlan_p = value; @@ -1602,9 +1614,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "svlan_cfi")) { len = num_arg(&user_buffer[i], 1, &value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { pkt_dev->svlan_cfi = value; @@ -1618,9 +1630,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "tos")) { __u32 tmp_value = 0; len = hex32_arg(&user_buffer[i], 2, &tmp_value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (len == 2) { pkt_dev->tos = tmp_value; @@ -1634,9 +1646,9 @@ static ssize_t pktgen_if_write(struct file *file, if (!strcmp(name, "traffic_class")) { __u32 tmp_value = 0; len = hex32_arg(&user_buffer[i], 2, &tmp_value); - if (len < 0) { + if (len < 0) return len; - } + i += len; if (len == 2) { pkt_dev->traffic_class = tmp_value; @@ -1906,13 +1918,14 @@ static int pktgen_device_event(struct notifier_block *unused, return NOTIFY_DONE; } -static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, const char *ifname) +static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, + const char *ifname) { char b[IFNAMSIZ+5]; int i = 0; - for(i=0; ifname[i] != '@'; i++) { - if(i == IFNAMSIZ) + for (i = 0; ifname[i] != '@'; i++) { + if (i == IFNAMSIZ) break; b[i] = ifname[i]; @@ -1979,7 +1992,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) printk(KERN_WARNING "pktgen: WARNING: Requested " "queue_map_min (zero-based) (%d) exceeds valid range " "[0 - %d] for (%d) queues on %s, resetting\n", - pkt_dev->queue_map_min, (ntxq ?: 1)- 1, ntxq, + pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq, pkt_dev->odev->name); pkt_dev->queue_map_min = ntxq - 1; } @@ -1987,7 +2000,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) printk(KERN_WARNING "pktgen: WARNING: Requested " "queue_map_max (zero-based) (%d) exceeds valid range " "[0 - %d] for (%d) queues on %s, resetting\n", - pkt_dev->queue_map_max, (ntxq ?: 1)- 1, ntxq, + pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq, pkt_dev->odev->name); pkt_dev->queue_map_max = ntxq - 1; } @@ -2028,7 +2041,8 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) */ rcu_read_lock(); - if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) { + idev = __in6_dev_get(pkt_dev->odev); + if (idev) { struct inet6_ifaddr *ifp; read_lock_bh(&idev->lock); @@ -2181,7 +2195,7 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) if (x) { pkt_dev->flows[flow].x = x; set_pkt_overhead(pkt_dev); - pkt_dev->pkt_overhead+=x->props.header_len; + pkt_dev->pkt_overhead += x->props.header_len; } } @@ -2320,18 +2334,18 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) if (!(pkt_dev->flags & F_IPV6)) { - if ((imn = ntohl(pkt_dev->saddr_min)) < (imx = - ntohl(pkt_dev-> - saddr_max))) { + imn = ntohl(pkt_dev->saddr_min); + imx = ntohl(pkt_dev->saddr_max); + if (imn < imx) { __u32 t; if (pkt_dev->flags & F_IPSRC_RND) t = random32() % (imx - imn) + imn; else { t = ntohl(pkt_dev->cur_saddr); t++; - if (t > imx) { + if (t > imx) t = imn; - } + } pkt_dev->cur_saddr = htonl(t); } @@ -2442,7 +2456,7 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) if (err) goto error; - x->curlft.bytes +=skb->len; + x->curlft.bytes += skb->len; x->curlft.packets++; error: spin_unlock(&x->lock); @@ -2474,11 +2488,11 @@ static int process_ipsec(struct pktgen_dev *pkt_dev, int ret; __u8 *eth; nhead = x->props.header_len - skb_headroom(skb); - if (nhead >0) { + if (nhead > 0) { ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); if (ret < 0) { printk(KERN_ERR "Error expanding " - "ipsec packet %d\n",ret); + "ipsec packet %d\n", ret); goto err; } } @@ -2488,13 +2502,13 @@ static int process_ipsec(struct pktgen_dev *pkt_dev, ret = pktgen_output_ipsec(skb, pkt_dev); if (ret) { printk(KERN_ERR "Error creating ipsec " - "packet %d\n",ret); + "packet %d\n", ret); goto err; } /* restore ll */ eth = (__u8 *) skb_push(skb, ETH_HLEN); memcpy(eth, pkt_dev->hh, 12); - *(u16 *) & eth[12] = protocol; + *(u16 *) ð[12] = protocol; } } return 1; @@ -2507,9 +2521,9 @@ err: static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) { unsigned i; - for (i = 0; i < pkt_dev->nr_labels; i++) { + for (i = 0; i < pkt_dev->nr_labels; i++) *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; - } + mpls--; *mpls |= MPLS_STACK_BOTTOM; } @@ -2676,8 +2690,9 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, } } - /* Stamp the time, and sequence number, convert them to network byte order */ - + /* Stamp the time, and sequence number, + * convert them to network byte order + */ if (pgh) { struct timeval timestamp; @@ -2931,7 +2946,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, udph = udp_hdr(skb); memcpy(eth, pkt_dev->hh, 12); - *(__be16 *) & eth[12] = protocol; + *(__be16 *) ð[12] = protocol; /* Eth + IPh + UDPh + mpls */ datalen = pkt_dev->cur_pkt_size - 14 - @@ -3025,8 +3040,10 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, } } - /* Stamp the time, and sequence number, convert them to network byte order */ - /* should we update cloned packets too ? */ + /* Stamp the time, and sequence number, + * convert them to network byte order + * should we update cloned packets too ? + */ if (pgh) { struct timeval timestamp; @@ -3174,7 +3191,8 @@ static void pktgen_run_all_threads(void) mutex_unlock(&pktgen_thread_lock); - schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ + /* Propagate thread->control */ + schedule_timeout_interruptible(msecs_to_jiffies(125)); pktgen_wait_all_threads_run(); } @@ -3192,7 +3210,8 @@ static void pktgen_reset_all_threads(void) mutex_unlock(&pktgen_thread_lock); - schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ + /* Propagate thread->control */ + schedule_timeout_interruptible(msecs_to_jiffies(125)); pktgen_wait_all_threads_run(); } @@ -3485,7 +3504,8 @@ static int pktgen_thread_worker(void *arg) init_waitqueue_head(&t->queue); complete(&t->start_done); - pr_debug("pktgen: starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); + pr_debug("pktgen: starting pktgen/%d: pid=%d\n", + cpu, task_pid_nr(current)); set_current_state(TASK_INTERRUPTIBLE); -- cgit v0.10.2 From c3d2f52dd40b5b6c122329dac32dc0e0351f0598 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Aug 2009 13:55:20 +0000 Subject: pktgen: increase version Increase module version, and cleanup module info. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 51b1e61..42e4cce 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -169,9 +169,7 @@ #include #include /* do_div */ -#define VERSION \ - "pktgen v2.70: Packet Generator for packet performance testing.\n" - +#define VERSION "2.72" #define IP_NAME_SZ 32 #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */ #define MPLS_STACK_BOTTOM htonl(0x00000100) @@ -422,7 +420,8 @@ static inline int ktime_lt(const ktime_t cmp1, const ktime_t cmp2) return cmp1.tv64 < cmp2.tv64; } -static const char version[] __initconst = VERSION; +static const char version[] = + "pktgen " VERSION ": Packet Generator for packet performance testing.\n"; static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); @@ -459,7 +458,7 @@ static struct notifier_block pktgen_notifier_block = { static int pgctrl_show(struct seq_file *seq, void *v) { - seq_puts(seq, VERSION); + seq_puts(seq, version); return 0; } @@ -3852,10 +3851,15 @@ static void __exit pg_cleanup(void) module_init(pg_init); module_exit(pg_cleanup); -MODULE_AUTHOR("Robert Olsson "); MODULE_DESCRIPTION("Packet Generator tool"); MODULE_LICENSE("GPL"); +MODULE_VERSION(VERSION); module_param(pg_count_d, int, 0); +MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject"); module_param(pg_delay_d, int, 0); +MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)"); module_param(pg_clone_skb_d, int, 0); +MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet"); module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Enable debugging of pktgen module"); -- cgit v0.10.2 From 2975315b79f4109523b3d43932f57ed8370b9da3 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 28 Aug 2009 23:34:43 -0700 Subject: pktgen: use proc_create_data() It looks like after rename device proc entry is unusable, because of no ->read_proc or ->proc_fops. And create_proc_entry() is deprecated. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 42e4cce..2001cb1 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1882,8 +1882,10 @@ static void pktgen_change_name(struct net_device *dev) remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); - pkt_dev->entry = create_proc_entry(dev->name, 0600, - pg_proc_dir); + pkt_dev->entry = proc_create_data(dev->name, 0600, + pg_proc_dir, + &pktgen_if_fops, + pkt_dev); if (!pkt_dev->entry) printk(KERN_ERR "pktgen: can't move proc " " entry for '%s'\n", dev->name); -- cgit v0.10.2 From 3d1427f87002735aa54c370558e0c2bacc61f31e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Aug 2009 23:45:21 -0700 Subject: ipv4: af_inet.c cleanups Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 197d024..6c30a73 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -124,7 +124,6 @@ static struct list_head inetsw[SOCK_MAX]; static DEFINE_SPINLOCK(inetsw_lock); struct ipv4_config ipv4_config; - EXPORT_SYMBOL(ipv4_config); /* New destruction routine */ @@ -139,12 +138,12 @@ void inet_sock_destruct(struct sock *sk) sk_mem_reclaim(sk); if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) { - printk("Attempt to release TCP socket in state %d %p\n", + pr_err("Attempt to release TCP socket in state %d %p\n", sk->sk_state, sk); return; } if (!sock_flag(sk, SOCK_DEAD)) { - printk("Attempt to release alive inet socket %p\n", sk); + pr_err("Attempt to release alive inet socket %p\n", sk); return; } @@ -157,6 +156,7 @@ void inet_sock_destruct(struct sock *sk) dst_release(sk->sk_dst_cache); sk_refcnt_debug_dec(sk); } +EXPORT_SYMBOL(inet_sock_destruct); /* * The routines beyond this point handle the behaviour of an AF_INET @@ -219,6 +219,7 @@ out: release_sock(sk); return err; } +EXPORT_SYMBOL(inet_listen); u32 inet_ehash_secret __read_mostly; EXPORT_SYMBOL(inet_ehash_secret); @@ -435,9 +436,11 @@ int inet_release(struct socket *sock) } return 0; } +EXPORT_SYMBOL(inet_release); /* It is off by default, see below. */ int sysctl_ip_nonlocal_bind __read_mostly; +EXPORT_SYMBOL(sysctl_ip_nonlocal_bind); int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { @@ -519,6 +522,7 @@ out_release_sock: out: return err; } +EXPORT_SYMBOL(inet_bind); int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr, int addr_len, int flags) @@ -532,6 +536,7 @@ int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr, return -EAGAIN; return sk->sk_prot->connect(sk, (struct sockaddr *)uaddr, addr_len); } +EXPORT_SYMBOL(inet_dgram_connect); static long inet_wait_for_connect(struct sock *sk, long timeo) { @@ -641,6 +646,7 @@ sock_error: sock->state = SS_DISCONNECTING; goto out; } +EXPORT_SYMBOL(inet_stream_connect); /* * Accept a pending connection. The TCP layer now gives BSD semantics. @@ -668,6 +674,7 @@ int inet_accept(struct socket *sock, struct socket *newsock, int flags) do_err: return err; } +EXPORT_SYMBOL(inet_accept); /* @@ -699,6 +706,7 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr, *uaddr_len = sizeof(*sin); return 0; } +EXPORT_SYMBOL(inet_getname); int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size) @@ -711,9 +719,11 @@ int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, return sk->sk_prot->sendmsg(iocb, sk, msg, size); } +EXPORT_SYMBOL(inet_sendmsg); -static ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) +static ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, + size_t size, int flags) { struct sock *sk = sock->sk; @@ -780,6 +790,7 @@ int inet_shutdown(struct socket *sock, int how) release_sock(sk); return err; } +EXPORT_SYMBOL(inet_shutdown); /* * ioctl() calls you can issue on an INET socket. Most of these are @@ -798,44 +809,45 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) struct net *net = sock_net(sk); switch (cmd) { - case SIOCGSTAMP: - err = sock_get_timestamp(sk, (struct timeval __user *)arg); - break; - case SIOCGSTAMPNS: - err = sock_get_timestampns(sk, (struct timespec __user *)arg); - break; - case SIOCADDRT: - case SIOCDELRT: - case SIOCRTMSG: - err = ip_rt_ioctl(net, cmd, (void __user *)arg); - break; - case SIOCDARP: - case SIOCGARP: - case SIOCSARP: - err = arp_ioctl(net, cmd, (void __user *)arg); - break; - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCSIFPFLAGS: - case SIOCGIFPFLAGS: - case SIOCSIFFLAGS: - err = devinet_ioctl(net, cmd, (void __user *)arg); - break; - default: - if (sk->sk_prot->ioctl) - err = sk->sk_prot->ioctl(sk, cmd, arg); - else - err = -ENOIOCTLCMD; - break; + case SIOCGSTAMP: + err = sock_get_timestamp(sk, (struct timeval __user *)arg); + break; + case SIOCGSTAMPNS: + err = sock_get_timestampns(sk, (struct timespec __user *)arg); + break; + case SIOCADDRT: + case SIOCDELRT: + case SIOCRTMSG: + err = ip_rt_ioctl(net, cmd, (void __user *)arg); + break; + case SIOCDARP: + case SIOCGARP: + case SIOCSARP: + err = arp_ioctl(net, cmd, (void __user *)arg); + break; + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCSIFPFLAGS: + case SIOCGIFPFLAGS: + case SIOCSIFFLAGS: + err = devinet_ioctl(net, cmd, (void __user *)arg); + break; + default: + if (sk->sk_prot->ioctl) + err = sk->sk_prot->ioctl(sk, cmd, arg); + else + err = -ENOIOCTLCMD; + break; } return err; } +EXPORT_SYMBOL(inet_ioctl); const struct proto_ops inet_stream_ops = { .family = PF_INET, @@ -862,6 +874,7 @@ const struct proto_ops inet_stream_ops = { .compat_getsockopt = compat_sock_common_getsockopt, #endif }; +EXPORT_SYMBOL(inet_stream_ops); const struct proto_ops inet_dgram_ops = { .family = PF_INET, @@ -887,6 +900,7 @@ const struct proto_ops inet_dgram_ops = { .compat_getsockopt = compat_sock_common_getsockopt, #endif }; +EXPORT_SYMBOL(inet_dgram_ops); /* * For SOCK_RAW sockets; should be the same as inet_dgram_ops but without @@ -1016,6 +1030,7 @@ out_illegal: p->type); goto out; } +EXPORT_SYMBOL(inet_register_protosw); void inet_unregister_protosw(struct inet_protosw *p) { @@ -1031,6 +1046,7 @@ void inet_unregister_protosw(struct inet_protosw *p) synchronize_net(); } } +EXPORT_SYMBOL(inet_unregister_protosw); /* * Shall we try to damage output packets if routing dev changes? @@ -1141,7 +1157,6 @@ int inet_sk_rebuild_header(struct sock *sk) return err; } - EXPORT_SYMBOL(inet_sk_rebuild_header); static int inet_gso_send_check(struct sk_buff *skb) @@ -1369,7 +1384,6 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family, } return rc; } - EXPORT_SYMBOL_GPL(inet_ctl_sock_create); unsigned long snmp_fold_field(void *mib[], int offt) @@ -1676,19 +1690,3 @@ static int __init ipv4_proc_init(void) MODULE_ALIAS_NETPROTO(PF_INET); -EXPORT_SYMBOL(inet_accept); -EXPORT_SYMBOL(inet_bind); -EXPORT_SYMBOL(inet_dgram_connect); -EXPORT_SYMBOL(inet_dgram_ops); -EXPORT_SYMBOL(inet_getname); -EXPORT_SYMBOL(inet_ioctl); -EXPORT_SYMBOL(inet_listen); -EXPORT_SYMBOL(inet_register_protosw); -EXPORT_SYMBOL(inet_release); -EXPORT_SYMBOL(inet_sendmsg); -EXPORT_SYMBOL(inet_shutdown); -EXPORT_SYMBOL(inet_sock_destruct); -EXPORT_SYMBOL(inet_stream_connect); -EXPORT_SYMBOL(inet_stream_ops); -EXPORT_SYMBOL(inet_unregister_protosw); -EXPORT_SYMBOL(sysctl_ip_nonlocal_bind); -- cgit v0.10.2 From ec0248ea35f6e1fc7426f377a7df071d997bdedd Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 26 Aug 2009 09:49:22 +0000 Subject: cnic: Put rx/tx ring allocation in separate function. This will allow the 10G iSCSI code to reuse the function. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 4869d77..039900c 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -742,6 +742,26 @@ static int cnic_alloc_context(struct cnic_dev *dev) return 0; } +static int cnic_alloc_l2_rings(struct cnic_dev *dev, int pages) +{ + struct cnic_local *cp = dev->cnic_priv; + + cp->l2_ring_size = pages * BCM_PAGE_SIZE; + cp->l2_ring = pci_alloc_consistent(dev->pcidev, cp->l2_ring_size, + &cp->l2_ring_map); + if (!cp->l2_ring) + return -ENOMEM; + + cp->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size; + cp->l2_buf_size = PAGE_ALIGN(cp->l2_buf_size); + cp->l2_buf = pci_alloc_consistent(dev->pcidev, cp->l2_buf_size, + &cp->l2_buf_map); + if (!cp->l2_buf) + return -ENOMEM; + + return 0; +} + static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; @@ -762,17 +782,8 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) if (ret) goto error; - cp->l2_ring_size = 2 * BCM_PAGE_SIZE; - cp->l2_ring = pci_alloc_consistent(dev->pcidev, cp->l2_ring_size, - &cp->l2_ring_map); - if (!cp->l2_ring) - goto error; - - cp->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size; - cp->l2_buf_size = PAGE_ALIGN(cp->l2_buf_size); - cp->l2_buf = pci_alloc_consistent(dev->pcidev, cp->l2_buf_size, - &cp->l2_buf_map); - if (!cp->l2_buf) + ret = cnic_alloc_l2_rings(dev, 2); + if (ret) goto error; uinfo = kzalloc(sizeof(*uinfo), GFP_ATOMIC); -- cgit v0.10.2 From 5e9b2dbfcbc9b180a0064d8a473a4652ee99c9ad Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 26 Aug 2009 09:49:23 +0000 Subject: cnic: Put uio init in separate function. This will allow the 10G iSCSI code to reuse the function. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 039900c..f8a0923 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -762,33 +762,14 @@ static int cnic_alloc_l2_rings(struct cnic_dev *dev, int pages) return 0; } -static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) -{ +static int cnic_alloc_uio(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; struct uio_info *uinfo; int ret; - ret = cnic_alloc_dma(dev, &cp->kwq_info, KWQ_PAGE_CNT, 1); - if (ret) - goto error; - cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr; - - ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 1); - if (ret) - goto error; - cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr; - - ret = cnic_alloc_context(dev); - if (ret) - goto error; - - ret = cnic_alloc_l2_rings(dev, 2); - if (ret) - goto error; - uinfo = kzalloc(sizeof(*uinfo), GFP_ATOMIC); if (!uinfo) - goto error; + return -ENOMEM; uinfo->mem[0].addr = dev->netdev->base_addr; uinfo->mem[0].internal_addr = dev->regview; @@ -796,10 +777,15 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) uinfo->mem[0].memtype = UIO_MEM_PHYS; uinfo->mem[1].addr = (unsigned long) cp->status_blk & PAGE_MASK; - if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) - uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9; - else - uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE; + if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) { + if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) + uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9; + else + uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE; + + uinfo->name = "bnx2_cnic"; + } + uinfo->mem[1].memtype = UIO_MEM_LOGICAL; uinfo->mem[2].addr = (unsigned long) cp->l2_ring; @@ -810,7 +796,6 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) uinfo->mem[3].size = cp->l2_buf_size; uinfo->mem[3].memtype = UIO_MEM_LOGICAL; - uinfo->name = "bnx2_cnic"; uinfo->version = CNIC_MODULE_VERSION; uinfo->irq = UIO_IRQ_CUSTOM; @@ -822,10 +807,39 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) ret = uio_register_device(&dev->pcidev->dev, uinfo); if (ret) { kfree(uinfo); - goto error; + return ret; } cp->cnic_uinfo = uinfo; + return 0; +} + +static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + int ret; + + ret = cnic_alloc_dma(dev, &cp->kwq_info, KWQ_PAGE_CNT, 1); + if (ret) + goto error; + cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr; + + ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 1); + if (ret) + goto error; + cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr; + + ret = cnic_alloc_context(dev); + if (ret) + goto error; + + ret = cnic_alloc_l2_rings(dev, 2); + if (ret) + goto error; + + ret = cnic_alloc_uio(dev); + if (ret) + goto error; return 0; -- cgit v0.10.2 From df19a6267705456f463871ae2aabc44299909d2a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Aug 2009 23:48:54 -0700 Subject: tcp: keepalive cleanups Introduce keepalive_probes(tp) helper, and use it, like keepalive_time_when(tp) and keepalive_intvl_when(tp) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/net/tcp.h b/include/net/tcp.h index 88af843..cbb2a48 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1007,6 +1007,11 @@ static inline int keepalive_time_when(const struct tcp_sock *tp) return tp->keepalive_time ? : sysctl_tcp_keepalive_time; } +static inline int keepalive_probes(const struct tcp_sock *tp) +{ + return tp->keepalive_probes ? : sysctl_tcp_keepalive_probes; +} + static inline int tcp_fin_time(const struct sock *sk) { int fin_timeout = tcp_sk(sk)->linger2 ? : sysctl_tcp_fin_timeout; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9114524..59f69a6 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2336,13 +2336,13 @@ static int do_tcp_getsockopt(struct sock *sk, int level, val = !!(tp->nonagle&TCP_NAGLE_CORK); break; case TCP_KEEPIDLE: - val = (tp->keepalive_time ? : sysctl_tcp_keepalive_time) / HZ; + val = keepalive_time_when(tp) / HZ; break; case TCP_KEEPINTVL: - val = (tp->keepalive_intvl ? : sysctl_tcp_keepalive_intvl) / HZ; + val = keepalive_intvl_when(tp) / HZ; break; case TCP_KEEPCNT: - val = tp->keepalive_probes ? : sysctl_tcp_keepalive_probes; + val = keepalive_probes(tp); break; case TCP_SYNCNT: val = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index b144a26..c520fb6 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -499,8 +499,7 @@ static void tcp_keepalive_timer (unsigned long data) elapsed = tcp_time_stamp - tp->rcv_tstamp; if (elapsed >= keepalive_time_when(tp)) { - if ((!tp->keepalive_probes && icsk->icsk_probes_out >= sysctl_tcp_keepalive_probes) || - (tp->keepalive_probes && icsk->icsk_probes_out >= tp->keepalive_probes)) { + if (icsk->icsk_probes_out >= keepalive_probes(tp)) { tcp_send_active_reset(sk, GFP_ATOMIC); tcp_write_err(sk); goto out; -- cgit v0.10.2 From 30038fc61adfdab162b1966e34261f06eda67f02 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Aug 2009 23:52:01 -0700 Subject: net: ip_rt_send_redirect() optimization While doing some forwarding benchmarks, I noticed ip_rt_send_redirect() is rather expensive, even if send_redirects is false for the device. Fix is to avoid two atomic ops, we dont really need to take a reference on in_dev Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/route.c b/net/ipv4/route.c index fafbe16..91867d3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1514,13 +1514,17 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) void ip_rt_send_redirect(struct sk_buff *skb) { struct rtable *rt = skb_rtable(skb); - struct in_device *in_dev = in_dev_get(rt->u.dst.dev); + struct in_device *in_dev; + int log_martians; - if (!in_dev) + rcu_read_lock(); + in_dev = __in_dev_get_rcu(rt->u.dst.dev); + if (!in_dev || !IN_DEV_TX_REDIRECTS(in_dev)) { + rcu_read_unlock(); return; - - if (!IN_DEV_TX_REDIRECTS(in_dev)) - goto out; + } + log_martians = IN_DEV_LOG_MARTIANS(in_dev); + rcu_read_unlock(); /* No redirected packets during ip_rt_redirect_silence; * reset the algorithm. @@ -1533,7 +1537,7 @@ void ip_rt_send_redirect(struct sk_buff *skb) */ if (rt->u.dst.rate_tokens >= ip_rt_redirect_number) { rt->u.dst.rate_last = jiffies; - goto out; + return; } /* Check for load limit; set rate_last to the latest sent @@ -1547,7 +1551,7 @@ void ip_rt_send_redirect(struct sk_buff *skb) rt->u.dst.rate_last = jiffies; ++rt->u.dst.rate_tokens; #ifdef CONFIG_IP_ROUTE_VERBOSE - if (IN_DEV_LOG_MARTIANS(in_dev) && + if (log_martians && rt->u.dst.rate_tokens == ip_rt_redirect_number && net_ratelimit()) printk(KERN_WARNING "host %pI4/if%d ignores redirects for %pI4 to %pI4.\n", @@ -1555,8 +1559,6 @@ void ip_rt_send_redirect(struct sk_buff *skb) &rt->rt_dst, &rt->rt_gateway); #endif } -out: - in_dev_put(in_dev); } static int ip_error(struct sk_buff *skb) -- cgit v0.10.2 From 8945a808f7d5efd21fa9fb6055d2dd7887bdd9d8 Mon Sep 17 00:00:00 2001 From: Sascha Hlusiak Date: Fri, 28 Aug 2009 23:53:53 -0700 Subject: sit: allow ip fragmentation when using nopmtudisc to fix package loss if tunnel parameters have frag_off set to IP_DF, pmtudisc on the ipv4 link will be performed by deriving the mtu from the ipv4 link and setting the DF-Flag of the encapsulating IPv4 Header. If fragmentation is needed on the way, the IPv4 pmtu gets adjusted, the ipv6 package will be resent eventually, using the new and lower mtu and everyone is happy. If the frag_off parameter is unset, the mtu for the tunnel will be derived from the tunnel device or the ipv6 pmtu, which might be higher than the ipv4 pmtu. In that case we must allow the fragmentation of the IPv4 packet because the IPv6 mtu wouldn't 'learn' from the adjusted IPv4 pmtu, resulting in frequent icmp_frag_needed and package loss on the IPv6 layer. This patch allows fragmentation when tunnel was created with parameter nopmtudisc, like in ipip/gre tunnels. Signed-off-by: Sascha Hlusiak Signed-off-by: David S. Miller diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d335a30..1d25a4d 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -778,7 +778,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) iph->version = 4; iph->ihl = sizeof(struct iphdr)>>2; if (mtu > IPV6_MIN_MTU) - iph->frag_off = htons(IP_DF); + iph->frag_off = tiph->frag_off; else iph->frag_off = 0; -- cgit v0.10.2 From 80b71b80df14d885f7e50e115c1348398f418759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20L=C3=A5=C3=A5s?= Date: Fri, 28 Aug 2009 23:57:15 -0700 Subject: fib_trie: resize rework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here is rework and cleanup of the resize function. Some bugs we had. We were using ->parent when we should use node_parent(). Also we used ->parent which is not assigned by inflate in inflate loop. Also a fix to set thresholds to power 2 to fit halve and double strategy. max_resize is renamed to max_work which better indicates it's function. Reaching max_work is not an error, so warning is removed. max_work only limits amount of work done per resize. (limits CPU-usage, outstanding memory etc). The clean-up makes it relatively easy to add fixed sized root-nodes if we would like to decrease the memory pressure on routers with large routing tables and dynamic routing. If we'll need that... Its been tested with 280k routes. Work done together with Robert Olsson. Signed-off-by: Jens Låås Signed-off-by: Robert Olsson Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index fe3c846..291bdf5 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -48,7 +48,7 @@ * Patrick McHardy */ -#define VERSION "0.408" +#define VERSION "0.409" #include #include @@ -325,10 +325,7 @@ static inline void check_tnode(const struct tnode *tn) static const int halve_threshold = 25; static const int inflate_threshold = 50; static const int halve_threshold_root = 15; -static const int inflate_threshold_root = 25; - -static int inflate_threshold_root_fix; -#define INFLATE_FIX_MAX 10 /* a comment in resize() */ +static const int inflate_threshold_root = 30; static void __alias_free_mem(struct rcu_head *head) { @@ -516,14 +513,14 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, rcu_assign_pointer(tn->child[i], n); } +#define MAX_WORK 10 static struct node *resize(struct trie *t, struct tnode *tn) { int i; - int err = 0; struct tnode *old_tn; int inflate_threshold_use; int halve_threshold_use; - int max_resize; + int max_work; if (!tn) return NULL; @@ -538,18 +535,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) } /* One child */ if (tn->empty_children == tnode_child_length(tn) - 1) - for (i = 0; i < tnode_child_length(tn); i++) { - struct node *n; - - n = tn->child[i]; - if (!n) - continue; - - /* compress one level */ - node_set_parent(n, NULL); - tnode_free_safe(tn); - return n; - } + goto one_child; /* * Double as long as the resulting node has a number of * nonempty nodes that are above the threshold. @@ -618,15 +604,17 @@ static struct node *resize(struct trie *t, struct tnode *tn) /* Keep root node larger */ - if (!tn->parent) - inflate_threshold_use = inflate_threshold_root + - inflate_threshold_root_fix; - else + if (!node_parent((struct node*) tn)) { + inflate_threshold_use = inflate_threshold_root; + halve_threshold_use = halve_threshold_root; + } + else { inflate_threshold_use = inflate_threshold; + halve_threshold_use = halve_threshold; + } - err = 0; - max_resize = 10; - while ((tn->full_children > 0 && max_resize-- && + max_work = MAX_WORK; + while ((tn->full_children > 0 && max_work-- && 50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >= inflate_threshold_use * tnode_child_length(tn))) { @@ -643,47 +631,19 @@ static struct node *resize(struct trie *t, struct tnode *tn) } } - if (max_resize < 0) { - if (!tn->parent) { - /* - * It was observed that during large updates even - * inflate_threshold_root = 35 might be needed to avoid - * this warning; but it should be temporary, so let's - * try to handle this automatically. - */ - if (inflate_threshold_root_fix < INFLATE_FIX_MAX) - inflate_threshold_root_fix++; - else - pr_warning("Fix inflate_threshold_root." - " Now=%d size=%d bits fix=%d\n", - inflate_threshold_root, tn->bits, - inflate_threshold_root_fix); - } else { - pr_warning("Fix inflate_threshold." - " Now=%d size=%d bits\n", - inflate_threshold, tn->bits); - } - } else if (max_resize > 3 && !tn->parent && inflate_threshold_root_fix) - inflate_threshold_root_fix--; - check_tnode(tn); + /* Return if at least one inflate is run */ + if( max_work != MAX_WORK) + return (struct node *) tn; + /* * Halve as long as the number of empty children in this * node is above threshold. */ - - /* Keep root node larger */ - - if (!tn->parent) - halve_threshold_use = halve_threshold_root; - else - halve_threshold_use = halve_threshold; - - err = 0; - max_resize = 10; - while (tn->bits > 1 && max_resize-- && + max_work = MAX_WORK; + while (tn->bits > 1 && max_work-- && 100 * (tnode_child_length(tn) - tn->empty_children) < halve_threshold_use * tnode_child_length(tn)) { @@ -698,19 +658,10 @@ static struct node *resize(struct trie *t, struct tnode *tn) } } - if (max_resize < 0) { - if (!tn->parent) - pr_warning("Fix halve_threshold_root." - " Now=%d size=%d bits\n", - halve_threshold_root, tn->bits); - else - pr_warning("Fix halve_threshold." - " Now=%d size=%d bits\n", - halve_threshold, tn->bits); - } /* Only one child remains */ - if (tn->empty_children == tnode_child_length(tn) - 1) + if (tn->empty_children == tnode_child_length(tn) - 1) { +one_child: for (i = 0; i < tnode_child_length(tn); i++) { struct node *n; @@ -724,7 +675,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) tnode_free_safe(tn); return n; } - + } return (struct node *) tn; } -- cgit v0.10.2 From 80a1096bac73ce6e98dbbce10cc00a154460bcbd Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 29 Aug 2009 00:00:35 -0700 Subject: tcp: fix premature termination of FIN_WAIT2 time-wait sockets There is a race condition in the time-wait sockets code that can lead to premature termination of FIN_WAIT2 and, subsequently, to RST generation when the FIN,ACK from the peer finally arrives: Time TCP header 0.000000 30755 > http [SYN] Seq=0 Win=2920 Len=0 MSS=1460 TSV=282912 TSER=0 0.000008 http > 30755 aSYN, ACK] Seq=0 Ack=1 Win=2896 Len=0 MSS=1460 TSV=... 0.136899 HEAD /1b.html?n1Lg=v1 HTTP/1.0 [Packet size limited during capture] 0.136934 HTTP/1.0 200 OK [Packet size limited during capture] 0.136945 http > 30755 [FIN, ACK] Seq=187 Ack=207 Win=2690 Len=0 TSV=270521... 0.136974 30755 > http [ACK] Seq=207 Ack=187 Win=2734 Len=0 TSV=283049 TSER=... 0.177983 30755 > http [ACK] Seq=207 Ack=188 Win=2733 Len=0 TSV=283089 TSER=... 0.238618 30755 > http [FIN, ACK] Seq=207 Ack=188 Win=2733 Len=0 TSV=283151... 0.238625 http > 30755 [RST] Seq=188 Win=0 Len=0 Say twdr->slot = 1 and we are running inet_twdr_hangman and in this instance inet_twdr_do_twkill_work returns 1. At that point we will mark slot 1 and schedule inet_twdr_twkill_work. We will also make twdr->slot = 2. Next, a connection is closed and tcp_time_wait(TCP_FIN_WAIT2, timeo) is called which will create a new FIN_WAIT2 time-wait socket and will place it in the last to be reached slot, i.e. twdr->slot = 1. At this point say inet_twdr_twkill_work will run which will start destroying the time-wait sockets in slot 1, including the just added TCP_FIN_WAIT2 one. To avoid this issue we increment the slot only if all entries in the slot have been purged. This change may delay the slots cleanup by a time-wait death row period but only if the worker thread didn't had the time to run/purge the current slot in the next period (6 seconds with default sysctl settings). However, on such a busy system even without this change we would probably see delays... Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 61283f9..13f0781 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -218,8 +218,8 @@ void inet_twdr_hangman(unsigned long data) /* We purged the entire slot, anything left? */ if (twdr->tw_count) need_timer = 1; + twdr->slot = ((twdr->slot + 1) & (INET_TWDR_TWKILL_SLOTS - 1)); } - twdr->slot = ((twdr->slot + 1) & (INET_TWDR_TWKILL_SLOTS - 1)); if (need_timer) mod_timer(&twdr->tw_timer, jiffies + twdr->period); out: -- cgit v0.10.2 From 078b0735881c7969aaf21469f3577831cddd9f8c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 29 Aug 2009 00:02:46 -0700 Subject: bnx2: Update firmware to 5.0.0.j3. - Better small packet receive performance. - Better handling of Flow control on 5709. - Fixed iSCSI TMP ABORT TASK problem. - Added iSCSI TCP timestamp option. Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4450177..c4e85f6 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -61,10 +61,11 @@ #define PFX DRV_MODULE_NAME ": " #define DRV_MODULE_VERSION "2.0.2" #define DRV_MODULE_RELDATE "Aug 21, 2009" -#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-4.6.16.fw" -#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-4.6.16.fw" -#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-4.6.17.fw" -#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-4.6.15.fw" +#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-5.0.0.j3.fw" +#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-5.0.0.j3.fw" +#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-5.0.0.j3.fw" +#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-5.0.0.j3.fw" +#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-5.0.0.j3.fw" #define RUN_AT(x) (jiffies + (x)) @@ -82,6 +83,7 @@ MODULE_FIRMWARE(FW_MIPS_FILE_06); MODULE_FIRMWARE(FW_RV2P_FILE_06); MODULE_FIRMWARE(FW_MIPS_FILE_09); MODULE_FIRMWARE(FW_RV2P_FILE_09); +MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax); static int disable_msi = 0; @@ -3621,7 +3623,11 @@ bnx2_request_firmware(struct bnx2 *bp) if (CHIP_NUM(bp) == CHIP_NUM_5709) { mips_fw_file = FW_MIPS_FILE_09; - rv2p_fw_file = FW_RV2P_FILE_09; + if ((CHIP_ID(bp) == CHIP_ID_5709_A0) || + (CHIP_ID(bp) == CHIP_ID_5709_A1)) + rv2p_fw_file = FW_RV2P_FILE_09_Ax; + else + rv2p_fw_file = FW_RV2P_FILE_09; } else { mips_fw_file = FW_MIPS_FILE_06; rv2p_fw_file = FW_RV2P_FILE_06; diff --git a/firmware/Makefile b/firmware/Makefile index 317212c..878329c 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -33,10 +33,11 @@ fw-shipped-$(CONFIG_ADAPTEC_STARFIRE) += adaptec/starfire_rx.bin \ fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw fw-shipped-$(CONFIG_BNX2X) += bnx2x-e1-5.0.21.0.fw bnx2x-e1h-5.0.21.0.fw -fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-4.6.17.fw \ - bnx2/bnx2-rv2p-09-4.6.15.fw \ - bnx2/bnx2-mips-06-4.6.16.fw \ - bnx2/bnx2-rv2p-06-4.6.16.fw +fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-5.0.0.j3.fw \ + bnx2/bnx2-rv2p-09-5.0.0.j3.fw \ + bnx2/bnx2-rv2p-09ax-5.0.0.j3.fw \ + bnx2/bnx2-mips-06-5.0.0.j3.fw \ + bnx2/bnx2-rv2p-06-5.0.0.j3.fw fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \ diff --git a/firmware/bnx2/bnx2-mips-06-4.6.16.fw.ihex b/firmware/bnx2/bnx2-mips-06-4.6.16.fw.ihex deleted file mode 100644 index 0df10b5..0000000 --- a/firmware/bnx2/bnx2-mips-06-4.6.16.fw.ihex +++ /dev/null @@ -1,5805 +0,0 @@ -:10000000080000F80800000000004DA4000000C82F -:1000100000000000000000000000000008004DA4E7 -:100020000000001400004E6C080000800800000072 -:10003000000056CC00004E800800582000000084CC -:100040000000A54C080056CC000001340000A5D0EB -:10005000080031D808000000000070DC0000A70490 -:10006000000000000000000000000000080070DC3C -:1000700000000024000117E00800048808000400C4 -:100080000000175C000118040000000000000000E0 -:100090000000000000000000000000000000000060 -:1000A000080000980800000000003A7400012F606A -:1000B0000000000000000000000000000000000040 -:0800C000000000000000000038 -:0800C8000A00003E00000000E8 -:1000D000000000000000000D636F6D342E362E31DD -:1000E00036000000040610020000000000000003BB -:1000F00000000014000000320000000300000000B7 -:1001000000000000000000000000000000000000EF -:1001100000000010000001360000EA60000000014D -:1001200000000000000000000000000000000008C7 -:1001300000000000000000000000000000000000BF -:1001400000000000000000000000000000000000AF -:10015000000000000000000000000000000000009F -:10016000000000020000000000000000000000008D -:10017000000000000000000000000000000000007F -:10018000000000000000000000000010000000005F -:10019000000000000000000000000000000000005F -:1001A000000000000000000000000000000000004F -:1001B000000000000000000000000000000000003F -:1001C0000000000010000003000000000000000D0F -:1001D0000000000D3C02080024424DE03C030800F2 -:1001E00024634ED4AC4000000043202B1480FFFD5C -:1001F000244200043C1D080037BD7FFC03A0F02111 -:100200003C100800261000F83C1C0800279C4DE01C -:100210000E0002AA000000000000000D3C03601068 -:100220008C6450002402FF7F3C1A8000008220244E -:100230003484380C24020037AC645000AF4200080C -:1002400024020C80AF4200243C1B80083C060800BE -:1002500024C6079C3C02080024424E182404001BBC -:100260002484FFFFAC4600000481FFFD244200040B -:100270003C020800244203803C010800AC224E20CE -:100280003C020800244206803C010800AC224E24B7 -:100290003C02080024420D803C010800AC224E6064 -:1002A0003C02080024420A103C03080024630908A9 -:1002B0003C040800248409443C05080024A53C248F -:1002C0003C010800AC224E683C0208002442057044 -:1002D0003C010800AC264E643C010800AC254E747D -:1002E0003C010800AC234E7C3C010800AC224E804F -:1002F0003C010800AC244E843C010800AC234E1C99 -:100300003C010800AC204E283C010800AC204E2CDB -:100310003C010800AC204E303C010800AC204E34BB -:100320003C010800AC204E383C010800AC204E3C9B -:100330003C010800AC204E403C010800AC244E4477 -:100340003C010800AC204E483C010800AC204E4C5B -:100350003C010800AC204E503C010800AC204E543B -:100360003C010800AC204E583C010800AC264E5C15 -:100370003C010800AC204E6C3C010800AC254E70DE -:100380003C010800AC234E780A0006F4000000008F -:100390003C0308008C6300208F8200081043000398 -:1003A000000000000A00052CAF83000803E00008ED -:1003B0000000000027BDFFE8AFB00010AFBF001481 -:1003C00027500100920200091040001A2403000186 -:1003D0003C0208008C42002010400016000018214A -:1003E0000E00056400000000960300083C060800AB -:1003F00094C64E968E0400188F8200209605000C3D -:1004000000031C0000661825AC440000AC45000445 -:1004100024040001AC400008AC40000CAC400010CB -:10042000AC400014AC4000180E000589AC43001C21 -:10043000000018218FBF00148FB000100060102141 -:1004400003E0000827BD001827BDFFE8AFBF00107C -:100450009742010830437000240220001062000A15 -:1004600028642001548000128FBF00102402400035 -:1004700010620008240260001062000A8FBF0010A2 -:100480000A0000FB000010218FBF00100A0000BB13 -:1004900027BD00180E0003F6000000000A0000FA55 -:1004A0008FBF00100E000FB6000000008FBF0010BD -:1004B0000000102103E0000827BD00183C020800DE -:1004C0008C42002027BDFFE810400027AFBF00107E -:1004D0000E00056400000000974201089743010CDC -:1004E0008F8500203042003E3063FFFF0002140081 -:1004F00000431025ACA200008F4201003C0608001A -:1005000094C64E968FBF0010ACA20004974301160C -:100510009744010E3C02200000031C003084FFFFC2 -:1005200000641825ACA3000800C2302597420110D2 -:100530009743011224040001000214003063FFFFFE -:1005400000431025ACA2000C9742011427BD0018EF -:100550003042FFFFACA20010ACA00014ACA0001809 -:100560000A000589ACA6001C8FBF001003E000083C -:1005700027BD00183C0208008C42002027BDFFE880 -:100580001040002AAFBF00100E00056400000000FC -:10059000974201089743010C8F8500203042003EAE -:1005A0003063FFFF0002140000431025ACA20000DE -:1005B0008F4201003C06080094C64E968FBF001083 -:1005C000ACA20004974301169744010E3C022000A0 -:1005D00000031C003084FFFF00641825ACA3000852 -:1005E00000C23025974201109743011224040001F4 -:1005F000000214003063FFFF00431025ACA2000C82 -:100600009742011427BD00183042FFFFACA2001032 -:100610008F420118ACA200149342010B304200FF3C -:10062000ACA200180A000589ACA6001C8FBF001000 -:1006300003E0000827BD001827BDFFE0AFB00010A1 -:10064000AFBF0018AFB10014275001009203000B98 -:100650002402001A961100081462003500002021BF -:100660003222000110400009000000008E0200004C -:1006700096030014000211C200021040005A10211B -:10068000A44300800A000179322200020E00012BEF -:10069000000000003C0208008C420040244200019F -:1006A0003C010800AC220040322200020002202B54 -:1006B0003C0208008C420044322300042442000122 -:1006C0003C010800AC2200441060001A8FBF0018E3 -:1006D0008F4202B804410008240400013C020800D3 -:1006E0008C420060244200013C010800AC22006002 -:1006F0000A00019C8FB100148E02002096030016A0 -:1007000000002021AF4202808E020004A743028431 -:10071000AF4202883C021000AF4202B83C0208001F -:100720008C42005C244200013C010800AC22005CC9 -:100730008FBF00188FB100148FB0001000801021FF -:1007400003E0000827BD002027BDFFE0AFB0001088 -:10075000AFBF0018AFB10014275001009203000B87 -:1007600024020003961100081462003500002021C5 -:100770003222000110400009000000008E0200003B -:1007800096030014000211C200021040005A10210A -:10079000A44300800A0001BD322200020E0000FDC9 -:1007A000000000003C0208008C420040244200018E -:1007B0003C010800AC220040322200020002202B43 -:1007C0003C0208008C420044322300042442000111 -:1007D0003C010800AC2200441060001A8FBF0018D2 -:1007E0008F4202B804410008240400013C020800C2 -:1007F0008C420060244200013C010800AC220060F1 -:100800000A0001E08FB100148E020020960300164A -:1008100000002021AF4202808E020004A743028420 -:10082000AF4202883C021000AF4202B83C0208000E -:100830008C42005C244200013C010800AC22005CB8 -:100840008FBF00188FB100148FB0001000801021EE -:1008500003E0000827BD00209362000003E00008C9 -:10086000AF80000403E000080000102127BDFFE86E -:10087000AFBF0014AFB000108F420100AF420020A4 -:100880008F420104AF4200A89350010B0E0001E417 -:10089000321000FF3C02080024424E18001018805D -:1008A0002E10001C16000004006210210E0001E74B -:1008B0000A0001FF000000008C4200000040F8091F -:1008C00000000000104000053C0240008F4301047E -:1008D0003C026020AC4300143C024000AF420138AF -:1008E0003C0208008C4200348FBF00148FB000100F -:1008F000244200013C010800AC22003403E000085F -:1009000027BD001827BDFFE8AFBF00108F42014090 -:100910000E0001E4AF4200200E0003800000000042 -:100920003C024000AF4201783C03080024630038D9 -:100930008C6200008FBF001027BD00182442000108 -:1009400003E00008AC62000027BDFFE8AFBF001065 -:100950008F4201800E0001E4AF4200208F430180EE -:1009600024020F0014620005000000008F4201887D -:10097000A742009C0A0002393C024000936200003A -:1009800024030050304200FF144300083C024000A2 -:100990000E00036400000000144000043C0240000C -:1009A0000E000E42000000003C024000AF4201B8C1 -:1009B0003C0208008C42003C8FBF00102442000122 -:1009C0003C010800AC22003C03E0000827BD0018F1 -:1009D00003E00008000010218F4301048F82001003 -:1009E00010430008000000003C0208008C42008414 -:1009F000244200013C010800AC2200848F42010423 -:100A0000AF82001003E000080000000027BDFFE8EF -:100A1000AFBF001027440100948200083043000259 -:100A2000304200041040001B000000008F4202B85A -:100A300004410008240500013C0208008C420060CB -:100A4000244200013C010800AC2200600A0002813F -:100A50008FBF00108C820020948300160000282194 -:100A6000AF4202808C820004A7430284AF42028816 -:100A70003C021000AF4202B83C0208008C42005C0D -:100A8000244200013C010800AC22005C0A00028103 -:100A90008FBF001010600008240500013C02080010 -:100AA0008C420084244200013C010800AC220084F6 -:100AB0000A0002818FBF00108F4401000E00024423 -:100AC00000000000000028218FBF001000A01021AE -:100AD00003E0000827BD00183C0208008C42008893 -:100AE000274301009465000C244200013C010800EA -:100AF000AC2200888C64001803451021904540000A -:100B0000AF4400388C62001C2403FFF800052E005F -:100B10000043102434420004AF42003C3C02000574 -:100B2000AF420030000000000000000000000000A4 -:100B3000AF450404000000000000000000000000B9 -:100B40003C02000634420001AF42003000000000C9 -:100B500000000000000000008F4200003042001042 -:100B60001040FFFD0000102103E00008000000001D -:100B700027BDFFE0AFBF0018AFB100140E00005555 -:100B8000AFB000103C028000344200708C42000084 -:100B9000AF8200140E0000B2000000003C02800092 -:100BA000344600703C0308008C6300A03C0208003F -:100BB0008C4200A4104300048F8400143C01080000 -:100BC000AC2300A4A743009E8CCA00003C0308008D -:100BD0008C6300BC3C0208008C4200B80144202316 -:100BE00000641821000040210064202B00481021DF -:100BF000004410213C010800AC2300BC3C0108006B -:100C0000AC2200B88F510000322200071040FFE1F3 -:100C1000AF8A00148CC600003C0508008CA500BCFF -:100C20003C0408008C8400B800CA302300A62821A8 -:100C30000000102100A6302B0082202100862021F8 -:100C4000322700013C010800AC2500BC3C01080033 -:100C5000AC2400B810E00021322200028F420100D3 -:100C6000AF4200208F420104AF4200A89342010B23 -:100C70000E0001E4305000FF2E02001C544000041E -:100C8000001010800E0001E70A0002F800000000CA -:100C90003C03080024634E18004310218C420000DE -:100CA0000040F80900000000104000053C02400030 -:100CB0008F4301043C026020AC4300143C0240001E -:100CC000AF4201383C0208008C420034244200014B -:100CD0003C010800AC220034322200021040000E19 -:100CE000322200048F4201400E0001E4AF42002096 -:100CF0000E000380000000003C024000AF4201787B -:100D00003C0208008C420038244200013C010800EB -:100D1000AC220038322200041040FF9B3C028000CD -:100D20008F4201800E0001E4AF4200208F4301801A -:100D300024020F0014620005000000008F420188A9 -:100D4000A742009C0A00032D3C0240009362000071 -:100D500024030050304200FF144300083C024000CE -:100D60000E00036400000000544000043C024000F8 -:100D70000E000E42000000003C024000AF4201B8ED -:100D80003C0208008C42003C244200013C01080067 -:100D9000AC22003C0A0002B03C0280003C02900001 -:100DA0003442000100822025AF4400208F42002001 -:100DB0000440FFFE0000000003E000080000000007 -:100DC0003C028000344200010082202503E000083C -:100DD000AF44002027BDFFE0AFB10014AFB000105A -:100DE00000808821AFBF00180E00033530B000FF2F -:100DF0009362007D0220202102028025A370007DE5 -:100E00008F7000743C0280000E00033E02028024BA -:100E1000160000098FBF00188F4201F80440FFFE42 -:100E200024020002AF5101C0A34201C43C021000E1 -:100E3000AF4201F88FBF00188FB100148FB00010BF -:100E400003E0000827BD002027BDFFD000001021CF -:100E500003E0000827BD003027BDFFE8AFBF00104A -:100E6000974201843042020010400005000020211A -:100E70000E001079000000000A000378240400012D -:100E80008F420188044000098FBF00108F42018803 -:100E90003C03FF00004310243C0304001443000300 -:100EA000240400019362003E8FBF001000801021D7 -:100EB00003E0000827BD0018A36000228F44014012 -:100EC0000A0003432405000127BDFFE8AFBF00145B -:100ED000AFB000109362000024030020304200FFF6 -:100EE0001043000B00000000936200002403003058 -:100EF000304200FF10430006000000009362000033 -:100F000024030050304200FF144300628FBF0014DE -:100F100093420148304200FF2443FFFF2C6200054A -:100F20001040005C8FBF0014000310803C030800D9 -:100F300024634DA4004310218C42000000400008AF -:100F4000000000000E0003358F4401408F70000C3C -:100F50008F4201441602000224020001AF62000C1D -:100F60000E00033E8F4401408F42014414500004A0 -:100F70008FBF00148FB000100A000FED27BD0018BE -:100F80008F62000C0A0003EC000000009762001062 -:100F90008F4301443042FFFF14620009000000004B -:100FA00024020001A76200108F420140AF420200FC -:100FB0003C021000AF4202380A0003F38FBF001456 -:100FC000976200100A0003EC000000000E000335D9 -:100FD0008F440140976200128F4301443050FFFF5D -:100FE0001603000224020001A76200120E00033E55 -:100FF0008F4401408F420144160200048FBF001449 -:101000008FB000100A00037C27BD00189762001201 -:101010000A0003EC00000000976200148F430144B3 -:101020003042FFFF146200068FBF0014240200014B -:101030008FB00010A76200140A00131927BD001812 -:10104000976200140A0003EC00000000976200168B -:101050008F4301443042FFFF146200062402000166 -:101060008FBF00148FB00010A76200160A000BE0BB -:1010700027BD001897620016144000068FBF0014A9 -:101080003C0208008C420070244200013C01080030 -:10109000AC2200708FB0001003E0000827BD0018DC -:1010A00027BDFFE8AFBF0014AFB0001093430109A4 -:1010B0002402001F8F500100106200A5286200204A -:1010C00010400018240200382862000A1040000C6A -:1010D0002402000B286200081040002C00000000D1 -:1010E000046000E728620002144000282402000681 -:1010F000106200268FBF00140A0004F08FB00010A9 -:101100001062005E2862000B144000DE8FBF0014E6 -:101110002402000E106200738FB000100A0004F069 -:1011200000000000106200C2286200391040000A6E -:101130002402008024020036106200CC28620037AE -:10114000104000B624020035106200C38FBF0014A7 -:101150000A0004F08FB000101062002B286200819A -:1011600010400006240200C824020039106200B6B4 -:101170008FBF00140A0004F08FB0001010620099B5 -:101180008FBF00140A0004F08FB000103C0208006A -:101190008C420020104000BB8FBF00140E0005647D -:1011A000000000008F4201008F8300209745010C52 -:1011B00097460108AC6200008F4201043C0408001D -:1011C00094844E9600052C00AC6200048F420118F6 -:1011D0000006340000C43025AC6200088F42011CB8 -:1011E00024040001AC62000C9342010A00A22825ED -:1011F000AC650010AC600014AC600018AC66001C5C -:101200000A0004C48FBF00143C0208008C42002076 -:101210001040009C8FBF00140E0005640000000009 -:10122000974401083C03080094634E969745010CCF -:10123000000422029746010E8F820020000426003F -:101240000083202500052C003C03008000A62825F3 -:1012500000832025AC400000AC400004AC400008F6 -:10126000AC40000CAC450010AC400014AC40001881 -:10127000AC44001C0A0004C3240400019742010C82 -:101280001440001500000000936200053042001079 -:1012900014400011000000000E0003350200202160 -:1012A0009362000502002021344200100E00033E2C -:1012B000A36200059362000024030020304200FF77 -:1012C0001043006F020020218FBF00148FB0001068 -:1012D0000A00108F27BD00180000000D0A0004EF5F -:1012E0008FBF00143C0208008C42002010400065B3 -:1012F0008FBF00140E000564000000008F4201043F -:101300008F8300209744010C3C05080094A54E965D -:10131000AC6200009762002C000424003042FFFF02 -:10132000008220253C02400E00A22825AC64000467 -:10133000AC600008AC60000CAC600010AC60001445 -:10134000AC600018AC65001C0A0004C32404000152 -:101350000E00033502002021A76000080E00033EA6 -:1013600002002021020020210E0003432405000179 -:101370003C0208008C420020104000428FBF001445 -:101380000E000564000000009742010C8F830020CE -:101390003C05080094A54E9600021400AC700000B5 -:1013A000AC620004AC6000088F64004C3C02401F3B -:1013B00000A22825AC64000C8F62005024040001B8 -:1013C000AC6200108F620054AC620014AC60001874 -:1013D000AC65001C8FBF00148FB000100A00058997 -:1013E00027BD00189362000024030020304200FF54 -:1013F000104300248FBF00140E000FD702002021DD -:10140000104000208FBF0014020020218FB0001078 -:10141000000028210A00034327BD001802002021F4 -:101420008FBF00148FB000100A00065127BD0018AE -:101430009745010C020020218FBF00148FB00010CF -:101440000A00067127BD0018020020218FB000108D -:101450000A00069627BD00189345010D02002021C1 -:101460008FB000100A0006E027BD001802002021FE -:101470008FBF00148FB000100A0006BC27BD0018F3 -:101480008FBF00148FB0001003E0000827BD0018C4 -:101490008F4202780440FFFE34820080AF42024057 -:1014A00024020002A34202443C02100003E00008B0 -:1014B000AF4202783C04080094844EA23C0208002B -:1014C0008C424EAC3083FFFF000318C00043102154 -:1014D000AF42003C3C0208008C424EA8AF420038AC -:1014E0003C02005034420008AF42003000000000CF -:1014F00000000000000000008F4200003042002089 -:101500001040FFFD000000008F4204003C01080075 -:10151000AC224E988F4204043C010800AC224E9C41 -:101520003C020020AF420030000000003C020800F6 -:1015300094424EA03C03080094634EA43C0508006E -:1015400094A54EA624840001004310213083FFFFA0 -:101550003C010800A4224EA03C010800A4244EA295 -:1015600014650003000000003C010800A4204EA206 -:1015700003E00008000000003C05000A27BDFFE86A -:10158000034528213C04080024844E88AFBF001086 -:101590000E0005EE2406000A3C02080094424E8A22 -:1015A0003C03080094634EA63042000F244200031F -:1015B0000043180424027FFF0043102B1040000258 -:1015C000AF83001C0000000D0E0004FB00000000B3 -:1015D0003C02080094424E928FBF001027BD0018B5 -:1015E00003E00008A74200A23C02000A03421021C7 -:1015F000944300063C02080094424E923C010800CD -:10160000A4234E8E004310238F83001C000214007D -:10161000000214030043102B03E0000838420001CD -:1016200027BDFFE8AFBF00103C02000A03421021B3 -:10163000944200063C010800A4224E8E0E0005488C -:10164000000000005440FFF93C02000A8FBF001068 -:1016500003E0000827BD001827BDFFE8AFBF00105A -:101660000E000548000000001040000300000000CC -:101670000E000556000000003C0208008C424E9807 -:101680008FBF001027430400AF4200383C0208001F -:101690008C424E9C27BD0018AF830020AF42003C17 -:1016A0003C020005AF42003003E00008AF800018A4 -:1016B0008F8200183C0300060002114000431025F1 -:1016C000AF420030000000000000000000000000F9 -:1016D0008F420000304200101040FFFD27420400FE -:1016E000AF82002003E00008AF8000183C0608002D -:1016F0008CC64E9C8F8500188F8300203C0208000A -:1017000094424E9227BDFFE024A5000124630020EF -:101710002442000124C70020AFB10014AFB0001074 -:10172000AFBF0018AF850018AF8300203C01080050 -:10173000A4224E92309000FF3C010800AC274E9C42 -:1017400004C100080000882104E000060000000039 -:101750003C0208008C424E98244200013C010800E3 -:10176000AC224E983C02080094424E923C03080082 -:1017700094634EA00010202B004310262C42000141 -:1017800000441025144000048F8300182402001028 -:101790001462000F000000000E00057A2411000101 -:1017A0003C03080094634E923C02080094424EA011 -:1017B00014620003000000000E0004FB00000000A3 -:1017C00016000003000000000E0005640000000089 -:1017D0003C03080094634E963C02080094424E94E9 -:1017E000246300013064FFFF3C010800A4234E96EF -:1017F00014820003000000003C010800A4204E9663 -:1018000012000006000000003C02080094424E92C4 -:10181000A74200A20A0005DC022010210E000548A4 -:101820000000000010400004022010210E000556A8 -:1018300000000000022010218FBF00188FB100149B -:101840008FB0001003E0000827BD00203084FFFFA8 -:1018500030A5FFFF000018211080000700000000E5 -:10186000308200011040000200042042006518216F -:101870000A0005E40005284003E00008006010218C -:1018800010C0000624C6FFFF8CA2000024A500049F -:10189000AC8200000A0005EE2484000403E0000886 -:1018A0000000000010A0000824A3FFFFAC86000089 -:1018B00000000000000000002402FFFF2463FFFF7F -:1018C0001462FFFA2484000403E000080000000012 -:1018D00024020001AF62000CA7620010A762001290 -:1018E000A762001403E00008A76200163082007FA0 -:1018F000034210213C08000E004818213C02080059 -:101900008C42002027BDFFD82407FF80AFB3001C06 -:10191000AFB20018AFB10014AFB00010AFBF0020DD -:101920000080802130B100FF0087202430D200FFEA -:101930001040002F00009821AF44002C906200005E -:1019400024030050304200FF1443000E000000004A -:101950003C0208008C4200E00202102100471024E3 -:10196000AF42002C3C0208008C4200E00202102131 -:101970003042007F0342102100481021944200D4DD -:101980003053FFFF0E000564000000003C02080019 -:1019900094424E968F8300200011340000C23025FF -:1019A00000122C003C02400000C2302534A500018A -:1019B000AC7000008FBF0020AC6000048FB2001834 -:1019C000AC7300088FB10014AC60000C8FB3001C26 -:1019D000AC6500108FB00010AC600014240400014E -:1019E000AC60001827BD00280A000589AC66001C01 -:1019F0008FBF00208FB3001C8FB200188FB100146E -:101A00008FB0001003E0000827BD00289343010FAA -:101A1000240200101062000E2865001110A00007BB -:101A200024020012240200082405003A1062000675 -:101A30000000302103E0000800000000240500350C -:101A40001462FFFC000030210A00060900000000BB -:101A50008F42007424420FA003E00008AF62000C24 -:101A600027BDFFE8AFBF00100E00034324050001AF -:101A70008FBF001024020001A762001227BD0018CA -:101A80002402000103E00008A360002227BDFFE05C -:101A9000AFB10014AFB00010AFBF001830B1FFFFFE -:101AA0000E000335008080219362003F2403000470 -:101AB000304200FF1443000C0200202112200008D5 -:101AC0002402000A0E0006020000000093620005D6 -:101AD0002403FFFE00431024A36200052402001229 -:101AE000A362003F020020210E00033EA36000819C -:101AF00016200003020020210E00066600000000F0 -:101B000002002021322600FF8FBF00188FB1001481 -:101B10008FB00010240500380A00060927BD0020F8 -:101B200027BDFFE0AFBF001CAFB20018AFB100147B -:101B3000AFB000100E000335008080210E000602B9 -:101B4000000000009362003F24120018305100FF93 -:101B5000123200030200202124020012A362003F7F -:101B6000936200052403FFFE004310240E00033E91 -:101B7000A362000502002021240500201632000780 -:101B8000000030218FBF001C8FB200188FB10014ED -:101B90008FB000100A00034327BD00208FBF001C38 -:101BA0008FB200188FB100148FB0001024050039D7 -:101BB0000A00060927BD002027BDFFE8AFB00010CE -:101BC000AFBF00149742010C24050036008080212D -:101BD00014400010304600FF0E00033500000000E6 -:101BE00024020012A362003F9362000534420010F9 -:101BF0000E000602A36200050E00033E0200202133 -:101C0000020020210E000343240500200A0006D50F -:101C1000000000000E000609000000000E00033561 -:101C200002002021936200232403FF9F0200202151 -:101C3000004310248FBF00148FB00010A362002354 -:101C40000A00033E27BD001827BDFFE0AFBF001804 -:101C5000AFB10014AFB0001030B100FF0E0003357B -:101C600000808021240200120E000602A362003FC1 -:101C70000E00033E0200202102002021022030211C -:101C80008FBF00188FB100148FB0001024050035ED -:101C90000A00060927BD0020A380002C03E00008ED -:101CA000A380002D8F4202780440FFFE8F82003413 -:101CB000AF42024024020002A34202443C02100050 -:101CC00003E00008AF4202783C0360008C625400DD -:101CD000304200081440FFFD000000008C625408F0 -:101CE000AF82000024020052AC605408AC6454304F -:101CF000AC6254342402000803E00008AC625400D3 -:101D00003C0260008C425400304200081040000544 -:101D10003C0360008C625400304200081440FFFD18 -:101D2000000000008F8300003C02600003E0000818 -:101D3000AC43540890A30000240200050080402119 -:101D40003063003F0000482114620005000050216C -:101D500090A2001C94A3001E304900FF306AFFFFD0 -:101D6000AD00000CAD000010AD0000249502001481 -:101D70008D05001C8D0400183042FFFF0049102320 -:101D800000021100000237C30040382100862023E2 -:101D900000A2102B0082202300A72823AD05001CE1 -:101DA000AD040018A5090014A5090020A50A001615 -:101DB00003E00008A50A00228F4201F80440FFFE5C -:101DC00024020002AF4401C0A34201C43C0210003F -:101DD00003E00008AF4201F83C0208008C4200B466 -:101DE00027BDFFE8AFBF001424420001AFB00010D0 -:101DF0003C010800AC2200B48F4300243C02001FC9 -:101E000030AA00FF3442FF8030D800FF00628024F7 -:101E10000080F82130EF00FF1158003B01405821AD -:101E2000240CFF803C19000A3163007F000310C0BE -:101E300000031940006218213C0208008C4200DCBB -:101E400025680001310D007F03E2102100431021BD -:101E50003043007F03431821004C102400794821AF -:101E6000AF4200248D220024016C1824006C7026DF -:101E7000AD22000C8D220024310800FFAD2200109D -:101E800095220014952300208D27001C3042FFFF6F -:101E90003063FFFF8D26001800431023000211005D -:101EA000000227C30040282100C4302300E2102B89 -:101EB00000C2302300E53823AD27001CAD260018F2 -:101EC00095220020A522001495220022154B000A1D -:101ED000A52200168D2300248D220008254600012E -:101EE000314500801462000430C4007F108F00026E -:101EF00038AA008000C0502151AF000131C800FF56 -:101F00001518FFC9010058218F8400343082007FEA -:101F1000034218213C02000A006218212402FF80BB -:101F200000822024AF440024A06A0079A06A0083C4 -:101F30008C6200508F840034AC6200708C65007439 -:101F40003C027FFF3442FFFF00A228240E00073C22 -:101F5000AC650074AF5000248FBF00148FB0001028 -:101F600003E0000827BD001827BDFFC0AFBE003842 -:101F7000AFB70034AFB5002CAFB20020AFB1001C3A -:101F8000AFB00018AFBF003CAFB60030AFB4002810 -:101F9000AFB300248F4500248F4600288F43002CC8 -:101FA0003C02001F3442FF800062182400C230242B -:101FB0000080A821AFA3001400A2F0240E000700A7 -:101FC000AFA600103C0208008C4200E02410FF8005 -:101FD0000360882102A2102100501024AF42002487 -:101FE0003C0208008C4200E002A210213042007F37 -:101FF000034218213C02000A00629021924200D262 -:1020000093630084305700FF306300FF2402000117 -:1020100010620034036020212402000214620036A2 -:10202000000000000E0012E50240282192230083E8 -:10203000922200833063007F3042007F000210C094 -:1020400000031940006218213C0208008C4200DCA9 -:1020500002A210210043382100F01024AF420028D2 -:10206000922500789224008330E2007F03421821F9 -:102070003C02000C14850007006280212402FFFF4F -:10208000A24200F12402FFFFA64200F20A0007F874 -:102090002402FFFF96020020A24200F196020022D5 -:1020A000A64200F28E020024AE4200F49222008387 -:1020B000A24200F08E4200C8AE4200FC8E4200C434 -:1020C000AE4200F88E220050AE4201008E4200CC9B -:1020D000AE420104922200853042003F0A000853BC -:1020E000344200400E00130802402821922200854D -:1020F0000A0008533042003F936200852403FFDF4B -:102100003042003FA36200859362008500431024A3 -:10211000A36200859363008393620078307400FFAC -:10212000304200FF10540036240AFF803C0C000CA3 -:102130003283007F000310C00003194000621821A1 -:102140003C0208008C4200DC268800013109007F37 -:1021500002A210210043382130E2007F03421821FF -:1021600000EA1024AF420028006C80218E02002477 -:10217000028A1824006A5826AE02000C8E0200243F -:10218000310800FFAE0200109602001496030020F2 -:102190008E07001C3042FFFF3063FFFF8E060018E1 -:1021A0000043102300021100000227C30040282131 -:1021B00000C4302300E2102B00C2302300E5382396 -:1021C000AE07001CAE06001896020020A6020014FE -:1021D00096020022A602001692220079304200FFE9 -:1021E000105400070000000051370001316800FF63 -:1021F00092220078304200FF1448FFCD0100A02158 -:1022000092220083A22200798E2200500A0008B395 -:10221000AE220070A22200858E22004C2405FF8091 -:10222000AE42010C9222008534420020A222008599 -:10223000924200D13C0308008C6300DC305400FF64 -:102240003C0208008C4200E400143140001420C01D -:1022500002A3182100C4202102A210210064382109 -:10226000004610210045182400E52824AF45002829 -:10227000AF43002C3042007F924400D030E3007F17 -:1022800003422821034318213C02000C00628021F4 -:102290003C02000E309600FF00A298211296002A00 -:1022A000000000008E02000C0200202102602821A4 -:1022B00010400025261000280E00071B000000001B -:1022C0009262000D26830001307400FF3042007FCF -:1022D000A262000D2404FF801697FFF026730020F1 -:1022E0003C0208008C4200DC0000A02102A2102168 -:1022F00000441024AF4200283C0208008C4200E455 -:102300003C0308008C6300DC02A21021004410246E -:10231000AF42002C3C0208008C4200E402A31821CA -:102320003063007F02A210213042007F034220214F -:10233000034318213C02000C006280213C02000E85 -:102340000A000875008298218E4200D8AE22005003 -:102350008E4200D8AE22007092250083924600D1B2 -:1023600092230083924400D12402FF8000A22824FB -:102370003063007F308400FF00A628250064182AFF -:102380001060000230A500FF38A50080A225008360 -:10239000A22500790E00070E000000009222007EA8 -:1023A00002A02021A222007A8E2300743C027FFF2B -:1023B0003442FFFF006218240E00073CAE23007475 -:1023C0008FA20010AF5E00248FBF003CAF420028F8 -:1023D0008FBE00388FA200148FB700348FB6003044 -:1023E0008FB5002C8FB400288FB300248FB200204B -:1023F0008FB1001C8FB0001827BD004003E000081B -:10240000AF42002C90A2000024420001A0A20000D4 -:102410003C0308008C6300F4304200FF1443000FBB -:1024200000803021A0A000003C0208008C4200E4A3 -:102430008F840034008220213082007F03421821E3 -:102440003C02000C006218212402FF80008220243C -:10245000ACC3000003E00008AF4400288C820000F9 -:102460002442002003E00008AC82000094C2000077 -:102470003C080800950800CA30E7FFFF00804821AB -:1024800001021021A4C2000094C200003042FFFFEC -:1024900000E2102B54400001A4C7000094A20000E9 -:1024A0003C0308008C6300CC24420001A4A200007D -:1024B00094A200003042FFFF544300078F8600289B -:1024C0000107102BA4A00000544000010100382196 -:1024D000A4C700008F8600288CC4001CAF44003CB9 -:1024E00094A200008F43003C3042FFFF000210C066 -:1024F00000621821AF43003C8F42003C0082202341 -:1025000018800004000000008CC200180A000914A2 -:10251000244200018CC20018AF4200383C02005037 -:1025200034420010AF420030000000000000000004 -:10253000000000008F420000304200201040FFFDEC -:10254000000000008F420404AD2200048F4204000A -:10255000AD2200003C020020AF42003003E0000842 -:102560000000000027BDFFE0AFB20018AFB10014BB -:10257000AFB00010AFBF001C94C2000000C08021AB -:102580003C120800965200C624420001A602000038 -:102590009603000094E2000000E03021144300059F -:1025A0008FB100300E0008E9024038210A000946C8 -:1025B000000000008C8300048C8200042442004050 -:1025C00004610007AC8200048C8200040440000413 -:1025D000000000008C82000024420001AC82000058 -:1025E000960200003042FFFF50520001A60000009A -:1025F0009622000024420001A62200008F820028BB -:102600009623000094420016144300048FBF001C60 -:1026100024020001A62200008FBF001C8FB2001808 -:102620008FB100148FB0001003E0000827BD002018 -:102630008F89002827BDFFE0AFBF00188D2200283A -:102640002748040030E700FFAF4200388D22002CFD -:10265000AF880030AF42003C3C020005AF42003082 -:10266000000000000000000000000000000000006A -:1026700000000000000000008C82000C8C82000C26 -:10268000AD0200008C820010AD0200048C820018A4 -:10269000AD0200088C82001CAD02000C8CA200145C -:1026A000AD0200108C820020AD0200149082000563 -:1026B000304200FF00021200AD0200188CA2001888 -:1026C000AD02001C8CA2000CAD0200208CA20010F8 -:1026D000AD0200248CA2001CAD0200288CA20020B8 -:1026E000AD02002CAD060030AD000034978300260B -:1026F0003402FFFF14620002006020213404FFFF57 -:1027000010E00011AD040038952300369524003602 -:10271000240200013063FFFF000318C20069182182 -:1027200090650040308400070082100400451025A9 -:10273000A06200408F820028944200563042FFFF82 -:102740000A0009ADAD02003C952300369524003601 -:10275000240200013063FFFF000318C20069182142 -:1027600090650040308400070082100400021027AA -:1027700000451024A0620040AD00003C00000000B5 -:1027800000000000000000003C020006344200404F -:10279000AF42003000000000000000000000000018 -:1027A0008F420000304200101040FFFD8F8600284D -:1027B000AF88003024C2005624C7003C24C400283F -:1027C00024C5003224C600360E000927AFA200102F -:1027D0008FBF001803E0000827BD00208F8300246E -:1027E0003C0508008CA500E88F82003430633FFF71 -:1027F0000003198000451021004310212403FF80AD -:102800003045007F00431024AF42002803451821C3 -:102810003C02000C0062302190C2000D0000382103 -:1028200034420010A0C2000D8F8900288F8A002436 -:1028300095230036000A1382304800032402000169 -:10284000A4C3000E1102000B290200021040000573 -:10285000240200021100000C240300010A0009F008 -:102860000000182111020006000000000A0009F013 -:10287000000018218CC2002C0A0009F0244300013A -:102880008CC20014244300018CC200180043102B9A -:1028900014400003000000000A0009F924070001A9 -:1028A0009522003E24420001A522003E000A138228 -:1028B000304300032C6200021040000900802821F0 -:1028C000146000040000000094C200360A000A09E7 -:1028D0003046FFFF8CC600380A000A090080282114 -:1028E000000030213C04080024844EB00A00095A3C -:1028F00000000000274901008D22000C95230006EE -:1029000001202021000216023045003F3063FFFF06 -:102910002402002728A6002810A2000EAF8300245E -:1029200010C00008240200312402002110A2000976 -:102930002402002510A200079382002D0A000A2716 -:102940000000000010A200059382002D0A000A2753 -:10295000000000000A0009C5000000000A0006F798 -:102960000000000095230006912400058D25000C31 -:102970008D2600108D2700188D28001C8D29002021 -:10298000244200013C010800A4234EB63C0108008B -:10299000A0244EB53C010800AC254EBC3C0108000B -:1029A000AC264EC03C010800AC274EC83C010800D4 -:1029B000AC284ECC3C010800AC294ED003E0000806 -:1029C000A382002D8F87002827BDFFC0AFB300343E -:1029D000AFB20030AFB1002CAFB00028AFBF0038AD -:1029E0003C0208008C4200D094E3003030B0FFFF7E -:1029F000005010073045FFFF3063FFFF00C09821F3 -:102A0000A7A200103C110800963100C614A30006CE -:102A10003092FFFF8CE2002424420030AF42003CA1 -:102A20000A000A608CE2002094E200323042FFFF8C -:102A300054A2000827A400188CE2002C2442003085 -:102A4000AF42003C8CE20028AF4200380A000A6E18 -:102A50008F84002827A5001027A6002002203821F7 -:102A60000E0008E9A7A000208FA200182442003021 -:102A7000AF4200388FA2001CAF42003C8F84002878 -:102A80003C020005AF42003094820034274304002A -:102A90003042FFFF0202102B14400007AF830030CA -:102AA00094820054948300340202102100431023C6 -:102AB0000A000A823043FFFF94830054948200345A -:102AC0000223182100501023006218233063FFFFF7 -:102AD000948200163042FFFF144300030000000000 -:102AE0000A000A9024030001948200163042FFFF7E -:102AF0000043102B104000058F8200309482001696 -:102B0000006210233043FFFF8F820030AC5300007F -:102B1000AC400004AC520008AC43000C3C02000680 -:102B200034420010AF4200300000000000000000FE -:102B3000000000008F420000304200101040FFFDF6 -:102B4000001018C20064182190650040320400078C -:102B5000240200018FBF00388FB300348FB20030E1 -:102B60008FB1002C8FB00028008210040045102582 -:102B700027BD004003E00008A062004027BDFFA879 -:102B8000AFB60050AFB5004CAFB40048AFB300448F -:102B9000AFB1003CAFBF0054AFB20040AFB000389F -:102BA0008C9000003C0208008C4200E88F860034C4 -:102BB000960300022413FF8000C2302130633FFFE0 -:102BC0000003198000C3382100F3102490B20000E4 -:102BD000AF42002C9203000230E2007F034230211A -:102BE0003C02000E00C28821306300C02402004075 -:102BF0000080A82100A0B021146200260000A021BE -:102C00008E3400388E220018144000022402000185 -:102C1000AE2200189202000D304200201440001530 -:102C20008F8200343C0308008C6300DC001238C043 -:102C3000001231400043102100C7302100463821E6 -:102C400030E300073C02008030E6007800C2302507 -:102C50000343182100F31024AF4208002463090045 -:102C6000AF4608108E2200188C6300080043102124 -:102C7000AE2200188E22002C8E2300182442000160 -:102C80000062182B1060003D000000000A000B4499 -:102C900000000000920300022402FFC00043102441 -:102CA000304200FF1440000524020001AE2200184B -:102CB000962200360A000B2D3054FFFF8E2200149E -:102CC00024420001AE220018920200000002160009 -:102CD00000021603044100290000000096020002D1 -:102CE00027A4001000802821A7A200169602000247 -:102CF00024070001000030213042FFFFAF82002492 -:102D00000E00095AAFA0001C960300023C04080004 -:102D10008C8400E88F82003430633FFF0003198009 -:102D200000441021004310213043007F3C05000C7B -:102D30000053102403431821AF42002800651821D6 -:102D40009062000D001221403042007FA062000D11 -:102D50003C0308008C6300E48F82003400431021A0 -:102D60000044382130E2007F034210210045102149 -:102D700000F31824AF430028AEA200009222000DF9 -:102D8000304200101040001302A020218F83002841 -:102D90008EA40000028030219462003E2442FFFF96 -:102DA000A462003E948400029625000E3084FFFF4A -:102DB0000E000A3F30A5FFFF8F82002894430034A5 -:102DC0009622000E1443000302A0202124020001D9 -:102DD000A382002C02C028210E0008CF00000000B2 -:102DE0008FBF00548FB600508FB5004C8FB4004891 -:102DF0008FB300448FB200408FB1003C8FB00038D9 -:102E000003E0000827BD00588F85002827BDFFD0AC -:102E1000AFB40028AFB20020AFBF002CAFB3002486 -:102E2000AFB1001CAFB0001890A800D090A600D1A0 -:102E30003C0208008C4200E48F83003430C700FF5E -:102E4000A3A600100062182100071140006218219B -:102E50003062007F034220213C02000C00822021CE -:102E60002402FF8000621824311200FF8CB100D8C8 -:102E7000AFA400148CB300DC0000A021AF430028F5 -:102E800010F2001F240200018FA6001427A40014D2 -:102E900027A500108CC2000402228021027010239A -:102EA000044000172402000190C3000D2402FF809B -:102EB00000431024304200FF144000070200882124 -:102EC00090C2000D344200400E0008CFA0C2000D99 -:102ED0000A000B8B93A200100E000AAD241400010F -:102EE0008F830028AC7000D893A20010A06200D19C -:102EF00093A200101452FFE58FA6001424020001D3 -:102F0000168200048FBF002C0E0006F700000000A0 -:102F10008FBF002C8FB400288FB300248FB2002005 -:102F20008FB1001C8FB0001803E0000827BD0030EF -:102F300027BDFFD8AFB3001CAFB20018AFB100146B -:102F4000AFB00010AFBF00200080982100E08021CA -:102F500030B1FFFF0E00056430D200FF000000001A -:102F600000000000000000008F820020AC51000033 -:102F7000AC520004AC530008AC40000CAC40001054 -:102F8000AC400014AC4000183C03080094634E961B -:102F900002038025AC50001C00000000000000006F -:102FA00000000000240400018FBF00208FB3001C2C -:102FB0008FB200188FB100148FB000100A0005897D -:102FC00027BD002827BDFFE8AFB00010AFBF001439 -:102FD00030A5FFFF30C600FF0080802124020C8056 -:102FE000AF420024000000000000000000000000CC -:102FF00000000000000000000E000B9A000000001E -:103000003C040800248400E08C8200002403FF803C -:103010008FBF00140202102100431024AF4200248D -:103020008C8200003C03000A020280213210007FE3 -:10303000035010218FB000100043102127BD00184D -:1030400003E00008AF82002827BDFFE8AFBF0010F3 -:103050008F4401403C0308008C6300E02402FF80A1 -:10306000AF8400340083182100621024AF42002492 -:103070003C02000803424021950500023063007FB6 -:103080003C02000A034318210062182130A5FFFF0B -:103090003402FFFF000030213C07602010A2000630 -:1030A000AF8300282402FFFFA5020002946500D42C -:1030B0000E000BBF30A5FFFF8FBF001024020C8055 -:1030C00027BD001803E00008AF4200243C020008BE -:1030D00003424021950200023C0A0800954A00C6BE -:1030E0003046FFFF14C000073402FFFF8F82002824 -:1030F0008F8400343C076020944500D40A000C28DB -:1031000030A5FFFF10C200248F87002894E20054EE -:1031100094E400163045FFFF00A6102300A6182BEC -:103120003089FFFF106000043044FFFF00C510230A -:10313000012210233044FFFF008A102B1040000CA6 -:10314000012A102324020001A50200162402FFFF19 -:10315000A502000294E500D48F84003400003021E1 -:1031600030A5FFFF3C0760200A000BBF00000000F5 -:103170000044102A104000080000000095020016CC -:103180003042000110400004000000009742007E21 -:1031900024420014A502001603E00008000000000D -:1031A0008F84002827BDFFE0AFBF00189482003451 -:1031B0009483003E1060001A3048FFFF9383002C78 -:1031C00024020001146200278FBF00188F8200289C -:1031D000000818C231080007006218212447003A8D -:1031E000244900542444002024450030244600345F -:1031F00090620040304200FF01021007304200019F -:10320000104000168FBF00180E000927AFA900104C -:103210008F820028944200340A000C413048FFFF9E -:1032200094830036948200341043000E8FBF001840 -:1032300094820036A482003494820056A482005402 -:103240008C82002CAC82002494820032A482003054 -:103250009482003CA482003A8FBF00180A000C013F -:1032600027BD002003E0000827BD002027BDFFE8A0 -:10327000AFBF00108F4A01003C0508008CA500E09C -:103280003C02080090424EBC3C0C0800958C4EB6A7 -:1032900001452821304B003F30A2007F03424021EE -:1032A000396900323C02000A3963003F2C63000197 -:1032B000010240212D2900012402FF8000A22824C0 -:1032C00001234825AF8A003400801821AF4500242F -:1032D000000030210080282124070001AF88002849 -:1032E0003C04080024844EB0AF8C00241520000656 -:1032F000A380002D240200201562000E3402FFFF7F -:103300001582000C00000000240200201562000558 -:10331000000000008C6300142402FFFF106200070D -:10332000000000000E00095A000000000A000C9D79 -:10333000000000000E0009C5006020210E000C36C0 -:10334000000000008FBF001024020C8027BD001871 -:1033500003E00008AF4200243C0208008C4200E079 -:1033600027BDFFA0AFB1003C008210212411FF80D7 -:10337000AFBE0058AFB70054AFB20040AFB0003896 -:10338000AFBF005CAFB60050AFB5004CAFB4004863 -:10339000AFB30044005110248F4800248F49002807 -:1033A0008F470028AF4200243C0208008C4200E016 -:1033B0000080902124060006008210213042007F08 -:1033C000034218213C02000A006280213C02001FD7 -:1033D0003442FF8000E2382427A40010260500F0C4 -:1033E0000122F0240102B8240E0005EEAFA7003040 -:1033F0008FA20018AE0200C48FA2001CAE0200C84B -:103400008FA20024AE0200CC93A40010920300D13E -:103410002402FF800082102400431025304900FF61 -:103420003083007F3122007F0062102A10400004A8 -:10343000000310C001311026304900FF000310C006 -:1034400000031940006218213C0208008C4200DC95 -:10345000920400D202421021004310210051102496 -:10346000AF42002893A300103063007F000310C018 -:1034700000031940006218213C0208008C4200DC65 -:1034800002421021004310213042007F03421821E4 -:103490003C02000C006240218FA300142402FFFFB5 -:1034A00010620030309500FF93A2001195030014C4 -:1034B000304400FF3063FFFF0064182B1060000DE4 -:1034C00000000000950400148D07001C8D060018F4 -:1034D0003084FFFF0044202300042100000010215D -:1034E00000E4382100E4202B00C230210A000D172F -:1034F00000C43021950400148D07001C8D060018AF -:103500003084FFFF008220230004210000001021EE -:103510000080182100C2302300E4202B00C4302397 -:1035200000E33823AD07001CAD06001893A200117C -:10353000A502001497A20012A50200168FA2001483 -:10354000AD0200108FA20014AD02000C93A2001176 -:10355000A502002097A20012A50200228FA200144B -:10356000AD0200242406FF80024610243256007F5C -:10357000AF420024035618213C02000A0062802159 -:103580008E02004C8FA200203124007F000428C04E -:10359000AE0200508FA200200004214000852821A7 -:1035A000AE02007093A2001001208821A2020083C5 -:1035B00093A20010A2020079920200853042003FDF -:1035C000A20200853C0208008C4200DC024210216D -:1035D0000045102100461024AF42002C3C02080098 -:1035E0008C4200E43C0308008C6300DC02421021A2 -:1035F0000044102100461024AF4200283C0208007D -:103600008C4200E402431821006518210242102177 -:10361000004410213042007F3063007F93A50010EA -:1036200003422021034318213C02000E0062402186 -:103630003C02000C10B1008C008248213233007F24 -:10364000166000192404FF803C0208008C4200DC54 -:103650000242102100441024AF42002C3C0208001A -:103660008C4200E43C0308008C6300DC0242102121 -:1036700000441024AF4200283C0208008C4200E4C1 -:10368000024318213063007F024210213042007F44 -:1036900003422021034318213C02000E0062402116 -:1036A0003C02000C008248219124000D2414FF806C -:1036B0000000102100942025A124000D9504000293 -:1036C000950500148D07001C3084FFFF30A5FFFF17 -:1036D0008D060018008520230004210000E4382115 -:1036E00000C2302100E4202B00C43021AD07001CB3 -:1036F000AD06001895020002A5020014A5000016F0 -:103700008D020008AD0200108D020008AD02000C11 -:1037100095020002A5020020A50000228D020008EB -:10372000AD0200249122000D3042004010400042C2 -:10373000262200013C0208008C4200E0A3B30028CE -:103740003C10000A0242102100541024AF42002411 -:103750003C0208008C4200E0A380002C27A4002C2F -:10376000024210213042007F0342182100701821CC -:103770008C6200D88D26000427A50028AFA9002C54 -:1037800000461021AC6200D80E000AADAF830028BD -:1037900093A300288F8200280E0006F7A04300D1D3 -:1037A0000E000C360000000002541024AF4200242A -:1037B0003C0208008C4200DC00132940001320C0AA -:1037C00000A42021024210210044102100541024A2 -:1037D000AF42002C3C0208008C4200E43C0308008D -:1037E0008C6300DC03563021024210210045102179 -:1037F00000541024AF4200283C0208008C4200E430 -:1038000002431821006418210242102100451021B2 -:103810003042007F3063007F0342202103431821A0 -:103820003C02000E006240213C02000C00D08021CE -:1038300000824821262200013043007F14750005D4 -:10384000304400FF2403FF8002231024004310268D -:10385000304400FF93A20010008088212508002832 -:103860001444FF762529002093A400108FA3001490 -:103870002402FFFF1062000A308900FF2482000149 -:10388000248300013042007F14550005306900FF99 -:103890002403FF800083102400431026304900FFDA -:1038A00092020078305300FF11330032012088214A -:1038B0003C0208008C4200DC3225007F000520C05D -:1038C0000005294000A42021024210212406FF8087 -:1038D0000044102100461024AF42002C3C03080095 -:1038E0008C6300DC3C0208008C4200E40243182197 -:1038F00002421021004510210064182100461024C6 -:103900003063007FAF420028034318213C02000EC1 -:10391000006240213C0208008C4200E48D06000C4D -:103920000100202102421021004510213042007F79 -:10393000034218213C02000C0062482110C0000D17 -:10394000012028210E00071B000000002402FF8038 -:103950000222182426240001006228263082007FDB -:1039600014550002308300FF30A300FF1473FFD012 -:10397000006088218E0300743C027FFF3442FFFF09 -:1039800000621824AE0300740E00073C02402021A0 -:10399000AF5700248FA20030AF5E00288FBF005CBD -:1039A0008FBE00588FB700548FB600508FB5004CB3 -:1039B0008FB400488FB300448FB200408FB1003CF9 -:1039C0008FB0003827BD006003E00008AF42002C34 -:1039D00027BDFFD8AFB1001CAFBF0020AFB00018AB -:1039E00027510188922200032408FF803C03000A2B -:1039F0003047007FA3A700108F4601803C020800DB -:103A00008C4200E0AF86003400C2282100A81024B8 -:103A1000AF4200249224000030A2007F0342102114 -:103A200000431021AF8200283084007F240200026E -:103A300014820025000719403C0208008C4200E473 -:103A400000C210210043282130A2007F0342182128 -:103A500000A81024AF4200283C02000C006218218C -:103A60009062000DAFA3001400481025A062000D65 -:103A70008FA300149062000D304200405040006A55 -:103A80008FBF00208F860028A380002C27A400145D -:103A90008CC200D88C63000427A5001000431021BD -:103AA0000E000AADACC200D893A300108F8200288C -:103AB0000E0006F7A04300D10E000C3600000000F7 -:103AC0000A000ED88FBF00200E00070000C0202182 -:103AD0000E00070E000000003C0200080342802197 -:103AE000922300019202007B1443004F8FBF0020FD -:103AF000922200003044007F24020004108200174C -:103B0000288200051040000624020005240200035C -:103B1000108200078FB1001C0A000ED900000000BF -:103B2000108200128FBF00200A000ED98FB1001C36 -:103B300092050083920600788E0700748F8400340B -:103B400030A500FF00073E0230C600FF0E0007440C -:103B500030E7007F0A000ED88FBF00200E000CA4B3 -:103B60008F8400340A000ED88FBF002024020C80FE -:103B7000AF4200249202003E30420040104000203C -:103B8000000000009202003E000216000002160330 -:103B900004410006000000008F8400340E0006710E -:103BA000240500930A000ED88FBF00209202003F28 -:103BB00024030018304200FF1443000C8F840034AB -:103BC000240500390E000609000030210E000335DF -:103BD0008F84003424020012A202003F0E00033E34 -:103BE0008F8400340A000ED88FBF002024050036D1 -:103BF0000E000609000030210A000ED88FBF0020F9 -:103C00000E0003358F8400349202000534420020F8 -:103C1000A20200050E00033E8F8400340E00108FB8 -:103C20008F8400348FBF00208FB1001C8FB000182C -:103C300024020C8027BD002803E00008AF420024C6 -:103C400027BDFFE8AFB00010AFBF0014274301004D -:103C500094620008000214000002140304410002F0 -:103C6000000080212410000194620008304200808E -:103C70001040001A02001021946200083042200017 -:103C800010400016020010218C6300183C021C2D0D -:103C9000344219ED240600061062000F3C07602133 -:103CA0003C0208008C4200D4104000078F8200289C -:103CB0008F830028906200623042000F344200403F -:103CC000A06200628F8200288F840034944500D463 -:103CD0000E000BBF30A5FFFF020010218FBF0014A4 -:103CE0008FB0001003E0000827BD001827BDFFE0DB -:103CF000AFB10014AFB00010A380002CAFBF00180C -:103D00008F4501003C0308008C6300E02402FF8023 -:103D1000AF85003400A318213064007F03442021C4 -:103D2000006218243C02000A00822021AF430024D4 -:103D3000275001008E0200148C8300DCAF84002821 -:103D40000043102318400004000088218E02001454 -:103D50000E000B50AC8200DC9202000B2403000228 -:103D6000304200FF1443002F0000000096020008BC -:103D7000304300FF24020082146200052402008404 -:103D80000E000A0B000000000A000F640000000093 -:103D900014620009240200818F8200288F8400347D -:103DA0003C076021944500D49206000530A5FFFF32 -:103DB0000A000F5330C600FF146200270000000005 -:103DC0009202000A304300FF3062002010400004DD -:103DD000306200408F8400340A000F4F24060040F8 -:103DE00010400004000316008F8400340A000F4FB7 -:103DF0002406004100021603044100178F8400349A -:103E0000240600428F8200283C076019944500D4A4 -:103E100030A5FFFF0E000BBF000000000A000F647A -:103E2000000000009202000B24030016304200FF45 -:103E300010430006000000009202000B240300174C -:103E4000304200FF14430004000000000E000EDEAC -:103E500000000000004088210E000C360000000029 -:103E60009202000A304200081040000624020C8032 -:103E70008F8500283C0400080E0012BD0344202159 -:103E800024020C80AF4200248FBF001802201021B2 -:103E90008FB000108FB1001403E0000827BD002090 -:103EA00027BDFFE8AFBF0014AFB000108F50002453 -:103EB0003C0308008C6300E08F4501002402FF8072 -:103EC00000A318213064007F0344202100621824DD -:103ED0003C02000A00822021AF850034AF43002459 -:103EE00090820062AF8400283042000F34420050BC -:103EF000A08200623C02001F3442FF800E0006F7E1 -:103F000002028024AF5000248FBF00148FB0001035 -:103F100003E0000827BD00183C0208008C42002086 -:103F20001040001D2745010090A300093C02000835 -:103F30000342202124020018546200033C020008BE -:103F40000A000FA5240200080342202124020016C3 -:103F5000146200052402001724020012A082003F10 -:103F60000A000FAF94A700085462000694A7000847 -:103F7000936200052403FFFE00431024A3620005A2 -:103F800094A7000890A6001B8CA4000094A500062E -:103F90000A000B9A00073C0003E000080000000044 -:103FA0002744010094820008304500FF38A30082B6 -:103FB00038A200842C6300012C4200010062182505 -:103FC00010600006240200839382002D1040000D33 -:103FD000000000000A000C690000000014A20005A7 -:103FE00024A2FF808F4301043C02602003E000080C -:103FF000AC430014304200FF2C420002104000038A -:10400000240200220A000F090000000014A200038D -:10401000000000000A000F76000000000A000F9464 -:10402000000000009363007E9362007A144300094D -:10403000000020219362000024030050304200FF62 -:1040400014430004240400019362007E2442000112 -:10405000A362007E03E00008008010218F4201F877 -:104060000440FFFE24020002AF4401C0A34201C489 -:104070003C02100003E00008AF4201F827BDFFE852 -:10408000AFBF00109362003F2403000A304200FFDC -:1040900014430046000000008F6300548F62004C00 -:1040A0001062007F036030219362000024030050FF -:1040B000304200FF1443002F000000008F440140F5 -:1040C0003C0208008C4200E02403FF8000821021A3 -:1040D00000431024AF4200243C0208008C4200E060 -:1040E0008F6500543C03000A008220213084007F49 -:1040F0000344102100431021AC4501089762003CA5 -:104100008F63004C3042FFFF000210400062182114 -:10411000AF63005C8F6300548F64004C9762003C77 -:10412000006418233042FFFF0003184300021040D0 -:104130000043102A10400006000000008F62005467 -:104140008F63004C004310230A0010250002104327 -:104150009762003C3042FFFF00021040ACC2006496 -:1041600024020001A0C0007CA0C2008424020C80B4 -:10417000AF4200240E000FD78F4401401040004989 -:104180008FBF00108F4301408F4201F80440FFFEB3 -:1041900024020002AF4301C0A34201C43C0210004C -:1041A000AF4201F80A0010778FBF00109362003F02 -:1041B00024030010304200FF1443000400000000FC -:1041C0008F4401400A001063000028219362003FE1 -:1041D00024030016304200FF14430004240200149C -:1041E000A362003F0A001071000000008F62004CC3 -:1041F0008F630050004310230441002A8FBF00103A -:104200009362008124420001A362008193620081D5 -:104210003C0308008C6300C0304200FF14430010D0 -:10422000000000009362003F24030004304200FFBE -:1042300014430006000000008F4401408FBF0010AF -:10424000240500930A00067127BD00188F44014021 -:10425000240500938FBF00100A0006E027BD001858 -:104260008F4401400E000335000000008F620054AF -:104270002442FFFFAF6200548F6200502442FFFFD0 -:10428000AF6200500E00033E8F4401408F44014056 -:104290008FBF0010240500040A00034327BD001847 -:1042A0008FBF001003E0000827BD00188F4201886F -:1042B0009363007E00021402304400FF306300FF6D -:1042C0001464000D0000000093620080304200FF83 -:1042D0001044000900000000A36400809362000005 -:1042E00024030050304200FF14430004000000008B -:1042F0000A0007A88F440180A364008003E000083F -:104300000000000027BDFFE8AFB00010AFBF0014F1 -:1043100093620005240300303042003014430089CA -:10432000008080213C0208008C4200201040008068 -:10433000020020210E000564000000008F8500208F -:10434000ACB000009362003E9363003F304200FF38 -:1043500000021200306300FF00431025ACA20004ED -:104360009362008200021600000216030441000559 -:10437000000000003C0308008C6300480A0010B5F0 -:10438000000000009362003E3042004014400003F1 -:104390000000182193620081304300FF9362008285 -:1043A00000031E00304200FF0002140000621825C6 -:1043B000ACA300088F620040ACA2000C8F620048E2 -:1043C000ACA200108F62004CACA200148F620050AF -:1043D0008F63004C004310230441000300000000E1 -:1043E0000A0010C98F62004C8F620050ACA2001806 -:1043F0003C02080094424E963C03C00B0000202172 -:10440000004310250E000589ACA2001C8F620054E9 -:104410008F840020AC8200008F620058AC820004C0 -:104420008F62005CAC8200088F6200608F43007472 -:1044300000431021AC82000C8F620064AC8200103B -:10444000976300689762006A00031C003042FFFF18 -:1044500000621825AC83001493620082240300805C -:10446000304200FF14430003000000000A0010FD6A -:10447000AC8000188F63000C240200011062000E53 -:104480002402FFFF9362003E304200401440000AC5 -:104490002402FFFF8F63000C8F4200740062182318 -:1044A0003C02080000621024144000020000282191 -:1044B0000060282100051043AC8200183C0208006F -:1044C00094424E963C03C00C00002021004310256E -:1044D0008F8300200E000589AC62001C8F620018DB -:1044E0008F8300203C05080094A54E96240400010B -:1044F000AC620000AC6000048F66006C3C02400DB2 -:1045000000A22825AC6600088F6200DCAC62000CBB -:10451000AC6000109362000500021600AC6200144B -:10452000AC6000180E000589AC65001C020020215B -:104530008FBF00148FB00010A36000050A0004F2C2 -:1045400027BD00188FBF00148FB0001003E00008D3 -:1045500027BD00189742007C30C600FFA08600846B -:104560003047FFFF2402000514C2000B24E346502D -:1045700090A201122C4200071040000724E30A0019 -:1045800090A30112240200140062100400E2102122 -:104590000A0011353047FFFF3067FFFF03E00008D6 -:1045A000A4870014AC87004C8CA201080080402135 -:1045B00000A0482100E2102330C600FF184000038D -:1045C00093AA001324E2FFFCACA2010830C2000150 -:1045D00010400008000000008D02005000E210238F -:1045E00004410013240600058D02005410E200105F -:1045F000000000008D02005414E2001A00000000C8 -:104600003C0208008C4200D8304200201040000AD2 -:1046100024020001910300789102008314430006F4 -:104620002402000101002021012028212406000489 -:104630000A00112300000000A100008411400009BD -:10464000A50200148F4301008F4201F80440FFFED1 -:1046500024020002AF4301C0A34201C43C02100087 -:10466000AF4201F803E000080000000027BDFFE8AA -:104670008FA90028AFBF00100080402100E9182357 -:104680001860007330C600FFA080007CA08000810D -:104690008CA2010800E210230440004D000000003D -:1046A0008C8200509483003C8C8400640047482333 -:1046B0003063FFFF012318210083202B10800004AA -:1046C000000000008D0200640A00118600E2102143 -:1046D0009502003C3042FFFF0122102100E2102130 -:1046E000AD02005C9502003C8D03005C3042FFFF90 -:1046F0000002104000E210210043102B1040000384 -:10470000000000000A0011958D02005C9502003C3B -:104710003042FFFF0002104000E21021AD02005CB9 -:10472000A1000084AD07004C8CA2010800E2102318 -:104730001840000224E2FFFCACA2010830C20001D4 -:104740001040000A000000008D02005000E210231B -:1047500004410004010020218D02005414E20003F2 -:10476000000000000A0011B7240600058D02005465 -:1047700014E200478FBF00103C0208008C4200D8B2 -:10478000304200201040000A24020001910300780A -:10479000910200831443000624020001010020213D -:1047A000240600048FBF00100A00112327BD001843 -:1047B000A1000084A50200148F4301008F4201F87C -:1047C0000440FFFE240200020A0011DC0000000089 -:1047D0008C82005C004910230043102B54400001E0 -:1047E000AC87005C9502003C3042FFFF0062102B5A -:1047F00014400007240200029502003C8D03005C77 -:104800003042FFFF00621821AD03005C2402000269 -:10481000AD07004CA10200840E000FD78F440100A9 -:104820001040001B8FBF00108F4301008F4201F822 -:104830000440FFFE24020002AF4301C0A34201C4B2 -:104840003C021000AF4201F80A0011F28FBF0010C5 -:1048500030C200101040000E8FBF00108C83005C2F -:104860009482003C006918233042FFFF0062182147 -:104870003C023FFF3444FFFF0083102B54400001F3 -:104880000080182101231021AD02005C8FBF0010B1 -:1048900003E0000827BD001827BDFFE88FAA002805 -:1048A000AFBF00100080402100EA482319200021FA -:1048B00030C600FF8C83005C8C820064006A182381 -:1048C0000043102B504000100069182194A20110E1 -:1048D00001221021A4A2011094A201103042FFFF76 -:1048E0000043102B1440000A3C023FFF94A2011029 -:1048F00000431023A4A201109482003C3042FFFF29 -:104900000A00121100621821A4A001103C023FFF0E -:104910003444FFFF0083102B544000010080182115 -:1049200000671021AD02005CA100007C0A00125952 -:10493000A100008130C200101040003C00000000C7 -:104940008C820050004A10231840003800000000FC -:104950009082007C24420001A082007C9082007C36 -:104960003C0308008C630024304200FF0043102BFE -:104970001440005C8FBF00108CA2010800E21023DD -:1049800018400058000000008C8300549482003CC2 -:10499000006A18233042FFFF000318430002104052 -:1049A0000043102A10400005000000008C820054D3 -:1049B000004A10230A001240000210439482003C77 -:1049C0003042FFFF00021040AD0200649502003C3F -:1049D0008D0400649503003C3042FFFF000210404C -:1049E000008220213063FFFF008318210143102142 -:1049F000AD02005C8D020054ACA20108240200024A -:104A0000A10200840E000FD78F4401001040003532 -:104A10008FBF00108F4301008F4201F80440FFFE5A -:104A2000240200020A00128200000000AD07004CC0 -:104A30008CA2010800E210231840000224E2FFFCCF -:104A4000ACA2010830C200011040000A00000000C2 -:104A50008D02005000E210230441000401002021D7 -:104A60008D02005414E20003000000000A001279D5 -:104A7000240600058D02005414E2001A8FBF0010B6 -:104A80003C0208008C4200D8304200201040000A4E -:104A90002402000191030078910200831443000670 -:104AA0002402000101002021240600048FBF001011 -:104AB0000A00112327BD0018A1000084A5020014DC -:104AC0008F4301008F4201F80440FFFE24020002E0 -:104AD000AF4301C0A34201C43C021000AF4201F841 -:104AE0008FBF001003E0000827BD00188FAA001038 -:104AF0008C8200500080402130C600FF004A102305 -:104B000000A048211840000700E0182124020001FD -:104B1000A0800084A0A00112A48200140A0011F455 -:104B2000AFAA0010A0800081AD07004C8CA2010844 -:104B300000E210231840000224E2FFFCACA20108AE -:104B400030C2000110400008000000008D0200503B -:104B50000062102304410013240600058D02005456 -:104B600010620010000000008D0200541462001159 -:104B7000000000003C0208008C4200D830420020B7 -:104B80001040000A24020001910300789102008382 -:104B900014430006240200010100202101202821E5 -:104BA000240600040A00112300000000A100008474 -:104BB000A502001403E000080000000027BDFFE08C -:104BC000AFBF0018274201009046000A8C4800142D -:104BD0008C8B004C9082008430C900FF0168182340 -:104BE000304A00FF1C60001A2D4600062402000116 -:104BF0000142100410C00016304300030120302190 -:104C00000100382114600007304C000C15800009A9 -:104C1000304200301440000B8FBF00180A0012E32E -:104C2000000000000E0011F4AFAB00100A0012E308 -:104C30008FBF00180E001169AFAB00100A0012E31D -:104C40008FBF0018AFAB00100E001289AFAA00147E -:104C50008FBF001803E0000827BD002024020003D6 -:104C6000A08200848C82005403E00008ACA20108FA -:104C70003C02000803421821906200812406004390 -:104C80003C07601924420001A0620081906300810A -:104C90003C0208008C4200C0306300FF1462001028 -:104CA0002403FF803C0208008C4200E000821021B7 -:104CB00000431024AF4200243C0208008C4200E074 -:104CC0003C03000A008210213042007F0342102181 -:104CD00000431021944500D40A000BBF30A5FFFF0C -:104CE00003E000080000000027BDFFE0AFBF001890 -:104CF000AFB10014AFB000108F420180008080215E -:104D000000A088210E0012EA00402021A2000084A9 -:104D10008E0200548FBF00188FB00010AE22010821 -:104D20008FB1001403E0000827BD002027BDFFE07D -:104D30003C020008AFB00010AFBF0018AFB10014C4 -:104D4000034280218F510140920300848E04005061 -:104D50008E02004C14820040306600FF3C020800C6 -:104D60008C4200E02403FF80022210210043102423 -:104D7000AF4200243C0208008C4200E09744007CD3 -:104D800092050081022210213042007F0342182147 -:104D90003C02000A0062182114A0000B3084FFFFBF -:104DA0002402000554C20014248205DC9062011222 -:104DB00024420001A062011224020C80AF420024B0 -:104DC0000A00134224020005A0600112240200051B -:104DD00014C20009248205DC920200812C420007E3 -:104DE0005040000524820A0092030081240200142E -:104DF00000621004008210213044FFFFA60400145A -:104E00000E0012EA022020219602003C8E03004C84 -:104E1000022020213042FFFF0002104000621821D2 -:104E20000E000335AE03005C9202007D02202021BB -:104E3000344200400E00033EA202007D8F4201F882 -:104E40000440FFFE24020002AF5101C0A34201C48E -:104E50003C021000AF4201F88FBF00188FB1001460 -:0C4E60008FB0001003E0000827BD002008 -:044E6C0008000E7CB0 -:104E700008000EC408000F0408000F5008000F843B -:104E80000A00002000000000000000000000000DEB -:104E90006370342E362E31360000000004061004F4 -:104EA0000000000000000000000000000000000002 -:104EB00000000000000000000000000000000000F2 -:104EC00000000000000000000000002000000000C2 -:104ED00000000000000000000000000000000000D2 -:104EE00000000000000000000000000000000000C2 -:104EF0000000000000000000000000010000002B86 -:104F00000000000010000003000000000000000D81 -:104F10000000000D3C020800244258A43C03080095 -:104F200024635F70AC4000000043202B1480FFFD21 -:104F3000244200043C1D080037BD7FFC03A0F02183 -:104F40003C100800261000803C1C0800279C58A438 -:104F50000E00019C000000000000000D27BDFFE8CE -:104F60003C096018AFBF00108D2C5000240DFF7F4E -:104F700024080031018D5824356A380C24070C00B0 -:104F80003C1A8000AD2A50003C04800AAF4800085B -:104F90003C1B8008AF4700240E000924AF8400109A -:104FA0000E0008E7000000000E00083400000000BA -:104FB0000E00125E000000003C0460168C850000AC -:104FC0003C06FFFF3C02535300A618241062003F2A -:104FD00034867C0094C201F2A780002C10400003AC -:104FE000A78000CC38581E1EA798002C94C201F848 -:104FF00010400004978300CC38591E1EA79900CC9E -:10500000978300CC2C7F006753E0000124030066E7 -:105010009784002C2C820401144000020060282197 -:10502000240404003C0760008CE904382403103C8D -:105030003128FFFF1103001730B9FFFF5720000C84 -:10504000A38000CE24020050A38200CE939F00CE06 -:1050500013E0000A8FBF001027BD0018A78000CC06 -:10506000A780002CA780003403E00008A78000E69A -:10507000939F00CE17E0FFF88FBF001027BD0018E8 -:10508000A78500CCA784002CA780003403E000088B -:10509000A78000E6A38000CE8CCB003C316A0001E3 -:1050A0001140000E0000000030A7FFFF10E0FFE6F7 -:1050B000240200508CCC00C83186000114C0FFE4EB -:1050C000939F00CE0A000072240200518C8F0004CE -:1050D0003C0E60000A00005501EE30218CEF0808FC -:1050E000240D5708000F740211CD000430B8FFFFE3 -:1050F000240500660A000073240404001700FFD48E -:10510000939F00CE0A000072240200508F86001088 -:105110003089FFFF000939408CC300103C08005063 -:1051200000E82025AF4300388CC500142742040056 -:10513000AF82001CAF45003CAF44003000000000CF -:10514000000000000000000000000000000000005F -:105150000000000000000000000000008F4B000075 -:10516000316A00201140FFFD0000000003E000084C -:10517000000000008F840010948A001A8C8700249D -:105180003149FFFF000940C000E83021AF46003C34 -:105190008C8500248F43003C00A310231840002975 -:1051A000000000008C8B0020256200013C0D0050A7 -:1051B00035AC0008AF420038AF4C003000000000B2 -:1051C00000000000000000000000000000000000DF -:1051D0000000000000000000000000008F4F0000F1 -:1051E00031EE002011C0FFFD000000008F4A0400D6 -:1051F0003C080020AC8A00108F490404AC890014DC -:10520000AF48003000000000948600189487001C0E -:1052100000C71821A48300189485001A24A2000155 -:10522000A482001A9498001A9499001E133800035F -:105230000000000003E000080000000003E0000898 -:10524000A480001A8C8200200A0000CC3C0D005083 -:105250000A0000BD000000003C0308008C63002031 -:105260008F82001827BDFFE810620008AFBF001052 -:105270000E0000F4AF8300183C0308008C6300208C -:1052800024040001106400048F8900108FBF0010F7 -:1052900003E0000827BD00188FBF00103C07601214 -:1052A000A520000A9528000A34E5001027BD001843 -:1052B0003106FFFF03E00008ACA600903C020800A6 -:1052C0008C42002027BDFFC8AFBF0034AFBE003006 -:1052D000AFB7002CAFB60028AFB50024AFB40020A4 -:1052E000AFB3001CAFB20018AFB1001410400050B3 -:1052F000AFB000108F840010948600069483000ADB -:1053000000C3282330B6FFFF12C0004A8FBF00340D -:1053100094890018948A000A012A40233102FFFF71 -:1053200002C2382B14E0000202C0202100402021DC -:105330002C8C0005158000020080A021241400049C -:105340000E0000A3028020218F8700100280982188 -:10535000AF80001494ED000A028088211280004E74 -:1053600031B2FFFF3C1770003C1540003C1E60004E -:105370008F8F001C8DEE000001D71824507500504F -:105380000220202102A3802B160000353C182000AB -:105390005078004702202021241000018F83001440 -:1053A00014600039029158230230F8230250C821BA -:1053B00033F1FFFF1620FFEE3332FFFF8F8700101F -:1053C0003C110020AF5100300000000094E6000ABC -:1053D0003C1E601237D5001002662821A4E5000AA1 -:1053E00094E2000A94F2000A94F400183057FFFF88 -:1053F0001292003BAEB700908CED00148CE40010CC -:105400000013714001AE4021000E5FC3010E502B0E -:10541000008B4821012A1821ACE80014ACE30010ED -:1054200002D3382330F6FFFF16C0FFB98F84001077 -:105430008FBF00348FBE00308FB7002C8FB600288E -:105440008FB500248FB400208FB3001C8FB20018DA -:105450008FB100148FB0001003E0000827BD0038A2 -:10546000107E001B000000001477FFCC2410000108 -:105470000E0015A9000000008F8300141060FFCB00 -:105480000230F823029158238F87001001702021E9 -:105490000A0001873093FFFF8F8300141460FFCB55 -:1054A0003C110020AF5100300A0001530000000001 -:1054B0000E00079B024028210A000147004080217E -:1054C0000E000341024028210A00014700408021CC -:1054D0000E001471022020210A00014700408021A3 -:1054E0000E0000BD000000000A00016902D338234D -:1054F00027BDFFE8AFB00010AFBF00140E000037AB -:10550000000000003C028000345000700A0001AA34 -:105510008E0600008F4F000039EE000131C20001FD -:10552000104000248F8600A88E0700003C0C080065 -:105530008D8C003C3C0908008D29003800E668236A -:10554000018D28210000502100AD302B012A40217F -:10555000010620213C010800AC25003CAF8700A8D3 -:105560003C010800AC2400380E0000F600000000EA -:105570003C0308008C6300701060FFE6006020218F -:105580003C0508008CA500683C0608008CC6006C31 -:105590000E001538000000003C010800AC2000702F -:1055A0008F4F000039EE000131C200011440FFDED0 -:1055B0008F8600A88E0A00008F8B00A83C0508008B -:1055C0008CA5003C3C0408008C840038014B482327 -:1055D00000A938210082182100E9402B0068102121 -:1055E0003C010800AC27003C3C010800AC2200381C -:1055F0008F5F01002419FF0024180C0003F92024F8 -:1056000010980012AF840000AF440020936D00009A -:10561000240C002031A600FF10CC0012240E0050F4 -:1056200010CE00043C194000AF5901380A0001A314 -:10563000000000000E0011D4000000003C194000E2 -:10564000AF5901380A0001A3000000000E00010F4D -:10565000000000003C194000AF5901380A0001A3C6 -:10566000000000008F58010000802821330F00FF48 -:1056700001E020210E0002EEAF8F00043C19400033 -:10568000AF5901380A0001A30000000000A4102B4C -:1056900024030001104000090000302100052840CB -:1056A00000A4102B04A00003000318405440FFFC8A -:1056B000000528405060000A0004182B0085382B94 -:1056C00054E000040003184200C330250085202365 -:1056D000000318421460FFF9000528420004182B4B -:1056E00003E0000800C310213084FFFF30A5FFFF56 -:1056F0008F4201B80440FFFE3C0740800087302500 -:105700003C031000AF400180AF450184AF460188E3 -:1057100003E00008AF4301B83084FFFF8F4201B8B7 -:105720000440FFFE3C0740388CA600000087282577 -:105730003C031000AF460180AF45018803E000083C -:10574000AF4301B88F8300388F8600301066000B9E -:10575000008040213C07080024E75A18000328C0B5 -:1057600000A710218C44000024630001108800056C -:105770003063000F5466FFFA000328C003E00008FE -:10578000000010213C07080024E75A1C00A7302124 -:1057900003E000088CC200003C039000346200016A -:1057A00000822025AF4400208F45002004A0FFFE8A -:1057B0000000000003E00008000000003C0380003F -:1057C000346200010082202503E00008AF4400207D -:1057D00027BDFFE0AFB100143091FFFFAFB0001064 -:1057E000AFBF00181220001500A080218CA500007A -:1057F00010A00013240400020E000C6B24060140CC -:10580000AE0000008F4201B80440000D00002821C6 -:105810003C064000022620258FBF00188FB10014DF -:105820008FB000103C03100027BD0020AF45018061 -:10583000AF44018803E00008AF4301B88CA5000025 -:105840008F4201B80440FFFE3C064000022620259E -:105850008FBF00188FB100148FB000103C031000F0 -:1058600027BD0020AF450180AF44018803E0000858 -:10587000AF4301B83086FFFF8F4201B80440FFFEFE -:105880003C0940068CA8000000C93825AF480180BB -:105890008CA400043C031000AF440184AF4701888E -:1058A00003E00008AF4301B827BDFFE0AFB0001030 -:1058B000AFBF0018AFB100149363003E0080802199 -:1058C0000080282130620040000020211040000F9D -:1058D0008E1100000E000860022020219367000056 -:1058E0002404005030E500FF50A400128E0F000089 -:1058F000022020218FBF00188FB100148FB000103C -:10590000A762013C0A00092027BD00200E00027D8D -:10591000000000000E0008600220202193670000B4 -:105920002404005030E500FF14A4FFF202202021DF -:105930008E0F00003C1008008E1000503C0D000C33 -:10594000240BFF8001F05021314E007F01DA6021ED -:10595000018D4021014B4824AF490028022020211D -:105960008FBF00188FB100148FB00010A50200D6B1 -:1059700027BD00200A000920AF8800D027BDFFE026 -:10598000AFBF0018AFB10014AFB0001093660001B4 -:10599000008080210E00024630D10004936400058F -:1059A000001029C2A765000034830040A3630005EE -:1059B0000E00024F020020210E00092202002021C9 -:1059C00024020001AF62000C02002821A76200102F -:1059D00024040002A762001224060140A7620014FA -:1059E0000E000C6BA76200161620000F8FBF001868 -:1059F000978C00343C0B08008D6B00782588FFFFE6 -:105A00003109FFFF256A0001012A382B10E000064A -:105A1000A78800343C0F6006240E001635ED0010F8 -:105A2000ADAE00508FBF00188FB100148FB00010C2 -:105A300003E0000827BD002027BDFFE0AFB1001440 -:105A4000AFBF0018AFB0001000A088211080000A7E -:105A50003C0360002402008010820012000000005D -:105A60000000000D8FBF00188FB100148FB0001020 -:105A700003E0000827BD00208C682BF80500FFFE1E -:105A800000000000AC712BC08FBF00188FB1001454 -:105A90008FB000103C09100027BD002003E0000873 -:105AA000AC692BF80E00024600A02021936500058A -:105AB000022020210E00024F30B000FF2403003EE0 -:105AC0001603FFE7000000008F4401780480FFFE0A -:105AD000240700073C061000AF510140022020219E -:105AE000A34701448FBF00188FB100148FB000107E -:105AF000AF4601780A0002BF27BD002027BDFFE89E -:105B0000AFBF0014AFB000108F50002000000000A5 -:105B10000E000922AF440020AF5000208FBF0014B8 -:105B20008FB0001003E0000827BD00183084FFFF8D -:105B30008F4201B80440FFFE3C0740350087302506 -:105B40003C031000AF450180AF400184AF4601889F -:105B500003E00008AF4301B83084FFFF8F4201B873 -:105B60000440FFFE3C074036008730253C03100010 -:105B7000AF450180AF400184AF46018803E00008D3 -:105B8000AF4301B827BDFFD0AFB3001C3093FFFF78 -:105B9000AFB50024AFB20018AFBF0028AFB40020EB -:105BA000AFB10014AFB0001030B5FFFF1260002796 -:105BB000000090218F90001C8E0300003C068000A6 -:105BC0002402004000033E0200032C0230E4007F68 -:105BD000006688241482001D30A500FF8F830028F2 -:105BE0002C68000A510000108F91001400035880A7 -:105BF0003C0C0800258C56CC016C50218D490000CE -:105C0000012000080000000002B218213065FFFFEB -:105C10000E00021A24040084162000028F90001C3B -:105C2000AF8000288F910014260C0020264B000125 -:105C3000018080213172FFFF16200004AF8C001C10 -:105C40000253402B1500FFDC000000000240102131 -:105C50008FBF00288FB500248FB400208FB3001CA5 -:105C60008FB200188FB100148FB0001003E000084D -:105C700027BD0030240D003414AD00F600000000F4 -:105C8000920B000E240A16803C07000CA36B002127 -:105C90009203000D0347F8213C066000A363002037 -:105CA000961100123C087FFF350CFFFFA771003CE6 -:105CB00096020010240B00053054FFFFAF740084DF -:105CC0008E19001CAF4A00288FF800008CCF444882 -:105CD0000319702601EE3021AF66004C8F69004C2D -:105CE00024CD00013C197F00AF6900508F64005043 -:105CF000AF640054AF660070AF6D00588F650058F8 -:105D000024040050AF65005CA3600023AF6C006406 -:105D1000A36B00378E030014AF6300488F710048F7 -:105D2000AF7100248E020018AF62006C9214000C58 -:105D3000A3740036936A003E355F0020A37F003EC7 -:105D40008F7800740319782435EE4000AF6E00742C -:105D500093700000320900FF112402332418FF80E1 -:105D60003C04080024845A980E00028A00000000B7 -:105D700024060004240700013C0408008C845A987F -:105D8000A366007DA36700058F4A01780540FFFEEA -:105D900024020002AF440140A34201448F90001C42 -:105DA0003C141000AF5401780A000369AF8000284A -:105DB0002CAD003751A0FF9C8F9100140005A080EE -:105DC0003C180800271856F4029878218DEE000040 -:105DD00001C00008000000002406000614A60011FF -:105DE000000000003C1F08008FFF5A9824040005A3 -:105DF000AF5F00208E190018AF7900188F78004C23 -:105E0000AF78001C8F6F0050122000C2AF6F00707F -:105E10000A000369AF840028240A000710AA00843E -:105E2000240300063C05080024A55A980E000254DD -:105E3000240400818F90001C0011102B0A000369BC -:105E4000AF820028240A000414AAFFF6240300509D -:105E50003C0E08008DCE5A98AF4E00208E090008E7 -:105E6000AF6900408E060008AF6600448E07000C44 -:105E7000AF6700488E040010AF64004C8E0D001018 -:105E8000AF6D00848E080014AF6800508E050018B6 -:105E9000AF6500548E0C001CAF6C0058936B000073 -:105EA000317400FF128301F5000000008F64004888 -:105EB0008F6600400086382304E000042404008C30 -:105EC0001620FFDE24020003240400823C050800A3 -:105ED00024A55A980E00027D000000008F90001C3F -:105EE000000010210A000369AF8200282409000580 -:105EF00014A9FFCC240520003C0A08008D4A5A98BA -:105F0000AF4A00208E1F0004AF7F005C921900088A -:105F100024100008A37900218F98001C930F00091A -:105F2000A36F00208F86001C90CE000A31C400FFB2 -:105F300010900010288300091460006C24020002F5 -:105F4000240800201088000B3405800028850021DB -:105F500014A0000824054000240D0040108D000509 -:105F60003C05000124070080108700023C05000268 -:105F7000240540008F6E00743C0FFF0001CF802489 -:105F800002054825AF69007490C4000BA36400812A -:105F90008F84001C9486000C10C0019B0000000040 -:105FA000948E000C241FFFBF24060004A76E003C43 -:105FB0009090000EA370003E8F89001C9124000F6A -:105FC000A364003F8F94001C8E8D00108F470074D7 -:105FD00001A72823AF6500608E880014AF680064B5 -:105FE000968C0018A76C0068968B001AA76B006A45 -:105FF0008E82001CAF62006C96830002A763013E94 -:10600000928A000EA36A003E9379003E033FC024AB -:106010001220016AA378003E8F90001C0A000369D9 -:10602000AF8600282414002214B4FF7E2403000746 -:106030003C0208008C425A981220000CAF4200200B -:106040000A000369AF830028240C003310AC00144D -:10605000240800283C05080024A55A980E000226B2 -:10606000240400810A0003EE8F90001C3C04080009 -:1060700024845A980E00028A00000000936B0000EE -:1060800024110050316300FF107101540000000022 -:106090008F90001C000018210A000369AF830028BC -:1060A0003C0508008CA55A9824040081AF450020C7 -:1060B000A36800343C05080024A55A980E00022667 -:1060C000000000008F90001C240200090A000369F0 -:1060D000AF82002802B288213225FFFF0E00021A8B -:1060E000240400840A0003698F90001C1082FFA121 -:1060F000240504002894000312800176240C000477 -:10610000240B0001548BFF9B240540000A00043D32 -:10611000240501003C04080024845A988F62004C36 -:106120000E00028A8F6300508F90001C0000202117 -:106130000A000369AF8400288E1000042404008A3A -:10614000AF500020936E000531C900021520016593 -:10615000020028219378002302002821330F002019 -:1061600015E001602404008D9362003F24190012A1 -:10617000305F00FF13F9015B240400810E0002462A -:106180000200202193740023240A0004020020212D -:1061900036830042A36300230E00024FA36A007DF2 -:1061A0008F4B01780560FFFE24050002AF500140CF -:1061B000A34501448F90001C3C0C1000AF4C0178AB -:1061C0000A0003EF0011102B8E1000042404008A33 -:1061D000AF500020936D000531A800021500001992 -:1061E000020028219367003F2414001230E400FFCE -:1061F0001094010100000000936E003F240600048B -:1062000031C900FF112600FC000000000E0002460C -:1062100002002021936200232419FFFE02002021A6 -:10622000345F0020A37F0023A374003F9378000510 -:10623000031978240E00024FA36F000502002821E5 -:10624000000020210E000336000000000A0003EECB -:106250008F90001C8E0500043C0F0008034F402166 -:10626000AF450020910E00002406005031C900FF08 -:106270001126017A240400888F5901B80720FFFEF7 -:106280003C0C400E008C58253C031000AF450180AB -:10629000AF400184AF4B0188AF4301B891020000C9 -:1062A000240AFF8024040004004AF825A11F0000EE -:1062B0000E000C6B240600300A0003EE8F90001CC9 -:1062C0008E04001C0E000231000000001040014C42 -:1062D000004048218F90001C240500898F4D01B893 -:1062E00005A0FFFE00000000AF4901808E0F001CDA -:1062F0003C1440010011702B00B448253C111000E3 -:10630000AF4F0184AF8E0028AF490188AF5101B86B -:106310000A00036A8F910014961900023C140800C9 -:1063200026945A9833380004130000F23C026000AF -:106330008E1F001C3C010800AC3F5A98AF5F002044 -:10634000920C0010240B0014318400FF148B011CEC -:106350000000000096090002312D000115A001B2D5 -:10636000000000008E020004AE8200083C0E08000F -:106370008DCE5AA011C001A8000000008F690074E2 -:106380003C0E800024040001012E6825AF6D0074CE -:10639000A3600005AF64000C3C0C08008D8C5AA073 -:1063A0008F88001CA7640010000C59C2A76400125B -:1063B000A7640014A7640016A76B00088D030008EB -:1063C00024040002AF63002C8D0A000CAF6A003079 -:1063D00091070010A36700348F82001C90450011C4 -:1063E000A36500358F86001C90D00012A370003684 -:1063F0008F9F001C93F90013A37900378F90001C26 -:1064000096180014A778003896140016A774003A5E -:106410008E0F0018AF6F00245620FE02AF840028B4 -:106420003C05080024A55A980E00025400002021C3 -:106430008F90001C0A0004AC000020218E0F000485 -:106440003C14080026945A983C010800AC2F5A9836 -:10645000AF4F0020920E000331C90004112000024A -:106460002402001224020006A362003F9203001BD4 -:10647000240AFFC03062003F004AF825A37F003E97 -:106480009219000333380001170000C1000000001A -:106490008E020008AE8200083C0208008C425AA01E -:1064A000104000C000000000000221C2A7640008E4 -:1064B0008E0D000C240B000124140014AF6D002C71 -:1064C0008E080010AF68003096050016A7650038EA -:1064D000960C0014A76C003AAF6B000CA76B001071 -:1064E000A76B0012A76B0014A76B0016122000EB1D -:1064F000A37400349206000330C700022CF00001A0 -:10650000260200088F90001C0A000369AF82002851 -:106510008E14000424030081AF54002093680023EC -:106520003105001010A000AC000000008F4401B83D -:106530000480FFFE3C06401F0011382B006610252A -:106540003C111000AF540180AF870028AF40018498 -:10655000AF420188AF5101B80A00036A8F9100145D -:106560008E0600043C19000803592021AF46002084 -:106570008E07000890980000240F0050331400FF8D -:10658000128F00A7240500888F4401B80480FFFE05 -:106590003C0D40090011602B00AD10253C1110008E -:1065A000AF460180AF8C0028AF470184AF4201881D -:1065B000AF5101B80A00036A8F9100143C0508002E -:1065C00024A55A980E00027D240400828F90001C9E -:1065D000000030210A000369AF8600283C0408004F -:1065E0008C845A980E0014F6000000008F90001C56 -:1065F0000A000486000018210E00033624040081DE -:106600000A0003EE8F90001C3C05080024A55A9850 -:106610000E00027D2404008B8F90001C0011302B93 -:106620000A000369AF8600283C1908008F395A9880 -:106630003C1F08008FFF005024CCFFFE033F782151 -:1066400001F87024AF4E00283C0408008C845A984E -:106650003C0908008D2900500089682131A5007F80 -:1066600000BA402101078021AE0600D8AF9000D0CB -:10667000AE0000DC0A0003B8AE0C0108AF60008475 -:106680003C0808008D085A983C0D08008DAD00505C -:106690002405FF803C02000C010D58210165602497 -:1066A000AF4C00288E0A00143174007F029A182122 -:1066B00000627821ADEA00D88E1F0014AF8F00D0A1 -:1066C000ADFF00DC8E1900102738FFFE0A00040B16 -:1066D000ADF80108548CFE27240540000A00043D53 -:1066E000240510000E00032B000000000A0003EE3A -:1066F0008F90001C8C46442C3C056C6234B0797041 -:106700003C010800AC205A9814D000082404000270 -:1067100097880034978A002C02802821010A382BA0 -:1067200010E0001124040092240400020E000C89E1 -:10673000240501403C010800AC225A98AF420020D9 -:106740003C0308008C635A98106000052404008301 -:106750000E000854000000001040000924040083CB -:106760003C05080024A55A980E00025400000000C1 -:106770008F90001C0011202B0A000369AF840028B1 -:106780000E000858000000000A0005308F90001C21 -:106790008E0400080E000231000000000A00058689 -:1067A000AE8200083C05080024A55A980E00022677 -:1067B000240400878F90001C0A0005A20011102BF2 -:1067C0000E00085C000000003C05080024A55A9853 -:1067D0000A00063A2404008B0E00024602802021A3 -:1067E0009370002302802021360D00100E00024F0E -:1067F000A36D00238F90001C0A0005AB0000182138 -:10680000240400040E000C89240500301440002AE2 -:10681000004048218F90001C0A00051724050083C2 -:106820009205000C30BF000113E0000300000000DF -:106830009602000EA482002C920A000C314800023D -:106840001100FF5100002821960B00128E03001446 -:10685000A48B001A0A0005C2AC83001C8F83003889 -:106860008F8700301067FE84000020213C0908005B -:1068700025295A1C000320C0008930218CD4000037 -:106880001285005E247800013303000F5467FFFA7D -:10689000000320C00A0004FE000020213C0508007F -:1068A00024A55A980E00027D240400828F90001CBB -:1068B0000A0005A2000010213C0B0008034B202118 -:1068C00024030050240A0001AF420020A0830000EE -:1068D000A08A00018F88001C91070004A08700187F -:1068E0008F82001C90450005A08500198F86001C32 -:1068F00090DF0006A09F001A8F99001C93380007B4 -:10690000A098001B8F94001C928F0008A08F001C81 -:106910008F90001C920E0009A08E001D8F8D001C10 -:1069200091AC000AA08C001E8F8B001C3C0C080050 -:10693000258C5A1C9163000B3C0B0800256B5A18E0 -:10694000A083001F8F8A001C9148000CA0880020A3 -:106950008F87001C90E5000DA08500218F82001C10 -:10696000240546469046000EA08600228F9F001CFC -:1069700093F9000FA09900238F98001C9314001026 -:10698000A09400248F8F001C91F00011A09000258E -:106990008F90001C8F8E00308F990038960D001458 -:1069A000000E18C025C80001A48D0028960A001604 -:1069B000006C3021006BF821A48A002A9607001889 -:1069C0003108000FA487002CA485002E8E02001C25 -:1069D000ACC90000AF88003011190003AFE200001D -:1069E0000A00051700002821250C00013184000F42 -:1069F000000028210A000517AF8400383C07080072 -:106A000024E75A180087802100002021ACC0000034 -:106A10000A0004FEAE0000003C05080024A55A98B8 -:106A20000A00063A240400878E0400040E00023196 -:106A3000000000000A00053BAE8200083084FFFF22 -:106A400030C600FF8F4201B80440FFFE000644003C -:106A5000010430253C07200000C720253C0310001E -:106A6000AF400180AF450184AF44018803E00008D6 -:106A7000AF4301B827BDFFE8AFB00010AFBF0014AF -:106A80003C076000240600021080000600A0802160 -:106A90000010102B8FBF00148FB0001003E000080F -:106AA00027BD00183C09600EAD2000348CE5201C89 -:106AB0008F82001C2408FFFC00A81824ACE3201CD3 -:106AC0000E0006EF8C45000C0010102B8FBF001439 -:106AD0008FB0001003E0000827BD00183C02600ED4 -:106AE0003447010024090018274A04000000000070 -:106AF00000000000000000003C06005034C302000B -:106B0000AF440038AF45003CAF430030014018218E -:106B10008F4B0000316800201100FFFD2406007F2C -:106B20002408FFFF8C6C000024C6FFFF24630004D0 -:106B3000ACEC000014C8FFFB24E7000400000000D8 -:106B400000000000000000003C0F0020AF4F0030AC -:106B50000000000024AD020001A5702B2529FFFFD5 -:106B6000008E20211520FFE101A0282103E000086C -:106B70000000000027BDFFE0AFB10014AFBF001858 -:106B8000AFB000103C05600E8CA20034008088215C -:106B9000144000063C0460008C87201C2408FFFC85 -:106BA00000E8302434C30001AC83201C8F8B001C10 -:106BB00024090001ACA90034956900028D65001418 -:106BC0008D70000C2D2400818D6700048D660008F7 -:106BD000108000078D6A00102D2C00041580000E17 -:106BE00030CE0007312D000311A0000B0000000083 -:106BF0002404008B020028210E0006EF2406000367 -:106C00000011102B8FBF00188FB100148FB000102F -:106C100003E0000827BD002015C0FFF62404008B08 -:106C20003C030020AF4300300000000024020001BC -:106C3000AF8200140000000000000000000000000F -:106C40003C1F0150013FC825253800033C0F600E52 -:106C5000AF47003800181882AF46003C35E8003CCA -:106C6000AF590030274704008F44000030860020D1 -:106C700010C0FFFD00000000106000082466FFFF48 -:106C80002403FFFF8CEB000024C6FFFF24E7000471 -:106C9000AD0B000014C3FFFB250800043C08600E88 -:106CA000AD090038000000000000000000000000F6 -:106CB0003C070020AF470030000000000E0007171F -:106CC0000140202102002821000020210E0006EFB3 -:106CD000240600030011102B8FBF00188FB1001481 -:106CE0008FB0001003E0000827BD002027BDFFD8AB -:106CF000AFB200183092FFFFAFB10014AFBF002059 -:106D0000AFB3001CAFB000101240002C000088216F -:106D10000A0007AF2413000150B3003C8CE5000CBF -:106D20000000000D262D000131B1FFFF24EC0020F2 -:106D30000232382B10E00021AF8C001C8F8200142F -:106D40001440001E8F87001C3C0670003C0320008E -:106D50008CE400000086282414A300188F85003CD2 -:106D6000000444023C0980000089802414A0FFEA4A -:106D7000310600FF2404000210C4001F28CA0003CB -:106D800011400016240B000314D3FFE7262D000149 -:106D9000020028210E0006FD240400018F87001C3C -:106DA000AF82003C262D000131B1FFFF24EC002012 -:106DB0000232382B14E0FFE1AF8C001C02201021BE -:106DC0008FBF00208FB3001C8FB200188FB100144A -:106DD0008FB0001003E0000827BD002814CBFFD2BD -:106DE000262D00010E00073D020020218F87001C88 -:106DF0000A0007C9AF82003C020028210E0006FDF0 -:106E0000000020210A0007C88F87001C0E0006EF33 -:106E1000240400841600FFC38F87001C0A0007A902 -:106E2000AF80003C3082FFFF1440000300001821B7 -:106E30000004240224030010308500FF14A0000584 -:106E40003087000F246600080004220230C300FFD0 -:106E50003087000F14E00005308900032468000427 -:106E600000042102310300FF3089000315200005D2 -:106E7000388B0001246A000200042082314300FFA5 -:106E8000388B00013164000110800002246C000185 -:106E9000318300FF03E0000800601021308BFFFF0A -:106EA000000B394230E600FF3C09080025295998BB -:106EB00000064080010960218D8700003164001FB9 -:106EC000240A0001008A180430A500FF00E32025F1 -:106ED00014A000020003102700E22024240F000168 -:106EE00000CF700401096821000E282714800005D6 -:106EF000ADA400008F86000C00A6102403E000085B -:106F0000AF82000C8F88000C01C8102503E0000838 -:106F1000AF82000C3C06001F3C0360003084FFFF82 -:106F200034C5FF8024020020AC602008AC60200C37 -:106F3000AC602010AC652014AC642018AC6220005A -:106F4000000000000000000003E000080000000056 -:106F500027BDFFE82402FFFFAFBF0010AF82000C87 -:106F6000000020213C06080024C659982405FFFF94 -:106F700024890001000440803124FFFF010618210C -:106F80002C87002014E0FFFAAC6500000E000825F5 -:106F900000002021240200013C04600024050020A0 -:106FA000AC822018AC85200000000000000000002A -:106FB00000000000244A00013142FFFF2C4604007B -:106FC00014C0FFF78FBF001003E0000827BD0018B2 -:106FD0008F8300082C62040003E00008384200019F -:106FE0008F8300082462000103E00008AF820008DC -:106FF0008F8300082462FFFF03E00008AF820008CF -:1070000027BDFFE0AFB10014AFBF0018AFB0001054 -:107010008F6B00303C06600000808821ACCB2008DC -:107020008F6A002C3C02800024030008ACCA200CAC -:107030009769003A9768003800092C003107FFFF74 -:1070400000A72025ACC42010ACC22014ACC3200083 -:107050000000000000000000000000003C03600091 -:107060008C6D200031AC00081580FFF90000000095 -:107070008C6E201405C00020000000000E0007E9FF -:107080008F84000C000240803C0908002529599893 -:10709000010938218CE400000E0007E9000281405C -:1070A000020220213090FFFF020020210E0008077D -:1070B000000028213C0C8000022C58253210FFFFD4 -:1070C0003C116000240A0020AE2B2014AE302018A2 -:1070D000AE2A2000000000000000000000000000B8 -:1070E000020010218FBF00188FB100148FB0001064 -:1070F00003E0000827BD00208C6620143C02001F1E -:107100003443FF803C1FFFE800C3C02437F9080068 -:1071100003198021001079C23C0C8000022C5825F4 -:1071200031F0FFFF3C116000240A0020AE2B201438 -:10713000AE302018AE2A2000000000000000000041 -:1071400000000000020010218FBF00188FB1001452 -:107150008FB0001003E0000827BD002027BDFFE826 -:10716000AFB000103402FFFF3090FFFFAFBF00143C -:1071700012020006020020210E0008250000000077 -:10718000020020210E000807240500018F8400085A -:107190008FBF00148FB000102483FFFF27BD00189D -:1071A00003E00008AF830008000439C230E6003F66 -:1071B00000043B4200071840240210002CC40020A9 -:1071C00024C8FFE0AF42002C2463000114800003B8 -:1071D00030A900FF00071840310600FF000360805F -:1071E00024080001019A58213C0A000E00C8280416 -:1071F000016A382111200005000530278CE90000C4 -:107200000125302503E00008ACE600008CEE00000C -:1072100001C6682403E00008ACED000027BDFFE8CC -:10722000AFBF0014AFB000103C0460008C850808AC -:107230003403F00030A2F0005043000624020001A5 -:107240008C8708083404E00030E6F00010C4001E0B -:1072500024020002AF8200403C1060003C0A0200A1 -:10726000AE0A0814240910003C08000E8E034400E6 -:1072700003482021AF49002C240501200E000CCF2B -:10728000000030218F830040106000043C02169102 -:10729000240B0001106B000E3C023D6C344F00903B -:1072A000AE0F44088FBF00148FB000103C0C60007C -:1072B000240E10003C0D020027BD0018AD8E4420A6 -:1072C00003E00008AD8D08100A0008F6AF8000400A -:1072D0003C0218DA344F0090AE0F44088FBF001400 -:1072E0008FB000103C0C6000240E10003C0D02001A -:1072F00027BD0018AD8E442003E00008AD8D0810B6 -:107300000A0008CA240500010A0008CA0000282152 -:107310003C08080025085DA42404FFFF0100182193 -:107320002402001E2442FFFFAC6400000441FFFD64 -:10733000246300043C07080024E75E208CE5FFFC82 -:107340002404001C24060001308A001F0146480462 -:1073500024840001000910272C8300201460FFFA08 -:1073600000A22824ACE5FFFC3C05666634A4616EEF -:107370003C06080024C65EE0AF840058AF88009C3D -:107380002404FFFF00C018212402001F2442FFFF35 -:10739000AC6400000441FFFD246300043C07666602 -:1073A0003C05080024A55EA0AF86004834E6616E67 -:1073B000AF8600982404FFFF00A018212402000FCC -:1073C0002442FFFFAC6400000441FFFD246300047D -:1073D0003C0B66663C06080024C65E203568616E7C -:1073E000AF8500A4AF8800702404FFFF00C01821FF -:1073F0002402001F2442FFFFAC6400000441FFFD93 -:10740000246300043C0D66663C0A0800254A5F6060 -:1074100035AC616EAF860090AF8C005C2404FFFF3A -:1074200001401821240200032442FFFFAC64000045 -:107430000441FFFD246300043C09080025295F7016 -:107440008D27FFFC24040006240500013099001F4D -:107450000325C00424840001001878272C8E002006 -:1074600015C0FFFA00EF3824AD27FFFC3C09666623 -:1074700024030400240403DC24050200240600661F -:107480003522616E3C08080025085AA4AF820074BA -:10749000AF830044AF83006CAF830050AF830084A0 -:1074A000AF8A008CAF840064AF85004CAF86005477 -:1074B000AF840078AF850060AF860080010018219E -:1074C000240200022442FFFFAC6000000441FFFDE3 -:1074D00024630004240400032403000C3C0A080075 -:1074E000254A5AB0AF8A00680A00099D2405FFFFAB -:1074F0000004188024840001006858212C8700C0F3 -:1075000014E0FFFBAD6500003C0E666635CD616E94 -:10751000240C17A024081800AF8D0088AF8C0094AD -:1075200003E00008AF88007C2484007F000421C2AF -:1075300000004021000030210000382100002821F7 -:107540000A0009B4AF8400A01060000624E700011F -:1075500000C4302124A500012CC20BF51440FFFA11 -:107560002CA300663C09080025295F600120182132 -:10757000240200032442FFFFAC6000000441FFFD31 -:107580002463000410E0001A24E3FFFF00032942F3 -:1075900010A0000A000020212406FFFF3C03080081 -:1075A00024635F60248400010085502BAC660000DA -:1075B000250800011540FFFB2463000430E2001F92 -:1075C0001040000800086880240C0001004C3804BA -:1075D000000858800169282124E6FFFF03E0000825 -:1075E000ACA6000001A940212409FFFFAD0900005D -:1075F00003E0000800000000AF4400283C04000C39 -:1076000003442021000528820A000CCF000030210D -:10761000000421803C036000AC64100800000000FE -:1076200000052980AC65100C0000000003E0000894 -:107630008C62100C27BDFFE800802821240400384C -:10764000AFBF00140E0009E4AFB0001024040E0018 -:10765000AF4400283C10000C0350202124050010EA -:107660000E000CCF0000302103501021AC40000070 -:10767000AC400004240400388FBF00148FB0001009 -:1076800024053FFF27BD00180A0009E48C430000D1 -:10769000000421803C036000AC641008000000007E -:1076A0008C62100C03E000080002118227BDFFC8A5 -:1076B000AFB400208F940068AFBE0030AFB7002C8D -:1076C000AFB600280000B8210080B021241E00C001 -:1076D000AFBF0034AFB50024AFB3001CAFB2001889 -:1076E000AFB10014AFB000100A000A21AFA5003CF2 -:1076F000504000018F94006827DEFFFF13C0002870 -:10770000269400048E9200003C03080024635DA0D0 -:107710001240FFF70283102B3C04080024845AA473 -:10772000028410230002A8C0000098210A000A3039 -:1077300024110001001188401220002600000000E2 -:1077400002B38021025128240200202110A0FFF959 -:10775000267300010E0009ED0000000000166840CD -:1077600032EC000101AC20210E0009E402002821C6 -:107770008F89009426F700018FA6003C3AEB0001A8 -:10778000316A00012528FFFF0011382702CAB02105 -:10779000AF88009416E6FFE702479024AE920000FF -:1077A00002E010218FBF00348FBE00308FB7002C55 -:1077B0008FB600288FB500248FB400208FB3001C33 -:1077C0008FB200188FB100148FB0001003E00008D2 -:1077D00027BD00383C0E080025CE5DA0028E102B80 -:1077E0000A000A1CAE92000027BDFFD8AFB10014FA -:1077F000AFB00010AFBF0020AFB3001CAFB2001895 -:1078000000A0882110A0001F000480403C13080045 -:1078100026735AA40A000A692412000112200019D2 -:10782000261000010E000A0402002021000231424D -:107830002444FFA0000618803045001F2C8217A1A9 -:10784000007318212631FFFF1040FFF400B230040E -:107850008C6900000200202124053FFF01264024FE -:107860001500FFEE012638250E0009E4AC67000084 -:107870008F8A009426100001254700011620FFE999 -:10788000AF8700948FBF00208FB3001C8FB2001809 -:107890008FB100148FB0001003E0000827BD00284E -:1078A0008F85009C00805821000040210000482165 -:1078B000240A001F3C0C0800258C5E1C3C0D0800AF -:1078C00025AD5DA48CA6000050C00014000040212E -:1078D00000AD1023000238C0240300010A000AA2F0 -:1078E000000020211500000300E41021244820247A -:1078F0000000482125290001512B00132506DFDC5B -:10790000106000062484000100C3702415C0FFF538 -:10791000000318400A000AA00000402110AC002615 -:1079200024A3000400602821254AFFFF1540FFE53D -:10793000AF85009C512B00042506DFDC00004021B0 -:1079400003E00008010010210006614230C5001F5D -:10795000000C50803C07080024E75DA424040001CB -:10796000014730211120000F00A420043C0508002D -:1079700024A55E20148000052529FFFF24C60004ED -:1079800010C5001100000000240400018CCF00008D -:107990000004C0270004204001F868241520FFF5EA -:1079A000ACCD00008F99007801001021032B4823F3 -:1079B00003E00008AF8900783C05080024A55DA419 -:1079C0000A000AAA000040213C06080024C65DA463 -:1079D0000A000AC324040001308800FF24020002C8 -:1079E0001102000A240300031103005C8F8900A424 -:1079F000240400041104005F24050005110500673C -:107A00000000182103E00008006010218F89004861 -:107A10003C0C0800258C5EE03C04080024845F6078 -:107A2000240300201060000F00005821240D0002E4 -:107A3000240E00033C0F080025EF5EE08D270000B8 -:107A400014E0000B30F9FFFF252900040124C02BAE -:107A500053000001018048212463FFFF5460FFF8B8 -:107A60008D2700000160182103E00008006010214C -:107A7000132000323C0500FF30E200FF00403021BF -:107A80001040004200005021240500010000202188 -:107A90000005C84000A6C02417000003332500FFDE -:107AA00014A0FFFB24840001012CC023001828C06F -:107AB00000AA6021008C50213144001F240C0001D9 -:107AC000008C18040003102700E23024110D00413F -:107AD000AD260000110E004C000A1840110D0036B2 -:107AE0008F87006C510E00568F8C0060240D0004AF -:107AF000110D005A8F8E0084240E0005150EFFDA3A -:107B000001601821240B14301140000600001821D8 -:107B10008F8400A024630001006A402B1500FFFD44 -:107B2000016458218F8A0080AF89008C0160182180 -:107B30002549FFFF0A000AFAAF89008000E52024EA -:107B4000000736021080FFD0240A001800075402F4 -:107B5000314600FF0A000B02240A00103C0C08000A -:107B6000258C5EA03C04080024845EE00A000AE93B -:107B7000240300103C0C0800258C5E203C04080007 -:107B800024845EA00A000AE88F89009000071A0288 -:107B9000306600FF0A000B02240A00088F89008C5F -:107BA0003C0C0800258C5F603C04080024845F7056 -:107BB0000A000AE924030004000A4080250B003073 -:107BC00024E6FFFF01601821AF8900480A000AFA85 -:107BD000AF86006C000AC982001978803C07080053 -:107BE00024E75EA001E72021000A18428C8F0000E4 -:107BF0003079001F032C38040007C02701F86024E7 -:107C00000A000B17AC8C00000003314200062880EC -:107C100000AF28213062001F8CB8000024630001EF -:107C2000004CC804000321420019382700041080CA -:107C300003073024004F20210A000B5BACA6000094 -:107C4000000A68C025AB0032258AFFFF01601821B9 -:107C5000AF8900A40A000AFAAF8A0060254B1030F1 -:107C6000AF8900900160182125C9FFFF0A000AFAB8 -:107C7000AF890084308600072CC200061040001433 -:107C800000000000000640803C030800246357D039 -:107C9000010338218CE4000000800008000000008F -:107CA0002409000310A9000E00000000240A0005AA -:107CB00010AA000B00000000240B000110AB00080C -:107CC000000000008F8C00A010AC00050000000038 -:107CD00003E00008000010210A000A8800A020210B -:107CE0000A000AD600C0202127BDFFE8308400FF2B -:107CF000240300021083000BAFBF00102406000312 -:107D00001086003A2408000410880068240E00053C -:107D1000108E007F2CAF14308FBF001003E00008DE -:107D200027BD00182CA200301440FFFC8FBF0010AC -:107D300024A5FFD0000531C2000668803C0708007A -:107D400024E75EE001A730218CC9000000052882ED -:107D500030AC001F240B0001018B50048F840048BD -:107D6000012A4025ACC800008C830000506000014F -:107D7000AF8600488F98006C30AE000124A6FFFF4C -:107D8000270F000115C00002AF8F006C24A6000170 -:107D90000006414200082080008718218C790000ED -:107DA00030C2001F240600010046F804033F3824B7 -:107DB00010E0FFDA8FBF00100005C182001870804C -:107DC0003C0F080025EF5EA001CF48218D2B00005D -:107DD0000005684231A5001F00A66004016C502513 -:107DE00027BD001803E00008AD2A00002CA70030D2 -:107DF00014E0FFCA8FBF001030B900071723FFC778 -:107E000024A8FFCE00086A02000D60803C0B080029 -:107E1000256B5EA0018B30218CC40000000828C2B5 -:107E200030AA001F24080001014848048F8200A4E2 -:107E300000891825ACC300008C5F000053E00001EE -:107E4000AF8600A400057040000E7942000F288024 -:107E50003C04080024845EE000A418218C6B000020 -:107E600025DF000131CD001F001F514201A8600431 -:107E7000016C4825000A1080AC69000000442821EC -:107E80008CA600008F98006033F9001F8FBF001090 -:107E90000328380400C77825270E000127BD0018E5 -:107EA000ACAF000003E00008AF8E006024A5EFD067 -:107EB0002CB804001300FF998FBF00100005314259 -:107EC000000658803C0A0800254A5E20016A3021DD -:107ED0008CC4000030A3001F2409000100691004B5 -:107EE0008F9900900082F825ACDF00008F270000FA -:107EF00050E00001AF8600908F8D00848FBF00108E -:107F000027BD001825AC000103E00008AF8C0084F9 -:107F100015E0FF828FBF00108F8600A00006104082 -:107F20000046F821001F210003E4C8210019384051 -:107F300024F8143000B8402B1100FF788FBF0010D8 -:107F400024A4EBD00E00020300C0282100027942D5 -:107F5000000F70803C0D080025AD5F6001CD202131 -:107F60008C8B0000304C001F240600010186180491 -:107F70008F89008C01635025AC8A00008D2500009C -:107F800050A00001AF84008C8F9800808FBF00103C -:107F900027BD00182708000103E00008AF88008013 -:107FA00030A500072403000310A3001028A200043A -:107FB00014400008240700022403000410A3001545 -:107FC0002408000510A8000F8F8500A003E000081A -:107FD0000000000014A7FFFD0080282114C3FFFB50 -:107FE000240400020A000B9A000000002409000586 -:107FF0000080282110C9FFFB2404000303E00008CF -:108000000000000014C5FFF1008028210A000B9A2F -:1080100024040005240A00010080282110CAFFF171 -:108020002404000403E000080000000027BDFFE076 -:10803000AFB00010000581C22603FFD024C5003F69 -:108040002C6223D024C6007FAFB20018AFB1001459 -:10805000AFBF001C309100FF000691C200052982CD -:1080600002002021104000082403FFFF0E000A5ADE -:108070000000000002002021022028210E000C48F0 -:1080800002403021000018218FBF001C8FB2001861 -:108090008FB100148FB000100060102103E00008C1 -:1080A00027BD002027BDFFD824A2007FAFB3001C4E -:1080B000AFB20018000299C2309200FF24A3003F23 -:1080C0000240202102602821AFB10014AFB000109F -:1080D000AFBF00200E000B7D00038982004080218D -:1080E000004020210220282114400009000018210E -:1080F0008FBF00208FB3001C8FB200188FB1001407 -:108100008FB000100060102103E0000827BD002898 -:108110000E000A0B00000000004028210200202170 -:108120001051FFF3001019C00E000A5A00000000A1 -:1081300002002021024028210E000C48026030215C -:108140008FBF00208FB3001C8FB200188FB10014B6 -:108150008FB00010000018210060102103E000081B -:1081600027BD00283084FFFF30A5FFFF10800007E7 -:10817000000018213082000110400002000420425B -:10818000006518211480FFFB0005284003E000086B -:108190000060102110C00007000000008CA2000049 -:1081A00024C6FFFF24A50004AC82000014C0FFFB1E -:1081B0002484000403E000080000000010A0000870 -:1081C00024A3FFFFAC8600000000000000000000B8 -:1081D0002402FFFF2463FFFF1462FFFA24840004DB -:1081E00003E000080000000030A5FFFF8F4201B847 -:1081F0000440FFFE3C07601500A730253C0310003B -:10820000AF440180AF400184AF46018803E000081D -:10821000AF4301B88F8500D02C8640000080182124 -:108220008CA700840087102B144000100000000071 -:108230008CA800842D06400050C0000F240340008D -:108240008CAA0084008A482B512000018CA3008452 -:1082500000035A42000B20803C05080024A558204A -:108260000085182103E000088C62000014C0FFF4B0 -:10827000000000002403400000035A42000B20804D -:108280003C05080024A558200085182103E00008BB -:108290008C6200008F8300D0906600D024C500015E -:1082A000A06500D08F8500D0906400D090A200D24D -:1082B0001044001700000000936C00788F8B00BC06 -:1082C000318A00FFA16A000C25490001938700C490 -:1082D000312200FF3048007F1107000B00026827A1 -:1082E000A36200788F4E017805C0FFFE8F9900B021 -:1082F000241800023C0F1000AF590140A35801445C -:1083000003E00008AF4F01780A000D1831A2008089 -:10831000A0A000D00A000D0E000000008F8700D042 -:1083200027BDFFC8AFBF0030AFB7002CAFB60028E5 -:10833000AFB50024AFB40020AFB3001CAFB200183B -:10834000AFB10014AFB0001094E300E094E200E29B -:10835000104300D72405FFFF3C047FFF3497FFFF45 -:108360002415FF800A000DFF3C16000E108A00D174 -:108370008FBF00308F9100B03C1808008F18005C50 -:10838000001230C0001291400311702101D57824F1 -:10839000AF4F002C94EC00E231CD007F01BA5821A0 -:1083A000318A7FFF01764821000A804002091021AE -:1083B000945300003C0808008D0800580246C02174 -:1083C00032733FFF0013198001032021022428216A -:1083D00030BF007F03FAC82100B5A024AF54002CA1 -:1083E0000336A0218E8700108E8F0030037858212D -:1083F000256D008800EF7023240C0002AE8E001063 -:10840000AF8D00ACA16C0088976A003C8E84003070 -:108410008F9100AC0E000CE53150FFFF00024B8045 -:10842000020940253C02420001022025AE2400043E -:108430008E8300048F8D00AC8E860000240E000811 -:10844000ADA3001CADA60018ADA0000CADA000109F -:10845000929F000A33F900FFA5B900149685000821 -:108460003C1F000CA5A500169298000A331100FFCE -:10847000A5B100209690000824180005A5B00022A0 -:10848000ADA00024928F000B2410C00031E700FF44 -:10849000A5A70002A1AE00018E8C00308F8B00AC2E -:1084A0008F8400B0AD6C00083C0A08008D4A00546F -:1084B0000144482101354024AF4800283C0208000F -:1084C0008C4200540044302130C3007F007AC82120 -:1084D000033F282102458821AF9100BCAF8500C031 -:1084E000A23800008F8A00BC2403FFBF2418FFDFDE -:1084F000954F000201F0382400F37025A54E0002CC -:10850000914D000231AC003F358B0040A14B000281 -:108510008F8600BC8F8900D0ACC000048D28007C01 -:108520003C098000ACC8000890C4000D3082007F78 -:10853000A0C2000D8F8500BC90BF000D03E3C824CE -:10854000A0B9000D8F9100BC9233000D02789024E9 -:10855000A232000D8E9000348F8B00BCAD700010E5 -:108560008E87002C8E8F003000EF7023AD6E0014CC -:10857000916D001831AC007FA16C00188F9F00BC7A -:108580008E8A00308FE8001801572024010930241A -:1085900000C41025AFE200189283000AA3E3001C78 -:1085A000969900088F8500BC8F9800D0A4B9001E52 -:1085B0008E9000308E8400300E0002038F05008400 -:1085C0008F8500D0000291400002990090AF00BC5E -:1085D000025388210040302131E7000210E00003FF -:1085E00002118021000290800212802190B900BC0B -:1085F0003327000410E000020006F880021F8021EB -:108600008E9800308F8B00BC24068000330F00034F -:10861000000F702331CD0003020D6021AD6C00040A -:1086200094A400E294AA00E294B000E231497FFFF2 -:108630002522000130537FFF0206182400734025D5 -:10864000A4A800E294A400E23C1408008E94006008 -:1086500030917FFF12340022000000000E000D0553 -:10866000000000008F8700D00000282194F300E074 -:1086700094F000E21213000F8FBF003090E900D099 -:1086800090E800D1313200FF310400FF0244302B6A -:1086900014C0FF36264A000190EE00D2264B00019E -:1086A00031CD00FF008D6021158BFF338F9100B01D -:1086B0008FBF00308FB7002C8FB600288FB50024F5 -:1086C0008FB400208FB3001C8FB200188FB100143C -:1086D0008FB0001000A0102103E0000827BD003873 -:1086E00094A300E200664024A4A800E290A400E263 -:1086F00090B900E2309100FF0011A1C20014F827E8 -:10870000001F39C03332007F024730250A000DF7C1 -:10871000A0A600E23084FFFF30A5FFFFAF440018A1 -:10872000AF45001C03E000088F42001427BDFFB8CE -:10873000AFB000208F9000D03084FFFFAFA40010B6 -:10874000AFBF0044AFBE0040AFB7003CAFB600388B -:10875000AFB50034AFB40030AFB3002CAFB20028D7 -:10876000AFB10024A7A00018920600D1920500D056 -:1087700030C400FF30A300FF0064102B1040012222 -:10878000AFA00014920900D08FB50010312800FF6F -:108790000088382324F4FFFF0014882B0015982B41 -:1087A00002339024524001268FB40014961E00120A -:1087B000961F00108FB7001003DFC82300171400A6 -:1087C0000019C400000224030018140302E2B02AB6 -:1087D00052C00001004020210284282B10A000027A -:1087E000008018210280182100033C0000071C03B0 -:1087F0003064FFFF2C86000914C000020060B8211D -:10880000241700088E0A0008001769808E09000CE2 -:1088100031ABFFFF3C0C0010016C402527520400D7 -:10882000AF4A0038AF9200B8AF49003CAF480030C3 -:108830000000000000000000000000000000000038 -:108840000000000000000000000000000000000028 -:108850008F4F000031EE002011C0FFFD0017982A55 -:10886000027110240A000E920000B02155E00101AF -:108870009258000131130080126001CF01202021A5 -:108880009655001232A5FFFF0E000CDAA7B50018AE -:108890008F9000D00291A02326C800018F9100B8CC -:1088A0000008B4000016B403262C004002D7782A32 -:1088B0000014882B240B00010180902101F1102469 -:1088C000AF8C00B8AFAB0014104001BC8F8900B072 -:1088D0003C0C08008D8C0054240BFF80921E00D0AD -:1088E00001895021014B2824921900D0AF4500285E -:1088F0008E4700103C0808008D0800583C180800FE -:108900008F18005430E33FFF000321800104302121 -:10891000012658212402FF800162F824920C00D025 -:10892000AF5F002C9248000033D100FF333500FFC9 -:108930000309982100117140001578C0326D007F45 -:1089400001CF382101BA2821318300FF3164007F33 -:108950003C0A000C00AA88210367F0210003314083 -:10896000009A10213108003F3C1F000E00D1C021A9 -:10897000005F982127D900882D150008AF9100C00D -:10898000AF9900ACAF9800BCAF9300B412A0018ABD -:1089900000008821240E0001010E4004310D005D0D -:1089A00011A0FFB2310F00028E4A00283C03008064 -:1089B0003C04FFEFAE6A00008E450024A260000A6E -:1089C0003488FFFFAE6500049247002C3C1FFF9FD8 -:1089D00037FEFFFFA267000C8E62000C3C180040BF -:1089E000A267000B0043302500C8C824033E88243A -:1089F0000238A825AE75000C8E490004AE60001840 -:108A00003C0F00FFAE6900148E4D002C35EEFFFFC9 -:108A10008F8B00B001AE6024AE6C00108E47000852 -:108A2000A660000896450012AE6700208E42000C3A -:108A300030B03FFF00105180AE6200248E5E001403 -:108A4000014B182130A40001AE7E00288E59001879 -:108A5000000331C200044380AE79002C8E51001C0B -:108A600000C8F821A67F001CAE71003096580002A5 -:108A70008E550020A678001EAE7500349249003352 -:108A80003130000456000005925000008F8C00D059 -:108A90008D8B007CAE6B0030925000008F8F00BC3D -:108AA000A1F00000924E003331CD000251A000072A -:108AB000925E00018F8900BC2418FF809131000074 -:108AC0000311A825A1350000925E00018F9900BC1A -:108AD0002409FFBF240BFFDFA33E00018F9500BCDC -:108AE00092B8000D3311007FA2B1000D8F8E00BC33 -:108AF00091D0000D02097824A1CF000D8F8800BC11 -:108B00008E6D0014910A000D2DAC0001000C29405F -:108B1000014B382400E51825A103000D96420012F0 -:108B20008F8800BC8F8700D0A50200028E4500040C -:108B300090FF00BC30A400030004302330DE0003AB -:108B400000BE102133F90002172000022444003433 -:108B50002444003090E200BC00A2302430DF000446 -:108B600017E0000224830004008018218F8F00ACDE -:108B700024090002AD030004A1E90000924E003F69 -:108B80008F8D00ACA1AE00018F9500AC924C003FE0 -:108B90008E440004A6AC0002976B003C0E000CE56E -:108BA0003170FFFF00025380020A38253C05420065 -:108BB00000E51825AEA300048F8600AC8E4800386F -:108BC000ACC800188E440034ACC4001CACC0000C0F -:108BD000ACC00010A4C00014A4C00016A4C00020A3 -:108BE000A4C00022ACC000248E6400145080000198 -:108BF00024040001ACC400080E000D05241100017E -:108C00000A000E858F9000D0920F00D2920E00D0F5 -:108C10008FB5001031EB00FF31CD00FF008D6023D8 -:108C2000016C50212554FFFF0014882B0015982B50 -:108C3000023390241640FEDD000000008FB40014C3 -:108C40008FBF00448FBE00403A8200018FB7003CC6 -:108C50008FB600388FB500348FB400308FB3002C3E -:108C60008FB200288FB100248FB0002003E00008ED -:108C700027BD004833110020122000EE241500010A -:108C8000921E00BC241F00010000A82133D900015E -:108C90001320000DAFBF001C8E4400148E0800840A -:108CA0000088102B14400002008030218E060084C2 -:108CB0008E03006400C3A82B16A0000200C0202170 -:108CC0008E0400640080A8218E4700148E05006485 -:108CD00000E5302B14C0000200E020218E04006467 -:108CE0000095F02313C000048FAC001C240A00027E -:108CF000AFAA001C8FAC001C028C582B156000A87A -:108D0000000018218E4F00388E6D000C3C0E008044 -:108D1000AE6F00008E4A00343C10FF9F01AE582514 -:108D2000AE6A00049246003F360CFFFF016C382407 -:108D30003C0500203C03FFEFA266000B00E5102578 -:108D40003468FFFF8F8700B80048F8243C0400080F -:108D500003E4C825AE79000C8CF80014AE6000184E -:108D600002BE7821AE7800148CF10018AE71001CA0 -:108D70008CE90008AE6900248CEE000CAE6F002C6C -:108D8000AE600028AE6E0020A6600038A660003AF3 -:108D90008CED001401B58023021E902312400011B7 -:108DA000AE72001090EA003D8E6500048E640000F3 -:108DB000000A310000A6C821000010210326402B24 -:108DC0000082F82103E8C021AE790004AE780000EB -:108DD00090F1003DA271000A8F8900B8953200061B -:108DE000A67200088F9800AC2419000202A020216E -:108DF000A31900009769003C8F9200AC0E000CE5AF -:108E00003131FFFF00027B808F8500B8022F68257B -:108E10003C0E420001AE8025AE5000048F8400ACB1 -:108E20008CAC0038AC8C00188CAB0034AC8B001CC4 -:108E3000AC80000CAC800010A4800014A48000164C -:108E4000A4800020A4800022AC80002490A7003FD2 -:108E5000A487000212A001342403000153C00002C1 -:108E600090A2003D90A2003E24480001A08800018D -:108E70008F9F00ACAFF500088F8300D0240700342B -:108E8000906600BC30C5000250A0000124070030ED -:108E90008F9200B88F8A00BC906D00BC924B00008E -:108EA0002412C00032A50003A14B00008F8600B839 -:108EB0008F8800BC2402000490C4000100451823E0 -:108EC00030790003A10400018F8A00BC8F9F00B895 -:108ED00000F538219558000297E9001200F9382171 -:108EE00003128824312F3FFF022F7025A54E000268 -:108EF0009150000231A80004320C003F358B004035 -:108F0000A14B000212A000028F8500BC00E83821AE -:108F10008F8E00D0ACA70004240BFFBF8DCD007C4A -:108F20002EA400012403FFDFACAD000890B0000DBB -:108F300000044140320C007FA0AC000D8F8600BCC5 -:108F400090CA000D014B1024A0C2000D8F8700BCF9 -:108F500090E5000D00A3F82403E8C825A0F9000D52 -:108F60008F9100B88F8D00BC8E380020ADB80010F6 -:108F70008E290024ADA900148E2F0028ADAF001853 -:108F80008E2E002C0E000D05ADAE001C8FB0001C07 -:108F9000240C0002120C00ED8F9000D08FA3001C57 -:108FA00000608821146000020060A8210000A02158 -:108FB00056A0FE390291A0230014882B8FAE00101A -:108FC000960700103C0A002001D6F02302C7C021FA -:108FD00033D2FFFFA6180010AFB20010AF4A003026 -:108FE0000000000096170010961300121277008EF2 -:108FF000001641808E16000C8E0F0008000817C363 -:1090000002C8282100A8582B01E2A82102AB182190 -:10901000AE05000CAE0300088FB300100013B82B90 -:10902000023780241200FF058F9000D00A000E4BFB -:10903000000000008E480038A6600008240F0003DE -:10904000AE6800008E4C0034A260000A8F9000B819 -:10905000AE6C00043C050080920B003FA26F000C38 -:109060008E62000C3C11FF9FA26B000B004568252F -:109070003623FFFF3C04FFEF8F8C00B801A33024A0 -:10908000349FFFFF00DFC824AE79000C8D890014E7 -:10909000959E00128F9800B0AE6900108D8E00145E -:1090A000AE600018AE600020AE6E0014AE6000240A -:1090B0008D87001833CE3FFF000E5180AE67002829 -:1090C0008D8800080158902133D00001AE6800302F -:1090D0008D91000C8F8D00AC001259C200107B8066 -:1090E000016F282124020002A665001CA66000363C -:1090F000AE71002CA1A200009763003C8F9800ACD9 -:109100003C044200307FFFFF03E43025AF0600043B -:109110008F9900B824070001240BC0008F3300385A -:1091200024060034AF1300188F290034AF09001C47 -:10913000AF00000CAF000010A7000014A70000163D -:10914000A7000020A7000022AF000024A7150002FE -:10915000A30700018F8A00AC8F9E00B88F8C00BCE3 -:10916000AD55000893C80000A18800008F9200B898 -:109170008F8F00BC92500001A1F000018F8400BCD1 -:1091800094910002022B282400AE1025A482000234 -:10919000908D000231A3003FA08300028F8300D096 -:1091A0008F8400BC907F00BC33F30002526000014A -:1091B00024060030AC8600048C65007C240DFFBFC3 -:1091C00002A08821AC8500089082000D3043007F0A -:1091D000A083000D8F8600BC90C4000D008DF82484 -:1091E000A0DF000D8F8E00BC91D9000D3729002023 -:1091F000A1C9000D8F9E00B88F9300BC8FC70020BF -:10920000AE6700108FD80024AE7800148FCA0028F3 -:10921000AE6A00188FD2002C0E000D05AE72001C35 -:109220000A00104C8F9000D0960200148E040004A7 -:109230003043FFFF000368C0008DF821AF5F003CA2 -:109240008E1900048F46003C032648231920003C59 -:10925000000000008E05000024A200013C0B00105D -:1092600035750008AF420038AF55003000000000EF -:1092700000000000000000000000000000000000EE -:109280000000000000000000000000008F4C000003 -:10929000318F002011E0FFFD000000008F5304001B -:1092A0003C080020AE1300088F570404AE17000CD2 -:1092B000AF480030000000003C0608008CC60044A7 -:1092C0002416000110D600BB000000009619001201 -:1092D0003C0508008CA5004000B94821A6090012F1 -:1092E000960E001425C70001A60700149618001456 -:1092F0003304FFFF5486FF498FB30010A60000140B -:109300000E000E2530A5FFFF3C0408008C840024CD -:10931000961F00120044682303ED3023A6060012B6 -:109320000A0010678FB30010A08300018F8200AC89 -:1093300024040001AC4400080A000FFF8F8300D012 -:109340008E0200000A0010F83C0B00108F9F00C036 -:109350008FB8001C920F00D0920B00D0920D00D05D -:1093600031F100FF316E00FF000E28C000111140E6 -:109370000045182131A600FF036350210006C940B3 -:10938000033F382125490088AF8900ACAF8700BC76 -:10939000A15800889768003C03C020218F9100AC41 -:1093A0000E000CE53110FFFF00026380020C7825EF -:1093B0003C0442008F8C00B801E45825AE2B000419 -:1093C0008D9100388F8B00AC00006821000D1100DA -:1093D000AD7100188D8E00343C087FFF3504FFFF0F -:1093E000AD6E001C9183003E8D65001C8D790018C8 -:1093F000000331000003870200A6C0210050F825B9 -:109400000306482B033F382100E95021AD78001CAA -:10941000AD6A0018AD60000CAD600010918F003E89 -:109420002405000503C45024A56F00149591000481 -:1094300003C02021A5710016918E003EA56E00206C -:10944000958D0004A56D0022AD6000249190003F31 -:10945000A57000029182003D24430001A163000138 -:109460008F8600AC8F9F00BCACDE0008A3E5000037 -:109470008F9000BC8F9900B82405FFBF96070002AB -:10948000973800120247782433093FFF01E9882505 -:10949000A6110002921200022418FFDF324E003F94 -:1094A00035CD0040A20D00028F8600BC8F8C00D00D -:1094B0002412FFFFACC000048D8B007C3C0C8000AC -:1094C000ACCB000890C2000D3043007FA0C3000D5C -:1094D0008F8700BC90FF000D03E5C824A0F9000DA4 -:1094E0008F9100BC9229000D01387824A22F000D25 -:1094F0008F9000BCAE120010AE150014920E001832 -:109500002415FF8002AE6825A20D00188F8500BCCF -:109510008F8300B88CAB0018016C1024004A3025F2 -:10952000ACA600189068003EA0A8001C8F9F00B851 -:109530008F8700BC8F9800D097F90004A4F9001E13 -:109540000E0002038F0500848F8600D00002794050 -:109550000002490090D200BC01E988210040282186 -:109560003255000212A0000303D120210002A8807E -:109570000095202190CC00BC3192000412400003E1 -:1095800033C900030005408000882021241900040D -:109590008F9E00BC0329382330F800030098502127 -:1095A000AFCA00040E000D05A66500380A0010477A -:1095B0008F9000D0960A00123C1E08008FDE002417 -:1095C00003CA9021A61200120A0010678FB3001080 -:1095D00027BDFFE03C1808008F180050AFB0001006 -:1095E000AFBF0018AFB10014AF8400B09371007426 -:1095F000030478212410FF8031EE007F3225007FA4 -:1096000001F0582401DA68213C0C000AA38500C44B -:1096100001AC2821AF4B002494A9001097680006E4 -:1096200090A6006200803821240200300109202326 -:1096300030C300F0AF8500D0106200193090FFFFFA -:1096400090AE0062240DFFF0240A005001AE6024A9 -:10965000318B00FF116A002F000000001600000788 -:10966000241F0C00AF5F00248FB100148FBF0018BF -:109670008FB0001003E0000827BD00200E000E2B65 -:1096800002002021241F0C00AF5F00248FB10014C2 -:109690008FBF00188FB0001003E0000827BD002026 -:1096A00094A200E094A400E290BF01130082182667 -:1096B0003079FFFF33E700C014E000092F310001CB -:1096C00016000038000000005620FFE6241F0C00A2 -:1096D0000E000D27000000000A0011F9241F0C00E5 -:1096E0001620FFDE000000000E000D270000000025 -:1096F0001440FFDC241F0C00160000228F8300D0D2 -:10970000906901133122003FA06201130A0011F990 -:10971000241F0C0094AF00D48F8600D400E02821D1 -:10972000240400050E000C6B31F0FFFF144000050F -:1097300024030003979100E6000018212625FFFF6F -:10974000A78500E68F5801B80700FFFE3C1960139B -:10975000AF400180241F0C00AF50018400793825F0 -:109760003C101000AF4701888FB10014AF5001B812 -:10977000AF5F00248FB000108FBF001803E0000817 -:1097800027BD00200E000E2B020020215040FFB507 -:10979000241F0C008F8300D0906901130A0012224D -:1097A0003122003F0E000E2B020020211440FFAD9D -:1097B000241F0C00122000078F8300D09068011333 -:1097C0003106003F34C20040A06201130A0011F9C3 -:1097D000241F0C000E000D27000000005040FFA1C8 -:1097E000241F0C008F8300D0906801133106003FC6 -:1097F0000A00125234C20040AF9B00C803E00008C8 -:10980000AF8000EC3089FFFF000940422D0200418B -:10981000000929801440000200095040240800403B -:10982000000879400008C0C001F85821256701A848 -:1098300000EF702125CC007F240DFF80018D1824BE -:109840000065302100CA282125640088240A008888 -:109850003C010800AC2A004C3C010800AC2400503C -:10986000AF8500D43C010800AC2900603C01080031 -:10987000AC2800643C010800AC2700543C010800FF -:10988000AC2300583C010800AC26005C03E0000853 -:1098900000000000308300FF30C6FFFF30E400FF0F -:1098A0008F4201B80440FFFE00034C00012438251C -:1098B0003C08600000E820253C031000AF45018013 -:1098C000AF460184AF44018803E00008AF4301B80C -:1098D0008F86001C3C096012352700108CCB0004D9 -:1098E0003C0C600E35850010316A00062D480001E1 -:1098F000ACE800C48CC40004ACA431808CC2000865 -:1099000094C30002ACA2318403E00008A78300E402 -:109910003C0308008C6300508F8400E88F86001C95 -:109920002402FF800064C0210302C824AF5900282C -:109930008CCD00043305007F00BA78213C0E000C6A -:1099400001EE2821ACAD00588CC80008AF8500D0CE -:109950003C076012ACA8005C8CCC001034E800100E -:10996000ACAC000C8CCB000CACAB000894AA00147F -:109970003C0208008C42004425490001A4A90014BF -:1099800094A400143083FFFF106200178F8400D06E -:109990003C0A08008D4A0040A4AA00128CCE001890 -:1099A000AC8E00248CCD0014AC8D00208CC7001828 -:1099B000AC87002C8CCC001424060001AC8C002851 -:1099C0008D0B00BC5166001A8D0200B48D0200B8E8 -:1099D000A482003A948F003AA48F003C948800D46B -:1099E00003E000083102FFFF3C0908008D29002434 -:1099F000A4A000148F8400D0A4A900128CCE00185B -:109A0000AC8E00248CCD0014AC8D00208CC70018C7 -:109A1000AC87002C8CCC001424060001AC8C0028F0 -:109A20008D0B00BC5566FFEA8D0200B88D0200B4B4 -:109A3000A482003A948F003AA48F003C948800D40A -:109A400003E000083102FFFF8F86001C3C0C080079 -:109A50008D8C0050240BFF808CCD00083C03000C43 -:109A6000000D51C0018A4021010B4824AF8A00E853 -:109A7000AF49002890C700073105007F00BA1021C8 -:109A80000043282130E400041080002FAF8500D06F -:109A900090CF000731EE000811C0003C000000002C -:109AA0008CD9000C8CC400140324C02B1300002696 -:109AB000000000008CC2000CACA200648CCD001829 -:109AC0002402FFF8ACAD00688CCC0010ACAC008078 -:109AD0008CCB000CACAB00848CCA001CACAA007C04 -:109AE00090A900BC01224024A0A800BC90C300079C -:109AF0003067000810E000048F8500D090AF00BCF4 -:109B000035EE0001A0AE00BC90D90007333800014B -:109B10001300000F8F8400D024070020908200BC27 -:109B200034490002A08900BC8F8400D09088006274 -:109B3000310300F014670006240A0034AC8A00C028 -:109B40000A001334000000000A00130E8CC2001437 -:109B500090CB00073166000210C000050000000035 -:109B6000908D00BC35AC0004A08C00BC8F8400D06C -:109B700090980113330F003FA08F01138F8E00D0F8 -:109B800095C500D403E0000830A2FFFFACA000643C -:109B90000A00130F0000000027BDFFD8AFB000106F -:109BA0008F90001CAFBF0024AFB40020AFB20018EC -:109BB000AFB10014AFB3001C9613000E3C07600A4F -:109BC0003C1460063264FFFF369300100E001261F1 -:109BD00034F404108F8400D43C11600E0E0009AAE6 -:109BE00036310010920E00153C0708008CE700602B -:109BF0003C12601231CD000FA38D00F08E0E0004D8 -:109C00008E0D000896080012961F00109619001A73 -:109C10009618001E960F001C310CFFFF33EBFFFF60 -:109C2000332AFFFF3309FFFF31E6FFFF3C01080045 -:109C3000AC2B00403C010800AC2C00243C01080087 -:109C4000AC2A0044AE293178AE26317C9202001550 -:109C50009603001636520010304400FF3065FFFFB7 -:109C60003C0608008CC60064AE243188AE4500B4C2 -:109C70009208001496190018241F0001011FC00447 -:109C8000332FFFFF3C0508008CA50058AE5800B8E4 -:109C9000AE4F00BC920C0014AF8E00D8AF8D00DC2C -:109CA000318B00FFAE4B00C0920A0015AE67004832 -:109CB000AE66004C314900FFAE4900C8AE65007C7D -:109CC0003C0308008C6300503C0408008C84004C6A -:109CD0003C0808008D0800543C0208008C42005CDF -:109CE0008FBF0024AE6300808FB00010AE8300747D -:109CF0008FB3001CAE22319CAE4200DCAE2731A0F7 -:109D0000AE2631A4AE24318CAE233190AE283194EE -:109D1000AE253198AE870050AE860054AE850070F7 -:109D20008FB10014AE4700E0AE4600E4AE4400CC74 -:109D3000AE4300D0AE4800D4AE4500D88FB400206A -:109D40008FB2001803E0000827BD002827BDFFE000 -:109D5000AFB10014AFBF0018241100010E00085469 -:109D6000AFB0001010510005978400E6978300CC37 -:109D70000083102B144000088F8500D424070002B4 -:109D80008FBF00188FB100148FB0001000E01021B9 -:109D900003E0000827BD00200E000C892404000504 -:109DA000AF8200E81040FFF6240700020E000858BA -:109DB0008F90001C979F00E68F9900E88F8D00C858 -:109DC00027EF0001240E0050AF590020A78F00E6B6 -:109DD000A1AE00003C0C08008D8C00648F8600C88A -:109DE000240A8000000C5E00ACCB0074A4C0000606 -:109DF00094C9000A241FFF803C0D000C012AC024D6 -:109E0000A4D8000A90C8000A24182000011F1825B1 -:109E1000A0C3000A8F8700C8A0E000788F8500C823 -:109E200000003821A0A000833C0208008C420050B2 -:109E30008F8400E80044782101FFC824AF5900282E -:109E4000960B000231EE007F01DA6021018D302196 -:109E5000A4CB00D4960A0002AF8600D03C0E0004CA -:109E600025492401A4C900E68E080004ACC80004FA -:109E70008E030008ACC30000A4C00010A4C00014EE -:109E8000A0C000D08F8500D02403FFBFA0A000D1C8 -:109E90003C0408008C8400648F8200D0A04400D26F -:109EA0008E1F000C8F8A00D0978F00E4AD5F001CDE -:109EB0008E19001024100030AD590018A540003054 -:109EC000A5510054A5510056A54F0016AD4E00688F -:109ED000AD580080AD580084914D006231AC000F48 -:109EE000358B0010A14B00628F8600D090C90063B3 -:109EF0003128007FA0C800638F8400D02406FFFFB4 -:109F00009085006300A31024A08200638F9100D08D -:109F100000E01021923F00BC37F90001A23900BCDB -:109F20008F8A00D0938F00F0AD580064AD5000C010 -:109F3000914E00D3000F690031CC000F018D5825E0 -:109F4000A14B00D38F8500D08F8900DCACA900E83D -:109F50008F8800D88FBF00188FB100148FB0001009 -:109F600027BD0020ACA800ECA4A600D6A4A000E069 -:109F7000A4A000E203E000080000000027BDFFE00D -:109F8000AFB000108F90001CAFB10014AFBF00182D -:109F90008E1900043C1808008F180050240FFF8011 -:109FA000001989C00238702131CD007F01CF6024B3 -:109FB00001BA50213C0B000CAF4C0028014B402152 -:109FC000950900D4950400D68E0700043131FFFFB7 -:109FD000AF8800D00E000922000721C08E060004C1 -:109FE0008F8300C8000629C0AF4500209064003E62 -:109FF00030820040144000068F8400D0341FFFFFE1 -:10A00000948300D63062FFFF145F0004000000005C -:10A01000948400D60E0008B73084FFFF8E0500043C -:10A02000022030218FBF00188FB100148FB00010B4 -:10A030002404002200003821000529C00A001285EE -:10A0400027BD002027BDFFE0AFB100143091FFFF16 -:10A05000AFB00010AFBF00181220001D000080211B -:10A060008F86001C8CC500002403000600053F02FB -:10A070000005140230E4000714830015304500FF8A -:10A080002CA800061100004D000558803C0C08006B -:10A09000258C57E8016C50218D49000001200008F3 -:10A0A000000000008F8E00EC240D000111CD00593E -:10A0B00000000000260B00013170FFFF24CA0020C1 -:10A0C0000211202B014030211480FFE6AF8A001CD2 -:10A0D000020010218FBF00188FB100148FB0001044 -:10A0E00003E0000827BD0020938700CE14E000386D -:10A0F000240400140E001346000000008F86001C8C -:10A10000240200010A00148DAF8200EC8F8900EC5C -:10A11000240800021128003B240400130000282119 -:10A1200000003021240700010E001285000000000D -:10A130000A00148D8F86001C8F8700EC2405000216 -:10A1400014E5FFF6240400120E0012F200000000D5 -:10A150008F8500E800403021240400120E00128593 -:10A16000000038210A00148D8F86001C8F8300ECBC -:10A17000241F0003147FFFD0260B00010E0012A441 -:10A18000000000008F8500E800403021240200021A -:10A190002404001000003821AF8200EC0E0012856C -:10A1A000000000000A00148D8F86001C8F8F00ECC9 -:10A1B0002406000211E6000B000000002404001039 -:10A1C00000002821000030210A0014AA2407000101 -:10A1D000000028210E001285000030210A00148D95 -:10A1E0008F86001C0E0013B3000000001440001204 -:10A1F0008F99001C8F86001C240200030A00148D16 -:10A20000AF8200EC0E00143F000000000A00148D25 -:10A210008F86001C0E001294000000002402000231 -:10A2200024040014000028210000302100003821FF -:10A230000A0014C7AF8200EC00403821240400104B -:10A2400097380002000028210E0012853306FFFF18 -:10A250000A00148D8F86001C8F8400C83C077FFF86 -:10A2600034E6FFFF8C8500742402000100A6182448 -:10A27000AC83007403E00008A082000510A0003643 -:10A280002CA20080274A04003C0B00052409008012 -:10A29000104000072408008030A6000F00C54021B0 -:10A2A0002D0300811460000200A0482124080080D2 -:10A2B000AF4B003000000000000000000000000074 -:10A2C0001100000900003821014030218C8D000070 -:10A2D00024E7000400E8602BACCD000024840004D7 -:10A2E0001580FFFA24C600040000000000000000F2 -:10A2F000000000003C0E0006010E3825AF4700307C -:10A300000000000000000000000000008F4F00006F -:10A3100031E800101100FFFD000000008F42003CFA -:10A320008F43003C0049C8210323C02B13000004C5 -:10A33000000000008F4C003825860001AF46003831 -:10A340008F47003C00A9282300E96821AF4D003C5D -:10A3500014A0FFCE2CA2008003E000080000000043 -:10A3600027BDFFD03C020002AFB100143C11000C2D -:10A37000AF450038AFB3001CAF46003C00809821C9 -:10A38000AF42003024050088AF440028035120214B -:10A39000AFBF0028AFB50024AFB40020AFB20018A3 -:10A3A0000E0014FFAFB000103C1F08008FFF004CE0 -:10A3B0003C1808008F1800642410FF8003F3A821C4 -:10A3C00032B9007F02B078240018A0C0033A70218F -:10A3D0000018914001D12021AF4F00280E0014FF3A -:10A3E000025428213C0D08008DAD005024050120A9 -:10A3F00001B35821316C007F01705024019A48212B -:10A40000013120210E0014FFAF4A00283C0808004B -:10A410008D0800543C0508008CA500640113382108 -:10A4200030E6007F00F0182400DA2021009120217E -:10A43000AF4300280E0014FF000529403C0208002D -:10A440008C4200583C1008008E1000601200001C66 -:10A45000005388212415FF800A0015823C14000C4B -:10A460003226007F0235182400DA202102402821FC -:10A47000AF430028009420210E0014FF2610FFC0D7 -:10A480001200000F023288212E05004110A0FFF4B7 -:10A49000241210003226007F00109180023518240B -:10A4A00000DA202102402821AF4300280094202117 -:10A4B0000E0014FF000080211600FFF302328821F5 -:10A4C0003C0B08008D6B005C240AFF802405000211 -:10A4D00001734021010A4824AF4900283C040800C8 -:10A4E000948400623110007F021A88213C07000C1E -:10A4F0000E000CB90227982100402821026020217B -:10A500008FBF00288FB500248FB400208FB3001CAC -:10A510008FB200188FB100148FB000100A0014FF22 -:10A5200027BD00308F83001C8C62000410400003A4 -:10A530000000000003E00008000000008C64001030 -:0CA540008C6500080A0015388C66000CC1 -:04A54C00000000000B -:10A550000000001B0000000F0000000A00000008BF -:10A5600000000006000000050000000500000004D7 -:10A5700000000004000000030000000300000003CE -:10A5800000000003000000030000000200000002C1 -:10A5900000000002000000020000000200000002B3 -:10A5A00000000002000000020000000200000002A3 -:10A5B0000000000200000002000000020000000293 -:10A5C0000000000200000001000000010000000186 -:10A5D00008000F3008000D8808000FC40800106C38 -:10A5E00008000F5808000F98080011A408000DA4D7 -:10A5F000080011C808000DF4080014980800144061 -:10A6000008000DA408000DA408000DA408001254B1 -:10A610000800125408000DA408000DA4080016E05C -:10A6200008000DA408000DA408000DA408000DA446 -:10A63000080013D408000DA408000DA408000DA400 -:10A6400008000DA408000DA408000DA408000DA426 -:10A6500008000DA408000DA408000DA408000DA416 -:10A6600008000DA408000DA408000DA408000FB8F0 -:10A6700008000DA408000DA40800169008000DA401 -:10A6800008000DA408000DA408000DA408000DA4E6 -:10A6900008000DA408000DA408000DA408000DA4D6 -:10A6A00008000DA408000DA408000DA408000DA4C6 -:10A6B00008000DA408000DA408000DA408000DA4B6 -:10A6C000080015BC08000DA408000DA408001348DC -:10A6D000080012B808002E5008002E5808002E203E -:10A6E00008002E2C08002E3808002E440800532C99 -:10A6F000080052EC080052B80800528C080052685A -:04A7000008005224D7 -:0CA704000A000C760000000000000000BD -:10A710000000000D727870342E362E3136000000A5 -:10A72000040610030000000000000001000000000B -:10A730000000000000000000000000000000000019 -:10A740000000000000000000000000000000000009 -:10A7500000000000000000000000000000000000F9 -:10A7600000000000000000000000000000000000E9 -:10A7700000000000000000000000000000000000D9 -:10A7800000000000000000000000000000000000C9 -:10A7900000000000000000000000000000000000B9 -:10A7A00000000000000000000000000000000000A9 -:10A7B0000000000000000000000000000000000099 -:10A7C0000000000000000000000000000000000089 -:10A7D0000000000000000000000000000000000079 -:10A7E0000000000000000000000000000000000069 -:10A7F0000000000000000000000000000000000059 -:10A800000000000000000000000000000000000048 -:10A810000000000000000000000000000000000038 -:10A820000000000000000000000000000000000028 -:10A830000000000000000000000000000000000018 -:10A840000000000000000000000000000000000008 -:10A8500000000000000000000000000000000000F8 -:10A8600000000000000000000000000000000000E8 -:10A8700000000000000000000000000000000000D8 -:10A8800000000000000000000000000000000000C8 -:10A8900000000000000000000000000000000000B8 -:10A8A00000000000000000000000000000000000A8 -:10A8B0000000000000000000000000000000000098 -:10A8C0000000000000000000000000000000000088 -:10A8D0000000000000000000000000000000000078 -:10A8E0000000000000000000000000000000000068 -:10A8F0000000000000000000000000000000000058 -:10A900000000000000000000000000000000000047 -:10A910000000000000000000000000000000000037 -:10A920000000000000000000000000000000000027 -:10A930000000000000000000000000000000000017 -:10A940000000000000000000000000000000000007 -:10A9500000000000000000000000000000000000F7 -:10A9600000000000000000000000000000000000E7 -:10A9700000000000000000000000000000000000D7 -:10A9800000000000000000000000000000000000C7 -:10A9900000000000000000000000000000000000B7 -:10A9A00000000000000000000000000000000000A7 -:10A9B0000000000000000000000000000000000097 -:10A9C0000000000000000000000000000000000087 -:10A9D0000000000000000000000000000000000077 -:10A9E0000000000000000000000000000000000067 -:10A9F0000000000000000000000000000000000057 -:10AA00000000000000000000000000000000000046 -:10AA10000000000000000000000000000000000036 -:10AA20000000000000000000000000000000000026 -:10AA30000000000000000000000000000000000016 -:10AA40000000000000000000000000000000000006 -:10AA500000000000000000000000000000000000F6 -:10AA600000000000000000000000000000000000E6 -:10AA700000000000000000000000000000000000D6 -:10AA800000000000000000000000000000000000C6 -:10AA900000000000000000000000000000000000B6 -:10AAA00000000000000000000000000000000000A6 -:10AAB0000000000000000000000000000000000096 -:10AAC0000000000000000000000000000000000086 -:10AAD0000000000000000000000000000000000076 -:10AAE0000000000000000000000000000000000066 -:10AAF0000000000000000000000000000000000056 -:10AB00000000000000000000000000000000000045 -:10AB10000000000000000000000000000000000035 -:10AB20000000000000000000000000000000000025 -:10AB30000000000000000000000000000000000015 -:10AB40000000000000000000000000000000000005 -:10AB500000000000000000000000000000000000F5 -:10AB600000000000000000000000000000000000E5 -:10AB700000000000000000000000000000000000D5 -:10AB800000000000000000000000000000000000C5 -:10AB900000000000000000000000000000000000B5 -:10ABA00000000000000000000000000000000000A5 -:10ABB0000000000000000000000000000000000095 -:10ABC0000000000000000000000000000000000085 -:10ABD0000000000000000000000000000000000075 -:10ABE0000000000000000000000000000000000065 -:10ABF0000000000000000000000000000000000055 -:10AC00000000000000000000000000000000000044 -:10AC10000000000000000000000000000000000034 -:10AC20000000000000000000000000000000000024 -:10AC30000000000000000000000000000000000014 -:10AC40000000000000000000000000000000000004 -:10AC500000000000000000000000000000000000F4 -:10AC600000000000000000000000000000000000E4 -:10AC700000000000000000000000000000000000D4 -:10AC800000000000000000000000000000000000C4 -:10AC900000000000000000000000000000000000B4 -:10ACA00000000000000000000000000000000000A4 -:10ACB0000000000000000000000000000000000094 -:10ACC0000000000000000000000000000000000084 -:10ACD0000000000000000000000000000000000074 -:10ACE0000000000000000000000000000000000064 -:10ACF0000000000000000000000000000000000054 -:10AD00000000000000000000000000000000000043 -:10AD10000000000000000000000000000000000033 -:10AD20000000000000000000000000000000000023 -:10AD30000000000000000000000000000000000013 -:10AD40000000000000000000000000000000000003 -:10AD500000000000000000000000000000000000F3 -:10AD600000000000000000000000000000000000E3 -:10AD700000000000000000000000000000000000D3 -:10AD800000000000000000000000000000000000C3 -:10AD900000000000000000000000000000000000B3 -:10ADA00000000000000000000000000000000000A3 -:10ADB0000000000000000000000000000000000093 -:10ADC0000000000000000000000000000000000083 -:10ADD0000000000000000000000000000000000073 -:10ADE0000000000000000000000000000000000063 -:10ADF0000000000000000000000000000000000053 -:10AE00000000000000000000000000000000000042 -:10AE10000000000000000000000000000000000032 -:10AE20000000000000000000000000000000000022 -:10AE30000000000000000000000000000000000012 -:10AE40000000000000000000000000000000000002 -:10AE500000000000000000000000000000000000F2 -:10AE600000000000000000000000000000000000E2 -:10AE700000000000000000000000000000000000D2 -:10AE800000000000000000000000000000000000C2 -:10AE900000000000000000000000000000000000B2 -:10AEA00000000000000000000000000000000000A2 -:10AEB0000000000000000000000000000000000092 -:10AEC0000000000000000000000000000000000082 -:10AED0000000000000000000000000000000000072 -:10AEE0000000000000000000000000000000000062 -:10AEF0000000000000000000000000000000000052 -:10AF00000000000000000000000000000000000041 -:10AF10000000000000000000000000000000000031 -:10AF20000000000000000000000000000000000021 -:10AF30000000000000000000000000000000000011 -:10AF40000000000000000000000000000000000001 -:10AF500000000000000000000000000000000000F1 -:10AF600000000000000000000000000000000000E1 -:10AF700000000000000000000000000000000000D1 -:10AF800000000000000000000000000000000000C1 -:10AF900000000000000000000000000000000000B1 -:10AFA00000000000000000000000000000000000A1 -:10AFB0000000000000000000000000000000000091 -:10AFC0000000000000000000000000000000000081 -:10AFD0000000000000000000000000000000000071 -:10AFE0000000000000000000000000000000000061 -:10AFF0000000000000000000000000000000000051 -:10B000000000000000000000000000000000000040 -:10B010000000000000000000000000000000000030 -:10B020000000000000000000000000000000000020 -:10B030000000000000000000000000000000000010 -:10B040000000000000000000000000000000000000 -:10B0500000000000000000000000000000000000F0 -:10B0600000000000000000000000000000000000E0 -:10B0700000000000000000000000000000000000D0 -:10B0800000000000000000000000000000000000C0 -:10B0900000000000000000000000000000000000B0 -:10B0A00000000000000000000000000000000000A0 -:10B0B0000000000000000000000000000000000090 -:10B0C0000000000000000000000000000000000080 -:10B0D0000000000000000000000000000000000070 -:10B0E0000000000000000000000000000000000060 -:10B0F0000000000000000000000000000000000050 -:10B10000000000000000000000000000000000003F -:10B11000000000000000000000000000000000002F -:10B12000000000000000000000000000000000001F -:10B13000000000000000000000000000000000000F -:10B1400000000000000000000000000000000000FF -:10B1500000000000000000000000000000000000EF -:10B1600000000000000000000000000000000000DF -:10B1700000000000000000000000000000000000CF -:10B1800000000000000000000000000000000000BF -:10B1900000000000000000000000000000000000AF -:10B1A000000000000000000000000000000000009F -:10B1B000000000000000000000000000000000008F -:10B1C000000000000000000000000000000000007F -:10B1D000000000000000000000000000000000006F -:10B1E000000000000000000000000000000000005F -:10B1F000000000000000000000000000000000004F -:10B20000000000000000000000000000000000003E -:10B21000000000000000000000000000000000002E -:10B22000000000000000000000000000000000001E -:10B23000000000000000000000000000000000000E -:10B2400000000000000000000000000000000000FE -:10B2500000000000000000000000000000000000EE -:10B2600000000000000000000000000000000000DE -:10B2700000000000000000000000000000000000CE -:10B2800000000000000000000000000000000000BE -:10B2900000000000000000000000000000000000AE -:10B2A000000000000000000000000000000000009E -:10B2B000000000000000000000000000000000008E -:10B2C000000000000000000000000000000000007E -:10B2D000000000000000000000000000000000006E -:10B2E000000000000000000000000000000000005E -:10B2F000000000000000000000000000000000004E -:10B30000000000000000000000000000000000003D -:10B31000000000000000000000000000000000002D -:10B32000000000000000000000000000000000001D -:10B33000000000000000000000000000000000000D -:10B3400000000000000000000000000000000000FD -:10B3500000000000000000000000000000000000ED -:10B3600000000000000000000000000000000000DD -:10B3700000000000000000000000000000000000CD -:10B3800000000000000000000000000000000000BD -:10B3900000000000000000000000000000000000AD -:10B3A000000000000000000000000000000000009D -:10B3B000000000000000000000000000000000008D -:10B3C000000000000000000000000000000000007D -:10B3D000000000000000000000000000000000006D -:10B3E000000000000000000000000000000000005D -:10B3F000000000000000000000000000000000004D -:10B40000000000000000000000000000000000003C -:10B41000000000000000000000000000000000002C -:10B42000000000000000000000000000000000001C -:10B43000000000000000000000000000000000000C -:10B4400000000000000000000000000000000000FC -:10B4500000000000000000000000000000000000EC -:10B4600000000000000000000000000000000000DC -:10B4700000000000000000000000000000000000CC -:10B4800000000000000000000000000000000000BC -:10B4900000000000000000000000000000000000AC -:10B4A000000000000000000000000000000000009C -:10B4B000000000000000000000000000000000008C -:10B4C000000000000000000000000000000000007C -:10B4D000000000000000000000000000000000006C -:10B4E000000000000000000000000000000000005C -:10B4F000000000000000000000000000000000004C -:10B50000000000000000000000000000000000003B -:10B51000000000000000000000000000000000002B -:10B52000000000000000000000000000000000001B -:10B53000000000000000000000000000000000000B -:10B5400000000000000000000000000000000000FB -:10B5500000000000000000000000000000000000EB -:10B5600000000000000000000000000000000000DB -:10B5700000000000000000000000000000000000CB -:10B5800000000000000000000000000000000000BB -:10B5900000000000000000000000000000000000AB -:10B5A000000000000000000000000000000000009B -:10B5B000000000000000000000000000000000008B -:10B5C000000000000000000000000000000000007B -:10B5D000000000000000000000000000000000006B -:10B5E000000000000000000000000000000000005B -:10B5F000000000000000000000000000000000004B -:10B60000000000000000000000000000000000003A -:10B61000000000000000000000000000000000002A -:10B62000000000000000000000000000000000001A -:10B63000000000000000000000000000000000000A -:10B6400000000000000000000000000000000000FA -:10B6500000000000000000000000000000000000EA -:10B6600000000000000000000000000000000000DA -:10B6700000000000000000000000000000000000CA -:10B6800000000000000000000000000000000000BA -:10B6900000000000000000000000000000000000AA -:10B6A000000000000000000000000000000000009A -:10B6B000000000000000000000000000000000008A -:10B6C000000000000000000000000000000000007A -:10B6D000000000000000000000000000000000006A -:10B6E000000000000000000000000000000000005A -:10B6F000000000000000000000000000000000004A -:10B700000000000000000000000000000000000039 -:10B710000000000000000000000000000000000029 -:10B720000000000000000000000000000000000019 -:10B730000000000000000000000000000000000009 -:10B7400000000000000000000000000000000000F9 -:10B7500000000000000000000000000000000000E9 -:10B7600000000000000000000000000000000000D9 -:10B7700000000000000000000000000000000000C9 -:10B7800000000000000000000000000000000000B9 -:10B7900000000000000000000000000000000000A9 -:10B7A0000000000000000000000000000000000099 -:10B7B0000000000000000000000000000000000089 -:10B7C0000000000000000000000000000000000079 -:10B7D0000000000000000000000000000000000069 -:10B7E0000000000000000000000000000000000059 -:10B7F0000000000000000000000000000000000049 -:10B800000000000000000000000000000000000038 -:10B810000000000000000000000000000000000028 -:10B820000000000000000000000000000000000018 -:10B830000000000000000000000000000000000008 -:10B8400000000000000000000000000000000000F8 -:10B8500000000000000000000000000000000000E8 -:10B8600000000000000000000000000000000000D8 -:10B8700000000000000000000000000000000000C8 -:10B8800000000000000000000000000000000000B8 -:10B8900000000000000000000000000000000000A8 -:10B8A0000000000000000000000000000000000098 -:10B8B0000000000000000000000000000000000088 -:10B8C0000000000000000000000000000000000078 -:10B8D0000000000000000000000000000000000068 -:10B8E0000000000000000000000000000000000058 -:10B8F0000000000000000000000000000000000048 -:10B900000000000000000000000000000000000037 -:10B910000000000000000000000000000000000027 -:10B920000000000000000000000000000000000017 -:10B930000000000000000000000000000000000007 -:10B9400000000000000000000000000000000000F7 -:10B9500000000000000000000000000000000000E7 -:10B9600000000000000000000000000000000000D7 -:10B9700000000000000000000000000000000000C7 -:10B9800000000000000000000000000000000000B7 -:10B9900000000000000000000000000000000000A7 -:10B9A0000000000000000000000000000000000097 -:10B9B0000000000000000000000000000000000087 -:10B9C0000000000000000000000000000000000077 -:10B9D0000000000000000000000000000000000067 -:10B9E0000000000000000000000000000000000057 -:10B9F0000000000000000000000000000000000047 -:10BA00000000000000000000000000000000000036 -:10BA10000000000000000000000000000000000026 -:10BA20000000000000000000000000000000000016 -:10BA30000000000000000000000000000000000006 -:10BA400000000000000000000000000000000000F6 -:10BA500000000000000000000000000000000000E6 -:10BA600000000000000000000000000000000000D6 -:10BA700000000000000000000000000000000000C6 -:10BA800000000000000000000000000000000000B6 -:10BA900000000000000000000000000000000000A6 -:10BAA0000000000000000000000000000000000096 -:10BAB0000000000000000000000000000000000086 -:10BAC0000000000000000000000000000000000076 -:10BAD0000000000000000000000000000000000066 -:10BAE0000000000000000000000000000000000056 -:10BAF0000000000000000000000000000000000046 -:10BB00000000000000000000000000000000000035 -:10BB10000000000000000000000000000000000025 -:10BB20000000000000000000000000000000000015 -:10BB30000000000000000000000000000000000005 -:10BB400000000000000000000000000000000000F5 -:10BB500000000000000000000000000000000000E5 -:10BB600000000000000000000000000000000000D5 -:10BB700000000000000000000000000000000000C5 -:10BB800000000000000000000000000000000000B5 -:10BB900000000000000000000000000000000000A5 -:10BBA0000000000000000000000000000000000095 -:10BBB0000000000000000000000000000000000085 -:10BBC0000000000000000000000000000000000075 -:10BBD0000000000000000000000000000000000065 -:10BBE0000000000000000000000000000000000055 -:10BBF0000000000000000000000000000000000045 -:10BC00000000000000000000000000000000000034 -:10BC10000000000000000000000000000000000024 -:10BC20000000000000000000000000000000000014 -:10BC30000000000000000000000000000000000004 -:10BC400000000000000000000000000000000000F4 -:10BC500000000000000000000000000000000000E4 -:10BC600000000000000000000000000000000000D4 -:10BC700000000000000000000000000000000000C4 -:10BC800000000000000000000000000000000000B4 -:10BC900000000000000000000000000000000000A4 -:10BCA0000000000000000000000000000000000094 -:10BCB0000000000000000000000000000000000084 -:10BCC0000000000000000000000000000000000074 -:10BCD0000000000000000000000000000000000064 -:10BCE0000000000000000000000000000000000054 -:10BCF0000000000000000000000000000000000044 -:10BD00000000000000000000000000000000000033 -:10BD10000000000000000000000000000000000023 -:10BD20000000000000000000000000000000000013 -:10BD30000000000000000000000000000000000003 -:10BD400000000000000000000000000000000000F3 -:10BD500000000000000000000000000000000000E3 -:10BD600000000000000000000000000000000000D3 -:10BD700000000000000000000000000000000000C3 -:10BD800000000000000000000000000000000000B3 -:10BD900000000000000000000000000000000000A3 -:10BDA0000000000000000000000000000000000093 -:10BDB0000000000000000000000000000000000083 -:10BDC0000000000000000000000000000000000073 -:10BDD0000000000000000000000000000000000063 -:10BDE0000000000000000000000000000000000053 -:10BDF0000000000000000000000000000000000043 -:10BE00000000000000000000000000000000000032 -:10BE10000000000000000000000000000000000022 -:10BE20000000000000000000000000000000000012 -:10BE30000000000000000000000000000000000002 -:10BE400000000000000000000000000000000000F2 -:10BE500000000000000000000000000000000000E2 -:10BE600000000000000000000000000000000000D2 -:10BE700000000000000000000000000000000000C2 -:10BE800000000000000000000000000000000000B2 -:10BE900000000000000000000000000000000000A2 -:10BEA0000000000000000000000000000000000092 -:10BEB0000000000000000000000000000000000082 -:10BEC0000000000000000000000000000000000072 -:10BED0000000000000000000000000000000000062 -:10BEE0000000000000000000000000000000000052 -:10BEF0000000000000000000000000000000000042 -:10BF00000000000000000000000000000000000031 -:10BF10000000000000000000000000000000000021 -:10BF20000000000000000000000000000000000011 -:10BF30000000000000000000000000000000000001 -:10BF400000000000000000000000000000000000F1 -:10BF500000000000000000000000000000000000E1 -:10BF600000000000000000000000000000000000D1 -:10BF700000000000000000000000000000000000C1 -:10BF800000000000000000000000000000000000B1 -:10BF900000000000000000000000000000000000A1 -:10BFA0000000000000000000000000000000000091 -:10BFB0000000000000000000000000000000000081 -:10BFC0000000000000000000000000000000000071 -:10BFD0000000000000000000000000000000000061 -:10BFE0000000000000000000000000000000000051 -:10BFF0000000000000000000000000000000000041 -:10C000000000000000000000000000000000000030 -:10C010000000000000000000000000000000000020 -:10C020000000000000000000000000000000000010 -:10C030000000000000000000000000000000000000 -:10C0400000000000000000000000000000000000F0 -:10C0500000000000000000000000000000000000E0 -:10C0600000000000000000000000000000000000D0 -:10C0700000000000000000000000000000000000C0 -:10C0800000000000000000000000000000000000B0 -:10C0900000000000000000000000000000000000A0 -:10C0A0000000000000000000000000000000000090 -:10C0B0000000000000000000000000000000000080 -:10C0C0000000000000000000000000000000000070 -:10C0D0000000000000000000000000000000000060 -:10C0E0000000000000000000000000000000000050 -:10C0F0000000000000000000000000000000000040 -:10C10000000000000000000000000000000000002F -:10C11000000000000000000000000000000000001F -:10C12000000000000000000000000000000000000F -:10C1300000000000000000000000000000000000FF -:10C1400000000000000000000000000000000000EF -:10C1500000000000000000000000000000000000DF -:10C1600000000000000000000000000000000000CF -:10C1700000000000000000000000000000000000BF -:10C1800000000000000000000000000000000000AF -:10C19000000000000000000000000000000000009F -:10C1A000000000000000000000000000000000008F -:10C1B000000000000000000000000000000000007F -:10C1C000000000000000000000000000000000006F -:10C1D000000000000000000000000000000000005F -:10C1E000000000000000000000000000000000004F -:10C1F000000000000000000000000000000000003F -:10C20000000000000000000000000000000000002E -:10C21000000000000000000000000000000000001E -:10C22000000000000000000000000000000000000E -:10C2300000000000000000000000000000000000FE -:10C2400000000000000000000000000000000000EE -:10C2500000000000000000000000000000000000DE -:10C2600000000000000000000000000000000000CE -:10C2700000000000000000000000000000000000BE -:10C2800000000000000000000000000000000000AE -:10C29000000000000000000000000000000000009E -:10C2A000000000000000000000000000000000008E -:10C2B000000000000000000000000000000000007E -:10C2C000000000000000000000000000000000006E -:10C2D000000000000000000000000000000000005E -:10C2E000000000000000000000000000000000004E -:10C2F000000000000000000000000000000000003E -:10C30000000000000000000000000000000000002D -:10C31000000000000000000000000000000000001D -:10C32000000000000000000000000000000000000D -:10C3300000000000000000000000000000000000FD -:10C3400000000000000000000000000000000000ED -:10C3500000000000000000000000000000000000DD -:10C3600000000000000000000000000000000000CD -:10C3700000000000000000000000000000000000BD -:10C3800000000000000000000000000000000000AD -:10C39000000000000000000000000000000000009D -:10C3A000000000000000000000000000000000008D -:10C3B000000000000000000000000000000000007D -:10C3C000000000000000000000000000000000006D -:10C3D000000000000000000000000000000000005D -:10C3E000000000000000000000000000000000004D -:10C3F000000000000000000000000000000000003D -:10C40000000000000000000000000000000000002C -:10C41000000000000000000000000000000000001C -:10C42000000000000000000000000000000000000C -:10C4300000000000000000000000000000000000FC -:10C4400000000000000000000000000000000000EC -:10C4500000000000000000000000000000000000DC -:10C4600000000000000000000000000000000000CC -:10C4700000000000000000000000000000000000BC -:10C4800000000000000000000000000000000000AC -:10C49000000000000000000000000000000000009C -:10C4A000000000000000000000000000000000008C -:10C4B000000000000000000000000000000000007C -:10C4C000000000000000000000000000000000006C -:10C4D000000000000000000000000000000000005C -:10C4E000000000000000000000000000000000004C -:10C4F000000000000000000000000000000000003C -:10C50000000000000000000000000000000000002B -:10C51000000000000000000000000000000000001B -:10C52000000000000000000000000000000000000B -:10C5300000000000000000000000000000000000FB -:10C5400000000000000000000000000000000000EB -:10C5500000000000000000000000000000000000DB -:10C5600000000000000000000000000000000000CB -:10C5700000000000000000000000000000000000BB -:10C5800000000000000000000000000000000000AB -:10C59000000000000000000000000000000000009B -:10C5A000000000000000000000000000000000008B -:10C5B000000000000000000000000000000000007B -:10C5C000000000000000000000000000000000006B -:10C5D000000000000000000000000000000000005B -:10C5E000000000000000000000000000000000004B -:10C5F000000000000000000000000000000000003B -:10C60000000000000000000000000000000000002A -:10C61000000000000000000000000000000000001A -:10C62000000000000000000000000000000000000A -:10C6300000000000000000000000000000000000FA -:10C6400000000000000000000000000000000000EA -:10C6500000000000000000000000000000000000DA -:10C6600000000000000000000000000000000000CA -:10C6700000000000000000000000000000000000BA -:10C6800000000000000000000000000000000000AA -:10C69000000000000000000000000000000000009A -:10C6A000000000000000000000000000000000008A -:10C6B000000000000000000000000000000000007A -:10C6C000000000000000000000000000000000006A -:10C6D000000000000000000000000000000000005A -:10C6E000000000000000000000000000000000004A -:10C6F000000000000000000000000000000000003A -:10C700000000000000000000000000000000000029 -:10C710000000000000000000000000000000000019 -:10C720000000000000000000000000000000000009 -:10C7300000000000000000000000000000000000F9 -:10C7400000000000000000000000000000000000E9 -:10C7500000000000000000000000000000000000D9 -:10C7600000000000000000000000000000000000C9 -:10C7700000000000000000000000000000000000B9 -:10C7800000000000000000000000000000000000A9 -:10C790000000000000000000000000000000000099 -:10C7A0000000000000000000000000000000000089 -:10C7B0000000000000000000000000000000000079 -:10C7C0000000000000000000000000000000000069 -:10C7D0000000000000000000000000000000000059 -:10C7E0000000000000000000000000000000000049 -:10C7F0000000000000000000000000000000000039 -:10C800000000000000000000000000000000000028 -:10C810000000000000000000000000000000000018 -:10C820000000000000000000000000000000000008 -:10C8300000000000000000000000000000000000F8 -:10C8400000000000000000000000000000000000E8 -:10C8500000000000000000000000000000000000D8 -:10C8600000000000000000000000000000000000C8 -:10C8700000000000000000000000000000000000B8 -:10C8800000000000000000000000000000000000A8 -:10C890000000000000000000000000000000000098 -:10C8A0000000000000000000000000000000000088 -:10C8B0000000000000000000000000000000000078 -:10C8C0000000000000000000000000000000000068 -:10C8D0000000000000000000000000000000000058 -:10C8E0000000000000000000000000000000000048 -:10C8F0000000000000000000000000000000000038 -:10C900000000000000000000000000000000000027 -:10C910000000000000000000000000000000000017 -:10C920000000000000000000000000000000000007 -:10C9300000000000000000000000000000000000F7 -:10C9400000000000000000000000000000000000E7 -:10C9500000000000000000000000000000000000D7 -:10C9600000000000000000000000000000000000C7 -:10C9700000000000000000000000000000000000B7 -:10C9800000000000000000000000000000000000A7 -:10C990000000000000000000000000000000000097 -:10C9A0000000000000000000000000000000000087 -:10C9B0000000000000000000000000000000000077 -:10C9C0000000000000000000000000000000000067 -:10C9D0000000000000000000000000000000000057 -:10C9E0000000000000000000000000000000000047 -:10C9F0000000000000000000000000000000000037 -:10CA00000000000000000000000000000000000026 -:10CA10000000000000000000000000000000000016 -:10CA20000000000000000000000000000000000006 -:10CA300000000000000000000000000000000000F6 -:10CA400000000000000000000000000000000000E6 -:10CA500000000000000000000000000000000000D6 -:10CA600000000000000000000000000000000000C6 -:10CA700000000000000000000000000000000000B6 -:10CA800000000000000000000000000000000000A6 -:10CA90000000000000000000000000000000000096 -:10CAA0000000000000000000000000000000000086 -:10CAB0000000000000000000000000000000000076 -:10CAC0000000000000000000000000000000000066 -:10CAD0000000000000000000000000000000000056 -:10CAE0000000000000000000000000000000000046 -:10CAF0000000000000000000000000000000000036 -:10CB00000000000000000000000000000000000025 -:10CB10000000000000000000000000000000000015 -:10CB20000000000000000000000000000000000005 -:10CB300000000000000000000000000000000000F5 -:10CB400000000000000000000000000000000000E5 -:10CB500000000000000000000000000000000000D5 -:10CB600000000000000000000000000000000000C5 -:10CB700000000000000000000000000000000000B5 -:10CB800000000000000000000000000000000000A5 -:10CB90000000000000000000000000000000000095 -:10CBA0000000000000000000000000000000000085 -:10CBB0000000000000000000000000000000000075 -:10CBC0000000000000000000000000000000000065 -:10CBD0000000000000000000000000000000000055 -:10CBE0000000000000000000000000000000000045 -:10CBF0000000000000000000000000000000000035 -:10CC00000000000000000000000000000000000024 -:10CC10000000000000000000000000000000000014 -:10CC20000000000000000000000000000000000004 -:10CC300000000000000000000000000000000000F4 -:10CC400000000000000000000000000000000000E4 -:10CC500000000000000000000000000000000000D4 -:10CC600000000000000000000000000000000000C4 -:10CC700000000000000000000000000000000000B4 -:10CC800000000000000000000000000000000000A4 -:10CC90000000000000000000000000000000000094 -:10CCA0000000000000000000000000000000000084 -:10CCB0000000000000000000000000000000000074 -:10CCC0000000000000000000000000000000000064 -:10CCD0000000000000000000000000000000000054 -:10CCE0000000000000000000000000000000000044 -:10CCF0000000000000000000000000000000000034 -:10CD00000000000000000000000000000000000023 -:10CD10000000000000000000000000000000000013 -:10CD20000000000000000000000000000000000003 -:10CD300000000000000000000000000000000000F3 -:10CD400000000000000000000000000000000000E3 -:10CD500000000000000000000000000000000000D3 -:10CD600000000000000000000000000000000000C3 -:10CD700000000000000000000000000000000000B3 -:10CD800000000000000000000000000000000000A3 -:10CD90000000000000000000000000000000000093 -:10CDA0000000000000000000000000000000000083 -:10CDB0000000000000000000000000000000000073 -:10CDC0000000000000000000000000000000000063 -:10CDD0000000000000000000000000000000000053 -:10CDE0000000000000000000000000000000000043 -:10CDF0000000000000000000000000000000000033 -:10CE00000000000000000000000000000000000022 -:10CE10000000000000000000000000000000000012 -:10CE20000000000000000000000000000000000002 -:10CE300000000000000000000000000000000000F2 -:10CE400000000000000000000000000000000000E2 -:10CE500000000000000000000000000000000000D2 -:10CE600000000000000000000000000000000000C2 -:10CE700000000000000000000000000000000000B2 -:10CE800000000000000000000000000000000000A2 -:10CE90000000000000000000000000000000000092 -:10CEA0000000000000000000000000000000000082 -:10CEB0000000000000000000000000000000000072 -:10CEC0000000000000000000000000000000000062 -:10CED0000000000000000000000000000000000052 -:10CEE0000000000000000000000000000000000042 -:10CEF0000000000000000000000000000000000032 -:10CF00000000000000000000000000000000000021 -:10CF10000000000000000000000000000000000011 -:10CF20000000000000000000000000000000000001 -:10CF300000000000000000000000000000000000F1 -:10CF400000000000000000000000000000000000E1 -:10CF500000000000000000000000000000000000D1 -:10CF600000000000000000000000000000000000C1 -:10CF700000000000000000000000000000000000B1 -:10CF800000000000000000000000000000000000A1 -:10CF90000000000000000000000000000000000091 -:10CFA0000000000000000000000000000000000081 -:10CFB0000000000000000000000000000000000071 -:10CFC0000000000000000000000000000000000061 -:10CFD0000000000000000000000000000000000051 -:10CFE0000000000000000000000000000000000041 -:10CFF0000000000000000000000000000000000031 -:10D000000000000000000000000000000000000020 -:10D010000000000000000000000000000000000010 -:10D020000000000000000000000000000000000000 -:10D0300000000000000000000000000000000000F0 -:10D0400000000000000000000000000000000000E0 -:10D0500000000000000000000000000000000000D0 -:10D0600000000000000000000000000000000000C0 -:10D0700000000000000000000000000000000000B0 -:10D0800000000000000000000000000000000000A0 -:10D090000000000000000000000000000000000090 -:10D0A0000000000000000000000000000000000080 -:10D0B0000000000000000000000000000000000070 -:10D0C0000000000000000000000000000000000060 -:10D0D0000000000000000000000000000000000050 -:10D0E0000000000000000000000000000000000040 -:10D0F0000000000000000000000000000000000030 -:10D10000000000000000000000000000000000001F -:10D11000000000000000000000000000000000000F -:10D1200000000000000000000000000000000000FF -:10D1300000000000000000000000000000000000EF -:10D1400000000000000000000000000000000000DF -:10D1500000000000000000000000000000000000CF -:10D1600000000000000000000000000000000000BF -:10D1700000000000000000000000000000000000AF -:10D18000000000000000000000000000000000009F -:10D19000000000000000000000000000000000008F -:10D1A000000000000000000000000000000000007F -:10D1B000000000000000000000000000000000006F -:10D1C000000000000000000000000000000000005F -:10D1D000000000000000000000000000000000004F -:10D1E000000000000000000000000000000000003F -:10D1F000000000000000000000000000000000002F -:10D20000000000000000000000000000000000001E -:10D21000000000000000000000000000000000000E -:10D2200000000000000000000000000000000000FE -:10D2300000000000000000000000000000000000EE -:10D2400000000000000000000000000000000000DE -:10D2500000000000000000000000000000000000CE -:10D2600000000000000000000000000000000000BE -:10D2700000000000000000000000000000000000AE -:10D28000000000000000000000000000000000009E -:10D29000000000000000000000000000000000008E -:10D2A000000000000000000000000000000000007E -:10D2B000000000000000000000000000000000006E -:10D2C000000000000000000000000000000000005E -:10D2D000000000000000000000000000000000004E -:10D2E000000000000000000000000000000000003E -:10D2F000000000000000000000000000000000002E -:10D30000000000000000000000000000000000001D -:10D31000000000000000000000000000000000000D -:10D3200000000000000000000000000000000000FD -:10D3300000000000000000000000000000000000ED -:10D3400000000000000000000000000000000000DD -:10D3500000000000000000000000000000000000CD -:10D3600000000000000000000000000000000000BD -:10D3700000000000000000000000000000000000AD -:10D38000000000000000000000000000000000009D -:10D39000000000000000000000000000000000008D -:10D3A000000000000000000000000000000000007D -:10D3B000000000000000000000000000000000006D -:10D3C000000000000000000000000000000000005D -:10D3D000000000000000000000000000000000004D -:10D3E000000000000000000000000000000000003D -:10D3F000000000000000000000000000000000002D -:10D40000000000000000000000000000000000001C -:10D41000000000000000000000000000000000000C -:10D4200000000000000000000000000000000000FC -:10D4300000000000000000000000000000000000EC -:10D4400000000000000000000000000000000000DC -:10D4500000000000000000000000000000000000CC -:10D4600000000000000000000000000000000000BC -:10D4700000000000000000000000000000000000AC -:10D48000000000000000000000000000000000009C -:10D49000000000000000000000000000000000008C -:10D4A000000000000000000000000000000000007C -:10D4B000000000000000000000000000000000006C -:10D4C000000000000000000000000000000000005C -:10D4D000000000000000000000000000000000004C -:10D4E000000000000000000000000000000000003C -:10D4F000000000000000000000000000000000002C -:10D50000000000000000000000000000000000001B -:10D51000000000000000000000000000000000000B -:10D5200000000000000000000000000000000000FB -:10D5300000000000000000000000000000000000EB -:10D5400000000000000000000000000000000000DB -:10D5500000000000000000000000000000000000CB -:10D5600000000000000000000000000000000000BB -:10D5700000000000000000000000000000000000AB -:10D58000000000000000000000000000000000009B -:10D59000000000000000000000000000000000008B -:10D5A000000000000000000000000000000000007B -:10D5B000000000000000000000000000000000006B -:10D5C000000000000000000000000000000000005B -:10D5D000000000000000000000000000000000004B -:10D5E000000000000000000000000000000000003B -:10D5F000000000000000000000000000000000002B -:10D60000000000000000000000000000000000001A -:10D61000000000000000000000000000000000000A -:10D6200000000000000000000000000000000000FA -:10D6300000000000000000000000000000000000EA -:10D6400000000000000000000000000000000000DA -:10D6500000000000000000000000000000000000CA -:10D6600000000000000000000000000000000000BA -:10D6700000000000000000000000000000000000AA -:10D68000000000000000000000000000000000009A -:10D69000000000000000000000000000000000008A -:10D6A000000000000000000000000000000000007A -:10D6B000000000000000000000000000000000006A -:10D6C000000000000000000000000000000000005A -:10D6D000000000000000000000000000000000004A -:10D6E000000000000000000000000000000000003A -:10D6F000000000000000000000000000000000002A -:10D700000000000000000000000000000000000019 -:10D710000000000000000000000000000000000009 -:10D7200000000000000000000000000000000000F9 -:10D7300000000000000000000000000000000000E9 -:10D7400000000000000000000000000000000000D9 -:10D7500000000000000000000000000000000000C9 -:10D7600000000000000000000000000000000000B9 -:10D7700000000000000000000000000000000000A9 -:10D780000000000000000000000000000000000099 -:10D790000000000000000000000000000000000089 -:10D7A0000000000000000000000000000000000079 -:10D7B0000000000000000000000000000000000069 -:10D7C0000000000000000000000000000000000059 -:10D7D0000000000000000000000000000000000049 -:10D7E0000000000000000000000000000000000039 -:10D7F0000000000000000000000000000000000029 -:10D800000000000000000000000000000000000018 -:10D810000000000000000000000000000000000008 -:10D8200000000000000000000000000000000000F8 -:10D8300000000000000000000000000000000000E8 -:10D8400000000000000000000000000000000000D8 -:10D8500000000000000000000000000000000000C8 -:10D8600000000000000000000000000000000000B8 -:10D8700000000000000000000000000000000000A8 -:10D880000000000000000000000000000000000098 -:10D890000000000000000000000000000000000088 -:10D8A0000000000000000000000000000000000078 -:10D8B0000000000000000000000000000000000068 -:10D8C0000000000000000000000000000000000058 -:10D8D0000000000000000000000000000000000048 -:10D8E00010000003000000000000000D0000000D0B -:10D8F0003C020800244271203C030800246375C8E0 -:10D90000AC4000000043202B1480FFFD24420004A3 -:10D910003C1D080037BD7FFC03A0F0213C1008002F -:10D92000261031D83C1C0800279C71200E00116481 -:10D93000000000000000000D30A5FFFF30C600FF12 -:10D94000274301808F4201B80440FFFE24020002F9 -:10D95000AC640000A4650008A066000AA062000B89 -:10D960003C021000AC67001803E00008AF4201B8A9 -:10D970003C0360008C624FF80440FFFE3C02020052 -:10D98000AC644FC0AC624FC43C02100003E000081E -:10D99000AC624FF827BDFFE8AFBF0014AFB0001076 -:10D9A0000E0011B300808021936200052403FFFE66 -:10D9B00002002021004310248FBF00148FB00010FC -:10D9C000A36200050A0011BC27BD001827BDFFE8AF -:10D9D000AFB00010AFBF00140E000EA40080802175 -:10D9E0009362000024030050304200FF14430004FF -:10D9F00024020100AF4201800A000CC10200202174 -:10DA0000AF400180020020218FBF00148FB00010B2 -:10DA10000A000F7D27BD001827BDFF98AFBE00602C -:10DA2000AFB7005CAFB20048AFBF0064AFB60058FC -:10DA3000AFB50054AFB40050AFB3004CAFB1004429 -:10DA4000AFB000408F5001289363003F9362000500 -:10DA50000000F021307200FF000210273042000168 -:10DA60000000B82114400066AFA0003893420116B0 -:10DA700093430112304200FF306300FF0342202134 -:10DA800003431021244540008F82000010400018FD -:10DA9000248840008F4201043C030001004310240D -:10DAA00010400013000000008CA3000C8F620030B7 -:10DAB000146201A2240200018CA300108F62002CCA -:10DAC0001462019E240200019762003A9483400090 -:10DAD0003042FFFF1462019924020001976200386E -:10DAE000950300023042FFFF1462019424020001FA -:10DAF00093620000304300FF240200201062000502 -:10DB00002402005010620006000000000A000D0B05 -:10DB1000000000000000000D0A000D14AFA000304E -:10DB20003C1E080027DE71880A000D14AFA00030EB -:10DB30003C0208008C4200DC244200013C01080049 -:10DB4000AC2200DC0E00127D000000000A000E8FE7 -:10DB50008FBF00648F4201043C0300209113000D2D -:10DB6000004310240002202B00042140AFA4003009 -:10DB70008F4301043C02004000621824146000023C -:10DB8000348700400080382132620020AFA7003087 -:10DB90001440000234E6008000E0302110C0000B89 -:10DBA000AFA6003093C500088F67004C020020210B -:10DBB00000052B0034A5008130A5F0810E000C8DEE -:10DBC00030C600FF0A000E8C000000009362003E89 -:10DBD000304200401040000E24020004564200066D -:10DBE00024020012020020210E0013DA010030216D -:10DBF0000A000E8F8FBF006416420005000000006F -:10DC00000E000CB2000020210A000E8F8FBF0064AE -:10DC10009742011A9504000E9363003532650004A3 -:10DC20003055FFFF00642004AFA4003C8D110004B8 -:10DC300010A000158D1400089362003E3042004091 -:10DC400010400007000000000E00133B02202021BE -:10DC50001040000D000000000A000E8C00000000C3 -:10DC60008F620044022210230440013200000000B1 -:10DC70008F620048022210230441012E2404001662 -:10DC80000A000DA28FC200048F62004802221023F6 -:10DC900004400008000000003C0208008C423100F3 -:10DCA000244200013C010800AC2231000A000E8130 -:10DCB000000000008F62004002221023184000097B -:10DCC0002402000C3C0208008C423100327300FC3C -:10DCD0000000A821244200013C010800AC223100D0 -:10DCE0002402000CAFA200308F62004000511823C4 -:10DCF0001860000D02A3102A144001030000000068 -:10DD00001475000602A310233A620001304200019C -:10DD1000144000FD0000000002A31023022388210C -:10DD20000A000D8A3055FFFF000018213262000200 -:10DD30001040001A326200109362003E30420040F0 -:10DD4000504000118FC200040E0011B302002021C8 -:10DD500024020018A362003F936200052403FFFE23 -:10DD600002002021004310240E0011BCA362000514 -:10DD700024040039000028210E0013242406001872 -:10DD80000A000E8E24020001240400170040F80946 -:10DD9000000000000A000E8E24020001104000E581 -:10DDA000000000008F64004C8F6200540282102338 -:10DDB0001C4000E002841023044200010080A021E6 -:10DDC000AFA30018AFB10010AFB50014934201200B -:10DDD0008F6600409764003C304200FF03422821D8 -:10DDE0008FA2003C00A328218FA300303084FFFFC6 -:10DDF0000044202B8FC200000064182524A5400099 -:10DE0000AFA50020AFA60028AFA30030AFA6002426 -:10DE1000AFA0002CAFB400340040F80927A40010D4 -:10DE20008FA200303042000254400001327300FEE5 -:10DE30009362003E30420040104000378FA3001430 -:10DE40008F6200541682001A32620001240200140C -:10DE5000124200102A42001510400006240200164B -:10DE60002402000C12420007326200010A000DEB8E -:10DE70000000000012420005326200010A000DEBB2 -:10DE8000000000000A000DE62417000E0A000DE64F -:10DE9000241700100A000DEA2417001293620023D1 -:10DEA0002403FFBD00431024A3620023326200015B -:10DEB000104000198FA300142402000C1242000E1F -:10DEC0002A42000D104000062402000E2402000A1F -:10DED000124200078FA200240A000E032442000110 -:10DEE000124200088FA200240A000E0324420001FF -:10DEF0000A000E01241700082402000E16E2000298 -:10DF000024170016241700108FA2002424420001B9 -:10DF1000AFA200248FA300148FA200248F760040AC -:10DF200000431021AF6200408FA2003C9364003692 -:10DF30008F630040028290213402FFFF00821004B0 -:10DF400000621821AF6300488FA6003030C200087D -:10DF50001040000E000000008F62005816420004BE -:10DF600030C600FF9742011A5040000134C600102D -:10DF700093C500088FA700340200202100052B0064 -:10DF800034A500800E000C8D30A5F0808F6200401B -:10DF900000561023184000178FA200183C020800FA -:10DFA0008C423198304200101040000924020001D8 -:10DFB000976200681440000624020001A76200680E -:10DFC0009742007A2442000A0A000E47A762001214 -:10DFD000A76200120E0011B3020020219362007D9F -:10DFE0002403000102002021344200010A000E45F2 -:10DFF000AFA300381840000A000000000E0011B363 -:10E00000020020219362007D2403000102002021F0 -:10E01000AFA30038344200040E0011BCA362007D9F -:10E020009362003E304200401440000C3262000116 -:10E030001040000A000000008F6300408FC20004FF -:10E0400024040018246300010040F809AF63004075 -:10E050008FA200300A000E8E304200048F620058FA -:10E0600010520010000000008F62001802221023DE -:10E070001C400008240200018F62001816220009CB -:10E08000000000008F62001C028210230440000583 -:10E0900024020001AF720058AFA20038AF7100181F -:10E0A000AF74001C12E0000B8FA300380E0011B3F8 -:10E0B00002002021A377003F0E0011BC02002021A6 -:10E0C00002E03021240400370E0013240000282130 -:10E0D0008FA3003810600003000000000E000C9BAE -:10E0E0000200202112A00005000018218FA200309C -:10E0F0003042000450400011006010212403000150 -:10E100000A000E8E006010210E0011B302002021C3 -:10E110009362007D02002021344200040E0011BCF5 -:10E12000A362007D0E000C9B020020210A000E8ECF -:10E1300024020001AF400044240200018FBF0064AC -:10E140008FBE00608FB7005C8FB600588FB500544B -:10E150008FB400508FB3004C8FB200488FB1004491 -:10E160008FB0004003E0000827BD00688C870004E2 -:10E170008C8600000000102100E5382100E5282BE6 -:10E1800000C2302100C53021AC87000403E0000844 -:10E19000AC8600008F4201B80440FFFE2402080054 -:10E1A000AF4201B803E00008000000003C02000894 -:10E1B0000342282194A200483084FFFF1040001B36 -:10E1C0002484001294A200483042FFFF0044102A29 -:10E1D00010400017240200032402001A9343012078 -:10E1E000A342018B8F820008306300FF3042400061 -:10E1F000104000092463FFFE94A200483042FFFF54 -:10E200000043102B144000058F820014A743019493 -:10E210000A000EC8344200018F8200142403FFFE5E -:10E220000043102403E00008AF820014240200031E -:10E2300003E00008A342018B27BDFFE0AFB2001846 -:10E24000AFB10014AFB00010AFBF001C30B1FFFF82 -:10E2500030D0FFFF30F2FFFF8F4201B80440FFFED5 -:10E2600000000000AF440180AF4400200E000EAA61 -:10E27000020020218F8300088F840014A751018C95 -:10E28000A750018EA74301908F8300043082800045 -:10E29000AF4301A8A75201881040000E8F820014DE -:10E2A00093420116304200FC24420004005A10211F -:10E2B0008C4240003042FFFF144000068F82001461 -:10E2C0003C02FFFF34427FFF00821024AF82001423 -:10E2D0008F8200142403BFFF00431024A74201A62D -:10E2E0009743010C8F42010400031C003042FFFFE2 -:10E2F00000621825AF4301AC3C021000AF4201B8E8 -:10E300008FBF001C8FB200188FB100148FB00010A7 -:10E3100003E0000827BD002027BDFFE0AFB20018D2 -:10E3200030D2FFFFAF440180AF44002002402021E3 -:10E33000AFB10014AFB0001030F1FFFFAFBF001C51 -:10E340000E000EAA30B0FFFF8F8300142402BFFF1F -:10E35000A750018C006218248F820008A752018EFA -:10E36000A7510188A74301A6A74201903C021000D3 -:10E37000AF4201B88FBF001C8FB200188FB10014DC -:10E380008FB0001003E0000827BD00202743018064 -:10E390008F4201B80440FFFE24022000A46200085E -:10E3A00024020002A062000BA46000103C021000D6 -:10E3B000AF4201B803E00008000000008F47007082 -:10E3C000934201128F83000827BDFFF0304200FF07 -:10E3D000000228823062010000003021104000431A -:10E3E00024A400033062400010400010306220007E -:10E3F00000041080005A10218C43400024A4000423 -:10E4000000041080AFA30000005A10218C4240008D -:10E41000AFA2000493420116304200FC005A1021C2 -:10E420008C4240000A000F56AFA200081040002F97 -:10E430000000302100041080005A10218C4340005D -:10E4400024A4000400041080AFA30000005A10218F -:10E450008C424000AFA00008AFA200048FA80008C3 -:10E460000000302100002021240A00083C09080097 -:10E470002529010003A41021148A000300042A00A6 -:10E480001100000A000000009042000024840001F6 -:10E490002C83000C00A210210002108000491021E2 -:10E4A0008C4200001460FFF300C230263C040800D8 -:10E4B0008C8431048F4200702C830020106000098E -:10E4C000004738233C03080024633108000410800F -:10E4D0000043102124830001AC4700003C010800E8 -:10E4E000AC233104AF8600042406000100C01021D3 -:10E4F00003E0000827BD00103C0208008C420038F1 -:10E5000027BDFFD0AFB50024AFB3001CAFBF0028BC -:10E51000AFB40020AFB20018AFB10014AFB000101C -:10E520003C15080026B50038144000022453FFFFB4 -:10E53000000098218F840008308240001040000ABB -:10E54000308280003C0200200082102450400006EF -:10E55000308280008F8200142403BFFF00831824C0 -:10E560000A000FA2344210001040000A3C020020B2 -:10E5700000821024104000078F8200143C03FFFF2C -:10E5800034637FFF0083182434428000AF8200147C -:10E59000AF8300080E000F2E00000000144000089A -:10E5A0008F8400089743011E9742011C3063FFFFD0 -:10E5B0000002140000621825AF8300048F84000855 -:10E5C0009742010C30831000106000113046FFFFAD -:10E5D000308200201440000F241200053C0210007D -:10E5E000008210241040000B241200013C030E0096 -:10E5F0003C020DFF008318243442FFFF0043102B20 -:10E6000010400004000000000A000FC4241200059E -:10E61000241200013C0508008CA5003454A0001908 -:10E620008F8400088F82001C544000168F840008DD -:10E630008F82001430424000544000128F84000842 -:10E640003C021F01008210243C0310001443000D03 -:10E650008F84000830C202001440000B3C0200010D -:10E660009746010E364700020000202124C6000410 -:10E6700030C6FFFF0E000F05240500020A00108DB2 -:10E680008FBF00283C020001008210241040000CC3 -:10E690008F8300143C0208008C4200D89746010E7C -:10E6A000240400802442000130C6FFFF240500023C -:10E6B0003C010800AC2200D80A00108A240700039D -:10E6C00030624000104000063C0210003C020F0087 -:10E6D0000082102450400001934201163C021000B9 -:10E6E0000082102410400044000000003C0208009A -:10E6F0008C4200301040000C306240001040000A94 -:10E700003C030F00008318243C0201000043102B3F -:10E7100014400005000000009746010E3647000235 -:10E720000A0010872404008010A0000D3082010030 -:10E730001040000B3C020F00008210243C0302003A -:10E74000104300078F82000400531024005510214D -:10E7500090420004244200040A00103A000221C042 -:10E76000000000008F8600083C0508008CA500D042 -:10E77000000616023050000F38A200012C420001A2 -:10E780002E03000C0043102414400018001021C078 -:10E790002602FFFC2C4200045440001400002021FB -:10E7A00038A200022C420001004310241040000354 -:10E7B000000612420A00103A000020210010182B17 -:10E7C0000043102450400009001021C09746010E5C -:10E7D000000020212405000224C6000430C6FFFFEB -:10E7E0000E000ECD3247FFFB001021C09746010EF0 -:10E7F0000A001087364700028F4240003C11080093 -:10E800008E310024304201001040004032220001CD -:10E810000220802110A00017325400043082010031 -:10E8200010400015240200013C020F000082102459 -:10E830003C0302001043000F8F8200049746010E34 -:10E840000240382100531024005510219044000448 -:10E8500024C6000430C6FFFF24840004000421C045 -:10E860000E000ECD240500022402FFFE02228024A9 -:10E870003252FFFB2402000116020007320200019F -:10E880003242000450400001365200029746010E09 -:10E890000A001086024038211040000A32020004AB -:10E8A0009746010E024038210000202124C60004B2 -:10E8B00030C6FFFF0E000ECD240500023252FFFBD2 -:10E8C000320200041040000B8F8200083042080022 -:10E8D00010400008000000009746010E0240382159 -:10E8E0002404010024C6000430C6FFFF0E000ECD34 -:10E8F00024050002568000108FBF00280E000F2252 -:10E90000000000000A00108D8FBF00281040000A90 -:10E910008FBF00289746010E3647000200002021D5 -:10E9200024C6000430C6FFFF240500020E000ECDF1 -:10E93000000000008FBF00288FB500248FB4002096 -:10E940008FB3001C8FB200188FB100148FB000106D -:10E950000000102103E0000827BD0030274301809C -:10E960008F4201B80440FFFE000000008F420148C2 -:10E9700000021402A462000824020002A062000B3C -:10E980008F420148A46200108F420144AC6200240F -:10E990003C02100003E00008AF4201B827BDFFE8C9 -:10E9A000AFB000103C04600CAFBF00148C8250006C -:10E9B0002403FF7F3C1A8000004310243442380CAB -:10E9C000AC825000240200033C106000AF420008FB -:10E9D0008E0208083C1B80083C010800AC20002087 -:10E9E0003042FFF0384200102C4200010E001B396B -:10E9F000AF8200003C04FFFF3C02040034830806A1 -:10EA00003442000CAE021948AE03194C3C056016A6 -:10EA10008E0219808CA30000344202000064182486 -:10EA2000AE0219803C0253531462000334A47C00EC -:10EA30008CA20004005020218C82007C8C83007802 -:10EA40008FBF00148FB0001027BD0018AF820018D0 -:10EA500003E00008AF83001027BDFFE8AFBF001040 -:10EA60008F4340003402FFFF3C040800248400F080 -:10EA700010620007000000008F4240003C040800C4 -:10EA8000248400E83042010010400009000000002A -:10EA90009745010E0E000E9A30A5FFFF9745010E17 -:10EAA0003C040800248431C80A0010FC8FBF001009 -:10EAB0008F4340008F8200103C040800248400E053 -:10EAC0001462000A000000008F4340048F82001887 -:10EAD00014620006000000009745010E3C04080087 -:10EAE000248431B80A0010FC8FBF00109745010E36 -:10EAF0008FBF001030A5FFFF0A000E9A27BD001837 -:10EB000027BDFFE8AFBF00108F420128AF420020B1 -:10EB10008F4201048F430100AF8200080E000EA453 -:10EB2000AF8300140E0010D5000000003C02080066 -:10EB30008C4200C0104000088F8400083C0208008E -:10EB40008C4200C4244200013C010800AC2200C4F5 -:10EB50000A001135000000003C0200100082102461 -:10EB60001440000A8F8300143C0208008C420020ED -:10EB7000244200013C010800AC2200200E000F7D61 -:10EB8000000020210A001133000000002402BFFF12 -:10EB9000006210241040000800000000240287FFDB -:10EBA00000621024144000083C020060008210241F -:10EBB00010400005000000000E000CC50000000021 -:10EBC0000A001133000000000E00119D000000003B -:10EBD000104000063C0240008F4301243C026020AC -:10EBE000AC430014000000003C024000AF4201387A -:10EBF000000000008FBF001003E0000827BD0018D0 -:10EC000027BDFFE8AFBF00108F4201403C04400029 -:10EC1000AF4200208F4301483C027000006218247C -:10EC2000106400100083102B144000063C026000AA -:10EC30003C02200010620007000000000A00115F83 -:10EC40003C0240001062000B3C0240000A00115FD1 -:10EC5000000000000E001096000000000A00115F86 -:10EC60003C0240000E0011C1000000000A00115FCC -:10EC70003C0240000E001B46000000003C02400029 -:10EC8000AF420178000000008FBF001003E00008D1 -:10EC900027BD001827BDFFE8AFBF00140E0010A667 -:10ECA000AFB000103C028000344200708C43000082 -:10ECB00000403821AF830020006030218CE8000044 -:10ECC0003C0508008CA500FC3C0408008C8400F87E -:10ECD000010630230000102100A6282100A6302BB9 -:10ECE00000822021008620213C010800AC2500FC88 -:10ECF0003C010800AC2400F88F50000032020003F1 -:10ED00001040FFEE010030218CE600003C050800B9 -:10ED10008CA500FC3C0408008C8400F800C830235B -:10ED200000A628210000102100A6302B00822021FF -:10ED300000862021320700013C010800AC2500FCC0 -:10ED4000AF8800203C010800AC2400F810E000046B -:10ED5000320200020E0010FF00000000320200022A -:10ED60005040FFD13C0280000E00113F0000000027 -:10ED70000A0011693C0280008F4201003042003ECF -:10ED80001440001124020001AF4000488F420100EE -:10ED9000304207C01040000500000000AF40004CAA -:10EDA000AF40005003E0000824020001AF400054CF -:10EDB000AF4000408F420100304238005440000113 -:10EDC000AF4000442402000103E0000800000000FE -:10EDD0003C0290003442000100822025AF44002014 -:10EDE0008F4200200440FFFE0000000003E0000806 -:10EDF000000000003C028000344200010082202517 -:10EE000003E00008AF44002027BDFFE0AFB20018C8 -:10EE1000AFBF001CAFB10014AFB000108F50014065 -:10EE20008F5101483C0280000011940202222024EC -:10EE3000324300FF2402000E1062008A2862000F95 -:10EE40001040001228620037240200061062003BC6 -:10EE50002862000710400007240200091060001A11 -:10EE60002402000110620025000000000A00127652 -:10EE7000000000001062007B2402000B1062005BA7 -:10EE80003222FFFF0A001276000000001040000846 -:10EE90002402003828620035104000802402001F40 -:10EEA0001062007E000000000A00127600000000E0 -:10EEB0001062007A2402008010620042000000000C -:10EEC0000A001276000000008F4201B80440FFFEE5 -:10EED00024020001AF500180AF400184A752018895 -:10EEE000A342018A24020002A342018BA751019090 -:10EEF0008F4201440A001271AF4201A41080000A3F -:10EF0000240200023C010800A02271783C010800A4 -:10EF1000AC3071808F4201443C010800AC22717C0E -:10EF20000A0012788FBF001C8F4201B80440FFFE18 -:10EF3000240200020A00125B000000008F4201B8A8 -:10EF40000440FFFE00000000AF5001803C020800BA -:10EF50009042717810400003000018213C03080023 -:10EF60008C637180AF430184A75201883C02080082 -:10EF7000904271780000182134420001A342018AB6 -:10EF800024020002A342018BA75101908F42014449 -:10EF9000AF4201A43C020800904271781040000387 -:10EFA0003C0210003C0308008C63717CAF4301A855 -:10EFB000AF4201B83C010800A02071780A00127825 -:10EFC0008FBF001C8F4201B80440FFFE24020002E4 -:10EFD000A342018BA7520188A75101908F4201449F -:10EFE000A74201920A0012733C0210001440001D57 -:10EFF0000000000093620005304200041440003716 -:10F00000000000000E0011B30200202193620005F1 -:10F0100002002021344200040E0011BCA36200054E -:10F02000936200053042000414400002000000001A -:10F030000000000D9362000024030020304200FF16 -:10F0400014430008000000008F4201B80440FFFE96 -:10F0500024020005AF500180A342018B3C02100046 -:10F06000AF4201B88F4201B80440FFFE2402000203 -:10F07000AF400180AF500184A7520188A342018AAA -:10F08000A342018BA7510190AF4001A48F420144DC -:10F09000AF4201A80A0012733C0210008F4201B86F -:10F0A0000440FFFE24020001AF500180AF40018404 -:10F0B000A7520188A342018A24020002A342018BC5 -:10F0C000A7510190AF4001A4AF4001A83C0210003D -:10F0D000AF4201B80A0012788FBF001C0000000D7B -:10F0E0008FBF001C8FB200188FB100148FB00010BA -:10F0F00003E0000827BD002027BDFFE8AFBF0010D8 -:10F100000E000EA400000000AF4001808FBF001071 -:10F11000000020210A000F7D27BD00183084FFFF6A -:10F1200030A5FFFF0000182110800007000000003C -:10F1300030820001104000020004204200651821C6 -:10F140000A0012890005284003E000080060102131 -:10F1500010C0000624C6FFFF8CA2000024A50004F6 -:10F16000AC8200000A0012932484000403E000082B -:10F170000000000010A0000824A3FFFFAC860000E0 -:10F1800000000000000000002402FFFF2463FFFFD6 -:10F190001462FFFA2484000403E000080000000069 -:10F1A00027BDFFE0AFB20018AFB10014AFB0001040 -:10F1B000AFBF001C9482000C00A088212490001492 -:10F1C0000002130200021080008290210000302112 -:10F1D00000A020210E00129C240500050212102B15 -:10F1E0001040005700001021920300002C6200091B -:10F1F0005040005192020001000310803C030800BF -:10F20000246370DC004310218C42000000400008A1 -:10F2100000000000920300012402000C1462004868 -:10F2200024020001025010232C42000A1440003630 -:10F23000261000028E22000034420100AE2200009F -:10F240009202000092030001920400029205000362 -:10F2500000031C00000216000043102500042200D9 -:10F26000004410250045102526100004AE2200049D -:10F270009202000092030001920400029205000332 -:10F280000002160000031C000043102500042200A9 -:10F290000044102500451025261000040A0012B66F -:10F2A000AE2200089203000124020004146200163A -:10F2B0002610000292020000920400018E2300003A -:10F2C00000021200004410253463000426100002DE -:10F2D000AE22000C0A0012B6AE2300009203000119 -:10F2E0002402000314620008261000028E2200008F -:10F2F000920300002610000134420008A2230010EF -:10F300000A0012B6AE2200000A00130F2402000108 -:10F31000920300012402000210620002260400028F -:10F32000024020210A0012B6008080210A0012B695 -:10F3300026100001920200010A0012B6020280218A -:10F340008FBF001C8FB200188FB100148FB0001057 -:10F3500003E0000827BD002027BDFFE8AFBF001471 -:10F36000AFB000100E0011B3008080219362007DC9 -:10F3700002002021344200200E0011BCA362007D57 -:10F38000020020218FBF00148FB000100A000C9BD8 -:10F3900027BD0018308300FF30A500FF30C600FFF6 -:10F3A000274701808F4201B80440FFFE00000000A3 -:10F3B0008F42012834634000ACE2000024020001C7 -:10F3C000ACE00004A4E30008A0E2000A240200026A -:10F3D000A0E2000B3C021000A4E50010ACE0002409 -:10F3E000ACE00028A4E6001203E00008AF4201B838 -:10F3F00027BDFFE8AFBF00109362003F2403001257 -:10F40000304200FF1043000D008030218F62004425 -:10F41000008210230440000A8FBF00108F62004852 -:10F42000240400390000282100C2102304410004F4 -:10F43000240600120E001324000000008FBF0010ED -:10F440002402000103E0000827BD001827BDFFC803 -:10F45000AFB1002C00A08821AFB2003027A500106A -:10F460000080902102202021AFBF00340E0012A79F -:10F47000AFB0002810400009024020218E22000871 -:10F48000AF6200840E001315AF6000402404003802 -:10F490002405008D0A0013D1240600129362003463 -:10F4A000936300378F640084304200FF306300FFB5 -:10F4B0000043282100A4202B1080000B0000000036 -:10F4C0009763003C8F6200843063FFFF0045102388 -:10F4D0000062182B14600004000000008F6200849A -:10F4E0000A00137B004580239762003C3050FFFFE9 -:10F4F0008FA3001030620004504000032E02021857 -:10F500008FA2001C0202102B1440000502002021D3 -:10F510003062000410400002240402188FA4001C72 -:10F520002C82008010400002008080212410008086 -:10F530000E0011B30240202124020001AF62000C32 -:10F540009362003E001020403042007FA362003EE4 -:10F550008E22000424420001AF620040A770003CEC -:10F560008F6200509623000E00431021AF620058B6 -:10F570008F62005000441021AF62005C8E220004B4 -:10F58000AF6200188E220008AF62001C8FA200102C -:10F59000304200085440000A93A20020A3600036C5 -:10F5A000936200362403FFDFA36200359362003EBE -:10F5B00000431024A362003E0A0013B18E2200080B -:10F5C000A36200358E220008AF62004C8F620024D7 -:10F5D0008F63004000431021AF6200489362000037 -:10F5E00024030050304200FF144300122403FF8024 -:10F5F0003C0208008C4231A002421021004310243A -:10F60000AF4200283C0208008C4231A08E24000842 -:10F610003C03000C024210213042007F03421021C3 -:10F6200000431021AC4400D88E230008AF8200288C -:10F63000AC4300DC0E0011BC024020212404003841 -:10F64000000028212406000A0E00132400000000F8 -:10F650008FBF00348FB200308FB1002C8FB00028E4 -:10F660002402000103E0000827BD003827BDFFE8A1 -:10F67000AFBF001090C7000D00C0282130E6001079 -:10F6800010C0000A30E200048CA300088F6200540E -:10F690001062000630E20004144000178FBF001013 -:10F6A000000020210A000CB227BD00181040000DF8 -:10F6B00030E3001210C000108FBF00108CA30008B0 -:10F6C0008F6200541462000D2402000124040038EB -:10F6D0002405008D0E001324240600120A0013FDD9 -:10F6E0008FBF001024020012146200038FBF0010AD -:10F6F0000A00135227BD00182402000103E000088D -:10F7000027BD001827BDFFF827420180AFA20000E7 -:10F71000308A00FF8F4201B80440FFFE0000000065 -:10F720008F4601283C0208008C4231A02403FF8050 -:10F73000AF86005000C2102100431024AF420024C5 -:10F740003C0208008C4231A08FA900008FA8000065 -:10F7500000C210213042007F034218213C02000AFF -:10F7600000621821946400D48FA700008FA50000C8 -:10F7700024020002AF830028A0A2000B8FA3000088 -:10F78000354260003084FFFFA4E200083C02100014 -:10F79000AD260000AD040004AC60002427BD0008C5 -:10F7A000AF4201B803E00008240200018C8200048B -:10F7B0008F83002800451023AC8200049062006310 -:10F7C0003042007FA06200638C820020938300306F -:10F7D0008F85002834420002AF830044A780004296 -:10F7E000AC820020A4A000E490A200632403FFBF29 -:10F7F0000043102403E00008A0A200632743018017 -:10F800008F4201B80440FFFE8F820050AC620000BE -:10F810008F420124AC62000424026083A4620008C9 -:10F8200024020002A062000B3C02100003E000086A -:10F83000AF4201B88F880044938200308F83002844 -:10F840003C07080024E7759400481023304200FF6D -:10F85000304900FC246500888F860048304A000348 -:10F860001120000900002021248200048CA3000044 -:10F87000304400FF0089102AACE3000024A50004F6 -:10F880001440FFF924E70004114000090000202182 -:10F890002482000190A30000304400FF008A102B56 -:10F8A000A0E3000024A500011440FFF924E70001B3 -:10F8B00030C20003144000048F850044310200036D -:10F8C0001040000D0000000010A0000900002021E1 -:10F8D0002482000190C30000304400FF0085102BFB -:10F8E000A0E3000024C600011440FFF924E7000152 -:10F8F00003E00008000000001100FFFD00002021CF -:10F90000248200048CC30000304400FF0088102BC8 -:10F91000ACE3000024C600041440FFF924E700040F -:10F9200003E00008000000008F8300449382003051 -:10F9300030C600FF30A500FF00431023304300FF16 -:10F940008F820028008038210043102114C000025B -:10F95000244800880083382130E200031440000569 -:10F9600030A2000314400003306200031040000D79 -:10F970000000000010A000090000202124820001E6 -:10F9800090E30000304400FF0085102BA10300002D -:10F9900024E700011440FFF92508000103E00008F6 -:10F9A0000000000010A0FFFD0000202124820004C0 -:10F9B0008CE30000304400FF0085102BAD030000F5 -:10F9C00024E700041440FFF92508000403E00008C0 -:10F9D0000000000027BDFFF82402FFFFAFA20000D7 -:10F9E000008038212405002F3C0908002529719446 -:10F9F000240800FF2406FFFF90E2000024A3FFFF7D -:10FA00000006220200C21026304200FF00021080D1 -:10FA1000004910218C420000306500FF24E70001FE -:10FA200014A8FFF50082302600061027AFA20004BC -:10FA3000AFA200000000282127A6000400C5102363 -:10FA40009044000324A2000100BD1821304500FFAE -:10FA50002CA200041440FFF9A06400008FA2000053 -:10FA600003E0000827BD00080080482130AAFFFFFE -:10FA700030C600FF30E7FFFF274801808F4201B802 -:10FA80000440FFFE8F820050AD0200008F4201242F -:10FA9000AD0200048D220020A5070008A102000A83 -:10FAA00024020016A102000B934301208D220008BE -:10FAB0008D240004306300FF00431021978300422F -:10FAC000004410218D250024004310233C0308002E -:10FAD0008C6331A08F840028A502000C246300E809 -:10FAE0002402FFFFA50A000EA5030010A5060012C0 -:10FAF000AD050018AD020024948201142403FFF721 -:10FB00003042FFFFAD0200288C820118AD02002CAC -:10FB10003C021000AD000030AF4201B88D22002041 -:10FB20000043102403E00008AD2200208F8200284B -:10FB300030E7FFFF00804821904200D330A5FFFF4F -:10FB400030C600FF0002110030420F0000E23825ED -:10FB5000274801808F4201B80440FFFE8F82005089 -:10FB6000AD0200008F420124AD0200048D2200206E -:10FB7000A5070008A102000A24020017A102000B39 -:10FB8000934301208D2200088D240004306300FF80 -:10FB90000043102197830042004410218F840028E5 -:10FBA000004310233C0308008C6331A0A502000C25 -:10FBB000A505000E246300E8A5030010A5060012A9 -:10FBC000AD0000148D220024AD0200188C82005C70 -:10FBD000AD02001C8C820058AD0200202402FFFF01 -:10FBE000AD020024948200E63042FFFFAD020028FF -:10FBF00094820060948300BE30427FFF3063FFFF39 -:10FC00000002120000431021AD02002C3C02100043 -:10FC1000AD000030AF4201B8948200BE2403FFF76C -:10FC200000A21021A48200BE8D22002000431024D7 -:10FC300003E00008AD220020274301808F4201B875 -:10FC40000440FFFE24020018AC640000A062000B18 -:10FC50008F820028944200E6A46200103C0210004B -:10FC6000AC60003003E00008AF4201B827430180D8 -:10FC70008F4201B80440FFFE8F82002C9442001C8A -:10FC80003042FFFF000211C0AC62000024020019E4 -:10FC9000A062000B3C021000AC60003003E00008E2 -:10FCA000AF4201B88F87003430C300FF8F4201B8E4 -:10FCB0000440FFFE8F82005034636000ACA200005D -:10FCC0009382004CA0A200058CE20010A4A20006C2 -:10FCD000A4A300088C8200202403FFF7A0A2000A3E -:10FCE00024020002A0A2000B8CE20000ACA20010D3 -:10FCF0008CE20004ACA200148CE2001CACA2002434 -:10FD00008CE20020ACA200288CE2002CACA2002CDB -:10FD10008C820024ACA200183C021000AF4201B853 -:10FD20008C8200200043102403E00008AC820020F5 -:10FD30009382004C2403000127BDFFE800433004F8 -:10FD40002C420020AFB00010AFBF00142410FFFE03 -:10FD500010400005274501803C0208008C4231908C -:10FD60000A00159C004610243C0208008C42319485 -:10FD70000046102414400007240600848F830028C6 -:10FD80002410FFFF906200623042000F34420040B6 -:10FD9000A06200620E001568000000000200102141 -:10FDA0008FBF00148FB0001003E0000827BD0018BB -:10FDB0008F83002C27BDFFE0AFB20018AFB1001455 -:10FDC000AFB00010AFBF001C9062000D00A09021EA -:10FDD00030D100FF3042007FA062000D8F850028E7 -:10FDE0008E430018008080218CA2007C14620005E4 -:10FDF0002402000E90A20063344200200A0015C5C0 -:10FE0000A0A200630E00158BA382004C2403FFFF09 -:10FE1000104300472404FFFF52200045000020212A -:10FE20008E4300003C020010006210245040000489 -:10FE30003C020008020020210A0015D4240200150B -:10FE400000621024504000098E450000020020216D -:10FE5000240200140E00158BA382004C2403FFFF24 -:10FE6000104300332404FFFF8E4500003C020002D3 -:10FE700000A21024104000163C0200048F86002CC3 -:10FE80008CC200148CC300108CC4001400431023D7 -:10FE90000044102B50400005020020218E43002C0E -:10FEA0008CC2001010620003020020210A00160517 -:10FEB000240200123C02000400A210245040001C46 -:10FEC00000002021020020210A0016052402001350 -:10FED00000A21024104000068F83002C8C620010BA -:10FEE00050400013000020210A0015FF02002021CD -:10FEF0008C620010504000048E42002C0200202131 -:10FF00000A001605240200115040000900002021BB -:10FF100002002021240200170E00158BA382004C42 -:10FF20002403FFFF104300022404FFFF00002021F0 -:10FF30008FBF001C8FB200188FB100148FB000105B -:10FF40000080102103E0000827BD002093830030CB -:10FF500027BDFFE024020034AFB20018AFB1001497 -:10FF6000AFBF001CAFB00010008088211462000CED -:10FF700000A090218F8400340E0014B48C900030C7 -:10FF80001202000724020005022020210E00158B1A -:10FF9000A382004C2403FFFF1043005F2404FFFFF3 -:10FFA00092420004104000098F8200280220202184 -:10FFB0002402000C0E00158BA382004C2403FFFFCB -:10FFC000104300552404FFFF8F820028A3800024E3 -:10FFD0008E4300048C4400803C0200FF3442FFFF4B -:10FFE000006218240083202B10800008AF83003C9F -:10FFF00002202021240200190E00158BA382004C40 -:020000040001F9 -:100000002403FFFF104300442404FFFF97820042B3 -:100010008F8700448F88003C00471023110000396F -:10002000A78200428F8600283045FFFF8F84005052 -:1000300090C300BC3C0208008C4231A0000318822F -:100040003070000100822021001010800102102178 -:1000500000A2282B10A00010248200888F84003476 -:100060001082000D3C033F018E420000004310242B -:100070003C0325001443000630E500FF8C8200009D -:10008000ACC200888C8200100A001665ACC20098D1 -:100090000E001489000030218F85003C93830024DA -:1000A0008F86002830A20003000210233042000394 -:1000B00000433821A387002494C400E400A228212F -:1000C0008F8300448F82004834841000A4C400E46D -:1000D00000431021AF8200481200000EAF8500449B -:1000E00024E20004A382002494C200E424A30004B8 -:1000F000AF83004434422000A4C200E40A00168505 -:10010000000020218F820048AF800044004710216A -:10011000AF820048000020218FBF001C8FB2001862 -:100120008FB100148FB000100080102103E0000890 -:1001300027BD00208F86002827BDFFE8AFBF001431 -:10014000AFB0001090C200633042002010400008A1 -:1001500030A500FF8CC2007C2403FFDF2442000195 -:10016000ACC2007C90C2006300431024A0C20063B4 -:1001700010A000238F83002827500180020028212F -:100180000E001568240600828F82002890420063CA -:100190003042004050400019A380004C8F8300344F -:1001A0008F4201B80440FFFE8F820050AE02000073 -:1001B00024026082A602000824020002A202000BB0 -:1001C0008C620008AE0200108C62000CAE020014BB -:1001D0008C620014AE0200188C620018AE0200247B -:1001E0008C620024AE0200288C620028AE02002C33 -:1001F0003C021000AF4201B8A380004C8F8300285E -:100200008FBF00148FB000109062006327BD0018EC -:100210003042007FA0620063978200428F860044D4 -:100220008F8500289383003000461023A782004268 -:10023000A4A000E490A400638F820048AF83004430 -:100240002403FFBF0046102100832024AF82004812 -:10025000A0A400638F820028A04000BD8F820028E8 -:1002600003E00008A44000BE8F8A002827BDFFE0FD -:10027000AFB10014AFB000108F880044AFBF0018BA -:1002800093890024954200E430D100FF0109182B26 -:100290000080802130AC00FF3047FFFF0000582174 -:1002A00014600003310600FF0120302101095823AA -:1002B000978300420068102B1440003200000000B9 -:1002C00014680007240200018E0200202403FFFBB3 -:1002D00034E7800000431024AE0200202402000115 -:1002E00034E70880158200053165FFFF0E0014D940 -:1002F000020020210A00171A020020210E00150A10 -:10030000020020210E00154D8F8400508F8400289C -:100310009482006024420001A48200609482006004 -:100320003C0308008C63318830427FFF5443000F48 -:1003300002002021948200602403800000431024E6 -:10034000A48200609082006090830060304200FFD1 -:10035000000211C200021027000211C03063007FAA -:1003600000621825A08300600200202102202821BD -:100370008FBF00188FB100148FB000100A00168CC8 -:1003800027BD0020914200632403FF800043102515 -:10039000A1420063978200423048FFFF1100002015 -:1003A000938300248F840028004B1023304600FFE5 -:1003B000948300E42402EFFF0168282B00621824D4 -:1003C000A48300E414A000038E0200200100582141 -:1003D000000030212403FFFB34E780000043102499 -:1003E000AE02002024020001158200053165FFFFE6 -:1003F0000E0014D9020020210A0017429783004200 -:100400000E00150A02002021978300428F820044CB -:10041000A780004200431023AF820044938300244E -:100420008F8200288FBF00188FB100148FB000108A -:1004300027BD002003E00008A04300BD8F820028F4 -:1004400090430088904500BD244900883063003FF8 -:100450002463FFE024020001006238042C630020C2 -:1004600030E80019A385002410600010AF89003423 -:100470003C028000344200022405000124060001F1 -:100480001500000800E2182400002821146000056F -:1004900030E20020104000052405000191260001F3 -:1004A00030C600010A0016D90000000003E0000871 -:1004B0000000000027BDFFD8AFB000108F900034BF -:1004C000AFB40020AFB10014AFBF0024AFB3001C25 -:1004D000AFB200188E0500103C0208008C4231B00B -:1004E0008F86003830A33FFF0062182B8CD3001496 -:1004F000008088218CD20020106000780000A021AC -:1005000090C3000D2402FF8000431024304200FFFE -:100510005040007302202021000513823042000366 -:100520005440006F0220202194C3001C8F820028B9 -:100530008E050028A44301148CC200100262182307 -:10054000146500072402001F8F82003C0062102106 -:100550000262102B104000088F83002C2402001828 -:100560000E00158BA382004C2403FFFF1043006F85 -:100570002404FFFF8F83002C8F84003C8C620010CA -:100580000244902100441023AC6200108F820028A6 -:10059000AC7200208C4200680052102B1040000901 -:1005A0008F830038022020212402001D0E00158BAD -:1005B000A382004C2403FFFF1043005C2404FFFFD0 -:1005C0008F8300388E0200248C63002410430007C0 -:1005D000022020212402001C0E00158BA382004C57 -:1005E0002403FFFF104300512404FFFF8F84002CDD -:1005F0008C82002424420001AC82002412530004A7 -:100600008F8200288C4200685642000E8E02000045 -:100610008E0200003C030080004310241440000DB3 -:100620002402001A022020210E00158BA382004C08 -:100630002403FFFF1043003D2404FFFF0A0017D6E8 -:100640008E0200143C03008000431024504000033D -:100650008E020014AC8000208E0200142412FFFFD2 -:10066000105200062402001B022020210E00158BD0 -:10067000A382004C1052002D2404FFFF8E030000C3 -:100680003C020001006210241040001F3C02008068 -:100690000062102414400008022020212402001AC5 -:1006A0000E00158BA382004C2403FFFF1043001F94 -:1006B0002404FFFF02202021020028210E0015AB98 -:1006C000240600012403FFFF2404FFFF1443000E4F -:1006D000241400010A00180B8FBF002402202021DF -:1006E0002402000D8FBF00248FB400208FB3001CA4 -:1006F0008FB200188FB100148FB0001027BD0028F2 -:100700000A00158BA382004C8F83002C022020212D -:100710000280302194620036240500012442000149 -:100720000E0016D9A4620036000020218FBF0024DD -:100730008FB400208FB3001C8FB200188FB100144B -:100740008FB000100080102103E0000827BD0028B2 -:100750008F83002827BDFFD8AFB40020AFB3001CA3 -:10076000AFB20018AFB10014AFB00010AFBF00249B -:10077000906200638F9100342412FFFF34420040E6 -:1007800092250000A06200638E2200100080982154 -:1007900030B0003F105200060360A0212402000D7B -:1007A0000E00158BA382004C105200522404FFFF50 -:1007B0008F8300288E2200188C63007C1043000772 -:1007C000026020212402000E0E00158BA382004C33 -:1007D0002403FFFF104300472404FFFF24040020EC -:1007E000120400048F8300289062006334420020CA -:1007F000A06200638F85003C10A0001E0000000076 -:10080000560400048F820028026020210A00185537 -:100810002402000A9683000A2404FFFD944200602B -:100820003042FFFF104300348FBF00243C02080019 -:100830008C42318C0045102B1440000602602021B0 -:10084000000028210E0016D9240600010A00187C99 -:10085000000020212402002D0E00158BA382004CE5 -:100860002403FFFF104300232404FFFF0A00187C29 -:1008700000002021160400058F8400288E23001418 -:100880002402FFFF50620018026020219482006061 -:1008900024420001A4820060948200603C030800AE -:1008A0008C63318830427FFF5443000F0260202167 -:1008B000948200602403800000431024A48200601E -:1008C0009082006090830060304200FF000211C2FD -:1008D00000021027000211C03063007F006218255B -:1008E000A0830060026020210E00168C2405000108 -:1008F000000020218FBF00248FB400208FB3001C84 -:100900008FB200188FB100148FB00010008010213A -:1009100003E0000827BD00288F83002827BDFFE8DB -:10092000AFB00010AFBF0014906200638F87003437 -:1009300000808021344200408CE60010A0620063F9 -:100940003C0308008C6331B030C23FFF0043102BE2 -:100950001040004E8F8500382402FF8090A3000DC8 -:1009600000431024304200FF504000490200202183 -:10097000000613823048000324020002550200449E -:100980000200202194A2001C8F850028240300234C -:10099000A4A201148CE60000000616023042003FBB -:1009A000104300103C0300838CE300188CA2007CF1 -:1009B000106200062402000E0E00158BA382004C6C -:1009C0002403FFFF104300382404FFFF8F83002817 -:1009D0009062006334420020A06200630A0018C1E4 -:1009E0008F83002C00C31024144300078F83002C36 -:1009F00090A200623042000F34420020A0A20062A8 -:100A0000A38800408F83002C9062000D3042007F4D -:100A1000A062000D8F83003C1060001802002021AE -:100A20008F8400388C8200100043102B1040000986 -:100A300024020018020020210E00158BA382004C16 -:100A40002403FFFF104300182404FFFF0A0018E9E5 -:100A5000000020218C8200102405000102002021CA -:100A6000004310238F83002C240600010E0016D9AA -:100A7000AC6200100A0018E9000020210E00168C5C -:100A8000240500010A0018E90000202102002021AD -:100A90002402000D8FBF00148FB0001027BD001876 -:100AA0000A00158BA382004C8FBF00148FB000107A -:100AB0000080102103E0000827BD001827BDFFD8E3 -:100AC000AFB000108F900034AFB3001CAFBF002058 -:100AD000AFB20018AFB100148E1200103C03080032 -:100AE0008C6331B032423FFF0043102B1040007C3A -:100AF000008098218F8500382402FF8090A3000D8C -:100B000000431024304200FF504000760260202154 -:100B10000012138230420003240300015443007189 -:100B20000260202190A2000D3042000854400003D2 -:100B30008F82003C0A00191924020024504000034F -:100B40008E03000C0A001919240200278CA2002031 -:100B500014620005240200208E0300088CA20024E9 -:100B600010620008240200200E00158BA382004CA6 -:100B70002403FFFF1043006A2404FFFF0A00194406 -:100B80008F84002C8E0200142411FFFF14510003E7 -:100B90008F8700280A00193F240200258E030018C1 -:100BA0008CE2007C146200162402000E8E030024E6 -:100BB0008CA2002814620012240200218E06002854 -:100BC0008CA2002C14C2000E2402001F8E03002CE5 -:100BD0001060000B240200238CE200680043102BFD -:100BE00014400007240200268CA20014006618217D -:100BF0000043102B504000078F84002C2402002259 -:100C00000E00158BA382004C105100452404FFFFF9 -:100C10008F84002C2403FFF79082000D00431024E2 -:100C2000A082000D8F8600283C0308008C6331AC45 -:100C30008F82005094C400E08F85002C0043102167 -:100C400030847FFF00042040004410213043007FA7 -:100C5000034320213C03000E008320212403FF8056 -:100C600000431024AF42002CA49200008CA2002864 -:100C700024420001ACA200288CA2002C8E03002C80 -:100C800000431021ACA2002C8E02002CACA200303C -:100C90008E020014ACA2003494A2003A2442000157 -:100CA000A4A2003A94C600E03C0208008C4231B095 -:100CB00024C4000130837FFF1462001300803021C0 -:100CC000240280000082302430C2FFFF000213C2E1 -:100CD000304200FF000210270A001981000233C0D1 -:100CE000026020212402000D8FBF00208FB3001C62 -:100CF0008FB200188FB100148FB0001027BD0028EC -:100D00000A00158BA382004C8F82002802602021EC -:100D1000240500010E00168CA44600E000002021EE -:100D20008FBF00208FB3001C8FB200188FB100144A -:100D30008FB000100080102103E0000827BD0028BC -:100D400027BDFFE0AFB100148F910034AFB00010A9 -:100D5000AFBF00188E2600103C0308008C6331B032 -:100D600030C23FFF0043102B1040005E0080802106 -:100D70008F8500382402FF8090A3000D00431024CB -:100D8000304200FF50400058020020218F82003C7A -:100D900010400008000613828F8200289763000A23 -:100DA0002404FFFD944200603042FFFF10430055D1 -:100DB00000061382304200031440000E00000000C1 -:100DC00092220002104000058E230024506000157E -:100DD000922300030A0019BA020020218CA20024E9 -:100DE0005062001092230003020020210A0019C261 -:100DF0002402000F90A2000D304200085440000968 -:100E00009223000302002021240200100E00158B03 -:100E1000A382004C2403FFFF1043003A2404FFFF89 -:100E200092230003240200025462000C9222000369 -:100E30008F82003C544000099222000302002021CE -:100E40002402002C0E00158BA382004C2403FFFF0C -:100E50001043002C2404FFFF9222000302202821CB -:100E600002002021384600102CC600012C4200014F -:100E70000E0015AB004630252411FFFF1051002154 -:100E80002404FFFF8F83003C106000120200202129 -:100E90003C0208008C42318C0043102B14400006A9 -:100EA00000000000000028210E0016D924060001D1 -:100EB0000A001A00000020212402002D0E00158BCC -:100EC000A382004C1051000F2404FFFF0A001A00F7 -:100ED000000020210E00168C240500010A001A00D3 -:100EE00000002021020020212402000D8FBF0018E5 -:100EF0008FB100148FB0001027BD00200A00158BA1 -:100F0000A382004C8FBF00188FB100148FB0001067 -:100F10000080102103E0000827BD002093830040DB -:100F200027BDFFE024020002AFB10014AFB00010F3 -:100F300000808821AFBF0018000080211062008C63 -:100F40002404FFFD978500428F83004430A2FFFFF9 -:100F50000043102B5440007D8F8400480E00144C39 -:100F6000000000003C020800244275940220202169 -:100F7000004028210E001612AF8200342409FFFF22 -:100F80001049007B2404FFFF3C0808008D0875A46D -:100F90003C0208008C4231B03C0308009063759419 -:100FA00031043FFF0082102B1040001B3067003FD0 -:100FB0003C0208008C4231A88F830050000421803D -:100FC00000621821006418213062007F034228214A -:100FD0003C02000C00A228213C02008034420001A7 -:100FE0003066007800C230252402FF8000621024A1 -:100FF000AF42002830640007AF4208048F82002807 -:101000000344202124840940AF460814AF85002CF6 -:10101000AF840038AC4301189383004024020003DE -:101020001462003B240200012402002610E2003D6D -:1010300028E200271040001324020032240200227C -:1010400010E2003828E200231040000824020024A7 -:101050002402002010E200242402002110E2001EDD -:10106000022020210A001A7F2402000B10E2002D2A -:101070002402002510E20010022020210A001A7F1D -:101080002402000B10E2001A28E200331040000690 -:101090002402003F2402003110E2000B0220202134 -:1010A0000A001A7F2402000B10E200110220202106 -:1010B0000A001A7F2402000B0E00176C0220202168 -:1010C0000A001A9A004080210E0018EE022020210A -:1010D0000A001A9A004080210E00198F0220202158 -:1010E0000A001A9A004080211509000E0000000035 -:1010F0000E001813022020210A001A9A00408021B5 -:101100000E00158BA382004C0A001A9A0040802121 -:1011100014620017020020212402002314E20005BB -:101120002402000B0E001885022020210A001A9AC2 -:101130000040802102202021A382004C0E00158B4C -:101140002410FFFF0A001A9B0200202130A500FF97 -:101150000E00148924060001978300428F82004408 -:10116000A780004200431023AF82004402002021E8 -:101170008FBF00188FB100148FB0001000801021B5 -:1011800003E0000827BD002027BDFFE0AFB1001439 -:10119000AFBF0018AFB000108F4601283C03080015 -:1011A0008C6331A02402FF80AF86005000C3182159 -:1011B0003065007F03452821006218243C02000AA4 -:1011C000AF43002400A2282190A200620080882161 -:1011D000AF850028304200FF00021102A3820040C8 -:1011E00090A200BC304200021440000224030034EC -:1011F000240300308F820028A383003093830040B3 -:101200008C4200C0A380004CAF8200442402000442 -:10121000106200308F8400448E2400045080002D22 -:101220008F8400448E2200103083FFFFA784004289 -:101230001060001FAF8200488F8300282405FF80C4 -:10124000022020219062006300A21024304200FF9F -:101250001440000D000000000E001A069790004296 -:1012600010400010004018212402FFFD54620011BC -:101270008E230020020028210E00142A02202021A3 -:101280000A001AEC8E2300209062006300A2102452 -:10129000304200FF10400003022020210E00174EB4 -:1012A00000000000978200421440FFE48F83002872 -:1012B0008E23002030620004104000068F8400441A -:1012C0002402FFFB006210240E00143EAE22002018 -:1012D0008F8400448F8300288FBF00188FB10014C3 -:1012E0008FB000102402000127BD002003E0000899 -:1012F000AC6400C030A500FF2403000124A9000154 -:101300000069102B1040000C00004021240A00014D -:1013100000A31023004A3804246300013082000136 -:101320000069302B104000020004204201074025D4 -:1013300054C0FFF800A3102303E0000801001021AF -:1013400027BDFFE03C021EDCAFB20018AFB10014B5 -:10135000AFBF001CAFB0001034526F4100008821B5 -:10136000240500080E001AFC0220202100118080B4 -:101370003C07080024E771940002160002071821B8 -:10138000AC6200000000282124A200013045FFFFCC -:101390008C6200002CA600080441000200022040DC -:1013A0000092202614C0FFF8AC64000002078021E0 -:1013B0008E0400000E001AFC2405002026230001E4 -:1013C0003071FFFF2E2301001460FFE5AE02000024 -:1013D0008FBF001C8FB200188FB100148FB00010A7 -:1013E00003E0000827BD00203C02080024426A8474 -:1013F0003C010800AC2271883C02080024425000E5 -:101400003C010800AC22718C240200063C0108005B -:10141000A02271900A001B0F0000000027BDFFD81A -:10142000AFB3001CAFB20018AFBF0020AFB10014C3 -:10143000AFB000108F5101408F480148000894025E -:10144000324300FF311300FF8F4201B80440FFFE1A -:1014500027500180AE1100008F420144AE0200040B -:1014600024020002A6120008A202000B24020014AB -:10147000AE130024106200252862001510400008F9 -:101480002402001524020010106200302402001211 -:10149000106200098FBF00200A001C308FB3001CAF -:1014A0001062006724020022106200378FBF002004 -:1014B0000A001C308FB3001C3C0208008C4231A093 -:1014C0002403FF800222102100431024AF42002495 -:1014D0003C0208008C4231A0022210213042007FE1 -:1014E000034218213C02000A00621821166000B372 -:1014F000AF830028906200623042000F3442003017 -:10150000A06200620A001C2F8FBF00203C04600014 -:101510008C832C083C02F0033442FFFF0062182445 -:10152000AC832C083C0208008C4231A08C832C0830 -:101530002442007400021082000214800062182508 -:10154000AC832C080A001C2F8FBF00203C0208002F -:101550008C4231A02403FF8002221021004310247A -:10156000AF4200243C0208008C4231A03C03000A38 -:10157000022210213042007F03421021004310213B -:101580000A001C2EAF8200283C0208008C4231A0C9 -:101590002404FF800222102100441024AF420024C2 -:1015A0003C0208008C4231A0022210213042007F10 -:1015B000034218213C02000A006218219062006375 -:1015C00000821024304200FF1040007CAF830028CE -:1015D00024620088944300123C0208008C4231A827 -:1015E00030633FFF000319800222102100431021C5 -:1015F0003043007F03431821004410243C04000CB6 -:1016000000641821AF4200280E00155AAF83002C49 -:101610008F4201B80440FFFE00000000AE11000040 -:101620008F420144AE02000424020002A612000808 -:10163000A202000BAE1300240A001C2F8FBF002053 -:101640002406FF8002261024AF4200203C0208003E -:101650008C4231A031043FFF00042180022210217E -:1016600000461024AF4200243C0308008C6331A8DC -:101670003C0208008C4231A03227007F022318214F -:1016800002221021006418213042007F3064007F64 -:10169000034228213C02000A0066182400A22821E7 -:1016A000034420213C02000C00822021AF4300288B -:1016B0003C0200080347182100629021AF850028F2 -:1016C000AF84002C0E00155A010080218F4201B812 -:1016D0000440FFFE8F82002C8F8400282745018064 -:1016E0009042000DACB10000A4B00006000216004C -:1016F0000002160300021027000237C214C00016B1 -:10170000248200889442001232033FFF30423FFFA0 -:101710001443001224026082908300632402FF803D -:1017200000431024304200FF5040000C240260822D -:10173000908200623042000F34420040A08200627A -:1017400024026084A4A200082402000DA0A20005C7 -:101750000A001C193C02270024026082A4A200088F -:10176000A0A000053C02270000061C00006218250E -:1017700024020002A0A2000BACA30010ACA0001435 -:10178000ACA00024ACA00028ACA0002C8E42004CE1 -:101790008F84002CACA200189083000D2402FF80DF -:1017A00000431024304200FF104000058FBF00208E -:1017B0009082000D3042007FA082000D8FBF00207C -:1017C0008FB3001C8FB200188FB100148FB00010BF -:1017D0003C02100027BD002803E00008AF4201B81A -:1017E00008004C2808004C2808004BA008004BD8E3 -:1017F00008004C0C08004C3008004C3008004C30FD -:0418000008004B1081 -:0C1804000A0001220000000000000000AB -:101810000000000D747061342E362E313600000049 -:10182000040610010000000000000000000000009D -:1018300000000000000000000000000000000000A8 -:101840000000000000000000000000000000000098 -:101850000000000000000000000000000000000088 -:101860000000000000000000000000000000000078 -:101870000000000000000000000000000000000068 -:101880000000000000000000000000000000000058 -:1018900010000003000000000000000D0000000D1B -:1018A0003C02080024421B803C03080024632014EF -:1018B000AC4000000043202B1480FFFD24420004B4 -:1018C0003C1D080037BD2FFC03A0F0213C10080090 -:1018D000261004883C1C0800279C1B800E00015A1F -:1018E000000000000000000D3084FFFF3082000780 -:1018F0008F85001810400002248300073064FFF831 -:101900000085302130C41FFF03441821247B400090 -:10191000AF85001CAF84001803E00008AF440084CA -:101920003084FFFF308200078F8500208F860028DB -:1019300010400002248300073064FFF80085202156 -:101940000086182B14600002AF8500240086202337 -:101950000344282134068000AF840020AF44008077 -:1019600000A6202103E00008AF84003827BDFFD87F -:10197000AFB3001CAFB20018AFB00010AFBF00246F -:10198000AFB40020AFB100143C0860088D145000C3 -:101990002418FF7F3C1A8000029898243672380C75 -:1019A000AD1250008F5100083C07601C3C086000DD -:1019B00036300001AF500008AF800018AF40008003 -:1019C000AF4000848CE600088D0F08083C076016C5 -:1019D0008CEC000031EEFFF039CA00103C0DFFFF27 -:1019E000340B80003C030080034B48212D44000150 -:1019F000018D28243C0253533C010800AC230420F1 -:101A0000AF890038AF860028AF840010275B400004 -:101A100014A2000334E37C008CF90004032818218D -:101A20008C7F007C8C6500783C0280003452007012 -:101A3000AF85003CAF9F00403C13080026731BC4D9 -:101A40000240A0218E4800008F46000038C30001EC -:101A50003064000110800017AF88003402804821F4 -:101A60008D2D00003C1908008F39045C3C110800E2 -:101A70008E31045801A8F823033F7821000040214B -:101A80000228382101FF802B00F070213C01080062 -:101A9000AC2F045C3C010800AC2E04588F4C0000B5 -:101AA000398B0001316A00011540FFED01A0402192 -:101AB000AF8D00348E4E00003C0C08008D8C045C11 -:101AC0003C0A08008D4A045801C86823018D28216A -:101AD0000000582100AD302B014B20210086102141 -:101AE0003C010800AC25045C3C010800AC22045811 -:101AF0008F4501088F44010030A92000AF85000008 -:101B0000AF84000C1120000A00A030213C0708001F -:101B10008CE7042C24EF00013C010800AC2F042CBE -:101B20003C104000AF5001380A0001900000000056 -:101B300030B002001600001424110F0010910012A2 -:101B400024070D001087023330B000065200FFF565 -:101B50003C104000936D0000240C001031A600F0F2 -:101B600010CC0269240E007010CE02DD8F8B0014A1 -:101B700025670001AF8700143C104000AF500138CA -:101B80000A00019000000000974801041100FFE5E1 -:101B90003C10400030B84000170000A200000000D8 -:101BA0008F5901780720FFFE8F870038240900082D -:101BB000240508008CE30008AF450178A7490140DF -:101BC000A7400142974201048F8600003049FFFF81 -:101BD00030DF000113E002D5012040212524FFFE63 -:101BE000240A0002A74A01463088FFFFA7440148A3 -:101BF0003C0B08008D6B043C156002C48F8F000CF9 -:101C000030C30020146000022404000924040001F1 -:101C100030CD0C00240C040051AC000134840004CD -:101C2000A744014A3C0508008CA504203C0200485A -:101C30003C19000100A2F82530D8000203F928253C -:101C400013000004000018213C04010000A4282512 -:101C50002403000130CA000451400005AF8300088E -:101C60003C06001000A6282524030001AF830008CD -:101C7000AF45100000000000000000000000000060 -:101C8000000000008F8300081060002300000000A7 -:101C90008F4B10000561FFFE000000001060001E69 -:101CA000000000008F4D10003C03002001A36024C1 -:101CB000118000198F8F000031EE000211C0001654 -:101CC00000000000975010141600001300000000E0 -:101CD0009745100830BFFFFF27F800060018C8829C -:101CE0000019308000C7282133110001330300039D -:101CF000122003208CA200000000000D00C7F82174 -:101D0000AFE200003C1908008F390430272600019B -:101D10003C010800AC2604308F6A00003405FFFF48 -:101D2000AF8A00048CE200001045029A00002021D6 -:101D30008CE5000030BF010013E0027E010020218D -:101D40003C0708008CE704743C1008008E10044C1B -:101D500000E858213C1808008F1804700168882B8F -:101D60003C0808008D080448000078210204602126 -:101D7000030F18210184702B010F6821007150217D -:101D800001AE10213C010800AC2C044C3C010800C1 -:101D9000AC2204483C010800AC2B04743C01080050 -:101DA000AC2A04708F8D00180120302131290007E2 -:101DB00025AE000831C21FFF03426021AF8D001C19 -:101DC000AF820018259B4000AF4200841120000321 -:101DD0008F90002024C800073106FFF88F84002868 -:101DE00000D0282100A4782B15E00002AF90002439 -:101DF00000A4282303452021340380000083102100 -:101E00003C061000AF850020AF820038AF4500804F -:101E1000AF4601788F8B0014256700010A0001DDB1 -:101E2000AF8700148F6200088F6700002411003014 -:101E30000007C602330300F0107100A2241900400D -:101E40001479FF4B8F8B00148F4A01780540FFFEF9 -:101E500030A7020014E00003000512820000000D0C -:101E6000000512823050000300104900013070213B -:101E7000000E688001B06021000C58800173802141 -:101E80008E08000015000002000000000000000D98 -:101E90008F6F000405E202B192030006920700056D -:101EA000920F00043C0200010007288000B060216E -:101EB0008D8900182771000825EE00050122682190 -:101EC000000E3082AD8D0018022020210E0005800A -:101ED00026050014920B00068F7F00043C087FFF4C -:101EE000000B2080009130218CC30004350AFFFFD5 -:101EF00003EAC8240079C021ACD800049207000589 -:101F000092090004960D00080007288000B1F8210E -:101F10008FEF0000974201043C07FFFF01E75024C8 -:101F2000304EFFFF01C96021018D58233168FFFF4A -:101F300001482025AFE400009203000724190001A6 -:101F4000107902692406000310660279000000007F -:101F50008E190010241F000AA75F0140A7590142F3 -:101F6000920300048F86000024070001A743014468 -:101F7000A74001469758010430D100023C050041BA -:101F8000A758014800001821A747014A1220000362 -:101F900030CA00043C050141240300015140000502 -:101FA000AF8300083C08001000A828252403000186 -:101FB000AF830008AF4510000000000000000000E3 -:101FC00000000000000000008F8B0008116000047A -:101FD000000000008F4410000481FFFE000000009C -:101FE0008F6A0000920700043C0508008CA5044499 -:101FF000AF8A0004975F01043C0F08008DEF044096 -:1020000030E300FF33F9FFFF0079C02100B86821F9 -:102010000000102124E6000A30C8FFFF01B8482B59 -:1020200001E2702101C96021311000073C01080064 -:10203000AC2D04443C010800AC2C04401200000309 -:102040008F8D0018250B00073168FFF8010D7021F6 -:1020500031CC1FFFAF8D001CAF8C0018AF4C00843B -:1020600097440104034C80213084FFFF308800072F -:1020700011000003261B4000248900073124FFF8CB -:102080008F8200208F850028008220210085782BF8 -:1020900015E00002AF82002400852023034488213C -:1020A00034058000022510213C061000AF8400207A -:1020B000AF820038AF440080AF4601780A00028545 -:1020C0008F8B00148F5F017807E0FFFE30AA0200BB -:1020D00015400003000542820000000D0005428209 -:1020E000310200030002710001C26821000D60800E -:1020F000018248210009288000B380218E0B000056 -:1021000011600002000000000000000D8F6F000C45 -:1021100005E001F38F87003824190001AE19000093 -:102120008CE30008A20000078F78000400181C024E -:10213000306600FF24D10005001130832CC400411B -:1021400014800002A20300040000000D8F6B000445 -:102150003C0EFFFF00E028213164FFFF248F000BBD -:10216000000F408200081080004748218D2D00009C -:1021700026040014A60B000801AE60240E000580A2 -:10218000AD2C00008F5F01083C0A100003EA3824E0 -:1021900010E001A30000000097460104920300072D -:1021A00024D1FFEC346500023224FFFFA2050007B2 -:1021B000960600082CC7001354E0000592030007A0 -:1021C000920A0007355F0001A21F00079203000773 -:1021D000240B0001106B01BA24090003106901CD22 -:1021E0008F88003830CFFFFF25E400020004C88349 -:1021F000333F00FF001F2880A219000500A85821C6 -:102200008D780000975101043C03FFFF0303602415 -:102210003222FFFF004F702325CDFFFE018D4825A0 -:10222000AD690000920600053C02FFF6344EFFFF48 -:1022300030CA00FF000A388000F020219099001475 -:102240003C1FFF7F37E7FFFF3323000F0066782135 -:1022500031F800FF0018288000B088218E2D002062 -:1022600000A86021A20F000601AE4824AE0D000CAC -:10227000AD89000C920B00068E04000C0127F82497 -:10228000000B50800150C821972600260148C0212C -:1022900000874024AF260024AE08000CAF3F00208A -:1022A000AF0600108F860000240C001024090002E5 -:1022B000A74C0140A7400142A7400144A74901465D -:1022C000974B01042407000130C80002256AFFFE75 -:1022D000A74A01483C050009A747014A110000032D -:1022E000000018213C0501092403000130CD000441 -:1022F00051A00005AF8300083C06001000A6282569 -:1023000024030001AF830008AF4510000000000067 -:10231000000000000000000000000000921800040F -:1023200027110002322F0007000F1023304E000744 -:10233000AE0E00108F900008120000040000000094 -:102340008F4310000461FFFE000000008F78000042 -:102350008F8F00183C1008008E100444AF980004C2 -:102360009751010425E6001030CA1FFF3222FFFFFB -:10237000AF8F001CAF8A0018AF4A00842449FFFECB -:102380003C0B08008D6B0440974E0104012068212E -:10239000000967C3020D282131C9FFFF00AD402BA2 -:1023A000016C382100E82021034AF8213139000767 -:1023B0003C010800AC2504443C010800AC24044066 -:1023C0001320000327FB4000252300073069FFF896 -:1023D0008F9F00208F840028013F382100E4C82B04 -:1023E00017200002AF9F002400E438230347202178 -:1023F00034058000008510213C061000AF870020C6 -:10240000AF820038AF470080AF4601780A000285EE -:102410008F8B0014975801041300FDC23C1040003C -:102420008F4301780460FFFE30B9400013200003A1 -:102430003C0400080000000D3C040008AF440140CB -:1024400024080800AF4801788F8B0000974A0104E8 -:10245000317F000113E000E93146FFFF24D0FFFE89 -:10246000240C0002A74C0146A75001488F8F00188A -:102470002405000DA745014A8F71000025E20008E0 -:1024800030491FFF0349702130CD0007AF91000490 -:10249000AF8F001CAF89001800C03821AF490084FD -:1024A00011A0000325DB400024C6000730C7FFF859 -:1024B0008F9800208F84002800F8302100C4382B2A -:1024C00014E00002AF98002400C430238F8A001467 -:1024D00003465821340880000168F821255900017D -:1024E0003C0310003C104000AF860020AF9F003836 -:1024F000AF460080AF430178AF990014AF50013868 -:102500000A000190000000008F6900009744010458 -:102510003127FFFF3088FFFF8F4F017805E0FFFE76 -:1025200030FF0007001F18233078000724E6FFFE65 -:102530002419000AA7590140A7580142A74601449F -:10254000A7400146A74801488F42010830510020AA -:1025500016200002240300092403000130AA00020F -:10256000A743014A3C040041114000030000182128 -:102570003C0401412403000130AB0004516000051C -:10258000AF8300083C0500100085202524030001CE -:10259000AF830008AF4410000000000000000000FE -:1025A00000000000000000008F90000812000004EE -:1025B000000000008F4C10000581FFFE00000000AD -:1025C0008F780000276200088F8D003CAF980004D0 -:1025D000944600089451000A944F000C30CEFFFF3F -:1025E0000011240031E9FFFF11CD00A20089202550 -:1025F0003C0308008C6304443C1808008F18044016 -:1026000000E85021255FFFFE007F782100001021A7 -:1026100001FF302B03028821022648213C010800DB -:10262000AC2F04443C010800AC29044024EB000812 -:102630003162FFFF3047000710E000038F8500186C -:10264000245000073202FFF83106FFFF30C80007B0 -:102650000045702131CD1FFF034D6021AF85001C67 -:10266000AF8D0018259B4000AF4D00841100000382 -:102670008F8F002024C400073086FFF88F84002845 -:1026800000CF282100A4482B15200002AF8F002482 -:1026900000A42823AF850020AF4500803C1108002E -:1026A0008E3104340345C0213402800003023021FE -:1026B00012200005AF860038938300172419000EFE -:1026C0001079000D241F043F3C0A1000AF4A017826 -:1026D0008F8B0014256700010A0001DDAF8700140D -:1026E0000E0005A63C1040008F8B001425670001EA -:1026F0000A0001DEAF8700143C0A1000A75F014802 -:10270000AF4A01780A0004B48F8B0014240E0F0026 -:1027100011EE003D30D100201620000224030009F4 -:10272000240300010A000208A743014A0A0001FB32 -:10273000A740014694E5000894E2000A94EB000CDF -:102740008F86003C0002FC00316AFFFF30B9FFFFBA -:102750001326003703EA20253C0508008CA5044415 -:102760003C1F08008FFF04400000502100A83821C2 -:1027700000E8302B03EAC8210326C0213C010800F1 -:10278000AC2704443C010800AC3804400A0002694C -:102790008F8D00183C1908008F39047C3C03080019 -:1027A0008C6304543C0608008CC604783C0F080077 -:1027B0008DEF0450032838210068682100E8C02B01 -:1027C00000C4882101A8402B01E47021023858215F -:1027D00001C860213C010800AC2D04543C010800F4 -:1027E000AC2C04503C010800AC27047C3C010800E0 -:1027F000AC2B04780A0002698F8D0018A7400146AF -:102800000A00041B8F8F001830D000201600FFC56F -:102810002403000D240300050A000208A743014A0F -:10282000975901042738FFF00A00036B3304FFFFB8 -:102830008F8C0040148CFFC8000080213C110800E0 -:102840008E31046C3C0408008C84046802287021DA -:1028500001C8782B00904021010F68213C0108003D -:10286000AC2E046C3C010800AC2D04680A0002691F -:102870008F8D00188F9900401499FF5D0000602132 -:102880003C0508008CA5046C3C1008008E10046800 -:1028900000E82021248EFFFE00AEF82103EE582B25 -:1028A000020C5021014B18213C010800AC3F046C84 -:1028B0003C010800AC2304680A00048B24EB0008E8 -:1028C0008F8800383C02FFFF8D0E000C01C2682487 -:1028D00001A46025AD0C000C0A00037930CFFFFF86 -:1028E0000A0003A9AE000000974B01049204000403 -:1028F0008E2A000C01644021251FFFF20147182495 -:1029000033F9FFFF0079C025AE38000C0A0002D46D -:102910008E1900103C03FFFF8D11001002232824A4 -:1029200000A47825AD0F00100A00037930CFFFFF17 -:1029300097450104920600048E2F001000A6102176 -:102940002449FFEE01E76824312EFFFF01AE602528 -:10295000AE2C00100A0002D48E1900108E06000C56 -:10296000AE0000000003C080031088210A0002A608 -:10297000AE2600201460000D3050FFFF3C04FFFF26 -:102980000044602401846826000D582B000C502B55 -:10299000014B102410400002000000000000000D58 -:1029A0008CA300000A00023E006410253A11FFFFCC -:1029B0000011782B0010702B01CF20241080000212 -:1029C000000000000000000D8CB800000A00023E6C -:1029D0003702FFFF3084FFFF30A5FFFF10800007A4 -:1029E0000000182130820001104000020004204243 -:1029F000006518211480FFFB0005284003E0000853 -:102A00000060102110C00007000000008CA2000030 -:102A100024C6FFFF24A50004AC82000014C0FFFB05 -:102A20002484000403E000080000000010A0000857 -:102A300024A3FFFFAC86000000000000000000009F -:102A40002402FFFF2463FFFF1462FFFA24840004C2 -:102A500003E0000800000000308EFFFF30D8FFFFC9 -:102A600000057C0001F8602539CDFFFF01AC502145 -:102A7000014C582B014B4821000944023127FFFF2C -:102A800000E830210006240230C5FFFF00A4182111 -:102A90003862FFFF03E000083042FFFF3C0C0800F3 -:102AA0008D8C0484240BFF8027BDFFD0018450212E -:102AB000014B4824AF4900203C0808008D080484DD -:102AC000AFB20020AFB00018AFBF0028AFB30024F2 -:102AD000AFB1001C936600040104382130E4007F8C -:102AE000009A10213C0300080043902130C50020CB -:102AF000036080213C080111277B000814A000021C -:102B0000264600702646006C92130004975101047B -:102B1000920F00043267000F322EFFFF31ED0040AC -:102B200001C7282311A0000500004821925900BCCC -:102B3000333800041700009000000000924300BCEE -:102B4000307F000413E0000F0000000010A0000D13 -:102B500000000000960E0002240AFF8000A76021FA -:102B600025CDFFFEA74D1016920B0004014B20242B -:102B7000308200FF10400085010C40253C0F04000E -:102B8000010F40258F5301780660FFFE2404000AE0 -:102B9000A7440140960D00022404000931AC00074F -:102BA000000C5823316A0007A74A0142960200022E -:102BB0002443FFFEA7430144A7400146975F010459 -:102BC000A75F01488F5901083338002053000001E6 -:102BD00024040001920F000431EE001015C0000221 -:102BE0003483001000801821A743014A0000000030 -:102BF000000000000000000000000000AF481000CE -:102C000000000000000000000000000000000000C4 -:102C10008F5110000621FFFE3113FFFF12600003E9 -:102C2000000000008F481018ACC800009603000692 -:102C3000307FFFFF27F90002001998820013888077 -:102C4000023B30218CD800001520005700183402B8 -:102C5000920300042405FF8000A3F82433F100FF51 -:102C60001220002C00000000924700BC30F200024D -:102C70001240002800000000974B100C2562FFFE58 -:102C8000A7421016000000003C0A0400354900303D -:102C9000AF4910000000000000000000000000002C -:102CA000000000008F4C10000581FFFE00000000B6 -:102CB0009749100C8F51101C00C020213127FFFFB5 -:102CC00024F20030001218820003288000BBF82193 -:102CD0003226FFFFAFF100000E00059500112C0217 -:102CE0000013C880033B98218E7800000002740016 -:102CF000AFB800108FA80010310FFFFFAFAF00106A -:102D00008FA4001001C46825AFAD00108FA600107D -:102D1000AE66000097730008976D000A9766000C76 -:102D20008F8A003C000D5C0030CCFFFF3262FFFF59 -:102D3000104A0036016C2025960600023C10100057 -:102D400024D300080E0001393264FFFF974C0104C0 -:102D50000E0001473184FFFFAF5001788FBF00287C -:102D60008FB300248FB200208FB1001C8FB00018E9 -:102D700003E0000827BD003010A0FF700000000035 -:102D800024A5FFFC0A0005CE240900048CD1000014 -:102D9000AF5110188F5301780660FF7A2404000A9F -:102DA0000A0005E30000000000A7C8218F88003852 -:102DB0008F4E101C0019C0820018788001E8202175 -:102DC000AC8E0000000E2C0200C020210E000595E4 -:102DD00031C6FFFF023B28218CAD000000025400E9 -:102DE00000403021AFAD00108FAC0010318BFFFFE1 -:102DF000AFAB00108FA2001001424825AFA9001010 -:102E00008FA700100A000613ACA700008F8F0040A8 -:102E1000148FFFC90000000097420104960B0002C6 -:102E20003C0508008CA5046C3049FFFF316AFFFFA8 -:102E30003C1108008E310468012A382124F2FFFE7B -:102E400000B240210012FFC30112C82B023FC02173 -:102E5000031920213C010800AC28046C3C01080047 -:102E6000AC2404680A00064D0000000000A4102BEA -:102E700010400009240300010005284000A4102B85 -:102E800004A00003000318405440FFFC0005284044 -:102E900010600007000000000085302B14C0000205 -:102EA00000031842008520231460FFFB0005284220 -:102EB00003E00008008010218F85002C27BDFFE86B -:102EC000000530272CC300012CA40002008310252C -:102ED00010400003AFBF00102405007FAF85002C19 -:102EE0000005282730A5FFFF0E000574240426F5F1 -:102EF0008F830030240402BD004030210083382B32 -:102F000010E0000924050001000420400083102B7C -:102F100004800003000528405440FFFC00042040CA -:102F200010A0000800C350210064402B15000002CF -:102F3000000528420064182314A0FFFB000420426F -:102F400000C350218FBF0010000A4C02312200FF45 -:102F500027BD0018AF8A002C03E00008AF890030BD -:102F60000A00002600000000000000000000000D24 -:102F7000747870342E362E313600000004061000AE -:102F80000000000A000001360000EA6000000000B6 -:102F90000000000000000000000000000000000031 -:102FA0000000000000000000000000000000000021 -:102FB0000000000000000000000000000000000011 -:102FC0000000001D000000000000000000000000E4 -:102FD00000000000000000000000000000000000F1 -:102FE00000000000000000000000000000000000E1 -:102FF00000000000000000000000000010000003BE -:10300000000000000000000D0000000D3C02080060 -:1030100024423AA03C03080024633C54AC40000026 -:103020000043202B1480FFFD244200043C1D0800B7 -:1030300037BD7FFC03A0F0213C100800261000984B -:103040003C1C0800279C3AA00E000305000000006D -:103050000000000D8F8300383C08800035070070A9 -:103060008CE50000008330253C02900000C2202542 -:10307000AF850030AF4400208F4900200520FFFEBF -:103080003C038000346200708C4500008F86003065 -:103090003C1908008F39007C3C0E08008DCE00786A -:1030A00000A6202303245821000078210164682B06 -:1030B00001CF6021018D50213C010800AC2B007C28 -:1030C0003C010800AC2A007803E000080000000082 -:1030D0000A00003D240400018F8400383C05800074 -:1030E00034A200010082182503E00008AF4300204D -:1030F00003E00008000010213084FFFF30A5FFFF2F -:1031000010800007000018213082000110400002EA -:1031100000042042006518211480FFFB00052840B0 -:1031200003E000080060102110C00007000000004C -:103130008CA2000024C6FFFF24A50004AC8200007E -:1031400014C0FFFB2484000403E00008000000001A -:1031500010A0000824A3FFFFAC86000000000000C0 -:10316000000000002402FFFF2463FFFF1462FFFA47 -:103170002484000403E0000800000000308AFFFF00 -:1031800093A80013A74A014497490E1630C600FFC2 -:103190003C021000A7490146AF450148A346015231 -:1031A000A748015AAF4701608FA400188FA30014ED -:1031B000A7440158AF43015403E00008AF4201782F -:1031C00003E00008000000003C038000346200704F -:1031D0008C4900008F88003C2484000727BDFFF83D -:1031E0003084FFF8AF890030974D008A31ACFFFF83 -:1031F000AFAC00008FAB0000016850232547FFFFF4 -:1032000030E61FFF00C4282B14A0FFF73C0C800001 -:10321000358B00708D6A00003C0708008CE7008445 -:103220003C0608008CC60080000810820149182363 -:103230000002788000E370210000202101C3C82B28 -:1032400000C4C02101FA4021031948212502400091 -:1032500027BD00083C010800AC2E00843C0108009A -:10326000AC29008003E00008000000008F82003CD1 -:103270002486000730C5FFF800A2182130641FFF24 -:1032800003E00008AF84003C3C0E20FF27BDFFE0B8 -:103290003C1A80003C0F800835CDFFFDAFBF001801 -:1032A000AFB10014AFB00010AF8F0044AF4D0E00AF -:1032B000000000000000000000000000000000000E -:1032C000000000003C0C00FF358BFFFDAF4B0E00F3 -:1032D0003C0660048CC95000240AFF7F3C1160004A -:1032E000012A40243507380CACC750008E2404381E -:1032F00024050009AF4500083083FFFF38622F71B5 -:103300002450C0B3AF80004C0E000064AF80003C7E -:1033100052000001AE20442C0E00046000000000AA -:103320008FBF00188FB100148FB000100A000E7705 -:1033300027BD002027BDFFD0AFB20028AFB10024C9 -:10334000AFBF002CAFB00020936200080080902136 -:1033500000A088211440002D240400100E00009AC3 -:10336000000000008F8E004C3C10320031C600FF80 -:1033700000067C0001F0602525CD0001AF8D004CDA -:10338000AC4C0000936B00099369000A316A00FF9E -:10339000000A3C00312800FF00E82025AC4400046E -:1033A0008F83004C06400043AC430008AC40000C47 -:1033B000979800403305000814A000022628000654 -:1033C0002628000297420E148F450E1C8F670004BA -:1033D000937F00023044FFFF33F900FFAFB90010C4 -:1033E0008F710014AFA800180E000087AFB1001451 -:1033F0008FBF002C8FB200288FB100248FB0002027 -:10340000240400100A0000C327BD0030936900099E -:103410009368000B312300FF310200FF006280211E -:10342000261F000A33F0FFFF0E00009A0200202141 -:103430008F86004C3C0D410024D90001AF99004C0F -:103440009378000930C600FF00067400330500FFC2 -:1034500024AF000201CF6025018D5825AC4B000040 -:103460008F6A000C97440E1401523825AC470004B3 -:103470008F450E1C8F670004936900023084FFFFA4 -:10348000312800FFAFA800108F630014AFB10018FF -:103490000E000087AFA30014020020218FBF002C74 -:1034A0008FB200288FB100248FB000200A0000C323 -:1034B00027BD00303C1280000A000114AC52000C01 -:1034C00027BDFFD8AFB3001CAFBF0020AFB20018BC -:1034D000AFB10014AFB00010936200081440008137 -:1034E00000809821AF60000C9785004030A4400018 -:1034F0001080008B2403001624104007A363000AE9 -:10350000AF700014938F00428F6C001431EE0007EF -:10351000000E6A40018D5825AF6B0014978A004059 -:103520008F6800143149001001093825AF67001475 -:103530009786004030C300085060008D00002821AD -:103540008F6600143C0310003C02810000C3282554 -:10355000AF65001497440E0A2418000E3405FFFCD2 -:10356000309FFFFF03E2C825AF790004A378000273 -:103570009372000A26510004A371000A9783004049 -:103580009364000A30661F00000611830044F8218E -:1035900027F90028A379000997580E0CA778001086 -:1035A0009372000926510002323000070010782380 -:1035B00031EE0007A36E000B936D0009976C0010AD -:1035C0008F9000349789004031AB00FF016C50218F -:1035D000014540213127004010E000053105FFFF83 -:1035E00000B0382B3C06800010E000140000882159 -:1035F0000205402B15000033000020218F4A0E14D5 -:10360000AF4A0E108F490E1CAF490E18AF450E0081 -:103610008F4C0000318B00081160FFFD000000009E -:10362000974D0E0800A0802100003021A78D00409A -:103630008F450E0424110001AF850034976E0010F1 -:1036400031D2FFFF8E640000009010231440000967 -:10365000AE6200008F6A00148F8700483549004031 -:10366000AF6900148F480E10ACE800208F430E188D -:10367000ACE3002400C020210E0000F50200282148 -:103680008E66000014C00005000000008F6B00145F -:10369000240CFFBF016C9824AF7300148F6D000CD5 -:1036A00001B22821AF65000C937200081640000398 -:1036B000000000001620003100000000A371000887 -:1036C000020020218FBF00208FB3001C8FB2001892 -:1036D0008FB100148FB000100080102103E00008AB -:1036E00027BD00288F900034979100403C06800051 -:1036F00002009021322F004015E0FFD20000882107 -:10370000977F00108F98003433F9FFFF1738FFEDD3 -:1037100000002021000030210A0001B9241100011D -:103720002403000E24104007A363000AAF700014A6 -:10373000938F00428F6C001431EE0007000E6A4038 -:10374000018D5825AF6B0014978A00408F680014D4 -:103750003149001001093825AF67001497860040F1 -:1037600030C300081460FF7600000000000028212C -:10377000AF6000040A000187A36000028F6F00148D -:103780003C19EFFF3738FFFE01F870240A0001D71B -:10379000AF6E00148F8700388F8A004427BDFFE08A -:1037A0008F860048AFB00018AFBF001C8F450104E2 -:1037B0008D4900ACAF4700808CC8002000A9382399 -:1037C00000008021AF480E108F440E1000004821E9 -:1037D000AF440E148CC20024AF420E188F430E1853 -:1037E000AF430E1C10E000362D390001936B00082A -:1037F0001160004F00000000976E001031CDFFFFF8 -:1038000000ED602B1580004A000000009778001042 -:10381000330FFFFFAF4F0E008F5F000033F900083A -:103820001320FFFD0000000097420E088F460E0493 -:103830003045FFFF30A300011060008A0000000047 -:103840000000000D30A8A040240400401104003BFB -:1038500030A9A0001120008500000000936C000832 -:103860005180000927A40010976F001031EEFFFF70 -:1038700000CE682B11A0000427A4001030B800402F -:103880001300007A00000000AFA70010A7850040D9 -:10389000AF8600340E0001580000000000404821AF -:1038A0001440FFD08FA700108F420E148F84004861 -:1038B000AC8200208F470E1CAC8700242D390001FC -:1038C0000330302510C000178FBF001C8F840038D4 -:1038D00024100F0010900085000000008F4F017829 -:1038E00005E0FFFE24180F001098006F0000000094 -:1038F0008F470E14240202403C101000AF470144D1 -:103900008F490E1CAF490148A3400152A740015AFC -:10391000AF400160A7400158AF420154AF50017859 -:103920008FBF001C8FB0001803E0000827BD0020E7 -:10393000AF470E000A00022E000000008F490178F8 -:103940000520FFFE240A08008F84003CAF4A01785E -:103950009758008A330FFFFF01E4702325CDFFFF46 -:1039600031AC1FFF2D8B00081560FFF9000000002F -:103970008F83004C8F9F003800C0482103442021D2 -:103980002466000124190F00AF86004C306A00FF46 -:1039900000E938232486400013F9000524080001BB -:1039A000938B004231680007000812403448000140 -:1039B000000A7C003C18010001F87025AC8E400024 -:1039C0008F8D004C30AC003630A40008ACCD000424 -:1039D0001080002E010C3025974D0E0A8F8C003C74 -:1039E0003C02810031A4FFFF258B000800824025A6 -:1039F0003C03100031651FFF25390006241F000E0F -:103A0000AF48016000C33025A75F015AAF85003C75 -:103A1000A759015814E0000A8F9F003824050F00B1 -:103A200053E500022410000134C600408F430E10FD -:103A30008F880048AD0300208F4B0E18AD0B00247B -:103A40008F420E14AF4201448F440E1CAF44014814 -:103A5000A34A01523C0A1000AF4601540A00022159 -:103A6000AF4A017814C0FF7830A8A0408F420E14EE -:103A70008F84004800004821AC8200208F470E1C34 -:103A8000AC8700240A0002582D3900018F98003CB1 -:103A900025390002A7590158270F000831EE1FFFF2 -:103AA0000A0002ADAF8E003CAF40014C1120002C4B -:103AB000000000008F460E10AF4601448F430E18E1 -:103AC000240200403C101000AF430148A3400152C3 -:103AD000A740015AAF400160A7400158AF420154CE -:103AE000AF5001780A0002718FBF001C1120000640 -:103AF00000000000975F0E0833E5004014A00002AC -:103B0000000000000000000D8F4801780500FFFE56 -:103B100000000000974E0E103C0D0500240320000D -:103B200031CCFFFF018D1025AF42014C8F440E14A4 -:103B30003C0B1000AF4401448F4A0E1CAF4A0148B1 -:103B4000A34001528F840038A740015AAF40016062 -:103B5000A7400158AF4301540A00025FAF4B017800 -:103B60008F590E14AF5901448F430E1C0A0002D91D -:103B70002402004027BDFFE0AFB20018AFB100142F -:103B8000AFB00010AFBF001C0E0000CA0000000064 -:103B90003C0280008F8A0044345000703C120800C0 -:103BA00026523B70020088218E0800008F450000DD -:103BB00038A400013083000110600017AF88003086 -:103BC000022048218D2C00003C0208008C42006C31 -:103BD0003C1808008F1800680188182300436821EA -:103BE0000000C82101A3782B0319702101CF4021C7 -:103BF0003C010800AC2D006C3C010800AC280068BA -:103C00008F4B00003967000130E6000114C0FFED62 -:103C100001804021AF8C00308E1800003C0E08005F -:103C20008DCE006C3C0C08008D8C00680308782356 -:103C300001CF28210000402100AF302B01885821FE -:103C4000016620213C010800AC25006C3C01080005 -:103C5000AC2400688F49010025470088AF870048E1 -:103C6000AF890038AF4900208E070000AF870030D1 -:103C70008F5901780720FFFE000000008E0F000022 -:103C80003C0D08008DAD00743C0C08008D8C00705C -:103C900001E7702301AE28210000302100AE582B2F -:103CA00001862021008B3821240908003C010800EE -:103CB000AC2500743C010800AC270070AF490178C6 -:103CC00093430108A383004293820042305F0001C6 -:103CD00017E000158F830038241F0D00107F001996 -:103CE00024020F001062001D000000009147000038 -:103CF0002403005030E900FF112300043C0540007C -:103D0000AF4501380A000312000000000E0008DA77 -:103D1000000000008F8A00443C054000AF45013898 -:103D20000A00031200000000939900423338000695 -:103D3000001851000E00020D0152D8210A00036E36 -:103D40008F8A00443C1B0800277B3BF00E00020DCD -:103D5000000000000A00036E8F8A00443C1B08002C -:103D6000277B3C100E00020D000000000A00036ECD -:103D70008F8A004490AA00018FAB00108CAC001019 -:103D80003C0300FF8D680004AD6C00208CAD001476 -:103D900000E060213462FFFFAD6D00248CA70018A5 -:103DA0003C09FF000109C024AD6700288CAE001C4F -:103DB0000182C82403197825AD6F0004AD6E002C74 -:103DC0008CAD0008314A00FFAD6D001C94A90002C3 -:103DD0003128FFFFAD68001090A70000A560000229 -:103DE000A1600004A167000090A30002306200FF00 -:103DF0000002198210600005240500011065000E04 -:103E00000000000003E00008A16A00018CD800282F -:103E1000354A0080AD7800188CCF0014AD6F0014C7 -:103E20008CCE0030AD6E00088CC4002CA16A00015D -:103E300003E00008AD64000C8CCD001CAD6D0018D3 -:103E40008CC90014AD6900148CC80024AD6800084A -:103E50008CC70020AD67000C8CC200148C830064FA -:103E60000043C82B13200007000000008CC2001480 -:103E7000144CFFE400000000354A008003E0000815 -:103E8000A16A00018C8200640A0003C400000000E3 -:103E900090AA000027BDFFF88FA9001CA3AA00006C -:103EA0008FAE00003C0FFF808FA8001835E2FFFFA7 -:103EB0008CCD002C01C26024AFAC0000A120000416 -:103EC00000E06021A7A000028FB800008D27000449 -:103ED0000188182100A0582100C05021006D28261B -:103EE0003C06FF7F3C0F00FF2CAD000135EEFFFFCD -:103EF00034D9FFFF3C02FF0003193024000D1DC020 -:103F0000010EC82400E2C02400C3702503197825DF -:103F1000AD2E0000AD2F00048D450024AFAE000093 -:103F2000AD2500088D4D00202405FFFFAD2D000CB0 -:103F3000956800023107FFFFAD2700109166001859 -:103F400030C200FF000219C2506000018D450034EC -:103F5000AD2500148D67000827BD0008AD27001CA3 -:103F60008C8B00CCAD2C0028AD20002CAD2B002478 -:103F7000AD20001803E00008AD20002027BDFFE0C1 -:103F8000AFB20018AFB10014AFB00010AFBF001C4B -:103F90009098000000C088213C0D00FF330F007F87 -:103FA000A0CF0000908E000135ACFFFF3C0AFF005F -:103FB000A0CE000194A6001EA22000048CAB001429 -:103FC0008E29000400A08021016C2824012A4024AD -:103FD0000080902101052025A6260002AE240004C1 -:103FE00026050020262400080E0000722406000288 -:103FF00092470000260500282624001400071E0012 -:104000000003160324060004044000032403FFFFFA -:10401000965900023323FFFF0E000072AE230010FA -:10402000262400248FBF001C8FB200188FB100140B -:104030008FB0001024050003000030210A00007C2E -:1040400027BD002027BDFFD8AFB1001CAFB00018BE -:10405000AFBF002090A80000240200018FB0003CF8 -:104060003103003F00808821106200148FAA0038BD -:10407000240B0005506B0016AFAA001000A02021F1 -:1040800000C028210E00040702003021922400BC49 -:10409000308300021060000326060030ACC0000030 -:1040A00024C600048FBF00208FB1001C8FB0001801 -:1040B00000C0102103E0000827BD0028014038217E -:1040C0000E000385AFB000100A00044B0000000092 -:1040D0000E0003CCAFB000140A00044B0000000037 -:1040E0003C02000A034218213C04080024843B08D7 -:1040F0002405001A000030210A00007CAF83002C48 -:104100003C038000346200708C48000000A05821FD -:1041100000C04821308A00FFAF8800308F4401780A -:104120000480FFFE3C0C8000358600708CC50000CA -:104130003C0308008C6300743C1808008F18007062 -:1041400000A82023006468210000C82101A4782B66 -:104150000319702101CF60213C010800AC2D0074CF -:104160003C010800AC2C00708F480E14AF4801448D -:10417000AF47014CA34A0152A74B0158934601088F -:1041800030C5000854A0000135291000934B0900E8 -:1041900024070050316A00FF1147000700000000AB -:1041A0008F450E1CAF450148AF4901543C09100032 -:1041B00003E00008AF490178934D010831A80008D9 -:1041C0001100001000000000934F010831EE0010B4 -:1041D00051C00001352900083C04080090843B6C64 -:1041E000A34401508F4309A4AF4301488F4209A063 -:1041F000AF420144AF4901543C09100003E00008FC -:10420000AF4901783C1908008F393B283338000842 -:104210005700FFF1352900080A00049E0000000045 -:1042200024070040AF470814AF4008108F420944EC -:104230008F4309508F4409548F45095C8F46094CC0 -:10424000AF820064AF830054AF840050AF85005C40 -:1042500003E00008AF8600609346010930C5007F87 -:10426000000518C0000521400083102103E000086C -:10427000244200883C0A0800914A3B2D3C09080072 -:1042800095293B263C051100000A3C002528000228 -:1042900000E8302500C5182524820008AC83000002 -:1042A00003E00008AC8000048F4A002C974D0908F9 -:1042B0003C0E000E034E382131ACFFFF000C41C014 -:1042C000AF48002C9743090894EB001A0080402166 -:1042D000240200013169FFFFAC8900008CE6001C5C -:1042E00000A05821AC8600048CE40020AD04000836 -:1042F00090E30019306300031062003E00000000EC -:104300002865000214A00071240F0002106F004CF9 -:104310000000000024180003107800550000000081 -:104320003C09080095293B1C93430934934F09210C -:104330003C05080094A53B22306400FF94EE002A5F -:104340000004688231EC00FF978F0058000DC60012 -:10435000000CCC003127FFFF0319102500A73021E6 -:104360000046202501CF68213C03400000836025E2 -:10437000000D4C00AD090004AD0C0000935909205C -:104380003C1800062509001400193E0000F82825F5 -:10439000AD0500088F4E092C25E6000130C27FFFD5 -:1043A000AD0E000C8F440930A7820058250200286A -:1043B000AD0400108F4D0938AD0D0014AD2B000475 -:1043C0008F4C0940AD2C0008934309373C19080075 -:1043D00093393B2CAD200010000347000019C400A6 -:1043E000011858253567FFFFAD27000C03E00008D2 -:1043F000AF4A002C3C09080095293B1C3C0D0800E5 -:1044000095AD3B263C0C0800958C3B1894E40024A9 -:10441000312EFFFF01AE302100CC18230004CC0068 -:104420002462FFF20322C025240F0800AD18000CFF -:10443000AD0F0014AD0000100A0004F225080018AA -:1044400094E5002494EE00283C09080095293B1CC3 -:1044500000056C00000E640035A68100358408005C -:10446000AD06000CAD0400100A0004F2250800148B -:104470003C09080095293B1C3C0F080095EF3B26A2 -:104480003C06080094C63B1894E400243125FFFF45 -:1044900094ED002801E5702101C660230004CC00E2 -:1044A000000D1C002582FFEE006278253738810060 -:1044B00024050800AD18000CAD0F0010AD05001864 -:1044C000AD0000140A0004F22508001C1460FF94DB -:1044D0000000000094E300243C09080095293B1CDF -:1044E0000003140034590800AD19000C0A0004F24E -:1044F0002508001003E00008240201F427BDFFE8AE -:10450000AFB00010AFBF00140E00005C008080212F -:1045100024050040AF4508148F8300548F84005059 -:104520008F85005C0070182100641023184000047F -:10453000AF830054AF6300548F660054AF860050C1 -:104540001200000C000000008F440074936800818A -:104550003409FA002D07000710E00005008910213A -:10456000936C0081240B01F4018B50040144102151 -:10457000AF62000C8F4E095C01C5682319A00004CE -:104580008FBF00148F4F095CAF8F005C8FBF00148A -:104590008FB000100A00005E27BD00188F840064F1 -:1045A0008F8300548F820050AF640044AF6300508B -:1045B00003E00008AF6200543C03800034620070E6 -:1045C0008C43000027BDFFF8308700FF30A900FFB3 -:1045D00030C800FFAF8300308F4401780480FFFEB5 -:1045E0003C028000345900708F380000A3A70003FC -:1045F0003C0708008CE700748FAC00003C06080004 -:104600008CC60070030378233C0E7FFF00EFC821A7 -:1046100035CDFFFF00005021018D282400CA18214C -:10462000000847C0032F202B00A810250064C021DC -:10463000AFA200003C010800AC3900743C01080046 -:10464000AC380070934F010AA3A000023C0E80FF1B -:10465000A3AF00018FAC0000312B007F35CDFFFFF1 -:10466000018D4824000B5600012A40252407300004 -:104670002406FF803C05100027BD0008AF48014C10 -:10468000AF470154A7400158A346015203E0000878 -:10469000AF45017827BDFFE8AFBF0014AFB00010F1 -:1046A0008F6500743C068000309000FF00A6202536 -:1046B0000E00005CAF640074936300053462000870 -:1046C0000E00005EA3620005020020218FBF0014CF -:1046D0008FB0001024050005240600010A0005968D -:1046E00027BD001827BDFFE03C038000AFB00010DD -:1046F000AFBF0018AFB10014346200708C470000E7 -:10470000309000FF30A800FFAF8700308F44017861 -:104710000480FFFE3C188000371100708E2F0000CF -:104720003C0D08008DAD00743C0A08008D4A0070F5 -:1047300001E7702301AE28210000582100AE302B84 -:10474000014B4821012638213C010800AC250074AA -:10475000000088213C010800AC2700701100000F08 -:10476000000000008F6200742619FFFF3208007FEE -:104770000002FE0233E5007F15000006332200FF31 -:104780002407FF800207202624A3FFFF0083802543 -:10479000320200FF00408021241110080E00005C4E -:1047A000000000008F4908183125000414A0FFFD07 -:1047B0003218007F001878C00018714001CF6821BE -:1047C00025AC0088AF4C0818274A09808D4B002083 -:1047D000AF4B01448D460024AF460148A350015021 -:1047E0000E00005EA7400158022010218FBF001864 -:1047F0008FB100148FB0001003E0000827BD002027 -:1048000027BDFFE8308400FFAFBF00100E0005E1B8 -:1048100030A500FF8F8300548FBF00103445004047 -:104820002404FF903C02100027BD0018AF43014C48 -:10483000A3440152AF45015403E00008AF420178A0 -:1048400027BDFFE8AFBF0014AFB000109345093F8C -:10485000240200063C08080095083B2230A300FF14 -:104860002487FFD8240500041062003624060002C5 -:10487000974E093C3C0D02040006340031CCFFFF8A -:10488000018D5825AC8B0000934A093E3149002028 -:104890001120000800000000935F09363C19010355 -:1048A0003738030033F000FF02187825240500088C -:1048B000AC8F000493580934934D09213C104000FB -:1048C000330E00FF000E608231AB00FF000C56007B -:1048D000000B1400014218250068F82503F0C825D4 -:1048E000AC99FFD8935809378F4C09488F4D094030 -:1048F00000057882330E00FF01CF5821018D282357 -:10490000000B57000146102530A3FFFF0043402550 -:10491000000F488001273021ACE800200E00005C29 -:1049200024D00028240400040E00005EA364003F8D -:10493000020010218FBF00148FB0001003E00008A8 -:1049400027BD00180A0006442406001227BDFFD028 -:1049500024090010AFB50024AFB40020AFB3001C91 -:10496000AFB10014AFB000103C010800A0293B2CEF -:10497000AFBF0028AFB2001897480908309400FF75 -:104980003C02000E3107FFFF000731C0AF46002C8C -:10499000974409089344010B30B300FF0342802180 -:1049A000308300300000A821106000E4000088215E -:1049B000240C00043C010800A02C3B2C934B093E26 -:1049C000000B5600000A2E0304A001310000000075 -:1049D000AF4000489352010B324F002011E0000617 -:1049E00000000000935F093E001FCE000019C603BF -:1049F00007000148000000009346010B30C2004050 -:104A0000104000038F9200548F87005424F2FFFF60 -:104A1000960A002C9345093493490937A78A005810 -:104A200030A600FF312700FF00071080004620213C -:104A30000091F8213C010800A43F3B22920300189A -:104A40003C010800A4203B1C3C010800A4203B18AA -:104A5000307000FF03F04021250B000A3170FFFF8A -:104A60003C010800A4283B243C010800A4283B2664 -:104A70000E00009A020020210E0004C500402021F3 -:104A80008F4B002C975809083C19000E0359402100 -:104A9000330FFFFF000F71C0AF4E002C9743090882 -:104AA000950D001A241100010040382131ACFFFFA0 -:104AB000AC4C00008D0A001CAC4A00048D0500209F -:104AC000AC4500089109001931230003107100BDA5 -:104AD0002871000216200103240C0002106C00F55E -:104AE000240D0003106D00CA000000003C090800FE -:104AF00095293B1C93430934935809213C0A08002B -:104B0000954A3B22306400FF950C002A0004F8828D -:104B1000331900FF97980058001F760000197C0099 -:104B20003126FFFF01CF402501466821010D882570 -:104B3000019828213C0840000228102500054C005F -:104B4000ACE90004ACE20000934309203C040006F9 -:104B500024E900140003FE0003E4C825ACF90008B2 -:104B60008F4E092C270F000131E67FFFACEE000CC1 -:104B70008F4D0930A786005824E60028ACED0010C0 -:104B80008F4C0938ACEC0014AD3200048F51094051 -:104B9000AD310008934209373C05080090A53B2C35 -:104BA000AD2000100002270000051C000083F8253E -:104BB00037F2FFFFAD32000CAF4B002C12A00033D8 -:104BC000000000009352093F24150006240500044C -:104BD000324B00FF117500CD24090002974F093CAC -:104BE0003C0E020431EDFFFF01AE6025ACEC002865 -:104BF0009351093E322200201040000800000000BE -:104C0000934409363C180103371F0300309900FF15 -:104C1000033F2825ACC5000424050008935209343D -:104C20009343092100056082324B00FF000BA882EC -:104C3000306400FF0015FE000004C40003F8C8251E -:104C4000032A782501E87025ACCEFFD8934D0937AB -:104C50008F5209488F42094031B100FF022C582180 -:104C600002423023000B1F000009AC0000754825EC -:104C700030C8FFFF012850250E00005CACEA002080 -:104C8000240700040E00005EA367003F0E0000C36F -:104C9000020020213C05080090A53B2C30B0000309 -:104CA0001200000F028020218F8800542509000186 -:104CB000AF890054AF6900508F6A0054014938230E -:104CC00018E00002012020218F640054AF640054DA -:104CD0008F420074244601F4AF66000C028020214C -:104CE00002602821A76000680E0005E13C13100057 -:104CF0008F8E005434540006AF4E014C8F8D004C03 -:104D00008FBF00288FB5002431B100FF25AC000112 -:104D1000AF8C004C8FB20018A35101528FB000101D -:104D2000AF5401548FB10014AF5301788FB40020F9 -:104D30008FB3001C03E0000827BD00309359093EE3 -:104D40000019C6000018960306420048241100020C -:104D500093420923304400021080FF1E8F870060B9 -:104D60008F86005414E6FF1B000000000E00005C5C -:104D7000000000009365003F2408001630A900FFE2 -:104D80001128000C240A00083C0D080091AD3B2CB2 -:104D900035AC00013C010800A02C3B2C936B003F7C -:104DA000316300FF106A0065240E000A106E005E79 -:104DB0002402000C0E00005E000000000A00069DA8 -:104DC000000000003C09080095293B1C3C19080024 -:104DD00097393B263C18080097183B18950E00247D -:104DE000313FFFFF033F782101F86823000E8C005C -:104DF00025ACFFF2022C502524050800244700189A -:104E0000AC4A000CAC4500140A0006E5AC400010AA -:104E10003C09080095293B1C3C18080097183B26C4 -:104E20003C0F080095EF3B18950D00243139FFFF2A -:104E3000950C00280319702101CF8823000D2C0048 -:104E4000000C54002622FFEE0142302534A48100DC -:104E500024030800ACE4000CACE60010ACE300183E -:104E6000ACE000140A0006E524E7001C3C01080041 -:104E7000A0313B2C9343093E24150001307F0020D4 -:104E800017E0FED4241100080A00069D2411000436 -:104E90008F6E00848F4D094011A0FECDAF8E00545F -:104EA000240F00143C010800A02F3B2C0A00069C94 -:104EB0000000000095020024950600283C09080027 -:104EC00095293B1C0002240000061C00349F810031 -:104ED00034790800ACFF000CACF900100A0006E5BC -:104EE00024E700141460FF0100000000951800245E -:104EF0003C09080095293B1C2447001000187C0041 -:104F000035EE08000A0006E5AC4E000C0A00071F4B -:104F1000240900128F64004CAF6400548F63005466 -:104F20000A0006A6AF630050A362003F0E00005EB9 -:104F3000000000000A00069D00000000240200148A -:104F40000A0007F3A362003F27BDFFE8308400FF9B -:104F5000AFBF00100E0005E130A500FF9378007E82 -:104F60009379007F936E00809368007A332F00FF5F -:104F700000186600000F6C0031CB00FF018D482542 -:104F8000000B52008FBF0010012A3825310600FFA8 -:104F90003444700000E628252402FF813C03100001 -:104FA00027BD0018AF45014CAF440154A342015244 -:104FB00003E00008AF43017827BDFFD8AFB2001867 -:104FC000AFB10014AFB00010AFBF0020AFB3001CF2 -:104FD00093420109308600FF30B000FF000618C27E -:104FE000320400023071000114800005305200FFCD -:104FF0009367000530E5000810A0000D30C80010D0 -:10500000024020210E0005CD0220282124040001A9 -:105010008FBF00208FB3001C8FB200188FB1001417 -:105020008FB000100080102103E0000827BD002889 -:105030001500003200000000934301090000282100 -:105040003062007F000220C00002F94003E4982192 -:1050500026790088033B98218E7800248E6F000803 -:10506000130F0046000000008F6400842418000223 -:105070000004FD8233F900031338007C00000000B7 -:1050800093660083934A0109514600043205007C6F -:1050900010A00060000000003205007C14A0005346 -:1050A0000240202116200006320400018E7F0024D9 -:1050B0008F59010417F9FFD60000202132040001A6 -:1050C0001080000A024020218F4209408F93006423 -:1050D00010530006000000000E00067B022028216D -:1050E0008F430940AF630044024020210E00062890 -:1050F000022028210A00082C240400013C09080091 -:105100008D290064252600013C010800AC260064BE -:1051100016000012000000008F6D00843C0E00C0DD -:1051200001AE602415800005024020210E0007FA20 -:10513000022028210A00082C240400012405000470 -:105140000E00059624060001024020210E0007FAF9 -:10515000022028210A00082C240400010E00003D32 -:1051600024040001936B007D020B50250E00005EAD -:10517000A36A007D0A00086F8F6D00848F6600743B -:105180008F4801048E67002400064E021507FFB603 -:105190003126007F936B008326440001308A007F14 -:1051A00011460043316300FF5464FFB08F640084F4 -:1051B0002645000130B1007F30A200FF1226000416 -:1051C00024050001004090210A000842241100013A -:1051D000240FFF80024F702401CF9026324200FF3F -:1051E000004090210A000842241100010E00067BB5 -:1051F00002202821321800301300FFAA321000824A -:10520000024020210E0005CD022028210A00082C92 -:10521000240400018F6E00743C0F800024050003FD -:1052200001CF9025AF7200749371008324060001B2 -:105230000E000596322400FF0E00003D24040001FC -:10524000936D007D020D60250E00005EA36C007D55 -:105250003C0B08008D6B0054257000013C010800D8 -:10526000AC3000540A00082C240400018F6800743C -:105270003C0980002405000401093825AF6700744B -:1052800093630083240600010E000596306400FF3E -:105290000E00003D240400019362007D0202982567 -:1052A0000E00005EA373007D0A00082C2404000198 -:1052B000324D008039AC0080546CFF6C8F640084E8 -:1052C0000A0008952645000127BDFFD03C0A0008CA -:1052D000AFBF002CAFB40028AFB30024AFB20020A2 -:1052E000AFB1001CAFB00018034AD8212409004018 -:1052F000AF490814AF4008108F4209448F4309504A -:105300008F4609548F47095C8F48094C9344010824 -:105310009345010BAF820064308400FF30A500FF8D -:10532000AF830054AF860050AF87005C0E000816B4 -:10533000AF8800601440015A8FBF002CA76000683E -:10534000934D0900240B00503C14080026943C3077 -:1053500031AC00FF3C12080026523C40118B000388 -:10536000000000000000A02100009021934F0109DF -:105370008F8800542402001031F1007F001170C0AA -:105380000011694001AE282124B80088AF580818E0 -:105390008F4A01048F4B09A43C0C000E034CC8211A -:1053A000014B48233C010800AC293B088F440958B5 -:1053B0003C010800A0223B2C9746090800881823CE -:1053C0003C010800AC233B0C30C7FFFF0007F9C0CD -:1053D0003C010800AC283B30AF5F002C9742090825 -:1053E0009730002C8E910000932F0018037898219D -:1053F000A7900058AF9300480220F80931F000FF51 -:10540000304E000215C0018E30530001126001427F -:10541000000000008F4F09A4241300013C01080084 -:10542000AC2F3B3493510934934E0937322500FF9A -:1054300031CD00FF000D60800185502101505821C1 -:105440003C010800A42B3B243C010800A42A3B2279 -:1054500093490934312200FF0202202124900010D8 -:105460003C010800A4303B20240800068F9900541A -:105470003C010800AC283B288F9F005C8F580958DE -:105480000000802103F9282304A0013C03192023F4 -:105490000480013A00A4382B10E0013C0000000019 -:1054A0003C010800AC253B0C8E4200000040F8098E -:1054B000000000003046000214C000DD00408821DA -:1054C00030430001546000108E4200043C04080088 -:1054D0008C843B103C09C00000898025AF500E0031 -:1054E0008F4B0000316A00081140FFFD00000000F2 -:1054F00097450E0824100001A78500408F4C0E042C -:10550000AF8C00348E4200040040F8090000000017 -:1055100002228825322D000215A00159000000004A -:105520003C09080095293B183C06080094C63B241A -:105530003C04080094843B1A3C1908008F393B1046 -:10554000012658213C1808008F183B343C1F0800E6 -:1055500097FF3B2E016418218F4E09400329282113 -:10556000246F00020319682100BF60213C0108007C -:10557000A42B3B26AF8E00643C010800AC2D3B34CD -:105580003C010800A42C3B1C0E00009A31E4FFFFF4 -:105590008F87004C004020213C010800A0273B2DB4 -:1055A0008E42000824E80001AF88004C0040F80952 -:1055B000000000008F4B002C974909083C0A000EA0 -:1055C000034A38213124FFFF000419C08F8A005498 -:1055D000AF43002C9743090894E6001A004040218D -:1055E00030DFFFFFAC5F00008CF9001CAC590004F9 -:1055F0008CF80020AC58000890EF001931E300034C -:10560000107300E60000000028620002144001024E -:10561000240C0002106C00F4240D0003106D00A790 -:10562000000000003C09080095293B1C9345093403 -:10563000934C09213C0F080095EF3B2230BF00FF3F -:1056400094EE002A001F6882319900FF978C005861 -:10565000000D16000019C4003124FFFF01E43021C1 -:10566000005848250126382501CC28213C0340005C -:1056700000E3F82500056C00AD0D0004AD1F00002F -:10568000935909203C180006250D001400197E00CE -:1056900001F87025AD0E00088F42092C2586000107 -:1056A0008E4C000CAD02000C8F44093030C97FFFD6 -:1056B000A7890058AD0400108F4709382504002839 -:1056C000AD070014ADAA00048F450940ADA5000840 -:1056D000934309373C1F080093FF3B2CADA00010FB -:1056E0000003C700001FCC000319782535EEFFFF2B -:1056F000ADAE000CAF4B002C0180F809000000009B -:105700003C06080094C63B263C02080094423B1A23 -:1057100000C24821252B00020E0000C33164FFFFA8 -:105720003C0808008D083B083C0708008CE73B104C -:10573000010750233C010800AC2A3B081540000635 -:10574000000000003C0808008D083B28350A004096 -:105750003C010800AC2A3B28120000848F830048DB -:105760008F470E108F900048AE0700208F4B0E1809 -:10577000AE0B00243C10080096103B1C0E00005C91 -:1057800000000000240F0040AF4F08148F86005423 -:105790008F89005000D018210069702319C00004BF -:1057A000AF830054AF6300548F640054AF84005043 -:1057B0001200000C000000008F44007493780081F8 -:1057C0003419FA002F020007104000050099182133 -:1057D000937F0081240C01F403EC680401A41821D8 -:1057E000AF63000C8F4A095C8F88005C0148282356 -:1057F00018A00003000000008F50095CAF90005C0F -:105800000E00005E000000008F8300548E470010E1 -:105810003C010800AC233B3000E0F8090000000028 -:105820003C0B08008D6B3B081560FF102408000638 -:105830008F590024975F09088F8900648F8E005468 -:105840003C0C001F978400588F8F002C8F930050C2 -:1058500033F8FFFF358DFF80032D3024001811C071 -:1058600032320010AF420024A5E4002CAF460024E1 -:10587000AF690044AF6E0050AF7300545640007CD7 -:105880008E850004322A0040554000318E91000878 -:105890008E88000C0100F809000000008FBF002C6A -:1058A0008FB400288FB300248FB200208FB1001C6A -:1058B0008FB0001803E0000827BD00303C09080045 -:1058C00095293B1C3C03080094633B263C040800DC -:1058D00094843B1894F900243125FFFF94F80028A4 -:1058E0000065F82103E478230019640000186C00B7 -:1058F00025EEFFEE01AE302535828100240308003D -:10590000AD02000CAD060010AD030018AD00001490 -:105910000A0009B32508001C934301098F8600384B -:1059200000033E0000E64025AF4800808F5F09A0DD -:105930008F5809A4AFBF0010AF5F0E148FB90010CD -:10594000AF590E10AF580E1C0A00092DAF580E1893 -:105950000220F809000000008E88000C0100F80900 -:10596000000000000A000A508FBF002CA460002035 -:10597000A47300220A000A05AC7300243C0108004D -:10598000AC203B0C0A0009538E4200003C01080089 -:10599000AC243B0C0A0009538E4200003C0908006D -:1059A00095293B1C3C1F080097FF3B263C0508003F -:1059B00094A53B1894F800243124FFFF03E4C82188 -:1059C0000325782300186C0025EEFFF201AE602558 -:1059D000AC4C000C24020800AD020014AD00001015 -:1059E0000A0009B32508001894E6002494E300286F -:1059F0003C09080095293B1C000624000003FC001C -:105A00003485810037F90800AD05000CAD19001090 -:105A10000A0009B3250800141460FF02000000000A -:105A200094F800243C09080095293B1C00187C00D0 -:105A300035EE0800AD0E000C0A0009B32508001071 -:105A400093520109000028210E000628324400FF6D -:105A50008FBF002C8FB400288FB300248FB200209A -:105A60008FB1001C8FB0001803E0000827BD003084 -:105A700000A0F809000000000A000A4A322A00408B -:105A80001200FF6B000000008F4E0E148F92004832 -:105A9000AE4E00208F530E1C0A000A34AE53002471 -:105AA0008F820018008040213C040100904700854F -:105AB00030E3002010600009000000003C070800EF -:105AC0008CE73B308F83001400E320230480000820 -:105AD0009389000014E300030100202103E0000883 -:105AE000008010213C04010003E000080080102128 -:105AF0001120000B006738238F8C001C2409003410 -:105B0000918B00BC316A0002514000012409003031 -:105B100000E9682B15A0FFF10100202100E93823DE -:105B20002419FFFC00B9C02400F9782400F8702B78 -:105B300015C0FFEA01E8202130C20003000218234B -:105B400014C00012306900030000302100A9702148 -:105B500001C6682100ED602B1180FFE03C040100CC -:105B60002D2F00010006482B0105382101E93024C2 -:105B700014C0FFDA24E4FFFC2419FFFC00B9C024A0 -:105B80000308202103E00008008010218F8B001CF7 -:105B900024060004916A00BC314400041480FFEC28 -:105BA00000A970210A000AFC0000302127BDFFE88F -:105BB000AFBF00108F460100934A01093C1F080047 -:105BC0008FFF00902407FF80314F00FF31E8007FF6 -:105BD0000008614003E6C821032CC02127090120E9 -:105BE000012770243C010800A02F3B6CAF4E080C2D -:105BF0003C0D08008DAD00903C0400803482000311 -:105C000001A65821016C18212465012030AA0078D2 -:105C100001424025AF48081C3C1F08008FFF009040 -:105C20008F88004403E6C021331900070307482486 -:105C3000033A7821AF49002825E909C0952E0002D2 -:105C40003C0D08008DAD008C3C0A08008D4A009088 -:105C500031CC3FFF01A61821000C5980006B282190 -:105C600000A72024AF44002C952200023C1F08000E -:105C70008FFF008C9107008530593FFF03E67821A4 -:105C80000019C1800146702101F8682131CC007FE4 -:105C900031AB007F019A2821017A50213C03000C8E -:105CA0003C04000E00A328210144102130E600200E -:105CB00027470980AF820028AF880018AF890020ED -:105CC000AF85001C10C00006AF8700248D02005075 -:105CD0008CA4010C0044302318C0007700000000A1 -:105CE000910C0085240DFFDF018D3824A10700856C -:105CF0008F8B00188F8900208F8700248D65004CC2 -:105D0000AF850014912F000D31EE002011C0001757 -:105D10000000000024090001A3890000AF800008F2 -:105D20008CE400248F850008240A0008AF8000045A -:105D3000AF80000C3C010800A42A3B1A3C0108007B -:105D4000A4203B2E0E000AD0000030218F850020B9 -:105D50008FBF0010AF82001090A8000D27BD001863 -:105D60000008394203E0000830E20001913F0002E0 -:105D70002418000133F900FF00192182109800391E -:105D8000240800021088005B8F8600288CE5002420 -:105D900014A0001B8F9F001C91220000240A000504 -:105DA0003046003F10CA0047240400018F860004DB -:105DB000A3840000AF86000CAF8600088CE40024AA -:105DC0008F850008240A00083C010800A42A3B1A19 -:105DD0003C010800A4203B2E0E000AD00000000069 -:105DE0008F8500208FBF0010AF82001090A8000D9B -:105DF00027BD00180008394203E0000830E2000126 -:105E00008CF800088CF900248FEE00C4A3800000F9 -:105E10008CE40024AF8E00088F8500088F86000474 -:105E200003197823240A0008AF8F000C3C010800F6 -:105E3000A42A3B1A3C010800A4203B2E0E000AD0E5 -:105E4000000000008F8500208FBF0010AF8200107F -:105E500090A8000D27BD00180008394203E0000893 -:105E600030E20001912300003062003F104400271F -:105E70008F85001C8CE400241480002100000000A9 -:105E80008D2E00183C187FFF8F85001C370FFFFFF9 -:105E900001CF1824AF8300048F9F00048CA80084D6 -:105EA00003E8C82B1720000203E020218CA4008403 -:105EB0000A000B8BAF8400048CA3010C0A000B6951 -:105EC000AF8300148D2C00188F8600043C0D7FFFDB -:105ED0008F89001C35A3FFFF01835824240400018F -:105EE000AF8B000CAD2000CCA38400000A000B9700 -:105EF000AF8600088CCA00140A000B8BAF8A00041E -:105F00008CA300C80A000BCEAF8300048F84002846 -:105F10008CAC00648C8D0014018D582B1160000432 -:105F2000000000008CA200640A000BCEAF820004C7 -:105F30008C8200140A000BCEAF8200048F8500080B -:105F400027BDFFE0AFBF0018AFB1001414A00007D9 -:105F5000AFB000108F8600202402000590C400001E -:105F60003083003F106200B68F84001C8F910004C4 -:105F700000A080218F8C00243C0508008CA53B0CE0 -:105F80008D8B000431663FFF00C5502B554000014A -:105F900000C02821938D000011A0007300B0F82BE1 -:105FA0008F98001C24040034930F00BC31EE0002D3 -:105FB00051C000012404003000A4C82B172000D1D8 -:105FC0000000000000A4282300B0F82B3C010800CA -:105FD000A4243B1817E00068020020213C030800BD -:105FE0008C633B080083102B544000010080182173 -:105FF0008F8800203C010800AC233B1000004821A2 -:106000009104000D30830020506000018F490E186C -:106010008F8300100123382B10E00059000000008E -:106020003C0408008C843B1000895821006B502BE5 -:10603000114000560090602B0069302300C02021E1 -:106040003C010800AC263B1012000003241FFFFC9B -:106050001090008A32270003009FC8243C010800EA -:10606000AC393B103C010800A4203B2E8F84000873 -:10607000120400078F83001CAF910004020020214E -:106080008C7100CCAF90000826300001AC7000CCC1 -:106090003C0208008C423B108F8A000C2407001839 -:1060A0000082202301422823AF84000810800002D0 -:1060B000AF85000C240700108F8600183C010800F3 -:1060C000A0273B2C2407004090CC0085318B00C0DA -:1060D000116700408F8D001014A0001500002021D2 -:1060E000934A01098F420974314500FF00022602DC -:1060F00024A300013090007F3071007F1230007ABD -:106100002407FF80A0C300833C0908008D293B2899 -:106110008F880020240D0002352C00083C01080067 -:10612000A02D3B6D3C010800AC2C3B282404001042 -:10613000910E000D31C6002010C00005008018210E -:10614000240800013C010800AC283B103483000106 -:106150008FBF00188FB100148FB0001000601021A5 -:1061600003E0000827BD00203C010800A4203B18E4 -:1061700013E0FF9A020020210A000C1F00A020213A -:106180003C0408008C843B100090602B1180FFAE13 -:10619000000000003C0F080095EF3B1801E470215F -:1061A00001C6682B11A000072C8200043C1F600070 -:1061B0008FF954043338003F1700FFE524030042F1 -:1061C0002C8200041040FFA0240300420A000C7D32 -:1061D0008FBF0018152DFFC0000000008CDF007479 -:1061E0003C0380002405FF8003E3C825ACD900747C -:1061F00090D80085240E000424040010330F003FC3 -:1062000001E54025A0C800858F8800203C010800DA -:10621000A02E3B6D240300019106000D30C9002023 -:1062200015200003000000003C0308008C633B10B5 -:106230003C010800AC233B080A000C74000000007D -:106240008F87000C8C88008400E8282B14A00002A3 -:1062500000E088218C91008424090001A3890000BA -:106260008F440E18022028210E000AD0022030216F -:10627000022080210A000C05AF82001000071823BD -:10628000306600033C010800A4263B2E12200005C6 -:106290008F8C001C918B00BC316A000415400015E6 -:1062A00024CD00043C0F080095EF3B2E01E4702143 -:1062B00000AE302B50C0FF6E8F8400082C85000587 -:1062C00014A0FFA32403004230980003170000022B -:1062D000009818232483FFFC3C010800AC233B10EA -:1062E0000A000C410000000000A758240A000C69B5 -:1062F000016718263C010800A42D3B2E0A000CD192 -:10630000000000003C010800AC203B100A000C7C9F -:10631000240300428F83000C14600007000010214A -:106320008F880020240500059106000030C400FF7E -:10633000108500030000000003E0000800000000DA -:10634000910A0018314900FF000939C214E0FFFA30 -:106350008F8500183C04080094843B183C03080017 -:106360008C633B303C1908008F393B103C0F080010 -:1063700095EF3B2E0064C0218CAD005403197021B1 -:1063800001CF6021018D58231960001D000000001D -:10639000910E001C8F8C0028974B0E1031CD00FF02 -:1063A0008D850004016D30238D88000030CEFFFF05 -:1063B000000E510000AAC821000038210107202149 -:1063C000032A182B0083C021AD990004AD9800006A -:1063D000918F000A01CF6821A18D000A8F880028C3 -:1063E000974B0E12A50B0008950A003825490001AD -:1063F000A50900389107000D34E60008A106000D3C -:1064000003E000080000000027BDFFE093870000C4 -:106410008F8F00208FAD00143C0E7FFF8F89000806 -:1064200035C8FFFFAFBF001CAFB0001801A818248B -:1064300091EA000D000717C03C1FBFFF00625825FE -:106440002D2E00018F90001437F9FFFF3C18080033 -:106450008F183B303C0F080095EF3B2601796824EC -:10646000000E47803C07EFFF3C05F0FF01A8182510 -:106470003149002034E2FFFF34ACFFFF0310582302 -:1064800027A500102406000225EA00020062182455 -:106490000080802115200002000040218F480E1C42 -:1064A000A7AA0012056000372407000030FF00FF94 -:1064B000001FCF008F8B001800793825AFA700147C -:1064C000916F00853C08080091083B2D3C18DFFFC8 -:1064D00031EE00C0370AFFFF000E182B3C1F0800EA -:1064E00097FF3B2000EA6824A3A80011000317408F -:1064F00001A248258FB90010AFA900143C0A08007A -:10650000914A3B2FA7BF00168FA80014032CC0246C -:106510003C0B01003C0F0FFF030B18253147000314 -:1065200035EEFFFF010C682400071600006EF8240A -:106530003C09700001A2C82503E95825AFB9001431 -:10654000AFAB00100E000072A3A000158F8C0020CE -:10655000260200089186000D30C40020108000063D -:106560008FBF001C3C05080094A53B1C24B0FFFF16 -:106570003C010800A4303B1C8FB0001803E0000869 -:1065800027BD00208F9800100118502B5540FFC7E1 -:10659000240700010A000D5430FF00FF9382000021 -:1065A00027BDFFE0AFBF00181040000F0080502152 -:1065B0008F880020240B00058F89000491070000BC -:1065C0008F84001C0100282130E3003F8F860028C3 -:1065D000106B000800003821AFA900100E0004392C -:1065E000AFAA0014A38000008FBF001803E00008CA -:1065F00027BD00208D1900183C0F08008DEF3B10BF -:106600008F98000C3C027FFF8D080014345FFFFF61 -:10661000033F682401F8702101AE6023018838210E -:10662000AFA900100E000439AFAA00140A000DA291 -:10663000A38000008F8700203C05080094A53B2E16 -:106640003C0208008C423B2890E6000D0005240027 -:1066500030C300201060002C004440258F850018B6 -:1066600000006021240B000190A300850000482158 -:10667000240A00013C0F800035EE00708DC7000039 -:10668000AF8700308F5801780700FFFE3C03800081 -:10669000347900708F3800003C0508008CA5007428 -:1066A0003C0D08008DAD00700307782300AF382142 -:1066B0000000102100EF302B01A2202100861821BC -:1066C0003C010800AC2700743C010800AC230070BA -:1066D000AF4B01483C1908008F393B30A7490144B2 -:1066E000A74A0146AF59014C3C0B0800916B3B2D6A -:1066F000A34B0152AF4801543C081000A74C01586D -:1067000003E00008AF4801788F4B0E1C3C0A0800DC -:106710008D4A3B1097490E16974D0E140145602186 -:10672000312AFFFF0A000DC531A9FFFF8F8300202A -:106730009064000D3082002010400029000000000D -:106740000000482100005021000040213C0780004B -:1067500034EB00708D670000AF8700308F4C0178FC -:106760000580FFFE3C0D800035AC00708D8B000075 -:106770003C0508008CA500743C0408008C84007063 -:106780000167302300A678210000102101E6C82B04 -:106790000082C021031970213C010800AC2F007455 -:1067A0003C010800AC2E0070AF4901483C0D0800C8 -:1067B0008DAD3B30A748014424090040A74A01465B -:1067C0003C081000240AFF91AF4D014CA34A01522E -:1067D000AF490154A740015803E00008AF480178D1 -:1067E0008F490E1897460E1297450E1030CAFFFFBC -:1067F0000A000DFB30A8FFFF8F83002027BDFFF8A4 -:106800009064000D308200201040003A000000002B -:10681000240B000100004821240A00013C088000EC -:10682000350700708CE30000AF8300308F4C017897 -:106830000580FFFE3C0E80003C04080090843B6C09 -:1068400035C700708CEC00003C0508008CA5007476 -:10685000A3A400033C1908008F3900708FAD00001D -:106860000183302300A63821000010210322782163 -:1068700000E6C02B01F8602101AE4025AFA8000062 -:106880003C010800AC2700743C010800AC2C0070EF -:106890009346010A3C04080090843B6DA3A00002CB -:1068A000A3A600018FA300003C0580FF3099007F64 -:1068B00034A2FFFF006278240019C60001F8702599 -:1068C000240D3000AF4E014C27BD0008AF4D0154E0 -:1068D000A7400158AF4B0148A7490144A74A0146C8 -:1068E0003C091000240AFF80A34A015203E000087B -:1068F000AF4901788F4B0E1897460E1297450E1030 -:1069000030CAFFFF0A000E2F30A9FFFF8F85001845 -:106910002402008090A40085308300C0106200052E -:106920008F86001C8F8800048F870008ACC800C8C1 -:10693000ACC700C403E00008000000003C0A0800E7 -:10694000254A37CC3C090800252938983C0808001E -:1069500025082C4C3C07080024E739AC3C0608000D -:1069600024C6363C3C05080024A533B43C0408008A -:1069700024842FDC3C030800246336D43C02080046 -:10698000244234A83C010800AC2A3C383C010800F1 -:10699000AC293C343C010800AC283C303C010800E8 -:1069A000AC273C3C3C010800AC263C4C3C010800B8 -:1069B000AC253C443C010800AC243C403C010800B0 -:1069C000AC233C503C010800AC223C4803E00008EA -:0469D00000000000C3 -:00000001FF -/* - * This file contains firmware data derived from proprietary unpublished - * source code, Copyright (c) 2004 - 2009 Broadcom Corporation. - * - * Permission is hereby granted for the distribution of this firmware data - * in hexadecimal or equivalent format, provided this copyright notice is - * accompanying it. - */ diff --git a/firmware/bnx2/bnx2-mips-06-5.0.0.j3.fw.ihex b/firmware/bnx2/bnx2-mips-06-5.0.0.j3.fw.ihex new file mode 100644 index 0000000..652e6c8 --- /dev/null +++ b/firmware/bnx2/bnx2-mips-06-5.0.0.j3.fw.ihex @@ -0,0 +1,5841 @@ +:10000000080001100800000000004CC8000000C8F3 +:1000100000000000000000000000000008004CC8C4 +:100020000000001400004D90080000880800000047 +:10003000000058D000004DA408005A400000008481 +:100040000000A674080058D0000001540000A6F873 +:10005000080031D808000000000070F00000A84C33 +:10006000000000000000000000000000080070F028 +:10007000000000240001193C080004880800040066 +:100080000000175C00011960000000000000000083 +:100090000000000000000000000000000000000060 +:1000A000080000A80800000000003B38000130BC38 +:1000B0000000000000000000000000000000000040 +:0800C000000000000000000038 +:0800C8000A00004400000000E2 +:1000D000000000000000000D636F6D352E302E30E3 +:1000E0006A33000005000002000000000000000369 +:1000F00000000014000000320000000300000000B7 +:1001000000000000000000000000000000000000EF +:1001100000000010000001360000EA600000000549 +:1001200000000000000000000000000000000008C7 +:1001300000000000000000000000000000000000BF +:1001400000000000000000000000000000000000AF +:10015000000000000000000000000000000000009F +:10016000000000020000000000000000000000008D +:10017000000000000000000000000000000000007F +:10018000000000000000000000000010000000005F +:10019000000000000000000000000000000000005F +:1001A000000000000000000000000000000000004F +:1001B000000000000000000000000000000000003F +:1001C000000000000000000000000000000000002F +:1001D000000000000000000000000000100000030C +:1001E000000000000000000D0000000D3C020800AF +:1001F00024424D003C03080024634DFCAC40000049 +:100200000043202B1480FFFD244200043C1D080005 +:1002100037BD7FFC03A0F0213C1008002610011020 +:100220003C1C0800279C4D000E000214000000003A +:100230000000000D27BDFFE8AFBF0014AFB00010F5 +:100240009742010830437000240220001062000B26 +:10025000286220011440002F0000102124024000D9 +:1002600010620025000000002402600010620026D9 +:10027000000010210A0000948FBF001427500100D5 +:10028000920200091040001A240300013C020800F9 +:100290008C42002010400016000018210E00052B93 +:1002A00000000000960300083C06080094C64DBEFE +:1002B0008E0400188F8200209605000C00031C009D +:1002C00000661825AC440000AC450004240400017D +:1002D000AC400008AC40000CAC400010AC40001436 +:1002E000AC4000180E000550AC43001C0000182163 +:1002F0000A000093006010210E0003BD0000000002 +:100300000A000093000010210E000F810000000081 +:10031000000010218FBF00148FB0001003E0000810 +:1003200027BD001827BDFFE0AFB00010AFBF001819 +:10033000AFB10014275001009203000B2402001AF1 +:10034000961100081462005B00002821322200018F +:1003500010400008000000008E0200009603001408 +:10036000000211C200021040005A10210A0000DBF6 +:10037000A44300803C0208008C420020104000286A +:10038000000000000E00052B00000000974201084D +:100390009743010C8F8500203042003E3063FFFF01 +:1003A0000002140000431025ACA200008F4201009F +:1003B0003C06080094C64DBEACA20004974301164B +:1003C0009744010E3C02200000031C003084FFFF14 +:1003D00000641825ACA3000800C230259742011024 +:1003E0009743011224040001000214003063FFFF50 +:1003F00000431025ACA2000C974201143042FFFFCD +:10040000ACA200108F420118ACA200149342010B61 +:10041000304200FFACA200180E000550ACA6001C34 +:100420003C0208008C420040244200013C010800CC +:10043000AC2200403C0308008C63004432220002DE +:1004400032240004246300013C010800AC23004472 +:10045000108000180002282B8F4202B804430008C5 +:100460008E0200203C0208008C4200602442000101 +:100470003C010800AC2200600A0000FB24050001DA +:100480009603001600002821AF4202808E0200046D +:10049000A7430284AF4202883C021000AF4202B878 +:1004A0003C0208008C42005C244200013C01080030 +:1004B000AC22005C8FBF00188FB100148FB0001009 +:1004C00000A0102103E0000827BD002027BDFFE0A9 +:1004D000AFB00010AFBF0018AFB10014275001003B +:1004E0009203000B24020003961100081462006DB1 +:1004F000000020213222000110400008000000000E +:100500008E02000096030014000211C20002104087 +:10051000005A10210A000142A44300803C02080056 +:100520008C42002010400025000000000E00052B2A +:1005300000000000974201089743010C8F850020BE +:100540003042003E3063FFFF0002140000431025DC +:10055000ACA200008F4201003C06080094C64DBECC +:10056000ACA20004974301169744010E3C02200000 +:1005700000031C003084FFFF00641825ACA30008B2 +:1005800000C2302597420110974301122404000154 +:10059000000214003063FFFF00431025ACA2000CE2 +:1005A000974201143042FFFFACA20010ACA000142F +:1005B000ACA000180E000550ACA6001C3C020800C0 +:1005C0008C420040244200013C010800AC22004063 +:1005D0003C0208008C420044322300042442000103 +:1005E0003C010800AC2200441060001A32220002D4 +:1005F0008F4202B8044300088E0200203C0208002B +:100600008C420060244200013C010800AC220060E2 +:100610000A0001772404000196030016000020213F +:10062000AF4202808E020004A7430284AF420288D8 +:100630003C021000AF4202B83C0208008C42005C51 +:10064000244200013C010800AC22005C0A00017851 +:100650008FBF001810400013000020218F430104B9 +:100660003C026020AC4300148C420004240301FED1 +:10067000304203FF1443000B000020218F42010091 +:10068000000211C02442FFFC2C420008104000026E +:100690002403000200031F403C026000AC436914C5 +:1006A000000020218FBF00188FB100148FB0001000 +:1006B0000080102103E0000827BD00208F430100C7 +:1006C0002402010050620003000311C20000000D6B +:1006D000000311C200021040005A1021A440008003 +:1006E00003E00008000010219362000003E000080E +:1006F000AF80000003E000080000102103E00008C4 +:1007000000001021240201001482000800000000F3 +:100710003C0208008C4200FC244200013C0108001D +:10072000AC2200FC0A00019F30A200203C0208001D +:100730008C420084244200013C010800AC22008469 +:1007400030A200201040000830A300103C02080036 +:100750008C420108244200013C010800AC2201083F +:1007600003E0000800000000106000080000000026 +:100770003C0208008C420104244200013C010800B4 +:10078000AC22010403E00008000000003C02080065 +:100790008C420100244200013C010800AC2201000F +:1007A00003E000080000000027BDFFE8AFBF001015 +:1007B0002744010094830008306200041040001BAD +:1007C000306600028F4202B804410008240500018F +:1007D0003C0208008C420060244200013C010800F9 +:1007E000AC2200600A0001EB8FBF00108C82002059 +:1007F0009483001600002821AF4202808C820004FE +:10080000A7430284AF4202883C021000AF4202B804 +:100810003C0208008C42005C244200013C010800BC +:10082000AC22005C0A0001EB8FBF001010C0000674 +:10083000006028218F4401000E00018F000000009D +:100840000A0001EA240500018F8200088F43010499 +:1008500050430007000028218F4401000E00018F43 +:10086000000000008F420104AF8200080000282130 +:100870008FBF001000A0102103E0000827BD001862 +:100880003C0208008C420088274301009465000C5C +:10089000244200013C010800AC2200888C6400184E +:1008A0000345102190454000AF4400388C62001C85 +:1008B0002403FFF800052E000043102434420004F6 +:1008C000AF42003C3C020005AF4200300000000097 +:1008D0000000000000000000AF450404000000001C +:1008E00000000000000000003C020006344200014D +:1008F000AF420030000000000000000000000000D7 +:100900008F420000304200101040FFFD0000102117 +:1009100003E000080000000027BDFFE0AFB20018B0 +:100920003C036010AFBF001CAFB10014AFB00010AB +:100930008C6450002402FF7F3C1A80000082202437 +:100940003484380C24020037AC6450003C12080098 +:1009500026524D38AF42000824020C80AF420024DA +:100960003C1B80083C06080024C6062C02401021CF +:100970002404001C2484FFFFAC4600000481FFFD1A +:10098000244200043C0208002442016C3C0108009F +:10099000AC224D403C020800244204043C01080003 +:1009A000AC224D443C020800244207B83C01080038 +:1009B000AC224D883C0208002442025C3C03080043 +:1009C000246306343C040800248406E03C05080047 +:1009D00024A53B503C010800AC224DA03C0208007D +:1009E000244205F43C010800AC264D843C0108007B +:1009F000AC254D943C010800AC234D9C3C01080003 +:100A0000AC244DA43C010800AC224DA83C010800D8 +:100A1000AC234D3C3C010800AC204D483C01080093 +:100A2000AC204D4C3C010800AC204D503C0108006E +:100A3000AC204D543C010800AC204D583C0108004E +:100A4000AC204D5C3C010800AC204D603C0108002E +:100A5000AC244D643C010800AC204D683C0108000A +:100A6000AC204D6C3C010800AC204D703C010800EE +:100A7000AC204D743C010800AC204D783C010800CE +:100A8000AC264D7C3C010800AC264D803C010800A2 +:100A9000AC204D8C3C010800AC254D903C01080079 +:100AA000AC234D980E0006BB000000003C02800005 +:100AB000344200708C420000AF8200143C030800F6 +:100AC0008C6300208F820004104300043C028000ED +:100AD0000E0004F3AF8300043C0280003446007033 +:100AE0003C0308008C6300A03C0208008C4200A478 +:100AF000104300048F8400143C010800AC2300A4C0 +:100B0000A743009E8CCA00003C0308008C6300BC15 +:100B10003C0208008C4200B80144202300641821E4 +:100B2000000040210064202B0048102100441021C7 +:100B30003C010800AC2300BC3C010800AC2200B81A +:100B40008F510000322200071040FFDCAF8A0014F2 +:100B50008CC600003C0508008CA500BC3C040800C5 +:100B60008C8400B800CA302300A628210000102180 +:100B700000A6302B00822021008620213227000190 +:100B80003C010800AC2500BC3C010800AC2400B8C6 +:100B900010E0001F322200028F420100AF4200200D +:100BA0008F420104AF4200A89342010B0E0001885E +:100BB000305000FF2E02001D544000040010108031 +:100BC0000E00018B0A0002C5000000000052102137 +:100BD0008C4200000040F8090000000010400005B1 +:100BE0003C0240008F4301043C026020AC430014EF +:100BF0003C024000AF4201383C0208008C42003405 +:100C0000244200013C010800AC22003432220002E0 +:100C10001040000E322200048F4201400E00018875 +:100C2000AF4200200E00034B000000003C024000D9 +:100C3000AF4201783C0208008C4200382442000197 +:100C40003C010800AC220038322200041040FF981A +:100C50003C0280008F4201800E000188AF420020DC +:100C60008F43018024020F00146200050000000081 +:100C70008F420188A742009C0A0002FA3C02400011 +:100C80009362000024030050304200FF1443000828 +:100C90003C0240000E00032D000000005440000400 +:100CA0003C0240000E000E0D000000003C0240001F +:100CB000AF4201B83C0208008C42003C24420001D3 +:100CC0003C010800AC22003C0A00027A3C02800091 +:100CD0003C0290003442000100822025AF440020F5 +:100CE0008F4200200440FFFE0000000003E00008E7 +:100CF000000000003C0280003442000100822025F8 +:100D000003E00008AF44002027BDFFE0AFB10014AE +:100D1000AFB0001000808821AFBF00180E000302A2 +:100D200030B000FF9362007D022020210202802566 +:100D3000A370007D8F7000743C0280000E00030BD6 +:100D400002028024160000098FBF00188F4201F8AC +:100D50000440FFFE24020002AF5101C0A34201C4BF +:100D60003C021000AF4201F88FBF00188FB1001491 +:100D70008FB0001003E0000827BD002027BDFFE86A +:100D8000AFBF0010974201843042020010400005BE +:100D9000000020210E001042000000000A00034164 +:100DA000240400018F420188044000098FBF001015 +:100DB0008F4201883C03FF00004310243C030400E1 +:100DC00014430003240400019362003E8FBF00100F +:100DD0000080102103E0000827BD00182402000154 +:100DE000A3600022A76200168F4401400A0003108E +:100DF0002405000127BDFFE8AFBF0014AFB000100D +:100E000093620000304400FF3883002038820030B5 +:100E10000003182B0002102B00621824106000033E +:100E200024020050148200628FBF001493420148D4 +:100E3000304200FF2443FFFF2C6200051040005C9D +:100E40008FBF0014000310803C03080024634CC8CB +:100E5000004310218C420000004000080000000008 +:100E60000E0003028F4401408F70000C8F4201443A +:100E70001602000224020001AF62000C0E00030BF8 +:100E80008F4401408F420144145000048FBF00146E +:100E90008FB000100A000FB827BD00188F62000C39 +:100EA0000A0003B300000000976200108F43014462 +:100EB0003042FFFF1462000900000000240200011C +:100EC000A76200108F420140AF4202003C021000B6 +:100ED000AF4202380A0003BA8FBF001497620010B5 +:100EE0000A0003B3000000000E0003028F4401401B +:100EF000976200128F4301443050FFFF1603000237 +:100F000024020001A76200120E00030B8F4401406F +:100F10008F420144160200048FBF00148FB00010EE +:100F20000A00034527BD0018976200120A0003B3A8 +:100F300000000000976200148F4301443042FFFF1D +:100F4000146200068FBF0014240200018FB000104D +:100F5000A76200140A0012E227BD0018976200146D +:100F60000A0003B300000000976200168F4301449B +:100F70003042FFFF14620006240200018FBF0014FC +:100F80008FB00010A76200160A000BAA27BD001838 +:100F900097620016144000068FBF00143C02080040 +:100FA0008C420070244200013C010800AC22007019 +:100FB0008FB0001003E0000827BD001827BDFFE830 +:100FC000AFBF0014AFB000108F500100936200005B +:100FD00093430109304400FF2402001F106200A562 +:100FE0002862002010400018240200382862000AFD +:100FF0001040000C2402000B286200081040002C56 +:1010000000000000046000E528620002144000288F +:1010100024020006106200268FBF00140A0004B7E5 +:101020008FB000101062005E2862000B144000DCDC +:101030008FBF00142402000E106200738FB00010E6 +:101040000A0004B700000000106200C028620039E6 +:101050001040000A2402008024020036106200CAF8 +:1010600028620037104000B424020035106200C12D +:101070008FBF00140A0004B78FB000101062002B5D +:101080002862008110400006240200C824020039B2 +:10109000106200B48FBF00140A0004B78FB00010B4 +:1010A000106200998FBF00140A0004B78FB00010BF +:1010B0003C0208008C420020104000B98FBF001491 +:1010C0000E00052B000000008F4201008F830020DE +:1010D0009745010C97460108AC6200008F4201045D +:1010E0003C04080094844DBE00052C00AC62000452 +:1010F0008F4201180006340000C43025AC6200089D +:101100008F42011C24040001AC62000C9342010ACE +:1011100000A22825AC650010AC600014AC6000187B +:10112000AC66001C0A00048D8FBF00143C0208004E +:101130008C4200201040009A8FBF00140E00052B37 +:1011400000000000974401083C03080094634DBE72 +:101150009745010C000422029746010E8F82002061 +:10116000000426000083202500052C003C0300809D +:1011700000A6282500832025AC400000AC400004D8 +:10118000AC400008AC40000CAC450010AC40001472 +:10119000AC400018AC44001C0A00048C240400017C +:1011A0009742010C144000150000000093620005F6 +:1011B0003042001014400011000000000E00030235 +:1011C0000200202193620005020020213442001019 +:1011D0000E00030BA36200059362000024030020AD +:1011E000304200FF1043006D020020218FBF001429 +:1011F0008FB000100A00105827BD00180000000D25 +:101200000A0004B68FBF00143C0208008C42002084 +:10121000104000638FBF00140E00052B000000007B +:101220008F4201048F8300209744010C3C05080085 +:1012300094A54DBEAC6200009762002C000424000F +:101240003042FFFF008220253C02400E00A22825EC +:10125000AC640004AC600008AC60000CAC60001032 +:10126000AC600014AC600018AC65001C0A00048C73 +:10127000240400010E00030202002021A7600008E0 +:101280000E00030B02002021020020210E0003109B +:10129000240500013C0208008C4200201040004060 +:1012A0008FBF00140E00052B000000009742010CB8 +:1012B0008F8300203C05080094A54DBE0002140059 +:1012C000AC700000AC620004AC6000088F64004C9D +:1012D0003C02401F00A22825AC64000C8F62005025 +:1012E00024040001AC6200108F620054AC62001450 +:1012F000AC600018AC65001C8FBF00148FB00010EC +:101300000A00055027BD0018240200205082002545 +:101310008FB000100E000FA202002021104000200C +:101320008FBF0014020020218FB000100000282180 +:101330000A00031027BD0018020020218FBF0014EF +:101340008FB000100A00061827BD00189745010C41 +:10135000020020218FBF00148FB000100A00063851 +:1013600027BD0018020020218FB000100A00065D82 +:1013700027BD00189345010D020020218FB00010F9 +:101380000A0006A727BD0018020020218FBF001405 +:101390008FB000100A00068327BD00188FBF00140D +:1013A0008FB0001003E0000827BD00188F420278BC +:1013B0000440FFFE2402000234840080AF44024057 +:1013C000A34202443C02100003E00008AF4202784E +:1013D0003C04080094844DCA3C0208008C424DD461 +:1013E0003083FFFF000318C000431021AF42003CD0 +:1013F0003C0208008C424DD0AF4200383C02005005 +:1014000034420008AF42003000000000000000003D +:10141000000000008F420000304200201040FFFD1D +:10142000000000008F4204003C010800AC224DC0C7 +:101430008F4204043C010800AC224DC43C02002051 +:10144000AF420030000000003C02080094424DC84A +:101450003C03080094634DCC3C05080094A54DCE98 +:1014600024840001004310213083FFFF3C01080069 +:10147000A4224DC83C010800A4244DCA14650003F1 +:10148000000000003C010800A4204DCA03E0000851 +:10149000000000003C05000A27BDFFE803452821A5 +:1014A0003C04080024844DB0AFBF00100E0005B509 +:1014B0002406000A3C02080094424DB23C03080096 +:1014C00094634DCE3042000F2442000300431804C1 +:1014D00024027FFF0043102B10400002AF83001C4A +:1014E0000000000D0E0004C2000000003C020800D5 +:1014F00094424DBA8FBF001027BD001803E00008CA +:10150000A74200A23C02000A0342102194430006B5 +:101510003C02080094424DBA3C010800A4234DB699 +:10152000004310238F83001C0002140000021403E8 +:101530000043102B03E000083842000127BDFFE8FC +:10154000AFBF00103C02000A034210219442000683 +:101550003C010800A4224DB60E00050F000000005B +:101560005440FFF93C02000A8FBF001003E000085E +:1015700027BD001827BDFFE8AFBF00100E00050F04 +:101580000000000010400003000000000E00051DD8 +:10159000000000003C0208008C424DC08FBF0010CC +:1015A00027430400AF4200383C0208008C424DC47F +:1015B00027BD0018AF830020AF42003C3C0200056D +:1015C000AF42003003E00008AF8000188F8200189F +:1015D0003C0300060002114000431025AF420030DA +:1015E0000000000000000000000000008F4200002A +:1015F000304200101040FFFD27420400AF8200205F +:1016000003E00008AF8000183C0608008CC64DC4FB +:101610008F8500188F8300203C02080094424DBA49 +:1016200027BDFFE024A5000124630020244200011F +:1016300024C70020AFB10014AFB00010AFBF001836 +:10164000AF850018AF8300203C010800A4224DBAEA +:10165000309000FF3C010800AC274DC404C10008D5 +:101660000000882104E00006000000003C020800A1 +:101670008C424DC0244200013C010800AC224DC008 +:101680003C02080094424DBA3C03080094634DC8E4 +:101690000010202B004310262C420001004410258E +:1016A000144000048F830018240200101462000FFD +:1016B000000000000E000541241100013C03080059 +:1016C00094634DBA3C02080094424DC81462000372 +:1016D000000000000E0004C200000000160000031D +:1016E000000000000E00052B000000003C03080075 +:1016F00094634DBE3C02080094424DBC246300013B +:101700003064FFFF3C010800A4234DBE1482000397 +:10171000000000003C010800A4204DBE120000069D +:10172000000000003C02080094424DBAA74200A20B +:101730000A0005A3022010210E00050F0000000082 +:1017400010400004022010210E00051D00000000C2 +:10175000022010218FBF00188FB100148FB000102D +:1017600003E0000827BD00203084FFFF30A5FFFF05 +:1017700000001821108000070000000030820001E6 +:101780001040000200042042006518210A0005AB49 +:101790000005284003E000080060102110C000068A +:1017A00024C6FFFF8CA2000024A50004AC82000028 +:1017B0000A0005B52484000403E0000800000000CE +:1017C00010A0000824A3FFFFAC860000000000006A +:1017D000000000002402FFFF2463FFFF1462FFFAF1 +:1017E0002484000403E0000800000000240200013B +:1017F000AF62000CA7620010A7620012A76200147B +:1018000003E00008A76200163082007F0342102127 +:101810003C08000E004818213C0208008C420020C1 +:1018200027BDFFD82407FF80AFB3001CAFB200185C +:10183000AFB10014AFB00010AFBF00200080802116 +:1018400030B100FF0087202430D200FF1040002F6D +:1018500000009821AF44002C906200002403005047 +:10186000304200FF1443000E000000003C0208005C +:101870008C4200E00202102100471024AF42002CED +:101880003C0208008C4200E0020210213042007F3E +:101890000342102100481021944200D43053FFFF2E +:1018A0000E00052B000000003C02080094424DBED3 +:1018B0008F8300200011340000C2302500122C005C +:1018C0003C02400000C2302534A50001AC7000008D +:1018D0008FBF0020AC6000048FB20018AC7300080A +:1018E0008FB10014AC60000C8FB3001CAC6500100D +:1018F0008FB00010AC60001424040001AC6000182C +:1019000027BD00280A000550AC66001C8FBF0020D0 +:101910008FB3001C8FB200188FB100148FB000106D +:1019200003E0000827BD00289343010F24020010A4 +:101930001062000E2865001110A00007240200129A +:10194000240200082405003A10620006000030213D +:1019500003E0000800000000240500351462FFFCCD +:10196000000030210A0005D0000000008F42007402 +:1019700024420FA003E00008AF62000C27BDFFE87F +:10198000AFBF00100E000310240500018FBF001030 +:1019900024020001A762001227BD001824020001E2 +:1019A00003E00008A360002227BDFFE0AFB10014F0 +:1019B000AFB00010AFBF001830B1FFFF0E00030240 +:1019C000008080219362003F24030004304200FF26 +:1019D0001443000C02002021122000082402000AF7 +:1019E0000E0005C900000000936200052403FFFEFD +:1019F00000431024A362000524020012A362003FEA +:101A0000020020210E00030BA360008116200003BA +:101A1000020020210E00062D0000000002002021FF +:101A2000322600FF8FBF00188FB100148FB0001056 +:101A3000240500380A0005D027BD002027BDFFE09F +:101A4000AFBF001CAFB20018AFB10014AFB00010B0 +:101A50000E000302008080210E0005C90000000076 +:101A60009362003F24120018305100FF123200032D +:101A70000200202124020012A362003F93620005AD +:101A80002403FFFE004310240E00030BA362000595 +:101A9000020020212405002016320007000030211A +:101AA0008FBF001C8FB200188FB100148FB00010D0 +:101AB0000A00031027BD00208FBF001C8FB2001842 +:101AC0008FB100148FB00010240500390A0005D032 +:101AD00027BD002027BDFFE8AFB00010AFBF001446 +:101AE0009742010C2405003600808021144000102C +:101AF000304600FF0E000302000000002402001226 +:101B0000A362003F93620005344200100E0005C935 +:101B1000A36200050E00030B020020210200202119 +:101B20000E000310240500200A00069C000000009F +:101B30000E0005D0000000000E000302020020216C +:101B4000936200232403FF9F0200202100431024FE +:101B50008FBF00148FB00010A36200230A00030B94 +:101B600027BD001827BDFFE0AFBF0018AFB10014BC +:101B7000AFB0001030B100FF0E00030200808021E2 +:101B8000240200120E0005C9A362003F0E00030BE1 +:101B90000200202102002021022030218FBF0018E6 +:101BA0008FB100148FB00010240500350A0005D055 +:101BB00027BD0020A380002C03E00008A380002D97 +:101BC0008F4202780440FFFE8F820034AF42024011 +:101BD00024020002A34202443C02100003E0000879 +:101BE000AF4202783C0360008C625400304200082F +:101BF0001440FFFD000000008C625408AF82000C0E +:101C000024020052AC605408AC645430AC625434CA +:101C10002402000803E00008AC6254003C026000AB +:101C20008C42540030420008104000053C03600024 +:101C30008C625400304200081440FFFD0000000098 +:101C40008F83000C3C02600003E00008AC435408A2 +:101C500090A3000024020005008040213063003F73 +:101C600000004821146200050000502190A2001CD1 +:101C700094A3001E304900FF306AFFFFAD00000C46 +:101C8000AD000010AD000024950200148D05001C6D +:101C90008D0400183042FFFF00491023000211009C +:101CA000000237C3004038210086202300A2102BF9 +:101CB0000082202300A72823AD05001CAD040018D6 +:101CC000A5090014A5090020A50A001603E00008D4 +:101CD000A50A00228F4201F80440FFFE2402000200 +:101CE000AF4401C0A34201C43C02100003E000085D +:101CF000AF4201F83C0208008C4200B427BDFFE867 +:101D0000AFBF001424420001AFB000103C01080036 +:101D1000AC2200B48F4300243C02001F30AA00FF15 +:101D20003442FF8030D800FF006280240080F82118 +:101D300030EF00FF1158003B01405821240CFF8078 +:101D40003C19000A3163007F000310C000031940F2 +:101D5000006218213C0208008C4200DC256800016A +:101D6000310D007F03E21021004310213043007F3A +:101D700003431821004C102400794821AF4200246D +:101D80008D220024016C1824006C7026AD22000CFA +:101D90008D220024310800FFAD220010952200148E +:101DA000952300208D27001C3042FFFF3063FFFF8A +:101DB0008D2600180043102300021100000227C3E3 +:101DC0000040282100C4302300E2102B00C2302341 +:101DD00000E53823AD27001CAD2600189522002011 +:101DE000A522001495220022154B000AA5220016F8 +:101DF0008D2300248D2200082546000131450080F6 +:101E00001462000430C4007F108F000238AA0080E2 +:101E100000C0502151AF000131C800FF1518FFC9A3 +:101E2000010058218F8400343082007F0342182142 +:101E30003C02000A006218212402FF800082202454 +:101E4000AF440024A06A0079A06A00838C6200502D +:101E50008F840034AC6200708C6500743C027FFF9C +:101E60003442FFFF00A228240E000703AC65007473 +:101E7000AF5000248FBF00148FB0001003E00008A3 +:101E800027BD001827BDFFC0AFBE0038AFB7003474 +:101E9000AFB5002CAFB20020AFB1001CAFB000183E +:101EA000AFBF003CAFB60030AFB40028AFB30024E2 +:101EB0008F4500248F4600288F43002C3C02001FD2 +:101EC0003442FF800062182400C230240080A82120 +:101ED000AFA3001400A2F0240E0006C7AFA60010A6 +:101EE0003C0208008C4200E02410FF80036088213F +:101EF00002A2102100501024AF4200243C0208002E +:101F00008C4200E002A210213042007F03421821DF +:101F10003C02000A00629021924200D29363008446 +:101F2000305700FF306300FF2402000110620034CC +:101F30000360202124020002146200360000000029 +:101F40000E0012AE024028219223008392220083C9 +:101F50003063007F3042007F000210C00003194050 +:101F6000006218213C0208008C4200DC02A2102111 +:101F70000043382100F01024AF4200289225007859 +:101F80009224008330E2007F034218213C02000CBF +:101F900014850007006280212402FFFFA24200F1A5 +:101FA0002402FFFFA64200F20A0007BF2402FFFF3F +:101FB00096020020A24200F196020022A64200F200 +:101FC0008E020024AE4200F492220083A24200F06E +:101FD0008E4200C8AE4200FC8E4200C4AE4200F801 +:101FE0008E220050AE4201008E4200CCAE4201046F +:101FF000922200853042003F0A00081A3442004015 +:102000000E0012D102402821922200850A00081AEF +:102010003042003F936200852403FFDF3042003FDF +:10202000A36200859362008500431024A3620085AB +:102030009363008393620078307400FF304200FFA6 +:1020400010540036240AFF803C0C000C3283007FC1 +:10205000000310C000031940006218213C02080070 +:102060008C4200DC268800013109007F02A2102189 +:102070000043382130E2007F0342182100EA102497 +:10208000AF420028006C80218E020024028A1824AE +:10209000006A5826AE02000C8E020024310800FFB0 +:1020A000AE02001096020014960300208E07001C5A +:1020B0003042FFFF3063FFFF8E06001800431023FD +:1020C00000021100000227C30040282100C4302371 +:1020D00000E2102B00C2302300E53823AE07001CBD +:1020E000AE06001896020020A602001496020022F6 +:1020F000A602001692220079304200FF1054000719 +:102100000000000051370001316800FF9222007882 +:10211000304200FF1448FFCD0100A021922200832D +:10212000A22200798E2200500A00087AAE220070A6 +:10213000A22200858E22004C2405FF80AE42010CB5 +:102140009222008534420020A2220085924200D1D2 +:102150003C0308008C6300DC305400FF3C020800A4 +:102160008C4200E400143140001420C002A3182166 +:1021700000C4202102A21021006438210046102151 +:102180000045182400E52824AF450028AF43002C63 +:102190003042007F924400D030E3007F0342282188 +:1021A000034318213C02000C006280213C02000E17 +:1021B000309600FF00A298211296002A000000002D +:1021C0008E02000C02002021026028211040002510 +:1021D000261000280E0006E2000000009262000DAA +:1021E00026830001307400FF3042007FA262000DA0 +:1021F0002404FF801697FFF0267300203C0208009D +:102200008C4200DC0000A02102A210210044102416 +:10221000AF4200283C0208008C4200E43C03080066 +:102220008C6300DC02A2102100441024AF42002C79 +:102230003C0208008C4200E402A318213063007FB6 +:1022400002A210213042007F0342202103431821C3 +:102250003C02000C006280213C02000E0A00083C97 +:10226000008298218E4200D8AE2200508E4200D8C3 +:10227000AE22007092250083924600D19223008303 +:10228000924400D12402FF8000A228243063007F02 +:10229000308400FF00A628250064182A1060000280 +:1022A00030A500FF38A50080A2250083A225007973 +:1022B0000E0006D5000000009222007E02A0202120 +:1022C000A222007A8E2300743C027FFF3442FFFF7B +:1022D000006218240E000703AE2300748FA20010C2 +:1022E000AF5E00248FBF003CAF4200288FBE003895 +:1022F0008FA200148FB700348FB600308FB5002C3A +:102300008FB400288FB300248FB200208FB1001C3F +:102310008FB0001827BD004003E00008AF42002C3A +:1023200090A2000024420001A0A200003C0308008B +:102330008C6300F4304200FF1443000F0080302112 +:10234000A0A000003C0208008C4200E48F8400340E +:10235000008220213082007F034218213C02000CC1 +:10236000006218212402FF8000822024ACC30000F8 +:1023700003E00008AF4400288C82000024420020C3 +:1023800003E00008AC82000094C200003C08080092 +:10239000950800CA30E7FFFF0080482101021021A4 +:1023A000A4C2000094C200003042FFFF00E2102BE4 +:1023B00054400001A4C7000094A200003C030800A0 +:1023C0008C6300CC24420001A4A2000094A200006F +:1023D0003042FFFF544300078F8600280107102B6F +:1023E000A4A000005440000101003821A4C700004F +:1023F0008F8600288CC4001CAF44003C94A20000CF +:102400008F43003C3042FFFF000210C000621821E1 +:10241000AF43003C8F42003C008220231880000420 +:10242000000000008CC200180A0008DB24420001F2 +:102430008CC20018AF4200383C02005034420010F9 +:10244000AF4200300000000000000000000000006B +:102450008F420000304200201040FFFD00000000CD +:102460008F420404AD2200048F420400AD2200001C +:102470003C020020AF42003003E0000800000000F2 +:1024800027BDFFE0AFB20018AFB10014AFB000102D +:10249000AFBF001C94C2000000C080213C120800A5 +:1024A000965200C624420001A602000096030000D6 +:1024B00094E2000000E03021144300058FB10030A9 +:1024C0000E0008B0024038210A00090D000000008B +:1024D0008C8300048C8200042442004004610007C5 +:1024E000AC8200048C820004044000040000000060 +:1024F0008C82000024420001AC82000096020000A1 +:102500003042FFFF50520001A6000000962200005A +:1025100024420001A62200008F820028962300009A +:1025200094420016144300048FBF001C24020001D3 +:10253000A62200008FBF001C8FB200188FB10014BC +:102540008FB0001003E0000827BD00208F8900280D +:1025500027BDFFE0AFBF00188D22002827480400E8 +:1025600030E700FFAF4200388D22002CAF880030EA +:10257000AF42003C3C020005AF42003000000000CA +:10258000000000000000000000000000000000004B +:10259000000000008C82000C8C82000CAD02000058 +:1025A0008C820010AD0200048C820018AD0200087D +:1025B0008C82001CAD02000C8CA20014AD02001035 +:1025C0008C820020AD02001490820005304200FF92 +:1025D00000021200AD0200188CA20018AD02001C0F +:1025E0008CA2000CAD0200208CA20010AD020024D1 +:1025F0008CA2001CAD0200288CA20020AD02002C91 +:10260000AD060030AD000034978300263402FFFF92 +:1026100014620002006020213404FFFF10E000116A +:10262000AD040038952300369524003624020001BD +:102630003063FFFF000318C2006918219065004055 +:10264000308400070082100400451025A06200407D +:102650008F820028944200563042FFFF0A0009741E +:10266000AD02003C9523003695240036240200017B +:102670003063FFFF000318C2006918219065004015 +:102680003084000700821004000210270045102447 +:10269000A0620040AD00003C00000000000000000F +:1026A000000000003C02000634420040AF4200300F +:1026B0000000000000000000000000008F42000049 +:1026C000304200101040FFFD8F860028AF88003098 +:1026D00024C2005624C7003C24C4002824C500326C +:1026E00024C600360E0008EEAFA200108FBF0018FF +:1026F00003E0000827BD00208F8300243C0608006B +:102700008CC600E88F82003430633FFF00031980DD +:1027100000461021004310212403FF803046007F33 +:1027200000431024AF420028034618213C02000C4D +:102730000062302190C2000D30A500FF000038215A +:1027400034420010A0C2000D8F8900288F8A002417 +:1027500095230036000A138230480003240200014A +:10276000A4C3000E1102000B290200021040000554 +:10277000240200021100000C240300010A0009B821 +:102780000000182111020006000000000A0009B82C +:10279000000018218CC2002C0A0009B82443000153 +:1027A0008CC20014244300018CC200180043102B7B +:1027B00050400009240700012402002714A200034E +:1027C000000000000A0009C4240700019522003E11 +:1027D00024420001A522003E000A13823043000378 +:1027E0002C620002104000090080282114600004BF +:1027F0000000000094C200360A0009D43046FFFFF2 +:102800008CC600380A0009D400802821000030213D +:102810003C04080024844DD80A000921000000006F +:10282000274901008D22000C95230006012020215C +:10283000000216023046003F3063FFFF24020027EB +:1028400000C0282128C7002810C2000EAF83002432 +:1028500010E00008240200312402002110C2000907 +:102860002402002510C200079382002D0A0009F3FC +:102870000000000010C200059382002D0A0009F339 +:10288000000000000A00098C000000000A0006BEDB +:102890000000000095230006912400058D25000C02 +:1028A0008D2600108D2700188D28001C8D290020F2 +:1028B000244200013C010800A4234DDE3C01080035 +:1028C000A0244DDD3C010800AC254DE43C0108008E +:1028D000AC264DE83C010800AC274DF03C01080057 +:1028E000AC284DF43C010800AC294DF803E0000889 +:1028F000A382002D8F87002827BDFFC0AFB300340F +:10290000AFB20030AFB1002CAFB00028AFBF00387D +:102910003C0208008C4200D094E3003030B0FFFF4E +:10292000005010073045FFFF3063FFFF00C09821C3 +:10293000A7A200103C110800963100C614A300069F +:102940003092FFFF8CE2002424420030AF42003C72 +:102950000A000A2C8CE2002094E200323042FFFF91 +:1029600054A2000827A400188CE2002C2442003056 +:10297000AF42003C8CE20028AF4200380A000A3A1D +:102980008F84002827A5001027A6002002203821C8 +:102990000E0008B0A7A000208FA20018244200302B +:1029A000AF4200388FA2001CAF42003C8F84002849 +:1029B0003C020005AF4200309482003427430400FB +:1029C0003042FFFF0202102B14400007AF8300309B +:1029D0009482005494830034020210210043102397 +:1029E0000A000A4E3043FFFF94830054948200345F +:1029F0000223182100501023006218233063FFFFC8 +:102A0000948200163042FFFF1443000300000000D0 +:102A10000A000A5C24030001948200163042FFFF82 +:102A20000043102B104000058F8200309482001666 +:102A3000006210233043FFFF8F820030AC53000050 +:102A4000AC400004AC520008AC43000C3C02000651 +:102A500034420010AF4200300000000000000000CF +:102A6000000000008F420000304200101040FFFDC7 +:102A7000001018C20064182190650040320400075D +:102A8000240200018FBF00388FB300348FB20030B2 +:102A90008FB1002C8FB00028008210040045102553 +:102AA00027BD004003E00008A062004027BDFFA84A +:102AB000AFB60050AFB5004CAFB40048AFB3004460 +:102AC000AFB1003CAFBF0054AFB20040AFB0003870 +:102AD0008C9000003C0208008C4200E88F86003495 +:102AE000960300022413FF8000C2302130633FFFB1 +:102AF0000003198000C3382100F3102490B20000B5 +:102B0000AF42002C9203000230E2007F03423021EA +:102B10003C02000E00C28821306300C02402004045 +:102B20000080A82100A0B021146200260000A0218E +:102B30008E3400388E220018144000022402000156 +:102B4000AE2200189202000D304200201440001501 +:102B50008F8200343C0308008C6300DC001238C014 +:102B6000001231400043102100C7302100463821B7 +:102B700030E300073C02008030E6007800C23025D8 +:102B80000343182100F31024AF4208002463090016 +:102B9000AF4608108E2200188C63000800431021F5 +:102BA000AE2200188E22002C8E2300182442000131 +:102BB0000062182B1060003D000000000A000B109E +:102BC00000000000920300022402FFC00043102412 +:102BD000304200FF1440000524020001AE2200181C +:102BE000962200360A000AF93054FFFF8E220014A4 +:102BF00024420001AE2200189202000000021600DA +:102C000000021603044100290000000096020002A1 +:102C100027A4001000802821A7A200169602000217 +:102C200024070001000030213042FFFFAF82002462 +:102C30000E000921AFA0001C960300023C0408000E +:102C40008C8400E88F82003430633FFF00031980DA +:102C500000441021004310213043007F3C05000C4C +:102C60000053102403431821AF42002800651821A7 +:102C70009062000D001221403042007FA062000DE2 +:102C80003C0308008C6300E48F8200340043102171 +:102C90000044382130E2007F03421021004510211A +:102CA00000F31824AF430028AEA200009222000DCA +:102CB000304200101040001302A020218F83002812 +:102CC0008EA40000028030219462003E2442FFFF67 +:102CD000A462003E948400029625000E3084FFFF1B +:102CE0000E000A0B30A5FFFF8F82002894430034AA +:102CF0009622000E1443000302A0202124020001AA +:102D0000A382002C02C028210E00089600000000BB +:102D10008FBF00548FB600508FB5004C8FB4004861 +:102D20008FB300448FB200408FB1003C8FB00038A9 +:102D300003E0000827BD00588F82002827BDFFD080 +:102D4000AFB40028AFB20020AFBF002CAFB3002457 +:102D5000AFB1001CAFB00018904400D0904300D138 +:102D60000000A021309200FFA3A30010306300FFF9 +:102D70008C5100D88C5300DC1072002B240200010F +:102D80003C0308008C6300E493A400108F8200349D +:102D90002406FF800004214000431021004410213C +:102DA0003043007F00461024AF420028034318211F +:102DB0003C02000C006218218C62000427A400145D +:102DC00027A5001002228021027010230440001564 +:102DD000AFA300149062000D00C21024304200FF27 +:102DE00014400007020088219062000D3442004028 +:102DF0000E000896A062000D0A000B5593A2001069 +:102E00000E000A79241400018F830028AC7000D8CA +:102E100093A20010A06200D193A200101452FFD818 +:102E20000000000024020001168200048FBF002C65 +:102E30000E0006BE000000008FBF002C8FB40028DB +:102E40008FB300248FB200208FB1001C8FB0001808 +:102E500003E0000827BD003027BDFFD8AFB3001C3A +:102E6000AFB20018AFB10014AFB00010AFBF002078 +:102E70000080982100E0802130B1FFFF0E00052B7B +:102E800030D200FF00000000000000000000000041 +:102E90008F820020AC510000AC520004AC530008FB +:102EA000AC40000CAC400010AC400014AC4000182A +:102EB0003C03080094634DBE02038025AC50001C07 +:102EC00000000000000000000000000024040001D9 +:102ED0008FBF00208FB3001C8FB200188FB1001479 +:102EE0008FB000100A00055027BD002827BDFFE85D +:102EF000AFB00010AFBF001430A5FFFF30C600FF19 +:102F00000080802124020C80AF42002400000000D9 +:102F100000000000000000000000000000000000B1 +:102F20000E000B64000000003C040800248400E054 +:102F30008C8200002403FF808FBF00140202102146 +:102F400000431024AF4200248C8200003C03000A9E +:102F5000020280213210007F035010218FB0001038 +:102F60000043102127BD001803E00008AF820028AD +:102F700027BDFFE8AFBF00108F4401403C030800AD +:102F80008C6300E02402FF80AF84003400831821AA +:102F900000621024AF4200243C020008034240219A +:102FA000950500023063007F3C02000A03431821AC +:102FB0000062182130A5FFFF3402FFFF000030211E +:102FC0003C07602010A20006AF8300282402FFFF08 +:102FD000A5020002946500D40E000B8930A5FFFF06 +:102FE0008FBF001024020C8027BD001803E00008EA +:102FF000AF4200243C020008034240219502000237 +:103000003C0A0800954A00C63046FFFF14C000077E +:103010003402FFFF8F8200288F8400343C07602039 +:10302000944500D40A000BF230A5FFFF10C2002423 +:103030008F87002894E2005494E400163045FFFF87 +:1030400000A6102300A6182B3089FFFF1060000493 +:103050003044FFFF00C51023012210233044FFFF3E +:10306000008A102B1040000C012A102324020001BA +:10307000A50200162402FFFFA502000294E500D479 +:103080008F8400340000302130A5FFFF3C07602012 +:103090000A000B89000000000044102A10400008BC +:1030A00000000000950200163042000110400004AC +:1030B000000000009742007E24420014A502001682 +:1030C00003E00008000000008F84002827BDFFE017 +:1030D000AFBF0018948200349483003E1060001A41 +:1030E0003048FFFF9383002C240200011462002764 +:1030F0008FBF00188F820028000818C2310800070F +:10310000006218212447003A244900542444002036 +:10311000244500302446003490620040304200FFD5 +:103120000102100730420001104000168FBF001846 +:103130000E0008EEAFA900108F82002894420034E0 +:103140000A000C0B3048FFFF948300369482003451 +:103150001043000E8FBF001894820036A482003402 +:1031600094820056A48200548C82002CAC820024ED +:1031700094820032A48200309482003CA482003AFF +:103180008FBF00180A000BCB27BD002003E000080A +:1031900027BD002027BDFFE8AFBF00108F4A010008 +:1031A0003C0508008CA500E03C02080090424DE47C +:1031B0003C0C0800958C4DDE01452821304B003F2A +:1031C00030A2007F03424021396900323C02000AEC +:1031D0003963003F2C630001010240212D290001C9 +:1031E0002402FF8000A2282401234825AF8A00344E +:1031F00000801821AF4500240000302100802821E4 +:1032000024070001AF8800283C04080024844DD81E +:10321000AF8C002415200007A380002D240200207D +:103220005562000F006020213402FFFF5582000C20 +:10323000006020212402002015620005000000002B +:103240008C6300142402FFFF1062000700000000DE +:103250000E000921000000000A000C6800000000B8 +:103260000E00098C016028210E000C0000000000F7 +:103270008FBF001024020C8027BD001803E0000857 +:10328000AF4200243C0208008C4200E027BDFFA0B2 +:10329000AFB1003C008210212411FF80AFBE005866 +:1032A000AFB70054AFB20040AFB00038AFBF005C62 +:1032B000AFB60050AFB5004CAFB40048AFB3004458 +:1032C000005110248F4800248F4900288F47002880 +:1032D000AF4200243C0208008C4200E000809021B4 +:1032E00024060006008210213042007F034218218C +:1032F0003C02000A006280213C02001F3442FF8031 +:1033000000E2382427A40010260500F00122F02452 +:103310000102B8240E0005B5AFA700308FA2001837 +:10332000AE0200C48FA2001CAE0200C88FA200240F +:10333000AE0200CC93A40010920300D12402FF80BF +:103340000082102400431025304900FF3083007FA5 +:103350003122007F0062102A10400004000310C0D8 +:1033600001311026304900FF000310C0000319404E +:10337000006218213C0208008C4200DC920400D25A +:10338000024210210043102100511024AF420028B6 +:1033900093A300103063007F000310C000031940A6 +:1033A000006218213C0208008C4200DC024210211D +:1033B000004310213042007F034218213C02000CE0 +:1033C000006240218FA300142402FFFF106200302E +:1033D000309500FF93A2001195030014304400FFC4 +:1033E0003063FFFF0064182B1060000D0000000028 +:1033F000950400148D07001C8D0600183084FFFF13 +:1034000000442023000421000000102100E43821A2 +:1034100000E4202B00C230210A000CE200C430215D +:10342000950400148D07001C8D0600183084FFFFE2 +:1034300000822023000421000000102100801821B8 +:1034400000C2302300E4202B00C4302300E33823E3 +:10345000AD07001CAD06001893A20011A5020014D0 +:1034600097A20012A50200168FA20014AD02001050 +:103470008FA20014AD02000C93A20011A50200203F +:1034800097A20012A50200228FA20014AD02002410 +:103490002406FF80024610243256007FAF420024EB +:1034A000035618213C02000A006280218E02004C63 +:1034B0008FA200203124007F000428C0AE020050FB +:1034C0008FA200200004214000852821AE02007058 +:1034D00093A2001001208821A202008393A2001071 +:1034E000A2020079920200853042003FA2020085CC +:1034F0003C0208008C4200DC0242102100451021F1 +:1035000000461024AF42002C3C0208008C4200E42C +:103510003C0308008C6300DC0242102100441021AF +:1035200000461024AF4200283C0208008C4200E410 +:103530000243182100651821024210210044102185 +:103540003042007F3063007F93A5001003422021AA +:10355000034318213C02000E006240213C02000C93 +:1035600010B1008C008248213233007F16600019B0 +:103570002404FF803C0208008C4200DC024210213F +:1035800000441024AF42002C3C0208008C4200E4AE +:103590003C0308008C6300DC02421021004410242C +:1035A000AF4200283C0208008C4200E4024318218C +:1035B0003063007F024210213042007F034220210D +:1035C000034318213C02000E006240213C02000C23 +:1035D000008248219124000D2414FF800000102156 +:1035E00000942025A124000D9504000295050014E7 +:1035F0008D07001C3084FFFF30A5FFFF8D060018EB +:10360000008520230004210000E4382100C230217D +:1036100000E4202B00C43021AD07001CAD060018CB +:1036200095020002A5020014A50000168D020008F4 +:10363000AD0200108D020008AD02000C95020002E0 +:10364000A5020020A50000228D020008AD02002482 +:103650009122000D3042004010400042262200011D +:103660003C0208008C4200E0A3B300283C10000A92 +:103670000242102100541024AF4200243C020800F2 +:103680008C4200E0A380002C27A4002C02421021D1 +:103690003042007F03421821007018218C6200D84C +:1036A0008D26000427A50028AFA9002C0046102174 +:1036B000AC6200D80E000A79AF83002893A30028DB +:1036C0008F8200280E0006BEA04300D10E000C0021 +:1036D0000000000002541024AF4200243C02080005 +:1036E0008C4200DC00132940001320C000A42021DC +:1036F000024210210044102100541024AF42002C3B +:103700003C0208008C4200E43C0308008C6300DCAF +:10371000035630210242102100451021005410248C +:10372000AF4200283C0208008C4200E4024318210A +:103730000064182102421021004510213042007F10 +:103740003063007F03422021034318213C02000E16 +:10375000006240213C02000C00D080210082482100 +:10376000262200013043007F14750005304400FF1D +:103770002403FF800223102400431026304400FF5E +:1037800093A2001000808821250800281444FF76A9 +:103790002529002093A400108FA300142402FFFF0A +:1037A0001062000A308900FF248200012483000196 +:1037B0003042007F14550005306900FF2403FF806C +:1037C0000083102400431026304900FF9202007845 +:1037D000305300FF11330032012088213C020800E1 +:1037E0008C4200DC3225007F000520C00005294006 +:1037F00000A42021024210212406FF800044102151 +:1038000000461024AF42002C3C0308008C6300DC0F +:103810003C0208008C4200E40243182102421021BD +:103820000045102100641821004610243063007FF9 +:10383000AF420028034318213C02000E00624021E1 +:103840003C0208008C4200E48D06000C010020219F +:1038500002421021004510213042007F034218210E +:103860003C02000C0062482110C0000D01202821FC +:103870000E0006E2000000002402FF80022218244D +:1038800026240001006228263082007F14550002A1 +:10389000308300FF30A300FF1473FFD00060882145 +:1038A0008E0300743C027FFF3442FFFF0062182445 +:1038B000AE0300740E00070302402021AF5700241E +:1038C0008FA20030AF5E00288FBF005C8FBE005813 +:1038D0008FB700548FB600508FB5004C8FB400489E +:1038E0008FB300448FB200408FB1003C8FB00038DE +:1038F00027BD006003E00008AF42002C27BDFFD8C1 +:10390000AFB1001CAFBF0020AFB000182751018835 +:10391000922200032408FF803C03000A3047007F06 +:10392000A3A700108F4601803C0208008C4200E0F3 +:10393000AF86003400C2282100A81024AF42002422 +:103940009224000030A2007F034210210043102186 +:10395000AF8200283084007F2402000214820025F8 +:10396000000719403C0208008C4200E400C210210C +:103970000043282130A2007F0342182100A8102410 +:10398000AF4200283C02000C006218219062000D3A +:10399000AFA3001400481025A062000D8FA30014EF +:1039A0009062000D304200405040006A8FBF0020FE +:1039B0008F860028A380002C27A400148CC200D876 +:1039C0008C63000427A50010004310210E000A7923 +:1039D000ACC200D893A300108F8200280E0006BE50 +:1039E000A04300D10E000C00000000000A000EA34E +:1039F0008FBF00200E0006C700C020210E0006D594 +:103A0000000000003C0200080342802192230001D4 +:103A10009202007B1443004F8FBF002092220000CF +:103A20003044007F24020004108200172882000521 +:103A30001040000624020005240200031082000743 +:103A40008FB1001C0A000EA40000000010820012BA +:103A50008FBF00200A000EA48FB1001C92050083C6 +:103A6000920600788E0700748F84003430A500FF22 +:103A700000073E0230C600FF0E00070B30E7007F54 +:103A80000A000EA38FBF00200E000C6F8F8400343D +:103A90000A000EA38FBF002024020C80AF42002436 +:103AA0009202003E30420040104000200000000022 +:103AB0009202003E000216000002160304410006B6 +:103AC000000000008F8400340E00063824050093A7 +:103AD0000A000EA38FBF00209202003F24030018AB +:103AE000304200FF1443000C8F8400342405003959 +:103AF0000E0005D0000030210E0003028F84003438 +:103B000024020012A202003F0E00030B8F84003437 +:103B10000A000EA38FBF0020240500360E0005D03A +:103B2000000030210A000EA38FBF00200E00030208 +:103B30008F8400349202000534420020A202000566 +:103B40000E00030B8F8400340E0010588F84003455 +:103B50008FBF00208FB1001C8FB0001824020C8092 +:103B600027BD002803E00008AF42002427BDFFE87E +:103B7000AFB00010AFBF00142743010094620008EB +:103B8000000214000002140304410002000080211E +:103B90002410000194620008304200801040001A96 +:103BA00002001021946200083042200010400016EC +:103BB000020010218C6300183C021C2D344219EDC8 +:103BC000240600061062000F3C0760213C0208003A +:103BD0008C4200D4104000078F8200288F83002879 +:103BE000906200623042000F34420040A0620062E6 +:103BF0008F8200288F840034944500D40E000B89F6 +:103C000030A5FFFF020010218FBF00148FB00010FD +:103C100003E0000827BD001827BDFFE0AFB1001486 +:103C2000AFB00010A380002CAFBF00188F4501007B +:103C30003C0308008C6300E02402FF80AF85003461 +:103C400000A318213064007F03442021006218245F +:103C50003C02000A00822021AF43002427500100CB +:103C60008E0200148C8300DCAF84002800431023F4 +:103C700018400004000088218E0200140E000B1C66 +:103C8000AC8200DC9202000B24030002304200FFF1 +:103C90001443002F0000000096020008304300FF8C +:103CA0002402008214620005240200840E0009D65A +:103CB000000000000A000F2F00000000146200093D +:103CC000240200818F8200288F8400343C07602109 +:103CD000944500D49206000530A5FFFF0A000F1E90 +:103CE00030C600FF14620027000000009202000AA4 +:103CF000304300FF3062002010400004306200407A +:103D00008F8400340A000F1A24060040104000047B +:103D1000000316008F8400340A000F1A24060041A5 +:103D200000021603044100178F8400342406004269 +:103D30008F8200283C076019944500D430A5FFFF0E +:103D40000E000B89000000000A000F2F0000000089 +:103D50009202000B24030016304200FF10430006BD +:103D6000000000009202000B24030017304200FF05 +:103D700014430004000000000E000EA90000000023 +:103D8000004088210E000C00000000009202000A92 +:103D9000304200081040000624020C808F85002865 +:103DA0003C0400080E0012860344202124020C80EB +:103DB000AF4200248FBF0018022010218FB00010E6 +:103DC0008FB1001403E0000827BD002027BDFFE8E5 +:103DD000AFBF0014AFB000108F5000243C030800A8 +:103DE0008C6300E08F4501002402FF8000A31821AE +:103DF0003064007F03442021006218243C02000A42 +:103E000000822021AF850034AF43002490820062FD +:103E1000AF8400283042000F34420050A08200627C +:103E20003C02001F3442FF800E0006BE02028024C6 +:103E3000AF5000248FBF00148FB0001003E00008C3 +:103E400027BD00183C0208008C4200201040001DD5 +:103E50002745010090A300093C02000803422021ED +:103E600024020018546200033C0200080A000F708C +:103E700024020008034220212402001614620005D7 +:103E80002402001724020012A082003F0A000F7AC9 +:103E900094A700085462000694A7000893620005E6 +:103EA0002403FFFE00431024A362000594A700082A +:103EB00090A6001B8CA4000094A500060A000B64C9 +:103EC00000073C0003E00008000000002744010058 +:103ED00094820008304500FF38A3008238A2008495 +:103EE0002C6300012C4200010062182510600006BE +:103EF000240200839382002D1040000D000000007A +:103F00000A000C330000000014A2000524A2FF8068 +:103F10008F4301043C02602003E00008AC4300141E +:103F2000304200FF2C420002104000032402002215 +:103F30000A000ED40000000014A2000300000000DC +:103F40000A000F41000000000A000F5F000000009F +:103F50009363007E9362007A1443000900002021DD +:103F60009362000024030050304200FF1443000419 +:103F7000240400019362007E24420001A362007EBB +:103F800003E00008008010218F4201F80440FFFE8A +:103F900024020002AF4401C0A34201C43C0210004D +:103FA00003E00008AF4201F827BDFFE8AFBF0010F3 +:103FB0009362003F2403000A304200FF144300468E +:103FC000000000008F6300548F62004C1062007D7F +:103FD000036030219362000024030050304200FF50 +:103FE0001443002F000000008F4401403C020800F1 +:103FF0008C4200E02403FF80008210210043102443 +:10400000AF4200243C0208008C4200E08F6500545F +:104010003C03000A008220213084007F03441021E9 +:1040200000431021AC4501089762003C8F63004CAF +:104030003042FFFF0002104000621821AF63005CB5 +:104040008F6300548F64004C9762003C0064182317 +:104050003042FFFF00031843000210400043102AC3 +:1040600010400006000000008F6200548F63004C77 +:10407000004310230A000FF0000210439762003C37 +:104080003042FFFF00021040ACC200642402000175 +:10409000A0C0007CA0C2008424020C80AF42002497 +:1040A0000E000FA28F440140104000478FBF001048 +:1040B0008F4301408F4201F80440FFFE24020002BA +:1040C000AF4301C0A34201C43C021000AF4201F85B +:1040D0000A0010408FBF00109362003F24030010BD +:1040E000304200FF14430004000000008F440140F0 +:1040F0000A00102C000028219362003F24030016C0 +:10410000304200FF1443000424020014A362003F65 +:104110000A00103A000000008F62004C8F630050CC +:1041200000431023044100288FBF001093620081D8 +:1041300024420001A3620081936200812C420004AA +:1041400014400010000000009362003F24030004AC +:10415000304200FF14430006000000008F4401407D +:104160008FBF0010240500930A00063827BD0018F1 +:104170008F440140240500938FBF00100A0006A75A +:1041800027BD00188F4401400E000302000000000C +:104190008F6200542442FFFFAF6200548F620050D0 +:1041A0002442FFFFAF6200500E00030B8F4401401A +:1041B0008F4401408FBF0010240500040A00031043 +:1041C00027BD00188FBF001003E0000827BD0018AE +:1041D0008F4201889363007E00021402304400FF86 +:1041E000306300FF1464000D000000009362008043 +:1041F000304200FF1044000900000000A36400806A +:104200009362000024030050304200FF1443000476 +:10421000000000000A00076F8F440180A364008043 +:1042200003E000080000000027BDFFE8AFB0001069 +:10423000AFBF001493620005240300303042003009 +:1042400014430089008080213C0208008C42002039 +:1042500010400080020020210E00052B000000000D +:104260008F850020ACB000009362003E9363003F56 +:10427000304200FF00021200306300FF00431025AF +:10428000ACA2000493620082000216000002160332 +:1042900004410005000000003C0308008C63004856 +:1042A0000A00107E000000009362003E3042004091 +:1042B000144000030000182193620081304300FF86 +:1042C0009362008200031E00304200FF00021400CF +:1042D00000621825ACA300088F620040ACA2000C5D +:1042E0008F620048ACA200108F62004CACA2001498 +:1042F0008F6200508F63004C004310230441000381 +:10430000000000000A0010928F62004C8F62005083 +:10431000ACA200183C02080094424DBE3C03C00B06 +:1043200000002021004310250E000550ACA2001C07 +:104330008F6200548F840020AC8200008F6200588E +:10434000AC8200048F62005CAC8200088F62006067 +:104350008F43007400431021AC82000C8F62006414 +:10436000AC820010976300689762006A00031C002B +:104370003042FFFF00621825AC8300149362008274 +:1043800024030080304200FF1443000300000000BB +:104390000A0010C6AC8000188F63000C24020001D4 +:1043A0001062000E2402FFFF9362003E3042004084 +:1043B0001440000A2402FFFF8F63000C8F42007438 +:1043C000006218233C02080000621024144000021E +:1043D000000028210060282100051043AC8200184D +:1043E0003C02080094424DBE3C03C00C000020215A +:1043F000004310258F8300200E000550AC62001C86 +:104400008F6200188F8300203C05080094A54DBEE4 +:1044100024040001AC620000AC6000048F66006CF4 +:104420003C02400D00A22825AC6600088F6200DC2B +:10443000AC62000CAC600010936200050002160034 +:10444000AC620014AC6000180E000550AC65001C96 +:10445000020020218FBF00148FB00010A360000560 +:104460000A0004B927BD00188FBF00148FB00010D8 +:1044700003E0000827BD00189742007C30C600FF0B +:10448000A08600843047FFFF2402000514C2000B01 +:1044900024E3465090A201122C420007104000076E +:1044A00024E30A0090A30112240200140062100405 +:1044B00000E210210A0010FE3047FFFF3067FFFFC7 +:1044C00003E00008A4870014AC87004C8CA201080C +:1044D0000080402100A0482100E2102330C600FFE8 +:1044E0001840000393AA001324E2FFFCACA20108C9 +:1044F00030C2000110400008000000008D02005092 +:1045000000E2102304410013240600058D0200542C +:1045100010E20010000000008D02005414E2001AA6 +:10452000000000003C0208008C4200D8304200200D +:104530001040000A240200019103007891020083D8 +:10454000144300062402000101002021012028213B +:10455000240600040A0010EC00000000A100008402 +:1045600011400009A50200148F4301008F4201F899 +:104570000440FFFE24020002AF4301C0A34201C475 +:104580003C021000AF4201F803E000080000000008 +:1045900027BDFFE88FA90028AFBF00100080402191 +:1045A00000E918231860007330C600FFA080007C6B +:1045B000A08000818CA2010800E210230440004D7D +:1045C000000000008C8200509483003C8C840064C6 +:1045D000004748233063FFFF012318210083202B6D +:1045E00010800004000000008D0200640A00114FDA +:1045F00000E210219502003C3042FFFF0122102111 +:1046000000E21021AD02005C9502003C8D03005CCD +:104610003042FFFF0002104000E210210043102B47 +:1046200010400003000000000A00115E8D02005CD3 +:104630009502003C3042FFFF0002104000E21021D2 +:10464000AD02005CA1000084AD07004C8CA2010803 +:1046500000E210231840000224E2FFFCACA2010893 +:1046600030C200011040000A000000008D0200501E +:1046700000E2102304410004010020218D020054B7 +:1046800014E20003000000000A0011802406000567 +:104690008D02005414E200478FBF00103C02080056 +:1046A0008C4200D8304200201040000A2402000151 +:1046B0009103007891020083144300062402000154 +:1046C00001002021240600048FBF00100A0010EC16 +:1046D00027BD0018A1000084A50200148F4301002B +:1046E0008F4201F80440FFFE240200020A0011A5D7 +:1046F000000000008C82005C004910230043102B56 +:1047000054400001AC87005C9502003C3042FFFF42 +:104710000062102B14400007240200029502003CA6 +:104720008D03005C3042FFFF00621821AD03005C86 +:1047300024020002AD07004CA10200840E000FA26B +:104740008F4401001040001B8FBF00108F430100F9 +:104750008F4201F80440FFFE24020002AF4301C073 +:10476000A34201C43C021000AF4201F80A0011BB91 +:104770008FBF001030C200101040000E8FBF00101D +:104780008C83005C9482003C006918233042FFFF58 +:10479000006218213C023FFF3444FFFF0083102BCE +:1047A000544000010080182101231021AD02005C5B +:1047B0008FBF001003E0000827BD001827BDFFE8E9 +:1047C0008FAA0028AFBF00100080402100EA4823D4 +:1047D0001920002130C600FF8C83005C8C820064AD +:1047E000006A18230043102B504000100069182164 +:1047F00094A2011001221021A4A2011094A2011080 +:104800003042FFFF0043102B1440000A3C023FFFE0 +:1048100094A2011000431023A4A201109482003C32 +:104820003042FFFF0A0011DA00621821A4A0011033 +:104830003C023FFF3444FFFF0083102B5440000133 +:104840000080182100671021AD02005CA100007CEF +:104850000A001222A100008130C200101040003C6A +:10486000000000008C820050004A102318400038DD +:10487000000000009082007C24420001A082007CA5 +:104880009082007C3C0308008C630024304200FFCF +:104890000043102B1440005C8FBF00108CA2010855 +:1048A00000E2102318400058000000008C830054E0 +:1048B0009482003C006A18233042FFFF0003184333 +:1048C000000210400043102A1040000500000000C4 +:1048D0008C820054004A10230A001209000210437F +:1048E0009482003C3042FFFF00021040AD020064A1 +:1048F0009502003C8D0400649503003C3042FFFFAC +:1049000000021040008220213063FFFF0083182145 +:1049100001431021AD02005C8D020054ACA20108DD +:1049200024020002A10200840E000FA28F440100A5 +:10493000104000358FBF00108F4301008F4201F8F7 +:104940000440FFFE240200020A00124B0000000097 +:10495000AD07004C8CA2010800E2102318400002B1 +:1049600024E2FFFCACA2010830C200011040000AA2 +:10497000000000008D02005000E2102304410004FA +:10498000010020218D02005414E200030000000009 +:104990000A001242240600058D02005414E2001A97 +:1049A0008FBF00103C0208008C4200D8304200202B +:1049B0001040000A24020001910300789102008354 +:1049C00014430006240200010100202124060004F3 +:1049D0008FBF00100A0010EC27BD0018A100008452 +:1049E000A50200148F4301008F4201F80440FFFE2E +:1049F00024020002AF4301C0A34201C43C021000E4 +:104A0000AF4201F88FBF001003E0000827BD001877 +:104A10008FAA00108C8200500080402130C600FF19 +:104A2000004A102300A048211840000700E0182188 +:104A300024020001A0800084A0A00112A48200141E +:104A40000A0011BDAFAA0010A0800081AD07004C84 +:104A50008CA2010800E210231840000224E2FFFCAF +:104A6000ACA2010830C200011040000800000000A4 +:104A70008D0200500062102304410013240600053B +:104A80008D02005410620010000000008D020054DE +:104A900014620011000000003C0208008C4200D8A3 +:104AA000304200201040000A2402000191030078E7 +:104AB000910200831443000624020001010020211A +:104AC00001202821240600040A0010EC0000000048 +:104AD000A1000084A502001403E00008000000000B +:104AE00027BDFFE0AFBF0018274201009046000A33 +:104AF0008C4800148C8B004C9082008430C900FFDD +:104B000001681823304A00FF1C60001A2D46000679 +:104B1000240200010142100410C0001630430003BB +:104B2000012030210100382114600007304C000CB6 +:104B300015800009304200301440000B8FBF001870 +:104B40000A0012AC000000000E0011BDAFAB001057 +:104B50000A0012AC8FBF00180E001132AFAB00106C +:104B60000A0012AC8FBF0018AFAB00100E0012523B +:104B7000AFAA00148FBF001803E0000827BD002073 +:104B800024020003A08200848C82005403E0000809 +:104B9000ACA201083C020008034218219062008187 +:104BA000240600433C07601924420001A0620081F2 +:104BB000906300813C0208008C4200C0306300FF1B +:104BC000146200102403FF803C0208008C4200E0C5 +:104BD0000082102100431024AF4200243C02080050 +:104BE0008C4200E03C03000A008210213042007F2A +:104BF0000342102100431021944500D40A000B8980 +:104C000030A5FFFF03E000080000000027BDFFE023 +:104C1000AFBF0018AFB10014AFB000108F420180D9 +:104C20000080802100A088210E0012B300402021C6 +:104C3000A20000848E0200548FBF00188FB00010B5 +:104C4000AE2201088FB1001403E0000827BD002048 +:104C500027BDFFE03C020008AFB00010AFBF001856 +:104C6000AFB10014034280218F51014092030084B0 +:104C70008E0400508E02004C14820040306600FF0B +:104C80003C0208008C4200E02403FF800222102135 +:104C900000431024AF4200243C0208008C4200E094 +:104CA0009744007C92050081022210213042007F4F +:104CB000034218213C02000A0062182114A0000BD4 +:104CC0003084FFFF2402000554C20014248205DC56 +:104CD0009062011224420001A062011224020C80A1 +:104CE000AF4200240A00130B24020005A060011249 +:104CF0002402000514C20009248205DC920200810E +:104D00002C4200075040000524820A0092030081D3 +:104D10002402001400621004008210213044FFFFBE +:104D2000A60400140E0012B3022020219602003CBB +:104D30008E03004C022020213042FFFF0002104071 +:104D4000006218210E000302AE03005C9202007D97 +:104D500002202021344200400E00030BA202007DFD +:104D60008F4201F80440FFFE24020002AF5101C04F +:104D7000A34201C43C021000AF4201F88FBF0018EB +:104D80008FB100148FB0001003E0000827BD002091 +:104D900008000D9808000DE008000E2008000E6CB9 +:044DA00008000EA059 +:0C4DA4000A0000220000000000000000D7 +:104DB0000000000D6370352E302E306A3300000085 +:104DC00005000004000000000000000000000000DA +:104DD00000000000000000000000000000000000D3 +:104DE00000000000000000000000000000000020A3 +:104DF00000000000000000000000000000000000B3 +:104E000000000000000000000000000000000000A2 +:104E10000000000000000000000000000000000191 +:104E20000000002B00000000000000000000000057 +:104E300010000003000000000000000D0000000D45 +:104E40003C02080024425AC43C03080024636190D9 +:104E5000AC4000000043202B1480FFFD24420004DE +:104E60003C1D080037BD7FFC03A0F0213C1008006A +:104E7000261000883C1C0800279C5AC40E0001A67E +:104E8000000000000000000D27BDFFE83C0960188D +:104E9000AFBF00108D2C5000240DFF7F240800317F +:104EA000018D5824356A380C24070C003C1A800008 +:104EB000AD2A50003C04800AAF4800083C1B800823 +:104EC000AF4700240E000938AF8400100E0008FB25 +:104ED000000000000E000848000000000E0012DF75 +:104EE000000000003C0460168C8500003C06FFFFBB +:104EF0003C02535300A618241062004734867C00FD +:104F000094C201F2A780002C10400003A78000CCBF +:104F100038581E1EA798002C94C201F810400004B7 +:104F2000978300CC38591E1EA79900CC978300CCDC +:104F30002C7F006753E00001240300669784002C57 +:104F40002C82040114400002006028212404040083 +:104F50003C0760008CE904382403103C3128FFFF33 +:104F60001103001F30B9FFFF57200010A38000CEAF +:104F700024020050A38200CE939F00CE53E0000F86 +:104F8000A78500CCA78000CC978500CC8FBF0010F0 +:104F9000A780002CA7800034A78000E63C01080011 +:104FA000AC25008003E0000827BD0018939F00CEC9 +:104FB00057E0FFF5A78000CCA78500CC978500CCF3 +:104FC0008FBF0010A784002CA7800034A78000E6C4 +:104FD0003C010800AC25008003E0000827BD001854 +:104FE000A38000CE8CCB003C316A00011140000E42 +:104FF0000000000030A7FFFF10E0FFDE2402005099 +:105000008CCC00C83186000114C0FFDC939F00CE19 +:105010000A000074240200518C8F00043C0E6000D2 +:105020000A00005701EE30218CEF0808240D5708C4 +:10503000000F740211CD000430B8FFFF2405006694 +:105040000A000075240404001700FFCC939F00CED3 +:105050000A000074240200508F8600103089FFFF80 +:10506000000939408CC300103C08005000E820259E +:10507000AF4300388CC5001427420400AF82001CE7 +:10508000AF45003CAF4400300000000000000000CD +:105090000000000000000000000000000000000010 +:1050A00000000000000000008F4B0000316A00206B +:1050B0001140FFFD0000000003E0000800000000B8 +:1050C0008F840010948A001A8C8700243149FFFFD6 +:1050D000000940C000E83021AF46003C8C85002428 +:1050E0008F43003C00A3102318400029000000005B +:1050F0008C8B0020256200013C0D005035AC00086F +:10510000AF420038AF4C003000000000000000004B +:10511000000000000000000000000000000000008F +:1051200000000000000000008F4F000031EE002062 +:1051300011C0FFFD000000008F4A04003C08002061 +:10514000AC8A00108F490404AC890014AF480030C9 +:1051500000000000948600189487001C00C71821E6 +:10516000A48300189485001A24A20001A482001AC6 +:105170009498001A9499001E133800030000000050 +:1051800003E000080000000003E00008A480001A0B +:105190008C8200200A0000D63C0D00500A0000C797 +:1051A000000000003C0308008C6300208F82001880 +:1051B00027BDFFE810620008AFBF00100E0000FE20 +:1051C000AF8300183C0308008C6300202404000116 +:1051D000106400048F8900108FBF001003E00008E6 +:1051E00027BD00188FBF00103C076012A520000AE1 +:1051F0009528000A34E5001027BD00183106FFFF8E +:1052000003E00008ACA600903C0208008C4200209D +:1052100027BDFFC8AFBF0034AFBE0030AFB7002C12 +:10522000AFB60028AFB50024AFB40020AFB3001C68 +:10523000AFB20018AFB1001410400050AFB0001072 +:105240008F840010948600069483000A00C32823EC +:1052500030B6FFFF12C0004A8FBF00349489001897 +:10526000948A000A012A40233102FFFF02C2382B30 +:1052700014E0000202C02021004020212C8C0005F7 +:10528000158000020080A021241400040E0000AD4F +:10529000028020218F87001002809821AF800014A7 +:1052A00094ED000A028088211280004E31B2FFFF87 +:1052B0003C1770003C1540003C1E60008F8F001CA6 +:1052C0008DEE000001D718245075005002202021D7 +:1052D00002A3802B160000353C18200050780047B0 +:1052E00002202021241000018F8300141460003953 +:1052F000029158230230F8230250C82133F1FFFFF6 +:105300001620FFEE3332FFFF8F8700103C11002084 +:10531000AF5100300000000094E6000A3C1E60120D +:1053200037D5001002662821A4E5000A94E2000A9D +:1053300094F2000A94F400183057FFFF1292003BD9 +:10534000AEB700908CED00148CE400100013714097 +:1053500001AE4021000E5FC3010E502B008B48218F +:10536000012A1821ACE80014ACE3001002D3382362 +:1053700030F6FFFF16C0FFB98F8400108FBF0034D6 +:105380008FBE00308FB7002C8FB600288FB5002459 +:105390008FB400208FB3001C8FB200188FB100149F +:1053A0008FB0001003E0000827BD0038107E001BFE +:1053B000000000001477FFCC241000010E00162A14 +:1053C000000000008F8300141060FFCB0230F82330 +:1053D000029158238F870010017020210A0001914B +:1053E0003093FFFF8F8300141460FFCB3C1100202B +:1053F000AF5100300A00015D000000000E0007A15F +:10540000024028210A000151004080210E00034B78 +:10541000024028210A000151004080210E0014F2B0 +:10542000022020210A000151004080210E0000C707 +:10543000000000000A00017302D3382327BDFFE8F3 +:10544000AFB00010AFBF00140E0000390000000024 +:105450003C028000345000700A0001B48E06000047 +:105460008F4F000039EE000131C2000110400024CE +:105470008F8600A88E0700003C0C08008D8C003C35 +:105480003C0908008D29003800E66823018D282199 +:105490000000502100AD302B012A402101062021BF +:1054A0003C010800AC25003CAF8700A83C01080087 +:1054B000AC2400380E000100000000003C0308008E +:1054C0008C6300701060FFE6006020213C0508003E +:1054D0008CA500683C0608008CC6006C0E0015B94F +:1054E000000000003C010800AC2000708F4F00005D +:1054F00039EE000131C200011440FFDE8F8600A8A2 +:105500008E0A00008F8B00A83C0508008CA5003C8B +:105510003C0408008C840038014B482300A9382142 +:105520000082182100E9402B006810213C0108008E +:10553000AC27003C3C010800AC2200388F5F010022 +:105540002419FF0024180C0003F9202410980012DD +:10555000AF840000AF440020936D0000240C0020B5 +:1055600031A600FF10CC0012240E005010CE000413 +:105570003C194000AF5901380A0001AD000000009D +:105580000E001255000000003C194000AF590138D0 +:105590000A0001AD000000000E000119000000002B +:1055A0003C194000AF5901380A0001AD000000006D +:1055B0008F58010000802821330F00FF01E02021D7 +:1055C0000E0002F8AF8F00043C194000AF590138BB +:1055D0000A0001AD0000000000A4102B240300010C +:1055E00010400009000030210005284000A4102BC5 +:1055F00004A00003000318405440FFFC00052840AD +:105600005060000A0004182B0085382B54E0000479 +:105610000003184200C330250085202300031842F0 +:105620001460FFF9000528420004182B03E000086D +:1056300000C310213084FFFF30A5FFFF8F4201B867 +:105640000440FFFE3C074080008730253C031000EB +:10565000AF400180AF450184AF46018803E00008F8 +:10566000AF4301B83084FFFF8F4201B80440FFFE12 +:105670003C0740388CA60000008728253C0310001A +:10568000AF460180AF45018803E00008AF4301B891 +:105690008F8300388F8600301066000B0080402119 +:1056A0003C07080024E75C38000328C000A710214D +:1056B0008C44000024630001108800053063000F53 +:1056C0005466FFFA000328C003E000080000102120 +:1056D0003C07080024E75C3C00A7302103E00008F9 +:1056E0008CC200003C03900034620001008220253F +:1056F000AF4400208F45002004A0FFFE0000000002 +:1057000003E00008000000003C0380003462000158 +:105710000082202503E00008AF44002027BDFFE001 +:10572000AFB100143091FFFFAFB00010AFBF001851 +:105730001220001500A080218CA5000010A00013ED +:10574000240400020E000C7F24060140AE0000007D +:105750008F4201B80440000D000028213C064000A3 +:10576000022620258FBF00188FB100148FB00010C3 +:105770003C03100027BD0020AF450180AF440188E5 +:1057800003E00008AF4301B88CA500008F4201B8C8 +:105790000440FFFE3C064000022620258FBF001873 +:1057A0008FB100148FB000103C03100027BD002003 +:1057B000AF450180AF44018803E00008AF4301B862 +:1057C0003086FFFF8F4201B80440FFFE3C094006CF +:1057D0008CA8000000C93825AF4801808CA40004C3 +:1057E0003C031000AF440184AF47018803E0000888 +:1057F000AF4301B827BDFFE0AFB00010AFBF001846 +:10580000AFB100149363003E008080210080282106 +:1058100030620040000020211040000F8E11000077 +:105820000E00087402202021936700002404005019 +:1058300030E500FF50A400128E0F0000022020214E +:105840008FBF00188FB100148FB00010A762013C09 +:105850000A00093427BD00200E0002870000000066 +:105860000E000874022020219367000024040050D9 +:1058700030E500FF14A4FFF2022020218E0F00006B +:105880003C1008008E1000503C0D000C240BFF80D3 +:1058900001F05021314E007F01DA6021018D40215D +:1058A000014B4824AF490028022020218FBF001857 +:1058B0008FB100148FB00010A50200D627BD0020C4 +:1058C0000A000934AF8800D027BDFFE0AFBF001841 +:1058D000AFB10014AFB000109366000100808021CA +:1058E0000E00025030D1000493640005001029C25C +:1058F000A765000034830040A36300050E00025931 +:10590000020020210E00093602002021240200019D +:10591000AF62000C02002821A762001024040002DC +:10592000A762001224060140A76200140E000C7F3B +:10593000A76200161620000F8FBF0018978C003446 +:105940003C0B08008D6B00782588FFFF3109FFFFB5 +:10595000256A0001012A382B10E00006A7880034D0 +:105960003C0F6006240E001635ED0010ADAE005061 +:105970008FBF00188FB100148FB0001003E0000833 +:1059800027BD002027BDFFE0AFB10014AFBF001856 +:10599000AFB0001000A088211080000A3C03600016 +:1059A0002402008010820012000000000000000DA0 +:1059B0008FBF00188FB100148FB0001003E00008F3 +:1059C00027BD00208C682BF80500FFFE00000000BA +:1059D000AC712BC08FBF00188FB100148FB00010B6 +:1059E0003C09100027BD002003E00008AC692BF83B +:1059F0000E00025000A02021936500050220202106 +:105A00000E00025930B000FF2403003E1603FFE7EA +:105A1000000000008F4401780480FFFE2407000787 +:105A20003C061000AF51014002202021A347014451 +:105A30008FBF00188FB100148FB00010AF460178EF +:105A40000A0002C927BD002027BDFFE8AFBF001430 +:105A5000AFB000108F500020000000000E0009368B +:105A6000AF440020AF5000208FBF00148FB0001053 +:105A700003E0000827BD00183084FFFF8F4201B803 +:105A80000440FFFE3C074035008730253C031000F2 +:105A9000AF450180AF400184AF46018803E00008B4 +:105AA000AF4301B83084FFFF8F4201B80440FFFECE +:105AB0003C074036008730253C031000AF4501808D +:105AC000AF400184AF46018803E00008AF4301B84E +:105AD00027BDFFD0AFB3001C3093FFFFAFB500244C +:105AE000AFB20018AFBF0028AFB40020AFB10014B0 +:105AF000AFB0001030B5FFFF12600027000090210A +:105B00008F90001C8E0300003C06800024020040A1 +:105B100000033E0200032C0230E4007F006688246C +:105B20001482001D30A500FF8F8300282C68000A16 +:105B3000510000108F910014000358803C0C0800A5 +:105B4000258C58D0016C50218D490000012000089F +:105B50000000000002B218213065FFFF0E00022491 +:105B600024040084162000028F90001CAF800028BF +:105B70008F910014260C0020264B0001018080210B +:105B80003172FFFF16200004AF8C001C0253282B3B +:105B900014A0FFDC00000000024010218FBF00288D +:105BA0008FB500248FB400208FB3001C8FB2001873 +:105BB0008FB100148FB0001003E0000827BD003043 +:105BC000240D003414AD00F600000000920B000E0E +:105BD000240A16803C07000CA36B00219203000DE1 +:105BE0000347F8213C066000A363002096110012D1 +:105BF0003C057FFF34ACFFFFA771003C960200100C +:105C0000240B00053054FFFFAF7400848E19001C74 +:105C1000AF4A00288FF800008CCF44480319702643 +:105C200001EE3021AF66004C8F69004C24CD00019D +:105C30003C197F00AF6900508F640050AF6400547E +:105C4000AF660070AF6D00588F6800582404005094 +:105C5000AF68005CA3600023AF6C0064A36B0037E7 +:105C60008E030014AF6300488F710048AF710024A9 +:105C70008E020018AF62006C9214000CA374003600 +:105C8000936A003E355F0020A37F003E8F7800744A +:105C90000319782435EE4000AF6E0074936900005C +:105CA000313000FF1204022B2418FF803C0408004E +:105CB00024845CB80E000294000000002406000456 +:105CC000240700013C0408008C845CB8A366007DB6 +:105CD000A36700058F4A01780540FFFE24020002F9 +:105CE000AF440140A34201448F90001C3C141000BB +:105CF000AF5401780A000373AF8000282CAD003741 +:105D000051A0FF9C8F9100140005A0803C18080052 +:105D1000271858F8029878218DEE000001C000087D +:105D2000000000002406000614A600110000000078 +:105D30003C1F08008FFF5CB824040005AF5F002003 +:105D40008E190018AF7900188F78004CAF78001CBE +:105D50008F6F0050122000C2AF6F00700A000373F3 +:105D6000AF840028240A000710AA00842403000638 +:105D70003C05080024A55CB80E00025E24040081E6 +:105D80008F90001C0011102B0A000373AF820028B3 +:105D90002402000414A2FFF6240A00503C09080063 +:105DA0008D295CB8AF4900208E040008AF64004024 +:105DB0008E060008AF6600448E07000CAF670048EF +:105DC0008E0D0010AF6D004C8E080010AF6800847F +:105DD0008E050014AF6500508E0C0018AF6C005497 +:105DE0008E0B001CAF6B005893740000328300FFD1 +:105DF000106A01ED000000008F6700488F660040C8 +:105E000000E6682305A000042404008C1620FFDEB1 +:105E100024020003240400823C05080024A55CB889 +:105E20000E000287000000008F90001C000010216F +:105E30000A000373AF8200282404000514A4FFCCD9 +:105E4000240520003C1F08008FFF5CB8AF5F0020D6 +:105E50008E190004AF79005C921800082410000825 +:105E6000A37800218F8F001C91EE0009A36E002003 +:105E70008F86001C90C9000A312400FF109000108A +:105E8000288A00091540006C24020002240C00201E +:105E9000108C000B340580002885002114A0000818 +:105EA0002405400024080040108800053C0500013E +:105EB000240D0080108D00023C05000224054000E6 +:105EC0008F6E00743C0FFF0001CF48240125802510 +:105ED000AF70007490C4000BA36400818F84001C19 +:105EE0009487000C10E0019300000000948E000CD9 +:105EF000241FFFBF24060004A76E003C9089000EFB +:105F0000A369003E8F90001C9204000FA364003F21 +:105F10008F94001C8E8D00108F47007401A74023C2 +:105F2000AF6800608E850014AF650064968C001821 +:105F3000A76C0068968B001AA76B006A8E83001C02 +:105F4000AF63006C96820002A762013E928A000E47 +:105F5000A36A003E9379003E033FC02412200166ED +:105F6000A378003E8F90001C0A000373AF860028C0 +:105F70002414002214B4FF7E240300073C0208000E +:105F80008C425CB81220000CAF4200200A00037360 +:105F9000AF830028240C003310AC00142405002823 +:105FA0003C05080024A55CB80E00023024040081E2 +:105FB0000A0003F88F90001C3C04080024845CB89D +:105FC0000E00029400000000936B000024110050AA +:105FD000316300FF10710150000000008F90001C21 +:105FE000000018210A000373AF8300283C08080052 +:105FF0008D085CB824040081AF480020A3650034FC +:106000003C05080024A55CB80E000230000000002A +:106010008F90001C240200090A000373AF8200283D +:1060200002B288213225FFFF0E00022424040084DE +:106030000A0003738F90001C1082FFA12405040046 +:10604000288300031060016E240B00042414000157 +:106050005494FF9B240540000A00044724050100D6 +:106060003C04080024845CB88F62004C0E0002944B +:106070008F6300508F90001C000020210A000373E2 +:10608000AF8400288E1000042404008AAF50002042 +:10609000936E000531C900021520015D0200282120 +:1060A0009378002302002821330F002015E00158C7 +:1060B0002404008D9362003F24190012305F00FF1A +:1060C00013F90153240400810E0002500200202124 +:1060D00093740023240A0004020020213683004226 +:1060E000A36300230E000259A36A007D8F4B017841 +:1060F0000560FFFE24050002AF500140A3450144A6 +:106100008F90001C3C0C1000AF4C01780A0003F982 +:106110000011102B8E100004AF500020936D00056D +:1061200031A80002550001782404008A9364003FDE +:106130002407000402002821308600FF10C7001049 +:10614000240400810E00025002002021937F0023CE +:1061500024180012240FFFFE37F90020A379002332 +:10616000A378003F936E00050200202101CF482450 +:106170000E000259A3690005020028210000202119 +:106180000E000340000000000A0003F88F90001C7E +:106190008E0500043C0F0008034F4021AF4500204E +:1061A000910E00002406005031C900FF1126017A2B +:1061B000240400888F5901B80720FFFE3C0C400ED4 +:1061C000008C58253C031000AF450180AF4001848E +:1061D000AF4B0188AF4301B891020000240AFF8051 +:1061E00024040004004AF825A11F00000E000C7FC3 +:1061F000240600300A0003F88F90001C8E0F000464 +:106200003C14080026945CB83C010800AC2F5CB834 +:10621000AF4F0020920E000331C90004112000028C +:106220002402001224020006A362003F9203001B16 +:10623000240AFFC03062003F004AF825A37F003ED9 +:1062400092190003333800011700012200000000FA +:106250008E020008AE8200083C0208008C425CC03E +:106260001040012D00000000000221C2A7640008B8 +:106270008E0D000C240B000124140014AF6D002CB3 +:106280008E080010AF68003096050016A76500382C +:10629000960C0014A76C003AAF6B000CA76B0010B3 +:1062A000A76B0012A76B0014A76B00161220014AFF +:1062B000A37400349206000330C700022CF00001E2 +:1062C000260200088F90001C0A000373AF8200288A +:1062D0008E14000424030081AF540020936800232F +:1062E0003105001010A00113000000008F4401B818 +:1062F0000480FFFE3C06401F0011382B006610256D +:106300003C111000AF540180AF870028AF400184DA +:10631000AF420188AF5101B80A0003748F91001495 +:106320008E0600043C19000803592021AF460020C6 +:106330008E07000890980000240F0050331400FFCF +:10634000128F0106240500888F4401B80480FFFEE7 +:106350003C0D40090011602B00AD10253C111000D0 +:10636000AF460180AF8C0028AF470184AF4201885F +:10637000AF5101B80A0003748F9100148E04001C01 +:106380000E00023B00000000104000D700404821F2 +:106390008F90001C240500898F4D01B805A0FFFED9 +:1063A00000000000AF4901808E0F001C3C1440012A +:1063B0000011702B00B448253C111000AF4F018430 +:1063C000AF8E0028AF490188AF5101B80A000374AD +:1063D0008F910014961900023C14080026945CB8B2 +:1063E000333800041300008E3C0260008E1F001C36 +:1063F0003C010800AC3F5CB8AF5F0020920C00107D +:10640000240B0014318400FF148B00AC000000004A +:1064100096090002312D000115A001520000000074 +:106420008E020004AE8200083C0E08008DCE5CC0D7 +:1064300011C00148000000008F6900743C0E80000C +:1064400024040001012E6825AF6D0074A3600005CF +:10645000AF64000C3C0C08008D8C5CC08F88001C65 +:10646000A7640010000C59C2A7640012A7640014AE +:10647000A7640016A76B00088D030008240400021F +:10648000AF63002C8D0A000CAF6A0030910700103A +:10649000A36700348F82001C90450011A36500356E +:1064A0008F86001C90D00012A37000368F9F001CB6 +:1064B00093F90013A37900378F90001C96180014ED +:1064C000A778003896140016A774003A8E0F0018AB +:1064D000AF6F00245620FDA6AF8400283C050800BD +:1064E00024A55CB80E00025E000020218F90001CE5 +:1064F0000A0004B6000020213C05080024A55CB871 +:106500000E000287240400828F90001C00003021BE +:106510000A000373AF8600283C0408008C845CB832 +:106520000E001577000000008F90001C0A000490F8 +:10653000000018213C05080024A55CB80E00028765 +:106540002404008B8F90001C0011302B0A00037371 +:10655000AF8600283C1908008F395CB83C1F080042 +:106560008FFF005024CCFFFE033F782101F87024F8 +:10657000AF4E00283C0408008C845CB83C0908003D +:106580008D2900500089682131A8007F011A282137 +:1065900000A78021AE0600D8AF9000D0AE0000DC8E +:1065A0000A0003C2AE0C0108AF6000843C0508007D +:1065B0008CA55CB83C0808008D080050240CFF80B6 +:1065C0003C02000C00A8A021028C5824AF4B0028EC +:1065D0008E1F00143283007F007A50210142702107 +:1065E000ADDF00D88E190014AF8E00D0ADD900DC1D +:1065F0008E180010270FFFFE0A000415ADCF01080A +:10660000548BFE2F240540000A0004472405100087 +:106610000E000335000000000A0003F88F90001CF4 +:106620008C46442C3C056C6234B079703C01080007 +:10663000AC205CB814D00008240400029788003411 +:10664000978A002C02802821010A382B10E00011C3 +:1066500024040092240400020E000C9D2405014035 +:106660003C010800AC225CB8AF4200203C030800AB +:106670008C635CB810600005240400830E00086879 +:106680000000000010400009240400833C050800BD +:1066900024A55CB80E00025E000000008F90001C74 +:1066A0000011202B0A000373AF8400280E00086C31 +:1066B000000000000A0005968F90001C0E00087074 +:1066C000000000003C05080024A55CB80A00063C58 +:1066D0002404008B8E0400080E00023B0000000022 +:1066E0000A00052DAE820008240400040E000C9D53 +:1066F000240500301440003F004048218F90001CCA +:106700000A00057D240500830E00034002002821B5 +:106710000A0004E2000000003C05080024A55CB863 +:106720000E000230240400878F90001C0A000549E7 +:106730000011102B0E0002500280202193700023C4 +:1067400002802021360D00100E000259A36D002397 +:106750008F90001C0A000552000018219205000CC1 +:1067600030BF000113E00003000000009602000E9D +:10677000A482002C920A000C314800021100FEF2A3 +:1067800000002821960B00128E030014A48B001A1F +:106790000A000569AC83001C8F8300388F870030A6 +:1067A0001067FE84000020213C09080025295C3C7C +:1067B000000320C0008930218CD400001285005EC7 +:1067C000247800013303000F5467FFFA000320C050 +:1067D0000A000504000020213C05080024A55CB83F +:1067E0000E000287240400828F90001C0A000549D5 +:1067F000000010213C0B0008034B20212403005013 +:10680000240A0001AF420020A0830000A08A0001FA +:106810008F88001C91070004A08700188F82001C3D +:1068200090450005A08500198F86001C90DF0006AA +:10683000A09F001A8F99001C93380007A098001B96 +:106840008F94001C928F0008A08F001C8F90001C5A +:10685000920E0009A08E001D8F8D001C91AC000AC5 +:10686000A08C001E8F8B001C3C0C0800258C5C3C0F +:106870009163000B3C0B0800256B5C38A083001F64 +:106880008F8A001C9148000CA08800208F87001C74 +:1068900090E5000DA08500218F82001C240546464E +:1068A0009046000EA08600228F9F001C93F9000FD7 +:1068B000A09900238F98001C93140010A09400242A +:1068C0008F8F001C91F00011A09000258F90001C6C +:1068D0008F8E00308F990038960D0014000E18C06E +:1068E00025C80001A48D0028960A0016006C3021EE +:1068F000006BF821A48A002A960700183108000FBF +:10690000A487002CA485002E8E02001CACC90000B8 +:10691000AF88003011190003AFE200000A00057DC6 +:1069200000002821250C00013184000F00002821DF +:106930000A00057DAF8400383C07080024E75C3876 +:106940000087802100002021ACC000000A0005045F +:10695000AE0000003C05080024A55CB80A00063C17 +:10696000240400878E0400040E00023B0000000097 +:106970000A0005A1AE8200083084FFFF30C600FF88 +:106980008F4201B80440FFFE000644000104302598 +:106990003C07200000C720253C031000AF400180C9 +:1069A000AF450184AF44018803E00008AF4301B85C +:1069B00027BDFFE8AFB00010AFBF00143C07600078 +:1069C000240600021080000600A080210010102B79 +:1069D0008FBF00148FB0001003E0000827BD00181F +:1069E0003C09600EAD2000348CE5201C8F82001C19 +:1069F0002408FFFC00A81824ACE3201C0E0006F5B8 +:106A00008C45000C0010102B8FBF00148FB00010AD +:106A100003E0000827BD00183C02600E3447010067 +:106A200024090018274A04000000000000000000AC +:106A3000000000003C06005034C30200AF440038A0 +:106A4000AF45003CAF430030014018218F4B0000A0 +:106A5000316800201100FFFD2406007F2408FFFF9D +:106A60008C6C000024C6FFFF24630004ACEC000023 +:106A700014C8FFFB24E70004000000000000000031 +:106A8000000000003C0F0020AF4F0030000000006D +:106A900024AD020001A5702B2529FFFF008E2021C7 +:106AA0001520FFE101A0282103E0000800000000FC +:106AB00027BDFFE0AFB10014AFBF0018AFB00010AA +:106AC0003C05600E8CA20034008088211440000632 +:106AD0003C0460008C87201C2408FFFC00E8302464 +:106AE00034C30001AC83201C8F8B001C24090001DF +:106AF000ACA90034956900028D6500148D70000CFE +:106B00002D2400818D6700048D6600081080000729 +:106B10008D6A00102D2C00041580000E30CE000769 +:106B2000312D000311A0000B000000002404008B95 +:106B3000020028210E0006F5240600030011102B88 +:106B40008FBF00188FB100148FB0001003E0000851 +:106B500027BD002015C0FFF62404008B3C03002055 +:106B6000AF4300300000000024020001AF82001497 +:106B70000000000000000000000000003C1F015069 +:106B8000013FC825253800033C0F600EAF47003891 +:106B900000181882AF46003C35E8003CAF59003081 +:106BA000274704008F4400003086002010C0FFFDFE +:106BB00000000000106000082466FFFF2403FFFFB0 +:106BC0008CEB000024C6FFFF24E70004AD0B00009F +:106BD00014C3FFFB250800043C08600EAD09003813 +:106BE0000000000000000000000000003C07002042 +:106BF000AF470030000000000E00071D01402021BB +:106C000002002821000020210E0006F524060003C2 +:106C10000011102B8FBF00188FB100148FB000101F +:106C200003E0000827BD002027BDFFD8AFB2001841 +:106C30003092FFFFAFB10014AFBF0020AFB3001C14 +:106C4000AFB000101240002C000088210A0007B5E8 +:106C50002413000150B300408CE5000C0000000D2F +:106C6000263900013331FFFF24F800200232382B8F +:106C700010E00021AF98001C8F8200141440001E09 +:106C80008F87001C3C0670003C0320008CE4000051 +:106C90000086282414A300188F85003C00044402B9 +:106CA0003C0980000089802414A0FFEA310600FF1F +:106CB000240A000210CA002E28CB0003116000161F +:106CC000240C000314D3FFE7263900010200282119 +:106CD0000E000703240400018F87001CAF82003CD4 +:106CE000263900013331FFFF24F800200232382B0F +:106CF00014E0FFE1AF98001C022010218FBF00209C +:106D00008FB3001C8FB200188FB100148FB0001029 +:106D100003E0000827BD002810CC001A240D000451 +:106D200014CDFFD026390001308EFFFF000E19C0B0 +:106D30008F4401B80480FFFE3C0F10003C1020047B +:106D4000AF430180AF400184AF500188AF4F01B81D +:106D50000A0007B0263900010E0006F5240400845D +:106D60001600FFBF8F87001C0A0007AFAF80003CF2 +:106D7000020028210E000703000020210A0007CE90 +:106D80008F87001C0E000743020020218F87001C04 +:106D90000A0007CFAF82003C3082FFFF144000039F +:106DA000000018210004240224030010308500FF95 +:106DB00014A000053087000F24660008000422029A +:106DC00030C300FF3087000F14E000053089000356 +:106DD0002468000400042102310300FF308900030D +:106DE00015200005388B0001246A0002000420826F +:106DF000314300FF388B0001316400011080000234 +:106E0000246C0001318300FF03E0000800601021C2 +:106E1000308BFFFF000B394230E600FF3C090800D1 +:106E200025295BB800064080010960218D8700009C +:106E30003164001F240A0001008A180430A500FFF5 +:106E400000E3202514A000020003102700E2202404 +:106E5000240F000100CF700401096821000E2827CB +:106E600014800005ADA400008F86000C00A610243D +:106E700003E00008AF82000C8F88000C01C81025C9 +:106E800003E00008AF82000C3C06001F3C036000DA +:106E90003084FFFF34C5FF8024020020AC6020084E +:106EA000AC60200CAC602010AC652014AC642018E1 +:106EB000AC622000000000000000000003E00008B9 +:106EC0000000000027BDFFE82402FFFFAFBF001055 +:106ED000AF82000C000020213C06080024C65BB8ED +:106EE0002405FFFF24890001000440803124FFFFB6 +:106EF000010618212C87002014E0FFFAAC65000081 +:106F00000E00083900002021240200013C0460002A +:106F100024050020AC822018AC8520000000000071 +:106F20000000000000000000244A00013142FFFF81 +:106F30002C46040014C0FFF78FBF001003E00008C8 +:106F400027BD00188F8300082C62040003E00008AE +:106F5000384200018F8300082462000103E000082A +:106F6000AF8200088F8300082462FFFF03E000085F +:106F7000AF82000827BDFFE0AFB10014AFBF00181B +:106F8000AFB000108F6B00303C066000008088219D +:106F9000ACCB20088F6A002C3C0280002403000840 +:106FA000ACCA200C9769003A9768003800092C0099 +:106FB0003107FFFF00A72025ACC42010ACC220146D +:106FC000ACC3200000000000000000000000000032 +:106FD0003C0360008C6D200031AC00081580FFF987 +:106FE000000000008C6E201405C00020000000008E +:106FF0000E0007FD8F84000C000240803C09080051 +:1070000025295BB8010938218CE400000E0007FD3A +:1070100000028140020220213090FFFF0200202167 +:107020000E00081B000028213C0C8000022C582573 +:107030003210FFFF3C116000240A0020AE2B201408 +:10704000AE302018AE2A2000000000000000000032 +:1070500000000000020010218FBF00188FB1001443 +:107060008FB0001003E0000827BD00208C662014BC +:107070003C02001F3443FF803C1FFFE800C3C024D4 +:1070800037F9080003198021001079C23C0C8000F8 +:10709000022C582531F0FFFF3C116000240A00202B +:1070A000AE2B2014AE302018AE2A200000000000C5 +:1070B0000000000000000000020010218FBF001837 +:1070C0008FB100148FB0001003E0000827BD00202E +:1070D00027BDFFE8AFB000103402FFFF3090FFFF84 +:1070E000AFBF001412020006020020210E00083972 +:1070F00000000000020020210E00081B24050001F2 +:107100008F8400088FBF00148FB000102483FFFF0E +:1071100027BD001803E00008AF830008000439C24F +:1071200030E6003F00043B420007184024021000F4 +:107130002CC4002024C8FFE0AF42002C24630001CF +:107140001480000330A900FF00071840310600FF3B +:107150000003608024080001019A58213C0A000EB7 +:1071600000C82804016A38211120000500053027D5 +:107170008CE900000125302503E00008ACE60000A2 +:107180008CEE000001C6682403E00008ACED0000AE +:1071900027BDFFE8AFBF0014AFB000103C04600093 +:1071A0008C8508083403F00030A2F000504300063C +:1071B000240200018C8708083404E00030E6F00067 +:1071C00010C4001E24020002AF8200403C10600088 +:1071D0003C0A0200AE0A0814240910003C08000E04 +:1071E0008E03440003482021AF49002C24050120D0 +:1071F0000E000CE3000030218F830040106000047B +:107200003C021691240B0001106B000E3C023D6CF9 +:10721000344F0090AE0F44088FBF00148FB00010A1 +:107220003C0C6000240E10003C0D020027BD00182D +:10723000AD8E442003E00008AD8D08100A00090A55 +:10724000AF8000403C0218DA344F0090AE0F440883 +:107250008FBF00148FB000103C0C6000240E100093 +:107260003C0D020027BD0018AD8E442003E000084D +:10727000AD8D08100A0008DE240500010A0008DEB2 +:10728000000028213C08080025085FC42404FFFFF3 +:10729000010018212402001E2442FFFFAC640000FC +:1072A0000441FFFD246300043C07080024E760401C +:1072B0008CE5FFFC2404001C24060001308A001F1A +:1072C0000146480424840001000910272C83002073 +:1072D0001460FFFA00A22824ACE5FFFC3C056666BA +:1072E00034A4616E3C06080024C66100AF840058D7 +:1072F000AF88009C2404FFFF00C018212402001F57 +:107300002442FFFFAC6400000441FFFD246300043D +:107310003C0766663C05080024A560C0AF860048AF +:1073200034E6616EAF8600982404FFFF00A01821A8 +:107330002402000F2442FFFFAC6400000441FFFD63 +:10734000246300043C0B66663C06080024C66040CB +:107350003568616EAF8500A4AF8800702404FFFF1C +:1073600000C018212402001F2442FFFFAC6400006B +:107370000441FFFD246300043C0D66663C0A0800DE +:10738000254A618035AC616EAF860090AF8C005CA1 +:107390002404FFFF01401821240200032442FFFFC0 +:1073A000AC6400000441FFFD246300043C090800B4 +:1073B000252961908D27FFFC240400062405000187 +:1073C0003099001F0325C004248400010018782789 +:1073D0002C8E002015C0FFFA00EF3824AD27FFFCEB +:1073E0003C09666624030400240403DC240502002F +:1073F000240600663522616E3C08080025085CC43E +:10740000AF820074AF830044AF83006CAF83005041 +:10741000AF830084AF8A008CAF840064AF85004CDA +:10742000AF860054AF840078AF850060AF860080DF +:1074300001001821240200022442FFFFAC6000007A +:107440000441FFFD24630004240400032403000C12 +:107450003C0A0800254A5CD0AF8A00680A0009B1DE +:107460002405FFFF000418802484000100685821CF +:107470002C8700C014E0FFFBAD6500003C0E666683 +:1074800035CD616E240C17A024081800AF8D00883C +:10749000AF8C009403E00008AF88007C2484007F58 +:1074A000000421C2000040210000302100003821EA +:1074B000000028210A0009C8AF8400A0106000065F +:1074C00024E7000100C4302124A500012CC20BF5E3 +:1074D0001440FFFA2CA300663C09080025296180AE +:1074E00001201821240200032442FFFFAC600000A9 +:1074F0000441FFFD2463000410E0001A24E3FFFFB1 +:107500000003294210A0000A000020212406FFFFEA +:107510003C03080024636180248400010085502B13 +:10752000AC660000250800011540FFFB2463000441 +:1075300030E2001F1040000800086880240C0001A1 +:10754000004C3804000858800169282124E6FFFF18 +:1075500003E00008ACA6000001A940212409FFFFB8 +:10756000AD09000003E0000800000000AF4400285F +:107570003C04000C03442021000528820A000CE38F +:1075800000003021000421803C036000AC6410083E +:107590000000000000052980AC65100C0000000010 +:1075A00003E000088C62100C27BDFFE80080282152 +:1075B00024040038AFBF00140E0009F8AFB000106B +:1075C00024040E00AF4400283C10000C035020217E +:1075D000240500100E000CE30000302103501021A0 +:1075E000AC400000AC400004240400388FBF0014FD +:1075F0008FB0001024053FFF27BD00180A0009F8CE +:107600008C430000000421803C036000AC6410083F +:10761000000000008C62100C03E0000800021182E0 +:1076200027BDFFC8AFB400208F940068AFBE003004 +:10763000AFB7002CAFB600280000B8210080B02101 +:10764000241E00C0AFBF0034AFB50024AFB3001C90 +:10765000AFB20018AFB10014AFB000100A000A3585 +:10766000AFA5003C504000018F94006827DEFFFF6B +:1076700013C00028269400048E9200003C030800EA +:1076800024635FC01240FFF70283102B3C04080004 +:1076900024845CC4028410230002A8C00000982146 +:1076A0000A000A442411000100118840122000261B +:1076B0000000000002B38021025128240200202192 +:1076C00010A0FFF9267300010E000A01000000005F +:1076D0000016684032EC000101AC20210E0009F8D0 +:1076E000020028218F89009426F700018FA6003C14 +:1076F0003AEB0001316A00012528FFFF001138270D +:1077000002CAB021AF88009416E6FFE70247902432 +:10771000AE92000002E010218FBF00348FBE003017 +:107720008FB7002C8FB600288FB500248FB40020AF +:107730008FB3001C8FB200188FB100148FB00010EF +:1077400003E0000827BD00383C0E080025CE5FC0CE +:10775000028E102B0A000A30AE92000027BDFFD81F +:10776000AFB10014AFB00010AFBF0020AFB3001C2A +:10777000AFB2001800A0882110A0001F00048040B4 +:107780003C13080026735CC40A000A7D2412000121 +:1077900012200019261000010E000A1802002021F4 +:1077A000000231422444FFA0000618803045001F2B +:1077B0002C8217A1007318212631FFFF1040FFF41F +:1077C00000B230048C6900000200202124053FFF34 +:1077D000012640241500FFEE012638250E0009F889 +:1077E000AC6700008F8A0094261000012547000135 +:1077F0001620FFE9AF8700948FBF00208FB3001CD5 +:107800008FB200188FB100148FB0001003E0000891 +:1078100027BD00288F85009C008058210000402152 +:1078200000004821240A001F3C0C0800258C603C05 +:107830003C0D080025AD5FC48CA6000050C00014AC +:107840000000402100AD1023000238C024030001D5 +:107850000A000AB6000020211500000300E41021F0 +:10786000244820240000482125290001512B001321 +:107870002506DFDC106000062484000100C37024AC +:1078800015C0FFF5000318400A000AB400004021AB +:1078900010AC002624A3000400602821254AFFFF25 +:1078A0001540FFE5AF85009C512B00042506DFDC69 +:1078B0000000402103E000080100102100066142A1 +:1078C00030C5001F000C50803C07080024E75FC44F +:1078D00024040001014730211120000F00A42004DE +:1078E0003C05080024A56040148000052529FFFF01 +:1078F00024C6000410C5001100000000240400018B +:107900008CCF00000004C0270004204001F8682448 +:107910001520FFF5ACCD00008F99007801001021F3 +:10792000032B482303E00008AF8900783C050800DA +:1079300024A55FC40A000ABE000040213C060800DE +:1079400024C65FC40A000AD724040001308800FF5F +:10795000240200021102000A240300031103005C48 +:107960008F8900A4240400041104005F240500058D +:10797000110500670000182103E0000800601021D5 +:107980008F8900483C0C0800258C61003C040800ED +:1079900024846180240300201060000F000058211F +:1079A000240D0002240E00033C0F080025EF6100A7 +:1079B0008D27000014E0000B30F9FFFF252900049B +:1079C0000124C02B53000001018048212463FFFFE4 +:1079D0005460FFF88D2700000160182103E00008C3 +:1079E00000601021132000323C0500FF30E200FF50 +:1079F00000403021104000420000502124050001C9 +:107A0000000020210005C84000A6C0241700000384 +:107A1000332500FF14A0FFFB24840001012CC023A8 +:107A2000001828C000AA6021008C50213144001F9A +:107A3000240C0001008C18040003102700E23024FD +:107A4000110D0041AD260000110E004C000A184037 +:107A5000110D00368F87006C510E00568F8C006020 +:107A6000240D0004110D005A8F8E0084240E000591 +:107A7000150EFFDA01601821240B143011400006A6 +:107A8000000018218F8400A024630001006A402BAD +:107A90001500FFFD016458218F8A0080AF89008C9A +:107AA000016018212549FFFF0A000B0EAF890080F5 +:107AB00000E52024000736021080FFD0240A0018B9 +:107AC00000075402314600FF0A000B16240A00107A +:107AD0003C0C0800258C60C03C0408002484610034 +:107AE0000A000AFD240300103C0C0800258C6040AD +:107AF0003C040800248460C00A000AFC8F890090BE +:107B000000071A02306600FF0A000B16240A00085C +:107B10008F89008C3C0C0800258C61803C04080097 +:107B2000248461900A000AFD24030004000A4080B6 +:107B3000250B003024E6FFFF01601821AF890048C3 +:107B40000A000B0EAF86006C000AC982001978800B +:107B50003C07080024E760C001E72021000A184222 +:107B60008C8F00003079001F032C38040007C027D9 +:107B700001F860240A000B2BAC8C0000000331429A +:107B80000006288000AF28213062001F8CB800005A +:107B900024630001004CC804000321420019382767 +:107BA0000004108003073024004F20210A000B6FCF +:107BB000ACA60000000A68C025AB0032258AFFFF92 +:107BC00001601821AF8900A40A000B0EAF8A006083 +:107BD000254B1030AF8900900160182125C9FFFFA7 +:107BE0000A000B0EAF890084308600072CC2000605 +:107BF0001040001400000000000640803C03080014 +:107C0000246359D4010338218CE40000008000086B +:107C1000000000002409000310A9000E000000006D +:107C2000240A000510AA000B00000000240B00012C +:107C300010AB0008000000008F8C00A010AC000505 +:107C40000000000003E00008000010210A000A9C68 +:107C500000A020210A000AEA00C0202127BDFFE879 +:107C6000308400FF240300021083000BAFBF00101C +:107C7000240600031086003A2408000410880068D7 +:107C8000240E0005108E007F2CAF14308FBF001023 +:107C900003E0000827BD00182CA200301440FFFCB0 +:107CA0008FBF001024A5FFD0000531C200066880F8 +:107CB0003C07080024E7610001A730218CC90000BF +:107CC0000005288230AC001F240B0001018B5004FA +:107CD0008F840048012A4025ACC800008C83000036 +:107CE00050600001AF8600488F98006C30AE0001F4 +:107CF00024A6FFFF270F000115C00002AF8F006C04 +:107D000024A60001000641420008208000871821B7 +:107D10008C79000030C2001F240600010046F804E0 +:107D2000033F382410E0FFDA8FBF00100005C18246 +:107D3000001870803C0F080025EF60C001CF48217B +:107D40008D2B00000005684231A5001F00A66004CD +:107D5000016C502527BD001803E00008AD2A000083 +:107D60002CA7003014E0FFCA8FBF001030B9000705 +:107D70001723FFC724A8FFCE00086A02000D608009 +:107D80003C0B0800256B60C0018B30218CC40000C7 +:107D9000000828C230AA001F240800010148480436 +:107DA0008F8200A400891825ACC300008C5F0000FE +:107DB00053E00001AF8600A400057040000E794238 +:107DC000000F28803C0408002484610000A41821CE +:107DD0008C6B000025DF000131CD001F001F5142D8 +:107DE00001A86004016C4825000A1080AC690000FD +:107DF000004428218CA600008F98006033F9001FF2 +:107E00008FBF00100328380400C77825270E000113 +:107E100027BD0018ACAF000003E00008AF8E006083 +:107E200024A5EFD02CB804001300FF998FBF0010D9 +:107E300000053142000658803C0A0800254A60408F +:107E4000016A30218CC4000030A3001F2409000106 +:107E5000006910048F9900900082F825ACDF0000C3 +:107E60008F27000050E00001AF8600908F8D0084C6 +:107E70008FBF001027BD001825AC000103E00008EB +:107E8000AF8C008415E0FF828FBF00108F8600A0AA +:107E9000000610400046F821001F210003E4C8211D +:107EA0000019384024F8143000B8402B1100FF7836 +:107EB0008FBF001024A4EBD00E00020D00C02821BB +:107EC00000027942000F70803C0D080025AD6180F2 +:107ED00001CD20218C8B0000304C001F24060001B6 +:107EE000018618048F89008C01635025AC8A00003C +:107EF0008D25000050A00001AF84008C8F98008079 +:107F00008FBF001027BD00182708000103E00008FC +:107F1000AF88008030A500072403000310A30010E1 +:107F200028A20004144000082407000224030004CF +:107F300010A300152408000510A8000F8F8500A0CD +:107F400003E000080000000014A7FFFD00802821C6 +:107F500014C3FFFB240400020A000BAE0000000063 +:107F6000240900050080282110C9FFFB2404000318 +:107F700003E000080000000014C5FFF10080282184 +:107F80000A000BAE24040005240A00010080282109 +:107F900010CAFFF12404000403E000080000000000 +:107FA00027BDFFE0AFB00010000581C22603FFD05F +:107FB00024C5003F2C6223D024C6007FAFB2001836 +:107FC000AFB10014AFBF001C309100FF000691C29A +:107FD0000005298202002021104000082403FFFF31 +:107FE0000E000A6E0000000002002021022028215D +:107FF0000E000C5C02403021000018218FBF001CD5 +:108000008FB200188FB100148FB0001000601021E3 +:1080100003E0000827BD002027BDFFD824A2007F71 +:10802000AFB3001CAFB20018000299C2309200FF3B +:1080300024A3003F0240202102602821AFB1001498 +:10804000AFB00010AFBF00200E000B91000389827B +:1080500000408021004020210220282114400009F6 +:10806000000018218FBF00208FB3001C8FB20018B2 +:108070008FB100148FB000100060102103E00008E1 +:1080800027BD00280E000A1F000000000040282124 +:10809000020020211051FFF3001019C00E000A6EDB +:1080A0000000000002002021024028210E000C5C8C +:1080B000026030218FBF00208FB3001C8FB20018E8 +:1080C0008FB100148FB00010000018210060102143 +:1080D00003E0000827BD00283084FFFF30A5FFFF24 +:1080E00010800007000018213082000110400002BB +:1080F00000042042006518211480FFFB0005284081 +:1081000003E000080060102110C00007000000001C +:108110008CA2000024C6FFFF24A50004AC8200004E +:1081200014C0FFFB2484000403E0000800000000EA +:1081300010A0000824A3FFFFAC8600000000000090 +:10814000000000002402FFFF2463FFFF1462FFFA17 +:108150002484000403E000080000000030A5FFFFB5 +:108160008F4201B80440FFFE3C07601500A7302590 +:108170003C031000AF440180AF400184AF4601884A +:1081800003E00008AF4301B88F8500D02C86400083 +:10819000008018218CA700840087102B1440001049 +:1081A000000000008CA800842D06400050C0000F85 +:1081B000240340008CAA0084008A482B512000012F +:1081C0008CA3008400035A42000B20803C05080069 +:1081D00024A55A400085182103E000088C620000A5 +:1081E00014C0FFF4000000002403400000035A42C2 +:1081F000000B20803C05080024A55A40008518216A +:1082000003E000088C6200008F8300D0906600D0ED +:1082100024C50001A06500D08F8500D0906400D0F7 +:1082200090A200D21044001700000000936C007868 +:108230008F8B00BC318A00FFA16A000C2549000128 +:10824000938700C4312200FF3048007F1107000BE4 +:1082500000026827A36200788F4E017805C0FFFEF8 +:108260008F9900B0241800023C0F1000AF59014054 +:10827000A358014403E00008AF4F01780A000D2C19 +:1082800031A20080A0A000D00A000D220000000052 +:1082900027BDFFD8AFB200188F9200B8AFBF002043 +:1082A000AFB3001CAFB00010AFB100148F9300B497 +:1082B0008E5900283C1000803C0EFFEFAE79000084 +:1082C0008E580024A260000A35CDFFFFAE7800046E +:1082D0009251002C3C0BFF9F356AFFFFA271000CEE +:1082E0008E6F000C3C080040A271000B01F060256D +:1082F000018D4824012A382400E83025AE66000CA0 +:108300008E450004AE6000183C0400FFAE6500140A +:108310008E43002C3482FFFFA66000080062F82420 +:10832000AE7F00108E5900088F9000B0964E00125C +:10833000AE7900208E51000C31D83FFF00187980B3 +:10834000AE7100248E4D001401F0602131CB00018C +:10835000AE6D00288E4A0018000C41C2000B4B8005 +:10836000AE6A002C8E46001C01093821A667001C4D +:10837000AE660030964500028E440020A665001EC1 +:10838000AE64003492430033306200045440000570 +:10839000924600008F8300D08C7F007CAE7F00303F +:1083A000924600008F8500BCA0A6000092440033D6 +:1083B0003082000250400007924E00018F8700BCBF +:1083C000240AFF8090E90000012A4025A0E800006F +:1083D000924E00018F8D00BC2409FFBF2404FFDFF3 +:1083E000A1AE00018F8A00BC914C000D318B007F43 +:1083F000A14B000D8F8600BC90C8000D01093824E8 +:10840000A0C7000D8F9100BC8E6500149223000D53 +:108410002CA200010002F9400064C824033FC025DB +:10842000A238000D8F8800BC965000128F8700D0B4 +:10843000A51000028E45000490ED00BC30AF000393 +:10844000000F702331CC000300AC102131AB0002CF +:1084500015600002244400342444003090F100BC34 +:1084600000B18024320F000415E0000224830004D0 +:10847000008018218F8900AC240A0002AD0300049B +:10848000A12A00009248003F8F8700ACA0E80001BD +:108490008F9100AC9246003F8E440004A626000255 +:1084A0009765003C0E000CF930B0FFFF000213800E +:1084B000005020253C0342000083F825AE3F000415 +:1084C0008F8500AC8E590038ACB900188E58003436 +:1084D000ACB8001CACA0000CACA00010A4A0001410 +:1084E000A4A00016A4A00020A4A00022ACA00024F8 +:1084F0008E62001450400001240200018FBF002052 +:108500008FB3001C8FB200188FB100148FB0001011 +:10851000ACA200080A000D1927BD00288F8600D0E4 +:1085200027BDFFD0AFBF002CAFB60028AFB50024E9 +:10853000AFB40020AFB3001CAFB20018AFB100144D +:10854000AFB0001094C300E094C200E210430041B9 +:108550002405FFFF3C16000E90C400D090C800D147 +:10856000309200FF310400FF0244382B10E0004439 +:1085700026490001108900378F9800B03C0508009B +:108580008CA5005C2414FF8000B86021019468244D +:10859000AF4D002C94CA00E2318B007F017A482154 +:1085A00031447FFF01364021000410400048A821DB +:1085B00096A700003C1F08008FFF005830F53FFFD2 +:1085C0000015198003E3C821031988213233007F85 +:1085D000027A782102348024AF50002C01F69821D1 +:1085E000926E000D31C5000410A00048000000008C +:1085F00094C300E294C300E294D800E22404800013 +:10860000307F7FFF27F9000133317FFF030480248F +:1086100002117825A4CF00E294CE00E23C120800BB +:108620008E52006031D47FFF129200DF0000000004 +:108630008E720018000028212646FFFFAE66002C2F +:108640008F8600D094C800E094C900E21528FFC2CC +:10865000000000008FBF002C8FB600288FB50024CB +:108660008FB400208FB3001C8FB200188FB100149C +:108670008FB0001000A0102103E0000827BD0030DB +:1086800090CD00D2264A000131AC00FF008C582169 +:10869000116AFFF08F9800B03C0508008CA5005CC3 +:1086A0002414FF8000B8602101946824AF4D002C91 +:1086B00094CA00E2318B007F017A482131447FFF68 +:1086C00001364021000410400048A82196A7000070 +:1086D0003C1F08008FFF005830F53FFF0015198040 +:1086E00003E3C821031988213233007F027A7821FD +:1086F00002348024AF50002C01F69821926E000DB8 +:1087000031C5000414A0FFBA000000008E660010FE +:108710000012C0C08E6E00300012914002587821C5 +:10872000036F582100CE6823256C008824020002C4 +:10873000AE6D0010AF8C00ACA1620088976A003C5F +:108740008E6400308F9100AC0E000CF93150FFFFA9 +:1087500000022380009048253C034200012340256D +:10876000AE2800048E6700048F8C00AC8E7F000062 +:10877000240D0008AD87001CAD9F0018AD80000CD3 +:10878000AD8000109265000A30B900FFA599001471 +:10879000967800083C05000CA59800169271000A16 +:1087A000322F00FFA58F00209670000824110005CD +:1087B000A5900022AD800024926E000B2410C00012 +:1087C00031C600FFA5860002A18D00018E6B00302E +:1087D0008F8200AC8F8800B0AC4B00083C0A0800C8 +:1087E0008D4A00540148202100944824AF490028B4 +:1087F0003C0308008C6300540068382130FF007F80 +:1088000003FAC8210325C02102587821AF8F00BC8C +:10881000AF9800C0A1F100008F8B00BC2403FFBF04 +:108820002405FFDF956E000201D0A024029590255B +:10883000A57200029166000230CD003F35AC0040C9 +:10884000A16C00028F8800BC8F8200D03C0C7FFF9F +:10885000AD0000048C4A007C358BFFFF3C02800099 +:10886000AD0A00089104000D3089007FA109000DB8 +:108870008F9F00BC93F5000D02A33824A3E7000DE1 +:108880008F9100BC9239000D0325C024A238000D41 +:108890008E6F00348F8D00BCADAF00108E6E002C3B +:1088A0008E70003001D0A023ADB4001491B2001836 +:1088B0003246007FA1A600188F8700BC8E6A003068 +:1088C0008CE40018014B4824008240240109A825AB +:1088D000ACF500189263000AA0E3001C967F000824 +:1088E0008F8500BC8F9900D0A4BF001E8E70003011 +:1088F0008E6400300E00020D8F2500848F8500D01D +:10890000000289400002C10090AE00BC023878210C +:108910000040302131D4000212800003020F802178 +:108920000002A8800215802190B200BC32540004DD +:10893000128000020006C880021980218E6F00306C +:108940008F8B00BC2406800031EE0003000E6823EC +:1089500031AC0003020C1021AD62000494A400E2CB +:1089600094AA00E294A300E231507FFF26040001A4 +:1089700030897FFF0066402401098825A4B100E208 +:1089800094A700E23C1308008E73006030FF7FFF65 +:1089900013F30012000000000E000D19000000008B +:1089A0000A000E270000282194CD00E201A46024D3 +:1089B000A4CC00E290CB00E290C200E2316A00FF5A +:1089C000000A49C200092027000441C03055007F39 +:1089D00002A838250A000E23A0C700E294B100E2E5 +:1089E00002263824A4A700E290BF00E290B400E27F +:1089F00033F300FF0013C9C2001990273298007F9B +:108A00000012A9C0031530250E000D19A0A600E222 +:108A10000A000E27000028213084FFFF30A5FFFF49 +:108A2000AF440018AF45001C03E000088F4200145B +:108A300027BDFFB0AFB000288F9000D0AFB4003892 +:108A4000AFBF004CAFBE0048AFB70044AFB6004068 +:108A5000AFB5003CAFB30034AFB20030AFB1002CC3 +:108A6000A7A00014920600D1920500D03094FFFF19 +:108A700030C400FF30A300FF0064102BA7A0001E2D +:108A800010400071AFA00010920900D00014982B84 +:108A9000312800FF0088382324F2FFFF0012882BC2 +:108AA0000233782451E000758FB20010961800123E +:108AB000961900100014F4000319B8230017B4002D +:108AC000001614030282A82A16A00002001E240326 +:108AD000004020210244F82B13E0000200801821FE +:108AE000024018210003340000061C033065FFFF1C +:108AF0002CA20009144000020060982124130008F1 +:108B00008E090008001359808E08000C3164FFFFA5 +:108B10003C0A0010008A3825274A0400AF49003873 +:108B2000AF8A00B8AF48003CAF47003000000000FB +:108B30000000000000000000000000000000000035 +:108B40000000000000000000000000008F4D000049 +:108B500031AC00201180FFFD0013702A01D11024D8 +:108B60000000A821104001C0000000008F9800B054 +:108B70003C0B08008D6B00542411FF80921E00D026 +:108B80000178202100911024921900D0AF420028D2 +:108B90008D4500103C0608008CC600583C170800A4 +:108BA0008EF7005430A73FFF0007198000C3402113 +:108BB000030820210091F824920B00D0AF5F002C15 +:108BC0009148000033D600FF332F00FF02F87021D8 +:108BD00000166140000F68C031C9007F018D382147 +:108BE000013A2821316300FF3086007F3C02000CEF +:108BF00000A2B021000389400367C82100DAF821F0 +:108C00003108003F3C1E000E0236B821273800888C +:108C100003FE88212D0F0008AF9800ACAF9700BC71 +:108C2000AF9600C011E0018FAF9100B400086880DA +:108C30003C0E080025CE59EC01AE60218D89000064 +:108C40000120000800000000920E00D2920D00D01A +:108C50000014982B31CA00FF31AC00FF008C582360 +:108C6000014B20212492FFFF0012882B023378242D +:108C700015E0FF8E000000008FB200108FBF004C87 +:108C80008FBE00483A4200018FB700448FB60040C3 +:108C90008FB5003C8FB400388FB300348FB20030F2 +:108CA0008FB1002C8FB0002803E0000827BD0050D2 +:108CB000915800013317002012E00204241600012D +:108CC000921F00BC0000B02133F900011320000DF9 +:108CD000241E00018D4800148E0300840103B02B74 +:108CE00016C00002010030218E0600848E0500644B +:108CF00000C5382B14E0000200C020218E0400645F +:108D00000080B0218D4200148E0B0064004B302B8C +:108D100014C00002004020218E0400640096B82395 +:108D200056E00001241E0002025E202B1480014840 +:108D3000000018218D5900388E2F000C3C1800803F +:108D4000AE3900008D5000343C0EFF9F01F86025C5 +:108D5000AE3000049149003F35CDFFFF018D202446 +:108D60003C0A00203C0BFFEFA229000B008A3825AB +:108D70003562FFFF00E228243C0600088F8700B818 +:108D800000A6C825AE39000C8CE30014AE200018F4 +:108D90003C08FFFBAE2300148CF80018351FFFFFC2 +:108DA000033F7024AE38001C8CEF000802D78021EE +:108DB000AE2F00248CED000CAE30002CAE2E000C3B +:108DC000AE2D0020AE200028A6200038A620003AB4 +:108DD0008CEC0014019648230137502311400011F8 +:108DE000AE2A001090EE003D8E2C00048E24000070 +:108DF000000E6900018D28210000502100AD302BAC +:108E0000008A582101661021AE250004AE22000020 +:108E100090E3003DA223000A8F8800B8951F00064A +:108E2000A63F00088F8B00AC2406000202C0202160 +:108E3000A16600009765003C8F9000AC30A2FFFF58 +:108E40000E000CF9AFA200208FA300200002438087 +:108E50008F8500B80103C8253C1F4200033FC02591 +:108E6000AE1800048F8400AC8CAF0038AC8F0018B3 +:108E70008CB00034AC90001CAC80000CAC800010B6 +:108E8000A4800014A4800016A4800020A4800022E6 +:108E9000AC80002490A7003FA487000212C00210FB +:108EA000240D000152E0000290A2003D90A2003E7D +:108EB000244A0001A08A00018F8400ACAC9600080F +:108EC0008F8300D024070034906F00BC31EE000285 +:108ED00051C00001240700308F8200B88F9900BC78 +:108EE000906800BC905F00002410000432CF0003A3 +:108EF000A33F00008F9800B88F8C00BC020F702336 +:108F0000930D00012405C00031CA0003A18D0001AA +:108F10008F9000BC8F8900B800F6382196040002BB +:108F20009526001200EA38210085582430C33FFFFF +:108F300001631025A6020002921F000231080004FE +:108F400033F9003F37380040A218000212C0000277 +:108F50008F8500BC00E838218F8600D0ACA70004C4 +:108F6000241FFFBF8CC3007C2ECB0001240FFFDF2A +:108F7000ACA3000890A8000D000B69403102007FEF +:108F8000A0A2000D8F9000BC9219000D033FC024D9 +:108F9000A218000D8F8A00BC914E000D01CF6024F5 +:108FA000018D4825A149000D8F8600B88F8B00BC2C +:108FB0008CC70020AD6700108CC50024AD6500147F +:108FC0008CC40028AD6400188CC3002C0E000D1951 +:108FD000AD63001C2408000257C8009C8F9000D08D +:108FE0008F8F00D08F8A00C002E0202191E800D04E +:108FF00091EB00D091E700D0311000FF316E00FFFF +:1090000000106940000E28C001A5182130E900FFBA +:109010000363C8210009314000CAF82127220088D3 +:10902000AF8200ACAF9F00BCA33E00880E000CF9DD +:109030008F9000AC8FB80020000263803C0F42008C +:10904000019840258F8C00B8010F5825AE0B000405 +:109050008D8400388F8B00AC00002821000539007A +:10906000AD6400188D8E00343C0F7FFF35E8FFFFA4 +:10907000AD6E001C9183003E8D69001C8D6600184A +:109080000003510000036F02012AC02100ED1025EA +:10909000030AF82B00C2C821033F8021AD78001CD1 +:1090A000AD700018AD60000CAD6000109184003E02 +:1090B000241F00052410C000A5640014958E000430 +:1090C00002E8402402E02021A56E00169185003EB2 +:1090D000A5650020958D0004A56D0022AD600024DB +:1090E0009187003FA56700029183003E9189003D72 +:1090F0000123502325460001A16600018F8200ACA8 +:109100008F9900BCAC570008A33F00008F8A00BCB9 +:109110008F9800B8954F0002970E00122418FFBFD9 +:10912000020F682431C53FFF01A53825A54700027D +:10913000914C00022405FFDF3189003F35230040B8 +:10914000A14300028F9900BC8F8600D02409FFFF45 +:10915000AF2000048CCB007C2403FF80AF2B0008E1 +:109160009322000D3C0B8000305F007FA33F000D79 +:109170008F8E00BC91D0000D02187824A1CF000D75 +:109180008F8C00BC918D000D01A53824A187000DA6 +:109190008F8600BCACC90010ACD6001490CA001871 +:1091A0000143B025A0D600188F8F00BC8F9800B85F +:1091B0008DE20018004BF82403E8C825ADF900182B +:1091C0009310003EA1F0001C8F8E00B88F8D00BC64 +:1091D0008F8700D095C50004A5A5001E0E00020DC6 +:1091E0008CE500848F8700D00002614000022100DE +:1091F00090EA00BC01844821004028213156000239 +:1092000012C0000302E930210002B08000D63021F4 +:1092100090EC00BC318400041080000332EA0003AB +:109220000005C08000D83021240900048F9700BCBD +:10923000012A1023305F000300DFC821AEF90004CB +:109240000E000D19A62500388F9000D003C01821FC +:10925000146000020060B0210000902156C000861A +:109260008F9700B80012882B9609001002955023A2 +:109270003C14002002A91021A6020010AF540030B7 +:109280003154FFFF0000000096130010961F0012DB +:1092900013F30011000000008E17000C8E0C000864 +:1092A0000015C98002F94021001927C30119B02B0C +:1092B0000184782101F65821AE08000CAE0B00089D +:1092C0000014A82B023580241200FE6B8F9000D072 +:1092D0000A000F4200000000960B00148E050004E7 +:1092E0003163FFFF000370C000AE3821AF47003C80 +:1092F0008E0600048F4D003C00CDF0231BC00036CD +:10930000000000008E080000250200013C1600103D +:1093100036CF0008AF420038AF4F003000000000E9 +:10932000000000000000000000000000000000003D +:109330000000000000000000000000008F4400005A +:10934000308C00201180FFFD000000008F590400C8 +:109350003C170020AE1900088F550404AE15000C10 +:10936000AF570030000000003C0608008CC60044E7 +:109370002418000110D800D3000000009607001246 +:109380003C0508008CA5004000A76821A60D00122E +:10939000961E001427C90001A609001496020014A5 +:1093A0003044FFFF5486FFC70014A82B30A5FFFFF1 +:1093B0000E000F1DA60000143C0308008C6300245F +:1093C000960500120043702300AE3023A60600125B +:1093D0000A0011480014A82B8E0200000A00115B3D +:1093E0003C1600109156000124100001001678422E +:1093F00015F0001C97A8001E8D5F00142411C000FA +:1094000033FE3FFF0111C8243C1808008F1800608C +:10941000033EB82532E53FFF00B8502B1140001144 +:10942000A7B7001E3C1008008E1000588F8F00B0A8 +:1094300000057180240CFF80020F682101AE4821D5 +:109440003124007F012C5824009A28213C02000E70 +:10945000AF4B002C00A2302190C7000D34E3000474 +:10946000A0C3000D0E000D3B000000008F9000D047 +:10947000240300018F9700B826B900010019AC0041 +:10948000024390230015AC0326F8004002B3202AC3 +:109490000012882B240C000103005021009110249D +:1094A000AF9800B80A000F70AFAC001095560012CC +:1094B0008F8400B032C5FFFF0E000CEEA7B600147B +:1094C0008F9000D00A0011B4000018218D59003887 +:1094D000A620000824040003AE3900008D57003494 +:1094E000A220000A8F9800B8AE3700043C0F00801D +:1094F000930C003FA224000C8E28000C3C0BFF9F15 +:10950000A22C000B010F1825356EFFFF3C05FFEF65 +:109510008F9700B8006E682434A7FFFF01A730249E +:10952000AE26000C8EFE001496FF00128F8200B053 +:10953000AE3E00108EF00014AE200018AE200020C9 +:10954000AE300014AE2000248EE9001833F03FFF47 +:1095500000105180AE2900288EF900080142C02178 +:1095600033EC0001AE3900308EEB000C8F8500AC7F +:10957000001879C2000C238001E44021240E00026F +:10958000A628001CA6200036AE2B002CA0AE0000A2 +:109590009767003C8F8A00AC3C03420030EDFFFF30 +:1095A00001A33025AD4600048F9E00B824020001BF +:1095B0002408C0008FD1003824060034AD510018B3 +:1095C0008FC90034AD49001CAD40000CAD40001007 +:1095D000A5400014A5400016A5400020A54000228B +:1095E000AD400024A5560002A14200018F9F00ACAF +:1095F0008F9900B88F9800BCAFF600089337000031 +:10960000A31700008F8C00B88F8F00BC91840001DD +:10961000A1E400018F8D00BC95AB000201687024AD +:1096200001D02825A5A5000291A7000230E3003F44 +:10963000A1A300028F8300D08F8400BC907100BC76 +:10964000323E000253C0000124060030AC86000404 +:109650008C6F007C2403FFBFAC8F00089088000D46 +:10966000310B007FA08B000D8F8700BC90EE000DAA +:1096700001C32824A0E5000D8F9E00BC93CD000DF2 +:1096800035A60020A3C6000D8F8A00B88F9100BCBC +:109690008D500020AE3000108D490024AE290014FA +:1096A0008D420028AE2200188D5F002CAE3F001CBA +:1096B0000E000D19000000008F9000D00A00112E3E +:1096C00002C01821960A00123C1F08008FFF0024D8 +:1096D00003EA9821A61300120A0011480014A82BCF +:1096E000A08D00018F8900AC240C0001AD2C000876 +:1096F0000A0010488F8300D027BDFFE03C18080007 +:109700008F180050AFB00010AFBF0018AFB10014F9 +:10971000AF8400B093710074030478212410FF809B +:1097200031EE007F3225007F01F0582401DA6821F4 +:109730003C0C000AA38500C401AC2821AF4B0024D7 +:1097400094A900109768000690A600620080382156 +:10975000240200300109202330C300F0AF8500D07F +:10976000106200193090FFFF90AE0062240DFFF0F0 +:10977000240A005001AE6024318B00FF116A002FD3 +:109780000000000016000007241F0C00AF5F00243B +:109790008FB100148FBF00188FB0001003E00008D5 +:1097A00027BD00200E000F2302002021241F0C00E3 +:1097B000AF5F00248FB100148FBF00188FB000106E +:1097C00003E0000827BD002094A200E094A400E27A +:1097D00090BF0113008218263079FFFF33E700C0E5 +:1097E00014E000092F3100011600003800000000CD +:1097F0005620FFE6241F0C000E000DDE00000000C6 +:109800000A00127A241F0C001620FFDE0000000060 +:109810000E000DDE000000001440FFDC241F0C00D1 +:10982000160000228F8300D0906901133122003F7F +:10983000A06201130A00127A241F0C0094AF00D416 +:109840008F8600D400E02821240400050E000C7F40 +:1098500031F0FFFF1440000524030003979100E658 +:10986000000018212625FFFFA78500E68F5801B8C4 +:109870000700FFFE3C196013AF400180241F0C005D +:10988000AF500184007938253C101000AF470188A3 +:109890008FB10014AF5001B8AF5F00248FB000103B +:1098A0008FBF001803E0000827BD00200E000F2323 +:1098B000020020215040FFB5241F0C008F8300D0F0 +:1098C000906901130A0012A33122003F0E000F23FA +:1098D000020020211440FFAD241F0C0012200007BD +:1098E0008F8300D0906801133106003F34C20040DE +:1098F000A06201130A00127A241F0C000E000DDE74 +:10990000000000005040FFA1241F0C008F8300D0F6 +:10991000906801133106003F0A0012D334C20040A0 +:10992000AF9B00C803E00008AF8000EC3089FFFF68 +:10993000000940422D020041000929801440000224 +:109940000009504024080040000879400008C0C0C9 +:1099500001F85821256701A800EF702125CC007F70 +:10996000240DFF80018D18240065302100CA2821B4 +:1099700025640088240A00883C010800AC2A004CB9 +:109980003C010800AC240050AF8500D43C01080025 +:10999000AC2900603C010800AC2800643C010800D0 +:1099A000AC2700543C010800AC2300583C010800DF +:1099B000AC26005C03E0000800000000308300FFDC +:1099C00030C6FFFF30E400FF8F4201B80440FFFEC5 +:1099D00000034C00012438253C08600000E82025E5 +:1099E0003C031000AF450180AF460184AF440188BD +:1099F00003E00008AF4301B88F86001C3C096012E9 +:109A0000352700108CCB00043C0C600E358500100F +:109A1000316A00062D480001ACE800C48CC4000483 +:109A2000ACA431808CC2000894C30002ACA2318483 +:109A300003E00008A78300E43C0308008C630050A7 +:109A40008F8400E88F86001C2402FF800064C02100 +:109A50000302C824AF5900288CCD00043305007FD1 +:109A600000BA78213C0E000C01EE2821ACAD005864 +:109A70008CC80008AF8500D03C076012ACA8005C21 +:109A80008CCC001034E80010ACAC000C8CCB000C7B +:109A9000ACAB000894AA00143C0208008C420044BD +:109AA00025490001A4A9001494A400143083FFFFE9 +:109AB000106200178F8400D03C0A08008D4A0040D5 +:109AC000A4AA00128CCE0018AC8E00248CCD0014F9 +:109AD000AC8D00208CC70018AC87002C8CCC0014F7 +:109AE00024060001AC8C00288D0B00BC5166001AC6 +:109AF0008D0200B48D0200B8A482003A948F003A1F +:109B0000A48F003C948800D403E000083102FFFFDA +:109B10003C0908008D290024A4A000148F8400D0E3 +:109B2000A4A900128CCE0018AC8E00248CCD001499 +:109B3000AC8D00208CC70018AC87002C8CCC001496 +:109B400024060001AC8C00288D0B00BC5566FFEA92 +:109B50008D0200B88D0200B4A482003A948F003ABE +:109B6000A48F003C948800D403E000083102FFFF7A +:109B70008F86001C3C0C08008D8C0050240BFF804D +:109B80008CCD00083C03000C000D51C0018A40211F +:109B9000010B4824AF8A00E8AF49002890C70007AE +:109BA0003105007F00BA10210043282130E4000471 +:109BB0001080002FAF8500D090CF000731EE000855 +:109BC00011C0003C000000008CD9000C8CC40014B3 +:109BD0000324C02B13000026000000008CC2000CE0 +:109BE000ACA200648CCD00182402FFF8ACAD006874 +:109BF0008CCC0010ACAC00808CCB000CACAB0084E7 +:109C00008CCA001CACAA007C90A900BC0122402494 +:109C1000A0A800BC90C300073067000810E0000453 +:109C20008F8500D090AF00BC35EE0001A0AE00BC27 +:109C300090D90007333800011300000F8F8400D043 +:109C400024070020908200BC34490002A08900BC97 +:109C50008F8400D090880062310300F01467000602 +:109C6000240A0034AC8A00C00A0013B500000000CA +:109C70000A00138F8CC2001490CB000731660002DB +:109C800010C0000500000000908D00BC35AC000441 +:109C9000A08C00BC8F8400D090980113330F003F3C +:109CA000A08F01138F8E00D095C500D403E000086B +:109CB00030A2FFFFACA000640A0013900000000077 +:109CC00027BDFFD8AFB000108F90001CAFBF00249D +:109CD000AFB40020AFB20018AFB10014AFB3001C96 +:109CE0009613000E3C07600A3C1460063264FFFFC6 +:109CF000369300100E0012E234F404108F8400D466 +:109D00003C11600E0E0009BE36310010920E001597 +:109D10003C0708008CE700603C12601231CD000F58 +:109D2000A38D00F08E0E00048E0D00089608001220 +:109D3000961F00109619001A9618001E960F001C08 +:109D4000310CFFFF33EBFFFF332AFFFF3309FFFF27 +:109D500031E6FFFF3C010800AC2B00403C0108004D +:109D6000AC2C00243C010800AC2A0044AE29317818 +:109D7000AE26317C92020015960300163652001072 +:109D8000304400FF3065FFFF3C0608008CC60064CD +:109D9000AE243188AE4500B492080014961900181C +:109DA000241F0001011FC004332FFFFF3C050800E2 +:109DB0008CA50058AE5800B8AE4F00BC920C0014F1 +:109DC000AF8E00D8AF8D00DC318B00FFAE4B00C0F2 +:109DD000920A0015AE670048AE66004C314900FF9C +:109DE000AE4900C8AE65007C3C0308008C6300509F +:109DF0003C0408008C84004C3C0808008D0800548A +:109E00003C0208008C42005C8FBF0024AE630080DF +:109E10008FB00010AE8300748FB3001CAE22319C53 +:109E2000AE4200DCAE2731A0AE2631A4AE24318C88 +:109E3000AE233190AE283194AE253198AE870050D4 +:109E4000AE860054AE8500708FB10014AE4700E0BE +:109E5000AE4600E4AE4400CCAE4300D0AE4800D4E1 +:109E6000AE4500D88FB400208FB2001803E0000880 +:109E700027BD002827BDFFE0AFB10014AFBF001819 +:109E8000241100010E000868AFB000101051000549 +:109E9000978400E6978300CC0083102B14400008C1 +:109EA0008F8500D4240700028FBF00188FB10014E3 +:109EB0008FB0001000E0102103E0000827BD002053 +:109EC0000E000C9D24040005AF8200E81040FFF650 +:109ED000240700020E00086C8F90001C979F00E67C +:109EE0008F9900E88F8D00C827EF0001240E0050E5 +:109EF000AF590020A78F00E6A1AE00003C0C08007F +:109F00008D8C00648F8600C8240A8000000C5E00DF +:109F1000ACCB0074A4C0000694C9000A241FFF80C3 +:109F20003C0D000C012AC024A4D8000A90C8000AE5 +:109F300024182000011F1825A0C3000A8F8700C81D +:109F4000A0E000788F8500C800003821A0A0008321 +:109F50003C0208008C4200508F8400E800447821C5 +:109F600001FFC824AF590028960B000231EE007F94 +:109F700001DA6021018D3021A4CB00D4960A0002C1 +:109F8000AF8600D03C0E000425492401A4C900E698 +:109F90008E080004ACC800048E030008ACC30000A7 +:109FA000A4C00010A4C00014A0C000D08F8500D0B1 +:109FB0002403FFBFA0A000D13C0408008C840064EF +:109FC0008F8200D0A04400D28E1F000C8F8A00D058 +:109FD000978F00E4AD5F001C8E1900102410003034 +:109FE000AD590018A5400030A5510054A5510056A8 +:109FF000A54F0016AD4E0068AD580080AD580084E6 +:10A00000914D006231AC000F358B0010A14B006206 +:10A010008F8600D090C900633128007FA0C80063FC +:10A020008F8400D02406FFFF9085006300A31024D6 +:10A03000A08200638F9100D000E01021923F00BC0D +:10A0400037F90001A23900BC8F8A00D0938F00F04D +:10A05000AD580064AD5000C0914E00D3000F6900B0 +:10A0600031CC000F018D5825A14B00D38F8500D036 +:10A070008F8900DCACA900E88F8800D88FBF00185A +:10A080008FB100148FB0001027BD0020ACA800ECE9 +:10A09000A4A600D6A4A000E0A4A000E203E000086B +:10A0A0000000000027BDFFE0AFB000108F90001C43 +:10A0B000AFB10014AFBF00188E1900043C1808009F +:10A0C0008F180050240FFF80001989C002387021BA +:10A0D00031CD007F01CF602401BA50213C0B000C30 +:10A0E000AF4C0028014B4021950900D4950400D6BF +:10A0F0008E0700043131FFFFAF8800D00E00093613 +:10A10000000721C08E0600048F8300C8000629C006 +:10A11000AF4500209064003E3082004014400006AD +:10A120008F8400D0341FFFFF948300D63062FFFF7E +:10A13000145F000400000000948400D60E0008CBD9 +:10A140003084FFFF8E050004022030218FBF0018ED +:10A150008FB100148FB000102404002200003821B9 +:10A16000000529C00A00130627BD002027BDFFE017 +:10A17000AFB100143091FFFFAFB00010AFBF0018B7 +:10A180001220001D000080218F86001C8CC500005D +:10A190002403000600053F020005140230E4000716 +:10A1A00014830015304500FF2CA800061100004D57 +:10A1B000000558803C0C0800258C5A0C016C50217D +:10A1C0008D49000001200008000000008F8E00EC87 +:10A1D000240D000111CD005900000000260B0001E4 +:10A1E0003170FFFF24CA00200211202B01403021D2 +:10A1F0001480FFE6AF8A001C020010218FBF0018F8 +:10A200008FB100148FB0001003E0000827BD0020BC +:10A21000938700CE14E00038240400140E0013C706 +:10A22000000000008F86001C240200010A00150EA9 +:10A23000AF8200EC8F8900EC240800021128003B5B +:10A24000240400130000282100003021240700010D +:10A250000E001306000000000A00150E8F86001C79 +:10A260008F8700EC2405000214E5FFF62404001299 +:10A270000E001373000000008F8500E800403021BD +:10A28000240400120E001306000038210A00150EE7 +:10A290008F86001C8F8300EC241F0003147FFFD0E7 +:10A2A000260B00010E001325000000008F8500E83A +:10A2B0000040302124020002240400100000382154 +:10A2C000AF8200EC0E001306000000000A00150E1D +:10A2D0008F86001C8F8F00EC2406000211E6000B15 +:10A2E000000000002404001000002821000030219C +:10A2F0000A00152B24070001000028210E00130678 +:10A30000000030210A00150E8F86001C0E00143448 +:10A3100000000000144000128F99001C8F86001C62 +:10A32000240200030A00150EAF8200EC0E0014C0D8 +:10A33000000000000A00150E8F86001C0E00131589 +:10A340000000000024020002240400140000282160 +:10A3500000003021000038210A001548AF8200ECCF +:10A360000040382124040010973800020000282102 +:10A370000E0013063306FFFF0A00150E8F86001C21 +:10A380008F8400C83C077FFF34E6FFFF8C85007494 +:10A390002402000100A61824AC83007403E0000826 +:10A3A000A082000510A000362CA20080274A0400DD +:10A3B0003C0B0005240900801040000724080080A1 +:10A3C00030A6000F00C540212D030081146000025B +:10A3D00000A0482124080080AF4B0030000000009E +:10A3E00000000000000000001100000900003821FA +:10A3F000014030218C8D000024E7000400E8602B30 +:10A40000ACCD0000248400041580FFFA24C60004AB +:10A410000000000000000000000000003C0E0006EC +:10A42000010E3825AF47003000000000000000009A +:10A43000000000008F4F000031E800101100FFFD08 +:10A44000000000008F42003C8F43003C0049C821BF +:10A450000323C02B13000004000000008F4C0038C1 +:10A4600025860001AF4600388F47003C00A928230D +:10A4700000E96821AF4D003C14A0FFCE2CA2008063 +:10A4800003E000080000000027BDFFD03C020002EE +:10A49000AFB100143C11000CAF450038AFB3001C45 +:10A4A000AF46003C00809821AF4200302405008870 +:10A4B000AF44002803512021AFBF0028AFB50024CE +:10A4C000AFB40020AFB200180E001580AFB000107E +:10A4D0003C1F08008FFF004C3C1808008F180064D8 +:10A4E0002410FF8003F3A82132B9007F02B0782442 +:10A4F0000018A0C0033A70210018914001D120211A +:10A50000AF4F00280E001580025428213C0D080092 +:10A510008DAD00502405012001B35821316C007F1E +:10A5200001705024019A4821013120210E0015802C +:10A53000AF4A00283C0808008D0800543C0508007C +:10A540008CA500640113382130E6007F00F0182448 +:10A5500000DA202100912021AF4300280E00158051 +:10A56000000529403C0208008C4200583C100800BD +:10A570008E1000601200001C005388212415FF80FB +:10A580000A0016033C14000C3226007F0235182402 +:10A5900000DA202102402821AF4300280094202126 +:10A5A0000E0015802610FFC01200000F0232882115 +:10A5B0002E05004110A0FFF4241210003226007F67 +:10A5C000001091800235182400DA20210240282151 +:10A5D000AF430028009420210E0015800000802148 +:10A5E0001600FFF3023288213C0B08008D6B005CE3 +:10A5F000240AFF802405000201734021010A482437 +:10A60000AF4900283C040800948400623110007FA8 +:10A61000021A88213C07000C0E000CCD022798215D +:10A6200000402821026020218FBF00288FB5002420 +:10A630008FB400208FB3001C8FB200188FB10014AC +:10A640008FB000100A00158027BD00308F83001CDA +:10A650008C620004104000030000000003E00008CA +:10A66000000000008C6400108C6500080A0015B919 +:04A670008C66000CE8 +:0CA67400000000000000001B0000000FB0 +:10A680000000000A000000080000000600000005AD +:10A6900000000005000000040000000400000003AA +:10A6A000000000030000000300000003000000039E +:10A6B0000000000200000002000000020000000292 +:10A6C0000000000200000002000000020000000282 +:10A6D0000000000200000002000000020000000272 +:10A6E0000000000200000002000000020000000163 +:08A6F000000000010000000160 +:08A6F80008000F5808000DB026 +:10A7000008000FEC0800109408000F8008000FC02C +:10A71000080011CC08000DCC080011F008000E1C38 +:10A7200008001630080015D808000DCC08000DCC24 +:10A7300008000DCC0800127C0800127C08000DCC2B +:10A7400008000DCC0800157C08000DCC08000DCCCD +:10A7500008000DCC08000DCC080013EC08000DCC4F +:10A7600008000DCC08000DCC08000DCC08000DCC65 +:10A7700008000DCC08000DCC08000DCC08000DCC55 +:10A7800008000DCC08000DCC08000DCC08000DCC45 +:10A7900008000DCC08000FE008000DCC08000DCC1F +:10A7A0000800152C08000DCC08000DCC08000DCCBD +:10A7B00008000DCC08000DCC08000DCC08000DCC15 +:10A7C00008000DCC08000DCC08000DCC08000DCC05 +:10A7D00008000DCC08000DCC08000DCC08000DCCF5 +:10A7E00008000DCC08000DCC0800145808000DCC52 +:10A7F00008000DCC08001370080012E008002EA01D +:10A8000008002EA808002E7008002E7C08002E8854 +:10A8100008002E94080046C008003F0C080046407F +:10A82000080046C0080046C0080044C0080046C0F2 +:10A830000800470808005530080054F0080054BCD0 +:0CA84000080054900800546C08005428D4 +:04A84C000A000C767C +:10A8500000000000000000000000000D727870355C +:10A860002E302E306A330000050000030000000087 +:10A8700000000001000000000000000000000000D7 +:10A8800000000000000000000000000000000000C8 +:10A8900000000000000000000000000000000000B8 +:10A8A00000000000000000000000000000000000A8 +:10A8B0000000000000000000000000000000000098 +:10A8C0000000000000000000000000000000000088 +:10A8D0000000000000000000000000000000000078 +:10A8E0000000000000000000000000000000000068 +:10A8F0000000000000000000000000000000000058 +:10A900000000000000000000000000000000000047 +:10A910000000000000000000000000000000000037 +:10A920000000000000000000000000000000000027 +:10A930000000000000000000000000000000000017 +:10A940000000000000000000000000000000000007 +:10A9500000000000000000000000000000000000F7 +:10A9600000000000000000000000000000000000E7 +:10A9700000000000000000000000000000000000D7 +:10A9800000000000000000000000000000000000C7 +:10A9900000000000000000000000000000000000B7 +:10A9A00000000000000000000000000000000000A7 +:10A9B0000000000000000000000000000000000097 +:10A9C0000000000000000000000000000000000087 +:10A9D0000000000000000000000000000000000077 +:10A9E0000000000000000000000000000000000067 +:10A9F0000000000000000000000000000000000057 +:10AA00000000000000000000000000000000000046 +:10AA10000000000000000000000000000000000036 +:10AA20000000000000000000000000000000000026 +:10AA30000000000000000000000000000000000016 +:10AA40000000000000000000000000000000000006 +:10AA500000000000000000000000000000000000F6 +:10AA600000000000000000000000000000000000E6 +:10AA700000000000000000000000000000000000D6 +:10AA800000000000000000000000000000000000C6 +:10AA900000000000000000000000000000000000B6 +:10AAA00000000000000000000000000000000000A6 +:10AAB0000000000000000000000000000000000096 +:10AAC0000000000000000000000000000000000086 +:10AAD0000000000000000000000000000000000076 +:10AAE0000000000000000000000000000000000066 +:10AAF0000000000000000000000000000000000056 +:10AB00000000000000000000000000000000000045 +:10AB10000000000000000000000000000000000035 +:10AB20000000000000000000000000000000000025 +:10AB30000000000000000000000000000000000015 +:10AB40000000000000000000000000000000000005 +:10AB500000000000000000000000000000000000F5 +:10AB600000000000000000000000000000000000E5 +:10AB700000000000000000000000000000000000D5 +:10AB800000000000000000000000000000000000C5 +:10AB900000000000000000000000000000000000B5 +:10ABA00000000000000000000000000000000000A5 +:10ABB0000000000000000000000000000000000095 +:10ABC0000000000000000000000000000000000085 +:10ABD0000000000000000000000000000000000075 +:10ABE0000000000000000000000000000000000065 +:10ABF0000000000000000000000000000000000055 +:10AC00000000000000000000000000000000000044 +:10AC10000000000000000000000000000000000034 +:10AC20000000000000000000000000000000000024 +:10AC30000000000000000000000000000000000014 +:10AC40000000000000000000000000000000000004 +:10AC500000000000000000000000000000000000F4 +:10AC600000000000000000000000000000000000E4 +:10AC700000000000000000000000000000000000D4 +:10AC800000000000000000000000000000000000C4 +:10AC900000000000000000000000000000000000B4 +:10ACA00000000000000000000000000000000000A4 +:10ACB0000000000000000000000000000000000094 +:10ACC0000000000000000000000000000000000084 +:10ACD0000000000000000000000000000000000074 +:10ACE0000000000000000000000000000000000064 +:10ACF0000000000000000000000000000000000054 +:10AD00000000000000000000000000000000000043 +:10AD10000000000000000000000000000000000033 +:10AD20000000000000000000000000000000000023 +:10AD30000000000000000000000000000000000013 +:10AD40000000000000000000000000000000000003 +:10AD500000000000000000000000000000000000F3 +:10AD600000000000000000000000000000000000E3 +:10AD700000000000000000000000000000000000D3 +:10AD800000000000000000000000000000000000C3 +:10AD900000000000000000000000000000000000B3 +:10ADA00000000000000000000000000000000000A3 +:10ADB0000000000000000000000000000000000093 +:10ADC0000000000000000000000000000000000083 +:10ADD0000000000000000000000000000000000073 +:10ADE0000000000000000000000000000000000063 +:10ADF0000000000000000000000000000000000053 +:10AE00000000000000000000000000000000000042 +:10AE10000000000000000000000000000000000032 +:10AE20000000000000000000000000000000000022 +:10AE30000000000000000000000000000000000012 +:10AE40000000000000000000000000000000000002 +:10AE500000000000000000000000000000000000F2 +:10AE600000000000000000000000000000000000E2 +:10AE700000000000000000000000000000000000D2 +:10AE800000000000000000000000000000000000C2 +:10AE900000000000000000000000000000000000B2 +:10AEA00000000000000000000000000000000000A2 +:10AEB0000000000000000000000000000000000092 +:10AEC0000000000000000000000000000000000082 +:10AED0000000000000000000000000000000000072 +:10AEE0000000000000000000000000000000000062 +:10AEF0000000000000000000000000000000000052 +:10AF00000000000000000000000000000000000041 +:10AF10000000000000000000000000000000000031 +:10AF20000000000000000000000000000000000021 +:10AF30000000000000000000000000000000000011 +:10AF40000000000000000000000000000000000001 +:10AF500000000000000000000000000000000000F1 +:10AF600000000000000000000000000000000000E1 +:10AF700000000000000000000000000000000000D1 +:10AF800000000000000000000000000000000000C1 +:10AF900000000000000000000000000000000000B1 +:10AFA00000000000000000000000000000000000A1 +:10AFB0000000000000000000000000000000000091 +:10AFC0000000000000000000000000000000000081 +:10AFD0000000000000000000000000000000000071 +:10AFE0000000000000000000000000000000000061 +:10AFF0000000000000000000000000000000000051 +:10B000000000000000000000000000000000000040 +:10B010000000000000000000000000000000000030 +:10B020000000000000000000000000000000000020 +:10B030000000000000000000000000000000000010 +:10B040000000000000000000000000000000000000 +:10B0500000000000000000000000000000000000F0 +:10B0600000000000000000000000000000000000E0 +:10B0700000000000000000000000000000000000D0 +:10B0800000000000000000000000000000000000C0 +:10B0900000000000000000000000000000000000B0 +:10B0A00000000000000000000000000000000000A0 +:10B0B0000000000000000000000000000000000090 +:10B0C0000000000000000000000000000000000080 +:10B0D0000000000000000000000000000000000070 +:10B0E0000000000000000000000000000000000060 +:10B0F0000000000000000000000000000000000050 +:10B10000000000000000000000000000000000003F +:10B11000000000000000000000000000000000002F +:10B12000000000000000000000000000000000001F +:10B13000000000000000000000000000000000000F +:10B1400000000000000000000000000000000000FF +:10B1500000000000000000000000000000000000EF +:10B1600000000000000000000000000000000000DF +:10B1700000000000000000000000000000000000CF +:10B1800000000000000000000000000000000000BF +:10B1900000000000000000000000000000000000AF +:10B1A000000000000000000000000000000000009F +:10B1B000000000000000000000000000000000008F +:10B1C000000000000000000000000000000000007F +:10B1D000000000000000000000000000000000006F +:10B1E000000000000000000000000000000000005F +:10B1F000000000000000000000000000000000004F +:10B20000000000000000000000000000000000003E +:10B21000000000000000000000000000000000002E +:10B22000000000000000000000000000000000001E +:10B23000000000000000000000000000000000000E +:10B2400000000000000000000000000000000000FE +:10B2500000000000000000000000000000000000EE +:10B2600000000000000000000000000000000000DE +:10B2700000000000000000000000000000000000CE +:10B2800000000000000000000000000000000000BE +:10B2900000000000000000000000000000000000AE +:10B2A000000000000000000000000000000000009E +:10B2B000000000000000000000000000000000008E +:10B2C000000000000000000000000000000000007E +:10B2D000000000000000000000000000000000006E +:10B2E000000000000000000000000000000000005E +:10B2F000000000000000000000000000000000004E +:10B30000000000000000000000000000000000003D +:10B31000000000000000000000000000000000002D +:10B32000000000000000000000000000000000001D +:10B33000000000000000000000000000000000000D +:10B3400000000000000000000000000000000000FD +:10B3500000000000000000000000000000000000ED +:10B3600000000000000000000000000000000000DD +:10B3700000000000000000000000000000000000CD +:10B3800000000000000000000000000000000000BD +:10B3900000000000000000000000000000000000AD +:10B3A000000000000000000000000000000000009D +:10B3B000000000000000000000000000000000008D +:10B3C000000000000000000000000000000000007D +:10B3D000000000000000000000000000000000006D +:10B3E000000000000000000000000000000000005D +:10B3F000000000000000000000000000000000004D +:10B40000000000000000000000000000000000003C +:10B41000000000000000000000000000000000002C +:10B42000000000000000000000000000000000001C +:10B43000000000000000000000000000000000000C +:10B4400000000000000000000000000000000000FC +:10B4500000000000000000000000000000000000EC +:10B4600000000000000000000000000000000000DC +:10B4700000000000000000000000000000000000CC +:10B4800000000000000000000000000000000000BC +:10B4900000000000000000000000000000000000AC +:10B4A000000000000000000000000000000000009C +:10B4B000000000000000000000000000000000008C +:10B4C000000000000000000000000000000000007C +:10B4D000000000000000000000000000000000006C +:10B4E000000000000000000000000000000000005C +:10B4F000000000000000000000000000000000004C +:10B50000000000000000000000000000000000003B +:10B51000000000000000000000000000000000002B +:10B52000000000000000000000000000000000001B +:10B53000000000000000000000000000000000000B +:10B5400000000000000000000000000000000000FB +:10B5500000000000000000000000000000000000EB +:10B5600000000000000000000000000000000000DB +:10B5700000000000000000000000000000000000CB +:10B5800000000000000000000000000000000000BB +:10B5900000000000000000000000000000000000AB +:10B5A000000000000000000000000000000000009B +:10B5B000000000000000000000000000000000008B +:10B5C000000000000000000000000000000000007B +:10B5D000000000000000000000000000000000006B +:10B5E000000000000000000000000000000000005B +:10B5F000000000000000000000000000000000004B +:10B60000000000000000000000000000000000003A +:10B61000000000000000000000000000000000002A +:10B62000000000000000000000000000000000001A +:10B63000000000000000000000000000000000000A +:10B6400000000000000000000000000000000000FA +:10B6500000000000000000000000000000000000EA +:10B6600000000000000000000000000000000000DA +:10B6700000000000000000000000000000000000CA +:10B6800000000000000000000000000000000000BA +:10B6900000000000000000000000000000000000AA +:10B6A000000000000000000000000000000000009A +:10B6B000000000000000000000000000000000008A +:10B6C000000000000000000000000000000000007A +:10B6D000000000000000000000000000000000006A +:10B6E000000000000000000000000000000000005A +:10B6F000000000000000000000000000000000004A +:10B700000000000000000000000000000000000039 +:10B710000000000000000000000000000000000029 +:10B720000000000000000000000000000000000019 +:10B730000000000000000000000000000000000009 +:10B7400000000000000000000000000000000000F9 +:10B7500000000000000000000000000000000000E9 +:10B7600000000000000000000000000000000000D9 +:10B7700000000000000000000000000000000000C9 +:10B7800000000000000000000000000000000000B9 +:10B7900000000000000000000000000000000000A9 +:10B7A0000000000000000000000000000000000099 +:10B7B0000000000000000000000000000000000089 +:10B7C0000000000000000000000000000000000079 +:10B7D0000000000000000000000000000000000069 +:10B7E0000000000000000000000000000000000059 +:10B7F0000000000000000000000000000000000049 +:10B800000000000000000000000000000000000038 +:10B810000000000000000000000000000000000028 +:10B820000000000000000000000000000000000018 +:10B830000000000000000000000000000000000008 +:10B8400000000000000000000000000000000000F8 +:10B8500000000000000000000000000000000000E8 +:10B8600000000000000000000000000000000000D8 +:10B8700000000000000000000000000000000000C8 +:10B8800000000000000000000000000000000000B8 +:10B8900000000000000000000000000000000000A8 +:10B8A0000000000000000000000000000000000098 +:10B8B0000000000000000000000000000000000088 +:10B8C0000000000000000000000000000000000078 +:10B8D0000000000000000000000000000000000068 +:10B8E0000000000000000000000000000000000058 +:10B8F0000000000000000000000000000000000048 +:10B900000000000000000000000000000000000037 +:10B910000000000000000000000000000000000027 +:10B920000000000000000000000000000000000017 +:10B930000000000000000000000000000000000007 +:10B9400000000000000000000000000000000000F7 +:10B9500000000000000000000000000000000000E7 +:10B9600000000000000000000000000000000000D7 +:10B9700000000000000000000000000000000000C7 +:10B9800000000000000000000000000000000000B7 +:10B9900000000000000000000000000000000000A7 +:10B9A0000000000000000000000000000000000097 +:10B9B0000000000000000000000000000000000087 +:10B9C0000000000000000000000000000000000077 +:10B9D0000000000000000000000000000000000067 +:10B9E0000000000000000000000000000000000057 +:10B9F0000000000000000000000000000000000047 +:10BA00000000000000000000000000000000000036 +:10BA10000000000000000000000000000000000026 +:10BA20000000000000000000000000000000000016 +:10BA30000000000000000000000000000000000006 +:10BA400000000000000000000000000000000000F6 +:10BA500000000000000000000000000000000000E6 +:10BA600000000000000000000000000000000000D6 +:10BA700000000000000000000000000000000000C6 +:10BA800000000000000000000000000000000000B6 +:10BA900000000000000000000000000000000000A6 +:10BAA0000000000000000000000000000000000096 +:10BAB0000000000000000000000000000000000086 +:10BAC0000000000000000000000000000000000076 +:10BAD0000000000000000000000000000000000066 +:10BAE0000000000000000000000000000000000056 +:10BAF0000000000000000000000000000000000046 +:10BB00000000000000000000000000000000000035 +:10BB10000000000000000000000000000000000025 +:10BB20000000000000000000000000000000000015 +:10BB30000000000000000000000000000000000005 +:10BB400000000000000000000000000000000000F5 +:10BB500000000000000000000000000000000000E5 +:10BB600000000000000000000000000000000000D5 +:10BB700000000000000000000000000000000000C5 +:10BB800000000000000000000000000000000000B5 +:10BB900000000000000000000000000000000000A5 +:10BBA0000000000000000000000000000000000095 +:10BBB0000000000000000000000000000000000085 +:10BBC0000000000000000000000000000000000075 +:10BBD0000000000000000000000000000000000065 +:10BBE0000000000000000000000000000000000055 +:10BBF0000000000000000000000000000000000045 +:10BC00000000000000000000000000000000000034 +:10BC10000000000000000000000000000000000024 +:10BC20000000000000000000000000000000000014 +:10BC30000000000000000000000000000000000004 +:10BC400000000000000000000000000000000000F4 +:10BC500000000000000000000000000000000000E4 +:10BC600000000000000000000000000000000000D4 +:10BC700000000000000000000000000000000000C4 +:10BC800000000000000000000000000000000000B4 +:10BC900000000000000000000000000000000000A4 +:10BCA0000000000000000000000000000000000094 +:10BCB0000000000000000000000000000000000084 +:10BCC0000000000000000000000000000000000074 +:10BCD0000000000000000000000000000000000064 +:10BCE0000000000000000000000000000000000054 +:10BCF0000000000000000000000000000000000044 +:10BD00000000000000000000000000000000000033 +:10BD10000000000000000000000000000000000023 +:10BD20000000000000000000000000000000000013 +:10BD30000000000000000000000000000000000003 +:10BD400000000000000000000000000000000000F3 +:10BD500000000000000000000000000000000000E3 +:10BD600000000000000000000000000000000000D3 +:10BD700000000000000000000000000000000000C3 +:10BD800000000000000000000000000000000000B3 +:10BD900000000000000000000000000000000000A3 +:10BDA0000000000000000000000000000000000093 +:10BDB0000000000000000000000000000000000083 +:10BDC0000000000000000000000000000000000073 +:10BDD0000000000000000000000000000000000063 +:10BDE0000000000000000000000000000000000053 +:10BDF0000000000000000000000000000000000043 +:10BE00000000000000000000000000000000000032 +:10BE10000000000000000000000000000000000022 +:10BE20000000000000000000000000000000000012 +:10BE30000000000000000000000000000000000002 +:10BE400000000000000000000000000000000000F2 +:10BE500000000000000000000000000000000000E2 +:10BE600000000000000000000000000000000000D2 +:10BE700000000000000000000000000000000000C2 +:10BE800000000000000000000000000000000000B2 +:10BE900000000000000000000000000000000000A2 +:10BEA0000000000000000000000000000000000092 +:10BEB0000000000000000000000000000000000082 +:10BEC0000000000000000000000000000000000072 +:10BED0000000000000000000000000000000000062 +:10BEE0000000000000000000000000000000000052 +:10BEF0000000000000000000000000000000000042 +:10BF00000000000000000000000000000000000031 +:10BF10000000000000000000000000000000000021 +:10BF20000000000000000000000000000000000011 +:10BF30000000000000000000000000000000000001 +:10BF400000000000000000000000000000000000F1 +:10BF500000000000000000000000000000000000E1 +:10BF600000000000000000000000000000000000D1 +:10BF700000000000000000000000000000000000C1 +:10BF800000000000000000000000000000000000B1 +:10BF900000000000000000000000000000000000A1 +:10BFA0000000000000000000000000000000000091 +:10BFB0000000000000000000000000000000000081 +:10BFC0000000000000000000000000000000000071 +:10BFD0000000000000000000000000000000000061 +:10BFE0000000000000000000000000000000000051 +:10BFF0000000000000000000000000000000000041 +:10C000000000000000000000000000000000000030 +:10C010000000000000000000000000000000000020 +:10C020000000000000000000000000000000000010 +:10C030000000000000000000000000000000000000 +:10C0400000000000000000000000000000000000F0 +:10C0500000000000000000000000000000000000E0 +:10C0600000000000000000000000000000000000D0 +:10C0700000000000000000000000000000000000C0 +:10C0800000000000000000000000000000000000B0 +:10C0900000000000000000000000000000000000A0 +:10C0A0000000000000000000000000000000000090 +:10C0B0000000000000000000000000000000000080 +:10C0C0000000000000000000000000000000000070 +:10C0D0000000000000000000000000000000000060 +:10C0E0000000000000000000000000000000000050 +:10C0F0000000000000000000000000000000000040 +:10C10000000000000000000000000000000000002F +:10C11000000000000000000000000000000000001F +:10C12000000000000000000000000000000000000F +:10C1300000000000000000000000000000000000FF +:10C1400000000000000000000000000000000000EF +:10C1500000000000000000000000000000000000DF +:10C1600000000000000000000000000000000000CF +:10C1700000000000000000000000000000000000BF +:10C1800000000000000000000000000000000000AF +:10C19000000000000000000000000000000000009F +:10C1A000000000000000000000000000000000008F +:10C1B000000000000000000000000000000000007F +:10C1C000000000000000000000000000000000006F +:10C1D000000000000000000000000000000000005F +:10C1E000000000000000000000000000000000004F +:10C1F000000000000000000000000000000000003F +:10C20000000000000000000000000000000000002E +:10C21000000000000000000000000000000000001E +:10C22000000000000000000000000000000000000E +:10C2300000000000000000000000000000000000FE +:10C2400000000000000000000000000000000000EE +:10C2500000000000000000000000000000000000DE +:10C2600000000000000000000000000000000000CE +:10C2700000000000000000000000000000000000BE +:10C2800000000000000000000000000000000000AE +:10C29000000000000000000000000000000000009E +:10C2A000000000000000000000000000000000008E +:10C2B000000000000000000000000000000000007E +:10C2C000000000000000000000000000000000006E +:10C2D000000000000000000000000000000000005E +:10C2E000000000000000000000000000000000004E +:10C2F000000000000000000000000000000000003E +:10C30000000000000000000000000000000000002D +:10C31000000000000000000000000000000000001D +:10C32000000000000000000000000000000000000D +:10C3300000000000000000000000000000000000FD +:10C3400000000000000000000000000000000000ED +:10C3500000000000000000000000000000000000DD +:10C3600000000000000000000000000000000000CD +:10C3700000000000000000000000000000000000BD +:10C3800000000000000000000000000000000000AD +:10C39000000000000000000000000000000000009D +:10C3A000000000000000000000000000000000008D +:10C3B000000000000000000000000000000000007D +:10C3C000000000000000000000000000000000006D +:10C3D000000000000000000000000000000000005D +:10C3E000000000000000000000000000000000004D +:10C3F000000000000000000000000000000000003D +:10C40000000000000000000000000000000000002C +:10C41000000000000000000000000000000000001C +:10C42000000000000000000000000000000000000C +:10C4300000000000000000000000000000000000FC +:10C4400000000000000000000000000000000000EC +:10C4500000000000000000000000000000000000DC +:10C4600000000000000000000000000000000000CC +:10C4700000000000000000000000000000000000BC +:10C4800000000000000000000000000000000000AC +:10C49000000000000000000000000000000000009C +:10C4A000000000000000000000000000000000008C +:10C4B000000000000000000000000000000000007C +:10C4C000000000000000000000000000000000006C +:10C4D000000000000000000000000000000000005C +:10C4E000000000000000000000000000000000004C +:10C4F000000000000000000000000000000000003C +:10C50000000000000000000000000000000000002B +:10C51000000000000000000000000000000000001B +:10C52000000000000000000000000000000000000B +:10C5300000000000000000000000000000000000FB +:10C5400000000000000000000000000000000000EB +:10C5500000000000000000000000000000000000DB +:10C5600000000000000000000000000000000000CB +:10C5700000000000000000000000000000000000BB +:10C5800000000000000000000000000000000000AB +:10C59000000000000000000000000000000000009B +:10C5A000000000000000000000000000000000008B +:10C5B000000000000000000000000000000000007B +:10C5C000000000000000000000000000000000006B +:10C5D000000000000000000000000000000000005B +:10C5E000000000000000000000000000000000004B +:10C5F000000000000000000000000000000000003B +:10C60000000000000000000000000000000000002A +:10C61000000000000000000000000000000000001A +:10C62000000000000000000000000000000000000A +:10C6300000000000000000000000000000000000FA +:10C6400000000000000000000000000000000000EA +:10C6500000000000000000000000000000000000DA +:10C6600000000000000000000000000000000000CA +:10C6700000000000000000000000000000000000BA +:10C6800000000000000000000000000000000000AA +:10C69000000000000000000000000000000000009A +:10C6A000000000000000000000000000000000008A +:10C6B000000000000000000000000000000000007A +:10C6C000000000000000000000000000000000006A +:10C6D000000000000000000000000000000000005A +:10C6E000000000000000000000000000000000004A +:10C6F000000000000000000000000000000000003A +:10C700000000000000000000000000000000000029 +:10C710000000000000000000000000000000000019 +:10C720000000000000000000000000000000000009 +:10C7300000000000000000000000000000000000F9 +:10C7400000000000000000000000000000000000E9 +:10C7500000000000000000000000000000000000D9 +:10C7600000000000000000000000000000000000C9 +:10C7700000000000000000000000000000000000B9 +:10C7800000000000000000000000000000000000A9 +:10C790000000000000000000000000000000000099 +:10C7A0000000000000000000000000000000000089 +:10C7B0000000000000000000000000000000000079 +:10C7C0000000000000000000000000000000000069 +:10C7D0000000000000000000000000000000000059 +:10C7E0000000000000000000000000000000000049 +:10C7F0000000000000000000000000000000000039 +:10C800000000000000000000000000000000000028 +:10C810000000000000000000000000000000000018 +:10C820000000000000000000000000000000000008 +:10C8300000000000000000000000000000000000F8 +:10C8400000000000000000000000000000000000E8 +:10C8500000000000000000000000000000000000D8 +:10C8600000000000000000000000000000000000C8 +:10C8700000000000000000000000000000000000B8 +:10C8800000000000000000000000000000000000A8 +:10C890000000000000000000000000000000000098 +:10C8A0000000000000000000000000000000000088 +:10C8B0000000000000000000000000000000000078 +:10C8C0000000000000000000000000000000000068 +:10C8D0000000000000000000000000000000000058 +:10C8E0000000000000000000000000000000000048 +:10C8F0000000000000000000000000000000000038 +:10C900000000000000000000000000000000000027 +:10C910000000000000000000000000000000000017 +:10C920000000000000000000000000000000000007 +:10C9300000000000000000000000000000000000F7 +:10C9400000000000000000000000000000000000E7 +:10C9500000000000000000000000000000000000D7 +:10C9600000000000000000000000000000000000C7 +:10C9700000000000000000000000000000000000B7 +:10C9800000000000000000000000000000000000A7 +:10C990000000000000000000000000000000000097 +:10C9A0000000000000000000000000000000000087 +:10C9B0000000000000000000000000000000000077 +:10C9C0000000000000000000000000000000000067 +:10C9D0000000000000000000000000000000000057 +:10C9E0000000000000000000000000000000000047 +:10C9F0000000000000000000000000000000000037 +:10CA00000000000000000000000000000000000026 +:10CA10000000000000000000000000000000000016 +:10CA20000000000000000000000000000000000006 +:10CA300000000000000000000000000000000000F6 +:10CA400000000000000000000000000000000000E6 +:10CA500000000000000000000000000000000000D6 +:10CA600000000000000000000000000000000000C6 +:10CA700000000000000000000000000000000000B6 +:10CA800000000000000000000000000000000000A6 +:10CA90000000000000000000000000000000000096 +:10CAA0000000000000000000000000000000000086 +:10CAB0000000000000000000000000000000000076 +:10CAC0000000000000000000000000000000000066 +:10CAD0000000000000000000000000000000000056 +:10CAE0000000000000000000000000000000000046 +:10CAF0000000000000000000000000000000000036 +:10CB00000000000000000000000000000000000025 +:10CB10000000000000000000000000000000000015 +:10CB20000000000000000000000000000000000005 +:10CB300000000000000000000000000000000000F5 +:10CB400000000000000000000000000000000000E5 +:10CB500000000000000000000000000000000000D5 +:10CB600000000000000000000000000000000000C5 +:10CB700000000000000000000000000000000000B5 +:10CB800000000000000000000000000000000000A5 +:10CB90000000000000000000000000000000000095 +:10CBA0000000000000000000000000000000000085 +:10CBB0000000000000000000000000000000000075 +:10CBC0000000000000000000000000000000000065 +:10CBD0000000000000000000000000000000000055 +:10CBE0000000000000000000000000000000000045 +:10CBF0000000000000000000000000000000000035 +:10CC00000000000000000000000000000000000024 +:10CC10000000000000000000000000000000000014 +:10CC20000000000000000000000000000000000004 +:10CC300000000000000000000000000000000000F4 +:10CC400000000000000000000000000000000000E4 +:10CC500000000000000000000000000000000000D4 +:10CC600000000000000000000000000000000000C4 +:10CC700000000000000000000000000000000000B4 +:10CC800000000000000000000000000000000000A4 +:10CC90000000000000000000000000000000000094 +:10CCA0000000000000000000000000000000000084 +:10CCB0000000000000000000000000000000000074 +:10CCC0000000000000000000000000000000000064 +:10CCD0000000000000000000000000000000000054 +:10CCE0000000000000000000000000000000000044 +:10CCF0000000000000000000000000000000000034 +:10CD00000000000000000000000000000000000023 +:10CD10000000000000000000000000000000000013 +:10CD20000000000000000000000000000000000003 +:10CD300000000000000000000000000000000000F3 +:10CD400000000000000000000000000000000000E3 +:10CD500000000000000000000000000000000000D3 +:10CD600000000000000000000000000000000000C3 +:10CD700000000000000000000000000000000000B3 +:10CD800000000000000000000000000000000000A3 +:10CD90000000000000000000000000000000000093 +:10CDA0000000000000000000000000000000000083 +:10CDB0000000000000000000000000000000000073 +:10CDC0000000000000000000000000000000000063 +:10CDD0000000000000000000000000000000000053 +:10CDE0000000000000000000000000000000000043 +:10CDF0000000000000000000000000000000000033 +:10CE00000000000000000000000000000000000022 +:10CE10000000000000000000000000000000000012 +:10CE20000000000000000000000000000000000002 +:10CE300000000000000000000000000000000000F2 +:10CE400000000000000000000000000000000000E2 +:10CE500000000000000000000000000000000000D2 +:10CE600000000000000000000000000000000000C2 +:10CE700000000000000000000000000000000000B2 +:10CE800000000000000000000000000000000000A2 +:10CE90000000000000000000000000000000000092 +:10CEA0000000000000000000000000000000000082 +:10CEB0000000000000000000000000000000000072 +:10CEC0000000000000000000000000000000000062 +:10CED0000000000000000000000000000000000052 +:10CEE0000000000000000000000000000000000042 +:10CEF0000000000000000000000000000000000032 +:10CF00000000000000000000000000000000000021 +:10CF10000000000000000000000000000000000011 +:10CF20000000000000000000000000000000000001 +:10CF300000000000000000000000000000000000F1 +:10CF400000000000000000000000000000000000E1 +:10CF500000000000000000000000000000000000D1 +:10CF600000000000000000000000000000000000C1 +:10CF700000000000000000000000000000000000B1 +:10CF800000000000000000000000000000000000A1 +:10CF90000000000000000000000000000000000091 +:10CFA0000000000000000000000000000000000081 +:10CFB0000000000000000000000000000000000071 +:10CFC0000000000000000000000000000000000061 +:10CFD0000000000000000000000000000000000051 +:10CFE0000000000000000000000000000000000041 +:10CFF0000000000000000000000000000000000031 +:10D000000000000000000000000000000000000020 +:10D010000000000000000000000000000000000010 +:10D020000000000000000000000000000000000000 +:10D0300000000000000000000000000000000000F0 +:10D0400000000000000000000000000000000000E0 +:10D0500000000000000000000000000000000000D0 +:10D0600000000000000000000000000000000000C0 +:10D0700000000000000000000000000000000000B0 +:10D0800000000000000000000000000000000000A0 +:10D090000000000000000000000000000000000090 +:10D0A0000000000000000000000000000000000080 +:10D0B0000000000000000000000000000000000070 +:10D0C0000000000000000000000000000000000060 +:10D0D0000000000000000000000000000000000050 +:10D0E0000000000000000000000000000000000040 +:10D0F0000000000000000000000000000000000030 +:10D10000000000000000000000000000000000001F +:10D11000000000000000000000000000000000000F +:10D1200000000000000000000000000000000000FF +:10D1300000000000000000000000000000000000EF +:10D1400000000000000000000000000000000000DF +:10D1500000000000000000000000000000000000CF +:10D1600000000000000000000000000000000000BF +:10D1700000000000000000000000000000000000AF +:10D18000000000000000000000000000000000009F +:10D19000000000000000000000000000000000008F +:10D1A000000000000000000000000000000000007F +:10D1B000000000000000000000000000000000006F +:10D1C000000000000000000000000000000000005F +:10D1D000000000000000000000000000000000004F +:10D1E000000000000000000000000000000000003F +:10D1F000000000000000000000000000000000002F +:10D20000000000000000000000000000000000001E +:10D21000000000000000000000000000000000000E +:10D2200000000000000000000000000000000000FE +:10D2300000000000000000000000000000000000EE +:10D2400000000000000000000000000000000000DE +:10D2500000000000000000000000000000000000CE +:10D2600000000000000000000000000000000000BE +:10D2700000000000000000000000000000000000AE +:10D28000000000000000000000000000000000009E +:10D29000000000000000000000000000000000008E +:10D2A000000000000000000000000000000000007E +:10D2B000000000000000000000000000000000006E +:10D2C000000000000000000000000000000000005E +:10D2D000000000000000000000000000000000004E +:10D2E000000000000000000000000000000000003E +:10D2F000000000000000000000000000000000002E +:10D30000000000000000000000000000000000001D +:10D31000000000000000000000000000000000000D +:10D3200000000000000000000000000000000000FD +:10D3300000000000000000000000000000000000ED +:10D3400000000000000000000000000000000000DD +:10D3500000000000000000000000000000000000CD +:10D3600000000000000000000000000000000000BD +:10D3700000000000000000000000000000000000AD +:10D38000000000000000000000000000000000009D +:10D39000000000000000000000000000000000008D +:10D3A000000000000000000000000000000000007D +:10D3B000000000000000000000000000000000006D +:10D3C000000000000000000000000000000000005D +:10D3D000000000000000000000000000000000004D +:10D3E000000000000000000000000000000000003D +:10D3F000000000000000000000000000000000002D +:10D40000000000000000000000000000000000001C +:10D41000000000000000000000000000000000000C +:10D4200000000000000000000000000000000000FC +:10D4300000000000000000000000000000000000EC +:10D4400000000000000000000000000000000000DC +:10D4500000000000000000000000000000000000CC +:10D4600000000000000000000000000000000000BC +:10D4700000000000000000000000000000000000AC +:10D48000000000000000000000000000000000009C +:10D49000000000000000000000000000000000008C +:10D4A000000000000000000000000000000000007C +:10D4B000000000000000000000000000000000006C +:10D4C000000000000000000000000000000000005C +:10D4D000000000000000000000000000000000004C +:10D4E000000000000000000000000000000000003C +:10D4F000000000000000000000000000000000002C +:10D50000000000000000000000000000000000001B +:10D51000000000000000000000000000000000000B +:10D5200000000000000000000000000000000000FB +:10D5300000000000000000000000000000000000EB +:10D5400000000000000000000000000000000000DB +:10D5500000000000000000000000000000000000CB +:10D5600000000000000000000000000000000000BB +:10D5700000000000000000000000000000000000AB +:10D58000000000000000000000000000000000009B +:10D59000000000000000000000000000000000008B +:10D5A000000000000000000000000000000000007B +:10D5B000000000000000000000000000000000006B +:10D5C000000000000000000000000000000000005B +:10D5D000000000000000000000000000000000004B +:10D5E000000000000000000000000000000000003B +:10D5F000000000000000000000000000000000002B +:10D60000000000000000000000000000000000001A +:10D61000000000000000000000000000000000000A +:10D6200000000000000000000000000000000000FA +:10D6300000000000000000000000000000000000EA +:10D6400000000000000000000000000000000000DA +:10D6500000000000000000000000000000000000CA +:10D6600000000000000000000000000000000000BA +:10D6700000000000000000000000000000000000AA +:10D68000000000000000000000000000000000009A +:10D69000000000000000000000000000000000008A +:10D6A000000000000000000000000000000000007A +:10D6B000000000000000000000000000000000006A +:10D6C000000000000000000000000000000000005A +:10D6D000000000000000000000000000000000004A +:10D6E000000000000000000000000000000000003A +:10D6F000000000000000000000000000000000002A +:10D700000000000000000000000000000000000019 +:10D710000000000000000000000000000000000009 +:10D7200000000000000000000000000000000000F9 +:10D7300000000000000000000000000000000000E9 +:10D7400000000000000000000000000000000000D9 +:10D7500000000000000000000000000000000000C9 +:10D7600000000000000000000000000000000000B9 +:10D7700000000000000000000000000000000000A9 +:10D780000000000000000000000000000000000099 +:10D790000000000000000000000000000000000089 +:10D7A0000000000000000000000000000000000079 +:10D7B0000000000000000000000000000000000069 +:10D7C0000000000000000000000000000000000059 +:10D7D0000000000000000000000000000000000049 +:10D7E0000000000000000000000000000000000039 +:10D7F0000000000000000000000000000000000029 +:10D800000000000000000000000000000000000018 +:10D810000000000000000000000000000000000008 +:10D8200000000000000000000000000000000000F8 +:10D8300000000000000000000000000000000000E8 +:10D8400000000000000000000000000000000000D8 +:10D8500000000000000000000000000000000000C8 +:10D8600000000000000000000000000000000000B8 +:10D8700000000000000000000000000000000000A8 +:10D880000000000000000000000000000000000098 +:10D890000000000000000000000000000000000088 +:10D8A0000000000000000000000000000000000078 +:10D8B0000000000000000000000000000000000068 +:10D8C0000000000000000000000000000000000058 +:10D8D0000000000000000000000000000000000048 +:10D8E0000000000000000000000000000000000038 +:10D8F0000000000000000000000000000000000028 +:10D900000000000000000000000000000000000017 +:10D910000000000000000000000000000000000007 +:10D9200000000000000000000000000000000000F7 +:10D9300000000000000000000000000000000000E7 +:10D9400000000000000000000000000000000000D7 +:10D9500000000000000000000000000000000000C7 +:10D9600000000000000000000000000000000000B7 +:10D9700000000000000000000000000000000000A7 +:10D980000000000000000000000000000000000097 +:10D990000000000000000000000000000000000087 +:10D9A0000000000000000000000000000000000077 +:10D9B0000000000000000000000000000000000067 +:10D9C0000000000000000000000000000000000057 +:10D9D0000000000000000000000000000000000047 +:10D9E0000000000000000000000000000000000037 +:10D9F0000000000000000000000000000000000027 +:10DA00000000000000000000000000000000000016 +:10DA10000000000000000000000000000000000006 +:10DA200000000000000000001000000300000000E3 +:10DA30000000000D0000000D3C020800244271406F +:10DA40003C030800246375E0AC4000000043202B39 +:10DA50001480FFFD244200043C1D080037BD7FFCFC +:10DA600003A0F0213C100800261031D83C1C08000F +:10DA7000279C71400E0010ED000000000000000D1A +:10DA800030A5FFFF30C600FF274301808F4201B859 +:10DA90000440FFFE24020002AC640000A4650008FC +:10DAA000A066000AA062000B3C021000AC670018E0 +:10DAB00003E00008AF4201B83C0360008C624FF8FD +:10DAC0000440FFFE3C020200AC644FC0AC624FC495 +:10DAD0003C02100003E00008AC624FF89482000C96 +:10DAE0002486001400A038210002130200021080D6 +:10DAF0000082402100C8102B104000570000000099 +:10DB000090C300002C6200095040005190C20001F7 +:10DB1000000310803C030800246370F000431021D0 +:10DB20008C420000004000080000000090C300018B +:10DB30002402000A1462003A0000000001061023CB +:10DB40002C42000A1440003624C600028CE2000079 +:10DB500034420100ACE2000090C2000090C300011A +:10DB600090C4000290C5000300031C0000021600D0 +:10DB70000043102500042200004410250045102514 +:10DB800024C60004ACE2000490C2000090C300016F +:10DB900090C4000290C500030002160000031C00A0 +:10DBA00000431025000422000044102500451025E4 +:10DBB00024C600040A000CAAACE2000890C30001CD +:10DBC000240200041462001624C6000290C2000061 +:10DBD00090C400018CE300000002120000441025F4 +:10DBE0003463000424C60002ACE2000C0A000CAA54 +:10DBF000ACE3000090C3000124020003146200089B +:10DC000024C600028CE2000090C3000024C600017C +:10DC100034420008A0E300100A000CAAACE20000A5 +:10DC200003E000082402000190C300012402000266 +:10DC30001062000224C40002010020210A000CAA84 +:10DC4000008030210A000CAA24C6000190C2000105 +:10DC50000A000CAA00C2302103E0000800001021D5 +:10DC600027BDFFE8AFBF0014AFB000100E0011FEDB +:10DC700000808021936200052403FFFE0200202122 +:10DC8000004310248FBF00148FB00010A362000562 +:10DC90000A00120727BD001827BDFFE8AFB000102B +:10DCA000AFBF00140E000F180080802193620000A7 +:10DCB00024030050304200FF1443000424020100FA +:10DCC000AF4201800A000D2202002021AF400180F6 +:10DCD000020020218FBF00148FB000100A000F79BE +:10DCE00027BD001827BDFF80AFBE0078AFB7007416 +:10DCF000AFB30064AFBF007CAFB60070AFB5006CCF +:10DD0000AFB40068AFB20060AFB1005CAFB0005814 +:10DD10008F5001289363003F936200050000F021BB +:10DD2000307300FF00021027304200010000B821CC +:10DD300014400066AFA000509342011693430112B5 +:10DD4000304200FF306300FF0342202103431021D3 +:10DD5000244540008F820018104000182491400094 +:10DD60008F4201043C0300010043102410400013C3 +:10DD7000000000008CA3000C8F620030146201B51B +:10DD8000240200018CA300108F62002C146201B1E8 +:10DD9000240200019762003A948340003042FFFF62 +:10DDA000146201AC2402000197620038962300023D +:10DDB0003042FFFF146201A72402000193620000B9 +:10DDC000304300FF240200201062000524020050AE +:10DDD00010620006000000000A000D6C0000000048 +:10DDE0000000000D0A000D75AFA000303C1E0800B9 +:10DDF00027DE71A00A000D75AFA000303C020800BC +:10DE00008C4200DC244200013C010800AC2200DC12 +:10DE10000E0012C8000000000A000F038FBF007C34 +:10DE20008F4201043C0300209234000D0043102473 +:10DE30000002202B00042140AFA400308F430104D6 +:10DE40003C02004000621824146000023487004045 +:10DE50000080382132820020AFA700301440000239 +:10DE600034E6008000E0302110C0000BAFA6003087 +:10DE700093C500088F67004C0200202100052B008D +:10DE800034A5008130A5F0810E000C8D30C600FF56 +:10DE90000A000F00000000009362003E3042004084 +:10DEA0001040000E240200045662000624020012F4 +:10DEB000020020210E0013D6022030210A000F0399 +:10DEC0008FBF007C16620005000000000E000D13DD +:10DED000000020210A000F038FBF007C9743011A26 +:10DEE0009624000E93620035328500043076FFFFE1 +:10DEF00000442004AFA400548E32000410A000158A +:10DF00008E3500089362003E30420040104000070A +:10DF1000000000000E001318024020211040000DE8 +:10DF2000000000000A000F00000000008F620044A3 +:10DF30000242102304400145000000008F620048A7 +:10DF40000242102304410141240400160A000E037A +:10DF50008FC200048F620048024210230440000870 +:10DF6000000000003C0208008C4231002442000105 +:10DF70003C010800AC2231000A000EF50000000050 +:10DF80008F62004002421023184000092402000C56 +:10DF90003C0208008C423100329400FC0000B021A9 +:10DFA000244200013C010800AC2231002402000C94 +:10DFB000AFA200308F620040005220231880000D75 +:10DFC00002C4102A14400116000000001496000636 +:10DFD00002C410233A8200013042000114400110B3 +:10DFE0000000000002C41023024490210A000DEB3F +:10DFF0003056FFFF00002021328200021040001A3C +:10E00000328200109362003E3042004050400011C6 +:10E010008FC200040E0011FE02002021240200180D +:10E02000A362003F936200052403FFFE020020214B +:10E03000004310240E001207A362000524040039D7 +:10E04000000028210E001301240600180A000F0208 +:10E0500024020001240400170040F8090000000019 +:10E060000A000F0224020001104000F80000000026 +:10E070008F63004C8F62005402A210231C4000F3F7 +:10E0800002A31023044200010060A821AFA40018DD +:10E09000AFB20010AFB60014934201208F6500406C +:10E0A0009763003C304200FF0342102100441021DE +:10E0B0008FA400543063FFFF244240000083182BDC +:10E0C0008FA40030AFA20020AFA500280083202538 +:10E0D000AFA40030AFA50024AFA0002CAFB5003432 +:10E0E0009362003E30420008504000118FC2000091 +:10E0F0000220202127A500380E000CA4AFA0003874 +:10E100005440000B8FC200008FA200383042010043 +:10E11000504000078FC200008FA3003C8F62006058 +:10E120000062102304430001AF6300608FC200004F +:10E130000040F80927A400108FA2003030420002EE +:10E1400054400001329400FE9362003E3042004091 +:10E15000104000378FA300148F62005416A2001ADB +:10E160003282000124020014126200102A6200159B +:10E1700010400006240200162402000C1262000760 +:10E18000328200010A000E5F0000000012620005EA +:10E19000328200010A000E5F000000000A000E5AE1 +:10E1A0002417000E0A000E5A241700100A000E5EF3 +:10E1B00024170012936200232403FFBD00431024A0 +:10E1C000A362002332820001104000198FA30014C3 +:10E1D0002402000C1262000E2A62000D104000069C +:10E1E0002402000E2402000A126200078FA20024FB +:10E1F0000A000E7724420001126200088FA2002458 +:10E200000A000E77244200010A000E752417000848 +:10E210002402000E16E20002241700162417001034 +:10E220008FA2002424420001AFA200248FA3001477 +:10E230008FA200248F73004000431021AF62004082 +:10E240008FA20054936400368F63004002A288219D +:10E250003402FFFF0082100400621821AF630048FF +:10E260008FA6003030C200081040000E00000000F1 +:10E270008F6200581622000430C600FF9742011A30 +:10E280005040000134C6001093C500088FA7003429 +:10E290000200202100052B0034A500800E000C8D0B +:10E2A00030A5F0808F620040005310231840001703 +:10E2B0008FA200183C0208008C42319830420010B6 +:10E2C0001040000924020001976200681440000613 +:10E2D00024020001A76200689742007A2442000AE3 +:10E2E0000A000EBBA7620012A76200120E0011FE08 +:10E2F000020020219362007D2403000102002021FE +:10E30000344200010A000EB9AFA300501840000AC1 +:10E31000000000000E0011FE020020219362007D2B +:10E320002403000102002021AFA300503442000466 +:10E330000E001207A362007D9362003E304200404F +:10E340001440000C328200011040000A000000005E +:10E350008F6300408FC2000424040018246300016E +:10E360000040F809AF6300408FA200300A000F029E +:10E37000304200048F62005810510010000000006D +:10E380008F620018024210231C4000082404000180 +:10E390008F62001816420009000000008F62001C06 +:10E3A00002A210230440000500000000AF710058D5 +:10E3B000AFA40050AF720018AF75001C12E0000B44 +:10E3C0008FA200500E0011FE02002021A377003F13 +:10E3D0000E0012070200202102E030212404003741 +:10E3E0000E001301000028218FA2005010400003EE +:10E3F000000000000E000C9B0200202112C000054E +:10E40000000018218FA2003030420004504000115B +:10E4100000601021240300010A000F020060102197 +:10E420000E0011FE020020219362007D02002021D7 +:10E43000344200040E001207A362007D0E000C9B04 +:10E44000020020210A000F0224020001AF40004414 +:10E45000240200018FBF007C8FBE00788FB700744C +:10E460008FB600708FB5006C8FB400688FB30064F6 +:10E470008FB200608FB1005C8FB0005803E00008DD +:10E4800027BD00808C8700048C86000000001021CE +:10E4900000E5382100E5282B00C2302100C53021DD +:10E4A000AC87000403E00008AC8600008F4201B88E +:10E4B0000440FFFE24020800AF4201B803E0000858 +:10E4C000000000003C0200080342282194A20048FA +:10E4D0003084FFFF1040001B2484001294A20048E7 +:10E4E0003042FFFF0044102A1040001724020003AE +:10E4F0002402001A93430120A342018B8F82000063 +:10E50000306300FF30424000104000092463FFFEEA +:10E5100094A200483042FFFF0043102B1440000536 +:10E520008F820004A74301940A000F3C344200018B +:10E530008F8200042403FFFE0043102403E0000840 +:10E54000AF8200042402000303E00008A342018B11 +:10E5500027BDFFE0AFB20018AFB10014AFB000109C +:10E56000AFBF001C30B1FFFF30D0FFFF30F2FFFF24 +:10E570008F4201B80440FFFE00000000AF4401805C +:10E58000AF4400200E000F1E020020218F830000E8 +:10E590008F840004A751018CA750018EA7430190DE +:10E5A0008F83000830828000AF4301A8A752018802 +:10E5B0001040000E8F82000493420116304200FC8E +:10E5C00024420004005A10218C4240003042FFFFD8 +:10E5D000144000068F8200043C02FFFF34427FFF9C +:10E5E00000821024AF8200048F8200042403BFFF46 +:10E5F00000431024A74201A69743010C8F42010457 +:10E6000000031C003042FFFF00621825AF4301AC3D +:10E610003C021000AF4201B88FBF001C8FB200183F +:10E620008FB100148FB0001003E0000827BD002058 +:10E630003C0208008C42003827BDFFC8AFB200285A +:10E64000AFBF0030AFB3002CAFB10024AFB000209B +:10E65000000090213C0E080025CE00381440000236 +:10E66000244DFFFF000068218F84000030824000AD +:10E670001040000A308280003C02002000821024FA +:10E6800050400006308280008F8200042403BFFFC8 +:10E69000008318240A000F9D344210001040000A25 +:10E6A0003C02002000821024104000078F820004EA +:10E6B0003C03FFFF34637FFF008318243442800053 +:10E6C000AF820004AF8300008F48007093420112B4 +:10E6D0008F860000304200FF0002288230C2010015 +:10E6E0001040004324A4000330C24000104000103A +:10E6F00030C2200000041080005A10218C434000DA +:10E7000024A4000400041080AFA30010005A1021BC +:10E710008C424000AFA2001493420116304200FC2C +:10E72000005A10218C4240000A000FC4AFA200180A +:10E730001040002F00041080005A10218C4340002C +:10E7400024A4000400041080AFA30010005A10217C +:10E750008C424000AFA00018AFA200148FA900188F +:10E760000000382100002021240C000827AB0010F5 +:10E770003C0A0800254A010001641021148C0003A2 +:10E7800000042A001120000A00000000904200004E +:10E79000248400012C83000C00A2102100021080B0 +:10E7A000004A10218C4200001460FFF300E238267A +:10E7B0003C0408008C8431048F4200702C830020BC +:10E7C00010600009004840233C030800246331081E +:10E7D000000410800043102124830001AC48000095 +:10E7E0003C010800AC2331040A000FEFAF8700089A +:10E7F0009743011E9742011C3063FFFF0002140083 +:10E8000000621825AF8300089742010C8F43400037 +:10E810003044FFFF3402FFFF1462000300000000D9 +:10E820000A000FFB241200208F42400030420100FA +:10E83000544000012412001030C210005040001457 +:10E840003652000130C200201440000B3C02100080 +:10E8500000C210245040000E365200013C030E004E +:10E860003C020DFF00C318243442FFFF0043102B6D +:10E8700050400007365200013C0208008C42002C38 +:10E88000244200013C010800AC22002C3652000555 +:10E890003C0508008CA5003454A000248F8400009F +:10E8A0008F82000C544000218F8400008F8200046E +:10E8B000304240005440001D8F8400003C021F0184 +:10E8C00000C288243C021000562200188F840000E9 +:10E8D00030820200144000158F8400009750010E12 +:10E8E000AF400180AF400020261000043210FFFF2F +:10E8F0000E000F1E020020218F8300042402BFFFA0 +:10E90000364400020062182424020002A742018C4F +:10E910008F820000A750018EA7440188A74301A65B +:10E92000A7420190AF5101B80A0010D93C02000182 +:10E93000008210241040000C3C0210003C02080031 +:10E940008C4200D89746010E240400802442000126 +:10E9500030C6FFFF240500023C010800AC2200D8AD +:10E960000A0010E324070003008210241040004531 +:10E97000000000003C0208008C4200301040000DF6 +:10E980008F820004304240001040000A3C030F0018 +:10E99000008318243C0201000043102B14400005A2 +:10E9A000000000009746010E364700020A0010E002 +:10E9B0002404008010A0000D308201001040000BE4 +:10E9C0003C020F00008210243C03020010430007A9 +:10E9D0008F820008004D1024004E10219042000448 +:10E9E000244200040A00108B000221C00000000035 +:10E9F0008F8600003C0508008CA500D0000616029A +:10EA00003050000F38A200012C4200012E03000CF0 +:10EA10000043102414400018001021C02602FFFCFF +:10EA20002C420004544000140000202138A20002AF +:10EA30002C42000100431024104000030006124243 +:10EA40000A00108B000020210010182B0043102416 +:10EA500050400009001021C09746010E00002021FF +:10EA60002405000224C6000430C6FFFF0E000F413B +:10EA70003247FFFB001021C09746010E0A0010E04C +:10EA8000364700028F4240003C1108008E310024BE +:10EA90003042010010400048322200010220802153 +:10EAA00010A00017325300043082010010400015FE +:10EAB000240200013C020F00008210243C030200EB +:10EAC0001043000F8F8200089746010E0240382144 +:10EAD000004D1024004E10219044000424C6000470 +:10EAE00030C6FFFF24840004000421C00E000F4143 +:10EAF000240500022402FFFE022280243252FFFB82 +:10EB00002402000116020007320200013242000412 +:10EB100050400001365200029746010E0A0010DFF5 +:10EB2000024038211040000A320200049746010ECC +:10EB3000024038210000202124C6000430C6FFFF17 +:10EB40000E000F41240500023252FFFB3202000486 +:10EB50001040000B8F820000304208001040000877 +:10EB6000000000009746010E0240382124040100F5 +:10EB700024C6000430C6FFFF0E000F41240500022A +:10EB8000166000188FBF0030274301808F4201B804 +:10EB90000440FFFE24022000A462000824020002B8 +:10EBA000A062000BA46000103C021000AF4201B84C +:10EBB0000A0010E68FBF00301040000A8FBF0030FF +:10EBC0009746010E364700020000202124C60004AB +:10EBD00030C6FFFF240500020E000F4100000000B8 +:10EBE0008FBF00308FB3002C8FB200288FB100246C +:10EBF0008FB000200000102103E0000827BD00387E +:10EC000027BDFFE8AFB000103C04600CAFBF00149C +:10EC10008C8250002403FF7F3C1A800000431024A4 +:10EC20003442380CAC825000240200033C106000D7 +:10EC3000AF4200088E0208083C1B80083C01080017 +:10EC4000AC2000203042FFF0384200102C4200017E +:10EC50000E001B35AF8200183C04FFFF3C0204008D +:10EC6000348308063442000CAE021948AE03194C36 +:10EC70003C0560168E0219808CA30000344202000D +:10EC800000641824AE0219803C025353146200033E +:10EC900034A47C008CA20004005020218C82007CD3 +:10ECA0008C830078AF820014AF8300103C02800098 +:10ECB000344200708C43000000403821AF83001CB8 +:10ECC000006030218CE800003C0508008CA500FCA9 +:10ECD0003C0408008C8400F8010630230000102159 +:10ECE00000A6282100A6302B0082202100862021AA +:10ECF0003C010800AC2500FC3C010800AC2400F8F5 +:10ED00008F500000320200031040FFEE010030215E +:10ED10008CE600003C0508008CA500FC3C040800C3 +:10ED20008C8400F800C8302300A6282100001021A0 +:10ED300000A6302B0082202100862021320700010E +:10ED40003C010800AC2500FCAF88001C3C01080019 +:10ED5000AC2400F810E00064320200028F42012867 +:10ED6000AF4200208F4201048F430100AF820000B8 +:10ED70000E000F18AF8300048F4340003402FFFFE2 +:10ED800014620006000000009745010E3C040800D4 +:10ED9000248400F00A00115B000000008F42400054 +:10EDA000304201001040000B000000009745010EAA +:10EDB0003C040800248400E80E000F0E30A5FFFF7D +:10EDC0009745010E3C040800248431C80A001172E2 +:10EDD000000000008F4340008F8200101462000A80 +:10EDE000000000008F4340048F820014146200066C +:10EDF000000000009745010E3C040800248431B84F +:10EE00000A001172000000009745010E3C04080042 +:10EE1000248400E00E000F0E30A5FFFF3C02080026 +:10EE20008C4200C0104000088F8400003C020800A3 +:10EE30008C4200C4244200013C010800AC2200C402 +:10EE40000A00119F000000003C0200100082102404 +:10EE50001440000A8F8300043C0208008C4200200A +:10EE6000244200013C010800AC2200200E000F7972 +:10EE7000000020210A00119D000000002402BFFFB5 +:10EE8000006210241040000800000000240287FFE8 +:10EE900000621024144000083C020060008210242C +:10EEA00010400005000000000E000D2600000000CC +:10EEB0000A00119D000000000E0011E80000000093 +:10EEC000104000063C0240008F4301243C026020B9 +:10EED000AC430014000000003C024000AF42013887 +:10EEE00000000000320200021040FF713C0280006E +:10EEF0008F4201403C044000AF4200208F43014854 +:10EF00003C027000006218241064002D0000000014 +:10EF10000083102B144000063C0260003C022000DD +:10EF2000106200073C0240000A0011E400000000EB +:10EF300010620027000000000A0011E43C024000BB +:10EF40008F4201482403000400021402304200FFF3 +:10EF50001443000B274401808F4301408F4201B8C6 +:10EF60000440FFFE2402001CAC830000A082000BC2 +:10EF70003C021000AF4201B80A0011E43C0240001C +:10EF80008F4201B80440FFFE000000008F4201489C +:10EF900000021402A482000824020002A082000BD6 +:10EFA0008F420148A48200108F420144AC820024A9 +:10EFB0003C021000AF4201B80A0011E43C024000DC +:10EFC0000E00120C000000000A0011E43C02400098 +:10EFD0000E001B42000000003C024000AF420178DE +:10EFE000000000000A0011193C0280008F4201005D +:10EFF0003042003E1440001124020001AF4000489E +:10F000008F420100304207C01040000500000000A0 +:10F01000AF40004CAF40005003E000082402000164 +:10F02000AF400054AF4000408F42010030423800F2 +:10F0300054400001AF4000442402000103E00008F6 +:10F04000000000003C0290003442000100822025B4 +:10F05000AF4400208F4200200440FFFE000000006B +:10F0600003E00008000000003C0280003442000180 +:10F070000082202503E00008AF44002027BDFFE008 +:10F08000AFB20018AFBF001CAFB10014AFB000109A +:10F090008F5001408F5101483C02800000119402C2 +:10F0A00002222024324300FF2402000E1062008A54 +:10F0B0002862000F10400012286200372402000668 +:10F0C0001062003B2862000710400007240200097C +:10F0D0001060001A240200011062002500000000E8 +:10F0E0000A0012C1000000001062007B2402000B25 +:10F0F0001062005B3222FFFF0A0012C10000000014 +:10F1000010400008240200382862003510400080BA +:10F110002402001F1062007E000000000A0012C1DD +:10F12000000000001062007A240200801062004299 +:10F13000000000000A0012C1000000008F4201B868 +:10F140000440FFFE24020001AF500180AF40018463 +:10F15000A7520188A342018A24020002A342018B24 +:10F16000A75101908F4201440A0012BCAF4201A492 +:10F170001080000A240200023C010800A0227190C5 +:10F180003C010800AC3071988F4201443C010800FA +:10F19000AC2271940A0012C38FBF001C8F4201B8C9 +:10F1A0000440FFFE240200020A0012A60000000034 +:10F1B0008F4201B80440FFFE00000000AF50018004 +:10F1C0003C0208009042719010400003000018219A +:10F1D0003C0308008C637198AF430184A7520188F7 +:10F1E0003C02080090427190000018213442000156 +:10F1F000A342018A24020002A342018BA75101907D +:10F200008F420144AF4201A43C0208009042719039 +:10F21000104000033C0210003C0308008C63719412 +:10F22000AF4301A8AF4201B83C010800A020719093 +:10F230000A0012C38FBF001C8F4201B80440FFFEBA +:10F2400024020002A342018BA7520188A75101901A +:10F250008F420144A74201920A0012BE3C021000F4 +:10F260001440001D000000009362000530420004BD +:10F2700014400037000000000E0011FE02002021A3 +:10F280009362000502002021344200040E001207A0 +:10F29000A36200059362000530420004144000029E +:10F2A000000000000000000D936200002403002015 +:10F2B000304200FF14430008000000008F4201B8F4 +:10F2C0000440FFFE24020005AF500180A342018BE1 +:10F2D0003C021000AF4201B88F4201B80440FFFE6B +:10F2E00024020002AF400180AF500184A752018880 +:10F2F000A342018AA342018BA7510190AF4001A410 +:10F300008F420144AF4201A80A0012BE3C02100025 +:10F310008F4201B80440FFFE24020001AF5001807B +:10F32000AF400184A7520188A342018A240200024F +:10F33000A342018BA7510190AF4001A4AF4001A8A7 +:10F340003C021000AF4201B80A0012C38FBF001C7C +:10F350000000000D8FBF001C8FB200188FB1001489 +:10F360008FB0001003E0000827BD002027BDFFE894 +:10F37000AFBF00100E000F1800000000AF4001806A +:10F380008FBF0010000020210A000F7927BD001850 +:10F390003084FFFF30A5FFFF000018211080000718 +:10F3A00000000000308200011040000200042042F2 +:10F3B000006518210A0012D40005284003E0000867 +:10F3C0000060102110C0000624C6FFFF8CA20000C0 +:10F3D00024A50004AC8200000A0012DE248400048C +:10F3E00003E000080000000010A0000824A3FFFFB5 +:10F3F000AC86000000000000000000002402FFFFB7 +:10F400002463FFFF1462FFFA2484000403E0000871 +:10F410000000000027BDFFE8AFBF0014AFB0001030 +:10F420000E0011FE008080219362007D02002021E9 +:10F43000344200200E001207A362007D020020214A +:10F440008FBF00148FB000100A000C9B27BD00185E +:10F45000308300FF30A500FF30C600FF2747018042 +:10F460008F4201B80440FFFE000000008F420128D7 +:10F4700034634000ACE2000024020001ACE0000470 +:10F48000A4E30008A0E2000A24020002A0E2000BAC +:10F490003C021000A4E50010ACE00024ACE0002821 +:10F4A000A4E6001203E00008AF4201B827BDFFE860 +:10F4B000AFBF00109362003F24030012304200FFF0 +:10F4C0001043000D008030218F6200440082102321 +:10F4D0000440000A8FBF00108F62004824040039E6 +:10F4E0000000282100C21023044100042406001259 +:10F4F0000E001301000000008FBF00102402000165 +:10F5000003E0000827BD001827BDFFC8AFB1002CDD +:10F5100000A08821AFB2003027A500100080902104 +:10F5200002202021AFBF0034AFB000280E000CA491 +:10F53000AFA0001010400009024020218E220008D8 +:10F54000AF6200840E0012F2AF6000402404003865 +:10F550002405008D0A0013CD240600129362003E9C +:10F56000304200081040000F8FA20010304201000E +:10F57000104000078FA300148F6200600062102308 +:10F5800004430008AF6300600A0013560000000047 +:10F59000AF6000609362003E2403FFF70043102435 +:10F5A000A362003E9362003E304200081440000215 +:10F5B0002406000300003021936200349363003777 +:10F5C0008F640084304200FF306300FF0066182122 +:10F5D000000318800043282100A4202B1080000B7A +:10F5E000000000009763003C8F6200843063FFFFDF +:10F5F000004510230062182B146000040000000076 +:10F600008F6200840A001372004580239762003CD9 +:10F610003050FFFF8FA30010306200041040000440 +:10F62000000628808FA2001C0A00137A0202102B09 +:10F630002E02021850400003240202180A0013830D +:10F6400002051023306300041060000300451023FE +:10F650008FA2001C00451023004080212C42008016 +:10F6600054400001241000800E0011FE02402021B1 +:10F6700024020001AF62000C9362003E00102040A3 +:10F680003042007FA362003E8E220004244200012B +:10F69000AF620040A770003C8F6200509623000EBE +:10F6A00000431021AF6200588F62005000441021C7 +:10F6B000AF62005C8E220004AF6200188E22000848 +:10F6C000AF62001C8FA20010304200085440000AB4 +:10F6D00093A20020A3600036936200362403FFDF6C +:10F6E000A36200359362003E00431024A362003EF3 +:10F6F0000A0013AD8E220008A36200358E22000896 +:10F70000AF62004C8F6200248F63004000431021E1 +:10F71000AF6200489362000024030050304200FFB3 +:10F72000144300122403FF803C0208008C4231A0E5 +:10F730000242102100431024AF4200283C0208007E +:10F740008C4231A08E2400083C03000C02421021A0 +:10F750003042007F0342102100431021AC4400D806 +:10F760008E230008AF820024AC4300DC0E00120799 +:10F770000240202124040038000028212406000A29 +:10F780000E001301000000008FBF00348FB2003064 +:10F790008FB1002C8FB000282402000103E0000884 +:10F7A00027BD003827BDFFE8AFBF001090C7000D90 +:10F7B00000C0282130E6001010C0000A30E200042A +:10F7C0008CA300088F6200541062000630E200042F +:10F7D000144000178FBF0010000020210A000D13F5 +:10F7E00027BD00181040000D30E3001210C00010BB +:10F7F0008FBF00108CA300088F6200541462000DAC +:10F8000024020001240400382405008D0E00130199 +:10F81000240600120A0013F98FBF00102402001200 +:10F82000146200038FBF00100A00132F27BD0018B9 +:10F830002402000103E0000827BD001827BDFFF8DF +:10F8400027420180AFA20000308A00FF8F4201B83A +:10F850000440FFFE000000008F4601283C02080023 +:10F860008C4231A02403FF80AF86004C00C21021DF +:10F8700000431024AF4200243C0208008C4231A017 +:10F880008FA900008FA8000000C210213042007F25 +:10F89000034218213C02000A00621821946400D43B +:10F8A0008FA700008FA5000024020002AF83002470 +:10F8B000A0A2000B8FA30000354260003084FFFF40 +:10F8C000A4E200083C021000AD260000AD040004D4 +:10F8D000AC60002427BD0008AF4201B803E0000877 +:10F8E000240200018C8200048F8300240045102331 +:10F8F000AC820004906200633042007FA06200632B +:10F900008C8200209383002C8F85002434420002D7 +:10F91000AF830040A780003EAC820020A4A000E49A +:10F9200090A200632403FFBF0043102403E00008FB +:10F93000A0A20063274301808F4201B80440FFFE6C +:10F940008F82004CAC6200008F420124AC62000444 +:10F9500024026083A462000824020002A062000B5B +:10F960003C02100003E00008AF4201B88F8800405D +:10F970009382002C8F8300243C07080024E775AC99 +:10F9800000481023304200FF304900FC2465008805 +:10F990008F860044304A0003112000090000202116 +:10F9A000248200048CA30000304400FF0089102A48 +:10F9B000ACE3000024A500041440FFF924E7000490 +:10F9C00011400009000020212482000190A30000C2 +:10F9D000304400FF008A102BA0E3000024A50001A2 +:10F9E0001440FFF924E7000130C200031440000472 +:10F9F0008F850040310200031040000D0000000020 +:10FA000010A00009000020212482000190C3000002 +:10FA1000304400FF0085102BA0E3000024C6000145 +:10FA20001440FFF924E7000103E000080000000093 +:10FA30001100FFFD00002021248200048CC300007F +:10FA4000304400FF0088102BACE3000024C6000403 +:10FA50001440FFF924E7000403E000080000000060 +:10FA60008F8300409382002C30C600FF30A500FF3A +:10FA700000431023304300FF8F8200240080382190 +:10FA80000043102114C0000224480088008338215C +:10FA900030E200031440000530A2000314400003CC +:10FAA000306200031040000D0000000010A00009AB +:10FAB000000020212482000190E30000304400FF78 +:10FAC0000085102BA103000024E700011440FFF97A +:10FAD0002508000103E000080000000010A0FFFD61 +:10FAE00000002021248200048CE30000304400FF49 +:10FAF0000085102BAD03000024E700041440FFF93B +:10FB00002508000403E000080000000027BDFFF8FE +:10FB10002402FFFFAFA20000008038212405002F3F +:10FB20003C090800252971AC240800FF2406FFFFCA +:10FB300090E2000024A3FFFF0006220200C210266C +:10FB4000304200FF00021080004910218C4200006A +:10FB5000306500FF24E7000114A8FFF5008230267D +:10FB600000061027AFA20004AFA200000000282169 +:10FB700027A6000400C510239044000324A200011E +:10FB800000BD1821304500FF2CA200041440FFF9ED +:10FB9000A06400008FA2000003E0000827BD000859 +:10FBA0000080482130AAFFFF30C600FF30E7FFFF8A +:10FBB000274801808F4201B80440FFFE8F82004C2D +:10FBC000AD0200008F420124AD0200048D2200200E +:10FBD000A5070008A102000A24020016A102000BDA +:10FBE000934301208D2200088D240004306300FF20 +:10FBF000004310219783003E004410218D250024EE +:10FC0000004310233C0308008C6331A08F84002440 +:10FC1000A502000C246300E82402FFFFA50A000EE1 +:10FC2000A5030010A5060012AD050018AD020024C2 +:10FC3000948201142403FFF73042FFFFAD02002835 +:10FC40008C820118AD02002C3C021000AD00003087 +:10FC5000AF4201B88D2200200043102403E00008C9 +:10FC6000AD2200208F82002430E7FFFF0080482172 +:10FC7000904200D330A5FFFF30C600FF0002110004 +:10FC800030420F0000E23825274801808F4201B83A +:10FC90000440FFFE8F82004CAD0200008F42012421 +:10FCA000AD0200048D220020A5070008A102000A71 +:10FCB00024020017A102000B934301208D220008AB +:10FCC0008D240004306300FF004310219783003E21 +:10FCD000004410218F840024004310233C030800BB +:10FCE0008C6331A0A502000CA505000E246300E87A +:10FCF000A5030010A5060012AD0000148D220024FB +:10FD0000AD0200188C82005CAD02001C8C82005891 +:10FD1000AD0200202402FFFFAD020024948200E621 +:10FD20003042FFFFAD02002894820060948300BE41 +:10FD300030427FFF3063FFFF0002120000431021BA +:10FD4000AD02002C3C021000AD000030AF4201B803 +:10FD5000948200BE2403FFF700A21021A48200BEFB +:10FD60008D2200200043102403E00008AD22002073 +:10FD7000274301808F4201B80440FFFE240200188F +:10FD8000AC640000A062000B8F820024944200E665 +:10FD9000A46200103C021000AC60003003E00008D8 +:10FDA000AF4201B8274301808F4201B80440FFFEF3 +:10FDB0008F8200289442001C3042FFFF000211C0D5 +:10FDC000AC62000024020019A062000B3C0210008B +:10FDD000AC60003003E00008AF4201B88F8700300C +:10FDE00030C300FF8F4201B80440FFFE8F82004CF9 +:10FDF00034636000ACA2000093820048A0A200051A +:10FE00008CE20010A4A20006A4A300088C820020AB +:10FE10002403FFF7A0A2000A24020002A0A2000B04 +:10FE20008CE20000ACA200108CE20004ACA2001432 +:10FE30008CE2001CACA200248CE20020ACA20028C2 +:10FE40008CE2002CACA2002C8C820024ACA2001806 +:10FE50003C021000AF4201B88C8200200043102405 +:10FE600003E00008AC8200209382004824030001D4 +:10FE700027BDFFE8004330042C420020AFB0001043 +:10FE8000AFBF00142410FFFE10400005274501807D +:10FE90003C0208008C4231900A001598004610245C +:10FEA0003C0208008C4231940046102414400007A4 +:10FEB000240600848F8300242410FFFF90620062D8 +:10FEC0003042000F34420040A06200620E00156410 +:10FED00000000000020010218FBF00148FB000103E +:10FEE00003E0000827BD00188F83002827BDFFE02E +:10FEF000AFB20018AFB10014AFB00010AFBF001C1C +:10FF00009062000D00A0902130D100FF3042007FB0 +:10FF1000A062000D8F8500248E4300180080802190 +:10FF20008CA2007C146200052402000E90A20063E3 +:10FF3000344200200A0015C1A0A200630E001587FC +:10FF4000A38200482403FFFF104300472404FFFF5F +:10FF500052200045000020218E4300003C0200108A +:10FF600000621024504000043C02000802002021DE +:10FF70000A0015D024020015006210245040000928 +:10FF80008E45000002002021240200140E00158777 +:10FF9000A38200482403FFFF104300332404FFFF23 +:10FFA0008E4500003C02000200A210241040001602 +:10FFB0003C0200048F8600288CC200148CC3001001 +:10FFC0008CC40014004310230044102B5040000543 +:10FFD000020020218E43002C8CC20010106200030E +:10FFE000020020210A001601240200123C02000433 +:10FFF00000A210245040001C0000202102002021FB +:020000040001F9 +:100000000A0016012402001300A21024104000066A +:100010008F8300288C6200105040001300002021C4 +:100020000A0015FB020020218C62001050400004E1 +:100030008E42002C020020210A0016012402001129 +:100040005040000900002021020020212402001756 +:100050000E001587A38200482403FFFF104300020F +:100060002404FFFF000020218FBF001C8FB2001866 +:100070008FB100148FB000100080102103E0000841 +:1000800027BD00209383002C27BDFFE0240200340D +:10009000AFB20018AFB10014AFBF001CAFB000107A +:1000A000008088211462000C00A090218F84003011 +:1000B0000E0014B08C9000301202000724020005DC +:1000C000022020210E001587A38200482403FFFF91 +:1000D0001043005F2404FFFF924200041040000917 +:1000E0008F820024022020212402000C0E0015879C +:1000F000A38200482403FFFF104300552404FFFFA0 +:100100008F820024A38000208E4300048C44008052 +:100110003C0200FF3442FFFF006218240083202BC2 +:1001200010800008AF83003802202021240200192B +:100130000E001587A38200482403FFFF10430044EC +:100140002404FFFF9782003E8F8700408F8800388D +:100150000047102311000039A782003E8F8600243B +:100160003045FFFF8F84004C90C300BC3C02080068 +:100170008C4231A0000318823070000100822021DF +:10018000001010800102102100A2282B10A00010E6 +:10019000248200888F8400301082000D3C033F01D0 +:1001A0008E420000004310243C0325001443000647 +:1001B00030E500FF8C820000ACC200888C82001009 +:1001C0000A001661ACC200980E00148500003021B0 +:1001D0008F850038938300208F86002430A200038F +:1001E000000210233042000300433821A38700207F +:1001F00094C400E400A228218F8300408F82004431 +:1002000034841000A4C400E400431021AF820044F1 +:100210001200000EAF85004024E20004A3820020FB +:1002200094C200E424A30004AF83004034422000C1 +:10023000A4C200E40A001681000020218F8200443D +:10024000AF80004000471021AF8200440000202111 +:100250008FBF001C8FB200188FB100148FB0001038 +:100260000080102103E0000827BD00208F860024B5 +:1002700027BDFFE8AFBF0014AFB0001090C200630D +:10028000304200201040000830A500FF8CC2007CE6 +:100290002403FFDF24420001ACC2007C90C2006353 +:1002A00000431024A0C2006310A000238F83002409 +:1002B00027500180020028210E00156424060082C8 +:1002C0008F82002490420063304200405040001969 +:1002D000A38000488F8300308F4201B80440FFFEA6 +:1002E0008F82004CAE02000024026082A602000849 +:1002F00024020002A202000B8C620008AE02001071 +:100300008C62000CAE0200148C620014AE02001865 +:100310008C620018AE0200248C620024AE02002819 +:100320008C620028AE02002C3C021000AF4201B8E3 +:10033000A38000488F8300248FBF00148FB000106B +:100340009062006327BD00183042007FA062006306 +:100350009782003E8F8600408F8500249383002C77 +:1003600000461023A782003EA4A000E490A40063EE +:100370008F820044AF8300402403FFBF004610215A +:1003800000832024AF820044A0A400638F82002455 +:10039000A04000BD8F82002403E00008A44000BEFE +:1003A0008F8A002427BDFFE0AFB10014AFB000106A +:1003B0008F880040AFBF001893890020954200E469 +:1003C00030D100FF0109182B0080802130AC00FFE4 +:1003D0003047FFFF0000582114600003310600FF82 +:1003E00001203021010958239783003E0068102B1B +:1003F00014400032000000001468000724020001CD +:100400008E0200202403FFFB34E780000043102409 +:10041000AE0200202402000134E7088015820005A6 +:100420003165FFFF0E0014D5020020210A001716C7 +:10043000020020210E001506020020210E001549A1 +:100440008F84004C8F840024948200602442000139 +:10045000A4820060948200603C0308008C633188B1 +:1004600030427FFF5443000F02002021948200603D +:100470002403800000431024A48200609082006066 +:1004800090830060304200FF000211C2000210277A +:10049000000211C03063007F00621825A083006055 +:1004A00002002021022028218FBF00188FB10014E4 +:1004B0008FB000100A00168827BD0020914200630B +:1004C0002403FF8000431025A14200639782003E71 +:1004D0003048FFFF11000020938300208F84002408 +:1004E000004B1023304600FF948300E42402EFFF0A +:1004F0000168282B00621824A48300E414A00003E0 +:100500008E02002001005821000030212403FFFB4F +:1005100034E7800000431024AE02002024020001D2 +:10052000158200053165FFFF0E0014D50200202161 +:100530000A00173E9783003E0E0015060200202198 +:100540009783003E8F820040A780003E0043102327 +:10055000AF820040938300208F8200248FBF001859 +:100560008FB100148FB0001027BD002003E00008F9 +:10057000A04300BD8F82002490430088904500BDB9 +:10058000244900883063003F2463FFE02402000117 +:10059000006238042C63002030E80019A385002095 +:1005A00010600010AF8900303C028000344200022D +:1005B00024050001240600011500000800E21824AB +:1005C000000028211460000530E2002010400005E2 +:1005D000240500019126000130C600010A0016D54D +:1005E0000000000003E000080000000027BDFFD865 +:1005F000AFB000108F900030AFB40020AFB1001446 +:10060000AFBF0024AFB3001CAFB200188E050010BE +:100610003C0208008C4231B08F86003430A33FFF8B +:100620000062182B8CD30014008088218CD200200B +:10063000106000780000A02190C3000D2402FF800C +:1006400000431024304200FF50400073022020215C +:1006500000051382304200035440006F0220202125 +:1006600094C3001C8F8200248E050028A44301142B +:100670008CC2001002621823146500072402001FB8 +:100680008F820038006210210262102B1040000897 +:100690008F830028240200180E001587A3820048CB +:1006A0002403FFFF1043006F2404FFFF8F83002803 +:1006B0008F8400388C620010024490210044102383 +:1006C000AC6200108F820024AC7200208C42006863 +:1006D0000052102B104000098F830034022020218B +:1006E0002402001D0E001587A38200482403FFFF8B +:1006F0001043005C2404FFFF8F8300348E0200242B +:100700008C63002410430007022020212402001CD7 +:100710000E001587A38200482403FFFF10430051F9 +:100720002404FFFF8F8400288C82002424420001CF +:10073000AC820024125300048F8200248C42006893 +:100740005642000E8E0200008E0200003C03008024 +:10075000004310241440000D2402001A022020211E +:100760000E001587A38200482403FFFF1043003DBD +:100770002404FFFF0A0017D28E0200143C030080FD +:1007800000431024504000038E020014AC8000206F +:100790008E0200142412FFFF105200062402001BD8 +:1007A000022020210E001587A38200481052002D40 +:1007B0002404FFFF8E0300003C02000100621024AD +:1007C0001040001F3C02008000621024144000080A +:1007D000022020212402001A0E001587A38200485F +:1007E0002403FFFF1043001F2404FFFF02202021E9 +:1007F000020028210E0015A7240600012403FFFF94 +:100800002404FFFF1443000E241400010A001807FB +:100810008FBF0024022020212402000D8FBF00245E +:100820008FB400208FB3001C8FB200188FB100145A +:100830008FB0001027BD00280A001587A38200484A +:100840008F8300280220202102803021946200360C +:1008500024050001244200010E0016D5A4620036D2 +:10086000000020218FBF00248FB400208FB3001C14 +:100870008FB200188FB100148FB0001000801021CB +:1008800003E0000827BD00288F83002427BDFFD880 +:10089000AFB40020AFB3001CAFB20018AFB100146A +:1008A000AFB00010AFBF0024906200638F910030A2 +:1008B0002412FFFF3442004092250000A062006332 +:1008C0008E2200100080982130B0003F10520006A8 +:1008D0000360A0212402000D0E001587A3820048AA +:1008E000105200522404FFFF8F8300248E22001830 +:1008F0008C63007C10430007026020212402000E5C +:100900000E001587A38200482403FFFF1043004711 +:100910002404FFFF24040020120400048F83002419 +:100920009062006334420020A06200638F8500382B +:1009300010A0001E00000000560400048F82002456 +:10094000026020210A0018512402000A9683000A3E +:100950002404FFFD944200603042FFFF1043003446 +:100960008FBF00243C0208008C42318C0045102BC4 +:100970001440000602602021000028210E0016D538 +:10098000240600010A001878000020212402002D0E +:100990000E001587A38200482403FFFF10430023A5 +:1009A0002404FFFF0A001878000020211604000527 +:1009B0008F8400248E2300142402FFFF506200184D +:1009C000026020219482006024420001A482006021 +:1009D000948200603C0308008C63318830427FFFC2 +:1009E0005443000F026020219482006024038000A1 +:1009F00000431024A4820060908200609083006015 +:100A0000304200FF000211C200021027000211C094 +:100A10003063007F00621825A083006002602021FF +:100A20000E00168824050001000020218FBF00243D +:100A30008FB400208FB3001C8FB200188FB1001448 +:100A40008FB000100080102103E0000827BD0028AF +:100A50008F83002427BDFFE8AFB00010AFBF0014A4 +:100A6000906200638F870030008080213442004014 +:100A70008CE60010A06200633C0308008C6331B078 +:100A800030C23FFF0043102B1040004E8F850034D2 +:100A90002402FF8090A3000D00431024304200FF89 +:100AA0005040004902002021000613823048000314 +:100AB00024020002550200440200202194A2001CDE +:100AC0008F85002424030023A4A201148CE60000D7 +:100AD000000616023042003F104300103C03008322 +:100AE0008CE300188CA2007C106200062402000E29 +:100AF0000E001587A38200482403FFFF104300382F +:100B00002404FFFF8F83002490620063344200209E +:100B1000A06200630A0018BD8F83002800C3102460 +:100B2000144300078F83002890A200623042000F18 +:100B300034420020A0A20062A388003C8F830028DA +:100B40009062000D3042007FA062000D8F8300385C +:100B500010600018020020218F8400348C82001065 +:100B60000043102B1040000924020018020020212D +:100B70000E001587A38200482403FFFF10430018CE +:100B80002404FFFF0A0018E5000020218C820010D9 +:100B90002405000102002021004310238F83002838 +:100BA000240600010E0016D5AC6200100A0018E5FC +:100BB000000020210E001688240500010A0018E517 +:100BC00000002021020020212402000D8FBF00140C +:100BD0008FB0001027BD00180A001587A3820048B7 +:100BE0008FBF00148FB000100080102103E00008B8 +:100BF00027BD001827BDFFD8AFB000108F90003080 +:100C0000AFB3001CAFBF0020AFB20018AFB10014EB +:100C10008E1200103C0308008C6331B032423FFF5B +:100C20000043102B1040007C008098218F850034F9 +:100C30002402FF8090A3000D00431024304200FFE7 +:100C400050400076026020210012138230420003DF +:100C500024030001544300710260202190A2000D82 +:100C600030420008544000038F8200380A001915F2 +:100C700024020024504000038E03000C0A001915C2 +:100C8000240200278CA20020146200052402002008 +:100C90008E0300088CA200241062000824020020A9 +:100CA0000E001587A38200482403FFFF1043006A4B +:100CB0002404FFFF0A0019408F8400288E020014CC +:100CC0002411FFFF145100038F8700240A00193BF1 +:100CD000240200258E0300188CE2007C14620016AA +:100CE0002402000E8E0300248CA20028146200123D +:100CF000240200218E0600288CA2002C14C2000EB3 +:100D00002402001F8E03002C1060000B240200231D +:100D10008CE200680043102B1440000724020026D8 +:100D20008CA20014006618210043102B50400007CD +:100D30008F840028240200220E001587A382004819 +:100D4000105100452404FFFF8F8400282403FFF77F +:100D50009082000D00431024A082000D8F86002495 +:100D60003C0308008C6331AC8F82004C94C400E0DB +:100D70008F8500280043102130847FFF000420402D +:100D8000004410213043007F034320213C03000E28 +:100D9000008320212403FF8000431024AF42002C55 +:100DA000A49200008CA2002824420001ACA20028DA +:100DB0008CA2002C8E03002C00431021ACA2002C2E +:100DC0008E02002CACA200308E020014ACA20034C3 +:100DD00094A2003A24420001A4A2003A94C600E082 +:100DE0003C0208008C4231B024C4000130837FFFF4 +:100DF000146200130080302124028000008230241D +:100E000030C2FFFF000213C2304200FF0002102771 +:100E10000A00197D000233C0026020212402000D67 +:100E20008FBF00208FB3001C8FB200188FB1001449 +:100E30008FB0001027BD00280A001587A382004844 +:100E40008F82002402602021240500010E001688F4 +:100E5000A44600E0000020218FBF00208FB3001CBB +:100E60008FB200188FB100148FB0001000801021D5 +:100E700003E0000827BD002827BDFFE0AFB1001444 +:100E80008F910030AFB00010AFBF00188E26001059 +:100E90003C0308008C6331B030C23FFF0043102B8D +:100EA0001040005E008080218F8500342402FF8086 +:100EB00090A3000D00431024304200FF5040005822 +:100EC000020020218F8200381040000800061382A3 +:100ED0008F8200249763000A2404FFFD944200607F +:100EE0003042FFFF104300550006138230420003DA +:100EF0001440000E00000000922200021040000585 +:100F00008E23002450600015922300030A0019B6B6 +:100F1000020020218CA200245062001092230003C2 +:100F2000020020210A0019BE2402000F90A2000D29 +:100F3000304200085440000992230003020020219F +:100F4000240200100E001587A38200482403FFFF2F +:100F50001043003A2404FFFF9223000324020002FE +:100F60005462000C922200038F8200385440000922 +:100F700092220003020020212402002C0E0015877B +:100F8000A38200482403FFFF1043002C2404FFFF2A +:100F9000922200030220282102002021384600105E +:100FA0002CC600012C4200010E0015A7004630257A +:100FB0002411FFFF105100212404FFFF8F8300380C +:100FC00010600012020020213C0208008C42318C8B +:100FD0000043102B144000060000000000002821F0 +:100FE0000E0016D5240600010A0019FC000020217D +:100FF0002402002D0E001587A38200481051000F17 +:101000002404FFFF0A0019FC000020210E001688AE +:10101000240500010A0019FC000020210200202103 +:101020002402000D8FBF00188FB100148FB0001084 +:1010300027BD00200A001587A38200488FBF001833 +:101040008FB100148FB000100080102103E0000861 +:1010500027BD00209383003C27BDFFE0240200024F +:10106000AFB10014AFB0001000808821AFBF0018EE +:10107000000080211062008C2404FFFD9785003E53 +:101080008F83004030A2FFFF0043102B5440007DAF +:101090008F8400440E001448000000003C02080049 +:1010A000244275AC02202021004028210E00160E9B +:1010B000AF8200302409FFFF1049007B2404FFFFAA +:1010C0003C0808008D0875BC3C0208008C4231B019 +:1010D0003C030800906375AC31043FFF0082102B85 +:1010E0001040001B3067003F3C0208008C4231A8D2 +:1010F0008F83004C000421800062182100641821B5 +:101100003062007F034228213C02000C00A228210B +:101110003C020080344200013066007800C2302575 +:101120002402FF8000621024AF42002830640007D0 +:10113000AF4208048F820024034420212484094004 +:10114000AF460814AF850028AF840034AC430118C3 +:101150009383003C240200031462003B240200013C +:101160002402002610E2003D28E200271040001370 +:10117000240200322402002210E2003828E2002378 +:1011800010400008240200242402002010E2002461 +:101190002402002110E2001E022020210A001A7BF6 +:1011A0002402000B10E2002D2402002510E20010A2 +:1011B000022020210A001A7B2402000B10E2001AF0 +:1011C00028E20033104000062402003F24020031D0 +:1011D00010E2000B022020210A001A7B2402000BDF +:1011E00010E20011022020210A001A7B2402000BC9 +:1011F0000E001768022020210A001A960040802164 +:101200000E0018EA022020210A001A9600408021D0 +:101210000E00198B022020210A001A96004080211E +:101220001509000E000000000E00180F02202021FA +:101230000A001A96004080210E001587A3820048FC +:101240000A001A9600408021146200170200202133 +:101250002402002314E200052402000B0E00188172 +:10126000022020210A001A9600408021022020211D +:10127000A38200480E0015872410FFFF0A001A976A +:101280000200202130A500FF0E0014852406000175 +:101290009783003E8F820040A780003E00431023CA +:1012A000AF820040020020218FBF00188FB10014D0 +:1012B0008FB000100080102103E0000827BD00203F +:1012C00027BDFFE0AFB10014AFBF0018AFB00010F2 +:1012D0008F4601283C0308008C6331A02402FF8064 +:1012E000AF86004C00C318213065007F03452821DC +:1012F000006218243C02000AAF43002400A2282107 +:1013000090A2006200808821AF850024304200FF57 +:1013100000021102A382003C90A200BC30420002F5 +:101320001440000224030034240300308F82002480 +:10133000A383002C9383003C8C4200C0A380004810 +:10134000AF82004024020004106200308F8400400D +:101350008E2400045080002D8F8400408E220010C7 +:101360003083FFFFA784003E1060001FAF8200445F +:101370008F8300242405FF800220202190620063D7 +:1013800000A21024304200FF1440000D00000000B5 +:101390000E001A029790003E1040001000401821E5 +:1013A0002402FFFD546200118E2300200200282138 +:1013B0000E001426022020210A001AE88E230020A5 +:1013C0009062006300A21024304200FF104000032E +:1013D000022020210E00174A000000009782003EE4 +:1013E0001440FFE48F8300248E2300203062000429 +:1013F000104000068F8400402402FFFB006210248E +:101400000E00143AAE2200208F8400408F83002407 +:101410008FBF00188FB100148FB00010240200019C +:1014200027BD002003E00008AC6400C030A500FF29 +:101430002403000124A900010069102B1040000CB6 +:1014400000004021240A000100A31023004A3804B0 +:1014500024630001308200010069302B104000023B +:10146000000420420107402554C0FFF800A31023C8 +:1014700003E000080100102127BDFFE03C021EDC54 +:10148000AFB20018AFB10014AFBF001CAFB0001076 +:1014900034526F4100008821240500080E001AF81C +:1014A00002202021001180803C07080024E771AC55 +:1014B0000002160002071821AC620000000028217B +:1014C00024A200013045FFFF8C6200002CA600081A +:1014D00004410002000220400092202614C0FFF8C0 +:1014E000AC640000020780218E0400000E001AF890 +:1014F00024050020262300013071FFFF2E23010068 +:101500001460FFE5AE0200008FBF001C8FB2001810 +:101510008FB100148FB0001003E0000827BD002039 +:101520003C02080024426A743C010800AC2271A00D +:101530003C02080024424FF03C010800AC2271A498 +:10154000240200063C010800A02271A80A001B0B1F +:101550000000000027BDFFD8AFB3001CAFB20018D9 +:10156000AFBF0020AFB10014AFB000108F510140E9 +:101570008F48014800089402324300FF311300FFF6 +:101580008F4201B80440FFFE27500180AE110000D9 +:101590008F420144AE02000424020002A612000899 +:1015A000A202000B24020014AE13002410620025D6 +:1015B00028620015104000082402001524020010C3 +:1015C0001062003024020012106200098FBF002058 +:1015D0000A001C358FB3001C106200702402002228 +:1015E000106200378FBF00200A001C358FB3001C2B +:1015F0003C0208008C4231A02403FF80022210210B +:1016000000431024AF4200243C0208008C4231A069 +:10161000022210213042007F034218213C02000ABE +:1016200000621821166000BCAF8300249062006243 +:101630003042000F34420030A06200620A001C34C5 +:101640008FBF00203C0460008C832C083C02F00318 +:101650003442FFFF00621824AC832C083C020800CF +:101660008C4231A08C832C0824420074000210822A +:101670000002148000621825AC832C080A001C3478 +:101680008FBF00203C0208008C4231A02403FF8061 +:101690000222102100431024AF4200243C02080023 +:1016A0008C4231A03C03000A022210213042007F0C +:1016B00003421021004310210A001C33AF82002492 +:1016C0003C0208008C4231A02405FF800222102138 +:1016D00000451024AF4200243C0208008C4231A097 +:1016E000022210213042007F034218213C02000AEE +:1016F000006218219062006300A21024304200FFB3 +:1017000010400085AF8300242462008894430012B7 +:101710003C0208008C4231A830633FFF000319806F +:1017200002221021004310213043007F0343202177 +:10173000004510243C03000C00832021AF42002808 +:101740009082000D00A21024304200FF1040007271 +:10175000AF8400289082000D304200101440006FCA +:101760008FBF00200E001556000000008F4201B808 +:101770000440FFFE00000000AE1100008F42014453 +:10178000AE02000424020002A6120008A202000B0E +:10179000AE1300240A001C348FBF00202406FF80F3 +:1017A00002261024AF4200203C0208008C4231A0E7 +:1017B00031043FFF00042180022210210046102442 +:1017C000AF4200243C0308008C6331A83C020800AF +:1017D0008C4231A03227007F0223182102221021DF +:1017E000006418213042007F3064007F03422821CA +:1017F0003C02000A0066182400A22821034420218C +:101800003C02000C00822021AF4300283C0200086B +:101810000347182100629021AF850024AF8400287F +:101820000E001556010080218F4201B80440FFFED2 +:101830008F8200288F840024274501809042000D6C +:10184000ACB10000A4B000060002160000021603AE +:1018500000021027000237C214C00016248200883C +:101860009442001232033FFF30423FFF1443001204 +:1018700024026082908300632402FF8000431024CE +:10188000304200FF5040000C2402608290820062CF +:101890003042000F34420040A08200622402608483 +:1018A000A4A200082402000DA0A200050A001C1E2C +:1018B0003C02270024026082A4A20008A0A0000528 +:1018C0003C02270000061C000062182524020002CA +:1018D000A0A2000BACA30010ACA00014ACA000248C +:1018E000ACA00028ACA0002C8E42004C8F840028B5 +:1018F000ACA200189083000D2402FF800043102446 +:10190000304200FF104000058FBF00209082000D84 +:101910003042007FA082000D8FBF00208FB3001CDB +:101920008FB200188FB100148FB000103C0210006D +:0C19300027BD002803E00008AF4201B80A +:04193C00080033F874 +:10194000080033F808003370080033A8080033DCBF +:10195000080034000800340008003400080032E0B9 +:101960000A00012200000000000000000000000D3D +:10197000747061352E302E306A330000050000018E +:101980000000000000000000000000000000000057 +:101990000000000000000000000000000000000047 +:1019A0000000000000000000000000000000000037 +:1019B0000000000000000000000000000000000027 +:1019C0000000000000000000000000000000000017 +:1019D0000000000000000000000000000000000007 +:1019E00000000000000000000000000010000003E4 +:1019F000000000000000000D0000000D3C02080087 +:101A000024421B803C03080024632014AC400000E7 +:101A10000043202B1480FFFD244200043C1D0800DD +:101A200037BD2FFC03A0F0213C10080026100488CD +:101A30003C1C0800279C1B800E00015A000000007F +:101A40000000000D3084FFFF308200078F850018F2 +:101A500010400002248300073064FFF80085302125 +:101A600030C41FFF03441821247B4000AF85001CB5 +:101A7000AF84001803E00008AF4400843084FFFF07 +:101A8000308200078F8500208F86002810400002DA +:101A9000248300073064FFF8008520210086182B7E +:101AA00014600002AF85002400862023034428210F +:101AB00034068000AF840020AF44008000A62021BF +:101AC00003E00008AF84003827BDFFD8AFB3001C87 +:101AD000AFB20018AFB00010AFBF0024AFB4002009 +:101AE000AFB100143C0860088D1450002418FF7F2B +:101AF0003C1A8000029898243672380CAD125000BF +:101B00008F5100083C07601C3C0860003630000123 +:101B1000AF500008AF800018AF400080AF40008495 +:101B20008CE600088D0F08083C0760168CEC00005E +:101B300031EEFFF039CA00103C0DFFFF340B80007E +:101B40003C030080034B48212D440001018D2824D3 +:101B50003C0253533C010800AC230420AF890038F9 +:101B6000AF860028AF840010275B400014A200035A +:101B700034E37C008CF90004032818218C7F007C5E +:101B80008C6500783C02800034520070AF85003CC8 +:101B9000AF9F00403C13080026731BC40240A021E5 +:101BA0008E4800008F46000038C3000130640001F9 +:101BB00010800017AF880034028048218D2D00006E +:101BC0003C1908008F39045C3C1108008E31045820 +:101BD00001A8F823033F7821000040210228382182 +:101BE00001FF802B00F070213C010800AC2F045C49 +:101BF0003C010800AC2E04588F4C0000398B0001CA +:101C0000316A00011540FFED01A04021AF8D003485 +:101C10008E4E00003C0C08008D8C045C3C0A0800D1 +:101C20008D4A045801C86823018D282100005821DD +:101C300000AD302B014B2021008610213C01080013 +:101C4000AC25045C3C010800AC2204588F45010817 +:101C50008F44010030A92000AF850000AF84000C44 +:101C60001120000A00A030213C0708008CE7042C5A +:101C700024EF00013C010800AC2F042C3C10400074 +:101C8000AF5001380A0001900000000030B002009F +:101C90001600001424110F001091001224070D00EB +:101CA0001087023330B000065200FFF53C104000B0 +:101CB000936D0000240C001031A600F010CC0269D6 +:101CC000240E007010CE02DD8F8B001425670001FA +:101CD000AF8700143C104000AF5001380A0001905B +:101CE00000000000974801041100FFE53C1040008F +:101CF00030B84000170000A2000000008F590178A2 +:101D00000720FFFE8F8700382409000824050800FB +:101D10008CE30008AF450178A7490140A740014284 +:101D2000974201048F8600003049FFFF30DF000139 +:101D300013E002D5012040212524FFFE240A0002E1 +:101D4000A74A01463088FFFFA74401483C0B080022 +:101D50008D6B043C156002C48F8F000C30C30020D3 +:101D600014600002240400092404000130CD0C009A +:101D7000240C040051AC000134840004A744014A3F +:101D80003C0508008CA504203C0200483C190001D9 +:101D900000A2F82530D8000203F92825130000041A +:101DA000000018213C04010000A4282524030001A0 +:101DB00030CA000451400005AF8300083C06001003 +:101DC00000A6282524030001AF830008AF451000BA +:101DD0000000000000000000000000000000000003 +:101DE0008F83000810600023000000008F4B10005C +:101DF0000561FFFE000000001060001E00000000F2 +:101E00008F4D10003C03002001A3602411800019B5 +:101E10008F8F000031EE000211C00016000000009C +:101E2000975010141600001300000000974510088A +:101E300030BFFFFF27F800060018C8820019308065 +:101E400000C72821331100013303000312200320AF +:101E50008CA200000000000D00C7F821AFE20000D6 +:101E60003C1908008F390430272600013C01080086 +:101E7000AC2604308F6A00003405FFFFAF8A0004EF +:101E80008CE200001045029A000020218CE5000041 +:101E900030BF010013E0027E010020213C07080052 +:101EA0008CE704743C1008008E10044C00E85821A4 +:101EB0003C1808008F1804700168882B3C08080043 +:101EC0008D0804480000782102046021030F1821C6 +:101ED0000184702B010F68210071502101AE102187 +:101EE0003C010800AC2C044C3C010800AC22044826 +:101EF0003C010800AC2B04743C010800AC2A0470BF +:101F00008F8D0018012030213129000725AE0008EF +:101F100031C21FFF03426021AF8D001CAF82001849 +:101F2000259B4000AF420084112000038F900020C9 +:101F300024C800073106FFF88F84002800D028212C +:101F400000A4782B15E00002AF90002400A4282301 +:101F50000345202134038000008310213C0610003B +:101F6000AF850020AF820038AF450080AF460178D2 +:101F70008F8B0014256700010A0001DDAF87001474 +:101F80008F6200088F670000241100300007C6022E +:101F9000330300F0107100A2241900401479FF4BA4 +:101FA0008F8B00148F4A01780540FFFE30A7020096 +:101FB00014E00003000512820000000D00051282EB +:101FC000305000030010490001307021000E68807D +:101FD00001B06021000C5880017380218E08000040 +:101FE00015000002000000000000000D8F6F0004CB +:101FF00005E202B19203000692070005920F000469 +:102000003C0200010007288000B060218D89001883 +:102010002771000825EE000501226821000E30829C +:10202000AD8D0018022020210E0005802605001429 +:10203000920B00068F7F00043C087FFF000B20807E +:10204000009130218CC30004350AFFFF03EAC82445 +:102050000079C021ACD80004920700059209000461 +:10206000960D00080007288000B1F8218FEF0000CE +:10207000974201043C07FFFF01E75024304EFFFF69 +:1020800001C96021018D58233168FFFF01482025D7 +:10209000AFE40000920300072419000110790269DF +:1020A0002406000310660279000000008E1900105B +:1020B000241F000AA75F0140A759014292030004B0 +:1020C0008F86000024070001A7430144A740014672 +:1020D0009758010430D100023C050041A75801483F +:1020E00000001821A747014A1220000330CA00044B +:1020F0003C0501412403000151400005AF83000865 +:102100003C08001000A8282524030001AF83000824 +:10211000AF451000000000000000000000000000BB +:10212000000000008F8B0008116000040000000018 +:102130008F4410000481FFFE000000008F6A000041 +:10214000920700043C0508008CA50444AF8A0004F3 +:10215000975F01043C0F08008DEF044030E300FF5F +:1021600033F9FFFF0079C02100B868210000102179 +:1021700024E6000A30C8FFFF01B8482B01E27021B5 +:1021800001C96021311000073C010800AC2D044456 +:102190003C010800AC2C0440120000038F8D001895 +:1021A000250B00073168FFF8010D702131CC1FFFAE +:1021B000AF8D001CAF8C0018AF4C00849744010415 +:1021C000034C80213084FFFF30880007110000039A +:1021D000261B4000248900073124FFF88F8200204D +:1021E0008F850028008220210085782B15E00002D1 +:1021F000AF82002400852023034488213405800019 +:10220000022510213C061000AF840020AF82003868 +:10221000AF440080AF4601780A0002858F8B00141E +:102220008F5F017807E0FFFE30AA0200154000032F +:10223000000542820000000D0005428231020003C9 +:102240000002710001C26821000D608001824821F6 +:102250000009288000B380218E0B0000116000026D +:10226000000000000000000D8F6F000C05E001F37E +:102270008F87003824190001AE1900008CE3000894 +:10228000A20000078F78000400181C02306600FFCF +:1022900024D10005001130822CC4004114800002BA +:1022A000A20300040000000D8F6B00043C0EFFFF32 +:1022B00000E028213164FFFF248F000B000F4082D3 +:1022C00000081080004748218D2D000026040014CE +:1022D000A60B000801AE60240E000580AD2C0000A6 +:1022E0008F5F01083C0A100003EA382410E001A3C4 +:1022F00000000000974601049203000724D1FFEC80 +:10230000346500023224FFFFA2050007960600088C +:102310002CC7001354E0000592030007920A00073F +:10232000355F0001A21F000792030007240B000184 +:10233000106B01BA24090003106901CD8F880038A1 +:1023400030CFFFFF25E400020004C883333F00FFC5 +:10235000001F2880A219000500A858218D780000D0 +:10236000975101043C03FFFF030360243222FFFF67 +:10237000004F702325CDFFFE018D4825AD6900007B +:10238000920600053C02FFF6344EFFFF30CA00FF04 +:10239000000A388000F02021909900143C1FFF7F34 +:1023A00037E7FFFF3323000F0066782131F800FF85 +:1023B0000018288000B088218E2D002000A8602100 +:1023C000A20F000601AE4824AE0D000CAD89000C32 +:1023D000920B00068E04000C0127F824000B50809D +:1023E0000150C821972600260148C02100874024BB +:1023F000AF260024AE08000CAF3F0020AF0600104F +:102400008F860000240C001024090002A74C014014 +:10241000A7400142A7400144A7490146974B010448 +:102420002407000130C80002256AFFFEA74A0148C0 +:102430003C050009A747014A1100000300001821CC +:102440003C0501092403000130CD000451A0000522 +:10245000AF8300083C06001000A6282524030001D5 +:10246000AF830008AF45100000000000000000002E +:102470000000000000000000921800042711000274 +:10248000322F0007000F1023304E0007AE0E001051 +:102490008F90000812000004000000008F4310001D +:1024A0000461FFFE000000008F7800008F8F00188D +:1024B0003C1008008E100444AF98000497510104AA +:1024C00025E6001030CA1FFF3222FFFFAF8F001C2D +:1024D000AF8A0018AF4A00842449FFFE3C0B080075 +:1024E0008D6B0440974E010401206821000967C3E9 +:1024F000020D282131C9FFFF00AD402B016C3821AE +:1025000000E82021034AF821313900073C01080086 +:10251000AC2504443C010800AC2404401320000313 +:1025200027FB4000252300073069FFF88F9F00201C +:102530008F840028013F382100E4C82B17200002B7 +:10254000AF9F002400E43823034720213405800096 +:10255000008510213C061000AF870020AF820038B4 +:10256000AF470080AF4601780A0002858F8B0014C8 +:10257000975801041300FDC23C1040008F430178BE +:102580000460FFFE30B94000132000033C04000843 +:102590000000000D3C040008AF440140240808007E +:1025A000AF4801788F8B0000974A0104317F00010A +:1025B00013E000E93146FFFF24D0FFFE240C0002A7 +:1025C000A74C0146A75001488F8F00182405000D25 +:1025D000A745014A8F71000025E2000830491FFF1E +:1025E0000349702130CD0007AF910004AF8F001C6C +:1025F000AF89001800C03821AF49008411A0000342 +:1026000025DB400024C6000730C7FFF88F98002064 +:102610008F84002800F8302100C4382B14E0000219 +:10262000AF98002400C430238F8A00140346582139 +:10263000340880000168F821255900013C0310008E +:102640003C104000AF860020AF9F0038AF460080AE +:10265000AF430178AF990014AF5001380A000190E0 +:10266000000000008F690000974401043127FFFF3C +:102670003088FFFF8F4F017805E0FFFE30FF000735 +:10268000001F18233078000724E6FFFE2419000AF3 +:10269000A7590140A7580142A7460144A740014657 +:1026A000A74801488F42010830510020162000023F +:1026B000240300092403000130AA0002A743014AB1 +:1026C0003C04004111400003000018213C0401417A +:1026D0002403000130AB000451600005AF83000803 +:1026E0003C0500100085202524030001AF8300086D +:1026F000AF441000000000000000000000000000D7 +:10270000000000008F90000812000004000000008C +:102710008F4C10000581FFFE000000008F78000044 +:10272000276200088F8D003CAF9800049446000893 +:102730009451000A944F000C30CEFFFF001124008A +:1027400031E9FFFF11CD00A2008920253C030800DC +:102750008C6304443C1808008F18044000E85021A2 +:10276000255FFFFE007F78210000102101FF302B44 +:1027700003028821022648213C010800AC2F0444B2 +:102780003C010800AC29044024EB00083162FFFF43 +:102790003047000710E000038F8500182450000721 +:1027A0003202FFF83106FFFF30C8000700457021F4 +:1027B00031CD1FFF034D6021AF85001CAF8D001888 +:1027C000259B4000AF4D0084110000038F8F002037 +:1027D00024C400073086FFF88F84002800CF28210A +:1027E00000A4482B15200002AF8F002400A428234A +:1027F000AF850020AF4500803C1108008E310434C5 +:102800000345C0213402800003023021122000055C +:10281000AF860038938300172419000E1079000D3D +:10282000241F043F3C0A1000AF4A01788F8B00142C +:10283000256700010A0001DDAF8700140E0005A620 +:102840003C1040008F8B0014256700010A0001DE58 +:10285000AF8700143C0A1000A75F0148AF4A017817 +:102860000A0004B48F8B0014240E0F0011EE003DFB +:1028700030D10020162000022403000924030001A7 +:102880000A000208A743014A0A0001FBA7400146CB +:1028900094E5000894E2000A94EB000C8F86003C5B +:1028A0000002FC00316AFFFF30B9FFFF132600373A +:1028B00003EA20253C0508008CA504443C1F0800C1 +:1028C0008FFF04400000502100A8382100E8302B81 +:1028D00003EAC8210326C0213C010800AC270444B8 +:1028E0003C010800AC3804400A0002698F8D0018D2 +:1028F0003C1908008F39047C3C0308008C630454A5 +:102900003C0608008CC604783C0F08008DEF04508C +:10291000032838210068682100E8C02B00C4882102 +:1029200001A8402B01E470210238582101C8602120 +:102930003C010800AC2D04543C010800AC2C0450B0 +:102940003C010800AC27047C3C010800AC2B047857 +:102950000A0002698F8D0018A74001460A00041B77 +:102960008F8F001830D000201600FFC52403000D03 +:10297000240300050A000208A743014A97590104ED +:102980002738FFF00A00036B3304FFFF8F8C0040F1 +:10299000148CFFC8000080213C1108008E31046CAB +:1029A0003C0408008C8404680228702101C8782B3C +:1029B00000904021010F68213C010800AC2E046CFE +:1029C0003C010800AC2D04680A0002698F8D0018D4 +:1029D0008F9900401499FF5D000060213C050800BC +:1029E0008CA5046C3C1008008E10046800E82021BF +:1029F000248EFFFE00AEF82103EE582B020C50216E +:102A0000014B18213C010800AC3F046C3C0108005C +:102A1000AC2304680A00048B24EB00088F8800387C +:102A20003C02FFFF8D0E000C01C2682401A460254A +:102A3000AD0C000C0A00037930CFFFFF0A0003A998 +:102A4000AE000000974B0104920400048E2A000C93 +:102A500001644021251FFFF20147182433F9FFFFCD +:102A60000079C025AE38000C0A0002D48E1900107F +:102A70003C03FFFF8D1100100223282400A47825B9 +:102A8000AD0F00100A00037930CFFFFF9745010416 +:102A9000920600048E2F001000A610212449FFEE9C +:102AA00001E76824312EFFFF01AE6025AE2C001037 +:102AB0000A0002D48E1900108E06000CAE00000031 +:102AC0000003C080031088210A0002A6AE26002061 +:102AD0001460000D3050FFFF3C04FFFF00446024F1 +:102AE00001846826000D582B000C502B014B10243C +:102AF00010400002000000000000000D8CA3000048 +:102B00000A00023E006410253A11FFFF0011782BE5 +:102B10000010702B01CF2024108000020000000064 +:102B20000000000D8CB800000A00023E3702FFFFD3 +:102B30003084FFFF30A5FFFF108000070000182140 +:102B4000308200011040000200042042006518217C +:102B50001480FFFB0005284003E0000800601021FE +:102B600010C00007000000008CA2000024C6FFFF78 +:102B700024A50004AC82000014C0FFFB24840004E0 +:102B800003E000080000000010A0000824A3FFFFDD +:102B9000AC86000000000000000000002402FFFFDF +:102BA0002463FFFF1462FFFA2484000403E000089A +:102BB00000000000308EFFFF30D8FFFF00057C00D2 +:102BC00001F8602539CDFFFF01AC5021014C582B95 +:102BD000014B4821000944023127FFFF00E8302162 +:102BE0000006240230C5FFFF00A418213862FFFF51 +:102BF00003E000083042FFFF3C0C08008D8C048489 +:102C0000240BFF8027BDFFD001845021014B4824B5 +:102C1000AF4900203C0808008D080484AFB20020B2 +:102C2000AFB00018AFBF0028AFB30024AFB1001C95 +:102C3000936600040104382130E4007F009A1021DB +:102C40003C0300080043902130C500200360802130 +:102C50003C080111277B000814A0000226460070E2 +:102C60002646006C9213000497510104920F000451 +:102C70003267000F322EFFFF31ED004001C72823DD +:102C800011A0000500004821925900BC333800040F +:102C90001700009000000000924300BC307F000449 +:102CA00013E0000F0000000010A0000D0000000065 +:102CB000960E0002240AFF8000A7602125CDFFFEAA +:102CC000A74D1016920B0004014B2024308200FF08 +:102CD00010400085010C40253C0F0400010F4025E9 +:102CE0008F5301780660FFFE2404000AA7440140C8 +:102CF000960D00022404000931AC0007000C582393 +:102D0000316A0007A74A0142960200022443FFFEEF +:102D1000A7430144A7400146975F0104A75F01480C +:102D20008F590108333800205300000124040001AA +:102D3000920F000431EE001015C000023483001021 +:102D400000801821A743014A000000000000000095 +:102D50000000000000000000AF481000000000006C +:102D60000000000000000000000000008F51100073 +:102D70000621FFFE3113FFFF126000030000000078 +:102D80008F481018ACC8000096030006307FFFFF84 +:102D900027F900020019988200138880023B302135 +:102DA0008CD800001520005700183402920300044C +:102DB0002405FF8000A3F82433F100FF1220002C2B +:102DC00000000000924700BC30F2000212400028D0 +:102DD00000000000974B100C2562FFFEA742101662 +:102DE000000000003C0A040035490030AF491000E3 +:102DF00000000000000000000000000000000000D3 +:102E00008F4C10000581FFFE000000009749100C58 +:102E10008F51101C00C020213127FFFF24F2003009 +:102E2000001218820003288000BBF8213226FFFF21 +:102E3000AFF100000E00059500112C020013C880B0 +:102E4000033B98218E78000000027400AFB8001098 +:102E50008FA80010310FFFFFAFAF00108FA400103C +:102E600001C46825AFAD00108FA60010AE6600004B +:102E700097730008976D000A9766000C8F8A003CD4 +:102E8000000D5C0030CCFFFF3262FFFF104A0036BD +:102E9000016C2025960600023C10100024D3000887 +:102EA0000E0001393264FFFF974C01040E00014708 +:102EB0003184FFFFAF5001788FBF00288FB300240B +:102EC0008FB200208FB1001C8FB0001803E0000803 +:102ED00027BD003010A0FF700000000024A5FFFCFB +:102EE0000A0005CE240900048CD10000AF5110184F +:102EF0008F5301780660FF7A2404000A0A0005E374 +:102F00000000000000A7C8218F8800388F4E101CD9 +:102F10000019C0820018788001E82021AC8E0000E2 +:102F2000000E2C0200C020210E00059531C6FFFFC7 +:102F3000023B28218CAD00000002540000403021EB +:102F4000AFAD00108FAC0010318BFFFFAFAB0010A6 +:102F50008FA2001001424825AFA900108FA70010D2 +:102F60000A000613ACA700008F8F0040148FFFC922 +:102F70000000000097420104960B00023C05080087 +:102F80008CA5046C3049FFFF316AFFFF3C1108003B +:102F90008E310468012A382124F2FFFE00B240215C +:102FA0000012FFC30112C82B023FC02103192021C8 +:102FB0003C010800AC28046C3C010800AC24046807 +:102FC0000A00064D0000000000A4102B104000096C +:102FD000240300010005284000A4102B04A00003D6 +:102FE000000318405440FFFC000528401060000713 +:102FF000000000000085302B14C0000200031842BE +:10300000008520231460FFFB0005284203E0000830 +:10301000008010218F85002C27BDFFE80005302798 +:103020002CC300012CA400020083102510400003D3 +:10303000AFBF00102405007FAF85002C00052827B6 +:1030400030A5FFFF0E000574240426F58F830030A1 +:10305000240402BD004030210083382B10E0000919 +:1030600024050001000420400083102B048000038D +:10307000000528405440FFFC0004204010A0000838 +:1030800000C350210064402B1500000200052842B7 +:103090000064182314A0FFFB0004204200C3502149 +:1030A0008FBF0010000A4C02312200FF27BD00181C +:0C30B000AF8A002C03E00008AF8900305C +:0430BC000A00002ADC +:1030C00000000000000000000000000D7478703562 +:1030D0002E302E306A330000050000000000000A88 +:1030E000000001360000EA6000000000000000005F +:1030F00000000000000000000000000000000000D0 +:1031000000000000000000000000000000000000BF +:103110000000000000000000000000000000001699 +:10312000000000000000000000000000000000009F +:10313000000000000000000000000000000000008F +:10314000000000000000000000000000000000007F +:10315000000000000000138800000000000005DCF3 +:10316000000000000000000010000003000000004C +:103170000000000D0000000D3C02080024423B60EE +:103180003C03080024633D14AC4000000043202BA6 +:103190001480FFFD244200043C1D080037BD7FFC65 +:1031A00003A0F0213C100800261000A83C1C0800D9 +:1031B000279C3B600E0002BA000000000000000DDA +:1031C0008F8300383C088000350700708CE50000D4 +:1031D000008330253C02900000C22025AF850030DE +:1031E000AF4400208F4900200520FFFE3C038000F3 +:1031F000346200708C4500008F8600303C19080056 +:103200008F39007C3C0E08008DCE007800A620236C +:1032100003245821000078210164682B01CF60212C +:10322000018D50213C010800AC2B007C3C010800C2 +:10323000AC2A007803E00008000000000A0000410A +:10324000240400018F8400383C05800034A2000172 +:103250000082182503E00008AF43002003E00008C7 +:10326000000010213084FFFF30A5FFFF1080000711 +:1032700000001821308200011040000200042042AA +:10328000006518211480FFFB0005284003E00008BA +:103290000060102110C00007000000008CA2000098 +:1032A00024C6FFFF24A50004AC82000014C0FFFB6D +:1032B0002484000403E000080000000010A00008BF +:1032C00024A3FFFFAC860000000000000000000007 +:1032D0002402FFFF2463FFFF1462FFFA248400042A +:1032E00003E0000800000000308AFFFF93A80013ED +:1032F000A74A014497490E1630C600FF3C02100051 +:10330000A7490146AF450148A3460152A748015AC3 +:10331000AF4701608FA400188FA30014A744015881 +:10332000AF43015403E00008AF42017803E0000816 +:10333000000000003C038000346200708C490000F3 +:103340008F8800002484000727BDFFF83084FFF831 +:10335000AF890030974D008A31ACFFFFAFAC000061 +:103360008FAB0000016850232547FFFF30E61FFFA9 +:1033700000C4282B14A0FFF73C0C8000358B007094 +:103380008D6A00003C0708008CE700843C060800BA +:103390008CC6008000081082014918230002788042 +:1033A00000E370210000202101C3C82B00C4C0210C +:1033B00001FA4021031948212502400027BD0008D9 +:1033C0003C010800AC2E00843C010800AC290080C0 +:1033D00003E00008000000008F8200002486000740 +:1033E00030C5FFF800A2182130641FFF03E0000879 +:1033F000AF8400008F8700388F8A004027BDFFB858 +:103400008F860044AFB60040AFBF0044AFB5003C6C +:10341000AFB40038AFB30034AFB20030AFB1002C5E +:10342000AFB000288F4501048D4900ACAF47008044 +:103430008CC8002000A938230000B021AF480E102E +:103440008F440E1000004821AF440E148CC200249B +:10345000AF420E188F430E18AF430E1C10E001252B +:103460002D230001936B0008116000D400000000C0 +:10347000976E001031CDFFFF00ED602B158000CF5F +:103480000000000097700010320FFFFFAF4F0E00DA +:103490008F520000325100081220FFFD0000000092 +:1034A00097540E088F460E043285FFFF30B300019B +:1034B00012600132000000000000000D30B8A04092 +:1034C00024150040131500C030A9A0001120012DC3 +:1034D00000000000937F000813E0000800000000D7 +:1034E00097630010306BFFFF00CB402B11000003EF +:1034F00030AC00401180012300000000A785003C93 +:10350000AF8600349366000800E02821AFA70020B2 +:1035100014C0012427B30020AF60000C9782003C48 +:103520003047400014E00002240300162403000E7C +:1035300024194007A363000AAF790014938A003E60 +:103540008F740014315800070018AA400295902586 +:10355000AF7200149784003C8F70001430910010FB +:1035600002117825AF6F0014978E003C31CD000812 +:1035700011A00147000028218F6700143C021000B1 +:103580003C0C810000E22825AF65001497460E0A26 +:103590002408000E3405FFFC30C3FFFF006C5825E3 +:1035A000AF6B0004A3680002937F000A27E90004C0 +:1035B000A369000A9786003C9363000A30CC1F0081 +:1035C000000C598301634021251F0028A37F0009B7 +:1035D00097490E0CA769001093790009272A000269 +:1035E000315800070018A82332B10007A371000B5F +:1035F00093740009976400108F910034978F003CFA +:10360000329200FF024480210205702131ED00401A +:1036100011A0000531C4FFFF0091282B3C1280004F +:1036200010A000140000A0210224382B14E0011B7C +:103630008FA500208F4D0E14AF4D0E108F420E1C23 +:10364000AF420E18AF440E008F4F000031EE00085D +:1036500011C0FFFD0000000097540E080080882173 +:1036600000009021A794003C8F500E042414000108 +:10367000AF900034976400103095FFFF8E68000013 +:103680000111F82317E00009AE7F00008F650014D8 +:103690008F8B004434A60040AF6600148F4C0E1090 +:1036A000AD6C00208F430E18AD63002493670008B3 +:1036B00014E000D2000000000E00009E2404001060 +:1036C0008F8900483C08320000402821312600FF45 +:1036D0000006FC0003E8502525390001AF99004899 +:1036E000AC4A0000937800099370000A330400FF8D +:1036F00000047400320F00FF01CF6825AC4D0004B8 +:103700008F820048064000EAACA20008ACA0000C82 +:103710009783003C306B00081560000226280006E5 +:1037200026280002974E0E148F450E1C8F6700044A +:10373000936D000231C4FFFF31A200FFAFA2001061 +:103740008F6C0014AFA800180E00008BAFAC0014F3 +:10375000240400100E0000C7000000008E7200005C +:1037600016400005000000008F6400142405FFBF10 +:1037700000859824AF7300148F79000C033538212D +:10378000AF67000C9375000816A000080000000049 +:1037900012800006000000008F7F00143C0BEFFF3A +:1037A0003568FFFE03E84824AF690014A3740008DD +:1037B0008FA500200A00024602202021AF470E00FC +:1037C0000A0000F5000000008F5901780720FFFE75 +:1037D000241F08008F840000AF5F0178974B008A98 +:1037E000316AFFFF014448232528FFFF31021FFFF4 +:1037F0002C4300081460FFF9000000008F8E004881 +:103800008F8D003800C048210344202125C60001C7 +:10381000240C0F00AF86004800E9382324864000BE +:1038200031CA00FF11AC0005240800019391003E4D +:103830003230000700107A4035E80001000AAC0081 +:103840003C18010002B8A025AC9440008F930048BA +:1038500030B2003630A40008ACD3000410800097CA +:1038600001123025974E0E0A8F8D00003C02810018 +:1038700031CCFFFF25AB0008018240253C0310003E +:1038800031651FFF25390006241F000EAF48016077 +:1038900000C33025A75F015AAF850000A759015822 +:1038A00014E0000A8F93003824120F0052720002B5 +:1038B0002416000134C600408F580E108F94004427 +:1038C000AE9800208F550E18AE9500248F450E142B +:1038D000AF4501448F590E1CAF590148A34A01520C +:1038E0003C0A1000AF460154AF4A017814E0FEDDF7 +:1038F0002D2300010076A025128000178FBF004401 +:103900008F84003824160F001096008400000000F9 +:103910008F45017804A0FFFE24150F001095006E5E +:10392000000000008F470E14240202403C1F1000CC +:10393000AF4701448F440E1CAF440148A3400152DD +:10394000A740015AAF400160A7400158AF4201545F +:10395000AF5F01788FBF00448FB600408FB5003C49 +:103960008FB400388FB300348FB200308FB1002C89 +:103970008FB0002803E0000827BD004814C0FED027 +:1039800030B8A0408F420E148F84004400004821BC +:10399000AC8200208F510E1CAC9100240A00020E54 +:1039A0002D2300018F910034978A003C3C12800047 +:1039B0000220A821315800401700FF300000A0214C +:1039C000976900108F9200343139FFFF13320035B0 +:1039D00000002021008048211480FEA000A0382192 +:1039E0008F420E148F840044AC8200208F510E1C35 +:1039F000AC9100240A00020E2D230001936A0009F5 +:103A00009378000B315000FF330F00FF020F70213D +:103A100025C2000A3050FFFF0E00009E0200202148 +:103A20008F8600483C1F410024CD0001AF8D004827 +:103A3000936C000930C600FF00064400318300FF8C +:103A4000246B0002010B4825013FC825AC5900003A +:103A50008F67000C97440E1400F22825AC45000433 +:103A60008F450E1C8F670004936A00023084FFFFAD +:103A7000315800FFAFB800108F6F0014AFB10018BD +:103A80000E00008BAFAF00140A0001A60200202137 +:103A9000AF6000040A00013EA36000020A00024673 +:103AA00000002021000090210A0001702414000170 +:103AB0003C1280000A000195ACB2000C8F9100000E +:103AC00025240002A744015826300008320F1FFFAA +:103AD0000A0001F9AF8F0000AF40014C1120002C0B +:103AE000000000008F590E10AF5901448F430E188B +:103AF000240200403C1F1000AF430148A340015284 +:103B0000A740015AAF400160A7400158AF4201549D +:103B1000AF5F01780A0002278FBF00441120000622 +:103B20000000000097460E0830CC004015800002CF +:103B3000000000000000000D8F4D017805A0FFFE81 +:103B40000000000097530E103C120500240E2000C8 +:103B5000326AFFFF0152C025AF58014C8F4F0E143F +:103B60003C021000AF4F01448F500E1CAF50014873 +:103B7000A34001528F840038A740015AAF40016032 +:103B8000A7400158AF4E01540A000215AF42017818 +:103B90008F490E14AF4901448F430E1C0A00028E58 +:103BA000240200403C0E20FF27BDFFE03C1A8000AD +:103BB0003C0F800835CDFFFDAFBF001CAFB2001831 +:103BC000AFB10014AFB00010AF8F0040AF4D0E008A +:103BD00000000000000000000000000000000000E5 +:103BE000000000003C0C00FF358BFFFDAF4B0E00CA +:103BF0003C0660048CC95000240AFF7F3C11600021 +:103C0000012A40243507380CACC750008E240438F4 +:103C100024050009AF4500083083FFFF38622F718B +:103C20002450C0B3AF8000480E000068AF80000091 +:103C300052000001AE20442C0E0004353C118000DF +:103C40000E000EA8363000708F8A00403C1208002B +:103C500026523BC8020088218E0800008F5F0000BA +:103C60003BF900013338000113000017AF88003022 +:103C7000022048218D2700003C0F08008DEF006CCA +:103C80003C0C08008D8C006800E8C02301F8282156 +:103C90000000682100B8302B018D582101664021B9 +:103CA0003C010800AC25006C3C010800AC28006811 +:103CB0008F44000038830001306200011440FFEDA2 +:103CC00000E04021AF8700308E0C00003C0508006A +:103CD0008CA5006C3C0408008C84006801883023AB +:103CE00000A638210000102100E6402B0082182198 +:103CF0000068F8213C010800AC27006C3C0108007A +:103D0000AC3F00688F49010025590088AF990044F5 +:103D1000AF890038AF4900208E070000AF87003020 +:103D20008F4D017805A0FFFE000000008E06000008 +:103D30003C0B08008D6B00743C0408008C84007000 +:103D400000C728230165F8210000102103E5402B5E +:103D50000082382100E8C821240908003C0108003D +:103D6000AC3F00743C010800AC390070AF490178E9 +:103D700093580108A398003E938F003E31EE000156 +:103D800015C000158F830038240E0D00106E001929 +:103D9000240F0F00106F001D00000000915900005B +:103DA00024180050332900FF113800043C1F400044 +:103DB000AF5F01380A0002E7000000000E0008EEC5 +:103DC000000000008F8A00403C1F4000AF5F0138B8 +:103DD0000A0002E700000000938D003E31AC0006AF +:103DE000000C51000E0000CE0152D8210A000343FE +:103DF0008F8A00403C1B0800277B3C480E0000CE09 +:103E0000000000000A0003438F8A00403C1B0800AA +:103E1000277B3C680E0000CE000000000A00034330 +:103E20008F8A004090AA00018FAB00108CAC00106C +:103E30003C0300FF8D680004AD6C00208CAD0014C5 +:103E400000E060213462FFFFAD6D00248CA70018F4 +:103E50003C09FF000109C024AD6700288CAE001C9E +:103E60000182C82403197825AD6F0004AD6E002CC3 +:103E70008CAD0008314A00FFAD6D001C94A9000212 +:103E80003128FFFFAD68001090A70000A560000278 +:103E9000A1600004A167000090A30002306200FF4F +:103EA0000002198210600005240500011065000E53 +:103EB0000000000003E00008A16A00018CD800287F +:103EC000354A0080AD7800188CCF0014AD6F001417 +:103ED0008CCE0030AD6E00088CC4002CA16A0001AD +:103EE00003E00008AD64000C8CCD001CAD6D001823 +:103EF0008CC90014AD6900148CC80024AD6800089A +:103F00008CC70020AD67000C8CC200148C83006449 +:103F10000043C82B13200007000000008CC20014CF +:103F2000144CFFE400000000354A008003E0000864 +:103F3000A16A00018C8200640A000399000000005D +:103F400090AA000027BDFFF88FA9001CA3AA0000BB +:103F50008FAE00003C0FFF808FA8001835E2FFFFF6 +:103F60008CCD002C01C26024AFAC0000A120000465 +:103F700000E06021A7A000028FB800008D27000498 +:103F80000188182100A0582100C05021006D28266A +:103F90003C06FF7F3C0F00FF2CAD000135EEFFFF1C +:103FA00034D9FFFF3C02FF0003193024000D1DC06F +:103FB000010EC82400E2C02400C37025031978252F +:103FC000AD2E0000AD2F00048D450024AFAE0000E3 +:103FD000AD2500088D4D00202405FFFFAD2D000C00 +:103FE000956800023107FFFFAD27001091660018A9 +:103FF00030C200FF000219C2506000018D4500343C +:10400000AD2500148D67000827BD0008AD27001CF2 +:104010008C8B00CCAD2C0028AD20002CAD2B0024C7 +:10402000AD20001803E00008AD20002027BDFFE010 +:10403000AFB20018AFB10014AFB00010AFBF001C9A +:104040009098000000C088213C0D00FF330F007FD6 +:10405000A0CF0000908E000135ACFFFF3C0AFF00AE +:10406000A0CE000194A6001EA22000048CAB001478 +:104070008E29000400A08021016C2824012A4024FC +:104080000080902101052025A6260002AE24000410 +:1040900026050020262400080E00007624060002D3 +:1040A00092470000260500282624001400071E0061 +:1040B0000003160324060004044000032403FFFF4A +:1040C000965900023323FFFF0E000076AE23001046 +:1040D000262400248FBF001C8FB200188FB100145B +:1040E0008FB0001024050003000030210A0000807A +:1040F00027BD002027BDFFD8AFB1001CAFB000180E +:10410000AFBF002090A80000240200018FB0003C47 +:104110003103003F00808821106200148FAA00380C +:10412000240B0005506B0016AFAA001000A0202140 +:1041300000C028210E0003DC02003021922400BCC4 +:10414000308300021060000326060030ACC000007F +:1041500024C600048FBF00208FB1001C8FB0001850 +:1041600000C0102103E0000827BD002801403821CD +:104170000E00035AAFB000100A0004200000000037 +:104180000E0003A1AFB000140A00042000000000DC +:104190003C02000A034218213C04080024843CAC81 +:1041A0002405001A000030210A000080AF8300546B +:1041B0003C038000346200708C48000000A058214D +:1041C00000C04821308A00FFAF8800308F4401785A +:1041D0000480FFFE3C0C8000358600708CC500001A +:1041E0003C0308008C6300743C1808008F180070B2 +:1041F00000A82023006468210000C82101A4782BB6 +:104200000319702101CF60213C010800AC2D00741E +:104210003C010800AC2C00708F480E14AF480144DC +:10422000AF47014CA34A0152A74B015893460108DE +:1042300030C5000854A0000135291000934B090037 +:1042400024070050316A00FF1147000700000000FA +:104250008F450E1CAF450148AF4901543C09100081 +:1042600003E00008AF490178934D010831A8000828 +:104270001100001000000000934F010831EE001003 +:1042800051C00001352900083C04080090843D100D +:10429000A34401508F4309A4AF4301488F4209A0B2 +:1042A000AF420144AF4901543C09100003E000084B +:1042B000AF4901783C1908008F393CCC33380008ED +:1042C0005700FFF1352900080A00047300000000C0 +:1042D00024070040AF470814AF4008108F4209443C +:1042E0008F4309508F4409548F45095C8F46094C10 +:1042F000AF820064AF830050AF84004CAF85005C98 +:1043000003E00008AF8600609346010930C5007FD6 +:10431000000518C0000521400083102103E00008BB +:10432000244200883C0A0800914A3CD13C0908001C +:1043300095293CCA3C051100000A3C0025280002D2 +:1043400000E8302500C5182524820008AC83000051 +:1043500003E00008AC8000048F4A002C974E090847 +:104360003C0F000E034F382131CDFFFF000D41C03F +:10437000AF48002C9743090894EC001A00804021B4 +:1043800024020001318BFFFFAC8B00008CE9001C84 +:1043900000A0582100C06021AC8900048CE40020FA +:1043A000AD04000890E30019306300031062004080 +:1043B000000000002865000214A00073240600021B +:1043C0001066004E0000000024180003107800570B +:1043D000000000003C09080095293CC093450934C1 +:1043E000934609213C0E080095CE3CC630A200FF42 +:1043F0000002C88294E5002A30C400FF9787005865 +:104400000019C60000041C00312FFFFF0303102514 +:1044100001CF6821004DC82500A720213C0640009F +:104420000326C02500044C00AD090004AD180000AF +:10443000934F09203C03000625090014000F760065 +:1044400001C36825AD0D00088F42092C24E5000149 +:1044500030A67FFFAD02000C8F59093025020028DD +:10446000A7860058AD1900108F440938AD04001418 +:10447000AD2B00048F580940AD380008934F093721 +:104480003C0D080091AD3CD0AD20001031EE00FF96 +:1044900001CC182100036700000D44000188582555 +:1044A0003567FFFFAD27000C03E00008AF4A002C82 +:1044B0003C09080095293CC03C05080094A53CCA6D +:1044C0003C0F080095EF3CBC94E400243126FFFF2C +:1044D00000A6702101CF682300041C0025A2FFF272 +:1044E0000062C82524180800AD19000CAD1800148E +:1044F000AD0000100A0004C82508001894E6002446 +:1045000094E500283C09080095293CC000067C0081 +:104510000005740035ED810035C40800AD0D000CB8 +:10452000AD0400100A0004C8250800143C09080066 +:1045300095293CC03C02080094423CCA3C06080055 +:1045400094C63CBC94E400243125FFFF94F8002875 +:104550000045C8210326782300181C0000046C00C5 +:1045600025EEFFEE006EC82535A281002418080054 +:10457000AD02000CAD190010AD180018AD0000140C +:104580000A0004C82508001C1460FF920000000007 +:1045900094E300243C09080095293CC00003140062 +:1045A00034590800AD19000C0A0004C82508001091 +:1045B00003E00008240201F427BDFFE8AFB00010BB +:1045C000AFBF00140E000060008080212405004071 +:1045D000AF4508148F8300508F84004C8F85005C9A +:1045E000007018210064102318400004AF830050AD +:1045F000AF6300548F660054AF86004C1200000C6D +:10460000000000008F440074936800813409FA00B0 +:104610002D07000710E0000500891021936C008130 +:10462000240B01F4018B500401441021AF62000CF3 +:104630008F4E095C01C5682319A000048FBF0014C8 +:104640008F4F095CAF8F005C8FBF00148FB00010DC +:104650000A00006227BD00188F8400648F83005019 +:104660008F82004CAF640044AF63005003E0000849 +:10467000AF6200543C038000346200708C43000041 +:1046800027BDFFF8308700FF30A900FF30C800FFCA +:10469000AF8300308F4401780480FFFE3C0280002D +:1046A000345900708F380000A3A700033C070800AE +:1046B0008CE700748FAC00003C0608008CC60070CC +:1046C000030378233C0E7FFF00EFC82135CDFFFFA9 +:1046D00000005021018D282400CA1821000847C07D +:1046E000032F202B00A810250064C021AFA20000DA +:1046F0003C010800AC3900743C010800AC38007083 +:10470000934F010AA3A000023C0E80FFA3AF00015B +:104710008FAC0000312B007F35CDFFFF018D482489 +:10472000000B5600012A4025240730002406FF8094 +:104730003C05100027BD0008AF48014CAF470154AD +:10474000A7400158A346015203E00008AF45017895 +:1047500027BDFFE8AFBF0014AFB000108F65007435 +:104760003C068000309000FF00A620250E0000606F +:10477000AF64007493630005346200080E000062A9 +:10478000A3620005020020218FBF00148FB000102B +:1047900024050005240600010A00056E27BD001847 +:1047A00027BDFFE03C038000AFB00010AFBF001892 +:1047B000AFB10014346200708C470000309000FFED +:1047C00030A800FFAF8700308F4401780480FFFEDF +:1047D0003C188000371100708E2F00003C0D08003F +:1047E0008DAD00743C0A08008D4A007001E770230B +:1047F00001AE28210000582100AE302B014B48218A +:10480000012638213C010800AC25007400008821F5 +:104810003C010800AC2700701100000F00000000F0 +:104820008F6200742619FFFF3208007F0002FE022B +:1048300033E5007F15000006332200FF2407FF80C8 +:104840000207202624A3FFFF00838025320200FFF9 +:1048500000408021241110080E00006000000000BC +:104860008F4908183125000414A0FFFD3218007F7D +:10487000001878C00018714001CF682125AC00886D +:10488000AF4C0818274A09808D4B0020AF4B0144DC +:104890008D460024AF460148A35001500E0000622F +:1048A000A7400158022010218FBF00188FB10014BB +:1048B0008FB0001003E0000827BD002027BDFFE8EF +:1048C000308400FFAFBF00100E0005B930A500FF17 +:1048D0008F8300508FBF0010344500402404FF90A8 +:1048E0003C02100027BD0018AF43014CA344015205 +:1048F000AF45015403E00008AF4201789343093EFD +:10490000306200081040000D3C0901013528080AFA +:10491000AC8800008F470074AC8700043C06080098 +:1049200090C63CD030C5001050A00006AC800008F6 +:104930008F6A0060AC8A00082484000C03E0000841 +:10494000008010210A0006202484000C27BDFFE807 +:10495000AFBF0014AFB000109346093F00A0502134 +:10496000000528800085382330C200FF240300069C +:104970003C09080095293CC624E8FFD8240500041A +:1049800010430037240600029750093C3C0F0204F4 +:1049900000063400320EFFFF01CF6825AC8D000009 +:1049A000934C093E318B002011600008000000008C +:1049B000934309363C020103345F0300307900FF62 +:1049C000033FC02524050008AC9800049343093434 +:1049D000935909210005F882306200FF0002C0826D +:1049E000332F00FF00186E00000F740001AE602529 +:1049F000018920253C09400000898025ACF0FFD8C2 +:104A0000934309378F4F09488F580940306200FFA0 +:104A1000004AC821033F702101F86023000E6F0097 +:104A200001A650253185FFFF001F5880014548250C +:104A300001683821AD0900200E00006024F0002834 +:104A4000240400040E000062A364003F0200102151 +:104A50008FBF00148FB0001003E0000827BD0018BE +:104A60000A0006332406001227BDFFD024090010D7 +:104A7000AFB60028AFB50024AFB40020AFB100142A +:104A8000AFB000103C010800A0293CD0AFBF002C03 +:104A9000AFB3001CAFB2001897480908309500FF6B +:104AA0003C02000E3107FFFF000731C0AF46002C6B +:104AB000974409089344010B30B400FF034280215E +:104AC000308300300000B021106001070000882111 +:104AD000240C00043C010800A02C3CD0934B093E60 +:104AE000000B5600000A2E0304A0014B000000003A +:104AF000AF400048934F010B31EE002011C000067B +:104B0000000000009358093E00189E000013960311 +:104B10000640016B000000009344010B308300400D +:104B2000106000038F9300508F8200502453FFFFCA +:104B30009347093E30E6000814C000022412000327 +:104B4000000090219619002C93580934934F09378F +:104B5000A7990058330C00FF31EE00FF024E682188 +:104B6000000D5880016C5021015140213C0108008A +:104B7000A4283CC69205001830A900FF010918219D +:104B80003C010800A4233CC8921100181620000321 +:104B90002467000A0000000D2467000A30F0FFFFC0 +:104BA0003C010800A4233CCA3C010800A4203CC0EE +:104BB0003C010800A4203CBC0E00009E0200202105 +:104BC0000E00049A004020218F4B002C974A0908C0 +:104BD0003C0C000E034C38213145FFFF000549C055 +:104BE000AF49002C9743090894F1001A0040402176 +:104BF000241F00013226FFFFAC4600008CE2001C9F +:104C0000AD0200048CE40020AD04000890E300191C +:104C100030630003107F00D6286D000215A0011C30 +:104C2000240E0002106E010E240F0003106F00E32B +:104C3000000000003C09080095293CC0934E09344F +:104C4000935109213C0A0800954A3CC631CD00FF2A +:104C500094F9002A000D188297870058322C00FF23 +:104C600000032E00000C24003126FFFF3142FFFF1D +:104C700000A4F8250046482103E978250327702180 +:104C80003C18400001F86825000E8C00AD0D0000B6 +:104C9000AD110004934C09203C03000625110014BB +:104CA000000C2E0000A31025AD0200088F49092C2E +:104CB00024E40001309F7FFFAD09000C8F460930CE +:104CC00025090028A79F0058AD0600108F59093804 +:104CD00001203021AD190014AE3300048F58094073 +:104CE000AE380008934F09373C0C0800918C3CD03B +:104CF000AE20001031EE00FF01D26821000D2F0020 +:104D0000000C1C0000A310253447FFFFAE27000C49 +:104D1000AF4B002C934B093E317300081260000D1D +:104D20003C0F010135E7080AAD0700288F4B0074DE +:104D3000AD2B00043C13080092733CD03268001085 +:104D400051000003AD2000088F780060AD380008E6 +:104D50002526000C12C0003800000000935F093FB8 +:104D6000241600062407000433F900FF133600D28E +:104D7000240800029743093C3C0C02043064FFFF06 +:104D8000008C2825ACC500009342093E3049002024 +:104D90001120000800000000934B09363C1301036A +:104DA000366E0300316D00FF01AE8825ACD10004E2 +:104DB000240700089349093493590921314BFFFF17 +:104DC000313F00FF001FB082333800FF001656004D +:104DD00000187C00014F982500122880026B68257E +:104DE0003C0E400000C5502301AE8825AD51FFD8D0 +:104DF000934309378F5F09488F490940306C00FFA2 +:104E000001921021000720820044C82103E9782381 +:104E10000019C7000008B4000316402531E7FFFF62 +:104E2000010730250E000060AD46FFF82412000493 +:104E30000E000062A372003F0E0000C70200202196 +:104E40003C12080092523CD0325000031200000F76 +:104E500002A020218F82005024470001AF8700501C +:104E6000AF6700508F6800540107302318C000025C +:104E700000E020218F640054AF6400548F4C007414 +:104E8000258401F4AF64000C02A0202102802821B7 +:104E9000A76000680E0005B93C1410008F8D00500B +:104EA00034550006AF4D014C8F9100488FBF002C48 +:104EB0008FB6002826230001AF8300488FB3001C63 +:104EC000A35101528FB20018AF5501548FB1001495 +:104ED000AF5401788FB500248FB400208FB000103C +:104EE00003E0000827BD00309358093E00189E00DB +:104EF0000013960306420051241100029344092333 +:104F0000308300021060FEFB8F8600608F820050AD +:104F100014C2FEF8000000000E0000600000000057 +:104F20009369003F24070016312800FF1107000C89 +:104F3000240500083C0C0800918C3CD0358B000106 +:104F40003C010800A02B3CD0936A003F314300FF96 +:104F500010650065240D000A106D005E2402000C2F +:104F60000E000062000000000A00068E0000000033 +:104F70003C09080095293CC03C04080094843CCAC4 +:104F80003C1F080097FF3CBC94F800243123FFFF2E +:104F90000083C821033F782300186C0025EEFFF240 +:104FA00001AE6025240A0800AD0C000CAD0A001407 +:104FB000AD0000100A0006E0250800183C090800B2 +:104FC00095293CC03C1F080097FF3CCA3C190800CB +:104FD00097393CBC94EF00243124FFFF94EE002865 +:104FE00003E4C02103196823000F2C00000E5400B5 +:104FF00025ACFFEE014C882534A281002406080070 +:10500000AD02000CAD110010AD060018AD0000148B +:105010000A0006E02508001C8F6E00848F4D0940B1 +:1050200011A0FEB3AF8E0050240F00143C01080005 +:10503000A02F3CD00A00068D000000003C010800B3 +:10504000A0313CD0935F093E2416000133F90020C3 +:105050001720FEA8241100080A00068E241100045F +:1050600094E5002494F100283C09080095293CC0EF +:1050700000051400001134003444810034C30800DA +:10508000AD04000CAD0300100A0006E02508001472 +:105090001460FEE80000000094FF00243C090800B2 +:1050A00095293CC0001FCC0037380800AD18000C13 +:1050B0000A0006E0250800100A00072E2408001246 +:1050C0008F7F004CAF7F00548F7900540A00069701 +:1050D000AF790050A362003F0E00006200000000A4 +:1050E0000A00068E00000000240200140A000807CF +:1050F000A362003F27BDFFE8308400FFAFBF001070 +:105100000E0005B930A500FF9378007E9379007FEB +:10511000936E00809368007A332F00FF00186600BA +:10512000000F6C0031CB00FF018D4825000B5200B1 +:105130008FBF0010012A3825310600FF344470006B +:1051400000E628252402FF813C03100027BD00183B +:10515000AF45014CAF440154A342015203E00008A3 +:10516000AF43017827BDFFD8AFB20018AFB100142C +:10517000AFB00010AFBF0020AFB3001C93420109D5 +:10518000308600FF30B000FF000618C23204000273 +:105190003071000114800005305200FF9367000554 +:1051A00030E5000810A0000D30C80010024020219A +:1051B0000E0005A502202821240400018FBF002035 +:1051C0008FB3001C8FB200188FB100148FB0001085 +:1051D0000080102103E0000827BD002815000032E0 +:1051E0000000000093430109000028213062007F85 +:1051F000000220C00002F94003E4982126790088CB +:10520000033B98218E7800248E6F0008130F004610 +:10521000000000008F640084241800020004FD8256 +:1052200033F900031338007C00000000936600830C +:10523000934A0109514600043205007C10A0006029 +:10524000000000003205007C14A000530240202121 +:1052500016200006320400018E7F00248F590104BD +:1052600017F9FFD600002021320400011080000A47 +:10527000024020218F4209408F93006410530006A2 +:10528000000000000E00066B022028218F43094019 +:10529000AF630044024020210E00060002202821B6 +:1052A0000A000840240400013C0908008D2900641C +:1052B000252600013C010800AC26006416000012FF +:1052C000000000008F6D00843C0E00C001AE602421 +:1052D00015800005024020210E00080E0220282122 +:1052E0000A00084024040001240500040E00056E95 +:1052F00024060001024020210E00080E0220282171 +:105300000A000840240400010E00004124040001AA +:10531000936B007D020B50250E000062A36A007D96 +:105320000A0008838F6D00848F6600748F48010423 +:105330008E67002400064E021507FFB63126007F57 +:10534000936B008326440001308A007F114600439E +:10535000316300FF5464FFB08F6400842645000170 +:1053600030B1007F30A200FF1226000424050001A6 +:10537000004090210A00085624110001240FFF80EC +:10538000024F702401CF9026324200FF004090214E +:105390000A000856241100010E00066B0220282185 +:1053A000321800301300FFAA321000820240202180 +:1053B0000E0005A5022028210A000840240400014F +:1053C0008F6E00743C0F80002405000301CF9025F0 +:1053D000AF72007493710083240600010E00056E05 +:1053E000322400FF0E00004124040001936D007D73 +:1053F000020D60250E000062A36C007D3C0B0800CE +:105400008D6B0054257000013C010800AC30005445 +:105410000A000840240400018F6800743C098000E1 +:105420002405000401093825AF67007493630083E5 +:10543000240600010E00056E306400FF0E000041DE +:10544000240400019362007D020298250E00006290 +:10545000A373007D0A00084024040001324D00803F +:1054600039AC0080546CFF6C8F6400840A0008A97A +:105470002645000127BDFFC83C0A0008AFBF003029 +:10548000AFB5002CAFB40028AFB30024AFB20020FA +:10549000AFB1001CAFB00018034AD8212409004066 +:1054A000AF490814AF4008108F4209448F43095098 +:1054B0008F4609548F47095C8F48094C9344010873 +:1054C0009345010BAF820064308400FF30A500FFDC +:1054D000AF830050AF86004CAF87005C0E00082AF7 +:1054E000AF880060144001748FBF0030A76000686F +:1054F000934D0900240B00503C15080026B53C884C +:1055000031AC00FF3C12080026523C98118B00037E +:10551000000000000000A821000090219351010923 +:105520008F9F005024040010322E007F000E68C0B0 +:10553000000E6140018D282124B40088AF54081862 +:105540008F4901048F4A09A43C0B000E034BC02174 +:10555000012A10233C010800AC223CAC8F430958BF +:105560003C010800A0243CD097470908007F302365 +:105570003C010800AC263CB030E8FFFF0008C9C081 +:105580003C010800AC3F3CD4AF59002C97420908BD +:105590009710002C8EB10000930F0018037498210F +:1055A000A7900058AF9300440220F80931F000FFA3 +:1055B000304E000215C001A9304F000111E0015D1D +:1055C000000000009343093E3066000814C000024A +:1055D000241400030000A0218F5809A42413000103 +:1055E0003C010800AC383CD8934F0934935109373B +:1055F00031EC00FF322E00FF028E6821000D288062 +:1056000000AC5021015058213C010800A42B3CC89B +:105610003C010800A42A3CC693490934312200FF0A +:1056200002022021249000103C010800A4303CC458 +:10563000240700068F9F00503C010800AC273CCC9B +:105640008F88005C8F59095800008021011F282392 +:1056500004A00151033F20230480014F00A4302BFC +:1056600010C00151000000003C010800AC253CB016 +:105670008E4200000040F8090000000030430002A4 +:10568000146000F100408821304400015480001073 +:105690008E4200043C0908008D293CB43C0AC0003D +:1056A000012A8025AF500E008F45000030AB000866 +:1056B0001160FFFD00000000974D0E08241000014E +:1056C000A78D003C8F4C0E04AF8C00348E4200043A +:1056D0000040F8090000000002228825322E000256 +:1056E00015C0016F000000003C09080095293CBC72 +:1056F0003C06080094C63CC83C04080094843CBEA8 +:105700003C1808008F183CB4012658213C0F0800B3 +:105710008DEF3CD83C1F080097FF3CD20164182154 +:105720008F4D09400309C821246E0002033F282140 +:1057300001F860213C010800A42B3CCAAF8D006435 +:105740003C010800AC2C3CD83C010800A4253CC01E +:105750000E00009E31C4FFFF8F87004800402021CB +:105760003C010800A0273CD18E42000824E800013B +:10577000AF8800480040F809000000008F4B002C63 +:10578000974909083C0A000E034A38213124FFFFDB +:10579000000419C08F8A0050AF43002C97430908BA +:1057A00094E6001A0040402130DFFFFFAC5F0000AC +:1057B0008CF9001CAC5900048CF80020AC5800088F +:1057C00090EF001931E30003107300FB00000000AC +:1057D0002862000214400117240500021065010927 +:1057E000240C0003106C00BC000000003C09080001 +:1057F00095293CC0935F0934934C09213C0D080066 +:1058000095AD3CC633F900FF94E5002A0019C0822B +:10581000318F00FF978C005800181600000F74009D +:105820003124FFFF004E382501A4302100E6F82581 +:1058300000ACC8213C03400003E3C02500194C0024 +:10584000AD180000AD090004934F09203C0E00067E +:1058500025090014000F6E0001AE2825AD050008D3 +:105860008F46092C2582000130477FFFAD06000CD2 +:105870008F440930A787005825060028AD04001082 +:105880008F43093800C02021AD030014AD2A000465 +:105890008F5F0940AD3F0008935909373C0E08005F +:1058A00091CE3CD0AD200010333800FF0314782196 +:1058B000000F6700000E6C00018D282534A2FFFF49 +:1058C000AD22000CAF4B002C9347093E30EA000894 +:1058D0005140000F8E58000C3C0301013469080A46 +:1058E000AD0900288F4A0074ACCA00043C0B0800C4 +:1058F000916B3CD03168001051000003ACC000082F +:105900008F650060ACC5000824C4000C8E58000CE4 +:105910000300F809000000003C0F080095EF3CCAA6 +:105920003C02080094423CBE01E2702125C4000202 +:105930000E0000C73084FFFF3C0608008CC63CAC5C +:105940003C0D08008DAD3CB400CD38233C0108006F +:10595000AC273CAC14E00006000000003C19080035 +:105960008F393CCC372C00403C010800AC2C3CCC9F +:10597000120000858F8B00448F480E108F900044DA +:10598000AE0800208F5F0E18AE1F00243C100800E8 +:1059900096103CC00E00006000000000240500408E +:1059A000AF4508148F8300508F89004C0070182178 +:1059B0000069502319400004AF830050AF630054C6 +:1059C0008F670054AF87004C1200000C00000000ED +:1059D0008F440074936D0081340EFA002DA60007E9 +:1059E00010C00005008E182193780081240201F474 +:1059F0000302780401E41821AF63000C8F4C095CAA +:105A00008F99005C0199202318800003000000009A +:105A10008F50095CAF90005C0E0000620000000037 +:105A20008F8B00508E4800103C010800AC2B3CD4FA +:105A30000100F809000000003C1F08008FFF3CAC8B +:105A400017E0FEFC240700068F4500249742090852 +:105A50008F8A00648F9400503C0F001F9787005876 +:105A60008F8300548F93004C304DFFFF35EEFF8045 +:105A700000AE4824000D31C032320010AF46002481 +:105A8000A467002CAF490024AF6A0044AF740050F3 +:105A9000AF7300545640007E8EB80004322400409C +:105AA000548000328EB100088EAC000C0180F809E1 +:105AB000000000008FBF00308FB5002C8FB400288D +:105AC0008FB300248FB200208FB1001C8FB000185C +:105AD00003E0000827BD00383C09080095293CC0B8 +:105AE0003C04080094843CCA3C1F080097FF3CBC5F +:105AF00094F800243123FFFF94EF00280083C8218D +:105B0000033F702300182C00000F640025CDFFEE2A +:105B1000018D302534A2810024030800AD02000C61 +:105B2000AD060010AD030018AD0000140A0009CE48 +:105B30002508001C934701098F8800380007FE00E4 +:105B400003E8C825AF5900808F5809A08F5309A4D6 +:105B5000AFB80010AF580E148FB40010AF540E1031 +:105B6000AF530E1C0A000942AF530E180220F80969 +:105B7000000000008EAC000C0180F809000000005D +:105B80000A000A7F8FBF0030A5600020A5730022A5 +:105B90000A000A34AD7300243C010800AC203CB07C +:105BA0000A00096E8E4200003C010800AC243CB0A3 +:105BB0000A00096E8E4200003C09080095293CC08D +:105BC0003C1F080097FF3CCA3C19080097393CBCB1 +:105BD00094EF00243124FFFF03E4C0210319702354 +:105BE000000F640025CDFFF2018D2825AC45000C87 +:105BF00024020800AD020014AD0000100A0009CE16 +:105C00002508001894E6002494E300283C090800C5 +:105C100095293CC0000624000003FC003499810053 +:105C200037F80800AD19000CAD1800100A0009CEB5 +:105C3000250800141460FEED0000000094EF00241D +:105C40003C09080095293CC0000F740035CD0800C0 +:105C5000AD0D000C0A0009CE250800109352010971 +:105C6000000028210E000600324400FF8FBF0030E4 +:105C70008FB5002C8FB400288FB300248FB2002082 +:105C80008FB1001C8FB0001803E0000827BD00385A +:105C90000300F809000000000A000A7932240040DD +:105CA0001200FF69000000008F540E148F92004410 +:105CB000AE5400208F530E1C0A000A63AE5300241A +:105CC0008F82001C008040213C0401009047008529 +:105CD00030E3002010600009000000003C070800CD +:105CE0008CE73CD48F83001800E320230480000855 +:105CF0009389000414E300030100202103E000085D +:105D0000008010213C04010003E000080080102105 +:105D10001120000B006738238F8C002024090034E9 +:105D2000918B00BC316A000251400001240900300F +:105D300000E9682B15A0FFF10100202100E93823BC +:105D40002419FFFC00B9C02400F9782400F8702B56 +:105D500015C0FFEA01E8202130C200030002182329 +:105D600014C00012306900030000302100A9702126 +:105D700001C6682100ED602B1180FFE03C040100AA +:105D80002D2F00010006482B0105382101E93024A0 +:105D900014C0FFDA24E4FFFC2419FFFC00B9C0247E +:105DA0000308202103E00008008010218F8B0020D1 +:105DB00024060004916A00BC314400041480FFEC06 +:105DC00000A970210A000B2D0000302127BDFFE83B +:105DD000AFBF00108F460100934A01093C1F080025 +:105DE0008FFF00902407FF80314F00FF31E8007FD4 +:105DF0000008614003E6C821032CC02127090120C7 +:105E0000012770243C010800A02F3D10AF4E080C64 +:105E10003C0D08008DAD00903C04008034820003EE +:105E200001A65821016C18212465012030AA0078B0 +:105E300001424025AF48081C3C1F08008FFF00901E +:105E40008F88004003E6C021331900070307482468 +:105E5000033A7821AF49002825E909C0952E0002B0 +:105E60003C0D08008DAD008C3C0A08008D4A009066 +:105E700031CC3FFF01A61821000C5980006B28216E +:105E800000A72024AF44002C952200023C1F0800EC +:105E90008FFF008C9107008530593FFF03E6782182 +:105EA0000019C1800146702101F8682131CC007FC2 +:105EB00031AB007F019A2821017A50213C03000C6C +:105EC0003C04000E00A328210144102130E60020EC +:105ED00027470980AF82002CAF88001CAF890024BF +:105EE000AF85002010C00006AF8700288D0200504B +:105EF0008CA4010C0044302318C00077000000007F +:105F0000910C0085240DFFDF018D3824A107008549 +:105F10008F8B001C8F8900248F8700288D65004C93 +:105F2000AF850018912F000D31EE002011C0001731 +:105F30000000000024090001A3890004AF80000CC8 +:105F40008CE400248F85000C240A0008AF80000830 +:105F5000AF8000103C010800A42A3CBE3C010800B0 +:105F6000A4203CD20E000B01000030218F850024BC +:105F70008FBF0010AF82001490A8000D27BD00183D +:105F80000008394203E0000830E20001913F0002BE +:105F90002418000133F900FF0019218210980039FC +:105FA000240800021088005B8F86002C8CE50024FA +:105FB00014A0001B8F9F002091220000240A0005DE +:105FC0003046003F10CA0047240400018F860008B5 +:105FD000A3840004AF860010AF86000C8CE400247C +:105FE0008F85000C240A00083C010800A42A3CBE4E +:105FF0003C010800A4203CD20E000B010000000070 +:106000008F8500248FBF0010AF82001490A8000D70 +:1060100027BD00180008394203E0000830E2000103 +:106020008CF800088CF900248FEE00C4A3800004D3 +:106030008CE40024AF8E000C8F85000C8F86000846 +:1060400003197823240A0008AF8F00103C010800D0 +:10605000A42A3CBE3C010800A4203CD20E000B0147 +:10606000000000008F8500248FBF0010AF82001455 +:1060700090A8000D27BD00180008394203E0000871 +:1060800030E20001912300003062003F10440027FD +:106090008F8500208CE40024148000210000000083 +:1060A0008D2E00183C187FFF8F850020370FFFFFD3 +:1060B00001CF1824AF8300088F9F00088CA80084AC +:1060C00003E8C82B1720000203E020218CA40084E1 +:1060D0000A000BBCAF8400088CA3010C0A000B9AC9 +:1060E000AF8300188D2C00188F8600083C0D7FFFB1 +:1060F0008F89002035A3FFFF018358242404000169 +:10610000AF8B0010AD2000CCA38400040A000BC8A4 +:10611000AF86000C8CCA00140A000BBCAF8A0008C2 +:106120008CA300C80A000BFFAF8300088F84002CEB +:106130008CAC00648C8D0014018D582B1160000410 +:10614000000000008CA200640A000BFFAF82000870 +:106150008C8200140A000BFFAF8200088F85000CB0 +:1061600027BDFFE0AFBF0018AFB1001414A00007B7 +:10617000AFB000108F8600242402000590C40000F8 +:106180003083003F106200B68F8400208F9100089A +:1061900000A080218F8C00283C0508008CA53CB015 +:1061A0008D8B000431663FFF00C5502B5540000128 +:1061B00000C02821938D000411A0007300B0F82BBB +:1061C0008F98002024040034930F00BC31EE0002AD +:1061D00051C000012404003000A4C82B172000D1B6 +:1061E0000000000000A4282300B0F82B3C010800A8 +:1061F000A4243CBC17E00068020020213C030800F6 +:106200008C633CAC0083102B5440000100801821AB +:106210008F8800243C010800AC233CB400004821D6 +:106220009104000D30830020506000018F490E184A +:106230008F8300140123382B10E000590000000068 +:106240003C0408008C843CB400895821006B502B1E +:10625000114000560090602B0069302300C02021BF +:106260003C010800AC263CB412000003241FFFFCD4 +:106270001090008A32270003009FC8243C010800C8 +:10628000AC393CB43C010800A4203CD28F84000C03 +:10629000120400078F830020AF9100080200202124 +:1062A0008C7100CCAF90000C26300001AC7000CC9B +:1062B0003C0208008C423CB48F8A0010240700186E +:1062C0000082202301422823AF84000C10800002AA +:1062D000AF850010240700108F86001C3C010800C9 +:1062E000A0273CD02407004090CC0085318B00C013 +:1062F000116700408F8D001414A0001500002021AC +:10630000934A01098F420974314500FF00022602B9 +:1063100024A300013090007F3071007F1230007A9A +:106320002407FF80A0C300833C0908008D293CCCD2 +:106330008F880024240D0002352C00083C01080041 +:10634000A02D3D113C010800AC2C3CCC24040010D5 +:10635000910E000D31C6002010C0000500801821EC +:10636000240800013C010800AC283CB4348300013F +:106370008FBF00188FB100148FB000100060102183 +:1063800003E0000827BD00203C010800A4203CBC1D +:1063900013E0FF9A020020210A000C5000A02021E7 +:1063A0003C0408008C843CB40090602B1180FFAE4C +:1063B000000000003C0F080095EF3CBC01E4702198 +:1063C00001C6682B11A000072C8200043C1F60004E +:1063D0008FF954043338003F1700FFE524030042CF +:1063E0002C8200041040FFA0240300420A000CAEDF +:1063F0008FBF0018152DFFC0000000008CDF007457 +:106400003C0380002405FF8003E3C825ACD9007459 +:1064100090D80085240E000424040010330F003FA0 +:1064200001E54025A0C800858F8800243C010800B4 +:10643000A02E3D11240300019106000D30C900205B +:1064400015200003000000003C0308008C633CB4EE +:106450003C010800AC233CAC0A000CA50000000085 +:106460008F8700108C88008400E8282B14A000027D +:1064700000E088218C91008424090001A389000494 +:106480008F440E18022028210E000B01022030211B +:10649000022080210A000C36AF8200140007182366 +:1064A000306600033C010800A4263CD212200005FF +:1064B0008F8C0020918B00BC316A000415400015C0 +:1064C00024CD00043C0F080095EF3CD201E470217C +:1064D00000AE302B50C0FF6E8F84000C2C85000561 +:1064E00014A0FFA324030042309800031700000209 +:1064F000009818232483FFFC3C010800AC233CB423 +:106500000A000C720000000000A758240A000C9A30 +:10651000016718263C010800A42D3CD20A000D0298 +:10652000000000003C010800AC203CB40A000CADA7 +:10653000240300428F830010146000070000102124 +:106540008F880024240500059106000030C400FF58 +:10655000108500030000000003E0000800000000B8 +:10656000910A0018314900FF000939C214E0FFFA0E +:106570008F85001C3C04080094843CBC3C0308004C +:106580008C633CD43C1908008F393CB43C0F0800A4 +:1065900095EF3CD20064C0218CAD005403197021EA +:1065A00001CF6021018D58231960001D00000000FB +:1065B000910E001C8F8C002C974B0E1031CD00FFDC +:1065C0008D850004016D30238D88000030CEFFFFE3 +:1065D000000E510000AAC821000038210107202127 +:1065E000032A182B0083C021AD990004AD98000048 +:1065F000918F000A01CF6821A18D000A8F88002C9D +:10660000974B0E12A50B0008950A0038254900018A +:10661000A50900389107000D34E60008A106000D19 +:1066200003E000080000000027BDFFE0938700049E +:106630008F8F00248FAD00143C0E7FFF8F89000CDC +:1066400035C8FFFFAFBF001CAFB0001801A8182469 +:1066500091EA000D000717C03C1FBFFF00625825DC +:106660002D2E00018F90001837F9FFFF3C1808000D +:106670008F183CD43C0F080095EF3CCA0179682480 +:10668000000E47803C07EFFF3C05F0FF01A81825EE +:106690003149002034E2FFFF34ACFFFF03105823E0 +:1066A00027A500102406000225EA00020062182433 +:1066B0000080802115200002000040218F480E1C20 +:1066C000A7AA0012056000372407000030FF00FF72 +:1066D000001FCF008F8B001C00793825AFA7001456 +:1066E000916F00853C08080091083CD13C18DFFF01 +:1066F00031EE00C0370AFFFF000E182B3C1F0800C8 +:1067000097FF3CC400EA6824A3A8001100031740C7 +:1067100001A248258FB90010AFA900143C0A080057 +:10672000914A3CD3A7BF00168FA80014032CC024A5 +:106730003C0B01003C0F0FFF030B182531470003F2 +:1067400035EEFFFF010C682400071600006EF824E8 +:106750003C09700001A2C82503E95825AFB900140F +:10676000AFAB00100E000076A3A000158F8C0024A4 +:10677000260200089186000D30C40020108000061B +:106780008FBF001C3C05080094A53CC024B0FFFF4F +:106790003C010800A4303CC08FB0001803E00008A2 +:1067A00027BD00208F9800140118502B5540FFC7BB +:1067B000240700010A000D8530FF00FF93820004CA +:1067C00027BDFFE0AFBF00181040000F0080502130 +:1067D0008F880024240B00058F8900089107000092 +:1067E0008F8400200100282130E3003F8F86002C99 +:1067F000106B000800003821AFA900100E00040E35 +:10680000AFAA0014A38000048FBF001803E00008A3 +:1068100027BD00208D1900183C0F08008DEF3CB4F7 +:106820008F9800103C027FFF8D080014345FFFFF3B +:10683000033F682401F8702101AE602301883821EC +:10684000AFA900100E00040EAFAA00140A000DD369 +:10685000A38000048F8700243C05080094A53CD247 +:106860003C0208008C423CCC90E6000D0005240060 +:1068700030C300201060002C004440258F85001C90 +:1068800000006021240B000190A300850000482136 +:10689000240A00013C0F800035EE00708DC7000017 +:1068A000AF8700308F5801780700FFFE3C0380005F +:1068B000347900708F3800003C0508008CA5007406 +:1068C0003C0D08008DAD00700307782300AF382120 +:1068D0000000102100EF302B01A22021008618219A +:1068E0003C010800AC2700743C010800AC23007098 +:1068F000AF4B01483C1908008F393CD4A7490144EB +:10690000A74A0146AF59014C3C0B0800916B3CD1A2 +:10691000A34B0152AF4801543C081000A74C01584A +:1069200003E00008AF4801788F4B0E1C3C0A0800BA +:106930008D4A3CB497490E16974D0E1401456021BF +:10694000312AFFFF0A000DF631A9FFFF8F830024D3 +:106950009064000D308200201040002900000000EB +:106960000000482100005021000040213C07800029 +:1069700034EB00708D670000AF8700308F4C0178DA +:106980000580FFFE3C0D800035AC00708D8B000053 +:106990003C0508008CA500743C0408008C84007041 +:1069A0000167302300A678210000102101E6C82BE2 +:1069B0000082C021031970213C010800AC2F007433 +:1069C0003C010800AC2E0070AF4901483C0D0800A6 +:1069D0008DAD3CD4A748014424090040A74A014694 +:1069E0003C081000240AFF91AF4D014CA34A01520C +:1069F000AF490154A740015803E00008AF480178AF +:106A00008F490E1897460E1297450E1030CAFFFF99 +:106A10000A000E2C30A8FFFF8F83002427BDFFF84B +:106A20009064000D308200201040003A0000000009 +:106A3000240B000100004821240A00013C088000CA +:106A4000350700708CE30000AF8300308F4C017875 +:106A50000580FFFE3C0E80003C04080090843D1041 +:106A600035C700708CEC00003C0508008CA5007454 +:106A7000A3A400033C1908008F3900708FAD0000FB +:106A80000183302300A63821000010210322782141 +:106A900000E6C02B01F8602101AE4025AFA8000040 +:106AA0003C010800AC2700743C010800AC2C0070CD +:106AB0009346010A3C04080090843D11A3A0000203 +:106AC000A3A600018FA300003C0580FF3099007F42 +:106AD00034A2FFFF006278240019C60001F8702577 +:106AE000240D3000AF4E014C27BD0008AF4D0154BE +:106AF000A7400158AF4B0148A7490144A74A0146A6 +:106B00003C091000240AFF80A34A015203E0000858 +:106B1000AF4901788F4B0E1897460E1297450E100D +:106B200030CAFFFF0A000E6030A9FFFF8F85001CEE +:106B30002402008090A40085308300C0106200050C +:106B40008F8600208F8800088F87000CACC800C893 +:106B5000ACC700C403E00008000000003C0A0800C5 +:106B6000254A38903C0908002529395C3C08080072 +:106B700025082D103C07080024E73A703C06080061 +:106B800024C637003C05080024A534783C040800DE +:106B9000248430A03C030800246337983C0208009A +:106BA0002442356C3C010800AC2A3C903C010800B2 +:106BB000AC293C8C3C010800AC283C883C01080016 +:106BC000AC273C943C010800AC263CA43C010800E6 +:106BD000AC253C9C3C010800AC243C983C010800DE +:106BE000AC233CA83C010800AC223CA003E0000818 +:046BF00000000000A1 +:00000001FF +/* + * This file contains firmware data derived from proprietary unpublished + * source code, Copyright (c) 2004 - 2009 Broadcom Corporation. + * + * Permission is hereby granted for the distribution of this firmware data + * in hexadecimal or equivalent format, provided this copyright notice is + * accompanying it. + */ diff --git a/firmware/bnx2/bnx2-mips-09-4.6.17.fw.ihex b/firmware/bnx2/bnx2-mips-09-4.6.17.fw.ihex deleted file mode 100644 index 7667c66..0000000 --- a/firmware/bnx2/bnx2-mips-09-4.6.17.fw.ihex +++ /dev/null @@ -1,5816 +0,0 @@ -:10000000080000F80800000000004AC8000000C80E -:1000100000000000000000000000000008004AC8C6 -:100020000000003000004B90080000800800000035 -:10003000000053A800004BC0080055400000008499 -:1000400000009F68080053A80000016C00009FECAE -:10005000080031D808000000000079080000A1580D -:100060000000000000000000000000000800790807 -:100070000000012400011A60080004880800040040 -:10008000000013A400011B84000000000000000019 -:1000900000000000080017A40000000400012F2841 -:1000A000080000980800000000003AFC00012F2C16 -:1000B00000000000000000000000000008003AFC02 -:0800C0000000003000016A2875 -:0800C8000A00003E00000000E8 -:1000D000000000000000000D636F6D342E362E31DD -:1000E00036000000040610020000000000000003BB -:1000F00000000014000000320000000300000000B7 -:1001000000000000000000000000000000000000EF -:1001100000000010000001360000EA60000000014D -:1001200000000000000000000000000000000008C7 -:1001300000000000000000000000000000000000BF -:1001400000000000000000000000000000000000AF -:10015000000000000000000000000000000000009F -:10016000000000020000000000000000000000008D -:10017000000000000000000000000000000000007F -:10018000000000000000000000000010000000005F -:10019000000000000000000000000000000000005F -:1001A000000000000000000000000000000000004F -:1001B000000000000000000000000000000000003F -:1001C0000000000010000003000000000000000D0F -:1001D0000000000D3C02080024424B203C030800B4 -:1001E00024634C18AC4000000043202B1480FFFD1A -:1001F000244200043C1D080037BD9FFC03A0F021F1 -:100200003C100800261000F83C1C0800279C4B20DE -:100210000E000273000000000000000D27BDFFE883 -:100220003C028000AFB00010AFBF0014345001009A -:10023000920200091040001A240300013C02080049 -:100240008C42002010400016000018210E000D7195 -:1002500000000000960300083C06080094C64BFE10 -:100260008E0400188F82002C9605000C00031C00E1 -:1002700000661825AC440000AC45000424040001CD -:10028000AC400008AC40000CAC400010AC40001486 -:10029000AC4000180E000D98AC43001C0000182163 -:1002A0008FBF00148FB000100060102103E0000821 -:1002B00027BD001827BDFFE8AFBF00103C0280003B -:1002C0009442010830437000240220001062000AAA -:1002D00028642001548000128FBF001024024000C7 -:1002E00010620008240260001062000A8FBF001034 -:1002F0000A000097000010218FBF00100A0000556F -:1003000027BD00180E000433000000000A0000960C -:100310008FBF00100E000C81000000008FBF001086 -:100320000000102103E0000827BD00183C0208006F -:100330008C42002027BDFFE810400028AFBF00100E -:100340000E000D71000000003C05800094A2010821 -:1003500094A3010C8F86002C3042003E3063FFFFD7 -:100360000002140000431025ACC200008CA2010062 -:100370003C07080094E74BFE8FBF0010ACC200049E -:1003800094A3011694A4010E3C02200000031C005B -:100390003084FFFF00641825ACC3000800E2382554 -:1003A00094A2011094A3011224040001000214007D -:1003B0003063FFFF00431025ACC2000C94A201146F -:1003C00027BD00183042FFFFACC20010ACC00014C3 -:1003D000ACC000180A000D98ACC7001C8FBF0010FD -:1003E00003E0000827BD00183C0680008CC202B85C -:1003F0002403000104410008008028213C02080079 -:100400008C420060244200013C010800AC220060E4 -:1004100003E00008006010218C8300209482001605 -:10042000ACC302802442FFFCA4C202843C02080048 -:100430008C42005C8C84000494A3000E24420001D2 -:100440003C010800AC22005C3C021000A4C3028600 -:10045000ACC4028800001821ACC202B803E0000856 -:10046000006010213C0208008C42002027BDFFE8FC -:100470001040002BAFBF00100E000D7100000000F7 -:100480003C05800094A2010894A3010C8F86002CE7 -:100490003042003E3063FFFF00021400004310258D -:1004A000ACC200008CA201003C07080094E74BFEA0 -:1004B0008FBF0010ACC2000494A3011694A4010ED7 -:1004C0003C02200000031C003084FFFF006418255C -:1004D000ACC3000800E2382594A2011094A30112D5 -:1004E00024040001000214003063FFFF00431025C4 -:1004F000ACC2000C94A2011427BD00183042FFFFCB -:10050000ACC200108CA20118ACC2001490A2010B66 -:10051000304200FFACC200180A000D98ACC7001CA6 -:100520008FBF001003E0000827BD001827BDFFE0C3 -:10053000AFB000103C108000AFB20018AFBF001C7D -:10054000AFB10014361201009243000B2402001ACE -:10055000965100081462005B00002821322200013D -:1005600010400018000000008E42000000022340EE -:100570003C02003F3442FFFF0044102B10400004B7 -:100580003C030040964200140A00013B00832021F6 -:100590008E030100240201005462000696420014FA -:1005A0003C028008944200043042000F0002250003 -:1005B0009642001400821025AE0200800A00016FEE -:1005C000000000003C0208008C420020104000287F -:1005D000000000000E000D710000000096020108EE -:1005E0009603010C8F85002C3042003E3063FFFFE4 -:1005F0000002140000431025ACA200008E0201008E -:100600003C06080094C64BFEACA2000496030116FB -:100610009604010E3C02200000031C003084FFFF02 -:1006200000641825ACA3000800C230259602011012 -:100630009603011224040001000214003063FFFF3E -:1006400000431025ACA2000C960201143042FFFFBB -:10065000ACA200108E020118ACA200149202010B91 -:10066000304200FFACA200180E000D98ACA6001C92 -:100670003C0208008C420040244200013C0108007A -:10068000AC2200403C0308008C630044322200028C -:1006900032240004246300013C010800AC23004420 -:1006A000108000080002282B024020218FBF001C70 -:1006B0008FB200188FB100148FB000100A0000C86C -:1006C00027BD00208FBF001C8FB200188FB100140F -:1006D0008FB0001000A0102103E0000827BD00200B -:1006E00027BDFFE03C058000AFB10014AFBF00188C -:1006F000AFB0001034B101009223000B24020003BC -:1007000014620043963000083202000110400016C7 -:100710003C02003F8E2300003442FFFF00032340D1 -:100720000044102B504000052402010096220014C2 -:100730003C0300400A0001A400832021546200060B -:10074000962200143C028008944200043042000FBC -:10075000000225009622001400821025ACA2008021 -:100760000A0001AF000000000E0000990000000028 -:100770003C0208008C420040244200013C01080079 -:10078000AC2200403C0208008C42004432030004CA -:10079000244200013C010800AC2200441060000724 -:1007A00032020002022020218FBF00188FB10014F6 -:1007B0008FB000100A0000C827BD002010400015AF -:1007C0008FBF00183C0480008C8301043C02602031 -:1007D000AC4300148C420004240301FE304203FFAA -:1007E0001443000C8FBF00188C820100000219C254 -:1007F0002462FFFC2C420008104000032404000285 -:100800002462FFFD004420043C026000AC446914F3 -:100810008FBF00188FB100148FB00010000010219E -:1008200003E0000827BD00203C0480008C83010009 -:1008300024020100506200033C0280080000000D09 -:100840003C02800894430004000010213063000F34 -:1008500000031D0003E00008AC8300803C02800818 -:10086000344200809042000003E00008AF800000A6 -:1008700003E000080000102127BDFFE83C028000D3 -:10088000AFBF0014AFB000108C430100AC43002098 -:100890008C430104AC4300A89050010B0E0001E50D -:1008A000321000FF3C02080024424B580010188010 -:1008B0002E10001D16000005006210210E0001EA36 -:1008C000004018210A000205000000008C420000D0 -:1008D0000040F80900000000004018213C02080018 -:1008E0008C42003410600005244400013C0280006A -:1008F0008C4301043C026020AC4300148FBF001401 -:100900008FB000103C0340003C02800027BD00185F -:10091000AC4301383C010800AC24003403E000087B -:100920000000000027BDFFE8AFBF0014AFB000100B -:100930003C1080008E0201400E0001E5AE02002056 -:100940000E000399000000003C04080024840038D5 -:100950008C8200003C034000AE0301788FBF00147E -:100960008FB000102442000127BD001803E00008EA -:10097000AC82000027BDFFE8AFB00010AFBF00148D -:100980003C1080008E0201800E0001E5AE020020C6 -:100990008E03018024020F00546200083C0280088C -:1009A0008E0201883C0300E03042FFFF0043102527 -:1009B000AE0200800A00024A3C02800034420080FD -:1009C0009042000024030050304200FF144300080E -:1009D0003C0280000E000379000000001440000477 -:1009E0003C0280000E000967000000003C0280000D -:1009F0003C034000AC4301B83C0208008C42003C80 -:100A00008FBF00148FB00010244200013C01080089 -:100A1000AC22003C03E0000827BD001803E00008FA -:100A2000000010213C05800034A4010094820008DD -:100A30003043000230420004104000030000000078 -:100A40000A0000C800000000106000052404000136 -:100A50003C0208008C4200840A00026F244200011C -:100A60008CA301048F82000C104300080000202199 -:100A70008CA301043C0208008C420084AF83000C6C -:100A8000244200013C010800AC22008403E000087D -:100A90000080102127BDFFE83C036010AFBF0014A9 -:100AA000AFB000108C6550002402FF7F3C04800032 -:100AB00000A2282434A5380C24020037AC6550006D -:100AC000AC82000824020C80AC8200243C060800A2 -:100AD00024C607A83C02080024424B582405001CE9 -:100AE00024A5FFFFAC46000004A1FFFD2442000442 -:100AF0003C020800244201EC3C010800AC224B609F -:100B00003C020800244206183C010800AC224B6459 -:100B10003C02080024420D103C010800AC224BA00E -:100B20003C020800244204643C0308002463095486 -:100B30003C0408002484095C3C05080024A52C948E -:100B40003C010800AC224BC03C0208002442076074 -:100B50003C010800AC264BA83C010800AC254BB476 -:100B60003C010800AC234BBC3C010800AC244BC446 -:100B70003C010800AC224BC83C010800AC234B5C94 -:100B80003C010800AC204B683C010800AC204B6CD9 -:100B90003C010800AC204B703C010800AC204B74B9 -:100BA0003C010800AC204B783C010800AC204B7C99 -:100BB0003C010800AC204B803C010800AC244B8475 -:100BC0003C010800AC204B883C010800AC204B8C59 -:100BD0003C010800AC204B903C010800AC204B9439 -:100BE0003C010800AC204B983C010800AC264B9C13 -:100BF0003C010800AC264BA43C010800AC204BACE7 -:100C00003C010800AC254BB03C010800AC234BB8BC -:100C10000E00055A000000003C02800034420070C3 -:100C20008C420000AF8200103C0308008C6300205F -:100C30008F820004104300043C0580000E000D3735 -:100C4000AF8300043C05800034A900708D280000AB -:100C50008F8400103C0708008CE700BC3C060800AD -:100C60008CC600B8010420230000102100E43821C4 -:100C700000C2302100E4202B00C430213C010800D8 -:100C8000AC2700BC3C010800AC2600B88CB00000CA -:100C9000320200071040FFE4AF8800108D260000EC -:100CA0003C0508008CA500BC3C0408008C8400B8FE -:100CB00000C8302300A628210000102100A6302BF8 -:100CC0000082202100862021320700013C0108001B -:100CD000AC2500BC3C010800AC2400B810E00004C6 -:100CE000320200020E0001EC00000000320200029D -:100CF00010400004320200040E0002170000000041 -:100D0000320200045040FFC53C0280000E00022B5E -:100D1000000000000A0002D53C0280003C02900066 -:100D200034420001008220253C028000AC440020B7 -:100D30003C0380008C6200200440FFFE00000000A5 -:100D400003E00008000000003C0280003443000182 -:100D50000083202503E00008AC44002027BDFFE00D -:100D6000AFB10014AFB0001000808821AFBF0018F1 -:100D70000E00031530B000FF8F83FFAC022020214E -:100D80009062002502028025A07000258C7000185A -:100D90003C0280000E000320020280241600000A9C -:100DA0008FBF00183C0380008C6201F80440FFFEF6 -:100DB00024020002AC7101C0A06201C43C02100018 -:100DC000AC6201F88FBF00188FB100148FB0001013 -:100DD00003E0000827BD002027BDFFB8AFBF0044D7 -:100DE000AFB000403C0780008CE601048F82FFA872 -:100DF000AFA600288C450020AFA5002C8C44003CF9 -:100E0000AFA400308C430040AFA300348C42004CB0 -:100E1000AFA60010AFA50014AFA20020AFA200380B -:100E20003C0208008C420020AFA40018AFA3001CB5 -:100E30008CF00100104000198FBF00440E000D71AE -:100E4000000000008F83002C3C05080094A54BFE99 -:100E50003C024018AC70000000A228258FA20010B0 -:100E600024040001AC6200048FA20014AC620008EC -:100E70008FA20018AC62000C8FA2001CAC620010A4 -:100E80008FA20020AC6200148FA20024AC62001874 -:100E90000E000D98AC65001C8FBF00448FB0004061 -:100EA0000000102103E0000827BD004827BDFFE82F -:100EB000AFBF00103C038000946201843042020006 -:100EC00010400005000020210E000FE3000000008C -:100ED0000A00038F240400018C6201880440000A88 -:100EE0008FBF00108C6201883C03FF000043102478 -:100EF0003C03040014430004240400018F82FFAC6F -:100F0000904200088FBF00100080102103E000080D -:100F100027BD00188F82FFB024050001A040001AF1 -:100F20003C0280000A0003258C44014027BDFFE0FD -:100F3000AFB100148F91FFACAFBF001CAFB200186F -:100F4000AFB000109222000024030020304200FFC6 -:100F50001043000C3C028000922200002403003069 -:100F6000304200FF104300073C0280009222000044 -:100F700024030050304200FF144300818FBF001C47 -:100F80003C02800090420148304200FF2443FFFFB2 -:100F90002C6200051040007A8FBF001C00031080F7 -:100FA0003C03080024634AD8004310218C4200000F -:100FB00000400008000000003C1180008E24014029 -:100FC0000E0003158F92FFAC8E50000C8E22014450 -:100FD0001602000224020001AE42000C0E000320A3 -:100FE0008E2401408E220144145000068FBF001C45 -:100FF0008FB200188FB100148FB000100A000F518B -:1010000027BD00208E42000C0A00042700000000CB -:10101000962200103C0480008C8301443042FFFF84 -:10102000146200090000000024020001A622001042 -:101030008C820140AC8202003C021000AC8202387B -:101040000A00042E8FBF001C962200100A000427FD -:10105000000000009222000024030020304200FF24 -:101060001443000B3C128000962200123C038000C7 -:101070008C6301443042FFFF14620018000000003E -:1010800024020001A62200120A0004008FBF001CE7 -:101090008E4401400E00031500000000962200124D -:1010A0008E4301443050FFFF16030002240200016A -:1010B000A62200120E0003208E4401408E420144FD -:1010C000160200068FBF001C8FB200188FB10014EB -:1010D0008FB000100A00039327BD00209622001253 -:1010E0000A00042700000000962200143C03800040 -:1010F0008C6301443042FFFF1462000900000000CD -:1011000024020001A62200148FBF001C8FB2001819 -:101110008FB100148FB000100A00126827BD0020A4 -:10112000962200140A0004270000000096220016F0 -:101130003C0380008C6301443042FFFF14620008CE -:1011400024020001A62200168FBF001C8FB20018D7 -:101150008FB100148FB000100A000B0B27BD0020C8 -:1011600096220016144000068FBF001C3C020800A7 -:101170008C420070244200013C010800AC22007047 -:101180008FB200188FB100148FB0001003E0000878 -:1011900027BD002027BDFFE03C028000AFB1001456 -:1011A000AFBF001CAFB20018AFB000103451010047 -:1011B000922300098C5001002402001F106200AA33 -:1011C0002862002010400018240200382862000A1B -:1011D0001040000C2402000B286200081040002C74 -:1011E0000000000004600100286200021440002892 -:1011F00024020006106200268FBF001C0A00054A68 -:101200008FB20018106200602862000B144000F7D3 -:101210008FBF001C2402000E106200778FB20018EE -:101220000A00054A00000000106200D3286200395D -:101230001040000A2402008024020036106200E3FD -:1012400028620037104000C524020035106200D823 -:101250008FBF001C0A00054A8FB200181062002DD3 -:101260002862008110400006240200C824020039D0 -:10127000106200C98FBF001C0A00054A8FB2001817 -:10128000106200A28FBF001C0A00054A8FB200182E -:101290003C0208008C420020104000D48FBF001C8C -:1012A0000E000D71000000003C028000344201007D -:1012B0008C4400008F83002C944700083C050800F4 -:1012C00094A54BFEAC6400008C44000400073C0075 -:1012D00000E53825AC6400048C4400189446000CEA -:1012E000AC6400088C45001C000634002404000196 -:1012F000AC65000C9042000A00C23025AC660010BC -:10130000AC600014AC600018AC67001C0A00050C4F -:101310008FBF001C3C0208008C420020104000B32C -:101320008FBF001C0E000D71000000009624000805 -:101330003C03080094634BFE9625000C0004220237 -:101340009626000E8F82002C0004260000832025A4 -:1013500000052C003C03008000A6282500832025E2 -:10136000AC400000AC400004AC400008AC40000CB5 -:10137000AC450010AC400014AC400018AC44001C5C -:101380000A00050B240400019622000C14400017EB -:101390008F91FFAC922200053042001014400013E0 -:1013A000000000000E00031502002021922200051B -:1013B00002002021344200100E000320A22200056A -:1013C0009222000024030020304200FF10430086D8 -:1013D000020020218FBF001C8FB200188FB10014B3 -:1013E0008FB000100A00104C27BD00200000000D37 -:1013F0000A0005498FBF001C3C0208008C420020F7 -:101400001040007A8FBF001C0E000D71000000001C -:101410008E2200048F83002C9624000C3C050800CB -:1014200094A54BFEAC6200003C0280089442002C64 -:10143000000424003042FFFF008220253C02400EC1 -:1014400000A22825AC640004AC600008AC60000C6D -:10145000AC600010AC600014AC600018AC65001CFF -:101460000A00050B240400010E00031502002021D0 -:101470008F92FFB0020020210E000320A640000C36 -:10148000020020210E000325240500013C02080073 -:101490008C420020104000558FBF001C0E000D71C3 -:1014A000000000009622000C8F83002C8F84FFAC7C -:1014B00000021400AC700000AC620004AC600008D4 -:1014C0008C8200383C05080094A54BFEAC62000CF1 -:1014D0008C86003C3C02401F00A22825AC66001010 -:1014E0008E42000424040001AC620014AC600018B9 -:1014F000AC65001C8FBF001C8FB200188FB10014A8 -:101500008FB000100A000D9827BD00208F82FFAC1D -:101510002403002090420000304200FF10430033BB -:101520008FBF001C0E000F37000000001040002F7E -:101530008FBF001C3C0380008C6201F80440FFFE5A -:1015400024020002AC7001C0A06201C43C02100081 -:10155000AC6201F80A0005498FBF001C020020217F -:101560008FBF001C8FB200188FB100148FB0001015 -:101570000A000E8027BD00209625000C02002021C5 -:101580008FBF001C8FB200188FB100148FB00010F5 -:101590000A000EA527BD0020020020218FB20018EE -:1015A0008FB100148FB000100A000ED027BD0020AC -:1015B0009225000D020020218FB200188FB1001477 -:1015C0008FB000100A000F2127BD0020020020214B -:1015D0008FBF001C8FB200188FB100148FB00010A5 -:1015E0000A000EF827BD00208FBF001C8FB2001824 -:1015F0008FB100148FB0001003E0000827BD002059 -:101600003C0380008C6202780440FFFE240200024A -:10161000AC640240A06202443C02100003E00008F7 -:10162000AC620278000411C003E0000824420240CA -:10163000A380001803E00008A38000193C03800089 -:101640008C6202780440FFFE8F82001CAC62024074 -:1016500024020002A06202443C02100003E00008E1 -:10166000AC62027803E000080000000090830030C4 -:1016700024020005008040213063003F0000482123 -:1016800014620005000050219082004C9483004EAB -:10169000304900FF306AFFFFAD00000CAD000010C4 -:1016A000AD000024950200148D05001C8D04001867 -:1016B0003042FFFF0049102300021100000237C32F -:1016C000004038210086202300A2102B0082202316 -:1016D00000A72823AD05001CAD040018A5090014BF -:1016E000A5090020A50A001603E00008A50A0022AB -:1016F00003E000080000000027BDFFD8AFB20018CB -:101700003C128008AFB40020AFB3001CAFB100148E -:10171000AFBF0024AFB00010365101009222000C80 -:101720003C140800929400F7304300FF24020001AB -:1017300010620031008098212402000214620034FB -:10174000365000800E001242000000009204004C4F -:101750000E0005573084007F026210212403FF80B1 -:10176000004318243C048000AC8300949245000898 -:101770009204004C3042007F3C0380061485000731 -:10178000004380212402FFFFA22200112402FFFF58 -:10179000A62200120A0005BA2402FFFF96020020CA -:1017A000A222001196020022A62200128E0200241C -:1017B0003C048008AE2200143485008090A2004CC6 -:1017C00034830100A06200108CA2003CAC620018BF -:1017D0008C820068AC6200E48C820064AC6200E041 -:1017E0008C82006CAC6200E824020001A0A20068B8 -:1017F0000A0005D63C0480080E00125B00000000C1 -:1018000036420080A04000680A0005D63C048008EB -:10181000A2000068A20000690A0006123C028008CB -:10182000348300808C62003834850100AC62006C27 -:1018300024020001A062006990A200C59083000804 -:10184000305100FF3072007F1232001B3C088008CC -:101850000E00055702202021026210212403FF8080 -:10186000004318243C048000AC8300943042007F85 -:101870003C038006004380218E02000C1040000DC6 -:10188000020020210E000569000000002622000150 -:10189000305100FF9203003C023410260002102B4E -:1018A000000210233063007F022288240A0005E032 -:1018B000A203003C3C088008350401008C8200D063 -:1018C00035070080ACE2003C8C8200D0AD02000005 -:1018D00090E5004C908600C590E3004C908400C5D4 -:1018E0002402FF8000A228243063007F308400FFA0 -:1018F00000A628250064182A1060000230A500FF09 -:1019000038A50080A0E5004CA10500093C02800834 -:101910009043000E344400803C058000A043000A40 -:101920008C8300183C027FFF3442FFFF00621824C2 -:10193000AC8300188CA201F80440FFFE00000000F8 -:10194000ACB301C08FBF00248FB400208FB3001C44 -:101950008FB200188FB100148FB000102402000263 -:10196000A0A201C427BD00283C02100003E000082B -:10197000ACA201F890A2000027BDFFE0AFB20018B2 -:1019800024420001A0A200003C0308008C6300F484 -:10199000304200FFAFB10014AFBF001CAFB0001069 -:1019A00000A088211443000200809021A0A0000024 -:1019B0000E000557922400008F90001C2403FF8026 -:1019C00002021021004310243C038000AC6200247A -:1019D0000E00055792240000020280213210007F81 -:1019E0003C02800A02028021AE5000008FBF001C22 -:1019F0008FB200188FB100148FB0001003E0000800 -:101A000027BD002094820006908300058C85000C81 -:101A10008C8600108C8700188C88001C8C84002019 -:101A20003C010800A4224BD23C010800A0234BD16A -:101A30003C010800AC254BD83C010800AC264BDC2F -:101A40003C010800AC274BE43C010800AC284BE803 -:101A50003C010800AC244BEC03E00008000000004F -:101A60003C028008344201008C4400343C03800076 -:101A700034650400AC6400388C420038AF85003017 -:101A8000AC62003C3C020005AC620030000000008B -:101A90000000000003E00008000000003C02000617 -:101AA000308400FF008220253C028000AC440030DE -:101AB0000000000000000000000000003C03800067 -:101AC0008C620000304200101040FFFD34620400C0 -:101AD00003E00008AF82003094C200003C08080018 -:101AE000950800CA30E7FFFF00804821010210215D -:101AF000A4C2000094C200003042FFFF00E2102B9D -:101B000054400001A4C7000094A200003C03080058 -:101B10008C6300CC24420001A4A2000094A2000027 -:101B20003042FFFF144300073C0280080107102BDE -:101B3000A4A000005440000101003821A4C7000007 -:101B40003C028008344601008CC3002894A20000A7 -:101B50003C0480003042FFFE000210C000621021F1 -:101B6000AC82003C8C82003C0062182318600004A8 -:101B7000000000008CC200240A0006AF24420001CD -:101B80008CC20024AC8200383C0200503442001069 -:101B90003C038000AC620030000000000000000048 -:101BA000000000008C620000304200201040FFFD69 -:101BB0000000000094A200003C04800030420001BC -:101BC000000210C0004410218C430400AD2300002B -:101BD0008C420404AD2200043C02002003E0000813 -:101BE000AC82003027BDFFE0AFB20018AFB10014E7 -:101BF000AFB00010AFBF001C94C2000000C0802135 -:101C00003C120800965200C624420001A6020000C1 -:101C10009603000094E2000000E030211443000528 -:101C20008FB100300E000684024038210A0006E61B -:101C3000000000008C8300048C82000424420040D9 -:101C400004610007AC8200048C820004044000049C -:101C5000000000008C82000024420001AC820000E1 -:101C6000960200003042FFFF50520001A600000023 -:101C70009622000024420001A62200003C028008B7 -:101C800034420100962300009442003C14430004B7 -:101C90008FBF001C24020001A62200008FBF001C81 -:101CA0008FB200188FB100148FB0001003E000084D -:101CB00027BD002027BDFFE03C028008AFBF001811 -:101CC000344201008C4800343C0380003469040035 -:101CD000AC6800388C42003830E700FFAF89003034 -:101CE000AC62003C3C020005AC6200300000000029 -:101CF00000000000000000000000000000000000E4 -:101D0000000000008C82000C8C82000C978300166F -:101D1000AD2200008C82001000604021AD22000442 -:101D20008C820018AD2200088C82001CAD22000CB1 -:101D30008CA20014AD2200108C820020AD22001471 -:101D400090820005304200FF00021200AD22001810 -:101D50008CA20018AD22001C8CA2000CAD22002029 -:101D60008CA20010AD2200248CA2001CAD22002801 -:101D70008CA20020AD22002C3402FFFFAD260030E3 -:101D8000AD200034506200013408FFFFAD28003858 -:101D900050E000113C0280083C04800834840100BB -:101DA000948200503042FFFFAD22003C94830044F7 -:101DB00094850044240200013063FFFF000318C231 -:101DC000006418219064005430A5000700A210049C -:101DD0000A0007510044102534420100AD20003CA8 -:101DE00094430044944400443063FFFF000318C24E -:101DF000006218213084000790650054240200011D -:101E0000008210040002102700451024A062005434 -:101E10000000000000000000000000003C0200067E -:101E2000344200403C038000AC62003000000000FF -:101E300000000000000000008C6200003042001032 -:101E40001040FFFD3C06800834C20150346304009A -:101E500034C7014A34C4013434C5014034C6014496 -:101E6000AFA200100E0006C7AF8300308FBF00186E -:101E700003E0000827BD00208F8300143C05080004 -:101E80008CA500E88F82001C30633FFF000319809F -:101E900000451021004310212403FF800043182433 -:101EA0003C058000ACA300283042007F3C03800C3E -:101EB0000043302190C2000D000038213442001050 -:101EC000A0C2000D8F8900143C028008344201003A -:101ED00094430044000913823048000324020001A7 -:101EE000A4C3000E1102000B2902000210400005DD -:101EF000240200021100000C240300010A000798CC -:101F00000000182111020006000000000A000798D6 -:101F1000000018218CC2002C0A00079824430001FD -:101F20008CC20014244300018CC200180043102B03 -:101F3000144000033C0380080A0007A224070001A4 -:101F4000346301009462004C24420001A462004CFE -:101F500000091382304300032C6200021040000984 -:101F600000802821146000040000000094C20034A6 -:101F70000A0007B23046FFFF8CC600380A0007B2DD -:101F800000802821000030213C04080024844BCC30 -:101F90000A0006FB0000000027BDFF90AFB60068F6 -:101FA000AFB50064AFB40060AFB3005CAFB200582F -:101FB000AFB10054AFBF006CAFB000508C900000C8 -:101FC0000080B0213C0208008C4200E896040032F8 -:101FD0008F83001C2414FF8030843FFF006218218F -:101FE0000004218000641821007410243C13800038 -:101FF00000A0902190A50000AE620028920400325B -:102000003C02800C3063007F00628821308400C075 -:10201000240200401482002D0000A8218E350038D3 -:102020008E2200181440000224020001AE22001883 -:102030009202003C304200201440000F00000000DB -:102040000E00055700A020218F83001C006218217C -:10205000306400783C02008000822025007418243F -:10206000AE630800AE6408108E2200188E030008CC -:1020700000431021AE2200188E22002C8E2300185F -:10208000244200010062182B1060003D0000000097 -:102090009242000024420001A24200003C030800DA -:1020A0008C6300F4304200FF50430001A240000066 -:1020B0000E000557924400008F90001C0202102170 -:1020C000005410240A0008B8AE62002492030032C3 -:1020D0002402FFC000431024304200FF14400005DA -:1020E00024020001AE220018962200340A00082EB5 -:1020F0003055FFFF8E22001424420001AE2200184A -:102100009202003000021600000216030441001C77 -:10211000000000009602003227A400100080282151 -:10212000A7A2001696020032000030212407000109 -:102130003042FFFFAF8200140E0006FBAFA0001C70 -:10214000960200328F83001C3C0408008C8400E857 -:1021500030423FFF00021180006418210062182104 -:1021600000741024AE62002C3063007F3C02800EAD -:10217000006218219062000D3042007FA062000DC5 -:102180009222000D30420010504000789242000030 -:102190003C028008344401009482004C8EC300004D -:1021A0003C130800967300C62442FFFFA482004C33 -:1021B000946200329623000E3054FFFF3070FFFF10 -:1021C0003C0308008C6300D000701807A7A30038F8 -:1021D0009482003E3063FFFF3042FFFF146200072D -:1021E000000000008C8200303C038000244200305C -:1021F000AC62003C0A0008568C82002C948200409D -:102200003042FFFF5462000927A400408C8200384E -:102210003C03800024420030AC62003C8C820034DD -:10222000AC6200380A0008653C03800027A500382E -:1022300027A60048026038210E000684A7A00048A7 -:102240008FA300403C02800024630030AC43003880 -:102250008FA30044AC43003C3C0380003C020005DB -:10226000AC6200303C028008344401009482004299 -:10227000346304003042FFFF0202102B14400007B9 -:10228000AF8300309482004E9483004202021021FA -:10229000004310230A00087B3043FFFF9483004E65 -:1022A0009482004202631821005010230062182318 -:1022B0003063FFFF3C028008344401009482003CFC -:1022C0003042FFFF14430003000000000A00088BA7 -:1022D000240300019482003C3042FFFF0062102B77 -:1022E000144000058F8200309482003C006210236D -:1022F0003043FFFF8F820030AC550000AC4000043B -:10230000AC540008AC43000C3C0200063442001000 -:102310003C038000AC6200300000000000000000C0 -:10232000000000008C620000304200101040FFFDF1 -:102330003C04800834840100001018C20064182195 -:102340009065005432020007240600010046100484 -:1023500000451025A0620054948300429622000E8E -:1023600050430001A386001892420000244200015D -:10237000A24200003C0308008C6300F4304200FFDE -:1023800050430001A24000000E0005579244000097 -:102390008F90001C2403FF800202102100431024B0 -:1023A0003C038000AC6200240E00055792440000FC -:1023B000020280213210007F3C02800A020280214A -:1023C000AED000008FBF006C8FB600688FB5006480 -:1023D0008FB400608FB3005C8FB200588FB100548F -:1023E0008FB0005003E0000827BD007027BDFFD864 -:1023F000AFB3001CAFB20018AFB10014AFB0001003 -:10240000AFBF00200080982100E0802130B1FFFFA5 -:102410000E000D7130D200FF00000000000000002F -:10242000000000008F82002CAC510000AC52000470 -:10243000AC530008AC40000CAC400010AC400014A1 -:10244000AC4000183C03080094634BFE0203802557 -:10245000AC50001C00000000000000000000000064 -:10246000240400018FBF00208FB3001C8FB200181E -:102470008FB100148FB000100A000D9827BD0028FE -:1024800030A5FFFF30C600FF24030C803C02800013 -:10249000AC43002400000000000000000000000029 -:1024A00000000000000000000A0008C90000000051 -:1024B0003C028008344301009462000E3C0808008E -:1024C000950800C63046FFFF14C000043402FFFF29 -:1024D000946500DA0A00091F8F84001C10C20027CF -:1024E000000000009462004E9464003C3045FFFF01 -:1024F00000A6102300A6182B3087FFFF10600004F1 -:102500003044FFFF00C5102300E210233044FFFFDA -:102510000088102B1040000E00E810233C028008B9 -:10252000344401002403000134420080A443001617 -:102530002402FFFFA482000E948500DA8F84001C21 -:102540000000302130A5FFFF0A0008EE3C076020A4 -:102550000044102A104000093C02800834430080E7 -:102560009462001630420001104000043C028000DA -:102570009442007E24420014A462001603E0000886 -:102580000000000027BDFFE03C028008AFBF001C38 -:10259000AFB0001834420100944300429442004C12 -:1025A000104000193068FFFF9383001824020001D7 -:1025B000146200298FBF001C3C06800834D0010043 -:1025C000000810C20050102190420054310300074F -:1025D00034C70148304200FF00621007304200015A -:1025E00034C9014E34C4012C34C5013E10400016DC -:1025F00034C601420E0006C7AFA900109602004281 -:102600000A00093C3048FFFF3C02800834440100C6 -:1026100094830044948200421043000F8FBF001C3B -:1026200094820044A482004294820050A482004E0E -:102630008C820038AC82003094820040A482003E3C -:102640009482004AA48200488FBF001C8FB00018FB -:102650000A0008FA27BD00208FB0001803E0000828 -:1026600027BD002027BDFFA0AFB1004C3C1180006A -:10267000AFBF0058AFB30054AFB20050AFB0004886 -:102680003626018890C200033044007FA3A40010C6 -:102690008E32018090C200003043007F240200038C -:1026A0001062003BAF92001C28620004104000063C -:1026B0002402000424020002106200098FBF0058A7 -:1026C0000A000B038FB300541062004B2402000574 -:1026D0001062014C8FBF00580A000B038FB30054E7 -:1026E000000411C0024210212404FF802442024051 -:1026F0000044102426430040AE2200243063007FB3 -:102700003C02800A006218219062003CAFA3003CAA -:1027100000441025A062003C8FA3003C9062003C66 -:10272000304200401040016A8FBF00583C108008C2 -:10273000A3800018361001008E0200D08C63003494 -:1027400027A4003C27A50010004310210E0007B469 -:10275000AE0200D093A200103C038000A20200C58C -:102760008C6202780440FFFE8F82001CAC62024043 -:1027700024020002A06202443C021000AC62027813 -:102780000E00092F000000000A000B028FBF005846 -:102790003C05800890C3000190A2000B1443014C3B -:1027A0008FBF005834A400808C8200189082004CA7 -:1027B00090A200088C8300183C027FFF3442FFFF88 -:1027C000006218243C0208008C4200B4AC8300185C -:1027D0003C038000244200013C010800AC2200B40C -:1027E0008C6201F80440FFFE8F82001CAC6201C0C5 -:1027F0000A000ACA240200023C10800890C30001AB -:102800009202000B144301328FBF005836050110AD -:1028100027A400180E000E202406000327A4002879 -:10282000360501E00E000E20240600038FA20028CA -:1028300036030100AE0200648FA2002CAE020068D5 -:102840008FA20030AE02006C93A40018906300C504 -:102850002402FF800082102400431025305000FF26 -:102860003084007F3202007F0082102A5440000131 -:102870003A1000800E0005570000000002421021AF -:102880002403FF8000431024AE22009493A4001878 -:102890003C130800927300F70E0005573084007F48 -:1028A000024210213042007F3C0380060043402159 -:1028B0008FA3001C2402FFFF10620034AFA8004069 -:1028C00093A2001995030014304400FF3063FFFF0A -:1028D0000064182B10600010000000009504001424 -:1028E0008D07001C8D0600183084FFFF0044202354 -:1028F0000004210000E438210000102100E4202B16 -:1029000000C2302100C43021AD07001CAD06001804 -:102910000A000A2393A20019950400148D07001CD5 -:102920008D0600183084FFFF008220230004210060 -:10293000000010210080182100C2302300E4202B69 -:1029400000C4302300E33823AD07001CAD06001897 -:1029500093A200198FA30040A462001497A2001A4A -:10296000A46200168FA2001CAC6200108FA2001C93 -:10297000AC62000C93A20019A462002097A2001A76 -:10298000A46200228FA2001CAC6200243C048008D8 -:10299000348300808C6200388FA2002002008821DE -:1029A000AC62003C8FA20020AC82000093A2001811 -:1029B000A062004C93A20018A0820009A0600068E9 -:1029C00093A200181051005293A400183230007FD7 -:1029D0000E00055702002021024210212407FF802B -:1029E0003046007F3C03800000471024AC62009416 -:1029F0003C02800600C2302190C2003CAFA60040DD -:102A00000000202100471025A0C2003C8FA80040F4 -:102A100095020002950300148D07001C3042FFFF51 -:102A20003063FFFF8D0600180043102300021100E1 -:102A300000E2382100E2102B00C4302100C2302116 -:102A4000AD07001CAD06001895020002A502001497 -:102A5000A50000168D020008AD0200108D020008CE -:102A6000AD02000C95020002A5020020A500002284 -:102A70008D020008AD0200249102003C304200406B -:102A80001040001A26220001A3B000383C10800834 -:102A9000A3800018361001008E0200D08D03003490 -:102AA00027A4004027A50038004310210E0007B4DA -:102AB000AE0200D093A200383C038000A20200C501 -:102AC0008C6202780440FFFE8F82001CAC620240E0 -:102AD00024020002A06202443C021000AC620278B0 -:102AE0000E00092F00000000262200013043007F65 -:102AF00014730004004020212403FF8002231024CB -:102B00000043202693A200180A000A3F309100FFDC -:102B10008FA3001C2402FFFF1062000A309000FF08 -:102B200024820001248300013042007F14530005F9 -:102B3000307000FF2403FF80008310240043102620 -:102B4000305000FF3C0280089042000802008821BB -:102B5000305000FF123000193222007F000211C0F5 -:102B600002421021244202402403FF800043182423 -:102B70003C048000AC8300943042007F3C0380061C -:102B8000004310218C43000C004020211060000BFA -:102B9000AFA200400E0005690000000026230001DE -:102BA0002405FF803062007F145300020225202498 -:102BB000008518260A000AA3307100FF3C04800833 -:102BC000348400808C8300183C027FFF3442FFFF76 -:102BD00000621824AC8300183C0380008C6201F86A -:102BE0000440FFFE00000000AC7201C0240200029D -:102BF000A06201C43C021000AC6201F80A000B02A2 -:102C00008FBF00583C04800890C300019082000BE5 -:102C10001443002F8FBF00583490008092020008A8 -:102C200030420040104000200000000092020008E6 -:102C30000002160000021603044100050240202194 -:102C40000E000EA5240500930A000B028FBF00584A -:102C50009202000924030018304200FF1443000DC3 -:102C600002402021240500390E000E3D00003021D5 -:102C70000E0003158F84001C8F82FFAC240300120A -:102C8000A04300090E0003208F84001C0A000B02E1 -:102C90008FBF0058240500360E000E3D0000302185 -:102CA0000A000B028FBF00580E00031502402021BE -:102CB000920200058F84001C344200200E00032085 -:102CC000A20200050E00104C8F84001C8FBF00581C -:102CD0008FB300548FB200508FB1004C8FB00048BA -:102CE00024030C803C02800027BD006003E0000844 -:102CF000AC43002427BDFFE83C028008AFB00010C1 -:102D0000AFBF0014344501003C1080008E0201402A -:102D100094A3000E0000302100402021AF82001C4F -:102D20003063FFFF3402FFFF106200063C076020A3 -:102D30002402FFFFA4A2000E94A500DA0E0008EE04 -:102D400030A5FFFF24020C80AE0200248FBF0014C8 -:102D50008FB0001003E0000827BD001827BDFFC09A -:102D60003C0980003C058008AFB70034AFB20020BA -:102D7000AFBF0038AFB60030AFB5002CAFB40028FD -:102D8000AFB30024AFB1001CAFB000183532010062 -:102D900034A801008D2701008E4200148D0300D459 -:102DA0000000B821A38000180043102318400055EC -:102DB000AF87001C8E4200142403FF8024E40040EF -:102DC000AD0200D490A60008910500C53084007FB4 -:102DD00030D3007F30A200FF000211C000E21021BA -:102DE00024420240A3A50010004310248D1400D0FB -:102DF0008D1500D4AD22002493A300103C02800A5C -:102E000000822021AFA40014107300330000B02111 -:102E10008FA3001427A4001427A500108C6200348F -:102E20000282802102B010230440002B2411FF8075 -:102E30009062003C02221024304200FF1440001B2C -:102E40000200A0219062003C34420040A062003C9D -:102E500093A2001024420001304300FFA3A20010FF -:102E60003C0208008C4200F450620001A3A0001054 -:102E70000E00055793A400108F90001C3C038000A7 -:102E80000202102100511024AC6200240E000557EC -:102E900093A40010020280213210007F3C02800ABD -:102EA000020280210A000B81AFB000140E0007B4AB -:102EB000000000003C02800834420100AC5000D009 -:102EC00093A3001024160001A04300C593A2001094 -:102ED0001453FFD08FA300142402000116C200096E -:102EE0003C0380008C6202780440FFFE8F82001C4D -:102EF000AC62024024020002A06202443C021000C4 -:102F0000AC6202789242000B24030002304200FFC0 -:102F1000144300720000000096420008304300FF96 -:102F20002402008214620040240200843C028000DB -:102F3000344901008D22000C952300060002160280 -:102F40003063FFFF3044003F240200271082000F4F -:102F5000AF830014288200281040000824020031AA -:102F6000240200211082000924020025108200079B -:102F7000938200190A000BC00000000010820007B5 -:102F8000938200190A000BC0000000000E00076CBD -:102F9000012020210A000C40000000003C038000BA -:102FA0008C6202780440FFFE8F82001CAC620240FB -:102FB00024020002A06202443C021000AC620278CB -:102FC0000A000C4000000000952300069124000533 -:102FD0008D25000C8D2600108D2700188D28001CD3 -:102FE0008D290020244200013C010800A4234BD27B -:102FF0003C010800A0244BD13C010800AC254BD873 -:103000003C010800AC264BDC3C010800AC274BE43B -:103010003C010800AC284BE83C010800AC294BEC13 -:103020000A000C40A38200191462000A24020081E5 -:103030003C02800834420100944500DA92460005C3 -:103040008F84001C30A5FFFF30C600FF0A000C0172 -:103050003C0760211462005C000000009242000AFC -:10306000304300FF30620020104000073062004013 -:103070003C02800834420100944500DA8F84001C31 -:103080000A000BFF24060040104000070003160052 -:103090003C02800834420100944500DA8F84001C11 -:1030A0000A000BFF240600410002160304410046FB -:1030B0003C02800834420100944500DA8F84001CF1 -:1030C0002406004230A5FFFF3C0760190E0008EE01 -:1030D000000000000A000C40000000009242000BBB -:1030E00024040016304200FF104400063C06800015 -:1030F0009242000B24030017304200FF14430032B9 -:103100000000000034C5010090A2000B304200FF17 -:103110001444000B000080218CA200208CA400200D -:103120002403FF8000431024000211403084007FFC -:10313000004410253C03200000431025ACC2083099 -:1031400094A20008000214000002140304420001CB -:103150002410000194A20008304200805040001A60 -:103160000200B82194A2000830422000504000160E -:103170000200B8218CA300183C021C2D344219ED2A -:10318000106200110200B8213C0208008C4200D4F9 -:10319000104000053C028008240300043442010072 -:1031A000A04300EC3C02800834420100944500DA60 -:1031B0008F84001C2406000630A5FFFF0E0008EED9 -:1031C0003C0760210200B8210E00092F000000001A -:1031D0009242000A30420008104000043C02800085 -:1031E0000E00121F000000003C02800024030C802F -:1031F000AC4300248FBF003802E010218FB60030AE -:103200008FB700348FB5002C8FB400288FB3002403 -:103210008FB200208FB1001C8FB0001803E00008AF -:1032200027BD00402402FF80008220243C02900041 -:1032300034420007008220253C028000AC4400207C -:103240003C0380008C6200200440FFFE0000000070 -:1032500003E00008000000003C0380002402FF801F -:10326000008220243462000700822025AC64002004 -:103270008C6200200440FFFE0000000003E0000814 -:10328000000000003C0280082403000534420100D5 -:10329000A04300EC3C0280008C4201003C03800013 -:1032A000AF82001C8C6202780440FFFE8F82001CFB -:1032B000AC62024024020002A06202443C02100000 -:1032C000AC62027803E000080000000027BDFFE8C0 -:1032D0003C068000AFBF001034C5010094A2000876 -:1032E000304400FF38830082388200842C63000160 -:1032F0002C42000100621825106000302402008377 -:1033000093820019504000398FBF00103C02080022 -:1033100090424BD88CC401003C07080094E74BD284 -:103320003046003F38C3003238C2003F2C630001F2 -:103330002C42000100621825AF84001CAF870014E6 -:10334000A38000191460000600A0202124020020A0 -:1033500014C200113402FFFF14E2000F000000004D -:103360002402002014C20005000000008CA30014F9 -:103370002402FFFF1062000A000000003C04080065 -:1033800024844BCC000030210E0006FB24070001F2 -:103390000A000CB6000000000E00076C00000000E0 -:1033A0000E00092F0000000024030C803C02800066 -:1033B000AC4300240A000CEF8FBF001014820006FB -:1033C0002482FF808CC301043C026020AC430014C3 -:1033D0000A000CEF8FBF0010304200FF2C420002A9 -:1033E00010400004240200228FBF00100A000B25A9 -:1033F00027BD0018148200038FBF00100A000C6F55 -:1034000027BD00183C0208008C4200201040001D1F -:103410002402001890A3000914620003240200167D -:103420000A000CDB240300081462000724020017C2 -:10343000240300123C02800834420080A0430009AB -:103440000A000CE894A700085462000794A700083B -:103450008F82FFAC2404FFFE904300050064182413 -:10346000A043000594A7000890A6001B8CA40000B0 -:1034700094A500068FBF001000073C000A0008C991 -:1034800027BD001803E0000827BD00183C05080010 -:1034900094A54C0A3C0308008C634C143C04800047 -:1034A00030A2FFFF000230C02402FFF000C210244F -:1034B00000621821AC83003C3C0208008C424C1096 -:1034C0003C038000AC8200383C02005034420010C3 -:1034D000AC620030000000000000000000000000AE -:1034E0008C620000304200201040FFFD30C2000816 -:1034F000104000093C0280008C6204088C63040CBC -:103500003C010800AC224C003C010800AC234C04F8 -:103510000A000D1B3C0300208C4304008C42040471 -:103520003C010800AC234C003C010800AC224C04D8 -:103530003C0300203C028000AC4300303C0780008C -:103540008CE20030004310241440FFFD0000000016 -:103550003C03080094634C083C02080094424C0C65 -:103560003C06080094C64C0E24A5000100621821F8 -:1035700030A4FFFF3C020040ACE200303C010800F8 -:10358000A4234C083C010800A4254C0A148600031F -:10359000000000003C010800A4204C0A03E00008E1 -:1035A0000000000027BDFFE83C04080024844BF025 -:1035B0003C05800AAFBF00100E000E202406000A52 -:1035C0003C02080094424BF23C03080094634C0E0A -:1035D0003042000F244200030043180424027FFFFE -:1035E0000043102B10400002AF8300280000000DA4 -:1035F0000E000CF1000000003C02080094424BF465 -:103600003C03080094634BFA8FBF00103042000F58 -:10361000000215000062182527BD00183C0280003A -:1036200003E00008AC4300A03C02800A944300067B -:103630003C02080094424BFA3C010800A4234BF6DC -:10364000004310238F8300283042FFFF0043102BDC -:1036500003E000083842000127BDFFE8AFBF0010BB -:103660003C02800A944200063C010800A4224BF66A -:103670000E000D58000000005440FFFA3C02800A82 -:103680008FBF001003E0000827BD001827BDFFE82A -:10369000AFBF00100E000D580000000010400003E6 -:1036A000000000000E000D64000000003C02080055 -:1036B0008C424C003C0380008FBF0010AC6200388D -:1036C0003C0208008C424C043464040027BD0018FE -:1036D000AC62003C3C020005AC620030AF84002CC0 -:1036E00003E00008AF8000248F8200243C03000622 -:1036F00000021140004310253C038000AC62003002 -:103700000000000000000000000000008C620000CB -:10371000304200101040FFFD34620400AF82002CE4 -:1037200003E00008AF8000243C0608008CC64C046F -:103730008F8500248F83002C3C02080094424BFAB2 -:1037400027BDFFE024A500012463002024420001DE -:1037500024C70020AFB10014AFB00010AFBF0018F5 -:10376000AF850024AF83002C3C010800A4224BFA53 -:10377000309000FF3C010800AC274C0404C1000855 -:103780000000882104E00006000000003C02080060 -:103790008C424C00244200013C010800AC224C0049 -:1037A0003C04080094844C083C02080094424BFA04 -:1037B0002E030001004410262C440001008318242D -:1037C000106000040010102B24020001AF820020C2 -:1037D0000010102B00821025144000068F8200205C -:1037E000144000048F830024240200101462000F90 -:1037F000000000000E000D88241100013C030800A9 -:1038000094634BFA3C02080094424C081462000393 -:10381000000000000E000CF1000000001600000384 -:10382000000000000E000D71000000003C030800C5 -:1038300094634BFE3C02080094424BFC246300015D -:103840003064FFFF3C010800A4234BFE14820003F8 -:10385000000000003C010800A4204BFE1200000BF9 -:10386000000000003C02080094424BF43C030800B6 -:1038700094634BFA00021500006218253C02800098 -:10388000AC4300A00A000DF7AF8000200E000D58D9 -:103890000000000010400004022010210E000D6402 -:1038A00000000000022010218FBF00188FB100140B -:1038B0008FB0001003E0000827BD002003E00008DF -:1038C000000000008F8200343C030006000211401B -:1038D000004310253C038000AC6200300000000073 -:1038E00000000000000000008C6200003042001068 -:1038F0001040FFFD34620400AF82003003E0000896 -:10390000AF80003403E000080000102103E000084D -:10391000000000003084FFFF30A5FFFF00001821E9 -:1039200010800007000000003082000110400002FB -:1039300000042042006518210A000E1600052840E8 -:1039400003E000080060102110C0000624C6FFFF3D -:103950008CA2000024A50004AC8200000A000E2006 -:103960002484000403E000080000000010A0000808 -:1039700024A3FFFFAC860000000000000000000050 -:103980002402FFFF2463FFFF1462FFFA2484000473 -:1039900003E00008000000003C0280083442008080 -:1039A00024030001AC43000CA4430010A443001204 -:1039B000A443001403E00008A443001627BDFFD869 -:1039C000248200802407FF803043007FAFB00010C6 -:1039D00000808021004720243C0208008C42002007 -:1039E0003C08800EAFB3001CAFB20018AFB100149A -:1039F000AFBF00203C0980000068182130B100FFF3 -:103A000030D200FF1040002900009821260201005A -:103A1000AD24002C004728243042007F004820219C -:103A20009062000024030050304200FF1443000461 -:103A300000000000AD25002C948200DA3053FFFF17 -:103A40000E000D71000000003C03080094634BFE63 -:103A50008F82002C00112C0000A3282500122400C6 -:103A60003C0340003484000100A32825AC50000032 -:103A70008FBF0020AC4000048FB20018AC53000888 -:103A80008FB10014AC40000C8FB3001CAC4400108C -:103A90008FB00010AC40001424040001AC400018AA -:103AA00027BD00280A000D98AC45001C8FBF0020E0 -:103AB0008FB3001C8FB200188FB100148FB00010AC -:103AC00003E0000827BD00283C06800034C2010046 -:103AD0009043000F240200101062000E28650011B0 -:103AE00010A0000724020012240200082405003A56 -:103AF000106200060000302103E000080000000012 -:103B0000240500351462FFFC000030210A000E3D40 -:103B1000000000008CC200748F83FFAC24420FA011 -:103B200003E00008AC62000C27BDFFE8AFBF001047 -:103B30000E000325240500013C0480088FBF0010FF -:103B40002402000134830080A462001227BD001803 -:103B50002402000103E00008A080001A27BDFFE056 -:103B6000AFB20018AFB10014AFB00010AFBF001C6F -:103B700030B2FFFF0E000315008088213C02800850 -:103B8000345000809202000924030004304200FFF8 -:103B90001443000C3C028008124000082402000A72 -:103BA0000E000E3400000000920200052403FFFE08 -:103BB00000431024A202000524020012A202000900 -:103BC0003C02800834420080022020210E000320A5 -:103BD000A040002716400003022020210E000E986E -:103BE0000000000002202021324600FF8FBF001C91 -:103BF0008FB200188FB100148FB000102405003868 -:103C00000A000E3D27BD002027BDFFE0AFBF001C0E -:103C1000AFB20018AFB10014AFB000100E00031522 -:103C2000008080210E000E34000000003C0280085D -:103C30003445008090A2000924120018305100FF82 -:103C4000123200030200202124020012A0A2000967 -:103C500090A200052403FFFE004310240E00032061 -:103C6000A0A2000502002021240500201632000732 -:103C7000000030218FBF001C8FB200188FB10014DC -:103C80008FB000100A00032527BD00208FBF001C45 -:103C90008FB200188FB100148FB0001024050039C6 -:103CA0000A000E3D27BD002027BDFFE83C02800032 -:103CB000AFB00010AFBF0014344201009442000CBA -:103CC000240500360080802114400012304600FF99 -:103CD0000E000315000000003C0280083442008002 -:103CE00024030012A0430009904300053463001030 -:103CF0000E000E34A04300050E0003200200202118 -:103D0000020020210E000325240500200A000F15C3 -:103D1000000000000E000E3D000000000E00031524 -:103D2000020020213C0280089043001B2405FF9FD5 -:103D300002002021006518248FBF00148FB00010EE -:103D4000A043001B0A00032027BD001827BDFFE089 -:103D5000AFBF0018AFB10014AFB0001030B100FF1A -:103D60000E000315008080213C028008240300120D -:103D7000344200800E000E34A04300090E000320E0 -:103D80000200202102002021022030218FBF0018D4 -:103D90008FB100148FB00010240500350A000E3DCD -:103DA00027BD00203C0480089083000E9082000A0A -:103DB0001443000B000028218F82FFAC2403005025 -:103DC0002405000190420000304200FF144300042B -:103DD000000000009082000E24420001A082000E2C -:103DE00003E0000800A010213C0380008C6201F871 -:103DF0000440FFFE24020002AC6401C0A06201C4C2 -:103E00003C02100003E00008AC6201F827BDFFE0AF -:103E1000AFB200183C128008AFB10014AFBF001C55 -:103E2000AFB0001036510080922200092403000A2E -:103E3000304200FF1443003A000000008E430004AB -:103E40008E2200385062007E8FBF001C922200003C -:103E500024030050304200FF144300253C02800040 -:103E60008C4201408E43000436420100022028218A -:103E7000AC43001C9622005C8E2300383042FFFFCA -:103E80000002104000621821AE23001C8E43000483 -:103E90008E2400389622005C006418233042FFFF15 -:103EA00000031843000210400043102A104000068F -:103EB000000000008E4200048E23003800431023CF -:103EC0000A000F83000220439622005C3042FFFF6D -:103ED000000220403C02800834430100344200804C -:103EE000ACA4002CA040002424020001A062000C1D -:103EF0000E000F3700000000104000518FBF001C63 -:103F00003C0280008C4401408FBF001C8FB200181F -:103F10008FB100148FB000100A000F4827BD002099 -:103F20009222000924030010304200FF14430004D1 -:103F30003C0280008C4401400A000FC5000028218B -:103F40009222000924030016304200FF14430006A9 -:103F500024020014A22200093C0280008C4401408B -:103F60000A000FD88FBF001C8E2200388E23003C21 -:103F700000431023044100328FBF001C922200270F -:103F800024420001A2220027922200273C030800BD -:103F90008C630048304200FF144300163C10800040 -:103FA0009222000924030004304200FF1443000958 -:103FB0003C0280008C4401408FBF001C8FB200186F -:103FC0008FB100148FB00010240500930A000EA5D5 -:103FD00027BD00208C440140240500938FBF001CA6 -:103FE0008FB200188FB100148FB000100A000F219B -:103FF00027BD00208E0401400E00031500000000C4 -:104000008E4200042442FFFFAE4200048E22003C98 -:104010002442FFFFAE22003C0E0003208E0401402C -:104020008E0401408FBF001C8FB200188FB10014A6 -:104030008FB00010240500040A00032527BD0020CE -:104040008FB200188FB100148FB0001003E0000889 -:1040500027BD00203C0680008CC201883C038008FC -:10406000346500809063000E00021402304400FFAB -:10407000306300FF1464000E3C02800890A200260A -:10408000304200FF104400098F82FFACA0A400263C -:104090002403005090420000304200FF1443000609 -:1040A000000000000A00058C8CC401803C028008DE -:1040B00034420080A044002603E000080000000015 -:1040C00027BDFFE030E700FFAFB20018AFBF001C14 -:1040D000AFB10014AFB000100080902114E00006D2 -:1040E00030C600FF000000000000000D00000000CE -:1040F0000A001037240001173C0380089062000E6C -:10410000304200FF144600233462008090420026B3 -:10411000304200FF1446001F000000009062000FB4 -:10412000304200FF1446001B000000009062000AAD -:10413000304200FF144600038F90FFAC0000000DDA -:104140008F90FFAC8F82FFB03C118000AE05003C29 -:10415000AC450000A066000A0E0003158E24010085 -:10416000A20000240E0003208E2401003C038000E6 -:104170008C6201F80440FFFE24020002AC7201C010 -:10418000A06201C43C021000AC6201F80A001038C1 -:104190008FBF001C000000000000000D00000000A8 -:1041A000240001408FBF001C8FB200188FB1001493 -:1041B0008FB0001003E0000827BD00208F83FFAC04 -:1041C0003C0280008C440100344201008C65003CBC -:1041D0009046001B0A000FFE240700013C028008E5 -:1041E0009043000E9042000A00431026304200FF28 -:1041F00003E000080002102B27BDFFE03C0280080E -:10420000AFB10014AFB00010AFBF00183450008041 -:104210009202000524030030304200301443008431 -:10422000008088213C0208008C4200201040008160 -:104230008FBF00180E000D71000000008F86002C4B -:10424000ACD100009202000892030009304200FF46 -:1042500000021200306300FF00431025ACC20004CE -:104260009202004D000216000002160304410005F0 -:10427000000000003C0308008C6300480A00107630 -:104280003C108008920200083042004014400003B5 -:104290000000182192020027304300FF3C108008E4 -:1042A000361100809222004D00031E003C050800DC -:1042B00094A54BFE304200FF000214000062182556 -:1042C000ACC300088E2300303C02C00B00A228259E -:1042D000ACC3000C8E22003400002021ACC20010C0 -:1042E0008E220038ACC200148E22003CACC20018F2 -:1042F0000E000D98ACC5001C8E0200048F84002CAB -:104300003C058000AC8200008E220020AC820004BC -:104310008E22001CAC8200088E2200588CA30074F0 -:1043200000431021AC82000C8E22002CAC820010C5 -:104330008E2200408E23004400021400004310250A -:10434000AC8200149222004D24030080304200FF12 -:1043500014430003000000000A0010B8AC800018ED -:104360008E23000C240200011062000E2402FFFFC5 -:1043700092220008304200401440000A2402FFFF4D -:104380008E23000C8CA20074006218233C020800EB -:10439000006210241440000200002821006028213F -:1043A00000051043AC8200183C02080094424BFE0A -:1043B0003C03C00C00002021004310258F83002CFB -:1043C0000E000D98AC62001C3C0480083482010091 -:1043D0008C4200008F83002C348400803C0608004F -:1043E00094C64BFEAC620000AC6000048C850048B3 -:1043F0003C02400D00C23025AC650008AC60000CEA -:10440000AC600010908200058FBF00188FB10014BF -:1044100000021600AC6200148FB00010AC600018EF -:1044200024040001AC66001C0A000D9827BD002082 -:104430008FBF00188FB100148FB0001003E0000888 -:1044400027BD00203C0280009443007C3C02800891 -:1044500034460100308400FF3065FFFF2402000570 -:1044600024A34650A0C4000C5482000C3065FFFF0A -:1044700090C2000D2C4200071040000724A30A0040 -:1044800090C3000D240200140062100400A2102149 -:104490000A0010F53045FFFF3065FFFF3C02800841 -:1044A0003442008003E00008A44500143C03800867 -:1044B00034680080AD050038346701008CE2001CD0 -:1044C000308400FF00A210231840000330C600FF14 -:1044D00024A2FFFCACE2001C308200015040000826 -:1044E0003C0380088D02003C00A21023044100120E -:1044F000240400058C62000410A2000F3C03800815 -:104500008C62000414A20018000000003C020800A5 -:104510008C4200D830420020104000093C02800844 -:1045200034620080906300089042004C1443000401 -:104530003C028008240400040A0010DF0000000090 -:104540003443008034420100A040000C24020001EA -:10455000A462001410C000043C0280008C440100DE -:104560000A000F480000000003E0000800000000FF -:1045700027BDFFE800A61823AFBF00101860004E4B -:10458000308800FF3C02800834470080A0E000240F -:1045900034440100A0E000278C82001C00A21023FC -:1045A0000440002B000000008CE2003C94E3005C1F -:1045B0008CE4002C004530233063FFFF00C318213A -:1045C0000083202B1080000400E018218CE2002CD6 -:1045D0000A00114800A2102194E2005C3042FFFF63 -:1045E00000C2102100A21021AC62001C3C02800815 -:1045F0003447008094E2005C8CE3001C3042FFFFF3 -:104600000002104000A210210043102B10400003B4 -:10461000000000000A0011598CE2001C94E2005CCA -:104620003042FFFF0002104000A21021ACE2001C4B -:104630003C028008344201008FBF0010010020219D -:1046400024060001A040000C0A0010F927BD001844 -:104650008CE2001C004610230043102B5440000144 -:10466000ACE5001C94E2005C3042FFFF0062102BBE -:10467000144000072402000294E2005C8CE3001C5A -:104680003042FFFF00621821ACE3001C240200024C -:10469000ACE500380E000F37A082000C1040001867 -:1046A0008FBF00103C0280008C4401008FBF0010BF -:1046B0000A000F4827BD00183102001010400010FA -:1046C0008FBF00103C028008344500808CA3001C82 -:1046D00094A2005C006618233042FFFF006218219C -:1046E0003C023FFF3444FFFF0083102B5440000185 -:1046F0000080182100C31021ACA2001C8FBF001045 -:1047000003E0000827BD001827BDFFE800C04021D6 -:1047100000A63023AFBF001018C00026308A00FF6B -:104720003C028008344900808D24001C8D23002C1D -:10473000008820230064182B1060000F344701000C -:104740008CE2002000461021ACE200208CE2002028 -:104750000044102B1440000B3C023FFF8CE2002071 -:1047600000441023ACE200209522005C3042FFFFA1 -:104770000A0011AE00822021ACE00020008620213A -:104780003C023FFF3443FFFF0064102B5440000104 -:10479000006020213C0280083442008000851821FE -:1047A000AC43001CA0400024A04000270A0011FDDB -:1047B0008FBF001031420010104000408FBF00102A -:1047C0003C06800834C400808C82003C00481023E2 -:1047D0005840003B014020219082002424420001E7 -:1047E000A0820024908200243C0308008C630024F3 -:1047F000304200FF0043102B544000348FBF0010A4 -:1048000034C201008C42001C00A210231840002F6B -:104810008FBF00108CC300049482005C00681823D2 -:104820003042FFFF00031843000210400043102AEB -:1048300010400005000000008CC200040048102356 -:104840000A0011E3000210439482005C3042FFFF33 -:10485000000210403C068008AC82002C34C5008069 -:1048600094A2005C8CA4002C94A3005C3042FFFF57 -:1048700000021040008220213063FFFF00832021CE -:1048800001041021ACA2001C8CC2000434C601003B -:10489000ACC2001C240200020E000F37A0C2000CA4 -:1048A0001040000A8FBF00103C0280008C440100C1 -:1048B0008FBF00100A000F4827BD001801402021BB -:1048C000240600010A0010F927BD001803E00008C3 -:1048D00027BD00183C098008352A00808D42003C25 -:1048E000308300FF352B01000046102330E700FF26 -:1048F000184000060060202124020001A160000C85 -:10490000A160000D0A001190A542001424020005C8 -:10491000352901000000302114E20008A1400027E1 -:104920009122000D2C4200061040000400000000FF -:104930009122000D24420001A122000D0A0010F96D -:10494000000000003C0380083C028000344201006B -:1049500034640080346301009045000A8C480014E0 -:104960008C8900389062000C30AA00FF01281823BF -:10497000304700FF1C60000E2CE4000624020001FA -:1049800000E210041080000A30430003014020219F -:10499000010028210120302114600007304B000C59 -:1049A000156000073042003014400007000000008E -:1049B00003E00008000000000A0011900000000061 -:1049C0000A00112A000000000A0012030000000083 -:1049D0003C0380083464010024020003A082000C20 -:1049E0008C62000403E00008AC82001C3C058008D7 -:1049F00034A300809062002734A501002406004300 -:104A000024420001A0620027906300273C020800B6 -:104A10008C420048306300FF146200043C076021B0 -:104A200094A500DA0A0008EE30A5FFFF03E00008B5 -:104A30000000000027BDFFE8AFBF00103C0280006F -:104A40000E0012498C4401803C028008344301006E -:104A5000A060000C8C4200048FBF001027BD00181E -:104A600003E00008AC62001C27BDFFE03C028008A8 -:104A7000AFBF0018AFB10014AFB0001034450080D4 -:104A8000344601003C0880008D09014090C3000CB1 -:104A90008CA4003C8CA2003814820038306700FFE0 -:104AA0009502007C90A30027146000093045FFFFA9 -:104AB0002402000554E200083C04800890C2000D66 -:104AC00024420001A0C2000D0A0012843C048008A8 -:104AD000A0C0000D3C048008348201009042000C0C -:104AE00024030005304200FF1443000A24A205DC21 -:104AF00034830080906200272C420007504000055C -:104B000024A20A009063002724020014006210040B -:104B100000A210213C108008361000803045FFFFB5 -:104B2000012020210E001249A60500149602005C07 -:104B30008E0300383C1180003042FFFF000210401D -:104B400000621821AE03001C0E0003158E240140E4 -:104B50009202002534420040A20200250E000320EC -:104B60008E2401408E2401408FBF00188FB10014A5 -:104B70008FB000100A000F4827BD00208FBF00181B -:104B80008FB100148FB0001003E0000827BD002093 -:104B90008008010080080080800800008008024032 -:104BA00008000EF008000F4808000F8C08001020C5 -:104BB0000800106480080100800800808008000060 -:104BC0000A00002000000000000000000000000DAE -:104BD0006370342E362E31370000000004061104B5 -:104BE00000000000000000000000000000000000C5 -:104BF0000000000038003C00000000000000000041 -:104C00000000000000000000000000200000000084 -:104C10000000000000000000000000000000000094 -:104C20000000000000000000000000000000000084 -:104C30000000000021003800000000010000002BEF -:104C40000000000010000003000000000000000D44 -:104C50000000000D3C020800244255C43C0308003B -:104C6000246357F4AC4000000043202B1480FFFD68 -:104C7000244200043C1D080037BD9FFC03A0F02126 -:104C80003C100800261000803C1C0800279C55C4DE -:104C90000E00026A000000000000000D00A01821B4 -:104CA00000801021008028213C0460003C07600047 -:104CB0002406000810600006348420788C4200002E -:104CC000ACE220088C63000003E00008ACE3200C99 -:104CD0000A000E1C00000000240300403C0260009B -:104CE00003E00008AC4320003C0760008F86000012 -:104CF0008CE520740086102100A2182B1460000798 -:104D0000000028218F8AFDEC24050001A144001336 -:104D10008F89000001244021AF88000003E00008D3 -:104D200000A010218F84FDEC8F8500009086001379 -:104D300030C300FF00A31023AF82000003E000088F -:104D4000A08000138F84FDEC27BDFFE8AFB00010FA -:104D5000AFBF001490890011908700112402002831 -:104D6000312800FF3906002830E300FF2485002C9D -:104D70002CD00001106200162484001C0E000037A5 -:104D8000000000008F8FFDEC3C056000240202044F -:104D900095EE003E95ED003C000E5C0031ACFFFF4F -:104DA000016C5025ACAA201052000001240200041E -:104DB000ACA2200000000000000000000000000085 -:104DC0008FBF00148FB0001003E0000827BD00184B -:104DD0000A00006F000028218F85FDEC27BDFFD859 -:104DE000AFBF0020AFB3001CAFB20018AFB10014CA -:104DF000AFB000100080982190A4001124B0001CD6 -:104E000024B1002C308300FF386200280E000059C6 -:104E10002C5200010E000061000000000200202161 -:104E20001240000202202821000028210E00003735 -:104E3000000000008F8DFDEC3C0880003C05600008 -:104E400095AC003E95AB003C02683025000C4C0050 -:104E5000316AFFFF012A3825ACA720102402020284 -:104E6000ACA6201452400001240200028FBF002093 -:104E70008FB3001C8FB200188FB100148FB00010D8 -:104E800027BD002803E00008ACA2200027BDFFE0FA -:104E9000AFB20018AFB10014AFB00010AFBF001C2C -:104EA0003C1160008E2320748F82000030D0FFFF01 -:104EB00030F2FFFF1062000C2406008F0E00003756 -:104EC000000000003C06801F0010440034C5FF00B5 -:104ED0000112382524040002AE27201000003021E2 -:104EE000AE252014AE2420008FBF001C8FB2001806 -:104EF0008FB100148FB0001000C0102103E0000833 -:104F000027BD002027BDFFE0AFB0001030D0FFFF6D -:104F1000AFBF0018AFB100140E00003730F1FFFF33 -:104F200000102400009180253C036000AC7020102C -:104F30008FBF00188FB100148FB00010240200043E -:104F4000AC62200027BD002003E000080000102113 -:104F500027BDFFE83C0C6018AFBF00108D985000D3 -:104F60002419FF7F3C0880000319782435EE380CA3 -:104F7000340D8071240A003124090C00AD8E5000DC -:104F80003C0B800AAD8D53BCAD0A0008AD0900246E -:104F90000E00048DAF8B002C0E00044B00000000AF -:104FA0000E000046000000003C0760008CE5080889 -:104FB0002406FFF03C03570900A620243462F000C9 -:104FC00010820048241F0001AF8000380E000BAE95 -:104FD000000000003C0660168CC700003C0860140E -:104FE0008D0500A03C03FFFF00E320243C02535347 -:104FF00000051FC21082003534C57C0094A201F266 -:10500000A780005010400003A7800060384C1E1E8F -:10501000A78C005094A201F8104000048F8E003835 -:10502000384D1E1EA78D00608F8E003811C0000401 -:1050300097840060240F0020A78F005097840060A1 -:105040002C980081530000012404008097850050B3 -:105050002CB9040153200001240504003C03600026 -:105060008C670438241F103C30E2FFFF105F000300 -:105070003088FFFF5100000B24060050A38000621F -:10508000938900621120000B8FBF001027BD00180C -:10509000A7800060A7800050A780005803E00008A8 -:1050A000A7800076A3860062938900621520FFF72F -:1050B0008FBF001027BD0018A7840060A78500508F -:1050C000A780005803E00008A780007600035880FE -:1050D000016650218D4900043C0660000A00010F62 -:1050E000012628210A000103AF9F00383083FFFF0B -:1050F0008F88002C8F870028000321403C0580000A -:105100003C020050008248253C0660003C0A010039 -:1051100034AC04008CCD08E001AA582411600005CD -:10512000000000008CCF08E024E7000101EA7025B0 -:10513000ACCE08E08D19001001805821ACB90038C0 -:105140008D180014ACB8003CACA900300000000081 -:10515000000000000000000000000000000000004F -:105160000000000000000000000000003C03800080 -:105170008C640000308200201040FFFD3C0F600076 -:105180008DED08E03C0E010001AE18241460FFE133 -:1051900000000000AF87002803E00008AF8B003C50 -:1051A0008F85002C240BFFF03C06800094A7001A8A -:1051B0008CA9002430ECFFFF000C38C000EB502419 -:1051C000012A4021ACC8003C8CA400248CC3003CC4 -:1051D0000083102318400033000000008CAD002035 -:1051E00025A200013C0F0050ACC2003835EE001083 -:1051F0003C068000ACCE0030000000000000000043 -:10520000000000000000000000000000000000009E -:1052100000000000000000003C0480008C990000A9 -:10522000333800201300FFFD30E200081040001763 -:105230003C0980008C880408ACA800108C83040C06 -:10524000ACA300143C1900203C188000AF190030BA -:1052500094AE001894AF001C01CF3021A4A6001812 -:1052600094AD001A25A70001A4A7001A94AB001A58 -:1052700094AC001E118B00030000000003E0000846 -:105280000000000003E00008A4A0001A8D2A04001A -:10529000ACAA00108D240404ACA400140A0001A2DE -:1052A0003C1900208CA200200A00018A3C0F00500B -:1052B0000A000178000000003C0308008C63002015 -:1052C0008F82003427BDFFE810620008AFBF0010D6 -:1052D0000E0001BCAF8300343C0308008C63002047 -:1052E00024040001106400048F8C002C8FBF001078 -:1052F00003E0000827BD00188FBF00103C058000A8 -:10530000A580000A958B000A958A000427BD001825 -:105310003167FFFF3149000F0009450000E83025E3 -:1053200003E00008ACA600803C0208008C4200208C -:1053300027BDFFC8AFBF0034AFBE0030AFB7002CF1 -:10534000AFB60028AFB50024AFB40020AFB3001C47 -:10535000AFB20018AFB1001410400053AFB000104E -:105360008F84002C948600069483000A00C32823AF -:1053700030B6FFFF12C0004D8FBF00349489001873 -:10538000948A000A012A40233102FFFF02C2382B0F -:1053900014E0000202C02021004020212C8C0005D6 -:1053A000158000020080A021241400040E00014B8F -:1053B000028020218F87002C02809821AF8000304E -:1053C00094ED000A028088211280005131B2FFFF63 -:1053D0003C1770003C1540003C1E60008F8F003C65 -:1053E0008DEE000001D718245075005302202021B3 -:1053F00002A3802B160000383C1820001078004AC9 -:1054000000000000241000018F8300301460003C75 -:10541000029158230230F8230250C82133F1FFFFD4 -:105420001620FFEE3332FFFF8F87002C3C12002046 -:105430003C118000AE32003094EA000A3C17800034 -:10544000026A4821A4E9000A94E3000A94E80004EF -:105450003065FFFF3106000F0006150000A2F025A1 -:10546000AEFE008094F4000A94F5001812B4003ADD -:105470000013C9408CF800148CEE00100319582159 -:10548000000078210179682B01CF6021018D202156 -:10549000ACEB0014ACE4001002D3382330F6FFFF6D -:1054A00016C0FFB68F84002C8FBF00348FBE003033 -:1054B0008FB7002C8FB600288FB500248FB4002042 -:1054C0008FB3001C8FB200188FB100148FB0001082 -:1054D00003E0000827BD0038107E001B000000001C -:1054E0001477FFC9241000010E0014E00000000032 -:1054F0008F8300301060FFC80230F82302915823D8 -:105500008F87002C017020210A0002553093FFFF85 -:105510008F8300301460FFC83C1200203C118000D3 -:105520000A00021EAE3200300E0003CE02202021FF -:105530000A000212004080210E0007C60240282106 -:105540000A000212004080210E000D7D0220202161 -:105550000A000212004080210E00017800000000C5 -:105560000A00023702D3382327BDFFD0AFB500248D -:10557000AFB40020AFB3001CAFB20018AFB100143D -:10558000AFB00010AFBF00280E0000E43C14800054 -:105590003C0280083C0320003C010800AC20007065 -:1055A00034550080347200032413000136900070DB -:1055B0002411FF800A0002858E0600003C1980003D -:1055C0008F3800003B0F000131E200011040002540 -:1055D0008F8600848E0700003C0D08008DAD003CD6 -:1055E0003C0A08008D4A003800E6702301AE4021D5 -:1055F00000005821010E302B014B482101262021AB -:105600003C010800AC28003CAF8700843C01080046 -:10561000AC2400380E0001BE000000003C0508006C -:105620008CA5007010A0FFE500A020213C0508001B -:105630008CA500683C0608008CC6006C0E00148324 -:10564000000000003C010800AC2000703C19800004 -:105650008F3800003B0F000131E200011440FFDDF4 -:105660008F8600848E0C00008F8D00843C0708001C -:105670008CE7003C3C0608008CC60038018D58239E -:1056800000EB282100AB202B00C24821012410216F -:105690003C010800AC25003C3C0880003C010800AF -:1056A000AC2200388D030100241F0C00107F00265F -:1056B000000000008D180100240E0020AD1800200D -:1056C00092AF000031E300FF106E00232419005058 -:1056D00010790026000000003C0480008C88010046 -:1056E0001500000300000000566000143C04400058 -:1056F0008C9901008C8F0100000098210331C02497 -:105700000018694031EE007F01AE602501925825F6 -:10571000AC8B08308C8701008C89010024EA0100E1 -:1057200001513024000629403123007F00A31025B9 -:105730000052F825AC9F08303C044000AE8401388C -:105740000A00027D000000000E0001DA00000000E7 -:105750000A0002C73C0480008D0401000E00077F90 -:10576000000000000A0002C73C0480008D04010014 -:105770000E00139B000000000A0002C73C048000DA -:1057800000A4102B24030001104000090000302168 -:105790000005284000A4102B04A0000300031840BB -:1057A0005440FFFC000528405060000A0004182BFC -:1057B0000085382B54E000040003184200C3302554 -:1057C00000852023000318421460FFF900052842D9 -:1057D0000004182B03E0000800C310213084FFFFF1 -:1057E00030C600FF3C0780008CE201B80440FFFE99 -:1057F00000064C00012430253C08200000C820256C -:105800003C031000ACE00180ACE50184ACE401880D -:1058100003E00008ACE301B83C0660008CC5201C26 -:105820002402FFF030830200308601001060000E79 -:1058300000A2282434A500013087300010E00005C4 -:1058400030830C0034A500043C04600003E0000831 -:10585000AC85201C1060FFFD3C04600034A50008EE -:1058600003E00008AC85201C54C0FFF334A50002FF -:105870000A00031F3087300027BDFFE8AFB00010DB -:10588000AFBF00143C076000240600021080001126 -:1058900000A080218F83003C0E0003168C6400184A -:1058A0008F82003C00002021240600018C45000C62 -:1058B0000E0003070000000016000002240200038F -:1058C000000010218FBF00148FB0001003E000080B -:1058D00027BD00188CE8201C2409FFF001092824AA -:1058E000ACE5201C8F87003C0A00033C8CE5000CD3 -:1058F0003C02600E0080402134460100240900185B -:105900000000000000000000000000003C0A005001 -:105910003C03800035470200AC6800383464040062 -:10592000AC65003CAC6700308C6C0000318B002013 -:105930001160FFFD2407FFFF2403007F8C8D000012 -:105940002463FFFF24840004ACCD00001467FFFB38 -:1059500024C6000400000000000000000000000059 -:1059600024A402000085282B3C0300203C0E80006C -:105970002529FFFF01054021ADC300301520FFE0C0 -:105980000080282103E00008000000008F82003C16 -:1059900027BDFFD8AFB3001CAFBF0020AFB20018C7 -:1059A000AFB10014AFB000109446000200809821FF -:1059B0008C5200182CC300818C4800048C470008CE -:1059C0008C51000C8C490010106000078C4A0014A8 -:1059D0002CC400041480001330EB000730C5000312 -:1059E00010A00010000000002410008B02002021F5 -:1059F000022028210E00030724060003166000027F -:105A000024020003000010218FBF00208FB3001C70 -:105A10008FB200188FB100148FB0001003E000089F -:105A200027BD00281560FFF12410008B3C0C80007E -:105A30003C030020241F0001AD830030AF9F0030E5 -:105A40000000000000000000000000002419FFF02A -:105A500024D8000F031978243C1000D0AD880038FA -:105A600001F0702524CD00033C08600EAD87003C9A -:105A700035850400AD8E0030000D38823504003CC1 -:105A80003C0380008C6B0000316200201040FFFD61 -:105A90000000000010E0000824E3FFFF2407FFFFE0 -:105AA0008CA800002463FFFF24A50004AC8800003C -:105AB0001467FFFB248400043C04600EAC860038AD -:105AC0000000000000000000000000003C07002073 -:105AD0003C0680000120202101402821ACC7003075 -:105AE0000E00034C000080210E000316024020210E -:105AF0000A00038C0200202127BDFFD8AFB2001896 -:105B00003092FFFFAFB10014AFBF0020AFB3001C55 -:105B1000AFB000101240002D000088210A0003E2FF -:105B20002413000350B300428CE5000C0000000D6C -:105B3000263900013331FFFF24F800200232382BD0 -:105B400010E00022AF98003C8F8200301440001F0C -:105B50008F87003C3C0670003C0320008CE4000072 -:105B60000086282414A300198F85004400044402F1 -:105B70003C0980000089802414A0FFEA310600FF60 -:105B8000240A000210CA003028CB0003116000175D -:105B9000000000002404000114C4FFE626390001BF -:105BA000020028210E00032E240400018F87003CF0 -:105BB000AF820044263900013331FFFF24F8002072 -:105BC0000232382B14E0FFE0AF98003C0220102195 -:105BD0008FBF00208FB3001C8FB200188FB100144C -:105BE0008FB0001003E0000827BD002810D3001B71 -:105BF000240C000414CCFFCF26390001308DFFFFA8 -:105C0000000D19C03C0480008C8E01B805C0FFFE59 -:105C10003C0F10003C102004AC830180AC80018458 -:105C2000AC900188AC8F01B80A0003DD2639000171 -:105C30000E000307240400841600FFBD8F87003C7C -:105C40000A0003DCAF800044020028210E00032E6E -:105C5000000020210A0003FC8F87003C0E00037324 -:105C6000020020218F87003C0A0003FDAF82004420 -:105C7000000449C23127003F000443423C02800037 -:105C800000082040240316802CE60020AC43002CA2 -:105C900024EAFFE02482000114C0000330A900FFC1 -:105CA00000801021314700FF000260803C0D800021 -:105CB000240A0001018D20213C0B000E00EA28047B -:105CC000008B302111200005000538278CCE000004 -:105CD00001C5382503E00008ACC700008CD80000DF -:105CE0000307782403E00008ACCF000027BDFFE0E5 -:105CF000AFB10014AFB00010AFBF00183C07600098 -:105D00008CE408083402F0003C1160003083F0009D -:105D1000240501C03C04800E000030211062000602 -:105D2000241000018CEA08083149F0003928E0000D -:105D30000008382B000780403C0D0200AE2D0814EF -:105D4000240C16803C0B80008E2744000E000E268B -:105D5000AD6C002C120000043C02169124050001D9 -:105D6000120500103C023D6C345800E0AE38440887 -:105D70003C1108008E31007C8FBF00183C0660008B -:105D800000118540360F16808FB100148FB00010BF -:105D90003C0E020027BD0020ACCF442003E00008E9 -:105DA000ACCE08103C0218DA345800E0AE38440893 -:105DB0003C1108008E31007C8FBF00183C0660004B -:105DC00000118540360F16808FB100148FB000107F -:105DD0003C0E020027BD0020ACCF442003E00008A9 -:105DE000ACCE08100A00042C240500010A00042C83 -:105DF0000000282124020400A782000CA7800004D0 -:105E0000000020213C06080024C656582405FFFF48 -:105E100024890001000440803124FFFF010618217D -:105E20002C87002014E0FFFAAC6500002404040075 -:105E3000A784000EA7800006000020213C06080071 -:105E400024C656D82405FFFF248D0001000460807D -:105E500031A4FFFF018658212C8A00201540FFFA4B -:105E6000AD650000A7800010A7800008A780000A89 -:105E7000000020213C06080024C657582405FFFFD7 -:105E8000249900010004C0803324FFFF0306782119 -:105E90002C8E000415C0FFFAADE500003C05600043 -:105EA0008CA73D002403E08F00E31024344601401A -:105EB00003E00008ACA63D002487007F000731C244 -:105EC00024C5FFFF000518C2246400013082FFFFD3 -:105ED000000238C0A78400183C010800AC2700303D -:105EE000AF80001400002821000020210000302194 -:105EF0002489000100A728213124FFFF2CA81701C5 -:105F0000110000032C8300801460FFF924C60001F7 -:105F100000C02821AF86001410C0001DA786001203 -:105F200024CAFFFF000A11423C0808002508575800 -:105F30001040000A00002021004030212407FFFF0C -:105F4000248E00010004688031C4FFFF01A8602195 -:105F50000086582B1560FFFAAD87000030A2001FA5 -:105F60005040000800043080240300010043C804AE -:105F700000041080004878212738FFFF03E0000864 -:105F8000ADF8000000C820212405FFFFAC8500000B -:105F900003E000080000000030A5FFFF30C6FFFF4F -:105FA00030A8001F0080602130E700FF0005294273 -:105FB0000000502110C0001D24090001240B000125 -:105FC00025180001010B2004330800FF0126782664 -:105FD000390E00202DED00012DC2000101A218256F -:105FE0001060000D014450250005C880032C40219D -:105FF0000100182110E0000F000A20278D04000086 -:10600000008A1825AD03000024AD000100004021E6 -:106010000000502131A5FFFF252E000131C9FFFFEF -:1060200000C9102B1040FFE72518000103E000080D -:10603000000000008D0A0000014440240A000512FF -:10604000AC68000027BDFFE830A5FFFF30C6FFFFAA -:10605000AFB00010AFBF001430E7FFFF00005021C9 -:106060003410FFFF0000602124AF001F00C0482152 -:10607000241800012419002005E0001601E0102179 -:106080000002F943019F682A0009702B01AE4024E9 -:1060900011000017000C18800064102110E00005AA -:1060A0008C4B000000F84004000838230167582496 -:1060B00000003821154000410000402155600016C5 -:1060C0003169FFFF258B0001316CFFFF05E1FFEC1B -:1060D00001E0102124A2003E0002F943019F682A3A -:1060E0000009702B01AE40241500FFEB000C188056 -:1060F000154600053402FFFF020028210E0004F6B9 -:1061000000003821020010218FBF00148FB0001052 -:1061100003E0000827BD00181520000301601821C6 -:10612000000B1C0224080010306A00FF1540000517 -:10613000306E000F250D000800031A0231A800FF81 -:10614000306E000F15C00005307F000325100004DD -:1061500000031902320800FF307F000317E000053A -:10616000386900012502000200031882304800FF50 -:10617000386900013123000110600004310300FF81 -:10618000250A0001314800FF310300FF000C69407F -:1061900001A34021240A000110CAFFD53110FFFFDE -:1061A000246E000131C800FF1119FFC638C9000173 -:1061B0002D1F002053E0001C258B0001240D000141 -:1061C0000A000589240E002051460017258B000186 -:1061D00025090001312800FF2D090020512000125F -:1061E000258B000125430001010D5004014B1024B3 -:1061F000250900011440FFF4306AFFFF3127FFFF3B -:1062000010EE000C2582FFFF304CFFFF00005021F4 -:106210003410FFFF312800FF2D0900205520FFF228 -:1062200025430001258B0001014648260A0005434D -:10623000316CFFFF00003821000050210A00059555 -:106240003410FFFF27BDFFD8AFB0001030F0FFFFC4 -:10625000AFB10014001039423211FFE00007108086 -:10626000AFB3001C00B1282330D3FFFFAFB200183A -:1062700030A5FFFF008090210260302100442021E2 -:10628000AFBF00200E0005213207001F0222882127 -:106290003403FFFF02402021020028210260302148 -:1062A00000003821104300093231FFFF0220102185 -:1062B0008FBF00208FB3001C8FB200188FB1001465 -:1062C0008FB0001003E0000827BD00280E00052154 -:1062D0000000000000408821022010218FBF002014 -:1062E0008FB3001C8FB200188FB100148FB0001054 -:1062F00003E0000827BD0028000424003C036000E0 -:10630000AC603D0810A000023482100634821016E2 -:1063100003E00008AC623D0427BDFFE0AFB0001011 -:10632000309000FF2E020006AFBF0018104000089A -:10633000AFB10014001030803C030800246353B454 -:1063400000C328218CA40000008000080000000089 -:10635000000020218FBF00188FB100148FB00010F3 -:106360000080102103E0000827BD00209791001253 -:1063700016200051000020213C020800904200330A -:106380000A0005FC00000000978D000E15A00031EA -:10639000000020210A0005FC240200089787000C59 -:1063A00014E0001A000018210060202124020001DE -:1063B0001080FFE98FBF0018000429C2004530217A -:1063C00000A6582B1160FFE43C0880003C07200029 -:1063D000000569C001A76025AD0C00203C038008C2 -:1063E0002402001F2442FFFFAC6000000441FFFDB7 -:1063F0002463000424A5000100A6702B15C0FFF53E -:10640000000569C00A0005E68FBF001897870004E1 -:106410003C04080024845658240504000E0005A1FD -:1064200024060001978B000C24440001308AFFFFF2 -:106430002569FFFF2D480400004028211500004079 -:10644000A789000C24AC3800000C19C00A0005FA1A -:10645000A7800004978700063C040800248456D8CF -:10646000240504000E0005A1240600019799000EE2 -:10647000244400013098FFFF272FFFFF2F0E040058 -:106480000040882115C0002CA78F000EA7800006B1 -:106490003A020003262401003084FFFF0E0005CEDF -:1064A0002C4500010011F8C027F00100001021C0A8 -:1064B0000A0005FC24020008978500169787000A49 -:1064C0003C040800248457580E0005A1240600014E -:1064D000978700128F8900142445000130A8FFFF20 -:1064E00024E3FFFF0109302B0040802114C0001875 -:1064F000A7830012A780000A978500180E000E10CF -:1065000002002021244A05003144FFFF0E0005CE81 -:10651000240500013C05080094A500320E000E1071 -:1065200002002021244521003C0208009042003353 -:106530000A0005FC000521C00A000634A7840006F5 -:1065400024AC3800000C19C00A0005FAA784000426 -:106550000A00064EA785000A308400FF27BDFFE829 -:106560002C820006AFBF0014AFB000101040001521 -:1065700000A03821000440803C030800246353CC71 -:10658000010328218CA40000008000080000000006 -:1065900024CC007F000751C2000C59C23170FFFFAC -:1065A0002547C40030E5FFFF2784000402003021A6 -:1065B0000E0004F624070001978600100206202131 -:1065C000A78400108FBF00148FB0001003E00008F4 -:1065D00027BD00183C0508008CA50030000779C2D3 -:1065E0000E0002F025E4DF003045FFFF3C04080008 -:1065F00024845758240600010E0004F624070001E5 -:10660000978E00128FBF00148FB0001025CD0001AF -:1066100027BD001803E00008A78D00120007C9C2BB -:106620002738FF00001878C231F0FFFF3C04080053 -:10663000248456D802002821240600010E0004F606 -:1066400024070001978D000E260E0100000E840025 -:1066500025AC00013C0B6000A78C000EAD603D082E -:1066600036040006000030213C0760008CE23D0447 -:10667000305F000617E0FFFD24C9000100061B0083 -:10668000312600FF006440252CC50004ACE83D0421 -:1066900014A0FFF68FBF00148FB0001003E00008B5 -:1066A00027BD0018000751C22549C8002406000173 -:1066B000240700013C040800248456580E0004F608 -:1066C0003125FFFF9787000C8FBF00148FB000109B -:1066D00024E6000127BD001803E00008A786000C8F -:1066E0003084FFFF30A5FFFF3C0680008CC201B85C -:1066F0000440FFFE3C084080008838253C03100021 -:10670000ACC00180ACC50184ACC7018803E00008BF -:10671000ACC301B83084FFFF3C0680008CC201B8D6 -:106720000440FFFE3C0840388CA700000088282564 -:106730003C031000ACC70180ACC5018803E0000831 -:10674000ACC301B88F83005C8F8600541066000BC9 -:10675000008040213C07080024E75768000328C058 -:1067600000A710218C44000024630001108800055C -:106770003063000F5466FFFA000328C003E00008EE -:10678000000010213C07080024E7576C00A73021C7 -:1067900003E000088CC200003C039000346200015A -:1067A000008220253C038000AC6400208C65002022 -:1067B00004A0FFFE0000000003E00008000000004D -:1067C0003C028000344300010083202503E00008E0 -:1067D000AC44002027BDFFE0AFB100143091FFFFB3 -:1067E000AFB00010AFBF00181220001200A080212F -:1067F0008CA5000014A00011240400023C068000B7 -:106800008CC201B80440FFFE3C074000022720254F -:106810008FBF00188FB100148FB000103C03100020 -:1068200027BD0020ACC50180ACC4018803E000088E -:10683000ACC301B80A00070F8CA500000E00066665 -:1068400024060200000028210A00070FAE00000005 -:106850003087FFFF3C0680008CC201B80440FFFE79 -:106860003C0A40068CA9000000EA4025ACC9018022 -:106870008CA400043C031000ACC40184ACC80188A3 -:1068800003E00008ACC301B88F83FDE827BDFFE833 -:10689000AFBF0014AFB00010906700080080102157 -:1068A0000080282130E600400000202110C00008B0 -:1068B0008C5000000E0000860200202102002021E2 -:1068C0008FBF00148FB000100A00048927BD001884 -:1068D0000E000724000000000E00008602002021A8 -:1068E000020020218FBF00148FB000100A0004891D -:1068F00027BD001827BDFFE0AFB000108F90FDE866 -:10690000AFBF001CAFB20018AFB100149206000177 -:10691000008088210E0006F630D2000492040005A3 -:10692000001129C2A605000034830040A20300051F -:106930000E000700022020210E00048B02202021DF -:1069400024020001AE02000C02202821A602001041 -:1069500024040002A602001224060200A60200146B -:106960000E000666A60200161640000F8FBF001C20 -:10697000978C00583C0B08008D6B00782588FFFF32 -:106980003109FFFF256A0001012A382B10E00006BB -:10699000A78800583C0F6006240E001635ED001045 -:1069A000ADAE00508FBF001C8FB200188FB1001425 -:1069B0008FB0001003E0000827BD002027BDFFE0D6 -:1069C000AFBF0018AFB10014AFB000100E0006F654 -:1069D000008088218F85FDE80220202190A30005FA -:1069E0000E000700307000FF2402003E1202000576 -:1069F0008FBF00188FB100148FB0001003E00008A3 -:106A000027BD00203C0580008CA401780480FFFE97 -:106A1000240700073C061000ACB1014002202021F1 -:106A2000A0A701448FBF00188FB100148FB00010D1 -:106A3000ACA601780A00074D27BD002027BDFFE066 -:106A4000AFB00010AFBF0018AFB100143C10800011 -:106A50008E110020000000000E00048BAE04002008 -:106A6000AE1100208FBF00188FB100148FB000103E -:106A700003E0000827BD00203084FFFF3C068000B3 -:106A80008CC201B80440FFFE3C0840350088382520 -:106A90003C031000ACC50180ACC00184ACC70188C8 -:106AA00003E00008ACC301B83084FFFF3C0680005F -:106AB0008CC201B80440FFFE3C08403600883825EF -:106AC0003C031000ACC50180ACC00184ACC7018898 -:106AD00003E00008ACC301B827BDFFD0AFB5002468 -:106AE0003095FFFFAFB60028AFB40020AFBF002C39 -:106AF000AFB3001CAFB20018AFB10014AFB00010BC -:106B000030B6FFFF12A000270000A0218F92003CAA -:106B10008E4300003C0680002402004000033E0239 -:106B200000032C0230E4007F006698241482001DCC -:106B300030A500FF8F83004C2C68000A5100001024 -:106B40008F860030000358803C0C0800258C53E8E9 -:106B5000016C50218D490000012000080000000058 -:106B600002D448213125FFFF0E0006C8240400840A -:106B7000166000028F92003CAF80004C8F86003080 -:106B800026580020268F00010300902131F4FFFFDA -:106B900014C00004AF98003C0295282B14A0FFDC21 -:106BA00000000000028010218FBF002C8FB600284B -:106BB0008FB500248FB400208FB3001C8FB2001853 -:106BC0008FB100148FB0001003E0000827BD003023 -:106BD0002407003414A70146000000009247000E6D -:106BE0008F99FDEC8F90FDE824181600A32700195B -:106BF000924A000D3C0880003C07800CA32A001834 -:106C0000964400123C0F60003C117FFFA604005C1C -:106C1000965F00103622FFFF240A000533E5FFFFD0 -:106C2000AE0500548E46001CAD1800288CE900000B -:106C30008DEE44480126682601CD3021AE0600388D -:106C40008E03003824CB00013C0E7F00AE03003CD5 -:106C50008E0C003CAF2C0004AE0B00208E130020E5 -:106C6000AE13001CA320001BAE02002CA32A0012AE -:106C70008E44001424130050AE0400348E1F0034E0 -:106C8000AF3F00148E450018AE0500489258000C26 -:106C9000A218004E920F000835E90020A209000852 -:106CA0008E0D001801AE1824346C4000AE0C001894 -:106CB000920B0000317200FF125302AD2413FF80CB -:106CC0003C040800248457E80E000732000000004E -:106CD00024030004240800013C0508008CA557E8A3 -:106CE0003C048000A2030025A20800058C900178D6 -:106CF0000600FFFE8F92003C240E00023C0D1000A7 -:106D0000AC850140A08E0144AC8D01780A0007EFEC -:106D1000AF80004C2CAD003711A0FF998F8600305A -:106D2000000580803C1108002631541002117821A2 -:106D30008DEE000001C000080000000024100004D7 -:106D400014B0008E3C0780003C0C08008D8C57E886 -:106D50008F86FDE8ACEC00208E4B00088F98FDEC90 -:106D600024090050ACCB00308E430008ACC3005067 -:106D70008E42000CACC200348E4A0010ACCA0038FF -:106D80008E440010ACC400548E5F0014ACDF003C95 -:106D90008E590018AF1900048E4F001CACCF002094 -:106DA00090D10000322500FF10A9027D00000000F4 -:106DB0008CD100348CCF0030022F302304C000F37C -:106DC0002404008C126000F0240200030A0007EF84 -:106DD000AF82004C2418000514B800683C0B8000FA -:106DE0003C0C08008D8C57E88F86FDE8AD6C0020C8 -:106DF0008E4300048F9FFDEC24072000ACC3001CD1 -:106E00009242000824120008A3E200198F8A003C75 -:106E100091440009A3E400188F85003C90B9000A52 -:106E2000332400FF1092001028880009150000BCD0 -:106E3000240D0002240900201089000B3407800073 -:106E4000289100211620000824074000240F00404C -:106E5000108F00053C0700012418008010980002E4 -:106E60003C070002240740008CC400183C0AFF00C5 -:106E7000008AF82403E7C825ACD9001890B2000BAB -:106E8000A0D200278F83003C9465000C10A0023133 -:106E9000000000009467000C3C1F8000A4C7005C49 -:106EA0009062000E2403FFBF24070004A0C2000864 -:106EB0008F8A003C9144000FA0C400098F88003CD9 -:106EC0008D1200108FF9007402592823ACC50058A8 -:106ED0008D180014ACD8002C950F001831F1FFFF6D -:106EE000ACD100409509001A3130FFFFACD000440E -:106EF0008D0E001CACCE0048950D0002A4CD00788C -:106F0000910C000EA0CC000890CB00080163102467 -:106F1000126001D7A0C200088F92003C0A0007EF60 -:106F2000AF87004C2406000614A600143C0E800017 -:106F30003C1008008E1057E88F8CFDE4ADD0002087 -:106F40008E4D00188F86FDE88F8BFDECAD8D000017 -:106F50008CC8003824040005AD8800048CC3003CB4 -:106F600012600081AD6300000A0007EFAF84004C9F -:106F70002409000710A9004B240400063C05080062 -:106F800024A557E80E000705240400818F92003CD9 -:106F90000013102B0A0007EFAF82004C241F0023C0 -:106FA00014BFFFF63C0C80003C0308008C6357E8DC -:106FB0008F8BFDECAD8300208F91FDE88E460004A1 -:106FC0002564002026450014AE2600282406000370 -:106FD0000E000E1C257000308F87003C020020211F -:106FE000240600030E000E1C24E500083C040800E3 -:106FF000248457E80E0007320000000092220000AF -:1070000024040050304A00FF5544FFE18F92003CB9 -:107010000E000E07000000000A0008F48F92003CEA -:107020002408003314A800323C0280003C11080000 -:107030008E3157E88F89FDECAC5100208E4A000854 -:10704000240F00288F8DFDE8AD2A00308E44000CFF -:1070500024060009AD2400348E5F0010AD3F0038D7 -:107060008E590014AD3900208E450018AD2500243E -:107070008E58001CAD380028A12F00118E4E000440 -:1070800012600031ADAE00288F92003C0A0007EF7D -:10709000AF86004C2411002214B1FFB8000000009C -:1070A000240400073C1808008F1857E83C0F8000A4 -:1070B000ADF800205660FEB1AF84004C3C040800DF -:1070C000248457E80E000732241300508F99FDE8FE -:1070D00093320000324500FF10B3016C0000000045 -:1070E0008F92003C000020210A0007EFAF84004C83 -:1070F0003C05080024A557E80E0006D524040081AD -:107100000A0008F48F92003C02D498213265FFFFF8 -:107110000E0006C8240400840A0007EF8F92003C8A -:10712000108DFF51240704002887000310E001AAF6 -:1071300024100004240E0001548EFF4B240740004D -:107140000A0008AA240701003C05080024A557E806 -:107150000E000724240400828F92003C000030219E -:107160000A0007EFAF86004C3C040800248457E86F -:107170008CC200380E0007328CC3003C8F92003C5A -:107180000A00094A00002021240400823C0508006E -:1071900024A557E80E000724000000008F92003C51 -:1071A000000010210A0007EFAF82004C8E5000044F -:1071B0008F91FDE83C0A8000AD500020922200052E -:1071C000020028213046000214C001872404008AEE -:1071D0008F92FDEC020028212404008D924B001BAD -:1071E000316300201460018000000000922D00092E -:1071F000240C001231A800FF110C017B2404008133 -:107200000E0006F6020020219245001B240E000409 -:107210000200202134A90042A249001B0E000700F1 -:10722000A22E00253C0480008C9101780620FFFEF0 -:1072300024180002AC900140A09801448F92003CB9 -:107240003C0F1000AC8F01780A0008F50013102BDA -:107250008E5000048F91FDE83C1F8000AFF00020AD -:1072600092390005020028213327000214E0001A99 -:107270002404008A922600092412001230C400FF60 -:10728000109201110000000092230009240A00045A -:10729000306200FF104A010C000000000E0006F6EC -:1072A000020020218F88FDEC240CFFFE020020212B -:1072B000910E001B35CD0020A10D001BA23200094C -:1072C000922B0005016C90240E000700A2320005ED -:1072D00002002821000020210E0007BA0000000053 -:1072E0000A0008F48F92003C8E5100043C0280009A -:1072F0003C100800261057E8AC5100203C01080063 -:10730000AC3157E89246000330C400041080016994 -:107310008F84FDE824020006A0820009924D001B24 -:107320002408FFC031AC003F01885825A08B00081D -:1073300092430003306A0001154001600000000024 -:107340008E420008AE0200083C0208008C4257F052 -:107350001040015F8F8EFDEC000281C28F85FDE839 -:10736000A5D0000C8E5F000C240F0001240900142E -:10737000ADDF002C8E590010ADD9001C96470016C9 -:10738000A5C7003C96580014A5D8003EACAF000C31 -:10739000A4AF0010A4AF0012A4AF0014A4AF001655 -:1073A00012600163A1C900119244000330920002EF -:1073B0002E5300018F92003C266200080A0007EF5E -:1073C000AF82004C8E4600043C0580003C048008DF -:1073D000ACA600208E4700089089000024110050C0 -:1073E000312200FF105100BC240500883C048000BD -:1073F0008C8F01B805E0FFFE0013802B3C1840097C -:1074000000B81025AF90004C3C101000AC860180F5 -:10741000AC870184AC820188AC9001B80A0007F007 -:107420008F8600308E4500043C0680003C098008B1 -:10743000ACC50020913F00002404005033F900FF48 -:10744000132400B4240600883C0480008C8A01B810 -:107450000540FFFE3C0E400E00CE68253C081000A3 -:10746000AC850180AC800184AC8D0188AC8801B80A -:10747000912B0000240CFF8024040004016C1825CB -:10748000240600300E000666A12300000A0008F45E -:107490008F92003C8E5000048F91FDEC3C0F8000D9 -:1074A000ADF000209225001B30A900101120007CB7 -:1074B000240300813C0480008C8701B804E0FFFEB7 -:1074C0003C1F401FAC900180007F10250013C82B8B -:1074D0003C101000AC800184AF99004CAC82018854 -:1074E000AC9001B80A0007F08F8600308E44001C73 -:1074F0000E0006E100000000104000FC00403821B2 -:107500008F92003C240600893C0580008CAE01B8B7 -:1075100005C0FFFE00000000ACA701808E50001CDB -:107520003C1140010013782B00D138253C1310008A -:10753000ACB00184AF8F004CACA70188ACB301B8EC -:107540000A0007F08F860030965900023C100800B0 -:10755000261057E833380004130000A73C046000ED -:107560008E5F001C3C068000ACDF00203C01080060 -:10757000AC3F57E8964F000231E7000114E000E706 -:10758000000000008E420004AE0200083C1008001B -:107590008E1057F0120000DD3C0680008F85FDE85C -:1075A000241000018CBF00188F91FDEC8F89FDE441 -:1075B00003E6C825ACB90018A0A00005ACB0000CCB -:1075C0003C1808008F1857F08F87003CA4B00010BB -:1075D000001879C2A4B00012A4B00014A4B0001620 -:1075E000A62F000C8CEE00088F8D003C8F8C003C89 -:1075F000AE2E002C8DA8000C24070002AE28001C23 -:10760000918B0010A22B00118F83003C906A001117 -:10761000A12A00088F82003C90440012A0A4004ED2 -:107620008F92003C92460013A22600128F92003CDB -:10763000965F0014A63F003C96590016A639003EFE -:107640008E580018AE3800145660FD4CAF87004CC1 -:107650003C05080024A557E80E000705000020217E -:107660008F92003C000038210A0007EFAF87004CE2 -:107670003C05080024A557E80E00072424040082D6 -:107680008F92003C0A0008D7000038210E000E0738 -:10769000000000008F92003C0A00094A00002021EF -:1076A0000E0006F6020020219232001B020020216B -:1076B000365800100E000700A238001B8F92003CC5 -:1076C0000A000A3D000018210E0007BA24040081B8 -:1076D0000A0008F48F92003C9243000C306A0001CB -:1076E0001140000300000000964B000EA48B002CFC -:1076F0009248000C310C00021180FF3C0000282150 -:10770000964E00128E4D0014A48E001A0A000A0B29 -:10771000AC8D001C8F83005C8F8700541067FF4A7C -:10772000000030213C0808002508576C000320C0E9 -:10773000008830218CD10000122500C8246200018D -:107740003043000F1467FFFA000320C00A000A222A -:10775000000030213C05080024A557E80E0007244E -:107760002404008B8F92003C0A0008D70013382BAA -:107770003C0C08008D8C57E824D9FFFE25910100B0 -:10778000322B007F0167902102331024AD020028C4 -:10779000AE4600D0AE4000D40A000840AE59001CEE -:1077A000ACC000543C0908008D2957E83C05800C0A -:1077B00034A80100ACE900288E500014AD1000D0B0 -:1077C0008E4E0014AD0E00D48E4D001025A7FFFE86 -:1077D0000A00087CAD07001C5490FDA3240740005C -:1077E0000A0008AA240710000E0007AE00000000DF -:1077F0000A0008F48F92003C8C83442C3C05DEADDB -:1078000034B2BEEF3C010800AC2057E81072004FC4 -:10781000000000003C046C6234827970146200083D -:1078200024040002978A0058978300500200282100 -:107830000143482B11200019240400922404000263 -:107840000E0005D6240502003C0B8000AD6200202E -:107850003C010800AC2257E81040000D8F8E003C20 -:10786000240C00282404000391CD001031A800FF4F -:10787000550C0001240400010E00004A0000000025 -:1078800010400004240400830A000A6D8F92003C1B -:10789000240400833C05080024A557E80E000705D2 -:1078A000000000008F92003C0013382B0A0007EF05 -:1078B000AF87004C0A0009D6240200128E4400084B -:1078C0000E0006E1000000000A0009E2AE02000816 -:1078D0003C05080024A557E80E0006D524040087BF -:1078E0008F92003C0A0009FF0013102B24040004AF -:1078F0000E0005D624050030144000170040382142 -:107900008F92003C0A000A52240600833C050800BE -:1079100024A557E80A000B37240400878E4400048E -:107920000E0006E1000000000A000A73AE02000823 -:107930003C05080024A557E80E0007242404008213 -:107940008F92003C0A0009FF000010218C83442C18 -:107950000A000B163C046C628F92003C3C088008C5 -:107960003C0C8000240B0050240A0001AD82002052 -:10797000A10B0000A10A000192490004A10900180E -:1079800092440005A1040019924300063C0408003B -:107990002484576CA103001A924200073C0308009C -:1079A00024635768A102001B92450008A105001C32 -:1079B00092460009A106001D925F000AA11F001E49 -:1079C0009259000BA119001F9258000CA118002019 -:1079D0009251000DA11100219250000EA110002221 -:1079E000924F000FA10F0023924E0010A10E002411 -:1079F000924D0011A10D0025964C0014A50C0028F5 -:107A0000964B00168F8A00548F98005CA50B002AB5 -:107A100096490018000A10C025450001A509002C50 -:107A20008E46001C0044C8210043F82130A5000FF9 -:107A3000AFE60000AF27000010B80003AF85005488 -:107A40000A000A520000302124AD000131A8000FC5 -:107A5000000030210A000A52AF88005C3C07080091 -:107A600024E7576800879021ACC000000000302157 -:107A70000A000A22AE4000003C0482013C03600080 -:107A800034820E02AC603D68AF80007C03E00008E9 -:107A9000AC623D6C27BDFFE8AFB000103090FFFF37 -:107AA000001018422C620041AFBF001414400002C5 -:107AB00024040080240300403C010800AC30006036 -:107AC0003C010800AC2300640E000E100060282169 -:107AD000244802BF2409FF800109282400103980AE -:107AE000001030408FBF00148FB0001000A720217D -:107AF00000861821AF8300643C010800AC250058C3 -:107B00003C010800AC24005C03E0000827BD00181D -:107B1000308300FF30C6FFFF30E400FF3C088000E8 -:107B20008D0201B80440FFFE0003540001443825D3 -:107B30003C09600000E920253C031000AD050180F0 -:107B4000AD060184AD04018803E00008AD0301B86F -:107B50008F86003C3C096012352700108CCB000456 -:107B60003C0C600E35850010316A00062D4800017E -:107B7000ACE800C48CC40004ACA431808CC2000802 -:107B800094C30002ACA2318403E00008A783007410 -:107B90008F85003C8F87FF408F86FF488CAE0004A6 -:107BA0003C0F601235E80010ACEE00688CAD0008A8 -:107BB000ACED006C8CAC0010ACCC004C8CAB000C71 -:107BC000ACCB004894CA00543C0208008C420044EC -:107BD00025490001A4C9005494C400543083FFFF18 -:107BE00010620017000000003C0208008C420040B8 -:107BF000A4C200528CA30018ACE300308CA2001485 -:107C0000ACE2002C8CB90018ACF900388CB8001428 -:107C100024050001ACF800348D0600BC50C50019E5 -:107C20008D0200B48D0200B8A4E2004894E400483C -:107C3000A4E4004A94E800DA03E000083102FFFF00 -:107C40003C0208008C420024A4C00054A4C200528C -:107C50008CA30018ACE300308CA20014ACE2002C22 -:107C60008CB90018ACF900388CB800142405000158 -:107C7000ACF800348D0600BC54C5FFEB8D0200B893 -:107C80008D0200B4A4E2004894E40048A4E4004A51 -:107C900094E800DA03E000083102FFFF8F86003C21 -:107CA0003C0480008CC900088CC80008000929C069 -:107CB000000839C0AC87002090C300073062000480 -:107CC0001040003AAF85007890CB0007316A000879 -:107CD000114000398F87FF448CCD000C8CCE0014EE -:107CE00001AE602B11800032000000008CC2000C3D -:107CF000ACE200708CCB00188F85FF408F88FF4866 -:107D0000ACEB00748CCA00102402FFF8ACAA00C8C7 -:107D10008CC9000CAD0900608CC4001CACA400C070 -:107D200090E3007C0062C824A0F9007C90D8000792 -:107D3000330F000811E000040000000090ED007C0B -:107D400035AC0001A0EC007C90CF000731EE0001C3 -:107D500011C000090000000090E4007C241800021B -:107D600034820002A0E2007C90A300EC307900FF96 -:107D7000133800132408003490C90007312600028C -:107D800010C000040000000090EB007C356A000485 -:107D9000A0EA007C90ED007D31AC003FA0EC007DBE -:107DA00094A700DA03E0000830E2FFFF8F87FF446A -:107DB0000A000C4C8CC200140A000C4DACE00070A0 -:107DC0000A000C6EACA800CC8F8C003C27BDFFD8FD -:107DD000AFB3001CAFB20018AFB00010AFBF0020AF -:107DE000AFB10014918F00153C13600E3673001074 -:107DF00031EB000FA38B00808D8F00048D8B00086A -:107E0000959F0012959900109584001A9598001E70 -:107E1000958E001C33EDFFFF332AFFFF3089FFFFF3 -:107E20003308FFFF31C7FFFF3C010800AC2D0024E1 -:107E30003C010800AC2900443C010800AC2A004089 -:107E4000AE683178AE67317C91850015959100164A -:107E50003C1260123652001030A200FF3230FFFF99 -:107E6000AE623188AE5000B491830014959F001823 -:107E7000240600010066C80433F8FFFFAE5900B8BD -:107E8000AE5800BC918E0014AF8F00683C086006AD -:107E900031CD00FFAE4D00C0918A00159584000ED3 -:107EA0003C07600A314900FFAF8B006C3084FFFF54 -:107EB000AE4900C8351100100E000BB534F00410A7 -:107EC0003C0208008C4200603C0308008C630064A4 -:107ED0003C0608008CC600583C0508008CA5005CD8 -:107EE0008F8400648FBF0020AE23004CAE65319CB0 -:107EF000AE030054AE4500DCAE6231A0AE6331A4E7 -:107F0000AE663198AE2200488FB3001CAE0200501E -:107F10008FB10014AE4200E0AE4300E4AE4600D89C -:107F20008FB000108FB200180A0004BE27BD0028D1 -:107F3000978500769783006027BDFFE8AFB00010FB -:107F400000A3102BAFBF0014240400058F90003C49 -:107F500010400055240900020E0005D68F850064EC -:107F6000AF820078240400031040004F240900026F -:107F70003C0680000E00004AACC20020240700012D -:107F8000240820001040004D24040005978E007640 -:107F90008F8AFF442409005025C50001A78500767B -:107FA000A14900003C0D08008DAD00642403800051 -:107FB0008F84FF40000D6600AD4C0018A540000600 -:107FC000954B000A8F85FF482402FF80016330240F -:107FD000A546000A915F000A0000482103E2C82577 -:107FE000A159000AA0A00008A140004CA08000C533 -:107FF00096180002978300743C020004A49800DAEB -:10800000960F00022418FFBF25EE2401A48E00AEB7 -:108010008E0D0004ACAD00448E0C0008ACAC0040EA -:10802000A4A00050A4A000548E0B000C240C00301F -:10803000AC8B00288E060010AC860024A480003E85 -:10804000A487004EA4870050A483003CAD42007476 -:10805000AC8800C8ACA80060A08700EC909F00C46A -:1080600033F9007FA09900C4909000C402187824CE -:10807000A08F00C4914E007C35CD0001A14D007C45 -:10808000938B0080AD480070AC8C00CCA08B00C6F8 -:108090008F88006C8F870068AC8800B4AC8700B80C -:1080A000A5400078A540007A8FBF00148FB0001063 -:1080B0000120102103E0000827BD00188F850078FB -:1080C0000E0006668F8600640A000D3A240900023D -:1080D00027BDFFE0AFB000108F90003CAFB100149F -:1080E000AFBF00188E0900040E00048B000921C0E8 -:1080F0008E0800048F84FF408F82FF48000839C03B -:108100003C068000ACC70020948500DA9043001341 -:108110001460001C30B1FFFF8F8CFF44918B00086E -:10812000316A00401540000B000000008E0D000475 -:10813000022030218FBF00188FB100148FB00010C3 -:108140002404002200003821000D29C00A000BD4AD -:1081500027BD00200E000061000000008E0D00040D -:10816000022030218FBF00188FB100148FB0001093 -:108170002404002200003821000D29C00A000BD47D -:1081800027BD00200E000059000000008E0D0004E5 -:10819000022030218FBF00188FB100148FB0001063 -:1081A0002404002200003821000D29C00A000BD44D -:1081B00027BD002027BDFFE0AFB200183092FFFFBF -:1081C000AFB00010AFBF001CAFB100141240001ED2 -:1081D000000080218F86003C8CC50000240300062F -:1081E00000053F020005140230E400071483001666 -:1081F000304500FF2CA80006110000400005588003 -:108200003C0C0800258C54EC016C50218D49000079 -:1082100001200008000000008F8E007C240D00016A -:1082200011CD005024020002AF82007C260900011B -:108230003130FFFF24C800200212202B0100302122 -:108240001480FFE5AF88003C020010218FBF001CA6 -:108250008FB200188FB100148FB0001003E0000837 -:1082600027BD00209387006254E0003400003021D5 -:108270000E000C82000000008F86003C0A000D9A60 -:10828000240200018F87007C2405000210E50031E4 -:1082900024040013000028210000302124070001DD -:1082A0000E000BD4000000000A000D9B8F86003CDE -:1082B0008F83007C240200021462FFF62404001263 -:1082C0000E000C37000000008F8500780040302140 -:1082D000240400120E000BD4000038210A000D9B6C -:1082E0008F86003C8F83007C2411000310710029CD -:1082F000241F0002107FFFCE260900012404001075 -:1083000000002821000030210A000DB824070001D8 -:108310008F91007C240600021626FFF92404001029 -:108320000E000CDC00000000144000238F98003C7D -:108330008F86003C0A000D9A2402000324040014D6 -:108340000E000BD4000028218F86003C0A000D9AF5 -:10835000240200020E000D44000000000A000D9BE4 -:108360008F86003C0E000BE4000000002419000280 -:1083700024040014000028210000302100003821CE -:10838000AF99007C0E000BD4000000000A000D9B8A -:108390008F86003C0E000BF4000000008F850078F3 -:1083A000241900020040302124040010000038216C -:1083B0000A000DF1AF99007C004038212404001020 -:1083C000970F0002000028210E000BD431E6FFFFBA -:1083D0008F86003C0A000D9BAF91007C8F84FF4488 -:1083E0003C077FFF34E6FFFF8C8500182402000164 -:1083F00000A61824AC83001803E00008A082000542 -:108400003084FFFF30A5FFFF108000070000182117 -:108410003082000110400002000420420065182153 -:108420001480FFFB0005284003E0000800601021D5 -:1084300010C00007000000008CA2000024C6FFFF4F -:1084400024A50004AC82000014C0FFFB24840004B7 -:1084500003E000080000000010A0000824A3FFFFB4 -:10846000AC86000000000000000000002402FFFFB6 -:108470002463FFFF1462FFFA2484000403E0000871 -:1084800000000000000411C003E000082442024084 -:1084900027BDFFE8AFB0001000808021AFBF0014FF -:1084A0000E000E3100A0202100504821240AFF8038 -:1084B0008FBF00148FB00010012A30243127007FB5 -:1084C0003C08800A3C04210000E8102100C4282553 -:1084D0003C03800027BD0018AC650024AF8200205B -:1084E000AC400000AC65002403E00008AC40004054 -:1084F0003C0D08008DAD005800056180240AFF8006 -:1085000001A45821016C4821012A30243127007F21 -:108510003C08800C3C04210000E8102100C4282500 -:108520003C038000AC650028AF82001C03E000081B -:10853000AC40002430A5FFFF3C0680008CC201B88F -:108540000440FFFE3C08601500A838253C031000DD -:10855000ACC40180ACC00184ACC7018803E0000852 -:10856000ACC301B83C0D08008DAD0058000561801A -:10857000240AFF8001A45821016C4021010A4824EB -:10858000000931403107007F00C728253C04200046 -:1085900000A418253C028000AC43083003E000082A -:1085A000AF80001C27BDFFE8AFB000100080802125 -:1085B000AFBF00140E000E3100A020210050482152 -:1085C000240BFF80012B5024000A39403128007F02 -:1085D0003C0620008FBF00148FB0001000E8282553 -:1085E00034C2000100A218253C04800027BD0018F9 -:1085F000AC83083003E00008AF8000203C05800811 -:108600008CA700603C0680080087102B14400011E6 -:108610002C8340008CA800602D0340001060000FE8 -:10862000240340008CC900600089282B14A000029C -:10863000008018218CC3006000035A42000B308078 -:108640003C0A0800254A554000CA202103E00008E2 -:108650008C8200001460FFF32403400000035A42A0 -:10866000000B30803C0A0800254A554000CA2021F2 -:1086700003E000088C8200003C05800890A60008FA -:108680009384009024C20001304200FF3043007FF9 -:108690001064000C00023827A0A200083C048000EF -:1086A0008C85017804A0FFFE8F8A008824090002CF -:1086B0003C081000AC8A0140A089014403E0000896 -:1086C000AC8801780A000EB630E2008027BDFFC8F2 -:1086D0003C05800834A40080AFBF0034AFBE00303A -:1086E000AFB7002CAFB60028AFB50024AFB4002060 -:1086F000AFB3001CAFB20018AFB10014AFB00010A0 -:10870000948300789482007A104300CD2405FFFF03 -:108710003C1E80080080B8210A000F923C168000A1 -:10872000108A00C88FBF00348F8400883C0B08007B -:108730008D6B005C240AFF803C07800E01644021A1 -:10874000010A4824AEC9002C96E6007A3102007F67 -:108750000047182130C57FFF000580400203A82193 -:1087600096BF00003C1908008F390058240FFF8085 -:1087700033F53FFF032488210015C1800238902182 -:10878000024F58243C0C0100016C5025324E007FF2 -:108790003C0D800C01CD9021028028210E000E346A -:1087A000AECA00288E4800108E4900308F86002007 -:1087B0002402000201093823AE470010A0C20000C5 -:1087C00096E3005C8E4400308F9100200E000E8FE7 -:1087D0003070FFFF00022B800205C8253C1F4200BD -:1087E000033FC025AE3800048E5100048F8700205F -:1087F0008E4F000024080008ACF1001CACEF0018FC -:10880000ACE0000CACE000109250000A2406000519 -:108810002405C000320E00FFA4EE0014964D00089F -:1088200002E09821A4ED0016924C000A3C0D80084D -:10883000318B00FFA4EB00209644000835AC01000A -:10884000A4E40022ACE00024924A000B314900FF6E -:10885000A4E90002A0E800018E4200308F830020CE -:108860002408FFBFAC620008A06600308F8E002095 -:108870002403FFDF95DF003203E5C8240335C0255C -:10888000A5D8003291D10032322F003F35F00040A0 -:10889000A1D000328F890020AD2000348D8B00C024 -:1088A000AD2B00389124003C3C0B7FFF308A007FC9 -:1088B000A12A003C8F8600203564FFFF90C7003C52 -:1088C00000E81024A0C2003C8F9900209325003CB2 -:1088D00000A3F824A33F003C8E5800348F8C002066 -:1088E000AD9800408E4F002C8E51003001F1802356 -:1088F000AD900044918E004831CD007FA18D00489D -:108900008F8500208E4A00308CA900480144402405 -:108910000136382400E83025ACA600489242000A0F -:10892000A0A2004C964300088F9F0020A7E3004EB2 -:108930008E5000308E4400300E0002F08FC5006073 -:1089400092F1007C0002C1400002C90003197821A5 -:10895000322E00020040282111C00003020F8021A6 -:108960000002208002048021926D007C31AC000462 -:108970001180000200057080020E80218E440030BC -:108980008F87002024058000308B0003000B5023CC -:108990003149000302094021ACE800349664007AB2 -:1089A0009662007A9670007A30467FFF24C30001F9 -:1089B000307F7FFF0205C824033FC025A678007AD8 -:1089C0009671007A3C1208008E520060322F7FFFB1 -:1089D00011F20028000000008F8400880E000E694C -:1089E00002A028218F8400880E000E7902802821A1 -:1089F0000E000EAE0000000096F3007896F4007AA8 -:108A00001293000F000028213C0980083524010042 -:108A100093C80008908700C53114007F30E400FF40 -:108A20000284302B14C0FF3E268A0001938D0090F3 -:108A3000268B0001008D6021158BFF3C8F84008800 -:108A40008FBF00348FBE00308FB7002C8FB6002848 -:108A50008FB500248FB400208FB3001C8FB2001894 -:108A60008FB100148FB0001000A0102103E00008A7 -:108A700027BD0038967F007A03E5C824A679007ADE -:108A80009278007A926E007A331100FF001179C259 -:108A9000000F9027001269C031CC007F018D28257E -:108AA000A265007A0A000F878F8400883C0380004B -:108AB0003084FFFF30A5FFFFAC640018AC65001CDC -:108AC00003E000088C62001427BDFFA83C06800864 -:108AD000AFBF0054AFBE0050AFB7004CAFB60048B8 -:108AE000AFB50044AFB40040AFB3003CAFB2003804 -:108AF000AFB10034AFB0003034C80100910500C5FB -:108B000090C700083084FFFF30A500FF30E2007FEF -:108B10000045182AAFA40010A7A000181060009C00 -:108B2000AFA0001490CA00083149007F00A930238B -:108B300024D4FFFF0014882B8FB300100013902B58 -:108B400002328024520000858FB400143C03800858 -:108B500094790052947E00508FB60010033EC023DB -:108B60000018BC00001714030016FC0002C2A82A5B -:108B700016A00002001F2C030040282100143C0016 -:108B80000007240300A4102A5440000100A0202163 -:108B90002885000914A000020080B02124160008D6 -:108BA0003C0C80088D860048001659808D88004C4A -:108BB0003C0380003169FFFF3C0A0010012A202598 -:108BC00034700400AC660038AF90008CAC68003C98 -:108BD000AC64003000000000000000000000000055 -:108BE0000000000000000000000000000000000085 -:108BF000000000008C6E000031CD002011A0FFFDB0 -:108C00000016902A0251782411E000360000B821A5 -:108C10003C1580003C118008922200088EA40100BF -:108C200000008821305E007F0E000E3403C0282132 -:108C30008E1F00108EA4010033F93FFF032028216E -:108C40000E000E4CAFB9001C921800003302003F1A -:108C50002C5300085260000D000080212405000103 -:108C6000004518043067005D14E000B18F92008C5D -:108C7000306400021480014D8F86008C30680080C3 -:108C80005500004A96180012000080218EA40100B1 -:108C90000E000E698FA5001C8EA401000E000E7937 -:108CA00003C028211200004F3C07800826E4000181 -:108CB0008F8C008C0004BC000291A0230017BC0321 -:108CC00002F6302A0014882B259F00402412000150 -:108CD00000D1F02403E08021AF9F008C17C0FFCDAE -:108CE000AFB200143C07800894E800508FB3001026 -:108CF0003C05800002E810213C0D0020A4E2005059 -:108D0000ACAD003094F5005094F600520277502339 -:108D10003149FFFF12D50041AFA900108CF6004C7D -:108D2000001749808CF7004802C9F8210000202173 -:108D300003E9302B02E4602101868021ACFF004C66 -:108D4000ACF000488FB300100013902B0232802447 -:108D50001600FF7F3C0380088FB400148FBF0054BF -:108D60008FBE00503A8200018FB7004C8FB600488A -:108D70008FB500448FB400408FB3003C8FB20038F1 -:108D80008FB100348FB0003003E0000827BD0058D9 -:108D900090CF0008938C009031EE007F00AE6823E6 -:108DA000018D58210A000FDD2574FFFF8F84008894 -:108DB00024100001A7B800180E000E5D97A500183A -:108DC0008EA401000E000E698FA5001C8EA4010068 -:108DD0000E000E7903C028211600FFB526E400011D -:108DE0003C07800894E800508FB300103C058000D9 -:108DF00002E810213C0D0020A4E20050ACAD003090 -:108E000094F5005094F60052027750233149FFFF49 -:108E10000014882B16D5FFC1AFA9001094FE005492 -:108E20008CF0004433D8FFFE001878C0020F702188 -:108E3000ACAE003C8CF900448CA3003C03235823C7 -:108E4000196002EA000000008CF200402642000196 -:108E5000ACA200383C05005034A700103C03800051 -:108E6000AC670030000000000000000000000000BF -:108E700000000000000000000000000000000000F2 -:108E8000000000008C7F000033E6002010C0FFFDD2 -:108E90003C108008960D00543C1780003C0680086A -:108EA00031B30001001350C00157B0218EC9040036 -:108EB0003C0708008CE700443C040020ACC9004893 -:108EC0008ED50404240C0001ACD5004C10EC02D06B -:108ED000AEE40030961800523C0508008CA5004016 -:108EE00000B87821A60F0052960E005425C3000149 -:108EF000A6030054961900543324FFFF5487FF0F34 -:108F00008FB3001030A5FFFF0E000FBBA60000546A -:108F10003C0508008CA50024961200520045382319 -:108F20000247F023A61E00520A000FDF8FB3001085 -:108F30008F93001C3C0700808E4400283C1FFFEFED -:108F400037F9FFFFAE6400008E420024A260000AE1 -:108F50003C0FFF9FAE6200049245002C35EEFFFFF0 -:108F60003C0C0040A265000C8E71000CA265000B49 -:108F70003C0600FF0227C0250319682401AE5824CF -:108F8000016C5025AE6A000C8E490004AE600018DA -:108F900034D0FFFFAE6900148E48002C8F82008809 -:108FA000A660000801102024AE6400108E51000855 -:108FB00096470012AE7100208E58000C30E33FFF40 -:108FC00000032980AE7800248E4C001400A2F82102 -:108FD00030F90001AE6C00288E4B0018001F71C2E2 -:108FE00000197B80AE6B002C8E49001C01CF6821DC -:108FF000A66D001CAE690030964A00028E46002025 -:10900000A66A001EAE66003492430033307000043E -:1090100056000006924B00003C06800834D0010048 -:109020008E0800C0AE680030924B00008F8A00208E -:10903000A14B0030924900333123000250600007F9 -:10904000924400018F8C0020240FFF80918E00300D -:1090500001CF6825A18D0030924400018F8200204D -:109060002418FFBF240AFFDFA04400318F9900209D -:109070003C088008350400809331003C323F007F7B -:10908000A33F003C8F8D002091AF003C01F870247D -:10909000A1AE003C8F8700208E6C001490E3003C52 -:1090A0002D8B0001000B4940006A302400C9802547 -:1090B000A0F0003C964500128F870020A4E5003206 -:1090C0008E450004909F007C30A20003000288239C -:1090D0003239000300B9102133F8000217000002F2 -:1090E00024440034244400303C038008346600806B -:1090F00090C9007C00A980243208000415000002F9 -:1091000024830004008018218F840020240800029A -:10911000ACE30034A08800009242003F8F9F002003 -:109120003C188008370F0080A3E200018F910020D7 -:109130009259003F8E440004A639000295EE005C6F -:109140000E000E8F31D0FFFF00026B80020D5825FC -:109150003C0C4200016C2825AE2500048E4A0038E4 -:109160008F850020ACAA00188E470034ACA7001CE5 -:10917000ACA0000CACA00010A4A00014A4A0001689 -:10918000A4A00020A4A00022ACA000248E620014A1 -:109190005040000124020001ACA200080E000EAEF7 -:1091A000241100010A0010332410000190D30001A3 -:1091B000327200201240018A241000013C0A80080B -:1091C0003547008090E3007C8F93001CAFA0002403 -:1091D0003069000111200011AFB000203C0580086B -:1091E0008CCB00148CAC0060016C882B1620000323 -:1091F000016028213C1080088E0500603C0F80082B -:1092000035E300808C6E007000AE682B15A0000264 -:1092100000A020218C640070AFA400248F82FF4C3A -:109220008CC400148C5900700099C02B53000001AD -:109230008C4400708FA200240082F82313E0000306 -:10924000AFBF002824040002AFA400208FB200208A -:109250000292402B1500015B000018218CC50038DC -:109260008E6B000C3C0C0080AE6500008CC9003495 -:109270003C11FF9F016C5025AE69000490C8003F6F -:109280003623FFFF014310243C1200203C04FFEF73 -:10929000A268000B00523825349FFFFF00FFC02456 -:1092A0003C1900088F87008C03197825AE6F000CDD -:1092B0008CED0014AE6000188FB10024AE6D001468 -:1092C0008CF000188FAE0028AE70001C8CE50008F2 -:1092D000022E6021AE6500248CEB000CA6600038E5 -:1092E000A660003AAE6C002CAE600028AE6B002089 -:1092F0008CEA00148FA30028015148230123302356 -:1093000010C00011AE66001090E9003D8E620004AE -:109310008E7F00000009910000527821000020217A -:1093200001F2C82B03E4C02103197021AE6F0004C1 -:10933000AE6E000090ED003DA26D000A8F90008C93 -:1093400096060006A66600088F98002024190002E1 -:109350003C0F80088FA4002435EE0080A319000084 -:1093600095CD005C8F9200200E000E8F31B0FFFF74 -:1093700000022B80020560253C0642008F85008C90 -:1093800001865825AE4B00048F8400208CB1003834 -:10939000AC9100188CA30034AC83001CAC80000C92 -:1093A000AC800010A4800014A4800016A4800020CB -:1093B000A4800022AC80002490AA003F8FA7002444 -:1093C000A48A000210E0000C240900018FBF0028CD -:1093D00053E0018890A2003D90A2003E2448000185 -:1093E000A08800018F8500208FA40024ACA4000871 -:1093F0000A0012133C118008A08900018F8500200B -:1094000024020001ACA200083C1180083623008031 -:10941000906A007C3147000214E000022406003408 -:10942000240600308F8D008C3C0F800835EE0080C4 -:1094300091AC000091C8007C8FB00024A0AC00303B -:109440008F91008C8F8200208FAA00249227000128 -:1094500032120003240B0004A047003101721823CC -:109460008F84008C8F8B0020241FC00094980012E2 -:109470009579003230690003330F3FFF033F7024BA -:1094800001CF6825A56D00329165003200CA3021F8 -:1094900000C9302130B0003F360C0040A16C0032D2 -:1094A0008FB2002431070004124000028F85002093 -:1094B00000C730213C048008ACA600343488010089 -:1094C0008D1900C08FBF0024240DFFBFACB9003838 -:1094D00090AF003C2FF800012412FFDF31EE007F37 -:1094E000A0AE003C8F8B0020001889409170003C9A -:1094F000020D6024A16C003C8F87002090E3003CAB -:109500000072502401511025A0E2003C8F88008C8D -:109510008F9900208D090020AF2900408D0600247E -:10952000AF2600448D040028AF2400488D1F002C76 -:10953000AF3F004C0E000EAE000000008FB80020C0 -:10954000240500025705009F8FA300203C1F8000C8 -:109550003C1280088FE40100925800088F92FF4C63 -:109560000E000E343305007F8F8E00208FAF002059 -:109570008FA40028A1CF00009659005C8F91002095 -:109580000E000E8F3330FFFF00025B80020B682558 -:109590003C0842008F8B008C01A83025AE260004C9 -:1095A0008D7000388F8600200000282100051100F2 -:1095B000ACD000188D6C00343C047FFF3488FFFF72 -:1095C000ACCC001C9171003E8CCA001C8CDF0018D2 -:1095D0000011390000111F02014770210043482586 -:1095E00001C7C02B03E9782101F8C821ACCE001CCB -:1095F000ACD90018ACC0000CACC00010916D003E9E -:109600008FAA002824070005A4CD0014957000043B -:109610002418C0000148C824A4D00016916C003E54 -:1096200001402021A4CC002095650004A4C500229F -:10963000ACC000249163003FA4C300029171003DBF -:1096400026220001A0C200018F8900203C02800870 -:1096500034460100AD2A0008A12700308F91002078 -:109660008F9F008C2402FF80962F003297EE00120D -:10967000030F802431CD3FFF020D6025A62C003260 -:10968000922500322418FFBF2410FFDF30AB003FCB -:1096900035630040A22300328F9F00202403FFFF88 -:1096A000AFE000348CCA00C0AFEA003893E7003C5A -:1096B00030E9007FA3E9003C8F8D00203C09800049 -:1096C00091AF003C01F87024A1AE003C8F8B0020CC -:1096D000916C003C01902824A165003C8F870020FC -:1096E000ACE300408FB100243C038008ACF100449F -:1096F00090EA004801423025A0E600488F90002003 -:109700008F8E008C8E1F004803E9C0240319782532 -:10971000AE0F004891CD003EA20D004C8F8C008C06 -:109720008F8B002095850004A565004E0E0002F089 -:109730008C650060924A007C004028218FA600289A -:109740000002114000058900005138213149000212 -:109750001120000300C71821000520800064182193 -:109760003C028008344A00809147007C30E90004C4 -:10977000112000038FB9002800056080006C1821BB -:10978000240B00048F91002033300003017040232C -:10979000310D0003006D3021AE2600343C038008FB -:1097A000A66500383C0580008CA401009073000879 -:1097B0000E000E793265007F0E000EAE0000000034 -:1097C0008FA300200003782B000F80230290A02499 -:1097D00000608021006088210A0010330010802B77 -:1097E0008F91001C8CD8003824190003A620000893 -:1097F000AE3800008CCF0034A220000A8F8E008C7F -:10980000AE2F00043C05008091CB003FA239000C34 -:109810008E28000C3C0DFF9FA22B000B010510258C -:1098200035A3FFFF3C13FFEF8F8E008C00433824DD -:10983000366AFFFF00EA4824AE29000C8DC40014EC -:1098400095D800128F860088AE2400108DCC0014AD -:10985000AE200018AE200020AE2C0014AE20002454 -:109860008DDF0018330C3FFF000C9180AE3F0028C5 -:109870008DCF00080246C821330B0001AE2F003007 -:109880008DC3000C8F930020001941C2000B2B8068 -:1098900001056821240200023C0A8008A62D001C54 -:1098A000A6200034AE23002C35470080A2620000C1 -:1098B00094E9005C8F9900203C044200313FFFFF97 -:1098C00003E43025AF2600048F98008C240E00019D -:1098D0002402C0008F12003824060034AF32001872 -:1098E0008F0F00343C12800836580080AF2F001CC8 -:1098F000AF20000CAF200010A7200014A7200016F6 -:10990000A7200020A7200022AF200024A7300002BB -:10991000A32E00018F8D00208F8B008CADB000082E -:1099200091680000A1A800308F91008C8F830020E7 -:1099300092250001A06500318F9F002097F300322F -:1099400002625024014C3825A7E7003293E9003227 -:109950003124003FA3E40032930F007C31EE00027B -:1099600015C000028F840020240600303C0E8008C1 -:10997000AC86003435D101008E3900C02403FFBF0E -:1099800002008821AC990038908B003C0010802B9D -:109990003165007FA085003C8F8D002091A8003CA0 -:1099A00001031024A1A2003C8F87002090F3003C0B -:1099B000366A0020A0EA003C8F9F008C8F92002026 -:1099C0008FE90020AE4900408FE40024AE440044FB -:1099D0008FEC0028AE4C00488FE6002C0E000EAE37 -:1099E000AE46004C0A001033000000000A0010A42C -:1099F0008CE2004024480001A08800018F850020EF -:109A00008FA40024ACA400080A0012133C118008A3 -:109A100094CB00523C0808008D080024010B102153 -:109A2000A4C200520A000FDF8FB3001027BDFFE071 -:109A30003C0D8008AFB20018AFB00010AFBF001CE3 -:109A4000AFB1001435B200808E4C001835A801006B -:109A5000964B000695A70050910900EC000C5602A9 -:109A6000016728233143007F312600FF24020003D1 -:109A7000A3830090AF84008810C2001B30B0FFFFAA -:109A8000910600EC2412000530C200FF1052003392 -:109A900000000000160000098FBF001C8FB20018E4 -:109AA0008FB100148FB00010240D0C003C0C80000E -:109AB00027BD002003E00008AD8D00240E000FC27A -:109AC000020020218FBF001C8FB200188FB100143C -:109AD0008FB00010240D0C003C0C800027BD00202E -:109AE00003E00008AD8D0024965800789651007A66 -:109AF000924E007D0238782631E8FFFF31C400C065 -:109B0000148000092D11000116000037000000002C -:109B10005620FFE28FBF001C0E000EC300000000A5 -:109B20000A0013B78FBF001C1620FFDA00000000E8 -:109B30000E000EC3000000001440FFD88FBF001CB1 -:109B40001600002200000000925F007D33E2003F1B -:109B5000A242007D0A0013B78FBF001C950900DAEE -:109B60008F86006400802821240400050E0006660C -:109B70003130FFFF978300763C0480002465FFFFAF -:109B8000A78500768C8A01B80540FFFE0000000022 -:109B9000AC8001808FBF001CAC9001848FB2001894 -:109BA0008FB100148FB000103C0760133C0B100005 -:109BB000240D0C003C0C800027BD0020AC870188E0 -:109BC000AC8B01B803E00008AD8D00240E000FC27D -:109BD000020020215040FFB18FBF001C925F007D2A -:109BE0000A0013E433E2003F0E000FC202002021FE -:109BF0001440FFAA8FBF001C1220000700000000C5 -:109C00009259007D3330003F36020040A242007D71 -:109C10000A0013B78FBF001C0E000EC30000000027 -:109C20005040FF9E8FBF001C9259007D3330003F93 -:109C30000A00141336020040000411C003E00008BB -:109C4000244202403C050006008510253C038000AC -:109C5000AC620030000000000000000000000000C6 -:109C60003C0580008CA7000030E6001010C0FFFD0E -:109C7000000000008CAB003C8CAA003C0164482131 -:109C8000012A402B110000043C0680008CAD0038F6 -:109C900025AC0001ACAC00388CCF003C01E4702155 -:109CA00003E00008ACCE003C27BDFFD0AFB20018E7 -:109CB000AFB00010AFBF0028AFB50024AFB4002094 -:109CC000AFB3001CAFB1001400A0902114A000128B -:109CD000008080218F8200240002188014600037E9 -:109CE000240400100E001421000000008FBF002883 -:109CF0008FB500248FB400208FB3001C8FB20018E2 -:109D00008FB100148FB000100000102127BD00306B -:109D100003E00008AF80002410A0001E000088218E -:109D20003C138000241400200A0014603C15000538 -:109D3000263100040232502B11400017024010213E -:109D40008F8800248E0700002404008000084880CB -:109D50000133182125060001AC6704002610000419 -:109D600014D4FFF3AF8600240E001421000000007D -:109D7000AE75003000000000000000000000000090 -:109D800000000000263100040232502B1540FFEC89 -:109D9000AF800024024010218FBF00288FB500241F -:109DA0008FB400208FB3001C8FB200188FB1001445 -:109DB0008FB0001003E0000827BD0030000320230F -:109DC0003085000F0A0014490065202127BDFFD807 -:109DD0003C03800000A03821AC670038AFB100140C -:109DE000AC66003C008088213C060022AC66003056 -:109DF000AFB00010AC7100283C10800C3C04800C0B -:109E000024050070AFBF0024AFB40020AFB3001C26 -:109E10000E00143AAFB20018260400800E00143A67 -:109E200024050080260401000E00143A240500F0E9 -:109E30003C0208008C4200641040001300008021A6 -:109E40003C1480002413FF803C12800C0E00141E72 -:109E50000200202100514821312A007F0133402493 -:109E60000152202124050050AE8800280E00143A2B -:109E7000261000013C0508008CA500640205202B7B -:109E80001480FFF2000000003C0608008CC6006051 -:109E900010C00015000080213C1480002413FF80B6 -:109EA0003C12800C3C1908008F3900580010C1800A -:109EB000240500400331782101F8682131AE007F8C -:109EC00001B3602401D22021AE8C00280E00143A88 -:109ED000261000013C0608008CC600600206582BC4 -:109EE0001560FFF0000000003C1008008E10005CC0 -:109EF0002414FF803C1F800C0211982102749024CE -:109F00003262007F3C118000005F2021AE320028C9 -:109F10000E00143A000628408FBF00248FB40020A2 -:109F20008FB3001C8FB200188FB100148FB00010D7 -:109F300000002021000028210A00143A27BD002833 -:109F40008F83003C8C62000410400003000000007E -:109F500003E00008000000008C6400108C6500081D -:089F60000A0014838C66000C5A -:089F6800000000000000001BD6 -:109F70000000000F0000000A0000000800000006BA -:109F800000000005000000050000000400000004BF -:109F900000000003000000030000000300000003B5 -:109FA00000000003000000020000000200000002A8 -:109FB0000000000200000002000000020000000299 -:109FC0000000000200000002000000020000000289 -:109FD0000000000200000002000000020000000279 -:0C9FE00000000001000000010000000172 -:049FEC0080080100E8 -:109FF0008008008080080000080017900800179073 -:10A00000080017C8080017C8080017DC080017ACBC -:10A0100008001A04080019D008001A5C08001A5C2D -:10A0200008001AE408001A148008024008002154AD -:10A0300008001FA00800217C0800221408002364E7 -:10A04000080023B0080024D4080023DC08002460A2 -:10A0500008002010080029880800292C08001FBCCF -:10A0600008001FBC08001FBC080025480800254840 -:10A0700008001FBC08001FBC0800280408001FBC03 -:10A0800008001FBC08001FBC08001FBC0800286493 -:10A0900008001FBC08001FBC08001FBC08001FBC34 -:10A0A00008001FBC08001FBC08001FBC08001FBC24 -:10A0B00008001FBC08001FBC08001FBC08001FBC14 -:10A0C00008001FBC08001FBC080023D008001FBCEC -:10A0D00008001FBC080028D408001FBC08001FBCD3 -:10A0E00008001FBC08001FBC08001FBC08001FBCE4 -:10A0F00008001FBC08001FBC08001FBC08001FBCD4 -:10A1000008001FBC08001FBC08001FBC08001FBCC3 -:10A1100008001FBC08001FBC08001FBC080027283F -:10A1200008001FBC08001FBC08002690080025EC92 -:10A130000800375008003724080036F0080036C4FD -:10A14000080036A408003658800801008008008006 -:08A15000800800008008008077 -:08A158000A000C760000000073 -:10A16000000000000000000D727870342E362E3191 -:10A17000360000000406100300000000000000018B -:10A1800000000000000000000000000000000000CF -:10A1900000000000000000000000000000000000BF -:10A1A00000000000000000000000000000000000AF -:10A1B000000000000000000000000000000000009F -:10A1C000000000000000000000000000000000008F -:10A1D000000000000000000000000000000000007F -:10A1E000000000000000000000000000000000006F -:10A1F000000000000000000000000000000000005F -:10A20000000000000000000000000000000000004E -:10A21000000000000000000000000000000000003E -:10A22000000000000000000000000000000000002E -:10A23000000000000000000000000000000000001E -:10A24000000000000000000000000000000000000E -:10A2500000000000000000000000000000000000FE -:10A2600000000000000000000000000000000000EE -:10A2700000000000000000000000000000000000DE -:10A2800000000000000000000000000000000000CE -:10A2900000000000000000000000000000000000BE -:10A2A00000000000000000000000000000000000AE -:10A2B000000000000000000000000000000000009E -:10A2C000000000000000000000000000000000008E -:10A2D000000000000000000000000000000000007E -:10A2E000000000000000000000000000000000006E -:10A2F000000000000000000000000000000000005E -:10A30000000000000000000000000000000000004D -:10A31000000000000000000000000000000000003D -:10A32000000000000000000000000000000000002D -:10A33000000000000000000000000000000000001D -:10A34000000000000000000000000000000000000D -:10A3500000000000000000000000000000000000FD -:10A3600000000000000000000000000000000000ED -:10A3700000000000000000000000000000000000DD -:10A3800000000000000000000000000000000000CD -:10A3900000000000000000000000000000000000BD -:10A3A00000000000000000000000000000000000AD -:10A3B000000000000000000000000000000000009D -:10A3C000000000000000000000000000000000008D -:10A3D000000000000000000000000000000000007D -:10A3E000000000000000000000000000000000006D -:10A3F000000000000000000000000000000000005D -:10A40000000000000000000000000000000000004C -:10A41000000000000000000000000000000000003C -:10A42000000000000000000000000000000000002C -:10A43000000000000000000000000000000000001C -:10A44000000000000000000000000000000000000C -:10A4500000000000000000000000000000000000FC -:10A4600000000000000000000000000000000000EC -:10A4700000000000000000000000000000000000DC -:10A4800000000000000000000000000000000000CC -:10A4900000000000000000000000000000000000BC -:10A4A00000000000000000000000000000000000AC -:10A4B000000000000000000000000000000000009C -:10A4C000000000000000000000000000000000008C -:10A4D000000000000000000000000000000000007C -:10A4E000000000000000000000000000000000006C -:10A4F000000000000000000000000000000000005C -:10A50000000000000000000000000000000000004B -:10A51000000000000000000000000000000000003B -:10A52000000000000000000000000000000000002B -:10A53000000000000000000000000000000000001B -:10A54000000000000000000000000000000000000B -:10A5500000000000000000000000000000000000FB -:10A5600000000000000000000000000000000000EB -:10A5700000000000000000000000000000000000DB -:10A5800000000000000000000000000000000000CB -:10A5900000000000000000000000000000000000BB -:10A5A00000000000000000000000000000000000AB -:10A5B000000000000000000000000000000000009B -:10A5C000000000000000000000000000000000008B -:10A5D000000000000000000000000000000000007B -:10A5E000000000000000000000000000000000006B -:10A5F000000000000000000000000000000000005B -:10A60000000000000000000000000000000000004A -:10A61000000000000000000000000000000000003A -:10A62000000000000000000000000000000000002A -:10A63000000000000000000000000000000000001A -:10A64000000000000000000000000000000000000A -:10A6500000000000000000000000000000000000FA -:10A6600000000000000000000000000000000000EA -:10A6700000000000000000000000000000000000DA -:10A6800000000000000000000000000000000000CA -:10A6900000000000000000000000000000000000BA -:10A6A00000000000000000000000000000000000AA -:10A6B000000000000000000000000000000000009A -:10A6C000000000000000000000000000000000008A -:10A6D000000000000000000000000000000000007A -:10A6E000000000000000000000000000000000006A -:10A6F000000000000000000000000000000000005A -:10A700000000000000000000000000000000000049 -:10A710000000000000000000000000000000000039 -:10A720000000000000000000000000000000000029 -:10A730000000000000000000000000000000000019 -:10A740000000000000000000000000000000000009 -:10A7500000000000000000000000000000000000F9 -:10A7600000000000000000000000000000000000E9 -:10A7700000000000000000000000000000000000D9 -:10A7800000000000000000000000000000000000C9 -:10A7900000000000000000000000000000000000B9 -:10A7A00000000000000000000000000000000000A9 -:10A7B0000000000000000000000000000000000099 -:10A7C0000000000000000000000000000000000089 -:10A7D0000000000000000000000000000000000079 -:10A7E0000000000000000000000000000000000069 -:10A7F0000000000000000000000000000000000059 -:10A800000000000000000000000000000000000048 -:10A810000000000000000000000000000000000038 -:10A820000000000000000000000000000000000028 -:10A830000000000000000000000000000000000018 -:10A840000000000000000000000000000000000008 -:10A8500000000000000000000000000000000000F8 -:10A8600000000000000000000000000000000000E8 -:10A8700000000000000000000000000000000000D8 -:10A8800000000000000000000000000000000000C8 -:10A8900000000000000000000000000000000000B8 -:10A8A00000000000000000000000000000000000A8 -:10A8B0000000000000000000000000000000000098 -:10A8C0000000000000000000000000000000000088 -:10A8D0000000000000000000000000000000000078 -:10A8E0000000000000000000000000000000000068 -:10A8F0000000000000000000000000000000000058 -:10A900000000000000000000000000000000000047 -:10A910000000000000000000000000000000000037 -:10A920000000000000000000000000000000000027 -:10A930000000000000000000000000000000000017 -:10A940000000000000000000000000000000000007 -:10A9500000000000000000000000000000000000F7 -:10A9600000000000000000000000000000000000E7 -:10A9700000000000000000000000000000000000D7 -:10A9800000000000000000000000000000000000C7 -:10A9900000000000000000000000000000000000B7 -:10A9A00000000000000000000000000000000000A7 -:10A9B0000000000000000000000000000000000097 -:10A9C0000000000000000000000000000000000087 -:10A9D0000000000000000000000000000000000077 -:10A9E0000000000000000000000000000000000067 -:10A9F0000000000000000000000000000000000057 -:10AA00000000000000000000000000000000000046 -:10AA10000000000000000000000000000000000036 -:10AA20000000000000000000000000000000000026 -:10AA30000000000000000000000000000000000016 -:10AA40000000000000000000000000000000000006 -:10AA500000000000000000000000000000000000F6 -:10AA600000000000000000000000000000000000E6 -:10AA700000000000000000000000000000000000D6 -:10AA800000000000000000000000000000000000C6 -:10AA900000000000000000000000000000000000B6 -:10AAA00000000000000000000000000000000000A6 -:10AAB0000000000000000000000000000000000096 -:10AAC0000000000000000000000000000000000086 -:10AAD0000000000000000000000000000000000076 -:10AAE0000000000000000000000000000000000066 -:10AAF0000000000000000000000000000000000056 -:10AB00000000000000000000000000000000000045 -:10AB10000000000000000000000000000000000035 -:10AB20000000000000000000000000000000000025 -:10AB30000000000000000000000000000000000015 -:10AB40000000000000000000000000000000000005 -:10AB500000000000000000000000000000000000F5 -:10AB600000000000000000000000000000000000E5 -:10AB700000000000000000000000000000000000D5 -:10AB800000000000000000000000000000000000C5 -:10AB900000000000000000000000000000000000B5 -:10ABA00000000000000000000000000000000000A5 -:10ABB0000000000000000000000000000000000095 -:10ABC0000000000000000000000000000000000085 -:10ABD0000000000000000000000000000000000075 -:10ABE0000000000000000000000000000000000065 -:10ABF0000000000000000000000000000000000055 -:10AC00000000000000000000000000000000000044 -:10AC10000000000000000000000000000000000034 -:10AC20000000000000000000000000000000000024 -:10AC30000000000000000000000000000000000014 -:10AC40000000000000000000000000000000000004 -:10AC500000000000000000000000000000000000F4 -:10AC600000000000000000000000000000000000E4 -:10AC700000000000000000000000000000000000D4 -:10AC800000000000000000000000000000000000C4 -:10AC900000000000000000000000000000000000B4 -:10ACA00000000000000000000000000000000000A4 -:10ACB0000000000000000000000000000000000094 -:10ACC0000000000000000000000000000000000084 -:10ACD0000000000000000000000000000000000074 -:10ACE0000000000000000000000000000000000064 -:10ACF0000000000000000000000000000000000054 -:10AD00000000000000000000000000000000000043 -:10AD10000000000000000000000000000000000033 -:10AD20000000000000000000000000000000000023 -:10AD30000000000000000000000000000000000013 -:10AD40000000000000000000000000000000000003 -:10AD500000000000000000000000000000000000F3 -:10AD600000000000000000000000000000000000E3 -:10AD700000000000000000000000000000000000D3 -:10AD800000000000000000000000000000000000C3 -:10AD900000000000000000000000000000000000B3 -:10ADA00000000000000000000000000000000000A3 -:10ADB0000000000000000000000000000000000093 -:10ADC0000000000000000000000000000000000083 -:10ADD0000000000000000000000000000000000073 -:10ADE0000000000000000000000000000000000063 -:10ADF0000000000000000000000000000000000053 -:10AE00000000000000000000000000000000000042 -:10AE10000000000000000000000000000000000032 -:10AE20000000000000000000000000000000000022 -:10AE30000000000000000000000000000000000012 -:10AE40000000000000000000000000000000000002 -:10AE500000000000000000000000000000000000F2 -:10AE600000000000000000000000000000000000E2 -:10AE700000000000000000000000000000000000D2 -:10AE800000000000000000000000000000000000C2 -:10AE900000000000000000000000000000000000B2 -:10AEA00000000000000000000000000000000000A2 -:10AEB0000000000000000000000000000000000092 -:10AEC0000000000000000000000000000000000082 -:10AED0000000000000000000000000000000000072 -:10AEE0000000000000000000000000000000000062 -:10AEF0000000000000000000000000000000000052 -:10AF00000000000000000000000000000000000041 -:10AF10000000000000000000000000000000000031 -:10AF20000000000000000000000000000000000021 -:10AF30000000000000000000000000000000000011 -:10AF40000000000000000000000000000000000001 -:10AF500000000000000000000000000000000000F1 -:10AF600000000000000000000000000000000000E1 -:10AF700000000000000000000000000000000000D1 -:10AF800000000000000000000000000000000000C1 -:10AF900000000000000000000000000000000000B1 -:10AFA00000000000000000000000000000000000A1 -:10AFB0000000000000000000000000000000000091 -:10AFC0000000000000000000000000000000000081 -:10AFD0000000000000000000000000000000000071 -:10AFE0000000000000000000000000000000000061 -:10AFF0000000000000000000000000000000000051 -:10B000000000000000000000000000000000000040 -:10B010000000000000000000000000000000000030 -:10B020000000000000000000000000000000000020 -:10B030000000000000000000000000000000000010 -:10B040000000000000000000000000000000000000 -:10B0500000000000000000000000000000000000F0 -:10B0600000000000000000000000000000000000E0 -:10B0700000000000000000000000000000000000D0 -:10B0800000000000000000000000000000000000C0 -:10B0900000000000000000000000000000000000B0 -:10B0A00000000000000000000000000000000000A0 -:10B0B0000000000000000000000000000000000090 -:10B0C0000000000000000000000000000000000080 -:10B0D0000000000000000000000000000000000070 -:10B0E0000000000000000000000000000000000060 -:10B0F0000000000000000000000000000000000050 -:10B10000000000000000000000000000000000003F -:10B11000000000000000000000000000000000002F -:10B12000000000000000000000000000000000001F -:10B13000000000000000000000000000000000000F -:10B1400000000000000000000000000000000000FF -:10B1500000000000000000000000000000000000EF -:10B1600000000000000000000000000000000000DF -:10B1700000000000000000000000000000000000CF -:10B1800000000000000000000000000000000000BF -:10B1900000000000000000000000000000000000AF -:10B1A000000000000000000000000000000000009F -:10B1B000000000000000000000000000000000008F -:10B1C000000000000000000000000000000000007F -:10B1D000000000000000000000000000000000006F -:10B1E000000000000000000000000000000000005F -:10B1F000000000000000000000000000000000004F -:10B20000000000000000000000000000000000003E -:10B21000000000000000000000000000000000002E -:10B22000000000000000000000000000000000001E -:10B23000000000000000000000000000000000000E -:10B2400000000000000000000000000000000000FE -:10B2500000000000000000000000000000000000EE -:10B2600000000000000000000000000000000000DE -:10B2700000000000000000000000000000000000CE -:10B2800000000000000000000000000000000000BE -:10B2900000000000000000000000000000000000AE -:10B2A000000000000000000000000000000000009E -:10B2B000000000000000000000000000000000008E -:10B2C000000000000000000000000000000000007E -:10B2D000000000000000000000000000000000006E -:10B2E000000000000000000000000000000000005E -:10B2F000000000000000000000000000000000004E -:10B30000000000000000000000000000000000003D -:10B31000000000000000000000000000000000002D -:10B32000000000000000000000000000000000001D -:10B33000000000000000000000000000000000000D -:10B3400000000000000000000000000000000000FD -:10B3500000000000000000000000000000000000ED -:10B3600000000000000000000000000000000000DD -:10B3700000000000000000000000000000000000CD -:10B3800000000000000000000000000000000000BD -:10B3900000000000000000000000000000000000AD -:10B3A000000000000000000000000000000000009D -:10B3B000000000000000000000000000000000008D -:10B3C000000000000000000000000000000000007D -:10B3D000000000000000000000000000000000006D -:10B3E000000000000000000000000000000000005D -:10B3F000000000000000000000000000000000004D -:10B40000000000000000000000000000000000003C -:10B41000000000000000000000000000000000002C -:10B42000000000000000000000000000000000001C -:10B43000000000000000000000000000000000000C -:10B4400000000000000000000000000000000000FC -:10B4500000000000000000000000000000000000EC -:10B4600000000000000000000000000000000000DC -:10B4700000000000000000000000000000000000CC -:10B4800000000000000000000000000000000000BC -:10B4900000000000000000000000000000000000AC -:10B4A000000000000000000000000000000000009C -:10B4B000000000000000000000000000000000008C -:10B4C000000000000000000000000000000000007C -:10B4D000000000000000000000000000000000006C -:10B4E000000000000000000000000000000000005C -:10B4F000000000000000000000000000000000004C -:10B50000000000000000000000000000000000003B -:10B51000000000000000000000000000000000002B -:10B52000000000000000000000000000000000001B -:10B53000000000000000000000000000000000000B -:10B5400000000000000000000000000000000000FB -:10B5500000000000000000000000000000000000EB -:10B5600000000000000000000000000000000000DB -:10B5700000000000000000000000000000000000CB -:10B5800000000000000000000000000000000000BB -:10B5900000000000000000000000000000000000AB -:10B5A000000000000000000000000000000000009B -:10B5B000000000000000000000000000000000008B -:10B5C000000000000000000000000000000000007B -:10B5D000000000000000000000000000000000006B -:10B5E000000000000000000000000000000000005B -:10B5F000000000000000000000000000000000004B -:10B60000000000000000000000000000000000003A -:10B61000000000000000000000000000000000002A -:10B62000000000000000000000000000000000001A -:10B63000000000000000000000000000000000000A -:10B6400000000000000000000000000000000000FA -:10B6500000000000000000000000000000000000EA -:10B6600000000000000000000000000000000000DA -:10B6700000000000000000000000000000000000CA -:10B6800000000000000000000000000000000000BA -:10B6900000000000000000000000000000000000AA -:10B6A000000000000000000000000000000000009A -:10B6B000000000000000000000000000000000008A -:10B6C000000000000000000000000000000000007A -:10B6D000000000000000000000000000000000006A -:10B6E000000000000000000000000000000000005A -:10B6F000000000000000000000000000000000004A -:10B700000000000000000000000000000000000039 -:10B710000000000000000000000000000000000029 -:10B720000000000000000000000000000000000019 -:10B730000000000000000000000000000000000009 -:10B7400000000000000000000000000000000000F9 -:10B7500000000000000000000000000000000000E9 -:10B7600000000000000000000000000000000000D9 -:10B7700000000000000000000000000000000000C9 -:10B7800000000000000000000000000000000000B9 -:10B7900000000000000000000000000000000000A9 -:10B7A0000000000000000000000000000000000099 -:10B7B0000000000000000000000000000000000089 -:10B7C0000000000000000000000000000000000079 -:10B7D0000000000000000000000000000000000069 -:10B7E0000000000000000000000000000000000059 -:10B7F0000000000000000000000000000000000049 -:10B800000000000000000000000000000000000038 -:10B810000000000000000000000000000000000028 -:10B820000000000000000000000000000000000018 -:10B830000000000000000000000000000000000008 -:10B8400000000000000000000000000000000000F8 -:10B8500000000000000000000000000000000000E8 -:10B8600000000000000000000000000000000000D8 -:10B8700000000000000000000000000000000000C8 -:10B8800000000000000000000000000000000000B8 -:10B8900000000000000000000000000000000000A8 -:10B8A0000000000000000000000000000000000098 -:10B8B0000000000000000000000000000000000088 -:10B8C0000000000000000000000000000000000078 -:10B8D0000000000000000000000000000000000068 -:10B8E0000000000000000000000000000000000058 -:10B8F0000000000000000000000000000000000048 -:10B900000000000000000000000000000000000037 -:10B910000000000000000000000000000000000027 -:10B920000000000000000000000000000000000017 -:10B930000000000000000000000000000000000007 -:10B9400000000000000000000000000000000000F7 -:10B9500000000000000000000000000000000000E7 -:10B9600000000000000000000000000000000000D7 -:10B9700000000000000000000000000000000000C7 -:10B9800000000000000000000000000000000000B7 -:10B9900000000000000000000000000000000000A7 -:10B9A0000000000000000000000000000000000097 -:10B9B0000000000000000000000000000000000087 -:10B9C0000000000000000000000000000000000077 -:10B9D0000000000000000000000000000000000067 -:10B9E0000000000000000000000000000000000057 -:10B9F0000000000000000000000000000000000047 -:10BA00000000000000000000000000000000000036 -:10BA10000000000000000000000000000000000026 -:10BA20000000000000000000000000000000000016 -:10BA30000000000000000000000000000000000006 -:10BA400000000000000000000000000000000000F6 -:10BA500000000000000000000000000000000000E6 -:10BA600000000000000000000000000000000000D6 -:10BA700000000000000000000000000000000000C6 -:10BA800000000000000000000000000000000000B6 -:10BA900000000000000000000000000000000000A6 -:10BAA0000000000000000000000000000000000096 -:10BAB0000000000000000000000000000000000086 -:10BAC0000000000000000000000000000000000076 -:10BAD0000000000000000000000000000000000066 -:10BAE0000000000000000000000000000000000056 -:10BAF0000000000000000000000000000000000046 -:10BB00000000000000000000000000000000000035 -:10BB10000000000000000000000000000000000025 -:10BB20000000000000000000000000000000000015 -:10BB30000000000000000000000000000000000005 -:10BB400000000000000000000000000000000000F5 -:10BB500000000000000000000000000000000000E5 -:10BB600000000000000000000000000000000000D5 -:10BB700000000000000000000000000000000000C5 -:10BB800000000000000000000000000000000000B5 -:10BB900000000000000000000000000000000000A5 -:10BBA0000000000000000000000000000000000095 -:10BBB0000000000000000000000000000000000085 -:10BBC0000000000000000000000000000000000075 -:10BBD0000000000000000000000000000000000065 -:10BBE0000000000000000000000000000000000055 -:10BBF0000000000000000000000000000000000045 -:10BC00000000000000000000000000000000000034 -:10BC10000000000000000000000000000000000024 -:10BC20000000000000000000000000000000000014 -:10BC30000000000000000000000000000000000004 -:10BC400000000000000000000000000000000000F4 -:10BC500000000000000000000000000000000000E4 -:10BC600000000000000000000000000000000000D4 -:10BC700000000000000000000000000000000000C4 -:10BC800000000000000000000000000000000000B4 -:10BC900000000000000000000000000000000000A4 -:10BCA0000000000000000000000000000000000094 -:10BCB0000000000000000000000000000000000084 -:10BCC0000000000000000000000000000000000074 -:10BCD0000000000000000000000000000000000064 -:10BCE0000000000000000000000000000000000054 -:10BCF0000000000000000000000000000000000044 -:10BD00000000000000000000000000000000000033 -:10BD10000000000000000000000000000000000023 -:10BD20000000000000000000000000000000000013 -:10BD30000000000000000000000000000000000003 -:10BD400000000000000000000000000000000000F3 -:10BD500000000000000000000000000000000000E3 -:10BD600000000000000000000000000000000000D3 -:10BD700000000000000000000000000000000000C3 -:10BD800000000000000000000000000000000000B3 -:10BD900000000000000000000000000000000000A3 -:10BDA0000000000000000000000000000000000093 -:10BDB0000000000000000000000000000000000083 -:10BDC0000000000000000000000000000000000073 -:10BDD0000000000000000000000000000000000063 -:10BDE0000000000000000000000000000000000053 -:10BDF0000000000000000000000000000000000043 -:10BE00000000000000000000000000000000000032 -:10BE10000000000000000000000000000000000022 -:10BE20000000000000000000000000000000000012 -:10BE30000000000000000000000000000000000002 -:10BE400000000000000000000000000000000000F2 -:10BE500000000000000000000000000000000000E2 -:10BE600000000000000000000000000000000000D2 -:10BE700000000000000000000000000000000000C2 -:10BE800000000000000000000000000000000000B2 -:10BE900000000000000000000000000000000000A2 -:10BEA0000000000000000000000000000000000092 -:10BEB0000000000000000000000000000000000082 -:10BEC0000000000000000000000000000000000072 -:10BED0000000000000000000000000000000000062 -:10BEE0000000000000000000000000000000000052 -:10BEF0000000000000000000000000000000000042 -:10BF00000000000000000000000000000000000031 -:10BF10000000000000000000000000000000000021 -:10BF20000000000000000000000000000000000011 -:10BF30000000000000000000000000000000000001 -:10BF400000000000000000000000000000000000F1 -:10BF500000000000000000000000000000000000E1 -:10BF600000000000000000000000000000000000D1 -:10BF700000000000000000000000000000000000C1 -:10BF800000000000000000000000000000000000B1 -:10BF900000000000000000000000000000000000A1 -:10BFA0000000000000000000000000000000000091 -:10BFB0000000000000000000000000000000000081 -:10BFC0000000000000000000000000000000000071 -:10BFD0000000000000000000000000000000000061 -:10BFE0000000000000000000000000000000000051 -:10BFF0000000000000000000000000000000000041 -:10C000000000000000000000000000000000000030 -:10C010000000000000000000000000000000000020 -:10C020000000000000000000000000000000000010 -:10C030000000000000000000000000000000000000 -:10C0400000000000000000000000000000000000F0 -:10C0500000000000000000000000000000000000E0 -:10C0600000000000000000000000000000000000D0 -:10C0700000000000000000000000000000000000C0 -:10C0800000000000000000000000000000000000B0 -:10C0900000000000000000000000000000000000A0 -:10C0A0000000000000000000000000000000000090 -:10C0B0000000000000000000000000000000000080 -:10C0C0000000000000000000000000000000000070 -:10C0D0000000000000000000000000000000000060 -:10C0E0000000000000000000000000000000000050 -:10C0F0000000000000000000000000000000000040 -:10C10000000000000000000000000000000000002F -:10C11000000000000000000000000000000000001F -:10C12000000000000000000000000000000000000F -:10C1300000000000000000000000000000000000FF -:10C1400000000000000000000000000000000000EF -:10C1500000000000000000000000000000000000DF -:10C1600000000000000000000000000000000000CF -:10C1700000000000000000000000000000000000BF -:10C1800000000000000000000000000000000000AF -:10C19000000000000000000000000000000000009F -:10C1A000000000000000000000000000000000008F -:10C1B000000000000000000000000000000000007F -:10C1C000000000000000000000000000000000006F -:10C1D000000000000000000000000000000000005F -:10C1E000000000000000000000000000000000004F -:10C1F000000000000000000000000000000000003F -:10C20000000000000000000000000000000000002E -:10C21000000000000000000000000000000000001E -:10C22000000000000000000000000000000000000E -:10C2300000000000000000000000000000000000FE -:10C2400000000000000000000000000000000000EE -:10C2500000000000000000000000000000000000DE -:10C2600000000000000000000000000000000000CE -:10C2700000000000000000000000000000000000BE -:10C2800000000000000000000000000000000000AE -:10C29000000000000000000000000000000000009E -:10C2A000000000000000000000000000000000008E -:10C2B000000000000000000000000000000000007E -:10C2C000000000000000000000000000000000006E -:10C2D000000000000000000000000000000000005E -:10C2E000000000000000000000000000000000004E -:10C2F000000000000000000000000000000000003E -:10C30000000000000000000000000000000000002D -:10C31000000000000000000000000000000000001D -:10C32000000000000000000000000000000000000D -:10C3300000000000000000000000000000000000FD -:10C3400000000000000000000000000000000000ED -:10C3500000000000000000000000000000000000DD -:10C3600000000000000000000000000000000000CD -:10C3700000000000000000000000000000000000BD -:10C3800000000000000000000000000000000000AD -:10C39000000000000000000000000000000000009D -:10C3A000000000000000000000000000000000008D -:10C3B000000000000000000000000000000000007D -:10C3C000000000000000000000000000000000006D -:10C3D000000000000000000000000000000000005D -:10C3E000000000000000000000000000000000004D -:10C3F000000000000000000000000000000000003D -:10C40000000000000000000000000000000000002C -:10C41000000000000000000000000000000000001C -:10C42000000000000000000000000000000000000C -:10C4300000000000000000000000000000000000FC -:10C4400000000000000000000000000000000000EC -:10C4500000000000000000000000000000000000DC -:10C4600000000000000000000000000000000000CC -:10C4700000000000000000000000000000000000BC -:10C4800000000000000000000000000000000000AC -:10C49000000000000000000000000000000000009C -:10C4A000000000000000000000000000000000008C -:10C4B000000000000000000000000000000000007C -:10C4C000000000000000000000000000000000006C -:10C4D000000000000000000000000000000000005C -:10C4E000000000000000000000000000000000004C -:10C4F000000000000000000000000000000000003C -:10C50000000000000000000000000000000000002B -:10C51000000000000000000000000000000000001B -:10C52000000000000000000000000000000000000B -:10C5300000000000000000000000000000000000FB -:10C5400000000000000000000000000000000000EB -:10C5500000000000000000000000000000000000DB -:10C5600000000000000000000000000000000000CB -:10C5700000000000000000000000000000000000BB -:10C5800000000000000000000000000000000000AB -:10C59000000000000000000000000000000000009B -:10C5A000000000000000000000000000000000008B -:10C5B000000000000000000000000000000000007B -:10C5C000000000000000000000000000000000006B -:10C5D000000000000000000000000000000000005B -:10C5E000000000000000000000000000000000004B -:10C5F000000000000000000000000000000000003B -:10C60000000000000000000000000000000000002A -:10C61000000000000000000000000000000000001A -:10C62000000000000000000000000000000000000A -:10C6300000000000000000000000000000000000FA -:10C6400000000000000000000000000000000000EA -:10C6500000000000000000000000000000000000DA -:10C6600000000000000000000000000000000000CA -:10C6700000000000000000000000000000000000BA -:10C6800000000000000000000000000000000000AA -:10C69000000000000000000000000000000000009A -:10C6A000000000000000000000000000000000008A -:10C6B000000000000000000000000000000000007A -:10C6C000000000000000000000000000000000006A -:10C6D000000000000000000000000000000000005A -:10C6E000000000000000000000000000000000004A -:10C6F000000000000000000000000000000000003A -:10C700000000000000000000000000000000000029 -:10C710000000000000000000000000000000000019 -:10C720000000000000000000000000000000000009 -:10C7300000000000000000000000000000000000F9 -:10C7400000000000000000000000000000000000E9 -:10C7500000000000000000000000000000000000D9 -:10C7600000000000000000000000000000000000C9 -:10C7700000000000000000000000000000000000B9 -:10C7800000000000000000000000000000000000A9 -:10C790000000000000000000000000000000000099 -:10C7A0000000000000000000000000000000000089 -:10C7B0000000000000000000000000000000000079 -:10C7C0000000000000000000000000000000000069 -:10C7D0000000000000000000000000000000000059 -:10C7E0000000000000000000000000000000000049 -:10C7F0000000000000000000000000000000000039 -:10C800000000000000000000000000000000000028 -:10C810000000000000000000000000000000000018 -:10C820000000000000000000000000000000000008 -:10C8300000000000000000000000000000000000F8 -:10C8400000000000000000000000000000000000E8 -:10C8500000000000000000000000000000000000D8 -:10C8600000000000000000000000000000000000C8 -:10C8700000000000000000000000000000000000B8 -:10C8800000000000000000000000000000000000A8 -:10C890000000000000000000000000000000000098 -:10C8A0000000000000000000000000000000000088 -:10C8B0000000000000000000000000000000000078 -:10C8C0000000000000000000000000000000000068 -:10C8D0000000000000000000000000000000000058 -:10C8E0000000000000000000000000000000000048 -:10C8F0000000000000000000000000000000000038 -:10C900000000000000000000000000000000000027 -:10C910000000000000000000000000000000000017 -:10C920000000000000000000000000000000000007 -:10C9300000000000000000000000000000000000F7 -:10C9400000000000000000000000000000000000E7 -:10C9500000000000000000000000000000000000D7 -:10C9600000000000000000000000000000000000C7 -:10C9700000000000000000000000000000000000B7 -:10C9800000000000000000000000000000000000A7 -:10C990000000000000000000000000000000000097 -:10C9A0000000000000000000000000000000000087 -:10C9B0000000000000000000000000000000000077 -:10C9C0000000000000000000000000000000000067 -:10C9D0000000000000000000000000000000000057 -:10C9E0000000000000000000000000000000000047 -:10C9F0000000000000000000000000000000000037 -:10CA00000000000000000000000000000000000026 -:10CA10000000000000000000000000000000000016 -:10CA20000000000000000000000000000000000006 -:10CA300000000000000000000000000000000000F6 -:10CA400000000000000000000000000000000000E6 -:10CA500000000000000000000000000000000000D6 -:10CA600000000000000000000000000000000000C6 -:10CA700000000000000000000000000000000000B6 -:10CA800000000000000000000000000000000000A6 -:10CA90000000000000000000000000000000000096 -:10CAA0000000000000000000000000000000000086 -:10CAB0000000000000000000000000000000000076 -:10CAC0000000000000000000000000000000000066 -:10CAD0000000000000000000000000000000000056 -:10CAE0000000000000000000000000000000000046 -:10CAF0000000000000000000000000000000000036 -:10CB00000000000000000000000000000000000025 -:10CB10000000000000000000000000000000000015 -:10CB20000000000000000000000000000000000005 -:10CB300000000000000000000000000000000000F5 -:10CB400000000000000000000000000000000000E5 -:10CB500000000000000000000000000000000000D5 -:10CB600000000000000000000000000000000000C5 -:10CB700000000000000000000000000000000000B5 -:10CB800000000000000000000000000000000000A5 -:10CB90000000000000000000000000000000000095 -:10CBA0000000000000000000000000000000000085 -:10CBB0000000000000000000000000000000000075 -:10CBC0000000000000000000000000000000000065 -:10CBD0000000000000000000000000000000000055 -:10CBE0000000000000000000000000000000000045 -:10CBF0000000000000000000000000000000000035 -:10CC00000000000000000000000000000000000024 -:10CC10000000000000000000000000000000000014 -:10CC20000000000000000000000000000000000004 -:10CC300000000000000000000000000000000000F4 -:10CC400000000000000000000000000000000000E4 -:10CC500000000000000000000000000000000000D4 -:10CC600000000000000000000000000000000000C4 -:10CC700000000000000000000000000000000000B4 -:10CC800000000000000000000000000000000000A4 -:10CC90000000000000000000000000000000000094 -:10CCA0000000000000000000000000000000000084 -:10CCB0000000000000000000000000000000000074 -:10CCC0000000000000000000000000000000000064 -:10CCD0000000000000000000000000000000000054 -:10CCE0000000000000000000000000000000000044 -:10CCF0000000000000000000000000000000000034 -:10CD00000000000000000000000000000000000023 -:10CD10000000000000000000000000000000000013 -:10CD20000000000000000000000000000000000003 -:10CD300000000000000000000000000000000000F3 -:10CD400000000000000000000000000000000000E3 -:10CD500000000000000000000000000000000000D3 -:10CD600000000000000000000000000000000000C3 -:10CD700000000000000000000000000000000000B3 -:10CD800000000000000000000000000000000000A3 -:10CD90000000000000000000000000000000000093 -:10CDA0000000000000000000000000000000000083 -:10CDB0000000000000000000000000000000000073 -:10CDC0000000000000000000000000000000000063 -:10CDD0000000000000000000000000000000000053 -:10CDE0000000000000000000000000000000000043 -:10CDF0000000000000000000000000000000000033 -:10CE00000000000000000000000000000000000022 -:10CE10000000000000000000000000000000000012 -:10CE20000000000000000000000000000000000002 -:10CE300000000000000000000000000000000000F2 -:10CE400000000000000000000000000000000000E2 -:10CE500000000000000000000000000000000000D2 -:10CE600000000000000000000000000000000000C2 -:10CE700000000000000000000000000000000000B2 -:10CE800000000000000000000000000000000000A2 -:10CE90000000000000000000000000000000000092 -:10CEA0000000000000000000000000000000000082 -:10CEB0000000000000000000000000000000000072 -:10CEC0000000000000000000000000000000000062 -:10CED0000000000000000000000000000000000052 -:10CEE0000000000000000000000000000000000042 -:10CEF0000000000000000000000000000000000032 -:10CF00000000000000000000000000000000000021 -:10CF10000000000000000000000000000000000011 -:10CF20000000000000000000000000000000000001 -:10CF300000000000000000000000000000000000F1 -:10CF400000000000000000000000000000000000E1 -:10CF500000000000000000000000000000000000D1 -:10CF600000000000000000000000000000000000C1 -:10CF700000000000000000000000000000000000B1 -:10CF800000000000000000000000000000000000A1 -:10CF90000000000000000000000000000000000091 -:10CFA0000000000000000000000000000000000081 -:10CFB0000000000000000000000000000000000071 -:10CFC0000000000000000000000000000000000061 -:10CFD0000000000000000000000000000000000051 -:10CFE0000000000000000000000000000000000041 -:10CFF0000000000000000000000000000000000031 -:10D000000000000000000000000000000000000020 -:10D010000000000000000000000000000000000010 -:10D020000000000000000000000000000000000000 -:10D0300000000000000000000000000000000000F0 -:10D0400000000000000000000000000000000000E0 -:10D0500000000000000000000000000000000000D0 -:10D0600000000000000000000000000000000000C0 -:10D0700000000000000000000000000000000000B0 -:10D0800000000000000000000000000000000000A0 -:10D090000000000000000000000000000000000090 -:10D0A0000000000000000000000000000000000080 -:10D0B0000000000000000000000000000000000070 -:10D0C0000000000000000000000000000000000060 -:10D0D0000000000000000000000000000000000050 -:10D0E0000000000000000000000000000000000040 -:10D0F0000000000000000000000000000000000030 -:10D10000000000000000000000000000000000001F -:10D11000000000000000000000000000000000000F -:10D1200000000000000000000000000000000000FF -:10D1300000000000000000000000000000000000EF -:10D1400000000000000000000000000000000000DF -:10D1500000000000000000000000000000000000CF -:10D1600000000000000000000000000000000000BF -:10D1700000000000000000000000000000000000AF -:10D18000000000000000000000000000000000009F -:10D19000000000000000000000000000000000008F -:10D1A000000000000000000000000000000000007F -:10D1B000000000000000000000000000000000006F -:10D1C000000000000000000000000000000000005F -:10D1D000000000000000000000000000000000004F -:10D1E000000000000000000000000000000000003F -:10D1F000000000000000000000000000000000002F -:10D20000000000000000000000000000000000001E -:10D21000000000000000000000000000000000000E -:10D2200000000000000000000000000000000000FE -:10D2300000000000000000000000000000000000EE -:10D2400000000000000000000000000000000000DE -:10D2500000000000000000000000000000000000CE -:10D2600000000000000000000000000000000000BE -:10D2700000000000000000000000000000000000AE -:10D28000000000000000000000000000000000009E -:10D29000000000000000000000000000000000008E -:10D2A000000000000000000000000000000000007E -:10D2B000000000000000000000000000000000006E -:10D2C000000000000000000000000000000000005E -:10D2D000000000000000000000000000000000004E -:10D2E000000000000000000000000000000000003E -:10D2F000000000000000000000000000000000002E -:10D30000000000000000000000000000000000001D -:10D31000000000000000000000000000000000000D -:10D3200000000000000000000000000000000000FD -:10D330000000000010000003000000000000000DCD -:10D340000000000D3C02080024427A603C03080003 -:10D3500024637AD8AC4000000043202B1480FFFDEA -:10D36000244200043C1D080037BD9FFC03A0F021AF -:10D370003C100800261031D83C1C0800279C7A601D -:10D380000E001253000000000000000D3C0280005F -:10D3900030A5FFFF30C600FF344301803C08800009 -:10D3A0008D0901B80520FFFE00000000AC640000FC -:10D3B00024040002A4650008A066000AA064000B13 -:10D3C000AC6700183C03100003E00008AD0301B88F -:10D3D0003C0560008CA24FF80440FFFE00000000F6 -:10D3E000ACA44FC03C0310003C040200ACA44FC4EA -:10D3F00003E00008ACA34FF827BDFFE8AFBF00145F -:10D40000AFB000100E0012A5008080213C048008FF -:10D410003485008090A600052403FFFE0200202131 -:10D4200000C310248FBF00148FB00010A0A200050D -:10D430000A0012AF27BD001827BDFFE8AFB00010EB -:10D44000AFBF00140E000ED6008080213C0680087D -:10D4500034C5008090A4000024020050308300FFF7 -:10D46000106200073C098000020020218FBF0014D9 -:10D470008FB00010AD2001800A000FC527BD001835 -:10D48000240801003C078000020020218FBF001407 -:10D490008FB00010ACE801800A000FC527BD00184E -:10D4A00027BDFF883C088008AFBE0070AFB600689B -:10D4B000AFB40060AFB00050AFBF0074AFB7006C46 -:10D4C000AFB50064AFB3005CAFB20058AFB1005469 -:10D4D000350500803C0780008CF1012890A40009EC -:10D4E000ACE0008490A60005309000FF0000A02171 -:10D4F00000061827306200010000B02114400067C8 -:10D500000000F02190A9000024050020312400FF34 -:10D5100010850016240A0050108A008D00000000BB -:10D520003C0C08008D8C00DC258B00013C010800C0 -:10D53000AC2B00DC0E00139B000000008FBF0074BA -:10D540008FBE00708FB7006C8FB600688FB5006417 -:10D550008FB400608FB3005C8FB200588FB100545D -:10D560008FB0005003E0000827BD00780000000DD8 -:10D570003C158000AFA0003096A201168EB90104C0 -:10D580003C1F002036B20C00033FC0240018B82B0B -:10D5900000173140AFA600308EAE01043053FFFFBC -:10D5A0003C0F00400272382101CF682490F2000D38 -:10D5B00011A0004834C4004032430020146000022F -:10D5C000348600800080302114C00094AFA6003063 -:10D5D0003C0980083525008090A8000831060040ED -:10D5E00050C000063C088008240A0004120A00A368 -:10D5F000240B0012120B00293C088008351501008D -:10D600003C17800096F3011A94EE000E92AF0008CA -:10D61000324C00043275FFFF01EE6804AFAD003CF0 -:10D620008CF30004118000318CF700083503008072 -:10D63000907800083307004014E000280000000044 -:10D640008C72005002728823062000063C0680007F -:10D650008C7F0034027FC823072200848E8200085A -:10D660003C068000ACC00044240200018FBF00745F -:10D670008FBE00708FB7006C8FB600688FB50064E6 -:10D680008FB400608FB3005C8FB200588FB100542C -:10D690008FB0005003E0000827BD00780E000CB8E2 -:10D6A000000020218FBF00748FBE00708FB7006C08 -:10D6B0008FB600688FB500648FB400608FB3005CD4 -:10D6C0008FB200588FB100548FB0005003E00008B3 -:10D6D00027BD00780A000D1800C020210E00146C30 -:10D6E000026020211440FFDF3C0680003C038008DC -:10D6F000346300808C6400340264102304400018FA -:10D70000000000003C1408008E94310026900001B7 -:10D710003C010800AC3031000E0012A5022020218F -:10D720003C048008349F008093FE002502202021C5 -:10D7300037C90004A3E900250E0012AF0000000065 -:10D740000E000C9E022020210A000D45240200013B -:10D750003C14080026947AC80A000D073C15800086 -:10D760008C6800300268302318C00008240B000CBD -:10D770003C0908008D293100325200FC0000A8212C -:10D78000252500013C010800AC253100AFAB00307D -:10D790008C6A003001534023190000E002A8602A7F -:10D7A0001580FFDD0000000012A8002A02A87823DF -:10D7B0000268982131F5FFFF3247000210E0003483 -:10D7C000325900103C13800836700080921E000809 -:10D7D00033D6004052C000D38E82000802202021A0 -:10D7E0000E0012A524120018A212000992170005BB -:10D7F0002418FFFE0220202102F8A8240E0012AFF8 -:10D80000A215000524040039000028210E00144749 -:10D81000240600180A000D45240200019296000C0F -:10D820003C048008349E00808FC700380016A30097 -:10D830003690008130C600FF022020210E000C8DA2 -:10D840003205F0813C068000ACC000440A000D4562 -:10D85000240200013A4E000131CD000115A0FFAEB7 -:10D86000026898210A000D97000000000040F809A6 -:10D87000240400160A000D45240200010220202184 -:10D880000E00152900E028210A000CFA8FBF007451 -:10D890001320FF733C048008348900808D230038F6 -:10D8A0008C82000402E2F8231FE0FF6E3C06800039 -:10D8B00002E3302304C200010060B821AFA80018C1 -:10D8C0003C198000AFB30010AFB5001497260120BB -:10D8D0008D2A00309524005C8FB8003C8FAD00305D -:10D8E0003087FFFF30DFFFFF03E87021372F400054 -:10D8F0000307282B8E82000401CF602101A5582543 -:10D90000AFA90048AFAC0020AFAA0028AFAB0030F1 -:10D91000AFAA0024AFA0002CAFB700340040F80934 -:10D9200027A400108FA8003031030002106000020D -:10D930008FA90048325200FE912300083069004050 -:10D94000512000138FA400243C0280088C4800045E -:10D95000111700A4240A0014325800015300000CCF -:10D960008FA400242419000C121900C02A1F000DD6 -:10D9700013E000BA2406000E2404000A5204000139 -:10D98000241600088FA9002425240001AFA4002438 -:10D990003C188008370500808FA700148CAF00303A -:10D9A000340CFFFF00877021ACAE0030AFAF003801 -:10D9B00090AD004E8CAB00308FA8003C01AC100441 -:10D9C00001625021ACAA00348FA6003002E8202169 -:10D9D00030C300081060000BAFA400408CB90020D9 -:10D9E0001324008F30C600FF9289000C8FA70034EB -:10D9F00000098300360400803085F0800E000C8D15 -:10DA0000022020213C0A8008355000808E0300301F -:10DA10008FA800380068302318C00065262F0080CA -:10DA20003C0E08008DCE31982407FF8001E7682462 -:10DA300031EC007F3C0680003C02800431CB0010BA -:10DA4000ACCD00901160003B0182282190B8006BA2 -:10DA5000570000393C048008241F0001A0BF006B60 -:10DA600094C5007A24B9000AA61900123C0A80085D -:10DA70003545008090A800083110004016000004D1 -:10DA80003C038008324B00011560006B0000000071 -:10DA9000346400808C8C00208FB200401192000909 -:10DAA000346301008C6D0000026D102318400012D9 -:10DAB0008FB80040241E0001AC980020AC73000019 -:10DAC000AC77000416C0002D0000000017C000272E -:10DAD0000000000012A00005000018218FA50030F2 -:10DAE00030B5000452A0FE9500601021240300010F -:10DAF0000A000CF9006010218C6E000015D3FFF1B4 -:10DB0000000000008C67000402E7782305E1FFE9CC -:10DB10008FB800400A000E5B000000000A000D985C -:10DB2000000040210040F809240400170A000D45B8 -:10DB3000240200013C04800834900080241E00016F -:10DB4000022020210E0012A5A61E00129209002517 -:10DB500002202021241E0001352200010E0012AFF8 -:10DB6000A20200250A000E463C0A80080E000C9E08 -:10DB7000022020210A000E5F000000000E0012A506 -:10DB8000022020213C198008373700800220202104 -:10DB90000E0012AFA2F6000902C0302124040037A3 -:10DBA0000E001447000028210A000E5D000000004E -:10DBB0008FA6001858C0FFAE3C0A80080E0012A5C0 -:10DBC000022020219203002502202021241E000192 -:10DBD000346200040E0012AFA20200250A000E46B5 -:10DBE0003C0A8008120A00302A0B0015116000243C -:10DBF000240D0016240C000C560CFF58325800015E -:10DC00003C05800890AF001B2407FFBD2416000EC2 -:10DC100001E77024A0AE001B0A000E01325800017B -:10DC20003C1F800097E5011A50A0FF6F34C600101A -:10DC30000A000E259289000C8CB300308E960008E5 -:10DC4000240400182674000102C0F809ACB40030A6 -:10DC50008FB100300A000CF9322200041606FF4A88 -:10DC60008FA900240A000E0C241600102410000EA8 -:10DC700052D0FF44241600100A000E0B2416001682 -:10DC8000560DFF36325800013C05800890AF001B4E -:10DC90002407FFBD2416001001E77024A0AE001B6E -:10DCA0000A000E01325800010A000E00241600126C -:10DCB0003C0380008C6201B80440FFFE240408008D -:10DCC000AC6401B803E00008000000003C058008D7 -:10DCD00094A200483084FFFF1040001924840012F1 -:10DCE00094A900483C0380003128FFFF0104382A32 -:10DCF00010E0001334660180946D01208F8C0004C5 -:10DD0000240B001A31AAFFFF31834000A0CB000B87 -:10DD1000106000102544FFFE94AF004831EEFFFF75 -:10DD200001C4282B14A0000C8F98000CA4C400146C -:10DD30008F86000C34C2000103E00008AF82000CA3 -:10DD40003C0780002404000334E2018003E0000863 -:10DD5000A044000B8F98000C2419FFFE0319102417 -:10DD600003E00008AF82000C27BDFFD8AFB400204D -:10DD7000AFB3001CAFB20018AFB10014AFBF0024A6 -:10DD8000AFB000100080182130B3FFFF30D2FFFF8A -:10DD900030F4FFFF3C1180008E2201B80440FFFEEA -:10DDA00036300180AE030000024020210E000EDD5F -:10DDB000AE2300208F86000C8F8500048F83000027 -:10DDC00030C48000A613000CA612000EA605001099 -:10DDD000AE030028A61400081080000E3C0F80003F -:10DDE000962C0116318BFFFC256A00040151482155 -:10DDF0008D2840003107FFFF14E000072414BFFF07 -:10DE00003C0EFFFF35CD7FFF00CD3024AF86000CE8 -:10DE10003C0F80002414BFFF35F1018000D498240A -:10DE2000A63300268DF20104AE32002C3C06100011 -:10DE3000ADE601B88FBF00248FB400208FB3001C63 -:10DE40008FB200188FB100148FB0001003E00008EB -:10DE500027BD002827BDFFD8AFB100143C118000BA -:10DE600000804021AFB40020AFB0001030D4FFFFDD -:10DE70003630018002802021AE080000AE2800204C -:10DE8000AFB3001CAFB2001830F3FFFFAFBF0024E8 -:10DE90000E000EDD30B2FFFF8F85000C8F83000473 -:10DEA0002406BFFF00A62024A612000CA614000E14 -:10DEB000A6130008A6040026A60300103C021000CA -:10DEC000AE2201B88FBF00248FB400208FB3001C96 -:10DED0008FB200188FB100148FB0001003E000085B -:10DEE00027BD00283C028000344501803C048000AE -:10DEF0008C8301B80460FFFE240720002406000282 -:10DF0000A4A70008A0A6000BA4A000103C051000C8 -:10DF1000AC8501B803E00008000000003C0580006B -:10DF200034A400708C8A000090A601128F84000433 -:10DF300027BDFFF030C300FF0003188230820100CC -:10DF4000000038211040003924660003308740006B -:10DF500050E0003930882000000610800045C821BC -:10DF60008F2F40002478000400187080AFAF0000AD -:10DF700001C568218DAC4000AFAC000494AB011624 -:10DF80003169FFFC012540218D054000AFA5000847 -:10DF90008FA9000800003021000028213C0708005C -:10DFA00024E701000A000F9E2408000890420000A8 -:10DFB00024A500012CAD000C0062C8210019C0800E -:10DFC000030778218DEE000011A0000600CE302658 -:10DFD00003A5102114A8FFF500051A005520FFF431 -:10DFE000904200003C048000348700703C0508002B -:10DFF0008CA531048CE300002CA80020110000093E -:10E00000006A3823000558803C0C0800258C310834 -:10E01000016C482124AA0001AD2700003C01080042 -:10E02000AC2A3104AF8600002407000100E0102173 -:10E0300003E0000827BD00101100FFFC000038219C -:10E0400000066080018558218D6440002469000429 -:10E0500000093880AFA4000000E518218C6640005C -:10E06000AFA000080A000F8EAFA600043C02080013 -:10E070008C42003827BDFFD8AFB40020AFB20018E3 -:10E08000AFBF0024AFB3001CAFB10014AFB000109D -:10E090003C14080026940038144000022452FFFF6C -:10E0A000000090218F85000430A340001060000F15 -:10E0B00030A980003C06002000A620241080000B20 -:10E0C0008F87000C2408BFFF00A8282434E3100029 -:10E0D000AF85000430AF200015E0000A3C110004B9 -:10E0E0002413FFBF0A000FEF0073102415200062F5 -:10E0F0003C0B002030AF200011E0FFF98F83000CB3 -:10E100003C11000400B180241200FFF62413FFBF6D -:10E110003462004030B801001300000FAF82000CE1 -:10E120003C1F002000BFC824132000053C0A8000CB -:10E130003C03000400A31024104000C800000000AD -:10E140009549011E9548011C3126FFFF00083C003F -:10E1500000C72025AF8400003C0D800095AC010C69 -:10E1600030AB1000116000083186FFFF30AE002098 -:10E1700015C00006241100053C10100000B07824E2 -:10E1800015E000733C1F0C002411000130A20100B7 -:10E19000544000093C0C00018F83001454600006B9 -:10E1A0003C0C00018F87000C30E440001080009A86 -:10E1B0003C0A1F013C0C000100AC302414C0006C70 -:10E1C0003C1080008F84000C3093400012600006E9 -:10E1D0003C0310003C190F0000B9C0241300008B51 -:10E1E0003C1F80003C03100000A310241040002CB2 -:10E1F0003C0680003C0708008CE7003014E0007308 -:10E200003088400030A6010010C000983C0E0F007E -:10E2100000AE68243C0C020011AC00948F93000007 -:10E22000027280240214782191F4000426920004E2 -:10E23000001221C03C0E800095C6010E3627000258 -:10E2400024D400043286FFFF240500020E000F04D0 -:10E25000000000008FBF00248FB400208FB3001C8B -:10E260008FB200188FB100148FB000100000102181 -:10E2700003E0000827BD002800AB50241140FF9E9A -:10E2800030AF20008F8C000C3C0EFFFF35CD7FFFA0 -:10E2900000AD2824358380000A000FDFAF8500041D -:10E2A0008CD04000320F010011E0003C30B801007A -:10E2B0003C1008008E1000241300001432330004B8 -:10E2C0003C020F0000A2F8243C19020013F9000FD1 -:10E2D0008F83000094C9010E022038210072582457 -:10E2E0000174502191480004252400043086FFFF6A -:10E2F00025140004001421C0240500020E000F04A0 -:10E300002412FFFE021280243231FFFB2407000199 -:10E310001207006F3206000114C000903C0E80000E -:10E32000320F000411E000048F980004331008003D -:10E33000160000783C1F80005660FFC78FBF002486 -:10E340000E000F63000000000A0010408FBF002481 -:10E350003C190BFF00BFC0243733FFFF0278882B26 -:10E360005220FF8A241100010A00100D241100051B -:10E370003C0E08008DCE00D8960F010E24040080BC -:10E3800025CD000131E6FFFF240500023C01080015 -:10E39000AC2D00D80A00103D240700033C120800F1 -:10E3A0008E520024324200011040FFAB8FBF002488 -:10E3B00094C6010E362700020000202124D4000458 -:10E3C0003286FFFF0A00103D240500021100FF8E77 -:10E3D00030A601003C0B0F0000AB50243C090100AB -:10E3E000012A202B1480FF88000000003C058000DB -:10E3F00094A6010E362700022404008024D40004D1 -:10E400003286FFFF0A00103D2405000297E3011643 -:10E410000A0010243C03100000AA48243C08100005 -:10E420001528FF653C0C000130CB02001560FF632E -:10E4300000AC30243C1480009692010E3627000276 -:10E44000000020212645000430A6FFFF0E000F3FEC -:10E45000240500020A0010408FBF00240E000F7137 -:10E46000000000000A0010008F850004000000007A -:10E470003C0608008CC600D0000516023050000F84 -:10E4800038DF00012FF900012E03000C0323C02404 -:10E490001700FF68001021C02608FFFC2D070004AC -:10E4A00014E000073C0E800038CA00022D4900012C -:10E4B000012320245080000E000532423C0E8000D3 -:10E4C00095C6010E000020210A00103A36270002EE -:10E4D0003233000452600001363100023C0C8000EF -:10E4E0009586010E022038210A0010990000202193 -:10E4F0000010182B00C358241560000F3C05800045 -:10E50000001021C03C0E800095C6010E0A00103A92 -:10E510003627000297F9010E022038212404010059 -:10E52000273100043226FFFF0E000F0424050002ED -:10E530000A0010780000000094AD010E00002021B8 -:10E540002405000225AC00043186FFFF0E000F04F5 -:10E550003227FFFB0A0010EB001021C095C5010E09 -:10E56000022038210000202124AD000431A6FFFF45 -:10E570000E000F04240500020A0010723231FFFB66 -:10E580003C0580008CA701482403000434A60180C8 -:10E5900000072402308200FF104300103C0480007A -:10E5A0008C8901B80520FFFE000000008C8F014817 -:10E5B000240D00023C0A1000000F7402A4CE0008D3 -:10E5C000A0CD000B8C8C0148A4CC00108C8B014496 -:10E5D000ACCB002403E00008AC8A01B88CA4014055 -:10E5E0003C03800000C028218C6601B804C0FFFEF7 -:10E5F0002408001CACA40000A0A8000B3C051000DF -:10E60000AC6501B803E000080000000027BDFFE88A -:10E61000AFB00010AFBF00143C10600C8E0D500066 -:10E62000240EFF7F2406000301AE60243588380CD9 -:10E630003C058000AE085000ACA600083C01080074 -:10E64000AC2000200E001555000000003C086016AC -:10E650008D0A00003C0BFFFF3C0900103523805160 -:10E660003C046000014B38243C025353AE03537CFE -:10E67000348420203C05080024A579082406000ADB -:10E6800010E2000935037C008C7F007C8C790078D7 -:10E690008FB00010AF9F00108FBF001427BD00186F -:10E6A0000A0013B1AF9900088D0F00043C186000F8 -:10E6B0008FB0001001F818218C7F007C8C790078D5 -:10E6C000AF9F00108FBF001427BD00180A0013B1C0 -:10E6D000AF9900083C0480008C8340003402FFFFA7 -:10E6E0001062003A000000008C87400030E5010015 -:10E6F00010A00021000000009487010E3C020800D9 -:10E700008C4200EC9485010E3C0D08008DAD31CC9F -:10E7100030E3FFFF3C1808008F1800E83C090800B0 -:10E720008D2931C80043602130ABFFFF0183782B76 -:10E730000000C82101AB18210000502103197021ED -:10E74000006B302B012A402101CF2021010610212E -:10E750003C010800AC2C00EC3C010800AC2400E8B3 -:10E760003C010800AC2331CC3C010800AC2231C88C -:10E7700003E00008000000008C8840008F8C000837 -:10E78000110C00323C0D800095AB010E3C0A0800D4 -:10E790008D4A00E43C0808008D0800E03169FFFF65 -:10E7A000014928210000302100A9602B01063821F1 -:10E7B00000EC10213C010800AC2500E43C010800FD -:10E7C000AC2200E003E00008000000009483010E8A -:10E7D0009482010E3C1908008F3900F43C090800AE -:10E7E0008D2931CC3C0E08008DCE00F03C0808008D -:10E7F0008D0831C83078FFFF304BFFFF03382821E8 -:10E80000012B1821000078210000502100B8682B4E -:10E8100001CF6021006B302B010A3821018D2021AE -:10E8200000E610213C010800AC2500F43C01080082 -:10E83000AC2400F03C010800AC2331CC3C010800C2 -:10E84000AC2231C803E00008000000008C894004BD -:10E850008F8600101526FFCC3C0D80009483010E9E -:10E860003C1908008F3931BC3C0E08008DCE31B800 -:10E870003078FFFF03385821000078210178202BE1 -:10E8800001CF682101A450213C010800AC2B31BC10 -:10E890003C010800AC2A31B803E000080000000089 -:10E8A00027BDFFE83C058000AFBF0014AFB00010EB -:10E8B0008CB00128ACB000208CA301048CA4010012 -:10E8C000AF8300040E000ED6AF84000C0E00115F63 -:10E8D000000000003C0208008C4200C010400026EE -:10E8E0008F8400043C0708008CE700C424E6000184 -:10E8F0003C010800AC2600C43C0280008C4401248A -:10E900003C1F6020AFE40014000000003C068000C3 -:10E910003C034000ACC301380000000012000013AB -:10E920008FBF0014260F0140261900802404FF80A9 -:10E9300001E4C0240324F824001F6940332E007F23 -:10E940000018594031EC007F3C0A20003548000295 -:10E9500001AE3825016C48250128802500E82825CE -:10E96000ACC50830ACD008308FBF00148FB0001099 -:10E9700003E0000827BD00183C090010008940246E -:10E980001100000F8F83000C240DBFFF006D602469 -:10E9900011800007240F87FF006F702415C000133B -:10E9A0003C1900600099C024130000100000000012 -:10E9B0000E000CD2000000000A001221000000002E -:10E9C0003C0B08008D6B0020256A00013C0108000B -:10E9D000AC2A00200E000FC5000020211040FFCC03 -:10E9E0003C0680000A0011E93C0280000E00128EF5 -:10E9F000000000000A0012210000000027BDFFE80F -:10EA00003C028000AFBF00108C4601403C03700008 -:10EA10003C054000AC4600208C4401480083202483 -:10EA20001085001300A4102B1040000B3C072000A1 -:10EA30003C08600010880017000000003C0A4000FD -:10EA40003C098000AD2A0178000000008FBF001053 -:10EA500003E0000827BD00185487FFF93C0A400076 -:10EA60000E00110A000000000A00123A3C0A4000A1 -:10EA70000E0012B4000000003C0A40003C09800077 -:10EA8000AD2A0178000000008FBF001003E00008ED -:10EA900027BD00180E001D6F000000000A00123A8A -:10EAA0003C0A400027BDFFE0AFB200183C128000D6 -:10EAB000AFB10014AFBF001CAFB000100E00112D9D -:10EAC000365100708E260000AF8600188E28000098 -:10EAD0003C0B08008D6B00FC3C0708008CE700F83D -:10EAE00001066023016C28210000482100AC302B76 -:10EAF00000E91821006620213C010800AC2500FC3B -:10EB00003C010800AC2400F88E50000032020003E3 -:10EB10001040FFEE010030218E2600003C05080069 -:10EB20008CA500FC3C1F08008FFF00F800C81823CC -:10EB300000A378210000102101E3C82B03E2C021CB -:10EB400003197021320D00013C010800AC2F00FCBC -:10EB5000AF8800183C010800AC2E00F815A0000892 -:10EB600000000000320800021100FFD60000000083 -:10EB70000E001229000000000A00125B00000000D5 -:10EB80000E0011D2000000000A00128432080002B8 -:10EB90003C0380008C6401003082003E1440000879 -:10EBA00000000000AC6000488C66010030C507C062 -:10EBB00010A0000500000000AC60004CAC600050EC -:10EBC00003E0000824020001AC600054AC60004087 -:10EBD0008C6801003107380010E0FFF900000000E8 -:10EBE0002402000103E00008AC6000443C039000F4 -:10EBF00034620001008220253C038000AC640020C8 -:10EC00008C65002004A0FFFE0000000003E0000867 -:10EC1000000000003C0280003443000100832025F6 -:10EC200003E00008AC44002027BDFFD8AFB10014BA -:10EC30003C048000AFBF0020AFB3001CAFB200188F -:10EC4000AFB000108C9201408C9001482402000E5D -:10EC500000108C02322300FF1062005902042824A5 -:10EC60002866000F10C00013286A0037240700062A -:10EC70001067008E286800075100002D2404000949 -:10EC8000106000783C06800024090001106900B083 -:10EC9000000000000000000D8FBF00208FB3001C9B -:10ECA0008FB200188FB100148FB0001003E000087D -:10ECB00027BD002811400059240D0038286B00356D -:10ECC000116000053C058000240C001F146CFFF14E -:10ECD000000000003C0580008CB801B80700FFFE72 -:10ECE00034B90180AF320000241F00012412000259 -:10ECF0003C021000AF200004A7310008A33F000A27 -:10ED0000A332000BA7300010AF200024AF20002852 -:10ED1000ACA201B88FBF00208FB3001C8FB20018C7 -:10ED20008FB100148FB0001003E0000827BD002849 -:10ED3000106400232405000B1465FFD63218FFFF72 -:10ED4000170000203C0580008F93FED4927F0005C1 -:10ED500033F900041720FFCF000000000E0012A5B9 -:10ED6000024020219269000502402021352800043C -:10ED70000E0012AFA26800059267000530E20004A1 -:10ED800014400002000000000000000D926B000023 -:10ED900024060020316A00FF1546000A3C05800069 -:10EDA0008CA401B80480FFFE34AD0180240E000560 -:10EDB0003C0C1000ADB20000A1AE000BACAC01B831 -:10EDC0003C0580008CA301B80460FFFE34AF0180D5 -:10EDD00024130002ADE00000ADF20004A5F100082C -:10EDE000A1F3000AA1F3000BA5F00010ADE0002490 -:10EDF0008CB101443C101000ADF10028ACB001B85A -:10EE00008FBF00208FB3001C8FB200188FB1001489 -:10EE10008FB0001003E0000827BD0028106DFFAD83 -:10EE2000240E0080146EFF9B000000003C05800053 -:10EE30008CA301B80460FFFE34AF018024120002ED -:10EE4000A1F2000BA5F10008A5F000108CB301445D -:10EE50003C021000A5F30012ACA201B80A0012F0A7 -:10EE60008FBF00208CC301B80460FFFE34D3018043 -:10EE7000AE720000AE60000424120001A67100080A -:10EE800024110002A272000AA271000BA6700010E9 -:10EE90008CD001443C0F1000AE700024AE600028FE -:10EEA000ACCF01B80A00132B8FBF00203C038000B9 -:10EEB0008C6601B804C0FFFE346201803C06080085 -:10EEC00090C67AB8AC52000010C000030000382190 -:10EED0003C0708008CE77AC03C05800034AA01801A -:10EEE0002404000234CC0001AC470004A551000802 -:10EEF000A14C000AA144000BA55000108CAB0144AA -:10EF00000000202101402821AD4B002410C0000347 -:10EF10008FBF00203C0408008C847ABC8FB3001C97 -:10EF20008FB200188FB100148FB000103C0E10008B -:10EF30003C0D800027BD0028ACA40028ADAE01B870 -:10EF40003C010800A0207AB803E00008000000009F -:10EF500010A0000B3C0680008C980144241900028C -:10EF60003C010800A0397AB83C010800AC327AC0F4 -:10EF70003C010800AC387ABC0A00132B8FBF00207C -:10EF80008CDF01B807E0FFFE34C7018024090002CE -:10EF9000ACE00000ACF20004A4F10008A0E9000A13 -:10EFA000A0E9000BA4F00010ACE000248CC80144E0 -:10EFB0003C021000ACE80028ACC201B80A00132BD8 -:10EFC0008FBF002027BDFFE8AFBF00100E000ED698 -:10EFD000000000003C0280008FBF001000002021D4 -:10EFE000AC4001800A000FC527BD00183084FFFF28 -:10EFF00030A5FFFF108000070000182130820001BB -:10F000001040000200042042006518211480FFFB1C -:10F010000005284003E000080060102110C0000730 -:10F02000000000008CA2000024C6FFFF24A50004FD -:10F03000AC82000014C0FFFB2484000403E000083D -:10F040000000000010A0000824A3FFFFAC86000011 -:10F0500000000000000000002402FFFF2463FFFF07 -:10F060001462FFFA2484000403E00008000000009A -:10F0700027BDFFE0AFB20018AFB10014AFB0001071 -:10F08000AFBF001C9486000C00A0902124900014B7 -:10F0900000061B020003108000448821000030217C -:10F0A00000A020210E0013BB240500050211202B17 -:10F0B0001080001200001021920300002C6500094E -:10F0C00050A0000992020001000348803C0A080099 -:10F0D000254A793C012A40218D07000000E0000804 -:10F0E0000000000092020001020280210211202B88 -:10F0F0005480FFF292030000000010218FBF001C1B -:10F100008FB200188FB100148FB0001003E0000818 -:10F1100027BD00200A0013D526100001920C000123 -:10F12000240B000C158B0040023070232DCD000AFB -:10F1300015A0003D260800068E43000026020002AE -:10F1400034640100AE440000921F00029059000197 -:10F15000904E0002904B0003001F7E000019C40077 -:10F1600001F86025000E6A00018D5025014B4825ED -:10F17000AE490004920700069105000191040002C7 -:10F180009119000300071E00000534000066F825F1 -:10F190000004120003E2C025031978252610000A96 -:10F1A0000A0013D5AE4F0008921F0001260400028A -:10F1B0002410000257F00001022020210A0013D57C -:10F1C00000808021920E0001240D000315CDFFCB9D -:10F1D000240200018E59000092180002261000033C -:10F1E000372F0008A25800100A0013D5AE4F0000B8 -:10F1F000920500012406000414A6FFC024020001A9 -:10F20000920C0002920B00038E490000000C520089 -:10F21000014B40253527000426100004AE48000CA1 -:10F220000A0013D5AE4700000A0013E924020001CA -:10F2300027BDFFE8AFBF0014AFB000100E0012A54D -:10F24000008080213C048008348300809065002584 -:10F250000200202134A200200E0012AFA06200257F -:10F26000020020218FBF00148FB000100A000C9EF6 -:10F2700027BD00183C03800027BDFFF834620180E1 -:10F28000AFA20000308C00FF30AD00FF30CE00FF99 -:10F290003C0B80008D6401B80480FFFE000000007C -:10F2A0008FA900008D6801288FAA00008FA7000099 -:10F2B0008FA400002405000124020002A085000A9A -:10F2C0008FA30000359940003C051000A062000BA0 -:10F2D0008FB800008FAC00008FA600008FAF000039 -:10F2E00027BD0008AD280000AD400004AD8000241B -:10F2F000ACC00028A4F90008A70D0010A5EE00126C -:10F3000003E00008AD6501B83C06800827BDFFE8B2 -:10F3100034C50080AFBF001090A70009240200127E -:10F3200030E300FF1062000B008030218CA80050F9 -:10F3300000882023048000088FBF00108CAA0034AE -:10F34000240400390000282100CA482305200005B4 -:10F35000240600128FBF00102402000103E0000801 -:10F3600027BD00180E001447000000008FBF0010DA -:10F370002402000103E0000827BD001827BDFFC8D4 -:10F38000AFB1002C00A08821AFB2003027A500103B -:10F390000080902102202021AFBF00340E0013C650 -:10F3A000AFB00028144000813C0C8008918B001104 -:10F3B000918A0012358600808CC80054316500FFA8 -:10F3C000314900FF00A9282100A8382B14E0004F84 -:10F3D0008FA3001094DF005C3066000410C000565C -:10F3E00033E4FFFF8FA2001C0082102B5440000565 -:10F3F0002C8300803067000414E0007E240402188F -:10F400002C83008010600002008080212410008086 -:10F410000E0012A5024020213C03800834660080C3 -:10F4200024070001ACC7000C90C200080010604027 -:10F4300034670100305F007FA0DF00088E390004D0 -:10F4400027380001ACD80030A4D0005C8CCE003C42 -:10F45000962F000E01CF6821ACCD00208CCB003C54 -:10F46000016C5021ACCA001C8E290004ACE90000DC -:10F470008E250008ACE500048FA8001031040008B8 -:10F480005480002F93A60020A0C0004E90C5004ECF -:10F490002408FFDF3C188008A0E5000890C400089D -:10F4A000370C00802409005000888024A0D0000878 -:10F4B0008E390008AD9900388F0E00148D8F003002 -:10F4C00001CF6821AD8D0034918B0000316A00FFBF -:10F4D00011490029264801000E0012AF02402021E8 -:10F4E00024040038000028210E0014472406000AD6 -:10F4F0008FBF00348FB200308FB1002C8FB0002846 -:10F500002402000103E0000827BD003894D8005C05 -:10F510008CD00054330EFFFF0205782301CF682BF7 -:10F5200015A0FFAC8FA300108CD9005430660004E6 -:10F5300014C0FFAC032520230A0014A52C82021856 -:10F540003C188008370C0080A0E600088E390008BF -:10F5500024090050AD9900388F0E00148D8F0030B3 -:10F5600001CF6821AD8D0034918B0000316A00FF1E -:10F570001549FFD9264801002406FF8001062824EA -:10F580003C048000AC8500288E2700083103007FF2 -:10F590003C10800C0070F821AFE700D08E220008EC -:10F5A000AF9F00240A0014E0AFE200D48E230008CD -:10F5B0003C04800834820080AC4300540240202187 -:10F5C0000E001436AC400030240400382405008DB1 -:10F5D0000E001447240600128FBF00348FB2003093 -:10F5E0008FB1002C8FB000282402000103E0000836 -:10F5F00027BD00380A0014AA8FA4001C27BDFFE80D -:10F60000AFBF001090A6000D30C7001010E0000C36 -:10F61000008040213C0280088C4400048CA3000838 -:10F620001064000830C9000430C5000410A0001C9C -:10F630008FBF00102402000103E0000827BD00185E -:10F6400030C900041120001030CB001210E0FFF987 -:10F650008FBF00103C0880088CA700088D060004AE -:10F6600014E6FFF524020001240400382405008D6F -:10F670000E001447240600128FBF00102402000160 -:10F6800003E0000827BD0018240A0012156AFFE9EC -:10F690008FBF0010010020210A00148927BD001827 -:10F6A000000020210A000CB827BD00183C05080006 -:10F6B00024A555983C040800248473583C02080093 -:10F6C000244255A0240300063C010800AC257AC85A -:10F6D0003C010800AC247ACC3C010800AC227AD072 -:10F6E0003C010800A0237AD403E0000800000000D9 -:10F6F00003E00008240200013C028000308800FF83 -:10F70000344701803C0680008CC301B80460FFFED2 -:10F71000000000008CC501282418FF803C0D800AE1 -:10F7200024AF010001F8702431EC007FACCE00243E -:10F73000018D2021ACE50000948B00DA35096000D2 -:10F7400024080002316AFFFFACEA00042402000131 -:10F75000A4E90008A0E8000BACE000243C0710007E -:10F76000ACC701B8AF84002403E00008AF850054A3 -:10F770008C9900048F8D00242409FFBF0325C0232A -:10F78000AC98000491AF00C42403FFEF31EE007F7A -:10F79000A1AE00C48C8C0020938B00308F86002497 -:10F7A000358A0002AF8B0048A7800044AC8A002055 -:10F7B000A4C000AC90C800C401093824A0C700C48C -:10F7C0008F840024AC8000DC908500C400A310244A -:10F7D00003E00008A08200C43C02800034450180A0 -:10F7E0003C0480008C8301B80460FFFE8F890054C4 -:10F7F0002407608324060002ACA900008C88012441 -:10F80000ACA80004A4A70008A0A6000B3C051000AB -:10F8100003E00008AC8501B8938800308F89004868 -:10F820008F82002430C600FF0109382330E900FF31 -:10F830000122182130A500FF2468007810C00002C2 -:10F84000012438210080382130E4000314800003B3 -:10F8500030AA00031140000D312B000310A0000955 -:10F860000000102190ED0000244E000131C200FF85 -:10F870000045602BA10D000024E700011580FFF971 -:10F880002508000103E00008000000001560FFF3F8 -:10F890000000000010A0FFFB000010218CF8000009 -:10F8A00024590004332200FF0045782BAD180000D6 -:10F8B00024E7000415E0FFF92508000403E0000830 -:10F8C0000000000093850030938800408F87004837 -:10F8D000000432003103007F00E5102B30C47F00AC -:10F8E0001040000F006428258F8400243C0980000C -:10F8F0008C8A00DCAD2A00A43C03800000A35825BC -:10F90000AC6B00A08C6C00A00580FFFE0000000026 -:10F910008C6D00ACAC8D00DC03E000088C6200A8AC -:10F920000A0015E88F840024938800413C0280007F -:10F9300000805021310300FEA383004130ABFFFF64 -:10F9400030CC00FF30E7FFFF344801803C098000E5 -:10F950008D2401B80480FFFE8F8D005424180016FA -:10F96000AD0D00008D2201248F8D0024AD02000416 -:10F970008D590020A5070008240201B4A119000A2E -:10F98000A118000B952F01208D4E00088D47000413 -:10F99000978300448D59002401CF302100C72821CE -:10F9A00000A320232418FFFFA504000CA50B000EC4 -:10F9B000A5020010A50C0012AD190018AD18002406 -:10F9C00095AF00D83C0B10002407FFF731EEFFFF86 -:10F9D000AD0E00288DAC0074AD0C002CAD2B01B821 -:10F9E0008D46002000C7282403E00008AD45002014 -:10F9F0008F8800240080582130E7FFFF910900C65E -:10FA00003C02800030A5FFFF312400FF00041A00F3 -:10FA10000067502530C600FF344701803C09800054 -:10FA20008D2C01B80580FFFE8F820054240F001733 -:10FA3000ACE200008D390124ACF900048D7800207F -:10FA4000A4EA0008241901B4A0F8000AA0EF000BF2 -:10FA5000952301208D6E00088D6D0004978400446D -:10FA600001C35021014D602101841023A4E2000C48 -:10FA7000A4E5000EA4F90010A4E60012ACE0001406 -:10FA80008D780024240DFFFFACF800188D0F006C5A -:10FA9000ACEF001C8D0E00683C0F1000ACEE002097 -:10FAA000ACED0024950A00AE240DFFF73146FFFFB0 -:10FAB000ACE60028950C00709504007231837FFF3E -:10FAC0000003CA003082FFFF0322C021ACF8002CE3 -:10FAD000AD2F01B8950E00728D6A002000AE302166 -:10FAE000014D2824A506007203E00008AD65002042 -:10FAF0003C028000344601803C0580008CA301B8A4 -:10FB00000460FFFE24090018ACC40000A0C9000B6B -:10FB10008F8800243C041000950700AEA4C7001095 -:10FB2000ACC0003003E00008ACA401B83C02800087 -:10FB3000344501803C0480008C8301B80460FFFEE2 -:10FB40008F8A002C240600199549001C3128FFFFDC -:10FB5000000839C0ACA70000A0A6000B3C051000AF -:10FB600003E00008AC8501B88F8700340080402195 -:10FB700030C400FF3C0680008CC201B80440FFFE88 -:10FB80008F8900549383005034996000ACA9000021 -:10FB9000A0A300058CE20010240F00022403FFF74D -:10FBA000A4A20006A4B900088D180020A0B8000A7D -:10FBB000A0AF000B8CEE0000ACAE00108CED00048A -:10FBC000ACAD00148CEC001CACAC00248CEB002021 -:10FBD000ACAB00288CEA002C3C071000ACAA002C2F -:10FBE0008D090024ACA90018ACC701B88D05002010 -:10FBF00000A3202403E00008AD04002093850050FA -:10FC00002403000127BDFFE800A330042CA200203C -:10FC1000AFB00010AFBF001400C018211040001397 -:10FC20002410FFFE3C0708008CE7319000E610240A -:10FC30003C0880003505018014400005240600843E -:10FC40008F890024240A00042410FFFFA12A00EC5D -:10FC50000E00168400000000020010218FBF001467 -:10FC60008FB0001003E0000827BD00183C06080014 -:10FC70008CC631940A0016B600C310248F87002C5E -:10FC800027BDFFE0AFB20018AFB10014AFB0001055 -:10FC9000AFBF001C30D000FF90E6000D00A088210F -:10FCA0000080902130C5007FA0E5000D8F850024E5 -:10FCB0008E2300188CA200C01062002E240A000EB1 -:10FCC0000E0016A9A38A00502409FFFF1049002244 -:10FCD0002404FFFF52000020000020218E26000097 -:10FCE0003C0C001000CC5824156000393C0E000874 -:10FCF00000CE682455A0003F024020213C1800029D -:10FD000000D880241200001F3C0A00048F87002CBA -:10FD10008CE200148CE300108CE500140043F823FF -:10FD200003E5C82B13200005024020218E24002C5F -:10FD30008CF10010109100310240202124020012A9 -:10FD4000A38200500E0016A92412FFFF10520002D9 -:10FD50002404FFFF000020218FBF001C8FB2001879 -:10FD60008FB100148FB000100080102103E0000854 -:10FD700027BD002090A800C4350400200A0016DF2B -:10FD8000A0A400C400CA48241520000B8F8B002CAF -:10FD90008F8D002C8DAC00101580000B02402021AF -:10FDA0008E2E002C51C0FFEC0000202102402021AB -:10FDB0000A0016FA240200178D66001050C0FFE6F4 -:10FDC00000002021024020210A0016FA240200111E -:10FDD00002402021240200150E0016A9A382005023 -:10FDE000240FFFFF104FFFDC2404FFFF0A0016E979 -:10FDF0008E2600000A001720240200143C0800048C -:10FE000000C8382450E0FFD4000020210240202107 -:10FE10000A0016FA240200138F86002427BDFFE093 -:10FE2000AFB10014AFBF0018AFB0001090C300C452 -:10FE300030A500FF306200201040000800808821BB -:10FE40008CCB00C02409FFDF256A0001ACCA00C0CA -:10FE500090C800C401093824A0C700C414A0004001 -:10FE60003C0C80008F840024908700C42418FFBFBE -:10FE70002406FFEF30E3007FA08300C4979F004477 -:10FE80008F8200488F8D002403E2C823A799004485 -:10FE9000A5A000AC91AF00C401F87024A1AE00C4CD -:10FEA0008F8C0024A18000C78F8A0024A540007297 -:10FEB000AD4000DC914500C400A65824A14B00C40D -:10FEC0008F9000208F8400489786004402042821E8 -:10FED00010C0000FAF850020A38000403C078000C9 -:10FEE0008E2C000894ED01208E2B0004018D5021F2 -:10FEF000014B8021020620233086FFFF30C8000F0F -:10FF0000390900013131000116200009A3880040A1 -:10FF1000938600308FBF00188FB100148FB000108F -:10FF200027BD0020AF85004C03E00008AF860048E5 -:10FF300000C870238FBF0018938600308FB1001463 -:10FF40008FB0001034EF0C00010F282127BD0020D6 -:10FF5000ACEE0084AF85004C03E00008AF8600489B -:10FF600035900180020028210E00168424060082AC -:10FF70008F840024908600C430C5004050A0FFBA92 -:10FF8000A38000508F8500343C0680008CCD01B8E2 -:10FF900005A0FFFE8F890054240860822407000218 -:10FFA000AE090000A6080008A207000B8CA30008F9 -:10FFB0003C0E1000AE0300108CA2000CAE02001428 -:10FFC0008CBF0014AE1F00188CB90018AE190024A5 -:10FFD0008CB80024AE1800288CAF0028AE0F002C7F -:10FFE000ACCE01B80A001744A38000508F8A0024C9 -:10FFF00027BDFFE0AFB10014AFB000108F880048FC -:020000040001F9 -:10000000AFBF001893890028954200AC30D100FFA3 -:100010000109182B0080802130AC00FF3047FFFF22 -:100020000000582114600003310600FF0120302138 -:1000300001095823978300440068202B1480001B7B -:100040000000000010680043240A0001118A0048E3 -:1000500034E708803165FFFF0E00162602002021DC -:100060000E0016668F8400548F840024948D0070D7 -:1000700025AC0001A48C0070948B00703C06080035 -:100080008CC6318831677FFF10E6004F000000000A -:1000900002002021022028218FBF00188FB10014F8 -:1000A0008FB000100A00173027BD0020914400C413 -:1000B0002406FF8000868825A15100C4978400444F -:1000C0003088FFFF1100001C938900288F8E0024C8 -:1000D0002419EFFF008BF82395D800AC0168682B3A -:1000E00033E900FF03197824A5CF00AC51A0002A02 -:1000F000010058218E0500202408FFFB2403000185 -:1001000000A81024AE0200201183002534E78000EF -:10011000020020213165FFFF0E001626012030214C -:10012000978B00448F870048A780004400EB802312 -:10013000AF900048938900288F8C00248FBF00184F -:100140008FB100148FB0001027BD002003E000081D -:10015000A18900C78E0800202409FFFB34E7800036 -:1001600001092824AE050020158AFFBA34E708806B -:10017000020020210E0015F43165FFFF020020214E -:10018000022028218FBF00188FB100148FB00010FB -:100190000A00173027BD00200A0017E70000482199 -:1001A000020020213165FFFF0E0015F401203021EF -:1001B000978B00448F870048A780004400EB802382 -:1001C0000A0017F7AF90004894890070240A800055 -:1001D000012A4024A48800709085007090990070D6 -:1001E00030A200FF000219C20003F827001FC1C09F -:1001F000332F007F01F87025A08E00700A0017CF02 -:10020000020020218F88002424030001910A007835 -:10021000910500C7250900783147003F24E6FFE03B -:1002200000C318042CC2002030670019A3850028E1 -:100230001040001AAF8900343C0A8000354B0002A0 -:10024000240500012406000114E00016006B1024B0 -:10025000000028211440000F306300201060000FC0 -:10026000240500018D0600748D1900742403FF809D -:1002700000C31024000279403338007F01F868255C -:100280003C0E100001AE6025AD4C083091280001F5 -:10029000310600010A0017A50000000003E0000875 -:1002A000000000008D0F00748D0D00742418FF8075 -:1002B00001F87024000E414031AC007F010C502544 -:1002C0003C0B1000014B38253C0980000A0017A5A3 -:1002D000AD27083027BDFFD8AFB000108F90003495 -:1002E000AFB40020AFB10014AFBF0024AFB3001C07 -:1002F000AFB200188E0500103C0208008C4231B0ED -:100300008F86003830A73FFF00E2182B8CD20014F4 -:10031000008088218CD30020106000070000A021FD -:1003200090CB000D240AFF80014B4824312800FFA8 -:100330001500000C00056382022020212411000D0D -:10034000A39100508FBF00248FB400208FB3001CF6 -:100350008FB200188FB100148FB000100A0016A9D8 -:1003600027BD00283185000354A0FFF4022020217E -:1003700094CF001C8F8E00248E070028A5CF00D8B4 -:100380008CCD0010024D302310E6005C2402001FCB -:100390000E0016A9A3820050241FFFFF105F004E1D -:1003A0002404FFFF8F83003C8F88002C0263982178 -:1003B0008D090010012310238F83001CAD02001053 -:1003C000AD1300208C67007400F3202B14800062B2 -:1003D000022020218F8600388E0C00248CC500243A -:1003E0001185000702202021240E001C0E0016A9F2 -:1003F000A38E0050240DFFFF104D00372404FFFF93 -:100400008F84002C8C980024270F0001AC8F0024CF -:10041000127200448F99001C8F32007412530041F5 -:100420003C0A00808E090000012A10241440003A82 -:10043000000000008E0400142412FFFF109200063A -:10044000240B001B022020210E0016A9A38B0050B4 -:10045000105200212404FFFF8E0300003C0C000119 -:10046000006C282410A000133C0600800066A02425 -:10047000168000090200282102202021240E001AE3 -:100480000E0016A9A38E0050240DFFFF104D001280 -:100490002404FFFF02002821022020210E0016C99B -:1004A000240600012410FFFF2404FFFF1050000A5F -:1004B000241400018F8F002C022020210280302183 -:1004C00095F2003424050001265800010E0017A5FE -:1004D000A5F80034000020218FBF00248FB4002035 -:1004E0008FB3001C8FB200188FB100148FB00010B2 -:1004F0000080102103E0000827BD00288F83003C06 -:1005000000E3C8210259C02B1300FFA88F88002CDC -:100510000A00188E24020018AC8000200A0018B8C7 -:100520008E0400148E1F00003C07008003E798240F -:100530001660FFF92408001A022020210E0016A9D7 -:10054000A38800502403FFFF1443FFBA2404FFFFD5 -:100550000A0018E18FBF0024240B001D0E0016A90D -:10056000A38B0050240AFFFF144AFF9A2404FFFFC4 -:100570000A0018E18FBF00248F85002427BDFFD813 -:10058000AFB3001CAFB20018AFB10014AFB0001091 -:10059000AFBF002090A700C48F9000342412FFFF4B -:1005A00034E2004092060000A0A200C48E030010B6 -:1005B000008098211072000630D1003F2408000D01 -:1005C0000E0016A9A3880050105200262406FFFF33 -:1005D0008F8A00248E0900188D4400C01124000762 -:1005E000240C000E026020210E0016A9A38C0050DE -:1005F000240BFFFF104B001B2406FFFF24040020E8 -:10060000122400048F8D002491AF00C435EE002029 -:10061000A1AE00C48F85003C10A0001A00000000AD -:100620001224004B8F9800248F92FED42406FFFDE5 -:10063000971000709651000A1230000B8FBF0020F7 -:100640003C1F08008FFF318C03E5C82B1720001ECC -:1006500002602021000028210E0017A524060001B9 -:10066000000030218FBF00208FB3001C8FB2001814 -:100670008FB100148FB0001000C0102103E00008FB -:1006800027BD00285224002A8E0300148F840024E2 -:100690009489007025280001A48800709487007058 -:1006A0003C0508008CA5318830E27FFF1045000E24 -:1006B00000000000026020210E0017302405000118 -:1006C0000A001943000030212402002DA3820050AB -:1006D0000E0016A92413FFFF1453FFE12406FFFFA9 -:1006E0000A0019448FBF00209498007024198000DC -:1006F0002405000103199024A492007090910070C9 -:10070000908D0070323000FF001079C2000F70270A -:10071000000E61C031AB007F016C5025A08A0070D3 -:100720000E001730026020210A001943000030211A -:100730002406FFFF1466FFD68F8400240260202168 -:100740000E001730240500010A0019430000302173 -:10075000026020210A00195D2402000A8F8800240B -:1007600027BDFFE8AFB00010AFBF0014910A00C46E -:100770008F87003400808021354900408CE60010CE -:10078000A10900C43C0208008C4231B030C53FFFD3 -:1007900000A2182B106000078F850038240DFF8001 -:1007A00090AE000D01AE6024318B00FF1560000893 -:1007B0000006C382020020212403000D8FBF001415 -:1007C0008FB0001027BD00180A0016A9A38300509F -:1007D00033060003240F000254CFFFF7020020214C -:1007E00094A2001C8F85002424190023A4A200D801 -:1007F0008CE8000000081E02307F003F13F900352E -:100800003C0A00838CE800188CA600C01106000882 -:10081000000000002405000E0E0016A9A38500505C -:100820002407FFFF104700182404FFFF8F850024D2 -:1008300090A900C435240020A0A400C48F8C002CF3 -:10084000918E000D31CD007FA18D000D8F83003C76 -:100850001060001C020020218F8400388C9800104A -:100860000303782B11E0000D241900180200202149 -:10087000A39900500E0016A92410FFFF105000028B -:100880002404FFFF000020218FBF00148FB0001050 -:100890000080102103E0000827BD00188C8600109E -:1008A0008F9F002C0200202100C31023AFE2001014 -:1008B000240500010E0017A5240600010A0019CC2A -:1008C000000020210E001730240500010A0019CC79 -:1008D00000002021010A5824156AFFD98F8C002CB2 -:1008E000A0A600EC0A0019B9A386004227BDFFD8D4 -:1008F000AFB000108F900034AFB20018AFBF00202F -:10090000AFB3001CAFB100148E1100103C030800FF -:100910008C6331B032253FFF00A3102B104000083C -:10092000008090218F8600382409FF8090CA000D36 -:10093000012A4024310700FF14E0000B00116B82F4 -:10094000024020212412000DA39200508FBF0020EE -:100950008FB3001C8FB200188FB100148FB000103D -:100960000A0016A927BD002831AC0003240B0001A2 -:10097000558BFFF40240202190CF000D31EE00088E -:1009800011C000608F93003C16600009240200270C -:100990008E19000C8CD80020173800052402002086 -:1009A0008E0200088CDF0024105F0040240200202B -:1009B0000E0016A9A38200502406FFFF1046003344 -:1009C0002404FFFF8F99002C240AFFF73C13800EAC -:1009D0009329000D2404FF803C0D8000012AF82497 -:1009E000A33F000D8F99001C3C0808008D0831AC16 -:1009F0008F830054972700788F9F002C01031021CC -:100A000030E57FFF000530400046782131F8007F57 -:100A10000313602101E47024ADAE002CA591000009 -:100A20008FEB0028256A0001AFEA00288FE3002C35 -:100A30008E09002C00694021AFE8002C8E07002CA5 -:100A4000AFE700308E050014AFE5003497E6003ABA -:100A500024C20001A7E2003A973300783C10080056 -:100A60008E1031B02663000130717FFF12300027F5 -:100A7000006030218F8F001C0240202124050001DE -:100A80000E001730A5E60078000020218FBF00205F -:100A90008FB3001C8FB200188FB100148FB00010FC -:100AA0000080102103E0000827BD00288E050014F7 -:100AB0002413FFFF10B3001D8F8300248E0800183D -:100AC0008C6700C0150700092402000E8E0A00245E -:100AD0008CC9002815490005240200218E07002832 -:100AE0008CCB002C10EB00132402001F0E0016A963 -:100AF000A38200501453FFB32404FFFF0A001A4ED0 -:100B00008FBF00200A001A1624020024240E800041 -:100B1000006E682431ACFFFF000C5BC2317100FF36 -:100B2000001180270A001A47001033C00A001A6516 -:100B3000240200258E05002C10A0FFEC24020023C7 -:100B40008F8E001C8DCD007401A5602B1580FFE7F2 -:100B5000240200268CCF001400A7C02101F8202B0E -:100B60001080FF998F99002C024020210A001A65FD -:100B70002402002227BDFFE0AFB000108F900034A8 -:100B8000AFB10014AFBF00188E0500103C03080081 -:100B90008C6331B00080882130A43FFF0083102B8C -:100BA000104000078F8600382409FF8090CA000D8E -:100BB000012A4024310700FF14E000098F8B003C1C -:100BC0002410000D02202021A39000508FBF001898 -:100BD0008FB100148FB000100A0016A927BD0020A5 -:100BE000116000080005C3828F8F00248F8EFED411 -:100BF0002407FFFD95EC007095CD000A11AC00387C -:100C00008FBF00183305000314A00010000000007F -:100C10009219000213200041000000008E060024FB -:100C200050C0000F92040003022020212402000F74 -:100C30000E0016A9A38200502408FFFF14480007E5 -:100C40002407FFFF0A001AE28FBF001890C3000DAF -:100C50003064000810800037022020219204000335 -:100C600024070002308900FF15270005308F00FFA0 -:100C70008F8A003C11400031240C002C308F00FF83 -:100C800039E500102CAD00012DEE000102002821F5 -:100C900001CD30250E0016C9022020212410FFFFAF -:100CA0001050000E2407FFFF8F83003C10600017D8 -:100CB000022020213C1908008F39318C0323C02BDE -:100CC0005700000C2411002D0220202100002821B3 -:100CD0000E0017A524060001000038218FBF001860 -:100CE0008FB100148FB0001000E0102103E0000865 -:100CF00027BD00200E0016A9A39100501450FFF646 -:100D00002407FFFF0A001AE28FBF00180E001730F9 -:100D1000240500010A001AE1000038218CDF0024BC -:100D20008E020024545FFFC1022020210A001AC253 -:100D3000920400030A001AB62402001002202021A7 -:100D40000E0016A9A38C0050240BFFFF104BFFE3ED -:100D50002407FFFF0A001AC99204000330A500FF10 -:100D60002406000124A9000100C9102B1040000C2A -:100D700000004021240A000100A61823308B000146 -:100D800024C60001006A38040004204211600002F9 -:100D900000C9182B010740251460FFF800A618238E -:100DA00003E000080100102127BDFFD8AFB00018F4 -:100DB0008F900034AFB1001CAFBF00202403FFFFB1 -:100DC0002411002FAFA30010920600002405000894 -:100DD00026100001006620260E001B01308400FF53 -:100DE00000021E003C021EDC34466F410A001B2933 -:100DF0000000102110A000090080182124450001E6 -:100E000030A2FFFF2C4500080461FFFA00032040D8 -:100E10000086202614A0FFF9008018210E001B0177 -:100E2000240500208FA300102629FFFF313100FF89 -:100E300000034202240700FF1627FFE201021826E2 -:100E400000035027AFAA0014AFAA00100000302101 -:100E500027A8001027A7001400E6782391ED0003CF -:100E600024CE000100C8602131C600FF2CCB000455 -:100E70001560FFF9A18D00008FA200108FBF002028 -:100E80008FB1001C8FB0001803E0000827BD0028B8 -:100E90009383003027BDFFE024020034AFB100147B -:100EA000AFB00010AFBF001CAFB2001800808821A7 -:100EB0001062006200A080219204000414800045AA -:100EC0008F880024A38000288E0500048D0600C8AA -:100ED0003C0700FF34E3FFFF00A3282400C5102BCC -:100EE0001440004DAF85003C978A00448F8700482E -:100EF0000147102310A00032A78200448F98001CE5 -:100F0000304CFFFF9312007C0012788231F1000117 -:100F10000011708001C56821018D582B116000619E -:100F20008F8600248F8900208F84004C1089005EFA -:100F30003C023F018E1F00003C10250003E2C82444 -:100F40001730007A8F8400348F8700348F86002416 -:100F50008CE30000ACC300788CE50010ACC50088C1 -:100F60008F8700488F85003C938D002830AE0003AA -:100F7000000E4023310A0003014D4021A3880028C0 -:100F800094CB00AC01276021AF8C002035691000A4 -:100F9000A4C900AC1620005101452021AF840048AF -:100FA000000020218FBF001C8FB200188FB10014E9 -:100FB0008FB000100080102103E0000827BD002042 -:100FC0008F840020AF800048008730210A001B92E8 -:100FD000AF860020241F000CA39F00500E0016A90E -:100FE000022020212419FFFF1059FFEE2404FFFFE7 -:100FF0008F880024A38000288E0500048D0600C879 -:101000003C0700FF34E3FFFF00A3282400C5102B9A -:101010001040FFB5AF85003C0220202124090019B3 -:10102000A38900500E0016A92411FFFF1051FFDD07 -:101030002404FFFF0A001B648F85003C8F8400247A -:101040008F8700348CF20030908600C430C50010C9 -:1010500014A000108F8300482C680005150000289C -:1010600000000000908A00C4246BFFFC314900108E -:1010700015200008316400FF8F8D004C8F8C0020FC -:1010800011AC0004388F000131EE000115C0002FB3 -:10109000000000000E001B14000000000A001BEB03 -:1010A000000000008F890020938D002830AE0003DF -:1010B000000E4023310A0003014D4021A38800287F -:1010C00094CB00AC01276021AF8C00203569100063 -:1010D000A4C900AC1220FFB101452021251800044D -:1010E000A398002894CF00AC24920004AF9200484B -:1010F00035F12000A4D100AC0A001B930000202190 -:101100008C8200DC1242FF6C022020212418000592 -:10111000A39800500E0016A92412FFFF1452FF6678 -:101120002404FFFF0A001B948FBF001C30E500FF62 -:101130000E0015B0000030218F8600248F870048F4 -:101140008F8900200A001B848F85003C0E0015DB70 -:10115000000000000A001BEB000000009383004227 -:1011600027BDFFE024020002AFB20018AFB10014A7 -:10117000AFBF001C00808821AFB00010000090219C -:10118000106200552404FFFD978300448F850048BA -:101190003066FFFF00C5202B1480005B9387003072 -:1011A0003C0880009504012010E500528F8A002041 -:1011B0008F84004C30A500FF0E0015B024060001FE -:1011C0008F9F00543C0580003C19408027ED01783A -:1011D00031B00078240EFF800219582534AF090081 -:1011E00031B8000701AE6024ACAC0800030F8021C9 -:1011F000ACAB081002202021020028210E001B4E5B -:10120000AF9000342403FFFF104300332404FFFF9A -:101210008E0C00103C0708008CE731B092060000ED -:1012200031843FFF0087102B1040002330CD003F5A -:101230008F980054000471803C0408008C8431A80D -:101240002409FF809390004100984021010E202145 -:1012500000897024000E51403C0980003099007FC5 -:101260003C0F00808F8800243525094035E20001BD -:1012700001593825308B0078308600073C03100078 -:101280003C1F800C00C5C0210162582500E3502599 -:10129000033F782136050001AD2E0804AF980038D1 -:1012A000AD2B0814AF8F002CAD2E0028AD040074B8 -:1012B000AD2A0830A3850041938300422410000327 -:1012C0005070002725A3FFE0240C0001106C001CC7 -:1012D00024060023024020218FBF001C8FB200187B -:1012E0008FB100148FB000100080102103E00008BF -:1012F00027BD0020314900035520FFAE8F84004CEC -:101300000A001C278F90004C8F84004C306500FF32 -:101310000E0015B024060001938B00302405003424 -:1013200011650018978300448F8500483062FFFFE5 -:1013300000A25823AF8B00480A001C5FA78000441E -:1013400011A6003700000000022020212411000B0C -:101350000E0016A9A39100500A001C5F00409021C6 -:101360002C7200201240FFF80003F8803C070800B0 -:1013700024E7796003E7C8218F2D000001A0000851 -:10138000000000008F8500482CA200055440001D7D -:10139000A7800044978A00443148FFFF00A84823F3 -:1013A0002D2F000511E00003314400FF24AEFFFCA7 -:1013B00031C400FF8F90004C8F9800201218000459 -:1013C00038990001332D000115A00029000000000C -:1013D0008F910024922500C434A30010A22300C4DE -:1013E000978300448F8500488F8400243062FFFF7C -:1013F00000A25823AC8000DCA78000440A001C5FD8 -:10140000AF8B00483062FFFF00A258230A001C5F28 -:10141000AF8B00482403FFFF11830005000000008C -:101420000E001981022020210A001C5F004090213B -:101430000E001908022020210A001C5F00409021A4 -:101440000E0019E5022020210A001C5F00409021B7 -:101450000E00185F022020210A001C5F004090212E -:101460000E001A87022020210A001C5F00409021F4 -:101470000E0015DB00000000978300448F850048B4 -:10148000306CFFFF00AC38232CFF000553E0FFA8B1 -:101490003062FFFF8F860024A7800044ACC200DCCE -:1014A0003062FFFF00A258230A001C5FAF8B004888 -:1014B00027BDFFD0AFB20018AFB00010AFBF0028FB -:1014C000AFB50024AFB40020AFB3001CAFB100141F -:1014D0003C0C80008D880128240FFF803C07800A87 -:1014E00025100100250B0080020F68243205007FC3 -:1014F000016F7024AD8E009000A72821AD8D0024CF -:1015000090A700EC3169007F3C0A8004012A182171 -:10151000A38700429066007C00809021AF83001C6E -:1015200030C20002AF880054AF85002400A018210B -:10153000144000022404003424040030A38400304A -:101540008C6600CC30F100FF24040004AF86004814 -:1015500012240004A38000508E5300041660001D66 -:101560003C0880009387004130F200011240000FD8 -:101570008FBF00288CB800748CA400742419FF80DD -:101580000319882400117140308F007F01CF60253E -:101590003C0D2000018D582530F500FE3C0A8000EE -:1015A000AD4B0830A39500418FBF00288FB50024B4 -:1015B0008FB400208FB3001C8FB200188FB10014BD -:1015C0008FB000102402000127BD003003E00008A6 -:1015D000ACA600CC8E590008951F01208E46001045 -:1015E000033FC0213307FFFF30F5000F32B4000185 -:1015F000AF8600201680003BA395004035060C0006 -:1016000002A6102100F51823AD030084AF82004C20 -:101610008E4900043128FFFF1100002BA7890044E8 -:101620002410FF803C1580003C1420000A001D4D52 -:101630002413FFFE90AE00C4020E682431AC00FFFC -:101640001580002A0240202193840041978600449F -:10165000308F000111E0000B026428248F890024E0 -:101660008D2300748D280074A38500410070102420 -:101670000002C940311F007F033FC02503148825A5 -:10168000AEB1083010C000108F85002490A700C4B0 -:1016900002075824316A00FF1540FFE6024020216E -:1016A0000E001C01979100441040FFE89384004114 -:1016B0002405FFFD544500058E430020022028210B -:1016C0000E001586024020218E4300203070000459 -:1016D0001600000A2414FFFB8F8500240A001D0356 -:1016E0008F8600480A001D2EAF86004C0E00182B76 -:1016F000000000000A001D3D9384004100749824FE -:101700000E0015A0AE5300208F8500240A001D0393 -:101710008F86004827BDFFD8AFB3001CAFB10014BF -:10172000AFBF0020AFB20018AFB000103C02800085 -:101730008C5201408C4B01483C048000000B8C0211 -:10174000322300FF317300FF8C8501B804A0FFFE37 -:1017500034900180AE1200008C8701442464FFF0B5 -:10176000240600022C830013AE070004A611000813 -:10177000A206000BAE1300241060004F8FBF0020A4 -:10178000000448803C0A0800254A79E0012A4021EB -:101790008D04000000800008000000003C100800DC -:1017A0008E1031A831733FFF001389800212282167 -:1017B000240CFF8000B12021264D01002647008027 -:1017C0003C0F80003C03800431A8007F30E9007F9B -:1017D000308A007F3C0E800A3C02800C008CC024C2 -:1017E00001AC302400ECC82401239821014280215F -:1017F000ADE60024010EF821ADF90090ADF8002807 -:10180000AF90002CAF9F0024AF93001C0E00167504 -:10181000016080213C0380008C6B01B80560FFFEF5 -:101820008F87002C8F8600243465018090F9000D8D -:10183000ACB2000024C200780019C60000187E0374 -:10184000000F9027001227C2A4B00006108000707D -:10185000240E6082A4AE0008A0A00005240F0002A0 -:10186000A0AF000B0004C4008F8B001C3C192700A4 -:1018700003199025ACB20010ACA00014ACA0002459 -:10188000ACA00028ACA0002C8D7300382411FF8080 -:10189000ACB3001890F0000D0230282430A400FFF3 -:1018A000108000058FBF002090EC000D319F007F5D -:1018B000A0FF000D8FBF00208FB3001C8FB2001857 -:1018C0008FB100148FB000103C0A10003C0D800056 -:1018D00027BD002803E00008ADAA01B8265F01007B -:1018E0002405FF8033F8007F3C06800003E5782460 -:1018F0003C19800A03192021ACCF0024908E00C42B -:1019000000AE682431AC00FF1180FFEAAF840024F0 -:10191000248E007895CD00123C0C08008D8C31A8E7 -:101920003C03800C31AB3FFF01924821000B5180FA -:10193000012A40213104007F010510240083382151 -:10194000ACC200280E001675AF87002C3C03800047 -:101950008C6501B804A0FFFE00000000AE1200007C -:101960008C720144AE120004A6110008241100027A -:10197000A211000BAE1300240A001DD88FBF002057 -:101980003C1260008E452C083C03F0033462FFFFDC -:1019900000A2F824AE5F2C088E582C083C1901B028 -:1019A00003199825AE532C080A001DD88FBF0020BC -:1019B000264D010031AF007F3C10800A240EFF80CD -:1019C00001F0282101AE60243C0B8000AD6C0024A6 -:1019D0001660FFB8AF85002424110003A0B100EC0D -:1019E0000A001DD88FBF002026480100310A007F61 -:1019F0003C0B800A2409FF80014B3021010920247F -:101A00003C078000ACE400240A001DD7AF86002408 -:101A1000944D0012321F3FFF31AC3FFF159FFF8DE9 -:101A2000240E608290C300C42409FF800123102487 -:101A3000304A00FF1140FF87000000002407000427 -:101A4000A0C700EC8F87002C240860842406000DBA -:101A5000A4A80008A0A600050A001DC2240F0002C9 -:101A60005F865437E4AC62CC50103A453662198533 -:101A7000BF14C0E81BC27A1E84F4B556094EA6FEF8 -:101A80007DDA01E7C04D7481800801008008008084 -:101A90008008000008004FBC08004FBC08005098A8 -:101AA0000800506C0800505008004F8C08004F8C04 -:101AB00008004F8C08004FC4080072BC080073086F -:101AC000080072C8080071F0080072C8080072F8B7 -:101AD000080072C8080071F0080071F0080071F089 -:101AE000080071F0080071F0080071F0080071F052 -:101AF000080071F0080071F0080071F0080072E849 -:101B0000080072D8080071F0080071F0080071F048 -:101B1000080071F0080071F0080071F0080071F021 -:101B2000080071F0080071F0080071F0080071F011 -:101B3000080071F0080072D8080078900800775CFF -:101B4000080078580800775C080078280800764478 -:101B50000800775C0800775C0800775C0800775C19 -:101B60000800775C0800775C0800775C0800775C09 -:101B70000800775C0800775C0800775C0800775CF9 -:041B8000080077845E -:0C1B84000A000122000000000000000028 -:101B90000000000D747061342E362E3135000000C7 -:101BA00004060F010000000000000000000000001B -:101BB0000000000000000000000000000000000025 -:101BC0000000000000000000000000000000000015 -:101BD0000000000000000000000000000000000005 -:101BE00000000000000000000000000000000000F5 -:101BF00000000000000000000000000000000000E5 -:101C000000000000000000000000000000000000D4 -:101C100010000003000000000000000D0000000D97 -:101C20003C020800244217C03C03080024632AB485 -:101C3000AC4000000043202B1480FFFD2442000430 -:101C40003C1D080037BD2FFC03A0F0213C1008000C -:101C5000261004883C1C0800279C17C00E00025E5A -:101C6000000000000000000D2402FF8027BDFFE0FF -:101C700000821024AFB00010AF420020AFBF0018A8 -:101C8000AFB10014936500043084007F0344182131 -:101C90003C0200080062182130A50020036080216A -:101CA0003C080111277B000814A000022466005C98 -:101CB0002466005892020004974301049204000431 -:101CC0003047000F3063FFFF308400400067282357 -:101CD00010800009000048219202000530420004F3 -:101CE000104000050000000010A0000300000000EC -:101CF00024A5FFFC240900049202000530420004E0 -:101D0000104000120000000010A0001000000000B1 -:101D10009602000200A72021010440252442FFFE74 -:101D2000A7421016920300042402FF8000431024EF -:101D3000304200FF104000033C0204000A00017220 -:101D4000010240258CC20000AF4210188F4201787A -:101D50000440FFFE2402000AA7420140960200024E -:101D6000240400093042000700021023304200071B -:101D7000A7420142960200022442FFFEA74201440C -:101D8000A740014697420104A74201488F4201083B -:101D9000304200205040000124040001920200045F -:101DA00030420010144000023483001000801821DB -:101DB000A743014A000000000000000000000000EE -:101DC00000000000AF48100000000000000000000C -:101DD00000000000000000008F4210000441FFFEE0 -:101DE0003102FFFF104000070000000092020004D3 -:101DF0003042004014400003000000008F421018E1 -:101E0000ACC20000960200063042FFFF24420002EE -:101E10000002104300021040036288219622000055 -:101E20001120000D3044FFFF00A710218F83003CDC -:101E30008F45101C00021082000210800043102108 -:101E4000AC45000030A6FFFF0E0005B700052C02D0 -:101E500000402021A6220000920300042402FF80FB -:101E600000431024304200FF1040001F000000001B -:101E700092020005304200021040001B00000000EA -:101E80009742100C2442FFFEA742101600000000EB -:101E90003C02040034420030AF4210000000000059 -:101EA0000000000000000000000000008F42100051 -:101EB0000441FFFE000000009742100C8F45101CEB -:101EC0003042FFFF244200300002108200021080E6 -:101ED000005B1021AC45000030A6FFFF0E0005B7E7 -:101EE00000052C02A62200009604000224840008AB -:101EF0000E0001E73084FFFF974401040E0001F556 -:101F00003084FFFF8FBF00188FB100148FB0001016 -:101F10003C02100027BD002003E00008AF4201781A -:101F20003084FFFF308200078F85002410400002BC -:101F3000248300073064FFF800A4102130421FFF03 -:101F400003421821247B4000AF850028AF82002483 -:101F500003E00008AF4200843084FFFF3082000FAE -:101F60008F85002C8F860034104000022483000FE0 -:101F70003064FFF000A410210046182BAF8500301C -:101F80000046202314600002AF82002CAF84002C96 -:101F90008F82002C34048000034218210064182131 -:101FA000AF83003C03E00008AF4200808F82001442 -:101FB000104000088F8200048F82FFE41440000567 -:101FC0008F8200043C02FFBF3442FFFF00822024C6 -:101FD0008F82000430430006240200021062000FCA -:101FE0003C0201012C620003504000052402000461 -:101FF0001060000F3C0200010A00022E00000000E9 -:1020000010620005240200061462000C3C0201115B -:102010000A000227008210253C02001100821025D0 -:10202000AF421000240200010A00022EAF82000C11 -:1020300000821025AF421000AF80000C00000000AD -:10204000000000000000000003E0000800000000A5 -:102050008F82000C10400004000000008F4210002E -:102060000441FFFE0000000003E000080000000043 -:102070008F820010000229C224A3FFF0000318423F -:102080002444F80000031140004310210002108096 -:1020900000431021000210803C0308002463180054 -:1020A0002C84030114800013004330218F84001816 -:1020B00000A4102B1440000F0000302100A41023B6 -:1020C00000021940006218210003188000621821E4 -:1020D0008F82001C008210212442FFFF0045102B3C -:1020E00014400004000318803C02080024421A1423 -:1020F0000062302103E0000800C0102127BDFFE08E -:10210000AFBF0018AFB10014AFB000103C046008BE -:102110008C8250002403FF7F3C06600000431024A3 -:102120003442380CAC8250008CC24C1C3C1A8000EB -:10213000000216023042000F10400007AF82001C60 -:102140008CC34C1C3C02001F3442FC00006218246B -:10215000000319C2AF8300188F420008275B4000BC -:1021600034420001AF420008AF8000243C02601CF2 -:10217000AF400080AF4000848C4500088CC3080845 -:1021800034028000034220212402FFF00062182460 -:102190003C0200803C010800AC2204203C025709AC -:1021A000AF84003C14620004AF85003424020001B7 -:1021B0000A00028EAF820014AF8000143C0280003F -:1021C000344400708C8300008F42000038420001CC -:1021D0003042000110400018AF83003800804021D9 -:1021E000006030218D0700003C0508008CA5045CD0 -:1021F0003C0408008C84045800E6302300001021C1 -:1022000000A6282100A6302B008220210086202154 -:102210003C010800AC25045C3C010800AC240458D7 -:102220008F42000038420001304200011440FFEDAF -:1022300000E03021AF8700383C028000344200705B -:102240008C4700008F8600383C0508008CA5045C94 -:102250003C0408008C84045800E638230000102158 -:1022600000A72821008220218F82001400A7302B94 -:10227000008620213C010800AC25045C3C010800DC -:10228000AC240458104000160000000097420104DE -:10229000104000058F830000146000072462FFFFD8 -:1022A0000A0002D02C62000A2C6200105040000488 -:1022B0008F83000024620001AF8200008F83000042 -:1022C0002C62000A144000032C6200070A0002D7A7 -:1022D000AF80FFE41040000224020001AF82FFE45F -:1022E0008F4301088F44010030622000AF83000457 -:1022F00010400008AF8400103C0208008C42042CFF -:10230000244200013C010800AC22042C0A0005B361 -:102310003C0240003065020014A0000324020F00BC -:102320001482026024020D0097420104104002C88A -:102330003C02400030624000144000AD8F82003CFF -:102340008C4400088F4201780440FFFE24020800FC -:10235000AF42017824020008A7420140A740014291 -:10236000974201048F8400043051FFFF3082000146 -:1023700010400007022080212623FFFE24020002D5 -:102380003070FFFFA74201460A000304A74301483B -:10239000A74001463C0208008C42043C1440000D5A -:1023A0008F830010308200201440000224030009B3 -:1023B00024030001006020218F8300102402090003 -:1023C0005062000134840004A744014A0A00031F3C -:1023D0000000000024020F0014620005308200207B -:1023E000144000062403000D0A00031E2403000508 -:1023F000144000022403000924030001A743014AFA -:102400003C0208008C4204203C0400480E00020AF2 -:10241000004420250E000233000000008F82000CD3 -:102420001040003E000000008F4210003C030020DE -:1024300000431024104000398F8200043042000213 -:102440001040003600000000974210141440003382 -:1024500000000000974210088F88003C3042FFFFC8 -:1024600024420006000218820003388000E8302170 -:10247000304300018CC400001060000430420003AF -:102480000000000D0A00036000E810215440001015 -:102490003084FFFF3C05FFFF0085202400851826BF -:1024A0000003182B0004102B0043102410400005DB -:1024B00000000000000000000000000D000000000F -:1024C000240001CB8CC200000A00035F00452025D8 -:1024D0003883FFFF0003182B0004102B0043102447 -:1024E0001040000500000000000000000000000D8A -:1024F00000000000240001D48CC200003444FFFF1F -:1025000000E81021AC4400003C0208008C4204307A -:10251000244200013C010800AC2204308F6200001C -:102520008F84003CAF8200088C8300003402FFFFE0 -:102530001462000F000010213C0508008CA5045413 -:102540003C0408008C84045000B0282100B0302BDB -:1025500000822021008620213C010800AC25045483 -:102560003C010800AC2404500A0005A9240400081A -:102570008C820000304201001040000F000010214A -:102580003C0508008CA5044C3C0408008C840448DD -:1025900000B0282100B0302B0082202100862021AD -:1025A0003C010800AC25044C3C010800AC24044864 -:1025B0000A0005A9240400083C0508008CA5044471 -:1025C0003C0408008C84044000B0282100B0302B6B -:1025D00000822021008620213C010800AC25044413 -:1025E0003C010800AC2404400A0005A924040008AA -:1025F0008F6200088F62000000021602304300F074 -:10260000240200301062000524020040106200E045 -:102610008F8200200A0005B12442000114A00005A9 -:1026200000000000000000000000000D000000009D -:10263000240001FE8F4201780440FFFE00000000EC -:102640000E00023B00000000144000050040802105 -:10265000000000000000000D000000002400020542 -:102660008E02000010400005000000000000000085 -:102670000000000D00000000240002088F62000C22 -:1026800004430003240200010A000457AE000000C6 -:10269000AE0200008F82003C8C480008A2000007B8 -:1026A0008F65000C8F64000430A3FFFF0004240238 -:1026B00000852023308200FF0043102124420005C2 -:1026C000000230832CC20081A605000A14400005D8 -:1026D000A2040004000000000000000D0000000043 -:1026E000240002208F85003C0E0005D5260400142E -:1026F0008F6200048F430108A60200083C0210000C -:1027000000621824106000080000000097420104D5 -:10271000920300072442FFEC346300023045FFFFC0 -:102720000A0003ECA2030007974201042442FFF0D1 -:102730003045FFFF960600082CC2001354400005E8 -:10274000920300079202000734420001A202000730 -:102750009203000724020001106200052402000316 -:102760001062000B8F82003C0A00040930C6FFFF94 -:102770008F82003C3C04FFFF8C43000C0064182453 -:1027800000651825AC43000C0A00040930C6FFFFA1 -:102790003C04FFFF8C4300100064182400651825DA -:1027A000AC43001030C6FFFF24C2000200021083B9 -:1027B000A20200058F83003C304200FF000210801F -:1027C000004328218CA800008CA2000024030004F0 -:1027D0000002170214430012000000009742010497 -:1027E0003C03FFFF010318243042FFFF0046102383 -:1027F0002442FFFE00624025ACA8000092030005C1 -:10280000306200FF0002108000501021904200143E -:102810003042000F004310210A00043EA2020006CD -:102820008CA40004974201049603000A3088FFFF3D -:102830003042FFFF004610232442FFD6000214005E -:1028400001024025ACA80004920200079204000592 -:102850002463002800031883006418213442000414 -:10286000A2030006A20200078F8200042403FFFBDC -:102870003442000200431024AF8200049203000699 -:102880008F87003C00031880007010218C440020CA -:102890003C02FFF63442FFFF00824024006718210B -:1028A000AE04000CAC68000C920500063C03FF7FF0 -:1028B0008E02000C0005288000B020213463FFFF49 -:1028C000010330249488002600A728210043102407 -:1028D000AE02000CAC860020AC880024ACA800102E -:1028E00024020010A742014024020002A740014236 -:1028F000A7400144A7420146974201043C04000856 -:102900002442FFFEA7420148240200010E00020AF1 -:10291000A742014A9603000A9202000400431021D4 -:102920002442000230420007000210233042000718 -:102930000E000233AE0200108F6200003C0308005C -:102940008C63044424040010AF8200089742010401 -:102950003042FFFF2442FFFE00403821000237C30F -:102960003C0208008C420440006718210067282BB5 -:1029700000461021004510213C010800AC2304440E -:102980003C010800AC2204400A00053E00000000A3 -:1029900014A0000500000000000000000000000D71 -:1029A000000000002400029E8F4201780440FFFED8 -:1029B000000000000E00023B000000001440000573 -:1029C00000408021000000000000000D0000000019 -:1029D000240002A58E020000544000069202000767 -:1029E000000000000000000D00000000240002A80C -:1029F0009202000730420004104000058F8200045C -:102A00002403FFFB3442000200431024AF82000481 -:102A10008F6200040443000892020007920200063D -:102A20008E03000CAE000000000210800050102148 -:102A3000AC430020920200073042000454400009D9 -:102A40009602000A920200053C0300010002108079 -:102A5000005010218C46001800C33021AC460018ED -:102A60009602000A92060004277100080220202125 -:102A700000C2302124C60005260500140E0005D52D -:102A800000063082920400068F6500043C027FFF3E -:102A900000042080009120218C8300043442FFFF39 -:102AA00000A2282400651821AC83000492020007CC -:102AB0009204000592030004304200041040001408 -:102AC00096070008308400FF000420800091202138 -:102AD0008C860004974201049605000A306300FFCB -:102AE0003042FFFF004310210045102130E3FFFF7B -:102AF000004310232442FFD830C6FFFF0002140019 -:102B000000C23025AC8600040A0004F292030007DC -:102B1000308500FF0005288000B128218CA400002A -:102B200097420104306300FF3042FFFF0043102151 -:102B3000004710233C03FFFF008320243042FFFFA7 -:102B400000822025ACA400009203000724020001AB -:102B50001062000600000000240200031062001151 -:102B6000000000000A0005158E03001097420104C2 -:102B7000920300049605000A8E24000C00431021E5 -:102B8000004510212442FFF23C03FFFF0083202474 -:102B90003042FFFF00822025AE24000C0A000515FC -:102BA0008E03001097420104920300049605000A68 -:102BB0008E24001000431021004510212442FFEE16 -:102BC0003C03FFFF008320243042FFFF00822025CA -:102BD000AE2400108E0300102402000AA742014018 -:102BE000A74301429603000A920200043C040040FD -:102BF00000431021A7420144A74001469742010427 -:102C0000A7420148240200010E00020AA742014A1D -:102C10000E000233000000008F62000092030004E7 -:102C200000002021AF820008974201049606000AA6 -:102C30003042FFFF00621821006028213C03080099 -:102C40008C6304443C0208008C4204400065182157 -:102C5000004410210065382B004710213C0108007A -:102C6000AC2304443C010800AC220440920400045C -:102C7000008620212484000A3084FFFF0E0001E733 -:102C800000000000974401043084FFFF0E0001F5AE -:102C9000000000003C021000AF4201780A0005B0BD -:102CA0008F820020148200273062000697420104C0 -:102CB000104000673C0240003062400010400005B8 -:102CC00000000000000000000000000D00000000F7 -:102CD000240003968F4201780440FFFE240208007E -:102CE000AF42017824020008A7420140A7400142F8 -:102CF0008F82000497430104304200011040000716 -:102D00003070FFFF2603FFFE24020002A7420146A7 -:102D1000A74301480A0005682402000DA7400146A8 -:102D20002402000DA742014A8F620000240400081B -:102D3000AF8200080E0001E7000000000A00054213 -:102D400002002021104000423C024000936200003B -:102D5000304300F0240200101062000524020070CD -:102D600010620035000000000A0005B08F820020CC -:102D70008F620000974301043050FFFF3071FFFF66 -:102D80008F4201780440FFFE320200070002102348 -:102D9000304200072403000A2604FFFEA743014037 -:102DA000A7420142A7440144A7400146A751014858 -:102DB0008F42010830420020144000022403000921 -:102DC00024030001A743014A0E00020A3C0400400C -:102DD0000E000233000000003C0708008CE70444AA -:102DE000021110212442FFFE3C0608008CC604405C -:102DF0000040182100E33821000010218F650000F9 -:102E000000E3402B00C230212604000800C8302116 -:102E10003084FFFFAF8500083C010800AC27044464 -:102E20003C010800AC2604400E0001E70000000051 -:102E30000A000542022020210E0001390000000096 -:102E40008F82002024420001AF8200203C0240001B -:102E5000AF420138000000000A00028F3C028000EF -:102E60003084FFFF30C6FFFF00052C0000A6282598 -:102E70003882FFFF004510210045282B0045102116 -:102E800000021C023042FFFF0043102100021C021E -:102E90003042FFFF004310213842FFFF03E00008EB -:102EA0003042FFFF3084FFFF30A5FFFF00001821F4 -:102EB0001080000700000000308200011040000276 -:102EC00000042042006518210A0005CB00052840B7 -:102ED00003E000080060102110C0000624C6FFFFB8 -:102EE0008CA2000024A50004AC8200000A0005D5D5 -:102EF0002484000403E000080000000010A0000883 -:102F000024A3FFFFAC8600000000000000000000CA -:102F10002402FFFF2463FFFF1462FFFA24840004ED -:082F200003E0000800000000BE -:042F280000000001A4 -:042F2C000A00002671 -:102F300000000000000000000000000D74787034F4 -:102F40002E362E3136000000040610000000000A64 -:102F5000000001360000EA600000000000000000F0 -:102F60000000000000000000000000000000000061 -:102F70000000000000000000000000000000000051 -:102F80000000000000000000000000000000001D24 -:102F90000000000000000000000000000000000031 -:102FA0000000000000000000000000000000000021 -:102FB0000000000000000000000000000000000011 -:102FC00000000000000000001000000300000000EE -:102FD0000000000D0000000D3C02080024423B6090 -:102FE0003C03080024633E18AC4000000043202B43 -:102FF0001480FFFD244200043C1D080037BD7FFC07 -:1030000003A0F0213C100800261000983C1C08008A -:10301000279C3B600E0004AE000000000000000D85 -:103020003C0580008F83003034A800708D070000BD -:10303000008330253C02900000C22025ACA4002073 -:10304000AF8700243C0480008C8900200520FFFE0F -:1030500000000000348400708C8500003C180800DB -:103060008F18007C3C0D08008DAD007800A7C823A8 -:1030700003195021000070210159602B01AE582125 -:10308000016C38213C010800AC2A007C3C0108009E -:10309000AC27007803E00008000000000A00003DB3 -:1030A000240400018F8500303C048000348300013B -:1030B00000A3102503E00008AC82002003E0000814 -:1030C000000010213084FFFF30A5FFFF10800007B3 -:1030D000000018213082000110400002000420424C -:1030E000006518211480FFFB0005284003E000085C -:1030F0000060102110C00007000000008CA200003A -:1031000024C6FFFF24A50004AC82000014C0FFFB0E -:103110002484000403E000080000000010A0000860 -:1031200024A3FFFFAC8600000000000000000000A8 -:103130002402FFFF2463FFFF1462FFFA24840004CB -:1031400003E000080000000090AA00318FAB0010DF -:103150008CAC00403C0300FF8D680004AD6C002087 -:103160008CAD004400E060213462FFFFAD6D0024AF -:103170008CA700483C09FF000109C024AD67002866 -:103180008CAE004C0182C82403197825AD6F000471 -:10319000AD6E002C8CAD0038314A00FFAD6D001CC7 -:1031A00094A900323128FFFFAD68001090A70030CD -:1031B000A5600002A1600004A167000090A3003296 -:1031C000306200FF00021982106000052405000132 -:1031D0001065000E0000000003E00008A16A000175 -:1031E0008CD80028354A0080AD7800188CCF0014A8 -:1031F000AD6F00148CCE0030AD6E00088CC4002C76 -:10320000A16A000103E00008AD64000C8CCD001C35 -:10321000AD6D00188CC90014AD6900148CC8002471 -:10322000AD6800088CC70020AD67000C8CC200148C -:103230008C8300700043C82B13200007000000009F -:103240008CC20014144CFFE400000000354A0080DA -:1032500003E00008A16A00018C8200700A0000C629 -:10326000000000009089003027BDFFF88FA8001CE7 -:10327000A3A900008FA300003C0DFF8035A2FFFF33 -:103280008CAC002C00625824AFAB0000A1000004FD -:1032900000C05821A7A000028D06000400A048210C -:1032A0000167C8218FA50000008050213C18FF7FD6 -:1032B000032C20263C0E00FF2C8C0001370FFFFF53 -:1032C00035CDFFFF3C02FF0000AFC82400EDC02455 -:1032D00000C27824000C1DC00323682501F8702566 -:1032E000AD0D0000AD0E00048D240024AFAD000034 -:1032F000AD0400088D2C00202404FFFFAD0C000C51 -:103300009547003230E6FFFFAD06001091450048BA -:1033100030A200FF000219C2506000018D24003469 -:10332000AD0400148D4700388FAA001827BD00088F -:10333000AD0B0028AD0A0024AD07001CAD00002C29 -:10334000AD00001803E00008AD00002027BDFFE03D -:10335000AFB20018AFB10014AFB00010AFBF001C87 -:103360009098003000C088213C0D00FF330F007F93 -:10337000A0CF0000908E003135ACFFFF3C0AFF006B -:10338000A0CE000194A6001EA22000048CAB001465 -:103390008E29000400A08021016C2824012A4024E9 -:1033A0000080902101052025A6260002AE240004FD -:1033B00026050020262400080E00007224060002C4 -:1033C00092470030260500282624001400071E001E -:1033D0000003160324060004044000032403FFFF37 -:1033E000965900323323FFFF0E000072AE23001007 -:1033F000262400248FBF001C8FB200188FB1001448 -:103400008FB0001024050003000030210A00007C6A -:1034100027BD002027BDFFD8AFB1001CAFB00018FA -:10342000AFBF002090A900302402000100E050212D -:103430003123003F00A040218FB000400080882150 -:1034400000C04821106200148FA70038240B00052B -:1034500000A0202100C02821106B001302003021A1 -:103460000E000108000000009225007C30A400023C -:103470001080000326030030AE0000302603003425 -:103480008FBF00208FB1001C8FB00018006010218A -:1034900003E0000827BD00280E000087AFB0001031 -:1034A0000A00014F000000008FA3003C0100202112 -:1034B0000120282101403021AFA300100E0000CED2 -:1034C000AFB000140A00014F000000008F820050CE -:1034D00024430001304200FFAF83005003E00008A6 -:1034E000000000003C0580008CA30E108F84004477 -:1034F000AC8300208CA20E1803E00008AC820024EC -:103500003C0580008CA30E148F840044AC83002003 -:103510008CA20E1C03E00008AC82002493820038C9 -:103520001040001B2483000F2404FFF000643824A3 -:1035300010E00019978B002C9784004C9389002E83 -:103540003C0A601C0A0001900164402301037021C1 -:10355000006428231126000231C2FFFF30A2FFFFC2 -:103560000047302B50C0000E00E448218D4D000C68 -:1035700031A3FFFF00036400000C2C0304A1FFF340 -:103580000000302130637FFF0A000188240600011B -:1035900003E00008000000009784004C00E448218C -:1035A0003123FFFF3168FFFF0068382B54E0FFF83C -:1035B000A783004C938A002E11400005240F0001C0 -:1035C000006BC023A380002E03E00008A798004CE6 -:1035D000006BC023A38F002E03E00008A798004CC7 -:1035E00003E000080000000027BDFFE8AFB00010B6 -:1035F0003084FFFF3C10800093A8002BAFBF001465 -:10360000A6040144960A0E1630C600FF8FA90030AA -:10361000A60A0146AE050148A2060152A608015AB3 -:10362000AE0701608FA3002CA609015801202021BC -:103630000E00017CAE0301543C021000AE02017882 -:103640008FBF00148FB0001003E0000827BD0018E2 -:103650003C038000346200708C4900008F87003C7E -:103660002484000727BDFFF83084FFF8AF890024C9 -:103670003C088000950E008A31CDFFFFAFAD000001 -:103680008FAC000001875823256AFFFF31461FFFDA -:1036900000C4282B14A0FFF7350D00708DAC00007E -:1036A0003C0508008CA500843C0A08008D4A008077 -:1036B000018958230000102100ABC0210007C882F7 -:1036C00001422021030B302B0019388035094000BE -:1036D0000086782100E9102127BD00083C01080080 -:1036E000AC3800843C010800AC2F008003E00008E7 -:1036F000000000008F82003C2486000730C5FFF8E0 -:1037000000A2182130641FFF03E00008AF84003CD2 -:103710003C0320FF27BDFFE83C0760003C08800019 -:10372000240500103464FFFDACE53008AFBF001085 -:10373000AD040E00000000000000000000000000CA -:1037400000000000000000003C0200FF345FFFFDAD -:10375000AD1F0E003C0B60048D7850002419FF7FD4 -:103760003C0E00020319782435EC380C35CD0109E4 -:10377000ACED4C1824060009AD6C50008CEA0438FE -:10378000AD060008AD0000148CE94C1C3145FFFF6C -:103790003C06570900091E0238A42F713062000F41 -:1037A00034C80010AF820048104000072485C0B321 -:1037B0008CEB4C1C3C0D001F35ACFC00016C502404 -:1037C000000A49C2AF8900348CF90808241FF000B0 -:1037D000033FC02403087026030678262DE8000165 -:1037E0002DC600010106382550E00009A3800038ED -:1037F0003C09601C8D24000824030001A3830038C9 -:1038000030827C00A780004CA380002EA782002C71 -:10381000AF80005014A00003AF80003C3C05600066 -:10382000ACA0442C0E000559000000008FBF001012 -:103830000A000E9927BD001827BDFFC8AFB3002CA2 -:10384000AFB20028AFBF0030AFB10024AFB000204E -:10385000936200080080982100A090211440003558 -:10386000240400100E0001C9000000000E000168D1 -:10387000004080210002C4003C1932000319882551 -:10388000AE110000936F0009976E0012936A000A50 -:1038900031EC00FF31CDFFFF018D5821000B4400BA -:1038A000314900FF01093825AE0700048F8500501B -:1038B0009784004000403021308320001460004D88 -:1038C000AE050008AE00000C3C0580009784004067 -:1038D0000662004F8E03000C3090000816000002B4 -:1038E000264800062648000294A40E148CA50E1C3F -:1038F0008F670004936A00023084FFFF314900FFA4 -:10390000AFA900108F720014AFA800180E0001AF0D -:10391000AFB200148FBF00308FB3002C8FB20028DD -:103920008FB100248FB00020240400100A0001F29F -:1039300027BD00389365000997710012936C000B46 -:1039400030AD00FF01B13021318B00FF00CB802171 -:103950002602000A3050FFFF0E0001C9020020219C -:103960000E000168004088219368000997640012E6 -:103970000002FC00310900FF308AFFFF012A3821D4 -:1039800024E3000203E3C0253C1941000319782514 -:10399000AE2F00008F6E000C3C0D800095AC0E1415 -:1039A00001D32825AE2500048DA50E1C8F670004C9 -:1039B000936B00023184FFFF316600FFAFA6001059 -:1039C0008F68001400403021AFB200180E0001AF24 -:1039D000AFA80014020020218FBF00308FB3002C4D -:1039E0008FB200288FB100248FB000200A0001F2AE -:1039F00027BD0038976200123C0580009784004084 -:103A0000305FFFFF0661FFB4AE1F000C8E03000C99 -:103A10003C078000006798250A00026BAE13000C7B -:103A200027BDFFD8AFB40020AFBF0024AFB3001C48 -:103A3000AFB20018AFB10014AFB00010936200082D -:103A4000144000940080A021AF60000C97850040D6 -:103A500030A440001080009E24030016241040076C -:103A6000A363000AAF700014938F00428F6C0014A0 -:103A700031EE0001000E6A40018D5825AF6B001435 -:103A8000978A00408F6800143149001001093825D9 -:103A9000AF6700149786004030C300081060009F95 -:103AA000000000008F6600143C0310003C048000FE -:103AB00000C32825AF65001494820E0A3C1F8100C4 -:103AC0002413000E3059FFFF033FC025AF780004D8 -:103AD000A37300029372000A3406FFFC265100040F -:103AE000A371000A978800403107200010E0009180 -:103AF000000000003C0B80009789004095680E0C88 -:103B000097840040000918423107C0003065000367 -:103B100000071303309F100000A2C025001FCA0336 -:103B200003199825001390C0A772001297910040C6 -:103B3000936F000A00118182320E003C01CF682190 -:103B400025AC003CA36C0009956A0E0C31493FFF7F -:103B5000A7690010976D0012936C0009018D582120 -:103B6000256A00023149000700094023310300079C -:103B7000A363000B93670009976400129765001018 -:103B800030E200FF8F900028979800400044F82111 -:103B900003E5C82103269821331200401240000596 -:103BA0003266FFFF00D0702B3C11800011C0001660 -:103BB000000090210206782B15E0002D0000202146 -:103BC0003C1080008E120E143C058000AE120E10C8 -:103BD0008E110E1CAE110E18AE060E008CB8000031 -:103BE000331300081260FFFD0000000094B90E08B6 -:103BF00000C0802100008821A79900408CA60E04F7 -:103C000024120001AF860028977F001033F3FFFFD6 -:103C10008E8900000130202310800058AE840000FF -:103C2000022020210E000243020028218E8C000079 -:103C300015800005000000008F6D0014240EFFBFEA -:103C400001AEA024AF7400148F78000C03138821F8 -:103C5000AF71000C936F000815E000030000000036 -:103C60001640004000000000A3720008020020215E -:103C70008FBF00248FB400208FB3001C8FB20018B8 -:103C80008FB100148FB000100080102103E00008F5 -:103C900027BD00288F900028978200403C118000AB -:103CA000020098213045004014A0FFD90000902167 -:103CB000976800108F8700283103FFFF1467FFEC1F -:103CC00000002021000088210A000339241200018D -:103CD0002403000E24104007A363000AAF700014F1 -:103CE000938F00428F6C001431EE0001000E6A4089 -:103CF000018D5825AF6B0014978A00408F6800141F -:103D00003149001001093825AF670014978600403B -:103D100030C300081460FF6300000000AF600004BF -:103D2000A3600002978800403107200014E0FF7173 -:103D300000003021A760001297910040936F000AA5 -:103D40003C0B800032301F000010718301CF6821CE -:103D500025AC0028A36C0009956A0E0C0A00030A22 -:103D6000A76A00108F6600143C1FEFFF37F9FFFEB3 -:103D700000D998240A00034FAF7300148F6B00140E -:103D8000356A00400E00016EAF6A00140A00033E5F -:103D9000022020218F8500448F8A003027BDFFC07C -:103DA0003C048000AFB70034AFB40028AFB1001CB2 -:103DB000AFBF0038AFB60030AFB5002CAFB30024B2 -:103DC000AFB20020AFB000188C8701048CA900248A -:103DD000AC8A00808CA8002000E988230000B8216C -:103DE000AC880E108CA600240000A021AC860E1812 -:103DF0008C820E10AC820E148C830E18AC830E1CB9 -:103E0000122000333C168000936B000811600054B0 -:103E100000000000976E001031CDFFFF022D602BD7 -:103E20001580004F0000000097700010320FFFFF58 -:103E3000AECF0E003C0580008CB30000327200084B -:103E40001240FFFD0000000094B50E088CA50E0482 -:103E500032B0FFFF32140001128000440000000065 -:103E60000000000D3219A04024180040133800450E -:103E70003214A0001280003F00000000937300087D -:103E80001260000927A4001097620010305FFFFF46 -:103E900000BFC82B53200005AFB10010320800400E -:103EA0001100003400000000AFB10010A7900040E6 -:103EB000AF8500280E0002BD000000000040A021D8 -:103EC000104000BE8FB100101620FFCF0000000090 -:103ED0002E96000102D78825122000178FBF0038C8 -:103EE0008F85003024170F0010B700713C0480004C -:103EF0008C8F017805E0FFFE24180F0050B8008F6A -:103F00003C0480008C990E14241402403C051000DF -:103F1000AC9901448C930E1CAC930148A0800152D3 -:103F2000A480015AAC800160A4800158AC94015473 -:103F3000AC8501788FBF00388FB700348FB6003062 -:103F40008FB5002C8FB400288FB300248FB20020CF -:103F50008FB1001C8FB0001803E0000827BD00409F -:103F6000AED10E000A0003C33C05800014A0FFBEC2 -:103F70003219A0400E0001750000A0210A0003EADA -:103F80002E9600013C0380008C7F017807E0FFFE45 -:103F9000240208008F84003CAC6201783C0380005E -:103FA000946B008A316AFFFF0144382324E9FFFF44 -:103FB00031281FFF2D06000814C0FFF9346C4000A3 -:103FC00000A0A0210E000168008C90218F8300309A -:103FD00024040F000040A821023488233C068000FE -:103FE0001064000524050001938E004231C50001D4 -:103FF00000056A4035A500010015FC003C020100E7 -:1040000003E2C825AE5900008F93005032180036E5 -:10401000320F0008AE53000411E0004100B89825AB -:1040200094C30E0A8F84003C3C0B8100306AFFFF72 -:104030002492000832481FFF014B48253C0710001E -:10404000269200062410000EACC901600267982574 -:10405000A4D0015AAF88003CA4D201581620000811 -:104060003C1080008F8E003024050F0051C50002E7 -:1040700024170001367300400E00016E3C108000D2 -:104080008E180E1402402021AE1801448E0F0E1C13 -:10409000AE0F0148A2150152AE1301540E00017C6F -:1040A0003C151000AE1501780A0003E7000000007F -:1040B000128000053C07800094F20E08324900404F -:1040C00011200042000000008C8A01780540FFFEAC -:1040D0000000000094950E103C1005002403200001 -:1040E00032AEFFFF01D06825AC8D014C8C8C0E14D4 -:1040F0003C0B1000AC8C01448C860E1CAC86014835 -:10410000A0800152A480015AAC800160A4800158B3 -:10411000AC830154AC8B01780A0003F13C048000AD -:104120008F8D003C26920002A4D2015825AC0008D5 -:1041300031861FFF0A00044CAF86003CAC80014C66 -:1041400012800019000000008C9F0E10AC9F0144EB -:104150008C830E183C08800024110040AC83014879 -:104160008FBF0038A10001528FB70034A500015A5B -:104170008FB60030AD0001608FB5002CA50001584E -:104180008FB40028AD1101548FB300248FB20020EA -:104190008FB1001C8FB000183C04100027BD0040F8 -:1041A00003E00008AD0401788C820E14AC82014457 -:1041B0008C830E1C0A00048B3C0880000E000175E5 -:1041C0002E9600010A0003EB02D7882500000000AC -:1041D0000000000D000000002400033A0A000467FC -:1041E0003C04800027BDFFD8AFB100143C11800013 -:1041F000AFB00010AFB40020AFB3001CAFB20018D6 -:10420000AFBF00243C13080026733C340E0001F9B4 -:10421000363000703C14080026943CB40200902113 -:104220008E0800008E2400003883000130620001F7 -:10423000104000163C0A8000024048218D270000F3 -:104240003C1F08008FFF006C3C0F08008DEF0068DA -:1042500000E8102303E260210000C0210182702BDE -:1042600001F8682101AE40213C010800AC2C006C33 -:104270003C010800AC2800688D4B00003966000145 -:1042800030C5000114A0FFED00E040218E1F0000AA -:104290003C1808008F18006C3C0D08008DAD0068BC -:1042A00003E8C823031938210000702100F9602BAE -:1042B00001AE4021010C58213C010800AC27006CE4 -:1042C0003C010800AC2B00688E2801002406FF800A -:1042D0003C04800A2505024000A64824AE280020A0 -:1042E000AE2900248E09000030A3007F0064502115 -:1042F0003C078000AF8A0044AF880030AF890024BB -:104300008CE201780440FFFE000000008E1F0000D8 -:104310003C1808008F1800743C0D08008DAD00702B -:1043200003E9C82303195821000070210179302BBB -:1043300001AE602101864821240508003C010800E7 -:10434000AC2B00743C010800AC290070ACE501788E -:1043500090E40108A384004293830042306A000184 -:104360001140000F240E0D002502F8002C47030118 -:1043700010E0001C000819C22464FFF00004504241 -:10438000000A41400E00039A0113D8213C0A400064 -:104390003C088000AD0A01380A0004BD000000009E -:1043A000110E0026240F0F00110F002A3C02800876 -:1043B0003447008090FF00002418005033F900FFBC -:1043C0001738FFF33C0A40000E0009A3000000006C -:1043D0003C0A40003C088000AD0A01380A0004BDD8 -:1043E000000000008F8400340064282B14A0000B10 -:1043F0008F86004800866021258BFFFF0163482BD4 -:104400001520000600646823000D19400E00039A71 -:104410000074D8210A0005193C0A40000000000081 -:104420000000000D00000000240003AD0E00039A00 -:10443000000000000A0005193C0A40003C1B08006F -:10444000277B3DB40E00039A000000000A00051906 -:104450003C0A40003C1B0800277B3DD40E00039A19 -:10446000000000000A0005193C0A40008F8200503D -:1044700024430001304200FFAF83005003E00008F6 -:1044800000000000000411C003E0000824420240C4 -:104490003C04080024843BCC2405001A0A00007C5C -:1044A0000000302127BDFFE0AFBF001CAFB20018F5 -:1044B000AFB10014AFB000103C108000920B0109A6 -:1044C0002412FF800E0005563164007F8F9100306A -:1044D0000051502101524024AE08002492030109EA -:1044E0000E0005563064007F24060080240700C0BB -:1044F00024040040AE000810AE040814AE060818EC -:10450000AE07081C920C01090051F82133F8007F16 -:104510003C19800A031910213184007F0E000556D2 -:10452000AF8200448E1101003C0C008035850001F3 -:104530000222782101F24824AE0908048E0E0100FF -:10454000359800023609090001C2682131AB0078B4 -:1045500001655025AE0A08208E0501008E08010075 -:10456000360509800102182124640040009230249D -:10457000AE0608088E07010000E2F82127F9004086 -:104580003332007802588825AE1108248E040100C9 -:10459000952F000C8FBF001C8FB2001831EEFFFF6B -:1045A000000E69C0AE0D0800AE0C0828952B000C5B -:1045B0008FB10014316AFFFF000A41C0AE08002C21 -:1045C0008CA300508FB000108CA2003C8D240004FE -:1045D0008CA6001C8CA7003827BD0020AF83006884 -:1045E000AF820058AF840054AF86006003E000083B -:1045F000AF8700643C0A0800914A3BF13C0908007F -:1046000095293BEA3C051100000A3C0025280002E0 -:1046100000E8302500C5182524820008AC8300007E -:1046200003E00008AC8000043C0880003507090066 -:1046300090E60011240200280080502130C300FFC2 -:1046400000A0602110620002340B86DD240B0800FC -:104650003C07800034E20A9A9459000034EF0A9C27 -:1046600034ED0AA03338FFFFAD5800008DEE000096 -:1046700034E80A8024040001AD4E00048DA9000036 -:10468000AD4900089105001930A3000310640043F0 -:104690002866000214C000B0240400021064008BDD -:1046A000240500031065009634E60AA43C090800BE -:1046B00095293BE0240208005162004D3C0E800029 -:1046C0003C0E800035C5090090A6001290B9001973 -:1046D00035CB09808D68002830C700FF000778803F -:1046E0003138FFFF332300FF01F8102100032500BC -:1046F0000088702500025C003C0D600001CD302573 -:10470000356906FFAD490004AD4600008CA7002CBA -:1047100025490028AD4700088CB90030AD59000C80 -:104720008CB80034AD5800108CAF0038AD4F001479 -:104730008CA3001CAD4300188CA800203C03800013 -:104740003462093CAD48001C8CA40024346F09007D -:10475000AD4400208CAD0028AD4D00248C590000E4 -:10476000AD2C000425220014AD3900008C78010C1A -:10477000AD38000891E800123C04080090843BF03A -:10478000AD20001000082F0000046C0000AD602573 -:10479000358AFFFF03E00008AD2A000C3C09080041 -:1047A00095293BE03C0F080095EF3BEA34F90AA459 -:1047B0003C0E080095CE3BDC972800003138FFFF07 -:1047C00001F8682101AE382300082C0024E3FFF231 -:1047D00000A3202524020800AD44000CAD400010C9 -:1047E000AD4B00141562FFB6254A00183C0E800040 -:1047F00035CD090091A2001191A700193C050800D0 -:1048000094A53BE6304600FF35CB0A80956E002A22 -:104810000006C88230F800FF9787005C00191E0070 -:1048200000187C003128FFFF00A82021006F4825D8 -:104830000124102501C730213C0B4000004BC82546 -:104840000006C400AD590000AD58000491AF001837 -:104850003C03000624E90001000F46000103702517 -:10486000AD4E00088DA5002C3C0380003462093C4D -:10487000AD45000C8DAB001C31247FFF2549001491 -:10488000AD4B00108C590000AD2C0004346F0900B2 -:10489000AD3900008C78010CA784005C252200143F -:1048A000AD38000891E800123C04080090843BF009 -:1048B000AD20001000082F0000046C0000AD602542 -:1048C000358AFFFF03E00008AD2A000C34E20AA499 -:1048D00094460000951900283C09080095293BE002 -:1048E0000006C40000197C00370E810001EB68252A -:1048F000AD4E000CAD4D00100A0005E2254A001433 -:104900003C09080095293BE03C18080097183BEA51 -:104910003C0F080095EF3BDC94CE00003139FFFFDF -:10492000950D002803194021010F3823000E2400A3 -:10493000000D2C0024E3FFEE00A33025348281001B -:10494000AD42000CAD460010AD400014AD4B001858 -:104950000A0005E2254A001C1460FF5434E90AA449 -:10496000952800003C09080095293BE000083C0020 -:1049700000EB1825AD43000C0A0005E2254A0010A3 -:1049800003E00008240207D027BDFFE0AFB2001803 -:10499000AFB10014AFB00010AFBF001C0E00005C40 -:1049A000008088218F8800588F8700543C0580083C -:1049B00034B20080011128213C10800024020080C4 -:1049C000240300C000A72023AE0208183C0680087C -:1049D000AE03081C18800004AF850058ACC5000465 -:1049E0008CC90004AF8900541220000936040980E4 -:1049F0000E00069500000000924C00278E0B0074FC -:104A000001825004014B3021AE46000C360409806F -:104A10008C8E001C8F8F006001CF682319A00004CA -:104A20008FBF001C8C90001CAF9000608FBF001CDB -:104A30008FB200188FB100148FB000100A00005E12 -:104A400027BD00208F8600688F8300588F82005416 -:104A50003C05800834A40080AC860050AC83003C48 -:104A600003E00008ACA200043C038000346700703F -:104A70008CE30000308700FF3C0408008C84005465 -:104A800027BDFFF830AA00FF248200013C01080086 -:104A9000AC22005430C800FFAF8300243C098000E2 -:104AA0008D25017804A0FFFE352B00708D65000078 -:104AB000A3A700033C1808008F1800748FB90000EA -:104AC0003C0D08008DAD007000A338233C047FFF2F -:104AD00000E078213482FFFF0307382100007021B5 -:104AE0000322582401AE302100EF602B000847C09C -:104AF00000CC182101682825AFA500003C01080062 -:104B0000AC2700743C010800AC2300709124010A1A -:104B1000A3A000023C0280FFA3A400018FB8000004 -:104B2000314F007F3459FFFF03196824000F7600CE -:104B30003C0B002001AE6025356A20002408FF8070 -:104B40003C06100027BD0008AD2C014CAD2A0154D5 -:104B5000A5200158A128015203E00008AD260178E4 -:104B60003C038000346200708C480000308A00FFF3 -:104B700030A900FFAF8800243C0480008C850178B8 -:104B800004A0FFFE348700708CEB00003C05080099 -:104B90008CA500743C1908008F390070016820232F -:104BA00000A470210000102101C4C02B0322782131 -:104BB0003C07800001F868213C010800AC2E00741D -:104BC00034E60A003C010800AC2D00708CCC0020BB -:104BD0000009582B34E80980ACEC01448CC900244E -:104BE000000B1540ACE90148A0EA01509104004CCB -:104BF000A0E4016D03E00008A4E0015827BDFFE830 -:104C0000308400FFAFBF00100E00070D30A500FF7D -:104C10008F8300588FBF00103C0580003446004051 -:104C20002404FF903C02100027BD0018ACA3014CE7 -:104C3000A0A40152ACA6015403E00008ACA2017884 -:104C400027BDFFE03C088008AFBF001CAFB20018D2 -:104C5000AFB10014AFB00010351000808E06001800 -:104C60003C078000309200FF00C72025AE040018EA -:104C70000E00005C30B100FF9203000534620008B2 -:104C80000E00005EA2020005024020210E00073443 -:104C900002202821024020218FBF001C8FB2001863 -:104CA0008FB100148FB00010240500052406000108 -:104CB0000A0006CF27BD00203C08800027BDFFE882 -:104CC000AFB0001035050980AFBF001490A70009F0 -:104CD000240200063506090030E300FF241000041A -:104CE000106200722408000294AE005C3C0D0204C5 -:104CF00031CCFFFF018D5825AC8B000090AA000835 -:104D000031490020112000080000000090BF004E33 -:104D10003C1901033738030033EF00FF01F8282561 -:104D200024100008AC85000490CC001190C900113B -:104D3000318A00FF000A5882312700FF256A0005EA -:104D4000000A108038E300281460002900824823FC -:104D500090CF00123C1980003722090031E500FF96 -:104D60000005708001D06821000D340034C406FFB6 -:104D7000AD240004904C001190580012373F098078 -:104D80008FE400348F2F010C00105882330500FF90 -:104D900000AB702100083400008F1823000E6F0054 -:104DA00001A61025319F00FC3067FFFF03E9C021F9 -:104DB0000047C825014B7821000F2880AF19000C4F -:104DC0000E00005C012580213C0A800824090004B3 -:104DD000354800800E00005EA10900090200102184 -:104DE0008FBF00148FB0001003E0000827BD00182B -:104DF00090CE001190CD00193C07080094E73BE6E7 -:104E000031C600FF0006208231AC00FF00045E00C6 -:104E1000000C1C00016310250047C8253C1F400002 -:104E2000033FC0253C198000AD380000372209003F -:104E3000904C001190580012373F09808FE40034E5 -:104E40008F2F010C00105882330500FF00AB70213A -:104E500000083400008F1823000E6F0001A61025F3 -:104E6000319F00FC3067FFFF03E9C0210047C825E0 -:104E7000014B7821000F2880AF19000C0E00005C58 -:104E8000012580213C0A800824090004354800805F -:104E90000E00005EA1090009020010218FBF00145E -:104EA0008FB0001003E0000827BD00180A00076F4C -:104EB0002408001227BDFFD8AFB40020AFB3001CF8 -:104EC000AFB20018AFB10014AFBF0024AFB00010F4 -:104ED0003C06800090C3010B309200FF30B300FF0E -:104EE000306200300000A0211040007000008821D6 -:104EF00034C409809088000800083E0000072E0393 -:104F000004A00097240400048F8800583C01080086 -:104F1000A0243BF03C0C8000AD8000483C038000A6 -:104F2000906E010B31C5002010A000073C028000EC -:104F300034790980933800080018860000107E0339 -:104F400005E2009C3C0280083450090034470A8086 -:104F5000904D010B94EB002C92030011921F001254 -:104F600090E50018307800FF33F900FF00197880D1 -:104F700001F8702101D1502130B100FF01514821C9 -:104F80002524000A31AC00403091FFFF000C302B8B -:104F900002202021A78B005C3C010800A42A3BE6EC -:104FA0003C010800A4293BE83C010800A4293BEA95 -:104FB0003C010800A4203BE03C010800A4203BDCAD -:104FC0000E0001C9010680230E0005B20040202119 -:104FD000004020210E0005BF020028211680005C41 -:104FE000000000000E0001F2022020213C08080011 -:104FF00091083BF031140003128000163C1F80081A -:105000008F8400583C0C800835860080248B00017A -:10501000ACCB003C3C0580088CAA00040160202138 -:10502000014B482319200002AF8B00588CA40004C8 -:105030000E000695ACA400043C0F80008DEE0074B9 -:105040003C05800834AD0080004E8821ADB1000CD5 -:105050003C1F800837F9008002402021026028218F -:10506000A320006B0E00070D3C1280008F980058A3 -:1050700034500006AE58014C0E0005503C13100091 -:10508000A24201528FBF0024AE5001548FB40020C1 -:10509000AE5301788FB100148FB3001C8FB200188B -:1050A0008FB0001003E0000827BD002834C309803A -:1050B000906F0008000F7600000E6E0305A000330D -:1050C00034C209009059001B241F00103C01080045 -:1050D000A03F3BF0333800021300FF908F88005848 -:1050E0008F8300641468FF8E3C0380000E00005C18 -:1050F000000000003C0980083525008090A40009CC -:1051000024070016308800FF1107000D0000000082 -:1051100090A600093C0C0800918C3BF0240A000882 -:1051200030C400FF358B00013C010800A02B3BF090 -:10513000108A002F240D000A108D00282402000C74 -:105140000E00005E000000000A0007FC8F88005877 -:105150000E000763004020210A00082E0000000016 -:105160003C0B8008356A00808D4800548CC9010CC6 -:105170001120FF66AF880058240600143C01080087 -:10518000A0263BF00A0007FB3C0C80009071000851 -:10519000241400023C010800A0343BF0323000200F -:1051A0001200000B241400018F8800580A0007FC2D -:1051B00024110008345F00808FE70038AC470004FA -:1051C0008C430004AFE3003C0A0008073C02800067 -:1051D0008F8800580A0007FC24110004A0A20009CF -:1051E0000E00005E000000000A0007FC8F880058D7 -:1051F000240200140A0008ADA0A2000927BDFFE8A0 -:10520000AFBF0014AFB000103C1080009202010943 -:10521000240500010E00070D304400FF3C1F8008EC -:1052200093F8000E37E3008093F9000F906E00268C -:1052300093E9000A332F00FF00186600000F6C008E -:1052400031CB00FF018D5025000B3200014638257F -:10525000312800FF3445600000E820252402FF814A -:105260003C031000AE04014C8FBF0014AE05015486 -:10527000A2020152AE0301788FB0001003E00008D3 -:1052800027BD001827BDFFE8308400FFAFBF001026 -:105290000E00070D30A500FF344600403C0480009E -:1052A0002405FF92AC860154A08501528F830058DB -:1052B0008FBF00103C02100027BD0018AC83014CCA -:1052C00003E00008AC82017827BDFFD8AFB2001818 -:1052D000AFB10014AFB00010AFBF0020AFB3001CDF -:1052E0003C07800090E20109308600FF30B000FFEB -:1052F000000618C232040002307100011480000759 -:10530000305200FF3C098008353300809268000568 -:105310003105000810A0000C30CA00100240202106 -:105320000E00074502202821240200018FBF002023 -:105330008FB3001C8FB200188FB100148FB0001013 -:1053400003E0000827BD00281540003034E50A00BE -:105350008CB900248CB800081338004700004021A5 -:105360003C0E800835D30080926D0068240B00024B -:1053700031AC00FF118B00803C068000927F004C16 -:1053800090C40109509F00043213007C1100006793 -:10539000000000003213007C1660005A02402021F9 -:1053A00016200008320C00013C07800034EB0A0094 -:1053B0008D6500248CE8010414A8FFDC0000102196 -:1053C000320C00011180000D024020213C108000B1 -:1053D0008E0E010C8F8D006811CD000800000000BA -:1053E0000E0007E2022028218E0F010C3C188008D5 -:1053F00037100080AE0F0050024020210E0007340D -:10540000022028210A000900240200013C070800AC -:105410008CE7006424E600013C010800AC2600642F -:105420001600000D00000000022028210E000734A5 -:1054300002402021926F0068240D000231EE00FF2F -:1054400011CD0022024020210E0008B4000000000F -:105450000A000900240200010E00003D240400019E -:10546000926C0025020C58250E00005EA26B0025F0 -:105470000A000940022028218E6300188CE40104F0 -:105480008CBF002400031602149FFFB53045007F37 -:105490009269004C264400013093007F1265004061 -:1054A000312300FF1464FFAF3C0E80082648000142 -:1054B0003111007F310200FF1225000B240800018A -:1054C000004090210A00090D241100012405000468 -:1054D0000E0006CF240600010E0008B400000000F4 -:1054E0000A000900240200012407FF800247282443 -:1054F00000A79026324200FF004090210A00090DCB -:10550000241100010E0007E202202821320600309B -:1055100010C0FFA332100082024020210E00074578 -:10552000022028210A000900240200018E630018CD -:105530000240202102202821006610250E0008D6F6 -:10554000AE6200189264004C24050003240600019A -:105550000E0006CF308400FF0E00003D2404000141 -:10556000926A0025020A48250E00005EA269002505 -:105570000A000900240200018E7800183C198000FE -:105580000240202103197825022028210E0007342B -:10559000AE6F00189264004C0A00098824050004CC -:1055A0003246008038CA0080146AFF6E3C0E8008C4 -:1055B0000A0009612648000127BDFFC0AFB00018EE -:1055C0003C108000AFBF0038AFB70034AFB600303A -:1055D000AFB5002CAFB40028AFB30024AFB20020A9 -:1055E0000E00055EAFB1001C920401089205010B8C -:1055F000308400FF0E0008E730A500FF144000D6FD -:105600008FBF00383C09800835280080A100006B5E -:105610003607098090E60000240200503C1708007D -:1056200026F73DF430C300FF3C14080026943E04E6 -:10563000106200033C1080000000B8210000A0218F -:10564000241F001036110A00361309808E1601043B -:105650008F8D00588E38002436190A808E720020F3 -:105660003C010800A03F3BF0972C002C8EF5000079 -:10567000932B0018024D702302D878233C010800B8 -:10568000AC2F3BCC3C010800AC2E3BD03C010800C9 -:10569000AC2D3BF4A78C005C02A0F809317200FF2E -:1056A000304A0002154000DA3045000110A000B475 -:1056B00000000000360509008E2B002490BF001169 -:1056C00090B9001290B6001133EF00FF333800FF9D -:1056D00032CD00FF0018708001CF8021024D602183 -:1056E0000212A821258A00103C010800A4353BE8DD -:1056F0003C010800AC2B3BF83C010800A42A3BE429 -:105700003C010800A4303BE60260B0213C1580005B -:105710008F9200588F8400608ED3002024110006E1 -:1057200000923023027228233C010800AC313BEC8C -:1057300004C000AF0000982104A000AD00C5102BEC -:10574000104000AF000000003C010800AC263BD038 -:105750008E9000000200F8090000000030430002B3 -:105760001460006F004088213046000154C00011D1 -:105770008E9200043C0808008D083BD43C09C00010 -:105780003C04800001093825AEA70E008C8B000078 -:10579000316A00081140FFFD00000000948D0E08E2 -:1057A00024130001A78D00408C8C0E04AF8C0028C0 -:1057B0008E9200040240F8090000000002228825B1 -:1057C000322E000215C000A5000000003C180800A1 -:1057D00097183BDC3C12080096523BE83C19080045 -:1057E00097393BDE3C0708008CE73BD4031240218D -:1057F0003C0B08008D6B3BF83C0E080095CE3BF24D -:105800003C128000011978218E46010C00F86821B5 -:1058100025EC000201AE482101675021AF860068E7 -:105820003C010800AC2A3BF83C010800A4293BE0FD -:105830003C010800A4283BEA0E0001C93184FFFFA7 -:105840000E000550004080213C010800A0223BF1E1 -:105850008E8200080040F809020020218F85005840 -:105860000E0005BF004020218E90000C0200F809B8 -:10587000004020213C03080094633BEA3C020800FE -:1058800094423BDE00622021248500020E0001F2DA -:1058900030A4FFFF3C1908008F393BCC3C1F0800A7 -:1058A0008FFF3BD4033FC0233C010800AC383BCC06 -:1058B00017000006000000003C0508008CA53BEC2A -:1058C00034BF00403C010800AC3F3BEC126000429A -:1058D0008F8200448E430E108F930044AE630020ED -:1058E0008E440E18AE6400243C04080094843BE00F -:1058F0000E000697000000008F8600588E8A001068 -:105900003C010800AC263BF40140F809000000000F -:105910003C0908008D293BCC1520FF7E8F92005852 -:105920009796005C3C14800E323500100E0006C6BF -:10593000A696002C56A000458EEB000432270040AE -:1059400054E0001E8EF100088EEC000C0180F80976 -:10595000000000008FBF00388FB700348FB60030D2 -:105960008FB5002C8FB400288FB300248FB2002095 -:105970008FB1001C8FB0001803E0000827BD004065 -:10598000920901098F88003000093E0000E83025A7 -:10599000AE0600808E2300208E240024AFA30010CA -:1059A000AE030E148FA20010AE020E10AE040E1C39 -:1059B000AE040E180A0009E3360509000220F809B2 -:1059C000000000008EEC000C0180F80900000000CF -:1059D0000A000A8B8FBF0038240800012410000140 -:1059E000A4400020A44800220A000A6FAC50002402 -:1059F0003C010800AC203BD00A000A0A8E9000004F -:105A00003C010800AC253BD00A000A0A8E90000039 -:105A100092110109000028210E000734322400FFF2 -:105A20008FBF00388FB700348FB600308FB5002C91 -:105A30008FB400288FB300248FB200208FB1001CD8 -:105A40008FB0001803E0000827BD00400160F8098E -:105A5000000000000A000A85322700405260FFB1B2 -:105A60009796005C8EB60E148F940044AE9600207C -:105A70008EAF0E1CAE8F00240A000A7E9796005C43 -:105A80008F8200000004218003E0000800821021C2 -:105A90003C07800834E20080904300690080402188 -:105AA000106000093C0401003C0708008CE73BF44F -:105AB0008F83001C00E320230480000893890008E2 -:105AC00014E300030100202103E0000800801021FE -:105AD0003C04010003E00008008010211120000BAD -:105AE000006738233C0D800035AC0980918B007C29 -:105AF000316A0002114000202409003400E9702BB3 -:105B000015C0FFF10100202100E938232403FFFC28 -:105B100000A3C82400E3C02400F9782B15E0FFEAB5 -:105B20000308202130C400030004102314C0001413 -:105B3000304900030000302100A9782101E67021DE -:105B400000EE682B11A0FFE03C0401002D3800019D -:105B50000006C82B010548210319382414E0FFDA98 -:105B60002524FFFC2402FFFC00A218240068202149 -:105B700003E00008008010210A000AF42409003024 -:105B80003C0C80003586098090CB007C316A000493 -:105B90001540FFE9240600040A000B030000302131 -:105BA0003C0308008C63005C8F82000427BDFFE883 -:105BB000AFBF001410620005AFB00010000329C091 -:105BC00024A40280AF840000AF8300043C10800056 -:105BD00036030A00946500320E000AD530A43FFF58 -:105BE0008E0401003C180080370F00030082C8219A -:105BF0002402FF80032260243329007F000CF94037 -:105C000003E94025332E00783C0D1000010D50258E -:105C100001CF5825AE0C002836080980AE0C080CC0 -:105C2000AE0B082CAE0A0830910300693C06800CCC -:105C30000126382110600006AF8700208D09003C46 -:105C40008D06006C0126382318E0007F000000005C -:105C50003C0C8008358B00803C0A8000A160006904 -:105C6000355009808E0200383C06800034C50A0099 -:105C700090AD003C31A8002011000019AF82001C3B -:105C8000240E00013C19800037300A00A38E000862 -:105C9000AF8000108E0400248F85001024180008A7 -:105CA000AF80000CAF8000143C010800A4383BDE3C -:105CB0003C010800A4203BF20E000AD9000030216C -:105CC000920F003C8FBF00148FB00010000F714284 -:105CD000AF82001827BD001803E0000831C20001A0 -:105CE00090B90032240F0001333800FF00182182E0 -:105CF000108F003F241F0002109F006234C20AC0B0 -:105D00003C03800034640A008C9900241720001D95 -:105D10003466090090830030241F00053062003F84 -:105D2000105F004C240500018F86000CA38500083D -:105D3000AF860014AF8600103C19800037300A008F -:105D40008E0400248F850010241800083C010800F0 -:105D5000A4383BDE3C010800A4203BF20E000AD927 -:105D600000000000920F003C8FBF00148FB00010A5 -:105D7000000F7142AF82001827BD001803E0000831 -:105D800031C200018C8800088C8D00248CCB00640B -:105D90003C19800037300A00AF8B0010A380000848 -:105DA0008E0400248F86000C8F850010010D602367 -:105DB00024180008AF8C00143C010800A4383BDE16 -:105DC0003C010800A4203BF20E000AD900000000AC -:105DD000920F003C8FBF00148FB00010000F714273 -:105DE000AF82001827BD001803E0000831C200018F -:105DF00090A7003030E3003F5064002834C50AC04B -:105E00008CAA00241540002234C809008CAB00483D -:105E10003C0C7FFF3585FFFF016510243C18800096 -:105E2000AF82000C370509008F8E000C8CAF00602C -:105E300001CF682B15A0000201C020218CA40060B6 -:105E40000A000B75AF84000C8D02006C0A000B5029 -:105E50003C0680008C8900488F86000C3C0A7FFF3E -:105E60003550FFFF013038243C0480082405000130 -:105E7000AF870014AC80006CA38500080A000B8378 -:105E8000AF8600108C4400140A000B75AF84000C20 -:105E90008D0200680A000BBD3C18800034C40980E4 -:105EA0008C8600708CB0001400D0482B11200004A8 -:105EB000000000008C8200700A000BBD3C188000BE -:105EC0008CA200140A000BBD3C1880008F850010C6 -:105ED00027BDFFE0AFBF0018AFB1001414A0000849 -:105EE000AFB000103C04800034870A0090E6003018 -:105EF0002402000530C3003F106200B7348409005B -:105F00008F91000C00A080213C048000348E0A0098 -:105F10008DCD00043C0608008CC63BD031A73FFF66 -:105F200000E6602B5580000100E03021938F0008CF -:105F300011E0007600D0102B349909809338007C52 -:105F400033040002108000772403003400C3F82BD0 -:105F500017E000D600C3302300D0102B3C0108000E -:105F6000A4233BDC1440006D020018213C0408000F -:105F70008C843BCC0064282B54A0000100602021BD -:105F80003C05800034A90A009128003C3C0108002F -:105F9000AC243BD4310300201460000200004821EF -:105FA0008CA90E188F8800180128502B1140005F13 -:105FB000000000003C0508008CA53BD400A960212E -:105FC000010C582B1160005C00B0682B01093823CC -:105FD00000E028213C010800AC273BD4120000035C -:105FE0002402FFFC10B0008C322A000300A2F82427 -:105FF0003C010800A4203BF23C010800AC3F3BD42C -:1060000003E028218F840010120400063C0380085E -:106010008C6A006C02002021AF91000C2550000119 -:10602000AC70006C8F8B001400858823AF9100103A -:1060300001652023AF8400141220000224070018F9 -:10604000240700103C0E800835C6008090CD006803 -:10605000240C00013C010800A0273BF031A700FF01 -:1060600010EC0047000000001480001800002821F8 -:106070003C0B800091650109357109808E23001861 -:1060800030A500FF0003560224A300013146007F23 -:106090003070007F1206007E240CFF803C0F8008C9 -:1060A00035E90080A123004C3C0808008D083BEC3A -:1060B000240E00023C010800A02E3C31350D0008E2 -:1060C0003C010800AC2D3BEC240500103C1F800077 -:1060D00037E40A009099003C333800201300000593 -:1060E00000A02021240200013C010800AC223BD486 -:1060F00034A400018FBF00188FB100148FB00010BE -:106100000080102103E0000827BD00203C010800AA -:10611000A4203BDC1040FF95020018210A000C105F -:1061200000C018210A000C08240300303C050800B8 -:106130008CA53BD400B0682B11A0FFA80000000084 -:106140003C04080094843BDC0085782101E7702B37 -:1061500011C000072CA200043C1F60008FF95404FA -:106160003338003F1700FFE3240400422CA2000450 -:106170001040FF9A240400420A000C738FBF0018DD -:106180001528FFB9000000008CC200183C188000E0 -:10619000241900020058F825ACDF001837040A0063 -:1061A000A0D900689089003C240F000400A01021B1 -:1061B000312800203C010800A02F3C3111000002D2 -:1061C00024050010240200013C010800AC223BCC55 -:1061D0000A000C693C1F80008F8800148C890060C5 -:1061E0000109282B14A00002010088218C91006075 -:1061F0003C0B80008D640E18240A00010220282127 -:1062000002203021A38A00080E000AD90220802132 -:106210000A000BF7AF820018000A182312200007AB -:10622000306400033C0D800035A7098090EC007CB1 -:10623000318B000415600019248E00043C01080015 -:10624000A4243BF23C18080097183BF203052021D8 -:1062500000C4782B11E0FF6C8F8400102CA6000581 -:1062600014C0FFA42404004230B900031720000228 -:1062700000B9182324A3FFFC3C010800AC233BD445 -:106280003C010800A4203BF20A000C3600602821E3 -:1062900000AC38240A000C5C00EC18263C01080015 -:1062A000A42E3BF20A000CC6000000003C010800CE -:1062B000AC203BD40A000C72240400428F830014EB -:1062C0003C0B8000356A0A001460000600001021B3 -:1062D000914600302405000530C400FF10850003FE -:1062E0000000000003E000080000000091490048A1 -:1062F000312800FF000839C214E0FFFA3C0480088E -:106300003C06080094C63BDC3C0308008C633BF46D -:106310003C0508008CA53BD43C18080097183BF2BC -:106320000066C8218C8E00040325782101F86821BD -:1063300001AE60231980001D000000009158004C40 -:106340008F8D0020956E0E10330F00FF8DA9000475 -:1063500001CF30238DAA000030CFFFFF000F610076 -:10636000012C2821000038210147202100AC182BE6 -:106370000083C821ADA50004ADB9000091B8000AA2 -:1063800001F87021A1AE000A956C0E128F8A0020D0 -:10639000A54C00089549003825280001A54800387B -:1063A0009147000D34EB0008A14B000D03E00008FD -:1063B0000000000027BDFFD8AFB00018938F000881 -:1063C0008FB000143C087FFF8F8700103C0C8000CA -:1063D0003518FFFFAFBF0020AFB1001C35990A0090 -:1063E00002181824932A003C000F5FC03C02BFFF34 -:1063F0002CF000013449FFFF006BF8253C08080031 -:106400008D083BF48F99001C3C18080097183BEA54 -:1064100003E9582400107F803C07EFFF3C05F0FFA4 -:10642000016F18253C1180003149002034E2FFFF44 -:1064300034ADFFFF362E098027A500102406000288 -:1064400001194023270A00020062182400808021DD -:1064500015200002000058218D8B0E1CA7AA0012E7 -:106460000500003A2407000030EF00FF000F3F0056 -:10647000006740253C028008AFA80014344B008020 -:10648000916A00683C0F080091EF3BF13C09DFFF87 -:10649000353FFFFF000A602B3C02080094423BE4BA -:1064A000A3AF0011011FC024000CCF400319182511 -:1064B0008FA70010AFA300143C1F080093FF3BF30D -:1064C000A7A200168FA8001400ED48243C0B010081 -:1064D0003C0A0FFF012BC82533F80003354CFFFFA2 -:1064E000010D78243C027000032C382400181E0093 -:1064F00000E2482501E35825AFAB0014AFA9001016 -:1065000091DF007CA3BF00150E00007200000000A8 -:10651000362D0A0091A6003C30C4002010800006F1 -:10652000260200083C11080096313BE0262EFFFFB2 -:106530003C010800A42E3BE08FBF00208FB1001C5F -:106540008FB0001803E0000827BD00288F8A0018CC -:10655000016A602B5580FFC4240700010A000D501A -:1065600030EF00FF938300083C02800027BDFFD876 -:1065700034480A0000805021AFBF002034460AC0D2 -:10658000010028211060000E34440980910700307A -:10659000240B00058F89000C30EC003F118B000BA1 -:1065A00000003821AFA900103C0B80088D69006CF9 -:1065B000AFAA00180E00013AAFA90014A38000088A -:1065C0008FBF002003E0000827BD00288D1F004872 -:1065D0003C1808008F183BD48F9900143C027FFFB1 -:1065E0008D0800443443FFFFAFA900103C0B800826 -:1065F0008D69006C03E370240319782101CF6823AF -:1066000001A83821AFAA00180E00013AAFA9001462 -:106610000A000DA5A38000083C05800034A60A00EE -:1066200090C7003C3C06080094C63BF23C020800C0 -:106630008C423BEC30E30020000624001060003167 -:10664000004448253C0880083505008090A3006878 -:1066500000006821240C000100005021240B0001DF -:106660003C188000370F00708DE800003C07800068 -:10667000AF8800248CF901780720FFFE34E5007014 -:106680008CA200003C0308008C6300743C0F0800DF -:106690008DEF007000482023006428210000C021F5 -:1066A00000A4302B01F8702101C640213C010800F4 -:1066B000AC2500743C010800AC280070ACEC01482B -:1066C0003C0208008C423BF4A4EA0144A4EB0146DE -:1066D000ACE2014C3C04080090843BF13C03800890 -:1066E000A0E40152ACE90154A4ED0158346D0080DE -:1066F00091AC004C3C091000A0EC016D03E00008D7 -:10670000ACE901788CAC0E1C3C0B08008D6B3BD4C3 -:1067100094AA0E1694AE0E1401666821314BFFFF49 -:106720000A000DCD31CAFFFF3C04800034830A000B -:106730009065003C30A200201040002B00000000BB -:106740000000582100005021000048213C08800032 -:10675000350400708C8800003C078000AF8800245E -:106760008CEC01780580FFFE34EE00708DCD0000CA -:106770003C0508008CA500743C0408008C84007063 -:1067800001A8602300ACC02100001021030C302BB5 -:106790000082C821032678213C010800AC3800742F -:1067A0003C010800AC2F0070ACEB01483C0E080027 -:1067B0008DCE3BF4240DFF91240B0040A4E901444D -:1067C000A4EA0146ACEE014CA0ED0152ACEB015441 -:1067D000A4E0015890EA01093C091000A0EA016D0B -:1067E00003E00008ACE901788C8B0E1894870E1238 -:1067F00094860E1030EAFFFF0A000E0830C9FFFF32 -:106800003C04800034830A009065003C30A20020E4 -:106810001040003927BDFFF8240C00010000502172 -:10682000240B00013C088000350400708C890000B6 -:106830003C088000AF8900248D0D017805A0FFFE83 -:10684000350E00708DC700003C0508008CA5007453 -:106850003C0408008C84007000E9682300ADC0216E -:1068600000001021030D302B0082C821032678215F -:106870003C010800AC3800743C010800AC2F0070EB -:10688000910901093C0E080091CE3C313C0380FF88 -:10689000A3A900038FAD000031C7007F3462FFFF62 -:1068A00001A82025AFA400009106010AA3A00002C0 -:1068B0000007CE00A3A600018FA50000240E300023 -:1068C0003C09100000A2C02403197825AD0F014C2B -:1068D00027BD0008AD0E0154A5000158AD0C0148BC -:1068E000A50A0144240AFF80A50B0146A10A015212 -:1068F00003E00008AD0901788C8C0E1894870E1205 -:1069000094860E1030EBFFFF0A000E3E30CAFFFFE8 -:1069100027BDFFE8AFB000103C108000AFBF0014EF -:1069200036180A00970F00320E000AD531E43FFFF7 -:106930008E0E0100240DFF803C04200001C258216E -:10694000016D6024000C4940316A007F012A402516 -:10695000010438253C048008AE07083034860080E6 -:1069600090C500682403000230A200FF1043000419 -:106970008F9F000C8F990010AC9F0068AC99006449 -:106980008FBF00148FB0001003E0000827BD00186F -:106990003C0A0800254A37FC3C090800252938D460 -:1069A0003C08080025082C743C07080024E739E45B -:1069B0003C06080024C636383C05080024A5339060 -:1069C0003C04080024842FA03C030800246336EC18 -:1069D0003C020800244234883C010800AC2A3DFCFB -:1069E0003C010800AC293DF83C010800AC283DF40E -:1069F0003C010800AC273E003C010800AC263E10DC -:106A00003C010800AC253E083C010800AC243E04D3 -:106A10003C010800AC233E143C010800AC223E0CB3 -:086A200003E000080000000083 -:086A2800800009408000090014 -:106A3000800801008008008080080000800E0000AF -:106A4000800800808008000080000A8080000A0022 -:086A50008000098080000900AC -:00000001FF -/* - * This file contains firmware data derived from proprietary unpublished - * source code, Copyright (c) 2004 - 2009 Broadcom Corporation. - * - * Permission is hereby granted for the distribution of this firmware data - * in hexadecimal or equivalent format, provided this copyright notice is - * accompanying it. - */ diff --git a/firmware/bnx2/bnx2-mips-09-5.0.0.j3.fw.ihex b/firmware/bnx2/bnx2-mips-09-5.0.0.j3.fw.ihex new file mode 100644 index 0000000..92e2204 --- /dev/null +++ b/firmware/bnx2/bnx2-mips-09-5.0.0.j3.fw.ihex @@ -0,0 +1,6051 @@ +:100000000800011008000000000051C4000000C8F2 +:10001000000000000000000000000000080051C4C3 +:10002000000000380000528C080000880800000022 +:10003000000051B4000052C4080053A00000008426 +:100040000000A478080051B4000001C00000A4FC26 +:10005000080031D808000000000080E40000A6BCC1 +:10006000000000000000000000000000080080E424 +:1000700000000124000127A00800048808000400F3 +:10008000000017EC000128C4000000000000000080 +:100090000000000008001BEC00000004000140B05C +:1000A000080000A80800000000003814000140B457 +:1000B00000000000000000000000000008003814EC +:0800C00000000030000178C8C7 +:0800C8000A00004400000000E2 +:1000D000000000000000000D636F6D352E302E30E3 +:1000E0006A33000005000002000000000000000369 +:1000F00000000014000000320000000300000000B7 +:1001000000000000000000000000000000000000EF +:1001100000000010000001360000EA600000000549 +:1001200000000000000000000000000000000008C7 +:1001300000000000000000000000000000000000BF +:1001400000000000000000000000000000000000AF +:10015000000000000000000000000000000000009F +:10016000000000020000000000000000000000008D +:10017000000000000000000000000000000000007F +:10018000000000000000000000000010000000005F +:10019000000000000000000000000000000000005F +:1001A000000000000000000000000000000000004F +:1001B000000000000000000000000000000000003F +:1001C000000000000000000000000000000000002F +:1001D000000000000000000000000000100000030C +:1001E000000000000000000D0000000D3C020800AF +:1001F000244252203C03080024635354AC400000C6 +:100200000043202B1480FFFD244200043C1D080005 +:1002100037BD9FFC03A0F0213C1008002610011000 +:100220003C1C0800279C52200E00025F00000000CA +:100230000000000D27BDFFE0AFBF0018AFB10014F4 +:10024000AFB000103C04800094820108304370007D +:10025000240220001062000B2862200114400036A6 +:1002600000001021240240001062002C0000000059 +:10027000240260001062002D000010210A00009D81 +:100280008FBF001834910100922400098E300018AD +:1002900010800020240300012402000914820006BB +:1002A0008F82001C3C0280089442001A0002140055 +:1002B000020280258F82001C8C42000C1040001529 +:1002C000000018210E000D45000000008F83001C67 +:1002D000962400088F8200189463001E9625000C57 +:1002E0000004240000832025AC500000AC4500042D +:1002F000AC400008AC40000CAC400010AC40001416 +:10030000AC400018AC44001C0E000D792404000120 +:10031000000018210A00009C006010210E00042E2D +:10032000000000000A00009C000010210E000C6577 +:1003300000000000000010218FBF00188FB10014D2 +:100340008FB0001003E0000827BD00208F82001C42 +:1003500027BDFFE0AFB00010AFBF0018AFB1001471 +:100360008C42000C3C1080008E11010010400034C3 +:100370008FBF00180E000D45000000008F8500188B +:1003800024047FFF0091202BACB100008E030104F8 +:100390009602010800031C003042FFFF006218258E +:1003A000ACA300049202010A96030114304200FF3C +:1003B0003063FFFF0002140000431025ACA20008C8 +:1003C0009603010C9602010E00031C003042FFFF51 +:1003D00000621825ACA3000C9603011096020112CE +:1003E00000031C003042FFFF00621825ACA3001080 +:1003F0008E020118ACA200148E02011CACA20018DF +:10040000148000088F82001C978200003C042005A5 +:100410000044182524420001ACA3001C0A0000DBA4 +:10042000A78200003C0340189442001E00431025A0 +:10043000ACA2001C0E000D79240400018FBF00182F +:100440008FB100148FB000100000102103E00008ED +:1004500027BD00203C0680008CC202B824030001A6 +:1004600004410008008028213C0208008C42006002 +:10047000244200013C010800AC22006003E00008B7 +:10048000006010218C83002094820016ACC302808F +:100490002442FFFCA4C202843C0208008C42005C9F +:1004A0008C84000494A3000E244200013C01080047 +:1004B000AC22005C3C021000A4C30286ACC40288DB +:1004C00000001821ACC202B803E00008006010214F +:1004D00027BDFFE0AFB000103C108000AFB20018A5 +:1004E000AFBF001CAFB10014361201009243000BE5 +:1004F0002402001A965100081462005A00002821B4 +:1005000032220001104000188F82001C8E42000031 +:10051000000223403C02003F3442FFFF0044102B06 +:10052000104000043C030040964200140A000124DD +:10053000008320218E030100240201005462000682 +:10054000964200143C028008904200043042000FA2 +:10055000000225009642001400821025AE020080A1 +:100560000A000157000000008C42000C10400028D7 +:10057000000000000E000D4500000000960201087A +:100580009603010C8F8500183042003E3063FFFF58 +:100590000002140000431025ACA200008E020100EE +:1005A000ACA20004960301169604010E8F82001C73 +:1005B00000031C003084FFFF00641825ACA3000872 +:1005C00096030110960401129446001E00031C00BD +:1005D0003084FFFF00641825ACA3000C3C0220000F +:1005E00000C2302596020114240400013042FFFFAE +:1005F000ACA200108E020118ACA200149202010BF2 +:10060000304200FFACA200180E000D79ACA6001C11 +:100610003C0208008C420040244200013C010800DA +:10062000AC2200403C0308008C63004432220002EC +:1006300032240004246300013C010800AC23004480 +:10064000108000080002282B024020218FBF001CD0 +:100650008FB200188FB100148FB000100A0000E3B1 +:1006600027BD00208FBF001C8FB200188FB100146F +:100670008FB0001000A0102103E0000827BD00206B +:1006800027BDFFE0AFB000103C108000AFB20018F3 +:10069000AFBF001CAFB10014361201009243000B33 +:1006A000240200031462006A9651000832220001FD +:1006B000104000178F82001C8E4300003C02003F58 +:1006C0003442FFFF000323400044102B504000053C +:1006D00024020100964200143C0300400A00018EEF +:1006E0000083202154620006964200143C028008D8 +:1006F000904200043042000F000225009642001490 +:1007000000821025AE0200800A0001BE0000000039 +:100710008C42000C10400025000000000E000D452A +:1007200000000000960201089603010C8F85001856 +:100730003042003E3063FFFF0002140000431025EA +:10074000ACA200008E020100ACA2000496030116C8 +:100750009604010E8F82001C00031C003084FFFFF2 +:1007600000641825ACA3000896030110960401123A +:100770009446001E00031C003084FFFF006418250F +:10078000ACA3000C3C02200000C2302596020114EC +:10079000240400013042FFFFACA20010ACA0001402 +:1007A000ACA000180E000D79ACA6001C3C0208009D +:1007B0008C420040244200013C010800AC22004071 +:1007C0003C0208008C420044322300042442000111 +:1007D0003C010800AC2200441060000832220002F4 +:1007E000024020218FBF001C8FB200188FB100146F +:1007F0008FB000100A0000E327BD00201040001554 +:100800008FBF001C3C0480008C8301043C026020EC +:10081000AC4300148C420004240301FE304203FF69 +:100820001443000C8FBF001C8C820100000219C20F +:100830002462FFFC2C420008104000032404000244 +:100840002462FFFD004420043C026000AC446914B3 +:100850008FBF001C8FB200188FB100148FB0001032 +:100860000000102103E0000827BD00203C048000A8 +:100870008C83010024020100506200033C028008C6 +:100880000000000D3C02800890430004000010218D +:100890003063000F00031D0003E00008AC830080FC +:1008A0002C8407811080000A000028213C0280006F +:1008B00094420108240320003042700014430005D4 +:1008C0002783FFB03C02800890420005304500FFBE +:1008D0002783FFB00005208000832021000510C081 +:1008E000004510238C8400003C030800246352E47C +:1008F000000210C0004310213C038000AC64009053 +:1009000003E00008AF82001C03E000080000102193 +:1009100003E00008000010212402010014820008F6 +:10092000000000003C0208008C4200FC2442000150 +:100930003C010800AC2200FC0A00022430A2002086 +:100940003C0208008C420084244200013C01080063 +:10095000AC22008430A200201040000830A3001018 +:100960003C0208008C420108244200013C010800BE +:10097000AC22010803E0000800000000106000083D +:10098000000000003C0208008C42010424420001E7 +:100990003C010800AC22010403E000080000000054 +:1009A0003C0208008C420100244200013C01080086 +:1009B000AC22010003E000080000000027BDFFE8B2 +:1009C000AFB000103C108000AFBF0014360401002F +:1009D0009483000830620004104000053066000275 +:1009E0008FBF00148FB000100A0000E327BD00186D +:1009F00010C00006006028218E0401000E000214C1 +:100A0000000000000A00025B240200018F8200083F +:100A10008E03010410430007000010218E04010022 +:100A20000E000214000000008E020104AF820008D4 +:100A3000000010218FBF00148FB0001003E00008E9 +:100A400027BD001827BDFFD83C036010AFB3001CC2 +:100A5000AFBF0020AFB20018AFB10014AFB00010AC +:100A60008C6450002402FF7F3C1308002673524818 +:100A7000008220243484380CAC6450003C02800096 +:100A800024030037AC4300083C06080024C6084095 +:100A9000026010212404001C2484FFFFAC460000E7 +:100AA0000481FFFD244200043C0208002442016C42 +:100AB0003C010800AC2252503C020800244205B818 +:100AC0003C010800AC2252543C020800244202843B +:100AD0003C010800AC2252903C0208002442040869 +:100AE0003C030800246308483C040800248408F4FC +:100AF0003C05080024A52C4C3C010800AC2252B057 +:100B00003C020800244207A43C010800AC2652988D +:100B10003C010800AC2552A43C010800AC2352ACB7 +:100B20003C010800AC2452B43C010800AC2252B88D +:100B30003C010800AC23524C3C010800AC20525848 +:100B40003C010800AC20525C3C010800AC20526023 +:100B50003C010800AC2052643C010800AC20526803 +:100B60003C010800AC20526C3C010800AC205270E3 +:100B70003C010800AC2452743C010800AC205278BF +:100B80003C010800AC20527C3C010800AC205280A3 +:100B90003C010800AC2052843C010800AC20528883 +:100BA0003C010800AC26528C3C010800AC26529453 +:100BB0003C010800AC20529C3C010800AC2552A02E +:100BC0003C010800AC2352A80E00055A00000000AA +:100BD0008F8300043C0208008C4200201062001F3A +:100BE000000088212792FFB03C100800261052E434 +:100BF0003C0208008C420020240500010225180454 +:100C0000004320248F820004004310245044000C31 +:100C10002631000110800008AF90001C8E430000B8 +:100C20003C028000AC4300900E000D0CAE05000CA1 +:100C30000A0002DE26310001AE00000C2631000160 +:100C40002E220002261000381440FFE9265200042C +:100C50003C0208008C420020AF8200043C1080005F +:100C60008E110000322200071040FFDA8F8300044B +:100C70003222000110400021322200028E020100C7 +:100C8000AE0200208E020104AE0200A80E0001F6A2 +:100C90008E0401009202010B304300FF2C62001D04 +:100CA00054400004000310800E0002100A0002FFEE +:100CB00000000000005310218C4200000040F809A1 +:100CC00000000000104000043C0280008C4301043E +:100CD0003C026020AC4300143C0208008C4200340B +:100CE0003C0440003C03800024420001AC64013815 +:100CF0003C010800AC2200343222000210400010F7 +:100D0000322200043C1080008E020140AE0200201E +:100D10000E0001F68E0401400E0003970000000053 +:100D20003C024000AE0201783C0208008C420038D0 +:100D3000244200013C010800AC22003832220004A9 +:100D40001040FFA48F8300043C1080008E020180BD +:100D5000AE0200200E0001F68E0401808E03018099 +:100D600024020F00146200073C0280088E020188F2 +:100D70003C0300E03042FFFF004310250A00033B24 +:100D8000AE020080344200809042000024030050F4 +:100D9000304200FF14430007000000000E000374FF +:100DA0000000000014400003000000000E00095D78 +:100DB000000000003C0208008C42003C3C04400063 +:100DC0003C03800024420001AC6401B83C010800EF +:100DD000AC22003C0A0002C38F8300043C02900056 +:100DE00034420001008220253C028000AC440020F7 +:100DF0003C0380008C6200200440FFFE00000000E5 +:100E000003E00008000000003C02800034430001C1 +:100E10000083202503E00008AC44002027BDFFE04C +:100E2000AFB10014AFB0001000808821AFBF001830 +:100E30000E00034530B000FF8F83FFA80220202161 +:100E40009062002502028025A07000258C70001899 +:100E50003C0280000E000350020280241600000AAB +:100E60008FBF00183C0380008C6201F80440FFFE35 +:100E700024020002AC7101C0A06201C43C02100057 +:100E8000AC6201F88FBF00188FB100148FB0001052 +:100E900003E0000827BD002027BDFFE8AFBF00101A +:100EA0003C0380009462018430420200104000053F +:100EB000000020210E000FCD000000000A00038A70 +:100EC000240400018C6201880440000A8FBF0010D6 +:100ED0008C6201883C03FF00004310243C030400A3 +:100EE00014430004240400018F82FFA890420008EC +:100EF0008FBF00100080102103E0000827BD0018FC +:100F00008F82FFAC2403000124050001A040001AD9 +:100F10008F82FFA8A44300163C0280000A000355FC +:100F20008C4401408F85FFA827BDFFE0AFBF001CA8 +:100F3000AFB20018AFB10014AFB0001090A2000023 +:100F4000304400FF38830020388200300003182B23 +:100F50000002102B00621824106000053C02800083 +:100F600024020050148200818FBF001C3C028000CC +:100F700090420148304200FF2443FFFF2C620005ED +:100F80001040007A8FBF001C000310803C03080053 +:100F9000246351DC004310218C4200000040000813 +:100FA000000000003C1180008E2401400E0003452B +:100FB0008F92FFA88E50000C8E2201441602000270 +:100FC00024020001AE42000C0E0003508E240140AA +:100FD0008E220144145000068FBF001C8FB20018EF +:100FE0008FB100148FB000100A000F3927BD002008 +:100FF0008E42000C0A0004220000000094A200109F +:101000003C0480008C8301443042FFFF14620009DD +:101010000000000024020001A4A200108C82014004 +:10102000AC8202003C021000AC8202380A000429A3 +:101030008FBF001C94A200100A00042200000000D0 +:10104000240200201482000E3C11800094A20012A1 +:101050003C0380008C6301443042FFFF14620005B2 +:101060000000000024020001A4A200120A0003FCF8 +:101070008FBF001C94A200120A000422000000008E +:101080008E2401400E0003458F92FFA89642001265 +:101090008E2301443050FFFF16030002240200019A +:1010A000A64200120E0003508E2401408E220144FD +:1010B000160200068FBF001C8FB200188FB10014FB +:1010C0008FB000100A00038E27BD00209642001248 +:1010D0000A0004220000000094A200143C038000D7 +:1010E0008C6301443042FFFF146200088FBF001C74 +:1010F000240200018FB200188FB100148FB00010CD +:10110000A4A200140A00142427BD002094A20014F5 +:101110000A0004220000000094A200163C03800094 +:101120008C6301443042FFFF146200082402000176 +:101130008FBF001C8FB200188FB100148FB0001049 +:10114000A4A200160A000B0027BD002094A20016DE +:10115000144000068FBF001C3C0208008C42007047 +:10116000244200013C010800AC2200708FB200183C +:101170008FB100148FB0001003E0000827BD0020DD +:1011800027BDFFD8AFB200188F92FFA8AFB10014EF +:10119000AFBF0020AFB3001CAFB000103C02800016 +:1011A000345101008C50010092420000922300094A +:1011B000304400FF2402001F106200AB28620020B0 +:1011C00010400019240200382862000A1040000D67 +:1011D0002402000B286200081040002E8F82001CA1 +:1011E00004600103286200021440002A8F82001C60 +:1011F00024020006106200268FBF00200A00054C62 +:101200008FB3001C106200602862000B144000F9CC +:101210008FBF00202402000E106200788F82001C15 +:101220000A00054C8FB3001C106200D128620039FF +:101230001040000A2402008024020036106200E4FC +:1012400028620037104000C224020035106200D826 +:101250008FBF00200A00054C8FB3001C1062002DC8 +:101260002862008110400006240200C824020039D0 +:10127000106200C88FBF00200A00054C8FB3001C0D +:10128000106200A28FBF00200A00054C8FB3001C23 +:101290008F82001C8C42000C104000D68FBF0020B3 +:1012A0000E000D45000000003C0380003463010087 +:1012B0008C6200008F850018946700089466000C0B +:1012C000ACA200008C6400048F82001C0006340075 +:1012D000ACA400049448001E8C62001800073C0077 +:1012E00000E83825ACA200088C62001C2404000130 +:1012F000ACA2000C9062000A00C23025ACA600101F +:10130000ACA00014ACA00018ACA7001C0A00050B90 +:101310008FBF00208F82001C8C42000C104000B553 +:101320008FBF00200E000D45000000008F82001CC2 +:10133000962400089625000C9443001E0004220207 +:101340009626000E8F8200180004260000832025B8 +:1013500000052C003C03008000A6282500832025E2 +:10136000AC400000AC400004AC400008AC40000CB5 +:10137000AC450010AC400014AC400018AC44001C5C +:101380000A00050A240400019622000C14400018EB +:10139000000000009242000530420010144000148A +:1013A000000000000E0003450200202192420005CB +:1013B00002002021344200100E000350A24200051A +:1013C0009242000024030020304200FF10430088B6 +:1013D000020020218FBF00208FB3001C8FB20018A5 +:1013E0008FB100148FB000100A00103627BD0028FE +:1013F0000000000D0A00054B8FBF00208C42000C3E +:101400001040007C8FBF00200E000D450000000042 +:101410008E2200048F8400189623000CAC820000FA +:101420003C0280089445002C8F82001C00031C00A5 +:1014300030A5FFFF9446001E3C02400E00651825B3 +:1014400000C23025AC830004AC800008AC80000CE6 +:10145000AC800010AC800014AC800018AC86001C7E +:101460000A00050A240400010E00034502002021A1 +:101470008F93FFAC020020210E000350A660000CE9 +:10148000020020210E000355240500018F82001C5C +:101490008C42000C104000578FBF00200E000D45FD +:1014A000000000009622000C8F8300180002140038 +:1014B000AC700000AC620004AC6000088E440038E0 +:1014C0008F82001CAC64000C8E46003C9445001ECC +:1014D0003C02401FAC66001000A228258E6200046A +:1014E00024040001AC620014AC600018AC65001C60 +:1014F0008FBF00208FB3001C8FB200188FB1001473 +:101500008FB000100A000D7927BD002824020020AA +:10151000108200398FB3001C0E000F1F0000000066 +:10152000104000348FBF00203C0380008C6201F823 +:101530000440FFFE24020002AC7001C0A06201C49E +:101540003C021000AC6201F80A00054B8FBF00207E +:10155000020020218FBF00208FB3001C8FB2001823 +:101560008FB100148FB000100A000E6827BD00284C +:101570009625000C020020218FBF00208FB3001C95 +:101580008FB200188FB100148FB000100A000E8DBA +:1015900027BD0028020020218FB3001C8FB2001845 +:1015A0008FB100148FB000100A000EB827BD0028BC +:1015B0009225000D020020218FB3001C8FB200186D +:1015C0008FB100148FB000100A000F0927BD00284A +:1015D000020020218FBF00208FB3001C8FB20018A3 +:1015E0008FB100148FB000100A000EE027BD002854 +:1015F0008FBF00208FB3001C8FB200188FB1001472 +:101600008FB0001003E0000827BD00283C038000D5 +:101610008C6202780440FFFE24020002AC640240A7 +:10162000A06202443C02100003E00008AC620278B1 +:10163000A380001003E00008A38000113C03800099 +:101640008C6202780440FFFE8F820014AC6202407C +:1016500024020002A06202443C02100003E00008E1 +:10166000AC6202783C02600003E000088C42540443 +:101670009083003024020005008040213063003F49 +:101680000000482114620005000050219082004CA7 +:101690009483004E304900FF306AFFFFAD00000C1C +:1016A000AD000010AD000024950200148D05001C53 +:1016B0008D0400183042FFFF004910230002110082 +:1016C000000237C3004038210086202300A2102BDF +:1016D0000082202300A72823AD05001CAD040018BC +:1016E000A5090014A5090020A50A001603E00008BA +:1016F000A50A002203E000080000000027BDFFD873 +:10170000AFB200183C128008AFB40020AFB3001C89 +:10171000AFB10014AFBF0024AFB0001036510100CC +:101720003C0260008C4254049222000C3C140800DD +:10173000929400F7304300FF24020001106200324F +:101740000080982124020002146200353650008087 +:101750000E0013FE000000009202004C2403FF80E4 +:101760003C0480003042007F000211C0244202404D +:101770000262102100431824AC83009492450008B3 +:101780009204004C3042007F3C0380061485000721 +:10179000004380212402FFFFA22200112402FFFF48 +:1017A000A62200120A0005BE2402FFFF96020020B6 +:1017B000A222001196020022A62200128E0200240C +:1017C0003C048008AE2200143485008090A2004CB6 +:1017D00034830100A06200108CA2003CAC620018AF +:1017E0008C820068AC6200E48C820064AC6200E031 +:1017F0008C82006CAC6200E824020001A0A20068A8 +:101800000A0005DA3C0480080E00141700000000EE +:1018100036420080A04000680A0005DA3C048008D7 +:10182000A2000068A20000690A0006153C028008B8 +:10183000348300808C62003834850100AC62006C17 +:1018400024020001A062006990A200C590830008F4 +:10185000305100FF3072007F12320019001111C0A8 +:1018600024420240026210212403FF800043182416 +:101870003C048000AC8300943042007F3C0380062F +:10188000004380218E02000C1040000D0200202138 +:101890000E00056A0000000026220001305100FF02 +:1018A0009203003C023410260002102B0002102389 +:1018B0003063007F022288240A0005E4A203003C72 +:1018C0003C088008350401008C8200D03507008078 +:1018D000ACE2003C8C8200D0AD02000090E5004CF0 +:1018E000908600C590E3004C908400C52402FF80E0 +:1018F00000A228243063007F308400FF00A6282542 +:101900000064182A1060000230A500FF38A500808E +:10191000A0E5004CA10500093C0280089043000EA0 +:10192000344400803C058000A043000A8C830018EA +:101930003C027FFF3442FFFF00621824AC83001892 +:101940008CA201F80440FFFE00000000ACB301C00F +:101950008FBF00248FB400208FB3001C8FB20018FB +:101960008FB100148FB0001024020002A0A201C4A5 +:1019700027BD00283C02100003E00008ACA201F8DB +:1019800090A2000024420001A0A200003C03080035 +:101990008C6300F4304200FF1443000200803021C9 +:1019A000A0A0000090A200008F840014000211C0CB +:1019B0002442024024830040008220212402FF8030 +:1019C000008220243063007F3C02800A00621821DC +:1019D0003C028000AC44002403E00008ACC30000DB +:1019E00094820006908300058C85000C8C86001084 +:1019F0008C8700188C88001C8C8400203C01080017 +:101A0000A42252C63C010800A02352C53C01080094 +:101A1000AC2552CC3C010800AC2652D03C01080059 +:101A2000AC2752D83C010800AC2852DC3C0108002D +:101A3000AC2452E003E00008000000003C028008F3 +:101A4000344201008C4400343C03800034650400BF +:101A5000AC6400388C420038AF850020AC62003C9A +:101A60003C020005AC6200300000000000000000F5 +:101A700003E00008000000003C020006308400FF84 +:101A8000008220253C028000AC44003000000000B1 +:101A900000000000000000003C0380008C62000099 +:101AA000304200101040FFFD3462040003E00008E3 +:101AB000AF82002094C200003C080800950800CACC +:101AC00030E7FFFF0080482101021021A4C200007E +:101AD00094C200003042FFFF00E2102B544000018E +:101AE000A4C7000094A200003C0308008C6300CC53 +:101AF00024420001A4A2000094A200003042FFFF93 +:101B0000144300073C0280080107102BA4A000002A +:101B10005440000101003821A4C700003C028008A5 +:101B2000344601008CC3002894A200003C048000CD +:101B30003042FFFE000210C000621021AC82003C67 +:101B40008C82003C00621823186000040000000032 +:101B50008CC200240A0006A6244200018CC2002484 +:101B6000AC8200383C020050344200103C0380003C +:101B7000AC62003000000000000000000000000027 +:101B80008C620000304200201040FFFD0000000089 +:101B900094A200003C04800030420001000210C00A +:101BA000004410218C430400AD2300008C42040447 +:101BB000AD2200043C02002003E00008AC820030AB +:101BC00027BDFFE0AFB20018AFB10014AFB00010F6 +:101BD000AFBF001C94C2000000C080213C1208006E +:101BE000965200C624420001A6020000960300009F +:101BF00094E2000000E03021144300058FB1003072 +:101C00000E00067B024038210A0006DD00000000BD +:101C10008C8300048C82000424420040046100078D +:101C2000AC8200048C820004044000040000000028 +:101C30008C82000024420001AC8200009602000069 +:101C40003042FFFF50520001A60000009622000023 +:101C500024420001A62200003C0280083442010018 +:101C6000962300009442003C144300048FBF001CE4 +:101C700024020001A62200008FBF001C8FB20018B2 +:101C80008FB100148FB0001003E0000827BD0020C2 +:101C900027BDFFE03C028008AFBF001834420100BE +:101CA0008C4800343C03800034690400AC68003880 +:101CB0008C42003830E700FFAF890020AC62003C66 +:101CC0003C020005AC620030000000000000000093 +:101CD0000000000000000000000000000000000004 +:101CE0008C82000C8C82000C9783000EAD220000C9 +:101CF0008C82001000604021AD2200048C8200180C +:101D0000AD2200088C82001CAD22000C8CA20014B5 +:101D1000AD2200108C820020AD22001490820005BC +:101D2000304200FF00021200AD2200188CA2001801 +:101D3000AD22001C8CA2000CAD2200208CA2001051 +:101D4000AD2200248CA2001CAD2200288CA2002011 +:101D5000AD22002C3402FFFFAD260030AD20003450 +:101D6000506200013408FFFFAD28003850E0001138 +:101D70003C0280083C0480083484010094820050B6 +:101D80003042FFFFAD22003C948300449485004420 +:101D9000240200013063FFFF000318C20064182111 +:101DA0009064005430A5000700A210040A00074800 +:101DB0000044102534420100AD20003C944300440F +:101DC000944400443063FFFF000318C200621821EE +:101DD0003084000790650054240200010082100442 +:101DE0000002102700451024A062005400000000EB +:101DF00000000000000000003C02000634420040E9 +:101E00003C038000AC6200300000000000000000D5 +:101E1000000000008C620000304200101040FFFD06 +:101E20003C06800834C201503463040034C7014AC0 +:101E300034C4013434C5014034C60144AFA200109B +:101E40000E0006BEAF8300208FBF001803E000081D +:101E500027BD00208F83000C3C0608008CC600E8DC +:101E60008F82001430633FFF000319800046102169 +:101E7000004310212403FF80004318243C06800007 +:101E8000ACC300283042007F3C03800C004330216B +:101E900090C2000D30A500FF000038213442001030 +:101EA000A0C2000D8F89000C3C0280083442010062 +:101EB00094430044000913823048000324020001C7 +:101EC000A4C3000E1102000B2902000210400005FD +:101ED000240200021100000C240300010A000790F4 +:101EE0000000182111020006000000000A000790FF +:101EF000000018218CC2002C0A0007902443000126 +:101F00008CC20014244300018CC200180043102B23 +:101F10005040000A240700012402002714A20003F5 +:101F20003C0380080A00079D240700013463010078 +:101F30009462004C24420001A462004C0009138208 +:101F4000304300032C620002104000090080282169 +:101F5000146000040000000094C200340A0007ADC1 +:101F60003046FFFF8CC600380A0007AD00802821EC +:101F7000000030213C040800248452C00A0006F20C +:101F80000000000027BDFF90AFB60068AFB5006449 +:101F9000AFB40060AFB3005CAFB20058AFB1005453 +:101FA000AFBF006CAFB000508C9000000080B0213B +:101FB0003C0208008C4200E8960400328F83001433 +:101FC0002414FF8030843FFF006218210004218028 +:101FD00000641821007410243C13800000A090219C +:101FE00090A50000AE620028920400323C02800CF2 +:101FF0003063007F00628821308400C024020040EA +:10200000148200320000A8218E3500388E2200187C +:102010001440000224020001AE2200189202003C8B +:10202000304200201440000E8F830014000511C0C0 +:102030002442024000621821306400783C02008093 +:102040000082202500741824AE630800AE640810D6 +:102050008E2200188E03000800431021AE220018C3 +:102060008E22002C8E230018244200010062182BBF +:102070001060004300000000924200002442000172 +:10208000A24200003C0308008C6300F4304200FFD1 +:1020900050430001A2400000924200008F840014CF +:1020A000000211C024420240248300403063007FBC +:1020B000008220213C02800A009420240062182122 +:1020C000AE6400240A0008BEAEC3000092030032D2 +:1020D0002402FFC000431024304200FF14400005DA +:1020E00024020001AE220018962200340A00082EB5 +:1020F0003055FFFF8E22001424420001AE2200184A +:102100009202003000021600000216030441001C77 +:10211000000000009602003227A400100080282151 +:10212000A7A2001696020032000030212407000109 +:102130003042FFFFAF82000C0E0006F2AFA0001C81 +:10214000960200328F8300143C0408008C8400E85F +:1021500030423FFF00021180006418210062182104 +:1021600000741024AE62002C3063007F3C02800EAD +:10217000006218219062000D3042007FA062000DC5 +:102180009222000D30420010504000789242000030 +:102190003C028008344401009482004C8EC300004D +:1021A0003C130800967300C62442FFFFA482004C33 +:1021B000946200329623000E3054FFFF3070FFFF10 +:1021C0003C0308008C6300D000701807A7A30038F8 +:1021D0009482003E3063FFFF3042FFFF146200072D +:1021E000000000008C8200303C038000244200305C +:1021F000AC62003C0A0008568C82002C948200409D +:102200003042FFFF5462000927A400408C8200384E +:102210003C03800024420030AC62003C8C820034DD +:10222000AC6200380A0008653C03800027A500382E +:1022300027A60048026038210E00067BA7A00048B0 +:102240008FA300403C02800024630030AC43003880 +:102250008FA30044AC43003C3C0380003C020005DB +:10226000AC6200303C028008344401009482004299 +:10227000346304003042FFFF0202102B14400007B9 +:10228000AF8300209482004E94830042020210210A +:10229000004310230A00087B3043FFFF9483004E65 +:1022A0009482004202631821005010230062182318 +:1022B0003063FFFF3C028008344401009482003CFC +:1022C0003042FFFF14430003000000000A00088BA7 +:1022D000240300019482003C3042FFFF0062102B77 +:1022E000144000058F8200209482003C006210237D +:1022F0003043FFFF8F820020AC550000AC4000044B +:10230000AC540008AC43000C3C0200063442001000 +:102310003C038000AC6200300000000000000000C0 +:10232000000000008C620000304200101040FFFDF1 +:102330003C04800834840100001018C20064182195 +:102340009065005432020007240600010046100484 +:1023500000451025A0620054948300429622000E8E +:1023600050430001A3860010924200002442000165 +:10237000A24200003C0308008C6300F4304200FFDE +:1023800050430001A2400000924200008F840014DC +:10239000000211C024420240248300400082202118 +:1023A0002402FF80008220243063007F3C02800AE8 +:1023B000006218213C028000AC440024AEC300003F +:1023C0008FBF006C8FB600688FB500648FB400605B +:1023D0008FB3005C8FB200588FB100548FB00050A3 +:1023E00003E0000827BD007027BDFFD8AFB3001C75 +:1023F000AFB20018AFB10014AFB00010AFBF0020F3 +:102400000080982100E0802130B1FFFF0E000D45D3 +:1024100030D200FF000000000000000000000000BB +:102420008F8200188F83001CAC510000AC52000456 +:10243000AC530008AC40000CAC400010AC400014A1 +:10244000AC4000189463001E02038025AC50001CB1 +:102450000000000000000000000000002404000153 +:102460008FBF00208FB3001C8FB200188FB10014F3 +:102470008FB000100A000D7927BD002830A5FFFF9E +:102480000A0008C830C600FF3C028008344301003F +:102490009462000E3C080800950800C63046FFFF15 +:1024A00014C000043402FFFF946500DA0A00091525 +:1024B0008F84001410C20027000000009462004EB8 +:1024C0009464003C3045FFFF00A6102300A6182BA3 +:1024D0003087FFFF106000043044FFFF00C5102369 +:1024E00000E210233044FFFF0088102B1040000E44 +:1024F00000E810233C02800834440100240300015A +:1025000034420080A44300162402FFFFA482000E80 +:10251000948500DA8F8400140000302130A5FFFF7D +:102520000A0008ED3C0760200044102A1040000912 +:102530003C0280083443008094620016304200015F +:10254000104000043C0280009442007E24420014AB +:10255000A462001603E000080000000027BDFFE0B1 +:102560003C028008AFBF001CAFB00018344201002D +:10257000944300429442004C104000193068FFFF21 +:102580009383001024020001146200298FBF001CF5 +:102590003C06800834D00100000810C20050102111 +:1025A000904200543103000734C70148304200FF15 +:1025B000006210073042000134C9014E34C4012CBE +:1025C00034C5013E1040001634C601420E0006BE5E +:1025D000AFA90010960200420A0009323048FFFFFE +:1025E0003C028008344401009483004494820042F9 +:1025F0001043000F8FBF001C94820044A48200424D +:1026000094820050A482004E8C820038AC8200304C +:1026100094820040A482003E9482004AA482004832 +:102620008FBF001C8FB000180A0008F027BD0020E3 +:102630008FB0001803E0000827BD002027BDFFA0D1 +:10264000AFB1004C3C118000AFBF0058AFB3005495 +:10265000AFB20050AFB000483626018890C20003E8 +:102660003044007FA3A400108E32018090C200008D +:102670003043007F240200031062003BAF9200143D +:102680002862000410400006240200042402000214 +:10269000106200098FBF00580A000AFB8FB3005474 +:1026A0001062004D240200051062014E8FBF0058D9 +:1026B0000A000AFB8FB30054000411C0024210212B +:1026C0002404FF802442024000441024264300409A +:1026D000AE2200243063007F3C02800A0062182191 +:1026E0009062003CAFA3003C00441025A062003C77 +:1026F0008FA3003C9062003C304200401040016CCF +:102700008FBF00583C108008A380001036100100D5 +:102710008E0200D08C63003427A4003C27A5001053 +:10272000004310210E0007AFAE0200D093A20010AC +:102730003C038000A20200C58C6202780440FFFEC8 +:102740008F820014AC62024024020002A0620244A4 +:102750003C021000AC6202780E0009250000000067 +:102760000A000AFA8FBF00583C05800890C3000198 +:1027700090A2000B1443014E8FBF005834A4008078 +:102780008C8200189082004C90A200083C026000ED +:102790008C4254048C8300183C027FFF3442FFFFBC +:1027A000006218243C0208008C4200B4AC8300187C +:1027B0003C038000244200013C010800AC2200B42C +:1027C0008C6201F80440FFFE8F820014AC6201C0ED +:1027D0000A000AC2240200023C10800890C30001D3 +:1027E0009202000B144301328FBF005827A4001837 +:1027F00036050110240600033C0260008C4254049C +:102800000E000E080000000027A40028360501E095 +:102810000E000E08240600038FA2002836030100D4 +:10282000AE0200648FA2002CAE0200688FA20030BE +:10283000AE02006C93A40018906300C52402FF80D0 +:102840000082102400431025304900FF3084007FAF +:102850003122007F0082102A544000013929008073 +:10286000000411C0244202402403FF8002421021D0 +:1028700000431024AE220094264200403042007FE4 +:102880003C038006004340218FA3001C2402FFFF6D +:10289000AFA800403C130800927300F710620033A9 +:1028A00093A2001995030014304400FF3063FFFF2A +:1028B0000064182B10600010000000009504001444 +:1028C0008D07001C8D0600183084FFFF0044202374 +:1028D0000004210000E438210000102100E4202B36 +:1028E00000C2302100C43021AD07001CAD06001825 +:1028F0000A000A1B93A20019950400148D07001CFE +:102900008D0600183084FFFF008220230004210080 +:10291000000010210080182100C2302300E4202B89 +:1029200000C4302300E33823AD07001CAD060018B7 +:1029300093A200198FA30040A462001497A2001A6A +:10294000A46200168FA2001CAC6200108FA2001CB3 +:10295000AC62000C93A20019A462002097A2001A96 +:10296000A46200228FA2001CAC6200243C048008F8 +:10297000348300808C6200388FA2002001208821DF +:10298000AC62003C8FA20020AC82000093A2001831 +:10299000A062004C93A20018A0820009A060006809 +:1029A00093A20018105100512407FF803229007FA4 +:1029B000000911C024420240024210213046007F2B +:1029C0003C03800000471024AC6200943C02800667 +:1029D00000C2302190C2003CAFA600400000202180 +:1029E00000471025A0C2003C8FA8004095020002BD +:1029F000950300148D07001C3042FFFF3063FFFF7A +:102A00008D060018004310230002110000E2382157 +:102A100000E2102B00C4302100C23021AD07001CA1 +:102A2000AD06001895020002A5020014A5000016CC +:102A30008D020008AD0200108D020008AD02000CEE +:102A400095020002A5020020A50000228D020008C8 +:102A5000AD0200249102003C304200401040001AB8 +:102A6000262200013C108008A3A90038A380001092 +:102A7000361001008E0200D08D03003427A40040E0 +:102A800027A50038004310210E0007AFAE0200D08A +:102A900093A200383C038000A20200C58C62027839 +:102AA0000440FFFE8F820014AC6202402402000248 +:102AB000A06202443C021000AC6202780E000925BC +:102AC00000000000262200013043007F1473000440 +:102AD000004020212403FF800223102400432026ED +:102AE00093A200180A000A37309100FF93A400183F +:102AF0008FA3001C2402FFFF1062000A308900FF30 +:102B000024820001248300013042007F1453000519 +:102B1000306900FF2403FF80008310240043102647 +:102B2000304900FF3C0280089042000801208821C3 +:102B3000305000FF123000193222007F000211C015 +:102B400002421021244202402403FF800043182443 +:102B50003C048000AC8300943042007F3C0380063C +:102B6000004310218C43000C004020211060000B1A +:102B7000AFA200400E00056A0000000026230001FD +:102B80002405FF803062007F1453000202252024B8 +:102B9000008518260A000A9B307100FF3C0480085B +:102BA000348400808C8300183C027FFF3442FFFF96 +:102BB00000621824AC8300183C0380008C6201F88A +:102BC0000440FFFE00000000AC7201C024020002BD +:102BD000A06201C43C021000AC6201F80A000AFACB +:102BE0008FBF00583C04800890C300019082000B06 +:102BF0001443002F8FBF00583490008092020008C9 +:102C00003042004010400020000000009202000806 +:102C100000021600000216030441000502402021B4 +:102C20000E000E8D240500930A000AFA8FBF00588B +:102C30009202000924030018304200FF1443000DE3 +:102C400002402021240500390E000E25000030210D +:102C50000E0003458F8400148F82FFA82403001206 +:102C6000A04300090E0003508F8400140A000AFAE2 +:102C70008FBF0058240500360E000E2500003021BD +:102C80000A000AFA8FBF00580E00034502402021B7 +:102C9000920200058F840014344200200E0003507D +:102CA000A20200050E0010368F8400148FBF00585A +:102CB0008FB300548FB200508FB1004C8FB00048DA +:102CC00003E0000827BD00603C0280083445010095 +:102CD0003C0280008C42014094A3000E0000302191 +:102CE00000402021AF8200143063FFFF3402FFFF59 +:102CF000106200063C0760202402FFFFA4A2000E21 +:102D000094A500DA0A0008ED30A5FFFF03E00008F3 +:102D10000000000027BDFFC83C0280003C06800880 +:102D2000AFB5002CAFB1001CAFBF0030AFB400286E +:102D3000AFB30024AFB20020AFB00018345101008F +:102D400034C501008C4301008E2200148CA400D4F1 +:102D50000000A821AF830014004410231840005243 +:102D6000A38000108E22001400005021ACA200D4D9 +:102D700090C3000890A200C53073007FA3A200108A +:102D80008CB200D08CB400D4304200FF1053003B12 +:102D900093A200108F8300142407FF80000211C04B +:102DA00000621021244202402463004000471024A6 +:102DB0003063007F3C0980003C08800A00681821CD +:102DC000AD2200248C62003427A4001427A5001033 +:102DD000024280210290102304400028AFA3001477 +:102DE0009062003C00E21024304200FF14400019C1 +:102DF000020090219062003C34420040A062003CFE +:102E00008F86001493A3001024C200403042007F3C +:102E1000004828213C0208008C4200F42463000191 +:102E2000306400FF14820002A3A30010A3A00010CE +:102E300093A20010AFA50014000211C0244202406A +:102E400000C2102100471024AD2200240A000B31DB +:102E500093A200100E0007AF000000003C028008A3 +:102E600034420100AC5000D093A30010240A0001AA +:102E7000A04300C50A000B3193A2001024020001F8 +:102E8000154200093C0380008C6202780440FFFE7A +:102E90008F820014AC62024024020002A06202444D +:102EA0003C021000AC6202789222000B2403000264 +:102EB000304200FF14430072000000009622000818 +:102EC000304300FF24020082146200402402008488 +:102ED0003C028000344901008D22000C952300063D +:102EE000000216023063FFFF3045003F2402002736 +:102EF00010A2000FAF83000C28A200281040000889 +:102F0000240200312402002110A20009240200251D +:102F100010A20007938200110A000BA90000000014 +:102F200010A20007938200110A000BA90000000004 +:102F30000E000763012020210A000C290000000078 +:102F40003C0380008C6202780440FFFE8F820014F4 +:102F5000AC62024024020002A06202443C02100063 +:102F6000AC6202780A000C290000000095230006DC +:102F7000912400058D25000C8D2600108D2700184A +:102F80008D28001C8D290020244200013C010800EE +:102F9000A42352C63C010800A02452C53C010800ED +:102FA000AC2552CC3C010800AC2652D03C010800B4 +:102FB000AC2752D83C010800AC2852DC3C01080088 +:102FC000AC2952E00A000C29A38200111462000A05 +:102FD000240200813C02800834420100944500DA5A +:102FE000922600058F84001430A5FFFF30C600FF35 +:102FF0000A000BEA3C0760211462005C000000003C +:103000009222000A304300FF306200201040000787 +:10301000306200403C02800834420100944500DAEE +:103020008F8400140A000BE82406004010400007BB +:10303000000316003C02800834420100944500DA87 +:103040008F8400140A000BE82406004100021603D6 +:10305000044100463C02800834420100944500DAF5 +:103060008F8400142406004230A5FFFF3C0760193E +:103070000E0008ED000000000A000C29000000000E +:103080009222000B24040016304200FF1044000678 +:103090003C0680009222000B24030017304200FF00 +:1030A000144300320000000034C5010090A2000B60 +:1030B000304200FF1444000B000080218CA200204D +:1030C0008CA400202403FF80004310240002114040 +:1030D0003084007F004410253C032000004310256D +:1030E000ACC2083094A200080002140000021403CD +:1030F000044200012410000194A200083042008024 +:103100005040001A0200A82194A20008304220007A +:10311000504000160200A8218CA300183C021C2D70 +:10312000344219ED106200110200A8213C0208008F +:103130008C4200D4104000053C02800824030004A7 +:1031400034420100A04300EC3C02800834420100FC +:10315000944500DA8F8400142406000630A5FFFF92 +:103160000E0008ED3C0760210200A8210E00092591 +:10317000000000009222000A3042000810400004C3 +:1031800002A010210E00133A0000000002A010213E +:103190008FBF00308FB5002C8FB400288FB3002470 +:1031A0008FB200208FB1001C8FB0001803E0000820 +:1031B00027BD00382402FF80008220243C029000BA +:1031C00034420007008220253C028000AC440020ED +:1031D0003C0380008C6200200440FFFE00000000E1 +:1031E00003E00008000000003C0380002402FF8090 +:1031F000008220243462000700822025AC64002075 +:103200008C6200200440FFFE0000000003E0000884 +:10321000000000003C028008240300053442010045 +:10322000A04300EC3C0280008C4201003C03800083 +:10323000AF8200148C6202780440FFFE8F8200147B +:10324000AC62024024020002A06202443C02100070 +:10325000AC62027803E000080000000027BDFFE830 +:103260003C068000AFBF001034C7010094E20008A4 +:10327000304400FF38830082388200842C630001D0 +:103280002C420001006218251060002D24020083EA +:1032900093820011504000368FBF00103C0208009E +:1032A000904252CC8CC401003C06080094C652C621 +:1032B0003045003F38A3003238A2003F2C630001A4 +:1032C0002C42000100621825AF840014AF86000C68 +:1032D000A38000111460000700E0202124020020D8 +:1032E00014A20012000000003402FFFF14C2000FFD +:1032F000000000002402002014A2000500E02821A4 +:103300008CE300142402FFFF5062000B8FBF0010FB +:103310003C040800248452C0000030210E0006F254 +:10332000240700010A000C9C8FBF00100E000763E9 +:10333000000000008FBF00100A00092527BD0018FB +:10334000148200062482FF808CC301043C026020AA +:10335000AC4300140A000CD28FBF0010304200FFB3 +:103360002C42000210400004240200228FBF0010F3 +:103370000A000B1327BD0018148200048F82001C62 +:103380008FBF00100A000C5327BD00188C42000CA0 +:103390001040001E00E0282190E3000924020018DC +:1033A00014620003240200160A000CBD2403000866 +:1033B0001462000724020017240300123C02800854 +:1033C00034420080A04300090A000CCA94A70008F8 +:1033D0005462000794A700088F82FFA82404FFFE10 +:1033E0009043000500641824A043000594A700083A +:1033F00090A6001B8CA4000094A500068FBF0010AF +:1034000000073C000A0008C827BD00188FBF001045 +:1034100003E0000827BD00188F85001C3C048000D5 +:1034200094A2002A8CA30034000230C02402FFF0D2 +:1034300000C2102400621821AC83003C8CA2003032 +:103440003C038000AC8200383C0200503442001043 +:10345000AC6200300000000000000000000000002E +:103460008C620000304200201040FFFD30C2000896 +:10347000104000063C0280008C620408ACA20020D0 +:103480008C62040C0A000CF5ACA200248C430400EE +:10349000ACA300208C420404ACA200243C03002016 +:1034A0003C028000AC4300303C0480008C82003041 +:1034B000004310241440FFFD8F86001C3C02004096 +:1034C000AC82003094C3002A94C2002894C4002C1B +:1034D00094C5002E24630001004410213064FFFFD6 +:1034E000A4C2002814850002A4C3002AA4C0002A94 +:1034F00003E00008000000008F84001C27BDFFE8E7 +:103500003C05800424840010AFBF00100E000E089C +:103510002406000A8F84001C948200129483002EDB +:103520003042000F244200030043180424027FFFAE +:103530000043102B10400002AC8300000000000D7F +:103540000E000CD4000000008F83001C8FBF001001 +:1035500027BD0018946200149463001A3042000FD3 +:1035600000021500006218253C02800003E00008FC +:10357000AC4300A08F83001C3C02800494440006EE +:103580009462001A8C650000A464001600441023A5 +:103590003042FFFF0045102B03E0000838420001D5 +:1035A0008F84001C3C0780049486001A8C850000E0 +:1035B00094E20006A482001694E3000600C31023E0 +:1035C0003042FFFF0045102B384200011440FFF845 +:1035D000A483001603E00008000000008F84001C94 +:1035E0003C028004944200069483001A8C850000FB +:1035F000A4820016006210233042FFFF0045102B0A +:10360000384200015040000D8F85001C00603021C1 +:103610003C07800494E20006A482001694E30006AE +:1036200000C310233042FFFF0045102B3842000139 +:103630001440FFF8A48300168F85001C3C03800013 +:10364000346204008CA40020AF820018AC640038FF +:103650008CA20024AC62003C3C020005AC6200304D +:1036600003E00008ACA000048F84001C3C030006AB +:103670008C82000400021140004310253C038000AE +:10368000AC620030000000000000000000000000FC +:103690008C620000304200101040FFFD34620400D4 +:1036A000AC80000403E00008AF8200188F86001C85 +:1036B00027BDFFE0AFB10014AFB00010AFBF0018DE +:1036C0008CC300048CC500248F820018309000FF4A +:1036D00094C4001A246300012442002024840001C1 +:1036E00024A70020ACC30004AF820018A4C4001AB1 +:1036F000ACC7002404A100060000882104E20005F4 +:1037000094C2001A8CC2002024420001ACC20020E6 +:1037100094C2001A94C300282E040001004310260E +:103720002C420001004410245040000594C2001AAD +:1037300024020001ACC2000894C2001A94C30028FD +:103740000010202B004310262C42000100441025BD +:1037500014400007000000008CC200081440000460 +:10376000240200108CC300041462000F8F85001C1B +:103770000E000D68241100018F82001C9443002864 +:103780009442001A14430003000000000E000CD401 +:1037900000000000160000048F85001C0E000D457F +:1037A000000000008F85001C94A2001E94A4001C41 +:1037B000244200013043FFFF14640002A4A2001E53 +:1037C000A4A0001E1200000A3C02800494A200146F +:1037D00094A3001A3042000F000215000062182561 +:1037E0003C028000AC4300A00A000DDFACA0000842 +:1037F0009442000694A3001A8CA40000A4A2001610 +:10380000006210233042FFFF0044102B38420001B9 +:103810001040000D02201021006030213C07800480 +:1038200094E20006A4A2001694E3000600C310234D +:103830003042FFFF0044102B384200011440FFF8D3 +:10384000A4A30016022010218FBF00188FB100140E +:103850008FB0001003E0000827BD002003E000083F +:10386000000000008F8200243C030006000211408B +:10387000004310253C038000AC62003000000000D3 +:1038800000000000000000008C62000030420010C8 +:103890001040FFFD34620400AF82002003E0000806 +:1038A000AF80002403E000080000102103E00008BE +:1038B000000000003084FFFF30A5FFFF000018214A +:1038C000108000070000000030820001104000025C +:1038D00000042042006518210A000DFE0005284062 +:1038E00003E000080060102110C0000624C6FFFF9E +:1038F0008CA2000024A50004AC8200000A000E087F +:103900002484000403E000080000000010A0000868 +:1039100024A3FFFFAC8600000000000000000000B0 +:103920002402FFFF2463FFFF1462FFFA24840004D3 +:1039300003E00008000000003C02800834420080E0 +:1039400024030001AC43000CA4430010A443001264 +:10395000A443001403E00008A44300168F82001C57 +:1039600027BDFFD8AFB3001CAFB20018AFB1001431 +:10397000AFB00010AFBF00208C47000C2482008045 +:103980002409FF803C08800E3043007F00808021A6 +:103990003C0A8000004920240068182130B100FF53 +:1039A00030D200FF10E0002900009821260201001B +:1039B000AD44002C004928243042007F00482021DB +:1039C0009062000024030050304200FF14430004C2 +:1039D00000000000AD45002C948200DA3053FFFF58 +:1039E0000E000D45000000008F82001C8F83001820 +:1039F00000112C009442001E0012240034840001A7 +:103A000000A228253C02400000A22825AC7000003E +:103A10008FBF0020AC6000048FB20018AC730008A8 +:103A20008FB10014AC60000C8FB3001CAC640010AC +:103A30008FB00010AC60001424040001AC600018CA +:103A400027BD00280A000D79AC65001C8FBF00203F +:103A50008FB3001C8FB200188FB100148FB000100C +:103A600003E0000827BD00283C06800034C20100A6 +:103A70009043000F240200101062000E2865001110 +:103A800010A0000724020012240200082405003AB6 +:103A9000106200060000302103E000080000000072 +:103AA000240500351462FFFC000030210A000E25B9 +:103AB000000000008CC200748F83FFA824420FA076 +:103AC00003E00008AC62000C27BDFFE8AFBF0010A8 +:103AD0000E000355240500013C0480088FBF001030 +:103AE0002402000134830080A462001227BD001864 +:103AF0002402000103E00008A080001A27BDFFE0B7 +:103B0000AFB20018AFB10014AFB00010AFBF001CCF +:103B100030B2FFFF0E000345008088213C02800880 +:103B2000345000809202000924030004304200FF58 +:103B30001443000C3C028008124000082402000AD2 +:103B40000E000E1C00000000920200052403FFFE80 +:103B500000431024A202000524020012A202000960 +:103B60003C02800834420080022020210E000350D5 +:103B7000A040002716400003022020210E000E80E6 +:103B80000000000002202021324600FF8FBF001CF1 +:103B90008FB200188FB100148FB0001024050038C8 +:103BA0000A000E2527BD002027BDFFE0AFBF001C87 +:103BB000AFB20018AFB10014AFB000100E00034553 +:103BC000008080210E000E1C000000003C028008D6 +:103BD0003445008090A2000924120018305100FFE3 +:103BE000123200030200202124020012A0A20009C8 +:103BF00090A200052403FFFE004310240E00035092 +:103C0000A0A2000502002021240500201632000792 +:103C1000000030218FBF001C8FB200188FB100143C +:103C20008FB000100A00035527BD00208FBF001C75 +:103C30008FB200188FB100148FB000102405003926 +:103C40000A000E2527BD002027BDFFE83C028000AA +:103C5000AFB00010AFBF0014344201009442000C1A +:103C6000240500360080802114400012304600FFF9 +:103C70000E000345000000003C0280083442008032 +:103C800024030012A0430009904300053463001090 +:103C90000E000E1CA04300050E0003500200202160 +:103CA000020020210E000355240500200A000EFD0D +:103CB000000000000E000E25000000000E0003456D +:103CC000020020213C0280089043001B2405FF9F36 +:103CD00002002021006518248FBF00148FB000104F +:103CE000A043001B0A00035027BD001827BDFFE0BA +:103CF000AFBF0018AFB10014AFB0001030B100FF7B +:103D00000E000345008080213C028008240300123D +:103D1000344200800E000E1CA04300090E00035028 +:103D20000200202102002021022030218FBF001834 +:103D30008FB100148FB00010240500350A000E2545 +:103D400027BD00203C0480089083000E9082000A6A +:103D50001443000B000028218F82FFA82403005089 +:103D60002405000190420000304200FF144300048B +:103D7000000000009082000E24420001A082000E8C +:103D800003E0000800A010213C0380008C6201F8D1 +:103D90000440FFFE24020002AC6401C0A06201C422 +:103DA0003C02100003E00008AC6201F827BDFFE010 +:103DB000AFB200183C128008AFB10014AFBF001CB6 +:103DC000AFB0001036510080922200092403000A8F +:103DD000304200FF1443003E000000008E43000408 +:103DE0008E220038506200808FBF001C922200009B +:103DF00024030050304200FF144300253C028000A1 +:103E00008C4201408E4300043642010002202821EA +:103E1000AC43001C9622005C8E2300383042FFFF2A +:103E20000002104000621821AE23001C8E430004E3 +:103E30008E2400389622005C006418233042FFFF75 +:103E400000031843000210400043102A10400006EF +:103E5000000000008E4200048E230038004310232F +:103E60000A000F6B000220439622005C3042FFFFE5 +:103E7000000220403C0280083443010034420080AC +:103E8000ACA4002CA040002424020001A062000C7D +:103E90000E000F1F00000000104000538FBF001CD9 +:103EA0003C0280008C4401403C0380008C6201F89D +:103EB0000440FFFE24020002AC6401C0A06201C401 +:103EC0003C021000AC6201F80A000FC88FBF001C52 +:103ED0009222000924030010304200FF1443000422 +:103EE0003C0280008C4401400A000FAF00002821F2 +:103EF0009222000924030016304200FF14430006FA +:103F000024020014A22200093C0280008C440140DB +:103F10000A000FC28FBF001C8E2200388E23003C87 +:103F200000431023044100308FBF001C9222002761 +:103F300024420001A2220027922200272C420004E2 +:103F4000144000163C108000922200092403000453 +:103F5000304200FF144300093C0280008C440140C1 +:103F60008FBF001C8FB200188FB100148FB00010EB +:103F7000240500930A000E8D27BD00208C440140CB +:103F8000240500938FBF001C8FB200188FB100145E +:103F90008FB000100A000F0927BD00208E040140D9 +:103FA0000E000345000000008E4200042442FFFF83 +:103FB000AE4200048E22003C2442FFFFAE22003CB1 +:103FC0000E0003508E0401408E0401408FBF001C80 +:103FD0008FB200188FB100148FB0001024050004B8 +:103FE0000A00035527BD00208FB200188FB10014BE +:103FF0008FB0001003E0000827BD00203C068000C1 +:104000008CC201883C038008346500809063000EF8 +:1040100000021402304400FF306300FF1464000EFD +:104020003C02800890A20026304200FF10440009A4 +:104030008F82FFA8A0A40026240300509042000015 +:10404000304200FF14430006000000000A00058D06 +:104050008CC401803C02800834420080A0440026C9 +:1040600003E000080000000027BDFFE030E700FF8C +:10407000AFB20018AFBF001CAFB10014AFB000105A +:104080000080902114E0000630C600FF0000000010 +:104090000000000D000000000A0010212400010EA5 +:1040A0003C0380089062000E304200FF144600235B +:1040B0003462008090420026304200FF1446001F08 +:1040C000000000009062000F304200FF1446001B09 +:1040D000000000009062000A304200FF1446000316 +:1040E0008F90FFA80000000D8F90FFA88F82FFAC7B +:1040F0003C118000AE05003CAC450000A066000A03 +:104100000E0003458E240100A20000240E0003507F +:104110008E2401003C0380008C6201F80440FFFE05 +:1041200024020002AC7201C0A06201C43C02100073 +:10413000AC6201F80A0010228FBF001C00000000D2 +:104140000000000D00000000240001378FBF001C9C +:104150008FB200188FB100148FB0001003E0000878 +:1041600027BD00208F83FFA83C0280008C44010003 +:10417000344201008C65003C9046001B0A000FE8A9 +:10418000240700013C0280089043000E9042000A80 +:1041900000431026304200FF03E000080002102B0D +:1041A00027BDFFE03C028008AFB10014AFB00010A3 +:1041B000AFBF001834500080920200052403003085 +:1041C0003042003014430085008088218F82001C1B +:1041D0008C42000C104000828FBF00180E000D456D +:1041E000000000008F860018ACD100009202000889 +:1041F00092030009304200FF00021200306300FF0A +:1042000000431025ACC200049202004D00021600CB +:104210000002160304410005000000003C030800F2 +:104220008C6300480A0010603C108008920200086D +:104230003042004014400003000018219202002781 +:10424000304300FF3C108008361100809222004D60 +:1042500000031E00304200FF000214000062182517 +:10426000ACC300088E2400308F82001CACC4000C4C +:104270008E2500349443001E3C02C00BACC50010D8 +:10428000006218258E22003800002021ACC20014E4 +:104290008E22003CACC200180E000D79ACC3001C8D +:1042A0008E0200048F8400183C058000AC82000060 +:1042B0008E220020AC8200048E22001CAC820008FA +:1042C0008E2200588CA3007400431021AC82000C95 +:1042D0008E22002CAC8200108E2200408E230044DF +:1042E0000002140000431025AC8200149222004DFD +:1042F00024030080304200FF14430004000000004B +:10430000AC8000180A0010A48F82001C8E23000CC1 +:10431000240200011062000E2402FFFF9222000816 +:10432000304200401440000A2402FFFF8E23000C9C +:104330008CA20074006218233C0208000062102462 +:1043400014400002000028210060282100051043CD +:10435000AC8200188F82001C000020219443001EB4 +:104360003C02C00C006218258F8200180E000D79E7 +:10437000AC43001C3C038008346201008C42000006 +:104380008F850018346300808FBF0018ACA2000036 +:10439000ACA000048C6400488F82001C8FB1001414 +:1043A000ACA40008ACA0000CACA000109063000509 +:1043B0009446001E3C02400D00031E0000C2302542 +:1043C000ACA300148FB00010ACA0001824040001AE +:1043D000ACA6001C0A000D7927BD00208FBF001875 +:1043E0008FB100148FB0001003E0000827BD00203B +:1043F0003C0280009443007C3C028008344601006B +:10440000308400FF3065FFFF2402000524A34650DE +:10441000A0C4000C5482000C3065FFFF90C2000D58 +:104420002C4200071040000724A30A0090C3000D8F +:10443000240200140062100400A210210A0010E0FF +:104440003045FFFF3065FFFF3C02800834420080AA +:1044500003E00008A44500143C0380083468008091 +:10446000AD050038346701008CE2001C308400FF89 +:1044700000A210231840000330C600FF24A2FFFC56 +:10448000ACE2001C30820001504000083C03800870 +:104490008D02003C00A210230441001224040005F8 +:1044A0008C62000410A2000F3C0380088C620004A0 +:1044B00014A2001E000000003C0208008C4200D83C +:1044C00030420020104000093C0280083462008025 +:1044D000906300089042004C144300043C028008A2 +:1044E000240400040A0010CA0000000034430080C5 +:1044F00034420100A040000C24020001A462001418 +:1045000010C0000A3C0280008C4401003C03800083 +:104510008C6201F80440FFFE24020002AC6401C07A +:10452000A06201C43C021000AC6201F803E0000884 +:104530000000000027BDFFE800A61823AFBF001051 +:1045400018600080308800FF3C02800834470080FB +:10455000A0E0002434440100A0E000278C82001C6D +:1045600000A2102304400056000000008CE2003C32 +:1045700094E3005C8CE4002C004530233063FFFFA3 +:1045800000C318210083202B1080000400E01821B4 +:104590008CE2002C0A00113900A2102194E2005C88 +:1045A0003042FFFF00C2102100A21021AC62001CAB +:1045B0003C028008344400809482005C8C83001CA0 +:1045C0003042FFFF0002104000A210210043102BD8 +:1045D00010400004000000008C82001C0A00114CF6 +:1045E0003C0680089482005C3042FFFF00021040CD +:1045F00000A210213C06800834C3010034C70080AB +:10460000AC82001CA060000CACE500388C62001C81 +:1046100000A210231840000224A2FFFCAC62001C80 +:1046200031020001104000083C0380088CE2003C8D +:1046300000A2102304410012240400058CC20004CF +:1046400010A200108FBF00108C62000414A2004F53 +:104650008FBF00103C0208008C4200D8304200207E +:104660001040000A3C028008346200809063000819 +:104670009042004C144300053C02800824040004CE +:104680008FBF00100A0010CA27BD001834430080F5 +:1046900034420100A040000C24020001A462001476 +:1046A0003C0280008C4401003C0380008C6201F8D5 +:1046B0000440FFFE240200020A00119900000000DD +:1046C0008CE2001C004610230043102B54400001D4 +:1046D000ACE5001C94E2005C3042FFFF0062102B4E +:1046E000144000072402000294E2005C8CE3001CEA +:1046F0003042FFFF00621821ACE3001C24020002DC +:10470000ACE500380E000F1FA082000C1040001F07 +:104710008FBF00103C0280008C4401003C038000ED +:104720008C6201F80440FFFE24020002AC6401C068 +:10473000A06201C43C021000AC6201F80A0011B191 +:104740008FBF001031020010104000108FBF00100A +:104750003C028008344500808CA3001C94A2005CBD +:10476000006618233042FFFF006218213C023FFF21 +:104770003444FFFF0083102B5440000100801821B7 +:1047800000C31021ACA2001C8FBF001003E0000882 +:1047900027BD001827BDFFE800C0402100A6302338 +:1047A000AFBF001018C00026308A00FF3C0280080E +:1047B000344900808D24001C8D23002C0088202388 +:1047C0000064182B1060000F344701008CE20020B9 +:1047D00000461021ACE200208CE200200044102BA7 +:1047E0001440000B3C023FFF8CE2002000441023E9 +:1047F000ACE200209522005C3042FFFF0A0011D19C +:1048000000822021ACE00020008620213C023FFFF6 +:104810003443FFFF0064102B54400001006020214E +:104820003C0280083442008000851821AC43001C03 +:10483000A0400024A04000270A0012233C03800867 +:1048400031420010104000433C0380083C068008C1 +:1048500034C400808C82003C004810235840003E45 +:10486000346600809082002424420001A08200244B +:10487000908200243C0308008C630024304200FF37 +:104880000043102B144000688FBF001034C2010099 +:104890008C42001C00A2102318400063000000009E +:1048A0008CC300049482005C006818233042FFFF30 +:1048B00000031843000210400043102A1040000576 +:1048C000000000008CC20004004810230A001206F9 +:1048D000000210439482005C3042FFFF000210404F +:1048E0003C068008AC82002C34C5008094A2005C99 +:1048F0008CA4002C94A3005C3042FFFF0002104007 +:10490000008220213063FFFF008320210104102159 +:10491000ACA2001C8CC2000434C60100ACC2001C56 +:10492000240200020E000F1FA0C2000C1040003E27 +:104930008FBF00103C0280008C4401003C038000CB +:104940008C6201F80440FFFE240200020A001253A8 +:104950000000000034660080ACC5003834640100FB +:104960008C82001C00A210231840000224A2FFFC2D +:10497000AC82001C314200015040000A3C03800818 +:104980008CC2003C00A21023044300142404000540 +:104990008C62000414A200033C0380080A00124544 +:1049A000240400058C62000414A2001F8FBF0010B5 +:1049B0003C0208008C4200D8304200201040000A1F +:1049C0003C02800834620080906300089042004CF2 +:1049D000144300053C028008240400048FBF00102B +:1049E0000A0010CA27BD0018344300803442010079 +:1049F000A040000C24020001A46200143C028000CC +:104A00008C4401003C0380008C6201F80440FFFEEE +:104A100024020002AC6401C0A06201C43C02100088 +:104A2000AC6201F88FBF001003E0000827BD00183A +:104A300027BDFFE83C0A8008AFBF00103549008061 +:104A40008D22003C00C04021308400FF004610232E +:104A50001840009D30E700FF3547010024020001A7 +:104A600000A63023A0E0000CA0E0000DA522001459 +:104A700018C00024308200108D23001C8D22002CD1 +:104A8000006818230043102B1040000F00000000A6 +:104A90008CE2002000461021ACE200208CE20020D5 +:104AA0000043102B1440000B3C023FFF8CE200201F +:104AB00000431023ACE200209522005C3042FFFF4F +:104AC0000A00128200621821ACE000200066182162 +:104AD0003C023FFF3446FFFF00C3102B544000014F +:104AE00000C018213C028008344200800065182173 +:104AF000AC43001CA0400024A04000270A0012D0B4 +:104B00003C038008104000403C0380088D22003C9C +:104B1000004810235840003D346700809122002453 +:104B200024420001A1220024912200243C03080019 +:104B30008C630024304200FF0043102B1440009A85 +:104B40008FBF00108CE2001C00A2102318400096BA +:104B5000000000008D4300049522005C00681823CB +:104B60003042FFFF00031843000210400043102AA8 +:104B700010400005012020218D4200040048102330 +:104B80000A0012B3000210439522005C3042FFFF7E +:104B9000000210403C068008AC82002C34C5008026 +:104BA00094A2005C8CA4002C94A3005C3042FFFF14 +:104BB00000021040008220213063FFFF0083182193 +:104BC00001031021ACA2001C8CC2000434C60100F9 +:104BD000ACC2001C240200020E000F1FA0C2000C79 +:104BE000104000718FBF00103C0280008C44010017 +:104BF0003C0380008C6201F80440FFFE24020002A6 +:104C00000A0012FA0000000034670080ACE50038AA +:104C1000346601008CC2001C00A210231840000260 +:104C200024A2FFFCACC2001C3082000150400008EE +:104C30003C0380088CE2003C00A210230443005196 +:104C4000240400058C62000410A2003E3C0380088E +:104C50008C62000454A200548FBF00103C02080074 +:104C60008C4200D830420020104000063C028008F0 +:104C700034620080906300089042004C1043004072 +:104C80003C0280083443008034420100A040000C04 +:104C900024020001A46200143C0280008C44010044 +:104CA0003C0380008C6201F80440FFFE24020002F5 +:104CB000AC6401C0A06201C43C021000AC6201F807 +:104CC0000A0013388FBF001024020005A12000271E +:104CD00014E2000A3C038008354301009062000D95 +:104CE0002C420006504000053C0380089062000DF5 +:104CF00024420001A062000D3C038008346700805C +:104D0000ACE50038346601008CC2001C00A2102300 +:104D10001840000224A2FFFCACC2001C308200013B +:104D20005040000A3C0380088CE2003C00A21023A3 +:104D300004410014240400058C62000414A2000342 +:104D40003C0380080A00132F240400058C62000431 +:104D500014A200158FBF00103C0208008C4200D83E +:104D6000304200201040000A3C028008346200807B +:104D7000906300089042004C144300053C028008F8 +:104D8000240400048FBF00100A0010CA27BD0018B9 +:104D90003443008034420100A040000C2402000192 +:104DA000A46200148FBF001003E0000827BD0018A4 +:104DB0003C0B800827BDFFE83C028000AFBF00101D +:104DC00034420100356A00809044000A35690100D0 +:104DD0008C4500148D4800389123000C308400FF6E +:104DE000010510231C4000B3306700FF2CE20006D1 +:104DF000504000B18FBF00102402000100E23004D7 +:104E000030C200035440000800A8302330C2000C18 +:104E1000144000A130C20030144000A38FBF001026 +:104E20000A0013FC0000000018C0002430820010AB +:104E30008D43001C8D42002C006818230043102B6A +:104E40001040000F000000008D22002000461021BD +:104E5000AD2200208D2200200043102B1440000BB7 +:104E60003C023FFF8D22002000431023AD22002092 +:104E70009542005C3042FFFF0A0013700062182167 +:104E8000AD200020006618213C023FFF3446FFFFA2 +:104E900000C3102B5440000100C018213C028008C0 +:104EA0003442008000651821AC43001CA04000245F +:104EB000A04000270A0013BE3C03800810400040B9 +:104EC0003C0380088D42003C004810231840003D00 +:104ED000346700809142002424420001A142002452 +:104EE000914200243C0308008C630024304200FF00 +:104EF0000043102B144000708FBF00108D22001C47 +:104F000000A210231840006C000000008D63000414 +:104F10009542005C006818233042FFFF00031843ED +:104F2000000210400043102A1040000501402021DB +:104F30008D620004004810230A0013A100021043F0 +:104F40009542005C3042FFFF000210403C068008A2 +:104F5000AC82002C34C5008094A2005C8CA4002C90 +:104F600094A3005C3042FFFF000210400082202129 +:104F70003063FFFF0083182101031021ACA2001C45 +:104F80008CC2000434C60100ACC2001C2402000222 +:104F90000E000F1FA0C2000C104000478FBF001072 +:104FA0003C0280008C4401003C0380008C6201F8CC +:104FB0000440FFFE240200020A0013EE000000007D +:104FC00034670080ACE50038346601008CC2001CF8 +:104FD00000A210231840000224A2FFFCACC2001C57 +:104FE000308200015040000A3C0380088CE2003C03 +:104FF00000A2102304430014240400058C62000462 +:1050000014A200033C0380080A0013E024040005F6 +:105010008C62000414A200288FBF00103C0208001C +:105020008C4200D8304200201040000A3C02800828 +:1050300034620080906300089042004C14430005E5 +:105040003C028008240400048FBF00100A0010CA2C +:1050500027BD00183443008034420100A040000CFA +:1050600024020001A46200143C0280008C44010070 +:105070003C0380008C6201F80440FFFE2402000221 +:10508000AC6401C0A06201C43C021000AC6201F833 +:105090000A0013FC8FBF00108FBF001001003021E9 +:1050A0000A00111B27BD0018010030210A00125A06 +:1050B00027BD00188FBF001003E0000827BD0018AF +:1050C0003C0380083464010024020003A082000C29 +:1050D0008C62000403E00008AC82001C3C058008E0 +:1050E00034A300809062002734A501002406004309 +:1050F00024420001A0620027906300273C020800C0 +:105100008C420048306300FF146200043C076021B9 +:1051100094A500DA0A0008ED30A5FFFF03E00008BF +:105120000000000027BDFFE8AFBF00103C02800078 +:105130000E0014058C4401803C02800834430100B9 +:10514000A060000C8C4200048FBF001027BD001827 +:1051500003E00008AC62001C27BDFFE03C028008B1 +:10516000AFBF0018AFB10014AFB0001034450080DD +:10517000344601003C0880008D09014090C3000CBA +:105180008CA4003C8CA200381482003B306700FFE6 +:105190009502007C90A30027146000093045FFFFB2 +:1051A0002402000554E200083C04800890C2000D6F +:1051B00024420001A0C2000D0A0014403C048008F3 +:1051C000A0C0000D3C048008348201009042000C15 +:1051D00024030005304200FF1443000A24A205DC2A +:1051E00034830080906200272C4200075040000565 +:1051F00024A20A0090630027240200140062100415 +:1052000000A210213C108008361000803045FFFFBE +:10521000012020210E001405A60500149602005C52 +:105220008E0300383C1180003042FFFF0002104026 +:1052300000621821AE03001C0E0003458E240140BD +:105240009202002534420040A20200250E000350C5 +:105250008E2401408E2401403C0380008C6201F8C2 +:105260000440FFFE24020002AC6401C0A06201C43D +:105270003C021000AC6201F88FBF00188FB100141F +:0C5280008FB0001003E0000827BD0020E4 +:04528C008008010095 +:10529000800800808008000000000C8000003200C0 +:1052A0008008024008000EDC08000F3408000F7868 +:1052B00008001010080010508008010080080080CD +:0452C0008008000062 +:0C52C4000A0000220000000000000000B2 +:1052D0000000000D6370352E302E306A3300000060 +:1052E00005000004000000000000000000000000B5 +:1052F000000000000000000038003C00000000003A +:10530000000000000000000000000000000000207D +:10531000000000000000000000000000000000008D +:10532000000000000000000000000000000000007D +:105330000000000000000000210038000000000113 +:105340000000002B00000000000000000000000032 +:1053500010000003000000000000000D0000000D20 +:105360003C020800244254243C0308002463564CA9 +:10537000AC4000000043202B1480FFFD24420004B9 +:105380003C1D080037BD9FFC03A0F0213C10080025 +:10539000261000883C1C0800279C54240E0002881C +:1053A000000000000000000D00A018210080102166 +:1053B000008028213C0460003C07600024060008AF +:1053C00010600006348420788C420000ACE2200893 +:1053D0008C63000003E00008ACE3200C0A000E2AF6 +:1053E00000000000240300403C02600003E00008CD +:1053F000AC4320003C0760008F8600008CE52074E1 +:105400000086102100A2182B14600007000028213C +:105410008F8AFD9824050001A14400138F890000A4 +:1054200001244021AF88000003E0000800A0102103 +:105430008F84FD988F8500009086001330C300FF95 +:1054400000A31023AF82000003E00008A080001337 +:105450008F84FD9827BDFFE8AFB00010AFBF0014E8 +:10546000908900119087001124020028312800FF44 +:105470003906002830E300FF2485002C2CD00001E1 +:10548000106200162484001C0E0000390000000089 +:105490008F8FFD983C0560002402020495EE003ECB +:1054A00095ED003C000E5C0031ACFFFF016C502517 +:1054B000ACAA20105200000124020004ACA220007B +:1054C0000000000000000000000000008FBF00147A +:1054D0008FB0001003E0000827BD00180A0000711B +:1054E000000028218F85FD9827BDFFD8AFBF002081 +:1054F000AFB3001CAFB20018AFB10014AFB00010D2 +:105500000080982190A4001124B0001C24B1002C2C +:10551000308300FF386200280E00005B2C5200012F +:105520000E00006300000000020020211240000273 +:1055300002202821000028210E0000390000000070 +:105540008F8DFD983C0880003C05600095AC003EC6 +:1055500095AB003C02683025000C4C00316AFFFF1F +:10556000012A3825ACA7201024020202ACA6201480 +:1055700052400001240200028FBF00208FB3001CA4 +:105580008FB200188FB100148FB0001027BD002813 +:1055900003E00008ACA2200027BDFFE0AFB2001876 +:1055A000AFB10014AFB00010AFBF001C3C116000E1 +:1055B0008E2320748F82000030D0FFFF30F2FFFF77 +:1055C0001062000C2406008F0E000039000000005D +:1055D0003C06801F0010440034C5FF00011238252E +:1055E00024040002AE27201000003021AE25201434 +:1055F000AE2420008FBF001C8FB200188FB10014A2 +:105600008FB0001000C0102103E0000827BD00206B +:1056100027BDFFE0AFB0001030D0FFFFAFBF0018D4 +:10562000AFB100140E00003930F1FFFF001024006C +:10563000009180253C036000AC7020108FBF0018E3 +:105640008FB100148FB0001024020004AC6220005F +:1056500027BD002003E000080000102127BDFFE85F +:105660003C0B6018AFBF00108D6F50002418FF7FF7 +:10567000340C807101F8702435CD380C240A0031C7 +:105680003C098000AD6D50003C08800AAD6C53BCF5 +:10569000AD2A00080E00049BAF88002C0E000459B0 +:1056A000000000000E000048000000003C07600001 +:1056B0008CE508082406FFF03C03570900A62024C7 +:1056C0003462F0001082005024190001AF800034D1 +:1056D0000E000BBC000000003C0660168CC40000ED +:1056E0003C0760148CE500A03C03FFFF00831024FE +:1056F0003C1F535300051FC2105F003D34C57C00A2 +:1057000094A201F2A780004C10400003A780005C27 +:10571000384B1E1EA78B004C94A201F810400004C9 +:105720008F8D0034384C1E1EA78C005C8F8D00348A +:1057300011A000049784005C240E0020A78E004C6A +:105740009784005C2C8F008151E0000124040080CC +:105750009785004C2CB80401530000012405040077 +:105760003C0260008C4304382419103C307FFFFF5A +:1057700013F900033087FFFF50E0000F24060050AC +:10578000A380005E9388005E51000010A784005C37 +:10579000A780005C9785005C8FBF0010A780004C3D +:1057A000A7800054A78000723C010800AC2500804F +:1057B00003E0000827BD0018A386005E9388005E02 +:1057C0005500FFF4A780005CA784005CA785004C0F +:1057D0008FBF00109785005CA7800054A7800072DF +:1057E0003C010800AC25008003E0000827BD00183C +:1057F00000035080014648218D2800043C066000CB +:105800000A00010F010628210A000103AF990034A4 +:105810003083FFFF8F88002C8F87002800032140F2 +:105820003C0580003C020050008248253C06600098 +:105830003C0A010034AC04008CCD08E001AA5824D5 +:1058400011600005000000008CCF08E024E7000193 +:1058500001EA7025ACCE08E08D19001001805821B6 +:10586000ACB900388D180014ACB8003CACA90030BD +:105870000000000000000000000000000000000028 +:105880000000000000000000000000000000000018 +:105890003C0380008C640000308200201040FFFD3B +:1058A0003C0F60008DED08E03C0E010001AE1824B5 +:1058B0001460FFE100000000AF87002803E000084B +:1058C000AF8B00388F85002C240BFFF03C06800046 +:1058D00094A7001A8CA9002430ECFFFF000C38C0FC +:1058E00000EB5024012A4021ACC8003C8CA40024C9 +:1058F0008CC3003C008310231840003300000000DC +:105900008CAD002025A200013C0F0050ACC2003835 +:1059100035EE00103C068000ACCE003000000000E8 +:105920000000000000000000000000000000000077 +:105930000000000000000000000000003C048000A7 +:105940008C990000333800201300FFFD30E200087E +:10595000104000173C0980008C880408ACA8001097 +:105960008C83040CACA300143C1900203C1880006C +:10597000AF19003094AE001894AF001C01CF302155 +:10598000A4A6001894AD001A25A70001A4A7001A28 +:1059900094AB001A94AC001E118B000300000000B1 +:1059A00003E000080000000003E00008A4A0001AC3 +:1059B0008D2A0400ACAA00108D240404ACA40014A9 +:1059C0000A0001AA3C1900208CA200200A000192C2 +:1059D0003C0F00500A0001800000000027BDFFE8D6 +:1059E000AFBF00100E0001C4000000008F89002C22 +:1059F0008FBF00103C038000A520000A9528000AF4 +:105A00009527000427BD00183105FFFF30E6000F81 +:105A10000006150000A2202503E00008AC64008009 +:105A20003C0508008CA500208F83000427BDFFE8FB +:105A3000AFB00010AFBF001410A300100000802111 +:105A4000240400010204300400A6202400C3102412 +:105A50005044000626100001001018802787FD9C86 +:105A60001480000A00671821261000012E09000288 +:105A70005520FFF38F830004AF8500048FBF00140F +:105A80008FB0001003E0000827BD00188C680000EC +:105A90003C058000ACA800240E0001C626100001C1 +:105AA0003C0508008CA500200A0001EB2E0900022D +:105AB00024050001008518043C0408008C840020A3 +:105AC00027BDFFC8AFBF003400831024AFBE003035 +:105AD000AFB7002CAFB60028AFB50024AFB400209C +:105AE000AFB3001CAFB20018AFB1001410400051AA +:105AF000AFB000108F84002C948700069488000AB1 +:105B000000E8302330D5FFFF12A0004B8FBF0034D8 +:105B1000948B0018948C000A016C50233142FFFFD3 +:105B200002A2482B1520000202A0202100402021C3 +:105B30002C8F000515E0000200809821241300043A +:105B40000E000153026020218F87002C02609021FB +:105B5000AF80003094F4000A026080211260004E91 +:105B60003291FFFF3C1670003C1440003C1E2000A8 +:105B70003C1760008F9900388F38000003161824F6 +:105B80001074004F0283F82B17E00036000000006D +:105B9000107E00478F86003014C0003A24030001B5 +:105BA00002031023022320213050FFFF1600FFF1D3 +:105BB0003091FFFF8F87002C3C1100203C108000AB +:105BC000AE11003094EB000A3C178000024B5021CC +:105BD000A4EA000A94E9000A94E800043123FFFFD4 +:105BE0003106000F00062D000065F025AEFE008096 +:105BF00094F3000A94F6001812D3003600122140E4 +:105C00008CFF00148CF4001003E468210000C02114 +:105C100001A4782B0298702101CF6021ACED001413 +:105C2000ACEC001002B2382330F5FFFF16A0FFB82D +:105C30008F84002C8FBF00348FBE00308FB7002CB4 +:105C40008FB600288FB500248FB400208FB3001CBE +:105C50008FB200188FB100148FB0001003E000085D +:105C600027BD00381477FFCC8F8600300E000D8BD7 +:105C700002002021004018218F86003010C0FFC98B +:105C800002031023027070238F87002C01C3682148 +:105C90000A00027631B2FFFF8F86003014C0FFC9C0 +:105CA0003C1100203C1080000A000240AE11003080 +:105CB0000E0003C4020020210A00026D00401821DA +:105CC000020020210E0007DB022028210A00026DBD +:105CD000004018210E000180000000000A00025957 +:105CE00002B2382327BDFFD8AFB40020AFB3001CE9 +:105CF000AFB20018AFB10014AFB00010AFBF0024B6 +:105D00000E0000E6241300013C0280083C03200042 +:105D10003C010800AC200070345400803472000351 +:105D20003C1080002411FF800E0001D7000000000D +:105D30008E06000038C5000130A400011480FFFA6F +:105D4000000000008E07010024030C0010E300098E +:105D50003C0580008E0901002D2830805500001080 +:105D60003C0480008E0B01002D6A31811140000C33 +:105D70003C0480008CAC0100118300040000202151 +:105D80008CAE010025CDFF8131A400FF8E0F0100F4 +:105D90000E0001FBAE0F00240A0002C13C0480008B +:105DA0008C9F010024180020AC9F002092990000D5 +:105DB000332300FF1078001F2402005010620022DD +:105DC000000000003C0480008C830100146000038C +:105DD00000000000566000143C0440008C8201006A +:105DE0008C990100000098210051F824001F79408F +:105DF0003338007F01F8702501D26825AC8D08305A +:105E00008C8C01008C890100258B010001715024CC +:105E1000000A39403128007F00E8302500D22825CB +:105E2000AC8508303C044000AE0401380A000299F9 +:105E3000000000008C8501000E00078D2404008006 +:105E40000A0002C13C0480008C8401000E0013EAA9 +:105E5000000000000A0002C13C04800000A4102BD6 +:105E600024030001104000090000302100052840F3 +:105E700000A4102B04A00003000318405440FFFCB2 +:105E8000000528405060000A0004182B0085382BBC +:105E900054E000040003184200C33025008520238D +:105EA000000318421460FFF9000528420004182B73 +:105EB00003E0000800C310213084FFFF30C600FF5C +:105EC0003C0780008CE201B80440FFFE00064C0055 +:105ED000012430253C08200000C820253C03100088 +:105EE000ACE00180ACE50184ACE4018803E000088B +:105EF000ACE301B83C0660008CC5201C2402FFF016 +:105F000030830200308601001060000E00A22824B9 +:105F100034A500013087300010E0000530830C000C +:105F200034A500043C04600003E00008AC85201C9C +:105F30001060FFFD3C04600034A5000803E0000889 +:105F4000AC85201C54C0FFF334A500020A000315E1 +:105F50003087300027BDFFE8AFB00010AFBF00149E +:105F60003C076000240600021080001100A0802180 +:105F70008F8300380E00030C8C6400188F82003869 +:105F800000002021240600018C45000C0E0002FDBB +:105F9000000000001600000224020003000010218F +:105FA0008FBF00148FB0001003E0000827BD001859 +:105FB0008CE8201C2409FFF001092824ACE5201CF2 +:105FC0008F8700380A0003328CE5000C3C02600E1B +:105FD0000080402134460100240900180000000020 +:105FE00000000000000000003C0A00503C0380005C +:105FF00035470200AC68003834640400AC65003CEE +:10600000AC6700308C6C0000318B00201160FFFD0C +:106010002407FFFF2403007F8C8D00002463FFFF13 +:1060200024840004ACCD00001467FFFB24C60004E8 +:1060300000000000000000000000000024A4020096 +:106040000085282B3C0300203C0E80002529FFFF03 +:1060500001054021ADC300301520FFE0008028215C +:1060600003E00008000000008F82003827BDFFD841 +:10607000AFB3001CAFBF0020AFB20018AFB1001427 +:10608000AFB0001094460002008098218C52001896 +:106090002CC300818C4800048C4700088C51000CF4 +:1060A0008C490010106000078C4A00142CC40004B6 +:1060B0001480001330EB000730C5000310A000105F +:1060C000000000002410008B020020210220282163 +:1060D0000E0002FD240600031660000224020003E5 +:1060E000000010218FBF00208FB3001C8FB200185A +:1060F0008FB100148FB0001003E0000827BD002806 +:106100001560FFF12410008B3C0C80003C03002044 +:10611000241F0001AD830030AF9F0030000000005D +:1061200000000000000000002419FFF024D8000F38 +:10613000031978243C1000D0AD88003801F0702598 +:1061400024CD00033C08600EAD87003C358504007B +:10615000AD8E0030000D38823504003C3C038000D9 +:106160008C6B0000316200201040FFFD0000000039 +:1061700010E0000824E3FFFF2407FFFF8CA80000C5 +:106180002463FFFF24A50004AC8800001467FFFB14 +:10619000248400043C04600EAC860038000000003B +:1061A00000000000000000003C0700203C068000CA +:1061B0000120202101402821ACC700300E000342FD +:1061C000000080210E00030C024020210A000382FF +:1061D0000200202127BDFFE0AFB200183092FFFF80 +:1061E000AFB10014AFBF001CAFB000101640000DDF +:1061F000000088210A0003F1022010212405000379 +:10620000508500278CE5000C0000000D262C0001B5 +:106210003191FFFF24EB00200232502B1140001976 +:10622000AF8B00388F820030144000168F87003803 +:106230003C0670003C0320008CE5000000A62024F2 +:10624000148300108F840040000544023C09800044 +:1062500000A980241480FFE9310600FF2CCA000B3E +:106260001140FFEB262C0001000668803C0E080060 +:1062700025CE51C801AE60218D8B00000160000861 +:1062800000000000022010218FBF001C8FB20018F8 +:106290008FB100148FB0001003E0000827BD00206C +:1062A0000E0002FD240400841600FFD88F870038FA +:1062B0000A0003D2AF800040020028210E00032410 +:1062C000240400018F8700380A0003D2AF82004007 +:1062D000020028210E000324000020210A000401EE +:1062E0008F8700380E000369020020218F87003855 +:1062F0000A0003D2AF82004030AFFFFF000F19C089 +:106300003C0480008C9001B80600FFFE3C1920047C +:106310003C181000AC830180AC800184AC990188EA +:10632000AC9801B80A0003D3262C000190E20002C9 +:1063300090FF00030000202100023A0000FF282502 +:10634000240600080E0002FD000000001600FFDD1C +:10635000240200038F870038000010210A0003D2B6 +:10636000AF82004090E50002000020210A000420D6 +:106370002406000994E5000490E9000390E300027C +:10638000000534000009420000C8202500832825AC +:106390002406000A0A0004200000202190E50002E3 +:1063A000000020210A0004202406000B000449C23A +:1063B0003127003F000443423C0280000008204097 +:1063C000240316802CE60020AC43002C24EAFFE0D6 +:1063D0002482000114C0000330A900FF00801021B6 +:1063E000314700FF000260803C0D8000240A00015C +:1063F000018D20213C0B000E00EA2804008B302187 +:1064000011200005000538278CCE000001C5382575 +:1064100003E00008ACC700008CD800000307782414 +:1064200003E00008ACCF000027BDFFE0AFB10014CF +:10643000AFB00010AFBF00183C0760008CE4080844 +:106440003402F0003C1160003083F000240501C0EC +:106450003C04800E00003021106200062410000170 +:106460008CEA08083149F0003928E0000008382B90 +:10647000000780403C0D0200AE2D0814240C16804D +:106480003C0B80008E2744000E000E34AD6C002CB7 +:10649000120000043C0216912405000112050010B0 +:1064A0003C023D6C345800E0AE3844083C11080012 +:1064B0008E31007C8FBF00183C06600000118540C3 +:1064C000360F16808FB100148FB000103C0E020002 +:1064D00027BD0020ACCF442003E00008ACCE08105C +:1064E0003C0218DA345800E0AE3844083C11080089 +:1064F0008E31007C8FBF00183C0660000011854083 +:10650000360F16808FB100148FB000103C0E0200C1 +:1065100027BD0020ACCF442003E00008ACCE08101B +:106520000A00043A240500010A00043A0000282168 +:1065300024020400A7820010A78000080000202188 +:106540003C06080024C654B02405FFFF248900013E +:10655000000440803124FFFF010618212C87002011 +:1065600014E0FFFAAC65000024040400A7840012C4 +:10657000A780000A000020213C06080024C65530F0 +:106580002405FFFF248D00010004608031A4FFFF7B +:10659000018658212C8A00201540FFFAAD650000C5 +:1065A000A7800014A780000CA780000E0000202107 +:1065B0003C06080024C655B02405FFFF24990001BD +:1065C0000004C0803324FFFF030678212C8E0004D2 +:1065D00015C0FFFAADE500003C0560008CA73D004A +:1065E0002403E08F00E310243446014003E0000858 +:1065F000ACA63D002487007F000731C224C5FFFF01 +:10660000000518C2246400013082FFFF000238C078 +:10661000A784001C3C010800AC270030AF800018A4 +:1066200000002821000020210000302124890001E1 +:1066300000A728213124FFFF2CA817011100000317 +:106640002C8300801460FFF924C6000100C02821BB +:10665000AF86001810C0001DA786001624CAFFFFD1 +:10666000000A11423C080800250855B01040000AF5 +:1066700000002021004030212407FFFF248E00016C +:106680000004688031C4FFFF01A860210086582BF8 +:106690001560FFFAAD87000030A2001F50400008CF +:1066A00000043080240300010043C804000410806B +:1066B000004878212738FFFF03E00008ADF800000C +:1066C00000C820212405FFFFAC85000003E000087E +:1066D0000000000030A5FFFF30C6FFFF30A8001FFC +:1066E0000080602130E700FF0005294200005021B2 +:1066F00010C0001D24090001240B00012518000111 +:10670000010B2004330800FF01267826390E0020F3 +:106710002DED00012DC2000101A218251060000D11 +:10672000014450250005C880032C40210100182198 +:1067300010E0000F000A20278D040000008A1825B1 +:10674000AD03000024AD00010000402100005021F5 +:1067500031A5FFFF252E000131C9FFFF00C9102B15 +:106760001040FFE72518000103E0000800000000CA +:106770008D0A0000014440240A000520AC68000096 +:1067800027BDFFE830A5FFFF30C6FFFFAFB0001008 +:10679000AFBF001430E7FFFF000050213410FFFFAF +:1067A0000000602124AF001F00C048212418000110 +:1067B0002419002005E0001601E010210002F94331 +:1067C000019F682A0009702B01AE402411000017B8 +:1067D000000C18800064102110E000058C4B0000B4 +:1067E00000F84004000838230167582400003821CD +:1067F0001540004100004021556000163169FFFF3F +:10680000258B0001316CFFFF05E1FFEC01E0102159 +:1068100024A2003E0002F943019F682A0009702B60 +:1068200001AE40241500FFEB000C18801546000552 +:106830003402FFFF020028210E0005040000382169 +:10684000020010218FBF00148FB0001003E0000879 +:1068500027BD00181520000301601821000B1C0241 +:1068600024080010306A00FF15400005306E000F4C +:10687000250D000800031A0231A800FF306E000F3A +:1068800015C00005307F0003251000040003190225 +:10689000320800FF307F000317E00005386900016F +:1068A0002502000200031882304800FF3869000109 +:1068B0003123000110600004310300FF250A0001AC +:1068C000314800FF310300FF000C694001A3402163 +:1068D000240A000110CAFFD53110FFFF246E000109 +:1068E00031C800FF1119FFC638C900012D1F002053 +:1068F00053E0001C258B0001240D00010A000597C0 +:10690000240E002051460017258B000125090001A7 +:10691000312800FF2D09002051200012258B000195 +:1069200025430001010D5004014B102425090001ED +:106930001440FFF4306AFFFF3127FFFF10EE000C18 +:106940002582FFFF304CFFFF000050213410FFFF75 +:10695000312800FF2D0900205520FFF225430001BA +:10696000258B0001014648260A000551316CFFFFC6 +:1069700000003821000050210A0005A33410FFFF59 +:1069800027BDFFD8AFB0001030F0FFFFAFB100144B +:10699000001039423211FFE000071080AFB3001C35 +:1069A00000B1282330D3FFFFAFB2001830A5FFFF9E +:1069B000008090210260302100442021AFBF0020E0 +:1069C0000E00052F3207001F022288213403FFFF2B +:1069D00002402021020028210260302100003821DD +:1069E000104300093231FFFF022010218FBF002029 +:1069F0008FB3001C8FB200188FB100148FB000103D +:106A000003E0000827BD00280E00052F000000004D +:106A100000408821022010218FBF00208FB3001C6E +:106A20008FB200188FB100148FB0001003E000087F +:106A300027BD0028000424003C036000AC603D0832 +:106A400010A00002348210063482101603E0000801 +:106A5000AC623D0427BDFFE0AFB00010309000FFF6 +:106A60002E020006AFBF001810400008AFB100149E +:106A7000001030803C030800246351F400C3282137 +:106A80008CA400000080000800000000000020210D +:106A90008FBF00188FB100148FB00010008010213C +:106AA00003E0000827BD0020979100161620005132 +:106AB000000020213C020800904200330A00060A30 +:106AC00000000000978D001215A000310000202169 +:106AD0000A00060A240200089787001014E0001A32 +:106AE0000000182100602021240200011080FFE92D +:106AF0008FBF0018000429C20045302100A6582B82 +:106B00001160FFE43C0880003C072000000569C0DC +:106B100001A76025AD0C00203C0380082402001F63 +:106B20002442FFFFAC6000000441FFFD2463000429 +:106B300024A5000100A6702B15C0FFF5000569C053 +:106B40000A0005F48FBF0018978700083C0408006E +:106B5000248454B0240504000E0005AF240600016F +:106B6000978B001024440001308AFFFF2569FFFF46 +:106B70002D4804000040282115000040A78900107E +:106B800024AC3800000C19C00A000608A7800008D1 +:106B90009787000A3C04080024845530240504002B +:106BA0000E0005AF2406000197990012244400014D +:106BB0003098FFFF272FFFFF2F0E04000040882191 +:106BC00015C0002CA78F0012A780000A3A0200030C +:106BD000262401003084FFFF0E0005DC2C45000157 +:106BE0000011F8C027F00100001021C00A00060AB9 +:106BF000240200089785001A9787000E3C040800BD +:106C0000248455B00E0005AF2406000197870016B6 +:106C10008F8900182445000130A8FFFF24E3FFFFFF +:106C20000109302B0040802114C00018A7830016F2 +:106C3000A780000E9785001C0E000E1E020020216A +:106C4000244A05003144FFFF0E0005DC2405000145 +:106C50003C05080094A500320E000E1E0200202103 +:106C6000244521003C020800904200330A00060A35 +:106C7000000521C00A000642A784000A24AC38009F +:106C8000000C19C00A000608A78400080A00065C68 +:106C9000A785000E308400FF27BDFFE82C82000688 +:106CA000AFBF0014AFB000101040001500A0382195 +:106CB000000440803C0308002463520C0103282197 +:106CC0008CA40000008000080000000024CC007F9D +:106CD000000751C2000C59C23170FFFF2547C400A4 +:106CE00030E5FFFF27840008020030210E00050474 +:106CF000240700019786001402062021A7840014AF +:106D00008FBF00148FB0001003E0000827BD0018EB +:106D10003C0508008CA50030000779C20E0002E691 +:106D200025E4DF003045FFFF3C040800248455B013 +:106D3000240600010E00050424070001978E0016AA +:106D40008FBF00148FB0001025CD000127BD0018A3 +:106D500003E00008A78D00160007C9C22738FF000E +:106D6000001878C231F0FFFF3C040800248455303D +:106D700002002821240600010E000504240700015A +:106D8000978D0012260E0100000E840025AC000134 +:106D90003C0B6000A78C0012AD603D083604000675 +:106DA000000030213C0760008CE23D04305F0006AB +:106DB00017E0FFFD24C9000100061B00312600FF7B +:106DC000006440252CC50004ACE83D0414A0FFF687 +:106DD0008FBF00148FB0001003E0000827BD00181B +:106DE000000751C22549C8002406000124070001FC +:106DF0003C040800248454B00E0005043125FFFF34 +:106E0000978700108FBF00148FB0001024E6000198 +:106E100027BD001803E00008A78600103084FFFF9C +:106E200030A5FFFF3C0680008CC201B80440FFFE85 +:106E30003C084080008838253C031000ACC001802D +:106E4000ACC50184ACC7018803E00008ACC301B83D +:106E50003084FFFF3C0680008CC201B80440FFFE76 +:106E60003C0840388CA70000008828253C0310000F +:106E7000ACC70180ACC5018803E00008ACC301B811 +:106E80008F8300588F8600501066000B00804021D1 +:106E90003C07080024E755C0000328C000A71021C4 +:106EA0008C44000024630001108800053063000F4B +:106EB0005466FFFA000328C003E000080000102118 +:106EC0003C07080024E755C400A7302103E0000870 +:106ED0008CC200003C039000346200010082202537 +:106EE0003C038000AC6400208C65002004A0FFFE01 +:106EF0000000000003E00008000000003C028000E9 +:106F0000344300010083202503E00008AC44002046 +:106F100027BDFFE0AFB100143091FFFFAFB000100C +:106F2000AFBF00181220001200A080218CA5000025 +:106F300014A00011240400023C0680008CC201B899 +:106F40000440FFFE3C074000022720258FBF0018A9 +:106F50008FB100148FB000103C03100027BD00203B +:106F6000ACC50180ACC4018803E00008ACC301B823 +:106F70000A00071D8CA500000E00067424060200FE +:106F8000000028210A00071DAE0000003087FFFF27 +:106F90003C0680008CC201B80440FFFE3C0A40065B +:106FA0008CA9000000EA4025ACC901808CA4000433 +:106FB0003C031000ACC40184ACC8018803E00008A5 +:106FC000ACC301B88F83FD9427BDFFE8AFBF0014A9 +:106FD000AFB00010906700080080102100802821C9 +:106FE00030E600400000202110C000088C50000056 +:106FF0000E00008802002021020020218FBF001413 +:107000008FB000100A00049727BD00180E00073249 +:10701000000000000E000088020020210200202154 +:107020008FBF00148FB000100A00049727BD00180E +:1070300027BDFFE0AFB000108F90FD94AFBF001CE4 +:10704000AFB20018AFB10014920600010080882191 +:107050000E00070430D2000492040005001129C27A +:10706000A605000034830040A20300050E00070EB1 +:10707000022020210E000499022020212402000178 +:10708000AE02000C02202821A602001024040002F7 +:10709000A602001224060200A60200140E000674C6 +:1070A000A60200161640000F8FBF001C978C0054DC +:1070B0003C0B08008D6B00782588FFFF3109FFFF2E +:1070C000256A0001012A382B10E00006A788005429 +:1070D0003C0F6006240E001635ED0010ADAE0050DA +:1070E0008FBF001C8FB200188FB100148FB000103A +:1070F00003E0000827BD002027BDFFE0AFB100146A +:10710000AFBF0018AFB000101080000400A08821AD +:107110002402008010820007000000000000000D23 +:107120008FBF00188FB100148FB0001003E000086B +:1071300027BD00200E00070400A020218F86FD94AB +:107140000220202190C500050E00070E30B000FF80 +:107150002403003E1603FFF1000000003C05800000 +:107160008CA401780480FFFE240800073C0710006F +:10717000ACB1014002202021A0A801448FBF00181B +:107180008FB100148FB00010ACA701780A00075B24 +:1071900027BD002027BDFFE0AFB00010AFBF001833 +:1071A000AFB100143C1080008E11002000000000E0 +:1071B0000E000499AE040020AE1100208FBF00180D +:1071C0008FB100148FB0001003E0000827BD00202D +:1071D0003084FFFF3C0680008CC201B80440FFFEF3 +:1071E0003C084035008838253C031000ACC50180C0 +:1071F000ACC00184ACC7018803E00008ACC301B88F +:107200003084FFFF3C0680008CC201B80440FFFEC2 +:107210003C084036008838253C031000ACC501808E +:10722000ACC00184ACC7018803E00008ACC301B85E +:1072300027BDFFD0AFB500243095FFFFAFB60028C3 +:10724000AFB40020AFBF002CAFB3001CAFB200182A +:10725000AFB10014AFB0001030B6FFFF12A000278E +:107260000000A0218F9200388E4300003C06800071 +:107270002402004000033E0200032C0230E4007FA1 +:10728000006698241482001D30A500FF8F830048FB +:107290002C68000A510000108F86003000035880CF +:1072A0003C0C0800258C5228016C50218D490000AF +:1072B000012000080000000002D4702131C5FFFF4A +:1072C0000E0006D624040084166000028F92003857 +:1072D000AF8000488F860030264F002026890001AD +:1072E00001E090213134FFFF14C00004AF8F00385B +:1072F0000295282B14A0FFDC000000000280102162 +:107300008FBF002C8FB600288FB500248FB40020CB +:107310008FB3001C8FB200188FB100148FB0001013 +:1073200003E0000827BD00302407003414A70146FD +:10733000000000009247000E8F98FD988F90FD94FA +:10734000240F1600A30700199244000D3C0880008A +:107350003C07800CA3040018965F00123C096000F3 +:107360003C117FFFA61F005C965900103622FFFFDC +:10737000240400053325FFFFAE0500548E46001C93 +:10738000AD0F00288CEE00008D2D444801C6182654 +:1073900001A33021AE0600388E0C003824CA00014B +:1073A0003C0D7F00AE0C003C8E0B003CAF0B00048C +:1073B000AE0A00208E130020AE13001CA300001B99 +:1073C000AE02002CA30400128E5F001424130050A0 +:1073D000AE1F00348E190034AF1900148E4500180A +:1073E000AE050048924F000CA20F004E9209000813 +:1073F000352E0020A20E00088E030018006D6024B8 +:10740000358B4000AE0B0018920A0000315200FF8D +:10741000125302A62413FF803C0408002484564023 +:107420000E00074000000000240C000424080001A6 +:107430003C0508008CA556403C048000A20C0025A9 +:10744000A20800058C9001780600FFFE8F9200389C +:10745000240D00023C031000AC850140A08D0144C6 +:10746000AC8301780A000804AF8000482CAD0037D7 +:1074700011A0FF998F860030000580803C11080024 +:1074800026315250021178218DEE000001C0000813 +:10749000000000002410000414B0008E3C0780009F +:1074A0003C0B08008D6B56408F86FD94ACEB0020A2 +:1074B0008E4300088F8FFD98240E0050ACC300301F +:1074C0008E4A0008ACCA00508E42000CACC2003498 +:1074D0008E440010ACC400388E5F0010ACDF005446 +:1074E0008E590014ACD9003C8E580018ADF8000439 +:1074F0008E51001CACD1002090C5000030A900FFC7 +:10750000112E0276000000008CC500348CD10030B2 +:1075100000B1302304C000F32404008C126000F09A +:10752000240200030A000804AF820048240F00056B +:1075300014AF00683C0B80003C0308008C6356408D +:107540008F86FD94AD6300208E4A00048F99FD98CC +:1075500024072000ACCA001C924200082412000834 +:10756000A32200198F840038909F0009A33F0018C0 +:107570008F85003890B8000A330400FF1092001085 +:10758000288C0009158000BC24080002240E00206D +:10759000108E000B34078000288900211520000878 +:1075A0002407400024110040109100053C07000111 +:1075B000240F0080108F00023C07000224074000C7 +:1075C0008CDF00183C04FF0003E4C8240327C02517 +:1075D000ACD8001890B2000BA0D200278F830038DF +:1075E0009465000C10A0022A000000009467000CB3 +:1075F0003C198000240BFFBFA4C7005C9062000E02 +:1076000024070004A0C200088F840038909F000F58 +:10761000A0DF00098F8C00388D9200108F38007425 +:1076200002582823ACC500588D8F0014ACCF002C15 +:10763000959100183229FFFFACC90040958E001AC1 +:1076400031D0FFFFACD000448D8D001CACCD004884 +:1076500095880002A4C800789183000EA0C300089A +:1076600090CA0008014B1024126001D4A0C2000887 +:107670008F9200380A000804AF87004824060006ED +:1076800014A600143C0D80003C1008008E105640DB +:107690008F8CFD90ADB000208E4800188F86FD9431 +:1076A0008F8AFD98AD8800008CC300382404000543 +:1076B000AD8300048CCB003C12600081AD4B000018 +:1076C0000A000804AF840048240E000710AE004BE7 +:1076D000240400063C05080024A556400E000713AC +:1076E000240400818F9200380013102B0A00080434 +:1076F000AF8200482419002314B9FFF63C0B800028 +:107700003C0C08008D8C56408F8AFD98AD6C002093 +:107710008F91FD948E4600042544002026450014D8 +:10772000AE260028240600030E000E2A2550003045 +:107730008F87003802002021240600030E000E2A45 +:1077400024E500083C040800248456400E0007404D +:107750000000000092220000241F0050304400FF6F +:10776000549FFFE18F9200380E000E1500000000BC +:107770000A0009098F9200382403003314A3003251 +:107780003C0280003C1108008E3156408F8EFD98DF +:10779000AC5100208E440008240900288F88FD94F5 +:1077A000ADC400308E5F000C24060009ADDF00344C +:1077B0008E590010ADD900388E580014ADD8002075 +:1077C0008E450018ADC500248E4F001CADCF00289B +:1077D000A1C900118E4D000412600031AD0D0028CA +:1077E0008F9200380A000804AF860048240900225E +:1077F00014A9FFB800000000240400073C0F080093 +:107800008DEF56403C118000AE2F00205660FEB137 +:10781000AF8400483C040800248456400E00074012 +:10782000241300508F98FD9493120000324500FFFE +:1078300010B30169000000008F9200380000202181 +:107840000A000804AF8400483C05080024A55640FF +:107850000E0006E3240400810A0009098F92003813 +:1078600002D498213265FFFF0E0006D6240400845E +:107870000A0008048F9200381088FF512407040082 +:107880002887000310E001A324100004240D000148 +:10789000548DFF4B240740000A0008BF2407010055 +:1078A0003C05080024A556400E000732240400823F +:1078B0008F920038000030210A000804AF8600488B +:1078C0003C040800248456408CC200380E00074057 +:1078D0008CC3003C8F9200380A00095F0000202111 +:1078E000240400823C05080024A556400E000732FF +:1078F000000000008F920038000010210A000804E8 +:10790000AF8200488E5000048F91FD943C0A8000A5 +:10791000AD500020922200050200282130460002CE +:1079200014C001802404008A8F92FD98020028214F +:107930002404008D924B001B3163002014600179F8 +:1079400000000000922D0009240C001231A800FF55 +:10795000110C0174240400810E0007040200202190 +:107960009245001B240E00040200202134A900428D +:10797000A249001B0E00070EA22E00253C04800029 +:107980008C9101780620FFFE24180002AC90014083 +:10799000A09801448F9200383C0F1000AC8F017802 +:1079A0000A00090A0013102B8E5000048F91FD94D9 +:1079B0003C1F8000AFF00020923900050200282112 +:1079C0003327000214E000172404008A92240009DF +:1079D0002412000402002821308600FF10D200117A +:1079E000240400810E000704020020218F8CFD98E2 +:1079F000240B00122403FFFE918D001B02002021A6 +:107A000035A80020A188001BA22B0009922A00059E +:107A1000014310240E00070EA222000502002821B7 +:107A2000000020210E0007CF000000000A00090915 +:107A30008F9200388E5100043C0280003C100800F8 +:107A400026105640AC5100203C010800AC31564095 +:107A50009246000330C40004108001658F84FD94B9 +:107A600024020006A0820009924D001B2408FFC0DA +:107A700031AC003F01885825A08B000892430003D9 +:107A8000306A00011540015C000000008E420008D1 +:107A9000AE0200083C0208008C4256481040015BD0 +:107AA0008F8EFD98000281C28F85FD94A5D0000CB9 +:107AB0008E5F000C240F000124090014ADDF002CA0 +:107AC0008E590010ADD9001C96470016A5C7003C82 +:107AD00096580014A5D8003EACAF000CA4AF00101F +:107AE000A4AF0012A4AF0014A4AF00161260015F8F +:107AF000A1C9001192440003309200022E530001EC +:107B00008F920038266200080A000804AF820048FD +:107B10008E4600043C0580003C048008ACA6002092 +:107B20008E4700089089000024110050312200FF88 +:107B3000105100B8240500883C0480008C8F01B8E7 +:107B400005E0FFFE0013802B3C18400900B810250B +:107B5000AF9000483C101000AC860180AC870184D7 +:107B6000AC820188AC9001B80A0008058F8600300D +:107B70008E4500043C0680003C098008ACC500200E +:107B8000913F00002404005033F900FF132400B09B +:107B9000240600883C0480008C8A01B80540FFFE62 +:107BA0003C0E400E00CE68253C081000AC850180DC +:107BB000AC800184AC8D0188AC8801B8912B0000A9 +:107BC000240CFF8024040004016C182524060030D6 +:107BD0000E000674A12300000A0009098F920038E4 +:107BE0008E5000048F91FD983C0F8000ADF0002076 +:107BF0009225001B30A900101120007C2403008175 +:107C00003C0480008C8701B804E0FFFE3C1F401F4D +:107C1000AC900180007F10250013C82B3C10100091 +:107C2000AC800184AF990048AC820188AC9001B867 +:107C30000A0008058F8600308E44001C0E0006EFF7 +:107C400000000000104000F8004038218F920038FA +:107C5000240600893C0580008CAE01B805C0FFFEFB +:107C600000000000ACA701808E50001C3C114001B8 +:107C70000013782B00D138253C131000ACB00184E0 +:107C8000AF8F0048ACA70188ACB301B80A00080563 +:107C90008F860030965900023C100800261056408E +:107CA00033380004130000A33C0460008E5F001C06 +:107CB0003C068000ACDF00203C010800AC3F564091 +:107CC000964F000231E7000114E000E300000000DD +:107CD0008E420004AE0200083C1008008E10564888 +:107CE000120000D93C0680008F85FD94241000010D +:107CF0008CBF00188F91FD988F89FD9003E6C825F1 +:107D0000ACB90018A0A00005ACB0000C3C180800ED +:107D10008F1856488F870038A4B00010001879C219 +:107D2000A4B00012A4B00014A4B00016A62F000C3A +:107D30008CEE00088F8D00388F8C0038AE2E002C12 +:107D40008DA8000C24070002AE28001C918B0010A7 +:107D5000A22B00118F830038906A0011A12A00081D +:107D60008F82003890440012A0A4004E8F920038F9 +:107D700092460013A22600128F920038965F0014DC +:107D8000A63F003C96590016A639003E8E580018B2 +:107D9000AE3800145660FD4FAF8700483C05080020 +:107DA00024A556400E000713000020218F920038B2 +:107DB000000038210A000804AF8700483C0508008D +:107DC00024A556400E000732240400828F9200380A +:107DD0000A0008EC000038210E000E15000000001B +:107DE0008F9200380A00095F000020210E0007046E +:107DF000020020219232001B020020213658001080 +:107E00000E00070EA238001B8F9200380A000A4F9E +:107E1000000018219243000C306A00011140000359 +:107E200000000000964B000EA48B002C9248000C22 +:107E3000310C00021180FF4000002821964E0012F4 +:107E40008E4D0014A48E001A0A000A1DAC8D001C71 +:107E50008F8300588F8700501067FF4E000030213D +:107E60003C080800250855C4000320C000883021C4 +:107E70008CD10000122500C8246200013043000F9D +:107E80001467FFFA000320C00A000A340000302102 +:107E90003C05080024A556400E0007322404008B40 +:107EA0008F9200380A0008EC0013382B3C0B0800B6 +:107EB0008D6B564024D8FFFE25710100322A007FC9 +:107EC0000147902102331024AD020028AE4600D0B5 +:107ED000AE4000D40A000855AE58001CACC0005497 +:107EE0003C0E08008DCE56403C09800C352C01001C +:107EF000ACEE00288E500014AD9000D08E4D0014D2 +:107F0000AD8D00D48E4800102507FFFE0A000891B1 +:107F1000AD87001C5490FDAA240740000A0008BF4A +:107F2000240710000E0007C3000000000A00090922 +:107F30008F9200388C83442C3C05DEAD34B2BEEF0A +:107F40003C010800AC205640107200900000000078 +:107F50003C046C62348279701462000824040002CC +:107F6000978A00549783004C020028210143482B34 +:107F70001120001924040092240400020E0005E4DC +:107F8000240502003C0B8000AD6200203C0108008B +:107F9000AC2256401040000D8F8E0038240C002873 +:107FA0002404000391CD001031A800FF550C0001FE +:107FB000240400010E00004C0000000010400004EA +:107FC000240400830A000A7F8F920038240400836F +:107FD0003C05080024A556400E00071300000000D1 +:107FE0008F9200380013382B0A000804AF8700482E +:107FF0000A0009E8240200128E4400080E0006EF71 +:10800000000000000A0009F4AE0200083C05080068 +:1080100024A556400E0006E3240400878F92003802 +:108020000A000A110013102B240400040E0005E4BA +:108030002405003014400014004038218F9200388D +:108040000A000A64240600833C05080024A5564063 +:108050000A000B45240400878E4400040E0006EF3E +:10806000000000000A000A85AE0200083C05080076 +:1080700024A556400E000732240400828F92003857 +:108080000A000A11000010218F9200383C08800875 +:108090003C0C8000240B0050240A0001AD8200201B +:1080A000A10B0000A10A000192490004A1090018D7 +:1080B00092440005A1040019924300063C04080004 +:1080C000248455C4A103001A924200073C0308000F +:1080D000246355C0A102001B92450008A105001CA5 +:1080E00092460009A106001D925F000AA11F001E12 +:1080F0009259000BA119001F9258000CA1180020E2 +:108100009251000DA11100219250000EA1100022E9 +:10811000924F000FA10F0023924E0010A10E0024D9 +:10812000924D0011A10D0025964C0014A50C0028BD +:10813000964B00168F8A00508F980058A50B002A86 +:1081400096490018000A10C025450001A509002C19 +:108150008E46001C0044C8210043F82130A5000FC2 +:10816000AFE60000AF27000010B80003AF85005055 +:108170000A000A640000302124AD000131A8000F7C +:10818000000030210A000A64AF8800588C83442C18 +:108190000A000B243C046C623C07080024E755C02D +:1081A00000879021ACC00000000030210A000A3492 +:1081B000AE4000003C0482013C03600034820E02A9 +:1081C000AC603D68AF80007803E00008AC623D6CB5 +:1081D00027BDFFE8AFB000103090FFFF001018423D +:1081E0002C620041AFBF0014144000022404008040 +:1081F000240300403C010800AC3000603C01080052 +:10820000AC2300640E000E1E00602821244802BF2B +:108210002409FF8001092824001039800010304013 +:108220008FBF00148FB0001000A7202100861821F6 +:10823000AF8300603C010800AC2500583C010800F9 +:10824000AC24005C03E0000827BD0018308300FF69 +:1082500030C6FFFF30E400FF3C0880008D0201B80B +:108260000440FFFE00035400014438253C0960002F +:1082700000E920253C031000AD050180AD06018416 +:10828000AD04018803E00008AD0301B88F86003813 +:108290003C096012352700108CCB00043C0C600EAA +:1082A00035850010316A00062D480001ACE800C495 +:1082B0008CC40004ACA431808CC2000894C30002BA +:1082C000ACA2318403E00008A78300708F850038DA +:1082D0008F87FF208F86FF288CAE00043C0F601232 +:1082E00035E80010ACEE00688CAD0008ACED006C19 +:1082F0008CAC0010ACCC004C8CAB000CACCB004870 +:1083000094CA00543C0208008C42004425490001F4 +:10831000A4C9005494C400543083FFFF10620017B6 +:10832000000000003C0208008C420040A4C2005241 +:108330008CA30018ACE300308CA20014ACE2002C3B +:108340008CB90018ACF900388CB800142405000171 +:10835000ACF800348D0600BC50C500198D0200B485 +:108360008D0200B8A4E2004894E40048A4E4004A66 +:1083700094E800DA03E000083102FFFF3C02080045 +:108380008C420024A4C00054A4C200528CA3001844 +:10839000ACE300308CA20014ACE2002C8CB90018C5 +:1083A000ACF900388CB8001424050001ACF8003496 +:1083B0008D0600BC54C5FFEB8D0200B88D0200B4E1 +:1083C000A4E2004894E40048A4E4004A94E800DAF7 +:1083D00003E000083102FFFF8F8600383C04800074 +:1083E0008CC900088CC80008000929C0000839C0E1 +:1083F000AC87002090C30007306200041040003AB0 +:10840000AF85007490CB0007316A00081140003935 +:108410008F87FF248CCD000C8CCE001401AE602B16 +:1084200011800032000000008CC2000CACE2007031 +:108430008CCB00188F85FF208F88FF28ACEB007451 +:108440008CCA00102402FFF8ACAA00C88CC9000C2A +:10845000AD0900608CC4001CACA400C090E3007C9B +:108460000062C824A0F9007C90D80007330F0008F0 +:1084700011E000040000000090ED007C35AC00012C +:10848000A0EC007C90CF000731EE000111C0000984 +:108490000000000090E4007C2418000234820002F6 +:1084A000A0E2007C90A300EC307900FF13380013A9 +:1084B0002408003490C900073126000210C00004CF +:1084C0000000000090EB007C356A0004A0EA007C0C +:1084D00090ED007D31AC003FA0EC007D94A700DA68 +:1084E00003E0000830E2FFFF8F87FF240A000C5AE8 +:1084F0008CC200140A000C5BACE000700A000C7C1B +:10850000ACA800CC8F8C003827BDFFD8AFB3001CBF +:10851000AFB20018AFB00010AFBF0020AFB1001471 +:10852000918F00153C13600E3673001031EB000F75 +:10853000A38B007C8D8F00048D8B0008959F00120B +:10854000959900109584001A9598001E958E001C30 +:1085500033EDFFFF332AFFFF3089FFFF3308FFFFB2 +:1085600031C7FFFF3C010800AC2D00243C0108008E +:10857000AC2900443C010800AC2A0040AE683178C8 +:10858000AE67317C91850015959100163C12601202 +:108590003652001030A200FF3230FFFFAE62318849 +:1085A000AE5000B491830014959F0018240600017A +:1085B0000066C80433F8FFFFAE5900B8AE5800BCDF +:1085C000918E0014AF8F00643C08600631CD00FF2F +:1085D000AE4D00C0918A00159584000E3C07600ADC +:1085E000314900FFAF8B00683084FFFFAE4900C8FF +:1085F000351100100E000BC334F004103C020800CB +:108600008C4200603C0308008C6300643C06080058 +:108610008CC600583C0508008CA5005C8F84006067 +:108620008FBF0020AE23004CAE65319CAE030054DA +:10863000AE4500DCAE6231A0AE6331A4AE663198C7 +:10864000AE2200488FB3001CAE0200508FB1001460 +:10865000AE4200E0AE4300E4AE4600D88FB000105A +:108660008FB200180A0004CC27BD0028978500723D +:108670009783005C27BDFFE8AFB0001000A3102B6C +:10868000AFBF0014240400058F900038104000553F +:10869000240900020E0005E48F850060AF8200749B +:1086A000240400031040004F240900023C0680000F +:1086B0000E00004CACC2002024070001240820005A +:1086C0001040004D24040005978E00728F8AFF240D +:1086D0002409005025C50001A7850072A1490000AA +:1086E0003C0D08008DAD0064240380008F84FF20C2 +:1086F000000D6600AD4C0018A5400006954B000A21 +:108700008F85FF282402FF8001633024A546000ADC +:10871000915F000A0000482103E2C825A159000A20 +:10872000A0A00008A140004CA08000C5961800023F +:10873000978300703C020004A49800DA960F0002B0 +:108740002418FFBF25EE2401A48E00AE8E0D000478 +:10875000ACAD00448E0C0008ACAC0040A4A00050AE +:10876000A4A000548E0B000C240C0030AC8B00280D +:108770008E060010AC860024A480003EA487004E24 +:10878000A4870050A483003CAD420074AC8800C8AC +:10879000ACA80060A08700EC909F00C433F9007F74 +:1087A000A09900C4909000C402187824A08F00C43F +:1087B000914E007C35CD0001A14D007C938B007C57 +:1087C000AD480070AC8C00CCA08B00C68F880068D0 +:1087D0008F870064AC8800B4AC8700B8A5400078EF +:1087E000A540007A8FBF00148FB000100120102127 +:1087F00003E0000827BD00188F8500740E00067482 +:108800008F8600600A000D482409000227BDFFE0A2 +:10881000AFB000108F900038AFB10014AFBF001898 +:108820008E0900040E000499000921C08E0800047E +:108830008F84FF208F82FF28000839C03C0680000B +:10884000ACC70020948500DA904300131460001C2C +:1088500030B1FFFF8F8CFF24918B0008316A0040FC +:108860001540000B000000008E0D00040220302196 +:108870008FBF00188FB100148FB0001024040022A5 +:1088800000003821000D29C00A000BE227BD00209E +:108890000E000063000000008E0D00040220302155 +:1088A0008FBF00188FB100148FB000102404002275 +:1088B00000003821000D29C00A000BE227BD00206E +:1088C0000E00005B000000008E0D0004022030212D +:1088D0008FBF00188FB100148FB000102404002245 +:1088E00000003821000D29C00A000BE227BD00203E +:1088F00027BDFFE0AFB200183092FFFFAFB000100D +:10890000AFBF001CAFB100141240001E0000802158 +:108910008F8600388CC500002403000600053F0246 +:108920000005140230E4000714830016304500FFF0 +:108930002CA8000611000040000558803C0C0800DF +:10894000258C532C016C50218D490000012000081A +:10895000000000008F8E0078240D000111CD005022 +:1089600024020002AF820078260900013130FFFFA7 +:1089700024C800200212202B010030211480FFE5C2 +:10898000AF880038020010218FBF001C8FB2001882 +:108990008FB100148FB0001003E0000827BD002045 +:1089A0009387005E54E00034000030210E000C90EC +:1089B000000000008F8600380A000DA82402000184 +:1089C0008F8700782405000210E50031240400138D +:1089D0000000282100003021240700010E000BE2D6 +:1089E000000000000A000DA98F8600388F830078F0 +:1089F000240200021462FFF6240400120E000C454B +:108A0000000000008F850074004030212404001213 +:108A10000E000BE2000038210A000DA98F860038F5 +:108A20008F8300782411000310710029241F000295 +:108A3000107FFFCE26090001240400100000282129 +:108A4000000030210A000DC6240700018F91007834 +:108A5000240600021626FFF9240400100E000CEA7A +:108A600000000000144000238F9800388F860038E3 +:108A70000A000DA824020003240400140E000BE2D7 +:108A8000000028218F8600380A000DA82402000269 +:108A90000E000D52000000000A000DA98F8600385C +:108AA0000E000BF200000000241900022404001440 +:108AB000000028210000302100003821AF99007803 +:108AC0000E000BE2000000000A000DA98F8600389E +:108AD0000E000C02000000008F85007424190002B3 +:108AE0000040302124040010000038210A000DFF4E +:108AF000AF9900780040382124040010970F00023D +:108B0000000028210E000BE231E6FFFF8F860038BF +:108B10000A000DA9AF9100788F84FF243C077FFFE6 +:108B200034E6FFFF8C8500182402000100A61824FB +:108B3000AC83001803E00008A08200053084FFFF2A +:108B400030A5FFFF108000070000182130820001CF +:108B50001040000200042042006518211480FFFB31 +:108B60000005284003E000080060102110C0000745 +:108B7000000000008CA2000024C6FFFF24A5000412 +:108B8000AC82000014C0FFFB2484000403E0000852 +:108B90000000000010A0000824A3FFFFAC86000026 +:108BA00000000000000000002402FFFF2463FFFF1C +:108BB0001462FFFA2484000403E0000800000000AF +:108BC000000411C003E000082442024027BDFFE872 +:108BD000AFB0001000808021AFBF00140E000E3F28 +:108BE00000A0202100504821240AFF808FBF0014DC +:108BF0008FB00010012A30243127007F3C08800A02 +:108C00003C04210000E8102100C428253C0380001A +:108C100027BD0018AC650024AF820024AC400000E2 +:108C2000AC65002403E00008AC4000403C0D0800A7 +:108C30008DAD005800056180240AFF8001A45821F1 +:108C4000016C4821012A30243127007F3C08800C28 +:108C50003C04210000E8102100C428253C038000CA +:108C6000AC650028AF82002003E00008AC4000247F +:108C700030A5FFFF3C0680008CC201B80440FFFE17 +:108C80003C08601500A838253C031000ACC40180E6 +:108C9000ACC00184ACC7018803E00008ACC301B8D4 +:108CA0003C0D08008DAD005800056180240AFF804E +:108CB00001A45821016C4021010A482400093140D7 +:108CC0003107007F00C728253C04200000A4182598 +:108CD0003C028000AC43083003E00008AF80002075 +:108CE00027BDFFE8AFB0001000808021AFBF0014A7 +:108CF0000E000E3F00A0202100504821240BFF80D1 +:108D0000012B5024000A39403128007F3C06200006 +:108D10008FBF00148FB0001000E8282534C2000176 +:108D200000A218253C04800027BD0018AC83083041 +:108D300003E00008AF8000243C0580088CA7006099 +:108D40003C0680080087102B144000112C83400043 +:108D50008CA800602D0340001060000F2403400029 +:108D60008CC900600089282B14A000020080182103 +:108D70008CC3006000035A42000B30803C0A08009C +:108D8000254A53A000CA202103E000088C8200007D +:108D90001460FFF32403400000035A42000B3080AC +:108DA0003C0A0800254A53A000CA202103E000081D +:108DB0008C8200003C05800890A6000893840088FF +:108DC00024C20001304200FF3043007F1064000CD9 +:108DD00000023827A0A200083C0480008C8501789E +:108DE00004A0FFFE8F8A0080240900023C081000C6 +:108DF000AC8A0140A089014403E00008AC880178F6 +:108E00000A000EC430E2008027BDFFD8AFB20018C0 +:108E10008F920084AFBF0020AFB3001CAFB0001032 +:108E2000AFB100148F9300208E5900283C100080B1 +:108E30003C0EFFEFAE7900008E580024A260000ABD +:108E400035CDFFFFAE7800049251002C3C0BFF9F04 +:108E5000356AFFFFA271000C8E6F000C3C080040C9 +:108E6000A271000B01F06025018D4824012A3824ED +:108E700000E83025AE66000C8E450004AE60001898 +:108E80003C0400FFAE6500148E43002C3482FFFFCB +:108E9000A66000080062F824AE7F00108E5900081A +:108EA0008F900080964E0012AE7900208E51000CFB +:108EB00031D83FFF00187980AE7100248E4D001428 +:108EC00001F0602131CB0001AE6D00288E4A001800 +:108ED000000C41C2000B4B80AE6A002C8E46001C79 +:108EE00001093821A667001CAE66003096450002D5 +:108EF0008E440020A665001EAE6400349243003309 +:108F00003062000454400006924700003C02800892 +:108F1000344301008C7F00C0AE7F003092470000D8 +:108F20008F860024A0C700309245003330A4000291 +:108F300050800007925100018F880024240BFF808D +:108F4000910A0030014B4825A109003092510001DF +:108F50008F900024240CFFBF2404FFDFA2110031F6 +:108F60008F8D00243C1880083711008091AF003CA1 +:108F700031EE007FA1AE003C8F890024912B003C94 +:108F8000016C5024A12A003C8F9F00248E6800149D +:108F900093E6003C2D0700010007114000C428247F +:108FA00000A21825A3E3003C8F87002496590012E5 +:108FB000A4F900328E450004922E007C30B00003EC +:108FC0000010782331ED000300AD102131CC0002F8 +:108FD0001580000224460034244600303C028008FC +:108FE00034430080907F007C00BFC82433380004E5 +:108FF0001700000224C2000400C010218F98002432 +:1090000024190002ACE20034A3190000924F003F83 +:109010008F8E00243C0C8008358B0080A1CF00018E +:109020008F910024924D003F8E440004A62D000233 +:10903000956A005C0E000E9D3150FFFF00024B80D0 +:10904000013038253C08420000E82825AE25000400 +:109050008E4400388F850024ACA400188E4600345E +:10906000ACA6001CACA0000CACA00010A4A0001486 +:10907000A4A00016A4A00020A4A00022ACA000245C +:109080008E62001450400001240200018FBF0020B6 +:109090008FB3001C8FB200188FB100148FB0001076 +:1090A000ACA200080A000EBC27BD002827BDFFC8DF +:1090B0003C05800834A40080AFBF0034AFBE003050 +:1090C000AFB7002CAFB60028AFB50024AFB4002076 +:1090D000AFB3001CAFB20018AFB10014AFB00010B6 +:1090E000948300789482007A104300512405FFFF96 +:1090F0000080F0210A000FCC0080B821108B004DB9 +:109100008FBF00348F8600803C1808008F18005CE9 +:109110002411FF803C1680000306782101F1802491 +:10912000AED0002C96EE007A31EC007F3C0D800E24 +:1091300031CB7FFF018D5021000B4840012AA8212F +:1091400096A400003C0808008D0800582405FF8004 +:1091500030953FFF01061821001539800067C821AE +:109160000325F8243C02010003E290253338007FF8 +:109170003C11800CAED20028031190219250000DBA +:10918000320F000411E0003702E0982196E3007AE4 +:1091900096E8007A96E5007A2404800031077FFF84 +:1091A00024E3000130627FFF00A4F82403E2C82515 +:1091B000A6F9007A96E6007A3C1408008E940060C6 +:1091C00030D67FFF12D400C1000000008E58001876 +:1091D0008F84008002A028212713FFFF0E000E7746 +:1091E000AE53002C97D5007897D4007A12950010D2 +:1091F000000028213C098008352401003C0A800831 +:1092000091480008908700C53114007F30E400FFCA +:109210000284302B14C0FFB9268B0001938E008886 +:10922000268C0001008E682115ACFFB78F86008068 +:109230008FBF00348FBE00308FB7002C8FB6002850 +:109240008FB500248FB400208FB3001C8FB200189C +:109250008FB100148FB0001000A0102103E00008AF +:1092600027BD003800C020210E000E4202802821B8 +:109270008E4B00108E4C00308F8400242409000295 +:10928000016C5023AE4A0010A089000096E3005CF8 +:109290008E4400308F9100240E000E9D3070FFFF31 +:1092A00000024380011028253C07420000A710253A +:1092B000AE2200048E5F00048F8A00248E590000C5 +:1092C000240B0008AD5F001CAD590018AD40000C28 +:1092D000AD4000109246000A240400052408C00096 +:1092E00030D000FFA550001496580008A55800166D +:1092F0009251000A3C188008322F00FFA54F002031 +:10930000964E000837110100A54E0022AD40002402 +:10931000924D000B31AC00FFA54C0002A14B0001A7 +:109320008E4900308F830024240BFFBFAC690008F6 +:10933000A06400308F9000242403FFDF96070032E2 +:1093400000E8282400B51025A6020032921F003242 +:1093500033F9003F37260040A20600328F8C0024EC +:10936000AD8000348E2F00C0AD8F0038918E003C50 +:109370003C0F7FFF31CD007FA18D003C8F84002406 +:1093800035EEFFFF908A003C014B4824A089003C49 +:109390008F85002490A8003C01033824A0A7003C3E +:1093A0008E4200348F9100243C038008AE2200409E +:1093B0008E59002C8E5F0030033F3023AE260044D0 +:1093C000923000483218007FA23800488F8800246D +:1093D0008E4D00308D0C004801AE5824019650246B +:1093E000014B4825AD0900489244000AA104004CF5 +:1093F000964700088F850024A4A7004E8E500030A9 +:109400008E4400300E0002E68C65006092F9007C0C +:109410000002F940004028210002110003E230213F +:109420003336000212C00003020680210005B0801E +:1094300002168021926D007C31B30004126000029C +:1094400000057080020E80218E4B003024058000C4 +:10945000316A0003000A4823312400030204182162 +:109460008F900024AE03003496E4007A96E8007AE8 +:1094700096F1007A31077FFF24E20001305F7FFF21 +:109480000225C824033F3025A6E6007A96F8007A24 +:109490003C1208008E520060330F7FFF11F200185B +:1094A000000000008F8400800E000E7702A02821AB +:1094B0008F8400800E000E87028028210E000EBCD3 +:1094C000000000000A000FC80000000096F1007ABA +:1094D00002248024A6F0007A92EF007A92EB007AC0 +:1094E00031EE00FF000E69C2000D6027000C51C074 +:1094F0003169007F012A20250A000FC2A2E4007A08 +:1095000096E6007A00C5C024A6F8007A92EF007AA9 +:1095100092F3007A31F200FF001271C2000E682748 +:10952000000DB1C0326C007F01962825A2E5007ABB +:109530000A0010798F8400803C0380003084FFFF94 +:1095400030A5FFFFAC640018AC65001C03E0000808 +:109550008C62001427BDFFA83C068008AFBE0050F7 +:10956000AFBF0054AFB7004CAFB60048AFB5004432 +:10957000AFB40040AFB3003CAFB20038AFB100347D +:10958000AFB0003034C80100910500C590C7000895 +:10959000309EFFFF30A500FF30E2007F0045182A13 +:1095A000A7A00014A7A0001E10600053AFA00010D9 +:1095B00090C900083126007F00A620232493FFFFD6 +:1095C0000013802B001E882B0211782451E00084A8 +:1095D0008FB300103C19800897360052973700501F +:1095E000001EC40002D7A8230015A4000014140311 +:1095F00003C2902A1640000200182C0300402821C4 +:10960000001314000002240300A4F82A57E000010C +:1096100000A0202128830009146000020080A021FE +:10962000241400083C0A80088D4500480014498035 +:109630008D48004C3C0380003124FFFF3C060010A5 +:109640000086382534710400AC650038AF91008481 +:10965000AC68003CAC670030000000000000000077 +:1096600000000000000000000000000000000000FA +:1096700000000000000000008C6C0000318B002016 +:109680001160FFFD0014682A01B010241040003959 +:109690000000A8213C16800892D700083C128000E8 +:1096A0008E44010032F6007F0E000E4202C02821D7 +:1096B0008E2F00108E4401000000902131F73FFFF3 +:1096C0000E000E5A02E02821922E000031C2003F07 +:1096D0002C50000852000010000088210002F88081 +:1096E0003C0308002463535403E3C8218F3800006F +:1096F000030000080000000090CE0008938B008853 +:1097000031CD007F00AD6023016C50210A0010BFF5 +:109710002553FFFF000088213C1080008E040100CB +:109720000E000E7702E028218E0401000E000E8745 +:1097300002C028211220000F0013802B8F8A008482 +:1097400026A900010009AC00027298230015AC03A1 +:109750002545004002B4B02A0013802B24170001D5 +:1097600000A0882102D01024AF8500841440FFC9D6 +:10977000AFB700103C07800894F100503C05800012 +:109780003C06002002B1C821A4F90050ACA600306C +:1097900094F4005094E3005203D560231074001D2C +:1097A000319EFFFF8CE5004C8CE90048001561807C +:1097B00000ACB0210000A02102CCA82B0134502124 +:1097C0000155B821ACF6004CACF70048001E882BC0 +:1097D0000211782415E0FF803C1980088FB3001037 +:1097E0008FBF00548FBE00503A6200018FB7004C0B +:1097F0008FB600488FB500448FB400408FB3003C53 +:109800008FB200388FB100348FB0003003E0000811 +:1098100027BD005894F200548CEF0044325FFFFEE5 +:10982000001FC0C001F87021ACAE003C8CEB0044BE +:109830008CAD003C016D40231900003B000000008E +:109840008CE20040244200013C07005034E4001048 +:109850003C038000ACA20038AC6400300000000083 +:1098600000000000000000000000000000000000F8 +:109870000000000000000000000000008C760000E6 +:1098800032D7002012E0FFFD3C11800896280054DA +:109890003C0A80003C06800831190001001960C0B4 +:1098A000018AA0218E8304003C0708008CE7004455 +:1098B0003C150020ACC300488E8904042405000137 +:1098C000ACC9004C10E50259AD550030963F00522E +:1098D0003C0508008CA5004000BFC021A6380052FE +:1098E000962F005425EE0001A62E00549626005413 +:1098F00030C4FFFF5487FF34001E882B30A5FFFFC4 +:109900000E00109DA62000543C0408008C84002406 +:10991000962700520044102300E29023A632005202 +:109920000A0010C1001E882B8CE200400A00116260 +:109930003C07005092280001240700013102007FFB +:109940001447001C97AC001E8E2A0014240BC00084 +:1099500031443FFF018B48243C0608008CC6006060 +:109960000124282530A43FFF0086882B12200011F7 +:10997000A7A5001E3C1108008E3100588F82008080 +:10998000000441802407FF80022218210068F8218A +:1099900003E7C82433EF007F3C1880003C12800EA0 +:1099A000AF19002C01F2682191AE000D35D00004F2 +:1099B000A1B0000D0E000ED12412000124110001EF +:1099C0003C1080008E0401000E000E7702E028217A +:1099D0008E0401000E000E8702C028211620FF58B9 +:1099E0008F8A00840A00112C0013802B8F8600843C +:1099F00090C900013125002010A0018A2410000127 +:109A00003C048008348C0080918B007C8F91002076 +:109A100000009021316A00011140000FAFB000201A +:109A20008CD000148C8E0060020E682B15A00003F1 +:109A3000020038218C8700603C0480083483008059 +:109A40008C72007000F2782B15E0000200E02021FB +:109A50008C640070008090213C07800834E5008011 +:109A60008CD900148CBF0070033FC02B170000027C +:109A7000032020218CA400700092182310600003A2 +:109A8000AFA3002824080002AFA800208FA5002063 +:109A90000265102B144000B5000018218CC400385A +:109AA0008E2F000C3C180080AE2400008CCE0034B9 +:109AB0003C10FF9F01F86025AE2E000490CB003FC4 +:109AC000360DFFFF018D48243C0A00203C06FFEFC5 +:109AD000A22B000B012A382534C5FFFF00E54024E6 +:109AE0003C0200088F87008401022025AE24000C70 +:109AF0008CE30014AE2000188FAF0028AE230014B2 +:109B00008CF800183C1FFFFB37F9FFFFAE38001C34 +:109B10008CEE000800996824024F8021AE2E0024AC +:109B20008CEC000CAE2D000CA6200038A620003ACC +:109B3000AE30002CAE2C0020AE2000288CEB0014A0 +:109B40008FAA002801724823012A302310C0001177 +:109B5000AE26001090F0003D8E2C00048E2A0000EE +:109B600000106900018D28210000102100AD302B6C +:109B70000142482101264021AE250004AE28000004 +:109B800090E3003DA223000A8F9F008497F900060E +:109B9000A63900088F8A0024240200023C068008AF +:109BA000A142000034C900809525005C02402021BC +:109BB0008F90002430A8FFFF0E000E9DAFA8002458 +:109BC0008FA300240002FB808F8500843C044200A8 +:109BD00003E3C8250324C025AE1800048F840024A5 +:109BE0008CAF0038AC8F00188CAE0034AC8E001CEB +:109BF000AC80000CAC800010A4800014A48000167F +:109C0000A4800020A4800022AC80002490A7003F04 +:109C1000A48700025240018C240700018FAB00286A +:109C20005160000290A2003D90A2003E244C000131 +:109C3000A08C00018F840024AC9200083C1880089E +:109C400037100080920F007C31EE000215C0000238 +:109C500024070034240700308F8500843C088008E6 +:109C60003509008090A300009128007C3259000340 +:109C7000A08300308F9F00848F9000242404000470 +:109C800093F8000100997823240DC000A218003138 +:109C90008F9900248F8E008431E50003972C0032C9 +:109CA00095CB001200F24821018D502431623FFF14 +:109CB00001423025A72600329323003201253821A6 +:109CC00031080004307F003F37E40040A324003215 +:109CD000124000028F85002400E838213C0C8008E7 +:109CE000ACA70034358B01008D6200C02E4400010A +:109CF0002403FFDFACA2003890AA003C0004C94056 +:109D00003146007FA0A6003C8F8900242405FFBFB8 +:109D10009127003C00E54024A128003C8F8F0024BF +:109D200091FF003C03E3C02403198025A1F0003C0F +:109D30008F8B00848F8A00248D6E0020AD4E0040F2 +:109D40008D6D0024AD4D00448D6C0028AD4C004855 +:109D50008D62002C0E000EBCAD42004C8FA6002080 +:109D60002407000210C700118FA300200003202B3E +:109D700000048023027098240060802100609021FC +:109D80000A0011150010882B962700128F8400807E +:109D90000000902130E5FFFFA7A700140E000E6B16 +:109DA000241100010A0011C03C1080003C19800001 +:109DB0003C0280088F240100905800080E000E42DB +:109DC0003305007F8F8E00248FAF00208FA40028E2 +:109DD000A1CF00000E000E9D8F9000248FAD0024B7 +:109DE00000023B803C0B420000ED40258F87008441 +:109DF000010B2025AE0400048CE500388F90002470 +:109E000000005021000A1900AE0500188CEC003447 +:109E10003C087FFF3504FFFFAE0C001C90E9003EBC +:109E20008E1F001C8E1800180009C9000009370297 +:109E300003F968210066102501B9782B030270210F +:109E400001CF5821AE0D001CAE0B0018AE00000C67 +:109E5000AE00001090E5003E8FAF0028240E0005F4 +:109E6000A605001494EC00042405C00001E4582465 +:109E7000A60C001690EA003E01E02021A60A002070 +:109E800094E60004A6060022AE00002490E3003F02 +:109E9000A603000290E9003E90FF003D03E9C823BD +:109EA00027380001A21800018F8D00243C10800883 +:109EB000ADAF0008A1AE00308F9800248F820084DF +:109EC000360F0100970C0032944A00122410FF80D4 +:109ED00000AC382431463FFF00E61825A7030032C6 +:109EE000930900322405FFBF2403FFDF313F003F09 +:109EF00037F90040A31900328F8C00242418FFFF8B +:109F0000AD8000348DEE00C0AD8E0038918D003CE8 +:109F100031A2007FA182003C8F87002490EA003CA0 +:109F200001453024A0E6003C8F9900249329003C91 +:109F30000123F824A33F003C8F8D00243C1F8008A0 +:109F4000ADB80040ADB2004491AF00483C12800073 +:109F500001F07025A1AE00488F8700248F86008411 +:109F60008CEC004801921024004B5025ACEA0048CC +:109F700090C5003EA0E5004C8F8800848F830024AC +:109F800095090004A469004E8FE500600E0002E60A +:109F9000000000008F99FF2C8FAE00280002814046 +:109FA000932F007C0002C1000218682131F20002E8 +:109FB00000402821164000AA01CD30213C0A80082B +:109FC000354300809069007C313F000413E00003BA +:109FD0008FAE00280005608000CC3021240D0004E5 +:109FE0008F90002431C7000301A758233168000374 +:109FF00000C82021AE0400343C068008A6250038A5 +:10A000003C0580008CA4010090D100080E000E8752 +:10A010003225007F0E000EBC000000000A0012AACC +:10A020008FA300208F8500208CC2003824180003E5 +:10A03000A4A00008ACA200008CDF0034A0A0000A9D +:10A040008F920084ACBF00043C040080924F003F1C +:10A05000A0B8000C8CAE000C3C0DFF9FA0AF000B15 +:10A0600001C4402535ABFFFF3C11FFEF8F98008402 +:10A07000010B30243639FFFF00D96024ACAC000C52 +:10A080008F030014971F00128F870080ACA300106D +:10A090008F090014ACA00018ACA00020ACA90014DB +:10A0A000ACA000248F0A001833E93FFF000911809B +:10A0B000ACAA00288F1200080047782133EE000177 +:10A0C000ACB200308F08000C8F990024000F69C2D9 +:10A0D000000E238001A45821241100023C068008B0 +:10A0E000A4AB001CA4A00034ACA8002CA331000039 +:10A0F00034D90080972C005C8F8F00243C034200F1 +:10A10000318AFFFF01433825ADE700048F820084C8 +:10A11000241800012411C0008C5F0038240700348B +:10A12000ADFF00188C520034ADF2001CADE0000C05 +:10A13000ADE00010A5E00014A5E00016A5E00020A9 +:10A14000A5E00022ADE00024A5F00002A1F8000186 +:10A150008F8B00248F8E0084AD70000891CD00009D +:10A16000A16D00308F8800848F8400249105000148 +:10A17000A08500318F920024964C0032019150242A +:10A1800001491825A6430032925F003233E2003FB6 +:10A19000A24200329338007C330F000215E0000227 +:10A1A0008F840024240700303C028008AC870034F0 +:10A1B000345201008E5F00C0240EFFBF02009021C8 +:10A1C000AC9F00389098003C330F007FA08F003C7C +:10A1D0008F880024910D003C01AE5824A10B003C57 +:10A1E0008F86002490D1003C36390020A0D9003C55 +:10A1F0008F8A00848F8500240010882B8D4C0020CE +:10A20000ACAC00408D430024ACA300448D49002831 +:10A21000ACA900488D47002CACA7004C0E000EBC2A +:10A220003C1080000A0011160000000094CD00527E +:10A230003C0B08008D6B0024016D8821A4D10052D5 +:10A240000A0010C1001E882BA08700018F84002403 +:10A25000240D0001AC8D00080A00125F3C18800834 +:10A26000000290800A00133E00D2302127BDFFE09B +:10A270003C0D8008AFB20018AFB00010AFBF001C9B +:10A28000AFB1001435B200808E4C001835A8010023 +:10A29000964B000695A70050910900EC000C560261 +:10A2A000016728233143007F312600FF2402000389 +:10A2B000A3830088AF84008010C2001B30B0FFFF72 +:10A2C000910600EC2412000530C200FF105200334A +:10A2D00000000000160000098FBF001C8FB200189C +:10A2E0008FB100148FB00010240D0C003C0C8000C6 +:10A2F00027BD002003E00008AD8D00240E0010A44F +:10A30000020020218FBF001C8FB200188FB10014F3 +:10A310008FB00010240D0C003C0C800027BD0020E5 +:10A3200003E00008AD8D0024965800789651007A1D +:10A33000924E007D0238782631E8FFFF31C400C01C +:10A34000148000092D1100011600003700000000E4 +:10A350005620FFE28FBF001C0E000F7A00000000A5 +:10A360000A0014068FBF001C1620FFDA0000000050 +:10A370000E000F7A000000001440FFD88FBF001CB1 +:10A380001600002200000000925F007D33E2003FD3 +:10A39000A242007D0A0014068FBF001C950900DA56 +:10A3A0008F86006000802821240400050E000674BA +:10A3B0003130FFFF978300723C0480002465FFFF6B +:10A3C000A78500728C8A01B80540FFFE00000000DE +:10A3D000AC8001808FBF001CAC9001848FB200184C +:10A3E0008FB100148FB000103C0760133C0B1000BD +:10A3F000240D0C003C0C800027BD0020AC87018898 +:10A40000AC8B01B803E00008AD8D00240E0010A451 +:10A41000020020215040FFB18FBF001C925F007DE1 +:10A420000A00143333E2003F0E0010A40200202182 +:10A430001440FFAA8FBF001C12200007000000007C +:10A440009259007D3330003F36020040A242007D29 +:10A450000A0014068FBF001C0E000F7A00000000D7 +:10A460005040FF9E8FBF001C9259007D3330003F4B +:08A470000A00146236020040EC +:08A47800000000000000001BC1 +:10A480000000000F0000000A0000000800000006A5 +:10A4900000000005000000050000000400000004AA +:10A4A00000000003000000030000000300000003A0 +:10A4B0000000000300000002000000020000000293 +:10A4C0000000000200000002000000020000000284 +:10A4D0000000000200000002000000020000000274 +:10A4E0000000000200000002000000020000000264 +:0CA4F0000000000100000001000000015D +:04A4FC0080080100D3 +:10A50000800800808008000000000C0000003080FF +:10A5100008000F4808000FF40800100C0800102075 +:10A520000800103408000F4808000F4808001068A1 +:10A53000080010A0080010B0080010D8080017C8C4 +:10A54000080017C8080018000800180008001814B0 +:10A55000080017E408001A3C08001A0808001A94BA +:10A5600008001A9408001B1C08001A4C80080240BE +:10A57000080021A808001FF4080021D00800226864 +:10A58000080023B808002404080025280800243007 +:10A59000080024B408002064080029D008002974A9 +:10A5A0000800201008002010080020100800259C3A +:10A5B0000800259C08002010080020100800284CE6 +:10A5C00008002010080020100800201008002010AB +:10A5D000080028AC080020100800201008002010F7 +:10A5E000080020100800201008002010080020108B +:10A5F000080020100800201008002010080020107B +:10A600000800201008002010080020100800242452 +:10A6100008002010080020100800291C0800201045 +:10A62000080020100800201008002010080020104A +:10A63000080020100800201008002010080020103A +:10A64000080020100800201008002010080020102A +:10A65000080020100800201008002010080020101A +:10A66000080027700800201008002010080026E4C9 +:10A6700008002640080037880800375C08003728A3 +:10A68000080036FC080036DC08003690800801001F +:10A69000800800808008000080080080080046F0E4 +:10A6A0000800472808004670080046F0080046F0F9 +:0CA6B00008004450080046F008004AC4AE +:04A6BC000A000C760E +:10A6C00000000000000000000000000D72787035EE +:10A6D0002E302E306A330000050000030000000019 +:10A6E0000000000100000000000000000000000069 +:10A6F000000000000000000000000000000000005A +:10A700000000000000000000000000000000000049 +:10A710000000000000000000000000000000000039 +:10A720000000000000000000000000000000000029 +:10A730000000000000000000000000000000000019 +:10A740000000000000000000000000000000000009 +:10A7500000000000000000000000000000000000F9 +:10A7600000000000000000000000000000000000E9 +:10A7700000000000000000000000000000000000D9 +:10A7800000000000000000000000000000000000C9 +:10A7900000000000000000000000000000000000B9 +:10A7A00000000000000000000000000000000000A9 +:10A7B0000000000000000000000000000000000099 +:10A7C0000000000000000000000000000000000089 +:10A7D0000000000000000000000000000000000079 +:10A7E0000000000000000000000000000000000069 +:10A7F0000000000000000000000000000000000059 +:10A800000000000000000000000000000000000048 +:10A810000000000000000000000000000000000038 +:10A820000000000000000000000000000000000028 +:10A830000000000000000000000000000000000018 +:10A840000000000000000000000000000000000008 +:10A8500000000000000000000000000000000000F8 +:10A8600000000000000000000000000000000000E8 +:10A8700000000000000000000000000000000000D8 +:10A8800000000000000000000000000000000000C8 +:10A8900000000000000000000000000000000000B8 +:10A8A00000000000000000000000000000000000A8 +:10A8B0000000000000000000000000000000000098 +:10A8C0000000000000000000000000000000000088 +:10A8D0000000000000000000000000000000000078 +:10A8E0000000000000000000000000000000000068 +:10A8F0000000000000000000000000000000000058 +:10A900000000000000000000000000000000000047 +:10A910000000000000000000000000000000000037 +:10A920000000000000000000000000000000000027 +:10A930000000000000000000000000000000000017 +:10A940000000000000000000000000000000000007 +:10A9500000000000000000000000000000000000F7 +:10A9600000000000000000000000000000000000E7 +:10A9700000000000000000000000000000000000D7 +:10A9800000000000000000000000000000000000C7 +:10A9900000000000000000000000000000000000B7 +:10A9A00000000000000000000000000000000000A7 +:10A9B0000000000000000000000000000000000097 +:10A9C0000000000000000000000000000000000087 +:10A9D0000000000000000000000000000000000077 +:10A9E0000000000000000000000000000000000067 +:10A9F0000000000000000000000000000000000057 +:10AA00000000000000000000000000000000000046 +:10AA10000000000000000000000000000000000036 +:10AA20000000000000000000000000000000000026 +:10AA30000000000000000000000000000000000016 +:10AA40000000000000000000000000000000000006 +:10AA500000000000000000000000000000000000F6 +:10AA600000000000000000000000000000000000E6 +:10AA700000000000000000000000000000000000D6 +:10AA800000000000000000000000000000000000C6 +:10AA900000000000000000000000000000000000B6 +:10AAA00000000000000000000000000000000000A6 +:10AAB0000000000000000000000000000000000096 +:10AAC0000000000000000000000000000000000086 +:10AAD0000000000000000000000000000000000076 +:10AAE0000000000000000000000000000000000066 +:10AAF0000000000000000000000000000000000056 +:10AB00000000000000000000000000000000000045 +:10AB10000000000000000000000000000000000035 +:10AB20000000000000000000000000000000000025 +:10AB30000000000000000000000000000000000015 +:10AB40000000000000000000000000000000000005 +:10AB500000000000000000000000000000000000F5 +:10AB600000000000000000000000000000000000E5 +:10AB700000000000000000000000000000000000D5 +:10AB800000000000000000000000000000000000C5 +:10AB900000000000000000000000000000000000B5 +:10ABA00000000000000000000000000000000000A5 +:10ABB0000000000000000000000000000000000095 +:10ABC0000000000000000000000000000000000085 +:10ABD0000000000000000000000000000000000075 +:10ABE0000000000000000000000000000000000065 +:10ABF0000000000000000000000000000000000055 +:10AC00000000000000000000000000000000000044 +:10AC10000000000000000000000000000000000034 +:10AC20000000000000000000000000000000000024 +:10AC30000000000000000000000000000000000014 +:10AC40000000000000000000000000000000000004 +:10AC500000000000000000000000000000000000F4 +:10AC600000000000000000000000000000000000E4 +:10AC700000000000000000000000000000000000D4 +:10AC800000000000000000000000000000000000C4 +:10AC900000000000000000000000000000000000B4 +:10ACA00000000000000000000000000000000000A4 +:10ACB0000000000000000000000000000000000094 +:10ACC0000000000000000000000000000000000084 +:10ACD0000000000000000000000000000000000074 +:10ACE0000000000000000000000000000000000064 +:10ACF0000000000000000000000000000000000054 +:10AD00000000000000000000000000000000000043 +:10AD10000000000000000000000000000000000033 +:10AD20000000000000000000000000000000000023 +:10AD30000000000000000000000000000000000013 +:10AD40000000000000000000000000000000000003 +:10AD500000000000000000000000000000000000F3 +:10AD600000000000000000000000000000000000E3 +:10AD700000000000000000000000000000000000D3 +:10AD800000000000000000000000000000000000C3 +:10AD900000000000000000000000000000000000B3 +:10ADA00000000000000000000000000000000000A3 +:10ADB0000000000000000000000000000000000093 +:10ADC0000000000000000000000000000000000083 +:10ADD0000000000000000000000000000000000073 +:10ADE0000000000000000000000000000000000063 +:10ADF0000000000000000000000000000000000053 +:10AE00000000000000000000000000000000000042 +:10AE10000000000000000000000000000000000032 +:10AE20000000000000000000000000000000000022 +:10AE30000000000000000000000000000000000012 +:10AE40000000000000000000000000000000000002 +:10AE500000000000000000000000000000000000F2 +:10AE600000000000000000000000000000000000E2 +:10AE700000000000000000000000000000000000D2 +:10AE800000000000000000000000000000000000C2 +:10AE900000000000000000000000000000000000B2 +:10AEA00000000000000000000000000000000000A2 +:10AEB0000000000000000000000000000000000092 +:10AEC0000000000000000000000000000000000082 +:10AED0000000000000000000000000000000000072 +:10AEE0000000000000000000000000000000000062 +:10AEF0000000000000000000000000000000000052 +:10AF00000000000000000000000000000000000041 +:10AF10000000000000000000000000000000000031 +:10AF20000000000000000000000000000000000021 +:10AF30000000000000000000000000000000000011 +:10AF40000000000000000000000000000000000001 +:10AF500000000000000000000000000000000000F1 +:10AF600000000000000000000000000000000000E1 +:10AF700000000000000000000000000000000000D1 +:10AF800000000000000000000000000000000000C1 +:10AF900000000000000000000000000000000000B1 +:10AFA00000000000000000000000000000000000A1 +:10AFB0000000000000000000000000000000000091 +:10AFC0000000000000000000000000000000000081 +:10AFD0000000000000000000000000000000000071 +:10AFE0000000000000000000000000000000000061 +:10AFF0000000000000000000000000000000000051 +:10B000000000000000000000000000000000000040 +:10B010000000000000000000000000000000000030 +:10B020000000000000000000000000000000000020 +:10B030000000000000000000000000000000000010 +:10B040000000000000000000000000000000000000 +:10B0500000000000000000000000000000000000F0 +:10B0600000000000000000000000000000000000E0 +:10B0700000000000000000000000000000000000D0 +:10B0800000000000000000000000000000000000C0 +:10B0900000000000000000000000000000000000B0 +:10B0A00000000000000000000000000000000000A0 +:10B0B0000000000000000000000000000000000090 +:10B0C0000000000000000000000000000000000080 +:10B0D0000000000000000000000000000000000070 +:10B0E0000000000000000000000000000000000060 +:10B0F0000000000000000000000000000000000050 +:10B10000000000000000000000000000000000003F +:10B11000000000000000000000000000000000002F +:10B12000000000000000000000000000000000001F +:10B13000000000000000000000000000000000000F +:10B1400000000000000000000000000000000000FF +:10B1500000000000000000000000000000000000EF +:10B1600000000000000000000000000000000000DF +:10B1700000000000000000000000000000000000CF +:10B1800000000000000000000000000000000000BF +:10B1900000000000000000000000000000000000AF +:10B1A000000000000000000000000000000000009F +:10B1B000000000000000000000000000000000008F +:10B1C000000000000000000000000000000000007F +:10B1D000000000000000000000000000000000006F +:10B1E000000000000000000000000000000000005F +:10B1F000000000000000000000000000000000004F +:10B20000000000000000000000000000000000003E +:10B21000000000000000000000000000000000002E +:10B22000000000000000000000000000000000001E +:10B23000000000000000000000000000000000000E +:10B2400000000000000000000000000000000000FE +:10B2500000000000000000000000000000000000EE +:10B2600000000000000000000000000000000000DE +:10B2700000000000000000000000000000000000CE +:10B2800000000000000000000000000000000000BE +:10B2900000000000000000000000000000000000AE +:10B2A000000000000000000000000000000000009E +:10B2B000000000000000000000000000000000008E +:10B2C000000000000000000000000000000000007E +:10B2D000000000000000000000000000000000006E +:10B2E000000000000000000000000000000000005E +:10B2F000000000000000000000000000000000004E +:10B30000000000000000000000000000000000003D +:10B31000000000000000000000000000000000002D +:10B32000000000000000000000000000000000001D +:10B33000000000000000000000000000000000000D +:10B3400000000000000000000000000000000000FD +:10B3500000000000000000000000000000000000ED +:10B3600000000000000000000000000000000000DD +:10B3700000000000000000000000000000000000CD +:10B3800000000000000000000000000000000000BD +:10B3900000000000000000000000000000000000AD +:10B3A000000000000000000000000000000000009D +:10B3B000000000000000000000000000000000008D +:10B3C000000000000000000000000000000000007D +:10B3D000000000000000000000000000000000006D +:10B3E000000000000000000000000000000000005D +:10B3F000000000000000000000000000000000004D +:10B40000000000000000000000000000000000003C +:10B41000000000000000000000000000000000002C +:10B42000000000000000000000000000000000001C +:10B43000000000000000000000000000000000000C +:10B4400000000000000000000000000000000000FC +:10B4500000000000000000000000000000000000EC +:10B4600000000000000000000000000000000000DC +:10B4700000000000000000000000000000000000CC +:10B4800000000000000000000000000000000000BC +:10B4900000000000000000000000000000000000AC +:10B4A000000000000000000000000000000000009C +:10B4B000000000000000000000000000000000008C +:10B4C000000000000000000000000000000000007C +:10B4D000000000000000000000000000000000006C +:10B4E000000000000000000000000000000000005C +:10B4F000000000000000000000000000000000004C +:10B50000000000000000000000000000000000003B +:10B51000000000000000000000000000000000002B +:10B52000000000000000000000000000000000001B +:10B53000000000000000000000000000000000000B +:10B5400000000000000000000000000000000000FB +:10B5500000000000000000000000000000000000EB +:10B5600000000000000000000000000000000000DB +:10B5700000000000000000000000000000000000CB +:10B5800000000000000000000000000000000000BB +:10B5900000000000000000000000000000000000AB +:10B5A000000000000000000000000000000000009B +:10B5B000000000000000000000000000000000008B +:10B5C000000000000000000000000000000000007B +:10B5D000000000000000000000000000000000006B +:10B5E000000000000000000000000000000000005B +:10B5F000000000000000000000000000000000004B +:10B60000000000000000000000000000000000003A +:10B61000000000000000000000000000000000002A +:10B62000000000000000000000000000000000001A +:10B63000000000000000000000000000000000000A +:10B6400000000000000000000000000000000000FA +:10B6500000000000000000000000000000000000EA +:10B6600000000000000000000000000000000000DA +:10B6700000000000000000000000000000000000CA +:10B6800000000000000000000000000000000000BA +:10B6900000000000000000000000000000000000AA +:10B6A000000000000000000000000000000000009A +:10B6B000000000000000000000000000000000008A +:10B6C000000000000000000000000000000000007A +:10B6D000000000000000000000000000000000006A +:10B6E000000000000000000000000000000000005A +:10B6F000000000000000000000000000000000004A +:10B700000000000000000000000000000000000039 +:10B710000000000000000000000000000000000029 +:10B720000000000000000000000000000000000019 +:10B730000000000000000000000000000000000009 +:10B7400000000000000000000000000000000000F9 +:10B7500000000000000000000000000000000000E9 +:10B7600000000000000000000000000000000000D9 +:10B7700000000000000000000000000000000000C9 +:10B7800000000000000000000000000000000000B9 +:10B7900000000000000000000000000000000000A9 +:10B7A0000000000000000000000000000000000099 +:10B7B0000000000000000000000000000000000089 +:10B7C0000000000000000000000000000000000079 +:10B7D0000000000000000000000000000000000069 +:10B7E0000000000000000000000000000000000059 +:10B7F0000000000000000000000000000000000049 +:10B800000000000000000000000000000000000038 +:10B810000000000000000000000000000000000028 +:10B820000000000000000000000000000000000018 +:10B830000000000000000000000000000000000008 +:10B8400000000000000000000000000000000000F8 +:10B8500000000000000000000000000000000000E8 +:10B8600000000000000000000000000000000000D8 +:10B8700000000000000000000000000000000000C8 +:10B8800000000000000000000000000000000000B8 +:10B8900000000000000000000000000000000000A8 +:10B8A0000000000000000000000000000000000098 +:10B8B0000000000000000000000000000000000088 +:10B8C0000000000000000000000000000000000078 +:10B8D0000000000000000000000000000000000068 +:10B8E0000000000000000000000000000000000058 +:10B8F0000000000000000000000000000000000048 +:10B900000000000000000000000000000000000037 +:10B910000000000000000000000000000000000027 +:10B920000000000000000000000000000000000017 +:10B930000000000000000000000000000000000007 +:10B9400000000000000000000000000000000000F7 +:10B9500000000000000000000000000000000000E7 +:10B9600000000000000000000000000000000000D7 +:10B9700000000000000000000000000000000000C7 +:10B9800000000000000000000000000000000000B7 +:10B9900000000000000000000000000000000000A7 +:10B9A0000000000000000000000000000000000097 +:10B9B0000000000000000000000000000000000087 +:10B9C0000000000000000000000000000000000077 +:10B9D0000000000000000000000000000000000067 +:10B9E0000000000000000000000000000000000057 +:10B9F0000000000000000000000000000000000047 +:10BA00000000000000000000000000000000000036 +:10BA10000000000000000000000000000000000026 +:10BA20000000000000000000000000000000000016 +:10BA30000000000000000000000000000000000006 +:10BA400000000000000000000000000000000000F6 +:10BA500000000000000000000000000000000000E6 +:10BA600000000000000000000000000000000000D6 +:10BA700000000000000000000000000000000000C6 +:10BA800000000000000000000000000000000000B6 +:10BA900000000000000000000000000000000000A6 +:10BAA0000000000000000000000000000000000096 +:10BAB0000000000000000000000000000000000086 +:10BAC0000000000000000000000000000000000076 +:10BAD0000000000000000000000000000000000066 +:10BAE0000000000000000000000000000000000056 +:10BAF0000000000000000000000000000000000046 +:10BB00000000000000000000000000000000000035 +:10BB10000000000000000000000000000000000025 +:10BB20000000000000000000000000000000000015 +:10BB30000000000000000000000000000000000005 +:10BB400000000000000000000000000000000000F5 +:10BB500000000000000000000000000000000000E5 +:10BB600000000000000000000000000000000000D5 +:10BB700000000000000000000000000000000000C5 +:10BB800000000000000000000000000000000000B5 +:10BB900000000000000000000000000000000000A5 +:10BBA0000000000000000000000000000000000095 +:10BBB0000000000000000000000000000000000085 +:10BBC0000000000000000000000000000000000075 +:10BBD0000000000000000000000000000000000065 +:10BBE0000000000000000000000000000000000055 +:10BBF0000000000000000000000000000000000045 +:10BC00000000000000000000000000000000000034 +:10BC10000000000000000000000000000000000024 +:10BC20000000000000000000000000000000000014 +:10BC30000000000000000000000000000000000004 +:10BC400000000000000000000000000000000000F4 +:10BC500000000000000000000000000000000000E4 +:10BC600000000000000000000000000000000000D4 +:10BC700000000000000000000000000000000000C4 +:10BC800000000000000000000000000000000000B4 +:10BC900000000000000000000000000000000000A4 +:10BCA0000000000000000000000000000000000094 +:10BCB0000000000000000000000000000000000084 +:10BCC0000000000000000000000000000000000074 +:10BCD0000000000000000000000000000000000064 +:10BCE0000000000000000000000000000000000054 +:10BCF0000000000000000000000000000000000044 +:10BD00000000000000000000000000000000000033 +:10BD10000000000000000000000000000000000023 +:10BD20000000000000000000000000000000000013 +:10BD30000000000000000000000000000000000003 +:10BD400000000000000000000000000000000000F3 +:10BD500000000000000000000000000000000000E3 +:10BD600000000000000000000000000000000000D3 +:10BD700000000000000000000000000000000000C3 +:10BD800000000000000000000000000000000000B3 +:10BD900000000000000000000000000000000000A3 +:10BDA0000000000000000000000000000000000093 +:10BDB0000000000000000000000000000000000083 +:10BDC0000000000000000000000000000000000073 +:10BDD0000000000000000000000000000000000063 +:10BDE0000000000000000000000000000000000053 +:10BDF0000000000000000000000000000000000043 +:10BE00000000000000000000000000000000000032 +:10BE10000000000000000000000000000000000022 +:10BE20000000000000000000000000000000000012 +:10BE30000000000000000000000000000000000002 +:10BE400000000000000000000000000000000000F2 +:10BE500000000000000000000000000000000000E2 +:10BE600000000000000000000000000000000000D2 +:10BE700000000000000000000000000000000000C2 +:10BE800000000000000000000000000000000000B2 +:10BE900000000000000000000000000000000000A2 +:10BEA0000000000000000000000000000000000092 +:10BEB0000000000000000000000000000000000082 +:10BEC0000000000000000000000000000000000072 +:10BED0000000000000000000000000000000000062 +:10BEE0000000000000000000000000000000000052 +:10BEF0000000000000000000000000000000000042 +:10BF00000000000000000000000000000000000031 +:10BF10000000000000000000000000000000000021 +:10BF20000000000000000000000000000000000011 +:10BF30000000000000000000000000000000000001 +:10BF400000000000000000000000000000000000F1 +:10BF500000000000000000000000000000000000E1 +:10BF600000000000000000000000000000000000D1 +:10BF700000000000000000000000000000000000C1 +:10BF800000000000000000000000000000000000B1 +:10BF900000000000000000000000000000000000A1 +:10BFA0000000000000000000000000000000000091 +:10BFB0000000000000000000000000000000000081 +:10BFC0000000000000000000000000000000000071 +:10BFD0000000000000000000000000000000000061 +:10BFE0000000000000000000000000000000000051 +:10BFF0000000000000000000000000000000000041 +:10C000000000000000000000000000000000000030 +:10C010000000000000000000000000000000000020 +:10C020000000000000000000000000000000000010 +:10C030000000000000000000000000000000000000 +:10C0400000000000000000000000000000000000F0 +:10C0500000000000000000000000000000000000E0 +:10C0600000000000000000000000000000000000D0 +:10C0700000000000000000000000000000000000C0 +:10C0800000000000000000000000000000000000B0 +:10C0900000000000000000000000000000000000A0 +:10C0A0000000000000000000000000000000000090 +:10C0B0000000000000000000000000000000000080 +:10C0C0000000000000000000000000000000000070 +:10C0D0000000000000000000000000000000000060 +:10C0E0000000000000000000000000000000000050 +:10C0F0000000000000000000000000000000000040 +:10C10000000000000000000000000000000000002F +:10C11000000000000000000000000000000000001F +:10C12000000000000000000000000000000000000F +:10C1300000000000000000000000000000000000FF +:10C1400000000000000000000000000000000000EF +:10C1500000000000000000000000000000000000DF +:10C1600000000000000000000000000000000000CF +:10C1700000000000000000000000000000000000BF +:10C1800000000000000000000000000000000000AF +:10C19000000000000000000000000000000000009F +:10C1A000000000000000000000000000000000008F +:10C1B000000000000000000000000000000000007F +:10C1C000000000000000000000000000000000006F +:10C1D000000000000000000000000000000000005F +:10C1E000000000000000000000000000000000004F +:10C1F000000000000000000000000000000000003F +:10C20000000000000000000000000000000000002E +:10C21000000000000000000000000000000000001E +:10C22000000000000000000000000000000000000E +:10C2300000000000000000000000000000000000FE +:10C2400000000000000000000000000000000000EE +:10C2500000000000000000000000000000000000DE +:10C2600000000000000000000000000000000000CE +:10C2700000000000000000000000000000000000BE +:10C2800000000000000000000000000000000000AE +:10C29000000000000000000000000000000000009E +:10C2A000000000000000000000000000000000008E +:10C2B000000000000000000000000000000000007E +:10C2C000000000000000000000000000000000006E +:10C2D000000000000000000000000000000000005E +:10C2E000000000000000000000000000000000004E +:10C2F000000000000000000000000000000000003E +:10C30000000000000000000000000000000000002D +:10C31000000000000000000000000000000000001D +:10C32000000000000000000000000000000000000D +:10C3300000000000000000000000000000000000FD +:10C3400000000000000000000000000000000000ED +:10C3500000000000000000000000000000000000DD +:10C3600000000000000000000000000000000000CD +:10C3700000000000000000000000000000000000BD +:10C3800000000000000000000000000000000000AD +:10C39000000000000000000000000000000000009D +:10C3A000000000000000000000000000000000008D +:10C3B000000000000000000000000000000000007D +:10C3C000000000000000000000000000000000006D +:10C3D000000000000000000000000000000000005D +:10C3E000000000000000000000000000000000004D +:10C3F000000000000000000000000000000000003D +:10C40000000000000000000000000000000000002C +:10C41000000000000000000000000000000000001C +:10C42000000000000000000000000000000000000C +:10C4300000000000000000000000000000000000FC +:10C4400000000000000000000000000000000000EC +:10C4500000000000000000000000000000000000DC +:10C4600000000000000000000000000000000000CC +:10C4700000000000000000000000000000000000BC +:10C4800000000000000000000000000000000000AC +:10C49000000000000000000000000000000000009C +:10C4A000000000000000000000000000000000008C +:10C4B000000000000000000000000000000000007C +:10C4C000000000000000000000000000000000006C +:10C4D000000000000000000000000000000000005C +:10C4E000000000000000000000000000000000004C +:10C4F000000000000000000000000000000000003C +:10C50000000000000000000000000000000000002B +:10C51000000000000000000000000000000000001B +:10C52000000000000000000000000000000000000B +:10C5300000000000000000000000000000000000FB +:10C5400000000000000000000000000000000000EB +:10C5500000000000000000000000000000000000DB +:10C5600000000000000000000000000000000000CB +:10C5700000000000000000000000000000000000BB +:10C5800000000000000000000000000000000000AB +:10C59000000000000000000000000000000000009B +:10C5A000000000000000000000000000000000008B +:10C5B000000000000000000000000000000000007B +:10C5C000000000000000000000000000000000006B +:10C5D000000000000000000000000000000000005B +:10C5E000000000000000000000000000000000004B +:10C5F000000000000000000000000000000000003B +:10C60000000000000000000000000000000000002A +:10C61000000000000000000000000000000000001A +:10C62000000000000000000000000000000000000A +:10C6300000000000000000000000000000000000FA +:10C6400000000000000000000000000000000000EA +:10C6500000000000000000000000000000000000DA +:10C6600000000000000000000000000000000000CA +:10C6700000000000000000000000000000000000BA +:10C6800000000000000000000000000000000000AA +:10C69000000000000000000000000000000000009A +:10C6A000000000000000000000000000000000008A +:10C6B000000000000000000000000000000000007A +:10C6C000000000000000000000000000000000006A +:10C6D000000000000000000000000000000000005A +:10C6E000000000000000000000000000000000004A +:10C6F000000000000000000000000000000000003A +:10C700000000000000000000000000000000000029 +:10C710000000000000000000000000000000000019 +:10C720000000000000000000000000000000000009 +:10C7300000000000000000000000000000000000F9 +:10C7400000000000000000000000000000000000E9 +:10C7500000000000000000000000000000000000D9 +:10C7600000000000000000000000000000000000C9 +:10C7700000000000000000000000000000000000B9 +:10C7800000000000000000000000000000000000A9 +:10C790000000000000000000000000000000000099 +:10C7A0000000000000000000000000000000000089 +:10C7B0000000000000000000000000000000000079 +:10C7C0000000000000000000000000000000000069 +:10C7D0000000000000000000000000000000000059 +:10C7E0000000000000000000000000000000000049 +:10C7F0000000000000000000000000000000000039 +:10C800000000000000000000000000000000000028 +:10C810000000000000000000000000000000000018 +:10C820000000000000000000000000000000000008 +:10C8300000000000000000000000000000000000F8 +:10C8400000000000000000000000000000000000E8 +:10C8500000000000000000000000000000000000D8 +:10C8600000000000000000000000000000000000C8 +:10C8700000000000000000000000000000000000B8 +:10C8800000000000000000000000000000000000A8 +:10C890000000000000000000000000000000000098 +:10C8A0000000000000000000000000000000000088 +:10C8B0000000000000000000000000000000000078 +:10C8C0000000000000000000000000000000000068 +:10C8D0000000000000000000000000000000000058 +:10C8E0000000000000000000000000000000000048 +:10C8F0000000000000000000000000000000000038 +:10C900000000000000000000000000000000000027 +:10C910000000000000000000000000000000000017 +:10C920000000000000000000000000000000000007 +:10C9300000000000000000000000000000000000F7 +:10C9400000000000000000000000000000000000E7 +:10C9500000000000000000000000000000000000D7 +:10C9600000000000000000000000000000000000C7 +:10C9700000000000000000000000000000000000B7 +:10C9800000000000000000000000000000000000A7 +:10C990000000000000000000000000000000000097 +:10C9A0000000000000000000000000000000000087 +:10C9B0000000000000000000000000000000000077 +:10C9C0000000000000000000000000000000000067 +:10C9D0000000000000000000000000000000000057 +:10C9E0000000000000000000000000000000000047 +:10C9F0000000000000000000000000000000000037 +:10CA00000000000000000000000000000000000026 +:10CA10000000000000000000000000000000000016 +:10CA20000000000000000000000000000000000006 +:10CA300000000000000000000000000000000000F6 +:10CA400000000000000000000000000000000000E6 +:10CA500000000000000000000000000000000000D6 +:10CA600000000000000000000000000000000000C6 +:10CA700000000000000000000000000000000000B6 +:10CA800000000000000000000000000000000000A6 +:10CA90000000000000000000000000000000000096 +:10CAA0000000000000000000000000000000000086 +:10CAB0000000000000000000000000000000000076 +:10CAC0000000000000000000000000000000000066 +:10CAD0000000000000000000000000000000000056 +:10CAE0000000000000000000000000000000000046 +:10CAF0000000000000000000000000000000000036 +:10CB00000000000000000000000000000000000025 +:10CB10000000000000000000000000000000000015 +:10CB20000000000000000000000000000000000005 +:10CB300000000000000000000000000000000000F5 +:10CB400000000000000000000000000000000000E5 +:10CB500000000000000000000000000000000000D5 +:10CB600000000000000000000000000000000000C5 +:10CB700000000000000000000000000000000000B5 +:10CB800000000000000000000000000000000000A5 +:10CB90000000000000000000000000000000000095 +:10CBA0000000000000000000000000000000000085 +:10CBB0000000000000000000000000000000000075 +:10CBC0000000000000000000000000000000000065 +:10CBD0000000000000000000000000000000000055 +:10CBE0000000000000000000000000000000000045 +:10CBF0000000000000000000000000000000000035 +:10CC00000000000000000000000000000000000024 +:10CC10000000000000000000000000000000000014 +:10CC20000000000000000000000000000000000004 +:10CC300000000000000000000000000000000000F4 +:10CC400000000000000000000000000000000000E4 +:10CC500000000000000000000000000000000000D4 +:10CC600000000000000000000000000000000000C4 +:10CC700000000000000000000000000000000000B4 +:10CC800000000000000000000000000000000000A4 +:10CC90000000000000000000000000000000000094 +:10CCA0000000000000000000000000000000000084 +:10CCB0000000000000000000000000000000000074 +:10CCC0000000000000000000000000000000000064 +:10CCD0000000000000000000000000000000000054 +:10CCE0000000000000000000000000000000000044 +:10CCF0000000000000000000000000000000000034 +:10CD00000000000000000000000000000000000023 +:10CD10000000000000000000000000000000000013 +:10CD20000000000000000000000000000000000003 +:10CD300000000000000000000000000000000000F3 +:10CD400000000000000000000000000000000000E3 +:10CD500000000000000000000000000000000000D3 +:10CD600000000000000000000000000000000000C3 +:10CD700000000000000000000000000000000000B3 +:10CD800000000000000000000000000000000000A3 +:10CD90000000000000000000000000000000000093 +:10CDA0000000000000000000000000000000000083 +:10CDB0000000000000000000000000000000000073 +:10CDC0000000000000000000000000000000000063 +:10CDD0000000000000000000000000000000000053 +:10CDE0000000000000000000000000000000000043 +:10CDF0000000000000000000000000000000000033 +:10CE00000000000000000000000000000000000022 +:10CE10000000000000000000000000000000000012 +:10CE20000000000000000000000000000000000002 +:10CE300000000000000000000000000000000000F2 +:10CE400000000000000000000000000000000000E2 +:10CE500000000000000000000000000000000000D2 +:10CE600000000000000000000000000000000000C2 +:10CE700000000000000000000000000000000000B2 +:10CE800000000000000000000000000000000000A2 +:10CE90000000000000000000000000000000000092 +:10CEA0000000000000000000000000000000000082 +:10CEB0000000000000000000000000000000000072 +:10CEC0000000000000000000000000000000000062 +:10CED0000000000000000000000000000000000052 +:10CEE0000000000000000000000000000000000042 +:10CEF0000000000000000000000000000000000032 +:10CF00000000000000000000000000000000000021 +:10CF10000000000000000000000000000000000011 +:10CF20000000000000000000000000000000000001 +:10CF300000000000000000000000000000000000F1 +:10CF400000000000000000000000000000000000E1 +:10CF500000000000000000000000000000000000D1 +:10CF600000000000000000000000000000000000C1 +:10CF700000000000000000000000000000000000B1 +:10CF800000000000000000000000000000000000A1 +:10CF90000000000000000000000000000000000091 +:10CFA0000000000000000000000000000000000081 +:10CFB0000000000000000000000000000000000071 +:10CFC0000000000000000000000000000000000061 +:10CFD0000000000000000000000000000000000051 +:10CFE0000000000000000000000000000000000041 +:10CFF0000000000000000000000000000000000031 +:10D000000000000000000000000000000000000020 +:10D010000000000000000000000000000000000010 +:10D020000000000000000000000000000000000000 +:10D0300000000000000000000000000000000000F0 +:10D0400000000000000000000000000000000000E0 +:10D0500000000000000000000000000000000000D0 +:10D0600000000000000000000000000000000000C0 +:10D0700000000000000000000000000000000000B0 +:10D0800000000000000000000000000000000000A0 +:10D090000000000000000000000000000000000090 +:10D0A0000000000000000000000000000000000080 +:10D0B0000000000000000000000000000000000070 +:10D0C0000000000000000000000000000000000060 +:10D0D0000000000000000000000000000000000050 +:10D0E0000000000000000000000000000000000040 +:10D0F0000000000000000000000000000000000030 +:10D10000000000000000000000000000000000001F +:10D11000000000000000000000000000000000000F +:10D1200000000000000000000000000000000000FF +:10D1300000000000000000000000000000000000EF +:10D1400000000000000000000000000000000000DF +:10D1500000000000000000000000000000000000CF +:10D1600000000000000000000000000000000000BF +:10D1700000000000000000000000000000000000AF +:10D18000000000000000000000000000000000009F +:10D19000000000000000000000000000000000008F +:10D1A000000000000000000000000000000000007F +:10D1B000000000000000000000000000000000006F +:10D1C000000000000000000000000000000000005F +:10D1D000000000000000000000000000000000004F +:10D1E000000000000000000000000000000000003F +:10D1F000000000000000000000000000000000002F +:10D20000000000000000000000000000000000001E +:10D21000000000000000000000000000000000000E +:10D2200000000000000000000000000000000000FE +:10D2300000000000000000000000000000000000EE +:10D2400000000000000000000000000000000000DE +:10D2500000000000000000000000000000000000CE +:10D2600000000000000000000000000000000000BE +:10D2700000000000000000000000000000000000AE +:10D28000000000000000000000000000000000009E +:10D29000000000000000000000000000000000008E +:10D2A000000000000000000000000000000000007E +:10D2B000000000000000000000000000000000006E +:10D2C000000000000000000000000000000000005E +:10D2D000000000000000000000000000000000004E +:10D2E000000000000000000000000000000000003E +:10D2F000000000000000000000000000000000002E +:10D30000000000000000000000000000000000001D +:10D31000000000000000000000000000000000000D +:10D3200000000000000000000000000000000000FD +:10D3300000000000000000000000000000000000ED +:10D3400000000000000000000000000000000000DD +:10D3500000000000000000000000000000000000CD +:10D3600000000000000000000000000000000000BD +:10D3700000000000000000000000000000000000AD +:10D38000000000000000000000000000000000009D +:10D39000000000000000000000000000000000008D +:10D3A000000000000000000000000000000000007D +:10D3B000000000000000000000000000000000006D +:10D3C000000000000000000000000000000000005D +:10D3D000000000000000000000000000000000004D +:10D3E000000000000000000000000000000000003D +:10D3F000000000000000000000000000000000002D +:10D40000000000000000000000000000000000001C +:10D41000000000000000000000000000000000000C +:10D4200000000000000000000000000000000000FC +:10D4300000000000000000000000000000000000EC +:10D4400000000000000000000000000000000000DC +:10D4500000000000000000000000000000000000CC +:10D4600000000000000000000000000000000000BC +:10D4700000000000000000000000000000000000AC +:10D48000000000000000000000000000000000009C +:10D49000000000000000000000000000000000008C +:10D4A000000000000000000000000000000000007C +:10D4B000000000000000000000000000000000006C +:10D4C000000000000000000000000000000000005C +:10D4D000000000000000000000000000000000004C +:10D4E000000000000000000000000000000000003C +:10D4F000000000000000000000000000000000002C +:10D50000000000000000000000000000000000001B +:10D51000000000000000000000000000000000000B +:10D5200000000000000000000000000000000000FB +:10D5300000000000000000000000000000000000EB +:10D5400000000000000000000000000000000000DB +:10D5500000000000000000000000000000000000CB +:10D5600000000000000000000000000000000000BB +:10D5700000000000000000000000000000000000AB +:10D58000000000000000000000000000000000009B +:10D59000000000000000000000000000000000008B +:10D5A000000000000000000000000000000000007B +:10D5B000000000000000000000000000000000006B +:10D5C000000000000000000000000000000000005B +:10D5D000000000000000000000000000000000004B +:10D5E000000000000000000000000000000000003B +:10D5F000000000000000000000000000000000002B +:10D60000000000000000000000000000000000001A +:10D61000000000000000000000000000000000000A +:10D6200000000000000000000000000000000000FA +:10D6300000000000000000000000000000000000EA +:10D6400000000000000000000000000000000000DA +:10D6500000000000000000000000000000000000CA +:10D6600000000000000000000000000000000000BA +:10D6700000000000000000000000000000000000AA +:10D68000000000000000000000000000000000009A +:10D69000000000000000000000000000000000008A +:10D6A000000000000000000000000000000000007A +:10D6B000000000000000000000000000000000006A +:10D6C000000000000000000000000000000000005A +:10D6D000000000000000000000000000000000004A +:10D6E000000000000000000000000000000000003A +:10D6F000000000000000000000000000000000002A +:10D700000000000000000000000000000000000019 +:10D710000000000000000000000000000000000009 +:10D7200000000000000000000000000000000000F9 +:10D7300000000000000000000000000000000000E9 +:10D7400000000000000000000000000000000000D9 +:10D7500000000000000000000000000000000000C9 +:10D7600000000000000000000000000000000000B9 +:10D7700000000000000000000000000000000000A9 +:10D780000000000000000000000000000000000099 +:10D790000000000000000000000000000000000089 +:10D7A0000000000000000000000000000000000079 +:10D7B0000000000000000000000000000000000069 +:10D7C0000000000000000000000000000000000059 +:10D7D0000000000000000000000000000000000049 +:10D7E0000000000000000000000000000000000039 +:10D7F0000000000000000000000000000000000029 +:10D800000000000000000000000000000000000018 +:10D810000000000000000000000000000000000008 +:10D8200000000000000000000000000000000000F8 +:10D8300000000000000000000000000000000000E8 +:10D8400000000000000000000000000000000000D8 +:10D8500000000000000000000000000000000000C8 +:10D8600000000000000000000000000000000000B8 +:10D8700000000000000000000000000000000000A8 +:10D880000000000000000000000000000000000098 +:10D890000000000000000000100000030000000075 +:10D8A0000000000D0000000D3C020801244282200F +:10D8B0003C030801246382E0AC4000000043202BBD +:10D8C0001480FFFD244200043C1D080037BD9FFC6E +:10D8D00003A0F0213C100800261031D83C1C0801A0 +:10D8E000279C82200E0011EA000000000000000DBD +:10D8F0003C02800030A5FFFF30C600FF34430180AA +:10D900003C0880008D0901B80520FFFE00000000E2 +:10D91000AC64000024040002A4650008A066000AAC +:10D92000A064000BAC6700183C03100003E0000883 +:10D93000AD0301B83C0560008CA24FF80440FFFE27 +:10D9400000000000ACA44FC03C0310003C040200E7 +:10D95000ACA44FC403E00008ACA34FF89486000CBD +:10D9600000A050212488001400062B02000510801E +:10D97000004448210109182B10600011000000002C +:10D98000910300002C6400095080000991190001E6 +:10D99000000360803C0D080125AD80E4018D582115 +:10D9A0008D67000000E000080000000091190001F0 +:10D9B000011940210109302B54C0FFF291030000EE +:10D9C00003E00008000010210A000CBE2508000139 +:10D9D000910F0001240E000A15EE00400128C82313 +:10D9E0002F38000A1700003D250D00028D58000059 +:10D9F000250F0006370E0100AD4E0000910C00020D +:10DA000091AB000191A4000291A60003000C2E002E +:10DA1000000B3C0000A7102500041A000043C82595 +:10DA20000326C025AD580004910E000691ED0001BB +:10DA300091E7000291E50003000E5E00000D640016 +:10DA4000016C30250007220000C410250045182570 +:10DA50002508000A0A000CBEAD430008910F000122 +:10DA6000250400022408000255E8000101202021BD +:10DA70000A000CBE00804021910C0001240B000321 +:10DA8000158B0016000000008D580000910E00025A +:10DA900025080003370D0008A14E00100A000CBE37 +:10DAA000AD4D000091190001240F0004172F000B49 +:10DAB0000000000091070002910400038D43000064 +:10DAC00000072A0000A4102534660004250800047D +:10DAD000AD42000C0A000CBEAD46000003E0000899 +:10DAE0002402000127BDFFE8AFBF0014AFB0001053 +:10DAF0000E0014E0008080213C0480083485008002 +:10DB000090A600052403FFFE0200202100C310247C +:10DB10008FBF00148FB00010A0A200050A0014EA05 +:10DB200027BD001827BDFFE8AFB00010AFBF00143D +:10DB30000E000F4E008080213C06800834C5008016 +:10DB400090A4000024020050308300FF1062000700 +:10DB50003C098000020020218FBF00148FB000100C +:10DB6000AD2001800A00101027BD00182408010014 +:10DB70003C078000020020218FBF00148FB00010EE +:10DB8000ACE801800A00101027BD001827BDFF7007 +:10DB90003C088008AFB60080AFB5007CAFB1006C28 +:10DBA000AFBF008CAFBE0088AFB70084AFB40078C1 +:10DBB000AFB30074AFB20070AFB00068350500803D +:10DBC0003C0780008CF2012890A40009ACE000849E +:10DBD00090A60005309100FF0000A821000618273C +:10DBE000306200010000B02114400067AFA0005077 +:10DBF00090A9000024050020312400FF10850016A4 +:10DC0000240A0050108A008C000000003C0C080020 +:10DC10008D8C00DC258B00013C010800AC2B00DC66 +:10DC20000E0015D6000000008FBF008C8FBE00884C +:10DC30008FB700848FB600808FB5007C8FB40078DA +:10DC40008FB300748FB200708FB1006C8FB000681A +:10DC500003E0000827BD00900000000D3C1080008C +:10DC6000AFA00030961F01168E1901043C1E002043 +:10DC700036130C00033EC0240018B82B00173140A7 +:10DC8000AFA600308E0E010433F4FFFF3C0F0040BE +:10DC90000293802101CF68249213000D11A0004847 +:10DCA00034C40040326200201440000234860080F8 +:10DCB0000080302114C00093AFA600303C058008DE +:10DCC00034A800809107000830E6004050C00006EC +:10DCD0003C06800824090004122900A2240A00122C +:10DCE000122A00293C06800834D401003C17800029 +:10DCF00096EF011A960D000E928E0008326B00040A +:10DD000031F7FFFF01CD6004AFAC00548E14000466 +:10DD1000116000318E1E000834C300809079000825 +:10DD20003338004017000028000000008C730050BA +:10DD300002939023064000063C0C80008C7E003449 +:10DD4000029E8023060200838EA200083C0C800005 +:10DD5000AD800044240200018FBF008C8FBE00887C +:10DD60008FB700848FB600808FB5007C8FB40078A9 +:10DD70008FB300748FB200708FB1006C8FB00068E9 +:10DD800003E0000827BD00900E000D1A00002021BE +:10DD90008FBF008C8FBE00888FB700848FB6008045 +:10DDA0008FB5007C8FB400788FB300748FB2007091 +:10DDB0008FB1006C8FB0006803E0000827BD0090B1 +:10DDC0000A000D7A00C020210E00163702802021A3 +:10DDD0001440FFDF3C0C80003C038008346300806B +:10DDE0008C6200340282F82307E000170000000074 +:10DDF0003C1508008EB5310026B100013C01080039 +:10DE0000AC3131000E0014E0024020213C0B8008B0 +:10DE100035700080920A002502402021354200041E +:10DE20000E0014EAA20200250E000C9E02402021E2 +:10DE30000A000DA7240200013C15080126B582D076 +:10DE40000A000D693C1080008C6600300286202399 +:10DE5000188000082409000C3C0808008D083100D7 +:10DE6000327300FC0000B821250700013C010800C6 +:10DE7000AC273100AFA900308C65003000B43823E6 +:10DE800018E000DB02E7502A1540FFDE000000002A +:10DE900012E7002A02E768230287A02131B7FFFFBB +:10DEA000326E000211C00034327F00103C14800832 +:10DEB00036900080920F000831F6004052C000CE2C +:10DEC0008EA20008024020210E0014E02413001846 +:10DED000A2130009921800052419FFFE0240202118 +:10DEE0000319B8240E0014EAA2170005240400390F +:10DEF000000028210E001612240600180A000DA7A3 +:10DF00002402000192B6000C3C0480083483008097 +:10DF10008C6700380016AB0036B10081024020212A +:10DF20003225F0810E000C8D30C600FF3C0C8000C5 +:10DF3000AD8000440A000DA7240200013A6C0001E4 +:10DF4000318B00011560FFAF0287A0210A000DF898 +:10DF5000000000000040F809240400160A000DA784 +:10DF600024020001024020210E0017170200282180 +:10DF70000A000D5C8FBF008C13E0FF743C03800827 +:10DF8000346800808D0400388C66000403C61023BA +:10DF90001C40FF6F3C0C800003C4282304A2000136 +:10DFA0000080F021AFB40010AFB70014AFA7001885 +:10DFB0003C1F800097E301208D0900309506005C2E +:10DFC0008FB900548FAC00303062FFFF30D8FFFFB4 +:10DFD0000047702137EF40000338682B01CF5821EC +:10DFE000018D5025AFAB0020AFA90028AFAA0030AB +:10DFF000AFA90024AFA0002CAFBE003491070008E9 +:10E0000030E400081480008F020020218EA200045A +:10E010000040F80927A400108FA900303128000221 +:10E0200055000001327300FE3C048008348C0080EF +:10E03000918B0008316A0040514000128FA40024E7 +:10E040008C8D000411BE00BE240E00143265000148 +:10E0500010A0000C8FA400242404000C122400D46F +:10E060002A27000D10E000CE2409000E2408000A23 +:10E0700052280001241600088FA200242444000125 +:10E08000AFA400248FA600143C03800834650080F0 +:10E090000086F8218CB10030ACBF003090B9004E42 +:10E0A0008CAE00303418FFFF0338780401CF6821AC +:10E0B000ACAD00348FA600308FAC005430CA0008DD +:10E0C00003CC58211140000CAFAB00588CA40020A9 +:10E0D0008FB000581090009430C600FF92A2000C40 +:10E0E0008FA700340240202100024B003528008019 +:10E0F0000E000C8D3105F0803C0C800835900080BE +:10E100008E0B003001715023194000702659008099 +:10E110003C1808008F183198241FFF80033F782493 +:10E12000332D007F3C0680003C0E8004331100102C +:10E13000ACCF00901220003401AE282190A3006BD8 +:10E14000546000323C10800824070001A0A7006B37 +:10E1500094C4007A2486000AA60600123C0D8008AA +:10E1600035A5008090B10008322C004015800004D5 +:10E170003C038008326E000115C000620000000000 +:10E18000346400808C8F00208FB3005811F3000A94 +:10E19000346301008C7900000299C0231B000077D2 +:10E1A0008FA80058AC880020AC7400002414000133 +:10E1B000AC7E0004AFB4005016C000370000000071 +:10E1C0008FA40050148000300000000012E0000511 +:10E1D000000018218FA900303137000452E0FE9270 +:10E1E00000601021240300010A000D5B0060102173 +:10E1F0000A000DF9000038210040F8092404001736 +:10E200000A000DA7240200013C108008361000808F +:10E2100024090001024020210E0014E0A60900128A +:10E220009208002524050001AFA500503502000129 +:10E23000024020210E0014EAA20200250A000EA9C5 +:10E240003C0D800827A50038AFA800600E000CA880 +:10E25000AFA000381440FF6D8FA800608FA5003874 +:10E2600030B001005200FF6A8EA200048FA3003C70 +:10E270008D070058006720230483FF64AD03005816 +:10E280000A000E558EA200040E000C9E02402021B2 +:10E290000A000EC4000000000E0014E0024020211D +:10E2A0003C05800834A30080024020210E0014EABF +:10E2B000A076000902C03021240400370E00161297 +:10E2C000000028210A000EC28FA400508FA200185F +:10E2D0005840FFA33C0D80080E0014E002402021AE +:10E2E000920A0025240B0001AFAB00503542000418 +:10E2F000024020210E0014EAA20200250A000EA905 +:10E300003C0D80088CB600308EBE00082404001836 +:10E3100026D5000103C0F809ACB500308FB200303B +:10E320000A000D5B324200043C07800094E5011AAC +:10E3300050A0FF6A34C600100A000E8992A2000C99 +:10E34000122E002A2A2F001511E0001E2419001693 +:10E350002418000C5638FF3E326500013C1F80082F +:10E3600093E3001B2410FFBD2416000E0070302420 +:10E37000A3E6001B0A000E65326500018C7F0000D9 +:10E3800017F4FF8D000000008C67000403C73023E2 +:10E3900004C1FF848FA800580A000EBF00000000CF +:10E3A0001629FF368FA200240A000E7024160010D2 +:10E3B0002411000E52D1FF30241600100A000E6FF7 +:10E3C000241600165639FF22326500013C1F8008D2 +:10E3D00093E3001B2410FFBD2416001000703024AE +:10E3E000A3E6001B0A000E65326500010A000E64F8 +:10E3F000241600123C0380008C6201B80440FFFE2A +:10E4000024040800AC6401B803E000080000000028 +:10E4100030A5FFFF30C6FFFF3C0780008CE201B84B +:10E420000440FFFE34E80180AD040000ACE40020AD +:10E430003C048008948300483063FFFF1060001D97 +:10E440003C0B800024AA0012006A482B5120001ABD +:10E45000240A000394F901208F890000240C001A7B +:10E460003338FFFF2707FFFE0067782B39EE0001E6 +:10E4700000096B8201AE5824A10C000B116000470B +:10E480008F830004A50700148F880004350700015E +:10E49000AF87000430CC00405580000F3C0880005E +:10E4A0003C0C800035840180A485000E0A000F9882 +:10E4B0008F8F000C240A00033564018030CC0040AB +:10E4C0008F8900008F870004A08A000B5180FFF520 +:10E4D0003C0C80003C088000950301203C0880082B +:10E4E000951800403079FFFF272EFFFE330FFFFF06 +:10E4F00001CF682B11A0000301C02021950200402C +:10E500003044FFFF3C0B800000A4502335650180A0 +:10E51000A4A4000EA4AA00248F8F000C3C05800048 +:10E5200034AE01802418000230ED8000A5D8000C24 +:10E53000A5C90010ADCF0028A5C6000811A0000E87 +:10E540003C04800094AA01163142FFFC24480004D8 +:10E55000010518218C7940003326FFFF14C0000705 +:10E56000240EBFFF3C0BFFFF35657FFF00E538241D +:10E57000AF8700043C048000240EBFFF348C018070 +:10E5800000EE6824A58D0026AD89002C3C07100004 +:10E59000AC8701B803E00008000000002402FFFE81 +:10E5A000006238240A000F76AF8700043C05800023 +:10E5B00034A400708C8A000090A601128F840000A1 +:10E5C00027BDFFF030C300FF000318823082010036 +:10E5D00000003821104000392466000330874000D5 +:10E5E00050E0003930882000000610800045C82126 +:10E5F0008F2F40002478000400187080AFAF000017 +:10E6000001C568218DAC4000AFAC000494AB01168D +:10E610003169FFFC012540218D054000AFA50008B0 +:10E620008FA9000800003021000028213C070800C5 +:10E6300024E701000A000FE92408000890420000C6 +:10E6400024A500012CAD000C0062C8210019C08077 +:10E65000030778218DEE000011A0000600CE3026C1 +:10E6600003A5102114A8FFF500051A005520FFF49A +:10E67000904200003C048000348700703C05080094 +:10E680008CA531048CE300002CA8002011000009A7 +:10E69000006A3823000558803C0C0800258C31089E +:10E6A000016C482124AA0001AD2700003C010800AC +:10E6B000AC2A3104AF86000C2407000100E01021D1 +:10E6C00003E0000827BD00101100FFFC0000382106 +:10E6D00000066080018558218D6440002469000493 +:10E6E00000093880AFA4000000E518218C664000C6 +:10E6F000AFA000080A000FD9AFA6000427BDFFD8BD +:10E70000AFB20018AFB00010AFBF0024AFB400200C +:10E71000AFB3001CAFB100148F8700003C04800031 +:10E720009483010E30E24000000080211040001070 +:10E730003072FFFF3C06002000E6282410A0000DE8 +:10E7400030EA80008F8800042409BFFF00E93824E4 +:10E7500035031000AF87000030F120001620000BB9 +:10E760003C1400042418FFBF0A001038007810245D +:10E7700030EA8000154000863C0C002030F120007B +:10E780001220FFF88F8300043C14000400F4982446 +:10E790001260FFF52418FFBF3462004030F9010019 +:10E7A0001320000FAF8200043C02002000E2F82496 +:10E7B00013E000053C0B80003C04000400E4182436 +:10E7C000106000CF00000000956A011E9569011CD1 +:10E7D0003146FFFF0009440000C82825AF85000C22 +:10E7E0003C0E800095CD010C8DC44000340CFFFF21 +:10E7F000108C00B031A5FFFF308F010055E0000103 +:10E800002410001030F110005220000836110001D1 +:10E8100030F300201660009F3C18100000F8A02480 +:10E82000168000963C040C003611000130E801000F +:10E830001500000B3C0A00018F88000431094000DC +:10E840001520000800EA30243C0C1F0100EC58247D +:10E850003C0A1000516A00AE30AD02003C0A0001D3 +:10E8600000EA302414C000953C05100000E5202487 +:10E8700000004021108000070000902100079E0248 +:10E880003272000F001278803C0E080125CE828083 +:10E8900001EE40218F940018128000470220802151 +:10E8A00010800091000000003C0980009539010EA5 +:10E8B00091030000022030213338FFFF27050004B8 +:10E8C000106000080000A021241F0003107F013AFF +:10E8D00024040002910C00011184011830EA004068 +:10E8E0000012A1C08F92001C524000013626004049 +:10E8F0003C1380008E6F400031F10100122000CBEC +:10E9000030D1FFFB3C1808008F18002430D20004DF +:10E910003306000414C000CC30B0FFFF56400001A5 +:10E920003631000402802021020028210E000F55FC +:10E93000022030211640000D0000202136650180A4 +:10E940003C0480008C9301B80660FFFE241920006F +:10E9500024140002A4B90008A0B4000BA4A0001065 +:10E960003C051000AC8501B8000020218FBF0024B9 +:10E970008FB400208FB3001C8FB200188FB1001429 +:10E980008FB000100080102103E0000827BD002890 +:10E9900000EC58241160FF7A30F120008F8D0004C4 +:10E9A0003C0FFFFF35EE7FFF00EE382435A38000DB +:10E9B0000A001027AF8700003C0208008C42003894 +:10E9C0003C040800248400381040004B2449FFFF19 +:10E9D0003C038000946C010E318BFFFF110000A0FE +:10E9E000257300043C1008008E1000301200000A4D +:10E9F00030E601008F8A00043143400010600006B9 +:10EA00003C0F0F0000EF70243C0D010001AE402BC5 +:10EA1000110000DF3265FFFF10C000693C140F00D9 +:10EA200000F428243C18020010B800658F99000CEF +:10EA30003270FFFF03299824026490219249000458 +:10EA400025270004000721C00200282136260002E5 +:10EA50000E000F55000000008FBF00248FB400206F +:10EA60008FB3001C8FB200188FB100148FB000104C +:10EA70000000102103E0000827BD00283C020BFF26 +:10EA800000E41824345FFFFF03E3C82B5320FF6723 +:10EA9000361100013C0608008CC6002C361100051A +:10EAA00024D000013C010800AC30002C0A00105DAD +:10EAB00030E801000A0010522410002002402821F2 +:10EAC0003C1208008E5200D824040080264D00011C +:10EAD0003C010800AC2D00D80E000F5524060003A1 +:10EAE0000A0010E88FBF00243C0808012508828036 +:10EAF0000A00107C3C0980000A0010C50000482173 +:10EB00000E000FBC000000000A0010498F870000B3 +:10EB100015A0FF533C0A00012645000430AAFFFF60 +:10EB2000362600023C0380008C7201B80640FFFECE +:10EB30008F85000834690180AD20000010A000AF6F +:10EB40003C048000254F001200AF702B51C000AC78 +:10EB500024030003947801202414001A30F14000AB +:10EB60003313FFFFA134000B122000B62663FFFE13 +:10EB700000A3C82B572000B4241FFFFE3508000156 +:10EB8000A5230014AF8800043C108000240CBFFFB4 +:10EB9000010C4824240B000236080180A50B000C50 +:10EBA000A50A000EA5060008A5090026A507001065 +:10EBB0003C071000AE0701B80A0010E88FBF002420 +:10EBC0003C0308008C6300D02E45000C001221C0CD +:10EBD000386B00012D6200010045F82417E0FF9A10 +:10EBE0003270FFFF264CFFFC2D840004548000503F +:10EBF00000002021386A00022D43000100658024B6 +:10EC00001600004A3270FFFF00076A420012702BA4 +:10EC100001AE40245500006300002021001221C0F5 +:10EC2000020028210A0010E53626000234DF000227 +:10EC30000280202133E6FFFF0E000F5530A5FFFFB5 +:10EC40000A0010AC00002021240401000200282149 +:10EC50000E000F55022030210A001098000000001D +:10EC60008C66400030CF010011E0003D30F801001B +:10EC70003C1208008E5200241300001132340004AC +:10EC80003C1F0F0000FFC8243C0502001325000CA8 +:10EC90008F8C000C022030213265FFFF018958243F +:10ECA00001641021904900043230FFFB2411FFFE63 +:10ECB000252700040E000F55000721C002519024A3 +:10ECC0002404000112440052324300011460005831 +:10ECD00002003021324A0004114000048F8D0000F0 +:10ECE00031A808001500005A3265FFFF1680FF5B4F +:10ECF0008FBF00243C138000366501803C048000F7 +:10ED00008C9001B80600FFFE24062000240F0002AC +:10ED1000A4A60008A0AF000BA4A000103C0E100099 +:10ED2000AC8E01B80A0010E88FBF0024000020213B +:10ED3000020028210A0010E5362600021140FEE9F3 +:10ED40000000A021952E0110950D000231C8FFFF93 +:10ED500051A8FEE40012A1C00A00108B8F92001C83 +:10ED60003C0508008CA5002430B800015300FF3B8F +:10ED70008FBF00243265FFFF3626000200002021ED +:10ED80000E000F55000000000A0010E88FBF00249D +:10ED9000362600020E000F55240400800A0010E8F9 +:10EDA0008FBF0024020028210E000F553226FFFBE2 +:10EDB0000A001159001221C0910300012402000130 +:10EDC0001062FEEA24040001241000021470FEC543 +:10EDD0000000A02130E300401060FEC38F92001CB1 +:10EDE000952B0110950900023167FFFF1127FEE006 +:10EDF0008FBF00240A00108B0000000024030003D2 +:10EE000034820180A043000B0A0011343C108000C2 +:10EE100032140004168000033265FFFF3612000230 +:10EE20003250FFFF020030210A0011B10000202102 +:10EE3000000020210E000F553265FFFF0A001186E9 +:10EE40003210FFFB241FFFFE0A001132011F402475 +:10EE5000020030210E000F55240401000A00118C1D +:10EE60000000000027BDFFC8AFB00010AFBF0034E6 +:10EE70003C10600CAFBE0030AFB7002CAFB600281E +:10EE8000AFB50024AFB40020AFB3001CAFB2001880 +:10EE9000AFB100148E0C5000240DFF7F3C058000A4 +:10EEA000018D5824356A380C24090003AE0A50003D +:10EEB000ACA900083C010800AC2000200E0017435C +:10EEC000000000003C0560168CA700003C08FFFF16 +:10EED0003C06001034C3805100E820243C02535308 +:10EEE000AE03537C1082026134A37C008C74007CDE +:10EEF0008C7500783C116000362420203C05080108 +:10EF000024A581142406000A3C1180003C13000251 +:10EF10003C12600CAF950010AF9400140E0015EC7D +:10EF2000363E0180AE5353FC8E3000003216000393 +:10EF300012C0FFFD3217000116E000583206000231 +:10EF400010C0FFF93C0480008C8F01402410004069 +:10EF5000AC8F00208C9201480012760231C3007001 +:10EF60001070013D2C67004150E00008240400604F +:10EF7000241500201075000E3C0340003C07800063 +:10EF8000ACE301780A00121B000000001464FFFBD0 +:10EF90003C0340000E001F5D000000003C034000E9 +:10EFA0003C078000ACE301780A00121B000000005F +:10EFB0008C830148241400043487018000034C0230 +:10EFC000312500FF8C83014010B4017124BFFFFA8A +:10EFD0002FF90006532000123C0580008C86014466 +:10EFE000241600FF30A500FF30CB00FF30CA00FF21 +:10EFF000115601BC256800042402000910A201AAD0 +:10F0000028AC000A118001962413000A240D000880 +:10F0100010AD00148F850018000819C03C05800051 +:10F020008CA801B80500FFFE24170002ACE3000025 +:10F03000A4E90008A0F7000B8CB401483C091000BB +:10F040003C034000A4F400108CA40144ACE4002470 +:10F050003C078000ACA901B8ACE301780A00121BA0 +:10F060000000000000067A020008A8803C040801A5 +:10F070002484828024AE000102A4902131E500FFA7 +:10F0800024100001A24F000014B0FFE3AF8E00185F +:10F09000000819C00A001258AF85001C8E340128E0 +:10F0A0003C028008AE3400208E2401048E2301002F +:10F0B000945F0048AF840000AF83000433F9FFFF82 +:10F0C0000E000F4EAF9900083C1808008F1800C0C2 +:10F0D000130000248F8700003C0708008CE700C461 +:10F0E00024E600013C010800AC2600C43C0380007B +:10F0F0008C6401243C076020ACE400140000000094 +:10F100003C0680003C154000ACD5013800000000F2 +:10F110005280FF8B32060002268C0140268D008033 +:10F120002409FF800189282401A99824001359404B +:10F1300031A2007F0005B140318A007F3C1F2000D2 +:10F1400037E800020162C02502CAC8250328A025AD +:10F150000308B825ACD70830ACD408300A00122117 +:10F16000320600023C05001000E54024150000A610 +:10F170008F8300043C0C08008D8C00203C0D800027 +:10F1800095AA010E258B000130E940003C010800E2 +:10F19000AC2B00203155FFFF112000B6000090215C +:10F1A0003C0F002000EF702411C000B330F7800046 +:10F1B0008F9300042416BFFF00F638243663100036 +:10F1C000AF87000030E22000104000B62405FFBFEA +:10F1D0003C08000400E8302410C000020065102440 +:10F1E0003462004030E901001120000EAF820004BB +:10F1F0003C0B002000EB5024114000043C0D0004A7 +:10F2000000ED602411800139000000009637011ED6 +:10F210009636011C32EFFFFF00169C0001F37025AB +:10F22000AF8E000C9639010C8E2440003418FFFF7D +:10F23000109800CA3325FFFF309F010057E00001FE +:10F240002412001030E31000106000133653000148 +:10F2500030E400201480000A3C06100000E6102470 +:10F260001040000D3C0C0C003C0B0BFF00EC50243C +:10F270003569FFFF012A402B1100000830EE010024 +:10F280003C0D08008DAD002C3653000525B2000161 +:10F290003C010800AC32002C30EE010015C0000B20 +:10F2A0003C0600018F880004310F400055E0000843 +:10F2B00000E628243C181F0100F8B8243C16100072 +:10F2C00052F6010E30B902003C06000100E6282487 +:10F2D00014A000A43C1F100000FF202400004021C7 +:10F2E000108000070000A82100075E023175000FA2 +:10F2F000001550803C0208012442828001424021D6 +:10F300008F8C001811800069026090211480000326 +:10F310003C0980003C080801250882809532010ED6 +:10F3200091030000026030213244FFFF2485000475 +:10F33000106000080000B821240D0003106D0122A8 +:10F34000241600029117000112F6002630F8004042 +:10F350000015B9C08F82001C504000013666004085 +:10F360003C1680008ECA400031530100126000C775 +:10F3700030D500043C0B08008D6B002430D3FFFB1C +:10F380003166000414C0010A30B2FFFF56A000012C +:10F390003673000402E02021024028210E000F55A0 +:10F3A0000260302116A0000D0000202136C501802A +:10F3B0003C0480008C8C01B80580FFFE240D2000E9 +:10F3C00024120002A4AD0008A0B2000BA4A00010FB +:10F3D0003C051000AC8501B8000020210A00135F35 +:10F3E000008010211300FFDB0000B821953F0110C1 +:10F3F0009519000233E8FFFF5328FFD60015B9C066 +:10F400000A0013278F82001C2413BFFF0073682497 +:10F4100011A00007240E87FF006E48241520000A63 +:10F420003C0F006000EF9024124000070000000035 +:10F430000E000D34000000001040FF323C0680003A +:10F440000A00128D3C0380000E0014C90000000069 +:10F450000A00135F000000000E0014EF000000001F +:10F460003C0340003C078000ACE301780A00121B1B +:10F470000000000030F7800012E0FF528F8300048C +:10F480003C19002000F9C0241300FF4E8F9F000498 +:10F490003C04FFFF34837FFF00E338240A0012C1DD +:10F4A00037E380000A0012CA006510243C040800FB +:10F4B0008C840038148000022489FFFF000048215A +:10F4C0003C038000946F010E31EEFFFF110000EB52 +:10F4D00025D600043C0308008C6300301060000A4D +:10F4E00030EA01008F9800043317400012E0000654 +:10F4F0003C020F0000E2F8243C190100033F402BBE +:10F50000110000D532C5FFFF114000303C0C0F0048 +:10F5100000EC58243C0602001166002C000000009C +:10F520008F95000C3C0D080025AD003832D2FFFF4E +:10F5300002A9282400ADB02192C7000424E90004E8 +:10F54000000921C002402821366600020E000F5536 +:10F55000000000000A00135F000010210A0012E200 +:10F56000241200203C1908008F3900D802A028215D +:10F5700024040080273800013C010800AC3800D882 +:10F580000E000F55240600030A00135F000010212F +:10F590008C84014000E028213C0380008C7701B876 +:10F5A00006E0FFFE2408001CACA40000A0A8000B8D +:10F5B0003C181000AC7801B83C0340003C078000C8 +:10F5C000ACE301780A00121B000000003C030800B5 +:10F5D0008C6300D02EA5000C001521C0386F0001EF +:10F5E0002DF200010245702415C0FFD632D2FFFF74 +:10F5F00026B7FFFC2EE40004148000080000202140 +:10F60000386800022D180001030518241060000658 +:10F610000007FA4232D2FFFF0000202102402821D9 +:10F620000A0013A4366600020015102B03E2C8245A +:10F630001720000532D2FFFF001521C0024028210B +:10F640000A0013A43666000200002021024028218F +:10F650000E000F553266FFFB0A0013E0001521C0B3 +:10F6600010B3006A000860802406000B14A6FE6B2D +:10F67000000819C0000828803C15080126B58280C2 +:10F6800000B530210A001258A0C0000134D5000294 +:10F6900002E0202130A5FFFF0E000F5532A6FFFF2C +:10F6A0000A001348000020210008B8803C0308012C +:10F6B0002463828002E31021905400001280FE57E0 +:10F6C000000819C0A04000008F9900182738FFFFDC +:10F6D0001700FE52AF980018000819C00A0012580F +:10F6E000AF80001C0A00124F240800030E000FBC5C +:10F6F000000000000A0012DA8F8700001720FEF3D6 +:10F700003C06000126BF000433E5FFFF3666000219 +:10F710003C0380008C7501B806A0FFFE8F890008AD +:10F720003C04800034930180AE60000011200099F9 +:10F73000240F000324AA0012012A102B1040009568 +:10F7400000000000946D01203C1280002403001A88 +:10F7500031ACFFFF364A018030EB4000A143000B83 +:10F760001160008F2583FFFE0123702B15C0008DD3 +:10F770002409FFFE35080001A5430014AF880004EA +:10F780002417BFFF0117B02424080002A7C8000CEB +:10F79000A7C5000EA7C60008A7D60026A7C7001059 +:10F7A0003C071000AE2701B80A00135F00001021CB +:10F7B00024040100024028210E000F550260302170 +:10F7C0000A00133400000000910300012415000119 +:10F7D0001075FF0224040001240E0002146EFEDDE9 +:10F7E0000000B82130E300401060FEDB8F82001C77 +:10F7F00095270110950F000230E9FFFF11E9FF0E78 +:10F80000008010210A0013278F82001C3C0F080182 +:10F8100025EF8280018F702100069202A1D20001A3 +:10F820003C1F60008FED1820241000010110980487 +:10F830003C0208012442828201B3B025018250219A +:10F8400000065C02000819C0A54B0000AFF61820A6 +:10F850000A0012593C058000366600020E000F5562 +:10F86000240400800A00135F000010218CAE000405 +:10F870003C0F60000A00120C01CF18218C6640007A +:10F8800030CA01001140003730EB01003C15080080 +:10F890008EB5002411600013327700043C0D0F0078 +:10F8A00000ED28243C0C020010AC000E8F84000CEC +:10F8B0003C0F080025EF00380260302100899024B9 +:10F8C000024F702191C7000432C5FFFF3272FFFB67 +:10F8D00024E90004000921C00E000F552413FFFE87 +:10F8E00002B3A8242403000112A3003032B800019F +:10F8F0001300000732A8000402403021000020213C +:10F900000E000F5532C5FFFF3252FFFB32A8000434 +:10F91000110000048F9F000033F908005720002BCE +:10F9200032C5FFFF16E0FEC4000010213C16800027 +:10F9300036C401803C0580008CA201B80440FFFE63 +:10F94000240B200024060002A48B0008A086000BD4 +:10F95000A48000103C0A1000ACAA01B80A00135F92 +:10F96000000010213C0508008CA5002430AC0001EB +:10F970005180FEB10000102132C5FFFF3666000243 +:10F98000000020210E000F55000000000A00135F48 +:10F9900000001021A3CF000B0A0014322417BFFF70 +:10F9A0002409FFFE0A0014300109402432550004E6 +:10F9B00016A0000332C5FFFF3657000232F2FFFFE8 +:10F9C000024030210A0014B2000020210240302100 +:10F9D0000E000F55240401000A00149A00000000D4 +:10F9E0003C0380008C6401003082003E144000081B +:10F9F00000000000AC6000488C66010030C507C004 +:10FA000010A0000500000000AC60004CAC6000508D +:10FA100003E0000824020001AC600054AC60004028 +:10FA20008C6801003107380010E0FFF90000000089 +:10FA30002402000103E00008AC6000443C03900095 +:10FA400034620001008220253C038000AC64002069 +:10FA50008C65002004A0FFFE0000000003E0000809 +:10FA6000000000003C028000344300010083202598 +:10FA700003E00008AC44002027BDFFD8AFB100145C +:10FA80003C048000AFBF0020AFB3001CAFB2001831 +:10FA9000AFB000108C9201408C9001482402000EFF +:10FAA00000108C02322300FF106200590204282447 +:10FAB0002866000F10C00013286A003724070006CC +:10FAC0001067008E286800075100002D24040009EB +:10FAD000106000783C06800024090001106900B025 +:10FAE000000000000000000D8FBF00208FB3001C3D +:10FAF0008FB200188FB100148FB0001003E000081F +:10FB000027BD002811400059240D0038286B00350E +:10FB1000116000053C058000240C001F146CFFF1EF +:10FB2000000000003C0580008CB801B80700FFFE13 +:10FB300034B90180AF320000241F000124120002FA +:10FB40003C021000AF200004A7310008A33F000AC8 +:10FB5000A332000BA7300010AF200024AF200028F4 +:10FB6000ACA201B88FBF00208FB3001C8FB2001869 +:10FB70008FB100148FB0001003E0000827BD0028EB +:10FB8000106400232405000B1465FFD63218FFFF14 +:10FB9000170000203C0580008F93FEEC927F00054B +:10FBA00033F900041720FFCF000000000E0014E01E +:10FBB00002402021926900050240202135280004DE +:10FBC0000E0014EAA26800059267000530E2000406 +:10FBD00014400002000000000000000D926B0000C5 +:10FBE00024060020316A00FF1546000A3C0580000B +:10FBF0008CA401B80480FFFE34AD0180240E000502 +:10FC00003C0C1000ADB20000A1AE000BACAC01B8D2 +:10FC10003C0580008CA301B80460FFFE34AF018076 +:10FC200024130002ADF20000ADF20004A5F10008BB +:10FC3000A1F3000AA1F3000BA5F00010ADE0002431 +:10FC40008CB101443C101000ADF10028ACB001B8FB +:10FC50008FBF00208FB3001C8FB200188FB100142B +:10FC60008FB0001003E0000827BD0028106DFFAD25 +:10FC7000240E0080146EFF9B000000003C058000F5 +:10FC80008CA301B80460FFFE34AF0180241200028F +:10FC9000A1F2000BA5F10008A5F000108CB30144FF +:10FCA0003C021000A5F30012ACA201B80A00152B0B +:10FCB0008FBF00208CC301B80460FFFE34D30180E5 +:10FCC000AE720000AE60000424120001A6710008AC +:10FCD00024110002A272000AA271000BA67000108B +:10FCE0008CD001443C0F1000AE700024AE600028A0 +:10FCF000ACCF01B80A0015668FBF00203C0380001E +:10FD00008C6601B804C0FFFE346201803C06080125 +:10FD100090C682C0AC52000010C000030000382121 +:10FD20003C0708018CE782C83C05800034AA0180AA +:10FD30002404000234CC0001AC470004A5510008A3 +:10FD4000A14C000AA144000BA55000108CAB01444B +:10FD50000000202101402821AD4B002410C00003E9 +:10FD60008FBF00203C0408018C8482C48FB3001C28 +:10FD70008FB200188FB100148FB000103C0E10002D +:10FD80003C0D800027BD0028ACA40028ADAE01B812 +:10FD90003C010801A02082C003E000080000000030 +:10FDA00010A0000B3C0680008C980144241900022E +:10FDB0003C010801A03982C03C010801AC3282C874 +:10FDC0003C010801AC3882C40A0015668FBF0020D0 +:10FDD0008CDF01B807E0FFFE34C701802409000270 +:10FDE000ACF20000ACF20004A4F10008A0E9000AA3 +:10FDF000A0E9000BA4F00010ACE000248CC8014482 +:10FE00003C021000ACE80028ACC201B80A0015663C +:10FE10008FBF002027BDFFE8AFBF00100E000F4EC0 +:10FE2000000000003C0280008FBF00100000202175 +:10FE3000AC4001800A00101027BD00183084FFFF7D +:10FE400030A5FFFF1080000700001821308200015C +:10FE50001040000200042042006518211480FFFBBE +:10FE60000005284003E000080060102110C00007D2 +:10FE7000000000008CA2000024C6FFFF24A500049F +:10FE8000AC82000014C0FFFB2484000403E00008DF +:10FE90000000000010A0000824A3FFFFAC860000B3 +:10FEA00000000000000000002402FFFF2463FFFFA9 +:10FEB0001462FFFA2484000403E00008000000003C +:10FEC00027BDFFE8AFBF0014AFB000100E0014E074 +:10FED000008080213C0480083483008090650025E8 +:10FEE0000200202134A200200E0014EAA0620025A6 +:10FEF000020020218FBF00148FB000100A000C9E5A +:10FF000027BD00183C03800027BDFFF83462018044 +:10FF1000AFA20000308C00FF30AD00FF30CE00FFFC +:10FF20003C0B80008D6401B80480FFFE00000000DF +:10FF30008FA900008D6801288FAA00008FA70000FC +:10FF40008FA400002405000124020002A085000AFD +:10FF50008FA30000359940003C051000A062000B03 +:10FF60008FB800008FAC00008FA600008FAF00009C +:10FF700027BD0008AD280000AD400004AD8000247E +:10FF8000ACC00028A4F90008A70D0010A5EE0012CF +:10FF900003E00008AD6501B83C06800827BDFFE816 +:10FFA00034C50080AFBF001090A7000924020012E2 +:10FFB00030E300FF1062000B008030218CA800505D +:10FFC00000882023048000088FBF00108CAA003412 +:10FFD000240400390000282100CA48230520000518 +:10FFE000240600128FBF00102402000103E0000865 +:10FFF00027BD00180E001612000000008FBF001071 +:020000040001F9 +:100000002402000103E0000827BD001827BDFFC837 +:10001000AFB1002C00A08821AFB2003027A500109E +:100020000080902102202021AFBF0034AFB0002813 +:100030000E000CA8AFA000101440009B3C078008E5 +:1000400034E400809086000830C5000814A00069E0 +:100050008FA700103C18800837100080920F00080E +:1000600031EE000815C00002240800030000402102 +:100070003C0B800891650011916A00123566008082 +:100080008CDF0054314900FF0128202130A300FFFC +:10009000000410800062282100BFC82B1320000834 +:1000A0000000000094D0005C8CCF0054320DFFFFA4 +:1000B00001E5702301AE602B118000940000000068 +:1000C00094D9005C3323FFFF30FF000413E0007479 +:1000D000000830808FA8001C0068102B5040004F93 +:1000E00030E30004006610232C46008010C000029C +:1000F00000408021241000800E0014E002402021E6 +:100100003C0380083466008024070001ACC7000C63 +:1001100090C800080010684034670100311F007F5C +:10012000A0DF00088E39000427380001ACD8003069 +:10013000A4D0005C8CCF003C9630000E01F0702102 +:10014000ACCE00208CCC003C018D5821ACCB001CE7 +:100150008E2A0004ACEA00008E290008ACE90004F5 +:100160008FA5001030A400085480003293A6002010 +:10017000A0C0004E90C9004E2402FFDF3C1880084A +:10018000A0E9000890C50008370D0080240A00503F +:1001900000A22024A0C400088E390008ADB90038A0 +:1001A0008F0F00148DB0003001F07021ADAE00341F +:1001B00091AC0000318B00FF116A002C2645010034 +:1001C0000E0014EA024020212404003800002821F7 +:1001D0000E0016122406000A8FBF00348FB20030C2 +:1001E0008FB1002C8FB000282402000103E000082A +:1001F00027BD003830E801001100003D8FA3001436 +:100200008C8A0058006A48230520FF933C18800818 +:10021000AC8300580A0016668FA700102407021846 +:100220001060FFB100E610238FA2001C0A00168B9D +:10023000004610233C188008370D0080A0E6000817 +:100240008E390008240A0050ADB900388F0F001411 +:100250008DB0003001F07021ADAE003491AC0000E3 +:10026000318B00FF156AFFD6264501002406FF806A +:1002700000A610243C098000AD2200288E2700082B +:1002800030A3007F3C04800C0064F821AFE700D06D +:100290008E280008AF9F00280A0016C1AFE800D4DE +:1002A0000A0016882C6202188E2300083C0480087D +:1002B00034820080AC430054024020210E0016011D +:1002C000AC400030240400382405008D0E001612C6 +:1002D000240600128FBF00348FB200308FB1002C83 +:1002E0008FB000282402000103E0000827BD003879 +:1002F000AC800058908C0008240DFFF7018D582425 +:10030000A08B00080A0016668FA700108CD8005436 +:100310000A0016830305182327BDFFE8AFBF0010AE +:1003200090A6000D30C7001010E0000C00804021A6 +:100330003C0280088C4400048CA300081064000870 +:1003400030C9000430C5000410A0001C8FBF00108D +:100350002402000103E0000827BD001830C9000492 +:100360001120001030CB001210E0FFF98FBF0010F9 +:100370003C0880088CA700088D06000414E6FFF5F1 +:1003800024020001240400382405008D0E001612FA +:10039000240600128FBF00102402000103E00008B1 +:1003A00027BD0018240A0012156AFFE98FBF00104C +:1003B000010020210A00165427BD0018000020214A +:1003C0000A000D1A27BD00183C05080024A55D5041 +:1003D0003C04080024847B103C02080024425D5841 +:1003E000240300063C010801AC2582D03C01080131 +:1003F000AC2482D43C010801AC2282D83C01080123 +:10040000A02382DC03E000080000000003E00008F5 +:10041000240200013C028000308800FF3447018044 +:100420003C0680008CC301B80460FFFE00000000A1 +:100430008CC501282418FF803C0D800A24AF0100E0 +:1004400001F8702431EC007FACCE0024018D202116 +:10045000ACE50000948B00DA350960002408000246 +:10046000316AFFFFACEA000424020001A4E900089D +:10047000A0E8000BACE000243C071000ACC701B8BA +:10048000AF84002803E00008AF8500588C99000471 +:100490008F8D00282409FFBF0325C023AC980004DA +:1004A00091AF00C42403FFEF31EE007FA1AE00C482 +:1004B0008C8C0020938B00348F860028358A0002B4 +:1004C000AF8B004CA7800048AC8A0020A4C000ACD1 +:1004D00090C800C401093824A0C700C48F84002834 +:1004E000AC8000DC908500C400A3102403E0000869 +:1004F000A08200C43C028000344501803C0480009E +:100500008C8301B80460FFFE8F8900582407608344 +:1005100024060002ACA900008C880124ACA80004C9 +:10052000A4A70008A0A6000B3C05100003E00008EB +:10053000AC8501B8938800348F89004C8F820028E5 +:1005400030C600FF0109382330E900FF01221821DD +:1005500030A500FF2468007810C000020124382173 +:100560000080382130E400031480000330AA000327 +:100570001140000D312B000310A0000900001021D4 +:1005800090ED0000244E000131C200FF0045602BB9 +:10059000A10D000024E700011580FFF925080001E6 +:1005A00003E00008000000001560FFF300000000F9 +:1005B00010A0FFFB000010218CF80000245900045B +:1005C000332200FF0045782BAD18000024E700041B +:1005D00015E0FFF92508000403E000080000000012 +:1005E00093850034938800448F87004C00043200C8 +:1005F0003103007F00E5102B30C47F001040000F56 +:10060000006428258F8400283C0980008C8A00DC47 +:10061000AD2A00A43C03800000A35825AC6B00A0C9 +:100620008C6C00A00580FFFE000000008C6D00AC0B +:10063000AC8D00DC03E000088C6200A80A0017D62D +:100640008F840028938800453C0280000080502160 +:10065000310300FEA383004530ABFFFF30CC00FF29 +:1006600030E7FFFF344801803C0980008D2401B849 +:100670000480FFFE8F8D005824180016AD0D000079 +:100680008D2201248F8D0028AD0200048D59002099 +:10069000A5070008240201B4A119000AA118000B43 +:1006A000952F01208D4E00088D4700049783004848 +:1006B0008D59002401CF302100C7282100A3202319 +:1006C0002418FFFFA504000CA50B000EA5020010C6 +:1006D000A50C0012AD190018AD18002495AF00D874 +:1006E0003C0B10002407FFF731EEFFFFAD0E002892 +:1006F0008DAC0074AD0C002CAD2B01B88D460020E4 +:1007000000C7282403E00008AD4500208F8800289A +:100710000080582130E7FFFF910900C63C028000AD +:1007200030A5FFFF312400FF00041A0000675025A8 +:1007300030C600FF344701803C0980008D2C01B891 +:100740000580FFFE8F820058240F0017ACE20000E6 +:100750008D390124ACF900048D780020A4EA00084A +:10076000241901B4A0F8000AA0EF000B9523012082 +:100770008D6E00088D6D00049784004801C35021E0 +:10078000014D602101841023A4E2000CA4E5000EB9 +:10079000A4F90010A4E60012ACE000148D78002447 +:1007A000240DFFFFACF800188D0F006CACEF001C9F +:1007B0008D0E00683C0F1000ACEE0020ACED002464 +:1007C000950A00AE240DFFF73146FFFFACE6002886 +:1007D000950C00709504007231837FFF0003CA00FE +:1007E0003082FFFF0322C021ACF8002CAD2F01B8EE +:1007F000950E00728D6A002000AE3021014D282434 +:10080000A506007203E00008AD6500203C028000F0 +:10081000344601803C0580008CA301B80460FFFED3 +:1008200024090018ACC40000A0C9000B8F88002860 +:100830003C041000950700AEA4C70010ACC0003007 +:1008400003E00008ACA401B83C02800034450180FC +:100850003C0480008C8301B80460FFFE8F8A003066 +:10086000240600199549001C3128FFFF000839C0F3 +:10087000ACA70000A0A6000B3C05100003E0000898 +:10088000AC8501B88F8700380080402130C400FF5C +:100890003C0680008CC201B80440FFFE8F890058DE +:1008A0009383005434996000ACA90000A0A3000514 +:1008B0008CE20010240F00022403FFF7A4A200061C +:1008C000A4B900088D180020A0B8000AA0AF000B42 +:1008D0008CEE0000ACAE00108CED0004ACAD00144A +:1008E0008CEC001CACAC00248CEB0020ACAB0028E2 +:1008F0008CEA002C3C071000ACAA002C8D090024C7 +:10090000ACA90018ACC701B88D05002000A32024B5 +:1009100003E00008AD040020938500542403000187 +:1009200027BDFFE800A330042CA20020AFB00010C8 +:10093000AFBF001400C01821104000132410FFFEA8 +:100940003C0708008CE7319000E610243C0880004A +:100950003505018014400005240600848F89002895 +:10096000240A00042410FFFFA12A00EC0E001872D4 +:1009700000000000020010218FBF00148FB0001093 +:1009800003E0000827BD00183C0608008CC631941F +:100990000A0018A400C310248F87003027BDFFE091 +:1009A000AFB20018AFB10014AFB00010AFBF001C61 +:1009B00030D000FF90E6000D00A08821008090213B +:1009C00030C5007FA0E5000D8F8500288E2300181C +:1009D0008CA200C01062002E240A000E0E00189790 +:1009E000A38A00542409FFFF104900222404FFFFBA +:1009F00052000020000020218E2600003C0C001038 +:100A000000CC5824156000393C0E000800CE682444 +:100A100055A0003F024020213C18000200D880244D +:100A20001200001F3C0A00048F8700308CE2001483 +:100A30008CE300108CE500140043F82303E5C82B79 +:100A400013200005024020218E24002C8CF1001080 +:100A5000109100310240202124020012A382005490 +:100A60000E0018972412FFFF105200022404FFFF0B +:100A7000000020218FBF001C8FB200188FB100141E +:100A80008FB000100080102103E0000827BD002077 +:100A900090A800C4350400200A0018CDA0A400C40A +:100AA00000CA48241520000B8F8B00308F8D00303A +:100AB0008DAC00101580000B024020218E2E002CE2 +:100AC00051C0FFEC00002021024020210A0018E85C +:100AD000240200178D66001050C0FFE600002021A0 +:100AE000024020210A0018E82402001102402021BF +:100AF000240200150E001897A3820054240FFFFF54 +:100B0000104FFFDC2404FFFF0A0018D78E260000D8 +:100B10000A00190E240200143C08000400C83824FE +:100B200050E0FFD400002021024020210A0018E8F4 +:100B3000240200138F86002827BDFFE0AFB1001408 +:100B4000AFBF0018AFB0001090C300C430A500FFC5 +:100B50003062002010400008008088218CCB00C04B +:100B60002409FFDF256A0001ACCA00C090C800C498 +:100B700001093824A0C700C414A000403C0C800028 +:100B80008F840028908700C42418FFBF2406FFEF3D +:100B900030E3007FA08300C4979F00488F82004C01 +:100BA0008F8D002803E2C823A7990048A5A000ACB8 +:100BB00091AF00C401F87024A1AE00C48F8C00284E +:100BC000A18000C78F8A0028A5400072AD4000DCDC +:100BD000914500C400A65824A14B00C48F90002466 +:100BE0008F84004C978600480204282110C0000F13 +:100BF000AF850024A38000443C0780008E2C0008B1 +:100C000094ED01208E2B0004018D5021014B802199 +:100C1000020620233086FFFF30C8000F390900018B +:100C20003131000116200009A38800449386003466 +:100C30008FBF00188FB100148FB0001027BD0020A7 +:100C4000AF85005003E00008AF86004C00C8702359 +:100C50008FBF0018938600348FB100148FB000103E +:100C600034EF0C00010F282127BD0020ACEE0084DA +:100C7000AF85005003E00008AF86004C359001803E +:100C8000020028210E001872240600828F8400289A +:100C9000908600C430C5004050A0FFBAA380005425 +:100CA0008F8500383C0680008CCD01B805A0FFFE82 +:100CB0008F8900582408608224070002AE090000D2 +:100CC000A6080008A207000B8CA300083C0E100029 +:100CD000AE0300108CA2000CAE0200148CBF0014F6 +:100CE000AE1F00188CB90018AE1900248CB800246F +:100CF000AE1800288CAF0028AE0F002CACCE01B887 +:100D00000A001932A38000548F8A002827BDFFE013 +:100D1000AFB10014AFB000108F88004CAFBF001807 +:100D20009389002C954200AC30D100FF0109182BAB +:100D30000080802130AC00FF3047FFFF00005821C9 +:100D400014600003310600FF0120302101095823FF +:100D5000978300480068202B1480001B00000000CF +:100D600010680043240A0001118A004834E7088013 +:100D70003165FFFF0E001814020020210E001854E8 +:100D80008F8400588F840028948D007025AC00015A +:100D9000A48C0070948B00703C0608008CC63188CF +:100DA00031677FFF10E6004F0000000002002021A5 +:100DB000022028218FBF00188FB100148FB00010BF +:100DC0000A00191E27BD0020914400C42406FF809C +:100DD00000868825A15100C4978400483088FFFF11 +:100DE0001100001C9389002C8F8E00282419EFFF1E +:100DF000008BF82395D800AC0168682B33E900FF1D +:100E000003197824A5CF00AC51A0002A0100582175 +:100E10008E0500202408FFFB2403000100A81024F5 +:100E2000AE0200201183002534E78000020020215B +:100E30003165FFFF0E00181401203021978B004808 +:100E40008F87004CA780004800EB8023AF90004CB8 +:100E50009389002C8F8C00288FBF00188FB100144D +:100E60008FB0001027BD002003E00008A18900C753 +:100E70008E0800202409FFFB34E7800001092824A4 +:100E8000AE050020158AFFBA34E708800200202151 +:100E90000E0017E23165FFFF020020210220282109 +:100EA0008FBF00188FB100148FB000100A00191EF8 +:100EB00027BD00200A0019D500004821020020218A +:100EC0003165FFFF0E0017E201203021978B0048AB +:100ED0008F87004CA780004800EB80230A0019E5AB +:100EE000AF90004C94890070240A8000012A4024AD +:100EF000A4880070908500709099007030A200FF67 +:100F0000000219C20003F827001FC1C0332F007F61 +:100F100001F87025A08E00700A0019BD0200202182 +:100F20008F88002824030001910A0078910500C7EA +:100F3000250900783147003F24E6FFE000C318048C +:100F40002CC2002030670019A385002C1040001A25 +:100F5000AF8900383C0A8000354B000224050001AF +:100F60002406000114E00016006B10240000282164 +:100F70001440000F306300201060000F24050001B2 +:100F80008D0600748D1900742403FF8000C31024A3 +:100F9000000279403338007F01F868253C0E1000CC +:100FA00001AE6025AD4C08309128000131060001EA +:100FB0000A0019930000000003E000080000000090 +:100FC0008D0F00748D0D00742418FF8001F87024BB +:100FD000000E414031AC007F010C50253C0B10004D +:100FE000014B38253C0980000A001993AD270830D1 +:100FF00027BDFFD8AFB000108F900038AFB40020ED +:10100000AFB10014AFBF0024AFB3001CAFB20018E3 +:101010008E0500103C0208008C4231B08F86003CE7 +:1010200030A73FFF00E2182B8CD2001400808821EB +:101030008CD30020106000070000A02190CB000D91 +:10104000240AFF80014B4824312800FF1500000CC2 +:1010500000056382022020212411000DA391005479 +:101060008FBF00248FB400208FB3001C8FB20018F4 +:101070008FB100148FB000100A00189727BD002808 +:101080003185000354A0FFF40220202194CF001CDE +:101090008F8E00288E070028A5CF00D88CCD001099 +:1010A000024D302310E6005C2402001F0E0018974A +:1010B000A3820054241FFFFF105F004E2404FFFF93 +:1010C0008F8300408F880030026398218D090010C3 +:1010D000012310238F830020AD020010AD130020E8 +:1010E0008C67007400F3202B148000620220202102 +:1010F0008F86003C8E0C00248CC5002411850007CF +:1011000002202021240E001C0E001897A38E0054EC +:10111000240DFFFF104D00372404FFFF8F840030A3 +:101120008C980024270F0001AC8F00241272004419 +:101130008F9900208F320074125300413C0A0080C6 +:101140008E090000012A10241440003A000000001B +:101150008E0400142412FFFF10920006240B001BC3 +:10116000022020210E001897A38B0054105200215A +:101170002404FFFF8E0300003C0C0001006C2824B7 +:1011800010A000133C0600800066A0241680000911 +:101190000200282102202021240E001A0E00189798 +:1011A000A38E0054240DFFFF104D00122404FFFFF6 +:1011B00002002821022020210E0018B72406000179 +:1011C0002410FFFF2404FFFF1050000A2414000124 +:1011D0008F8F0030022020210280302195F20034D0 +:1011E00024050001265800010E001993A5F80034CB +:1011F000000020218FBF00248FB400208FB3001C7B +:101200008FB200188FB100148FB000100080102131 +:1012100003E0000827BD00288F83004000E3C821B9 +:101220000259C02B1300FFA88F8800300A001A7CD7 +:1012300024020018AC8000200A001AA68E040014B4 +:101240008E1F00003C07008003E798241660FFF91A +:101250002408001A022020210E001897A3880054A9 +:101260002403FFFF1443FFBA2404FFFF0A001ACF30 +:101270008FBF0024240B001D0E001897A38B005471 +:10128000240AFFFF144AFF9A2404FFFF0A001ACF22 +:101290008FBF00248F85002827BDFFD8AFB3001C67 +:1012A000AFB20018AFB10014AFB00010AFBF002054 +:1012B00090A700C48F9000382412FFFF34E2004052 +:1012C00092060000A0A200C48E03001000809821A6 +:1012D0001072000630D1003F2408000D0E00189750 +:1012E000A3880054105200262406FFFF8F8A00288E +:1012F0008E0900188D4400C011240007240C000E34 +:10130000026020210E001897A38C0054240BFFFFCD +:10131000104B001B2406FFFF2404002012240004AD +:101320008F8D002891AF00C435EE0020A1AE00C41F +:101330008F85004010A0001A000000001224004B0E +:101340008F9800288F92FEEC2406FFFD9710007006 +:101350009651000A1230000B8FBF00203C1F08007E +:101360008FFF318C03E5C82B1720001E026020215F +:10137000000028210E0019932406000100003021EE +:101380008FBF00208FB3001C8FB200188FB10014E4 +:101390008FB0001000C0102103E0000827BD002816 +:1013A0005224002A8E0300148F8400289489007030 +:1013B00025280001A4880070948700703C0508006F +:1013C0008CA5318830E27FFF1045000E0000000040 +:1013D000026020210E00191E240500010A001B31A5 +:1013E000000030212402002DA38200540E00189723 +:1013F0002413FFFF1453FFE12406FFFF0A001B32F2 +:101400008FBF0020949800702419800024050001EB +:1014100003199024A492007090910070908D007038 +:10142000323000FF001079C2000F7027000E61C03B +:1014300031AB007F016C5025A08A00700E00191E90 +:10144000026020210A001B31000030212406FFFF2A +:101450001466FFD68F840028026020210E00191E1A +:10146000240500010A001B31000030210260202108 +:101470000A001B4B2402000A8F88002827BDFFE8C2 +:10148000AFB00010AFBF0014910A00C48F870038BE +:1014900000808021354900408CE60010A10900C47D +:1014A0003C0208008C4231B030C53FFF00A2182B2F +:1014B000106000078F85003C240DFF8090AE000D6A +:1014C00001AE6024318B00FF156000080006C38266 +:1014D000020020212403000D8FBF00148FB00010E4 +:1014E00027BD00180A001897A38300543306000391 +:1014F000240F000254CFFFF70200202194A2001C09 +:101500008F85002824190023A4A200D88CE80000AD +:1015100000081E02307F003F13F900353C0A0083AB +:101520008CE800188CA600C011060008000000001E +:101530002405000E0E001897A38500542407FFFF12 +:10154000104700182404FFFF8F85002890A900C4CD +:1015500035240020A0A400C48F8C0030918E000D93 +:1015600031CD007FA18D000D8F8300401060001CE5 +:10157000020020218F84003C8C9800100303782BFC +:1015800011E0000D2419001802002021A399005435 +:101590000E0018972410FFFF105000022404FFFFD4 +:1015A000000020218FBF00148FB000100080102198 +:1015B00003E0000827BD00188C8600108F9F0030C4 +:1015C0000200202100C31023AFE200102405000117 +:1015D0000E001993240600010A001BBA0000202106 +:1015E0000E00191E240500010A001BBA000020216C +:1015F000010A5824156AFFD98F8C0030A0A600EC90 +:101600000A001BA7A386004627BDFFD8AFB0001075 +:101610008F900038AFB20018AFBF0020AFB3001CEE +:10162000AFB100148E1100103C0308008C6331B080 +:1016300032253FFF00A3102B1040000800809021AE +:101640008F86003C2409FF8090CA000D012A4024A7 +:10165000310700FF14E0000B00116B8202402021D3 +:101660002412000DA39200548FBF00208FB3001CE2 +:101670008FB200188FB100148FB000100A001897B5 +:1016800027BD002831AC0003240B0001558BFFF46B +:101690000240202190CF000D31EE000811C0006003 +:1016A0008F93004016600009240200278E19000C59 +:1016B0008CD8002017380005240200208E02000874 +:1016C0008CDF0024105F0040240200200E001897D9 +:1016D000A38200542406FFFF104600332404FFFFBA +:1016E0008F990030240AFFF73C13800E9329000DD8 +:1016F0002404FF803C0D8000012AF824A33F000D44 +:101700008F9900203C0808008D0831AC8F83005869 +:10171000972700788F9F00300103102130E57FFF6D +:10172000000530400046782131F8007F0313602126 +:1017300001E47024ADAE002CA59100008FEB0028D1 +:10174000256A0001AFEA00288FE3002C8E09002CE7 +:1017500000694021AFE8002C8E07002CAFE7003075 +:101760008E050014AFE5003497E6003A24C200016C +:10177000A7E2003A973300783C1008008E1031B091 +:101780002663000130717FFF123000270060302196 +:101790008F8F002002402021240500010E00191E19 +:1017A000A5E60078000020218FBF00208FB3001C29 +:1017B0008FB200188FB100148FB00010008010217C +:1017C00003E0000827BD00288E0500142413FFFF46 +:1017D00010B3001D8F8300288E0800188C6700C08E +:1017E000150700092402000E8E0A00248CC9002867 +:1017F00015490005240200218E0700288CCB002CFF +:1018000010EB00132402001F0E001897A38200544F +:101810001453FFB32404FFFF0A001C3C8FBF0020B9 +:101820000A001C0424020024240E8000006E682498 +:1018300031ACFFFF000C5BC2317100FF001180274B +:101840000A001C35001033C00A001C532402002576 +:101850008E05002C10A0FFEC240200238F8E0020A8 +:101860008DCD007401A5602B1580FFE724020026B2 +:101870008CCF001400A7C02101F8202B1080FF9905 +:101880008F990030024020210A001C5324020022BC +:1018900027BDFFE0AFB000108F900038AFB100144B +:1018A000AFBF00188E0500103C0308008C6331B0F8 +:1018B0000080882130A43FFF0083102B10400007D8 +:1018C0008F86003C2409FF8090CA000D012A402425 +:1018D000310700FF14E000098F8B00402410000D39 +:1018E00002202021A39000548FBF00188FB1001454 +:1018F0008FB000100A00189727BD00201160000863 +:101900000005C3828F8F00288F8EFEEC2407FFFD19 +:1019100095EC007095CD000A11AC00388FBF00180F +:101920003305000314A0001000000000921900020B +:1019300013200041000000008E06002450C0000F5C +:1019400092040003022020212402000F0E001897A9 +:10195000A38200542408FFFF144800072407FFFF58 +:101960000A001CD08FBF001890C3000D306400081F +:101970001080003702202021920400032407000277 +:10198000308900FF15270005308F00FF8F8A004047 +:1019900011400031240C002C308F00FF39E500107D +:1019A0002CAD00012DEE00010200282101CD3025D3 +:1019B0000E0018B7022020212410FFFF1050000E47 +:1019C0002407FFFF8F8300401060001702202021B2 +:1019D0003C1908008F39318C0323C02B5700000CB1 +:1019E0002411002D02202021000028210E0019932F +:1019F00024060001000038218FBF00188FB10014A9 +:101A00008FB0001000E0102103E0000827BD002087 +:101A10000E001897A39100541450FFF62407FFFFFF +:101A20000A001CD08FBF00180E00191E24050001EB +:101A30000A001CCF000038218CDF00248E02002415 +:101A4000545FFFC1022020210A001CB09204000351 +:101A50000A001CA424020010022020210E00189766 +:101A6000A38C0054240BFFFF104BFFE32407FFFF60 +:101A70000A001CB79204000330A500FF24060001F1 +:101A800024A9000100C9102B1040000C00004021C7 +:101A9000240A000100A61823308B000124C600018F +:101AA000006A3804000420421160000200C9182BAB +:101AB000010740251460FFF800A6182303E0000882 +:101AC0000100102127BDFFD8AFB000188F9000385B +:101AD000AFB1001CAFBF00202403FFFF2411002F73 +:101AE000AFA3001092060000240500082610000194 +:101AF000006620260E001CEF308400FF00021E004E +:101B00003C021EDC34466F410A001D170000102104 +:101B100010A00009008018212445000130A2FFFF19 +:101B20002C4500080461FFFA0003204000862026AF +:101B300014A0FFF9008018210E001CEF24050020DE +:101B40008FA300102629FFFF313100FF000342025E +:101B5000240700FF1627FFE2010218260003502782 +:101B6000AFAA0014AFAA00100000302127A800106F +:101B700027A7001400E6782391ED000324CE00018E +:101B800000C8602131C600FF2CCB00041560FFF9AE +:101B9000A18D00008FA200108FBF00208FB1001C0C +:101BA0008FB0001803E0000827BD0028938300349D +:101BB00027BDFFE024020034AFB10014AFB0001025 +:101BC000AFBF001CAFB20018008088211062006215 +:101BD00000A0802192040004148000458F88002812 +:101BE000A380002C8E0500048D0600C83C0700FF72 +:101BF00034E3FFFF00A3282400C5102B1440004D40 +:101C0000AF850040978A00488F87004C014710231A +:101C100010A00032A78200488F980020304CFFFFB0 +:101C20009312007C0012788231F100010011708063 +:101C300001C56821018D582B116000618F86002835 +:101C40008F8900248F8400501089005E3C023F0180 +:101C50008E1F00003C10250003E2C8241730007AD4 +:101C60008F8400388F8700388F8600288CE300002F +:101C7000ACC300788CE50010ACC500888F87004CA1 +:101C80008F850040938D002C30AE0003000E402362 +:101C9000310A0003014D4021A388002C94CB00ACF5 +:101CA00001276021AF8C002435691000A4C900AC65 +:101CB0001620005101452021AF84004C0000202156 +:101CC0008FBF001C8FB200188FB100148FB00010AE +:101CD0000080102103E0000827BD00208F8400242D +:101CE000AF80004C008730210A001D80AF860024A1 +:101CF000241F000CA39F00540E00189702202021DF +:101D00002419FFFF1059FFEE2404FFFF8F880028DD +:101D1000A380002C8E0500048D0600C83C0700FF40 +:101D200034E3FFFF00A3282400C5102B1040FFB5AB +:101D3000AF8500400220202124090019A389005406 +:101D40000E0018972411FFFF1051FFDD2404FFFF40 +:101D50000A001D528F8500408F8400288F8700382D +:101D60008CF20030908600C430C5001014A0001022 +:101D70008F83004C2C68000515000028000000002F +:101D8000908A00C4246BFFFC314900101520000824 +:101D9000316400FF8F8D00508F8C002411AC000443 +:101DA000388F000131EE000115C0002F0000000047 +:101DB0000E001D02000000000A001DD900000000F6 +:101DC0008F890024938D002C30AE0003000E402339 +:101DD000310A0003014D4021A388002C94CB00ACB4 +:101DE00001276021AF8C002435691000A4C900AC24 +:101DF0001220FFB10145202125180004A398002CD2 +:101E000094CF00AC24920004AF92004C35F1200036 +:101E1000A4D100AC0A001D81000020218C8200DCCE +:101E20001242FF6C0220202124180005A3980054C0 +:101E30000E0018972412FFFF1452FF662404FFFFC0 +:101E40000A001D828FBF001C30E500FF0E00179EA8 +:101E5000000030218F8600288F87004C8F89002456 +:101E60000A001D728F8500400E0017C90000000097 +:101E70000A001DD9000000009383004627BDFFE043 +:101E800024020002AFB20018AFB10014AFBF001CB3 +:101E900000808821AFB00010000090211062005532 +:101EA0002404FFFD978300488F85004C3066FFFFB8 +:101EB00000C5202B1480005B938700343C08800011 +:101EC0009504012010E500528F8A00248F84005071 +:101ED00030A500FF0E00179E240600018F9F0058BA +:101EE0003C0580003C19408027ED017831B0007836 +:101EF000240EFF800219582534AF090031B80007BD +:101F000001AE6024ACAC0800030F8021ACAB08101C +:101F100002202021020028210E001D3CAF90003835 +:101F20002403FFFF104300332404FFFF8E0C001036 +:101F30003C0708008CE731B09206000031843FFF77 +:101F40000087102B1040002330CD003F8F980058A1 +:101F5000000471803C0408008C8431A82409FF80AF +:101F60009390004500984021010E202100897024A3 +:101F7000000E51403C0980003099007F3C0F0080EA +:101F80008F8800283525094035E2000101593825A0 +:101F9000308B0078308600073C0310003C1F800C1B +:101FA00000C5C0210162582500E35025033F782178 +:101FB00036050001AD2E0804AF98003CAD2B081487 +:101FC000AF8F0030AD2E0028AD040074AD2A08306C +:101FD000A38500459383004624100003507000271A +:101FE00025A3FFE0240C0001106C001C2406002334 +:101FF000024020218FBF001C8FB200188FB1001447 +:102000008FB000100080102103E0000827BD0020E1 +:10201000314900035520FFAE8F8400500A001E1581 +:102020008F9000508F840050306500FF0E00179E87 +:1020300024060001938B0034240500341165001838 +:10204000978300488F85004C3062FFFF00A2582321 +:10205000AF8B004C0A001E4DA780004811A6003728 +:1020600000000000022020212411000B0E00189710 +:10207000A39100540A001E4D004090212C720020B4 +:102080001240FFF80003F8803C07080124E7813C78 +:1020900003E7C8218F2D000001A000080000000008 +:1020A0008F85004C2CA200055440001DA7800048DD +:1020B000978A00483148FFFF00A848232D2F0005CC +:1020C00011E00003314400FF24AEFFFC31C400FFE7 +:1020D0008F9000508F980024121800043899000146 +:1020E000332D000115A00029000000008F91002869 +:1020F000922500C434A30010A22300C49783004893 +:102100008F85004C8F8400283062FFFF00A2582387 +:10211000AC8000DCA78000480A001E4DAF8B004C4D +:102120003062FFFF00A258230A001E4DAF8B004C07 +:102130002403FFFF11830005000000000E001B6F49 +:10214000022020210A001E4D004090210E001AF6A8 +:10215000022020210A001E4D004090210E001BD3BA +:10216000022020210A001E4D004090210E001A4D31 +:10217000022020210A001E4D004090210E001C75F7 +:10218000022020210A001E4D004090210E0017C998 +:1021900000000000978300488F85004C306CFFFFE3 +:1021A00000AC38232CFF000553E0FFA83062FFFF8E +:1021B0008F860028A7800048ACC200DC3062FFFF99 +:1021C00000A258230A001E4DAF8B004C27BDFFD044 +:1021D000AFB20018AFB00010AFBF0028AFB50024F9 +:1021E000AFB40020AFB3001CAFB100143C0C8000B2 +:1021F0008D880128240FFF803C07800A25100100EC +:10220000250B0080020F68243205007F016F7024C7 +:10221000AD8E009000A72821AD8D002490A700EC82 +:102220003169007F3C0A8004012A1821A3870046F7 +:102230009066007C00809021AF83002030C20002B5 +:10224000AF880058AF85002800A018211440000274 +:102250002404003424040030A38400348C6600CCB1 +:1022600030F100FF24040004AF86004C1224000467 +:10227000A38000548E5300041660001D3C088000AB +:102280009387004530F200011240000F8FBF0028F5 +:102290008CB800748CA400742419FF80031988245E +:1022A00000117140308F007F01CF60253C0D200070 +:1022B000018D582530F500FE3C0A8000AD4B0830FA +:1022C000A39500458FBF00288FB500248FB4002050 +:1022D0008FB3001C8FB200188FB100148FB00010A4 +:1022E0002402000127BD003003E00008ACA600CCAA +:1022F0008E590008951F01208E460010033FC02113 +:102300003307FFFF30F5000F32B40001AF86002421 +:102310001680003BA395004435060C0002A6102150 +:1023200000F51823AD030084AF8200508E490004ED +:102330003128FFFF1100002BA78900482410FF80DF +:102340003C1580003C1420000A001F3B2413FFFEB4 +:1023500090AE00C4020E682431AC00FF1580002A44 +:10236000024020219384004597860048308F000169 +:1023700011E0000B026428248F8900288D2300744B +:102380008D280074A3850045007010240002C94008 +:10239000311F007F033FC02503148825AEB10830EC +:1023A00010C000108F85002890A700C40207582491 +:1023B000316A00FF1540FFE6024020210E001DEFAC +:1023C000979100481040FFE8938400452405FFFDE5 +:1023D000544500058E430020022028210E0017746A +:1023E000024020218E430020307000041600000AB5 +:1023F0002414FFFB8F8500280A001EF18F86004CF5 +:102400000A001F1CAF8600500E001A1900000000C1 +:102410000A001F2B93840045007498240E00178E29 +:10242000AE5300208F8500280A001EF18F86004CD5 +:1024300027BDFFD8AFB3001CAFB10014AFBF002061 +:10244000AFB20018AFB000103C0280008C520140C7 +:102450008C4B01483C048000000B8C02322300FFAF +:10246000317300FF8C8501B804A0FFFE3490018019 +:10247000AE1200008C8701442464FFF024060002A1 +:102480002C830013AE070004A6110008A206000B5F +:10249000AE1300241060004F8FBF0020000448805E +:1024A0003C0A0801254A81BC012A40218D04000014 +:1024B00000800008000000003C1008008E1031A8C9 +:1024C00031733FFF001389800212C8212405FF8069 +:1024D00003312021264C0100264700803C1F80004C +:1024E00000E51824318F007F30E9007F308A007FBB +:1024F0003C18800A3C0E80043C0D800C00851024A2 +:1025000001853024014D8021AFE6002401F84021EF +:10251000AFE30090012E9821AFE20028AF90003089 +:10252000AF880028AF9300200E001863016080215F +:102530003C0380008C6B01B80560FFFE8F87003084 +:10254000346501808F86002890E3000DACB2000056 +:10255000A4B00006000316000002FE03001F90272F +:10256000001227C21080007A24C2007824196082E9 +:10257000A4B90008A0A00005241F0002A0BF000B02 +:1025800000041C008F8B00203C0227000062902575 +:10259000ACB20010ACA00014ACA00024ACA0002889 +:1025A000ACA0002C8D7300382410FF80ACB3001851 +:1025B00090E4000D02048824322500FF10A00005DD +:1025C0008FBF002090EC000D3188007FA0E8000D47 +:1025D0008FBF00208FB3001C8FB200188FB1001482 +:1025E0008FB000103C0D10003C0A800027BD002871 +:1025F00003E00008AD4D01B8265F01002405FF800F +:1026000033F8007F3C06800003E578243C19800AFB +:1026100003192021ACCF0024908E00C400AE6824A2 +:1026200031AC00FF1180FFEAAF840028248E0078CF +:1026300095CD00123C0C08008D8C31A831AB3FFFCA +:1026400001924821000B5180012A402101052024DC +:10265000ACC400283107007F3C06800C00E6202136 +:102660009083000D00A31024304500FF10A0FFD878 +:10267000AF8400309098000D330F001015E0FFD5A7 +:102680008FBF00200E001863000000003C03800094 +:102690008C7901B80720FFFE00000000AE12000098 +:1026A0008C720144AE120004A6110008241100022D +:1026B000A211000BAE1300240A001FC68FBF00201A +:1026C0003C1260008E452C083C03F0033462FFFF8F +:1026D00000A2F824AE5F2C088E582C083C1901B0DB +:1026E00003199825AE532C080A001FC68FBF00207F +:1026F000264D010031AF007F3C10800A240EFF8080 +:1027000001F0282101AE60243C0B8000AD6C002458 +:102710001660FFAFAF85002824110003A0B100ECC4 +:102720000A001FC68FBF002026480100310A007F23 +:102730003C0B800A2409FF80014B30210109202431 +:102740003C078000ACE400240A001FC5AF860028C7 +:10275000944A001232083FFF314C3FFF1588FF8436 +:102760002419608290CF00C4240EFF8001CF48243A +:10277000312D00FF11A0FF7E00000000240700049F +:10278000A0C700EC8F870030241860842406000D59 +:10279000A4B80008A0A600050A001FB0241F00026C +:1027A0000800330C0800330C080033E8080033BC81 +:1027B000080033A0080032F0080032F0080032F0C0 +:1027C00008003314800801008008008080080000A1 +:1027D0005F865437E4AC62CC50103A4536621985B6 +:1027E000BF14C0E81BC27A1E84F4B556094EA6FE7B +:1027F0007DDA01E7C04D748108007A7408007AC060 +:1028000008007A80080079A808007A8008007AB069 +:1028100008007A80080079A8080079A8080079A83B +:10282000080079A8080079A8080079A8080079A804 +:10283000080079A8080079A8080079A808007AA0FB +:1028400008007A90080079A8080079A8080079A8FB +:10285000080079A8080079A8080079A8080079A8D4 +:10286000080079A8080079A8080079A8080079A8C4 +:10287000080079A808007A900800806C08007F148E +:102880000800803408007F140800800408007DFCE4 +:1028900008007F1408007F1408007F1408007F14CC +:1028A00008007F1408007F1408007F1408007F14BC +:1028B00008007F1408007F1408007F1408007F14AC +:0428C00008007F3C51 +:0C28C4000A0001220000000000000000DB +:1028D0000000000D747061352E302E306A33000018 +:1028E00005000001000000000000000000000000E2 +:1028F00000000000000000000000000000000000D8 +:1029000000000000000000000000000000000000C7 +:1029100000000000000000000000000000000000B7 +:1029200000000000000000000000000000000000A7 +:102930000000000000000000000000000000000097 +:102940000000000000000000000000000000000087 +:1029500010000003000000000000000D0000000D4A +:102960003C02080024421C203C03080024631FA0F2 +:10297000AC4000000043202B1480FFFD24420004E3 +:102980003C1D080037BD2FFC03A0F0213C100800BF +:10299000261004883C1C0800279C1C200E0002E224 +:1029A000000000000000000D2402FF8027BDFFE0B2 +:1029B00000821024AFB00010AF420020AFBF00185B +:1029C000AFB10014936500043084007F03441821E4 +:1029D0003C0200080062182130A50020036080211D +:1029E0003C080111277B000814A000022466005C4B +:1029F00024660058920200049743010492040004E4 +:102A00003047000F3063FFFF308400400067282309 +:102A100010800009000048219202000530420004A5 +:102A2000104000050000000010A00003000000009E +:102A300024A5FFFC24090004920200053042000492 +:102A4000104000120000000010A000100000000064 +:102A50009602000200A72021010440252442FFFE27 +:102A6000A7421016920300042402FF8000431024A2 +:102A7000304200FF104000033C0204000A000172D3 +:102A8000010240258CC20000AF4210188F4201782D +:102A90000440FFFE2402000AA74201409602000201 +:102AA00024040009304200070002102330420007CE +:102AB000A7420142960200022442FFFEA7420144BF +:102AC000A740014697420104A74201488F420108EE +:102AD0003042002050400001240400019202000412 +:102AE000304200101440000234830010008018218E +:102AF000A743014A000000000000000000000000A1 +:102B000000000000AF4810000000000000000000BE +:102B100000000000000000008F4210000441FFFE92 +:102B20003102FFFF10400007000000009202000485 +:102B30003042004014400003000000008F42101893 +:102B4000ACC20000960200063042FFFF24420002A1 +:102B50000002104300021040036288219622000008 +:102B60001120000D3044FFFF00A710218F83003893 +:102B70008F45101C000210820002108000431021BB +:102B8000AC45000030A6FFFF0E0002D100052C026C +:102B900000402021A6220000920300042402FF80AE +:102BA00000431024304200FF1040001F00000000CE +:102BB00092020005304200021040001B000000009D +:102BC0009742100C2442FFFEA7421016000000009E +:102BD0003C02040034420030AF421000000000000C +:102BE0000000000000000000000000008F42100004 +:102BF0000441FFFE000000009742100C8F45101C9E +:102C00003042FFFF24420030000210820002108098 +:102C1000005B1021AC45000030A6FFFF0E0002D182 +:102C200000052C02A622000096040002248400085D +:102C30000E0001E73084FFFF974401040E0001F508 +:102C40003084FFFF8FBF00188FB100148FB00010C9 +:102C50003C02100027BD002003E00008AF420178CD +:102C60003084FFFF308200078F850024104000026F +:102C7000248300073064FFF800A4102130421FFFB6 +:102C800003421821247B4000AF850028AF82002436 +:102C900003E00008AF4200843084FFFF3082000F61 +:102CA0008F85002C8F860034104000022483000F93 +:102CB0003064FFF000A410210046182BAF850030CF +:102CC0000046202314600002AF82002CAF84002C49 +:102CD0008F82002C340480000342182100641821E4 +:102CE000AF83003803E00008AF4200808F820014F9 +:102CF000104000088F8200048F82FFCC1440000532 +:102D00008F8200043C02FFBF3442FFFF0082202478 +:102D10008F82000430430006240200021062000F7C +:102D20003C0201012C620003504000052402000413 +:102D30001060000F3C0200010A00022E000000009B +:102D400010620005240200061462000C3C0201110E +:102D50000A000227008210253C0200110082102583 +:102D6000AF421000240200010A00022EAF82000CC4 +:102D700000821025AF421000AF80000C0000000060 +:102D8000000000000000000003E000080000000058 +:102D90008F82000C10400004000000008F421000E1 +:102DA0000441FFFE0000000003E0000800000000F6 +:102DB0008F8200102443F800000229C224A2FFF0F1 +:102DC0002C63030110600003000210420A00025548 +:102DD000AC8200008F83001800A3102B1440000B5E +:102DE0000000382100A31023244600018F82001C1C +:102DF000006210212442FFFF0045102B54400004C4 +:102E00002402FFFF0A000255AC8600002402FFFFE7 +:102E10000A00025AAC8200008C8200003C030800C9 +:102E200024631C5C000211400043382103E00008C9 +:102E300000E010213C0908008D291D80000451404C +:102E40003C19080027391C5C00C0782100806021F3 +:102E5000240EFFFF000038210159402111200036C7 +:102E6000000030213C18080027181D983C0D080070 +:102E700025AD1D9C000F582B000611800046102127 +:102E8000000218C0007810218C420000158200203A +:102E9000006D20218CA20000544000098D02001812 +:102EA0003C0208008C421D8424420001AC820000D8 +:102EB0003C010800AC221D840A0002CF0000202142 +:102EC0008F47002000003021000211C01160004A2D +:102ED000AF4200208D08001C3C0900088CA30000B4 +:102EE0000066182100031880007A10210049102183 +:102EF0008C44000024C600010068182100CF102B6C +:102F00001440FFF6AC6400000A0002CD000000008F +:102F10008C840000008E102B5040000424C6000159 +:102F20000080702100C0382124C6000100C9102B88 +:102F30001440FFD20006118024020001ACA2000060 +:102F40003C0208008C421D7C3C0308008C631D8001 +:102F50000043102B1440002A2404FFFE01591021C5 +:102F60008C420018104000262404FFFF0007218037 +:102F70003C0508008CA51D84008720218D060018C3 +:102F8000000420C03C02080024421D980082102149 +:102F90003C03080024631D9CAC4C000024A50001E8 +:102FA000008318213C02080024421DA0AC650000EB +:102FB000000631C03C010800AC251D8400822021A0 +:102FC0008F470020AD04001CAF46002011E0000A2E +:102FD000000030213C020008034228218CA200009E +:102FE00024C6000100CF182BAC82000024A50004E9 +:102FF0001460FFFA24840004AF4700200000202161 +:1030000003E00008008010213084FFFF30C6FFFF7E +:1030100000052C0000A628253882FFFF004510215E +:103020000045282B0045102100021C023042FFFF02 +:103030000043102100021C023042FFFF0043102118 +:103040003842FFFF03E000083042FFFF27BDFFC802 +:10305000AFBF0030AFB3002CAFB20028AFB1002437 +:10306000AFB000203C0460088C8250002403FF7F36 +:103070003C066000004310243442380CAC825000FF +:103080008CC24C1C3C1A8000000216023042000F19 +:1030900010400007AF82001C8CC34C1C3C02001F78 +:1030A0003442FC0000621824000319C2AF830018E8 +:1030B0008F420008275B400034420001AF42000805 +:1030C000AF8000243C02601CAF400080AF40008411 +:1030D0008C4500088CC3080834028000034220217C +:1030E0002402FFF0006218243C0200803C0108002A +:1030F000AC2204203C025709AF840038146200045B +:10310000AF850034240200010A000314AF820014CA +:10311000AF8000142403003D240200043C01080099 +:10312000AC221D943C010800AC231D903C0108001A +:10313000AC231D8C3C010800AC231D883C13080007 +:1031400026731C5C240400043C02080024421C7406 +:10315000240300082463FFFFAC400004AC400000DF +:103160000461FFFC24420020000410C00044102130 +:103170002442003D3C010800AC221D9024020001C5 +:103180003C010800AC221D7C2402FFFF3C0108002A +:10319000AC221D983C010800AC201D848F42000029 +:1031A00038420001304200011440FFFC8F820014BD +:1031B0001040001600000000974201041040000576 +:1031C0008F830000146000072462FFFF0A00034B96 +:1031D0002C62000A2C620010504000048F83000013 +:1031E00024620001AF8200008F8300002C62000A7D +:1031F000144000032C6200070A000352AF80FFCC8A +:103200001040000224020001AF82FFCC8F4301086E +:103210008F44010030622000AF830004104000089A +:10322000AF8400103C0208008C42042C24420001B0 +:103230003C010800AC22042C0A0006D73C024000E6 +:103240003065020014A0000324020F001482030959 +:1032500024020D0097420104104003713C0240001B +:1032600030624000144000AD8F8200388C4400086A +:103270008F4201780440FFFE24020800AF4201782B +:1032800024020008A7420140A740014297420104DE +:103290008F8400043051FFFF30820001104000078E +:1032A000022080212623FFFE240200023070FFFF4F +:1032B000A74201460A00037FA7430148A7400146F1 +:1032C0003C0208008C42043C1440000D8F83001027 +:1032D000308200201440000224030009240300016E +:1032E000006020218F830010240209005062000139 +:1032F00034840004A744014A0A00039A0000000035 +:1033000024020F00146200053082002014400006E1 +:103310002403000D0A000399240300051440000251 +:103320002403000924030001A743014A3C020800CA +:103330008C4204203C0400480E00020A0044202570 +:103340000E000233000000008F82000C1040003E8F +:10335000000000008F4210003C03002000431024B6 +:10336000104000398F8200043042000210400036C5 +:1033700000000000974210141440003300000000C9 +:10338000974210088F8800383042FFFF2442000621 +:10339000000218820003388000E830213043000129 +:1033A0008CC4000010600004304200030000000DD7 +:1033B0000A0003DB00E81021544000103084FFFFB6 +:1033C0003C05FFFF00852024008518260003182BEC +:1033D0000004102B004310241040000500000000E2 +:1033E000000000000000000D000000002400021C8E +:1033F0008CC200000A0003DA004520253883FFFF55 +:103400000003182B0004102B00431024104000056B +:1034100000000000000000000000000D000000009F +:10342000240002258CC200003444FFFF00E8102174 +:10343000AC4400003C0208008C42043024420001ED +:103440003C010800AC2204308F6200008F840038F9 +:10345000AF8200088C8300003402FFFF1462000F6B +:10346000000010213C0508008CA504543C04080011 +:103470008C84045000B0282100B0302B0082202121 +:10348000008620213C010800AC2504543C010800C2 +:10349000AC2404500A0006CD240400088C820000ED +:1034A000304201001040000F000010213C050800D0 +:1034B0008CA5044C3C0408008C84044800B02821EE +:1034C00000B0302B00822021008620213C01080022 +:1034D000AC25044C3C010800AC2404480A0006CD8D +:1034E000240400083C0508008CA504443C040800A2 +:1034F0008C84044000B0282100B0302B00822021B1 +:10350000008620213C010800AC2504443C01080051 +:10351000AC2404400A0006CD240400088F62000891 +:103520008F62000000021602304300F024020030D7 +:1035300010620005240200401062016B8F8200209F +:103540000A0006D52442000114A000050000000076 +:10355000000000000000000D0000000024000250E8 +:103560008F4201780440FFFE000000000E00023B85 +:1035700027A4001014400005004080210000000036 +:103580000000000D00000000240002578E02000021 +:103590001040000500000000000000000000000DC9 +:1035A000000000002400025A8F62000C0443000354 +:1035B000240200010A00055DAE000000AE0200001A +:1035C0008F8200388C450008A20000078F65000C30 +:1035D0008F64000430A3FFFF000424020085202331 +:1035E000308200FF0043102124420005000288833E +:1035F0002E220081A605000A14400005A204000442 +:10360000000000000000000D000000002400027215 +:103610003C0708008CE71D808FA800102409FFFFDD +:103620000000502110E00013000030213C0C080085 +:10363000258C1D9C01802821000018218CA2FFFCF4 +:103640005102002F006C18218CA400002463020892 +:103650000089102B1040000324A502080080482197 +:1036600000C0502124C6000100C7102B5440FFF4B5 +:103670008CA2FFFC3C0508008CA51D803C020800C4 +:103680008C421D7C3C09080025291C603C03080075 +:1036900024631D9800A2102B3C0C0800258C1D9C57 +:1036A0003C0408008C841D843C0B0800256B1DA085 +:1036B0001040001A0008314000051180004510211B +:1036C000000210C000C9382124840001004B3021C1 +:1036D0000043182124A50001004C1021AC68000013 +:1036E000ACE600183C010800AC241D84AC4400008A +:1036F0003C010800AC251D800A0004A88E04001CB3 +:103700003C0208008C421D84244200013C01080058 +:10371000AC221D840A0004A7AC620000000A1180DC +:10372000004A1021000210C0004328218CA3000091 +:10373000004C3821248400010003194000C93021C5 +:1037400000691821004B1021ACA80000AC600018E3 +:103750003C010800AC241D84ACC20018ACE400009D +:103760008E04001C8F8500380E0006E702203021F1 +:103770008F6200048F430108A60200083C0210007B +:103780000062182410600008000000009742010445 +:10379000920300072442FFEC346300023045FFFF30 +:1037A0000A0004BCA2030007974201042442FFF070 +:1037B0003045FFFF960600082CC200135440000558 +:1037C000920300079202000734420001A2020007A0 +:1037D0009203000724020001106200052402000386 +:1037E0001062000B30C7FFFF0A0004DB24E2000276 +:1037F0008F8200383C04FFFF8C43000C00641824C7 +:1038000000651825AC43000C0A0004DA30C7FFFF3E +:103810008F8200383C04FFFF8C43001000641824A2 +:1038200000651825AC43001030C7FFFF24E20002FA +:1038300000021083A20200058F830038304200FF8F +:1038400000021080004330218CC500008CC20000B3 +:1038500024030004000217021443001300000000B8 +:10386000974201043C03FFFF00A318243042FFFFEE +:10387000004710232442FFFE00622825ACC500004B +:10388000920400058E03001C308200FF00021080AD +:1038900000431021904200003042000F00441021EC +:1038A0000A000510A20200068CC40004974201041D +:1038B0009603000A3085FFFF3042FFFF00471023C8 +:1038C0002442FFD60002140000A22825ACC5000443 +:1038D0009202000792040005246300280003188365 +:1038E0000064182134420004A2030006A20200076B +:1038F0008F8200042403FFFB3442000200431024A3 +:10390000AF820004920300068E07001C8F860038E9 +:1039100000031880006710218C44000C3C02FFF665 +:103920003442FFFF0082282400661821AE04000CF8 +:10393000AC65000C920300068E04000C3C02FF7F75 +:103940003442FFFF0003188000A2282400822024B4 +:1039500000671821AE04000CAC65000C9202000652 +:10396000000210800047102194450012AC45001061 +:10397000920200060002108000461021AC450010A3 +:103980008FA200109203000500021140000318806E +:1039900000671821005320218C6200048C830018DA +:1039A0001460000EAE0200143C0308008C631D8CF2 +:1039B000AC8300183C0208008C421D900062102B62 +:1039C00010400019000000003C0208008C421D94C9 +:1039D000006210213C010800AC221D8C8E020018F0 +:1039E0008F48002000003021000211C01220000B7F +:1039F000AF4200203C0200080342282100E02021C1 +:103A00008C82000024C6000100D1182BACA200005B +:103A1000248400041460FFFA24A50004AF480020A9 +:103A20000A00055E24020010000000000000000DE6 +:103A300000000000240002D424020010A74201402C +:103A400024020002A7400142A7400144A7420146C8 +:103A5000974201043C0400082442FFFEA7420148AB +:103A6000240200010E00020AA742014A9603000A3E +:103A70009202000400431021244200023042000759 +:103A800000021023304200070E000233AE02001085 +:103A90008F6200003C0308008C630444240400107F +:103AA000AF820008974201043042FFFF2442FFFE2C +:103AB00000403821000237C33C0208008C42044019 +:103AC000006718210067282B0046102100451021AF +:103AD0003C010800AC2304443C010800AC22044033 +:103AE0000A0006620000000014A0000500000000AB +:103AF000000000000000000D00000000240003048E +:103B00008F4201780440FFFE000000000E00023BDF +:103B100027A400141440000500408021000000008C +:103B20000000000D000000002400030B92060004BA +:103B30008FA4001427A50018000630820E00025C36 +:103B4000AFA00018504000068E02000000000000E8 +:103B50000000000D00000000240003118E02000090 +:103B60005440000692020007000000000000000D13 +:103B700000000000240003169202000730420004F7 +:103B8000104000058F8200042403FFFB3442000232 +:103B900000431024AF8200048F6200040443000934 +:103BA00092020007920200068E03001C8E04000C95 +:103BB0000002108000431021AC44000CAE00000055 +:103BC00092020007304200045440000B92030004AC +:103BD000920300058E0400148E05001C000318805B +:103BE0003C0200010082202100651821AE0400146F +:103BF000AC640004920300049602000A00621021E3 +:103C000024420005000290838FA200181040000D8E +:103C1000277100088FA40014000310820242302391 +:103C200027A500180E00025CAFA200185040000645 +:103C30008E05001C000000000000000D00000000C8 +:103C40002400033F8E05001C022020210E0006E701 +:103C500002403021920400068F6500043C027FFF81 +:103C600000042080009120218C8300043442FFFF57 +:103C700000A2282400651821AC83000492020007EA +:103C80009203000492050005304200041040001425 +:103C90009607000830A500FF0005288000B1282104 +:103CA0008CA40004974201049606000A306300FFCA +:103CB0003042FFFF004310210046102130E3FFFF98 +:103CC000004310232442FFD83084FFFF0002140079 +:103CD00000822025ACA400040A0006169203000707 +:103CE00030A500FF0005288000B128218CA4000029 +:103CF00097420104306300FF3042FFFF0043102170 +:103D0000004710233C03FFFF008320243042FFFFC5 +:103D100000822025ACA400009203000724020001C9 +:103D2000106200060000000024020003106200116F +:103D3000000000000A0006398E03001097420104BB +:103D4000920300049605000A8E24000C0043102103 +:103D5000004510212442FFF23C03FFFF0083202492 +:103D60003042FFFF00822025AE24000C0A000639F5 +:103D70008E03001097420104920300049605000A86 +:103D80008E24001000431021004510212442FFEE34 +:103D90003C03FFFF008320243042FFFF00822025E8 +:103DA000AE2400108E0300102402000AA742014036 +:103DB000A74301429603000A920200043C0400401B +:103DC00000431021A7420144A74001469742010445 +:103DD000A7420148240200010E00020AA742014A3C +:103DE0000E000233000000008F6200009203000406 +:103DF00000002021AF820008974201049606000AC5 +:103E00003042FFFF00621821006028213C030800B7 +:103E10008C6304443C0208008C4204400065182175 +:103E2000004410210065382B004710213C01080098 +:103E3000AC2304443C010800AC220440920400047A +:103E4000008620212484000A3084FFFF0E0001E751 +:103E500000000000974401043084FFFF0E0001F5CC +:103E6000000000003C021000AF4201780A0006D4B6 +:103E70008F820020148200273062000697420104DE +:103E8000104000673C0240003062400010400005D6 +:103E900000000000000000000000000D0000000015 +:103EA0002400041A8F4201780440FFFE2402080017 +:103EB000AF42017824020008A7420140A740014216 +:103EC0008F82000497430104304200011040000734 +:103ED0003070FFFF2603FFFE24020002A7420146C6 +:103EE000A74301480A00068C2402000DA7400146A2 +:103EF0002402000DA742014A8F620000240400083A +:103F0000AF8200080E0001E7000000000A0006660C +:103F100002002021104000423C0240009362000059 +:103F2000304300F0240200101062000524020070EB +:103F3000106200358F8200200A0006D5244200015D +:103F40008F620000974301043050FFFF3071FFFF84 +:103F50008F4201780440FFFE320200070002102366 +:103F6000304200072403000A2604FFFEA743014055 +:103F7000A7420142A7440144A7400146A751014876 +:103F80008F4201083042002014400002240300093F +:103F900024030001A743014A0E00020A3C0400402A +:103FA0000E000233000000003C0708008CE70444C8 +:103FB000021110212442FFFE3C0608008CC604407A +:103FC0000040182100E33821000010218F65000017 +:103FD00000E3402B00C230212604000800C8302135 +:103FE0003084FFFFAF8500083C010800AC27044483 +:103FF0003C010800AC2604400E0001E70000000070 +:104000000A000666022020210E000139000000008F +:104010008F82002024420001AF8200203C02400039 +:10402000AF4201380A000336000000003084FFFF71 +:1040300030A5FFFF000018211080000700000000DD +:104040003082000110400002000420420065182167 +:104050000A0006DD0005284003E00008006010218A +:1040600010C0000624C6FFFF8CA2000024A5000497 +:10407000AC8200000A0006E72484000403E0000884 +:104080000000000010A0000824A3FFFFAC86000081 +:1040900000000000000000002402FFFF2463FFFF77 +:1040A0001462FFFA2484000403E00008000000000A +:0440B000000000010B +:0C40B4000A00002A0000000000000000CC +:1040C0000000000D747870352E302E306A330000F9 +:1040D000050000000000000A000001360000EA6050 +:1040E00000000000000000000000000000000000D0 +:1040F00000000000000000000000000000000000C0 +:1041000000000000000000000000000000000000AF +:104110000000000000000016000000000000000089 +:10412000000000000000000000000000000000008F +:10413000000000000000000000000000000000007F +:1041400000000000000000000000000000001388D4 +:1041500000000000000005DC00000000000000007E +:1041600010000003000000000000000D0000000D22 +:104170003C020800244238603C03080024633B14DE +:10418000AC4000000043202B1480FFFD24420004BB +:104190003C1D080037BD7FFC03A0F0213C10080047 +:1041A000261000A83C1C0800279C38600E0004075D +:1041B000000000000000000D8F86003C3C039000D2 +:1041C0003C0280000086282500A32025AC44002066 +:1041D0003C0380008C67002004E0FFFE000000002C +:1041E00003E00008000000000A0000412404000170 +:1041F0008F85003C3C0480003483000100A310251F +:1042000003E00008AC82002003E000080000102159 +:104210003084FFFF30A5FFFF108000070000182149 +:104220003082000110400002000420420065182185 +:104230001480FFFB0005284003E000080060102107 +:1042400010C00007000000008CA2000024C6FFFF81 +:1042500024A50004AC82000014C0FFFB24840004E9 +:1042600003E000080000000010A0000824A3FFFFE6 +:10427000AC86000000000000000000002402FFFFE8 +:104280002463FFFF1462FFFA2484000403E00008A3 +:104290000000000090AA00318FAB00108CAC0040F1 +:1042A0003C0300FF8D680004AD6C00208CAD004421 +:1042B00000E060213462FFFFAD6D00248CA7004850 +:1042C0003C09FF000109C024AD6700288CAE004CFA +:1042D0000182C82403197825AD6F0004AD6E002C4F +:1042E0008CAD0038314A00FFAD6D001C94A900323E +:1042F0003128FFFFAD68001090A70030A5600002D4 +:10430000A1600004A167000090A30032306200FFAA +:104310000002198210600005240500011065000EDE +:104320000000000003E00008A16A00018CD800280A +:10433000354A0080AD7800188CCF0014AD6F0014A2 +:104340008CCE0030AD6E00088CC4002CA16A000138 +:1043500003E00008AD64000C8CCD001CAD6D0018AE +:104360008CC90014AD6900148CC80024AD68000825 +:104370008CC70020AD67000C8CC200148C830070C9 +:104380000043C82B13200007000000008CC200145B +:10439000144CFFE400000000354A008003E00008F0 +:1043A000A16A00018C8200700A0000B700000000C2 +:1043B0009089003027BDFFF88FA8001CA3A900003A +:1043C0008FA300003C0DFF8035A2FFFF8CAC002CBA +:1043D00000625824AFAB0000A100000400C05821C7 +:1043E000A7A000028D06000400A048210167C82193 +:1043F0008FA50000008050213C18FF7F032C202651 +:104400003C0E00FF2C8C0001370FFFFF35CDFFFF66 +:104410003C02FF0000AFC82400EDC02400C2782495 +:10442000000C1DC00323682501F87025AD0D0000A8 +:10443000AD0E00048D240024AFAD0000AD040008D3 +:104440008D2C00202404FFFFAD0C000C954700329A +:1044500030E6FFFFAD0600109145004830A200FF96 +:10446000000219C2506000018D240034AD04001414 +:104470008D4700388FAA001827BD0008AD0B002813 +:10448000AD0A0024AD07001CAD00002CAD000018E3 +:1044900003E00008AD00002027BDFFE0AFB2001828 +:1044A000AFB10014AFB00010AFBF001C9098003047 +:1044B00000C088213C0D00FF330F007FA0CF00001B +:1044C000908E003135ACFFFF3C0AFF00A0CE00010A +:1044D00094A6001EA22000048CAB00148E290004B8 +:1044E00000A08021016C2824012A40240080902112 +:1044F00001052025A6260002AE2400042605002082 +:10450000262400080E0000632406000292470030B3 +:10451000260500282624001400071E0000031603A9 +:1045200024060004044000032403FFFF96590032D0 +:104530003323FFFF0E000063AE2300102624002467 +:104540008FBF001C8FB200188FB100148FB0001005 +:1045500024050003000030210A00006D27BD002063 +:1045600027BDFFD8AFB1001CAFB00018AFBF00200F +:1045700090A900302402000100E050213123003FC7 +:1045800000A040218FB000400080882100C0482159 +:10459000106200148FA70038240B000500A0202112 +:1045A00000C02821106B0013020030210E0000F91A +:1045B000000000009225007C30A40002108000035F +:1045C00026030030AE000030260300348FBF0020E9 +:1045D0008FB1001C8FB000180060102103E00008AC +:1045E00027BD00280E000078AFB000100A0001407F +:1045F000000000008FA3003C0100202101202821A1 +:1046000001403021AFA300100E0000BFAFB0001476 +:104610000A000140000000003C0580008CA30E1041 +:104620008F840044AC8300208CA20E1803E00008A5 +:10463000AC8200243C0580008CA30E148F840044BF +:10464000AC8300208CA20E1C03E00008AC82002486 +:104650009382000C1040001B2483000F2404FFF001 +:104660000064382410E00019978B00109784000E26 +:104670009389000D3C0A601C0A00017B0164402301 +:1046800001037021006428231126000231C2FFFFBC +:1046900030A2FFFF0047302B50C0000E00E448213D +:1046A0008D4D000C31A3FFFF00036400000C2C03B0 +:1046B00004A1FFF30000302130637FFF0A00017383 +:1046C0002406000103E00008000000009784000EAB +:1046D00000E448213123FFFF3168FFFF0068382BD9 +:1046E00054E0FFF8A783000E938A000D11400005E7 +:1046F000240F0001006BC023A380000D03E000081D +:10470000A798000E006BC023A38F000D03E00008E4 +:10471000A798000E03E000080000000027BDFFE896 +:10472000AFB000103084FFFF3C10800093A8002B36 +:10473000AFBF0014A6040144960A0E1630C600FF4F +:104740008FA90030A60A0146AE050148A206015213 +:10475000A608015AAE0701608FA3002CA6090158D4 +:10476000012020210E000167AE0301543C0210001D +:10477000AE0201788FBF00148FB0001003E0000874 +:1047800027BD00188F8500002484000727BDFFF88F +:104790003084FFF83C06800094CB008A316AFFFF2A +:1047A000AFAA00008FA90000012540232507FFFFC5 +:1047B00030E31FFF0064102B1440FFF700056882F0 +:1047C000000D288034CC400000AC102103E000082C +:1047D00027BD00088F8200002486000730C5FFF83F +:1047E00000A2182130641FFF03E00008AF8400001E +:1047F0008F8500448F8A003C27BDFFB03C048000B9 +:10480000AFB70044AFB40038AFB1002CAFBF004821 +:10481000AFB60040AFB5003CAFB30034AFB200302C +:10482000AFB000288C8701048CA90024AC8A0080DA +:104830008CA8002000E988230000B821AC880E1065 +:104840008CA600240000A021AC860E188C820E10CD +:10485000AC820E148C830E18AC830E1C122000FB4D +:104860003C168000936B0008116000F1000000000E +:10487000976E001031CDFFFF022D602B158000ECEC +:104880000000000097700010320FFFFFAECF0E0047 +:104890003C0580008CB30000327200081240FFFD1E +:1048A0000000000094B50E088CA70E0432A5FFFF8F +:1048B00030B40001128000E1000000000000000D93 +:1048C00030B9A040241800401338011730B4A000BC +:1048D000128000DC000000009373000812600008E2 +:1048E00000000000976900103122FFFF00E2202B3A +:1048F0001080000330A6004010C000D2000000006D +:10490000A7850040AF870038936A0008022038214D +:10491000AFB10020154000F127B40020AF60000CBB +:104920009785004030B14000162000022403001695 +:104930002403000E24154007A363000AAF7500147A +:10494000939000428F6F0014321900010019C24089 +:1049500001F84025AF680014978700408F6300146A +:1049600030EE0010006E6825AF6D0014978C00408B +:10497000318B000811600165000000008F65001494 +:104980003C0B10003C0A800000AB8825AF7100147E +:1049900095460E0A3C0981002413000E30C2FFFF29 +:1049A00000492025AF640004A3730002937F000A2E +:1049B0003406FFFC27F20004A372000A978D004022 +:1049C00031AC200011800157000000003C0780003E +:1049D000978D004094EC0E0C97910040000D5842CA +:1049E0003185C000316A000300051303322910002D +:1049F00001429825000922030264F825001F90C097 +:104A0000A7720012979500409379000A00158182E1 +:104A10003218003C0319782125E8003CA3680009FE +:104A200094EE0E0C31C33FFFA76300109763001292 +:104A30009367000900E3702125CD000231AC000727 +:104A4000000C582331650007A365000B9371000922 +:104A500097640012976A0010322200FF8F9100388D +:104A6000979F004000444821012A98210266902126 +:104A700033F5004012A000053246FFFF00D1402B65 +:104A80003C12800011000016000098210226782BAD +:104A900015E001368FA700203C1880008F100E14FF +:104AA0003C058000AF100E108F190E1CAF190E18A8 +:104AB000AF060E008CB200003255000812A0FFFDB8 +:104AC0000000000094BF0E0800C088210000902163 +:104AD000A79F00408CA60E0424130001AF86003867 +:104AE000976900103135FFFF8E8C00000191202363 +:104AF00010800118AE8400009367000814E000D80D +:104B0000000000000E0001B4240400108F8E004845 +:104B10003C0332000040282131C600FF00063C0063 +:104B200000E3602525CD0001AF8D0048AC4C0000AE +:104B30009362000997640012937F000A304A00FFD5 +:104B4000308BFFFF014B48210009CC0033F000FF00 +:104B50000330C025ACB800048F8F00489788004010 +:104B60003103200010600103ACAF0008976F001202 +:104B700031E8FFFF06400101ACA8000C979000400F +:104B80003205000814A0000226280006262800028C +:104B90003C048000948B0E148C850E1C8F670004DF +:104BA000936A00023164FFFF314900FFAFA9001092 +:104BB0008F7F0014AFA80018AFBF00140E00019A39 +:104BC00000000000240400100E0001C800000000D6 +:104BD0008E92000016400005000000008F7900143E +:104BE0002405FFBF0325A024AF7400148F69000CB7 +:104BF0000135F821AF7F000C9375000816A000085E +:104C00000000000012600006000000008F6B00141E +:104C10003C0CEFFF3584FFFE01645024AF6A0014A2 +:104C2000A37300088FA700200A000316022020218A +:104C3000AED10E000A0001F83C05800014E0FF210F +:104C400030B9A0400E0001600000A0212E910001AB +:104C50000237B02512C000178FBF00488F85003C77 +:104C600024170F0010B700CD3C0480008C99017808 +:104C70000720FFFE24150F0050B500EB3C04800018 +:104C80008C890E14240502403C141000AC890144A8 +:104C90008C9F0E1CAC9F0148A0800152A480015A39 +:104CA000AC800160A4800158AC850154AC940178BB +:104CB0008FBF00488FB700448FB600408FB5003CCF +:104CC0008FB400388FB300348FB200308FB1002C16 +:104CD0008FB0002803E0000827BD00508F910038F6 +:104CE000979300403C1280000220A821326A0040C5 +:104CF0001540FF7D00009821976B00108F850038CC +:104D00003162FFFF104500A2000020210080A02199 +:104D1000108000E500E088211620FED2000000008F +:104D20000A0002E72E9100013C0380008C7F01788D +:104D300007E0FFFE240408008F860000AC640178C1 +:104D40003C038000946C008A318BFFFF0166502386 +:104D50002549FFFF31281FFF2D0200081440FFF9ED +:104D6000000000008F8E0048346F40008F83003CAD +:104D700000E0A021240D0F0025C70001AF870048E7 +:104D800000CF3021023488233C08800031D500FF59 +:104D9000106D000524070001939300423272000158 +:104DA0000012824036070001001514003C09010082 +:104DB00000492025ACC400008F9F004830B9003660 +:104DC00030B80008ACDF00041300009000F998250B +:104DD00095070E0A8F8E00003C03810030EDFFFF27 +:104DE00025CB000801A328253C0C1000316A1FFFC9 +:104DF000269200062406000EAD050160026C98257F +:104E0000A506015AAF8A0000A51201581620000815 +:104E10003C1080008F99003C24180F00533800028A +:104E200024170001367300400E0001593C10800029 +:104E30008E1F0E1402402021AE1F01448E120E1C44 +:104E4000AE120148A2150152AE1301540E000167C3 +:104E50003C151000AE1501780A000319000000008F +:104E600093780009976300129368000B330F00FFDB +:104E700001E33821310200FF00E2702125D0000A51 +:104E80003210FFFF0E0001B4020020218F8600487F +:104E90003C1941003C07800024CD0001AF8D004843 +:104EA000936C00099764001230C600FF318A00FF3E +:104EB000308BFFFF014B482100062C00253F0002EC +:104EC00000BFC02503197825AC4F00008F68000C87 +:104ED00094EE0E1401121825AC4300048CE50E1C50 +:104EE0008F670004936D000231C4FFFF31AC00FFF7 +:104EF000AFAC00108F620014AFB100180E00019A21 +:104F0000AFA200140A0002C502002021AF60000415 +:104F1000A3600002978D004031AC20001580FEABED +:104F200000003021A7600012979000409378000A9B +:104F30003C03800032191F000019798301F84021D9 +:104F400025070028A3670009946E0E0C0A00025E74 +:104F5000A76E00108F6E001435CD00400E00015971 +:104F6000AF6D00140A000291000000000A00031651 +:104F7000000020210641FF01ACA0000C8CB8000C01 +:104F80003C198000031990250A0002B2ACB2000C53 +:104F9000000090210A00028D2413000112800005F8 +:104FA0003C0D800095A60E0830D3004012600042F0 +:104FB000000000008C9001780600FFFE0000000059 +:104FC00094920E103C030500240720003258FFFF86 +:104FD00003037825AC8F014C8C880E143C0E100016 +:104FE000AC8801448C820E1CAC820148A080015226 +:104FF000A480015AAC800160A4800158AC870154A0 +:10500000AC8E01780A0002EE3C0480008F90000014 +:1050100026920002A5120158260F000831E81FFF52 +:105020000A000356AF880000AC80014C12800019C2 +:10503000000000008C8A0E10AC8A01448C830E188C +:105040003C0C800024160040AC8301488FBF004810 +:10505000A18001528FB70044A580015A8FB5003C52 +:10506000AD8001608FB40038A58001588FB3003443 +:10507000AD9601548FB200308FB600408FB1002C36 +:105080008FB000283C04100027BD005003E000084A +:10509000AD8401788C8B0E14AC8B01448C830E1C78 +:1050A0000A0003E43C0C80000E0001602E91000118 +:1050B0000A0002E80237B025000000000000000DE1 +:1050C000000000002400033A0A0003C03C048000F2 +:1050D00027BDFFE0AFBF001C3C1F20FF3C07600066 +:1050E0003C0980002402001037F9FFFDACE23008D3 +:1050F000AFB20018AFB10014AFB00010AD390E0060 +:10510000000000000000000000000000000000009F +:10511000000000003C1800FF3712FFFDAD320E000A +:105120003C0B60048D7050002411FF7F3C0E000288 +:105130000211782435EC380C35CD0109ACED4C1852 +:10514000240A0009AD6C50008CE80438AD2A000830 +:10515000AD2000148CE54C1C3106FFFF38C42F71C4 +:1051600000051E023062000F2486C0B31040000705 +:10517000AF8200088CE54C1C3C09001F3528FC0060 +:1051800000A81824000321C2AF8400048CF1080891 +:105190003C0F57092412F0000232702435F0001041 +:1051A00001D0602601CF68262DAA00012D8B0001B9 +:1051B000014B382550E00009A380000C3C02601C24 +:1051C0008C590008241F0001A39F000C33387C0079 +:1051D000A7980010A780000EA380000DAF800048A4 +:1051E00014C00003AF8000003C066000ACC0442C3B +:1051F0000E0004B63C1080000E000DDF0000000021 +:105200003C110800263138C83C12080026523948A3 +:105210008E05000038A30001306400011480FFFCFB +:10522000000000008E0601003C0C800A240AFF806A +:1052300024C7024030EB007F016C482100EA402483 +:10524000AE060020AF890044AE0800243C03800075 +:10525000AF86003C8C6D017805A0FFFE2419080084 +:10526000AC79017890780108A3980042938F0042AE +:1052700031EE000111C0000F240D0D0024C2F80012 +:105280002C5F030113E0001C000629C224A3FFF0D9 +:1052900000032042000431400E0001CF00D1D8218C +:1052A0003C0440003C068000ACC401380A000457AE +:1052B0000000000010CD0026240E0F0010CE002AA2 +:1052C0003C028008345F008093F90000240F0050F6 +:1052D000333800FF170FFFF33C0440000E000912A3 +:1052E000000000003C0440003C068000ACC40138D3 +:1052F0000A000457000000008F83000400A3402B25 +:105300001500000B8F8B0008006B50212547FFFF15 +:1053100000E5482B1520000600A36023000C29405F +:105320000E0001CF00B2D8210A00047C3C044000EA +:10533000000000000000000D00000000240003AD8C +:105340000E0001CF000000000A00047C3C04400075 +:105350003C1B0800277B3A480E0001CF00000000EC +:105360000A00047C3C0440003C1B0800277B3A6890 +:105370000E0001CF000000000A00047C3C04400045 +:10538000000411C003E00008244202403C0408006D +:1053900024843AAC2405001A0A00006D0000302174 +:1053A00027BDFFE0AFBF001CAFB20018AFB10014C3 +:1053B000AFB000103C108000920B01092412FF8056 +:1053C0000E0004B33164007F8F91003C00515021E6 +:1053D00001524024AE080024920301090E0004B3D8 +:1053E0003064007F24060080240700C024040040AD +:1053F000AE000810AE040814AE060818AE07081C6C +:10540000920C01090051F82133F8007F3C19800A01 +:10541000031910213184007F0E0004B3AF820044D1 +:105420008E1101003C0C008035850001022278219C +:1054300001F24824AE0908048E0E010035980002DE +:105440003609090001C2682131AB00780165502599 +:10545000AE0A08208E0501008E080100360509807D +:10546000010218212464004000923024AE0608088E +:105470008E07010000E2F82127F90040333200785E +:1054800002588825AE1108248E040100952F000CC7 +:105490008FBF001C8FB2001831EEFFFF000E69C0F5 +:1054A000AE0D0800AE0C0828952B000C8FB100142F +:1054B000316AFFFF000A41C0AE08002C8CA30050E7 +:1054C0008FB000108CA2003C8D2400048CA6001C20 +:1054D0008CA7003827BD0020AF830060AF8200504A +:1054E000AF84004CAF86005803E00008AF87005C33 +:1054F0003C0A0800914A3AD13C09080095293ACA69 +:105500003C051100000A3C002528000200E8302577 +:1055100000C5182524820008AC83000003E00008C1 +:10552000AC8000043C098000352809009107001177 +:10553000240200280080502130E300FF00A06821F1 +:1055400000C0602110620002340B86DD240B0800CD +:105550003C07800034E20A9A9443000034F80A9C25 +:1055600034E60AA03079FFFFAD5900008F0F00002C +:1055700034E80A8024040001AD4F00048CCE000002 +:10558000AD4E00089105001930A3000310640046D9 +:1055900028690002152000B5240400021064009060 +:1055A000240500031065009B34E40AA43C090800AC +:1055B00095293AC024070800516700503C18800024 +:1055C0003C0280003459090093280012932E0019E0 +:1055D00034580980310F00FF8F06002801EC182194 +:1055E000000338803124FFFF31CB00FF00E410219D +:1055F000000B2D0000A6C02500027C003C086000C6 +:105600000308182535E906FFAD430000AD49000445 +:105610008F2E002C3C0380003478093CAD4E0008EE +:105620008F27003025490028346E0900AD47000C53 +:105630008F2B0034AD4B00108F240038AD44001484 +:105640008F25001CAD4500188F220020AD42001CA4 +:105650008F26002425220014AD4600208F28002824 +:10566000AD4800248F0F0000AD2D0004AD2F0000C9 +:105670008C64010CAD24000891C700123C050800A1 +:1056800090A53AD0AD20001030EB00FF016C302126 +:1056900000066F000005CC0001B96025358AFFFFC8 +:1056A00003E00008AD2A000C3C09080095293AC027 +:1056B0003C19080097393ACA34E20AA43C060800AB +:1056C00094C63ABC944F00003123FFFF0323C0214E +:1056D00003067023000F3C0025C8FFF200E82825D0 +:1056E00024070800AD45000CAD400010AD4B001480 +:1056F0001567FFB3254A00183C18800037080900D9 +:10570000910F00119107001937030A8031EE00FF55 +:105710003C19080097393AC6946F002A000E588247 +:1057200030E400FF97870054000B160000042C00A3 +:105730003126FFFF0326C02100454825013870258A +:1057400001E758213C03400001C32025000B2C0039 +:10575000AD440000AD450004910200183C0600066F +:105760003C0380000002CE000326C025AD5800088F +:105770008D0F002C3478093C24E90001AD4F000C5A +:105780008D0B001C312E7FFF25490014AD4B0010FE +:105790008F0F0000AD2D0004A78E0054AD2F000028 +:1057A0008C64010C346E090025220014AD2400081D +:1057B00091C700123C05080090A53AD0AD2000101A +:1057C00030EB00FF016C302100066F000005CC00BB +:1057D00001B96025358AFFFF03E00008AD2A000CFF +:1057E00034E90AA495240000950200283C09080029 +:1057F00095293AC000041C000002CC0034788100D6 +:10580000032B7825AD58000CAD4F00100A00054061 +:10581000254A00143C09080095293AC03C050800B7 +:1058200094A53ACA3C06080094C63ABC9499000074 +:105830003123FFFF9518002800A31021004678238C +:1058400000193C000018440025EEFFEE010E28254B +:1058500034E48100AD44000CAD450010AD400014AF +:10586000AD4B00180A000540254A001C1460FF4F8C +:1058700034E60AA494CE00003C09080095293AC0F9 +:10588000000E4400010B3825AD47000C0A0005400E +:10589000254A001003E00008240207D027BDFFE0DE +:1058A000AFB20018AFB10014AFB00010AFBF001C12 +:1058B0000E00004D008088218F8800508F87004C9B +:1058C0003C05800834B20080011128213C10800082 +:1058D00024020080240300C000A72023AE02081881 +:1058E0003C068008AE03081C18800004AF850050F9 +:1058F000ACC500048CC90004AF89004C122000091B +:10590000360409800E0005F800000000924C0027C4 +:105910008E0B007401825004014B3021AE46000C06 +:10592000360409808C8E001C8F8F005801CF6823AD +:1059300019A000048FBF001C8C90001CAF90005871 +:105940008FBF001C8FB200188FB100148FB00010F1 +:105950000A00004F27BD00208F8600608F83005013 +:105960008F82004C3C05800834A40080AC86005037 +:10597000AC83003C03E00008ACA200043C03080038 +:105980008C63005427BDFFF8308400FF24620001BF +:1059900030A500FF3C010800AC22005430C600FFD7 +:1059A0003C0780008CE801780500FFFE3C0A7FFF81 +:1059B000A3A400038FA400003549FFFF0089182429 +:1059C000000647C000681025AFA2000090F9010A48 +:1059D000A3A000023C1880FFA3B900018FAE000015 +:1059E00030AD007F370FFFFF01CF5824000D660058 +:1059F0003C090020016C5025352620002405FF803D +:105A00003C04100027BD0008ACEA014CACE6015490 +:105A1000A4E00158A0E5015203E00008ACE40178DD +:105A2000308800FF3C03800030A400FF8C620178C6 +:105A30000440FFFE000000003C03800034660A00C2 +:105A40008CCA0020346709800004482BAC6A0144EA +:105A50008CC5002400091540AC650148A0680150C0 +:105A600090E4004CA064016D03E00008A4600158BC +:105A700027BDFFE8308400FFAFBF00100E00065BBB +:105A800030A500FF8F8300508FBF00103C058000C1 +:105A9000344600402404FF903C02100027BD00184B +:105AA000ACA3014CA0A40152ACA6015403E0000831 +:105AB000ACA2017827BDFFE03C088008AFBF001C06 +:105AC000AFB20018AFB10014AFB0001035100080B5 +:105AD0008E0600183C078000309200FF00C720258A +:105AE000AE0400180E00004D30B100FF9203000517 +:105AF000346200080E00004FA2020005024020217F +:105B00000E00066F02202821024020218FBF001CBA +:105B10008FB200188FB100148FB00010240500055B +:105B2000240600010A00063227BD00203C05800043 +:105B300034A309809066000830C200081040000FAE +:105B40003C0A01013549080AAC8900008CA80074A0 +:105B5000AC8800043C07080090E73AD030E500101C +:105B600050A00008AC8000083C0D800835AC0080D7 +:105B70008D8B0058AC8B00082484000C03E00008D7 +:105B8000008010210A0006B22484000C27BDFFE823 +:105B90003C088000AFB00010AFBF0014350609808C +:105BA00090C70009240200063509090030E300FF10 +:105BB0000080802100A06021240B00041062007985 +:105BC0002407000294CF005C3C0E020431EDFFFF7D +:105BD00001AE5025AE0A000090C5000830A4002098 +:105BE000108000080000000090C2004E3C1F01031E +:105BF00037F90300305800FF03193025240B000843 +:105C0000AE06000491390011912600129124001172 +:105C1000333800FF0018708230CF00FF01CF5021D1 +:105C2000014C6821308800FF31AAFFFF39030028AA +:105C3000000A28801460002B0205402391240012E2 +:105C40003C0E800035D90980308500FF00AC18215A +:105C500000031080004BF821001F8400360906FF66 +:105C6000AD09000435C9090091260011912F0012D9 +:105C7000000BC0828F2B003431ED00FF8DC4010C6E +:105C800001AC282100B810210164F823000784002A +:105C900000021F000070C82533E9FFFF30CF00FC71 +:105CA000032970250158202101E868210004508053 +:105CB000ADAE000C0E00004D010A80213C078008AB +:105CC000240C000434EB00800E00004FA16C00098E +:105CD000020010218FBF00148FB0001003E00008F5 +:105CE00027BD001891250011912300193C180800C8 +:105CF00097183AC630A200FF0002F882307000FF09 +:105D0000001FCE0000104C000329302500D870255C +:105D10003C0F400001CF68253C0E8000AD0D000017 +:105D200035C9090091260011912F001235D909803B +:105D3000000BC08231ED00FF8F2B00348DC4010CAD +:105D400001AC282100B810210164F8230007840069 +:105D500000021F000070C82533E9FFFF30CF00FCB0 +:105D6000032970250158202101E868210004508092 +:105D7000ADAE000C0E00004D010A80213C078008EA +:105D8000240C000434EB00800E00004FA16C0009CD +:105D9000020010218FBF00148FB0001003E0000834 +:105DA00027BD00180A0006C42407001227BDFFD033 +:105DB000AFB50024AFB40020AFB3001CAFB00010EB +:105DC000AFBF0028AFB20018AFB100143C0680008E +:105DD00090C3010B309300FF30B400FF30620030FD +:105DE0000000A821104000820000802134C40980F6 +:105DF0009088000800083E0000072E0304A000A9B8 +:105E0000240400048F8700503C010800A0243AD0ED +:105E10003C0C8000AD8000483C038000906E010B7C +:105E200031C5002010A000073C0C800034780980A8 +:105E30009312000800128E0000117E0305E000AEF0 +:105E40003C028008918B010B3586098090C40008C4 +:105E5000316A0040000A482B3088000824110003F2 +:105E60001500000200E99023000088213C03800017 +:105E700034780A80346A09009707002C9144001195 +:105E80009149001293050018309F00FF312800FF50 +:105E9000022810210002C880930D0018033F7821CA +:105EA00001F0702130B000FF01D01821A787005405 +:105EB0003C010800A42E3AC63C010800A4233AC8BD +:105EC00015A00003246B000A0000000D246B000ADB +:105ED0003170FFFF3C010800A4233ACA3C010800CE +:105EE000A4203AC03C010800A4203ABC0E0001B432 +:105EF000020020210E00050F00402021004020213B +:105F0000024028210E00051C022030210E00069EB2 +:105F10000040202116A0005F004020210E0001C893 +:105F2000020020213C11080092313AD032350003A2 +:105F300012A000163C0A80088F8700503C0E800893 +:105F400035CD008024EC0001ADAC003C3C05800860 +:105F50008CA600040180202100CC90231A4000026E +:105F6000AF8C00508CA400040E0005F8ACA4000413 +:105F70003C1980008F3800743C0F800835F0008099 +:105F800000582821AE05000C3C0A800835420080EC +:105F90000260202102802821A040006B0E00065BD9 +:105FA0003C1380008F840050345F0006AE64014CC7 +:105FB0008F8800483C1410008FB50024250900018B +:105FC000AF8900488FB20018A26801528FB1001447 +:105FD000AE7F01548FB00010AE7401788FBF0028DF +:105FE0008FB400208FB3001C03E0000827BD0030F1 +:105FF00034C30980906F0008000F7600000E6E0316 +:1060000005A0003334C209009059001B241F001062 +:106010003C010800A03F3AD0333800021300FF7E55 +:106020008F8700508F83005C1467FF7C3C038000E7 +:106030000E00004D000000003C098008352500805E +:1060400090A4000924070016308800FF1107000DF6 +:106050000000000090A600093C0C0800918C3AD08A +:10606000240A000830C400FF358B00013C01080001 +:10607000A02B3AD0108A002F240D000A108D002882 +:106080002402000C0E00004F000000000A00075917 +:106090008F8700500E0006B6022028210A00079ABA +:1060A000000000003C0B8008356A00808D470054DA +:1060B0008CC9010C1120FF54AF8700502406001436 +:1060C0003C010800A0263AD00A0007583C0C80008A +:1060D00090710008241200023C010800A0323AD05E +:1060E000323000201200000B241500018F87005071 +:1060F0000A00075924100008345900808F23003803 +:10610000AC4300048C5F0004AF3F003C0A0007640E +:106110003C0C80008F8700500A00075924100004AF +:10612000A0A200090E00004F000000000A0007595D +:106130008F870050240200140A00081CA0A2000946 +:1061400027BDFFE8AFBF0014AFB000103C108000C7 +:1061500092020109240500010E00065B304400FF95 +:106160003C1F800893F8000E37E3008093F9000F7E +:10617000906E002693E9000A332F00FF0018660096 +:10618000000F6C0031CB00FF018D5025000B320059 +:1061900001463825312800FF3445600000E82025FD +:1061A0002402FF813C031000AE04014C8FBF001499 +:1061B000AE050154A2020152AE0301788FB0001067 +:1061C00003E0000827BD001827BDFFE8308400FF6A +:1061D000AFBF00100E00065B30A500FF3446004044 +:1061E0003C0480002405FF92AC860154A085015236 +:1061F0008F8300508FBF00103C02100027BD001895 +:10620000AC83014C03E00008AC82017827BDFFD8C5 +:10621000AFB20018AFB10014AFB00010AFBF002094 +:10622000AFB3001C3C07800090E20109308600FFFC +:1062300030B000FF000618C23204000230710001C5 +:1062400014800007305200FF3C098008353300807D +:10625000926800053105000810A0000C30CA00103B +:10626000024020210E000680022028212402000185 +:106270008FBF00208FB3001C8FB200188FB10014A5 +:106280008FB0001003E0000827BD00281540003043 +:1062900034E50A008CB900248CB800081338004794 +:1062A000000040213C0E800835D30080926D0068CC +:1062B000240B000231AC00FF118B00803C068000F3 +:1062C000927F004C90C40109509F00043213007C5F +:1062D00011000067000000003213007C1660005AB5 +:1062E0000240202116200008320C00013C078000EB +:1062F00034EB0A008D6500248CE8010414A8FFDC4F +:1063000000001021320C00011180000D02402021FC +:106310003C1080008E0E010C8F8D006011CD0008A6 +:10632000000000000E00073E022028218E0F010C05 +:106330003C18800837100080AE0F0050024020212A +:106340000E00066F022028210A00086F24020001B7 +:106350003C0708008CE7006424E600013C010800CB +:10636000AC2600641600000D000000000220282169 +:106370000E00066F02402021926F0068240D00027B +:1063800031EE00FF11CD0022024020210E00082333 +:10639000000000000A00086F240200010E00004106 +:1063A00024040001926C0025020C58250E00004FB9 +:1063B000A26B00250A0008AF022028218E63001876 +:1063C0008CE401048CBF002400031602149FFFB567 +:1063D0003045007F9269004C264400013093007FD5 +:1063E00012650040312300FF1464FFAF3C0E8008AB +:1063F000264800013111007F310200FF1225000BF9 +:1064000024080001004090210A00087C24110001AA +:10641000240500040E000632240600010E000823A5 +:10642000000000000A00086F240200012407FF801A +:106430000247282400A79026324200FF0040902106 +:106440000A00087C241100010E00073E02202821CA +:106450003206003010C0FFA332100082024020211B +:106460000E000680022028210A00086F2402000185 +:106470008E6300180240202102202821006610258A +:106480000E000845AE6200189264004C240500031B +:10649000240600010E000632308400FF0E00004189 +:1064A00024040001926A0025020A48250E00004FCC +:1064B000A26900250A00086F240200018E780018E6 +:1064C0003C19800002402021031978250220282150 +:1064D0000E00066FAE6F00189264004C0A0008F7B9 +:1064E000240500043246008038CA0080146AFF6E1A +:1064F0003C0E80080A0008D02648000127BDFFC0D6 +:10650000AFB000183C108000AFBF0038AFB7003408 +:10651000AFB60030AFB5002CAFB40028AFB3002445 +:10652000AFB200200E0004BBAFB1001C9204010802 +:106530009205010B308400FF0E00085630A500FFC5 +:10654000144000E38FBF00383C09800835280080E4 +:10655000A100006B3607098090E60000240200507D +:106560003C17080026F73A8830C300FF3C130800A8 +:1065700026733A98106200033C1080000000B82196 +:1065800000009821241F001036110A0036140980DB +:106590008E1601048F8D00508E38002436190A8023 +:1065A0008E9200203C010800A03F3AD0972C002C8E +:1065B0008EF50000932B0018024D702302D878232B +:1065C0003C010800AC2F3AAC3C010800AC2E3AB0BC +:1065D0003C010800AC2D3AD4A78C005402A0F80965 +:1065E000317200FF304A0002154000E630450001DC +:1065F00010A000C100000000928A0008315000087D +:1066000016000002241400030000A0213C068000B4 +:1066100034C4090034C30A008C6E00249085001134 +:10662000908200129099001130B800FF305100FFA5 +:106630000291F821001FB080332F00FF02D85821AB +:10664000024FA82126AC0010017268213C15800081 +:106650003C010800AC2E3AD83C010800A42D3AC8F1 +:106660003C010800A42C3AC43C010800A42B3AC603 +:1066700036B609808F8700508F8900588ED200204F +:106680002408000601273023024728233C01080084 +:10669000AC283ACC04C000B30000902104A000B1A3 +:1066A00000C5802B120000B3000000003C01080070 +:1066B000AC263AB08E7100000220F80900000000FC +:1066C000304A00021540007400408021304B000128 +:1066D000556000118E7100043C0D08008DAD3AB478 +:1066E0003C0EC0003C04800001AE6025AEAC0E0044 +:1066F0008C980000330F000811E0FFFD000000003F +:10670000949F0E0824120001A79F00408C990E044C +:10671000AF9900388E7100040220F80900000000D3 +:106720000202802532020002144000A9000000008D +:106730003C08080095083ABC3C11080096313AC85C +:106740003C09080095293ABE3C0308008C633AB422 +:10675000011168213C1F08008FFF3AD83C07080050 +:1067600094E73AD23C11800001A920218E38010C17 +:10677000006828212499000200A7702103E37821F2 +:10678000AF9800603C010800AC2F3AD83C010800EB +:10679000A42E3AC03C010800A42D3ACA0E0001B450 +:1067A0003324FFFF8F8C0048004020213C0108006B +:1067B000A02C3AD18E620008258B0001AF8B0048D7 +:1067C0000040F809000000008F8500500280302151 +:1067D0000E00051C004020210E00069E00402021D6 +:1067E0008E6A000C0140F809004020213C08080096 +:1067F00095083ACA3C09080095293ABE0109382192 +:1068000024E600020E0001C830C4FFFF3C0408006B +:106810008C843AAC3C0308008C633AB40083282390 +:106820003C010800AC253AAC14A0000600000000B2 +:106830003C0A08008D4A3ACC354600403C0108002D +:10684000AC263ACC124000418F8C00448E2B0E10A7 +:106850008F920044AE4B00208E220E18AE420024D0 +:106860003C04080094843AC00E0005FA00000000C1 +:106870008F9900508E7800103C010800AC393AD452 +:106880000300F809000000003C0F08008DEF3AAC4F +:1068900015E0FF798F870050979400543C13800EC9 +:1068A000321500100E000629A674002C56A00044D4 +:1068B0008EF60004321F004057E0001D8EF00008E5 +:1068C0008EE3000C0060F809000000008FBF003864 +:1068D0008FB700348FB600308FB5002C8FB40028EE +:1068E0008FB300248FB200208FB1001C8FB000182E +:1068F00003E0000827BD0040920901098F88003C91 +:1069000000093E0000E83025AE0600808E230020FE +:106910008E240024AFA30010AE030E148FA200102B +:10692000AE020E10AE040E1C0A000951AE040E1881 +:106930000200F809000000008EE3000C0060F80976 +:10694000000000000A000A078FBF0038240E000173 +:10695000240D0001A5800020A58E00220A0009EB6D +:10696000AD8D00243C010800AC203AB00A0009813A +:106970008E7100003C010800AC253AB00A00098184 +:106980008E71000092110109000028210E00066F8F +:10699000322400FF8FBF00388FB700348FB600302D +:1069A0008FB5002C8FB400288FB300248FB2002045 +:1069B0008FB1001C8FB0001803E0000827BD004015 +:1069C00002C0F809000000000A000A01321F00405E +:1069D0005240FFB2979400548EB60E148F93004429 +:1069E000AE7600208EB40E1CAE7400240A0009FAA4 +:1069F000979400548F8200140004218003E0000863 +:106A0000008210213C07800834E200809043006936 +:106A100000804021106000093C0401003C07080090 +:106A20008CE73AD48F83003000E3202304800008F1 +:106A30009389001C14E300030100202103E00008F7 +:106A4000008010213C04010003E0000800801021B8 +:106A50001120000B006738233C0D800035AC098005 +:106A6000918B007C316A000211400020240900341F +:106A700000E9702B15C0FFF10100202100E9382347 +:106A80002403FFFC00A3C82400E3C02400F9782BF2 +:106A900015E0FFEA0308202130C40003000410239E +:106AA00014C00014304900030000302100A97821EF +:106AB00001E6702100EE682B11A0FFE03C0401000C +:106AC0002D3800010006C82B010548210319382480 +:106AD00014E0FFDA2524FFFC2402FFFC00A21824A6 +:106AE0000068202103E00008008010210A000A6FDE +:106AF000240900303C0C80003586098090CB007C56 +:106B0000316A00041540FFE9240600040A000A7EE9 +:106B1000000030213C0308008C63005C8F82001869 +:106B200027BDFFE8AFBF001410620005AFB0001032 +:106B3000000329C024A40280AF840014AF8300188E +:106B40003C10800036030A00946500320E000A50A3 +:106B500030A43FFF8E0401003C180080370F000373 +:106B60000082C8212402FF80032260243329007F91 +:106B7000000CF94003E94025332E00783C0D10004D +:106B8000010D502501CF5825AE0C0028360809808C +:106B9000AE0C080CAE0B082CAE0A0830910300694D +:106BA0003C06800C0126382110600006AF870034B7 +:106BB0008D09003C8D06006C0126382318E0007F0B +:106BC000000000003C0C8008358B00803C0A8000EF +:106BD000A1600069355009808E0200383C068000B3 +:106BE00034C50A0090AD003C31A800201100001906 +:106BF000AF820030240E00013C19800037300A00BB +:106C0000A38E001CAF8000248E0400248F850024F6 +:106C100024180008AF800020AF8000283C01080045 +:106C2000A4383ABE3C010800A4203AD20E000A540F +:106C300000003021920F003C8FBF00148FB0001075 +:106C4000000F7142AF82002C27BD001803E000083E +:106C500031C2000190B90032240F0001333800FF27 +:106C600000182182108F003F241F0002109F006235 +:106C700034C20AC03C03800034640A008C990024AA +:106C80001720001D3466090090830030241F000582 +:106C90003062003F105F004C240500018F86002009 +:106CA000A385001CAF860028AF8600243C19800015 +:106CB00037300A008E0400248F8500242418000831 +:106CC0003C010800A4383ABE3C010800A4203AD296 +:106CD0000E000A5400000000920F003C8FBF001409 +:106CE0008FB00010000F7142AF82002C27BD00183A +:106CF00003E0000831C200018C8800088C8D00245C +:106D00008CCB00643C19800037300A00AF8B002424 +:106D1000A380001C8E0400248F8600208F85002411 +:106D2000010D602324180008AF8C00283C010800E6 +:106D3000A4383ABE3C010800A4203AD20E000A54FE +:106D400000000000920F003C8FBF00148FB00010B5 +:106D5000000F7142AF82002C27BD001803E000082D +:106D600031C2000190A7003030E3003F506400289A +:106D700034C50AC08CAA00241540002234C809007A +:106D80008CAB00483C0C7FFF3585FFFF016510246C +:106D90003C188000AF820020370509008F8E00204C +:106DA0008CAF006001CF682B15A0000201C020212C +:106DB0008CA400600A000AF0AF8400208D02006CF1 +:106DC0000A000ACB3C0680008C8900488F86002090 +:106DD0003C0A7FFF3550FFFF013038243C04800817 +:106DE00024050001AF870028AC80006CA385001C3F +:106DF0000A000AFEAF8600248C4400140A000AF040 +:106E0000AF8400208D0200680A000B383C18800017 +:106E100034C409808C8600708CB0001400D0482BDC +:106E200011200004000000008C8200700A000B3862 +:106E30003C1880008CA200140A000B383C1880001B +:106E40008F85002427BDFFE0AFBF0018AFB100144D +:106E500014A00008AFB000103C04800034870A0082 +:106E600090E600302402000530C3003F106200B7F6 +:106E7000348409008F91002000A080213C04800010 +:106E8000348E0A008DCD00043C0608008CC63AB052 +:106E900031A73FFF00E6602B5580000100E0302164 +:106EA000938F001C11E0007600D0102B34990980DC +:106EB0009338007C330400021080007724030034F0 +:106EC00000C3F82B17E000D600C3302300D0102BEE +:106ED0003C010800A4233ABC1440006D02001821B4 +:106EE0003C0408008C843AAC0064282B54A00001B8 +:106EF000006020213C05800034A90A009128003C54 +:106F00003C010800AC243AB43103002014600002B4 +:106F1000000048218CA90E188F88002C0128502BC6 +:106F20001140005F000000003C0508008CA53AB449 +:106F300000A96021010C582B1160005C00B0682B87 +:106F40000109382300E028213C010800AC273AB4AD +:106F5000120000032402FFFC10B0008C322A000350 +:106F600000A2F8243C010800A4203AD23C01080009 +:106F7000AC3F3AB403E028218F84002412040006B9 +:106F80003C0380088C6A006C02002021AF91002035 +:106F900025500001AC70006C8F8B00280085882381 +:106FA000AF91002401652023AF8400281220000245 +:106FB00024070018240700103C0E800835C6008006 +:106FC00090CD0068240C00013C010800A0273AD0B5 +:106FD00031A700FF10EC00470000000014800018EB +:106FE000000028213C0B8000916501093571098062 +:106FF0008E23001830A500FF0003560224A30001D1 +:107000003146007F3070007F1206007E240CFF8026 +:107010003C0F800835E90080A123004C3C080800A3 +:107020008D083ACC240E00023C010800A02E3B1132 +:10703000350D00083C010800AC2D3ACC24050010A9 +:107040003C1F800037E40A009099003C3338002050 +:107050001300000500A02021240200013C010800CB +:10706000AC223AB434A400018FBF00188FB10014D1 +:107070008FB000100080102103E0000827BD002021 +:107080003C010800A4203ABC1040FF9502001821E2 +:107090000A000B8B00C018210A000B832403003068 +:1070A0003C0508008CA53AB400B0682B11A0FFA8DD +:1070B000000000003C04080094843ABC008578215C +:1070C00001E7702B11C000072CA200043C1F6000D8 +:1070D0008FF954043338003F1700FFE324040042C3 +:1070E0002CA200041040FF9A240400420A000BEE78 +:1070F0008FBF00181528FFB9000000008CC20018CF +:107100003C188000241900020058F825ACDF001854 +:1071100037040A00A0D900689089003C240F0004BD +:1071200000A01021312800203C010800A02F3B11B5 +:107130001100000224050010240200013C01080097 +:10714000AC223AAC0A000BE43C1F80008F88002878 +:107150008C8900600109282B14A0000201008821FD +:107160008C9100603C0B80008D640E18240A000195 +:107170000220282102203021A38A001C0E000A547C +:10718000022080210A000B72AF82002C000A182313 +:1071900012200007306400033C0D800035A70980F1 +:1071A00090EC007C318B000415600019248E0004E3 +:1071B0003C010800A4243AD23C18080097183AD29F +:1071C0000305202100C4782B11E0FF6C8F8400247C +:1071D0002CA6000514C0FFA42404004230B900030B +:1071E0001720000200B9182324A3FFFC3C0108006B +:1071F000AC233AB43C010800A4203AD20A000BB1F7 +:107200000060282100AC38240A000BD700EC1826B7 +:107210003C010800A42E3AD20A000C4100000000F4 +:107220003C010800AC203AB40A000BED24040042F3 +:107230008F8300283C0B8000356A0A00146000062A +:1072400000001021914600302405000530C400FFE5 +:10725000108500030000000003E0000800000000AB +:1072600091490048312800FF000839C214E0FFFAB4 +:107270003C0480083C06080094C63ABC3C03080065 +:107280008C633AD43C0508008CA53AB43C1808003D +:1072900097183AD20066C8218C8E00040325782105 +:1072A00001F8682101AE60231980001D0000000074 +:1072B0009158004C8F8D0034956E0E10330F00FFE7 +:1072C0008DA9000401CF30238DAA000030CFFFFF2D +:1072D000000F6100012C28210000382101472021E6 +:1072E00000AC182B0083C821ADA50004ADB9000087 +:1072F00091B8000A01F87021A1AE000A956C0E1237 +:107300008F8A0034A54C00089549003825280001D3 +:10731000A54800389147000D34EB0008A14B000D43 +:1073200003E000080000000027BDFFD8AFB0001840 +:10733000938F001C8FB000143C087FFF8F870024C0 +:107340003C0C80003518FFFFAFBF0020AFB1001C20 +:1073500035990A0002181824932A003C000F5FC0D8 +:107360003C02BFFF2CF000013449FFFF006BF82501 +:107370003C0808008D083AD48F9900303C1808006A +:1073800097183ACA03E9582400107F803C07EFFFA2 +:107390003C05F0FF016F18253C11800031490020A9 +:1073A00034E2FFFF34ADFFFF362E098027A5001021 +:1073B0002406000201194023270A00020062182453 +:1073C0000080802115200002000058218D8B0E1CAA +:1073D000A7AA00120500003A2407000030EF00FFC2 +:1073E000000F3F00006740253C028008AFA8001452 +:1073F000344B0080916A00683C0F080091EF3AD14D +:107400003C09DFFF353FFFFF000A602B3C0208000C +:1074100094423AC4A3AF0011011FC024000CCF4016 +:10742000031918258FA70010AFA300143C1F0800F4 +:1074300093FF3AD3A7A200168FA8001400ED4824AA +:107440003C0B01003C0A0FFF012BC82533F8000359 +:10745000354CFFFF010D78243C027000032C3824CA +:1074600000181E0000E2482501E35825AFAB0014C8 +:10747000AFA9001091DF007CA3BF00150E000063D0 +:1074800000000000362D0A0091A6003C30C4002008 +:1074900010800006260200083C11080096313AC010 +:1074A000262EFFFF3C010800A42E3AC08FBF00200B +:1074B0008FB1001C8FB0001803E0000827BD002822 +:1074C0008F8A002C016A602B5580FFC424070001BD +:1074D0000A000CCB30EF00FF9383001C3C028000BD +:1074E00027BDFFD834480A0000805021AFBF0020DC +:1074F00034460AC0010028211060000E344409807F +:1075000091070030240B00058F89002030EC003FEC +:10751000118B000B00003821AFA900103C0B800834 +:107520008D69006CAFAA00180E00012BAFA90014E2 +:10753000A380001C8FBF002003E0000827BD0028A7 +:107540008D1F00483C1808008F183AB48F99002806 +:107550003C027FFF8D0800443443FFFFAFA90010B9 +:107560003C0B80088D69006C03E3702403197821BB +:1075700001CF682301A83821AFAA00180E00012B03 +:10758000AFA900140A000D20A380001C3C05800058 +:1075900034A60A0090C7003C3C06080094C63AD2C4 +:1075A0003C0208008C423ACC30E300200006240064 +:1075B0001060001E004438253C0880083505008016 +:1075C00090A3006800003021240800010000202161 +:1075D000240300013C0580008CAC01780580FFFE8F +:1075E00000000000ACA80148A4A40144A4A30146E3 +:1075F0003C0308008C633AD43C188008370F0080A5 +:10760000ACA3014C3C19080093393AD13C0D100051 +:10761000A0B90152ACA70154A4A6015891EE004CA8 +:10762000A0AE016D03E00008ACAD01788CA80E1C83 +:107630003C0B08008D6B3AB494AA0E1694A90E1454 +:10764000016630213143FFFF0A000D483124FFFF5E +:107650003C04800034830A009065003C30A2002086 +:107660001040001C0000000000003021000020211C +:10767000000018213C0580008CA901780520FFFE40 +:1076800000000000ACA601483C0E08008DCE3AD4A4 +:10769000240DFF91240C00403C0B8008A4A301445E +:1076A000356A0080A4A40146ACAE014CA0AD0152E5 +:1076B000ACAC0154A4A0015890A301099144004C22 +:1076C00090A601093C041000A0A6016D03E000088B +:1076D000ACA401788C860E1894880E1294870E1034 +:1076E0003104FFFF0A000D7030E3FFFF3C0480000F +:1076F00034830A009065003C30A200201040002630 +:1077000027BDFFF8240900010000382124080001EA +:107710003C0680008CC401780480FFFE000000005D +:1077200090CA01093C04080090843B113C1880FF7A +:10773000A3AA00038FA300003085007F370FFFFF4F +:1077400000661025AFA2000090D9010AA3A0000294 +:1077500000056E00A3B900018FAE0000240A3000BE +:1077600027BD000801CF6024018D5825ACCB014C0A +:10777000ACCA0154A4C00158ACC90148A4C7014413 +:107780002409FF80A4C801463C081000A0C901528A +:1077900003E00008ACC801788C890E1894870E129B +:1077A00094860E1030E8FFFF0A000D9730C7FFFFE8 +:1077B00027BDFFE8AFB000103C108000AFBF001441 +:1077C00036180A00970F00320E000A5031E43FFFCE +:1077D0008E0E0100240DFF803C04200001C25821C0 +:1077E000016D6024000C4940316A007F012A402568 +:1077F000010438253C048008AE0708303486008038 +:1078000090C500682403000230A200FF104300046A +:107810008F9F00208F990024AC9F0068AC99006472 +:107820008FBF00148FB0001003E0000827BD0018C0 +:107830003C0A0800254A359C3C09080025293638B1 +:107840003C08080025082A603C07080024E736FCAD +:107850003C06080024C634243C05080024A5317CDD +:107860003C04080024842D8C3C030800246334D895 +:107870003C020800244232743C010800AC2A3A90D1 +:107880003C010800AC293A8C3C010800AC283A883D +:107890003C010800AC273A943C010800AC263AA40D +:1078A0003C010800AC253A9C3C010800AC243A9805 +:1078B0003C010800AC233AA83C010800AC223AA0E5 +:0878C00003E0000800000000D5 +:0878C800800009408000090066 +:1078D000800801008008008080080000800E000001 +:1078E000800800808008000080000A8080000A0074 +:0878F0008000098080000900FE +:00000001FF +/* + * This file contains firmware data derived from proprietary unpublished + * source code, Copyright (c) 2004 - 2009 Broadcom Corporation. + * + * Permission is hereby granted for the distribution of this firmware data + * in hexadecimal or equivalent format, provided this copyright notice is + * accompanying it. + */ diff --git a/firmware/bnx2/bnx2-rv2p-06-4.6.16.fw.ihex b/firmware/bnx2/bnx2-rv2p-06-4.6.16.fw.ihex deleted file mode 100644 index 871de9e..0000000 --- a/firmware/bnx2/bnx2-rv2p-06-4.6.16.fw.ihex +++ /dev/null @@ -1,441 +0,0 @@ -:100000000000000000000CA00000005800000000EC -:1000100000000000000000000000000000000000E0 -:1000200000000000000000000000000000000000D0 -:1000300000000DE000000CF80000000500000000CA -:1000400000000000000000000000000000000000B0 -:080050000000000000000000A8 -:0800580000000010B18000025D -:100060000000001F0103010000000008AC000001B7 -:1000700000000000050000000000000C2F800001BF -:10008000000000002B000000000000002B8000009A -:1000900000000010203F006300000010213F00031B -:1000A0000000001020BF0032000000188000FFFD9B -:1000B00000000010B1B8B00D0000000B2FDF0002EF -:1000C0000000000003D80000000000002C380000F1 -:1000D0000000001091D400000000000806005555F3 -:1000E0000000001880000075000000188000010B5F -:1000F00000000008020000020000000F42E0001CA7 -:100100000000001091840A11000000102C62000B06 -:10011000000000188000001E00000008020000021D -:100120000000000F42E0001C0000001091840A183B -:10013000000000082C8000B1000000082D0000091C -:100140000000001091D40000000000082D8001077D -:10015000000000188000006F0000001880000015EB -:1001600000000008B1000001000000082C8000B071 -:10017000000000082D000008000000082D8000018C -:1001800000000018800000690000000B2FDF000253 -:100190000000000C1F800002000000002C0700007F -:1001A0000000001091DE00000000000005000000CB -:1001B000000000188000FFDC0000000B2FDF0002B1 -:1001C0000000000C1F800000000000002C07000051 -:1001D0000000001091DE000000000000050000009B -:1001E000000000188000FFD60000000C1F800002F5 -:1001F0000000000005000000000000188000FFD390 -:100200000000000C298000020000000C1F8000028A -:10021000000000002ADF0000000000082A0000059E -:100220000000000805005555000000188000FFCDB3 -:10023000000000080224003C000000180004000038 -:10024000000000188000001C000000188000001E44 -:100250000000001880000052000000188000009E7E -:10026000000000188000009D0000001880000000C1 -:10027000000000188000000000000018800000004E -:10028000000000188000000000000018800000003E -:10029000000000188000000000000018800000002E -:1002A000000000188000000000000018800000DF3F -:1002B000000000188000000000000018800000000E -:1002C0000000001880000015000000188000001BCE -:1002D000000000188000000000000018800000B43A -:1002E000000000188000002E00000018800000DFD1 -:1002F000000000188000010A00000018800000D5EE -:10030000000000188000012E000000188000003B53 -:10031000000000188000000000000018800000713C -:100320000000000C1F80000100000000050000001C -:10033000000000188000FFAC0000001091D4000005 -:100340000000000C298000010000000C1F8000014B -:10035000000000082A000002000000000500000064 -:10036000000000188000FFA60000001091D40000DB -:100370000000000C298000010000000C1F8000011B -:100380000000000029420000000000082A000002CE -:100390000000000005000000000000188000FF9F22 -:1003A000000000188000FF9E00000010B1BCB00AE1 -:1003B0000000000B2FDF00020000000003D8000047 -:1003C000000000002C3C00000000001091D4000050 -:1003D00000000008060055550000001880000016B7 -:1003E00000000018800000AC000000102C6201BA70 -:1003F0000000001880000005000000082C8000B1FB -:10040000000000082D0000090000001091D4000039 -:10041000000000082D8001070000000C298000006A -:100420000000000C1F8000000000001091DE0000A2 -:10043000000000002ADF0000000000082A0000067B -:100440000000000805005555000000188000FF89D5 -:100450000000001091D400000000000C2980000171 -:100460000000000C1F800001000000082A00000BA3 -:100470000000000005000000000000188000FF835D -:1004800000000018000200000000000006820000CA -:1004900000000010B18A000600000000860C140065 -:1004A00000000010B18C00040000000005000000F6 -:1004B000000000082A0000010000001091D4000094 -:1004C00000000018000D0000000000000502000000 -:1004D0000000001091DE000000000018000A00007B -:1004E00000000010B1A0B0130000000B2FDF0002CD -:1004F000000000002C200000000000082C800000FC -:10050000000000082D0000000000001091D4000041 -:100510000000000806005555000000188000FFEE9E -:10052000000000082D80011C00000010001F0000CA -:100530000000001091DE00000000000F476000087E -:100540000000000F060E0001000000000F58000020 -:10055000000000000A640000000000000AE500003E -:10056000000000090B66FFFF000000000D610000A5 -:1005700000000018800000130000000F4760000812 -:100580000000000B2FDF0002000000082C8000009C -:10059000000000082D0000000000001091D40000B1 -:1005A000000000082D80011C0000000F060E000155 -:1005B00000000010001F0000000000000F580000A5 -:1005C0000000001091DE0000000000000A6400003E -:1005D000000000000AE50000000000090B66FFFFB4 -:1005E000000000000D610000000000000262000039 -:1005F0000000000B2FDF00020000000031040000AB -:1006000000000000309A0000000000000C96180066 -:10061000000000090C99FFFF00000004CC99340091 -:1006200000000010B1963202000000080F800000A8 -:100630000000000C298000010000001000220002D0 -:100640000000000C295200010000000C295200009B -:10065000000000080200000E000000080280001ADE -:1006600000000010B1C40A020000000802000003EC -:1006700000000008220000010000000C1F800001A3 -:10068000000000002ADF0000000000002A0008002F -:100690000000000805005555000000188000FF3FCD -:1006A0000000000B2FDF00020000001091D40000BA -:1006B000000000082A000001000000002C200000BB -:1006C000000000082C800000000000082D00000041 -:1006D000000000082D80011C0000001091D40000D3 -:1006E0000000001091DE0000000000082C800006D1 -:1006F000000000082D00000600000000308000000F -:100700000000000031000000000000082D800006FD -:100710000000000C298000010000000C1F80000177 -:100720000000001091DE0000000000002ADF000041 -:10073000000000082A000010000000000500000072 -:10074000000000188000FF2A0000001091A0B009EE -:10075000000000082C8000B1000000082D000009F6 -:100760000000001091D40000000000082D80010757 -:10077000000000188000FFAB00000018800000108F -:1007800000000008AC000001000000188000000B11 -:10079000000000000380B0000000000B2FDF00020B -:1007A000000000002C0040000000001091D4000068 -:1007B0000000000806005555000000188000FF9A50 -:1007C00000000018800000300000001880000006C3 -:1007D0000000000B2FDF0002000000002C000E00C4 -:1007E000000000082A000007000000080500555519 -:1007F000000000188000FF140000000006820000C6 -:100800000000000C298000010000000C1F80000186 -:10081000000000100CE70007000000090562FFFF60 -:1008200000000010BA6C1405000000002ADF000070 -:100830000000000021000000000000082A00000560 -:100840000000001091D40000000000082C8000B0CF -:10085000000000082D0000080000000C31620018A4 -:10086000000000082D800001000000188000FF8CAF -:1008700000000018000D000000000010B1A0B00E34 -:100880000000000B2FDF00020000000003D8000072 -:10089000000000002C2000000000001091D4000097 -:1008A0000000001880000014000000102C620002FC -:1008B000000000188000000B0000000B2FDF00027A -:1008C000000000002C0700000000000C1F80000149 -:1008D0000000001091DE0000000000000500000094 -:1008E000000000188000FEF6000000082C8000B117 -:1008F000000000082D0000090000001091D4000045 -:10090000000000082D8001070000000C2980000174 -:100910000000000C1F8000010000001091DE0000AC -:10092000000000002ADF0000000000082A00000A82 -:100930000000000005000000000000188000FEEB31 -:100940000000000005020000000000082C8000B03C -:10095000000000082D000008000000082D80015054 -:10096000000000000000000000000010205F0000F8 -:10097000000000082C800000000000082D0000008E -:10098000000000082D8001080000000000000000A9 -:100990000000001091DE000000000018000A0000B6 -:1009A0000000001091D40000000000080600AAAA70 -:1009B000000000188000FF5B0000000C298000018F -:1009C0000000000C1F800001000000082A00000940 -:1009D000000000080500AAAA000000188000FED749 -:1009E0000000001091D400000000000806005555DA -:1009F000000000188000FF530000001091A03C028E -:100A000000000010B1E662070000000B2FDF0002BB -:100A1000000000002C310000000000092CB1007F14 -:100A2000000000082CD90000000000082D00000084 -:100A3000000000082D80010D00000010B1A8000684 -:100A400000000010205F0000000000002C200000CB -:100A5000000000002CA70000000000082D0000107E -:100A6000000000082D800108000000188000FF4CE5 -:100A700000000010B1A6001000000010001F0000D0 -:100A80000000000F0F300007000000000A600000A7 -:100A9000000000000AE100000000000F4B620008A7 -:100AA000000000090B1600FF000000000D620000AE -:100AB000000000090D1A00FF0000001007300003BD -:100AC0000000000C0D1A00080000000C0B160008B6 -:100AD0000000000F4CE30018000000000C992C00EF -:100AE00000000004CC993400000000080F800000D2 -:100AF0000000000C298000010000000033310000DC -:100B00000000000822000016000000002ADF00009C -:100B1000000000082A00000C00000010009F0000E8 -:100B2000000000000F2000000000000C1F800001EA -:100B30000000000805005555000000188000FEABBD -:100B40000000001091D40000000000080600AAAACE -:100B5000000000188000FF270000000F4722000857 -:100B600000000009070E000F00000008070E000833 -:100B700000000008028000010000000702851C0040 -:100B800000000008828500010000000002854C0082 -:100B90000000000742851C0000000003C3AA5200A9 -:100BA0000000000003B10E00000000074B071C000E -:100BB0000000000F0F3000070000000F0A9600032E -:100BC000000000000A955C00000000004A005A0086 -:100BD000000000000C960A00000000090C99FFFFBD -:100BE000000000080D00FFFF00000010B196320267 -:100BF000000000080F80000500000010B1A80008E8 -:100C000000000010205F00000000000B2FDF00023A -:100C1000000000002C200000000000002CA70000B5 -:100C2000000000082D000010000000082D800108C1 -:100C3000000000188000FF130000000C2980000154 -:100C400000000010001F00000000000C1F800001C9 -:100C5000000000002ADF0000000000082A00000D4C -:100C6000000000080500AAAA000000188000FE8508 -:100C70000000001091D40000000000080600555547 -:100C8000000000188000FF010000000C2980000116 -:100C90000000000C1F800001000000082A0000076F -:100CA0000000000805005555000000188000FE7D7A -:100CB00000000008030500040000000683040C0087 -:100CC00000000008028502000000000086050C00FC -:100CD00000000001860C0E00000000080204000461 -:100CE00000000000020418000000000083871800C4 -:080CF0000000001800020000E2 -:080CF80000000010B1800004AF -:100D00000000001F0103010000000008050000FFB3 -:100D10000000001800020000000000002A0000008F -:100D200000000010B1D400000000000C2980000178 -:100D30000000000802540008000000180004000031 -:100D40000000001880000010000000188000001152 -:100D5000000000188000003A000000188000010424 -:100D6000000000188000010300000018800001024C -:100D70000000001880000102000000188000000040 -:100D8000000000188000011400000018800000FE20 -:100D9000000000188000000C0000001880000118FE -:100DA000000000188000016A000000188000006741 -:100DB00000000018800000DA00000018800000E742 -:100DC000000000002A000000000000188000FFEB77 -:100DD000000000002A0000000000000C2980000034 -:100DE0000000001020530000000000188000FFE702 -:100DF000000000002A000000000000188000FFE54D -:100E000000000018000200000000000005020000C1 -:100E1000000000109196342100000010205F0000B7 -:100E2000000000002C1E0000000000082C800006BE -:100E3000000000082D000006000000082D800102BF -:100E400000000000000000000000001091DE000023 -:100E5000000000000D61000000000018000A000002 -:100E600000000000050200000000001091963416FA -:100E700000000010205F00000000000009D8000002 -:100E8000000000002C1E0000000000082C8000B2B2 -:100E9000000000082D00000A000000082D8001025B -:100EA00000000000000000000000001091DE0000C3 -:100EB000000000000D620000000000002C13000084 -:100EC00000000018000A00000000000005020000F9 -:100ED000000000109196340900000010205F00000F -:100EE000000000002C1E0000000000082C800006FE -:100EF000000000082D00006A000000082D8001029B -:100F000000000000000000000000001091DE000062 -:100F1000000000000D7A000000000018000A000028 -:100F20000000001091DE000000000010001F000013 -:100F3000000000002F80AA00000000002A0000002E -:100F4000000000000D6100000000000003620000CE -:100F5000000000002C4000000000000002638C0034 -:100F600000000000264600000000000802040012F5 -:100F700000000010B9060827000000000F5800000C -:100F8000000000000A640000000000000AE5000004 -:100F9000000000090B66FFFF000000000C000000CD -:100FA000000000000B800000000000080CC60012CA -:100FB000000000188000FFCB000000080F80000335 -:100FC000000000000000000000000010009F000072 -:100FD00000000008271100120000000066900000C9 -:100FE00000000008A31B001200000010B1980003CD -:100FF00000000010001F0000000000080F80000427 -:101000000000000822000003000000082C80000CF3 -:10101000000000082D00000C00000010009F0000E0 -:1010200000000000259600000000000C2980000050 -:101030000000000006660000000000008661180045 -:10104000000000090260000F0000000F020400020F -:1010500000000010B60C08030000000C1FBF0000C9 -:101060000000000C33660010000000003214000085 -:1010700000000000329500000000000573662C009F -:101080000000000031E32E00000000082D80001059 -:1010900000000010205300000000001091DE00004E -:1010A000000000188000FF900000000023000000F6 -:1010B0000000000925E6FFFF000000082200000BE9 -:1010C0000000000C695200000000000C29800000A4 -:1010D0000000001020530000000000188000FF896D -:1010E0000000001091DE000000000010001F000052 -:1010F000000000002F80AA00000000002A0000006D -:10110000000000002C400000000000082C8000407F -:10111000000000082D000020000000082D80011CA8 -:1011200000000000000000000000001091DE000040 -:101130000000000F42EA001000000010004F000401 -:1011400000000010B746920000000008024900129B -:1011500000000010B5840A00000000000D610000CE -:1011600000000010BA66345A00000000036200005C -:1011700000000010B8630C5800000008830500123E -:1011800000000010004F00020000000003490000B2 -:101190000000000183068C000000000083C60C00E4 -:1011A00000000010B1870010000000000B6E00006E -:1011B000000000188000FF6B0000000106691400A9 -:1011C00000000010918C000200000008B4E900014A -:1011D00000000010B1E92C4C0000000086692C00D2 -:1011E00000000000020000000000000902EAFFFF0A -:1011F00000000010000C00020000000002040A00C1 -:101200000000000F460C00010000000F02850001E5 -:1012100000000010918C01FC00000010B7040E4388 -:10122000000000002C400000000000000F40000003 -:10123000000000000D610000000000000A640000D2 -:10124000000000000AE50000000000090B66FFFF37 -:10125000000000000C000000000000000B800000F7 -:10126000000000080C860012000000080F80000338 -:101270000000000C2952000000000010009F000038 -:101280000000000827110012000000006690000016 -:1012900000000000264600000000000023060000B9 -:1012A00000000010B198000500000010001F0000B1 -:1012B000000000080F800004000000000000000093 -:1012C00000000010001F00000000000032140000A9 -:1012D00000000000329500000000000031E32E0005 -:1012E0000000000573662C00000000002596000039 -:1012F00000000010B18700160000000C29800000DB -:101300000000000F0F6B0007000000000D690000D7 -:10131000000000000A6C0000000000000AED000060 -:10132000000000000B6E0000000000000B800000B9 -:10133000000000000C870000000000080F80000380 -:1013400000000010205300000000000C6952000152 -:1013500000000010001F00000000000022C58C00EB -:1013600000000000231B0000000000002711000007 -:10137000000000002690000000000010B8170E03C7 -:101380000000000C29800000000000188000FFF61B -:1013900000000010B1980002000000080F80000457 -:1013A000000000082200001A000000082C80000C39 -:1013B000000000082D00000C000000082D80001027 -:1013C00000000010001F0000000000000D6E000073 -:1013D00000000003E7CF34000000000C298000006B -:1013E0000000001091DE000000000010B18700072F -:1013F00000000000361400000000000036950000D8 -:101400000000000037160000000000082C8000508B -:10141000000000082D000030000000082D80000CA6 -:101420000000001020530000000000188000FF1F83 -:10143000000000002646000000000000230000001D -:101440000000000925E6FFFF000000000B6E000011 -:1014500000000003E7CF2C00000000082200001B62 -:101460000000000C695200000000000C2980000000 -:101470000000001020530000000000188000FF153D -:10148000000000002FD50000000000002A0000002E -:1014900000000010003F000B000000000666000086 -:1014A000000000008661180000000009026000F0E2 -:1014B00000000010B70C08070000000C7366001055 -:1014C000000000082C800018000000082D00001803 -:1014D000000000082D8000020000000C5FBF00002B -:1014E0000000001091DE0000000000188000FF07DF -:1014F000000000002FD50000000000002A000000BE -:10150000000000002C4000000000000C29800000BA -:101510000000001091DE0000000000082C80001A7E -:10152000000000082D00001A000000003300000039 -:10153000000000082D800002000000003180000043 -:101540000000001091DE0000000000082C80000C5C -:10155000000000082D00000C000000082D80000491 -:1015600000000010205300000000001091DE000079 -:10157000000000188000FEF6000000188000FEF554 -:10158000000000002A00000000000010001F000002 -:10159000000000000F008000000000080F8000071E -:1015A0000000001880000014000000000502000088 -:1015B000000000082200000900000000286D000063 -:1015C00000000000290000000000000F6568001006 -:1015D00000000003F66C940000000010B972A00433 -:1015E0000000000C73E700190000000C2142000409 -:1015F000000000003BF600000000000C2980000005 -:101600000000001020530000000000082200000825 -:101610000000000C6142000400000018000A0000F5 -:10162000000000002A00000000000010001F000061 -:101630000000000F0F470007000000080F8000089F -:101640000000000C29800000000000102053000062 -:10165000000000188000FEDA0000001091DE00009B -:10166000000000002FD5000000000010001F000047 -:101670000000000033510000000000002A000000BC -:1016800000000010B1C600230000000F0F5000073B -:10169000000000000A600000000000000AE10000F5 -:1016A0000000000F4B620008000000090B1600FF4D -:1016B0000000000F4C620010000000000D620000EE -:1016C000000000090D1A00FF000000100750000381 -:1016D0000000000C0D1A00080000000C0B1600089A -:1016E000000000000CC60000000000000B8000009D -:1016F0000000000006980000000000080F800003B2 -:101700000000001006C200040000000C29000002C6 -:1017100000000010264200020000000C29520003C5 -:10172000000000082200000100000010009F0000DF -:1017300000000000231B00000000000027111A0019 -:1017400000000000669000000000000C295200001C -:1017500000000010B19732090000000C2980000041 -:101760000000000006980000000000102053000058 -:101770000000000C295200030000000022C58C006C -:1017800000000010001F0000000000080F80000390 -:10179000000000188000FFF300000010B1C8001323 -:1017A00000000010B1C600030000000C29800000FA -:1017B00000000010205300000000000C295200001F -:1017C0000000000C295200030000001006C20002B5 -:1017D0000000000C295200020000000022C58C000D -:1017E00000000000276500000000000026E4000063 -:1017F000000000082200001600000010B1C600031F -:10180000000000002348000000000010B180000527 -:1018100000000000234800000000000C29800000A8 -:101820000000000F0F500007000000188000001299 -:1018300000000008220000160000000C29800000B3 -:10184000000000003014000000000000309500008F -:101850000000001007500003000000090B1600FFF5 -:10186000000000090D1A00FF0000000F31160008EB -:10187000000000003162340000000003F16230001B -:1018800000000010205F0000000000002C5100004C -:10189000000000092CD1007F000000082CD90000B6 -:1018A000000000082D000000000000082D80000C42 -:1018B00000000000000000000000001091DE0000A9 -:1018C0000000001005C2000300000000330000000B -:1018D000000000080F8000070000001020530000E7 -:1018E00000000010009F0000000000188000FE872C -:1018F000000000002FD50000000000002A000000BA -:101900000000000F0F50000700000010B1C6002DAE -:101910000000000F4742000800000009070E000FFA -:1019200000000008070E000800000010001F000063 -:1019300000000008090000010000000709121C0057 -:1019400000000003CBCA9200000000000B97A20029 -:101950000000000742171C00000000000B040000FC -:101960000000000F0A840003000000000A959C009C -:10197000000000004A009A000000000882120001E6 -:10198000000000010C170800000000000C978C00FC -:101990000000000002180000000000080D00FFFF1A -:1019A000000000080F8000060000000C2900000065 -:1019B0000000001006C200040000000C29520002C2 -:1019C00000000010264200020000000C2952000313 -:1019D000000000082200000100000010009F00002D -:1019E00000000010B197320C00000000231B000023 -:1019F00000000000271108000000000066900000B1 -:101A00000000000C29800000000000000218000007 -:101A100000000010205300000000000C29520003B9 -:101A20000000000022C5360000000010001F00006A -:101A3000000000080F800006000000188000FFF47E -:101A400000000000231B0000000000002711080018 -:101A5000000000006690000000000010B1C8000BFC -:101A60000000000C2980000000000010205300003E -:101A70000000000C295200000000000C2952000355 -:101A80000000001006C200020000000C29520002F3 -:101A90000000000022C58C00000000002765000047 -:101AA0000000000026E400000000000023480000C1 -:101AB00000000008220000170000000C2980000030 -:101AC00000000010001F0000000000102053000064 -:081AD000000000188000FE4A2E -:00000001FF -/* - * This file contains firmware data derived from proprietary unpublished - * source code, Copyright (c) 2004 - 2009 Broadcom Corporation. - * - * Permission is hereby granted for the distribution of this firmware data - * in hexadecimal or equivalent format, provided this copyright notice is - * accompanying it. - */ diff --git a/firmware/bnx2/bnx2-rv2p-06-5.0.0.j3.fw.ihex b/firmware/bnx2/bnx2-rv2p-06-5.0.0.j3.fw.ihex new file mode 100644 index 0000000..52c4963 --- /dev/null +++ b/firmware/bnx2/bnx2-rv2p-06-5.0.0.j3.fw.ihex @@ -0,0 +1,424 @@ +:100000000000000000000C900000005800000009F3 +:1000100000000000000000000000000000000000E0 +:1000200000000000000000000000000000000000D0 +:1000300000000CE000000CE80000000500000000DB +:1000400000000000000000000000000000000000B0 +:080050000000000000000000A8 +:0800580000000010B180000659 +:100060000000001F01030300000000080500FFFF5F +:10007000000000180002000000000008050000FF5A +:10008000000000180002000000000008AC000001A1 +:1000900000000000050000000000000C2F8000019F +:1000A000000000002B000000000000002B8000007A +:1000B0000000001091E0000200000008AC00000108 +:1000C00000000010203F004D00000010213F000301 +:1000D0000000001020BF001C000000188000FFFD81 +:1000E00000000008B1000001000000082C8000B0F2 +:1000F000000000082D000008000000082D8000010D +:10010000000000188000006C0000000B2FDF0002D0 +:100110000000000C1F800002000000002C070000FF +:100120000000001091DE0000000000080500555599 +:10013000000000188000FFF00000000B2FDF00021D +:100140000000000C1F800000000000002C070000D1 +:100150000000001091DE0000000000080500555569 +:10016000000000188000FFEA0000000C1F80000261 +:100170000000000805005555000000188000FFE74A +:100180000000000C298000020000000C1F8000020B +:10019000000000002ADF0000000000082A0000051F +:1001A0000000000805005555000000188000FFE120 +:1001B000000000080224002C0000001800040000C9 +:1001C000000000188000001C000000188000001EC5 +:1001D000000000188000006500000018800000B0DA +:1001E00000000018800000AF000000188000000030 +:1001F00000000018800000000000001880000000CF +:1002000000000018800000000000001880000000BE +:1002100000000018800000000000001880000000AE +:10022000000000188000000000000018800000F6A8 +:10023000000000188000000000000018800000008E +:100240000000001880000015000000188000001B4E +:10025000000000188000000000000018800000C6A8 +:10026000000000188000002F00000018800000F639 +:10027000000000188000012100000018800000EC40 +:100280000000001880000145000000188000004EAA +:1002900000000018800000000000001880000083AB +:1002A0000000000C1F80000100000000050000009D +:1002B000000000188000FFC00000001091D4000072 +:1002C0000000000C298000010000000C1F800001CC +:1002D000000000082A0000020000000005000000E5 +:1002E000000000188000FFBA0000001091D4000048 +:1002F0000000000C298000010000000C1F8000019C +:100300000000000029420000000000082A0000024E +:100310000000000005000000000000188000FFB38E +:10032000000000188000FFB200000010B1BCB00A4D +:100330000000000B2FDF00020000000003D80000C7 +:10034000000000002C3C00000000001091D40000D0 +:100350000000000806005555000000188000001736 +:1003600000000018800000BF000000102C6201BADD +:100370000000001880000006000000082C8000B17A +:10038000000000082D0000090000001091D40000BA +:10039000000000082D8001070000001880000024E4 +:1003A0000000000C298000000000000C1F800000ED +:1003B0000000001091DE0000000000002ADF0000B5 +:1003C000000000082A00000600000008050055553E +:1003D000000000188000FF9C0000001091D4000075 +:1003E0000000000C298000010000000C1F800001AB +:1003F000000000082A00000B0000000005000000BB +:10040000000000188000FF960000001800020000A5 +:10041000000000000682000000000010B18A000801 +:1004200000000010B18C14070000000B050AFFFF4C +:1004300000000010B18A000300000000860A1800C6 +:1004400000000010918C0000000000082A0000014C +:100450000000001091D4000000000018000D000002 +:1004600000000000050200000000001091DE000006 +:1004700000000018000A00000000000006820000D2 +:100480000000001091DE000000000010BEE1000539 +:10049000000000188000FF7D0000000105611400CD +:1004A00000000010918A000200000008B0E1000185 +:1004B00000000018000D000000000000068200008F +:1004C0000000001091DE000000000010BEE20005F8 +:1004D000000000188000FF75000000010562140094 +:1004E00000000010918A000200000008B1620001C3 +:1004F00000000018000D000000000010B1A0B013B3 +:100500000000000B2FDF0002000000002C20000084 +:10051000000000082C800000000000082D000000F2 +:100520000000001091D4000000000008060055559E +:10053000000000188000FFDC000000082D80011C76 +:1005400000000010001F0000000000188000FFE6FF +:100550000000000F476000080000000F060E0001B9 +:10056000000000000F580000000000000A640000B6 +:10057000000000000AE50000000000090B66FFFF14 +:10058000000000000D610000000000188000001352 +:100590000000000F476000080000000B2FDF000282 +:1005A000000000082C800000000000082D00000062 +:1005B0000000001091D40000000000082D80011CF4 +:1005C0000000000F060E000100000010001F0000D8 +:1005D000000000000F580000000000188000FFD449 +:1005E000000000000A640000000000000AE50000AE +:1005F000000000090B66FFFF000000000D61000015 +:1006000000000000026200000000000B2FDF00026B +:10061000000000003104000000000000309A0000DB +:10062000000000000C961800000000090C99FFFF64 +:1006300000000004CC99340000000010B196320292 +:10064000000000080F8000000000000C298000015D +:100650000000000C295200010000000C295200008B +:10066000000000080200000E000000080280001ACE +:1006700000000010B1C40A020000000802000003DC +:1006800000000008220000010000000C1F80000193 +:10069000000000002ADF0000000000002A0008001F +:1006A0000000000805005555000000188000FF41BB +:1006B0000000000B2FDF00020000001091D40000AA +:1006C000000000082A000001000000002C200000AB +:1006D0000000001091D40000000000082C800000F1 +:1006E000000000082D000000000000082D80011C03 +:1006F000000000188000FFAE000000082C800006FB +:10070000000000082D0000060000000030800000FE +:100710000000000031000000000000082D800006ED +:100720000000000C298000010000000C1F80000167 +:100730000000001091DE0000000000002ADF000031 +:10074000000000082A000010000000000500000062 +:10075000000000188000FF2C0000001091A0B009DC +:10076000000000082C8000B1000000082D000009E6 +:100770000000001091D40000000000082D80010747 +:10078000000000188000FFA7000000188000001083 +:1007900000000008AC000001000000188000000B01 +:1007A000000000000380B0000000000B2FDF0002FB +:1007B000000000002C0040000000001091D4000058 +:1007C0000000000806005555000000188000FF8951 +:1007D00000000018800000310000001880000006B2 +:1007E0000000000B2FDF0002000000002C000E00B4 +:1007F000000000082A000007000000080500555509 +:10080000000000188000FF160000000006820000B3 +:100810000000000C298000010000000C1F80000176 +:10082000000000100CE70007000000090562FFFF50 +:1008300000000010BA6C1405000000002ADF000060 +:100840000000000021000000000000082A00000550 +:100850000000001091D40000000000082C8000B0BF +:10086000000000082D0000080000000C3162001894 +:10087000000000082D800001000000188000FF7DAE +:1008800000000018000D000000000010B1A0B00E24 +:100890000000000B2FDF00020000000003D8000062 +:1008A000000000002C2000000000001091D4000087 +:1008B0000000001880000015000000102C620002EB +:1008C000000000188000000C0000000B2FDF000269 +:1008D000000000002C0700000000000C1F80000139 +:1008E0000000001091DE0000000000080500FFFF7E +:1008F000000000188000FEF8000000082C8000B105 +:10090000000000082D0000090000001091D4000034 +:10091000000000082D800107000000188000FF740F +:100920000000000C298000010000000C1F80000165 +:100930000000001091DE0000000000002ADF00002F +:10094000000000082A00000A000000000500000066 +:10095000000000188000FEEC00000000068200008D +:10096000000000082C8000B0000000082D000008E6 +:10097000000000082D800150000000000000000071 +:100980000000001091DE0000000000082C80000034 +:10099000000000082D000000000000082D80010567 +:1009A00000000010BEE20005000000188000FEDA22 +:1009B000000000010562140000000010918A00028E +:1009C00000000008B16200010000001091DE00008C +:1009D00000000018000D00000000001091D400007D +:1009E000000000080600AAAA000000188000FF45C9 +:1009F0000000000C298000010000000C1F80000195 +:100A0000000000082A000009000000080500AAAA4A +:100A1000000000188000FED40000001091D40000F7 +:100A20000000000806005555000000188000FF3D3A +:100A30000000001091A03C0200000010B1E6620727 +:100A40000000000B2FDF0002000000002C3100002E +:100A5000000000092CB1007F000000082CD9000024 +:100A6000000000082D000000000000082D80010D8E +:100A700000000010B1A8000600000010205F000078 +:100A8000000000002C200000000000002CA7000047 +:100A9000000000082D000010000000082D80010853 +:100AA000000000188000FF3800000010B1A6001000 +:100AB00000000010001F00000000000F0F300007B2 +:100AC000000000000A600000000000000AE10000D1 +:100AD0000000000F4B620008000000090B1600FF29 +:100AE000000000000D620000000000090D1A00FF68 +:100AF00000000010073000030000000C0D1A000871 +:100B00000000000C0B1600080000000F4CE300185A +:100B1000000000000C992C0000000004CC99340067 +:100B2000000000080F8000000000000C2980000178 +:100B30000000000033310000000000082200001611 +:100B4000000000002ADF0000000000082A00000C5E +:100B500000000010009F0000000000000F200000B7 +:100B60000000000C1F800001000000080500555522 +:100B7000000000188000FEA80000001091D40000C2 +:100B8000000000080600AAAA000000188000FF115B +:100B90000000000F4722000800000009070E000FA8 +:100BA00000000008070E0008000000080280000195 +:100BB0000000000702851C0000000008828500017B +:100BC0000000000002854C000000000742851C0068 +:100BD00000000003C3AA52000000000003B10E0091 +:100BE000000000074B071C000000000F0F3000073B +:100BF0000000000F0A960003000000000A955C0048 +:100C0000000000004A005A00000000000C960A0094 +:100C1000000000090C99FFFF000000080D00FFFF15 +:100C200000000010B1963202000000080F8000059D +:100C300000000010B1A8000800000010205F0000B4 +:100C40000000000B2FDF0002000000002C2000003D +:100C5000000000002CA70000000000082D0000107C +:100C6000000000082D800108000000188000FEFF31 +:100C70000000000C2980000100000010001F00008F +:100C80000000000C1F800001000000002ADF0000AF +:100C9000000000082A00000D000000080500AAAAB4 +:100CA000000000188000FE820000001091D40000B7 +:100CB0000000000806005555000000188000FEEBFB +:100CC0000000000C298000010000000C1F800001C2 +:100CD000000000082A000007000000080500555524 +:080CE000000000188000FE7AFC +:080CE80000000010B1800004BF +:100CF0000000001F0103030000000008050000FFC2 +:100D00000000001800020000000000002A0000009F +:100D100000000010B1D400000000001091DE0000BF +:100D2000000000102053000000000010001F000011 +:100D3000000000002F80AA000000000C29800001A4 +:100D4000000000080254000D000000002C400000CC +:100D500000000018000400000000001880000010CF +:100D60000000001880000011000000188000003909 +:100D700000000018800000DF00000018800000DE86 +:100D800000000018800000DD00000018800000DD79 +:100D9000000000188000000000000018800000F52E +:100DA00000000018800000D9000000188000000B2F +:100DB00000000018800000F90000001880000147C2 +:100DC000000000188000005900000018800000C4D6 +:100DD00000000018800000C5000000002A0000008C +:100DE000000000188000FFE6000000002A0000005C +:100DF0000000000C29800000000000188000FFE3C4 +:100E0000000000002A000000000000188000FFE140 +:100E100000000018000200000000000005020000B1 +:100E2000000000109196342100000010205F0000A7 +:100E3000000000002C1E0000000000082C800006AE +:100E4000000000082D000006000000082D800102AF +:100E500000000000000000000000001091DE000013 +:100E6000000000000D61000000000018000A0000F2 +:100E700000000000050200000000001091963416EA +:100E800000000010205F00000000000009D80000F2 +:100E9000000000002C1E0000000000082C8000B2A2 +:100EA000000000082D00000A000000082D8001024B +:100EB00000000000000000000000001091DE0000B3 +:100EC000000000000D620000000000002C13000074 +:100ED00000000018000A00000000000005020000E9 +:100EE000000000109196340900000010205F0000FF +:100EF000000000002C1E0000000000082C800006EE +:100F0000000000082D00006A000000082D8001028A +:100F100000000000000000000000001091DE000052 +:100F2000000000000D7A000000000018000A000018 +:100F3000000000002A000000000000000D61000019 +:100F4000000000000362000000000010234200A324 +:100F50000000000002638C00000000002646000034 +:100F6000000000080204001200000010B906081E6C +:100F7000000000000F580000000000000A6400009C +:100F8000000000000AE50000000000090B66FFFFFA +:100F9000000000000C000000000000000B800000BA +:100FA000000000080CC60012000000188000FFCEF0 +:100FB000000000080F800003000000000000000097 +:100FC00000000010009F0000000000082711001220 +:100FD000000000006690000000000008A31B001243 +:100FE00000000010B198000300000010001F000076 +:100FF000000000080F800004000000082200000329 +:10100000000000082C80000C000000082D00000CDF +:1010100000000010009F0000000000002596000066 +:101020000000000C298000000000000032140000C5 +:1010300000000000329500000000000573662C00DF +:101040000000000031E32E00000000082D80001099 +:10105000000000188000FF9800000000230000003E +:101060000000000925E6FFFF000000082200000B39 +:101070000000000C695200000000000C29800000F4 +:10108000000000188000FF92000000002A0000000D +:10109000000000082C800040000000082D00002007 +:1010A000000000082D80011C00000000000000006E +:1010B0000000001091DE00000000000F42EA001066 +:1010C00000000010004F000400000010B74692001E +:1010D000000000080249001200000010B5840A0058 +:1010E000000000000D61000000000010BA663457D7 +:1010F000000000088305001200000010004F0002ED +:1011000000000000034900000000000183068C007D +:101110000000000083C60C0000000010B187001121 +:10112000000000000B6E000000000010BEE900058A +:10113000000000188000FF7900000001056914001C +:1011400000000010918A000200000008B4E90001CC +:1011500000000010B1E92C4A0000000086692C0054 +:1011600000000000020000000000000902EAFFFF8A +:1011700000000010000C00020000000002040A0041 +:101180000000000F460C00010000000F0285000166 +:1011900000000010918C01FC00000010B7040E410B +:1011A000000000000F400000000000000D61000082 +:1011B000000000000A640000000000000AE50000D2 +:1011C000000000090B66FFFF000000000C0000009B +:1011D000000000000B800000000000080C860012D8 +:1011E000000000080F8000030000000C29520000DE +:1011F00000000010009F00000000000827110012EE +:10120000000000006690000000000000264600007C +:10121000000000002306000000000010B198000547 +:1012200000000010001F0000000000080F800004F4 +:10123000000000000000000000000010001F00007F +:101240000000000032140000000000003295000091 +:101250000000000031E32E000000000573662C0042 +:10126000000000002596000000000010B187001665 +:101270000000000C298000000000000F0F6B000729 +:10128000000000000D690000000000000A6C000072 +:10129000000000000AED0000000000000B6E0000DE +:1012A000000000000B800000000000000C87000020 +:1012B000000000080F800003000000102053000011 +:1012C0000000000C6952000100000010001F000027 +:1012D0000000000022C58C0000000000231B00005D +:1012E0000000000027110000000000002690000010 +:1012F00000000010B8170E030000000C2980000049 +:10130000000000188000FFF600000010B1980002F5 +:10131000000000080F800004000000082200001AEE +:10132000000000082C80000C000000082D00000CBC +:10133000000000082D80001000000010001F0000B9 +:10134000000000000D6E000000000003E7CF340035 +:101350000000000C298000000000001091DE000059 +:1013600000000010B18700070000000036140000E4 +:101370000000000036950000000000003716000055 +:10138000000000082C800050000000082D000030F4 +:10139000000000082D80000C000000188000FF2FC6 +:1013A00000000000264600000000000023000000AE +:1013B0000000000925E6FFFF000000000B6E0000A2 +:1013C00000000003E7CF2C00000000082200001BF3 +:1013D0000000000C695200000000000C2980000091 +:1013E000000000188000FF26000000002A00000016 +:1013F000000000188000FF24000000002A00000008 +:101400000000000C298000000000001091DE0000A8 +:10141000000000082C80001A000000082D00001AAF +:101420000000000573660000000000082D80000227 +:1014300000000000318000000000001091DE00007C +:10144000000000082C80000C000000082D00000C9B +:10145000000000082D800004000000188000FF1725 +:101460000000001800020000000000188000FF15B6 +:10147000000000002A00000000000010001F000013 +:10148000000000000F008000000000080F8000072F +:10149000000000188000001A00000000280A000068 +:1014A0000000000005020000000000082200000902 +:1014B00000000000290000000000000F6568001017 +:1014C00000000003F66C940000000010B972A00444 +:1014D0000000000C73E700190000000C214200041A +:1014E000000000003CF800000000000C2980000013 +:1014F0000000001020530000000000082200000837 +:101500000000000C6142000400000018000A000006 +:1015100000000000050200000000000C6142000015 +:1015200000000010014200030000000C33E7001D22 +:101530000000000C6142000200000018000A0000D8 +:10154000000000002A00000000000010001F000042 +:101550000000000F0F470007000000080F80000880 +:101560000000000C2980000000000010009F000017 +:10157000000000188000FEF400000000335100005D +:10158000000000002A00000000000010B1C6002387 +:101590000000000F0F500007000000000A6000006C +:1015A000000000000AE100000000000F4B6200088C +:1015B000000000090B1600FF0000000F4C62001035 +:1015C000000000000D620000000000090D1A00FF7D +:1015D00000000010075000030000000C0D1A000866 +:1015E0000000000C0B160008000000000CC60000F4 +:1015F000000000000B8000000000000006980000C2 +:10160000000000080F8000030000001006C2000464 +:101610000000000C29000002000000102642000219 +:101620000000000C29520003000000082200000105 +:1016300000000010009F000000000000231B0000BD +:101640000000000027111A00000000006690000052 +:101650000000000C2952000000000010B197320970 +:101660000000000C29800000000000000698000027 +:1016700000000010205300000000000C295200035D +:101680000000000022C58C0000000010001F0000B8 +:10169000000000080F800003000000188000FFF326 +:1016A00000000010B1C8001300000010B1C6000314 +:1016B0000000000C298000000000001020530000F2 +:1016C0000000000C295200000000000C2952000309 +:1016D0000000001006C200020000000C29520002A7 +:1016E0000000000022C58C000000000027650000FB +:1016F0000000000026E400000000000822000016A0 +:1017000000000010B1C600030000000023480000E4 +:1017100000000010B1800005000000002348000018 +:101720000000000C298000000000000F0F5000078F +:1017300000000018800000120000000822000016BF +:101740000000000C298000000000000030140000A0 +:10175000000000003095000000000010075000035A +:10176000000000090B1600FF000000090D1A00FF21 +:101770000000000F31160008000000003162340044 +:1017800000000003F162300000000010205F000044 +:10179000000000002C510000000000092CD1007F47 +:1017A000000000082CD90000000000082D000000F7 +:1017B000000000082D80000C000000000000000068 +:1017C0000000001091DE00000000001005C20004BF +:1017D000000000080F800007000000003300000038 +:1017E00000000010009F0000000000188000FEA50F +:1017F000000000002A0000000000000F0F5000074A +:1018000000000010B1C6002D0000000F4742000884 +:1018100000000009070E000F00000008070E000876 +:1018200000000010001F0000000000080900000177 +:101830000000000709121C0000000003CBCA920040 +:10184000000000000B97A2000000000742171C00D8 +:10185000000000000B0400000000000F0A840003D9 +:10186000000000000A959C00000000004A009A0059 +:101870000000000882120001000000010C1708009F +:10188000000000000C978C0000000000021800000F +:10189000000000080D00FFFF000000080F80000698 +:1018A0000000000C290000000000001006C2000427 +:1018B0000000000C29520002000000102642000225 +:1018C0000000000C29520003000000082200000163 +:1018D00000000010009F000000000010B197320CC3 +:1018E00000000000231B000000000000271108007A +:1018F00000000000669000000000000C298000003D +:10190000000000000218000000000010205300003A +:101910000000000C295200030000000022C5360020 +:1019200000000010001F0000000000080F800006EB +:10193000000000188000FFF400000000231B0000DE +:101940000000000027110800000000006690000061 +:1019500000000010B1C8000B0000000C298000003E +:1019600000000010205300000000000C295200006D +:101970000000000C295200030000001006C2000203 +:101980000000000C295200020000000022C58C005B +:1019900000000000276500000000000026E40000B1 +:1019A000000000002348000000000008220000178B +:1019B0000000000C2980000000000010001F000043 +:0819C000000000188000FE6A1F +:00000001FF +/* + * This file contains firmware data derived from proprietary unpublished + * source code, Copyright (c) 2004 - 2009 Broadcom Corporation. + * + * Permission is hereby granted for the distribution of this firmware data + * in hexadecimal or equivalent format, provided this copyright notice is + * accompanying it. + */ diff --git a/firmware/bnx2/bnx2-rv2p-09-4.6.15.fw.ihex b/firmware/bnx2/bnx2-rv2p-09-4.6.15.fw.ihex deleted file mode 100644 index 63995bb..0000000 --- a/firmware/bnx2/bnx2-rv2p-09-4.6.15.fw.ihex +++ /dev/null @@ -1,490 +0,0 @@ -:100000000000000000000D88000000580000000003 -:1000100000000000000000000000000000000000E0 -:1000200000000000000000000000000000000000D0 -:100030000000101800000DE00000000500000000A6 -:1000400000000000000000000000000000000000B0 -:080050000000000000000000A8 -:0800580000000010B18000025D -:100060000000001F0303010000000008AC000001B5 -:1000700000000000050000000000000C2F800001BF -:10008000000000002B000000000000002B8000009A -:1000900000000010203F006C00000010213F000312 -:1000A0000000001020BF003B000000188000FFFD92 -:1000B00000000010B1B8B0150000000B2FDF0002E7 -:1000C0000000000003D80000000000002C380000F1 -:1000D000000000082C800000000000082D00000037 -:1000E0000000001091D400000000000806005555E3 -:1000F000000000188000008F000000082D80011C07 -:1001000000000008020000010000001091DE000065 -:100110000000000F42E0001C0000001091840A174C -:1001200000000010086600160000000C2980000284 -:100130000000000C1F800002000000002ADF000009 -:10014000000000082A00000F0000000805005555B7 -:10015000000000188000FFE8000000080200000115 -:100160000000000F42E0001C0000001091840A19FA -:10017000000000082C800006000000082D0000068A -:100180000000001091D40000000000082D8001063E -:1001900000000018800000830000001008660013B3 -:1001A000000000188000FFF100000008B10000010D -:1001B000000000082C80010C000000082D00000841 -:1001C000000000082D800001000000188000007C65 -:1001D0000000000B2FDF00020000000C1F80000257 -:1001E000000000002C0700000000001091DE00005D -:1001F0000000000005000000000000188000FFD390 -:100200000000000B2FDF00020000000C1F80000028 -:10021000000000002C0700000000001091DE00002C -:100220000000000005000000000000188000FFCD65 -:100230000000000C1F80000200000000050000000C -:10024000000000188000FFCA0000000C2980000296 -:100250000000000C1F800002000000002ADF0000E8 -:10026000000000082A0000050000000805005555A0 -:10027000000000188000FFC40000000802240045B0 -:100280000000001800040000000000188000001C9E -:10029000000000188000001E0000001880000065AB -:1002A00000000018800000AD00000018800000ACC5 -:1002B000000000188000000000000018800000000E -:1002C00000000018800000000000001880000000FE -:1002D00000000018800000000000001880000000EE -:1002E00000000018800000000000001880000000DE -:1002F00000000018800000F30000001880000000DB -:1003000000000018800000000000001880000015A8 -:10031000000000188000001B000000188000000092 -:1003200000000018800000C3000000188000002EAC -:1003300000000018800000F3000000188000011E7B -:1003400000000018800000E9000000188000014251 -:10035000000000188000004E00000018800000001F -:1003600000000018800000800000000C1F800001C9 -:100370000000000005000000000000188000FFA33E -:100380000000001091D400000000000C2980000142 -:100390000000000C1F800001000000082A0000027D -:1003A0000000000005000000000000188000FF9D14 -:1003B0000000001091D400000000000C2980000112 -:1003C0000000000C1F800001000000002942000016 -:1003D000000000082A0000020000000005000000E4 -:1003E000000000188000FF96000000188000FF95B4 -:1003F00000000010B1BCB00A0000000B2FDF0002AB -:100400000000000003D80000000000002C3C0000A9 -:100410000000001091D400000000000806005555AF -:10042000000000188000002900000018800000BBB8 -:10043000000000102C6201BA0000001880000005C6 -:10044000000000082C80010D000000082D000009AC -:100450000000001091D40000000000082D8001076A -:100460000000000C298000000000000C1F8000002C -:100470000000001091DE0000000000002ADF0000F4 -:10048000000000082A00000600000008050055557D -:10049000000000188000FF800000001091D40000D0 -:1004A0000000000C298000010000000C1F800001EA -:1004B000000000082A00000B0000000005000000FA -:1004C000000000188000FF7A000000000202000017 -:1004D00000000000029A000000000000060C2C0042 -:1004E00000000004C60C340000000010001F0000D3 -:1004F00000000010B196180C0000000806960004D9 -:1005000000000009068DFFFC00000004CD051A0064 -:1005100000000004CC9A18000000001020D7000052 -:100520000000000C2B56000000000000000000003E -:1005300000000000000000000000001020D70000B4 -:10054000000000080F80000100000010B18001F4DD -:1005500000000010001F00000000000C6B5600009F -:1005600000000018000400000000000006820000E7 -:1005700000000010B18A000600000000860C140084 -:1005800000000010B18C0004000000000500000015 -:10059000000000082A0000010000001091D40000B3 -:1005A00000000018000D000000000000050200001F -:1005B0000000001091DE000000000018000A00009A -:1005C00000000010B1A0B0130000000B2FDF0002EC -:1005D000000000002C200000000000082C8000001B -:1005E000000000082D0000000000001091D4000061 -:1005F0000000000806005555000000188000FFEEBE -:10060000000000082D80011C00000010001F0000E9 -:100610000000001091DE00000000000F476000089D -:100620000000000F060E0001000000000F5800003F -:10063000000000000A640000000000000AE500005D -:10064000000000090B66FFFF000000000D610000C4 -:1006500000000018800000130000000F4760000831 -:100660000000000B2FDF0002000000082C800000BB -:10067000000000082D0000000000001091D40000D0 -:10068000000000082D80011C0000000F060E000174 -:1006900000000010001F0000000000000F580000C4 -:1006A0000000001091DE0000000000000A6400005D -:1006B000000000000AE50000000000090B66FFFFD3 -:1006C000000000000D610000000000000262000058 -:1006D0000000000B2FDF00020000000031040000CA -:1006E00000000000309A0000000000188000FFBCED -:1006F0000000000C29800001000000100022000210 -:100700000000000C295200010000000C29520000DA -:10071000000000080200000E000000080280001A1D -:1007200000000010B1C40A0200000008020000032B -:1007300000000008220000010000000C1F800001E2 -:10074000000000002ADF0000000000002A0008006E -:100750000000000805005555000000188000FF2724 -:100760000000000B2FDF00020000001091D40000F9 -:10077000000000082A000001000000002C200000FA -:10078000000000082C800000000000082D00000080 -:10079000000000082D80011C0000001091D4000012 -:1007A0000000001091DE0000000000082C80000610 -:1007B000000000082D00000600000000308000004E -:1007C0000000000031000000000000082D8000063D -:1007D0000000000C298000010000000C1F800001B7 -:1007E0000000001091DE0000000000002ADF000081 -:1007F000000000082A0000100000000005000000B2 -:10080000000000188000FF120000001091A0B00945 -:10081000000000082C80010D000000082D000009D8 -:100820000000001091D40000000000082D80010796 -:10083000000000188000FFAF0000001880000010CA -:1008400000000008AC000001000000188000000B50 -:10085000000000000380B0000000000B2FDF00024A -:10086000000000002C0040000000001091D40000A7 -:100870000000000806005555000000188000FF9E8B -:100880000000001880000030000000188000000602 -:100890000000000B2FDF0002000000002C000E0003 -:1008A000000000082A000007000000080500555558 -:1008B000000000188000FEFC00000000068200001E -:1008C0000000000C298000010000000C1F800001C6 -:1008D000000000100CE70007000000090562FFFFA0 -:1008E00000000010BA6C1405000000002ADF0000B0 -:1008F0000000000021000000000000082A000005A0 -:100900000000001091D40000000000082C80010CB1 -:10091000000000082D0000080000000C31620018E3 -:10092000000000082D800001000000188000FF90EA -:1009300000000018000D000000000010B1A0B00E73 -:100940000000000B2FDF00020000000003D80000B1 -:10095000000000002C2000000000001091D40000D6 -:100960000000001880000014000000102C6200023B -:10097000000000188000000B0000000B2FDF0002B9 -:10098000000000002C0700000000000C1F80000188 -:100990000000001091DE00000000000005000000D3 -:1009A000000000188000FEDE000000082C80010D11 -:1009B000000000082D0000090000001091D4000084 -:1009C000000000082D8001070000000C29800001B4 -:1009D0000000000C1F8000010000001091DE0000EC -:1009E000000000002ADF0000000000082A00000AC2 -:1009F0000000000005000000000000188000FED389 -:100A00000000000005020000000000082C80010C1E -:100A1000000000082D000008000000082D800134AF -:100A2000000000000000000000000010205F000037 -:100A3000000000082C800140000000082D00003C50 -:100A4000000000082D80011C0000000000000000D4 -:100A500000000010205F0000000000082C800080D3 -:100A6000000000082D000000000000082D80010893 -:100A700000000000000000000000001091DE0000F7 -:100A800000000018000A00000000001091D40000CF -:100A9000000000080600AAAA000000188000FF5A03 -:100AA0000000000C298000010000000C1F800001E4 -:100AB000000000082A000009000000080500AAAA9A -:100AC000000000188000FEBA0000001091D4000061 -:100AD0000000000806005555000000188000FF5275 -:100AE0000000001091A03C0200000010B1E6620777 -:100AF0000000000B2FDF0002000000002C3100007E -:100B0000000000092CB1007F000000082CD9000073 -:100B1000000000082D000000000000082D80010DDD -:100B200000000010B1A8000600000010205F0000C7 -:100B3000000000002C200000000000002CA7000096 -:100B4000000000082D000010000000082D800108A2 -:100B5000000000188000FF4B00000010B1A600103C -:100B600000000010001F00000000000F0F30000701 -:100B7000000000000A600000000000000AE1000020 -:100B80000000000F4B620008000000090B1600FF78 -:100B9000000000000D620000000000090D1A00FFB7 -:100BA00000000010073000030000000C0D1A0008C0 -:100BB0000000000C0B1600080000000F4CE30018AA -:100BC000000000000C992C0000000004CC993400B7 -:100BD000000000080F8000000000000C29800001C8 -:100BE0000000000033310000000000082200001661 -:100BF000000000002ADF0000000000082A00000CAE -:100C000000000010009F0000000000000F20000006 -:100C10000000000C1F800001000000080500555571 -:100C2000000000188000FE8E0000001091D400002B -:100C3000000000080600AAAA000000188000FF2695 -:100C40000000000F4722000800000009070E000FF7 -:100C500000000008070E00080000000802800001E4 -:100C60000000000702851C000000000882850001CA -:100C70000000000002854C000000000742851C00B7 -:100C800000000003C3AA52000000000003B10E00E0 -:100C9000000000074B071C000000000F0F3000078A -:100CA0000000000F0A960003000000000A955C0097 -:100CB000000000004A005A00000000000C960A00E4 -:100CC000000000090C99FFFF000000080D00FFFF65 -:100CD00000000010B1963202000000080F800005ED -:100CE00000000010B1A8000800000010205F000004 -:100CF0000000000B2FDF0002000000002C2000008D -:100D0000000000002CA70000000000082D000010CB -:100D1000000000082D800108000000188000FF126C -:100D20000000000C2980000100000010001F0000DE -:100D30000000000C1F800001000000002ADF0000FE -:100D4000000000082A00000D000000080500AAAA03 -:100D5000000000188000FE680000001091D4000020 -:100D60000000000806005555000000188000FF0034 -:100D70000000000C298000010000000C1F80000111 -:100D8000000000082A000007000000080500555573 -:100D9000000000188000FE60000000080305000449 -:100DA0000000000683040C00000000080285020019 -:100DB0000000000086050C0000000001860C0E00FB -:100DC00000000008020400040000000002041800F3 -:100DD00000000000838718000000001800020000D7 -:100DE00000000010B18000040000001F0303010098 -:100DF00000000008050000FF0000001800020000CD -:100E0000000000002A00000000000010B1D4000023 -:100E10000000000C298000010000000802540009B5 -:100E2000000000092952003F0000001800040000E3 -:100E30000000001880000010000000188000001161 -:100E4000000000188000004B000000188000013CEA -:100E5000000000188000013B000000188000013AEB -:100E6000000000188000013A000000188000000017 -:100E7000000000188000014D0000001880000136BD -:100E8000000000188000000C0000001880000152D3 -:100E900000000018800001AC0000001880000080F5 -:100EA00000000018800001070000001880000115F4 -:100EB000000000002A000000000000188000FFEA87 -:100EC000000000002A0000000000000C2980000043 -:100ED0000000001020530000000000188000FFE612 -:100EE000000000002A000000000000188000FFE45D -:100EF0000000000003820000000000188000FFDFF7 -:100F0000000000010C161400000000008C181400F2 -:100F10000000001091980003000000080C960002E9 -:100F200000000010B1800003000000080C960001D2 -:100F3000000000000C000000000000000D1900007F -:100F400000000010205600000000000C2BD700010C -:100F5000000000080F8000010000000000000000F9 -:100F600000000010001F00000000000C6BD7000103 -:100F700000000010011301F100000018000700003C -:100F800000000000050200000000001091963421CE -:100F900000000010205F0000000000002C1E000078 -:100FA000000000082C800006000000082D0000064C -:100FB000000000082D800102000000000000000079 -:100FC0000000001091DE0000000000000D61000034 -:100FD00000000018000A00000000000005020000E8 -:100FE000000000109196341600000010205F0000F1 -:100FF0000000000009D80000000000002C1E0000C6 -:10100000000000082C80010E000000082D00000ADE -:10101000000000082D800102000000000000000018 -:101020000000001091DE0000000000000D620000D2 -:10103000000000002C13000000000018000A00004F -:101040000000000005020000000000109196340925 -:1010500000000010205F0000000000002C1E0000B7 -:10106000000000082C800006000000082D00006A27 -:10107000000000082D8001020000000000000000B8 -:101080000000001091DE0000000000000D7A00005A -:1010900000000018000A00000000001091DE0000AF -:1010A00000000010001F00000000000C6BD70001C2 -:1010B000000000002F80AA00000000002A000000AD -:1010C000000000000D61000000000000036200004D -:1010D000000000002C4000000000000002638C00B3 -:1010E0000000000026460000000000080204001274 -:1010F00000000010B906082E000000000F58000084 -:10110000000000000A640000000000000AE5000082 -:10111000000000090B66FFFF000000000C0000004B -:10112000000000000B800000000000080CC6001248 -:10113000000000188000FFCA0000001020560000C8 -:101140000000000C2BD70001000000080F800003F6 -:10115000000000000000000000000010001F000060 -:101160000000000C6BD700010000000827110012DE -:10117000000000006690000000000008A31B0012A1 -:1011800000000010B198000600000010001F0000D1 -:101190000000000C6BD7000100000010205600007A -:1011A0000000000C2BD70001000000080F80000495 -:1011B0000000000822000003000000082C80000C42 -:1011C000000000082D00000C00000010001F0000AF -:1011D0000000000C6BD70001000000002596000005 -:1011E0000000000C298000000000000006660000DE -:1011F0000000000086611800000000090260000F76 -:101200000000000F0204000200000010B60C0803EA -:101210000000000C1FBF00000000000C336600102F -:1012200000000000321400000000000032950000B1 -:101230000000000573662C000000000031E32E0062 -:10124000000000082D800010000000102053000056 -:101250000000001091DE0000000000188000FF7602 -:1012600000000000230000000000000925E6FFFF49 -:10127000000000082200000B0000000C6952000072 -:101280000000000C29800000000000102053000026 -:10129000000000188000FF6F0000001091DE0000C9 -:1012A00000000010001F00000000000C6BD70001C0 -:1012B000000000002F80AA00000000002A000000AB -:1012C000000000002C400000000000082C800040BE -:1012D000000000082D000020000000082D80011CE7 -:1012E00000000000000000000000001091DE00007F -:1012F0000000000F42EA001000000010004F000440 -:1013000000000010B74692000000000802490012D9 -:1013100000000010B5840A00000000000D6100000C -:1013200000000010BA66346D000000000362000087 -:1013300000000010B8630C6B000000088305001269 -:1013400000000010004F00020000000003490000F0 -:101350000000000183068C000000000083C60C0022 -:1013600000000010B1870010000000000B6E0000AC -:10137000000000188000FF50000000010669140002 -:1013800000000010918C000200000008B4E9000188 -:1013900000000010B1E92C5F0000000086692C00FD -:1013A00000000000020000000000000902EAFFFF48 -:1013B00000000010000C00020000000002040A00FF -:1013C0000000000F460C00010000000F0285000124 -:1013D00000000010918C01FC00000010B7040E56B4 -:1013E000000000002C400000000000000F40000042 -:1013F000000000000D610000000000000A64000011 -:10140000000000000AE50000000000090B66FFFF75 -:10141000000000000C000000000000000B80000035 -:10142000000000080C86001200000010205600008A -:101430000000000C2BD70001000000080F80000303 -:101440000000000C2952000000000010001F0000E6 -:101450000000000C6BD700010000000827110012EB -:10146000000000006690000000000000264600001A -:10147000000000002306000000000010B1980009E1 -:1014800000000010001F00000000000C6BD70001DE -:1014900000000010205600000000000C2BD70001B7 -:1014A000000000080F8000040000000000000000A1 -:1014B00000000010001F00000000000C6BD70001AE -:1014C000000000003214000000000000329500000F -:1014D0000000000031E32E000000000573662C00C0 -:1014E000000000002596000000000010B1870021D8 -:1014F0000000000C298000000000000F0F6B0007A7 -:10150000000000000D690000000000000A6C0000EF -:10151000000000000AED0000000000000B6E00005B -:10152000000000000B800000000000000C8700009D -:10153000000000188000FF18000000010C161400C5 -:10154000000000008C181400000000080C96000138 -:101550000000001091980002000000080C990001A2 -:10156000000000000D190000000000000C00000049 -:1015700000000010205600000000000C2BD70001D6 -:10158000000000080F800001000000102053000040 -:101590000000000C6952000100000010001F000054 -:1015A0000000000C6BD700010000000022C58C0079 -:1015B00000000000231200000000000027110000BE -:1015C000000000002690000000000010B8170E0375 -:1015D0000000000C29800000000000188000FFEBD4 -:1015E0000000000082970E0000000000A3120A0015 -:1015F000000000082200001A000000082C80000CE7 -:10160000000000082D00000C000000082D800010D4 -:1016100000000010001F00000000000C6BD700014C -:10162000000000000D6E000000000003E7CF340052 -:101630000000000C298000000000001091DE000076 -:1016400000000010B1870007000000003614000001 -:101650000000000036950000000000003716000072 -:10166000000000082C800050000000082D00003011 -:10167000000000082D80000C000000102053000026 -:10168000000000188000FEF1000000002646000067 -:1016900000000000230000000000000925E6FFFF15 -:1016A000000000000B6E000000000003E7CF2C00DC -:1016B000000000082200001B0000000C695200001E -:1016C0000000000C298000000000001020530000E2 -:1016D000000000188000FEE7000000002FD5000089 -:1016E000000000002A00000000000010003F000C75 -:1016F000000000000666000000000000866118007F -:1017000000000009026000F000000010B70C08089B -:10171000000000002C4000000000000C7366001068 -:10172000000000082C800018000000082D000018A0 -:10173000000000082D8000020000000C5FBF0000C8 -:101740000000001091DE0000000000188000FED8AC -:10175000000000002FD50000000000002A0000005B -:10176000000000002C4000000000000C7366001018 -:10177000000000082C800018000000082D00001850 -:10178000000000082D8000020000000C5FBF000078 -:101790000000001091DE0000000000082C80000313 -:1017A000000000082D000003000000093060FFF079 -:1017B000000000082D8000010000000C29800000BE -:1017C0000000001091DE0000000000082C80001ACC -:1017D000000000082D00001A000000003300000087 -:1017E000000000082D800002000000003180000091 -:1017F0000000001091DE0000000000082C80000CAA -:10180000000000082D00000C000000082D800004DE -:1018100000000010205300000000001091DE0000C6 -:10182000000000188000FEBD000000188000FEBC13 -:10183000000000002A00000000000010001F00004F -:101840000000000C6BD70001000000000F008000BA -:10185000000000080F80000700000018800000153D -:10186000000000000502000000000008220000093E -:1018700000000000286D00000000000029000000AA -:101880000000000F6568001000000003F66C940073 -:1018900000000010B972A0040000000C73E70019EA -:1018A0000000000C21420004000000003BF6000094 -:1018B0000000000C298000000000001020530000F0 -:1018C00000000008220000080000000C6142000433 -:1018D00000000018000A0000000000002A000000BC -:1018E00000000010001F00000000000C6BD700017A -:1018F0000000000F0F470007000000080F800008DD -:101900000000000C2980000000000010205300009F -:10191000000000188000FE9F0000001091DE000013 -:10192000000000002FD5000000000010001F000084 -:101930000000000C6BD700010000000033510000D4 -:10194000000000002A00000000000010B1C60029BD -:101950000000000F0F500007000000000A600000A8 -:10196000000000000AE100000000000F4B620008C8 -:10197000000000090B1600FF0000000F4C62001071 -:10198000000000000D620000000000090D1A00FFB9 -:1019900000000010075000030000000C0D1A0008A2 -:1019A0000000000C0B160008000000000CC6000030 -:1019B000000000000B8000000000000006980000FE -:1019C00000000010205600000000000C2BD7000182 -:1019D000000000080F8000030000001006C2000491 -:1019E0000000000C29000002000000102642000246 -:1019F0000000000C29520003000000082200000132 -:101A000000000010001F00000000000C6BD7000158 -:101A100000000000231B00000000000027111A0036 -:101A200000000000669000000000000C2952000039 -:101A300000000010B197320C0000000C298000005B -:101A40000000000006980000000000102053000075 -:101A50000000000C295200030000000022C58C0089 -:101A600000000010001F00000000000C6BD70001F8 -:101A700000000010205600000000000C2BD70001D1 -:101A8000000000080F800003000000188000FFEF36 -:101A900000000010B1C8001300000010B1C6000320 -:101AA0000000000C298000000000001020530000FE -:101AB0000000000C295200000000000C2952000315 -:101AC0000000001006C200020000000C29520002B3 -:101AD0000000000022C58C00000000002765000007 -:101AE0000000000026E400000000000822000016AC -:101AF00000000010B1C600030000000023480000F1 -:101B000000000010B1800005000000002348000024 -:101B10000000000C298000000000000F0F5000079B -:101B200000000018800000120000000822000016CB -:101B30000000000C298000000000000030140000AC -:101B40000000000030950000000000100750000366 -:101B5000000000090B1600FF000000090D1A00FF2D -:101B60000000000F31160008000000003162340050 -:101B700000000003F162300000000010205F000050 -:101B8000000000002C510000000000092CD1007F53 -:101B9000000000082CD90000000000082D00000003 -:101BA000000000082D80000C000000000000000074 -:101BB0000000001091DE00000000001005C20003CC -:101BC0000000000033000000000000080F80000744 -:101BD000000000102053000000000010001F000053 -:101BE0000000000C6BD70001000000188000FE44CC -:101BF000000000002FD50000000000002A000000B7 -:101C00000000000F0F50000700000010B1C60030A8 -:101C10000000000F4742000800000009070E000FF7 -:101C200000000008070E000800000010001F000060 -:101C30000000000C6BD70001000000080900000143 -:101C40000000000709121C0000000003CBCA92002C -:101C5000000000000B97A2000000000742171C00C4 -:101C6000000000000B0400000000000F0A840003C5 -:101C7000000000000A959C00000000004A009A0045 -:101C80000000000882120001000000010C1708008B -:101C9000000000000C978C000000000002180000FB -:101CA000000000080D00FFFF000000080F80000684 -:101CB0000000000C290000000000001006C2000413 -:101CC0000000000C29520002000000102642000211 -:101CD0000000000C2952000300000008220000014F -:101CE00000000010001F00000000000C6BD7000176 -:101CF00000000010B197320D00000000231B00000F -:101D0000000000002711080000000000669000009D -:101D10000000000C298000000000000002180000F4 -:101D200000000010205300000000000C29520003A6 -:101D30000000000022C5360000000010001F000057 -:101D40000000000C6BD70001000000080F800006A7 -:101D5000000000188000FFF200000000231B0000BC -:101D6000000000002711080000000000669000003D -:101D700000000010B1C8000B0000000C298000001A -:101D800000000010205300000000000C2952000049 -:101D90000000000C295200030000001006C20002DF -:101DA0000000000C295200020000000022C58C0037 -:101DB00000000000276500000000000026E400008D -:101DC0000000000023480000000000082200001767 -:101DD0000000000C2980000000000010001F00001F -:101DE0000000000C6BD70001000000102053000021 -:081DF000000000188000FE0352 -:00000001FF -/* - * This file contains firmware data derived from proprietary unpublished - * source code, Copyright (c) 2004 - 2009 Broadcom Corporation. - * - * Permission is hereby granted for the distribution of this firmware data - * in hexadecimal or equivalent format, provided this copyright notice is - * accompanying it. - */ diff --git a/firmware/bnx2/bnx2-rv2p-09-5.0.0.j3.fw.ihex b/firmware/bnx2/bnx2-rv2p-09-5.0.0.j3.fw.ihex new file mode 100644 index 0000000..69f5e95 --- /dev/null +++ b/firmware/bnx2/bnx2-rv2p-09-5.0.0.j3.fw.ihex @@ -0,0 +1,462 @@ +:100000000000000000000E00000000580000000981 +:1000100000000000000000000000000000000000E0 +:1000200000000000000000000000000000000000D0 +:1000300000000DD800000E58000000050000000070 +:1000400000000000000000000000000000000000B0 +:080050000000000000000000A8 +:0800580000000010B180000659 +:100060000000001F05030300000000080500FFFF5B +:10007000000000180002000000000008050000FF5A +:10008000000000180002000000000008AC000001A1 +:1000900000000000050000000000000C2F8000019F +:1000A000000000002B000000000000002B8000007A +:1000B0000000001091E0000200000008AC00000108 +:1000C00000000010203F006B00000010213F0003E3 +:1000D0000000001020BF003A000000188000FFFD63 +:1000E00000000010B1B8B0150000000B2FDF0002B7 +:1000F0000000000003D80000000000002C380000C1 +:10010000000000082C800000000000082D00000006 +:100110000000001091D400000000000806005555B2 +:10012000000000188000007C000000082D80011CE9 +:1001300000000008020000010000001091DE000035 +:100140000000000F42E0001C0000001091840A161D +:1001500000000018800000830000000C29800002CD +:100160000000000C1F800002000000002ADF0000D9 +:10017000000000082A00000F000000000500000039 +:10018000000000188000FFE60000000802000001E7 +:100190000000000F42E0001C0000001091840A18CB +:1001A000000000082C800006000000082D0000065A +:1001B0000000001091D40000000000082D8001060E +:1001C0000000001880000072000000188000FFF19D +:1001D00000000008B1000001000000082C80010CA4 +:1001E000000000082D000008000000082D8000011C +:1001F000000000188000006C0000000B2FDF0002E0 +:100200000000000C1F800002000000002C0700000E +:100210000000001091DE00000000000805005555A8 +:10022000000000188000FFD20000000B2FDF00024A +:100230000000000C1F800000000000002C070000E0 +:100240000000001091DE0000000000080500555578 +:10025000000000188000FFCC0000000C1F8000028E +:100260000000000805005555000000188000FFC977 +:100270000000000C298000020000000C1F8000021A +:10028000000000002ADF0000000000082A0000052E +:100290000000000805005555000000188000FFC34D +:1002A000000000080224004A0000001800040000BA +:1002B000000000188000001C000000188000001ED4 +:1002C000000000188000006500000018800000BBDE +:1002D00000000018800000BA000000188000000034 +:1002E00000000018800000000000001880000000DE +:1002F00000000018800000000000001880000000CE +:1003000000000018800000000000001880000000BD +:1003100000000018800000000000001880000106A6 +:10032000000000188000000000000018800000009D +:100330000000001880000015000000188000001B5D +:10034000000000188000000000000018800000D1AC +:10035000000000188000002F000000188000010637 +:10036000000000188000013100000018800000FC2F +:100370000000001880000155000000188000004EA9 +:100380000000001880000000000000188000008EAF +:100390000000000C1F8000010000000005000000AC +:1003A000000000188000FFA20000001091D400009F +:1003B0000000000C298000010000000C1F800001DB +:1003C000000000082A0000020000000005000000F4 +:1003D000000000188000FF9C0000001091D4000075 +:1003E0000000000C298000010000000C1F800001AB +:1003F0000000000029420000000000082A0000025E +:100400000000000005000000000000188000FF95BB +:10041000000000188000FF9400000010B1BCB00A7A +:100420000000000B2FDF00020000000003D80000D6 +:10043000000000002C3C00000000001091D40000DF +:100440000000000806005555000000188000001745 +:1004500000000018800000CA000000102C6201BAE1 +:100460000000001880000006000000082C80010D2C +:10047000000000082D0000090000001091D40000C9 +:10048000000000082D8001070000001880000024F3 +:100490000000000C298000000000000C1F800000FC +:1004A0000000001091DE0000000000002ADF0000C4 +:1004B000000000082A00000600000008050055554D +:1004C000000000188000FF7E0000001091D40000A2 +:1004D0000000000C298000010000000C1F800001BA +:1004E000000000082A00000B0000000005000000CA +:1004F000000000188000FF780000001800020000D3 +:10050000000000000682000000000010B18A000810 +:1005100000000010B18C14070000000B050AFFFF5B +:1005200000000010B18A000300000000860A1800D5 +:1005300000000010918C0000000000082A0000015B +:100540000000001091D4000000000018000D000011 +:1005500000000000050200000000001091DE000015 +:1005600000000018000A00000000000006820000E1 +:100570000000001091DE000000000010BEE1000548 +:10058000000000188000FF5F0000000105611400FA +:1005900000000010918A000200000008B0E1000194 +:1005A00000000018000D000000000000068200009E +:1005B0000000001091DE000000000010BEE2000507 +:1005C000000000188000FF570000000105621400C1 +:1005D00000000010918A000200000008B1620001D2 +:1005E00000000018000D000000000010B1A0B013C2 +:1005F0000000000B2FDF0002000000002C20000094 +:10060000000000082C800000000000082D00000001 +:100610000000001091D400000000000806005555AD +:10062000000000188000FFDC000000082D80011C85 +:1006300000000010001F0000000000188000FFE60E +:100640000000000F476000080000000F060E0001C8 +:10065000000000000F580000000000000A640000C5 +:10066000000000000AE50000000000090B66FFFF23 +:10067000000000000D610000000000188000001361 +:100680000000000F476000080000000B2FDF000291 +:10069000000000082C800000000000082D00000071 +:1006A0000000001091D40000000000082D80011C03 +:1006B0000000000F060E000100000010001F0000E7 +:1006C000000000000F580000000000188000FFD458 +:1006D000000000000A640000000000000AE50000BD +:1006E000000000090B66FFFF000000000D61000024 +:1006F00000000000026200000000000B2FDF00027B +:10070000000000003104000000000000309A0000EA +:10071000000000090560000F00000010B18A000A07 +:100720000000000005634C0000000008050A0012EC +:1007300000000010B9621403000000000300000074 +:100740000000001880000005000000188000FF2451 +:1007500000000010B60614030000000803060001A4 +:10076000000000188000FF2A000000000C9618000E +:10077000000000090C99FFFF00000004CC99340030 +:1007800000000010B1963202000000080F80000047 +:100790000000000C298000010000000C295200011B +:1007A0000000000C29520000000000080200000EAA +:1007B000000000080280001A00000010B1C40A0204 +:1007C00000000008020000030000000822000001F1 +:1007D0000000000C1F800001000000002ADF000064 +:1007E000000000002A000800000000080500555520 +:1007F000000000188000FF180000000B2FDF00022F +:100800000000001091D40000000000082A00000140 +:10081000000000002C2000000000001091D4000017 +:10082000000000082C800000000000082D000000DF +:10083000000000082D80011C000000188000FFA3AC +:10084000000000082C800006000000082D000006B3 +:1008500000000000308000000000000031000000B7 +:10086000000000082D8000060000000C2980000117 +:100870000000000C1F8000010000001091DE00004D +:10088000000000002ADF0000000000082A0000101D +:100890000000000005000000000000188000FF03B9 +:1008A0000000001091A0B009000000082C80010D8C +:1008B000000000082D0000090000001091D4000085 +:1008C000000000082D800107000000188000FF9C38 +:1008D000000000188000001000000008AC000001BB +:1008E000000000188000000B000000000380B00032 +:1008F0000000000B2FDF0002000000002C00400071 +:100900000000001091D400000000000806005555BA +:10091000000000188000FF7E0000001880000031F9 +:1009200000000018800000060000000B2FDF00020E +:10093000000000002C000E00000000082A00000744 +:100940000000000805005555000000188000FEED6D +:1009500000000000068200000000000C2980000159 +:100960000000000C1F800001000000100CE70007D1 +:10097000000000090562FFFF00000010BA6C1405BA +:10098000000000002ADF000000000000210000003D +:10099000000000082A0000050000001091D40000AB +:1009A000000000082C80010C000000082D00000849 +:1009B0000000000C31620018000000082D800001CA +:1009C000000000188000FF7200000018000D0000F9 +:1009D00000000010B1A0B00E0000000B2FDF0002DD +:1009E0000000000003D80000000000002C200000E0 +:1009F0000000001091D400000000001880000015D5 +:100A0000000000102C620002000000188000000CA2 +:100A10000000000B2FDF0002000000002C07000088 +:100A20000000000C1F8000010000001091DE00009B +:100A3000000000080500FFFF000000188000FECF46 +:100A4000000000082C80010D000000082D000009A6 +:100A50000000001091D40000000000082D80010764 +:100A6000000000188000FF690000000C29800001D0 +:100A70000000000C1F8000010000001091DE00004B +:100A8000000000002ADF0000000000082A00000A21 +:100A90000000000005000000000000188000FEC3F8 +:100AA0000000000006820000000000082C80010CFD +:100AB000000000082D000008000000082D8001340F +:100AC000000000000000000000000010205F000097 +:100AD000000000082C800140000000082D00003CB0 +:100AE000000000082D80012400000000000000002C +:100AF0000000001091DE0000000000082C80008043 +:100B0000000000082D000000000000082D800105F5 +:100B100000000010BEE20005000000188000FEACDE +:100B2000000000010562140000000010918A00021C +:100B300000000008B16200010000001091DE00001A +:100B400000000018000D00000000001091D400000B +:100B5000000000080600AAAA000000188000FF3567 +:100B60000000000C298000010000000C1F80000123 +:100B7000000000082A000009000000080500AAAAD9 +:100B8000000000188000FEA60000001091D40000B4 +:100B90000000000806005555000000188000FF2DD9 +:100BA0000000001091A03C0200000010B1E66207B6 +:100BB0000000000B2FDF0002000000002C310000BD +:100BC000000000092CB1007F000000082CD90000B3 +:100BD000000000082D000000000000082D80010D1D +:100BE00000000010B1A8000600000010205F000007 +:100BF000000000002C200000000000002CA70000D6 +:100C0000000000082D000010000000082D800108E1 +:100C1000000000188000FF2800000010B1A600109E +:100C200000000010001F00000000000F0F30000740 +:100C3000000000000A600000000000000AE100005F +:100C40000000000F4B620008000000090B1600FFB7 +:100C5000000000000D620000000000090D1A00FFF6 +:100C600000000010073000030000000C0D1A0008FF +:100C70000000000C0B1600080000000F4CE30018E9 +:100C8000000000000C992C0000000004CC993400F6 +:100C9000000000080F8000000000000C2980000107 +:100CA00000000000333100000000000822000016A0 +:100CB000000000002ADF0000000000082A00000CED +:100CC00000000010009F0000000000000F20000046 +:100CD0000000000C1F8000010000000805005555B1 +:100CE000000000188000FE7A0000001091D400007F +:100CF000000000080600AAAA000000188000FF01FA +:100D00000000000F4722000800000009070E000F36 +:100D100000000008070E0008000000080280000123 +:100D20000000000702851C00000000088285000109 +:100D30000000000002854C000000000742851C00F6 +:100D400000000003C3AA52000000000003B10E001F +:100D5000000000074B071C000000000F0F300007C9 +:100D60000000000F0A960003000000000A955C00D6 +:100D7000000000004A005A00000000000C960A0023 +:100D8000000000090C99FFFF000000080D00FFFFA4 +:100D900000000010B1963202000000080F8000052C +:100DA00000000010B1A8000800000010205F000043 +:100DB0000000000B2FDF0002000000002C200000CC +:100DC000000000002CA70000000000082D0000100B +:100DD000000000082D800108000000188000FEEFD0 +:100DE0000000000C2980000100000010001F00001E +:100DF0000000000C1F800001000000002ADF00003E +:100E0000000000082A00000D000000080500AAAA42 +:100E1000000000188000FE540000001091D4000073 +:100E20000000000806005555000000188000FEDB99 +:100E30000000000C298000010000000C1F80000150 +:100E4000000000082A0000070000000805005555B2 +:080E5000000000188000FE4CB8 +:080E580000000010B18000044D +:100E60000000001F0503030000000008050000FF4C +:100E70000000001800020000000000002A0000002E +:100E800000000010B1D400000000001091DE00004E +:100E9000000000102053000000000010001F0000A0 +:100EA000000000002F80AA000000000C2980000133 +:100EB000000000080254000E000000002C4000005A +:100EC000000000092952003F000000180004000043 +:100ED00000000018800000100000001880000011C1 +:100EE000000000188000003900000018800000FD9C +:100EF00000000018800000FC00000018800000FBCB +:100F000000000018800000FB0000001880000000B6 +:100F1000000000188000011300000018800000F796 +:100F2000000000188000000B00000018800001176E +:100F300000000018800001650000001880000063B8 +:100F400000000018800000CE00000018800000DEC5 +:100F5000000000002A000000000000188000FFE5EB +:100F6000000000002A0000000000000C29800000A2 +:100F7000000000188000FFE2000000002A000000CE +:100F8000000000188000FFE00000001800020000D0 +:100F900000000000050200000000001091963421BE +:100FA00000000010205F0000000000002C1E000068 +:100FB000000000082C800006000000082D0000063C +:100FC000000000082D800102000000000000000069 +:100FD0000000001091DE0000000000000D61000024 +:100FE00000000018000A00000000000005020000D8 +:100FF000000000109196341600000010205F0000E1 +:101000000000000009D80000000000002C1E0000B5 +:10101000000000082C80010E000000082D00000ACE +:10102000000000082D800102000000000000000008 +:101030000000001091DE0000000000000D620000C2 +:10104000000000002C13000000000018000A00003F +:101050000000000005020000000000109196340915 +:1010600000000010205F0000000000002C1E0000A7 +:10107000000000082C800006000000082D00006A17 +:10108000000000082D8001020000000000000000A8 +:101090000000001091DE0000000000000D7A00004A +:1010A00000000018000A0000000000002A000000F4 +:1010B000000000000D61000000000000036200005D +:1010C00000000010234200C10000000002638C00F9 +:1010D0000000000026460000000000080204001284 +:1010E00000000010B9060827000000000F5800009B +:1010F000000000000A640000000000000AE5000093 +:10110000000000090B66FFFF000000000C0000005B +:10111000000000000B800000000000080CC6001258 +:10112000000000188000FFCE000000080F800003C0 +:10113000000000000000000000000010009F000000 +:101140000000000827110012000000006690000057 +:1011500000000008A31B001200000010B19800035B +:1011600000000010001F0000000000080F800004B5 +:101170000000000822000003000000082C80000C82 +:10118000000000082D00000C00000010009F00006F +:1011900000000000259600000000000C29800000DF +:1011A00000000000066600000000000086611800D4 +:1011B000000000090260000F0000000F020400029E +:1011C00000000010B60C08050000000C1FBF000056 +:1011D000000000102866000300000008078F0001CF +:1011E0000000000C33660010000000003214000004 +:1011F00000000000329500000000000573662C001E +:101200000000000031E32E00000000082D800010D7 +:10121000000000188000FF8E000000002300000086 +:101220000000000925E6FFFF000000082200000B77 +:101230000000000C695200000000000C2980000032 +:101240000000001028660075000000188000FF876D +:10125000000000002A000000000000082C80004070 +:10126000000000082D000020000000082D80011C57 +:1012700000000000000000000000001091DE0000EF +:101280000000000F42EA001000000010004F0004B0 +:1012900000000010B746920000000008024900124A +:1012A00000000010B5840A00000000000D6100007D +:1012B00000000010BA6634570000000883050012D1 +:1012C00000000010004F0002000000000349000071 +:1012D0000000000183068C000000000083C60C00A3 +:1012E00000000010B1870011000000000B6E00002C +:1012F00000000010BEE90005000000188000FF6E2D +:10130000000000010569140000000010918A00022D +:1013100000000008B4E9000100000010B1E92C4A07 +:101320000000000086692C000000000002000000A0 +:101330000000000902EAFFFF00000010000C00029C +:101340000000000002040A000000000F460C00012B +:101350000000000F0285000100000010918C01FCCC +:1013600000000010B7040E41000000000F40000014 +:10137000000000000D610000000000000A64000091 +:10138000000000000AE50000000000090B66FFFFF6 +:10139000000000000C000000000000000B800000B6 +:1013A000000000080C860012000000080F800003F7 +:1013B0000000000C2952000000000010009F0000F7 +:1013C00000000008271100120000000066900000D5 +:1013D0000000000026460000000000002306000078 +:1013E00000000010B198000500000010001F000070 +:1013F000000000080F800004000000000000000052 +:1014000000000010001F0000000000003214000067 +:1014100000000000329500000000000031E32E00C3 +:101420000000000573662C000000000025960000F7 +:1014300000000010B18700160000000C2980000099 +:101440000000000F0F6B0007000000000D69000096 +:10145000000000000A6C0000000000000AED00001F +:10146000000000000B6E0000000000000B80000078 +:10147000000000000C870000000000080F8000033F +:1014800000000010205300000000000C6952000111 +:1014900000000010001F00000000000022C58C00AA +:1014A00000000000231B00000000000027110000C6 +:1014B000000000002690000000000010B8170E0386 +:1014C0000000000C29800000000000188000FFF6DA +:1014D00000000010B1980002000000080F80000416 +:1014E000000000082200001A000000082C80000CF8 +:1014F000000000082D00000C000000082D800010E6 +:1015000000000010001F0000000000000D6E000031 +:1015100000000003E7CF34000000000C2980000029 +:101520000000001091DE000000000010B1870007ED +:101530000000000036140000000000003695000096 +:101540000000000037160000000000082C8000504A +:10155000000000082D000030000000082D80000C65 +:10156000000000188000FF24000000002646000054 +:1015700000000000230000000000000925E6FFFF36 +:10158000000000000B6E000000000003E7CF2C00FD +:10159000000000082200001B0000000C695200003F +:1015A0000000000C29800000000000188000FF1BD4 +:1015B000000000002A00000000000010086600057E +:1015C00000000000066600000000000086611800B0 +:1015D00000000009026000F000000010B60C0802D4 +:1015E000000000188000FF140000000006820000C8 +:1015F00000000010B18F000000000008878F00017C +:101600000000000C73660010000000082C80001819 +:10161000000000082D000018000000082D800002C6 +:101620000000000C5FBF00000000001091DE000011 +:1016300000000018000D0000000000002A0000005B +:1016400000000010286601F5000000082C8000034F +:10165000000000082D000003000000093060FFF0CA +:10166000000000082D8000010000000C298000000F +:101670000000001091DE0000000000082C80001A1D +:10168000000000082D00001A00000005736600002D +:10169000000000082D8000020000000031800000E2 +:1016A0000000001091DE0000000000082C80000CFB +:1016B000000000082D00000C000000082D80000430 +:1016C000000000188000FEF8000000180002000072 +:1016D000000000188000FEF6000000002A00000054 +:1016E00000000010001F0000000000000F0080003C +:1016F000000000080F800007000000188000001A9A +:1017000000000000280A00000000000005020000A0 +:10171000000000082200000900000000290000006D +:101720000000000F6568001000000003F66C9400D4 +:1017300000000010B972A0040000000C73E700194B +:101740000000000C21420004000000003CF80000F2 +:101750000000000C29800000000000102053000051 +:1017600000000008220000080000000C6142000494 +:1017700000000018000A0000000000000502000040 +:101780000000000C61420000000000100142000354 +:101790000000000C33E7001D0000000C6142000255 +:1017A00000000018000A0000000000002A000000ED +:1017B00000000010001F00000000000F0F4700078E +:1017C000000000080F8000080000000C29800000C5 +:1017D00000000010009F0000000000188000FED5EF +:1017E0000000000033510000000000002A0000004B +:1017F00000000010B1C600230000000F0F500007CA +:10180000000000000A600000000000000AE1000083 +:101810000000000F4B620008000000090B1600FFDB +:101820000000000F4C620010000000000D6200007C +:10183000000000090D1A00FF00000010075000030F +:101840000000000C0D1A00080000000C0B16000828 +:10185000000000000CC60000000000000B8000002B +:101860000000000006980000000000080F80000340 +:101870000000001006C200040000000C2900000255 +:1018800000000010264200020000000C2952000354 +:10189000000000082200000100000010009F00006E +:1018A00000000000231B00000000000027111A00A8 +:1018B00000000000669000000000000C29520000AB +:1018C00000000010B19732090000000C29800000D0 +:1018D00000000000069800000000001020530000E7 +:1018E0000000000C295200030000000022C58C00FB +:1018F00000000010001F0000000000080F8000031F +:10190000000000188000FFF300000010B1C80013B1 +:1019100000000010B1C600030000000C2980000088 +:1019200000000010205300000000000C29520000AD +:101930000000000C295200030000001006C2000243 +:101940000000000C295200020000000022C58C009B +:1019500000000000276500000000000026E40000F1 +:10196000000000082200001600000010B1C60003AD +:10197000000000002348000000000010B1800005B6 +:1019800000000000234800000000000C2980000037 +:101990000000000F0F500007000000188000001228 +:1019A00000000008220000160000000C2980000042 +:1019B000000000003014000000000000309500001E +:1019C0000000001007500003000000090B1600FF84 +:1019D000000000090D1A00FF0000000F311600087A +:1019E000000000003162340000000003F1623000AA +:1019F00000000010205F0000000000002C510000DB +:101A0000000000092CD1007F000000082CD9000044 +:101A1000000000082D000000000000082D80000CD0 +:101A200000000000000000000000001091DE000037 +:101A30000000001005C20004000000080F8000072D +:101A4000000000003300000000000010009F0000B4 +:101A5000000000188000FE86000000002A00000040 +:101A60000000000F0F50000700000010B1C6002D4D +:101A70000000000F4742000800000009070E000F99 +:101A800000000008070E000800000010001F000002 +:101A900000000008090000010000000709121C00F6 +:101AA00000000003CBCA9200000000000B97A200C8 +:101AB0000000000742171C00000000000B0400009B +:101AC0000000000F0A840003000000000A959C003B +:101AD000000000004A009A00000000088212000185 +:101AE000000000010C170800000000000C978C009B +:101AF0000000000002180000000000080D00FFFFB9 +:101B0000000000080F8000060000000C2900000003 +:101B10000000001006C200040000000C2952000260 +:101B200000000010264200020000000C29520003B1 +:101B3000000000082200000100000010009F0000CB +:101B400000000010B197320C00000000231B0000C1 +:101B5000000000002711080000000000669000004F +:101B60000000000C298000000000000002180000A6 +:101B700000000010205300000000000C2952000358 +:101B80000000000022C5360000000010001F000009 +:101B9000000000080F800006000000188000FFF41D +:101BA00000000000231B00000000000027110800B7 +:101BB000000000006690000000000010B1C8000B9B +:101BC0000000000C298000000000001020530000DD +:101BD0000000000C295200000000000C29520003F4 +:101BE0000000001006C200020000000C2952000292 +:101BF0000000000022C58C000000000027650000E6 +:101C00000000000026E4000000000000234800005F +:101C100000000008220000170000000C29800000CE +:101C200000000010001F0000000000188000FE4BA4 +:00000001FF +/* + * This file contains firmware data derived from proprietary unpublished + * source code, Copyright (c) 2004 - 2009 Broadcom Corporation. + * + * Permission is hereby granted for the distribution of this firmware data + * in hexadecimal or equivalent format, provided this copyright notice is + * accompanying it. + */ diff --git a/firmware/bnx2/bnx2-rv2p-09ax-5.0.0.j3.fw.ihex b/firmware/bnx2/bnx2-rv2p-09ax-5.0.0.j3.fw.ihex new file mode 100644 index 0000000..533dbea --- /dev/null +++ b/firmware/bnx2/bnx2-rv2p-09ax-5.0.0.j3.fw.ihex @@ -0,0 +1,498 @@ +:100000000000000000000E78000000580000000909 +:1000100000000000000000000000000000000000E0 +:1000200000000000000000000000000000000000D0 +:1000300000000FA800000ED0000000050000000026 +:1000400000000000000000000000000000000000B0 +:080050000000000000000000A8 +:0800580000000010B180000659 +:100060000000001F03030300000000080500FFFF5D +:10007000000000180002000000000008050000FF5A +:10008000000000180002000000000008AC000001A1 +:1000900000000000050000000000000C2F8000019F +:1000A000000000002B000000000000002B8000007A +:1000B0000000001091E0000200000008AC00000108 +:1000C00000000010203F006B00000010213F0003E3 +:1000D0000000001020BF003A000000188000FFFD63 +:1000E00000000010B1B8B0150000000B2FDF0002B7 +:1000F0000000000003D80000000000002C380000C1 +:10010000000000082C800000000000082D00000006 +:100110000000001091D400000000000806005555B2 +:10012000000000188000008F000000082D80011CD6 +:1001300000000008020000010000001091DE000035 +:100140000000000F42E0001C0000001091840A161D +:1001500000000018800000960000000C29800002BA +:100160000000000C1F800002000000002ADF0000D9 +:10017000000000082A00000F000000000500000039 +:10018000000000188000FFE60000000802000001E7 +:100190000000000F42E0001C0000001091840A18CB +:1001A000000000082C800006000000082D0000065A +:1001B0000000001091D40000000000082D8001060E +:1001C0000000001880000085000000188000FFF18A +:1001D00000000008B1000001000000082C80010CA4 +:1001E000000000082D000008000000082D8000011C +:1001F000000000188000007F0000000B2FDF0002CD +:100200000000000C1F800002000000002C0700000E +:100210000000001091DE00000000000805005555A8 +:10022000000000188000FFD20000000B2FDF00024A +:100230000000000C1F800000000000002C070000E0 +:100240000000001091DE0000000000080500555578 +:10025000000000188000FFCC0000000C1F8000028E +:100260000000000805005555000000188000FFC977 +:100270000000000C298000020000000C1F8000021A +:10028000000000002ADF0000000000082A0000052E +:100290000000000805005555000000188000FFC34D +:1002A000000000080224004A0000001800040000BA +:1002B000000000188000001C000000188000001ED4 +:1002C000000000188000007800000018800000CABC +:1002D00000000018800000C9000000188000000025 +:1002E00000000018800000000000001880000000DE +:1002F00000000018800000000000001880000000CE +:1003000000000018800000000000001880000000BD +:100310000000001880000000000000188000011597 +:10032000000000188000000000000018800000009D +:100330000000001880000015000000188000001B5D +:10034000000000188000000000000018800000E09D +:10035000000000188000002F000000188000011528 +:100360000000001880000140000000188000010B10 +:100370000000001880000164000000188000006187 +:100380000000001880000000000000188000009DA0 +:100390000000000C1F8000010000000005000000AC +:1003A000000000188000FFA20000001091D400009F +:1003B0000000000C298000010000000C1F800001DB +:1003C000000000082A0000020000000005000000F4 +:1003D000000000188000FF9C0000001091D4000075 +:1003E0000000000C298000010000000C1F800001AB +:1003F0000000000029420000000000082A0000025E +:100400000000000005000000000000188000FF95BB +:10041000000000188000FF9400000010B1BCB00A7A +:100420000000000B2FDF00020000000003D80000D6 +:10043000000000002C3C00000000001091D40000DF +:100440000000000806005555000000188000002A32 +:1004500000000018800000D9000000102C6201BAD2 +:100460000000001880000006000000082C80010D2C +:10047000000000082D0000090000001091D40000C9 +:10048000000000082D8001070000001880000037E0 +:100490000000000C298000000000000C1F800000FC +:1004A0000000001091DE0000000000002ADF0000C4 +:1004B000000000082A00000600000008050055554D +:1004C000000000188000FF7E0000001091D40000A2 +:1004D0000000000C298000010000000C1F800001BA +:1004E000000000082A00000B0000000005000000CA +:1004F000000000188000FF780000000002020000E9 +:1005000000000000029A000000000000060C2C0011 +:1005100000000004C60C340000000010001F0000A2 +:1005200000000010B196180C0000000806960004A8 +:1005300000000009068DFFFC00000004CD051A0034 +:1005400000000004CC9A18000000001020D7000022 +:100550000000000C2B56000000000000000000000E +:1005600000000000000000000000001020D7000084 +:10057000000000080F80000100000010B18001F4AD +:1005800000000010001F00000000000C6B5600006F +:1005900000000018000400000000000006820000B7 +:1005A00000000010B18A000800000010B18C140790 +:1005B0000000000B050AFFFF00000010B18A0003D5 +:1005C00000000000860A180000000010918C000056 +:1005D000000000082A0000010000001091D4000073 +:1005E00000000018000D00000000000005020000DF +:1005F0000000001091DE000000000018000A00005A +:1006000000000000068200000000001091DE0000E3 +:1006100000000010BEE10005000000188000FF4C43 +:10062000000000010561140000000010918A000222 +:1006300000000008B0E1000100000018000D0000FB +:1006400000000000068200000000001091DE0000A3 +:1006500000000010BEE20005000000188000FF440A +:10066000000000010562140000000010918A0002E1 +:1006700000000008B162000100000018000D000039 +:1006800000000010B1A0B0130000000B2FDF00022B +:10069000000000002C200000000000082C8000005A +:1006A000000000082D0000000000001091D40000A0 +:1006B0000000000806005555000000188000FFDC0F +:1006C000000000082D80011C00000010001F000029 +:1006D000000000188000FFE60000000F47600008DF +:1006E0000000000F060E0001000000000F5800007F +:1006F000000000000A640000000000000AE500009D +:10070000000000090B66FFFF000000000D61000003 +:1007100000000018800000130000000F4760000870 +:100720000000000B2FDF0002000000082C800000FA +:10073000000000082D0000000000001091D400000F +:10074000000000082D80011C0000000F060E0001B3 +:1007500000000010001F0000000000000F58000003 +:10076000000000188000FFD4000000000A640000B0 +:10077000000000000AE50000000000090B66FFFF12 +:10078000000000000D610000000000000262000097 +:100790000000000B2FDF0002000000003104000009 +:1007A00000000000309A0000000000090560000F02 +:1007B00000000010B18A000A0000000005634C0030 +:1007C00000000008050A001200000010B9621403BE +:1007D0000000000003000000000000188000000579 +:1007E000000000188000FF1100000010B60614037E +:1007F0000000000803060001000000188000FF1739 +:10080000000000188000FF9F0000000C29800001FC +:100810000000000C295200010000000C29520000C9 +:10082000000000080200000E000000080280001A0C +:1008300000000010B1C40A0200000008020000031A +:1008400000000008220000010000000C1F800001D1 +:10085000000000002ADF0000000000002A0008005D +:100860000000000805005555000000188000FF0931 +:100870000000000B2FDF00020000001091D40000E8 +:10088000000000082A000001000000002C200000E9 +:100890000000001091D40000000000082C8000002F +:1008A000000000082D000000000000082D80011C41 +:1008B000000000188000FFA7000000082C80000640 +:1008C000000000082D00000600000000308000003D +:1008D0000000000031000000000000082D8000062C +:1008E0000000000C298000010000000C1F800001A6 +:1008F0000000001091DE0000000000002ADF000070 +:10090000000000082A0000100000000005000000A0 +:10091000000000188000FEF40000001091A0B00953 +:10092000000000082C80010D000000082D000009C7 +:100930000000001091D40000000000082D80010785 +:10094000000000188000FFA00000001880000010C8 +:1009500000000008AC000001000000188000000B3F +:10096000000000000380B0000000000B2FDF000239 +:10097000000000002C0040000000001091D4000096 +:100980000000000806005555000000188000FF8296 +:1009900000000018800000310000001880000006F0 +:1009A0000000000B2FDF0002000000002C000E00F2 +:1009B000000000082A000007000000080500555547 +:1009C000000000188000FEDE00000000068200002B +:1009D0000000000C298000010000000C1F800001B5 +:1009E000000000100CE70007000000090562FFFF8F +:1009F00000000010BA6C1405000000002ADF00009F +:100A00000000000021000000000000082A0000058E +:100A10000000001091D40000000000082C80010CA0 +:100A2000000000082D0000080000000C31620018D2 +:100A3000000000082D800001000000188000FF76F3 +:100A400000000018000D000000000010B1A0B00E62 +:100A50000000000B2FDF00020000000003D80000A0 +:100A6000000000002C2000000000001091D40000C5 +:100A70000000001880000015000000102C62000229 +:100A8000000000188000000C0000000B2FDF0002A7 +:100A9000000000002C0700000000000C1F80000177 +:100AA0000000001091DE0000000000080500FFFFBC +:100AB000000000188000FEC0000000082C80010D1E +:100AC000000000082D0000090000001091D4000073 +:100AD000000000082D800107000000188000FF6D55 +:100AE0000000000C298000010000000C1F800001A4 +:100AF0000000001091DE0000000000002ADF00006E +:100B0000000000082A00000A0000000005000000A4 +:100B1000000000188000FEB4000000000682000003 +:100B2000000000082C80010C000000082D000008C7 +:100B3000000000082D8001340000000000000000CB +:100B400000000010205F0000000000082C80014021 +:100B5000000000082D00003C000000082D80011C52 +:100B600000000000000000000000001091DE000006 +:100B7000000000082C800080000000082D0000000C +:100B8000000000082D80010500000010BEE20005F5 +:100B9000000000188000FE9D0000000105621400A6 +:100BA00000000010918A000200000008B1620001FC +:100BB0000000001091DE000000000018000D000091 +:100BC0000000001091D40000000000080600AAAA4E +:100BD000000000188000FF390000000C298000018F +:100BE0000000000C1F800001000000082A0000091E +:100BF000000000080500AAAA000000188000FE9767 +:100C00000000001091D400000000000806005555B7 +:100C1000000000188000FF310000001091A03C028D +:100C200000000010B1E662070000000B2FDF000299 +:100C3000000000002C310000000000092CB1007FF2 +:100C4000000000082CD90000000000082D00000062 +:100C5000000000082D80010D00000010B1A8000662 +:100C600000000010205F0000000000002C200000A9 +:100C7000000000002CA70000000000082D0000105C +:100C8000000000082D800108000000188000FF2CE3 +:100C900000000010B1A6001000000010001F0000AE +:100CA0000000000F0F300007000000000A60000085 +:100CB000000000000AE100000000000F4B62000885 +:100CC000000000090B1600FF000000000D6200008C +:100CD000000000090D1A00FF00000010073000039B +:100CE0000000000C0D1A00080000000C0B16000894 +:100CF0000000000F4CE30018000000000C992C00CD +:100D000000000004CC993400000000080F800000AF +:100D10000000000C298000010000000033310000B9 +:100D20000000000822000016000000002ADF00007A +:100D3000000000082A00000C00000010009F0000C6 +:100D4000000000000F2000000000000C1F800001C8 +:100D50000000000805005555000000188000FE6BDB +:100D60000000001091D40000000000080600AAAAAC +:100D7000000000188000FF050000000F4722000857 +:100D800000000009070E000F00000008070E000811 +:100D900000000008028000010000000702851C001E +:100DA00000000008828500010000000002854C0060 +:100DB0000000000742851C0000000003C3AA520087 +:100DC0000000000003B10E00000000074B071C00EC +:100DD0000000000F0F3000070000000F0A9600030C +:100DE000000000000A955C00000000004A005A0064 +:100DF000000000000C960A00000000090C99FFFF9B +:100E0000000000080D00FFFF00000010B196320244 +:100E1000000000080F80000500000010B1A80008C5 +:100E200000000010205F00000000000B2FDF000218 +:100E3000000000002C200000000000002CA7000093 +:100E4000000000082D000010000000082D8001089F +:100E5000000000188000FEF30000000C2980000153 +:100E600000000010001F00000000000C1F800001A7 +:100E7000000000002ADF0000000000082A00000D2A +:100E8000000000080500AAAA000000188000FE4526 +:100E90000000001091D40000000000080600555525 +:100EA000000000188000FEDF0000000C2980000117 +:100EB0000000000C1F800001000000082A0000074D +:100EC0000000000805005555000000188000FE3D98 +:100ED00000000010B18000040000001F03030300A5 +:100EE00000000008050000FF0000001800020000DC +:100EF000000000002A00000000000010B1D4000033 +:100F00000000001091DE00000000001020530000DF +:100F100000000010001F00000000000C6BD7000153 +:100F2000000000002F80AA000000000C29800001B2 +:100F3000000000080254000F000000002C400000D8 +:100F4000000000092952003F0000001800040000C2 +:100F50000000001880000010000000188000001140 +:100F6000000000188000004A0000001880000128DE +:100F700000000018800001270000001880000126F2 +:100F8000000000188000012600000018800000000A +:100F9000000000188000013F0000001880000122BE +:100FA000000000188000000B0000001880000145C0 +:100FB000000000188000019A000000188000007BEB +:100FC00000000018800000F90000001880000109EE +:100FD000000000002A000000000000188000FFE46C +:100FE000000000002A0000000000000C2980000022 +:100FF000000000188000FFE1000000002A0000004F +:10100000000000188000FFDF0000000003820000E5 +:10101000000000188000FFDA000000010C16140028 +:10102000000000008C1814000000001091980003CC +:10103000000000080C96000200000010B1800003C0 +:10104000000000080C960001000000000C000000E9 +:10105000000000000D1900000000001020560000E4 +:101060000000000C2BD70001000000080F800001D9 +:10107000000000000000000000000010001F000041 +:101080000000000C6BD7000100000010011301F1FB +:10109000000000180007000000000000050200002A +:1010A000000000109196342100000010205F000025 +:1010B000000000002C1E0000000000082C8000062C +:1010C000000000082D000006000000082D8001022D +:1010D00000000000000000000000001091DE000091 +:1010E000000000000D61000000000018000A000070 +:1010F0000000000005020000000000109196341668 +:1011000000000010205F00000000000009D800006F +:10111000000000002C1E0000000000082C80010EC2 +:10112000000000082D00000A000000082D800102C8 +:1011300000000000000000000000001091DE000030 +:10114000000000000D620000000000002C130000F1 +:1011500000000018000A0000000000000502000066 +:10116000000000109196340900000010205F00007C +:10117000000000002C1E0000000000082C8000066B +:10118000000000082D00006A000000082D80010208 +:1011900000000000000000000000001091DE0000D0 +:1011A000000000000D7A000000000018000A000096 +:1011B000000000002A000000000000000D61000097 +:1011C000000000000362000000000010234200DB6A +:1011D0000000000002638C000000000026460000B2 +:1011E000000000080204001200000010B906082EDA +:1011F000000000000F580000000000000A6400001A +:10120000000000000AE50000000000090B66FFFF77 +:10121000000000000C000000000000000B80000037 +:10122000000000080CC60012000000188000FFCE6D +:1012300000000010205600000000000C2BD7000119 +:10124000000000080F800003000000000000000004 +:1012500000000010001F00000000000C6BD7000110 +:101260000000000827110012000000006690000036 +:1012700000000008A31B001200000010B198000637 +:1012800000000010001F00000000000C6BD70001E0 +:1012900000000010205600000000000C2BD70001B9 +:1012A000000000080F800004000000082200000376 +:1012B000000000082C80000C000000082D00000C2D +:1012C00000000010001F00000000000C6BD70001A0 +:1012D00000000000259600000000000C298000009E +:1012E0000000000006660000000000008661180093 +:1012F000000000090260000F0000000F020400025D +:1013000000000010B60C08050000000C1FBF000014 +:10131000000000102866000300000008078F00018D +:101320000000000C336600100000000032140000C2 +:1013300000000000329500000000000573662C00DC +:101340000000000031E32E00000000082D80001096 +:10135000000000188000FF7500000000230000005E +:101360000000000925E6FFFF000000082200000B36 +:101370000000000C695200000000000C29800000F1 +:101380000000001028660088000000188000FF6E32 +:10139000000000002A000000000000082C8000402F +:1013A000000000082D000020000000082D80011C16 +:1013B00000000000000000000000001091DE0000AE +:1013C0000000000F42EA001000000010004F00046F +:1013D00000000010B7469200000000080249001209 +:1013E00000000010B5840A00000000000D6100003C +:1013F00000000010BA66346A00000008830500127D +:1014000000000010004F000200000000034900002F +:101410000000000183068C000000000083C60C0061 +:1014200000000010B1870011000000000B6E0000EA +:1014300000000010BEE90005000000188000FF5504 +:10144000000000010569140000000010918A0002EC +:1014500000000008B4E9000100000010B1E92C5DB3 +:101460000000000086692C0000000000020000005F +:101470000000000902EAFFFF00000010000C00025B +:101480000000000002040A000000000F460C0001EA +:101490000000000F0285000100000010918C01FC8B +:1014A00000000010B7040E54000000000F400000C0 +:1014B000000000000D610000000000000A64000050 +:1014C000000000000AE50000000000090B66FFFFB5 +:1014D000000000000C000000000000000B80000075 +:1014E000000000080C8600120000001020560000CA +:1014F0000000000C2BD70001000000080F80000343 +:101500000000000C2952000000000010001F000025 +:101510000000000C6BD7000100000008271100122A +:101520000000000066900000000000002646000059 +:10153000000000002306000000000010B198000920 +:1015400000000010001F00000000000C6BD700011D +:1015500000000010205600000000000C2BD70001F6 +:10156000000000080F8000040000000000000000E0 +:1015700000000010001F00000000000C6BD70001ED +:10158000000000003214000000000000329500004E +:101590000000000031E32E000000000573662C00FF +:1015A000000000002596000000000010B187002117 +:1015B0000000000C298000000000000F0F6B0007E6 +:1015C000000000000D690000000000000A6C00002F +:1015D000000000000AED0000000000000B6E00009B +:1015E000000000000B800000000000000C870000DD +:1015F000000000188000FF1E000000010C161400FF +:10160000000000008C181400000000080C96000177 +:101610000000001091980002000000080C990001E1 +:10162000000000000D190000000000000C00000088 +:1016300000000010205600000000000C2BD7000115 +:10164000000000080F80000100000010205300007F +:101650000000000C6952000100000010001F000093 +:101660000000000C6BD700010000000022C58C00B8 +:1016700000000000231200000000000027110000FD +:10168000000000002690000000000010B8170E03B4 +:101690000000000C29800000000000188000FFEB13 +:1016A0000000000082970E0000000000A3120A0054 +:1016B000000000082200001A000000082C80000C26 +:1016C000000000082D00000C000000082D80001014 +:1016D00000000010001F00000000000C6BD700018C +:1016E000000000000D6E000000000003E7CF340092 +:1016F0000000000C298000000000001091DE0000B6 +:1017000000000010B1870007000000003614000040 +:1017100000000000369500000000000037160000B1 +:10172000000000082C800050000000082D00003050 +:10173000000000082D80000C000000188000FEF85A +:10174000000000002646000000000000230000000A +:101750000000000925E6FFFF000000000B6E0000FE +:1017600000000003E7CF2C00000000082200001B4F +:101770000000000C695200000000000C29800000ED +:10178000000000188000FEEF000000002A000000AA +:10179000000000100866000500000000066600005A +:1017A000000000008661180000000009026000F0DF +:1017B00000000010B60C0802000000188000FEE8CF +:1017C000000000000682000000000010B18F000041 +:1017D00000000008878F00010000000C73660010F5 +:1017E000000000082C800018000000082D000018E0 +:1017F000000000082D8000020000000C5FBF000008 +:101800000000001091DE000000000018000D000034 +:10181000000000002A00000000000010286601F50A +:10182000000000082C800003000000082D000003C9 +:10183000000000093060FFF0000000082D8000016A +:101840000000000C298000000000001091DE000064 +:10185000000000082C80001A000000082D00001A6B +:101860000000000573660000000000082D800002E3 +:1018700000000000318000000000001091DE000038 +:10188000000000082C80000C000000082D00000C57 +:10189000000000082D800004000000188000FECC2D +:1018A0000000001800020000000000188000FECABE +:1018B000000000002A00000000000010001F0000CF +:1018C0000000000C6BD70001000000000F0080003A +:1018D000000000080F800007000000188000001BB7 +:1018E00000000000280A00000000000005020000BF +:1018F000000000082200000900000000290000008C +:101900000000000F6568001000000003F66C9400F2 +:1019100000000010B972A0040000000C73E7001969 +:101920000000000C21420004000000003CF8000010 +:101930000000000C2980000000000010205300006F +:1019400000000008220000080000000C61420004B2 +:1019500000000018000A000000000000050200005E +:101960000000000C61420000000000100142000372 +:101970000000000C33E7001D0000000C6142000273 +:1019800000000018000A0000000000002A0000000B +:1019900000000010001F00000000000C6BD70001C9 +:1019A0000000000F0F470007000000080F8000082C +:1019B0000000000C2980000000000010001F000043 +:1019C0000000000C6BD70001000000188000FEA68C +:1019D0000000000033510000000000002A00000059 +:1019E00000000010B1C600290000000F0F500007D2 +:1019F000000000000A600000000000000AE1000092 +:101A00000000000F4B620008000000090B1600FFE9 +:101A10000000000F4C620010000000000D6200008A +:101A2000000000090D1A00FF00000010075000031D +:101A30000000000C0D1A00080000000C0B16000836 +:101A4000000000000CC60000000000000B80000039 +:101A50000000000006980000000000102056000062 +:101A60000000000C2BD70001000000080F800003CD +:101A70000000001006C200040000000C2900000253 +:101A800000000010264200020000000C2952000352 +:101A9000000000082200000100000010001F0000EC +:101AA0000000000C6BD7000100000000231B0000A9 +:101AB0000000000027111A000000000066900000DE +:101AC0000000000C2952000000000010B197320CF9 +:101AD0000000000C298000000000000006980000B3 +:101AE00000000010205300000000000C29520003E9 +:101AF0000000000022C58C0000000010001F000044 +:101B00000000000C6BD70001000000102056000000 +:101B10000000000C2BD70001000000080F8000031C +:101B2000000000188000FFEF00000010B1C8001393 +:101B300000000010B1C600030000000C2980000066 +:101B400000000010205300000000000C295200008B +:101B50000000000C295200030000001006C2000221 +:101B60000000000C295200020000000022C58C0079 +:101B700000000000276500000000000026E40000CF +:101B8000000000082200001600000010B1C600038B +:101B9000000000002348000000000010B180000594 +:101BA00000000000234800000000000C2980000015 +:101BB0000000000F0F500007000000188000001206 +:101BC00000000008220000160000000C2980000020 +:101BD00000000000301400000000000030950000FC +:101BE0000000001007500003000000090B1600FF62 +:101BF000000000090D1A00FF0000000F3116000858 +:101C0000000000003162340000000003F162300087 +:101C100000000010205F0000000000002C510000B8 +:101C2000000000092CD1007F000000082CD9000022 +:101C3000000000082D000000000000082D80000CAE +:101C400000000000000000000000001091DE000015 +:101C50000000001005C20005000000080F8000070A +:101C6000000000003300000000000010001F000012 +:101C70000000000C6BD70001000000188000FE502F +:101C8000000000002A0000000000000F0F500007B5 +:101C900000000010B1C600300000000F47420008ED +:101CA00000000009070E000F00000008070E0008E2 +:101CB00000000010001F00000000000C6BD70001A6 +:101CC00000000008090000010000000709121C00C4 +:101CD00000000003CBCA9200000000000B97A20096 +:101CE0000000000742171C00000000000B04000069 +:101CF0000000000F0A840003000000000A959C0009 +:101D0000000000004A009A00000000088212000152 +:101D1000000000010C170800000000000C978C0068 +:101D20000000000002180000000000080D00FFFF86 +:101D3000000000080F8000060000000C29000000D1 +:101D40000000001006C200040000000C295200022E +:101D500000000010264200020000000C295200037F +:101D6000000000082200000100000010001F000019 +:101D70000000000C6BD7000100000010B197320D7D +:101D800000000000231B00000000000027110800D5 +:101D900000000000669000000000000C2980000098 +:101DA0000000000002180000000000102053000096 +:101DB0000000000C295200030000000022C536007C +:101DC00000000010001F00000000000C6BD7000195 +:101DD000000000080F800006000000188000FFF2DD +:101DE00000000000231B0000000000002711080075 +:101DF000000000006690000000000010B1C8000B59 +:101E00000000000C2980000000000010205300009A +:101E10000000000C295200000000000C29520003B1 +:101E20000000001006C200020000000C295200024F +:101E30000000000022C58C000000000027650000A3 +:101E40000000000026E4000000000000234800001D +:101E500000000008220000170000000C298000008C +:101E600000000010001F00000000000C6BD70001F4 +:081E7000000000188000FE11C3 +:00000001FF +/* + * This file contains firmware data derived from proprietary unpublished + * source code, Copyright (c) 2004 - 2009 Broadcom Corporation. + * + * Permission is hereby granted for the distribution of this firmware data + * in hexadecimal or equivalent format, provided this copyright notice is + * accompanying it. + */ -- cgit v0.10.2 From 31ce8c71a3bdab12debb5899b1f6dac13e54c71d Mon Sep 17 00:00:00 2001 From: David Ward Date: Sat, 29 Aug 2009 00:04:09 -0700 Subject: ipv6: Update Neighbor Cache when IPv6 RA is received on a router When processing a received IPv6 Router Advertisement, the kernel creates or updates an IPv6 Neighbor Cache entry for the sender -- but presently this does not occur if IPv6 forwarding is enabled (net.ipv6.conf.*.forwarding = 1), or if IPv6 Router Advertisements are not accepted (net.ipv6.conf.*.accept_ra = 0), because in these cases processing of the Router Advertisement has already halted. This patch allows the Neighbor Cache to be updated in these cases, while still avoiding any modification to routes or link parameters. This continues to satisfy RFC 4861, since any entry created in the Neighbor Cache as the result of a received Router Advertisement is still placed in the STALE state. Signed-off-by: David Ward Signed-off-by: David S. Miller diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 1ba42bd..44b4c87 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1151,10 +1151,6 @@ static void ndisc_router_discovery(struct sk_buff *skb) skb->dev->name); return; } - if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) { - in6_dev_put(in6_dev); - return; - } if (!ndisc_parse_options(opt, optlen, &ndopts)) { in6_dev_put(in6_dev); @@ -1163,6 +1159,10 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } + /* skip route and link configuration on routers */ + if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) + goto skip_linkparms; + #ifdef CONFIG_IPV6_NDISC_NODETYPE /* skip link-specific parameters from interior routers */ if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) @@ -1283,9 +1283,7 @@ skip_defrtr: } } -#ifdef CONFIG_IPV6_NDISC_NODETYPE skip_linkparms: -#endif /* * Process options. @@ -1312,6 +1310,10 @@ skip_linkparms: NEIGH_UPDATE_F_ISROUTER); } + /* skip route and link configuration on routers */ + if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) + goto out; + #ifdef CONFIG_IPV6_ROUTE_INFO if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { struct nd_opt_hdr *p; -- cgit v0.10.2 From fd3ae5e8fc5e947a9f151e80a65763a24b6368a9 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Tue, 18 Aug 2009 21:55:59 +0000 Subject: Speed-up pfifo_fast lookup using a private bitmap Maintain a per-qdisc bitmap for pfifo_fast giving availability of skbs for each band. This allows faster lookup for a skb when there are no high priority skbs. Also, it helps in (rare) cases when there are no skbs on the list, where an immediate lookup is faster than iterating through the three bands. Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 693df7a..6f7aebd 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -406,18 +406,38 @@ static const u8 prio2band[TC_PRIO_MAX+1] = #define PFIFO_FAST_BANDS 3 -static inline struct sk_buff_head *prio2list(struct sk_buff *skb, - struct Qdisc *qdisc) +/* + * Private data for a pfifo_fast scheduler containing: + * - queues for the three band + * - bitmap indicating which of the bands contain skbs + */ +struct pfifo_fast_priv { + u32 bitmap; + struct sk_buff_head q[PFIFO_FAST_BANDS]; +}; + +/* + * Convert a bitmap to the first band number where an skb is queued, where: + * bitmap=0 means there are no skbs on any band. + * bitmap=1 means there is an skb on band 0. + * bitmap=7 means there are skbs on all 3 bands, etc. + */ +static const int bitmap2band[] = {-1, 0, 1, 0, 2, 0, 1, 0}; + +static inline struct sk_buff_head *band2list(struct pfifo_fast_priv *priv, + int band) { - struct sk_buff_head *list = qdisc_priv(qdisc); - return list + prio2band[skb->priority & TC_PRIO_MAX]; + return priv->q + band; } static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc) { - struct sk_buff_head *list = prio2list(skb, qdisc); + int band = prio2band[skb->priority & TC_PRIO_MAX]; + struct pfifo_fast_priv *priv = qdisc_priv(qdisc); + struct sk_buff_head *list = band2list(priv, band); if (skb_queue_len(list) < qdisc_dev(qdisc)->tx_queue_len) { + priv->bitmap |= (1 << band); qdisc->q.qlen++; return __qdisc_enqueue_tail(skb, qdisc, list); } @@ -427,14 +447,18 @@ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc) static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc) { - int prio; - struct sk_buff_head *list = qdisc_priv(qdisc); + struct pfifo_fast_priv *priv = qdisc_priv(qdisc); + int band = bitmap2band[priv->bitmap]; - for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { - if (!skb_queue_empty(list + prio)) { - qdisc->q.qlen--; - return __qdisc_dequeue_head(qdisc, list + prio); - } + if (likely(band >= 0)) { + struct sk_buff_head *list = band2list(priv, band); + struct sk_buff *skb = __qdisc_dequeue_head(qdisc, list); + + qdisc->q.qlen--; + if (skb_queue_empty(list)) + priv->bitmap &= ~(1 << band); + + return skb; } return NULL; @@ -442,12 +466,13 @@ static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc) static struct sk_buff *pfifo_fast_peek(struct Qdisc* qdisc) { - int prio; - struct sk_buff_head *list = qdisc_priv(qdisc); + struct pfifo_fast_priv *priv = qdisc_priv(qdisc); + int band = bitmap2band[priv->bitmap]; + + if (band >= 0) { + struct sk_buff_head *list = band2list(priv, band); - for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { - if (!skb_queue_empty(list + prio)) - return skb_peek(list + prio); + return skb_peek(list); } return NULL; @@ -456,11 +481,12 @@ static struct sk_buff *pfifo_fast_peek(struct Qdisc* qdisc) static void pfifo_fast_reset(struct Qdisc* qdisc) { int prio; - struct sk_buff_head *list = qdisc_priv(qdisc); + struct pfifo_fast_priv *priv = qdisc_priv(qdisc); for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) - __qdisc_reset_queue(qdisc, list + prio); + __qdisc_reset_queue(qdisc, band2list(priv, prio)); + priv->bitmap = 0; qdisc->qstats.backlog = 0; qdisc->q.qlen = 0; } @@ -480,17 +506,17 @@ nla_put_failure: static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt) { int prio; - struct sk_buff_head *list = qdisc_priv(qdisc); + struct pfifo_fast_priv *priv = qdisc_priv(qdisc); for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) - skb_queue_head_init(list + prio); + skb_queue_head_init(band2list(priv, prio)); return 0; } static struct Qdisc_ops pfifo_fast_ops __read_mostly = { .id = "pfifo_fast", - .priv_size = PFIFO_FAST_BANDS * sizeof(struct sk_buff_head), + .priv_size = sizeof(struct pfifo_fast_priv), .enqueue = pfifo_fast_enqueue, .dequeue = pfifo_fast_dequeue, .peek = pfifo_fast_peek, -- cgit v0.10.2 From 9a7030b76ab3c2b23b1629c49b6df33fb5aed305 Mon Sep 17 00:00:00 2001 From: John Dykstra Date: Wed, 19 Aug 2009 09:47:41 +0000 Subject: tcp: Remove redundant copy of MD5 authentication key Remove the copy of the MD5 authentication key from tcp_check_req(). This key has already been copied by tcp_v4_syn_recv_sock() or tcp_v6_syn_recv_sock(). Signed-off-by: John Dykstra Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index f8d67cc..6c8b422 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -657,29 +657,6 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL); if (child == NULL) goto listen_overflow; -#ifdef CONFIG_TCP_MD5SIG - else { - /* Copy over the MD5 key from the original socket */ - struct tcp_md5sig_key *key; - struct tcp_sock *tp = tcp_sk(sk); - key = tp->af_specific->md5_lookup(sk, child); - if (key != NULL) { - /* - * We're using one, so create a matching key on the - * newsk structure. If we fail to get memory then we - * end up not copying the key across. Shucks. - */ - char *newkey = kmemdup(key->key, key->keylen, - GFP_ATOMIC); - if (newkey) { - if (!tcp_alloc_md5sig_pool()) - BUG(); - tp->af_specific->md5_add(child, child, newkey, - key->keylen); - } - } - } -#endif inet_csk_reqsk_queue_unlink(sk, req, prev); inet_csk_reqsk_queue_removed(sk, req); -- cgit v0.10.2 From 8a27f7c90ffcb791eed7574922b51fb60b08fc89 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 17 Aug 2009 12:29:44 +0000 Subject: lib/vsprintf.c: Add "%pI6c" - print pointer as compressed ipv6 address Signed-off-by: Joe Perches Tested-by: Jens Rosenboom Signed-off-by: David S. Miller diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 756ccaf..cb8a112 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -25,6 +25,7 @@ #include #include #include +#include #include /* for PAGE_SIZE */ #include @@ -630,60 +631,156 @@ static char *resource_string(char *buf, char *end, struct resource *res, } static char *mac_address_string(char *buf, char *end, u8 *addr, - struct printf_spec spec) + struct printf_spec spec, const char *fmt) { - char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */ + char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")]; char *p = mac_addr; int i; for (i = 0; i < 6; i++) { p = pack_hex_byte(p, addr[i]); - if (!(spec.flags & SPECIAL) && i != 5) + if (fmt[0] == 'M' && i != 5) *p++ = ':'; } *p = '\0'; - spec.flags &= ~SPECIAL; return string(buf, end, mac_addr, spec); } -static char *ip6_addr_string(char *buf, char *end, u8 *addr, - struct printf_spec spec) +static char *ip4_string(char *p, const u8 *addr, bool leading_zeros) +{ + int i; + + for (i = 0; i < 4; i++) { + char temp[3]; /* hold each IP quad in reverse order */ + int digits = put_dec_trunc(temp, addr[i]) - temp; + if (leading_zeros) { + if (digits < 3) + *p++ = '0'; + if (digits < 2) + *p++ = '0'; + } + /* reverse the digits in the quad */ + while (digits--) + *p++ = temp[digits]; + if (i < 3) + *p++ = '.'; + } + + *p = '\0'; + return p; +} + +static char *ip6_compressed_string(char *p, const struct in6_addr *addr) { - char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */ - char *p = ip6_addr; int i; + int j; + int range; + unsigned char zerolength[8]; + int longest = 1; + int colonpos = -1; + u16 word; + u8 hi; + u8 lo; + bool needcolon = false; + bool useIPv4 = ipv6_addr_v4mapped(addr) || ipv6_addr_is_isatap(addr); + + memset(zerolength, 0, sizeof(zerolength)); + + if (useIPv4) + range = 6; + else + range = 8; + + /* find position of longest 0 run */ + for (i = 0; i < range; i++) { + for (j = i; j < range; j++) { + if (addr->s6_addr16[j] != 0) + break; + zerolength[i]++; + } + } + for (i = 0; i < range; i++) { + if (zerolength[i] > longest) { + longest = zerolength[i]; + colonpos = i; + } + } + + /* emit address */ + for (i = 0; i < range; i++) { + if (i == colonpos) { + if (needcolon || i == 0) + *p++ = ':'; + *p++ = ':'; + needcolon = false; + i += longest - 1; + continue; + } + if (needcolon) { + *p++ = ':'; + needcolon = false; + } + /* hex u16 without leading 0s */ + word = ntohs(addr->s6_addr16[i]); + hi = word >> 8; + lo = word & 0xff; + if (hi) { + if (hi > 0x0f) + p = pack_hex_byte(p, hi); + else + *p++ = hex_asc_lo(hi); + } + if (hi || lo > 0x0f) + p = pack_hex_byte(p, lo); + else + *p++ = hex_asc_lo(lo); + needcolon = true; + } + + if (useIPv4) { + if (needcolon) + *p++ = ':'; + p = ip4_string(p, &addr->s6_addr[12], false); + } + *p = '\0'; + return p; +} + +static char *ip6_string(char *p, const struct in6_addr *addr, const char *fmt) +{ + int i; for (i = 0; i < 8; i++) { - p = pack_hex_byte(p, addr[2 * i]); - p = pack_hex_byte(p, addr[2 * i + 1]); - if (!(spec.flags & SPECIAL) && i != 7) + p = pack_hex_byte(p, addr->s6_addr[2 * i]); + p = pack_hex_byte(p, addr->s6_addr[2 * i + 1]); + if (fmt[0] == 'I' && i != 7) *p++ = ':'; } + *p = '\0'; - spec.flags &= ~SPECIAL; + return p; +} + +static char *ip6_addr_string(char *buf, char *end, const u8 *addr, + struct printf_spec spec, const char *fmt) +{ + char ip6_addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; + + if (fmt[0] == 'I' && fmt[2] == 'c') + ip6_compressed_string(ip6_addr, (const struct in6_addr *)addr); + else + ip6_string(ip6_addr, (const struct in6_addr *)addr, fmt); return string(buf, end, ip6_addr, spec); } -static char *ip4_addr_string(char *buf, char *end, u8 *addr, - struct printf_spec spec) +static char *ip4_addr_string(char *buf, char *end, const u8 *addr, + struct printf_spec spec, const char *fmt) { - char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */ - char temp[3]; /* hold each IP quad in reverse order */ - char *p = ip4_addr; - int i, digits; + char ip4_addr[sizeof("255.255.255.255")]; - for (i = 0; i < 4; i++) { - digits = put_dec_trunc(temp, addr[i]) - temp; - /* reverse the digits in the quad */ - while (digits--) - *p++ = temp[digits]; - if (i != 3) - *p++ = '.'; - } - *p = '\0'; - spec.flags &= ~SPECIAL; + ip4_string(ip4_addr, addr, fmt[0] == 'i'); return string(buf, end, ip4_addr, spec); } @@ -702,11 +799,15 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, * addresses (not the name nor the flags) * - 'M' For a 6-byte MAC address, it prints the address in the * usual colon-separated hex notation - * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated - * decimal for v4 and colon separated network-order 16 bit hex for v6) - * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is - * currently the same - * + * - 'm' For a 6-byte MAC address, it prints the hex address without colons + * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way + * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) + * IPv6 uses colon separated network-order 16 bit hex with leading 0's + * - 'i' [46] for 'raw' IPv4/IPv6 addresses + * IPv6 omits the colons (01020304...0f) + * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006) + * - 'I6c' for IPv6 addresses printed as specified by + * http://www.ietf.org/id/draft-kawamura-ipv6-text-representation-03.txt * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 * function pointers are really function descriptors, which contain a * pointer to the real address. @@ -726,20 +827,24 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, return symbol_string(buf, end, ptr, spec, *fmt); case 'R': return resource_string(buf, end, ptr, spec); - case 'm': - spec.flags |= SPECIAL; - /* Fallthrough */ - case 'M': - return mac_address_string(buf, end, ptr, spec); - case 'i': - spec.flags |= SPECIAL; - /* Fallthrough */ - case 'I': - if (fmt[1] == '6') - return ip6_addr_string(buf, end, ptr, spec); - if (fmt[1] == '4') - return ip4_addr_string(buf, end, ptr, spec); - spec.flags &= ~SPECIAL; + case 'M': /* Colon separated: 00:01:02:03:04:05 */ + case 'm': /* Contiguous: 000102030405 */ + return mac_address_string(buf, end, ptr, spec, fmt); + case 'I': /* Formatted IP supported + * 4: 1.2.3.4 + * 6: 0001:0203:...:0708 + * 6c: 1::708 or 1::1.2.3.4 + */ + case 'i': /* Contiguous: + * 4: 001.002.003.004 + * 6: 000102...0f + */ + switch (fmt[1]) { + case '6': + return ip6_addr_string(buf, end, ptr, spec, fmt); + case '4': + return ip4_addr_string(buf, end, ptr, spec, fmt); + } break; } spec.flags |= SMALL; -- cgit v0.10.2 From 38edb5b87ea26314cb6ad4524c3f3b0fea0e33de Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Wed, 19 Aug 2009 23:56:20 +0000 Subject: WAN/LMC: Fix type_trans(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix lmc_proto_type() invocation. Signed-off-by: Krzysztof Hałasa Signed-off-by: David S. Miller diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 6e6b08c..4b83d88 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1657,7 +1657,7 @@ static int lmc_rx(struct net_device *dev) } skb_copy_from_linear_data(skb, skb_put(nsb, len), len); - nsb->protocol = lmc_proto_type(sc, skb); + nsb->protocol = lmc_proto_type(sc, nsb); skb_reset_mac_header(nsb); /* skb_reset_network_header(nsb); */ nsb->dev = dev; -- cgit v0.10.2 From 2db9517ef3dd48790c02a531e2b0db1957afd891 Mon Sep 17 00:00:00 2001 From: "Rajashekhara, Sudhakar" Date: Wed, 19 Aug 2009 10:39:55 +0000 Subject: TI DaVinci EMAC: delay DaVinci EMAC initialization On TI's DA850/OMAP-L138 EVM, MAC address is stored in SPI flash which is accessed using MTD interface. This patch delays the initialization of DaVinci EMAC driver by changing module_init to late_initcall. This helps SPI and MTD drivers to get initialized before EMAC thereby enabling EMAC driver to read the MAC address while booting and use it. Tested with NFS on DM644x, DM6467, DA830/OMAP-L137 and DA850/OMAP-L138 EVMs. Signed-off-by: Sudhakar Rajashekhara Reviewed-by: Chaithrika U S Signed-off-by: Kevin Hilman Signed-off-by: David S. Miller diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 12fd446..5e6652b 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -2817,7 +2817,7 @@ static int __init davinci_emac_init(void) { return platform_driver_register(&davinci_emac_driver); } -module_init(davinci_emac_init); +late_initcall(davinci_emac_init); /** * davinci_emac_exit: EMAC driver module exit -- cgit v0.10.2 From 4923576b8ac5bfd36ab2beb176aeb747aaab7e41 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 27 Aug 2009 23:25:03 +0000 Subject: net: sh_eth: add value of ether_link pin in platform_data The method of ETHER_LINK pin is board dependence. This patch adding paramters are: - no_ether_link : If set to 1, do not use ETHER_LINK - ether_link_active_low : If set to 1, ETHER_LINK is active low. Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller diff --git a/arch/sh/include/asm/sh_eth.h b/arch/sh/include/asm/sh_eth.h index bb83258..acf9970 100644 --- a/arch/sh/include/asm/sh_eth.h +++ b/arch/sh/include/asm/sh_eth.h @@ -6,6 +6,9 @@ enum {EDMAC_LITTLE_ENDIAN, EDMAC_BIG_ENDIAN}; struct sh_eth_plat_data { int phy; int edmac_endian; + + unsigned no_ether_link:1; + unsigned ether_link_active_low:1; }; #endif diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 4c4dcbf..f49d0800 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -772,13 +772,15 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) mdp->stats.tx_carrier_errors++; if (felic_stat & ECSR_LCHNG) { /* Link Changed */ - if (mdp->cd->no_psr) { + if (mdp->cd->no_psr || mdp->no_ether_link) { if (mdp->link == PHY_DOWN) link_stat = 0; else link_stat = PHY_ST_LINK; } else { link_stat = (ctrl_inl(ioaddr + PSR)); + if (mdp->ether_link_active_low) + link_stat = ~link_stat; } if (!(link_stat & PHY_ST_LINK)) { /* Link Down : disable tx and rx */ @@ -1410,6 +1412,8 @@ static int sh_eth_drv_probe(struct platform_device *pdev) mdp->phy_id = pd->phy; /* EDMAC endian */ mdp->edmac_endian = pd->edmac_endian; + mdp->no_ether_link = pd->no_ether_link; + mdp->ether_link_active_low = pd->ether_link_active_low; /* set cpu data */ mdp->cd = &sh_eth_my_cpu_data; diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 9afe5b4..ba151f8 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -729,6 +729,9 @@ struct sh_eth_private { char post_rx; /* POST receive */ char post_fw; /* POST forward */ struct net_device_stats tsu_stats; /* TSU forward status */ + + unsigned no_ether_link:1; + unsigned ether_link_active_low:1; }; static inline void sh_eth_soft_swap(char *src, int len) -- cgit v0.10.2 From ea00b8e2223170a842bee06e0f27754ccdf2a217 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 28 Aug 2009 09:57:21 +0000 Subject: can: switch to seq_file create_proc_read_entry() is going to be removed soon. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/net/can/bcm.c b/net/can/bcm.c index 72720c7..597da4f 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -146,23 +147,18 @@ static char *bcm_proc_getifname(int ifindex) return "???"; } -static int bcm_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int bcm_proc_show(struct seq_file *m, void *v) { - int len = 0; - struct sock *sk = (struct sock *)data; + struct sock *sk = (struct sock *)m->private; struct bcm_sock *bo = bcm_sk(sk); struct bcm_op *op; - len += snprintf(page + len, PAGE_SIZE - len, ">>> socket %p", - sk->sk_socket); - len += snprintf(page + len, PAGE_SIZE - len, " / sk %p", sk); - len += snprintf(page + len, PAGE_SIZE - len, " / bo %p", bo); - len += snprintf(page + len, PAGE_SIZE - len, " / dropped %lu", - bo->dropped_usr_msgs); - len += snprintf(page + len, PAGE_SIZE - len, " / bound %s", - bcm_proc_getifname(bo->ifindex)); - len += snprintf(page + len, PAGE_SIZE - len, " <<<\n"); + seq_printf(m, ">>> socket %p", sk->sk_socket); + seq_printf(m, " / sk %p", sk); + seq_printf(m, " / bo %p", bo); + seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs); + seq_printf(m, " / bound %s", bcm_proc_getifname(bo->ifindex)); + seq_printf(m, " <<<\n"); list_for_each_entry(op, &bo->rx_ops, list) { @@ -172,71 +168,62 @@ static int bcm_read_proc(char *page, char **start, off_t off, if (!op->frames_abs) continue; - len += snprintf(page + len, PAGE_SIZE - len, - "rx_op: %03X %-5s ", + seq_printf(m, "rx_op: %03X %-5s ", op->can_id, bcm_proc_getifname(op->ifindex)); - len += snprintf(page + len, PAGE_SIZE - len, "[%d]%c ", - op->nframes, + seq_printf(m, "[%d]%c ", op->nframes, (op->flags & RX_CHECK_DLC)?'d':' '); if (op->kt_ival1.tv64) - len += snprintf(page + len, PAGE_SIZE - len, - "timeo=%lld ", + seq_printf(m, "timeo=%lld ", (long long) ktime_to_us(op->kt_ival1)); if (op->kt_ival2.tv64) - len += snprintf(page + len, PAGE_SIZE - len, - "thr=%lld ", + seq_printf(m, "thr=%lld ", (long long) ktime_to_us(op->kt_ival2)); - len += snprintf(page + len, PAGE_SIZE - len, - "# recv %ld (%ld) => reduction: ", + seq_printf(m, "# recv %ld (%ld) => reduction: ", op->frames_filtered, op->frames_abs); reduction = 100 - (op->frames_filtered * 100) / op->frames_abs; - len += snprintf(page + len, PAGE_SIZE - len, "%s%ld%%\n", + seq_printf(m, "%s%ld%%\n", (reduction == 100)?"near ":"", reduction); - - if (len > PAGE_SIZE - 200) { - /* mark output cut off */ - len += snprintf(page + len, PAGE_SIZE - len, "(..)\n"); - break; - } } list_for_each_entry(op, &bo->tx_ops, list) { - len += snprintf(page + len, PAGE_SIZE - len, - "tx_op: %03X %s [%d] ", + seq_printf(m, "tx_op: %03X %s [%d] ", op->can_id, bcm_proc_getifname(op->ifindex), op->nframes); if (op->kt_ival1.tv64) - len += snprintf(page + len, PAGE_SIZE - len, "t1=%lld ", + seq_printf(m, "t1=%lld ", (long long) ktime_to_us(op->kt_ival1)); if (op->kt_ival2.tv64) - len += snprintf(page + len, PAGE_SIZE - len, "t2=%lld ", + seq_printf(m, "t2=%lld ", (long long) ktime_to_us(op->kt_ival2)); - len += snprintf(page + len, PAGE_SIZE - len, "# sent %ld\n", - op->frames_abs); - - if (len > PAGE_SIZE - 100) { - /* mark output cut off */ - len += snprintf(page + len, PAGE_SIZE - len, "(..)\n"); - break; - } + seq_printf(m, "# sent %ld\n", op->frames_abs); } + seq_putc(m, '\n'); + return 0; +} - len += snprintf(page + len, PAGE_SIZE - len, "\n"); - - *eof = 1; - return len; +static int bcm_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, bcm_proc_show, PDE(inode)->data); } +static const struct file_operations bcm_proc_fops = { + .owner = THIS_MODULE, + .open = bcm_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* * bcm_can_tx - send the (next) CAN frame to the appropriate CAN interface * of the given bcm tx op @@ -1515,9 +1502,9 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len, if (proc_dir) { /* unique socket address as filename */ sprintf(bo->procname, "%p", sock); - bo->bcm_proc_read = create_proc_read_entry(bo->procname, 0644, - proc_dir, - bcm_read_proc, sk); + bo->bcm_proc_read = proc_create_data(bo->procname, 0644, + proc_dir, + &bcm_proc_fops, sk); } return 0; diff --git a/net/can/proc.c b/net/can/proc.c index 1463653..9b9ad29 100644 --- a/net/can/proc.c +++ b/net/can/proc.c @@ -196,8 +196,8 @@ void can_stat_update(unsigned long data) * */ -static int can_print_rcvlist(char *page, int len, struct hlist_head *rx_list, - struct net_device *dev) +static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, + struct net_device *dev) { struct receiver *r; struct hlist_node *n; @@ -208,199 +208,188 @@ static int can_print_rcvlist(char *page, int len, struct hlist_head *rx_list, " %-5s %08X %08x %08x %08x %8ld %s\n" : " %-5s %03X %08x %08lx %08lx %8ld %s\n"; - len += snprintf(page + len, PAGE_SIZE - len, fmt, - DNAME(dev), r->can_id, r->mask, + seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask, (unsigned long)r->func, (unsigned long)r->data, r->matches, r->ident); - - /* does a typical line fit into the current buffer? */ - - /* 100 Bytes before end of buffer */ - if (len > PAGE_SIZE - 100) { - /* mark output cut off */ - len += snprintf(page + len, PAGE_SIZE - len, - " (..)\n"); - break; - } } rcu_read_unlock(); - - return len; } -static int can_print_recv_banner(char *page, int len) +static void can_print_recv_banner(struct seq_file *m) { /* * can1. 00000000 00000000 00000000 * ....... 0 tp20 */ - len += snprintf(page + len, PAGE_SIZE - len, - " device can_id can_mask function" + seq_puts(m, " device can_id can_mask function" " userdata matches ident\n"); - - return len; } -static int can_proc_read_stats(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int can_stats_proc_show(struct seq_file *m, void *v) { - int len = 0; + seq_putc(m, '\n'); + seq_printf(m, " %8ld transmitted frames (TXF)\n", can_stats.tx_frames); + seq_printf(m, " %8ld received frames (RXF)\n", can_stats.rx_frames); + seq_printf(m, " %8ld matched frames (RXMF)\n", can_stats.matches); - len += snprintf(page + len, PAGE_SIZE - len, "\n"); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld transmitted frames (TXF)\n", - can_stats.tx_frames); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld received frames (RXF)\n", can_stats.rx_frames); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld matched frames (RXMF)\n", can_stats.matches); - - len += snprintf(page + len, PAGE_SIZE - len, "\n"); + seq_putc(m, '\n'); if (can_stattimer.function == can_stat_update) { - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld %% total match ratio (RXMR)\n", + seq_printf(m, " %8ld %% total match ratio (RXMR)\n", can_stats.total_rx_match_ratio); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld frames/s total tx rate (TXR)\n", + seq_printf(m, " %8ld frames/s total tx rate (TXR)\n", can_stats.total_tx_rate); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld frames/s total rx rate (RXR)\n", + seq_printf(m, " %8ld frames/s total rx rate (RXR)\n", can_stats.total_rx_rate); - len += snprintf(page + len, PAGE_SIZE - len, "\n"); + seq_putc(m, '\n'); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld %% current match ratio (CRXMR)\n", + seq_printf(m, " %8ld %% current match ratio (CRXMR)\n", can_stats.current_rx_match_ratio); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld frames/s current tx rate (CTXR)\n", + seq_printf(m, " %8ld frames/s current tx rate (CTXR)\n", can_stats.current_tx_rate); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld frames/s current rx rate (CRXR)\n", + seq_printf(m, " %8ld frames/s current rx rate (CRXR)\n", can_stats.current_rx_rate); - len += snprintf(page + len, PAGE_SIZE - len, "\n"); + seq_putc(m, '\n'); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld %% max match ratio (MRXMR)\n", + seq_printf(m, " %8ld %% max match ratio (MRXMR)\n", can_stats.max_rx_match_ratio); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld frames/s max tx rate (MTXR)\n", + seq_printf(m, " %8ld frames/s max tx rate (MTXR)\n", can_stats.max_tx_rate); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld frames/s max rx rate (MRXR)\n", + seq_printf(m, " %8ld frames/s max rx rate (MRXR)\n", can_stats.max_rx_rate); - len += snprintf(page + len, PAGE_SIZE - len, "\n"); + seq_putc(m, '\n'); } - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld current receive list entries (CRCV)\n", + seq_printf(m, " %8ld current receive list entries (CRCV)\n", can_pstats.rcv_entries); - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld maximum receive list entries (MRCV)\n", + seq_printf(m, " %8ld maximum receive list entries (MRCV)\n", can_pstats.rcv_entries_max); if (can_pstats.stats_reset) - len += snprintf(page + len, PAGE_SIZE - len, - "\n %8ld statistic resets (STR)\n", + seq_printf(m, "\n %8ld statistic resets (STR)\n", can_pstats.stats_reset); if (can_pstats.user_reset) - len += snprintf(page + len, PAGE_SIZE - len, - " %8ld user statistic resets (USTR)\n", + seq_printf(m, " %8ld user statistic resets (USTR)\n", can_pstats.user_reset); - len += snprintf(page + len, PAGE_SIZE - len, "\n"); - - *eof = 1; - return len; + seq_putc(m, '\n'); + return 0; } -static int can_proc_read_reset_stats(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int can_stats_proc_open(struct inode *inode, struct file *file) { - int len = 0; + return single_open(file, can_stats_proc_show, NULL); +} + +static const struct file_operations can_stats_proc_fops = { + .owner = THIS_MODULE, + .open = can_stats_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +static int can_reset_stats_proc_show(struct seq_file *m, void *v) +{ user_reset = 1; if (can_stattimer.function == can_stat_update) { - len += snprintf(page + len, PAGE_SIZE - len, - "Scheduled statistic reset #%ld.\n", + seq_printf(m, "Scheduled statistic reset #%ld.\n", can_pstats.stats_reset + 1); } else { if (can_stats.jiffies_init != jiffies) can_init_stats(); - len += snprintf(page + len, PAGE_SIZE - len, - "Performed statistic reset #%ld.\n", + seq_printf(m, "Performed statistic reset #%ld.\n", can_pstats.stats_reset); } + return 0; +} - *eof = 1; - return len; +static int can_reset_stats_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, can_reset_stats_proc_show, NULL); } -static int can_proc_read_version(char *page, char **start, off_t off, - int count, int *eof, void *data) +static const struct file_operations can_reset_stats_proc_fops = { + .owner = THIS_MODULE, + .open = can_reset_stats_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int can_version_proc_show(struct seq_file *m, void *v) { - int len = 0; + seq_printf(m, "%s\n", CAN_VERSION_STRING); + return 0; +} - len += snprintf(page + len, PAGE_SIZE - len, "%s\n", - CAN_VERSION_STRING); - *eof = 1; - return len; +static int can_version_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, can_version_proc_show, NULL); } -static int can_proc_read_rcvlist(char *page, char **start, off_t off, - int count, int *eof, void *data) +static const struct file_operations can_version_proc_fops = { + .owner = THIS_MODULE, + .open = can_version_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int can_rcvlist_proc_show(struct seq_file *m, void *v) { /* double cast to prevent GCC warning */ - int idx = (int)(long)data; - int len = 0; + int idx = (int)(long)m->private; struct dev_rcv_lists *d; struct hlist_node *n; - len += snprintf(page + len, PAGE_SIZE - len, - "\nreceive list '%s':\n", rx_list_name[idx]); + seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]); rcu_read_lock(); hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) { if (!hlist_empty(&d->rx[idx])) { - len = can_print_recv_banner(page, len); - len = can_print_rcvlist(page, len, &d->rx[idx], d->dev); + can_print_recv_banner(m); + can_print_rcvlist(m, &d->rx[idx], d->dev); } else - len += snprintf(page + len, PAGE_SIZE - len, - " (%s: no entry)\n", DNAME(d->dev)); - - /* exit on end of buffer? */ - if (len > PAGE_SIZE - 100) - break; + seq_printf(m, " (%s: no entry)\n", DNAME(d->dev)); } rcu_read_unlock(); - len += snprintf(page + len, PAGE_SIZE - len, "\n"); + seq_putc(m, '\n'); + return 0; +} - *eof = 1; - return len; +static int can_rcvlist_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, can_rcvlist_proc_show, PDE(inode)->data); } -static int can_proc_read_rcvlist_sff(char *page, char **start, off_t off, - int count, int *eof, void *data) +static const struct file_operations can_rcvlist_proc_fops = { + .owner = THIS_MODULE, + .open = can_rcvlist_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v) { - int len = 0; struct dev_rcv_lists *d; struct hlist_node *n; /* RX_SFF */ - len += snprintf(page + len, PAGE_SIZE - len, - "\nreceive list 'rx_sff':\n"); + seq_puts(m, "\nreceive list 'rx_sff':\n"); rcu_read_lock(); hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) { @@ -413,46 +402,38 @@ static int can_proc_read_rcvlist_sff(char *page, char **start, off_t off, } if (!all_empty) { - len = can_print_recv_banner(page, len); + can_print_recv_banner(m); for (i = 0; i < 0x800; i++) { - if (!hlist_empty(&d->rx_sff[i]) && - len < PAGE_SIZE - 100) - len = can_print_rcvlist(page, len, - &d->rx_sff[i], - d->dev); + if (!hlist_empty(&d->rx_sff[i])) + can_print_rcvlist(m, &d->rx_sff[i], + d->dev); } } else - len += snprintf(page + len, PAGE_SIZE - len, - " (%s: no entry)\n", DNAME(d->dev)); - - /* exit on end of buffer? */ - if (len > PAGE_SIZE - 100) - break; + seq_printf(m, " (%s: no entry)\n", DNAME(d->dev)); } rcu_read_unlock(); - len += snprintf(page + len, PAGE_SIZE - len, "\n"); + seq_putc(m, '\n'); + return 0; +} - *eof = 1; - return len; +static int can_rcvlist_sff_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, can_rcvlist_sff_proc_show, NULL); } +static const struct file_operations can_rcvlist_sff_proc_fops = { + .owner = THIS_MODULE, + .open = can_rcvlist_sff_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* * proc utility functions */ -static struct proc_dir_entry *can_create_proc_readentry(const char *name, - mode_t mode, - read_proc_t *read_proc, - void *data) -{ - if (can_dir) - return create_proc_read_entry(name, mode, can_dir, read_proc, - data); - else - return NULL; -} - static void can_remove_proc_readentry(const char *name) { if (can_dir) @@ -474,24 +455,24 @@ void can_init_proc(void) } /* own procfs entries from the AF_CAN core */ - pde_version = can_create_proc_readentry(CAN_PROC_VERSION, 0644, - can_proc_read_version, NULL); - pde_stats = can_create_proc_readentry(CAN_PROC_STATS, 0644, - can_proc_read_stats, NULL); - pde_reset_stats = can_create_proc_readentry(CAN_PROC_RESET_STATS, 0644, - can_proc_read_reset_stats, NULL); - pde_rcvlist_err = can_create_proc_readentry(CAN_PROC_RCVLIST_ERR, 0644, - can_proc_read_rcvlist, (void *)RX_ERR); - pde_rcvlist_all = can_create_proc_readentry(CAN_PROC_RCVLIST_ALL, 0644, - can_proc_read_rcvlist, (void *)RX_ALL); - pde_rcvlist_fil = can_create_proc_readentry(CAN_PROC_RCVLIST_FIL, 0644, - can_proc_read_rcvlist, (void *)RX_FIL); - pde_rcvlist_inv = can_create_proc_readentry(CAN_PROC_RCVLIST_INV, 0644, - can_proc_read_rcvlist, (void *)RX_INV); - pde_rcvlist_eff = can_create_proc_readentry(CAN_PROC_RCVLIST_EFF, 0644, - can_proc_read_rcvlist, (void *)RX_EFF); - pde_rcvlist_sff = can_create_proc_readentry(CAN_PROC_RCVLIST_SFF, 0644, - can_proc_read_rcvlist_sff, NULL); + pde_version = proc_create(CAN_PROC_VERSION, 0644, can_dir, + &can_version_proc_fops); + pde_stats = proc_create(CAN_PROC_STATS, 0644, can_dir, + &can_stats_proc_fops); + pde_reset_stats = proc_create(CAN_PROC_RESET_STATS, 0644, can_dir, + &can_reset_stats_proc_fops); + pde_rcvlist_err = proc_create_data(CAN_PROC_RCVLIST_ERR, 0644, can_dir, + &can_rcvlist_proc_fops, (void *)RX_ERR); + pde_rcvlist_all = proc_create_data(CAN_PROC_RCVLIST_ALL, 0644, can_dir, + &can_rcvlist_proc_fops, (void *)RX_ALL); + pde_rcvlist_fil = proc_create_data(CAN_PROC_RCVLIST_FIL, 0644, can_dir, + &can_rcvlist_proc_fops, (void *)RX_FIL); + pde_rcvlist_inv = proc_create_data(CAN_PROC_RCVLIST_INV, 0644, can_dir, + &can_rcvlist_proc_fops, (void *)RX_INV); + pde_rcvlist_eff = proc_create_data(CAN_PROC_RCVLIST_EFF, 0644, can_dir, + &can_rcvlist_proc_fops, (void *)RX_EFF); + pde_rcvlist_sff = proc_create(CAN_PROC_RCVLIST_SFF, 0644, can_dir, + &can_rcvlist_sff_proc_fops); } /* -- cgit v0.10.2 From b3df9a514f3c2020952cff34bc5bc6694a31c00c Mon Sep 17 00:00:00 2001 From: roel kluin Date: Thu, 27 Aug 2009 02:03:15 +0000 Subject: tipc: fix test of bearer_priority range in tipc_register_media() For the bearer_priority to be less than TIPC_MIN_LINK_PRI and greater than TIPC_MAX_LINK_PRI is logically impossible. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index a7a3677..327011f 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -119,7 +119,7 @@ int tipc_register_media(u32 media_type, warn("Media <%s> rejected, no broadcast address\n", name); goto exit; } - if ((bearer_priority < TIPC_MIN_LINK_PRI) && + if ((bearer_priority < TIPC_MIN_LINK_PRI) || (bearer_priority > TIPC_MAX_LINK_PRI)) { warn("Media <%s> rejected, illegal priority (%u)\n", name, bearer_priority); -- cgit v0.10.2 From a367b17f34e1280270a6b577c11d5ecff093f9ae Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Sat, 29 Aug 2009 17:36:25 +1000 Subject: crypto: ansi_cprng - Fix module initialization Return the value we got from crypto_register_alg() instead of returning 0 in any case. Signed-off-by: Steffen Klassert Acked-by: Neil Horman Signed-off-by: Herbert Xu diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index 5357ba7..3aa6e38 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -408,17 +408,10 @@ static struct crypto_alg rng_alg = { /* Module initalization */ static int __init prng_mod_init(void) { - int ret = 0; - if (fips_enabled) rng_alg.cra_priority += 200; - ret = crypto_register_alg(&rng_alg); - - if (ret) - goto out; -out: - return 0; + return crypto_register_alg(&rng_alg); } static void __exit prng_mod_fini(void) -- cgit v0.10.2 From a417887637e862b434b293404f2a31ad1f282a58 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 29 Aug 2009 18:47:59 +0800 Subject: lockdep: Remove recursion stattistics Since lockdep has introduced BFS to avoid recursion, statistics for recursion does not make any sense now. So remove them. Signed-off-by: Ming Lei Cc: a.p.zijlstra@chello.nl LKML-Reference: <1251542879-5211-1-git-send-email-tom.leiming@gmail.com> Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 0843584..f74d2d7 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -399,7 +399,6 @@ unsigned int nr_hardirq_chains; unsigned int nr_softirq_chains; unsigned int nr_process_chains; unsigned int max_lockdep_depth; -unsigned int max_recursion_depth; #ifdef CONFIG_DEBUG_LOCKDEP /* @@ -429,11 +428,8 @@ atomic_t redundant_softirqs_on; atomic_t redundant_softirqs_off; atomic_t nr_unused_locks; atomic_t nr_cyclic_checks; -atomic_t nr_cyclic_check_recursions; atomic_t nr_find_usage_forwards_checks; -atomic_t nr_find_usage_forwards_recursions; atomic_t nr_find_usage_backwards_checks; -atomic_t nr_find_usage_backwards_recursions; #endif /* diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index 8dac840..ec33c6a 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c @@ -199,16 +199,10 @@ static void lockdep_stats_debug_show(struct seq_file *m) debug_atomic_read(&chain_lookup_hits)); seq_printf(m, " cyclic checks: %11u\n", debug_atomic_read(&nr_cyclic_checks)); - seq_printf(m, " cyclic-check recursions: %11u\n", - debug_atomic_read(&nr_cyclic_check_recursions)); seq_printf(m, " find-mask forwards checks: %11u\n", debug_atomic_read(&nr_find_usage_forwards_checks)); - seq_printf(m, " find-mask forwards recursions: %11u\n", - debug_atomic_read(&nr_find_usage_forwards_recursions)); seq_printf(m, " find-mask backwards checks: %11u\n", debug_atomic_read(&nr_find_usage_backwards_checks)); - seq_printf(m, " find-mask backwards recursions:%11u\n", - debug_atomic_read(&nr_find_usage_backwards_recursions)); seq_printf(m, " hardirq on events: %11u\n", hi1); seq_printf(m, " hardirq off events: %11u\n", hi2); @@ -350,8 +344,6 @@ static int lockdep_stats_show(struct seq_file *m, void *v) nr_unused); seq_printf(m, " max locking depth: %11u\n", max_lockdep_depth); - seq_printf(m, " max recursion depth: %11u\n", - max_recursion_depth); #ifdef CONFIG_PROVE_LOCKING seq_printf(m, " max bfs queue depth: %11u\n", max_bfs_queue_depth); -- cgit v0.10.2 From dd5d19bafd90d33043a4a14b2e2d98612caa293c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 27 Aug 2009 14:58:16 -0700 Subject: rcu: Create rcutree plugins to handle hotplug CPU for multi-level trees When offlining CPUs from a multi-level tree, there is the possibility of offlining the last CPU from a given node when there are preempted RCU read-side critical sections that started life on one of the CPUs on that node. In this case, the corresponding tasks will be enqueued via the task_struct's rcu_node_entry list_head onto one of the rcu_node's blocked_tasks[] lists. These tasks need to be moved somewhere else so that they will prevent the current grace period from ending. That somewhere is the root rcu_node. 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: <20090827215816.GA30472@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 79d4bae..9e7f2e8 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -98,7 +98,7 @@ extern struct group_info init_groups; #define INIT_TASK_RCU_PREEMPT(tsk) \ .rcu_read_lock_nesting = 0, \ .rcu_read_unlock_special = 0, \ - .rcu_blocked_cpu = -1, \ + .rcu_blocked_node = NULL, \ .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry), #else #define INIT_TASK_RCU_PREEMPT(tsk) diff --git a/include/linux/sched.h b/include/linux/sched.h index bfca26d6..3fe0315 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1208,7 +1208,7 @@ struct task_struct { #ifdef CONFIG_TREE_PREEMPT_RCU int rcu_read_lock_nesting; char rcu_read_unlock_special; - int rcu_blocked_cpu; + void *rcu_blocked_node; struct list_head rcu_node_entry; #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ @@ -1735,7 +1735,7 @@ static inline void rcu_copy_process(struct task_struct *p) { p->rcu_read_lock_nesting = 0; p->rcu_read_unlock_special = 0; - p->rcu_blocked_cpu = -1; + p->rcu_blocked_node = NULL; INIT_LIST_HEAD(&p->rcu_node_entry); } diff --git a/kernel/rcutree.c b/kernel/rcutree.c index fee6316..d903e2f 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -81,6 +81,7 @@ struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh_state); DEFINE_PER_CPU(struct rcu_data, rcu_bh_data); extern long rcu_batches_completed_sched(void); +static struct rcu_node *rcu_get_root(struct rcu_state *rsp); static void cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, struct rcu_node *rnp, unsigned long flags); static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags); @@ -876,6 +877,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) spin_unlock(&rnp->lock); /* irqs remain disabled. */ break; } + rcu_preempt_offline_tasks(rsp, rnp); mask = rnp->grpmask; spin_unlock(&rnp->lock); /* irqs remain disabled. */ rnp = rnp->parent; diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 201334c..04343be 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -92,7 +92,7 @@ static void rcu_preempt_qs(int cpu) rnp = rdp->mynode; spin_lock(&rnp->lock); t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED; - t->rcu_blocked_cpu = cpu; + t->rcu_blocked_node = (void *)rnp; /* * If this CPU has already checked in, then this task @@ -170,12 +170,21 @@ static void rcu_read_unlock_special(struct task_struct *t) if (special & RCU_READ_UNLOCK_BLOCKED) { t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_BLOCKED; - /* Remove this task from the list it blocked on. */ - rnp = rcu_preempt_state.rda[t->rcu_blocked_cpu]->mynode; - spin_lock(&rnp->lock); + /* + * Remove this task from the list it blocked on. The + * task can migrate while we acquire the lock, but at + * most one time. So at most two passes through loop. + */ + for (;;) { + rnp = (struct rcu_node *)t->rcu_blocked_node; + spin_lock(&rnp->lock); + if (rnp == (struct rcu_node *)t->rcu_blocked_node) + break; + spin_unlock(&rnp->lock); + } empty = list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1]); list_del_init(&t->rcu_node_entry); - t->rcu_blocked_cpu = -1; + t->rcu_blocked_node = NULL; /* * If this was the last task on the current list, and if @@ -262,6 +271,47 @@ static int rcu_preempted_readers(struct rcu_node *rnp) #ifdef CONFIG_HOTPLUG_CPU /* + * Handle tasklist migration for case in which all CPUs covered by the + * specified rcu_node have gone offline. Move them up to the root + * rcu_node. The reason for not just moving them to the immediate + * parent is to remove the need for rcu_read_unlock_special() to + * make more than two attempts to acquire the target rcu_node's lock. + * + * The caller must hold rnp->lock with irqs disabled. + */ +static void rcu_preempt_offline_tasks(struct rcu_state *rsp, + struct rcu_node *rnp) +{ + int i; + struct list_head *lp; + struct list_head *lp_root; + struct rcu_node *rnp_root = rcu_get_root(rsp); + struct task_struct *tp; + + if (rnp == rnp_root) + return; /* Shouldn't happen: at least one CPU online. */ + + /* + * Move tasks up to root rcu_node. Rely on the fact that the + * root rcu_node can be at most one ahead of the rest of the + * rcu_nodes in terms of gp_num value. This fact allows us to + * move the blocked_tasks[] array directly, element by element. + */ + for (i = 0; i < 2; i++) { + lp = &rnp->blocked_tasks[i]; + lp_root = &rnp_root->blocked_tasks[i]; + while (!list_empty(lp)) { + tp = list_entry(lp->next, typeof(*tp), rcu_node_entry); + spin_lock(&rnp_root->lock); /* irqs already disabled */ + list_del(&tp->rcu_node_entry); + tp->rcu_blocked_node = rnp_root; + list_add(&tp->rcu_node_entry, lp_root); + spin_unlock(&rnp_root->lock); /* irqs remain disabled */ + } + } +} + +/* * Do CPU-offline processing for preemptable RCU. */ static void rcu_preempt_offline_cpu(int cpu) @@ -410,6 +460,15 @@ static int rcu_preempted_readers(struct rcu_node *rnp) #ifdef CONFIG_HOTPLUG_CPU /* + * Because preemptable RCU does not exist, it never needs to migrate + * tasks that were blocked within RCU read-side critical sections. + */ +static void rcu_preempt_offline_tasks(struct rcu_state *rsp, + struct rcu_node *rnp) +{ +} + +/* * Because preemptable RCU does not exist, it never needs CPU-offline * processing. */ -- cgit v0.10.2 From 868489660dabc0c28087cca3dbc1adbbc398c6fe Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 27 Aug 2009 15:00:12 -0700 Subject: rcu: Changes from reviews: avoid casts, fix/add warnings, improve comments Changes suggested by review comments from Josh Triplett and Mathieu Desnoyers. Signed-off-by: Paul E. McKenney Acked-by: Josh Triplett Acked-by: Mathieu Desnoyers Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: akpm@linux-foundation.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org LKML-Reference: <20090827220012.GA30525@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 3fe0315..855fd0d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1163,6 +1163,8 @@ struct sched_rt_entity { #endif }; +struct rcu_node; + struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ void *stack; @@ -1208,7 +1210,7 @@ struct task_struct { #ifdef CONFIG_TREE_PREEMPT_RCU int rcu_read_lock_nesting; char rcu_read_unlock_special; - void *rcu_blocked_node; + struct rcu_node *rcu_blocked_node; struct list_head rcu_node_entry; #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ diff --git a/kernel/rcutree.c b/kernel/rcutree.c index d903e2f..71bc797 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -229,7 +229,6 @@ static int rcu_implicit_offline_qs(struct rcu_data *rdp) #endif /* #ifdef CONFIG_SMP */ #ifdef CONFIG_NO_HZ -static DEFINE_RATELIMIT_STATE(rcu_rs, 10 * HZ, 5); /** * rcu_enter_nohz - inform RCU that current CPU is entering nohz @@ -249,7 +248,7 @@ void rcu_enter_nohz(void) rdtp = &__get_cpu_var(rcu_dynticks); rdtp->dynticks++; rdtp->dynticks_nesting--; - WARN_ON_RATELIMIT(rdtp->dynticks & 0x1, &rcu_rs); + WARN_ON_ONCE(rdtp->dynticks & 0x1); local_irq_restore(flags); } @@ -268,7 +267,7 @@ void rcu_exit_nohz(void) rdtp = &__get_cpu_var(rcu_dynticks); rdtp->dynticks++; rdtp->dynticks_nesting++; - WARN_ON_RATELIMIT(!(rdtp->dynticks & 0x1), &rcu_rs); + WARN_ON_ONCE(!(rdtp->dynticks & 0x1)); local_irq_restore(flags); smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ } @@ -287,7 +286,7 @@ void rcu_nmi_enter(void) if (rdtp->dynticks & 0x1) return; rdtp->dynticks_nmi++; - WARN_ON_RATELIMIT(!(rdtp->dynticks_nmi & 0x1), &rcu_rs); + WARN_ON_ONCE(!(rdtp->dynticks_nmi & 0x1)); smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ } @@ -306,7 +305,7 @@ void rcu_nmi_exit(void) return; smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ rdtp->dynticks_nmi++; - WARN_ON_RATELIMIT(rdtp->dynticks_nmi & 0x1, &rcu_rs); + WARN_ON_ONCE(rdtp->dynticks_nmi & 0x1); } /** @@ -322,7 +321,7 @@ void rcu_irq_enter(void) if (rdtp->dynticks_nesting++) return; rdtp->dynticks++; - WARN_ON_RATELIMIT(!(rdtp->dynticks & 0x1), &rcu_rs); + WARN_ON_ONCE(!(rdtp->dynticks & 0x1)); smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ } @@ -341,7 +340,7 @@ void rcu_irq_exit(void) return; smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ rdtp->dynticks++; - WARN_ON_RATELIMIT(rdtp->dynticks & 0x1, &rcu_rs); + WARN_ON_ONCE(rdtp->dynticks & 0x1); /* If the interrupt queued a callback, get out of dyntick mode. */ if (__get_cpu_var(rcu_sched_data).nxtlist || diff --git a/kernel/rcutree.h b/kernel/rcutree.h index ca56036..bf8a6f9 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -81,6 +81,8 @@ struct rcu_dynticks { struct rcu_node { spinlock_t lock; long gpnum; /* Current grace period for this node. */ + /* This will either be equal to or one */ + /* behind the root rcu_node's gpnum. */ unsigned long qsmask; /* CPUs or groups that need to switch in */ /* order for current grace period to proceed.*/ unsigned long qsmaskinit; diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 04343be..4778936 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -92,7 +92,7 @@ static void rcu_preempt_qs(int cpu) rnp = rdp->mynode; spin_lock(&rnp->lock); t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED; - t->rcu_blocked_node = (void *)rnp; + t->rcu_blocked_node = rnp; /* * If this CPU has already checked in, then this task @@ -176,9 +176,9 @@ static void rcu_read_unlock_special(struct task_struct *t) * most one time. So at most two passes through loop. */ for (;;) { - rnp = (struct rcu_node *)t->rcu_blocked_node; + rnp = t->rcu_blocked_node; spin_lock(&rnp->lock); - if (rnp == (struct rcu_node *)t->rcu_blocked_node) + if (rnp == t->rcu_blocked_node) break; spin_unlock(&rnp->lock); } @@ -288,8 +288,10 @@ static void rcu_preempt_offline_tasks(struct rcu_state *rsp, struct rcu_node *rnp_root = rcu_get_root(rsp); struct task_struct *tp; - if (rnp == rnp_root) + if (rnp == rnp_root) { + WARN_ONCE(1, "Last CPU thought to be offlined?"); return; /* Shouldn't happen: at least one CPU online. */ + } /* * Move tasks up to root rcu_node. Rely on the fact that the -- cgit v0.10.2 From 84e9dabf6e6a78928c6a1a8ba235c9fb0908d0f8 Mon Sep 17 00:00:00 2001 From: Anirban Sinha Date: Fri, 28 Aug 2009 22:40:43 -0700 Subject: sched: Rename init_cfs_rq => init_tg_cfs_rq ... so that it does not share a common name with a function within the same scope. Signed-off-by: Anirban Sinha LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 523e20a..6244d24 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -309,8 +309,8 @@ void set_tg_uid(struct user_struct *user) /* * Root task group. - * Every UID task group (including init_task_group aka UID-0) will - * be a child to this group. + * Every UID task group (including init_task_group aka UID-0) will + * be a child to this group. */ struct task_group root_task_group; @@ -318,7 +318,7 @@ struct task_group root_task_group; /* Default task group's sched entity on each cpu */ static DEFINE_PER_CPU(struct sched_entity, init_sched_entity); /* Default task group's cfs_rq on each cpu */ -static DEFINE_PER_CPU(struct cfs_rq, init_cfs_rq) ____cacheline_aligned_in_smp; +static DEFINE_PER_CPU(struct cfs_rq, init_tg_cfs_rq) ____cacheline_aligned_in_smp; #endif /* CONFIG_FAIR_GROUP_SCHED */ #ifdef CONFIG_RT_GROUP_SCHED @@ -9400,11 +9400,11 @@ void __init sched_init(void) * system cpu resource, based on the weight assigned to root * user's cpu share (INIT_TASK_GROUP_LOAD). This is accomplished * by letting tasks of init_task_group sit in a separate cfs_rq - * (init_cfs_rq) and having one entity represent this group of + * (init_tg_cfs_rq) and having one entity represent this group of * tasks in rq->cfs (i.e init_task_group->se[] != NULL). */ init_tg_cfs_entry(&init_task_group, - &per_cpu(init_cfs_rq, i), + &per_cpu(init_tg_cfs_rq, i), &per_cpu(init_sched_entity, i), i, 1, root_task_group.se[i]); -- cgit v0.10.2 From 372e24b0cb764ec55b4cf3408a95ae40a29e5b96 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 26 Aug 2009 16:20:13 -0700 Subject: irq: Make sure irq_desc for legacy irq get correct node setting when there is no ram on node 0. Signed-off-by: Yinghai Lu Cc: Andrew Morton Cc: Jesse Barnes LKML-Reference: <4A95C32D.5040605@kernel.org> Signed-off-by: Ingo Molnar diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 065205b..a81cf80 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -161,7 +161,7 @@ int __init early_irq_init(void) desc = irq_desc_legacy; legacy_count = ARRAY_SIZE(irq_desc_legacy); - node = first_online_node; + node = first_online_node; /* allocate irq_desc_ptrs array based on nr_irqs */ irq_desc_ptrs = kcalloc(nr_irqs, sizeof(void *), GFP_NOWAIT); @@ -172,6 +172,9 @@ int __init early_irq_init(void) for (i = 0; i < legacy_count; i++) { desc[i].irq = i; +#ifdef CONFIG_SMP + desc[i].node = node; +#endif desc[i].kstat_irqs = kstat_irqs_legacy + i * nr_cpu_ids; lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); alloc_desc_masks(&desc[i], node, true); -- cgit v0.10.2 From 5bfb5b51382f4bd01d9ced11503264d2cc74fe41 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 26 Aug 2009 16:20:48 -0700 Subject: irq: Add irq_node() primitive ... to return irq_desc node info without #ifdefs at the callsites. Signed-off-by: Yinghai Lu Cc: Andrew Morton Cc: Jesse Barnes LKML-Reference: <4A95C350.8060308@kernel.org> Signed-off-by: Ingo Molnar diff --git a/include/linux/irqnr.h b/include/linux/irqnr.h index ec87b21..7bf89bc 100644 --- a/include/linux/irqnr.h +++ b/include/linux/irqnr.h @@ -41,6 +41,12 @@ extern struct irq_desc *irq_to_desc(unsigned int irq); ; \ else +#ifdef CONFIG_SMP +#define irq_node(irq) (irq_to_desc(irq)->node) +#else +#define irq_node(irq) 0 +#endif + #endif /* CONFIG_GENERIC_HARDIRQS */ #define for_each_irq_nr(irq) \ -- cgit v0.10.2 From 70590ea75b7f9ef4846b0b0f4400e8338dbcc7eb Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 26 Aug 2009 16:21:54 -0700 Subject: pci/intr_remapping: Allocate irq_iommu on node make it use the node from irq_desc. Signed-off-by: Yinghai Lu Acked-by: Jesse Barnes Cc: Andrew Morton LKML-Reference: <4A95C392.5050903@kernel.org> Signed-off-by: Ingo Molnar diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 4f5b871..4480364 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c @@ -55,15 +55,12 @@ static struct irq_2_iommu *irq_2_iommu(unsigned int irq) return desc->irq_2_iommu; } -static struct irq_2_iommu *irq_2_iommu_alloc_node(unsigned int irq, int node) +static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) { struct irq_desc *desc; struct irq_2_iommu *irq_iommu; - /* - * alloc irq desc if not allocated already. - */ - desc = irq_to_desc_alloc_node(irq, node); + desc = irq_to_desc(irq); if (!desc) { printk(KERN_INFO "can not get irq_desc for %d\n", irq); return NULL; @@ -72,16 +69,11 @@ static struct irq_2_iommu *irq_2_iommu_alloc_node(unsigned int irq, int node) irq_iommu = desc->irq_2_iommu; if (!irq_iommu) - desc->irq_2_iommu = get_one_free_irq_2_iommu(node); + desc->irq_2_iommu = get_one_free_irq_2_iommu(irq_node(irq)); return desc->irq_2_iommu; } -static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) -{ - return irq_2_iommu_alloc_node(irq, cpu_to_node(boot_cpu_id)); -} - #else /* !CONFIG_SPARSE_IRQ */ static struct irq_2_iommu irq_2_iommuX[NR_IRQS]; -- cgit v0.10.2 From 0a9140cff22e405fce1747a2e02d41851c36c55a Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 12:27:50 +0000 Subject: tg3: Delay mdio bus init until fw finishes The device firmware uses the MDIO bus during early setup. If the driver modifies the MDIO bus configuration while it is in use by the firmware, any number of bad things can happen. This patch delays MDIO setup until after the firmware posts its magic signature, signifying initialization is complete. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 8af2cdf..ab3159e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6348,14 +6348,14 @@ static int tg3_chip_reset(struct tg3 *tp) tw32_f(MAC_MODE, 0); udelay(40); - tg3_mdio_start(tp); - tg3_ape_unlock(tp, TG3_APE_LOCK_GRC); err = tg3_poll_fw(tp); if (err) return err; + tg3_mdio_start(tp); + if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) { val = tr32(0x7c00); -- cgit v0.10.2 From 2befdcea96fcd9a13e94373c66ea1dd7365d2a74 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 12:28:45 +0000 Subject: tg3: Add new 5785 10/100 only device ID This patch adds a new device ID for those 5785 devices that will only use 10/100 phys. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ab3159e..d43b30b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -219,7 +219,8 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761S)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761SE)}, - {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5785_G)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5785_F)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57760)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790)}, diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 60b12ab..1c9495d 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -44,6 +44,8 @@ #define TG3PCI_DEVICE_TIGON3_57760 0x1690 #define TG3PCI_DEVICE_TIGON3_57790 0x1694 #define TG3PCI_DEVICE_TIGON3_57788 0x1691 +#define TG3PCI_DEVICE_TIGON3_5785_G 0x1699 /* GPHY */ +#define TG3PCI_DEVICE_TIGON3_5785_F 0x16a0 /* 10/100 only */ /* 0x04 --> 0x64 unused */ #define TG3PCI_MSI_DATA 0x00000064 /* 0x66 --> 0x68 unused */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index fdc3110..8549254 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2064,7 +2064,6 @@ #define PCI_DEVICE_ID_TIGON3_5787M 0x1693 #define PCI_DEVICE_ID_TIGON3_5782 0x1696 #define PCI_DEVICE_ID_TIGON3_5784 0x1698 -#define PCI_DEVICE_ID_TIGON3_5785 0x1699 #define PCI_DEVICE_ID_TIGON3_5786 0x169a #define PCI_DEVICE_ID_TIGON3_5787 0x169b #define PCI_DEVICE_ID_TIGON3_5788 0x169c -- cgit v0.10.2 From 8590a603e5e20ccf49d6cf0ea71ecf5388d1f9da Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 12:29:16 +0000 Subject: tg3: Reformat NVRAM case statements This patch fixes up the NVRAM detection switch statements to conform to the kernel coding style. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d43b30b..4c4d164 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10302,8 +10302,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) nvcfg1 = tr32(NVRAM_CFG1); if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) { tp->tg3_flags2 |= TG3_FLG2_FLASH; - } - else { + } else { nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; tw32(NVRAM_CFG1, nvcfg1); } @@ -10311,37 +10310,36 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { - case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - break; - case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->nvram_pagesize = ATMEL_AT25F512_PAGE_SIZE; - break; - case FLASH_VENDOR_ATMEL_EEPROM: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - break; - case FLASH_VENDOR_ST: - tp->nvram_jedecnum = JEDEC_ST; - tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - break; - case FLASH_VENDOR_SAIFUN: - tp->nvram_jedecnum = JEDEC_SAIFUN; - tp->nvram_pagesize = SAIFUN_SA25F0XX_PAGE_SIZE; - break; - case FLASH_VENDOR_SST_SMALL: - case FLASH_VENDOR_SST_LARGE: - tp->nvram_jedecnum = JEDEC_SST; - tp->nvram_pagesize = SST_25VF0X0_PAGE_SIZE; - break; + case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->nvram_pagesize = ATMEL_AT25F512_PAGE_SIZE; + break; + case FLASH_VENDOR_ATMEL_EEPROM: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_VENDOR_ST: + tp->nvram_jedecnum = JEDEC_ST; + tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_VENDOR_SAIFUN: + tp->nvram_jedecnum = JEDEC_SAIFUN; + tp->nvram_pagesize = SAIFUN_SA25F0XX_PAGE_SIZE; + break; + case FLASH_VENDOR_SST_SMALL: + case FLASH_VENDOR_SST_LARGE: + tp->nvram_jedecnum = JEDEC_SST; + tp->nvram_pagesize = SST_25VF0X0_PAGE_SIZE; + break; } - } - else { + } else { tp->nvram_jedecnum = JEDEC_ATMEL; tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; @@ -10359,48 +10357,47 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM; switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { - case FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ: - case FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - break; - case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - break; - case FLASH_5752VENDOR_ST_M45PE10: - case FLASH_5752VENDOR_ST_M45PE20: - case FLASH_5752VENDOR_ST_M45PE40: - tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - break; + case FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ: + case FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + break; + case FLASH_5752VENDOR_ST_M45PE10: + case FLASH_5752VENDOR_ST_M45PE20: + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + break; } if (tp->tg3_flags2 & TG3_FLG2_FLASH) { switch (nvcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) { - case FLASH_5752PAGE_SIZE_256: - tp->nvram_pagesize = 256; - break; - case FLASH_5752PAGE_SIZE_512: - tp->nvram_pagesize = 512; - break; - case FLASH_5752PAGE_SIZE_1K: - tp->nvram_pagesize = 1024; - break; - case FLASH_5752PAGE_SIZE_2K: - tp->nvram_pagesize = 2048; - break; - case FLASH_5752PAGE_SIZE_4K: - tp->nvram_pagesize = 4096; - break; - case FLASH_5752PAGE_SIZE_264: - tp->nvram_pagesize = 264; - break; + case FLASH_5752PAGE_SIZE_256: + tp->nvram_pagesize = 256; + break; + case FLASH_5752PAGE_SIZE_512: + tp->nvram_pagesize = 512; + break; + case FLASH_5752PAGE_SIZE_1K: + tp->nvram_pagesize = 1024; + break; + case FLASH_5752PAGE_SIZE_2K: + tp->nvram_pagesize = 2048; + break; + case FLASH_5752PAGE_SIZE_4K: + tp->nvram_pagesize = 4096; + break; + case FLASH_5752PAGE_SIZE_264: + tp->nvram_pagesize = 264; + break; } - } - else { + } else { /* For eeprom, set pagesize to maximum eeprom size */ tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; @@ -10423,45 +10420,45 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp) nvcfg1 &= NVRAM_CFG1_5752VENDOR_MASK; switch (nvcfg1) { - case FLASH_5755VENDOR_ATMEL_FLASH_1: - case FLASH_5755VENDOR_ATMEL_FLASH_2: - case FLASH_5755VENDOR_ATMEL_FLASH_3: - case FLASH_5755VENDOR_ATMEL_FLASH_5: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->nvram_pagesize = 264; - if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1 || - nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_5) - tp->nvram_size = (protect ? 0x3e200 : - TG3_NVRAM_SIZE_512KB); - else if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_2) - tp->nvram_size = (protect ? 0x1f200 : - TG3_NVRAM_SIZE_256KB); - else - tp->nvram_size = (protect ? 0x1f200 : - TG3_NVRAM_SIZE_128KB); - break; - case FLASH_5752VENDOR_ST_M45PE10: - case FLASH_5752VENDOR_ST_M45PE20: - case FLASH_5752VENDOR_ST_M45PE40: - tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->nvram_pagesize = 256; - if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10) - tp->nvram_size = (protect ? - TG3_NVRAM_SIZE_64KB : - TG3_NVRAM_SIZE_128KB); - else if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE20) - tp->nvram_size = (protect ? - TG3_NVRAM_SIZE_64KB : - TG3_NVRAM_SIZE_256KB); - else - tp->nvram_size = (protect ? - TG3_NVRAM_SIZE_128KB : - TG3_NVRAM_SIZE_512KB); - break; + case FLASH_5755VENDOR_ATMEL_FLASH_1: + case FLASH_5755VENDOR_ATMEL_FLASH_2: + case FLASH_5755VENDOR_ATMEL_FLASH_3: + case FLASH_5755VENDOR_ATMEL_FLASH_5: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 264; + if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1 || + nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_5) + tp->nvram_size = (protect ? 0x3e200 : + TG3_NVRAM_SIZE_512KB); + else if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_2) + tp->nvram_size = (protect ? 0x1f200 : + TG3_NVRAM_SIZE_256KB); + else + tp->nvram_size = (protect ? 0x1f200 : + TG3_NVRAM_SIZE_128KB); + break; + case FLASH_5752VENDOR_ST_M45PE10: + case FLASH_5752VENDOR_ST_M45PE20: + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 256; + if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10) + tp->nvram_size = (protect ? + TG3_NVRAM_SIZE_64KB : + TG3_NVRAM_SIZE_128KB); + else if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE20) + tp->nvram_size = (protect ? + TG3_NVRAM_SIZE_64KB : + TG3_NVRAM_SIZE_256KB); + else + tp->nvram_size = (protect ? + TG3_NVRAM_SIZE_128KB : + TG3_NVRAM_SIZE_512KB); + break; } } @@ -10472,34 +10469,34 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp) nvcfg1 = tr32(NVRAM_CFG1); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { - case FLASH_5787VENDOR_ATMEL_EEPROM_64KHZ: - case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ: - case FLASH_5787VENDOR_MICRO_EEPROM_64KHZ: - case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + case FLASH_5787VENDOR_ATMEL_EEPROM_64KHZ: + case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ: + case FLASH_5787VENDOR_MICRO_EEPROM_64KHZ: + case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; - nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; - tw32(NVRAM_CFG1, nvcfg1); - break; - case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: - case FLASH_5755VENDOR_ATMEL_FLASH_1: - case FLASH_5755VENDOR_ATMEL_FLASH_2: - case FLASH_5755VENDOR_ATMEL_FLASH_3: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->nvram_pagesize = 264; - break; - case FLASH_5752VENDOR_ST_M45PE10: - case FLASH_5752VENDOR_ST_M45PE20: - case FLASH_5752VENDOR_ST_M45PE40: - tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->nvram_pagesize = 256; - break; + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + break; + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: + case FLASH_5755VENDOR_ATMEL_FLASH_1: + case FLASH_5755VENDOR_ATMEL_FLASH_2: + case FLASH_5755VENDOR_ATMEL_FLASH_3: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 264; + break; + case FLASH_5752VENDOR_ST_M45PE10: + case FLASH_5752VENDOR_ST_M45PE20: + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 256; + break; } } @@ -10517,63 +10514,63 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) nvcfg1 &= NVRAM_CFG1_5752VENDOR_MASK; switch (nvcfg1) { - case FLASH_5761VENDOR_ATMEL_ADB021D: - case FLASH_5761VENDOR_ATMEL_ADB041D: - case FLASH_5761VENDOR_ATMEL_ADB081D: - case FLASH_5761VENDOR_ATMEL_ADB161D: - case FLASH_5761VENDOR_ATMEL_MDB021D: - case FLASH_5761VENDOR_ATMEL_MDB041D: - case FLASH_5761VENDOR_ATMEL_MDB081D: - case FLASH_5761VENDOR_ATMEL_MDB161D: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 256; - break; - case FLASH_5761VENDOR_ST_A_M45PE20: - case FLASH_5761VENDOR_ST_A_M45PE40: - case FLASH_5761VENDOR_ST_A_M45PE80: - case FLASH_5761VENDOR_ST_A_M45PE16: - case FLASH_5761VENDOR_ST_M_M45PE20: - case FLASH_5761VENDOR_ST_M_M45PE40: - case FLASH_5761VENDOR_ST_M_M45PE80: - case FLASH_5761VENDOR_ST_M_M45PE16: - tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->nvram_pagesize = 256; - break; + case FLASH_5761VENDOR_ATMEL_ADB021D: + case FLASH_5761VENDOR_ATMEL_ADB041D: + case FLASH_5761VENDOR_ATMEL_ADB081D: + case FLASH_5761VENDOR_ATMEL_ADB161D: + case FLASH_5761VENDOR_ATMEL_MDB021D: + case FLASH_5761VENDOR_ATMEL_MDB041D: + case FLASH_5761VENDOR_ATMEL_MDB081D: + case FLASH_5761VENDOR_ATMEL_MDB161D: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 256; + break; + case FLASH_5761VENDOR_ST_A_M45PE20: + case FLASH_5761VENDOR_ST_A_M45PE40: + case FLASH_5761VENDOR_ST_A_M45PE80: + case FLASH_5761VENDOR_ST_A_M45PE16: + case FLASH_5761VENDOR_ST_M_M45PE20: + case FLASH_5761VENDOR_ST_M_M45PE40: + case FLASH_5761VENDOR_ST_M_M45PE80: + case FLASH_5761VENDOR_ST_M_M45PE16: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 256; + break; } if (protect) { tp->nvram_size = tr32(NVRAM_ADDR_LOCKOUT); } else { switch (nvcfg1) { - case FLASH_5761VENDOR_ATMEL_ADB161D: - case FLASH_5761VENDOR_ATMEL_MDB161D: - case FLASH_5761VENDOR_ST_A_M45PE16: - case FLASH_5761VENDOR_ST_M_M45PE16: - tp->nvram_size = TG3_NVRAM_SIZE_2MB; - break; - case FLASH_5761VENDOR_ATMEL_ADB081D: - case FLASH_5761VENDOR_ATMEL_MDB081D: - case FLASH_5761VENDOR_ST_A_M45PE80: - case FLASH_5761VENDOR_ST_M_M45PE80: - tp->nvram_size = TG3_NVRAM_SIZE_1MB; - break; - case FLASH_5761VENDOR_ATMEL_ADB041D: - case FLASH_5761VENDOR_ATMEL_MDB041D: - case FLASH_5761VENDOR_ST_A_M45PE40: - case FLASH_5761VENDOR_ST_M_M45PE40: - tp->nvram_size = TG3_NVRAM_SIZE_512KB; - break; - case FLASH_5761VENDOR_ATMEL_ADB021D: - case FLASH_5761VENDOR_ATMEL_MDB021D: - case FLASH_5761VENDOR_ST_A_M45PE20: - case FLASH_5761VENDOR_ST_M_M45PE20: - tp->nvram_size = TG3_NVRAM_SIZE_256KB; - break; + case FLASH_5761VENDOR_ATMEL_ADB161D: + case FLASH_5761VENDOR_ATMEL_MDB161D: + case FLASH_5761VENDOR_ST_A_M45PE16: + case FLASH_5761VENDOR_ST_M_M45PE16: + tp->nvram_size = TG3_NVRAM_SIZE_2MB; + break; + case FLASH_5761VENDOR_ATMEL_ADB081D: + case FLASH_5761VENDOR_ATMEL_MDB081D: + case FLASH_5761VENDOR_ST_A_M45PE80: + case FLASH_5761VENDOR_ST_M_M45PE80: + tp->nvram_size = TG3_NVRAM_SIZE_1MB; + break; + case FLASH_5761VENDOR_ATMEL_ADB041D: + case FLASH_5761VENDOR_ATMEL_MDB041D: + case FLASH_5761VENDOR_ST_A_M45PE40: + case FLASH_5761VENDOR_ST_M_M45PE40: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + case FLASH_5761VENDOR_ATMEL_ADB021D: + case FLASH_5761VENDOR_ATMEL_MDB021D: + case FLASH_5761VENDOR_ST_A_M45PE20: + case FLASH_5761VENDOR_ST_M_M45PE20: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; } } } -- cgit v0.10.2 From fdb72b38c94c0ead1f78ecc8db64b832feda22c3 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 13:57:12 +0000 Subject: tg3: Break out mini producer ring handling This patch separates the code that sets up the mini producer ring from the code that sets up the jumbo producer rings. The 5717 asic rev devices do not have a mini ring, but do have a jumbo frame implementation similar to the 5704 and previous devices. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4c4d164..606703c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6967,19 +6967,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC); - /* Don't even try to program the JUMBO/MINI buffer descriptor - * configs on 5705. - */ - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { - tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, - RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT); - } else { - tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, - RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT); - + /* Disable the mini ring */ + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED); + /* Program the jumbo buffer descriptor ring control + * blocks on those devices that have them. + */ + if ((tp->tg3_flags2 & TG3_FLG2_JUMBO_CAPABLE) && + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { /* Setup replenish threshold. */ tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8); @@ -6997,7 +6994,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_DISABLED); } - } + val = RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT; + } else + val = RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT; + + tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, val); /* There is only one send ring on 5705/5750, no need to explicitly * disable the others. -- cgit v0.10.2 From 8f666b07ac53eeedd6c035adf6d4299f9ed0df2d Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 13:58:24 +0000 Subject: tg3: Move the JUMBO_CAPABLE and SUPPORT_MSI flags This patch moves where the jumbo capable and msi support flags are located. This is prep work for the addition of msix support flags. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 606703c..5e74a19 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -92,7 +92,7 @@ /* hardware minimum and maximum for a single frame's data payload */ #define TG3_MIN_MTU 60 #define TG3_MAX_MTU(tp) \ - ((tp->tg3_flags2 & TG3_FLG2_JUMBO_CAPABLE) ? 9000 : 1500) + ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) ? 9000 : 1500) /* These numbers seem to be hard coded in the NIC firmware somehow. * You can't change the ring sizes, but you can change where you place @@ -1921,7 +1921,7 @@ out: if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { /* Cannot do read-modify-write on 5401 */ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20); - } else if (tp->tg3_flags2 & TG3_FLG2_JUMBO_CAPABLE) { + } else if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { u32 phy_reg; /* Set bit 14 with read-modify-write to preserve other bits */ @@ -1933,7 +1933,7 @@ out: /* Set phy register 0x10 bit 0 to high fifo elasticity to support * jumbo frames transmission. */ - if (tp->tg3_flags2 & TG3_FLG2_JUMBO_CAPABLE) { + if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { u32 phy_reg; if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &phy_reg)) @@ -6975,7 +6975,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* Program the jumbo buffer descriptor ring control * blocks on those devices that have them. */ - if ((tp->tg3_flags2 & TG3_FLG2_JUMBO_CAPABLE) && + if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { /* Setup replenish threshold. */ tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8); @@ -12034,7 +12034,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) - tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; + tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE; pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 1c9495d..5efae2c 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2601,6 +2601,7 @@ struct tg3 { #define TG3_FLAG_EEPROM_WRITE_PROT 0x00001000 #define TG3_FLAG_NVRAM 0x00002000 #define TG3_FLAG_NVRAM_BUFFERED 0x00004000 +#define TG3_FLAG_SUPPORT_MSI 0x00008000 #define TG3_FLAG_PCIX_MODE 0x00020000 #define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 #define TG3_FLAG_PCI_32BIT 0x00080000 @@ -2613,7 +2614,7 @@ struct tg3 { #define TG3_FLAG_CPMU_PRESENT 0x04000000 #define TG3_FLAG_40BIT_DMA_BUG 0x08000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 -#define TG3_FLAG_SUPPORT_MSI 0x20000000 +#define TG3_FLAG_JUMBO_CAPABLE 0x20000000 #define TG3_FLAG_CHIP_RESETTING 0x40000000 #define TG3_FLAG_INIT_COMPLETE 0x80000000 u32 tg3_flags2; @@ -2639,7 +2640,6 @@ struct tg3 { #define TG3_FLG2_5750_PLUS 0x00080000 #define TG3_FLG2_PROTECTED_NVRAM 0x00100000 #define TG3_FLG2_USING_MSI 0x00200000 -#define TG3_FLG2_JUMBO_CAPABLE 0x00400000 #define TG3_FLG2_MII_SERDES 0x00800000 #define TG3_FLG2_ANY_SERDES (TG3_FLG2_PHY_SERDES | \ TG3_FLG2_MII_SERDES) -- cgit v0.10.2 From 287be12e1774d842bff21ea0c1809c2387d7b310 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 13:58:46 +0000 Subject: tg3: Clarify rx buffer relationships This patch attempts to document the various rx buffer sizes used by the driver and how they relate to each other. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5e74a19..a2a5f31 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -125,8 +125,15 @@ TG3_TX_RING_SIZE) #define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1)) -#define RX_PKT_BUF_SZ (1536 + tp->rx_offset + 64) -#define RX_JUMBO_PKT_BUF_SZ (9046 + tp->rx_offset + 64) +#define TG3_DMA_BYTE_ENAB 64 + +#define TG3_RX_STD_DMA_SZ 1536 +#define TG3_RX_JMB_DMA_SZ 9046 + +#define TG3_RX_DMA_TO_MAP_SZ(x) ((x) + TG3_DMA_BYTE_ENAB) + +#define TG3_RX_STD_MAP_SZ TG3_RX_DMA_TO_MAP_SZ(TG3_RX_STD_DMA_SZ) +#define TG3_RX_JMB_MAP_SZ TG3_RX_DMA_TO_MAP_SZ(TG3_RX_JMB_DMA_SZ) /* minimum number of free TX descriptors required to wake up TX process */ #define TG3_TX_WAKEUP_THRESH(tp) ((tp)->tx_pending / 4) @@ -4354,7 +4361,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, map = &tp->rx_std_buffers[dest_idx]; if (src_idx >= 0) src_map = &tp->rx_std_buffers[src_idx]; - skb_size = tp->rx_pkt_buf_sz; + skb_size = tp->rx_pkt_map_sz; break; case RXD_OPAQUE_RING_JUMBO: @@ -4363,7 +4370,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, map = &tp->rx_jumbo_buffers[dest_idx]; if (src_idx >= 0) src_map = &tp->rx_jumbo_buffers[src_idx]; - skb_size = RX_JUMBO_PKT_BUF_SZ; + skb_size = TG3_RX_JMB_MAP_SZ; break; default: @@ -4376,14 +4383,13 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, * Callers depend upon this behavior and assume that * we leave everything unchanged if we fail. */ - skb = netdev_alloc_skb(tp->dev, skb_size); + skb = netdev_alloc_skb(tp->dev, skb_size + tp->rx_offset); if (skb == NULL) return -ENOMEM; skb_reserve(skb, tp->rx_offset); - mapping = pci_map_single(tp->pdev, skb->data, - skb_size - tp->rx_offset, + mapping = pci_map_single(tp->pdev, skb->data, skb_size, PCI_DMA_FROMDEVICE); map->skb = skb; @@ -4540,8 +4546,7 @@ static int tg3_rx(struct tg3 *tp, int budget) if (skb_size < 0) goto drop_it; - pci_unmap_single(tp->pdev, dma_addr, - skb_size - tp->rx_offset, + pci_unmap_single(tp->pdev, dma_addr, skb_size, PCI_DMA_FROMDEVICE); skb_put(skb, len); @@ -5531,7 +5536,7 @@ static void tg3_free_rings(struct tg3 *tp) continue; pci_unmap_single(tp->pdev, pci_unmap_addr(rxp, mapping), - tp->rx_pkt_buf_sz - tp->rx_offset, + tp->rx_pkt_map_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(rxp->skb); rxp->skb = NULL; @@ -5544,7 +5549,7 @@ static void tg3_free_rings(struct tg3 *tp) continue; pci_unmap_single(tp->pdev, pci_unmap_addr(rxp, mapping), - RX_JUMBO_PKT_BUF_SZ - tp->rx_offset, + TG3_RX_JMB_MAP_SZ, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(rxp->skb); rxp->skb = NULL; @@ -5581,7 +5586,7 @@ static void tg3_free_rings(struct tg3 *tp) */ static int tg3_init_rings(struct tg3 *tp) { - u32 i; + u32 i, rx_pkt_dma_sz; /* Free up all the SKBs. */ tg3_free_rings(tp); @@ -5592,10 +5597,11 @@ static int tg3_init_rings(struct tg3 *tp) memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); - tp->rx_pkt_buf_sz = RX_PKT_BUF_SZ; + rx_pkt_dma_sz = TG3_RX_STD_DMA_SZ; if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && - (tp->dev->mtu > ETH_DATA_LEN)) - tp->rx_pkt_buf_sz = RX_JUMBO_PKT_BUF_SZ; + tp->dev->mtu > ETH_DATA_LEN) + rx_pkt_dma_sz = TG3_RX_JMB_DMA_SZ; + tp->rx_pkt_map_sz = TG3_RX_DMA_TO_MAP_SZ(rx_pkt_dma_sz); /* Initialize invariants of the rings, we only set this * stuff once. This works because the card does not @@ -5605,8 +5611,7 @@ static int tg3_init_rings(struct tg3 *tp) struct tg3_rx_buffer_desc *rxd; rxd = &tp->rx_std[i]; - rxd->idx_len = (tp->rx_pkt_buf_sz - tp->rx_offset - 64) - << RXD_LEN_SHIFT; + rxd->idx_len = rx_pkt_dma_sz << RXD_LEN_SHIFT; rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT); rxd->opaque = (RXD_OPAQUE_RING_STD | (i << RXD_OPAQUE_INDEX_SHIFT)); @@ -5617,8 +5622,7 @@ static int tg3_init_rings(struct tg3 *tp) struct tg3_rx_buffer_desc *rxd; rxd = &tp->rx_jumbo[i]; - rxd->idx_len = (RX_JUMBO_PKT_BUF_SZ - tp->rx_offset - 64) - << RXD_LEN_SHIFT; + rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT; rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | RXD_FLAG_JUMBO; rxd->opaque = (RXD_OPAQUE_RING_JUMBO | diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 5efae2c..d029b4b 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2571,7 +2571,7 @@ struct tg3 { struct tg3_rx_buffer_desc *rx_rcb; dma_addr_t rx_rcb_mapping; - u32 rx_pkt_buf_sz; + u32 rx_pkt_map_sz; /* begin "everything else" cacheline(s) section */ struct net_device_stats net_stats; -- cgit v0.10.2 From cf7a7298c4f47ab7546b933bb54ad3ea03a1daf6 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 13:59:57 +0000 Subject: tg3: Create rx producer ring setup routines Later patches are going to complicate the ring initialization routines. This patch breaks out the setup and teardown of the rx producer rings into separate functions to make the code more readable. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a2a5f31..5d0a1e6e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5517,14 +5517,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) return err; } -/* Free up pending packets in all rx/tx rings. - * - * The chip has been shut down and the driver detached from - * the networking, so no interrupts or new tx packets will - * end up in the driver. tp->{tx,}lock is not held and we are not - * in an interrupt context and thus may sleep. - */ -static void tg3_free_rings(struct tg3 *tp) +static void tg3_rx_prodring_free(struct tg3 *tp) { struct ring_info *rxp; int i; @@ -5534,46 +5527,29 @@ static void tg3_free_rings(struct tg3 *tp) if (rxp->skb == NULL) continue; - pci_unmap_single(tp->pdev, - pci_unmap_addr(rxp, mapping), - tp->rx_pkt_map_sz, - PCI_DMA_FROMDEVICE); - dev_kfree_skb_any(rxp->skb); - rxp->skb = NULL; - } - - for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { - rxp = &tp->rx_jumbo_buffers[i]; - if (rxp->skb == NULL) - continue; pci_unmap_single(tp->pdev, pci_unmap_addr(rxp, mapping), - TG3_RX_JMB_MAP_SZ, + tp->rx_pkt_map_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(rxp->skb); rxp->skb = NULL; } - for (i = 0; i < TG3_TX_RING_SIZE; ) { - struct tx_ring_info *txp; - struct sk_buff *skb; + if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { + for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { + rxp = &tp->rx_jumbo_buffers[i]; - txp = &tp->tx_buffers[i]; - skb = txp->skb; + if (rxp->skb == NULL) + continue; - if (skb == NULL) { - i++; - continue; + pci_unmap_single(tp->pdev, + pci_unmap_addr(rxp, mapping), + TG3_RX_JMB_MAP_SZ, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(rxp->skb); + rxp->skb = NULL; } - - skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); - - txp->skb = NULL; - - i += skb_shinfo(skb)->nr_frags + 1; - - dev_kfree_skb_any(skb); } } @@ -5584,18 +5560,12 @@ static void tg3_free_rings(struct tg3 *tp) * end up in the driver. tp->{tx,}lock are held and thus * we may not sleep. */ -static int tg3_init_rings(struct tg3 *tp) +static int tg3_rx_prodring_alloc(struct tg3 *tp) { u32 i, rx_pkt_dma_sz; - /* Free up all the SKBs. */ - tg3_free_rings(tp); - /* Zero out all descriptors. */ memset(tp->rx_std, 0, TG3_RX_RING_BYTES); - memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES); - memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); - memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); rx_pkt_dma_sz = TG3_RX_STD_DMA_SZ; if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && @@ -5617,19 +5587,6 @@ static int tg3_init_rings(struct tg3 *tp) (i << RXD_OPAQUE_INDEX_SHIFT)); } - if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { - for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { - struct tg3_rx_buffer_desc *rxd; - - rxd = &tp->rx_jumbo[i]; - rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT; - rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | - RXD_FLAG_JUMBO; - rxd->opaque = (RXD_OPAQUE_RING_JUMBO | - (i << RXD_OPAQUE_INDEX_SHIFT)); - } - } - /* Now allocate fresh SKBs for each rx ring. */ for (i = 0; i < tp->rx_pending; i++) { if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD, -1, i) < 0) { @@ -5639,13 +5596,29 @@ static int tg3_init_rings(struct tg3 *tp) "successfully.\n", tp->dev->name, i, tp->rx_pending); if (i == 0) - return -ENOMEM; + goto initfail; tp->rx_pending = i; break; } } + if (!(tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE)) + goto done; + + memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES); + if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { + for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { + struct tg3_rx_buffer_desc *rxd; + + rxd = &tp->rx_jumbo[i]; + rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT; + rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | + RXD_FLAG_JUMBO; + rxd->opaque = (RXD_OPAQUE_RING_JUMBO | + (i << RXD_OPAQUE_INDEX_SHIFT)); + } + for (i = 0; i < tp->rx_jumbo_pending; i++) { if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO, -1, i) < 0) { @@ -5654,26 +5627,28 @@ static int tg3_init_rings(struct tg3 *tp) "only %d out of %d buffers were " "allocated successfully.\n", tp->dev->name, i, tp->rx_jumbo_pending); - if (i == 0) { - tg3_free_rings(tp); - return -ENOMEM; - } + if (i == 0) + goto initfail; tp->rx_jumbo_pending = i; break; } } } + +done: return 0; + +initfail: + tg3_rx_prodring_free(tp); + return -ENOMEM; } -/* - * Must not be invoked with interrupt sources disabled and - * the hardware shutdown down. - */ -static void tg3_free_consistent(struct tg3 *tp) +static void tg3_rx_prodring_fini(struct tg3 *tp) { kfree(tp->rx_std_buffers); tp->rx_std_buffers = NULL; + kfree(tp->rx_jumbo_buffers); + tp->rx_jumbo_buffers = NULL; if (tp->rx_std) { pci_free_consistent(tp->pdev, TG3_RX_RING_BYTES, tp->rx_std, tp->rx_std_mapping); @@ -5684,6 +5659,103 @@ static void tg3_free_consistent(struct tg3 *tp) tp->rx_jumbo, tp->rx_jumbo_mapping); tp->rx_jumbo = NULL; } +} + +static int tg3_rx_prodring_init(struct tg3 *tp) +{ + tp->rx_std_buffers = kzalloc(sizeof(struct ring_info) * + TG3_RX_RING_SIZE, GFP_KERNEL); + if (!tp->rx_std_buffers) + return -ENOMEM; + + tp->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES, + &tp->rx_std_mapping); + if (!tp->rx_std) + goto err_out; + + if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { + tp->rx_jumbo_buffers = kzalloc(sizeof(struct ring_info) * + TG3_RX_JUMBO_RING_SIZE, + GFP_KERNEL); + if (!tp->rx_jumbo_buffers) + goto err_out; + + tp->rx_jumbo = pci_alloc_consistent(tp->pdev, + TG3_RX_JUMBO_RING_BYTES, + &tp->rx_jumbo_mapping); + if (!tp->rx_jumbo) + goto err_out; + } + + return 0; + +err_out: + tg3_rx_prodring_fini(tp); + return -ENOMEM; +} + +/* Free up pending packets in all rx/tx rings. + * + * The chip has been shut down and the driver detached from + * the networking, so no interrupts or new tx packets will + * end up in the driver. tp->{tx,}lock is not held and we are not + * in an interrupt context and thus may sleep. + */ +static void tg3_free_rings(struct tg3 *tp) +{ + int i; + + for (i = 0; i < TG3_TX_RING_SIZE; ) { + struct tx_ring_info *txp; + struct sk_buff *skb; + + txp = &tp->tx_buffers[i]; + skb = txp->skb; + + if (skb == NULL) { + i++; + continue; + } + + skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); + + txp->skb = NULL; + + i += skb_shinfo(skb)->nr_frags + 1; + + dev_kfree_skb_any(skb); + } + + tg3_rx_prodring_free(tp); +} + +/* Initialize tx/rx rings for packet processing. + * + * The chip has been shut down and the driver detached from + * the networking, so no interrupts or new tx packets will + * end up in the driver. tp->{tx,}lock are held and thus + * we may not sleep. + */ +static int tg3_init_rings(struct tg3 *tp) +{ + /* Free up all the SKBs. */ + tg3_free_rings(tp); + + /* Zero out all descriptors. */ + memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); + + return tg3_rx_prodring_alloc(tp); +} + +/* + * Must not be invoked with interrupt sources disabled and + * the hardware shutdown down. + */ +static void tg3_free_consistent(struct tg3 *tp) +{ + kfree(tp->tx_buffers); + tp->tx_buffers = NULL; if (tp->rx_rcb) { pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), tp->rx_rcb, tp->rx_rcb_mapping); @@ -5704,6 +5776,7 @@ static void tg3_free_consistent(struct tg3 *tp) tp->hw_stats, tp->stats_mapping); tp->hw_stats = NULL; } + tg3_rx_prodring_fini(tp); } /* @@ -5712,28 +5785,12 @@ static void tg3_free_consistent(struct tg3 *tp) */ static int tg3_alloc_consistent(struct tg3 *tp) { - tp->rx_std_buffers = kzalloc((sizeof(struct ring_info) * - (TG3_RX_RING_SIZE + - TG3_RX_JUMBO_RING_SIZE)) + - (sizeof(struct tx_ring_info) * - TG3_TX_RING_SIZE), - GFP_KERNEL); - if (!tp->rx_std_buffers) + if (tg3_rx_prodring_init(tp)) return -ENOMEM; - tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE]; - tp->tx_buffers = (struct tx_ring_info *) - &tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE]; - - tp->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES, - &tp->rx_std_mapping); - if (!tp->rx_std) - goto err_out; - - tp->rx_jumbo = pci_alloc_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES, - &tp->rx_jumbo_mapping); - - if (!tp->rx_jumbo) + tp->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * + TG3_TX_RING_SIZE, GFP_KERNEL); + if (!tp->tx_buffers) goto err_out; tp->rx_rcb = pci_alloc_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), -- cgit v0.10.2 From 21f581a5366d48d86b9ae86043fc61d44e992c0c Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:00:25 +0000 Subject: tg3: Create a new prodring_set structure This patch migrates most of the rx producer ring variables to a new tg3_rx_prodring_set structure and modifies the code accordingly. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5d0a1e6e..053d4e8 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4352,24 +4352,25 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, struct sk_buff *skb; dma_addr_t mapping; int skb_size, dest_idx; + struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; src_map = NULL; switch (opaque_key) { case RXD_OPAQUE_RING_STD: dest_idx = dest_idx_unmasked % TG3_RX_RING_SIZE; - desc = &tp->rx_std[dest_idx]; - map = &tp->rx_std_buffers[dest_idx]; + desc = &tpr->rx_std[dest_idx]; + map = &tpr->rx_std_buffers[dest_idx]; if (src_idx >= 0) - src_map = &tp->rx_std_buffers[src_idx]; + src_map = &tpr->rx_std_buffers[src_idx]; skb_size = tp->rx_pkt_map_sz; break; case RXD_OPAQUE_RING_JUMBO: dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE; - desc = &tp->rx_jumbo[dest_idx]; - map = &tp->rx_jumbo_buffers[dest_idx]; + desc = &tpr->rx_jmb[dest_idx]; + map = &tpr->rx_jmb_buffers[dest_idx]; if (src_idx >= 0) - src_map = &tp->rx_jumbo_buffers[src_idx]; + src_map = &tpr->rx_jmb_buffers[src_idx]; skb_size = TG3_RX_JMB_MAP_SZ; break; @@ -4414,22 +4415,23 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, struct tg3_rx_buffer_desc *src_desc, *dest_desc; struct ring_info *src_map, *dest_map; int dest_idx; + struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; switch (opaque_key) { case RXD_OPAQUE_RING_STD: dest_idx = dest_idx_unmasked % TG3_RX_RING_SIZE; - dest_desc = &tp->rx_std[dest_idx]; - dest_map = &tp->rx_std_buffers[dest_idx]; - src_desc = &tp->rx_std[src_idx]; - src_map = &tp->rx_std_buffers[src_idx]; + dest_desc = &tpr->rx_std[dest_idx]; + dest_map = &tpr->rx_std_buffers[dest_idx]; + src_desc = &tpr->rx_std[src_idx]; + src_map = &tpr->rx_std_buffers[src_idx]; break; case RXD_OPAQUE_RING_JUMBO: dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE; - dest_desc = &tp->rx_jumbo[dest_idx]; - dest_map = &tp->rx_jumbo_buffers[dest_idx]; - src_desc = &tp->rx_jumbo[src_idx]; - src_map = &tp->rx_jumbo_buffers[src_idx]; + dest_desc = &tpr->rx_jmb[dest_idx]; + dest_map = &tpr->rx_jmb_buffers[dest_idx]; + src_desc = &tpr->rx_jmb[src_idx]; + src_map = &tpr->rx_jmb_buffers[src_idx]; break; default: @@ -4482,6 +4484,7 @@ static int tg3_rx(struct tg3 *tp, int budget) u32 sw_idx = tp->rx_rcb_ptr; u16 hw_idx; int received; + struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; hw_idx = tp->hw_status->idx[0].rx_producer; /* @@ -4501,20 +4504,18 @@ static int tg3_rx(struct tg3 *tp, int budget) desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; if (opaque_key == RXD_OPAQUE_RING_STD) { - dma_addr = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], - mapping); - skb = tp->rx_std_buffers[desc_idx].skb; - post_ptr = &tp->rx_std_ptr; + struct ring_info *ri = &tpr->rx_std_buffers[desc_idx]; + dma_addr = pci_unmap_addr(ri, mapping); + skb = ri->skb; + post_ptr = &tpr->rx_std_ptr; rx_std_posted++; } else if (opaque_key == RXD_OPAQUE_RING_JUMBO) { - dma_addr = pci_unmap_addr(&tp->rx_jumbo_buffers[desc_idx], - mapping); - skb = tp->rx_jumbo_buffers[desc_idx].skb; - post_ptr = &tp->rx_jumbo_ptr; - } - else { + struct ring_info *ri = &tpr->rx_jmb_buffers[desc_idx]; + dma_addr = pci_unmap_addr(ri, mapping); + skb = ri->skb; + post_ptr = &tpr->rx_jmb_ptr; + } else goto next_pkt_nopost; - } work_mask |= opaque_key; @@ -4627,12 +4628,12 @@ next_pkt_nopost: /* Refill RX ring(s). */ if (work_mask & RXD_OPAQUE_RING_STD) { - sw_idx = tp->rx_std_ptr % TG3_RX_RING_SIZE; + sw_idx = tpr->rx_std_ptr % TG3_RX_RING_SIZE; tw32_rx_mbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, sw_idx); } if (work_mask & RXD_OPAQUE_RING_JUMBO) { - sw_idx = tp->rx_jumbo_ptr % TG3_RX_JUMBO_RING_SIZE; + sw_idx = tpr->rx_jmb_ptr % TG3_RX_JUMBO_RING_SIZE; tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, sw_idx); } @@ -5517,13 +5518,14 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) return err; } -static void tg3_rx_prodring_free(struct tg3 *tp) +static void tg3_rx_prodring_free(struct tg3 *tp, + struct tg3_rx_prodring_set *tpr) { struct ring_info *rxp; int i; for (i = 0; i < TG3_RX_RING_SIZE; i++) { - rxp = &tp->rx_std_buffers[i]; + rxp = &tpr->rx_std_buffers[i]; if (rxp->skb == NULL) continue; @@ -5538,7 +5540,7 @@ static void tg3_rx_prodring_free(struct tg3 *tp) if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { - rxp = &tp->rx_jumbo_buffers[i]; + rxp = &tpr->rx_jmb_buffers[i]; if (rxp->skb == NULL) continue; @@ -5560,12 +5562,13 @@ static void tg3_rx_prodring_free(struct tg3 *tp) * end up in the driver. tp->{tx,}lock are held and thus * we may not sleep. */ -static int tg3_rx_prodring_alloc(struct tg3 *tp) +static int tg3_rx_prodring_alloc(struct tg3 *tp, + struct tg3_rx_prodring_set *tpr) { u32 i, rx_pkt_dma_sz; /* Zero out all descriptors. */ - memset(tp->rx_std, 0, TG3_RX_RING_BYTES); + memset(tpr->rx_std, 0, TG3_RX_RING_BYTES); rx_pkt_dma_sz = TG3_RX_STD_DMA_SZ; if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && @@ -5580,7 +5583,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp) for (i = 0; i < TG3_RX_RING_SIZE; i++) { struct tg3_rx_buffer_desc *rxd; - rxd = &tp->rx_std[i]; + rxd = &tpr->rx_std[i]; rxd->idx_len = rx_pkt_dma_sz << RXD_LEN_SHIFT; rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT); rxd->opaque = (RXD_OPAQUE_RING_STD | @@ -5605,13 +5608,13 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp) if (!(tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE)) goto done; - memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES); + memset(tpr->rx_jmb, 0, TG3_RX_JUMBO_RING_BYTES); if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { struct tg3_rx_buffer_desc *rxd; - rxd = &tp->rx_jumbo[i]; + rxd = &tpr->rx_jmb[i]; rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT; rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | RXD_FLAG_JUMBO; @@ -5639,58 +5642,60 @@ done: return 0; initfail: - tg3_rx_prodring_free(tp); + tg3_rx_prodring_free(tp, tpr); return -ENOMEM; } -static void tg3_rx_prodring_fini(struct tg3 *tp) +static void tg3_rx_prodring_fini(struct tg3 *tp, + struct tg3_rx_prodring_set *tpr) { - kfree(tp->rx_std_buffers); - tp->rx_std_buffers = NULL; - kfree(tp->rx_jumbo_buffers); - tp->rx_jumbo_buffers = NULL; - if (tp->rx_std) { + kfree(tpr->rx_std_buffers); + tpr->rx_std_buffers = NULL; + kfree(tpr->rx_jmb_buffers); + tpr->rx_jmb_buffers = NULL; + if (tpr->rx_std) { pci_free_consistent(tp->pdev, TG3_RX_RING_BYTES, - tp->rx_std, tp->rx_std_mapping); - tp->rx_std = NULL; + tpr->rx_std, tpr->rx_std_mapping); + tpr->rx_std = NULL; } - if (tp->rx_jumbo) { + if (tpr->rx_jmb) { pci_free_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES, - tp->rx_jumbo, tp->rx_jumbo_mapping); - tp->rx_jumbo = NULL; + tpr->rx_jmb, tpr->rx_jmb_mapping); + tpr->rx_jmb = NULL; } } -static int tg3_rx_prodring_init(struct tg3 *tp) +static int tg3_rx_prodring_init(struct tg3 *tp, + struct tg3_rx_prodring_set *tpr) { - tp->rx_std_buffers = kzalloc(sizeof(struct ring_info) * - TG3_RX_RING_SIZE, GFP_KERNEL); - if (!tp->rx_std_buffers) + tpr->rx_std_buffers = kzalloc(sizeof(struct ring_info) * + TG3_RX_RING_SIZE, GFP_KERNEL); + if (!tpr->rx_std_buffers) return -ENOMEM; - tp->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES, - &tp->rx_std_mapping); - if (!tp->rx_std) + tpr->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES, + &tpr->rx_std_mapping); + if (!tpr->rx_std) goto err_out; if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { - tp->rx_jumbo_buffers = kzalloc(sizeof(struct ring_info) * - TG3_RX_JUMBO_RING_SIZE, - GFP_KERNEL); - if (!tp->rx_jumbo_buffers) + tpr->rx_jmb_buffers = kzalloc(sizeof(struct ring_info) * + TG3_RX_JUMBO_RING_SIZE, + GFP_KERNEL); + if (!tpr->rx_jmb_buffers) goto err_out; - tp->rx_jumbo = pci_alloc_consistent(tp->pdev, - TG3_RX_JUMBO_RING_BYTES, - &tp->rx_jumbo_mapping); - if (!tp->rx_jumbo) + tpr->rx_jmb = pci_alloc_consistent(tp->pdev, + TG3_RX_JUMBO_RING_BYTES, + &tpr->rx_jmb_mapping); + if (!tpr->rx_jmb) goto err_out; } return 0; err_out: - tg3_rx_prodring_fini(tp); + tg3_rx_prodring_fini(tp, tpr); return -ENOMEM; } @@ -5726,7 +5731,7 @@ static void tg3_free_rings(struct tg3 *tp) dev_kfree_skb_any(skb); } - tg3_rx_prodring_free(tp); + tg3_rx_prodring_free(tp, &tp->prodring[0]); } /* Initialize tx/rx rings for packet processing. @@ -5745,7 +5750,7 @@ static int tg3_init_rings(struct tg3 *tp) memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); - return tg3_rx_prodring_alloc(tp); + return tg3_rx_prodring_alloc(tp, &tp->prodring[0]); } /* @@ -5776,7 +5781,7 @@ static void tg3_free_consistent(struct tg3 *tp) tp->hw_stats, tp->stats_mapping); tp->hw_stats = NULL; } - tg3_rx_prodring_fini(tp); + tg3_rx_prodring_fini(tp, &tp->prodring[0]); } /* @@ -5785,7 +5790,7 @@ static void tg3_free_consistent(struct tg3 *tp) */ static int tg3_alloc_consistent(struct tg3 *tp) { - if (tg3_rx_prodring_init(tp)) + if (tg3_rx_prodring_init(tp, &tp->prodring[0])) return -ENOMEM; tp->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * @@ -6794,6 +6799,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) { u32 val, rdmac_mode; int i, err, limit; + struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; tg3_disable_ints(tp); @@ -7022,9 +7028,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) * configurable. */ tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, - ((u64) tp->rx_std_mapping >> 32)); + ((u64) tpr->rx_std_mapping >> 32)); tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, - ((u64) tp->rx_std_mapping & 0xffffffff)); + ((u64) tpr->rx_std_mapping & 0xffffffff)); tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC); @@ -7043,9 +7049,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, - ((u64) tp->rx_jumbo_mapping >> 32)); + ((u64) tpr->rx_jmb_mapping >> 32)); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, - ((u64) tp->rx_jumbo_mapping & 0xffffffff)); + ((u64) tpr->rx_jmb_mapping & 0xffffffff)); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR, @@ -7102,14 +7108,14 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_MAXLEN_SHIFT), 0); - tp->rx_std_ptr = tp->rx_pending; + tpr->rx_std_ptr = tp->rx_pending; tw32_rx_mbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, - tp->rx_std_ptr); + tpr->rx_std_ptr); - tp->rx_jumbo_ptr = (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) ? - tp->rx_jumbo_pending : 0; + tpr->rx_jmb_ptr = (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) ? + tp->rx_jumbo_pending : 0; tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, - tp->rx_jumbo_ptr); + tpr->rx_jmb_ptr); /* Initialize MAC address and backoff seed. */ __tg3_set_mac_addr(tp, 0); @@ -9815,6 +9821,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) dma_addr_t map; int num_pkts, tx_len, rx_len, i, err; struct tg3_rx_buffer_desc *desc; + struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; if (loopback_mode == TG3_MAC_LOOPBACK) { /* HW errata - mac loopback fails in some cases on 5780. @@ -9949,9 +9956,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) if (rx_len != tx_len) goto out; - rx_skb = tp->rx_std_buffers[desc_idx].skb; + rx_skb = tpr->rx_std_buffers[desc_idx].skb; - map = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], mapping); + map = pci_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping); pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE); for (i = 14; i < tx_len; i++) { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d029b4b..7a27cff 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2476,6 +2476,17 @@ struct tg3_ethtool_stats { u64 nic_tx_threshold_hit; }; +struct tg3_rx_prodring_set { + u32 rx_std_ptr; + u32 rx_jmb_ptr; + struct tg3_rx_buffer_desc *rx_std; + struct tg3_rx_buffer_desc *rx_jmb; + struct ring_info *rx_std_buffers; + struct ring_info *rx_jmb_buffers; + dma_addr_t rx_std_mapping; + dma_addr_t rx_jmb_mapping; +}; + struct tg3 { /* begin "general, frequently-used members" cacheline section */ @@ -2551,27 +2562,19 @@ struct tg3 { void (*write32_rx_mbox) (struct tg3 *, u32, u32); u32 rx_rcb_ptr; - u32 rx_std_ptr; - u32 rx_jumbo_ptr; u32 rx_pending; u32 rx_jumbo_pending; + u32 rx_std_max_post; + u32 rx_pkt_map_sz; #if TG3_VLAN_TAG_USED struct vlan_group *vlgrp; #endif - struct tg3_rx_buffer_desc *rx_std; - struct ring_info *rx_std_buffers; - dma_addr_t rx_std_mapping; - u32 rx_std_max_post; - - struct tg3_rx_buffer_desc *rx_jumbo; - struct ring_info *rx_jumbo_buffers; - dma_addr_t rx_jumbo_mapping; - struct tg3_rx_buffer_desc *rx_rcb; dma_addr_t rx_rcb_mapping; - u32 rx_pkt_map_sz; + struct tg3_rx_prodring_set prodring[1]; + /* begin "everything else" cacheline(s) section */ struct net_device_stats net_stats; -- cgit v0.10.2 From 79ed5ac7ddd5f8d6463f5a17b3575772e9896481 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:00:55 +0000 Subject: tg3: Use ext rx bds The 5717 only uses extended buffer descriptors for the jumbo producer ring. Extended buffer descriptors are available on all devices that support a separate jumbo producer ring so make the change universal. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 053d4e8..3725ac8 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -117,10 +117,10 @@ #define TG3_RX_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ TG3_RX_RING_SIZE) -#define TG3_RX_JUMBO_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ - TG3_RX_JUMBO_RING_SIZE) +#define TG3_RX_JUMBO_RING_BYTES (sizeof(struct tg3_ext_rx_buffer_desc) * \ + TG3_RX_JUMBO_RING_SIZE) #define TG3_RX_RCB_RING_BYTES(tp) (sizeof(struct tg3_rx_buffer_desc) * \ - TG3_RX_RCB_RING_SIZE(tp)) + TG3_RX_RCB_RING_SIZE(tp)) #define TG3_TX_RING_BYTES (sizeof(struct tg3_tx_buffer_desc) * \ TG3_TX_RING_SIZE) #define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1)) @@ -4367,7 +4367,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, case RXD_OPAQUE_RING_JUMBO: dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE; - desc = &tpr->rx_jmb[dest_idx]; + desc = &tpr->rx_jmb[dest_idx].std; map = &tpr->rx_jmb_buffers[dest_idx]; if (src_idx >= 0) src_map = &tpr->rx_jmb_buffers[src_idx]; @@ -4428,9 +4428,9 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, case RXD_OPAQUE_RING_JUMBO: dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE; - dest_desc = &tpr->rx_jmb[dest_idx]; + dest_desc = &tpr->rx_jmb[dest_idx].std; dest_map = &tpr->rx_jmb_buffers[dest_idx]; - src_desc = &tpr->rx_jmb[src_idx]; + src_desc = &tpr->rx_jmb[src_idx].std; src_map = &tpr->rx_jmb_buffers[src_idx]; break; @@ -5614,7 +5614,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { struct tg3_rx_buffer_desc *rxd; - rxd = &tpr->rx_jmb[i]; + rxd = &tpr->rx_jmb[i].std; rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT; rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | RXD_FLAG_JUMBO; @@ -7053,7 +7053,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tpr->rx_jmb_mapping & 0xffffffff)); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, - RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT); + (RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) | + BDINFO_FLAGS_USE_EXT_RECV); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_JUMBO_BUFFER_DESC); } else { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 7a27cff..982171f 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2480,7 +2480,7 @@ struct tg3_rx_prodring_set { u32 rx_std_ptr; u32 rx_jmb_ptr; struct tg3_rx_buffer_desc *rx_std; - struct tg3_rx_buffer_desc *rx_jmb; + struct tg3_ext_rx_buffer_desc *rx_jmb; struct ring_info *rx_std_buffers; struct ring_info *rx_jmb_buffers; dma_addr_t rx_std_mapping; -- cgit v0.10.2 From 07b0173cb5d6a9d77646cd855066ebe90b9203f2 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:01:15 +0000 Subject: tg3: Cleanup interrupt setup / teardown Later patches will be adding MSIX support, which will complicate interrupt initialization. This patch prepares for the integration by breaking out the interrupt setup and teardown code into separate functions and cleaning up the error return paths. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 3725ac8..37a4629 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7865,6 +7865,33 @@ static int tg3_request_firmware(struct tg3 *tp) return 0; } +static void tg3_ints_init(struct tg3 *tp) +{ + if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) { + /* All MSI supporting chips should support tagged + * status. Assert that this is the case. + */ + if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { + printk(KERN_WARNING PFX "%s: MSI without TAGGED? " + "Not using MSI.\n", tp->dev->name); + } else if (pci_enable_msi(tp->pdev) == 0) { + u32 msi_mode; + + msi_mode = tr32(MSGINT_MODE); + tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); + tp->tg3_flags2 |= TG3_FLG2_USING_MSI; + } + } +} + +static void tg3_ints_fini(struct tg3 *tp) +{ + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + pci_disable_msi(tp->pdev); + tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; + } +} + static int tg3_open(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); @@ -7906,33 +7933,14 @@ static int tg3_open(struct net_device *dev) if (err) return err; - if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) { - /* All MSI supporting chips should support tagged - * status. Assert that this is the case. - */ - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { - printk(KERN_WARNING PFX "%s: MSI without TAGGED? " - "Not using MSI.\n", tp->dev->name); - } else if (pci_enable_msi(tp->pdev) == 0) { - u32 msi_mode; + tg3_ints_init(tp); - msi_mode = tr32(MSGINT_MODE); - tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); - tp->tg3_flags2 |= TG3_FLG2_USING_MSI; - } - } - err = tg3_request_irq(tp); + napi_enable(&tp->napi); - if (err) { - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - } - tg3_free_consistent(tp); - return err; - } + err = tg3_request_irq(tp); - napi_enable(&tp->napi); + if (err) + goto err_out1; tg3_full_lock(tp, 0); @@ -7960,36 +7968,19 @@ static int tg3_open(struct net_device *dev) tg3_full_unlock(tp); - if (err) { - napi_disable(&tp->napi); - free_irq(tp->pdev->irq, dev); - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - } - tg3_free_consistent(tp); - return err; - } + if (err) + goto err_out2; if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { err = tg3_test_msi(tp); if (err) { tg3_full_lock(tp, 0); - - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - } tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); - tg3_free_consistent(tp); - tg3_full_unlock(tp); - napi_disable(&tp->napi); - - return err; + goto err_out1; } if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { @@ -8015,6 +8006,15 @@ static int tg3_open(struct net_device *dev) netif_start_queue(dev); return 0; + +err_out2: + free_irq(tp->pdev->irq, dev); + +err_out1: + napi_disable(&tp->napi); + tg3_ints_fini(tp); + tg3_free_consistent(tp); + return err; } #if 0 @@ -8273,10 +8273,8 @@ static int tg3_close(struct net_device *dev) tg3_full_unlock(tp); free_irq(tp->pdev->irq, dev); - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - } + + tg3_ints_fini(tp); memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev), sizeof(tp->net_stats_prev)); -- cgit v0.10.2 From 8ef0442f98850333196bc56415192e52a6267878 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:01:37 +0000 Subject: tg3: Move napi to per-int struct This patch creates a per-interrupt data structure, moves the napi member over, and creates a tg3 pointer back to the device structure. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 37a4629..b308c40 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -687,7 +687,7 @@ static void tg3_restart_ints(struct tg3 *tp) static inline void tg3_netif_stop(struct tg3 *tp) { tp->dev->trans_start = jiffies; /* prevent tx timeout */ - napi_disable(&tp->napi); + napi_disable(&tp->napi[0].napi); netif_tx_disable(tp->dev); } @@ -698,7 +698,7 @@ static inline void tg3_netif_start(struct tg3 *tp) * so long as all callers are assured to have free tx slots * (such as after tg3_init_hw) */ - napi_enable(&tp->napi); + napi_enable(&tp->napi[0].napi); tp->hw_status->status |= SD_STATUS_UPDATED; tg3_enable_ints(tp); } @@ -4447,13 +4447,6 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, src_map->skb = NULL; } -#if TG3_VLAN_TAG_USED -static int tg3_vlan_rx(struct tg3 *tp, struct sk_buff *skb, u16 vlan_tag) -{ - return vlan_gro_receive(&tp->napi, tp->vlgrp, vlan_tag, skb); -} -#endif - /* The RX ring scheme is composed of multiple rings which post fresh * buffers to the chip, and one special ring the chip uses to report * status back to the host. @@ -4591,11 +4584,11 @@ static int tg3_rx(struct tg3 *tp, int budget) #if TG3_VLAN_TAG_USED if (tp->vlgrp != NULL && desc->type_flags & RXD_FLAG_VLAN) { - tg3_vlan_rx(tp, skb, - desc->err_vlan & RXD_VLAN_MASK); + vlan_gro_receive(&tp->napi[0].napi, tp->vlgrp, + desc->err_vlan & RXD_VLAN_MASK, skb); } else #endif - napi_gro_receive(&tp->napi, skb); + napi_gro_receive(&tp->napi[0].napi, skb); received++; budget--; @@ -4686,7 +4679,8 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) static int tg3_poll(struct napi_struct *napi, int budget) { - struct tg3 *tp = container_of(napi, struct tg3, napi); + struct tg3_napi *tnapi = container_of(napi, struct tg3_napi, napi); + struct tg3 *tp = tnapi->tp; int work_done = 0; struct tg3_hw_status *sblk = tp->hw_status; @@ -4770,7 +4764,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) - napi_schedule(&tp->napi); + napi_schedule(&tp->napi[0].napi); return IRQ_HANDLED; } @@ -4795,7 +4789,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (likely(!tg3_irq_sync(tp))) - napi_schedule(&tp->napi); + napi_schedule(&tp->napi[0].napi); return IRQ_RETVAL(1); } @@ -4837,7 +4831,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tp))) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - napi_schedule(&tp->napi); + napi_schedule(&tp->napi[0].napi); } else { /* No work, shared interrupt perhaps? re-enable * interrupts, and flush that PCI write @@ -4895,7 +4889,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - napi_schedule(&tp->napi); + napi_schedule(&tp->napi[0].napi); out: return IRQ_RETVAL(handled); @@ -4936,7 +4930,7 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy) tg3_full_unlock(tp); del_timer_sync(&tp->timer); tp->irq_sync = 0; - napi_enable(&tp->napi); + napi_enable(&tp->napi[0].napi); dev_close(tp->dev); tg3_full_lock(tp, 0); } @@ -7935,7 +7929,7 @@ static int tg3_open(struct net_device *dev) tg3_ints_init(tp); - napi_enable(&tp->napi); + napi_enable(&tp->napi[0].napi); err = tg3_request_irq(tp); @@ -8011,7 +8005,7 @@ err_out2: free_irq(tp->pdev->irq, dev); err_out1: - napi_disable(&tp->napi); + napi_disable(&tp->napi[0].napi); tg3_ints_fini(tp); tg3_free_consistent(tp); return err; @@ -8252,7 +8246,7 @@ static int tg3_close(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - napi_disable(&tp->napi); + napi_disable(&tp->napi[0].napi); cancel_work_sync(&tp->reset_task); netif_stop_queue(dev); @@ -13396,7 +13390,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING; tp->tx_pending = TG3_DEF_TX_RING_PENDING; - netif_napi_add(dev, &tp->napi, tg3_poll, 64); + tp->napi[0].tp = tp; + netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; dev->irq = pdev->irq; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 982171f..aff3f04 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2487,6 +2487,13 @@ struct tg3_rx_prodring_set { dma_addr_t rx_jmb_mapping; }; +#define TG3_IRQ_MAX_VECS 1 + +struct tg3_napi { + struct napi_struct napi ____cacheline_aligned; + struct tg3 *tp; +}; + struct tg3 { /* begin "general, frequently-used members" cacheline section */ @@ -2558,7 +2565,7 @@ struct tg3 { dma_addr_t tx_desc_mapping; /* begin "rx thread" cacheline section */ - struct napi_struct napi; + struct tg3_napi napi[TG3_IRQ_MAX_VECS]; void (*write32_rx_mbox) (struct tg3 *, u32, u32); u32 rx_rcb_ptr; -- cgit v0.10.2 From 09943a1819a240ff4a72f924d0038818fcdd0a90 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:01:57 +0000 Subject: tg3: Convert ISR parameter to tnapi This patch migrates the ISR parameter from struct net_device to struct tg3_napi. Checkpatch complains about the existence of the preexisting IRQF_SAMPLE_RANDOM flag. I've opted to keep this patch conservative and let it continue to exist until the flag gets officially purged from the kernel. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b308c40..bf9a333 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4757,14 +4757,14 @@ static inline void tg3_full_unlock(struct tg3 *tp) */ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct tg3 *tp = netdev_priv(dev); + struct tg3_napi *tnapi = dev_id; + struct tg3 *tp = tnapi->tp; prefetch(tp->hw_status); prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) - napi_schedule(&tp->napi[0].napi); + napi_schedule(&tnapi->napi); return IRQ_HANDLED; } @@ -4775,8 +4775,8 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) */ static irqreturn_t tg3_msi(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct tg3 *tp = netdev_priv(dev); + struct tg3_napi *tnapi = dev_id; + struct tg3 *tp = tnapi->tp; prefetch(tp->hw_status); prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); @@ -4789,15 +4789,15 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (likely(!tg3_irq_sync(tp))) - napi_schedule(&tp->napi[0].napi); + napi_schedule(&tnapi->napi); return IRQ_RETVAL(1); } static irqreturn_t tg3_interrupt(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct tg3 *tp = netdev_priv(dev); + struct tg3_napi *tnapi = dev_id; + struct tg3 *tp = tnapi->tp; struct tg3_hw_status *sblk = tp->hw_status; unsigned int handled = 1; @@ -4831,7 +4831,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tp))) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - napi_schedule(&tp->napi[0].napi); + napi_schedule(&tnapi->napi); } else { /* No work, shared interrupt perhaps? re-enable * interrupts, and flush that PCI write @@ -4845,8 +4845,8 @@ out: static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct tg3 *tp = netdev_priv(dev); + struct tg3_napi *tnapi = dev_id; + struct tg3 *tp = tnapi->tp; struct tg3_hw_status *sblk = tp->hw_status; unsigned int handled = 1; @@ -4889,7 +4889,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - napi_schedule(&tp->napi[0].napi); + napi_schedule(&tnapi->napi); out: return IRQ_RETVAL(handled); @@ -4898,8 +4898,8 @@ out: /* ISR for interrupt test */ static irqreturn_t tg3_test_isr(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct tg3 *tp = netdev_priv(dev); + struct tg3_napi *tnapi = dev_id; + struct tg3 *tp = tnapi->tp; struct tg3_hw_status *sblk = tp->hw_status; if ((sblk->status & SD_STATUS_UPDATED) || @@ -7697,7 +7697,7 @@ static int tg3_request_irq(struct tg3 *tp) { irq_handler_t fn; unsigned long flags; - struct net_device *dev = tp->dev; + char *name = tp->dev->name; if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { fn = tg3_msi; @@ -7710,11 +7710,12 @@ static int tg3_request_irq(struct tg3 *tp) fn = tg3_interrupt_tagged; flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM; } - return (request_irq(tp->pdev->irq, fn, flags, dev->name, dev)); + return request_irq(tp->pdev->irq, fn, flags, name, &tp->napi[0]); } static int tg3_test_interrupt(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; struct net_device *dev = tp->dev; int err, i, intr_ok = 0; @@ -7723,10 +7724,10 @@ static int tg3_test_interrupt(struct tg3 *tp) tg3_disable_ints(tp); - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, tnapi); err = request_irq(tp->pdev->irq, tg3_test_isr, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); + IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi); if (err) return err; @@ -7754,7 +7755,7 @@ static int tg3_test_interrupt(struct tg3 *tp) tg3_disable_ints(tp); - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, tnapi); err = tg3_request_irq(tp); @@ -7772,7 +7773,6 @@ static int tg3_test_interrupt(struct tg3 *tp) */ static int tg3_test_msi(struct tg3 *tp) { - struct net_device *dev = tp->dev; int err; u16 pci_cmd; @@ -7803,7 +7803,8 @@ static int tg3_test_msi(struct tg3 *tp) "the PCI maintainer and include system chipset information.\n", tp->dev->name); - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, &tp->napi[0]); + pci_disable_msi(tp->pdev); tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; @@ -7823,7 +7824,7 @@ static int tg3_test_msi(struct tg3 *tp) tg3_full_unlock(tp); if (err) - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, &tp->napi[0]); return err; } @@ -8002,7 +8003,7 @@ static int tg3_open(struct net_device *dev) return 0; err_out2: - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, &tp->napi[0]); err_out1: napi_disable(&tp->napi[0].napi); @@ -8266,7 +8267,7 @@ static int tg3_close(struct net_device *dev) tg3_full_unlock(tp); - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, &tp->napi[0]); tg3_ints_fini(tp); -- cgit v0.10.2 From 17375d25d3dcd3d4caf9456fa94f60e29d6b1146 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:02:18 +0000 Subject: tg3: Convert napi handlers to use tnapi This patch converts the napi interrupt handler functions to accept and use tg3_napi structures. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index bf9a333..27ebe3b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -643,8 +643,9 @@ static void tg3_enable_ints(struct tg3 *tp) tg3_cond_int(tp); } -static inline unsigned int tg3_has_work(struct tg3 *tp) +static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) { + struct tg3 *tp = tnapi->tp; struct tg3_hw_status *sblk = tp->hw_status; unsigned int work_exists = 0; @@ -663,13 +664,15 @@ static inline unsigned int tg3_has_work(struct tg3 *tp) return work_exists; } -/* tg3_restart_ints +/* tg3_int_reenable * similar to tg3_enable_ints, but it accurately determines whether there * is new work pending and can return without flushing the PIO write * which reenables interrupts */ -static void tg3_restart_ints(struct tg3 *tp) +static void tg3_int_reenable(struct tg3_napi *tnapi) { + struct tg3 *tp = tnapi->tp; + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, tp->last_tag << 24); mmiowb(); @@ -679,7 +682,7 @@ static void tg3_restart_ints(struct tg3 *tp) * work we've completed. */ if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && - tg3_has_work(tp)) + tg3_has_work(tnapi)) tw32(HOSTCC_MODE, tp->coalesce_mode | (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); } @@ -4278,8 +4281,9 @@ static inline u32 tg3_tx_avail(struct tg3 *tp) * need special logic to handle SKBs that have not had all * of their frags sent yet, like SunGEM does. */ -static void tg3_tx(struct tg3 *tp) +static void tg3_tx(struct tg3_napi *tnapi) { + struct tg3 *tp = tnapi->tp; u32 hw_idx = tp->hw_status->idx[0].tx_consumer; u32 sw_idx = tp->tx_cons; @@ -4344,9 +4348,10 @@ static void tg3_tx(struct tg3 *tp) * buffers the cpu only reads the last cacheline of the RX descriptor * (to fetch the error flags, vlan tag, checksum, and opaque cookie). */ -static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, +static int tg3_alloc_rx_skb(struct tg3_napi *tnapi, u32 opaque_key, int src_idx, u32 dest_idx_unmasked) { + struct tg3 *tp = tnapi->tp; struct tg3_rx_buffer_desc *desc; struct ring_info *map, *src_map; struct sk_buff *skb; @@ -4409,9 +4414,10 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, * members of the RX descriptor are invariant. See notes above * tg3_alloc_rx_skb for full details. */ -static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, +static void tg3_recycle_rx(struct tg3_napi *tnapi, u32 opaque_key, int src_idx, u32 dest_idx_unmasked) { + struct tg3 *tp = tnapi->tp; struct tg3_rx_buffer_desc *src_desc, *dest_desc; struct ring_info *src_map, *dest_map; int dest_idx; @@ -4471,8 +4477,9 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, * If both the host and chip were to write into the same ring, cache line * eviction could occur since both entities want it in an exclusive state. */ -static int tg3_rx(struct tg3 *tp, int budget) +static int tg3_rx(struct tg3_napi *tnapi, int budget) { + struct tg3 *tp = tnapi->tp; u32 work_mask, rx_std_posted = 0; u32 sw_idx = tp->rx_rcb_ptr; u16 hw_idx; @@ -4515,7 +4522,7 @@ static int tg3_rx(struct tg3 *tp, int budget) if ((desc->err_vlan & RXD_ERR_MASK) != 0 && (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) { drop_it: - tg3_recycle_rx(tp, opaque_key, + tg3_recycle_rx(tnapi, opaque_key, desc_idx, *post_ptr); drop_it_no_recycle: /* Other statistics kept track of by card. */ @@ -4535,7 +4542,7 @@ static int tg3_rx(struct tg3 *tp, int budget) ) { int skb_size; - skb_size = tg3_alloc_rx_skb(tp, opaque_key, + skb_size = tg3_alloc_rx_skb(tnapi, opaque_key, desc_idx, *post_ptr); if (skb_size < 0) goto drop_it; @@ -4547,7 +4554,7 @@ static int tg3_rx(struct tg3 *tp, int budget) } else { struct sk_buff *copy_skb; - tg3_recycle_rx(tp, opaque_key, + tg3_recycle_rx(tnapi, opaque_key, desc_idx, *post_ptr); copy_skb = netdev_alloc_skb(tp->dev, @@ -4584,11 +4591,11 @@ static int tg3_rx(struct tg3 *tp, int budget) #if TG3_VLAN_TAG_USED if (tp->vlgrp != NULL && desc->type_flags & RXD_FLAG_VLAN) { - vlan_gro_receive(&tp->napi[0].napi, tp->vlgrp, + vlan_gro_receive(&tnapi->napi, tp->vlgrp, desc->err_vlan & RXD_VLAN_MASK, skb); } else #endif - napi_gro_receive(&tp->napi[0].napi, skb); + napi_gro_receive(&tnapi->napi, skb); received++; budget--; @@ -4635,8 +4642,9 @@ next_pkt_nopost: return received; } -static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) +static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) { + struct tg3 *tp = tnapi->tp; struct tg3_hw_status *sblk = tp->hw_status; /* handle link change and other phy events */ @@ -4662,7 +4670,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) /* run TX completion thread */ if (sblk->idx[0].tx_consumer != tp->tx_cons) { - tg3_tx(tp); + tg3_tx(tnapi); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) return work_done; } @@ -4672,7 +4680,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) * code synchronizes with tg3->napi.poll() */ if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) - work_done += tg3_rx(tp, budget - work_done); + work_done += tg3_rx(tnapi, budget - work_done); return work_done; } @@ -4685,7 +4693,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) struct tg3_hw_status *sblk = tp->hw_status; while (1) { - work_done = tg3_poll_work(tp, work_done, budget); + work_done = tg3_poll_work(tnapi, work_done, budget); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) goto tx_recovery; @@ -4694,7 +4702,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) break; if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { - /* tp->last_tag is used in tg3_restart_ints() below + /* tp->last_tag is used in tg3_int_reenable() below * to tell the hw how much work has been processed, * so we must read it before checking for more work. */ @@ -4704,9 +4712,9 @@ static int tg3_poll(struct napi_struct *napi, int budget) } else sblk->status &= ~SD_STATUS_UPDATED; - if (likely(!tg3_has_work(tp))) { + if (likely(!tg3_has_work(tnapi))) { napi_complete(napi); - tg3_restart_ints(tp); + tg3_int_reenable(tnapi); break; } } @@ -4829,7 +4837,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) if (tg3_irq_sync(tp)) goto out; sblk->status &= ~SD_STATUS_UPDATED; - if (likely(tg3_has_work(tp))) { + if (likely(tg3_has_work(tnapi))) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); napi_schedule(&tnapi->napi); } else { @@ -5560,6 +5568,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, struct tg3_rx_prodring_set *tpr) { u32 i, rx_pkt_dma_sz; + struct tg3_napi *tnapi = &tp->napi[0]; /* Zero out all descriptors. */ memset(tpr->rx_std, 0, TG3_RX_RING_BYTES); @@ -5586,7 +5595,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, /* Now allocate fresh SKBs for each rx ring. */ for (i = 0; i < tp->rx_pending; i++) { - if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD, -1, i) < 0) { + if (tg3_alloc_rx_skb(tnapi, RXD_OPAQUE_RING_STD, -1, i) < 0) { printk(KERN_WARNING PFX "%s: Using a smaller RX standard ring, " "only %d out of %d buffers were allocated " @@ -5617,7 +5626,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, } for (i = 0; i < tp->rx_jumbo_pending; i++) { - if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO, + if (tg3_alloc_rx_skb(tnapi, RXD_OPAQUE_RING_JUMBO, -1, i) < 0) { printk(KERN_WARNING PFX "%s: Using a smaller RX jumbo ring, " -- cgit v0.10.2 From 898a56f8d8170c188e47ae3acb90d2ea9a585ebe Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:02:40 +0000 Subject: tg3: Move general int members to a per-int struct This patch moves the last_tag, last_tag_irq, and hw_status device members to a per-interrupt structure. It also adds a new interrupt mailbox member (int_mbox) and converts the code to use it rather than a direct preprocessor constant. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 27ebe3b..5b8d6e0 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -615,13 +615,13 @@ static void tg3_disable_ints(struct tg3 *tp) { tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT)); - tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + tw32_mailbox_f(tp->napi[0].int_mbox, 0x00000001); } static inline void tg3_cond_int(struct tg3 *tp) { if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && - (tp->hw_status->status & SD_STATUS_UPDATED)) + (tp->napi[0].hw_status->status & SD_STATUS_UPDATED)) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); else tw32(HOSTCC_MODE, tp->coalesce_mode | @@ -630,23 +630,22 @@ static inline void tg3_cond_int(struct tg3 *tp) static void tg3_enable_ints(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; tp->irq_sync = 0; wmb(); tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); - tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - (tp->last_tag << 24)); + tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) - tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - (tp->last_tag << 24)); + tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); tg3_cond_int(tp); } static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) { struct tg3 *tp = tnapi->tp; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; unsigned int work_exists = 0; /* check for phy events */ @@ -673,8 +672,7 @@ static void tg3_int_reenable(struct tg3_napi *tnapi) { struct tg3 *tp = tnapi->tp; - tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - tp->last_tag << 24); + tw32_mailbox(tnapi->int_mbox, tnapi->last_tag << 24); mmiowb(); /* When doing tagged status, this work check is unnecessary. @@ -696,13 +694,14 @@ static inline void tg3_netif_stop(struct tg3 *tp) static inline void tg3_netif_start(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; netif_wake_queue(tp->dev); /* NOTE: unconditional netif_wake_queue is only appropriate * so long as all callers are assured to have free tx slots * (such as after tg3_init_hw) */ - napi_enable(&tp->napi[0].napi); - tp->hw_status->status |= SD_STATUS_UPDATED; + napi_enable(&tnapi->napi); + tnapi->hw_status->status |= SD_STATUS_UPDATED; tg3_enable_ints(tp); } @@ -3902,9 +3901,9 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) else current_link_up = tg3_setup_fiber_by_hand(tp, mac_status); - tp->hw_status->status = + tp->napi[0].hw_status->status = (SD_STATUS_UPDATED | - (tp->hw_status->status & ~SD_STATUS_LINK_CHG)); + (tp->napi[0].hw_status->status & ~SD_STATUS_LINK_CHG)); for (i = 0; i < 100; i++) { tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | @@ -4284,7 +4283,7 @@ static inline u32 tg3_tx_avail(struct tg3 *tp) static void tg3_tx(struct tg3_napi *tnapi) { struct tg3 *tp = tnapi->tp; - u32 hw_idx = tp->hw_status->idx[0].tx_consumer; + u32 hw_idx = tnapi->hw_status->idx[0].tx_consumer; u32 sw_idx = tp->tx_cons; while (sw_idx != hw_idx) { @@ -4486,7 +4485,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) int received; struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; - hw_idx = tp->hw_status->idx[0].rx_producer; + hw_idx = tnapi->hw_status->idx[0].rx_producer; /* * We need to order the read of hw_idx and the read of * the opaque cookie. @@ -4617,7 +4616,7 @@ next_pkt_nopost: /* Refresh hw_idx to see if there is new work */ if (sw_idx == hw_idx) { - hw_idx = tp->hw_status->idx[0].rx_producer; + hw_idx = tnapi->hw_status->idx[0].rx_producer; rmb(); } } @@ -4645,7 +4644,7 @@ next_pkt_nopost: static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) { struct tg3 *tp = tnapi->tp; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; /* handle link change and other phy events */ if (!(tp->tg3_flags & @@ -4690,7 +4689,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) struct tg3_napi *tnapi = container_of(napi, struct tg3_napi, napi); struct tg3 *tp = tnapi->tp; int work_done = 0; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; while (1) { work_done = tg3_poll_work(tnapi, work_done, budget); @@ -4706,8 +4705,8 @@ static int tg3_poll(struct napi_struct *napi, int budget) * to tell the hw how much work has been processed, * so we must read it before checking for more work. */ - tp->last_tag = sblk->status_tag; - tp->last_irq_tag = tp->last_tag; + tnapi->last_tag = sblk->status_tag; + tnapi->last_irq_tag = tnapi->last_tag; rmb(); } else sblk->status &= ~SD_STATUS_UPDATED; @@ -4768,7 +4767,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) struct tg3_napi *tnapi = dev_id; struct tg3 *tp = tnapi->tp; - prefetch(tp->hw_status); + prefetch(tnapi->hw_status); prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) @@ -4786,7 +4785,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) struct tg3_napi *tnapi = dev_id; struct tg3 *tp = tnapi->tp; - prefetch(tp->hw_status); + prefetch(tnapi->hw_status); prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); /* * Writing any value to intr-mbox-0 clears PCI INTA# and @@ -4806,7 +4805,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) { struct tg3_napi *tnapi = dev_id; struct tg3 *tp = tnapi->tp; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; unsigned int handled = 1; /* In INTx mode, it is possible for the interrupt to arrive at @@ -4855,7 +4854,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) { struct tg3_napi *tnapi = dev_id; struct tg3 *tp = tnapi->tp; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; unsigned int handled = 1; /* In INTx mode, it is possible for the interrupt to arrive at @@ -4863,7 +4862,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * Reading the PCI State register will confirm whether the * interrupt is ours and will flush the status block. */ - if (unlikely(sblk->status_tag == tp->last_irq_tag)) { + if (unlikely(sblk->status_tag == tnapi->last_irq_tag)) { if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) || (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { handled = 0; @@ -4890,7 +4889,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * so that the above check can report that the screaming interrupts * are unhandled. Eventually they will be silenced. */ - tp->last_irq_tag = sblk->status_tag; + tnapi->last_irq_tag = sblk->status_tag; if (tg3_irq_sync(tp)) goto out; @@ -4908,7 +4907,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id) { struct tg3_napi *tnapi = dev_id; struct tg3 *tp = tnapi->tp; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; if ((sblk->status & SD_STATUS_UPDATED) || !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { @@ -5762,6 +5761,8 @@ static int tg3_init_rings(struct tg3 *tp) */ static void tg3_free_consistent(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; + kfree(tp->tx_buffers); tp->tx_buffers = NULL; if (tp->rx_rcb) { @@ -5774,10 +5775,11 @@ static void tg3_free_consistent(struct tg3 *tp) tp->tx_ring, tp->tx_desc_mapping); tp->tx_ring = NULL; } - if (tp->hw_status) { + if (tnapi->hw_status) { pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE, - tp->hw_status, tp->status_mapping); - tp->hw_status = NULL; + tnapi->hw_status, + tnapi->status_mapping); + tnapi->hw_status = NULL; } if (tp->hw_stats) { pci_free_consistent(tp->pdev, sizeof(struct tg3_hw_stats), @@ -5793,6 +5795,8 @@ static void tg3_free_consistent(struct tg3 *tp) */ static int tg3_alloc_consistent(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; + if (tg3_rx_prodring_init(tp, &tp->prodring[0])) return -ENOMEM; @@ -5811,19 +5815,20 @@ static int tg3_alloc_consistent(struct tg3 *tp) if (!tp->tx_ring) goto err_out; - tp->hw_status = pci_alloc_consistent(tp->pdev, - TG3_HW_STATUS_SIZE, - &tp->status_mapping); - if (!tp->hw_status) + tnapi->hw_status = pci_alloc_consistent(tp->pdev, + TG3_HW_STATUS_SIZE, + &tnapi->status_mapping); + if (!tnapi->hw_status) goto err_out; + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + tp->hw_stats = pci_alloc_consistent(tp->pdev, sizeof(struct tg3_hw_stats), &tp->stats_mapping); if (!tp->hw_stats) goto err_out; - memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); return 0; @@ -5885,6 +5890,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int static int tg3_abort_hw(struct tg3 *tp, int silent) { int i, err; + struct tg3_napi *tnapi = &tp->napi[0]; tg3_disable_ints(tp); @@ -5936,8 +5942,8 @@ static int tg3_abort_hw(struct tg3 *tp, int silent) err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE, silent); err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE, silent); - if (tp->hw_status) - memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); + if (tnapi->hw_status) + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); if (tp->hw_stats) memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); @@ -6264,12 +6270,12 @@ static int tg3_chip_reset(struct tg3 *tp) * sharing or irqpoll. */ tp->tg3_flags |= TG3_FLAG_CHIP_RESETTING; - if (tp->hw_status) { - tp->hw_status->status = 0; - tp->hw_status->status_tag = 0; + if (tp->napi[0].hw_status) { + tp->napi[0].hw_status->status = 0; + tp->napi[0].hw_status->status_tag = 0; } - tp->last_tag = 0; - tp->last_irq_tag = 0; + tp->napi[0].last_tag = 0; + tp->napi[0].last_irq_tag = 0; smp_mb(); synchronize_irq(tp->pdev->irq); @@ -7210,9 +7216,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* set status block DMA address */ tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, - ((u64) tp->status_mapping >> 32)); + ((u64) tp->napi[0].status_mapping >> 32)); tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, - ((u64) tp->status_mapping & 0xffffffff)); + ((u64) tp->napi[0].status_mapping & 0xffffffff)); if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { /* Status/statistics block address. See tg3_timer, @@ -7241,7 +7247,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_write_mem(tp, i, 0); udelay(40); } - memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); + memset(tp->napi[0].hw_status, 0, TG3_HW_STATUS_SIZE); if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) { tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT; @@ -7294,7 +7300,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); - tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); + tw32_mailbox_f(tp->napi[0].int_mbox, 0); if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); @@ -7596,7 +7602,7 @@ static void tg3_timer(unsigned long __opaque) * IRQ status the mailbox/status_block protocol the chip * uses with the cpu is race prone. */ - if (tp->hw_status->status & SD_STATUS_UPDATED) { + if (tp->napi[0].hw_status->status & SD_STATUS_UPDATED) { tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); } else { @@ -7740,7 +7746,7 @@ static int tg3_test_interrupt(struct tg3 *tp) if (err) return err; - tp->hw_status->status &= ~SD_STATUS_UPDATED; + tnapi->hw_status->status &= ~SD_STATUS_UPDATED; tg3_enable_ints(tp); tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | @@ -7749,8 +7755,7 @@ static int tg3_test_interrupt(struct tg3 *tp) for (i = 0; i < 5; i++) { u32 int_mbox, misc_host_ctrl; - int_mbox = tr32_mailbox(MAILBOX_INTERRUPT_0 + - TG3_64BIT_REG_LOW); + int_mbox = tr32_mailbox(tnapi->int_mbox); misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL); if ((int_mbox != 0) || @@ -8027,6 +8032,7 @@ err_out1: u32 val32, val32_2, val32_3, val32_4, val32_5; u16 val16; int i; + struct tg3_hw_status *sblk = tp->napi[0]->hw_status; pci_read_config_word(tp->pdev, PCI_STATUS, &val16); pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &val32); @@ -8179,14 +8185,15 @@ err_out1: val32, val32_2, val32_3, val32_4, val32_5); /* SW status block */ - printk("DEBUG: Host status block [%08x:%08x:(%04x:%04x:%04x):(%04x:%04x)]\n", - tp->hw_status->status, - tp->hw_status->status_tag, - tp->hw_status->rx_jumbo_consumer, - tp->hw_status->rx_consumer, - tp->hw_status->rx_mini_consumer, - tp->hw_status->idx[0].rx_producer, - tp->hw_status->idx[0].tx_consumer); + printk(KERN_DEBUG + "Host status block [%08x:%08x:(%04x:%04x:%04x):(%04x:%04x)]\n", + sblk->status, + sblk->status_tag, + sblk->rx_jumbo_consumer, + sblk->rx_consumer, + sblk->rx_mini_consumer, + sblk->idx[0].rx_producer, + sblk->idx[0].tx_consumer); /* SW statistics block */ printk("DEBUG: Host statistics block [%08x:%08x:%08x:%08x]\n", @@ -9824,8 +9831,12 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) dma_addr_t map; int num_pkts, tx_len, rx_len, i, err; struct tg3_rx_buffer_desc *desc; + struct tg3_napi *tnapi, *rnapi; struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; + tnapi = &tp->napi[0]; + rnapi = &tp->napi[0]; + if (loopback_mode == TG3_MAC_LOOPBACK) { /* HW errata - mac loopback fails in some cases on 5780. * Normal traffic and PHY loopback are not affected by @@ -9907,7 +9918,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) udelay(10); - rx_start_idx = tp->hw_status->idx[0].rx_producer; + rx_start_idx = rnapi->hw_status->idx[0].rx_producer; num_pkts = 0; @@ -9929,8 +9940,8 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) udelay(10); - tx_idx = tp->hw_status->idx[0].tx_consumer; - rx_idx = tp->hw_status->idx[0].rx_producer; + tx_idx = tnapi->hw_status->idx[0].tx_consumer; + rx_idx = rnapi->hw_status->idx[0].rx_producer; if ((tx_idx == tp->tx_prod) && (rx_idx == (rx_start_idx + num_pkts))) break; @@ -13401,6 +13412,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->tx_pending = TG3_DEF_TX_RING_PENDING; tp->napi[0].tp = tp; + tp->napi[0].int_mbox = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index aff3f04..f46e619 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2492,6 +2492,13 @@ struct tg3_rx_prodring_set { struct tg3_napi { struct napi_struct napi ____cacheline_aligned; struct tg3 *tp; + struct tg3_hw_status *hw_status; + + u32 last_tag; + u32 last_irq_tag; + u32 int_mbox; + + dma_addr_t status_mapping; }; struct tg3 { @@ -2546,11 +2553,6 @@ struct tg3 { struct net_device *dev; struct pci_dev *pdev; - struct tg3_hw_status *hw_status; - dma_addr_t status_mapping; - u32 last_tag; - u32 last_irq_tag; - u32 msg_enable; /* begin "tx thread" cacheline section */ -- cgit v0.10.2 From 723344820aa405ac2663ab9e36fd27833d06129b Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:03:01 +0000 Subject: tg3: Move per-int rx members to per-int struct This patch moves the rx_rcb, rx_rcb_mapping, and rx_rcb_ptr return ring device members to a per-interrupt structure. It also adds a new return ring consumer mailbox register member (consmbox) and converts the code to use it rather than a preprocessor constant. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5b8d6e0..939574c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -657,7 +657,7 @@ static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) } /* check for RX/TX work to do */ if (sblk->idx[0].tx_consumer != tp->tx_cons || - sblk->idx[0].rx_producer != tp->rx_rcb_ptr) + sblk->idx[0].rx_producer != tnapi->rx_rcb_ptr) work_exists = 1; return work_exists; @@ -4480,7 +4480,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) { struct tg3 *tp = tnapi->tp; u32 work_mask, rx_std_posted = 0; - u32 sw_idx = tp->rx_rcb_ptr; + u32 sw_idx = tnapi->rx_rcb_ptr; u16 hw_idx; int received; struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; @@ -4494,7 +4494,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) work_mask = 0; received = 0; while (sw_idx != hw_idx && budget > 0) { - struct tg3_rx_buffer_desc *desc = &tp->rx_rcb[sw_idx]; + struct tg3_rx_buffer_desc *desc = &tnapi->rx_rcb[sw_idx]; unsigned int len; struct sk_buff *skb; dma_addr_t dma_addr; @@ -4622,8 +4622,8 @@ next_pkt_nopost: } /* ACK the status ring. */ - tp->rx_rcb_ptr = sw_idx; - tw32_rx_mbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, sw_idx); + tnapi->rx_rcb_ptr = sw_idx; + tw32_rx_mbox(tnapi->consmbox, sw_idx); /* Refill RX ring(s). */ if (work_mask & RXD_OPAQUE_RING_STD) { @@ -4678,7 +4678,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) * All RX "locking" is done by ensuring outside * code synchronizes with tg3->napi.poll() */ - if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) + if (sblk->idx[0].rx_producer != tnapi->rx_rcb_ptr) work_done += tg3_rx(tnapi, budget - work_done); return work_done; @@ -4768,7 +4768,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) struct tg3 *tp = tnapi->tp; prefetch(tnapi->hw_status); - prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) napi_schedule(&tnapi->napi); @@ -4786,7 +4786,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) struct tg3 *tp = tnapi->tp; prefetch(tnapi->hw_status); - prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); /* * Writing any value to intr-mbox-0 clears PCI INTA# and * chip-internal interrupt pending events. @@ -4837,7 +4837,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) goto out; sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tnapi))) { - prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); napi_schedule(&tnapi->napi); } else { /* No work, shared interrupt perhaps? re-enable @@ -4894,7 +4894,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) if (tg3_irq_sync(tp)) goto out; - prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); napi_schedule(&tnapi->napi); @@ -5745,13 +5745,17 @@ static void tg3_free_rings(struct tg3 *tp) */ static int tg3_init_rings(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; + /* Free up all the SKBs. */ tg3_free_rings(tp); /* Zero out all descriptors. */ - memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); + tnapi->rx_rcb_ptr = 0; + memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + return tg3_rx_prodring_alloc(tp, &tp->prodring[0]); } @@ -5765,16 +5769,16 @@ static void tg3_free_consistent(struct tg3 *tp) kfree(tp->tx_buffers); tp->tx_buffers = NULL; - if (tp->rx_rcb) { - pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), - tp->rx_rcb, tp->rx_rcb_mapping); - tp->rx_rcb = NULL; - } if (tp->tx_ring) { pci_free_consistent(tp->pdev, TG3_TX_RING_BYTES, tp->tx_ring, tp->tx_desc_mapping); tp->tx_ring = NULL; } + if (tnapi->rx_rcb) { + pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), + tnapi->rx_rcb, tnapi->rx_rcb_mapping); + tnapi->rx_rcb = NULL; + } if (tnapi->hw_status) { pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE, tnapi->hw_status, @@ -5805,11 +5809,6 @@ static int tg3_alloc_consistent(struct tg3 *tp) if (!tp->tx_buffers) goto err_out; - tp->rx_rcb = pci_alloc_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), - &tp->rx_rcb_mapping); - if (!tp->rx_rcb) - goto err_out; - tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, &tp->tx_desc_mapping); if (!tp->tx_ring) @@ -5823,6 +5822,14 @@ static int tg3_alloc_consistent(struct tg3 *tp) memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + tnapi->rx_rcb = pci_alloc_consistent(tp->pdev, + TG3_RX_RCB_RING_BYTES(tp), + &tnapi->rx_rcb_mapping); + if (!tnapi->rx_rcb) + goto err_out; + + memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + tp->hw_stats = pci_alloc_consistent(tp->pdev, sizeof(struct tg3_hw_stats), &tp->stats_mapping); @@ -7109,11 +7116,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } } - tp->rx_rcb_ptr = 0; - tw32_rx_mbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0); + tw32_rx_mbox(tp->napi[0].consmbox, 0); tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB, - tp->rx_rcb_mapping, + tp->napi[0].rx_rcb_mapping, (TG3_RX_RCB_RING_SIZE(tp) << BDINFO_FLAGS_MAXLEN_SHIFT), 0); @@ -9956,7 +9962,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) if (rx_idx != rx_start_idx + num_pkts) goto out; - desc = &tp->rx_rcb[rx_start_idx]; + desc = &rnapi->rx_rcb[rx_start_idx]; desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; if (opaque_key != RXD_OPAQUE_RING_STD) @@ -13413,6 +13419,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->napi[0].tp = tp; tp->napi[0].int_mbox = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; + tp->napi[0].consmbox = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index f46e619..b91ac29 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2497,8 +2497,13 @@ struct tg3_napi { u32 last_tag; u32 last_irq_tag; u32 int_mbox; + u32 consmbox; + u32 rx_rcb_ptr; + + struct tg3_rx_buffer_desc *rx_rcb; dma_addr_t status_mapping; + dma_addr_t rx_rcb_mapping; }; struct tg3 { @@ -2570,7 +2575,6 @@ struct tg3 { struct tg3_napi napi[TG3_IRQ_MAX_VECS]; void (*write32_rx_mbox) (struct tg3 *, u32, u32); - u32 rx_rcb_ptr; u32 rx_pending; u32 rx_jumbo_pending; u32 rx_std_max_post; @@ -2579,9 +2583,6 @@ struct tg3 { struct vlan_group *vlgrp; #endif - struct tg3_rx_buffer_desc *rx_rcb; - dma_addr_t rx_rcb_mapping; - struct tg3_rx_prodring_set prodring[1]; -- cgit v0.10.2 From f3f3f27e5b4e27737f824535e6f145a3c88b976c Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:03:21 +0000 Subject: tg3: Move per-int tx members to a per-int struct This patch moves the tx_prod, tx_cons, tx_pending, tx_ring, and tx_buffers transmit ring device members to a per-interrupt structure. It also adds a new transmit producer mailbox member (prodmbox) and converts the code to use it rather than a preprocessor constant. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 939574c..e36b0b2 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -136,7 +136,7 @@ #define TG3_RX_JMB_MAP_SZ TG3_RX_DMA_TO_MAP_SZ(TG3_RX_JMB_DMA_SZ) /* minimum number of free TX descriptors required to wake up TX process */ -#define TG3_TX_WAKEUP_THRESH(tp) ((tp)->tx_pending / 4) +#define TG3_TX_WAKEUP_THRESH(tnapi) ((tnapi)->tx_pending / 4) #define TG3_RAW_IP_ALIGN 2 @@ -656,7 +656,7 @@ static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) work_exists = 1; } /* check for RX/TX work to do */ - if (sblk->idx[0].tx_consumer != tp->tx_cons || + if (sblk->idx[0].tx_consumer != tnapi->tx_cons || sblk->idx[0].rx_producer != tnapi->rx_rcb_ptr) work_exists = 1; @@ -4269,11 +4269,11 @@ static void tg3_tx_recover(struct tg3 *tp) spin_unlock(&tp->lock); } -static inline u32 tg3_tx_avail(struct tg3 *tp) +static inline u32 tg3_tx_avail(struct tg3_napi *tnapi) { smp_mb(); - return (tp->tx_pending - - ((tp->tx_prod - tp->tx_cons) & (TG3_TX_RING_SIZE - 1))); + return tnapi->tx_pending - + ((tnapi->tx_prod - tnapi->tx_cons) & (TG3_TX_RING_SIZE - 1)); } /* Tigon3 never reports partial packet sends. So we do not @@ -4284,10 +4284,10 @@ static void tg3_tx(struct tg3_napi *tnapi) { struct tg3 *tp = tnapi->tp; u32 hw_idx = tnapi->hw_status->idx[0].tx_consumer; - u32 sw_idx = tp->tx_cons; + u32 sw_idx = tnapi->tx_cons; while (sw_idx != hw_idx) { - struct tx_ring_info *ri = &tp->tx_buffers[sw_idx]; + struct tx_ring_info *ri = &tnapi->tx_buffers[sw_idx]; struct sk_buff *skb = ri->skb; int i, tx_bug = 0; @@ -4303,7 +4303,7 @@ static void tg3_tx(struct tg3_napi *tnapi) sw_idx = NEXT_TX(sw_idx); for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - ri = &tp->tx_buffers[sw_idx]; + ri = &tnapi->tx_buffers[sw_idx]; if (unlikely(ri->skb != NULL || sw_idx == hw_idx)) tx_bug = 1; sw_idx = NEXT_TX(sw_idx); @@ -4317,7 +4317,7 @@ static void tg3_tx(struct tg3_napi *tnapi) } } - tp->tx_cons = sw_idx; + tnapi->tx_cons = sw_idx; /* Need to make the tx_cons update visible to tg3_start_xmit() * before checking for netif_queue_stopped(). Without the @@ -4327,10 +4327,10 @@ static void tg3_tx(struct tg3_napi *tnapi) smp_mb(); if (unlikely(netif_queue_stopped(tp->dev) && - (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))) { + (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)))) { netif_tx_lock(tp->dev); if (netif_queue_stopped(tp->dev) && - (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))) + (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi))) netif_wake_queue(tp->dev); netif_tx_unlock(tp->dev); } @@ -4668,7 +4668,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) } /* run TX completion thread */ - if (sblk->idx[0].tx_consumer != tp->tx_cons) { + if (tnapi->hw_status->idx[0].tx_consumer != tnapi->tx_cons) { tg3_tx(tnapi); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) return work_done; @@ -5044,13 +5044,14 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping, #endif } -static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, u32); +static void tg3_set_txd(struct tg3_napi *, int, dma_addr_t, int, u32, u32); /* Workaround 4GB and 40-bit hardware DMA bugs. */ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, u32 last_plus_one, u32 *start, u32 base_flags, u32 mss) { + struct tg3_napi *tnapi = &tp->napi[0]; struct sk_buff *new_skb; dma_addr_t new_addr = 0; u32 entry = *start; @@ -5085,7 +5086,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, dev_kfree_skb(new_skb); new_skb = NULL; } else { - tg3_set_txd(tp, entry, new_addr, new_skb->len, + tg3_set_txd(tnapi, entry, new_addr, new_skb->len, base_flags, 1 | (mss << 1)); *start = NEXT_TX(entry); } @@ -5094,11 +5095,10 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, /* Now clean up the sw ring entries. */ i = 0; while (entry != last_plus_one) { - if (i == 0) { - tp->tx_buffers[entry].skb = new_skb; - } else { - tp->tx_buffers[entry].skb = NULL; - } + if (i == 0) + tnapi->tx_buffers[entry].skb = new_skb; + else + tnapi->tx_buffers[entry].skb = NULL; entry = NEXT_TX(entry); i++; } @@ -5109,11 +5109,11 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, return ret; } -static void tg3_set_txd(struct tg3 *tp, int entry, +static void tg3_set_txd(struct tg3_napi *tnapi, int entry, dma_addr_t mapping, int len, u32 flags, u32 mss_and_is_end) { - struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry]; + struct tg3_tx_buffer_desc *txd = &tnapi->tx_ring[entry]; int is_end = (mss_and_is_end & 0x1); u32 mss = (mss_and_is_end >> 1); u32 vlan_tag = 0; @@ -5141,6 +5141,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 len, entry, base_flags, mss; struct skb_shared_info *sp; dma_addr_t mapping; + struct tg3_napi *tnapi = &tp->napi[0]; len = skb_headlen(skb); @@ -5149,7 +5150,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) * interrupt. Furthermore, IRQ processing runs lockless so we have * no IRQ context deadlocks to worry about either. Rejoice! */ - if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { + if (unlikely(tg3_tx_avail(tnapi) <= (skb_shinfo(skb)->nr_frags + 1))) { if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); @@ -5160,7 +5161,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } - entry = tp->tx_prod; + entry = tnapi->tx_prod; base_flags = 0; mss = 0; if ((mss = skb_shinfo(skb)->gso_size) != 0) { @@ -5208,9 +5209,9 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) mapping = sp->dma_head; - tp->tx_buffers[entry].skb = skb; + tnapi->tx_buffers[entry].skb = skb; - tg3_set_txd(tp, entry, mapping, len, base_flags, + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); entry = NEXT_TX(entry); @@ -5225,9 +5226,9 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) len = frag->size; mapping = sp->dma_maps[i]; - tp->tx_buffers[entry].skb = NULL; + tnapi->tx_buffers[entry].skb = NULL; - tg3_set_txd(tp, entry, mapping, len, + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (i == last) | (mss << 1)); entry = NEXT_TX(entry); @@ -5235,12 +5236,12 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* Packets are ready, update Tx producer idx local and on card. */ - tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); + tw32_tx_mbox(tnapi->prodmbox, entry); - tp->tx_prod = entry; - if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { + tnapi->tx_prod = entry; + if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); - if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)) + if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)) netif_wake_queue(tp->dev); } @@ -5258,11 +5259,12 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *); static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) { struct sk_buff *segs, *nskb; + u32 frag_cnt_est = skb_shinfo(skb)->gso_segs * 3; /* Estimate the number of fragments in the worst case */ - if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))) { + if (unlikely(tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est)) { netif_stop_queue(tp->dev); - if (tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3)) + if (tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est) return NETDEV_TX_BUSY; netif_wake_queue(tp->dev); @@ -5295,6 +5297,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) struct skb_shared_info *sp; int would_hit_hwbug; dma_addr_t mapping; + struct tg3_napi *tnapi = &tp->napi[0]; len = skb_headlen(skb); @@ -5303,7 +5306,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) * interrupt. Furthermore, IRQ processing runs lockless so we have * no IRQ context deadlocks to worry about either. Rejoice! */ - if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { + if (unlikely(tg3_tx_avail(tnapi) <= (skb_shinfo(skb)->nr_frags + 1))) { if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); @@ -5314,7 +5317,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } - entry = tp->tx_prod; + entry = tnapi->tx_prod; base_flags = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) base_flags |= TXD_FLAG_TCPUDP_CSUM; @@ -5384,7 +5387,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) mapping = sp->dma_head; - tp->tx_buffers[entry].skb = skb; + tnapi->tx_buffers[entry].skb = skb; would_hit_hwbug = 0; @@ -5393,7 +5396,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) else if (tg3_4g_overflow_test(mapping, len)) would_hit_hwbug = 1; - tg3_set_txd(tp, entry, mapping, len, base_flags, + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); entry = NEXT_TX(entry); @@ -5409,7 +5412,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) len = frag->size; mapping = sp->dma_maps[i]; - tp->tx_buffers[entry].skb = NULL; + tnapi->tx_buffers[entry].skb = NULL; if (tg3_4g_overflow_test(mapping, len)) would_hit_hwbug = 1; @@ -5418,10 +5421,10 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) would_hit_hwbug = 1; if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) - tg3_set_txd(tp, entry, mapping, len, + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (i == last)|(mss << 1)); else - tg3_set_txd(tp, entry, mapping, len, + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (i == last)); entry = NEXT_TX(entry); @@ -5446,12 +5449,12 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) } /* Packets are ready, update Tx producer idx local and on card. */ - tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); + tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, entry); - tp->tx_prod = entry; - if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { + tnapi->tx_prod = entry; + if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); - if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)) + if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)) netif_wake_queue(tp->dev); } @@ -5522,8 +5525,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) static void tg3_rx_prodring_free(struct tg3 *tp, struct tg3_rx_prodring_set *tpr) { - struct ring_info *rxp; int i; + struct ring_info *rxp; for (i = 0; i < TG3_RX_RING_SIZE; i++) { rxp = &tpr->rx_std_buffers[i]; @@ -5710,13 +5713,14 @@ err_out: */ static void tg3_free_rings(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; int i; for (i = 0; i < TG3_TX_RING_SIZE; ) { struct tx_ring_info *txp; struct sk_buff *skb; - txp = &tp->tx_buffers[i]; + txp = &tnapi->tx_buffers[i]; skb = txp->skb; if (skb == NULL) { @@ -5751,7 +5755,7 @@ static int tg3_init_rings(struct tg3 *tp) tg3_free_rings(tp); /* Zero out all descriptors. */ - memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); + memset(tnapi->tx_ring, 0, TG3_TX_RING_BYTES); tnapi->rx_rcb_ptr = 0; memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); @@ -5767,12 +5771,12 @@ static void tg3_free_consistent(struct tg3 *tp) { struct tg3_napi *tnapi = &tp->napi[0]; - kfree(tp->tx_buffers); - tp->tx_buffers = NULL; - if (tp->tx_ring) { + kfree(tnapi->tx_buffers); + tnapi->tx_buffers = NULL; + if (tnapi->tx_ring) { pci_free_consistent(tp->pdev, TG3_TX_RING_BYTES, - tp->tx_ring, tp->tx_desc_mapping); - tp->tx_ring = NULL; + tnapi->tx_ring, tnapi->tx_desc_mapping); + tnapi->tx_ring = NULL; } if (tnapi->rx_rcb) { pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), @@ -5804,14 +5808,14 @@ static int tg3_alloc_consistent(struct tg3 *tp) if (tg3_rx_prodring_init(tp, &tp->prodring[0])) return -ENOMEM; - tp->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * - TG3_TX_RING_SIZE, GFP_KERNEL); - if (!tp->tx_buffers) + tnapi->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * + TG3_TX_RING_SIZE, GFP_KERNEL); + if (!tnapi->tx_buffers) goto err_out; - tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, - &tp->tx_desc_mapping); - if (!tp->tx_ring) + tnapi->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, + &tnapi->tx_desc_mapping); + if (!tnapi->tx_ring) goto err_out; tnapi->hw_status = pci_alloc_consistent(tp->pdev, @@ -7094,13 +7098,15 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_DISABLED); } - tp->tx_prod = 0; - tp->tx_cons = 0; - tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); + tp->napi[0].tx_prod = 0; + tp->napi[0].tx_cons = 0; tw32_tx_mbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); + val = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; + tw32_mailbox(val, 0); + tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, - tp->tx_desc_mapping, + tp->napi[0].tx_desc_mapping, (TG3_TX_RING_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT), NIC_SRAM_TX_BUFFER_DESC); @@ -9093,7 +9099,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam * else ering->rx_jumbo_pending = 0; - ering->tx_pending = tp->tx_pending; + ering->tx_pending = tp->napi[0].tx_pending; } static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) @@ -9123,7 +9129,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tp->rx_pending > 63) tp->rx_pending = 63; tp->rx_jumbo_pending = ering->rx_jumbo_pending; - tp->tx_pending = ering->tx_pending; + tp->napi[0].tx_pending = ering->tx_pending; if (netif_running(dev)) { tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); @@ -9928,14 +9934,13 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) num_pkts = 0; - tg3_set_txd(tp, tp->tx_prod, map, tx_len, 0, 1); + tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len, 0, 1); - tp->tx_prod++; + tnapi->tx_prod++; num_pkts++; - tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, - tp->tx_prod); - tr32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW); + tw32_tx_mbox(tnapi->prodmbox, tnapi->tx_prod); + tr32_mailbox(tnapi->prodmbox); udelay(10); @@ -9948,7 +9953,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) tx_idx = tnapi->hw_status->idx[0].tx_consumer; rx_idx = rnapi->hw_status->idx[0].rx_producer; - if ((tx_idx == tp->tx_prod) && + if ((tx_idx == tnapi->tx_prod) && (rx_idx == (rx_start_idx + num_pkts))) break; } @@ -9956,7 +9961,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); - if (tx_idx != tp->tx_prod) + if (tx_idx != tnapi->tx_prod) goto out; if (rx_idx != rx_start_idx + num_pkts) @@ -13415,11 +13420,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->rx_pending = TG3_DEF_RX_RING_PENDING; tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING; - tp->tx_pending = TG3_DEF_TX_RING_PENDING; tp->napi[0].tp = tp; tp->napi[0].int_mbox = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; tp->napi[0].consmbox = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; + tp->napi[0].prodmbox = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; + tp->napi[0].tx_pending = TG3_DEF_TX_RING_PENDING; netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index b91ac29..a816b2c 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2497,13 +2497,21 @@ struct tg3_napi { u32 last_tag; u32 last_irq_tag; u32 int_mbox; + u32 tx_prod; + u32 tx_cons; + u32 tx_pending; + u32 prodmbox; + u32 consmbox; u32 rx_rcb_ptr; struct tg3_rx_buffer_desc *rx_rcb; + struct tg3_tx_buffer_desc *tx_ring; + struct tx_ring_info *tx_buffers; dma_addr_t status_mapping; dma_addr_t rx_rcb_mapping; + dma_addr_t tx_desc_mapping; }; struct tg3 { @@ -2563,13 +2571,6 @@ struct tg3 { /* begin "tx thread" cacheline section */ void (*write32_tx_mbox) (struct tg3 *, u32, u32); - u32 tx_prod; - u32 tx_cons; - u32 tx_pending; - - struct tg3_tx_buffer_desc *tx_ring; - struct tx_ring_info *tx_buffers; - dma_addr_t tx_desc_mapping; /* begin "rx thread" cacheline section */ struct tg3_napi napi[TG3_IRQ_MAX_VECS]; -- cgit v0.10.2 From fc57e515a2c02599b00d252545521288dfc0158a Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:03:44 +0000 Subject: tg3: Update version to 3.101 This patch updates the tg3 version to 3.101. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e36b0b2..a7d14aa 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.100" -#define DRV_MODULE_RELDATE "August 25, 2009" +#define DRV_MODULE_VERSION "3.101" +#define DRV_MODULE_RELDATE "August 28, 2009" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v0.10.2 From 23386d63bbb3199cf247313ec088878d72debcfd Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Sat, 29 Aug 2009 18:27:18 +0200 Subject: x86: Detect stack protector for i386 builds on x86_64 Stack protector support was not detected when building with ARCH=i386 on x86_64 systems: arch/x86/Makefile:80: stack protector enabled but no compiler support The "-m32" argument needs to be passed to the detection script. Signed-off-by: Michal Schmidt Cc: Tejun Heo Cc: Jeremy Fitzhardinge Cc: Arjan van de Ven LKML-Reference: <20090829182718.10f566b1@leela> Signed-off-by: Ingo Molnar -- diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 1b68659..5e7db44 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -72,7 +72,7 @@ endif ifdef CONFIG_CC_STACKPROTECTOR cc_has_sp := $(srctree)/scripts/gcc-x86_$(BITS)-has-stack-protector.sh - ifeq ($(shell $(CONFIG_SHELL) $(cc_has_sp) $(CC)),y) + ifeq ($(shell $(CONFIG_SHELL) $(cc_has_sp) $(CC) $(biarch)),y) stackp-y := -fstack-protector stackp-$(CONFIG_CC_STACKPROTECTOR_ALL) += -fstack-protector-all KBUILD_CFLAGS += $(stackp-y) -- cgit v0.10.2 From e0ad2cd8ff7fb957be867d17d44fb4b7093c91bd Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 27 Aug 2009 07:35:47 +0000 Subject: ucc_geth: Fix NULL pointer dereference in uec_get_ethtool_stats() In commit 3e73fc9a12679a546284d597c1f19165792d0b83 ("ucc_geth: Fix IO memory (un)mapping code") I fixed ug_regs IO memory leak by properly freeing the allocated memory. But ethtool_stats() callback doesn't check for ug_regs being NULL, and that causes following oops if 'ethtool -S' is executed on a closed eth device: Unable to handle kernel paging request for data at address 0x00000180 Faulting instruction address: 0xc0208228 Oops: Kernel access of bad area, sig: 11 [#1] ... NIP [c0208228] uec_get_ethtool_stats+0x38/0x140 LR [c02559a0] ethtool_get_stats+0xf8/0x23c Call Trace: [ef87bcd0] [c025597c] ethtool_get_stats+0xd4/0x23c (unreliable) [ef87bd00] [c025706c] dev_ethtool+0xfe8/0x11bc [ef87be00] [c0252b5c] dev_ioctl+0x454/0x6a8 ... ---[ end trace 77fff1162a9586b0 ]--- Segmentation fault This patch fixes the issue. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 61fe80d..304128f 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -319,9 +319,13 @@ static void uec_get_ethtool_stats(struct net_device *netdev, int i, j = 0; if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) { - base = (u32 __iomem *)&ugeth->ug_regs->tx64; + if (ugeth->ug_regs) + base = (u32 __iomem *)&ugeth->ug_regs->tx64; + else + base = NULL; + for (i = 0; i < UEC_HW_STATS_LEN; i++) - data[j++] = in_be32(&base[i]); + data[j++] = base ? in_be32(&base[i]) : 0; } if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) { base = (u32 __iomem *)ugeth->p_tx_fw_statistics_pram; -- cgit v0.10.2 From ed24157ede901608e00f28b4897398a373e1e926 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 27 Aug 2009 07:35:50 +0000 Subject: powerpc/qe: Implement qe_alive_during_sleep() helper function In some CPUs (i.e. MPC8569) QE shuts down completely during sleep, drivers may want to know that to reinitialize registers and buffer descriptors. This patch implements qe_alive_during_sleep() helper function, so far it just checks if MPC8569-compatible power management controller is present, which is a sign that QE turns off during sleep. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller diff --git a/arch/powerpc/include/asm/qe.h b/arch/powerpc/include/asm/qe.h index 157c5ca..f388f0a 100644 --- a/arch/powerpc/include/asm/qe.h +++ b/arch/powerpc/include/asm/qe.h @@ -154,6 +154,7 @@ int qe_get_snum(void); void qe_put_snum(u8 snum); unsigned int qe_get_num_of_risc(void); unsigned int qe_get_num_of_snums(void); +int qe_alive_during_sleep(void); /* we actually use cpm_muram implementation, define this for convenience */ #define qe_muram_init cpm_muram_init diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index 237e365..464271b 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -65,6 +65,19 @@ static unsigned int qe_num_of_snum; static phys_addr_t qebase = -1; +int qe_alive_during_sleep(void) +{ + static int ret = -1; + + if (ret != -1) + return ret; + + ret = !of_find_compatible_node(NULL, NULL, "fsl,mpc8569-pmc"); + + return ret; +} +EXPORT_SYMBOL(qe_alive_during_sleep); + phys_addr_t get_qe_base(void) { struct device_node *qe; -- cgit v0.10.2 From 54b15983840c9eb264e41f3b14af398a72ebd426 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 27 Aug 2009 07:35:54 +0000 Subject: ucc_geth: Factor out MAC initialization steps into a call This patch factors out MAC initialization into ucc_geth_init_mac() function that we'll use for suspend/resume. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 52a6750..e474e57 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3429,46 +3429,25 @@ static int ucc_geth_set_mac_addr(struct net_device *dev, void *p) return 0; } -/* Called when something needs to use the ethernet device */ -/* Returns 0 for success. */ -static int ucc_geth_open(struct net_device *dev) +static int ucc_geth_init_mac(struct ucc_geth_private *ugeth) { - struct ucc_geth_private *ugeth = netdev_priv(dev); + struct net_device *dev = ugeth->ndev; int err; - ugeth_vdbg("%s: IN", __func__); - - /* Test station address */ - if (dev->dev_addr[0] & ENET_GROUP_ADDR) { - if (netif_msg_ifup(ugeth)) - ugeth_err("%s: Multicast address used for station address" - " - is this what you wanted?", __func__); - return -EINVAL; - } - - err = init_phy(dev); - if (err) { - if (netif_msg_ifup(ugeth)) - ugeth_err("%s: Cannot initialize PHY, aborting.", - dev->name); - return err; - } - err = ucc_struct_init(ugeth); if (err) { if (netif_msg_ifup(ugeth)) - ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name); - goto out_err_stop; + ugeth_err("%s: Cannot configure internal struct, " + "aborting.", dev->name); + goto err; } - napi_enable(&ugeth->napi); - err = ucc_geth_startup(ugeth); if (err) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot configure net device, aborting.", dev->name); - goto out_err; + goto err; } err = adjust_enet_interface(ugeth); @@ -3476,7 +3455,7 @@ static int ucc_geth_open(struct net_device *dev) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot configure net device, aborting.", dev->name); - goto out_err; + goto err; } /* Set MACSTNADDR1, MACSTNADDR2 */ @@ -3490,13 +3469,51 @@ static int ucc_geth_open(struct net_device *dev) &ugeth->ug_regs->macstnaddr1, &ugeth->ug_regs->macstnaddr2); - phy_start(ugeth->phydev); - err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); if (err) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot enable net device, aborting.", dev->name); - goto out_err; + goto err; + } + + return 0; +err: + ucc_geth_stop(ugeth); + return err; +} + +/* Called when something needs to use the ethernet device */ +/* Returns 0 for success. */ +static int ucc_geth_open(struct net_device *dev) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + int err; + + ugeth_vdbg("%s: IN", __func__); + + /* Test station address */ + if (dev->dev_addr[0] & ENET_GROUP_ADDR) { + if (netif_msg_ifup(ugeth)) + ugeth_err("%s: Multicast address used for station " + "address - is this what you wanted?", + __func__); + return -EINVAL; + } + + err = init_phy(dev); + if (err) { + if (netif_msg_ifup(ugeth)) + ugeth_err("%s: Cannot initialize PHY, aborting.", + dev->name); + return err; + } + + err = ucc_geth_init_mac(ugeth); + if (err) { + if (netif_msg_ifup(ugeth)) + ugeth_err("%s: Cannot initialize MAC, aborting.", + dev->name); + goto err; } err = request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, @@ -3505,16 +3522,16 @@ static int ucc_geth_open(struct net_device *dev) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot get IRQ for net device, aborting.", dev->name); - goto out_err; + goto err; } + phy_start(ugeth->phydev); + napi_enable(&ugeth->napi); netif_start_queue(dev); return err; -out_err: - napi_disable(&ugeth->napi); -out_err_stop: +err: ucc_geth_stop(ugeth); return err; } -- cgit v0.10.2 From bf5aec2e79418adb42f1457152b427fd3d6316d9 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 27 Aug 2009 07:35:56 +0000 Subject: ucc_geth: Remove UGETH_MAGIC_PACKET Kconfig symbol and code This patch removes currently unused UGETH_MAGIC_PACKET Kconfig symbol and code, i.e. magic_packet_detection_{enable,disable} functions. The two functions each contain just two steps that we'll place into suspend/resume code path under CONFIG_PM. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bbe77a0..fed9bda 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2373,10 +2373,6 @@ config UCC_GETH This driver supports the Gigabit Ethernet mode of the QUICC Engine, which is available on some Freescale SOCs. -config UGETH_MAGIC_PACKET - bool "Magic Packet detection support" - depends on UCC_GETH - config UGETH_TX_ON_DEMAND bool "Transmit on Demand support" depends on UCC_GETH diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index e474e57..d2ca61d 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -438,38 +438,6 @@ static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth, QE_CR_PROTOCOL_ETHERNET, 0); } -#ifdef CONFIG_UGETH_MAGIC_PACKET -static void magic_packet_detection_enable(struct ucc_geth_private *ugeth) -{ - struct ucc_fast_private *uccf; - struct ucc_geth __iomem *ug_regs; - - uccf = ugeth->uccf; - ug_regs = ugeth->ug_regs; - - /* Enable interrupts for magic packet detection */ - setbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD); - - /* Enable magic packet detection */ - setbits32(&ug_regs->maccfg2, MACCFG2_MPE); -} - -static void magic_packet_detection_disable(struct ucc_geth_private *ugeth) -{ - struct ucc_fast_private *uccf; - struct ucc_geth __iomem *ug_regs; - - uccf = ugeth->uccf; - ug_regs = ugeth->ug_regs; - - /* Disable interrupts for magic packet detection */ - clrbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD); - - /* Disable magic packet detection */ - clrbits32(&ug_regs->maccfg2, MACCFG2_MPE); -} -#endif /* MAGIC_PACKET */ - static inline int compare_addr(u8 **addr1, u8 **addr2) { return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS); -- cgit v0.10.2 From 2394905f67aeec5f9452f2881cbeb2b42009de0e Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 27 Aug 2009 07:35:57 +0000 Subject: ucc_geth: Implement suspend/resume and Wake-On-LAN support This patch implements suspend/resume and WOL support for UCC Ethernet driver. We support two wake up events: wake on PHY/link changes and wake on magic packet. In some CPUs (like MPC8569) QE shuts down during sleep, so magic packet detection is unusable, and also on resume we should fully reinitialize UCC structures. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index d2ca61d..7fb96f3 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3497,6 +3497,10 @@ static int ucc_geth_open(struct net_device *dev) napi_enable(&ugeth->napi); netif_start_queue(dev); + device_set_wakeup_capable(&dev->dev, + qe_alive_during_sleep() || ugeth->phydev->irq); + device_set_wakeup_enable(&dev->dev, ugeth->wol_en); + return err; err: @@ -3561,6 +3565,85 @@ static void ucc_geth_timeout(struct net_device *dev) schedule_work(&ugeth->timeout_work); } + +#ifdef CONFIG_PM + +static int ucc_geth_suspend(struct of_device *ofdev, pm_message_t state) +{ + struct net_device *ndev = dev_get_drvdata(&ofdev->dev); + struct ucc_geth_private *ugeth = netdev_priv(ndev); + + if (!netif_running(ndev)) + return 0; + + napi_disable(&ugeth->napi); + + /* + * Disable the controller, otherwise we'll wakeup on any network + * activity. + */ + ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); + + if (ugeth->wol_en & WAKE_MAGIC) { + setbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD); + setbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE); + ucc_fast_enable(ugeth->uccf, COMM_DIR_RX_AND_TX); + } else if (!(ugeth->wol_en & WAKE_PHY)) { + phy_stop(ugeth->phydev); + } + + return 0; +} + +static int ucc_geth_resume(struct of_device *ofdev) +{ + struct net_device *ndev = dev_get_drvdata(&ofdev->dev); + struct ucc_geth_private *ugeth = netdev_priv(ndev); + int err; + + if (!netif_running(ndev)) + return 0; + + if (qe_alive_during_sleep()) { + if (ugeth->wol_en & WAKE_MAGIC) { + ucc_fast_disable(ugeth->uccf, COMM_DIR_RX_AND_TX); + clrbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE); + clrbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD); + } + ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); + } else { + /* + * Full reinitialization is required if QE shuts down + * during sleep. + */ + ucc_geth_memclean(ugeth); + + err = ucc_geth_init_mac(ugeth); + if (err) { + ugeth_err("%s: Cannot initialize MAC, aborting.", + ndev->name); + return err; + } + } + + ugeth->oldlink = 0; + ugeth->oldspeed = 0; + ugeth->oldduplex = -1; + + phy_stop(ugeth->phydev); + phy_start(ugeth->phydev); + + napi_enable(&ugeth->napi); + netif_start_queue(ndev); + + return 0; +} + +#else +#define ucc_geth_suspend NULL +#define ucc_geth_resume NULL +#endif + static phy_interface_t to_phy_interface(const char *phy_connection_type) { if (strcasecmp(phy_connection_type, "mii") == 0) @@ -3852,6 +3935,8 @@ static struct of_platform_driver ucc_geth_driver = { .match_table = ucc_geth_match, .probe = ucc_geth_probe, .remove = ucc_geth_remove, + .suspend = ucc_geth_suspend, + .resume = ucc_geth_resume, }; static int __init ucc_geth_init(void) diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index cfb31af..03a6ca0 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1222,6 +1222,7 @@ struct ucc_geth_private { int oldspeed; int oldduplex; int oldlink; + int wol_en; struct device_node *node; }; diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 304128f..7075f26 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -359,6 +359,44 @@ uec_get_drvinfo(struct net_device *netdev, drvinfo->regdump_len = uec_get_regs_len(netdev); } +#ifdef CONFIG_PM + +static void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct ucc_geth_private *ugeth = netdev_priv(netdev); + struct phy_device *phydev = ugeth->phydev; + + if (phydev && phydev->irq) + wol->supported |= WAKE_PHY; + if (qe_alive_during_sleep()) + wol->supported |= WAKE_MAGIC; + + wol->wolopts = ugeth->wol_en; +} + +static int uec_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct ucc_geth_private *ugeth = netdev_priv(netdev); + struct phy_device *phydev = ugeth->phydev; + + if (wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC)) + return -EINVAL; + else if (wol->wolopts & WAKE_PHY && (!phydev || !phydev->irq)) + return -EINVAL; + else if (wol->wolopts & WAKE_MAGIC && !qe_alive_during_sleep()) + return -EINVAL; + + ugeth->wol_en = wol->wolopts; + device_set_wakeup_enable(&netdev->dev, ugeth->wol_en); + + return 0; +} + +#else +#define uec_get_wol NULL +#define uec_set_wol NULL +#endif /* CONFIG_PM */ + static const struct ethtool_ops uec_ethtool_ops = { .get_settings = uec_get_settings, .set_settings = uec_set_settings, @@ -377,6 +415,8 @@ static const struct ethtool_ops uec_ethtool_ops = { .get_sset_count = uec_get_sset_count, .get_strings = uec_get_strings, .get_ethtool_stats = uec_get_ethtool_stats, + .get_wol = uec_get_wol, + .set_wol = uec_set_wol, }; void uec_set_ethtool_ops(struct net_device *netdev) -- cgit v0.10.2 From 5de3fcab91b0e1809eec030355d15801daf25083 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Thu, 20 Aug 2009 04:04:40 +0000 Subject: WAN: bit and/or confusion Fix the tests that check whether Frame* bits are not set Signed-off-by: Roel Kluin Signed-off-by: David S. Miller diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index e81946d..cc00e0f8 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -663,12 +663,12 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, } else { if (skb->data[pkt_len] & FrameRdo) dev->stats.rx_fifo_errors++; - else if (!(skb->data[pkt_len] | ~FrameCrc)) + else if (!(skb->data[pkt_len] & FrameCrc)) dev->stats.rx_crc_errors++; - else if (!(skb->data[pkt_len] | ~(FrameVfr | FrameRab))) + else if ((skb->data[pkt_len] & (FrameVfr | FrameRab)) != + FrameVfr | FrameRab) dev->stats.rx_length_errors++; - else - dev->stats.rx_errors++; + dev->stats.rx_errors++; dev_kfree_skb_irq(skb); } refill: -- cgit v0.10.2 From 6ca8b990e07914a87fd1f6dfc5507f5e1c4572e2 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sat, 29 Aug 2009 06:45:09 +0000 Subject: can: use correct NET_RX_ return values Dropped skb's should be documented by an appropriate return value. Use the correct NET_RX_DROP and NET_RX_SUCCESS values for that reason. Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/net/can/af_can.c b/net/can/af_can.c index f9c027b..ef1c43a 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -686,11 +686,11 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, can_stats.matches_delta++; } - return 0; + return NET_RX_SUCCESS; drop: kfree_skb(skb); - return 0; + return NET_RX_DROP; } /* -- cgit v0.10.2 From 7b3d3e4fc685a7d7e0b4c207ce24dfbab5689eb0 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Sat, 29 Aug 2009 20:21:21 +0000 Subject: netdevice: Consolidate to use existing macros where available. Patch compiled and 32 simultaneous netperf testing ran fine. Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9192cdf..60d3aac 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1257,7 +1257,7 @@ static inline void netif_tx_wake_queue(struct netdev_queue *dev_queue) { #ifdef CONFIG_NETPOLL_TRAP if (netpoll_trap()) { - clear_bit(__QUEUE_STATE_XOFF, &dev_queue->state); + netif_tx_start_queue(dev_queue); return; } #endif @@ -1363,7 +1363,8 @@ static inline int netif_running(const struct net_device *dev) static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index) { struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); - clear_bit(__QUEUE_STATE_XOFF, &txq->state); + + netif_tx_start_queue(txq); } /** @@ -1380,7 +1381,7 @@ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index) if (netpoll_trap()) return; #endif - set_bit(__QUEUE_STATE_XOFF, &txq->state); + netif_tx_stop_queue(txq); } /** @@ -1394,7 +1395,8 @@ static inline int __netif_subqueue_stopped(const struct net_device *dev, u16 queue_index) { struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); - return test_bit(__QUEUE_STATE_XOFF, &txq->state); + + return netif_tx_queue_stopped(txq); } static inline int netif_subqueue_stopped(const struct net_device *dev, @@ -1746,8 +1748,7 @@ static inline void netif_tx_unlock(struct net_device *dev) * force a schedule. */ clear_bit(__QUEUE_STATE_FROZEN, &txq->state); - if (!test_bit(__QUEUE_STATE_XOFF, &txq->state)) - __netif_schedule(txq->qdisc); + netif_schedule_queue(txq); } spin_unlock(&dev->tx_global_lock); } -- cgit v0.10.2 From 03a9a447d2dab755b22df79b5e205fdbb9b2c851 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Sat, 29 Aug 2009 20:21:36 +0000 Subject: net: convert remaining non-symbolic return values in dev_queue_xmit Patch compiled and 32 simultaneous netperf testing ran fine. Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 4b83789..4b33566 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1917,7 +1917,7 @@ gso: HARD_TX_LOCK(dev, txq, cpu); if (!netif_tx_queue_stopped(txq)) { - rc = 0; + rc = NET_XMIT_SUCCESS; if (!dev_hard_start_xmit(skb, dev, txq)) { HARD_TX_UNLOCK(dev, txq); goto out; -- cgit v0.10.2 From a453e0689a3ccf85c08cb89753d7685046248c5c Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Sun, 30 Aug 2009 22:20:28 -0700 Subject: pkt_sched: Fix resource limiting in pfifo_fast pfifo_fast_enqueue has this check: if (skb_queue_len(list) < qdisc_dev(qdisc)->tx_queue_len) { which allows each band to enqueue upto tx_queue_len skbs for a total of 3*tx_queue_len skbs. I am not sure if this was the intention of limiting in qdisc. Patch compiled and 32 simultaneous netperf testing ran fine. Also: # tc -s qdisc show dev eth2 qdisc pfifo_fast 0: root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 Sent 16835026752 bytes 373116 pkt (dropped 0, overlimits 0 requeues 25) rate 0bit 0pps backlog 0b 0p requeues 25 Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 6f7aebd..6128e6f 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -432,11 +432,11 @@ static inline struct sk_buff_head *band2list(struct pfifo_fast_priv *priv, static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc) { - int band = prio2band[skb->priority & TC_PRIO_MAX]; - struct pfifo_fast_priv *priv = qdisc_priv(qdisc); - struct sk_buff_head *list = band2list(priv, band); + if (skb_queue_len(&qdisc->q) < qdisc_dev(qdisc)->tx_queue_len) { + int band = prio2band[skb->priority & TC_PRIO_MAX]; + struct pfifo_fast_priv *priv = qdisc_priv(qdisc); + struct sk_buff_head *list = band2list(priv, band); - if (skb_queue_len(list) < qdisc_dev(qdisc)->tx_queue_len) { priv->bitmap |= (1 << band); qdisc->q.qlen++; return __qdisc_enqueue_tail(skb, qdisc, list); -- cgit v0.10.2 From 6fce365df8c4af573ea77e744fe310e034931d42 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:40 +0000 Subject: s2io.c: Use const for strings Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index bd6d713..07e95e9 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -125,7 +125,7 @@ static inline int is_s2io_card_up(const struct s2io_nic * sp) } /* Ethtool related variables and Macros. */ -static char s2io_gstrings[][ETH_GSTRING_LEN] = { +static const char s2io_gstrings[][ETH_GSTRING_LEN] = { "Register test\t(offline)", "Eeprom test\t(offline)", "Link test\t(online)", @@ -133,7 +133,7 @@ static char s2io_gstrings[][ETH_GSTRING_LEN] = { "BIST Test\t(offline)" }; -static char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = { +static const char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = { {"tmac_frms"}, {"tmac_data_octets"}, {"tmac_drop_frms"}, @@ -230,7 +230,7 @@ static char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = { {"rxf_wr_cnt"} }; -static char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = { +static const char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = { {"rmac_ttl_1519_4095_frms"}, {"rmac_ttl_4096_8191_frms"}, {"rmac_ttl_8192_max_frms"}, @@ -249,7 +249,7 @@ static char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = { {"link_fault_cnt"} }; -static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { +static const char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { {"\n DRIVER STATISTICS"}, {"single_bit_ecc_errs"}, {"double_bit_ecc_errs"}, -- cgit v0.10.2 From 13d866a9c912d6bc7133f4ef4d536c3a960b06cb Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:41 +0000 Subject: s2io.c: Shorten code line length by using intermediate pointers Repeated variable use and line wrapping is hard to read. Use temp variables instead of direct references. struct fifo_info *fifo = &mac_control->fifos[i]; struct ring_info *ring = &mac_control->rings[i]; struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 07e95e9..b6bd3c8 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -364,13 +364,19 @@ static void s2io_vlan_rx_register(struct net_device *dev, struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; - for (i = 0; i < config->tx_fifo_num; i++) - spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags[i]); + for (i = 0; i < config->tx_fifo_num; i++) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + spin_lock_irqsave(&fifo->tx_lock, flags[i]); + } nic->vlgrp = grp; - for (i = config->tx_fifo_num - 1; i >= 0; i--) - spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock, - flags[i]); + + for (i = config->tx_fifo_num - 1; i >= 0; i--) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + spin_unlock_irqrestore(&fifo->tx_lock, flags[i]); + } } /* Unregister the vlan */ @@ -382,15 +388,20 @@ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; - for (i = 0; i < config->tx_fifo_num; i++) - spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags[i]); + for (i = 0; i < config->tx_fifo_num; i++) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + spin_lock_irqsave(&fifo->tx_lock, flags[i]); + } if (nic->vlgrp) vlan_group_set_device(nic->vlgrp, vid, NULL); - for (i = config->tx_fifo_num - 1; i >= 0; i--) - spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock, - flags[i]); + for (i = config->tx_fifo_num - 1; i >= 0; i--) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + spin_unlock_irqrestore(&fifo->tx_lock, flags[i]); + } } /* @@ -635,11 +646,12 @@ static int init_shared_mem(struct s2io_nic *nic) mac_control = &nic->mac_control; config = &nic->config; - - /* Allocation and initialization of TXDLs in FIOFs */ + /* Allocation and initialization of TXDLs in FIFOs */ size = 0; for (i = 0; i < config->tx_fifo_num; i++) { - size += config->tx_cfg[i].fifo_len; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + size += tx_cfg->fifo_len; } if (size > MAX_AVAILABLE_TXDS) { DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, "); @@ -649,7 +661,9 @@ static int init_shared_mem(struct s2io_nic *nic) size = 0; for (i = 0; i < config->tx_fifo_num; i++) { - size = config->tx_cfg[i].fifo_len; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + size = tx_cfg->fifo_len; /* * Legal values are from 2 to 8192 */ @@ -666,11 +680,13 @@ static int init_shared_mem(struct s2io_nic *nic) lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { - int fifo_len = config->tx_cfg[i].fifo_len; + struct fifo_info *fifo = &mac_control->fifos[i]; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + int fifo_len = tx_cfg->fifo_len; int list_holder_size = fifo_len * sizeof(struct list_info_hold); - mac_control->fifos[i].list_info = kzalloc(list_holder_size, - GFP_KERNEL); - if (!mac_control->fifos[i].list_info) { + + fifo->list_info = kzalloc(list_holder_size, GFP_KERNEL); + if (!fifo->list_info) { DBG_PRINT(INFO_DBG, "Malloc failed for list_info\n"); return -ENOMEM; @@ -680,16 +696,17 @@ static int init_shared_mem(struct s2io_nic *nic) for (i = 0; i < config->tx_fifo_num; i++) { int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len, lst_per_page); - mac_control->fifos[i].tx_curr_put_info.offset = 0; - mac_control->fifos[i].tx_curr_put_info.fifo_len = - config->tx_cfg[i].fifo_len - 1; - mac_control->fifos[i].tx_curr_get_info.offset = 0; - mac_control->fifos[i].tx_curr_get_info.fifo_len = - config->tx_cfg[i].fifo_len - 1; - mac_control->fifos[i].fifo_no = i; - mac_control->fifos[i].nic = nic; - mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2; - mac_control->fifos[i].dev = dev; + struct fifo_info *fifo = &mac_control->fifos[i]; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + fifo->tx_curr_put_info.offset = 0; + fifo->tx_curr_put_info.fifo_len = tx_cfg->fifo_len - 1; + fifo->tx_curr_get_info.offset = 0; + fifo->tx_curr_get_info.fifo_len = tx_cfg->fifo_len - 1; + fifo->fifo_no = i; + fifo->nic = nic; + fifo->max_txds = MAX_SKB_FRAGS + 2; + fifo->dev = dev; for (j = 0; j < page_num; j++) { int k = 0; @@ -726,11 +743,11 @@ static int init_shared_mem(struct s2io_nic *nic) } while (k < lst_per_page) { int l = (j * lst_per_page) + k; - if (l == config->tx_cfg[i].fifo_len) + if (l == tx_cfg->fifo_len) break; - mac_control->fifos[i].list_info[l].list_virt_addr = + fifo->list_info[l].list_virt_addr = tmp_v + (k * lst_size); - mac_control->fifos[i].list_info[l].list_phy_addr = + fifo->list_info[l].list_phy_addr = tmp_p + (k * lst_size); k++; } @@ -738,10 +755,12 @@ static int init_shared_mem(struct s2io_nic *nic) } for (i = 0; i < config->tx_fifo_num; i++) { - size = config->tx_cfg[i].fifo_len; - mac_control->fifos[i].ufo_in_band_v - = kcalloc(size, sizeof(u64), GFP_KERNEL); - if (!mac_control->fifos[i].ufo_in_band_v) + struct fifo_info *fifo = &mac_control->fifos[i]; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + size = tx_cfg->fifo_len; + fifo->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL); + if (!fifo->ufo_in_band_v) return -ENOMEM; mem_allocated += (size * sizeof(u64)); } @@ -749,20 +768,19 @@ static int init_shared_mem(struct s2io_nic *nic) /* Allocation and initialization of RXDs in Rings */ size = 0; for (i = 0; i < config->rx_ring_num; i++) { - if (config->rx_cfg[i].num_rxd % - (rxd_count[nic->rxd_mode] + 1)) { + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + if (rx_cfg->num_rxd % (rxd_count[nic->rxd_mode] + 1)) { DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name); - DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ", - i); + DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ", i); DBG_PRINT(ERR_DBG, "RxDs per Block"); return FAILURE; } - size += config->rx_cfg[i].num_rxd; - mac_control->rings[i].block_count = - config->rx_cfg[i].num_rxd / + size += rx_cfg->num_rxd; + ring->block_count = rx_cfg->num_rxd / (rxd_count[nic->rxd_mode] + 1 ); - mac_control->rings[i].pkt_cnt = config->rx_cfg[i].num_rxd - - mac_control->rings[i].block_count; + ring->pkt_cnt = rx_cfg->num_rxd - ring->block_count; } if (nic->rxd_mode == RXD_MODE_1) size = (size * (sizeof(struct RxD1))); @@ -770,26 +788,26 @@ static int init_shared_mem(struct s2io_nic *nic) size = (size * (sizeof(struct RxD3))); for (i = 0; i < config->rx_ring_num; i++) { - mac_control->rings[i].rx_curr_get_info.block_index = 0; - mac_control->rings[i].rx_curr_get_info.offset = 0; - mac_control->rings[i].rx_curr_get_info.ring_len = - config->rx_cfg[i].num_rxd - 1; - mac_control->rings[i].rx_curr_put_info.block_index = 0; - mac_control->rings[i].rx_curr_put_info.offset = 0; - mac_control->rings[i].rx_curr_put_info.ring_len = - config->rx_cfg[i].num_rxd - 1; - mac_control->rings[i].nic = nic; - mac_control->rings[i].ring_no = i; - mac_control->rings[i].lro = lro_enable; - - blk_cnt = config->rx_cfg[i].num_rxd / - (rxd_count[nic->rxd_mode] + 1); + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + ring->rx_curr_get_info.block_index = 0; + ring->rx_curr_get_info.offset = 0; + ring->rx_curr_get_info.ring_len = rx_cfg->num_rxd - 1; + ring->rx_curr_put_info.block_index = 0; + ring->rx_curr_put_info.offset = 0; + ring->rx_curr_put_info.ring_len = rx_cfg->num_rxd - 1; + ring->nic = nic; + ring->ring_no = i; + ring->lro = lro_enable; + + blk_cnt = rx_cfg->num_rxd / (rxd_count[nic->rxd_mode] + 1); /* Allocating all the Rx blocks */ for (j = 0; j < blk_cnt; j++) { struct rx_block_info *rx_blocks; int l; - rx_blocks = &mac_control->rings[i].rx_blocks[j]; + rx_blocks = &ring->rx_blocks[j]; size = SIZE_OF_BLOCK; //size is always page size tmp_v_addr = pci_alloc_consistent(nic->pdev, size, &tmp_p_addr); @@ -825,16 +843,11 @@ static int init_shared_mem(struct s2io_nic *nic) } /* Interlinking all Rx Blocks */ for (j = 0; j < blk_cnt; j++) { - tmp_v_addr = - mac_control->rings[i].rx_blocks[j].block_virt_addr; - tmp_v_addr_next = - mac_control->rings[i].rx_blocks[(j + 1) % - blk_cnt].block_virt_addr; - tmp_p_addr = - mac_control->rings[i].rx_blocks[j].block_dma_addr; - tmp_p_addr_next = - mac_control->rings[i].rx_blocks[(j + 1) % - blk_cnt].block_dma_addr; + int next = (j + 1) % blk_cnt; + tmp_v_addr = ring->rx_blocks[j].block_virt_addr; + tmp_v_addr_next = ring->rx_blocks[next].block_virt_addr; + tmp_p_addr = ring->rx_blocks[j].block_dma_addr; + tmp_p_addr_next = ring->rx_blocks[next].block_dma_addr; pre_rxd_blk = (struct RxD_block *) tmp_v_addr; pre_rxd_blk->reserved_2_pNext_RxD_block = @@ -849,26 +862,28 @@ static int init_shared_mem(struct s2io_nic *nic) * and the buffers as well. */ for (i = 0; i < config->rx_ring_num; i++) { - blk_cnt = config->rx_cfg[i].num_rxd / - (rxd_count[nic->rxd_mode]+ 1); - mac_control->rings[i].ba = - kmalloc((sizeof(struct buffAdd *) * blk_cnt), - GFP_KERNEL); - if (!mac_control->rings[i].ba) + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + blk_cnt = rx_cfg->num_rxd / + (rxd_count[nic->rxd_mode]+ 1); + ring->ba = kmalloc((sizeof(struct buffAdd *) * blk_cnt), + GFP_KERNEL); + if (!ring->ba) return -ENOMEM; mem_allocated +=(sizeof(struct buffAdd *) * blk_cnt); for (j = 0; j < blk_cnt; j++) { int k = 0; - mac_control->rings[i].ba[j] = + ring->ba[j] = kmalloc((sizeof(struct buffAdd) * (rxd_count[nic->rxd_mode] + 1)), GFP_KERNEL); - if (!mac_control->rings[i].ba[j]) + if (!ring->ba[j]) return -ENOMEM; mem_allocated += (sizeof(struct buffAdd) * \ (rxd_count[nic->rxd_mode] + 1)); while (k != rxd_count[nic->rxd_mode]) { - ba = &mac_control->rings[i].ba[j][k]; + ba = &ring->ba[j][k]; ba->ba_0_org = (void *) kmalloc (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL); @@ -952,22 +967,23 @@ static void free_shared_mem(struct s2io_nic *nic) lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { - page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len, - lst_per_page); + struct fifo_info *fifo = &mac_control->fifos[i]; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + page_num = TXD_MEM_PAGE_CNT(tx_cfg->fifo_len, lst_per_page); for (j = 0; j < page_num; j++) { int mem_blks = (j * lst_per_page); - if (!mac_control->fifos[i].list_info) + struct list_info_hold *fli; + + if (!fifo->list_info) return; - if (!mac_control->fifos[i].list_info[mem_blks]. - list_virt_addr) + + fli = &fifo->list_info[mem_blks]; + if (!fli->list_virt_addr) break; pci_free_consistent(nic->pdev, PAGE_SIZE, - mac_control->fifos[i]. - list_info[mem_blks]. - list_virt_addr, - mac_control->fifos[i]. - list_info[mem_blks]. - list_phy_addr); + fli->list_virt_addr, + fli->list_phy_addr); nic->mac_control.stats_info->sw_stat.mem_freed += PAGE_SIZE; } @@ -986,25 +1002,25 @@ static void free_shared_mem(struct s2io_nic *nic) nic->mac_control.stats_info->sw_stat.mem_freed += PAGE_SIZE; } - kfree(mac_control->fifos[i].list_info); + kfree(fifo->list_info); nic->mac_control.stats_info->sw_stat.mem_freed += (nic->config.tx_cfg[i].fifo_len *sizeof(struct list_info_hold)); } size = SIZE_OF_BLOCK; for (i = 0; i < config->rx_ring_num; i++) { - blk_cnt = mac_control->rings[i].block_count; + struct ring_info *ring = &mac_control->rings[i]; + + blk_cnt = ring->block_count; for (j = 0; j < blk_cnt; j++) { - tmp_v_addr = mac_control->rings[i].rx_blocks[j]. - block_virt_addr; - tmp_p_addr = mac_control->rings[i].rx_blocks[j]. - block_dma_addr; + tmp_v_addr = ring->rx_blocks[j].block_virt_addr; + tmp_p_addr = ring->rx_blocks[j].block_dma_addr; if (tmp_v_addr == NULL) break; pci_free_consistent(nic->pdev, size, tmp_v_addr, tmp_p_addr); nic->mac_control.stats_info->sw_stat.mem_freed += size; - kfree(mac_control->rings[i].rx_blocks[j].rxds); + kfree(ring->rx_blocks[j].rxds); nic->mac_control.stats_info->sw_stat.mem_freed += ( sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]); } @@ -1013,15 +1029,17 @@ static void free_shared_mem(struct s2io_nic *nic) if (nic->rxd_mode == RXD_MODE_3B) { /* Freeing buffer storage addresses in 2BUFF mode. */ for (i = 0; i < config->rx_ring_num; i++) { - blk_cnt = config->rx_cfg[i].num_rxd / - (rxd_count[nic->rxd_mode] + 1); + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + blk_cnt = rx_cfg->num_rxd / + (rxd_count[nic->rxd_mode] + 1); for (j = 0; j < blk_cnt; j++) { int k = 0; - if (!mac_control->rings[i].ba[j]) + if (!ring->ba[j]) continue; while (k != rxd_count[nic->rxd_mode]) { - struct buffAdd *ba = - &mac_control->rings[i].ba[j][k]; + struct buffAdd *ba = &ring->ba[j][k]; kfree(ba->ba_0_org); nic->mac_control.stats_info->sw_stat.\ mem_freed += (BUF0_LEN + ALIGN_SIZE); @@ -1030,22 +1048,25 @@ static void free_shared_mem(struct s2io_nic *nic) mem_freed += (BUF1_LEN + ALIGN_SIZE); k++; } - kfree(mac_control->rings[i].ba[j]); + kfree(ring->ba[j]); nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd) * (rxd_count[nic->rxd_mode] + 1)); } - kfree(mac_control->rings[i].ba); + kfree(ring->ba); nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd *) * blk_cnt); } } for (i = 0; i < nic->config.tx_fifo_num; i++) { - if (mac_control->fifos[i].ufo_in_band_v) { + struct fifo_info *fifo = &mac_control->fifos[i]; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + if (fifo->ufo_in_band_v) { nic->mac_control.stats_info->sw_stat.mem_freed - += (config->tx_cfg[i].fifo_len * sizeof(u64)); - kfree(mac_control->fifos[i].ufo_in_band_v); + += (tx_cfg->fifo_len * sizeof(u64)); + kfree(fifo->ufo_in_band_v); } } @@ -1339,10 +1360,10 @@ static int init_nic(struct s2io_nic *nic) for (i = 0, j = 0; i < config->tx_fifo_num; i++) { - val64 |= - vBIT(config->tx_cfg[i].fifo_len - 1, ((j * 32) + 19), - 13) | vBIT(config->tx_cfg[i].fifo_priority, - ((j * 32) + 5), 3); + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + val64 |= vBIT(tx_cfg->fifo_len - 1, ((j * 32) + 19), 13) | + vBIT(tx_cfg->fifo_priority, ((j * 32) + 5), 3); if (i == (config->tx_fifo_num - 1)) { if (i % 2 == 0) @@ -1400,9 +1421,9 @@ static int init_nic(struct s2io_nic *nic) /* Rx DMA intialization. */ val64 = 0; for (i = 0; i < config->rx_ring_num; i++) { - val64 |= - vBIT(config->rx_cfg[i].ring_priority, (5 + (i * 8)), - 3); + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + + val64 |= vBIT(rx_cfg->ring_priority, (5 + (i * 8)), 3); } writeq(val64, &bar0->rx_queue_priority); @@ -2276,7 +2297,9 @@ static int start_nic(struct s2io_nic *nic) /* PRC Initialization and configuration */ for (i = 0; i < config->rx_ring_num; i++) { - writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr, + struct ring_info *ring = &mac_control->rings[i]; + + writeq((u64) ring->rx_blocks[0].block_dma_addr, &bar0->prc_rxd0_n[i]); val64 = readq(&bar0->prc_ctrl_n[i]); @@ -2434,11 +2457,13 @@ static void free_tx_buffers(struct s2io_nic *nic) config = &nic->config; for (i = 0; i < config->tx_fifo_num; i++) { + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + struct fifo_info *fifo = &mac_control->fifos[i]; unsigned long flags; - spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags); - for (j = 0; j < config->tx_cfg[i].fifo_len; j++) { - txdp = (struct TxD *) \ - mac_control->fifos[i].list_info[j].list_virt_addr; + + spin_lock_irqsave(&fifo->tx_lock, flags); + for (j = 0; j < tx_cfg->fifo_len; j++) { + txdp = (struct TxD *)fifo->list_info[j].list_virt_addr; skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j); if (skb) { nic->mac_control.stats_info->sw_stat.mem_freed @@ -2450,9 +2475,9 @@ static void free_tx_buffers(struct s2io_nic *nic) DBG_PRINT(INTR_DBG, "%s:forcibly freeing %d skbs on FIFO%d\n", dev->name, cnt, i); - mac_control->fifos[i].tx_curr_get_info.offset = 0; - mac_control->fifos[i].tx_curr_put_info.offset = 0; - spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock, flags); + fifo->tx_curr_get_info.offset = 0; + fifo->tx_curr_put_info.offset = 0; + spin_unlock_irqrestore(&fifo->tx_lock, flags); } } @@ -2795,14 +2820,16 @@ static void free_rx_buffers(struct s2io_nic *sp) config = &sp->config; for (i = 0; i < config->rx_ring_num; i++) { + struct ring_info *ring = &mac_control->rings[i]; + for (blk = 0; blk < rx_ring_sz[i]; blk++) free_rxd_blk(sp,i,blk); - mac_control->rings[i].rx_curr_put_info.block_index = 0; - mac_control->rings[i].rx_curr_get_info.block_index = 0; - mac_control->rings[i].rx_curr_put_info.offset = 0; - mac_control->rings[i].rx_curr_get_info.offset = 0; - mac_control->rings[i].rx_bufs_left = 0; + ring->rx_curr_put_info.block_index = 0; + ring->rx_curr_get_info.block_index = 0; + ring->rx_curr_put_info.offset = 0; + ring->rx_curr_get_info.offset = 0; + ring->rx_bufs_left = 0; DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n", dev->name, buf_cnt, i); } @@ -2866,7 +2893,6 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) static int s2io_poll_inta(struct napi_struct *napi, int budget) { struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); - struct ring_info *ring; struct config_param *config; struct mac_info *mac_control; int pkts_processed = 0; @@ -2881,7 +2907,7 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) return 0; for (i = 0; i < config->rx_ring_num; i++) { - ring = &mac_control->rings[i]; + struct ring_info *ring = &mac_control->rings[i]; ring_pkts_processed = rx_intr_handler(ring, budget); s2io_chk_rx_buffers(nic, ring); pkts_processed += ring_pkts_processed; @@ -2936,12 +2962,16 @@ static void s2io_netpoll(struct net_device *dev) tx_intr_handler(&mac_control->fifos[i]); /* check for received packet and indicate up to network */ - for (i = 0; i < config->rx_ring_num; i++) - rx_intr_handler(&mac_control->rings[i], 0); + for (i = 0; i < config->rx_ring_num; i++) { + struct ring_info *ring = &mac_control->rings[i]; + + rx_intr_handler(ring, 0); + } for (i = 0; i < config->rx_ring_num; i++) { - if (fill_rx_buffers(nic, &mac_control->rings[i], 0) == - -ENOMEM) { + struct ring_info *ring = &mac_control->rings[i]; + + if (fill_rx_buffers(nic, ring, 0) == -ENOMEM) { DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n"); break; @@ -4803,8 +4833,11 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) if (reason & GEN_INTR_RXTRAFFIC) writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); - for (i = 0; i < config->rx_ring_num; i++) - rx_intr_handler(&mac_control->rings[i], 0); + for (i = 0; i < config->rx_ring_num; i++) { + struct ring_info *ring = &mac_control->rings[i]; + + rx_intr_handler(ring, 0); + } } /* @@ -4825,8 +4858,11 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) * Reallocate the buffers from the interrupt handler itself. */ if (!config->napi) { - for (i = 0; i < config->rx_ring_num; i++) - s2io_chk_rx_buffers(sp, &mac_control->rings[i]); + for (i = 0; i < config->rx_ring_num; i++) { + struct ring_info *ring = &mac_control->rings[i]; + + s2io_chk_rx_buffers(sp, ring); + } } writeq(sp->general_int_mask, &bar0->general_int_mask); readl(&bar0->general_int_status); @@ -4923,8 +4959,10 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) /* collect per-ring rx_packets and rx_bytes */ dev->stats.rx_packets = dev->stats.rx_bytes = 0; for (i = 0; i < config->rx_ring_num; i++) { - dev->stats.rx_packets += mac_control->rings[i].rx_packets; - dev->stats.rx_bytes += mac_control->rings[i].rx_bytes; + struct ring_info *ring = &mac_control->rings[i]; + + dev->stats.rx_packets += ring->rx_packets; + dev->stats.rx_bytes += ring->rx_bytes; } return (&dev->stats); @@ -6974,15 +7012,16 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp) size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4; for (i = 0; i < config->rx_ring_num; i++) { - blk_cnt = config->rx_cfg[i].num_rxd / - (rxd_count[sp->rxd_mode] +1); + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + blk_cnt = rx_cfg->num_rxd / (rxd_count[sp->rxd_mode] +1); for (j = 0; j < blk_cnt; j++) { for (k = 0; k < rxd_count[sp->rxd_mode]; k++) { - rxdp = mac_control->rings[i]. - rx_blocks[j].rxds[k].virt_addr; + rxdp = ring-> rx_blocks[j].rxds[k].virt_addr; if(sp->rxd_mode == RXD_MODE_3B) - ba = &mac_control->rings[i].ba[j][k]; + ba = &ring->ba[j][k]; if (set_rxd_buffer_pointer(sp, rxdp, ba, &skb,(u64 *)&temp0_64, (u64 *)&temp1_64, @@ -7205,8 +7244,10 @@ static int s2io_card_up(struct s2io_nic * sp) config = &sp->config; for (i = 0; i < config->rx_ring_num; i++) { - mac_control->rings[i].mtu = dev->mtu; - ret = fill_rx_buffers(sp, &mac_control->rings[i], 1); + struct ring_info *ring = &mac_control->rings[i]; + + ring->mtu = dev->mtu; + ret = fill_rx_buffers(sp, ring, 1); if (ret) { DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n", dev->name); @@ -7215,7 +7256,7 @@ static int s2io_card_up(struct s2io_nic * sp) return -ENOMEM; } DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i, - mac_control->rings[i].rx_bufs_left); + ring->rx_bufs_left); } /* Initialise napi */ @@ -7875,8 +7916,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) config->multiq = dev_multiq; for (i = 0; i < config->tx_fifo_num; i++) { - config->tx_cfg[i].fifo_len = tx_fifo_len[i]; - config->tx_cfg[i].fifo_priority = i; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + tx_cfg->fifo_len = tx_fifo_len[i]; + tx_cfg->fifo_priority = i; } /* mapping the QoS priority to the configured fifos */ @@ -7890,9 +7933,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) config->tx_intr_type = TXD_INT_TYPE_UTILZ; for (i = 0; i < config->tx_fifo_num; i++) { - config->tx_cfg[i].f_no_snoop = - (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER); - if (config->tx_cfg[i].fifo_len < 65) { + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + tx_cfg->f_no_snoop = (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER); + if (tx_cfg->fifo_len < 65) { config->tx_intr_type = TXD_INT_TYPE_PER_LIST; break; } @@ -7903,20 +7947,23 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Rx side parameters. */ config->rx_ring_num = rx_ring_num; for (i = 0; i < config->rx_ring_num; i++) { - config->rx_cfg[i].num_rxd = rx_ring_sz[i] * - (rxd_count[sp->rxd_mode] + 1); - config->rx_cfg[i].ring_priority = i; - mac_control->rings[i].rx_bufs_left = 0; - mac_control->rings[i].rxd_mode = sp->rxd_mode; - mac_control->rings[i].rxd_count = rxd_count[sp->rxd_mode]; - mac_control->rings[i].pdev = sp->pdev; - mac_control->rings[i].dev = sp->dev; + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + rx_cfg->num_rxd = rx_ring_sz[i] * (rxd_count[sp->rxd_mode] + 1); + rx_cfg->ring_priority = i; + ring->rx_bufs_left = 0; + ring->rxd_mode = sp->rxd_mode; + ring->rxd_count = rxd_count[sp->rxd_mode]; + ring->pdev = sp->pdev; + ring->dev = sp->dev; } for (i = 0; i < rx_ring_num; i++) { - config->rx_cfg[i].ring_org = RING_ORG_BUFF1; - config->rx_cfg[i].f_no_snoop = - (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER); + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + + rx_cfg->ring_org = RING_ORG_BUFF1; + rx_cfg->f_no_snoop = (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER); } /* Setting Mac Control parameters */ @@ -8015,9 +8062,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } if (config->intr_type == MSI_X) { - for (i = 0; i < config->rx_ring_num ; i++) - netif_napi_add(dev, &mac_control->rings[i].napi, - s2io_poll_msix, 64); + for (i = 0; i < config->rx_ring_num ; i++) { + struct ring_info *ring = &mac_control->rings[i]; + + netif_napi_add(dev, &ring->napi, s2io_poll_msix, 64); + } } else { netif_napi_add(dev, &sp->napi, s2io_poll_inta, 64); } @@ -8089,8 +8138,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->state = 0; /* Initialize spinlocks */ - for (i = 0; i < sp->config.tx_fifo_num; i++) - spin_lock_init(&mac_control->fifos[i].tx_lock); + for (i = 0; i < sp->config.tx_fifo_num; i++) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + spin_lock_init(&fifo->tx_lock); + } /* * SXE-002: Configure link and activity LED to init state @@ -8165,8 +8217,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) break; } if (sp->config.multiq) { - for (i = 0; i < sp->config.tx_fifo_num; i++) - mac_control->fifos[i].multiq = config->multiq; + for (i = 0; i < sp->config.tx_fifo_num; i++) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + fifo->multiq = config->multiq; + } DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n", dev->name); } else -- cgit v0.10.2 From 4f87032021be1aa0c3bb66b0c89d30cb35b57f8f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:42 +0000 Subject: s2io.c: Use calculated size in kmallocs Use consistent style. Don't calculate the kmalloc size multiple times Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index b6bd3c8..75f2209 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -823,15 +823,15 @@ static int init_shared_mem(struct s2io_nic *nic) } mem_allocated += size; memset(tmp_v_addr, 0, size); + + size = sizeof(struct rxd_info) * + rxd_count[nic->rxd_mode]; rx_blocks->block_virt_addr = tmp_v_addr; rx_blocks->block_dma_addr = tmp_p_addr; - rx_blocks->rxds = kmalloc(sizeof(struct rxd_info)* - rxd_count[nic->rxd_mode], - GFP_KERNEL); + rx_blocks->rxds = kmalloc(size, GFP_KERNEL); if (!rx_blocks->rxds) return -ENOMEM; - mem_allocated += - (sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]); + mem_allocated += size; for (l=0; lrxd_mode];l++) { rx_blocks->rxds[l].virt_addr = rx_blocks->block_virt_addr + @@ -867,41 +867,37 @@ static int init_shared_mem(struct s2io_nic *nic) blk_cnt = rx_cfg->num_rxd / (rxd_count[nic->rxd_mode]+ 1); - ring->ba = kmalloc((sizeof(struct buffAdd *) * blk_cnt), - GFP_KERNEL); + size = sizeof(struct buffAdd *) * blk_cnt; + ring->ba = kmalloc(size, GFP_KERNEL); if (!ring->ba) return -ENOMEM; - mem_allocated +=(sizeof(struct buffAdd *) * blk_cnt); + mem_allocated += size; for (j = 0; j < blk_cnt; j++) { int k = 0; - ring->ba[j] = - kmalloc((sizeof(struct buffAdd) * - (rxd_count[nic->rxd_mode] + 1)), - GFP_KERNEL); + + size = sizeof(struct buffAdd) * + (rxd_count[nic->rxd_mode] + 1); + ring->ba[j] = kmalloc(size, GFP_KERNEL); if (!ring->ba[j]) return -ENOMEM; - mem_allocated += (sizeof(struct buffAdd) * \ - (rxd_count[nic->rxd_mode] + 1)); + mem_allocated += size; while (k != rxd_count[nic->rxd_mode]) { ba = &ring->ba[j][k]; - - ba->ba_0_org = (void *) kmalloc - (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL); + size = BUF0_LEN + ALIGN_SIZE; + ba->ba_0_org = kmalloc(size, GFP_KERNEL); if (!ba->ba_0_org) return -ENOMEM; - mem_allocated += - (BUF0_LEN + ALIGN_SIZE); + mem_allocated += size; tmp = (unsigned long)ba->ba_0_org; tmp += ALIGN_SIZE; tmp &= ~((unsigned long) ALIGN_SIZE); ba->ba_0 = (void *) tmp; - ba->ba_1_org = (void *) kmalloc - (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL); + size = BUF1_LEN + ALIGN_SIZE; + ba->ba_1_org = kmalloc(size, GFP_KERNEL); if (!ba->ba_1_org) return -ENOMEM; - mem_allocated - += (BUF1_LEN + ALIGN_SIZE); + mem_allocated += size; tmp = (unsigned long) ba->ba_1_org; tmp += ALIGN_SIZE; tmp &= ~((unsigned long) ALIGN_SIZE); @@ -3835,23 +3831,22 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) u64 rx_mat; u16 msi_control; /* Temp variable */ int ret, i, j, msix_indx = 1; + int size; - nic->entries = kmalloc(nic->num_entries * sizeof(struct msix_entry), - GFP_KERNEL); + size = nic->num_entries * sizeof(struct msix_entry); + nic->entries = kmalloc(size, GFP_KERNEL); if (!nic->entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \ __func__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated - += (nic->num_entries * sizeof(struct msix_entry)); + nic->mac_control.stats_info->sw_stat.mem_allocated += size; - memset(nic->entries, 0, nic->num_entries * sizeof(struct msix_entry)); + memset(nic->entries, 0, size); - nic->s2io_entries = - kmalloc(nic->num_entries * sizeof(struct s2io_msix_entry), - GFP_KERNEL); + size = nic->num_entries * sizeof(struct s2io_msix_entry); + nic->s2io_entries = kmalloc(size, GFP_KERNEL); if (!nic->s2io_entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __func__); @@ -3861,10 +3856,8 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) += (nic->num_entries * sizeof(struct msix_entry)); return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated - += (nic->num_entries * sizeof(struct s2io_msix_entry)); - memset(nic->s2io_entries, 0, - nic->num_entries * sizeof(struct s2io_msix_entry)); + nic->mac_control.stats_info->sw_stat.mem_allocated += size; + memset(nic->s2io_entries, 0, size); nic->entries[0].entry = 0; nic->s2io_entries[0].entry = 0; -- cgit v0.10.2 From 44364a035a4f7c5b58fd96b1a90b52746d1aab6b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:43 +0000 Subject: s2io.c: use kzalloc Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 75f2209..134cdb3 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -3834,7 +3834,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) int size; size = nic->num_entries * sizeof(struct msix_entry); - nic->entries = kmalloc(size, GFP_KERNEL); + nic->entries = kzalloc(size, GFP_KERNEL); if (!nic->entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \ __func__); @@ -3843,10 +3843,8 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) } nic->mac_control.stats_info->sw_stat.mem_allocated += size; - memset(nic->entries, 0, size); - size = nic->num_entries * sizeof(struct s2io_msix_entry); - nic->s2io_entries = kmalloc(size, GFP_KERNEL); + nic->s2io_entries = kzalloc(size, GFP_KERNEL); if (!nic->s2io_entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __func__); @@ -3857,7 +3855,6 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) return -ENOMEM; } nic->mac_control.stats_info->sw_stat.mem_allocated += size; - memset(nic->s2io_entries, 0, size); nic->entries[0].entry = 0; nic->s2io_entries[0].entry = 0; -- cgit v0.10.2 From d44570e4067aa8b832b1c1e1eb6da079f590d501 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:44 +0000 Subject: s2io.c: Make more conforming to normal kernel style Still has a few long lines. checkpatch was: total: 263 errors, 53 warnings, 8751 lines checked is: total: 4 errors, 35 warnings, 8767 lines checked Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 134cdb3..003dd8c 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1,7 +1,7 @@ /************************************************************************ * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC * Copyright(c) 2002-2007 Neterion Inc. - + * * This software may be used and distributed according to the terms of * the GNU General Public License (GPL), incorporated herein by reference. * Drivers based on or derived from this code fall under the GPL and must @@ -75,11 +75,11 @@ #include #include #include +#include +#include #include #include -#include -#include #include #include @@ -93,15 +93,15 @@ static char s2io_driver_name[] = "Neterion"; static char s2io_driver_version[] = DRV_VERSION; -static int rxd_size[2] = {32,48}; -static int rxd_count[2] = {127,85}; +static int rxd_size[2] = {32, 48}; +static int rxd_count[2] = {127, 85}; static inline int RXD_IS_UP2DT(struct RxD_t *rxdp) { int ret; ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) && - (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK)); + (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK)); return ret; } @@ -111,15 +111,15 @@ static inline int RXD_IS_UP2DT(struct RxD_t *rxdp) * problem, 600B, 600C, 600D, 640B, 640C and 640D. * macro below identifies these cards given the subsystem_id. */ -#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \ - (dev_type == XFRAME_I_DEVICE) ? \ - ((((subid >= 0x600B) && (subid <= 0x600D)) || \ - ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0 +#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \ + (dev_type == XFRAME_I_DEVICE) ? \ + ((((subid >= 0x600B) && (subid <= 0x600D)) || \ + ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0 #define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \ ADAPTER_STATUS_RMAC_LOCAL_FAULT))) -static inline int is_s2io_card_up(const struct s2io_nic * sp) +static inline int is_s2io_card_up(const struct s2io_nic *sp) { return test_bit(__S2IO_STATE_CARD_UP, &sp->state); } @@ -328,20 +328,20 @@ static const char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { #define S2IO_ENHANCED_STAT_LEN ARRAY_SIZE(ethtool_enhanced_stats_keys) #define S2IO_DRIVER_STAT_LEN ARRAY_SIZE(ethtool_driver_stats_keys) -#define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN ) -#define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN ) +#define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN) +#define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN) -#define XFRAME_I_STAT_STRINGS_LEN ( XFRAME_I_STAT_LEN * ETH_GSTRING_LEN ) -#define XFRAME_II_STAT_STRINGS_LEN ( XFRAME_II_STAT_LEN * ETH_GSTRING_LEN ) +#define XFRAME_I_STAT_STRINGS_LEN (XFRAME_I_STAT_LEN * ETH_GSTRING_LEN) +#define XFRAME_II_STAT_STRINGS_LEN (XFRAME_II_STAT_LEN * ETH_GSTRING_LEN) #define S2IO_TEST_LEN ARRAY_SIZE(s2io_gstrings) -#define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN +#define S2IO_STRINGS_LEN (S2IO_TEST_LEN * ETH_GSTRING_LEN) -#define S2IO_TIMER_CONF(timer, handle, arg, exp) \ - init_timer(&timer); \ - timer.function = handle; \ - timer.data = (unsigned long) arg; \ - mod_timer(&timer, (jiffies + exp)) \ +#define S2IO_TIMER_CONF(timer, handle, arg, exp) \ + init_timer(&timer); \ + timer.function = handle; \ + timer.data = (unsigned long)arg; \ + mod_timer(&timer, (jiffies + exp)) \ /* copy mac addr to def_mac_addr array */ static void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr) @@ -507,11 +507,11 @@ S2IO_PARM_INT(ufo, 0); S2IO_PARM_INT(vlan_tag_strip, NO_STRIP_IN_PROMISC); static unsigned int tx_fifo_len[MAX_TX_FIFOS] = - {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN}; +{DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN}; static unsigned int rx_ring_sz[MAX_RX_RINGS] = - {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT}; +{[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT}; static unsigned int rts_frm_len[MAX_RX_RINGS] = - {[0 ...(MAX_RX_RINGS - 1)] = 0 }; +{[0 ...(MAX_RX_RINGS - 1)] = 0 }; module_param_array(tx_fifo_len, uint, NULL, 0); module_param_array(rx_ring_sz, uint, NULL, 0); @@ -527,9 +527,9 @@ static struct pci_device_id s2io_tbl[] __devinitdata = { {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI, PCI_ANY_ID, PCI_ANY_ID}, {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN, - PCI_ANY_ID, PCI_ANY_ID}, - {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI, - PCI_ANY_ID, PCI_ANY_ID}, + PCI_ANY_ID, PCI_ANY_ID}, + {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI, + PCI_ANY_ID, PCI_ANY_ID}, {0,} }; @@ -542,11 +542,11 @@ static struct pci_error_handlers s2io_err_handler = { }; static struct pci_driver s2io_driver = { - .name = "S2IO", - .id_table = s2io_tbl, - .probe = s2io_init_nic, - .remove = __devexit_p(s2io_rem_nic), - .err_handler = &s2io_err_handler, + .name = "S2IO", + .id_table = s2io_tbl, + .probe = s2io_init_nic, + .remove = __devexit_p(s2io_rem_nic), + .err_handler = &s2io_err_handler, }; /* A simplifier macro used both by init and free shared_mem Fns(). */ @@ -655,7 +655,8 @@ static int init_shared_mem(struct s2io_nic *nic) } if (size > MAX_AVAILABLE_TXDS) { DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, "); - DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size); + DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", + size); return -EINVAL; } @@ -671,7 +672,7 @@ static int init_shared_mem(struct s2io_nic *nic) DBG_PRINT(ERR_DBG, "s2io: Invalid fifo len (%d)", size); DBG_PRINT(ERR_DBG, "for fifo %d\n", i); DBG_PRINT(ERR_DBG, "s2io: Legal values for fifo len" - "are 2 to 8192\n"); + "are 2 to 8192\n"); return -EINVAL; } } @@ -687,8 +688,7 @@ static int init_shared_mem(struct s2io_nic *nic) fifo->list_info = kzalloc(list_holder_size, GFP_KERNEL); if (!fifo->list_info) { - DBG_PRINT(INFO_DBG, - "Malloc failed for list_info\n"); + DBG_PRINT(INFO_DBG, "Malloc failed for list_info\n"); return -ENOMEM; } mem_allocated += list_holder_size; @@ -715,8 +715,7 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { - DBG_PRINT(INFO_DBG, - "pci_alloc_consistent "); + DBG_PRINT(INFO_DBG, "pci_alloc_consistent "); DBG_PRINT(INFO_DBG, "failed for TxDL\n"); return -ENOMEM; } @@ -728,15 +727,17 @@ static int init_shared_mem(struct s2io_nic *nic) if (!tmp_p) { mac_control->zerodma_virt_addr = tmp_v; DBG_PRINT(INIT_DBG, - "%s: Zero DMA address for TxDL. ", dev->name); + "%s: Zero DMA address for TxDL. ", + dev->name); DBG_PRINT(INIT_DBG, - "Virtual address %p\n", tmp_v); + "Virtual address %p\n", tmp_v); tmp_v = pci_alloc_consistent(nic->pdev, - PAGE_SIZE, &tmp_p); + PAGE_SIZE, &tmp_p); if (!tmp_v) { DBG_PRINT(INFO_DBG, - "pci_alloc_consistent "); - DBG_PRINT(INFO_DBG, "failed for TxDL\n"); + "pci_alloc_consistent "); + DBG_PRINT(INFO_DBG, + "failed for TxDL\n"); return -ENOMEM; } mem_allocated += PAGE_SIZE; @@ -746,9 +747,9 @@ static int init_shared_mem(struct s2io_nic *nic) if (l == tx_cfg->fifo_len) break; fifo->list_info[l].list_virt_addr = - tmp_v + (k * lst_size); + tmp_v + (k * lst_size); fifo->list_info[l].list_phy_addr = - tmp_p + (k * lst_size); + tmp_p + (k * lst_size); k++; } } @@ -779,7 +780,7 @@ static int init_shared_mem(struct s2io_nic *nic) } size += rx_cfg->num_rxd; ring->block_count = rx_cfg->num_rxd / - (rxd_count[nic->rxd_mode] + 1 ); + (rxd_count[nic->rxd_mode] + 1); ring->pkt_cnt = rx_cfg->num_rxd - ring->block_count; } if (nic->rxd_mode == RXD_MODE_1) @@ -808,7 +809,7 @@ static int init_shared_mem(struct s2io_nic *nic) int l; rx_blocks = &ring->rx_blocks[j]; - size = SIZE_OF_BLOCK; //size is always page size + size = SIZE_OF_BLOCK; /* size is always page size */ tmp_v_addr = pci_alloc_consistent(nic->pdev, size, &tmp_p_addr); if (tmp_v_addr == NULL) { @@ -832,7 +833,7 @@ static int init_shared_mem(struct s2io_nic *nic) if (!rx_blocks->rxds) return -ENOMEM; mem_allocated += size; - for (l=0; lrxd_mode];l++) { + for (l = 0; l < rxd_count[nic->rxd_mode]; l++) { rx_blocks->rxds[l].virt_addr = rx_blocks->block_virt_addr + (rxd_size[nic->rxd_mode] * l); @@ -849,11 +850,11 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_p_addr = ring->rx_blocks[j].block_dma_addr; tmp_p_addr_next = ring->rx_blocks[next].block_dma_addr; - pre_rxd_blk = (struct RxD_block *) tmp_v_addr; + pre_rxd_blk = (struct RxD_block *)tmp_v_addr; pre_rxd_blk->reserved_2_pNext_RxD_block = - (unsigned long) tmp_v_addr_next; + (unsigned long)tmp_v_addr_next; pre_rxd_blk->pNext_RxD_Blk_physical = - (u64) tmp_p_addr_next; + (u64)tmp_p_addr_next; } } if (nic->rxd_mode == RXD_MODE_3B) { @@ -866,7 +867,7 @@ static int init_shared_mem(struct s2io_nic *nic) struct ring_info *ring = &mac_control->rings[i]; blk_cnt = rx_cfg->num_rxd / - (rxd_count[nic->rxd_mode]+ 1); + (rxd_count[nic->rxd_mode] + 1); size = sizeof(struct buffAdd *) * blk_cnt; ring->ba = kmalloc(size, GFP_KERNEL); if (!ring->ba) @@ -890,18 +891,18 @@ static int init_shared_mem(struct s2io_nic *nic) mem_allocated += size; tmp = (unsigned long)ba->ba_0_org; tmp += ALIGN_SIZE; - tmp &= ~((unsigned long) ALIGN_SIZE); - ba->ba_0 = (void *) tmp; + tmp &= ~((unsigned long)ALIGN_SIZE); + ba->ba_0 = (void *)tmp; size = BUF1_LEN + ALIGN_SIZE; ba->ba_1_org = kmalloc(size, GFP_KERNEL); if (!ba->ba_1_org) return -ENOMEM; mem_allocated += size; - tmp = (unsigned long) ba->ba_1_org; + tmp = (unsigned long)ba->ba_1_org; tmp += ALIGN_SIZE; - tmp &= ~((unsigned long) ALIGN_SIZE); - ba->ba_1 = (void *) tmp; + tmp &= ~((unsigned long)ALIGN_SIZE); + ba->ba_1 = (void *)tmp; k++; } } @@ -910,8 +911,9 @@ static int init_shared_mem(struct s2io_nic *nic) /* Allocation and initialization of Statistics block */ size = sizeof(struct stat_block); - mac_control->stats_mem = pci_alloc_consistent - (nic->pdev, size, &mac_control->stats_mem_phy); + mac_control->stats_mem = + pci_alloc_consistent(nic->pdev, size, + &mac_control->stats_mem_phy); if (!mac_control->stats_mem) { /* @@ -925,10 +927,10 @@ static int init_shared_mem(struct s2io_nic *nic) mac_control->stats_mem_sz = size; tmp_v_addr = mac_control->stats_mem; - mac_control->stats_info = (struct stat_block *) tmp_v_addr; + mac_control->stats_info = (struct stat_block *)tmp_v_addr; memset(tmp_v_addr, 0, size); DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name, - (unsigned long long) tmp_p_addr); + (unsigned long long)tmp_p_addr); mac_control->stats_info->sw_stat.mem_allocated += mem_allocated; return SUCCESS; } @@ -959,7 +961,7 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control = &nic->mac_control; config = &nic->config; - lst_size = (sizeof(struct TxD) * config->max_txds); + lst_size = sizeof(struct TxD) * config->max_txds; lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { @@ -981,7 +983,7 @@ static void free_shared_mem(struct s2io_nic *nic) fli->list_virt_addr, fli->list_phy_addr); nic->mac_control.stats_info->sw_stat.mem_freed - += PAGE_SIZE; + += PAGE_SIZE; } /* If we got a zero DMA address during allocation, * free the page now @@ -991,16 +993,17 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control->zerodma_virt_addr, (dma_addr_t)0); DBG_PRINT(INIT_DBG, - "%s: Freeing TxDL with zero DMA addr. ", - dev->name); + "%s: Freeing TxDL with zero DMA addr. ", + dev->name); DBG_PRINT(INIT_DBG, "Virtual address %p\n", - mac_control->zerodma_virt_addr); + mac_control->zerodma_virt_addr); nic->mac_control.stats_info->sw_stat.mem_freed - += PAGE_SIZE; + += PAGE_SIZE; } kfree(fifo->list_info); nic->mac_control.stats_info->sw_stat.mem_freed += - (nic->config.tx_cfg[i].fifo_len *sizeof(struct list_info_hold)); + nic->config.tx_cfg[i].fifo_len * + sizeof(struct list_info_hold); } size = SIZE_OF_BLOCK; @@ -1018,7 +1021,7 @@ static void free_shared_mem(struct s2io_nic *nic) nic->mac_control.stats_info->sw_stat.mem_freed += size; kfree(ring->rx_blocks[j].rxds); nic->mac_control.stats_info->sw_stat.mem_freed += - ( sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]); + sizeof(struct rxd_info) * rxd_count[nic->rxd_mode]; } } @@ -1038,20 +1041,20 @@ static void free_shared_mem(struct s2io_nic *nic) struct buffAdd *ba = &ring->ba[j][k]; kfree(ba->ba_0_org); nic->mac_control.stats_info->sw_stat.\ - mem_freed += (BUF0_LEN + ALIGN_SIZE); + mem_freed += (BUF0_LEN + ALIGN_SIZE); kfree(ba->ba_1_org); nic->mac_control.stats_info->sw_stat.\ - mem_freed += (BUF1_LEN + ALIGN_SIZE); + mem_freed += (BUF1_LEN + ALIGN_SIZE); k++; } kfree(ring->ba[j]); nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd) * - (rxd_count[nic->rxd_mode] + 1)); + (rxd_count[nic->rxd_mode] + 1)); } kfree(ring->ba); nic->mac_control.stats_info->sw_stat.mem_freed += - (sizeof(struct buffAdd *) * blk_cnt); + (sizeof(struct buffAdd *) * blk_cnt); } } @@ -1089,7 +1092,7 @@ static int s2io_verify_pci_mode(struct s2io_nic *nic) val64 = readq(&bar0->pci_mode); mode = (u8)GET_PCI_MODE(val64); - if ( val64 & PCI_MODE_UNKNOWN_MODE) + if (val64 & PCI_MODE_UNKNOWN_MODE) return -1; /* Unknown PCI mode */ return mode; } @@ -1124,50 +1127,47 @@ static int s2io_print_pci_mode(struct s2io_nic *nic) val64 = readq(&bar0->pci_mode); mode = (u8)GET_PCI_MODE(val64); - if ( val64 & PCI_MODE_UNKNOWN_MODE) + if (val64 & PCI_MODE_UNKNOWN_MODE) return -1; /* Unknown PCI mode */ config->bus_speed = bus_speed[mode]; if (s2io_on_nec_bridge(nic->pdev)) { DBG_PRINT(ERR_DBG, "%s: Device is on PCI-E bus\n", - nic->dev->name); + nic->dev->name); return mode; } - if (val64 & PCI_MODE_32_BITS) { - DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name); - } else { - DBG_PRINT(ERR_DBG, "%s: Device is on 64 bit ", nic->dev->name); - } + DBG_PRINT(ERR_DBG, "%s: Device is on %d bit ", + nic->dev->name, val64 & PCI_MODE_32_BITS ? 32 : 64); - switch(mode) { - case PCI_MODE_PCI_33: - DBG_PRINT(ERR_DBG, "33MHz PCI bus\n"); - break; - case PCI_MODE_PCI_66: - DBG_PRINT(ERR_DBG, "66MHz PCI bus\n"); - break; - case PCI_MODE_PCIX_M1_66: - DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n"); - break; - case PCI_MODE_PCIX_M1_100: - DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n"); - break; - case PCI_MODE_PCIX_M1_133: - DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n"); - break; - case PCI_MODE_PCIX_M2_66: - DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n"); - break; - case PCI_MODE_PCIX_M2_100: - DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n"); - break; - case PCI_MODE_PCIX_M2_133: - DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n"); - break; - default: - return -1; /* Unsupported bus speed */ + switch (mode) { + case PCI_MODE_PCI_33: + DBG_PRINT(ERR_DBG, "33MHz PCI bus\n"); + break; + case PCI_MODE_PCI_66: + DBG_PRINT(ERR_DBG, "66MHz PCI bus\n"); + break; + case PCI_MODE_PCIX_M1_66: + DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n"); + break; + case PCI_MODE_PCIX_M1_100: + DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n"); + break; + case PCI_MODE_PCIX_M1_133: + DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n"); + break; + case PCI_MODE_PCIX_M2_66: + DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n"); + break; + case PCI_MODE_PCIX_M2_100: + DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n"); + break; + case PCI_MODE_PCIX_M2_133: + DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n"); + break; + default: + return -1; /* Unsupported bus speed */ } return mode; @@ -1205,9 +1205,9 @@ static int init_tti(struct s2io_nic *nic, int link) val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078); val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) | - TTI_DATA1_MEM_TX_URNG_B(0x10) | - TTI_DATA1_MEM_TX_URNG_C(0x30) | - TTI_DATA1_MEM_TX_TIMER_AC_EN; + TTI_DATA1_MEM_TX_URNG_B(0x10) | + TTI_DATA1_MEM_TX_URNG_C(0x30) | + TTI_DATA1_MEM_TX_TIMER_AC_EN; if (i == 0) if (use_continuous_tx_intrs && (link == LINK_UP)) val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN; @@ -1220,11 +1220,11 @@ static int init_tti(struct s2io_nic *nic, int link) TTI_DATA2_MEM_TX_UFC_D(0x300); } else { if ((nic->config.tx_steering_type == - TX_DEFAULT_STEERING) && - (config->tx_fifo_num > 1) && - (i >= nic->udp_fifo_idx) && - (i < (nic->udp_fifo_idx + - nic->total_udp_fifos))) + TX_DEFAULT_STEERING) && + (config->tx_fifo_num > 1) && + (i >= nic->udp_fifo_idx) && + (i < (nic->udp_fifo_idx + + nic->total_udp_fifos))) val64 = TTI_DATA2_MEM_TX_UFC_A(0x50) | TTI_DATA2_MEM_TX_UFC_B(0x80) | TTI_DATA2_MEM_TX_UFC_C(0x100) | @@ -1238,12 +1238,14 @@ static int init_tti(struct s2io_nic *nic, int link) writeq(val64, &bar0->tti_data2_mem); - val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD | - TTI_CMD_MEM_OFFSET(i); + val64 = TTI_CMD_MEM_WE | + TTI_CMD_MEM_STROBE_NEW_CMD | + TTI_CMD_MEM_OFFSET(i); writeq(val64, &bar0->tti_command_mem); if (wait_for_cmd_complete(&bar0->tti_command_mem, - TTI_CMD_MEM_STROBE_NEW_CMD, S2IO_BIT_RESET) != SUCCESS) + TTI_CMD_MEM_STROBE_NEW_CMD, + S2IO_BIT_RESET) != SUCCESS) return FAILURE; } @@ -1277,8 +1279,8 @@ static int init_nic(struct s2io_nic *nic) config = &nic->config; /* to set the swapper controle on the card */ - if(s2io_set_swapper(nic)) { - DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n"); + if (s2io_set_swapper(nic)) { + DBG_PRINT(ERR_DBG, "ERROR: Setting Swapper failed\n"); return -EIO; } @@ -1317,7 +1319,7 @@ static int init_nic(struct s2io_nic *nic) val64 = readq(&bar0->mac_cfg); val64 |= MAC_RMAC_BCAST_ENABLE; writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); - writel((u32) val64, add); + writel((u32)val64, add); writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); writel((u32) (val64 >> 32), (add + 4)); @@ -1354,7 +1356,6 @@ static int init_nic(struct s2io_nic *nic) writeq(val64, &bar0->tx_fifo_partition_2); writeq(val64, &bar0->tx_fifo_partition_3); - for (i = 0, j = 0; i < config->tx_fifo_num; i++) { struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; @@ -1397,21 +1398,22 @@ static int init_nic(struct s2io_nic *nic) * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug * SXE-008 TRANSMIT DMA ARBITRATION ISSUE. */ - if ((nic->device_type == XFRAME_I_DEVICE) && - (nic->pdev->revision < 4)) + if ((nic->device_type == XFRAME_I_DEVICE) && (nic->pdev->revision < 4)) writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable); val64 = readq(&bar0->tx_fifo_partition_0); DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n", - &bar0->tx_fifo_partition_0, (unsigned long long) val64); + &bar0->tx_fifo_partition_0, (unsigned long long)val64); /* * Initialization of Tx_PA_CONFIG register to ignore packet * integrity checking. */ val64 = readq(&bar0->tx_pa_cfg); - val64 |= TX_PA_CFG_IGNORE_FRM_ERR | TX_PA_CFG_IGNORE_SNAP_OUI | - TX_PA_CFG_IGNORE_LLC_CTRL | TX_PA_CFG_IGNORE_L2_ERR; + val64 |= TX_PA_CFG_IGNORE_FRM_ERR | + TX_PA_CFG_IGNORE_SNAP_OUI | + TX_PA_CFG_IGNORE_LLC_CTRL | + TX_PA_CFG_IGNORE_L2_ERR; writeq(val64, &bar0->tx_pa_cfg); /* Rx DMA intialization. */ @@ -1703,7 +1705,7 @@ static int init_nic(struct s2io_nic *nic) */ if (rts_frm_len[i] != 0) { writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]), - &bar0->rts_frm_len_n[i]); + &bar0->rts_frm_len_n[i]); } } @@ -1711,7 +1713,7 @@ static int init_nic(struct s2io_nic *nic) for (i = 0; i < 64; i++) { if (rts_ds_steer(nic, i, 0) == FAILURE) { DBG_PRINT(ERR_DBG, "%s: failed rts ds steering", - dev->name); + dev->name); DBG_PRINT(ERR_DBG, "set on codepoint %d\n", i); return -ENODEV; } @@ -1730,7 +1732,7 @@ static int init_nic(struct s2io_nic *nic) * bandwidth utilization. */ val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) | - MAC_RX_LINK_UTIL_VAL(rmac_util_period); + MAC_RX_LINK_UTIL_VAL(rmac_util_period); writeq(val64, &bar0->mac_link_util); /* @@ -1753,24 +1755,26 @@ static int init_nic(struct s2io_nic *nic) } else val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF); val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) | - RTI_DATA1_MEM_RX_URNG_B(0x10) | - RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN; + RTI_DATA1_MEM_RX_URNG_B(0x10) | + RTI_DATA1_MEM_RX_URNG_C(0x30) | + RTI_DATA1_MEM_RX_TIMER_AC_EN; writeq(val64, &bar0->rti_data1_mem); val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | RTI_DATA2_MEM_RX_UFC_B(0x2) ; if (nic->config.intr_type == MSI_X) - val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \ - RTI_DATA2_MEM_RX_UFC_D(0x40)); + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | + RTI_DATA2_MEM_RX_UFC_D(0x40)); else - val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \ - RTI_DATA2_MEM_RX_UFC_D(0x80)); + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | + RTI_DATA2_MEM_RX_UFC_D(0x80)); writeq(val64, &bar0->rti_data2_mem); for (i = 0; i < config->rx_ring_num; i++) { - val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD - | RTI_CMD_MEM_OFFSET(i); + val64 = RTI_CMD_MEM_WE | + RTI_CMD_MEM_STROBE_NEW_CMD | + RTI_CMD_MEM_OFFSET(i); writeq(val64, &bar0->rti_command_mem); /* @@ -1843,19 +1847,17 @@ static int init_nic(struct s2io_nic *nic) */ val64 = 0; for (i = 0; i < 4; i++) { - val64 |= - (((u64) 0xFF00 | nic->mac_control. - mc_pause_threshold_q0q3) - << (i * 2 * 8)); + val64 |= (((u64)0xFF00 | + nic->mac_control.mc_pause_threshold_q0q3) + << (i * 2 * 8)); } writeq(val64, &bar0->mc_pause_thresh_q0q3); val64 = 0; for (i = 0; i < 4; i++) { - val64 |= - (((u64) 0xFF00 | nic->mac_control. - mc_pause_threshold_q4q7) - << (i * 2 * 8)); + val64 |= (((u64)0xFF00 | + nic->mac_control.mc_pause_threshold_q4q7) + << (i * 2 * 8)); } writeq(val64, &bar0->mc_pause_thresh_q4q7); @@ -1918,10 +1920,10 @@ static void do_s2io_write_bits(u64 value, int flag, void __iomem *addr) temp64 = readq(addr); - if(flag == ENABLE_INTRS) - temp64 &= ~((u64) value); + if (flag == ENABLE_INTRS) + temp64 &= ~((u64)value); else - temp64 |= ((u64) value); + temp64 |= ((u64)value); writeq(temp64, addr); } @@ -1933,124 +1935,125 @@ static void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag) writeq(DISABLE_ALL_INTRS, &bar0->general_int_mask); if (mask & TX_DMA_INTR) { - gen_int_mask |= TXDMA_INT_M; do_s2io_write_bits(TXDMA_TDA_INT | TXDMA_PFC_INT | - TXDMA_PCC_INT | TXDMA_TTI_INT | - TXDMA_LSO_INT | TXDMA_TPA_INT | - TXDMA_SM_INT, flag, &bar0->txdma_int_mask); + TXDMA_PCC_INT | TXDMA_TTI_INT | + TXDMA_LSO_INT | TXDMA_TPA_INT | + TXDMA_SM_INT, flag, &bar0->txdma_int_mask); do_s2io_write_bits(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM | - PFC_MISC_0_ERR | PFC_MISC_1_ERR | - PFC_PCIX_ERR | PFC_ECC_SG_ERR, flag, - &bar0->pfc_err_mask); + PFC_MISC_0_ERR | PFC_MISC_1_ERR | + PFC_PCIX_ERR | PFC_ECC_SG_ERR, flag, + &bar0->pfc_err_mask); do_s2io_write_bits(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM | - TDA_SM1_ERR_ALARM | TDA_Fn_ECC_SG_ERR | - TDA_PCIX_ERR, flag, &bar0->tda_err_mask); + TDA_SM1_ERR_ALARM | TDA_Fn_ECC_SG_ERR | + TDA_PCIX_ERR, flag, &bar0->tda_err_mask); do_s2io_write_bits(PCC_FB_ECC_DB_ERR | PCC_TXB_ECC_DB_ERR | - PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM | - PCC_N_SERR | PCC_6_COF_OV_ERR | - PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR | - PCC_7_LSO_OV_ERR | PCC_FB_ECC_SG_ERR | - PCC_TXB_ECC_SG_ERR, flag, &bar0->pcc_err_mask); + PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM | + PCC_N_SERR | PCC_6_COF_OV_ERR | + PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR | + PCC_7_LSO_OV_ERR | PCC_FB_ECC_SG_ERR | + PCC_TXB_ECC_SG_ERR, + flag, &bar0->pcc_err_mask); do_s2io_write_bits(TTI_SM_ERR_ALARM | TTI_ECC_SG_ERR | - TTI_ECC_DB_ERR, flag, &bar0->tti_err_mask); + TTI_ECC_DB_ERR, flag, &bar0->tti_err_mask); do_s2io_write_bits(LSO6_ABORT | LSO7_ABORT | - LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM | - LSO6_SEND_OFLOW | LSO7_SEND_OFLOW, - flag, &bar0->lso_err_mask); + LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM | + LSO6_SEND_OFLOW | LSO7_SEND_OFLOW, + flag, &bar0->lso_err_mask); do_s2io_write_bits(TPA_SM_ERR_ALARM | TPA_TX_FRM_DROP, - flag, &bar0->tpa_err_mask); + flag, &bar0->tpa_err_mask); do_s2io_write_bits(SM_SM_ERR_ALARM, flag, &bar0->sm_err_mask); - } if (mask & TX_MAC_INTR) { gen_int_mask |= TXMAC_INT_M; do_s2io_write_bits(MAC_INT_STATUS_TMAC_INT, flag, - &bar0->mac_int_mask); + &bar0->mac_int_mask); do_s2io_write_bits(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR | - TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR | - TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR, - flag, &bar0->mac_tmac_err_mask); + TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR | + TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR, + flag, &bar0->mac_tmac_err_mask); } if (mask & TX_XGXS_INTR) { gen_int_mask |= TXXGXS_INT_M; do_s2io_write_bits(XGXS_INT_STATUS_TXGXS, flag, - &bar0->xgxs_int_mask); + &bar0->xgxs_int_mask); do_s2io_write_bits(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR | - TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR, - flag, &bar0->xgxs_txgxs_err_mask); + TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR, + flag, &bar0->xgxs_txgxs_err_mask); } if (mask & RX_DMA_INTR) { gen_int_mask |= RXDMA_INT_M; do_s2io_write_bits(RXDMA_INT_RC_INT_M | RXDMA_INT_RPA_INT_M | - RXDMA_INT_RDA_INT_M | RXDMA_INT_RTI_INT_M, - flag, &bar0->rxdma_int_mask); + RXDMA_INT_RDA_INT_M | RXDMA_INT_RTI_INT_M, + flag, &bar0->rxdma_int_mask); do_s2io_write_bits(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR | - RC_PRCn_SM_ERR_ALARM | RC_FTC_SM_ERR_ALARM | - RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR | - RC_RDA_FAIL_WR_Rn, flag, &bar0->rc_err_mask); + RC_PRCn_SM_ERR_ALARM | RC_FTC_SM_ERR_ALARM | + RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR | + RC_RDA_FAIL_WR_Rn, flag, &bar0->rc_err_mask); do_s2io_write_bits(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn | - PRC_PCI_AB_F_WR_Rn | PRC_PCI_DP_RD_Rn | - PRC_PCI_DP_WR_Rn | PRC_PCI_DP_F_WR_Rn, flag, - &bar0->prc_pcix_err_mask); + PRC_PCI_AB_F_WR_Rn | PRC_PCI_DP_RD_Rn | + PRC_PCI_DP_WR_Rn | PRC_PCI_DP_F_WR_Rn, flag, + &bar0->prc_pcix_err_mask); do_s2io_write_bits(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR | - RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, flag, - &bar0->rpa_err_mask); + RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, flag, + &bar0->rpa_err_mask); do_s2io_write_bits(RDA_RXDn_ECC_DB_ERR | RDA_FRM_ECC_DB_N_AERR | - RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM | - RDA_RXD_ECC_DB_SERR | RDA_RXDn_ECC_SG_ERR | - RDA_FRM_ECC_SG_ERR | RDA_MISC_ERR|RDA_PCIX_ERR, - flag, &bar0->rda_err_mask); + RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM | + RDA_RXD_ECC_DB_SERR | RDA_RXDn_ECC_SG_ERR | + RDA_FRM_ECC_SG_ERR | + RDA_MISC_ERR|RDA_PCIX_ERR, + flag, &bar0->rda_err_mask); do_s2io_write_bits(RTI_SM_ERR_ALARM | - RTI_ECC_SG_ERR | RTI_ECC_DB_ERR, - flag, &bar0->rti_err_mask); + RTI_ECC_SG_ERR | RTI_ECC_DB_ERR, + flag, &bar0->rti_err_mask); } if (mask & RX_MAC_INTR) { gen_int_mask |= RXMAC_INT_M; do_s2io_write_bits(MAC_INT_STATUS_RMAC_INT, flag, - &bar0->mac_int_mask); - interruptible = RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR | - RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR | - RMAC_DOUBLE_ECC_ERR; + &bar0->mac_int_mask); + interruptible = (RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR | + RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR | + RMAC_DOUBLE_ECC_ERR); if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) interruptible |= RMAC_LINK_STATE_CHANGE_INT; do_s2io_write_bits(interruptible, - flag, &bar0->mac_rmac_err_mask); + flag, &bar0->mac_rmac_err_mask); } - if (mask & RX_XGXS_INTR) - { + if (mask & RX_XGXS_INTR) { gen_int_mask |= RXXGXS_INT_M; do_s2io_write_bits(XGXS_INT_STATUS_RXGXS, flag, - &bar0->xgxs_int_mask); + &bar0->xgxs_int_mask); do_s2io_write_bits(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, flag, - &bar0->xgxs_rxgxs_err_mask); + &bar0->xgxs_rxgxs_err_mask); } if (mask & MC_INTR) { gen_int_mask |= MC_INT_M; - do_s2io_write_bits(MC_INT_MASK_MC_INT, flag, &bar0->mc_int_mask); + do_s2io_write_bits(MC_INT_MASK_MC_INT, + flag, &bar0->mc_int_mask); do_s2io_write_bits(MC_ERR_REG_SM_ERR | MC_ERR_REG_ECC_ALL_SNG | - MC_ERR_REG_ECC_ALL_DBL | PLL_LOCK_N, flag, - &bar0->mc_err_mask); + MC_ERR_REG_ECC_ALL_DBL | PLL_LOCK_N, flag, + &bar0->mc_err_mask); } nic->general_int_mask = gen_int_mask; /* Remove this line when alarm interrupts are enabled */ nic->general_int_mask = 0; } + /** * en_dis_able_nic_intrs - Enable or Disable the interrupts * @nic: device private variable, @@ -2082,11 +2085,11 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) * TODO */ if (s2io_link_fault_indication(nic) == - LINK_UP_DOWN_INTERRUPT ) { + LINK_UP_DOWN_INTERRUPT) { do_s2io_write_bits(PIC_INT_GPIO, flag, - &bar0->pic_int_mask); + &bar0->pic_int_mask); do_s2io_write_bits(GPIO_INT_MASK_LINK_UP, flag, - &bar0->gpio_int_mask); + &bar0->gpio_int_mask); } else writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); } else if (flag == DISABLE_INTRS) { @@ -2133,7 +2136,7 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); if (flag == ENABLE_INTRS) - temp64 &= ~((u64) intr_mask); + temp64 &= ~((u64)intr_mask); else temp64 = DISABLE_ALL_INTRS; writeq(temp64, &bar0->general_int_mask); @@ -2198,7 +2201,7 @@ static int verify_xena_quiescence(struct s2io_nic *sp) return 0; } if (!(val64 & ADAPTER_STATUS_RDMA_READY)) { - DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!"); + DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!"); return 0; } if (!(val64 & ADAPTER_STATUS_PFC_READY)) { @@ -2232,13 +2235,13 @@ static int verify_xena_quiescence(struct s2io_nic *sp) * not be asserted. */ if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) && - sp->device_type == XFRAME_II_DEVICE && mode != - PCI_MODE_PCI_33) { + sp->device_type == XFRAME_II_DEVICE && + mode != PCI_MODE_PCI_33) { DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!"); return 0; } if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + ADAPTER_STATUS_RC_PRC_QUIESCENT)) { DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!"); return 0; } @@ -2253,7 +2256,7 @@ static int verify_xena_quiescence(struct s2io_nic *sp) * */ -static void fix_mac_address(struct s2io_nic * sp) +static void fix_mac_address(struct s2io_nic *sp) { struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; @@ -2295,7 +2298,7 @@ static int start_nic(struct s2io_nic *nic) for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i]; - writeq((u64) ring->rx_blocks[0].block_dma_addr, + writeq((u64)ring->rx_blocks[0].block_dma_addr, &bar0->prc_rxd0_n[i]); val64 = readq(&bar0->prc_ctrl_n[i]); @@ -2349,7 +2352,7 @@ static int start_nic(struct s2io_nic *nic) if (!verify_xena_quiescence(nic)) { DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name); DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n", - (unsigned long long) val64); + (unsigned long long)val64); return FAILURE; } @@ -2389,8 +2392,8 @@ static int start_nic(struct s2io_nic *nic) /** * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb */ -static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \ - TxD *txdlp, int get_off) +static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, + struct TxD *txdlp, int get_off) { struct s2io_nic *nic = fifo_data->nic; struct sk_buff *skb; @@ -2399,22 +2402,18 @@ static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \ txds = txdlp; if (txds->Host_Control == (u64)(long)fifo_data->ufo_in_band_v) { - pci_unmap_single(nic->pdev, (dma_addr_t) - txds->Buffer_Pointer, sizeof(u64), - PCI_DMA_TODEVICE); + pci_unmap_single(nic->pdev, (dma_addr_t)txds->Buffer_Pointer, + sizeof(u64), PCI_DMA_TODEVICE); txds++; } - skb = (struct sk_buff *) ((unsigned long) - txds->Host_Control); + skb = (struct sk_buff *)((unsigned long)txds->Host_Control); if (!skb) { memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds)); return NULL; } - pci_unmap_single(nic->pdev, (dma_addr_t) - txds->Buffer_Pointer, - skb->len - skb->data_len, - PCI_DMA_TODEVICE); + pci_unmap_single(nic->pdev, (dma_addr_t)txds->Buffer_Pointer, + skb->len - skb->data_len, PCI_DMA_TODEVICE); frg_cnt = skb_shinfo(skb)->nr_frags; if (frg_cnt) { txds++; @@ -2422,13 +2421,13 @@ static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \ skb_frag_t *frag = &skb_shinfo(skb)->frags[j]; if (!txds->Buffer_Pointer) break; - pci_unmap_page(nic->pdev, (dma_addr_t) - txds->Buffer_Pointer, + pci_unmap_page(nic->pdev, + (dma_addr_t)txds->Buffer_Pointer, frag->size, PCI_DMA_TODEVICE); } } - memset(txdlp,0, (sizeof(struct TxD) * fifo_data->max_txds)); - return(skb); + memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds)); + return skb; } /** @@ -2437,7 +2436,7 @@ static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \ * Description: * Free all queued Tx buffers. * Return Value: void -*/ + */ static void free_tx_buffers(struct s2io_nic *nic) { @@ -2533,7 +2532,7 @@ static void stop_nic(struct s2io_nic *nic) * SUCCESS on success or an appropriate -ve value on failure. */ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, - int from_card_up) + int from_card_up) { struct sk_buff *skb; struct RxD_t *rxdp; @@ -2564,17 +2563,16 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, rxd_index += (block_no * ring->rxd_count); if ((block_no == block_no1) && - (off == ring->rx_curr_get_info.offset) && - (rxdp->Host_Control)) { - DBG_PRINT(INTR_DBG, "%s: Get and Put", - ring->dev->name); + (off == ring->rx_curr_get_info.offset) && + (rxdp->Host_Control)) { + DBG_PRINT(INTR_DBG, "%s: Get and Put", ring->dev->name); DBG_PRINT(INTR_DBG, " info equated\n"); goto end; } if (off && (off == ring->rxd_count)) { ring->rx_curr_put_info.block_index++; if (ring->rx_curr_put_info.block_index == - ring->block_count) + ring->block_count) ring->rx_curr_put_info.block_index = 0; block_no = ring->rx_curr_put_info.block_index; off = 0; @@ -2586,14 +2584,15 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, } if ((rxdp->Control_1 & RXD_OWN_XENA) && - ((ring->rxd_mode == RXD_MODE_3B) && - (rxdp->Control_2 & s2BIT(0)))) { + ((ring->rxd_mode == RXD_MODE_3B) && + (rxdp->Control_2 & s2BIT(0)))) { ring->rx_curr_put_info.offset = off; goto end; } /* calculate size of skb based on ring mode */ - size = ring->mtu + HEADER_ETHERNET_II_802_3_SIZE + - HEADER_802_2_SIZE + HEADER_SNAP_SIZE; + size = ring->mtu + + HEADER_ETHERNET_II_802_3_SIZE + + HEADER_802_2_SIZE + HEADER_SNAP_SIZE; if (ring->rxd_mode == RXD_MODE_1) size += NET_IP_ALIGN; else @@ -2601,7 +2600,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, /* allocate skb */ skb = dev_alloc_skb(size); - if(!skb) { + if (!skb) { DBG_PRINT(INFO_DBG, "%s: Out of ", ring->dev->name); DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n"); if (first_rxdp) { @@ -2616,19 +2615,20 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, if (ring->rxd_mode == RXD_MODE_1) { /* 1 buffer mode - normal operation mode */ - rxdp1 = (struct RxD1*)rxdp; + rxdp1 = (struct RxD1 *)rxdp; memset(rxdp, 0, sizeof(struct RxD1)); skb_reserve(skb, NET_IP_ALIGN); - rxdp1->Buffer0_ptr = pci_map_single - (ring->pdev, skb->data, size - NET_IP_ALIGN, - PCI_DMA_FROMDEVICE); + rxdp1->Buffer0_ptr = + pci_map_single(ring->pdev, skb->data, + size - NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(nic->pdev, - rxdp1->Buffer0_ptr)) + rxdp1->Buffer0_ptr)) goto pci_map_failed; rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN); - rxdp->Host_Control = (unsigned long) (skb); + rxdp->Host_Control = (unsigned long)skb; } else if (ring->rxd_mode == RXD_MODE_3B) { /* * 2 buffer mode - @@ -2636,7 +2636,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, * byte aligned receive buffers. */ - rxdp3 = (struct RxD3*)rxdp; + rxdp3 = (struct RxD3 *)rxdp; /* save buffer pointers to avoid frequent dma mapping */ Buffer0_ptr = rxdp3->Buffer0_ptr; Buffer1_ptr = rxdp3->Buffer1_ptr; @@ -2647,7 +2647,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, ba = &ring->ba[block_no][off]; skb_reserve(skb, BUF0_LEN); - tmp = (u64)(unsigned long) skb->data; + tmp = (u64)(unsigned long)skb->data; tmp += ALIGN_SIZE; tmp &= ~ALIGN_SIZE; skb->data = (void *) (unsigned long)tmp; @@ -2655,15 +2655,17 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, if (from_card_up) { rxdp3->Buffer0_ptr = - pci_map_single(ring->pdev, ba->ba_0, - BUF0_LEN, PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(nic->pdev, - rxdp3->Buffer0_ptr)) + pci_map_single(ring->pdev, ba->ba_0, + BUF0_LEN, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(nic->pdev, + rxdp3->Buffer0_ptr)) goto pci_map_failed; } else pci_dma_sync_single_for_device(ring->pdev, - (dma_addr_t) rxdp3->Buffer0_ptr, - BUF0_LEN, PCI_DMA_FROMDEVICE); + (dma_addr_t)rxdp3->Buffer0_ptr, + BUF0_LEN, + PCI_DMA_FROMDEVICE); rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN); if (ring->rxd_mode == RXD_MODE_3B) { @@ -2673,34 +2675,35 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, * Buffer2 will have L3/L4 header plus * L4 payload */ - rxdp3->Buffer2_ptr = pci_map_single - (ring->pdev, skb->data, ring->mtu + 4, - PCI_DMA_FROMDEVICE); + rxdp3->Buffer2_ptr = pci_map_single(ring->pdev, + skb->data, + ring->mtu + 4, + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(nic->pdev, - rxdp3->Buffer2_ptr)) + rxdp3->Buffer2_ptr)) goto pci_map_failed; if (from_card_up) { rxdp3->Buffer1_ptr = pci_map_single(ring->pdev, - ba->ba_1, BUF1_LEN, - PCI_DMA_FROMDEVICE); + ba->ba_1, + BUF1_LEN, + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(nic->pdev, - rxdp3->Buffer1_ptr)) { - pci_unmap_single - (ring->pdev, - (dma_addr_t)(unsigned long) - skb->data, - ring->mtu + 4, - PCI_DMA_FROMDEVICE); + rxdp3->Buffer1_ptr)) { + pci_unmap_single(ring->pdev, + (dma_addr_t)(unsigned long) + skb->data, + ring->mtu + 4, + PCI_DMA_FROMDEVICE); goto pci_map_failed; } } rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1); rxdp->Control_2 |= SET_BUFFER2_SIZE_3 - (ring->mtu + 4); + (ring->mtu + 4); } rxdp->Control_2 |= s2BIT(0); rxdp->Host_Control = (unsigned long) (skb); @@ -2724,7 +2727,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, alloc_tab++; } - end: +end: /* Transfer ownership of first descriptor to adapter just before * exiting. Before that, use memory barrier so that ownership * and other fields are seen by adapter correctly. @@ -2735,6 +2738,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, } return SUCCESS; + pci_map_failed: stats->pci_map_fail_cnt++; stats->mem_freed += skb->truesize; @@ -2756,38 +2760,34 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) mac_control = &sp->mac_control; for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) { rxdp = mac_control->rings[ring_no]. - rx_blocks[blk].rxds[j].virt_addr; - skb = (struct sk_buff *) - ((unsigned long) rxdp->Host_Control); - if (!skb) { + rx_blocks[blk].rxds[j].virt_addr; + skb = (struct sk_buff *)((unsigned long)rxdp->Host_Control); + if (!skb) continue; - } if (sp->rxd_mode == RXD_MODE_1) { - rxdp1 = (struct RxD1*)rxdp; - pci_unmap_single(sp->pdev, (dma_addr_t) - rxdp1->Buffer0_ptr, - dev->mtu + - HEADER_ETHERNET_II_802_3_SIZE - + HEADER_802_2_SIZE + - HEADER_SNAP_SIZE, - PCI_DMA_FROMDEVICE); + rxdp1 = (struct RxD1 *)rxdp; + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp1->Buffer0_ptr, + dev->mtu + + HEADER_ETHERNET_II_802_3_SIZE + + HEADER_802_2_SIZE + HEADER_SNAP_SIZE, + PCI_DMA_FROMDEVICE); memset(rxdp, 0, sizeof(struct RxD1)); - } else if(sp->rxd_mode == RXD_MODE_3B) { - rxdp3 = (struct RxD3*)rxdp; - ba = &mac_control->rings[ring_no]. - ba[blk][j]; - pci_unmap_single(sp->pdev, (dma_addr_t) - rxdp3->Buffer0_ptr, - BUF0_LEN, - PCI_DMA_FROMDEVICE); - pci_unmap_single(sp->pdev, (dma_addr_t) - rxdp3->Buffer1_ptr, - BUF1_LEN, - PCI_DMA_FROMDEVICE); - pci_unmap_single(sp->pdev, (dma_addr_t) - rxdp3->Buffer2_ptr, - dev->mtu + 4, - PCI_DMA_FROMDEVICE); + } else if (sp->rxd_mode == RXD_MODE_3B) { + rxdp3 = (struct RxD3 *)rxdp; + ba = &mac_control->rings[ring_no].ba[blk][j]; + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer0_ptr, + BUF0_LEN, + PCI_DMA_FROMDEVICE); + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer1_ptr, + BUF1_LEN, + PCI_DMA_FROMDEVICE); + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer2_ptr, + dev->mtu + 4, + PCI_DMA_FROMDEVICE); memset(rxdp, 0, sizeof(struct RxD3)); } sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; @@ -2819,7 +2819,7 @@ static void free_rx_buffers(struct s2io_nic *sp) struct ring_info *ring = &mac_control->rings[i]; for (blk = 0; blk < rx_ring_sz[i]; blk++) - free_rxd_blk(sp,i,blk); + free_rxd_blk(sp, i, blk); ring->rx_curr_put_info.block_index = 0; ring->rx_curr_get_info.block_index = 0; @@ -2886,6 +2886,7 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) } return pkts_processed; } + static int s2io_poll_inta(struct napi_struct *napi, int budget) { struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); @@ -2999,8 +3000,8 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) struct sk_buff *skb; int pkt_cnt = 0, napi_pkts = 0; int i; - struct RxD1* rxdp1; - struct RxD3* rxdp3; + struct RxD1 *rxdp1; + struct RxD3 *rxdp3; get_info = ring_data->rx_curr_get_info; get_block = get_info.block_index; @@ -3016,10 +3017,10 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) if ((get_block == put_block) && (get_info.offset + 1) == put_info.offset) { DBG_PRINT(INTR_DBG, "%s: Ring Full\n", - ring_data->dev->name); + ring_data->dev->name); break; } - skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control); + skb = (struct sk_buff *)((unsigned long)rxdp->Host_Control); if (skb == NULL) { DBG_PRINT(ERR_DBG, "%s: The skb is ", ring_data->dev->name); @@ -3027,30 +3028,31 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) return 0; } if (ring_data->rxd_mode == RXD_MODE_1) { - rxdp1 = (struct RxD1*)rxdp; + rxdp1 = (struct RxD1 *)rxdp; pci_unmap_single(ring_data->pdev, (dma_addr_t) - rxdp1->Buffer0_ptr, - ring_data->mtu + - HEADER_ETHERNET_II_802_3_SIZE + - HEADER_802_2_SIZE + - HEADER_SNAP_SIZE, - PCI_DMA_FROMDEVICE); + rxdp1->Buffer0_ptr, + ring_data->mtu + + HEADER_ETHERNET_II_802_3_SIZE + + HEADER_802_2_SIZE + + HEADER_SNAP_SIZE, + PCI_DMA_FROMDEVICE); } else if (ring_data->rxd_mode == RXD_MODE_3B) { - rxdp3 = (struct RxD3*)rxdp; - pci_dma_sync_single_for_cpu(ring_data->pdev, (dma_addr_t) - rxdp3->Buffer0_ptr, - BUF0_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single(ring_data->pdev, (dma_addr_t) - rxdp3->Buffer2_ptr, - ring_data->mtu + 4, - PCI_DMA_FROMDEVICE); + rxdp3 = (struct RxD3 *)rxdp; + pci_dma_sync_single_for_cpu(ring_data->pdev, + (dma_addr_t)rxdp3->Buffer0_ptr, + BUF0_LEN, + PCI_DMA_FROMDEVICE); + pci_unmap_single(ring_data->pdev, + (dma_addr_t)rxdp3->Buffer2_ptr, + ring_data->mtu + 4, + PCI_DMA_FROMDEVICE); } prefetch(skb->data); rx_osm_handler(ring_data, rxdp); get_info.offset++; ring_data->rx_curr_get_info.offset = get_info.offset; rxdp = ring_data->rx_blocks[get_block]. - rxds[get_info.offset].virt_addr; + rxds[get_info.offset].virt_addr; if (get_info.offset == rxd_count[ring_data->rxd_mode]) { get_info.offset = 0; ring_data->rx_curr_get_info.offset = get_info.offset; @@ -3073,7 +3075,7 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) } if (ring_data->lro) { /* Clear all LRO sessions before exiting */ - for (i=0; ilro0_n[i]; if (lro->in_use) { update_L3L4_header(ring_data->nic, lro); @@ -3082,7 +3084,7 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) } } } - return(napi_pkts); + return napi_pkts; } /** @@ -3108,12 +3110,12 @@ static void tx_intr_handler(struct fifo_info *fifo_data) u8 err_mask; if (!spin_trylock_irqsave(&fifo_data->tx_lock, flags)) - return; + return; get_info = fifo_data->tx_curr_get_info; memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info)); - txdlp = (struct TxD *) fifo_data->list_info[get_info.offset]. - list_virt_addr; + txdlp = (struct TxD *) + fifo_data->list_info[get_info.offset].list_virt_addr; while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) && (get_info.offset != put_info.offset) && (txdlp->Host_Control)) { @@ -3123,44 +3125,43 @@ static void tx_intr_handler(struct fifo_info *fifo_data) err = txdlp->Control_1 & TXD_T_CODE; if (err & 0x1) { nic->mac_control.stats_info->sw_stat. - parity_err_cnt++; + parity_err_cnt++; } /* update t_code statistics */ err_mask = err >> 48; - switch(err_mask) { - case 2: - nic->mac_control.stats_info->sw_stat. - tx_buf_abort_cnt++; + switch (err_mask) { + case 2: + nic->mac_control.stats_info->sw_stat. + tx_buf_abort_cnt++; break; - case 3: - nic->mac_control.stats_info->sw_stat. - tx_desc_abort_cnt++; + case 3: + nic->mac_control.stats_info->sw_stat. + tx_desc_abort_cnt++; break; - case 7: - nic->mac_control.stats_info->sw_stat. - tx_parity_err_cnt++; + case 7: + nic->mac_control.stats_info->sw_stat. + tx_parity_err_cnt++; break; - case 10: - nic->mac_control.stats_info->sw_stat. - tx_link_loss_cnt++; + case 10: + nic->mac_control.stats_info->sw_stat. + tx_link_loss_cnt++; break; - case 15: - nic->mac_control.stats_info->sw_stat. - tx_list_proc_err_cnt++; + case 15: + nic->mac_control.stats_info->sw_stat. + tx_list_proc_err_cnt++; break; - } + } } skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset); if (skb == NULL) { spin_unlock_irqrestore(&fifo_data->tx_lock, flags); - DBG_PRINT(ERR_DBG, "%s: Null skb ", - __func__); + DBG_PRINT(ERR_DBG, "%s: Null skb ", __func__); DBG_PRINT(ERR_DBG, "in Tx Free Intr\n"); return; } @@ -3174,10 +3175,9 @@ static void tx_intr_handler(struct fifo_info *fifo_data) get_info.offset++; if (get_info.offset == get_info.fifo_len + 1) get_info.offset = 0; - txdlp = (struct TxD *) fifo_data->list_info - [get_info.offset].list_virt_addr; - fifo_data->tx_curr_get_info.offset = - get_info.offset; + txdlp = (struct TxD *) + fifo_data->list_info[get_info.offset].list_virt_addr; + fifo_data->tx_curr_get_info.offset = get_info.offset; } s2io_wake_tx_queue(fifo_data, pkt_cnt, nic->config.multiq); @@ -3195,43 +3195,41 @@ static void tx_intr_handler(struct fifo_info *fifo_data) * This function is used to write values to the MDIO registers * NONE */ -static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev) +static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, + struct net_device *dev) { - u64 val64 = 0x0; + u64 val64; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; - //address transaction - val64 = val64 | MDIO_MMD_INDX_ADDR(addr) - | MDIO_MMD_DEV_ADDR(mmd_type) - | MDIO_MMS_PRT_ADDR(0x0); + /* address transaction */ + val64 = MDIO_MMD_INDX_ADDR(addr) | + MDIO_MMD_DEV_ADDR(mmd_type) | + MDIO_MMS_PRT_ADDR(0x0); writeq(val64, &bar0->mdio_control); val64 = val64 | MDIO_CTRL_START_TRANS(0xE); writeq(val64, &bar0->mdio_control); udelay(100); - //Data transaction - val64 = 0x0; - val64 = val64 | MDIO_MMD_INDX_ADDR(addr) - | MDIO_MMD_DEV_ADDR(mmd_type) - | MDIO_MMS_PRT_ADDR(0x0) - | MDIO_MDIO_DATA(value) - | MDIO_OP(MDIO_OP_WRITE_TRANS); + /* Data transaction */ + val64 = MDIO_MMD_INDX_ADDR(addr) | + MDIO_MMD_DEV_ADDR(mmd_type) | + MDIO_MMS_PRT_ADDR(0x0) | + MDIO_MDIO_DATA(value) | + MDIO_OP(MDIO_OP_WRITE_TRANS); writeq(val64, &bar0->mdio_control); val64 = val64 | MDIO_CTRL_START_TRANS(0xE); writeq(val64, &bar0->mdio_control); udelay(100); - val64 = 0x0; - val64 = val64 | MDIO_MMD_INDX_ADDR(addr) - | MDIO_MMD_DEV_ADDR(mmd_type) - | MDIO_MMS_PRT_ADDR(0x0) - | MDIO_OP(MDIO_OP_READ_TRANS); + val64 = MDIO_MMD_INDX_ADDR(addr) | + MDIO_MMD_DEV_ADDR(mmd_type) | + MDIO_MMS_PRT_ADDR(0x0) | + MDIO_OP(MDIO_OP_READ_TRANS); writeq(val64, &bar0->mdio_control); val64 = val64 | MDIO_CTRL_START_TRANS(0xE); writeq(val64, &bar0->mdio_control); udelay(100); - } /** @@ -3251,20 +3249,19 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev) struct XENA_dev_config __iomem *bar0 = sp->bar0; /* address transaction */ - val64 = val64 | MDIO_MMD_INDX_ADDR(addr) - | MDIO_MMD_DEV_ADDR(mmd_type) - | MDIO_MMS_PRT_ADDR(0x0); + val64 = val64 | (MDIO_MMD_INDX_ADDR(addr) + | MDIO_MMD_DEV_ADDR(mmd_type) + | MDIO_MMS_PRT_ADDR(0x0)); writeq(val64, &bar0->mdio_control); val64 = val64 | MDIO_CTRL_START_TRANS(0xE); writeq(val64, &bar0->mdio_control); udelay(100); /* Data transaction */ - val64 = 0x0; - val64 = val64 | MDIO_MMD_INDX_ADDR(addr) - | MDIO_MMD_DEV_ADDR(mmd_type) - | MDIO_MMS_PRT_ADDR(0x0) - | MDIO_OP(MDIO_OP_READ_TRANS); + val64 = MDIO_MMD_INDX_ADDR(addr) | + MDIO_MMD_DEV_ADDR(mmd_type) | + MDIO_MMS_PRT_ADDR(0x0) | + MDIO_OP(MDIO_OP_READ_TRANS); writeq(val64, &bar0->mdio_control); val64 = val64 | MDIO_CTRL_START_TRANS(0xE); writeq(val64, &bar0->mdio_control); @@ -3276,6 +3273,7 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev) rval64 = rval64 >> 16; return rval64; } + /** * s2io_chk_xpak_counter - Function to check the status of the xpak counters * @counter : couter value to be updated @@ -3286,45 +3284,43 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev) * NONE */ -static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, u16 flag, u16 type) +static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, + u16 flag, u16 type) { u64 mask = 0x3; u64 val64; int i; - for(i = 0; i 0) - { + if (flag > 0) { *counter = *counter + 1; val64 = *regs_stat & mask; val64 = val64 >> (index * 0x2); val64 = val64 + 1; - if(val64 == 3) - { - switch(type) - { + if (val64 == 3) { + switch (type) { case 1: DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " "service. Excessive temperatures may " "result in premature transceiver " "failure \n"); - break; + break; case 2: DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " "service Excessive bias currents may " "indicate imminent laser diode " "failure \n"); - break; + break; case 3: DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " "service Excessive laser output " "power may saturate far-end " "receiver\n"); - break; + break; default: - DBG_PRINT(ERR_DBG, "Incorrect XPAK Alarm " - "type \n"); + DBG_PRINT(ERR_DBG, + "Incorrect XPAK Alarm type\n"); } val64 = 0x0; } @@ -3358,16 +3354,14 @@ static void s2io_updt_xpak_counter(struct net_device *dev) addr = MDIO_CTRL1; val64 = 0x0; val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); - if((val64 == 0xFFFF) || (val64 == 0x0000)) - { + if ((val64 == 0xFFFF) || (val64 == 0x0000)) { DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - " "Returned %llx\n", (unsigned long long)val64); return; } /* Check for the expected value of control reg 1 */ - if(val64 != MDIO_CTRL1_SPEED10G) - { + if (val64 != MDIO_CTRL1_SPEED10G) { DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - "); DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x%x\n", (unsigned long long)val64, MDIO_CTRL1_SPEED10G); @@ -3387,28 +3381,28 @@ static void s2io_updt_xpak_counter(struct net_device *dev) flag = CHECKBIT(val64, 0x7); type = 1; s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high, - &stat_info->xpak_stat.xpak_regs_stat, - 0x0, flag, type); + &stat_info->xpak_stat.xpak_regs_stat, + 0x0, flag, type); - if(CHECKBIT(val64, 0x6)) + if (CHECKBIT(val64, 0x6)) stat_info->xpak_stat.alarm_transceiver_temp_low++; flag = CHECKBIT(val64, 0x3); type = 2; s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high, - &stat_info->xpak_stat.xpak_regs_stat, - 0x2, flag, type); + &stat_info->xpak_stat.xpak_regs_stat, + 0x2, flag, type); - if(CHECKBIT(val64, 0x2)) + if (CHECKBIT(val64, 0x2)) stat_info->xpak_stat.alarm_laser_bias_current_low++; flag = CHECKBIT(val64, 0x1); type = 3; s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high, - &stat_info->xpak_stat.xpak_regs_stat, - 0x4, flag, type); + &stat_info->xpak_stat.xpak_regs_stat, + 0x4, flag, type); - if(CHECKBIT(val64, 0x0)) + if (CHECKBIT(val64, 0x0)) stat_info->xpak_stat.alarm_laser_output_power_low++; /* Reading the Warning flags */ @@ -3416,22 +3410,22 @@ static void s2io_updt_xpak_counter(struct net_device *dev) val64 = 0x0; val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); - if(CHECKBIT(val64, 0x7)) + if (CHECKBIT(val64, 0x7)) stat_info->xpak_stat.warn_transceiver_temp_high++; - if(CHECKBIT(val64, 0x6)) + if (CHECKBIT(val64, 0x6)) stat_info->xpak_stat.warn_transceiver_temp_low++; - if(CHECKBIT(val64, 0x3)) + if (CHECKBIT(val64, 0x3)) stat_info->xpak_stat.warn_laser_bias_current_high++; - if(CHECKBIT(val64, 0x2)) + if (CHECKBIT(val64, 0x2)) stat_info->xpak_stat.warn_laser_bias_current_low++; - if(CHECKBIT(val64, 0x1)) + if (CHECKBIT(val64, 0x1)) stat_info->xpak_stat.warn_laser_output_power_high++; - if(CHECKBIT(val64, 0x0)) + if (CHECKBIT(val64, 0x0)) stat_info->xpak_stat.warn_laser_output_power_low++; } @@ -3447,7 +3441,7 @@ static void s2io_updt_xpak_counter(struct net_device *dev) */ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit, - int bit_state) + int bit_state) { int ret = FAILURE, cnt = 0, delay = 1; u64 val64; @@ -3469,7 +3463,7 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit, } } - if(in_interrupt()) + if (in_interrupt()) mdelay(delay); else msleep(delay); @@ -3509,7 +3503,7 @@ static u16 check_pci_device_id(u16 id) * void. */ -static void s2io_reset(struct s2io_nic * sp) +static void s2io_reset(struct s2io_nic *sp) { struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; @@ -3519,17 +3513,16 @@ static void s2io_reset(struct s2io_nic * sp) unsigned long long up_cnt, down_cnt, up_time, down_time, reset_cnt; unsigned long long mem_alloc_cnt, mem_free_cnt, watchdog_cnt; - DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n", - __func__, sp->dev->name); + DBG_PRINT(INIT_DBG, "%s - Resetting XFrame card %s\n", + __func__, sp->dev->name); /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */ pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd)); val64 = SW_RESET_ALL; writeq(val64, &bar0->sw_reset); - if (strstr(sp->product_name, "CX4")) { + if (strstr(sp->product_name, "CX4")) msleep(750); - } msleep(250); for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) { @@ -3541,9 +3534,8 @@ static void s2io_reset(struct s2io_nic * sp) msleep(200); } - if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) { - DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __func__); - } + if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) + DBG_PRINT(ERR_DBG, "%s SW_Reset failed!\n", __func__); pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd); @@ -3571,7 +3563,7 @@ static void s2io_reset(struct s2io_nic * sp) } /* Reset device statistics maintained by OS */ - memset(&sp->stats, 0, sizeof (struct net_device_stats)); + memset(&sp->stats, 0, sizeof(struct net_device_stats)); up_cnt = sp->mac_control.stats_info->sw_stat.link_up_cnt; down_cnt = sp->mac_control.stats_info->sw_stat.link_down_cnt; @@ -3626,7 +3618,7 @@ static void s2io_reset(struct s2io_nic * sp) * SUCCESS on success and FAILURE on failure. */ -static int s2io_set_swapper(struct s2io_nic * sp) +static int s2io_set_swapper(struct s2io_nic *sp) { struct net_device *dev = sp->dev; struct XENA_dev_config __iomem *bar0 = sp->bar0; @@ -3645,7 +3637,7 @@ static int s2io_set_swapper(struct s2io_nic * sp) 0x4200004242000042ULL, /* FE=0, SE=1 */ 0}; /* FE=0, SE=0 */ - while(i<4) { + while (i < 4) { writeq(value[i], &bar0->swapper_ctrl); val64 = readq(&bar0->pif_rd_swapper_fb); if (val64 == 0x0123456789ABCDEFULL) @@ -3654,9 +3646,9 @@ static int s2io_set_swapper(struct s2io_nic * sp) } if (i == 4) { DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ", - dev->name); + dev->name); DBG_PRINT(ERR_DBG, "feedback read %llx\n", - (unsigned long long) val64); + (unsigned long long)val64); return FAILURE; } valr = value[i]; @@ -3668,22 +3660,22 @@ static int s2io_set_swapper(struct s2io_nic * sp) writeq(valt, &bar0->xmsi_address); val64 = readq(&bar0->xmsi_address); - if(val64 != valt) { + if (val64 != valt) { int i = 0; u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */ 0x0081810000818100ULL, /* FE=1, SE=0 */ 0x0042420000424200ULL, /* FE=0, SE=1 */ 0}; /* FE=0, SE=0 */ - while(i<4) { + while (i < 4) { writeq((value[i] | valr), &bar0->swapper_ctrl); writeq(valt, &bar0->xmsi_address); val64 = readq(&bar0->xmsi_address); - if(val64 == valt) + if (val64 == valt) break; i++; } - if(i == 4) { + if (i == 4) { unsigned long long x = val64; DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr "); DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x); @@ -3693,21 +3685,22 @@ static int s2io_set_swapper(struct s2io_nic * sp) val64 = readq(&bar0->swapper_ctrl); val64 &= 0xFFFF000000000000ULL; -#ifdef __BIG_ENDIAN +#ifdef __BIG_ENDIAN /* * The device by default set to a big endian format, so a * big endian driver need not set anything. */ val64 |= (SWAPPER_CTRL_TXP_FE | - SWAPPER_CTRL_TXP_SE | - SWAPPER_CTRL_TXD_R_FE | - SWAPPER_CTRL_TXD_W_FE | - SWAPPER_CTRL_TXF_R_FE | - SWAPPER_CTRL_RXD_R_FE | - SWAPPER_CTRL_RXD_W_FE | - SWAPPER_CTRL_RXF_W_FE | - SWAPPER_CTRL_XMSI_FE | - SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); + SWAPPER_CTRL_TXP_SE | + SWAPPER_CTRL_TXD_R_FE | + SWAPPER_CTRL_TXD_W_FE | + SWAPPER_CTRL_TXF_R_FE | + SWAPPER_CTRL_RXD_R_FE | + SWAPPER_CTRL_RXD_W_FE | + SWAPPER_CTRL_RXF_W_FE | + SWAPPER_CTRL_XMSI_FE | + SWAPPER_CTRL_STATS_FE | + SWAPPER_CTRL_STATS_SE); if (sp->config.intr_type == INTA) val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); @@ -3718,19 +3711,20 @@ static int s2io_set_swapper(struct s2io_nic * sp) * we want to set. */ val64 |= (SWAPPER_CTRL_TXP_FE | - SWAPPER_CTRL_TXP_SE | - SWAPPER_CTRL_TXD_R_FE | - SWAPPER_CTRL_TXD_R_SE | - SWAPPER_CTRL_TXD_W_FE | - SWAPPER_CTRL_TXD_W_SE | - SWAPPER_CTRL_TXF_R_FE | - SWAPPER_CTRL_RXD_R_FE | - SWAPPER_CTRL_RXD_R_SE | - SWAPPER_CTRL_RXD_W_FE | - SWAPPER_CTRL_RXD_W_SE | - SWAPPER_CTRL_RXF_W_FE | - SWAPPER_CTRL_XMSI_FE | - SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); + SWAPPER_CTRL_TXP_SE | + SWAPPER_CTRL_TXD_R_FE | + SWAPPER_CTRL_TXD_R_SE | + SWAPPER_CTRL_TXD_W_FE | + SWAPPER_CTRL_TXD_W_SE | + SWAPPER_CTRL_TXF_R_FE | + SWAPPER_CTRL_RXD_R_FE | + SWAPPER_CTRL_RXD_R_SE | + SWAPPER_CTRL_RXD_W_FE | + SWAPPER_CTRL_RXD_W_SE | + SWAPPER_CTRL_RXF_W_FE | + SWAPPER_CTRL_XMSI_FE | + SWAPPER_CTRL_STATS_FE | + SWAPPER_CTRL_STATS_SE); if (sp->config.intr_type == INTA) val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); @@ -3747,7 +3741,7 @@ static int s2io_set_swapper(struct s2io_nic * sp) DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ", dev->name); DBG_PRINT(ERR_DBG, "feedback read %llx\n", - (unsigned long long) val64); + (unsigned long long)val64); return FAILURE; } @@ -3766,7 +3760,7 @@ static int wait_for_msix_trans(struct s2io_nic *nic, int i) break; mdelay(1); cnt++; - } while(cnt < 5); + } while (cnt < 5); if (cnt == 5) { DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i); ret = 1; @@ -3781,12 +3775,11 @@ static void restore_xmsi_data(struct s2io_nic *nic) u64 val64; int i, msix_index; - if (nic->device_type == XFRAME_I_DEVICE) return; - for (i=0; i < MAX_REQUESTED_MSI_X; i++) { - msix_index = (i) ? ((i-1) * 8 + 1): 0; + for (i = 0; i < MAX_REQUESTED_MSI_X; i++) { + msix_index = (i) ? ((i-1) * 8 + 1) : 0; writeq(nic->msix_info[i].addr, &bar0->xmsi_address); writeq(nic->msix_info[i].data, &bar0->xmsi_data); val64 = (s2BIT(7) | s2BIT(15) | vBIT(msix_index, 26, 6)); @@ -3808,8 +3801,8 @@ static void store_xmsi_data(struct s2io_nic *nic) return; /* Store and display */ - for (i=0; i < MAX_REQUESTED_MSI_X; i++) { - msix_index = (i) ? ((i-1) * 8 + 1): 0; + for (i = 0; i < MAX_REQUESTED_MSI_X; i++) { + msix_index = (i) ? ((i-1) * 8 + 1) : 0; val64 = (s2BIT(15) | vBIT(msix_index, 26, 6)); writeq(val64, &bar0->xmsi_access); if (wait_for_msix_trans(nic, msix_index)) { @@ -3836,8 +3829,8 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) size = nic->num_entries * sizeof(struct msix_entry); nic->entries = kzalloc(size, GFP_KERNEL); if (!nic->entries) { - DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \ - __func__); + DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", + __func__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; return -ENOMEM; } @@ -3847,7 +3840,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) nic->s2io_entries = kzalloc(size, GFP_KERNEL); if (!nic->s2io_entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", - __func__); + __func__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; kfree(nic->entries); nic->mac_control.stats_info->sw_stat.mem_freed @@ -3926,14 +3919,14 @@ static int s2io_test_msi(struct s2io_nic *sp) u64 val64, saved64; err = request_irq(sp->entries[1].vector, s2io_test_intr, 0, - sp->name, sp); + sp->name, sp); if (err) { DBG_PRINT(ERR_DBG, "%s: PCI %s: cannot assign irq %d\n", - sp->dev->name, pci_name(pdev), pdev->irq); + sp->dev->name, pci_name(pdev), pdev->irq); return err; } - init_waitqueue_head (&sp->msi_wait); + init_waitqueue_head(&sp->msi_wait); sp->msi_detected = 0; saved64 = val64 = readq(&bar0->scheduled_int_ctrl); @@ -3947,8 +3940,8 @@ static int s2io_test_msi(struct s2io_nic *sp) if (!sp->msi_detected) { /* MSI(X) test failed, go back to INTx mode */ DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated " - "using MSI(X) during test\n", sp->dev->name, - pci_name(pdev)); + "using MSI(X) during test\n", sp->dev->name, + pci_name(pdev)); err = -EOPNOTSUPP; } @@ -3966,8 +3959,7 @@ static void remove_msix_isr(struct s2io_nic *sp) u16 msi_control; for (i = 0; i < sp->num_entries; i++) { - if (sp->s2io_entries[i].in_use == - MSIX_REGISTERED_SUCCESS) { + if (sp->s2io_entries[i].in_use == MSIX_REGISTERED_SUCCESS) { int vector = sp->entries[i].vector; void *arg = sp->s2io_entries[i].arg; free_irq(vector, arg); @@ -4043,12 +4035,12 @@ hw_init_failed: if (sp->entries) { kfree(sp->entries); sp->mac_control.stats_info->sw_stat.mem_freed - += (sp->num_entries * sizeof(struct msix_entry)); + += (sp->num_entries * sizeof(struct msix_entry)); } if (sp->s2io_entries) { kfree(sp->s2io_entries); sp->mac_control.stats_info->sw_stat.mem_freed - += (sp->num_entries * sizeof(struct s2io_msix_entry)); + += (sp->num_entries * sizeof(struct s2io_msix_entry)); } } return err; @@ -4075,8 +4067,8 @@ static int s2io_close(struct net_device *dev) int offset; /* Return if the device is already closed * - * Can happen when s2io_card_up failed in change_mtu * - */ + * Can happen when s2io_card_up failed in change_mtu * + */ if (!is_s2io_card_up(sp)) return 0; @@ -4152,20 +4144,20 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) if ((ip->frag_off & htons(IP_OFFSET|IP_MF)) == 0) { th = (struct tcphdr *)(((unsigned char *)ip) + - ip->ihl*4); + ip->ihl*4); if (ip->protocol == IPPROTO_TCP) { queue_len = sp->total_tcp_fifos; queue = (ntohs(th->source) + - ntohs(th->dest)) & - sp->fifo_selector[queue_len - 1]; + ntohs(th->dest)) & + sp->fifo_selector[queue_len - 1]; if (queue >= queue_len) queue = queue_len - 1; } else if (ip->protocol == IPPROTO_UDP) { queue_len = sp->total_udp_fifos; queue = (ntohs(th->source) + - ntohs(th->dest)) & - sp->fifo_selector[queue_len - 1]; + ntohs(th->dest)) & + sp->fifo_selector[queue_len - 1]; if (queue >= queue_len) queue = queue_len - 1; queue += sp->udp_fifo_idx; @@ -4178,7 +4170,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) } else if (sp->config.tx_steering_type == TX_PRIORITY_STEERING) /* get fifo number based on skb->priority value */ queue = config->fifo_mapping - [skb->priority & (MAX_TX_FIFOS - 1)]; + [skb->priority & (MAX_TX_FIFOS - 1)]; fifo = &mac_control->fifos[queue]; if (do_spin_lock) @@ -4200,14 +4192,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) } } - put_off = (u16) fifo->tx_curr_put_info.offset; - get_off = (u16) fifo->tx_curr_get_info.offset; - txdp = (struct TxD *) fifo->list_info[put_off].list_virt_addr; + put_off = (u16)fifo->tx_curr_put_info.offset; + get_off = (u16)fifo->tx_curr_get_info.offset; + txdp = (struct TxD *)fifo->list_info[put_off].list_virt_addr; queue_len = fifo->tx_curr_put_info.fifo_len + 1; /* Avoid "put" pointer going beyond "get" pointer */ if (txdp->Host_Control || - ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) { + ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) { DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n"); s2io_stop_tx_queue(sp, fifo->fifo_no); dev_kfree_skb(skb); @@ -4221,9 +4213,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb)); } if (skb->ip_summed == CHECKSUM_PARTIAL) { - txdp->Control_2 |= - (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN | - TXD_TX_CKO_UDP_EN); + txdp->Control_2 |= (TXD_TX_CKO_IPV4_EN | + TXD_TX_CKO_TCP_EN | + TXD_TX_CKO_UDP_EN); } txdp->Control_1 |= TXD_GATHER_CODE_FIRST; txdp->Control_1 |= TXD_LIST_OWN_XENA; @@ -4248,26 +4240,27 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef __BIG_ENDIAN /* both variants do cpu_to_be64(be32_to_cpu(...)) */ fifo->ufo_in_band_v[put_off] = - (__force u64)skb_shinfo(skb)->ip6_frag_id; + (__force u64)skb_shinfo(skb)->ip6_frag_id; #else fifo->ufo_in_band_v[put_off] = - (__force u64)skb_shinfo(skb)->ip6_frag_id << 32; + (__force u64)skb_shinfo(skb)->ip6_frag_id << 32; #endif txdp->Host_Control = (unsigned long)fifo->ufo_in_band_v; txdp->Buffer_Pointer = pci_map_single(sp->pdev, - fifo->ufo_in_band_v, - sizeof(u64), PCI_DMA_TODEVICE); + fifo->ufo_in_band_v, + sizeof(u64), + PCI_DMA_TODEVICE); if (pci_dma_mapping_error(sp->pdev, txdp->Buffer_Pointer)) goto pci_map_failed; txdp++; } - txdp->Buffer_Pointer = pci_map_single - (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE); + txdp->Buffer_Pointer = pci_map_single(sp->pdev, skb->data, + frg_len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(sp->pdev, txdp->Buffer_Pointer)) goto pci_map_failed; - txdp->Host_Control = (unsigned long) skb; + txdp->Host_Control = (unsigned long)skb; txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len); if (offload_type == SKB_GSO_UDP) txdp->Control_1 |= TXD_UFO_EN; @@ -4280,9 +4273,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) if (!frag->size) continue; txdp++; - txdp->Buffer_Pointer = (u64) pci_map_page - (sp->pdev, frag->page, frag->page_offset, - frag->size, PCI_DMA_TODEVICE); + txdp->Buffer_Pointer = (u64)pci_map_page(sp->pdev, frag->page, + frag->page_offset, + frag->size, + PCI_DMA_TODEVICE); txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size); if (offload_type == SKB_GSO_UDP) txdp->Control_1 |= TXD_UFO_EN; @@ -4422,17 +4416,16 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) * This is unstable state so clear both up/down * interrupt and adapter to re-evaluate the link state. */ - val64 |= GPIO_INT_REG_LINK_DOWN; + val64 |= GPIO_INT_REG_LINK_DOWN; val64 |= GPIO_INT_REG_LINK_UP; writeq(val64, &bar0->gpio_int_reg); val64 = readq(&bar0->gpio_int_mask); val64 &= ~(GPIO_INT_MASK_LINK_UP | GPIO_INT_MASK_LINK_DOWN); writeq(val64, &bar0->gpio_int_mask); - } - else if (val64 & GPIO_INT_REG_LINK_UP) { + } else if (val64 & GPIO_INT_REG_LINK_UP) { val64 = readq(&bar0->adapter_status); - /* Enable Adapter */ + /* Enable Adapter */ val64 = readq(&bar0->adapter_control); val64 |= ADAPTER_CNTL_EN; writeq(val64, &bar0->adapter_control); @@ -4451,7 +4444,7 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) val64 |= GPIO_INT_MASK_LINK_UP; writeq(val64, &bar0->gpio_int_mask); - }else if (val64 & GPIO_INT_REG_LINK_DOWN) { + } else if (val64 & GPIO_INT_REG_LINK_DOWN) { val64 = readq(&bar0->adapter_status); s2io_link(sp, LINK_DOWN); /* Link is down so unmaks link up interrupt */ @@ -4462,7 +4455,7 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) /* turn off LED */ val64 = readq(&bar0->adapter_control); - val64 = val64 &(~ADAPTER_LED_ON); + val64 = val64 & (~ADAPTER_LED_ON); writeq(val64, &bar0->adapter_control); } } @@ -4479,12 +4472,12 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) * 1 - if alarm bit set * 0 - if alarm bit is not set */ -static int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, - unsigned long long *cnt) +static int do_s2io_chk_alarm_bit(u64 value, void __iomem *addr, + unsigned long long *cnt) { u64 val64; val64 = readq(addr); - if ( val64 & value ) { + if (val64 & value) { writeq(val64, addr); (*cnt)++; return 1; @@ -4501,12 +4494,12 @@ static int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, * Return Value: * NONE */ -static void s2io_handle_errors(void * dev_id) +static void s2io_handle_errors(void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = (struct net_device *)dev_id; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; - u64 temp64 = 0,val64=0; + u64 temp64 = 0, val64 = 0; int i = 0; struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat; @@ -4519,10 +4512,10 @@ static void s2io_handle_errors(void * dev_id) return; memset(&sw_stat->ring_full_cnt, 0, - sizeof(sw_stat->ring_full_cnt)); + sizeof(sw_stat->ring_full_cnt)); /* Handling the XPAK counters update */ - if(stats->xpak_timer_count < 72000) { + if (stats->xpak_timer_count < 72000) { /* waiting for an hour */ stats->xpak_timer_count++; } else { @@ -4541,191 +4534,227 @@ static void s2io_handle_errors(void * dev_id) /* In case of a serious error, the device will be Reset. */ if (do_s2io_chk_alarm_bit(SERR_SOURCE_ANY, &bar0->serr_source, - &sw_stat->serious_err_cnt)) + &sw_stat->serious_err_cnt)) goto reset; /* Check for data parity error */ if (do_s2io_chk_alarm_bit(GPIO_INT_REG_DP_ERR_INT, &bar0->gpio_int_reg, - &sw_stat->parity_err_cnt)) + &sw_stat->parity_err_cnt)) goto reset; /* Check for ring full counter */ if (sp->device_type == XFRAME_II_DEVICE) { val64 = readq(&bar0->ring_bump_counter1); - for (i=0; i<4; i++) { - temp64 = ( val64 & vBIT(0xFFFF,(i*16),16)); + for (i = 0; i < 4; i++) { + temp64 = (val64 & vBIT(0xFFFF, (i*16), 16)); temp64 >>= 64 - ((i+1)*16); sw_stat->ring_full_cnt[i] += temp64; } val64 = readq(&bar0->ring_bump_counter2); - for (i=0; i<4; i++) { - temp64 = ( val64 & vBIT(0xFFFF,(i*16),16)); + for (i = 0; i < 4; i++) { + temp64 = (val64 & vBIT(0xFFFF, (i*16), 16)); temp64 >>= 64 - ((i+1)*16); - sw_stat->ring_full_cnt[i+4] += temp64; + sw_stat->ring_full_cnt[i+4] += temp64; } } val64 = readq(&bar0->txdma_int_status); /*check for pfc_err*/ if (val64 & TXDMA_PFC_INT) { - if (do_s2io_chk_alarm_bit(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM| - PFC_MISC_0_ERR | PFC_MISC_1_ERR| - PFC_PCIX_ERR, &bar0->pfc_err_reg, - &sw_stat->pfc_err_cnt)) + if (do_s2io_chk_alarm_bit(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM | + PFC_MISC_0_ERR | PFC_MISC_1_ERR | + PFC_PCIX_ERR, + &bar0->pfc_err_reg, + &sw_stat->pfc_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(PFC_ECC_SG_ERR, &bar0->pfc_err_reg, - &sw_stat->pfc_err_cnt); + do_s2io_chk_alarm_bit(PFC_ECC_SG_ERR, + &bar0->pfc_err_reg, + &sw_stat->pfc_err_cnt); } /*check for tda_err*/ if (val64 & TXDMA_TDA_INT) { - if(do_s2io_chk_alarm_bit(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM | - TDA_SM1_ERR_ALARM, &bar0->tda_err_reg, - &sw_stat->tda_err_cnt)) + if (do_s2io_chk_alarm_bit(TDA_Fn_ECC_DB_ERR | + TDA_SM0_ERR_ALARM | + TDA_SM1_ERR_ALARM, + &bar0->tda_err_reg, + &sw_stat->tda_err_cnt)) goto reset; do_s2io_chk_alarm_bit(TDA_Fn_ECC_SG_ERR | TDA_PCIX_ERR, - &bar0->tda_err_reg, &sw_stat->tda_err_cnt); + &bar0->tda_err_reg, + &sw_stat->tda_err_cnt); } /*check for pcc_err*/ if (val64 & TXDMA_PCC_INT) { - if (do_s2io_chk_alarm_bit(PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM - | PCC_N_SERR | PCC_6_COF_OV_ERR - | PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR - | PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR - | PCC_TXB_ECC_DB_ERR, &bar0->pcc_err_reg, - &sw_stat->pcc_err_cnt)) + if (do_s2io_chk_alarm_bit(PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM | + PCC_N_SERR | PCC_6_COF_OV_ERR | + PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR | + PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR | + PCC_TXB_ECC_DB_ERR, + &bar0->pcc_err_reg, + &sw_stat->pcc_err_cnt)) goto reset; do_s2io_chk_alarm_bit(PCC_FB_ECC_SG_ERR | PCC_TXB_ECC_SG_ERR, - &bar0->pcc_err_reg, &sw_stat->pcc_err_cnt); + &bar0->pcc_err_reg, + &sw_stat->pcc_err_cnt); } /*check for tti_err*/ if (val64 & TXDMA_TTI_INT) { - if (do_s2io_chk_alarm_bit(TTI_SM_ERR_ALARM, &bar0->tti_err_reg, - &sw_stat->tti_err_cnt)) + if (do_s2io_chk_alarm_bit(TTI_SM_ERR_ALARM, + &bar0->tti_err_reg, + &sw_stat->tti_err_cnt)) goto reset; do_s2io_chk_alarm_bit(TTI_ECC_SG_ERR | TTI_ECC_DB_ERR, - &bar0->tti_err_reg, &sw_stat->tti_err_cnt); + &bar0->tti_err_reg, + &sw_stat->tti_err_cnt); } /*check for lso_err*/ if (val64 & TXDMA_LSO_INT) { - if (do_s2io_chk_alarm_bit(LSO6_ABORT | LSO7_ABORT - | LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM, - &bar0->lso_err_reg, &sw_stat->lso_err_cnt)) + if (do_s2io_chk_alarm_bit(LSO6_ABORT | LSO7_ABORT | + LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM, + &bar0->lso_err_reg, + &sw_stat->lso_err_cnt)) goto reset; do_s2io_chk_alarm_bit(LSO6_SEND_OFLOW | LSO7_SEND_OFLOW, - &bar0->lso_err_reg, &sw_stat->lso_err_cnt); + &bar0->lso_err_reg, + &sw_stat->lso_err_cnt); } /*check for tpa_err*/ if (val64 & TXDMA_TPA_INT) { - if (do_s2io_chk_alarm_bit(TPA_SM_ERR_ALARM, &bar0->tpa_err_reg, - &sw_stat->tpa_err_cnt)) + if (do_s2io_chk_alarm_bit(TPA_SM_ERR_ALARM, + &bar0->tpa_err_reg, + &sw_stat->tpa_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(TPA_TX_FRM_DROP, &bar0->tpa_err_reg, - &sw_stat->tpa_err_cnt); + do_s2io_chk_alarm_bit(TPA_TX_FRM_DROP, + &bar0->tpa_err_reg, + &sw_stat->tpa_err_cnt); } /*check for sm_err*/ if (val64 & TXDMA_SM_INT) { - if (do_s2io_chk_alarm_bit(SM_SM_ERR_ALARM, &bar0->sm_err_reg, - &sw_stat->sm_err_cnt)) + if (do_s2io_chk_alarm_bit(SM_SM_ERR_ALARM, + &bar0->sm_err_reg, + &sw_stat->sm_err_cnt)) goto reset; } val64 = readq(&bar0->mac_int_status); if (val64 & MAC_INT_STATUS_TMAC_INT) { if (do_s2io_chk_alarm_bit(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR, - &bar0->mac_tmac_err_reg, - &sw_stat->mac_tmac_err_cnt)) + &bar0->mac_tmac_err_reg, + &sw_stat->mac_tmac_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR - | TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR, - &bar0->mac_tmac_err_reg, - &sw_stat->mac_tmac_err_cnt); + do_s2io_chk_alarm_bit(TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR | + TMAC_DESC_ECC_SG_ERR | + TMAC_DESC_ECC_DB_ERR, + &bar0->mac_tmac_err_reg, + &sw_stat->mac_tmac_err_cnt); } val64 = readq(&bar0->xgxs_int_status); if (val64 & XGXS_INT_STATUS_TXGXS) { if (do_s2io_chk_alarm_bit(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR, - &bar0->xgxs_txgxs_err_reg, - &sw_stat->xgxs_txgxs_err_cnt)) + &bar0->xgxs_txgxs_err_reg, + &sw_stat->xgxs_txgxs_err_cnt)) goto reset; do_s2io_chk_alarm_bit(TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR, - &bar0->xgxs_txgxs_err_reg, - &sw_stat->xgxs_txgxs_err_cnt); + &bar0->xgxs_txgxs_err_reg, + &sw_stat->xgxs_txgxs_err_cnt); } val64 = readq(&bar0->rxdma_int_status); if (val64 & RXDMA_INT_RC_INT_M) { - if (do_s2io_chk_alarm_bit(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR - | RC_PRCn_SM_ERR_ALARM |RC_FTC_SM_ERR_ALARM, - &bar0->rc_err_reg, &sw_stat->rc_err_cnt)) + if (do_s2io_chk_alarm_bit(RC_PRCn_ECC_DB_ERR | + RC_FTC_ECC_DB_ERR | + RC_PRCn_SM_ERR_ALARM | + RC_FTC_SM_ERR_ALARM, + &bar0->rc_err_reg, + &sw_stat->rc_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR - | RC_RDA_FAIL_WR_Rn, &bar0->rc_err_reg, - &sw_stat->rc_err_cnt); - if (do_s2io_chk_alarm_bit(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn - | PRC_PCI_AB_F_WR_Rn, &bar0->prc_pcix_err_reg, - &sw_stat->prc_pcix_err_cnt)) + do_s2io_chk_alarm_bit(RC_PRCn_ECC_SG_ERR | + RC_FTC_ECC_SG_ERR | + RC_RDA_FAIL_WR_Rn, &bar0->rc_err_reg, + &sw_stat->rc_err_cnt); + if (do_s2io_chk_alarm_bit(PRC_PCI_AB_RD_Rn | + PRC_PCI_AB_WR_Rn | + PRC_PCI_AB_F_WR_Rn, + &bar0->prc_pcix_err_reg, + &sw_stat->prc_pcix_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(PRC_PCI_DP_RD_Rn | PRC_PCI_DP_WR_Rn - | PRC_PCI_DP_F_WR_Rn, &bar0->prc_pcix_err_reg, - &sw_stat->prc_pcix_err_cnt); + do_s2io_chk_alarm_bit(PRC_PCI_DP_RD_Rn | + PRC_PCI_DP_WR_Rn | + PRC_PCI_DP_F_WR_Rn, + &bar0->prc_pcix_err_reg, + &sw_stat->prc_pcix_err_cnt); } if (val64 & RXDMA_INT_RPA_INT_M) { if (do_s2io_chk_alarm_bit(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR, - &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt)) + &bar0->rpa_err_reg, + &sw_stat->rpa_err_cnt)) goto reset; do_s2io_chk_alarm_bit(RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, - &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt); + &bar0->rpa_err_reg, + &sw_stat->rpa_err_cnt); } if (val64 & RXDMA_INT_RDA_INT_M) { - if (do_s2io_chk_alarm_bit(RDA_RXDn_ECC_DB_ERR - | RDA_FRM_ECC_DB_N_AERR | RDA_SM1_ERR_ALARM - | RDA_SM0_ERR_ALARM | RDA_RXD_ECC_DB_SERR, - &bar0->rda_err_reg, &sw_stat->rda_err_cnt)) + if (do_s2io_chk_alarm_bit(RDA_RXDn_ECC_DB_ERR | + RDA_FRM_ECC_DB_N_AERR | + RDA_SM1_ERR_ALARM | + RDA_SM0_ERR_ALARM | + RDA_RXD_ECC_DB_SERR, + &bar0->rda_err_reg, + &sw_stat->rda_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(RDA_RXDn_ECC_SG_ERR | RDA_FRM_ECC_SG_ERR - | RDA_MISC_ERR | RDA_PCIX_ERR, - &bar0->rda_err_reg, &sw_stat->rda_err_cnt); + do_s2io_chk_alarm_bit(RDA_RXDn_ECC_SG_ERR | + RDA_FRM_ECC_SG_ERR | + RDA_MISC_ERR | + RDA_PCIX_ERR, + &bar0->rda_err_reg, + &sw_stat->rda_err_cnt); } if (val64 & RXDMA_INT_RTI_INT_M) { - if (do_s2io_chk_alarm_bit(RTI_SM_ERR_ALARM, &bar0->rti_err_reg, - &sw_stat->rti_err_cnt)) + if (do_s2io_chk_alarm_bit(RTI_SM_ERR_ALARM, + &bar0->rti_err_reg, + &sw_stat->rti_err_cnt)) goto reset; do_s2io_chk_alarm_bit(RTI_ECC_SG_ERR | RTI_ECC_DB_ERR, - &bar0->rti_err_reg, &sw_stat->rti_err_cnt); + &bar0->rti_err_reg, + &sw_stat->rti_err_cnt); } val64 = readq(&bar0->mac_int_status); if (val64 & MAC_INT_STATUS_RMAC_INT) { if (do_s2io_chk_alarm_bit(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR, - &bar0->mac_rmac_err_reg, - &sw_stat->mac_rmac_err_cnt)) + &bar0->mac_rmac_err_reg, + &sw_stat->mac_rmac_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(RMAC_UNUSED_INT|RMAC_SINGLE_ECC_ERR| - RMAC_DOUBLE_ECC_ERR, &bar0->mac_rmac_err_reg, - &sw_stat->mac_rmac_err_cnt); + do_s2io_chk_alarm_bit(RMAC_UNUSED_INT | + RMAC_SINGLE_ECC_ERR | + RMAC_DOUBLE_ECC_ERR, + &bar0->mac_rmac_err_reg, + &sw_stat->mac_rmac_err_cnt); } val64 = readq(&bar0->xgxs_int_status); if (val64 & XGXS_INT_STATUS_RXGXS) { if (do_s2io_chk_alarm_bit(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, - &bar0->xgxs_rxgxs_err_reg, - &sw_stat->xgxs_rxgxs_err_cnt)) + &bar0->xgxs_rxgxs_err_reg, + &sw_stat->xgxs_rxgxs_err_cnt)) goto reset; } val64 = readq(&bar0->mc_int_status); - if(val64 & MC_INT_STATUS_MC_INT) { - if (do_s2io_chk_alarm_bit(MC_ERR_REG_SM_ERR, &bar0->mc_err_reg, - &sw_stat->mc_err_cnt)) + if (val64 & MC_INT_STATUS_MC_INT) { + if (do_s2io_chk_alarm_bit(MC_ERR_REG_SM_ERR, + &bar0->mc_err_reg, + &sw_stat->mc_err_cnt)) goto reset; /* Handling Ecc errors */ @@ -4738,10 +4767,10 @@ static void s2io_handle_errors(void * dev_id) * Reset XframeI only if critical error */ if (val64 & - (MC_ERR_REG_MIRI_ECC_DB_ERR_0 | - MC_ERR_REG_MIRI_ECC_DB_ERR_1)) - goto reset; - } + (MC_ERR_REG_MIRI_ECC_DB_ERR_0 | + MC_ERR_REG_MIRI_ECC_DB_ERR_1)) + goto reset; + } } else sw_stat->single_ecc_errs++; } @@ -4770,7 +4799,7 @@ reset: */ static irqreturn_t s2io_isr(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = (struct net_device *)dev_id; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; int i; @@ -4797,14 +4826,11 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) */ reason = readq(&bar0->general_int_status); - if (unlikely(reason == S2IO_MINUS_ONE) ) { - /* Nothing much can be done. Get out */ - return IRQ_HANDLED; - } + if (unlikely(reason == S2IO_MINUS_ONE)) + return IRQ_HANDLED; /* Nothing much can be done. Get out */ - if (reason & (GEN_INTR_RXTRAFFIC | - GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC)) - { + if (reason & + (GEN_INTR_RXTRAFFIC | GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC)) { writeq(S2IO_MINUS_ONE, &bar0->general_int_mask); if (config->napi) { @@ -4859,8 +4885,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) return IRQ_HANDLED; - } - else if (!reason) { + } else if (!reason) { /* The interrupt was not raised by us */ return IRQ_NONE; } @@ -4890,7 +4915,7 @@ static void s2io_updt_stats(struct s2io_nic *sp) cnt++; if (cnt == 5) break; /* Updt failed */ - } while(1); + } while (1); } } @@ -4921,7 +4946,7 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) /* Using sp->stats as a staging area, because reset (due to mtu change, for example) will clear some hardware counters */ dev->stats.tx_packets += - le32_to_cpu(mac_control->stats_info->tmac_frms) - + le32_to_cpu(mac_control->stats_info->tmac_frms) - sp->stats.tx_packets; sp->stats.tx_packets = le32_to_cpu(mac_control->stats_info->tmac_frms); @@ -4936,12 +4961,12 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) sp->stats.rx_errors = le64_to_cpu(mac_control->stats_info->rmac_drop_frms); dev->stats.multicast = - le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms) - + le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms) - sp->stats.multicast; sp->stats.multicast = le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms); dev->stats.rx_length_errors = - le64_to_cpu(mac_control->stats_info->rmac_long_frms) - + le64_to_cpu(mac_control->stats_info->rmac_long_frms) - sp->stats.rx_length_errors; sp->stats.rx_length_errors = le64_to_cpu(mac_control->stats_info->rmac_long_frms); @@ -4955,7 +4980,7 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) dev->stats.rx_bytes += ring->rx_bytes; } - return (&dev->stats); + return &dev->stats; } /** @@ -4978,7 +5003,7 @@ static void s2io_set_multicast(struct net_device *dev) struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, multi_mac = 0x010203040506ULL, mask = - 0xfeffffffffffULL; + 0xfeffffffffffULL; u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, mac_addr = 0; void __iomem *add; struct config_param *config = &sp->config; @@ -4990,13 +5015,13 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA1_MEM_MASK(mask), &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | - RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(config->max_mc_addr - 1); + RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + RMAC_ADDR_CMD_MEM_OFFSET(config->max_mc_addr - 1); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET); sp->m_cast_flg = 1; sp->all_multi_pos = config->max_mc_addr - 1; @@ -5007,13 +5032,13 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0), &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | - RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos); + RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET); sp->m_cast_flg = 0; sp->all_multi_pos = 0; @@ -5026,7 +5051,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 |= MAC_CFG_RMAC_PROM_ENABLE; writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); - writel((u32) val64, add); + writel((u32)val64, add); writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); writel((u32) (val64 >> 32), (add + 4)); @@ -5048,7 +5073,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 &= ~MAC_CFG_RMAC_PROM_ENABLE; writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); - writel((u32) val64, add); + writel((u32)val64, add); writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); writel((u32) (val64 >> 32), (add + 4)); @@ -5084,19 +5109,18 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr), &bar0->rmac_addr_data0_mem); writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL), - &bar0->rmac_addr_data1_mem); + &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | - RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET - (config->mc_start_offset + i); + RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + RMAC_ADDR_CMD_MEM_OFFSET + (config->mc_start_offset + i); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait for command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET)) { - DBG_PRINT(ERR_DBG, "%s: Adding ", - dev->name); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { + DBG_PRINT(ERR_DBG, "%s: Adding ", dev->name); DBG_PRINT(ERR_DBG, "Multicasts failed\n"); return; } @@ -5116,19 +5140,18 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr), &bar0->rmac_addr_data0_mem); writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL), - &bar0->rmac_addr_data1_mem); + &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | - RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET - (i + config->mc_start_offset); + RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + RMAC_ADDR_CMD_MEM_OFFSET + (i + config->mc_start_offset); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait for command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET)) { - DBG_PRINT(ERR_DBG, "%s: Adding ", - dev->name); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { + DBG_PRINT(ERR_DBG, "%s: Adding ", dev->name); DBG_PRINT(ERR_DBG, "Multicasts failed\n"); return; } @@ -5163,11 +5186,11 @@ static void do_s2io_restore_unicast_mc(struct s2io_nic *sp) /* restore unicast mac address */ for (offset = 0; offset < config->max_mac_addr; offset++) do_s2io_prog_unicast(sp->dev, - sp->def_mac_addr[offset].mac_addr); + sp->def_mac_addr[offset].mac_addr); /* restore multicast mac address */ for (offset = config->mc_start_offset; - offset < config->max_mc_addr; offset++) + offset < config->max_mc_addr; offset++) do_s2io_add_mc(sp, sp->def_mac_addr[offset].mac_addr); } @@ -5197,13 +5220,13 @@ static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr) } if (i == config->max_mc_addr) { DBG_PRINT(ERR_DBG, - "CAM full no space left for multicast MAC\n"); + "CAM full no space left for multicast MAC\n"); return FAILURE; } /* Update the internal structure with this new mac address */ do_s2io_copy_mac_addr(sp, i, mac_addr); - return (do_s2io_add_mac(sp, mac_addr, i)); + return do_s2io_add_mac(sp, mac_addr, i); } /* add MAC address to CAM */ @@ -5213,17 +5236,16 @@ static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int off) struct XENA_dev_config __iomem *bar0 = sp->bar0; writeq(RMAC_ADDR_DATA0_MEM_ADDR(addr), - &bar0->rmac_addr_data0_mem); + &bar0->rmac_addr_data0_mem); - val64 = - RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET(off); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET)) { + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { DBG_PRINT(INFO_DBG, "do_s2io_add_mac failed\n"); return FAILURE; } @@ -5237,7 +5259,7 @@ static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr) struct config_param *config = &sp->config; for (offset = 1; - offset < config->max_mc_addr; offset++) { + offset < config->max_mc_addr; offset++) { tmp64 = do_s2io_read_unicast_mc(sp, offset); if (tmp64 == addr) { /* disable the entry by writing 0xffffffffffffULL */ @@ -5249,7 +5271,7 @@ static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr) } } DBG_PRINT(ERR_DBG, "MAC address 0x%llx not found in CAM\n", - (unsigned long long)addr); + (unsigned long long)addr); return FAILURE; } @@ -5260,20 +5282,20 @@ static u64 do_s2io_read_unicast_mc(struct s2io_nic *sp, int offset) struct XENA_dev_config __iomem *bar0 = sp->bar0; /* read mac addr */ - val64 = - RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET(offset); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET)) { + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { DBG_PRINT(INFO_DBG, "do_s2io_read_unicast_mc failed\n"); return FAILURE; } tmp64 = readq(&bar0->rmac_addr_data0_mem); - return (tmp64 >> 16); + + return tmp64 >> 16; } /** @@ -5290,7 +5312,7 @@ static int s2io_set_mac_addr(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); /* store the MAC address in CAM */ - return (do_s2io_prog_unicast(dev, dev->dev_addr)); + return do_s2io_prog_unicast(dev, dev->dev_addr); } /** * do_s2io_prog_unicast - Programs the Xframe mac address @@ -5311,10 +5333,10 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) struct config_param *config = &sp->config; /* - * Set the new MAC address as the new unicast filter and reflect this - * change on the device address registered with the OS. It will be - * at offset 0. - */ + * Set the new MAC address as the new unicast filter and reflect this + * change on the device address registered with the OS. It will be + * at offset 0. + */ for (i = 0; i < ETH_ALEN; i++) { mac_addr <<= 8; mac_addr |= addr[i]; @@ -5334,8 +5356,8 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) if (tmp64 == mac_addr) { DBG_PRINT(INFO_DBG, - "MAC addr:0x%llx already present in CAM\n", - (unsigned long long)mac_addr); + "MAC addr:0x%llx already present in CAM\n", + (unsigned long long)mac_addr); return SUCCESS; } } @@ -5345,7 +5367,8 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) } /* Update the internal structure with this new mac address */ do_s2io_copy_mac_addr(sp, i, mac_addr); - return (do_s2io_add_mac(sp, mac_addr, i)); + + return do_s2io_add_mac(sp, mac_addr, i); } /** @@ -5358,14 +5381,15 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) * the NIC. * Return value: * 0 on success. -*/ + */ static int s2io_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info) { struct s2io_nic *sp = netdev_priv(dev); if ((info->autoneg == AUTONEG_ENABLE) || - (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL)) + (info->speed != SPEED_10000) || + (info->duplex != DUPLEX_FULL)) return -EINVAL; else { s2io_close(sp->dev); @@ -5446,14 +5470,14 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev, * buffer area. * Return value : * void . -*/ + */ static void s2io_ethtool_gregs(struct net_device *dev, struct ethtool_regs *regs, void *space) { int i; u64 reg; - u8 *reg_space = (u8 *) space; + u8 *reg_space = (u8 *)space; struct s2io_nic *sp = netdev_priv(dev); regs->len = XENA_REG_SPACE; @@ -5473,17 +5497,17 @@ static void s2io_ethtool_gregs(struct net_device *dev, * adapter LED bit of the adapter control bit to set/reset every time on * invocation. The timer is set for 1/2 a second, hence tha NIC blinks * once every second. -*/ + */ static void s2io_phy_id(unsigned long data) { - struct s2io_nic *sp = (struct s2io_nic *) data; + struct s2io_nic *sp = (struct s2io_nic *)data; struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0; u16 subid; subid = sp->pdev->subsystem_device; if ((sp->device_type == XFRAME_II_DEVICE) || - ((subid & 0xFF) >= 0x07)) { + ((subid & 0xFF) >= 0x07)) { val64 = readq(&bar0->gpio_control); val64 ^= GPIO_CTRL_GPIO_0; writeq(val64, &bar0->gpio_control); @@ -5520,8 +5544,7 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) subid = sp->pdev->subsystem_device; last_gpio_ctrl_val = readq(&bar0->gpio_control); - if ((sp->device_type == XFRAME_I_DEVICE) && - ((subid & 0xFF) < 0x07)) { + if ((sp->device_type == XFRAME_I_DEVICE) && ((subid & 0xFF) < 0x07)) { val64 = readq(&bar0->adapter_control); if (!(val64 & ADAPTER_CNTL_EN)) { printk(KERN_ERR @@ -5532,7 +5555,7 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) if (sp->id_timer.function == NULL) { init_timer(&sp->id_timer); sp->id_timer.function = s2io_phy_id; - sp->id_timer.data = (unsigned long) sp; + sp->id_timer.data = (unsigned long)sp; } mod_timer(&sp->id_timer, jiffies); if (data) @@ -5550,10 +5573,10 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) } static void s2io_ethtool_gringparam(struct net_device *dev, - struct ethtool_ringparam *ering) + struct ethtool_ringparam *ering) { struct s2io_nic *sp = netdev_priv(dev); - int i,tx_desc_count=0,rx_desc_count=0; + int i, tx_desc_count = 0, rx_desc_count = 0; if (sp->rxd_mode == RXD_MODE_1) ering->rx_max_pending = MAX_RX_DESC_1; @@ -5564,7 +5587,7 @@ static void s2io_ethtool_gringparam(struct net_device *dev, for (i = 0 ; i < sp->config.tx_fifo_num ; i++) tx_desc_count += sp->config.tx_cfg[i].fifo_len; - DBG_PRINT(INFO_DBG,"\nmax txds : %d\n",sp->config.max_txds); + DBG_PRINT(INFO_DBG, "\nmax txds : %d\n", sp->config.max_txds); ering->tx_pending = tx_desc_count; rx_desc_count = 0; for (i = 0 ; i < sp->config.rx_ring_num ; i++) @@ -5574,7 +5597,7 @@ static void s2io_ethtool_gringparam(struct net_device *dev, ering->rx_mini_max_pending = 0; ering->rx_mini_pending = 0; - if(sp->rxd_mode == RXD_MODE_1) + if (sp->rxd_mode == RXD_MODE_1) ering->rx_jumbo_max_pending = MAX_RX_DESC_1; else if (sp->rxd_mode == RXD_MODE_3B) ering->rx_jumbo_max_pending = MAX_RX_DESC_2; @@ -5619,7 +5642,7 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, */ static int s2io_ethtool_setpause_data(struct net_device *dev, - struct ethtool_pauseparam *ep) + struct ethtool_pauseparam *ep) { u64 val64; struct s2io_nic *sp = netdev_priv(dev); @@ -5655,7 +5678,7 @@ static int s2io_ethtool_setpause_data(struct net_device *dev, */ #define S2IO_DEV_ID 5 -static int read_eeprom(struct s2io_nic * sp, int off, u64 * data) +static int read_eeprom(struct s2io_nic *sp, int off, u64 *data) { int ret = -1; u32 exit_cnt = 0; @@ -5663,9 +5686,11 @@ static int read_eeprom(struct s2io_nic * sp, int off, u64 * data) struct XENA_dev_config __iomem *bar0 = sp->bar0; if (sp->device_type == XFRAME_I_DEVICE) { - val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | - I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ | - I2C_CONTROL_CNTL_START; + val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | + I2C_CONTROL_ADDR(off) | + I2C_CONTROL_BYTE_CNT(0x3) | + I2C_CONTROL_READ | + I2C_CONTROL_CNTL_START; SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); while (exit_cnt < 5) { @@ -5720,16 +5745,18 @@ static int read_eeprom(struct s2io_nic * sp, int off, u64 * data) * 0 on success, -1 on failure. */ -static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt) +static int write_eeprom(struct s2io_nic *sp, int off, u64 data, int cnt) { int exit_cnt = 0, ret = -1; u64 val64; struct XENA_dev_config __iomem *bar0 = sp->bar0; if (sp->device_type == XFRAME_I_DEVICE) { - val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | - I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) | - I2C_CONTROL_CNTL_START; + val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | + I2C_CONTROL_ADDR(off) | + I2C_CONTROL_BYTE_CNT(cnt) | + I2C_CONTROL_SET_DATA((u32)data) | + I2C_CONTROL_CNTL_START; SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); while (exit_cnt < 5) { @@ -5746,7 +5773,7 @@ static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt) if (sp->device_type == XFRAME_II_DEVICE) { int write_cnt = (cnt == 8) ? 0 : cnt; - writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data); + writeq(SPI_DATA_WRITE(data, (cnt << 3)), &bar0->spi_data); val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 | SPI_CONTROL_BYTECNT(write_cnt) | @@ -5773,14 +5800,13 @@ static void s2io_vpd_read(struct s2io_nic *nic) { u8 *vpd_data; u8 data; - int i=0, cnt, fail = 0; + int i = 0, cnt, fail = 0; int vpd_addr = 0x80; if (nic->device_type == XFRAME_II_DEVICE) { strcpy(nic->product_name, "Xframe II 10GbE network adapter"); vpd_addr = 0x80; - } - else { + } else { strcpy(nic->product_name, "Xframe I 10GbE network adapter"); vpd_addr = 0x50; } @@ -5793,11 +5819,11 @@ static void s2io_vpd_read(struct s2io_nic *nic) } nic->mac_control.stats_info->sw_stat.mem_allocated += 256; - for (i = 0; i < 256; i +=4 ) { + for (i = 0; i < 256; i += 4) { pci_write_config_byte(nic->pdev, (vpd_addr + 2), i); pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data); pci_write_config_byte(nic->pdev, (vpd_addr + 3), 0); - for (cnt = 0; cnt <5; cnt++) { + for (cnt = 0; cnt < 5; cnt++) { msleep(2); pci_read_config_byte(nic->pdev, (vpd_addr + 3), &data); if (data == 0x80) @@ -5812,15 +5838,15 @@ static void s2io_vpd_read(struct s2io_nic *nic) (u32 *)&vpd_data[i]); } - if(!fail) { + if (!fail) { /* read serial number of adapter */ for (cnt = 0; cnt < 256; cnt++) { - if ((vpd_data[cnt] == 'S') && - (vpd_data[cnt+1] == 'N') && - (vpd_data[cnt+2] < VPD_STRING_LEN)) { + if ((vpd_data[cnt] == 'S') && + (vpd_data[cnt+1] == 'N') && + (vpd_data[cnt+2] < VPD_STRING_LEN)) { memset(nic->serial_num, 0, VPD_STRING_LEN); memcpy(nic->serial_num, &vpd_data[cnt + 3], - vpd_data[cnt+2]); + vpd_data[cnt+2]); break; } } @@ -5848,7 +5874,7 @@ static void s2io_vpd_read(struct s2io_nic *nic) */ static int s2io_ethtool_geeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 * data_buf) + struct ethtool_eeprom *eeprom, u8 * data_buf) { u32 i, valid; u64 data; @@ -5886,7 +5912,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev, static int s2io_ethtool_seeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, - u8 * data_buf) + u8 *data_buf) { int len = eeprom->len, cnt = 0; u64 valid = 0, data; @@ -5895,16 +5921,15 @@ static int s2io_ethtool_seeprom(struct net_device *dev, if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { DBG_PRINT(ERR_DBG, "ETHTOOL_WRITE_EEPROM Err: Magic value "); - DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n", - eeprom->magic); + DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n", eeprom->magic); return -EFAULT; } while (len) { - data = (u32) data_buf[cnt] & 0x000000FF; - if (data) { - valid = (u32) (data << 24); - } else + data = (u32)data_buf[cnt] & 0x000000FF; + if (data) + valid = (u32)(data << 24); + else valid = data; if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) { @@ -5934,7 +5959,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev, * 0 on success. */ -static int s2io_register_test(struct s2io_nic * sp, uint64_t * data) +static int s2io_register_test(struct s2io_nic *sp, uint64_t *data) { struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, exp_val; @@ -6001,7 +6026,7 @@ static int s2io_register_test(struct s2io_nic * sp, uint64_t * data) * 0 on success. */ -static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data) +static int s2io_eeprom_test(struct s2io_nic *sp, uint64_t *data) { int fail = 0; u64 ret_data, org_4F0, org_7F0; @@ -6030,9 +6055,9 @@ static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data) if (ret_data != 0x012345) { DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. " - "Data written %llx Data read %llx\n", - dev->name, (unsigned long long)0x12345, - (unsigned long long)ret_data); + "Data written %llx Data read %llx\n", + dev->name, (unsigned long long)0x12345, + (unsigned long long)ret_data); fail = 1; } @@ -6052,9 +6077,9 @@ static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data) if (ret_data != 0x012345) { DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. " - "Data written %llx Data read %llx\n", - dev->name, (unsigned long long)0x12345, - (unsigned long long)ret_data); + "Data written %llx Data read %llx\n", + dev->name, (unsigned long long)0x12345, + (unsigned long long)ret_data); fail = 1; } @@ -6103,7 +6128,7 @@ static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data) * 0 on success and -1 on failure. */ -static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data) +static int s2io_bist_test(struct s2io_nic *sp, uint64_t *data) { u8 bist = 0; int cnt = 0, ret = -1; @@ -6139,13 +6164,13 @@ static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data) * 0 on success. */ -static int s2io_link_test(struct s2io_nic * sp, uint64_t * data) +static int s2io_link_test(struct s2io_nic *sp, uint64_t *data) { struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; val64 = readq(&bar0->adapter_status); - if(!(LINK_IS_UP(val64))) + if (!(LINK_IS_UP(val64))) *data = 1; else *data = 0; @@ -6166,7 +6191,7 @@ static int s2io_link_test(struct s2io_nic * sp, uint64_t * data) * 0 on success. */ -static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data) +static int s2io_rldram_test(struct s2io_nic *sp, uint64_t *data) { struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; @@ -6189,28 +6214,26 @@ static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data) while (iteration < 2) { val64 = 0x55555555aaaa0000ULL; - if (iteration == 1) { + if (iteration == 1) val64 ^= 0xFFFFFFFFFFFF0000ULL; - } writeq(val64, &bar0->mc_rldram_test_d0); val64 = 0xaaaa5a5555550000ULL; - if (iteration == 1) { + if (iteration == 1) val64 ^= 0xFFFFFFFFFFFF0000ULL; - } writeq(val64, &bar0->mc_rldram_test_d1); val64 = 0x55aaaaaaaa5a0000ULL; - if (iteration == 1) { + if (iteration == 1) val64 ^= 0xFFFFFFFFFFFF0000ULL; - } writeq(val64, &bar0->mc_rldram_test_d2); val64 = (u64) (0x0000003ffffe0100ULL); writeq(val64, &bar0->mc_rldram_test_add); - val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE | - MC_RLDRAM_TEST_GO; + val64 = MC_RLDRAM_TEST_MODE | + MC_RLDRAM_TEST_WRITE | + MC_RLDRAM_TEST_GO; SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); for (cnt = 0; cnt < 5; cnt++) { @@ -6268,7 +6291,7 @@ static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data) static void s2io_ethtool_test(struct net_device *dev, struct ethtool_test *ethtest, - uint64_t * data) + uint64_t *data) { struct s2io_nic *sp = netdev_priv(dev); int orig_state = netif_running(sp->dev); @@ -6301,8 +6324,7 @@ static void s2io_ethtool_test(struct net_device *dev, } else { /* Online Tests. */ if (!orig_state) { - DBG_PRINT(ERR_DBG, - "%s: is not up, cannot run test\n", + DBG_PRINT(ERR_DBG, "%s: is not up, cannot run test\n", dev->name); data[0] = -1; data[1] = -1; @@ -6323,7 +6345,7 @@ static void s2io_ethtool_test(struct net_device *dev, static void s2io_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, - u64 * tmp_stats) + u64 *tmp_stats) { int i = 0, k; struct s2io_nic *sp = netdev_priv(dev); @@ -6344,19 +6366,19 @@ static void s2io_get_ethtool_stats(struct net_device *dev, (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 | le32_to_cpu(stat_info->tmac_bcst_frms); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms); - tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 | - le32_to_cpu(stat_info->tmac_ttl_octets); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_ucst_frms); + (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 | + le32_to_cpu(stat_info->tmac_ttl_octets); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_nucst_frms); + (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_ucst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_nucst_frms); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 | le32_to_cpu(stat_info->tmac_any_err_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets); + tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 | @@ -6392,23 +6414,23 @@ static void s2io_get_ethtool_stats(struct net_device *dev, tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms); - tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 | + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 | le32_to_cpu(stat_info->rmac_ttl_octets); - tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow) - << 32 | le32_to_cpu(stat_info->rmac_accepted_ucst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow) - << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms); + (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow) << 32 + | le32_to_cpu(stat_info->rmac_accepted_ucst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow) + << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 | le32_to_cpu(stat_info->rmac_discarded_frms); - tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow) - << 32 | le32_to_cpu(stat_info->rmac_drop_events); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow) + << 32 | le32_to_cpu(stat_info->rmac_drop_events); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 | le32_to_cpu(stat_info->rmac_usized_frms); @@ -6422,11 +6444,11 @@ static void s2io_get_ethtool_stats(struct net_device *dev, (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 | le32_to_cpu(stat_info->rmac_jabber_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 | le32_to_cpu(stat_info->rmac_ip); @@ -6446,27 +6468,27 @@ static void s2io_get_ethtool_stats(struct net_device *dev, (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 | le32_to_cpu(stat_info->rmac_err_drp_udp); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 | le32_to_cpu(stat_info->rmac_pause_cnt); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 | le32_to_cpu(stat_info->rmac_accepted_ip); @@ -6491,13 +6513,13 @@ static void s2io_get_ethtool_stats(struct net_device *dev, tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt); /* Enhanced statistics exist only for Hercules */ - if(sp->device_type == XFRAME_II_DEVICE) { + if (sp->device_type == XFRAME_II_DEVICE) { tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms); + le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms); tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms); + le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms); tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_8192_max_frms); + le64_to_cpu(stat_info->rmac_ttl_8192_max_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms); @@ -6550,8 +6572,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev, count++; } tmp_stats[i++] = count; - } - else + } else tmp_stats[i++] = 0; tmp_stats[i++] = stat_info->sw_stat.mem_alloc_fail_cnt; tmp_stats[i++] = stat_info->sw_stat.pci_map_fail_cnt; @@ -6599,15 +6620,15 @@ static void s2io_get_ethtool_stats(struct net_device *dev, static int s2io_ethtool_get_regs_len(struct net_device *dev) { - return (XENA_REG_SPACE); + return XENA_REG_SPACE; } -static u32 s2io_ethtool_get_rx_csum(struct net_device * dev) +static u32 s2io_ethtool_get_rx_csum(struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); - return (sp->rx_csum); + return sp->rx_csum; } static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) @@ -6624,7 +6645,7 @@ static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) static int s2io_get_eeprom_len(struct net_device *dev) { - return (XENA_EEPROM_SPACE); + return XENA_EEPROM_SPACE; } static int s2io_get_sset_count(struct net_device *dev, int sset) @@ -6635,7 +6656,7 @@ static int s2io_get_sset_count(struct net_device *dev, int sset) case ETH_SS_TEST: return S2IO_TEST_LEN; case ETH_SS_STATS: - switch(sp->device_type) { + switch (sp->device_type) { case XFRAME_I_DEVICE: return XFRAME_I_STAT_LEN; case XFRAME_II_DEVICE: @@ -6649,7 +6670,7 @@ static int s2io_get_sset_count(struct net_device *dev, int sset) } static void s2io_ethtool_get_strings(struct net_device *dev, - u32 stringset, u8 * data) + u32 stringset, u8 *data) { int stat_size = 0; struct s2io_nic *sp = netdev_priv(dev); @@ -6660,16 +6681,16 @@ static void s2io_ethtool_get_strings(struct net_device *dev, break; case ETH_SS_STATS: stat_size = sizeof(ethtool_xena_stats_keys); - memcpy(data, ðtool_xena_stats_keys,stat_size); - if(sp->device_type == XFRAME_II_DEVICE) { + memcpy(data, ðtool_xena_stats_keys, stat_size); + if (sp->device_type == XFRAME_II_DEVICE) { memcpy(data + stat_size, - ðtool_enhanced_stats_keys, - sizeof(ethtool_enhanced_stats_keys)); + ðtool_enhanced_stats_keys, + sizeof(ethtool_enhanced_stats_keys)); stat_size += sizeof(ethtool_enhanced_stats_keys); } memcpy(data + stat_size, ðtool_driver_stats_keys, - sizeof(ethtool_driver_stats_keys)); + sizeof(ethtool_driver_stats_keys)); } } @@ -6758,8 +6779,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) int ret = 0; if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) { - DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n", - dev->name); + DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n", dev->name); return -EPERM; } @@ -6792,7 +6812,8 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) static void s2io_set_link(struct work_struct *work) { - struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task); + struct s2io_nic *nic = container_of(work, struct s2io_nic, + set_link_task); struct net_device *dev = nic->dev; struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64; @@ -6825,7 +6846,7 @@ static void s2io_set_link(struct work_struct *work) val64 |= ADAPTER_CNTL_EN; writeq(val64, &bar0->adapter_control); if (CARDS_WITH_FAULTY_LINK_INDICATORS( - nic->device_type, subid)) { + nic->device_type, subid)) { val64 = readq(&bar0->gpio_control); val64 |= GPIO_CTRL_GPIO_0; writeq(val64, &bar0->gpio_control); @@ -6855,7 +6876,7 @@ static void s2io_set_link(struct work_struct *work) } /* turn off LED */ val64 = readq(&bar0->adapter_control); - val64 = val64 &(~ADAPTER_LED_ON); + val64 = val64 & (~ADAPTER_LED_ON); writeq(val64, &bar0->adapter_control); s2io_link(nic, LINK_DOWN); } @@ -6866,9 +6887,9 @@ out_unlock: } static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, - struct buffAdd *ba, - struct sk_buff **skb, u64 *temp0, u64 *temp1, - u64 *temp2, int size) + struct buffAdd *ba, + struct sk_buff **skb, u64 *temp0, u64 *temp1, + u64 *temp2, int size) { struct net_device *dev = sp->dev; struct swStat *stats = &sp->mac_control.stats_info->sw_stat; @@ -6890,7 +6911,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); DBG_PRINT(INFO_DBG, "memory to allocate "); DBG_PRINT(INFO_DBG, "1 buf mode SKBs\n"); - sp->mac_control.stats_info->sw_stat. \ + sp->mac_control.stats_info->sw_stat. mem_alloc_fail_cnt++; return -ENOMEM ; } @@ -6901,9 +6922,9 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, * Host Control is NULL */ rxdp1->Buffer0_ptr = *temp0 = - pci_map_single( sp->pdev, (*skb)->data, - size - NET_IP_ALIGN, - PCI_DMA_FROMDEVICE); + pci_map_single(sp->pdev, (*skb)->data, + size - NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(sp->pdev, rxdp1->Buffer0_ptr)) goto memalloc_failed; rxdp->Host_Control = (unsigned long) (*skb); @@ -6921,7 +6942,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); DBG_PRINT(INFO_DBG, "memory to allocate "); DBG_PRINT(INFO_DBG, "2 buf mode SKBs\n"); - sp->mac_control.stats_info->sw_stat. \ + sp->mac_control.stats_info->sw_stat. mem_alloc_fail_cnt++; return -ENOMEM; } @@ -6934,13 +6955,14 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, if (pci_dma_mapping_error(sp->pdev, rxdp3->Buffer2_ptr)) goto memalloc_failed; rxdp3->Buffer0_ptr = *temp0 = - pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN, - PCI_DMA_FROMDEVICE); + pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN, + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(sp->pdev, - rxdp3->Buffer0_ptr)) { - pci_unmap_single (sp->pdev, - (dma_addr_t)rxdp3->Buffer2_ptr, - dev->mtu + 4, PCI_DMA_FROMDEVICE); + rxdp3->Buffer0_ptr)) { + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer2_ptr, + dev->mtu + 4, + PCI_DMA_FROMDEVICE); goto memalloc_failed; } rxdp->Host_Control = (unsigned long) (*skb); @@ -6948,25 +6970,27 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, /* Buffer-1 will be dummy buffer not used */ rxdp3->Buffer1_ptr = *temp1 = pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN, - PCI_DMA_FROMDEVICE); + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(sp->pdev, - rxdp3->Buffer1_ptr)) { - pci_unmap_single (sp->pdev, - (dma_addr_t)rxdp3->Buffer0_ptr, - BUF0_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single (sp->pdev, - (dma_addr_t)rxdp3->Buffer2_ptr, - dev->mtu + 4, PCI_DMA_FROMDEVICE); + rxdp3->Buffer1_ptr)) { + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer0_ptr, + BUF0_LEN, PCI_DMA_FROMDEVICE); + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer2_ptr, + dev->mtu + 4, + PCI_DMA_FROMDEVICE); goto memalloc_failed; } } } return 0; - memalloc_failed: - stats->pci_map_fail_cnt++; - stats->mem_freed += (*skb)->truesize; - dev_kfree_skb(*skb); - return -ENOMEM; + +memalloc_failed: + stats->pci_map_fail_cnt++; + stats->mem_freed += (*skb)->truesize; + dev_kfree_skb(*skb); + return -ENOMEM; } static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp, @@ -6974,18 +6998,18 @@ static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp, { struct net_device *dev = sp->dev; if (sp->rxd_mode == RXD_MODE_1) { - rxdp->Control_2 = SET_BUFFER0_SIZE_1( size - NET_IP_ALIGN); + rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN); } else if (sp->rxd_mode == RXD_MODE_3B) { rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN); rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1); - rxdp->Control_2 |= SET_BUFFER2_SIZE_3( dev->mtu + 4); + rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu + 4); } } static int rxd_owner_bit_reset(struct s2io_nic *sp) { int i, j, k, blk_cnt = 0, size; - struct mac_info * mac_control = &sp->mac_control; + struct mac_info *mac_control = &sp->mac_control; struct config_param *config = &sp->config; struct net_device *dev = sp->dev; struct RxD_t *rxdp = NULL; @@ -7005,18 +7029,18 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp) struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; struct ring_info *ring = &mac_control->rings[i]; - blk_cnt = rx_cfg->num_rxd / (rxd_count[sp->rxd_mode] +1); + blk_cnt = rx_cfg->num_rxd / (rxd_count[sp->rxd_mode] + 1); for (j = 0; j < blk_cnt; j++) { for (k = 0; k < rxd_count[sp->rxd_mode]; k++) { - rxdp = ring-> rx_blocks[j].rxds[k].virt_addr; - if(sp->rxd_mode == RXD_MODE_3B) + rxdp = ring->rx_blocks[j].rxds[k].virt_addr; + if (sp->rxd_mode == RXD_MODE_3B) ba = &ring->ba[j][k]; - if (set_rxd_buffer_pointer(sp, rxdp, ba, - &skb,(u64 *)&temp0_64, - (u64 *)&temp1_64, - (u64 *)&temp2_64, - size) == -ENOMEM) { + if (set_rxd_buffer_pointer(sp, rxdp, ba, &skb, + (u64 *)&temp0_64, + (u64 *)&temp1_64, + (u64 *)&temp2_64, + size) == -ENOMEM) { return 0; } @@ -7031,7 +7055,7 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp) } -static int s2io_add_isr(struct s2io_nic * sp) +static int s2io_add_isr(struct s2io_nic *sp) { int ret = 0; struct net_device *dev = sp->dev; @@ -7044,7 +7068,10 @@ static int s2io_add_isr(struct s2io_nic * sp) sp->config.intr_type = INTA; } - /* Store the values of the MSIX table in the struct s2io_nic structure */ + /* + * Store the values of the MSIX table in + * the struct s2io_nic structure + */ store_xmsi_data(sp); /* After proper initialization of H/W, register ISR */ @@ -7054,45 +7081,47 @@ static int s2io_add_isr(struct s2io_nic * sp) for (i = 0; i < sp->num_entries; i++) { if (sp->s2io_entries[i].in_use == MSIX_FLG) { if (sp->s2io_entries[i].type == - MSIX_RING_TYPE) { + MSIX_RING_TYPE) { sprintf(sp->desc[i], "%s:MSI-X-%d-RX", dev->name, i); err = request_irq(sp->entries[i].vector, - s2io_msix_ring_handle, 0, - sp->desc[i], - sp->s2io_entries[i].arg); + s2io_msix_ring_handle, + 0, + sp->desc[i], + sp->s2io_entries[i].arg); } else if (sp->s2io_entries[i].type == - MSIX_ALARM_TYPE) { + MSIX_ALARM_TYPE) { sprintf(sp->desc[i], "%s:MSI-X-%d-TX", - dev->name, i); + dev->name, i); err = request_irq(sp->entries[i].vector, - s2io_msix_fifo_handle, 0, - sp->desc[i], - sp->s2io_entries[i].arg); + s2io_msix_fifo_handle, + 0, + sp->desc[i], + sp->s2io_entries[i].arg); } /* if either data or addr is zero print it. */ if (!(sp->msix_info[i].addr && - sp->msix_info[i].data)) { + sp->msix_info[i].data)) { DBG_PRINT(ERR_DBG, - "%s @Addr:0x%llx Data:0x%llx\n", - sp->desc[i], - (unsigned long long) - sp->msix_info[i].addr, - (unsigned long long) - ntohl(sp->msix_info[i].data)); + "%s @Addr:0x%llx Data:0x%llx\n", + sp->desc[i], + (unsigned long long) + sp->msix_info[i].addr, + (unsigned long long) + ntohl(sp->msix_info[i].data)); } else msix_rx_cnt++; if (err) { remove_msix_isr(sp); DBG_PRINT(ERR_DBG, - "%s:MSI-X-%d registration " - "failed\n", dev->name, i); + "%s:MSI-X-%d registration " + "failed\n", dev->name, i); DBG_PRINT(ERR_DBG, - "%s: Defaulting to INTA\n", - dev->name); + "%s: Defaulting to INTA\n", + dev->name); sp->config.intr_type = INTA; break; } @@ -7102,14 +7131,14 @@ static int s2io_add_isr(struct s2io_nic * sp) } if (!err) { printk(KERN_INFO "MSI-X-RX %d entries enabled\n", - --msix_rx_cnt); + --msix_rx_cnt); DBG_PRINT(INFO_DBG, "MSI-X-TX entries enabled" - " through alarm vector\n"); + " through alarm vector\n"); } } if (sp->config.intr_type == INTA) { - err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED, - sp->name, dev); + err = request_irq((int)sp->pdev->irq, s2io_isr, IRQF_SHARED, + sp->name, dev); if (err) { DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", dev->name); @@ -7118,7 +7147,8 @@ static int s2io_add_isr(struct s2io_nic * sp) } return 0; } -static void s2io_rem_isr(struct s2io_nic * sp) + +static void s2io_rem_isr(struct s2io_nic *sp) { if (sp->config.intr_type == MSI_X) remove_msix_isr(sp); @@ -7126,7 +7156,7 @@ static void s2io_rem_isr(struct s2io_nic * sp) remove_inta_isr(sp); } -static void do_s2io_card_down(struct s2io_nic * sp, int do_io) +static void do_s2io_card_down(struct s2io_nic *sp, int do_io) { int cnt = 0; struct XENA_dev_config __iomem *bar0 = sp->bar0; @@ -7139,9 +7169,8 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) del_timer_sync(&sp->alarm_timer); /* If s2io_set_link task is executing, wait till it completes. */ - while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) { + while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) msleep(50); - } clear_bit(__S2IO_STATE_CARD_UP, &sp->state); /* Disable napi */ @@ -7150,7 +7179,7 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) if (config->intr_type == MSI_X) { for (; off < sp->config.rx_ring_num; off++) napi_disable(&sp->mac_control.rings[off].napi); - } + } else napi_disable(&sp->napi); } @@ -7165,7 +7194,7 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) s2io_link(sp, LINK_DOWN); /* Check if the device is Quiescent and then Reset the NIC */ - while(do_io) { + while (do_io) { /* As per the HW requirement we need to replenish the * receive buffer to avoid the ring bump. Since there is * no intention of processing the Rx frame at this pointwe are @@ -7177,17 +7206,16 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) val64 = readq(&bar0->adapter_status); if (verify_xena_quiescence(sp)) { - if(verify_pcc_quiescent(sp, sp->device_enabled_once)) - break; + if (verify_pcc_quiescent(sp, sp->device_enabled_once)) + break; } msleep(50); cnt++; if (cnt == 10) { - DBG_PRINT(ERR_DBG, - "s2io_close:Device not Quiescent "); + DBG_PRINT(ERR_DBG, "s2io_close:Device not Quiescent "); DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n", - (unsigned long long) val64); + (unsigned long long)val64); break; } } @@ -7203,17 +7231,17 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state)); } -static void s2io_card_down(struct s2io_nic * sp) +static void s2io_card_down(struct s2io_nic *sp) { do_s2io_card_down(sp, 1); } -static int s2io_card_up(struct s2io_nic * sp) +static int s2io_card_up(struct s2io_nic *sp) { int i, ret = 0; struct mac_info *mac_control; struct config_param *config; - struct net_device *dev = (struct net_device *) sp->dev; + struct net_device *dev = (struct net_device *)sp->dev; u16 interruptible; /* Initialize the H/W I/O registers */ @@ -7264,7 +7292,7 @@ static int s2io_card_up(struct s2io_nic * sp) sp->promisc_flg = 0; if (sp->m_cast_flg) { sp->m_cast_flg = 0; - sp->all_multi_pos= 0; + sp->all_multi_pos = 0; } /* Setting its receive mode */ @@ -7273,7 +7301,7 @@ static int s2io_card_up(struct s2io_nic * sp) if (sp->lro) { /* Initialize max aggregatable pkts per session based on MTU */ sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu; - /* Check if we can use(if specified) user provided value */ + /* Check if we can use (if specified) user provided value */ if (lro_max_pkts < sp->lro_max_aggr_per_sess) sp->lro_max_aggr_per_sess = lro_max_pkts; } @@ -7335,12 +7363,10 @@ static void s2io_restart_nic(struct work_struct *work) s2io_card_down(sp); if (s2io_card_up(sp)) { - DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n", - dev->name); + DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n", dev->name); } s2io_wake_all_tx_queue(sp); - DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n", - dev->name); + DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n", dev->name); out_unlock: rtnl_unlock(); } @@ -7389,9 +7415,9 @@ static void s2io_tx_watchdog(struct net_device *dev) static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) { struct s2io_nic *sp = ring_data->nic; - struct net_device *dev = (struct net_device *) ring_data->dev; + struct net_device *dev = (struct net_device *)ring_data->dev; struct sk_buff *skb = (struct sk_buff *) - ((unsigned long) rxdp->Host_Control); + ((unsigned long)rxdp->Host_Control); int ring_no = ring_data->ring_no; u16 l3_csum, l4_csum; unsigned long long err = rxdp->Control_1 & RXD_T_CODE; @@ -7402,66 +7428,57 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) if (err) { /* Check for parity error */ - if (err & 0x1) { + if (err & 0x1) sp->mac_control.stats_info->sw_stat.parity_err_cnt++; - } + err_mask = err >> 48; - switch(err_mask) { - case 1: - sp->mac_control.stats_info->sw_stat. - rx_parity_err_cnt++; + switch (err_mask) { + case 1: + sp->mac_control.stats_info->sw_stat.rx_parity_err_cnt++; break; - case 2: - sp->mac_control.stats_info->sw_stat. - rx_abort_cnt++; + case 2: + sp->mac_control.stats_info->sw_stat.rx_abort_cnt++; break; - case 3: - sp->mac_control.stats_info->sw_stat. - rx_parity_abort_cnt++; + case 3: + sp->mac_control.stats_info->sw_stat.rx_parity_abort_cnt++; break; - case 4: - sp->mac_control.stats_info->sw_stat. - rx_rda_fail_cnt++; + case 4: + sp->mac_control.stats_info->sw_stat.rx_rda_fail_cnt++; break; - case 5: - sp->mac_control.stats_info->sw_stat. - rx_unkn_prot_cnt++; + case 5: + sp->mac_control.stats_info->sw_stat.rx_unkn_prot_cnt++; break; - case 6: - sp->mac_control.stats_info->sw_stat. - rx_fcs_err_cnt++; + case 6: + sp->mac_control.stats_info->sw_stat.rx_fcs_err_cnt++; break; - case 7: - sp->mac_control.stats_info->sw_stat. - rx_buf_size_err_cnt++; + case 7: + sp->mac_control.stats_info->sw_stat.rx_buf_size_err_cnt++; break; - case 8: - sp->mac_control.stats_info->sw_stat. - rx_rxd_corrupt_cnt++; + case 8: + sp->mac_control.stats_info->sw_stat.rx_rxd_corrupt_cnt++; break; - case 15: - sp->mac_control.stats_info->sw_stat. - rx_unkn_err_cnt++; + case 15: + sp->mac_control.stats_info->sw_stat.rx_unkn_err_cnt++; break; } /* - * Drop the packet if bad transfer code. Exception being - * 0x5, which could be due to unsupported IPv6 extension header. - * In this case, we let stack handle the packet. - * Note that in this case, since checksum will be incorrect, - * stack will validate the same. - */ + * Drop the packet if bad transfer code. Exception being + * 0x5, which could be due to unsupported IPv6 extension header. + * In this case, we let stack handle the packet. + * Note that in this case, since checksum will be incorrect, + * stack will validate the same. + */ if (err_mask != 0x5) { DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n", - dev->name, err_mask); + dev->name, err_mask); dev->stats.rx_crc_errors++; sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; @@ -7494,8 +7511,9 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) skb_put(skb, buf2_len); } - if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!ring_data->lro) || - (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) && + if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && + ((!ring_data->lro) || + (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) && (sp->rx_csum)) { l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); @@ -7512,52 +7530,44 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) int ret = 0; ret = s2io_club_tcp_session(ring_data, - skb->data, &tcp, &tcp_len, &lro, - rxdp, sp); + skb->data, &tcp, + &tcp_len, &lro, + rxdp, sp); switch (ret) { - case 3: /* Begin anew */ - lro->parent = skb; - goto aggregate; - case 1: /* Aggregate */ - { - lro_append_pkt(sp, lro, - skb, tcp_len); - goto aggregate; - } - case 4: /* Flush session */ - { - lro_append_pkt(sp, lro, - skb, tcp_len); - queue_rx_frame(lro->parent, - lro->vlan_tag); - clear_lro_session(lro); - sp->mac_control.stats_info-> - sw_stat.flush_max_pkts++; - goto aggregate; - } - case 2: /* Flush both */ - lro->parent->data_len = - lro->frags_len; - sp->mac_control.stats_info-> - sw_stat.sending_both++; - queue_rx_frame(lro->parent, - lro->vlan_tag); - clear_lro_session(lro); - goto send_up; - case 0: /* sessions exceeded */ - case -1: /* non-TCP or not - * L2 aggregatable - */ - case 5: /* - * First pkt in session not - * L3/L4 aggregatable - */ - break; - default: - DBG_PRINT(ERR_DBG, - "%s: Samadhana!!\n", - __func__); - BUG(); + case 3: /* Begin anew */ + lro->parent = skb; + goto aggregate; + case 1: /* Aggregate */ + lro_append_pkt(sp, lro, skb, tcp_len); + goto aggregate; + case 4: /* Flush session */ + lro_append_pkt(sp, lro, skb, tcp_len); + queue_rx_frame(lro->parent, + lro->vlan_tag); + clear_lro_session(lro); + sp->mac_control.stats_info-> + sw_stat.flush_max_pkts++; + goto aggregate; + case 2: /* Flush both */ + lro->parent->data_len = lro->frags_len; + sp->mac_control.stats_info-> + sw_stat.sending_both++; + queue_rx_frame(lro->parent, + lro->vlan_tag); + clear_lro_session(lro); + goto send_up; + case 0: /* sessions exceeded */ + case -1: /* non-TCP or not L2 aggregatable */ + case 5: /* + * First pkt in session not + * L3/L4 aggregatable + */ + break; + default: + DBG_PRINT(ERR_DBG, + "%s: Samadhana!!\n", + __func__); + BUG(); } } } else { @@ -7592,9 +7602,9 @@ aggregate: * void. */ -static void s2io_link(struct s2io_nic * sp, int link) +static void s2io_link(struct s2io_nic *sp, int link) { - struct net_device *dev = (struct net_device *) sp->dev; + struct net_device *dev = (struct net_device *)sp->dev; if (link != sp->last_link_state) { init_tti(sp, link); @@ -7602,15 +7612,16 @@ static void s2io_link(struct s2io_nic * sp, int link) DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name); s2io_stop_all_tx_queue(sp); netif_carrier_off(dev); - if(sp->mac_control.stats_info->sw_stat.link_up_cnt) - sp->mac_control.stats_info->sw_stat.link_up_time = - jiffies - sp->start_time; + if (sp->mac_control.stats_info->sw_stat.link_up_cnt) + sp->mac_control.stats_info->sw_stat. + link_up_time = jiffies - sp->start_time; sp->mac_control.stats_info->sw_stat.link_down_cnt++; } else { DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name); if (sp->mac_control.stats_info->sw_stat.link_down_cnt) - sp->mac_control.stats_info->sw_stat.link_down_time = - jiffies - sp->start_time; + sp->mac_control.stats_info-> + sw_stat.link_down_time = + jiffies - sp->start_time; sp->mac_control.stats_info->sw_stat.link_up_cnt++; netif_carrier_on(dev); s2io_wake_all_tx_queue(sp); @@ -7631,7 +7642,7 @@ static void s2io_link(struct s2io_nic * sp, int link) * void */ -static void s2io_init_pci(struct s2io_nic * sp) +static void s2io_init_pci(struct s2io_nic *sp) { u16 pci_cmd = 0, pcix_cmd = 0; @@ -7651,12 +7662,11 @@ static void s2io_init_pci(struct s2io_nic * sp) } static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, - u8 *dev_multiq) + u8 *dev_multiq) { - if ((tx_fifo_num > MAX_TX_FIFOS) || - (tx_fifo_num < 1)) { + if ((tx_fifo_num > MAX_TX_FIFOS) || (tx_fifo_num < 1)) { DBG_PRINT(ERR_DBG, "s2io: Requested number of tx fifos " - "(%d) not supported\n", tx_fifo_num); + "(%d) not supported\n", tx_fifo_num); if (tx_fifo_num < 1) tx_fifo_num = 1; @@ -7673,24 +7683,24 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, if (tx_steering_type && (1 == tx_fifo_num)) { if (tx_steering_type != TX_DEFAULT_STEERING) DBG_PRINT(ERR_DBG, - "s2io: Tx steering is not supported with " - "one fifo. Disabling Tx steering.\n"); + "s2io: Tx steering is not supported with " + "one fifo. Disabling Tx steering.\n"); tx_steering_type = NO_STEERING; } if ((tx_steering_type < NO_STEERING) || - (tx_steering_type > TX_DEFAULT_STEERING)) { - DBG_PRINT(ERR_DBG, "s2io: Requested transmit steering not " - "supported\n"); + (tx_steering_type > TX_DEFAULT_STEERING)) { + DBG_PRINT(ERR_DBG, + "s2io: Requested transmit steering not supported\n"); DBG_PRINT(ERR_DBG, "s2io: Disabling transmit steering\n"); tx_steering_type = NO_STEERING; } if (rx_ring_num > MAX_RX_RINGS) { - DBG_PRINT(ERR_DBG, "s2io: Requested number of rx rings not " - "supported\n"); + DBG_PRINT(ERR_DBG, + "s2io: Requested number of rx rings not supported\n"); DBG_PRINT(ERR_DBG, "s2io: Default to %d rx rings\n", - MAX_RX_RINGS); + MAX_RX_RINGS); rx_ring_num = MAX_RX_RINGS; } @@ -7701,10 +7711,10 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, } if ((*dev_intr_type == MSI_X) && - ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && - (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { + ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && + (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. " - "Defaulting to INTA\n"); + "Defaulting to INTA\n"); *dev_intr_type = INTA; } @@ -7743,8 +7753,8 @@ static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring) writeq(val64, &bar0->rts_ds_mem_ctrl); return wait_for_cmd_complete(&bar0->rts_ds_mem_ctrl, - RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED, - S2IO_BIT_RESET); + RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED, + S2IO_BIT_RESET); } static const struct net_device_ops s2io_netdev_ops = { @@ -7800,7 +7810,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (ret) return ret; - if ((ret = pci_enable_device(pdev))) { + ret = pci_enable_device(pdev); + if (ret) { DBG_PRINT(ERR_DBG, "s2io_init_nic: pci_enable_device failed\n"); return ret; @@ -7809,11 +7820,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n"); dma_flag = true; - if (pci_set_consistent_dma_mask - (pdev, DMA_BIT_MASK(64))) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { DBG_PRINT(ERR_DBG, - "Unable to obtain 64bit DMA for \ - consistent allocations\n"); + "Unable to obtain 64bit DMA " + "for consistent allocations\n"); pci_disable_device(pdev); return -ENOMEM; } @@ -7823,8 +7833,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) pci_disable_device(pdev); return -ENOMEM; } - if ((ret = pci_request_regions(pdev, s2io_driver_name))) { - DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", __func__, ret); + ret = pci_request_regions(pdev, s2io_driver_name); + if (ret) { + DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", + __func__, ret); pci_disable_device(pdev); return -ENODEV; } @@ -7858,7 +7870,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->config.intr_type = dev_intr_type; if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || - (pdev->device == PCI_DEVICE_ID_HERC_UNI)) + (pdev->device == PCI_DEVICE_ID_HERC_UNI)) sp->device_type = XFRAME_II_DEVICE; else sp->device_type = XFRAME_I_DEVICE; @@ -7889,16 +7901,16 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Initialize the fifos used for tx steering */ if (config->tx_fifo_num < 5) { - if (config->tx_fifo_num == 1) - sp->total_tcp_fifos = 1; - else - sp->total_tcp_fifos = config->tx_fifo_num - 1; - sp->udp_fifo_idx = config->tx_fifo_num - 1; - sp->total_udp_fifos = 1; - sp->other_fifo_idx = sp->total_tcp_fifos - 1; + if (config->tx_fifo_num == 1) + sp->total_tcp_fifos = 1; + else + sp->total_tcp_fifos = config->tx_fifo_num - 1; + sp->udp_fifo_idx = config->tx_fifo_num - 1; + sp->total_udp_fifos = 1; + sp->other_fifo_idx = sp->total_tcp_fifos - 1; } else { sp->total_tcp_fifos = (tx_fifo_num - FIFO_UDP_MAX_NUM - - FIFO_OTHER_MAX_NUM); + FIFO_OTHER_MAX_NUM); sp->udp_fifo_idx = sp->total_tcp_fifos; sp->total_udp_fifos = FIFO_UDP_MAX_NUM; sp->other_fifo_idx = sp->udp_fifo_idx + FIFO_UDP_MAX_NUM; @@ -7964,8 +7976,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* initialize the shared memory used by the NIC and the host */ if (init_shared_mem(sp)) { - DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", - dev->name); + DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", dev->name); ret = -ENOMEM; goto mem_alloc_failed; } @@ -7987,12 +7998,13 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } dev->irq = pdev->irq; - dev->base_addr = (unsigned long) sp->bar0; + dev->base_addr = (unsigned long)sp->bar0; /* Initializing the BAR1 address as the start of the FIFO pointer. */ for (j = 0; j < MAX_TX_FIFOS; j++) { - mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *) - (sp->bar1 + (j * 0x00020000)); + mac_control->tx_FIFO_start[j] = + (struct TxFIFO_element __iomem *) + (sp->bar1 + (j * 0x00020000)); } /* Driver entry points */ @@ -8046,7 +8058,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (ret) { DBG_PRINT(ERR_DBG, - "s2io: MSI-X requested but failed to enable\n"); + "s2io: MSI-X requested but failed to enable\n"); sp->config.intr_type = INTA; } } @@ -8077,12 +8089,13 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) */ bar0 = sp->bar0; val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(0 + S2IO_MAC_ADDR_START_OFFSET); + RMAC_ADDR_CMD_MEM_OFFSET(0 + S2IO_MAC_ADDR_START_OFFSET); writeq(val64, &bar0->rmac_addr_cmd_mem); wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET); tmp64 = readq(&bar0->rmac_addr_data0_mem); - mac_down = (u32) tmp64; + mac_down = (u32)tmp64; mac_up = (u32) (tmp64 >> 32); sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up); @@ -8113,10 +8126,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Configure MSIX vector for number of rings configured plus one */ if ((sp->device_type == XFRAME_II_DEVICE) && - (config->intr_type == MSI_X)) + (config->intr_type == MSI_X)) sp->num_entries = config->rx_ring_num + 1; - /* Store the values of the MSIX table in the s2io_nic structure */ + /* Store the values of the MSIX table in the s2io_nic structure */ store_xmsi_data(sp); /* reset Nic and bring it to known state */ s2io_reset(sp); @@ -8144,7 +8157,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) val64 |= 0x0000800000000000ULL; writeq(val64, &bar0->gpio_control); val64 = 0x0411040400000000ULL; - writeq(val64, (void __iomem *) bar0 + 0x2700); + writeq(val64, (void __iomem *)bar0 + 0x2700); val64 = readq(&bar0->gpio_control); } @@ -8157,7 +8170,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } s2io_vpd_read(sp); DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n"); - DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name, + DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n", dev->name, sp->product_name, pdev->revision); DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, s2io_driver_version); @@ -8172,15 +8185,15 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto set_swap_failed; } } - switch(sp->rxd_mode) { - case RXD_MODE_1: - DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n", - dev->name); - break; - case RXD_MODE_3B: - DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n", - dev->name); - break; + switch (sp->rxd_mode) { + case RXD_MODE_1: + DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n", + dev->name); + break; + case RXD_MODE_3B: + DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n", + dev->name); + break; } switch (sp->config.napi) { @@ -8193,18 +8206,18 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name, - sp->config.tx_fifo_num); + sp->config.tx_fifo_num); DBG_PRINT(ERR_DBG, "%s: Using %d Rx ring(s)\n", dev->name, sp->config.rx_ring_num); - switch(sp->config.intr_type) { - case INTA: - DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name); - break; - case MSI_X: - DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name); - break; + switch (sp->config.intr_type) { + case INTA: + DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name); + break; + case MSI_X: + DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name); + break; } if (sp->config.multiq) { for (i = 0; i < sp->config.tx_fifo_num; i++) { @@ -8213,31 +8226,34 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) fifo->multiq = config->multiq; } DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n", - dev->name); + dev->name); } else DBG_PRINT(ERR_DBG, "%s: Multiqueue support disabled\n", - dev->name); + dev->name); switch (sp->config.tx_steering_type) { case NO_STEERING: - DBG_PRINT(ERR_DBG, "%s: No steering enabled for" - " transmit\n", dev->name); - break; + DBG_PRINT(ERR_DBG, "%s: No steering enabled for transmit\n", + dev->name); + break; case TX_PRIORITY_STEERING: - DBG_PRINT(ERR_DBG, "%s: Priority steering enabled for" - " transmit\n", dev->name); + DBG_PRINT(ERR_DBG, + "%s: Priority steering enabled for transmit\n", + dev->name); break; case TX_DEFAULT_STEERING: - DBG_PRINT(ERR_DBG, "%s: Default steering enabled for" - " transmit\n", dev->name); + DBG_PRINT(ERR_DBG, + "%s: Default steering enabled for transmit\n", + dev->name); } if (sp->lro) DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n", dev->name); if (ufo) - DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)" - " enabled\n", dev->name); + DBG_PRINT(ERR_DBG, + "%s: UDP Fragmentation Offload(UFO) enabled\n", + dev->name); /* Initialize device name */ sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name); @@ -8255,13 +8271,13 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) return 0; - register_failed: - set_swap_failed: +register_failed: +set_swap_failed: iounmap(sp->bar1); - bar1_remap_failed: +bar1_remap_failed: iounmap(sp->bar0); - bar0_remap_failed: - mem_alloc_failed: +bar0_remap_failed: +mem_alloc_failed: free_shared_mem(sp); pci_disable_device(pdev); pci_release_regions(pdev); @@ -8283,7 +8299,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) static void __devexit s2io_rem_nic(struct pci_dev *pdev) { struct net_device *dev = - (struct net_device *) pci_get_drvdata(pdev); + (struct net_device *)pci_get_drvdata(pdev); struct s2io_nic *sp; if (dev == NULL) { @@ -8331,28 +8347,28 @@ module_init(s2io_starter); module_exit(s2io_closer); static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, - struct tcphdr **tcp, struct RxD_t *rxdp, - struct s2io_nic *sp) + struct tcphdr **tcp, struct RxD_t *rxdp, + struct s2io_nic *sp) { int ip_off; u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len; if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) { - DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n", + DBG_PRINT(INIT_DBG, + "%s: Non-TCP frames not supported for LRO\n", __func__); return -1; } /* Checking for DIX type or DIX type with VLAN */ - if ((l2_type == 0) - || (l2_type == 4)) { + if ((l2_type == 0) || (l2_type == 4)) { ip_off = HEADER_ETHERNET_II_802_3_SIZE; /* * If vlan stripping is disabled and the frame is VLAN tagged, * shift the offset by the VLAN header size bytes. */ if ((!sp->vlan_strip_flag) && - (rxdp->Control_1 & RXD_FRAME_VLAN_TAG)) + (rxdp->Control_1 & RXD_FRAME_VLAN_TAG)) ip_off += HEADER_VLAN_SIZE; } else { /* LLC, SNAP etc are considered non-mergeable */ @@ -8370,22 +8386,25 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, static int check_for_socket_match(struct lro *lro, struct iphdr *ip, struct tcphdr *tcp) { - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); - if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) || - (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest)) + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); + if ((lro->iph->saddr != ip->saddr) || + (lro->iph->daddr != ip->daddr) || + (lro->tcph->source != tcp->source) || + (lro->tcph->dest != tcp->dest)) return -1; return 0; } static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp) { - return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2)); + return ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2); } static void initiate_new_session(struct lro *lro, u8 *l2h, - struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len, u16 vlan_tag) + struct iphdr *ip, struct tcphdr *tcp, + u32 tcp_pyld_len, u16 vlan_tag) { - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); lro->l2h = l2h; lro->iph = ip; lro->tcph = tcp; @@ -8396,9 +8415,9 @@ static void initiate_new_session(struct lro *lro, u8 *l2h, lro->frags_len = 0; lro->vlan_tag = vlan_tag; /* - * check if we saw TCP timestamp. Other consistency checks have - * already been done. - */ + * Check if we saw TCP timestamp. + * Other consistency checks have already been done. + */ if (tcp->doff == 8) { __be32 *ptr; ptr = (__be32 *)(tcp+1); @@ -8415,7 +8434,7 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) struct tcphdr *tcp = lro->tcph; __sum16 nchk; struct stat_block *statinfo = sp->mac_control.stats_info; - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); /* Update L3 header */ ip->tot_len = htons(lro->total_len); @@ -8441,9 +8460,9 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) } static void aggregate_new_rx(struct lro *lro, struct iphdr *ip, - struct tcphdr *tcp, u32 l4_pyld) + struct tcphdr *tcp, u32 l4_pyld) { - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); lro->total_len += l4_pyld; lro->frags_len += l4_pyld; lro->tcp_next_seq += l4_pyld; @@ -8467,7 +8486,7 @@ static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip, { u8 *ptr; - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); if (!tcp_pyld_len) { /* Runt frame or a pure ack */ @@ -8482,8 +8501,9 @@ static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip, return -1; /* If we see ECE or CWR flags in TCP header, packet is not mergeable */ - if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin || - tcp->ece || tcp->cwr || !tcp->ack) { + if (tcp->urg || tcp->psh || tcp->rst || + tcp->syn || tcp->fin || + tcp->ece || tcp->cwr || !tcp->ack) { /* * Currently recognize only the ack control word and * any other control field being set would result in @@ -8519,27 +8539,26 @@ static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip, return 0; } -static int -s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp, - u32 *tcp_len, struct lro **lro, struct RxD_t *rxdp, - struct s2io_nic *sp) +static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, + u8 **tcp, u32 *tcp_len, struct lro **lro, + struct RxD_t *rxdp, struct s2io_nic *sp) { struct iphdr *ip; struct tcphdr *tcph; int ret = 0, i; u16 vlan_tag = 0; - if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp, - rxdp, sp))) { - DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n", - ip->saddr, ip->daddr); - } else + ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp, + rxdp, sp); + if (ret) return ret; + DBG_PRINT(INFO_DBG, "IP Saddr: %x Daddr: %x\n", ip->saddr, ip->daddr); + vlan_tag = RXD_GET_VLAN_TAG(rxdp->Control_2); tcph = (struct tcphdr *)*tcp; *tcp_len = get_l4_pyld_length(ip, tcph); - for (i=0; ilro0_n[i]; if (l_lro->in_use) { if (check_for_socket_match(l_lro, ip, tcph)) @@ -8554,12 +8573,13 @@ s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp, ntohl(tcph->seq)); sp->mac_control.stats_info-> - sw_stat.outof_sequence_pkts++; + sw_stat.outof_sequence_pkts++; ret = 2; break; } - if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len)) + if (!verify_l3_l4_lro_capable(l_lro, ip, tcph, + *tcp_len)) ret = 1; /* Aggregate */ else ret = 2; /* Flush both */ @@ -8573,11 +8593,10 @@ s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp, * don't create new LRO session. Just send this * packet up. */ - if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) { + if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) return 5; - } - for (i=0; ilro0_n[i]; if (!(l_lro->in_use)) { *lro = l_lro; @@ -8588,31 +8607,30 @@ s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp, } if (ret == 0) { /* sessions exceeded */ - DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n", + DBG_PRINT(INFO_DBG, "%s:All LRO sessions already in use\n", __func__); *lro = NULL; return ret; } switch (ret) { - case 3: - initiate_new_session(*lro, buffer, ip, tcph, *tcp_len, - vlan_tag); - break; - case 2: + case 3: + initiate_new_session(*lro, buffer, ip, tcph, *tcp_len, + vlan_tag); + break; + case 2: + update_L3L4_header(sp, *lro); + break; + case 1: + aggregate_new_rx(*lro, ip, tcph, *tcp_len); + if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) { update_L3L4_header(sp, *lro); - break; - case 1: - aggregate_new_rx(*lro, ip, tcph, *tcp_len); - if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) { - update_L3L4_header(sp, *lro); - ret = 4; /* Flush the LRO */ - } - break; - default: - DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n", - __func__); - break; + ret = 4; /* Flush the LRO */ + } + break; + default: + DBG_PRINT(ERR_DBG, "%s:Dont know, can't say!!\n", __func__); + break; } return ret; @@ -8631,8 +8649,7 @@ static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag) struct s2io_nic *sp = netdev_priv(dev); skb->protocol = eth_type_trans(skb, dev); - if (sp->vlgrp && vlan_tag - && (sp->vlan_strip_flag)) { + if (sp->vlgrp && vlan_tag && (sp->vlan_strip_flag)) { /* Queueing the vlan frame to the upper layer */ if (sp->config.napi) vlan_hwaccel_receive_skb(skb, sp->vlgrp, vlan_tag); @@ -8647,8 +8664,7 @@ static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag) } static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, - struct sk_buff *skb, - u32 tcp_len) + struct sk_buff *skb, u32 tcp_len) { struct sk_buff *first = lro->parent; @@ -8674,7 +8690,7 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, * this device has been detected. */ static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) + pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); struct s2io_nic *sp = netdev_priv(netdev); -- cgit v0.10.2 From 6cef2b8eb73f1a8fd7c0ed528091ddc406fef950 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:45 +0000 Subject: s2io.c: convert printks to pr_ Fixed trivial typo as well Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 003dd8c..2805edd 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -54,6 +54,8 @@ * Possible values '1' for enable and '0' for disable. Default is '0' ************************************************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -5547,8 +5549,7 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) if ((sp->device_type == XFRAME_I_DEVICE) && ((subid & 0xFF) < 0x07)) { val64 = readq(&bar0->adapter_control); if (!(val64 & ADAPTER_CNTL_EN)) { - printk(KERN_ERR - "Adapter Link down, cannot blink LED\n"); + pr_err("Adapter Link down, cannot blink LED\n"); return -EFAULT; } } @@ -7130,8 +7131,7 @@ static int s2io_add_isr(struct s2io_nic *sp) } } if (!err) { - printk(KERN_INFO "MSI-X-RX %d entries enabled\n", - --msix_rx_cnt); + pr_info("MSI-X-RX %d entries enabled\n", --msix_rx_cnt); DBG_PRINT(INFO_DBG, "MSI-X-TX entries enabled" " through alarm vector\n"); } @@ -8724,8 +8724,7 @@ static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev) struct s2io_nic *sp = netdev_priv(netdev); if (pci_enable_device(pdev)) { - printk(KERN_ERR "s2io: " - "Cannot re-enable PCI device after reset.\n"); + pr_err("Cannot re-enable PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; } @@ -8749,15 +8748,13 @@ static void s2io_io_resume(struct pci_dev *pdev) if (netif_running(netdev)) { if (s2io_card_up(sp)) { - printk(KERN_ERR "s2io: " - "Can't bring device back up after reset.\n"); + pr_err("Can't bring device back up after reset.\n"); return; } if (s2io_set_mac_addr(netdev, netdev->dev_addr) == FAILURE) { s2io_card_down(sp); - printk(KERN_ERR "s2io: " - "Can't resetore mac addr after reset.\n"); + pr_err("Can't restore mac addr after reset.\n"); return; } } -- cgit v0.10.2 From a2a20aef44da92b1c3b8c86ea069117dc3bc8bd6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:46 +0000 Subject: s2io.c: fix spelling explaination Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 2805edd..4897f04 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -25,7 +25,7 @@ * Christopher Hellwig : Some more 2.6 specific issues in the driver. * * The module loadable parameters that are supported by the driver and a brief - * explaination of all the variables. + * explanation of all the variables. * * rx_ring_num : This can be used to program the number of receive rings used * in the driver. -- cgit v0.10.2 From ffb5df6ce776a05eec1fbe4876cc6603c6336140 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:47 +0000 Subject: s2io.c: Standardize statistics accessors Regularize the declaration and uses of struct config_param *config = &sp->config; struct mac_info *mac_control = &sp->mac_control; and use struct stat_block *stats = mac_control->stats_info; struct swStat *swstats = &stats->sw_stat; struct xpakStat *xstats = &stats->xpak_stat; and convert the longish uses like nic->mac_control.stats_info->sw_stat. to swstats-> etc. This also makes the statistics code marginally smaller and presumably faster. Old: $ size s2io.o text data bss dec hex filename 114289 516 33360 148165 242c5 s2io.o New: $ size s2io.o text data bss dec hex filename 114097 516 33360 147973 24205 s2io.o Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 4897f04..06223df 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -363,8 +363,8 @@ static void s2io_vlan_rx_register(struct net_device *dev, int i; struct s2io_nic *nic = netdev_priv(dev); unsigned long flags[MAX_TX_FIFOS]; - struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; for (i = 0; i < config->tx_fifo_num; i++) { struct fifo_info *fifo = &mac_control->fifos[i]; @@ -387,8 +387,8 @@ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) int i; struct s2io_nic *nic = netdev_priv(dev); unsigned long flags[MAX_TX_FIFOS]; - struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; for (i = 0; i < config->tx_fifo_num; i++) { struct fifo_info *fifo = &mac_control->fifos[i]; @@ -640,14 +640,10 @@ static int init_shared_mem(struct s2io_nic *nic) struct net_device *dev = nic->dev; unsigned long tmp; struct buffAdd *ba; - - struct mac_info *mac_control; - struct config_param *config; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; unsigned long long mem_allocated = 0; - mac_control = &nic->mac_control; - config = &nic->config; - /* Allocation and initialization of TXDLs in FIFOs */ size = 0; for (i = 0; i < config->tx_fifo_num; i++) { @@ -949,19 +945,23 @@ static void free_shared_mem(struct s2io_nic *nic) int i, j, blk_cnt, size; void *tmp_v_addr; dma_addr_t tmp_p_addr; - struct mac_info *mac_control; - struct config_param *config; int lst_size, lst_per_page; struct net_device *dev; int page_num = 0; + struct config_param *config; + struct mac_info *mac_control; + struct stat_block *stats; + struct swStat *swstats; if (!nic) return; dev = nic->dev; - mac_control = &nic->mac_control; config = &nic->config; + mac_control = &nic->mac_control; + stats = mac_control->stats_info; + swstats = &stats->sw_stat; lst_size = sizeof(struct TxD) * config->max_txds; lst_per_page = PAGE_SIZE / lst_size; @@ -984,8 +984,7 @@ static void free_shared_mem(struct s2io_nic *nic) pci_free_consistent(nic->pdev, PAGE_SIZE, fli->list_virt_addr, fli->list_phy_addr); - nic->mac_control.stats_info->sw_stat.mem_freed - += PAGE_SIZE; + swstats->mem_freed += PAGE_SIZE; } /* If we got a zero DMA address during allocation, * free the page now @@ -999,12 +998,10 @@ static void free_shared_mem(struct s2io_nic *nic) dev->name); DBG_PRINT(INIT_DBG, "Virtual address %p\n", mac_control->zerodma_virt_addr); - nic->mac_control.stats_info->sw_stat.mem_freed - += PAGE_SIZE; + swstats->mem_freed += PAGE_SIZE; } kfree(fifo->list_info); - nic->mac_control.stats_info->sw_stat.mem_freed += - nic->config.tx_cfg[i].fifo_len * + swstats->mem_freed += nic->config.tx_cfg[i].fifo_len * sizeof(struct list_info_hold); } @@ -1020,10 +1017,10 @@ static void free_shared_mem(struct s2io_nic *nic) break; pci_free_consistent(nic->pdev, size, tmp_v_addr, tmp_p_addr); - nic->mac_control.stats_info->sw_stat.mem_freed += size; + swstats->mem_freed += size; kfree(ring->rx_blocks[j].rxds); - nic->mac_control.stats_info->sw_stat.mem_freed += - sizeof(struct rxd_info) * rxd_count[nic->rxd_mode]; + swstats->mem_freed += sizeof(struct rxd_info) * + rxd_count[nic->rxd_mode]; } } @@ -1042,21 +1039,20 @@ static void free_shared_mem(struct s2io_nic *nic) while (k != rxd_count[nic->rxd_mode]) { struct buffAdd *ba = &ring->ba[j][k]; kfree(ba->ba_0_org); - nic->mac_control.stats_info->sw_stat.\ - mem_freed += (BUF0_LEN + ALIGN_SIZE); + swstats->mem_freed += + BUF0_LEN + ALIGN_SIZE; kfree(ba->ba_1_org); - nic->mac_control.stats_info->sw_stat.\ - mem_freed += (BUF1_LEN + ALIGN_SIZE); + swstats->mem_freed += + BUF1_LEN + ALIGN_SIZE; k++; } kfree(ring->ba[j]); - nic->mac_control.stats_info->sw_stat.mem_freed += - (sizeof(struct buffAdd) * - (rxd_count[nic->rxd_mode] + 1)); + swstats->mem_freed += sizeof(struct buffAdd) * + (rxd_count[nic->rxd_mode] + 1); } kfree(ring->ba); - nic->mac_control.stats_info->sw_stat.mem_freed += - (sizeof(struct buffAdd *) * blk_cnt); + swstats->mem_freed += sizeof(struct buffAdd *) * + blk_cnt; } } @@ -1065,15 +1061,14 @@ static void free_shared_mem(struct s2io_nic *nic) struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; if (fifo->ufo_in_band_v) { - nic->mac_control.stats_info->sw_stat.mem_freed - += (tx_cfg->fifo_len * sizeof(u64)); + swstats->mem_freed += tx_cfg->fifo_len * + sizeof(u64); kfree(fifo->ufo_in_band_v); } } if (mac_control->stats_mem) { - nic->mac_control.stats_info->sw_stat.mem_freed += - mac_control->stats_mem_sz; + swstats->mem_freed += mac_control->stats_mem_sz; pci_free_consistent(nic->pdev, mac_control->stats_mem_sz, mac_control->stats_mem, @@ -1190,9 +1185,7 @@ static int init_tti(struct s2io_nic *nic, int link) struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0; int i; - struct config_param *config; - - config = &nic->config; + struct config_param *config = &nic->config; for (i = 0; i < config->tx_fifo_num; i++) { /* @@ -1271,14 +1264,11 @@ static int init_nic(struct s2io_nic *nic) void __iomem *add; u32 time; int i, j; - struct mac_info *mac_control; - struct config_param *config; int dtx_cnt = 0; unsigned long long mem_share; int mem_size; - - mac_control = &nic->mac_control; - config = &nic->config; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; /* to set the swapper controle on the card */ if (s2io_set_swapper(nic)) { @@ -2290,11 +2280,8 @@ static int start_nic(struct s2io_nic *nic) struct net_device *dev = nic->dev; register u64 val64 = 0; u16 subid, i; - struct mac_info *mac_control; - struct config_param *config; - - mac_control = &nic->mac_control; - config = &nic->config; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; /* PRC Initialization and configuration */ for (i = 0; i < config->rx_ring_num; i++) { @@ -2446,12 +2433,11 @@ static void free_tx_buffers(struct s2io_nic *nic) struct sk_buff *skb; struct TxD *txdp; int i, j; - struct mac_info *mac_control; - struct config_param *config; int cnt = 0; - - mac_control = &nic->mac_control; - config = &nic->config; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; + struct stat_block *stats = mac_control->stats_info; + struct swStat *swstats = &stats->sw_stat; for (i = 0; i < config->tx_fifo_num; i++) { struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; @@ -2463,8 +2449,7 @@ static void free_tx_buffers(struct s2io_nic *nic) txdp = (struct TxD *)fifo->list_info[j].list_virt_addr; skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j); if (skb) { - nic->mac_control.stats_info->sw_stat.mem_freed - += skb->truesize; + swstats->mem_freed += skb->truesize; dev_kfree_skb(skb); cnt++; } @@ -2493,11 +2478,6 @@ static void stop_nic(struct s2io_nic *nic) struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0; u16 interruptible; - struct mac_info *mac_control; - struct config_param *config; - - mac_control = &nic->mac_control; - config = &nic->config; /* Disable all interrupts */ en_dis_err_alarms(nic, ENA_ALL_INTRS, DISABLE_INTRS); @@ -2548,7 +2528,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, int rxd_index = 0; struct RxD1 *rxdp1; struct RxD3 *rxdp3; - struct swStat *stats = &ring->nic->mac_control.stats_info->sw_stat; + struct swStat *swstats = &ring->nic->mac_control.stats_info->sw_stat; alloc_cnt = ring->pkt_cnt - ring->rx_bufs_left; @@ -2609,11 +2589,11 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, wmb(); first_rxdp->Control_1 |= RXD_OWN_XENA; } - stats->mem_alloc_fail_cnt++; + swstats->mem_alloc_fail_cnt++; return -ENOMEM ; } - stats->mem_allocated += skb->truesize; + swstats->mem_allocated += skb->truesize; if (ring->rxd_mode == RXD_MODE_1) { /* 1 buffer mode - normal operation mode */ @@ -2742,8 +2722,8 @@ end: return SUCCESS; pci_map_failed: - stats->pci_map_fail_cnt++; - stats->mem_freed += skb->truesize; + swstats->pci_map_fail_cnt++; + swstats->mem_freed += skb->truesize; dev_kfree_skb_irq(skb); return -ENOMEM; } @@ -2754,12 +2734,13 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) int j; struct sk_buff *skb; struct RxD_t *rxdp; - struct mac_info *mac_control; struct buffAdd *ba; struct RxD1 *rxdp1; struct RxD3 *rxdp3; + struct mac_info *mac_control = &sp->mac_control; + struct stat_block *stats = mac_control->stats_info; + struct swStat *swstats = &stats->sw_stat; - mac_control = &sp->mac_control; for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) { rxdp = mac_control->rings[ring_no]. rx_blocks[blk].rxds[j].virt_addr; @@ -2792,7 +2773,7 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) PCI_DMA_FROMDEVICE); memset(rxdp, 0, sizeof(struct RxD3)); } - sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; + swstats->mem_freed += skb->truesize; dev_kfree_skb(skb); mac_control->rings[ring_no].rx_bufs_left -= 1; } @@ -2811,11 +2792,8 @@ static void free_rx_buffers(struct s2io_nic *sp) { struct net_device *dev = sp->dev; int i, blk = 0, buf_cnt = 0; - struct mac_info *mac_control; - struct config_param *config; - - mac_control = &sp->mac_control; - config = &sp->config; + struct config_param *config = &sp->config; + struct mac_info *mac_control = &sp->mac_control; for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i]; @@ -2859,8 +2837,6 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) { struct ring_info *ring = container_of(napi, struct ring_info, napi); struct net_device *dev = ring->dev; - struct config_param *config; - struct mac_info *mac_control; int pkts_processed = 0; u8 __iomem *addr = NULL; u8 val8 = 0; @@ -2868,9 +2844,6 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) struct XENA_dev_config __iomem *bar0 = nic->bar0; int budget_org = budget; - config = &nic->config; - mac_control = &nic->mac_control; - if (unlikely(!is_s2io_card_up(nic))) return 0; @@ -2892,15 +2865,12 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) static int s2io_poll_inta(struct napi_struct *napi, int budget) { struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); - struct config_param *config; - struct mac_info *mac_control; int pkts_processed = 0; int ring_pkts_processed, i; struct XENA_dev_config __iomem *bar0 = nic->bar0; int budget_org = budget; - - config = &nic->config; - mac_control = &nic->mac_control; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; if (unlikely(!is_s2io_card_up(nic))) return 0; @@ -2936,20 +2906,17 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) static void s2io_netpoll(struct net_device *dev) { struct s2io_nic *nic = netdev_priv(dev); - struct mac_info *mac_control; - struct config_param *config; struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 val64 = 0xFFFFFFFFFFFFFFFFULL; int i; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; if (pci_channel_offline(nic->pdev)) return; disable_irq(dev->irq); - mac_control = &nic->mac_control; - config = &nic->config; - writeq(val64, &bar0->rx_traffic_int); writeq(val64, &bar0->tx_traffic_int); @@ -3110,6 +3077,8 @@ static void tx_intr_handler(struct fifo_info *fifo_data) int pkt_cnt = 0; unsigned long flags = 0; u8 err_mask; + struct stat_block *stats = nic->mac_control.stats_info; + struct swStat *swstats = &stats->sw_stat; if (!spin_trylock_irqsave(&fifo_data->tx_lock, flags)) return; @@ -3126,36 +3095,30 @@ static void tx_intr_handler(struct fifo_info *fifo_data) unsigned long long err; err = txdlp->Control_1 & TXD_T_CODE; if (err & 0x1) { - nic->mac_control.stats_info->sw_stat. - parity_err_cnt++; + swstats->parity_err_cnt++; } /* update t_code statistics */ err_mask = err >> 48; switch (err_mask) { case 2: - nic->mac_control.stats_info->sw_stat. - tx_buf_abort_cnt++; + swstats->tx_buf_abort_cnt++; break; case 3: - nic->mac_control.stats_info->sw_stat. - tx_desc_abort_cnt++; + swstats->tx_desc_abort_cnt++; break; case 7: - nic->mac_control.stats_info->sw_stat. - tx_parity_err_cnt++; + swstats->tx_parity_err_cnt++; break; case 10: - nic->mac_control.stats_info->sw_stat. - tx_link_loss_cnt++; + swstats->tx_link_loss_cnt++; break; case 15: - nic->mac_control.stats_info->sw_stat. - tx_list_proc_err_cnt++; + swstats->tx_list_proc_err_cnt++; break; } } @@ -3171,7 +3134,7 @@ static void tx_intr_handler(struct fifo_info *fifo_data) /* Updating the statistics block */ nic->dev->stats.tx_bytes += skb->len; - nic->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; + swstats->mem_freed += skb->truesize; dev_kfree_skb_irq(skb); get_info.offset++; @@ -3350,7 +3313,8 @@ static void s2io_updt_xpak_counter(struct net_device *dev) u64 addr = 0x0; struct s2io_nic *sp = netdev_priv(dev); - struct stat_block *stat_info = sp->mac_control.stats_info; + struct stat_block *stats = sp->mac_control.stats_info; + struct xpakStat *xstats = &stats->xpak_stat; /* Check the communication with the MDIO slave */ addr = MDIO_CTRL1; @@ -3382,30 +3346,30 @@ static void s2io_updt_xpak_counter(struct net_device *dev) flag = CHECKBIT(val64, 0x7); type = 1; - s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high, - &stat_info->xpak_stat.xpak_regs_stat, + s2io_chk_xpak_counter(&xstats->alarm_transceiver_temp_high, + &xstats->xpak_regs_stat, 0x0, flag, type); if (CHECKBIT(val64, 0x6)) - stat_info->xpak_stat.alarm_transceiver_temp_low++; + xstats->alarm_transceiver_temp_low++; flag = CHECKBIT(val64, 0x3); type = 2; - s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high, - &stat_info->xpak_stat.xpak_regs_stat, + s2io_chk_xpak_counter(&xstats->alarm_laser_bias_current_high, + &xstats->xpak_regs_stat, 0x2, flag, type); if (CHECKBIT(val64, 0x2)) - stat_info->xpak_stat.alarm_laser_bias_current_low++; + xstats->alarm_laser_bias_current_low++; flag = CHECKBIT(val64, 0x1); type = 3; - s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high, - &stat_info->xpak_stat.xpak_regs_stat, + s2io_chk_xpak_counter(&xstats->alarm_laser_output_power_high, + &xstats->xpak_regs_stat, 0x4, flag, type); if (CHECKBIT(val64, 0x0)) - stat_info->xpak_stat.alarm_laser_output_power_low++; + xstats->alarm_laser_output_power_low++; /* Reading the Warning flags */ addr = 0xA074; @@ -3413,22 +3377,22 @@ static void s2io_updt_xpak_counter(struct net_device *dev) val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); if (CHECKBIT(val64, 0x7)) - stat_info->xpak_stat.warn_transceiver_temp_high++; + xstats->warn_transceiver_temp_high++; if (CHECKBIT(val64, 0x6)) - stat_info->xpak_stat.warn_transceiver_temp_low++; + xstats->warn_transceiver_temp_low++; if (CHECKBIT(val64, 0x3)) - stat_info->xpak_stat.warn_laser_bias_current_high++; + xstats->warn_laser_bias_current_high++; if (CHECKBIT(val64, 0x2)) - stat_info->xpak_stat.warn_laser_bias_current_low++; + xstats->warn_laser_bias_current_low++; if (CHECKBIT(val64, 0x1)) - stat_info->xpak_stat.warn_laser_output_power_high++; + xstats->warn_laser_output_power_high++; if (CHECKBIT(val64, 0x0)) - stat_info->xpak_stat.warn_laser_output_power_low++; + xstats->warn_laser_output_power_low++; } /** @@ -3514,6 +3478,8 @@ static void s2io_reset(struct s2io_nic *sp) u16 val16; unsigned long long up_cnt, down_cnt, up_time, down_time, reset_cnt; unsigned long long mem_alloc_cnt, mem_free_cnt, watchdog_cnt; + struct stat_block *stats; + struct swStat *swstats; DBG_PRINT(INIT_DBG, "%s - Resetting XFrame card %s\n", __func__, sp->dev->name); @@ -3567,25 +3533,30 @@ static void s2io_reset(struct s2io_nic *sp) /* Reset device statistics maintained by OS */ memset(&sp->stats, 0, sizeof(struct net_device_stats)); - up_cnt = sp->mac_control.stats_info->sw_stat.link_up_cnt; - down_cnt = sp->mac_control.stats_info->sw_stat.link_down_cnt; - up_time = sp->mac_control.stats_info->sw_stat.link_up_time; - down_time = sp->mac_control.stats_info->sw_stat.link_down_time; - reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt; - mem_alloc_cnt = sp->mac_control.stats_info->sw_stat.mem_allocated; - mem_free_cnt = sp->mac_control.stats_info->sw_stat.mem_freed; - watchdog_cnt = sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt; + stats = sp->mac_control.stats_info; + swstats = &stats->sw_stat; + /* save link up/down time/cnt, reset/memory/watchdog cnt */ - memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block)); + up_cnt = swstats->link_up_cnt; + down_cnt = swstats->link_down_cnt; + up_time = swstats->link_up_time; + down_time = swstats->link_down_time; + reset_cnt = swstats->soft_reset_cnt; + mem_alloc_cnt = swstats->mem_allocated; + mem_free_cnt = swstats->mem_freed; + watchdog_cnt = swstats->watchdog_timer_cnt; + + memset(stats, 0, sizeof(struct stat_block)); + /* restore link up/down time/cnt, reset/memory/watchdog cnt */ - sp->mac_control.stats_info->sw_stat.link_up_cnt = up_cnt; - sp->mac_control.stats_info->sw_stat.link_down_cnt = down_cnt; - sp->mac_control.stats_info->sw_stat.link_up_time = up_time; - sp->mac_control.stats_info->sw_stat.link_down_time = down_time; - sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt; - sp->mac_control.stats_info->sw_stat.mem_allocated = mem_alloc_cnt; - sp->mac_control.stats_info->sw_stat.mem_freed = mem_free_cnt; - sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt = watchdog_cnt; + swstats->link_up_cnt = up_cnt; + swstats->link_down_cnt = down_cnt; + swstats->link_up_time = up_time; + swstats->link_down_time = down_time; + swstats->soft_reset_cnt = reset_cnt; + swstats->mem_allocated = mem_alloc_cnt; + swstats->mem_freed = mem_free_cnt; + swstats->watchdog_timer_cnt = watchdog_cnt; /* SXE-002: Configure link and activity LED to turn it off */ subid = sp->pdev->subsystem_device; @@ -3827,29 +3798,31 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) u16 msi_control; /* Temp variable */ int ret, i, j, msix_indx = 1; int size; + struct stat_block *stats = nic->mac_control.stats_info; + struct swStat *swstats = &stats->sw_stat; size = nic->num_entries * sizeof(struct msix_entry); nic->entries = kzalloc(size, GFP_KERNEL); if (!nic->entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __func__); - nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; + swstats->mem_alloc_fail_cnt++; return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated += size; + swstats->mem_allocated += size; size = nic->num_entries * sizeof(struct s2io_msix_entry); nic->s2io_entries = kzalloc(size, GFP_KERNEL); if (!nic->s2io_entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __func__); - nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; + swstats->mem_alloc_fail_cnt++; kfree(nic->entries); - nic->mac_control.stats_info->sw_stat.mem_freed + swstats->mem_freed += (nic->num_entries * sizeof(struct msix_entry)); return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated += size; + swstats->mem_allocated += size; nic->entries[0].entry = 0; nic->s2io_entries[0].entry = 0; @@ -3880,11 +3853,11 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) if (ret) { DBG_PRINT(ERR_DBG, "s2io: Enabling MSI-X failed\n"); kfree(nic->entries); - nic->mac_control.stats_info->sw_stat.mem_freed - += (nic->num_entries * sizeof(struct msix_entry)); + swstats->mem_freed += nic->num_entries * + sizeof(struct msix_entry); kfree(nic->s2io_entries); - nic->mac_control.stats_info->sw_stat.mem_freed - += (nic->num_entries * sizeof(struct s2io_msix_entry)); + swstats->mem_freed += nic->num_entries * + sizeof(struct s2io_msix_entry); nic->entries = NULL; nic->s2io_entries = NULL; return -ENOMEM; @@ -4006,6 +3979,7 @@ static void remove_inta_isr(struct s2io_nic *sp) static int s2io_open(struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; int err = 0; /* @@ -4036,13 +4010,13 @@ hw_init_failed: if (sp->config.intr_type == MSI_X) { if (sp->entries) { kfree(sp->entries); - sp->mac_control.stats_info->sw_stat.mem_freed - += (sp->num_entries * sizeof(struct msix_entry)); + swstats->mem_freed += sp->num_entries * + sizeof(struct msix_entry); } if (sp->s2io_entries) { kfree(sp->s2io_entries); - sp->mac_control.stats_info->sw_stat.mem_freed - += (sp->num_entries * sizeof(struct s2io_msix_entry)); + swstats->mem_freed += sp->num_entries * + sizeof(struct s2io_msix_entry); } } return err; @@ -4110,15 +4084,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags = 0; u16 vlan_tag = 0; struct fifo_info *fifo = NULL; - struct mac_info *mac_control; - struct config_param *config; int do_spin_lock = 1; int offload_type; int enable_per_list_interrupt = 0; - struct swStat *stats = &sp->mac_control.stats_info->sw_stat; - - mac_control = &sp->mac_control; - config = &sp->config; + struct config_param *config = &sp->config; + struct mac_info *mac_control = &sp->mac_control; + struct stat_block *stats = mac_control->stats_info; + struct swStat *swstats = &stats->sw_stat; DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name); @@ -4308,23 +4280,24 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) /* Avoid "put" pointer going beyond "get" pointer */ if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) { - sp->mac_control.stats_info->sw_stat.fifo_full_cnt++; + swstats->fifo_full_cnt++; DBG_PRINT(TX_DBG, "No free TxDs for xmit, Put: 0x%x Get:0x%x\n", put_off, get_off); s2io_stop_tx_queue(sp, fifo->fifo_no); } - mac_control->stats_info->sw_stat.mem_allocated += skb->truesize; + swstats->mem_allocated += skb->truesize; spin_unlock_irqrestore(&fifo->tx_lock, flags); if (sp->config.intr_type == MSI_X) tx_intr_handler(fifo); return NETDEV_TX_OK; + pci_map_failed: - stats->pci_map_fail_cnt++; + swstats->pci_map_fail_cnt++; s2io_stop_tx_queue(sp, fifo->fifo_no); - stats->mem_freed += skb->truesize; + swstats->mem_freed += skb->truesize; dev_kfree_skb(skb); spin_unlock_irqrestore(&fifo->tx_lock, flags); return NETDEV_TX_OK; @@ -4816,8 +4789,8 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) if (!is_s2io_card_up(sp)) return IRQ_NONE; - mac_control = &sp->mac_control; config = &sp->config; + mac_control = &sp->mac_control; /* * Identify the cause for interrupt and call the appropriate @@ -4934,44 +4907,35 @@ static void s2io_updt_stats(struct s2io_nic *sp) static struct net_device_stats *s2io_get_stats(struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); - struct mac_info *mac_control; - struct config_param *config; + struct config_param *config = &sp->config; + struct mac_info *mac_control = &sp->mac_control; + struct stat_block *stats = mac_control->stats_info; int i; - - mac_control = &sp->mac_control; - config = &sp->config; - /* Configure Stats for immediate updt */ s2io_updt_stats(sp); /* Using sp->stats as a staging area, because reset (due to mtu change, for example) will clear some hardware counters */ - dev->stats.tx_packets += - le32_to_cpu(mac_control->stats_info->tmac_frms) - + dev->stats.tx_packets += le32_to_cpu(stats->tmac_frms) - sp->stats.tx_packets; - sp->stats.tx_packets = - le32_to_cpu(mac_control->stats_info->tmac_frms); - dev->stats.tx_errors += - le32_to_cpu(mac_control->stats_info->tmac_any_err_frms) - + sp->stats.tx_packets = le32_to_cpu(stats->tmac_frms); + + dev->stats.tx_errors += le32_to_cpu(stats->tmac_any_err_frms) - sp->stats.tx_errors; - sp->stats.tx_errors = - le32_to_cpu(mac_control->stats_info->tmac_any_err_frms); - dev->stats.rx_errors += - le64_to_cpu(mac_control->stats_info->rmac_drop_frms) - + sp->stats.tx_errors = le32_to_cpu(stats->tmac_any_err_frms); + + dev->stats.rx_errors += le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_errors; - sp->stats.rx_errors = - le64_to_cpu(mac_control->stats_info->rmac_drop_frms); - dev->stats.multicast = - le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms) - + sp->stats.rx_errors = le64_to_cpu(stats->rmac_drop_frms); + + dev->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms) - sp->stats.multicast; - sp->stats.multicast = - le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms); - dev->stats.rx_length_errors = - le64_to_cpu(mac_control->stats_info->rmac_long_frms) - + sp->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms); + + dev->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms) - sp->stats.rx_length_errors; - sp->stats.rx_length_errors = - le64_to_cpu(mac_control->stats_info->rmac_long_frms); + sp->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms); /* collect per-ring rx_packets and rx_bytes */ dev->stats.rx_packets = dev->stats.rx_bytes = 0; @@ -5803,6 +5767,7 @@ static void s2io_vpd_read(struct s2io_nic *nic) u8 data; int i = 0, cnt, fail = 0; int vpd_addr = 0x80; + struct swStat *swstats = &nic->mac_control.stats_info->sw_stat; if (nic->device_type == XFRAME_II_DEVICE) { strcpy(nic->product_name, "Xframe II 10GbE network adapter"); @@ -5815,10 +5780,10 @@ static void s2io_vpd_read(struct s2io_nic *nic) vpd_data = kmalloc(256, GFP_KERNEL); if (!vpd_data) { - nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; + swstats->mem_alloc_fail_cnt++; return; } - nic->mac_control.stats_info->sw_stat.mem_allocated += 256; + swstats->mem_allocated += 256; for (i = 0; i < 256; i += 4) { pci_write_config_byte(nic->pdev, (vpd_addr + 2), i); @@ -5858,7 +5823,7 @@ static void s2io_vpd_read(struct s2io_nic *nic) memcpy(nic->product_name, &vpd_data[3], vpd_data[1]); } kfree(vpd_data); - nic->mac_control.stats_info->sw_stat.mem_freed += 256; + swstats->mem_freed += 256; } /** @@ -6350,273 +6315,275 @@ static void s2io_get_ethtool_stats(struct net_device *dev, { int i = 0, k; struct s2io_nic *sp = netdev_priv(dev); - struct stat_block *stat_info = sp->mac_control.stats_info; + struct stat_block *stats = sp->mac_control.stats_info; + struct swStat *swstats = &stats->sw_stat; + struct xpakStat *xstats = &stats->xpak_stat; s2io_updt_stats(sp); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_frms); + (u64)le32_to_cpu(stats->tmac_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 | - le32_to_cpu(stat_info->tmac_data_octets); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms); + (u64)le32_to_cpu(stats->tmac_data_octets_oflow) << 32 | + le32_to_cpu(stats->tmac_data_octets); + tmp_stats[i++] = le64_to_cpu(stats->tmac_drop_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_mcst_frms); + (u64)le32_to_cpu(stats->tmac_mcst_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_mcst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_bcst_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms); + (u64)le32_to_cpu(stats->tmac_bcst_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_bcst_frms); + tmp_stats[i++] = le64_to_cpu(stats->tmac_pause_ctrl_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 | - le32_to_cpu(stat_info->tmac_ttl_octets); + (u64)le32_to_cpu(stats->tmac_ttl_octets_oflow) << 32 | + le32_to_cpu(stats->tmac_ttl_octets); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_ucst_frms); + (u64)le32_to_cpu(stats->tmac_ucst_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_ucst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_nucst_frms); + (u64)le32_to_cpu(stats->tmac_nucst_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_nucst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_any_err_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets); + (u64)le32_to_cpu(stats->tmac_any_err_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_any_err_frms); + tmp_stats[i++] = le64_to_cpu(stats->tmac_ttl_less_fb_octets); + tmp_stats[i++] = le64_to_cpu(stats->tmac_vld_ip_octets); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 | - le32_to_cpu(stat_info->tmac_vld_ip); + (u64)le32_to_cpu(stats->tmac_vld_ip_oflow) << 32 | + le32_to_cpu(stats->tmac_vld_ip); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 | - le32_to_cpu(stat_info->tmac_drop_ip); + (u64)le32_to_cpu(stats->tmac_drop_ip_oflow) << 32 | + le32_to_cpu(stats->tmac_drop_ip); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 | - le32_to_cpu(stat_info->tmac_icmp); + (u64)le32_to_cpu(stats->tmac_icmp_oflow) << 32 | + le32_to_cpu(stats->tmac_icmp); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 | - le32_to_cpu(stat_info->tmac_rst_tcp); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp); - tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 | - le32_to_cpu(stat_info->tmac_udp); + (u64)le32_to_cpu(stats->tmac_rst_tcp_oflow) << 32 | + le32_to_cpu(stats->tmac_rst_tcp); + tmp_stats[i++] = le64_to_cpu(stats->tmac_tcp); + tmp_stats[i++] = (u64)le32_to_cpu(stats->tmac_udp_oflow) << 32 | + le32_to_cpu(stats->tmac_udp); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_vld_frms); + (u64)le32_to_cpu(stats->rmac_vld_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_vld_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 | - le32_to_cpu(stat_info->rmac_data_octets); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms); + (u64)le32_to_cpu(stats->rmac_data_octets_oflow) << 32 | + le32_to_cpu(stats->rmac_data_octets); + tmp_stats[i++] = le64_to_cpu(stats->rmac_fcs_err_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_drop_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_vld_mcst_frms); + (u64)le32_to_cpu(stats->rmac_vld_mcst_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_vld_mcst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_vld_bcst_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_out_rng_len_err_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms); + (u64)le32_to_cpu(stats->rmac_vld_bcst_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_vld_bcst_frms); + tmp_stats[i++] = le32_to_cpu(stats->rmac_in_rng_len_err_frms); + tmp_stats[i++] = le32_to_cpu(stats->rmac_out_rng_len_err_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_long_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_pause_ctrl_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_unsup_ctrl_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 | - le32_to_cpu(stat_info->rmac_ttl_octets); + (u64)le32_to_cpu(stats->rmac_ttl_octets_oflow) << 32 | + le32_to_cpu(stats->rmac_ttl_octets); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow) << 32 - | le32_to_cpu(stat_info->rmac_accepted_ucst_frms); + (u64)le32_to_cpu(stats->rmac_accepted_ucst_frms_oflow) << 32 + | le32_to_cpu(stats->rmac_accepted_ucst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow) - << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms); + (u64)le32_to_cpu(stats->rmac_accepted_nucst_frms_oflow) + << 32 | le32_to_cpu(stats->rmac_accepted_nucst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_discarded_frms); + (u64)le32_to_cpu(stats->rmac_discarded_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_discarded_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow) - << 32 | le32_to_cpu(stat_info->rmac_drop_events); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms); + (u64)le32_to_cpu(stats->rmac_drop_events_oflow) + << 32 | le32_to_cpu(stats->rmac_drop_events); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_less_fb_octets); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_usized_frms); + (u64)le32_to_cpu(stats->rmac_usized_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_usized_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_osized_frms); + (u64)le32_to_cpu(stats->rmac_osized_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_osized_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_frag_frms); + (u64)le32_to_cpu(stats->rmac_frag_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_frag_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_jabber_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms); + (u64)le32_to_cpu(stats->rmac_jabber_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_jabber_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_64_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_65_127_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_128_255_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_256_511_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_512_1023_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_1024_1518_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 | - le32_to_cpu(stat_info->rmac_ip); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip); + (u64)le32_to_cpu(stats->rmac_ip_oflow) << 32 | + le32_to_cpu(stats->rmac_ip); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ip_octets); + tmp_stats[i++] = le32_to_cpu(stats->rmac_hdr_err_ip); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 | - le32_to_cpu(stat_info->rmac_drop_ip); + (u64)le32_to_cpu(stats->rmac_drop_ip_oflow) << 32 | + le32_to_cpu(stats->rmac_drop_ip); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 | - le32_to_cpu(stat_info->rmac_icmp); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp); + (u64)le32_to_cpu(stats->rmac_icmp_oflow) << 32 | + le32_to_cpu(stats->rmac_icmp); + tmp_stats[i++] = le64_to_cpu(stats->rmac_tcp); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 | - le32_to_cpu(stat_info->rmac_udp); + (u64)le32_to_cpu(stats->rmac_udp_oflow) << 32 | + le32_to_cpu(stats->rmac_udp); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 | - le32_to_cpu(stat_info->rmac_err_drp_udp); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7); + (u64)le32_to_cpu(stats->rmac_err_drp_udp_oflow) << 32 | + le32_to_cpu(stats->rmac_err_drp_udp); + tmp_stats[i++] = le64_to_cpu(stats->rmac_xgmii_err_sym); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q0); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q1); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q2); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q3); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q4); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q5); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q6); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q7); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q0); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q1); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q2); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q3); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q4); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q5); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q6); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q7); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 | - le32_to_cpu(stat_info->rmac_pause_cnt); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt); + (u64)le32_to_cpu(stats->rmac_pause_cnt_oflow) << 32 | + le32_to_cpu(stats->rmac_pause_cnt); + tmp_stats[i++] = le64_to_cpu(stats->rmac_xgmii_data_err_cnt); + tmp_stats[i++] = le64_to_cpu(stats->rmac_xgmii_ctrl_err_cnt); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 | - le32_to_cpu(stat_info->rmac_accepted_ip); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp); - tmp_stats[i++] = le32_to_cpu(stat_info->rd_req_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_rtry_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_rd_ack_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->wr_req_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_rtry_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->wr_disc_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_wr_ack_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->txp_wr_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->txd_rd_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->txd_wr_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rxd_rd_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt); + (u64)le32_to_cpu(stats->rmac_accepted_ip_oflow) << 32 | + le32_to_cpu(stats->rmac_accepted_ip); + tmp_stats[i++] = le32_to_cpu(stats->rmac_err_tcp); + tmp_stats[i++] = le32_to_cpu(stats->rd_req_cnt); + tmp_stats[i++] = le32_to_cpu(stats->new_rd_req_cnt); + tmp_stats[i++] = le32_to_cpu(stats->new_rd_req_rtry_cnt); + tmp_stats[i++] = le32_to_cpu(stats->rd_rtry_cnt); + tmp_stats[i++] = le32_to_cpu(stats->wr_rtry_rd_ack_cnt); + tmp_stats[i++] = le32_to_cpu(stats->wr_req_cnt); + tmp_stats[i++] = le32_to_cpu(stats->new_wr_req_cnt); + tmp_stats[i++] = le32_to_cpu(stats->new_wr_req_rtry_cnt); + tmp_stats[i++] = le32_to_cpu(stats->wr_rtry_cnt); + tmp_stats[i++] = le32_to_cpu(stats->wr_disc_cnt); + tmp_stats[i++] = le32_to_cpu(stats->rd_rtry_wr_ack_cnt); + tmp_stats[i++] = le32_to_cpu(stats->txp_wr_cnt); + tmp_stats[i++] = le32_to_cpu(stats->txd_rd_cnt); + tmp_stats[i++] = le32_to_cpu(stats->txd_wr_cnt); + tmp_stats[i++] = le32_to_cpu(stats->rxd_rd_cnt); + tmp_stats[i++] = le32_to_cpu(stats->rxd_wr_cnt); + tmp_stats[i++] = le32_to_cpu(stats->txf_rd_cnt); + tmp_stats[i++] = le32_to_cpu(stats->rxf_wr_cnt); /* Enhanced statistics exist only for Hercules */ if (sp->device_type == XFRAME_II_DEVICE) { tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms); + le64_to_cpu(stats->rmac_ttl_1519_4095_frms); tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms); + le64_to_cpu(stats->rmac_ttl_4096_8191_frms); tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_8192_max_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt); + le64_to_cpu(stats->rmac_ttl_8192_max_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_gt_max_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_osized_alt_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_jabber_alt_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_gt_max_alt_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_vlan_frms); + tmp_stats[i++] = le32_to_cpu(stats->rmac_len_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_fcs_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_pf_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_da_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_red_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_rts_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_ingm_full_discard); + tmp_stats[i++] = le32_to_cpu(stats->link_fault_cnt); } tmp_stats[i++] = 0; - tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs; - tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs; - tmp_stats[i++] = stat_info->sw_stat.parity_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt; - tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt; + tmp_stats[i++] = swstats->single_ecc_errs; + tmp_stats[i++] = swstats->double_ecc_errs; + tmp_stats[i++] = swstats->parity_err_cnt; + tmp_stats[i++] = swstats->serious_err_cnt; + tmp_stats[i++] = swstats->soft_reset_cnt; + tmp_stats[i++] = swstats->fifo_full_cnt; for (k = 0; k < MAX_RX_RINGS; k++) - tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt[k]; - tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high; - tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low; - tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high; - tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_low; - tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_high; - tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_low; - tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_high; - tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_low; - tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_high; - tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_low; - tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_high; - tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_low; - tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt; - tmp_stats[i++] = stat_info->sw_stat.sending_both; - tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts; - tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts; - if (stat_info->sw_stat.num_aggregations) { - u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated; + tmp_stats[i++] = swstats->ring_full_cnt[k]; + tmp_stats[i++] = xstats->alarm_transceiver_temp_high; + tmp_stats[i++] = xstats->alarm_transceiver_temp_low; + tmp_stats[i++] = xstats->alarm_laser_bias_current_high; + tmp_stats[i++] = xstats->alarm_laser_bias_current_low; + tmp_stats[i++] = xstats->alarm_laser_output_power_high; + tmp_stats[i++] = xstats->alarm_laser_output_power_low; + tmp_stats[i++] = xstats->warn_transceiver_temp_high; + tmp_stats[i++] = xstats->warn_transceiver_temp_low; + tmp_stats[i++] = xstats->warn_laser_bias_current_high; + tmp_stats[i++] = xstats->warn_laser_bias_current_low; + tmp_stats[i++] = xstats->warn_laser_output_power_high; + tmp_stats[i++] = xstats->warn_laser_output_power_low; + tmp_stats[i++] = swstats->clubbed_frms_cnt; + tmp_stats[i++] = swstats->sending_both; + tmp_stats[i++] = swstats->outof_sequence_pkts; + tmp_stats[i++] = swstats->flush_max_pkts; + if (swstats->num_aggregations) { + u64 tmp = swstats->sum_avg_pkts_aggregated; int count = 0; /* * Since 64-bit divide does not work on all platforms, * do repeated subtraction. */ - while (tmp >= stat_info->sw_stat.num_aggregations) { - tmp -= stat_info->sw_stat.num_aggregations; + while (tmp >= swstats->num_aggregations) { + tmp -= swstats->num_aggregations; count++; } tmp_stats[i++] = count; } else tmp_stats[i++] = 0; - tmp_stats[i++] = stat_info->sw_stat.mem_alloc_fail_cnt; - tmp_stats[i++] = stat_info->sw_stat.pci_map_fail_cnt; - tmp_stats[i++] = stat_info->sw_stat.watchdog_timer_cnt; - tmp_stats[i++] = stat_info->sw_stat.mem_allocated; - tmp_stats[i++] = stat_info->sw_stat.mem_freed; - tmp_stats[i++] = stat_info->sw_stat.link_up_cnt; - tmp_stats[i++] = stat_info->sw_stat.link_down_cnt; - tmp_stats[i++] = stat_info->sw_stat.link_up_time; - tmp_stats[i++] = stat_info->sw_stat.link_down_time; - - tmp_stats[i++] = stat_info->sw_stat.tx_buf_abort_cnt; - tmp_stats[i++] = stat_info->sw_stat.tx_desc_abort_cnt; - tmp_stats[i++] = stat_info->sw_stat.tx_parity_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.tx_link_loss_cnt; - tmp_stats[i++] = stat_info->sw_stat.tx_list_proc_err_cnt; - - tmp_stats[i++] = stat_info->sw_stat.rx_parity_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_abort_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_parity_abort_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_rda_fail_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_unkn_prot_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_fcs_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_buf_size_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_rxd_corrupt_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_unkn_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.tda_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.pfc_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.pcc_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.tti_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.tpa_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.sm_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.lso_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.mac_tmac_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.mac_rmac_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.xgxs_txgxs_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.xgxs_rxgxs_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rc_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.prc_pcix_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rpa_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rda_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rti_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.mc_err_cnt; + tmp_stats[i++] = swstats->mem_alloc_fail_cnt; + tmp_stats[i++] = swstats->pci_map_fail_cnt; + tmp_stats[i++] = swstats->watchdog_timer_cnt; + tmp_stats[i++] = swstats->mem_allocated; + tmp_stats[i++] = swstats->mem_freed; + tmp_stats[i++] = swstats->link_up_cnt; + tmp_stats[i++] = swstats->link_down_cnt; + tmp_stats[i++] = swstats->link_up_time; + tmp_stats[i++] = swstats->link_down_time; + + tmp_stats[i++] = swstats->tx_buf_abort_cnt; + tmp_stats[i++] = swstats->tx_desc_abort_cnt; + tmp_stats[i++] = swstats->tx_parity_err_cnt; + tmp_stats[i++] = swstats->tx_link_loss_cnt; + tmp_stats[i++] = swstats->tx_list_proc_err_cnt; + + tmp_stats[i++] = swstats->rx_parity_err_cnt; + tmp_stats[i++] = swstats->rx_abort_cnt; + tmp_stats[i++] = swstats->rx_parity_abort_cnt; + tmp_stats[i++] = swstats->rx_rda_fail_cnt; + tmp_stats[i++] = swstats->rx_unkn_prot_cnt; + tmp_stats[i++] = swstats->rx_fcs_err_cnt; + tmp_stats[i++] = swstats->rx_buf_size_err_cnt; + tmp_stats[i++] = swstats->rx_rxd_corrupt_cnt; + tmp_stats[i++] = swstats->rx_unkn_err_cnt; + tmp_stats[i++] = swstats->tda_err_cnt; + tmp_stats[i++] = swstats->pfc_err_cnt; + tmp_stats[i++] = swstats->pcc_err_cnt; + tmp_stats[i++] = swstats->tti_err_cnt; + tmp_stats[i++] = swstats->tpa_err_cnt; + tmp_stats[i++] = swstats->sm_err_cnt; + tmp_stats[i++] = swstats->lso_err_cnt; + tmp_stats[i++] = swstats->mac_tmac_err_cnt; + tmp_stats[i++] = swstats->mac_rmac_err_cnt; + tmp_stats[i++] = swstats->xgxs_txgxs_err_cnt; + tmp_stats[i++] = swstats->xgxs_rxgxs_err_cnt; + tmp_stats[i++] = swstats->rc_err_cnt; + tmp_stats[i++] = swstats->prc_pcix_err_cnt; + tmp_stats[i++] = swstats->rpa_err_cnt; + tmp_stats[i++] = swstats->rda_err_cnt; + tmp_stats[i++] = swstats->rti_err_cnt; + tmp_stats[i++] = swstats->mc_err_cnt; } static int s2io_ethtool_get_regs_len(struct net_device *dev) @@ -6912,12 +6879,10 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); DBG_PRINT(INFO_DBG, "memory to allocate "); DBG_PRINT(INFO_DBG, "1 buf mode SKBs\n"); - sp->mac_control.stats_info->sw_stat. - mem_alloc_fail_cnt++; + stats->mem_alloc_fail_cnt++; return -ENOMEM ; } - sp->mac_control.stats_info->sw_stat.mem_allocated - += (*skb)->truesize; + stats->mem_allocated += (*skb)->truesize; /* storing the mapped addr in a temp variable * such it will be used for next rxd whose * Host Control is NULL @@ -6943,12 +6908,10 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); DBG_PRINT(INFO_DBG, "memory to allocate "); DBG_PRINT(INFO_DBG, "2 buf mode SKBs\n"); - sp->mac_control.stats_info->sw_stat. - mem_alloc_fail_cnt++; + stats->mem_alloc_fail_cnt++; return -ENOMEM; } - sp->mac_control.stats_info->sw_stat.mem_allocated - += (*skb)->truesize; + stats->mem_allocated += (*skb)->truesize; rxdp3->Buffer2_ptr = *temp2 = pci_map_single(sp->pdev, (*skb)->data, dev->mtu + 4, @@ -7010,8 +6973,8 @@ static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp, static int rxd_owner_bit_reset(struct s2io_nic *sp) { int i, j, k, blk_cnt = 0, size; - struct mac_info *mac_control = &sp->mac_control; struct config_param *config = &sp->config; + struct mac_info *mac_control = &sp->mac_control; struct net_device *dev = sp->dev; struct RxD_t *rxdp = NULL; struct sk_buff *skb = NULL; @@ -7239,8 +7202,8 @@ static void s2io_card_down(struct s2io_nic *sp) static int s2io_card_up(struct s2io_nic *sp) { int i, ret = 0; - struct mac_info *mac_control; struct config_param *config; + struct mac_info *mac_control; struct net_device *dev = (struct net_device *)sp->dev; u16 interruptible; @@ -7258,8 +7221,8 @@ static int s2io_card_up(struct s2io_nic *sp) * Initializing the Rx buffers. For now we are considering only 1 * Rx ring and initializing buffers into 30 Rx blocks */ - mac_control = &sp->mac_control; config = &sp->config; + mac_control = &sp->mac_control; for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i]; @@ -7387,11 +7350,12 @@ out_unlock: static void s2io_tx_watchdog(struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; if (netif_carrier_ok(dev)) { - sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt++; + swstats->watchdog_timer_cnt++; schedule_work(&sp->rst_timer_task); - sp->mac_control.stats_info->sw_stat.soft_reset_cnt++; + swstats->soft_reset_cnt++; } } @@ -7423,50 +7387,51 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) unsigned long long err = rxdp->Control_1 & RXD_T_CODE; struct lro *uninitialized_var(lro); u8 err_mask; + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; skb->dev = dev; if (err) { /* Check for parity error */ if (err & 0x1) - sp->mac_control.stats_info->sw_stat.parity_err_cnt++; + swstats->parity_err_cnt++; err_mask = err >> 48; switch (err_mask) { case 1: - sp->mac_control.stats_info->sw_stat.rx_parity_err_cnt++; + swstats->rx_parity_err_cnt++; break; case 2: - sp->mac_control.stats_info->sw_stat.rx_abort_cnt++; + swstats->rx_abort_cnt++; break; case 3: - sp->mac_control.stats_info->sw_stat.rx_parity_abort_cnt++; + swstats->rx_parity_abort_cnt++; break; case 4: - sp->mac_control.stats_info->sw_stat.rx_rda_fail_cnt++; + swstats->rx_rda_fail_cnt++; break; case 5: - sp->mac_control.stats_info->sw_stat.rx_unkn_prot_cnt++; + swstats->rx_unkn_prot_cnt++; break; case 6: - sp->mac_control.stats_info->sw_stat.rx_fcs_err_cnt++; + swstats->rx_fcs_err_cnt++; break; case 7: - sp->mac_control.stats_info->sw_stat.rx_buf_size_err_cnt++; + swstats->rx_buf_size_err_cnt++; break; case 8: - sp->mac_control.stats_info->sw_stat.rx_rxd_corrupt_cnt++; + swstats->rx_rxd_corrupt_cnt++; break; case 15: - sp->mac_control.stats_info->sw_stat.rx_unkn_err_cnt++; + swstats->rx_unkn_err_cnt++; break; } /* @@ -7480,7 +7445,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n", dev->name, err_mask); dev->stats.rx_crc_errors++; - sp->mac_control.stats_info->sw_stat.mem_freed + swstats->mem_freed += skb->truesize; dev_kfree_skb(skb); ring_data->rx_bufs_left -= 1; @@ -7545,13 +7510,11 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) queue_rx_frame(lro->parent, lro->vlan_tag); clear_lro_session(lro); - sp->mac_control.stats_info-> - sw_stat.flush_max_pkts++; + swstats->flush_max_pkts++; goto aggregate; case 2: /* Flush both */ lro->parent->data_len = lro->frags_len; - sp->mac_control.stats_info-> - sw_stat.sending_both++; + swstats->sending_both++; queue_rx_frame(lro->parent, lro->vlan_tag); clear_lro_session(lro); @@ -7580,7 +7543,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) } else skb->ip_summed = CHECKSUM_NONE; - sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; + swstats->mem_freed += skb->truesize; send_up: skb_record_rx_queue(skb, ring_no); queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2)); @@ -7605,6 +7568,7 @@ aggregate: static void s2io_link(struct s2io_nic *sp, int link) { struct net_device *dev = (struct net_device *)sp->dev; + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; if (link != sp->last_link_state) { init_tti(sp, link); @@ -7612,17 +7576,16 @@ static void s2io_link(struct s2io_nic *sp, int link) DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name); s2io_stop_all_tx_queue(sp); netif_carrier_off(dev); - if (sp->mac_control.stats_info->sw_stat.link_up_cnt) - sp->mac_control.stats_info->sw_stat. - link_up_time = jiffies - sp->start_time; - sp->mac_control.stats_info->sw_stat.link_down_cnt++; + if (swstats->link_up_cnt) + swstats->link_up_time = + jiffies - sp->start_time; + swstats->link_down_cnt++; } else { DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name); - if (sp->mac_control.stats_info->sw_stat.link_down_cnt) - sp->mac_control.stats_info-> - sw_stat.link_down_time = + if (swstats->link_down_cnt) + swstats->link_down_time = jiffies - sp->start_time; - sp->mac_control.stats_info->sw_stat.link_up_cnt++; + swstats->link_up_cnt++; netif_carrier_on(dev); s2io_wake_all_tx_queue(sp); } @@ -7800,8 +7763,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) u64 val64 = 0, tmp64 = 0; struct XENA_dev_config __iomem *bar0 = NULL; u16 subid; - struct mac_info *mac_control; struct config_param *config; + struct mac_info *mac_control; int mode; u8 dev_intr_type = intr_type; u8 dev_multiq = 0; @@ -7887,8 +7850,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) * these parameters are not not specified during load time, they * are initialized with default values. */ - mac_control = &sp->mac_control; config = &sp->config; + mac_control = &sp->mac_control; config->napi = napi; config->tx_steering_type = tx_steering_type; @@ -8433,7 +8396,8 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) struct iphdr *ip = lro->iph; struct tcphdr *tcp = lro->tcph; __sum16 nchk; - struct stat_block *statinfo = sp->mac_control.stats_info; + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); /* Update L3 header */ @@ -8455,8 +8419,8 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) /* Update counters required for calculation of * average no. of packets aggregated. */ - statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num; - statinfo->sw_stat.num_aggregations++; + swstats->sum_avg_pkts_aggregated += lro->sg_num; + swstats->num_aggregations++; } static void aggregate_new_rx(struct lro *lro, struct iphdr *ip, @@ -8547,6 +8511,7 @@ static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, struct tcphdr *tcph; int ret = 0, i; u16 vlan_tag = 0; + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp, rxdp, sp); @@ -8572,8 +8537,7 @@ static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, (*lro)->tcp_next_seq, ntohl(tcph->seq)); - sp->mac_control.stats_info-> - sw_stat.outof_sequence_pkts++; + swstats->outof_sequence_pkts++; ret = 2; break; } @@ -8667,6 +8631,7 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, struct sk_buff *skb, u32 tcp_len) { struct sk_buff *first = lro->parent; + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; first->len += tcp_len; first->data_len = lro->frags_len; @@ -8677,7 +8642,7 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, skb_shinfo(first)->frag_list = skb; first->truesize += skb->truesize; lro->last_frag = skb; - sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++; + swstats->clubbed_frms_cnt++; return; } -- cgit v0.10.2 From 82c2d02356229c66daa6b6e51f8da559327b87b0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:48 +0000 Subject: s2io.c: Convert skipped nic->config.tx_cfg[i]. to tx_cfg-> Missed doing the conversion in earlier patch. Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 06223df..1d13f60 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1001,7 +1001,7 @@ static void free_shared_mem(struct s2io_nic *nic) swstats->mem_freed += PAGE_SIZE; } kfree(fifo->list_info); - swstats->mem_freed += nic->config.tx_cfg[i].fifo_len * + swstats->mem_freed += tx_cfg->fifo_len * sizeof(struct list_info_hold); } -- cgit v0.10.2 From 9e39f7c5b311a306977c5471f9e2ce4c456aa038 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 25 Aug 2009 08:52:00 +0000 Subject: s2io: Generate complete messages using single line DBG_PRINTs Single line log messages should be emitted by a single call where possible. Converted multiple calls to DBG_PRINT to single call form. Removed "s2io:" preface from DBG_PRINTs. The DBG_PRINT macro now emits a log level and is surrounded by a do {...} while (0) All s2io log output is now prefaced with KBUILD_MODNAME ": " via pr_fmt. The DBG_PRINT macro should probably be converted to use the dev_ form eventually. Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 1d13f60..3138df5 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -652,9 +652,9 @@ static int init_shared_mem(struct s2io_nic *nic) size += tx_cfg->fifo_len; } if (size > MAX_AVAILABLE_TXDS) { - DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, "); - DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", - size); + DBG_PRINT(ERR_DBG, + "Too many TxDs requested: %d, max supported: %d\n", + size, MAX_AVAILABLE_TXDS); return -EINVAL; } @@ -667,10 +667,9 @@ static int init_shared_mem(struct s2io_nic *nic) * Legal values are from 2 to 8192 */ if (size < 2) { - DBG_PRINT(ERR_DBG, "s2io: Invalid fifo len (%d)", size); - DBG_PRINT(ERR_DBG, "for fifo %d\n", i); - DBG_PRINT(ERR_DBG, "s2io: Legal values for fifo len" - "are 2 to 8192\n"); + DBG_PRINT(ERR_DBG, "Fifo %d: Invalid length (%d) - " + "Valid lengths are 2 through 8192\n", + i, size); return -EINVAL; } } @@ -713,8 +712,8 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { - DBG_PRINT(INFO_DBG, "pci_alloc_consistent "); - DBG_PRINT(INFO_DBG, "failed for TxDL\n"); + DBG_PRINT(INFO_DBG, + "pci_alloc_consistent failed for TxDL\n"); return -ENOMEM; } /* If we got a zero DMA address(can happen on @@ -725,17 +724,14 @@ static int init_shared_mem(struct s2io_nic *nic) if (!tmp_p) { mac_control->zerodma_virt_addr = tmp_v; DBG_PRINT(INIT_DBG, - "%s: Zero DMA address for TxDL. ", - dev->name); - DBG_PRINT(INIT_DBG, - "Virtual address %p\n", tmp_v); + "%s: Zero DMA address for TxDL. " + "Virtual address %p\n", + dev->name, tmp_v); tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { DBG_PRINT(INFO_DBG, - "pci_alloc_consistent "); - DBG_PRINT(INFO_DBG, - "failed for TxDL\n"); + "pci_alloc_consistent failed for TxDL\n"); return -ENOMEM; } mem_allocated += PAGE_SIZE; @@ -771,9 +767,9 @@ static int init_shared_mem(struct s2io_nic *nic) struct ring_info *ring = &mac_control->rings[i]; if (rx_cfg->num_rxd % (rxd_count[nic->rxd_mode] + 1)) { - DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name); - DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ", i); - DBG_PRINT(ERR_DBG, "RxDs per Block"); + DBG_PRINT(ERR_DBG, "%s: Ring%d RxD count is not a " + "multiple of RxDs per Block\n", + dev->name, i); return FAILURE; } size += rx_cfg->num_rxd; @@ -927,7 +923,7 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_v_addr = mac_control->stats_mem; mac_control->stats_info = (struct stat_block *)tmp_v_addr; memset(tmp_v_addr, 0, size); - DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name, + DBG_PRINT(INIT_DBG, "%s: Ring Mem PHY: 0x%llx\n", dev->name, (unsigned long long)tmp_p_addr); mac_control->stats_info->sw_stat.mem_allocated += mem_allocated; return SUCCESS; @@ -994,10 +990,9 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control->zerodma_virt_addr, (dma_addr_t)0); DBG_PRINT(INIT_DBG, - "%s: Freeing TxDL with zero DMA addr. ", - dev->name); - DBG_PRINT(INIT_DBG, "Virtual address %p\n", - mac_control->zerodma_virt_addr); + "%s: Freeing TxDL with zero DMA address. " + "Virtual address %p\n", + dev->name, mac_control->zerodma_virt_addr); swstats->mem_freed += PAGE_SIZE; } kfree(fifo->list_info); @@ -1120,6 +1115,7 @@ static int s2io_print_pci_mode(struct s2io_nic *nic) register u64 val64 = 0; int mode; struct config_param *config = &nic->config; + const char *pcimode; val64 = readq(&bar0->pci_mode); mode = (u8)GET_PCI_MODE(val64); @@ -1135,38 +1131,39 @@ static int s2io_print_pci_mode(struct s2io_nic *nic) return mode; } - DBG_PRINT(ERR_DBG, "%s: Device is on %d bit ", - nic->dev->name, val64 & PCI_MODE_32_BITS ? 32 : 64); - switch (mode) { case PCI_MODE_PCI_33: - DBG_PRINT(ERR_DBG, "33MHz PCI bus\n"); + pcimode = "33MHz PCI bus"; break; case PCI_MODE_PCI_66: - DBG_PRINT(ERR_DBG, "66MHz PCI bus\n"); + pcimode = "66MHz PCI bus"; break; case PCI_MODE_PCIX_M1_66: - DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n"); + pcimode = "66MHz PCIX(M1) bus"; break; case PCI_MODE_PCIX_M1_100: - DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n"); + pcimode = "100MHz PCIX(M1) bus"; break; case PCI_MODE_PCIX_M1_133: - DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n"); + pcimode = "133MHz PCIX(M1) bus"; break; case PCI_MODE_PCIX_M2_66: - DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n"); + pcimode = "133MHz PCIX(M2) bus"; break; case PCI_MODE_PCIX_M2_100: - DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n"); + pcimode = "200MHz PCIX(M2) bus"; break; case PCI_MODE_PCIX_M2_133: - DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n"); + pcimode = "266MHz PCIX(M2) bus"; break; default: - return -1; /* Unsupported bus speed */ + pcimode = "unsupported bus!"; + mode = -1; } + DBG_PRINT(ERR_DBG, "%s: Device is on %d bit %s\n", + nic->dev->name, val64 & PCI_MODE_32_BITS ? 32 : 64, pcimode); + return mode; } @@ -1704,9 +1701,9 @@ static int init_nic(struct s2io_nic *nic) /* Disable differentiated services steering logic */ for (i = 0; i < 64; i++) { if (rts_ds_steer(nic, i, 0) == FAILURE) { - DBG_PRINT(ERR_DBG, "%s: failed rts ds steering", - dev->name); - DBG_PRINT(ERR_DBG, "set on codepoint %d\n", i); + DBG_PRINT(ERR_DBG, + "%s: rts_ds_steer failed on codepoint %d\n", + dev->name, i); return -ENODEV; } } @@ -1783,7 +1780,7 @@ static int init_nic(struct s2io_nic *nic) break; if (time > 10) { - DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n", + DBG_PRINT(ERR_DBG, "%s: RTI init failed\n", dev->name); return -ENODEV; } @@ -2189,35 +2186,35 @@ static int verify_xena_quiescence(struct s2io_nic *sp) mode = s2io_verify_pci_mode(sp); if (!(val64 & ADAPTER_STATUS_TDMA_READY)) { - DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!"); + DBG_PRINT(ERR_DBG, "TDMA is not ready!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_RDMA_READY)) { - DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!"); + DBG_PRINT(ERR_DBG, "RDMA is not ready!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_PFC_READY)) { - DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!"); + DBG_PRINT(ERR_DBG, "PFC is not ready!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) { - DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!"); + DBG_PRINT(ERR_DBG, "TMAC BUF is not empty!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) { - DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!"); + DBG_PRINT(ERR_DBG, "PIC is not QUIESCENT!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) { - DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!"); + DBG_PRINT(ERR_DBG, "MC_DRAM is not ready!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) { - DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!"); + DBG_PRINT(ERR_DBG, "MC_QUEUES is not ready!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) { - DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!"); + DBG_PRINT(ERR_DBG, "M_PLL is not locked!\n"); return 0; } @@ -2229,12 +2226,12 @@ static int verify_xena_quiescence(struct s2io_nic *sp) if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) && sp->device_type == XFRAME_II_DEVICE && mode != PCI_MODE_PCI_33) { - DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!"); + DBG_PRINT(ERR_DBG, "P_PLL is not locked!\n"); return 0; } if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == ADAPTER_STATUS_RC_PRC_QUIESCENT)) { - DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!"); + DBG_PRINT(ERR_DBG, "RC_PRC is not QUIESCENT!\n"); return 0; } return 1; @@ -2339,9 +2336,9 @@ static int start_nic(struct s2io_nic *nic) */ val64 = readq(&bar0->adapter_status); if (!verify_xena_quiescence(nic)) { - DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name); - DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n", - (unsigned long long)val64); + DBG_PRINT(ERR_DBG, "%s: device is not ready, " + "Adapter status reads: 0x%llx\n", + dev->name, (unsigned long long)val64); return FAILURE; } @@ -2455,7 +2452,7 @@ static void free_tx_buffers(struct s2io_nic *nic) } } DBG_PRINT(INTR_DBG, - "%s:forcibly freeing %d skbs on FIFO%d\n", + "%s: forcibly freeing %d skbs on FIFO%d\n", dev->name, cnt, i); fifo->tx_curr_get_info.offset = 0; fifo->tx_curr_put_info.offset = 0; @@ -2547,8 +2544,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, if ((block_no == block_no1) && (off == ring->rx_curr_get_info.offset) && (rxdp->Host_Control)) { - DBG_PRINT(INTR_DBG, "%s: Get and Put", ring->dev->name); - DBG_PRINT(INTR_DBG, " info equated\n"); + DBG_PRINT(INTR_DBG, "%s: Get and Put info equated\n", + ring->dev->name); goto end; } if (off && (off == ring->rxd_count)) { @@ -2583,8 +2580,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, /* allocate skb */ skb = dev_alloc_skb(size); if (!skb) { - DBG_PRINT(INFO_DBG, "%s: Out of ", ring->dev->name); - DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n"); + DBG_PRINT(INFO_DBG, "%s: Could not allocate skb\n", + ring->dev->name); if (first_rxdp) { wmb(); first_rxdp->Control_1 |= RXD_OWN_XENA; @@ -2806,7 +2803,7 @@ static void free_rx_buffers(struct s2io_nic *sp) ring->rx_curr_put_info.offset = 0; ring->rx_curr_get_info.offset = 0; ring->rx_bufs_left = 0; - DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n", + DBG_PRINT(INIT_DBG, "%s: Freed 0x%x Rx Buffers on ring%d\n", dev->name, buf_cnt, i); } } @@ -2814,8 +2811,8 @@ static void free_rx_buffers(struct s2io_nic *sp) static int s2io_chk_rx_buffers(struct s2io_nic *nic, struct ring_info *ring) { if (fill_rx_buffers(nic, ring, 0) == -ENOMEM) { - DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name); - DBG_PRINT(INFO_DBG, " in Rx Intr!!\n"); + DBG_PRINT(INFO_DBG, "%s: Out of memory in Rx Intr!!\n", + ring->dev->name); } return 0; } @@ -2938,8 +2935,9 @@ static void s2io_netpoll(struct net_device *dev) struct ring_info *ring = &mac_control->rings[i]; if (fill_rx_buffers(nic, ring, 0) == -ENOMEM) { - DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); - DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n"); + DBG_PRINT(INFO_DBG, + "%s: Out of memory in Rx Netpoll!!\n", + dev->name); break; } } @@ -2991,9 +2989,8 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) } skb = (struct sk_buff *)((unsigned long)rxdp->Host_Control); if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: The skb is ", + DBG_PRINT(ERR_DBG, "%s: NULL skb in Rx Intr\n", ring_data->dev->name); - DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); return 0; } if (ring_data->rxd_mode == RXD_MODE_1) { @@ -3126,8 +3123,8 @@ static void tx_intr_handler(struct fifo_info *fifo_data) skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset); if (skb == NULL) { spin_unlock_irqrestore(&fifo_data->tx_lock, flags); - DBG_PRINT(ERR_DBG, "%s: Null skb ", __func__); - DBG_PRINT(ERR_DBG, "in Tx Free Intr\n"); + DBG_PRINT(ERR_DBG, "%s: NULL skb in Tx Free Intr\n", + __func__); return; } pkt_cnt++; @@ -3266,22 +3263,22 @@ static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, if (val64 == 3) { switch (type) { case 1: - DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " - "service. Excessive temperatures may " - "result in premature transceiver " - "failure \n"); + DBG_PRINT(ERR_DBG, + "Take Xframe NIC out of service.\n"); + DBG_PRINT(ERR_DBG, +"Excessive temperatures may result in premature transceiver failure.\n"); break; case 2: - DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " - "service Excessive bias currents may " - "indicate imminent laser diode " - "failure \n"); + DBG_PRINT(ERR_DBG, + "Take Xframe NIC out of service.\n"); + DBG_PRINT(ERR_DBG, +"Excessive bias currents may indicate imminent laser diode failure.\n"); break; case 3: - DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " - "service Excessive laser output " - "power may saturate far-end " - "receiver\n"); + DBG_PRINT(ERR_DBG, + "Take Xframe NIC out of service.\n"); + DBG_PRINT(ERR_DBG, +"Excessive laser output power may saturate far-end receiver.\n"); break; default: DBG_PRINT(ERR_DBG, @@ -3321,15 +3318,16 @@ static void s2io_updt_xpak_counter(struct net_device *dev) val64 = 0x0; val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); if ((val64 == 0xFFFF) || (val64 == 0x0000)) { - DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - " - "Returned %llx\n", (unsigned long long)val64); + DBG_PRINT(ERR_DBG, + "ERR: MDIO slave access failed - Returned %llx\n", + (unsigned long long)val64); return; } /* Check for the expected value of control reg 1 */ if (val64 != MDIO_CTRL1_SPEED10G) { - DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - "); - DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x%x\n", + DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - " + "Returned: %llx- Expected: 0x%x\n", (unsigned long long)val64, MDIO_CTRL1_SPEED10G); return; } @@ -3481,7 +3479,7 @@ static void s2io_reset(struct s2io_nic *sp) struct stat_block *stats; struct swStat *swstats; - DBG_PRINT(INIT_DBG, "%s - Resetting XFrame card %s\n", + DBG_PRINT(INIT_DBG, "%s: Resetting XFrame card %s\n", __func__, sp->dev->name); /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */ @@ -3618,10 +3616,9 @@ static int s2io_set_swapper(struct s2io_nic *sp) i++; } if (i == 4) { - DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ", - dev->name); - DBG_PRINT(ERR_DBG, "feedback read %llx\n", - (unsigned long long)val64); + DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, " + "feedback read %llx\n", + dev->name, (unsigned long long)val64); return FAILURE; } valr = value[i]; @@ -3650,8 +3647,8 @@ static int s2io_set_swapper(struct s2io_nic *sp) } if (i == 4) { unsigned long long x = val64; - DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr "); - DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x); + DBG_PRINT(ERR_DBG, + "Write failed, Xmsi_addr reads:0x%llx\n", x); return FAILURE; } } @@ -3711,10 +3708,9 @@ static int s2io_set_swapper(struct s2io_nic *sp) val64 = readq(&bar0->pif_rd_swapper_fb); if (val64 != 0x0123456789ABCDEFULL) { /* Endian settings are incorrect, calls for another dekko. */ - DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ", - dev->name); - DBG_PRINT(ERR_DBG, "feedback read %llx\n", - (unsigned long long)val64); + DBG_PRINT(ERR_DBG, + "%s: Endian settings are wrong, feedback read %llx\n", + dev->name, (unsigned long long)val64); return FAILURE; } @@ -3758,7 +3754,8 @@ static void restore_xmsi_data(struct s2io_nic *nic) val64 = (s2BIT(7) | s2BIT(15) | vBIT(msix_index, 26, 6)); writeq(val64, &bar0->xmsi_access); if (wait_for_msix_trans(nic, msix_index)) { - DBG_PRINT(ERR_DBG, "failed in %s\n", __func__); + DBG_PRINT(ERR_DBG, "%s: index: %d failed\n", + __func__, msix_index); continue; } } @@ -3779,7 +3776,8 @@ static void store_xmsi_data(struct s2io_nic *nic) val64 = (s2BIT(15) | vBIT(msix_index, 26, 6)); writeq(val64, &bar0->xmsi_access); if (wait_for_msix_trans(nic, msix_index)) { - DBG_PRINT(ERR_DBG, "failed in %s\n", __func__); + DBG_PRINT(ERR_DBG, "%s: index: %d failed\n", + __func__, msix_index); continue; } addr = readq(&bar0->xmsi_address); @@ -3851,7 +3849,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) ret = pci_enable_msix(nic->pdev, nic->entries, nic->num_entries); /* We fail init if error or we get less vectors than min required */ if (ret) { - DBG_PRINT(ERR_DBG, "s2io: Enabling MSI-X failed\n"); + DBG_PRINT(ERR_DBG, "Enabling MSI-X failed\n"); kfree(nic->entries); swstats->mem_freed += nic->num_entries * sizeof(struct msix_entry); @@ -3915,8 +3913,8 @@ static int s2io_test_msi(struct s2io_nic *sp) if (!sp->msi_detected) { /* MSI(X) test failed, go back to INTx mode */ DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated " - "using MSI(X) during test\n", sp->dev->name, - pci_name(pdev)); + "using MSI(X) during test\n", + sp->dev->name, pci_name(pdev)); err = -EOPNOTSUPP; } @@ -4095,7 +4093,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name); if (unlikely(skb->len <= 0)) { - DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name); + DBG_PRINT(TX_DBG, "%s: Buffer has no data..\n", dev->name); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -5052,18 +5050,17 @@ static void s2io_set_multicast(struct net_device *dev) val64 = readq(&bar0->mac_cfg); sp->promisc_flg = 0; - DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n", - dev->name); + DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n", dev->name); } /* Update individual M_CAST address list */ if ((!sp->m_cast_flg) && dev->mc_count) { if (dev->mc_count > (config->max_mc_addr - config->max_mac_addr)) { - DBG_PRINT(ERR_DBG, "%s: No more Rx filters ", + DBG_PRINT(ERR_DBG, + "%s: No more Rx filters can be added - " + "please enable ALL_MULTI instead\n", dev->name); - DBG_PRINT(ERR_DBG, "can be added, please enable "); - DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n"); return; } @@ -5086,8 +5083,9 @@ static void s2io_set_multicast(struct net_device *dev) if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) { - DBG_PRINT(ERR_DBG, "%s: Adding ", dev->name); - DBG_PRINT(ERR_DBG, "Multicasts failed\n"); + DBG_PRINT(ERR_DBG, + "%s: Adding Multicasts failed\n", + dev->name); return; } } @@ -5117,8 +5115,9 @@ static void s2io_set_multicast(struct net_device *dev) if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) { - DBG_PRINT(ERR_DBG, "%s: Adding ", dev->name); - DBG_PRINT(ERR_DBG, "Multicasts failed\n"); + DBG_PRINT(ERR_DBG, + "%s: Adding Multicasts failed\n", + dev->name); return; } } @@ -5552,7 +5551,7 @@ static void s2io_ethtool_gringparam(struct net_device *dev, for (i = 0 ; i < sp->config.tx_fifo_num ; i++) tx_desc_count += sp->config.tx_cfg[i].fifo_len; - DBG_PRINT(INFO_DBG, "\nmax txds : %d\n", sp->config.max_txds); + DBG_PRINT(INFO_DBG, "max txds: %d\n", sp->config.max_txds); ering->tx_pending = tx_desc_count; rx_desc_count = 0; for (i = 0 ; i < sp->config.rx_ring_num ; i++) @@ -5886,8 +5885,10 @@ static int s2io_ethtool_seeprom(struct net_device *dev, if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { DBG_PRINT(ERR_DBG, - "ETHTOOL_WRITE_EEPROM Err: Magic value "); - DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n", eeprom->magic); + "ETHTOOL_WRITE_EEPROM Err: " + "Magic value is wrong, it is 0x%x should be 0x%x\n", + (sp->pdev->vendor | (sp->pdev->device << 16)), + eeprom->magic); return -EFAULT; } @@ -5900,9 +5901,8 @@ static int s2io_ethtool_seeprom(struct net_device *dev, if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) { DBG_PRINT(ERR_DBG, - "ETHTOOL_WRITE_EEPROM Err: Cannot "); - DBG_PRINT(ERR_DBG, - "write into the specified offset\n"); + "ETHTOOL_WRITE_EEPROM Err: " + "Cannot write into the specified offset\n"); return -EFAULT; } cnt++; @@ -5934,13 +5934,13 @@ static int s2io_register_test(struct s2io_nic *sp, uint64_t *data) val64 = readq(&bar0->pif_rd_swapper_fb); if (val64 != 0x123456789abcdefULL) { fail = 1; - DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n"); + DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 1); } val64 = readq(&bar0->rmac_pause_cfg); if (val64 != 0xc000ffff00000000ULL) { fail = 1; - DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n"); + DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 2); } val64 = readq(&bar0->rx_queue_cfg); @@ -5950,13 +5950,13 @@ static int s2io_register_test(struct s2io_nic *sp, uint64_t *data) exp_val = 0x0808080808080808ULL; if (val64 != exp_val) { fail = 1; - DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n"); + DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 3); } val64 = readq(&bar0->xgxs_efifo_cfg); if (val64 != 0x000000001923141EULL) { fail = 1; - DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n"); + DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 4); } val64 = 0x5A5A5A5A5A5A5A5AULL; @@ -5964,7 +5964,7 @@ static int s2io_register_test(struct s2io_nic *sp, uint64_t *data) val64 = readq(&bar0->xmsi_data); if (val64 != 0x5A5A5A5A5A5A5A5AULL) { fail = 1; - DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n"); + DBG_PRINT(ERR_DBG, "Write Test level %d fails\n", 1); } val64 = 0xA5A5A5A5A5A5A5A5ULL; @@ -5972,7 +5972,7 @@ static int s2io_register_test(struct s2io_nic *sp, uint64_t *data) val64 = readq(&bar0->xmsi_data); if (val64 != 0xA5A5A5A5A5A5A5A5ULL) { fail = 1; - DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n"); + DBG_PRINT(ERR_DBG, "Write Test level %d fails\n", 2); } *data = fail; @@ -6825,8 +6825,9 @@ static void s2io_set_link(struct work_struct *work) } nic->device_enabled_once = true; } else { - DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name); - DBG_PRINT(ERR_DBG, "device is not Quiescent\n"); + DBG_PRINT(ERR_DBG, + "%s: Error: device is not Quiescent\n", + dev->name); s2io_stop_all_tx_queue(nic); } } @@ -6876,9 +6877,9 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, } else { *skb = dev_alloc_skb(size); if (!(*skb)) { - DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); - DBG_PRINT(INFO_DBG, "memory to allocate "); - DBG_PRINT(INFO_DBG, "1 buf mode SKBs\n"); + DBG_PRINT(INFO_DBG, + "%s: Out of memory to allocate %s\n", + dev->name, "1 buf mode SKBs"); stats->mem_alloc_fail_cnt++; return -ENOMEM ; } @@ -6905,9 +6906,10 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, } else { *skb = dev_alloc_skb(size); if (!(*skb)) { - DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); - DBG_PRINT(INFO_DBG, "memory to allocate "); - DBG_PRINT(INFO_DBG, "2 buf mode SKBs\n"); + DBG_PRINT(INFO_DBG, + "%s: Out of memory to allocate %s\n", + dev->name, + "2 buf mode SKBs"); stats->mem_alloc_fail_cnt++; return -ENOMEM; } @@ -7095,8 +7097,8 @@ static int s2io_add_isr(struct s2io_nic *sp) } if (!err) { pr_info("MSI-X-RX %d entries enabled\n", --msix_rx_cnt); - DBG_PRINT(INFO_DBG, "MSI-X-TX entries enabled" - " through alarm vector\n"); + DBG_PRINT(INFO_DBG, + "MSI-X-TX entries enabled through alarm vector\n"); } } if (sp->config.intr_type == INTA) { @@ -7176,8 +7178,8 @@ static void do_s2io_card_down(struct s2io_nic *sp, int do_io) msleep(50); cnt++; if (cnt == 10) { - DBG_PRINT(ERR_DBG, "s2io_close:Device not Quiescent "); - DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n", + DBG_PRINT(ERR_DBG, "Device not Quiescent - " + "adapter status reads 0x%llx\n", (unsigned long long)val64); break; } @@ -7628,7 +7630,7 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, u8 *dev_multiq) { if ((tx_fifo_num > MAX_TX_FIFOS) || (tx_fifo_num < 1)) { - DBG_PRINT(ERR_DBG, "s2io: Requested number of tx fifos " + DBG_PRINT(ERR_DBG, "Requested number of tx fifos " "(%d) not supported\n", tx_fifo_num); if (tx_fifo_num < 1) @@ -7636,8 +7638,7 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, else tx_fifo_num = MAX_TX_FIFOS; - DBG_PRINT(ERR_DBG, "s2io: Default to %d ", tx_fifo_num); - DBG_PRINT(ERR_DBG, "tx fifos\n"); + DBG_PRINT(ERR_DBG, "Default to %d tx fifos\n", tx_fifo_num); } if (multiq) @@ -7646,7 +7647,7 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, if (tx_steering_type && (1 == tx_fifo_num)) { if (tx_steering_type != TX_DEFAULT_STEERING) DBG_PRINT(ERR_DBG, - "s2io: Tx steering is not supported with " + "Tx steering is not supported with " "one fifo. Disabling Tx steering.\n"); tx_steering_type = NO_STEERING; } @@ -7654,21 +7655,21 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, if ((tx_steering_type < NO_STEERING) || (tx_steering_type > TX_DEFAULT_STEERING)) { DBG_PRINT(ERR_DBG, - "s2io: Requested transmit steering not supported\n"); - DBG_PRINT(ERR_DBG, "s2io: Disabling transmit steering\n"); + "Requested transmit steering not supported\n"); + DBG_PRINT(ERR_DBG, "Disabling transmit steering\n"); tx_steering_type = NO_STEERING; } if (rx_ring_num > MAX_RX_RINGS) { DBG_PRINT(ERR_DBG, - "s2io: Requested number of rx rings not supported\n"); - DBG_PRINT(ERR_DBG, "s2io: Default to %d rx rings\n", + "Requested number of rx rings not supported\n"); + DBG_PRINT(ERR_DBG, "Default to %d rx rings\n", MAX_RX_RINGS); rx_ring_num = MAX_RX_RINGS; } if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) { - DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. " + DBG_PRINT(ERR_DBG, "Wrong intr_type requested. " "Defaulting to INTA\n"); *dev_intr_type = INTA; } @@ -7676,14 +7677,14 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, if ((*dev_intr_type == MSI_X) && ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { - DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. " + DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. " "Defaulting to INTA\n"); *dev_intr_type = INTA; } if ((rx_ring_mode != 1) && (rx_ring_mode != 2)) { - DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n"); - DBG_PRINT(ERR_DBG, "s2io: Defaulting to 1-buffer mode\n"); + DBG_PRINT(ERR_DBG, "Requested ring mode not supported\n"); + DBG_PRINT(ERR_DBG, "Defaulting to 1-buffer mode\n"); rx_ring_mode = 1; } return SUCCESS; @@ -7776,12 +7777,12 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) ret = pci_enable_device(pdev); if (ret) { DBG_PRINT(ERR_DBG, - "s2io_init_nic: pci_enable_device failed\n"); + "%s: pci_enable_device failed\n", __func__); return ret; } if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n"); + DBG_PRINT(INIT_DBG, "%s: Using 64bit DMA\n", __func__); dma_flag = true; if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { DBG_PRINT(ERR_DBG, @@ -7791,14 +7792,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) return -ENOMEM; } } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n"); + DBG_PRINT(INIT_DBG, "%s: Using 32bit DMA\n", __func__); } else { pci_disable_device(pdev); return -ENOMEM; } ret = pci_request_regions(pdev, s2io_driver_name); if (ret) { - DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", + DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x\n", __func__, ret); pci_disable_device(pdev); return -ENODEV; @@ -7992,7 +7993,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Setting swapper control on the NIC, for proper reset operation */ if (s2io_set_swapper(sp)) { - DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n", + DBG_PRINT(ERR_DBG, "%s: swapper settings are wrong\n", dev->name); ret = -EAGAIN; goto set_swap_failed; @@ -8002,8 +8003,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (sp->device_type & XFRAME_II_DEVICE) { mode = s2io_verify_pci_mode(sp); if (mode < 0) { - DBG_PRINT(ERR_DBG, "%s: ", __func__); - DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n"); + DBG_PRINT(ERR_DBG, "%s: Unsupported PCI bus mode\n", + __func__); ret = -EBADSLT; goto set_swap_failed; } @@ -8021,7 +8022,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (ret) { DBG_PRINT(ERR_DBG, - "s2io: MSI-X requested but failed to enable\n"); + "MSI-X requested but failed to enable\n"); sp->config.intr_type = INTA; } } @@ -8137,12 +8138,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->product_name, pdev->revision); DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, s2io_driver_version); - DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %pM\n", dev->name, dev->dev_addr); - DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num); + DBG_PRINT(ERR_DBG, "%s: MAC Address: %pM\n", dev->name, dev->dev_addr); + DBG_PRINT(ERR_DBG, "Serial number: %s\n", sp->serial_num); if (sp->device_type & XFRAME_II_DEVICE) { mode = s2io_print_pci_mode(sp); if (mode < 0) { - DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n"); ret = -EBADSLT; unregister_netdev(dev); goto set_swap_failed; @@ -8532,8 +8532,9 @@ static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, *lro = l_lro; if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) { - DBG_PRINT(INFO_DBG, "%s:Out of order. expected " - "0x%x, actual 0x%x\n", __func__, + DBG_PRINT(INFO_DBG, "%s: Out of sequence. " + "expected 0x%x, actual 0x%x\n", + __func__, (*lro)->tcp_next_seq, ntohl(tcph->seq)); @@ -8571,7 +8572,7 @@ static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, } if (ret == 0) { /* sessions exceeded */ - DBG_PRINT(INFO_DBG, "%s:All LRO sessions already in use\n", + DBG_PRINT(INFO_DBG, "%s: All LRO sessions already in use\n", __func__); *lro = NULL; return ret; @@ -8593,7 +8594,7 @@ static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, } break; default: - DBG_PRINT(ERR_DBG, "%s:Dont know, can't say!!\n", __func__); + DBG_PRINT(ERR_DBG, "%s: Don't know, can't say!!\n", __func__); break; } diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index d5c5be6..47c36e0 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -64,7 +64,10 @@ enum { static int debug_level = ERR_DBG; /* DEBUG message print. */ -#define DBG_PRINT(dbg_level, args...) if(!(debug_level= debug_level) \ + pr_info(fmt, ##args); \ + } while (0) /* Protocol assist features of the NIC */ #define L3_CKSUM_OK 0xFFFF -- cgit v0.10.2 From 2bf2901669a564b402cd0e40eb3f941c391e64c4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 31 Aug 2009 15:56:54 +1000 Subject: crypto: api - Do not displace newly registered algorithms We have a mechanism where newly registered algorithms of a higher priority can displace existing instances that use a different implementation of the same algorithm with a lower priority. Unfortunately the same mechanism can cause a newly registered algorithm to displace itself if it depends on an existing version of the same algorithm. This patch fixes this by keeping all algorithms that the newly reigstered algorithm depends on, thus protecting them from being removed. Signed-off-by: Herbert Xu diff --git a/crypto/algapi.c b/crypto/algapi.c index 6a98076..feb77e4 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -81,16 +81,35 @@ static void crypto_destroy_instance(struct crypto_alg *alg) crypto_tmpl_put(tmpl); } +static struct list_head *crypto_more_spawns(struct crypto_alg *alg, + struct list_head *stack, + struct list_head *top, + struct list_head *secondary_spawns) +{ + struct crypto_spawn *spawn, *n; + + if (list_empty(stack)) + return NULL; + + spawn = list_first_entry(stack, struct crypto_spawn, list); + n = list_entry(spawn->list.next, struct crypto_spawn, list); + + if (spawn->alg && &n->list != stack && !n->alg) + n->alg = (n->list.next == stack) ? alg : + &list_entry(n->list.next, struct crypto_spawn, + list)->inst->alg; + + list_move(&spawn->list, secondary_spawns); + + return &n->list == stack ? top : &n->inst->alg.cra_users; +} + static void crypto_remove_spawn(struct crypto_spawn *spawn, - struct list_head *list, - struct list_head *secondary_spawns) + struct list_head *list) { struct crypto_instance *inst = spawn->inst; struct crypto_template *tmpl = inst->tmpl; - list_del_init(&spawn->list); - spawn->alg = NULL; - if (crypto_is_dead(&inst->alg)) return; @@ -106,25 +125,55 @@ static void crypto_remove_spawn(struct crypto_spawn *spawn, hlist_del(&inst->list); inst->alg.cra_destroy = crypto_destroy_instance; - list_splice(&inst->alg.cra_users, secondary_spawns); + BUG_ON(!list_empty(&inst->alg.cra_users)); } -static void crypto_remove_spawns(struct list_head *spawns, - struct list_head *list, u32 new_type) +static void crypto_remove_spawns(struct crypto_alg *alg, + struct list_head *list, + struct crypto_alg *nalg) { + u32 new_type = (nalg ?: alg)->cra_flags; struct crypto_spawn *spawn, *n; LIST_HEAD(secondary_spawns); + struct list_head *spawns; + LIST_HEAD(stack); + LIST_HEAD(top); + spawns = &alg->cra_users; list_for_each_entry_safe(spawn, n, spawns, list) { if ((spawn->alg->cra_flags ^ new_type) & spawn->mask) continue; - crypto_remove_spawn(spawn, list, &secondary_spawns); + list_move(&spawn->list, &top); } - while (!list_empty(&secondary_spawns)) { - list_for_each_entry_safe(spawn, n, &secondary_spawns, list) - crypto_remove_spawn(spawn, list, &secondary_spawns); + spawns = ⊤ + do { + while (!list_empty(spawns)) { + struct crypto_instance *inst; + + spawn = list_first_entry(spawns, struct crypto_spawn, + list); + inst = spawn->inst; + + BUG_ON(&inst->alg == alg); + + list_move(&spawn->list, &stack); + + if (&inst->alg == nalg) + break; + + spawn->alg = NULL; + spawns = &inst->alg.cra_users; + } + } while ((spawns = crypto_more_spawns(alg, &stack, &top, + &secondary_spawns))); + + list_for_each_entry_safe(spawn, n, &secondary_spawns, list) { + if (spawn->alg) + list_move(&spawn->list, &spawn->alg->cra_users); + else + crypto_remove_spawn(spawn, list); } } @@ -258,7 +307,7 @@ found: q->cra_priority > alg->cra_priority) continue; - crypto_remove_spawns(&q->cra_users, &list, alg->cra_flags); + crypto_remove_spawns(q, &list, alg); } complete: @@ -330,7 +379,7 @@ static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list) crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg); list_del_init(&alg->cra_list); - crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags); + crypto_remove_spawns(alg, list, NULL); return 0; } -- cgit v0.10.2 From e9af4f365fee8065c0c1b2389fe10e540dd9d60a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 29 Aug 2009 23:23:08 +0200 Subject: ALSA: hda - Fix ALC268/ALC269 headphone pin routing Fix the headphone pin routing of ALC268/ALC269 codecs. Using alc882 routine doesn't work because alc268/alc269 parser assumes the independent DACs for both HP and speaker outputs. Need to assign the DAC depending on the pin. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d572db6..bc17a96 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -12303,6 +12303,42 @@ static int alc268_auto_create_input_ctls(struct hda_codec *codec, return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24); } +static void alc268_auto_set_output_and_unmute(struct hda_codec *codec, + hda_nid_t nid, int pin_type) +{ + int idx; + + alc_set_pin_output(codec, nid, pin_type); + if (nid == 0x14 || nid == 0x16) + idx = 0; + else + idx = 1; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); +} + +static void alc268_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid = spec->autocfg.line_out_pins[0]; + if (nid) { + int pin_type = get_pin_type(spec->autocfg.line_out_type); + alc268_auto_set_output_and_unmute(codec, nid, pin_type); + } +} + +static void alc268_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) + alc268_auto_set_output_and_unmute(codec, pin, PIN_HP); + pin = spec->autocfg.speaker_pins[0]; + if (pin) + alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT); +} + static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -12311,9 +12347,10 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) hda_nid_t line_nid = spec->autocfg.line_out_pins[0]; unsigned int dac_vol1, dac_vol2; - if (speaker_nid) { + if (line_nid == 0x1d || speaker_nid == 0x1d) { snd_hda_codec_write(codec, speaker_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + /* mute mixer inputs from 0x1d */ snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)); @@ -12321,6 +12358,7 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)); } else { + /* unmute mixer inputs from 0x1d */ snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)); snd_hda_codec_write(codec, 0x10, 0, @@ -12408,8 +12446,6 @@ static int alc268_parse_auto_config(struct hda_codec *codec) return 1; } -#define alc268_auto_init_multi_out alc882_auto_init_multi_out -#define alc268_auto_init_hp_out alc882_auto_init_hp_out #define alc268_auto_init_analog_input alc882_auto_init_analog_input /* init callback for auto-configuration model -- overriding the default init */ @@ -13220,8 +13256,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec) return 1; } -#define alc269_auto_init_multi_out alc882_auto_init_multi_out -#define alc269_auto_init_hp_out alc882_auto_init_hp_out +#define alc269_auto_init_multi_out alc268_auto_init_multi_out +#define alc269_auto_init_hp_out alc268_auto_init_hp_out #define alc269_auto_init_analog_input alc882_auto_init_analog_input -- cgit v0.10.2 From 17bbaa6f600a36930879fd58e4e38a8c25bf9b60 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 30 Aug 2009 12:15:59 +0200 Subject: ALSA: hda - Add support of docking auto-mute/mic for AD1984A laptop model Add the support of automatic mute and mic-switching of the docking station HP and mic plugs for AD1984A laptop model for some HP machines. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index f22c3c0..570e072 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3703,19 +3703,29 @@ static struct hda_amp_list ad1884a_loopbacks[] = { * Port F: Internal speakers */ -static struct hda_input_mux ad1884a_laptop_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, /* port-B */ - { "Internal Mic", 0x1 }, /* port-C */ - { "Dock Mic", 0x4 }, /* port-E */ - { "Mix", 0x3 }, - }, -}; +static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + int mute = (!ucontrol->value.integer.value[0] && + !ucontrol->value.integer.value[1]); + /* toggle GPIO1 according to the mute state */ + snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + mute ? 0x02 : 0x0); + return ret; +} static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = ad1884a_mobile_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + }, HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), @@ -3730,36 +3740,9 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, { } /* end */ }; -static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - int mute = (!ucontrol->value.integer.value[0] && - !ucontrol->value.integer.value[1]); - /* toggle GPIO1 according to the mute state */ - snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - mute ? 0x02 : 0x0); - return ret; -} - static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ @@ -3829,6 +3812,63 @@ static int ad1884a_hp_init(struct hda_codec *codec) return 0; } +/* mute internal speaker if HP or docking HP is plugged */ +static void ad1884a_laptop_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0); + present &= AC_PINSENSE_PRESENCE; + if (!present) { + present = snd_hda_codec_read(codec, 0x12, 0, + AC_VERB_GET_PIN_SENSE, 0); + present &= AC_PINSENSE_PRESENCE; + } + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, + present ? 0x00 : 0x02); +} + +/* switch to external mic if plugged */ +static void ad1884a_laptop_automic(struct hda_codec *codec) +{ + unsigned int idx; + + if (snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & + AC_PINSENSE_PRESENCE) + idx = 0; + else if (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & + AC_PINSENSE_PRESENCE) + idx = 4; + else + idx = 1; + snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx); +} + +/* unsolicited event for HP jack sensing */ +static void ad1884a_laptop_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case AD1884A_HP_EVENT: + ad1884a_laptop_automute(codec); + break; + case AD1884A_MIC_EVENT: + ad1884a_laptop_automic(codec); + break; + } +} + +/* initialize jack-sensing, too */ +static int ad1884a_laptop_init(struct hda_codec *codec) +{ + ad198x_init(codec); + ad1884a_laptop_automute(codec); + ad1884a_laptop_automic(codec); + return 0; +} + /* additional verbs for laptop model */ static struct hda_verb ad1884a_laptop_verbs[] = { /* Port-A (HP) pin - always unmuted */ @@ -3849,7 +3889,9 @@ static struct hda_verb ad1884a_laptop_verbs[] = { {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* unsolicited event for pin-sense */ {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, + {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, { } /* end */ }; @@ -4059,9 +4101,8 @@ static int patch_ad1884a(struct hda_codec *codec) spec->mixers[0] = ad1884a_laptop_mixers; spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1884a_laptop_capture_source; - codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; - codec->patch_ops.init = ad1884a_hp_init; + codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event; + codec->patch_ops.init = ad1884a_laptop_init; /* set the upper-limit for mixer amp to 0dB for avoiding the * possible damage by overloading */ -- cgit v0.10.2 From fe7e56814cb82eb28698c2a74bdb830ae0592a45 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 31 Aug 2009 08:37:46 +0200 Subject: ALSA: hda - Add missing GPIO initialization for AD1984A laptop model A similar initialization of GPIO1 pin like mobile model is needed for laptop model, too. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 570e072..db3f3b1 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3892,6 +3892,10 @@ static struct hda_verb ad1884a_laptop_verbs[] = { {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, + /* allow to touch GPIO1 (for mute control) */ + {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ { } /* end */ }; -- cgit v0.10.2 From ec7ba4ea1d605029fb09601ab4ad3053bc1f519c Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 31 Aug 2009 03:32:03 +0200 Subject: perf tools: Add missing parameters documentation Add missing documentation for the following parameters: - perf record -R - perf report -g Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo LKML-Reference: <1251682323-10395-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 6be696b..0ff23de 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -91,6 +91,10 @@ OPTIONS --no-samples:: Don't sample. +-R:: +--raw-samples:: +Collect raw sample records from all opened counters (typically for tracepoint counters). + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 370344a..59f0b84 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -51,6 +51,16 @@ OPTIONS all occurances of this separator in symbol names (and other output) with a '.' character, that thus it's the only non valid separator. +-g [type,min]:: +--call-graph:: + Display callchains using type and min percent threshold. + type can be either: + - flat: single column, linear exposure of callchains. + - graph: use a graph tree, displaying absolute overhead rates. + - fractal: like graph, but displays relative rates. Each branch of + the tree is considered as a new profiled object. + + Default: fractal,0.5. + SEE ALSO -------- linkperf:perf-stat[1] -- cgit v0.10.2 From 5b447a6a13ea823b698bf4c01193654fd7ebf4ec Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 31 Aug 2009 06:45:18 +0200 Subject: perf tools: Librarize idle thread registration Librarize register_idle_thread() used by annotate and report. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo LKML-Reference: <1251693921-6579-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 4c7bc44..043d85b 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -472,17 +472,6 @@ static void output__resort(void) } } -static void register_idle_thread(void) -{ - struct thread *thread = threads__findnew(0, &threads, &last_match); - - if (thread == NULL || - thread__set_comm(thread, "[idle]")) { - fprintf(stderr, "problem inserting idle task.\n"); - exit(-1); - } -} - static unsigned long total = 0, total_mmap = 0, total_comm = 0, @@ -970,7 +959,7 @@ static int __cmd_annotate(void) uint32_t size; char *buf; - register_idle_thread(); + register_idle_thread(&threads, &last_match); input = open(input_name, O_RDONLY); if (input < 0) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index cdd46ab..cdf9a8d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -666,12 +666,9 @@ static void dso__calc_col_width(struct dso *self) self->slen_calculated = 1; } -static int thread__set_comm_adjust(struct thread *self, const char *comm) +static void thread__comm_adjust(struct thread *self) { - int ret = thread__set_comm(self, comm); - - if (ret) - return ret; + char *comm = self->comm; if (!col_width_list_str && !field_sep && (!comm_list || strlist__has_entry(comm_list, comm))) { @@ -682,6 +679,16 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm) threads__col_width = slen + 6; } } +} + +static int thread__set_comm_adjust(struct thread *self, const char *comm) +{ + int ret = thread__set_comm(self, comm); + + if (ret) + return ret; + + thread__comm_adjust(self); return 0; } @@ -1073,17 +1080,6 @@ print_entries: return ret; } -static void register_idle_thread(void) -{ - struct thread *thread = threads__findnew(0, &threads, &last_match); - - if (thread == NULL || - thread__set_comm_adjust(thread, "[idle]")) { - fprintf(stderr, "problem inserting idle task.\n"); - exit(-1); - } -} - static unsigned long total = 0, total_mmap = 0, total_comm = 0, @@ -1381,11 +1377,13 @@ static int __cmd_report(void) unsigned long offset = 0; unsigned long head, shift; struct stat input_stat; + struct thread *idle; event_t *event; uint32_t size; char *buf; - register_idle_thread(); + idle = register_idle_thread(&threads, &last_match); + thread__comm_adjust(idle); if (show_threads) perf_read_values_init(&show_threads_values); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index f98032c..3acd37f 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -80,6 +80,19 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) return th; } +struct thread * +register_idle_thread(struct rb_root *threads, struct thread **last_match) +{ + struct thread *thread = threads__findnew(0, threads, last_match); + + if (!thread || thread__set_comm(thread, "[idle]")) { + fprintf(stderr, "problem inserting idle task.\n"); + exit(-1); + } + + return thread; +} + void thread__insert_map(struct thread *self, struct map *map) { struct map *pos, *tmp; diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index b1c6671..634f280 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -13,6 +13,8 @@ struct thread { int thread__set_comm(struct thread *self, const char *comm); struct thread * threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); +struct thread * +register_idle_thread(struct rb_root *threads, struct thread **last_match); void thread__insert_map(struct thread *self, struct map *map); int thread__fork(struct thread *self, struct thread *parent); struct map *thread__find_map(struct thread *self, u64 ip); -- cgit v0.10.2 From 3a2684ca58e06941ff00e3f096ca44f898a6d13e Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 31 Aug 2009 06:45:19 +0200 Subject: perf tools: Resolve idle thread cmdline for perf trace The cmd-trace tool used the cmdline file and resolved the idle thread using a hardcoded check for the 0 task pid. Now we have a centralized way to do that from perf using register_idle_thread() API. Before: :0-0 [000] 0.000000: irq_handler_entry: irq=0 handler=name :0-0 [000] 0.000000: irq_handler_entry: irq=0 handler=name After: [idle]-0 [000] 0.000000: irq_handler_entry: irq=0 handler=name [idle]-0 [000] 0.000000: irq_handler_entry: irq=0 handler=name Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo LKML-Reference: <1251693921-6579-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index dd3c2e7..8247fd0 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -164,6 +164,7 @@ static int __cmd_trace(void) char *buf; trace_report(); + register_idle_thread(&threads, &last_match); input = open(input_name, O_RDONLY); if (input < 0) { -- cgit v0.10.2 From 9b8055a52c8986167e0a7357460d528a00db67e6 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 31 Aug 2009 06:45:20 +0200 Subject: perf tools: Unify swapper tasks naming In perf tools, we hardcode the pid 0 cmdline resolving to "idle" because the init task is not included in the COMM events. But the idle tasks secondary cpus are resolved into their "init" name through the COMM events. We have then such strange result in perf report (ditto with trace): 19.66% init [kernel] [k] acpi_idle_enter_c1 17.32% [idle] [kernel] [k] acpi_idle_enter_c1 It's then better to unify the swapper tasks into a single init name. Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo LKML-Reference: <1251693921-6579-3-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 3acd37f..7635928 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -85,7 +85,7 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match) { struct thread *thread = threads__findnew(0, threads, last_match); - if (!thread || thread__set_comm(thread, "[idle]")) { + if (!thread || thread__set_comm(thread, "[init]")) { fprintf(stderr, "problem inserting idle task.\n"); exit(-1); } -- cgit v0.10.2 From 561f732c1233f6bf7c3c5c5fb9b4d90bb6c107aa Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 31 Aug 2009 06:45:21 +0200 Subject: perf tools: Complete support for dynamic strings Complete support for __str_loc type strings of ftrace events which have dynamic offsets values set for each of them inside their sammples. Before: geany-5759 [000] 0.000000: lock_release: name geany-5759 [000] 0.000000: lock_release: name geany-5759 [000] 0.000000: lock_release: name kondemand/0-362 [000] 0.000000: lock_release: name pdflush-421 [000] 0.000000: lock_release: name After: geany-5759 [000] 0.000000: lock_release: &u->lock geany-5759 [000] 0.000000: lock_release: key geany-5759 [000] 0.000000: lock_release: &group->notification_mutex kondemand/0-362 [000] 0.000000: lock_release: &rq->lock pdflush-421 [000] 0.000000: lock_release: &rq->lock Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Steven Rostedt LKML-Reference: <1251693921-6579-4-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Steven Rostedt diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 96c5e97..665dac2 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1548,6 +1548,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok) arg->type = PRINT_STRING; arg->string.string = token; + arg->string.offset = -1; if (read_expected(EVENT_DELIM, (char *)")") < 0) return EVENT_ERROR; @@ -2031,9 +2032,20 @@ static void print_str_arg(void *data, int size, case PRINT_TYPE: break; - case PRINT_STRING: - printf("%s", arg->string.string); + case PRINT_STRING: { + int str_offset; + + if (arg->string.offset == -1) { + struct format_field *f; + + f = find_any_field(event, arg->string.string); + arg->string.offset = f->offset; + } + str_offset = *(int *)(data + arg->string.offset); + str_offset &= 0xffff; + printf("%s", ((char *)data) + str_offset); break; + } case PRINT_OP: /* * The only op for string should be ? : diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 051fcf3..420294a 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -50,6 +50,7 @@ struct print_arg_atom { struct print_arg_string { char *string; + int offset; }; struct print_arg_field { -- cgit v0.10.2 From 8e254c1d183f0225ad21f9049641529e56cce4da Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 31 Aug 2009 16:49:41 +0800 Subject: tracing/filters: Defer pred allocation init_preds() allocates about 5392 bytes of memory (on x86_32) for a TRACE_EVENT. With my config, at system boot total memory occupied is: 5392 * (642 + 15) == 3459KB 642 == cat available_events | wc -l 15 == number of dirs in events/ftrace That's quite a lot, so we'd better defer memory allocation util it's needed, that's when filter is used. Signed-off-by: Li Zefan Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Tom Zanussi Cc: Masami Hiramatsu LKML-Reference: <4A9B8EA5.6020700@cn.fujitsu.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index ace2da9..7554804 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -133,7 +133,6 @@ struct ftrace_event_call { #define MAX_FILTER_PRED 32 #define MAX_FILTER_STR_VAL 128 -extern int init_preds(struct ftrace_event_call *call); extern void destroy_preds(struct ftrace_event_call *call); extern int filter_match_preds(struct ftrace_event_call *call, void *rec); extern int filter_current_check_discard(struct ftrace_event_call *call, diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index f124c89..a8e3782 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -177,7 +177,6 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \ event_enter_##sname.id = id; \ set_syscall_enter_id(num, id); \ INIT_LIST_HEAD(&event_enter_##sname.fields); \ - init_preds(&event_enter_##sname); \ return 0; \ } \ TRACE_SYS_ENTER_PROFILE(sname); \ @@ -214,7 +213,6 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \ event_exit_##sname.id = id; \ set_syscall_exit_id(num, id); \ INIT_LIST_HEAD(&event_exit_##sname.fields); \ - init_preds(&event_exit_##sname); \ return 0; \ } \ TRACE_SYS_EXIT_PROFILE(sname); \ diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 57c56a9..bfbc842 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -622,7 +622,6 @@ static int ftrace_raw_init_event_##call(void) \ return -ENODEV; \ event_##call.id = id; \ INIT_LIST_HEAD(&event_##call.fields); \ - init_preds(&event_##call); \ return 0; \ } \ \ diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 9f03082..c6b2edf 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -309,7 +309,7 @@ void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s) struct event_filter *filter = call->filter; mutex_lock(&event_mutex); - if (filter->filter_string) + if (filter && filter->filter_string) trace_seq_printf(s, "%s\n", filter->filter_string); else trace_seq_printf(s, "none\n"); @@ -322,7 +322,7 @@ void print_subsystem_event_filter(struct event_subsystem *system, struct event_filter *filter = system->filter; mutex_lock(&event_mutex); - if (filter->filter_string) + if (filter && filter->filter_string) trace_seq_printf(s, "%s\n", filter->filter_string); else trace_seq_printf(s, "none\n"); @@ -390,6 +390,9 @@ void destroy_preds(struct ftrace_event_call *call) struct event_filter *filter = call->filter; int i; + if (!filter) + return; + for (i = 0; i < MAX_FILTER_PRED; i++) { if (filter->preds[i]) filter_free_pred(filter->preds[i]); @@ -400,7 +403,7 @@ void destroy_preds(struct ftrace_event_call *call) call->filter = NULL; } -int init_preds(struct ftrace_event_call *call) +static int init_preds(struct ftrace_event_call *call) { struct event_filter *filter; struct filter_pred *pred; @@ -410,7 +413,6 @@ int init_preds(struct ftrace_event_call *call) if (!call->filter) return -ENOMEM; - call->filter_active = 0; filter->n_preds = 0; filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL); @@ -432,7 +434,28 @@ oom: return -ENOMEM; } -EXPORT_SYMBOL_GPL(init_preds); + +static int init_subsystem_preds(struct event_subsystem *system) +{ + struct ftrace_event_call *call; + int err; + + list_for_each_entry(call, &ftrace_events, list) { + if (!call->define_fields) + continue; + + if (strcmp(call->system, system->name) != 0) + continue; + + if (!call->filter) { + err = init_preds(call); + if (err) + return err; + } + } + + return 0; +} enum { FILTER_DISABLE_ALL, @@ -449,6 +472,9 @@ static void filter_free_subsystem_preds(struct event_subsystem *system, if (!call->define_fields) continue; + if (strcmp(call->system, system->name) != 0) + continue; + if (flag == FILTER_INIT_NO_RESET) { call->filter->no_reset = false; continue; @@ -457,10 +483,8 @@ static void filter_free_subsystem_preds(struct event_subsystem *system, if (flag == FILTER_SKIP_NO_RESET && call->filter->no_reset) continue; - if (!strcmp(call->system, system->name)) { - filter_disable_preds(call); - remove_filter_string(call->filter); - } + filter_disable_preds(call); + remove_filter_string(call->filter); } } @@ -1094,6 +1118,10 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) mutex_lock(&event_mutex); + err = init_preds(call); + if (err) + goto out_unlock; + if (!strcmp(strstrip(filter_string), "0")) { filter_disable_preds(call); remove_filter_string(call->filter); @@ -1139,6 +1167,10 @@ int apply_subsystem_event_filter(struct event_subsystem *system, mutex_lock(&event_mutex); + err = init_subsystem_preds(system); + if (err) + goto out_unlock; + if (!strcmp(strstrip(filter_string), "0")) { filter_free_subsystem_preds(system, FILTER_DISABLE_ALL); remove_filter_string(system->filter); diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index 029a91f..df1bf6e 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c @@ -135,7 +135,6 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ static int ftrace_raw_init_event_##call(void) \ { \ INIT_LIST_HEAD(&event_##call.fields); \ - init_preds(&event_##call); \ return 0; \ } \ -- cgit v0.10.2 From 1e66dafc75f40a08b2addb82779987b269b4ca23 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 31 Aug 2009 14:18:48 +0200 Subject: ipvs: Use atomic operations atomicly A pointed out by Shin Hong, IPVS doesn't always use atomic operations in an atomic manner. While this seems unlikely to be manifest in strange behaviour, it seems appropriate to clean this up. Cc: shin hong Signed-off-by: Simon Horman Signed-off-by: Patrick McHardy diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index b227750..a986ee2 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1259,7 +1259,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, struct ip_vs_iphdr iph; struct ip_vs_protocol *pp; struct ip_vs_conn *cp; - int ret, restart, af; + int ret, restart, af, pkts; af = (skb->protocol == htons(ETH_P_IP)) ? AF_INET : AF_INET6; @@ -1346,12 +1346,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, * Sync connection if it is about to close to * encorage the standby servers to update the connections timeout */ - atomic_inc(&cp->in_pkts); + pkts = atomic_add_return(1, &cp->in_pkts); if (af == AF_INET && (ip_vs_sync_state & IP_VS_STATE_MASTER) && (((cp->protocol != IPPROTO_TCP || cp->state == IP_VS_TCP_S_ESTABLISHED) && - (atomic_read(&cp->in_pkts) % sysctl_ip_vs_sync_threshold[1] + (pkts % sysctl_ip_vs_sync_threshold[1] == sysctl_ip_vs_sync_threshold[0])) || ((cp->protocol == IPPROTO_TCP) && (cp->old_state != cp->state) && ((cp->state == IP_VS_TCP_S_FIN_WAIT) || diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c index 70ff82cd..6182e8e 100644 --- a/net/netfilter/ipvs/ip_vs_wrr.c +++ b/net/netfilter/ipvs/ip_vs_wrr.c @@ -77,11 +77,12 @@ static int ip_vs_wrr_gcd_weight(struct ip_vs_service *svc) static int ip_vs_wrr_max_weight(struct ip_vs_service *svc) { struct ip_vs_dest *dest; - int weight = 0; + int new_weight, weight = 0; list_for_each_entry(dest, &svc->destinations, n_list) { - if (atomic_read(&dest->weight) > weight) - weight = atomic_read(&dest->weight); + new_weight = atomic_read(&dest->weight); + if (new_weight > weight) + weight = new_weight; } return weight; -- cgit v0.10.2 From ee254fa44d902ab89fd0d66851701098f07872a7 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 31 Aug 2009 14:23:15 +0200 Subject: netfilter: nf_conntrack: netns fix re reliable conntrack event delivery Conntracks in netns other than init_net dying list were never killed. Signed-off-by: Alexey Dobriyan Acked-by: Pablo Neira Ayuso Signed-off-by: Patrick McHardy diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 565c3a8..b371098 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1089,14 +1089,14 @@ void nf_conntrack_flush_report(struct net *net, u32 pid, int report) } EXPORT_SYMBOL_GPL(nf_conntrack_flush_report); -static void nf_ct_release_dying_list(void) +static void nf_ct_release_dying_list(struct net *net) { struct nf_conntrack_tuple_hash *h; struct nf_conn *ct; struct hlist_nulls_node *n; spin_lock_bh(&nf_conntrack_lock); - hlist_nulls_for_each_entry(h, n, &init_net.ct.dying, hnnode) { + hlist_nulls_for_each_entry(h, n, &net->ct.dying, hnnode) { ct = nf_ct_tuplehash_to_ctrack(h); /* never fails to remove them, no listeners at this point */ nf_ct_kill(ct); @@ -1115,7 +1115,7 @@ static void nf_conntrack_cleanup_net(struct net *net) { i_see_dead_people: nf_ct_iterate_cleanup(net, kill_all, NULL); - nf_ct_release_dying_list(); + nf_ct_release_dying_list(net); if (atomic_read(&net->ct.count) != 0) { schedule(); goto i_see_dead_people; -- cgit v0.10.2 From 488908696971c5ea1dcc5d13f29c158ba4f6ae7d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 31 Aug 2009 15:30:31 +0200 Subject: netfilter: ip6t_eui: fix read outside array bounds Use memcmp() instead of open coded comparison that reads one byte past the intended end. Based on patch from Roel Kluin Signed-off-by: Patrick McHardy diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c index db610ba..ca287f6 100644 --- a/net/ipv6/netfilter/ip6t_eui64.c +++ b/net/ipv6/netfilter/ip6t_eui64.c @@ -23,7 +23,6 @@ static bool eui64_mt6(const struct sk_buff *skb, const struct xt_match_param *par) { unsigned char eui64[8]; - int i = 0; if (!(skb_mac_header(skb) >= skb->head && skb_mac_header(skb) + ETH_HLEN <= skb->data) && @@ -42,12 +41,8 @@ eui64_mt6(const struct sk_buff *skb, const struct xt_match_param *par) eui64[4] = 0xfe; eui64[0] ^= 0x02; - i = 0; - while (ipv6_hdr(skb)->saddr.s6_addr[8 + i] == eui64[i] - && i < 8) - i++; - - if (i == 8) + if (!memcmp(ipv6_hdr(skb)->saddr.s6_addr + 8, eui64, + sizeof(eui64))) return true; } } -- cgit v0.10.2 From 94b265514a8398ba3cfecb5a821a027b68a5c38e Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Mon, 31 Aug 2009 16:22:23 +0200 Subject: IPVS: Add handling of incoming ICMPV6 messages Add handling of incoming ICMPv6 messages. This follows the handling of IPv4 ICMP messages. Amongst ther things this problem allows IPVS to behave sensibly when an ICMPV6_PKT_TOOBIG message is received: This message is received when a realserver sends a packet >PMTU to the client. The hop on this path with insufficient MTU will generate an ICMPv6 Packet Too Big message back to the VIP. The LVS server receives this message, but the call to the function handling this has been missing. Thus, IPVS fails to forward the message to the real server, which then does not adjust the path MTU. This patch adds the missing call to ip_vs_in_icmp_v6() in ip_vs_in() to handle this situation. Thanks to Rob Gallagher from HEAnet for reporting this issue and for testing this patch in production (with direct routing mode). [horms@verge.net.au: tweaked changelog] Signed-off-by: Julius Volz Tested-by: Rob Gallagher Signed-off-by: Simon Horman Signed-off-by: Patrick McHardy diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index a986ee2..b95699f 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1277,13 +1277,24 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, return NF_ACCEPT; } - if (unlikely(iph.protocol == IPPROTO_ICMP)) { - int related, verdict = ip_vs_in_icmp(skb, &related, hooknum); +#ifdef CONFIG_IP_VS_IPV6 + if (af == AF_INET6) { + if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { + int related, verdict = ip_vs_in_icmp_v6(skb, &related, hooknum); - if (related) - return verdict; - ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); - } + if (related) + return verdict; + ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); + } + } else +#endif + if (unlikely(iph.protocol == IPPROTO_ICMP)) { + int related, verdict = ip_vs_in_icmp(skb, &related, hooknum); + + if (related) + return verdict; + ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); + } /* Protocol supported? */ pp = ip_vs_proto_get(iph.protocol); -- cgit v0.10.2 From cbbb05703da4b205bb17fde555d3b2926d8b3194 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 31 Aug 2009 16:32:12 +0200 Subject: ALSA: allocation may fail in snd_pcm_oss_change_params() Allocation may fail, show if it did. Signed-off-by: Roel Kluin [Additional fix for invalid runtime->oss.prepare flag set by tiwai] Signed-off-by: Takashi Iwai diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index dbe406b..d35d61b 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1043,10 +1043,15 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) runtime->oss.channels = params_channels(params); runtime->oss.rate = params_rate(params); - runtime->oss.params = 0; - runtime->oss.prepare = 1; vfree(runtime->oss.buffer); runtime->oss.buffer = vmalloc(runtime->oss.period_bytes); + if (!runtime->oss.buffer) { + err = -ENOMEM; + goto failure; + } + + runtime->oss.params = 0; + runtime->oss.prepare = 1; runtime->oss.buffer_used = 0; if (runtime->dma_area) snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes)); -- cgit v0.10.2 From 8307a98097222f4d9c2e62ebccd6f5df439328de Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 31 Aug 2009 14:43:31 +0200 Subject: locking, powerpc: Rename __spin_try_lock() and friends Needed to avoid namespace conflicts when the common code function bodies of _spin_try_lock() etc. are moved to a header file where the function name would be __spin_try_lock(). Signed-off-by: Heiko Carstens Acked-by: Peter Zijlstra Cc: Arnd Bergmann Cc: Nick Piggin Cc: Martin Schwidefsky Cc: Horst Hartmann Cc: Christian Ehrhardt Cc: Andrew Morton Cc: Linus Torvalds Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: LKML-Reference: <20090831124415.918799705@de.ibm.com> Signed-off-by: Ingo Molnar diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h index c3b1931..198266c 100644 --- a/arch/powerpc/include/asm/spinlock.h +++ b/arch/powerpc/include/asm/spinlock.h @@ -54,7 +54,7 @@ * This returns the old value in the lock, so we succeeded * in getting the lock if the return value is 0. */ -static inline unsigned long __spin_trylock(raw_spinlock_t *lock) +static inline unsigned long arch_spin_trylock(raw_spinlock_t *lock) { unsigned long tmp, token; @@ -76,7 +76,7 @@ static inline unsigned long __spin_trylock(raw_spinlock_t *lock) static inline int __raw_spin_trylock(raw_spinlock_t *lock) { CLEAR_IO_SYNC; - return __spin_trylock(lock) == 0; + return arch_spin_trylock(lock) == 0; } /* @@ -108,7 +108,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock) { CLEAR_IO_SYNC; while (1) { - if (likely(__spin_trylock(lock) == 0)) + if (likely(arch_spin_trylock(lock) == 0)) break; do { HMT_low(); @@ -126,7 +126,7 @@ void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) CLEAR_IO_SYNC; while (1) { - if (likely(__spin_trylock(lock) == 0)) + if (likely(arch_spin_trylock(lock) == 0)) break; local_save_flags(flags_dis); local_irq_restore(flags); @@ -181,7 +181,7 @@ extern void __raw_spin_unlock_wait(raw_spinlock_t *lock); * This returns the old value in the lock + 1, * so we got a read lock if the return value is > 0. */ -static inline long __read_trylock(raw_rwlock_t *rw) +static inline long arch_read_trylock(raw_rwlock_t *rw) { long tmp; @@ -205,7 +205,7 @@ static inline long __read_trylock(raw_rwlock_t *rw) * This returns the old value in the lock, * so we got the write lock if the return value is 0. */ -static inline long __write_trylock(raw_rwlock_t *rw) +static inline long arch_write_trylock(raw_rwlock_t *rw) { long tmp, token; @@ -228,7 +228,7 @@ static inline long __write_trylock(raw_rwlock_t *rw) static inline void __raw_read_lock(raw_rwlock_t *rw) { while (1) { - if (likely(__read_trylock(rw) > 0)) + if (likely(arch_read_trylock(rw) > 0)) break; do { HMT_low(); @@ -242,7 +242,7 @@ static inline void __raw_read_lock(raw_rwlock_t *rw) static inline void __raw_write_lock(raw_rwlock_t *rw) { while (1) { - if (likely(__write_trylock(rw) == 0)) + if (likely(arch_write_trylock(rw) == 0)) break; do { HMT_low(); @@ -255,12 +255,12 @@ static inline void __raw_write_lock(raw_rwlock_t *rw) static inline int __raw_read_trylock(raw_rwlock_t *rw) { - return __read_trylock(rw) > 0; + return arch_read_trylock(rw) > 0; } static inline int __raw_write_trylock(raw_rwlock_t *rw) { - return __write_trylock(rw) == 0; + return arch_write_trylock(rw) == 0; } static inline void __raw_read_unlock(raw_rwlock_t *rw) -- cgit v0.10.2 From 9f34ceb60357a7166c929d7b52bd057ad7ffc54b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 31 Aug 2009 14:43:32 +0200 Subject: locking, sparc: Rename __spin_try_lock() and friends Needed to avoid namespace conflicts when the common code function bodies of _spin_try_lock() etc. are moved to a header file where the function name would be __spin_try_lock(). Signed-off-by: Heiko Carstens Acked-by: David S. Miller Acked-by: Peter Zijlstra Cc: Arnd Bergmann Cc: Nick Piggin Cc: Martin Schwidefsky Cc: Horst Hartmann Cc: Christian Ehrhardt Cc: Andrew Morton Cc: Linus Torvalds Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: LKML-Reference: <20090831124416.306495811@de.ibm.com> Signed-off-by: Ingo Molnar diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h index 46f91ab..857630c 100644 --- a/arch/sparc/include/asm/spinlock_32.h +++ b/arch/sparc/include/asm/spinlock_32.h @@ -76,7 +76,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock) * * Unfortunately this scheme limits us to ~16,000,000 cpus. */ -static inline void __read_lock(raw_rwlock_t *rw) +static inline void arch_read_lock(raw_rwlock_t *rw) { register raw_rwlock_t *lp asm("g1"); lp = rw; @@ -92,11 +92,11 @@ static inline void __read_lock(raw_rwlock_t *rw) #define __raw_read_lock(lock) \ do { unsigned long flags; \ local_irq_save(flags); \ - __read_lock(lock); \ + arch_read_lock(lock); \ local_irq_restore(flags); \ } while(0) -static inline void __read_unlock(raw_rwlock_t *rw) +static inline void arch_read_unlock(raw_rwlock_t *rw) { register raw_rwlock_t *lp asm("g1"); lp = rw; @@ -112,7 +112,7 @@ static inline void __read_unlock(raw_rwlock_t *rw) #define __raw_read_unlock(lock) \ do { unsigned long flags; \ local_irq_save(flags); \ - __read_unlock(lock); \ + arch_read_unlock(lock); \ local_irq_restore(flags); \ } while(0) @@ -150,7 +150,7 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw) return (val == 0); } -static inline int __read_trylock(raw_rwlock_t *rw) +static inline int arch_read_trylock(raw_rwlock_t *rw) { register raw_rwlock_t *lp asm("g1"); register int res asm("o0"); @@ -169,7 +169,7 @@ static inline int __read_trylock(raw_rwlock_t *rw) ({ unsigned long flags; \ int res; \ local_irq_save(flags); \ - res = __read_trylock(lock); \ + res = arch_read_trylock(lock); \ local_irq_restore(flags); \ res; \ }) diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h index f6b2b92..43e5147 100644 --- a/arch/sparc/include/asm/spinlock_64.h +++ b/arch/sparc/include/asm/spinlock_64.h @@ -92,7 +92,7 @@ static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long fla /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */ -static void inline __read_lock(raw_rwlock_t *lock) +static void inline arch_read_lock(raw_rwlock_t *lock) { unsigned long tmp1, tmp2; @@ -115,7 +115,7 @@ static void inline __read_lock(raw_rwlock_t *lock) : "memory"); } -static int inline __read_trylock(raw_rwlock_t *lock) +static int inline arch_read_trylock(raw_rwlock_t *lock) { int tmp1, tmp2; @@ -136,7 +136,7 @@ static int inline __read_trylock(raw_rwlock_t *lock) return tmp1; } -static void inline __read_unlock(raw_rwlock_t *lock) +static void inline arch_read_unlock(raw_rwlock_t *lock) { unsigned long tmp1, tmp2; @@ -152,7 +152,7 @@ static void inline __read_unlock(raw_rwlock_t *lock) : "memory"); } -static void inline __write_lock(raw_rwlock_t *lock) +static void inline arch_write_lock(raw_rwlock_t *lock) { unsigned long mask, tmp1, tmp2; @@ -177,7 +177,7 @@ static void inline __write_lock(raw_rwlock_t *lock) : "memory"); } -static void inline __write_unlock(raw_rwlock_t *lock) +static void inline arch_write_unlock(raw_rwlock_t *lock) { __asm__ __volatile__( " stw %%g0, [%0]" @@ -186,7 +186,7 @@ static void inline __write_unlock(raw_rwlock_t *lock) : "memory"); } -static int inline __write_trylock(raw_rwlock_t *lock) +static int inline arch_write_trylock(raw_rwlock_t *lock) { unsigned long mask, tmp1, tmp2, result; @@ -210,14 +210,14 @@ static int inline __write_trylock(raw_rwlock_t *lock) return result; } -#define __raw_read_lock(p) __read_lock(p) -#define __raw_read_lock_flags(p, f) __read_lock(p) -#define __raw_read_trylock(p) __read_trylock(p) -#define __raw_read_unlock(p) __read_unlock(p) -#define __raw_write_lock(p) __write_lock(p) -#define __raw_write_lock_flags(p, f) __write_lock(p) -#define __raw_write_unlock(p) __write_unlock(p) -#define __raw_write_trylock(p) __write_trylock(p) +#define __raw_read_lock(p) arch_read_lock(p) +#define __raw_read_lock_flags(p, f) arch_read_lock(p) +#define __raw_read_trylock(p) arch_read_trylock(p) +#define __raw_read_unlock(p) arch_read_unlock(p) +#define __raw_write_lock(p) arch_write_lock(p) +#define __raw_write_lock_flags(p, f) arch_write_lock(p) +#define __raw_write_unlock(p) arch_write_unlock(p) +#define __raw_write_trylock(p) arch_write_trylock(p) #define __raw_read_can_lock(rw) (!((rw)->lock & 0x80000000UL)) #define __raw_write_can_lock(rw) (!(rw)->lock) -- cgit v0.10.2 From f159ee782990aacb5494738c98f13a2aa61dbb4a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 31 Aug 2009 14:43:33 +0200 Subject: locking, m68k/asm-offsets: Rename pt_regs offset defines In order to be able to use asm-offsets.h in C files the existing namespace conflicts must be solved first. In asm-offsets.h e.g. PT_D0 gets defined which is the offset of the d0 member of the pt_regs structure. However a same define (with a different meaning) exists in asm/ptregs.h. So rename the defines created with the asm-offset mechanism to PT_OFF_D0 etc. There also already exist a few defines with these names that have the same meaning. So remove the existing defines and use the asm-offset generated ones. Signed-off-by: Heiko Carstens Acked-by: Peter Zijlstra Cc: Arnd Bergmann Cc: Nick Piggin Cc: Martin Schwidefsky Cc: Horst Hartmann Cc: Christian Ehrhardt Cc: Andrew Morton Cc: Linus Torvalds Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: LKML-Reference: <20090831124416.666403991@de.ibm.com> Signed-off-by: Ingo Molnar diff --git a/arch/m68k/include/asm/entry_mm.h b/arch/m68k/include/asm/entry_mm.h index 5202f5a..4fcfc28 100644 --- a/arch/m68k/include/asm/entry_mm.h +++ b/arch/m68k/include/asm/entry_mm.h @@ -118,9 +118,6 @@ PT_DTRACE_BIT = 2 #define STR(X) STR1(X) #define STR1(X) #X -#define PT_OFF_ORIG_D0 0x24 -#define PT_OFF_FORMATVEC 0x32 -#define PT_OFF_SR 0x2C #define SAVE_ALL_INT \ "clrl %%sp@-;" /* stk_adj */ \ "pea -1:w;" /* orig d0 = -1 */ \ diff --git a/arch/m68k/include/asm/entry_no.h b/arch/m68k/include/asm/entry_no.h index c2553d2..907ed03 100644 --- a/arch/m68k/include/asm/entry_no.h +++ b/arch/m68k/include/asm/entry_no.h @@ -72,8 +72,8 @@ LENOSYS = 38 lea %sp@(-32),%sp /* space for 8 regs */ moveml %d1-%d5/%a0-%a2,%sp@ movel sw_usp,%a0 /* get usp */ - movel %a0@-,%sp@(PT_PC) /* copy exception program counter */ - movel %a0@-,%sp@(PT_FORMATVEC)/* copy exception format/vector/sr */ + movel %a0@-,%sp@(PT_OFF_PC) /* copy exception program counter */ + movel %a0@-,%sp@(PT_OFF_FORMATVEC)/*copy exception format/vector/sr */ bra 7f 6: clrl %sp@- /* stkadj */ @@ -89,8 +89,8 @@ LENOSYS = 38 bnes 8f /* no, skip */ move #0x2700,%sr /* disable intrs */ movel sw_usp,%a0 /* get usp */ - movel %sp@(PT_PC),%a0@- /* copy exception program counter */ - movel %sp@(PT_FORMATVEC),%a0@-/* copy exception format/vector/sr */ + movel %sp@(PT_OFF_PC),%a0@- /* copy exception program counter */ + movel %sp@(PT_OFF_FORMATVEC),%a0@-/*copy exception format/vector/sr */ moveml %sp@,%d1-%d5/%a0-%a2 lea %sp@(32),%sp /* space for 8 regs */ movel %sp@+,%d0 diff --git a/arch/m68k/include/asm/math-emu.h b/arch/m68k/include/asm/math-emu.h index ddfab96..5e9249b 100644 --- a/arch/m68k/include/asm/math-emu.h +++ b/arch/m68k/include/asm/math-emu.h @@ -145,16 +145,16 @@ extern unsigned int fp_debugprint; * these are only used during instruction decoding * where we always know how deep we're on the stack. */ -#define FPS_DO (PT_D0) -#define FPS_D1 (PT_D1) -#define FPS_D2 (PT_D2) -#define FPS_A0 (PT_A0) -#define FPS_A1 (PT_A1) -#define FPS_A2 (PT_A2) -#define FPS_SR (PT_SR) -#define FPS_PC (PT_PC) -#define FPS_EA (PT_PC+6) -#define FPS_PC2 (PT_PC+10) +#define FPS_DO (PT_OFF_D0) +#define FPS_D1 (PT_OFF_D1) +#define FPS_D2 (PT_OFF_D2) +#define FPS_A0 (PT_OFF_A0) +#define FPS_A1 (PT_OFF_A1) +#define FPS_A2 (PT_OFF_A2) +#define FPS_SR (PT_OFF_SR) +#define FPS_PC (PT_OFF_PC) +#define FPS_EA (PT_OFF_PC+6) +#define FPS_PC2 (PT_OFF_PC+10) .macro fp_get_fp_reg lea (FPD_FPREG,FPDATA,%d0.w*4),%a0 diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c index b1f012f..0cffab8 100644 --- a/arch/m68k/kernel/asm-offsets.c +++ b/arch/m68k/kernel/asm-offsets.c @@ -44,20 +44,20 @@ int main(void) DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags)); /* offsets into the pt_regs */ - DEFINE(PT_D0, offsetof(struct pt_regs, d0)); - DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0)); - DEFINE(PT_D1, offsetof(struct pt_regs, d1)); - DEFINE(PT_D2, offsetof(struct pt_regs, d2)); - DEFINE(PT_D3, offsetof(struct pt_regs, d3)); - DEFINE(PT_D4, offsetof(struct pt_regs, d4)); - DEFINE(PT_D5, offsetof(struct pt_regs, d5)); - DEFINE(PT_A0, offsetof(struct pt_regs, a0)); - DEFINE(PT_A1, offsetof(struct pt_regs, a1)); - DEFINE(PT_A2, offsetof(struct pt_regs, a2)); - DEFINE(PT_PC, offsetof(struct pt_regs, pc)); - DEFINE(PT_SR, offsetof(struct pt_regs, sr)); + DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0)); + DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0)); + DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1)); + DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2)); + DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3)); + DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4)); + DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5)); + DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0)); + DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1)); + DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2)); + DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc)); + DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr)); /* bitfields are a bit difficult */ - DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4); + DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4); /* offsets into the irq_handler struct */ DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler)); diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index c3735cd..922f52e 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -77,17 +77,17 @@ ENTRY(ret_from_fork) jra .Lret_from_exception do_trace_entry: - movel #-ENOSYS,%sp@(PT_D0) | needed for strace + movel #-ENOSYS,%sp@(PT_OFF_D0)| needed for strace subql #4,%sp SAVE_SWITCH_STACK jbsr syscall_trace RESTORE_SWITCH_STACK addql #4,%sp - movel %sp@(PT_ORIG_D0),%d0 + movel %sp@(PT_OFF_ORIG_D0),%d0 cmpl #NR_syscalls,%d0 jcs syscall badsys: - movel #-ENOSYS,%sp@(PT_D0) + movel #-ENOSYS,%sp@(PT_OFF_D0) jra ret_from_syscall do_trace_exit: @@ -103,7 +103,7 @@ ENTRY(ret_from_signal) addql #4,%sp /* on 68040 complete pending writebacks if any */ #ifdef CONFIG_M68040 - bfextu %sp@(PT_VECTOR){#0,#4},%d0 + bfextu %sp@(PT_OFF_FORMATVEC){#0,#4},%d0 subql #7,%d0 | bus error frame ? jbne 1f movel %sp,%sp@- @@ -127,7 +127,7 @@ ENTRY(system_call) jcc badsys syscall: jbsr @(sys_call_table,%d0:l:4)@(0) - movel %d0,%sp@(PT_D0) | save the return value + movel %d0,%sp@(PT_OFF_D0) | save the return value ret_from_syscall: |oriw #0x0700,%sr movew %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0 @@ -135,7 +135,7 @@ ret_from_syscall: 1: RESTORE_ALL syscall_exit_work: - btst #5,%sp@(PT_SR) | check if returning to kernel + btst #5,%sp@(PT_OFF_SR) | check if returning to kernel bnes 1b | if so, skip resched, signals lslw #1,%d0 jcs do_trace_exit @@ -148,7 +148,7 @@ syscall_exit_work: ENTRY(ret_from_exception) .Lret_from_exception: - btst #5,%sp@(PT_SR) | check if returning to kernel + btst #5,%sp@(PT_OFF_SR) | check if returning to kernel bnes 1f | if so, skip resched, signals | only allow interrupts when we are really the last one on the | kernel stack, otherwise stack overflow can occur during @@ -182,7 +182,7 @@ do_signal_return: jbra resume_userspace do_delayed_trace: - bclr #7,%sp@(PT_SR) | clear trace bit in SR + bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR pea 1 | send SIGTRAP movel %curptr,%sp@- pea LSIGTRAP @@ -199,7 +199,7 @@ ENTRY(auto_inthandler) GET_CURRENT(%d0) addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | put exception # in d0 - bfextu %sp@(PT_VECTOR){#4,#10},%d0 + bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0 subw #VEC_SPUR,%d0 movel %sp,%sp@- @@ -216,7 +216,7 @@ ret_from_interrupt: ALIGN ret_from_last_interrupt: moveq #(~ALLOWINT>>8)&0xff,%d0 - andb %sp@(PT_SR),%d0 + andb %sp@(PT_OFF_SR),%d0 jne 2b /* check if we need to do software interrupts */ @@ -232,7 +232,7 @@ ENTRY(user_inthandler) GET_CURRENT(%d0) addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | put exception # in d0 - bfextu %sp@(PT_VECTOR){#4,#10},%d0 + bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0 user_irqvec_fixup = . + 2 subw #VEC_USER,%d0 diff --git a/arch/m68k/math-emu/fp_entry.S b/arch/m68k/math-emu/fp_entry.S index 954b4f3..916c6f3 100644 --- a/arch/m68k/math-emu/fp_entry.S +++ b/arch/m68k/math-emu/fp_entry.S @@ -122,17 +122,17 @@ fp_get_data_reg: .long fp_get_d6, fp_get_d7 fp_get_d0: - move.l (PT_D0+8,%sp),%d0 + move.l (PT_OFF_D0+8,%sp),%d0 printf PREGISTER,"{d0->%08x}",1,%d0 rts fp_get_d1: - move.l (PT_D1+8,%sp),%d0 + move.l (PT_OFF_D1+8,%sp),%d0 printf PREGISTER,"{d1->%08x}",1,%d0 rts fp_get_d2: - move.l (PT_D2+8,%sp),%d0 + move.l (PT_OFF_D2+8,%sp),%d0 printf PREGISTER,"{d2->%08x}",1,%d0 rts @@ -173,35 +173,35 @@ fp_put_data_reg: fp_put_d0: printf PREGISTER,"{d0<-%08x}",1,%d0 - move.l %d0,(PT_D0+8,%sp) + move.l %d0,(PT_OFF_D0+8,%sp) rts fp_put_d1: printf PREGISTER,"{d1<-%08x}",1,%d0 - move.l %d0,(PT_D1+8,%sp) + move.l %d0,(PT_OFF_D1+8,%sp) rts fp_put_d2: printf PREGISTER,"{d2<-%08x}",1,%d0 - move.l %d0,(PT_D2+8,%sp) + move.l %d0,(PT_OFF_D2+8,%sp) rts fp_put_d3: printf PREGISTER,"{d3<-%08x}",1,%d0 | move.l %d0,%d3 - move.l %d0,(PT_D3+8,%sp) + move.l %d0,(PT_OFF_D3+8,%sp) rts fp_put_d4: printf PREGISTER,"{d4<-%08x}",1,%d0 | move.l %d0,%d4 - move.l %d0,(PT_D4+8,%sp) + move.l %d0,(PT_OFF_D4+8,%sp) rts fp_put_d5: printf PREGISTER,"{d5<-%08x}",1,%d0 | move.l %d0,%d5 - move.l %d0,(PT_D5+8,%sp) + move.l %d0,(PT_OFF_D5+8,%sp) rts fp_put_d6: @@ -225,17 +225,17 @@ fp_get_addr_reg: .long fp_get_a6, fp_get_a7 fp_get_a0: - move.l (PT_A0+8,%sp),%a0 + move.l (PT_OFF_A0+8,%sp),%a0 printf PREGISTER,"{a0->%08x}",1,%a0 rts fp_get_a1: - move.l (PT_A1+8,%sp),%a0 + move.l (PT_OFF_A1+8,%sp),%a0 printf PREGISTER,"{a1->%08x}",1,%a0 rts fp_get_a2: - move.l (PT_A2+8,%sp),%a0 + move.l (PT_OFF_A2+8,%sp),%a0 printf PREGISTER,"{a2->%08x}",1,%a0 rts @@ -276,17 +276,17 @@ fp_put_addr_reg: fp_put_a0: printf PREGISTER,"{a0<-%08x}",1,%a0 - move.l %a0,(PT_A0+8,%sp) + move.l %a0,(PT_OFF_A0+8,%sp) rts fp_put_a1: printf PREGISTER,"{a1<-%08x}",1,%a0 - move.l %a0,(PT_A1+8,%sp) + move.l %a0,(PT_OFF_A1+8,%sp) rts fp_put_a2: printf PREGISTER,"{a2<-%08x}",1,%a0 - move.l %a0,(PT_A2+8,%sp) + move.l %a0,(PT_OFF_A2+8,%sp) rts fp_put_a3: -- cgit v0.10.2 From 0ee000e5e8fa2e5c760250be0d78d5906e3eb94b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 31 Aug 2009 14:43:35 +0200 Subject: locking, m68k: Calculate thread_info offset with asm offset m68k has the thread_info structure embedded in its task struct. Therefore its not possible to implement current_thread_info() by looking at the stack pointer and do some simple calculations like most other architectures do it. To return the thread_info pointer for a task two defines are used. This works until the spinlock function bodies get moved into an own header file and CONFIG_SPINLOCK_DEBUG is turned on. That results into this compile error: In file included from include/linux/spinlock.h:378, from include/linux/seqlock.h:29, from include/linux/time.h:8, from include/linux/timex.h:56, from include/linux/sched.h:54, from arch/m68k/kernel/asm-offsets.c:12: include/linux/spinlock_api_smp.h: In function '__spin_unlock_irq': include/linux/spinlock_api_smp.h:371: error: 'current' undeclared (first use in this function) include/linux/spinlock_api_smp.h:371: error: (Each undeclared identifier is reported only once include/linux/spinlock_api_smp.h:371: error: for each function it appears in.) Including asm/current.h to asm-offsets.c wouldn't help since the definition of struct task is needed. So we end up with ugly header file include dependencies. To solve this calculate the offset of the thread_info structure into the task struct in asm-offsets.h and use the offset in task_thread_info(). This works just like it does for IA64 as well. Signed-off-by: Heiko Carstens Acked-by: Peter Zijlstra Cc: Arnd Bergmann Cc: Nick Piggin Cc: Martin Schwidefsky Cc: Horst Hartmann Cc: Christian Ehrhardt Cc: Andrew Morton Cc: Linus Torvalds Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: LKML-Reference: <20090831124417.329662275@de.ibm.com> Signed-off-by: Ingo Molnar diff --git a/arch/m68k/include/asm/thread_info_mm.h b/arch/m68k/include/asm/thread_info_mm.h index 6ea5c33..b6da388 100644 --- a/arch/m68k/include/asm/thread_info_mm.h +++ b/arch/m68k/include/asm/thread_info_mm.h @@ -1,6 +1,10 @@ #ifndef _ASM_M68K_THREAD_INFO_H #define _ASM_M68K_THREAD_INFO_H +#ifndef ASM_OFFSETS_C +#include +#endif +#include #include #include @@ -31,7 +35,12 @@ struct thread_info { #define init_thread_info (init_task.thread.info) #define init_stack (init_thread_union.stack) -#define task_thread_info(tsk) (&(tsk)->thread.info) +#ifdef ASM_OFFSETS_C +#define task_thread_info(tsk) ((struct thread_info *) NULL) +#else +#define task_thread_info(tsk) ((struct thread_info *)((char *)tsk+TASK_TINFO)) +#endif + #define task_stack_page(tsk) ((tsk)->stack) #define current_thread_info() task_thread_info(current) diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c index 0cffab8..25d6b72 100644 --- a/arch/m68k/kernel/asm-offsets.c +++ b/arch/m68k/kernel/asm-offsets.c @@ -8,6 +8,8 @@ * #defines from the assembly-language output. */ +#define ASM_OFFSETS_C + #include #include #include @@ -27,6 +29,9 @@ int main(void) DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info)); DEFINE(TASK_MM, offsetof(struct task_struct, mm)); DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); +#ifdef CONFIG_MMU + DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info)); +#endif /* offsets into the thread struct */ DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); -- cgit v0.10.2 From 69d0ee7377eef808e34ba5542b554ec97244b871 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 31 Aug 2009 14:43:36 +0200 Subject: locking: Move spinlock function bodies to header file Move spinlock function bodies to header file by creating a static inline version of each variant. Use the inline version on the out-of-line code. This shouldn't make any difference besides that the spinlock code can now be used to generate inlined spinlock code. Signed-off-by: Heiko Carstens Acked-by: Arnd Bergmann Acked-by: Peter Zijlstra Cc: Nick Piggin Cc: Martin Schwidefsky Cc: Horst Hartmann Cc: Christian Ehrhardt Cc: Andrew Morton Cc: Linus Torvalds Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: LKML-Reference: <20090831124417.859022429@de.ibm.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 4be57ab..da76a06 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -143,15 +143,6 @@ static inline void smp_mb__after_lock(void) { smp_mb(); } */ #define spin_unlock_wait(lock) __raw_spin_unlock_wait(&(lock)->raw_lock) -/* - * Pull the _spin_*()/_read_*()/_write_*() functions/declarations: - */ -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) -# include -#else -# include -#endif - #ifdef CONFIG_DEBUG_SPINLOCK extern void _raw_spin_lock(spinlock_t *lock); #define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) @@ -380,4 +371,13 @@ extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); */ #define spin_can_lock(lock) (!spin_is_locked(lock)) +/* + * Pull the _spin_*()/_read_*()/_write_*() functions/declarations: + */ +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) +# include +#else +# include +#endif + #endif /* __LINUX_SPINLOCK_H */ diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h index d79845d..6b108f5 100644 --- a/include/linux/spinlock_api_smp.h +++ b/include/linux/spinlock_api_smp.h @@ -60,4 +60,267 @@ void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) __releases(lock); +static inline int __spin_trylock(spinlock_t *lock) +{ + preempt_disable(); + if (_raw_spin_trylock(lock)) { + spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); + return 1; + } + preempt_enable(); + return 0; +} + +static inline int __read_trylock(rwlock_t *lock) +{ + preempt_disable(); + if (_raw_read_trylock(lock)) { + rwlock_acquire_read(&lock->dep_map, 0, 1, _RET_IP_); + return 1; + } + preempt_enable(); + return 0; +} + +static inline int __write_trylock(rwlock_t *lock) +{ + preempt_disable(); + if (_raw_write_trylock(lock)) { + rwlock_acquire(&lock->dep_map, 0, 1, _RET_IP_); + return 1; + } + preempt_enable(); + return 0; +} + +/* + * If lockdep is enabled then we use the non-preemption spin-ops + * even on CONFIG_PREEMPT, because lockdep assumes that interrupts are + * not re-enabled during lock-acquire (which the preempt-spin-ops do): + */ +#if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC) + +static inline void __read_lock(rwlock_t *lock) +{ + preempt_disable(); + rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock); +} + +static inline unsigned long __spin_lock_irqsave(spinlock_t *lock) +{ + unsigned long flags; + + local_irq_save(flags); + preempt_disable(); + spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); + /* + * On lockdep we dont want the hand-coded irq-enable of + * _raw_spin_lock_flags() code, because lockdep assumes + * that interrupts are not re-enabled during lock-acquire: + */ +#ifdef CONFIG_LOCKDEP + LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); +#else + _raw_spin_lock_flags(lock, &flags); +#endif + return flags; +} + +static inline void __spin_lock_irq(spinlock_t *lock) +{ + local_irq_disable(); + preempt_disable(); + spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); +} + +static inline void __spin_lock_bh(spinlock_t *lock) +{ + local_bh_disable(); + preempt_disable(); + spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); +} + +static inline unsigned long __read_lock_irqsave(rwlock_t *lock) +{ + unsigned long flags; + + local_irq_save(flags); + preempt_disable(); + rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED_FLAGS(lock, _raw_read_trylock, _raw_read_lock, + _raw_read_lock_flags, &flags); + return flags; +} + +static inline void __read_lock_irq(rwlock_t *lock) +{ + local_irq_disable(); + preempt_disable(); + rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock); +} + +static inline void __read_lock_bh(rwlock_t *lock) +{ + local_bh_disable(); + preempt_disable(); + rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock); +} + +static inline unsigned long __write_lock_irqsave(rwlock_t *lock) +{ + unsigned long flags; + + local_irq_save(flags); + preempt_disable(); + rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED_FLAGS(lock, _raw_write_trylock, _raw_write_lock, + _raw_write_lock_flags, &flags); + return flags; +} + +static inline void __write_lock_irq(rwlock_t *lock) +{ + local_irq_disable(); + preempt_disable(); + rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock); +} + +static inline void __write_lock_bh(rwlock_t *lock) +{ + local_bh_disable(); + preempt_disable(); + rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock); +} + +static inline void __spin_lock(spinlock_t *lock) +{ + preempt_disable(); + spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); +} + +static inline void __write_lock(rwlock_t *lock) +{ + preempt_disable(); + rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock); +} + +#endif /* CONFIG_PREEMPT */ + +static inline void __spin_unlock(spinlock_t *lock) +{ + spin_release(&lock->dep_map, 1, _RET_IP_); + _raw_spin_unlock(lock); + preempt_enable(); +} + +static inline void __write_unlock(rwlock_t *lock) +{ + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_write_unlock(lock); + preempt_enable(); +} + +static inline void __read_unlock(rwlock_t *lock) +{ + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_read_unlock(lock); + preempt_enable(); +} + +static inline void __spin_unlock_irqrestore(spinlock_t *lock, + unsigned long flags) +{ + spin_release(&lock->dep_map, 1, _RET_IP_); + _raw_spin_unlock(lock); + local_irq_restore(flags); + preempt_enable(); +} + +static inline void __spin_unlock_irq(spinlock_t *lock) +{ + spin_release(&lock->dep_map, 1, _RET_IP_); + _raw_spin_unlock(lock); + local_irq_enable(); + preempt_enable(); +} + +static inline void __spin_unlock_bh(spinlock_t *lock) +{ + spin_release(&lock->dep_map, 1, _RET_IP_); + _raw_spin_unlock(lock); + preempt_enable_no_resched(); + local_bh_enable_ip((unsigned long)__builtin_return_address(0)); +} + +static inline void __read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) +{ + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_read_unlock(lock); + local_irq_restore(flags); + preempt_enable(); +} + +static inline void __read_unlock_irq(rwlock_t *lock) +{ + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_read_unlock(lock); + local_irq_enable(); + preempt_enable(); +} + +static inline void __read_unlock_bh(rwlock_t *lock) +{ + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_read_unlock(lock); + preempt_enable_no_resched(); + local_bh_enable_ip((unsigned long)__builtin_return_address(0)); +} + +static inline void __write_unlock_irqrestore(rwlock_t *lock, + unsigned long flags) +{ + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_write_unlock(lock); + local_irq_restore(flags); + preempt_enable(); +} + +static inline void __write_unlock_irq(rwlock_t *lock) +{ + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_write_unlock(lock); + local_irq_enable(); + preempt_enable(); +} + +static inline void __write_unlock_bh(rwlock_t *lock) +{ + rwlock_release(&lock->dep_map, 1, _RET_IP_); + _raw_write_unlock(lock); + preempt_enable_no_resched(); + local_bh_enable_ip((unsigned long)__builtin_return_address(0)); +} + +static inline int __spin_trylock_bh(spinlock_t *lock) +{ + local_bh_disable(); + preempt_disable(); + if (_raw_spin_trylock(lock)) { + spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); + return 1; + } + preempt_enable_no_resched(); + local_bh_enable_ip((unsigned long)__builtin_return_address(0)); + return 0; +} + #endif /* __LINUX_SPINLOCK_API_SMP_H */ diff --git a/kernel/spinlock.c b/kernel/spinlock.c index 7932653..2c000f5 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -23,40 +23,19 @@ int __lockfunc _spin_trylock(spinlock_t *lock) { - preempt_disable(); - if (_raw_spin_trylock(lock)) { - spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); - return 1; - } - - preempt_enable(); - return 0; + return __spin_trylock(lock); } EXPORT_SYMBOL(_spin_trylock); int __lockfunc _read_trylock(rwlock_t *lock) { - preempt_disable(); - if (_raw_read_trylock(lock)) { - rwlock_acquire_read(&lock->dep_map, 0, 1, _RET_IP_); - return 1; - } - - preempt_enable(); - return 0; + return __read_trylock(lock); } EXPORT_SYMBOL(_read_trylock); int __lockfunc _write_trylock(rwlock_t *lock) { - preempt_disable(); - if (_raw_write_trylock(lock)) { - rwlock_acquire(&lock->dep_map, 0, 1, _RET_IP_); - return 1; - } - - preempt_enable(); - return 0; + return __write_trylock(lock); } EXPORT_SYMBOL(_write_trylock); @@ -69,129 +48,74 @@ EXPORT_SYMBOL(_write_trylock); void __lockfunc _read_lock(rwlock_t *lock) { - preempt_disable(); - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock); + __read_lock(lock); } EXPORT_SYMBOL(_read_lock); unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) { - unsigned long flags; - - local_irq_save(flags); - preempt_disable(); - spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); - /* - * On lockdep we dont want the hand-coded irq-enable of - * _raw_spin_lock_flags() code, because lockdep assumes - * that interrupts are not re-enabled during lock-acquire: - */ -#ifdef CONFIG_LOCKDEP - LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); -#else - _raw_spin_lock_flags(lock, &flags); -#endif - return flags; + return __spin_lock_irqsave(lock); } EXPORT_SYMBOL(_spin_lock_irqsave); void __lockfunc _spin_lock_irq(spinlock_t *lock) { - local_irq_disable(); - preempt_disable(); - spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); + __spin_lock_irq(lock); } EXPORT_SYMBOL(_spin_lock_irq); void __lockfunc _spin_lock_bh(spinlock_t *lock) { - local_bh_disable(); - preempt_disable(); - spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); + __spin_lock_bh(lock); } EXPORT_SYMBOL(_spin_lock_bh); unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) { - unsigned long flags; - - local_irq_save(flags); - preempt_disable(); - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED_FLAGS(lock, _raw_read_trylock, _raw_read_lock, - _raw_read_lock_flags, &flags); - return flags; + return __read_lock_irqsave(lock); } EXPORT_SYMBOL(_read_lock_irqsave); void __lockfunc _read_lock_irq(rwlock_t *lock) { - local_irq_disable(); - preempt_disable(); - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock); + __read_lock_irq(lock); } EXPORT_SYMBOL(_read_lock_irq); void __lockfunc _read_lock_bh(rwlock_t *lock) { - local_bh_disable(); - preempt_disable(); - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock); + __read_lock_bh(lock); } EXPORT_SYMBOL(_read_lock_bh); unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) { - unsigned long flags; - - local_irq_save(flags); - preempt_disable(); - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED_FLAGS(lock, _raw_write_trylock, _raw_write_lock, - _raw_write_lock_flags, &flags); - return flags; + return __write_lock_irqsave(lock); } EXPORT_SYMBOL(_write_lock_irqsave); void __lockfunc _write_lock_irq(rwlock_t *lock) { - local_irq_disable(); - preempt_disable(); - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock); + __write_lock_irq(lock); } EXPORT_SYMBOL(_write_lock_irq); void __lockfunc _write_lock_bh(rwlock_t *lock) { - local_bh_disable(); - preempt_disable(); - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock); + __write_lock_bh(lock); } EXPORT_SYMBOL(_write_lock_bh); void __lockfunc _spin_lock(spinlock_t *lock) { - preempt_disable(); - spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); + __spin_lock(lock); } - EXPORT_SYMBOL(_spin_lock); void __lockfunc _write_lock(rwlock_t *lock) { - preempt_disable(); - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock); + __write_lock(lock); } - EXPORT_SYMBOL(_write_lock); #else /* CONFIG_PREEMPT: */ @@ -320,121 +244,79 @@ EXPORT_SYMBOL(_spin_lock_nest_lock); void __lockfunc _spin_unlock(spinlock_t *lock) { - spin_release(&lock->dep_map, 1, _RET_IP_); - _raw_spin_unlock(lock); - preempt_enable(); + __spin_unlock(lock); } EXPORT_SYMBOL(_spin_unlock); void __lockfunc _write_unlock(rwlock_t *lock) { - rwlock_release(&lock->dep_map, 1, _RET_IP_); - _raw_write_unlock(lock); - preempt_enable(); + __write_unlock(lock); } EXPORT_SYMBOL(_write_unlock); void __lockfunc _read_unlock(rwlock_t *lock) { - rwlock_release(&lock->dep_map, 1, _RET_IP_); - _raw_read_unlock(lock); - preempt_enable(); + __read_unlock(lock); } EXPORT_SYMBOL(_read_unlock); void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) { - spin_release(&lock->dep_map, 1, _RET_IP_); - _raw_spin_unlock(lock); - local_irq_restore(flags); - preempt_enable(); + __spin_unlock_irqrestore(lock, flags); } EXPORT_SYMBOL(_spin_unlock_irqrestore); void __lockfunc _spin_unlock_irq(spinlock_t *lock) { - spin_release(&lock->dep_map, 1, _RET_IP_); - _raw_spin_unlock(lock); - local_irq_enable(); - preempt_enable(); + __spin_unlock_irq(lock); } EXPORT_SYMBOL(_spin_unlock_irq); void __lockfunc _spin_unlock_bh(spinlock_t *lock) { - spin_release(&lock->dep_map, 1, _RET_IP_); - _raw_spin_unlock(lock); - preempt_enable_no_resched(); - local_bh_enable_ip((unsigned long)__builtin_return_address(0)); + __spin_unlock_bh(lock); } EXPORT_SYMBOL(_spin_unlock_bh); void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) { - rwlock_release(&lock->dep_map, 1, _RET_IP_); - _raw_read_unlock(lock); - local_irq_restore(flags); - preempt_enable(); + __read_unlock_irqrestore(lock, flags); } EXPORT_SYMBOL(_read_unlock_irqrestore); void __lockfunc _read_unlock_irq(rwlock_t *lock) { - rwlock_release(&lock->dep_map, 1, _RET_IP_); - _raw_read_unlock(lock); - local_irq_enable(); - preempt_enable(); + __read_unlock_irq(lock); } EXPORT_SYMBOL(_read_unlock_irq); void __lockfunc _read_unlock_bh(rwlock_t *lock) { - rwlock_release(&lock->dep_map, 1, _RET_IP_); - _raw_read_unlock(lock); - preempt_enable_no_resched(); - local_bh_enable_ip((unsigned long)__builtin_return_address(0)); + __read_unlock_bh(lock); } EXPORT_SYMBOL(_read_unlock_bh); void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) { - rwlock_release(&lock->dep_map, 1, _RET_IP_); - _raw_write_unlock(lock); - local_irq_restore(flags); - preempt_enable(); + __write_unlock_irqrestore(lock, flags); } EXPORT_SYMBOL(_write_unlock_irqrestore); void __lockfunc _write_unlock_irq(rwlock_t *lock) { - rwlock_release(&lock->dep_map, 1, _RET_IP_); - _raw_write_unlock(lock); - local_irq_enable(); - preempt_enable(); + __write_unlock_irq(lock); } EXPORT_SYMBOL(_write_unlock_irq); void __lockfunc _write_unlock_bh(rwlock_t *lock) { - rwlock_release(&lock->dep_map, 1, _RET_IP_); - _raw_write_unlock(lock); - preempt_enable_no_resched(); - local_bh_enable_ip((unsigned long)__builtin_return_address(0)); + __write_unlock_bh(lock); } EXPORT_SYMBOL(_write_unlock_bh); int __lockfunc _spin_trylock_bh(spinlock_t *lock) { - local_bh_disable(); - preempt_disable(); - if (_raw_spin_trylock(lock)) { - spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); - return 1; - } - - preempt_enable_no_resched(); - local_bh_enable_ip((unsigned long)__builtin_return_address(0)); - return 0; + return __spin_trylock_bh(lock); } EXPORT_SYMBOL(_spin_trylock_bh); -- cgit v0.10.2 From 892a7c67c12da63fa4b51728bbe5b982356a090a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 31 Aug 2009 14:43:37 +0200 Subject: locking: Allow arch-inlined spinlocks This allows an architecture to specify per lock variant if the locking code should be kept out-of-line or inlined. If an architecure wants out-of-line locking code no change is needed. To force inlining of e.g. spin_lock() the line: #define __always_inline__spin_lock needs to be added to arch/<...>/include/asm/spinlock.h If CONFIG_DEBUG_SPINLOCK or CONFIG_GENERIC_LOCKBREAK are defined the per architecture defines are (partly) ignored and still out-of-line spinlock code will be generated. Signed-off-by: Heiko Carstens Acked-by: Peter Zijlstra Cc: Arnd Bergmann Cc: Nick Piggin Cc: Martin Schwidefsky Cc: Horst Hartmann Cc: Christian Ehrhardt Cc: Andrew Morton Cc: Linus Torvalds Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: LKML-Reference: <20090831124418.375299024@de.ibm.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h index 6b108f5..1a411e3 100644 --- a/include/linux/spinlock_api_smp.h +++ b/include/linux/spinlock_api_smp.h @@ -60,6 +60,125 @@ void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) __releases(lock); +#ifndef CONFIG_DEBUG_SPINLOCK +#ifndef CONFIG_GENERIC_LOCKBREAK + +#ifdef __always_inline__spin_lock +#define _spin_lock(lock) __spin_lock(lock) +#endif + +#ifdef __always_inline__read_lock +#define _read_lock(lock) __read_lock(lock) +#endif + +#ifdef __always_inline__write_lock +#define _write_lock(lock) __write_lock(lock) +#endif + +#ifdef __always_inline__spin_lock_bh +#define _spin_lock_bh(lock) __spin_lock_bh(lock) +#endif + +#ifdef __always_inline__read_lock_bh +#define _read_lock_bh(lock) __read_lock_bh(lock) +#endif + +#ifdef __always_inline__write_lock_bh +#define _write_lock_bh(lock) __write_lock_bh(lock) +#endif + +#ifdef __always_inline__spin_lock_irq +#define _spin_lock_irq(lock) __spin_lock_irq(lock) +#endif + +#ifdef __always_inline__read_lock_irq +#define _read_lock_irq(lock) __read_lock_irq(lock) +#endif + +#ifdef __always_inline__write_lock_irq +#define _write_lock_irq(lock) __write_lock_irq(lock) +#endif + +#ifdef __always_inline__spin_lock_irqsave +#define _spin_lock_irqsave(lock) __spin_lock_irqsave(lock) +#endif + +#ifdef __always_inline__read_lock_irqsave +#define _read_lock_irqsave(lock) __read_lock_irqsave(lock) +#endif + +#ifdef __always_inline__write_lock_irqsave +#define _write_lock_irqsave(lock) __write_lock_irqsave(lock) +#endif + +#endif /* !CONFIG_GENERIC_LOCKBREAK */ + +#ifdef __always_inline__spin_trylock +#define _spin_trylock(lock) __spin_trylock(lock) +#endif + +#ifdef __always_inline__read_trylock +#define _read_trylock(lock) __read_trylock(lock) +#endif + +#ifdef __always_inline__write_trylock +#define _write_trylock(lock) __write_trylock(lock) +#endif + +#ifdef __always_inline__spin_trylock_bh +#define _spin_trylock_bh(lock) __spin_trylock_bh(lock) +#endif + +#ifdef __always_inline__spin_unlock +#define _spin_unlock(lock) __spin_unlock(lock) +#endif + +#ifdef __always_inline__read_unlock +#define _read_unlock(lock) __read_unlock(lock) +#endif + +#ifdef __always_inline__write_unlock +#define _write_unlock(lock) __write_unlock(lock) +#endif + +#ifdef __always_inline__spin_unlock_bh +#define _spin_unlock_bh(lock) __spin_unlock_bh(lock) +#endif + +#ifdef __always_inline__read_unlock_bh +#define _read_unlock_bh(lock) __read_unlock_bh(lock) +#endif + +#ifdef __always_inline__write_unlock_bh +#define _write_unlock_bh(lock) __write_unlock_bh(lock) +#endif + +#ifdef __always_inline__spin_unlock_irq +#define _spin_unlock_irq(lock) __spin_unlock_irq(lock) +#endif + +#ifdef __always_inline__read_unlock_irq +#define _read_unlock_irq(lock) __read_unlock_irq(lock) +#endif + +#ifdef __always_inline__write_unlock_irq +#define _write_unlock_irq(lock) __write_unlock_irq(lock) +#endif + +#ifdef __always_inline__spin_unlock_irqrestore +#define _spin_unlock_irqrestore(lock, flags) __spin_unlock_irqrestore(lock, flags) +#endif + +#ifdef __always_inline__read_unlock_irqrestore +#define _read_unlock_irqrestore(lock, flags) __read_unlock_irqrestore(lock, flags) +#endif + +#ifdef __always_inline__write_unlock_irqrestore +#define _write_unlock_irqrestore(lock, flags) __write_unlock_irqrestore(lock, flags) +#endif + +#endif /* CONFIG_DEBUG_SPINLOCK */ + static inline int __spin_trylock(spinlock_t *lock) { preempt_disable(); diff --git a/kernel/spinlock.c b/kernel/spinlock.c index 2c000f5..5ddab73 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -21,23 +21,29 @@ #include #include +#ifndef _spin_trylock int __lockfunc _spin_trylock(spinlock_t *lock) { return __spin_trylock(lock); } EXPORT_SYMBOL(_spin_trylock); +#endif +#ifndef _read_trylock int __lockfunc _read_trylock(rwlock_t *lock) { return __read_trylock(lock); } EXPORT_SYMBOL(_read_trylock); +#endif +#ifndef _write_trylock int __lockfunc _write_trylock(rwlock_t *lock) { return __write_trylock(lock); } EXPORT_SYMBOL(_write_trylock); +#endif /* * If lockdep is enabled then we use the non-preemption spin-ops @@ -46,77 +52,101 @@ EXPORT_SYMBOL(_write_trylock); */ #if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC) +#ifndef _read_lock void __lockfunc _read_lock(rwlock_t *lock) { __read_lock(lock); } EXPORT_SYMBOL(_read_lock); +#endif +#ifndef _spin_lock_irqsave unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) { return __spin_lock_irqsave(lock); } EXPORT_SYMBOL(_spin_lock_irqsave); +#endif +#ifndef _spin_lock_irq void __lockfunc _spin_lock_irq(spinlock_t *lock) { __spin_lock_irq(lock); } EXPORT_SYMBOL(_spin_lock_irq); +#endif +#ifndef _spin_lock_bh void __lockfunc _spin_lock_bh(spinlock_t *lock) { __spin_lock_bh(lock); } EXPORT_SYMBOL(_spin_lock_bh); +#endif +#ifndef _read_lock_irqsave unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) { return __read_lock_irqsave(lock); } EXPORT_SYMBOL(_read_lock_irqsave); +#endif +#ifndef _read_lock_irq void __lockfunc _read_lock_irq(rwlock_t *lock) { __read_lock_irq(lock); } EXPORT_SYMBOL(_read_lock_irq); +#endif +#ifndef _read_lock_bh void __lockfunc _read_lock_bh(rwlock_t *lock) { __read_lock_bh(lock); } EXPORT_SYMBOL(_read_lock_bh); +#endif +#ifndef _write_lock_irqsave unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) { return __write_lock_irqsave(lock); } EXPORT_SYMBOL(_write_lock_irqsave); +#endif +#ifndef _write_lock_irq void __lockfunc _write_lock_irq(rwlock_t *lock) { __write_lock_irq(lock); } EXPORT_SYMBOL(_write_lock_irq); +#endif +#ifndef _write_lock_bh void __lockfunc _write_lock_bh(rwlock_t *lock) { __write_lock_bh(lock); } EXPORT_SYMBOL(_write_lock_bh); +#endif +#ifndef _spin_lock void __lockfunc _spin_lock(spinlock_t *lock) { __spin_lock(lock); } EXPORT_SYMBOL(_spin_lock); +#endif +#ifndef _write_lock void __lockfunc _write_lock(rwlock_t *lock) { __write_lock(lock); } EXPORT_SYMBOL(_write_lock); +#endif #else /* CONFIG_PREEMPT: */ @@ -242,83 +272,109 @@ EXPORT_SYMBOL(_spin_lock_nest_lock); #endif +#ifndef _spin_unlock void __lockfunc _spin_unlock(spinlock_t *lock) { __spin_unlock(lock); } EXPORT_SYMBOL(_spin_unlock); +#endif +#ifndef _write_unlock void __lockfunc _write_unlock(rwlock_t *lock) { __write_unlock(lock); } EXPORT_SYMBOL(_write_unlock); +#endif +#ifndef _read_unlock void __lockfunc _read_unlock(rwlock_t *lock) { __read_unlock(lock); } EXPORT_SYMBOL(_read_unlock); +#endif +#ifndef _spin_unlock_irqrestore void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) { __spin_unlock_irqrestore(lock, flags); } EXPORT_SYMBOL(_spin_unlock_irqrestore); +#endif +#ifndef _spin_unlock_irq void __lockfunc _spin_unlock_irq(spinlock_t *lock) { __spin_unlock_irq(lock); } EXPORT_SYMBOL(_spin_unlock_irq); +#endif +#ifndef _spin_unlock_bh void __lockfunc _spin_unlock_bh(spinlock_t *lock) { __spin_unlock_bh(lock); } EXPORT_SYMBOL(_spin_unlock_bh); +#endif +#ifndef _read_unlock_irqrestore void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) { __read_unlock_irqrestore(lock, flags); } EXPORT_SYMBOL(_read_unlock_irqrestore); +#endif +#ifndef _read_unlock_irq void __lockfunc _read_unlock_irq(rwlock_t *lock) { __read_unlock_irq(lock); } EXPORT_SYMBOL(_read_unlock_irq); +#endif +#ifndef _read_unlock_bh void __lockfunc _read_unlock_bh(rwlock_t *lock) { __read_unlock_bh(lock); } EXPORT_SYMBOL(_read_unlock_bh); +#endif +#ifndef _write_unlock_irqrestore void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) { __write_unlock_irqrestore(lock, flags); } EXPORT_SYMBOL(_write_unlock_irqrestore); +#endif +#ifndef _write_unlock_irq void __lockfunc _write_unlock_irq(rwlock_t *lock) { __write_unlock_irq(lock); } EXPORT_SYMBOL(_write_unlock_irq); +#endif +#ifndef _write_unlock_bh void __lockfunc _write_unlock_bh(rwlock_t *lock) { __write_unlock_bh(lock); } EXPORT_SYMBOL(_write_unlock_bh); +#endif +#ifndef _spin_trylock_bh int __lockfunc _spin_trylock_bh(spinlock_t *lock) { return __spin_trylock_bh(lock); } EXPORT_SYMBOL(_spin_trylock_bh); +#endif notrace int in_lock_functions(unsigned long addr) { -- cgit v0.10.2 From bb7bed082500179519c7caf0678ba3bed9752658 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 31 Aug 2009 14:43:38 +0200 Subject: locking: Simplify spinlock inlining For !DEBUG_SPINLOCK && !PREEMPT && SMP the spin_unlock() functions were always inlined by using special defines which would call the __raw* functions. The out-of-line variants for these functions would be generated anyway. Use the new per unlock/locking variant mechanism to force inlining of the unlock functions like before. This is not a functional change, we just get rid of one additional way to force inlining. Signed-off-by: Heiko Carstens Acked-by: Peter Zijlstra Cc: Arnd Bergmann Cc: Nick Piggin Cc: Martin Schwidefsky Cc: Horst Hartmann Cc: Christian Ehrhardt Cc: Andrew Morton Cc: Linus Torvalds Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: LKML-Reference: <20090831124418.848735034@de.ibm.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index da76a06..f0ca7a7 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -259,50 +259,16 @@ static inline void smp_mb__after_lock(void) { smp_mb(); } #define spin_lock_irq(lock) _spin_lock_irq(lock) #define spin_lock_bh(lock) _spin_lock_bh(lock) - #define read_lock_irq(lock) _read_lock_irq(lock) #define read_lock_bh(lock) _read_lock_bh(lock) - #define write_lock_irq(lock) _write_lock_irq(lock) #define write_lock_bh(lock) _write_lock_bh(lock) - -/* - * We inline the unlock functions in the nondebug case: - */ -#if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || \ - !defined(CONFIG_SMP) -# define spin_unlock(lock) _spin_unlock(lock) -# define read_unlock(lock) _read_unlock(lock) -# define write_unlock(lock) _write_unlock(lock) -# define spin_unlock_irq(lock) _spin_unlock_irq(lock) -# define read_unlock_irq(lock) _read_unlock_irq(lock) -# define write_unlock_irq(lock) _write_unlock_irq(lock) -#else -# define spin_unlock(lock) \ - do {__raw_spin_unlock(&(lock)->raw_lock); __release(lock); } while (0) -# define read_unlock(lock) \ - do {__raw_read_unlock(&(lock)->raw_lock); __release(lock); } while (0) -# define write_unlock(lock) \ - do {__raw_write_unlock(&(lock)->raw_lock); __release(lock); } while (0) -# define spin_unlock_irq(lock) \ -do { \ - __raw_spin_unlock(&(lock)->raw_lock); \ - __release(lock); \ - local_irq_enable(); \ -} while (0) -# define read_unlock_irq(lock) \ -do { \ - __raw_read_unlock(&(lock)->raw_lock); \ - __release(lock); \ - local_irq_enable(); \ -} while (0) -# define write_unlock_irq(lock) \ -do { \ - __raw_write_unlock(&(lock)->raw_lock); \ - __release(lock); \ - local_irq_enable(); \ -} while (0) -#endif +#define spin_unlock(lock) _spin_unlock(lock) +#define read_unlock(lock) _read_unlock(lock) +#define write_unlock(lock) _write_unlock(lock) +#define spin_unlock_irq(lock) _spin_unlock_irq(lock) +#define read_unlock_irq(lock) _read_unlock_irq(lock) +#define write_unlock_irq(lock) _write_unlock_irq(lock) #define spin_unlock_irqrestore(lock, flags) \ do { \ diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h index 1a411e3..7a7e18f 100644 --- a/include/linux/spinlock_api_smp.h +++ b/include/linux/spinlock_api_smp.h @@ -60,6 +60,18 @@ void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) __releases(lock); +/* + * We inline the unlock functions in the nondebug case: + */ +#if !defined(CONFIG_DEBUG_SPINLOCK) && !defined(CONFIG_PREEMPT) +#define __always_inline__spin_unlock +#define __always_inline__read_unlock +#define __always_inline__write_unlock +#define __always_inline__spin_unlock_irq +#define __always_inline__read_unlock_irq +#define __always_inline__write_unlock_irq +#endif + #ifndef CONFIG_DEBUG_SPINLOCK #ifndef CONFIG_GENERIC_LOCKBREAK -- cgit v0.10.2 From b62e180cae6bd82e246d871a1e44e03f8019d421 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 31 Aug 2009 14:43:39 +0200 Subject: locking: Inline spinlock code for all locking variants on s390 Speeds up several benchmarks in a measurable way, so inline all spin-lock variants by default. Signed-off-by: Heiko Carstens Acked-by: Peter Zijlstra Cc: Arnd Bergmann Cc: Nick Piggin Cc: Martin Schwidefsky Cc: Horst Hartmann Cc: Christian Ehrhardt Cc: Andrew Morton Cc: Linus Torvalds Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: LKML-Reference: <20090831124419.319518405@de.ibm.com> Signed-off-by: Ingo Molnar diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h index c9af0d19..41ce686 100644 --- a/arch/s390/include/asm/spinlock.h +++ b/arch/s390/include/asm/spinlock.h @@ -191,4 +191,33 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw) #define _raw_read_relax(lock) cpu_relax() #define _raw_write_relax(lock) cpu_relax() +#define __always_inline__spin_lock +#define __always_inline__read_lock +#define __always_inline__write_lock +#define __always_inline__spin_lock_bh +#define __always_inline__read_lock_bh +#define __always_inline__write_lock_bh +#define __always_inline__spin_lock_irq +#define __always_inline__read_lock_irq +#define __always_inline__write_lock_irq +#define __always_inline__spin_lock_irqsave +#define __always_inline__read_lock_irqsave +#define __always_inline__write_lock_irqsave +#define __always_inline__spin_trylock +#define __always_inline__read_trylock +#define __always_inline__write_trylock +#define __always_inline__spin_trylock_bh +#define __always_inline__spin_unlock +#define __always_inline__read_unlock +#define __always_inline__write_unlock +#define __always_inline__spin_unlock_bh +#define __always_inline__read_unlock_bh +#define __always_inline__write_unlock_bh +#define __always_inline__spin_unlock_irq +#define __always_inline__read_unlock_irq +#define __always_inline__write_unlock_irq +#define __always_inline__spin_unlock_irqrestore +#define __always_inline__read_unlock_irqrestore +#define __always_inline__write_unlock_irqrestore + #endif /* __ASM_SPINLOCK_H */ -- cgit v0.10.2 From 5027309b5581e9c251a46f0ecbf88996d5e0f1e0 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 28 Aug 2009 09:44:45 -0700 Subject: iwlwifi: remove 60 Mbps from sband bitrates table ieee80211_supported_band is supposed to only contain legacy rates in the bitrates table (HT rates go in the ieee80211_sta_ht_cap substruct). Make iwlwifi driver obey this restriction by removing the 60 Mbps rate. Also, clean up a few pieces of other code that formerly relied on 60 Mbps being in sband->bitrates. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 26ec969..8239e55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -818,15 +818,15 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, { int status; u8 retries; - int rs_index, index = 0; + int rs_index, mac_index, index = 0; struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_link_quality_cmd *table; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl_priv *priv = (struct iwl_priv *)priv_r; - struct ieee80211_hw *hw = priv->hw; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_rate_scale_data *window = NULL; struct iwl_rate_scale_data *search_win = NULL; + enum mac80211_rate_control_flags mac_flags; u32 tx_rate; struct iwl_scale_tbl_info tbl_type; struct iwl_scale_tbl_info *curr_tbl, *search_tbl; @@ -876,16 +876,17 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; + mac_flags = info->status.rates[0].flags; + mac_index = info->status.rates[0].idx; - if ((info->status.rates[0].idx < 0) || - (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) || - (tbl_type.is_ht40 != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || - (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) || + if ((mac_index < 0) || + (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || + (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || + (tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA)) || (tbl_type.ant_type != info->antenna_sel_tx) || - (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) || - (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) || - (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) { + (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) || + (!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || + rs_index != mac_index) { IWL_DEBUG_RATE(priv, "initial rate does not match 0x%x\n", tx_rate); /* the last LQ command could failed so the LQ in ucode not * the same in driver sync up @@ -2542,8 +2543,12 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK) info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; } else { - if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) + /* Check for invalid rates */ + if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) || + ((sband->band == IEEE80211_BAND_5GHZ) && + (rate_idx < IWL_FIRST_OFDM_RATE))) rate_idx = rate_lowest_index(sband, sta); + /* On valid 5 GHz rate, adjust index */ else if (sband->band == IEEE80211_BAND_5GHZ) rate_idx -= IWL_FIRST_OFDM_RATE; info->control.rates[0].flags = 0; @@ -2584,9 +2589,6 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_conf *conf = &priv->hw->conf; struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct iwl_lq_sta *lq_sta = priv_sta; - u16 mask_bit = 0; - int count; - int start_rate = 0; lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->supp_rates[sband->band]; @@ -2661,20 +2663,10 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->drv = priv; - /* Find highest tx rate supported by hardware and destination station */ - mask_bit = sta->supp_rates[sband->band]; - count = sband->n_bitrates; - if (sband->band == IEEE80211_BAND_5GHZ) { - count += IWL_FIRST_OFDM_RATE; - start_rate = IWL_FIRST_OFDM_RATE; - mask_bit <<= IWL_FIRST_OFDM_RATE; - } - - mask_bit = mask_bit & lq_sta->active_legacy_rate; - lq_sta->last_txrate_idx = 4; - for (i = start_rate; i < count; i++) - if (mask_bit & BIT(i)) - lq_sta->last_txrate_idx = i; + /* Set last_txrate_idx to lowest rate */ + lq_sta->last_txrate_idx = rate_lowest_index(sband, sta); + if (sband->band == IEEE80211_BAND_5GHZ) + lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; rs_initialize_lq(priv, conf, sta, lq_sta); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 25050bf..9fac530 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -73,6 +73,7 @@ enum { IWL_RATE_54M_INDEX, IWL_RATE_60M_INDEX, IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ + IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */ IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1, IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, IWL_RATE_INVALID = IWL_RATE_COUNT, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 0bfd4e9..8135824 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -439,12 +439,12 @@ static void iwlcore_init_hw_rates(struct iwl_priv *priv, { int i; - for (i = 0; i < IWL_RATE_COUNT; i++) { + for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) { rates[i].bitrate = iwl_rates[i].ieee * 5; rates[i].hw_value = i; /* Rate scaling will work on indexes */ rates[i].hw_value_short = i; rates[i].flags = 0; - if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { + if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) { /* * If CCK != 1M then set short preamble rate flag. */ @@ -480,7 +480,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) if (!channels) return -ENOMEM; - rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), + rates = kzalloc((sizeof(struct ieee80211_rate) * IWL_RATE_COUNT_LEGACY), GFP_KERNEL); if (!rates) { kfree(channels); @@ -492,7 +492,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; /* just OFDM */ sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; - sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; + sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE; if (priv->cfg->sku & IWL_SKU_N) iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, @@ -502,7 +502,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) sband->channels = channels; /* OFDM & CCK */ sband->bitrates = rates; - sband->n_bitrates = IWL_RATE_COUNT; + sband->n_bitrates = IWL_RATE_COUNT_LEGACY; if (priv->cfg->sku & IWL_SKU_N) iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, @@ -1231,7 +1231,7 @@ static void iwl_set_rate(struct iwl_priv *priv) for (i = 0; i < hw->n_bitrates; i++) { rate = &(hw->bitrates[i]); - if (rate->hw_value < IWL_RATE_COUNT) + if (rate->hw_value < IWL_RATE_COUNT_LEGACY) priv->active_rate |= (1 << rate->hw_value); } -- cgit v0.10.2 From b58ef214b7db57cfcbca0e1edae08566cdfd56b7 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 28 Aug 2009 09:44:46 -0700 Subject: iwlwifi: remove incorrect uses of ieee80211_get_tx_rate to prevent TX stall Refactor and correct rate selection for outgoing transmitted packets. First, note that HT rates in the mac80211 rate table do not provide valid indices when ieee80211_get_tx_rate is called; the check to see if we could to abort a transmission early in iwl_tx_skb() would thus occasionally read invalid memory and occasionally stall transmission (if the erroneous byte was 0xff). We remove that code; the check wasn't valid anyway. Second, iwl_tx_cmd_build_rate() also called ieee80211_get_tx_rate to be used for sending management packets, which do not use the uCode station table. This patch refactors that function and adds comments to enhance legibility, replaces the call to ieee80211_get_tx_rate() with a direct lookup, and adds error handling in case the table entry is invalid. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 7bc9c00..a7422e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -566,62 +566,81 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, - __le16 fc, int sta_id, - int is_hcca) + __le16 fc, int is_hcca) { - u32 rate_flags = 0; + u32 rate_flags; int rate_idx; - u8 rts_retry_limit = 0; - u8 data_retry_limit = 0; + u8 rts_retry_limit; + u8 data_retry_limit; u8 rate_plcp; - rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff, - IWL_RATE_COUNT - 1); - - rate_plcp = iwl_rates[rate_idx].plcp; - - rts_retry_limit = (is_hcca) ? - RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; - - if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) - rate_flags |= RATE_MCS_CCK_MSK; - - - if (ieee80211_is_probe_resp(fc)) { - data_retry_limit = 3; - if (data_retry_limit < rts_retry_limit) - rts_retry_limit = data_retry_limit; - } else - data_retry_limit = IWL_DEFAULT_TX_RETRY; - + /* Set retry limit on DATA packets and Probe Responses*/ if (priv->data_retry_limit != -1) data_retry_limit = priv->data_retry_limit; + else if (ieee80211_is_probe_resp(fc)) + data_retry_limit = 3; + else + data_retry_limit = IWL_DEFAULT_TX_RETRY; + tx_cmd->data_retry_limit = data_retry_limit; + /* Set retry limit on RTS packets */ + rts_retry_limit = (is_hcca) ? RTS_HCCA_RETRY_LIMIT : + RTS_DFAULT_RETRY_LIMIT; + if (data_retry_limit < rts_retry_limit) + rts_retry_limit = data_retry_limit; + tx_cmd->rts_retry_limit = rts_retry_limit; + /* DATA packets will use the uCode station table for rate/antenna + * selection */ if (ieee80211_is_data(fc)) { tx_cmd->initial_rate_index = 0; tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; - } else { - switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { - case cpu_to_le16(IEEE80211_STYPE_AUTH): - case cpu_to_le16(IEEE80211_STYPE_DEAUTH): - case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): - case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): - if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) { - tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK; - } - break; - default: - break; - } + return; + } + + /** + * If the current TX rate stored in mac80211 has the MCS bit set, it's + * not really a TX rate. Thus, we use the lowest supported rate for + * this band. Also use the lowest supported rate if the stored rate + * index is invalid. + */ + rate_idx = info->control.rates[0].idx; + if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS || + (rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY)) + rate_idx = rate_lowest_index(&priv->bands[info->band], + info->control.sta); + /* For 5 GHZ band, remap mac80211 rate indices into driver indices */ + if (info->band == IEEE80211_BAND_5GHZ) + rate_idx += IWL_FIRST_OFDM_RATE; + /* Get PLCP rate for tx_cmd->rate_n_flags */ + rate_plcp = iwl_rates[rate_idx].plcp; + /* Zero out flags for this packet */ + rate_flags = 0; - priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); - rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); + /* Set CCK flag as needed */ + if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) + rate_flags |= RATE_MCS_CCK_MSK; + + /* Set up RTS and CTS flags for certain packets */ + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_AUTH): + case cpu_to_le16(IEEE80211_STYPE_DEAUTH): + case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): + case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): + if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) { + tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK; + } + break; + default: + break; } - tx_cmd->rts_retry_limit = rts_retry_limit; - tx_cmd->data_retry_limit = data_retry_limit; + /* Set up antennas */ + priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); + rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); + + /* Set the rate in the TX cmd */ tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags); } @@ -701,12 +720,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) goto drop_unlock; } - if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == - IWL_INVALID_RATE) { - IWL_ERR(priv, "ERROR: No TX rate available.\n"); - goto drop_unlock; - } - fc = hdr->frame_control; #ifdef CONFIG_IWLWIFI_DEBUG @@ -807,7 +820,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) iwl_dbg_log_tx_data_frame(priv, len, hdr); /* set is_hcca to 0; it probably will never be implemented */ - iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); + iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, 0); iwl_update_stats(priv, true, fc, len); /* -- cgit v0.10.2 From 31513be8a06874eb359908b7b735929837831a9a Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 28 Aug 2009 09:44:47 -0700 Subject: iwlwifi: use iwl_hwrate_get_mac80211_idx where appropriate For HT packets, mac80211 expects the rate_idx to be an MCS number, which is the lower byte of rate_n_flags. However, iwl_hwrate_to_plcp_idx takes the MCS number and reduces it down to the range 0-8 (6 to 60 Mbps), removing the bits that signify multiply streams, HT40 Duplicate mode, or unequal modulation. This version is used for various internal purposes through the driver. Add the function iwl_hwrate_get_mac80211_idx, an alternate version which takes the rate and the band and returns the mac80211 index (MCS, for HT packets, and PLCP rate, for legacy packets). Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 8239e55..40b207a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -878,6 +878,12 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, rs_index -= IWL_FIRST_OFDM_RATE; mac_flags = info->status.rates[0].flags; mac_index = info->status.rates[0].idx; + /* For HT packets, map MCS to PLCP */ + if (mac_flags & IEEE80211_TX_RC_MCS) { + mac_index &= RATE_MCS_CODE_MSK; /* Remove # of streams */ + if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE)) + mac_index++; + } if ((mac_index < 0) || (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || @@ -886,8 +892,8 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, (tbl_type.ant_type != info->antenna_sel_tx) || (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) || (!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || - rs_index != mac_index) { - IWL_DEBUG_RATE(priv, "initial rate does not match 0x%x\n", tx_rate); + (rs_index != mac_index)) { + IWL_DEBUG_RATE(priv, "initial rate %d does not match %d (0x%x)\n", mac_index, rs_index, tx_rate); /* the last LQ command could failed so the LQ in ucode not * the same in driver sync up */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8135824..acfd7b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -96,7 +96,6 @@ EXPORT_SYMBOL(iwl_rates); void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, struct ieee80211_tx_info *info) { - int rate_index; struct ieee80211_tx_rate *r = &info->control.rates[0]; info->antenna_sel_tx = @@ -111,10 +110,7 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, r->flags |= IEEE80211_TX_RC_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) r->flags |= IEEE80211_TX_RC_SHORT_GI; - rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags); - if (info->band == IEEE80211_BAND_5GHZ) - rate_index -= IWL_FIRST_OFDM_RATE; - r->idx = rate_index; + r->idx = iwl_hwrate_to_mac80211_idx(rate_n_flags, info->band); } EXPORT_SYMBOL(iwl_hwrate_to_tx_control); @@ -149,6 +145,27 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) } EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx); +int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band) +{ + int idx = 0; + int band_offset = 0; + + /* HT rate format: mac80211 wants an MCS number, which is just LSB */ + if (rate_n_flags & RATE_MCS_HT_MSK) { + idx = (rate_n_flags & 0xff); + return idx; + /* Legacy rate format, search for match in table */ + } else { + if (band == IEEE80211_BAND_5GHZ) + band_offset = IWL_FIRST_OFDM_RATE; + for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) + if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) + return idx - band_offset; + } + + return -1; +} + u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant) { int i; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 62d9036..c04d2a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -423,6 +423,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, struct ieee80211_tx_info *info); int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); +int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band); u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index e34d3fc..8150c5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -962,6 +962,9 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, return; } + /* This will be used in several places later */ + rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); + /* rx_status carries information about the packet to mac80211 */ rx_status.mactime = le64_to_cpu(phy_res->timestamp); rx_status.freq = @@ -969,10 +972,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; rx_status.rate_idx = - iwl_hwrate_to_plcp_idx(le32_to_cpu(phy_res->rate_n_flags)); - if (rx_status.band == IEEE80211_BAND_5GHZ) - rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; - + iwl_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); rx_status.flag = 0; /* TSF isn't reliable. In order to allow smooth user experience, @@ -1034,7 +1034,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, rx_status.flag |= RX_FLAG_SHORTPRE; /* Set up the HT phy flags */ - rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); if (rate_n_flags & RATE_MCS_HT_MSK) rx_status.flag |= RX_FLAG_HT; if (rate_n_flags & RATE_MCS_HT40_MSK) -- cgit v0.10.2 From 4c561a02291326c50f9b1f647eae891af9d1f3b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 28 Aug 2009 09:44:48 -0700 Subject: iwlwifi: use sleep interval succession Some concerns were raised about the automatic adjustment of sleep intervals to all the same, potentially high, value, and I can imagine the hardware behaving better when we don't ask too much of it. So let's convert to use a succession of sleep levels when requesting to go to deeper sleeps (which can only happen with large DTIM intervals), using the succession values from power level three, which have the benefit of also having been tested extensively already. As a result, the automatic sleep level adjustment will now be mostly equivalent to power level three, except for the RX/TX timeouts and possibly using smaller sleep vectors to account for networking latency. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 0b16841..081a7ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -216,8 +216,27 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, int dynps_ms, int wakeup_period) { + /* + * These are the original power level 3 sleep successions. The + * device may behave better with such succession and was also + * only tested with that. Just like the original sleep commands, + * also adjust the succession here to the wakeup_period below. + * The ranges are the same as for the sleep commands, 0-2, 3-9 + * and >10, which is selected based on the DTIM interval for + * the sleep index but here we use the wakeup period since that + * is what we need to do for the latency requirements. + */ + static const u8 slp_succ_r0[IWL_POWER_VEC_SIZE] = { 2, 2, 2, 2, 2 }; + static const u8 slp_succ_r1[IWL_POWER_VEC_SIZE] = { 2, 4, 6, 7, 9 }; + static const u8 slp_succ_r2[IWL_POWER_VEC_SIZE] = { 2, 7, 9, 9, 0xFF }; + const u8 *slp_succ = slp_succ_r0; int i; + if (wakeup_period > IWL_DTIM_RANGE_0_MAX) + slp_succ = slp_succ_r1; + if (wakeup_period > IWL_DTIM_RANGE_1_MAX) + slp_succ = slp_succ_r2; + memset(cmd, 0, sizeof(*cmd)); cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK | @@ -230,7 +249,8 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms); for (i = 0; i < IWL_POWER_VEC_SIZE; i++) - cmd->sleep_interval[i] = cpu_to_le32(wakeup_period); + cmd->sleep_interval[i] = + cpu_to_le32(min_t(int, slp_succ[i], wakeup_period)); IWL_DEBUG_POWER(priv, "Automatic sleep command\n"); } -- cgit v0.10.2 From b57d46aa0db87b6349737e7b110ebe48ee14c143 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 28 Aug 2009 09:44:49 -0700 Subject: iwlwifi: fix situation in which debug message is printed 3945 does not have update_chain_flags defined and because if this we always see the debug message that does not apply to it. Add a check to be specific about what is actually happening. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 081a7ea..4ec6a83 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -321,7 +321,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); - else + else if (priv->cfg->ops->lib->update_chain_flags) IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise " "calibration running: %d\n", -- cgit v0.10.2 From af472a953ef23d6b9fe717486974d7caff3fa194 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 28 Aug 2009 09:58:50 -0700 Subject: iwl3945: reduce debug noise when default debug flags used Significant literature suggests users use debug flags 0x43fff - this causes the debug flags to be set that causes information to be printed for every received frame - including beacons. In the best case it fills up the logs, at worst it slows driver down and causes failures due to timeouts. In the RX handler, print debugging only if user requested RX debugging. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 3479041..2238c9f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1373,7 +1373,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) fill_rx = 1; /* Rx interrupt, but nothing sent from uCode */ if (i == r) - IWL_DEBUG(priv, IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); + IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); while (i != r) { rxb = rxq->queue[i]; @@ -1404,15 +1404,13 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) * handle those that need handling via function in * rx_handlers table. See iwl3945_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { - IWL_DEBUG(priv, IWL_DL_HCMD | IWL_DL_RX | IWL_DL_ISR, - "r = %d, i = %d, %s, 0x%02x\n", r, i, + IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; } else { /* No handling needed */ - IWL_DEBUG(priv, IWL_DL_HCMD | IWL_DL_RX | IWL_DL_ISR, - "r %d i %d No handler needed for %s, 0x%02x\n", + IWL_DEBUG_RX(priv, "r %d i %d No handler needed for %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); } -- cgit v0.10.2 From c206a39d58fa335275403088171482f66fdbedcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 28 Aug 2009 21:37:00 +0200 Subject: b43: Refactor and update antenna diversity for A/G-PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Make use of the b43_phy_set/mask/maskset helpers. -Fix a few errors in the code. -Make the code more readable. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 809ec97..d90217c 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -518,58 +518,40 @@ static unsigned int b43_aphy_op_get_default_chan(struct b43_wldev *dev) static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) {//TODO struct b43_phy *phy = &dev->phy; - u64 hf; u16 tmp; int autodiv = 0; if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) autodiv = 1; - hf = b43_hf_read(dev); - hf &= ~B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP); - tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); - tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO1 : antenna) - << B43_PHY_BBANDCFG_RXANT_SHIFT; - b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + b43_phy_maskset(dev, B43_PHY_BBANDCFG, ~B43_PHY_BBANDCFG_RXANT, + (autodiv ? B43_ANTENNA_AUTO1 : antenna) << + B43_PHY_BBANDCFG_RXANT_SHIFT); if (autodiv) { tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - if (antenna == B43_ANTENNA_AUTO0) + if (antenna == B43_ANTENNA_AUTO1) tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; else tmp |= B43_PHY_ANTDWELL_AUTODIV1; b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); } - if (phy->rev < 3) { - tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - tmp = (tmp & 0xFF00) | 0x24; - b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); - } else { - tmp = b43_phy_read(dev, B43_PHY_OFDM61); - tmp |= 0x10; - b43_phy_write(dev, B43_PHY_OFDM61, tmp); - if (phy->analog == 3) { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, - 0x1D); - b43_phy_write(dev, B43_PHY_ADIVRELATED, - 8); + if (phy->rev < 3) + b43_phy_maskset(dev, B43_PHY_ANTDWELL, 0xFF00, 0x24); + else { + b43_phy_set(dev, B43_PHY_OFDM61, 0x10); + if (phy->rev == 3) { + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, 0x1D); + b43_phy_write(dev, B43_PHY_ADIVRELATED, 8); } else { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, - 0x3A); - tmp = - b43_phy_read(dev, - B43_PHY_ADIVRELATED); - tmp = (tmp & 0xFF00) | 8; - b43_phy_write(dev, B43_PHY_ADIVRELATED, - tmp); + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, 0x3A); + b43_phy_maskset(dev, B43_PHY_ADIVRELATED, 0xFF00, 8); } } - hf |= B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP); } static void b43_aphy_op_adjust_txpower(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index bdff9af..5afa4df 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2651,65 +2651,54 @@ static unsigned int b43_gphy_op_get_default_chan(struct b43_wldev *dev) static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) { struct b43_phy *phy = &dev->phy; - u64 hf; u16 tmp; int autodiv = 0; if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) autodiv = 1; - hf = b43_hf_read(dev); - hf &= ~B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP); - tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); - tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO1 : antenna) - << B43_PHY_BBANDCFG_RXANT_SHIFT; - b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + b43_phy_maskset(dev, B43_PHY_BBANDCFG, ~B43_PHY_BBANDCFG_RXANT, + (autodiv ? B43_ANTENNA_AUTO1 : antenna) << + B43_PHY_BBANDCFG_RXANT_SHIFT); if (autodiv) { tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - if (antenna == B43_ANTENNA_AUTO0) + if (antenna == B43_ANTENNA_AUTO1) tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; else tmp |= B43_PHY_ANTDWELL_AUTODIV1; b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); } + tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT); if (autodiv) tmp |= B43_PHY_ANTWRSETT_ARXDIV; else tmp &= ~B43_PHY_ANTWRSETT_ARXDIV; b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp); - if (phy->rev >= 2) { - tmp = b43_phy_read(dev, B43_PHY_OFDM61); - tmp |= B43_PHY_OFDM61_10; - b43_phy_write(dev, B43_PHY_OFDM61, tmp); - tmp = - b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK); - tmp = (tmp & 0xFF00) | 0x15; - b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK, - tmp); + if (autodiv) + b43_phy_set(dev, B43_PHY_ANTWRSETT, B43_PHY_ANTWRSETT_ARXDIV); + else { + b43_phy_mask(dev, B43_PHY_ANTWRSETT, + B43_PHY_ANTWRSETT_ARXDIV); + } - if (phy->rev == 2) { - b43_phy_write(dev, B43_PHY_ADIVRELATED, - 8); - } else { - tmp = - b43_phy_read(dev, - B43_PHY_ADIVRELATED); - tmp = (tmp & 0xFF00) | 8; - b43_phy_write(dev, B43_PHY_ADIVRELATED, - tmp); - } + if (phy->rev >= 2) { + b43_phy_set(dev, B43_PHY_OFDM61, B43_PHY_OFDM61_10); + b43_phy_maskset(dev, B43_PHY_DIVSRCHGAINBACK, 0xFF00, 0x15); + + if (phy->rev == 2) + b43_phy_write(dev, B43_PHY_ADIVRELATED, 8); + else + b43_phy_maskset(dev, B43_PHY_ADIVRELATED, 0xFF00, 8); } if (phy->rev >= 6) b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC); - hf |= B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP); } static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev, -- cgit v0.10.2 From 0136e51edbdae7f82aa1c32ad5cd6a49ec917c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 28 Aug 2009 22:32:17 +0200 Subject: b43: Add myself to module authors & to LP-PHY file copyright notices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also mark the LP-PHY driver "802.11a/g" instead of "802.11g", as LP-PHY is capable of both 2GHz and 5GHz operation. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 0f16844..2852cac 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -58,6 +58,7 @@ MODULE_DESCRIPTION("Broadcom B43 wireless driver"); MODULE_AUTHOR("Martin Langer"); MODULE_AUTHOR("Stefano Brivio"); MODULE_AUTHOR("Michael Buesch"); +MODULE_AUTHOR("Gábor Stefanik"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID); diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 1ab00b0..3e02d96 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1,9 +1,10 @@ /* Broadcom B43 wireless driver - IEEE 802.11g LP-PHY driver + IEEE 802.11a/g LP-PHY driver Copyright (c) 2008-2009 Michael Buesch + Copyright (c) 2009 Gábor Stefanik 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 diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index c784def..cb56882 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -1,9 +1,10 @@ /* Broadcom B43 wireless driver - IEEE 802.11g LP-PHY and radio device data tables + IEEE 802.11a/g LP-PHY and radio device data tables Copyright (c) 2009 Michael Buesch + Copyright (c) 2009 Gábor Stefanik 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 -- cgit v0.10.2 From c71dbd3316d9ae8bc49d90b5a0b2915cd5089cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 28 Aug 2009 22:34:21 +0200 Subject: b43: Fix typo in modparam_btcoex description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2852cac..ae05f66 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -91,7 +91,7 @@ MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); static int modparam_btcoex = 1; module_param_named(btcoex, modparam_btcoex, int, 0444); -MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistance (default on)"); +MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistence (default on)"); int b43_modparam_verbose = B43_VERBOSITY_DEFAULT; module_param_named(verbose, b43_modparam_verbose, int, 0644); -- cgit v0.10.2 From 1ee50cd9a22fdb22ce7bdb7f978d25b79993788d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Stefanik?= Date: Fri, 28 Aug 2009 22:36:02 +0200 Subject: b43: LP-PHY: Fix TX gain tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rev1 2GHz and rev2 5GHz gain tables were incorrectly documented on the specs originally. Update these gaintables to match the cor- rected specs. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index cb56882..61027ee 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -1613,11 +1613,62 @@ static struct lpphy_tx_gain_table_entry lpphy_rev1_nopa_tx_gain_table[] = { }; static struct lpphy_tx_gain_table_entry lpphy_rev1_2ghz_tx_gain_table[] = { - { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 85, }, - { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 81, }, - { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 78, }, - { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 76, }, - { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 74, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 90, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 88, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 85, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 83, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 81, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 78, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 76, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 74, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 59, }, { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 72, }, { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, @@ -1690,57 +1741,6 @@ static struct lpphy_tx_gain_table_entry lpphy_rev1_2ghz_tx_gain_table[] = { { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 64, }, { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 62, }, { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 60, }, - { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 59, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 72, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 70, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 68, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 66, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 64, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 62, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 60, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 59, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 70, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 68, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 66, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 64, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 63, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 61, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 59, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 71, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 69, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 67, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 65, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 63, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 62, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 60, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 58, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 70, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 68, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 66, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 65, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 63, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 61, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 59, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 68, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 66, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 64, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 62, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 61, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 59, }, - { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 67, }, - { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 65, }, - { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 63, }, - { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 62, }, - { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 60, }, - { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 65, }, - { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 63, }, - { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 61, }, - { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 60, }, - { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 58, }, - { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 68, }, - { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 66, }, - { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 64, }, - { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 62, }, }; static struct lpphy_tx_gain_table_entry lpphy_rev1_5ghz_tx_gain_table[] = { @@ -2168,103 +2168,103 @@ static struct lpphy_tx_gain_table_entry lpphy_rev2_5ghz_tx_gain_table[] = { { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 68, }, { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 66, }, { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 248, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 241, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 234, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 227, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 221, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 215, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 208, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 203, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 197, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 191, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 186, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 181, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 175, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 170, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 166, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 161, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 156, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 152, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 148, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 143, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 139, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 135, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 132, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 128, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 124, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 121, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 117, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 114, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 111, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 108, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 104, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 102, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 99, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 96, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 93, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 90, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 88, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 85, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 83, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 81, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 78, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 76, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 74, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 72, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 70, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 68, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 66, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 62, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 62, .pad = 248, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 60, .pad = 248, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 60, .pad = 241, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 59, .pad = 241, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 59, .pad = 234, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 57, .pad = 234, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 57, .pad = 227, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 55, .pad = 227, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 55, .pad = 221, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 54, .pad = 221, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 54, .pad = 215, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 52, .pad = 215, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 52, .pad = 208, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 51, .pad = 208, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 51, .pad = 203, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 49, .pad = 203, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 49, .pad = 197, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 48, .pad = 197, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 48, .pad = 191, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 47, .pad = 191, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 47, .pad = 186, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 45, .pad = 186, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 45, .pad = 181, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 44, .pad = 181, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 44, .pad = 175, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 43, .pad = 175, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 43, .pad = 170, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 42, .pad = 170, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 42, .pad = 166, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 40, .pad = 166, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 40, .pad = 161, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 39, .pad = 161, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 39, .pad = 156, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 38, .pad = 156, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 38, .pad = 152, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 37, .pad = 152, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 37, .pad = 148, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 36, .pad = 148, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 36, .pad = 143, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 35, .pad = 143, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 35, .pad = 139, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 34, .pad = 139, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 34, .pad = 135, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 33, .pad = 135, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 33, .pad = 132, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 32, .pad = 132, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 32, .pad = 128, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 248, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 241, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 234, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 227, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 221, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 215, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 208, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 191, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 175, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 170, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 156, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 143, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 139, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 135, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 128, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 124, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 121, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 117, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 114, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 111, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 108, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 104, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 102, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 99, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 96, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 93, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 90, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 88, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 85, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 83, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 81, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 78, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 76, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 74, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 72, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 70, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 68, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 66, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 248, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 248, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 241, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 241, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 234, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 234, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 227, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 227, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 221, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 221, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 215, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 215, .pad = 52, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 208, .pad = 52, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 208, .pad = 51, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 203, .pad = 51, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 203, .pad = 49, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 197, .pad = 49, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 197, .pad = 48, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 191, .pad = 48, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 191, .pad = 47, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 186, .pad = 47, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 186, .pad = 45, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 181, .pad = 45, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 181, .pad = 44, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 175, .pad = 44, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 175, .pad = 43, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 170, .pad = 43, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 170, .pad = 42, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 166, .pad = 42, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 166, .pad = 40, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 161, .pad = 40, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 161, .pad = 39, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 156, .pad = 39, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 156, .pad = 38, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 152, .pad = 38, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 152, .pad = 37, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 148, .pad = 37, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 148, .pad = 36, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 143, .pad = 36, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 143, .pad = 35, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 139, .pad = 35, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 139, .pad = 34, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 135, .pad = 34, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 135, .pad = 33, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 132, .pad = 33, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 132, .pad = 32, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 128, .pad = 32, .dac = 0, .bb_mult = 64, }, }; void lpphy_rev0_1_table_init(struct b43_wldev *dev) -- cgit v0.10.2 From 2e27cff871dec9371e41022aaaebb3452ec069c0 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 29 Aug 2009 19:10:14 +0200 Subject: rt2x00: Fix TX status reporting Not all values of the TX status enumeration were covered during updating of the TX statistics. This could lead to wrong bitrate tuning but also wrong behavior in tools like hostapd. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 3f8c70e..0647e51 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -206,6 +206,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb); u8 rate_idx, rate_flags, retry_rates; unsigned int i; + bool success; /* * Unmap the skb. @@ -234,13 +235,18 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); /* - * Update TX statistics. + * Determine if the frame has been successfully transmitted. */ - rt2x00dev->link.qual.tx_success += + success = test_bit(TXDONE_SUCCESS, &txdesc->flags) || - test_bit(TXDONE_UNKNOWN, &txdesc->flags); - rt2x00dev->link.qual.tx_failed += - test_bit(TXDONE_FAILURE, &txdesc->flags); + test_bit(TXDONE_UNKNOWN, &txdesc->flags) || + test_bit(TXDONE_FALLBACK, &txdesc->flags); + + /* + * Update TX statistics. + */ + rt2x00dev->link.qual.tx_success += success; + rt2x00dev->link.qual.tx_failed += !success; rate_idx = skbdesc->tx_rate_idx; rate_flags = skbdesc->tx_rate_flags; @@ -263,22 +269,20 @@ void rt2x00lib_txdone(struct queue_entry *entry, tx_info->status.rates[i].flags = rate_flags; tx_info->status.rates[i].count = 1; } - if (i < (IEEE80211_TX_MAX_RATES -1)) + if (i < (IEEE80211_TX_MAX_RATES - 1)) tx_info->status.rates[i].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || - test_bit(TXDONE_UNKNOWN, &txdesc->flags)) + if (success) tx_info->flags |= IEEE80211_TX_STAT_ACK; - else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) + else rt2x00dev->low_level_stats.dot11ACKFailureCount++; } if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || - test_bit(TXDONE_UNKNOWN, &txdesc->flags)) + if (success) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; - else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) + else rt2x00dev->low_level_stats.dot11RTSFailureCount++; } -- cgit v0.10.2 From daee6c092aa49ea090612738253ef0d11d120344 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 29 Aug 2009 20:30:45 +0200 Subject: rt2x00: Reorganize padding & L2 padding The old function rt2x00queue_payload_align() handled both adding and removing L2 padding and some basic frame alignment. The entire function was being abused because it had multiple functions and the header length argument was somtimes used to align the header instead of the payload. Additionally there was a bug when inserting L2 padding that only the payload was aligned but not the header. This happens when the header wasn't aligned properly by mac80211, but rt2x00lib only moves the payload. A secondary problem was that when removing L2 padding during TXdone or RX the skb wasn't resized to the proper size. Split the function into seperate functions each handling its task as it should. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 30fbd3b..de36837d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -154,7 +154,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length) skbdesc->flags &= ~SKBDESC_IV_STRIPPED; } -void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int header_length, struct rxdone_entry_desc *rxdesc) { @@ -199,7 +199,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, * move the header more then iv_len since we must * make room for the payload move as well. */ - if (l2pad) { + if (rxdesc->dev_flags & RXDONE_L2PAD) { skb_push(skb, iv_len - align); skb_put(skb, icv_len); @@ -230,7 +230,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, * Move payload for alignment purposes. Note that * this is only needed when no l2 padding is present. */ - if (!l2pad) { + if (!(rxdesc->dev_flags & RXDONE_L2PAD)) { memmove(skb->data + transfer, skb->data + transfer + align, payload_len); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 0647e51..71761b3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -217,7 +217,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, * Remove L2 padding which was added during */ if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) - rt2x00queue_payload_align(entry->skb, true, header_length); + rt2x00queue_remove_l2pad(entry->skb, header_length); /* * If the IV/EIV data was stripped from the frame before it was @@ -364,7 +364,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; unsigned int header_length; - bool l2pad; int rate_idx; /* * Allocate a new sk_buffer. If no new buffer available, drop the @@ -393,7 +392,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * aligned on a 4 byte boundary. */ header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - l2pad = !!(rxdesc.dev_flags & RXDONE_L2PAD); /* * Hardware might have stripped the IV/EIV/ICV data, @@ -403,10 +401,12 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, */ if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && (rxdesc.flags & RX_FLAG_IV_STRIPPED)) - rt2x00crypto_rx_insert_iv(entry->skb, l2pad, header_length, + rt2x00crypto_rx_insert_iv(entry->skb, header_length, &rxdesc); + else if (rxdesc.dev_flags & RXDONE_L2PAD) + rt2x00queue_remove_l2pad(entry->skb, header_length); else - rt2x00queue_payload_align(entry->skb, l2pad, header_length); + rt2x00queue_align_payload(entry->skb, header_length); /* * Check if the frame was received using HT. In that case, diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index eeb2881..5462cb5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -120,21 +120,42 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); /** - * rt2x00queue_payload_align - Align 802.11 payload to 4-byte boundary + * rt2x00queue_align_frame - Align 802.11 frame to 4-byte boundary + * @skb: The skb to align + * + * Align the start of the 802.11 frame to a 4-byte boundary, this could + * mean the payload is not aligned properly though. + */ +void rt2x00queue_align_frame(struct sk_buff *skb); + +/** + * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary + * @skb: The skb to align + * @header_length: Length of 802.11 header + * + * Align the 802.11 payload to a 4-byte boundary, this could + * mean the header is not aligned properly though. + */ +void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length); + +/** + * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary + * @skb: The skb to align + * @header_length: Length of 802.11 header + * + * Apply L2 padding to align both header and payload to 4-byte boundary + */ +void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length); + +/** + * rt2x00queue_insert_l2pad - Remove L2 padding from 802.11 frame * @skb: The skb to align - * @l2pad: Should L2 padding be used * @header_length: Length of 802.11 header * - * This function prepares the @skb to be send to the device or mac80211. - * If @l2pad is set to true padding will occur between the 802.11 header - * and payload. Otherwise the padding will be done in front of the 802.11 - * header. - * When @l2pad is set the function will check for the &SKBDESC_L2_PADDED - * flag in &skb_frame_desc. If that flag is set, the padding is removed - * and the flag cleared. Otherwise the padding is added and the flag is set. + * Remove L2 padding used to align both header and payload to 4-byte boundary, + * by removing the L2 padding the header will no longer be 4-byte aligned. */ -void rt2x00queue_payload_align(struct sk_buff *skb, - bool l2pad, unsigned int header_length); +void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length); /** * rt2x00queue_write_tx_frame - Write TX frame to hardware @@ -324,7 +345,7 @@ void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc); void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length); -void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int header_length, struct rxdone_entry_desc *rxdesc); #else diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 06af823..577029e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -148,35 +148,89 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) dev_kfree_skb_any(skb); } -void rt2x00queue_payload_align(struct sk_buff *skb, - bool l2pad, unsigned int header_length) +void rt2x00queue_align_frame(struct sk_buff *skb) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); unsigned int frame_length = skb->len; - unsigned int align = ALIGN_SIZE(skb, header_length); + unsigned int align = ALIGN_SIZE(skb, 0); if (!align) return; - if (l2pad) { - if (skbdesc->flags & SKBDESC_L2_PADDED) { - /* Remove L2 padding */ - memmove(skb->data + align, skb->data, header_length); - skb_pull(skb, align); - skbdesc->flags &= ~SKBDESC_L2_PADDED; - } else { - /* Add L2 padding */ - skb_push(skb, align); - memmove(skb->data, skb->data + align, header_length); - skbdesc->flags |= SKBDESC_L2_PADDED; - } + skb_push(skb, align); + memmove(skb->data, skb->data + align, frame_length); + skb_trim(skb, frame_length); +} + +void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_lengt) +{ + unsigned int frame_length = skb->len; + unsigned int align = ALIGN_SIZE(skb, header_lengt); + + if (!align) + return; + + skb_push(skb, align); + memmove(skb->data, skb->data + align, frame_length); + skb_trim(skb, frame_length); +} + +void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int frame_length = skb->len; + unsigned int header_align = ALIGN_SIZE(skb, 0); + unsigned int payload_align = ALIGN_SIZE(skb, header_length); + unsigned int l2pad = 4 - (payload_align - header_align); + + if (header_align == payload_align) { + /* + * Both header and payload must be moved the same + * amount of bytes to align them properly. This means + * we don't use the L2 padding but just move the entire + * frame. + */ + rt2x00queue_align_frame(skb); + } else if (!payload_align) { + /* + * Simple L2 padding, only the header needs to be moved, + * the payload is already properly aligned. + */ + skb_push(skb, header_align); + memmove(skb->data, skb->data + header_align, frame_length); + skbdesc->flags |= SKBDESC_L2_PADDED; } else { - /* Generic payload alignment to 4-byte boundary */ - skb_push(skb, align); - memmove(skb->data, skb->data + align, frame_length); + /* + * + * Complicated L2 padding, both header and payload need + * to be moved. By default we only move to the start + * of the buffer, so our header alignment needs to be + * increased if there is not enough room for the header + * to be moved. + */ + if (payload_align > header_align) + header_align += 4; + + skb_push(skb, header_align); + memmove(skb->data, skb->data + header_align, header_length); + memmove(skb->data + header_length + l2pad, + skb->data + header_length + l2pad + header_align, + frame_length - header_length); + skbdesc->flags |= SKBDESC_L2_PADDED; } } +void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int l2pad = 4 - (header_length & 3); + + if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED)) + return; + + memmove(skb->data + l2pad, skb->data, header_length); + skb_pull(skb, l2pad); +} + static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, struct txentry_desc *txdesc) { @@ -456,18 +510,15 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) /* * When DMA allocation is required we should guarentee to the * driver that the DMA is aligned to a 4-byte boundary. - * Aligning the header to this boundary can be done by calling - * rt2x00queue_payload_align with the header length of 0. * However some drivers require L2 padding to pad the payload * rather then the header. This could be a requirement for * PCI and USB devices, while header alignment only is valid * for PCI devices. */ if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) - rt2x00queue_payload_align(entry->skb, true, - txdesc.header_length); + rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length); else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) - rt2x00queue_payload_align(entry->skb, false, 0); + rt2x00queue_align_frame(entry->skb); /* * It could be possible that the queue was corrupted and this -- cgit v0.10.2 From 3107edbae8216a80920bed7f8d4ec2e6b62390f2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 30 Aug 2009 13:22:57 -0700 Subject: ipw2200: fix kconfig dependencies Fix kconfig dependencies for ipw2x00 drivers, fixes build errors: ERROR: "wiphy_free" [drivers/net/wireless/ipw2x00/libipw.ko] undefined! ERROR: "wiphy_unregister" [drivers/net/wireless/ipw2x00/libipw.ko] undefined! ERROR: "wiphy_new" [drivers/net/wireless/ipw2x00/libipw.ko] undefined! ERROR: "cfg80211_wext_giwname" [drivers/net/wireless/ipw2x00/ipw2200.ko] undefined! ERROR: "wiphy_register" [drivers/net/wireless/ipw2x00/ipw2200.ko] undefined! Signed-off-by: Randy Dunlap Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index 85cc799..a813138 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -4,7 +4,7 @@ config IPW2100 tristate "Intel PRO/Wireless 2100 Network Connection" - depends on PCI && WLAN_80211 + depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT select FW_LOADER select LIB80211 @@ -63,7 +63,7 @@ config IPW2100_DEBUG config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && WLAN_80211 + depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT select FW_LOADER select LIB80211 @@ -150,7 +150,7 @@ config IPW2200_DEBUG config LIBIPW tristate - depends on PCI && WLAN_80211 + depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT select CRYPTO select CRYPTO_ARC4 -- cgit v0.10.2 From 1c29ce672fe817c208309eea0c1ff7bf76250f15 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 31 Aug 2009 17:48:36 +0530 Subject: ath9k: Do an AHB reset before doing RTC reset Doing an RTC reset when DMA is active may corrupt memory, make sure no DMA is active at this moment by doing an AHB reset. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e340dac..71f27f3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1712,8 +1712,15 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, AR_RC_AHB); + REG_WRITE(ah, AR_RTC_RESET, 0); udelay(2); + + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, 0); + REG_WRITE(ah, AR_RTC_RESET, 1); if (!ath9k_hw_wait(ah, -- cgit v0.10.2 From 132ec92f3f70fe365c1f4b8d46e66cf8a2a16880 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 31 Aug 2009 09:50:09 +0200 Subject: x86, msr: Add rd/wrmsr interfaces with preset registers native_{rdmsr,wrmsr}_safe_regs are two new interfaces which allow presetting of a subset of eight x86 GPRs before executing the rd/wrmsr instructions. This is needed at least on AMD K8 for accessing an erratum workaround MSR. Originally based on an idea by H. Peter Anvin. Signed-off-by: Borislav Petkov LKML-Reference: <1251705011-18636-1-git-send-email-petkovbb@gmail.com> Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 48ad9d2..184d4a1 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -113,6 +113,9 @@ notrace static inline int native_write_msr_safe(unsigned int msr, extern unsigned long long native_read_tsc(void); +extern int native_rdmsr_safe_regs(u32 *regs); +extern int native_wrmsr_safe_regs(u32 *regs); + static __always_inline unsigned long long __native_read_tsc(void) { DECLARE_ARGS(val, low, high); @@ -189,6 +192,16 @@ static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) return err; } +static inline int rdmsr_safe_regs(u32 *regs) +{ + return native_rdmsr_safe_regs(regs); +} + +static inline int wrmsr_safe_regs(u32 *regs) +{ + return native_wrmsr_safe_regs(regs); +} + #define rdtscl(low) \ ((low) = (u32)__native_read_tsc()) diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 4fb37c8..1705944 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -168,7 +168,9 @@ struct pv_cpu_ops { err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */ u64 (*read_msr_amd)(unsigned int msr, int *err); u64 (*read_msr)(unsigned int msr, int *err); + int (*rdmsr_regs)(u32 *regs); int (*write_msr)(unsigned int msr, unsigned low, unsigned high); + int (*wrmsr_regs)(u32 *regs); u64 (*read_tsc)(void); u64 (*read_pmc)(int counter); @@ -820,6 +822,12 @@ static inline u64 paravirt_read_msr(unsigned msr, int *err) { return PVOP_CALL2(u64, pv_cpu_ops.read_msr, msr, err); } + +static inline int paravirt_rdmsr_regs(u32 *regs) +{ + return PVOP_CALL1(int, pv_cpu_ops.rdmsr_regs, regs); +} + static inline u64 paravirt_read_msr_amd(unsigned msr, int *err) { return PVOP_CALL2(u64, pv_cpu_ops.read_msr_amd, msr, err); @@ -829,6 +837,11 @@ static inline int paravirt_write_msr(unsigned msr, unsigned low, unsigned high) return PVOP_CALL3(int, pv_cpu_ops.write_msr, msr, low, high); } +static inline int paravirt_wrmsr_regs(u32 *regs) +{ + return PVOP_CALL1(int, pv_cpu_ops.wrmsr_regs, regs); +} + /* These should all do BUG_ON(_err), but our headers are too tangled. */ #define rdmsr(msr, val1, val2) \ do { \ @@ -862,6 +875,9 @@ do { \ _err; \ }) +#define rdmsr_safe_regs(regs) paravirt_rdmsr_regs(regs) +#define wrmsr_safe_regs(regs) paravirt_wrmsr_regs(regs) + static inline int rdmsrl_safe(unsigned msr, unsigned long long *p) { int err; diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 70ec9b9..67594af 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -362,8 +362,10 @@ struct pv_cpu_ops pv_cpu_ops = { #endif .wbinvd = native_wbinvd, .read_msr = native_read_msr_safe, + .rdmsr_regs = native_rdmsr_safe_regs, .read_msr_amd = native_read_msr_amd_safe, .write_msr = native_write_msr_safe, + .wrmsr_regs = native_wrmsr_safe_regs, .read_tsc = native_read_tsc, .read_pmc = native_read_pmc, .read_tscp = native_read_tscp, diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 07c3189..b59c064 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -8,6 +8,7 @@ lib-y := delay.o lib-y += thunk_$(BITS).o lib-y += usercopy_$(BITS).o getuser.o putuser.o lib-y += memcpy_$(BITS).o +lib-y += msr-reg.o ifeq ($(CONFIG_X86_32),y) obj-y += atomic64_32.o diff --git a/arch/x86/lib/msr-reg.S b/arch/x86/lib/msr-reg.S new file mode 100644 index 0000000..51f1bb3 --- /dev/null +++ b/arch/x86/lib/msr-reg.S @@ -0,0 +1,98 @@ +#include +#include +#include +#include + +#ifdef CONFIG_X86_64 +/* + * int native_{rdmsr,wrmsr}_safe_regs(u32 gprs[8]); + * + * reg layout: u32 gprs[eax, ecx, edx, ebx, esp, ebp, esi, edi] + * + */ +.macro op_safe_regs op:req +ENTRY(native_\op\()_safe_regs) + push %rbx + push %rbp + push $0 /* Return value */ + push %rdi + movl (%rdi), %eax + movl 4(%rdi), %ecx + movl 8(%rdi), %edx + movl 12(%rdi), %ebx + movl 20(%rdi), %ebp + movl 24(%rdi), %esi + movl 28(%rdi), %edi +1: \op +2: movl %edi, %r10d + pop %rdi + movl %eax, (%rdi) + movl %ecx, 4(%rdi) + movl %edx, 8(%rdi) + movl %ebx, 12(%rdi) + movl %ebp, 20(%rdi) + movl %esi, 24(%rdi) + movl %r10d, 28(%rdi) + pop %rax + pop %rbp + pop %rbx + ret +3: + movq $-EIO, 8(%rsp) + jmp 2b + .section __ex_table,"ax" + .balign 4 + .quad 1b, 3b + .previous +ENDPROC(native_\op\()_safe_regs) +.endm + +#else /* X86_32 */ + +.macro op_safe_regs op:req +ENTRY(native_\op\()_safe_regs) + push %ebx + push %ebp + push %esi + push %edi + push $0 /* Return value */ + push %eax + movl 4(%eax), %ecx + movl 8(%eax), %edx + movl 12(%eax), %ebx + movl 20(%eax), %ebp + movl 24(%eax), %esi + movl 28(%eax), %edi + movl (%eax), %eax +1: \op +2: push %eax + movl 4(%esp), %eax + pop (%eax) + addl $4, %esp + movl %ecx, 4(%eax) + movl %edx, 8(%eax) + movl %ebx, 12(%eax) + movl %ebp, 20(%eax) + movl %esi, 24(%eax) + movl %edi, 28(%eax) + pop %eax + pop %edi + pop %esi + pop %ebp + pop %ebx + ret +3: + movl $-EIO, 4(%esp) + jmp 2b + .section __ex_table,"ax" + .balign 4 + .long 1b, 3b + .previous +ENDPROC(native_\op\()_safe_regs) +.endm + +#endif + +op_safe_regs rdmsr +op_safe_regs wrmsr + -- cgit v0.10.2 From 177fed1ee8d727c39601ce9fc2299b4cb25a718e Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 31 Aug 2009 09:50:10 +0200 Subject: x86, msr: Rewrite AMD rd/wrmsr variants Switch them to native_{rd,wr}msr_safe_regs and remove pv_cpu_ops.read_msr_amd. Signed-off-by: Borislav Petkov LKML-Reference: <1251705011-18636-2-git-send-email-petkovbb@gmail.com> Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 184d4a1..09c5ca7 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -71,22 +71,6 @@ static inline unsigned long long native_read_msr_safe(unsigned int msr, return EAX_EDX_VAL(val, low, high); } -static inline unsigned long long native_read_msr_amd_safe(unsigned int msr, - int *err) -{ - DECLARE_ARGS(val, low, high); - - asm volatile("2: rdmsr ; xor %0,%0\n" - "1:\n\t" - ".section .fixup,\"ax\"\n\t" - "3: mov %3,%0 ; jmp 1b\n\t" - ".previous\n\t" - _ASM_EXTABLE(2b, 3b) - : "=r" (*err), EAX_EDX_RET(val, low, high) - : "c" (msr), "D" (0x9c5a203a), "i" (-EFAULT)); - return EAX_EDX_VAL(val, low, high); -} - static inline void native_write_msr(unsigned int msr, unsigned low, unsigned high) { @@ -184,14 +168,34 @@ static inline int rdmsrl_safe(unsigned msr, unsigned long long *p) *p = native_read_msr_safe(msr, &err); return err; } + static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) { + u32 gprs[8] = { 0 }; int err; - *p = native_read_msr_amd_safe(msr, &err); + gprs[1] = msr; + gprs[7] = 0x9c5a203a; + + err = native_rdmsr_safe_regs(gprs); + + *p = gprs[0] | ((u64)gprs[2] << 32); + return err; } +static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val) +{ + u32 gprs[8] = { 0 }; + + gprs[0] = (u32)val; + gprs[1] = msr; + gprs[2] = val >> 32; + gprs[7] = 0x9c5a203a; + + return native_wrmsr_safe_regs(gprs); +} + static inline int rdmsr_safe_regs(u32 *regs) { return native_rdmsr_safe_regs(regs); diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 1705944..1157493 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -166,7 +166,6 @@ struct pv_cpu_ops { /* MSR, PMC and TSR operations. err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */ - u64 (*read_msr_amd)(unsigned int msr, int *err); u64 (*read_msr)(unsigned int msr, int *err); int (*rdmsr_regs)(u32 *regs); int (*write_msr)(unsigned int msr, unsigned low, unsigned high); @@ -828,10 +827,6 @@ static inline int paravirt_rdmsr_regs(u32 *regs) return PVOP_CALL1(int, pv_cpu_ops.rdmsr_regs, regs); } -static inline u64 paravirt_read_msr_amd(unsigned msr, int *err) -{ - return PVOP_CALL2(u64, pv_cpu_ops.read_msr_amd, msr, err); -} static inline int paravirt_write_msr(unsigned msr, unsigned low, unsigned high) { return PVOP_CALL3(int, pv_cpu_ops.write_msr, msr, low, high); @@ -887,12 +882,31 @@ static inline int rdmsrl_safe(unsigned msr, unsigned long long *p) } static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) { + u32 gprs[8] = { 0 }; int err; - *p = paravirt_read_msr_amd(msr, &err); + gprs[1] = msr; + gprs[7] = 0x9c5a203a; + + err = paravirt_rdmsr_regs(gprs); + + *p = gprs[0] | ((u64)gprs[2] << 32); + return err; } +static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val) +{ + u32 gprs[8] = { 0 }; + + gprs[0] = (u32)val; + gprs[1] = msr; + gprs[2] = val >> 32; + gprs[7] = 0x9c5a203a; + + return paravirt_wrmsr_regs(gprs); +} + static inline u64 paravirt_read_tsc(void) { return PVOP_CALL0(u64, pv_cpu_ops.read_tsc); diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 67594af..f5b0b4a 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -363,7 +363,6 @@ struct pv_cpu_ops pv_cpu_ops = { .wbinvd = native_wbinvd, .read_msr = native_read_msr_safe, .rdmsr_regs = native_rdmsr_safe_regs, - .read_msr_amd = native_read_msr_amd_safe, .write_msr = native_write_msr_safe, .wrmsr_regs = native_wrmsr_safe_regs, .read_tsc = native_read_tsc, -- cgit v0.10.2 From 6b0f43ddfa358dc71ad2a2d57bce5906c1c5dc1a Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 31 Aug 2009 09:50:11 +0200 Subject: x86, AMD: Disable wrongly set X86_FEATURE_LAHF_LM CPUID bit fbd8b1819e80ac5a176d085fdddc3a34d1499318 turns off the bit for /proc/cpuinfo. However, a proper/full fix would be to additionally turn off the bit in the CPUID output so that future callers get correct CPU features info. Do that by basically reversing what the BIOS wrongfully does at boot. Signed-off-by: Borislav Petkov LKML-Reference: <1251705011-18636-3-git-send-email-petkovbb@gmail.com> Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 63fddcd..0a717fc 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -404,9 +404,18 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) /* * Some BIOSes incorrectly force this feature, but only K8 * revision D (model = 0x14) and later actually support it. + * (AMD Erratum #110, docId: 25759). */ - if (c->x86_model < 0x14) + if (c->x86_model < 0x14 && cpu_has(c, X86_FEATURE_LAHF_LM)) { + u64 val; + clear_cpu_cap(c, X86_FEATURE_LAHF_LM); + if (!rdmsrl_amd_safe(0xc001100d, &val)) { + val &= ~(1ULL << 32); + wrmsrl_amd_safe(0xc001100d, val); + } + } + } if (c->x86 == 0x10 || c->x86 == 0x11) set_cpu_cap(c, X86_FEATURE_REP_GOOD); -- cgit v0.10.2 From fe9b4e4e40ffdabbd385cdf171cb861c2fd517c0 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 31 Aug 2009 11:53:23 -0700 Subject: x86, asm: Add 32-bit versions of the combined CFI macros Add 32-bit versions of the combined CFI macros, equivalent to the 64-bit ones except, obviously, operating on 32-bit stack words. Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/dwarf2.h b/arch/x86/include/asm/dwarf2.h index 3afc5e8..ae6253a 100644 --- a/arch/x86/include/asm/dwarf2.h +++ b/arch/x86/include/asm/dwarf2.h @@ -87,9 +87,25 @@ CFI_RESTORE \reg .endm #else /*!CONFIG_X86_64*/ + .macro pushl_cfi reg + pushl \reg + CFI_ADJUST_CFA_OFFSET 4 + .endm - /* 32bit defenitions are missed yet */ + .macro popl_cfi reg + popl \reg + CFI_ADJUST_CFA_OFFSET -4 + .endm + .macro movl_cfi reg offset=0 + movl %\reg, \offset(%esp) + CFI_REL_OFFSET \reg, \offset + .endm + + .macro movl_cfi_restore offset reg + movl \offset(%esp), %\reg + CFI_RESTORE \reg + .endm #endif /*!CONFIG_X86_64*/ #endif /*__ASSEMBLY__*/ -- cgit v0.10.2 From 709972b1f6f70535d1fddbe1243a51b90c408a1c Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 31 Aug 2009 11:57:20 -0700 Subject: x86, asm: Make _ASM_EXTABLE() usable from assembly code We have had this convenient macro _ASM_EXTABLE() to generate exception table entry in inline assembly. Make it also usable for pure assembly. Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index 56be78f..b3ed1e1 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -3,7 +3,7 @@ #ifdef __ASSEMBLY__ # define __ASM_FORM(x) x -# define __ASM_EX_SEC .section __ex_table +# define __ASM_EX_SEC .section __ex_table, "a" #else # define __ASM_FORM(x) " " #x " " # define __ASM_EX_SEC " .section __ex_table,\"a\"\n" @@ -38,10 +38,18 @@ #define _ASM_DI __ASM_REG(di) /* Exception table entry */ +#ifdef __ASSEMBLY__ +# define _ASM_EXTABLE(from,to) \ + __ASM_EX_SEC ; \ + _ASM_ALIGN ; \ + _ASM_PTR from , to ; \ + .previous +#else # define _ASM_EXTABLE(from,to) \ __ASM_EX_SEC \ _ASM_ALIGN "\n" \ _ASM_PTR #from "," #to "\n" \ " .previous\n" +#endif #endif /* _ASM_X86_ASM_H */ -- cgit v0.10.2 From 79c5dca3619d6ae15815eec14cd7a43db5f38b47 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 31 Aug 2009 13:59:53 -0700 Subject: x86, msr: CFI annotations, cleanups for msr-reg.S Add CFI annotations for native_{rd,wr}msr_safe_regs(). Simplify the 64-bit implementation: we don't allow the upper half registers to be set, and so we can use them to carry state across the operation. Signed-off-by: H. Peter Anvin Cc: Borislav Petkov LKML-Reference: <1251705011-18636-1-git-send-email-petkovbb@gmail.com> diff --git a/arch/x86/lib/msr-reg.S b/arch/x86/lib/msr-reg.S index 51f1bb3..9e8cdcf 100644 --- a/arch/x86/lib/msr-reg.S +++ b/arch/x86/lib/msr-reg.S @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -12,10 +13,11 @@ */ .macro op_safe_regs op:req ENTRY(native_\op\()_safe_regs) - push %rbx - push %rbp - push $0 /* Return value */ - push %rdi + CFI_STARTPROC + pushq_cfi %rbx + pushq_cfi %rbp + movq %rdi, %r10 /* Save pointer */ + xorl %r11d, %r11d /* Return value */ movl (%rdi), %eax movl 4(%rdi), %ecx movl 8(%rdi), %edx @@ -23,27 +25,26 @@ ENTRY(native_\op\()_safe_regs) movl 20(%rdi), %ebp movl 24(%rdi), %esi movl 28(%rdi), %edi + CFI_REMEMBER_STATE 1: \op -2: movl %edi, %r10d - pop %rdi - movl %eax, (%rdi) - movl %ecx, 4(%rdi) - movl %edx, 8(%rdi) - movl %ebx, 12(%rdi) - movl %ebp, 20(%rdi) - movl %esi, 24(%rdi) - movl %r10d, 28(%rdi) - pop %rax - pop %rbp - pop %rbx +2: movl %eax, (%r10) + movl %r11d, %eax /* Return value */ + movl %ecx, 4(%r10) + movl %edx, 8(%r10) + movl %ebx, 12(%r10) + movl %ebp, 20(%r10) + movl %esi, 24(%r10) + movl %edi, 28(%r10) + popq_cfi %rbp + popq_cfi %rbx ret 3: - movq $-EIO, 8(%rsp) + CFI_RESTORE_STATE + movl $-EIO, %r11d jmp 2b - .section __ex_table,"ax" - .balign 4 - .quad 1b, 3b - .previous + + _ASM_EXTABLE(1b, 3b) + CFI_ENDPROC ENDPROC(native_\op\()_safe_regs) .endm @@ -51,12 +52,13 @@ ENDPROC(native_\op\()_safe_regs) .macro op_safe_regs op:req ENTRY(native_\op\()_safe_regs) - push %ebx - push %ebp - push %esi - push %edi - push $0 /* Return value */ - push %eax + CFI_STARTPROC + pushl_cfi %ebx + pushl_cfi %ebp + pushl_cfi %esi + pushl_cfi %edi + pushl_cfi $0 /* Return value */ + pushl_cfi %eax movl 4(%eax), %ecx movl 8(%eax), %edx movl 12(%eax), %ebx @@ -64,30 +66,32 @@ ENTRY(native_\op\()_safe_regs) movl 24(%eax), %esi movl 28(%eax), %edi movl (%eax), %eax + CFI_REMEMBER_STATE 1: \op -2: push %eax +2: pushl_cfi %eax movl 4(%esp), %eax - pop (%eax) + popl_cfi (%eax) addl $4, %esp + CFI_ADJUST_CFA_OFFSET -4 movl %ecx, 4(%eax) movl %edx, 8(%eax) movl %ebx, 12(%eax) movl %ebp, 20(%eax) movl %esi, 24(%eax) movl %edi, 28(%eax) - pop %eax - pop %edi - pop %esi - pop %ebp - pop %ebx + popl_cfi %eax + popl_cfi %edi + popl_cfi %esi + popl_cfi %ebp + popl_cfi %ebx ret 3: + CFI_RESTORE_STATE movl $-EIO, 4(%esp) jmp 2b - .section __ex_table,"ax" - .balign 4 - .long 1b, 3b - .previous + + _ASM_EXTABLE(1b, 3b) + CFI_ENDPROC ENDPROC(native_\op\()_safe_regs) .endm -- cgit v0.10.2 From 0cc0213e73af5963eca259c84876937c20689dbd Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 31 Aug 2009 14:23:29 -0700 Subject: x86, msr: Have the _safe MSR functions return -EIO, not -EFAULT For some reason, the _safe MSR functions returned -EFAULT, not -EIO. However, the only user which cares about the return code as anything other than a boolean is the MSR driver, which wants -EIO. Change it to -EIO across the board. Signed-off-by: H. Peter Anvin Cc: Jeremy Fitzhardinge Cc: Chris Wright Cc: Alok Kataria Cc: Rusty Russell diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 09c5ca7..943fdd5 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -67,7 +67,7 @@ static inline unsigned long long native_read_msr_safe(unsigned int msr, ".previous\n\t" _ASM_EXTABLE(2b, 3b) : [err] "=r" (*err), EAX_EDX_RET(val, low, high) - : "c" (msr), [fault] "i" (-EFAULT)); + : "c" (msr), [fault] "i" (-EIO)); return EAX_EDX_VAL(val, low, high); } @@ -90,7 +90,7 @@ notrace static inline int native_write_msr_safe(unsigned int msr, _ASM_EXTABLE(2b, 3b) : [err] "=a" (err) : "c" (msr), "0" (low), "d" (high), - [fault] "i" (-EFAULT) + [fault] "i" (-EIO) : "memory"); return err; } diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index 98fd6cd..2cfbb4b 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -80,11 +80,8 @@ static ssize_t msr_read(struct file *file, char __user *buf, for (; count; count -= 8) { err = rdmsr_safe_on_cpu(cpu, reg, &data[0], &data[1]); - if (err) { - if (err == -EFAULT) /* Fix idiotic error code */ - err = -EIO; + if (err) break; - } if (copy_to_user(tmp, &data, 8)) { err = -EFAULT; break; @@ -115,11 +112,8 @@ static ssize_t msr_write(struct file *file, const char __user *buf, break; } err = wrmsr_safe_on_cpu(cpu, reg, data[0], data[1]); - if (err) { - if (err == -EFAULT) /* Fix idiotic error code */ - err = -EIO; + if (err) break; - } tmp += 2; bytes += 8; } diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 0a1700a..a8432d8 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -713,7 +713,7 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) set: base = ((u64)high << 32) | low; if (HYPERVISOR_set_segment_base(which, base) != 0) - ret = -EFAULT; + ret = -EIO; break; #endif -- cgit v0.10.2 From 2b980dbd77d229eb60588802162c9659726b11f4 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 28 Aug 2009 18:12:43 -0400 Subject: lsm: Add hooks to the TUN driver The TUN driver lacks any LSM hooks which makes it difficult for LSM modules, such as SELinux, to enforce access controls on network traffic generated by TUN users; this is particularly problematic for virtualization apps such as QEMU and KVM. This patch adds three new LSM hooks designed to control the creation and attachment of TUN devices, the hooks are: * security_tun_dev_create() Provides access control for the creation of new TUN devices * security_tun_dev_post_create() Provides the ability to create the necessary socket LSM state for newly created TUN devices * security_tun_dev_attach() Provides access control for attaching to existing, persistent TUN devices and the ability to update the TUN device's socket LSM state as necessary Signed-off-by: Paul Moore Acked-by: Eric Paris Acked-by: Serge Hallyn Acked-by: David S. Miller Signed-off-by: James Morris diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 42b6c63..87214a2 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -130,17 +130,10 @@ static inline struct tun_sock *tun_sk(struct sock *sk) static int tun_attach(struct tun_struct *tun, struct file *file) { struct tun_file *tfile = file->private_data; - const struct cred *cred = current_cred(); int err; ASSERT_RTNL(); - /* Check permissions */ - if (((tun->owner != -1 && cred->euid != tun->owner) || - (tun->group != -1 && !in_egroup_p(tun->group))) && - !capable(CAP_NET_ADMIN)) - return -EPERM; - netif_tx_lock_bh(tun->dev); err = -EINVAL; @@ -926,6 +919,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) dev = __dev_get_by_name(net, ifr->ifr_name); if (dev) { + const struct cred *cred = current_cred(); + if (ifr->ifr_flags & IFF_TUN_EXCL) return -EBUSY; if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops) @@ -935,6 +930,14 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) else return -EINVAL; + if (((tun->owner != -1 && cred->euid != tun->owner) || + (tun->group != -1 && !in_egroup_p(tun->group))) && + !capable(CAP_NET_ADMIN)) + return -EPERM; + err = security_tun_dev_attach(tun->sk); + if (err < 0) + return err; + err = tun_attach(tun, file); if (err < 0) return err; @@ -947,6 +950,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) if (!capable(CAP_NET_ADMIN)) return -EPERM; + err = security_tun_dev_create(); + if (err < 0) + return err; /* Set dev type */ if (ifr->ifr_flags & IFF_TUN) { @@ -989,6 +995,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) tun->sk = sk; container_of(sk, struct tun_sock, sk)->tun = tun; + security_tun_dev_post_create(sk); + tun_net_init(dev); if (strchr(dev->name, '%')) { diff --git a/include/linux/security.h b/include/linux/security.h index a16d6b7..40ba39e 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -998,6 +998,17 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Sets the connection's peersid to the secmark on skb. * @req_classify_flow: * Sets the flow's sid to the openreq sid. + * @tun_dev_create: + * Check permissions prior to creating a new TUN device. + * @tun_dev_post_create: + * This hook allows a module to update or allocate a per-socket security + * structure. + * @sk contains the newly created sock structure. + * @tun_dev_attach: + * Check permissions prior to attaching to a persistent TUN device. This + * hook can also be used by the module to update any security state + * associated with the TUN device's sock structure. + * @sk contains the existing sock structure. * * Security hooks for XFRM operations. * @@ -1597,6 +1608,9 @@ struct security_operations { void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req); void (*inet_conn_established) (struct sock *sk, struct sk_buff *skb); void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl); + int (*tun_dev_create)(void); + void (*tun_dev_post_create)(struct sock *sk); + int (*tun_dev_attach)(struct sock *sk); #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM @@ -2586,6 +2600,9 @@ void security_inet_csk_clone(struct sock *newsk, const struct request_sock *req); void security_inet_conn_established(struct sock *sk, struct sk_buff *skb); +int security_tun_dev_create(void); +void security_tun_dev_post_create(struct sock *sk); +int security_tun_dev_attach(struct sock *sk); #else /* CONFIG_SECURITY_NETWORK */ static inline int security_unix_stream_connect(struct socket *sock, @@ -2736,6 +2753,20 @@ static inline void security_inet_conn_established(struct sock *sk, struct sk_buff *skb) { } + +static inline int security_tun_dev_create(void) +{ + return 0; +} + +static inline void security_tun_dev_post_create(struct sock *sk) +{ +} + +static inline int security_tun_dev_attach(struct sock *sk) +{ + return 0; +} #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM diff --git a/security/capability.c b/security/capability.c index 1b943f5..06400cf 100644 --- a/security/capability.c +++ b/security/capability.c @@ -706,10 +706,26 @@ static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb) { } + + static void cap_req_classify_flow(const struct request_sock *req, struct flowi *fl) { } + +static int cap_tun_dev_create(void) +{ + return 0; +} + +static void cap_tun_dev_post_create(struct sock *sk) +{ +} + +static int cap_tun_dev_attach(struct sock *sk) +{ + return 0; +} #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM @@ -1026,6 +1042,9 @@ void security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, inet_csk_clone); set_to_cap_if_null(ops, inet_conn_established); set_to_cap_if_null(ops, req_classify_flow); + set_to_cap_if_null(ops, tun_dev_create); + set_to_cap_if_null(ops, tun_dev_post_create); + set_to_cap_if_null(ops, tun_dev_attach); #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM set_to_cap_if_null(ops, xfrm_policy_alloc_security); diff --git a/security/security.c b/security/security.c index 0e993f4..f88eaf6 100644 --- a/security/security.c +++ b/security/security.c @@ -1117,6 +1117,24 @@ void security_inet_conn_established(struct sock *sk, security_ops->inet_conn_established(sk, skb); } +int security_tun_dev_create(void) +{ + return security_ops->tun_dev_create(); +} +EXPORT_SYMBOL(security_tun_dev_create); + +void security_tun_dev_post_create(struct sock *sk) +{ + return security_ops->tun_dev_post_create(sk); +} +EXPORT_SYMBOL(security_tun_dev_post_create); + +int security_tun_dev_attach(struct sock *sk) +{ + return security_ops->tun_dev_attach(sk); +} +EXPORT_SYMBOL(security_tun_dev_attach); + #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM -- cgit v0.10.2 From ed6d76e4c32de0c2ad5f1d572b948ef49e465176 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 28 Aug 2009 18:12:49 -0400 Subject: selinux: Support for the new TUN LSM hooks Add support for the new TUN LSM hooks: security_tun_dev_create(), security_tun_dev_post_create() and security_tun_dev_attach(). This includes the addition of a new object class, tun_socket, which represents the socks associated with TUN devices. The _tun_dev_create() and _tun_dev_post_create() hooks are fairly similar to the standard socket functions but _tun_dev_attach() is a bit special. The _tun_dev_attach() is unique because it involves a domain attaching to an existing TUN device and its associated tun_socket object, an operation which does not exist with standard sockets and most closely resembles a relabel operation. Signed-off-by: Paul Moore Acked-by: Eric Paris Signed-off-by: James Morris diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index ac79f9e..27b4c55 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -13,8 +13,8 @@ * Eric Paris * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * - * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. - * Paul Moore + * Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P. + * Paul Moore * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. * Yuichi Nakamura * @@ -4325,6 +4325,59 @@ static void selinux_req_classify_flow(const struct request_sock *req, fl->secid = req->secid; } +static int selinux_tun_dev_create(void) +{ + u32 sid = current_sid(); + + /* we aren't taking into account the "sockcreate" SID since the socket + * that is being created here is not a socket in the traditional sense, + * instead it is a private sock, accessible only to the kernel, and + * representing a wide range of network traffic spanning multiple + * connections unlike traditional sockets - check the TUN driver to + * get a better understanding of why this socket is special */ + + return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE, + NULL); +} + +static void selinux_tun_dev_post_create(struct sock *sk) +{ + struct sk_security_struct *sksec = sk->sk_security; + + /* we don't currently perform any NetLabel based labeling here and it + * isn't clear that we would want to do so anyway; while we could apply + * labeling without the support of the TUN user the resulting labeled + * traffic from the other end of the connection would almost certainly + * cause confusion to the TUN user that had no idea network labeling + * protocols were being used */ + + /* see the comments in selinux_tun_dev_create() about why we don't use + * the sockcreate SID here */ + + sksec->sid = current_sid(); + sksec->sclass = SECCLASS_TUN_SOCKET; +} + +static int selinux_tun_dev_attach(struct sock *sk) +{ + struct sk_security_struct *sksec = sk->sk_security; + u32 sid = current_sid(); + int err; + + err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET, + TUN_SOCKET__RELABELFROM, NULL); + if (err) + return err; + err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, + TUN_SOCKET__RELABELTO, NULL); + if (err) + return err; + + sksec->sid = sid; + + return 0; +} + static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) { int err = 0; @@ -5494,6 +5547,9 @@ static struct security_operations selinux_ops = { .inet_csk_clone = selinux_inet_csk_clone, .inet_conn_established = selinux_inet_conn_established, .req_classify_flow = selinux_req_classify_flow, + .tun_dev_create = selinux_tun_dev_create, + .tun_dev_post_create = selinux_tun_dev_post_create, + .tun_dev_attach = selinux_tun_dev_attach, #ifdef CONFIG_SECURITY_NETWORK_XFRM .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, diff --git a/security/selinux/include/av_inherit.h b/security/selinux/include/av_inherit.h index 8377a4b..abedcd7 100644 --- a/security/selinux/include/av_inherit.h +++ b/security/selinux/include/av_inherit.h @@ -15,6 +15,7 @@ S_(SECCLASS_KEY_SOCKET, socket, 0x00400000UL) S_(SECCLASS_UNIX_STREAM_SOCKET, socket, 0x00400000UL) S_(SECCLASS_UNIX_DGRAM_SOCKET, socket, 0x00400000UL) + S_(SECCLASS_TUN_SOCKET, socket, 0x00400000UL) S_(SECCLASS_IPC, ipc, 0x00000200UL) S_(SECCLASS_SEM, ipc, 0x00000200UL) S_(SECCLASS_MSGQ, ipc, 0x00000200UL) diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index 21c7226..0546d61 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h @@ -423,6 +423,28 @@ #define UNIX_DGRAM_SOCKET__RECV_MSG 0x00080000UL #define UNIX_DGRAM_SOCKET__SEND_MSG 0x00100000UL #define UNIX_DGRAM_SOCKET__NAME_BIND 0x00200000UL +#define TUN_SOCKET__IOCTL 0x00000001UL +#define TUN_SOCKET__READ 0x00000002UL +#define TUN_SOCKET__WRITE 0x00000004UL +#define TUN_SOCKET__CREATE 0x00000008UL +#define TUN_SOCKET__GETATTR 0x00000010UL +#define TUN_SOCKET__SETATTR 0x00000020UL +#define TUN_SOCKET__LOCK 0x00000040UL +#define TUN_SOCKET__RELABELFROM 0x00000080UL +#define TUN_SOCKET__RELABELTO 0x00000100UL +#define TUN_SOCKET__APPEND 0x00000200UL +#define TUN_SOCKET__BIND 0x00000400UL +#define TUN_SOCKET__CONNECT 0x00000800UL +#define TUN_SOCKET__LISTEN 0x00001000UL +#define TUN_SOCKET__ACCEPT 0x00002000UL +#define TUN_SOCKET__GETOPT 0x00004000UL +#define TUN_SOCKET__SETOPT 0x00008000UL +#define TUN_SOCKET__SHUTDOWN 0x00010000UL +#define TUN_SOCKET__RECVFROM 0x00020000UL +#define TUN_SOCKET__SENDTO 0x00040000UL +#define TUN_SOCKET__RECV_MSG 0x00080000UL +#define TUN_SOCKET__SEND_MSG 0x00100000UL +#define TUN_SOCKET__NAME_BIND 0x00200000UL #define PROCESS__FORK 0x00000001UL #define PROCESS__TRANSITION 0x00000002UL #define PROCESS__SIGCHLD 0x00000004UL diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h index 21ec786..7ab9299 100644 --- a/security/selinux/include/class_to_string.h +++ b/security/selinux/include/class_to_string.h @@ -77,3 +77,4 @@ S_(NULL) S_(NULL) S_("kernel_service") + S_("tun_socket") diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h index 882f27d..f248500 100644 --- a/security/selinux/include/flask.h +++ b/security/selinux/include/flask.h @@ -53,6 +53,7 @@ #define SECCLASS_PEER 68 #define SECCLASS_CAPABILITY2 69 #define SECCLASS_KERNEL_SERVICE 74 +#define SECCLASS_TUN_SOCKET 75 /* * Security identifier indices for initial entities -- cgit v0.10.2 From 8b956bf1f0f2b552ed93cf6cafe823edff298b3b Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 31 Aug 2009 14:13:48 -0700 Subject: x86, msr: Create _on_cpu helpers for {rw,wr}msr_safe_regs() Create _on_cpu helpers for {rw,wr}msr_safe_regs() analogously with the other MSR functions. This will be necessary to add support for these to the MSR driver. Signed-off-by: H. Peter Anvin Cc: Borislav Petkov diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 943fdd5..8e56712 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -97,8 +97,8 @@ notrace static inline int native_write_msr_safe(unsigned int msr, extern unsigned long long native_read_tsc(void); -extern int native_rdmsr_safe_regs(u32 *regs); -extern int native_wrmsr_safe_regs(u32 *regs); +extern int native_rdmsr_safe_regs(u32 regs[8]); +extern int native_wrmsr_safe_regs(u32 regs[8]); static __always_inline unsigned long long __native_read_tsc(void) { @@ -196,12 +196,12 @@ static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val) return native_wrmsr_safe_regs(gprs); } -static inline int rdmsr_safe_regs(u32 *regs) +static inline int rdmsr_safe_regs(u32 regs[8]) { return native_rdmsr_safe_regs(regs); } -static inline int wrmsr_safe_regs(u32 *regs) +static inline int wrmsr_safe_regs(u32 regs[8]) { return native_wrmsr_safe_regs(regs); } @@ -245,6 +245,8 @@ void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs); void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs); int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); +int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); +int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); #else /* CONFIG_SMP */ static inline int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) { @@ -275,6 +277,14 @@ static inline int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) { return wrmsr_safe(msr_no, l, h); } +static inline int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]) +{ + return rdmsr_safe_regs(regs); +} +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__ */ diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c index caa24ac..33a1e3c 100644 --- a/arch/x86/lib/msr.c +++ b/arch/x86/lib/msr.c @@ -175,3 +175,52 @@ int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) return err ? err : rv.err; } EXPORT_SYMBOL(wrmsr_safe_on_cpu); + +/* + * These variants are significantly slower, but allows control over + * the entire 32-bit GPR set. + */ +struct msr_regs_info { + u32 *regs; + int err; +}; + +static void __rdmsr_safe_regs_on_cpu(void *info) +{ + struct msr_regs_info *rv = info; + + rv->err = rdmsr_safe_regs(rv->regs); +} + +static void __wrmsr_safe_regs_on_cpu(void *info) +{ + struct msr_regs_info *rv = info; + + rv->err = wrmsr_safe_regs(rv->regs); +} + +int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) +{ + int err; + struct msr_regs_info rv; + + rv.regs = regs; + rv.err = -EIO; + err = smp_call_function_single(cpu, __rdmsr_safe_regs_on_cpu, &rv, 1); + + return err ? err : rv.err; +} +EXPORT_SYMBOL(rdmsr_safe_regs_on_cpu); + +int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) +{ + int err; + struct msr_regs_info rv; + + rv.regs = regs; + rv.err = -EIO; + err = smp_call_function_single(cpu, __wrmsr_safe_regs_on_cpu, &rv, 1); + + return err ? err : rv.err; +} +EXPORT_SYMBOL(wrmsr_safe_regs_on_cpu); -- cgit v0.10.2 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 diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index dbea4f9..1c058b5 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 8e56712..7e2b6ba 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 2cfbb4b..7dd9500 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 v0.10.2 From f8ff035e38514ea60aae8752af45ed90e7598fcd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 1 Sep 2009 08:53:19 +0200 Subject: ALSA: hda - Add another entry for Nvidia HDMI device Added another entry for Nvidia HDMI device (10de:0003). Reference: kernel bug#14097 http://bugzilla.kernel.org/show_bug.cgi?id=14097 Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index f5792e2..c8435c9 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -377,6 +377,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) */ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, + { .id = 0x10de0003, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, @@ -385,6 +386,7 @@ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { }; MODULE_ALIAS("snd-hda-codec-id:10de0002"); +MODULE_ALIAS("snd-hda-codec-id:10de0003"); MODULE_ALIAS("snd-hda-codec-id:10de0006"); MODULE_ALIAS("snd-hda-codec-id:10de0007"); MODULE_ALIAS("snd-hda-codec-id:10de0067"); -- cgit v0.10.2 From 2ad81ba0147919edc0cf56b80c6224775656b78d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 1 Sep 2009 09:09:26 +0200 Subject: ALSA: hda - Unmute docking line-out as default with AD1984A codec Unmute the docking-station line-out as default on machines with AD1984A codec chip. It can be still muted via "Dock" mixer switch. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index db3f3b1..215e72a 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3885,6 +3885,8 @@ static struct hda_verb ad1884a_laptop_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ + /* Port-D (docking line-out) pin - default unmuted */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* analog mix */ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* unsolicited event for pin-sense */ -- cgit v0.10.2 From 96910b6dc8a4fdb75e69f09f47b62d41743d36ba Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 31 Aug 2009 14:43:34 +0200 Subject: locking, m68k/asm-offsets: Rename signal defines In order to be able to use asm-offsets.h in C files the existing namespace conflicts must be solved first. In asm-offsets.h there are defines for signal constants, so they can be used in assembler files. Unfortunately the existing defines use a 1:1 mapping for the macro names which results in name space conflicts if the header file would also be used in C files. So rename the created defines and add an "L" prefix to each one since that has already been done for the SIGTRAP define in entry_mm. Signed-off-by: Heiko Carstens Cc: Peter Zijlstra Cc: Arnd Bergmann Cc: Nick Piggin Cc: Martin Schwidefsky Cc: Horst Hartmann Cc: Christian Ehrhardt Cc: Andrew Morton Cc: Linus Torvalds Cc: David Miller Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: LKML-Reference: <20090831124416.998821502@de.ibm.com> Signed-off-by: Ingo Molnar diff --git a/arch/m68k/include/asm/entry_mm.h b/arch/m68k/include/asm/entry_mm.h index 4fcfc28..4741258 100644 --- a/arch/m68k/include/asm/entry_mm.h +++ b/arch/m68k/include/asm/entry_mm.h @@ -46,7 +46,6 @@ #define curptr a2 LFLUSH_I_AND_D = 0x00000808 -LSIGTRAP = 5 /* process bits for task_struct.ptrace */ PT_TRACESYS_OFF = 3 diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c index 25d6b72..73e5e58 100644 --- a/arch/m68k/kernel/asm-offsets.c +++ b/arch/m68k/kernel/asm-offsets.c @@ -89,10 +89,10 @@ int main(void) DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref)); /* signal defines */ - DEFINE(SIGSEGV, SIGSEGV); - DEFINE(SEGV_MAPERR, SEGV_MAPERR); - DEFINE(SIGTRAP, SIGTRAP); - DEFINE(TRAP_TRACE, TRAP_TRACE); + DEFINE(LSIGSEGV, SIGSEGV); + DEFINE(LSEGV_MAPERR, SEGV_MAPERR); + DEFINE(LSIGTRAP, SIGTRAP); + DEFINE(LTRAP_TRACE, TRAP_TRACE); /* offsets into the custom struct */ DEFINE(CUSTOMBASE, &amiga_custom); diff --git a/arch/m68k/math-emu/fp_entry.S b/arch/m68k/math-emu/fp_entry.S index 916c6f3..a3fe1f3 100644 --- a/arch/m68k/math-emu/fp_entry.S +++ b/arch/m68k/math-emu/fp_entry.S @@ -85,8 +85,8 @@ fp_err_ua2: fp_err_ua1: addq.l #4,%sp move.l %a0,-(%sp) - pea SEGV_MAPERR - pea SIGSEGV + pea LSEGV_MAPERR + pea LSIGSEGV jsr fpemu_signal add.w #12,%sp jra ret_from_exception @@ -96,8 +96,8 @@ fp_err_ua1: | it does not really belong here, but... fp_sendtrace060: move.l (FPS_PC,%sp),-(%sp) - pea TRAP_TRACE - pea SIGTRAP + pea LTRAP_TRACE + pea LSIGTRAP jsr fpemu_signal add.w #12,%sp jra ret_from_exception -- cgit v0.10.2 From dc1f8bf68b311b1537cb65893430b6796118498a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:40 +0000 Subject: netdev: change transmit to limited range type The transmit function should only return one of three possible values, some drivers got confused and returned errno's or other values. This changes the definition so that this can be caught at compile time. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 60d3aac..376a2e1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -79,17 +79,19 @@ struct wireless_dev; #define net_xmit_eval(e) ((e) == NET_XMIT_CN? 0 : (e)) #define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0) +/* Driver transmit return codes */ +enum netdev_tx { + NETDEV_TX_OK = 0, /* driver took care of packet */ + NETDEV_TX_BUSY, /* driver tx path was busy*/ + NETDEV_TX_LOCKED = -1, /* driver tx lock was already taken */ +}; +typedef enum netdev_tx netdev_tx_t; + #endif #define MAX_ADDR_LEN 32 /* Largest hardware address length */ -/* Driver transmit return codes */ -#define NETDEV_TX_OK 0 /* driver took care of packet */ -#define NETDEV_TX_BUSY 1 /* driver tx path was busy*/ -#define NETDEV_TX_LOCKED -1 /* driver tx lock was already taken */ - #ifdef __KERNEL__ - /* * Compute the worst case header length according to the protocols * used. @@ -507,9 +509,11 @@ struct netdev_queue { * This function is called when network device transistions to the down * state. * - * int (*ndo_start_xmit)(struct sk_buff *skb, struct net_device *dev); + * netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, + * struct net_device *dev); * Called when a packet needs to be transmitted. - * Must return NETDEV_TX_OK , NETDEV_TX_BUSY, or NETDEV_TX_LOCKED, + * Must return NETDEV_TX_OK , NETDEV_TX_BUSY. + * (can also return NETDEV_TX_LOCKED iff NETIF_F_LLTX) * Required can not be NULL. * * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb); @@ -580,7 +584,7 @@ struct net_device_ops { void (*ndo_uninit)(struct net_device *dev); int (*ndo_open)(struct net_device *dev); int (*ndo_stop)(struct net_device *dev); - int (*ndo_start_xmit) (struct sk_buff *skb, + netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb, struct net_device *dev); u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb); -- cgit v0.10.2 From 6fef4c0c8eeff7de13007a5f56113475444a253d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:41 +0000 Subject: netdev: convert pseudo-devices to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index f5c586c..1ad8785 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -169,7 +169,8 @@ static int ether1394_header_cache(const struct neighbour *neigh, static void ether1394_header_cache_update(struct hh_cache *hh, const struct net_device *dev, const unsigned char *haddr); -static int ether1394_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ether1394_tx(struct sk_buff *skb, + struct net_device *dev); static void ether1394_iso(struct hpsb_iso *iso); static struct ethtool_ops ethtool_ops; @@ -1555,7 +1556,8 @@ static void ether1394_complete_cb(void *__ptask) } /* Transmit a packet (called by kernel) */ -static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ether1394_tx(struct sk_buff *skb, + struct net_device *dev) { struct eth1394hdr hdr_buf; struct eth1394_priv *priv = netdev_priv(dev); @@ -1694,14 +1696,6 @@ fail: dev->stats.tx_errors++; spin_unlock_irqrestore(&priv->lock, flags); - /* - * FIXME: According to a patch from 2003-02-26, "returning non-zero - * causes serious problems" here, allegedly. Before that patch, - * -ERRNO was returned which is not appropriate under Linux 2.6. - * Perhaps more needs to be done? Stop the queue in serious - * conditions and restart it elsewhere? - */ - /* return NETDEV_TX_BUSY; */ return NETDEV_TX_OK; } diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 6e695ac..84a2be4 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -288,7 +288,8 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, return rc; } -static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); @@ -325,8 +326,8 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); u16 vlan_tci; diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index 9c42990..26fb831 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -165,7 +165,8 @@ static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session } #endif -static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t bnep_net_xmit(struct sk_buff *skb, + struct net_device *dev) { struct bnep_session *s = netdev_priv(dev); struct sock *sk = s->sock->sk; diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 15d43ba..07a0777 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -20,7 +20,7 @@ #include "br_private.h" /* net device transmit always called with no BH (preempt_disabled) */ -int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); const unsigned char *dest = skb->data; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 8319247..2114e45 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -143,7 +143,8 @@ static inline int br_is_root_bridge(const struct net_bridge *br) /* br_device.c */ extern void br_dev_setup(struct net_device *dev); -extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev); +extern netdev_tx_t br_dev_xmit(struct sk_buff *skb, + struct net_device *dev); /* br_fdb.c */ extern int br_fdb_init(void); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 2001cb1..0bcecbf 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3381,7 +3381,7 @@ static void idle(struct pktgen_dev *pkt_dev) static void pktgen_xmit(struct pktgen_dev *pkt_dev) { struct net_device *odev = pkt_dev->odev; - int (*xmit)(struct sk_buff *, struct net_device *) + netdev_tx_t (*xmit)(struct sk_buff *, struct net_device *) = odev->netdev_ops->ndo_start_xmit; struct netdev_queue *txq; u16 queue_map; diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 41055f3..4b0ea05 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -169,13 +169,13 @@ struct net_device *dsa_slave_create(struct dsa_switch *ds, int port, char *name); /* tag_dsa.c */ -int dsa_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev); /* tag_edsa.c */ -int edsa_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev); /* tag_trailer.c */ -int trailer_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev); #endif diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c index 8fa25ba..cdf2d28 100644 --- a/net/dsa/tag_dsa.c +++ b/net/dsa/tag_dsa.c @@ -15,7 +15,7 @@ #define DSA_HLEN 4 -int dsa_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); u8 *dsa_header; diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c index 815607b..8f53948 100644 --- a/net/dsa/tag_edsa.c +++ b/net/dsa/tag_edsa.c @@ -16,7 +16,7 @@ #define DSA_HLEN 4 #define EDSA_HLEN 8 -int edsa_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); u8 *edsa_header; diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c index 1c3e30c..a85c829 100644 --- a/net/dsa/tag_trailer.c +++ b/net/dsa/tag_trailer.c @@ -13,7 +13,7 @@ #include #include "dsa_priv.h" -int trailer_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct sk_buff *nskb; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index b902ef5..5b1af70 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -662,7 +662,7 @@ drop_nolock: return(0); } -static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct net_device_stats *stats = &tunnel->dev->stats; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 98075b6..62548cb 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -387,7 +387,7 @@ static int ipip_rcv(struct sk_buff *skb) * and that skb is filled properly by that function. */ -static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct net_device_stats *stats = &tunnel->dev->stats; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 06c33fb..65d421c 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -201,7 +201,7 @@ failure: #ifdef CONFIG_IP_PIMSM -static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) { struct net *net = dev_net(dev); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index a1d6045..7d25bbe 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1036,7 +1036,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static int +static netdev_tx_t ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip6_tnl *t = netdev_priv(dev); diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 07ded50..19c8dec 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -416,7 +416,8 @@ static struct inet6_protocol pim6_protocol = { /* Service routines creating virtual interfaces: PIMREG */ -static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, + struct net_device *dev) { struct net *net = dev_net(dev); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 1d25a4d..0ae4f64 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -609,7 +609,8 @@ static inline __be32 try_6to4(struct in6_addr *v6dst) * and that skb is filled properly by that function. */ -static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct net_device_stats *stats = &tunnel->dev->stats; diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 12434b6..5a002c2 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -268,7 +268,7 @@ static inline int teql_resolve(struct sk_buff *skb, return __teql_resolve(skb, skb_res, dev); } -static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) { struct teql_master *master = netdev_priv(dev); struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); @@ -307,7 +307,7 @@ restart: if (!netif_tx_queue_stopped(slave_txq) && !netif_tx_queue_frozen(slave_txq) && - slave_ops->ndo_start_xmit(skb, slave) == 0) { + slave_ops->ndo_start_xmit(skb, slave) == NETDEV_TX_OK) { txq_trans_update(slave_txq); __netif_tx_unlock(slave_txq); master->slaves = NEXT_SLAVE(q); -- cgit v0.10.2 From 3c805a22a3a178fc5aaadd518afa5358b78bf69e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:42 +0000 Subject: convert ATM drivers to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 848af11..d6be0d1 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -223,7 +223,8 @@ static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb, return list_empty(&brdev->brvccs) ? NULL : list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */ } -static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t br2684_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct br2684_dev *brdev = BRPRIV(dev); struct br2684_vcc *brvcc; diff --git a/net/atm/clip.c b/net/atm/clip.c index 64910bb..27f6852 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -360,7 +360,8 @@ static int clip_encap(struct atm_vcc *vcc, int mode) return 0; } -static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t clip_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct clip_priv *clip_priv = PRIV(dev); struct atmarp_entry *entry; diff --git a/net/atm/lec.c b/net/atm/lec.c index 8e723c2..b2d6445 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -59,7 +59,8 @@ static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 }; */ static int lec_open(struct net_device *dev); -static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t lec_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int lec_close(struct net_device *dev); static void lec_init(struct net_device *dev); static struct lec_arp_table *lec_arp_find(struct lec_priv *priv, @@ -247,7 +248,8 @@ static void lec_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lec_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct sk_buff *skb2; struct lec_priv *priv = netdev_priv(dev); diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 1ac4b94..38a6cb0 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -73,7 +73,8 @@ static void mpoad_close(struct atm_vcc *vcc); static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb); static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb); -static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t mpc_send_packet(struct sk_buff *skb, + struct net_device *dev); static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev); static void mpc_timer_refresh(void); static void mpc_cache_check( unsigned long checking_time ); @@ -528,7 +529,8 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) /* * Probably needs some error checks and locking, not sure... */ -static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t mpc_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct mpoa_client *mpc; struct ethhdr *eth; -- cgit v0.10.2 From 36e4d64a82d9a91a73a2b9b32117aedfe2211fb3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:43 +0000 Subject: convert hamradio drivers to netdev_txreturnt_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 6cb2bdf..fb58830 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -242,7 +242,7 @@ out_drop: /* Encapsulate an IP datagram and kick it into a TTY queue. */ -static int sp_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sp_xmit(struct sk_buff *skb, struct net_device *dev) { struct sixpack *sp = netdev_priv(dev); diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 4c5f4df..3c7cc7f 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -247,7 +247,7 @@ drop: /* * Send an AX.25 frame via an ethernet interface */ -static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t bpq_xmit(struct sk_buff *skb, struct net_device *dev) { struct sk_buff *newskb; unsigned char *ptr; diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index 16b060b..0013c40 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -399,7 +399,8 @@ void hdlcdrv_arbitrate(struct net_device *dev, struct hdlcdrv_state *s) * ===================== network driver interface ========================= */ -static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hdlcdrv_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct hdlcdrv_state *sm = netdev_priv(dev); diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index ac191ef..33b55f7 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -525,7 +525,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) } /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ -static int ax_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ax_xmit(struct sk_buff *skb, struct net_device *dev) { struct mkiss *ax = netdev_priv(dev); diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index c540652..35c9361 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -209,7 +209,8 @@ static void scc_net_setup(struct net_device *dev); static int scc_net_open(struct net_device *dev); static int scc_net_close(struct net_device *dev); static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb); -static int scc_net_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t scc_net_tx(struct sk_buff *skb, + struct net_device *dev); static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int scc_net_set_mac_address(struct net_device *dev, void *addr); static struct net_device_stats * scc_net_get_stats(struct net_device *dev); @@ -1634,7 +1635,7 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb) /* ----> transmit frame <---- */ -static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t scc_net_tx(struct sk_buff *skb, struct net_device *dev) { struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; unsigned long flags; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index b85aa16..694132e 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -594,7 +594,8 @@ static void ptt_off(struct net_device *dev) outb(PTT_OFF, MCR(dev->base_addr)); } -static int yam_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t yam_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct yam_port *yp = netdev_priv(dev); diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c index c7b7838..7aa11b0 100644 --- a/net/netrom/nr_dev.c +++ b/net/netrom/nr_dev.c @@ -169,7 +169,7 @@ static int nr_close(struct net_device *dev) return 0; } -static int nr_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t nr_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = &dev->stats; unsigned int len = skb->len; diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c index c711e2e..424b893 100644 --- a/net/rose/rose_dev.c +++ b/net/rose/rose_dev.c @@ -131,7 +131,7 @@ static int rose_close(struct net_device *dev) return 0; } -static int rose_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t rose_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = &dev->stats; -- cgit v0.10.2 From 8b62ff2dbc3d6c13997b9d440dfd0ed00e6df96d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:44 +0000 Subject: isdn: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index c73004b..72eb926 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -119,7 +119,7 @@ net_close(struct net_device *dev) /* send a packet on this interface. */ /* new style for kernel >= 2.3.33 */ /************************************/ -static int +static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev) { struct net_local *lp = (struct net_local *) dev; diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 57bf4bf..90b56ed 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -176,7 +176,8 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) /* Prototypes */ static int isdn_net_force_dial_lp(isdn_net_local *); -static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); +static netdev_tx_t isdn_net_start_xmit(struct sk_buff *, + struct net_device *); static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); @@ -1160,7 +1161,7 @@ static void isdn_net_tx_timeout(struct net_device * ndev) * If this interface isn't connected to a ISDN-Channel, find a free channel, * and start dialing. */ -static int +static netdev_tx_t isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) { isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); -- cgit v0.10.2 From 25a79c41ce0ce88a4288adf278e9b0e00f228383 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:45 +0000 Subject: usbnet: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 7abdc4a..0ffc0c6 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -411,7 +411,8 @@ static void catc_tx_done(struct urb *urb) spin_unlock_irqrestore(&catc->tx_lock, flags); } -static int catc_start_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t catc_start_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct catc *catc = netdev_priv(netdev); unsigned long flags; diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 792af72..0ca5916 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -55,7 +55,7 @@ static void rx_complete(struct urb *req); /* * Network device callbacks */ -static int usbpn_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t usbpn_xmit(struct sk_buff *skb, struct net_device *dev) { struct usbpn_dev *pnd = netdev_priv(dev); struct urb *req = NULL; @@ -82,12 +82,12 @@ static int usbpn_xmit(struct sk_buff *skb, struct net_device *dev) if (pnd->tx_queue >= dev->tx_queue_len) netif_stop_queue(dev); spin_unlock_irqrestore(&pnd->tx_lock, flags); - return 0; + return NETDEV_TX_OK; drop: dev_kfree_skb(skb); dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } static void tx_complete(struct urb *req) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index ffe4106..123f9b8 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -771,7 +771,8 @@ static void write_bulk_callback(struct urb *urb) } /* called by kernel when we need to transmit a packet */ -static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net) +static netdev_tx_t hso_net_start_xmit(struct sk_buff *skb, + struct net_device *net) { struct hso_net *odev = netdev_priv(net); int result; diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 200fe3d..7f39736 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -803,7 +803,8 @@ static void kaweth_usb_transmit_complete(struct urb *urb) /**************************************************************** * kaweth_start_xmit ****************************************************************/ -static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) +static netdev_tx_t kaweth_start_xmit(struct sk_buff *skb, + struct net_device *net) { struct kaweth_device *kaweth = netdev_priv(net); __le16 *private_header; diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 69d2df9..7b935b8 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -876,7 +876,8 @@ static void pegasus_tx_timeout(struct net_device *net) pegasus->stats.tx_errors++; } -static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) +static netdev_tx_t pegasus_start_xmit(struct sk_buff *skb, + struct net_device *net) { pegasus_t *pegasus = netdev_priv(net); int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3; diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index bac8b77..d9f84f2 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -727,7 +727,8 @@ static void rtl8150_set_multicast(struct net_device *netdev) netif_wake_queue(netdev); } -static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + struct net_device *netdev) { rtl8150_t *dev = netdev_priv(netdev); int count, res; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 7d471fc..d166e33 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1007,15 +1007,16 @@ EXPORT_SYMBOL_GPL(usbnet_tx_timeout); /*-------------------------------------------------------------------------*/ -int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) +netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, + struct net_device *net) { struct usbnet *dev = netdev_priv(net); int length; - int retval = NET_XMIT_SUCCESS; struct urb *urb = NULL; struct skb_data *entry; struct driver_info *info = dev->driver_info; unsigned long flags; + int retval; // some devices want funky USB-level framing, for // win32 driver (usually) and/or hardware quirks @@ -1079,7 +1080,6 @@ int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) if (netif_msg_tx_err (dev)) devdbg (dev, "drop, code %d", retval); drop: - retval = NET_XMIT_SUCCESS; dev->net->stats.tx_dropped++; if (skb) dev_kfree_skb_any (skb); @@ -1088,7 +1088,7 @@ drop: devdbg (dev, "> tx, len %d, type 0x%x", length, skb->protocol); } - return retval; + return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(usbnet_start_xmit); diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index aac69b5..dc3ebd1 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -465,7 +465,8 @@ static inline int is_promisc(u16 cdc_filter) return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; } -static int eth_start_xmit(struct sk_buff *skb, struct net_device *net) +static netdev_tx_t eth_start_xmit(struct sk_buff *skb, + struct net_device *net) { struct eth_dev *dev = netdev_priv(net); int length = skb->len; diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 0951425..bb69e25 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -182,7 +182,8 @@ struct skb_data { /* skb->cb is one of these */ extern int usbnet_open (struct net_device *net); extern int usbnet_stop (struct net_device *net); -extern int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net); +extern netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, + struct net_device *net); extern void usbnet_tx_timeout (struct net_device *net); extern int usbnet_change_mtu (struct net_device *net, int new_mtu); -- cgit v0.10.2 From 61a84108547c1c017683f15311ccbede249fc6fa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:46 +0000 Subject: tokenring: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 1787d52..7241589 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -128,7 +128,7 @@ static int xl_init(struct net_device *dev); static int xl_open(struct net_device *dev); static int xl_open_hw(struct net_device *dev) ; static int xl_hw_reset(struct net_device *dev); -static int xl_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t xl_xmit(struct sk_buff *skb, struct net_device *dev); static void xl_dn_comp(struct net_device *dev); static int xl_close(struct net_device *dev); static void xl_set_rx_mode(struct net_device *dev); @@ -1193,7 +1193,7 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id) * Tx - Polling configuration */ -static int xl_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t xl_xmit(struct sk_buff *skb, struct net_device *dev) { struct xl_private *xl_priv=netdev_priv(dev); struct xl_tx_desc *txd ; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 96d00c8..525bbc5 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -191,7 +191,8 @@ static int tok_init_card(struct net_device *dev); static void tok_open_adapter(unsigned long dev_addr); static void open_sap(unsigned char type, struct net_device *dev); static void tok_set_multicast_list(struct net_device *dev); -static int tok_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t tok_send_packet(struct sk_buff *skb, + struct net_device *dev); static int tok_close(struct net_device *dev); static irqreturn_t tok_interrupt(int irq, void *dev_id); static void initial_tok_int(struct net_device *dev); @@ -1022,7 +1023,8 @@ static void tok_set_multicast_list(struct net_device *dev) #define STATION_ID_OFST 4 -static int tok_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tok_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct tok_info *ti; unsigned long flags; diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index d07e61a..26dca2b 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -203,7 +203,8 @@ static int streamer_ioctl(struct net_device *, struct ifreq *, int); static int streamer_reset(struct net_device *dev); static int streamer_open(struct net_device *dev); -static int streamer_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t streamer_xmit(struct sk_buff *skb, + struct net_device *dev); static int streamer_close(struct net_device *dev); static void streamer_set_rx_mode(struct net_device *dev); static irqreturn_t streamer_interrupt(int irq, void *dev_id); @@ -1141,7 +1142,8 @@ static irqreturn_t streamer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t streamer_xmit(struct sk_buff *skb, + struct net_device *dev) { struct streamer_private *streamer_priv = netdev_priv(dev); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index f73f4e6..d9ec7f0 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -182,7 +182,8 @@ MODULE_DEVICE_TABLE(pci,olympic_pci_tbl) ; static int olympic_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static int olympic_init(struct net_device *dev); static int olympic_open(struct net_device *dev); -static int olympic_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t olympic_xmit(struct sk_buff *skb, + struct net_device *dev); static int olympic_close(struct net_device *dev); static void olympic_set_rx_mode(struct net_device *dev); static void olympic_freemem(struct net_device *dev) ; @@ -1030,7 +1031,8 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t olympic_xmit(struct sk_buff *skb, + struct net_device *dev) { struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 23e012f..ebda61b 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -234,7 +234,8 @@ static int smctr_rx_frame(struct net_device *dev); /* S */ static int smctr_send_dat(struct net_device *dev); -static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t smctr_send_packet(struct sk_buff *skb, + struct net_device *dev); static int smctr_send_lobe_media_test(struct net_device *dev); static int smctr_send_rpt_addr(struct net_device *dev, MAC_HEADER *rmf, __u16 correlator); @@ -4571,7 +4572,8 @@ static void smctr_timeout(struct net_device *dev) /* * Gets skb from system, queues it and checks if it can be sent */ -static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smctr_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct net_local *tp = netdev_priv(dev); diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 07f6dfd..a7b6888 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -144,8 +144,8 @@ static void tms380tr_exec_sifcmd(struct net_device *dev, unsigned int WriteValu /* "G" */ static struct net_device_stats *tms380tr_get_stats(struct net_device *dev); /* "H" */ -static int tms380tr_hardware_send_packet(struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t tms380tr_hardware_send_packet(struct sk_buff *skb, + struct net_device *dev); /* "I" */ static int tms380tr_init_adapter(struct net_device *dev); static void tms380tr_init_ipb(struct net_local *tp); @@ -165,7 +165,8 @@ static int tms380tr_reset_adapter(struct net_device *dev); static void tms380tr_reset_interrupt(struct net_device *dev); static void tms380tr_ring_status_irq(struct net_device *dev); /* "S" */ -static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t tms380tr_send_packet(struct sk_buff *skb, + struct net_device *dev); static void tms380tr_set_multicast_list(struct net_device *dev); static int tms380tr_set_mac_address(struct net_device *dev, void *addr); /* "T" */ @@ -599,21 +600,23 @@ static void tms380tr_timeout(struct net_device *dev) /* * Gets skb from system, queues it and checks if it can be sent */ -static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tms380tr_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct net_local *tp = netdev_priv(dev); - int err; + netdev_tx_t rc; - err = tms380tr_hardware_send_packet(skb, dev); + rc = tms380tr_hardware_send_packet(skb, dev); if(tp->TplFree->NextTPLPtr->BusyFlag) netif_stop_queue(dev); - return (err); + return rc; } /* * Move frames into adapter tx queue */ -static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tms380tr_hardware_send_packet(struct sk_buff *skb, + struct net_device *dev) { TPL *tpl; short length; -- cgit v0.10.2 From d71a674922e7519edb477ecb585e7d29d69c7aa7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:47 +0000 Subject: wan: convert drivers to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 61581ee..66360a2 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -279,7 +279,7 @@ static int cosa_net_attach(struct net_device *dev, unsigned short encoding, static int cosa_net_open(struct net_device *d); static int cosa_net_close(struct net_device *d); static void cosa_net_timeout(struct net_device *d); -static int cosa_net_tx(struct sk_buff *skb, struct net_device *d); +static netdev_tx_t cosa_net_tx(struct sk_buff *skb, struct net_device *d); static char *cosa_net_setup_rx(struct channel_data *channel, int size); static int cosa_net_rx_done(struct channel_data *channel); static int cosa_net_tx_done(struct channel_data *channel, int size); @@ -672,7 +672,8 @@ static int cosa_net_open(struct net_device *dev) return 0; } -static int cosa_net_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t cosa_net_tx(struct sk_buff *skb, + struct net_device *dev) { struct channel_data *chan = dev_to_chan(dev); @@ -680,7 +681,7 @@ static int cosa_net_tx(struct sk_buff *skb, struct net_device *dev) chan->tx_skb = skb; cosa_start_tx(chan, skb->data, skb->len); - return 0; + return NETDEV_TX_OK; } static void cosa_net_timeout(struct net_device *dev) diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 4ae9bd2..2573c18 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -139,8 +139,8 @@ static int cycx_netdevice_hard_header(struct sk_buff *skb, const void *daddr, const void *saddr, unsigned len); static int cycx_netdevice_rebuild_header(struct sk_buff *skb); -static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev); static struct net_device_stats * cycx_netdevice_get_stats(struct net_device *dev); @@ -593,8 +593,8 @@ static int cycx_netdevice_rebuild_header(struct sk_buff *skb) * bottom half" (with interrupts enabled). * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ -static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 8526b6d..69d269d 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -186,12 +186,11 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); } -static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t dlci_transmit(struct sk_buff *skb, + struct net_device *dev) { struct dlci_local *dlp; - int ret; - - ret = 0; + netdev_tx_t ret; if (!skb || !dev) return NETDEV_TX_OK; @@ -200,6 +199,8 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); + /* This is hackish, overloads driver specific return values + on top of normal transmit return! */ ret = dlp->slave->netdev_ops->ndo_start_xmit(skb, dlp->slave); switch (ret) { @@ -207,11 +208,11 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; ret = NETDEV_TX_OK; break; - case DLCI_RET_ERR: + case DLCI_RET_ERR: dev->stats.tx_errors++; ret = NETDEV_TX_OK; break; - case DLCI_RET_DROP: + case DLCI_RET_DROP: dev->stats.tx_dropped++; ret = NETDEV_TX_BUSY; break; diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index cc00e0f8..b2247bd 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -359,7 +359,8 @@ static void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); static int dscc4_found1(struct pci_dev *, void __iomem *ioaddr); static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent); static int dscc4_open(struct net_device *); -static int dscc4_start_xmit(struct sk_buff *, struct net_device *); +static netdev_tx_t dscc4_start_xmit(struct sk_buff *, + struct net_device *); static int dscc4_close(struct net_device *); static int dscc4_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int dscc4_init_ring(struct net_device *); @@ -1148,7 +1149,8 @@ static int dscc4_tx_poll(struct dscc4_dev_priv *dpriv, struct net_device *dev) } #endif /* DSCC4_POLLING */ -static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t dscc4_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct dscc4_dev_priv *dpriv = dscc4_priv(dev); struct dscc4_pci_priv *ppriv = dpriv->pci_priv; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 20a1237..3e90eb8 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -2274,7 +2274,7 @@ fst_tx_timeout(struct net_device *dev) port->start = 0; } -static int +static netdev_tx_t fst_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fst_card_info *card; diff --git a/drivers/net/wan/hd64570.c b/drivers/net/wan/hd64570.c index 1ea1ef6..80114c9 100644 --- a/drivers/net/wan/hd64570.c +++ b/drivers/net/wan/hd64570.c @@ -620,7 +620,7 @@ static void sca_dump_rings(struct net_device *dev) #endif /* DEBUG_RINGS */ -static int sca_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev) { port_t *port = dev_to_port(dev); card_t *card = port_to_card(port); @@ -674,7 +674,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&port->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c index f099c34..84f0137 100644 --- a/drivers/net/wan/hd64572.c +++ b/drivers/net/wan/hd64572.c @@ -562,7 +562,7 @@ static void sca_dump_rings(struct net_device *dev) #endif /* DEBUG_RINGS */ -static int sca_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev) { port_t *port = dev_to_port(dev); card_t *card = port->card; @@ -601,7 +601,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&port->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index 7596eae..cc07236 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -66,7 +66,7 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, return hdlc->proto->netif_rx(skb); } -int hdlc_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t hdlc_start_xmit(struct sk_buff *skb, struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 52438c7..840cff7 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -407,7 +407,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; } -static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t pvc_xmit(struct sk_buff *skb, struct net_device *dev) { pvc_device *pvc = dev->ml_priv; diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index 49e68f5..1b30fcc 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -25,7 +25,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr); -static int eth_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t eth_tx(struct sk_buff *skb, struct net_device *dev) { int pad = ETH_ZLEN - skb->len; if (pad > 0) { /* Pad the frame with zeros */ diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index b1dc29e..aa9248f 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -87,7 +87,7 @@ static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb) -static int x25_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev) { int result; @@ -98,7 +98,7 @@ static int x25_xmit(struct sk_buff *skb, struct net_device *dev) skb_pull(skb, 1); if ((result = lapb_data_request(dev, skb)) != LAPB_OK) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; case 1: if ((result = lapb_connect_request(dev))!= LAPB_OK) { @@ -129,7 +129,7 @@ static int x25_xmit(struct sk_buff *skb, struct net_device *dev) } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index 567d4f5..15002c3 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -156,7 +156,8 @@ static int hostess_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) * Passed network frames, fire them downwind. */ -static int hostess_queue_xmit(struct sk_buff *skb, struct net_device *d) +static netdev_tx_t hostess_queue_xmit(struct sk_buff *skb, + struct net_device *d) { return z8530_queue_xmit(&dev_to_sv(d)->chanA, skb); } diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index aff4f6b..d1e3c67 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -147,7 +147,8 @@ static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb) /* * Send a LAPB frame via an ethernet interface */ -static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lapbeth_xmit(struct sk_buff *skb, + struct net_device *dev) { int err; diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 4b83d88..7ea71b3 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -89,7 +89,8 @@ MODULE_DEVICE_TABLE(pci, lmc_pci_tbl); MODULE_LICENSE("GPL v2"); -static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t lmc_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int lmc_rx (struct net_device *dev); static int lmc_open(struct net_device *dev); static int lmc_close(struct net_device *dev); @@ -1423,12 +1424,12 @@ lmc_int_fail_out: return IRQ_RETVAL(handled); } -static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lmc_start_xmit(struct sk_buff *skb, + struct net_device *dev) { lmc_softc_t *sc = dev_to_sc(dev); u32 flag; int entry; - int ret = NETDEV_TX_OK; unsigned long flags; lmc_trace(dev, "lmc_start_xmit in"); @@ -1510,7 +1511,7 @@ static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sc->lmc_lock, flags); lmc_trace(dev, "lmc_start_xmit_out"); - return ret; + return NETDEV_TX_OK; } diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 85c02a2..1cc24a4 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -114,7 +114,8 @@ static int sbni_pci_probe( struct net_device * ); static struct net_device *sbni_probe1(struct net_device *, unsigned long, int); static int sbni_open( struct net_device * ); static int sbni_close( struct net_device * ); -static int sbni_start_xmit( struct sk_buff *, struct net_device * ); +static netdev_tx_t sbni_start_xmit(struct sk_buff *, + struct net_device * ); static int sbni_ioctl( struct net_device *, struct ifreq *, int ); static void set_multicast_list( struct net_device * ); @@ -444,7 +445,7 @@ sbni_probe1( struct net_device *dev, unsigned long ioaddr, int irq ) #ifdef CONFIG_SBNI_MULTILINE -static int +static netdev_tx_t sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) { struct net_device *p; @@ -472,7 +473,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) #else /* CONFIG_SBNI_MULTILINE */ -static int +static netdev_tx_t sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) { struct net_local *nl = netdev_priv(dev); diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 1d637f4..63c7645 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -651,7 +651,8 @@ static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, i **************************/ /* NOTE: the DLCI driver deals with freeing the SKB!! */ -static int sdla_transmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sdla_transmit(struct sk_buff *skb, + struct net_device *dev) { struct frad_local *flp; int ret, addr, accept, i; @@ -737,7 +738,7 @@ static int sdla_transmit(struct sk_buff *skb, struct net_device *dev) if(flp->master[i]!=NULL) netif_wake_queue(flp->master[i]); } - return(ret); + return NETDEV_TX_OK; } static void sdla_receive(struct net_device *dev) diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index 23b2690..0c525e2 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c @@ -156,7 +156,8 @@ static int sealevel_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) * Passed network frames, fire them downwind. */ -static int sealevel_queue_xmit(struct sk_buff *skb, struct net_device *d) +static netdev_tx_t sealevel_queue_xmit(struct sk_buff *skb, + struct net_device *d) { return z8530_queue_xmit(dev_to_chan(d)->chan, skb); } diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index 03b76ad..daee8a0 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -268,7 +268,7 @@ static irqreturn_t wanxl_intr(int irq, void* dev_id) -static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t wanxl_xmit(struct sk_buff *skb, struct net_device *dev) { port_t *port = dev_to_port(dev); desc_t *desc; diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 1047920..2794504 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -299,7 +299,8 @@ static void x25_asy_timeout(struct net_device *dev) /* Encapsulate an IP datagram and kick it into a TTY queue. */ -static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t x25_asy_xmit(struct sk_buff *skb, + struct net_device *dev) { struct x25_asy *sl = netdev_priv(dev); int err; diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index ad4e79c..0be7ec7 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -1727,15 +1727,14 @@ static inline int spans_boundary(struct sk_buff *skb) * point. */ -int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) +netdev_tx_t z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) { unsigned long flags; netif_stop_queue(c->netdevice); if(c->tx_next_skb) - { - return 1; - } + return NETDEV_TX_BUSY; + /* PC SPECIFIC - DMA limits */ @@ -1767,7 +1766,7 @@ int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) z8530_tx_begin(c); spin_unlock_irqrestore(c->lock, flags); - return 0; + return NETDEV_TX_OK; } EXPORT_SYMBOL(z8530_queue_xmit); diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h index 85b3e78..f29d554 100644 --- a/drivers/net/wan/z85230.h +++ b/drivers/net/wan/z85230.h @@ -406,7 +406,8 @@ extern int z8530_sync_dma_close(struct net_device *, struct z8530_channel *); extern int z8530_sync_txdma_open(struct net_device *, struct z8530_channel *); extern int z8530_sync_txdma_close(struct net_device *, struct z8530_channel *); extern int z8530_channel_load(struct z8530_channel *, u8 *); -extern int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb); +extern netdev_tx_t z8530_queue_xmit(struct z8530_channel *c, + struct sk_buff *skb); extern void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb); -- cgit v0.10.2 From 4c5d502d8b2db8947c44dc44bdc67dbe55cce2b9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:48 +0000 Subject: hdlc: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 77b3648..caf6e4d 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -4005,10 +4005,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, * * skb socket buffer containing HDLC frame * dev pointer to network device structure - * - * returns 0 if success, otherwise error code */ -static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, + struct net_device *dev) { MGSLPC_INFO *info = dev_to_port(dev); unsigned long flags; @@ -4043,7 +4042,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) } spin_unlock_irqrestore(&info->lock,flags); - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 813552f..4846b73 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -7697,10 +7697,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, * * skb socket buffer containing HDLC frame * dev pointer to network device structure - * - * returns 0 if success, otherwise error code */ -static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, + struct net_device *dev) { struct mgsl_struct *info = dev_to_port(dev); unsigned long flags; @@ -7731,7 +7730,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) usc_start_transmitter(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 91f20a9..8678f0c 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -1497,10 +1497,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, * * skb socket buffer containing HDLC frame * dev pointer to network device structure - * - * returns 0 if success, otherwise error code */ -static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, + struct net_device *dev) { struct slgt_info *info = dev_to_port(dev); unsigned long flags; @@ -1529,7 +1528,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) update_tx_timer(info); spin_unlock_irqrestore(&info->lock,flags); - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 8d4a2a8..2b18adc 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -1608,10 +1608,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, * * skb socket buffer containing HDLC frame * dev pointer to network device structure - * - * returns 0 if success, otherwise error code */ -static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, + struct net_device *dev) { SLMP_INFO *info = dev_to_port(dev); unsigned long flags; @@ -1642,7 +1641,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) tx_start(info); spin_unlock_irqrestore(&info->lock,flags); - return 0; + return NETDEV_TX_OK; } /** diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h index 6a6e701..ee275c8 100644 --- a/include/linux/hdlc.h +++ b/include/linux/hdlc.h @@ -38,7 +38,7 @@ struct hdlc_proto { int (*ioctl)(struct net_device *dev, struct ifreq *ifr); __be16 (*type_trans)(struct sk_buff *skb, struct net_device *dev); int (*netif_rx)(struct sk_buff *skb); - int (*xmit)(struct sk_buff *skb, struct net_device *dev); + netdev_tx_t (*xmit)(struct sk_buff *skb, struct net_device *dev); struct module *module; struct hdlc_proto *next; /* next protocol in the list */ }; @@ -51,7 +51,7 @@ typedef struct hdlc_device { unsigned short encoding, unsigned short parity); /* hardware driver must handle this instead of dev->hard_start_xmit */ - int (*xmit)(struct sk_buff *skb, struct net_device *dev); + netdev_tx_t (*xmit)(struct sk_buff *skb, struct net_device *dev); /* Things below are for HDLC layer internal use only */ const struct hdlc_proto *proto; @@ -60,7 +60,7 @@ typedef struct hdlc_device { spinlock_t state_lock; void *state; void *priv; -}hdlc_device; +} hdlc_device; @@ -106,7 +106,7 @@ void hdlc_close(struct net_device *dev); /* May be used by hardware driver */ int hdlc_change_mtu(struct net_device *dev, int new_mtu); /* Must be pointed to by hw driver's dev->netdev_ops->ndo_start_xmit */ -int hdlc_start_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t hdlc_start_xmit(struct sk_buff *skb, struct net_device *dev); int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto, size_t size); -- cgit v0.10.2 From dbf02fae406daf4d583a279743869c686024c341 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:49 +0000 Subject: netdev: convert pcmcia drivers to netdev_tx_t Update all the pcmcia network drivers for netdev_tx_t. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index a23aa87..382d265 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -239,7 +239,8 @@ static void tc574_wait_for_completion(struct net_device *dev, int cmd); static void tc574_reset(struct net_device *dev); static void media_check(unsigned long arg); static int el3_open(struct net_device *dev); -static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t el3_interrupt(int irq, void *dev_id); static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); @@ -778,7 +779,8 @@ static void pop_tx_status(struct net_device *dev) } } -static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, + struct net_device *dev) { unsigned int ioaddr = dev->base_addr; struct el3_private *lp = netdev_priv(dev); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index d2156ab..569fb06 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -149,7 +149,8 @@ static void tc589_reset(struct net_device *dev); static void media_check(unsigned long arg); static int el3_config(struct net_device *dev, struct ifmap *map); static int el3_open(struct net_device *dev); -static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t el3_interrupt(int irq, void *dev_id); static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); @@ -604,7 +605,8 @@ static void pop_tx_status(struct net_device *dev) } } -static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, + struct net_device *dev) { unsigned int ioaddr = dev->base_addr; struct el3_private *priv = netdev_priv(dev); diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 1e87d63..3b681c1 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -92,7 +92,8 @@ static void axnet_release(struct pcmcia_device *link); static int axnet_open(struct net_device *dev); static int axnet_close(struct net_device *dev); static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t axnet_start_xmit(struct sk_buff *skb, + struct net_device *dev); static struct net_device_stats *get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void axnet_tx_timeout(struct net_device *dev); @@ -1063,7 +1064,8 @@ static void axnet_tx_timeout(struct net_device *dev) * Sends a packet to an 8390 network device. */ -static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t axnet_start_xmit(struct sk_buff *skb, + struct net_device *dev) { long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 434d940..7e01fbd 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -96,7 +96,8 @@ static void fmvj18x_detach(struct pcmcia_device *p_dev); static int fjn_config(struct net_device *dev, struct ifmap *map); static int fjn_open(struct net_device *dev); static int fjn_close(struct net_device *dev); -static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t fjn_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t fjn_interrupt(int irq, void *dev_id); static void fjn_rx(struct net_device *dev); static void fjn_reset(struct net_device *dev); @@ -856,7 +857,8 @@ static void fjn_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t fjn_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct local_info_t *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index dd60590..5ed6339 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -424,7 +424,8 @@ static void nmclan_reset(struct net_device *dev); static int mace_config(struct net_device *dev, struct ifmap *map); static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); -static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t mace_start_xmit(struct sk_buff *skb, + struct net_device *dev); static void mace_tx_timeout(struct net_device *dev); static irqreturn_t mace_interrupt(int irq, void *dev_id); static struct net_device_stats *mace_get_stats(struct net_device *dev); @@ -937,7 +938,8 @@ static void mace_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t mace_start_xmit(struct sk_buff *skb, + struct net_device *dev) { mace_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 2f39244..7bde2cd 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -288,7 +288,8 @@ static int smc_open(struct net_device *dev); static int smc_close(struct net_device *dev); static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void smc_tx_timeout(struct net_device *dev); -static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t smc_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t smc_interrupt(int irq, void *dev_id); static void smc_rx(struct net_device *dev); static void set_rx_mode(struct net_device *dev); @@ -1370,7 +1371,8 @@ static void smc_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smc_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct smc_private *smc = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index eda7bf6..68de891 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -352,7 +352,8 @@ typedef struct local_info_t { /**************** * Some more prototypes */ -static int do_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t do_start_xmit(struct sk_buff *skb, + struct net_device *dev); static void xirc_tx_timeout(struct net_device *dev); static void xirc2ps_tx_timeout_task(struct work_struct *work); static void set_addresses(struct net_device *dev); @@ -1361,7 +1362,7 @@ xirc_tx_timeout(struct net_device *dev) schedule_work(&lp->tx_timeout_task); } -static int +static netdev_tx_t do_start_xmit(struct sk_buff *skb, struct net_device *dev) { local_info_t *lp = netdev_priv(dev); -- cgit v0.10.2 From 6518bbb803fe02b15a3211c8db2afdff0ac4f808 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:50 +0000 Subject: irda: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index f0d0cea..12c7b00 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -111,7 +111,8 @@ static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud); /* SIR function */ -static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ali_ircc_sir_hard_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self); static void ali_ircc_sir_receive(struct ali_ircc_cb *self); static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self); @@ -119,7 +120,8 @@ static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len); static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed); /* FIR function */ -static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb, + struct net_device *dev); static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 speed); static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self); static int ali_ircc_dma_receive(struct ali_ircc_cb *self); @@ -1435,7 +1437,8 @@ static int ali_ircc_net_close(struct net_device *dev) * Transmit the frame * */ -static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ali_ircc_cb *self; unsigned long flags; @@ -1957,7 +1960,8 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) * Transmit the frame! * */ -static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ali_ircc_sir_hard_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ali_ircc_cb *self; unsigned long flags; diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index e4e9056..2d7b5c1 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -970,7 +970,7 @@ toshoboe_probe (struct toshoboe_cb *self) /* Netdev style code */ /* Transmit something */ -static int +static netdev_tx_t toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) { struct toshoboe_cb *self; diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 6a1aa7a..215adf6 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -111,7 +111,8 @@ static void irda_usb_init_qos(struct irda_usb_cb *self) ; static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf); static void irda_usb_disconnect(struct usb_interface *intf); static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); -static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb, + struct net_device *dev); static int irda_usb_open(struct irda_usb_cb *self); static void irda_usb_close(struct irda_usb_cb *self); static void speed_bulk_callback(struct urb *urb); @@ -381,7 +382,8 @@ static void speed_bulk_callback(struct urb *urb) /* * Send an IrDA frame to the USB dongle (for transmission) */ -static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct irda_usb_cb *self = netdev_priv(netdev); struct urb *urb = self->tx_urb; diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index c3e4e2c..2fc30b4 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -150,7 +150,8 @@ static void kingsun_send_irq(struct urb *urb) /* * Called from net/core when new frame is available. */ -static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct kingsun_cb *kingsun; int wraplen; @@ -416,7 +417,7 @@ static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq, } static const struct net_device_ops kingsun_ops = { - .ndo_start_xmit = kingsun_hard_xmit, + .ndo_start_xmit = kingsun_hard_xmit, .ndo_open = kingsun_net_open, .ndo_stop = kingsun_net_close, .ndo_do_ioctl = kingsun_net_ioctl, diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index d73b8b6..f4d13fc 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -385,7 +385,8 @@ static void ks959_send_irq(struct urb *urb) /* * Called from net/core when new frame is available. */ -static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ks959_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct ks959_cb *kingsun; unsigned int wraplen; diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index 1ef45ec..5f9d733 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -298,7 +298,8 @@ static void ksdazzle_send_irq(struct urb *urb) /* * Called from net/core when new frame is available. */ -static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ksdazzle_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct ksdazzle_cb *kingsun; unsigned int wraplen; diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index f4df100..b3d30bc 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -817,7 +817,8 @@ static void mcs_send_irq(struct urb *urb) } /* Transmit callback funtion. */ -static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb, + struct net_device *ndev) { unsigned long flags; struct mcs_cb *mcs; diff --git a/drivers/net/irda/mcs7780.h b/drivers/net/irda/mcs7780.h index 6bdc621..b10689b 100644 --- a/drivers/net/irda/mcs7780.h +++ b/drivers/net/irda/mcs7780.h @@ -156,7 +156,8 @@ static int mcs_net_open(struct net_device *netdev); static void mcs_receive_irq(struct urb *urb); static void mcs_send_irq(struct urb *urb); -static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *netdev); +static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb, + struct net_device *netdev); static int mcs_probe(struct usb_interface *intf, const struct usb_device_id *id); diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 51ca89c..2413295 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -173,8 +173,10 @@ static int nsc_ircc_setup(chipio_t *info); static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self); static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self); static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase); -static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev); -static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t nsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev); static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size); static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase); static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud); @@ -1355,7 +1357,8 @@ static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed) * Transmit the frame! * */ -static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t nsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev) { struct nsc_ircc_cb *self; unsigned long flags; @@ -1427,7 +1430,8 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev) { struct nsc_ircc_cb *self; unsigned long flags; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 71dce20..4b2a1a9 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -582,7 +582,8 @@ EXPORT_SYMBOL(sirdev_receive); /* callbacks from network layer */ -static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t sirdev_hard_xmit(struct sk_buff *skb, + struct net_device *ndev) { struct sir_dev *dev = netdev_priv(ndev); unsigned long flags; diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 15f8a7f..1e8dd8c 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -194,8 +194,10 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self); static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self); static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self); static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self); -static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev); -static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t smsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t smsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev); static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs); static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self); static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed); @@ -486,7 +488,8 @@ static int __init smsc_ircc_init(void) return ret; } -static int smsc_ircc_net_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smsc_ircc_net_xmit(struct sk_buff *skb, + struct net_device *dev) { struct smsc_ircc_cb *self = netdev_priv(dev); @@ -878,7 +881,8 @@ static void smsc_ircc_timeout(struct net_device *dev) * waits until the next transmit interrupt, and continues until the * frame is transmitted. */ -static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev) { struct smsc_ircc_cb *self; unsigned long flags; @@ -1183,7 +1187,8 @@ static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed) * Transmit the frame! * */ -static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev) { struct smsc_ircc_cb *self; unsigned long flags; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index c475b23..528767d 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -560,7 +560,8 @@ static int change_speed(struct stir_cb *stir, unsigned speed) /* * Called from net/core when new frame is available. */ -static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t stir_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct stir_cb *stir = netdev_priv(netdev); diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 36a6074..a5ca71c 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -87,10 +87,10 @@ static int via_ircc_close(struct via_ircc_cb *self); static int via_ircc_dma_receive(struct via_ircc_cb *self); static int via_ircc_dma_receive_complete(struct via_ircc_cb *self, int iobase); -static int via_ircc_hard_xmit_sir(struct sk_buff *skb, - struct net_device *dev); -static int via_ircc_hard_xmit_fir(struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t via_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t via_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev); static void via_hw_init(struct via_ircc_cb *self); static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 baud); static irqreturn_t via_ircc_interrupt(int irq, void *dev_id); @@ -823,8 +823,8 @@ static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 speed) * Transmit the frame! * */ -static int via_ircc_hard_xmit_sir(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t via_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev) { struct via_ircc_cb *self; unsigned long flags; @@ -895,8 +895,8 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, return NETDEV_TX_OK; } -static int via_ircc_hard_xmit_fir(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t via_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev) { struct via_ircc_cb *self; u16 iobase; diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 08e26f1..7cfb8b6 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -854,7 +854,8 @@ static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase) return ret; } -static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb, + struct net_device *ndev) { vlsi_irda_dev_t *idev = netdev_priv(ndev); struct vlsi_ring *r = idev->tx_ring; diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 462bc43..551810f 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -93,7 +93,8 @@ static int w83977af_close(struct w83977af_ir *self); static int w83977af_probe(int iobase, int irq, int dma); static int w83977af_dma_receive(struct w83977af_ir *self); static int w83977af_dma_receive_complete(struct w83977af_ir *self); -static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, + struct net_device *dev); static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size); static void w83977af_dma_write(struct w83977af_ir *self, int iobase); static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed); @@ -490,7 +491,8 @@ static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) * Sets up a DMA transfer to send the current frame. * */ -static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, + struct net_device *dev) { struct w83977af_ir *self; __s32 speed; diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 64230cf..7b6b631 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -41,7 +41,8 @@ static int irlan_eth_open(struct net_device *dev); static int irlan_eth_close(struct net_device *dev); -static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, + struct net_device *dev); static void irlan_eth_set_multicast_list( struct net_device *dev); static struct net_device_stats *irlan_eth_get_stats(struct net_device *dev); @@ -162,7 +163,8 @@ static int irlan_eth_close(struct net_device *dev) * Transmits ethernet frames over IrDA link. * */ -static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, + struct net_device *dev) { struct irlan_cb *self = netdev_priv(dev); int ret; -- cgit v0.10.2 From 424efe9caf6047ffbcd6b383ff4d2347254aabf1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:51 +0000 Subject: netdev: convert pseudo drivers to netdev_tx_t These are all drivers that don't touch real hardware. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index a42209a..d923d1d 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1188,7 +1188,7 @@ static int fwnet_stop(struct net_device *net) return 0; } -static int fwnet_tx(struct sk_buff *skb, struct net_device *net) +static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) { struct fwnet_header hdr_buf; struct fwnet_device *dev = netdev_priv(net); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 7c0e0bd..a7e731f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4450,7 +4450,7 @@ static void bond_set_xmit_hash_policy(struct bonding *bond) } } -static int bond_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) { const struct bonding *bond = netdev_priv(dev); diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index a10c1d7..6971f6c 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -83,7 +83,7 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev) netif_rx(skb); } -static int vcan_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = &dev->stats; int loop; diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 713ce6c..37dcfdc 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -39,8 +39,6 @@ static int numdummies = 1; -static int dummy_xmit(struct sk_buff *skb, struct net_device *dev); - static int dummy_set_address(struct net_device *dev, void *p) { struct sockaddr *sa = p; @@ -57,6 +55,16 @@ static void set_multicast_list(struct net_device *dev) { } + +static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) +{ + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + static const struct net_device_ops dummy_netdev_ops = { .ndo_start_xmit = dummy_xmit, .ndo_validate_addr = eth_validate_addr, @@ -78,16 +86,6 @@ static void dummy_setup(struct net_device *dev) dev->flags &= ~IFF_MULTICAST; random_ether_addr(dev->dev_addr); } - -static int dummy_xmit(struct sk_buff *skb, struct net_device *dev) -{ - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) { if (tb[IFLA_ADDRESS]) { diff --git a/drivers/net/eql.c b/drivers/net/eql.c index c0e69c5..d4d9a3e 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -127,7 +127,7 @@ static int eql_open(struct net_device *dev); static int eql_close(struct net_device *dev); static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t eql_slave_xmit(struct sk_buff *skb, struct net_device *dev); #define eql_is_slave(dev) ((dev->flags & IFF_SLAVE) == IFF_SLAVE) #define eql_is_master(dev) ((dev->flags & IFF_MASTER) == IFF_MASTER) @@ -325,7 +325,7 @@ static slave_t *__eql_schedule_slaves(slave_queue_t *queue) return best_slave; } -static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) { equalizer_t *eql = netdev_priv(dev); slave_t *slave; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 0a79b45..801f088 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -59,7 +59,7 @@ struct ifb_private { static int numifbs = 2; static void ri_tasklet(unsigned long dev); -static int ifb_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev); static int ifb_open(struct net_device *dev); static int ifb_close(struct net_device *dev); @@ -160,11 +160,10 @@ static void ifb_setup(struct net_device *dev) random_ether_addr(dev->dev_addr); } -static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) { struct ifb_private *dp = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; - int ret = NETDEV_TX_OK; u32 from = G_TC_FROM(skb->tc_verd); stats->rx_packets++; @@ -173,7 +172,7 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->iif) { dev_kfree_skb(skb); stats->rx_dropped++; - return ret; + return NETDEV_TX_OK; } if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) { @@ -187,7 +186,7 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) tasklet_schedule(&dp->ifb_tasklet); } - return ret; + return NETDEV_TX_OK; } static int ifb_close(struct net_device *dev) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 99eed9f..f893cd4 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -184,7 +184,8 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) return NULL; } -static int macvlan_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, + struct net_device *dev) { const struct macvlan_dev *vlan = netdev_priv(dev); unsigned int len = skb->len; diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 35be2e8..9bf2a6b 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -951,7 +951,7 @@ out: /* * Network interface unit routines. */ -static int +static netdev_tx_t ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ppp *ppp = netdev_priv(dev); diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 899c4a2..26f6ee9 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -474,7 +474,7 @@ out: /* Encapsulate an IP datagram and kick it into a TTY queue. */ -static int +static netdev_tx_t sl_xmit(struct sk_buff *skb, struct net_device *dev) { struct slip *sl = netdev_priv(dev); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 2533f5c..5f7842e 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -358,7 +358,7 @@ static int tun_net_close(struct net_device *dev) } /* Net device start xmit */ -static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 190f784..d1941cd 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -148,7 +148,7 @@ static struct ethtool_ops veth_ethtool_ops = { * xmit */ -static int veth_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device *rcv = NULL; struct veth_priv *priv, *rcv_priv; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index a6f903f..31279c4 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -519,7 +519,7 @@ static void xmit_tasklet(unsigned long data) netif_tx_unlock_bh(vi->dev); } -static int start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c index 4667af5..d183509 100644 --- a/net/phonet/pep-gprs.c +++ b/net/phonet/pep-gprs.c @@ -183,7 +183,7 @@ static int gprs_close(struct net_device *dev) return 0; } -static int gprs_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t gprs_xmit(struct sk_buff *skb, struct net_device *dev) { struct gprs_dev *gp = netdev_priv(dev); struct sock *sk = gp->sk; -- cgit v0.10.2 From 3a27c149ab0e31a7b86e5ee6a27bb3b8b5687f32 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:52 +0000 Subject: uwb: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h index 3421d33..2e31f53 100644 --- a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h +++ b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h @@ -267,7 +267,8 @@ extern void i1480u_sysfs_release(struct i1480u *); /* netdev interface */ extern int i1480u_open(struct net_device *); extern int i1480u_stop(struct net_device *); -extern int i1480u_hard_start_xmit(struct sk_buff *, struct net_device *); +extern netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *, + struct net_device *); extern void i1480u_tx_timeout(struct net_device *); extern int i1480u_set_config(struct net_device *, struct ifmap *); extern int i1480u_change_mtu(struct net_device *, int); diff --git a/drivers/uwb/i1480/i1480u-wlp/tx.c b/drivers/uwb/i1480/i1480u-wlp/tx.c index 26bacc0..3db3449 100644 --- a/drivers/uwb/i1480/i1480u-wlp/tx.c +++ b/drivers/uwb/i1480/i1480u-wlp/tx.c @@ -503,7 +503,8 @@ out: * * @net_dev->xmit_lock is held */ -int i1480u_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) +netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *skb, + struct net_device *net_dev) { int result; struct i1480u *i1480u = netdev_priv(net_dev); -- cgit v0.10.2 From ad096463f7ff809389454ea4219058a36564d55e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:53 +0000 Subject: tulip: convert drivers to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index bc8a6b2..74e5ba4 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -599,7 +599,8 @@ next: netif_wake_queue(de->dev); } -static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t de_start_xmit (struct sk_buff *skb, + struct net_device *dev) { struct de_private *de = netdev_priv(dev); unsigned int entry, tx_free; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index acfdccd..a8349b7 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -895,7 +895,8 @@ static struct { ** Public Functions */ static int de4x5_open(struct net_device *dev); -static int de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t de4x5_queue_pkt(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t de4x5_interrupt(int irq, void *dev_id); static int de4x5_close(struct net_device *dev); static struct net_device_stats *de4x5_get_stats(struct net_device *dev); @@ -1456,18 +1457,16 @@ de4x5_sw_reset(struct net_device *dev) /* ** Writes a socket buffer address to the next available transmit descriptor. */ -static int +static netdev_tx_t de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) { struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; - int status = NETDEV_TX_OK; u_long flags = 0; netif_stop_queue(dev); - if (!lp->tx_enable) { /* Cannot send for now */ + if (!lp->tx_enable) /* Cannot send for now */ return NETDEV_TX_LOCKED; - } /* ** Clean out the TX ring asynchronously to interrupts - sometimes the @@ -1521,7 +1520,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) lp->cache.lock = 0; - return status; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 5e15fab..a45ded0 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -311,7 +311,7 @@ static u8 SF_mode; /* Special Function: 1:VLAN, 2:RX Flow Control /* function declaration ------------------------------------- */ static int dmfe_open(struct DEVICE *); -static int dmfe_start_xmit(struct sk_buff *, struct DEVICE *); +static netdev_tx_t dmfe_start_xmit(struct sk_buff *, struct DEVICE *); static int dmfe_stop(struct DEVICE *); static void dmfe_set_filter_mode(struct DEVICE *); static const struct ethtool_ops netdev_ethtool_ops; @@ -661,7 +661,8 @@ static void dmfe_init_dm910x(struct DEVICE *dev) * Send a packet to media from the upper layer. */ -static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) +static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb, + struct DEVICE *dev) { struct dmfe_board_info *db = netdev_priv(dev); struct tx_desc *txptr; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 019050f..2a01f0e 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -256,7 +256,8 @@ const char tulip_media_cap[32] = static void tulip_tx_timeout(struct net_device *dev); static void tulip_init_ring(struct net_device *dev); static void tulip_free_ring(struct net_device *dev); -static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t tulip_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int tulip_open(struct net_device *dev); static int tulip_close(struct net_device *dev); static void tulip_up(struct net_device *dev); @@ -645,7 +646,7 @@ static void tulip_init_ring(struct net_device *dev) tp->tx_ring[i-1].buffer2 = cpu_to_le32(tp->tx_ring_dma); } -static int +static netdev_tx_t tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tulip_private *tp = netdev_priv(dev); diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 9074a34..c457a0c 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -215,7 +215,8 @@ static int mode = 8; /* function declaration ------------------------------------- */ static int uli526x_open(struct net_device *); -static int uli526x_start_xmit(struct sk_buff *, struct net_device *); +static netdev_tx_t uli526x_start_xmit(struct sk_buff *, + struct net_device *); static int uli526x_stop(struct net_device *); static void uli526x_set_filter_mode(struct net_device *); static const struct ethtool_ops netdev_ethtool_ops; @@ -567,7 +568,8 @@ static void uli526x_init(struct net_device *dev) * Send a packet to media from the upper layer. */ -static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct uli526x_board_info *db = netdev_priv(dev); struct tx_desc *txptr; diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 1853530..3e59397e 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -333,7 +333,7 @@ static void init_registers(struct net_device *dev); static void tx_timeout(struct net_device *dev); static int alloc_ringdesc(struct net_device *dev); static void free_ringdesc(struct netdev_private *np); -static int start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int netdev_rx(struct net_device *dev); @@ -997,7 +997,7 @@ static void free_ringdesc(struct netdev_private *np) } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); unsigned entry; diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 22b6a23..0f2ca598 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -113,7 +113,8 @@ struct xircom_private { static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void xircom_remove(struct pci_dev *pdev); static irqreturn_t xircom_interrupt(int irq, void *dev_instance); -static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t xircom_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int xircom_open(struct net_device *dev); static int xircom_close(struct net_device *dev); static void xircom_up(struct xircom_private *card); @@ -384,7 +385,8 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance) return IRQ_HANDLED; } -static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t xircom_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct xircom_private *card; unsigned long flags; -- cgit v0.10.2 From 27a1de95a1461ec0589005c293d6ac23a46cb72d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:54 +0000 Subject: 3com: convert drivers to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index e29fb1a..f603091 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -409,7 +409,7 @@ static void el_timeout(struct net_device *dev) * no real choice. */ -static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h index f40b049..183fd55 100644 --- a/drivers/net/3c501.h +++ b/drivers/net/3c501.h @@ -6,7 +6,7 @@ static int el1_probe1(struct net_device *dev, int ioaddr); static int el_open(struct net_device *dev); static void el_timeout(struct net_device *dev); -static int el_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t el_interrupt(int irq, void *dev_id); static void el_receive(struct net_device *dev); static void el_reset(struct net_device *dev); diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index 7bba480..a21c9d1 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -976,7 +976,7 @@ static int elp_open(struct net_device *dev) * ******************************************************/ -static bool send_packet(struct net_device *dev, struct sk_buff *skb) +static netdev_tx_t send_packet(struct net_device *dev, struct sk_buff *skb) { elp_device *adapter = netdev_priv(dev); unsigned long target; @@ -1067,7 +1067,7 @@ static void elp_timeout(struct net_device *dev) * ******************************************************/ -static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t elp_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; elp_device *adapter = netdev_priv(dev); diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 9e93a0b..a6dc8bc 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -284,7 +284,8 @@ static unsigned short init_words[] = { static int el16_probe1(struct net_device *dev, int ioaddr); static int el16_open(struct net_device *dev); -static int el16_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t el16_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t el16_interrupt(int irq, void *dev_id); static void el16_rx(struct net_device *dev); static int el16_close(struct net_device *dev); @@ -509,7 +510,8 @@ static void el16_tx_timeout (struct net_device *dev) } -static int el16_send_packet (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t el16_send_packet (struct sk_buff *skb, + struct net_device *dev) { struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index d2515d8..3b00a4e 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -191,7 +191,7 @@ static void el3_common_remove(struct net_device *dev); static ushort id_read_eeprom(int index); static ushort read_eeprom(int ioaddr, int index); static int el3_open(struct net_device *dev); -static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t el3_interrupt(int irq, void *dev_id); static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); @@ -816,7 +816,7 @@ el3_tx_timeout (struct net_device *dev) } -static int +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct el3_private *lp = netdev_priv(dev); diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 3116410..4adcb950 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -369,8 +369,8 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, struct pnp_dev *idev, int card_number); static int corkscrew_open(struct net_device *dev); static void corkscrew_timer(unsigned long arg); -static int corkscrew_start_xmit(struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int corkscrew_rx(struct net_device *dev); static void corkscrew_timeout(struct net_device *dev); static int boomerang_rx(struct net_device *dev); @@ -998,8 +998,8 @@ static void corkscrew_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int corkscrew_start_xmit(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct corkscrew_private *vp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 70c701b..cb0b730 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -183,7 +183,7 @@ sizeof(nop_cmd) = 8; static irqreturn_t elmc_interrupt(int irq, void *dev_id); static int elmc_open(struct net_device *dev); static int elmc_close(struct net_device *dev); -static int elmc_send_packet(struct sk_buff *, struct net_device *); +static netdev_tx_t elmc_send_packet(struct sk_buff *, struct net_device *); static struct net_device_stats *elmc_get_stats(struct net_device *dev); static void elmc_timeout(struct net_device *dev); #ifdef ELMC_MULTICAST @@ -1129,7 +1129,7 @@ static void elmc_timeout(struct net_device *dev) * send frame */ -static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t elmc_send_packet(struct sk_buff *skb, struct net_device *dev) { int len; int i; diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 72b9ed7..6021e6d 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -213,7 +213,8 @@ static int mc32_probe1(struct net_device *dev, int ioaddr); static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len); static int mc32_open(struct net_device *dev); static void mc32_timeout(struct net_device *dev); -static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t mc32_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t mc32_interrupt(int irq, void *dev_id); static int mc32_close(struct net_device *dev); static struct net_device_stats *mc32_get_stats(struct net_device *dev); @@ -1020,7 +1021,8 @@ static void mc32_timeout(struct net_device *dev) * */ -static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t mc32_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); u32 head = atomic_read(&lp->tx_ring_head); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index beb0402..7adff4d 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -716,8 +716,10 @@ static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *vp, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); static void rx_oom_timer(unsigned long arg); -static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t vortex_start_xmit(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t boomerang_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int vortex_rx(struct net_device *dev); static int boomerang_rx(struct net_device *dev); static irqreturn_t vortex_interrupt(int irq, void *dev_id); @@ -2035,7 +2037,7 @@ vortex_error(struct net_device *dev, int status) } } -static int +static netdev_tx_t vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); @@ -2090,7 +2092,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static int +static netdev_tx_t boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); -- cgit v0.10.2 From 3b29a56d31d585d39bf9ffe9ef1f10bd637ee0f1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:55 +0000 Subject: intel: convert drivers to netdev_tx_t Get rid of some bogus return wrapping as well. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 569df19..6a31760 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1690,7 +1690,8 @@ static void e100_xmit_prepare(struct nic *nic, struct cb *cb, cb->u.tcb.tbd.size = cpu_to_le16(skb->len); } -static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t e100_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct nic *nic = netdev_priv(netdev); int err; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index d7df00c..b3063e6 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -125,7 +125,8 @@ static void e1000_set_rx_mode(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); static void e1000_82547_tx_fifo_stall(unsigned long data); -static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, + struct net_device *netdev); static struct net_device_stats * e1000_get_stats(struct net_device *netdev); static int e1000_change_mtu(struct net_device *netdev, int new_mtu); static int e1000_set_mac(struct net_device *netdev, void *p); @@ -3249,7 +3250,8 @@ static int e1000_maybe_stop_tx(struct net_device *netdev, } #define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) -static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 63415bb..428bf6d 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4097,7 +4097,8 @@ static int e1000_maybe_stop_tx(struct net_device *netdev, int size) } #define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) -static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_ring *tx_ring = adapter->tx_ring; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index cef4289..7a054d9 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -98,9 +98,11 @@ static void igb_set_multi(struct net_device *); static void igb_update_phy_info(unsigned long); static void igb_watchdog(unsigned long); static void igb_watchdog_task(struct work_struct *); -static int igb_xmit_frame_ring_adv(struct sk_buff *, struct net_device *, - struct igb_ring *); -static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *); +static netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *, + struct net_device *, + struct igb_ring *); +static netdev_tx_t igb_xmit_frame_adv(struct sk_buff *skb, + struct net_device *); static struct net_device_stats *igb_get_stats(struct net_device *); static int igb_change_mtu(struct net_device *, int); static int igb_set_mac(struct net_device *, void *); @@ -3295,9 +3297,9 @@ static int igb_maybe_stop_tx(struct net_device *netdev, return __igb_maybe_stop_tx(netdev, tx_ring, size); } -static int igb_xmit_frame_ring_adv(struct sk_buff *skb, - struct net_device *netdev, - struct igb_ring *tx_ring) +static netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb, + struct net_device *netdev, + struct igb_ring *tx_ring) { struct igb_adapter *adapter = netdev_priv(netdev); unsigned int first; @@ -3385,7 +3387,8 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, return NETDEV_TX_OK; } -static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t igb_xmit_frame_adv(struct sk_buff *skb, + struct net_device *netdev) { struct igb_adapter *adapter = netdev_priv(netdev); struct igb_ring *tx_ring; @@ -3398,7 +3401,7 @@ static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *netdev) * to a flow. Right now, performance is impacted slightly negatively * if using multiple tx queues. If the stack breaks away from a * single qdisc implementation, we can look at this again. */ - return (igb_xmit_frame_ring_adv(skb, netdev, tx_ring)); + return igb_xmit_frame_ring_adv(skb, netdev, tx_ring); } /** diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 3f03c42..dadb782 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2204,9 +2204,9 @@ static inline void igbvf_tx_queue_adv(struct igbvf_adapter *adapter, mmiowb(); } -static int igbvf_xmit_frame_ring_adv(struct sk_buff *skb, - struct net_device *netdev, - struct igbvf_ring *tx_ring) +static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb, + struct net_device *netdev, + struct igbvf_ring *tx_ring) { struct igbvf_adapter *adapter = netdev_priv(netdev); unsigned int first, tx_flags = 0; @@ -2279,11 +2279,11 @@ static int igbvf_xmit_frame_ring_adv(struct sk_buff *skb, return NETDEV_TX_OK; } -static int igbvf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t igbvf_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct igbvf_adapter *adapter = netdev_priv(netdev); struct igbvf_ring *tx_ring; - int retval; if (test_bit(__IGBVF_DOWN, &adapter->state)) { dev_kfree_skb_any(skb); @@ -2292,9 +2292,7 @@ static int igbvf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_ring = &adapter->tx_ring[0]; - retval = igbvf_xmit_frame_ring_adv(skb, netdev, tx_ring); - - return retval; + return igbvf_xmit_frame_ring_adv(skb, netdev, tx_ring); } /** diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index fad08ce..8aa44dc 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -81,7 +81,8 @@ static void ixgb_clean_tx_ring(struct ixgb_adapter *adapter); static void ixgb_clean_rx_ring(struct ixgb_adapter *adapter); static void ixgb_set_multi(struct net_device *netdev); static void ixgb_watchdog(unsigned long data); -static int ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +static netdev_tx_t ixgb_xmit_frame(struct sk_buff *skb, + struct net_device *netdev); static struct net_device_stats *ixgb_get_stats(struct net_device *netdev); static int ixgb_change_mtu(struct net_device *netdev, int new_mtu); static int ixgb_set_mac(struct net_device *netdev, void *p); @@ -1442,7 +1443,7 @@ static int ixgb_maybe_stop_tx(struct net_device *netdev, MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1 /* for context */ \ + 1 /* one more needed for sentinel TSO workaround */ -static int +static netdev_tx_t ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct ixgb_adapter *adapter = netdev_priv(netdev); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 0bea096..7e964a6 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5107,7 +5107,8 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) return skb_tx_hash(dev, skb); } -static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_ring *tx_ring; -- cgit v0.10.2 From 0fc480987e69f22b9212f087545b4d1ca6950807 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:56 +0000 Subject: appletalk: convert drivers to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 29b279f..b5dc7f5 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -192,7 +192,8 @@ static irqreturn_t cops_interrupt (int irq, void *dev_id); static void cops_poll (unsigned long ltdev); static void cops_timeout(struct net_device *dev); static void cops_rx (struct net_device *dev); -static int cops_send_packet (struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t cops_send_packet (struct sk_buff *skb, + struct net_device *dev); static void set_multicast_list (struct net_device *dev); static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static int cops_close (struct net_device *dev); @@ -875,7 +876,8 @@ static void cops_timeout(struct net_device *dev) * Make the card transmit a LocalTalk packet. */ -static int cops_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t cops_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct cops_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 6cfd961..bea87da 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -48,7 +48,8 @@ static int ipddp_mode = IPDDP_DECAP; #endif /* Index to functions, as function prototypes. */ -static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ipddp_xmit(struct sk_buff *skb, + struct net_device *dev); static int ipddp_create(struct ipddp_route *new_rt); static int ipddp_delete(struct ipddp_route *rt); static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt); @@ -113,7 +114,7 @@ static struct net_device * __init ipddp_init(void) /* * Transmit LLAP/ELAP frame using aarp_send_ddp. */ -static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev) { __be32 paddr = skb_rtable(skb)->rt_gateway; struct ddpehdr *ddp; diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index c80fb9c..08760ba 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -697,7 +697,7 @@ static int do_read(struct net_device *dev, void *cbuf, int cbuflen, static struct timer_list ltpc_timer; -static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ltpc_xmit(struct sk_buff *skb, struct net_device *dev); static int read_30 ( struct net_device *dev) { @@ -895,7 +895,7 @@ static void ltpc_poll(unsigned long l) /* DDP to LLAP translation */ -static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ltpc_xmit(struct sk_buff *skb, struct net_device *dev) { /* in kernel 1.3.xx, on entry skb->data points to ddp header, * and skb->len is the length of the ddp data + ddp header -- cgit v0.10.2 From d0cf9c0dadcdc89a755bcb301cfc9c796eb28ccf Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:57 +0000 Subject: wireless: convert drivers to netdev_tx_t Mostly just simple conversions: * ray_cs had bogus return of NET_TX_LOCKED but driver was not using NETIF_F_LLTX * hostap and ipw2x00 had some code that returned value from a called function that also had to change to return netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 9653f47..796396c 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -334,12 +334,12 @@ int i2400m_net_tx(struct i2400m *i2400m, struct net_device *net_dev, * that will sleep. See i2400m_net_wake_tx() for details. */ static -int i2400m_hard_start_xmit(struct sk_buff *skb, - struct net_device *net_dev) +netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb, + struct net_device *net_dev) { - int result; struct i2400m *i2400m = net_dev_to_i2400m(net_dev); struct device *dev = i2400m_dev(i2400m); + int result; d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); if (i2400m->state == I2400M_SS_IDLE) @@ -353,9 +353,9 @@ int i2400m_hard_start_xmit(struct sk_buff *skb, net_dev->stats.tx_bytes += skb->len; } kfree_skb(skb); - result = NETDEV_TX_OK; - d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result); - return result; + + d_fnend(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); + return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index c150c48..7116a1a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1920,7 +1920,9 @@ static int airo_open(struct net_device *dev) { return 0; } -static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { +static netdev_tx_t mpi_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ int npacks, pending; unsigned long flags; struct airo_info *ai = dev->ml_priv; @@ -2119,7 +2121,9 @@ static void airo_end_xmit(struct net_device *dev) { dev_kfree_skb(skb); } -static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { +static netdev_tx_t airo_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ s16 len; int i, j; struct airo_info *priv = dev->ml_priv; @@ -2184,7 +2188,9 @@ static void airo_end_xmit11(struct net_device *dev) { dev_kfree_skb(skb); } -static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { +static netdev_tx_t airo_start_xmit11(struct sk_buff *skb, + struct net_device *dev) +{ s16 len; int i, j; struct airo_info *priv = dev->ml_priv; diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index f96c634..921a082 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -77,7 +77,7 @@ struct arlan_conf_stru arlan_conf[MAX_ARLANS]; static int arlans_found; static int arlan_open(struct net_device *dev); -static int arlan_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t arlan_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t arlan_interrupt(int irq, void *dev_id); static int arlan_close(struct net_device *dev); static struct net_device_stats * @@ -1169,7 +1169,7 @@ static void arlan_tx_timeout (struct net_device *dev) } -static int arlan_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t arlan_tx(struct sk_buff *skb, struct net_device *dev) { short length; unsigned char *buf; diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 05813bc..a3b36b3 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -781,7 +781,7 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, priv->tx_free_mem -= len; } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; struct atmel_private *priv = netdev_priv(dev); diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h index 2e9fb0f..7f9d8d9 100644 --- a/drivers/net/wireless/hostap/hostap_80211.h +++ b/drivers/net/wireless/hostap/hostap_80211.h @@ -3,6 +3,7 @@ #include #include +#include struct hostap_ieee80211_mgmt { __le16 frame_control; @@ -85,8 +86,11 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats); void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); -int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev); -int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); -int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, + struct net_device *dev); +netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, + struct net_device *dev); +netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, + struct net_device *dev); #endif /* HOSTAP_80211_H */ diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 1fe1bba..90108b6 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -53,7 +53,8 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) /* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta) * Convert Ethernet header into a suitable IEEE 802.11 header depending on * device configuration. */ -int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct hostap_interface *iface; local_info_t *local; @@ -261,7 +262,8 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) /* hard_start_xmit function for hostapd wlan#ap interfaces */ -int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct hostap_interface *iface; local_info_t *local; @@ -373,11 +375,12 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, /* hard_start_xmit function for master radio interface wifi#. * AP processing (TX rate control, power save buffering, etc.). * Use hardware TX function to send the frame. */ -int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct hostap_interface *iface; local_info_t *local; - int ret = NETDEV_TX_BUSY; + netdev_tx_t ret = NETDEV_TX_BUSY; u16 fc; struct hostap_tx_data tx; ap_tx_ret tx_ret; diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 7745738..240cff1 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -3330,8 +3330,8 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data) return IRQ_NONE; } -static int ipw2100_tx(struct libipw_txb *txb, struct net_device *dev, - int pri) +static netdev_tx_t ipw2100_tx(struct libipw_txb *txb, + struct net_device *dev, int pri) { struct ipw2100_priv *priv = libipw_priv(dev); struct list_head *element; @@ -3369,12 +3369,12 @@ static int ipw2100_tx(struct libipw_txb *txb, struct net_device *dev, ipw2100_tx_send_data(priv); spin_unlock_irqrestore(&priv->low_lock, flags); - return 0; + return NETDEV_TX_OK; - fail_unlock: +fail_unlock: netif_stop_queue(dev); spin_unlock_irqrestore(&priv->low_lock, flags); - return 1; + return NETDEV_TX_BUSY; } static int ipw2100_msg_allocate(struct ipw2100_priv *priv) diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 3f8372d..3838f9f 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -10459,12 +10459,12 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, } #endif -static int ipw_net_hard_start_xmit(struct libipw_txb *txb, - struct net_device *dev, int pri) +static netdev_tx_t ipw_net_hard_start_xmit(struct libipw_txb *txb, + struct net_device *dev, int pri) { struct ipw_priv *priv = libipw_priv(dev); unsigned long flags; - int ret; + netdev_tx_t ret; IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size); spin_lock_irqsave(&priv->lock, flags); @@ -11602,7 +11602,8 @@ static int ipw_prom_stop(struct net_device *dev) return 0; } -static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ipw_prom_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { IPW_DEBUG_INFO("prom dev->xmit\n"); dev_kfree_skb(skb); diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h index 8f91d34..bf45391 100644 --- a/drivers/net/wireless/ipw2x00/libipw.h +++ b/drivers/net/wireless/ipw2x00/libipw.h @@ -867,8 +867,8 @@ struct libipw_device { /* Callback functions */ void (*set_security) (struct net_device * dev, struct libipw_security * sec); - int (*hard_start_xmit) (struct libipw_txb * txb, - struct net_device * dev, int pri); + netdev_tx_t (*hard_start_xmit) (struct libipw_txb * txb, + struct net_device * dev, int pri); int (*reset_port) (struct net_device * dev); int (*is_queue_full) (struct net_device * dev, int pri); @@ -1028,7 +1028,8 @@ extern void libipw_networks_age(struct libipw_device *ieee, extern int libipw_set_encryption(struct libipw_device *ieee); /* libipw_tx.c */ -extern int libipw_xmit(struct sk_buff *skb, struct net_device *dev); +extern netdev_tx_t libipw_xmit(struct sk_buff *skb, + struct net_device *dev); extern void libipw_txb_free(struct libipw_txb *); /* libipw_rx.c */ diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index 46530ce..da8beac 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -252,7 +252,7 @@ static int libipw_classify(struct sk_buff *skb) /* Incoming skb is converted to a txb which consists of * a block of 802.11 fragment packets (stored as skbs) */ -int libipw_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev) { struct libipw_device *ieee = netdev_priv(dev); struct libipw_txb *txb = NULL; @@ -523,8 +523,8 @@ int libipw_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb_any(skb); if (txb) { - int ret = (*ieee->hard_start_xmit) (txb, dev, priority); - if (ret == 0) { + netdev_tx_t ret = (*ieee->hard_start_xmit)(txb, dev, priority); + if (ret == NETDEV_TX_OK) { dev->stats.tx_packets++; dev->stats.tx_bytes += txb->payload_size; return NETDEV_TX_OK; diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 0b84bdc..8b15380 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -6,7 +6,7 @@ #ifndef _LBS_DECL_H_ #define _LBS_DECL_H_ -#include +#include #include "defs.h" @@ -41,7 +41,8 @@ u8 lbs_data_rate_to_fw_index(u32 rate); int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len); void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, int result); -int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev); int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band); int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 8df1cfd..87b4e49 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1647,7 +1647,8 @@ static int lbs_rtap_stop(struct net_device *dev) return 0; } -static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lbs_rtap_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { netif_stop_queue(dev); return NETDEV_TX_BUSY; diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 160cfd8..4c018f7 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -57,19 +57,17 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) * @param skb A pointer to skb which includes TX packet * @return 0 or -1 */ -int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; struct lbs_private *priv = dev->ml_priv; struct txpd *txpd; char *p802x_hdr; uint16_t pkt_len; - int ret; + netdev_tx_t ret = NETDEV_TX_OK; lbs_deb_enter(LBS_DEB_TX); - ret = NETDEV_TX_OK; - /* We need to protect against the queues being restarted before we get round to stopping them */ spin_lock_irqsave(&priv->driver_lock, flags); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 6f6cd43..896f532 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -312,7 +312,8 @@ struct hwsim_radiotap_hdr { } __attribute__ ((packed)); -static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, + struct net_device *dev) { /* TODO: allow packet injection */ dev_kfree_skb(skb); diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 712f26e..9498b46 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -203,7 +203,8 @@ static int netwave_open(struct net_device *dev); /* Open the device */ static int netwave_close(struct net_device *dev); /* Close the device */ /* Packet transmission and Packet reception */ -static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t netwave_start_xmit( struct sk_buff *skb, + struct net_device *dev); static int netwave_rx( struct net_device *dev); /* Interrupt routines */ @@ -1026,7 +1027,8 @@ static int netwave_hw_xmit(unsigned char* data, int len, return 0; } -static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) { +static netdev_tx_t netwave_start_xmit(struct sk_buff *skb, + struct net_device *dev) { /* This flag indicate that the hardware can't perform a transmission. * Theoritically, NET3 check it before sending a packet to the driver, * but in fact it never do that and pool continuously. diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 2c7dc65..7a32bcb 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -337,7 +337,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu) /* Tx path */ /********************************************************************/ -static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 9b5ee34..872b647 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -72,7 +72,7 @@ islpci_eth_cleanup_transmit(islpci_private *priv, } } -int +netdev_tx_t islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) { islpci_private *priv = netdev_priv(ndev); diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h index 61454d3..54f9a4b 100644 --- a/drivers/net/wireless/prism54/islpci_eth.h +++ b/drivers/net/wireless/prism54/islpci_eth.h @@ -64,7 +64,7 @@ struct avs_80211_1_header { }; void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *); -int islpci_eth_transmit(struct sk_buff *, struct net_device *); +netdev_tx_t islpci_eth_transmit(struct sk_buff *, struct net_device *); int islpci_eth_receive(islpci_private *); void islpci_eth_tx_timeout(struct net_device *); void islpci_do_reset_and_wake(struct work_struct *); diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 3252069..88cd58e 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -104,7 +104,8 @@ static int ray_dev_init(struct net_device *dev); static const struct ethtool_ops netdev_ethtool_ops; static int ray_open(struct net_device *dev); -static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb, + struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void ray_update_multi_list(struct net_device *dev, int all); static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, @@ -915,16 +916,19 @@ static int ray_dev_config(struct net_device *dev, struct ifmap *map) } /*===========================================================================*/ -static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb, + struct net_device *dev) { ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; short length = skb->len; - if (!(pcmcia_dev_present(link))) { + if (!pcmcia_dev_present(link)) { DEBUG(2, "ray_dev_start_xmit - device not present\n"); - return NETDEV_TX_LOCKED; + dev_kfree_skb(skb); + return NETDEV_TX_OK; } + DEBUG(3, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev); if (local->authentication_state == NEED_TO_AUTH) { DEBUG(0, "ray_cs Sending authentication request.\n"); @@ -951,8 +955,8 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) default: dev->trans_start = jiffies; dev_kfree_skb(skb); - return NETDEV_TX_OK; } + return NETDEV_TX_OK; } /* ray_dev_start_xmit */ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index ef2cb20..ea6a87c 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1533,7 +1533,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) } /* Encapsulate a datagram and kick it into a TTY queue. */ -static int strip_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t strip_xmit(struct sk_buff *skb, struct net_device *dev) { struct strip *strip_info = netdev_priv(dev); diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 5cb5329..d634b2d 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2841,7 +2841,8 @@ static int wv_packet_write(struct net_device * dev, void *buf, short length) * the packet. We also prevent reentrance. Then we call the function * to send the packet. */ -static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) +static netdev_tx_t wavelan_packet_xmit(struct sk_buff *skb, + struct net_device * dev) { net_local *lp = netdev_priv(dev); unsigned long flags; diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h index 2daa021..dbe8de6 100644 --- a/drivers/net/wireless/wavelan.p.h +++ b/drivers/net/wireless/wavelan.p.h @@ -611,7 +611,7 @@ static inline int wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer. */ void *, short); -static int +static netdev_tx_t wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */ struct net_device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index b9748d4..431a20e 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3078,7 +3078,7 @@ wv_packet_write(struct net_device * dev, * the packet. We also prevent reentrance. Then, we call the function * to send the packet... */ -static int +static netdev_tx_t wavelan_packet_xmit(struct sk_buff * skb, struct net_device * dev) { diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index 706fd300..81d9153 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -707,7 +707,7 @@ static void wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer */ void *, short); -static int +static netdev_tx_t wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ struct net_device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index a83a562..4f1e0cf 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1333,7 +1333,8 @@ static void wl3501_tx_timeout(struct net_device *dev) * 1 - Could not transmit (dev_queue_xmit will queue it) * and try to sent it later */ -static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t wl3501_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { int enabled, rc; struct wl3501_card *this = netdev_priv(dev); diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index dae1bfb..bc81974 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -779,7 +779,8 @@ static int zd1201_net_stop(struct net_device *dev) (llc+snap+type+payload) zd 1 null byte, zd1201 packet type */ -static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct zd1201 *zd = netdev_priv(dev); unsigned char *txbuf = zd->txdata; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index dbd8411..588005c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1050,8 +1050,10 @@ void ieee80211_recalc_idle(struct ieee80211_local *local); /* tx handling */ void ieee80211_clear_tx_pending(struct ieee80211_local *local); void ieee80211_tx_pending(unsigned long data); -int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); -int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, + struct net_device *dev); +netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, + struct net_device *dev); /* HT */ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0c08d1e..5143d20 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1483,8 +1483,8 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, dev_put(sdata->dev); } -int ieee80211_monitor_start_xmit(struct sk_buff *skb, - struct net_device *dev) +netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_channel *chan = local->hw.conf.channel; @@ -1568,8 +1568,8 @@ fail: * encapsulated packet will then be passed to master interface, wlan#.11, for * transmission (through low-level driver). */ -int ieee80211_subif_start_xmit(struct sk_buff *skb, - struct net_device *dev) +netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; -- cgit v0.10.2 From 61357325f377889a1daffa14962d705dc814dd0e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:58 +0000 Subject: netdev: convert bulk of drivers to netdev_tx_t In a couple of cases collapse some extra code like: int retval = NETDEV_TX_OK; ... return retval; into return NETDEV_TX_OK; Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index c1c9697..96a2959 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -257,7 +257,8 @@ static int ieee802154_fake_close(struct net_device *dev) return 0; } -static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ieee802154_fake_xmit(struct sk_buff *skb, + struct net_device *dev) { skb->iif = dev->ifindex; skb->dev = dev; diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 4a8995a..462d9f59 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -736,7 +736,8 @@ static void cp_tx (struct cp_private *cp) netif_wake_queue(cp->dev); } -static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t cp_start_xmit (struct sk_buff *skb, + struct net_device *dev) { struct cp_private *cp = netdev_priv(dev); unsigned entry; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index b39ec98..4a36287 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -628,8 +628,8 @@ static void mdio_write (struct net_device *dev, int phy_id, int location, static void rtl8139_start_thread(struct rtl8139_private *tp); static void rtl8139_tx_timeout (struct net_device *dev); static void rtl8139_init_ring (struct net_device *dev); -static int rtl8139_start_xmit (struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb, + struct net_device *dev); #ifdef CONFIG_NET_POLL_CONTROLLER static void rtl8139_poll_controller(struct net_device *dev); #endif @@ -1687,7 +1687,8 @@ static void rtl8139_tx_timeout (struct net_device *dev) } } -static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb, + struct net_device *dev) { struct rtl8139_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 996cc91..ea6b139 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -356,7 +356,7 @@ static char init_setup[] = 0x7f /* *multi IA */ }; static int i596_open(struct net_device *dev); -static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t i596_interrupt(int irq, void *dev_id); static int i596_close(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); @@ -1054,8 +1054,7 @@ static void i596_tx_timeout (struct net_device *dev) netif_wake_queue (dev); } - -static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct i596_private *lp = dev->ml_priv; struct tx_cmd *tx_cmd; diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 21153de..7c7518b 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -17,7 +17,7 @@ int ei_close(struct net_device *dev) } EXPORT_SYMBOL(ei_close); -int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { return __ei_start_xmit(skb, dev); } diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 3c61d6d..3d9e8fb 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -40,7 +40,7 @@ extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); extern irqreturn_t ei_interrupt(int irq, void *dev_id); extern void ei_tx_timeout(struct net_device *dev); -extern int ei_start_xmit(struct sk_buff *skb, struct net_device *dev); +extern netdev_tx_t ei_start_xmit(struct sk_buff *skb, struct net_device *dev); extern void ei_set_multicast_list(struct net_device *dev); extern struct net_device_stats *ei_get_stats(struct net_device *dev); @@ -58,7 +58,7 @@ extern int eip_open(struct net_device *dev); extern int eip_close(struct net_device *dev); extern irqreturn_t eip_interrupt(int irq, void *dev_id); extern void eip_tx_timeout(struct net_device *dev); -extern int eip_start_xmit(struct sk_buff *skb, struct net_device *dev); +extern netdev_tx_t eip_start_xmit(struct sk_buff *skb, struct net_device *dev); extern void eip_set_multicast_list(struct net_device *dev); extern struct net_device_stats *eip_get_stats(struct net_device *dev); diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c index d225c29..a2a64ea 100644 --- a/drivers/net/8390p.c +++ b/drivers/net/8390p.c @@ -22,7 +22,7 @@ int eip_close(struct net_device *dev) } EXPORT_SYMBOL(eip_close); -int eip_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t eip_start_xmit(struct sk_buff *skb, struct net_device *dev) { return __ei_start_xmit(skb, dev); } diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 174a811..b7ec036 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -547,7 +547,8 @@ static void lance_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lance_start_xmit (struct sk_buff *skb, + struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 08419ee..5f0b05c 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2464,7 +2464,8 @@ ace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc, u64 addr, } -static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ace_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ace_private *ap = netdev_priv(dev); struct ace_regs __iomem *regs = ap->regs; diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h index c987c9b..17079b9 100644 --- a/drivers/net/acenic.h +++ b/drivers/net/acenic.h @@ -775,7 +775,8 @@ static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs); static irqreturn_t ace_interrupt(int irq, void *dev_id); static int ace_load_firmware(struct net_device *dev); static int ace_open(struct net_device *dev); -static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ace_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int ace_close(struct net_device *dev); static void ace_tasklet(unsigned long dev); static void ace_dump_trace(struct ace_private *ap); diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 61ac671..98b5f46 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1300,7 +1300,8 @@ static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp ) This function will queue the transmit packets to the descriptors and will trigger the send operation. It also initializes the transmit descriptors with buffer physical address, byte count, ownership to hardware etc. */ -static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) +static netdev_tx_t amd8111e_start_xmit(struct sk_buff *skb, + struct net_device * dev) { struct amd8111e_priv *lp = netdev_priv(dev); int tx_index; diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 7d227cda..75a5725 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -591,7 +591,8 @@ static int arcnet_rebuild_header(struct sk_buff *skb) /* Called by the kernel in order to transmit a packet. */ -int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t arcnet_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct arcnet_local *lp = netdev_priv(dev); struct archdr *pkt; diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 47d976c..c35af3e 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -115,7 +115,8 @@ struct lancedata { static int ariadne_open(struct net_device *dev); static void ariadne_init_ring(struct net_device *dev); -static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ariadne_start_xmit(struct sk_buff *skb, + struct net_device *dev); static void ariadne_tx_timeout(struct net_device *dev); static int ariadne_rx(struct net_device *dev); static void ariadne_reset(struct net_device *dev); @@ -589,7 +590,8 @@ static void ariadne_tx_timeout(struct net_device *dev) } -static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ariadne_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ariadne_private *priv = netdev_priv(dev); volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 5349c58..544d5af 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -159,7 +159,8 @@ struct net_local { static int at1700_probe1(struct net_device *dev, int ioaddr); static int read_eeprom(long ioaddr, int location); static int net_open(struct net_device *dev); -static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t net_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t net_interrupt(int irq, void *dev_id); static void net_rx(struct net_device *dev); static int net_close(struct net_device *dev); @@ -595,7 +596,8 @@ static void net_tx_timeout (struct net_device *dev) } -static int net_send_packet (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t net_send_packet (struct sk_buff *skb, + struct net_device *dev) { struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 1d601ce..bf7cc83 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -2055,7 +2055,8 @@ static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb, AT_WRITE_REG(&adapter->hw, REG_MB_PRIO_PROD_IDX, prod_data); } -static int atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct atl1c_adapter *adapter = netdev_priv(netdev); unsigned long flags; diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 4570749..bca127e 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1839,7 +1839,8 @@ static void atl1e_tx_queue(struct atl1e_adapter *adapter, u16 count, AT_WRITE_REG(&adapter->hw, REG_MB_TPD_PROD_IDX, tx_ring->next_to_use); } -static int atl1e_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct atl1e_adapter *adapter = netdev_priv(netdev); unsigned long flags; diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 8bca12f..00569dc 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2349,7 +2349,8 @@ static void atl1_tx_queue(struct atl1_adapter *adapter, u16 count, atomic_set(&tpd_ring->next_to_use, next_to_use); } -static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct atl1_adapter *adapter = netdev_priv(netdev); struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index 204db96..d0bcb57 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -821,7 +821,8 @@ static inline int TxdFreeBytes(struct atl2_adapter *adapter) (int) (txd_read_ptr - adapter->txd_write_ptr - 1); } -static int atl2_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t atl2_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct atl2_adapter *adapter = netdev_priv(netdev); struct tx_pkt_header *txph; diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 4beacc9..9043294 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -199,7 +199,8 @@ static int net_open(struct net_device *dev); static void hardware_init(struct net_device *dev); static void write_packet(long ioaddr, int length, unsigned char *packet, int pad, int mode); static void trigger_send(long ioaddr, int length); -static int atp_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t atp_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t atp_interrupt(int irq, void *dev_id); static void net_rx(struct net_device *dev); static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode); @@ -552,7 +553,8 @@ static void tx_timeout(struct net_device *dev) dev->stats.tx_errors++; } -static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t atp_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 2aab1eb..407fd45 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -937,7 +937,7 @@ static int au1000_close(struct net_device *dev) /* * Au1000 transmit routine. */ -static int au1000_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev) { struct au1000_private *aup = netdev_priv(dev); struct net_device_stats *ps = &dev->stats; diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 07c92f3..bee5101 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -946,7 +946,7 @@ static void b44_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t b44_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct b44 *bp = netdev_priv(dev); int rc = NETDEV_TX_OK; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 7b9efee..e19fe1d 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -427,7 +427,8 @@ static int make_tx_wrbs(struct be_adapter *adapter, return copied; } -static int be_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t be_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); struct be_tx_obj *tx_obj = &adapter->tx_obj; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index c4e85f6..fcaf3bc 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6283,7 +6283,7 @@ bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp) * bnx2_tx_int() runs without netif_tx_lock unless it needs to call * netif_wake_queue(). */ -static int +static netdev_tx_t bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index b318d16..e2e5026 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -10936,7 +10936,7 @@ exit_lbl: * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call * netif_wake_queue() */ -static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); struct bnx2x_fastpath *fp, *fp_stat; diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index b3004de..9ce3dda 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -238,7 +238,8 @@ static void chipset_init(struct net_device *dev) * xx xx xx xx ff ll 00 11 22 33 44 55 66 77 * [ can-id ] [flags] [len] [can data (up to 8 bytes] */ -static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 299a33b..7517dc1 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2918,7 +2918,7 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring, return 0; } -static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t cas_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct cas *cp = netdev_priv(dev); diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 3711d64..8c658cf 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1776,7 +1776,7 @@ static inline int eth_hdr_len(const void *data) /* * Adds the CPL header to the sk_buff and passes it to t1_sge_tx. */ -int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct adapter *adapter = dev->ml_priv; struct sge *sge = adapter->sge; diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h index 8c94051..00cc37f 100644 --- a/drivers/net/chelsio/sge.h +++ b/drivers/net/chelsio/sge.h @@ -78,7 +78,7 @@ void t1_sge_destroy(struct sge *); irqreturn_t t1_interrupt(int irq, void *cookie); int t1_poll(struct napi_struct *, int); -int t1_start_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev); void t1_set_vlan_accel(struct adapter *adapter, int on_off); void t1_sge_start(struct sge *); void t1_sge_stop(struct sge *); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 839cac5..0c54219 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -246,7 +246,7 @@ struct net_local { static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular); static int net_open(struct net_device *dev); -static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t net_interrupt(int irq, void *dev_id); static void set_multicast_list(struct net_device *dev); static void net_timeout(struct net_device *dev); @@ -1518,7 +1518,7 @@ static void net_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int net_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t net_send_packet(struct sk_buff *skb,struct net_device *dev) { struct net_local *lp = netdev_priv(dev); unsigned long flags; diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 74723f2..2b1aea6 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -309,7 +309,7 @@ void t3_stop_sge_timers(struct adapter *adap); void t3_free_sge_resources(struct adapter *adap); void t3_sge_err_intr_handler(struct adapter *adapter); irq_handler_t t3_intr_handler(struct adapter *adap, int polling); -int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev); int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb); void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p); int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 29c79eb..f866128 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -1216,7 +1216,7 @@ static inline void t3_stop_tx_queue(struct netdev_queue *txq, * * Add a packet to an SGE Tx queue. Runs with softirqs disabled. */ -int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) { int qidx; unsigned int ndesc, pidx, credits, gen, compl; diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index b2e0a8f..6a6ea03 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -300,7 +300,8 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers); static void dfx_rcv_queue_process(DFX_board_t *bp); static void dfx_rcv_flush(DFX_board_t *bp); -static int dfx_xmt_queue_pkt(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, + struct net_device *dev); static int dfx_xmt_done(DFX_board_t *bp); static void dfx_xmt_flush(DFX_board_t *bp); @@ -3188,11 +3189,8 @@ static void dfx_rcv_queue_process( * None */ -static int dfx_xmt_queue_pkt( - struct sk_buff *skb, - struct net_device *dev - ) - +static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, + struct net_device *dev) { DFX_board_t *bp = netdev_priv(dev); u8 prod; /* local transmit producer index */ diff --git a/drivers/net/depca.c b/drivers/net/depca.c index adb997c..9686c1f 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -516,7 +516,8 @@ struct depca_private { ** Public Functions */ static int depca_open(struct net_device *dev); -static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t depca_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t depca_interrupt(int irq, void *dev_id); static int depca_close(struct net_device *dev); static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -928,7 +929,8 @@ static void depca_tx_timeout(struct net_device *dev) /* ** Writes a socket buffer to TX descriptor ring and starts transmission */ -static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t depca_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 4b6a219..7fa7a90 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -59,7 +59,7 @@ static int rio_open (struct net_device *dev); static void rio_timer (unsigned long data); static void rio_tx_timeout (struct net_device *dev); static void alloc_list (struct net_device *dev); -static int start_xmit (struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_xmit (struct sk_buff *skb, struct net_device *dev); static irqreturn_t rio_interrupt (int irq, void *dev_instance); static void rio_free_tx (struct net_device *dev, int irq); static void tx_error (struct net_device *dev, int tx_status); @@ -600,7 +600,7 @@ alloc_list (struct net_device *dev) return; } -static int +static netdev_tx_t start_xmit (struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c index 2818d5d..2346852 100644 --- a/drivers/net/dnet.c +++ b/drivers/net/dnet.c @@ -541,7 +541,7 @@ static inline void dnet_print_skb(struct sk_buff *skb) #define dnet_print_skb(skb) do {} while (0) #endif -static int dnet_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t dnet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct dnet *bp = netdev_priv(dev); diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 53317a8..1e93416 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -309,7 +309,8 @@ struct eepro_local { static int eepro_probe1(struct net_device *dev, int autoprobe); static int eepro_open(struct net_device *dev); -static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t eepro_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t eepro_interrupt(int irq, void *dev_id); static void eepro_rx(struct net_device *dev); static void eepro_transmit_interrupt(struct net_device *dev); @@ -1133,7 +1134,8 @@ static void eepro_tx_timeout (struct net_device *dev) } -static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t eepro_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct eepro_local *lp = netdev_priv(dev); unsigned long flags; diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index d1b6368..592de8f 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -246,7 +246,8 @@ static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 }; static int eexp_open(struct net_device *dev); static int eexp_close(struct net_device *dev); static void eexp_timeout(struct net_device *dev); -static int eexp_xmit(struct sk_buff *buf, struct net_device *dev); +static netdev_tx_t eexp_xmit(struct sk_buff *buf, + struct net_device *dev); static irqreturn_t eexp_irq(int irq, void *dev_addr); static void eexp_set_multicast(struct net_device *dev); @@ -650,7 +651,7 @@ static void eexp_timeout(struct net_device *dev) * Called to transmit a packet, or to allow us to right ourselves * if the kernel thinks we've died. */ -static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) +static netdev_tx_t eexp_xmit(struct sk_buff *buf, struct net_device *dev) { short length = buf->len; #ifdef CONFIG_SMP diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 372d6c6..117fc6c 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1276,7 +1276,8 @@ static void enc28j60_hw_tx(struct enc28j60_net *priv) locked_reg_bfset(priv, ECON1, ECON1_TXRTS); } -static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t enc28j60_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct enc28j60_net *priv = netdev_priv(dev); diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 8005b60..49912eb 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -622,7 +622,8 @@ static inline void enic_queue_wq_skb(struct enic *enic, } /* netif_tx_lock held, process context with BHs disabled, or BH */ -static int enic_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct enic *enic = netdev_priv(netdev); struct vnic_wq *wq = &enic->wq[0]; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index d668ff2..641a10d 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -298,7 +298,8 @@ static void epic_restart(struct net_device *dev); static void epic_timer(unsigned long data); static void epic_tx_timeout(struct net_device *dev); static void epic_init_ring(struct net_device *dev); -static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t epic_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int epic_rx(struct net_device *dev, int budget); static int epic_poll(struct napi_struct *napi, int budget); static irqreturn_t epic_interrupt(int irq, void *dev_instance); @@ -961,7 +962,7 @@ static void epic_init_ring(struct net_device *dev) return; } -static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t epic_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct epic_private *ep = netdev_priv(dev); int entry, free_count; diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 97d5205..71bfeec 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -405,7 +405,7 @@ static int eth16i_read_eeprom_word(int ioaddr); static void eth16i_eeprom_cmd(int ioaddr, unsigned char command); static int eth16i_open(struct net_device *dev); static int eth16i_close(struct net_device *dev); -static int eth16i_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t eth16i_tx(struct sk_buff *skb, struct net_device *dev); static void eth16i_rx(struct net_device *dev); static void eth16i_timeout(struct net_device *dev); static irqreturn_t eth16i_interrupt(int irq, void *dev_id); @@ -1053,7 +1053,7 @@ static void eth16i_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t eth16i_tx(struct sk_buff *skb, struct net_device *dev) { struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index 4dbe5f1..b871aef 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -802,7 +802,7 @@ static struct net_device_stats *ethoc_stats(struct net_device *dev) return &priv->stats; } -static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ethoc *priv = netdev_priv(dev); struct ethoc_bd bd; diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 9c51bc8..b2a5ec8 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -298,7 +298,7 @@ struct ewrk3_private { ** Public Functions */ static int ewrk3_open(struct net_device *dev); -static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev); static irqreturn_t ewrk3_interrupt(int irq, void *dev_id); static int ewrk3_close(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -764,7 +764,7 @@ static void ewrk3_timeout(struct net_device *dev) /* ** Writes a socket buffer to the free page queue */ -static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev) { struct ewrk3_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index f66da84..18d5fbb 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -433,7 +433,7 @@ static void netdev_timer(unsigned long data); static void reset_timer(unsigned long data); static void fealnx_tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); -static int start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static int netdev_rx(struct net_device *dev); static void set_rx_mode(struct net_device *dev); @@ -1305,7 +1305,7 @@ static void init_ring(struct net_device *dev) } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); unsigned long flags; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 3b4e076..0a1c2bb 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -2137,7 +2137,7 @@ static void nv_gear_backoff_reseed(struct net_device *dev) * nv_start_xmit: dev->hard_start_xmit function * Called with netif_tx_lock held. */ -static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u32 tx_flags = 0; @@ -2257,7 +2257,8 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, + struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u32 tx_flags = 0; diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 635341d..1d5064a 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -557,7 +557,8 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void hamachi_timer(unsigned long data); static void hamachi_tx_timeout(struct net_device *dev); static void hamachi_init_ring(struct net_device *dev); -static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t hamachi_interrupt(int irq, void *dev_instance); static int hamachi_rx(struct net_device *dev); static inline int hamachi_tx(struct net_device *dev); @@ -1263,7 +1264,8 @@ do { \ } while (0) #endif -static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct hamachi_private *hmp = netdev_priv(dev); unsigned entry; diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index d1b6338..a9a1a99 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -240,9 +240,10 @@ static int hp100_probe1(struct net_device *dev, int ioaddr, u_char bus, static int hp100_open(struct net_device *dev); static int hp100_close(struct net_device *dev); -static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int hp100_start_xmit_bm(struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t hp100_start_xmit(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb, + struct net_device *dev); static void hp100_rx(struct net_device *dev); static struct net_device_stats *hp100_get_stats(struct net_device *dev); static void hp100_misc_interrupt(struct net_device *dev); @@ -1483,7 +1484,8 @@ static int hp100_check_lan(struct net_device *dev) */ /* tx function for busmaster mode */ -static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb, + struct net_device *dev) { unsigned long flags; int i, ok_flag; @@ -1635,7 +1637,8 @@ static void hp100_clean_txring(struct net_device *dev) } /* tx function for slave modes */ -static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hp100_start_xmit(struct sk_buff *skb, + struct net_device *dev) { unsigned long flags; int i, ok_flag; diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 448098d..090a6d3 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -812,7 +812,7 @@ static int ibmlana_close(struct net_device *dev) /* transmit a block. */ -static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ibmlana_tx(struct sk_buff *skb, struct net_device *dev) { ibmlana_priv *priv = netdev_priv(dev); int tmplen, addr; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 76b295a..5862282 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -887,7 +887,8 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) #define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1)) -static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev_priv(netdev); union ibmveth_buf_desc desc; diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 4301946..382c553 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -1858,7 +1858,8 @@ static int ipg_nic_stop(struct net_device *dev) return 0; } -static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ipg_nic_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); void __iomem *ioaddr = sp->ioaddr; diff --git a/drivers/net/jme.c b/drivers/net/jme.c index e7068c7..1d2a325 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -1931,7 +1931,7 @@ jme_stop_queue_if_full(struct jme_adapter *jme) * This function is already protected by netif_tx_lock() */ -static int +static netdev_tx_t jme_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct jme_adapter *jme = netdev_priv(netdev); diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index 39b0aea..6e74aa9 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c @@ -551,7 +551,8 @@ static int ks8842_close(struct net_device *netdev) return 0; } -static int ks8842_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ks8842_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { int ret; struct ks8842_adapter *adapter = netdev_priv(netdev); diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index 9a1dea6..547ac7c 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -868,11 +868,12 @@ static int ks8851_net_stop(struct net_device *dev) * and secondly so we can round up more than one packet to transmit which * means we can try and avoid generating too many transmit done interrupts. */ -static int ks8851_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ks8851_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ks8851_net *ks = netdev_priv(dev); unsigned needed = calc_txlen(skb->len); - int ret = NETDEV_TX_OK; + netdev_tx_t ret = NETDEV_TX_OK; if (netif_msg_tx_queued(ks)) ks_dbg(ks, "%s: skb %p, %d@%p\n", __func__, diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 30fd4f5..dcda303 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -300,7 +300,8 @@ static unsigned char lance_need_isa_bounce_buffers = 1; static int lance_open(struct net_device *dev); static void lance_init_ring(struct net_device *dev, gfp_t mode); -static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int lance_rx(struct net_device *dev); static irqreturn_t lance_interrupt(int irq, void *dev_id); static int lance_close(struct net_device *dev); @@ -949,7 +950,8 @@ static void lance_tx_timeout (struct net_device *dev) } -static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct lance_private *lp = dev->ml_priv; int ioaddr = dev->base_addr; diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index d6be360..2561198 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -299,7 +299,8 @@ static void __ei_tx_timeout(struct net_device *dev) * Sends a packet to an 8390 network device. */ -static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t __ei_start_xmit(struct sk_buff *skb, + struct net_device *dev) { unsigned long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 51bbce7..1bc654a 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -69,7 +69,8 @@ struct pcpu_lstats { * The higher levels take care of making this non-reentrant (it's * called with bh's disabled). */ -static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t loopback_xmit(struct sk_buff *skb, + struct net_device *dev) { struct pcpu_lstats *pcpu_lstats, *lb_stats; int len; diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index c292bad..cc3ed9c 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -377,7 +377,7 @@ static char init_setup[14] = { }; static int i596_open(struct net_device *dev); -static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t i596_interrupt(int irq, void *dev_id); static int i596_close(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); @@ -863,7 +863,7 @@ static int i596_open(struct net_device *dev) return 0; /* Always succeed */ } -static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { +static netdev_tx_t i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { struct tx_cmd *tx_cmd; short length; diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 0ecc1e1..d3d6e99 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -588,7 +588,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb) return skb_tx_hash(dev, skb); } -int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 4513fb4..4376147 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -518,7 +518,7 @@ int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); void mlx4_en_poll_tx_cq(unsigned long data); void mlx4_en_tx_irq(struct mlx4_cq *mcq); u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb); -int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, u32 size, u16 stride); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 75deef3..6930c87 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -360,7 +360,8 @@ MODULE_PARM_DESC(myri10ge_dca, "Enable DCA if possible"); #define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8) static void myri10ge_set_multicast_list(struct net_device *dev); -static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t myri10ge_sw_tso(struct sk_buff *skb, + struct net_device *dev); static inline void put_be32(__be32 val, __be32 __iomem * p) { @@ -2656,7 +2657,8 @@ myri10ge_submit_req(struct myri10ge_tx_buf *tx, struct mcp_kreq_ether_send *src, * it and try again. */ -static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t myri10ge_xmit(struct sk_buff *skb, + struct net_device *dev) { struct myri10ge_priv *mgp = netdev_priv(dev); struct myri10ge_slice_state *ss; @@ -2947,12 +2949,13 @@ drop: } -static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t myri10ge_sw_tso(struct sk_buff *skb, + struct net_device *dev) { struct sk_buff *segs, *curr; struct myri10ge_priv *mgp = netdev_priv(dev); struct myri10ge_slice_state *ss; - int status; + netdev_tx_t status; segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6); if (IS_ERR(segs)) diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 32db12a2..bd41351 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -621,7 +621,7 @@ static void drain_ring(struct net_device *dev); static void free_ring(struct net_device *dev); static void reinit_ring(struct net_device *dev); static void init_registers(struct net_device *dev); -static int start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int natsemi_poll(struct napi_struct *napi, int budget); @@ -2079,7 +2079,7 @@ static void reinit_ring(struct net_device *dev) reinit_rx(dev); } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index fab51d1..f824a39 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -63,7 +63,8 @@ static int __devinit netxen_nic_probe(struct pci_dev *pdev, static void __devexit netxen_nic_remove(struct pci_dev *pdev); static int netxen_nic_open(struct net_device *netdev); static int netxen_nic_close(struct net_device *netdev); -static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); +static netdev_tx_t netxen_nic_xmit_frame(struct sk_buff *, + struct net_device *); static void netxen_tx_timeout(struct net_device *netdev); static void netxen_reset_task(struct work_struct *work); static void netxen_watchdog(unsigned long); @@ -1599,7 +1600,7 @@ netxen_clear_cmddesc(u64 *desc) desc[2] = 0ULL; } -static int +static netdev_tx_t netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index a0ac5d4..bd0ac69 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -170,7 +170,7 @@ static int ni52_probe1(struct net_device *dev, int ioaddr); static irqreturn_t ni52_interrupt(int irq, void *dev_id); static int ni52_open(struct net_device *dev); static int ni52_close(struct net_device *dev); -static int ni52_send_packet(struct sk_buff *, struct net_device *); +static netdev_tx_t ni52_send_packet(struct sk_buff *, struct net_device *); static struct net_device_stats *ni52_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void ni52_timeout(struct net_device *dev); @@ -1173,7 +1173,8 @@ static void ni52_timeout(struct net_device *dev) * send frame */ -static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ni52_send_packet(struct sk_buff *skb, + struct net_device *dev) { int len, i; #ifndef NO_NOPCOMMANDS diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 81a0617..752c2e4 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -252,7 +252,8 @@ static void ni65_xmit_intr(struct net_device *dev,int); static int ni65_open(struct net_device *dev); static int ni65_lance_reinit(struct net_device *dev); static void ni65_init_lance(struct priv *p,unsigned char*,int,int); -static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ni65_send_packet(struct sk_buff *skb, + struct net_device *dev); static void ni65_timeout(struct net_device *dev); static int ni65_close(struct net_device *dev); static int ni65_alloc_buffer(struct net_device *dev); @@ -1157,7 +1158,8 @@ static void ni65_timeout(struct net_device *dev) * Send a packet */ -static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ni65_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct priv *p = dev->ml_priv; diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 3ada7ea..119fd4e 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6657,7 +6657,8 @@ static u64 niu_compute_tx_flags(struct sk_buff *skb, struct ethhdr *ehdr, return ret; } -static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t niu_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct niu *np = netdev_priv(dev); unsigned long align, headroom; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 1576ac0..c594e19 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1077,7 +1077,8 @@ static void ns83820_cleanup_tx(struct ns83820 *dev) * while trying to track down a bug in either the zero copy code or * the tx fifo (hence the MAX_FRAG_LEN). */ -static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t ns83820_hard_start_xmit(struct sk_buff *skb, + struct net_device *ndev) { struct ns83820 *dev = PRIV(ndev); u32 free_idx, cmdsts, extsts; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 6859442..6d28b18 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -303,7 +303,8 @@ static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); static int pcnet32_probe1(unsigned long, int, struct pci_dev *); static int pcnet32_open(struct net_device *); static int pcnet32_init_ring(struct net_device *); -static int pcnet32_start_xmit(struct sk_buff *, struct net_device *); +static netdev_tx_t pcnet32_start_xmit(struct sk_buff *, + struct net_device *); static void pcnet32_tx_timeout(struct net_device *dev); static irqreturn_t pcnet32_interrupt(int, void *); static int pcnet32_close(struct net_device *); @@ -2481,7 +2482,8 @@ static void pcnet32_tx_timeout(struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); } -static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct pcnet32_private *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 3e4b67a..4c61051 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2572,7 +2572,8 @@ map_error: * The IOCB is always the top of the chain followed by one or more * OALs (when necessary). */ -static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t ql3xxx_send(struct sk_buff *skb, + struct net_device *ndev) { struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 8dd266b..2205292 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2103,7 +2103,7 @@ static void ql_hw_csum_setup(struct sk_buff *skb, iph->daddr, len, iph->protocol, 0); } -static int qlge_send(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev) { struct tx_ring_desc *tx_ring_desc; struct ob_mac_iocb_req *mac_iocb_ptr; diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 8068a07..7dfcb58 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -883,13 +883,13 @@ static int r6040_open(struct net_device *dev) return 0; } -static int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t r6040_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); struct r6040_descriptor *descptr; void __iomem *ioaddr = lp->base; unsigned long flags; - int ret = NETDEV_TX_OK; /* Critical Section */ spin_lock_irqsave(&lp->lock, flags); @@ -899,8 +899,7 @@ static int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); netif_stop_queue(dev); printk(KERN_ERR DRV_NAME ": no tx descriptor\n"); - ret = NETDEV_TX_BUSY; - return ret; + return NETDEV_TX_BUSY; } /* Statistic Counter */ @@ -928,7 +927,8 @@ static int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&lp->lock, flags); - return ret; + + return NETDEV_TX_OK; } static void r6040_multicast_list(struct net_device *dev) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 8cd8530..ec0092af 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -507,7 +507,8 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(RTL8169_VERSION); static int rtl8169_open(struct net_device *dev); -static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance); static int rtl8169_init_ring(struct net_device *dev); static void rtl_hw_start(struct net_device *dev); @@ -3357,7 +3358,8 @@ static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev) return 0; } -static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); unsigned int frags, entry = tp->cur_tx % NUM_TX_DESC; @@ -3366,7 +3368,6 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) dma_addr_t mapping; u32 status, len; u32 opts1; - int ret = NETDEV_TX_OK; if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) { if (netif_msg_drv(tp)) { @@ -3418,13 +3419,12 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) } out: - return ret; + return NETDEV_TX_OK; err_stop: netif_stop_queue(dev); - ret = NETDEV_TX_BUSY; dev->stats.tx_dropped++; - goto out; + return NETDEV_TX_BUSY; } static void rtl8169_pcierr_interrupt(struct net_device *dev) diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index d955346..20a7174 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1401,7 +1401,8 @@ static int rr_close(struct net_device *dev) } -static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t rr_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct rr_private *rrpriv = netdev_priv(dev); struct rr_regs __iomem *regs = rrpriv->regs; diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h index 6173f11..2816904 100644 --- a/drivers/net/rrunner.h +++ b/drivers/net/rrunner.h @@ -831,7 +831,8 @@ static int rr_init1(struct net_device *dev); static irqreturn_t rr_interrupt(int irq, void *dev_id); static int rr_open(struct net_device *dev); -static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t rr_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int rr_close(struct net_device *dev); static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static unsigned int rr_read_eeprom(struct rr_private *rrpriv, diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 3138df5..ddccf5f 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -4072,7 +4072,7 @@ static int s2io_close(struct net_device *dev) * 0 on success & 1 on failure. */ -static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off; diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 6a81aec..ee366c5 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -82,7 +82,8 @@ struct sb1000_private { extern int sb1000_probe(struct net_device *dev); static int sb1000_open(struct net_device *dev); static int sb1000_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); -static int sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t sb1000_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t sb1000_interrupt(int irq, void *dev_id); static int sb1000_close(struct net_device *dev); @@ -1080,7 +1081,7 @@ static int sb1000_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } /* transmit function: do nothing since SB1000 can't send anything out */ -static int +static netdev_tx_t sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev) { printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name); diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index e3156c9..8d60300 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -941,7 +941,8 @@ static struct net_device_stats *sc92031_get_stats(struct net_device *dev) return &dev->stats; } -static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sc92031_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct sc92031_priv *priv = netdev_priv(dev); void __iomem *port_base = priv->port_base; diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 7cc8bb8..39246d4 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -81,7 +81,8 @@ struct net_local { static int seeq8005_probe1(struct net_device *dev, int ioaddr); static int seeq8005_open(struct net_device *dev); static void seeq8005_timeout(struct net_device *dev); -static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t seeq8005_interrupt(int irq, void *dev_id); static void seeq8005_rx(struct net_device *dev); static int seeq8005_close(struct net_device *dev); @@ -394,7 +395,8 @@ static void seeq8005_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb, + struct net_device *dev) { short length = skb->len; unsigned char *buf; diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index da157aa..aecaf62 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -20,8 +20,9 @@ #define FALCON_B_P_DEVID 0x0710 /* TX */ -extern int efx_xmit(struct efx_nic *efx, - struct efx_tx_queue *tx_queue, struct sk_buff *skb); +extern netdev_tx_t efx_xmit(struct efx_nic *efx, + struct efx_tx_queue *tx_queue, + struct sk_buff *skb); extern void efx_stop_queue(struct efx_nic *efx); extern void efx_wake_queue(struct efx_nic *efx); diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index b67ccca..817c7ef 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -400,7 +400,8 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) struct efx_loopback_state *state = efx->loopback_selftest; struct efx_loopback_payload *payload; struct sk_buff *skb; - int i, rc; + int i; + netdev_tx_t rc; /* Transmit N copies of buffer */ for (i = 0; i < state->packet_count; i++) { diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 14a1478..489c4de 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -138,8 +138,8 @@ static void efx_tsoh_free(struct efx_tx_queue *tx_queue, * Returns NETDEV_TX_OK or NETDEV_TX_BUSY * You must hold netif_tx_lock() to call this function. */ -static int efx_enqueue_skb(struct efx_tx_queue *tx_queue, - struct sk_buff *skb) +static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, + struct sk_buff *skb) { struct efx_nic *efx = tx_queue->efx; struct pci_dev *pci_dev = efx->pci_dev; @@ -152,7 +152,7 @@ static int efx_enqueue_skb(struct efx_tx_queue *tx_queue, unsigned int dma_len; bool unmap_single; int q_space, i = 0; - int rc = NETDEV_TX_OK; + netdev_tx_t rc = NETDEV_TX_OK; EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count); @@ -353,14 +353,11 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, * * Context: netif_tx_lock held */ -inline int efx_xmit(struct efx_nic *efx, - struct efx_tx_queue *tx_queue, struct sk_buff *skb) +inline netdev_tx_t efx_xmit(struct efx_nic *efx, + struct efx_tx_queue *tx_queue, struct sk_buff *skb) { - int rc; - /* Map fragments for DMA and add to TX queue */ - rc = efx_enqueue_skb(tx_queue, skb); - return rc; + return efx_enqueue_skb(tx_queue, skb); } /* Initiate a packet transmission. We use one channel per CPU @@ -372,7 +369,8 @@ inline int efx_xmit(struct efx_nic *efx, * Note that returning anything other than NETDEV_TX_OK will cause the * OS to free the skb. */ -int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) +netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, + struct net_device *net_dev) { struct efx_nic *efx = netdev_priv(net_dev); struct efx_tx_queue *tx_queue; diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h index 5e1cc23..e367896 100644 --- a/drivers/net/sfc/tx.h +++ b/drivers/net/sfc/tx.h @@ -18,7 +18,8 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); void efx_init_tx_queue(struct efx_tx_queue *tx_queue); void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); -int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); +netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, + struct net_device *net_dev); void efx_release_tx_buffers(struct efx_tx_queue *tx_queue); #endif /* EFX_TX_H */ diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 1f040e8..7cc9898 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1168,7 +1168,8 @@ static int sis190_close(struct net_device *dev) return 0; } -static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sis190_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct sis190_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 61ceeaa..d882732 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -214,7 +214,8 @@ static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_p static void sis900_tx_timeout(struct net_device *net_dev); static void sis900_init_tx_ring(struct net_device *net_dev); static void sis900_init_rx_ring(struct net_device *net_dev); -static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev); +static netdev_tx_t sis900_start_xmit(struct sk_buff *skb, + struct net_device *net_dev); static int sis900_rx(struct net_device *net_dev); static void sis900_finish_xmit (struct net_device *net_dev); static irqreturn_t sis900_interrupt(int irq, void *dev_instance); @@ -1571,7 +1572,7 @@ static void sis900_tx_timeout(struct net_device *net_dev) * tell upper layer if the buffer is full */ -static int +static netdev_tx_t sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) { struct sis900_private *sis_priv = netdev_priv(net_dev); diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 888a14a..38a508b 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -107,7 +107,8 @@ static void skfp_ctl_set_multicast_list(struct net_device *dev); static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev); static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr); static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t skfp_send_pkt(struct sk_buff *skb, + struct net_device *dev); static void send_queued_packets(struct s_smc *smc); static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr); static void ResetAdapter(struct s_smc *smc); @@ -1056,7 +1057,8 @@ static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) * Side Effects: * None */ -static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t skfp_send_pkt(struct sk_buff *skb, + struct net_device *dev) { struct s_smc *smc = netdev_priv(dev); skfddi_priv *bp = &smc->os; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 543af20..1a1e685 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2746,7 +2746,8 @@ static inline int skge_avail(const struct skge_ring *ring) + (ring->to_clean - ring->to_use) - 1; } -static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, + struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index dd630cf..c7c0a5b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1574,7 +1574,8 @@ static void sky2_tx_unmap(struct pci_dev *pdev, * the number of ring elements will probably be less than the number * of list elements used. */ -static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb, + struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 0a1b6f4..934a120 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -299,7 +299,8 @@ static void smc_hardware_send_packet( struct net_device * dev ); . to store the packet, I call this routine, which either sends it . now, or generates an interrupt when the card is ready for the . packet */ -static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev ); +static netdev_tx_t smc_wait_to_send_packet( struct sk_buff * skb, + struct net_device *dev ); /* this does a soft reset on the device */ static void smc_reset( int ioaddr ); @@ -487,7 +488,8 @@ static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs . o (NO): Enable interrupts and let the interrupt handler deal with it. . o (YES):Send it now. */ -static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ) +static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index 60abdb1..514311d 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -968,7 +968,8 @@ static void smsc9420_complete_tx(struct net_device *dev) } } -static int smsc9420_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smsc9420_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct smsc9420_pdata *pd = netdev_priv(dev); dma_addr_t mapping; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 5e7645e..a36e2b5 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -595,7 +595,7 @@ static int netdev_open(struct net_device *dev); static void check_duplex(struct net_device *dev); static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); -static int start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int __netdev_rx(struct net_device *dev, int *quota); @@ -1223,7 +1223,7 @@ static void init_ring(struct net_device *dev) } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); unsigned int entry; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index d09be48..e13685a 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -415,7 +415,7 @@ static void check_duplex(struct net_device *dev); static void netdev_timer(unsigned long data); static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); -static int start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); static int reset_tx (struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void rx_poll(unsigned long data); @@ -1053,7 +1053,7 @@ static void tx_poll (unsigned long data) return; } -static int +static netdev_tx_t start_tx (struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index d2dfe0a..e0dfdd2 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -1015,7 +1015,8 @@ static __inline__ int gem_intme(int entry) return 0; } -static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t gem_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct gem *gp = netdev_priv(dev); int entry; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 008bd59..37d721b 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2252,7 +2252,8 @@ static void happy_meal_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct happy_meal *hp = netdev_priv(dev); int entry; diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 3c2679c..918d4c9 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -1622,7 +1622,8 @@ static inline int bdx_tx_space(struct bdx_priv *priv) * the driver. Note: the driver must NOT put the skb in its DMA ring. * o NETDEV_TX_LOCKED Locking failed, please retry quickly. */ -static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t bdx_tx_transmit(struct sk_buff *skb, + struct net_device *ndev) { struct bdx_priv *priv = netdev_priv(ndev); struct txd_fifo *f = &priv->txd_fifo0; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a7d14aa..9d5c178 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5135,7 +5135,8 @@ static void tg3_set_txd(struct tg3_napi *tnapi, int entry, /* hard_start_xmit for devices that don't have any bugs and * support TG3_FLG2_HW_TSO_2 only. */ -static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); u32 len, entry, base_flags, mss; @@ -5251,7 +5252,8 @@ out_unlock: return NETDEV_TX_OK; } -static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *); +static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *, + struct net_device *); /* Use GSO to workaround a rare TSO bug that may be triggered when the * TSO header is greater than 80 bytes. @@ -5290,7 +5292,8 @@ tg3_tso_bug_end: /* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and * support TG3_FLG2_HW_TSO_1 or firmware TSO only. */ -static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, + struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); u32 len, entry, base_flags, mss; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 70c9ec4..49e273b 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -289,7 +289,7 @@ static void TLan_EisaProbe( void ); static void TLan_Eisa_Cleanup( void ); static int TLan_Init( struct net_device * ); static int TLan_Open( struct net_device *dev ); -static int TLan_StartTx( struct sk_buff *, struct net_device *); +static netdev_tx_t TLan_StartTx( struct sk_buff *, struct net_device *); static irqreturn_t TLan_HandleInterrupt( int, void *); static int TLan_Close( struct net_device *); static struct net_device_stats *TLan_GetStats( struct net_device *); @@ -1083,7 +1083,7 @@ static void TLan_tx_timeout_work(struct work_struct *work) * **************************************************************/ -static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) +static netdev_tx_t TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) { TLanPrivateInfo *priv = netdev_priv(dev); dma_addr_t tail_list_phys; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 2c26b45..d6d3452 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -762,7 +762,7 @@ typhoon_tso_fill(struct sk_buff *skb, struct transmit_ring *txRing, tcpd->status = 0; } -static int +static netdev_tx_t typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) { struct typhoon *tp = netdev_priv(dev); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 46eb618..081402c 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -408,7 +408,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int rhine_open(struct net_device *dev); static void rhine_tx_timeout(struct net_device *dev); -static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t rhine_start_tx(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t rhine_interrupt(int irq, void *dev_instance); static void rhine_tx(struct net_device *dev); static int rhine_rx(struct net_device *dev, int limit); @@ -1213,7 +1214,8 @@ static void rhine_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t rhine_start_tx(struct sk_buff *skb, + struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 47be41a..e56cf6b 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2465,7 +2465,8 @@ static int velocity_close(struct net_device *dev) * Called by the networ layer to request a packet is queued to * the velocity. Returns zero on success. */ -static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t velocity_xmit(struct sk_buff *skb, + struct net_device *dev) { struct velocity_info *vptr = netdev_priv(dev); int qnum = 0; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 094d155..41dccba 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -812,7 +812,7 @@ static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header) * NOTE: when device cant queue the pkt, just the trans_start variable will * not be upadted. */ -static int +static netdev_tx_t vxge_xmit(struct sk_buff *skb, struct net_device *dev) { struct vxge_fifo *fifo = NULL; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 7676423..9509477 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -347,7 +347,8 @@ static int yellowfin_open(struct net_device *dev); static void yellowfin_timer(unsigned long data); static void yellowfin_tx_timeout(struct net_device *dev); static void yellowfin_init_ring(struct net_device *dev); -static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance); static int yellowfin_rx(struct net_device *dev); static void yellowfin_error(struct net_device *dev, int intr_status); @@ -808,7 +809,8 @@ static void yellowfin_init_ring(struct net_device *dev) return; } -static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct yellowfin_private *yp = netdev_priv(dev); unsigned entry; diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 7f9e141..a0384b6 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -156,7 +156,8 @@ struct netidblk { }; static int znet_open(struct net_device *dev); -static int znet_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t znet_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t znet_interrupt(int irq, void *dev_id); static void znet_rx(struct net_device *dev); static int znet_close(struct net_device *dev); @@ -534,7 +535,7 @@ static void znet_tx_timeout (struct net_device *dev) netif_wake_queue (dev); } -static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev) { int ioaddr = dev->base_addr; struct znet_private *znet = netdev_priv(dev); diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index cd4bcb6..7d650a0 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -337,7 +337,8 @@ struct net_device *alloc_arcdev(const char *name); int arcnet_open(struct net_device *dev); int arcnet_close(struct net_device *dev); -int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t arcnet_send_packet(struct sk_buff *skb, + struct net_device *dev); void arcnet_timeout(struct net_device *dev); #endif /* __KERNEL__ */ -- cgit v0.10.2 From cb45439977d3602b91dd0aca2d94fa3b32aebba6 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 31 Aug 2009 12:31:36 +0000 Subject: net: Add ndo_fcoe_enable/ndo_fcoe_disable to net_device_ops Add ndo_fcoe_enable/_disable to net_device_ops so the corresponding HW can initialize itself for FCoE traffic or clean up after FCoE traffic is done. This is expected to be called by the kernel FCoE stack upon receiving a request for creating an FCoE instance on the corresponding netdev interface. When implemented by the actual HW, the HW driver check the op code to perform corresponding initialization or clean up for FCoE. The initialization normally includes allocating extra queues for FCoE, setting corresponding HW registers for FCoE, indicating FCoE offload features via netdev, etc. The clean-up would include releasing the resources allocated for FCoE. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 376a2e1..121cbad 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -627,6 +627,8 @@ struct net_device_ops { void (*ndo_poll_controller)(struct net_device *dev); #endif #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) + int (*ndo_fcoe_enable)(struct net_device *dev); + int (*ndo_fcoe_disable)(struct net_device *dev); int (*ndo_fcoe_ddp_setup)(struct net_device *dev, u16 xid, struct scatterlist *sgl, -- cgit v0.10.2 From 0af46d997fcbfd25a9e166c2431bfebc03720a36 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 31 Aug 2009 12:31:55 +0000 Subject: vlan: Add support for net_devices_ops.ndo_fcoe_enable/_disable to VLAN This adds implementation of the net_devices_ops.ndo_fcoe_enable/_disable to the VLAN driver. It checks if the real_dev has support for ndo_fcoe_enable/ ndo_fcoe_disable and if so, passes on to call the associated real_dev. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 84a2be4..53f84c7 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -587,6 +587,28 @@ static int vlan_dev_fcoe_ddp_done(struct net_device *dev, u16 xid) return len; } + +static int vlan_dev_fcoe_enable(struct net_device *dev) +{ + struct net_device *real_dev = vlan_dev_info(dev)->real_dev; + const struct net_device_ops *ops = real_dev->netdev_ops; + int rc = -EINVAL; + + if (ops->ndo_fcoe_enable) + rc = ops->ndo_fcoe_enable(real_dev); + return rc; +} + +static int vlan_dev_fcoe_disable(struct net_device *dev) +{ + struct net_device *real_dev = vlan_dev_info(dev)->real_dev; + const struct net_device_ops *ops = real_dev->netdev_ops; + int rc = -EINVAL; + + if (ops->ndo_fcoe_disable) + rc = ops->ndo_fcoe_disable(real_dev); + return rc; +} #endif static void vlan_dev_change_rx_flags(struct net_device *dev, int change) @@ -750,6 +772,8 @@ static const struct net_device_ops vlan_netdev_ops = { #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, + .ndo_fcoe_enable = vlan_dev_fcoe_enable, + .ndo_fcoe_disable = vlan_dev_fcoe_disable, #endif }; @@ -770,6 +794,8 @@ static const struct net_device_ops vlan_netdev_accel_ops = { #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, + .ndo_fcoe_enable = vlan_dev_fcoe_enable, + .ndo_fcoe_disable = vlan_dev_fcoe_disable, #endif }; -- cgit v0.10.2 From 8450ff8cd7fba6e78c07d7c14bf4dc582f8a6c3d Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 31 Aug 2009 12:32:14 +0000 Subject: ixgbe: Add support for the net_device_ops.ndo_fcoe_enable/disable to 82599 This adds support to the net_device_ops.ndo_fcoe_enable/disable for 82599. This consequently allows us to dynamically turn FCoE offload feature on or off upon incoming calls to ndo_fcoe_enable/disable. When this happens, FCoE offload features are enabled/disabled accordingly, and this is regardless of whether DCB being turned on or not. Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index c983c89..daed0ac 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -450,6 +450,8 @@ extern int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, extern int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, struct scatterlist *sgl, unsigned int sgc); extern int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid); +extern int ixgbe_fcoe_enable(struct net_device *netdev); +extern int ixgbe_fcoe_disable(struct net_device *netdev); #endif /* IXGBE_FCOE */ #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 34bca45..e05c62a 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -139,23 +139,6 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; } adapter->flags |= IXGBE_FLAG_DCB_ENABLED; -#ifdef IXGBE_FCOE - /* Turn on FCoE offload */ - if ((adapter->flags & IXGBE_FLAG_FCOE_CAPABLE) && - (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))) { - adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; - adapter->ring_feature[RING_F_FCOE].indices = - IXGBE_FCRETA_SIZE; - netdev->features |= NETIF_F_FCOE_CRC; - netdev->features |= NETIF_F_FSO; - netdev->features |= NETIF_F_FCOE_MTU; - netdev->vlan_features |= NETIF_F_FCOE_CRC; - netdev->vlan_features |= NETIF_F_FSO; - netdev->vlan_features |= NETIF_F_FCOE_MTU; - netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; - netdev_features_change(netdev); - } -#endif /* IXGBE_FCOE */ ixgbe_init_interrupt_scheme(adapter); if (netif_running(netdev)) netdev->netdev_ops->ndo_open(netdev); @@ -174,22 +157,6 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) if (adapter->hw.mac.type == ixgbe_mac_82599EB) adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE; -#ifdef IXGBE_FCOE - /* Turn off FCoE offload */ - if (adapter->flags & (IXGBE_FLAG_FCOE_CAPABLE | - IXGBE_FLAG_FCOE_ENABLED)) { - adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; - adapter->ring_feature[RING_F_FCOE].indices = 0; - netdev->features &= ~NETIF_F_FCOE_CRC; - netdev->features &= ~NETIF_F_FSO; - netdev->features &= ~NETIF_F_FCOE_MTU; - netdev->vlan_features &= ~NETIF_F_FCOE_CRC; - netdev->vlan_features &= ~NETIF_F_FSO; - netdev->vlan_features &= ~NETIF_F_FCOE_MTU; - netdev->fcoe_ddp_xid = 0; - netdev_features_change(netdev); - } -#endif /* IXGBE_FCOE */ ixgbe_init_interrupt_scheme(adapter); if (netif_running(netdev)) netdev->netdev_ops->ndo_open(netdev); diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 28cf104..26fe46f 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -554,3 +554,97 @@ void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter) fcoe->pool = NULL; } } + +/** + * ixgbe_fcoe_enable - turn on FCoE offload feature + * @netdev: the corresponding netdev + * + * Turns on FCoE offload feature in 82599. + * + * Returns : 0 indicates success or -EINVAL on failure + */ +int ixgbe_fcoe_enable(struct net_device *netdev) +{ + int rc = -EINVAL; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + + if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) + goto out_enable; + + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + goto out_enable; + + DPRINTK(DRV, INFO, "Enabling FCoE offload features.\n"); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + + ixgbe_clear_interrupt_scheme(adapter); + + adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; + adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE; + netdev->features |= NETIF_F_FCOE_CRC; + netdev->features |= NETIF_F_FSO; + netdev->features |= NETIF_F_FCOE_MTU; + netdev->vlan_features |= NETIF_F_FCOE_CRC; + netdev->vlan_features |= NETIF_F_FSO; + netdev->vlan_features |= NETIF_F_FCOE_MTU; + netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; + netdev_features_change(netdev); + + ixgbe_init_interrupt_scheme(adapter); + + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + rc = 0; + +out_enable: + return rc; +} + +/** + * ixgbe_fcoe_disable - turn off FCoE offload feature + * @netdev: the corresponding netdev + * + * Turns off FCoE offload feature in 82599. + * + * Returns : 0 indicates success or -EINVAL on failure + */ +int ixgbe_fcoe_disable(struct net_device *netdev) +{ + int rc = -EINVAL; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) + goto out_disable; + + if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) + goto out_disable; + + DPRINTK(DRV, INFO, "Disabling FCoE offload features.\n"); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + + ixgbe_clear_interrupt_scheme(adapter); + + adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; + adapter->ring_feature[RING_F_FCOE].indices = 0; + netdev->features &= ~NETIF_F_FCOE_CRC; + netdev->features &= ~NETIF_F_FSO; + netdev->features &= ~NETIF_F_FCOE_MTU; + netdev->vlan_features &= ~NETIF_F_FCOE_CRC; + netdev->vlan_features &= ~NETIF_F_FSO; + netdev->vlan_features &= ~NETIF_F_FCOE_MTU; + netdev->fcoe_ddp_xid = 0; + netdev_features_change(netdev); + + ixgbe_cleanup_fcoe(adapter); + + ixgbe_init_interrupt_scheme(adapter); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + rc = 0; + +out_disable: + return rc; +} diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 7e964a6..30a58fb 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5377,6 +5377,8 @@ static const struct net_device_ops ixgbe_netdev_ops = { #ifdef IXGBE_FCOE .ndo_fcoe_ddp_setup = ixgbe_fcoe_ddp_get, .ndo_fcoe_ddp_done = ixgbe_fcoe_ddp_put, + .ndo_fcoe_enable = ixgbe_fcoe_enable, + .ndo_fcoe_disable = ixgbe_fcoe_disable, #endif /* IXGBE_FCOE */ }; -- cgit v0.10.2 From 0f6f290259896afdca30e1ff4a28aff8edd79a14 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 31 Aug 2009 12:32:34 +0000 Subject: dcbnl: Add support for setapp/getapp commands to dcbnl This patch adds dcbnl command definitions to support setapp/getapp functionality from the IEEE 802.1Qaz Data Center Bridging Capability Exchange protocol (DCBX) specification. Section 3.3 defines the application protocol and its 802.1p user priority in DCBX, which is implemented here as a pair of setapp/getapp commands in the kernel dcbnl for setting and retrieving the user priority for an given application protocol. The protocol is identified by the combination of an id and an idtype. Currently, when idtype is 0, the corresponding id gives the ether type of this protocol, e.g., for FCoE, it will be 0x8906; when idtype is 1, then the corresponding id gives the TCP or UDP port number. For more information regarding DCBX spec., please refer to the following: http://www.ieee802.org/1/files/public/docs2008/ az-wadekar-dcbx-capability-exchange-discovery-protocol-1108-v1.01.pdf Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h index 7d2e100..b7cdbb4 100644 --- a/include/linux/dcbnl.h +++ b/include/linux/dcbnl.h @@ -50,6 +50,8 @@ struct dcbmsg { * @DCB_CMD_SNUMTCS: set the number of traffic classes * @DCB_CMD_GBCN: set backward congestion notification configuration * @DCB_CMD_SBCN: get backward congestion notification configration. + * @DCB_CMD_GAPP: get application protocol configuration + * @DCB_CMD_SAPP: set application protocol configuration */ enum dcbnl_commands { DCB_CMD_UNDEFINED, @@ -80,6 +82,9 @@ enum dcbnl_commands { DCB_CMD_BCN_GCFG, DCB_CMD_BCN_SCFG, + DCB_CMD_GAPP, + DCB_CMD_SAPP, + __DCB_CMD_ENUM_MAX, DCB_CMD_MAX = __DCB_CMD_ENUM_MAX - 1, }; @@ -114,6 +119,7 @@ enum dcbnl_attrs { DCB_ATTR_CAP, DCB_ATTR_NUMTCS, DCB_ATTR_BCN, + DCB_ATTR_APP, __DCB_ATTR_ENUM_MAX, DCB_ATTR_MAX = __DCB_ATTR_ENUM_MAX - 1, @@ -338,5 +344,17 @@ enum dcb_general_attr_values { DCB_ATTR_VALUE_UNDEFINED = 0xff }; +#define DCB_APP_IDTYPE_ETHTYPE 0x00 +#define DCB_APP_IDTYPE_PORTNUM 0x01 +enum dcbnl_app_attrs { + DCB_APP_ATTR_UNDEFINED, + + DCB_APP_ATTR_IDTYPE, + DCB_APP_ATTR_ID, + DCB_APP_ATTR_PRIORITY, + + __DCB_APP_ATTR_ENUM_MAX, + DCB_APP_ATTR_MAX = __DCB_APP_ATTR_ENUM_MAX - 1, +}; #endif /* __LINUX_DCBNL_H__ */ -- cgit v0.10.2 From 7114323b1761bdf787ed79323a4a13f787878295 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 31 Aug 2009 12:32:55 +0000 Subject: dcbnl: Add support for setapp/getapp to netdev dcbnl_rtnl_ops Adds support of dcbnl setapp/getapp to dcbnl_rtnl_ops in netdev to allow LLDs to implement their corresponding dcbnl setapp/getapp ops to support the IEEE 802.1Q DCBX setapp/getapp commands. Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h index 775cfc8..b36ac7e 100644 --- a/include/net/dcbnl.h +++ b/include/net/dcbnl.h @@ -48,6 +48,8 @@ struct dcbnl_rtnl_ops { void (*setbcncfg)(struct net_device *, int, u32); void (*getbcnrp)(struct net_device *, int, u8 *); void (*setbcnrp)(struct net_device *, int, u8); + u8 (*setapp)(struct net_device *, u8, u16, u8); + u8 (*getapp)(struct net_device *, u8, u16); }; #endif /* __NET_DCBNL_H__ */ -- cgit v0.10.2 From 6fa382af61338908e5713234bcee598423f661c3 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 31 Aug 2009 12:33:20 +0000 Subject: dcbnl: Add netlink attributes for setapp/getapp to dcbnl Add defines for dcbnl netlink attributes to support netlink message passing of setapp/getapp in dcbnl. Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 8379496..4046468 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -64,6 +64,7 @@ static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { [DCB_ATTR_CAP] = {.type = NLA_NESTED}, [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, [DCB_ATTR_BCN] = {.type = NLA_NESTED}, + [DCB_ATTR_APP] = {.type = NLA_NESTED}, }; /* DCB priority flow control to User Priority nested attributes */ @@ -158,6 +159,13 @@ static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, }; +/* DCB APP nested attributes. */ +static struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = { + [DCB_APP_ATTR_IDTYPE] = {.type = NLA_U8}, + [DCB_APP_ATTR_ID] = {.type = NLA_U16}, + [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, +}; + /* standard netlink reply call */ static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, u32 seq, u16 flags) -- cgit v0.10.2 From 579496865cf4ea429146382d62047ffdbaab0dee Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 31 Aug 2009 12:33:40 +0000 Subject: dcbnl: Add implementations of dcbnl setapp/getapp commands Implements the dcbnl netlink setapp/getapp pair. When a setapp/getapp is received, dcbnl would just pass on to dcbnl_rtnl_op.setapp/getapp that are supposed to be implemented by the low level drivers. Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 4046468..e0879bf 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -544,6 +544,120 @@ static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb, return ret; } +static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + struct sk_buff *dcbnl_skb; + struct nlmsghdr *nlh; + struct dcbmsg *dcb; + struct nlattr *app_nest; + struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; + u16 id; + u8 up, idtype; + int ret = -EINVAL; + + if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp) + goto out; + + ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], + dcbnl_app_nest); + if (ret) + goto out; + + ret = -EINVAL; + /* all must be non-null */ + if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || + (!app_tb[DCB_APP_ATTR_ID])) + goto out; + + /* either by eth type or by socket number */ + idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); + if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && + (idtype != DCB_APP_IDTYPE_PORTNUM)) + goto out; + + id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); + up = netdev->dcbnl_ops->getapp(netdev, idtype, id); + + /* send this back */ + dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!dcbnl_skb) + goto out; + + nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); + dcb = NLMSG_DATA(nlh); + dcb->dcb_family = AF_UNSPEC; + dcb->cmd = DCB_CMD_GAPP; + + app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP); + ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype); + if (ret) + goto out_cancel; + + ret = nla_put_u16(dcbnl_skb, DCB_APP_ATTR_ID, id); + if (ret) + goto out_cancel; + + ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_PRIORITY, up); + if (ret) + goto out_cancel; + + nla_nest_end(dcbnl_skb, app_nest); + nlmsg_end(dcbnl_skb, nlh); + + ret = rtnl_unicast(dcbnl_skb, &init_net, pid); + if (ret) + goto nlmsg_failure; + + goto out; + +out_cancel: + nla_nest_cancel(dcbnl_skb, app_nest); +nlmsg_failure: + kfree_skb(dcbnl_skb); +out: + return ret; +} + +static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + int ret = -EINVAL; + u16 id; + u8 up, idtype; + struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; + + if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->setapp) + goto out; + + ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], + dcbnl_app_nest); + if (ret) + goto out; + + ret = -EINVAL; + /* all must be non-null */ + if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || + (!app_tb[DCB_APP_ATTR_ID]) || + (!app_tb[DCB_APP_ATTR_PRIORITY])) + goto out; + + /* either by eth type or by socket number */ + idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); + if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && + (idtype != DCB_APP_IDTYPE_PORTNUM)) + goto out; + + id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); + up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); + + ret = dcbnl_reply(netdev->dcbnl_ops->setapp(netdev, idtype, id, up), + RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, + pid, seq, flags); +out: + return ret; +} + static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, u32 pid, u32 seq, u16 flags, int dir) { @@ -1101,6 +1215,14 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq, nlh->nlmsg_flags); goto out; + case DCB_CMD_GAPP: + ret = dcbnl_getapp(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_SAPP: + ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; default: goto errout; } -- cgit v0.10.2 From 6ee1652051f14d1c110f48a5b3ee037d63d0c2fa Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 31 Aug 2009 12:34:28 +0000 Subject: ixgbe: Add support for dcbnl_rtnl_ops.setapp/getapp Add support for dcbnl_rtnl_ops.setapp/getapp to set or get the current user priority bitmap for the given application protocol. Currently, 82599 only supports setapp/getapp for Fiber Channel over Ethernet (FCoE) protocol. Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index daed0ac..dd688d4 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -452,6 +452,10 @@ extern int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, extern int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid); extern int ixgbe_fcoe_enable(struct net_device *netdev); extern int ixgbe_fcoe_disable(struct net_device *netdev); +#ifdef CONFIG_IXGBE_DCB +extern u8 ixgbe_fcoe_getapp(struct ixgbe_adapter *adapter); +extern u8 ixgbe_fcoe_setapp(struct ixgbe_adapter *adapter, u8 up); +#endif /* CONFIG_IXGBE_DCB */ #endif /* IXGBE_FCOE */ #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index e05c62a..47d9dde 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -480,6 +480,64 @@ static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state) return; } +/** + * ixgbe_dcbnl_getapp - retrieve the DCBX application user priority + * @netdev : the corresponding netdev + * @idtype : identifies the id as ether type or TCP/UDP port number + * @id: id is either ether type or TCP/UDP port number + * + * Returns : on success, returns a non-zero 802.1p user priority bitmap + * otherwise returns 0 as the invalid user priority bitmap to indicate an + * error. + */ +static u8 ixgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) +{ + u8 rval = 0; + + switch (idtype) { + case DCB_APP_IDTYPE_ETHTYPE: +#ifdef IXGBE_FCOE + if (id == ETH_P_FCOE) + rval = ixgbe_fcoe_getapp(netdev_priv(netdev)); +#endif + break; + case DCB_APP_IDTYPE_PORTNUM: + break; + default: + break; + } + return rval; +} + +/** + * ixgbe_dcbnl_setapp - set the DCBX application user priority + * @netdev : the corresponding netdev + * @idtype : identifies the id as ether type or TCP/UDP port number + * @id: id is either ether type or TCP/UDP port number + * @up: the 802.1p user priority bitmap + * + * Returns : 0 on success or 1 on error + */ +static u8 ixgbe_dcbnl_setapp(struct net_device *netdev, + u8 idtype, u16 id, u8 up) +{ + u8 rval = 1; + + switch (idtype) { + case DCB_APP_IDTYPE_ETHTYPE: +#ifdef IXGBE_FCOE + if (id == ETH_P_FCOE) + rval = ixgbe_fcoe_setapp(netdev_priv(netdev), up); +#endif + break; + case DCB_APP_IDTYPE_PORTNUM: + break; + default: + break; + } + return rval; +} + struct dcbnl_rtnl_ops dcbnl_ops = { .getstate = ixgbe_dcbnl_get_state, .setstate = ixgbe_dcbnl_set_state, @@ -500,5 +558,7 @@ struct dcbnl_rtnl_ops dcbnl_ops = { .setnumtcs = ixgbe_dcbnl_setnumtcs, .getpfcstate = ixgbe_dcbnl_getpfcstate, .setpfcstate = ixgbe_dcbnl_setpfcstate, + .getapp = ixgbe_dcbnl_getapp, + .setapp = ixgbe_dcbnl_setapp, }; diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 26fe46f..0607cff 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -27,6 +27,9 @@ #include "ixgbe.h" +#ifdef CONFIG_IXGBE_DCB +#include "ixgbe_dcb_82599.h" +#endif /* CONFIG_IXGBE_DCB */ #include #include #include @@ -648,3 +651,64 @@ int ixgbe_fcoe_disable(struct net_device *netdev) out_disable: return rc; } + +#ifdef CONFIG_IXGBE_DCB +/** + * ixgbe_fcoe_getapp - retrieves current user priority bitmap for FCoE + * @adapter : ixgbe adapter + * + * Finds out the corresponding user priority bitmap from the current + * traffic class that FCoE belongs to. Returns 0 as the invalid user + * priority bitmap to indicate an error. + * + * Returns : 802.1p user priority bitmap for FCoE + */ +u8 ixgbe_fcoe_getapp(struct ixgbe_adapter *adapter) +{ + int i; + u8 tc; + u32 up2tc; + + up2tc = IXGBE_READ_REG(&adapter->hw, IXGBE_RTTUP2TC); + for (i = 0; i < MAX_USER_PRIORITY; i++) { + tc = (u8)(up2tc >> (i * IXGBE_RTTUP2TC_UP_SHIFT)); + tc &= (MAX_TRAFFIC_CLASS - 1); + if (adapter->fcoe.tc == tc) + return 1 << i; + } + + return 0; +} + +/** + * ixgbe_fcoe_setapp - sets the user priority bitmap for FCoE + * @adapter : ixgbe adapter + * @up : 802.1p user priority bitmap + * + * Finds out the traffic class from the input user priority + * bitmap for FCoE. + * + * Returns : 0 on success otherwise returns 1 on error + */ +u8 ixgbe_fcoe_setapp(struct ixgbe_adapter *adapter, u8 up) +{ + int i; + u32 up2tc; + + /* valid user priority bitmap must not be 0 */ + if (up) { + /* from user priority to the corresponding traffic class */ + up2tc = IXGBE_READ_REG(&adapter->hw, IXGBE_RTTUP2TC); + for (i = 0; i < MAX_USER_PRIORITY; i++) { + if (up & (1 << i)) { + up2tc >>= (i * IXGBE_RTTUP2TC_UP_SHIFT); + up2tc &= (MAX_TRAFFIC_CLASS - 1); + adapter->fcoe.tc = (u8)up2tc; + return 0; + } + } + } + + return 1; +} +#endif /* CONFIG_IXGBE_DCB */ diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ixgbe/ixgbe_fcoe.h index c5b5002..b5dee7b 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.h +++ b/drivers/net/ixgbe/ixgbe_fcoe.h @@ -46,6 +46,9 @@ #define IXGBE_FCBUFF_MIN 4096 /* 4KB min */ #define IXGBE_FCOE_DDP_MAX 512 /* 9 bits xid */ +/* Default traffic class to use for FCoE */ +#define IXGBE_FCOE_DEFTC 3 + /* fcerr */ #define IXGBE_FCERR_BADCRC 0x00100000 @@ -59,6 +62,7 @@ struct ixgbe_fcoe_ddp { }; struct ixgbe_fcoe { + u8 tc; spinlock_t lock; struct pci_pool *pool; struct ixgbe_fcoe_ddp ddp[IXGBE_FCOE_DDP_MAX]; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 30a58fb..f907836 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3801,6 +3801,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE; adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; adapter->ring_feature[RING_F_FCOE].indices = 0; + /* Default traffic class to use for FCoE */ + adapter->fcoe.tc = IXGBE_FCOE_DEFTC; #endif /* IXGBE_FCOE */ } -- cgit v0.10.2 From 4d1a2d9ec1c17df077ed09a0d135bccf5637a3b7 Mon Sep 17 00:00:00 2001 From: Damian Lukowski Date: Wed, 26 Aug 2009 00:16:27 +0000 Subject: Revert Backoff [v3]: Rename skb to icmp_skb in tcp_v4_err() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This supplementary patch renames skb to icmp_skb in tcp_v4_err() in order to disambiguate from another sk_buff variable, which will be introduced in a separate patch. Signed-off-by: Damian Lukowski Acked-by: Ilpo Järvinen Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 6d88219..6ca1bc8 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -328,26 +328,26 @@ static void do_pmtu_discovery(struct sock *sk, struct iphdr *iph, u32 mtu) * */ -void tcp_v4_err(struct sk_buff *skb, u32 info) +void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) { - struct iphdr *iph = (struct iphdr *)skb->data; - struct tcphdr *th = (struct tcphdr *)(skb->data + (iph->ihl << 2)); + struct iphdr *iph = (struct iphdr *)icmp_skb->data; + struct tcphdr *th = (struct tcphdr *)(icmp_skb->data + (iph->ihl << 2)); struct tcp_sock *tp; struct inet_sock *inet; - const int type = icmp_hdr(skb)->type; - const int code = icmp_hdr(skb)->code; + const int type = icmp_hdr(icmp_skb)->type; + const int code = icmp_hdr(icmp_skb)->code; struct sock *sk; __u32 seq; int err; - struct net *net = dev_net(skb->dev); + struct net *net = dev_net(icmp_skb->dev); - if (skb->len < (iph->ihl << 2) + 8) { + if (icmp_skb->len < (iph->ihl << 2) + 8) { ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); return; } sk = inet_lookup(net, &tcp_hashinfo, iph->daddr, th->dest, - iph->saddr, th->source, inet_iif(skb)); + iph->saddr, th->source, inet_iif(icmp_skb)); if (!sk) { ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); return; -- cgit v0.10.2 From f1ecd5d9e7366609d640ff4040304ea197fbc618 Mon Sep 17 00:00:00 2001 From: Damian Lukowski Date: Wed, 26 Aug 2009 00:16:31 +0000 Subject: Revert Backoff [v3]: Revert RTO on ICMP destination unreachable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here, an ICMP host/network unreachable message, whose payload fits to TCP's SND.UNA, is taken as an indication that the RTO retransmission has not been lost due to congestion, but because of a route failure somewhere along the path. With true congestion, a router won't trigger such a message and the patched TCP will operate as standard TCP. This patch reverts one RTO backoff, if an ICMP host/network unreachable message, whose payload fits to TCP's SND.UNA, arrives. Based on the new RTO, the retransmission timer is reset to reflect the remaining time, or - if the revert clocked out the timer - a retransmission is sent out immediately. Backoffs are only reverted, if TCP is in RTO loss recovery, i.e. if there have been retransmissions and reversible backoffs, already. Changes from v2: 1) Renaming of skb in tcp_v4_err() moved to another patch. 2) Reintroduced tcp_bound_rto() and __tcp_set_rto(). 3) Fixed code comments. Signed-off-by: Damian Lukowski Acked-by: Ilpo Järvinen Signed-off-by: David S. Miller diff --git a/include/net/tcp.h b/include/net/tcp.h index cbb2a48..54f212c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -469,6 +469,7 @@ extern void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, int nonagle); extern int tcp_may_send_now(struct sock *sk); extern int tcp_retransmit_skb(struct sock *, struct sk_buff *); +extern void tcp_retransmit_timer(struct sock *sk); extern void tcp_xmit_retransmit_queue(struct sock *); extern void tcp_simple_retransmit(struct sock *); extern int tcp_trim_head(struct sock *, struct sk_buff *, u32); @@ -521,6 +522,17 @@ extern int tcp_mtu_to_mss(struct sock *sk, int pmtu); extern int tcp_mss_to_mtu(struct sock *sk, int mss); extern void tcp_mtup_init(struct sock *sk); +static inline void tcp_bound_rto(const struct sock *sk) +{ + if (inet_csk(sk)->icsk_rto > TCP_RTO_MAX) + inet_csk(sk)->icsk_rto = TCP_RTO_MAX; +} + +static inline u32 __tcp_set_rto(const struct tcp_sock *tp) +{ + return (tp->srtt >> 3) + tp->rttvar; +} + static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd) { tp->pred_flags = htonl((tp->tcp_header_len << 26) | diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2bdb0da..af6d6fa 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -685,7 +685,7 @@ static inline void tcp_set_rto(struct sock *sk) * is invisible. Actually, Linux-2.4 also generates erratic * ACKs in some circumstances. */ - inet_csk(sk)->icsk_rto = (tp->srtt >> 3) + tp->rttvar; + inet_csk(sk)->icsk_rto = __tcp_set_rto(tp); /* 2. Fixups made earlier cannot be right. * If we do not estimate RTO correctly without them, @@ -696,8 +696,7 @@ static inline void tcp_set_rto(struct sock *sk) /* NOTE: clamping at TCP_RTO_MIN is not required, current algo * guarantees that rto is higher. */ - if (inet_csk(sk)->icsk_rto > TCP_RTO_MAX) - inet_csk(sk)->icsk_rto = TCP_RTO_MAX; + tcp_bound_rto(sk); } /* Save metrics learned by this TCP session. diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 6ca1bc8..6755e29 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -332,12 +332,15 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) { struct iphdr *iph = (struct iphdr *)icmp_skb->data; struct tcphdr *th = (struct tcphdr *)(icmp_skb->data + (iph->ihl << 2)); + struct inet_connection_sock *icsk; struct tcp_sock *tp; struct inet_sock *inet; const int type = icmp_hdr(icmp_skb)->type; const int code = icmp_hdr(icmp_skb)->code; struct sock *sk; + struct sk_buff *skb; __u32 seq; + __u32 remaining; int err; struct net *net = dev_net(icmp_skb->dev); @@ -367,6 +370,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) if (sk->sk_state == TCP_CLOSE) goto out; + icsk = inet_csk(sk); tp = tcp_sk(sk); seq = ntohl(th->seq); if (sk->sk_state != TCP_LISTEN && @@ -393,6 +397,39 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) } err = icmp_err_convert[code].errno; + /* check if icmp_skb allows revert of backoff + * (see draft-zimmermann-tcp-lcd) */ + if (code != ICMP_NET_UNREACH && code != ICMP_HOST_UNREACH) + break; + if (seq != tp->snd_una || !icsk->icsk_retransmits || + !icsk->icsk_backoff) + break; + + icsk->icsk_backoff--; + inet_csk(sk)->icsk_rto = __tcp_set_rto(tp) << + icsk->icsk_backoff; + tcp_bound_rto(sk); + + skb = tcp_write_queue_head(sk); + BUG_ON(!skb); + + remaining = icsk->icsk_rto - min(icsk->icsk_rto, + tcp_time_stamp - TCP_SKB_CB(skb)->when); + + if (remaining) { + inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, + remaining, TCP_RTO_MAX); + } else if (sock_owned_by_user(sk)) { + /* RTO revert clocked out retransmission, + * but socket is locked. Will defer. */ + inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, + HZ/20, TCP_RTO_MAX); + } else { + /* RTO revert clocked out retransmission. + * Will retransmit now */ + tcp_retransmit_timer(sk); + } + break; case ICMP_TIME_EXCEEDED: err = EHOSTUNREACH; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index c520fb6..408fa4b 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -279,7 +279,7 @@ static void tcp_probe_timer(struct sock *sk) * The TCP retransmit timer. */ -static void tcp_retransmit_timer(struct sock *sk) +void tcp_retransmit_timer(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); struct inet_connection_sock *icsk = inet_csk(sk); -- cgit v0.10.2 From 6fa12c85031485dff38ce550c24f10da23b0adaa Mon Sep 17 00:00:00 2001 From: Damian Lukowski Date: Wed, 26 Aug 2009 00:16:34 +0000 Subject: Revert Backoff [v3]: Calculate TCP's connection close threshold as a time value. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RFC 1122 specifies two threshold values R1 and R2 for connection timeouts, which may represent a number of allowed retransmissions or a timeout value. Currently linux uses sysctl_tcp_retries{1,2} to specify the thresholds in number of allowed retransmissions. For any desired threshold R2 (by means of time) one can specify tcp_retries2 (by means of number of retransmissions) such that TCP will not time out earlier than R2. This is the case, because the RTO schedule follows a fixed pattern, namely exponential backoff. However, the RTO behaviour is not predictable any more if RTO backoffs can be reverted, as it is the case in the draft "Make TCP more Robust to Long Connectivity Disruptions" (http://tools.ietf.org/html/draft-zimmermann-tcp-lcd). In the worst case TCP would time out a connection after 3.2 seconds, if the initial RTO equaled MIN_RTO and each backoff has been reverted. This patch introduces a function retransmits_timed_out(N), which calculates the timeout of a TCP connection, assuming an initial RTO of MIN_RTO and N unsuccessful, exponentially backed-off retransmissions. Whenever timeout decisions are made by comparing the retransmission counter to some value N, this function can be used, instead. The meaning of tcp_retries2 will be changed, as many more RTO retransmissions can occur than the value indicates. However, it yields a timeout which is similar to the one of an unpatched, exponentially backing off TCP in the same scenario. As no application could rely on an RTO greater than MIN_RTO, there should be no risk of a regression. Signed-off-by: Damian Lukowski Acked-by: Ilpo Järvinen Signed-off-by: David S. Miller diff --git a/include/net/tcp.h b/include/net/tcp.h index 54f212c..e531949 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1252,6 +1252,24 @@ static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_bu #define tcp_for_write_queue_from_safe(skb, tmp, sk) \ skb_queue_walk_from_safe(&(sk)->sk_write_queue, skb, tmp) +static inline bool retransmits_timed_out(const struct sock *sk, + unsigned int boundary) +{ + int limit, K; + if (!inet_csk(sk)->icsk_retransmits) + return false; + + K = ilog2(TCP_RTO_MAX/TCP_RTO_MIN); + + if (boundary <= K) + limit = ((2 << boundary) - 1) * TCP_RTO_MIN; + else + limit = ((2 << K) - 1) * TCP_RTO_MIN + + (boundary - K) * TCP_RTO_MAX; + + return (tcp_time_stamp - tcp_sk(sk)->retrans_stamp) >= limit; +} + static inline struct sk_buff *tcp_send_head(struct sock *sk) { return sk->sk_send_head; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 408fa4b..cdb2ca7 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -137,13 +137,14 @@ static int tcp_write_timeout(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); int retry_until; + bool do_reset; if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { if (icsk->icsk_retransmits) dst_negative_advice(&sk->sk_dst_cache); retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries; } else { - if (icsk->icsk_retransmits >= sysctl_tcp_retries1) { + if (retransmits_timed_out(sk, sysctl_tcp_retries1)) { /* Black hole detection */ tcp_mtu_probing(icsk, sk); @@ -155,13 +156,15 @@ static int tcp_write_timeout(struct sock *sk) const int alive = (icsk->icsk_rto < TCP_RTO_MAX); retry_until = tcp_orphan_retries(sk, alive); + do_reset = alive || + !retransmits_timed_out(sk, retry_until); - if (tcp_out_of_resources(sk, alive || icsk->icsk_retransmits < retry_until)) + if (tcp_out_of_resources(sk, do_reset)) return 1; } } - if (icsk->icsk_retransmits >= retry_until) { + if (retransmits_timed_out(sk, retry_until)) { /* Has it gone just too far? */ tcp_write_err(sk); return 1; @@ -385,7 +388,7 @@ void tcp_retransmit_timer(struct sock *sk) out_reset_timer: icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX); - if (icsk->icsk_retransmits > sysctl_tcp_retries1) + if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1)) __sk_dst_reset(sk); out:; -- cgit v0.10.2 From acde31dc467797ccae3a55b791a77af446cce018 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 27 Aug 2009 14:29:20 +0100 Subject: kmemleak: Ignore the aperture memory hole on x86_64 This block is allocated with alloc_bootmem() and scanned by kmemleak but the kernel direct mapping may no longer exist. This patch tells kmemleak to ignore this memory hole. The dma32_bootmem_ptr in dma32_reserve_bootmem() is also ignored. Signed-off-by: Catalin Marinas Acked-by: Ingo Molnar diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 676debf..128111d 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -94,6 +95,11 @@ static u32 __init allocate_aperture(void) * code for safe */ p = __alloc_bootmem_nopanic(aper_size, aper_size, 512ULL<<20); + /* + * Kmemleak should not scan this block as it may not be mapped via the + * kernel direct mapping. + */ + kmemleak_ignore(p); if (!p || __pa(p)+aper_size > 0xffffffff) { printk(KERN_ERR "Cannot allocate aperture memory hole (%p,%uK)\n", diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 1a041bc..fa80f60 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -88,6 +89,11 @@ void __init dma32_reserve_bootmem(void) size = roundup(dma32_bootmem_size, align); dma32_bootmem_ptr = __alloc_bootmem_nopanic(size, align, 512ULL<<20); + /* + * Kmemleak should not scan this block as it may not be mapped via the + * kernel direct mapping. + */ + kmemleak_ignore(dma32_bootmem_ptr); if (dma32_bootmem_ptr) dma32_bootmem_size = size; else -- cgit v0.10.2 From dce944dbb2d0046628bcdba882e8edc2c1d93200 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Tue, 1 Sep 2009 12:45:14 +0800 Subject: ASoC: new board driver to connect bfin-5xx with ad1836 codec As discussed, the patch uses the original TDM order without rewriting. For the match between TDM slot number and audio channel number, a new API need be added. Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mark Brown diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 8a4de4d..ac927ff 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -88,6 +88,14 @@ config SND_BF5XX_SOC_AC97 select SND_SOC_AC97_BUS select SND_BF5XX_SOC_SPORT +config SND_BF5XX_SOC_AD1836 + tristate "SoC AD1836 Audio support for BF5xx" + depends on SND_BF5XX_TDM + select SND_BF5XX_SOC_TDM + select SND_SOC_AD1836 + help + Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT. + config SND_BF5XX_SOC_AD1980 tristate "SoC AD1980/1 Audio support for BF5xx" depends on SND_BF5XX_AC97 diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile index f4d7607..87e3042 100644 --- a/sound/soc/blackfin/Makefile +++ b/sound/soc/blackfin/Makefile @@ -16,11 +16,13 @@ obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o # Blackfin Machine Support +snd-ad1836-objs := bf5xx-ad1836.o snd-ad1980-objs := bf5xx-ad1980.o snd-ssm2602-objs := bf5xx-ssm2602.o snd-ad73311-objs := bf5xx-ad73311.o snd-ad1938-objs := bf5xx-ad1938.o +obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c new file mode 100644 index 0000000..cd361e3 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-ad1836.c @@ -0,0 +1,128 @@ +/* + * File: sound/soc/blackfin/bf5xx-ad1836.c + * Author: Barry Song + * + * Created: Aug 4 2009 + * Description: Board driver for ad1836 sound chip + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../codecs/ad1836.h" +#include "bf5xx-sport.h" + +#include "bf5xx-tdm-pcm.h" +#include "bf5xx-tdm.h" + +static struct snd_soc_card bf5xx_ad1836; + +static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + cpu_dai->private_data = sport_handle; + return 0; +} + +static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + int ret = 0; + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops bf5xx_ad1836_ops = { + .startup = bf5xx_ad1836_startup, + .hw_params = bf5xx_ad1836_hw_params, +}; + +static struct snd_soc_dai_link bf5xx_ad1836_dai = { + .name = "ad1836", + .stream_name = "AD1836", + .cpu_dai = &bf5xx_tdm_dai, + .codec_dai = &ad1836_dai, + .ops = &bf5xx_ad1836_ops, +}; + +static struct snd_soc_card bf5xx_ad1836 = { + .name = "bf5xx_ad1836", + .platform = &bf5xx_tdm_soc_platform, + .dai_link = &bf5xx_ad1836_dai, + .num_links = 1, +}; + +static struct snd_soc_device bf5xx_ad1836_snd_devdata = { + .card = &bf5xx_ad1836, + .codec_dev = &soc_codec_dev_ad1836, +}; + +static struct platform_device *bfxx_ad1836_snd_device; + +static int __init bf5xx_ad1836_init(void) +{ + int ret; + + bfxx_ad1836_snd_device = platform_device_alloc("soc-audio", -1); + if (!bfxx_ad1836_snd_device) + return -ENOMEM; + + platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836_snd_devdata); + bf5xx_ad1836_snd_devdata.dev = &bfxx_ad1836_snd_device->dev; + ret = platform_device_add(bfxx_ad1836_snd_device); + + if (ret) + platform_device_put(bfxx_ad1836_snd_device); + + return ret; +} + +static void __exit bf5xx_ad1836_exit(void) +{ + platform_device_unregister(bfxx_ad1836_snd_device); +} + +module_init(bf5xx_ad1836_init); +module_exit(bf5xx_ad1836_exit); + +/* Module information */ +MODULE_AUTHOR("Barry Song"); +MODULE_DESCRIPTION("ALSA SoC AD1836 board driver"); +MODULE_LICENSE("GPL"); + -- cgit v0.10.2 From 5c0d38c9478e79ab7deb1b470dd181d2308a608e Mon Sep 17 00:00:00 2001 From: jassi brar Date: Tue, 1 Sep 2009 11:35:08 +0900 Subject: ASoC: Debugged improper setting of PLL fields in WM8580 driver Bug was caught while trying to use WM8580 as I2S master on SMDK. Symptoms were lesser LRCLK read by CRO(41.02 instead of 44.1 KHz) Solved by referring to WM8580A manual and setting mask value correctly and making the code to not touch 'reserved' bits of PLL4 register. Signed-off-by: Jassi Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index d547347..6bded8c 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -458,12 +458,12 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, return 0; snd_soc_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); - snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff); + snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0x1ff); snd_soc_write(codec, WM8580_PLLA3 + offset, (pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); reg = snd_soc_read(codec, WM8580_PLLA4 + offset); - reg &= ~0x3f; + reg &= ~0x1b; reg |= pll_div.prescale | pll_div.postscale << 1 | pll_div.freqmode << 3; -- cgit v0.10.2 From 8a56df0ae1690f8f42a3c6c4532f4b06f93febea Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 1 Sep 2009 14:34:01 +0200 Subject: netfilter: ebt_ulog: fix checkentry return value Commit 19eda87 (netfilter: change return types of check functions for Ebtables extensions) broke the ebtables ulog module by missing a return value conversion. Signed-off-by: Patrick McHardy diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index 133eeae..ce50688 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c @@ -266,7 +266,7 @@ static bool ebt_ulog_tg_check(const struct xt_tgchk_param *par) if (uloginfo->qthreshold > EBT_ULOG_MAX_QLEN) uloginfo->qthreshold = EBT_ULOG_MAX_QLEN; - return 0; + return true; } static struct xt_target ebt_ulog_tg_reg __read_mostly = { -- cgit v0.10.2 From 8bc11b491b6cad75e737f1d38bb4b261bd95b291 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Aug 2009 18:13:17 +0200 Subject: rfkill: relicense header file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This header file is copied into userspace tools that need not be GPLv2 licensed, make that easier. Signed-off-by: Johannes Berg Acked-by: Alan Jenkins Acked-by: Henrique de Moraes Holschuh Acked-by: Iñaky Pérez-González Acked-by: Ivo van Doorn Acked-by: Jaswinder Singh Rajput Acked-by: Michael Buesch Acked-by: Tomas Winkler Signed-off-by: John W. Linville diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 21ca51b..3392c59 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -6,20 +6,17 @@ * Copyright (C) 2007 Dmitry Torokhov * Copyright 2009 Johannes Berg * - * 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. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * 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. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include -- cgit v0.10.2 From ebb8e1d78c2f8b1737627ec260d7e39c4bd47385 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 1 Sep 2009 17:46:32 +0530 Subject: ath9k: Move generic hw timer intr handler to bottom-half There is no point handling this in hard irq, move it to tasklet. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4fae699..efee193 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -506,6 +506,10 @@ static void ath9k_tasklet(unsigned long data) sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; } + if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + if (status & ATH9K_INT_GENTIMER) + ath_gen_timer_isr(sc->sc_ah); + /* re-enable hardware interrupt */ ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); ath9k_ps_restore(sc); @@ -521,7 +525,8 @@ irqreturn_t ath_isr(int irq, void *dev) ATH9K_INT_TX | \ ATH9K_INT_BMISS | \ ATH9K_INT_CST | \ - ATH9K_INT_TSFOOR) + ATH9K_INT_TSFOOR | \ + ATH9K_INT_GENTIMER) struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; @@ -602,10 +607,6 @@ irqreturn_t ath_isr(int irq, void *dev) sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; } - if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) - if (status & ATH9K_INT_GENTIMER) - ath_gen_timer_isr(ah); - chip_reset: ath_debug_stat_interrupt(sc, status); -- cgit v0.10.2 From 8f43161aa6bd7bfed0905d3de6cc660fd6b9c2bc Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 1 Sep 2009 17:46:33 +0530 Subject: ath9k: Call spin_lock_bh() on btcoex_lock As generic hw timer interrupt handler is moved to tasklet, we no more need to call spin_lock_irqsave(). Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 8fb3567..e8bfb01 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -84,15 +84,14 @@ static void ath_btcoex_period_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *) data; struct ath_btcoex_info *btinfo = &sc->btcoex_info; - unsigned long flags; ath_detect_bt_priority(sc); - spin_lock_irqsave(&btinfo->btcoex_lock, flags); + spin_lock_bh(&btinfo->btcoex_lock); ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); - spin_unlock_irqrestore(&btinfo->btcoex_lock, flags); + spin_unlock_bh(&btinfo->btcoex_lock); if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) { if (btinfo->hw_timer_enabled) @@ -119,18 +118,17 @@ static void ath_btcoex_no_stomp_timer(void *arg) { struct ath_softc *sc = (struct ath_softc *)arg; struct ath_btcoex_info *btinfo = &sc->btcoex_info; - unsigned long flags; DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n"); - spin_lock_irqsave(&btinfo->btcoex_lock, flags); + spin_lock_bh(&btinfo->btcoex_lock); if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); - spin_unlock_irqrestore(&btinfo->btcoex_lock, flags); + spin_unlock_bh(&btinfo->btcoex_lock); } static int ath_init_btcoex_info(struct ath_hw *hw, -- cgit v0.10.2 From 051ae0bf7ff67c0a64485ac3b46a29aeb55a28dc Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 1 Sep 2009 15:32:55 +0300 Subject: rndis_wlan: use bool for on/off switches Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 402d367..dc2804f 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -466,7 +466,7 @@ struct rndis_wlan_private { u32 param_workaround_interval; /* hardware state */ - int radio_on; + bool radio_on; int infra_mode; bool connected; u8 bssid[ETH_ALEN]; @@ -966,8 +966,8 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) } if (ret == 0) { memcpy(&priv->essid, ssid, sizeof(priv->essid)); - priv->radio_on = 1; - devdbg(usbdev, "set_essid: radio_on = 1"); + priv->radio_on = true; + devdbg(usbdev, "set_essid: radio_on = true"); } return ret; @@ -1028,7 +1028,7 @@ static bool is_associated(struct usbnet *usbdev) } -static int disassociate(struct usbnet *usbdev, int reset_ssid) +static int disassociate(struct usbnet *usbdev, bool reset_ssid) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_ssid ssid; @@ -1037,8 +1037,8 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) if (priv->radio_on) { ret = rndis_set_oid(usbdev, OID_802_11_DISASSOCIATE, NULL, 0); if (ret == 0) { - priv->radio_on = 0; - devdbg(usbdev, "disassociate: radio_on = 0"); + priv->radio_on = false; + devdbg(usbdev, "disassociate: radio_on = false"); if (reset_ssid) msleep(100); @@ -1234,7 +1234,7 @@ static int deauthenticate(struct usbnet *usbdev) { int ret; - ret = disassociate(usbdev, 1); + ret = disassociate(usbdev, true); set_default_iw_params(usbdev); return ret; } @@ -1634,7 +1634,7 @@ static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, */ if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) { if (!priv->radio_on) - disassociate(usbdev, 1); /* turn on radio */ + disassociate(usbdev, true); /* turn on radio */ return 0; } @@ -1923,7 +1923,7 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, return ret; err_turn_radio_on: - disassociate(usbdev, 1); + disassociate(usbdev, true); return ret; } @@ -2031,7 +2031,7 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, return ret; err_turn_radio_on: - disassociate(usbdev, 1); + disassociate(usbdev, true); return ret; } @@ -2823,8 +2823,8 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD); /* turn radio on */ - priv->radio_on = 1; - disassociate(usbdev, 1); + priv->radio_on = true; + disassociate(usbdev, true); netif_carrier_off(usbdev->net); return 0; @@ -2846,7 +2846,7 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* turn radio off */ - disassociate(usbdev, 0); + disassociate(usbdev, false); cancel_delayed_work_sync(&priv->dev_poller_work); cancel_delayed_work_sync(&priv->scan_work); @@ -2894,7 +2894,7 @@ static int rndis_wlan_stop(struct usbnet *usbdev) devdbg(usbdev, "rndis_wlan_stop"); - retval = disassociate(usbdev, 0); + retval = disassociate(usbdev, false); priv->work_pending = 0; cancel_delayed_work_sync(&priv->dev_poller_work); -- cgit v0.10.2 From c5c4fe90e399e4c1265414249c33429c19a16ea8 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 1 Sep 2009 15:33:00 +0300 Subject: rndis_wlan: cleanup - remove double newlines between functions - remove commented out function (rndis_set_config_parameter_u32()) - coding style fix in rndis_set_config_parameter_str() - add comment banners between function sections Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index dc2804f..add2eb8 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -560,7 +560,6 @@ static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) return (struct rndis_wlan_private *)dev->driver_priv; } - static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) { switch (priv->param_power_output) { @@ -576,7 +575,6 @@ static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) } } - static bool is_wpa_key(struct rndis_wlan_private *priv, int idx) { int cipher = priv->encr_keys[idx].cipher; @@ -585,7 +583,6 @@ static bool is_wpa_key(struct rndis_wlan_private *priv, int idx) cipher == WLAN_CIPHER_SUITE_TKIP); } - static int rndis_cipher_to_alg(u32 cipher) { switch (cipher) { @@ -613,7 +610,6 @@ static int rndis_akm_suite_to_key_mgmt(u32 akm_suite) } } - #ifdef DEBUG static const char *oid_to_string(__le32 oid) { @@ -675,7 +671,6 @@ static const char *oid_to_string(__le32 oid) } #endif - /* translate error code */ static int rndis_error_status(__le32 rndis_status) { @@ -699,7 +694,6 @@ static int rndis_error_status(__le32 rndis_status) return ret; } - static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); @@ -758,7 +752,6 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) return ret; } - static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); @@ -817,7 +810,6 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) return ret; } - static int rndis_reset(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -840,7 +832,6 @@ static int rndis_reset(struct usbnet *usbdev) return 0; } - /* * Specs say that we can only set config parameters only soon after device * initialization. @@ -927,16 +918,9 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param, static int rndis_set_config_parameter_str(struct usbnet *dev, char *param, char *value) { - return(rndis_set_config_parameter(dev, param, 2, value)); + return rndis_set_config_parameter(dev, param, 2, value); } -/*static int rndis_set_config_parameter_u32(struct usbnet *dev, - char *param, u32 value) -{ - return(rndis_set_config_parameter(dev, param, 0, &value)); -}*/ - - /* * data conversion functions */ @@ -946,7 +930,6 @@ static int level_to_qual(int level) return qual >= 0 ? (qual <= 100 ? qual : 100) : 0; } - /* * common functions */ @@ -1027,7 +1010,6 @@ static bool is_associated(struct usbnet *usbdev) return (ret == 0 && !is_zero_ether_addr(bssid)); } - static int disassociate(struct usbnet *usbdev, bool reset_ssid) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1064,7 +1046,6 @@ static int disassociate(struct usbnet *usbdev, bool reset_ssid) return ret; } - static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, enum nl80211_auth_type auth_type, int keymgmt) { @@ -1109,7 +1090,6 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, return 0; } - static int set_priv_filter(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1127,7 +1107,6 @@ static int set_priv_filter(struct usbnet *usbdev) sizeof(tmp)); } - static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1163,7 +1142,6 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) return 0; } - static int set_infra_mode(struct usbnet *usbdev, int mode) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1189,7 +1167,6 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) return 0; } - static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) { __le32 tmp; @@ -1204,7 +1181,6 @@ static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) sizeof(tmp)); } - static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) { __le32 tmp; @@ -1219,7 +1195,6 @@ static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) sizeof(tmp)); } - static void set_default_iw_params(struct usbnet *usbdev) { set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); @@ -1229,7 +1204,6 @@ static void set_default_iw_params(struct usbnet *usbdev) set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); } - static int deauthenticate(struct usbnet *usbdev) { int ret; @@ -1239,7 +1213,6 @@ static int deauthenticate(struct usbnet *usbdev) return ret; } - static int set_channel(struct usbnet *usbdev, int channel) { struct ndis_80211_conf config; @@ -1270,7 +1243,6 @@ static int set_channel(struct usbnet *usbdev, int channel) return ret; } - /* index must be 0 - N, as per NDIS */ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, int index) @@ -1322,7 +1294,6 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, return 0; } - static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, int index, const u8 *addr, const u8 *rx_seq, int seq_len, u32 cipher, int flags) @@ -1417,7 +1388,6 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, return 0; } - static int restore_key(struct usbnet *usbdev, int key_idx) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1436,7 +1406,6 @@ static int restore_key(struct usbnet *usbdev, int key_idx) return add_wep_key(usbdev, key.material, key.len, key_idx); } - static void restore_keys(struct usbnet *usbdev) { int i; @@ -1445,13 +1414,11 @@ static void restore_keys(struct usbnet *usbdev) restore_key(usbdev, i); } - static void clear_key(struct rndis_wlan_private *priv, int idx) { memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx])); } - /* remove_key is for both wep and wpa */ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid) { @@ -1508,7 +1475,6 @@ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid) return 0; } - static void set_multicast_list(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1568,7 +1534,6 @@ static void set_multicast_list(struct usbnet *usbdev) le32_to_cpu(filter), ret); } - /* * cfg80211 ops */ @@ -1597,7 +1562,6 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, return set_infra_mode(usbdev, mode); } - static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) { struct rndis_wlan_private *priv = wiphy_priv(wiphy); @@ -1619,7 +1583,6 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) return 0; } - static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, int dbm) { @@ -1642,7 +1605,6 @@ static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, return -ENOTSUPP; } - static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) { struct rndis_wlan_private *priv = wiphy_priv(wiphy); @@ -1655,7 +1617,6 @@ static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) return 0; } - #define SCAN_DELAY_JIFFIES (6 * HZ) static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) @@ -1692,7 +1653,6 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, return ret; } - static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, struct ndis_80211_bssid_ex *bssid) { @@ -1741,7 +1701,6 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, GFP_KERNEL); } - static int rndis_check_bssid_list(struct usbnet *usbdev) { void *buf = NULL; @@ -1790,7 +1749,6 @@ out: return ret; } - static void rndis_get_scan_results(struct work_struct *work) { struct rndis_wlan_private *priv = @@ -2175,7 +2133,9 @@ static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, return 0; } - +/* + * workers, indication handlers, device poller + */ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2293,7 +2253,6 @@ static void rndis_wlan_set_multicast_list(struct net_device *dev) queue_work(priv->workqueue, &priv->work); } - static void rndis_wlan_auth_indication(struct usbnet *usbdev, struct ndis_80211_status_indication *indication, int len) @@ -2476,7 +2435,6 @@ static void rndis_wlan_media_specific_indication(struct usbnet *usbdev, } } - static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2523,7 +2481,6 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) } } - static int rndis_wlan_get_caps(struct usbnet *usbdev) { struct { @@ -2560,7 +2517,6 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev) return retval; } - #define DEVICE_POLLER_JIFFIES (HZ) static void rndis_device_poller(struct work_struct *work) { @@ -2632,7 +2588,9 @@ end: update_jiffies); } - +/* + * driver/device initialization + */ static int bcm4320a_early_init(struct usbnet *usbdev) { /* bcm4320a doesn't handle configuration parameters well. Try @@ -2642,7 +2600,6 @@ static int bcm4320a_early_init(struct usbnet *usbdev) return 0; } - static int bcm4320b_early_init(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2721,7 +2678,6 @@ static const struct net_device_ops rndis_wlan_netdev_ops = { .ndo_set_multicast_list = rndis_wlan_set_multicast_list, }; - static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) { struct wiphy *wiphy; @@ -2840,7 +2796,6 @@ fail: return retval; } - static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2863,7 +2818,6 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) wiphy_free(priv->wdev.wiphy); } - static int rndis_wlan_reset(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2885,7 +2839,6 @@ static int rndis_wlan_reset(struct usbnet *usbdev) return deauthenticate(usbdev); } - static int rndis_wlan_stop(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2916,7 +2869,6 @@ static int rndis_wlan_stop(struct usbnet *usbdev) return retval; } - static const struct driver_info bcm4320b_info = { .description = "Wireless RNDIS device, BCM4320b based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | -- cgit v0.10.2 From 53d27eaf55fb5a6e820d8e3759588473826d659e Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 1 Sep 2009 15:33:06 +0300 Subject: rndis_wlan: fix sparse endianess warnings Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index add2eb8..54175b6 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -253,8 +253,8 @@ struct ndis_80211_pmkid_cand_list { struct ndis_80211_status_indication { __le32 status_type; union { - enum ndis_80211_media_stream_mode media_stream_mode; - enum ndis_80211_radio_status radio_status; + __le32 media_stream_mode; + __le32 radio_status; struct ndis_80211_auth_request auth_request[0]; struct ndis_80211_pmkid_cand_list cand_list; } u; @@ -1296,7 +1296,7 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, int index, const u8 *addr, const u8 *rx_seq, - int seq_len, u32 cipher, int flags) + int seq_len, u32 cipher, __le32 flags) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_key ndis_key; @@ -2023,7 +2023,7 @@ static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, { struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; - int flags; + __le32 flags; devdbg(usbdev, "rndis_add_key(%i, %pM, %08x)", key_index, mac_addr, params->cipher); -- cgit v0.10.2 From 2b7dcfb7d01c9fc9efc6e39618cbf495a6051f9a Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 1 Sep 2009 15:33:11 +0300 Subject: rndis_wlan: remove 'select WIRELESS_EXT' in Kconfig Since rndis_wlan is now converted to cfg80211, WIRELESS_EXT isn't required anymore. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index dda7cc2..623897f 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -337,7 +337,6 @@ config USB_NET_RNDIS_WLAN select USB_USBNET select USB_NET_CDCETHER select USB_NET_RNDIS_HOST - select WIRELESS_EXT ---help--- This is a driver for wireless RNDIS devices. These are USB based adapters found in devices such as: -- cgit v0.10.2 From ae73abf2350de7cbfc5c46a936f4d2a532b36679 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Sep 2009 15:13:58 +0200 Subject: iwmc3200wifi: invalidate profile when necessary before connect If cfg80211 requests to connect when we have already had an active profile, invalidate the current profile first before sending a new profile to UMAC. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index a6e852f..789ef5c 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -326,11 +326,8 @@ static int iwm_cfg80211_change_iface(struct wiphy *wiphy, iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode); - if (iwm->umac_profile_active) { - int ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - } + if (iwm->umac_profile_active) + iwm_invalidate_mlme_profile(iwm); return 0; } @@ -573,6 +570,14 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, if (!sme->ssid) return -EINVAL; + if (iwm->umac_profile_active) { + ret = iwm_invalidate_mlme_profile(iwm); + if (ret) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + } + if (chan) iwm->channel = ieee80211_frequency_to_channel(chan->center_freq); -- cgit v0.10.2 From b90a5c9561d3f75f906a84613cc0071121143fb6 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 1 Sep 2009 15:13:59 +0200 Subject: iwmc3200wifi: Set WEP key from connect When connect is called with the LEGACY_PSK authentication type set, and a proper sme->key, we need to set the WEP key straight after setting the profile otherwise the authentication will never start. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 789ef5c..d8bb723 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -562,6 +562,7 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, { struct iwm_priv *iwm = wiphy_to_iwm(wiphy); struct ieee80211_channel *chan = sme->channel; + struct key_params key_param; int ret; if (!test_bit(IWM_STATUS_READY, &iwm->status)) @@ -619,7 +620,48 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return ret; } - return iwm_send_mlme_profile(iwm); + /* + * We save the WEP key in case we want to do shared authentication. + * We have to do it so because UMAC will assert whenever it gets a + * key before a profile. + */ + if (sme->key) { + key_param.key = kmemdup(sme->key, sme->key_len, GFP_KERNEL); + if (key_param.key == NULL) + return -ENOMEM; + key_param.key_len = sme->key_len; + key_param.seq_len = 0; + key_param.cipher = sme->crypto.ciphers_pairwise[0]; + + ret = iwm_key_init(&iwm->keys[sme->key_idx], sme->key_idx, + NULL, &key_param); + kfree(key_param.key); + if (ret < 0) { + IWM_ERR(iwm, "Invalid key_params\n"); + return ret; + } + + iwm->default_key = sme->key_idx; + } + + ret = iwm_send_mlme_profile(iwm); + + if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK || + sme->key == NULL) + return ret; + + /* + * We want to do shared auth. + * We need to actually set the key we previously cached, + * and then tell the UMAC it's the default one. + * That will trigger the auth+assoc UMAC machinery, and again, + * this must be done after setting the profile. + */ + ret = iwm_set_key(iwm, 0, &iwm->keys[sme->key_idx]); + if (ret < 0) + return ret; + + return iwm_set_tx_key(iwm, iwm->default_key); } static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, -- cgit v0.10.2 From d041811d931d4f515fd58e222757cbc7d6375db4 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 1 Sep 2009 15:14:00 +0200 Subject: iwmc3200wifi: Fix sparse warning iwm_cfg80211_get_station() should be static. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index d8bb723..2784b08 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -238,8 +238,9 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, return iwm_set_tx_key(iwm, key_index); } -int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, - u8 *mac, struct station_info *sinfo) +static int iwm_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *ndev, + u8 *mac, struct station_info *sinfo) { struct iwm_priv *iwm = ndev_to_iwm(ndev); -- cgit v0.10.2 From de15fd31fcabb4b81a556736dd67ec4f71462f07 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Sep 2009 15:14:01 +0200 Subject: iwmc3200wifi: use cfg80211_roamed to send roam event The device sends connection terminated and [re]association success (or failure) events when roaming occours. The patch uses cfg80211_roamed instead of cfg80211_connect_result to notify SME for roaming. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 2784b08..a56a2b0 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -673,7 +673,7 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active); if (iwm->umac_profile_active) - return iwm_invalidate_mlme_profile(iwm); + iwm_invalidate_mlme_profile(iwm); return 0; } diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index a68a2af..23b52fa 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -756,6 +756,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) return ret; } + set_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); return 0; } diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 7a51bc3..f054cc8 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -175,7 +175,7 @@ struct iwm_key { #define IWM_STATUS_READY 0 #define IWM_STATUS_SCANNING 1 #define IWM_STATUS_SCAN_ABORTING 2 -#define IWM_STATUS_ASSOCIATING 3 +#define IWM_STATUS_SME_CONNECTING 3 #define IWM_STATUS_ASSOCIATED 4 struct iwm_tx_queue { diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 86079a1..9e6f2cd 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -487,8 +487,6 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf, start = (struct iwm_umac_notif_assoc_start *)buf; - set_bit(IWM_STATUS_ASSOCIATING, &iwm->status); - IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n", start->bssid, le32_to_cpu(start->roam_reason)); @@ -507,14 +505,23 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", complete->bssid, complete->status); - clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); - switch (le32_to_cpu(complete->status)) { case UMAC_ASSOC_COMPLETE_SUCCESS: set_bit(IWM_STATUS_ASSOCIATED, &iwm->status); memcpy(iwm->bssid, complete->bssid, ETH_ALEN); iwm->channel = complete->channel; + /* Internal roaming state, avoid notifying SME. */ + if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) + && iwm->conf.mode == UMAC_MODE_BSS) { + cfg80211_roamed(iwm_to_ndev(iwm), + complete->bssid, + iwm->req_ie, iwm->req_ie_len, + iwm->resp_ie, iwm->resp_ie_len, + GFP_KERNEL); + break; + } + iwm_link_on(iwm); if (iwm->conf.mode == UMAC_MODE_IBSS) @@ -531,6 +538,11 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, memset(iwm->bssid, 0, ETH_ALEN); iwm->channel = 0; + /* Internal roaming state, avoid notifying SME. */ + if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) + && iwm->conf.mode == UMAC_MODE_BSS) + break; + iwm_link_off(iwm); if (iwm->conf.mode == UMAC_MODE_IBSS) @@ -540,6 +552,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); + break; default: break; } @@ -562,7 +575,7 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", le32_to_cpu(invalid->reason)); - clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); + clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); iwm->umac_profile_active = 0; @@ -813,7 +826,8 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, iwm->resp_ie_len, GFP_KERNEL); } else { - IWM_ERR(iwm, "Unsupported management frame"); + IWM_ERR(iwm, "Unsupported management frame: 0x%x", + cpu_to_le16(mgt->frame_control)); return 0; } -- cgit v0.10.2 From c7436273889e0ce511b317041f35344e92344885 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Sep 2009 15:14:02 +0200 Subject: iwmc3200wifi: add disconnect work When the driver receives "connection terminated" event from device, it could be caused by 2 reasons: the firmware is roaming or the connection is lost (AP disappears). For the former, an association complete event is supposed to come within 3 seconds. For the latter, the driver won't receive any event except the connection terminated. So we kick a delayed work (5*HZ) when we receive the connection terminated event. It will be canceled if it turns out to be a roaming event later. Otherwise we notify SME and userspace the disconnection. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index f054cc8..da49df6 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -273,6 +273,7 @@ struct iwm_priv { struct iw_statistics wstats; struct delayed_work stats_request; + struct delayed_work disconnect; struct iwm_debugfs dbg; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index cf25744..c41fa8c 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -108,6 +108,26 @@ static void iwm_statistics_request(struct work_struct *work) iwm_send_umac_stats_req(iwm, 0); } +static void iwm_disconnect_work(struct work_struct *work) +{ + struct iwm_priv *iwm = + container_of(work, struct iwm_priv, disconnect.work); + + if (iwm->umac_profile_active) + iwm_invalidate_mlme_profile(iwm); + + clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); + iwm->umac_profile_active = 0; + memset(iwm->bssid, 0, ETH_ALEN); + iwm->channel = 0; + + iwm_link_off(iwm); + + wake_up_interruptible(&iwm->mlme_queue); + + cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); +} + int __iwm_up(struct iwm_priv *iwm); int __iwm_down(struct iwm_priv *iwm); @@ -198,6 +218,7 @@ int iwm_priv_init(struct iwm_priv *iwm) spin_lock_init(&iwm->cmd_lock); iwm->scan_id = 1; INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); + INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work); INIT_WORK(&iwm->reset_worker, iwm_reset_worker); INIT_LIST_HEAD(&iwm->bss_list); diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 9e6f2cd..4d9793e 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -514,6 +514,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, /* Internal roaming state, avoid notifying SME. */ if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) && iwm->conf.mode == UMAC_MODE_BSS) { + cancel_delayed_work(&iwm->disconnect); cfg80211_roamed(iwm_to_ndev(iwm), complete->bssid, iwm->req_ie, iwm->req_ie_len, @@ -540,8 +541,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, /* Internal roaming state, avoid notifying SME. */ if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) - && iwm->conf.mode == UMAC_MODE_BSS) + && iwm->conf.mode == UMAC_MODE_BSS) { + cancel_delayed_work(&iwm->disconnect); break; + } iwm_link_off(iwm); @@ -569,11 +572,18 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, struct iwm_wifi_cmd *cmd) { struct iwm_umac_notif_profile_invalidate *invalid; + u32 reason; invalid = (struct iwm_umac_notif_profile_invalidate *)buf; + reason = le32_to_cpu(invalid->reason); + + IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", reason); - IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", - le32_to_cpu(invalid->reason)); + if (reason != UMAC_PROFILE_INVALID_REQUEST && + test_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)) + cfg80211_connect_result(iwm_to_ndev(iwm), NULL, NULL, 0, NULL, + 0, WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); @@ -589,6 +599,19 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, return 0; } +#define IWM_DISCONNECT_INTERVAL (5 * HZ) + +static int iwm_mlme_connection_terminated(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); + + schedule_delayed_work(&iwm->disconnect, IWM_DISCONNECT_INTERVAL); + + return 0; +} + static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) @@ -848,8 +871,7 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf, case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE: return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd); case WIFI_IF_NTFY_CONNECTION_TERMINATED: - IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); - break; + return iwm_mlme_connection_terminated(iwm, buf, buf_size, cmd); case WIFI_IF_NTFY_SCAN_COMPLETE: return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd); case WIFI_IF_NTFY_STA_TABLE_CHANGE: -- cgit v0.10.2 From 31452420ca956f2cf37f705c869e265c33894f07 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Sep 2009 15:14:03 +0200 Subject: iwmc3200wifi: fix misuse of le16_to_cpu Also mark some functions static. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index c41fa8c..6cf2f0c 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -128,8 +128,8 @@ static void iwm_disconnect_work(struct work_struct *work) cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); } -int __iwm_up(struct iwm_priv *iwm); -int __iwm_down(struct iwm_priv *iwm); +static int __iwm_up(struct iwm_priv *iwm); +static int __iwm_down(struct iwm_priv *iwm); static void iwm_reset_worker(struct work_struct *work) { @@ -559,7 +559,7 @@ static int iwm_channels_init(struct iwm_priv *iwm) return 0; } -int __iwm_up(struct iwm_priv *iwm) +static int __iwm_up(struct iwm_priv *iwm) { int ret; struct iwm_notif *notif_reboot, *notif_ack = NULL; @@ -693,7 +693,7 @@ int iwm_up(struct iwm_priv *iwm) return ret; } -int __iwm_down(struct iwm_priv *iwm) +static int __iwm_down(struct iwm_priv *iwm) { int ret; diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 4d9793e..2daa586 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -850,7 +850,7 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, iwm->resp_ie_len, GFP_KERNEL); } else { IWM_ERR(iwm, "Unsupported management frame: 0x%x", - cpu_to_le16(mgt->frame_control)); + le16_to_cpu(mgt->frame_control)); return 0; } -- cgit v0.10.2 From d04bd6283cf7433d56f3d8f648f1d6963fda4fdc Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 1 Sep 2009 15:14:04 +0200 Subject: iwmc3200wifi: New initial LMAC calibration The LMAC calibration API got broken mostly by having a configuration bitmap being different than the result one. This patch tries to address that issue by correctly running calibrations with the newest firmwares, and keeping a backward compatibility fallback path for older firmwares, where the configuration and result bitmaps were identical. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index 0f32cab..6b0bcad 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -261,6 +261,33 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN), 0); } +static int iwm_init_calib(struct iwm_priv *iwm, unsigned long cfg_bitmap, + unsigned long expected_bitmap, u8 rx_iq_cmd) +{ + /* Read RX IQ calibration result from EEPROM */ + if (test_bit(rx_iq_cmd, &cfg_bitmap)) { + iwm_store_rxiq_calib_result(iwm); + set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); + } + + iwm_send_prio_table(iwm); + iwm_send_init_calib_cfg(iwm, cfg_bitmap); + + while (iwm->calib_done_map != expected_bitmap) { + if (iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, + IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT)) { + IWM_DBG_FW(iwm, DBG, "Initial calibration timeout\n"); + return -ETIMEDOUT; + } + + IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " + "0x%lx, expected calibrations: 0x%lx\n", + iwm->calib_done_map, expected_bitmap); + } + + return 0; +} + /* * We currently have to load 3 FWs: * 1) The UMAC (Upper MAC). @@ -276,6 +303,7 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) int iwm_load_fw(struct iwm_priv *iwm) { unsigned long init_calib_map, periodic_calib_map; + unsigned long expected_calib_map; int ret; /* We first start downloading the UMAC */ @@ -317,27 +345,21 @@ int iwm_load_fw(struct iwm_priv *iwm) } init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK; + expected_calib_map = iwm->conf.expected_calib_map & + IWM_CALIB_MAP_INIT_MSK; periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map); - /* Read RX IQ calibration result from EEPROM */ - if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) { - iwm_store_rxiq_calib_result(iwm); - set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); - } - - iwm_send_prio_table(iwm); - iwm_send_init_calib_cfg(iwm, init_calib_map); - - while (iwm->calib_done_map != init_calib_map) { - ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, - IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); - if (ret) { - IWM_ERR(iwm, "Wait for calibration result timeout\n"); + ret = iwm_init_calib(iwm, init_calib_map, expected_calib_map, + CALIB_CFG_RX_IQ_IDX); + if (ret < 0) { + /* Let's try the old way */ + ret = iwm_init_calib(iwm, expected_calib_map, + expected_calib_map, + PHY_CALIBRATE_RX_IQ_CMD); + if (ret < 0) { + IWM_ERR(iwm, "Calibration result timeout\n"); goto out; } - IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " - "0x%lx, requested calibrations: 0x%lx\n", - iwm->calib_done_map, init_calib_map); } /* Handle LMAC CALIBRATION_COMPLETE notification */ diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index da49df6..74964ee 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -64,6 +64,7 @@ struct iwm_conf { u32 sdio_ior_timeout; unsigned long calib_map; + unsigned long expected_calib_map; bool reset_on_fatal_err; bool auto_connect; bool wimax_not_present; diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h index 19213e1..6c1a14c 100644 --- a/drivers/net/wireless/iwmc3200wifi/lmac.h +++ b/drivers/net/wireless/iwmc3200wifi/lmac.h @@ -396,9 +396,24 @@ enum { CALIBRATION_CMD_NUM, }; +enum { + CALIB_CFG_RX_BB_IDX = 0, + CALIB_CFG_DC_IDX = 1, + CALIB_CFG_LO_IDX = 2, + CALIB_CFG_TX_IQ_IDX = 3, + CALIB_CFG_RX_IQ_IDX = 4, + CALIB_CFG_NOISE_IDX = 5, + CALIB_CFG_CRYSTAL_IDX = 6, + CALIB_CFG_TEMPERATURE_IDX = 7, + CALIB_CFG_PAPD_IDX = 8, + CALIB_CFG_LAST_IDX = CALIB_CFG_PAPD_IDX, + CALIB_CFG_MODULE_NUM, +}; + #define IWM_CALIB_MAP_INIT_MSK 0xFFFF #define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16) #define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24) +#define IWM_CALIB_OPCODE_TO_INDEX(op) (op - PHY_CALIBRATE_OPCODES_NUM) struct iwm_lmac_calib_hdr { u8 opcode; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 6cf2f0c..fc7fce4 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -53,7 +53,12 @@ static struct iwm_conf def_iwm_conf = { .sdio_ior_timeout = 5000, - .calib_map = BIT(PHY_CALIBRATE_DC_CMD) | + .calib_map = BIT(CALIB_CFG_DC_IDX) | + BIT(CALIB_CFG_LO_IDX) | + BIT(CALIB_CFG_TX_IQ_IDX) | + BIT(CALIB_CFG_RX_IQ_IDX) | + BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), + .expected_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | BIT(PHY_CALIBRATE_LO_CMD) | BIT(PHY_CALIBRATE_TX_IQ_CMD) | BIT(PHY_CALIBRATE_RX_IQ_CMD) | -- cgit v0.10.2 From d210176eaaed0c7883caba52665bcfb5d420c660 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 1 Sep 2009 15:14:05 +0200 Subject: iwmc3200wifi: Handle UMAC stalls and UMAC assert properly When UMAC stalls or asserts, we want to reset the device. But when we're associated, the current reset worker will end up calling cfg80211_connect_result() with the cfg80211 sme layer knowing that we're reassociating. That ends up with some ugly warnings. With this patch we're telling the upper layer that we've roamed if reassociation succeeds, and that we're disconnected if it fails. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 74964ee..f5c2d6f 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -178,6 +178,7 @@ struct iwm_key { #define IWM_STATUS_SCAN_ABORTING 2 #define IWM_STATUS_SME_CONNECTING 3 #define IWM_STATUS_ASSOCIATED 4 +#define IWM_STATUS_RESETTING 5 struct iwm_tx_queue { int id; @@ -317,6 +318,7 @@ int iwm_mode_to_nl80211_iftype(int mode); int iwm_priv_init(struct iwm_priv *iwm); void iwm_priv_deinit(struct iwm_priv *iwm); void iwm_reset(struct iwm_priv *iwm); +void iwm_resetting(struct iwm_priv *iwm); void iwm_tx_credit_init_pools(struct iwm_priv *iwm, struct iwm_umac_notif_alive *alive); int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb); diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index fc7fce4..6a5b76a 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -187,7 +187,8 @@ static void iwm_reset_worker(struct work_struct *work) memcpy(iwm->umac_profile, profile, sizeof(*profile)); iwm_send_mlme_profile(iwm); kfree(profile); - } + } else + clear_bit(IWM_STATUS_RESETTING, &iwm->status); out: mutex_unlock(&iwm->mutex); @@ -200,7 +201,7 @@ static void iwm_watchdog(unsigned long data) IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n"); if (modparam_reset) - schedule_work(&iwm->reset_worker); + iwm_resetting(iwm); } int iwm_priv_init(struct iwm_priv *iwm) @@ -284,7 +285,11 @@ void iwm_reset(struct iwm_priv *iwm) if (test_bit(IWM_STATUS_READY, &iwm->status)) iwm_target_reset(iwm); - iwm->status = 0; + if (test_bit(IWM_STATUS_RESETTING, &iwm->status)) { + iwm->status = 0; + set_bit(IWM_STATUS_RESETTING, &iwm->status); + } else + iwm->status = 0; iwm->scan_id = 1; list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) { @@ -300,6 +305,13 @@ void iwm_reset(struct iwm_priv *iwm) iwm_link_off(iwm); } +void iwm_resetting(struct iwm_priv *iwm) +{ + set_bit(IWM_STATUS_RESETTING, &iwm->status); + + schedule_work(&iwm->reset_worker); +} + /* * Notification code: * diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 2daa586..14950b1 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -118,6 +118,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status)); IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status)); + iwm_resetting(iwm); + return 0; } @@ -528,11 +530,19 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, if (iwm->conf.mode == UMAC_MODE_IBSS) goto ibss; - cfg80211_connect_result(iwm_to_ndev(iwm), + if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) + cfg80211_connect_result(iwm_to_ndev(iwm), + complete->bssid, + iwm->req_ie, iwm->req_ie_len, + iwm->resp_ie, iwm->resp_ie_len, + WLAN_STATUS_SUCCESS, + GFP_KERNEL); + else + cfg80211_roamed(iwm_to_ndev(iwm), complete->bssid, iwm->req_ie, iwm->req_ie_len, iwm->resp_ie, iwm->resp_ie_len, - WLAN_STATUS_SUCCESS, GFP_KERNEL); + GFP_KERNEL); break; case UMAC_ASSOC_COMPLETE_FAILURE: clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); @@ -551,19 +561,26 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, if (iwm->conf.mode == UMAC_MODE_IBSS) goto ibss; - cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, - NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); + if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) + cfg80211_connect_result(iwm_to_ndev(iwm), + complete->bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + else + cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, + GFP_KERNEL); break; default: break; } + clear_bit(IWM_STATUS_RESETTING, &iwm->status); return 0; ibss: cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); + clear_bit(IWM_STATUS_RESETTING, &iwm->status); return 0; } -- cgit v0.10.2 From 04e715cd46ba523806070fbf9ded009f10e107cd Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 1 Sep 2009 15:14:06 +0200 Subject: iwmc3200wifi: Add a last_fw_err debugfs entry In order to check what was the last fw error we got accross resets, we add this debugfs entry. It displays the complete ASSERT information. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h index 8fbb42d..e35c9b6 100644 --- a/drivers/net/wireless/iwmc3200wifi/debug.h +++ b/drivers/net/wireless/iwmc3200wifi/debug.h @@ -108,6 +108,8 @@ struct iwm_debugfs { struct dentry *txq_dentry; struct dentry *tx_credit_dentry; struct dentry *rx_ticket_dentry; + + struct dentry *fw_err_dentry; }; #ifdef CONFIG_IWM_DEBUG diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c index 0fa7b91..1465379 100644 --- a/drivers/net/wireless/iwmc3200wifi/debugfs.c +++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c @@ -98,7 +98,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules, iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write, "%llu\n"); -static int iwm_txrx_open(struct inode *inode, struct file *filp) +static int iwm_generic_open(struct inode *inode, struct file *filp) { filp->private_data = inode->i_private; return 0; @@ -289,25 +289,111 @@ static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp, return ret; } +static ssize_t iwm_debugfs_fw_err_read(struct file *filp, + char __user *buffer, + size_t count, loff_t *ppos) +{ + + struct iwm_priv *iwm = filp->private_data; + char buf[512]; + int buf_len = 512; + size_t len = 0; + + if (*ppos != 0) + return 0; + if (count < sizeof(buf)) + return -ENOSPC; + + if (!iwm->last_fw_err) + return -ENOMEM; + + if (iwm->last_fw_err->line_num == 0) + goto out; + + len += snprintf(buf + len, buf_len - len, "%cMAC FW ERROR:\n", + (le32_to_cpu(iwm->last_fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) + ? 'L' : 'U'); + len += snprintf(buf + len, buf_len - len, + "\tCategory: %d\n", + le32_to_cpu(iwm->last_fw_err->category)); + + len += snprintf(buf + len, buf_len - len, + "\tStatus: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->status)); + + len += snprintf(buf + len, buf_len - len, + "\tPC: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->pc)); + + len += snprintf(buf + len, buf_len - len, + "\tblink1: %d\n", + le32_to_cpu(iwm->last_fw_err->blink1)); + + len += snprintf(buf + len, buf_len - len, + "\tblink2: %d\n", + le32_to_cpu(iwm->last_fw_err->blink2)); + + len += snprintf(buf + len, buf_len - len, + "\tilink1: %d\n", + le32_to_cpu(iwm->last_fw_err->ilink1)); + + len += snprintf(buf + len, buf_len - len, + "\tilink2: %d\n", + le32_to_cpu(iwm->last_fw_err->ilink2)); + + len += snprintf(buf + len, buf_len - len, + "\tData1: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->data1)); + + len += snprintf(buf + len, buf_len - len, + "\tData2: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->data2)); + + len += snprintf(buf + len, buf_len - len, + "\tLine number: %d\n", + le32_to_cpu(iwm->last_fw_err->line_num)); + + len += snprintf(buf + len, buf_len - len, + "\tUMAC status: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->umac_status)); + + len += snprintf(buf + len, buf_len - len, + "\tLMAC status: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->lmac_status)); + + len += snprintf(buf + len, buf_len - len, + "\tSDIO status: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->sdio_status)); + +out: + + return simple_read_from_buffer(buffer, len, ppos, buf, buf_len); +} static const struct file_operations iwm_debugfs_txq_fops = { .owner = THIS_MODULE, - .open = iwm_txrx_open, + .open = iwm_generic_open, .read = iwm_debugfs_txq_read, }; static const struct file_operations iwm_debugfs_tx_credit_fops = { .owner = THIS_MODULE, - .open = iwm_txrx_open, + .open = iwm_generic_open, .read = iwm_debugfs_tx_credit_read, }; static const struct file_operations iwm_debugfs_rx_ticket_fops = { .owner = THIS_MODULE, - .open = iwm_txrx_open, + .open = iwm_generic_open, .read = iwm_debugfs_rx_ticket_read, }; +static const struct file_operations iwm_debugfs_fw_err_fops = { + .owner = THIS_MODULE, + .open = iwm_generic_open, + .read = iwm_debugfs_fw_err_read, +}; + int iwm_debugfs_init(struct iwm_priv *iwm) { int i, result; @@ -423,6 +509,16 @@ int iwm_debugfs_init(struct iwm_priv *iwm) goto error; } + iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200, + iwm->dbg.dbgdir, iwm, + &iwm_debugfs_fw_err_fops); + result = PTR_ERR(iwm->dbg.fw_err_dentry); + if (IS_ERR(iwm->dbg.fw_err_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create last FW err: %d\n", result); + goto error; + } + + return 0; error: @@ -441,6 +537,7 @@ void iwm_debugfs_exit(struct iwm_priv *iwm) debugfs_remove(iwm->dbg.txq_dentry); debugfs_remove(iwm->dbg.tx_credit_dentry); debugfs_remove(iwm->dbg.rx_ticket_dentry); + debugfs_remove(iwm->dbg.fw_err_dentry); if (iwm->bus_ops->debugfs_exit) iwm->bus_ops->debugfs_exit(iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index f5c2d6f..1b02a4e 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -289,6 +289,8 @@ struct iwm_priv { u8 *resp_ie; int resp_ie_len; + struct iwm_fw_error_hdr *last_fw_err; + char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 6a5b76a..d668e47 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -260,6 +260,11 @@ int iwm_priv_init(struct iwm_priv *iwm) iwm->watchdog.data = (unsigned long)iwm; mutex_init(&iwm->mutex); + iwm->last_fw_err = kzalloc(sizeof(struct iwm_fw_error_hdr), + GFP_KERNEL); + if (iwm->last_fw_err == NULL) + return -ENOMEM; + return 0; } @@ -271,6 +276,7 @@ void iwm_priv_deinit(struct iwm_priv *iwm) destroy_workqueue(iwm->txq[i].wq); destroy_workqueue(iwm->rx_wq); + kfree(iwm->last_fw_err); } /* diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 14950b1..40dbcbc 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -102,6 +102,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, error = (struct iwm_umac_notif_error *)buf; fw_err = &error->err; + memcpy(iwm->last_fw_err, fw_err, sizeof(struct iwm_fw_error_hdr)); + IWM_ERR(iwm, "%cMAC FW ERROR:\n", (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); -- cgit v0.10.2 From f6909f394c2d4a0a71320797df72d54c49c5927e Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 1 Sep 2009 13:31:52 -0700 Subject: x86, msr: fix msr-reg.S compilation with gas 2.16.1 msr-reg.S used the :req option on a macro argument, which wasn't supported by gas 2.16.1 (but apparently by some earlier versions of gas, just to be confusing.) It isn't necessary, so just remove it. Signed-off-by: H. Peter Anvin Cc: Borislav Petkov diff --git a/arch/x86/lib/msr-reg.S b/arch/x86/lib/msr-reg.S index 9e8cdcf..d5eaf53 100644 --- a/arch/x86/lib/msr-reg.S +++ b/arch/x86/lib/msr-reg.S @@ -11,7 +11,7 @@ * reg layout: u32 gprs[eax, ecx, edx, ebx, esp, ebp, esi, edi] * */ -.macro op_safe_regs op:req +.macro op_safe_regs op ENTRY(native_\op\()_safe_regs) CFI_STARTPROC pushq_cfi %rbx -- cgit v0.10.2 From d94ff6b7cab20cc014e22b2fd5f0ff35d3e2308f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 Sep 2009 00:20:21 +0200 Subject: ALSA: hda - Fix obsolete CONFIG_SND_DEBUG_DETECT Fix the old dead CONFIG_SND_DEBUG_DETECT to CONFIG_SND_DEBUG_VERBOSE. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 24401d5..af989f6 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3127,7 +3127,7 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, tbl = q; if (tbl->value >= 0 && tbl->value < num_configs) { -#ifdef CONFIG_SND_DEBUG_DETECT +#ifdef CONFIG_SND_DEBUG_VERBOSE char tmp[10]; const char *model = NULL; if (models) -- cgit v0.10.2 From e2aec17100331669ecae8550a83f551f5e8fc4b8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 Sep 2009 01:00:05 +0200 Subject: ALSA: hda - Fix input source selection of IDT92HD73xx Fix the mux_nids to select directly the input source instead of mux mixers so that it works with the current mux enum handler for IDT 92HD73xx codecs. Also, clean up useless / unnecessary mixer controls and init verbs. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c878dfa..4cce92c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -329,11 +329,6 @@ static hda_nid_t stac92hd73xx_adc_nids[2] = { 0x1a, 0x1b }; -#define DELL_M6_AMP 2 -static hda_nid_t stac92hd73xx_amp_nids[3] = { - 0x0b, 0x0c, 0x0e -}; - #define STAC92HD73XX_NUM_DMICS 2 static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { 0x13, 0x14, 0 @@ -341,8 +336,8 @@ static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { #define STAC92HD73_DAC_COUNT 5 -static hda_nid_t stac92hd73xx_mux_nids[4] = { - 0x28, 0x29, 0x2a, 0x2b, +static hda_nid_t stac92hd73xx_mux_nids[2] = { + 0x20, 0x21, }; static hda_nid_t stac92hd73xx_dmux_nids[2] = { @@ -920,84 +915,16 @@ static struct hda_verb stac9200_eapd_init[] = { {} }; -static struct hda_verb stac92hd73xx_6ch_core_init[] = { - /* set master volume and direct control */ - { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* setup adcs to point to mixer */ - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, - { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* setup import muxs */ - { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {} -}; - static struct hda_verb dell_eq_core_init[] = { /* set master volume to max value without distortion * and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec}, - /* setup adcs to point to mixer */ - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, - { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, - /* setup import muxs */ - { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {} -}; - -static struct hda_verb dell_m6_core_init[] = { - { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* setup adcs to point to mixer */ - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, - { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, - /* setup import muxs */ - { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00}, - {} -}; - -static struct hda_verb stac92hd73xx_8ch_core_init[] = { - /* set master volume and direct control */ - { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* setup adcs to point to mixer */ - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, - { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* setup import muxs */ - { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03}, {} }; -static struct hda_verb stac92hd73xx_10ch_core_init[] = { +static struct hda_verb stac92hd73xx_core_init[] = { /* set master volume and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* dac3 is connected to import3 mux */ - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f}, - /* setup adcs to point to mixer */ - { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, - { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* setup import muxs */ - { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03}, {} }; @@ -1130,28 +1057,6 @@ static struct snd_kcontrol_new stac9200_mixer[] = { { } /* end */ }; -#define DELL_M6_MIXER 6 -static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = { - /* start of config #1 */ - HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), - - HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT), - - /* start of config #2 */ - HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), - - { } /* end */ -}; - static struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3), {} @@ -1167,42 +1072,6 @@ static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = { {} }; -static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = { - HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), - - HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT), - - HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = { - HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), - - HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT), - - HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT), - { } /* end */ -}; - static struct snd_kcontrol_new stac92hd71bxx_loopback[] = { STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2) @@ -5188,20 +5057,15 @@ again: "number of channels defaulting to DAC count\n"); num_dacs = STAC92HD73_DAC_COUNT; } + spec->init = stac92hd73xx_core_init; switch (num_dacs) { case 0x3: /* 6 Channel */ - spec->mixer = stac92hd73xx_6ch_mixer; - spec->init = stac92hd73xx_6ch_core_init; spec->aloopback_ctl = stac92hd73xx_6ch_loopback; break; case 0x4: /* 8 Channel */ - spec->mixer = stac92hd73xx_8ch_mixer; - spec->init = stac92hd73xx_8ch_core_init; spec->aloopback_ctl = stac92hd73xx_8ch_loopback; break; case 0x5: /* 10 Channel */ - spec->mixer = stac92hd73xx_10ch_mixer; - spec->init = stac92hd73xx_10ch_core_init; spec->aloopback_ctl = stac92hd73xx_10ch_loopback; break; } @@ -5216,8 +5080,6 @@ again: spec->dmic_nids = stac92hd73xx_dmic_nids; spec->dmux_nids = stac92hd73xx_dmux_nids; spec->smux_nids = stac92hd73xx_smux_nids; - spec->amp_nids = stac92hd73xx_amp_nids; - spec->num_amps = ARRAY_SIZE(stac92hd73xx_amp_nids); spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids); spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids); @@ -5235,13 +5097,8 @@ again: case STAC_DELL_M6_DMIC: case STAC_DELL_M6_BOTH: spec->num_smuxes = 0; - spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER]; - spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP]; spec->eapd_switch = 0; - spec->num_amps = 1; - if (spec->board_config != STAC_DELL_EQ) - spec->init = dell_m6_core_init; switch (spec->board_config) { case STAC_DELL_M6_AMIC: /* Analog Mics */ snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); -- cgit v0.10.2 From 4a9678909b366b1f95e1f93220c61340ab866151 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 Sep 2009 01:04:24 +0200 Subject: ALSA: hda - Remove dead codes from patch_sigmatel.c Due to the previous fix of input source for IDT92HD73xx, the amp mux and amp vol stuff became unused. Let's rip off dead codes. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 4cce92c..83a338b 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -228,7 +228,6 @@ struct sigmatel_spec { /* playback */ struct hda_input_mux *mono_mux; - struct hda_input_mux *amp_mux; unsigned int cur_mmux; struct hda_multi_out multiout; hda_nid_t dac_nids[5]; @@ -281,7 +280,6 @@ struct sigmatel_spec { unsigned int cur_smux[2]; unsigned int cur_amux; hda_nid_t *amp_nids; - unsigned int num_amps; unsigned int powerdown_adcs; /* i/o switches */ @@ -300,7 +298,6 @@ struct sigmatel_spec { struct hda_input_mux private_dimux; struct hda_input_mux private_imux; struct hda_input_mux private_smux; - struct hda_input_mux private_amp_mux; struct hda_input_mux private_mono_mux; }; @@ -590,34 +587,6 @@ static hda_nid_t stac9205_pin_nids[12] = { 0x21, 0x22, }; -#define stac92xx_amp_volume_info snd_hda_mixer_amp_volume_info - -static int stac92xx_amp_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = spec->amp_nids[spec->cur_amux]; - - kcontrol->private_value ^= get_amp_nid(kcontrol); - kcontrol->private_value |= nid; - - return snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); -} - -static int stac92xx_amp_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = spec->amp_nids[spec->cur_amux]; - - kcontrol->private_value ^= get_amp_nid(kcontrol); - kcontrol->private_value |= nid; - - return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); -} - static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -813,41 +782,6 @@ static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol, spec->mono_nid, &spec->cur_mmux); } -static int stac92xx_amp_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->amp_mux, uinfo); -} - -static int stac92xx_amp_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->cur_amux; - return 0; -} - -static int stac92xx_amp_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - struct snd_kcontrol *ctl = - snd_hda_find_mixer_ctl(codec, "Amp Capture Volume"); - if (!ctl) - return -EINVAL; - - snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE | - SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); - - return snd_hda_input_mux_put(codec, spec->amp_mux, ucontrol, - 0, &spec->cur_amux); -} - #define stac92xx_aloopback_info snd_ctl_boolean_mono_info static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, @@ -1002,31 +936,6 @@ static struct hda_verb stac9205_core_init[] = { .put = stac92xx_mono_mux_enum_put, \ } -#define STAC_AMP_MUX \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Amp Selector Capture Switch", \ - .count = 1, \ - .info = stac92xx_amp_mux_enum_info, \ - .get = stac92xx_amp_mux_enum_get, \ - .put = stac92xx_amp_mux_enum_put, \ - } - -#define STAC_AMP_VOL(xname, nid, chs, idx, dir) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = 0, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ - .info = stac92xx_amp_volume_info, \ - .get = stac92xx_amp_volume_get, \ - .put = stac92xx_amp_volume_put, \ - .tlv = { .c = snd_hda_mixer_amp_tlv }, \ - .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \ - } - #define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \ { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ @@ -2698,8 +2607,6 @@ enum { STAC_CTL_WIDGET_VOL, STAC_CTL_WIDGET_MUTE, STAC_CTL_WIDGET_MONO_MUX, - STAC_CTL_WIDGET_AMP_MUX, - STAC_CTL_WIDGET_AMP_VOL, STAC_CTL_WIDGET_HP_SWITCH, STAC_CTL_WIDGET_IO_SWITCH, STAC_CTL_WIDGET_CLFE_SWITCH, @@ -2710,8 +2617,6 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), STAC_MONO_MUX, - STAC_AMP_MUX, - STAC_AMP_VOL(NULL, 0, 0, 0, 0), STAC_CODEC_HP_SWITCH(NULL), STAC_CODEC_IO_SWITCH(NULL, 0), STAC_CODEC_CLFE_SWITCH(NULL, 0), @@ -3268,37 +3173,6 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec) "Mono Mux", spec->mono_nid); } -/* labels for amp mux outputs */ -static const char *stac92xx_amp_labels[3] = { - "Front Microphone", "Microphone", "Line In", -}; - -/* create amp out controls mux on capable codecs */ -static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *amp_mux = &spec->private_amp_mux; - int i, err; - - for (i = 0; i < spec->num_amps; i++) { - amp_mux->items[amp_mux->num_items].label = - stac92xx_amp_labels[i]; - amp_mux->items[amp_mux->num_items].index = i; - amp_mux->num_items++; - } - - if (spec->num_amps > 1) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX, - "Amp Selector Capture Switch", 0); - if (err < 0) - return err; - } - return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL, - "Amp Capture Volume", - HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT)); -} - - /* create PC beep volume controls */ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, hda_nid_t nid) @@ -3869,11 +3743,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out if (err < 0) return err; } - if (spec->num_amps > 0) { - err = stac92xx_auto_create_amp_output_ctls(codec); - if (err < 0) - return err; - } if (spec->num_dmics > 0 && !spec->dinput_mux) if ((err = stac92xx_auto_create_dmic_input_ctls(codec, &spec->autocfg)) < 0) @@ -3910,7 +3779,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out spec->dinput_mux = &spec->private_dimux; spec->sinput_mux = &spec->private_smux; spec->mono_mux = &spec->private_mono_mux; - spec->amp_mux = &spec->private_amp_mux; return 1; } -- cgit v0.10.2 From 54c38444fad6a99b4b19512f8f0055d69115e69e Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 7 Apr 2009 19:13:15 -0400 Subject: [libata] EH: freeze port before aborting commands Call the ->freeze() hook before aborting qc's, because some hardware requires special handling prior to accessing the taskfile registers (for diagnosis/analysis/reset). Most notably, hardware may wish to disable the DMA engine or interrupts in the ->freeze() hook. Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 79711b6..9159abe 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -999,7 +999,9 @@ static void __ata_port_freeze(struct ata_port *ap) * ata_port_freeze - abort & freeze port * @ap: ATA port to freeze * - * Abort and freeze @ap. + * Abort and freeze @ap. The freeze operation must be called + * first, because some hardware requires special operations + * before the taskfile registers are accessible. * * LOCKING: * spin_lock_irqsave(host lock) @@ -1013,8 +1015,8 @@ int ata_port_freeze(struct ata_port *ap) WARN_ON(!ap->ops->error_handler); - nr_aborted = ata_port_abort(ap); __ata_port_freeze(ap); + nr_aborted = ata_port_abort(ap); return nr_aborted; } -- cgit v0.10.2 From 2fc37adba0fb05760b8635c6706773af828ccf3c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 7 Apr 2009 19:18:32 -0400 Subject: [libata] sata_sil: disable DMA engine in sil_freeze() We must disable the DMA engine before accessing taskfile registers. Signed-off-by: Jeff Garzik diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 35bd5cc..3cb69d5 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -565,6 +565,19 @@ static void sil_freeze(struct ata_port *ap) tmp |= SIL_MASK_IDE0_INT << ap->port_no; writel(tmp, mmio_base + SIL_SYSCFG); readl(mmio_base + SIL_SYSCFG); /* flush */ + + /* Ensure DMA_ENABLE is off. + * + * This is because the controller will not give us access to the + * taskfile registers while a DMA is in progress + */ + iowrite8(ioread8(ap->ioaddr.bmdma_addr) & ~SIL_DMA_ENABLE, + ap->ioaddr.bmdma_addr); + + /* According to ata_bmdma_stop, an HDMA transition requires + * on PIO cycle. But we can't read a taskfile register. + */ + ioread8(ap->ioaddr.bmdma_addr); } static void sil_thaw(struct ata_port *ap) -- cgit v0.10.2 From 388539f3ff0cf1de926b03f94e1eec112358f74d Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 27 Jul 2009 09:24:35 +0800 Subject: [libata] add DMA setup FIS auto-activate feature Hopefully results in fewer on-the-wire FIS's and no breakage. We'll see! Signed-off-by: Shaohua Li Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index fe3eba5..7a3124a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -2869,7 +2869,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* prepare host */ if (hpriv->cap & HOST_CAP_NCQ) - pi.flags |= ATA_FLAG_NCQ; + pi.flags |= ATA_FLAG_NCQ | ATA_FLAG_FPDMA_AA; if (hpriv->cap & HOST_CAP_PMP) pi.flags |= ATA_FLAG_PMP; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 072ba5e..98af50f 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2299,29 +2299,49 @@ static inline u8 ata_dev_knobble(struct ata_device *dev) return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); } -static void ata_dev_config_ncq(struct ata_device *dev, +static int ata_dev_config_ncq(struct ata_device *dev, char *desc, size_t desc_sz) { struct ata_port *ap = dev->link->ap; int hdepth = 0, ddepth = ata_id_queue_depth(dev->id); + unsigned int err_mask; + char *aa_desc = ""; if (!ata_id_has_ncq(dev->id)) { desc[0] = '\0'; - return; + return 0; } if (dev->horkage & ATA_HORKAGE_NONCQ) { snprintf(desc, desc_sz, "NCQ (not used)"); - return; + return 0; } if (ap->flags & ATA_FLAG_NCQ) { hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1); dev->flags |= ATA_DFLAG_NCQ; } + if (!(dev->horkage & ATA_HORKAGE_BROKEN_FPDMA_AA) && + (ap->flags & ATA_FLAG_FPDMA_AA) && + ata_id_has_fpdma_aa(dev->id)) { + err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE, + SATA_FPDMA_AA); + if (err_mask) { + ata_dev_printk(dev, KERN_ERR, "failed to enable AA" + "(error_mask=0x%x)\n", err_mask); + if (err_mask != AC_ERR_DEV) { + dev->horkage |= ATA_HORKAGE_BROKEN_FPDMA_AA; + return -EIO; + } + } else + aa_desc = ", AA"; + } + if (hdepth >= ddepth) - snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth); + snprintf(desc, desc_sz, "NCQ (depth %d)%s", ddepth, aa_desc); else - snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth); + snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth, + ddepth, aa_desc); + return 0; } /** @@ -2461,7 +2481,7 @@ int ata_dev_configure(struct ata_device *dev) if (ata_id_has_lba(id)) { const char *lba_desc; - char ncq_desc[20]; + char ncq_desc[24]; lba_desc = "LBA"; dev->flags |= ATA_DFLAG_LBA; @@ -2475,7 +2495,9 @@ int ata_dev_configure(struct ata_device *dev) } /* config NCQ */ - ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); + rc = ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); + if (rc) + return rc; /* print device info to dmesg */ if (ata_msg_drv(ap) && print_info) { diff --git a/include/linux/ata.h b/include/linux/ata.h index 9c75921..f549405 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -306,6 +306,7 @@ enum { /* SETFEATURE Sector counts for SATA features */ SATA_AN = 0x05, /* Asynchronous Notification */ SATA_DIPM = 0x03, /* Device Initiated Power Management */ + SATA_FPDMA_AA = 0x02, /* DMA Setup FIS Auto-Activate */ /* feature values for SET_MAX */ ATA_SET_MAX_ADDR = 0x00, @@ -525,6 +526,9 @@ static inline int ata_is_data(u8 prot) #define ata_id_has_atapi_AN(id) \ ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ ((id)[78] & (1 << 5)) ) +#define ata_id_has_fpdma_aa(id) \ + ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ + ((id)[78] & (1 << 2)) ) #define ata_id_iordy_disable(id) ((id)[ATA_ID_CAPABILITY] & (1 << 10)) #define ata_id_has_iordy(id) ((id)[ATA_ID_CAPABILITY] & (1 << 11)) #define ata_id_u32(id,n) \ diff --git a/include/linux/libata.h b/include/linux/libata.h index e5b6e33..d3f7cab 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -190,6 +190,7 @@ enum { ATA_FLAG_NO_POWEROFF_SPINDOWN = (1 << 11), /* don't spindown before poweroff */ ATA_FLAG_NO_HIBERNATE_SPINDOWN = (1 << 12), /* don't spindown before hibernation */ ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_FPDMA_AA = (1 << 14), /* driver supports Auto-Activate */ ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */ @@ -386,6 +387,7 @@ enum { ATA_HORKAGE_FIRMWARE_WARN = (1 << 12), /* firmware update warning */ ATA_HORKAGE_1_5_GBPS = (1 << 13), /* force 1.5 Gbps */ ATA_HORKAGE_NOSETXFER = (1 << 14), /* skip SETXFER, SATA only */ + ATA_HORKAGE_BROKEN_FPDMA_AA = (1 << 15), /* skip AA */ /* DMA mask for user DMA control: User visible values; DO NOT renumber */ -- cgit v0.10.2 From 1e641060c4b564e820abdb6a4c7a603a0d386250 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 17 Jul 2009 11:58:33 +0900 Subject: libata: clear eh_info on reset completion Resets are done with port frozen but some controllers still issue interrupts during reset and they may end up recording error conditions in ehi leading to unnecessary EH retrials. This patch makes ata_eh_reset() clear ehi on reset completion. As reset is the most severe recovery action, there's nothing to lose by clearing ehi on its completion. Signed-off-by: Tejun Heo Reported-by: Zdenek Kaspar Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 9159abe..2c34de8 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2576,11 +2576,17 @@ int ata_eh_reset(struct ata_link *link, int classify, postreset(slave, classes); } - /* clear cached SError */ + /* + * Some controllers can't be frozen very well and may set + * spuruious error conditions during reset. Clear accumulated + * error information. As reset is the final recovery action, + * nothing is lost by doing this. + */ spin_lock_irqsave(link->ap->lock, flags); - link->eh_info.serror = 0; + memset(&link->eh_info, 0, sizeof(link->eh_info)); if (slave) - slave->eh_info.serror = 0; + memset(&slave->eh_info, 0, sizeof(link->eh_info)); + ap->pflags &= ~ATA_PFLAG_EH_PENDING; spin_unlock_irqrestore(link->ap->lock, flags); /* Make sure onlineness and classification result correspond. -- cgit v0.10.2 From 6521148c6449724c3b707820b9c535c7e8b8afcd Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Tue, 14 Jul 2009 20:43:39 -0600 Subject: libata: add command name parsing for error output This patch improve libata's output for error/notification messages to allow easier comprehension and debugging: When ATAPI commands issued through the SCSI layer fail, use SCSI functions to print the CDB in human-readable form instead of just dumping out the CDB in hex. Print out the name of the failed command (as defined by the ATA specification) in error handling output along with the raw register contents. When reporting status of ACPI taskfile commands executed on resume, also output the names of the commands being executed (or not) in readable form. Since the extra data for printing command names increases kernel size slightly, a config option has been added to allow disabling command name output (as well as some of the error register parsing) for those highly sensitive to kernel text size. Signed-off-by: Robert Hancock Signed-off-by: Jeff Garzik diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index b17c57f..8e64d3c 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -26,6 +26,17 @@ config ATA_NONSTANDARD bool default n +config ATA_VERBOSE_ERROR + bool "Verbose ATA error reporting" + default y + help + This option adds parsing of ATA command descriptions and error bits + in libata kernel output, making it easier to interpret. + This option will enlarge the kernel by approx. 6KB. Disable it only + if kernel size is more important than ease of debugging. + + If unsure, say Y. + config ATA_ACPI bool "ATA ACPI Support" depends on ACPI && PCI diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index ac176da..01964b6 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -689,6 +689,7 @@ static int ata_acpi_run_tf(struct ata_device *dev, struct ata_taskfile tf, ptf, rtf; unsigned int err_mask; const char *level; + const char *descr; char msg[60]; int rc; @@ -736,11 +737,13 @@ static int ata_acpi_run_tf(struct ata_device *dev, snprintf(msg, sizeof(msg), "filtered out"); rc = 0; } + descr = ata_get_cmd_descript(tf.command); ata_dev_printk(dev, level, - "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x %s\n", + "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x (%s) %s\n", tf.command, tf.feature, tf.nsect, tf.lbal, - tf.lbam, tf.lbah, tf.device, msg); + tf.lbam, tf.lbah, tf.device, + (descr ? descr : "unknown"), msg); return rc; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 2c34de8..a04488f 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "../scsi/scsi_transport_api.h" #include @@ -2112,6 +2113,116 @@ void ata_eh_autopsy(struct ata_port *ap) } /** + * ata_get_cmd_descript - get description for ATA command + * @command: ATA command code to get description for + * + * Return a textual description of the given command, or NULL if the + * command is not known. + * + * LOCKING: + * None + */ +const char *ata_get_cmd_descript(u8 command) +{ +#ifdef CONFIG_ATA_VERBOSE_ERROR + static const struct + { + u8 command; + const char *text; + } cmd_descr[] = { + { ATA_CMD_DEV_RESET, "DEVICE RESET" }, + { ATA_CMD_CHK_POWER, "CHECK POWER MODE" }, + { ATA_CMD_STANDBY, "STANDBY" }, + { ATA_CMD_IDLE, "IDLE" }, + { ATA_CMD_EDD, "EXECUTE DEVICE DIAGNOSTIC" }, + { ATA_CMD_DOWNLOAD_MICRO, "DOWNLOAD MICROCODE" }, + { ATA_CMD_NOP, "NOP" }, + { ATA_CMD_FLUSH, "FLUSH CACHE" }, + { ATA_CMD_FLUSH_EXT, "FLUSH CACHE EXT" }, + { ATA_CMD_ID_ATA, "IDENTIFY DEVICE" }, + { ATA_CMD_ID_ATAPI, "IDENTIFY PACKET DEVICE" }, + { ATA_CMD_SERVICE, "SERVICE" }, + { ATA_CMD_READ, "READ DMA" }, + { ATA_CMD_READ_EXT, "READ DMA EXT" }, + { ATA_CMD_READ_QUEUED, "READ DMA QUEUED" }, + { ATA_CMD_READ_STREAM_EXT, "READ STREAM EXT" }, + { ATA_CMD_READ_STREAM_DMA_EXT, "READ STREAM DMA EXT" }, + { ATA_CMD_WRITE, "WRITE DMA" }, + { ATA_CMD_WRITE_EXT, "WRITE DMA EXT" }, + { ATA_CMD_WRITE_QUEUED, "WRITE DMA QUEUED EXT" }, + { ATA_CMD_WRITE_STREAM_EXT, "WRITE STREAM EXT" }, + { ATA_CMD_WRITE_STREAM_DMA_EXT, "WRITE STREAM DMA EXT" }, + { ATA_CMD_WRITE_FUA_EXT, "WRITE DMA FUA EXT" }, + { ATA_CMD_WRITE_QUEUED_FUA_EXT, "WRITE DMA QUEUED FUA EXT" }, + { ATA_CMD_FPDMA_READ, "READ FPDMA QUEUED" }, + { ATA_CMD_FPDMA_WRITE, "WRITE FPDMA QUEUED" }, + { ATA_CMD_PIO_READ, "READ SECTOR(S)" }, + { ATA_CMD_PIO_READ_EXT, "READ SECTOR(S) EXT" }, + { ATA_CMD_PIO_WRITE, "WRITE SECTOR(S)" }, + { ATA_CMD_PIO_WRITE_EXT, "WRITE SECTOR(S) EXT" }, + { ATA_CMD_READ_MULTI, "READ MULTIPLE" }, + { ATA_CMD_READ_MULTI_EXT, "READ MULTIPLE EXT" }, + { ATA_CMD_WRITE_MULTI, "WRITE MULTIPLE" }, + { ATA_CMD_WRITE_MULTI_EXT, "WRITE MULTIPLE EXT" }, + { ATA_CMD_WRITE_MULTI_FUA_EXT, "WRITE MULTIPLE FUA EXT" }, + { ATA_CMD_SET_FEATURES, "SET FEATURES" }, + { ATA_CMD_SET_MULTI, "SET MULTIPLE MODE" }, + { ATA_CMD_VERIFY, "READ VERIFY SECTOR(S)" }, + { ATA_CMD_VERIFY_EXT, "READ VERIFY SECTOR(S) EXT" }, + { ATA_CMD_WRITE_UNCORR_EXT, "WRITE UNCORRECTABLE EXT" }, + { ATA_CMD_STANDBYNOW1, "STANDBY IMMEDIATE" }, + { ATA_CMD_IDLEIMMEDIATE, "IDLE IMMEDIATE" }, + { ATA_CMD_SLEEP, "SLEEP" }, + { ATA_CMD_INIT_DEV_PARAMS, "INITIALIZE DEVICE PARAMETERS" }, + { ATA_CMD_READ_NATIVE_MAX, "READ NATIVE MAX ADDRESS" }, + { ATA_CMD_READ_NATIVE_MAX_EXT, "READ NATIVE MAX ADDRESS EXT" }, + { ATA_CMD_SET_MAX, "SET MAX ADDRESS" }, + { ATA_CMD_SET_MAX_EXT, "SET MAX ADDRESS EXT" }, + { ATA_CMD_READ_LOG_EXT, "READ LOG EXT" }, + { ATA_CMD_WRITE_LOG_EXT, "WRITE LOG EXT" }, + { ATA_CMD_READ_LOG_DMA_EXT, "READ LOG DMA EXT" }, + { ATA_CMD_WRITE_LOG_DMA_EXT, "WRITE LOG DMA EXT" }, + { ATA_CMD_TRUSTED_RCV, "TRUSTED RECEIVE" }, + { ATA_CMD_TRUSTED_RCV_DMA, "TRUSTED RECEIVE DMA" }, + { ATA_CMD_TRUSTED_SND, "TRUSTED SEND" }, + { ATA_CMD_TRUSTED_SND_DMA, "TRUSTED SEND DMA" }, + { ATA_CMD_PMP_READ, "READ BUFFER" }, + { ATA_CMD_PMP_WRITE, "WRITE BUFFER" }, + { ATA_CMD_CONF_OVERLAY, "DEVICE CONFIGURATION OVERLAY" }, + { ATA_CMD_SEC_SET_PASS, "SECURITY SET PASSWORD" }, + { ATA_CMD_SEC_UNLOCK, "SECURITY UNLOCK" }, + { ATA_CMD_SEC_ERASE_PREP, "SECURITY ERASE PREPARE" }, + { ATA_CMD_SEC_ERASE_UNIT, "SECURITY ERASE UNIT" }, + { ATA_CMD_SEC_FREEZE_LOCK, "SECURITY FREEZE LOCK" }, + { ATA_CMD_SEC_DISABLE_PASS, "SECURITY DISABLE PASSWORD" }, + { ATA_CMD_CONFIG_STREAM, "CONFIGURE STREAM" }, + { ATA_CMD_SMART, "SMART" }, + { ATA_CMD_MEDIA_LOCK, "DOOR LOCK" }, + { ATA_CMD_MEDIA_UNLOCK, "DOOR UNLOCK" }, + { ATA_CMD_CHK_MED_CRD_TYP, "CHECK MEDIA CARD TYPE" }, + { ATA_CMD_CFA_REQ_EXT_ERR, "CFA REQUEST EXTENDED ERROR" }, + { ATA_CMD_CFA_WRITE_NE, "CFA WRITE SECTORS WITHOUT ERASE" }, + { ATA_CMD_CFA_TRANS_SECT, "CFA TRANSLATE SECTOR" }, + { ATA_CMD_CFA_ERASE, "CFA ERASE SECTORS" }, + { ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" }, + { ATA_CMD_READ_LONG, "READ LONG (with retries)" }, + { ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" }, + { ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" }, + { ATA_CMD_WRITE_LONG_ONCE, "WRITE LONG (without retries)" }, + { ATA_CMD_RESTORE, "RECALIBRATE" }, + { 0, NULL } /* terminate list */ + }; + + unsigned int i; + for (i = 0; cmd_descr[i].text; i++) + if (cmd_descr[i].command == command) + return cmd_descr[i].text; +#endif + + return NULL; +} + +/** * ata_eh_link_report - report error handling to user * @link: ATA link EH is going on * @@ -2177,6 +2288,7 @@ static void ata_eh_link_report(struct ata_link *link) ata_link_printk(link, KERN_ERR, "%s\n", desc); } +#ifdef CONFIG_ATA_VERBOSE_ERROR if (ehc->i.serror) ata_link_printk(link, KERN_ERR, "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n", @@ -2197,6 +2309,7 @@ static void ata_eh_link_report(struct ata_link *link) ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "", ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "", ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : ""); +#endif for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); @@ -2228,14 +2341,23 @@ static void ata_eh_link_report(struct ata_link *link) dma_str[qc->dma_dir]); } - if (ata_is_atapi(qc->tf.protocol)) - snprintf(cdb_buf, sizeof(cdb_buf), + if (ata_is_atapi(qc->tf.protocol)) { + if (qc->scsicmd) + scsi_print_command(qc->scsicmd); + else + snprintf(cdb_buf, sizeof(cdb_buf), "cdb %02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x\n ", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11], cdb[12], cdb[13], cdb[14], cdb[15]); + } else { + const char *descr = ata_get_cmd_descript(cmd->command); + if (descr) + ata_dev_printk(qc->dev, KERN_ERR, + "failed command: %s\n", descr); + } ata_dev_printk(qc->dev, KERN_ERR, "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " @@ -2254,6 +2376,7 @@ static void ata_eh_link_report(struct ata_link *link) res->device, qc->err_mask, ata_err_string(qc->err_mask), qc->err_mask & AC_ERR_NCQ ? " " : ""); +#ifdef CONFIG_ATA_VERBOSE_ERROR if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) { if (res->command & ATA_BUSY) @@ -2277,6 +2400,7 @@ static void ata_eh_link_report(struct ata_link *link) res->feature & ATA_UNC ? "UNC " : "", res->feature & ATA_IDNF ? "IDNF " : "", res->feature & ATA_ABORTED ? "ABRT " : ""); +#endif } } diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 89a1e00..be8e262 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -164,6 +164,7 @@ extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, extern void ata_eh_done(struct ata_link *link, struct ata_device *dev, unsigned int action); extern void ata_eh_autopsy(struct ata_port *ap); +const char *ata_get_cmd_descript(u8 command); extern void ata_eh_report(struct ata_port *ap); extern int ata_eh_reset(struct ata_link *link, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, diff --git a/include/linux/ata.h b/include/linux/ata.h index f549405..6299a25 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -210,15 +210,25 @@ enum { ATA_CMD_STANDBY = 0xE2, /* place in standby power mode */ ATA_CMD_IDLE = 0xE3, /* place in idle power mode */ ATA_CMD_EDD = 0x90, /* execute device diagnostic */ + ATA_CMD_DOWNLOAD_MICRO = 0x92, + ATA_CMD_NOP = 0x00, ATA_CMD_FLUSH = 0xE7, ATA_CMD_FLUSH_EXT = 0xEA, ATA_CMD_ID_ATA = 0xEC, ATA_CMD_ID_ATAPI = 0xA1, + ATA_CMD_SERVICE = 0xA2, ATA_CMD_READ = 0xC8, ATA_CMD_READ_EXT = 0x25, + ATA_CMD_READ_QUEUED = 0x26, + ATA_CMD_READ_STREAM_EXT = 0x2B, + ATA_CMD_READ_STREAM_DMA_EXT = 0x2A, ATA_CMD_WRITE = 0xCA, ATA_CMD_WRITE_EXT = 0x35, + ATA_CMD_WRITE_QUEUED = 0x36, + ATA_CMD_WRITE_STREAM_EXT = 0x3B, + ATA_CMD_WRITE_STREAM_DMA_EXT = 0x3A, ATA_CMD_WRITE_FUA_EXT = 0x3D, + ATA_CMD_WRITE_QUEUED_FUA_EXT = 0x3E, ATA_CMD_FPDMA_READ = 0x60, ATA_CMD_FPDMA_WRITE = 0x61, ATA_CMD_PIO_READ = 0x20, @@ -235,6 +245,7 @@ enum { ATA_CMD_PACKET = 0xA0, ATA_CMD_VERIFY = 0x40, ATA_CMD_VERIFY_EXT = 0x42, + ATA_CMD_WRITE_UNCORR_EXT = 0x45, ATA_CMD_STANDBYNOW1 = 0xE0, ATA_CMD_IDLEIMMEDIATE = 0xE1, ATA_CMD_SLEEP = 0xE6, @@ -243,15 +254,34 @@ enum { ATA_CMD_READ_NATIVE_MAX_EXT = 0x27, ATA_CMD_SET_MAX = 0xF9, ATA_CMD_SET_MAX_EXT = 0x37, - ATA_CMD_READ_LOG_EXT = 0x2f, + ATA_CMD_READ_LOG_EXT = 0x2F, + ATA_CMD_WRITE_LOG_EXT = 0x3F, + ATA_CMD_READ_LOG_DMA_EXT = 0x47, + ATA_CMD_WRITE_LOG_DMA_EXT = 0x57, + ATA_CMD_TRUSTED_RCV = 0x5C, + ATA_CMD_TRUSTED_RCV_DMA = 0x5D, + ATA_CMD_TRUSTED_SND = 0x5E, + ATA_CMD_TRUSTED_SND_DMA = 0x5F, ATA_CMD_PMP_READ = 0xE4, ATA_CMD_PMP_WRITE = 0xE8, ATA_CMD_CONF_OVERLAY = 0xB1, + ATA_CMD_SEC_SET_PASS = 0xF1, + ATA_CMD_SEC_UNLOCK = 0xF2, + ATA_CMD_SEC_ERASE_PREP = 0xF3, + ATA_CMD_SEC_ERASE_UNIT = 0xF4, ATA_CMD_SEC_FREEZE_LOCK = 0xF5, + ATA_CMD_SEC_DISABLE_PASS = 0xF6, + ATA_CMD_CONFIG_STREAM = 0x51, ATA_CMD_SMART = 0xB0, ATA_CMD_MEDIA_LOCK = 0xDE, ATA_CMD_MEDIA_UNLOCK = 0xDF, ATA_CMD_DSM = 0x06, + ATA_CMD_CHK_MED_CRD_TYP = 0xD1, + ATA_CMD_CFA_REQ_EXT_ERR = 0x03, + ATA_CMD_CFA_WRITE_NE = 0x38, + ATA_CMD_CFA_TRANS_SECT = 0x87, + ATA_CMD_CFA_ERASE = 0xC0, + ATA_CMD_CFA_WRITE_MULT_NE = 0xCD, /* marked obsolete in the ATA/ATAPI-7 spec */ ATA_CMD_RESTORE = 0x10, -- cgit v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 09e031c..b3b6290 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 d0dfeef..de3a005 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 d3f7cab..76319bf 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 v0.10.2 From 87c8b22be201cc4c139f98ef5e0471dd15c01239 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 28 Jun 2009 09:26:17 -0700 Subject: drivers/ata: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: Jeff Garzik diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index abdd19f..e807cc3 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -213,7 +213,7 @@ static void octeon_cf_set_dmamode(struct ata_port *ap, struct ata_device *dev) * This is tI, C.F. spec. says 0, but Sony CF card requires * more, we use 20 nS. */ - dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, 20);; + dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, 20); dma_tim.s.dmack_h = ns_to_tim_reg(tim_mult, dma_ackh); dma_tim.s.dmarq = dma_arq; diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 8d890cc..4406902 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -405,7 +405,7 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance) struct ata_host *host = dev_instance; struct inic_host_priv *hpriv = host->private_data; u16 host_irq_stat; - int i, handled = 0;; + int i, handled = 0; host_irq_stat = readw(hpriv->mmio_base + HOST_IRQ_STAT); -- cgit v0.10.2 From 6b406782ad0408f9cb480c2e1b543d194e8206d0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Jun 2009 18:29:44 +0100 Subject: [libata] Add pata_rdc driver for RDC ATA devices From: Alan Cox Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 8e64d3c..ab2fa4e 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -597,6 +597,16 @@ config PATA_RB532 If unsure, say N. +config PATA_RDC + tristate "RDC PATA support" + depends on PCI + help + This option enables basic support for the later RDC PATA controllers + controllers via the new ATA layer. For the RDC 1010, you need to + enable the IT821X driver instead. + + If unsure, say N. + config PATA_RZ1000 tristate "PC Tech RZ1000 PATA support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 38906f9..463eb52 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o obj-$(CONFIG_PATA_QDI) += pata_qdi.o obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o +obj-$(CONFIG_PATA_RDC) += pata_rdc.o obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o diff --git a/drivers/ata/pata_rdc.c b/drivers/ata/pata_rdc.c new file mode 100644 index 0000000..c843a1e --- /dev/null +++ b/drivers/ata/pata_rdc.c @@ -0,0 +1,400 @@ +/* + * pata_rdc - Driver for later RDC PATA controllers + * + * This is actually a driver for hardware meeting + * INCITS 370-2004 (1510D): ATA Host Adapter Standards + * + * Based on ata_piix. + * + * 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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_rdc" +#define DRV_VERSION "0.01" + +struct rdc_host_priv { + u32 saved_iocfg; +}; + +/** + * rdc_pata_cable_detect - Probe host controller cable detect info + * @ap: Port for which cable detect info is desired + * + * Read 80c cable indicator from ATA PCI device's PCI config + * register. This register is normally set by firmware (BIOS). + * + * LOCKING: + * None (inherited from caller). + */ + +static int rdc_pata_cable_detect(struct ata_port *ap) +{ + struct rdc_host_priv *hpriv = ap->host->private_data; + u8 mask; + + /* check BIOS cable detect results */ + mask = 0x30 << (2 * ap->port_no); + if ((hpriv->saved_iocfg & mask) == 0) + return ATA_CBL_PATA40; + return ATA_CBL_PATA80; +} + +/** + * rdc_pata_prereset - prereset for PATA host controller + * @link: Target link + * @deadline: deadline jiffies for the operation + * + * LOCKING: + * None (inherited from caller). + */ +static int rdc_pata_prereset(struct ata_link *link, unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + + static const struct pci_bits rdc_enable_bits[] = { + { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ + { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */ + }; + + if (!pci_test_config_bits(pdev, &rdc_enable_bits[ap->port_no])) + return -ENOENT; + return ata_sff_prereset(link, deadline); +} + +/** + * rdc_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um + * + * Set PIO mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void rdc_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + unsigned int pio = adev->pio_mode - XFER_PIO_0; + struct pci_dev *dev = to_pci_dev(ap->host->dev); + unsigned int is_slave = (adev->devno != 0); + unsigned int master_port= ap->port_no ? 0x42 : 0x40; + unsigned int slave_port = 0x44; + u16 master_data; + u8 slave_data; + u8 udma_enable; + int control = 0; + + static const /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + if (pio >= 2) + control |= 1; /* TIME1 enable */ + if (ata_pio_need_iordy(adev)) + control |= 2; /* IE enable */ + + if (adev->class == ATA_DEV_ATA) + control |= 4; /* PPE enable */ + + /* PIO configuration clears DTE unconditionally. It will be + * programmed in set_dmamode which is guaranteed to be called + * after set_piomode if any DMA mode is available. + */ + pci_read_config_word(dev, master_port, &master_data); + if (is_slave) { + /* clear TIME1|IE1|PPE1|DTE1 */ + master_data &= 0xff0f; + /* Enable SITRE (separate slave timing register) */ + master_data |= 0x4000; + /* enable PPE1, IE1 and TIME1 as needed */ + master_data |= (control << 4); + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data &= (ap->port_no ? 0x0f : 0xf0); + /* Load the timing nibble for this slave */ + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) + << (ap->port_no ? 4 : 0); + } else { + /* clear ISP|RCT|TIME0|IE0|PPE0|DTE0 */ + master_data &= 0xccf0; + /* Enable PPE, IE and TIME as appropriate */ + master_data |= control; + /* load ISP and RCT */ + master_data |= + (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } + pci_write_config_word(dev, master_port, master_data); + if (is_slave) + pci_write_config_byte(dev, slave_port, slave_data); + + /* Ensure the UDMA bit is off - it will be turned back on if + UDMA is selected */ + + pci_read_config_byte(dev, 0x48, &udma_enable); + udma_enable &= ~(1 << (2 * ap->port_no + adev->devno)); + pci_write_config_byte(dev, 0x48, udma_enable); +} + +/** + * rdc_set_dmamode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: Drive in question + * + * Set UDMA mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void rdc_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + struct pci_dev *dev = to_pci_dev(ap->host->dev); + u8 master_port = ap->port_no ? 0x42 : 0x40; + u16 master_data; + u8 speed = adev->dma_mode; + int devid = adev->devno + 2 * ap->port_no; + u8 udma_enable = 0; + + static const /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pci_read_config_word(dev, master_port, &master_data); + pci_read_config_byte(dev, 0x48, &udma_enable); + + if (speed >= XFER_UDMA_0) { + unsigned int udma = adev->dma_mode - XFER_UDMA_0; + u16 udma_timing; + u16 ideconf; + int u_clock, u_speed; + + /* + * UDMA is handled by a combination of clock switching and + * selection of dividers + * + * Handy rule: Odd modes are UDMATIMx 01, even are 02 + * except UDMA0 which is 00 + */ + u_speed = min(2 - (udma & 1), udma); + if (udma == 5) + u_clock = 0x1000; /* 100Mhz */ + else if (udma > 2) + u_clock = 1; /* 66Mhz */ + else + u_clock = 0; /* 33Mhz */ + + udma_enable |= (1 << devid); + + /* Load the CT/RP selection */ + pci_read_config_word(dev, 0x4A, &udma_timing); + udma_timing &= ~(3 << (4 * devid)); + udma_timing |= u_speed << (4 * devid); + pci_write_config_word(dev, 0x4A, udma_timing); + + /* Select a 33/66/100Mhz clock */ + pci_read_config_word(dev, 0x54, &ideconf); + ideconf &= ~(0x1001 << devid); + ideconf |= u_clock << devid; + pci_write_config_word(dev, 0x54, ideconf); + } else { + /* + * MWDMA is driven by the PIO timings. We must also enable + * IORDY unconditionally along with TIME1. PPE has already + * been set when the PIO timing was set. + */ + unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0; + unsigned int control; + u8 slave_data; + const unsigned int needed_pio[3] = { + XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 + }; + int pio = needed_pio[mwdma] - XFER_PIO_0; + + control = 3; /* IORDY|TIME1 */ + + /* If the drive MWDMA is faster than it can do PIO then + we must force PIO into PIO0 */ + + if (adev->pio_mode < needed_pio[mwdma]) + /* Enable DMA timing only */ + control |= 8; /* PIO cycles in PIO0 */ + + if (adev->devno) { /* Slave */ + master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */ + master_data |= control << 4; + pci_read_config_byte(dev, 0x44, &slave_data); + slave_data &= (ap->port_no ? 0x0f : 0xf0); + /* Load the matching timing */ + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0); + pci_write_config_byte(dev, 0x44, slave_data); + } else { /* Master */ + master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY + and master timing bits */ + master_data |= control; + master_data |= + (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } + + udma_enable &= ~(1 << devid); + pci_write_config_word(dev, master_port, master_data); + } + pci_write_config_byte(dev, 0x48, udma_enable); +} + +static struct ata_port_operations rdc_pata_ops = { + .inherits = &ata_bmdma32_port_ops, + .cable_detect = rdc_pata_cable_detect, + .set_piomode = rdc_set_piomode, + .set_dmamode = rdc_set_dmamode, + .prereset = rdc_pata_prereset, +}; + +static struct ata_port_info rdc_port_info = { + + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + .port_ops = &rdc_pata_ops, +}; + +static struct scsi_host_template rdc_sht = { + ATA_BMDMA_SHT(DRV_NAME), +}; + +/** + * rdc_init_one - Register PIIX ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in rdc_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. We probe for combined mode (sigh), + * and then hand over control to libata, for it to do the rest. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int __devinit rdc_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int printed_version; + struct device *dev = &pdev->dev; + struct ata_port_info port_info[2]; + const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] }; + unsigned long port_flags; + struct ata_host *host; + struct rdc_host_priv *hpriv; + int rc; + + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); + + port_info[0] = rdc_port_info; + port_info[1] = rdc_port_info; + + port_flags = port_info[0].flags; + + /* enable device and prepare host */ + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; + + /* Save IOCFG, this will be used for cable detection, quirk + * detection and restoration on detach. + */ + pci_read_config_dword(pdev, 0x54, &hpriv->saved_iocfg); + + rc = ata_pci_sff_prepare_host(pdev, ppi, &host); + if (rc) + return rc; + host->private_data = hpriv; + + pci_intx(pdev, 1); + + host->flags |= ATA_HOST_PARALLEL_SCAN; + + pci_set_master(pdev); + return ata_pci_sff_activate_host(host, ata_sff_interrupt, &rdc_sht); +} + +static void rdc_remove_one(struct pci_dev *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct rdc_host_priv *hpriv = host->private_data; + + pci_write_config_dword(pdev, 0x54, hpriv->saved_iocfg); + + ata_pci_remove_one(pdev); +} + +static const struct pci_device_id rdc_pci_tbl[] = { + { PCI_DEVICE(0x17F3, 0x1011), }, + { PCI_DEVICE(0x17F3, 0x1012), }, + { } /* terminate list */ +}; + +static struct pci_driver rdc_pci_driver = { + .name = DRV_NAME, + .id_table = rdc_pci_tbl, + .probe = rdc_init_one, + .remove = rdc_remove_one, +}; + + +static int __init rdc_init(void) +{ + return pci_register_driver(&rdc_pci_driver); +} + +static void __exit rdc_exit(void) +{ + pci_unregister_driver(&rdc_pci_driver); +} + +module_init(rdc_init); +module_exit(rdc_exit); + +MODULE_AUTHOR("Alan Cox (based on ata_piix)"); +MODULE_DESCRIPTION("SCSI low-level driver for RDC PATA controllers"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, rdc_pci_tbl); +MODULE_VERSION(DRV_VERSION); -- cgit v0.10.2 From f17259a31237cf0fd5c6c8cf2a4f9e6df405744b Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Wed, 24 Jun 2009 21:01:45 -0400 Subject: libata: Delegate nonrot flag setting to SCSI Now that the SCSI disk driver correctly handles non-rotational devices we can move setting the queue flag to SCSI. Signed-off-by: Martin K. Petersen Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index de3a005..5d7a1bd 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1119,10 +1119,6 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN); } else { - if (ata_id_is_ssd(dev->id)) - queue_flag_set_unlocked(QUEUE_FLAG_NONROT, - sdev->request_queue); - /* ATA devices must be sector aligned */ blk_queue_update_dma_alignment(sdev->request_queue, ATA_SECT_SIZE - 1); -- cgit v0.10.2 From 77cdec1ad527560b59ab8dbb063dbb3d0a138bf7 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 17 Jul 2009 19:13:47 +0100 Subject: libata: Export AHCI capabilities AHCI exports various capability bits that may be of interest to userspace such as whether the BIOS claims a port is hotpluggable or eSATA. Providing these via sysfs along with the version of the AHCI spec implemented by the host allows userspace to make policy decisions for things like ALPM. Signed-off-by: Matthew Garrett Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 7a3124a..be4c39f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -329,10 +329,24 @@ static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val); static void ahci_init_sw_activity(struct ata_link *link); +static ssize_t ahci_show_host_caps(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t ahci_show_host_version(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t ahci_show_port_cmd(struct device *dev, + struct device_attribute *attr, char *buf); + +DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); +DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL); +DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL); + static struct device_attribute *ahci_shost_attrs[] = { &dev_attr_link_power_management_policy, &dev_attr_em_message_type, &dev_attr_em_message, + &dev_attr_ahci_host_caps, + &dev_attr_ahci_host_version, + &dev_attr_ahci_port_cmd, NULL }; @@ -702,6 +716,36 @@ static void ahci_enable_ahci(void __iomem *mmio) WARN_ON(1); } +static ssize_t ahci_show_host_caps(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + struct ahci_host_priv *hpriv = ap->host->private_data; + + return sprintf(buf, "%x\n", hpriv->cap); +} + +static ssize_t ahci_show_host_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + + return sprintf(buf, "%x\n", readl(mmio + HOST_VERSION)); +} + +static ssize_t ahci_show_port_cmd(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + void __iomem *port_mmio = ahci_port_base(ap); + + return sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD)); +} + /** * ahci_save_initial_config - Save and fixup initial config values * @pdev: target PCI device -- cgit v0.10.2 From 4f1a0ee11d6f9c104c8e6a13dae995709a6922a8 Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Thu, 30 Jul 2009 14:11:29 -0600 Subject: sata_sil24: always set protocol override for non-ATAPI data commands The sil24 hardware has a built-in list of commands and associated protocols that gets used by default to decide how to handle a given command. However, if the command is not known to the controller then it presumably assumes it to be a non-data command which then causes protocol mismatch errors if the device ends up requesting data transfer. The new DATA SET MANAGEMENT - Trim command causes this issue since it's a DMA data-out command. Since we should always know best what protocol the command should be using, let's just set the override flag to inform the controller what protocol to use for all non-ATAPI commands with data transfer. Signed-off-by: Robert Hancock Tested-by: Mark Lord Signed-off-by: Jeff Garzik diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 77aa8d7..e6946fc 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -846,6 +846,17 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) if (!ata_is_atapi(qc->tf.protocol)) { prb = &cb->ata.prb; sge = cb->ata.sge; + if (ata_is_data(qc->tf.protocol)) { + u16 prot = 0; + ctrl = PRB_CTRL_PROTOCOL; + if (ata_is_ncq(qc->tf.protocol)) + prot |= PRB_PROT_NCQ; + if (qc->tf.flags & ATA_TFLAG_WRITE) + prot |= PRB_PROT_WRITE; + else + prot |= PRB_PROT_READ; + prb->prot = cpu_to_le16(prot); + } } else { prb = &cb->atapi.prb; sge = cb->atapi.sge; -- cgit v0.10.2 From fd38d7a0a0618656e491ed67af735bc4e3600367 Mon Sep 17 00:00:00 2001 From: "Graham, David" Date: Mon, 31 Aug 2009 14:12:51 +0000 Subject: e1000: Fix for e1000 kills IPMI on a tagged vlan. Enabling VLAN filters (VFE) when the primary interface is brought up (per commit 78ed11a) has caused problems for some users who manage their systems using IPMI over a VLAN. This is because when the driver enables the VLAN filter, this same filter table is enabled for the management channel, and the table is initially empty, which means that the IPMI/VLAN packets are filtered out and not received by the BMC. This is a problem only on e1000 class adapters, as it is only on e1000 that the filter table is common to the management and host streams. With this change, filtering is only enabled when one or more host VLANs exist, and is disabled when the last host VLAN is removed. VLAN filtering is always disabled when the primary interface is in promiscuous mode, and will be (re)enabled if VLANs exist when the interface exits promiscuous mode. Note that this does not completely resolve the issue for those using VLAN management, because if the host adds a VLAN, then the above problem occurs when that VLAN is enabled. However, it does mean the there is no problem for configurations where management is on a VLAN and the host is not. A complete solution to this issue would require further driver changes. The driver would need to discover if (and which) management VLANs are active before enabling VLAN filtering, so that it could ensure that the managed VLANs are included in the VLAN filter table. This discovery requires that the BMC identifies its VLAN in registers accessible to the driver, and at least on Dell PE2850 systems the BMC does not identify its VLAN to allow such discovery. Intel is pursuing this issue with the BMC vendor. Signed-off-by: Dave Graham Signed-off-by: Jeff Kirsher Tested-by: Krzysztof Piotr Oledzki Signed-off-by: David S. Miller diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index b3063e6..2c723b1 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2402,7 +2402,9 @@ static void e1000_set_rx_mode(struct net_device *netdev) rctl &= ~E1000_RCTL_MPE; } if (adapter->hw.mac_type != e1000_ich8lan) - rctl |= E1000_RCTL_VFE; + /* Enable VLAN filter if there is a VLAN */ + if (adapter->vlgrp) + rctl |= E1000_RCTL_VFE; } if (netdev->uc.count > rar_entries - 1) { @@ -4856,6 +4858,8 @@ static void e1000_vlan_rx_register(struct net_device *netdev, /* enable VLAN receive filtering */ rctl = er32(RCTL); rctl &= ~E1000_RCTL_CFIEN; + if (!(netdev->flags & IFF_PROMISC)) + rctl |= E1000_RCTL_VFE; ew32(RCTL, rctl); e1000_update_mng_vlan(adapter); } @@ -4866,6 +4870,11 @@ static void e1000_vlan_rx_register(struct net_device *netdev, ew32(CTRL, ctrl); if (adapter->hw.mac_type != e1000_ich8lan) { + /* disable VLAN receive filtering */ + rctl = er32(RCTL); + rctl &= ~E1000_RCTL_VFE; + ew32(RCTL, rctl); + if (adapter->mng_vlan_id != (u16)E1000_MNG_VLAN_NONE) { e1000_vlan_rx_kill_vid(netdev, -- cgit v0.10.2 From 8620a103b5e38d952280f3d97b5e1bcce8d7874c Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 1 Sep 2009 13:49:35 +0000 Subject: ixgbe: refactor link setup code Link code cleanup: a number of redundant functions and MAC variables are cleaned up, with some functions being consolidated into a single-purpose code path. Removed following deprecated link functions and mac variables * ixgbe_setup_copper_link_speed_82598 * ixgbe_setup_mac_link_speed_multispeed_fiber * ixgbe_setup_mac_link_speed_82599 * mac.autoneg, mac.autoneg_succeeded, phy.autoneg_wait_to_complete Signed-off-by: Mallikarjuna R Chilakala Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 916430f..cb7f0c3 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -41,8 +41,7 @@ static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg); -static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw); -static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, +static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete); @@ -156,8 +155,6 @@ static s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) /* Overwrite the link function pointers if copper PHY */ if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { mac->ops.setup_link = &ixgbe_setup_copper_link_82598; - mac->ops.setup_link_speed = - &ixgbe_setup_copper_link_speed_82598; mac->ops.get_link_capabilities = &ixgbe_get_copper_link_capabilities_82598; } @@ -465,13 +462,14 @@ out: } /** - * ixgbe_setup_mac_link_82598 - Configures MAC link settings + * ixgbe_start_mac_link_82598 - Configures MAC link settings * @hw: pointer to hardware structure * * Configures link settings based on values in the ixgbe_hw struct. * Restarts the link. Performs autonegotiation if needed. **/ -static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) +static s32 ixgbe_start_mac_link_82598(struct ixgbe_hw *hw, + bool autoneg_wait_to_complete) { u32 autoc_reg; u32 links_reg; @@ -484,7 +482,7 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); /* Only poll for autoneg to complete if specified to do so */ - if (hw->phy.autoneg_wait_to_complete) { + if (autoneg_wait_to_complete) { if ((autoc_reg & IXGBE_AUTOC_LMS_MASK) == IXGBE_AUTOC_LMS_KX4_AN || (autoc_reg & IXGBE_AUTOC_LMS_MASK) == @@ -600,7 +598,7 @@ out: /** - * ixgbe_setup_mac_link_speed_82598 - Set MAC link speed + * ixgbe_setup_mac_link_82598 - Set MAC link speed * @hw: pointer to hardware structure * @speed: new link speed * @autoneg: true if auto-negotiation enabled @@ -608,7 +606,7 @@ out: * * Set the link speed in the AUTOC register and restarts link. **/ -static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, +static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete) { @@ -638,14 +636,12 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, } if (status == 0) { - hw->phy.autoneg_wait_to_complete = autoneg_wait_to_complete; - /* * Setup and restart the link based on the new values in * ixgbe_hw This will write the AUTOC register based on the new * stored values */ - status = ixgbe_setup_mac_link_82598(hw); + status = ixgbe_start_mac_link_82598(hw, autoneg_wait_to_complete); } return status; @@ -653,29 +649,7 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, /** - * ixgbe_setup_copper_link_82598 - Setup copper link settings - * @hw: pointer to hardware structure - * - * Configures link settings based on values in the ixgbe_hw struct. - * Restarts the link. Performs autonegotiation if needed. Restart - * phy and wait for autonegotiate to finish. Then synchronize the - * MAC and PHY. - **/ -static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw) -{ - s32 status; - - /* Restart autonegotiation on PHY */ - status = hw->phy.ops.setup_link(hw); - - /* Set up MAC */ - ixgbe_setup_mac_link_82598(hw); - - return status; -} - -/** - * ixgbe_setup_copper_link_speed_82598 - Set the PHY autoneg advertised field + * ixgbe_setup_copper_link_82598 - Set the PHY autoneg advertised field * @hw: pointer to hardware structure * @speed: new link speed * @autoneg: true if autonegotiation enabled @@ -683,7 +657,7 @@ static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw) * * Sets the link speed in the AUTOC register in the MAC and restarts link. **/ -static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, +static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete) @@ -695,7 +669,7 @@ static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, autoneg_wait_to_complete); /* Set up MAC */ - ixgbe_setup_mac_link_82598(hw); + ixgbe_start_mac_link_82598(hw, autoneg_wait_to_complete); return status; } @@ -1163,7 +1137,6 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .read_analog_reg8 = &ixgbe_read_analog_reg8_82598, .write_analog_reg8 = &ixgbe_write_analog_reg8_82598, .setup_link = &ixgbe_setup_mac_link_82598, - .setup_link_speed = &ixgbe_setup_mac_link_speed_82598, .check_link = &ixgbe_check_mac_link_82598, .get_link_capabilities = &ixgbe_get_link_capabilities_82598, .led_on = &ixgbe_led_on_generic, diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 364b6d2..5ee5608 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -38,23 +38,23 @@ #define IXGBE_82599_MC_TBL_SIZE 128 #define IXGBE_82599_VFT_TBL_SIZE 128 -static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw); -static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, - bool autoneg_wait_to_complete); -static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw); -static s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete); +s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); +s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, + bool autoneg_wait_to_complete); +s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg); -static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw); -static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete); +static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) @@ -62,15 +62,9 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) struct ixgbe_mac_info *mac = &hw->mac; if (hw->phy.multispeed_fiber) { /* Set up dual speed SFP+ support */ - mac->ops.setup_link = - &ixgbe_setup_mac_link_multispeed_fiber; - mac->ops.setup_link_speed = - &ixgbe_setup_mac_link_speed_multispeed_fiber; + mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber; } else { - mac->ops.setup_link = - &ixgbe_setup_mac_link_82599; - mac->ops.setup_link_speed = - &ixgbe_setup_mac_link_speed_82599; + mac->ops.setup_link = &ixgbe_setup_mac_link_82599; } } @@ -178,8 +172,6 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) /* If copper media, overwrite with copper function pointers */ if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { mac->ops.setup_link = &ixgbe_setup_copper_link_82599; - mac->ops.setup_link_speed = - &ixgbe_setup_copper_link_speed_82599; mac->ops.get_link_capabilities = &ixgbe_get_copper_link_capabilities_82599; } @@ -354,13 +346,15 @@ out: } /** - * ixgbe_setup_mac_link_82599 - Setup MAC link settings + * ixgbe_start_mac_link_82599 - Setup MAC link settings * @hw: pointer to hardware structure + * @autoneg_wait_to_complete: true when waiting for completion is needed * * Configures link settings based on values in the ixgbe_hw struct. * Restarts the link. Performs autonegotiation if needed. **/ -static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) +s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, + bool autoneg_wait_to_complete) { u32 autoc_reg; u32 links_reg; @@ -373,7 +367,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); /* Only poll for autoneg to complete if specified to do so */ - if (hw->phy.autoneg_wait_to_complete) { + if (autoneg_wait_to_complete) { if ((autoc_reg & IXGBE_AUTOC_LMS_MASK) == IXGBE_AUTOC_LMS_KX4_KX_KR || (autoc_reg & IXGBE_AUTOC_LMS_MASK) == @@ -401,25 +395,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) } /** - * ixgbe_setup_mac_link_multispeed_fiber - Setup MAC link settings - * @hw: pointer to hardware structure - * - * Configures link settings based on values in the ixgbe_hw struct. - * Restarts the link for multi-speed fiber at 1G speed, if link - * fails at 10G. - * Performs autonegotiation if needed. - **/ -static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw) -{ - s32 status = 0; - ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_82599_AUTONEG; - status = ixgbe_setup_mac_link_speed_multispeed_fiber(hw, link_speed, - true, true); - return status; -} - -/** - * ixgbe_setup_mac_link_speed_multispeed_fiber - Set MAC link speed + * ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed * @hw: pointer to hardware structure * @speed: new link speed * @autoneg: true if autonegotiation enabled @@ -427,10 +403,10 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw) * * Set the link speed in the AUTOC register and restarts link. **/ -static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete) +s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete) { s32 status = 0; ixgbe_link_speed phy_link_speed; @@ -485,10 +461,10 @@ static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, /* Allow module to change analog characteristics (1G->10G) */ msleep(40); - status = ixgbe_setup_mac_link_speed_82599(hw, - IXGBE_LINK_SPEED_10GB_FULL, - autoneg, - autoneg_wait_to_complete); + status = ixgbe_setup_mac_link_82599(hw, + IXGBE_LINK_SPEED_10GB_FULL, + autoneg, + autoneg_wait_to_complete); if (status != 0) goto out; @@ -539,7 +515,7 @@ static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, /* Allow module to change analog characteristics (10G->1G) */ msleep(40); - status = ixgbe_setup_mac_link_speed_82599(hw, + status = ixgbe_setup_mac_link_82599(hw, IXGBE_LINK_SPEED_1GB_FULL, autoneg, autoneg_wait_to_complete); @@ -576,10 +552,10 @@ static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, * single highest speed that the user requested. */ if (speedcnt > 1) - status = ixgbe_setup_mac_link_speed_multispeed_fiber(hw, - highest_link_speed, - autoneg, - autoneg_wait_to_complete); + status = ixgbe_setup_mac_link_multispeed_fiber(hw, + highest_link_speed, + autoneg, + autoneg_wait_to_complete); out: return status; @@ -640,7 +616,7 @@ static s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, } /** - * ixgbe_setup_mac_link_speed_82599 - Set MAC link speed + * ixgbe_setup_mac_link_82599 - Set MAC link speed * @hw: pointer to hardware structure * @speed: new link speed * @autoneg: true if autonegotiation enabled @@ -648,10 +624,9 @@ static s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, * * Set the link speed in the AUTOC register and restarts link. **/ -static s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete) +s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, bool autoneg, + bool autoneg_wait_to_complete) { s32 status = 0; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); @@ -751,26 +726,7 @@ out: } /** - * ixgbe_setup_copper_link_82599 - Setup copper link settings - * @hw: pointer to hardware structure - * - * Restarts the link on PHY and then MAC. Performs autonegotiation if needed. - **/ -static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw) -{ - s32 status; - - /* Restart autonegotiation on PHY */ - status = hw->phy.ops.setup_link(hw); - - /* Set up MAC */ - ixgbe_setup_mac_link_82599(hw); - - return status; -} - -/** - * ixgbe_setup_copper_link_speed_82599 - Set the PHY autoneg advertised field + * ixgbe_setup_copper_link_82599 - Set the PHY autoneg advertised field * @hw: pointer to hardware structure * @speed: new link speed * @autoneg: true if autonegotiation enabled @@ -778,10 +734,10 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw) * * Restarts link on PHY and MAC based on settings passed in. **/ -static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete) +static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete) { s32 status; @@ -789,7 +745,7 @@ static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw, status = hw->phy.ops.setup_link_speed(hw, speed, autoneg, autoneg_wait_to_complete); /* Set up MAC */ - ixgbe_setup_mac_link_82599(hw); + ixgbe_start_mac_link_82599(hw, autoneg_wait_to_complete); return status; } @@ -2470,7 +2426,6 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .read_analog_reg8 = &ixgbe_read_analog_reg8_82599, .write_analog_reg8 = &ixgbe_write_analog_reg8_82599, .setup_link = &ixgbe_setup_mac_link_82599, - .setup_link_speed = &ixgbe_setup_mac_link_speed_82599, .check_link = &ixgbe_check_mac_link_82599, .get_link_capabilities = &ixgbe_get_link_capabilities_82599, .led_on = &ixgbe_led_on_generic, diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 1444ec5..026e94a 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -233,11 +233,11 @@ static int ixgbe_set_settings(struct net_device *netdev, return err; /* this sets the link speed and restarts auto-neg */ hw->mac.autotry_restart = true; - err = hw->mac.ops.setup_link_speed(hw, advertised, true, true); + err = hw->mac.ops.setup_link(hw, advertised, true, true); if (err) { DPRINTK(PROBE, INFO, "setup link failed with code %d\n", err); - hw->mac.ops.setup_link_speed(hw, old, true, true); + hw->mac.ops.setup_link(hw, old, true, true); } } else { /* in this case we currently only support 10Gb/FULL */ diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f907836..4042d878 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2516,7 +2516,7 @@ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter) static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw) { u32 autoneg; - bool link_up = false; + bool negotiation, link_up = false; u32 ret = IXGBE_ERR_LINK_SETUP; if (hw->mac.ops.check_link) @@ -2526,13 +2526,12 @@ static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw) goto link_cfg_out; if (hw->mac.ops.get_link_capabilities) - ret = hw->mac.ops.get_link_capabilities(hw, &autoneg, - &hw->mac.autoneg); + ret = hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); if (ret) goto link_cfg_out; - if (hw->mac.ops.setup_link_speed) - ret = hw->mac.ops.setup_link_speed(hw, autoneg, true, link_up); + if (hw->mac.ops.setup_link) + ret = hw->mac.ops.setup_link(hw, autoneg, negotiation, link_up); link_cfg_out: return ret; } @@ -4517,14 +4516,14 @@ static void ixgbe_multispeed_fiber_task(struct work_struct *work) multispeed_fiber_task); struct ixgbe_hw *hw = &adapter->hw; u32 autoneg; + bool negotiation; adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK; autoneg = hw->phy.autoneg_advertised; if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) - hw->mac.ops.get_link_capabilities(hw, &autoneg, - &hw->mac.autoneg); - if (hw->mac.ops.setup_link_speed) - hw->mac.ops.setup_link_speed(hw, autoneg, true, true); + hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); + if (hw->mac.ops.setup_link) + hw->mac.ops.setup_link(hw, autoneg, negotiation, true); adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; adapter->flags &= ~IXGBE_FLAG_IN_SFP_LINK_TASK; } diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index f0f3406..8ba90ee 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -2332,9 +2332,7 @@ struct ixgbe_mac_operations { s32 (*enable_rx_dma)(struct ixgbe_hw *, u32); /* Link */ - s32 (*setup_link)(struct ixgbe_hw *); - s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool, - bool); + s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool); s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); @@ -2406,8 +2404,6 @@ struct ixgbe_mac_info { u32 orig_autoc; u32 orig_autoc2; bool orig_link_settings_stored; - bool autoneg; - bool autoneg_succeeded; bool autotry_restart; }; @@ -2422,7 +2418,6 @@ struct ixgbe_phy_info { enum ixgbe_media_type media_type; bool reset_disable; ixgbe_autoneg_advertised autoneg_advertised; - bool autoneg_wait_to_complete; bool multispeed_fiber; }; -- cgit v0.10.2 From b7fdb714856541cd4b659a7b86ec04415e2809f7 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Tue, 1 Sep 2009 13:49:56 +0000 Subject: ixgbe: Properly disable DCB arbiters prior to applying changes When disabling the Rx and Tx data arbiters prior to configuration changes, the arbiters were not being shut down properly. This can create a race in the DCB hardware blocks, and potentially hang the arbiters. Also, the Tx descriptor arbiter shouldn't be disabled when applying configuration changes; disabling this arbiter can cause a Tx hang. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index 589f62c..ec8a252 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -145,8 +145,12 @@ s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, u32 credit_max = 0; u8 i = 0; - /* Disable the arbiter before changing parameters */ - IXGBE_WRITE_REG(hw, IXGBE_RTRPCS, IXGBE_RTRPCS_ARBDIS); + /* + * Disable the arbiter before changing parameters + * (always enable recycle mode; WSP) + */ + reg = IXGBE_RTRPCS_RRM | IXGBE_RTRPCS_RAC | IXGBE_RTRPCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTRPCS, reg); /* Map all traffic classes to their UP, 1 to 1 */ reg = 0; @@ -194,9 +198,6 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, u32 reg, max_credits; u8 i; - /* Disable the arbiter before changing parameters */ - IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, IXGBE_RTTDCS_ARBDIS); - /* Clear the per-Tx queue credits; we use per-TC instead */ for (i = 0; i < 128; i++) { IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, i); @@ -244,8 +245,14 @@ s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, u32 reg; u8 i; - /* Disable the arbiter before changing parameters */ - IXGBE_WRITE_REG(hw, IXGBE_RTTPCS, IXGBE_RTTPCS_ARBDIS); + /* + * Disable the arbiter before changing parameters + * (always enable recycle mode; SP; arb delay) + */ + reg = IXGBE_RTTPCS_TPPAC | IXGBE_RTTPCS_TPRM | + (IXGBE_RTTPCS_ARBD_DCB << IXGBE_RTTPCS_ARBD_SHIFT) | + IXGBE_RTTPCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTTPCS, reg); /* Map all traffic classes to their UP, 1 to 1 */ reg = 0; -- cgit v0.10.2 From c3c7432741211bc9f6b072958653647b9d5cdd5d Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 1 Sep 2009 13:50:14 +0000 Subject: ixgbe: Patch to fix 82599 multispeed fiber link issues when driver is loaded without any cable and reconnecting it to 1G partner In 82599 multi speed fiber case when driver is loaded without any cable and reconnecting the cable with a 1G partner does not bring up the link in 1Gb mode. When there is no link we first setup the link at 10G & 1G and then try to re-establish the link at highest speed 10G and thereby changing autoneg_advertised value to highest speed 10G. After connecting back the cable to a 1G link partner we never try 1G as autoneg advertised value is changed to link at 10G only. The following patch fixes the issue by properly initializing the autoneg_advertised value just before exiting from link setup routine. Signed-off-by: Mallikarjuna R Chilakala Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 5ee5608..61af47e 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -421,15 +421,6 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, hw->mac.ops.get_link_capabilities(hw, &phy_link_speed, &negotiation); speed &= phy_link_speed; - /* Set autoneg_advertised value based on input link speed */ - hw->phy.autoneg_advertised = 0; - - if (speed & IXGBE_LINK_SPEED_10GB_FULL) - hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; - - if (speed & IXGBE_LINK_SPEED_1GB_FULL) - hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; - /* * When the driver changes the link speeds that it can support, * it sets autotry_restart to true to indicate that we need to @@ -466,7 +457,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, autoneg, autoneg_wait_to_complete); if (status != 0) - goto out; + return status; /* Flap the tx laser if it has not already been done */ if (hw->mac.autotry_restart) { @@ -520,7 +511,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, autoneg, autoneg_wait_to_complete); if (status != 0) - goto out; + return status; /* Flap the tx laser if it has not already been done */ if (hw->mac.autotry_restart) { @@ -558,6 +549,15 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, autoneg_wait_to_complete); out: + /* Set autoneg_advertised value based on input link speed */ + hw->phy.autoneg_advertised = 0; + + if (speed & IXGBE_LINK_SPEED_10GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; + + if (speed & IXGBE_LINK_SPEED_1GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; + return status; } -- cgit v0.10.2 From ac06713d55d450cbc9ef871b1b238409238f0fe0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 1 Sep 2009 05:46:05 +0000 Subject: macvlan: Use compare_ether_addr_64bits() To speedup ether addresses compares, we can use compare_ether_addr_64bits() (all operands are guaranteed to be at least 8 bytes long) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index f893cd4..c85c46d 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -54,7 +54,7 @@ static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port, struct hlist_node *n; hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[addr[5]], hlist) { - if (!compare_ether_addr(vlan->dev->dev_addr, addr)) + if (!compare_ether_addr_64bits(vlan->dev->dev_addr, addr)) return vlan; } return NULL; @@ -92,7 +92,7 @@ static int macvlan_addr_busy(const struct macvlan_port *port, * currently in use by the underlying device or * another macvlan. */ - if (memcmp(port->dev->dev_addr, addr, ETH_ALEN) == 0) + if (!compare_ether_addr_64bits(port->dev->dev_addr, addr)) return 1; if (macvlan_hash_lookup(port, addr)) @@ -130,7 +130,7 @@ static void macvlan_broadcast(struct sk_buff *skb, dev->stats.multicast++; nskb->dev = dev; - if (!compare_ether_addr(eth->h_dest, dev->broadcast)) + if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast)) nskb->pkt_type = PACKET_BROADCAST; else nskb->pkt_type = PACKET_MULTICAST; -- cgit v0.10.2 From 885a136c52a8871175477baf3903e1c38751b35a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 1 Sep 2009 06:31:18 +0000 Subject: bonding: use compare_ether_addr_64bits() in ALB We can speedup ether addresses compares using compare_ether_addr_64bits() instead of memcmp(). We make sure all operands are at least 8 bytes long and 16bits aligned (or better, long word aligned if possible) Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 2108706..9b5936f 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -79,8 +79,15 @@ */ #define RLB_PROMISC_TIMEOUT 10*ALB_TIMER_TICKS_PER_SEC -static const u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; -static const u8 mac_v6_allmcast[ETH_ALEN] = {0x33,0x33,0x00,0x00,0x00,0x01}; +#ifndef __long_aligned +#define __long_aligned __attribute__((aligned((sizeof(long))))) +#endif +static const u8 mac_bcast[ETH_ALEN] __long_aligned = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; +static const u8 mac_v6_allmcast[ETH_ALEN] __long_aligned = { + 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 +}; static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; #pragma pack(1) @@ -460,8 +467,8 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) if (assigned_slave) { rx_hash_table[index].slave = assigned_slave; - if (memcmp(rx_hash_table[index].mac_dst, - mac_bcast, ETH_ALEN)) { + if (compare_ether_addr_64bits(rx_hash_table[index].mac_dst, + mac_bcast)) { bond_info->rx_hashtbl[index].ntt = 1; bond_info->rx_ntt = 1; /* A slave has been removed from the @@ -575,7 +582,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla client_info = &(bond_info->rx_hashtbl[hash_index]); if ((client_info->slave == slave) && - memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { + compare_ether_addr_64bits(client_info->mac_dst, mac_bcast)) { client_info->ntt = 1; ntt = 1; } @@ -616,9 +623,9 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip) * unicast mac address. */ if ((client_info->ip_src == src_ip) && - memcmp(client_info->slave->dev->dev_addr, - bond->dev->dev_addr, ETH_ALEN) && - memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { + compare_ether_addr_64bits(client_info->slave->dev->dev_addr, + bond->dev->dev_addr) && + compare_ether_addr_64bits(client_info->mac_dst, mac_bcast)) { client_info->ntt = 1; bond_info->rx_ntt = 1; } @@ -645,7 +652,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon if ((client_info->ip_src == arp->ip_src) && (client_info->ip_dst == arp->ip_dst)) { /* the entry is already assigned to this client */ - if (memcmp(arp->mac_dst, mac_bcast, ETH_ALEN)) { + if (compare_ether_addr_64bits(arp->mac_dst, mac_bcast)) { /* update mac address from arp */ memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); } @@ -680,7 +687,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); client_info->slave = assigned_slave; - if (memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { + if (compare_ether_addr_64bits(client_info->mac_dst, mac_bcast)) { client_info->ntt = 1; bond->alb_info.rx_ntt = 1; } else { @@ -1046,21 +1053,18 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla int perm_curr_diff; int perm_bond_diff; - perm_curr_diff = memcmp(slave->perm_hwaddr, - slave->dev->dev_addr, - ETH_ALEN); - perm_bond_diff = memcmp(slave->perm_hwaddr, - bond->dev->dev_addr, - ETH_ALEN); + perm_curr_diff = compare_ether_addr_64bits(slave->perm_hwaddr, + slave->dev->dev_addr); + perm_bond_diff = compare_ether_addr_64bits(slave->perm_hwaddr, + bond->dev->dev_addr); if (perm_curr_diff && perm_bond_diff) { struct slave *tmp_slave; int i, found = 0; bond_for_each_slave(bond, tmp_slave, i) { - if (!memcmp(slave->perm_hwaddr, - tmp_slave->dev->dev_addr, - ETH_ALEN)) { + if (!compare_ether_addr_64bits(slave->perm_hwaddr, + tmp_slave->dev->dev_addr)) { found = 1; break; } @@ -1114,10 +1118,10 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav * check uniqueness of slave's mac address against the other * slaves in the bond. */ - if (memcmp(slave->perm_hwaddr, bond->dev->dev_addr, ETH_ALEN)) { + if (compare_ether_addr_64bits(slave->perm_hwaddr, bond->dev->dev_addr)) { bond_for_each_slave(bond, tmp_slave1, i) { - if (!memcmp(tmp_slave1->dev->dev_addr, slave->dev->dev_addr, - ETH_ALEN)) { + if (!compare_ether_addr_64bits(tmp_slave1->dev->dev_addr, + slave->dev->dev_addr)) { found = 1; break; } @@ -1140,9 +1144,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav bond_for_each_slave(bond, tmp_slave1, i) { found = 0; bond_for_each_slave(bond, tmp_slave2, j) { - if (!memcmp(tmp_slave1->perm_hwaddr, - tmp_slave2->dev->dev_addr, - ETH_ALEN)) { + if (!compare_ether_addr_64bits(tmp_slave1->perm_hwaddr, + tmp_slave2->dev->dev_addr)) { found = 1; break; } @@ -1157,9 +1160,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav } if (!has_bond_addr) { - if (!memcmp(tmp_slave1->dev->dev_addr, - bond->dev->dev_addr, - ETH_ALEN)) { + if (!compare_ether_addr_64bits(tmp_slave1->dev->dev_addr, + bond->dev->dev_addr)) { has_bond_addr = tmp_slave1; } @@ -1313,7 +1315,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) case ETH_P_IP: { const struct iphdr *iph = ip_hdr(skb); - if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) || + if (!compare_ether_addr_64bits(eth_data->h_dest, mac_bcast) || (iph->daddr == ip_bcast) || (iph->protocol == IPPROTO_IGMP)) { do_tx_balance = 0; @@ -1327,7 +1329,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) /* IPv6 doesn't really use broadcast mac address, but leave * that here just in case. */ - if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { + if (!compare_ether_addr_64bits(eth_data->h_dest, mac_bcast)) { do_tx_balance = 0; break; } @@ -1335,7 +1337,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) /* IPv6 uses all-nodes multicast as an equivalent to * broadcasts in IPv4. */ - if (memcmp(eth_data->h_dest, mac_v6_allmcast, ETH_ALEN) == 0) { + if (!compare_ether_addr_64bits(eth_data->h_dest, mac_v6_allmcast)) { do_tx_balance = 0; break; } @@ -1660,8 +1662,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave struct slave *tmp_slave; /* find slave that is holding the bond's mac address */ bond_for_each_slave(bond, tmp_slave, i) { - if (!memcmp(tmp_slave->dev->dev_addr, - bond->dev->dev_addr, ETH_ALEN)) { + if (!compare_ether_addr_64bits(tmp_slave->dev->dev_addr, + bond->dev->dev_addr)) { swap_slave = tmp_slave; break; } @@ -1739,7 +1741,8 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) swap_slave = NULL; bond_for_each_slave(bond, slave, i) { - if (!memcmp(slave->dev->dev_addr, bond_dev->dev_addr, ETH_ALEN)) { + if (!compare_ether_addr_64bits(slave->dev->dev_addr, + bond_dev->dev_addr)) { swap_slave = slave; break; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 6290a50..6824771 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -163,9 +163,9 @@ struct slave { u32 original_flags; u32 original_mtu; u32 link_failure_count; + u8 perm_hwaddr[ETH_ALEN]; u16 speed; u8 duplex; - u8 perm_hwaddr[ETH_ALEN]; struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */ struct tlb_slave_info tlb_info; }; -- cgit v0.10.2 From 86393e52c3f1e2f6be18383f6ecdbcdc5727d545 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 29 Aug 2009 01:34:49 +0000 Subject: netns: embed ip6_dst_ops directly struct net::ipv6.ip6_dst_ops is separatedly dynamically allocated, but there is no fundamental reason for it. Embed it directly into struct netns_ipv6. For that: * move struct dst_ops into separate header to fix circular dependencies I honestly tried not to, it's pretty impossible to do other way * drop dynamical allocation, allocate together with netns For a change, remove struct dst_ops::dst_net, it's deducible by using container_of() given dst_ops pointer. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/include/net/dst.h b/include/net/dst.h index 7fc409c..5a900dd 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -8,6 +8,7 @@ #ifndef _NET_DST_H #define _NET_DST_H +#include #include #include #include @@ -102,28 +103,6 @@ struct dst_entry }; }; - -struct dst_ops -{ - unsigned short family; - __be16 protocol; - unsigned gc_thresh; - - int (*gc)(struct dst_ops *ops); - struct dst_entry * (*check)(struct dst_entry *, __u32 cookie); - void (*destroy)(struct dst_entry *); - void (*ifdown)(struct dst_entry *, - struct net_device *dev, int how); - struct dst_entry * (*negative_advice)(struct dst_entry *); - void (*link_failure)(struct sk_buff *); - void (*update_pmtu)(struct dst_entry *dst, u32 mtu); - int (*local_out)(struct sk_buff *skb); - - atomic_t entries; - struct kmem_cache *kmem_cachep; - struct net *dst_net; -}; - #ifdef __KERNEL__ static inline u32 diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h new file mode 100644 index 0000000..d1ff9b7 --- /dev/null +++ b/include/net/dst_ops.h @@ -0,0 +1,28 @@ +#ifndef _NET_DST_OPS_H +#define _NET_DST_OPS_H +#include + +struct dst_entry; +struct kmem_cachep; +struct net_device; +struct sk_buff; + +struct dst_ops { + unsigned short family; + __be16 protocol; + unsigned gc_thresh; + + int (*gc)(struct dst_ops *ops); + struct dst_entry * (*check)(struct dst_entry *, __u32 cookie); + void (*destroy)(struct dst_entry *); + void (*ifdown)(struct dst_entry *, + struct net_device *dev, int how); + struct dst_entry * (*negative_advice)(struct dst_entry *); + void (*link_failure)(struct sk_buff *); + void (*update_pmtu)(struct dst_entry *dst, u32 mtu); + int (*local_out)(struct sk_buff *skb); + + atomic_t entries; + struct kmem_cache *kmem_cachep; +}; +#endif diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index afab4e4..dfeb2d7 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -6,6 +6,7 @@ #ifndef __NETNS_IPV6_H__ #define __NETNS_IPV6_H__ +#include struct ctl_table_header; @@ -42,7 +43,7 @@ struct netns_ipv6 { struct timer_list ip6_fib_timer; struct hlist_head *fib_table_hash; struct fib6_table *fib6_main_tbl; - struct dst_ops *ip6_dst_ops; + struct dst_ops ip6_dst_ops; unsigned int ip6_rt_gc_expire; unsigned long ip6_rt_last_gc; #ifdef CONFIG_IPV6_MULTIPLE_TABLES diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 1473ee0..9ccfef3 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -665,7 +665,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *dad net->ipv6.sysctl.ip6_rt_gc_elasticity = 1; net->ipv6.sysctl.ip6_rt_gc_min_interval = 0; - ip6_dst_gc(net->ipv6.ip6_dst_ops); + ip6_dst_gc(&net->ipv6.ip6_dst_ops); net->ipv6.sysctl.ip6_rt_gc_elasticity = saved_rt_elasticity; @@ -970,7 +970,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, if (unlikely(idev == NULL)) return NULL; - rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); + rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); if (unlikely(rt == NULL)) { in6_dev_put(idev); goto out; @@ -1060,7 +1060,7 @@ static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg), static int ip6_dst_gc(struct dst_ops *ops) { unsigned long now = jiffies; - struct net *net = ops->dst_net; + struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops); int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval; int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size; int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; @@ -1154,7 +1154,7 @@ int ip6_route_add(struct fib6_config *cfg) goto out; } - rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); + rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); if (rt == NULL) { err = -ENOMEM; @@ -1643,7 +1643,7 @@ out: static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) { struct net *net = dev_net(ort->rt6i_dev); - struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); + struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); if (rt) { rt->u.dst.input = ort->u.dst.input; @@ -1923,7 +1923,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, int anycast) { struct net *net = dev_net(idev->dev); - struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); + struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); struct neighbour *neigh; if (rt == NULL) @@ -2501,7 +2501,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v) net->ipv6.rt6_stats->fib_rt_alloc, net->ipv6.rt6_stats->fib_rt_entries, net->ipv6.rt6_stats->fib_rt_cache, - atomic_read(&net->ipv6.ip6_dst_ops->entries), + atomic_read(&net->ipv6.ip6_dst_ops.entries), net->ipv6.rt6_stats->fib_discarded_routes); return 0; @@ -2637,7 +2637,7 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) if (table) { table[0].data = &net->ipv6.sysctl.flush_delay; - table[1].data = &net->ipv6.ip6_dst_ops->gc_thresh; + table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh; table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout; @@ -2655,12 +2655,8 @@ static int ip6_route_net_init(struct net *net) { int ret = -ENOMEM; - net->ipv6.ip6_dst_ops = kmemdup(&ip6_dst_ops_template, - sizeof(*net->ipv6.ip6_dst_ops), - GFP_KERNEL); - if (!net->ipv6.ip6_dst_ops) - goto out; - net->ipv6.ip6_dst_ops->dst_net = hold_net(net); + memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template, + sizeof(net->ipv6.ip6_dst_ops)); net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, sizeof(*net->ipv6.ip6_null_entry), @@ -2669,7 +2665,7 @@ static int ip6_route_net_init(struct net *net) goto out_ip6_dst_ops; net->ipv6.ip6_null_entry->u.dst.path = (struct dst_entry *)net->ipv6.ip6_null_entry; - net->ipv6.ip6_null_entry->u.dst.ops = net->ipv6.ip6_dst_ops; + net->ipv6.ip6_null_entry->u.dst.ops = &net->ipv6.ip6_dst_ops; #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, @@ -2679,7 +2675,7 @@ static int ip6_route_net_init(struct net *net) goto out_ip6_null_entry; net->ipv6.ip6_prohibit_entry->u.dst.path = (struct dst_entry *)net->ipv6.ip6_prohibit_entry; - net->ipv6.ip6_prohibit_entry->u.dst.ops = net->ipv6.ip6_dst_ops; + net->ipv6.ip6_prohibit_entry->u.dst.ops = &net->ipv6.ip6_dst_ops; net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, sizeof(*net->ipv6.ip6_blk_hole_entry), @@ -2688,7 +2684,7 @@ static int ip6_route_net_init(struct net *net) goto out_ip6_prohibit_entry; net->ipv6.ip6_blk_hole_entry->u.dst.path = (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; - net->ipv6.ip6_blk_hole_entry->u.dst.ops = net->ipv6.ip6_dst_ops; + net->ipv6.ip6_blk_hole_entry->u.dst.ops = &net->ipv6.ip6_dst_ops; #endif net->ipv6.sysctl.flush_delay = 0; @@ -2717,8 +2713,6 @@ out_ip6_null_entry: kfree(net->ipv6.ip6_null_entry); #endif out_ip6_dst_ops: - release_net(net->ipv6.ip6_dst_ops->dst_net); - kfree(net->ipv6.ip6_dst_ops); goto out; } @@ -2733,8 +2727,6 @@ static void ip6_route_net_exit(struct net *net) kfree(net->ipv6.ip6_prohibit_entry); kfree(net->ipv6.ip6_blk_hole_entry); #endif - release_net(net->ipv6.ip6_dst_ops->dst_net); - kfree(net->ipv6.ip6_dst_ops); } static struct pernet_operations ip6_route_net_ops = { -- cgit v0.10.2 From 89f56d1e91cfa535ccc6cc60e9e12e02682fd972 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 30 Aug 2009 07:04:42 +0000 Subject: tun: reuse struct sock fields As tun always has an embeedded struct sock, use sk and sk_receive_queue fields instead of duplicating them in tun_struct. Signed-off-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 5f7842e..589a44a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -103,13 +103,10 @@ struct tun_struct { uid_t owner; gid_t group; - struct sk_buff_head readq; - struct net_device *dev; struct fasync_struct *fasync; struct tap_filter txflt; - struct sock *sk; struct socket socket; #ifdef TUN_DEBUG @@ -155,7 +152,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file) tfile->tun = tun; tun->tfile = tfile; dev_hold(tun->dev); - sock_hold(tun->sk); + sock_hold(tun->socket.sk); atomic_inc(&tfile->count); out: @@ -171,7 +168,7 @@ static void __tun_detach(struct tun_struct *tun) netif_tx_unlock_bh(tun->dev); /* Drop read queue */ - skb_queue_purge(&tun->readq); + skb_queue_purge(&tun->socket.sk->sk_receive_queue); /* Drop the extra count on the net device */ dev_put(tun->dev); @@ -340,7 +337,7 @@ static void tun_free_netdev(struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); - sock_put(tun->sk); + sock_put(tun->socket.sk); } /* Net device open. */ @@ -374,7 +371,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) if (!check_filter(&tun->txflt, skb)) goto drop; - if (skb_queue_len(&tun->readq) >= dev->tx_queue_len) { + if (skb_queue_len(&tun->socket.sk->sk_receive_queue) >= dev->tx_queue_len) { if (!(tun->flags & TUN_ONE_QUEUE)) { /* Normal queueing mode. */ /* Packet scheduler handles dropping of further packets. */ @@ -391,7 +388,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) } /* Enqueue packet */ - skb_queue_tail(&tun->readq, skb); + skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb); dev->trans_start = jiffies; /* Notify and wake up reader process */ @@ -492,13 +489,13 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) if (!tun) return POLLERR; - sk = tun->sk; + sk = tun->socket.sk; DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name); poll_wait(file, &tun->socket.wait, wait); - if (!skb_queue_empty(&tun->readq)) + if (!skb_queue_empty(&sk->sk_receive_queue)) mask |= POLLIN | POLLRDNORM; if (sock_writeable(sk) || @@ -519,7 +516,7 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun, size_t prepad, size_t len, size_t linear, int noblock) { - struct sock *sk = tun->sk; + struct sock *sk = tun->socket.sk; struct sk_buff *skb; int err; @@ -787,7 +784,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, current->state = TASK_INTERRUPTIBLE; /* Read frames from the queue */ - if (!(skb=skb_dequeue(&tun->readq))) { + if (!(skb=skb_dequeue(&tun->socket.sk->sk_receive_queue))) { if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; @@ -824,8 +821,6 @@ static void tun_setup(struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); - skb_queue_head_init(&tun->readq); - tun->owner = -1; tun->group = -1; @@ -991,7 +986,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) sk->sk_write_space = tun_sock_write_space; sk->sk_sndbuf = INT_MAX; - tun->sk = sk; container_of(sk, struct tun_sock, sk)->tun = tun; tun_net_init(dev); @@ -1249,7 +1243,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, break; case TUNGETSNDBUF: - sndbuf = tun->sk->sk_sndbuf; + sndbuf = tun->socket.sk->sk_sndbuf; if (copy_to_user(argp, &sndbuf, sizeof(sndbuf))) ret = -EFAULT; break; @@ -1260,7 +1254,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, break; } - tun->sk->sk_sndbuf = sndbuf; + tun->socket.sk->sk_sndbuf = sndbuf; break; default: @@ -1343,7 +1337,7 @@ static int tun_chr_close(struct inode *inode, struct file *file) tun = tfile->tun; if (tun) - sock_put(tun->sk); + sock_put(tun->socket.sk); put_net(tfile->net); kfree(tfile); -- cgit v0.10.2 From 10547ae2c01acdace636e23c991b21fef05428b4 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 07:31:41 +0000 Subject: sky2: fix management of driver LED Observed by Mike McCormack. The LED bit here is just a software controlled value used to turn on one of the LED's on some boards. The register value was wrong, which could have been causing some power control issues. Get rid of problematic define use the correct mask. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index c7c0a5b..ba5180a 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -256,6 +256,9 @@ static void sky2_power_on(struct sky2_hw *hw) sky2_read32(hw, B2_GP_IO); } + + /* Turn on "driver loaded" LED */ + sky2_write16(hw, B0_CTST, Y2_LED_STAT_ON); } static void sky2_power_aux(struct sky2_hw *hw) @@ -274,6 +277,9 @@ static void sky2_power_aux(struct sky2_hw *hw) sky2_write8(hw, B0_POWER_CTRL, (PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF)); + + /* turn off "driver loaded LED" */ + sky2_write16(hw, B0_CTST, Y2_LED_STAT_OFF); } static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) @@ -1867,9 +1873,6 @@ static int sky2_down(struct net_device *dev) sky2_phy_power_down(hw, port); spin_unlock_bh(&sky2->phy_lock); - /* turn off LED's */ - sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); - sky2_tx_reset(hw, port); /* Free any pending frames stuck in HW queue */ @@ -2983,8 +2986,6 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B2_TI_CTRL, TIM_STOP); sky2_write8(hw, B2_TI_CTRL, TIM_CLR_IRQ); - sky2_write8(hw, B0_Y2LED, LED_STAT_ON); - /* Turn off descriptor polling */ sky2_write32(hw, B28_DPT_CTRL, DPT_STOP); @@ -4601,7 +4602,6 @@ static void __devexit sky2_remove(struct pci_dev *pdev) sky2_power_aux(hw); - sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); sky2_write8(hw, B0_CTST, CS_RST_SET); sky2_read8(hw, B0_CTST); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 73c9547..34042ff 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -155,7 +155,7 @@ enum pci_cfg_reg1 { enum csr_regs { B0_RAP = 0x0000, B0_CTST = 0x0004, - B0_Y2LED = 0x0005, + B0_POWER_CTRL = 0x0007, B0_ISRC = 0x0008, B0_IMSK = 0x000c, @@ -283,13 +283,6 @@ enum { CS_RST_SET = 1, /* Set Software reset */ }; -/* B0_LED 8 Bit LED register */ -enum { -/* Bit 7.. 2: reserved */ - LED_STAT_ON = 1<<1, /* Status LED on */ - LED_STAT_OFF = 1, /* Status LED off */ -}; - /* B0_POWER_CTRL 8 Bit Power Control reg (YUKON only) */ enum { PC_VAUX_ENA = 1<<7, /* Switch VAUX Enable */ -- cgit v0.10.2 From 90bbebb4a8258a398705ecaa2e6b9e177928ee7a Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Tue, 1 Sep 2009 03:21:35 +0000 Subject: sky2: Create buffer alloc and free helpers Refactor similar two sections of code that free buffers into one. Only call tx_init if all buffer allocations succeed. Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ba5180a..7108b12 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1405,6 +1405,61 @@ nomem: return -ENOMEM; } +static int sky2_alloc_buffers(struct sky2_port *sky2) +{ + struct sky2_hw *hw = sky2->hw; + + /* must be power of 2 */ + sky2->tx_le = pci_alloc_consistent(hw->pdev, + sky2->tx_ring_size * + sizeof(struct sky2_tx_le), + &sky2->tx_le_map); + if (!sky2->tx_le) + goto nomem; + + sky2->tx_ring = kcalloc(sky2->tx_ring_size, sizeof(struct tx_ring_info), + GFP_KERNEL); + if (!sky2->tx_ring) + goto nomem; + + sky2->rx_le = pci_alloc_consistent(hw->pdev, RX_LE_BYTES, + &sky2->rx_le_map); + if (!sky2->rx_le) + goto nomem; + memset(sky2->rx_le, 0, RX_LE_BYTES); + + sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct rx_ring_info), + GFP_KERNEL); + if (!sky2->rx_ring) + goto nomem; + + return 0; +nomem: + return -ENOMEM; +} + +static void sky2_free_buffers(struct sky2_port *sky2) +{ + struct sky2_hw *hw = sky2->hw; + + if (sky2->rx_le) { + pci_free_consistent(hw->pdev, RX_LE_BYTES, + sky2->rx_le, sky2->rx_le_map); + sky2->rx_le = NULL; + } + if (sky2->tx_le) { + pci_free_consistent(hw->pdev, + sky2->tx_ring_size * sizeof(struct sky2_tx_le), + sky2->tx_le, sky2->tx_le_map); + sky2->tx_le = NULL; + } + kfree(sky2->tx_ring); + kfree(sky2->rx_ring); + + sky2->tx_ring = NULL; + sky2->rx_ring = NULL; +} + /* Bring up network interface. */ static int sky2_up(struct net_device *dev) { @@ -1412,7 +1467,7 @@ static int sky2_up(struct net_device *dev) struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; u32 imask, ramsize; - int cap, err = -ENOMEM; + int cap, err; struct net_device *otherdev = hw->dev[sky2->port^1]; /* @@ -1431,32 +1486,12 @@ static int sky2_up(struct net_device *dev) netif_carrier_off(dev); - /* must be power of 2 */ - sky2->tx_le = pci_alloc_consistent(hw->pdev, - sky2->tx_ring_size * - sizeof(struct sky2_tx_le), - &sky2->tx_le_map); - if (!sky2->tx_le) - goto err_out; - - sky2->tx_ring = kcalloc(sky2->tx_ring_size, sizeof(struct tx_ring_info), - GFP_KERNEL); - if (!sky2->tx_ring) + err = sky2_alloc_buffers(sky2); + if (err) goto err_out; tx_init(sky2); - sky2->rx_le = pci_alloc_consistent(hw->pdev, RX_LE_BYTES, - &sky2->rx_le_map); - if (!sky2->rx_le) - goto err_out; - memset(sky2->rx_le, 0, RX_LE_BYTES); - - sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct rx_ring_info), - GFP_KERNEL); - if (!sky2->rx_ring) - goto err_out; - sky2_mac_init(hw, port); /* Register is number of 4K blocks on internal RAM buffer. */ @@ -1513,22 +1548,7 @@ static int sky2_up(struct net_device *dev) return 0; err_out: - if (sky2->rx_le) { - pci_free_consistent(hw->pdev, RX_LE_BYTES, - sky2->rx_le, sky2->rx_le_map); - sky2->rx_le = NULL; - } - if (sky2->tx_le) { - pci_free_consistent(hw->pdev, - sky2->tx_ring_size * sizeof(struct sky2_tx_le), - sky2->tx_le, sky2->tx_le_map); - sky2->tx_le = NULL; - } - kfree(sky2->tx_ring); - kfree(sky2->rx_ring); - - sky2->tx_ring = NULL; - sky2->rx_ring = NULL; + sky2_free_buffers(sky2); return err; } @@ -1880,20 +1900,7 @@ static int sky2_down(struct net_device *dev) sky2_rx_clean(sky2); - pci_free_consistent(hw->pdev, RX_LE_BYTES, - sky2->rx_le, sky2->rx_le_map); - kfree(sky2->rx_ring); - - pci_free_consistent(hw->pdev, - sky2->tx_ring_size * sizeof(struct sky2_tx_le), - sky2->tx_le, sky2->tx_le_map); - kfree(sky2->tx_ring); - - sky2->tx_le = NULL; - sky2->rx_le = NULL; - - sky2->rx_ring = NULL; - sky2->tx_ring = NULL; + sky2_free_buffers(sky2); return 0; } -- cgit v0.10.2 From 72c60683282a6cd047db47d605eb96e2a6fac72c Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Tue, 1 Sep 2009 03:54:27 +0000 Subject: sky2: Use 32bit read to read Y2_VAUX_AVAIL B0_CTST is a 24bit register according to the vendor driver (sk98lin). A 16bit read on B0_CTST will always return 0 for Y2_VAUX_AVAIL (1<<16), so use a 32bit read when testing Y2_VAUX_AVAIL Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 7108b12..d1f3b46 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -273,7 +273,7 @@ static void sky2_power_aux(struct sky2_hw *hw) Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); /* switch power to VAUX */ - if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) + if (sky2_read32(hw, B0_CTST) & Y2_VAUX_AVAIL) sky2_write8(hw, B0_POWER_CTRL, (PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF)); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 34042ff..e0f23a1 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -260,7 +260,7 @@ enum csr_regs { Y2_CFG_AER = 0x1d00, /* PCI Advanced Error Report region */ }; -/* B0_CTST 16 bit Control/Status register */ +/* B0_CTST 24 bit Control/Status register */ enum { Y2_VMAIN_AVAIL = 1<<17,/* VMAIN available (YUKON-2 only) */ Y2_VAUX_AVAIL = 1<<16,/* VAUX available (YUKON-2 only) */ -- cgit v0.10.2 From 5152fc7de3ae31b46692022ea63ce0501280f5b1 Mon Sep 17 00:00:00 2001 From: Damian Lukowski Date: Tue, 1 Sep 2009 10:24:00 +0000 Subject: RTO connection timeout: coding style fixes and comments This patch affects the retransmits_timed_out() function. Changes: 1) Variables have more meaningful names 2) retransmits_timed_out() has an introductionary comment. 3) Small coding style changes. Signed-off-by: Damian Lukowski Signed-off-by: David S. Miller diff --git a/include/net/tcp.h b/include/net/tcp.h index e531949..df50bc4 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1252,22 +1252,27 @@ static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_bu #define tcp_for_write_queue_from_safe(skb, tmp, sk) \ skb_queue_walk_from_safe(&(sk)->sk_write_queue, skb, tmp) +/* This function calculates a "timeout" which is equivalent to the timeout of a + * TCP connection after "boundary" unsucessful, exponentially backed-off + * retransmissions with an initial RTO of TCP_RTO_MIN. + */ static inline bool retransmits_timed_out(const struct sock *sk, unsigned int boundary) { - int limit, K; + unsigned int timeout, linear_backoff_thresh; + if (!inet_csk(sk)->icsk_retransmits) return false; - K = ilog2(TCP_RTO_MAX/TCP_RTO_MIN); + linear_backoff_thresh = ilog2(TCP_RTO_MAX/TCP_RTO_MIN); - if (boundary <= K) - limit = ((2 << boundary) - 1) * TCP_RTO_MIN; + if (boundary <= linear_backoff_thresh) + timeout = ((2 << boundary) - 1) * TCP_RTO_MIN; else - limit = ((2 << K) - 1) * TCP_RTO_MIN + - (boundary - K) * TCP_RTO_MAX; + timeout = ((2 << linear_backoff_thresh) - 1) * TCP_RTO_MIN + + (boundary - linear_backoff_thresh) * TCP_RTO_MAX; - return (tcp_time_stamp - tcp_sk(sk)->retrans_stamp) >= limit; + return (tcp_time_stamp - tcp_sk(sk)->retrans_stamp) >= timeout; } static inline struct sk_buff *tcp_send_head(struct sock *sk) -- cgit v0.10.2 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 diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 8be7623..4e9c6d7 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 v0.10.2 From dcbfef820bdd1cdb412ccf234840e23edf67014f Mon Sep 17 00:00:00 2001 From: roel kluin Date: Sun, 30 Aug 2009 22:40:15 +0000 Subject: au1000_eth: possible NULL dereference of aup->mii_bus->irq in au1000_probe() aup->mii_bus->irq allocation may fail, prevent a dereference of NULL. Signed-off-by: Roel Kluin Acked-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 407fd45..fdf5937 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -1157,6 +1157,9 @@ static struct net_device * au1000_probe(int port_num) aup->mii_bus->name = "au1000_eth_mii"; snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id); aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + if (aup->mii_bus->irq == NULL) + goto err_out; + for(i = 0; i < PHY_MAX_ADDR; ++i) aup->mii_bus->irq[i] = PHY_POLL; -- cgit v0.10.2 From 89d69d2b75a8f7e258f4b634cd985374cfd3202e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 1 Sep 2009 11:13:19 +0000 Subject: net: make neigh_ops constant These tables are never modified at runtime. Move to read-only section. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/include/net/arp.h b/include/net/arp.h index c236270..716f43c 100644 --- a/include/net/arp.h +++ b/include/net/arp.h @@ -26,6 +26,6 @@ extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, const unsigned char *target_hw); extern void arp_xmit(struct sk_buff *skb); -extern struct neigh_ops arp_broken_ops; +extern const struct neigh_ops arp_broken_ops; #endif /* _ARP_H */ diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 18b69b6..3817fda 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -118,7 +118,7 @@ struct neighbour int (*output)(struct sk_buff *skb); struct sk_buff_head arp_queue; struct timer_list timer; - struct neigh_ops *ops; + const struct neigh_ops *ops; u8 primary_key[0]; }; diff --git a/net/atm/clip.c b/net/atm/clip.c index 27f6852..64629c3 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -267,7 +267,7 @@ static void clip_neigh_error(struct neighbour *neigh, struct sk_buff *skb) kfree_skb(skb); } -static struct neigh_ops clip_neigh_ops = { +static const struct neigh_ops clip_neigh_ops = { .family = AF_INET, .solicit = clip_neigh_solicit, .error_report = clip_neigh_error, diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 923786b..794b5bf 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -59,7 +59,7 @@ static int dn_phase3_output(struct sk_buff *); /* * For talking to broadcast devices: Ethernet & PPP */ -static struct neigh_ops dn_long_ops = { +static const struct neigh_ops dn_long_ops = { .family = AF_DECnet, .error_report = dn_long_error_report, .output = dn_long_output, @@ -71,7 +71,7 @@ static struct neigh_ops dn_long_ops = { /* * For talking to pointopoint and multidrop devices: DDCMP and X.25 */ -static struct neigh_ops dn_short_ops = { +static const struct neigh_ops dn_short_ops = { .family = AF_DECnet, .error_report = dn_short_error_report, .output = dn_short_output, @@ -83,7 +83,7 @@ static struct neigh_ops dn_short_ops = { /* * For talking to DECnet phase III nodes */ -static struct neigh_ops dn_phase3_ops = { +static const struct neigh_ops dn_phase3_ops = { .family = AF_DECnet, .error_report = dn_short_error_report, /* Can use short version here */ .output = dn_phase3_output, diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 090e999..4e80f33 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -130,7 +130,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb); static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); static void parp_redo(struct sk_buff *skb); -static struct neigh_ops arp_generic_ops = { +static const struct neigh_ops arp_generic_ops = { .family = AF_INET, .solicit = arp_solicit, .error_report = arp_error_report, @@ -140,7 +140,7 @@ static struct neigh_ops arp_generic_ops = { .queue_xmit = dev_queue_xmit, }; -static struct neigh_ops arp_hh_ops = { +static const struct neigh_ops arp_hh_ops = { .family = AF_INET, .solicit = arp_solicit, .error_report = arp_error_report, @@ -150,7 +150,7 @@ static struct neigh_ops arp_hh_ops = { .queue_xmit = dev_queue_xmit, }; -static struct neigh_ops arp_direct_ops = { +static const struct neigh_ops arp_direct_ops = { .family = AF_INET, .output = dev_queue_xmit, .connected_output = dev_queue_xmit, @@ -158,7 +158,7 @@ static struct neigh_ops arp_direct_ops = { .queue_xmit = dev_queue_xmit, }; -struct neigh_ops arp_broken_ops = { +const struct neigh_ops arp_broken_ops = { .family = AF_INET, .solicit = arp_solicit, .error_report = arp_error_report, diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 44b4c87..7015478 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -98,7 +98,7 @@ static int pndisc_constructor(struct pneigh_entry *n); static void pndisc_destructor(struct pneigh_entry *n); static void pndisc_redo(struct sk_buff *skb); -static struct neigh_ops ndisc_generic_ops = { +static const struct neigh_ops ndisc_generic_ops = { .family = AF_INET6, .solicit = ndisc_solicit, .error_report = ndisc_error_report, @@ -108,7 +108,7 @@ static struct neigh_ops ndisc_generic_ops = { .queue_xmit = dev_queue_xmit, }; -static struct neigh_ops ndisc_hh_ops = { +static const struct neigh_ops ndisc_hh_ops = { .family = AF_INET6, .solicit = ndisc_solicit, .error_report = ndisc_error_report, @@ -119,7 +119,7 @@ static struct neigh_ops ndisc_hh_ops = { }; -static struct neigh_ops ndisc_direct_ops = { +static const struct neigh_ops ndisc_direct_ops = { .family = AF_INET6, .output = dev_queue_xmit, .connected_output = dev_queue_xmit, -- cgit v0.10.2 From 3732e9bd2d841db588624b1bf560bfc9d0dcb1fd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 1 Sep 2009 17:50:50 -0700 Subject: xilinx_emaclite: Fix permissions on driver sources. Noticed by Michal Simek. Signed-off-by: David S. Miller diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c old mode 100755 new mode 100644 -- cgit v0.10.2 From e7a088f935180b90cfe6ab0aaae8a556f46885fe Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 1 Sep 2009 17:54:07 -0700 Subject: sparc: convert /proc/io_map, /proc/dvma_map to seq_file Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 87ea0d0..e71ce79 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -35,6 +35,7 @@ #include #include /* struct pci_dev */ #include +#include #include #include @@ -663,26 +664,33 @@ EXPORT_SYMBOL(pci_dma_sync_sg_for_device); #ifdef CONFIG_PROC_FS -static int -_sparc_io_get_info(char *buf, char **start, off_t fpos, int length, int *eof, - void *data) +static int sparc_io_proc_show(struct seq_file *m, void *v) { - char *p = buf, *e = buf + length; - struct resource *r; + struct resource *root = m->private, *r; const char *nm; - for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) { - if (p + 32 >= e) /* Better than nothing */ - break; + for (r = root->child; r != NULL; r = r->sibling) { if ((nm = r->name) == 0) nm = "???"; - p += sprintf(p, "%016llx-%016llx: %s\n", + seq_printf(m, "%016llx-%016llx: %s\n", (unsigned long long)r->start, (unsigned long long)r->end, nm); } - return p-buf; + return 0; } +static int sparc_io_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, sparc_io_proc_show, PDE(inode)->data); +} + +static const struct file_operations sparc_io_proc_fops = { + .owner = THIS_MODULE, + .open = sparc_io_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif /* CONFIG_PROC_FS */ /* @@ -707,7 +715,7 @@ static struct resource *_sparc_find_resource(struct resource *root, static void register_proc_sparc_ioport(void) { #ifdef CONFIG_PROC_FS - create_proc_read_entry("io_map",0,NULL,_sparc_io_get_info,&sparc_iomap); - create_proc_read_entry("dvma_map",0,NULL,_sparc_io_get_info,&_sparc_dvma); + proc_create_data("io_map", 0, NULL, &sparc_io_proc_fops, &sparc_iomap); + proc_create_data("dvma_map", 0, NULL, &sparc_io_proc_fops, &_sparc_dvma); #endif } -- cgit v0.10.2 From f2798eb4e01b095f273f4bf40f511c9d69c0e1da Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Sun, 30 Aug 2009 20:10:43 +0000 Subject: drop_monitor: fix trace_napi_poll_hit() The net_dev of backlog napi is NULL, like below: __get_cpu_var(softnet_data).backlog.dev == NULL So, we should check it in napi tracepoint's probe function Acked-by: Neil Horman Signed-off-by: Xiao Guangrong Signed-off-by: David S. Miller diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 9d66fa9..d311202 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -182,7 +182,8 @@ static void trace_napi_poll_hit(struct napi_struct *napi) /* * Ratelimit our check time to dm_hw_check_delta jiffies */ - if (!time_after(jiffies, napi->dev->last_rx + dm_hw_check_delta)) + if (!napi->dev || + !time_after(jiffies, napi->dev->last_rx + dm_hw_check_delta)) return; rcu_read_lock(); -- cgit v0.10.2 From 0625491493d9000e4556bf566d205c28c8e7dc4e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 1 Sep 2009 18:37:16 -0700 Subject: ipv6: ip6_push_pending_frames() should increment IPSTATS_MIB_OUTDISCARDS qdisc drops should be notified to IP_RECVERR enabled sockets, as done in IPV4. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 6ad5aad..a931229 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1520,6 +1520,7 @@ out: ip6_cork_release(inet, np); return err; error: + IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); goto out; } -- cgit v0.10.2 From ae4b688db2432baad379f73fdcac13ec24f603d5 Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Mon, 31 Aug 2009 13:11:54 +0800 Subject: x86: Move kernel_fpu_using to irq_fpu_usable in asm/i387.h This function measures whether the FPU/SSE state can be touched in interrupt context. If the interrupted code is in user space or has no valid FPU/SSE context (CR0.TS == 1), FPU/SSE state can be used in IRQ or soft_irq context too. This is used by AES-NI accelerated AES implementation and PCLMULQDQ accelerated GHASH implementation. v3: - Renamed to irq_fpu_usable to reflect the purpose of the function. v2: - Renamed to irq_is_fpu_using to reflect the real situation. Signed-off-by: Huang Ying CC: H. Peter Anvin Signed-off-by: H. Peter Anvin diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index c580c5e..7667235 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -59,13 +59,6 @@ asmlinkage void aesni_cbc_enc(struct crypto_aes_ctx *ctx, u8 *out, asmlinkage void aesni_cbc_dec(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len, u8 *iv); -static inline int kernel_fpu_using(void) -{ - if (in_interrupt() && !(read_cr0() & X86_CR0_TS)) - return 1; - return 0; -} - static inline struct crypto_aes_ctx *aes_ctx(void *raw_ctx) { unsigned long addr = (unsigned long)raw_ctx; @@ -89,7 +82,7 @@ static int aes_set_key_common(struct crypto_tfm *tfm, void *raw_ctx, return -EINVAL; } - if (kernel_fpu_using()) + if (irq_fpu_usable()) err = crypto_aes_expand_key(ctx, in_key, key_len); else { kernel_fpu_begin(); @@ -110,7 +103,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm)); - if (kernel_fpu_using()) + if (irq_fpu_usable()) crypto_aes_encrypt_x86(ctx, dst, src); else { kernel_fpu_begin(); @@ -123,7 +116,7 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm)); - if (kernel_fpu_using()) + if (irq_fpu_usable()) crypto_aes_decrypt_x86(ctx, dst, src); else { kernel_fpu_begin(); @@ -349,7 +342,7 @@ static int ablk_encrypt(struct ablkcipher_request *req) struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); - if (kernel_fpu_using()) { + if (irq_fpu_usable()) { struct ablkcipher_request *cryptd_req = ablkcipher_request_ctx(req); memcpy(cryptd_req, req, sizeof(*req)); @@ -370,7 +363,7 @@ static int ablk_decrypt(struct ablkcipher_request *req) struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); - if (kernel_fpu_using()) { + if (irq_fpu_usable()) { struct ablkcipher_request *cryptd_req = ablkcipher_request_ctx(req); memcpy(cryptd_req, req, sizeof(*req)); diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 175adf5..fb7f0d6 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -301,6 +301,14 @@ static inline void kernel_fpu_end(void) preempt_enable(); } +static inline bool irq_fpu_usable(void) +{ + struct pt_regs *regs; + + return !in_interrupt() || !(regs = get_irq_regs()) || \ + user_mode(regs) || (read_cr0() & X86_CR0_TS); +} + /* * Some instructions like VIA's padlock instructions generate a spurious * DNA fault but don't modify SSE registers. And these instructions -- cgit v0.10.2 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 diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index abffd41..32d8cc0 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 83a338b..e31e53d 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 v0.10.2 From 8f0dfc34e9b323a028c2ec41abb7e9de477b7a94 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Mon, 20 Jul 2009 11:26:58 -0700 Subject: sched: Provide iowait counters For counting how long an application has been waiting for (disk) IO, there currently is only the HZ sample driven information available, while for all other counters in this class, a high resolution version is available via CONFIG_SCHEDSTATS. In order to make an improved bootchart tool possible, we also need a higher resolution version of the iowait time. This patch below adds this scheduler statistic to the kernel. Signed-off-by: Arjan van de Ven Signed-off-by: Peter Zijlstra LKML-Reference: <4A64B813.1080506@linux.intel.com> Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index e209ae0..9c96ef2 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1111,6 +1111,8 @@ struct sched_entity { u64 wait_max; u64 wait_count; u64 wait_sum; + u64 iowait_count; + u64 iowait_sum; u64 sleep_start; u64 sleep_max; @@ -1231,6 +1233,8 @@ struct task_struct { unsigned did_exec:1; unsigned in_execve:1; /* Tell the LSMs that the process is doing an * execve */ + unsigned in_iowait:1; + /* Revert to default priority/policy when forking */ unsigned sched_reset_on_fork:1; diff --git a/kernel/sched.c b/kernel/sched.c index 6244d24..38d05a8 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6754,7 +6754,9 @@ void __sched io_schedule(void) delayacct_blkio_start(); atomic_inc(&rq->nr_iowait); + current->in_iowait = 1; schedule(); + current->in_iowait = 0; atomic_dec(&rq->nr_iowait); delayacct_blkio_end(); } @@ -6767,7 +6769,9 @@ long __sched io_schedule_timeout(long timeout) delayacct_blkio_start(); atomic_inc(&rq->nr_iowait); + current->in_iowait = 1; ret = schedule_timeout(timeout); + current->in_iowait = 0; atomic_dec(&rq->nr_iowait); delayacct_blkio_end(); return ret; diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c index 70c7e0b..5ddbd08 100644 --- a/kernel/sched_debug.c +++ b/kernel/sched_debug.c @@ -409,6 +409,8 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m) PN(se.wait_max); PN(se.wait_sum); P(se.wait_count); + PN(se.iowait_sum); + P(se.iowait_count); P(sched_info.bkl_count); P(se.nr_migrations); P(se.nr_migrations_cold); @@ -479,6 +481,8 @@ void proc_sched_set_task(struct task_struct *p) p->se.wait_max = 0; p->se.wait_sum = 0; p->se.wait_count = 0; + p->se.iowait_sum = 0; + p->se.iowait_count = 0; p->se.sleep_max = 0; p->se.sum_sleep_runtime = 0; p->se.block_max = 0; diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 342000b..471fa28 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -652,6 +652,11 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) se->sum_sleep_runtime += delta; if (tsk) { + if (tsk->in_iowait) { + se->iowait_sum += delta; + se->iowait_count++; + } + /* * Blocking time is in units of nanosecs, so shift by * 20 to get a milliseconds-range estimation of the -- cgit v0.10.2 From 768d0c27226e6587cad2fcf543f9711da3f3774e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 23 Jul 2009 20:13:26 +0200 Subject: sched: Add wait, sleep and iowait accounting tracepoints Add 3 schedstat tracepoints to help account for wait-time, sleep-time and iowait-time. They can also be used as a perf-counter source to profile tasks on these clocks. Signed-off-by: Peter Zijlstra Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Arjan van de Ven LKML-Reference: [ build fix for the !CONFIG_SCHEDSTATS case ] Signed-off-by: Ingo Molnar diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 8949bb7..a4c369e 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -340,6 +340,101 @@ TRACE_EVENT(sched_signal_send, __entry->sig, __entry->comm, __entry->pid) ); +/* + * XXX the below sched_stat tracepoints only apply to SCHED_OTHER/BATCH/IDLE + * adding sched_stat support to SCHED_FIFO/RR would be welcome. + */ + +/* + * Tracepoint for accounting wait time (time the task is runnable + * but not actually running due to scheduler contention). + */ +TRACE_EVENT(sched_stat_wait, + + TP_PROTO(struct task_struct *tsk, u64 delay), + + TP_ARGS(tsk, delay), + + TP_STRUCT__entry( + __array( char, comm, TASK_COMM_LEN ) + __field( pid_t, pid ) + __field( u64, delay ) + ), + + TP_fast_assign( + memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN); + __entry->pid = tsk->pid; + __entry->delay = delay; + ) + TP_perf_assign( + __perf_count(delay); + ), + + TP_printk("task: %s:%d wait: %Lu [ns]", + __entry->comm, __entry->pid, + (unsigned long long)__entry->delay) +); + +/* + * Tracepoint for accounting sleep time (time the task is not runnable, + * including iowait, see below). + */ +TRACE_EVENT(sched_stat_sleep, + + TP_PROTO(struct task_struct *tsk, u64 delay), + + TP_ARGS(tsk, delay), + + TP_STRUCT__entry( + __array( char, comm, TASK_COMM_LEN ) + __field( pid_t, pid ) + __field( u64, delay ) + ), + + TP_fast_assign( + memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN); + __entry->pid = tsk->pid; + __entry->delay = delay; + ) + TP_perf_assign( + __perf_count(delay); + ), + + TP_printk("task: %s:%d sleep: %Lu [ns]", + __entry->comm, __entry->pid, + (unsigned long long)__entry->delay) +); + +/* + * Tracepoint for accounting iowait time (time the task is not runnable + * due to waiting on IO to complete). + */ +TRACE_EVENT(sched_stat_iowait, + + TP_PROTO(struct task_struct *tsk, u64 delay), + + TP_ARGS(tsk, delay), + + TP_STRUCT__entry( + __array( char, comm, TASK_COMM_LEN ) + __field( pid_t, pid ) + __field( u64, delay ) + ), + + TP_fast_assign( + memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN); + __entry->pid = tsk->pid; + __entry->delay = delay; + ) + TP_perf_assign( + __perf_count(delay); + ), + + TP_printk("task: %s:%d iowait: %Lu [ns]", + __entry->comm, __entry->pid, + (unsigned long long)__entry->delay) +); + #endif /* _TRACE_SCHED_H */ /* This part must be outside protection */ diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 471fa28..2ff850f 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -546,6 +546,13 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se) schedstat_set(se->wait_sum, se->wait_sum + rq_of(cfs_rq)->clock - se->wait_start); schedstat_set(se->wait_start, 0); + +#ifdef CONFIG_SCHEDSTATS + if (entity_is_task(se)) { + trace_sched_stat_wait(task_of(se), + rq_of(cfs_rq)->clock - se->wait_start); + } +#endif } static inline void @@ -636,8 +643,10 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) se->sleep_start = 0; se->sum_sleep_runtime += delta; - if (tsk) + if (tsk) { account_scheduler_latency(tsk, delta >> 10, 1); + trace_sched_stat_sleep(tsk, delta); + } } if (se->block_start) { u64 delta = rq_of(cfs_rq)->clock - se->block_start; @@ -655,6 +664,7 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) if (tsk->in_iowait) { se->iowait_sum += delta; se->iowait_count++; + trace_sched_stat_iowait(tsk, delta); } /* -- cgit v0.10.2 From f19af9c2cc015e42dfe4bd5c383e32066ec2801c Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:47:49 +0000 Subject: tg3: inline tg3_cond_int() This patch inlines the code of tg3_cond_int() into the function's only callsite. This prep work makes the following patch cleaner. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9d5c178..65ff286 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -618,18 +618,9 @@ static void tg3_disable_ints(struct tg3 *tp) tw32_mailbox_f(tp->napi[0].int_mbox, 0x00000001); } -static inline void tg3_cond_int(struct tg3 *tp) -{ - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && - (tp->napi[0].hw_status->status & SD_STATUS_UPDATED)) - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); - else - tw32(HOSTCC_MODE, tp->coalesce_mode | - (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); -} - static void tg3_enable_ints(struct tg3 *tp) { + u32 coal_now; struct tg3_napi *tnapi = &tp->napi[0]; tp->irq_sync = 0; wmb(); @@ -639,7 +630,16 @@ static void tg3_enable_ints(struct tg3 *tp) tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); - tg3_cond_int(tp); + + coal_now = HOSTCC_MODE_NOW; + + /* Force an initial interrupt */ + if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && + (tp->napi[0].hw_status->status & SD_STATUS_UPDATED)) + tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); + else + tw32(HOSTCC_MODE, tp->coalesce_mode | + HOSTCC_MODE_ENABLE | coal_now); } static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) -- cgit v0.10.2 From fd2ce37f8e4a570ce90b141a2e7c476c5b399836 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:51:13 +0000 Subject: tg3: Add per-int coalesce now member Each interrupt vector has its own bit in the host coalescing register to force that vector's status block to be updated and generate an interrupt. This patch adds a member to the per-interrupt structure that records which bit belongs to that vector. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 65ff286..ff65ae8 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -631,7 +631,7 @@ static void tg3_enable_ints(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); - coal_now = HOSTCC_MODE_NOW; + coal_now = tnapi->coal_now; /* Force an initial interrupt */ if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && @@ -682,7 +682,7 @@ static void tg3_int_reenable(struct tg3_napi *tnapi) if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && tg3_has_work(tnapi)) tw32(HOSTCC_MODE, tp->coalesce_mode | - (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); + HOSTCC_MODE_ENABLE | tnapi->coal_now); } static inline void tg3_netif_stop(struct tg3 *tp) @@ -7622,7 +7622,7 @@ static void tg3_timer(unsigned long __opaque) tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); } else { tw32(HOSTCC_MODE, tp->coalesce_mode | - (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); + HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW); } if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { @@ -7765,7 +7765,7 @@ static int tg3_test_interrupt(struct tg3 *tp) tg3_enable_ints(tp); tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | - HOSTCC_MODE_NOW); + tnapi->coal_now); for (i = 0; i < 5; i++) { u32 int_mbox, misc_host_ctrl; @@ -9840,7 +9840,7 @@ static int tg3_test_memory(struct tg3 *tp) static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) { u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key; - u32 desc_idx; + u32 desc_idx, coal_now; struct sk_buff *skb, *rx_skb; u8 *tx_data; dma_addr_t map; @@ -9851,6 +9851,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) tnapi = &tp->napi[0]; rnapi = &tp->napi[0]; + coal_now = tnapi->coal_now | rnapi->coal_now; if (loopback_mode == TG3_MAC_LOOPBACK) { /* HW errata - mac loopback fails in some cases on 5780. @@ -9929,7 +9930,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE); tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | - HOSTCC_MODE_NOW); + rnapi->coal_now); udelay(10); @@ -9950,7 +9951,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) /* 250 usec to allow enough time on some 10/100 Mbps devices. */ for (i = 0; i < 25; i++) { tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | - HOSTCC_MODE_NOW); + coal_now); udelay(10); @@ -13428,6 +13429,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->napi[0].int_mbox = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; tp->napi[0].consmbox = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; tp->napi[0].prodmbox = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; + tp->napi[0].coal_now = HOSTCC_MODE_NOW; tp->napi[0].tx_pending = TG3_DEF_TX_RING_PENDING; netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index a816b2c..626b968 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1031,6 +1031,7 @@ #define HOSTCC_MODE_CLRTICK_TXBD 0x00000400 #define HOSTCC_MODE_NOINT_ON_NOW 0x00000800 #define HOSTCC_MODE_NOINT_ON_FORCE 0x00001000 +#define HOSTCC_MODE_COAL_VEC1_NOW 0x00002000 #define HOSTCC_STATUS 0x00003c04 #define HOSTCC_STATUS_ERROR_ATTN 0x00000004 #define HOSTCC_RXCOL_TICKS 0x00003c08 @@ -2497,6 +2498,7 @@ struct tg3_napi { u32 last_tag; u32 last_irq_tag; u32 int_mbox; + u32 coal_now; u32 tx_prod; u32 tx_cons; u32 tx_pending; -- cgit v0.10.2 From 2d31ecaf10c4ae03d49aed516481b2839b0220f6 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:53:31 +0000 Subject: tg3: Create tg3_rings_reset() This patch moves most of the chip ring setup logic into a separate function. This will make it easier to verify the multi ring setup changes. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ff65ae8..14cead6 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6818,6 +6818,76 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) } /* tp->lock is held. */ +static void tg3_rings_reset(struct tg3 *tp) +{ + int i; + u32 txrcb, rxrcb, limit; + struct tg3_napi *tnapi = &tp->napi[0]; + + /* Disable all transmit rings but the first. */ + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16; + else + limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE; + + for (txrcb = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE; + txrcb < limit; txrcb += TG3_BDINFO_SIZE) + tg3_write_mem(tp, txrcb + TG3_BDINFO_MAXLEN_FLAGS, + BDINFO_FLAGS_DISABLED); + + + /* Disable all receive return rings but the first. */ + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16; + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) + limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 4; + else + limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE; + + for (rxrcb = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE; + rxrcb < limit; rxrcb += TG3_BDINFO_SIZE) + tg3_write_mem(tp, rxrcb + TG3_BDINFO_MAXLEN_FLAGS, + BDINFO_FLAGS_DISABLED); + + /* Disable interrupts */ + tw32_mailbox_f(tp->napi[0].int_mbox, 1); + + /* Zero mailbox registers. */ + tp->napi[0].tx_prod = 0; + tp->napi[0].tx_cons = 0; + tw32_mailbox(tp->napi[0].prodmbox, 0); + tw32_rx_mbox(tp->napi[0].consmbox, 0); + + /* Make sure the NIC-based send BD rings are disabled. */ + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + u32 mbox = MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW; + for (i = 0; i < 16; i++) + tw32_tx_mbox(mbox + i * 8, 0); + } + + txrcb = NIC_SRAM_SEND_RCB; + rxrcb = NIC_SRAM_RCV_RET_RCB; + + /* Clear status block in ram. */ + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + + /* Set status block DMA address */ + tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, + ((u64) tnapi->status_mapping >> 32)); + tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, + ((u64) tnapi->status_mapping & 0xffffffff)); + + tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping, + (TG3_TX_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + NIC_SRAM_TX_BUFFER_DESC); + + tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping, + (TG3_RX_RCB_RING_SIZE(tp) << + BDINFO_FLAGS_MAXLEN_SHIFT), 0); +} + +/* tp->lock is held. */ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) { u32 val, rdmac_mode; @@ -7091,48 +7161,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, val); - /* There is only one send ring on 5705/5750, no need to explicitly - * disable the others. - */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { - /* Clear out send RCB ring in SRAM. */ - for (i = NIC_SRAM_SEND_RCB; i < NIC_SRAM_RCV_RET_RCB; i += TG3_BDINFO_SIZE) - tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS, - BDINFO_FLAGS_DISABLED); - } - - tp->napi[0].tx_prod = 0; - tp->napi[0].tx_cons = 0; - tw32_tx_mbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); - - val = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; - tw32_mailbox(val, 0); - - tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, - tp->napi[0].tx_desc_mapping, - (TG3_TX_RING_SIZE << - BDINFO_FLAGS_MAXLEN_SHIFT), - NIC_SRAM_TX_BUFFER_DESC); - - /* There is only one receive return ring on 5705/5750, no need - * to explicitly disable the others. - */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { - for (i = NIC_SRAM_RCV_RET_RCB; i < NIC_SRAM_STATS_BLK; - i += TG3_BDINFO_SIZE) { - tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS, - BDINFO_FLAGS_DISABLED); - } - } - - tw32_rx_mbox(tp->napi[0].consmbox, 0); - - tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB, - tp->napi[0].rx_rcb_mapping, - (TG3_RX_RCB_RING_SIZE(tp) << - BDINFO_FLAGS_MAXLEN_SHIFT), - 0); - tpr->rx_std_ptr = tp->rx_pending; tw32_rx_mbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, tpr->rx_std_ptr); @@ -7142,6 +7170,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, tpr->rx_jmb_ptr); + tg3_rings_reset(tp); + /* Initialize MAC address and backoff seed. */ __tg3_set_mac_addr(tp, 0); @@ -7229,12 +7259,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) __tg3_set_coalesce(tp, &tp->coal); - /* set status block DMA address */ - tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, - ((u64) tp->napi[0].status_mapping >> 32)); - tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, - ((u64) tp->napi[0].status_mapping & 0xffffffff)); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { /* Status/statistics block address. See tg3_timer, * the tg3_periodic_fetch_stats call there, and @@ -7245,7 +7269,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tp->stats_mapping & 0xffffffff)); tw32(HOSTCC_STATS_BLK_NIC_ADDR, NIC_SRAM_STATS_BLK); + tw32(HOSTCC_STATUS_BLK_NIC_ADDR, NIC_SRAM_STATUS_BLK); + + /* Clear statistics and status block memory areas */ + for (i = NIC_SRAM_STATS_BLK; + i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE; + i += sizeof(u32)) { + tg3_write_mem(tp, i, 0); + udelay(40); + } } tw32(HOSTCC_MODE, HOSTCC_MODE_ENABLE | tp->coalesce_mode); @@ -7255,15 +7288,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE); - /* Clear statistics/status block in chip, and status block in ram. */ - for (i = NIC_SRAM_STATS_BLK; - i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE; - i += sizeof(u32)) { - tg3_write_mem(tp, i, 0); - udelay(40); - } - memset(tp->napi[0].hw_status, 0, TG3_HW_STATUS_SIZE); - if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) { tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT; /* reset to prevent losing 1st rx packet intermittently */ @@ -7315,8 +7339,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); - tw32_mailbox_f(tp->napi[0].int_mbox, 0); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); udelay(40); -- cgit v0.10.2 From 4f125f42dd55390016e21f8b3960f99d02d1001f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:55:02 +0000 Subject: tg3: Add support code around kernel interrupt API This patch adds code to support multiple interrupt vectors around the kernel's interrupt API. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 14cead6..7717eae 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4729,12 +4729,15 @@ tx_recovery: static void tg3_irq_quiesce(struct tg3 *tp) { + int i; + BUG_ON(tp->irq_sync); tp->irq_sync = 1; smp_mb(); - synchronize_irq(tp->pdev->irq); + for (i = 0; i < tp->irq_cnt; i++) + synchronize_irq(tp->napi[i].irq_vec); } static inline int tg3_irq_sync(struct tg3 *tp) @@ -4947,9 +4950,11 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy) #ifdef CONFIG_NET_POLL_CONTROLLER static void tg3_poll_controller(struct net_device *dev) { + int i; struct tg3 *tp = netdev_priv(dev); - tg3_interrupt(tp->pdev->irq, dev); + for (i = 0; i < tp->irq_cnt; i++) + tg3_interrupt(tp->napi[i].irq_vec, dev); } #endif @@ -6244,7 +6249,7 @@ static int tg3_chip_reset(struct tg3 *tp) { u32 val; void (*write_op)(struct tg3 *, u32, u32); - int err; + int i, err; tg3_nvram_lock(tp); @@ -6291,7 +6296,9 @@ static int tg3_chip_reset(struct tg3 *tp) tp->napi[0].last_tag = 0; tp->napi[0].last_irq_tag = 0; smp_mb(); - synchronize_irq(tp->pdev->irq); + + for (i = 0; i < tp->irq_cnt; i++) + synchronize_irq(tp->napi[i].irq_vec); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) { val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN; @@ -7745,11 +7752,20 @@ restart_timer: add_timer(&tp->timer); } -static int tg3_request_irq(struct tg3 *tp) +static int tg3_request_irq(struct tg3 *tp, int irq_num) { irq_handler_t fn; unsigned long flags; - char *name = tp->dev->name; + char *name; + struct tg3_napi *tnapi = &tp->napi[irq_num]; + + if (tp->irq_cnt == 1) + name = tp->dev->name; + else { + name = &tnapi->irq_lbl[0]; + snprintf(name, IFNAMSIZ, "%s-%d", tp->dev->name, irq_num); + name[IFNAMSIZ-1] = 0; + } if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { fn = tg3_msi; @@ -7762,7 +7778,8 @@ static int tg3_request_irq(struct tg3 *tp) fn = tg3_interrupt_tagged; flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM; } - return request_irq(tp->pdev->irq, fn, flags, name, &tp->napi[0]); + + return request_irq(tnapi->irq_vec, fn, flags, name, tnapi); } static int tg3_test_interrupt(struct tg3 *tp) @@ -7776,9 +7793,9 @@ static int tg3_test_interrupt(struct tg3 *tp) tg3_disable_ints(tp); - free_irq(tp->pdev->irq, tnapi); + free_irq(tnapi->irq_vec, tnapi); - err = request_irq(tp->pdev->irq, tg3_test_isr, + err = request_irq(tnapi->irq_vec, tg3_test_isr, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi); if (err) return err; @@ -7806,9 +7823,9 @@ static int tg3_test_interrupt(struct tg3 *tp) tg3_disable_ints(tp); - free_irq(tp->pdev->irq, tnapi); + free_irq(tnapi->irq_vec, tnapi); - err = tg3_request_irq(tp); + err = tg3_request_irq(tp, 0); if (err) return err; @@ -7854,13 +7871,13 @@ static int tg3_test_msi(struct tg3 *tp) "the PCI maintainer and include system chipset information.\n", tp->dev->name); - free_irq(tp->pdev->irq, &tp->napi[0]); + free_irq(tp->napi[0].irq_vec, &tp->napi[0]); pci_disable_msi(tp->pdev); tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - err = tg3_request_irq(tp); + err = tg3_request_irq(tp, 0); if (err) return err; @@ -7875,7 +7892,7 @@ static int tg3_test_msi(struct tg3 *tp) tg3_full_unlock(tp); if (err) - free_irq(tp->pdev->irq, &tp->napi[0]); + free_irq(tp->napi[0].irq_vec, &tp->napi[0]); return err; } @@ -7928,6 +7945,9 @@ static void tg3_ints_init(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_USING_MSI; } } + + tp->irq_cnt = 1; + tp->napi[0].irq_vec = tp->pdev->irq; } static void tg3_ints_fini(struct tg3 *tp) @@ -7941,7 +7961,7 @@ static void tg3_ints_fini(struct tg3 *tp) static int tg3_open(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - int err; + int i, err; if (tp->fw_needed) { err = tg3_request_firmware(tp); @@ -7983,7 +8003,15 @@ static int tg3_open(struct net_device *dev) napi_enable(&tp->napi[0].napi); - err = tg3_request_irq(tp); + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + err = tg3_request_irq(tp, i); + if (err) { + for (i--; i >= 0; i--) + free_irq(tnapi->irq_vec, tnapi); + break; + } + } if (err) goto err_out1; @@ -8054,7 +8082,10 @@ static int tg3_open(struct net_device *dev) return 0; err_out2: - free_irq(tp->pdev->irq, &tp->napi[0]); + for (i = tp->irq_cnt - 1; i >= 0; i--) { + struct tg3_napi *tnapi = &tp->napi[i]; + free_irq(tnapi->irq_vec, tnapi); + } err_out1: napi_disable(&tp->napi[0].napi); @@ -8298,6 +8329,7 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *); static int tg3_close(struct net_device *dev) { + int i; struct tg3 *tp = netdev_priv(dev); napi_disable(&tp->napi[0].napi); @@ -8320,7 +8352,10 @@ static int tg3_close(struct net_device *dev) tg3_full_unlock(tp); - free_irq(tp->pdev->irq, &tp->napi[0]); + for (i = tp->irq_cnt - 1; i >= 0; i--) { + struct tg3_napi *tnapi = &tp->napi[i]; + free_irq(tnapi->irq_vec, tnapi); + } tg3_ints_fini(tp); @@ -12151,6 +12186,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } } + tp->irq_max = 1; + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 626b968..a78a0db 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2514,6 +2514,9 @@ struct tg3_napi { dma_addr_t status_mapping; dma_addr_t rx_rcb_mapping; dma_addr_t tx_desc_mapping; + + char irq_lbl[IFNAMSIZ]; + unsigned int irq_vec; }; struct tg3 { @@ -2829,6 +2832,9 @@ struct tg3 { #define SST_25VF0X0_PAGE_SIZE 4098 + unsigned int irq_max; + unsigned int irq_cnt; + struct ethtool_coalesce coal; /* firmware info */ -- cgit v0.10.2 From 679563f47cd2547a0e091b5bd3ddf30027af6b08 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:55:46 +0000 Subject: tg3: Add MSI-X support This patch adds MSI-X support. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7717eae..12ead83 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -160,6 +160,7 @@ MODULE_FIRMWARE(FIRMWARE_TG3); MODULE_FIRMWARE(FIRMWARE_TG3TSO); MODULE_FIRMWARE(FIRMWARE_TG3TSO5); +#define TG3_RSS_MIN_NUM_MSIX_VECS 2 static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */ module_param(tg3_debug, int, 0); @@ -7767,7 +7768,7 @@ static int tg3_request_irq(struct tg3 *tp, int irq_num) name[IFNAMSIZ-1] = 0; } - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { fn = tg3_msi; if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) fn = tg3_msi_1shot; @@ -7928,34 +7929,81 @@ static int tg3_request_firmware(struct tg3 *tp) return 0; } +static bool tg3_enable_msix(struct tg3 *tp) +{ + int i, rc, cpus = num_online_cpus(); + struct msix_entry msix_ent[tp->irq_max]; + + if (cpus == 1) + /* Just fallback to the simpler MSI mode. */ + return false; + + /* + * We want as many rx rings enabled as there are cpus. + * The first MSIX vector only deals with link interrupts, etc, + * so we add one to the number of vectors we are requesting. + */ + tp->irq_cnt = min_t(unsigned, cpus + 1, tp->irq_max); + + for (i = 0; i < tp->irq_max; i++) { + msix_ent[i].entry = i; + msix_ent[i].vector = 0; + } + + rc = pci_enable_msix(tp->pdev, msix_ent, tp->irq_cnt); + if (rc != 0) { + if (rc < TG3_RSS_MIN_NUM_MSIX_VECS) + return false; + if (pci_enable_msix(tp->pdev, msix_ent, rc)) + return false; + printk(KERN_NOTICE + "%s: Requested %d MSI-X vectors, received %d\n", + tp->dev->name, tp->irq_cnt, rc); + tp->irq_cnt = rc; + } + + for (i = 0; i < tp->irq_max; i++) + tp->napi[i].irq_vec = msix_ent[i].vector; + + return true; +} + static void tg3_ints_init(struct tg3 *tp) { - if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) { + if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI_OR_MSIX) && + !(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { /* All MSI supporting chips should support tagged * status. Assert that this is the case. */ - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { - printk(KERN_WARNING PFX "%s: MSI without TAGGED? " - "Not using MSI.\n", tp->dev->name); - } else if (pci_enable_msi(tp->pdev) == 0) { - u32 msi_mode; - - msi_mode = tr32(MSGINT_MODE); - tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); - tp->tg3_flags2 |= TG3_FLG2_USING_MSI; - } + printk(KERN_WARNING PFX "%s: MSI without TAGGED? " + "Not using MSI.\n", tp->dev->name); + goto defcfg; } - tp->irq_cnt = 1; - tp->napi[0].irq_vec = tp->pdev->irq; + if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) && tg3_enable_msix(tp)) + tp->tg3_flags2 |= TG3_FLG2_USING_MSIX; + else if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) && + pci_enable_msi(tp->pdev) == 0) + tp->tg3_flags2 |= TG3_FLG2_USING_MSI; + + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { + u32 msi_mode = tr32(MSGINT_MODE); + tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); + } +defcfg: + if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) { + tp->irq_cnt = 1; + tp->napi[0].irq_vec = tp->pdev->irq; + } } static void tg3_ints_fini(struct tg3 *tp) { - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - } + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + pci_disable_msix(tp->pdev); + else if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) + pci_disable_msi(tp->pdev); + tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI_OR_MSIX; } static int tg3_open(struct net_device *dev) @@ -7992,14 +8040,18 @@ static int tg3_open(struct net_device *dev) tg3_full_unlock(tp); + /* + * Setup interrupts first so we know how + * many NAPI resources to allocate + */ + tg3_ints_init(tp); + /* The placement of this call is tied * to the setup and use of Host TX descriptors. */ err = tg3_alloc_consistent(tp); if (err) - return err; - - tg3_ints_init(tp); + goto err_out1; napi_enable(&tp->napi[0].napi); @@ -8014,7 +8066,7 @@ static int tg3_open(struct net_device *dev) } if (err) - goto err_out1; + goto err_out2; tg3_full_lock(tp, 0); @@ -8043,7 +8095,7 @@ static int tg3_open(struct net_device *dev) tg3_full_unlock(tp); if (err) - goto err_out2; + goto err_out3; if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { err = tg3_test_msi(tp); @@ -8054,7 +8106,7 @@ static int tg3_open(struct net_device *dev) tg3_free_rings(tp); tg3_full_unlock(tp); - goto err_out1; + goto err_out2; } if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { @@ -8081,16 +8133,18 @@ static int tg3_open(struct net_device *dev) return 0; -err_out2: +err_out3: for (i = tp->irq_cnt - 1; i >= 0; i--) { struct tg3_napi *tnapi = &tp->napi[i]; free_irq(tnapi->irq_vec, tnapi); } -err_out1: +err_out2: napi_disable(&tp->napi[0].napi); - tg3_ints_fini(tp); tg3_free_consistent(tp); + +err_out1: + tg3_ints_fini(tp); return err; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index a78a0db..65bbd77 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2621,6 +2621,9 @@ struct tg3 { #define TG3_FLAG_NVRAM 0x00002000 #define TG3_FLAG_NVRAM_BUFFERED 0x00004000 #define TG3_FLAG_SUPPORT_MSI 0x00008000 +#define TG3_FLAG_SUPPORT_MSIX 0x00010000 +#define TG3_FLAG_SUPPORT_MSI_OR_MSIX (TG3_FLAG_SUPPORT_MSI | \ + TG3_FLAG_SUPPORT_MSIX) #define TG3_FLAG_PCIX_MODE 0x00020000 #define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 #define TG3_FLAG_PCI_32BIT 0x00080000 @@ -2659,6 +2662,9 @@ struct tg3 { #define TG3_FLG2_5750_PLUS 0x00080000 #define TG3_FLG2_PROTECTED_NVRAM 0x00100000 #define TG3_FLG2_USING_MSI 0x00200000 +#define TG3_FLG2_USING_MSIX 0x00400000 +#define TG3_FLG2_USING_MSI_OR_MSIX (TG3_FLG2_USING_MSI | \ + TG3_FLG2_USING_MSIX) #define TG3_FLG2_MII_SERDES 0x00800000 #define TG3_FLG2_ANY_SERDES (TG3_FLG2_PHY_SERDES | \ TG3_FLG2_MII_SERDES) -- cgit v0.10.2 From 646c9eddcffd202bb0f3d906cecf94eaf10cad31 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:58:41 +0000 Subject: tg3: Add mailbox assignments The 5717 assigns mailbox locations to interrupt vectors in a rather non-intuitive way. (Much of the complexity stems from legacy compatibility issues.) This patch implements the assignment scheme. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 12ead83..4d16ce0 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9219,7 +9219,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam * static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { struct tg3 *tp = netdev_priv(dev); - int irq_sync = 0, err = 0; + int i, irq_sync = 0, err = 0; if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) || (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) || @@ -9243,7 +9243,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tp->rx_pending > 63) tp->rx_pending = 63; tp->rx_jumbo_pending = ering->rx_jumbo_pending; - tp->napi[0].tx_pending = ering->tx_pending; + + for (i = 0; i < TG3_IRQ_MAX_VECS; i++) + tp->napi[i].tx_pending = ering->tx_pending; if (netif_running(dev)) { tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); @@ -13443,7 +13445,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, static int tg3_version_printed = 0; struct net_device *dev; struct tg3 *tp; - int err, pm_cap; + int i, err, pm_cap; + u32 sndmbx, rcvmbx, intmbx; char str[40]; u64 dma_mask, persist_dma_mask; @@ -13538,12 +13541,50 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->rx_pending = TG3_DEF_RX_RING_PENDING; tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING; - tp->napi[0].tp = tp; - tp->napi[0].int_mbox = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; - tp->napi[0].consmbox = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; - tp->napi[0].prodmbox = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; - tp->napi[0].coal_now = HOSTCC_MODE_NOW; - tp->napi[0].tx_pending = TG3_DEF_TX_RING_PENDING; + intmbx = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; + rcvmbx = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; + sndmbx = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; + for (i = 0; i < TG3_IRQ_MAX_VECS; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + + tnapi->tp = tp; + tnapi->tx_pending = TG3_DEF_TX_RING_PENDING; + + tnapi->int_mbox = intmbx; + if (i < 4) + intmbx += 0x8; + else + intmbx += 0x4; + + tnapi->consmbox = rcvmbx; + tnapi->prodmbox = sndmbx; + + if (i) + tnapi->coal_now = HOSTCC_MODE_COAL_VEC1_NOW << (i - 1); + else + tnapi->coal_now = HOSTCC_MODE_NOW; + + if (!(tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX)) + break; + + /* + * If we support MSIX, we'll be using RSS. If we're using + * RSS, the first vector only handles link interrupts and the + * remaining vectors handle rx and tx interrupts. Reuse the + * mailbox values for the next iteration. The values we setup + * above are still useful for the single vectored mode. + */ + if (!i) + continue; + + rcvmbx += 0x8; + + if (sndmbx & 0x4) + sndmbx -= 0x4; + else + sndmbx += 0xc; + } + netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; -- cgit v0.10.2 From f77a6a8e6cee17b21a43bdf6b853cc2fc0e2c4df Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:04:37 +0000 Subject: tg3: Add tx and rx ring resource tracking This patch adds code to assign status block, tx producer ring and rx return ring resources needed for the other interrupt vectors. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4d16ce0..58a8986 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5722,28 +5722,31 @@ err_out: */ static void tg3_free_rings(struct tg3 *tp) { - struct tg3_napi *tnapi = &tp->napi[0]; - int i; + int i, j; - for (i = 0; i < TG3_TX_RING_SIZE; ) { - struct tx_ring_info *txp; - struct sk_buff *skb; + for (j = 0; j < tp->irq_cnt; j++) { + struct tg3_napi *tnapi = &tp->napi[j]; - txp = &tnapi->tx_buffers[i]; - skb = txp->skb; + for (i = 0; i < TG3_TX_RING_SIZE; ) { + struct tx_ring_info *txp; + struct sk_buff *skb; - if (skb == NULL) { - i++; - continue; - } + txp = &tnapi->tx_buffers[i]; + skb = txp->skb; - skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); + if (skb == NULL) { + i++; + continue; + } - txp->skb = NULL; + skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); - i += skb_shinfo(skb)->nr_frags + 1; + txp->skb = NULL; - dev_kfree_skb_any(skb); + i += skb_shinfo(skb)->nr_frags + 1; + + dev_kfree_skb_any(skb); + } } tg3_rx_prodring_free(tp, &tp->prodring[0]); @@ -5758,16 +5761,27 @@ static void tg3_free_rings(struct tg3 *tp) */ static int tg3_init_rings(struct tg3 *tp) { - struct tg3_napi *tnapi = &tp->napi[0]; + int i; /* Free up all the SKBs. */ tg3_free_rings(tp); - /* Zero out all descriptors. */ - memset(tnapi->tx_ring, 0, TG3_TX_RING_BYTES); + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; - tnapi->rx_rcb_ptr = 0; - memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + tnapi->last_tag = 0; + tnapi->last_irq_tag = 0; + tnapi->hw_status->status = 0; + tnapi->hw_status->status_tag = 0; + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + + tnapi->tx_prod = 0; + tnapi->tx_cons = 0; + memset(tnapi->tx_ring, 0, TG3_TX_RING_BYTES); + + tnapi->rx_rcb_ptr = 0; + memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + } return tg3_rx_prodring_alloc(tp, &tp->prodring[0]); } @@ -5778,31 +5792,41 @@ static int tg3_init_rings(struct tg3 *tp) */ static void tg3_free_consistent(struct tg3 *tp) { - struct tg3_napi *tnapi = &tp->napi[0]; + int i; - kfree(tnapi->tx_buffers); - tnapi->tx_buffers = NULL; - if (tnapi->tx_ring) { - pci_free_consistent(tp->pdev, TG3_TX_RING_BYTES, - tnapi->tx_ring, tnapi->tx_desc_mapping); - tnapi->tx_ring = NULL; - } - if (tnapi->rx_rcb) { - pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), - tnapi->rx_rcb, tnapi->rx_rcb_mapping); - tnapi->rx_rcb = NULL; - } - if (tnapi->hw_status) { - pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE, - tnapi->hw_status, - tnapi->status_mapping); - tnapi->hw_status = NULL; + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + + if (tnapi->tx_ring) { + pci_free_consistent(tp->pdev, TG3_TX_RING_BYTES, + tnapi->tx_ring, tnapi->tx_desc_mapping); + tnapi->tx_ring = NULL; + } + + kfree(tnapi->tx_buffers); + tnapi->tx_buffers = NULL; + + if (tnapi->rx_rcb) { + pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), + tnapi->rx_rcb, + tnapi->rx_rcb_mapping); + tnapi->rx_rcb = NULL; + } + + if (tnapi->hw_status) { + pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE, + tnapi->hw_status, + tnapi->status_mapping); + tnapi->hw_status = NULL; + } } + if (tp->hw_stats) { pci_free_consistent(tp->pdev, sizeof(struct tg3_hw_stats), tp->hw_stats, tp->stats_mapping); tp->hw_stats = NULL; } + tg3_rx_prodring_fini(tp, &tp->prodring[0]); } @@ -5812,44 +5836,49 @@ static void tg3_free_consistent(struct tg3 *tp) */ static int tg3_alloc_consistent(struct tg3 *tp) { - struct tg3_napi *tnapi = &tp->napi[0]; + int i; if (tg3_rx_prodring_init(tp, &tp->prodring[0])) return -ENOMEM; - tnapi->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * - TG3_TX_RING_SIZE, GFP_KERNEL); - if (!tnapi->tx_buffers) + tp->hw_stats = pci_alloc_consistent(tp->pdev, + sizeof(struct tg3_hw_stats), + &tp->stats_mapping); + if (!tp->hw_stats) goto err_out; - tnapi->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, - &tnapi->tx_desc_mapping); - if (!tnapi->tx_ring) - goto err_out; + memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); - tnapi->hw_status = pci_alloc_consistent(tp->pdev, - TG3_HW_STATUS_SIZE, - &tnapi->status_mapping); - if (!tnapi->hw_status) - goto err_out; + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; - memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + tnapi->hw_status = pci_alloc_consistent(tp->pdev, + TG3_HW_STATUS_SIZE, + &tnapi->status_mapping); + if (!tnapi->hw_status) + goto err_out; - tnapi->rx_rcb = pci_alloc_consistent(tp->pdev, - TG3_RX_RCB_RING_BYTES(tp), - &tnapi->rx_rcb_mapping); - if (!tnapi->rx_rcb) - goto err_out; + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); - memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + tnapi->rx_rcb = pci_alloc_consistent(tp->pdev, + TG3_RX_RCB_RING_BYTES(tp), + &tnapi->rx_rcb_mapping); + if (!tnapi->rx_rcb) + goto err_out; - tp->hw_stats = pci_alloc_consistent(tp->pdev, - sizeof(struct tg3_hw_stats), - &tp->stats_mapping); - if (!tp->hw_stats) - goto err_out; + memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); - memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); + tnapi->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * + TG3_TX_RING_SIZE, GFP_KERNEL); + if (!tnapi->tx_buffers) + goto err_out; + + tnapi->tx_ring = pci_alloc_consistent(tp->pdev, + TG3_TX_RING_BYTES, + &tnapi->tx_desc_mapping); + if (!tnapi->tx_ring) + goto err_out; + } return 0; @@ -5910,7 +5939,6 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int static int tg3_abort_hw(struct tg3 *tp, int silent) { int i, err; - struct tg3_napi *tnapi = &tp->napi[0]; tg3_disable_ints(tp); @@ -5962,8 +5990,11 @@ static int tg3_abort_hw(struct tg3 *tp, int silent) err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE, silent); err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE, silent); - if (tnapi->hw_status) - memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + if (tnapi->hw_status) + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + } if (tp->hw_stats) memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); @@ -6290,12 +6321,15 @@ static int tg3_chip_reset(struct tg3 *tp) * sharing or irqpoll. */ tp->tg3_flags |= TG3_FLAG_CHIP_RESETTING; - if (tp->napi[0].hw_status) { - tp->napi[0].hw_status->status = 0; - tp->napi[0].hw_status->status_tag = 0; + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + if (tnapi->hw_status) { + tnapi->hw_status->status = 0; + tnapi->hw_status->status_tag = 0; + } + tnapi->last_tag = 0; + tnapi->last_irq_tag = 0; } - tp->napi[0].last_tag = 0; - tp->napi[0].last_irq_tag = 0; smp_mb(); for (i = 0; i < tp->irq_cnt; i++) @@ -6829,7 +6863,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) static void tg3_rings_reset(struct tg3 *tp) { int i; - u32 txrcb, rxrcb, limit; + u32 stblk, txrcb, rxrcb, limit; struct tg3_napi *tnapi = &tp->napi[0]; /* Disable all transmit rings but the first. */ @@ -6861,10 +6895,20 @@ static void tg3_rings_reset(struct tg3 *tp) tw32_mailbox_f(tp->napi[0].int_mbox, 1); /* Zero mailbox registers. */ - tp->napi[0].tx_prod = 0; - tp->napi[0].tx_cons = 0; - tw32_mailbox(tp->napi[0].prodmbox, 0); - tw32_rx_mbox(tp->napi[0].consmbox, 0); + if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) { + for (i = 1; i < TG3_IRQ_MAX_VECS; i++) { + tp->napi[i].tx_prod = 0; + tp->napi[i].tx_cons = 0; + tw32_mailbox(tp->napi[i].prodmbox, 0); + tw32_rx_mbox(tp->napi[i].consmbox, 0); + tw32_mailbox_f(tp->napi[i].int_mbox, 1); + } + } else { + tp->napi[0].tx_prod = 0; + tp->napi[0].tx_cons = 0; + tw32_mailbox(tp->napi[0].prodmbox, 0); + tw32_rx_mbox(tp->napi[0].consmbox, 0); + } /* Make sure the NIC-based send BD rings are disabled. */ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { @@ -6885,14 +6929,44 @@ static void tg3_rings_reset(struct tg3 *tp) tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tnapi->status_mapping & 0xffffffff)); - tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping, - (TG3_TX_RING_SIZE << - BDINFO_FLAGS_MAXLEN_SHIFT), - NIC_SRAM_TX_BUFFER_DESC); + if (tnapi->tx_ring) { + tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping, + (TG3_TX_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + NIC_SRAM_TX_BUFFER_DESC); + txrcb += TG3_BDINFO_SIZE; + } - tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping, - (TG3_RX_RCB_RING_SIZE(tp) << - BDINFO_FLAGS_MAXLEN_SHIFT), 0); + if (tnapi->rx_rcb) { + tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping, + (TG3_RX_RCB_RING_SIZE(tp) << + BDINFO_FLAGS_MAXLEN_SHIFT), 0); + rxrcb += TG3_BDINFO_SIZE; + } + + stblk = HOSTCC_STATBLCK_RING1; + + for (i = 1, tnapi++; i < tp->irq_cnt; i++, tnapi++) { + u64 mapping = (u64)tnapi->status_mapping; + tw32(stblk + TG3_64BIT_REG_HIGH, mapping >> 32); + tw32(stblk + TG3_64BIT_REG_LOW, mapping & 0xffffffff); + + /* Clear status block in ram. */ + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + + tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping, + (TG3_TX_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + NIC_SRAM_TX_BUFFER_DESC); + + tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping, + (TG3_RX_RCB_RING_SIZE(tp) << + BDINFO_FLAGS_MAXLEN_SHIFT), 0); + + stblk += 8; + txrcb += TG3_BDINFO_SIZE; + rxrcb += TG3_BDINFO_SIZE; + } } /* tp->lock is held. */ diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 65bbd77..6452d48 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1117,7 +1117,8 @@ #define HOSTCC_SND_CON_IDX_13 0x00003cf4 #define HOSTCC_SND_CON_IDX_14 0x00003cf8 #define HOSTCC_SND_CON_IDX_15 0x00003cfc -/* 0x3d00 --> 0x4000 unused */ +#define HOSTCC_STATBLCK_RING1 0x00003d00 +/* 0x3d04 --> 0x4000 unused */ /* Memory arbiter control registers */ #define MEMARB_MODE 0x00004000 -- cgit v0.10.2 From 89aeb3bceaa1a02651206a76a7b9dcb8f3884702 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:08:58 +0000 Subject: tg3: Update intmbox and coal_now for msix This patch fixes up two spots that need attention now that msix support has been added. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 58a8986..5389654 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -614,25 +614,33 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum) static void tg3_disable_ints(struct tg3 *tp) { + int i; + tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT)); - tw32_mailbox_f(tp->napi[0].int_mbox, 0x00000001); + for (i = 0; i < tp->irq_max; i++) + tw32_mailbox_f(tp->napi[i].int_mbox, 0x00000001); } static void tg3_enable_ints(struct tg3 *tp) { - u32 coal_now; - struct tg3_napi *tnapi = &tp->napi[0]; + int i; + u32 coal_now = 0; + tp->irq_sync = 0; wmb(); tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); - tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); - if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) + + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); + if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) + tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); - coal_now = tnapi->coal_now; + coal_now |= tnapi->coal_now; + } /* Force an initial interrupt */ if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && -- cgit v0.10.2 From fe5f5787f0866e9f883bdd90018a354f2f3defd1 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:09:39 +0000 Subject: tg3: Add TSS support This patch exposes the additional transmit rings to the kernel and makes the necessary modifications to transmit, open, and close paths. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5389654..2e0f4a5 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -704,11 +704,13 @@ static inline void tg3_netif_stop(struct tg3 *tp) static inline void tg3_netif_start(struct tg3 *tp) { struct tg3_napi *tnapi = &tp->napi[0]; - netif_wake_queue(tp->dev); - /* NOTE: unconditional netif_wake_queue is only appropriate - * so long as all callers are assured to have free tx slots - * (such as after tg3_init_hw) + + /* NOTE: unconditional netif_tx_wake_all_queues is only + * appropriate so long as all callers are assured to + * have free tx slots (such as after tg3_init_hw) */ + netif_tx_wake_all_queues(tp->dev); + napi_enable(&tnapi->napi); tnapi->hw_status->status |= SD_STATUS_UPDATED; tg3_enable_ints(tp); @@ -4294,6 +4296,13 @@ static void tg3_tx(struct tg3_napi *tnapi) struct tg3 *tp = tnapi->tp; u32 hw_idx = tnapi->hw_status->idx[0].tx_consumer; u32 sw_idx = tnapi->tx_cons; + struct netdev_queue *txq; + int index = tnapi - tp->napi; + + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + index--; + + txq = netdev_get_tx_queue(tp->dev, index); while (sw_idx != hw_idx) { struct tx_ring_info *ri = &tnapi->tx_buffers[sw_idx]; @@ -4335,13 +4344,13 @@ static void tg3_tx(struct tg3_napi *tnapi) */ smp_mb(); - if (unlikely(netif_queue_stopped(tp->dev) && + if (unlikely(netif_tx_queue_stopped(txq) && (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)))) { - netif_tx_lock(tp->dev); - if (netif_queue_stopped(tp->dev) && + __netif_tx_lock(txq, smp_processor_id()); + if (netif_tx_queue_stopped(txq) && (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi))) - netif_wake_queue(tp->dev); - netif_tx_unlock(tp->dev); + netif_tx_wake_queue(txq); + __netif_tx_unlock(txq); } } @@ -5156,9 +5165,13 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, u32 len, entry, base_flags, mss; struct skb_shared_info *sp; dma_addr_t mapping; - struct tg3_napi *tnapi = &tp->napi[0]; + struct tg3_napi *tnapi; + struct netdev_queue *txq; - len = skb_headlen(skb); + txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); + tnapi = &tp->napi[skb_get_queue_mapping(skb)]; + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + tnapi++; /* We are running in BH disabled context with netif_tx_lock * and TX reclaim runs via tp->napi.poll inside of a software @@ -5166,8 +5179,8 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, * no IRQ context deadlocks to worry about either. Rejoice! */ if (unlikely(tg3_tx_avail(tnapi) <= (skb_shinfo(skb)->nr_frags + 1))) { - if (!netif_queue_stopped(dev)) { - netif_stop_queue(dev); + if (!netif_tx_queue_stopped(txq)) { + netif_tx_stop_queue(txq); /* This is a hard error, log it. */ printk(KERN_ERR PFX "%s: BUG! Tx Ring full when " @@ -5226,6 +5239,8 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, tnapi->tx_buffers[entry].skb = skb; + len = skb_headlen(skb); + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); @@ -5255,9 +5270,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, tnapi->tx_prod = entry; if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) { - netif_stop_queue(dev); + netif_tx_stop_queue(txq); if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)) - netif_wake_queue(tp->dev); + netif_tx_wake_queue(txq); } out_unlock: @@ -8047,6 +8062,8 @@ static bool tg3_enable_msix(struct tg3 *tp) for (i = 0; i < tp->irq_max; i++) tp->napi[i].irq_vec = msix_ent[i].vector; + tp->dev->real_num_tx_queues = tp->irq_cnt - 1; + return true; } @@ -8076,6 +8093,7 @@ defcfg: if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) { tp->irq_cnt = 1; tp->napi[0].irq_vec = tp->pdev->irq; + tp->dev->real_num_tx_queues = 1; } } @@ -8211,7 +8229,7 @@ static int tg3_open(struct net_device *dev) tg3_full_unlock(tp); - netif_start_queue(dev); + netif_tx_start_all_queues(dev); return 0; @@ -8471,7 +8489,7 @@ static int tg3_close(struct net_device *dev) napi_disable(&tp->napi[0].napi); cancel_work_sync(&tp->reset_task); - netif_stop_queue(dev); + netif_tx_stop_all_queues(dev); del_timer_sync(&tp->timer); @@ -13560,7 +13578,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_free_res; } - dev = alloc_etherdev(sizeof(*tp)); + dev = alloc_etherdev_mq(sizeof(*tp), TG3_IRQ_MAX_VECS); if (!dev) { printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); err = -ENOMEM; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 6452d48..d1c7add 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -822,6 +822,7 @@ #define SNDBDI_MODE_RESET 0x00000001 #define SNDBDI_MODE_ENABLE 0x00000002 #define SNDBDI_MODE_ATTN_ENABLE 0x00000004 +#define SNDBDI_MODE_MULTI_TXQ_EN 0x00000020 #define SNDBDI_STATUS 0x00001804 #define SNDBDI_STATUS_ERROR_ATTN 0x00000004 #define SNDBDI_IN_PROD_IDX_0 0x00001808 -- cgit v0.10.2 From fed9781081aa9600765346c108ff22751e003715 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:10:19 +0000 Subject: tg3: Enable NAPI instances for other int vectors This patch adds code to enable and disable the rest of the NAPI instances. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2e0f4a5..a4e46e4 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -694,25 +694,39 @@ static void tg3_int_reenable(struct tg3_napi *tnapi) HOSTCC_MODE_ENABLE | tnapi->coal_now); } +static void tg3_napi_disable(struct tg3 *tp) +{ + int i; + + for (i = tp->irq_cnt - 1; i >= 0; i--) + napi_disable(&tp->napi[i].napi); +} + +static void tg3_napi_enable(struct tg3 *tp) +{ + int i; + + for (i = 0; i < tp->irq_cnt; i++) + napi_enable(&tp->napi[i].napi); +} + static inline void tg3_netif_stop(struct tg3 *tp) { tp->dev->trans_start = jiffies; /* prevent tx timeout */ - napi_disable(&tp->napi[0].napi); + tg3_napi_disable(tp); netif_tx_disable(tp->dev); } static inline void tg3_netif_start(struct tg3 *tp) { - struct tg3_napi *tnapi = &tp->napi[0]; - /* NOTE: unconditional netif_tx_wake_all_queues is only * appropriate so long as all callers are assured to * have free tx slots (such as after tg3_init_hw) */ netif_tx_wake_all_queues(tp->dev); - napi_enable(&tnapi->napi); - tnapi->hw_status->status |= SD_STATUS_UPDATED; + tg3_napi_enable(tp); + tp->napi[0].hw_status->status |= SD_STATUS_UPDATED; tg3_enable_ints(tp); } @@ -4958,7 +4972,7 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy) tg3_full_unlock(tp); del_timer_sync(&tp->timer); tp->irq_sync = 0; - napi_enable(&tp->napi[0].napi); + tg3_napi_enable(tp); dev_close(tp->dev); tg3_full_lock(tp, 0); } @@ -8153,7 +8167,7 @@ static int tg3_open(struct net_device *dev) if (err) goto err_out1; - napi_enable(&tp->napi[0].napi); + tg3_napi_enable(tp); for (i = 0; i < tp->irq_cnt; i++) { struct tg3_napi *tnapi = &tp->napi[i]; @@ -8240,7 +8254,7 @@ err_out3: } err_out2: - napi_disable(&tp->napi[0].napi); + tg3_napi_disable(tp); tg3_free_consistent(tp); err_out1: @@ -8486,7 +8500,7 @@ static int tg3_close(struct net_device *dev) int i; struct tg3 *tp = netdev_priv(dev); - napi_disable(&tp->napi[0].napi); + tg3_napi_disable(tp); cancel_work_sync(&tp->reset_task); netif_tx_stop_all_queues(dev); -- cgit v0.10.2 From b6080e126012047d42e53154189fdca286d0600e Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:12:00 +0000 Subject: tg3: Add coalesce parameters for msix vectors This patch adds code to tune the coalescing parameters for the other msix vectors. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a4e46e4..f51c29c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6876,24 +6876,63 @@ static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr, static void __tg3_set_rx_mode(struct net_device *); static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) { - tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs); - tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs); - tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames); - tw32(HOSTCC_TXMAX_FRAMES, ec->tx_max_coalesced_frames); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { - tw32(HOSTCC_RXCOAL_TICK_INT, ec->rx_coalesce_usecs_irq); - tw32(HOSTCC_TXCOAL_TICK_INT, ec->tx_coalesce_usecs_irq); + int i; + + if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) { + tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs); + tw32(HOSTCC_TXMAX_FRAMES, ec->tx_max_coalesced_frames); + tw32(HOSTCC_TXCOAL_MAXF_INT, ec->tx_max_coalesced_frames_irq); + + tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs); + tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames); + tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq); + } else { + tw32(HOSTCC_TXCOL_TICKS, 0); + tw32(HOSTCC_TXMAX_FRAMES, 0); + tw32(HOSTCC_TXCOAL_MAXF_INT, 0); + + tw32(HOSTCC_RXCOL_TICKS, 0); + tw32(HOSTCC_RXMAX_FRAMES, 0); + tw32(HOSTCC_RXCOAL_MAXF_INT, 0); } - tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq); - tw32(HOSTCC_TXCOAL_MAXF_INT, ec->tx_max_coalesced_frames_irq); + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { u32 val = ec->stats_block_coalesce_usecs; + tw32(HOSTCC_RXCOAL_TICK_INT, ec->rx_coalesce_usecs_irq); + tw32(HOSTCC_TXCOAL_TICK_INT, ec->tx_coalesce_usecs_irq); + if (!netif_carrier_ok(tp->dev)) val = 0; tw32(HOSTCC_STAT_COAL_TICKS, val); } + + for (i = 0; i < tp->irq_cnt - 1; i++) { + u32 reg; + + reg = HOSTCC_RXCOL_TICKS_VEC1 + i * 0x18; + tw32(reg, ec->rx_coalesce_usecs); + reg = HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18; + tw32(reg, ec->tx_coalesce_usecs); + reg = HOSTCC_RXMAX_FRAMES_VEC1 + i * 0x18; + tw32(reg, ec->rx_max_coalesced_frames); + reg = HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18; + tw32(reg, ec->tx_max_coalesced_frames); + reg = HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18; + tw32(reg, ec->rx_max_coalesced_frames_irq); + reg = HOSTCC_TXCOAL_MAXF_INT_VEC1 + i * 0x18; + tw32(reg, ec->tx_max_coalesced_frames_irq); + } + + for (; i < tp->irq_max - 1; i++) { + tw32(HOSTCC_RXCOL_TICKS_VEC1 + i * 0x18, 0); + tw32(HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18, 0); + tw32(HOSTCC_RXMAX_FRAMES_VEC1 + i * 0x18, 0); + tw32(HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18, 0); + tw32(HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18, 0); + tw32(HOSTCC_TXCOAL_MAXF_INT_VEC1 + i * 0x18, 0); + } } /* tp->lock is held. */ diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d1c7add..978b6d9 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1119,7 +1119,15 @@ #define HOSTCC_SND_CON_IDX_14 0x00003cf8 #define HOSTCC_SND_CON_IDX_15 0x00003cfc #define HOSTCC_STATBLCK_RING1 0x00003d00 -/* 0x3d04 --> 0x4000 unused */ +/* 0x3d00 --> 0x3d80 unused */ + +#define HOSTCC_RXCOL_TICKS_VEC1 0x00003d80 +#define HOSTCC_TXCOL_TICKS_VEC1 0x00003d84 +#define HOSTCC_RXMAX_FRAMES_VEC1 0x00003d88 +#define HOSTCC_TXMAX_FRAMES_VEC1 0x00003d8c +#define HOSTCC_RXCOAL_MAXF_INT_VEC1 0x00003d90 +#define HOSTCC_TXCOAL_MAXF_INT_VEC1 0x00003d94 +/* 0x3d98 --> 0x4000 unused */ /* Memory arbiter control registers */ #define MEMARB_MODE 0x00004000 -- cgit v0.10.2 From baf8a94a572928710e9e60967d153a7bf3aebd9c Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:13:00 +0000 Subject: tg3: Add RSS support This patch adds code needed to enable RSS. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f51c29c..26e9db8 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -102,6 +102,7 @@ #define TG3_DEF_RX_RING_PENDING 200 #define TG3_RX_JUMBO_RING_SIZE 256 #define TG3_DEF_RX_JUMBO_RING_PENDING 100 +#define TG3_RSS_INDIR_TBL_SIZE 128 /* Do not place this n-ring entries value into the tp struct itself, * we really want to expose these constants to GCC so that modulo et @@ -7497,6 +7498,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) { + val = tr32(MSGINT_MODE); + val |= MSGINT_MODE_MULTIVEC_EN | MSGINT_MODE_ENABLE; + tw32(MSGINT_MODE, val); + } + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); udelay(40); @@ -7565,7 +7572,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE); if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8); - tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE); + val = SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE; + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + val |= SNDBDI_MODE_MULTI_TXQ_EN; + tw32(SNDBDI_MODE, val); tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE); if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) { @@ -7584,10 +7594,46 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(MAC_TX_MODE, tp->tx_mode); udelay(100); + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) { + u32 reg = MAC_RSS_INDIR_TBL_0; + u8 *ent = (u8 *)&val; + + /* Setup the indirection table */ + for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++) { + int idx = i % sizeof(val); + + ent[idx] = i % (tp->irq_cnt - 1); + if (idx == sizeof(val) - 1) { + tw32(reg, val); + reg += 4; + } + } + + /* Setup the "secret" hash key. */ + tw32(MAC_RSS_HASH_KEY_0, 0x5f865437); + tw32(MAC_RSS_HASH_KEY_1, 0xe4ac62cc); + tw32(MAC_RSS_HASH_KEY_2, 0x50103a45); + tw32(MAC_RSS_HASH_KEY_3, 0x36621985); + tw32(MAC_RSS_HASH_KEY_4, 0xbf14c0e8); + tw32(MAC_RSS_HASH_KEY_5, 0x1bc27a1e); + tw32(MAC_RSS_HASH_KEY_6, 0x84f4b556); + tw32(MAC_RSS_HASH_KEY_7, 0x094ea6fe); + tw32(MAC_RSS_HASH_KEY_8, 0x7dda01e7); + tw32(MAC_RSS_HASH_KEY_9, 0xc04d7481); + } + tp->rx_mode = RX_MODE_ENABLE; if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) + tp->rx_mode |= RX_MODE_RSS_ENABLE | + RX_MODE_RSS_ITBL_HASH_BITS_7 | + RX_MODE_RSS_IPV6_HASH_EN | + RX_MODE_RSS_TCP_IPV6_HASH_EN | + RX_MODE_RSS_IPV4_HASH_EN | + RX_MODE_RSS_TCP_IPV4_HASH_EN; + tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); @@ -8112,6 +8158,8 @@ static bool tg3_enable_msix(struct tg3 *tp) tp->irq_cnt = rc; } + tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS; + for (i = 0; i < tp->irq_max; i++) tp->napi[i].irq_vec = msix_ent[i].vector; @@ -8140,6 +8188,8 @@ static void tg3_ints_init(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { u32 msi_mode = tr32(MSGINT_MODE); + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + msi_mode |= MSGINT_MODE_MULTIVEC_EN; tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); } defcfg: @@ -8157,6 +8207,7 @@ static void tg3_ints_fini(struct tg3 *tp) else if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) pci_disable_msi(tp->pdev); tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI_OR_MSIX; + tp->tg3_flags3 &= ~TG3_FLG3_ENABLE_RSS; } static int tg3_open(struct net_device *dev) diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 978b6d9..348add2 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -446,6 +446,12 @@ #define RX_MODE_PROMISC 0x00000100 #define RX_MODE_NO_CRC_CHECK 0x00000200 #define RX_MODE_KEEP_VLAN_TAG 0x00000400 +#define RX_MODE_RSS_IPV4_HASH_EN 0x00010000 +#define RX_MODE_RSS_TCP_IPV4_HASH_EN 0x00020000 +#define RX_MODE_RSS_IPV6_HASH_EN 0x00040000 +#define RX_MODE_RSS_TCP_IPV6_HASH_EN 0x00080000 +#define RX_MODE_RSS_ITBL_HASH_BITS_7 0x00700000 +#define RX_MODE_RSS_ENABLE 0x00800000 #define RX_MODE_IPV6_CSUM_ENABLE 0x01000000 #define MAC_RX_STATUS 0x0000046c #define RX_STATUS_REMOTE_TX_XOFFED 0x00000001 @@ -690,7 +696,22 @@ /* 0x5b8 --> 0x600 unused */ #define MAC_TX_MAC_STATE_BASE 0x00000600 /* 16 bytes */ #define MAC_RX_MAC_STATE_BASE 0x00000610 /* 20 bytes */ -/* 0x624 --> 0x800 unused */ +/* 0x624 --> 0x670 unused */ + +#define MAC_RSS_INDIR_TBL_0 0x00000630 + +#define MAC_RSS_HASH_KEY_0 0x00000670 +#define MAC_RSS_HASH_KEY_1 0x00000674 +#define MAC_RSS_HASH_KEY_2 0x00000678 +#define MAC_RSS_HASH_KEY_3 0x0000067c +#define MAC_RSS_HASH_KEY_4 0x00000680 +#define MAC_RSS_HASH_KEY_5 0x00000684 +#define MAC_RSS_HASH_KEY_6 0x00000688 +#define MAC_RSS_HASH_KEY_7 0x0000068c +#define MAC_RSS_HASH_KEY_8 0x00000690 +#define MAC_RSS_HASH_KEY_9 0x00000694 +/* 0x698 --> 0x800 unused */ + #define MAC_TX_STATS_OCTETS 0x00000800 #define MAC_TX_STATS_RESV1 0x00000804 #define MAC_TX_STATS_COLLISIONS 0x00000808 @@ -1465,6 +1486,7 @@ #define MSGINT_MODE 0x00006000 #define MSGINT_MODE_RESET 0x00000001 #define MSGINT_MODE_ENABLE 0x00000002 +#define MSGINT_MODE_MULTIVEC_EN 0x00000080 #define MSGINT_STATUS 0x00006004 #define MSGINT_FIFO 0x00006008 /* 0x600c --> 0x6400 unused */ @@ -2704,6 +2726,7 @@ struct tg3 { #define TG3_FLG3_NO_NVRAM 0x00004000 #define TG3_FLG3_TOGGLE_10_100_L1PLLPD 0x00008000 #define TG3_FLG3_PHY_IS_FET 0x00010000 +#define TG3_FLG3_ENABLE_RSS 0x00020000 struct timer_list timer; u16 timer_counter; -- cgit v0.10.2 From 0c1d0e2b05e92ad847b3ebe1c75b7974086bc8fa Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:16:33 +0000 Subject: tg3: Adjust RSS ring allocation strategies When multivector RSS is enabled, the first interrupt vector is only used to report link interrupts and error conditions. This patch changes the code so that rx and tx ring resources are not allocated for this vector. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 26e9db8..5782511 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4804,7 +4804,8 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) struct tg3 *tp = tnapi->tp; prefetch(tnapi->hw_status); - prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); + if (tnapi->rx_rcb) + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) napi_schedule(&tnapi->napi); @@ -4822,7 +4823,8 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) struct tg3 *tp = tnapi->tp; prefetch(tnapi->hw_status); - prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); + if (tnapi->rx_rcb) + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); /* * Writing any value to intr-mbox-0 clears PCI INTA# and * chip-internal interrupt pending events. @@ -5765,6 +5767,9 @@ static void tg3_free_rings(struct tg3 *tp) for (j = 0; j < tp->irq_cnt; j++) { struct tg3_napi *tnapi = &tp->napi[j]; + if (!tnapi->tx_buffers) + continue; + for (i = 0; i < TG3_TX_RING_SIZE; ) { struct tx_ring_info *txp; struct sk_buff *skb; @@ -5815,10 +5820,12 @@ static int tg3_init_rings(struct tg3 *tp) tnapi->tx_prod = 0; tnapi->tx_cons = 0; - memset(tnapi->tx_ring, 0, TG3_TX_RING_BYTES); + if (tnapi->tx_ring) + memset(tnapi->tx_ring, 0, TG3_TX_RING_BYTES); tnapi->rx_rcb_ptr = 0; - memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + if (tnapi->rx_rcb) + memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); } return tg3_rx_prodring_alloc(tp, &tp->prodring[0]); @@ -5898,6 +5905,13 @@ static int tg3_alloc_consistent(struct tg3 *tp) memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + /* + * If multivector RSS is enabled, vector 0 does not handle + * rx or tx interrupts. Don't allocate any resources for it. + */ + if (!i && (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) + continue; + tnapi->rx_rcb = pci_alloc_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), &tnapi->rx_rcb_mapping); @@ -10166,8 +10180,13 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) struct tg3_napi *tnapi, *rnapi; struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; - tnapi = &tp->napi[0]; - rnapi = &tp->napi[0]; + if (tp->irq_cnt > 1) { + tnapi = &tp->napi[1]; + rnapi = &tp->napi[1]; + } else { + tnapi = &tp->napi[0]; + rnapi = &tp->napi[0]; + } coal_now = tnapi->coal_now | rnapi->coal_now; if (loopback_mode == TG3_MAC_LOOPBACK) { -- cgit v0.10.2 From 8d9d7cfc0ec2fe37ff9afd74326d03f38f96ad1b Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:19:05 +0000 Subject: tg3: Assign rx ret producer indexes by vector When RSS is enabled, the status block format changes slightly. The "rx_jumbo_consumer", "reserved", and "rx_mini_consumer" members get mapped to the other three rx return ring producer indexes. This patch introduces a new per-interrupt member which identifies which location in the status block a particular vector should look for return ring updates. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5782511..f71ea46 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -667,7 +667,7 @@ static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) } /* check for RX/TX work to do */ if (sblk->idx[0].tx_consumer != tnapi->tx_cons || - sblk->idx[0].rx_producer != tnapi->rx_rcb_ptr) + *(tnapi->rx_rcb_prod_idx) != tnapi->rx_rcb_ptr) work_exists = 1; return work_exists; @@ -4518,7 +4518,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) int received; struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; - hw_idx = tnapi->hw_status->idx[0].rx_producer; + hw_idx = *(tnapi->rx_rcb_prod_idx); /* * We need to order the read of hw_idx and the read of * the opaque cookie. @@ -4649,7 +4649,7 @@ next_pkt_nopost: /* Refresh hw_idx to see if there is new work */ if (sw_idx == hw_idx) { - hw_idx = tnapi->hw_status->idx[0].rx_producer; + hw_idx = *(tnapi->rx_rcb_prod_idx); rmb(); } } @@ -4711,7 +4711,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) * All RX "locking" is done by ensuring outside * code synchronizes with tg3->napi.poll() */ - if (sblk->idx[0].rx_producer != tnapi->rx_rcb_ptr) + if (*(tnapi->rx_rcb_prod_idx) != tnapi->rx_rcb_ptr) work_done += tg3_rx(tnapi, budget - work_done); return work_done; @@ -5896,6 +5896,7 @@ static int tg3_alloc_consistent(struct tg3 *tp) for (i = 0; i < tp->irq_cnt; i++) { struct tg3_napi *tnapi = &tp->napi[i]; + struct tg3_hw_status *sblk; tnapi->hw_status = pci_alloc_consistent(tp->pdev, TG3_HW_STATUS_SIZE, @@ -5904,6 +5905,28 @@ static int tg3_alloc_consistent(struct tg3 *tp) goto err_out; memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + sblk = tnapi->hw_status; + + /* + * When RSS is enabled, the status block format changes + * slightly. The "rx_jumbo_consumer", "reserved", + * and "rx_mini_consumer" members get mapped to the + * other three rx return ring producer indexes. + */ + switch (i) { + default: + tnapi->rx_rcb_prod_idx = &sblk->idx[0].rx_producer; + break; + case 2: + tnapi->rx_rcb_prod_idx = &sblk->rx_jumbo_consumer; + break; + case 3: + tnapi->rx_rcb_prod_idx = &sblk->reserved; + break; + case 4: + tnapi->rx_rcb_prod_idx = &sblk->rx_mini_consumer; + break; + } /* * If multivector RSS is enabled, vector 0 does not handle diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 348add2..685d971 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2538,6 +2538,7 @@ struct tg3_napi { u32 consmbox; u32 rx_rcb_ptr; + u16 *rx_rcb_prod_idx; struct tg3_rx_buffer_desc *rx_rcb; struct tg3_tx_buffer_desc *tx_ring; -- cgit v0.10.2 From f6eb9b1fc1411d22c073f5264e5630a541d0f7df Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:19:53 +0000 Subject: tg3: Add 5717 asic rev This patch adds the 5717 asic rev. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f71ea46..f8bb5b7 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -111,7 +111,8 @@ * replace things like '% foo' with '& (foo - 1)'. */ #define TG3_RX_RCB_RING_SIZE(tp) \ - ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ? 512 : 1024) + (((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && \ + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) ? 512 : 1024) #define TG3_TX_RING_SIZE 512 #define TG3_DEF_TX_RING_PENDING (TG3_TX_RING_SIZE - 1) @@ -733,13 +734,15 @@ static inline void tg3_netif_start(struct tg3 *tp) static void tg3_switch_clocks(struct tg3 *tp) { - u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); + u32 clock_ctrl; u32 orig_clock_ctrl; if ((tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) return; + clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); + orig_clock_ctrl = clock_ctrl; clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN | CLOCK_CTRL_CLKRUN_OENABLE | @@ -1993,8 +1996,9 @@ static void tg3_frob_aux_power(struct tg3 *tp) if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0) return; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { struct net_device *dev_peer; dev_peer = pci_get_drvdata(tp->pdev_peer); @@ -5211,6 +5215,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, mss = 0; if ((mss = skb_shinfo(skb)->gso_size) != 0) { int tcp_opt_len, ip_tcp_len; + u32 hdrlen; if (skb_header_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { @@ -5219,7 +5224,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, } if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) - mss |= (skb_headlen(skb) - ETH_HLEN) << 9; + hdrlen = skb_headlen(skb) - ETH_HLEN; else { struct iphdr *iph = ip_hdr(skb); @@ -5228,9 +5233,17 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, iph->check = 0; iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); - mss |= (ip_tcp_len + tcp_opt_len) << 9; + hdrlen = ip_tcp_len + tcp_opt_len; } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + mss |= (hdrlen & 0xc) << 12; + if (hdrlen & 0x10) + base_flags |= 0x00000010; + base_flags |= (hdrlen & 0x3e0) << 5; + } else + mss |= hdrlen << 9; + base_flags |= (TXD_FLAG_CPU_PRE_DMA | TXD_FLAG_CPU_POST_DMA); @@ -5258,6 +5271,10 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, len = skb_headlen(skb); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + !mss && skb->len > ETH_DATA_LEN) + base_flags |= TXD_FLAG_JMB_PKT; + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); @@ -6564,7 +6581,9 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_mdio_start(tp); if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && - tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) { + tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { val = tr32(0x7c00); tw32(0x7c00, val | (1 << 25)); @@ -6993,7 +7012,9 @@ static void tg3_rings_reset(struct tg3 *tp) /* Disable all receive return rings but the first. */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17; + else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 4; @@ -7197,7 +7218,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return err; if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { /* This value is determined during the probe time DMA * engine test, tg3_test_dma. */ @@ -7351,7 +7373,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_DISABLED); } - val = RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + val = (RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT) | + (RX_STD_MAX_SIZE << 2); + else + val = RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT; } else val = RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT; @@ -7366,6 +7392,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, tpr->rx_jmb_ptr); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + tw32(STD_REPLENISH_LWM, 32); + tw32(JMB_REPLENISH_LWM, 16); + } + tg3_rings_reset(tp); /* Initialize MAC address and backoff seed. */ @@ -8021,6 +8052,7 @@ static int tg3_test_interrupt(struct tg3 *tp) struct tg3_napi *tnapi = &tp->napi[0]; struct net_device *dev = tp->dev; int err, i, intr_ok = 0; + u32 val; if (!netif_running(dev)) return -ENODEV; @@ -8029,6 +8061,16 @@ static int tg3_test_interrupt(struct tg3 *tp) free_irq(tnapi->irq_vec, tnapi); + /* + * Turn off MSI one shot mode. Otherwise this test has no + * observable way to know whether the interrupt was delivered. + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { + val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE; + tw32(MSGINT_MODE, val); + } + err = request_irq(tnapi->irq_vec, tg3_test_isr, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi); if (err) @@ -8064,8 +8106,15 @@ static int tg3_test_interrupt(struct tg3 *tp) if (err) return err; - if (intr_ok) + if (intr_ok) { + /* Reenable MSI one shot mode. */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { + val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE; + tw32(MSGINT_MODE, val); + } return 0; + } return -EIO; } @@ -8350,13 +8399,13 @@ static int tg3_open(struct net_device *dev) goto err_out2; } - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) { - u32 val = tr32(PCIE_TRANSACTION_CFG); + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && + (tp->tg3_flags2 & TG3_FLG2_USING_MSI) && + (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)) { + u32 val = tr32(PCIE_TRANSACTION_CFG); - tw32(PCIE_TRANSACTION_CFG, - val | PCIE_TRANS_CFG_1SHOT_MSI); - } + tw32(PCIE_TRANSACTION_CFG, + val | PCIE_TRANS_CFG_1SHOT_MSI); } } @@ -9392,7 +9441,8 @@ static int tg3_set_tso(struct net_device *dev, u32 value) (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) dev->features |= NETIF_F_TSO_ECN; } else dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN); @@ -12291,8 +12341,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) { u32 prod_id_asic_rev; - pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV, - &prod_id_asic_rev); + if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717C || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717S || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718C || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718S) + pci_read_config_dword(tp->pdev, + TG3PCI_GEN2_PRODID_ASICREV, + &prod_id_asic_rev); + else + pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV, + &prod_id_asic_rev); + tp->pci_chip_rev_id = prod_id_asic_rev; } @@ -12430,8 +12489,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl); - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) tp->pdev_peer = tg3_find_peer(tp); /* Intentionally exclude ASIC_REV_5906 */ @@ -12440,7 +12500,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) tp->tg3_flags3 |= TG3_FLG3_5755_PLUS; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || @@ -12490,8 +12551,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->irq_max = 1; +#ifdef TG3_NAPI + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + tp->tg3_flags |= TG3_FLAG_SUPPORT_MSIX; + tp->irq_max = TG3_IRQ_MAX_VECS; + } +#endif + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE; pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, @@ -12625,7 +12694,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->write32 = tg3_write_flush_reg32; } - if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) || (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) { tp->write32_tx_mbox = tg3_write32_tx_mbox; @@ -12684,7 +12752,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; /* Set up tp->grc_local_ctrl before calling tg3_set_power_state(). @@ -12762,7 +12831,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && !(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || @@ -13486,7 +13556,8 @@ static void __devinit tg3_init_link_config(struct tg3 *tp) static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) { - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { tp->bufmgr_config.mbuf_read_dma_low_water = DEFAULT_MB_RDMA_LOW_WATER_5705; tp->bufmgr_config.mbuf_mac_rx_low_water = @@ -13925,7 +13996,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) dev->features |= NETIF_F_TSO_ECN; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 685d971..5994476 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -46,6 +46,10 @@ #define TG3PCI_DEVICE_TIGON3_57788 0x1691 #define TG3PCI_DEVICE_TIGON3_5785_G 0x1699 /* GPHY */ #define TG3PCI_DEVICE_TIGON3_5785_F 0x16a0 /* 10/100 only */ +#define TG3PCI_DEVICE_TIGON3_5717C 0x1655 +#define TG3PCI_DEVICE_TIGON3_5717S 0x1656 +#define TG3PCI_DEVICE_TIGON3_5718C 0x1665 +#define TG3PCI_DEVICE_TIGON3_5718S 0x1666 /* 0x04 --> 0x64 unused */ #define TG3PCI_MSI_DATA 0x00000064 /* 0x66 --> 0x68 unused */ @@ -117,6 +121,7 @@ #define ASIC_REV_5761 0x5761 #define ASIC_REV_5785 0x5785 #define ASIC_REV_57780 0x57780 +#define ASIC_REV_5717 0x5717 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -203,20 +208,20 @@ #define TG3PCI_MEM_WIN_BASE_ADDR 0x0000007c #define TG3PCI_REG_DATA 0x00000080 #define TG3PCI_MEM_WIN_DATA 0x00000084 -#define TG3PCI_MODE_CTRL 0x00000088 -#define TG3PCI_MISC_CFG 0x0000008c #define TG3PCI_MISC_LOCAL_CTRL 0x00000090 /* 0x94 --> 0x98 unused */ #define TG3PCI_STD_RING_PROD_IDX 0x00000098 /* 64-bit */ #define TG3PCI_RCV_RET_RING_CON_IDX 0x000000a0 /* 64-bit */ -#define TG3PCI_SND_PROD_IDX 0x000000a8 /* 64-bit */ -/* 0xb0 --> 0xb8 unused */ +/* 0xa0 --> 0xb8 unused */ #define TG3PCI_DUAL_MAC_CTRL 0x000000b8 #define DUAL_MAC_CTRL_CH_MASK 0x00000003 #define DUAL_MAC_CTRL_ID 0x00000004 #define TG3PCI_PRODID_ASICREV 0x000000bc #define PROD_ID_ASIC_REV_MASK 0x0fffffff -/* 0xc0 --> 0x110 unused */ +/* 0xc0 --> 0xf4 unused */ + +#define TG3PCI_GEN2_PRODID_ASICREV 0x000000f4 +/* 0xf8 --> 0x200 unused */ #define TG3_CORR_ERR_STAT 0x00000110 #define TG3_CORR_ERR_STAT_CLEAR 0xffffffff @@ -972,7 +977,11 @@ #define RCVBDI_MINI_THRESH 0x00002c14 #define RCVBDI_STD_THRESH 0x00002c18 #define RCVBDI_JUMBO_THRESH 0x00002c1c -/* 0x2c20 --> 0x3000 unused */ +/* 0x2c20 --> 0x2d00 unused */ + +#define STD_REPLENISH_LWM 0x00002d00 +#define JMB_REPLENISH_LWM 0x00002d04 +/* 0x2d08 --> 0x3000 unused */ /* Receive BD Completion Control Registers */ #define RCVCC_MODE 0x00003000 @@ -1486,6 +1495,7 @@ #define MSGINT_MODE 0x00006000 #define MSGINT_MODE_RESET 0x00000001 #define MSGINT_MODE_ENABLE 0x00000002 +#define MSGINT_MODE_ONE_SHOT_DISABLE 0x00000020 #define MSGINT_MODE_MULTIVEC_EN 0x00000080 #define MSGINT_STATUS 0x00006004 #define MSGINT_FIFO 0x00006008 @@ -2124,6 +2134,7 @@ struct tg3_tx_buffer_desc { #define TXD_FLAG_IP_CSUM 0x0002 #define TXD_FLAG_END 0x0004 #define TXD_FLAG_IP_FRAG 0x0008 +#define TXD_FLAG_JMB_PKT 0x0008 #define TXD_FLAG_IP_FRAG_END 0x0010 #define TXD_FLAG_VLAN 0x0040 #define TXD_FLAG_COAL_NOW 0x0080 @@ -2520,7 +2531,7 @@ struct tg3_rx_prodring_set { dma_addr_t rx_jmb_mapping; }; -#define TG3_IRQ_MAX_VECS 1 +#define TG3_IRQ_MAX_VECS 5 struct tg3_napi { struct napi_struct napi ____cacheline_aligned; -- cgit v0.10.2 From a1b950d56de3c72bea3343f54de24c43fb7dc74e Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:20:17 +0000 Subject: tg3: Add 5717 NVRAM detection routines This patch adds NVRAM detection routines for the 5717. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f8bb5b7..2de1ab6 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10853,6 +10853,33 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) } } +static void __devinit tg3_nvram_get_pagesize(struct tg3 *tp, u32 nvmcfg1) +{ + switch (nvmcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) { + case FLASH_5752PAGE_SIZE_256: + tp->nvram_pagesize = 256; + break; + case FLASH_5752PAGE_SIZE_512: + tp->nvram_pagesize = 512; + break; + case FLASH_5752PAGE_SIZE_1K: + tp->nvram_pagesize = 1024; + break; + case FLASH_5752PAGE_SIZE_2K: + tp->nvram_pagesize = 2048; + break; + case FLASH_5752PAGE_SIZE_4K: + tp->nvram_pagesize = 4096; + break; + case FLASH_5752PAGE_SIZE_264: + tp->nvram_pagesize = 264; + break; + case FLASH_5752PAGE_SIZE_528: + tp->nvram_pagesize = 528; + break; + } +} + static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) { u32 nvcfg1; @@ -10884,26 +10911,7 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) } if (tp->tg3_flags2 & TG3_FLG2_FLASH) { - switch (nvcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) { - case FLASH_5752PAGE_SIZE_256: - tp->nvram_pagesize = 256; - break; - case FLASH_5752PAGE_SIZE_512: - tp->nvram_pagesize = 512; - break; - case FLASH_5752PAGE_SIZE_1K: - tp->nvram_pagesize = 1024; - break; - case FLASH_5752PAGE_SIZE_2K: - tp->nvram_pagesize = 2048; - break; - case FLASH_5752PAGE_SIZE_4K: - tp->nvram_pagesize = 4096; - break; - case FLASH_5752PAGE_SIZE_264: - tp->nvram_pagesize = 264; - break; - } + tg3_nvram_get_pagesize(tp, nvcfg1); } else { /* For eeprom, set pagesize to maximum eeprom size */ tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; @@ -11156,34 +11164,84 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) return; } - switch (nvcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) { - case FLASH_5752PAGE_SIZE_256: + tg3_nvram_get_pagesize(tp, nvcfg1); + if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 256; - break; - case FLASH_5752PAGE_SIZE_512: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 512; - break; - case FLASH_5752PAGE_SIZE_1K: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 1024; - break; - case FLASH_5752PAGE_SIZE_2K: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 2048; - break; - case FLASH_5752PAGE_SIZE_4K: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 4096; - break; - case FLASH_5752PAGE_SIZE_264: - tp->nvram_pagesize = 264; +} + + +static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1; + + nvcfg1 = tr32(NVRAM_CFG1); + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5717VENDOR_ATMEL_EEPROM: + case FLASH_5717VENDOR_MICRO_EEPROM: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + return; + case FLASH_5717VENDOR_ATMEL_MDB011D: + case FLASH_5717VENDOR_ATMEL_ADB011B: + case FLASH_5717VENDOR_ATMEL_ADB011D: + case FLASH_5717VENDOR_ATMEL_MDB021D: + case FLASH_5717VENDOR_ATMEL_ADB021B: + case FLASH_5717VENDOR_ATMEL_ADB021D: + case FLASH_5717VENDOR_ATMEL_45USPT: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5717VENDOR_ATMEL_MDB021D: + case FLASH_5717VENDOR_ATMEL_ADB021B: + case FLASH_5717VENDOR_ATMEL_ADB021D: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + default: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + } break; - case FLASH_5752PAGE_SIZE_528: - tp->nvram_pagesize = 528; + case FLASH_5717VENDOR_ST_M_M25PE10: + case FLASH_5717VENDOR_ST_A_M25PE10: + case FLASH_5717VENDOR_ST_M_M45PE10: + case FLASH_5717VENDOR_ST_A_M45PE10: + case FLASH_5717VENDOR_ST_M_M25PE20: + case FLASH_5717VENDOR_ST_A_M25PE20: + case FLASH_5717VENDOR_ST_M_M45PE20: + case FLASH_5717VENDOR_ST_A_M45PE20: + case FLASH_5717VENDOR_ST_25USPT: + case FLASH_5717VENDOR_ST_45USPT: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5717VENDOR_ST_M_M25PE20: + case FLASH_5717VENDOR_ST_A_M25PE20: + case FLASH_5717VENDOR_ST_M_M45PE20: + case FLASH_5717VENDOR_ST_A_M45PE20: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + default: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + } break; + default: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM; + return; } + + tg3_nvram_get_pagesize(tp, nvcfg1); + if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; } /* Chips other than 5700/5701 use the NVRAM for fetching info. */ @@ -11228,6 +11286,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_5906_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tg3_get_57780_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + tg3_get_5717_nvram_info(tp); else tg3_get_nvram_info(tp); @@ -13074,8 +13134,10 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) tw32_f(NVRAM_CMD, NVRAM_CMD_RESET); else tg3_nvram_unlock(tp); - } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + if (tr32(TG3_CPMU_STATUS) & TG3_CPMU_STATUS_PCIE_FUNC) + mac_offset = 0xcc; + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) mac_offset = 0x10; /* First try to get it from MAC address mailbox. */ diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 5994476..ea57a3a 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1027,8 +1027,10 @@ #define TG3_CPMU_HST_ACC 0x0000361c #define CPMU_HST_ACC_MACCLK_MASK 0x001f0000 #define CPMU_HST_ACC_MACCLK_6_25 0x00130000 -/* 0x3620 --> 0x3630 unused */ +/* 0x3620 --> 0x362c unused */ +#define TG3_CPMU_STATUS 0x0000362c +#define TG3_CPMU_STATUS_PCIE_FUNC 0x20000000 #define TG3_CPMU_CLCK_STAT 0x00003630 #define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000 #define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000 @@ -1692,6 +1694,25 @@ #define FLASH_57780VENDOR_ATMEL_AT45DB021B 0x03400002 #define FLASH_57780VENDOR_ATMEL_AT45DB041D 0x00400001 #define FLASH_57780VENDOR_ATMEL_AT45DB041B 0x03400001 +#define FLASH_5717VENDOR_ATMEL_EEPROM 0x02000001 +#define FLASH_5717VENDOR_MICRO_EEPROM 0x02000003 +#define FLASH_5717VENDOR_ATMEL_MDB011D 0x01000001 +#define FLASH_5717VENDOR_ATMEL_MDB021D 0x01000003 +#define FLASH_5717VENDOR_ST_M_M25PE10 0x02000000 +#define FLASH_5717VENDOR_ST_M_M25PE20 0x02000002 +#define FLASH_5717VENDOR_ST_M_M45PE10 0x00000001 +#define FLASH_5717VENDOR_ST_M_M45PE20 0x00000003 +#define FLASH_5717VENDOR_ATMEL_ADB011B 0x01400000 +#define FLASH_5717VENDOR_ATMEL_ADB021B 0x01400002 +#define FLASH_5717VENDOR_ATMEL_ADB011D 0x01400001 +#define FLASH_5717VENDOR_ATMEL_ADB021D 0x01400003 +#define FLASH_5717VENDOR_ST_A_M25PE10 0x02400000 +#define FLASH_5717VENDOR_ST_A_M25PE20 0x02400002 +#define FLASH_5717VENDOR_ST_A_M45PE10 0x02400001 +#define FLASH_5717VENDOR_ST_A_M45PE20 0x02400003 +#define FLASH_5717VENDOR_ATMEL_45USPT 0x03400000 +#define FLASH_5717VENDOR_ST_25USPT 0x03400002 +#define FLASH_5717VENDOR_ST_45USPT 0x03400001 #define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000 #define FLASH_5752PAGE_SIZE_256 0x00000000 #define FLASH_5752PAGE_SIZE_512 0x10000000 -- cgit v0.10.2 From 882e9793faa9425dff581c33b1af45ed10145626 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:21:36 +0000 Subject: tg3: Add MDIO bus address assignments The 5717 is a dual port chip that has a shared MDIO bus design. While it is impossible for one function to interface with the wrong phy, that function still needs to know which MDIO bus address to use when interfacing with its own phy. This patch adds code to determine which MDIO bus address to use. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2de1ab6..9ff97cc 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -782,7 +782,7 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val) *val = 0x0; - frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) & + frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) & MI_COM_PHY_ADDR_MASK); frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & MI_COM_REG_ADDR_MASK); @@ -833,7 +833,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) udelay(80); } - frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) & + frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) & MI_COM_PHY_ADDR_MASK); frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & MI_COM_REG_ADDR_MASK); @@ -1021,6 +1021,21 @@ static void tg3_mdio_start(struct tg3 *tp) tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(80); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + u32 funcnum, is_serdes; + + funcnum = tr32(TG3_CPMU_STATUS) & TG3_CPMU_STATUS_PCIE_FUNC; + if (funcnum) + tp->phy_addr = 2; + else + tp->phy_addr = 1; + + is_serdes = tr32(SG_DIG_STATUS) & SG_DIG_IS_SERDES; + if (is_serdes) + tp->phy_addr += 7; + } else + tp->phy_addr = PHY_ADDR; + if ((tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) && GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tg3_mdio_config_5785(tp); @@ -9266,7 +9281,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->speed = tp->link_config.active_speed; cmd->duplex = tp->link_config.active_duplex; } - cmd->phy_address = PHY_ADDR; + cmd->phy_address = tp->phy_addr; cmd->transceiver = XCVR_INTERNAL; cmd->autoneg = tp->link_config.autoneg; cmd->maxtxpkt = 0; @@ -10570,7 +10585,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch(cmd) { case SIOCGMIIPHY: - data->phy_id = PHY_ADDR; + data->phy_id = tp->phy_addr; /* fallthru */ case SIOCGMIIREG: { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index ea57a3a..82b45d8 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -694,6 +694,7 @@ #define SG_DIG_PARTNER_FULL_DUPLEX 0x00020000 /* If !MRADV_CRC16_SELECT */ #define SG_DIG_PARTNER_NEXT_PAGE 0x00010000 /* If !MRADV_CRC16_SELECT */ #define SG_DIG_AUTONEG_STATE_MASK 0x00000ff0 +#define SG_DIG_IS_SERDES 0x00000100 #define SG_DIG_COMMA_DETECTOR 0x00000008 #define SG_DIG_MAC_ACK_STATUS 0x00000004 #define SG_DIG_AUTONEG_COMPLETE 0x00000002 @@ -2805,6 +2806,8 @@ struct tg3 { struct mii_bus *mdio_bus; int mdio_irq[PHY_MAX_ADDR]; + u8 phy_addr; + /* PHY info */ u32 phy_id; #define PHY_ID_MASK 0xfffffff0 -- cgit v0.10.2 From daf09de817353f18bb81a23a023d429cfd258e62 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:22:42 +0000 Subject: tg3: Update version to 3.102 This patch updates the tg3 version to 3.102. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9ff97cc..bd49810 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.101" -#define DRV_MODULE_RELDATE "August 28, 2009" +#define DRV_MODULE_VERSION "3.102" +#define DRV_MODULE_RELDATE "September 1, 2009" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v0.10.2 From 0fc0b732eaa38beb93a6fb62f77c7bd9622c76ec Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 2 Sep 2009 01:03:33 -0700 Subject: netdev: drivers should make ethtool_ops const No need to put ethtool_ops in data, they should be const. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 4c75409..f114813 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -285,7 +285,7 @@ static void uml_net_get_drvinfo(struct net_device *dev, strcpy(info->version, "42"); } -static struct ethtool_ops uml_net_ethtool_ops = { +static const struct ethtool_ops uml_net_ethtool_ops = { .get_drvinfo = uml_net_get_drvinfo, .get_link = ethtool_op_get_link, }; diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index d923d1d..84edc8b 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1342,7 +1342,7 @@ static void fwnet_get_drvinfo(struct net_device *net, strcpy(info->bus_info, "ieee1394"); } -static struct ethtool_ops fwnet_ethtool_ops = { +static const struct ethtool_ops fwnet_ethtool_ops = { .get_drvinfo = fwnet_get_drvinfo, }; diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 1ad8785..3a62c4c 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -173,7 +173,7 @@ static netdev_tx_t ether1394_tx(struct sk_buff *skb, struct net_device *dev); static void ether1394_iso(struct hpsb_iso *iso); -static struct ethtool_ops ethtool_ops; +static const struct ethtool_ops ethtool_ops; static int ether1394_write(struct hpsb_host *host, int srcid, int destid, quadlet_t *data, u64 addr, size_t len, u16 flags); @@ -1706,7 +1706,7 @@ static void ether1394_get_drvinfo(struct net_device *dev, strcpy(info->bus_info, "ieee1394"); /* FIXME provide more detail? */ } -static struct ethtool_ops ethtool_ops = { +static const struct ethtool_ops ethtool_ops = { .get_drvinfo = ether1394_get_drvinfo }; diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index c6e6611..538e409 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1508,7 +1508,7 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd } -static struct ethtool_ops nes_ethtool_ops = { +static const struct ethtool_ops nes_ethtool_ops = { .get_link = ethtool_op_get_link, .get_settings = nes_netdev_get_settings, .set_settings = nes_netdev_set_settings, diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index fbf4645..2be49c8 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -762,7 +762,7 @@ static u32 ep93xx_get_link(struct net_device *dev) return mii_link_ok(&ep->mii); } -static struct ethtool_ops ep93xx_ethtool_ops = { +static const struct ethtool_ops ep93xx_ethtool_ops = { .get_drvinfo = ep93xx_get_drvinfo, .get_settings = ep93xx_get_settings, .set_settings = ep93xx_set_settings, diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index 3fe0987..691b81e 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -802,7 +802,7 @@ static int ixp4xx_nway_reset(struct net_device *dev) return phy_start_aneg(port->phydev); } -static struct ethtool_ops ixp4xx_ethtool_ops = { +static const struct ethtool_ops ixp4xx_ethtool_ops = { .get_drvinfo = ixp4xx_get_drvinfo, .get_settings = ixp4xx_get_settings, .set_settings = ixp4xx_set_settings, diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index 35cd264..4f702d5 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -1063,7 +1063,7 @@ ks8695_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) sizeof(info->bus_info)); } -static struct ethtool_ops ks8695_ethtool_ops = { +static const struct ethtool_ops ks8695_ethtool_ops = { .get_msglevel = ks8695_get_msglevel, .set_msglevel = ks8695_set_msglevel, .get_settings = ks8695_get_settings, diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c index 00d11b4..9b1e0ea 100644 --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -294,7 +294,7 @@ static int atl1c_nway_reset(struct net_device *netdev) return 0; } -static struct ethtool_ops atl1c_ethtool_ops = { +static const struct ethtool_ops atl1c_ethtool_ops = { .get_settings = atl1c_get_settings, .set_settings = atl1c_set_settings, .get_drvinfo = atl1c_get_drvinfo, diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c index 4003955..60edb9f 100644 --- a/drivers/net/atl1e/atl1e_ethtool.c +++ b/drivers/net/atl1e/atl1e_ethtool.c @@ -378,7 +378,7 @@ static int atl1e_nway_reset(struct net_device *netdev) return 0; } -static struct ethtool_ops atl1e_ethtool_ops = { +static const struct ethtool_ops atl1e_ethtool_ops = { .get_settings = atl1e_get_settings, .set_settings = atl1e_set_settings, .get_drvinfo = atl1e_get_drvinfo, diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index d0bcb57..10c06b9 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -2094,7 +2094,7 @@ static int atl2_nway_reset(struct net_device *netdev) return 0; } -static struct ethtool_ops atl2_ethtool_ops = { +static const struct ethtool_ops atl2_ethtool_ops = { .get_settings = atl2_get_settings, .set_settings = atl2_set_settings, .get_drvinfo = atl2_get_drvinfo, diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index beb1313..6c45a22 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -259,7 +259,7 @@ struct be_adapter { bool promiscuous; }; -extern struct ethtool_ops be_ethtool_ops; +extern const struct ethtool_ops be_ethtool_ops; #define drvr_stats(adapter) (&adapter->stats.drvr_stats) diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index c480c19..4ff3cc4 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -332,7 +332,7 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) return status; } -struct ethtool_ops be_ethtool_ops = { +const struct ethtool_ops be_ethtool_ops = { .get_settings = be_get_settings, .get_drvinfo = be_get_drvinfo, .get_link = ethtool_op_get_link, diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index f580b21..14bd380 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -491,7 +491,7 @@ static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev, strcpy(info->bus_info, dev_name(&dev->dev)); } -static struct ethtool_ops bfin_mac_ethtool_ops = { +static const struct ethtool_ops bfin_mac_ethtool_ops = { .get_settings = bfin_mac_ethtool_getsettings, .set_settings = bfin_mac_ethtool_setsettings, .get_link = ethtool_op_get_link, diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index e2e5026..20f0ed9 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -10606,7 +10606,7 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data) return 0; } -static struct ethtool_ops bnx2x_ethtool_ops = { +static const struct ethtool_ops bnx2x_ethtool_ops = { .get_settings = bnx2x_get_settings, .set_settings = bnx2x_set_settings, .get_drvinfo = bnx2x_get_drvinfo, diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 49912eb..2ea0363 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -256,7 +256,7 @@ static void enic_set_msglevel(struct net_device *netdev, u32 value) enic->msg_enable = value; } -static struct ethtool_ops enic_ethtool_ops = { +static const struct ethtool_ops enic_ethtool_ops = { .get_settings = enic_get_settings, .get_drvinfo = enic_get_drvinfo, .get_msglevel = enic_get_msglevel, diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 114ccab..d004c35 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -2016,7 +2016,7 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) } } -static struct ethtool_ops igb_ethtool_ops = { +static const struct ethtool_ops igb_ethtool_ops = { .get_settings = igb_get_settings, .set_settings = igb_set_settings, .get_drvinfo = igb_get_drvinfo, diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 382c553..9f7b5d4 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -2186,7 +2186,7 @@ static int ipg_nway_reset(struct net_device *dev) return rc; } -static struct ethtool_ops ipg_ethtool_ops = { +static const struct ethtool_ops ipg_ethtool_ops = { .get_settings = ipg_get_settings, .set_settings = ipg_set_settings, .nway_reset = ipg_nway_reset, diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 51ca54c..03199fa 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -743,7 +743,7 @@ static u32 netdev_get_link(struct net_device *dev) return mii_link_ok(&lp->mii_if); } -static struct ethtool_ops netdev_ethtool_ops = { +static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .set_settings = netdev_set_settings, diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index 6e74aa9..99e9541 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c @@ -619,7 +619,7 @@ static const struct net_device_ops ks8842_netdev_ops = { .ndo_validate_addr = eth_validate_addr }; -static struct ethtool_ops ks8842_ethtool_ops = { +static const struct ethtool_ops ks8842_ethtool_ops = { .get_link = ethtool_op_get_link, }; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 01aaca9..fb65b42 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1079,7 +1079,7 @@ static void macb_get_drvinfo(struct net_device *dev, strcpy(info->bus_info, dev_name(&bp->pdev->dev)); } -static struct ethtool_ops macb_ethtool_ops = { +static const struct ethtool_ops macb_ethtool_ops = { .get_settings = macb_get_settings, .set_settings = macb_set_settings, .get_drvinfo = macb_get_drvinfo, diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 449d351..224a746 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1410,6 +1410,6 @@ extern void netxen_change_ringparam(struct netxen_adapter *adapter); extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp); -extern struct ethtool_ops netxen_nic_ethtool_ops; +extern const struct ethtool_ops netxen_nic_ethtool_ops; #endif /* __NETXEN_NIC_H_ */ diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 3886135..e376a1c 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -963,7 +963,7 @@ static int netxen_nic_set_flags(struct net_device *netdev, u32 data) return 0; } -struct ethtool_ops netxen_nic_ethtool_ops = { +const struct ethtool_ops netxen_nic_ethtool_ops = { .get_settings = netxen_nic_get_settings, .set_settings = netxen_nic_set_settings, .get_drvinfo = netxen_nic_get_drvinfo, diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index a3932c9..b211613 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1346,7 +1346,7 @@ done: return status; } -static struct ethtool_ops gelic_ether_ethtool_ops = { +static const struct ethtool_ops gelic_ether_ethtool_ops = { .get_drvinfo = gelic_net_get_drvinfo, .get_settings = gelic_ether_get_settings, .get_link = ethtool_op_get_link, diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 6932b08..227b141 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -2714,7 +2714,7 @@ static const struct net_device_ops gelic_wl_netdevice_ops = { #endif }; -static struct ethtool_ops gelic_wl_ethtool_ops = { +static const struct ethtool_ops gelic_wl_ethtool_ops = { .get_drvinfo = gelic_net_get_drvinfo, .get_link = gelic_wl_get_link, .get_tx_csum = ethtool_op_get_tx_csum, diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 997ea2a..45018f2 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -731,7 +731,7 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev, } -struct ethtool_ops efx_ethtool_ops = { +const struct ethtool_ops efx_ethtool_ops = { .get_settings = efx_ethtool_get_settings, .set_settings = efx_ethtool_set_settings, .get_drvinfo = efx_ethtool_get_drvinfo, diff --git a/drivers/net/sfc/ethtool.h b/drivers/net/sfc/ethtool.h index 3628e43..295ead4 100644 --- a/drivers/net/sfc/ethtool.h +++ b/drivers/net/sfc/ethtool.h @@ -22,6 +22,6 @@ extern int efx_ethtool_get_settings(struct net_device *net_dev, extern int efx_ethtool_set_settings(struct net_device *net_dev, struct ethtool_cmd *ecmd); -extern struct ethtool_ops efx_ethtool_ops; +extern const struct ethtool_ops efx_ethtool_ops; #endif /* EFX_ETHTOOL_H */ diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 918d4c9..ec9dfb2 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -2428,7 +2428,7 @@ static void bdx_get_ethtool_stats(struct net_device *netdev, */ static void bdx_ethtool_ops(struct net_device *netdev) { - static struct ethtool_ops bdx_ethtool_ops = { + static const struct ethtool_ops bdx_ethtool_ops = { .get_settings = bdx_get_settings, .get_drvinfo = bdx_get_drvinfo, .get_link = ethtool_op_get_link, diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 87b4a02..6ce7f77 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -731,7 +731,7 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) /* We need to override some ethtool_ops so we require our own structure so we don't interfere with other usbnet devices that may be connected at the same time. */ -static struct ethtool_ops ax88172_ethtool_ops = { +static const struct ethtool_ops ax88172_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, .get_msglevel = usbnet_get_msglevel, @@ -873,7 +873,7 @@ out: return ret; } -static struct ethtool_ops ax88772_ethtool_ops = { +static const struct ethtool_ops ax88772_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, .get_msglevel = usbnet_get_msglevel, diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 0ffc0c6..2bed6b0 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -698,7 +698,7 @@ static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) return 0; } -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = catc_get_drvinfo, .get_settings = catc_get_settings, .get_link = ethtool_op_get_link diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 1d3730d..72470f7 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -356,7 +356,7 @@ static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd) return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); } -static struct ethtool_ops dm9601_ethtool_ops = { +static const struct ethtool_ops dm9601_ethtool_ops = { .get_drvinfo = dm9601_get_drvinfo, .get_link = dm9601_get_link, .get_msglevel = usbnet_get_msglevel, diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 123f9b8..3f9c92a 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -829,7 +829,7 @@ static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info usb_make_path(odev->parent->usb, info->bus_info, sizeof info->bus_info); } -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = hso_get_drvinfo, .get_link = ethtool_op_get_link }; diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 7f39736..e2a39b9 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -778,7 +778,7 @@ static u32 kaweth_get_link(struct net_device *dev) return kaweth->linkstate; } -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = kaweth_get_drvinfo, .get_link = kaweth_get_link }; diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 7ae9afe..10873d9 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -449,7 +449,7 @@ static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, mcs7830_get_reg(dev, 0, regs->len, data); } -static struct ethtool_ops mcs7830_ethtool_ops = { +static const struct ethtool_ops mcs7830_ethtool_ops = { .get_drvinfo = mcs7830_get_drvinfo, .get_regs_len = mcs7830_get_regs_len, .get_regs = mcs7830_get_regs, diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 7b935b8..6fdaba8 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1174,7 +1174,7 @@ static void pegasus_set_msglevel(struct net_device *dev, u32 v) pegasus->msg_enable = v; } -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = pegasus_get_drvinfo, .get_settings = pegasus_get_settings, .set_settings = pegasus_set_settings, diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index d9f84f2..b091e20 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -865,7 +865,7 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e return 0; } -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = rtl8150_get_drvinfo, .get_settings = rtl8150_get_settings, .get_link = ethtool_op_get_link diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 09bd635..938fb35 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -625,7 +625,7 @@ static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val) return smsc95xx_set_csums(dev); } -static struct ethtool_ops smsc95xx_ethtool_ops = { +static const struct ethtool_ops smsc95xx_ethtool_ops = { .get_link = usbnet_get_link, .nway_reset = usbnet_nway_reset, .get_drvinfo = usbnet_get_drvinfo, diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index d166e33..24b36f7 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -854,7 +854,7 @@ void usbnet_set_msglevel (struct net_device *net, u32 level) EXPORT_SYMBOL_GPL(usbnet_set_msglevel); /* drivers may override default ethtool_ops in their bind() routine */ -static struct ethtool_ops usbnet_ethtool_ops = { +static const struct ethtool_ops usbnet_ethtool_ops = { .get_settings = usbnet_get_settings, .set_settings = usbnet_set_settings, .get_link = usbnet_get_link, diff --git a/drivers/net/veth.c b/drivers/net/veth.c index d1941cd..ade5b34 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -129,7 +129,7 @@ static int veth_set_tx_csum(struct net_device *dev, u32 data) return 0; } -static struct ethtool_ops veth_ethtool_ops = { +static const struct ethtool_ops veth_ethtool_ops = { .get_settings = veth_get_settings, .get_drvinfo = veth_get_drvinfo, .get_link = ethtool_op_get_link, diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 51e9ce4..32266fb 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -798,7 +798,7 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid) dev_warn(&dev->dev, "Failed to kill VLAN ID %d.\n", vid); } -static struct ethtool_ops virtnet_ethtool_ops = { +static const struct ethtool_ops virtnet_ethtool_ops = { .set_tx_csum = virtnet_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = ethtool_op_set_tso, diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 578c697..d3b69a4 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -14,7 +14,7 @@ #include "defs.h" #include "hostcmd.h" -extern struct ethtool_ops lbs_ethtool_ops; +extern const struct ethtool_ops lbs_ethtool_ops; #define MAX_BSSID_PER_CHANNEL 16 diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index b118a35..039b555 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -183,7 +183,7 @@ static int lbs_ethtool_set_wol(struct net_device *dev, return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL); } -struct ethtool_ops lbs_ethtool_ops = { +const struct ethtool_ops lbs_ethtool_ops = { .get_drvinfo = lbs_ethtool_get_drvinfo, .get_eeprom = lbs_ethtool_get_eeprom, .get_eeprom_len = lbs_ethtool_get_eeprom_len, diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 3700c49..baa051d 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -51,7 +51,7 @@ #include #include -static struct ethtool_ops xennet_ethtool_ops; +static const struct ethtool_ops xennet_ethtool_ops; struct netfront_cb { struct page *page; @@ -1627,7 +1627,7 @@ static void backend_changed(struct xenbus_device *dev, } } -static struct ethtool_ops xennet_ethtool_ops = +static const struct ethtool_ops xennet_ethtool_ops = { .set_tx_csum = ethtool_op_set_tx_csum, .set_sg = xennet_set_sg, diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 12ee7a3..94b1611 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -863,7 +863,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) return; } -static struct ethtool_ops qeth_l2_ethtool_ops = { +static const struct ethtool_ops qeth_l2_ethtool_ops = { .get_link = ethtool_op_get_link, .get_strings = qeth_core_get_strings, .get_ethtool_stats = qeth_core_get_ethtool_stats, @@ -872,7 +872,7 @@ static struct ethtool_ops qeth_l2_ethtool_ops = { .get_settings = qeth_core_ethtool_get_settings, }; -static struct ethtool_ops qeth_l2_osn_ops = { +static const struct ethtool_ops qeth_l2_osn_ops = { .get_strings = qeth_core_get_strings, .get_ethtool_stats = qeth_core_get_ethtool_stats, .get_stats_count = qeth_core_get_stats_count, diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index d9fabe3..115b4a0 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2946,7 +2946,7 @@ static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) return 0; } -static struct ethtool_ops qeth_l3_ethtool_ops = { +static const struct ethtool_ops qeth_l3_ethtool_ops = { .get_link = ethtool_op_get_link, .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_hw_csum, diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c index 7b8aa5e..c165c50 100644 --- a/drivers/staging/at76_usb/at76_usb.c +++ b/drivers/staging/at76_usb/at76_usb.c @@ -3396,7 +3396,7 @@ static u32 at76_ethtool_get_link(struct net_device *netdev) return priv->mac_state == MAC_CONNECTED; } -static struct ethtool_ops at76_ethtool_ops = { +static const struct ethtool_ops at76_ethtool_ops = { .get_drvinfo = at76_ethtool_get_drvinfo, .get_link = at76_ethtool_get_link, }; diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c index 93cab0a..42230e6 100644 --- a/drivers/staging/octeon/ethernet-mdio.c +++ b/drivers/staging/octeon/ethernet-mdio.c @@ -170,7 +170,7 @@ static u32 cvm_oct_get_link(struct net_device *dev) return ret; } -struct ethtool_ops cvm_oct_ethtool_ops = { +struct const ethtool_ops cvm_oct_ethtool_ops = { .get_drvinfo = cvm_oct_get_drvinfo, .get_settings = cvm_oct_get_settings, .set_settings = cvm_oct_set_settings, diff --git a/drivers/staging/octeon/ethernet-mdio.h b/drivers/staging/octeon/ethernet-mdio.h index 6314141..b3328ae 100644 --- a/drivers/staging/octeon/ethernet-mdio.h +++ b/drivers/staging/octeon/ethernet-mdio.h @@ -41,6 +41,6 @@ #include #endif /* CONFIG_XFRM */ -extern struct ethtool_ops cvm_oct_ethtool_ops; +extern const struct ethtool_ops cvm_oct_ethtool_ops; int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); int cvm_oct_mdio_setup_device(struct net_device *dev); diff --git a/drivers/staging/sxg/sxg.h b/drivers/staging/sxg/sxg.h index f07aa70..110096a 100644 --- a/drivers/staging/sxg/sxg.h +++ b/drivers/staging/sxg/sxg.h @@ -782,6 +782,6 @@ struct slic_crash_info { #define SIOCSLICSETINTAGG (SIOCDEVPRIVATE+10) #define SIOCSLICTRACEDUMP (SIOCDEVPRIVATE+11) -extern struct ethtool_ops sxg_nic_ethtool_ops; +extern const struct ethtool_ops sxg_nic_ethtool_ops; #define SXG_COMPLETE_SLOW_SEND_LIMIT 128 #endif /* __SXG_DRIVER_H__ */ diff --git a/drivers/staging/sxg/sxg_ethtool.c b/drivers/staging/sxg/sxg_ethtool.c index ad89cb8..f5a0706 100644 --- a/drivers/staging/sxg/sxg_ethtool.c +++ b/drivers/staging/sxg/sxg_ethtool.c @@ -300,7 +300,7 @@ static int sxg_nic_get_eeprom(struct net_device *netdev, return 0; } -struct ethtool_ops sxg_nic_ethtool_ops = { +const struct ethtool_ops sxg_nic_ethtool_ops = { .get_settings = sxg_nic_get_settings, .set_settings = sxg_nic_set_settings, .get_drvinfo = sxg_nic_get_drvinfo, diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index dc3ebd1..c665219 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -181,7 +181,7 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) * - ... probably more ethtool ops */ -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = eth_get_drvinfo, .get_link = ethtool_op_get_link, }; -- cgit v0.10.2 From 98147d527a038c4aab599e57323a4e5d727c28a6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 1 Sep 2009 19:25:02 +0000 Subject: net: seq_operations should be const Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 19c8dec..d2df837 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -204,7 +204,7 @@ static int ip6mr_vif_seq_show(struct seq_file *seq, void *v) return 0; } -static struct seq_operations ip6mr_vif_seq_ops = { +static const struct seq_operations ip6mr_vif_seq_ops = { .start = ip6mr_vif_seq_start, .next = ip6mr_vif_seq_next, .stop = ip6mr_vif_seq_stop, diff --git a/net/key/af_key.c b/net/key/af_key.c index dba9abd..7b1e99b 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3705,7 +3705,7 @@ static void pfkey_seq_stop(struct seq_file *f, void *v) read_unlock(&pfkey_table_lock); } -static struct seq_operations pfkey_seq_ops = { +static const struct seq_operations pfkey_seq_ops = { .start = pfkey_seq_start, .next = pfkey_seq_next, .stop = pfkey_seq_stop, -- cgit v0.10.2 From b2e4b3debc327a5b53d9622e0b1785eea2ea2aad Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 1 Sep 2009 19:25:03 +0000 Subject: tcp: MD5 operations should be const Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 8afac76..61723a7 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -233,7 +233,7 @@ struct tcp_request_sock { struct inet_request_sock req; #ifdef CONFIG_TCP_MD5SIG /* Only used by TCP MD5 Signature so far. */ - struct tcp_request_sock_ops *af_specific; + const struct tcp_request_sock_ops *af_specific; #endif u32 rcv_isn; u32 snt_isn; @@ -401,9 +401,9 @@ struct tcp_sock { #ifdef CONFIG_TCP_MD5SIG /* TCP AF-Specific parts; only used by MD5 Signature support so far */ - struct tcp_sock_af_ops *af_specific; + const struct tcp_sock_af_ops *af_specific; -/* TCP MD5 Signagure Option information */ +/* TCP MD5 Signature Option information */ struct tcp_md5sig_info *md5sig_info; #endif }; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 6755e29..3efbe94 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1195,7 +1195,7 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = { }; #ifdef CONFIG_TCP_MD5SIG -static struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { +static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { .md5_lookup = tcp_v4_reqsk_md5_lookup, .calc_md5_hash = tcp_v4_md5_hash_skb, }; @@ -1774,7 +1774,7 @@ struct inet_connection_sock_af_ops ipv4_specific = { }; #ifdef CONFIG_TCP_MD5SIG -static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { +static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = { .md5_lookup = tcp_v4_md5_lookup, .calc_md5_hash = tcp_v4_md5_hash_skb, .md5_add = tcp_v4_md5_add_func, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index d849dd5..eadbc58 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -78,8 +78,8 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); static struct inet_connection_sock_af_ops ipv6_mapped; static struct inet_connection_sock_af_ops ipv6_specific; #ifdef CONFIG_TCP_MD5SIG -static struct tcp_sock_af_ops tcp_sock_ipv6_specific; -static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; +static const struct tcp_sock_af_ops tcp_sock_ipv6_specific; +static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; #else static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, struct in6_addr *addr) @@ -894,7 +894,7 @@ struct request_sock_ops tcp6_request_sock_ops __read_mostly = { }; #ifdef CONFIG_TCP_MD5SIG -static struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { +static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { .md5_lookup = tcp_v6_reqsk_md5_lookup, .calc_md5_hash = tcp_v6_md5_hash_skb, }; @@ -1780,7 +1780,7 @@ static struct inet_connection_sock_af_ops ipv6_specific = { }; #ifdef CONFIG_TCP_MD5SIG -static struct tcp_sock_af_ops tcp_sock_ipv6_specific = { +static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = { .md5_lookup = tcp_v6_md5_lookup, .calc_md5_hash = tcp_v6_md5_hash_skb, .md5_add = tcp_v6_md5_add_func, @@ -1812,7 +1812,7 @@ static struct inet_connection_sock_af_ops ipv6_mapped = { }; #ifdef CONFIG_TCP_MD5SIG -static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { +static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { .md5_lookup = tcp_v4_md5_lookup, .calc_md5_hash = tcp_v4_md5_hash_skb, .md5_add = tcp_v6_md5_add_func, -- cgit v0.10.2 From 3b401a81c0d50ea9c718cf837f62cc2e6e79cc30 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 1 Sep 2009 19:25:04 +0000 Subject: inet: inet_connection_sock_af_ops const The function block inet_connect_sock_af_ops contains no data make it constant. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index bfb240c..d65381c 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -51,7 +51,7 @@ extern int datagram_send_ctl(struct net *net, /* * address family specific functions */ -extern struct inet_connection_sock_af_ops ipv4_specific; +extern const struct inet_connection_sock_af_ops ipv4_specific; extern void inet6_destroy_sock(struct sock *sk); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index a0a36c9..d01c00d 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -880,7 +880,7 @@ discard_and_relse: goto discard_it; } -static struct inet_connection_sock_af_ops dccp_ipv4_af_ops = { +static const struct inet_connection_sock_af_ops dccp_ipv4_af_ops = { .queue_xmit = ip_queue_xmit, .send_check = dccp_v4_send_check, .rebuild_header = inet_sk_rebuild_header, diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 3e70faa..64f011c 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -35,8 +35,8 @@ /* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */ -static struct inet_connection_sock_af_ops dccp_ipv6_mapped; -static struct inet_connection_sock_af_ops dccp_ipv6_af_ops; +static const struct inet_connection_sock_af_ops dccp_ipv6_mapped; +static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops; static void dccp_v6_hash(struct sock *sk) { @@ -1055,7 +1055,7 @@ failure: return err; } -static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { +static const struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { .queue_xmit = inet6_csk_xmit, .send_check = dccp_v6_send_check, .rebuild_header = inet6_sk_rebuild_header, @@ -1076,7 +1076,7 @@ static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { /* * DCCP over IPv4 via INET6 API */ -static struct inet_connection_sock_af_ops dccp_ipv6_mapped = { +static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = { .queue_xmit = ip_queue_xmit, .send_check = dccp_v4_send_check, .rebuild_header = inet_sk_rebuild_header, diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 3efbe94..ce7d3b0 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1754,7 +1754,7 @@ int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw) return 0; } -struct inet_connection_sock_af_ops ipv4_specific = { +const struct inet_connection_sock_af_ops ipv4_specific = { .queue_xmit = ip_queue_xmit, .send_check = tcp_v4_send_check, .rebuild_header = inet_sk_rebuild_header, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index eadbc58..d73617e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -75,8 +75,8 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); -static struct inet_connection_sock_af_ops ipv6_mapped; -static struct inet_connection_sock_af_ops ipv6_specific; +static const struct inet_connection_sock_af_ops ipv6_mapped; +static const struct inet_connection_sock_af_ops ipv6_specific; #ifdef CONFIG_TCP_MD5SIG static const struct tcp_sock_af_ops tcp_sock_ipv6_specific; static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; @@ -1760,7 +1760,7 @@ static int tcp_v6_remember_stamp(struct sock *sk) return 0; } -static struct inet_connection_sock_af_ops ipv6_specific = { +static const struct inet_connection_sock_af_ops ipv6_specific = { .queue_xmit = inet6_csk_xmit, .send_check = tcp_v6_send_check, .rebuild_header = inet6_sk_rebuild_header, @@ -1792,7 +1792,7 @@ static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = { * TCP over IPv4 via INET6 API */ -static struct inet_connection_sock_af_ops ipv6_mapped = { +static const struct inet_connection_sock_af_ops ipv6_mapped = { .queue_xmit = ip_queue_xmit, .send_check = tcp_v4_send_check, .rebuild_header = inet_sk_rebuild_header, -- cgit v0.10.2 From 5ca1b998d33c39819fca2b675d80c4469e705f2d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 1 Sep 2009 19:25:05 +0000 Subject: net: file_operations should be const All instances of file_operations should be const. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index d2df837..5c8d737 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -217,7 +217,7 @@ static int ip6mr_vif_open(struct inode *inode, struct file *file) sizeof(struct ipmr_vif_iter)); } -static struct file_operations ip6mr_vif_fops = { +static const struct file_operations ip6mr_vif_fops = { .owner = THIS_MODULE, .open = ip6mr_vif_open, .read = seq_read, @@ -341,7 +341,7 @@ static int ipmr_mfc_open(struct inode *inode, struct file *file) sizeof(struct ipmr_mfc_iter)); } -static struct file_operations ip6mr_mfc_fops = { +static const struct file_operations ip6mr_mfc_fops = { .owner = THIS_MODULE, .open = ipmr_mfc_open, .read = seq_read, diff --git a/net/irda/irnet/irnet_ppp.h b/net/irda/irnet/irnet_ppp.h index d9f8bd4..b5df241 100644 --- a/net/irda/irnet/irnet_ppp.h +++ b/net/irda/irnet/irnet_ppp.h @@ -95,7 +95,7 @@ static int /**************************** VARIABLES ****************************/ /* Filesystem callbacks (to call us) */ -static struct file_operations irnet_device_fops = +static const struct file_operations irnet_device_fops = { .owner = THIS_MODULE, .read = dev_irnet_read, diff --git a/net/irda/irproc.c b/net/irda/irproc.c index 8ff1861..318766e 100644 --- a/net/irda/irproc.c +++ b/net/irda/irproc.c @@ -34,21 +34,21 @@ #include #include -extern struct file_operations discovery_seq_fops; -extern struct file_operations irlap_seq_fops; -extern struct file_operations irlmp_seq_fops; -extern struct file_operations irttp_seq_fops; -extern struct file_operations irias_seq_fops; +extern const struct file_operations discovery_seq_fops; +extern const struct file_operations irlap_seq_fops; +extern const struct file_operations irlmp_seq_fops; +extern const struct file_operations irttp_seq_fops; +extern const struct file_operations irias_seq_fops; struct irda_entry { const char *name; - struct file_operations *fops; + const struct file_operations *fops; }; struct proc_dir_entry *proc_irda; EXPORT_SYMBOL(proc_irda); -static struct irda_entry irda_dirs[] = { +static const struct irda_entry irda_dirs[] = { {"discovery", &discovery_seq_fops}, {"irttp", &irttp_seq_fops}, {"irlmp", &irlmp_seq_fops}, diff --git a/net/key/af_key.c b/net/key/af_key.c index 7b1e99b..4e98193 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3718,7 +3718,7 @@ static int pfkey_seq_open(struct inode *inode, struct file *file) sizeof(struct seq_net_private)); } -static struct file_operations pfkey_proc_ops = { +static const struct file_operations pfkey_proc_ops = { .open = pfkey_seq_open, .read = seq_read, .llseek = seq_lseek, diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index 3d72ec5..a715d94 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c @@ -139,7 +139,7 @@ minstrel_stats_release(struct inode *inode, struct file *file) return 0; } -static struct file_operations minstrel_stat_fops = { +static const struct file_operations minstrel_stat_fops = { .owner = THIS_MODULE, .open = minstrel_stats_open, .read = minstrel_stats_read, diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index a08a9b5..a59043fb 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c @@ -198,7 +198,7 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, #undef RC_PID_PRINT_BUF_SIZE -static struct file_operations rc_pid_fop_events = { +static const struct file_operations rc_pid_fop_events = { .owner = THIS_MODULE, .read = rate_control_pid_events_read, .poll = rate_control_pid_events_poll, diff --git a/net/xfrm/xfrm_proc.c b/net/xfrm/xfrm_proc.c index a2adb51..fef8db5 100644 --- a/net/xfrm/xfrm_proc.c +++ b/net/xfrm/xfrm_proc.c @@ -60,7 +60,7 @@ static int xfrm_statistics_seq_open(struct inode *inode, struct file *file) return single_open_net(inode, file, xfrm_statistics_seq_show); } -static struct file_operations xfrm_statistics_seq_fops = { +static const struct file_operations xfrm_statistics_seq_fops = { .owner = THIS_MODULE, .open = xfrm_statistics_seq_open, .read = seq_read, -- cgit v0.10.2 From f1939f7c56456d22a559d2c75156e91912a2e97e Mon Sep 17 00:00:00 2001 From: Shane Wang Date: Wed, 2 Sep 2009 20:05:22 +1000 Subject: crypto: vmac - New hash algorithm for intel_txt support This patch adds VMAC (a fast MAC) support into crypto framework. Signed-off-by: Shane Wang Signed-off-by: Joseph Cihula Signed-off-by: Herbert Xu diff --git a/crypto/Kconfig b/crypto/Kconfig index 7623442..26b5dd0 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -269,6 +269,18 @@ config CRYPTO_XCBC http://csrc.nist.gov/encryption/modes/proposedmodes/ xcbc-mac/xcbc-mac-spec.pdf +config CRYPTO_VMAC + tristate "VMAC support" + depends on EXPERIMENTAL + select CRYPTO_HASH + select CRYPTO_MANAGER + help + VMAC is a message authentication algorithm designed for + very high speed on 64-bit architectures. + + See also: + + comment "Digest" config CRYPTO_CRC32C diff --git a/crypto/Makefile b/crypto/Makefile index c2ca721..9e8f619 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -32,6 +32,7 @@ cryptomgr-objs := algboss.o testmgr.o obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o obj-$(CONFIG_CRYPTO_HMAC) += hmac.o +obj-$(CONFIG_CRYPTO_VMAC) += vmac.o obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o obj-$(CONFIG_CRYPTO_MD4) += md4.o diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 5a375e8..aa3f84c 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -719,6 +719,10 @@ static int do_test(int m) ret += tcrypt_test("hmac(rmd160)"); break; + case 109: + ret += tcrypt_test("vmac(aes)"); + break; + case 150: ret += tcrypt_test("ansi_cprng"); break; diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 29b228d..6d5b746 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -2248,6 +2248,15 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "vmac(aes)", + .test = alg_test_hash, + .suite = { + .hash = { + .vecs = aes_vmac128_tv_template, + .count = VMAC_AES_TEST_VECTORS + } + } + }, { .alg = "wp256", .test = alg_test_hash, .suite = { diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 6931622..9963b18 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -1654,6 +1654,22 @@ static struct hash_testvec aes_xcbc128_tv_template[] = { } }; +#define VMAC_AES_TEST_VECTORS 1 +static char vmac_string[128] = {'\x01', '\x01', '\x01', '\x01', + '\x02', '\x03', '\x02', '\x02', + '\x02', '\x04', '\x01', '\x07', + '\x04', '\x01', '\x04', '\x03',}; +static struct hash_testvec aes_vmac128_tv_template[] = { + { + .key = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .plaintext = vmac_string, + .digest = "\xcb\xd7\x8a\xfd\xb7\x33\x79\xe7", + .psize = 128, + .ksize = 16, + }, +}; + /* * SHA384 HMAC test vectors from RFC4231 */ diff --git a/crypto/vmac.c b/crypto/vmac.c new file mode 100644 index 0000000..0a9468e --- /dev/null +++ b/crypto/vmac.c @@ -0,0 +1,678 @@ +/* + * Modified to interface to the Linux kernel + * Copyright (c) 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., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +/* -------------------------------------------------------------------------- + * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. + * This implementation is herby placed in the public domain. + * The authors offers no warranty. Use at your own risk. + * Please send bug reports to the authors. + * Last modified: 17 APR 08, 1700 PDT + * ----------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Constants and masks + */ +#define UINT64_C(x) x##ULL +const u64 p64 = UINT64_C(0xfffffffffffffeff); /* 2^64 - 257 prime */ +const u64 m62 = UINT64_C(0x3fffffffffffffff); /* 62-bit mask */ +const u64 m63 = UINT64_C(0x7fffffffffffffff); /* 63-bit mask */ +const u64 m64 = UINT64_C(0xffffffffffffffff); /* 64-bit mask */ +const u64 mpoly = UINT64_C(0x1fffffff1fffffff); /* Poly key mask */ + +#ifdef __LITTLE_ENDIAN +#define INDEX_HIGH 1 +#define INDEX_LOW 0 +#else +#define INDEX_HIGH 0 +#define INDEX_LOW 1 +#endif + +/* + * The following routines are used in this implementation. They are + * written via macros to simulate zero-overhead call-by-reference. + * + * MUL64: 64x64->128-bit multiplication + * PMUL64: assumes top bits cleared on inputs + * ADD128: 128x128->128-bit addition + */ + +#define ADD128(rh, rl, ih, il) \ + do { \ + u64 _il = (il); \ + (rl) += (_il); \ + if ((rl) < (_il)) \ + (rh)++; \ + (rh) += (ih); \ + } while (0) + +#define MUL32(i1, i2) ((u64)(u32)(i1)*(u32)(i2)) + +#define PMUL64(rh, rl, i1, i2) /* Assumes m doesn't overflow */ \ + do { \ + u64 _i1 = (i1), _i2 = (i2); \ + u64 m = MUL32(_i1, _i2>>32) + MUL32(_i1>>32, _i2); \ + rh = MUL32(_i1>>32, _i2>>32); \ + rl = MUL32(_i1, _i2); \ + ADD128(rh, rl, (m >> 32), (m << 32)); \ + } while (0) + +#define MUL64(rh, rl, i1, i2) \ + do { \ + u64 _i1 = (i1), _i2 = (i2); \ + u64 m1 = MUL32(_i1, _i2>>32); \ + u64 m2 = MUL32(_i1>>32, _i2); \ + rh = MUL32(_i1>>32, _i2>>32); \ + rl = MUL32(_i1, _i2); \ + ADD128(rh, rl, (m1 >> 32), (m1 << 32)); \ + ADD128(rh, rl, (m2 >> 32), (m2 << 32)); \ + } while (0) + +/* + * For highest performance the L1 NH and L2 polynomial hashes should be + * carefully implemented to take advantage of one's target architechture. + * Here these two hash functions are defined multiple time; once for + * 64-bit architectures, once for 32-bit SSE2 architectures, and once + * for the rest (32-bit) architectures. + * For each, nh_16 *must* be defined (works on multiples of 16 bytes). + * Optionally, nh_vmac_nhbytes can be defined (for multiples of + * VMAC_NHBYTES), and nh_16_2 and nh_vmac_nhbytes_2 (versions that do two + * NH computations at once). + */ + +#ifdef CONFIG_64BIT + +#define nh_16(mp, kp, nw, rh, rl) \ + do { \ + int i; u64 th, tl; \ + rh = rl = 0; \ + for (i = 0; i < nw; i += 2) { \ + MUL64(th, tl, le64_to_cpup((mp)+i)+(kp)[i], \ + le64_to_cpup((mp)+i+1)+(kp)[i+1]); \ + ADD128(rh, rl, th, tl); \ + } \ + } while (0) + +#define nh_16_2(mp, kp, nw, rh, rl, rh1, rl1) \ + do { \ + int i; u64 th, tl; \ + rh1 = rl1 = rh = rl = 0; \ + for (i = 0; i < nw; i += 2) { \ + MUL64(th, tl, le64_to_cpup((mp)+i)+(kp)[i], \ + le64_to_cpup((mp)+i+1)+(kp)[i+1]); \ + ADD128(rh, rl, th, tl); \ + MUL64(th, tl, le64_to_cpup((mp)+i)+(kp)[i+2], \ + le64_to_cpup((mp)+i+1)+(kp)[i+3]); \ + ADD128(rh1, rl1, th, tl); \ + } \ + } while (0) + +#if (VMAC_NHBYTES >= 64) /* These versions do 64-bytes of message at a time */ +#define nh_vmac_nhbytes(mp, kp, nw, rh, rl) \ + do { \ + int i; u64 th, tl; \ + rh = rl = 0; \ + for (i = 0; i < nw; i += 8) { \ + MUL64(th, tl, le64_to_cpup((mp)+i)+(kp)[i], \ + le64_to_cpup((mp)+i+1)+(kp)[i+1]); \ + ADD128(rh, rl, th, tl); \ + MUL64(th, tl, le64_to_cpup((mp)+i+2)+(kp)[i+2], \ + le64_to_cpup((mp)+i+3)+(kp)[i+3]); \ + ADD128(rh, rl, th, tl); \ + MUL64(th, tl, le64_to_cpup((mp)+i+4)+(kp)[i+4], \ + le64_to_cpup((mp)+i+5)+(kp)[i+5]); \ + ADD128(rh, rl, th, tl); \ + MUL64(th, tl, le64_to_cpup((mp)+i+6)+(kp)[i+6], \ + le64_to_cpup((mp)+i+7)+(kp)[i+7]); \ + ADD128(rh, rl, th, tl); \ + } \ + } while (0) + +#define nh_vmac_nhbytes_2(mp, kp, nw, rh, rl, rh1, rl1) \ + do { \ + int i; u64 th, tl; \ + rh1 = rl1 = rh = rl = 0; \ + for (i = 0; i < nw; i += 8) { \ + MUL64(th, tl, le64_to_cpup((mp)+i)+(kp)[i], \ + le64_to_cpup((mp)+i+1)+(kp)[i+1]); \ + ADD128(rh, rl, th, tl); \ + MUL64(th, tl, le64_to_cpup((mp)+i)+(kp)[i+2], \ + le64_to_cpup((mp)+i+1)+(kp)[i+3]); \ + ADD128(rh1, rl1, th, tl); \ + MUL64(th, tl, le64_to_cpup((mp)+i+2)+(kp)[i+2], \ + le64_to_cpup((mp)+i+3)+(kp)[i+3]); \ + ADD128(rh, rl, th, tl); \ + MUL64(th, tl, le64_to_cpup((mp)+i+2)+(kp)[i+4], \ + le64_to_cpup((mp)+i+3)+(kp)[i+5]); \ + ADD128(rh1, rl1, th, tl); \ + MUL64(th, tl, le64_to_cpup((mp)+i+4)+(kp)[i+4], \ + le64_to_cpup((mp)+i+5)+(kp)[i+5]); \ + ADD128(rh, rl, th, tl); \ + MUL64(th, tl, le64_to_cpup((mp)+i+4)+(kp)[i+6], \ + le64_to_cpup((mp)+i+5)+(kp)[i+7]); \ + ADD128(rh1, rl1, th, tl); \ + MUL64(th, tl, le64_to_cpup((mp)+i+6)+(kp)[i+6], \ + le64_to_cpup((mp)+i+7)+(kp)[i+7]); \ + ADD128(rh, rl, th, tl); \ + MUL64(th, tl, le64_to_cpup((mp)+i+6)+(kp)[i+8], \ + le64_to_cpup((mp)+i+7)+(kp)[i+9]); \ + ADD128(rh1, rl1, th, tl); \ + } \ + } while (0) +#endif + +#define poly_step(ah, al, kh, kl, mh, ml) \ + do { \ + u64 t1h, t1l, t2h, t2l, t3h, t3l, z = 0; \ + /* compute ab*cd, put bd into result registers */ \ + PMUL64(t3h, t3l, al, kh); \ + PMUL64(t2h, t2l, ah, kl); \ + PMUL64(t1h, t1l, ah, 2*kh); \ + PMUL64(ah, al, al, kl); \ + /* add 2 * ac to result */ \ + ADD128(ah, al, t1h, t1l); \ + /* add together ad + bc */ \ + ADD128(t2h, t2l, t3h, t3l); \ + /* now (ah,al), (t2l,2*t2h) need summing */ \ + /* first add the high registers, carrying into t2h */ \ + ADD128(t2h, ah, z, t2l); \ + /* double t2h and add top bit of ah */ \ + t2h = 2 * t2h + (ah >> 63); \ + ah &= m63; \ + /* now add the low registers */ \ + ADD128(ah, al, mh, ml); \ + ADD128(ah, al, z, t2h); \ + } while (0) + +#else /* ! CONFIG_64BIT */ + +#ifndef nh_16 +#define nh_16(mp, kp, nw, rh, rl) \ + do { \ + u64 t1, t2, m1, m2, t; \ + int i; \ + rh = rl = t = 0; \ + for (i = 0; i < nw; i += 2) { \ + t1 = le64_to_cpup(mp+i) + kp[i]; \ + t2 = le64_to_cpup(mp+i+1) + kp[i+1]; \ + m2 = MUL32(t1 >> 32, t2); \ + m1 = MUL32(t1, t2 >> 32); \ + ADD128(rh, rl, MUL32(t1 >> 32, t2 >> 32), \ + MUL32(t1, t2)); \ + rh += (u64)(u32)(m1 >> 32) \ + + (u32)(m2 >> 32); \ + t += (u64)(u32)m1 + (u32)m2; \ + } \ + ADD128(rh, rl, (t >> 32), (t << 32)); \ + } while (0) +#endif + +static void poly_step_func(u64 *ahi, u64 *alo, + const u64 *kh, const u64 *kl, + const u64 *mh, const u64 *ml) +{ +#define a0 (*(((u32 *)alo)+INDEX_LOW)) +#define a1 (*(((u32 *)alo)+INDEX_HIGH)) +#define a2 (*(((u32 *)ahi)+INDEX_LOW)) +#define a3 (*(((u32 *)ahi)+INDEX_HIGH)) +#define k0 (*(((u32 *)kl)+INDEX_LOW)) +#define k1 (*(((u32 *)kl)+INDEX_HIGH)) +#define k2 (*(((u32 *)kh)+INDEX_LOW)) +#define k3 (*(((u32 *)kh)+INDEX_HIGH)) + + u64 p, q, t; + u32 t2; + + p = MUL32(a3, k3); + p += p; + p += *(u64 *)mh; + p += MUL32(a0, k2); + p += MUL32(a1, k1); + p += MUL32(a2, k0); + t = (u32)(p); + p >>= 32; + p += MUL32(a0, k3); + p += MUL32(a1, k2); + p += MUL32(a2, k1); + p += MUL32(a3, k0); + t |= ((u64)((u32)p & 0x7fffffff)) << 32; + p >>= 31; + p += (u64)(((u32 *)ml)[INDEX_LOW]); + p += MUL32(a0, k0); + q = MUL32(a1, k3); + q += MUL32(a2, k2); + q += MUL32(a3, k1); + q += q; + p += q; + t2 = (u32)(p); + p >>= 32; + p += (u64)(((u32 *)ml)[INDEX_HIGH]); + p += MUL32(a0, k1); + p += MUL32(a1, k0); + q = MUL32(a2, k3); + q += MUL32(a3, k2); + q += q; + p += q; + *(u64 *)(alo) = (p << 32) | t2; + p >>= 32; + *(u64 *)(ahi) = p + t; + +#undef a0 +#undef a1 +#undef a2 +#undef a3 +#undef k0 +#undef k1 +#undef k2 +#undef k3 +} + +#define poly_step(ah, al, kh, kl, mh, ml) \ + poly_step_func(&(ah), &(al), &(kh), &(kl), &(mh), &(ml)) + +#endif /* end of specialized NH and poly definitions */ + +/* At least nh_16 is defined. Defined others as needed here */ +#ifndef nh_16_2 +#define nh_16_2(mp, kp, nw, rh, rl, rh2, rl2) \ + do { \ + nh_16(mp, kp, nw, rh, rl); \ + nh_16(mp, ((kp)+2), nw, rh2, rl2); \ + } while (0) +#endif +#ifndef nh_vmac_nhbytes +#define nh_vmac_nhbytes(mp, kp, nw, rh, rl) \ + nh_16(mp, kp, nw, rh, rl) +#endif +#ifndef nh_vmac_nhbytes_2 +#define nh_vmac_nhbytes_2(mp, kp, nw, rh, rl, rh2, rl2) \ + do { \ + nh_vmac_nhbytes(mp, kp, nw, rh, rl); \ + nh_vmac_nhbytes(mp, ((kp)+2), nw, rh2, rl2); \ + } while (0) +#endif + +static void vhash_abort(struct vmac_ctx *ctx) +{ + ctx->polytmp[0] = ctx->polykey[0] ; + ctx->polytmp[1] = ctx->polykey[1] ; + ctx->first_block_processed = 0; +} + +static u64 l3hash(u64 p1, u64 p2, + u64 k1, u64 k2, u64 len) +{ + u64 rh, rl, t, z = 0; + + /* fully reduce (p1,p2)+(len,0) mod p127 */ + t = p1 >> 63; + p1 &= m63; + ADD128(p1, p2, len, t); + /* At this point, (p1,p2) is at most 2^127+(len<<64) */ + t = (p1 > m63) + ((p1 == m63) && (p2 == m64)); + ADD128(p1, p2, z, t); + p1 &= m63; + + /* compute (p1,p2)/(2^64-2^32) and (p1,p2)%(2^64-2^32) */ + t = p1 + (p2 >> 32); + t += (t >> 32); + t += (u32)t > 0xfffffffeu; + p1 += (t >> 32); + p2 += (p1 << 32); + + /* compute (p1+k1)%p64 and (p2+k2)%p64 */ + p1 += k1; + p1 += (0 - (p1 < k1)) & 257; + p2 += k2; + p2 += (0 - (p2 < k2)) & 257; + + /* compute (p1+k1)*(p2+k2)%p64 */ + MUL64(rh, rl, p1, p2); + t = rh >> 56; + ADD128(t, rl, z, rh); + rh <<= 8; + ADD128(t, rl, z, rh); + t += t << 8; + rl += t; + rl += (0 - (rl < t)) & 257; + rl += (0 - (rl > p64-1)) & 257; + return rl; +} + +static void vhash_update(const unsigned char *m, + unsigned int mbytes, /* Pos multiple of VMAC_NHBYTES */ + struct vmac_ctx *ctx) +{ + u64 rh, rl, *mptr; + const u64 *kptr = (u64 *)ctx->nhkey; + int i; + u64 ch, cl; + u64 pkh = ctx->polykey[0]; + u64 pkl = ctx->polykey[1]; + + mptr = (u64 *)m; + i = mbytes / VMAC_NHBYTES; /* Must be non-zero */ + + ch = ctx->polytmp[0]; + cl = ctx->polytmp[1]; + + if (!ctx->first_block_processed) { + ctx->first_block_processed = 1; + nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); + rh &= m62; + ADD128(ch, cl, rh, rl); + mptr += (VMAC_NHBYTES/sizeof(u64)); + i--; + } + + while (i--) { + nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); + rh &= m62; + poly_step(ch, cl, pkh, pkl, rh, rl); + mptr += (VMAC_NHBYTES/sizeof(u64)); + } + + ctx->polytmp[0] = ch; + ctx->polytmp[1] = cl; +} + +static u64 vhash(unsigned char m[], unsigned int mbytes, + u64 *tagl, struct vmac_ctx *ctx) +{ + u64 rh, rl, *mptr; + const u64 *kptr = (u64 *)ctx->nhkey; + int i, remaining; + u64 ch, cl; + u64 pkh = ctx->polykey[0]; + u64 pkl = ctx->polykey[1]; + + mptr = (u64 *)m; + i = mbytes / VMAC_NHBYTES; + remaining = mbytes % VMAC_NHBYTES; + + if (ctx->first_block_processed) { + ch = ctx->polytmp[0]; + cl = ctx->polytmp[1]; + } else if (i) { + nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, ch, cl); + ch &= m62; + ADD128(ch, cl, pkh, pkl); + mptr += (VMAC_NHBYTES/sizeof(u64)); + i--; + } else if (remaining) { + nh_16(mptr, kptr, 2*((remaining+15)/16), ch, cl); + ch &= m62; + ADD128(ch, cl, pkh, pkl); + mptr += (VMAC_NHBYTES/sizeof(u64)); + goto do_l3; + } else {/* Empty String */ + ch = pkh; cl = pkl; + goto do_l3; + } + + while (i--) { + nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); + rh &= m62; + poly_step(ch, cl, pkh, pkl, rh, rl); + mptr += (VMAC_NHBYTES/sizeof(u64)); + } + if (remaining) { + nh_16(mptr, kptr, 2*((remaining+15)/16), rh, rl); + rh &= m62; + poly_step(ch, cl, pkh, pkl, rh, rl); + } + +do_l3: + vhash_abort(ctx); + remaining *= 8; + return l3hash(ch, cl, ctx->l3key[0], ctx->l3key[1], remaining); +} + +static u64 vmac(unsigned char m[], unsigned int mbytes, + unsigned char n[16], u64 *tagl, + struct vmac_ctx_t *ctx) +{ + u64 *in_n, *out_p; + u64 p, h; + int i; + + in_n = ctx->__vmac_ctx.cached_nonce; + out_p = ctx->__vmac_ctx.cached_aes; + + i = n[15] & 1; + if ((*(u64 *)(n+8) != in_n[1]) || (*(u64 *)(n) != in_n[0])) { + in_n[0] = *(u64 *)(n); + in_n[1] = *(u64 *)(n+8); + ((unsigned char *)in_n)[15] &= 0xFE; + crypto_cipher_encrypt_one(ctx->child, + (unsigned char *)out_p, (unsigned char *)in_n); + + ((unsigned char *)in_n)[15] |= (unsigned char)(1-i); + } + p = be64_to_cpup(out_p + i); + h = vhash(m, mbytes, (u64 *)0, &ctx->__vmac_ctx); + return p + h; +} + +static int vmac_set_key(unsigned char user_key[], struct vmac_ctx_t *ctx) +{ + u64 in[2] = {0}, out[2]; + unsigned i; + int err = 0; + + err = crypto_cipher_setkey(ctx->child, user_key, VMAC_KEY_LEN); + if (err) + return err; + + /* Fill nh key */ + ((unsigned char *)in)[0] = 0x80; + for (i = 0; i < sizeof(ctx->__vmac_ctx.nhkey)/8; i += 2) { + crypto_cipher_encrypt_one(ctx->child, + (unsigned char *)out, (unsigned char *)in); + ctx->__vmac_ctx.nhkey[i] = be64_to_cpup(out); + ctx->__vmac_ctx.nhkey[i+1] = be64_to_cpup(out+1); + ((unsigned char *)in)[15] += 1; + } + + /* Fill poly key */ + ((unsigned char *)in)[0] = 0xC0; + in[1] = 0; + for (i = 0; i < sizeof(ctx->__vmac_ctx.polykey)/8; i += 2) { + crypto_cipher_encrypt_one(ctx->child, + (unsigned char *)out, (unsigned char *)in); + ctx->__vmac_ctx.polytmp[i] = + ctx->__vmac_ctx.polykey[i] = + be64_to_cpup(out) & mpoly; + ctx->__vmac_ctx.polytmp[i+1] = + ctx->__vmac_ctx.polykey[i+1] = + be64_to_cpup(out+1) & mpoly; + ((unsigned char *)in)[15] += 1; + } + + /* Fill ip key */ + ((unsigned char *)in)[0] = 0xE0; + in[1] = 0; + for (i = 0; i < sizeof(ctx->__vmac_ctx.l3key)/8; i += 2) { + do { + crypto_cipher_encrypt_one(ctx->child, + (unsigned char *)out, (unsigned char *)in); + ctx->__vmac_ctx.l3key[i] = be64_to_cpup(out); + ctx->__vmac_ctx.l3key[i+1] = be64_to_cpup(out+1); + ((unsigned char *)in)[15] += 1; + } while (ctx->__vmac_ctx.l3key[i] >= p64 + || ctx->__vmac_ctx.l3key[i+1] >= p64); + } + + /* Invalidate nonce/aes cache and reset other elements */ + ctx->__vmac_ctx.cached_nonce[0] = (u64)-1; /* Ensure illegal nonce */ + ctx->__vmac_ctx.cached_nonce[1] = (u64)0; /* Ensure illegal nonce */ + ctx->__vmac_ctx.first_block_processed = 0; + + return err; +} + +static int vmac_setkey(struct crypto_shash *parent, + const u8 *key, unsigned int keylen) +{ + struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); + + if (keylen != VMAC_KEY_LEN) { + crypto_shash_set_flags(parent, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + return vmac_set_key((u8 *)key, ctx); +} + +static int vmac_init(struct shash_desc *pdesc) +{ + struct crypto_shash *parent = pdesc->tfm; + struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); + + memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx)); + return 0; +} + +static int vmac_update(struct shash_desc *pdesc, const u8 *p, + unsigned int len) +{ + struct crypto_shash *parent = pdesc->tfm; + struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); + + vhash_update(p, len, &ctx->__vmac_ctx); + + return 0; +} + +static int vmac_final(struct shash_desc *pdesc, u8 *out) +{ + struct crypto_shash *parent = pdesc->tfm; + struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); + vmac_t mac; + u8 nonce[16] = {}; + + mac = vmac(NULL, 0, nonce, NULL, ctx); + memcpy(out, &mac, sizeof(vmac_t)); + memset(&mac, 0, sizeof(vmac_t)); + memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx)); + return 0; +} + +static int vmac_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_cipher *cipher; + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_spawn *spawn = crypto_instance_ctx(inst); + struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm); + + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctx->child = cipher; + return 0; +} + +static void vmac_exit_tfm(struct crypto_tfm *tfm) +{ + struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm); + crypto_free_cipher(ctx->child); +} + +static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct shash_instance *inst; + struct crypto_alg *alg; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH); + if (err) + return err; + + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK); + if (IS_ERR(alg)) + return PTR_ERR(alg); + + inst = shash_alloc_instance("vmac", alg); + err = PTR_ERR(inst); + if (IS_ERR(inst)) + goto out_put_alg; + + err = crypto_init_spawn(shash_instance_ctx(inst), alg, + shash_crypto_instance(inst), + CRYPTO_ALG_TYPE_MASK); + if (err) + goto out_free_inst; + + inst->alg.base.cra_priority = alg->cra_priority; + inst->alg.base.cra_blocksize = alg->cra_blocksize; + inst->alg.base.cra_alignmask = alg->cra_alignmask; + + inst->alg.digestsize = sizeof(vmac_t); + inst->alg.base.cra_ctxsize = sizeof(struct vmac_ctx_t); + inst->alg.base.cra_init = vmac_init_tfm; + inst->alg.base.cra_exit = vmac_exit_tfm; + + inst->alg.init = vmac_init; + inst->alg.update = vmac_update; + inst->alg.final = vmac_final; + inst->alg.setkey = vmac_setkey; + + err = shash_register_instance(tmpl, inst); + if (err) { +out_free_inst: + shash_free_instance(shash_crypto_instance(inst)); + } + +out_put_alg: + crypto_mod_put(alg); + return err; +} + +static struct crypto_template vmac_tmpl = { + .name = "vmac", + .create = vmac_create, + .free = shash_free_instance, + .module = THIS_MODULE, +}; + +static int __init vmac_module_init(void) +{ + return crypto_register_template(&vmac_tmpl); +} + +static void __exit vmac_module_exit(void) +{ + crypto_unregister_template(&vmac_tmpl); +} + +module_init(vmac_module_init); +module_exit(vmac_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VMAC hash algorithm"); + diff --git a/include/crypto/vmac.h b/include/crypto/vmac.h new file mode 100644 index 0000000..c4467c5 --- /dev/null +++ b/include/crypto/vmac.h @@ -0,0 +1,61 @@ +/* + * Modified to interface to the Linux kernel + * Copyright (c) 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., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef __CRYPTO_VMAC_H +#define __CRYPTO_VMAC_H + +/* -------------------------------------------------------------------------- + * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. + * This implementation is herby placed in the public domain. + * The authors offers no warranty. Use at your own risk. + * Please send bug reports to the authors. + * Last modified: 17 APR 08, 1700 PDT + * ----------------------------------------------------------------------- */ + +/* + * User definable settings. + */ +#define VMAC_TAG_LEN 64 +#define VMAC_KEY_SIZE 128/* Must be 128, 192 or 256 */ +#define VMAC_KEY_LEN (VMAC_KEY_SIZE/8) +#define VMAC_NHBYTES 128/* Must 2^i for any 3 < i < 13 Standard = 128*/ + +/* + * This implementation uses u32 and u64 as names for unsigned 32- + * and 64-bit integer types. These are defined in C99 stdint.h. The + * following may need adaptation if you are not running a C99 or + * Microsoft C environment. + */ +struct vmac_ctx { + u64 nhkey[(VMAC_NHBYTES/8)+2*(VMAC_TAG_LEN/64-1)]; + u64 polykey[2*VMAC_TAG_LEN/64]; + u64 l3key[2*VMAC_TAG_LEN/64]; + u64 polytmp[2*VMAC_TAG_LEN/64]; + u64 cached_nonce[2]; + u64 cached_aes[2]; + int first_block_processed; +}; + +typedef u64 vmac_t; + +struct vmac_ctx_t { + struct crypto_cipher *child; + struct vmac_ctx __vmac_ctx; +}; + +#endif /* __CRYPTO_VMAC_H */ -- cgit v0.10.2 From e0e817392b9acf2c98d3be80c233dddb1b52003d Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 2 Sep 2009 09:13:40 +0100 Subject: CRED: Add some configurable debugging [try #6] Add a config option (CONFIG_DEBUG_CREDENTIALS) to turn on some debug checking for credential management. The additional code keeps track of the number of pointers from task_structs to any given cred struct, and checks to see that this number never exceeds the usage count of the cred struct (which includes all references, not just those from task_structs). Furthermore, if SELinux is enabled, the code also checks that the security pointer in the cred struct is never seen to be invalid. This attempts to catch the bug whereby inode_has_perm() faults in an nfsd kernel thread on seeing cred->security be a NULL pointer (it appears that the credential struct has been previously released): http://www.kerneloops.org/oops.php?number=252883 Signed-off-by: David Howells Signed-off-by: James Morris diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 5573508..36fcabbf 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c @@ -34,6 +34,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) int flags = nfsexp_flags(rqstp, exp); int ret; + validate_process_creds(); + /* discard any old override before preparing the new set */ revert_creds(get_cred(current->real_cred)); new = prepare_creds(); @@ -86,8 +88,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) else new->cap_effective = cap_raise_nfsd_set(new->cap_effective, new->cap_permitted); + validate_process_creds(); put_cred(override_creds(new)); put_cred(new); + validate_process_creds(); return 0; oom: diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 492c79b..24d58ad 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -496,7 +496,9 @@ nfsd(void *vrqstp) /* Lock the export hash tables for reading. */ exp_readlock(); + validate_process_creds(); svc_process(rqstp); + validate_process_creds(); /* Unlock export hash tables */ exp_readunlock(); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 23341c1..8fa09bf 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -684,6 +684,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, __be32 err; int host_err; + validate_process_creds(); + /* * If we get here, then the client has already done an "open", * and (hopefully) checked permission - so allow OWNER_OVERRIDE @@ -740,6 +742,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, out_nfserr: err = nfserrno(host_err); out: + validate_process_creds(); return err; } diff --git a/fs/open.c b/fs/open.c index 40d1fa2..31191bf 100644 --- a/fs/open.c +++ b/fs/open.c @@ -959,6 +959,8 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, int error; struct file *f; + validate_creds(cred); + /* * We must always pass in a valid mount pointer. Historically * callers got away with not passing it, but we must enforce this at diff --git a/include/linux/cred.h b/include/linux/cred.h index b3c76e8..85439ab 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -114,6 +114,13 @@ struct thread_group_cred { */ struct cred { atomic_t usage; +#ifdef CONFIG_DEBUG_CREDENTIALS + atomic_t subscribers; /* number of processes subscribed */ + void *put_addr; + unsigned magic; +#define CRED_MAGIC 0x43736564 +#define CRED_MAGIC_DEAD 0x44656144 +#endif uid_t uid; /* real UID of the task */ gid_t gid; /* real GID of the task */ uid_t suid; /* saved UID of the task */ @@ -143,6 +150,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 *prepare_creds(void); extern struct cred *prepare_exec_creds(void); @@ -158,6 +166,60 @@ extern int set_security_override_from_ctx(struct cred *, const char *); extern int set_create_files_as(struct cred *, struct inode *); extern void __init cred_init(void); +/* + * check for validity of credentials + */ +#ifdef CONFIG_DEBUG_CREDENTIALS +extern void __invalid_creds(const struct cred *, const char *, unsigned); +extern void __validate_process_creds(struct task_struct *, + const char *, unsigned); + +static inline bool creds_are_invalid(const struct cred *cred) +{ + if (cred->magic != CRED_MAGIC) + return true; + if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers)) + return true; +#ifdef CONFIG_SECURITY_SELINUX + if ((unsigned long) cred->security < PAGE_SIZE) + return true; + if ((*(u32*)cred->security & 0xffffff00) == + (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)) + return true; +#endif + return false; +} + +static inline void __validate_creds(const struct cred *cred, + const char *file, unsigned line) +{ + if (unlikely(creds_are_invalid(cred))) + __invalid_creds(cred, file, line); +} + +#define validate_creds(cred) \ +do { \ + __validate_creds((cred), __FILE__, __LINE__); \ +} while(0) + +#define validate_process_creds() \ +do { \ + __validate_process_creds(current, __FILE__, __LINE__); \ +} while(0) + +extern void validate_creds_for_do_exit(struct task_struct *); +#else +static inline void validate_creds(const struct cred *cred) +{ +} +static inline void validate_creds_for_do_exit(struct task_struct *tsk) +{ +} +static inline void validate_process_creds(void) +{ +} +#endif + /** * get_new_cred - Get a reference on a new set of credentials * @cred: The new credentials to reference @@ -187,6 +249,7 @@ static inline struct cred *get_new_cred(struct cred *cred) static inline const struct cred *get_cred(const struct cred *cred) { struct cred *nonconst_cred = (struct cred *) cred; + validate_creds(cred); return get_new_cred(nonconst_cred); } @@ -205,7 +268,7 @@ static inline void put_cred(const struct cred *_cred) { struct cred *cred = (struct cred *) _cred; - BUG_ON(atomic_read(&(cred)->usage) <= 0); + validate_creds(cred); if (atomic_dec_and_test(&(cred)->usage)) __put_cred(cred); } diff --git a/kernel/cred.c b/kernel/cred.c index 1bb4d7e..24dd2f5 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -18,6 +18,18 @@ #include #include "cred-internals.h" +#if 0 +#define kdebug(FMT, ...) \ + printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__) +#else +static inline __attribute__((format(printf, 1, 2))) +void no_printk(const char *fmt, ...) +{ +} +#define kdebug(FMT, ...) \ + no_printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__) +#endif + static struct kmem_cache *cred_jar; /* @@ -36,6 +48,10 @@ static struct thread_group_cred init_tgcred = { */ struct cred init_cred = { .usage = ATOMIC_INIT(4), +#ifdef CONFIG_DEBUG_CREDENTIALS + .subscribers = ATOMIC_INIT(2), + .magic = CRED_MAGIC, +#endif .securebits = SECUREBITS_DEFAULT, .cap_inheritable = CAP_INIT_INH_SET, .cap_permitted = CAP_FULL_SET, @@ -48,6 +64,31 @@ struct cred init_cred = { #endif }; +static inline void set_cred_subscribers(struct cred *cred, int n) +{ +#ifdef CONFIG_DEBUG_CREDENTIALS + atomic_set(&cred->subscribers, n); +#endif +} + +static inline int read_cred_subscribers(const struct cred *cred) +{ +#ifdef CONFIG_DEBUG_CREDENTIALS + return atomic_read(&cred->subscribers); +#else + return 0; +#endif +} + +static inline void alter_cred_subscribers(const struct cred *_cred, int n) +{ +#ifdef CONFIG_DEBUG_CREDENTIALS + struct cred *cred = (struct cred *) _cred; + + atomic_add(n, &cred->subscribers); +#endif +} + /* * Dispose of the shared task group credentials */ @@ -85,9 +126,22 @@ static void put_cred_rcu(struct rcu_head *rcu) { struct cred *cred = container_of(rcu, struct cred, rcu); + kdebug("put_cred_rcu(%p)", cred); + +#ifdef CONFIG_DEBUG_CREDENTIALS + if (cred->magic != CRED_MAGIC_DEAD || + atomic_read(&cred->usage) != 0 || + read_cred_subscribers(cred) != 0) + panic("CRED: put_cred_rcu() sees %p with" + " mag %x, put %p, usage %d, subscr %d\n", + cred, cred->magic, cred->put_addr, + atomic_read(&cred->usage), + read_cred_subscribers(cred)); +#else if (atomic_read(&cred->usage) != 0) panic("CRED: put_cred_rcu() sees %p with usage %d\n", cred, atomic_read(&cred->usage)); +#endif security_cred_free(cred); key_put(cred->thread_keyring); @@ -106,12 +160,47 @@ static void put_cred_rcu(struct rcu_head *rcu) */ void __put_cred(struct cred *cred) { + kdebug("__put_cred(%p{%d,%d})", cred, + atomic_read(&cred->usage), + read_cred_subscribers(cred)); + BUG_ON(atomic_read(&cred->usage) != 0); +#ifdef CONFIG_DEBUG_CREDENTIALS + BUG_ON(read_cred_subscribers(cred) != 0); + cred->magic = CRED_MAGIC_DEAD; + cred->put_addr = __builtin_return_address(0); +#endif + BUG_ON(cred == current->cred); + BUG_ON(cred == current->real_cred); call_rcu(&cred->rcu, put_cred_rcu); } EXPORT_SYMBOL(__put_cred); +/* + * Clean up a task's credentials when it exits + */ +void exit_creds(struct task_struct *tsk) +{ + struct cred *cred; + + kdebug("exit_creds(%u,%p,%p,{%d,%d})", tsk->pid, tsk->real_cred, tsk->cred, + atomic_read(&tsk->cred->usage), + read_cred_subscribers(tsk->cred)); + + cred = (struct cred *) tsk->real_cred; + tsk->real_cred = NULL; + validate_creds(cred); + alter_cred_subscribers(cred, -1); + put_cred(cred); + + cred = (struct cred *) tsk->cred; + tsk->cred = NULL; + validate_creds(cred); + alter_cred_subscribers(cred, -1); + put_cred(cred); +} + /** * prepare_creds - Prepare a new set of credentials for modification * @@ -132,16 +221,19 @@ struct cred *prepare_creds(void) const struct cred *old; struct cred *new; - BUG_ON(atomic_read(&task->real_cred->usage) < 1); + validate_process_creds(); new = kmem_cache_alloc(cred_jar, GFP_KERNEL); if (!new) return NULL; + kdebug("prepare_creds() alloc %p", new); + old = task->cred; memcpy(new, old, sizeof(struct cred)); atomic_set(&new->usage, 1); + set_cred_subscribers(new, 0); get_group_info(new->group_info); get_uid(new->user); @@ -157,6 +249,7 @@ struct cred *prepare_creds(void) if (security_prepare_creds(new, old, GFP_KERNEL) < 0) goto error; + validate_creds(new); return new; error: @@ -229,9 +322,12 @@ struct cred *prepare_usermodehelper_creds(void) if (!new) return NULL; + kdebug("prepare_usermodehelper_creds() alloc %p", new); + memcpy(new, &init_cred, sizeof(struct cred)); atomic_set(&new->usage, 1); + set_cred_subscribers(new, 0); get_group_info(new->group_info); get_uid(new->user); @@ -250,6 +346,7 @@ struct cred *prepare_usermodehelper_creds(void) #endif if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0) goto error; + validate_creds(new); BUG_ON(atomic_read(&new->usage) != 1); return new; @@ -286,6 +383,10 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) ) { p->real_cred = get_cred(p->cred); get_cred(p->cred); + alter_cred_subscribers(p->cred, 2); + kdebug("share_creds(%p{%d,%d})", + p->cred, atomic_read(&p->cred->usage), + read_cred_subscribers(p->cred)); atomic_inc(&p->cred->user->processes); return 0; } @@ -331,6 +432,8 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) atomic_inc(&new->user->processes); p->cred = p->real_cred = get_cred(new); + alter_cred_subscribers(new, 2); + validate_creds(new); return 0; error_put: @@ -355,13 +458,20 @@ error_put: int commit_creds(struct cred *new) { struct task_struct *task = current; - const struct cred *old; + const struct cred *old = task->real_cred; - BUG_ON(task->cred != task->real_cred); - BUG_ON(atomic_read(&task->real_cred->usage) < 2); + kdebug("commit_creds(%p{%d,%d})", new, + atomic_read(&new->usage), + read_cred_subscribers(new)); + + BUG_ON(task->cred != old); +#ifdef CONFIG_DEBUG_CREDENTIALS + BUG_ON(read_cred_subscribers(old) < 2); + validate_creds(old); + validate_creds(new); +#endif BUG_ON(atomic_read(&new->usage) < 1); - old = task->real_cred; security_commit_creds(new, old); get_cred(new); /* we will require a ref for the subj creds too */ @@ -390,12 +500,14 @@ int commit_creds(struct cred *new) * cheaply with the new uid cache, so if it matters * we should be checking for it. -DaveM */ + alter_cred_subscribers(new, 2); if (new->user != old->user) atomic_inc(&new->user->processes); rcu_assign_pointer(task->real_cred, new); rcu_assign_pointer(task->cred, new); if (new->user != old->user) atomic_dec(&old->user->processes); + alter_cred_subscribers(old, -2); sched_switch_user(task); @@ -428,6 +540,13 @@ EXPORT_SYMBOL(commit_creds); */ void abort_creds(struct cred *new) { + kdebug("abort_creds(%p{%d,%d})", new, + atomic_read(&new->usage), + read_cred_subscribers(new)); + +#ifdef CONFIG_DEBUG_CREDENTIALS + BUG_ON(read_cred_subscribers(new) != 0); +#endif BUG_ON(atomic_read(&new->usage) < 1); put_cred(new); } @@ -444,7 +563,20 @@ const struct cred *override_creds(const struct cred *new) { const struct cred *old = current->cred; - rcu_assign_pointer(current->cred, get_cred(new)); + kdebug("override_creds(%p{%d,%d})", new, + atomic_read(&new->usage), + read_cred_subscribers(new)); + + validate_creds(old); + validate_creds(new); + get_cred(new); + alter_cred_subscribers(new, 1); + rcu_assign_pointer(current->cred, new); + alter_cred_subscribers(old, -1); + + kdebug("override_creds() = %p{%d,%d}", old, + atomic_read(&old->usage), + read_cred_subscribers(old)); return old; } EXPORT_SYMBOL(override_creds); @@ -460,7 +592,15 @@ void revert_creds(const struct cred *old) { const struct cred *override = current->cred; + kdebug("revert_creds(%p{%d,%d})", old, + atomic_read(&old->usage), + read_cred_subscribers(old)); + + validate_creds(old); + validate_creds(override); + alter_cred_subscribers(old, 1); rcu_assign_pointer(current->cred, old); + alter_cred_subscribers(override, -1); put_cred(override); } EXPORT_SYMBOL(revert_creds); @@ -502,11 +642,15 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) if (!new) return NULL; + kdebug("prepare_kernel_cred() alloc %p", new); + if (daemon) old = get_task_cred(daemon); else old = get_cred(&init_cred); + validate_creds(old); + *new = *old; get_uid(new->user); get_group_info(new->group_info); @@ -526,7 +670,9 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) goto error; atomic_set(&new->usage, 1); + set_cred_subscribers(new, 0); put_cred(old); + validate_creds(new); return new; error: @@ -589,3 +735,95 @@ int set_create_files_as(struct cred *new, struct inode *inode) return security_kernel_create_files_as(new, inode); } EXPORT_SYMBOL(set_create_files_as); + +#ifdef CONFIG_DEBUG_CREDENTIALS + +/* + * dump invalid credentials + */ +static void dump_invalid_creds(const struct cred *cred, const char *label, + const struct task_struct *tsk) +{ + printk(KERN_ERR "CRED: %s credentials: %p %s%s%s\n", + label, cred, + cred == &init_cred ? "[init]" : "", + cred == tsk->real_cred ? "[real]" : "", + cred == tsk->cred ? "[eff]" : ""); + printk(KERN_ERR "CRED: ->magic=%x, put_addr=%p\n", + cred->magic, cred->put_addr); + printk(KERN_ERR "CRED: ->usage=%d, subscr=%d\n", + atomic_read(&cred->usage), + read_cred_subscribers(cred)); + printk(KERN_ERR "CRED: ->*uid = { %d,%d,%d,%d }\n", + cred->uid, cred->euid, cred->suid, cred->fsuid); + printk(KERN_ERR "CRED: ->*gid = { %d,%d,%d,%d }\n", + cred->gid, cred->egid, cred->sgid, cred->fsgid); +#ifdef CONFIG_SECURITY + printk(KERN_ERR "CRED: ->security is %p\n", cred->security); + if ((unsigned long) cred->security >= PAGE_SIZE && + (((unsigned long) cred->security & 0xffffff00) != + (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))) + printk(KERN_ERR "CRED: ->security {%x, %x}\n", + ((u32*)cred->security)[0], + ((u32*)cred->security)[1]); +#endif +} + +/* + * report use of invalid credentials + */ +void __invalid_creds(const struct cred *cred, const char *file, unsigned line) +{ + printk(KERN_ERR "CRED: Invalid credentials\n"); + printk(KERN_ERR "CRED: At %s:%u\n", file, line); + dump_invalid_creds(cred, "Specified", current); + BUG(); +} +EXPORT_SYMBOL(__invalid_creds); + +/* + * check the credentials on a process + */ +void __validate_process_creds(struct task_struct *tsk, + const char *file, unsigned line) +{ + if (tsk->cred == tsk->real_cred) { + if (unlikely(read_cred_subscribers(tsk->cred) < 2 || + creds_are_invalid(tsk->cred))) + goto invalid_creds; + } else { + if (unlikely(read_cred_subscribers(tsk->real_cred) < 1 || + read_cred_subscribers(tsk->cred) < 1 || + creds_are_invalid(tsk->real_cred) || + creds_are_invalid(tsk->cred))) + goto invalid_creds; + } + return; + +invalid_creds: + printk(KERN_ERR "CRED: Invalid process credentials\n"); + printk(KERN_ERR "CRED: At %s:%u\n", file, line); + + dump_invalid_creds(tsk->real_cred, "Real", tsk); + if (tsk->cred != tsk->real_cred) + dump_invalid_creds(tsk->cred, "Effective", tsk); + else + printk(KERN_ERR "CRED: Effective creds == Real creds\n"); + BUG(); +} +EXPORT_SYMBOL(__validate_process_creds); + +/* + * check creds for do_exit() + */ +void validate_creds_for_do_exit(struct task_struct *tsk) +{ + kdebug("validate_creds_for_do_exit(%p,%p{%d,%d})", + tsk->real_cred, tsk->cred, + atomic_read(&tsk->cred->usage), + read_cred_subscribers(tsk->cred)); + + __validate_process_creds(tsk, __FILE__, __LINE__); +} + +#endif /* CONFIG_DEBUG_CREDENTIALS */ diff --git a/kernel/exit.c b/kernel/exit.c index 869dc22..c98ff7a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -901,6 +901,8 @@ NORET_TYPE void do_exit(long code) tracehook_report_exit(&code); + validate_creds_for_do_exit(tsk); + /* * We're taking recursive faults here in do_exit. Safest is to just * leave this task alone and wait for reboot. @@ -1009,6 +1011,8 @@ NORET_TYPE void do_exit(long code) if (tsk->splice_pipe) __free_pipe_info(tsk->splice_pipe); + validate_creds_for_do_exit(tsk); + preempt_disable(); /* causes final put_task_struct in finish_task_switch(). */ tsk->state = TASK_DEAD; diff --git a/kernel/fork.c b/kernel/fork.c index 144326b..043b5d8 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -152,8 +152,7 @@ void __put_task_struct(struct task_struct *tsk) WARN_ON(atomic_read(&tsk->usage)); WARN_ON(tsk == current); - put_cred(tsk->real_cred); - put_cred(tsk->cred); + exit_creds(tsk); delayacct_tsk_free(tsk); if (!profile_handoff_task(tsk)) @@ -1307,8 +1306,7 @@ bad_fork_cleanup_put_domain: module_put(task_thread_info(p)->exec_domain->module); bad_fork_cleanup_count: atomic_dec(&p->cred->user->processes); - put_cred(p->real_cred); - put_cred(p->cred); + exit_creds(p); bad_fork_free: free_task(p); fork_out: diff --git a/kernel/kmod.c b/kernel/kmod.c index 5a7ae57..4e8cae2 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -466,6 +466,7 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int retval = 0; BUG_ON(atomic_read(&sub_info->cred->usage) != 1); + validate_creds(sub_info->cred); helper_lock(); if (sub_info->path[0] == '\0') diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 12327b2..fbb87cf 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -653,6 +653,21 @@ config DEBUG_NOTIFIERS This is a relatively cheap check but if you care about maximum performance, say N. +config DEBUG_CREDENTIALS + bool "Debug credential management" + depends on DEBUG_KERNEL + help + Enable this to turn on some debug checking for credential + management. The additional code keeps track of the number of + pointers from task_structs to any given cred struct, and checks to + see that this number never exceeds the usage count of the cred + struct. + + Furthermore, if SELinux is enabled, this also checks that the + security pointer in the cred struct is never seen to be invalid. + + If unsure, say N. + # # Select this config option from the architecture Kconfig, if it # it is preferred to always offer frame pointers as a config diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 27b4c55..c3bb31e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1531,6 +1531,8 @@ static int inode_has_perm(const struct cred *cred, struct common_audit_data ad; u32 sid; + validate_creds(cred); + if (unlikely(IS_PRIVATE(inode))) return 0; @@ -3236,7 +3238,9 @@ static int selinux_task_create(unsigned long clone_flags) static void selinux_cred_free(struct cred *cred) { struct task_security_struct *tsec = cred->security; - cred->security = NULL; + + BUG_ON((unsigned long) cred->security < PAGE_SIZE); + cred->security = (void *) 0x7UL; kfree(tsec); } -- cgit v0.10.2 From 5593122eec26b061cc0b6fbff32118f1aadf4a27 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 2 Sep 2009 09:13:45 +0100 Subject: KEYS: Deal with dead-type keys appropriately [try #6] Allow keys for which the key type has been removed to be unlinked. Currently dead-type keys can only be disposed of by completely clearing the keyrings that point to them. Signed-off-by: David Howells Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/security/keys/internal.h b/security/keys/internal.h index 9fb679c..a7252e7 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -124,8 +124,11 @@ extern struct key *request_key_and_link(struct key_type *type, struct key *dest_keyring, unsigned long flags); -extern key_ref_t lookup_user_key(key_serial_t id, int create, int partial, +extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, key_perm_t perm); +#define KEY_LOOKUP_CREATE 0x01 +#define KEY_LOOKUP_PARTIAL 0x02 +#define KEY_LOOKUP_FOR_UNLINK 0x04 extern long join_session_keyring(const char *name); diff --git a/security/keys/key.c b/security/keys/key.c index 4a1297d..3762d5b 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -642,10 +642,8 @@ struct key *key_lookup(key_serial_t id) goto error; found: - /* pretend it doesn't exist if it's dead */ - if (atomic_read(&key->usage) == 0 || - test_bit(KEY_FLAG_DEAD, &key->flags) || - key->type == &key_type_dead) + /* pretend it doesn't exist if it is awaiting deletion */ + if (atomic_read(&key->usage) == 0) goto not_found; /* this races with key_put(), but that doesn't matter since key_put() diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 7f09fb8..b85ace2 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -103,7 +103,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, } /* find the target keyring (which must be writable) */ - keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); + keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error3; @@ -185,7 +185,8 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, /* get the destination keyring if specified */ dest_ref = NULL; if (destringid) { - dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE); + dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, + KEY_WRITE); if (IS_ERR(dest_ref)) { ret = PTR_ERR(dest_ref); goto error3; @@ -233,9 +234,11 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, long keyctl_get_keyring_ID(key_serial_t id, int create) { key_ref_t key_ref; + unsigned long lflags; long ret; - key_ref = lookup_user_key(id, create, 0, KEY_SEARCH); + lflags = create ? KEY_LOOKUP_CREATE : 0; + key_ref = lookup_user_key(id, lflags, KEY_SEARCH); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -309,7 +312,7 @@ long keyctl_update_key(key_serial_t id, } /* find the target key (which must be writable) */ - key_ref = lookup_user_key(id, 0, 0, KEY_WRITE); + key_ref = lookup_user_key(id, 0, KEY_WRITE); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error2; @@ -337,7 +340,7 @@ long keyctl_revoke_key(key_serial_t id) key_ref_t key_ref; long ret; - key_ref = lookup_user_key(id, 0, 0, KEY_WRITE); + key_ref = lookup_user_key(id, 0, KEY_WRITE); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -363,7 +366,7 @@ long keyctl_keyring_clear(key_serial_t ringid) key_ref_t keyring_ref; long ret; - keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); + keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error; @@ -389,13 +392,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) key_ref_t keyring_ref, key_ref; long ret; - keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); + keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error; } - key_ref = lookup_user_key(id, 1, 0, KEY_LINK); + key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error2; @@ -423,13 +426,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) key_ref_t keyring_ref, key_ref; long ret; - keyring_ref = lookup_user_key(ringid, 0, 0, KEY_WRITE); + keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error; } - key_ref = lookup_user_key(id, 0, 0, 0); + key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error2; @@ -465,7 +468,7 @@ long keyctl_describe_key(key_serial_t keyid, char *tmpbuf; long ret; - key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW); + key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); if (IS_ERR(key_ref)) { /* viewing a key under construction is permitted if we have the * authorisation token handy */ @@ -474,7 +477,8 @@ long keyctl_describe_key(key_serial_t keyid, if (!IS_ERR(instkey)) { key_put(instkey); key_ref = lookup_user_key(keyid, - 0, 1, 0); + KEY_LOOKUP_PARTIAL, + 0); if (!IS_ERR(key_ref)) goto okay; } @@ -558,7 +562,7 @@ long keyctl_keyring_search(key_serial_t ringid, } /* get the keyring at which to begin the search */ - keyring_ref = lookup_user_key(ringid, 0, 0, KEY_SEARCH); + keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error2; @@ -567,7 +571,8 @@ long keyctl_keyring_search(key_serial_t ringid, /* get the destination keyring if specified */ dest_ref = NULL; if (destringid) { - dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE); + dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, + KEY_WRITE); if (IS_ERR(dest_ref)) { ret = PTR_ERR(dest_ref); goto error3; @@ -637,7 +642,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) long ret; /* find the key first */ - key_ref = lookup_user_key(keyid, 0, 0, 0); + key_ref = lookup_user_key(keyid, 0, 0); if (IS_ERR(key_ref)) { ret = -ENOKEY; goto error; @@ -700,7 +705,8 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) if (uid == (uid_t) -1 && gid == (gid_t) -1) goto error; - key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); + key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, + KEY_SETATTR); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -805,7 +811,8 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) goto error; - key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); + key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, + KEY_SETATTR); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -847,7 +854,7 @@ static long get_instantiation_keyring(key_serial_t ringid, /* if a specific keyring is nominated by ID, then use that */ if (ringid > 0) { - dkref = lookup_user_key(ringid, 1, 0, KEY_WRITE); + dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); if (IS_ERR(dkref)) return PTR_ERR(dkref); *_dest_keyring = key_ref_to_ptr(dkref); @@ -1083,7 +1090,8 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) time_t expiry; long ret; - key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); + key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, + KEY_SETATTR); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -1170,7 +1178,7 @@ long keyctl_get_security(key_serial_t keyid, char *context; long ret; - key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW); + key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); if (IS_ERR(key_ref)) { if (PTR_ERR(key_ref) != -EACCES) return PTR_ERR(key_ref); @@ -1182,7 +1190,7 @@ long keyctl_get_security(key_serial_t keyid, return PTR_ERR(key_ref); key_put(instkey); - key_ref = lookup_user_key(keyid, 0, 1, 0); + key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0); if (IS_ERR(key_ref)) return PTR_ERR(key_ref); } diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index ed929af..4739cfb 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -487,7 +487,7 @@ static int lookup_user_key_possessed(const struct key *key, const void *target) * - don't create special keyrings unless so requested * - partially constructed keys aren't found unless requested */ -key_ref_t lookup_user_key(key_serial_t id, int create, int partial, +key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, key_perm_t perm) { struct request_key_auth *rka; @@ -503,7 +503,7 @@ try_again: switch (id) { case KEY_SPEC_THREAD_KEYRING: if (!cred->thread_keyring) { - if (!create) + if (!(lflags & KEY_LOOKUP_CREATE)) goto error; ret = install_thread_keyring(); @@ -521,7 +521,7 @@ try_again: case KEY_SPEC_PROCESS_KEYRING: if (!cred->tgcred->process_keyring) { - if (!create) + if (!(lflags & KEY_LOOKUP_CREATE)) goto error; ret = install_process_keyring(); @@ -642,7 +642,14 @@ try_again: break; } - if (!partial) { + /* unlink does not use the nominated key in any way, so can skip all + * the permission checks as it is only concerned with the keyring */ + if (lflags & KEY_LOOKUP_FOR_UNLINK) { + ret = 0; + goto error; + } + + if (!(lflags & KEY_LOOKUP_PARTIAL)) { ret = wait_for_key_construction(key, true); switch (ret) { case -ERESTARTSYS: @@ -660,7 +667,8 @@ try_again: } ret = -EIO; - if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) + if (!(lflags & KEY_LOOKUP_PARTIAL) && + !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) goto invalid_key; /* check the permissions */ -- cgit v0.10.2 From 0c2c9a3fc77e8b60d43d9bd2ca46eb4dddb0ff76 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 2 Sep 2009 09:13:50 +0100 Subject: KEYS: Allow keyctl_revoke() on keys that have SETATTR but not WRITE perm [try #6] Allow keyctl_revoke() to operate on keys that have SETATTR but not WRITE permission, rather than only on keys that have WRITE permission. Signed-off-by: David Howells Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index b85ace2..1160b64 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -343,7 +343,13 @@ long keyctl_revoke_key(key_serial_t id) key_ref = lookup_user_key(id, 0, KEY_WRITE); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); - goto error; + if (ret != -EACCES) + goto error; + key_ref = lookup_user_key(id, 0, KEY_SETATTR); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); + goto error; + } } key_revoke(key_ref_to_ptr(key_ref)); -- cgit v0.10.2 From f041ae2f99d49adc914153a34a2d0e14e4389d90 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 2 Sep 2009 09:13:55 +0100 Subject: KEYS: Flag dead keys to induce EKEYREVOKED [try #6] Set the KEY_FLAG_DEAD flag on keys for which the type has been removed. This causes the key_permission() function to return EKEYREVOKED in response to various commands. It does not, however, prevent unlinking or clearing of keyrings from detaching the key. Signed-off-by: David Howells Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/security/keys/key.c b/security/keys/key.c index 3762d5b..bd9d2670 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -956,8 +956,10 @@ void unregister_key_type(struct key_type *ktype) for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { key = rb_entry(_n, struct key, serial_node); - if (key->type == ktype) + if (key->type == ktype) { key->type = &key_type_dead; + set_bit(KEY_FLAG_DEAD, &key->flags); + } } spin_unlock(&key_serial_lock); -- cgit v0.10.2 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 diff --git a/Documentation/keys.txt b/Documentation/keys.txt index b56aacc..203487e 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 e544f46..33e0165 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 747a464..74d5447 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 0000000..44adc32 --- /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 a7252e7..fb83051 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 bd9d2670..08531ad 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 1160b64..736d780 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 3dba81c..ac977f6 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 b611d49..5e05dc0 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 v0.10.2 From ad73a717e0fc6949c44e587ca5d63c273a30e6f5 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Wed, 2 Sep 2009 09:14:05 +0100 Subject: KEYS: Make /proc/keys use keyid not numread as file position [try #6] Make the file position maintained by /proc/keys represent the ID of the key just read rather than the number of keys read. This should make it faster to perform a lookup as we don't have to scan the key ID tree from the beginning to find the current position. Signed-off-by: Serge E. Hallyn Signed-off-by: David Howells Signed-off-by: James Morris diff --git a/security/keys/proc.c b/security/keys/proc.c index 39793c7..624c650 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -91,57 +91,90 @@ __initcall(key_proc_init); */ #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS -static struct rb_node *__key_serial_next(struct rb_node *n) +static struct rb_node *key_serial_next(struct rb_node *n) { + struct user_namespace *user_ns = current_user_ns(); + + n = rb_next(n); while (n) { struct key *key = rb_entry(n, struct key, serial_node); - if (key->user->user_ns == current_user_ns()) + if (key->user->user_ns == user_ns) break; n = rb_next(n); } return n; } -static struct rb_node *key_serial_next(struct rb_node *n) +static int proc_keys_open(struct inode *inode, struct file *file) { - return __key_serial_next(rb_next(n)); + return seq_open(file, &proc_keys_ops); } -static struct rb_node *key_serial_first(struct rb_root *r) +static struct key *find_ge_key(key_serial_t id) { - struct rb_node *n = rb_first(r); - return __key_serial_next(n); -} + struct user_namespace *user_ns = current_user_ns(); + struct rb_node *n = key_serial_tree.rb_node; + struct key *minkey = NULL; -static int proc_keys_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &proc_keys_ops); + while (n) { + struct key *key = rb_entry(n, struct key, serial_node); + if (id < key->serial) { + if (!minkey || minkey->serial > key->serial) + minkey = key; + n = n->rb_left; + } else if (id > key->serial) { + n = n->rb_right; + } else { + minkey = key; + break; + } + key = NULL; + } + if (!minkey) + return NULL; + + for (;;) { + if (minkey->user->user_ns == user_ns) + return minkey; + n = rb_next(&minkey->serial_node); + if (!n) + return NULL; + minkey = rb_entry(n, struct key, serial_node); + } } static void *proc_keys_start(struct seq_file *p, loff_t *_pos) __acquires(key_serial_lock) { - struct rb_node *_p; - loff_t pos = *_pos; + key_serial_t pos = *_pos; + struct key *key; spin_lock(&key_serial_lock); - _p = key_serial_first(&key_serial_tree); - while (pos > 0 && _p) { - pos--; - _p = key_serial_next(_p); - } - - return _p; + if (*_pos > INT_MAX) + return NULL; + key = find_ge_key(pos); + if (!key) + return NULL; + *_pos = key->serial; + return &key->serial_node; +} +static inline key_serial_t key_node_serial(struct rb_node *n) +{ + struct key *key = rb_entry(n, struct key, serial_node); + return key->serial; } static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) { - (*_pos)++; - return key_serial_next((struct rb_node *) v); + struct rb_node *n; + n = key_serial_next(v); + if (n) + *_pos = key_node_serial(n); + return n; } static void proc_keys_stop(struct seq_file *p, void *v) -- cgit v0.10.2 From 7b1b9164598286fe93927ff41eed2a2609fd9056 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 2 Sep 2009 09:14:11 +0100 Subject: KEYS: Do some whitespace cleanups [try #6] Do some whitespace cleanups in the key management code. Signed-off-by: David Howells Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/security/keys/proc.c b/security/keys/proc.c index 624c650..9d01021 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -209,11 +209,9 @@ static int proc_keys_show(struct seq_file *m, void *v) /* come up with a suitable timeout value */ if (key->expiry == 0) { memcpy(xbuf, "perm", 5); - } - else if (now.tv_sec >= key->expiry) { + } else if (now.tv_sec >= key->expiry) { memcpy(xbuf, "expd", 5); - } - else { + } else { timo = key->expiry - now.tv_sec; if (timo < 60) @@ -253,9 +251,7 @@ static int proc_keys_show(struct seq_file *m, void *v) seq_putc(m, '\n'); rcu_read_unlock(); - return 0; - } #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ @@ -281,6 +277,7 @@ static struct rb_node *key_user_first(struct rb_root *r) struct rb_node *n = rb_first(r); return __key_user_next(n); } + /*****************************************************************************/ /* * implement "/proc/key-users" to provides a list of the key users @@ -288,7 +285,6 @@ static struct rb_node *key_user_first(struct rb_root *r) static int proc_key_users_open(struct inode *inode, struct file *file) { return seq_open(file, &proc_key_users_ops); - } static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) @@ -306,14 +302,12 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) } return _p; - } static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) { (*_pos)++; return key_user_next((struct rb_node *) v); - } static void proc_key_users_stop(struct seq_file *p, void *v) -- cgit v0.10.2 From d0420c83f39f79afb82010c2d2cafd150eef651b Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 2 Sep 2009 09:14:16 +0100 Subject: KEYS: Extend TIF_NOTIFY_RESUME to (almost) all architectures [try #6] Implement TIF_NOTIFY_RESUME for most of those architectures in which isn't yet available, and, whilst we're at it, have it call the appropriate tracehook. After this patch, blackfin, m68k* and xtensa still lack support and need alteration of assembly code to make it work. Resume notification can then be used (by a later patch) to install a new session keyring on the parent of a process. Signed-off-by: David Howells Acked-by: Russell King cc: linux-arch@vger.kernel.org Signed-off-by: James Morris diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h index 60c83ab..5076a88 100644 --- a/arch/alpha/include/asm/thread_info.h +++ b/arch/alpha/include/asm/thread_info.h @@ -75,6 +75,7 @@ register struct thread_info *__current_thread_info __asm__("$8"); #define TIF_UAC_SIGBUS 7 #define TIF_MEMDIE 8 #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal */ +#define TIF_NOTIFY_RESUME 10 /* callback before returning to user */ #define TIF_FREEZE 16 /* is freezing for suspend */ #define _TIF_SYSCALL_TRACE (1<blocked, regs, syscall); + + if (thread_flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } } diff --git a/arch/avr32/include/asm/thread_info.h b/arch/avr32/include/asm/thread_info.h index fc42de5..fd0c5d7 100644 --- a/arch/avr32/include/asm/thread_info.h +++ b/arch/avr32/include/asm/thread_info.h @@ -84,6 +84,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_MEMDIE 6 #define TIF_RESTORE_SIGMASK 7 /* restore signal mask in do_signal */ #define TIF_CPU_GOING_TO_SLEEP 8 /* CPU is entering sleep 0 mode */ +#define TIF_NOTIFY_RESUME 9 /* callback before returning to user */ #define TIF_FREEZE 29 #define TIF_DEBUG 30 /* debugging enabled */ #define TIF_USERSPACE 31 /* true if FS sets userspace */ @@ -96,6 +97,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_MEMDIE (1 << TIF_MEMDIE) #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP) +#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_FREEZE (1 << TIF_FREEZE) /* Note: The masks below must never span more than 16 bits! */ @@ -103,13 +105,15 @@ static inline struct thread_info *current_thread_info(void) /* work to do on interrupt/exception return */ #define _TIF_WORK_MASK \ ((1 << TIF_SIGPENDING) \ + | _TIF_NOTIFY_RESUME \ | (1 << TIF_NEED_RESCHED) \ | (1 << TIF_POLLING_NRFLAG) \ | (1 << TIF_BREAKPOINT) \ | (1 << TIF_RESTORE_SIGMASK)) /* work to do on any return to userspace */ -#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK | (1 << TIF_SYSCALL_TRACE)) +#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK | (1 << TIF_SYSCALL_TRACE) | \ + _TIF_NOTIFY_RESUME) /* work to do on return from debug mode */ #define _TIF_DBGWORK_MASK (_TIF_WORK_MASK & ~(1 << TIF_BREAKPOINT)) diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index 009a801..169268c 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S @@ -281,7 +281,7 @@ syscall_exit_work: ld.w r1, r0[TI_flags] rjmp 1b -2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK +2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NOTIFY_RESUME tst r1, r2 breq 3f unmask_interrupts diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 2722756..62d242e 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -322,4 +322,9 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) if (ti->flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) do_signal(regs, ¤t->blocked, syscall); + + if (ti->flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } } diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c index b326023..4f06d7f 100644 --- a/arch/cris/kernel/ptrace.c +++ b/arch/cris/kernel/ptrace.c @@ -36,4 +36,9 @@ void do_notify_resume(int canrestart, struct pt_regs *regs, /* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING) do_signal(canrestart,regs); + + if (thread_info_flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } } diff --git a/arch/h8300/include/asm/thread_info.h b/arch/h8300/include/asm/thread_info.h index 8bbc8b0..70e67e47 100644 --- a/arch/h8300/include/asm/thread_info.h +++ b/arch/h8300/include/asm/thread_info.h @@ -89,6 +89,7 @@ static inline struct thread_info *current_thread_info(void) TIF_NEED_RESCHED */ #define TIF_MEMDIE 4 #define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */ +#define TIF_NOTIFY_RESUME 6 /* callback before returning to user */ #define TIF_FREEZE 16 /* is freezing for suspend */ /* as above, but as bit values */ @@ -97,6 +98,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_NEED_RESCHED (1<) %r19, %r20, %r0 b,n intr_restore /* skip past if we've nothing to do */ diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index f825442..b3bfc43 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -645,4 +645,9 @@ void do_notify_resume(struct pt_regs *regs, long in_syscall) if (test_thread_flag(TIF_SIGPENDING) || test_thread_flag(TIF_RESTORE_SIGMASK)) do_signal(regs, in_syscall); + + if (test_thread_flag(TIF_NOTIFY_RESUME)) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } } -- cgit v0.10.2 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 diff --git a/Documentation/keys.txt b/Documentation/keys.txt index 203487e..e4dbbdb 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 04e17c1..d91aaa7 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 13dec27..ea4ad3a 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 62d242e..de9f7fe 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 4f06d7f..32e9d5e 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 4a7a62c..6b0a2b6 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 56b3ab7..abac3ee 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 5d7c0e5..89969e9 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 3220258..f80bac1 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 a3d1015..c2acf31 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 feb2f2e..a21f43b 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 b3bfc43..5ca1c02 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 062bd64..6b4fef8 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 b5afbec..04a2188 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 0663a0e..9e5c9b1 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 181d069..7ce1a10 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 ec82d76..647afbd 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 4c57875..81e5823 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 85439ab..24520a5 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 33e0165..cd50dfa 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 c0688eb..bd383f1 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 5c7ce13..9304027 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 40ba39e..97de3fe 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 24dd2f5..006fcab 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 06400cf..93a2ffe 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 c766c68..792c0a6 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 44adc32..1e616ae 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 fb83051..24ba030 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 736d780..74c9685 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 4739cfb..5c23afb 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 f88eaf6..d8b7276 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 c3bb31e..134a9c0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3233,6 +3233,21 @@ static int selinux_task_create(unsigned long clone_flags) } /* + * 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 */ static void selinux_cred_free(struct cred *cred) @@ -3264,6 +3279,17 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old, } /* + * 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 c243a2b..969f5fe 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1080,6 +1080,22 @@ static int smack_file_receive(struct file *file) */ /** + * 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 * @@ -1117,6 +1133,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. * @secid: specifies the security ID to be set @@ -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 35a13e7..9548a09 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 v0.10.2 From 61562445c80452ec417fb6a6895b991f6c1dd930 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 2 Sep 2009 14:50:23 +0200 Subject: perf tools: Clean up warnings list in the Makefile Make it easier to turn warnings on/off by using a separate line for each warning added. Some of the warnings have too much of a nuisance factor and we might want to turn them off in the future. Cc: Arjan van de Ven Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/Makefile b/tools/perf/Makefile index c481a51..9f8d207 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -169,7 +169,30 @@ endif # # Include saner warnings here, which can catch bugs: # -EXTRA_WARNINGS = -Wcast-align -Wformat -Wformat-security -Wformat-y2k -Wshadow -Winit-self -Wpacked -Wredundant-decls -Wstack-protector -Wstrict-aliasing=3 -Wswitch-default -Wswitch-enum -Wno-system-headers -Wundef -Wvolatile-register-var -Wwrite-strings -Wbad-function-cast -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wstrict-prototypes -Wdeclaration-after-statement + +EXTRA_WARNINGS := -Wcast-align +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstack-protector +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3 +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wvolatile-register-var +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes +EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement CFLAGS = $(M64) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) LDFLAGS = -lpthread -lrt -lelf -lm -- cgit v0.10.2 From 65014ab36196f6d86edc9ee23759d6930b9d89a8 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 2 Sep 2009 14:55:55 +0200 Subject: perf tools: Work around strict aliasing related warnings Older versions of GCC are rather stupid about strict aliasing: util/trace-event-parse.c: In function 'parse_cmdlines': util/trace-event-parse.c:93: warning: dereferencing type-punned pointer will break strict-aliasing rules util/trace-event-parse.c: In function 'parse_proc_kallsyms': util/trace-event-parse.c:155: warning: dereferencing type-punned pointer will break strict-aliasing rules util/trace-event-parse.c:157: warning: dereferencing type-punned pointer will break strict-aliasing rules util/trace-event-parse.c:158: warning: dereferencing type-punned pointer will break strict-aliasing rules util/trace-event-parse.c: In function 'parse_ftrace_printk': util/trace-event-parse.c:294: warning: dereferencing type-punned pointer will break strict-aliasing rules util/trace-event-parse.c:295: warning: dereferencing type-punned pointer will break strict-aliasing rules make: *** [util/trace-event-parse.o] Error 1 Make it clear to GCC that we intend with those pointers, by passing them through via an explicit (void *) cast. We might want to add -fno-strict-aliasing as well, like the kernel itself does. Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 8161527..6c9302a 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -188,7 +188,7 @@ int bigendian(void) unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; unsigned int *ptr; - ptr = (unsigned int *)str; + ptr = (unsigned int *)(void *)str; return *ptr == 0x01020304; } diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 665dac2..37b10c2 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -90,7 +90,7 @@ void parse_cmdlines(char *file, int size __unused) while (line) { item = malloc_or_die(sizeof(*item)); sscanf(line, "%d %as", &item->pid, - (float *)&item->comm); /* workaround gcc warning */ + (float *)(void *)&item->comm); /* workaround gcc warning */ item->next = list; list = item; line = strtok_r(NULL, "\n", &next); @@ -152,10 +152,10 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused) item = malloc_or_die(sizeof(*item)); item->mod = NULL; ret = sscanf(line, "%as %c %as\t[%as", - (float *)&addr_str, /* workaround gcc warning */ + (float *)(void *)&addr_str, /* workaround gcc warning */ &ch, - (float *)&item->func, - (float *)&item->mod); + (float *)(void *)&item->func, + (float *)(void *)&item->mod); item->addr = strtoull(addr_str, NULL, 16); free(addr_str); @@ -291,8 +291,8 @@ void parse_ftrace_printk(char *file, unsigned int size __unused) while (line) { item = malloc_or_die(sizeof(*item)); ret = sscanf(line, "%as : %as", - (float *)&addr_str, /* workaround gcc warning */ - (float *)&item->printk); + (float *)(void *)&addr_str, /* workaround gcc warning */ + (float *)(void *)&item->printk); item->addr = strtoull(addr_str, NULL, 16); free(addr_str); -- cgit v0.10.2 From 2eff31e8096513d03b0b6484b85fd2c417eb87e8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 2 Sep 2009 18:51:19 +0100 Subject: ASoC: Fully specify DC servo bits to update in wm_hubs Avoids potential issues if we read back unexpected values during a read/modify/write cycle. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 41699bd..e542027 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -273,17 +273,12 @@ static int hp_event(struct snd_soc_dapm_widget *w, /* Start the DC servo */ snd_soc_update_bits(codec, WM8993_DC_SERVO_0, - WM8993_DCS_ENA_CHAN_0 | - WM8993_DCS_ENA_CHAN_1 | - WM8993_DCS_TRIG_STARTUP_1 | - WM8993_DCS_TRIG_STARTUP_0, + 0xFFFF, WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1 | WM8993_DCS_TRIG_STARTUP_1 | WM8993_DCS_TRIG_STARTUP_0); wait_for_dc_servo(codec); - snd_soc_update_bits(codec, WM8993_DC_SERVO_1, - WM8993_DCS_TIMER_PERIOD_01_MASK, 0xa); reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; @@ -298,11 +293,8 @@ static int hp_event(struct snd_soc_dapm_widget *w, WM8993_HPOUT1R_DLY | WM8993_HPOUT1R_OUTP); - snd_soc_update_bits(codec, WM8993_DC_SERVO_1, - WM8993_DCS_TIMER_PERIOD_01_MASK, 0); snd_soc_update_bits(codec, WM8993_DC_SERVO_0, - WM8993_DCS_ENA_CHAN_0 | - WM8993_DCS_ENA_CHAN_1, 0); + 0xffff, 0); snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, -- cgit v0.10.2 From cd6feeeafddbef6abfe4d90fb26e42fd844d34ed Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 2 Sep 2009 20:20:38 +0200 Subject: perf trace: Sample the CPU too Sample, record, parse and print the CPU field - it had all zeroes before. Before (watch the second column, the CPU values): perf-32685 [000] 0.000000: sched_wakeup_new: task perf:32686 [120] success=1 [011] perf-32685 [000] 0.000000: sched_migrate_task: task perf:32685 [120] from: 1 to: 11 perf-32685 [000] 0.000000: sched_process_fork: parent perf:32685 child perf:32686 true-32686 [000] 0.000000: sched_wakeup: task migration/11:25 [0] success=1 [011] true-32686 [000] 0.000000: sched_wakeup: task distccd:12793 [125] success=1 [015] true-32686 [000] 0.000000: sched_wakeup: task distccd:12793 [125] success=1 [015] perf-32685 [000] 0.000000: sched_switch: task perf:32685 [120] (S) ==> swapper:0 [140] true-32686 [000] 0.000000: sched_switch: task perf:32686 [120] (R) ==> migration/11:25 [0] true-32686 [000] 0.000000: sched_switch: task perf:32686 [120] (R) ==> distccd:12793 [125] true-32686 [000] 0.000000: sched_switch: task true:32686 [120] (R) ==> distccd:12793 [125] true-32686 [000] 0.000000: sched_process_exit: task true:32686 [120] true-32686 [000] 0.000000: sched_stat_wait: task: distccd:12793 wait: 6767985949080 [ns] true-32686 [000] 0.000000: sched_stat_wait: task: distccd:12793 wait: 6767986139446 [ns] true-32686 [000] 0.000000: sched_stat_sleep: task: distccd:12793 sleep: 132844 [ns] true-32686 [000] 0.000000: sched_stat_sleep: task: distccd:12793 sleep: 131724 [ns] After: perf-32685 [001] 0.000000: sched_wakeup_new: task perf:32686 [120] success=1 [011] perf-32685 [001] 0.000000: sched_migrate_task: task perf:32685 [120] from: 1 to: 11 perf-32685 [001] 0.000000: sched_process_fork: parent perf:32685 child perf:32686 true-32686 [011] 0.000000: sched_wakeup: task migration/11:25 [0] success=1 [011] true-32686 [015] 0.000000: sched_wakeup: task distccd:12793 [125] success=1 [015] true-32686 [015] 0.000000: sched_wakeup: task distccd:12793 [125] success=1 [015] perf-32685 [001] 0.000000: sched_switch: task perf:32685 [120] (S) ==> swapper:0 [140] true-32686 [011] 0.000000: sched_switch: task perf:32686 [120] (R) ==> migration/11:25 [0] true-32686 [015] 0.000000: sched_switch: task perf:32686 [120] (R) ==> distccd:12793 [125] true-32686 [015] 0.000000: sched_switch: task true:32686 [120] (R) ==> distccd:12793 [125] true-32686 [015] 0.000000: sched_process_exit: task true:32686 [120] true-32686 [015] 0.000000: sched_stat_wait: task: distccd:12793 wait: 6767985949080 [ns] true-32686 [015] 0.000000: sched_stat_wait: task: distccd:12793 wait: 6767986139446 [ns] true-32686 [015] 0.000000: sched_stat_sleep: task: distccd:12793 sleep: 132844 [ns] true-32686 [015] 0.000000: sched_stat_sleep: task: distccd:12793 sleep: 131724 [ns] So we can now see how this workload migrated between CPUs. Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker Cc: Li Zefan Cc: Mike Galbraith Cc: Arnaldo Carvalho de Melo LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index add514d..ff93f8e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -403,8 +403,10 @@ static void create_counter(int counter, int cpu, pid_t pid) if (call_graph) attr->sample_type |= PERF_SAMPLE_CALLCHAIN; - if (raw_samples) + if (raw_samples) { attr->sample_type |= PERF_SAMPLE_RAW; + attr->sample_type |= PERF_SAMPLE_CPU; + } attr->mmap = track; attr->comm = track; diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8247fd0..bbe4c44 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -58,12 +58,19 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) struct dso *dso = NULL; struct thread *thread; u64 ip = event->ip.ip; + u32 cpu = -1; u64 period = 1; void *more_data = event->ip.__more_data; int cpumode; thread = threads__findnew(event->ip.pid, &threads, &last_match); + if (sample_type & PERF_SAMPLE_CPU) { + cpu = *(u32 *)more_data; + more_data += sizeof(u32); + more_data += sizeof(u32); /* reserved */ + } + if (sample_type & PERF_SAMPLE_PERIOD) { period = *(u64 *)more_data; more_data += sizeof(u64); @@ -120,7 +127,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) * field, although it should be the same than this perf * event pid */ - print_event(0, raw->data, raw->size, 0, thread->comm); + print_event(cpu, raw->data, raw->size, 0, thread->comm); } total += period; -- cgit v0.10.2 From 44175272ba5f08e842877ef230ff4ed21cf9ec39 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 1 Sep 2009 08:22:40 -0700 Subject: wireless: update top level wireless driver entry Change it to a menuconfig to give it some documentation, to refer users to our wireless wiki for extra resources and documentation. It seems our wiki is still obscure to some. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 623897f..a8871a8 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -2,8 +2,17 @@ # Wireless LAN device configuration # -menu "Wireless LAN" +menuconfig WLAN + bool "Wireless LAN" depends on !S390 + ---help--- + This section contains all the pre 802.11 and 802.11 wireless + device drivers. For a complete list of drivers and documentation + on them refer to the wireless wiki: + + http://wireless.kernel.org/en/users/Drivers + +if WLAN menuconfig WLAN_PRE80211 bool "Wireless LAN (pre-802.11)" @@ -505,4 +514,4 @@ source "drivers/net/wireless/orinoco/Kconfig" source "drivers/net/wireless/wl12xx/Kconfig" source "drivers/net/wireless/iwmc3200wifi/Kconfig" -endmenu +endif # WLAN -- cgit v0.10.2 From 253850c10d1f9af46f4870616ed29f38ed39fd15 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 1 Sep 2009 08:22:43 -0700 Subject: wireless: update reg debug kconfig entry Refer to the wireless wiki for more information. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index aea7e68..68c504f 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -40,6 +40,10 @@ config CFG80211_REG_DEBUG default n ---help--- You can enable this if you want to debug regulatory changes. + For more information on cfg80211 regulatory refer to the wireless + wiki: + + http://wireless.kernel.org/en/developers/Regulatory If unsure, say N. -- cgit v0.10.2 From abd8ea22c23c917f56fefcda8a4468fbc2247d7f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 1 Sep 2009 08:22:46 -0700 Subject: wireless: remove mac80211 rate selection extra menu We can just display this upon enabling mac80211 with an 'if MAC80211 != n' check. Cc: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 9db4ff8..4d5543a 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -13,8 +13,7 @@ config MAC80211 comment "CFG80211 needs to be enabled for MAC80211" depends on CFG80211=n -menu "Rate control algorithm selection" - depends on MAC80211 != n +if MAC80211 != n config MAC80211_RC_PID bool "PID controller based rate control algorithm" if EMBEDDED @@ -61,7 +60,7 @@ config MAC80211_RC_DEFAULT default "pid" if MAC80211_RC_DEFAULT_PID default "" -endmenu +endif config MAC80211_MESH bool "Enable mac80211 mesh networking (pre-802.11s) support" -- cgit v0.10.2 From fcc6cb0c13555e78c2d47257b6d1b5e59b0c419a Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 1 Sep 2009 18:12:11 -0400 Subject: cfg80211: fix looping soft lockup in find_ie() The find_ie() function uses a size_t for the len parameter, and directly uses len as a loop variable. If any received packets are malformed, it is possible for the decrease of len to overflow, and since the result is unsigned, the loop will not terminate. Change it to a signed int so the loop conditional works for negative values. This fixes the following soft lockup: [38573.102007] BUG: soft lockup - CPU#0 stuck for 61s! [phy0:2230] [38573.102007] Modules linked in: aes_i586 aes_generic fuse af_packet ipt_REJECT xt_tcpudp nf_conntrack_ipv4 nf_defrag_ipv4 xt_state iptable_filter ip_tables x_tables acpi_cpufreq binfmt_misc dm_mirror dm_region_hash dm_log dm_multipath dm_mod kvm_intel kvm uinput i915 arc4 ecb drm snd_hda_codec_idt ath5k snd_hda_intel hid_apple mac80211 usbhid appletouch snd_hda_codec snd_pcm ath cfg80211 snd_timer i2c_algo_bit ohci1394 video snd processor ieee1394 rfkill ehci_hcd sg sky2 backlight snd_page_alloc uhci_hcd joydev output ac thermal button battery sr_mod applesmc cdrom input_polldev evdev unix [last unloaded: scsi_wait_scan] [38573.102007] irq event stamp: 2547724535 [38573.102007] hardirqs last enabled at (2547724534): [] restore_all_notrace+0x0/0x18 [38573.102007] hardirqs last disabled at (2547724535): [] apic_timer_interrupt+0x28/0x34 [38573.102007] softirqs last enabled at (92950144): [] __do_softirq+0x108/0x210 [38573.102007] softirqs last disabled at (92950274): [] _spin_lock_bh+0x14/0x80 [38573.102007] [38573.102007] Pid: 2230, comm: phy0 Tainted: G W (2.6.31-rc7-wl #8) MacBook1,1 [38573.102007] EIP: 0060:[] EFLAGS: 00010292 CPU: 0 [38573.102007] EIP is at cmp_ies+0x30/0x180 [cfg80211] [38573.102007] EAX: 00000082 EBX: 00000000 ECX: ffffffc1 EDX: d8efd014 [38573.102007] ESI: ffffff7c EDI: 0000004d EBP: eee2dc50 ESP: eee2dc3c [38573.102007] DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 [38573.102007] CR0: 8005003b CR2: d8efd014 CR3: 01694000 CR4: 000026d0 [38573.102007] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 [38573.102007] DR6: ffff0ff0 DR7: 00000400 [38573.102007] Call Trace: [38573.102007] [] cmp_bss+0xed/0x100 [cfg80211] [38573.102007] [] cfg80211_bss_update+0x84/0x410 [cfg80211] [38573.102007] [] cfg80211_inform_bss_frame+0x114/0x180 [cfg80211] [38573.102007] [] ieee80211_bss_info_update+0x4f/0x180 [mac80211] [38573.102007] [] ieee80211_rx_bss_info+0x88/0xf0 [mac80211] [38573.102007] [] ? ieee802_11_parse_elems+0x27/0x30 [mac80211] [38573.102007] [] ieee80211_rx_mgmt_probe_resp+0xa4/0x1c0 [mac80211] [38573.102007] [] ieee80211_sta_rx_queued_mgmt+0x919/0xc50 [mac80211] [38573.102007] [] ? sched_clock+0x27/0xa0 [38573.102007] [] ? sched_clock+0x27/0xa0 [38573.102007] [] ? mark_held_locks+0x60/0x80 [38573.102007] [] ? _spin_unlock_irqrestore+0x55/0x70 [38573.102007] [] ? sub_preempt_count+0x85/0xc0 [38573.102007] [] ? _spin_unlock_irqrestore+0x3e/0x70 [38573.102007] [] ? skb_dequeue+0x4f/0x70 [38573.102007] [] ieee80211_sta_work+0x91/0xb80 [mac80211] [38573.102007] [] ? sched_clock+0x27/0xa0 [38573.102007] [] ? sub_preempt_count+0x85/0xc0 [38573.102007] [] worker_thread+0x18f/0x320 [38573.102007] [] ? worker_thread+0x12e/0x320 [38573.102007] [] ? _spin_unlock_irqrestore+0x55/0x70 [38573.102007] [] ? ieee80211_sta_work+0x0/0xb80 [mac80211] [38573.102007] [] ? autoremove_wake_function+0x0/0x50 [38573.102007] [] ? worker_thread+0x0/0x320 [38573.102007] [] kthread+0x84/0x90 [38573.102007] [] ? kthread+0x0/0x90 [38573.102007] [] kernel_thread_helper+0x7/0x10 Cc: stable@kernel.org Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 7043de6..19c5a9a 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -141,7 +141,7 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) dev->bss_generation++; } -static u8 *find_ie(u8 num, u8 *ies, size_t len) +static u8 *find_ie(u8 num, u8 *ies, int len) { while (len > 2 && ies[0] != num) { len -= ies[1] + 2; -- cgit v0.10.2 From d0bec34293bb0b8dddc26d25bd46a6631d6b3ec3 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Wed, 2 Sep 2009 15:50:55 +0530 Subject: ath9k: Reconfigure beacon timers after the scan is completed. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index efee193..c2efdf2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2773,6 +2773,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) sc->sc_flags &= ~SC_OP_SCANNING; sc->sc_flags |= SC_OP_FULL_RESET; spin_unlock_bh(&sc->ani_lock); + ath_beacon_config(sc, NULL); mutex_unlock(&sc->mutex); } -- cgit v0.10.2 From 0fbdea19e9394a5cb5f2f5081b028c50b558910a Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 2 Sep 2009 21:46:00 +0200 Subject: perf_counter: Introduce new (non-)paranoia level to allow raw tracepoint access I want to sample inherited tracepoint workloads as a normal user and the CAP_SYS_ADMIN check prevents me from doing that right now. Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index d988dfb4..0aa609f 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -46,12 +46,18 @@ static atomic_t nr_task_counters __read_mostly; /* * perf counter paranoia level: - * 0 - not paranoid - * 1 - disallow cpu counters to unpriv - * 2 - disallow kernel profiling to unpriv + * -1 - not paranoid at all + * 0 - disallow raw tracepoint access for unpriv + * 1 - disallow cpu counters for unpriv + * 2 - disallow kernel profiling for unpriv */ int sysctl_perf_counter_paranoid __read_mostly = 1; +static inline bool perf_paranoid_tracepoint_raw(void) +{ + return sysctl_perf_counter_paranoid > -1; +} + static inline bool perf_paranoid_cpu(void) { return sysctl_perf_counter_paranoid > 0; @@ -3971,6 +3977,7 @@ static const struct pmu *tp_perf_counter_init(struct perf_counter *counter) * have these. */ if ((counter->attr.sample_type & PERF_SAMPLE_RAW) && + perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) return ERR_PTR(-EPERM); -- cgit v0.10.2 From 5848cc096a23b80b3d15c27d72299f79caf7c517 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 2 Sep 2009 14:37:45 -0700 Subject: net: drop_monitor: make last_rx timestamp private It was recently pointed out to me that the last_rx field of the net_device structure wasn't updated regularly. In fact only the bonding driver really uses it currently. Since the drop_monitor code relies on the last_rx field to detect drops on recevie in hardware, We need to find a more reliable way to rate limit our drop checks (so that we don't check for drops on every frame recevied, which would be inefficient. This patch makes a last_rx timestamp that is private to the drop monitor code and is updated for every device that we track. Signed-off-by: Neil Horman Signed-off-by: David S. Miller diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index d311202..0a113f2 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -52,6 +52,7 @@ struct per_cpu_dm_data { struct dm_hw_stat_delta { struct net_device *dev; + unsigned long last_rx; struct list_head list; struct rcu_head rcu; unsigned long last_drop_val; @@ -180,18 +181,25 @@ static void trace_napi_poll_hit(struct napi_struct *napi) struct dm_hw_stat_delta *new_stat; /* - * Ratelimit our check time to dm_hw_check_delta jiffies + * Don't check napi structures with no associated device */ - if (!napi->dev || - !time_after(jiffies, napi->dev->last_rx + dm_hw_check_delta)) + if (!napi->dev) return; rcu_read_lock(); list_for_each_entry_rcu(new_stat, &hw_stats_list, list) { + /* + * only add a note to our monitor buffer if: + * 1) this is the dev we received on + * 2) its after the last_rx delta + * 3) our rx_dropped count has gone up + */ if ((new_stat->dev == napi->dev) && + (time_after(jiffies, new_stat->last_rx + dm_hw_check_delta)) && (napi->dev->stats.rx_dropped != new_stat->last_drop_val)) { trace_drop_common(NULL, NULL); new_stat->last_drop_val = napi->dev->stats.rx_dropped; + new_stat->last_rx = jiffies; break; } } @@ -287,6 +295,7 @@ static int dropmon_net_event(struct notifier_block *ev_block, goto out; new_stat->dev = dev; + new_stat->last_rx = jiffies; INIT_RCU_HEAD(&new_stat->rcu); spin_lock(&trace_state_lock); list_add_rcu(&new_stat->list, &hw_stats_list); -- cgit v0.10.2 From 2e59af3dcbdf11635c03f22bfc9706744465d589 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Sep 2009 18:03:00 -0700 Subject: vlan: multiqueue vlan device vlan devices are currently not multi-queue capable. We can do that with a new rtnl_link_ops method, get_tx_queues(), called from rtnl_create_link() This new method gets num_tx_queues/real_num_tx_queues from real device. register_vlan_device() is also handled. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 3c1895e..b630196 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -70,6 +70,9 @@ struct rtnl_link_ops { size_t (*get_xstats_size)(const struct net_device *dev); int (*fill_xstats)(struct sk_buff *skb, const struct net_device *dev); + int (*get_tx_queues)(struct net *net, struct nlattr *tb[], + unsigned int *tx_queues, + unsigned int *real_tx_queues); }; extern int __rtnl_link_register(struct rtnl_link_ops *ops); diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index e814794..8836575 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -330,12 +330,13 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) snprintf(name, IFNAMSIZ, "vlan%.4i", vlan_id); } - new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name, - vlan_setup); + new_dev = alloc_netdev_mq(sizeof(struct vlan_dev_info), name, + vlan_setup, real_dev->num_tx_queues); if (new_dev == NULL) return -ENOBUFS; + new_dev->real_num_tx_queues = real_dev->real_num_tx_queues; dev_net_set(new_dev, net); /* need 4 bytes for extra VLAN header info, * hope the underlying device can handle it. diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index e9c91dc..343146e 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -100,6 +100,25 @@ static int vlan_changelink(struct net_device *dev, return 0; } +static int vlan_get_tx_queues(struct net *net, + struct nlattr *tb[], + unsigned int *num_tx_queues, + unsigned int *real_num_tx_queues) +{ + struct net_device *real_dev; + + if (!tb[IFLA_LINK]) + return -EINVAL; + + real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK])); + if (!real_dev) + return -ENODEV; + + *num_tx_queues = real_dev->num_tx_queues; + *real_num_tx_queues = real_dev->real_num_tx_queues; + return 0; +} + static int vlan_newlink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { @@ -216,6 +235,7 @@ struct rtnl_link_ops vlan_link_ops __read_mostly = { .maxtype = IFLA_VLAN_MAX, .policy = vlan_policy, .priv_size = sizeof(struct vlan_dev_info), + .get_tx_queues = vlan_get_tx_queues, .setup = vlan_setup, .validate = vlan_validate, .newlink = vlan_newlink, diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index b44775f..bbcba2a 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -974,12 +974,20 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, { int err; struct net_device *dev; + unsigned int num_queues = 1; + unsigned int real_num_queues = 1; + if (ops->get_tx_queues) { + err = ops->get_tx_queues(net, tb, &num_queues, &real_num_queues); + if (err) + goto err; + } err = -ENOMEM; - dev = alloc_netdev(ops->priv_size, ifname, ops->setup); + dev = alloc_netdev_mq(ops->priv_size, ifname, ops->setup, num_queues); if (!dev) goto err; + dev->real_num_tx_queues = real_num_queues; if (strchr(dev->name, '%')) { err = dev_alloc_name(dev, dev->name); if (err < 0) -- cgit v0.10.2 From 6ce9e7b5fe3195d1ae6e3a0753d4ddcac5cd699e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Sep 2009 18:05:33 -0700 Subject: ip: Report qdisc packet drops Christoph Lameter pointed out that packet drops at qdisc level where not accounted in SNMP counters. Only if application sets IP_RECVERR, drops are reported to user (-ENOBUFS errors) and SNMP counters updated. IP_RECVERR is used to enable extended reliable error message passing, but these are not needed to update system wide SNMP stats. This patch changes things a bit to allow SNMP counters to be updated, regardless of IP_RECVERR being set or not on the socket. Example after an UDP tx flood # netstat -s ... IP: 1487048 outgoing packets dropped ... Udp: ... SndbufErrors: 1487048 send() syscalls, do however still return an OK status, to not break applications. Note : send() manual page explicitly says for -ENOBUFS error : "The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion. (Normally, this does not occur in Linux. Packets are just silently dropped when a device queue overflows.) " This is not true for IP_RECVERR enabled sockets : a send() syscall that hit a qdisc drop returns an ENOBUFS error. Many thanks to Christoph, David, and last but not least, Alexey ! Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 7d08210..afae0cb 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1302,7 +1302,7 @@ int ip_push_pending_frames(struct sock *sk) err = ip_local_out(skb); if (err) { if (err > 0) - err = inet->recverr ? net_xmit_errno(err) : 0; + err = net_xmit_errno(err); if (err) goto error; } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 2979f14..ebb1e58 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -375,7 +375,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, err = NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); if (err > 0) - err = inet->recverr ? net_xmit_errno(err) : 0; + err = net_xmit_errno(err); if (err) goto error; out: @@ -386,6 +386,8 @@ error_fault: kfree_skb(skb); error: IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); + if (err == -ENOBUFS && !inet->recverr) + err = 0; return err; } @@ -576,8 +578,11 @@ back_from_confirm: &ipc, &rt, msg->msg_flags); if (err) ip_flush_pending_frames(sk); - else if (!(msg->msg_flags & MSG_MORE)) + else if (!(msg->msg_flags & MSG_MORE)) { err = ip_push_pending_frames(sk); + if (err == -ENOBUFS && !inet->recverr) + err = 0; + } release_sock(sk); } done: diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 29ebb0d..ebaaa7f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -561,12 +561,18 @@ static int udp_push_pending_frames(struct sock *sk) send: err = ip_push_pending_frames(sk); + if (err) { + if (err == -ENOBUFS && !inet->recverr) { + UDP_INC_STATS_USER(sock_net(sk), + UDP_MIB_SNDBUFERRORS, is_udplite); + err = 0; + } + } else + UDP_INC_STATS_USER(sock_net(sk), + UDP_MIB_OUTDATAGRAMS, is_udplite); out: up->len = 0; up->pending = 0; - if (!err) - UDP_INC_STATS_USER(sock_net(sk), - UDP_MIB_OUTDATAGRAMS, is_udplite); return err; } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index a931229..cd48801 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1511,7 +1511,7 @@ int ip6_push_pending_frames(struct sock *sk) err = ip6_local_out(skb); if (err) { if (err > 0) - err = np->recverr ? net_xmit_errno(err) : 0; + err = net_xmit_errno(err); if (err) goto error; } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 5068410..7d675b8 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -642,7 +642,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); if (err > 0) - err = np->recverr ? net_xmit_errno(err) : 0; + err = net_xmit_errno(err); if (err) goto error; out: @@ -653,6 +653,8 @@ error_fault: kfree_skb(skb); error: IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); + if (err == -ENOBUFS && !np->recverr) + err = 0; return err; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 20d2ffc..1640406 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -724,12 +724,18 @@ static int udp_v6_push_pending_frames(struct sock *sk) send: err = ip6_push_pending_frames(sk); + if (err) { + if (err == -ENOBUFS && !inet6_sk(sk)->recverr) { + UDP6_INC_STATS_USER(sock_net(sk), + UDP_MIB_SNDBUFERRORS, is_udplite); + err = 0; + } + } else + UDP6_INC_STATS_USER(sock_net(sk), + UDP_MIB_OUTDATAGRAMS, is_udplite); out: up->len = 0; up->pending = 0; - if (!err) - UDP6_INC_STATS_USER(sock_net(sk), - UDP_MIB_OUTDATAGRAMS, is_udplite); return err; } -- cgit v0.10.2 From 6c1488fd581a447ec87c4b59f0d33f95f0aa441b Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 2 Sep 2009 11:40:32 -0400 Subject: IMA: open new file for read When creating a new file, ima_path_check() assumed the new file was being opened for write. Call ima_path_check() with the appropriate acc_mode so that the read/write counters are incremented correctly. Signed-off-by: Mimi Zohar Signed-off-by: James Morris diff --git a/fs/namei.c b/fs/namei.c index f3c5b27..ee01308 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1533,9 +1533,11 @@ int may_open(struct path *path, int acc_mode, int flag) if (error) return error; - error = ima_path_check(path, - acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC), + error = ima_path_check(path, acc_mode ? + acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) : + ACC_MODE(flag) & (MAY_READ | MAY_WRITE), IMA_COUNT_UPDATE); + if (error) return error; /* -- cgit v0.10.2 From 451f14439847db302e5104c44458b2dbb4b1829d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 31 Aug 2009 06:34:50 +0000 Subject: drivers: Kill now superfluous ->last_rx stores The generic packet receive code takes care of setting netdev->last_rx when necessary, for the sake of the bonding ARP monitor. Signed-off-by: Eric Dumazet Acked-by: Neil Horman Signed-off-by: David S. Miller diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 84edc8b..cbaf420 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -663,8 +663,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, if (netif_queue_stopped(net)) netif_wake_queue(net); - net->last_rx = jiffies; - return 0; } diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 3a62c4c..a4e9dcb 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -1301,7 +1301,6 @@ static void ether1394_iso(struct hpsb_iso *iso) hpsb_iso_recv_release_packets(iso, i); - dev->last_rx = jiffies; } /****************************************** diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c index 0cfbb6d..8c5d284 100644 --- a/drivers/infiniband/hw/amso1100/c2.c +++ b/drivers/infiniband/hw/amso1100/c2.c @@ -530,7 +530,6 @@ static void c2_rx_interrupt(struct net_device *netdev) netif_rx(skb); - netdev->last_rx = jiffies; netdev->stats.rx_packets++; netdev->stats.rx_bytes += buflen; } diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 4a84d02..97d4c2a 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2741,7 +2741,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) } skip_rx_indicate0: - nesvnic->netdev->last_rx = jiffies; + ; /* nesvnic->netstats.rx_packets++; */ /* nesvnic->netstats.rx_bytes += rx_pkt_size; */ } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 181b1f3..986f07f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -663,7 +663,6 @@ copied: skb_reset_mac_header(skb); skb_pull(skb, IPOIB_ENCAP_LEN); - dev->last_rx = jiffies; ++dev->stats.rx_packets; dev->stats.rx_bytes += skb->len; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index e7e5adf..c9dcb20 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -277,7 +277,6 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) skb_reset_mac_header(skb); skb_pull(skb, IPOIB_ENCAP_LEN); - dev->last_rx = jiffies; ++dev->stats.rx_packets; dev->stats.rx_bytes += skb->len; diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 212da9a..16f0abd 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -240,7 +240,6 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) (void *)skb->head, (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->len); - xpnet_device->last_rx = jiffies; xpnet_device->stats.rx_packets++; xpnet_device->stats.rx_bytes += skb->len + ETH_HLEN; diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index 4f702d5..2a7b774 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -467,7 +467,6 @@ ks8695_rx_irq(int irq, void *dev_id) netif_rx(skb); /* Record stats */ - ndev->last_rx = jiffies; ndev->stats.rx_packets++; ndev->stats.rx_bytes += pktlen; goto rx_finished; diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c index 3a0948f..25e2627 100644 --- a/drivers/net/arm/w90p910_ether.c +++ b/drivers/net/arm/w90p910_ether.c @@ -777,7 +777,6 @@ static void netdev_rx(struct net_device *dev) rxbd = ðer->rdesc->desclist[ether->cur_rx]; - dev->last_rx = jiffies; } while (1); } diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index bf7cc83..e46bf92 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -1740,7 +1740,6 @@ rrs_checked: } else netif_receive_skb(skb); - netdev->last_rx = jiffies; (*work_done)++; count++; } diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index e19fe1d..bac85f9 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -775,8 +775,6 @@ static void be_rx_compl_process(struct be_adapter *adapter, netif_receive_skb(skb); } - adapter->netdev->last_rx = jiffies; - return; } diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index e1a4f82..1d29082 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -357,7 +357,6 @@ void can_restart(unsigned long data) netif_rx(skb); - dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += cf->can_dlc; diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 9ce3dda..fd7fa71 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -340,7 +340,6 @@ static void sja1000_rx(struct net_device *dev) netif_rx(skb); - dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += dlc; } @@ -455,7 +454,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) netif_rx(skb); - dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += cf->can_dlc; diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 5e6652b..d465eaa 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -1920,7 +1920,6 @@ static int emac_net_rx_cb(struct emac_priv *priv, skb_put(p_skb, net_pkt_list->pkt_length); EMAC_CACHE_INVALIDATE((unsigned long)p_skb->data, p_skb->len); p_skb->protocol = eth_type_trans(p_skb, priv->ndev); - p_skb->dev->last_rx = jiffies; netif_receive_skb(p_skb); priv->net_dev_stats.rx_bytes += net_pkt_list->pkt_length; priv->net_dev_stats.rx_packets++; diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index b871aef..b7311bc 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -404,7 +404,6 @@ static int ethoc_rx(struct net_device *dev, int limit) void *src = priv->membase + bd.addr; memcpy_fromio(skb_put(skb, size), src, size); skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; priv->stats.rx_packets++; priv->stats.rx_bytes += size; netif_receive_skb(skb); diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index dadb782..91024a3 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -96,8 +96,6 @@ static void igbvf_receive_skb(struct igbvf_adapter *adapter, E1000_RXD_SPC_VLAN_MASK); else netif_receive_skb(skb); - - netdev->last_rx = jiffies; } static inline void igbvf_rx_checksum_adv(struct igbvf_adapter *adapter, @@ -342,8 +340,6 @@ send_up: igbvf_receive_skb(adapter, netdev, skb, staterr, rx_desc->wb.upper.vlan); - netdev->last_rx = jiffies; - next_desc: rx_desc->wb.upper.status_error = 0; diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index c266785..ccdd196 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -1047,7 +1047,6 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) /* Update counters */ dev->stats.rx_packets++; dev->stats.rx_bytes += (pktlength - 4); - dev->last_rx = jiffies; } /* Return total received packets */ diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index 514311d..b4909a2 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -817,7 +817,6 @@ static void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index, skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; } static int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index) diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 41dccba..b378037 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -588,8 +588,6 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, if (first_dtr) vxge_hw_ring_rxd_post_post_wmb(ringh, first_dtr); - dev->last_rx = jiffies; - vxge_debug_entryexit(VXGE_TRACE, "%s:%d Exiting...", __func__, __LINE__); diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index f79cee8..103f3c9 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -590,7 +590,6 @@ void b43legacy_rx(struct b43legacy_wldev *dev, chanstat); } - dev->stats.last_rx = jiffies; memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); ieee80211_rx_irqsafe(dev->wl->hw, skb); diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index 7e05b40..dc22782 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -587,7 +587,6 @@ static void xemaclite_rx_handler(struct net_device *dev) dev->stats.rx_packets++; dev->stats.rx_bytes += len; - dev->last_rx = jiffies; netif_rx(skb); /* Send the packet upstream */ } diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 38b5079..c5b8387 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -164,7 +164,6 @@ void ctcm_unpack_skb(struct channel *ch, struct sk_buff *pskb) priv->stats.rx_packets++; priv->stats.rx_bytes += skblen; netif_rx_ni(skb); - dev->last_rx = jiffies; if (len > 0) { skb_pull(pskb, header->length); if (skb_tailroom(pskb) < LL_HEADER_LENGTH) { diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index bb1183a..271c4a8 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -676,7 +676,6 @@ static void netiucv_unpack_skb(struct iucv_connection *conn, * we must use netif_rx_ni() instead of netif_rx() */ netif_rx_ni(skb); - dev->last_rx = jiffies; skb_pull(pskb, header->next); skb_put(pskb, NETIUCV_HDRLEN); } diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 94b1611..f4f3ca1 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -449,7 +449,6 @@ static void qeth_l2_process_inbound_buffer(struct qeth_card *card, QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); continue; } - card->dev->last_rx = jiffies; card->stats.rx_packets++; card->stats.rx_bytes += len; } diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 115b4a0..073b6d3 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1987,7 +1987,6 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, continue; } - card->dev->last_rx = jiffies; card->stats.rx_packets++; card->stats.rx_bytes += len; } -- cgit v0.10.2 From 05c6a8d7a7d778f26d8eb821556988993b766092 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 2 Sep 2009 17:02:55 +0000 Subject: net/ethtool: Add support for the ethtool feature to flash firmware image from a specified file. This patch adds support to flash a firmware image to a device using ethtool. The driver gets the filename of the firmware image and flashes the image using the request firmware path. The region "on the chip" to be flashed can be specified by an option. It is upto the device driver to enumerate the region number passed by ethtool, to the region to be flashed. The default behavior is to flash all the regions on the chip. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 90c4a36..15e4eb7 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -362,6 +362,18 @@ struct ethtool_rxnfc { __u32 rule_locs[0]; }; +#define ETHTOOL_FLASH_MAX_FILENAME 128 +enum ethtool_flash_op_type { + ETHTOOL_FLASH_ALL_REGIONS = 0, +}; + +/* for passing firmware flashing related parameters */ +struct ethtool_flash { + __u32 cmd; + __u32 region; + char data[ETHTOOL_FLASH_MAX_FILENAME]; +}; + #ifdef __KERNEL__ struct net_device; @@ -489,6 +501,7 @@ struct ethtool_ops { int (*get_stats_count)(struct net_device *);/* use get_sset_count */ int (*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, void *); int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); + int (*flash_device)(struct net_device *, struct ethtool_flash *); }; #endif /* __KERNEL__ */ @@ -545,6 +558,7 @@ struct ethtool_ops { #define ETHTOOL_GRXCLSRLALL 0x00000030 /* Get all RX classification rule */ #define ETHTOOL_SRXCLSRLDEL 0x00000031 /* Delete RX classification rule */ #define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */ +#define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 44e5711..4c12ddb 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -898,6 +898,19 @@ static int ethtool_set_value(struct net_device *dev, char __user *useraddr, return actor(dev, edata.data); } +static int ethtool_flash_device(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_flash efl; + + if (copy_from_user(&efl, useraddr, sizeof(efl))) + return -EFAULT; + + if (!dev->ethtool_ops->flash_device) + return -EOPNOTSUPP; + + return dev->ethtool_ops->flash_device(dev, &efl); +} + /* The main entry point in this file. Called from net/core/dev.c */ int dev_ethtool(struct net *net, struct ifreq *ifr) @@ -1111,6 +1124,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_SGRO: rc = ethtool_set_gro(dev, useraddr); break; + case ETHTOOL_FLASHDEV: + rc = ethtool_flash_device(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } -- cgit v0.10.2 From aa1330766c49199bdab4d4a9096d98b072df9044 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 2 Sep 2009 23:45:45 -0700 Subject: tcp: replace hard coded GFP_KERNEL with sk_allocation This fixed a lockdep warning which appeared when doing stress memory tests over NFS: inconsistent {RECLAIM_FS-ON-W} -> {IN-RECLAIM_FS-W} usage. page reclaim => nfs_writepage => tcp_sendmsg => lock sk_lock mount_root => nfs_root_data => tcp_close => lock sk_lock => tcp_send_fin => alloc_skb_fclone => page reclaim David raised a concern that if the allocation fails in tcp_send_fin(), and it's GFP_ATOMIC, we are going to yield() (which sleeps) and loop endlessly waiting for the allocation to succeed. But fact is, the original GFP_KERNEL also sleeps. GFP_ATOMIC+yield() looks weird, but it is no worse the implicit sleep inside GFP_KERNEL. Both could loop endlessly under memory pressure. CC: Arnaldo Carvalho de Melo CC: David S. Miller CC: Herbert Xu Signed-off-by: Wu Fengguang Signed-off-by: David S. Miller diff --git a/include/net/tcp.h b/include/net/tcp.h index df50bc4..b71a446 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1186,7 +1186,7 @@ extern int tcp_v4_md5_do_del(struct sock *sk, #define tcp_twsk_md5_key(twsk) NULL #endif -extern struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void); +extern struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(struct sock *); extern void tcp_free_md5sig_pool(void); extern struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 59f69a6..edeea06 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1839,7 +1839,7 @@ void tcp_close(struct sock *sk, long timeout) /* Unread data was tossed, zap the connection. */ NET_INC_STATS_USER(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE); tcp_set_state(sk, TCP_CLOSE); - tcp_send_active_reset(sk, GFP_KERNEL); + tcp_send_active_reset(sk, sk->sk_allocation); } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { /* Check zero linger _after_ checking for unread data. */ sk->sk_prot->disconnect(sk, 0); @@ -2658,7 +2658,7 @@ void tcp_free_md5sig_pool(void) EXPORT_SYMBOL(tcp_free_md5sig_pool); -static struct tcp_md5sig_pool **__tcp_alloc_md5sig_pool(void) +static struct tcp_md5sig_pool **__tcp_alloc_md5sig_pool(struct sock *sk) { int cpu; struct tcp_md5sig_pool **pool; @@ -2671,7 +2671,7 @@ static struct tcp_md5sig_pool **__tcp_alloc_md5sig_pool(void) struct tcp_md5sig_pool *p; struct crypto_hash *hash; - p = kzalloc(sizeof(*p), GFP_KERNEL); + p = kzalloc(sizeof(*p), sk->sk_allocation); if (!p) goto out_free; *per_cpu_ptr(pool, cpu) = p; @@ -2688,7 +2688,7 @@ out_free: return NULL; } -struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void) +struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(struct sock *sk) { struct tcp_md5sig_pool **pool; int alloc = 0; @@ -2709,7 +2709,7 @@ retry: if (alloc) { /* we cannot hold spinlock here because this may sleep. */ - struct tcp_md5sig_pool **p = __tcp_alloc_md5sig_pool(); + struct tcp_md5sig_pool **p = __tcp_alloc_md5sig_pool(sk); spin_lock_bh(&tcp_md5sig_pool_lock); if (!p) { tcp_md5sig_users--; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ce7d3b0..0543561 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -886,7 +886,7 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, } sk->sk_route_caps &= ~NETIF_F_GSO_MASK; } - if (tcp_alloc_md5sig_pool() == NULL) { + if (tcp_alloc_md5sig_pool(sk) == NULL) { kfree(newkey); return -ENOMEM; } @@ -1007,8 +1007,9 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, if (!tcp_sk(sk)->md5sig_info) { struct tcp_sock *tp = tcp_sk(sk); - struct tcp_md5sig_info *p = kzalloc(sizeof(*p), GFP_KERNEL); + struct tcp_md5sig_info *p; + p = kzalloc(sizeof(*p), sk->sk_allocation); if (!p) return -EINVAL; @@ -1016,7 +1017,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, sk->sk_route_caps &= ~NETIF_F_GSO_MASK; } - newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); + newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, sk->sk_allocation); if (!newkey) return -ENOMEM; return tcp_v4_md5_do_add(sk, sin->sin_addr.s_addr, diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 6c8b422..e48c37d 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -322,7 +322,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) if (key != NULL) { memcpy(&tcptw->tw_md5_key, key->key, key->keylen); tcptw->tw_md5_keylen = key->keylen; - if (tcp_alloc_md5sig_pool() == NULL) + if (tcp_alloc_md5sig_pool(sk) == NULL) BUG(); } } while (0); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 4e00442..5200aab 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2135,7 +2135,8 @@ void tcp_send_fin(struct sock *sk) } else { /* Socket is locked, keep trying until memory is available. */ for (;;) { - skb = alloc_skb_fclone(MAX_TCP_HEADER, GFP_KERNEL); + skb = alloc_skb_fclone(MAX_TCP_HEADER, + sk->sk_allocation); if (skb) break; yield(); @@ -2388,7 +2389,7 @@ int tcp_connect(struct sock *sk) sk->sk_wmem_queued += buff->truesize; sk_mem_charge(sk, buff->truesize); tp->packets_out += tcp_skb_pcount(buff); - tcp_transmit_skb(sk, buff, 1, GFP_KERNEL); + tcp_transmit_skb(sk, buff, 1, sk->sk_allocation); /* We change tp->snd_nxt after the tcp_transmit_skb() call * in order to make this packet get counted in tcpOutSegs. diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index d73617e..65aecf2 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -591,7 +591,7 @@ static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer, } sk->sk_route_caps &= ~NETIF_F_GSO_MASK; } - if (tcp_alloc_md5sig_pool() == NULL) { + if (tcp_alloc_md5sig_pool(sk) == NULL) { kfree(newkey); return -ENOMEM; } -- cgit v0.10.2 From ab08999d6029bb2c79c16be5405d63d2bedbdfea Mon Sep 17 00:00:00 2001 From: roel kluin Date: Tue, 1 Sep 2009 06:24:53 +0000 Subject: WARNING: some request_irq() failures ignored in el2_open() Request_irq() may fail in different ways, handle accordingly. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 134638a..81c148a 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -383,7 +383,7 @@ out: static int el2_open(struct net_device *dev) { - int retval = -EAGAIN; + int retval; if (dev->irq < 2) { int irqlist[] = {5, 9, 3, 4, 0}; @@ -391,7 +391,8 @@ el2_open(struct net_device *dev) outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM and interrupts. */ do { - if (request_irq (*irqp, NULL, 0, "bogus", dev) != -EBUSY) { + retval = request_irq(*irqp, NULL, 0, "bogus", dev); + if (retval >= 0) { /* Twinkle the interrupt, and check if it's seen. */ unsigned long cookie = probe_irq_on(); outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR); @@ -400,11 +401,14 @@ el2_open(struct net_device *dev) && ((retval = request_irq(dev->irq = *irqp, eip_interrupt, 0, dev->name, dev)) == 0)) break; + } else { + if (retval != -EBUSY) + return reval; } } while (*++irqp); if (*irqp == 0) { outb(EGACFR_IRQOFF, E33G_GACFR); /* disable interrupts. */ - return retval; + return -EAGAIN; } } else { if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) { -- cgit v0.10.2 From 3eb0027594e25f5947f074ae53fea30c15c5a7f6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 2 Sep 2009 23:09:29 -0700 Subject: NET: Fix possible corruption in bpqether driver The bpq ether driver is modifying the data art of the skb by first dropping the KISS byte (a command byte for the radio) then prepending the length + 4 of the remaining AX.25 packet to be transmitted as a little endian 16-bit number. If the high byte of the length has a different value than the dropped KISS byte users of clones of the skb may observe this as corruption. This was observed with by running listen(8) -a which uses a packet socket which clones transmit packets. The corruption will then typically be displayed for as a KISS "TX Delay" command for AX.25 packets in the range of 252..508 bytes or any other KISS command for yet larger packets. Fixed by using skb_cow to create a private copy should the skb be cloned. Using skb_cow also allows us to cleanup the old logic to ensure sufficient headroom in the skb. While at it, replace a return of 0 from bpq_xmit with the proper constant NETDEV_TX_OK which is now being used everywhere else in this function. Affected: all 2.2, 2.4 and 2.6 kernels. Signed-off-by: Ralf Baechle Reported-by: Jann Traschewski Signed-off-by: David S. Miller diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 3c7cc7f..fe893c9 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -249,7 +249,6 @@ drop: */ static netdev_tx_t bpq_xmit(struct sk_buff *skb, struct net_device *dev) { - struct sk_buff *newskb; unsigned char *ptr; struct bpqdev *bpq; int size; @@ -263,28 +262,23 @@ static netdev_tx_t bpq_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - skb_pull(skb, 1); + skb_pull(skb, 1); /* Drop KISS byte */ size = skb->len; /* - * The AX.25 code leaves enough room for the ethernet header, but - * sendto() does not. + * We're about to mess with the skb which may still shared with the + * generic networking code so unshare and ensure it's got enough + * space for the BPQ headers. */ - if (skb_headroom(skb) < AX25_BPQ_HEADER_LEN) { /* Ough! */ - if ((newskb = skb_realloc_headroom(skb, AX25_BPQ_HEADER_LEN)) == NULL) { - printk(KERN_WARNING "bpqether: out of memory\n"); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - if (skb->sk != NULL) - skb_set_owner_w(newskb, skb->sk); - + if (skb_cow(skb, AX25_BPQ_HEADER_LEN)) { + if (net_ratelimit()) + pr_err("bpqether: out of memory\n"); kfree_skb(skb); - skb = newskb; + + return NETDEV_TX_OK; } - ptr = skb_push(skb, 2); + ptr = skb_push(skb, 2); /* Make space for length */ *ptr++ = (size + 5) % 256; *ptr++ = (size + 5) / 256; -- cgit v0.10.2 From 84177a20799072c65a69b62571660d4d9780823c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 1 Sep 2009 23:14:15 +0000 Subject: fec: fix recursive locking of mii_lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mii_discover_phy is only called by fec_enet_mii (via mip->mii_func). So &fep->mii_lock is already held and mii_discover_phy must not call mii_queue which locks &fep->mii_lock, too. This was noticed by lockdep: ============================================= [ INFO: possible recursive locking detected ] 2.6.31-rc8-00038-g37d0892 #109 --------------------------------------------- swapper/1 is trying to acquire lock: (&fep->mii_lock){-.....}, at: [] mii_queue+0x2c/0xcc but task is already holding lock: (&fep->mii_lock){-.....}, at: [] fec_enet_interrupt+0x78/0x460 other info that might help us debug this: 2 locks held by swapper/1: #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x18/0x20 #1: (&fep->mii_lock){-.....}, at: [] fec_enet_interrupt+0x78/0x460 stack backtrace: Backtrace: [] (dump_backtrace+0x0/0x108) from [] (dump_stack+0x18/0x1c) r6:c781d118 r5:c03e41d8 r4:00000001 [] (dump_stack+0x0/0x1c) from [] (__lock_acquire+0x1a20/0x1a88) [] (__lock_acquire+0x0/0x1a88) from [] (lock_acquire+0x60/0x74) [] (lock_acquire+0x0/0x74) from [] (_spin_lock_irqsave+0x54/0x68) r7:60000093 r6:c01569f8 r5:c785e468 r4:00000000 [] (_spin_lock_irqsave+0x0/0x68) from [] (mii_queue+0x2c/0xcc) r7:c785e468 r6:c0156b24 r5:600a0000 r4:c785e000 [] (mii_queue+0x0/0xcc) from [] (mii_discover_phy+0x54/0xa8) r8:00000002 r7:00000032 r6:c785e000 r5:c785e360 r4:c785e000 [] (mii_discover_phy+0x0/0xa8) from [] (fec_enet_interrupt+0xa4/0x460) r5:c785e360 r4:c077a170 [] (fec_enet_interrupt+0x0/0x460) from [] (handle_IRQ_event+0x48/0x120) [] (handle_IRQ_event+0x0/0x120) from [] (handle_level_irq+0x94/0x11c) ... Signed-off-by: Uwe Kleine-König Cc: Greg Ungerer Cc: Ben Hutchings Cc: Patrick McHardy Cc: Sascha Hauer Cc: Matt Waddel Cc: netdev@vger.kernel.org Cc: Tim Sander Acked-by: Greg Ungerer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 967ad01..e730da2 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -637,16 +637,15 @@ unlock: } static int -mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *)) +mii_queue_unlocked(struct net_device *dev, int regval, + void (*func)(uint, struct net_device *)) { struct fec_enet_private *fep; - unsigned long flags; mii_list_t *mip; int retval; /* Add PHY address to register command */ fep = netdev_priv(dev); - spin_lock_irqsave(&fep->mii_lock, flags); regval |= fep->phy_addr << 23; retval = 0; @@ -667,6 +666,19 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi retval = 1; } + return retval; +} + +static int +mii_queue(struct net_device *dev, int regval, + void (*func)(uint, struct net_device *)) +{ + struct fec_enet_private *fep; + unsigned long flags; + int retval; + fep = netdev_priv(dev); + spin_lock_irqsave(&fep->mii_lock, flags); + retval = mii_queue_unlocked(dev, regval, func); spin_unlock_irqrestore(&fep->mii_lock, flags); return retval; } @@ -1373,11 +1385,11 @@ mii_discover_phy(uint mii_reg, struct net_device *dev) /* Got first part of ID, now get remainder */ fep->phy_id = phytype << 16; - mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), + mii_queue_unlocked(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3); } else { fep->phy_addr++; - mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), + mii_queue_unlocked(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); } } else { -- cgit v0.10.2 From 81538e74ca12a71ea37ce72f809ebc65a90b9538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 1 Sep 2009 23:14:16 +0000 Subject: fec: don't enable irqs in hard irq context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fec_enet_mii, fec_enet_rx and fec_enet_tx are both only called by fec_enet_interrupt in interrupt context. So they must not use spin_lock_irq/spin_unlock_irq. This fixes: WARNING: at kernel/lockdep.c:2140 trace_hardirqs_on_caller+0x130/0x194() ... Signed-off-by: Uwe Kleine-König Cc: Greg Ungerer Cc: Ben Hutchings Cc: Patrick McHardy Cc: Sascha Hauer Cc: Matt Waddel Cc: netdev@vger.kernel.org Cc: Tim Sander Acked-by: Greg Ungerer Signed-off-by: David S. Miller diff --git a/drivers/net/fec.c b/drivers/net/fec.c index e730da2..b472018 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -427,7 +427,7 @@ fec_enet_tx(struct net_device *dev) struct sk_buff *skb; fep = netdev_priv(dev); - spin_lock_irq(&fep->hw_lock); + spin_lock(&fep->hw_lock); bdp = fep->dirty_tx; while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { @@ -486,7 +486,7 @@ fec_enet_tx(struct net_device *dev) } } fep->dirty_tx = bdp; - spin_unlock_irq(&fep->hw_lock); + spin_unlock(&fep->hw_lock); } @@ -509,7 +509,7 @@ fec_enet_rx(struct net_device *dev) flush_cache_all(); #endif - spin_lock_irq(&fep->hw_lock); + spin_lock(&fep->hw_lock); /* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. @@ -604,7 +604,7 @@ rx_processing_done: } fep->cur_rx = bdp; - spin_unlock_irq(&fep->hw_lock); + spin_unlock(&fep->hw_lock); } /* called from interrupt context */ @@ -615,7 +615,7 @@ fec_enet_mii(struct net_device *dev) mii_list_t *mip; fep = netdev_priv(dev); - spin_lock_irq(&fep->mii_lock); + spin_lock(&fep->mii_lock); if ((mip = mii_head) == NULL) { printk("MII and no head!\n"); @@ -633,7 +633,7 @@ fec_enet_mii(struct net_device *dev) writel(mip->mii_regval, fep->hwp + FEC_MII_DATA); unlock: - spin_unlock_irq(&fep->mii_lock); + spin_unlock(&fep->mii_lock); } static int -- cgit v0.10.2 From 137742cf9738f1b4784058ff79aec7ca85e769d4 Mon Sep 17 00:00:00 2001 From: Karl Hiramoto Date: Wed, 2 Sep 2009 23:26:39 -0700 Subject: atm/br2684: netif_stop_queue() when atm device busy and netif_wake_queue() when we can send packets again. This patch removes the call to dev_kfree_skb() when the atm device is busy. Calling dev_kfree_skb() causes heavy packet loss then the device is under heavy load, the more correct behavior should be to stop the upper layers, then when the lower device can queue packets again wake the upper layers. Signed-off-by: Karl Hiramoto Signed-off-by: Chas Williams Signed-off-by: David S. Miller diff --git a/net/atm/br2684.c b/net/atm/br2684.c index d6be0d1..26a646d 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -69,7 +69,7 @@ struct br2684_vcc { struct net_device *device; /* keep old push, pop functions for chaining */ void (*old_push) (struct atm_vcc * vcc, struct sk_buff * skb); - /* void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); */ + void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); enum br2684_encaps encaps; struct list_head brvccs; #ifdef CONFIG_ATM_BR2684_IPFILTER @@ -142,6 +142,22 @@ static struct net_device *br2684_find_dev(const struct br2684_if_spec *s) return NULL; } +/* chained vcc->pop function. Check if we should wake the netif_queue */ +static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct br2684_vcc *brvcc = BR2684_VCC(vcc); + struct net_device *net_dev = skb->dev; + + pr_debug("br2684_pop(vcc %p ; net_dev %p )\n", vcc, net_dev); + brvcc->old_pop(vcc, skb); + + if (!net_dev) + return; + + if (atm_may_send(vcc, 0)) + netif_wake_queue(net_dev); + +} /* * Send a packet out a particular vcc. Not to useful right now, but paves * the way for multiple vcc's per itf. Returns true if we can send, @@ -200,20 +216,19 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev, ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev); - if (!atm_may_send(atmvcc, skb->truesize)) { - /* - * We free this here for now, because we cannot know in a higher - * layer whether the skb pointer it supplied wasn't freed yet. - * Now, it always is. - */ - dev_kfree_skb(skb); - return 0; - } atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc); ATM_SKB(skb)->atm_options = atmvcc->atm_options; dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; atmvcc->send(atmvcc, skb); + + if (!atm_may_send(atmvcc, 0)) { + netif_stop_queue(brvcc->device); + /*check for race with br2684_pop*/ + if (atm_may_send(atmvcc, 0)) + netif_start_queue(brvcc->device); + } + return 1; } @@ -504,8 +519,10 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) atmvcc->user_back = brvcc; brvcc->encaps = (enum br2684_encaps)be.encaps; brvcc->old_push = atmvcc->push; + brvcc->old_pop = atmvcc->pop; barrier(); atmvcc->push = br2684_push; + atmvcc->pop = br2684_pop; __skb_queue_head_init(&queue); rq = &sk_atm(atmvcc)->sk_receive_queue; -- cgit v0.10.2 From d1b19dff9159bb88fe839c30a7c071faf4761933 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 3 Sep 2009 01:29:39 -0700 Subject: net: net/core/dev.c cleanups Pure style cleanup patch before surgery :) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 4b33566..dd94ae6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -191,7 +191,6 @@ static struct list_head ptype_all __read_mostly; /* Taps */ * semaphore held. */ DEFINE_RWLOCK(dev_base_lock); - EXPORT_SYMBOL(dev_base_lock); #define NETDEV_HASHBITS 8 @@ -248,6 +247,7 @@ static RAW_NOTIFIER_HEAD(netdev_chain); */ DEFINE_PER_CPU(struct softnet_data, softnet_data); +EXPORT_PER_CPU_SYMBOL(softnet_data); #ifdef CONFIG_LOCKDEP /* @@ -381,6 +381,7 @@ void dev_add_pack(struct packet_type *pt) } spin_unlock_bh(&ptype_lock); } +EXPORT_SYMBOL(dev_add_pack); /** * __dev_remove_pack - remove packet handler @@ -418,6 +419,8 @@ void __dev_remove_pack(struct packet_type *pt) out: spin_unlock_bh(&ptype_lock); } +EXPORT_SYMBOL(__dev_remove_pack); + /** * dev_remove_pack - remove packet handler * @pt: packet type declaration @@ -436,6 +439,7 @@ void dev_remove_pack(struct packet_type *pt) synchronize_net(); } +EXPORT_SYMBOL(dev_remove_pack); /****************************************************************************** @@ -499,6 +503,7 @@ int netdev_boot_setup_check(struct net_device *dev) } return 0; } +EXPORT_SYMBOL(netdev_boot_setup_check); /** @@ -591,6 +596,7 @@ struct net_device *__dev_get_by_name(struct net *net, const char *name) } return NULL; } +EXPORT_SYMBOL(__dev_get_by_name); /** * dev_get_by_name - find a device by its name @@ -615,6 +621,7 @@ struct net_device *dev_get_by_name(struct net *net, const char *name) read_unlock(&dev_base_lock); return dev; } +EXPORT_SYMBOL(dev_get_by_name); /** * __dev_get_by_index - find a device by its ifindex @@ -640,6 +647,7 @@ struct net_device *__dev_get_by_index(struct net *net, int ifindex) } return NULL; } +EXPORT_SYMBOL(__dev_get_by_index); /** @@ -664,6 +672,7 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex) read_unlock(&dev_base_lock); return dev; } +EXPORT_SYMBOL(dev_get_by_index); /** * dev_getbyhwaddr - find a device by its hardware address @@ -693,7 +702,6 @@ struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *h return NULL; } - EXPORT_SYMBOL(dev_getbyhwaddr); struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type) @@ -707,7 +715,6 @@ struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type) return NULL; } - EXPORT_SYMBOL(__dev_getfirstbyhwtype); struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type) @@ -721,7 +728,6 @@ struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type) rtnl_unlock(); return dev; } - EXPORT_SYMBOL(dev_getfirstbyhwtype); /** @@ -736,7 +742,8 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype); * dev_put to indicate they have finished with it. */ -struct net_device * dev_get_by_flags(struct net *net, unsigned short if_flags, unsigned short mask) +struct net_device *dev_get_by_flags(struct net *net, unsigned short if_flags, + unsigned short mask) { struct net_device *dev, *ret; @@ -752,6 +759,7 @@ struct net_device * dev_get_by_flags(struct net *net, unsigned short if_flags, u read_unlock(&dev_base_lock); return ret; } +EXPORT_SYMBOL(dev_get_by_flags); /** * dev_valid_name - check if name is okay for network device @@ -777,6 +785,7 @@ int dev_valid_name(const char *name) } return 1; } +EXPORT_SYMBOL(dev_valid_name); /** * __dev_alloc_name - allocate a name for a device @@ -870,6 +879,7 @@ int dev_alloc_name(struct net_device *dev, const char *name) strlcpy(dev->name, buf, IFNAMSIZ); return ret; } +EXPORT_SYMBOL(dev_alloc_name); /** @@ -906,8 +916,7 @@ int dev_change_name(struct net_device *dev, const char *newname) err = dev_alloc_name(dev, newname); if (err < 0) return err; - } - else if (__dev_get_by_name(net, newname)) + } else if (__dev_get_by_name(net, newname)) return -EEXIST; else strlcpy(dev->name, newname, IFNAMSIZ); @@ -970,7 +979,7 @@ int dev_set_alias(struct net_device *dev, const char *alias, size_t len) return 0; } - dev->ifalias = krealloc(dev->ifalias, len+1, GFP_KERNEL); + dev->ifalias = krealloc(dev->ifalias, len + 1, GFP_KERNEL); if (!dev->ifalias) return -ENOMEM; @@ -1006,6 +1015,7 @@ void netdev_state_change(struct net_device *dev) rtmsg_ifinfo(RTM_NEWLINK, dev, 0); } } +EXPORT_SYMBOL(netdev_state_change); void netdev_bonding_change(struct net_device *dev) { @@ -1034,6 +1044,7 @@ void dev_load(struct net *net, const char *name) if (!dev && capable(CAP_SYS_MODULE)) request_module("%s", name); } +EXPORT_SYMBOL(dev_load); /** * dev_open - prepare an interface for use. @@ -1118,6 +1129,7 @@ int dev_open(struct net_device *dev) return ret; } +EXPORT_SYMBOL(dev_open); /** * dev_close - shutdown an interface. @@ -1184,6 +1196,7 @@ int dev_close(struct net_device *dev) return 0; } +EXPORT_SYMBOL(dev_close); /** @@ -1279,6 +1292,7 @@ rollback: raw_notifier_chain_unregister(&netdev_chain, nb); goto unlock; } +EXPORT_SYMBOL(register_netdevice_notifier); /** * unregister_netdevice_notifier - unregister a network notifier block @@ -1299,6 +1313,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb) rtnl_unlock(); return err; } +EXPORT_SYMBOL(unregister_netdevice_notifier); /** * call_netdevice_notifiers - call all network notifier blocks @@ -1321,11 +1336,13 @@ void net_enable_timestamp(void) { atomic_inc(&netstamp_needed); } +EXPORT_SYMBOL(net_enable_timestamp); void net_disable_timestamp(void) { atomic_dec(&netstamp_needed); } +EXPORT_SYMBOL(net_disable_timestamp); static inline void net_timestamp(struct sk_buff *skb) { @@ -1359,7 +1376,7 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) if ((ptype->dev == dev || !ptype->dev) && (ptype->af_packet_priv == NULL || (struct sock *)ptype->af_packet_priv != skb->sk)) { - struct sk_buff *skb2= skb_clone(skb, GFP_ATOMIC); + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); if (!skb2) break; @@ -1527,6 +1544,7 @@ out_set_summed: out: return ret; } +EXPORT_SYMBOL(skb_checksum_help); /** * skb_gso_segment - Perform segmentation on skb. @@ -1589,7 +1607,6 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) return segs; } - EXPORT_SYMBOL(skb_gso_segment); /* Take action when hardware reception checksum errors are detected. */ @@ -1755,7 +1772,7 @@ u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb) if (skb_rx_queue_recorded(skb)) { hash = skb_get_rx_queue(skb); - while (unlikely (hash >= dev->real_num_tx_queues)) + while (unlikely(hash >= dev->real_num_tx_queues)) hash -= dev->real_num_tx_queues; return hash; } @@ -1890,7 +1907,7 @@ gso: q = rcu_dereference(txq->qdisc); #ifdef CONFIG_NET_CLS_ACT - skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_EGRESS); + skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS); #endif if (q->enqueue) { rc = __dev_xmit_skb(skb, q, dev, txq); @@ -1946,6 +1963,7 @@ out: rcu_read_unlock_bh(); return rc; } +EXPORT_SYMBOL(dev_queue_xmit); /*======================================================================= @@ -2012,6 +2030,7 @@ enqueue: kfree_skb(skb); return NET_RX_DROP; } +EXPORT_SYMBOL(netif_rx); int netif_rx_ni(struct sk_buff *skb) { @@ -2025,7 +2044,6 @@ int netif_rx_ni(struct sk_buff *skb) return err; } - EXPORT_SYMBOL(netif_rx_ni); static void net_tx_action(struct softirq_action *h) @@ -2358,6 +2376,7 @@ out: rcu_read_unlock(); return ret; } +EXPORT_SYMBOL(netif_receive_skb); /* Network device is going away, flush any packets still pending */ static void flush_backlog(void *arg) @@ -2874,7 +2893,7 @@ softnet_break: goto out; } -static gifconf_func_t * gifconf_list [NPROTO]; +static gifconf_func_t *gifconf_list[NPROTO]; /** * register_gifconf - register a SIOCGIF handler @@ -2885,13 +2904,14 @@ static gifconf_func_t * gifconf_list [NPROTO]; * that is passed must not be freed or reused until it has been replaced * by another handler. */ -int register_gifconf(unsigned int family, gifconf_func_t * gifconf) +int register_gifconf(unsigned int family, gifconf_func_t *gifconf) { if (family >= NPROTO) return -EINVAL; gifconf_list[family] = gifconf; return 0; } +EXPORT_SYMBOL(register_gifconf); /* @@ -3102,7 +3122,7 @@ static int softnet_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n", s->total, s->dropped, s->time_squeeze, 0, 0, 0, 0, 0, /* was fastroute */ - s->cpu_collision ); + s->cpu_collision); return 0; } @@ -3338,6 +3358,7 @@ int netdev_set_master(struct net_device *slave, struct net_device *master) rtmsg_ifinfo(RTM_NEWLINK, slave, IFF_SLAVE); return 0; } +EXPORT_SYMBOL(netdev_set_master); static void dev_change_rx_flags(struct net_device *dev, int flags) { @@ -3416,6 +3437,7 @@ int dev_set_promiscuity(struct net_device *dev, int inc) dev_set_rx_mode(dev); return err; } +EXPORT_SYMBOL(dev_set_promiscuity); /** * dev_set_allmulti - update allmulti count on a device @@ -3459,6 +3481,7 @@ int dev_set_allmulti(struct net_device *dev, int inc) } return 0; } +EXPORT_SYMBOL(dev_set_allmulti); /* * Upload unicast and multicast address lists to device and @@ -4088,6 +4111,7 @@ unsigned dev_get_flags(const struct net_device *dev) return flags; } +EXPORT_SYMBOL(dev_get_flags); /** * dev_change_flags - change device settings @@ -4138,12 +4162,13 @@ int dev_change_flags(struct net_device *dev, unsigned flags) } if (dev->flags & IFF_UP && - ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI | + ((old_flags ^ dev->flags) & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE))) call_netdevice_notifiers(NETDEV_CHANGE, dev); if ((flags ^ dev->gflags) & IFF_PROMISC) { - int inc = (flags & IFF_PROMISC) ? +1 : -1; + int inc = (flags & IFF_PROMISC) ? 1 : -1; + dev->gflags ^= IFF_PROMISC; dev_set_promiscuity(dev, inc); } @@ -4153,7 +4178,8 @@ int dev_change_flags(struct net_device *dev, unsigned flags) IFF_ALLMULTI is requested not asking us and not reporting. */ if ((flags ^ dev->gflags) & IFF_ALLMULTI) { - int inc = (flags & IFF_ALLMULTI) ? +1 : -1; + int inc = (flags & IFF_ALLMULTI) ? 1 : -1; + dev->gflags ^= IFF_ALLMULTI; dev_set_allmulti(dev, inc); } @@ -4165,6 +4191,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags) return ret; } +EXPORT_SYMBOL(dev_change_flags); /** * dev_set_mtu - Change maximum transfer unit @@ -4198,6 +4225,7 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); return err; } +EXPORT_SYMBOL(dev_set_mtu); /** * dev_set_mac_address - Change Media Access Control Address @@ -4222,6 +4250,7 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); return err; } +EXPORT_SYMBOL(dev_set_mac_address); /* * Perform the SIOCxIFxxx calls, inside read_lock(dev_base_lock) @@ -4235,56 +4264,56 @@ static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cm return -ENODEV; switch (cmd) { - case SIOCGIFFLAGS: /* Get interface flags */ - ifr->ifr_flags = (short) dev_get_flags(dev); - return 0; + case SIOCGIFFLAGS: /* Get interface flags */ + ifr->ifr_flags = (short) dev_get_flags(dev); + return 0; - case SIOCGIFMETRIC: /* Get the metric on the interface - (currently unused) */ - ifr->ifr_metric = 0; - return 0; + case SIOCGIFMETRIC: /* Get the metric on the interface + (currently unused) */ + ifr->ifr_metric = 0; + return 0; - case SIOCGIFMTU: /* Get the MTU of a device */ - ifr->ifr_mtu = dev->mtu; - return 0; + case SIOCGIFMTU: /* Get the MTU of a device */ + ifr->ifr_mtu = dev->mtu; + return 0; - case SIOCGIFHWADDR: - if (!dev->addr_len) - memset(ifr->ifr_hwaddr.sa_data, 0, sizeof ifr->ifr_hwaddr.sa_data); - else - memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr, - min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); - ifr->ifr_hwaddr.sa_family = dev->type; - return 0; + case SIOCGIFHWADDR: + if (!dev->addr_len) + memset(ifr->ifr_hwaddr.sa_data, 0, sizeof ifr->ifr_hwaddr.sa_data); + else + memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr, + min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); + ifr->ifr_hwaddr.sa_family = dev->type; + return 0; - case SIOCGIFSLAVE: - err = -EINVAL; - break; + case SIOCGIFSLAVE: + err = -EINVAL; + break; - case SIOCGIFMAP: - ifr->ifr_map.mem_start = dev->mem_start; - ifr->ifr_map.mem_end = dev->mem_end; - ifr->ifr_map.base_addr = dev->base_addr; - ifr->ifr_map.irq = dev->irq; - ifr->ifr_map.dma = dev->dma; - ifr->ifr_map.port = dev->if_port; - return 0; + case SIOCGIFMAP: + ifr->ifr_map.mem_start = dev->mem_start; + ifr->ifr_map.mem_end = dev->mem_end; + ifr->ifr_map.base_addr = dev->base_addr; + ifr->ifr_map.irq = dev->irq; + ifr->ifr_map.dma = dev->dma; + ifr->ifr_map.port = dev->if_port; + return 0; - case SIOCGIFINDEX: - ifr->ifr_ifindex = dev->ifindex; - return 0; + case SIOCGIFINDEX: + ifr->ifr_ifindex = dev->ifindex; + return 0; - case SIOCGIFTXQLEN: - ifr->ifr_qlen = dev->tx_queue_len; - return 0; + case SIOCGIFTXQLEN: + ifr->ifr_qlen = dev->tx_queue_len; + return 0; - default: - /* dev_ioctl() should ensure this case - * is never reached - */ - WARN_ON(1); - err = -EINVAL; - break; + default: + /* dev_ioctl() should ensure this case + * is never reached + */ + WARN_ON(1); + err = -EINVAL; + break; } return err; @@ -4305,92 +4334,91 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) ops = dev->netdev_ops; switch (cmd) { - case SIOCSIFFLAGS: /* Set interface flags */ - return dev_change_flags(dev, ifr->ifr_flags); - - case SIOCSIFMETRIC: /* Set the metric on the interface - (currently unused) */ - return -EOPNOTSUPP; - - case SIOCSIFMTU: /* Set the MTU of a device */ - return dev_set_mtu(dev, ifr->ifr_mtu); + case SIOCSIFFLAGS: /* Set interface flags */ + return dev_change_flags(dev, ifr->ifr_flags); - case SIOCSIFHWADDR: - return dev_set_mac_address(dev, &ifr->ifr_hwaddr); + case SIOCSIFMETRIC: /* Set the metric on the interface + (currently unused) */ + return -EOPNOTSUPP; - case SIOCSIFHWBROADCAST: - if (ifr->ifr_hwaddr.sa_family != dev->type) - return -EINVAL; - memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, - min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); - call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); - return 0; + case SIOCSIFMTU: /* Set the MTU of a device */ + return dev_set_mtu(dev, ifr->ifr_mtu); - case SIOCSIFMAP: - if (ops->ndo_set_config) { - if (!netif_device_present(dev)) - return -ENODEV; - return ops->ndo_set_config(dev, &ifr->ifr_map); - } - return -EOPNOTSUPP; + case SIOCSIFHWADDR: + return dev_set_mac_address(dev, &ifr->ifr_hwaddr); - case SIOCADDMULTI: - if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) || - ifr->ifr_hwaddr.sa_family != AF_UNSPEC) - return -EINVAL; - if (!netif_device_present(dev)) - return -ENODEV; - return dev_mc_add(dev, ifr->ifr_hwaddr.sa_data, - dev->addr_len, 1); + case SIOCSIFHWBROADCAST: + if (ifr->ifr_hwaddr.sa_family != dev->type) + return -EINVAL; + memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, + min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + return 0; - case SIOCDELMULTI: - if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) || - ifr->ifr_hwaddr.sa_family != AF_UNSPEC) - return -EINVAL; + case SIOCSIFMAP: + if (ops->ndo_set_config) { if (!netif_device_present(dev)) return -ENODEV; - return dev_mc_delete(dev, ifr->ifr_hwaddr.sa_data, - dev->addr_len, 1); + return ops->ndo_set_config(dev, &ifr->ifr_map); + } + return -EOPNOTSUPP; - case SIOCSIFTXQLEN: - if (ifr->ifr_qlen < 0) - return -EINVAL; - dev->tx_queue_len = ifr->ifr_qlen; - return 0; + case SIOCADDMULTI: + if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) || + ifr->ifr_hwaddr.sa_family != AF_UNSPEC) + return -EINVAL; + if (!netif_device_present(dev)) + return -ENODEV; + return dev_mc_add(dev, ifr->ifr_hwaddr.sa_data, + dev->addr_len, 1); + + case SIOCDELMULTI: + if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) || + ifr->ifr_hwaddr.sa_family != AF_UNSPEC) + return -EINVAL; + if (!netif_device_present(dev)) + return -ENODEV; + return dev_mc_delete(dev, ifr->ifr_hwaddr.sa_data, + dev->addr_len, 1); - case SIOCSIFNAME: - ifr->ifr_newname[IFNAMSIZ-1] = '\0'; - return dev_change_name(dev, ifr->ifr_newname); + case SIOCSIFTXQLEN: + if (ifr->ifr_qlen < 0) + return -EINVAL; + dev->tx_queue_len = ifr->ifr_qlen; + return 0; - /* - * Unknown or private ioctl - */ + case SIOCSIFNAME: + ifr->ifr_newname[IFNAMSIZ-1] = '\0'; + return dev_change_name(dev, ifr->ifr_newname); - default: - if ((cmd >= SIOCDEVPRIVATE && - cmd <= SIOCDEVPRIVATE + 15) || - cmd == SIOCBONDENSLAVE || - cmd == SIOCBONDRELEASE || - cmd == SIOCBONDSETHWADDR || - cmd == SIOCBONDSLAVEINFOQUERY || - cmd == SIOCBONDINFOQUERY || - cmd == SIOCBONDCHANGEACTIVE || - cmd == SIOCGMIIPHY || - cmd == SIOCGMIIREG || - cmd == SIOCSMIIREG || - cmd == SIOCBRADDIF || - cmd == SIOCBRDELIF || - cmd == SIOCSHWTSTAMP || - cmd == SIOCWANDEV) { - err = -EOPNOTSUPP; - if (ops->ndo_do_ioctl) { - if (netif_device_present(dev)) - err = ops->ndo_do_ioctl(dev, ifr, cmd); - else - err = -ENODEV; - } - } else - err = -EINVAL; + /* + * Unknown or private ioctl + */ + default: + if ((cmd >= SIOCDEVPRIVATE && + cmd <= SIOCDEVPRIVATE + 15) || + cmd == SIOCBONDENSLAVE || + cmd == SIOCBONDRELEASE || + cmd == SIOCBONDSETHWADDR || + cmd == SIOCBONDSLAVEINFOQUERY || + cmd == SIOCBONDINFOQUERY || + cmd == SIOCBONDCHANGEACTIVE || + cmd == SIOCGMIIPHY || + cmd == SIOCGMIIREG || + cmd == SIOCSMIIREG || + cmd == SIOCBRADDIF || + cmd == SIOCBRDELIF || + cmd == SIOCSHWTSTAMP || + cmd == SIOCWANDEV) { + err = -EOPNOTSUPP; + if (ops->ndo_do_ioctl) { + if (netif_device_present(dev)) + err = ops->ndo_do_ioctl(dev, ifr, cmd); + else + err = -ENODEV; + } + } else + err = -EINVAL; } return err; @@ -4447,135 +4475,135 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) */ switch (cmd) { - /* - * These ioctl calls: - * - can be done by all. - * - atomic and do not require locking. - * - return a value - */ - case SIOCGIFFLAGS: - case SIOCGIFMETRIC: - case SIOCGIFMTU: - case SIOCGIFHWADDR: - case SIOCGIFSLAVE: - case SIOCGIFMAP: - case SIOCGIFINDEX: - case SIOCGIFTXQLEN: - dev_load(net, ifr.ifr_name); - read_lock(&dev_base_lock); - ret = dev_ifsioc_locked(net, &ifr, cmd); - read_unlock(&dev_base_lock); - if (!ret) { - if (colon) - *colon = ':'; - if (copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - } - return ret; + /* + * These ioctl calls: + * - can be done by all. + * - atomic and do not require locking. + * - return a value + */ + case SIOCGIFFLAGS: + case SIOCGIFMETRIC: + case SIOCGIFMTU: + case SIOCGIFHWADDR: + case SIOCGIFSLAVE: + case SIOCGIFMAP: + case SIOCGIFINDEX: + case SIOCGIFTXQLEN: + dev_load(net, ifr.ifr_name); + read_lock(&dev_base_lock); + ret = dev_ifsioc_locked(net, &ifr, cmd); + read_unlock(&dev_base_lock); + if (!ret) { + if (colon) + *colon = ':'; + if (copy_to_user(arg, &ifr, + sizeof(struct ifreq))) + ret = -EFAULT; + } + return ret; - case SIOCETHTOOL: - dev_load(net, ifr.ifr_name); - rtnl_lock(); - ret = dev_ethtool(net, &ifr); - rtnl_unlock(); - if (!ret) { - if (colon) - *colon = ':'; - if (copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - } - return ret; + case SIOCETHTOOL: + dev_load(net, ifr.ifr_name); + rtnl_lock(); + ret = dev_ethtool(net, &ifr); + rtnl_unlock(); + if (!ret) { + if (colon) + *colon = ':'; + if (copy_to_user(arg, &ifr, + sizeof(struct ifreq))) + ret = -EFAULT; + } + return ret; - /* - * These ioctl calls: - * - require superuser power. - * - require strict serialization. - * - return a value - */ - case SIOCGMIIPHY: - case SIOCGMIIREG: - case SIOCSIFNAME: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - dev_load(net, ifr.ifr_name); - rtnl_lock(); - ret = dev_ifsioc(net, &ifr, cmd); - rtnl_unlock(); - if (!ret) { - if (colon) - *colon = ':'; - if (copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - } - return ret; + /* + * These ioctl calls: + * - require superuser power. + * - require strict serialization. + * - return a value + */ + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSIFNAME: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + dev_load(net, ifr.ifr_name); + rtnl_lock(); + ret = dev_ifsioc(net, &ifr, cmd); + rtnl_unlock(); + if (!ret) { + if (colon) + *colon = ':'; + if (copy_to_user(arg, &ifr, + sizeof(struct ifreq))) + ret = -EFAULT; + } + return ret; - /* - * These ioctl calls: - * - require superuser power. - * - require strict serialization. - * - do not return a value - */ - case SIOCSIFFLAGS: - case SIOCSIFMETRIC: - case SIOCSIFMTU: - case SIOCSIFMAP: - case SIOCSIFHWADDR: - case SIOCSIFSLAVE: - case SIOCADDMULTI: - case SIOCDELMULTI: - case SIOCSIFHWBROADCAST: - case SIOCSIFTXQLEN: - case SIOCSMIIREG: - case SIOCBONDENSLAVE: - case SIOCBONDRELEASE: - case SIOCBONDSETHWADDR: - case SIOCBONDCHANGEACTIVE: - case SIOCBRADDIF: - case SIOCBRDELIF: - case SIOCSHWTSTAMP: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - /* fall through */ - case SIOCBONDSLAVEINFOQUERY: - case SIOCBONDINFOQUERY: + /* + * These ioctl calls: + * - require superuser power. + * - require strict serialization. + * - do not return a value + */ + case SIOCSIFFLAGS: + case SIOCSIFMETRIC: + case SIOCSIFMTU: + case SIOCSIFMAP: + case SIOCSIFHWADDR: + case SIOCSIFSLAVE: + case SIOCADDMULTI: + case SIOCDELMULTI: + case SIOCSIFHWBROADCAST: + case SIOCSIFTXQLEN: + case SIOCSMIIREG: + case SIOCBONDENSLAVE: + case SIOCBONDRELEASE: + case SIOCBONDSETHWADDR: + case SIOCBONDCHANGEACTIVE: + case SIOCBRADDIF: + case SIOCBRDELIF: + case SIOCSHWTSTAMP: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + /* fall through */ + case SIOCBONDSLAVEINFOQUERY: + case SIOCBONDINFOQUERY: + dev_load(net, ifr.ifr_name); + rtnl_lock(); + ret = dev_ifsioc(net, &ifr, cmd); + rtnl_unlock(); + return ret; + + case SIOCGIFMEM: + /* Get the per device memory space. We can add this but + * currently do not support it */ + case SIOCSIFMEM: + /* Set the per device memory buffer space. + * Not applicable in our case */ + case SIOCSIFLINK: + return -EINVAL; + + /* + * Unknown or private ioctl. + */ + default: + if (cmd == SIOCWANDEV || + (cmd >= SIOCDEVPRIVATE && + cmd <= SIOCDEVPRIVATE + 15)) { dev_load(net, ifr.ifr_name); rtnl_lock(); ret = dev_ifsioc(net, &ifr, cmd); rtnl_unlock(); + if (!ret && copy_to_user(arg, &ifr, + sizeof(struct ifreq))) + ret = -EFAULT; return ret; - - case SIOCGIFMEM: - /* Get the per device memory space. We can add this but - * currently do not support it */ - case SIOCSIFMEM: - /* Set the per device memory buffer space. - * Not applicable in our case */ - case SIOCSIFLINK: - return -EINVAL; - - /* - * Unknown or private ioctl. - */ - default: - if (cmd == SIOCWANDEV || - (cmd >= SIOCDEVPRIVATE && - cmd <= SIOCDEVPRIVATE + 15)) { - dev_load(net, ifr.ifr_name); - rtnl_lock(); - ret = dev_ifsioc(net, &ifr, cmd); - rtnl_unlock(); - if (!ret && copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - return ret; - } - /* Take care of Wireless Extensions */ - if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) - return wext_handle_ioctl(net, &ifr, cmd, arg); - return -EINVAL; + } + /* Take care of Wireless Extensions */ + if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) + return wext_handle_ioctl(net, &ifr, cmd, arg); + return -EINVAL; } } @@ -4840,6 +4868,7 @@ err_uninit: dev->netdev_ops->ndo_uninit(dev); goto out; } +EXPORT_SYMBOL(register_netdevice); /** * init_dummy_netdev - init a dummy network device for NAPI @@ -5126,6 +5155,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, } dev = PTR_ALIGN(p, NETDEV_ALIGN); + pr_err("%s dev=%p queue_count=%d tx=%p\n", name, dev, queue_count, tx); + WARN_ON(queue_count == 1); dev->padded = (char *)dev - (char *)p; if (dev_addr_init(dev)) @@ -5192,6 +5223,7 @@ void free_netdev(struct net_device *dev) /* will free via device release */ put_device(&dev->dev); } +EXPORT_SYMBOL(free_netdev); /** * synchronize_net - Synchronize with packet receive processing @@ -5204,6 +5236,7 @@ void synchronize_net(void) might_sleep(); synchronize_rcu(); } +EXPORT_SYMBOL(synchronize_net); /** * unregister_netdevice - remove device from the kernel @@ -5224,6 +5257,7 @@ void unregister_netdevice(struct net_device *dev) /* Finish processing unregister after unlock */ net_set_todo(dev); } +EXPORT_SYMBOL(unregister_netdevice); /** * unregister_netdev - remove device from the kernel @@ -5242,7 +5276,6 @@ void unregister_netdev(struct net_device *dev) unregister_netdevice(dev); rtnl_unlock(); } - EXPORT_SYMBOL(unregister_netdev); /** @@ -5432,7 +5465,7 @@ unsigned long netdev_increment_features(unsigned long all, unsigned long one, unsigned long mask) { /* If device needs checksumming, downgrade to it. */ - if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM)) + if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM)) all ^= NETIF_F_NO_CSUM | (one & NETIF_F_ALL_CSUM); else if (mask & NETIF_F_ALL_CSUM) { /* If one device supports v4/v6 checksumming, set for all. */ @@ -5658,41 +5691,3 @@ static int __init initialize_hashrnd(void) late_initcall_sync(initialize_hashrnd); -EXPORT_SYMBOL(__dev_get_by_index); -EXPORT_SYMBOL(__dev_get_by_name); -EXPORT_SYMBOL(__dev_remove_pack); -EXPORT_SYMBOL(dev_valid_name); -EXPORT_SYMBOL(dev_add_pack); -EXPORT_SYMBOL(dev_alloc_name); -EXPORT_SYMBOL(dev_close); -EXPORT_SYMBOL(dev_get_by_flags); -EXPORT_SYMBOL(dev_get_by_index); -EXPORT_SYMBOL(dev_get_by_name); -EXPORT_SYMBOL(dev_open); -EXPORT_SYMBOL(dev_queue_xmit); -EXPORT_SYMBOL(dev_remove_pack); -EXPORT_SYMBOL(dev_set_allmulti); -EXPORT_SYMBOL(dev_set_promiscuity); -EXPORT_SYMBOL(dev_change_flags); -EXPORT_SYMBOL(dev_set_mtu); -EXPORT_SYMBOL(dev_set_mac_address); -EXPORT_SYMBOL(free_netdev); -EXPORT_SYMBOL(netdev_boot_setup_check); -EXPORT_SYMBOL(netdev_set_master); -EXPORT_SYMBOL(netdev_state_change); -EXPORT_SYMBOL(netif_receive_skb); -EXPORT_SYMBOL(netif_rx); -EXPORT_SYMBOL(register_gifconf); -EXPORT_SYMBOL(register_netdevice); -EXPORT_SYMBOL(register_netdevice_notifier); -EXPORT_SYMBOL(skb_checksum_help); -EXPORT_SYMBOL(synchronize_net); -EXPORT_SYMBOL(unregister_netdevice); -EXPORT_SYMBOL(unregister_netdevice_notifier); -EXPORT_SYMBOL(net_enable_timestamp); -EXPORT_SYMBOL(net_disable_timestamp); -EXPORT_SYMBOL(dev_get_flags); - -EXPORT_SYMBOL(dev_load); - -EXPORT_PER_CPU_SYMBOL(softnet_data); -- cgit v0.10.2 From 2f8bc32b7a08502a79e0ccec8697000f2977f2fd Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 3 Sep 2009 02:19:58 -0700 Subject: vlan: enable multiqueue xmits vlan_dev_hard_start_xmit() & vlan_dev_hwaccel_hard_start_xmit() select txqueue number 0, instead of using index provided by skb_get_queue_mapping(). This is not correct after commit 2e59af3dcbdf11635c03f [vlan: multiqueue vlan device] because txq->tx_packets & txq->tx_bytes changes are performed on a single location, and not the right locking. Fix is to take the appropriate struct netdev_queue pointer Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 53f84c7..3938c3e 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -291,7 +291,8 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); + int i = skb_get_queue_mapping(skb); + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); /* Handle non-VLAN frames if they are sent to us, for example by DHCP. @@ -329,7 +330,8 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); + int i = skb_get_queue_mapping(skb); + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); u16 vlan_tci; vlan_tci = vlan_dev_info(dev)->vlan_id; -- cgit v0.10.2 From 9d32e03d01649d2dd837923470f3f323e3b88253 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 31 Aug 2009 15:07:23 +0200 Subject: ALSA: Release v1.0.21 Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai diff --git a/include/sound/version.h b/include/sound/version.h index 456f135..2293914 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h */ -#define CONFIG_SND_VERSION "1.0.20" +#define CONFIG_SND_VERSION "1.0.21" #define CONFIG_SND_DATE "" -- cgit v0.10.2 From e3e59876e82a5e1a07f365d5474e7b6943524725 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 3 Sep 2009 14:02:10 +0200 Subject: x86/amd-iommu: Dump fault entry on DTE error This patch adds code to dump the content of the device table entry which caused an ILLEGAL_DEV_TABLE_ENTRY error from the IOMMU hardware. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 6c99f50..364c6de 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -138,6 +138,15 @@ static int iommu_has_npcache(struct amd_iommu *iommu) * ****************************************************************************/ +static void dump_dte_entry(u16 devid) +{ + int i; + + for (i = 0; i < 8; ++i) + pr_err("AMD-Vi: DTE[%d]: %08x\n", i, + amd_iommu_dev_table[devid].data[i]); +} + static void iommu_print_event(void *__evt) { u32 *event = __evt; @@ -155,6 +164,7 @@ static void iommu_print_event(void *__evt) "address=0x%016llx flags=0x%04x]\n", PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid), address, flags); + dump_dte_entry(devid); break; case EVENT_TYPE_IO_FAULT: printk("IO_PAGE_FAULT device=%02x:%02x.%x " -- cgit v0.10.2 From 55f9d6786de2f9cf37db50dbe8ae16f887f3ad7f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 3 Sep 2009 05:17:20 -0700 Subject: net: Remove debugging code Remove a debugging aid I accidently left in previous 'cleanup' patch Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index dd94ae6..1a6561b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5155,8 +5155,6 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, } dev = PTR_ALIGN(p, NETDEV_ALIGN); - pr_err("%s dev=%p queue_count=%d tx=%p\n", name, dev, queue_count, tx); - WARN_ON(queue_count == 1); dev->padded = (char *)dev - (char *)p; if (dev_addr_init(dev)) -- cgit v0.10.2 From 945b4ac44e5700acd3d974c176c8ace34b4d2e8e Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 3 Sep 2009 14:25:02 +0200 Subject: x86/amd-iommu: Dump illegal command on ILLEGAL_COMMAND_ERROR This patch adds code to dump the command which caused an ILLEGAL_COMMAND_ERROR raised by the IOMMU hardware. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 364c6de..e62b35f 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -147,6 +147,15 @@ static void dump_dte_entry(u16 devid) amd_iommu_dev_table[devid].data[i]); } +static void dump_command(unsigned long phys_addr) +{ + struct iommu_cmd *cmd = phys_to_virt(phys_addr); + int i; + + for (i = 0; i < 4; ++i) + pr_err("AMD-Vi: CMD[%d]: %08x\n", i, cmd->data[i]); +} + static void iommu_print_event(void *__evt) { u32 *event = __evt; @@ -186,6 +195,7 @@ static void iommu_print_event(void *__evt) break; case EVENT_TYPE_ILL_CMD: printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address); + dump_command(address); break; case EVENT_TYPE_CMD_HARD_ERR: printk("COMMAND_HARDWARE_ERROR address=0x%016llx " -- cgit v0.10.2 From e394d72aa8b319211b8f947d151d9d50b0fde842 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 3 Sep 2009 15:28:33 +0200 Subject: x86/amd-iommu: Introduce function for iommu-local domain flush This patch introduces a function to flush all domain tlbs for on one given IOMMU. This is required later to reset the command buffer on one IOMMU. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index e62b35f..64cc582 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -465,38 +465,55 @@ static void iommu_flush_tlb_pde(struct amd_iommu *iommu, u16 domid) } /* - * This function is used to flush the IO/TLB for a given protection domain - * on every IOMMU in the system + * This function flushes one domain on one IOMMU */ -static void iommu_flush_domain(u16 domid) +static void flush_domain_on_iommu(struct amd_iommu *iommu, u16 domid) { - unsigned long flags; - struct amd_iommu *iommu; struct iommu_cmd cmd; - - INC_STATS_COUNTER(domain_flush_all); + unsigned long flags; __iommu_build_inv_iommu_pages(&cmd, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, domid, 1, 1); - for_each_iommu(iommu) { - spin_lock_irqsave(&iommu->lock, flags); - __iommu_queue_command(iommu, &cmd); - __iommu_completion_wait(iommu); - __iommu_wait_for_completion(iommu); - spin_unlock_irqrestore(&iommu->lock, flags); - } + spin_lock_irqsave(&iommu->lock, flags); + __iommu_queue_command(iommu, &cmd); + __iommu_completion_wait(iommu); + __iommu_wait_for_completion(iommu); + spin_unlock_irqrestore(&iommu->lock, flags); } -void amd_iommu_flush_all_domains(void) +static void flush_all_domains_on_iommu(struct amd_iommu *iommu) { int i; for (i = 1; i < MAX_DOMAIN_ID; ++i) { if (!test_bit(i, amd_iommu_pd_alloc_bitmap)) continue; - iommu_flush_domain(i); + flush_domain_on_iommu(iommu, i); } + +} + +/* + * This function is used to flush the IO/TLB for a given protection domain + * on every IOMMU in the system + */ +static void iommu_flush_domain(u16 domid) +{ + struct amd_iommu *iommu; + + INC_STATS_COUNTER(domain_flush_all); + + for_each_iommu(iommu) + flush_domain_on_iommu(iommu, domid); +} + +void amd_iommu_flush_all_domains(void) +{ + struct amd_iommu *iommu; + + for_each_iommu(iommu) + flush_all_domains_on_iommu(iommu); } void amd_iommu_flush_all_devices(void) -- cgit v0.10.2 From 6ddf259da76cab6555c2086386f8bcd10bbb86d2 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 3 Sep 2009 12:00:22 +0200 Subject: perf trace: Sample timestamps as well Before: perf-21082 [013] 0.000000: sched_wakeup_new: task perf:21083 [120] success=1 [015] perf-21082 [013] 0.000000: sched_migrate_task: task perf:21082 [120] from: 13 to: 15 perf-21082 [013] 0.000000: sched_process_fork: parent perf:21082 child perf:21083 true-21083 [015] 0.000000: sched_wakeup: task migration/15:33 [0] success=1 [015] perf-21082 [013] 0.000000: sched_switch: task perf:21082 [120] (S) ==> swapper:0 [140] true-21083 [015] 0.000000: sched_switch: task perf:21083 [120] (R) ==> migration/15:33 [0] true-21083 [011] 0.000000: sched_process_exit: task true:21083 [120] After: perf-21082 [013] 14674.797613: sched_wakeup_new: task perf:21083 [120] success=1 [015] perf-21082 [013] 14674.797506: sched_migrate_task: task perf:21082 [120] from: 13 to: 15 perf-21082 [013] 14674.797610: sched_process_fork: parent perf:21082 child perf:21083 true-21083 [015] 14674.797725: sched_wakeup: task migration/15:33 [0] success=1 [015] perf-21082 [013] 14674.797722: sched_switch: task perf:21082 [120] (S) ==> swapper:0 [140] true-21083 [015] 14674.797729: sched_switch: task perf:21083 [120] (R) ==> migration/15:33 [0] true-21083 [011] 14674.798159: sched_process_exit: task true:21083 [120] Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ff93f8e..99a12fe 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -404,6 +404,7 @@ static void create_counter(int counter, int cpu, pid_t pid) attr->sample_type |= PERF_SAMPLE_CALLCHAIN; if (raw_samples) { + attr->sample_type |= PERF_SAMPLE_TIME; attr->sample_type |= PERF_SAMPLE_RAW; attr->sample_type |= PERF_SAMPLE_CPU; } diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index bbe4c44..d59bf8a 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -58,6 +58,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) struct dso *dso = NULL; struct thread *thread; u64 ip = event->ip.ip; + u64 timestamp = -1; u32 cpu = -1; u64 period = 1; void *more_data = event->ip.__more_data; @@ -65,6 +66,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) thread = threads__findnew(event->ip.pid, &threads, &last_match); + if (sample_type & PERF_SAMPLE_TIME) { + timestamp = *(u64 *)more_data; + more_data += sizeof(u64); + } + if (sample_type & PERF_SAMPLE_CPU) { cpu = *(u32 *)more_data; more_data += sizeof(u32); @@ -127,7 +133,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) * field, although it should be the same than this perf * event pid */ - print_event(cpu, raw->data, raw->size, 0, thread->comm); + print_event(cpu, raw->data, raw->size, timestamp, thread->comm); } total += period; -- cgit v0.10.2 From f2430bd104bec2706315e9e983a9d9f828ff9565 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Aug 2009 12:10:19 +0200 Subject: x86/amd-iommu: Remove some merge helper code This patch removes some left-overs which where put into the code to simplify merging code which also depends on changes in other trees. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 6c99f50..70fdef5 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -41,9 +41,7 @@ static DEFINE_RWLOCK(amd_iommu_devtable_lock); static LIST_HEAD(iommu_pd_list); static DEFINE_SPINLOCK(iommu_pd_list_lock); -#ifdef CONFIG_IOMMU_API static struct iommu_ops amd_iommu_ops; -#endif /* * general struct to manage commands send to an IOMMU @@ -62,10 +60,6 @@ static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, unsigned long start_page, unsigned int pages); -#ifndef BUS_NOTIFY_UNBOUND_DRIVER -#define BUS_NOTIFY_UNBOUND_DRIVER 0x0005 -#endif - #ifdef CONFIG_AMD_IOMMU_STATS /* -- cgit v0.10.2 From 4c6f40d4e0f0bba77a5f27eec4e1c6d1c457d324 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 1 Sep 2009 16:43:58 +0200 Subject: x86/amd-iommu: replace "AMD IOMMU" by "AMD-Vi" This patch replaces the "AMD IOMMU" printk strings with the official name for the hardware: "AMD-Vi". Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 0c878ca..106e130 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -198,7 +198,7 @@ extern bool amd_iommu_dump; #define DUMP_printk(format, arg...) \ do { \ if (amd_iommu_dump) \ - printk(KERN_INFO "AMD IOMMU: " format, ## arg); \ + printk(KERN_INFO "AMD-Vi: " format, ## arg); \ } while(0); /* diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 70fdef5..3e62d78 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -141,7 +141,7 @@ static void iommu_print_event(void *__evt) int flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK; u64 address = (u64)(((u64)event[3]) << 32) | event[2]; - printk(KERN_ERR "AMD IOMMU: Event logged ["); + printk(KERN_ERR "AMD-Vi: Event logged ["); switch (type) { case EVENT_TYPE_ILL_DEV: diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index c1b17e9..169958a 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -252,7 +252,7 @@ static void __init iommu_feature_disable(struct amd_iommu *iommu, u8 bit) /* Function to enable the hardware */ static void iommu_enable(struct amd_iommu *iommu) { - printk(KERN_INFO "AMD IOMMU: Enabling IOMMU at %s cap 0x%hx\n", + printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx\n", dev_name(&iommu->dev->dev), iommu->cap_ptr); iommu_feature_enable(iommu, CONTROL_IOMMU_EN); @@ -902,7 +902,7 @@ static int __init iommu_setup_msi(struct amd_iommu *iommu) r = request_irq(iommu->dev->irq, amd_iommu_int_handler, IRQF_SAMPLE_RANDOM, - "AMD IOMMU", + "AMD-Vi", NULL); if (r) { @@ -1150,7 +1150,7 @@ int __init amd_iommu_init(void) if (no_iommu) { - printk(KERN_INFO "AMD IOMMU disabled by kernel command line\n"); + printk(KERN_INFO "AMD-Vi disabled by kernel command line\n"); return 0; } @@ -1248,16 +1248,16 @@ int __init amd_iommu_init(void) enable_iommus(); - printk(KERN_INFO "AMD IOMMU: device isolation "); + printk(KERN_INFO "AMD-Vi: device isolation "); if (amd_iommu_isolate) printk("enabled\n"); else printk("disabled\n"); if (amd_iommu_unmap_flush) - printk(KERN_INFO "AMD IOMMU: IO/TLB flush on unmap enabled\n"); + printk(KERN_INFO "AMD-Vi: IO/TLB flush on unmap enabled\n"); else - printk(KERN_INFO "AMD IOMMU: Lazy IO/TLB flushing enabled\n"); + printk(KERN_INFO "AMD-Vi: Lazy IO/TLB flushing enabled\n"); out: return ret; -- cgit v0.10.2 From ae908c22aa2b9f7d4b41bd02d14e473f79c22dd3 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 1 Sep 2009 16:52:16 +0200 Subject: x86/amd-iommu: Remove redundant 'IOMMU' string The 'IOMMU: ' prefix is not necessary because the DUMP_printk macro already prints its own prefix. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 169958a..264b3ef 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -858,7 +858,7 @@ static int __init init_iommu_all(struct acpi_table_header *table) switch (*p) { case ACPI_IVHD_TYPE: - DUMP_printk("IOMMU: device: %02x:%02x.%01x cap: %04x " + DUMP_printk("device: %02x:%02x.%01x cap: %04x " "seg: %d flags: %01x info %04x\n", PCI_BUS(h->devid), PCI_SLOT(h->devid), PCI_FUNC(h->devid), h->cap_ptr, -- cgit v0.10.2 From e0faf54ee82bf9c07f0307b4391caad4020bd659 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 3 Sep 2009 15:45:51 +0200 Subject: x86/amd-iommu: fix broken check in amd_iommu_flush_all_devices The amd_iommu_pd_table is indexed by protection domain number and not by device id. So this check is broken and must be removed. Cc: stable@kernel.org Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 3e62d78..009d722 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -479,8 +479,6 @@ void amd_iommu_flush_all_devices(void) int i; for (i = 0; i <= amd_iommu_last_bdf; ++i) { - if (amd_iommu_pd_table[i] == NULL) - continue; iommu = amd_iommu_rlookup_table[i]; if (!iommu) -- cgit v0.10.2 From d586d7852ccd0cecb502bf4809f827e60c486af0 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 3 Sep 2009 15:39:23 +0200 Subject: x86/amd-iommu: Add function to flush all DTEs on one IOMMU This function flushes all DTE entries on one IOMMU for all devices behind this IOMMU. This is required for command buffer resetting later. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 64cc582..2dc0933 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -516,6 +516,19 @@ void amd_iommu_flush_all_domains(void) flush_all_domains_on_iommu(iommu); } +static void flush_all_devices_for_iommu(struct amd_iommu *iommu) +{ + int i; + + for (i = 0; i <= amd_iommu_last_bdf; ++i) { + if (iommu != amd_iommu_rlookup_table[i]) + continue; + + iommu_queue_inv_dev_entry(iommu, i); + iommu_completion_wait(iommu); + } +} + void amd_iommu_flush_all_devices(void) { struct amd_iommu *iommu; -- cgit v0.10.2 From 93f1cc67cf3196174412adca87321b25c1c986b0 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 3 Sep 2009 14:50:20 +0200 Subject: x86/amd-iommu: Add reset function for command buffers This patch factors parts of the command buffer initialization code into a seperate function which can be used to reset the command buffer later. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 0c878ca..c54bc979 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -457,4 +457,7 @@ static inline void amd_iommu_stats_init(void) { } #endif /* CONFIG_AMD_IOMMU_STATS */ +/* some function prototypes */ +extern void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu); + #endif /* _ASM_X86_AMD_IOMMU_TYPES_H */ diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index c1b17e9..1752afe 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -435,6 +435,20 @@ static u8 * __init alloc_command_buffer(struct amd_iommu *iommu) } /* + * This function resets the command buffer if the IOMMU stopped fetching + * commands from it. + */ +void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu) +{ + iommu_feature_disable(iommu, CONTROL_CMDBUF_EN); + + writel(0x00, iommu->mmio_base + MMIO_CMD_HEAD_OFFSET); + writel(0x00, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); + + iommu_feature_enable(iommu, CONTROL_CMDBUF_EN); +} + +/* * This function writes the command buffer address to the hardware and * enables it. */ @@ -450,11 +464,7 @@ static void iommu_enable_command_buffer(struct amd_iommu *iommu) memcpy_toio(iommu->mmio_base + MMIO_CMD_BUF_OFFSET, &entry, sizeof(entry)); - /* set head and tail to zero manually */ - writel(0x00, iommu->mmio_base + MMIO_CMD_HEAD_OFFSET); - writel(0x00, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); - - iommu_feature_enable(iommu, CONTROL_CMDBUF_EN); + amd_iommu_reset_cmd_buffer(iommu); } static void __init free_command_buffer(struct amd_iommu *iommu) -- cgit v0.10.2 From a345b23b79f1900e7d87c3165182504419180de4 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 3 Sep 2009 15:01:43 +0200 Subject: x86/amd-iommu: Reset command buffer on ILLEGAL_COMMAND_ERROR On an ILLEGAL_COMMAND_ERROR the IOMMU stops executing further commands. This patch changes the code to handle this case better by resetting the command buffer in the IOMMU. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 2dc0933..2333d61 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -61,6 +61,7 @@ static u64* alloc_pte(struct protection_domain *dom, static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, unsigned long start_page, unsigned int pages); +static void reset_iommu_command_buffer(struct amd_iommu *iommu); #ifndef BUS_NOTIFY_UNBOUND_DRIVER #define BUS_NOTIFY_UNBOUND_DRIVER 0x0005 @@ -156,7 +157,7 @@ static void dump_command(unsigned long phys_addr) pr_err("AMD-Vi: CMD[%d]: %08x\n", i, cmd->data[i]); } -static void iommu_print_event(void *__evt) +static void iommu_print_event(struct amd_iommu *iommu, void *__evt) { u32 *event = __evt; int type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; @@ -195,6 +196,7 @@ static void iommu_print_event(void *__evt) break; case EVENT_TYPE_ILL_CMD: printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address); + reset_iommu_command_buffer(iommu); dump_command(address); break; case EVENT_TYPE_CMD_HARD_ERR: @@ -229,7 +231,7 @@ static void iommu_poll_events(struct amd_iommu *iommu) tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET); while (head != tail) { - iommu_print_event(iommu->evt_buf + head); + iommu_print_event(iommu, iommu->evt_buf + head); head = (head + EVENT_ENTRY_SIZE) % iommu->evt_buf_size; } @@ -547,6 +549,15 @@ void amd_iommu_flush_all_devices(void) } } +static void reset_iommu_command_buffer(struct amd_iommu *iommu) +{ + pr_err("AMD-Vi: Resetting IOMMU command buffer\n"); + + amd_iommu_reset_cmd_buffer(iommu); + flush_all_devices_for_iommu(iommu); + flush_all_domains_on_iommu(iommu); +} + /**************************************************************************** * * The functions below are used the create the page table mappings for -- cgit v0.10.2 From b26e81b871bd18184968f0bb3f12945906eadfce Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 3 Sep 2009 15:08:09 +0200 Subject: x86/amd-iommu: Panic if IOMMU command buffer reset fails To prevent the driver from doing recursive command buffer resets, just panic when that recursion happens. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index c54bc979..e676746 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -337,6 +337,9 @@ struct amd_iommu { /* if one, we need to send a completion wait command */ bool need_sync; + /* becomes true if a command buffer reset is running */ + bool reset_in_progress; + /* default dma_ops domain for that IOMMU */ struct dma_ops_domain *default_dom; }; diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 2333d61..b62a2f6 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -553,9 +553,16 @@ static void reset_iommu_command_buffer(struct amd_iommu *iommu) { pr_err("AMD-Vi: Resetting IOMMU command buffer\n"); + if (iommu->reset_in_progress) + panic("AMD-Vi: ILLEGAL_COMMAND_ERROR while resetting command buffer\n"); + + iommu->reset_in_progress = true; + amd_iommu_reset_cmd_buffer(iommu); flush_all_devices_for_iommu(iommu); flush_all_domains_on_iommu(iommu); + + iommu->reset_in_progress = false; } /**************************************************************************** -- cgit v0.10.2 From 6a1eddd2f951656a6abbd42e2cddc2267c4a639d Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 3 Sep 2009 15:15:10 +0200 Subject: x86/amd-iommu: Reset command buffer if wait loop fails Instead of a panic on an comletion wait loop failure, try to recover from that event from resetting the command buffer. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index b62a2f6..cfca80b 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -318,8 +318,11 @@ static void __iommu_wait_for_completion(struct amd_iommu *iommu) status &= ~MMIO_STATUS_COM_WAIT_INT_MASK; writel(status, iommu->mmio_base + MMIO_STATUS_OFFSET); - if (unlikely(i == EXIT_LOOP_COUNT)) - panic("AMD IOMMU: Completion wait loop failed\n"); + if (unlikely(i == EXIT_LOOP_COUNT)) { + spin_unlock(&iommu->lock); + reset_iommu_command_buffer(iommu); + spin_lock(&iommu->lock); + } } /* -- cgit v0.10.2 From c631d03c6873b9e17906556e84fcafc42f26a7c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 3 Sep 2009 15:59:26 +0200 Subject: ALSA: dummy - Support high-res timer mode Allow snd-dummy driver to use high-res timer as its timing source instead of the system timer. The new module option "hrtimer" is added to turn on/off the high-res timer support. It can be switched even dynamically via sysfs. Signed-off-by: Takashi Iwai diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 54239d2..f387d53 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -148,6 +150,9 @@ static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; +#ifdef CONFIG_HIGH_RES_TIMERS +static int hrtimer = 1; +#endif module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for dummy soundcard."); @@ -161,6 +166,10 @@ 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."); +#ifdef CONFIG_HIGH_RES_TIMERS +module_param(hrtimer, bool, 0644); +MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source."); +#endif static struct platform_device *devices[SNDRV_CARDS]; @@ -171,16 +180,29 @@ static struct platform_device *devices[SNDRV_CARDS]; #define MIXER_ADDR_CD 4 #define MIXER_ADDR_LAST 4 +struct dummy_timer_ops { + int (*create)(struct snd_pcm_substream *); + void (*free)(struct snd_pcm_substream *); + int (*prepare)(struct snd_pcm_substream *); + int (*start)(struct snd_pcm_substream *); + int (*stop)(struct snd_pcm_substream *); + snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); +}; + struct snd_dummy { struct snd_card *card; struct snd_pcm *pcm; spinlock_t mixer_lock; int mixer_volume[MIXER_ADDR_LAST+1][2]; int capture_source[MIXER_ADDR_LAST+1][2]; + const struct dummy_timer_ops *timer_ops; }; -struct snd_dummy_pcm { - struct snd_dummy *dummy; +/* + * system timer interface + */ + +struct dummy_systimer_pcm { spinlock_t lock; struct timer_list timer; unsigned int pcm_buffer_size; @@ -192,46 +214,29 @@ struct snd_dummy_pcm { struct snd_pcm_substream *substream; }; - -static inline void snd_card_dummy_pcm_timer_start(struct snd_dummy_pcm *dpcm) +static int dummy_systimer_start(struct snd_pcm_substream *substream) { + struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; + spin_lock(&dpcm->lock); dpcm->timer.expires = 1 + jiffies; add_timer(&dpcm->timer); + spin_unlock(&dpcm->lock); + return 0; } -static inline void snd_card_dummy_pcm_timer_stop(struct snd_dummy_pcm *dpcm) -{ - del_timer(&dpcm->timer); -} - -static int snd_card_dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int dummy_systimer_stop(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dummy_pcm *dpcm = runtime->private_data; - int err = 0; - + struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; spin_lock(&dpcm->lock); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - snd_card_dummy_pcm_timer_start(dpcm); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - snd_card_dummy_pcm_timer_stop(dpcm); - break; - default: - err = -EINVAL; - break; - } + del_timer(&dpcm->timer); spin_unlock(&dpcm->lock); return 0; } -static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream) +static int dummy_systimer_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dummy_pcm *dpcm = runtime->private_data; + struct dummy_systimer_pcm *dpcm = runtime->private_data; int bps; bps = snd_pcm_format_width(runtime->format) * runtime->rate * @@ -247,15 +252,12 @@ static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream) dpcm->pcm_irq_pos = 0; dpcm->pcm_buf_pos = 0; - snd_pcm_format_set_silence(runtime->format, runtime->dma_area, - bytes_to_samples(runtime, runtime->dma_bytes)); - return 0; } -static void snd_card_dummy_pcm_timer_function(unsigned long data) +static void dummy_systimer_callback(unsigned long data) { - struct snd_dummy_pcm *dpcm = (struct snd_dummy_pcm *)data; + struct dummy_systimer_pcm *dpcm = (struct dummy_systimer_pcm *)data; unsigned long flags; spin_lock_irqsave(&dpcm->lock, flags); @@ -272,36 +274,212 @@ static void snd_card_dummy_pcm_timer_function(unsigned long data) spin_unlock_irqrestore(&dpcm->lock, flags); } -static snd_pcm_uframes_t snd_card_dummy_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t +dummy_systimer_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dummy_pcm *dpcm = runtime->private_data; + struct dummy_systimer_pcm *dpcm = runtime->private_data; return bytes_to_frames(runtime, dpcm->pcm_buf_pos / dpcm->pcm_hz); } -static struct snd_pcm_hardware snd_card_dummy_playback = +static int dummy_systimer_create(struct snd_pcm_substream *substream) { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), - .formats = USE_FORMATS, - .rates = USE_RATE, - .rate_min = USE_RATE_MIN, - .rate_max = USE_RATE_MAX, - .channels_min = USE_CHANNELS_MIN, - .channels_max = USE_CHANNELS_MAX, - .buffer_bytes_max = MAX_BUFFER_SIZE, - .period_bytes_min = 64, - .period_bytes_max = MAX_PERIOD_SIZE, - .periods_min = USE_PERIODS_MIN, - .periods_max = USE_PERIODS_MAX, - .fifo_size = 0, + struct dummy_systimer_pcm *dpcm; + + dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); + if (!dpcm) + return -ENOMEM; + substream->runtime->private_data = dpcm; + init_timer(&dpcm->timer); + dpcm->timer.data = (unsigned long) dpcm; + dpcm->timer.function = dummy_systimer_callback; + spin_lock_init(&dpcm->lock); + dpcm->substream = substream; + return 0; +} + +static void dummy_systimer_free(struct snd_pcm_substream *substream) +{ + kfree(substream->runtime->private_data); +} + +static struct dummy_timer_ops dummy_systimer_ops = { + .create = dummy_systimer_create, + .free = dummy_systimer_free, + .prepare = dummy_systimer_prepare, + .start = dummy_systimer_start, + .stop = dummy_systimer_stop, + .pointer = dummy_systimer_pointer, +}; + +#ifdef CONFIG_HIGH_RES_TIMERS +/* + * hrtimer interface + */ + +struct dummy_hrtimer_pcm { + ktime_t base_time; + ktime_t period_time; + atomic_t running; + struct hrtimer timer; + struct tasklet_struct tasklet; + struct snd_pcm_substream *substream; +}; + +static void dummy_hrtimer_pcm_elapsed(unsigned long priv) +{ + struct dummy_hrtimer_pcm *dpcm = (struct dummy_hrtimer_pcm *)priv; + if (atomic_read(&dpcm->running)) + snd_pcm_period_elapsed(dpcm->substream); +} + +static enum hrtimer_restart dummy_hrtimer_callback(struct hrtimer *timer) +{ + struct dummy_hrtimer_pcm *dpcm; + + dpcm = container_of(timer, struct dummy_hrtimer_pcm, timer); + if (!atomic_read(&dpcm->running)) + return HRTIMER_NORESTART; + tasklet_schedule(&dpcm->tasklet); + hrtimer_forward_now(timer, dpcm->period_time); + return HRTIMER_RESTART; +} + +static int dummy_hrtimer_start(struct snd_pcm_substream *substream) +{ + struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data; + + dpcm->base_time = hrtimer_cb_get_time(&dpcm->timer); + hrtimer_start(&dpcm->timer, dpcm->period_time, HRTIMER_MODE_REL); + atomic_set(&dpcm->running, 1); + return 0; +} + +static int dummy_hrtimer_stop(struct snd_pcm_substream *substream) +{ + struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data; + + atomic_set(&dpcm->running, 0); + hrtimer_cancel(&dpcm->timer); + return 0; +} + +static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm) +{ + tasklet_kill(&dpcm->tasklet); +} + +static snd_pcm_uframes_t +dummy_hrtimer_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct dummy_hrtimer_pcm *dpcm = runtime->private_data; + u64 delta; + u32 pos; + + delta = ktime_us_delta(hrtimer_cb_get_time(&dpcm->timer), + dpcm->base_time); + delta = div_u64(delta * runtime->rate + 999999, 1000000); + div_u64_rem(delta, runtime->buffer_size, &pos); + return pos; +} + +static int dummy_hrtimer_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct dummy_hrtimer_pcm *dpcm = runtime->private_data; + unsigned int period, rate; + long sec; + unsigned long nsecs; + + dummy_hrtimer_sync(dpcm); + period = runtime->period_size; + rate = runtime->rate; + sec = period / rate; + period %= rate; + nsecs = div_u64((u64)period * 1000000000UL + rate - 1, rate); + dpcm->period_time = ktime_set(sec, nsecs); + + return 0; +} + +static int dummy_hrtimer_create(struct snd_pcm_substream *substream) +{ + struct dummy_hrtimer_pcm *dpcm; + + dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); + if (!dpcm) + return -ENOMEM; + substream->runtime->private_data = dpcm; + hrtimer_init(&dpcm->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + dpcm->timer.function = dummy_hrtimer_callback; + dpcm->substream = substream; + atomic_set(&dpcm->running, 0); + tasklet_init(&dpcm->tasklet, dummy_hrtimer_pcm_elapsed, + (unsigned long)dpcm); + return 0; +} + +static void dummy_hrtimer_free(struct snd_pcm_substream *substream) +{ + struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data; + dummy_hrtimer_sync(dpcm); + kfree(dpcm); +} + +static struct dummy_timer_ops dummy_hrtimer_ops = { + .create = dummy_hrtimer_create, + .free = dummy_hrtimer_free, + .prepare = dummy_hrtimer_prepare, + .start = dummy_hrtimer_start, + .stop = dummy_hrtimer_stop, + .pointer = dummy_hrtimer_pointer, }; -static struct snd_pcm_hardware snd_card_dummy_capture = +#endif /* CONFIG_HIGH_RES_TIMERS */ + +/* + * PCM interface + */ + +static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_dummy *dummy = snd_pcm_substream_chip(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + return dummy->timer_ops->start(substream); + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + return dummy->timer_ops->stop(substream); + } + return -EINVAL; +} + +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); +} + +static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream) { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), + struct snd_dummy *dummy = snd_pcm_substream_chip(substream); + + return dummy->timer_ops->pointer(substream); +} + +static struct snd_pcm_hardware dummy_pcm_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_MMAP_VALID), .formats = USE_FORMATS, .rates = USE_RATE, .rate_min = USE_RATE_MIN, @@ -316,117 +494,70 @@ static struct snd_pcm_hardware snd_card_dummy_capture = .fifo_size = 0, }; -static void snd_card_dummy_runtime_free(struct snd_pcm_runtime *runtime) -{ - kfree(runtime->private_data); -} - -static int snd_card_dummy_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) +static int dummy_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); } -static int snd_card_dummy_hw_free(struct snd_pcm_substream *substream) +static int dummy_pcm_hw_free(struct snd_pcm_substream *substream) { return snd_pcm_lib_free_pages(substream); } -static struct snd_dummy_pcm *new_pcm_stream(struct snd_pcm_substream *substream) -{ - struct snd_dummy_pcm *dpcm; - - dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); - if (! dpcm) - return dpcm; - init_timer(&dpcm->timer); - dpcm->timer.data = (unsigned long) dpcm; - dpcm->timer.function = snd_card_dummy_pcm_timer_function; - spin_lock_init(&dpcm->lock); - dpcm->substream = substream; - return dpcm; -} - -static int snd_card_dummy_playback_open(struct snd_pcm_substream *substream) +static int dummy_pcm_open(struct snd_pcm_substream *substream) { + struct snd_dummy *dummy = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dummy_pcm *dpcm; int err; - if ((dpcm = new_pcm_stream(substream)) == NULL) - return -ENOMEM; - runtime->private_data = dpcm; - /* makes the infrastructure responsible for freeing dpcm */ - runtime->private_free = snd_card_dummy_runtime_free; - runtime->hw = snd_card_dummy_playback; - if (substream->pcm->device & 1) { - runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; - runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; - } - if (substream->pcm->device & 2) - runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID); - err = add_playback_constraints(runtime); + dummy->timer_ops = &dummy_systimer_ops; +#ifdef CONFIG_HIGH_RES_TIMERS + if (hrtimer) + dummy->timer_ops = &dummy_hrtimer_ops; +#endif + + err = dummy->timer_ops->create(substream); if (err < 0) return err; - return 0; -} - -static int snd_card_dummy_capture_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dummy_pcm *dpcm; - int err; - - if ((dpcm = new_pcm_stream(substream)) == NULL) - return -ENOMEM; - runtime->private_data = dpcm; - /* makes the infrastructure responsible for freeing dpcm */ - runtime->private_free = snd_card_dummy_runtime_free; - runtime->hw = snd_card_dummy_capture; - if (substream->pcm->device == 1) { + runtime->hw = dummy_pcm_hardware; + if (substream->pcm->device & 1) { runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; } if (substream->pcm->device & 2) - runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID); - err = add_capture_constraints(runtime); - if (err < 0) + runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + err = add_playback_constraints(substream->runtime); + else + err = add_capture_constraints(substream->runtime); + if (err < 0) { + dummy->timer_ops->free(substream); return err; - - return 0; -} - -static int snd_card_dummy_playback_close(struct snd_pcm_substream *substream) -{ + } return 0; } -static int snd_card_dummy_capture_close(struct snd_pcm_substream *substream) +static int dummy_pcm_close(struct snd_pcm_substream *substream) { + struct snd_dummy *dummy = snd_pcm_substream_chip(substream); + dummy->timer_ops->free(substream); return 0; } -static struct snd_pcm_ops snd_card_dummy_playback_ops = { - .open = snd_card_dummy_playback_open, - .close = snd_card_dummy_playback_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_card_dummy_hw_params, - .hw_free = snd_card_dummy_hw_free, - .prepare = snd_card_dummy_pcm_prepare, - .trigger = snd_card_dummy_pcm_trigger, - .pointer = snd_card_dummy_pcm_pointer, -}; - -static struct snd_pcm_ops snd_card_dummy_capture_ops = { - .open = snd_card_dummy_capture_open, - .close = snd_card_dummy_capture_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_card_dummy_hw_params, - .hw_free = snd_card_dummy_hw_free, - .prepare = snd_card_dummy_pcm_prepare, - .trigger = snd_card_dummy_pcm_trigger, - .pointer = snd_card_dummy_pcm_pointer, +static struct snd_pcm_ops dummy_pcm_ops = { + .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, }; static int __devinit snd_card_dummy_pcm(struct snd_dummy *dummy, int device, @@ -440,8 +571,8 @@ 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, &snd_card_dummy_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_dummy_capture_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dummy_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &dummy_pcm_ops); pcm->private_data = dummy; pcm->info_flags = 0; strcpy(pcm->name, "Dummy PCM"); -- cgit v0.10.2 From b142037b4c1edf5ad0b2871c518d4f14ac1cd470 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 3 Sep 2009 16:01:06 +0200 Subject: ALSA: dummy - Better jiffies handling In the system-timer mode, snd-dummy driver issues each tick to update the position. This is highly inefficient and even inaccurate if the timer can't be triggered at each tick. Now rewritten to wake up only at the period boundary. The position is calculated from the current jiffies. Signed-off-by: Takashi Iwai diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index f387d53..0a798bd 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -205,21 +205,43 @@ struct snd_dummy { struct dummy_systimer_pcm { spinlock_t lock; struct timer_list timer; - unsigned int pcm_buffer_size; - unsigned int pcm_period_size; - unsigned int pcm_bps; /* bytes per second */ - unsigned int pcm_hz; /* HZ */ - unsigned int pcm_irq_pos; /* IRQ position */ - unsigned int pcm_buf_pos; /* position in buffer */ + unsigned long base_time; + unsigned int frac_pos; /* fractional sample position (based HZ) */ + unsigned int frac_buffer_size; /* buffer_size * HZ */ + unsigned int frac_period_size; /* period_size * HZ */ + unsigned int rate; struct snd_pcm_substream *substream; }; +static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm) +{ + unsigned long frac; + + frac = dpcm->frac_pos % dpcm->frac_period_size; + dpcm->timer.expires = jiffies + + (dpcm->frac_period_size + dpcm->rate - 1) / dpcm->rate; + add_timer(&dpcm->timer); +} + +static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm) +{ + unsigned long delta; + + delta = jiffies - dpcm->base_time; + if (!delta) + return; + dpcm->base_time = jiffies; + dpcm->frac_pos += delta * dpcm->rate; + while (dpcm->frac_pos >= dpcm->frac_buffer_size) + dpcm->frac_pos -= dpcm->frac_buffer_size; +} + static int dummy_systimer_start(struct snd_pcm_substream *substream) { struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; spin_lock(&dpcm->lock); - dpcm->timer.expires = 1 + jiffies; - add_timer(&dpcm->timer); + dpcm->base_time = jiffies; + dummy_systimer_rearm(dpcm); spin_unlock(&dpcm->lock); return 0; } @@ -237,20 +259,11 @@ static int dummy_systimer_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct dummy_systimer_pcm *dpcm = runtime->private_data; - int bps; - bps = snd_pcm_format_width(runtime->format) * runtime->rate * - runtime->channels / 8; - - if (bps <= 0) - return -EINVAL; - - dpcm->pcm_bps = bps; - dpcm->pcm_hz = HZ; - dpcm->pcm_buffer_size = snd_pcm_lib_buffer_bytes(substream); - dpcm->pcm_period_size = snd_pcm_lib_period_bytes(substream); - dpcm->pcm_irq_pos = 0; - dpcm->pcm_buf_pos = 0; + dpcm->frac_pos = 0; + dpcm->rate = runtime->rate; + dpcm->frac_buffer_size = runtime->buffer_size * HZ; + dpcm->frac_period_size = runtime->period_size * HZ; return 0; } @@ -261,26 +274,21 @@ static void dummy_systimer_callback(unsigned long data) unsigned long flags; spin_lock_irqsave(&dpcm->lock, flags); - dpcm->timer.expires = 1 + jiffies; - add_timer(&dpcm->timer); - dpcm->pcm_irq_pos += dpcm->pcm_bps; - dpcm->pcm_buf_pos += dpcm->pcm_bps; - dpcm->pcm_buf_pos %= dpcm->pcm_buffer_size * dpcm->pcm_hz; - if (dpcm->pcm_irq_pos >= dpcm->pcm_period_size * dpcm->pcm_hz) { - dpcm->pcm_irq_pos %= dpcm->pcm_period_size * dpcm->pcm_hz; - spin_unlock_irqrestore(&dpcm->lock, flags); - snd_pcm_period_elapsed(dpcm->substream); - } else - spin_unlock_irqrestore(&dpcm->lock, flags); + dummy_systimer_update(dpcm); + dummy_systimer_rearm(dpcm); + spin_unlock_irqrestore(&dpcm->lock, flags); + snd_pcm_period_elapsed(dpcm->substream); } static snd_pcm_uframes_t dummy_systimer_pointer(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct dummy_systimer_pcm *dpcm = runtime->private_data; + struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; - return bytes_to_frames(runtime, dpcm->pcm_buf_pos / dpcm->pcm_hz); + spin_lock(&dpcm->lock); + dummy_systimer_update(dpcm); + spin_unlock(&dpcm->lock); + return dpcm->frac_pos / HZ; } static int dummy_systimer_create(struct snd_pcm_substream *substream) -- cgit v0.10.2 From 9355a08186e52b7c120adea91c984923b54efa10 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 14:24:08 +0200 Subject: x86/amd-iommu: Make fetch_pte aware of dynamic mapping levels This patch changes the fetch_pte function in the AMD IOMMU driver to support dynamic mapping levels. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 0c878ca..7fce4ef 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -146,12 +146,21 @@ #define PAGE_MODE_1_LEVEL 0x01 #define PAGE_MODE_2_LEVEL 0x02 #define PAGE_MODE_3_LEVEL 0x03 +#define PAGE_MODE_4_LEVEL 0x04 +#define PAGE_MODE_5_LEVEL 0x05 +#define PAGE_MODE_6_LEVEL 0x06 #define IOMMU_PDE_NL_0 0x000ULL #define IOMMU_PDE_NL_1 0x200ULL #define IOMMU_PDE_NL_2 0x400ULL #define IOMMU_PDE_NL_3 0x600ULL +#define PM_LEVEL_SHIFT(x) (12 + ((x) * 9)) +#define PM_LEVEL_SIZE(x) (((x) < 6) ? \ + ((1ULL << PM_LEVEL_SHIFT((x))) - 1): \ + (0xffffffffffffffffULL)) +#define PM_LEVEL_INDEX(x, a) (((a) >> PM_LEVEL_SHIFT((x))) & 0x1ffULL) + #define IOMMU_PTE_L2_INDEX(address) (((address) >> 30) & 0x1ffULL) #define IOMMU_PTE_L1_INDEX(address) (((address) >> 21) & 0x1ffULL) #define IOMMU_PTE_L0_INDEX(address) (((address) >> 12) & 0x1ffULL) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 6c99f50..29bcd35 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -61,6 +61,8 @@ static u64* alloc_pte(struct protection_domain *dom, static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, unsigned long start_page, unsigned int pages); +static u64 *fetch_pte(struct protection_domain *domain, + unsigned long address); #ifndef BUS_NOTIFY_UNBOUND_DRIVER #define BUS_NOTIFY_UNBOUND_DRIVER 0x0005 @@ -670,24 +672,24 @@ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom, * This function checks if there is a PTE for a given dma address. If * there is one, it returns the pointer to it. */ -static u64* fetch_pte(struct protection_domain *domain, +static u64 *fetch_pte(struct protection_domain *domain, unsigned long address) { + int level; u64 *pte; - pte = &domain->pt_root[IOMMU_PTE_L2_INDEX(address)]; + level = domain->mode - 1; + pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)]; - if (!IOMMU_PTE_PRESENT(*pte)) - return NULL; + while (level > 0) { + if (!IOMMU_PTE_PRESENT(*pte)) + return NULL; - pte = IOMMU_PTE_PAGE(*pte); - pte = &pte[IOMMU_PTE_L1_INDEX(address)]; + level -= 1; - if (!IOMMU_PTE_PRESENT(*pte)) - return NULL; - - pte = IOMMU_PTE_PAGE(*pte); - pte = &pte[IOMMU_PTE_L0_INDEX(address)]; + pte = IOMMU_PTE_PAGE(*pte); + pte = &pte[PM_LEVEL_INDEX(level, address)]; + } return pte; } -- cgit v0.10.2 From 38a76eeeafb251bf67d143a34b37a8105cff302e Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 17:02:47 +0200 Subject: x86/amd-iommu: Use fetch_pte in iommu_unmap_page Instead of reimplementing existing logic use fetch_pte to walk the page table in iommu_unmap_page. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 29bcd35..5e52798 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -546,23 +546,10 @@ static int iommu_map_page(struct protection_domain *dom, static void iommu_unmap_page(struct protection_domain *dom, unsigned long bus_addr) { - u64 *pte; - - pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(bus_addr)]; - - if (!IOMMU_PTE_PRESENT(*pte)) - return; - - pte = IOMMU_PTE_PAGE(*pte); - pte = &pte[IOMMU_PTE_L1_INDEX(bus_addr)]; - - if (!IOMMU_PTE_PRESENT(*pte)) - return; - - pte = IOMMU_PTE_PAGE(*pte); - pte = &pte[IOMMU_PTE_L1_INDEX(bus_addr)]; + u64 *pte = fetch_pte(dom, bus_addr); - *pte = 0; + if (pte) + *pte = 0; } /* -- cgit v0.10.2 From a6d41a4027b758a9473197a78fab45afb31003aa Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 17:08:55 +0200 Subject: x86/amd-iommu: Use fetch_pte in amd_iommu_iova_to_phys Don't reimplement the page table walker in this function. Use the generic one. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 5e52798..4a54366 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -2140,21 +2140,9 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom, phys_addr_t paddr; u64 *pte; - pte = &domain->pt_root[IOMMU_PTE_L2_INDEX(iova)]; + pte = fetch_pte(domain, iova); - if (!IOMMU_PTE_PRESENT(*pte)) - return 0; - - pte = IOMMU_PTE_PAGE(*pte); - pte = &pte[IOMMU_PTE_L1_INDEX(iova)]; - - if (!IOMMU_PTE_PRESENT(*pte)) - return 0; - - pte = IOMMU_PTE_PAGE(*pte); - pte = &pte[IOMMU_PTE_L0_INDEX(iova)]; - - if (!IOMMU_PTE_PRESENT(*pte)) + if (!pte || !IOMMU_PTE_PRESENT(*pte)) return 0; paddr = *pte & IOMMU_PAGE_MASK; -- cgit v0.10.2 From 6a0dbcbe4e612fbc9d73cd4dde8ebef19295058a Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 15:41:59 +0200 Subject: x86/amd-iommu: Add a gneric version of amd_iommu_flush_all_devices This patch adds a generic variant of amd_iommu_flush_all_devices function which flushes only the DTEs for a given protection domain. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 4a54366..5265dd17 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -481,13 +481,14 @@ void amd_iommu_flush_all_domains(void) } } -void amd_iommu_flush_all_devices(void) +static void flush_devices_by_domain(struct protection_domain *domain) { struct amd_iommu *iommu; int i; for (i = 0; i <= amd_iommu_last_bdf; ++i) { - if (amd_iommu_pd_table[i] == NULL) + if ((domain == NULL && amd_iommu_pd_table[i] == NULL) || + (amd_iommu_pd_table[i] != domain)) continue; iommu = amd_iommu_rlookup_table[i]; @@ -499,6 +500,11 @@ void amd_iommu_flush_all_devices(void) } } +void amd_iommu_flush_all_devices(void) +{ + flush_devices_by_domain(NULL); +} + /**************************************************************************** * * The functions below are used the create the page table mappings for -- cgit v0.10.2 From 407d733e30a97daf5ea6f9eb5f9ebbd42a0a9ef2 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 16:07:00 +0200 Subject: x86/amd-iommu: Introduce set_dte_entry function This function factors out some logic of attach_device to a seperate function. This new function will be used to update device table entries when necessary. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 5265dd17..0fab1f1 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1058,18 +1058,10 @@ static struct protection_domain *domain_for_device(u16 devid) return dom; } -/* - * If a device is not yet associated with a domain, this function does - * assigns it visible for the hardware - */ -static void attach_device(struct amd_iommu *iommu, - struct protection_domain *domain, - u16 devid) +static void set_dte_entry(u16 devid, struct protection_domain *domain) { - unsigned long flags; u64 pte_root = virt_to_phys(domain->pt_root); - - domain->dev_cnt += 1; + unsigned long flags; pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK) << DEV_ENTRY_MODE_SHIFT; @@ -1082,6 +1074,21 @@ static void attach_device(struct amd_iommu *iommu, amd_iommu_pd_table[devid] = domain; write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); +} + +/* + * If a device is not yet associated with a domain, this function does + * assigns it visible for the hardware + */ +static void attach_device(struct amd_iommu *iommu, + struct protection_domain *domain, + u16 devid) +{ + /* set the DTE entry */ + set_dte_entry(devid, domain); + + /* increase reference counter */ + domain->dev_cnt += 1; /* * We might boot into a crash-kernel here. The crashed kernel -- cgit v0.10.2 From 04bfdd8406099fca2e6b8844748c4d6c5eba8c8d Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 16:00:23 +0200 Subject: x86/amd-iommu: Flush domains if address space size was increased Thist patch introduces the update_domain function which propagates the larger address space of a protection domain to the device table and flushes all relevant DTEs and the domain TLB. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 7fce4ef..97f3d09 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -235,6 +235,7 @@ struct protection_domain { int mode; /* paging mode (0-6 levels) */ u64 *pt_root; /* page table root pointer */ unsigned long flags; /* flags to find out type of domain */ + bool updated; /* complete domain flush required */ unsigned dev_cnt; /* devices assigned to this domain */ void *priv; /* private data */ }; diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 0fab1f1..5eab6a8 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -63,6 +63,7 @@ static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, unsigned int pages); static u64 *fetch_pte(struct protection_domain *domain, unsigned long address); +static void update_domain(struct protection_domain *domain); #ifndef BUS_NOTIFY_UNBOUND_DRIVER #define BUS_NOTIFY_UNBOUND_DRIVER 0x0005 @@ -546,6 +547,8 @@ static int iommu_map_page(struct protection_domain *dom, *pte = __pte; + update_domain(dom); + return 0; } @@ -762,9 +765,13 @@ static int alloc_new_range(struct amd_iommu *iommu, dma_ops_reserve_addresses(dma_dom, i << PAGE_SHIFT, 1); } + update_domain(&dma_dom->domain); + return 0; out_free: + update_domain(&dma_dom->domain); + free_page((unsigned long)dma_dom->aperture[index]->bitmap); kfree(dma_dom->aperture[index]); @@ -1294,6 +1301,29 @@ static int get_device_resources(struct device *dev, return 1; } +static void update_device_table(struct protection_domain *domain) +{ + int i; + + for (i = 0; i <= amd_iommu_last_bdf; ++i) { + if (amd_iommu_pd_table[i] != domain) + continue; + set_dte_entry(i, domain); + } +} + +static void update_domain(struct protection_domain *domain) +{ + if (!domain->updated) + return; + + update_device_table(domain); + flush_devices_by_domain(domain); + iommu_flush_domain(domain->id); + + domain->updated = false; +} + /* * If the pte_page is not yet allocated this function is called */ @@ -1351,6 +1381,8 @@ static u64* dma_ops_get_pte(struct dma_ops_domain *dom, } else pte += IOMMU_PTE_L0_INDEX(address); + update_domain(&dom->domain); + return pte; } -- cgit v0.10.2 From 50020fb6324465e478d6c8cdbf3c695f0a60358d Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 15:38:40 +0200 Subject: x86/amd-iommu: Introduce increase_address_space function This function will be used to increase the address space size of a protection domain. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 97f3d09..1b4b3d6 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -160,6 +160,10 @@ ((1ULL << PM_LEVEL_SHIFT((x))) - 1): \ (0xffffffffffffffffULL)) #define PM_LEVEL_INDEX(x, a) (((a) >> PM_LEVEL_SHIFT((x))) & 0x1ffULL) +#define PM_LEVEL_ENC(x) (((x) << 9) & 0xe00ULL) +#define PM_LEVEL_PDE(x, a) ((a) | PM_LEVEL_ENC((x)) | \ + IOMMU_PTE_P | IOMMU_PTE_IR | IOMMU_PTE_IW) + #define IOMMU_PTE_L2_INDEX(address) (((address) >> 30) & 0x1ffULL) #define IOMMU_PTE_L1_INDEX(address) (((address) >> 21) & 0x1ffULL) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 5eab6a8..fc97b51 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1325,6 +1325,33 @@ static void update_domain(struct protection_domain *domain) } /* + * This function is used to add another level to an IO page table. Adding + * another level increases the size of the address space by 9 bits to a size up + * to 64 bits. + */ +static bool increase_address_space(struct protection_domain *domain, + gfp_t gfp) +{ + u64 *pte; + + if (domain->mode == PAGE_MODE_6_LEVEL) + /* address space already 64 bit large */ + return false; + + pte = (void *)get_zeroed_page(gfp); + if (!pte) + return false; + + *pte = PM_LEVEL_PDE(domain->mode, + virt_to_phys(domain->pt_root)); + domain->pt_root = pte; + domain->mode += 1; + domain->updated = true; + + return true; +} + +/* * If the pte_page is not yet allocated this function is called */ static u64* alloc_pte(struct protection_domain *dom, -- cgit v0.10.2 From 8bc3e127421bf3b735edbde05135892c12c5f615 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 16:48:40 +0200 Subject: x86/amd-iommu: Change alloc_pte to support 64 bit address space This patch changes the alloc_pte function to be able to map pages into the whole 64 bit address space supported by AMD IOMMU hardware from the old limit of 2**39 bytes. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index fc97b51..3be2b61 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -55,7 +55,7 @@ struct iommu_cmd { static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, struct unity_map_entry *e); static struct dma_ops_domain *find_protection_domain(u16 devid); -static u64* alloc_pte(struct protection_domain *dom, +static u64 *alloc_pte(struct protection_domain *domain, unsigned long address, u64 **pte_page, gfp_t gfp); static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, @@ -1351,39 +1351,35 @@ static bool increase_address_space(struct protection_domain *domain, return true; } -/* - * If the pte_page is not yet allocated this function is called - */ -static u64* alloc_pte(struct protection_domain *dom, +static u64 *alloc_pte(struct protection_domain *domain, unsigned long address, u64 **pte_page, gfp_t gfp) { u64 *pte, *page; + int level; - pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(address)]; + while (address > PM_LEVEL_SIZE(domain->mode)) + increase_address_space(domain, gfp); - if (!IOMMU_PTE_PRESENT(*pte)) { - page = (u64 *)get_zeroed_page(gfp); - if (!page) - return NULL; - *pte = IOMMU_L2_PDE(virt_to_phys(page)); - } + level = domain->mode - 1; + pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)]; - pte = IOMMU_PTE_PAGE(*pte); - pte = &pte[IOMMU_PTE_L1_INDEX(address)]; + while (level > 0) { + if (!IOMMU_PTE_PRESENT(*pte)) { + page = (u64 *)get_zeroed_page(gfp); + if (!page) + return NULL; + *pte = PM_LEVEL_PDE(level, virt_to_phys(page)); + } - if (!IOMMU_PTE_PRESENT(*pte)) { - page = (u64 *)get_zeroed_page(gfp); - if (!page) - return NULL; - *pte = IOMMU_L1_PDE(virt_to_phys(page)); - } + level -= 1; - pte = IOMMU_PTE_PAGE(*pte); + pte = IOMMU_PTE_PAGE(*pte); - if (pte_page) - *pte_page = pte; + if (pte_page && level == 0) + *pte_page = pte; - pte = &pte[IOMMU_PTE_L0_INDEX(address)]; + pte = &pte[PM_LEVEL_INDEX(level, address)]; + } return pte; } -- cgit v0.10.2 From 8c8c143cdc95ebe50fd962917556e25e8912997b Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 17:30:00 +0200 Subject: x86/amd-iommu: Remove last usages of IOMMU_PTE_L0_INDEX This change allows to remove these old macros later. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 3be2b61..ebc1c84 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1402,7 +1402,7 @@ static u64* dma_ops_get_pte(struct dma_ops_domain *dom, pte = alloc_pte(&dom->domain, address, &pte_page, GFP_ATOMIC); aperture->pte_pages[APERTURE_PAGE_INDEX(address)] = pte_page; } else - pte += IOMMU_PTE_L0_INDEX(address); + pte += PM_LEVEL_INDEX(0, address); update_domain(&dom->domain); @@ -1466,7 +1466,7 @@ static void dma_ops_domain_unmap(struct amd_iommu *iommu, if (!pte) return; - pte += IOMMU_PTE_L0_INDEX(address); + pte += PM_LEVEL_INDEX(0, address); WARN_ON(!*pte); -- cgit v0.10.2 From bad1cac28a707c69301a4d0612da9ccbecd51953 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 16:52:23 +0200 Subject: x86/amd-iommu: Remove bus_addr check in iommu_map_page The driver now supports full 64 bit device address spaces. So this check is not longer required. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index ebc1c84..6ffb3e6 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -530,8 +530,7 @@ static int iommu_map_page(struct protection_domain *dom, bus_addr = PAGE_ALIGN(bus_addr); phys_addr = PAGE_ALIGN(phys_addr); - /* only support 512GB address spaces for now */ - if (bus_addr > IOMMU_MAP_SIZE_L3 || !(prot & IOMMU_PROT_MASK)) + if (!(prot & IOMMU_PROT_MASK)) return -EINVAL; pte = alloc_pte(dom, bus_addr, NULL, GFP_KERNEL); -- cgit v0.10.2 From 8f7a017ce05ed4522809448e169daa44fe6edeb1 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 16:55:24 +0200 Subject: x86/amd-iommu: Use 2-level page tables for dma_ops domains The driver now supports a dynamic number of levels for IO page tables. This allows to reduce the number of levels for dma_ops domains by one because a dma_ops domain has usually an address space size between 128MB and 4G. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 6ffb3e6..addf658 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1010,7 +1010,7 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu) dma_dom->domain.id = domain_id_alloc(); if (dma_dom->domain.id == 0) goto free_dma_dom; - dma_dom->domain.mode = PAGE_MODE_3_LEVEL; + dma_dom->domain.mode = PAGE_MODE_2_LEVEL; dma_dom->domain.pt_root = (void *)get_zeroed_page(GFP_KERNEL); dma_dom->domain.flags = PD_DMA_OPS_MASK; dma_dom->domain.priv = dma_dom; -- cgit v0.10.2 From 674d798a80cb6ea1defa01899099f40d9124423c Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 2 Sep 2009 17:26:09 +0200 Subject: x86/amd-iommu: Remove old page table handling macros These macros are not longer required. So remove them. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 1b4b3d6..d66430d 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -150,11 +150,6 @@ #define PAGE_MODE_5_LEVEL 0x05 #define PAGE_MODE_6_LEVEL 0x06 -#define IOMMU_PDE_NL_0 0x000ULL -#define IOMMU_PDE_NL_1 0x200ULL -#define IOMMU_PDE_NL_2 0x400ULL -#define IOMMU_PDE_NL_3 0x600ULL - #define PM_LEVEL_SHIFT(x) (12 + ((x) * 9)) #define PM_LEVEL_SIZE(x) (((x) < 6) ? \ ((1ULL << PM_LEVEL_SHIFT((x))) - 1): \ @@ -164,15 +159,6 @@ #define PM_LEVEL_PDE(x, a) ((a) | PM_LEVEL_ENC((x)) | \ IOMMU_PTE_P | IOMMU_PTE_IR | IOMMU_PTE_IW) - -#define IOMMU_PTE_L2_INDEX(address) (((address) >> 30) & 0x1ffULL) -#define IOMMU_PTE_L1_INDEX(address) (((address) >> 21) & 0x1ffULL) -#define IOMMU_PTE_L0_INDEX(address) (((address) >> 12) & 0x1ffULL) - -#define IOMMU_MAP_SIZE_L1 (1ULL << 21) -#define IOMMU_MAP_SIZE_L2 (1ULL << 30) -#define IOMMU_MAP_SIZE_L3 (1ULL << 39) - #define IOMMU_PTE_P (1ULL << 0) #define IOMMU_PTE_TV (1ULL << 1) #define IOMMU_PTE_U (1ULL << 59) @@ -180,11 +166,6 @@ #define IOMMU_PTE_IR (1ULL << 61) #define IOMMU_PTE_IW (1ULL << 62) -#define IOMMU_L1_PDE(address) \ - ((address) | IOMMU_PDE_NL_1 | IOMMU_PTE_P | IOMMU_PTE_IR | IOMMU_PTE_IW) -#define IOMMU_L2_PDE(address) \ - ((address) | IOMMU_PDE_NL_2 | IOMMU_PTE_P | IOMMU_PTE_IR | IOMMU_PTE_IW) - #define IOMMU_PAGE_MASK (((1ULL << 52) - 1) & ~0xfffULL) #define IOMMU_PTE_PRESENT(pte) ((pte) & IOMMU_PTE_P) #define IOMMU_PTE_PAGE(pte) (phys_to_virt((pte) & IOMMU_PAGE_MASK)) -- cgit v0.10.2 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 diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 4252697..bb488b5 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 v0.10.2 From a6b256b41357c33ccb2d105a4457e22bdc83e021 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 3 Sep 2009 12:21:31 +0200 Subject: x86/amd-iommu: Support higher level PTEs in iommu_page_unmap This patch changes fetch_pte and iommu_page_unmap to support different page sizes too. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index d66430d..351ca39 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -158,6 +158,7 @@ #define PM_LEVEL_ENC(x) (((x) << 9) & 0xe00ULL) #define PM_LEVEL_PDE(x, a) ((a) | PM_LEVEL_ENC((x)) | \ IOMMU_PTE_P | IOMMU_PTE_IR | IOMMU_PTE_IW) +#define PM_PTE_LEVEL(pte) (((pte) >> 9) & 0x7ULL) #define IOMMU_PTE_P (1ULL << 0) #define IOMMU_PTE_TV (1ULL << 1) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index addf658..002cf9c 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -62,7 +62,7 @@ static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, unsigned long start_page, unsigned int pages); static u64 *fetch_pte(struct protection_domain *domain, - unsigned long address); + unsigned long address, int map_size); static void update_domain(struct protection_domain *domain); #ifndef BUS_NOTIFY_UNBOUND_DRIVER @@ -552,9 +552,9 @@ static int iommu_map_page(struct protection_domain *dom, } static void iommu_unmap_page(struct protection_domain *dom, - unsigned long bus_addr) + unsigned long bus_addr, int map_size) { - u64 *pte = fetch_pte(dom, bus_addr); + u64 *pte = fetch_pte(dom, bus_addr, map_size); if (pte) *pte = 0; @@ -668,7 +668,7 @@ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom, * there is one, it returns the pointer to it. */ static u64 *fetch_pte(struct protection_domain *domain, - unsigned long address) + unsigned long address, int map_size) { int level; u64 *pte; @@ -676,7 +676,7 @@ static u64 *fetch_pte(struct protection_domain *domain, level = domain->mode - 1; pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)]; - while (level > 0) { + while (level > map_size) { if (!IOMMU_PTE_PRESENT(*pte)) return NULL; @@ -684,6 +684,11 @@ static u64 *fetch_pte(struct protection_domain *domain, pte = IOMMU_PTE_PAGE(*pte); pte = &pte[PM_LEVEL_INDEX(level, address)]; + + if ((PM_PTE_LEVEL(*pte) == 0) && level != map_size) { + pte = NULL; + break; + } } return pte; @@ -757,7 +762,7 @@ static int alloc_new_range(struct amd_iommu *iommu, for (i = dma_dom->aperture[index]->offset; i < dma_dom->aperture_size; i += PAGE_SIZE) { - u64 *pte = fetch_pte(&dma_dom->domain, i); + u64 *pte = fetch_pte(&dma_dom->domain, i, PM_MAP_4k); if (!pte || !IOMMU_PTE_PRESENT(*pte)) continue; @@ -2192,7 +2197,7 @@ static void amd_iommu_unmap_range(struct iommu_domain *dom, iova &= PAGE_MASK; for (i = 0; i < npages; ++i) { - iommu_unmap_page(domain, iova); + iommu_unmap_page(domain, iova, PM_MAP_4k); iova += PAGE_SIZE; } @@ -2207,7 +2212,7 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom, phys_addr_t paddr; u64 *pte; - pte = fetch_pte(domain, iova); + pte = fetch_pte(domain, iova, PM_MAP_4k); if (!pte || !IOMMU_PTE_PRESENT(*pte)) return 0; -- cgit v0.10.2 From abdc5eb3d69279039ba6cb89719913d08013ab14 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 3 Sep 2009 11:33:51 +0200 Subject: x86/amd-iommu: Change iommu_map_page to support multiple page sizes This patch adds a map_size parameter to the iommu_map_page function which makes it generic enough to handle multiple page sizes. This also requires a change to alloc_pte which is also done in this patch. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 351ca39..9e8bb97 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -160,6 +160,12 @@ IOMMU_PTE_P | IOMMU_PTE_IR | IOMMU_PTE_IW) #define PM_PTE_LEVEL(pte) (((pte) >> 9) & 0x7ULL) +#define PM_MAP_4k 0 +#define PM_ADDR_MASK 0x000ffffffffff000ULL +#define PM_MAP_MASK(lvl) (PM_ADDR_MASK & \ + (~((1ULL << (12 + ((lvl) * 9))) - 1))) +#define PM_ALIGNED(lvl, addr) ((PM_MAP_MASK(lvl) & (addr)) == (addr)) + #define IOMMU_PTE_P (1ULL << 0) #define IOMMU_PTE_TV (1ULL << 1) #define IOMMU_PTE_U (1ULL << 59) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 002cf9c..45be949 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -56,8 +56,8 @@ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, struct unity_map_entry *e); static struct dma_ops_domain *find_protection_domain(u16 devid); static u64 *alloc_pte(struct protection_domain *domain, - unsigned long address, u64 - **pte_page, gfp_t gfp); + unsigned long address, int end_lvl, + u64 **pte_page, gfp_t gfp); static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, unsigned long start_page, unsigned int pages); @@ -523,17 +523,21 @@ void amd_iommu_flush_all_devices(void) static int iommu_map_page(struct protection_domain *dom, unsigned long bus_addr, unsigned long phys_addr, - int prot) + int prot, + int map_size) { u64 __pte, *pte; bus_addr = PAGE_ALIGN(bus_addr); phys_addr = PAGE_ALIGN(phys_addr); + BUG_ON(!PM_ALIGNED(map_size, bus_addr)); + BUG_ON(!PM_ALIGNED(map_size, phys_addr)); + if (!(prot & IOMMU_PROT_MASK)) return -EINVAL; - pte = alloc_pte(dom, bus_addr, NULL, GFP_KERNEL); + pte = alloc_pte(dom, bus_addr, map_size, NULL, GFP_KERNEL); if (IOMMU_PTE_PRESENT(*pte)) return -EBUSY; @@ -612,7 +616,8 @@ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, for (addr = e->address_start; addr < e->address_end; addr += PAGE_SIZE) { - ret = iommu_map_page(&dma_dom->domain, addr, addr, e->prot); + ret = iommu_map_page(&dma_dom->domain, addr, addr, e->prot, + PM_MAP_4k); if (ret) return ret; /* @@ -729,7 +734,7 @@ static int alloc_new_range(struct amd_iommu *iommu, u64 *pte, *pte_page; for (i = 0; i < num_ptes; ++i) { - pte = alloc_pte(&dma_dom->domain, address, + pte = alloc_pte(&dma_dom->domain, address, PM_MAP_4k, &pte_page, gfp); if (!pte) goto out_free; @@ -1356,7 +1361,10 @@ static bool increase_address_space(struct protection_domain *domain, } static u64 *alloc_pte(struct protection_domain *domain, - unsigned long address, u64 **pte_page, gfp_t gfp) + unsigned long address, + int end_lvl, + u64 **pte_page, + gfp_t gfp) { u64 *pte, *page; int level; @@ -1367,7 +1375,7 @@ static u64 *alloc_pte(struct protection_domain *domain, level = domain->mode - 1; pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)]; - while (level > 0) { + while (level > end_lvl) { if (!IOMMU_PTE_PRESENT(*pte)) { page = (u64 *)get_zeroed_page(gfp); if (!page) @@ -1379,7 +1387,7 @@ static u64 *alloc_pte(struct protection_domain *domain, pte = IOMMU_PTE_PAGE(*pte); - if (pte_page && level == 0) + if (pte_page && level == end_lvl) *pte_page = pte; pte = &pte[PM_LEVEL_INDEX(level, address)]; @@ -1403,7 +1411,8 @@ static u64* dma_ops_get_pte(struct dma_ops_domain *dom, pte = aperture->pte_pages[APERTURE_PAGE_INDEX(address)]; if (!pte) { - pte = alloc_pte(&dom->domain, address, &pte_page, GFP_ATOMIC); + pte = alloc_pte(&dom->domain, address, PM_MAP_4k, &pte_page, + GFP_ATOMIC); aperture->pte_pages[APERTURE_PAGE_INDEX(address)] = pte_page; } else pte += PM_LEVEL_INDEX(0, address); @@ -2176,7 +2185,7 @@ static int amd_iommu_map_range(struct iommu_domain *dom, paddr &= PAGE_MASK; for (i = 0; i < npages; ++i) { - ret = iommu_map_page(domain, iova, paddr, prot); + ret = iommu_map_page(domain, iova, paddr, prot, PM_MAP_4k); if (ret) return ret; -- cgit v0.10.2 From ac0101d396fee24994632f71b55b9f7f9ee16eff Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 1 Sep 2009 16:00:35 +0200 Subject: x86/dma: Mark iommu_pass_through as __read_mostly This variable is read most of the time. This patch marks it as such. It also documents the meaning the this variable while at it. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 1a041bc..873aa07 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -32,7 +32,14 @@ int no_iommu __read_mostly; /* Set this to 1 if there is a HW IOMMU in the system */ int iommu_detected __read_mostly = 0; -int iommu_pass_through; +/* + * This variable becomes 1 if iommu=pt is passed on the kernel command line. + * If this variable is 1, IOMMU implementations do no DMA ranslation for + * devices and allow every device to access to whole physical memory. This is + * useful if a user want to use an IOMMU only for KVM device assignment to + * guests and not for driver dma translation. + */ +int iommu_pass_through __read_mostly; dma_addr_t bad_dma_address __read_mostly = 0; EXPORT_SYMBOL(bad_dma_address); -- cgit v0.10.2 From 2650815fb03fe2bf1e6701584087ba669dcf92cd Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Aug 2009 16:52:40 +0200 Subject: x86/amd-iommu: Add core functions for pd allocation/freeing This patch factors some code of protection domain allocation into seperate functions. This way the logic can be used to allocate the passthrough domain later. As a side effect this patch fixes an unlikely domain id leakage bug. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 6c99f50..0934348 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1988,19 +1988,47 @@ static void cleanup_domain(struct protection_domain *domain) write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); } -static int amd_iommu_domain_init(struct iommu_domain *dom) +static void protection_domain_free(struct protection_domain *domain) +{ + if (!domain) + return; + + if (domain->id) + domain_id_free(domain->id); + + kfree(domain); +} + +static struct protection_domain *protection_domain_alloc(void) { struct protection_domain *domain; domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) - return -ENOMEM; + return NULL; spin_lock_init(&domain->lock); - domain->mode = PAGE_MODE_3_LEVEL; domain->id = domain_id_alloc(); if (!domain->id) + goto out_err; + + return domain; + +out_err: + kfree(domain); + + return NULL; +} + +static int amd_iommu_domain_init(struct iommu_domain *dom) +{ + struct protection_domain *domain; + + domain = protection_domain_alloc(); + if (!domain) goto out_free; + + domain->mode = PAGE_MODE_3_LEVEL; domain->pt_root = (void *)get_zeroed_page(GFP_KERNEL); if (!domain->pt_root) goto out_free; @@ -2010,7 +2038,7 @@ static int amd_iommu_domain_init(struct iommu_domain *dom) return 0; out_free: - kfree(domain); + protection_domain_free(domain); return -ENOMEM; } -- cgit v0.10.2 From 0feae533ddebe02cda6ccce5cac7349b446776a8 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Aug 2009 15:26:30 +0200 Subject: x86/amd-iommu: Add passthrough mode initialization functions When iommu=pt is passed on kernel command line the devices should run untranslated. This requires the allocation of a special domain for that purpose. This patch implements the allocation and initialization path for iommu=pt. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu.h b/arch/x86/include/asm/amd_iommu.h index bdf96f1..ac95995 100644 --- a/arch/x86/include/asm/amd_iommu.h +++ b/arch/x86/include/asm/amd_iommu.h @@ -25,6 +25,7 @@ #ifdef CONFIG_AMD_IOMMU extern int amd_iommu_init(void); extern int amd_iommu_init_dma_ops(void); +extern int amd_iommu_init_passthrough(void); extern void amd_iommu_detect(void); extern irqreturn_t amd_iommu_int_handler(int irq, void *data); extern void amd_iommu_flush_all_domains(void); diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 0c878ca..49f7453 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -143,6 +143,7 @@ #define EVT_BUFFER_SIZE 8192 /* 512 entries */ #define EVT_LEN_MASK (0x9ULL << 56) +#define PAGE_MODE_NONE 0x00 #define PAGE_MODE_1_LEVEL 0x01 #define PAGE_MODE_2_LEVEL 0x02 #define PAGE_MODE_3_LEVEL 0x03 @@ -194,6 +195,9 @@ #define PD_DMA_OPS_MASK (1UL << 0) /* domain used for dma_ops */ #define PD_DEFAULT_MASK (1UL << 1) /* domain is a default dma_ops domain for an IOMMU */ +#define PD_PASSTHROUGH_MASK (1UL << 2) /* domain has no page + translation */ + extern bool amd_iommu_dump; #define DUMP_printk(format, arg...) \ do { \ diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 0934348..7987f20 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -41,6 +41,12 @@ static DEFINE_RWLOCK(amd_iommu_devtable_lock); static LIST_HEAD(iommu_pd_list); static DEFINE_SPINLOCK(iommu_pd_list_lock); +/* + * Domain for untranslated devices - only allocated + * if iommu=pt passed on kernel cmd line. + */ +static struct protection_domain *pt_domain; + #ifdef CONFIG_IOMMU_API static struct iommu_ops amd_iommu_ops; #endif @@ -1067,9 +1073,9 @@ static struct protection_domain *domain_for_device(u16 devid) * If a device is not yet associated with a domain, this function does * assigns it visible for the hardware */ -static void attach_device(struct amd_iommu *iommu, - struct protection_domain *domain, - u16 devid) +static void __attach_device(struct amd_iommu *iommu, + struct protection_domain *domain, + u16 devid) { unsigned long flags; u64 pte_root = virt_to_phys(domain->pt_root); @@ -1087,12 +1093,19 @@ static void attach_device(struct amd_iommu *iommu, amd_iommu_pd_table[devid] = domain; write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); +} - /* - * We might boot into a crash-kernel here. The crashed kernel - * left the caches in the IOMMU dirty. So we have to flush - * here to evict all dirty stuff. - */ +static void attach_device(struct amd_iommu *iommu, + struct protection_domain *domain, + u16 devid) +{ + __attach_device(iommu, domain, devid); + + /* + * We might boot into a crash-kernel here. The crashed kernel + * left the caches in the IOMMU dirty. So we have to flush + * here to evict all dirty stuff. + */ iommu_queue_inv_dev_entry(iommu, devid); iommu_flush_tlb_pde(iommu, domain->id); } @@ -2219,3 +2232,46 @@ static struct iommu_ops amd_iommu_ops = { .domain_has_cap = amd_iommu_domain_has_cap, }; +/***************************************************************************** + * + * The next functions do a basic initialization of IOMMU for pass through + * mode + * + * In passthrough mode the IOMMU is initialized and enabled but not used for + * DMA-API translation. + * + *****************************************************************************/ + +int __init amd_iommu_init_passthrough(void) +{ + struct pci_dev *dev = NULL; + u16 devid, devid2; + + /* allocate passthroug domain */ + pt_domain = protection_domain_alloc(); + if (!pt_domain) + return -ENOMEM; + + pt_domain->mode |= PAGE_MODE_NONE; + + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + struct amd_iommu *iommu; + + devid = calc_devid(dev->bus->number, dev->devfn); + if (devid > amd_iommu_last_bdf) + continue; + + devid2 = amd_iommu_alias_table[devid]; + + iommu = amd_iommu_rlookup_table[devid2]; + if (!iommu) + continue; + + __attach_device(iommu, pt_domain, devid); + __attach_device(iommu, pt_domain, devid2); + } + + pr_info("AMD-Vi: Initialized for Passthrough Mode\n"); + + return 0; +} -- cgit v0.10.2 From aa879fff5d12318259816aa35023e941a1e4d3d9 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 31 Aug 2009 16:01:48 +0200 Subject: x86/amd-iommu: Fix device table write order The V bit of the device table entry has to be set after the rest of the entry is written to not confuse the hardware. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 7987f20..2b1e77c 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1087,9 +1087,9 @@ static void __attach_device(struct amd_iommu *iommu, pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV; write_lock_irqsave(&amd_iommu_devtable_lock, flags); - amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); - amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); amd_iommu_dev_table[devid].data[2] = domain->id; + amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); + amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); amd_iommu_pd_table[devid] = domain; write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); -- cgit v0.10.2 From eba6ac60ba66c6bf6858938442204feaa67dea31 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 1 Sep 2009 12:07:08 +0200 Subject: x86/amd-iommu: Align locking between attach_device and detach_device This patch makes the locking behavior between the functions attach_device and __attach_device consistent with the locking behavior between detach_device and __detach_device. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 2b1e77c..9aa135d 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1077,29 +1077,38 @@ static void __attach_device(struct amd_iommu *iommu, struct protection_domain *domain, u16 devid) { - unsigned long flags; - u64 pte_root = virt_to_phys(domain->pt_root); + u64 pte_root; - domain->dev_cnt += 1; + /* lock domain */ + spin_lock(&domain->lock); + + pte_root = virt_to_phys(domain->pt_root); pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK) << DEV_ENTRY_MODE_SHIFT; pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV; - write_lock_irqsave(&amd_iommu_devtable_lock, flags); amd_iommu_dev_table[devid].data[2] = domain->id; amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); amd_iommu_pd_table[devid] = domain; - write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); + + domain->dev_cnt += 1; + + /* ready */ + spin_unlock(&domain->lock); } static void attach_device(struct amd_iommu *iommu, struct protection_domain *domain, u16 devid) { + unsigned long flags; + + write_lock_irqsave(&amd_iommu_devtable_lock, flags); __attach_device(iommu, domain, devid); + write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); /* * We might boot into a crash-kernel here. The crashed kernel -- cgit v0.10.2 From 21129f786f231f7a9dce5b504617b893f50a435f Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 1 Sep 2009 11:59:42 +0200 Subject: x86/amd-iommu: Make sure a device is assigned in passthrough mode When the IOMMU driver runs in passthrough mode it has to make sure that every device not assigned to an IOMMU-API domain must be put into the passthrough domain instead of keeping it unassigned. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 9aa135d..a8e74c3 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1141,6 +1141,15 @@ static void __detach_device(struct protection_domain *domain, u16 devid) /* ready */ spin_unlock(&domain->lock); + + /* + * If we run in passthrough mode the device must be assigned to the + * passthrough domain if it is detached from any other domain + */ + if (iommu_pass_through) { + struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; + __attach_device(iommu, pt_domain, devid); + } } /* -- cgit v0.10.2 From a1ca331c8aa75cd58fdf685e2e8745e1d3ec5c8f Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 1 Sep 2009 12:22:22 +0200 Subject: x86/amd-iommu: Don't detach device from pt domain on driver unbind This patch makes sure a device is not detached from the passthrough domain when the device driver is unloaded or does otherwise release the device. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index a8e74c3..12a541d 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1195,6 +1195,8 @@ static int device_change_notifier(struct notifier_block *nb, case BUS_NOTIFY_UNBOUND_DRIVER: if (!domain) goto out; + if (iommu_pass_through) + break; detach_device(domain, devid); break; case BUS_NOTIFY_ADD_DEVICE: -- cgit v0.10.2 From 4751a95134e05f1172131d2001c6991d671fa58c Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 1 Sep 2009 15:53:54 +0200 Subject: x86/amd-iommu: Initialize passthrough mode when requested This patch enables the passthrough mode for AMD IOMMU by running the initialization function when iommu=pt is passed on the kernel command line. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index c1b17e9..f00f489 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -1242,12 +1242,18 @@ int __init amd_iommu_init(void) if (ret) goto free; - ret = amd_iommu_init_dma_ops(); + if (iommu_pass_through) + ret = amd_iommu_init_passthrough(); + else + ret = amd_iommu_init_dma_ops(); if (ret) goto free; enable_iommus(); + if (iommu_pass_through) + goto out; + printk(KERN_INFO "AMD IOMMU: device isolation "); if (amd_iommu_isolate) printk("enabled\n"); -- cgit v0.10.2 From 8886f42d6d8dabeb488c706c339634a0e3e08df4 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 3 Sep 2009 16:19:57 +0200 Subject: perf trace: Fix parsing of perf.data We started parsing perf.data at head 0. This caused -D to segfault and it could possibly also case incorrect trace entries to be displayed. Parse it at data_offset instead. Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d59bf8a..914ab36 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -196,6 +196,7 @@ static int __cmd_trace(void) exit(0); } header = perf_header__read(input); + head = header->data_offset; sample_type = perf_header__sample_type(header); if (!(sample_type & PERF_SAMPLE_RAW)) -- cgit v0.10.2 From 6ac162d6c01ac7626f46c68c0770556cf682ce34 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 3 Sep 2009 16:20:55 +0200 Subject: x86/gart: Do not select AGP for GART_IOMMU There is no dependency from the gart code to the agp code. And since a lot of systems today do not have agp anymore remove this dependency from the kernel configuration. Signed-off-by: Pavel Vasilyev Signed-off-by: Joerg Roedel diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 13ffa5d..1d9c18aa 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -586,7 +586,6 @@ config GART_IOMMU bool "GART IOMMU support" if EMBEDDED default y select SWIOTLB - select AGP depends on X86_64 && PCI ---help--- Support for full DMA access of devices with 32bit memory access only -- cgit v0.10.2 From 2e01d1791168bb824226d8cc70e50374767dcc42 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 3 Sep 2009 16:21:11 +0200 Subject: perf tools: Seek to the end of the header area Leave the input fd at the data area. It does not matter right now - but seeking at the end of it certainly did not make sense. Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a37a222..ec4d4c2 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -237,7 +237,7 @@ struct perf_header *perf_header__read(int fd) self->data_offset = f_header.data.offset; self->data_size = f_header.data.size; - lseek(fd, self->data_offset + self->data_size, SEEK_SET); + lseek(fd, self->data_offset, SEEK_SET); self->frozen = 1; -- cgit v0.10.2 From 00fc97863c21c41e257a941e83410c56341e2a5d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 3 Sep 2009 16:22:02 +0200 Subject: perf trace: Print out in nanoseconds Print out more accurate timestamps - usecs does not cut it anymore on fast enough boxes ;-) Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 37b10c2..629e602 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -2708,9 +2708,9 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs, return pretty_print_func_graph(data, size, event, cpu, pid, comm, secs, usecs); - printf("%16s-%-5d [%03d] %5lu.%06lu: %s: ", + printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ", comm, pid, cpu, - secs, usecs, event->name); + secs, nsecs, event->name); pretty_print(data, size, event); printf("\n"); -- cgit v0.10.2 From 6f4596d9312ba5fbf5f3231ef484823c4e684d2e Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 3 Sep 2009 16:22:45 +0200 Subject: perf trace: Fix read_string() We did not account for the enclosing \0. Depending on what malloc() gave us this resulted in corrupted version string printouts. Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index b12e490..a1217a1 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -113,8 +113,11 @@ static char *read_string(void) } } + /* trailing \0: */ + i++; + /* move the file descriptor to the end of the string */ - r = lseek(input_fd, -(r - (i+1)), SEEK_CUR); + r = lseek(input_fd, -(r - i), SEEK_CUR); if (r < 0) die("lseek"); -- cgit v0.10.2 From dc86cabe4b242446ea9aa8492c727e1220817898 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 3 Sep 2009 18:03:00 +0200 Subject: perf_counter: Fix output-sharing error path We forget to release the fd in the PERF_FLAG_FD_OUTPUT error path. Reorganize the error flow here to be a clean fall-through logic. Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 0aa609f..e0d91fd 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -4316,15 +4316,15 @@ SYSCALL_DEFINE5(perf_counter_open, struct file *group_file = NULL; int fput_needed = 0; int fput_needed2 = 0; - int ret; + int err; /* for future expandability... */ if (flags & ~(PERF_FLAG_FD_NO_GROUP | PERF_FLAG_FD_OUTPUT)) return -EINVAL; - ret = perf_copy_attr(attr_uptr, &attr); - if (ret) - return ret; + err = perf_copy_attr(attr_uptr, &attr); + if (err) + return err; if (!attr.exclude_kernel) { if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) @@ -4348,7 +4348,7 @@ SYSCALL_DEFINE5(perf_counter_open, */ group_leader = NULL; if (group_fd != -1 && !(flags & PERF_FLAG_FD_NO_GROUP)) { - ret = -EINVAL; + err = -EINVAL; group_file = fget_light(group_fd, &fput_needed); if (!group_file) goto err_put_context; @@ -4377,22 +4377,22 @@ SYSCALL_DEFINE5(perf_counter_open, counter = perf_counter_alloc(&attr, cpu, ctx, group_leader, NULL, GFP_KERNEL); - ret = PTR_ERR(counter); + err = PTR_ERR(counter); if (IS_ERR(counter)) goto err_put_context; - ret = anon_inode_getfd("[perf_counter]", &perf_fops, counter, 0); - if (ret < 0) + err = anon_inode_getfd("[perf_counter]", &perf_fops, counter, 0); + if (err < 0) goto err_free_put_context; - counter_file = fget_light(ret, &fput_needed2); + counter_file = fget_light(err, &fput_needed2); if (!counter_file) goto err_free_put_context; if (flags & PERF_FLAG_FD_OUTPUT) { - ret = perf_counter_set_output(counter, group_fd); - if (ret) - goto err_free_put_context; + err = perf_counter_set_output(counter, group_fd); + if (err) + goto err_fput_free_put_context; } counter->filp = counter_file; @@ -4408,20 +4408,20 @@ SYSCALL_DEFINE5(perf_counter_open, list_add_tail(&counter->owner_entry, ¤t->perf_counter_list); mutex_unlock(¤t->perf_counter_mutex); +err_fput_free_put_context: fput_light(counter_file, fput_needed2); -out_fput: - fput_light(group_file, fput_needed); - - return ret; - err_free_put_context: - kfree(counter); + if (err < 0) + kfree(counter); err_put_context: - put_ctx(ctx); + if (err < 0) + put_ctx(ctx); + + fput_light(group_file, fput_needed); - goto out_fput; + return err; } /* -- cgit v0.10.2 From 8adf65cfae2d6c2ec5c06e4521f089c62f9eff05 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 3 Sep 2009 21:26:34 +0200 Subject: x86, msr: Fix msr-reg.S compilation with gas 2.16.1, on 32-bit too The macro was defined in the 32-bit path as well - breaking the build on 32-bit platforms: arch/x86/lib/msr-reg.S: Assembler messages: arch/x86/lib/msr-reg.S:53: Error: Bad macro parameter list arch/x86/lib/msr-reg.S:100: Error: invalid character '_' in mnemonic arch/x86/lib/msr-reg.S:101: Error: invalid character '_' in mnemonic Cc: Borislav Petkov Cc: H. Peter Anvin LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/arch/x86/lib/msr-reg.S b/arch/x86/lib/msr-reg.S index d5eaf53..69fa106 100644 --- a/arch/x86/lib/msr-reg.S +++ b/arch/x86/lib/msr-reg.S @@ -50,7 +50,7 @@ ENDPROC(native_\op\()_safe_regs) #else /* X86_32 */ -.macro op_safe_regs op:req +.macro op_safe_regs op ENTRY(native_\op\()_safe_regs) CFI_STARTPROC pushl_cfi %ebx -- cgit v0.10.2 From 1ea0d14e480c245683927eecc03a70faf06e80c8 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 3 Sep 2009 12:27:15 -0700 Subject: x86/i386: Make sure stack-protector segment base is cache aligned The Intel Optimization Reference Guide says: In Intel Atom microarchitecture, the address generation unit assumes that the segment base will be 0 by default. Non-zero segment base will cause load and store operations to experience a delay. - If the segment base isn't aligned to a cache line boundary, the max throughput of memory operations is reduced to one [e]very 9 cycles. [...] Assembly/Compiler Coding Rule 15. (H impact, ML generality) For Intel Atom processors, use segments with base set to 0 whenever possible; avoid non-zero segment base address that is not aligned to cache line boundary at all cost. We can't avoid having a non-zero base for the stack-protector segment, but we can make it cache-aligned. Signed-off-by: Jeremy Fitzhardinge Cc: LKML-Reference: <4AA01893.6000507@goop.org> Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index c776826..e597ecc 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -403,7 +403,17 @@ extern unsigned long kernel_eflags; extern asmlinkage void ignore_sysret(void); #else /* X86_64 */ #ifdef CONFIG_CC_STACKPROTECTOR -DECLARE_PER_CPU(unsigned long, stack_canary); +/* + * Make sure stack canary segment base is cached-aligned: + * "For Intel Atom processors, avoid non zero segment base address + * that is not aligned to cache line boundary at all cost." + * (Optim Ref Manual Assembly/Compiler Coding Rule 15.) + */ +struct stack_canary { + char __pad[20]; /* canary at %gs:20 */ + unsigned long canary; +}; +DECLARE_PER_CPU(struct stack_canary, stack_canary) ____cacheline_aligned; #endif #endif /* X86_64 */ diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h index 44efdff..1575177 100644 --- a/arch/x86/include/asm/stackprotector.h +++ b/arch/x86/include/asm/stackprotector.h @@ -78,14 +78,14 @@ static __always_inline void boot_init_stack_canary(void) #ifdef CONFIG_X86_64 percpu_write(irq_stack_union.stack_canary, canary); #else - percpu_write(stack_canary, canary); + percpu_write(stack_canary.canary, canary); #endif } static inline void setup_stack_canary_segment(int cpu) { #ifdef CONFIG_X86_32 - unsigned long canary = (unsigned long)&per_cpu(stack_canary, cpu) - 20; + unsigned long canary = (unsigned long)&per_cpu(stack_canary, cpu); struct desc_struct *gdt_table = get_cpu_gdt_table(cpu); struct desc_struct desc; diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h index 75c49c7..f08f973 100644 --- a/arch/x86/include/asm/system.h +++ b/arch/x86/include/asm/system.h @@ -31,7 +31,7 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, "movl %P[task_canary](%[next]), %%ebx\n\t" \ "movl %%ebx, "__percpu_arg([stack_canary])"\n\t" #define __switch_canary_oparam \ - , [stack_canary] "=m" (per_cpu_var(stack_canary)) + , [stack_canary] "=m" (per_cpu_var(stack_canary.canary)) #define __switch_canary_iparam \ , [task_canary] "i" (offsetof(struct task_struct, stack_canary)) #else /* CC_STACKPROTECTOR */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index ced07ba..7d84bc4 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1043,7 +1043,7 @@ DEFINE_PER_CPU(struct orig_ist, orig_ist); #else /* CONFIG_X86_64 */ #ifdef CONFIG_CC_STACKPROTECTOR -DEFINE_PER_CPU(unsigned long, stack_canary); +DEFINE_PER_CPU(struct stack_canary, stack_canary) ____cacheline_aligned; #endif /* Make sure %fs and %gs are initialized properly in idle threads */ diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index cc827ac..7ffec6b 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -439,7 +439,6 @@ is386: movl $2,%ecx # set MP jne 1f movl $per_cpu__gdt_page,%eax movl $per_cpu__stack_canary,%ecx - subl $20, %ecx movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax) shrl $16, %ecx movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax) -- cgit v0.10.2 From 4a376ec3a2599c02207cd4cbd5dbf73783548463 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Thu, 3 Sep 2009 09:40:21 +0200 Subject: x86: Fix CPU llc_shared_map information for AMD Magny-Cours Construct entire NodeID and use it as cpu_llc_id. Thus internal node siblings are stored in llc_shared_map. Signed-off-by: Andreas Herrmann Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 4a28d22..847fee6 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -95,6 +95,7 @@ #define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */ #define X86_FEATURE_CLFLUSH_MONITOR (3*32+25) /* "" clflush reqd with monitor */ #define X86_FEATURE_EXTD_APICID (3*32+26) /* has extended APICID (8 bits) */ +#define X86_FEATURE_AMD_DCM (3*32+27) /* multi-node processor */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ #define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */ diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 0a717fc..a76d2c1 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -251,6 +251,64 @@ static int __cpuinit nearby_node(int apicid) #endif /* + * Fixup core topology information for AMD multi-node processors. + * Assumption 1: Number of cores in each internal node is the same. + * Assumption 2: Mixed systems with both single-node and dual-node + * processors are not supported. + */ +#ifdef CONFIG_X86_HT +static void __cpuinit amd_fixup_dcm(struct cpuinfo_x86 *c) +{ +#ifdef CONFIG_PCI + u32 t, cpn; + u8 n, n_id; + int cpu = smp_processor_id(); + + /* fixup topology information only once for a core */ + if (cpu_has(c, X86_FEATURE_AMD_DCM)) + return; + + /* check for multi-node processor on boot cpu */ + t = read_pci_config(0, 24, 3, 0xe8); + if (!(t & (1 << 29))) + return; + + set_cpu_cap(c, X86_FEATURE_AMD_DCM); + + /* cores per node: each internal node has half the number of cores */ + cpn = c->x86_max_cores >> 1; + + /* even-numbered NB_id of this dual-node processor */ + n = c->phys_proc_id << 1; + + /* + * determine internal node id and assign cores fifty-fifty to + * each node of the dual-node processor + */ + t = read_pci_config(0, 24 + n, 3, 0xe8); + n = (t>>30) & 0x3; + if (n == 0) { + if (c->cpu_core_id < cpn) + n_id = 0; + else + n_id = 1; + } else { + if (c->cpu_core_id < cpn) + n_id = 1; + else + n_id = 0; + } + + /* compute entire NodeID, use llc_shared_map to store sibling info */ + per_cpu(cpu_llc_id, cpu) = (c->phys_proc_id << 1) + n_id; + + /* fixup core id to be in range from 0 to cpn */ + c->cpu_core_id = c->cpu_core_id % cpn; +#endif +} +#endif + +/* * On a AMD dual core setup the lower bits of the APIC id distingush the cores. * Assumes number of cores is a power of two. */ @@ -267,6 +325,9 @@ static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c) c->phys_proc_id = c->initial_apicid >> bits; /* use socket ID also for last level cache */ per_cpu(cpu_llc_id, cpu) = c->phys_proc_id; + /* fixup topology information on multi-node processors */ + if ((c->x86 == 0x10) && (c->x86_model == 9)) + amd_fixup_dcm(c); #endif } @@ -277,7 +338,8 @@ static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c) int node; unsigned apicid = cpu_has_apic ? hard_smp_processor_id() : c->apicid; - node = c->phys_proc_id; + node = per_cpu(cpu_llc_id, cpu); + if (apicid_to_node[apicid] != NUMA_NO_NODE) node = apicid_to_node[apicid]; if (!node_online(node)) { -- cgit v0.10.2 From a326e948c538e8ce998f30d92e146ecea8a30421 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Thu, 3 Sep 2009 09:41:19 +0200 Subject: x86, cacheinfo: Fixup L3 cache information for AMD multi-node processors L3 cache size, associativity and shared_cpu information need to be adapted to show information for an internal node instead of the entire physical package. Signed-off-by: Andreas Herrmann Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 789efe2..cb98a73 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -241,7 +241,7 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax, case 0: if (!l1->val) return; - assoc = l1->assoc; + assoc = assocs[l1->assoc]; line_size = l1->line_size; lines_per_tag = l1->lines_per_tag; size_in_kb = l1->size_in_kb; @@ -249,7 +249,7 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax, case 2: if (!l2.val) return; - assoc = l2.assoc; + assoc = assocs[l2.assoc]; line_size = l2.line_size; lines_per_tag = l2.lines_per_tag; /* cpu_data has errata corrections for K7 applied */ @@ -258,10 +258,14 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax, case 3: if (!l3.val) return; - assoc = l3.assoc; + assoc = assocs[l3.assoc]; line_size = l3.line_size; lines_per_tag = l3.lines_per_tag; size_in_kb = l3.size_encoded * 512; + if (boot_cpu_has(X86_FEATURE_AMD_DCM)) { + size_in_kb = size_in_kb >> 1; + assoc = assoc >> 1; + } break; default: return; @@ -270,18 +274,14 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax, eax->split.is_self_initializing = 1; eax->split.type = types[leaf]; eax->split.level = levels[leaf]; - if (leaf == 3) - eax->split.num_threads_sharing = - current_cpu_data.x86_max_cores - 1; - else - eax->split.num_threads_sharing = 0; + eax->split.num_threads_sharing = 0; eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1; - if (assoc == 0xf) + if (assoc == 0xffff) eax->split.is_fully_associative = 1; ebx->split.coherency_line_size = line_size - 1; - ebx->split.ways_of_associativity = assocs[assoc] - 1; + ebx->split.ways_of_associativity = assoc - 1; ebx->split.physical_line_partition = lines_per_tag - 1; ecx->split.number_of_sets = (size_in_kb * 1024) / line_size / (ebx->split.ways_of_associativity + 1) - 1; @@ -522,6 +522,18 @@ static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index) int index_msb, i; struct cpuinfo_x86 *c = &cpu_data(cpu); + if ((index == 3) && (c->x86_vendor == X86_VENDOR_AMD)) { + struct cpuinfo_x86 *d; + for_each_online_cpu(i) { + if (!per_cpu(cpuid4_info, i)) + continue; + d = &cpu_data(i); + this_leaf = CPUID4_INFO_IDX(i, index); + cpumask_copy(to_cpumask(this_leaf->shared_cpu_map), + d->llc_shared_map); + } + return; + } this_leaf = CPUID4_INFO_IDX(cpu, index); num_threads_sharing = 1 + this_leaf->eax.split.num_threads_sharing; -- cgit v0.10.2 From cb9805ab5b97079f69a21b6b4e344a69d5c96157 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Thu, 3 Sep 2009 09:42:20 +0200 Subject: x86, mcheck: Use correct cpumask for shared bank4 This fixes threshold_bank4 support on multi-node processors. The correct mask to use is llc_shared_map, representing an internal node on Magny-Cours. We need to create 2 sets of symlinks for sibling shared banks -- one set for each internal node, symlinks of each set should target the first core on same internal node. Currently only one set is created where all symlinks are targeting the first core of the entire socket. Signed-off-by: Andreas Herrmann Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index ddae216..1fecba4 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -489,12 +489,14 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) int i, err = 0; struct threshold_bank *b = NULL; char name[32]; + struct cpuinfo_x86 *c = &cpu_data(cpu); + sprintf(name, "threshold_bank%i", bank); #ifdef CONFIG_SMP if (cpu_data(cpu).cpu_core_id && shared_bank[bank]) { /* symlink */ - i = cpumask_first(cpu_core_mask(cpu)); + i = cpumask_first(c->llc_shared_map); /* first core not up yet */ if (cpu_data(i).cpu_core_id) @@ -514,7 +516,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) if (err) goto out; - cpumask_copy(b->cpus, cpu_core_mask(cpu)); + cpumask_copy(b->cpus, c->llc_shared_map); per_cpu(threshold_banks, cpu)[bank] = b; goto out; @@ -539,7 +541,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) #ifndef CONFIG_SMP cpumask_setall(b->cpus); #else - cpumask_copy(b->cpus, cpu_core_mask(cpu)); + cpumask_copy(b->cpus, c->llc_shared_map); #endif per_cpu(threshold_banks, cpu)[bank] = b; -- cgit v0.10.2 From 5a925b4282d7f805deafde62001a83dbaf8be275 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Thu, 3 Sep 2009 09:44:28 +0200 Subject: x86, sched: Workaround broken sched domain creation for AMD Magny-Cours Current sched domain creation code can't handle multi-node processors. When switching to power_savings scheduling errors show up and system might hang later on (due to broken sched domain hierarchy): # echo 0 >> /sys/devices/system/cpu/sched_mc_power_savings CPU0 attaching sched-domain: domain 0: span 0-5 level MC groups: 0 1 2 3 4 5 domain 1: span 0-23 level NODE groups: 0-5 6-11 18-23 12-17 ... # echo 1 >> /sys/devices/system/cpu/sched_mc_power_savings CPU0 attaching sched-domain: domain 0: span 0-11 level MC groups: 0 1 2 3 4 5 6 7 8 9 10 11 ERROR: parent span is not a superset of domain->span domain 1: span 0-5 level CPU ERROR: domain->groups does not contain CPU0 groups: 6-11 (__cpu_power = 12288) ERROR: groups don't span domain->span domain 2: span 0-23 level NODE groups: ERROR: domain->cpu_power not set ERROR: groups don't span domain->span ... Fixing all aspects of power-savings scheduling for Magny-Cours needs some larger changes in the sched domain creation code. As a short-term and temporary workaround avoid the problems by extending "the worst possible hack" ;-( and always use llc_shared_map on AMD Magny-Cours when MC domain span is calculated. With this I get: # echo 1 >> /sys/devices/system/cpu/sched_mc_power_savings CPU0 attaching sched-domain: domain 0: span 0-5 level MC groups: 0 1 2 3 4 5 domain 1: span 0-5 level CPU groups: 0-5 (__cpu_power = 6144) domain 2: span 0-23 level NODE groups: 0-5 (__cpu_power = 6144) 6-11 (__cpu_power = 6144) 18-23 (__cpu_power = 6144) 12-17 (__cpu_power = 6144) ... I.e. no errors during sched domain creation, no system hangs, and also mc_power_savings scheduling works to a certain extend. Cc: Peter Zijlstra Signed-off-by: Andreas Herrmann Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 2fecda6..c36cc14 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -434,7 +434,8 @@ const struct cpumask *cpu_coregroup_mask(int cpu) * For perf, we return last level cache shared map. * And for power savings, we return cpu_core_map */ - if (sched_mc_power_savings || sched_smt_power_savings) + if ((sched_mc_power_savings || sched_smt_power_savings) && + !(cpu_has(c, X86_FEATURE_AMD_DCM))) return cpu_core_mask(cpu); else return c->llc_shared_map; -- cgit v0.10.2 From ff41f8dcc63b4d027ed314ae909df53746c40632 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 3 Sep 2009 14:48:56 +0000 Subject: igb: add support for set_rx_mode netdevice operation This patch adds support for the set_rx_mode netdevice operation so that igb can better support multiple unicast addresses. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 7a054d9..95089a8 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -94,7 +94,7 @@ static void igb_clean_all_tx_rings(struct igb_adapter *); static void igb_clean_all_rx_rings(struct igb_adapter *); static void igb_clean_tx_ring(struct igb_ring *); static void igb_clean_rx_ring(struct igb_ring *); -static void igb_set_multi(struct net_device *); +static void igb_set_rx_mode(struct net_device *); static void igb_update_phy_info(unsigned long); static void igb_watchdog(unsigned long); static void igb_watchdog_task(struct work_struct *); @@ -928,7 +928,7 @@ static void igb_configure(struct igb_adapter *adapter) int i; igb_get_hw_control(adapter); - igb_set_multi(netdev); + igb_set_rx_mode(netdev); igb_restore_vlan(adapter); @@ -1169,7 +1169,8 @@ static const struct net_device_ops igb_netdev_ops = { .ndo_stop = igb_close, .ndo_start_xmit = igb_xmit_frame_adv, .ndo_get_stats = igb_get_stats, - .ndo_set_multicast_list = igb_set_multi, + .ndo_set_rx_mode = igb_set_rx_mode, + .ndo_set_multicast_list = igb_set_rx_mode, .ndo_set_mac_address = igb_set_mac, .ndo_change_mtu = igb_change_mtu, .ndo_do_ioctl = igb_ioctl, @@ -2519,48 +2520,70 @@ static int igb_set_mac(struct net_device *netdev, void *p) memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len); - hw->mac.ops.rar_set(hw, hw->mac.addr, 0); - + igb_rar_set(hw, hw->mac.addr, 0); igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0); return 0; } /** - * igb_set_multi - Multicast and Promiscuous mode set + * igb_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set * @netdev: network interface device structure * - * The set_multi entry point is called whenever the multicast address - * list or the network interface flags are updated. This routine is - * responsible for configuring the hardware for proper multicast, + * The set_rx_mode entry point is called whenever the unicast or multicast + * address lists or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper unicast, multicast, * promiscuous mode, and all-multi behavior. **/ -static void igb_set_multi(struct net_device *netdev) +static void igb_set_rx_mode(struct net_device *netdev) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct dev_mc_list *mc_ptr; + unsigned int rar_entries = hw->mac.rar_entry_count - + (adapter->vfs_allocated_count + 1); + struct dev_mc_list *mc_ptr = netdev->mc_list; u8 *mta_list = NULL; u32 rctl; int i; /* Check for Promiscuous and All Multicast modes */ - rctl = rd32(E1000_RCTL); if (netdev->flags & IFF_PROMISC) { rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); rctl &= ~E1000_RCTL_VFE; } else { - if (netdev->flags & IFF_ALLMULTI) { + if (netdev->flags & IFF_ALLMULTI) rctl |= E1000_RCTL_MPE; + else + rctl &= ~E1000_RCTL_MPE; + + if (netdev->uc.count > rar_entries) + rctl |= E1000_RCTL_UPE; + else rctl &= ~E1000_RCTL_UPE; - } else - rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); rctl |= E1000_RCTL_VFE; } wr32(E1000_RCTL, rctl); + if (netdev->uc.count && rar_entries) { + struct netdev_hw_addr *ha; + list_for_each_entry(ha, &netdev->uc.list, list) { + if (!rar_entries) + break; + igb_rar_set(hw, ha->addr, rar_entries); + igb_set_rah_pool(hw, adapter->vfs_allocated_count, + rar_entries); + rar_entries--; + } + } + /* write the addresses in reverse order to avoid write combining */ + for (; rar_entries > 0 ; rar_entries--) { + wr32(E1000_RAH(rar_entries), 0); + wr32(E1000_RAL(rar_entries), 0); + } + wrfl(); + if (!netdev->mc_count) { /* nothing to program, so clear mc list */ igb_update_mc_addr_list(hw, NULL, 0); @@ -2576,8 +2599,6 @@ static void igb_set_multi(struct net_device *netdev) } /* The shared function expects a packed array of only addresses. */ - mc_ptr = netdev->mc_list; - for (i = 0; i < netdev->mc_count; i++) { if (!mc_ptr) break; @@ -3938,7 +3959,7 @@ static int igb_set_vf_multicasts(struct igb_adapter *adapter, vf_data->vf_mc_hashes[i] = hash_list[i];; /* Flush and reset the mta with the new values */ - igb_set_multi(adapter->netdev); + igb_set_rx_mode(adapter->netdev); return 0; } @@ -4072,13 +4093,14 @@ static inline void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf) adapter->vf_data[vf].num_vf_mc_hashes = 0; /* Flush and reset the mta with the new values */ - igb_set_multi(adapter->netdev); + igb_set_rx_mode(adapter->netdev); } static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf) { struct e1000_hw *hw = &adapter->hw; unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses; + int rar_entry = hw->mac.rar_entry_count - (vf + 1); u32 reg, msgbuf[3]; u8 *addr = (u8 *)(&msgbuf[1]); @@ -4086,8 +4108,8 @@ static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf) igb_vf_reset_event(adapter, vf); /* set vf mac address */ - igb_rar_set(hw, vf_mac, vf + 1); - igb_set_rah_pool(hw, vf, vf + 1); + igb_rar_set(hw, vf_mac, rar_entry); + igb_set_rah_pool(hw, vf, rar_entry); /* enable transmit and receive for vf */ reg = rd32(E1000_VFTE); @@ -5228,7 +5250,7 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake) if (wufc) { igb_setup_rctl(adapter); - igb_set_multi(netdev); + igb_set_rx_mode(netdev); /* turn on all-multi mode if wake on multicast is enabled */ if (wufc & E1000_WUFC_MC) { @@ -5482,12 +5504,13 @@ static int igb_set_vf_mac(struct igb_adapter *adapter, int vf, unsigned char *mac_addr) { struct e1000_hw *hw = &adapter->hw; - int rar_entry = vf + 1; /* VF MAC addresses start at entry 1 */ - - igb_rar_set(hw, mac_addr, rar_entry); + /* VF MAC addresses start at end of receive addresses and moves + * torwards the first, as a result a collision should not be possible */ + int rar_entry = hw->mac.rar_entry_count - (vf + 1); memcpy(adapter->vf_data[vf].vf_mac_addresses, mac_addr, ETH_ALEN); + igb_rar_set(hw, mac_addr, rar_entry); igb_set_rah_pool(hw, vf, rar_entry); return 0; -- cgit v0.10.2 From 2dfd12126573d6feb12f1d215a352851750fcbd7 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 3 Sep 2009 14:49:15 +0000 Subject: igb: only disable/enable interrupt bits for igb physical function The igb_irq_disable/enable calls were causing virtual functions associated with the igb physical function to have their interrupts disabled. In order to prevent this from occuring we should only clear/set the bits related to the physical function. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 95089a8..1d03fcb 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -821,9 +821,11 @@ static void igb_irq_disable(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; if (adapter->msix_entries) { - wr32(E1000_EIAM, 0); - wr32(E1000_EIMC, ~0); - wr32(E1000_EIAC, 0); + u32 regval = rd32(E1000_EIAM); + wr32(E1000_EIAM, regval & ~adapter->eims_enable_mask); + wr32(E1000_EIMC, adapter->eims_enable_mask); + regval = rd32(E1000_EIAC); + wr32(E1000_EIAC, regval & ~adapter->eims_enable_mask); } wr32(E1000_IAM, 0); @@ -841,8 +843,10 @@ static void igb_irq_enable(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; if (adapter->msix_entries) { - wr32(E1000_EIAC, adapter->eims_enable_mask); - wr32(E1000_EIAM, adapter->eims_enable_mask); + u32 regval = rd32(E1000_EIAC); + wr32(E1000_EIAC, regval | adapter->eims_enable_mask); + regval = rd32(E1000_EIAM); + wr32(E1000_EIAM, regval | adapter->eims_enable_mask); wr32(E1000_EIMS, adapter->eims_enable_mask); if (adapter->vfs_allocated_count) wr32(E1000_MBVFIMR, 0xFF); -- cgit v0.10.2 From ae641bdc264a5998b7872622c86f0690a5b1c5b5 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 3 Sep 2009 14:49:33 +0000 Subject: igb: set vf rlpml wasn't taking vlan tag into account This patch updates things so that vlan tags are taken into account when setting the receive large packet maximum length. This allows the VF driver to correctly receive full sized frames when vlans are enabled. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index b2c98de..7126fea 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -70,6 +70,7 @@ struct vf_data_storage { unsigned char vf_mac_addresses[ETH_ALEN]; u16 vf_mc_hashes[IGB_MAX_VF_MC_ENTRIES]; u16 num_vf_mc_hashes; + u16 vlans_enabled; bool clear_to_send; }; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 1d03fcb..90b0b1b 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -154,6 +154,12 @@ static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size, struct e1000_hw *hw = &adapter->hw; u32 vmolr; + /* if it isn't the PF check to see if VFs are enabled and + * increase the size to support vlan tags */ + if (vfn < adapter->vfs_allocated_count && + adapter->vf_data[vfn].vlans_enabled) + size += VLAN_TAG_SIZE; + vmolr = rd32(E1000_VMOLR(vfn)); vmolr &= ~E1000_VMOLR_RLPML_MASK; vmolr |= size | E1000_VMOLR_LPE; @@ -4006,6 +4012,8 @@ static void igb_clear_vf_vfta(struct igb_adapter *adapter, u32 vf) wr32(E1000_VLVF(i), reg); } + + adapter->vf_data[vf].vlans_enabled = 0; } static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf) @@ -4054,6 +4062,22 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf) reg |= vid; wr32(E1000_VLVF(i), reg); + + /* do not modify RLPML for PF devices */ + if (vf >= adapter->vfs_allocated_count) + return 0; + + if (!adapter->vf_data[vf].vlans_enabled) { + u32 size; + reg = rd32(E1000_VMOLR(vf)); + size = reg & E1000_VMOLR_RLPML_MASK; + size += 4; + reg &= ~E1000_VMOLR_RLPML_MASK; + reg |= size; + wr32(E1000_VMOLR(vf), reg); + } + adapter->vf_data[vf].vlans_enabled++; + return 0; } } else { @@ -4066,6 +4090,21 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf) igb_vfta_set(hw, vid, false); } wr32(E1000_VLVF(i), reg); + + /* do not modify RLPML for PF devices */ + if (vf >= adapter->vfs_allocated_count) + return 0; + + adapter->vf_data[vf].vlans_enabled--; + if (!adapter->vf_data[vf].vlans_enabled) { + u32 size; + reg = rd32(E1000_VMOLR(vf)); + size = reg & E1000_VMOLR_RLPML_MASK; + size -= 4; + reg &= ~E1000_VMOLR_RLPML_MASK; + reg |= size; + wr32(E1000_VMOLR(vf), reg); + } return 0; } } -- cgit v0.10.2 From 8de8b2e63490fe7e90128299983198d09d1679c9 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Thu, 3 Sep 2009 14:55:50 +0000 Subject: ixgbe: Add support for multiple Tx queues for FCoE in 82599 This patch adds support for multiple transmit queues to the Fiber Channel over Ethernet (FCoE) feature found in 82599. Currently, FCoE has multiple Rx queues available, along with a redirection table, that helps distribute the I/O load across multiple CPUs based on the FC exchange ID. To make this the most effective, we need to provide the same layout of transmit queues to match receive. Particularly, when Data Center Bridging (DCB) is enabled, the designated traffic class for FCoE can have dedicated queues for just FCoE traffic, while not affecting any other type of traffic flow. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 47d9dde..a6bc1ef 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -36,6 +36,7 @@ #define BIT_PFC 0x02 #define BIT_PG_RX 0x04 #define BIT_PG_TX 0x08 +#define BIT_APP_UPCHG 0x10 #define BIT_RESETLINK 0x40 #define BIT_LINKSPEED 0x80 @@ -348,8 +349,14 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) msleep(1); - if (netif_running(netdev)) - ixgbe_down(adapter); + if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + ixgbe_clear_interrupt_scheme(adapter); + } else { + if (netif_running(netdev)) + ixgbe_down(adapter); + } } ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, @@ -373,8 +380,14 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) } if (adapter->dcb_set_bitmap & BIT_RESETLINK) { - if (netif_running(netdev)) - ixgbe_up(adapter); + if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { + ixgbe_init_interrupt_scheme(adapter); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + } else { + if (netif_running(netdev)) + ixgbe_up(adapter); + } ret = DCB_HW_CHG_RST; } else if (adapter->dcb_set_bitmap & BIT_PFC) { if (adapter->hw.mac.type == ixgbe_mac_82598EB) @@ -526,8 +539,20 @@ static u8 ixgbe_dcbnl_setapp(struct net_device *netdev, switch (idtype) { case DCB_APP_IDTYPE_ETHTYPE: #ifdef IXGBE_FCOE - if (id == ETH_P_FCOE) - rval = ixgbe_fcoe_setapp(netdev_priv(netdev), up); + if (id == ETH_P_FCOE) { + u8 tc; + struct ixgbe_adapter *adapter; + + adapter = netdev_priv(netdev); + tc = adapter->fcoe.tc; + rval = ixgbe_fcoe_setapp(adapter, up); + if ((!rval) && (tc != adapter->fcoe.tc) && + (adapter->flags & IXGBE_FLAG_DCB_ENABLED) && + (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) { + adapter->dcb_set_bitmap |= BIT_APP_UPCHG; + adapter->dcb_set_bitmap |= BIT_RESETLINK; + } + } #endif break; case DCB_APP_IDTYPE_PORTNUM: diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 4042d878..724754a 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3113,14 +3113,16 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter) f->indices = min((int)num_online_cpus(), f->indices); if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + adapter->num_rx_queues = 1; + adapter->num_tx_queues = 1; #ifdef CONFIG_IXGBE_DCB if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { - DPRINTK(PROBE, INFO, "FCOE enabled with DCB \n"); + DPRINTK(PROBE, INFO, "FCoE enabled with DCB \n"); ixgbe_set_dcb_queues(adapter); } #endif if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { - DPRINTK(PROBE, INFO, "FCOE enabled with RSS \n"); + DPRINTK(PROBE, INFO, "FCoE enabled with RSS \n"); if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) || (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)) ixgbe_set_fdir_queues(adapter); @@ -3130,8 +3132,7 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter) /* adding FCoE rx rings to the end */ f->mask = adapter->num_rx_queues; adapter->num_rx_queues += f->indices; - if (adapter->num_tx_queues == 0) - adapter->num_tx_queues = f->indices; + adapter->num_tx_queues += f->indices; ret = true; } @@ -3371,15 +3372,36 @@ static bool inline ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter) */ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter) { - int i, fcoe_i = 0; + int i, fcoe_rx_i = 0, fcoe_tx_i = 0; bool ret = false; struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE]; if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { #ifdef CONFIG_IXGBE_DCB if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + struct ixgbe_fcoe *fcoe = &adapter->fcoe; + ixgbe_cache_ring_dcb(adapter); - fcoe_i = adapter->rx_ring[0].reg_idx + 1; + /* find out queues in TC for FCoE */ + fcoe_rx_i = adapter->rx_ring[fcoe->tc].reg_idx + 1; + fcoe_tx_i = adapter->tx_ring[fcoe->tc].reg_idx + 1; + /* + * In 82599, the number of Tx queues for each traffic + * class for both 8-TC and 4-TC modes are: + * TCs : TC0 TC1 TC2 TC3 TC4 TC5 TC6 TC7 + * 8 TCs: 32 32 16 16 8 8 8 8 + * 4 TCs: 64 64 32 32 + * We have max 8 queues for FCoE, where 8 the is + * FCoE redirection table size. If TC for FCoE is + * less than or equal to TC3, we have enough queues + * to add max of 8 queues for FCoE, so we start FCoE + * tx descriptor from the next one, i.e., reg_idx + 1. + * If TC for FCoE is above TC3, implying 8 TC mode, + * and we need 8 for FCoE, we have to take all queues + * in that traffic class for FCoE. + */ + if ((f->indices == IXGBE_FCRETA_SIZE) && (fcoe->tc > 3)) + fcoe_tx_i--; } #endif /* CONFIG_IXGBE_DCB */ if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { @@ -3389,10 +3411,13 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter) else ixgbe_cache_ring_rss(adapter); - fcoe_i = f->mask; + fcoe_rx_i = f->mask; + fcoe_tx_i = f->mask; + } + for (i = 0; i < f->indices; i++, fcoe_rx_i++, fcoe_tx_i++) { + adapter->rx_ring[f->mask + i].reg_idx = fcoe_rx_i; + adapter->tx_ring[f->mask + i].reg_idx = fcoe_tx_i; } - for (i = 0; i < f->indices; i++, fcoe_i++) - adapter->rx_ring[f->mask + i].reg_idx = fcoe_i; ret = true; } return ret; -- cgit v0.10.2 From 09ad1cc099f4ba4735d11ce1c5f024ffc521be3b Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Thu, 3 Sep 2009 14:56:10 +0000 Subject: ixgbe: Distribute transmission of FCoE traffic in 82599 This adds a simple selection of a FCoE tx queue based on the current cpu id to distribute transmission of FCoE traffic evenly among multiple FCoE transmit queues. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 724754a..45bf8b9 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5168,9 +5168,15 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, tx_ring = &adapter->tx_ring[r_idx]; if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && - (skb->protocol == htons(ETH_P_FCOE))) + (skb->protocol == htons(ETH_P_FCOE))) { tx_flags |= IXGBE_TX_FLAGS_FCOE; - +#ifdef IXGBE_FCOE + r_idx = smp_processor_id(); + r_idx &= (adapter->ring_feature[RING_F_FCOE].indices - 1); + r_idx += adapter->ring_feature[RING_F_FCOE].mask; + tx_ring = &adapter->tx_ring[r_idx]; +#endif + } /* four things can cause us to need a context descriptor */ if (skb_is_gso(skb) || (skb->ip_summed == CHECKSUM_PARTIAL) || -- cgit v0.10.2 From d4ab88194e982a0d213000a75475d3e76b2626f0 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Thu, 3 Sep 2009 14:56:31 +0000 Subject: ixgbe: Add support for using FCoE DDP in 82599 as FCoE targets The FCoE DDP in 82599 can be used for both FCoE initiator as well as FCoE target, depending on the indication of the exchange being the responder or originator in the F_CTL (frame control) field in the encapsulated Fiber Channel frame header (T10 Spec., FC-FS). For the initiator, OX_ID is used for FCoE DDP, where for the target RX_ID is used for FCoE DDP. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 0607cff..a3c9f99 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -292,6 +292,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, struct sk_buff *skb) { u16 xid; + u32 fctl; u32 sterr, fceofe, fcerr, fcstat; int rc = -EINVAL; struct ixgbe_fcoe *fcoe; @@ -312,7 +313,12 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, skb_set_transport_header(skb, skb_network_offset(skb) + sizeof(struct fcoe_hdr)); fh = (struct fc_frame_header *)skb_transport_header(skb); - xid = be16_to_cpu(fh->fh_ox_id); + fctl = ntoh24(fh->fh_f_ctl); + if (fctl & FC_FC_EX_CTX) + xid = be16_to_cpu(fh->fh_ox_id); + else + xid = be16_to_cpu(fh->fh_rx_id); + if (xid >= IXGBE_FCOE_DDP_MAX) goto ddp_out; -- cgit v0.10.2 From bc75e5bfad2a6d24fc5a9885a2f6b93f82c6c5f1 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Thu, 3 Sep 2009 13:10:53 +0000 Subject: netxen: fix lro buffer allocation Alloc 12k skbuffs so that firmware can aggregate more packets into one buffer. This doesn't raise memory consumption since 9k skbs use 16k slab cache anyway. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 224a746..ede2fa7 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -149,6 +149,7 @@ #define NX_P2_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P2_MAX_MTU) #define NX_P3_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P3_MAX_MTU) #define NX_CT_DEFAULT_RX_BUF_LEN 2048 +#define NX_LRO_BUFFER_EXTRA 2048 #define NX_RX_LRO_BUFFER_LENGTH (8060) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 8d4aa6f..04e36f2 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -265,6 +265,10 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) else rds_ring->dma_size = NX_P2_RX_JUMBO_BUF_MAX_LEN; + + if (adapter->capabilities & NX_CAP0_HW_LRO) + rds_ring->dma_size += NX_LRO_BUFFER_EXTRA; + rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN; break; @@ -1217,6 +1221,7 @@ netxen_process_rcv(struct netxen_adapter *adapter, if (pkt_offset) skb_pull(skb, pkt_offset); + skb->truesize = skb->len + sizeof(struct sk_buff); skb->protocol = eth_type_trans(skb, netdev); napi_gro_receive(&sds_ring->napi, skb); @@ -1278,8 +1283,7 @@ netxen_process_lro(struct netxen_adapter *adapter, skb_put(skb, lro_length + data_offset); - skb->truesize = (skb->len + sizeof(struct sk_buff) + - ((unsigned long)skb->data - (unsigned long)skb->head)); + skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb); skb_pull(skb, l2_hdr_offset); skb->protocol = eth_type_trans(skb, netdev); -- cgit v0.10.2 From 270e57e133a9e61c8c62ea4a0d1ffdf53f91caf1 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Thu, 3 Sep 2009 13:10:54 +0000 Subject: netxen: remove duplicate napi_add Remove duplicate calls to netxen_napi_add(). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index f824a39..53d57dc 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1095,10 +1095,6 @@ netxen_setup_netdev(struct netxen_adapter *adapter, netdev->irq = adapter->msix_entries[0].vector; - err = netxen_napi_add(adapter, netdev); - if (err) - return err; - init_timer(&adapter->watchdog_timer); adapter->watchdog_timer.function = &netxen_watchdog; adapter->watchdog_timer.data = (unsigned long)adapter; @@ -2038,8 +2034,6 @@ netxen_remove_sysfs_entries(struct netxen_adapter *adapter) device_remove_file(dev, &dev_attr_bridged_mode); } -static void netxen_watchdog(unsigned long); - #ifdef CONFIG_INET #define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops) -- cgit v0.10.2 From cf503e8f458cec455b18d3938b3b27de6db3105e Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Thu, 3 Sep 2009 13:10:55 +0000 Subject: netxen: fix infinite loop on dma mapping failure Fix a perpetual while() loop in unwinding partial mapped tx skb on dma mapping failure. Reported-by: "Juha Leppanen" Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 53d57dc..41b2967 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1577,8 +1577,8 @@ netxen_map_tx_skb(struct pci_dev *pdev, return 0; unwind: - while (i > 0) { - nf = &pbuf->frag_array[i]; + while (--i >= 0) { + nf = &pbuf->frag_array[i+1]; pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); } -- cgit v0.10.2 From c23ddf8f22fc2c871ce476ff917d1208bbe4f3de Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 3 Sep 2009 06:16:25 +0000 Subject: sky2: only enable Vaux if capable of wakeup While perusing vendor driver, I saw that it did not enable the Vaux power unless device was able to wake from lan for D3cold. This might help for Rene's power issue. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index d1f3b46..bab591b4 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -272,8 +272,9 @@ static void sky2_power_aux(struct sky2_hw *hw) Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); - /* switch power to VAUX */ - if (sky2_read32(hw, B0_CTST) & Y2_VAUX_AVAIL) + /* switch power to VAUX if supported and PME from D3cold */ + if ( (sky2_read32(hw, B0_CTST) & Y2_VAUX_AVAIL) && + pci_pme_capable(hw->pdev, PCI_D3cold)) sky2_write8(hw, B0_POWER_CTRL, (PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF)); -- cgit v0.10.2 From aae5e7c30fc660c50dfecbdd745799b05af90f01 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 3 Sep 2009 10:38:33 +0000 Subject: netdev: Remove SIOCDEVPRIVATE aliases for MDIO ioctls The standard MDIO ioctl numbers are well-established and these should no longer be needed. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index d7579e4..24ae671 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2218,16 +2218,13 @@ static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCGMIIPHY: - case SIOCDEVPRIVATE: data[0] = dev->phy.address; /* Fall through */ case SIOCGMIIREG: - case SIOCDEVPRIVATE + 1: data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]); return 0; case SIOCSMIIREG: - case SIOCDEVPRIVATE + 2: if (!capable(CAP_NET_ADMIN)) return -EPERM; emac_mdio_write(ndev, dev->phy.address, data[1], data[2]); diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index bd41351..b52e5d9 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -3053,12 +3053,10 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch(cmd) { case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ data->phy_id = np->phy_addr_external; /* Fall Through */ case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ /* The phy_id is not enough to uniquely identify * the intended target. Therefore the command is sent to * the given mii on the current port. @@ -3077,7 +3075,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; if (dev->if_port == PORT_TP) { -- cgit v0.10.2 From 7ab0f2736bfe137a82a7084bbfb5f809da95cabd Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 3 Sep 2009 10:39:43 +0000 Subject: netdev: Remove redundant checks for CAP_NET_ADMIN in MDIO implementations dev_ioctl() already checks capable(CAP_NET_ADMIN) before calling the driver's implementation of MDIO ioctls. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 98b5f46..4e6359f 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1524,9 +1524,6 @@ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd) int err; u32 mii_regval; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - switch(cmd) { case SIOCGMIIPHY: data->phy_id = lp->ext_phy_addr; diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index e46bf92..be2c6cf 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -534,10 +534,6 @@ static int atl1c_mii_ioctl(struct net_device *netdev, break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) { - retval = -EPERM; - goto out; - } if (atl1c_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) { retval = -EIO; @@ -546,10 +542,6 @@ static int atl1c_mii_ioctl(struct net_device *netdev, break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) { - retval = -EPERM; - goto out; - } if (data->reg_num & ~(0x1F)) { retval = -EFAULT; goto out; diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index bca127e..69b830f 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -453,10 +453,6 @@ static int atl1e_mii_ioctl(struct net_device *netdev, break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) { - retval = -EPERM; - goto out; - } if (atl1e_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) { retval = -EIO; @@ -465,10 +461,6 @@ static int atl1e_mii_ioctl(struct net_device *netdev, break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) { - retval = -EPERM; - goto out; - } if (data->reg_num & ~(0x1F)) { retval = -EFAULT; goto out; diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index 10c06b9..ab68886 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -966,8 +966,6 @@ static int atl2_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) data->phy_id = 0; break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; spin_lock_irqsave(&adapter->stats_lock, flags); if (atl2_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) { @@ -977,8 +975,6 @@ static int atl2_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) spin_unlock_irqrestore(&adapter->stats_lock, flags); break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (data->reg_num & ~(0x1F)) return -EFAULT; spin_lock_irqsave(&adapter->stats_lock, flags); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 1357d54..08cddb6 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -7480,9 +7480,6 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) return -EOPNOTSUPP; diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 7517dc1..05916aa 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4875,10 +4875,6 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) { - rc = -EPERM; - break; - } spin_lock_irqsave(&cp->lock, flags); cas_mif_poll(cp, 0); rc = cas_phy_write(cp, data->reg_num & 0x1f, data->val_in); diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 2c723b1..c66dd4f 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4714,8 +4714,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, data->phy_id = hw->phy_addr; break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; spin_lock_irqsave(&adapter->stats_lock, flags); if (e1000_read_phy_reg(hw, data->reg_num & 0x1F, &data->val_out)) { @@ -4725,8 +4723,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, spin_unlock_irqrestore(&adapter->stats_lock, flags); break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (data->reg_num & ~(0x1F)) return -EFAULT; mii_reg = data->val_in; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 0f8d961..16c193a 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4346,8 +4346,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, data->phy_id = adapter->hw.phy.addr; break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; switch (data->reg_num & 0x1F) { case MII_BMCR: data->val_out = adapter->phy_regs.bmcr; diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 24ae671..8a95234 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2225,8 +2225,6 @@ static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; emac_mdio_write(ndev, dev->phy.address, data[1], data[2]); return 0; default: diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 90b0b1b..943186b 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -4914,8 +4914,6 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) data->phy_id = adapter->hw.phy.addr; break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) return -EIO; diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index 7d2e610..21f8754 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -380,10 +380,7 @@ int mdio_mii_ioctl(const struct mdio_if_info *mdio, cmd = SIOCGMIIREG; break; case SIOCGMIIREG: - break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; break; default: return -EOPNOTSUPP; diff --git a/drivers/net/mii.c b/drivers/net/mii.c index d81a5d2..210b2b1 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -433,9 +433,6 @@ int generic_mii_ioctl(struct mii_if_info *mii_if, case SIOCSMIIREG: { u16 val = mii_data->val_in; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (mii_data->phy_id == mii_if->phy_id) { switch(mii_data->reg_num) { case MII_BMCR: { diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index b52e5d9..b2722c4 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -3075,8 +3075,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (dev->if_port == PORT_TP) { if ((data->phy_id & 0x1f) == np->phy_addr_external) { if ((data->reg_num & 0x1f) == MII_ADVERTISE) diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index c47ba36..0c44b48 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1784,11 +1784,6 @@ static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) break; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable (CAP_NET_ADMIN)) { - rc = -EPERM; - break; - } - spin_lock_irqsave (&tp->lock, flags); mdio_write (dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); spin_unlock_irqrestore (&tp->lock, flags); diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 382d265..d836af1 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -1124,8 +1124,6 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) int saved_window; unsigned long flags; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; spin_lock_irqsave(&lp->window_lock, flags); saved_window = inw(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 3b681c1..4f2fef6 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -706,8 +706,6 @@ static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]); return 0; } diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 9ef1c1b..8996b45 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1204,8 +1204,6 @@ static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]); return 0; } diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 68de891..9709dd1 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1575,8 +1575,6 @@ do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) data[3] = mii_rd(ioaddr, data[0] & 0x1f, data[1] & 0x1f); break; case SIOCSMIIREG: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; mii_wr(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2], 16); break; default: diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index eda94fc..6b71b00 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -324,9 +324,6 @@ int phy_mii_ioctl(struct phy_device *phydev, break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (mii_data->phy_id == phydev->addr) { switch(mii_data->reg_num) { case MII_BMCR: diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index ec0092af..a91e9b3 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1991,8 +1991,6 @@ static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *dat return 0; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; mdio_write(tp->mmio_addr, data->reg_num & 0x1f, data->val_in); return 0; } diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index d882732..97949d0 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -2128,8 +2128,6 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; mdio_write(net_dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; default: diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 1a1e685..62e852e 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2496,9 +2496,6 @@ static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - spin_lock_bh(&hw->phy_lock); if (hw->chip_id == CHIP_ID_GENESIS) err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f, diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index bab591b4..00bc65a 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1214,9 +1214,6 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - spin_lock_bh(&sky2->phy_lock); err = gm_phy_write(hw, sky2->port, data->reg_num & 0x1f, data->val_in); diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index e0dfdd2..305ec3d 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2852,9 +2852,7 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - rc = -EPERM; - else if (!gp->running) + if (!gp->running) rc = -EAGAIN; else { __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index bd49810..7cf8000 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10610,9 +10610,6 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) break; /* We have no PHY */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (tp->link_config.phy_is_low_power) return -EAGAIN; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 49e273b..3d31b47 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1004,8 +1004,6 @@ static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; TLan_MiiWriteReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index b89b73c..6b2330e 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -923,8 +923,6 @@ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable (CAP_NET_ADMIN)) - return -EPERM; if (regnum & ~0x1f) return -EINVAL; if (data->phy_id == phy) { diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 3e59397e..b38d3b7 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1470,8 +1470,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; spin_lock_irq(&np->lock); mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); spin_unlock_irq(&np->lock); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index ced1446..e04e5be 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2328,14 +2328,10 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd miidata->phy_id = readb(®s->MIIADR) & 0x1f; break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0) return -ETIMEDOUT; break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; spin_lock_irqsave(&vptr->lock, flags); err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in); spin_unlock_irqrestore(&vptr->lock, flags); diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 4987040..40ad0de 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1365,8 +1365,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (data->phy_id == np->phys[0]) { u16 value = data->val_in; switch (data->reg_num) { -- cgit v0.10.2 From 0fa0ee053aaa53939306376719450cfe56e33e3b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 3 Sep 2009 10:41:17 +0000 Subject: netdev: Convert MDIO ioctl implementation to use struct mii_ioctl_data A few drivers still access the arguments to MDIO ioctls as an array of u16. Convert them to use struct mii_ioctl_data. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 8a95234..1d7d7fe 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2209,7 +2209,7 @@ static const struct ethtool_ops emac_ethtool_ops = { static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { struct emac_instance *dev = netdev_priv(ndev); - uint16_t *data = (uint16_t *) & rq->ifr_ifru; + struct mii_ioctl_data *data = if_mii(rq); DBG(dev, "ioctl %08x" NL, cmd); @@ -2218,14 +2218,16 @@ static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCGMIIPHY: - data[0] = dev->phy.address; + data->phy_id = dev->phy.address; /* Fall through */ case SIOCGMIIREG: - data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]); + data->val_out = emac_mdio_read(ndev, dev->phy.address, + data->reg_num); return 0; case SIOCSMIIREG: - emac_mdio_write(ndev, dev->phy.address, data[1], data[2]); + emac_mdio_write(ndev, dev->phy.address, data->reg_num, + data->val_in); return 0; default: return -EOPNOTSUPP; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index d836af1..ee8ad3e 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -85,6 +85,7 @@ earlier 3Com products. #include #include #include +#include #include #include @@ -1096,16 +1097,16 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_ifru; + struct mii_ioctl_data *data = if_mii(rq); int phy = lp->phys & 0x1f; DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", dev->name, rq->ifr_ifrn.ifrn_name, cmd, - data[0], data[1], data[2], data[3]); + data->phy_id, data->reg_num, data->val_in, data->val_out); switch(cmd) { case SIOCGMIIPHY: /* Get the address of the PHY in use. */ - data[0] = phy; + data->phy_id = phy; case SIOCGMIIREG: /* Read the specified MII register. */ { int saved_window; @@ -1114,7 +1115,8 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) spin_lock_irqsave(&lp->window_lock, flags); saved_window = inw(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); - data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, + data->reg_num & 0x1f); EL3WINDOW(saved_window); spin_unlock_irqrestore(&lp->window_lock, flags); return 0; @@ -1127,7 +1129,8 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) spin_lock_irqsave(&lp->window_lock, flags); saved_window = inw(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); - mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(ioaddr, data->phy_id & 0x1f, + data->reg_num & 0x1f, data->val_in); EL3WINDOW(saved_window); spin_unlock_irqrestore(&lp->window_lock, flags); return 0; diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 4f2fef6..3131a59 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "../8390.h" #include @@ -697,16 +698,16 @@ static const struct ethtool_ops netdev_ethtool_ops = { static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { axnet_dev_t *info = PRIV(dev); - u16 *data = (u16 *)&rq->ifr_ifru; + struct mii_ioctl_data *data = if_mii(rq); unsigned int mii_addr = dev->base_addr + AXNET_MII_EEP; switch (cmd) { case SIOCGMIIPHY: - data[0] = info->phy_id; + data->phy_id = info->phy_id; case SIOCGMIIREG: /* Read MII PHY register. */ - data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f); + data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]); + mdio_write(mii_addr, data->phy_id, data->reg_num & 0x1f, data->val_in); return 0; } return -EOPNOTSUPP; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 8996b45..90a94d2 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "../8390.h" #include @@ -1191,7 +1192,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { pcnet_dev_t *info = PRIV(dev); - u16 *data = (u16 *)&rq->ifr_ifru; + struct mii_ioctl_data *data = if_mii(rq); unsigned int mii_addr = dev->base_addr + DLINK_GPIO; if (!(info->flags & (IS_DL10019|IS_DL10022))) @@ -1199,12 +1200,12 @@ static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCGMIIPHY: - data[0] = info->phy_id; + data->phy_id = info->phy_id; case SIOCGMIIREG: /* Read MII PHY register. */ - data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f); + data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]); + mdio_write(mii_addr, data->phy_id, data->reg_num & 0x1f, data->val_in); return 0; } return -EOPNOTSUPP; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 9709dd1..cf84231 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include @@ -1558,24 +1559,26 @@ do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { local_info_t *local = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_ifru; + struct mii_ioctl_data *data = if_mii(rq); DEBUG(1, "%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n", dev->name, rq->ifr_ifrn.ifrn_name, cmd, - data[0], data[1], data[2], data[3]); + data->phy_id, data->reg_num, data->val_in, data->val_out); if (!local->mohawk) return -EOPNOTSUPP; switch(cmd) { case SIOCGMIIPHY: /* Get the address of the PHY in use. */ - data[0] = 0; /* we have only this address */ + data->phy_id = 0; /* we have only this address */ /* fall through */ case SIOCGMIIREG: /* Read the specified MII register. */ - data[3] = mii_rd(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + data->val_out = mii_rd(ioaddr, data->phy_id & 0x1f, + data->reg_num & 0x1f); break; case SIOCSMIIREG: /* Write the specified MII register */ - mii_wr(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2], 16); + mii_wr(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in, + 16); break; default: return -EOPNOTSUPP; -- cgit v0.10.2 From 2c11455321f37da6fe6cc36353149f9ac9183334 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 3 Sep 2009 00:11:45 +0000 Subject: macvlan: add multiqueue capability macvlan devices are currently not multi-queue capable. We can do that defining rtnl_link_ops method, get_tx_queues(), called from rtnl_create_link() This new method gets num_tx_queues/real_num_tx_queues from lower device. macvlan_get_tx_queues() is a copy of vlan_get_tx_queues(). Because macvlan_start_xmit() has to update netdev_queue stats only (and not dev->stats), I chose to change tx_errors/tx_aborted_errors accounting to tx_dropped, since netdev_queue structure doesnt define tx_errors / tx_aborted_errors. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index c85c46d..3aabfd9 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -187,6 +187,8 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, struct net_device *dev) { + int i = skb_get_queue_mapping(skb); + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); const struct macvlan_dev *vlan = netdev_priv(dev); unsigned int len = skb->len; int ret; @@ -195,12 +197,11 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, ret = dev_queue_xmit(skb); if (likely(ret == NET_XMIT_SUCCESS)) { - dev->stats.tx_packets++; - dev->stats.tx_bytes += len; - } else { - dev->stats.tx_errors++; - dev->stats.tx_aborted_errors++; - } + txq->tx_packets++; + txq->tx_bytes += len; + } else + txq->tx_dropped++; + return NETDEV_TX_OK; } @@ -484,6 +485,25 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) return 0; } +static int macvlan_get_tx_queues(struct net *net, + struct nlattr *tb[], + unsigned int *num_tx_queues, + unsigned int *real_num_tx_queues) +{ + struct net_device *real_dev; + + if (!tb[IFLA_LINK]) + return -EINVAL; + + real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK])); + if (!real_dev) + return -ENODEV; + + *num_tx_queues = real_dev->num_tx_queues; + *real_num_tx_queues = real_dev->real_num_tx_queues; + return 0; +} + static int macvlan_newlink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { @@ -550,6 +570,7 @@ static void macvlan_dellink(struct net_device *dev) static struct rtnl_link_ops macvlan_link_ops __read_mostly = { .kind = "macvlan", .priv_size = sizeof(struct macvlan_dev), + .get_tx_queues = macvlan_get_tx_queues, .setup = macvlan_setup, .validate = macvlan_validate, .newlink = macvlan_newlink, -- cgit v0.10.2 From 1a123a3168566b10f87f228ae963770b26f27420 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 3 Sep 2009 00:39:16 +0000 Subject: vlan: adds drops accounting Its hard to tell if vlans are dropping frames, since every frame given to vlan_???_start_xmit() functions is accounted as fully transmitted by lower device. We can test dev_queue_xmit() return values to properly account for dropped frames. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 3938c3e..4198ec5 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -294,6 +294,8 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, int i = skb_get_queue_mapping(skb); struct netdev_queue *txq = netdev_get_tx_queue(dev, i); struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); + unsigned int len; + int ret; /* Handle non-VLAN frames if they are sent to us, for example by DHCP. * @@ -319,11 +321,17 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, vlan_dev_info(dev)->cnt_inc_headroom_on_tx++; } - txq->tx_packets++; - txq->tx_bytes += skb->len; skb->dev = vlan_dev_info(dev)->real_dev; - dev_queue_xmit(skb); + len = skb->len; + ret = dev_queue_xmit(skb); + + if (likely(ret == NET_XMIT_SUCCESS)) { + txq->tx_packets++; + txq->tx_bytes += len; + } else + txq->tx_dropped++; + return NETDEV_TX_OK; } @@ -333,16 +341,23 @@ static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, int i = skb_get_queue_mapping(skb); struct netdev_queue *txq = netdev_get_tx_queue(dev, i); u16 vlan_tci; + unsigned int len; + int ret; vlan_tci = vlan_dev_info(dev)->vlan_id; vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); skb = __vlan_hwaccel_put_tag(skb, vlan_tci); - txq->tx_packets++; - txq->tx_bytes += skb->len; - skb->dev = vlan_dev_info(dev)->real_dev; - dev_queue_xmit(skb); + len = skb->len; + ret = dev_queue_xmit(skb); + + if (likely(ret == NET_XMIT_SUCCESS)) { + txq->tx_packets++; + txq->tx_bytes += len; + } else + txq->tx_dropped++; + return NETDEV_TX_OK; } -- cgit v0.10.2 From 27e6c7d33835e7f347cdfb5025766b7d9a6596d1 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:01:53 +0000 Subject: enic: add support for multiple BARs Nic firmware can place resources (queues, intrs, etc) on multiple BARs, so allow driver to discover/map resources beyond BAR0. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index c26cea0..cfe94b2 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -33,13 +33,15 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco 10G Ethernet Driver" -#define DRV_VERSION "1.0.0.933" -#define DRV_COPYRIGHT "Copyright 2008 Cisco Systems, Inc" +#define DRV_VERSION "1.1.0.100" +#define DRV_COPYRIGHT "Copyright 2008-2009 Cisco Systems, Inc" #define PFX DRV_NAME ": " #define ENIC_LRO_MAX_DESC 8 #define ENIC_LRO_MAX_AGGR 64 +#define ENIC_BARS_MAX 6 + enum enic_cq_index { ENIC_CQ_RQ, ENIC_CQ_WQ, @@ -73,7 +75,7 @@ struct enic { struct net_device *netdev; struct pci_dev *pdev; struct vnic_enet_config config; - struct vnic_dev_bar bar0; + struct vnic_dev_bar bar[ENIC_BARS_MAX]; struct vnic_dev *vdev; struct timer_list notify_timer; struct work_struct reset; diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 2ea0363..2821a1d 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1609,12 +1609,6 @@ static void enic_clear_intr_mode(struct enic *enic) vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN); } -static void enic_iounmap(struct enic *enic) -{ - if (enic->bar0.vaddr) - iounmap(enic->bar0.vaddr); -} - static const struct net_device_ops enic_netdev_ops = { .ndo_open = enic_open, .ndo_stop = enic_stop, @@ -1633,6 +1627,15 @@ static const struct net_device_ops enic_netdev_ops = { #endif }; +static void enic_iounmap(struct enic *enic) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(enic->bar); i++) + if (enic->bar[i].vaddr) + iounmap(enic->bar[i].vaddr); +} + static int __devinit enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1710,31 +1713,28 @@ static int __devinit enic_probe(struct pci_dev *pdev, using_dac = 1; } - /* Map vNIC resources from BAR0 + /* Map vNIC resources from BAR0-5 */ - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - printk(KERN_ERR PFX - "BAR0 not memory-map'able, aborting.\n"); - err = -ENODEV; - goto err_out_release_regions; - } - - enic->bar0.vaddr = pci_iomap(pdev, 0, enic->bar0.len); - enic->bar0.bus_addr = pci_resource_start(pdev, 0); - enic->bar0.len = pci_resource_len(pdev, 0); - - if (!enic->bar0.vaddr) { - printk(KERN_ERR PFX - "Cannot memory-map BAR0 res hdr, aborting.\n"); - err = -ENODEV; - goto err_out_release_regions; + for (i = 0; i < ARRAY_SIZE(enic->bar); i++) { + if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM)) + continue; + enic->bar[i].len = pci_resource_len(pdev, i); + enic->bar[i].vaddr = pci_iomap(pdev, i, enic->bar[i].len); + if (!enic->bar[i].vaddr) { + printk(KERN_ERR PFX + "Cannot memory-map BAR %d, aborting.\n", i); + err = -ENODEV; + goto err_out_iounmap; + } + enic->bar[i].bus_addr = pci_resource_start(pdev, i); } /* Register vNIC device */ - enic->vdev = vnic_dev_register(NULL, enic, pdev, &enic->bar0); + enic->vdev = vnic_dev_register(NULL, enic, pdev, enic->bar, + ARRAY_SIZE(enic->bar)); if (!enic->vdev) { printk(KERN_ERR PFX "vNIC registration failed, aborting.\n"); diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index e21b9d6..d5c28ef 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -31,6 +31,7 @@ struct vnic_res { void __iomem *vaddr; + dma_addr_t bus_addr; unsigned int count; }; @@ -67,12 +68,15 @@ void *vnic_dev_priv(struct vnic_dev *vdev) } static int vnic_dev_discover_res(struct vnic_dev *vdev, - struct vnic_dev_bar *bar) + struct vnic_dev_bar *bar, unsigned int num_bars) { struct vnic_resource_header __iomem *rh; struct vnic_resource __iomem *r; u8 type; + if (num_bars == 0) + return -EINVAL; + if (bar->len < VNIC_MAX_RES_HDR_SIZE) { printk(KERN_ERR "vNIC BAR0 res hdr length error\n"); return -EINVAL; @@ -104,7 +108,10 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, r++; - if (bar_num != 0) /* only mapping in BAR0 resources */ + if (bar_num >= num_bars) + continue; + + if (!bar[bar_num].len || !bar[bar_num].vaddr) continue; switch (type) { @@ -114,13 +121,13 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, case RES_TYPE_INTR_CTRL: /* each count is stride bytes long */ len = count * VNIC_RES_STRIDE; - if (len + bar_offset > bar->len) { + if (len + bar_offset > bar[bar_num].len) { printk(KERN_ERR "vNIC BAR0 resource %d " "out-of-bounds, offset 0x%x + " "size 0x%x > bar len 0x%lx\n", type, bar_offset, len, - bar->len); + bar[bar_num].len); return -EINVAL; } break; @@ -133,7 +140,9 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, } vdev->res[type].count = count; - vdev->res[type].vaddr = (char __iomem *)bar->vaddr + bar_offset; + vdev->res[type].vaddr = (char __iomem *)bar[bar_num].vaddr + + bar_offset; + vdev->res[type].bus_addr = bar[bar_num].bus_addr + bar_offset; } return 0; @@ -163,6 +172,21 @@ void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, } } +dma_addr_t vnic_dev_get_res_bus_addr(struct vnic_dev *vdev, + enum vnic_res_type type, unsigned int index) +{ + switch (type) { + case RES_TYPE_WQ: + case RES_TYPE_RQ: + case RES_TYPE_CQ: + case RES_TYPE_INTR_CTRL: + return vdev->res[type].bus_addr + + index * VNIC_RES_STRIDE; + default: + return vdev->res[type].bus_addr; + } +} + unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, unsigned int desc_count, unsigned int desc_size) { @@ -257,7 +281,7 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, iowrite32(cmd, &devcmd->cmd); if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) - return 0; + return 0; for (delay = 0; delay < wait; delay++) { @@ -684,7 +708,8 @@ void vnic_dev_unregister(struct vnic_dev *vdev) } struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, - void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar) + void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar, + unsigned int num_bars) { if (!vdev) { vdev = kzalloc(sizeof(struct vnic_dev), GFP_ATOMIC); @@ -695,7 +720,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, vdev->priv = priv; vdev->pdev = pdev; - if (vnic_dev_discover_res(vdev, bar)) + if (vnic_dev_discover_res(vdev, bar, num_bars)) goto err_out; vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index 8aa8db2..d960edb 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h @@ -75,6 +75,8 @@ unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, enum vnic_res_type type); void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, unsigned int index); +dma_addr_t vnic_dev_get_res_bus_addr(struct vnic_dev *vdev, + enum vnic_res_type type, unsigned int index); unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, unsigned int desc_count, unsigned int desc_size); void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring); @@ -117,6 +119,7 @@ void vnic_dev_set_intr_mode(struct vnic_dev *vdev, enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev); void vnic_dev_unregister(struct vnic_dev *vdev); struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, - void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar); + void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar, + unsigned int num_bars); #endif /* _VNIC_DEV_H_ */ -- cgit v0.10.2 From 4badc385d1a9e140ad0992537237fc22211adad0 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:01:58 +0000 Subject: enic: workaround A0 erratum A0 revision ASIC has an erratum on the RQ desc cache on chip where the cache can become corrupted causing pkt buf writes to wrong locations. The s/w workaround is to post a dummy RQ desc in the ring every 32 descs, causing a flush of the cache. A0 parts are not production, but there are enough of these parts in the wild in test setups to warrant including workaround. A1 revision ASIC parts fix erratum. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 2821a1d..58cae6e 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -851,6 +851,50 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq) return 0; } +static int enic_rq_alloc_buf_a1(struct vnic_rq *rq) +{ + struct rq_enet_desc *desc = vnic_rq_next_desc(rq); + + if (vnic_rq_posting_soon(rq)) { + + /* SW workaround for A0 HW erratum: if we're just about + * to write posted_index, insert a dummy desc + * of type resvd + */ + + rq_enet_desc_enc(desc, 0, RQ_ENET_TYPE_RESV2, 0); + vnic_rq_post(rq, 0, 0, 0, 0); + } else { + return enic_rq_alloc_buf(rq); + } + + return 0; +} + +static int enic_set_rq_alloc_buf(struct enic *enic) +{ + enum vnic_dev_hw_version hw_ver; + int err; + + err = vnic_dev_hw_version(enic->vdev, &hw_ver); + if (err) + return err; + + switch (hw_ver) { + case VNIC_DEV_HW_VER_A1: + enic->rq_alloc_buf = enic_rq_alloc_buf_a1; + break; + case VNIC_DEV_HW_VER_A2: + case VNIC_DEV_HW_VER_UNKNOWN: + enic->rq_alloc_buf = enic_rq_alloc_buf; + break; + default: + return -ENODEV; + } + + return 0; +} + static int enic_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph, u64 *hdr_flags, void *priv) { @@ -1058,7 +1102,7 @@ static int enic_poll(struct napi_struct *napi, int budget) /* Replenish RQ */ - vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); + vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf); } else { @@ -1093,7 +1137,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) /* Replenish RQ */ - vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); + vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf); /* Return intr event credits for this polling * cycle. An intr event is the completion of a @@ -1269,7 +1313,7 @@ static int enic_open(struct net_device *netdev) } for (i = 0; i < enic->rq_count; i++) { - err = vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf); + err = vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf); if (err) { printk(KERN_ERR PFX "%s: Unable to alloc receive buffers.\n", diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index d5c28ef..c8d3fc7 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -349,6 +349,25 @@ int vnic_dev_fw_info(struct vnic_dev *vdev, return err; } +int vnic_dev_hw_version(struct vnic_dev *vdev, enum vnic_dev_hw_version *hw_ver) +{ + struct vnic_devcmd_fw_info *fw_info; + int err; + + err = vnic_dev_fw_info(vdev, &fw_info); + if (err) + return err; + + if (strncmp(fw_info->hw_version, "A1", sizeof("A1")) == 0) + *hw_ver = VNIC_DEV_HW_VER_A1; + else if (strncmp(fw_info->hw_version, "A2", sizeof("A2")) == 0) + *hw_ver = VNIC_DEV_HW_VER_A2; + else + *hw_ver = VNIC_DEV_HW_VER_UNKNOWN; + + return 0; +} + int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, void *value) { diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index d960edb..db1d63e 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h @@ -41,6 +41,12 @@ static inline void writeq(u64 val, void __iomem *reg) } #endif +enum vnic_dev_hw_version { + VNIC_DEV_HW_VER_UNKNOWN, + VNIC_DEV_HW_VER_A1, + VNIC_DEV_HW_VER_A2, +}; + enum vnic_dev_intr_mode { VNIC_DEV_INTR_MODE_UNKNOWN, VNIC_DEV_INTR_MODE_INTX, @@ -88,6 +94,8 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait); int vnic_dev_fw_info(struct vnic_dev *vdev, struct vnic_devcmd_fw_info **fw_info); +int vnic_dev_hw_version(struct vnic_dev *vdev, + enum vnic_dev_hw_version *hw_ver); int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, void *value); int vnic_dev_stats_clear(struct vnic_dev *vdev); diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h index fd0ef66..f7b5730 100644 --- a/drivers/net/enic/vnic_rq.h +++ b/drivers/net/enic/vnic_rq.h @@ -143,6 +143,11 @@ static inline void vnic_rq_post(struct vnic_rq *rq, } } +static inline int vnic_rq_posting_soon(struct vnic_rq *rq) +{ + return ((rq->to_use->index & VNIC_RQ_RETURN_RATE) == 0); +} + static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) { rq->ring.desc_avail += count; @@ -186,7 +191,7 @@ static inline int vnic_rq_fill(struct vnic_rq *rq, { int err; - while (vnic_rq_desc_avail(rq) > 1) { + while (vnic_rq_desc_avail(rq) > 0) { err = (*buf_fill)(rq); if (err) -- cgit v0.10.2 From ea0d7d9181b0831f1b570b02fa02a15f25520c12 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:03 +0000 Subject: enic: bug fix: split TSO fragments larger than 16K into multiple descs enic WQ desc supports a maximum 16K buf size, so split any send fragments larger than 16K into several descs. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 58cae6e..bc5cb22 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -44,10 +44,15 @@ #include "enic.h" #define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ) +#define WQ_ENET_MAX_DESC_LEN (1 << WQ_ENET_LEN_BITS) +#define MAX_TSO (1 << 16) +#define ENIC_DESC_MAX_SPLITS (MAX_TSO / WQ_ENET_MAX_DESC_LEN + 1) + +#define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ /* Supported devices */ static struct pci_device_id enic_id_table[] = { - { PCI_VDEVICE(CISCO, 0x0043) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, { 0, } /* end of table */ }; @@ -310,7 +315,8 @@ static int enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, opaque); if (netif_queue_stopped(enic->netdev) && - vnic_wq_desc_avail(&enic->wq[q_number]) >= MAX_SKB_FRAGS + 1) + vnic_wq_desc_avail(&enic->wq[q_number]) >= + (MAX_SKB_FRAGS + ENIC_DESC_MAX_SPLITS)) netif_wake_queue(enic->netdev); spin_unlock(&enic->wq_lock[q_number]); @@ -525,7 +531,11 @@ static inline void enic_queue_wq_skb_vlan(struct enic *enic, unsigned int len_left = skb->len - head_len; int eop = (len_left == 0); - /* Queue the main skb fragment */ + /* Queue the main skb fragment. The fragments are no larger + * than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less + * than WQ_ENET_MAX_DESC_LEN length. So only one descriptor + * per fragment is queued. + */ enic_queue_wq_desc(wq, skb, pci_map_single(enic->pdev, skb->data, head_len, PCI_DMA_TODEVICE), @@ -547,7 +557,11 @@ static inline void enic_queue_wq_skb_csum_l4(struct enic *enic, unsigned int csum_offset = hdr_len + skb->csum_offset; int eop = (len_left == 0); - /* Queue the main skb fragment */ + /* Queue the main skb fragment. The fragments are no larger + * than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less + * than WQ_ENET_MAX_DESC_LEN length. So only one descriptor + * per fragment is queued. + */ enic_queue_wq_desc_csum_l4(wq, skb, pci_map_single(enic->pdev, skb->data, head_len, PCI_DMA_TODEVICE), @@ -565,10 +579,14 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss, int vlan_tag_insert, unsigned int vlan_tag) { - unsigned int head_len = skb_headlen(skb); - unsigned int len_left = skb->len - head_len; + unsigned int frag_len_left = skb_headlen(skb); + unsigned int len_left = skb->len - frag_len_left; unsigned int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); int eop = (len_left == 0); + unsigned int len; + dma_addr_t dma_addr; + unsigned int offset = 0; + skb_frag_t *frag; /* Preload TCP csum field with IP pseudo hdr calculated * with IP length set to zero. HW will later add in length @@ -584,17 +602,49 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic, &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); } - /* Queue the main skb fragment */ - enic_queue_wq_desc_tso(wq, skb, - pci_map_single(enic->pdev, skb->data, - head_len, PCI_DMA_TODEVICE), - head_len, - mss, hdr_len, - vlan_tag_insert, vlan_tag, - eop); + /* Queue WQ_ENET_MAX_DESC_LEN length descriptors + * for the main skb fragment + */ + while (frag_len_left) { + len = min(frag_len_left, (unsigned int)WQ_ENET_MAX_DESC_LEN); + dma_addr = pci_map_single(enic->pdev, skb->data + offset, + len, PCI_DMA_TODEVICE); + enic_queue_wq_desc_tso(wq, skb, + dma_addr, + len, + mss, hdr_len, + vlan_tag_insert, vlan_tag, + eop && (len == frag_len_left)); + frag_len_left -= len; + offset += len; + } - if (!eop) - enic_queue_wq_skb_cont(enic, wq, skb, len_left); + if (eop) + return; + + /* Queue WQ_ENET_MAX_DESC_LEN length descriptors + * for additional data fragments + */ + for (frag = skb_shinfo(skb)->frags; len_left; frag++) { + len_left -= frag->size; + frag_len_left = frag->size; + offset = frag->page_offset; + + while (frag_len_left) { + len = min(frag_len_left, + (unsigned int)WQ_ENET_MAX_DESC_LEN); + dma_addr = pci_map_page(enic->pdev, frag->page, + offset, len, + PCI_DMA_TODEVICE); + enic_queue_wq_desc_cont(wq, skb, + dma_addr, + len, + (len_left == 0) && + (len == frag_len_left)); /* EOP? */ + frag_len_left -= len; + offset += len; + } + } } static inline void enic_queue_wq_skb(struct enic *enic, @@ -648,7 +698,8 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb, spin_lock_irqsave(&enic->wq_lock[0], flags); - if (vnic_wq_desc_avail(wq) < skb_shinfo(skb)->nr_frags + 1) { + if (vnic_wq_desc_avail(wq) < + skb_shinfo(skb)->nr_frags + ENIC_DESC_MAX_SPLITS) { netif_stop_queue(netdev); /* This is a hard error, log it */ printk(KERN_ERR PFX "%s: BUG! Tx ring full when " @@ -659,7 +710,7 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb, enic_queue_wq_skb(enic, wq, skb); - if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + 1) + if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + ENIC_DESC_MAX_SPLITS) netif_stop_queue(netdev); spin_unlock_irqrestore(&enic->wq_lock[0], flags); -- cgit v0.10.2 From d19e22dc2c1c43724c1d9ce4a5456ae74eeb6da8 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:08 +0000 Subject: enic: use netdev_alloc_skb Use netdev_alloc_skb rather than dev_alloc_skb Signed-off-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index bc5cb22..73f0107 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -869,11 +869,12 @@ static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) dev_kfree_skb_any(buf->os_buf); } -static inline struct sk_buff *enic_rq_alloc_skb(unsigned int size) +static inline struct sk_buff *enic_rq_alloc_skb(struct net_device *netdev, + unsigned int size) { struct sk_buff *skb; - skb = dev_alloc_skb(size + NET_IP_ALIGN); + skb = netdev_alloc_skb(netdev, size + NET_IP_ALIGN); if (skb) skb_reserve(skb, NET_IP_ALIGN); @@ -884,12 +885,13 @@ static inline struct sk_buff *enic_rq_alloc_skb(unsigned int size) static int enic_rq_alloc_buf(struct vnic_rq *rq) { struct enic *enic = vnic_dev_priv(rq->vdev); + struct net_device *netdev = enic->netdev; struct sk_buff *skb; - unsigned int len = enic->netdev->mtu + ETH_HLEN; + unsigned int len = netdev->mtu + ETH_HLEN; unsigned int os_buf_index = 0; dma_addr_t dma_addr; - skb = enic_rq_alloc_skb(len); + skb = enic_rq_alloc_skb(netdev, len); if (!skb) return -ENOMEM; -- cgit v0.10.2 From 56ac88b38e5918d92bdfc97c528068e45ff4581c Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:14 +0000 Subject: enic: bug fix: protect fw call i/f with spinlock Some driver -> nic firmware calls weren't guarded with a spinlock, exposing the call i/f to a race between two threads Signed-off-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 73f0107..36cf0fc 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1316,6 +1316,7 @@ static int enic_notify_set(struct enic *enic) { int err; + spin_lock(&enic->devcmd_lock); switch (vnic_dev_get_intr_mode(enic->vdev)) { case VNIC_DEV_INTR_MODE_INTX: err = vnic_dev_notify_set(enic->vdev, ENIC_INTX_NOTIFY); @@ -1327,6 +1328,7 @@ static int enic_notify_set(struct enic *enic) err = vnic_dev_notify_set(enic->vdev, -1 /* no intr */); break; } + spin_unlock(&enic->devcmd_lock); return err; } @@ -1380,12 +1382,16 @@ static int enic_open(struct net_device *netdev) for (i = 0; i < enic->rq_count; i++) vnic_rq_enable(&enic->rq[i]); + spin_lock(&enic->devcmd_lock); enic_add_station_addr(enic); + spin_unlock(&enic->devcmd_lock); enic_set_multicast_list(netdev); netif_wake_queue(netdev); napi_enable(&enic->napi); + spin_lock(&enic->devcmd_lock); vnic_dev_enable(enic->vdev); + spin_unlock(&enic->devcmd_lock); for (i = 0; i < enic->intr_count; i++) vnic_intr_unmask(&enic->intr[i]); @@ -1395,7 +1401,9 @@ static int enic_open(struct net_device *netdev) return 0; err_out_notify_unset: + spin_lock(&enic->devcmd_lock); vnic_dev_notify_unset(enic->vdev); + spin_unlock(&enic->devcmd_lock); err_out_free_intr: enic_free_intr(enic); @@ -1411,7 +1419,9 @@ static int enic_stop(struct net_device *netdev) del_timer_sync(&enic->notify_timer); + spin_lock(&enic->devcmd_lock); vnic_dev_disable(enic->vdev); + spin_unlock(&enic->devcmd_lock); napi_disable(&enic->napi); netif_stop_queue(netdev); @@ -1429,7 +1439,9 @@ static int enic_stop(struct net_device *netdev) return err; } + spin_lock(&enic->devcmd_lock); vnic_dev_notify_unset(enic->vdev); + spin_unlock(&enic->devcmd_lock); enic_free_intr(enic); (void)vnic_cq_service(&enic->cq[ENIC_CQ_RQ], -- cgit v0.10.2 From 350991e12ac1ac407850169a0d65f522a7fd029e Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:19 +0000 Subject: enic: bug fix: included MAC drops in rx_dropped netstat Bug fix: included MAC drops in rx_dropped netstat. Also track Rx trunctations stat at the MAC Signed-off-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index cfe94b2..f7c5b33 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -99,6 +99,7 @@ struct enic { ____cacheline_aligned struct vnic_rq rq[1]; unsigned int rq_count; int (*rq_alloc_buf)(struct vnic_rq *rq); + u64 rq_truncated_pkts; u64 rq_bad_fcs; struct napi_struct napi; struct net_lro_mgr lro_mgr; diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 36cf0fc..b265b10 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -738,8 +738,9 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev) net_stats->rx_bytes = stats->rx.rx_bytes_ok; net_stats->rx_errors = stats->rx.rx_errors; net_stats->multicast = stats->rx.rx_multicast_frames_ok; + net_stats->rx_over_errors = enic->rq_truncated_pkts; net_stats->rx_crc_errors = enic->rq_bad_fcs; - net_stats->rx_dropped = stats->rx.rx_no_bufs; + net_stats->rx_dropped = stats->rx.rx_no_bufs + stats->rx.rx_drop; return net_stats; } @@ -1029,8 +1030,12 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, if (packet_error) { - if (bytes_written > 0 && !fcs_ok) - enic->rq_bad_fcs++; + if (!fcs_ok) { + if (bytes_written > 0) + enic->rq_bad_fcs++; + else if (bytes_written == 0) + enic->rq_truncated_pkts++; + } dev_kfree_skb_any(skb); -- cgit v0.10.2 From 6ba9cdc09678d6925c205ef0b0bd374e31589ecf Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:24 +0000 Subject: enic: provision for multiple Rx/Tx queues; prepare for RSS support Provision for multiple Rx/Tx queues. Max of 8 WQs and 8 RQs. Max for completion queue is 8+8=16 and max for interrupt resources is 8+8+2. Add driver/firmware interface for setting up RSS secret key and indirection table. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index f7c5b33..e1c2076 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -29,6 +29,7 @@ #include "vnic_cq.h" #include "vnic_intr.h" #include "vnic_stats.h" +#include "vnic_nic.h" #include "vnic_rss.h" #define DRV_NAME "enic" @@ -42,17 +43,20 @@ #define ENIC_BARS_MAX 6 +#define ENIC_WQ_MAX 8 +#define ENIC_RQ_MAX 8 +#define ENIC_CQ_MAX (ENIC_WQ_MAX + ENIC_RQ_MAX) +#define ENIC_INTR_MAX (ENIC_CQ_MAX + 2) + enum enic_cq_index { ENIC_CQ_RQ, ENIC_CQ_WQ, - ENIC_CQ_MAX, }; enum enic_intx_intr_index { ENIC_INTX_WQ_RQ, ENIC_INTX_ERR, ENIC_INTX_NOTIFY, - ENIC_INTX_MAX, }; enum enic_msix_intr_index { @@ -90,13 +94,13 @@ struct enic { u32 port_mtu; /* work queue cache line section */ - ____cacheline_aligned struct vnic_wq wq[1]; - spinlock_t wq_lock[1]; + ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX]; + spinlock_t wq_lock[ENIC_WQ_MAX]; unsigned int wq_count; struct vlan_group *vlan_group; /* receive queue cache line section */ - ____cacheline_aligned struct vnic_rq rq[1]; + ____cacheline_aligned struct vnic_rq rq[ENIC_RQ_MAX]; unsigned int rq_count; int (*rq_alloc_buf)(struct vnic_rq *rq); u64 rq_truncated_pkts; @@ -106,7 +110,7 @@ struct enic { struct net_lro_desc lro_desc[ENIC_LRO_MAX_DESC]; /* interrupt resource cache line section */ - ____cacheline_aligned struct vnic_intr intr[ENIC_MSIX_MAX]; + ____cacheline_aligned struct vnic_intr intr[ENIC_INTR_MAX]; unsigned int intr_count; u32 __iomem *legacy_pba; /* memory-mapped */ diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index b265b10..e01067e 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1586,7 +1586,7 @@ static int enic_set_niccfg(struct enic *enic) const u8 ig_vlan_strip_en = 1; /* Enable VLAN tag stripping. RSS not enabled (yet). - */ + */ return enic_set_nic_cfg(enic, rss_default_cpu, rss_hash_type, @@ -1621,8 +1621,8 @@ static void enic_reset(struct work_struct *work) static int enic_set_intr_mode(struct enic *enic) { - unsigned int n = ARRAY_SIZE(enic->rq); - unsigned int m = ARRAY_SIZE(enic->wq); + unsigned int n = 1; + unsigned int m = 1; unsigned int i; /* Set interrupt mode (INTx, MSI, MSI-X) depending diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index e5fc938..3211114 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -156,6 +156,22 @@ int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type, return vnic_dev_cmd(enic->vdev, CMD_NIC_CFG, &a0, &a1, wait); } +int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len) +{ + u64 a0 = (u64)key_pa, a1 = len; + int wait = 1000; + + return vnic_dev_cmd(enic->vdev, CMD_RSS_KEY, &a0, &a1, wait); +} + +int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len) +{ + u64 a0 = (u64)cpu_pa, a1 = len; + int wait = 1000; + + return vnic_dev_cmd(enic->vdev, CMD_RSS_CPU, &a0, &a1, wait); +} + void enic_free_vnic_resources(struct enic *enic) { unsigned int i; @@ -172,11 +188,18 @@ void enic_free_vnic_resources(struct enic *enic) void enic_get_res_counts(struct enic *enic) { - enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ); - enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ); - enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ); - enic->intr_count = vnic_dev_get_res_count(enic->vdev, - RES_TYPE_INTR_CTRL); + enic->wq_count = min_t(int, + vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ), + ENIC_WQ_MAX); + enic->rq_count = min_t(int, + vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ), + ENIC_RQ_MAX); + enic->cq_count = min_t(int, + vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ), + ENIC_CQ_MAX); + enic->intr_count = min_t(int, + vnic_dev_get_res_count(enic->vdev, RES_TYPE_INTR_CTRL), + ENIC_INTR_MAX); printk(KERN_INFO PFX "vNIC resources avail: " "wq %d rq %d cq %d intr %d\n", diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h index 7bf272f..abc1974 100644 --- a/drivers/net/enic/enic_res.h +++ b/drivers/net/enic/enic_res.h @@ -139,6 +139,8 @@ void enic_del_vlan(struct enic *enic, u16 vlanid); int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type, u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en, u8 ig_vlan_strip_en); +int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len); +int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len); void enic_get_res_counts(struct enic *enic); void enic_init_vnic_resources(struct enic *enic); int enic_alloc_vnic_resources(struct enic *); diff --git a/drivers/net/enic/vnic_nic.h b/drivers/net/enic/vnic_nic.h index dadf26f..eeaf329 100644 --- a/drivers/net/enic/vnic_nic.h +++ b/drivers/net/enic/vnic_nic.h @@ -41,6 +41,13 @@ #define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD 1UL #define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT 24 +#define NIC_CFG_RSS_HASH_TYPE_IPV4 (1 << 0) +#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 (1 << 1) +#define NIC_CFG_RSS_HASH_TYPE_IPV6 (1 << 2) +#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6 (1 << 3) +#define NIC_CFG_RSS_HASH_TYPE_IPV6_EX (1 << 4) +#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX (1 << 5) + static inline void vnic_set_nic_cfg(u32 *nic_cfg, u8 rss_default_cpu, u8 rss_hash_type, u8 rss_hash_bits, u8 rss_base_cpu, -- cgit v0.10.2 From 9f63a7c6aef00a8eafa7521342099f199f68c575 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:29 +0000 Subject: enic: bug fix: enable VLAN filtering Bug fix: enable VLAN filtering Signed-off-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index e01067e..e0bf224 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1968,7 +1968,8 @@ static int __devinit enic_probe(struct pci_dev *pdev, break; } - netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->features |= NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; if (ENIC_SETTING(enic, TXCSUM)) netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; if (ENIC_SETTING(enic, TSO)) -- cgit v0.10.2 From d73149f51e165f5872bc431ae181650396145265 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:35 +0000 Subject: enic: changes to driver/firmware interface Deprecate some old APIa; change arguments to stats dump all API; add new interrupt assert API Signed-off-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index c8d3fc7..29a48e8 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -560,6 +560,20 @@ void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err); } +int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr) +{ + u64 a0 = intr, a1 = 0; + int wait = 1000; + int err; + + err = vnic_dev_cmd(vdev, CMD_IAR, &a0, &a1, wait); + if (err) + printk(KERN_ERR "Failed to raise INTR[%d], err %d\n", + intr, err); + + return err; +} + int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) { u64 a0, a1; diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index db1d63e..fc5e3eb 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h @@ -106,6 +106,7 @@ void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr); void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr); int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr); +int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr); int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr); void vnic_dev_notify_unset(struct vnic_dev *vdev); int vnic_dev_link_status(struct vnic_dev *vdev); diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h index 2587f34..d78bbcc 100644 --- a/drivers/net/enic/vnic_devcmd.h +++ b/drivers/net/enic/vnic_devcmd.h @@ -105,14 +105,6 @@ enum vnic_devcmd_cmd { CMD_MAC_ADDR = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 9), - /* disable/enable promisc mode: (u8)a0=0/1 */ -/***** XXX DEPRECATED *****/ - CMD_PROMISC_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 10), - - /* disable/enable all-multi mode: (u8)a0=0/1 */ -/***** XXX DEPRECATED *****/ - CMD_ALLMULTI_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 11), - /* add addr from (u48)a0 */ CMD_ADDR_ADD = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 12), @@ -182,7 +174,9 @@ enum vnic_devcmd_cmd { /* disable virtual link */ CMD_DISABLE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 29), - /* stats dump all vnics on uplink in mem: (u64)a0=paddr (u32)a1=uif */ + /* stats dump sum of all vnic stats on same uplink in mem: + * (u64)a0=paddr + * (u16)a1=sizeof stats area */ CMD_STATS_DUMP_ALL = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 30), /* init status: @@ -211,7 +205,12 @@ enum vnic_devcmd_cmd { /* persistent binding info * in: (u64)a0=paddr of arg * (u32)a1=CMD_PERBI_XXX */ - CMD_PERBI = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_FC, 37), + CMD_PERBI = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_FC, 37), + + /* Interrupt Assert Register functionality + * in: (u16)a0=interrupt number to assert + */ + CMD_IAR = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 38), }; /* flags for CMD_OPEN */ @@ -244,6 +243,7 @@ enum vnic_devcmd_error { ERR_ENOMEM = 7, ERR_ETIMEDOUT = 8, ERR_ELINKDOWN = 9, + ERR_EMAXRES = 10, }; struct vnic_devcmd_fw_info { diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c index ddc38f8..1f8786d 100644 --- a/drivers/net/enic/vnic_intr.c +++ b/drivers/net/enic/vnic_intr.c @@ -60,3 +60,8 @@ void vnic_intr_clean(struct vnic_intr *intr) { iowrite32(0, &intr->ctrl->int_credits); } + +void vnic_intr_raise(struct vnic_intr *intr) +{ + vnic_dev_raise_intr(intr->vdev, (u16)intr->index); +} -- cgit v0.10.2 From 491598a44f12fe8b862ab4123de1a1ffe9b86832 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:40 +0000 Subject: enic: bug fix: check for zero port MTU before posting warning Nic firmware can return zero for port MTU, so check for non-zero value before checking for change in port MTU. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index e0bf224..f800218 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -362,7 +362,7 @@ static void enic_mtu_check(struct enic *enic) { u32 mtu = vnic_dev_mtu(enic->vdev); - if (mtu != enic->port_mtu) { + if (mtu && mtu != enic->port_mtu) { if (mtu < enic->netdev->mtu) printk(KERN_WARNING PFX "%s: interface MTU (%d) set higher " -- cgit v0.10.2 From 6fdfa97073a2bcbb60d900654c612b2ff09b9cb7 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:45 +0000 Subject: enic: organize device initialization/deinit into separate functions To unclutter probe() a little bit, put all device initialization code in one spot and device deinit code in another spot. Also remove unused rq->buf_index variable/func. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index f800218..d69d52e 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1741,6 +1741,88 @@ static const struct net_device_ops enic_netdev_ops = { #endif }; +void enic_dev_deinit(struct enic *enic) +{ + netif_napi_del(&enic->napi); + enic_free_vnic_resources(enic); + enic_clear_intr_mode(enic); +} + +int enic_dev_init(struct enic *enic) +{ + struct net_device *netdev = enic->netdev; + int err; + + /* Get vNIC configuration + */ + + err = enic_get_vnic_config(enic); + if (err) { + printk(KERN_ERR PFX + "Get vNIC configuration failed, aborting.\n"); + return err; + } + + /* Get available resource counts + */ + + enic_get_res_counts(enic); + + /* Set interrupt mode based on resource counts and system + * capabilities + */ + + err = enic_set_intr_mode(enic); + if (err) { + printk(KERN_ERR PFX + "Failed to set intr mode, aborting.\n"); + return err; + } + + /* Allocate and configure vNIC resources + */ + + err = enic_alloc_vnic_resources(enic); + if (err) { + printk(KERN_ERR PFX + "Failed to alloc vNIC resources, aborting.\n"); + goto err_out_free_vnic_resources; + } + + enic_init_vnic_resources(enic); + + err = enic_set_rq_alloc_buf(enic); + if (err) { + printk(KERN_ERR PFX + "Failed to set RQ buffer allocator, aborting.\n"); + goto err_out_free_vnic_resources; + } + + err = enic_set_niccfg(enic); + if (err) { + printk(KERN_ERR PFX + "Failed to config nic, aborting.\n"); + goto err_out_free_vnic_resources; + } + + switch (vnic_dev_get_intr_mode(enic->vdev)) { + default: + netif_napi_add(netdev, &enic->napi, enic_poll, 64); + break; + case VNIC_DEV_INTR_MODE_MSIX: + netif_napi_add(netdev, &enic->napi, enic_poll_msix, 64); + break; + } + + return 0; + +err_out_free_vnic_resources: + enic_clear_intr_mode(enic); + enic_free_vnic_resources(enic); + + return err; +} + static void enic_iounmap(struct enic *enic) { unsigned int i; @@ -1883,51 +1965,13 @@ static int __devinit enic_probe(struct pci_dev *pdev, goto err_out_dev_close; } - /* Get vNIC configuration - */ - - err = enic_get_vnic_config(enic); + err = enic_dev_init(enic); if (err) { printk(KERN_ERR PFX - "Get vNIC configuration failed, aborting.\n"); + "Device initialization failed, aborting.\n"); goto err_out_dev_close; } - /* Get available resource counts - */ - - enic_get_res_counts(enic); - - /* Set interrupt mode based on resource counts and system - * capabilities - */ - - err = enic_set_intr_mode(enic); - if (err) { - printk(KERN_ERR PFX - "Failed to set intr mode, aborting.\n"); - goto err_out_dev_close; - } - - /* Allocate and configure vNIC resources - */ - - err = enic_alloc_vnic_resources(enic); - if (err) { - printk(KERN_ERR PFX - "Failed to alloc vNIC resources, aborting.\n"); - goto err_out_free_vnic_resources; - } - - enic_init_vnic_resources(enic); - - err = enic_set_niccfg(enic); - if (err) { - printk(KERN_ERR PFX - "Failed to config nic, aborting.\n"); - goto err_out_free_vnic_resources; - } - /* Setup notification timer, HW reset task, and locks */ @@ -1952,22 +1996,13 @@ static int __devinit enic_probe(struct pci_dev *pdev, if (err) { printk(KERN_ERR PFX "Invalid MAC address, aborting.\n"); - goto err_out_free_vnic_resources; + goto err_out_dev_deinit; } netdev->netdev_ops = &enic_netdev_ops; netdev->watchdog_timeo = 2 * HZ; netdev->ethtool_ops = &enic_ethtool_ops; - switch (vnic_dev_get_intr_mode(enic->vdev)) { - default: - netif_napi_add(netdev, &enic->napi, enic_poll, 64); - break; - case VNIC_DEV_INTR_MODE_MSIX: - netif_napi_add(netdev, &enic->napi, enic_poll_msix, 64); - break; - } - netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; if (ENIC_SETTING(enic, TXCSUM)) @@ -1995,17 +2030,16 @@ static int __devinit enic_probe(struct pci_dev *pdev, if (err) { printk(KERN_ERR PFX "Cannot register net device, aborting.\n"); - goto err_out_free_vnic_resources; + goto err_out_dev_deinit; } return 0; -err_out_free_vnic_resources: - enic_free_vnic_resources(enic); +err_out_dev_deinit: + enic_dev_deinit(enic); err_out_dev_close: vnic_dev_close(enic->vdev); err_out_vnic_unregister: - enic_clear_intr_mode(enic); vnic_dev_unregister(enic->vdev); err_out_iounmap: enic_iounmap(enic); @@ -2029,9 +2063,8 @@ static void __devexit enic_remove(struct pci_dev *pdev) flush_scheduled_work(); unregister_netdev(netdev); - enic_free_vnic_resources(enic); + enic_dev_deinit(enic); vnic_dev_close(enic->vdev); - enic_clear_intr_mode(enic); vnic_dev_unregister(enic->vdev); enic_iounmap(enic); pci_release_regions(pdev); diff --git a/drivers/net/enic/vnic_rq.c b/drivers/net/enic/vnic_rq.c index 9365e63..7558397 100644 --- a/drivers/net/enic/vnic_rq.c +++ b/drivers/net/enic/vnic_rq.c @@ -62,7 +62,6 @@ static int vnic_rq_alloc_bufs(struct vnic_rq *rq) } rq->to_use = rq->to_clean = rq->bufs[0]; - rq->buf_index = 0; return 0; } @@ -113,12 +112,12 @@ int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, return 0; } -void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, +void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index, + unsigned int fetch_index, unsigned int posted_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset) { u64 paddr; - u32 fetch_index; paddr = (u64)rq->ring.base_addr | VNIC_PADDR_TARGET; writeq(paddr, &rq->ctrl->ring_base); @@ -128,15 +127,27 @@ void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, iowrite32(error_interrupt_offset, &rq->ctrl->error_interrupt_offset); iowrite32(0, &rq->ctrl->dropped_packet_count); iowrite32(0, &rq->ctrl->error_status); + iowrite32(fetch_index, &rq->ctrl->fetch_index); + iowrite32(posted_index, &rq->ctrl->posted_index); - /* Use current fetch_index as the ring starting point */ - fetch_index = ioread32(&rq->ctrl->fetch_index); rq->to_use = rq->to_clean = &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES] [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES]; - iowrite32(fetch_index, &rq->ctrl->posted_index); +} + +void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset) +{ + u32 fetch_index; - rq->buf_index = 0; + /* Use current fetch_index as the ring starting point */ + fetch_index = ioread32(&rq->ctrl->fetch_index); + + vnic_rq_init_start(rq, cq_index, + fetch_index, fetch_index, + error_interrupt_enable, + error_interrupt_offset); } unsigned int vnic_rq_error_status(struct vnic_rq *rq) @@ -192,8 +203,6 @@ void vnic_rq_clean(struct vnic_rq *rq, [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES]; iowrite32(fetch_index, &rq->ctrl->posted_index); - rq->buf_index = 0; - vnic_dev_clear_desc_ring(&rq->ring); } diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h index f7b5730..35e736c 100644 --- a/drivers/net/enic/vnic_rq.h +++ b/drivers/net/enic/vnic_rq.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2008, 2009 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. * * This program is free software; you may redistribute it and/or modify @@ -79,7 +79,6 @@ struct vnic_rq { struct vnic_rq_buf *to_use; struct vnic_rq_buf *to_clean; void *os_buf_head; - unsigned int buf_index; unsigned int pkts_outstanding; }; @@ -105,11 +104,6 @@ static inline unsigned int vnic_rq_next_index(struct vnic_rq *rq) return rq->to_use->index; } -static inline unsigned int vnic_rq_next_buf_index(struct vnic_rq *rq) -{ - return rq->buf_index++; -} - static inline void vnic_rq_post(struct vnic_rq *rq, void *os_buf, unsigned int os_buf_index, dma_addr_t dma_addr, unsigned int len) @@ -204,6 +198,10 @@ static inline int vnic_rq_fill(struct vnic_rq *rq, void vnic_rq_free(struct vnic_rq *rq); int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, unsigned int desc_count, unsigned int desc_size); +void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index, + unsigned int fetch_index, unsigned int posted_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset); void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset); diff --git a/drivers/net/enic/vnic_wq.c b/drivers/net/enic/vnic_wq.c index a576d04..d2e00e5 100644 --- a/drivers/net/enic/vnic_wq.c +++ b/drivers/net/enic/vnic_wq.c @@ -112,7 +112,8 @@ int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, return 0; } -void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, +void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, + unsigned int fetch_index, unsigned int posted_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset) { @@ -121,12 +122,25 @@ void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET; writeq(paddr, &wq->ctrl->ring_base); iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size); - iowrite32(0, &wq->ctrl->fetch_index); - iowrite32(0, &wq->ctrl->posted_index); + iowrite32(fetch_index, &wq->ctrl->fetch_index); + iowrite32(posted_index, &wq->ctrl->posted_index); iowrite32(cq_index, &wq->ctrl->cq_index); iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable); iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset); iowrite32(0, &wq->ctrl->error_status); + + wq->to_use = wq->to_clean = + &wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES] + [fetch_index % VNIC_WQ_BUF_BLK_ENTRIES]; +} + +void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset) +{ + vnic_wq_init_start(wq, cq_index, 0, 0, + error_interrupt_enable, + error_interrupt_offset); } unsigned int vnic_wq_error_status(struct vnic_wq *wq) diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/enic/vnic_wq.h index c826137..9c34d41 100644 --- a/drivers/net/enic/vnic_wq.h +++ b/drivers/net/enic/vnic_wq.h @@ -149,6 +149,10 @@ static inline void vnic_wq_service(struct vnic_wq *wq, void vnic_wq_free(struct vnic_wq *wq); int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, unsigned int desc_count, unsigned int desc_size); +void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, + unsigned int fetch_index, unsigned int posted_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset); void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset); -- cgit v0.10.2 From a8fdf2b331b38d61fb5f11f3aec4a4f9fb2dedcb Mon Sep 17 00:00:00 2001 From: Cosmin Ratiu Date: Thu, 3 Sep 2009 20:44:38 -0700 Subject: ipv6: Fix tcp_v6_send_response(): it didn't set skb transport header Here is a patch which fixes an issue observed when using TCP over IPv6 and AH from IPsec. When a connection gets closed the 4-way method and the last ACK from the server gets dropped, the subsequent FINs from the client do not get ACKed because tcp_v6_send_response does not set the transport header pointer. This causes ah6_output to try to allocate a lot of memory, which typically fails, so the ACKs never make it out of the stack. I have reproduced the problem on kernel 2.6.7, but after looking at the latest kernel it seems the problem is still there. Signed-off-by: Cosmin Ratiu Signed-off-by: David S. Miller diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 65aecf2..3aae0f2 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1003,6 +1003,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); t1 = (struct tcphdr *) skb_push(buff, tot_len); + skb_reset_transport_header(skb); /* Swap the send and the receive. */ memset(t1, 0, sizeof(*t1)); -- cgit v0.10.2 From fab4e76373a614d3af624caedf18bee43fc6ca16 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 3 Sep 2009 21:34:39 -0700 Subject: WAN: dscc4: Fix warning pointing out a bug. Noticed by Stephen Rothwell: Today's linux-next build (x86_64 allmodconfig gcc-4.4.0) produced this warning: drivers/net/wan/dscc4.c: In function 'dscc4_rx_skb': drivers/net/wan/dscc4.c:670: warning: suggest parentheses around comparison in operand of '|' which actually points out a bug, I think. It is doing (x & (y | z)) != y | z when it probably means (x & (y | z)) != (y | z) Introduced by commit 5de3fcab91b0e1809eec030355d15801daf25083 ("WAN: bit and/or confusion"). Signed-off-by: David S. Miller diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index b2247bd..81c8aec 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -667,7 +667,7 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, else if (!(skb->data[pkt_len] & FrameCrc)) dev->stats.rx_crc_errors++; else if ((skb->data[pkt_len] & (FrameVfr | FrameRab)) != - FrameVfr | FrameRab) + (FrameVfr | FrameRab)) dev->stats.rx_length_errors++; dev->stats.rx_errors++; dev_kfree_skb_irq(skb); -- cgit v0.10.2 From 53f824520b6d84ca5b4a8fd71addc91dbf64357e Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 3 Sep 2009 14:31:44 -0700 Subject: x86/i386: Put aligned stack-canary in percpu shared_aligned section Pack aligned things together into a special section to minimize padding holes. Suggested-by: Eric Dumazet Signed-off-by: Jeremy Fitzhardinge Cc: Tejun Heo LKML-Reference: <4AA035C0.9070202@goop.org> [ queued up in tip:x86/asm because it depends on this commit: x86/i386: Make sure stack-protector segment base is cache aligned ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index e597ecc..ac7e796 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -413,7 +413,7 @@ struct stack_canary { char __pad[20]; /* canary at %gs:20 */ unsigned long canary; }; -DECLARE_PER_CPU(struct stack_canary, stack_canary) ____cacheline_aligned; +DECLARE_PER_CPU_ALIGNED(struct stack_canary, stack_canary); #endif #endif /* X86_64 */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 7d84bc4..f23e236 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1043,7 +1043,7 @@ DEFINE_PER_CPU(struct orig_ist, orig_ist); #else /* CONFIG_X86_64 */ #ifdef CONFIG_CC_STACKPROTECTOR -DEFINE_PER_CPU(struct stack_canary, stack_canary) ____cacheline_aligned; +DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary); #endif /* Make sure %fs and %gs are initialized properly in idle threads */ diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index aa00800..90079c3 100644 --- a/include/asm-generic/percpu.h +++ b/include/asm-generic/percpu.h @@ -81,14 +81,17 @@ extern void setup_per_cpu_areas(void); #ifdef MODULE #define PER_CPU_SHARED_ALIGNED_SECTION "" +#define PER_CPU_ALIGNED_SECTION "" #else #define PER_CPU_SHARED_ALIGNED_SECTION ".shared_aligned" +#define PER_CPU_ALIGNED_SECTION ".shared_aligned" #endif #define PER_CPU_FIRST_SECTION ".first" #else #define PER_CPU_SHARED_ALIGNED_SECTION "" +#define PER_CPU_ALIGNED_SECTION ".shared_aligned" #define PER_CPU_FIRST_SECTION "" #endif diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h index 68438e1..3058cf9 100644 --- a/include/linux/percpu-defs.h +++ b/include/linux/percpu-defs.h @@ -66,6 +66,14 @@ DEFINE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) \ ____cacheline_aligned_in_smp +#define DECLARE_PER_CPU_ALIGNED(type, name) \ + DECLARE_PER_CPU_SECTION(type, name, PER_CPU_ALIGNED_SECTION) \ + ____cacheline_aligned + +#define DEFINE_PER_CPU_ALIGNED(type, name) \ + DEFINE_PER_CPU_SECTION(type, name, PER_CPU_ALIGNED_SECTION) \ + ____cacheline_aligned + /* * Declaration/definition used for per-CPU variables that must be page aligned. */ -- cgit v0.10.2 From b5d10781731ece07bb2049e7743907194a5cc3f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 4 Sep 2009 08:45:11 +0200 Subject: ALSA: dummy - Fix the timer calculation in systimer mode Fix the expire-time calculation in the systimer mode when the buffer size isn't aligned to the period size. Signed-off-by: Takashi Iwai diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 0a798bd..e8e29bf 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -207,19 +207,18 @@ struct dummy_systimer_pcm { struct timer_list timer; unsigned long base_time; unsigned int frac_pos; /* fractional sample position (based HZ) */ + unsigned int frac_period_rest; unsigned int frac_buffer_size; /* buffer_size * HZ */ unsigned int frac_period_size; /* period_size * HZ */ unsigned int rate; + int elapsed; struct snd_pcm_substream *substream; }; static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm) { - unsigned long frac; - - frac = dpcm->frac_pos % dpcm->frac_period_size; dpcm->timer.expires = jiffies + - (dpcm->frac_period_size + dpcm->rate - 1) / dpcm->rate; + (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate; add_timer(&dpcm->timer); } @@ -230,10 +229,16 @@ static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm) delta = jiffies - dpcm->base_time; if (!delta) return; - dpcm->base_time = jiffies; - dpcm->frac_pos += delta * dpcm->rate; + dpcm->base_time += delta; + delta *= dpcm->rate; + dpcm->frac_pos += delta; while (dpcm->frac_pos >= dpcm->frac_buffer_size) dpcm->frac_pos -= dpcm->frac_buffer_size; + while (dpcm->frac_period_rest <= delta) { + dpcm->elapsed++; + dpcm->frac_period_rest += dpcm->frac_period_size; + } + dpcm->frac_period_rest -= delta; } static int dummy_systimer_start(struct snd_pcm_substream *substream) @@ -264,6 +269,8 @@ static int dummy_systimer_prepare(struct snd_pcm_substream *substream) dpcm->rate = runtime->rate; dpcm->frac_buffer_size = runtime->buffer_size * HZ; dpcm->frac_period_size = runtime->period_size * HZ; + dpcm->frac_period_rest = dpcm->frac_period_size; + dpcm->elapsed = 0; return 0; } @@ -272,23 +279,29 @@ static void dummy_systimer_callback(unsigned long data) { struct dummy_systimer_pcm *dpcm = (struct dummy_systimer_pcm *)data; unsigned long flags; + int elapsed = 0; spin_lock_irqsave(&dpcm->lock, flags); dummy_systimer_update(dpcm); dummy_systimer_rearm(dpcm); + elapsed = dpcm->elapsed; + dpcm->elapsed = 0; spin_unlock_irqrestore(&dpcm->lock, flags); - snd_pcm_period_elapsed(dpcm->substream); + if (elapsed) + snd_pcm_period_elapsed(dpcm->substream); } static snd_pcm_uframes_t dummy_systimer_pointer(struct snd_pcm_substream *substream) { struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; + snd_pcm_uframes_t pos; spin_lock(&dpcm->lock); dummy_systimer_update(dpcm); + pos = dpcm->frac_pos / HZ; spin_unlock(&dpcm->lock); - return dpcm->frac_pos / HZ; + return pos; } static int dummy_systimer_create(struct snd_pcm_substream *substream) -- cgit v0.10.2 From 747b50aaf728987732e6ff3ba10aba4acc4e0277 Mon Sep 17 00:00:00 2001 From: "markus.t.metzger@intel.com" Date: Wed, 2 Sep 2009 16:04:46 +0200 Subject: x86, perf_counter, bts: Fail if BTS is not available Reserve PERF_COUNT_HW_BRANCH_INSTRUCTIONS with sample_period == 1 for BTS tracing and fail, if BTS is not available. Signed-off-by: Markus Metzger Acked-by: Peter Zijlstra LKML-Reference: <20090902140612.943801000@intel.com> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c index 396e35d..2f41874 100644 --- a/arch/x86/kernel/cpu/perf_counter.c +++ b/arch/x86/kernel/cpu/perf_counter.c @@ -769,7 +769,7 @@ static int reserve_bts_hardware(void) int cpu, err = 0; if (!bts_available()) - return -EOPNOTSUPP; + return 0; get_online_cpus(); @@ -914,7 +914,7 @@ static int __hw_perf_counter_init(struct perf_counter *counter) if (!reserve_pmc_hardware()) err = -EBUSY; else - reserve_bts_hardware(); + err = reserve_bts_hardware(); } if (!err) atomic_inc(&active_counters); @@ -979,6 +979,13 @@ static int __hw_perf_counter_init(struct perf_counter *counter) if (config == -1LL) return -EINVAL; + /* + * Branch tracing: + */ + if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) && + (hwc->sample_period == 1) && !bts_available()) + return -EOPNOTSUPP; + hwc->config |= config; return 0; @@ -1355,19 +1362,9 @@ static int x86_pmu_enable(struct perf_counter *counter) idx = fixed_mode_idx(counter, hwc); if (idx == X86_PMC_IDX_FIXED_BTS) { - /* - * Try to use BTS for branch tracing. If that is not - * available, try to get a generic counter. - */ - if (unlikely(!cpuc->ds)) - goto try_generic; - - /* - * Try to get the fixed counter, if that is already taken - * then try to get a generic counter: - */ + /* BTS is already occupied. */ if (test_and_set_bit(idx, cpuc->used_mask)) - goto try_generic; + return -EAGAIN; hwc->config_base = 0; hwc->counter_base = 0; -- cgit v0.10.2 From 596da17f94c103348ebe04129c00d536ea0e80e2 Mon Sep 17 00:00:00 2001 From: "markus.t.metzger@intel.com" Date: Wed, 2 Sep 2009 16:04:47 +0200 Subject: x86, perf_counter, bts: Correct pointer-to-u64 casts On 32bit, pointers in the DS AREA configuration are cast to u64. The current (long) cast to avoid compiler warnings results in a signed 64bit address. Signed-off-by: Markus Metzger Acked-by: Peter Zijlstra LKML-Reference: <20090902140615.305889000@intel.com> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c index 2f41874..3776b0b 100644 --- a/arch/x86/kernel/cpu/perf_counter.c +++ b/arch/x86/kernel/cpu/perf_counter.c @@ -726,7 +726,8 @@ static inline void init_debug_store_on_cpu(int cpu) return; wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, - (u32)((u64)(long)ds), (u32)((u64)(long)ds >> 32)); + (u32)((u64)(unsigned long)ds), + (u32)((u64)(unsigned long)ds >> 32)); } static inline void fini_debug_store_on_cpu(int cpu) @@ -757,7 +758,7 @@ static void release_bts_hardware(void) per_cpu(cpu_hw_counters, cpu).ds = NULL; - kfree((void *)(long)ds->bts_buffer_base); + kfree((void *)(unsigned long)ds->bts_buffer_base); kfree(ds); } @@ -788,7 +789,7 @@ static int reserve_bts_hardware(void) break; } - ds->bts_buffer_base = (u64)(long)buffer; + ds->bts_buffer_base = (u64)(unsigned long)buffer; ds->bts_index = ds->bts_buffer_base; ds->bts_absolute_maximum = ds->bts_buffer_base + BTS_BUFFER_SIZE; @@ -1491,7 +1492,7 @@ static void intel_pmu_drain_bts_buffer(struct cpu_hw_counters *cpuc, }; struct perf_counter *counter = cpuc->counters[X86_PMC_IDX_FIXED_BTS]; unsigned long orig_ip = data->regs->ip; - u64 at; + struct bts_record *at, *top; if (!counter) return; @@ -1499,19 +1500,18 @@ static void intel_pmu_drain_bts_buffer(struct cpu_hw_counters *cpuc, if (!ds) return; - for (at = ds->bts_buffer_base; - at < ds->bts_index; - at += sizeof(struct bts_record)) { - struct bts_record *rec = (struct bts_record *)(long)at; + at = (struct bts_record *)(unsigned long)ds->bts_buffer_base; + top = (struct bts_record *)(unsigned long)ds->bts_index; - data->regs->ip = rec->from; - data->addr = rec->to; + ds->bts_index = ds->bts_buffer_base; + + for (; at < top; at++) { + data->regs->ip = at->from; + data->addr = at->to; perf_counter_output(counter, 1, data); } - ds->bts_index = ds->bts_buffer_base; - data->regs->ip = orig_ip; data->addr = 0; -- cgit v0.10.2 From 1653192f510bd8114b7b133d7289e6e5c3e95046 Mon Sep 17 00:00:00 2001 From: "markus.t.metzger@intel.com" Date: Wed, 2 Sep 2009 16:04:48 +0200 Subject: x86, perf_counter, bts: Do not allow kernel BTS tracing for now Kernel BTS tracing generates too much data too fast for us to handle, causing the kernel to hang. Fail for BTS requests for kernel code. Signed-off-by: Markus Metzger Acked-by: Peter Zijlstra LKML-Reference: <20090902140616.901253000@intel.com> [ This is really a workaround - but we want BTS tracing in .32 so make sure we dont regress. The lockup should be fixed ASAP. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c index 3776b0b..f9cd084 100644 --- a/arch/x86/kernel/cpu/perf_counter.c +++ b/arch/x86/kernel/cpu/perf_counter.c @@ -984,8 +984,15 @@ static int __hw_perf_counter_init(struct perf_counter *counter) * Branch tracing: */ if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) && - (hwc->sample_period == 1) && !bts_available()) - return -EOPNOTSUPP; + (hwc->sample_period == 1)) { + /* BTS is not supported by this architecture. */ + if (!bts_available()) + return -EOPNOTSUPP; + + /* BTS is currently only allowed for user-mode. */ + if (hwc->config & ARCH_PERFMON_EVENTSEL_OS) + return -EOPNOTSUPP; + } hwc->config |= config; -- cgit v0.10.2 From 7db905e636f08ea5bc9825c1f73d77802e8ccad5 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 2 Sep 2009 14:01:24 -0700 Subject: rcu: Move end of special early-boot RCU operation earlier Ingo was getting warnings from rcu_scheduler_starting() indicating that context switches had occurred before RCU ended its special early-boot handling of grace periods. This is a dangerous condition, as it indicates that RCU might have prematurely ended grace periods. This exploratory fix moves rcu_scheduler_starting() earlier in boot. Reported-by: Ingo Molnar Signed-off-by: Paul E. McKenney Signed-off-by: Ingo Molnar diff --git a/init/main.c b/init/main.c index 11f4f14..525f6fb 100644 --- a/init/main.c +++ b/init/main.c @@ -451,6 +451,7 @@ static noinline void __init_refok rest_init(void) { int pid; + rcu_scheduler_starting(); kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); numa_default_policy(); pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); @@ -462,7 +463,6 @@ static noinline void __init_refok rest_init(void) * at least once to get things moving: */ init_idle_bootup_task(current); - rcu_scheduler_starting(); preempt_enable_no_resched(); schedule(); preempt_disable(); -- cgit v0.10.2 From 0d96b9ff748b5f57d6f1d6d21209f5745245aadc Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sat, 29 Aug 2009 13:17:14 -0700 Subject: x86: Use hard_smp_processor_id() to get apic id for AMD K8 cpus Otherwise, system with apci id lifting will have wrong apicid in /proc/cpuinfo. and use that in srat_detect_node(). Signed-off-by: Yinghai Lu Cc: Andreas Herrmann Cc: Suresh Siddha Cc: Cyrill Gorcunov LKML-Reference: <4A998CCA.1040407@kernel.org> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index a76d2c1..e1600c7 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -336,7 +336,7 @@ static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c) #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64) int cpu = smp_processor_id(); int node; - unsigned apicid = cpu_has_apic ? hard_smp_processor_id() : c->apicid; + unsigned apicid = c->apicid; node = per_cpu(cpu_llc_id, cpu); @@ -481,6 +481,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) } if (c->x86 == 0x10 || c->x86 == 0x11) set_cpu_cap(c, X86_FEATURE_REP_GOOD); + + /* get apicid instead of initial apic id from cpuid */ + c->apicid = hard_smp_processor_id(); #else /* -- cgit v0.10.2 From f93e65c186ab3c05ce2068733ca10e34fd00125e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 1 Sep 2009 10:34:32 +0200 Subject: sched: Restore __cpu_power to a straight sum of power cpu_power is supposed to be a representation of the process capacity of the cpu, not a value to randomly tweak in order to affect placement. Remove the placement hacks. Signed-off-by: Peter Zijlstra Tested-by: Andreas Herrmann Acked-by: Andreas Herrmann Acked-by: Gautham R Shenoy Cc: Balbir Singh LKML-Reference: <20090901083825.810860576@chello.nl> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index da1edc8..584a122 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8464,15 +8464,13 @@ static void free_sched_groups(const struct cpumask *cpu_map, * there are asymmetries in the topology. If there are asymmetries, group * having more cpu_power will pickup more load compared to the group having * less cpu_power. - * - * cpu_power will be a multiple of SCHED_LOAD_SCALE. This multiple represents - * the maximum number of tasks a group can handle in the presence of other idle - * or lightly loaded groups in the same sched domain. */ static void init_sched_groups_power(int cpu, struct sched_domain *sd) { struct sched_domain *child; struct sched_group *group; + long power; + int weight; WARN_ON(!sd || !sd->groups); @@ -8483,22 +8481,20 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) sd->groups->__cpu_power = 0; - /* - * For perf policy, if the groups in child domain share resources - * (for example cores sharing some portions of the cache hierarchy - * or SMT), then set this domain groups cpu_power such that each group - * can handle only one task, when there are other idle groups in the - * same sched domain. - */ - if (!child || (!(sd->flags & SD_POWERSAVINGS_BALANCE) && - (child->flags & - (SD_SHARE_CPUPOWER | SD_SHARE_PKG_RESOURCES)))) { - sg_inc_cpu_power(sd->groups, SCHED_LOAD_SCALE); + if (!child) { + power = SCHED_LOAD_SCALE; + weight = cpumask_weight(sched_domain_span(sd)); + /* + * SMT siblings share the power of a single core. + */ + if ((sd->flags & SD_SHARE_CPUPOWER) && weight > 1) + power /= weight; + sg_inc_cpu_power(sd->groups, power); return; } /* - * add cpu_power of each child group to this groups cpu_power + * Add cpu_power of each child group to this groups cpu_power. */ group = child->groups; do { -- cgit v0.10.2 From b5d978e0c7e79a7ff842e895c85a86b38c71f1cd Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 1 Sep 2009 10:34:33 +0200 Subject: sched: Add SD_PREFER_SIBLING Do the placement thing using SD flags. Signed-off-by: Peter Zijlstra Tested-by: Andreas Herrmann Acked-by: Andreas Herrmann Acked-by: Gautham R Shenoy Cc: Balbir Singh LKML-Reference: <20090901083825.897028974@chello.nl> Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 9c96ef2..651dded 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -798,18 +798,19 @@ enum cpu_idle_type { #define SCHED_LOAD_SCALE_FUZZ SCHED_LOAD_SCALE #ifdef CONFIG_SMP -#define SD_LOAD_BALANCE 1 /* Do load balancing on this domain. */ -#define SD_BALANCE_NEWIDLE 2 /* Balance when about to become idle */ -#define SD_BALANCE_EXEC 4 /* Balance on exec */ -#define SD_BALANCE_FORK 8 /* Balance on fork, clone */ -#define SD_WAKE_IDLE 16 /* Wake to idle CPU on task wakeup */ -#define SD_WAKE_AFFINE 32 /* Wake task to waking CPU */ -#define SD_WAKE_BALANCE 64 /* Perform balancing at task wakeup */ -#define SD_SHARE_CPUPOWER 128 /* Domain members share cpu power */ -#define SD_POWERSAVINGS_BALANCE 256 /* Balance for power savings */ -#define SD_SHARE_PKG_RESOURCES 512 /* Domain members share cpu pkg resources */ -#define SD_SERIALIZE 1024 /* Only a single load balancing instance */ -#define SD_WAKE_IDLE_FAR 2048 /* Gain latency sacrificing cache hit */ +#define SD_LOAD_BALANCE 0x0001 /* Do load balancing on this domain. */ +#define SD_BALANCE_NEWIDLE 0x0002 /* Balance when about to become idle */ +#define SD_BALANCE_EXEC 0x0004 /* Balance on exec */ +#define SD_BALANCE_FORK 0x0008 /* Balance on fork, clone */ +#define SD_WAKE_IDLE 0x0010 /* Wake to idle CPU on task wakeup */ +#define SD_WAKE_AFFINE 0x0020 /* Wake task to waking CPU */ +#define SD_WAKE_BALANCE 0x0040 /* Perform balancing at task wakeup */ +#define SD_SHARE_CPUPOWER 0x0080 /* Domain members share cpu power */ +#define SD_POWERSAVINGS_BALANCE 0x0100 /* Balance for power savings */ +#define SD_SHARE_PKG_RESOURCES 0x0200 /* Domain members share cpu pkg resources */ +#define SD_SERIALIZE 0x0400 /* Only a single load balancing instance */ +#define SD_WAKE_IDLE_FAR 0x0800 /* Gain latency sacrificing cache hit */ +#define SD_PREFER_SIBLING 0x1000 /* Prefer to place tasks in a sibling domain */ enum powersavings_balance_level { POWERSAVINGS_BALANCE_NONE = 0, /* No power saving load balance */ @@ -829,7 +830,7 @@ static inline int sd_balance_for_mc_power(void) if (sched_smt_power_savings) return SD_POWERSAVINGS_BALANCE; - return 0; + return SD_PREFER_SIBLING; } static inline int sd_balance_for_package_power(void) @@ -837,7 +838,7 @@ static inline int sd_balance_for_package_power(void) if (sched_mc_power_savings | sched_smt_power_savings) return SD_POWERSAVINGS_BALANCE; - return 0; + return SD_PREFER_SIBLING; } /* diff --git a/kernel/sched.c b/kernel/sched.c index 584a122..9d64cec 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3811,9 +3811,13 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, const struct cpumask *cpus, int *balance, struct sd_lb_stats *sds) { + struct sched_domain *child = sd->child; struct sched_group *group = sd->groups; struct sg_lb_stats sgs; - int load_idx; + int load_idx, prefer_sibling = 0; + + if (child && child->flags & SD_PREFER_SIBLING) + prefer_sibling = 1; init_sd_power_savings_stats(sd, sds, idle); load_idx = get_sd_load_idx(sd, idle); @@ -3833,6 +3837,14 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, sds->total_load += sgs.group_load; sds->total_pwr += group->__cpu_power; + /* + * In case the child domain prefers tasks go to siblings + * first, lower the group capacity to one so that we'll try + * and move all the excess tasks away. + */ + if (prefer_sibling) + sgs.group_capacity = 1; + if (local_group) { sds->this_load = sgs.avg_load; sds->this = group; -- cgit v0.10.2 From cc9fba7d7672fa3ed58d9d9ecb6c45b1351c29a6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 1 Sep 2009 10:34:34 +0200 Subject: sched: Update the cpu_power sum during load-balance In order to prepare for a more dynamic cpu_power, update the group sum while walking the sched domains during load-balance. Signed-off-by: Peter Zijlstra Tested-by: Andreas Herrmann Acked-by: Andreas Herrmann Acked-by: Gautham R Shenoy Cc: Balbir Singh LKML-Reference: <20090901083825.985050292@chello.nl> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 9d64cec..ecb4a47 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3699,6 +3699,28 @@ static inline int check_power_save_busiest_group(struct sd_lb_stats *sds, } #endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ +static void update_sched_power(struct sched_domain *sd) +{ + struct sched_domain *child = sd->child; + struct sched_group *group, *sdg = sd->groups; + unsigned long power = sdg->__cpu_power; + + if (!child) { + /* compute cpu power for this cpu */ + return; + } + + sdg->__cpu_power = 0; + + group = child->groups; + do { + sdg->__cpu_power += group->__cpu_power; + group = group->next; + } while (group != child->groups); + + if (power != sdg->__cpu_power) + sdg->reciprocal_cpu_power = reciprocal_value(sdg->__cpu_power); +} /** * update_sg_lb_stats - Update sched_group's statistics for load balancing. @@ -3712,7 +3734,8 @@ static inline int check_power_save_busiest_group(struct sd_lb_stats *sds, * @balance: Should we balance. * @sgs: variable to hold the statistics for this group. */ -static inline void update_sg_lb_stats(struct sched_group *group, int this_cpu, +static inline void update_sg_lb_stats(struct sched_domain *sd, + struct sched_group *group, int this_cpu, enum cpu_idle_type idle, int load_idx, int *sd_idle, int local_group, const struct cpumask *cpus, int *balance, struct sg_lb_stats *sgs) @@ -3723,8 +3746,11 @@ static inline void update_sg_lb_stats(struct sched_group *group, int this_cpu, unsigned long sum_avg_load_per_task; unsigned long avg_load_per_task; - if (local_group) + if (local_group) { balance_cpu = group_first_cpu(group); + if (balance_cpu == this_cpu) + update_sched_power(sd); + } /* Tally up the load of all CPUs in the group */ sum_avg_load_per_task = avg_load_per_task = 0; @@ -3828,7 +3854,7 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, local_group = cpumask_test_cpu(this_cpu, sched_group_cpus(group)); memset(&sgs, 0, sizeof(sgs)); - update_sg_lb_stats(group, this_cpu, idle, load_idx, sd_idle, + update_sg_lb_stats(sd, group, this_cpu, idle, load_idx, sd_idle, local_group, cpus, balance, &sgs); if (local_group && balance && !(*balance)) @@ -3863,7 +3889,6 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, update_sd_power_savings_stats(group, sds, local_group, &sgs); group = group->next; } while (group != sd->groups); - } /** -- cgit v0.10.2 From a52bfd73589eaf88d9c95ad2c1de0b38a6b27972 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 1 Sep 2009 10:34:35 +0200 Subject: sched: Add smt_gain The idea is that multi-threading a core yields more work capacity than a single thread, provide a way to express a static gain for threads. Signed-off-by: Peter Zijlstra Tested-by: Andreas Herrmann Acked-by: Andreas Herrmann Acked-by: Gautham R Shenoy Cc: Balbir Singh LKML-Reference: <20090901083826.073345955@chello.nl> Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 651dded..9c81c92 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -921,6 +921,7 @@ struct sched_domain { unsigned int newidle_idx; unsigned int wake_idx; unsigned int forkexec_idx; + unsigned int smt_gain; int flags; /* See SD_* */ enum sched_domain_level level; diff --git a/include/linux/topology.h b/include/linux/topology.h index 7402c1a..6203ae5 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -99,6 +99,7 @@ int arch_update_cpu_topology(void); | SD_SHARE_CPUPOWER, \ .last_balance = jiffies, \ .balance_interval = 1, \ + .smt_gain = 1178, /* 15% */ \ } #endif #endif /* CONFIG_SCHED_SMT */ diff --git a/kernel/sched.c b/kernel/sched.c index ecb4a47..5511226 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8523,9 +8523,15 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) weight = cpumask_weight(sched_domain_span(sd)); /* * SMT siblings share the power of a single core. + * Usually multiple threads get a better yield out of + * that one core than a single thread would have, + * reflect that in sd->smt_gain. */ - if ((sd->flags & SD_SHARE_CPUPOWER) && weight > 1) + if ((sd->flags & SD_SHARE_CPUPOWER) && weight > 1) { + power *= sd->smt_gain; power /= weight; + power >>= SCHED_LOAD_SHIFT; + } sg_inc_cpu_power(sd->groups, power); return; } -- cgit v0.10.2 From ab29230e673c646292c90c8b9d378b9562145af0 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 1 Sep 2009 10:34:36 +0200 Subject: sched: Implement dynamic cpu_power Recompute the cpu_power for each cpu during load-balance. Signed-off-by: Peter Zijlstra Tested-by: Andreas Herrmann Acked-by: Andreas Herrmann Acked-by: Gautham R Shenoy Cc: Balbir Singh LKML-Reference: <20090901083826.162033479@chello.nl> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 5511226..036600f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3699,14 +3699,46 @@ static inline int check_power_save_busiest_group(struct sd_lb_stats *sds, } #endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ -static void update_sched_power(struct sched_domain *sd) +unsigned long __weak arch_smt_gain(struct sched_domain *sd, int cpu) +{ + unsigned long weight = cpumask_weight(sched_domain_span(sd)); + unsigned long smt_gain = sd->smt_gain; + + smt_gain /= weight; + + return smt_gain; +} + +static void update_cpu_power(struct sched_domain *sd, int cpu) +{ + unsigned long weight = cpumask_weight(sched_domain_span(sd)); + unsigned long power = SCHED_LOAD_SCALE; + struct sched_group *sdg = sd->groups; + unsigned long old = sdg->__cpu_power; + + /* here we could scale based on cpufreq */ + + if ((sd->flags & SD_SHARE_CPUPOWER) && weight > 1) { + power *= arch_smt_gain(sd, cpu); + power >>= SCHED_LOAD_SHIFT; + } + + /* here we could scale based on RT time */ + + if (power != old) { + sdg->__cpu_power = power; + sdg->reciprocal_cpu_power = reciprocal_value(power); + } +} + +static void update_group_power(struct sched_domain *sd, int cpu) { struct sched_domain *child = sd->child; struct sched_group *group, *sdg = sd->groups; unsigned long power = sdg->__cpu_power; if (!child) { - /* compute cpu power for this cpu */ + update_cpu_power(sd, cpu); return; } @@ -3749,7 +3781,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd, if (local_group) { balance_cpu = group_first_cpu(group); if (balance_cpu == this_cpu) - update_sched_power(sd); + update_group_power(sd, this_cpu); } /* Tally up the load of all CPUs in the group */ -- cgit v0.10.2 From e9e9250bc78e7f6342517214c0178a529807964b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 1 Sep 2009 10:34:37 +0200 Subject: sched: Scale down cpu_power due to RT tasks Keep an average on the amount of time spend on RT tasks and use that fraction to scale down the cpu_power for regular tasks. Signed-off-by: Peter Zijlstra Tested-by: Andreas Herrmann Acked-by: Andreas Herrmann Acked-by: Gautham R Shenoy Cc: Balbir Singh LKML-Reference: <20090901083826.287778431@chello.nl> Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 9c81c92..c67ddf3 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1831,6 +1831,7 @@ extern unsigned int sysctl_sched_child_runs_first; extern unsigned int sysctl_sched_features; extern unsigned int sysctl_sched_migration_cost; extern unsigned int sysctl_sched_nr_migrate; +extern unsigned int sysctl_sched_time_avg; extern unsigned int sysctl_timer_migration; int sched_nr_latency_handler(struct ctl_table *table, int write, diff --git a/kernel/sched.c b/kernel/sched.c index 036600f..ab532b5 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -627,6 +627,9 @@ struct rq { struct task_struct *migration_thread; struct list_head migration_queue; + + u64 rt_avg; + u64 age_stamp; #endif /* calc_load related fields */ @@ -863,6 +866,14 @@ unsigned int sysctl_sched_shares_ratelimit = 250000; unsigned int sysctl_sched_shares_thresh = 4; /* + * period over which we average the RT time consumption, measured + * in ms. + * + * default: 1s + */ +const_debug unsigned int sysctl_sched_time_avg = MSEC_PER_SEC; + +/* * period over which we measure -rt task cpu usage in us. * default: 1s */ @@ -1280,12 +1291,37 @@ void wake_up_idle_cpu(int cpu) } #endif /* CONFIG_NO_HZ */ +static u64 sched_avg_period(void) +{ + return (u64)sysctl_sched_time_avg * NSEC_PER_MSEC / 2; +} + +static void sched_avg_update(struct rq *rq) +{ + s64 period = sched_avg_period(); + + while ((s64)(rq->clock - rq->age_stamp) > period) { + rq->age_stamp += period; + rq->rt_avg /= 2; + } +} + +static void sched_rt_avg_update(struct rq *rq, u64 rt_delta) +{ + rq->rt_avg += rt_delta; + sched_avg_update(rq); +} + #else /* !CONFIG_SMP */ static void resched_task(struct task_struct *p) { assert_spin_locked(&task_rq(p)->lock); set_tsk_need_resched(p); } + +static void sched_rt_avg_update(struct rq *rq, u64 rt_delta) +{ +} #endif /* CONFIG_SMP */ #if BITS_PER_LONG == 32 @@ -3699,7 +3735,7 @@ static inline int check_power_save_busiest_group(struct sd_lb_stats *sds, } #endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ -unsigned long __weak arch_smt_gain(struct sched_domain *sd, int cpu) +unsigned long __weak arch_scale_smt_power(struct sched_domain *sd, int cpu) { unsigned long weight = cpumask_weight(sched_domain_span(sd)); unsigned long smt_gain = sd->smt_gain; @@ -3709,6 +3745,24 @@ unsigned long __weak arch_smt_gain(struct sched_domain *sd, int cpu) return smt_gain; } +unsigned long scale_rt_power(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + u64 total, available; + + sched_avg_update(rq); + + total = sched_avg_period() + (rq->clock - rq->age_stamp); + available = total - rq->rt_avg; + + if (unlikely((s64)total < SCHED_LOAD_SCALE)) + total = SCHED_LOAD_SCALE; + + total >>= SCHED_LOAD_SHIFT; + + return div_u64(available, total); +} + static void update_cpu_power(struct sched_domain *sd, int cpu) { unsigned long weight = cpumask_weight(sched_domain_span(sd)); @@ -3719,11 +3773,15 @@ static void update_cpu_power(struct sched_domain *sd, int cpu) /* here we could scale based on cpufreq */ if ((sd->flags & SD_SHARE_CPUPOWER) && weight > 1) { - power *= arch_smt_gain(sd, cpu); + power *= arch_scale_smt_power(sd, cpu); power >>= SCHED_LOAD_SHIFT; } - /* here we could scale based on RT time */ + power *= scale_rt_power(cpu); + power >>= SCHED_LOAD_SHIFT; + + if (!power) + power = 1; if (power != old) { sdg->__cpu_power = power; diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index 3d4020a..2eb4bd6 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -615,6 +615,8 @@ static void update_curr_rt(struct rq *rq) curr->se.exec_start = rq->clock; cpuacct_charge(curr, delta_exec); + sched_rt_avg_update(rq, delta_exec); + if (!rt_bandwidth_enabled()) return; @@ -887,8 +889,6 @@ static void enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup) if (!task_current(rq, p) && p->rt.nr_cpus_allowed > 1) enqueue_pushable_task(rq, p); - - inc_cpu_load(rq, p->se.load.weight); } static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int sleep) @@ -899,8 +899,6 @@ static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int sleep) dequeue_rt_entity(rt_se); dequeue_pushable_task(rq, p); - - dec_cpu_load(rq, p->se.load.weight); } /* diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 58be760..6c9836e 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -332,6 +332,14 @@ static struct ctl_table kern_table[] = { }, { .ctl_name = CTL_UNNUMBERED, + .procname = "sched_time_avg", + .data = &sysctl_sched_time_avg, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, .procname = "timer_migration", .data = &sysctl_timer_migration, .maxlen = sizeof(unsigned int), -- cgit v0.10.2 From bdb94aa5dbd8b55e75f5a50b61312fe589e2c2d1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 1 Sep 2009 10:34:38 +0200 Subject: sched: Try to deal with low capacity When the capacity drops low, we want to migrate load away. Allow the load-balancer to remove all tasks when we hit rock bottom. Signed-off-by: Peter Zijlstra Tested-by: Andreas Herrmann Acked-by: Andreas Herrmann Acked-by: Gautham R Shenoy Cc: Balbir Singh LKML-Reference: <20090901083826.342231003@chello.nl> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index ab532b5..5f5b359 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3908,8 +3908,8 @@ static inline void update_sg_lb_stats(struct sched_domain *sd, if ((max_cpu_load - min_cpu_load) > 2*avg_load_per_task) sgs->group_imb = 1; - sgs->group_capacity = group->__cpu_power / SCHED_LOAD_SCALE; - + sgs->group_capacity = + DIV_ROUND_CLOSEST(group->__cpu_power, SCHED_LOAD_SCALE); } /** @@ -3959,7 +3959,7 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, * and move all the excess tasks away. */ if (prefer_sibling) - sgs.group_capacity = 1; + sgs.group_capacity = min(sgs.group_capacity, 1UL); if (local_group) { sds->this_load = sgs.avg_load; @@ -4191,6 +4191,26 @@ ret: return NULL; } +static struct sched_group *group_of(int cpu) +{ + struct sched_domain *sd = rcu_dereference(cpu_rq(cpu)->sd); + + if (!sd) + return NULL; + + return sd->groups; +} + +static unsigned long power_of(int cpu) +{ + struct sched_group *group = group_of(cpu); + + if (!group) + return SCHED_LOAD_SCALE; + + return group->__cpu_power; +} + /* * find_busiest_queue - find the busiest runqueue among the cpus in group. */ @@ -4203,15 +4223,18 @@ find_busiest_queue(struct sched_group *group, enum cpu_idle_type idle, int i; for_each_cpu(i, sched_group_cpus(group)) { + unsigned long power = power_of(i); + unsigned long capacity = DIV_ROUND_CLOSEST(power, SCHED_LOAD_SCALE); unsigned long wl; if (!cpumask_test_cpu(i, cpus)) continue; rq = cpu_rq(i); - wl = weighted_cpuload(i); + wl = weighted_cpuload(i) * SCHED_LOAD_SCALE; + wl /= power; - if (rq->nr_running == 1 && wl > imbalance) + if (capacity && rq->nr_running == 1 && wl > imbalance) continue; if (wl > max_load) { -- cgit v0.10.2 From d899a789c28ded9c72b57ddb61868d6b8fc23e80 Mon Sep 17 00:00:00 2001 From: Gautham R Shenoy Date: Wed, 2 Sep 2009 16:59:10 +0530 Subject: sched: Try to deal with low capacity, fix update_sd_power_savings_stats() sgs.group_capacity can now be 0, if for some reason group->__cpu_power happens to be less than SCHED_LOAD_SCALE/2. In that case, we need the following fix to make it work for update_sd_power_savings_stats(). That's because both sum_nr_running and group_capacity are unsigned longs. Cc: Gautham R Shenoy Cc: Peter Zijlstra Cc: Andreas Herrmann Cc: Balbir Singh Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 5f5b359..e1ebf9b 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3668,7 +3668,7 @@ static inline void update_sd_power_savings_stats(struct sched_group *group, * capacity but still has some space to pick up some load * from other group and save more power */ - if (sgs->sum_nr_running > sgs->group_capacity - 1) + if (sgs->sum_nr_running + 1 > sgs->group_capacity) return; if (sgs->sum_nr_running > sds->leader_nr_running || -- cgit v0.10.2 From 18a3885fc1ffa92c2212ff0afdf033403d5b0fa0 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 1 Sep 2009 10:34:39 +0200 Subject: sched: Remove reciprocal for cpu_power Its a source of fail, also, now that cpu_power is dynamical, its a waste of time. before: -0 [000] 132.877936: find_busiest_group: avg_load: 0 group_load: 8241 power: 1 after: bash-1689 [001] 137.862151: find_busiest_group: avg_load: 10636288 group_load: 10387 power: 1 [ v2: build fix from From: Andreas Herrmann ] Signed-off-by: Peter Zijlstra Tested-by: Andreas Herrmann Acked-by: Andreas Herrmann Acked-by: Gautham R Shenoy Cc: Balbir Singh LKML-Reference: <20090901083826.425896304@chello.nl> Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index c67ddf3..3b7f43e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -860,15 +860,9 @@ struct sched_group { /* * CPU power of this group, SCHED_LOAD_SCALE being max power for a - * single CPU. This is read only (except for setup, hotplug CPU). - * Note : Never change cpu_power without recompute its reciprocal + * single CPU. */ - unsigned int __cpu_power; - /* - * reciprocal value of cpu_power to avoid expensive divides - * (see include/linux/reciprocal_div.h) - */ - u32 reciprocal_cpu_power; + unsigned int cpu_power; /* * The CPUs this group covers. diff --git a/kernel/sched.c b/kernel/sched.c index e1ebf9b..b537853 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -64,7 +64,6 @@ #include #include #include -#include #include #include #include @@ -120,30 +119,8 @@ */ #define RUNTIME_INF ((u64)~0ULL) -#ifdef CONFIG_SMP - static void double_rq_lock(struct rq *rq1, struct rq *rq2); -/* - * Divide a load by a sched group cpu_power : (load / sg->__cpu_power) - * Since cpu_power is a 'constant', we can use a reciprocal divide. - */ -static inline u32 sg_div_cpu_power(const struct sched_group *sg, u32 load) -{ - return reciprocal_divide(load, sg->reciprocal_cpu_power); -} - -/* - * Each time a sched group cpu_power is changed, - * we must compute its reciprocal value - */ -static inline void sg_inc_cpu_power(struct sched_group *sg, u32 val) -{ - sg->__cpu_power += val; - sg->reciprocal_cpu_power = reciprocal_value(sg->__cpu_power); -} -#endif - static inline int rt_policy(int policy) { if (unlikely(policy == SCHED_FIFO || policy == SCHED_RR)) @@ -2335,8 +2312,7 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu) } /* Adjust by relative CPU power of the group */ - avg_load = sg_div_cpu_power(group, - avg_load * SCHED_LOAD_SCALE); + avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power; if (local_group) { this_load = avg_load; @@ -3768,7 +3744,6 @@ static void update_cpu_power(struct sched_domain *sd, int cpu) unsigned long weight = cpumask_weight(sched_domain_span(sd)); unsigned long power = SCHED_LOAD_SCALE; struct sched_group *sdg = sd->groups; - unsigned long old = sdg->__cpu_power; /* here we could scale based on cpufreq */ @@ -3783,33 +3758,26 @@ static void update_cpu_power(struct sched_domain *sd, int cpu) if (!power) power = 1; - if (power != old) { - sdg->__cpu_power = power; - sdg->reciprocal_cpu_power = reciprocal_value(power); - } + sdg->cpu_power = power; } static void update_group_power(struct sched_domain *sd, int cpu) { struct sched_domain *child = sd->child; struct sched_group *group, *sdg = sd->groups; - unsigned long power = sdg->__cpu_power; if (!child) { update_cpu_power(sd, cpu); return; } - sdg->__cpu_power = 0; + sdg->cpu_power = 0; group = child->groups; do { - sdg->__cpu_power += group->__cpu_power; + sdg->cpu_power += group->cpu_power; group = group->next; } while (group != child->groups); - - if (power != sdg->__cpu_power) - sdg->reciprocal_cpu_power = reciprocal_value(sdg->__cpu_power); } /** @@ -3889,8 +3857,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd, } /* Adjust by relative CPU power of the group */ - sgs->avg_load = sg_div_cpu_power(group, - sgs->group_load * SCHED_LOAD_SCALE); + sgs->avg_load = (sgs->group_load * SCHED_LOAD_SCALE) / group->cpu_power; /* @@ -3902,14 +3869,14 @@ static inline void update_sg_lb_stats(struct sched_domain *sd, * normalized nr_running number somewhere that negates * the hierarchy? */ - avg_load_per_task = sg_div_cpu_power(group, - sum_avg_load_per_task * SCHED_LOAD_SCALE); + avg_load_per_task = (sum_avg_load_per_task * SCHED_LOAD_SCALE) / + group->cpu_power; if ((max_cpu_load - min_cpu_load) > 2*avg_load_per_task) sgs->group_imb = 1; sgs->group_capacity = - DIV_ROUND_CLOSEST(group->__cpu_power, SCHED_LOAD_SCALE); + DIV_ROUND_CLOSEST(group->cpu_power, SCHED_LOAD_SCALE); } /** @@ -3951,7 +3918,7 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, return; sds->total_load += sgs.group_load; - sds->total_pwr += group->__cpu_power; + sds->total_pwr += group->cpu_power; /* * In case the child domain prefers tasks go to siblings @@ -4016,28 +3983,28 @@ static inline void fix_small_imbalance(struct sd_lb_stats *sds, * moving them. */ - pwr_now += sds->busiest->__cpu_power * + pwr_now += sds->busiest->cpu_power * min(sds->busiest_load_per_task, sds->max_load); - pwr_now += sds->this->__cpu_power * + pwr_now += sds->this->cpu_power * min(sds->this_load_per_task, sds->this_load); pwr_now /= SCHED_LOAD_SCALE; /* Amount of load we'd subtract */ - tmp = sg_div_cpu_power(sds->busiest, - sds->busiest_load_per_task * SCHED_LOAD_SCALE); + tmp = (sds->busiest_load_per_task * SCHED_LOAD_SCALE) / + sds->busiest->cpu_power; if (sds->max_load > tmp) - pwr_move += sds->busiest->__cpu_power * + pwr_move += sds->busiest->cpu_power * min(sds->busiest_load_per_task, sds->max_load - tmp); /* Amount of load we'd add */ - if (sds->max_load * sds->busiest->__cpu_power < + if (sds->max_load * sds->busiest->cpu_power < sds->busiest_load_per_task * SCHED_LOAD_SCALE) - tmp = sg_div_cpu_power(sds->this, - sds->max_load * sds->busiest->__cpu_power); + tmp = (sds->max_load * sds->busiest->cpu_power) / + sds->this->cpu_power; else - tmp = sg_div_cpu_power(sds->this, - sds->busiest_load_per_task * SCHED_LOAD_SCALE); - pwr_move += sds->this->__cpu_power * + tmp = (sds->busiest_load_per_task * SCHED_LOAD_SCALE) / + sds->this->cpu_power; + pwr_move += sds->this->cpu_power * min(sds->this_load_per_task, sds->this_load + tmp); pwr_move /= SCHED_LOAD_SCALE; @@ -4072,8 +4039,8 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu, sds->max_load - sds->busiest_load_per_task); /* How much load to actually move to equalise the imbalance */ - *imbalance = min(max_pull * sds->busiest->__cpu_power, - (sds->avg_load - sds->this_load) * sds->this->__cpu_power) + *imbalance = min(max_pull * sds->busiest->cpu_power, + (sds->avg_load - sds->this_load) * sds->this->cpu_power) / SCHED_LOAD_SCALE; /* @@ -4208,7 +4175,7 @@ static unsigned long power_of(int cpu) if (!group) return SCHED_LOAD_SCALE; - return group->__cpu_power; + return group->cpu_power; } /* @@ -7922,7 +7889,7 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, break; } - if (!group->__cpu_power) { + if (!group->cpu_power) { printk(KERN_CONT "\n"); printk(KERN_ERR "ERROR: domain->cpu_power not " "set\n"); @@ -7946,9 +7913,9 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, cpulist_scnprintf(str, sizeof(str), sched_group_cpus(group)); printk(KERN_CONT " %s", str); - if (group->__cpu_power != SCHED_LOAD_SCALE) { - printk(KERN_CONT " (__cpu_power = %d)", - group->__cpu_power); + if (group->cpu_power != SCHED_LOAD_SCALE) { + printk(KERN_CONT " (cpu_power = %d)", + group->cpu_power); } group = group->next; @@ -8233,7 +8200,7 @@ init_sched_build_groups(const struct cpumask *span, continue; cpumask_clear(sched_group_cpus(sg)); - sg->__cpu_power = 0; + sg->cpu_power = 0; for_each_cpu(j, span) { if (group_fn(j, cpu_map, NULL, tmpmask) != group) @@ -8491,7 +8458,7 @@ static void init_numa_sched_groups_power(struct sched_group *group_head) continue; } - sg_inc_cpu_power(sg, sd->groups->__cpu_power); + sg->cpu_power += sd->groups->cpu_power; } sg = sg->next; } while (sg != group_head); @@ -8528,7 +8495,7 @@ static int build_numa_sched_groups(struct s_data *d, sd->groups = sg; } - sg->__cpu_power = 0; + sg->cpu_power = 0; cpumask_copy(sched_group_cpus(sg), d->nodemask); sg->next = sg; cpumask_or(d->covered, d->covered, d->nodemask); @@ -8551,7 +8518,7 @@ static int build_numa_sched_groups(struct s_data *d, "Can not alloc domain group for node %d\n", j); return -ENOMEM; } - sg->__cpu_power = 0; + sg->cpu_power = 0; cpumask_copy(sched_group_cpus(sg), d->tmpmask); sg->next = prev->next; cpumask_or(d->covered, d->covered, d->tmpmask); @@ -8629,7 +8596,7 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) child = sd->child; - sd->groups->__cpu_power = 0; + sd->groups->cpu_power = 0; if (!child) { power = SCHED_LOAD_SCALE; @@ -8645,7 +8612,7 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) power /= weight; power >>= SCHED_LOAD_SHIFT; } - sg_inc_cpu_power(sd->groups, power); + sd->groups->cpu_power += power; return; } @@ -8654,7 +8621,7 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) */ group = child->groups; do { - sg_inc_cpu_power(sd->groups, group->__cpu_power); + sd->groups->cpu_power += group->cpu_power; group = group->next; } while (group != child->groups); } -- cgit v0.10.2 From 39e3ab6fded4d7e66e01a878f0cae23ddd480c3b Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Tue, 1 Sep 2009 05:26:12 +0000 Subject: can: add can_free_echo_skb() for upcoming drivers This patch adds the function can_free_echo_skb to the CAN device interface to allow upcoming drivers to release echo skb's in case of error. Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 1d29082..f0b9a1e 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -315,7 +315,7 @@ void can_get_echo_skb(struct net_device *dev, int idx) { struct can_priv *priv = netdev_priv(dev); - if ((dev->flags & IFF_ECHO) && priv->echo_skb[idx]) { + if (priv->echo_skb[idx]) { netif_rx(priv->echo_skb[idx]); priv->echo_skb[idx] = NULL; } @@ -323,6 +323,22 @@ void can_get_echo_skb(struct net_device *dev, int idx) EXPORT_SYMBOL_GPL(can_get_echo_skb); /* + * Remove the skb from the stack and free it. + * + * The function is typically called when TX failed. + */ +void can_free_echo_skb(struct net_device *dev, int idx) +{ + struct can_priv *priv = netdev_priv(dev); + + if (priv->echo_skb[idx]) { + kfree_skb(priv->echo_skb[idx]); + priv->echo_skb[idx] = NULL; + } +} +EXPORT_SYMBOL_GPL(can_free_echo_skb); + +/* * CAN device restart for bus-off recovery */ void can_restart(unsigned long data) diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 4a37a56..5824b20 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -66,5 +66,6 @@ void can_bus_off(struct net_device *dev); void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx); void can_get_echo_skb(struct net_device *dev, int idx); +void can_free_echo_skb(struct net_device *dev, int idx); #endif /* CAN_DEV_H */ -- cgit v0.10.2 From 8935f57e68c40c6469efe03f996bfb6150e18c6b Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Tue, 1 Sep 2009 05:29:41 +0000 Subject: can: sja1000: fix network statistics update The member "tx_bytes" of "struct net_device_stats" should be incremented when the interrupt is done and an "arbitration lost error" is a TX error and the statistics should be updated accordingly. Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index fd7fa71..16d2ecd 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -242,7 +242,6 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - struct net_device_stats *stats = &dev->stats; struct can_frame *cf = (struct can_frame *)skb->data; uint8_t fi; uint8_t dlc; @@ -276,7 +275,6 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, for (i = 0; i < dlc; i++) priv->write_reg(priv, dreg++, cf->data[i]); - stats->tx_bytes += dlc; dev->trans_start = jiffies; can_put_echo_skb(skb, dev, 0); @@ -427,7 +425,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) dev_dbg(dev->dev.parent, "arbitration lost interrupt\n"); alc = priv->read_reg(priv, REG_ALC); priv->can.can_stats.arbitration_lost++; - stats->rx_errors++; + stats->tx_errors++; cf->can_id |= CAN_ERR_LOSTARB; cf->data[0] = alc & 0x1f; } @@ -484,6 +482,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) if (isrc & IRQ_TI) { /* transmission complete interrupt */ + stats->tx_bytes += priv->read_reg(priv, REG_FI) & 0xf; stats->tx_packets++; can_get_echo_skb(dev, 0); netif_wake_queue(dev); -- cgit v0.10.2 From 2a6ba39ad6a277595ef9a0187a44f09e062dd3b2 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Tue, 1 Sep 2009 05:37:33 +0000 Subject: can: sja1000: legacy SJA1000 ISA bus driver This patch adds support for legacy SJA1000 CAN controllers on the ISA or PC-104 bus. The I/O port or memory address and the IRQ number must be specified via module parameters: insmod sja1000_isa.ko port=0x310,0x380 irq=7,11 for ISA devices using I/O ports or: insmod sja1000_isa.ko mem=0xd1000,0xd1000 irq=7,11 for memory mapped ISA devices. Indirect access via address and data port is supported as well: insmod sja1000_isa.ko port=0x310,0x380 indirect=1 irq=7,11 Here is a full list of the supported module parameters: port:I/O port number (array of ulong) mem:I/O memory address (array of ulong) indirect:Indirect access via address and data port (array of byte) irq:IRQ number (array of int) clk:External oscillator clock frequency (default=16000000 [16 MHz]) (array of int) cdr:Clock divider register (default=0x48 [CDR_CBP | CDR_CLK_OFF]) (array of byte) ocr:Output clock register (default=0x18 [OCR_TX0_PUSHPULL]) (array of byte) Note: for clk, cdr, ocr, the first argument re-defines the default for all other devices, e.g.: insmod sja1000_isa.ko mem=0xd1000,0xd1000 irq=7,11 clk=24000000 is equivalent to insmod sja1000_isa.ko mem=0xd1000,0xd1000 irq=7,11 \ clk=24000000,24000000 Signed-off-by: Wolfgang Grandegger Tested-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 30ae55d..0900743 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -41,6 +41,13 @@ config CAN_SJA1000 ---help--- Driver for the SJA1000 CAN controllers from Philips or NXP +config CAN_SJA1000_ISA + depends on CAN_SJA1000 && ISA + tristate "ISA Bus based legacy SJA1000 driver" + ---help--- + This driver adds legacy support for SJA1000 chips connected to + the ISA bus using I/O port, memory mapped or indirect access. + config CAN_SJA1000_PLATFORM depends on CAN_SJA1000 tristate "Generic Platform Bus based SJA1000 driver" diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index 9d0c08d..9d245ac 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_CAN_SJA1000) += sja1000.o +obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o diff --git a/drivers/net/can/sja1000/sja1000_isa.c b/drivers/net/can/sja1000/sja1000_isa.c new file mode 100644 index 0000000..a6a51f1 --- /dev/null +++ b/drivers/net/can/sja1000/sja1000_isa.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2009 Wolfgang Grandegger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "sja1000_isa" + +#define MAXDEV 8 + +MODULE_AUTHOR("Wolfgang Grandegger "); +MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the ISA bus"); +MODULE_LICENSE("GPL v2"); + +#define CLK_DEFAULT 16000000 /* 16 MHz */ +#define CDR_DEFAULT (CDR_CBP | CDR_CLK_OFF) +#define OCR_DEFAULT OCR_TX0_PUSHPULL + +static unsigned long port[MAXDEV]; +static unsigned long mem[MAXDEV]; +static int __devinitdata irq[MAXDEV]; +static int __devinitdata clk[MAXDEV]; +static char __devinitdata cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; +static char __devinitdata ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; +static char __devinitdata indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; + +module_param_array(port, ulong, NULL, S_IRUGO); +MODULE_PARM_DESC(port, "I/O port number"); + +module_param_array(mem, ulong, NULL, S_IRUGO); +MODULE_PARM_DESC(mem, "I/O memory address"); + +module_param_array(indirect, byte, NULL, S_IRUGO); +MODULE_PARM_DESC(indirect, "Indirect access via address and data port"); + +module_param_array(irq, int, NULL, S_IRUGO); +MODULE_PARM_DESC(irq, "IRQ number"); + +module_param_array(clk, int, NULL, S_IRUGO); +MODULE_PARM_DESC(clk, "External oscillator clock frequency " + "(default=16000000 [16 MHz])"); + +module_param_array(cdr, byte, NULL, S_IRUGO); +MODULE_PARM_DESC(cdr, "Clock divider register " + "(default=0x48 [CDR_CBP | CDR_CLK_OFF])"); + +module_param_array(ocr, byte, NULL, S_IRUGO); +MODULE_PARM_DESC(ocr, "Output control register " + "(default=0x18 [OCR_TX0_PUSHPULL])"); + +#define SJA1000_IOSIZE 0x20 +#define SJA1000_IOSIZE_INDIRECT 0x02 + +static u8 sja1000_isa_mem_read_reg(const struct sja1000_priv *priv, int reg) +{ + return readb(priv->reg_base + reg); +} + +static void sja1000_isa_mem_write_reg(const struct sja1000_priv *priv, + int reg, u8 val) +{ + writeb(val, priv->reg_base + reg); +} + +static u8 sja1000_isa_port_read_reg(const struct sja1000_priv *priv, int reg) +{ + return inb((unsigned long)priv->reg_base + reg); +} + +static void sja1000_isa_port_write_reg(const struct sja1000_priv *priv, + int reg, u8 val) +{ + outb(val, (unsigned long)priv->reg_base + reg); +} + +static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv, + int reg) +{ + unsigned long base = (unsigned long)priv->reg_base; + + outb(reg, base); + return inb(base + 1); +} + +static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv, + int reg, u8 val) +{ + unsigned long base = (unsigned long)priv->reg_base; + + outb(reg, base); + outb(val, base + 1); +} + +static int __devinit sja1000_isa_match(struct device *pdev, unsigned int idx) +{ + if (port[idx] || mem[idx]) { + if (irq[idx]) + return 1; + } else if (idx) + return 0; + + dev_err(pdev, "insufficient parameters supplied\n"); + return 0; +} + +static int __devinit sja1000_isa_probe(struct device *pdev, unsigned int idx) +{ + struct net_device *dev; + struct sja1000_priv *priv; + void __iomem *base = NULL; + int iosize = SJA1000_IOSIZE; + int err; + + if (mem[idx]) { + if (!request_mem_region(mem[idx], iosize, DRV_NAME)) { + err = -EBUSY; + goto exit; + } + base = ioremap_nocache(mem[idx], iosize); + if (!base) { + err = -ENOMEM; + goto exit_release; + } + } else { + if (indirect[idx] > 0 || + (indirect[idx] == -1 && indirect[0] > 0)) + iosize = SJA1000_IOSIZE_INDIRECT; + if (!request_region(port[idx], iosize, DRV_NAME)) { + err = -EBUSY; + goto exit; + } + } + + dev = alloc_sja1000dev(0); + if (!dev) { + err = -ENOMEM; + goto exit_unmap; + } + priv = netdev_priv(dev); + + dev->irq = irq[idx]; + priv->irq_flags = IRQF_SHARED; + if (mem[idx]) { + priv->reg_base = base; + dev->base_addr = mem[idx]; + priv->read_reg = sja1000_isa_mem_read_reg; + priv->write_reg = sja1000_isa_mem_write_reg; + } else { + priv->reg_base = (void __iomem *)port[idx]; + dev->base_addr = port[idx]; + + if (iosize == SJA1000_IOSIZE_INDIRECT) { + priv->read_reg = sja1000_isa_port_read_reg_indirect; + priv->write_reg = sja1000_isa_port_write_reg_indirect; + } else { + priv->read_reg = sja1000_isa_port_read_reg; + priv->write_reg = sja1000_isa_port_write_reg; + } + } + + if (clk[idx]) + priv->can.clock.freq = clk[idx] / 2; + else if (clk[0]) + priv->can.clock.freq = clk[0] / 2; + else + priv->can.clock.freq = CLK_DEFAULT / 2; + + if (ocr[idx] != -1) + priv->ocr = ocr[idx] & 0xff; + else if (ocr[0] != -1) + priv->ocr = ocr[0] & 0xff; + else + priv->ocr = OCR_DEFAULT; + + if (cdr[idx] != -1) + priv->cdr = cdr[idx] & 0xff; + else if (cdr[0] != -1) + priv->cdr = cdr[0] & 0xff; + else + priv->cdr = CDR_DEFAULT; + + dev_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, pdev); + + err = register_sja1000dev(dev); + if (err) { + dev_err(pdev, "registering %s failed (err=%d)\n", + DRV_NAME, err); + goto exit_unmap; + } + + dev_info(pdev, "%s device registered (reg_base=0x%p, irq=%d)\n", + DRV_NAME, priv->reg_base, dev->irq); + return 0; + + exit_unmap: + if (mem[idx]) + iounmap(base); + exit_release: + if (mem[idx]) + release_mem_region(mem[idx], iosize); + else + release_region(port[idx], iosize); + exit: + return err; +} + +static int __devexit sja1000_isa_remove(struct device *pdev, unsigned int idx) +{ + struct net_device *dev = dev_get_drvdata(pdev); + struct sja1000_priv *priv = netdev_priv(dev); + + unregister_sja1000dev(dev); + dev_set_drvdata(pdev, NULL); + + if (mem[idx]) { + iounmap(priv->reg_base); + release_mem_region(mem[idx], SJA1000_IOSIZE); + } else { + if (priv->read_reg == sja1000_isa_port_read_reg_indirect) + release_region(port[idx], SJA1000_IOSIZE_INDIRECT); + else + release_region(port[idx], SJA1000_IOSIZE); + } + free_sja1000dev(dev); + + return 0; +} + +static struct isa_driver sja1000_isa_driver = { + .match = sja1000_isa_match, + .probe = sja1000_isa_probe, + .remove = __devexit_p(sja1000_isa_remove), + .driver = { + .name = DRV_NAME, + }, +}; + +static int __init sja1000_isa_init(void) +{ + int err = isa_register_driver(&sja1000_isa_driver, MAXDEV); + + if (!err) + printk(KERN_INFO + "Legacy %s driver for max. %d devices registered\n", + DRV_NAME, MAXDEV); + return err; +} + +static void __exit sja1000_isa_exit(void) +{ + isa_unregister_driver(&sja1000_isa_driver); +} + +module_init(sja1000_isa_init); +module_exit(sja1000_isa_exit); -- cgit v0.10.2 From d7ea17a76916e456fcc78e45142c66f7fb875e3d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 4 Sep 2009 11:49:25 +0200 Subject: sched: Fix dynamic power-balancing crash This crash: [ 1774.088275] divide error: 0000 [#1] SMP [ 1774.100355] CPU 13 [ 1774.102498] Modules linked in: [ 1774.105631] Pid: 30881, comm: hackbench Not tainted 2.6.31-rc8-tip-01308-g484d664-dirty #1629 X8DTN [ 1774.114807] RIP: 0010:[] [] sched_balance_self+0x19b/0x2d4 Triggers because update_group_power() modifies the sd tree and does temporary calculations there - not considering that other CPUs could observe intermediate values, such as the zero initial value. Calculate it in a temporary variable instead. (we need no memory barrier as these are all statistical values anyway) Acked-by: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: <20090904092742.GA11014@elte.hu> Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index b537853..796baf7 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3765,19 +3765,22 @@ static void update_group_power(struct sched_domain *sd, int cpu) { struct sched_domain *child = sd->child; struct sched_group *group, *sdg = sd->groups; + unsigned long power; if (!child) { update_cpu_power(sd, cpu); return; } - sdg->cpu_power = 0; + power = 0; group = child->groups; do { - sdg->cpu_power += group->cpu_power; + power += group->cpu_power; group = group->next; } while (group != child->groups); + + sdg->cpu_power = power; } /** -- cgit v0.10.2 From 47734f89be0614b5acbd6a532390f9c72f019648 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 4 Sep 2009 11:21:24 +0200 Subject: sched: Clean up topology.h Re-organize the flag settings so that it's visible at a glance which sched-domains flags are set and which not. With the new balancer code we'll need to re-tune these details anyway, so make it cleaner to make fewer mistakes down the road ;-) Cc: Peter Zijlstra Cc: Andreas Herrmann Cc: Andreas Herrmann Cc: Gautham R Shenoy Cc: Balbir Singh LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index 066ef59..be29eb8 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -129,25 +129,34 @@ extern unsigned long node_remap_size[]; #endif /* sched_domains SD_NODE_INIT for NUMA machines */ -#define SD_NODE_INIT (struct sched_domain) { \ - .min_interval = 8, \ - .max_interval = 32, \ - .busy_factor = 32, \ - .imbalance_pct = 125, \ - .cache_nice_tries = SD_CACHE_NICE_TRIES, \ - .busy_idx = 3, \ - .idle_idx = SD_IDLE_IDX, \ - .newidle_idx = SD_NEWIDLE_IDX, \ - .wake_idx = 1, \ - .forkexec_idx = SD_FORKEXEC_IDX, \ - .flags = SD_LOAD_BALANCE \ - | SD_BALANCE_EXEC \ - | SD_BALANCE_FORK \ - | SD_WAKE_AFFINE \ - | SD_WAKE_BALANCE \ - | SD_SERIALIZE, \ - .last_balance = jiffies, \ - .balance_interval = 1, \ +#define SD_NODE_INIT (struct sched_domain) { \ + .min_interval = 8, \ + .max_interval = 32, \ + .busy_factor = 32, \ + .imbalance_pct = 125, \ + .cache_nice_tries = SD_CACHE_NICE_TRIES, \ + .busy_idx = 3, \ + .idle_idx = SD_IDLE_IDX, \ + .newidle_idx = SD_NEWIDLE_IDX, \ + .wake_idx = 1, \ + .forkexec_idx = SD_FORKEXEC_IDX, \ + \ + .flags = 1*SD_LOAD_BALANCE \ + | 0*SD_BALANCE_NEWIDLE \ + | 1*SD_BALANCE_EXEC \ + | 1*SD_BALANCE_FORK \ + | 0*SD_WAKE_IDLE \ + | 1*SD_WAKE_AFFINE \ + | 1*SD_WAKE_BALANCE \ + | 0*SD_SHARE_CPUPOWER \ + | 0*SD_POWERSAVINGS_BALANCE \ + | 0*SD_SHARE_PKG_RESOURCES \ + | 1*SD_SERIALIZE \ + | 0*SD_WAKE_IDLE_FAR \ + | 0*SD_PREFER_SIBLING \ + , \ + .last_balance = jiffies, \ + .balance_interval = 1, \ } #ifdef CONFIG_X86_64_ACPI_NUMA diff --git a/include/linux/topology.h b/include/linux/topology.h index 6203ae5..fe2c032 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -85,21 +85,29 @@ int arch_update_cpu_topology(void); #define ARCH_HAS_SCHED_WAKE_IDLE /* Common values for SMT siblings */ #ifndef SD_SIBLING_INIT -#define SD_SIBLING_INIT (struct sched_domain) { \ - .min_interval = 1, \ - .max_interval = 2, \ - .busy_factor = 64, \ - .imbalance_pct = 110, \ - .flags = SD_LOAD_BALANCE \ - | SD_BALANCE_NEWIDLE \ - | SD_BALANCE_FORK \ - | SD_BALANCE_EXEC \ - | SD_WAKE_AFFINE \ - | SD_WAKE_BALANCE \ - | SD_SHARE_CPUPOWER, \ - .last_balance = jiffies, \ - .balance_interval = 1, \ - .smt_gain = 1178, /* 15% */ \ +#define SD_SIBLING_INIT (struct sched_domain) { \ + .min_interval = 1, \ + .max_interval = 2, \ + .busy_factor = 64, \ + .imbalance_pct = 110, \ + \ + .flags = 1*SD_LOAD_BALANCE \ + | 1*SD_BALANCE_NEWIDLE \ + | 1*SD_BALANCE_EXEC \ + | 1*SD_BALANCE_FORK \ + | 0*SD_WAKE_IDLE \ + | 1*SD_WAKE_AFFINE \ + | 1*SD_WAKE_BALANCE \ + | 1*SD_SHARE_CPUPOWER \ + | 0*SD_POWERSAVINGS_BALANCE \ + | 0*SD_SHARE_PKG_RESOURCES \ + | 0*SD_SERIALIZE \ + | 0*SD_WAKE_IDLE_FAR \ + | 0*SD_PREFER_SIBLING \ + , \ + .last_balance = jiffies, \ + .balance_interval = 1, \ + .smt_gain = 1178, /* 15% */ \ } #endif #endif /* CONFIG_SCHED_SMT */ @@ -107,69 +115,94 @@ int arch_update_cpu_topology(void); #ifdef CONFIG_SCHED_MC /* Common values for MC siblings. for now mostly derived from SD_CPU_INIT */ #ifndef SD_MC_INIT -#define SD_MC_INIT (struct sched_domain) { \ - .min_interval = 1, \ - .max_interval = 4, \ - .busy_factor = 64, \ - .imbalance_pct = 125, \ - .cache_nice_tries = 1, \ - .busy_idx = 2, \ - .wake_idx = 1, \ - .forkexec_idx = 1, \ - .flags = SD_LOAD_BALANCE \ - | SD_BALANCE_FORK \ - | SD_BALANCE_EXEC \ - | SD_WAKE_AFFINE \ - | SD_WAKE_BALANCE \ - | SD_SHARE_PKG_RESOURCES\ - | sd_balance_for_mc_power()\ - | sd_power_saving_flags(),\ - .last_balance = jiffies, \ - .balance_interval = 1, \ +#define SD_MC_INIT (struct sched_domain) { \ + .min_interval = 1, \ + .max_interval = 4, \ + .busy_factor = 64, \ + .imbalance_pct = 125, \ + .cache_nice_tries = 1, \ + .busy_idx = 2, \ + .wake_idx = 1, \ + .forkexec_idx = 1, \ + \ + .flags = 1*SD_LOAD_BALANCE \ + | 0*SD_BALANCE_NEWIDLE \ + | 1*SD_BALANCE_EXEC \ + | 1*SD_BALANCE_FORK \ + | 0*SD_WAKE_IDLE \ + | 1*SD_WAKE_AFFINE \ + | 1*SD_WAKE_BALANCE \ + | 0*SD_SHARE_CPUPOWER \ + | 1*SD_SHARE_PKG_RESOURCES \ + | 0*SD_SERIALIZE \ + | 0*SD_WAKE_IDLE_FAR \ + | sd_balance_for_mc_power() \ + | sd_power_saving_flags() \ + , \ + .last_balance = jiffies, \ + .balance_interval = 1, \ } #endif #endif /* CONFIG_SCHED_MC */ /* Common values for CPUs */ #ifndef SD_CPU_INIT -#define SD_CPU_INIT (struct sched_domain) { \ - .min_interval = 1, \ - .max_interval = 4, \ - .busy_factor = 64, \ - .imbalance_pct = 125, \ - .cache_nice_tries = 1, \ - .busy_idx = 2, \ - .idle_idx = 1, \ - .newidle_idx = 2, \ - .wake_idx = 1, \ - .forkexec_idx = 1, \ - .flags = SD_LOAD_BALANCE \ - | SD_BALANCE_EXEC \ - | SD_BALANCE_FORK \ - | SD_WAKE_AFFINE \ - | SD_WAKE_BALANCE \ - | sd_balance_for_package_power()\ - | sd_power_saving_flags(),\ - .last_balance = jiffies, \ - .balance_interval = 1, \ +#define SD_CPU_INIT (struct sched_domain) { \ + .min_interval = 1, \ + .max_interval = 4, \ + .busy_factor = 64, \ + .imbalance_pct = 125, \ + .cache_nice_tries = 1, \ + .busy_idx = 2, \ + .idle_idx = 1, \ + .newidle_idx = 2, \ + .wake_idx = 1, \ + .forkexec_idx = 1, \ + \ + .flags = 1*SD_LOAD_BALANCE \ + | 0*SD_BALANCE_NEWIDLE \ + | 1*SD_BALANCE_EXEC \ + | 1*SD_BALANCE_FORK \ + | 0*SD_WAKE_IDLE \ + | 0*SD_WAKE_AFFINE \ + | 1*SD_WAKE_BALANCE \ + | 0*SD_SHARE_CPUPOWER \ + | 0*SD_SHARE_PKG_RESOURCES \ + | 0*SD_SERIALIZE \ + | 0*SD_WAKE_IDLE_FAR \ + | sd_balance_for_package_power() \ + | sd_power_saving_flags() \ + , \ + .last_balance = jiffies, \ + .balance_interval = 1, \ } #endif /* sched_domains SD_ALLNODES_INIT for NUMA machines */ -#define SD_ALLNODES_INIT (struct sched_domain) { \ - .min_interval = 64, \ - .max_interval = 64*num_online_cpus(), \ - .busy_factor = 128, \ - .imbalance_pct = 133, \ - .cache_nice_tries = 1, \ - .busy_idx = 3, \ - .idle_idx = 3, \ - .flags = SD_LOAD_BALANCE \ - | SD_BALANCE_NEWIDLE \ - | SD_WAKE_AFFINE \ - | SD_SERIALIZE, \ - .last_balance = jiffies, \ - .balance_interval = 64, \ +#define SD_ALLNODES_INIT (struct sched_domain) { \ + .min_interval = 64, \ + .max_interval = 64*num_online_cpus(), \ + .busy_factor = 128, \ + .imbalance_pct = 133, \ + .cache_nice_tries = 1, \ + .busy_idx = 3, \ + .idle_idx = 3, \ + .flags = 1*SD_LOAD_BALANCE \ + | 1*SD_BALANCE_NEWIDLE \ + | 0*SD_BALANCE_EXEC \ + | 0*SD_BALANCE_FORK \ + | 0*SD_WAKE_IDLE \ + | 1*SD_WAKE_AFFINE \ + | 0*SD_WAKE_BALANCE \ + | 0*SD_SHARE_CPUPOWER \ + | 0*SD_POWERSAVINGS_BALANCE \ + | 0*SD_SHARE_PKG_RESOURCES \ + | 1*SD_SERIALIZE \ + | 0*SD_WAKE_IDLE_FAR \ + | 0*SD_PREFER_SIBLING \ + , \ + .last_balance = jiffies, \ + .balance_interval = 64, \ } #ifdef CONFIG_NUMA -- cgit v0.10.2 From 840a0653100dbde599ae8ddf83fa214dfa5fd1aa Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 4 Sep 2009 11:32:54 +0200 Subject: sched: Turn on SD_BALANCE_NEWIDLE Start the re-tuning of the balancer by turning on newidle. It improves hackbench performance and parallelism on a 4x4 box. The "perf stat --repeat 10" measurements give us: domain0 domain1 ....................................... -SD_BALANCE_NEWIDLE -SD_BALANCE_NEWIDLE: 2041.273208 task-clock-msecs # 9.354 CPUs ( +- 0.363% ) +SD_BALANCE_NEWIDLE -SD_BALANCE_NEWIDLE: 2086.326925 task-clock-msecs # 11.934 CPUs ( +- 0.301% ) +SD_BALANCE_NEWIDLE +SD_BALANCE_NEWIDLE: 2115.289791 task-clock-msecs # 12.158 CPUs ( +- 0.263% ) Acked-by: Peter Zijlstra Cc: Andreas Herrmann Cc: Andreas Herrmann Cc: Gautham R Shenoy Cc: Balbir Singh LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index be29eb8..ef7bc7f 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -142,7 +142,7 @@ extern unsigned long node_remap_size[]; .forkexec_idx = SD_FORKEXEC_IDX, \ \ .flags = 1*SD_LOAD_BALANCE \ - | 0*SD_BALANCE_NEWIDLE \ + | 1*SD_BALANCE_NEWIDLE \ | 1*SD_BALANCE_EXEC \ | 1*SD_BALANCE_FORK \ | 0*SD_WAKE_IDLE \ diff --git a/include/linux/topology.h b/include/linux/topology.h index fe2c032..66774fd 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -126,7 +126,7 @@ int arch_update_cpu_topology(void); .forkexec_idx = 1, \ \ .flags = 1*SD_LOAD_BALANCE \ - | 0*SD_BALANCE_NEWIDLE \ + | 1*SD_BALANCE_NEWIDLE \ | 1*SD_BALANCE_EXEC \ | 1*SD_BALANCE_FORK \ | 0*SD_WAKE_IDLE \ @@ -160,7 +160,7 @@ int arch_update_cpu_topology(void); .forkexec_idx = 1, \ \ .flags = 1*SD_LOAD_BALANCE \ - | 0*SD_BALANCE_NEWIDLE \ + | 1*SD_BALANCE_NEWIDLE \ | 1*SD_BALANCE_EXEC \ | 1*SD_BALANCE_FORK \ | 0*SD_WAKE_IDLE \ -- cgit v0.10.2 From 825c9fb47a0837db12fecf8d360e0e1d284ddb49 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 4 Sep 2009 02:56:22 -0700 Subject: sparc: add basic support for 'perf' This wires up the perf_counter_open() syscall so that basic software support for perf is working. Signed-off-by: Jens Axboe Signed-off-by: David S. Miller diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index b847f88..2aa7cd3 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -25,6 +25,7 @@ config SPARC select ARCH_WANT_OPTIONAL_GPIOLIB select RTC_CLASS select RTC_DRV_M48T59 + select HAVE_PERF_COUNTERS config SPARC32 def_bool !64BIT @@ -44,6 +45,7 @@ config SPARC64 select RTC_DRV_BQ4802 select RTC_DRV_SUN4V select RTC_DRV_STARFIRE + select HAVE_PERF_COUNTERS config ARCH_DEFCONFIG string diff --git a/arch/sparc/include/asm/perf_counter.h b/arch/sparc/include/asm/perf_counter.h new file mode 100644 index 0000000..f07c587 --- /dev/null +++ b/arch/sparc/include/asm/perf_counter.h @@ -0,0 +1,8 @@ +#ifndef __ASM_SPARC_PERF_COUNTER_H +#define __ASM_SPARC_PERF_COUNTER_H + +static inline void set_perf_counter_pending(void) { } + +#define PERF_COUNTER_INDEX_OFFSET 0 + +#endif diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index b2c406d..706df66 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -395,8 +395,9 @@ #define __NR_preadv 324 #define __NR_pwritev 325 #define __NR_rt_tgsigqueueinfo 326 +#define __NR_perf_counter_open 327 -#define NR_SYSCALLS 327 +#define NR_SYSCALLS 328 #ifdef __32bit_syscall_numbers__ /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 6909016..0418157 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -82,5 +82,5 @@ sys_call_table: /*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate /*315*/ .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv -/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo +/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_counter_open diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 2ee7250..91b06b7 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -83,7 +83,7 @@ sys_call_table32: /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv - .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo + .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_counter_open #endif /* CONFIG_COMPAT */ @@ -158,4 +158,4 @@ sys_call_table: /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv - .word sys_pwritev, sys_rt_tgsigqueueinfo + .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_counter_open diff --git a/tools/perf/perf.h b/tools/perf/perf.h index e5148e2..2abeb20 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -41,6 +41,12 @@ #define cpu_relax() asm volatile("" ::: "memory"); #endif +#ifdef __sparc__ +#include "../../arch/sparc/include/asm/unistd.h" +#define rmb() asm volatile("":::"memory") +#define cpu_relax() asm volatile("":::"memory") +#endif + #include #include #include -- cgit v0.10.2 From 8a34e2f8ba7d4302977c90e357921994a6c39af9 Mon Sep 17 00:00:00 2001 From: Sachin Sant Date: Fri, 4 Sep 2009 03:41:07 -0700 Subject: net: Fix a build break because of a typo in drivers/net/3c503.c Signed-off-by: Sachin Sant Signed-off-by: David S. Miller diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 81c148a..c71e12d 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -403,7 +403,7 @@ el2_open(struct net_device *dev) break; } else { if (retval != -EBUSY) - return reval; + return retval; } } while (*++irqp); if (*irqp == 0) { -- cgit v0.10.2 From 506d4bc8d5dab20d84624aa07cdc6dcd77915d52 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 4 Sep 2009 15:36:12 +0200 Subject: perf stat: Change noise calculation to use stddev The current noise computation does: \Sum abs(n_i - avg(n)) * N^-1.5 Which is (afaik) not a regular noise function, and needs the complete sample set available to post-process. Change this to use a regular stddev computation which can be done by keeping a two sums: stddev = sqrt( 1/N (\Sum n_i^2) - avg(n)^2 ) For which we only need to keep \Sum n_i and \Sum n_i^2. Signed-off-by: Peter Zijlstra Cc: LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 1a26262..31ffc4d 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -83,19 +83,32 @@ static u64 runtime_cycles[MAX_RUN]; static u64 event_res[MAX_RUN][MAX_COUNTERS][3]; static u64 event_scaled[MAX_RUN][MAX_COUNTERS]; -static u64 event_res_avg[MAX_COUNTERS][3]; -static u64 event_res_noise[MAX_COUNTERS][3]; +struct stats +{ + double sum; + double sum_sq; +}; -static u64 event_scaled_avg[MAX_COUNTERS]; +static double avg_stats(struct stats *stats) +{ + return stats->sum / run_count; +} -static u64 runtime_nsecs_avg; -static u64 runtime_nsecs_noise; +/* + * stddev = sqrt(1/N (\Sum n_i^2) - avg(n)^2) + */ +static double stddev_stats(struct stats *stats) +{ + double avg = stats->sum / run_count; -static u64 walltime_nsecs_avg; -static u64 walltime_nsecs_noise; + return sqrt(stats->sum_sq/run_count - avg*avg); +} -static u64 runtime_cycles_avg; -static u64 runtime_cycles_noise; +struct stats event_res_stats[MAX_COUNTERS][3]; +struct stats event_scaled_stats[MAX_COUNTERS]; +struct stats runtime_nsecs_stats; +struct stats walltime_nsecs_stats; +struct stats runtime_cycles_stats; #define MATCH_EVENT(t, c, counter) \ (attrs[counter].type == PERF_TYPE_##t && \ @@ -279,42 +292,37 @@ static int run_perf_stat(int argc __used, const char **argv) return WEXITSTATUS(status); } -static void print_noise(u64 *count, u64 *noise) +static void print_noise(double avg, double stddev) { if (run_count > 1) - fprintf(stderr, " ( +- %7.3f%% )", - (double)noise[0]/(count[0]+1)*100.0); + fprintf(stderr, " ( +- %7.3f%% )", 100*stddev / avg); } -static void nsec_printout(int counter, u64 *count, u64 *noise) +static void nsec_printout(int counter, double avg, double stddev) { - double msecs = (double)count[0] / 1000000; + double msecs = avg / 1e6; fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter)); if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { - if (walltime_nsecs_avg) - fprintf(stderr, " # %10.3f CPUs ", - (double)count[0] / (double)walltime_nsecs_avg); + fprintf(stderr, " # %10.3f CPUs ", + avg / avg_stats(&walltime_nsecs_stats)); } - print_noise(count, noise); + print_noise(avg, stddev); } -static void abs_printout(int counter, u64 *count, u64 *noise) +static void abs_printout(int counter, double avg, double stddev) { - fprintf(stderr, " %14Ld %-24s", count[0], event_name(counter)); + fprintf(stderr, " %14.0f %-24s", avg, event_name(counter)); - if (runtime_cycles_avg && - MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { + if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { fprintf(stderr, " # %10.3f IPC ", - (double)count[0] / (double)runtime_cycles_avg); + avg / avg_stats(&runtime_cycles_stats)); } else { - if (runtime_nsecs_avg) { - fprintf(stderr, " # %10.3f M/sec", - (double)count[0]/runtime_nsecs_avg*1000.0); - } + fprintf(stderr, " # %10.3f M/sec", + 1000.0 * avg / avg_stats(&runtime_nsecs_stats)); } - print_noise(count, noise); + print_noise(avg, stddev); } /* @@ -322,12 +330,12 @@ static void abs_printout(int counter, u64 *count, u64 *noise) */ static void print_counter(int counter) { - u64 *count, *noise; + double avg, stddev; int scaled; - count = event_res_avg[counter]; - noise = event_res_noise[counter]; - scaled = event_scaled_avg[counter]; + avg = avg_stats(&event_res_stats[counter][0]); + stddev = stddev_stats(&event_res_stats[counter][0]); + scaled = avg_stats(&event_scaled_stats[counter]); if (scaled == -1) { fprintf(stderr, " %14s %-24s\n", @@ -336,36 +344,34 @@ static void print_counter(int counter) } if (nsec_counter(counter)) - nsec_printout(counter, count, noise); + nsec_printout(counter, avg, stddev); else - abs_printout(counter, count, noise); + abs_printout(counter, avg, stddev); + + if (scaled) { + double avg_enabled, avg_running; + + avg_enabled = avg_stats(&event_res_stats[counter][1]); + avg_running = avg_stats(&event_res_stats[counter][2]); - if (scaled) fprintf(stderr, " (scaled from %.2f%%)", - (double) count[2] / count[1] * 100); + 100 * avg_running / avg_enabled); + } fprintf(stderr, "\n"); } -/* - * normalize_noise noise values down to stddev: - */ -static void normalize_noise(u64 *val) +static void update_stats(const char *name, int idx, struct stats *stats, u64 *val) { - double res; + double sq = *val; - res = (double)*val / (run_count * sqrt((double)run_count)); - - *val = (u64)res; -} - -static void update_avg(const char *name, int idx, u64 *avg, u64 *val) -{ - *avg += *val; + stats->sum += *val; + stats->sum_sq += sq * sq; if (verbose > 1) fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val); } + /* * Calculate the averages and noises: */ @@ -377,61 +383,22 @@ static void calc_avg(void) fprintf(stderr, "\n"); for (i = 0; i < run_count; i++) { - update_avg("runtime", 0, &runtime_nsecs_avg, runtime_nsecs + i); - update_avg("walltime", 0, &walltime_nsecs_avg, walltime_nsecs + i); - update_avg("runtime_cycles", 0, &runtime_cycles_avg, runtime_cycles + i); + update_stats("runtime", 0, &runtime_nsecs_stats, runtime_nsecs + i); + update_stats("walltime", 0, &walltime_nsecs_stats, walltime_nsecs + i); + update_stats("runtime_cycles", 0, &runtime_cycles_stats, runtime_cycles + i); for (j = 0; j < nr_counters; j++) { - update_avg("counter/0", j, - event_res_avg[j]+0, event_res[i][j]+0); - update_avg("counter/1", j, - event_res_avg[j]+1, event_res[i][j]+1); - update_avg("counter/2", j, - event_res_avg[j]+2, event_res[i][j]+2); + update_stats("counter/0", j, + event_res_stats[j]+0, event_res[i][j]+0); + update_stats("counter/1", j, + event_res_stats[j]+1, event_res[i][j]+1); + update_stats("counter/2", j, + event_res_stats[j]+2, event_res[i][j]+2); if (event_scaled[i][j] != (u64)-1) - update_avg("scaled", j, - event_scaled_avg + j, event_scaled[i]+j); - else - event_scaled_avg[j] = -1; + update_stats("scaled", j, + event_scaled_stats + j, event_scaled[i]+j); } } - runtime_nsecs_avg /= run_count; - walltime_nsecs_avg /= run_count; - runtime_cycles_avg /= run_count; - - for (j = 0; j < nr_counters; j++) { - event_res_avg[j][0] /= run_count; - event_res_avg[j][1] /= run_count; - event_res_avg[j][2] /= run_count; - } - - for (i = 0; i < run_count; i++) { - runtime_nsecs_noise += - abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg)); - walltime_nsecs_noise += - abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg)); - runtime_cycles_noise += - abs((s64)(runtime_cycles[i] - runtime_cycles_avg)); - - for (j = 0; j < nr_counters; j++) { - event_res_noise[j][0] += - abs((s64)(event_res[i][j][0] - event_res_avg[j][0])); - event_res_noise[j][1] += - abs((s64)(event_res[i][j][1] - event_res_avg[j][1])); - event_res_noise[j][2] += - abs((s64)(event_res[i][j][2] - event_res_avg[j][2])); - } - } - - normalize_noise(&runtime_nsecs_noise); - normalize_noise(&walltime_nsecs_noise); - normalize_noise(&runtime_cycles_noise); - - for (j = 0; j < nr_counters; j++) { - normalize_noise(&event_res_noise[j][0]); - normalize_noise(&event_res_noise[j][1]); - normalize_noise(&event_res_noise[j][2]); - } } static void print_stat(int argc, const char **argv) @@ -458,10 +425,11 @@ static void print_stat(int argc, const char **argv) fprintf(stderr, "\n"); fprintf(stderr, " %14.9f seconds time elapsed", - (double)walltime_nsecs_avg/1e9); + avg_stats(&walltime_nsecs_stats)/1e9); if (run_count > 1) { fprintf(stderr, " ( +- %7.3f%% )", - 100.0*(double)walltime_nsecs_noise/(double)walltime_nsecs_avg); + 100*stddev_stats(&walltime_nsecs_stats) / + avg_stats(&walltime_nsecs_stats)); } fprintf(stderr, "\n\n"); } -- cgit v0.10.2 From 9e9772c458d50dabdb5327821da3803254638cd1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 4 Sep 2009 15:36:08 +0200 Subject: perf stat: Remove the limit on repeat Since we don't need all the individual samples to calculate the error remove both the limit and the storage overhead associated with that. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 31ffc4d..9c6377f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -62,8 +62,6 @@ static struct perf_counter_attr default_attrs[] = { }; -#define MAX_RUN 100 - static int system_wide = 0; static unsigned int nr_cpus = 0; static int run_idx = 0; @@ -76,12 +74,8 @@ static int null_run = 0; static int fd[MAX_NR_CPUS][MAX_COUNTERS]; -static u64 runtime_nsecs[MAX_RUN]; -static u64 walltime_nsecs[MAX_RUN]; -static u64 runtime_cycles[MAX_RUN]; - -static u64 event_res[MAX_RUN][MAX_COUNTERS][3]; -static u64 event_scaled[MAX_RUN][MAX_COUNTERS]; +static u64 event_res[MAX_COUNTERS][3]; +static u64 event_scaled[MAX_COUNTERS]; struct stats { @@ -89,6 +83,14 @@ struct stats double sum_sq; }; +static void update_stats(struct stats *stats, u64 val) +{ + double sq = val; + + stats->sum += val; + stats->sum_sq += sq * sq; +} + static double avg_stats(struct stats *stats) { return stats->sum / run_count; @@ -167,8 +169,9 @@ static void read_counter(int counter) unsigned int cpu; size_t res, nv; int scaled; + int i; - count = event_res[run_idx][counter]; + count = event_res[counter]; count[0] = count[1] = count[2] = 0; @@ -193,24 +196,33 @@ static void read_counter(int counter) scaled = 0; if (scale) { if (count[2] == 0) { - event_scaled[run_idx][counter] = -1; + event_scaled[counter] = -1; count[0] = 0; return; } if (count[2] < count[1]) { - event_scaled[run_idx][counter] = 1; + event_scaled[counter] = 1; count[0] = (unsigned long long) ((double)count[0] * count[1] / count[2] + 0.5); } } + + for (i = 0; i < 3; i++) + update_stats(&event_res_stats[counter][i], count[i]); + + if (verbose) { + fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter), + count[0], count[1], count[2]); + } + /* * Save the full runtime - to allow normalization during printout: */ if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) - runtime_nsecs[run_idx] = count[0]; + update_stats(&runtime_nsecs_stats, count[0]); if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) - runtime_cycles[run_idx] = count[0]; + update_stats(&runtime_cycles_stats, count[0]); } static int run_perf_stat(int argc __used, const char **argv) @@ -284,7 +296,7 @@ static int run_perf_stat(int argc __used, const char **argv) t1 = rdclock(); - walltime_nsecs[run_idx] = t1 - t0; + update_stats(&walltime_nsecs_stats, t1 - t0); for (counter = 0; counter < nr_counters; counter++) read_counter(counter); @@ -361,52 +373,10 @@ static void print_counter(int counter) fprintf(stderr, "\n"); } -static void update_stats(const char *name, int idx, struct stats *stats, u64 *val) -{ - double sq = *val; - - stats->sum += *val; - stats->sum_sq += sq * sq; - - if (verbose > 1) - fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val); -} - -/* - * Calculate the averages and noises: - */ -static void calc_avg(void) -{ - int i, j; - - if (verbose > 1) - fprintf(stderr, "\n"); - - for (i = 0; i < run_count; i++) { - update_stats("runtime", 0, &runtime_nsecs_stats, runtime_nsecs + i); - update_stats("walltime", 0, &walltime_nsecs_stats, walltime_nsecs + i); - update_stats("runtime_cycles", 0, &runtime_cycles_stats, runtime_cycles + i); - - for (j = 0; j < nr_counters; j++) { - update_stats("counter/0", j, - event_res_stats[j]+0, event_res[i][j]+0); - update_stats("counter/1", j, - event_res_stats[j]+1, event_res[i][j]+1); - update_stats("counter/2", j, - event_res_stats[j]+2, event_res[i][j]+2); - if (event_scaled[i][j] != (u64)-1) - update_stats("scaled", j, - event_scaled_stats + j, event_scaled[i]+j); - } - } -} - static void print_stat(int argc, const char **argv) { int i, counter; - calc_avg(); - fflush(stdout); fprintf(stderr, "\n"); @@ -484,7 +454,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) PARSE_OPT_STOP_AT_NON_OPTION); if (!argc) usage_with_options(stat_usage, options); - if (run_count <= 0 || run_count > MAX_RUN) + if (run_count <= 0) usage_with_options(stat_usage, options); /* Set attrs and nr_counters if no event is selected and !null_run */ -- cgit v0.10.2 From 8e019366ba749a536131cde1947af6dcaccf8e8f Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Thu, 27 Aug 2009 14:50:00 +0100 Subject: kmemleak: Don't scan uninitialized memory when kmemcheck is enabled Ingo Molnar reported the following kmemcheck warning when running both kmemleak and kmemcheck enabled: PM: Adding info for No Bus:vcsa7 WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (f6f6e1a4) d873f9f600000000c42ae4c1005c87f70000000070665f666978656400000000 i i i i u u u u i i i i i i i i i i i i i i i i i i i i i u u u ^ Pid: 3091, comm: kmemleak Not tainted (2.6.31-rc7-tip #1303) P4DC6 EIP: 0060:[] EFLAGS: 00010006 CPU: 0 EIP is at scan_block+0x3f/0xe0 EAX: f40bd700 EBX: f40bd780 ECX: f16b46c0 EDX: 00000001 ESI: f6f6e1a4 EDI: 00000000 EBP: f10f3f4c ESP: c2605fcc DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 CR0: 8005003b CR2: e89a4844 CR3: 30ff1000 CR4: 000006f0 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff4ff0 DR7: 00000400 [] scan_object+0x7c/0xf0 [] kmemleak_scan+0x1d9/0x400 [] kmemleak_scan_thread+0x4c/0xb0 [] kthread+0x74/0x80 [] kernel_thread_helper+0x7/0x3c [] 0xffffffff kmemleak: 515 new suspected memory leaks (see /sys/kernel/debug/kmemleak) kmemleak: 42 new suspected memory leaks (see /sys/kernel/debug/kmemleak) The problem here is that kmemleak will scan partially initialized objects that makes kmemcheck complain. Fix that up by skipping uninitialized memory regions when kmemcheck is enabled. Reported-by: Ingo Molnar Acked-by: Ingo Molnar Acked-by: Catalin Marinas Signed-off-by: Pekka Enberg diff --git a/arch/x86/mm/kmemcheck/kmemcheck.c b/arch/x86/mm/kmemcheck/kmemcheck.c index 2c55ed0..528bf95 100644 --- a/arch/x86/mm/kmemcheck/kmemcheck.c +++ b/arch/x86/mm/kmemcheck/kmemcheck.c @@ -331,6 +331,20 @@ static void kmemcheck_read_strict(struct pt_regs *regs, kmemcheck_shadow_set(shadow, size); } +bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size) +{ + enum kmemcheck_shadow status; + void *shadow; + + shadow = kmemcheck_shadow_lookup(addr); + if (!shadow) + return true; + + status = kmemcheck_shadow_test(shadow, size); + + return status == KMEMCHECK_SHADOW_INITIALIZED; +} + /* Access may cross page boundary */ static void kmemcheck_read(struct pt_regs *regs, unsigned long addr, unsigned int size) diff --git a/include/linux/kmemcheck.h b/include/linux/kmemcheck.h index 47b39b7..dc2fd54 100644 --- a/include/linux/kmemcheck.h +++ b/include/linux/kmemcheck.h @@ -34,6 +34,8 @@ void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n); int kmemcheck_show_addr(unsigned long address); int kmemcheck_hide_addr(unsigned long address); +bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size); + #else #define kmemcheck_enabled 0 @@ -99,6 +101,11 @@ static inline void kmemcheck_mark_initialized_pages(struct page *p, { } +static inline bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size) +{ + return true; +} + #endif /* CONFIG_KMEMCHECK */ /* diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 1d7645b..c494fee 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -97,6 +97,7 @@ #include #include +#include #include /* @@ -967,15 +968,22 @@ static void scan_block(void *_start, void *_end, unsigned long *end = _end - (BYTES_PER_POINTER - 1); for (ptr = start; ptr < end; ptr++) { - unsigned long flags; - unsigned long pointer = *ptr; struct kmemleak_object *object; + unsigned long flags; + unsigned long pointer; if (allow_resched) cond_resched(); if (scan_should_stop()) break; + /* don't scan uninitialized memory */ + if (!kmemcheck_is_obj_initialized((unsigned long)ptr, + BYTES_PER_POINTER)) + continue; + + pointer = *ptr; + object = find_and_get_object(pointer, 1); if (!object) continue; -- cgit v0.10.2 From 43ed5d6ee0f9bfd655d6bc3cb2d964b80c4422c0 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 1 Sep 2009 11:12:44 +0100 Subject: kmemleak: Scan all thread stacks This patch changes the for_each_process() loop with the do_each_thread()/while_each_thread() pair. Signed-off-by: Catalin Marinas diff --git a/mm/kmemleak.c b/mm/kmemleak.c index c494fee..74d4089 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1074,7 +1074,6 @@ static void kmemleak_scan(void) { unsigned long flags; struct kmemleak_object *object, *tmp; - struct task_struct *task; int i; int new_leaks = 0; int gray_list_pass = 0; @@ -1141,15 +1140,16 @@ static void kmemleak_scan(void) } /* - * Scanning the task stacks may introduce false negatives and it is - * not enabled by default. + * Scanning the task stacks (may introduce false negatives). */ if (kmemleak_stack_scan) { + struct task_struct *p, *g; + read_lock(&tasklist_lock); - for_each_process(task) - scan_block(task_stack_page(task), - task_stack_page(task) + THREAD_SIZE, - NULL, 0); + do_each_thread(g, p) { + scan_block(task_stack_page(p), task_stack_page(p) + + THREAD_SIZE, NULL, 0); + } while_each_thread(g, p); read_unlock(&tasklist_lock); } -- cgit v0.10.2 From 41b6a95d693319f804607b559893fbbd27498548 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 2 Sep 2009 09:59:48 -0400 Subject: ring-buffer: do not reset while in a commit The callers of reset must ensure that no commit can be taking place at the time of the reset. If it does then we may corrupt the ring buffer. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index da2c59d..79d6012 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -3373,12 +3373,16 @@ void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu) spin_lock_irqsave(&cpu_buffer->reader_lock, flags); + if (RB_WARN_ON(cpu_buffer, local_read(&cpu_buffer->committing))) + goto out; + __raw_spin_lock(&cpu_buffer->lock); rb_reset_cpu(cpu_buffer); __raw_spin_unlock(&cpu_buffer->lock); + out: spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); atomic_dec(&cpu_buffer->record_disabled); -- cgit v0.10.2 From 98277991a99734f3a31d638afb47d4484ac73e43 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 2 Sep 2009 10:56:15 -0400 Subject: ring-buffer: do not swap buffers during a commit If a commit is taking place on a CPU ring buffer, do not allow it to be swapped. Return -EBUSY when this is detected instead. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 79d6012..2878bd43 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -3519,16 +3519,23 @@ int ring_buffer_swap_cpu(struct ring_buffer *buffer_a, atomic_inc(&cpu_buffer_a->record_disabled); atomic_inc(&cpu_buffer_b->record_disabled); + ret = -EBUSY; + if (local_read(&cpu_buffer_a->committing)) + goto out_dec; + if (local_read(&cpu_buffer_b->committing)) + goto out_dec; + buffer_a->buffers[cpu] = cpu_buffer_b; buffer_b->buffers[cpu] = cpu_buffer_a; cpu_buffer_b->buffer = buffer_a; cpu_buffer_a->buffer = buffer_b; + ret = 0; + +out_dec: atomic_dec(&cpu_buffer_a->record_disabled); atomic_dec(&cpu_buffer_b->record_disabled); - - ret = 0; out: return ret; } -- cgit v0.10.2 From 1b959e18c4d6b4b981f887260b0f8e7939efa411 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 3 Sep 2009 10:12:13 -0400 Subject: ring-buffer: remove unnecessary cpu_relax The loops in the ring buffer that use cpu_relax are not dependent on other CPUs. They simply came across some padding in the ring buffer and are skipping over them. It is a normal loop and does not require a cpu_relax. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 2878bd43..a05541a 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -3132,10 +3132,8 @@ ring_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts) spin_unlock(&cpu_buffer->reader_lock); local_irq_restore(flags); - if (event && event->type_len == RINGBUF_TYPE_PADDING) { - cpu_relax(); + if (event && event->type_len == RINGBUF_TYPE_PADDING) goto again; - } return event; } @@ -3160,10 +3158,8 @@ ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts) event = rb_iter_peek(iter, ts); spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); - if (event && event->type_len == RINGBUF_TYPE_PADDING) { - cpu_relax(); + if (event && event->type_len == RINGBUF_TYPE_PADDING) goto again; - } return event; } @@ -3209,10 +3205,8 @@ ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts) out: preempt_enable(); - if (event && event->type_len == RINGBUF_TYPE_PADDING) { - cpu_relax(); + if (event && event->type_len == RINGBUF_TYPE_PADDING) goto again; - } return event; } @@ -3302,10 +3296,8 @@ ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts) out: spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); - if (event && event->type_len == RINGBUF_TYPE_PADDING) { - cpu_relax(); + if (event && event->type_len == RINGBUF_TYPE_PADDING) goto again; - } return event; } -- cgit v0.10.2 From 7e9391cfedce34eb9786bfa69d7d545dc93ef930 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 3 Sep 2009 10:02:09 -0400 Subject: ring-buffer: fix ring_buffer_read crossing pages When the ring buffer uses an iterator (static read mode, not on the fly reading), when it crosses a page boundery, it will skip the first entry on the next page. The reason is that the last entry of a page is usually padding if the page is not full. The padding will not be returned to the user. The problem arises on ring_buffer_read because it also increments the iterator. Because both the read and peek use the same rb_iter_peek, the rb_iter_peak will return the padding but also increment to the next item. This is because the ring_buffer_peek will not incerment it itself. The ring_buffer_read will increment it again and then call rb_iter_peek again to get the next item. But that will be the second item, not the first one on the page. The reason this never showed up before, is because the ftrace utility always calls ring_buffer_peek first and only uses ring_buffer_read to increment to the next item. The ring_buffer_peek will always keep the pointer to a valid item and not padding. This just hid the bug. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index a05541a..9d939e7 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -3286,19 +3286,19 @@ ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts) struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer; unsigned long flags; - again: spin_lock_irqsave(&cpu_buffer->reader_lock, flags); + again: event = rb_iter_peek(iter, ts); if (!event) goto out; + if (event->type_len == RINGBUF_TYPE_PADDING) + goto again; + rb_advance_iter(iter); out: spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); - if (event && event->type_len == RINGBUF_TYPE_PADDING) - goto again; - return event; } EXPORT_SYMBOL_GPL(ring_buffer_read); -- cgit v0.10.2 From dc892f7339af2d125478b800edb9081d6149665b Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 3 Sep 2009 15:33:41 -0400 Subject: ring-buffer: remove ring_buffer_event_discard The function ring_buffer_event_discard can be used on any item in the ring buffer, even after the item was committed. This function provides no safety nets and is very race prone. An item may be safely removed from the ring buffer before it is committed with the ring_buffer_discard_commit. Since there are currently no users of this function, and because this function is racey and error prone, this patch removes it altogether. Note, removing this function also allows the counters to ignore all discarded events (patches will follow). Signed-off-by: Steven Rostedt diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index 7fca716..e061b4e 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h @@ -75,20 +75,6 @@ ring_buffer_event_time_delta(struct ring_buffer_event *event) } /* - * ring_buffer_event_discard can discard any event in the ring buffer. - * it is up to the caller to protect against a reader from - * consuming it or a writer from wrapping and replacing it. - * - * No external protection is needed if this is called before - * the event is commited. But in that case it would be better to - * use ring_buffer_discard_commit. - * - * Note, if an event that has not been committed is discarded - * with ring_buffer_event_discard, it must still be committed. - */ -void ring_buffer_event_discard(struct ring_buffer_event *event); - -/* * ring_buffer_discard_commit will remove an event that has not * ben committed yet. If this is used, then ring_buffer_unlock_commit * must not be called on the discarded event. This function diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 9d939e7..092fe0c 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2328,31 +2328,16 @@ static inline void rb_event_discard(struct ring_buffer_event *event) } /** - * ring_buffer_event_discard - discard any event in the ring buffer - * @event: the event to discard - * - * Sometimes a event that is in the ring buffer needs to be ignored. - * This function lets the user discard an event in the ring buffer - * and then that event will not be read later. - * - * Note, it is up to the user to be careful with this, and protect - * against races. If the user discards an event that has been consumed - * it is possible that it could corrupt the ring buffer. - */ -void ring_buffer_event_discard(struct ring_buffer_event *event) -{ - rb_event_discard(event); -} -EXPORT_SYMBOL_GPL(ring_buffer_event_discard); - -/** * ring_buffer_commit_discard - discard an event that has not been committed * @buffer: the ring buffer * @event: non committed event to discard * - * This is similar to ring_buffer_event_discard but must only be - * performed on an event that has not been committed yet. The difference - * is that this will also try to free the event from the ring buffer + * Sometimes an event that is in the ring buffer needs to be ignored. + * This function lets the user discard an event in the ring buffer + * and then that event will not be read later. + * + * This function only works if it is called before the the item has been + * committed. It will try to free the event from the ring buffer * if another event has not been added behind it. * * If another event has been added behind it, it will set the event -- cgit v0.10.2 From 63d40deb2e7c64ed55943d49f078e09fc4b64b54 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 4 Sep 2009 17:03:13 +0200 Subject: perf stat: Use stddev_mean in stead of stddev When we're computing the mean by sampling the distribution, then the std dev of the mean is related to the std dev of the sample set by: stddev_mean = std_dev / sqrt(N) Which is exactly what we want. This results in the error on the mean decreasing with increasing number of samples. Also fix the scaled == -1, aka not counted case. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 9c6377f..e9424fa 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -75,7 +75,7 @@ static int null_run = 0; static int fd[MAX_NR_CPUS][MAX_COUNTERS]; static u64 event_res[MAX_COUNTERS][3]; -static u64 event_scaled[MAX_COUNTERS]; +static int event_scaled[MAX_COUNTERS]; struct stats { @@ -97,17 +97,31 @@ static double avg_stats(struct stats *stats) } /* - * stddev = sqrt(1/N (\Sum n_i^2) - avg(n)^2) + * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance + * + * (\Sum n_i^2) - ((\Sum n_i)^2)/n + * s^2 ------------------------------- + * n - 1 + * + * http://en.wikipedia.org/wiki/Stddev + * + * The std dev of the mean is related to the std dev by: + * + * s + * s_mean = ------- + * sqrt(n) + * */ static double stddev_stats(struct stats *stats) { double avg = stats->sum / run_count; + double variance = (stats->sum_sq - stats->sum*avg)/(run_count - 1); + double variance_mean = variance / run_count; - return sqrt(stats->sum_sq/run_count - avg*avg); + return sqrt(variance_mean); } struct stats event_res_stats[MAX_COUNTERS][3]; -struct stats event_scaled_stats[MAX_COUNTERS]; struct stats runtime_nsecs_stats; struct stats walltime_nsecs_stats; struct stats runtime_cycles_stats; @@ -343,11 +357,10 @@ static void abs_printout(int counter, double avg, double stddev) static void print_counter(int counter) { double avg, stddev; - int scaled; + int scaled = event_scaled[counter]; avg = avg_stats(&event_res_stats[counter][0]); stddev = stddev_stats(&event_res_stats[counter][0]); - scaled = avg_stats(&event_scaled_stats[counter]); if (scaled == -1) { fprintf(stderr, " %14s %-24s\n", -- cgit v0.10.2 From 8a02631a470d6f2ccec7bcf79c1058b0d4240bce Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 4 Sep 2009 17:26:26 +0200 Subject: perf stat: More advanced variance computation Use the more advanced single pass variance algorithm outlined on the wikipedia page. This is numerically more stable for larger sample sets. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e9424fa..32b5c00 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -79,29 +79,30 @@ static int event_scaled[MAX_COUNTERS]; struct stats { - double sum; - double sum_sq; + double n, mean, M2; }; static void update_stats(struct stats *stats, u64 val) { - double sq = val; + double delta; - stats->sum += val; - stats->sum_sq += sq * sq; + stats->n++; + delta = val - stats->mean; + stats->mean += delta / stats->n; + stats->M2 += delta*(val - stats->mean); } static double avg_stats(struct stats *stats) { - return stats->sum / run_count; + return stats->mean; } /* * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance * - * (\Sum n_i^2) - ((\Sum n_i)^2)/n - * s^2 ------------------------------- - * n - 1 + * (\Sum n_i^2) - ((\Sum n_i)^2)/n + * s^2 = ------------------------------- + * n - 1 * * http://en.wikipedia.org/wiki/Stddev * @@ -114,9 +115,8 @@ static double avg_stats(struct stats *stats) */ static double stddev_stats(struct stats *stats) { - double avg = stats->sum / run_count; - double variance = (stats->sum_sq - stats->sum*avg)/(run_count - 1); - double variance_mean = variance / run_count; + double variance = stats->M2 / (stats->n - 1); + double variance_mean = variance / stats->n; return sqrt(variance_mean); } -- cgit v0.10.2 From a1863c212b7517afc2b13e549552ac322fb44cab Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 3 Sep 2009 10:23:58 -0400 Subject: ring-buffer: do not count discarded events The latency tracers report the number of items in the trace buffer. This uses the ring buffer data to calculate this. Because discarded events are also counted, the numbers do not match the number of items that are printed. The ring buffer also adds a "padding" item to the end of each buffer page which also gets counted as a discarded item. This patch decrements the counter to the page entries on a discard. This allows us to ignore discarded entries while reading the buffer. Decrementing the counter is still safe since it can only happen while the committing flag is still set. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 092fe0c..c8d2a66 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -218,17 +218,12 @@ enum { static inline int rb_null_event(struct ring_buffer_event *event) { - return event->type_len == RINGBUF_TYPE_PADDING - && event->time_delta == 0; -} - -static inline int rb_discarded_event(struct ring_buffer_event *event) -{ - return event->type_len == RINGBUF_TYPE_PADDING && event->time_delta; + return event->type_len == RINGBUF_TYPE_PADDING && !event->time_delta; } static void rb_event_set_padding(struct ring_buffer_event *event) { + /* padding has a NULL time_delta */ event->type_len = RINGBUF_TYPE_PADDING; event->time_delta = 0; } @@ -1778,9 +1773,6 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer, event->type_len = RINGBUF_TYPE_PADDING; /* time delta must be non zero */ event->time_delta = 1; - /* Account for this as an entry */ - local_inc(&tail_page->entries); - local_inc(&cpu_buffer->entries); /* Set write to end of buffer */ length = (tail + length) - BUF_PAGE_SIZE; @@ -2269,18 +2261,23 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length) } EXPORT_SYMBOL_GPL(ring_buffer_lock_reserve); -static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer, +static void +rb_update_write_stamp(struct ring_buffer_per_cpu *cpu_buffer, struct ring_buffer_event *event) { - local_inc(&cpu_buffer->entries); - /* * The event first in the commit queue updates the * time stamp. */ if (rb_event_is_commit(cpu_buffer, event)) cpu_buffer->write_stamp += event->time_delta; +} +static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event) +{ + local_inc(&cpu_buffer->entries); + rb_update_write_stamp(cpu_buffer, event); rb_end_commit(cpu_buffer); } @@ -2327,6 +2324,46 @@ static inline void rb_event_discard(struct ring_buffer_event *event) event->time_delta = 1; } +/* + * Decrement the entries to the page that an event is on. + * The event does not even need to exist, only the pointer + * to the page it is on. This may only be called before the commit + * takes place. + */ +static inline void +rb_decrement_entry(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event) +{ + unsigned long addr = (unsigned long)event; + struct buffer_page *bpage = cpu_buffer->commit_page; + struct buffer_page *start; + + addr &= PAGE_MASK; + + /* Do the likely case first */ + if (likely(bpage->page == (void *)addr)) { + local_dec(&bpage->entries); + return; + } + + /* + * Because the commit page may be on the reader page we + * start with the next page and check the end loop there. + */ + rb_inc_page(cpu_buffer, &bpage); + start = bpage; + do { + if (bpage->page == (void *)addr) { + local_dec(&bpage->entries); + return; + } + rb_inc_page(cpu_buffer, &bpage); + } while (bpage != start); + + /* commit not part of this buffer?? */ + RB_WARN_ON(cpu_buffer, 1); +} + /** * ring_buffer_commit_discard - discard an event that has not been committed * @buffer: the ring buffer @@ -2365,14 +2402,15 @@ void ring_buffer_discard_commit(struct ring_buffer *buffer, */ RB_WARN_ON(buffer, !local_read(&cpu_buffer->committing)); + rb_decrement_entry(cpu_buffer, event); if (rb_try_to_discard(cpu_buffer, event)) goto out; /* * The commit is still visible by the reader, so we - * must increment entries. + * must still update the timestamp. */ - local_inc(&cpu_buffer->entries); + rb_update_write_stamp(cpu_buffer, event); out: rb_end_commit(cpu_buffer); @@ -2884,8 +2922,7 @@ static void rb_advance_reader(struct ring_buffer_per_cpu *cpu_buffer) event = rb_reader_event(cpu_buffer); - if (event->type_len <= RINGBUF_TYPE_DATA_TYPE_LEN_MAX - || rb_discarded_event(event)) + if (event->type_len <= RINGBUF_TYPE_DATA_TYPE_LEN_MAX) cpu_buffer->read++; rb_update_read_stamp(cpu_buffer, event); -- cgit v0.10.2 From 077c5407cd3231cf13472623995f0dfdda510d62 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 3 Sep 2009 19:53:46 -0400 Subject: ring-buffer: disable all cpu buffers when one finds a problem Currently the way RB_WARN_ON works, is to disable either the current CPU buffer or all CPU buffers, depending on whether a ring_buffer or ring_buffer_per_cpu struct was passed into the macro. Most users of the RB_WARN_ON pass in the CPU buffer, so only the one CPU buffer gets disabled but the rest are still active. This may confuse users even though a warning is sent to the console. This patch changes the macro to disable the entire buffer even if the CPU buffer is passed in. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index c8d2a66..f83a42a 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -467,14 +467,19 @@ struct ring_buffer_iter { }; /* buffer may be either ring_buffer or ring_buffer_per_cpu */ -#define RB_WARN_ON(buffer, cond) \ - ({ \ - int _____ret = unlikely(cond); \ - if (_____ret) { \ - atomic_inc(&buffer->record_disabled); \ - WARN_ON(1); \ - } \ - _____ret; \ +#define RB_WARN_ON(b, cond) \ + ({ \ + int _____ret = unlikely(cond); \ + if (_____ret) { \ + if (__same_type(*(b), struct ring_buffer_per_cpu)) { \ + struct ring_buffer_per_cpu *__b = \ + (void *)b; \ + atomic_inc(&__b->buffer->record_disabled); \ + } else \ + atomic_inc(&b->record_disabled); \ + WARN_ON(1); \ + } \ + _____ret; \ }) /* Up this if you want to test the TIME_EXTENTS and normalization */ -- cgit v0.10.2 From 8248ac052dfd1eb41819fbc0ca5c7a1667e7e70c Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 2 Sep 2009 12:27:41 -0400 Subject: tracing: print out start and stop in latency traces During development of the tracer, we would copy information from the live tracer to the max tracer with one memcpy. Since then we added a generic ring buffer and we handle the copies differently now. Unfortunately, we never copied the critical section information, and we lost the output: # => started at: kmem_cache_alloc # => ended at: kmem_cache_alloc This patch adds back the critical start and end copying as well as removes the unused "trace_idx" and "overrun" fields of the trace_array_cpu structure. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 0f08816..df2c9f7 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -407,19 +407,22 @@ static void __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) { struct trace_array_cpu *data = tr->data[cpu]; + struct trace_array_cpu *max_data = tr->data[cpu]; max_tr.cpu = cpu; max_tr.time_start = data->preempt_timestamp; - data = max_tr.data[cpu]; - data->saved_latency = tracing_max_latency; + max_data = max_tr.data[cpu]; + max_data->saved_latency = tracing_max_latency; + max_data->critical_start = data->critical_start; + max_data->critical_end = data->critical_end; memcpy(data->comm, tsk->comm, TASK_COMM_LEN); - data->pid = tsk->pid; - data->uid = task_uid(tsk); - data->nice = tsk->static_prio - 20 - MAX_RT_PRIO; - data->policy = tsk->policy; - data->rt_priority = tsk->rt_priority; + max_data->pid = tsk->pid; + max_data->uid = task_uid(tsk); + max_data->nice = tsk->static_prio - 20 - MAX_RT_PRIO; + max_data->policy = tsk->policy; + max_data->rt_priority = tsk->rt_priority; /* record this tasks comm */ tracing_record_cmdline(tsk); @@ -1501,7 +1504,7 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter) seq_puts(m, "\n# => ended at: "); seq_print_ip_sym(&iter->seq, data->critical_end, sym_flags); trace_print_seq(m, &iter->seq); - seq_puts(m, "#\n"); + seq_puts(m, "\n#\n"); } seq_puts(m, "#\n"); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index e2c06b2..f2af713 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -234,9 +234,6 @@ struct trace_array_cpu { atomic_t disabled; void *buffer_page; /* ring buffer spare */ - /* these fields get copied into max-trace: */ - unsigned long trace_idx; - unsigned long overrun; unsigned long saved_latency; unsigned long critical_start; unsigned long critical_end; -- cgit v0.10.2 From b8de7bd168fa54d059b16d3057b2f8a32cc5bdc3 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 31 Aug 2009 22:32:27 -0400 Subject: tracing: disable update max tracer while reading trace When reading the tracer from the trace file, updating the max latency may corrupt the output. This patch disables the tracing of the max latency while reading the trace file. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index df2c9f7..e521f1e 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -263,6 +263,9 @@ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK | TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME | TRACE_ITER_GRAPH_TIME; +static int trace_stop_count; +static DEFINE_SPINLOCK(tracing_start_lock); + /** * trace_wake_up - wake up tasks waiting for trace input * @@ -442,6 +445,9 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) { struct ring_buffer *buf = tr->buffer; + if (trace_stop_count) + return; + WARN_ON_ONCE(!irqs_disabled()); __raw_spin_lock(&ftrace_max_lock); @@ -469,6 +475,9 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu) { int ret; + if (trace_stop_count) + return; + WARN_ON_ONCE(!irqs_disabled()); __raw_spin_lock(&ftrace_max_lock); @@ -685,9 +694,6 @@ static void trace_init_cmdlines(void) cmdline_idx = 0; } -static int trace_stop_count; -static DEFINE_SPINLOCK(tracing_start_lock); - /** * ftrace_off_permanent - disable all ftrace code permanently * -- cgit v0.10.2 From 621968cdb2563b667d6ecb484ba91ef4c3a797b3 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 4 Sep 2009 12:02:35 -0400 Subject: tracing: disable buffers and synchronize_sched before resetting Resetting the ring buffers while traces are happening can corrupt the ring buffer and disable it (no kernel crash to worry about). The safest thing to do is disable the ring buffers, call synchronize_sched() to wait for all current writers to finish and then reset the buffer. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index e521f1e..9110329 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -658,12 +658,20 @@ void tracing_reset(struct trace_array *tr, int cpu) void tracing_reset_online_cpus(struct trace_array *tr) { + struct ring_buffer *buffer = tr->buffer; int cpu; + ring_buffer_record_disable(buffer); + + /* Make sure all commits have finished */ + synchronize_sched(); + tr->time_start = ftrace_now(tr->cpu); for_each_online_cpu(cpu) tracing_reset(tr, cpu); + + ring_buffer_record_enable(buffer); } void tracing_reset_current(int cpu) -- cgit v0.10.2 From 76f0d07376388f32698ba51b6090a26b90c1342f Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 4 Sep 2009 12:12:39 -0400 Subject: tracing: remove users of tracing_reset The function tracing_reset is deprecated for outside use of trace.c. The new function to reset the the buffers is tracing_reset_online_cpus. The reason for this is that resetting the buffers while the event trace points are active can corrupt the buffers, because they may be writing at the time of reset. The tracing_reset_online_cpus disables writes and waits for current writers to finish. This patch replaces all users of tracing_reset except for the latency tracers. Those changes require more work and will be removed in the following patches. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/kmemtrace.c b/kernel/trace/kmemtrace.c index dda53cc..81b1645 100644 --- a/kernel/trace/kmemtrace.c +++ b/kernel/trace/kmemtrace.c @@ -183,11 +183,9 @@ static void kmemtrace_stop_probes(void) static int kmem_trace_init(struct trace_array *tr) { - int cpu; kmemtrace_array = tr; - for_each_cpu(cpu, cpu_possible_mask) - tracing_reset(tr, cpu); + tracing_reset_online_cpus(tr); kmemtrace_start_probes(); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 9110329..54517a8 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -550,7 +550,6 @@ __acquires(kernel_lock) if (type->selftest && !tracing_selftest_disabled) { struct tracer *saved_tracer = current_trace; struct trace_array *tr = &global_trace; - int i; /* * Run a selftest on this tracer. @@ -559,8 +558,7 @@ __acquires(kernel_lock) * internal tracing to verify that everything is in order. * If we fail, we do not register this tracer. */ - for_each_tracing_cpu(i) - tracing_reset(tr, i); + tracing_reset_online_cpus(tr); current_trace = type; /* the test is responsible for initializing and enabling */ @@ -573,8 +571,7 @@ __acquires(kernel_lock) goto out; } /* Only reset on passing, to avoid touching corrupted buffers */ - for_each_tracing_cpu(i) - tracing_reset(tr, i); + tracing_reset_online_cpus(tr); printk(KERN_CONT "PASSED\n"); } diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c index a29ef23..8631393 100644 --- a/kernel/trace/trace_boot.c +++ b/kernel/trace/trace_boot.c @@ -41,14 +41,12 @@ void disable_boot_trace(void) static int boot_trace_init(struct trace_array *tr) { - int cpu; boot_trace = tr; if (!tr) return 0; - for_each_cpu(cpu, cpu_possible_mask) - tracing_reset(tr, cpu); + tracing_reset_online_cpus(tr); tracing_sched_switch_assign_trace(tr); return 0; diff --git a/kernel/trace/trace_power.c b/kernel/trace/trace_power.c index 8a30d98..a5d5a4f 100644 --- a/kernel/trace/trace_power.c +++ b/kernel/trace/trace_power.c @@ -144,14 +144,12 @@ static void power_trace_reset(struct trace_array *tr) static int power_trace_init(struct trace_array *tr) { - int cpu; power_trace = tr; trace_power_enabled = 1; tracing_power_register(); - for_each_cpu(cpu, cpu_possible_mask) - tracing_reset(tr, cpu); + tracing_reset_online_cpus(tr); return 0; } -- cgit v0.10.2 From b19ae3999891cad21a3995c34d313dda5df014e2 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 4 Sep 2009 10:00:09 -0700 Subject: x86, msr: change msr-reg.o to obj-y, and export its symbols Change msr-reg.o to obj-y (it will be included in virtually every kernel since it is used by the initialization code for AMD processors) and add a separate C file to export its symbols to modules, so that msr.ko can use them; on uniprocessors we bypass the helper functions in msr.o and use the accessor functions directly via inlines. Signed-off-by: H. Peter Anvin LKML-Reference: <20090904140834.GA15789@elte.hu> Cc: Borislav Petkov diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index b59c064..9e60920 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -8,7 +8,8 @@ lib-y := delay.o lib-y += thunk_$(BITS).o lib-y += usercopy_$(BITS).o getuser.o putuser.o lib-y += memcpy_$(BITS).o -lib-y += msr-reg.o + +obj-y += msr-reg.o msr-reg-export.o ifeq ($(CONFIG_X86_32),y) obj-y += atomic64_32.o diff --git a/arch/x86/lib/msr-reg-export.c b/arch/x86/lib/msr-reg-export.c new file mode 100644 index 0000000..a311cc5 --- /dev/null +++ b/arch/x86/lib/msr-reg-export.c @@ -0,0 +1,5 @@ +#include +#include + +EXPORT_SYMBOL(native_rdmsr_safe_regs); +EXPORT_SYMBOL(native_wrmsr_safe_regs); -- cgit v0.10.2 From 849abde92bd3314a4894f2b4f70b30c2accf8653 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 4 Sep 2009 18:23:38 +0200 Subject: perf stat: Clean up statistics calculations a bit more Remove some, now useless, global storage. Don't calculate the stddev when not needed. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 32b5c00..61b8282 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -74,7 +74,6 @@ static int null_run = 0; static int fd[MAX_NR_CPUS][MAX_COUNTERS]; -static u64 event_res[MAX_COUNTERS][3]; static int event_scaled[MAX_COUNTERS]; struct stats @@ -179,14 +178,12 @@ static inline int nsec_counter(int counter) */ static void read_counter(int counter) { - u64 *count, single_count[3]; + u64 count[3], single_count[3]; unsigned int cpu; size_t res, nv; int scaled; int i; - count = event_res[counter]; - count[0] = count[1] = count[2] = 0; nv = scale ? 3 : 1; @@ -318,13 +315,16 @@ static int run_perf_stat(int argc __used, const char **argv) return WEXITSTATUS(status); } -static void print_noise(double avg, double stddev) +static void print_noise(int counter, double avg) { - if (run_count > 1) - fprintf(stderr, " ( +- %7.3f%% )", 100*stddev / avg); + if (run_count == 1) + return; + + fprintf(stderr, " ( +- %7.3f%% )", + 100 * stddev_stats(&event_res_stats[counter][0]) / avg); } -static void nsec_printout(int counter, double avg, double stddev) +static void nsec_printout(int counter, double avg) { double msecs = avg / 1e6; @@ -334,10 +334,9 @@ static void nsec_printout(int counter, double avg, double stddev) fprintf(stderr, " # %10.3f CPUs ", avg / avg_stats(&walltime_nsecs_stats)); } - print_noise(avg, stddev); } -static void abs_printout(int counter, double avg, double stddev) +static void abs_printout(int counter, double avg) { fprintf(stderr, " %14.0f %-24s", avg, event_name(counter)); @@ -348,7 +347,6 @@ static void abs_printout(int counter, double avg, double stddev) fprintf(stderr, " # %10.3f M/sec", 1000.0 * avg / avg_stats(&runtime_nsecs_stats)); } - print_noise(avg, stddev); } /* @@ -356,12 +354,9 @@ static void abs_printout(int counter, double avg, double stddev) */ static void print_counter(int counter) { - double avg, stddev; + double avg = avg_stats(&event_res_stats[counter][0]); int scaled = event_scaled[counter]; - avg = avg_stats(&event_res_stats[counter][0]); - stddev = stddev_stats(&event_res_stats[counter][0]); - if (scaled == -1) { fprintf(stderr, " %14s %-24s\n", "", event_name(counter)); @@ -369,9 +364,11 @@ static void print_counter(int counter) } if (nsec_counter(counter)) - nsec_printout(counter, avg, stddev); + nsec_printout(counter, avg); else - abs_printout(counter, avg, stddev); + abs_printout(counter, avg); + + print_noise(counter, avg); if (scaled) { double avg_enabled, avg_running; -- cgit v0.10.2 From 367da1527aff2a4f789d03082f9fb191cdf332c4 Mon Sep 17 00:00:00 2001 From: Robert Schwebel Date: Fri, 4 Sep 2009 21:16:36 +0200 Subject: ASoC: fix pxa2xx-ac97.c breakage Today's linux-next fails to build with sound/arm/pxa2xx-ac97.c: In function 'pxa2xx_ac97_probe': sound/arm/pxa2xx-ac97.c:211: error: 'pxa2xx_audio_ops_t' has no member named 'codec_data' make[2]: *** [sound/arm/pxa2xx-ac97.o] Error 1 It looks like commit e2365bf313fb21b49b1e4c911033389564428d03 has introduced this; patch below. Signed-off-by: Robert Schwebel Signed-off-by: Mark Brown diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 757b480..4e34d19 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -207,7 +207,7 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) snprintf(card->longname, sizeof(card->longname), "%s (%s)", dev->dev.driver->name, card->mixername); - if (pdata && pdata->codec_data[0]) + if (pdata && pdata->codec_pdata[0]) snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata[0]); snd_card_set_dev(card, &dev->dev); ret = snd_card_register(card); -- cgit v0.10.2 From 6b58e7f146f8d79c08f62087f928e1f01747de71 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Fri, 4 Sep 2009 16:39:51 -0300 Subject: perf tools: Avoid unnecessary work in directory lookups This patch improves some (common) inefficiencies in the handling of directory lookups: - not using the d_type information returned by the kernel - constructing (absolute) paths for file operation even though directory-relative operations using the *at functions is possible There are more places to fix but this is a start. Signed-off-by: Ulrich Drepper Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Mike Galbraith LKML-Reference: <20090904193951.GB6186@ghostprotocols.net> Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 89d46c9..52219d5 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1,14 +1,12 @@ -#include "../perf.h" #include "util.h" +#include "../perf.h" #include "parse-options.h" #include "parse-events.h" #include "exec_cmd.h" #include "string.h" #include "cache.h" -extern char *strcasestr(const char *haystack, const char *needle); - int nr_counters; struct perf_counter_attr attrs[MAX_COUNTERS]; @@ -113,11 +111,9 @@ static unsigned long hw_cache_stat[C(MAX)] = { [C(BPU)] = (CACHE_READ), }; -#define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \ +#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ - if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \ - sys_dirent.d_name) && \ - (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ + if (sys_dirent.d_type == DT_DIR && \ (strcmp(sys_dirent.d_name, ".")) && \ (strcmp(sys_dirent.d_name, ".."))) @@ -136,11 +132,9 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) return 0; } -#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ +#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \ while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ - if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \ - sys_dirent.d_name, evt_dirent.d_name) && \ - (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ + if (evt_dirent.d_type == DT_DIR && \ (strcmp(evt_dirent.d_name, ".")) && \ (strcmp(evt_dirent.d_name, "..")) && \ (!tp_event_has_id(&sys_dirent, &evt_dirent))) @@ -163,9 +157,8 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) struct tracepoint_path *path = NULL; DIR *sys_dir, *evt_dir; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; - struct stat st; char id_buf[4]; - int fd; + int sys_dir_fd, fd; u64 id; char evt_path[MAXPATHLEN]; @@ -175,17 +168,23 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) sys_dir = opendir(debugfs_path); if (!sys_dir) goto cleanup; - - for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { - evt_dir = opendir(evt_path); - if (!evt_dir) - goto cleanup; - for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, - evt_path, st) { - snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", - debugfs_path, sys_dirent.d_name, + sys_dir_fd = dirfd(sys_dir); + + for_each_subsystem(sys_dir, sys_dirent, sys_next) { + int dfd = openat(sys_dir_fd, sys_dirent.d_name, + O_RDONLY|O_DIRECTORY), evt_dir_fd; + if (dfd == -1) + continue; + evt_dir = fdopendir(dfd); + if (!evt_dir) { + close(dfd); + continue; + } + evt_dir_fd = dirfd(evt_dir); + for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { + snprintf(evt_path, MAXPATHLEN, "%s/id", evt_dirent.d_name); - fd = open(evt_path, O_RDONLY); + fd = openat(evt_dir_fd, evt_path, O_RDONLY); if (fd < 0) continue; if (read(fd, id_buf, sizeof(id_buf)) < 0) { @@ -629,7 +628,7 @@ static void print_tracepoint_events(void) { DIR *sys_dir, *evt_dir; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; - struct stat st; + int sys_dir_fd; char evt_path[MAXPATHLEN]; if (valid_debugfs_mount(debugfs_path)) @@ -638,13 +637,20 @@ static void print_tracepoint_events(void) sys_dir = opendir(debugfs_path); if (!sys_dir) goto cleanup; - - for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { - evt_dir = opendir(evt_path); - if (!evt_dir) - goto cleanup; - for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, - evt_path, st) { + sys_dir_fd = dirfd(sys_dir); + + for_each_subsystem(sys_dir, sys_dirent, sys_next) { + int dfd = openat(sys_dir_fd, sys_dirent.d_name, + O_RDONLY|O_DIRECTORY), evt_dir_fd; + if (dfd == -1) + continue; + evt_dir = fdopendir(dfd); + if (!evt_dir) { + close(dfd); + continue; + } + evt_dir_fd = dirfd(evt_dir); + for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { snprintf(evt_path, MAXPATHLEN, "%s:%s", sys_dirent.d_name, evt_dirent.d_name); fprintf(stderr, " %-40s [%s]\n", evt_path, -- cgit v0.10.2 From c58b43218c1a04a0bcf338ea47406c759ac28e11 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Tue, 1 Sep 2009 13:31:38 +0800 Subject: tracing/filters: Defer pred allocation, fix memory leak The predicates of an event and their filter structure are allocated when we create an event filter for the first time. These objects must be created once but each time we come with a new filter, we overwrite such pre-existing allocation, if any. Thus, this patch checks if the filter has already been allocated before going ahead. Spotted-by: Frederic Weisbecker Signed-off-by: Li Zefan Cc: Steven Rostedt Cc: Tom Zanussi Cc: Masami Hiramatsu LKML-Reference: <4A9CB1BA.3060402@cn.fujitsu.com> Signed-off-by: Frederic Weisbecker diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index c6b2edf..93660fb 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -409,6 +409,9 @@ static int init_preds(struct ftrace_event_call *call) struct filter_pred *pred; int i; + if (call->filter) + return 0; + filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL); if (!call->filter) return -ENOMEM; @@ -447,11 +450,9 @@ static int init_subsystem_preds(struct event_subsystem *system) if (strcmp(call->system, system->name) != 0) continue; - if (!call->filter) { - err = init_preds(call); - if (err) - return err; - } + err = init_preds(call); + if (err) + return err; } return 0; -- cgit v0.10.2 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 diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index a39b3c7..355d0f1 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 v0.10.2 From 425e0f685230986511b1fdf80340e2f28b214c5d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 16 Jun 2009 14:47:30 +0800 Subject: sctp: avoid overwrite the return value of sctp_process_asconf_ack() The return value of sctp_process_asconf_ack() may be overwritten while process parameters with no error. This patch fixed the problem. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 61cc607..b7acc9c 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -3104,7 +3104,7 @@ done: } /* Process a asconf parameter that is successfully acked. */ -static int sctp_asconf_param_success(struct sctp_association *asoc, +static void sctp_asconf_param_success(struct sctp_association *asoc, sctp_addip_param_t *asconf_param) { struct sctp_af *af; @@ -3113,7 +3113,6 @@ static int sctp_asconf_param_success(struct sctp_association *asoc, union sctp_addr_param *addr_param; struct sctp_transport *transport; struct sctp_sockaddr_entry *saddr; - int retval = 0; addr_param = (union sctp_addr_param *) ((void *)asconf_param + sizeof(sctp_addip_param_t)); @@ -3136,7 +3135,7 @@ static int sctp_asconf_param_success(struct sctp_association *asoc, break; case SCTP_PARAM_DEL_IP: local_bh_disable(); - retval = sctp_del_bind_addr(bp, &addr); + sctp_del_bind_addr(bp, &addr); local_bh_enable(); list_for_each_entry(transport, &asoc->peer.transport_addr_list, transports) { @@ -3148,8 +3147,6 @@ static int sctp_asconf_param_success(struct sctp_association *asoc, default: break; } - - return retval; } /* Get the corresponding ASCONF response error code from the ASCONF_ACK chunk @@ -3266,7 +3263,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, switch (err_code) { case SCTP_ERROR_NO_ERROR: - retval = sctp_asconf_param_success(asoc, asconf_param); + sctp_asconf_param_success(asoc, asconf_param); break; case SCTP_ERROR_RSRC_LOW: -- cgit v0.10.2 From 44e65c1ef1e771b32c82546ebfba910137aa8871 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 16 Jun 2009 14:48:24 +0800 Subject: sctp: check the unrecognized ASCONF parameter before access it This patch fix to check the unrecognized ASCONF parameter before access it. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index b7acc9c..3d867ce 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2861,6 +2861,11 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, addr_param = (union sctp_addr_param *) ((void *)asconf_param + sizeof(sctp_addip_param_t)); + if (asconf_param->param_hdr.type != SCTP_PARAM_ADD_IP && + asconf_param->param_hdr.type != SCTP_PARAM_DEL_IP && + asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY) + return SCTP_ERROR_UNKNOWN_PARAM; + switch (addr_param->v4.param_hdr.type) { case SCTP_PARAM_IPV6_ADDRESS: if (!asoc->peer.ipv6_address) @@ -2958,9 +2963,6 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, sctp_assoc_set_primary(asoc, peer); break; - default: - return SCTP_ERROR_UNKNOWN_PARAM; - break; } return SCTP_ERROR_NO_ERROR; -- cgit v0.10.2 From 3cd9749c0b758223a71e059fa44c2234547d9ee0 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 16 Jun 2009 10:07:23 +0800 Subject: sctp: update the route for non-active transports after addresses are added Update the route and saddr entries for the non-active transports as some of the added addresses can be used as better source addresses, or may be there is a better route. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 3d867ce..9d881a6 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -3134,6 +3134,14 @@ static void sctp_asconf_param_success(struct sctp_association *asoc, saddr->state = SCTP_ADDR_SRC; } local_bh_enable(); + list_for_each_entry(transport, &asoc->peer.transport_addr_list, + transports) { + if (transport->state == SCTP_ACTIVE) + continue; + dst_release(transport->dst); + sctp_transport_route(transport, NULL, + sctp_sk(asoc->base.sk)); + } break; case SCTP_PARAM_DEL_IP: local_bh_disable(); -- cgit v0.10.2 From 40187886bc31aee9c5c6f08f46cde4ab618e9736 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 23 Jun 2009 11:28:05 -0400 Subject: sctp: release cached route when the transport goes down. When the sctp transport is marked down, we can release the cached route and force a new lookup when attempting to use this transport for anything. This way, if a better route or source address is available, we'll try to use it. Signed-off-by: Vlad Yasevich diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 525864b..215b569 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -810,11 +810,16 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, break; case SCTP_TRANSPORT_DOWN: - /* if the transort was never confirmed, do not transition it - * to inactive state. + /* If the transport was never confirmed, do not transition it + * to inactive state. Also, release the cached route since + * there may be a better route next time. */ if (transport->state != SCTP_UNCONFIRMED) transport->state = SCTP_INACTIVE; + else { + dst_release(transport->dst); + transport->dst = NULL; + } spc_state = SCTP_ADDR_UNREACHABLE; break; -- cgit v0.10.2 From b4e8c6a7e6caa9c80edcbfb78fc50962b792d5f0 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Thu, 30 Jul 2009 09:38:43 +0300 Subject: sctp: remove unused union (sctp_cmsg_data_t) definition This patch removes an unused union definition (sctp_cmsg_data_t) from include/net/sctp/user.h. Signed-off-by: Rami Rosen Signed-off-by: Vlad Yasevich diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 1580c04..be2334a 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -210,12 +210,6 @@ enum sctp_sinfo_flags { }; -typedef union { - __u8 raw; - struct sctp_initmsg init; - struct sctp_sndrcvinfo sndrcv; -} sctp_cmsg_data_t; - /* These are cmsg_types. */ typedef enum sctp_cmsg_type { SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ -- cgit v0.10.2 From af87b823ca2b05257192e8d48dc686db6173d7b2 Mon Sep 17 00:00:00 2001 From: Doug Graham Date: Wed, 29 Jul 2009 12:05:57 -0400 Subject: sctp: Fix piggybacked ACKs This patch corrects the conditions under which a SACK will be piggybacked on a DATA packet. The previous condition was incorrect due to a misinterpretation of RFC 4960 and/or RFC 2960. Specifically, the following paragraph from section 6.2 had not been implemented correctly: Before an endpoint transmits a DATA chunk, if any received DATA chunks have not been acknowledged (e.g., due to delayed ack), the sender should create a SACK and bundle it with the outbound DATA chunk, as long as the size of the final SCTP packet does not exceed the current MTU. See Section 6.2. When about to send a DATA chunk, the code now checks to see if the SACK timer is running. If it is, we know we have a SACK to send to the peer, so we append the SACK (assuming available space in the packet) and turn off the timer. For a simple request-response scenario, this will result in the SACK being bundled with the response, meaning the the SACK is received quickly by the client, and also meaning that no separate SACK packet needs to be sent by the server to acknowledge the request. Prior to this patch, a separate SACK packet would have been sent by the server SCTP only after its delayed-ACK timer had expired (usually 200ms). This is wasteful of bandwidth, and can also have a major negative impact on performance due the interaction of delayed ACKs with the Nagle algorithm. Signed-off-by: Doug Graham Signed-off-by: Vlad Yasevich diff --git a/net/sctp/output.c b/net/sctp/output.c index b94c211..94c110d 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -234,18 +234,19 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt, if (sctp_chunk_is_data(chunk) && !pkt->has_sack && !pkt->has_cookie_echo) { struct sctp_association *asoc; + struct timer_list *timer; asoc = pkt->transport->asoc; + timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK]; - if (asoc->a_rwnd > asoc->rwnd) { + /* If the SACK timer is running, we have a pending SACK */ + if (timer_pending(timer)) { struct sctp_chunk *sack; asoc->a_rwnd = asoc->rwnd; sack = sctp_make_sack(asoc); if (sack) { - struct timer_list *timer; retval = sctp_packet_append_chunk(pkt, sack); asoc->peer.sack_needed = 0; - timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK]; - if (timer_pending(timer) && del_timer(timer)) + if (del_timer(timer)) sctp_association_put(asoc); } } -- cgit v0.10.2 From bec9640bb0d451813b1bb1f2cc13a5bfb17c3e48 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 30 Jul 2009 18:08:28 -0400 Subject: sctp: Disallow new connection on a closing socket If a socket has a lot of association that are in the process of of being closed/aborted, it is possible for a remote to establish new associations during the time period that the old ones are shutting down. If this was a result of a close() call, there will be no socket and will cause a memory leak. We'll prevent this by setting the socket state to CLOSING and disallow new associations when in this state. Signed-off-by: Vlad Yasevich diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 8bc25f7..af8c150 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -231,7 +231,7 @@ typedef enum { SCTP_SS_LISTENING = TCP_LISTEN, SCTP_SS_ESTABLISHING = TCP_SYN_SENT, SCTP_SS_ESTABLISHED = TCP_ESTABLISHED, - SCTP_SS_DISCONNECTING = TCP_CLOSING, + SCTP_SS_CLOSING = TCP_CLOSING, } sctp_sock_state_t; /* These functions map various type to printable names. */ diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 7288192..50225dd 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -334,6 +334,15 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t))) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* If the INIT is coming toward a closing socket, we'll send back + * and ABORT. Essentially, this catches the race of INIT being + * backloged to the socket at the same time as the user isses close(). + * Since the socket and all its associations are going away, we + * can treat this OOTB + */ + if (sctp_sstate(ep->base.sk, CLOSING)) + return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); + /* Verify the INIT chunk before processing it. */ err_chunk = NULL; if (!sctp_verify_init(asoc, chunk->chunk_hdr->type, diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 971890d..a7e544e 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1361,6 +1361,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) sctp_lock_sock(sk); sk->sk_shutdown = SHUTDOWN_MASK; + sk->sk_state = SCTP_SS_CLOSING; ep = sctp_sk(sk)->ep; -- cgit v0.10.2 From 3e62abf92f34d75fe22352d8d102e3cd2755804d Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:20:56 -0400 Subject: sctp: Fix data segmentation with small frag_size Since an application may specify the maximum SCTP fragment size that all data should be fragmented to, we need to fix how we do segmentation. Right now, if a user specifies a small fragment size, the segment size can go negative in the presence of AUTH or COOKIE_ECHO bundling. What we need to do is track the largest possbile DATA chunk that can fit into the mtu. Then if the fragment size specified is bigger then this maximum length, we'll shrink it down. Otherwise, we just use the smaller segment size without changing it further. Signed-off-by: Vlad Yasevich diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 1748ef9..9292294 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -158,6 +158,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, { int max, whole, i, offset, over, err; int len, first_len; + int max_data; struct sctp_chunk *chunk; struct sctp_datamsg *msg; struct list_head *pos, *temp; @@ -179,8 +180,14 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, __func__, msg, msg->expires_at, jiffies); } - max = asoc->frag_point; + /* This is the biggest possible DATA chunk that can fit into + * the packet + */ + max_data = asoc->pathmtu - + sctp_sk(asoc->base.sk)->pf->af->net_header_len - + sizeof(struct sctphdr) - sizeof(struct sctp_data_chunk); + max = asoc->frag_point; /* If the the peer requested that we authenticate DATA chunks * we need to accound for bundling of the AUTH chunks along with * DATA. @@ -189,23 +196,30 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc); if (hmac_desc) - max -= WORD_ROUND(sizeof(sctp_auth_chunk_t) + + max_data -= WORD_ROUND(sizeof(sctp_auth_chunk_t) + hmac_desc->hmac_len); } + /* Now, check if we need to reduce our max */ + if (max > max_data) + max = max_data; + whole = 0; first_len = max; /* Encourage Cookie-ECHO bundling. */ if (asoc->state < SCTP_STATE_COOKIE_ECHOED) { - whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN); + max_data -= SCTP_ARBITRARY_COOKIE_ECHO_LEN; - /* Account for the DATA to be bundled with the COOKIE-ECHO. */ - if (whole) { - first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN; - msg_len -= first_len; - whole = 1; - } + /* This is the biggesr first_len we can have */ + if (first_len > max_data) + first_len = max_data; + } + + /* Account for a different sized first fragment */ + if (msg_len >= first_len) { + msg_len -= first_len; + whole = 1; } /* How many full sized? How many bytes leftover? */ -- cgit v0.10.2 From e83963b769a2c38b436f5dcf82309f5cbc2f6012 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 7 Aug 2009 10:43:07 -0400 Subject: sctp: Generate SACKs when actually sending outbound DATA We are now trying to bundle SACKs when we have outbound DATA to send. However, there are situations where this outbound DATA will not be sent (due to congestion or available window). In such cases it's ok to wait for the timer to expire. This patch refactors the sending code so that betfore attempting to bundle the SACK we check to see if the DATA will actually be transmitted. Based on eirlier works for Doug Graham and Wei Youngjun . Signed-off-by: Vlad Yasevich diff --git a/net/sctp/output.c b/net/sctp/output.c index 94c110d..e25e2e2 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -61,8 +61,13 @@ #include /* Forward declarations for private helpers. */ -static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, +static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, struct sctp_chunk *chunk); +static void sctp_packet_append_data(struct sctp_packet *packet, + struct sctp_chunk *chunk); +static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet, + struct sctp_chunk *chunk, + u16 chunk_len); /* Config a packet. * This appears to be a followup set of initializations. @@ -262,13 +267,20 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, { sctp_xmit_t retval = SCTP_XMIT_OK; __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); - size_t psize; - size_t pmtu; - int too_big; SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet, chunk); + /* Data chunks are special. Before seeing what else we can + * bundle into this packet, check to see if we are allowed to + * send this DATA. + */ + if (sctp_chunk_is_data(chunk)) { + retval = sctp_packet_can_append_data(packet, chunk); + if (retval != SCTP_XMIT_OK) + goto finish; + } + /* Try to bundle AUTH chunk */ retval = sctp_packet_bundle_auth(packet, chunk); if (retval != SCTP_XMIT_OK) @@ -279,51 +291,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, if (retval != SCTP_XMIT_OK) goto finish; - psize = packet->size; - pmtu = ((packet->transport->asoc) ? - (packet->transport->asoc->pathmtu) : - (packet->transport->pathmtu)); - - too_big = (psize + chunk_len > pmtu); - - /* Decide if we need to fragment or resubmit later. */ - if (too_big) { - /* It's OK to fragmet at IP level if any one of the following - * is true: - * 1. The packet is empty (meaning this chunk is greater - * the MTU) - * 2. The chunk we are adding is a control chunk - * 3. The packet doesn't have any data in it yet and data - * requires authentication. - */ - if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) || - (!packet->has_data && chunk->auth)) { - /* We no longer do re-fragmentation. - * Just fragment at the IP layer, if we - * actually hit this condition - */ - packet->ipfragok = 1; - goto append; - - } else { - retval = SCTP_XMIT_PMTU_FULL; - goto finish; - } - } - -append: - /* We believe that this chunk is OK to add to the packet (as - * long as we have the cwnd for it). - */ + /* Check to see if this chunk will fit into the packet */ + retval = sctp_packet_will_fit(packet, chunk, chunk_len); + if (retval != SCTP_XMIT_OK) + goto finish; - /* DATA is a special case since we must examine both rwnd and cwnd - * before we send DATA. - */ + /* We believe that this chunk is OK to add to the packet */ switch (chunk->chunk_hdr->type) { case SCTP_CID_DATA: - retval = sctp_packet_append_data(packet, chunk); - if (SCTP_XMIT_OK != retval) - goto finish; + /* Account for the data being in the packet */ + sctp_packet_append_data(packet, chunk); /* Disallow SACK bundling after DATA. */ packet->has_sack = 1; /* Disallow AUTH bundling after DATA */ @@ -633,16 +610,15 @@ nomem: * 2nd Level Abstractions ********************************************************************/ -/* This private function handles the specifics of appending DATA chunks. */ -static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, +/* This private function check to see if a chunk can be added */ +static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, struct sctp_chunk *chunk) { sctp_xmit_t retval = SCTP_XMIT_OK; - size_t datasize, rwnd, inflight; + size_t datasize, rwnd, inflight, flight_size; struct sctp_transport *transport = packet->transport; __u32 max_burst_bytes; struct sctp_association *asoc = transport->asoc; - struct sctp_sock *sp = sctp_sk(asoc->base.sk); struct sctp_outq *q = &asoc->outqueue; /* RFC 2960 6.1 Transmission of DATA Chunks @@ -659,7 +635,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, */ rwnd = asoc->peer.rwnd; - inflight = asoc->outqueue.outstanding_bytes; + inflight = q->outstanding_bytes; + flight_size = transport->flight_size; datasize = sctp_data_size(chunk); @@ -682,8 +659,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, * cwnd = flightsize + Max.Burst * MTU */ max_burst_bytes = asoc->max_burst * asoc->pathmtu; - if ((transport->flight_size + max_burst_bytes) < transport->cwnd) { - transport->cwnd = transport->flight_size + max_burst_bytes; + if ((flight_size + max_burst_bytes) < transport->cwnd) { + transport->cwnd = flight_size + max_burst_bytes; SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " "transport: %p, cwnd: %d, " "ssthresh: %d, flight_size: %d, " @@ -708,7 +685,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, * ignore the value of cwnd and SHOULD NOT delay retransmission. */ if (chunk->fast_retransmit != SCTP_NEED_FRTX) - if (transport->flight_size >= transport->cwnd) { + if (flight_size >= transport->cwnd) { retval = SCTP_XMIT_RWND_FULL; goto finish; } @@ -718,8 +695,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, * if any previously transmitted data on the connection remains * unacknowledged. */ - if (!sp->nodelay && sctp_packet_empty(packet) && - q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) { + if (!sctp_sk(asoc->base.sk)->nodelay && sctp_packet_empty(packet) && + inflight && sctp_state(asoc, ESTABLISHED)) { unsigned len = datasize + q->out_qlen; /* Check whether this chunk and all the rest of pending @@ -732,6 +709,19 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, } } +finish: + return retval; +} + +/* This private function does management things when adding DATA chunk */ +static void sctp_packet_append_data(struct sctp_packet *packet, + struct sctp_chunk *chunk) +{ + struct sctp_transport *transport = packet->transport; + size_t datasize = sctp_data_size(chunk); + struct sctp_association *asoc = transport->asoc; + u32 rwnd = asoc->peer.rwnd; + /* Keep track of how many bytes are in flight over this transport. */ transport->flight_size += datasize; @@ -754,7 +744,45 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, /* Has been accepted for transmission. */ if (!asoc->peer.prsctp_capable) chunk->msg->can_abandon = 0; +} + +static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet, + struct sctp_chunk *chunk, + u16 chunk_len) +{ + size_t psize; + size_t pmtu; + int too_big; + sctp_xmit_t retval = SCTP_XMIT_OK; + + psize = packet->size; + pmtu = ((packet->transport->asoc) ? + (packet->transport->asoc->pathmtu) : + (packet->transport->pathmtu)); + + too_big = (psize + chunk_len > pmtu); + + /* Decide if we need to fragment or resubmit later. */ + if (too_big) { + /* It's OK to fragmet at IP level if any one of the following + * is true: + * 1. The packet is empty (meaning this chunk is greater + * the MTU) + * 2. The chunk we are adding is a control chunk + * 3. The packet doesn't have any data in it yet and data + * requires authentication. + */ + if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) || + (!packet->has_data && chunk->auth)) { + /* We no longer do re-fragmentation. + * Just fragment at the IP layer, if we + * actually hit this condition + */ + packet->ipfragok = 1; + } else { + retval = SCTP_XMIT_PMTU_FULL; + } + } -finish: return retval; } -- cgit v0.10.2 From 5d7ff261ef497c62f54c39effc259910a28b313d Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 7 Aug 2009 13:23:28 -0400 Subject: sctp: Try to encourage SACK bundling with DATA. If the association has a SACK timer pending and now DATA queued to be send, we'll try to bundle the SACK with the next application send. As such, try encourage bundling by accounting for SACK in the size of the first chunk fragment. Signed-off-by: Vlad Yasevich diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 9292294..7acaf15 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -207,14 +207,25 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, whole = 0; first_len = max; + /* Check to see if we have a pending SACK and try to let it be bundled + * with this message. Do this if we don't have any data queued already. + * To check that, look at out_qlen and retransmit list. + * NOTE: we will not reduce to account for SACK, if the message would + * not have been fragmented. + */ + if (timer_pending(&asoc->timers[SCTP_EVENT_TIMEOUT_SACK]) && + asoc->outqueue.out_qlen == 0 && + list_empty(&asoc->outqueue.retransmit) && + msg_len > max) + max_data -= WORD_ROUND(sizeof(sctp_sack_chunk_t)); + /* Encourage Cookie-ECHO bundling. */ - if (asoc->state < SCTP_STATE_COOKIE_ECHOED) { + if (asoc->state < SCTP_STATE_COOKIE_ECHOED) max_data -= SCTP_ARBITRARY_COOKIE_ECHO_LEN; - /* This is the biggesr first_len we can have */ - if (first_len > max_data) - first_len = max_data; - } + /* Now that we adjusted completely, reset first_len */ + if (first_len > max_data) + first_len = max_data; /* Account for a different sized first fragment */ if (msg_len >= first_len) { -- cgit v0.10.2 From 9c5c62be2f794c7cee533d856f9f34c3cf21ff1b Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 10 Aug 2009 13:51:03 -0400 Subject: sctp: Send user messages to the lower layer as one Currenlty, sctp breaks up user messages into fragments and sends each fragment to the lower layer by itself. This means that for each fragment we go all the way down the stack and back up. This also discourages bundling of multiple fragments when they can fit into a sigle packet (ex: due to user setting a low fragmentation threashold). We introduce a new command SCTP_CMD_SND_MSG and hand the whole message down state machine. The state machine and the side-effect parser will cork the queue, add all chunks from the message to the queue, and then un-cork the queue thus causing the chunks to get transmitted. Signed-off-by: Vlad Yasevich diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index 3b96680..8be5135 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -106,6 +106,7 @@ typedef enum { SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */ SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */ SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */ + SCTP_CMD_SEND_MSG, /* Send the whole use message */ SCTP_CMD_LAST } sctp_verb_t; @@ -139,6 +140,7 @@ typedef union { struct sctp_ulpevent *ulpevent; struct sctp_packet *packet; sctp_sackhdr_t *sackh; + struct sctp_datamsg *msg; } sctp_arg_t; /* We are simulating ML type constructors here. @@ -188,6 +190,7 @@ SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init) SCTP_ARG_CONSTRUCTOR(ULPEVENT, struct sctp_ulpevent *, ulpevent) SCTP_ARG_CONSTRUCTOR(PACKET, struct sctp_packet *, packet) SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh) +SCTP_ARG_CONSTRUCTOR(DATAMSG, struct sctp_datamsg *, msg) typedef struct { sctp_arg_t obj; diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index edfcacf..97024fa 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -643,6 +643,7 @@ struct sctp_datamsg { struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *, struct sctp_sndrcvinfo *, struct msghdr *, int len); +void sctp_datamsg_free(struct sctp_datamsg *); void sctp_datamsg_put(struct sctp_datamsg *); void sctp_chunk_fail(struct sctp_chunk *, int error); int sctp_chunk_abandoned(struct sctp_chunk *); diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 7acaf15..645577d 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -73,6 +73,19 @@ SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(gfp_t gfp) return msg; } +void sctp_datamsg_free(struct sctp_datamsg *msg) +{ + struct sctp_chunk *chunk; + + /* This doesn't have to be a _safe vairant because + * sctp_chunk_free() only drops the refs. + */ + list_for_each_entry(chunk, &msg->chunks, frag_list) + sctp_chunk_free(chunk); + + sctp_datamsg_put(msg); +} + /* Final destructruction of datamsg memory. */ static void sctp_datamsg_destroy(struct sctp_datamsg *msg) { diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 86426aa..238adf7 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -931,6 +931,27 @@ static void sctp_cmd_t1_timer_update(struct sctp_association *asoc, } +/* Send the whole message, chunk by chunk, to the outqueue. + * This way the whole message is queued up and bundling if + * encouraged for small fragments. + */ +static int sctp_cmd_send_msg(struct sctp_association *asoc, + struct sctp_datamsg *msg) +{ + struct sctp_chunk *chunk; + int error = 0; + + list_for_each_entry(chunk, &msg->chunks, frag_list) { + error = sctp_outq_tail(&asoc->outqueue, chunk); + if (error) + break; + } + + return error; +} + + + /* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real * functionality there. @@ -1575,7 +1596,13 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, case SCTP_CMD_UPDATE_INITTAG: asoc->peer.i.init_tag = cmd->obj.u32; break; - + case SCTP_CMD_SEND_MSG: + if (!asoc->outqueue.cork) { + sctp_outq_cork(&asoc->outqueue); + local_cork = 1; + } + error = sctp_cmd_send_msg(asoc, cmd->obj.msg); + break; default: printk(KERN_WARNING "Impossible command: %u, %p\n", cmd->verb, cmd->obj.ptr); diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 50225dd..9109269 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -4555,9 +4555,9 @@ sctp_disposition_t sctp_sf_do_prm_send(const struct sctp_endpoint *ep, void *arg, sctp_cmd_seq_t *commands) { - struct sctp_chunk *chunk = arg; + struct sctp_datamsg *msg = arg; - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk)); + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_MSG, SCTP_DATAMSG(msg)); return SCTP_DISPOSITION_CONSUME; } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index a7e544e..95a5623 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1814,20 +1814,22 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, sctp_set_owner_w(chunk); chunk->transport = chunk_tp; - - /* Send it to the lower layers. Note: all chunks - * must either fail or succeed. The lower layer - * works that way today. Keep it that way or this - * breaks. - */ - err = sctp_primitive_SEND(asoc, chunk); - /* Did the lower layer accept the chunk? */ - if (err) - sctp_chunk_free(chunk); - SCTP_DEBUG_PRINTK("We sent primitively.\n"); } - sctp_datamsg_put(datamsg); + /* Send it to the lower layers. Note: all chunks + * must either fail or succeed. The lower layer + * works that way today. Keep it that way or this + * breaks. + */ + err = sctp_primitive_SEND(asoc, datamsg); + /* Did the lower layer accept the chunk? */ + if (err) + sctp_datamsg_free(datamsg); + else + sctp_datamsg_put(datamsg); + + SCTP_DEBUG_PRINTK("We sent primitively.\n"); + if (err) goto out_free; else -- cgit v0.10.2 From a2f36eec5647548fa94fb68e2843b00fb9c0d46b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 22 Aug 2009 11:24:00 +0800 Subject: sctp: drop SHUTDOWN chunk if the TSN is less than the CTSN If Cumulative TSN Ack field of SHUTDOWN chunk is less than the Cumulative TSN Ack Point then drop the SHUTDOWN chunk. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 9109269..73bdeb2 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -2570,6 +2570,12 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep, chunk->subh.shutdown_hdr = sdh; ctsn = ntohl(sdh->cum_tsn_ack); + if (TSN_lt(ctsn, asoc->ctsn_ack_point)) { + SCTP_DEBUG_PRINTK("ctsn %x\n", ctsn); + SCTP_DEBUG_PRINTK("ctsn_ack_point %x\n", asoc->ctsn_ack_point); + return SCTP_DISPOSITION_DISCARD; + } + /* If Cumulative TSN Ack beyond the max tsn currently * send, terminating the association and respond to the * sender with an ABORT. @@ -2633,6 +2639,7 @@ sctp_disposition_t sctp_sf_do_9_2_shut_ctsn(const struct sctp_endpoint *ep, { struct sctp_chunk *chunk = arg; sctp_shutdownhdr_t *sdh; + __u32 ctsn; if (!sctp_vtag_verify(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -2644,12 +2651,19 @@ sctp_disposition_t sctp_sf_do_9_2_shut_ctsn(const struct sctp_endpoint *ep, commands); sdh = (sctp_shutdownhdr_t *)chunk->skb->data; + ctsn = ntohl(sdh->cum_tsn_ack); + + if (TSN_lt(ctsn, asoc->ctsn_ack_point)) { + SCTP_DEBUG_PRINTK("ctsn %x\n", ctsn); + SCTP_DEBUG_PRINTK("ctsn_ack_point %x\n", asoc->ctsn_ack_point); + return SCTP_DISPOSITION_DISCARD; + } /* If Cumulative TSN Ack beyond the max tsn currently * send, terminating the association and respond to the * sender with an ABORT. */ - if (!TSN_lt(ntohl(sdh->cum_tsn_ack), asoc->next_tsn)) + if (!TSN_lt(ctsn, asoc->next_tsn)) return sctp_sf_violation_ctsn(ep, asoc, type, arg, commands); /* verify, by checking the Cumulative TSN Ack field of the -- cgit v0.10.2 From dadb50cc1ada2906594df83d991f0bc388039bb6 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 22 Aug 2009 11:27:37 +0800 Subject: sctp: fix check the chunk length of received HEARTBEAT-ACK chunk The receiver of the HEARTBEAT should respond with a HEARTBEAT ACK that contains the Heartbeat Information field copied from the received HEARTBEAT chunk. So the received HEARTBEAT-ACK chunk must have a length of: sizeof(sctp_chunkhdr_t) + sizeof(sctp_sender_hb_info_t) A badly formatted HB-ACK chunk, it is possible that we may access invalid memory. We should really make sure that the chunk format is what we expect, before attempting to touch the data. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 73bdeb2..7fb08a6 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1115,7 +1115,8 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, return sctp_sf_pdiscard(ep, asoc, type, arg, commands); /* Make sure that the HEARTBEAT-ACK chunk has a valid length. */ - if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t))) + if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t) + + sizeof(sctp_sender_hb_info_t))) return sctp_sf_violation_chunklen(ep, asoc, type, arg, commands); -- cgit v0.10.2 From d71a09ed555e52299b5d3ad8945bdf84f65423a6 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 23 Aug 2009 23:11:36 +0400 Subject: sctp: use proc_create() create_proc_entry() is deprecated (not formally, though). Signed-off-by: Alexey Dobriyan Signed-off-by: Vlad Yasevich diff --git a/net/sctp/proc.c b/net/sctp/proc.c index f268910..d093cbf 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -512,10 +512,8 @@ int __init sctp_remaddr_proc_init(void) { struct proc_dir_entry *p; - p = create_proc_entry("remaddr", S_IRUGO, proc_net_sctp); + p = proc_create("remaddr", S_IRUGO, proc_net_sctp, &sctp_remaddr_seq_fops); if (!p) return -ENOMEM; - p->proc_fops = &sctp_remaddr_seq_fops; - return 0; } -- cgit v0.10.2 From b9f8478682445c2a3e0b87718a0563ef543ad94e Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 26 Aug 2009 09:36:25 -0400 Subject: sctp: Fix error count increments that were results of HEARTBEATS SCTP RFC 4960 states that unacknowledged HEARTBEATS count as errors agains a given transport or endpoint. As such, we should increment the error counts for only for unacknowledged HB, otherwise we detect failure too soon. This goes for both the overall error count and the path error count. Now, there is a difference in how the detection is done between the two. The path error detection is done after the increment, so to detect it properly, we actually need to exceed the path threshold. The overall error detection is done _BEFORE_ the increment. Thus to detect the failure, it's enough for the error count to match the threshold. This is why all the state functions use '>=' to detect failure, while path detection uses '>'. Thanks goes to Chunbo Luo who first proposed patches to fix this issue and made me re-read the spec and the code to figure out how this cruft really works. Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 238adf7..694f749 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -440,14 +440,26 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc, /* The check for association's overall error counter exceeding the * threshold is done in the state function. */ - /* When probing UNCONFIRMED addresses, the association overall - * error count is NOT incremented + /* We are here due to a timer expiration. If the timer was + * not a HEARTBEAT, then normal error tracking is done. + * If the timer was a heartbeat, we only increment error counts + * when we already have an outstanding HEARTBEAT that has not + * been acknowledged. + * Additionaly, some tranport states inhibit error increments. */ - if (transport->state != SCTP_UNCONFIRMED) + if (!is_hb) { asoc->overall_error_count++; + if (transport->state != SCTP_INACTIVE) + transport->error_count++; + } else if (transport->hb_sent) { + if (transport->state != SCTP_UNCONFIRMED) + asoc->overall_error_count++; + if (transport->state != SCTP_INACTIVE) + transport->error_count++; + } if (transport->state != SCTP_INACTIVE && - (transport->error_count++ >= transport->pathmaxrxt)) { + (transport->error_count > transport->pathmaxrxt)) { SCTP_DEBUG_PRINTK_IPADDR("transport_strike:association %p", " transport IP: port:%d failed.\n", asoc, diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 7fb08a6..45b8bca 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -971,7 +971,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep, { struct sctp_transport *transport = (struct sctp_transport *) arg; - if (asoc->overall_error_count > asoc->max_retrans) { + if (asoc->overall_error_count >= asoc->max_retrans) { sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ETIMEDOUT)); /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ -- cgit v0.10.2 From 33ce828131ca6655b48bd2070dadd80f816dfe0d Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:20:58 -0400 Subject: sctp: Clear fast_recovery on the transport when T3 timer expires. If T3 timer expires, we are retransmitting data due to timeout any any fast recovery is null and void. We can clear the fast recovery flag. Signed-off-by: Vlad Yasevich diff --git a/net/sctp/transport.c b/net/sctp/transport.c index e5dde45..c256e48 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -503,6 +503,9 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, transport->ssthresh = max(transport->cwnd/2, 4*transport->asoc->pathmtu); transport->cwnd = transport->asoc->pathmtu; + + /* T3-rtx also clears fast recovery on the transport */ + transport->fast_recovery = 0; break; case SCTP_LOWER_CWND_FAST_RTX: -- cgit v0.10.2 From 4d3c46e6833208428d366630aa708f6876e61fc1 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:20:59 -0400 Subject: sctp: drop a_rwnd to 0 when receive buffer overflows. SCTP has a problem that when small chunks are used, it is possible to exhaust the receiver buffer without fully closing receive window. This happens due to all overhead that we have account for with small messages. To fix this, when receive buffer is exceeded, we'll drop the window to 0 and save the 'drop' portion. When application starts reading data and freeing up recevie buffer space, we'll wait until we've reached the 'drop' window and then add back this 'drop' one mtu at a time. This worked well in testing and under stress produced rather even recovery. Signed-off-by: Vlad Yasevich diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 97024fa..b1bd268 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1739,6 +1739,12 @@ struct sctp_association { */ __u32 rwnd_over; + /* Keeps treack of rwnd pressure. This happens when we have + * a window, but not recevie buffer (i.e small packets). This one + * is releases slowly (1 PMTU at a time ). + */ + __u32 rwnd_press; + /* This is the sndbuf size in use for the association. * This corresponds to the sndbuf size for the association, * as specified in the sk->sndbuf. diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 215b569..39c3821 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -202,6 +202,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->a_rwnd = asoc->rwnd; asoc->rwnd_over = 0; + asoc->rwnd_press = 0; /* Use my own max window until I learn something better. */ asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; @@ -1374,6 +1375,17 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len) asoc->rwnd += len; } + /* If we had window pressure, start recovering it + * once our rwnd had reached the accumulated pressure + * threshold. The idea is to recover slowly, but up + * to the initial advertised window. + */ + if (asoc->rwnd_press && asoc->rwnd >= asoc->rwnd_press) { + int change = min(asoc->pathmtu, asoc->rwnd_press); + asoc->rwnd += change; + asoc->rwnd_press -= change; + } + SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) " "- %u\n", __func__, asoc, len, asoc->rwnd, asoc->rwnd_over, asoc->a_rwnd); @@ -1406,17 +1418,38 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len) /* Decrease asoc's rwnd by len. */ void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len) { + int rx_count; + int over = 0; + SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return); + + if (asoc->ep->rcvbuf_policy) + rx_count = atomic_read(&asoc->rmem_alloc); + else + rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc); + + /* If we've reached or overflowed our receive buffer, announce + * a 0 rwnd if rwnd would still be positive. Store the + * the pottential pressure overflow so that the window can be restored + * back to original value. + */ + if (rx_count >= asoc->base.sk->sk_rcvbuf) + over = 1; + if (asoc->rwnd >= len) { asoc->rwnd -= len; + if (over) { + asoc->rwnd_press = asoc->rwnd; + asoc->rwnd = 0; + } } else { asoc->rwnd_over = len - asoc->rwnd; asoc->rwnd = 0; } - SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n", + SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u, %u)\n", __func__, asoc, len, asoc->rwnd, - asoc->rwnd_over); + asoc->rwnd_over, asoc->rwnd_press); } /* Build the bind address list for the association based on info from the -- cgit v0.10.2 From d4d6fb5787a6ef6e1dab731d617ebda6be73d561 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:20:59 -0400 Subject: sctp: Try not to change a_rwnd when faking a SACK from SHUTDOWN. We currently set a_rwnd to 0 when faking a SACK from SHUTDOWN. This results in an hung association if the remote only uses SHUTDOWNs (which it's allowed to do) to acknowlege DATA when closing. The reason for that is that we simply honor the a_rwnd from the sack, but since we faked it to be 0, we enter 0-window probing. The fix is to use the peers old rwnd and add our flight size to it. Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 694f749..8674d49 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1533,7 +1533,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, case SCTP_CMD_PROCESS_CTSN: /* Dummy up a SACK for processing. */ sackh.cum_tsn_ack = cmd->obj.be32; - sackh.a_rwnd = 0; + sackh.a_rwnd = asoc->peer.rwnd + + asoc->outqueue.outstanding_bytes; sackh.num_gap_ack_blocks = 0; sackh.num_dup_tsns = 0; sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, @@ -1632,9 +1633,9 @@ out: */ if (asoc && SCTP_EVENT_T_CHUNK == event_type && chunk) { if (chunk->end_of_packet || chunk->singleton) - sctp_outq_uncork(&asoc->outqueue); + error = sctp_outq_uncork(&asoc->outqueue); } else if (local_cork) - sctp_outq_uncork(&asoc->outqueue); + error = sctp_outq_uncork(&asoc->outqueue); return error; nomem: error = -ENOMEM; -- cgit v0.10.2 From b29e7907288554db9c987c36facfd0304ee8ff5a Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:20:59 -0400 Subject: sctp: Nagle delay should be based on path mtu The decision to delay due to Nagle should be based on the path mtu and future packet size. We currently incorrectly base it on 'frag_point' which is the SCTP DATA segment size, and also we do not count DATA chunk header overhead in the computation. This actuall allows situations where a user can set low 'frag_point', and then send small messages without delay. Signed-off-by: Vlad Yasevich diff --git a/net/sctp/output.c b/net/sctp/output.c index e25e2e2..d0b84f6 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -697,13 +697,14 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, */ if (!sctp_sk(asoc->base.sk)->nodelay && sctp_packet_empty(packet) && inflight && sctp_state(asoc, ESTABLISHED)) { - unsigned len = datasize + q->out_qlen; + unsigned max = transport->pathmtu - packet->overhead; + unsigned len = chunk->skb->len + q->out_qlen; /* Check whether this chunk and all the rest of pending * data will fit or delay in hopes of bundling a full * sized packet. */ - if (len < asoc->frag_point) { + if (len < max) { retval = SCTP_XMIT_NAGLE_DELAY; goto finish; } -- cgit v0.10.2 From cb95ea32a457871f72752164de8d94fa20f4703c Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:20:59 -0400 Subject: sctp: Don't do NAGLE delay on large writes that were fragmented small SCTP will delay the last part of a large write due to NAGLE, if that part is smaller then MTU. Since we are doing large writes, we might as well send the last portion now instead of waiting untill the next large write happens. The small portion will be sent as is regardless, so it's better to not delay it. This is a result of much discussions with Wei Yongjun and Doug Graham . Many thanks go out to them. Signed-off-by: Vlad Yasevich diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index b1bd268..df4c632 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -628,7 +628,7 @@ struct sctp_datamsg { /* Chunks waiting to be submitted to lower layer. */ struct list_head chunks; /* Chunks that have been transmitted. */ - struct list_head track; + size_t msg_size; /* Reference counting. */ atomic_t refcnt; /* When is this message no longer interesting to the peer? */ diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 645577d..acf7c4d 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -59,6 +59,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg) msg->can_abandon = 0; msg->expires_at = 0; INIT_LIST_HEAD(&msg->chunks); + msg->msg_size = 0; } /* Allocate and initialize datamsg. */ @@ -155,6 +156,7 @@ static void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chu { sctp_datamsg_hold(msg); chunk->msg = msg; + msg->msg_size += chunk->skb->len; } diff --git a/net/sctp/output.c b/net/sctp/output.c index d0b84f6..b801bc9 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -703,8 +703,10 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, /* Check whether this chunk and all the rest of pending * data will fit or delay in hopes of bundling a full * sized packet. + * Don't delay large message writes that may have been + * fragmeneted into small peices. */ - if (len < max) { + if ((len < max) && (chunk->msg->msg_size < max)) { retval = SCTP_XMIT_NAGLE_DELAY; goto finish; } -- cgit v0.10.2 From f68b2e05f326971cd76c65aa91a1a41771dd7485 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:21:00 -0400 Subject: sctp: Fix SCTP_MAXSEG socket option to comply to spec. We had a bug that we never stored the user-defined value for MAXSEG when setting the value on an association. Thus future PMTU events ended up re-writing the frag point and increasing it past user limit. Additionally, when setting the option on the socket/endpoint, we effect all current associations, which is against spec. Now, we store the user 'maxseg' value along with the computed 'frag_point'. We inherit 'maxseg' from the socket at association creation and use it as an upper limit for 'frag_point' when its set. Signed-off-by: Vlad Yasevich diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index d16a304..8a6d529 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -486,15 +486,16 @@ static inline __s32 sctp_jitter(__u32 rto) } /* Break down data chunks at this point. */ -static inline int sctp_frag_point(const struct sctp_sock *sp, int pmtu) +static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu) { + struct sctp_sock *sp = sctp_sk(asoc->base.sk); int frag = pmtu; frag -= sp->pf->af->net_header_len; frag -= sizeof(struct sctphdr) + sizeof(struct sctp_data_chunk); - if (sp->user_frag) - frag = min_t(int, frag, sp->user_frag); + if (asoc->user_frag) + frag = min_t(int, frag, asoc->user_frag); frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN); diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index df4c632..b106128 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1763,6 +1763,7 @@ struct sctp_association { /* The message size at which SCTP fragmentation will occur. */ __u32 frag_point; + __u32 user_frag; /* Counter used to count INIT errors. */ int init_err_counter; diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 39c3821..1f05b94 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -112,6 +112,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000) * 1000; asoc->frag_point = 0; + asoc->user_frag = sp->user_frag; /* Set the association max_retrans and RTO values from the * socket values. @@ -674,7 +675,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, "%d\n", asoc, asoc->pathmtu); peer->pmtu_pending = 0; - asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); + asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu); /* The asoc->peer.port might not be meaningful yet, but * initialize the packet structure anyway. @@ -1330,9 +1331,8 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc) } if (pmtu) { - struct sctp_sock *sp = sctp_sk(asoc->base.sk); asoc->pathmtu = pmtu; - asoc->frag_point = sctp_frag_point(sp, pmtu); + asoc->frag_point = sctp_frag_point(asoc, pmtu); } SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n", diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 95a5623..89af37a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2243,7 +2243,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, sctp_assoc_sync_pmtu(asoc); } else if (asoc) { asoc->pathmtu = params->spp_pathmtu; - sctp_frag_point(sp, params->spp_pathmtu); + sctp_frag_point(asoc, params->spp_pathmtu); } else { sp->pathmtu = params->spp_pathmtu; } @@ -2880,15 +2880,10 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optl val -= sizeof(struct sctphdr) + sizeof(struct sctp_data_chunk); } - - asoc->frag_point = val; + asoc->user_frag = val; + asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu); } else { sp->user_frag = val; - - /* Update the frag_point of the existing associations. */ - list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { - asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); - } } return 0; -- cgit v0.10.2 From 31b02e1549406efa346534acad956a42bc3f28c4 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:21:00 -0400 Subject: sctp: Failover transmitted list on transport delete Add-IP feature allows users to delete an active transport. If that transport has chunks in flight, those chunks need to be moved to another transport or association may get into unrecoverable state. Reported-by: Rafael Laufer Signed-off-by: Vlad Yasevich diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 1f05b94..caba989 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -584,6 +584,33 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, asoc->addip_last_asconf->transport == peer) asoc->addip_last_asconf->transport = NULL; + /* If we have something on the transmitted list, we have to + * save it off. The best place is the active path. + */ + if (!list_empty(&peer->transmitted)) { + struct sctp_transport *active = asoc->peer.active_path; + struct sctp_chunk *ch; + + /* Reset the transport of each chunk on this list */ + list_for_each_entry(ch, &peer->transmitted, + transmitted_list) { + ch->transport = NULL; + ch->rtt_in_progress = 0; + } + + list_splice_tail_init(&peer->transmitted, + &active->transmitted); + + /* Start a T3 timer here in case it wasn't running so + * that these migrated packets have a chance to get + * retrnasmitted. + */ + if (!timer_pending(&active->T3_rtx_timer)) + if (!mod_timer(&active->T3_rtx_timer, + jiffies + active->rto)) + sctp_transport_hold(active); + } + asoc->peer.transport_count--; sctp_transport_free(peer); diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index d765fc5..c9f20e2 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -406,8 +406,9 @@ void sctp_retransmit_mark(struct sctp_outq *q, * not be retransmitted */ if (!chunk->tsn_gap_acked) { - chunk->transport->flight_size -= - sctp_data_size(chunk); + if (chunk->transport) + chunk->transport->flight_size -= + sctp_data_size(chunk); q->outstanding_bytes -= sctp_data_size(chunk); q->asoc->peer.rwnd += (sctp_data_size(chunk) + sizeof(struct sk_buff)); @@ -443,7 +444,8 @@ void sctp_retransmit_mark(struct sctp_outq *q, q->asoc->peer.rwnd += (sctp_data_size(chunk) + sizeof(struct sk_buff)); q->outstanding_bytes -= sctp_data_size(chunk); - transport->flight_size -= sctp_data_size(chunk); + if (chunk->transport) + transport->flight_size -= sctp_data_size(chunk); /* sctpimpguide-05 Section 2.8.2 * M5) If a T3-rtx timer expires, the @@ -1310,6 +1312,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, __u32 rtt; __u8 restart_timer = 0; int bytes_acked = 0; + int migrate_bytes = 0; /* These state variables are for coherent debug output. --xguo */ @@ -1343,8 +1346,9 @@ static void sctp_check_transmitted(struct sctp_outq *q, * considering it as 'outstanding'. */ if (!tchunk->tsn_gap_acked) { - tchunk->transport->flight_size -= - sctp_data_size(tchunk); + if (tchunk->transport) + tchunk->transport->flight_size -= + sctp_data_size(tchunk); q->outstanding_bytes -= sctp_data_size(tchunk); } continue; @@ -1378,6 +1382,20 @@ static void sctp_check_transmitted(struct sctp_outq *q, rtt); } } + + /* If the chunk hasn't been marked as ACKED, + * mark it and account bytes_acked if the + * chunk had a valid transport (it will not + * have a transport if ASCONF had deleted it + * while DATA was outstanding). + */ + if (!tchunk->tsn_gap_acked) { + tchunk->tsn_gap_acked = 1; + bytes_acked += sctp_data_size(tchunk); + if (!tchunk->transport) + migrate_bytes += sctp_data_size(tchunk); + } + if (TSN_lte(tsn, sack_ctsn)) { /* RFC 2960 6.3.2 Retransmission Timer Rules * @@ -1391,8 +1409,6 @@ static void sctp_check_transmitted(struct sctp_outq *q, restart_timer = 1; if (!tchunk->tsn_gap_acked) { - tchunk->tsn_gap_acked = 1; - bytes_acked += sctp_data_size(tchunk); /* * SFR-CACC algorithm: * 2) If the SACK contains gap acks @@ -1432,10 +1448,6 @@ static void sctp_check_transmitted(struct sctp_outq *q, * older than that newly acknowledged DATA * chunk, are qualified as 'Stray DATA chunks'. */ - if (!tchunk->tsn_gap_acked) { - tchunk->tsn_gap_acked = 1; - bytes_acked += sctp_data_size(tchunk); - } list_add_tail(lchunk, &tlist); } @@ -1491,7 +1503,8 @@ static void sctp_check_transmitted(struct sctp_outq *q, tsn); tchunk->tsn_gap_acked = 0; - bytes_acked -= sctp_data_size(tchunk); + if (tchunk->transport) + bytes_acked -= sctp_data_size(tchunk); /* RFC 2960 6.3.2 Retransmission Timer Rules * @@ -1561,6 +1574,14 @@ static void sctp_check_transmitted(struct sctp_outq *q, #endif /* SCTP_DEBUG */ if (transport) { if (bytes_acked) { + /* We may have counted DATA that was migrated + * to this transport due to DEL-IP operation. + * Subtract those bytes, since the were never + * send on this transport and shouldn't be + * credited to this transport. + */ + bytes_acked -= migrate_bytes; + /* 8.2. When an outstanding TSN is acknowledged, * the endpoint shall clear the error counter of * the destination transport address to which the @@ -1589,7 +1610,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, transport->flight_size -= bytes_acked; if (transport->flight_size == 0) transport->partial_bytes_acked = 0; - q->outstanding_bytes -= bytes_acked; + q->outstanding_bytes -= bytes_acked + migrate_bytes; } else { /* RFC 2960 6.1, sctpimpguide-06 2.15.2 * When a sender is doing zero window probing, it diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 45b8bca..a7f18a3 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3543,6 +3543,12 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep, asconf_ack = sctp_assoc_lookup_asconf_ack(asoc, hdr->serial); if (!asconf_ack) return SCTP_DISPOSITION_DISCARD; + + /* Reset the transport so that we select the correct one + * this time around. This is to make sure that we don't + * accidentally use a stale transport that's been removed. + */ + asconf_ack->transport = NULL; } else { /* ADDIP 5.2 E5) Otherwise, the ASCONF Chunk is discarded since * it must be either a stale packet or from an attacker. -- cgit v0.10.2 From d521c08f4c16d27f193718da778503a6472501da Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 2 Sep 2009 13:05:33 +0800 Subject: sctp: fix to reset packet information after packet transmit The packet information does not reset after packet transmit, this may cause some problems such as following DATA chunk be sent without AUTH chunk, even if the authentication of DATA chunk has been requested by the peer. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/output.c b/net/sctp/output.c index b801bc9..1f93361 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -136,6 +136,17 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet, return packet; } +static void sctp_packet_reset(struct sctp_packet *packet) +{ + packet->size = packet->overhead; + packet->has_cookie_echo = 0; + packet->has_sack = 0; + packet->has_data = 0; + packet->has_auth = 0; + packet->ipfragok = 0; + packet->auth = NULL; +} + /* Free a packet. */ void sctp_packet_free(struct sctp_packet *packet) { @@ -576,7 +587,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) (*tp->af_specific->sctp_xmit)(nskb, tp); out: - packet->size = packet->overhead; + sctp_packet_reset(packet); return err; no_route: kfree_skb(nskb); -- cgit v0.10.2 From 4007cc88ceec8892b74792f0a10983b140beae72 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:21:00 -0400 Subject: sctp: Correctly track if AUTH has been bundled. We currently track if AUTH has been bundled using the 'auth' pointer to the chunk. However, AUTH is disallowed after DATA is already in the packet, so we need to instead use the 'has_auth' field. Signed-off-by: Vlad Yasevich diff --git a/net/sctp/output.c b/net/sctp/output.c index 1f93361..e47398c 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -220,7 +220,7 @@ static sctp_xmit_t sctp_packet_bundle_auth(struct sctp_packet *pkt, /* See if this is an auth chunk we are bundling or if * auth is already bundled. */ - if (chunk->chunk_hdr->type == SCTP_CID_AUTH || pkt->auth) + if (chunk->chunk_hdr->type == SCTP_CID_AUTH || pkt->has_auth) return retval; /* if the peer did not request this chunk to be authenticated, -- cgit v0.10.2 From a803c942303e6a4ef0ab6b80114529852cffa058 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:21:01 -0400 Subject: sctp: Turn flags in 'sctp_packet' into bit fields This shrinks the size of sctp_packet a little. Signed-off-by: Vlad Yasevich diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index b106128..993cfff 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -812,22 +812,12 @@ struct sctp_packet { /* pointer to the auth chunk for this packet */ struct sctp_chunk *auth; - /* This packet contains a COOKIE-ECHO chunk. */ - __u8 has_cookie_echo; - - /* This packet contains a SACK chunk. */ - __u8 has_sack; - - /* This packet contains an AUTH chunk */ - __u8 has_auth; - - /* This packet contains at least 1 DATA chunk */ - __u8 has_data; - - /* SCTP cannot fragment this packet. So let ip fragment it. */ - __u8 ipfragok; - - __u8 malloced; + u8 has_cookie_echo:1, /* This packet contains a COOKIE-ECHO chunk. */ + has_sack:1, /* This packet contains a SACK chunk. */ + has_auth:1, /* This packet contains an AUTH chunk */ + has_data:1, /* This packet contains at least 1 DATA chunk */ + ipfragok:1, /* So let ip fragment this packet */ + malloced:1; /* Is it malloced? */ }; struct sctp_packet *sctp_packet_init(struct sctp_packet *, -- cgit v0.10.2 From 8da645e101a8c20c6073efda3c7cc74eec01b87f Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:21:01 -0400 Subject: sctp: Get rid of an extra routing lookup when adding a transport. We used to perform 2 routing lookups for a new transport: one just for path mtu detection, and one to actually route to destination and path mtu update when sending a packet. There is no point in doing both of them, especially since the first one just for path mtu doesn't take into account source address and sometimes gives the wrong route, causing path mtu updates anyway. We now do just the one call to do both route to destination and get path mtu updates. Signed-off-by: Vlad Yasevich diff --git a/net/sctp/associola.c b/net/sctp/associola.c index caba989..8450960 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -680,13 +680,15 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, */ peer->param_flags = asoc->param_flags; + sctp_transport_route(peer, NULL, sp); + /* Initialize the pmtu of the transport. */ - if (peer->param_flags & SPP_PMTUD_ENABLE) - sctp_transport_pmtu(peer); - else if (asoc->pathmtu) - peer->pathmtu = asoc->pathmtu; - else - peer->pathmtu = SCTP_DEFAULT_MAXSEGMENT; + if (peer->param_flags & SPP_PMTUD_DISABLE) { + if (asoc->pathmtu) + peer->pathmtu = asoc->pathmtu; + else + peer->pathmtu = SCTP_DEFAULT_MAXSEGMENT; + } /* If this is the first transport addr on this association, * initialize the association PMTU to the peer's PMTU. -- cgit v0.10.2 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 diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 4e9c6d7..fbe427a 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 af8c150..58f714a 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 993cfff..a48d80e 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 6d5944a..13a6fba 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 a76da65..60093be 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 63eabbc..ab7151d 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 v0.10.2 From 9237ccbc0b22b5aa5396463ba0b14dc5efe5b98c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 4 Sep 2009 14:33:19 +0800 Subject: sctp: turn flags in 'struct sctp_association' into bit fields This shrinks the size of struct sctp_association a little. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index a48d80e..42d00ce 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1568,13 +1568,13 @@ struct sctp_association { __u32 sack_cnt; /* These are capabilities which our peer advertised. */ - __u8 ecn_capable; /* Can peer do ECN? */ - __u8 ipv4_address; /* Peer understands IPv4 addresses? */ - __u8 ipv6_address; /* Peer understands IPv6 addresses? */ - __u8 hostname_address;/* Peer understands DNS addresses? */ - __u8 asconf_capable; /* Does peer support ADDIP? */ - __u8 prsctp_capable; /* Can peer do PR-SCTP? */ - __u8 auth_capable; /* Is peer doing SCTP-AUTH? */ + __u8 ecn_capable:1, /* Can peer do ECN? */ + ipv4_address:1, /* Peer understands IPv4 addresses? */ + ipv6_address:1, /* Peer understands IPv6 addresses? */ + hostname_address:1, /* Peer understands DNS addresses? */ + asconf_capable:1, /* Does peer support ADDIP? */ + prsctp_capable:1, /* Can peer do PR-SCTP? */ + auth_capable:1; /* Is peer doing SCTP-AUTH? */ __u32 adaptation_ind; /* Adaptation Code point. */ @@ -1913,11 +1913,8 @@ struct sctp_association { __u16 active_key_id; - /* Need to send an ECNE Chunk? */ - char need_ecne; - - /* Is it a temporary association? */ - char temp; + __u8 need_ecne:1, /* Need to send an ECNE Chunk? */ + temp:1; /* Is it a temporary association? */ }; -- cgit v0.10.2 From be2971438dec2e2d041af4701472a93a7dd03642 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 4 Sep 2009 14:34:06 +0800 Subject: sctp: remove dup code in net/sctp/output.c Use sctp_packet_reset() instead of dup code. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich diff --git a/net/sctp/output.c b/net/sctp/output.c index e47398c..5cbda8f 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -69,6 +69,17 @@ static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet, struct sctp_chunk *chunk, u16 chunk_len); +static void sctp_packet_reset(struct sctp_packet *packet) +{ + packet->size = packet->overhead; + packet->has_cookie_echo = 0; + packet->has_sack = 0; + packet->has_data = 0; + packet->has_auth = 0; + packet->ipfragok = 0; + packet->auth = NULL; +} + /* Config a packet. * This appears to be a followup set of initializations. */ @@ -80,13 +91,8 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet, SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); + sctp_packet_reset(packet); packet->vtag = vtag; - packet->has_cookie_echo = 0; - packet->has_sack = 0; - packet->has_auth = 0; - packet->has_data = 0; - packet->ipfragok = 0; - packet->auth = NULL; if (ecn_capable && sctp_packet_empty(packet)) { chunk = sctp_get_ecne_prepend(packet->transport->asoc); @@ -124,29 +130,12 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet, } overhead += sizeof(struct sctphdr); packet->overhead = overhead; - packet->size = overhead; + sctp_packet_reset(packet); packet->vtag = 0; - packet->has_cookie_echo = 0; - packet->has_sack = 0; - packet->has_auth = 0; - packet->has_data = 0; - packet->ipfragok = 0; packet->malloced = 0; - packet->auth = NULL; return packet; } -static void sctp_packet_reset(struct sctp_packet *packet) -{ - packet->size = packet->overhead; - packet->has_cookie_echo = 0; - packet->has_sack = 0; - packet->has_data = 0; - packet->has_auth = 0; - packet->ipfragok = 0; - packet->auth = NULL; -} - /* Free a packet. */ void sctp_packet_free(struct sctp_packet *packet) { -- cgit v0.10.2 From f1751c57f7bb816c9b6b4cb5d79c703aaa7199da Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:21:03 -0400 Subject: sctp: Catch bogus stream sequence numbers Since our TSN map is capable of holding at most a 4K chunk gap, there is no way that during this gap, a stream sequence number (unsigned short) can wrap such that the new number is smaller then the next expected one. If such a case is encountered, this is a protocol violation. Signed-off-by: Vlad Yasevich diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index a7f18a3..c8fae19 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -2891,6 +2891,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, goto discard_force; case SCTP_IERROR_NO_DATA: goto consume; + case SCTP_IERROR_PROTO_VIOLATION: + return sctp_sf_abort_violation(ep, asoc, chunk, commands, + (u8 *)chunk->subh.data_hdr, sizeof(sctp_datahdr_t)); default: BUG(); } @@ -3001,6 +3004,9 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep, break; case SCTP_IERROR_NO_DATA: goto consume; + case SCTP_IERROR_PROTO_VIOLATION: + return sctp_sf_abort_violation(ep, asoc, chunk, commands, + (u8 *)chunk->subh.data_hdr, sizeof(sctp_datahdr_t)); default: BUG(); } @@ -5877,6 +5883,9 @@ static int sctp_eat_data(const struct sctp_association *asoc, __u32 tsn; struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; struct sock *sk = asoc->base.sk; + u16 ssn; + u16 sid; + u8 ordered = 0; data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); @@ -6016,8 +6025,10 @@ static int sctp_eat_data(const struct sctp_association *asoc, */ if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) SCTP_INC_STATS(SCTP_MIB_INUNORDERCHUNKS); - else + else { SCTP_INC_STATS(SCTP_MIB_INORDERCHUNKS); + ordered = 1; + } /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number * @@ -6027,7 +6038,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) * and discard the DATA chunk. */ - if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { + sid = ntohs(data_hdr->stream); + if (sid >= asoc->c.sinit_max_instreams) { /* Mark tsn as received even though we drop it */ sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); @@ -6040,6 +6052,18 @@ static int sctp_eat_data(const struct sctp_association *asoc, return SCTP_IERROR_BAD_STREAM; } + /* Check to see if the SSN is possible for this TSN. + * The biggest gap we can record is 4K wide. Since SSNs wrap + * at an unsigned short, there is no way that an SSN can + * wrap and for a valid TSN. We can simply check if the current + * SSN is smaller then the next expected one. If it is, it wrapped + * and is invalid. + */ + ssn = ntohs(data_hdr->ssn); + if (ordered && SSN_lt(ssn, sctp_ssn_peek(&asoc->ssnmap->in, sid))) { + return SCTP_IERROR_PROTO_VIOLATION; + } + /* Send the data up to the user. Note: Schedule the * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK * chunk needs the updated rwnd. -- cgit v0.10.2 From 2f26ebd549b9ab55ac756b836ec759c11fe93f81 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 1 Sep 2009 11:06:29 -0400 Subject: tracing: use timestamp to determine start of latency traces Currently the latency tracers reset the ring buffer. Unfortunately if a commit is in process (due to a trace event), this can corrupt the ring buffer. When this happens, the ring buffer will detect the corruption and then permanently disable the ring buffer. The bug does not crash the system, but it does prevent further tracing after the bug is hit. Instead of reseting the trace buffers, the timestamp of the start of the trace is used instead. The buffers will still contain the previous data, but the output will not count any data that is before the timestamp of the trace. Note, this only affects the static trace output (trace) and not the runtime trace output (trace_pipe). The runtime trace output does not make sense for the latency tracers anyway. Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 54517a8..7daf372 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -454,10 +454,6 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) tr->buffer = max_tr.buffer; max_tr.buffer = buf; - ftrace_disable_cpu(); - ring_buffer_reset(tr->buffer); - ftrace_enable_cpu(); - __update_max_tr(tr, tsk, cpu); __raw_spin_unlock(&ftrace_max_lock); } @@ -483,7 +479,6 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu) ftrace_disable_cpu(); - ring_buffer_reset(max_tr.buffer); ret = ring_buffer_swap_cpu(max_tr.buffer, tr->buffer, cpu); ftrace_enable_cpu(); @@ -1374,6 +1369,37 @@ static void *s_next(struct seq_file *m, void *v, loff_t *pos) return ent; } +static void tracing_iter_reset(struct trace_iterator *iter, int cpu) +{ + struct trace_array *tr = iter->tr; + struct ring_buffer_event *event; + struct ring_buffer_iter *buf_iter; + unsigned long entries = 0; + u64 ts; + + tr->data[cpu]->skipped_entries = 0; + + if (!iter->buffer_iter[cpu]) + return; + + buf_iter = iter->buffer_iter[cpu]; + ring_buffer_iter_reset(buf_iter); + + /* + * We could have the case with the max latency tracers + * that a reset never took place on a cpu. This is evident + * by the timestamp being before the start of the buffer. + */ + while ((event = ring_buffer_iter_peek(buf_iter, &ts))) { + if (ts >= iter->tr->time_start) + break; + entries++; + ring_buffer_read(buf_iter, NULL); + } + + tr->data[cpu]->skipped_entries = entries; +} + /* * No necessary locking here. The worst thing which can * happen is loosing events consumed at the same time @@ -1412,10 +1438,9 @@ static void *s_start(struct seq_file *m, loff_t *pos) if (cpu_file == TRACE_PIPE_ALL_CPU) { for_each_tracing_cpu(cpu) - ring_buffer_iter_reset(iter->buffer_iter[cpu]); + tracing_iter_reset(iter, cpu); } else - ring_buffer_iter_reset(iter->buffer_iter[cpu_file]); - + tracing_iter_reset(iter, cpu_file); ftrace_enable_cpu(); @@ -1464,16 +1489,32 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter) struct trace_array *tr = iter->tr; struct trace_array_cpu *data = tr->data[tr->cpu]; struct tracer *type = current_trace; - unsigned long total; - unsigned long entries; + unsigned long entries = 0; + unsigned long total = 0; + unsigned long count; const char *name = "preemption"; + int cpu; if (type) name = type->name; - entries = ring_buffer_entries(iter->tr->buffer); - total = entries + - ring_buffer_overruns(iter->tr->buffer); + + for_each_tracing_cpu(cpu) { + count = ring_buffer_entries_cpu(tr->buffer, cpu); + /* + * If this buffer has skipped entries, then we hold all + * entries for the trace and we need to ignore the + * ones before the time stamp. + */ + if (tr->data[cpu]->skipped_entries) { + count -= tr->data[cpu]->skipped_entries; + /* total is the same as the entries */ + total += count; + } else + total += count + + ring_buffer_overrun_cpu(tr->buffer, cpu); + entries += count; + } seq_printf(m, "# %s latency trace v1.1.5 on %s\n", name, UTS_RELEASE); @@ -1534,6 +1575,9 @@ static void test_cpu_buff_start(struct trace_iterator *iter) if (cpumask_test_cpu(iter->cpu, iter->started)) return; + if (iter->tr->data[iter->cpu]->skipped_entries) + return; + cpumask_set_cpu(iter->cpu, iter->started); /* Don't print started cpu buffer for the first entry of the trace */ @@ -1796,19 +1840,23 @@ __tracing_open(struct inode *inode, struct file *file) if (ring_buffer_overruns(iter->tr->buffer)) iter->iter_flags |= TRACE_FILE_ANNOTATE; + /* stop the trace while dumping */ + tracing_stop(); + if (iter->cpu_file == TRACE_PIPE_ALL_CPU) { for_each_tracing_cpu(cpu) { iter->buffer_iter[cpu] = ring_buffer_read_start(iter->tr->buffer, cpu); + tracing_iter_reset(iter, cpu); } } else { cpu = iter->cpu_file; iter->buffer_iter[cpu] = ring_buffer_read_start(iter->tr->buffer, cpu); + tracing_iter_reset(iter, cpu); } - /* TODO stop tracer */ ret = seq_open(file, &tracer_seq_ops); if (ret < 0) { fail_ret = ERR_PTR(ret); @@ -1818,9 +1866,6 @@ __tracing_open(struct inode *inode, struct file *file) m = file->private_data; m->private = iter; - /* stop the trace while dumping */ - tracing_stop(); - mutex_unlock(&trace_types_lock); return iter; @@ -1831,6 +1876,7 @@ __tracing_open(struct inode *inode, struct file *file) ring_buffer_read_finish(iter->buffer_iter[cpu]); } free_cpumask_var(iter->started); + tracing_start(); fail: mutex_unlock(&trace_types_lock); kfree(iter->trace); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index f2af713..ca070de 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -241,6 +241,7 @@ struct trace_array_cpu { unsigned long nice; unsigned long policy; unsigned long rt_priority; + unsigned long skipped_entries; cycle_t preempt_timestamp; pid_t pid; uid_t uid; diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index b923d13..5555b75 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -178,7 +178,6 @@ out_unlock: out: data->critical_sequence = max_sequence; data->preempt_timestamp = ftrace_now(cpu); - tracing_reset(tr, cpu); trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc); } @@ -208,7 +207,6 @@ start_critical_timing(unsigned long ip, unsigned long parent_ip) data->critical_sequence = max_sequence; data->preempt_timestamp = ftrace_now(cpu); data->critical_start = parent_ip ? : ip; - tracing_reset(tr, cpu); local_save_flags(flags); @@ -379,6 +377,7 @@ static void __irqsoff_tracer_init(struct trace_array *tr) irqsoff_trace = tr; /* make sure that the tracer is visible */ smp_wmb(); + tracing_reset_online_cpus(tr); start_irqsoff_tracer(tr); } diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c index eacb272..ad69f10 100644 --- a/kernel/trace/trace_sched_wakeup.c +++ b/kernel/trace/trace_sched_wakeup.c @@ -186,11 +186,6 @@ out: static void __wakeup_reset(struct trace_array *tr) { - int cpu; - - for_each_possible_cpu(cpu) - tracing_reset(tr, cpu); - wakeup_cpu = -1; wakeup_prio = -1; @@ -204,6 +199,8 @@ static void wakeup_reset(struct trace_array *tr) { unsigned long flags; + tracing_reset_online_cpus(tr); + local_irq_save(flags); __raw_spin_lock(&wakeup_lock); __wakeup_reset(tr); -- cgit v0.10.2 From f633903af2ceb0cec07d45e499a072b6593d0ed1 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 4 Sep 2009 12:35:16 -0400 Subject: tracing: make tracing_reset safe for external use Reseting the trace buffer without first disabling the buffer and waiting for any writers to complete, can corrupt the ring buffer. This patch makes the external version of tracing_reset safe from corruption by disabling the ring buffer and calling synchronize_sched. This version can no longer be called from interrupt context. But all those callers have been removed. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 7daf372..0418e26 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -641,13 +641,26 @@ void unregister_tracer(struct tracer *type) mutex_unlock(&trace_types_lock); } -void tracing_reset(struct trace_array *tr, int cpu) +static void __tracing_reset(struct trace_array *tr, int cpu) { ftrace_disable_cpu(); ring_buffer_reset_cpu(tr->buffer, cpu); ftrace_enable_cpu(); } +void tracing_reset(struct trace_array *tr, int cpu) +{ + struct ring_buffer *buffer = tr->buffer; + + ring_buffer_record_disable(buffer); + + /* Make sure all commits have finished */ + synchronize_sched(); + __tracing_reset(tr, cpu); + + ring_buffer_record_enable(buffer); +} + void tracing_reset_online_cpus(struct trace_array *tr) { struct ring_buffer *buffer = tr->buffer; @@ -661,7 +674,7 @@ void tracing_reset_online_cpus(struct trace_array *tr) tr->time_start = ftrace_now(tr->cpu); for_each_online_cpu(cpu) - tracing_reset(tr, cpu); + __tracing_reset(tr, cpu); ring_buffer_record_enable(buffer); } -- cgit v0.10.2 From e77405ad80f53966524b5c31244e13fbbbecbd84 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 2 Sep 2009 14:17:06 -0400 Subject: tracing: pass around ring buffer instead of tracer The latency tracers (irqsoff and wakeup) can swap trace buffers on the fly. If an event is happening and has reserved data on one of the buffers, and the latency tracer swaps the global buffer with the max buffer, the result is that the event may commit the data to the wrong buffer. This patch changes the API to the trace recording to be recieve the buffer that was used to reserve a commit. Then this buffer can be passed in to the commit. Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 7554804..23f7179 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -93,13 +93,17 @@ void tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags, int pc); struct ring_buffer_event * -trace_current_buffer_lock_reserve(int type, unsigned long len, +trace_current_buffer_lock_reserve(struct ring_buffer **current_buffer, + int type, unsigned long len, unsigned long flags, int pc); -void trace_current_buffer_unlock_commit(struct ring_buffer_event *event, +void trace_current_buffer_unlock_commit(struct ring_buffer *buffer, + struct ring_buffer_event *event, unsigned long flags, int pc); -void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event, +void trace_nowake_buffer_unlock_commit(struct ring_buffer *buffer, + struct ring_buffer_event *event, unsigned long flags, int pc); -void trace_current_buffer_discard_commit(struct ring_buffer_event *event); +void trace_current_buffer_discard_commit(struct ring_buffer *buffer, + struct ring_buffer_event *event); void tracing_record_cmdline(struct task_struct *tsk); @@ -135,7 +139,8 @@ struct ftrace_event_call { extern void destroy_preds(struct ftrace_event_call *call); extern int filter_match_preds(struct ftrace_event_call *call, void *rec); -extern int filter_current_check_discard(struct ftrace_event_call *call, +extern int filter_current_check_discard(struct ring_buffer *buffer, + struct ftrace_event_call *call, void *rec, struct ring_buffer_event *event); diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index bfbc842..308bafd 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -460,13 +460,15 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\ * { * struct ring_buffer_event *event; * struct ftrace_raw_ *entry; <-- defined in stage 1 + * struct ring_buffer *buffer; * unsigned long irq_flags; * int pc; * * local_save_flags(irq_flags); * pc = preempt_count(); * - * event = trace_current_buffer_lock_reserve(event_.id, + * event = trace_current_buffer_lock_reserve(&buffer, + * event_.id, * sizeof(struct ftrace_raw_), * irq_flags, pc); * if (!event) @@ -476,7 +478,7 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\ * ; <-- Here we assign the entries by the __field and * __array macros. * - * trace_current_buffer_unlock_commit(event, irq_flags, pc); + * trace_current_buffer_unlock_commit(buffer, event, irq_flags, pc); * } * * static int ftrace_raw_reg_event_(void) @@ -568,6 +570,7 @@ static void ftrace_raw_event_##call(proto) \ struct ftrace_event_call *event_call = &event_##call; \ struct ring_buffer_event *event; \ struct ftrace_raw_##call *entry; \ + struct ring_buffer *buffer; \ unsigned long irq_flags; \ int __data_size; \ int pc; \ @@ -577,7 +580,8 @@ static void ftrace_raw_event_##call(proto) \ \ __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ \ - event = trace_current_buffer_lock_reserve(event_##call.id, \ + event = trace_current_buffer_lock_reserve(&buffer, \ + event_##call.id, \ sizeof(*entry) + __data_size, \ irq_flags, pc); \ if (!event) \ @@ -589,8 +593,9 @@ static void ftrace_raw_event_##call(proto) \ \ { assign; } \ \ - if (!filter_current_check_discard(event_call, entry, event)) \ - trace_nowake_buffer_unlock_commit(event, irq_flags, pc); \ + if (!filter_current_check_discard(buffer, event_call, entry, event)) \ + trace_nowake_buffer_unlock_commit(buffer, \ + event, irq_flags, pc); \ } \ \ static int ftrace_raw_reg_event_##call(void *ptr) \ diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 1090b0a..243bafc 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -65,13 +65,15 @@ static void trace_note(struct blk_trace *bt, pid_t pid, int action, { struct blk_io_trace *t; struct ring_buffer_event *event = NULL; + struct ring_buffer *buffer = NULL; int pc = 0; int cpu = smp_processor_id(); bool blk_tracer = blk_tracer_enabled; if (blk_tracer) { + buffer = blk_tr->buffer; pc = preempt_count(); - event = trace_buffer_lock_reserve(blk_tr, TRACE_BLK, + event = trace_buffer_lock_reserve(buffer, TRACE_BLK, sizeof(*t) + len, 0, pc); if (!event) @@ -96,7 +98,7 @@ record_it: memcpy((void *) t + sizeof(*t), data, len); if (blk_tracer) - trace_buffer_unlock_commit(blk_tr, event, 0, pc); + trace_buffer_unlock_commit(buffer, event, 0, pc); } } @@ -179,6 +181,7 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, { struct task_struct *tsk = current; struct ring_buffer_event *event = NULL; + struct ring_buffer *buffer = NULL; struct blk_io_trace *t; unsigned long flags = 0; unsigned long *sequence; @@ -204,8 +207,9 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, if (blk_tracer) { tracing_record_cmdline(current); + buffer = blk_tr->buffer; pc = preempt_count(); - event = trace_buffer_lock_reserve(blk_tr, TRACE_BLK, + event = trace_buffer_lock_reserve(buffer, TRACE_BLK, sizeof(*t) + pdu_len, 0, pc); if (!event) @@ -252,7 +256,7 @@ record_it: memcpy((void *) t + sizeof(*t), pdu_data, pdu_len); if (blk_tracer) { - trace_buffer_unlock_commit(blk_tr, event, 0, pc); + trace_buffer_unlock_commit(buffer, event, 0, pc); return; } } diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 0418e26..0c61836 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -169,10 +169,11 @@ static struct trace_array global_trace; static DEFINE_PER_CPU(struct trace_array_cpu, global_trace_cpu); -int filter_current_check_discard(struct ftrace_event_call *call, void *rec, +int filter_current_check_discard(struct ring_buffer *buffer, + struct ftrace_event_call *call, void *rec, struct ring_buffer_event *event) { - return filter_check_discard(call, rec, global_trace.buffer, event); + return filter_check_discard(call, rec, buffer, event); } EXPORT_SYMBOL_GPL(filter_current_check_discard); @@ -887,14 +888,15 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags, } EXPORT_SYMBOL_GPL(tracing_generic_entry_update); -struct ring_buffer_event *trace_buffer_lock_reserve(struct trace_array *tr, - int type, - unsigned long len, - unsigned long flags, int pc) +struct ring_buffer_event * +trace_buffer_lock_reserve(struct ring_buffer *buffer, + int type, + unsigned long len, + unsigned long flags, int pc) { struct ring_buffer_event *event; - event = ring_buffer_lock_reserve(tr->buffer, len); + event = ring_buffer_lock_reserve(buffer, len); if (event != NULL) { struct trace_entry *ent = ring_buffer_event_data(event); @@ -905,53 +907,59 @@ struct ring_buffer_event *trace_buffer_lock_reserve(struct trace_array *tr, return event; } -static inline void __trace_buffer_unlock_commit(struct trace_array *tr, - struct ring_buffer_event *event, - unsigned long flags, int pc, - int wake) +static inline void +__trace_buffer_unlock_commit(struct ring_buffer *buffer, + struct ring_buffer_event *event, + unsigned long flags, int pc, + int wake) { - ring_buffer_unlock_commit(tr->buffer, event); + ring_buffer_unlock_commit(buffer, event); - ftrace_trace_stack(tr, flags, 6, pc); - ftrace_trace_userstack(tr, flags, pc); + ftrace_trace_stack(buffer, flags, 6, pc); + ftrace_trace_userstack(buffer, flags, pc); if (wake) trace_wake_up(); } -void trace_buffer_unlock_commit(struct trace_array *tr, - struct ring_buffer_event *event, - unsigned long flags, int pc) +void trace_buffer_unlock_commit(struct ring_buffer *buffer, + struct ring_buffer_event *event, + unsigned long flags, int pc) { - __trace_buffer_unlock_commit(tr, event, flags, pc, 1); + __trace_buffer_unlock_commit(buffer, event, flags, pc, 1); } struct ring_buffer_event * -trace_current_buffer_lock_reserve(int type, unsigned long len, +trace_current_buffer_lock_reserve(struct ring_buffer **current_rb, + int type, unsigned long len, unsigned long flags, int pc) { - return trace_buffer_lock_reserve(&global_trace, + *current_rb = global_trace.buffer; + return trace_buffer_lock_reserve(*current_rb, type, len, flags, pc); } EXPORT_SYMBOL_GPL(trace_current_buffer_lock_reserve); -void trace_current_buffer_unlock_commit(struct ring_buffer_event *event, +void trace_current_buffer_unlock_commit(struct ring_buffer *buffer, + struct ring_buffer_event *event, unsigned long flags, int pc) { - __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 1); + __trace_buffer_unlock_commit(buffer, event, flags, pc, 1); } EXPORT_SYMBOL_GPL(trace_current_buffer_unlock_commit); -void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event, - unsigned long flags, int pc) +void trace_nowake_buffer_unlock_commit(struct ring_buffer *buffer, + struct ring_buffer_event *event, + unsigned long flags, int pc) { - __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 0); + __trace_buffer_unlock_commit(buffer, event, flags, pc, 0); } EXPORT_SYMBOL_GPL(trace_nowake_buffer_unlock_commit); -void trace_current_buffer_discard_commit(struct ring_buffer_event *event) +void trace_current_buffer_discard_commit(struct ring_buffer *buffer, + struct ring_buffer_event *event) { - ring_buffer_discard_commit(global_trace.buffer, event); + ring_buffer_discard_commit(buffer, event); } EXPORT_SYMBOL_GPL(trace_current_buffer_discard_commit); @@ -961,6 +969,7 @@ trace_function(struct trace_array *tr, int pc) { struct ftrace_event_call *call = &event_function; + struct ring_buffer *buffer = tr->buffer; struct ring_buffer_event *event; struct ftrace_entry *entry; @@ -968,7 +977,7 @@ trace_function(struct trace_array *tr, if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled)))) return; - event = trace_buffer_lock_reserve(tr, TRACE_FN, sizeof(*entry), + event = trace_buffer_lock_reserve(buffer, TRACE_FN, sizeof(*entry), flags, pc); if (!event) return; @@ -976,8 +985,8 @@ trace_function(struct trace_array *tr, entry->ip = ip; entry->parent_ip = parent_ip; - if (!filter_check_discard(call, entry, tr->buffer, event)) - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, buffer, event)) + ring_buffer_unlock_commit(buffer, event); } void @@ -990,7 +999,7 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data, } #ifdef CONFIG_STACKTRACE -static void __ftrace_trace_stack(struct trace_array *tr, +static void __ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, int skip, int pc) { @@ -999,7 +1008,7 @@ static void __ftrace_trace_stack(struct trace_array *tr, struct stack_entry *entry; struct stack_trace trace; - event = trace_buffer_lock_reserve(tr, TRACE_STACK, + event = trace_buffer_lock_reserve(buffer, TRACE_STACK, sizeof(*entry), flags, pc); if (!event) return; @@ -1012,26 +1021,27 @@ static void __ftrace_trace_stack(struct trace_array *tr, trace.entries = entry->caller; save_stack_trace(&trace); - if (!filter_check_discard(call, entry, tr->buffer, event)) - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, buffer, event)) + ring_buffer_unlock_commit(buffer, event); } -void ftrace_trace_stack(struct trace_array *tr, unsigned long flags, int skip, - int pc) +void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, + int skip, int pc) { if (!(trace_flags & TRACE_ITER_STACKTRACE)) return; - __ftrace_trace_stack(tr, flags, skip, pc); + __ftrace_trace_stack(buffer, flags, skip, pc); } void __trace_stack(struct trace_array *tr, unsigned long flags, int skip, int pc) { - __ftrace_trace_stack(tr, flags, skip, pc); + __ftrace_trace_stack(tr->buffer, flags, skip, pc); } -void ftrace_trace_userstack(struct trace_array *tr, unsigned long flags, int pc) +void +ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc) { struct ftrace_event_call *call = &event_user_stack; struct ring_buffer_event *event; @@ -1041,7 +1051,7 @@ void ftrace_trace_userstack(struct trace_array *tr, unsigned long flags, int pc) if (!(trace_flags & TRACE_ITER_USERSTACKTRACE)) return; - event = trace_buffer_lock_reserve(tr, TRACE_USER_STACK, + event = trace_buffer_lock_reserve(buffer, TRACE_USER_STACK, sizeof(*entry), flags, pc); if (!event) return; @@ -1055,8 +1065,8 @@ void ftrace_trace_userstack(struct trace_array *tr, unsigned long flags, int pc) trace.entries = entry->caller; save_stack_trace_user(&trace); - if (!filter_check_discard(call, entry, tr->buffer, event)) - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, buffer, event)) + ring_buffer_unlock_commit(buffer, event); } #ifdef UNUSED @@ -1075,9 +1085,10 @@ ftrace_trace_special(void *__tr, { struct ring_buffer_event *event; struct trace_array *tr = __tr; + struct ring_buffer *buffer = tr->buffer; struct special_entry *entry; - event = trace_buffer_lock_reserve(tr, TRACE_SPECIAL, + event = trace_buffer_lock_reserve(buffer, TRACE_SPECIAL, sizeof(*entry), 0, pc); if (!event) return; @@ -1085,7 +1096,7 @@ ftrace_trace_special(void *__tr, entry->arg1 = arg1; entry->arg2 = arg2; entry->arg3 = arg3; - trace_buffer_unlock_commit(tr, event, 0, pc); + trace_buffer_unlock_commit(buffer, event, 0, pc); } void @@ -1131,6 +1142,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) struct ftrace_event_call *call = &event_bprint; struct ring_buffer_event *event; + struct ring_buffer *buffer; struct trace_array *tr = &global_trace; struct trace_array_cpu *data; struct bprint_entry *entry; @@ -1163,7 +1175,9 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) goto out_unlock; size = sizeof(*entry) + sizeof(u32) * len; - event = trace_buffer_lock_reserve(tr, TRACE_BPRINT, size, flags, pc); + buffer = tr->buffer; + event = trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size, + flags, pc); if (!event) goto out_unlock; entry = ring_buffer_event_data(event); @@ -1171,8 +1185,8 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) entry->fmt = fmt; memcpy(entry->buf, trace_buf, sizeof(u32) * len); - if (!filter_check_discard(call, entry, tr->buffer, event)) - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, buffer, event)) + ring_buffer_unlock_commit(buffer, event); out_unlock: __raw_spin_unlock(&trace_buf_lock); @@ -1194,6 +1208,7 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args) struct ftrace_event_call *call = &event_print; struct ring_buffer_event *event; + struct ring_buffer *buffer; struct trace_array *tr = &global_trace; struct trace_array_cpu *data; int cpu, len = 0, size, pc; @@ -1222,7 +1237,9 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args) trace_buf[len] = 0; size = sizeof(*entry) + len + 1; - event = trace_buffer_lock_reserve(tr, TRACE_PRINT, size, irq_flags, pc); + buffer = tr->buffer; + event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, size, + irq_flags, pc); if (!event) goto out_unlock; entry = ring_buffer_event_data(event); @@ -1230,8 +1247,8 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args) memcpy(&entry->buf, trace_buf, len); entry->buf[len] = 0; - if (!filter_check_discard(call, entry, tr->buffer, event)) - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, buffer, event)) + ring_buffer_unlock_commit(buffer, event); out_unlock: __raw_spin_unlock(&trace_buf_lock); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index ca070de..4d30414 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -415,12 +415,13 @@ void init_tracer_sysprof_debugfs(struct dentry *d_tracer); struct ring_buffer_event; -struct ring_buffer_event *trace_buffer_lock_reserve(struct trace_array *tr, - int type, - unsigned long len, - unsigned long flags, - int pc); -void trace_buffer_unlock_commit(struct trace_array *tr, +struct ring_buffer_event * +trace_buffer_lock_reserve(struct ring_buffer *buffer, + int type, + unsigned long len, + unsigned long flags, + int pc); +void trace_buffer_unlock_commit(struct ring_buffer *buffer, struct ring_buffer_event *event, unsigned long flags, int pc); @@ -481,10 +482,10 @@ void update_max_tr_single(struct trace_array *tr, #endif /* CONFIG_TRACER_MAX_TRACE */ #ifdef CONFIG_STACKTRACE -void ftrace_trace_stack(struct trace_array *tr, unsigned long flags, +void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, int skip, int pc); -void ftrace_trace_userstack(struct trace_array *tr, unsigned long flags, +void ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc); void __trace_stack(struct trace_array *tr, unsigned long flags, int skip, diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c index 8631393..19bfc75 100644 --- a/kernel/trace/trace_boot.c +++ b/kernel/trace/trace_boot.c @@ -130,6 +130,7 @@ struct tracer boot_tracer __read_mostly = void trace_boot_call(struct boot_trace_call *bt, initcall_t fn) { struct ring_buffer_event *event; + struct ring_buffer *buffer; struct trace_boot_call *entry; struct trace_array *tr = boot_trace; @@ -142,13 +143,14 @@ void trace_boot_call(struct boot_trace_call *bt, initcall_t fn) sprint_symbol(bt->func, (unsigned long)fn); preempt_disable(); - event = trace_buffer_lock_reserve(tr, TRACE_BOOT_CALL, + buffer = tr->buffer; + event = trace_buffer_lock_reserve(buffer, TRACE_BOOT_CALL, sizeof(*entry), 0, 0); if (!event) goto out; entry = ring_buffer_event_data(event); entry->boot_call = *bt; - trace_buffer_unlock_commit(tr, event, 0, 0); + trace_buffer_unlock_commit(buffer, event, 0, 0); out: preempt_enable(); } @@ -156,6 +158,7 @@ void trace_boot_call(struct boot_trace_call *bt, initcall_t fn) void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn) { struct ring_buffer_event *event; + struct ring_buffer *buffer; struct trace_boot_ret *entry; struct trace_array *tr = boot_trace; @@ -165,13 +168,14 @@ void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn) sprint_symbol(bt->func, (unsigned long)fn); preempt_disable(); - event = trace_buffer_lock_reserve(tr, TRACE_BOOT_RET, + buffer = tr->buffer; + event = trace_buffer_lock_reserve(buffer, TRACE_BOOT_RET, sizeof(*entry), 0, 0); if (!event) goto out; entry = ring_buffer_event_data(event); entry->boot_ret = *bt; - trace_buffer_unlock_commit(tr, event, 0, 0); + trace_buffer_unlock_commit(buffer, event, 0, 0); out: preempt_enable(); } diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index d33bcde..78b1ed2 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -1438,6 +1438,7 @@ static void function_test_events_call(unsigned long ip, unsigned long parent_ip) { struct ring_buffer_event *event; + struct ring_buffer *buffer; struct ftrace_entry *entry; unsigned long flags; long disabled; @@ -1455,7 +1456,8 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip) local_save_flags(flags); - event = trace_current_buffer_lock_reserve(TRACE_FN, sizeof(*entry), + event = trace_current_buffer_lock_reserve(&buffer, + TRACE_FN, sizeof(*entry), flags, pc); if (!event) goto out; @@ -1463,7 +1465,7 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip) entry->ip = ip; entry->parent_ip = parent_ip; - trace_nowake_buffer_unlock_commit(event, flags, pc); + trace_nowake_buffer_unlock_commit(buffer, event, flags, pc); out: atomic_dec(&per_cpu(test_event_disable, cpu)); diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 3f4a251..b3749a2 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -173,19 +173,20 @@ static int __trace_graph_entry(struct trace_array *tr, { struct ftrace_event_call *call = &event_funcgraph_entry; struct ring_buffer_event *event; + struct ring_buffer *buffer = tr->buffer; struct ftrace_graph_ent_entry *entry; if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled)))) return 0; - event = trace_buffer_lock_reserve(tr, TRACE_GRAPH_ENT, + event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT, sizeof(*entry), flags, pc); if (!event) return 0; entry = ring_buffer_event_data(event); entry->graph_ent = *trace; - if (!filter_current_check_discard(call, entry, event)) - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_current_check_discard(buffer, call, entry, event)) + ring_buffer_unlock_commit(buffer, event); return 1; } @@ -236,19 +237,20 @@ static void __trace_graph_return(struct trace_array *tr, { struct ftrace_event_call *call = &event_funcgraph_exit; struct ring_buffer_event *event; + struct ring_buffer *buffer = tr->buffer; struct ftrace_graph_ret_entry *entry; if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled)))) return; - event = trace_buffer_lock_reserve(tr, TRACE_GRAPH_RET, + event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_RET, sizeof(*entry), flags, pc); if (!event) return; entry = ring_buffer_event_data(event); entry->ret = *trace; - if (!filter_current_check_discard(call, entry, event)) - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_current_check_discard(buffer, call, entry, event)) + ring_buffer_unlock_commit(buffer, event); } void trace_graph_return(struct ftrace_graph_ret *trace) diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c index d53b45e..c4c9bbd 100644 --- a/kernel/trace/trace_mmiotrace.c +++ b/kernel/trace/trace_mmiotrace.c @@ -307,11 +307,12 @@ static void __trace_mmiotrace_rw(struct trace_array *tr, struct trace_array_cpu *data, struct mmiotrace_rw *rw) { + struct ring_buffer *buffer = tr->buffer; struct ring_buffer_event *event; struct trace_mmiotrace_rw *entry; int pc = preempt_count(); - event = trace_buffer_lock_reserve(tr, TRACE_MMIO_RW, + event = trace_buffer_lock_reserve(buffer, TRACE_MMIO_RW, sizeof(*entry), 0, pc); if (!event) { atomic_inc(&dropped_count); @@ -319,7 +320,7 @@ static void __trace_mmiotrace_rw(struct trace_array *tr, } entry = ring_buffer_event_data(event); entry->rw = *rw; - trace_buffer_unlock_commit(tr, event, 0, pc); + trace_buffer_unlock_commit(buffer, event, 0, pc); } void mmio_trace_rw(struct mmiotrace_rw *rw) @@ -333,11 +334,12 @@ static void __trace_mmiotrace_map(struct trace_array *tr, struct trace_array_cpu *data, struct mmiotrace_map *map) { + struct ring_buffer *buffer = tr->buffer; struct ring_buffer_event *event; struct trace_mmiotrace_map *entry; int pc = preempt_count(); - event = trace_buffer_lock_reserve(tr, TRACE_MMIO_MAP, + event = trace_buffer_lock_reserve(buffer, TRACE_MMIO_MAP, sizeof(*entry), 0, pc); if (!event) { atomic_inc(&dropped_count); @@ -345,7 +347,7 @@ static void __trace_mmiotrace_map(struct trace_array *tr, } entry = ring_buffer_event_data(event); entry->map = *map; - trace_buffer_unlock_commit(tr, event, 0, pc); + trace_buffer_unlock_commit(buffer, event, 0, pc); } void mmio_trace_mapping(struct mmiotrace_map *map) diff --git a/kernel/trace/trace_power.c b/kernel/trace/trace_power.c index a5d5a4f..fe1a00f 100644 --- a/kernel/trace/trace_power.c +++ b/kernel/trace/trace_power.c @@ -38,6 +38,7 @@ static void probe_power_end(struct power_trace *it) { struct ftrace_event_call *call = &event_power; struct ring_buffer_event *event; + struct ring_buffer *buffer; struct trace_power *entry; struct trace_array_cpu *data; struct trace_array *tr = power_trace; @@ -45,18 +46,20 @@ static void probe_power_end(struct power_trace *it) if (!trace_power_enabled) return; + buffer = tr->buffer; + preempt_disable(); it->end = ktime_get(); data = tr->data[smp_processor_id()]; - event = trace_buffer_lock_reserve(tr, TRACE_POWER, + event = trace_buffer_lock_reserve(buffer, TRACE_POWER, sizeof(*entry), 0, 0); if (!event) goto out; entry = ring_buffer_event_data(event); entry->state_data = *it; - if (!filter_check_discard(call, entry, tr->buffer, event)) - trace_buffer_unlock_commit(tr, event, 0, 0); + if (!filter_check_discard(call, entry, buffer, event)) + trace_buffer_unlock_commit(buffer, event, 0, 0); out: preempt_enable(); } @@ -66,6 +69,7 @@ static void probe_power_mark(struct power_trace *it, unsigned int type, { struct ftrace_event_call *call = &event_power; struct ring_buffer_event *event; + struct ring_buffer *buffer; struct trace_power *entry; struct trace_array_cpu *data; struct trace_array *tr = power_trace; @@ -73,6 +77,8 @@ static void probe_power_mark(struct power_trace *it, unsigned int type, if (!trace_power_enabled) return; + buffer = tr->buffer; + memset(it, 0, sizeof(struct power_trace)); it->state = level; it->type = type; @@ -81,14 +87,14 @@ static void probe_power_mark(struct power_trace *it, unsigned int type, it->end = it->stamp; data = tr->data[smp_processor_id()]; - event = trace_buffer_lock_reserve(tr, TRACE_POWER, + event = trace_buffer_lock_reserve(buffer, TRACE_POWER, sizeof(*entry), 0, 0); if (!event) goto out; entry = ring_buffer_event_data(event); entry->state_data = *it; - if (!filter_check_discard(call, entry, tr->buffer, event)) - trace_buffer_unlock_commit(tr, event, 0, 0); + if (!filter_check_discard(call, entry, buffer, event)) + trace_buffer_unlock_commit(buffer, event, 0, 0); out: preempt_enable(); } diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c index e1285d7..5fca0f5 100644 --- a/kernel/trace/trace_sched_switch.c +++ b/kernel/trace/trace_sched_switch.c @@ -28,10 +28,11 @@ tracing_sched_switch_trace(struct trace_array *tr, unsigned long flags, int pc) { struct ftrace_event_call *call = &event_context_switch; + struct ring_buffer *buffer = tr->buffer; struct ring_buffer_event *event; struct ctx_switch_entry *entry; - event = trace_buffer_lock_reserve(tr, TRACE_CTX, + event = trace_buffer_lock_reserve(buffer, TRACE_CTX, sizeof(*entry), flags, pc); if (!event) return; @@ -44,8 +45,8 @@ tracing_sched_switch_trace(struct trace_array *tr, entry->next_state = next->state; entry->next_cpu = task_cpu(next); - if (!filter_check_discard(call, entry, tr->buffer, event)) - trace_buffer_unlock_commit(tr, event, flags, pc); + if (!filter_check_discard(call, entry, buffer, event)) + trace_buffer_unlock_commit(buffer, event, flags, pc); } static void @@ -86,8 +87,9 @@ tracing_sched_wakeup_trace(struct trace_array *tr, struct ftrace_event_call *call = &event_wakeup; struct ring_buffer_event *event; struct ctx_switch_entry *entry; + struct ring_buffer *buffer = tr->buffer; - event = trace_buffer_lock_reserve(tr, TRACE_WAKE, + event = trace_buffer_lock_reserve(buffer, TRACE_WAKE, sizeof(*entry), flags, pc); if (!event) return; @@ -100,10 +102,10 @@ tracing_sched_wakeup_trace(struct trace_array *tr, entry->next_state = wakee->state; entry->next_cpu = task_cpu(wakee); - if (!filter_check_discard(call, entry, tr->buffer, event)) - ring_buffer_unlock_commit(tr->buffer, event); - ftrace_trace_stack(tr, flags, 6, pc); - ftrace_trace_userstack(tr, flags, pc); + if (!filter_check_discard(call, entry, buffer, event)) + ring_buffer_unlock_commit(buffer, event); + ftrace_trace_stack(tr->buffer, flags, 6, pc); + ftrace_trace_userstack(tr->buffer, flags, pc); } static void diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 4f5fae6..8712ce3 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -223,6 +223,7 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id) struct syscall_trace_enter *entry; struct syscall_metadata *sys_data; struct ring_buffer_event *event; + struct ring_buffer *buffer; int size; int syscall_nr; @@ -238,8 +239,8 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id) size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args; - event = trace_current_buffer_lock_reserve(sys_data->enter_id, size, - 0, 0); + event = trace_current_buffer_lock_reserve(&buffer, sys_data->enter_id, + size, 0, 0); if (!event) return; @@ -247,8 +248,9 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id) entry->nr = syscall_nr; syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args); - if (!filter_current_check_discard(sys_data->enter_event, entry, event)) - trace_current_buffer_unlock_commit(event, 0, 0); + if (!filter_current_check_discard(buffer, sys_data->enter_event, + entry, event)) + trace_current_buffer_unlock_commit(buffer, event, 0, 0); } void ftrace_syscall_exit(struct pt_regs *regs, long ret) @@ -256,6 +258,7 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret) struct syscall_trace_exit *entry; struct syscall_metadata *sys_data; struct ring_buffer_event *event; + struct ring_buffer *buffer; int syscall_nr; syscall_nr = syscall_get_nr(current, regs); @@ -268,7 +271,7 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret) if (!sys_data) return; - event = trace_current_buffer_lock_reserve(sys_data->exit_id, + event = trace_current_buffer_lock_reserve(&buffer, sys_data->exit_id, sizeof(*entry), 0, 0); if (!event) return; @@ -277,8 +280,9 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret) entry->nr = syscall_nr; entry->ret = syscall_get_return_value(current, regs); - if (!filter_current_check_discard(sys_data->exit_event, entry, event)) - trace_current_buffer_unlock_commit(event, 0, 0); + if (!filter_current_check_discard(buffer, sys_data->exit_event, + entry, event)) + trace_current_buffer_unlock_commit(buffer, event, 0, 0); } int reg_event_syscall_enter(void *ptr) -- cgit v0.10.2 From 659372d3e42a3e17a2e042d38a8bcdb94bfbe797 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 3 Sep 2009 19:11:07 -0400 Subject: tracing: add trace_array_printk for internal tracers to use This patch adds a trace_array_printk to allow a tracer to use the trace_printk on its own trace array. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 0c61836..ef08328 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1201,7 +1201,23 @@ out: } EXPORT_SYMBOL_GPL(trace_vbprintk); -int trace_vprintk(unsigned long ip, const char *fmt, va_list args) +int trace_array_printk(struct trace_array *tr, + unsigned long ip, const char *fmt, ...) +{ + int ret; + va_list ap; + + if (!(trace_flags & TRACE_ITER_PRINTK)) + return 0; + + va_start(ap, fmt); + ret = trace_array_vprintk(tr, ip, fmt, ap); + va_end(ap); + return ret; +} + +int trace_array_vprintk(struct trace_array *tr, + unsigned long ip, const char *fmt, va_list args) { static raw_spinlock_t trace_buf_lock = __RAW_SPIN_LOCK_UNLOCKED; static char trace_buf[TRACE_BUF_SIZE]; @@ -1209,7 +1225,6 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args) struct ftrace_event_call *call = &event_print; struct ring_buffer_event *event; struct ring_buffer *buffer; - struct trace_array *tr = &global_trace; struct trace_array_cpu *data; int cpu, len = 0, size, pc; struct print_entry *entry; @@ -1260,6 +1275,11 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args) return len; } + +int trace_vprintk(unsigned long ip, const char *fmt, va_list args) +{ + return trace_array_printk(&global_trace, ip, fmt, args); +} EXPORT_SYMBOL_GPL(trace_vprintk); enum trace_file_type { diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 4d30414..fa1dccb 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -566,6 +566,11 @@ extern int trace_vbprintk(unsigned long ip, const char *fmt, va_list args); extern int trace_vprintk(unsigned long ip, const char *fmt, va_list args); +extern int +trace_array_vprintk(struct trace_array *tr, + unsigned long ip, const char *fmt, va_list args); +int trace_array_printk(struct trace_array *tr, + unsigned long ip, const char *fmt, ...); extern unsigned long trace_flags; -- cgit v0.10.2 From e8165dbb03ed04d798163ee512074b9a9466a9c8 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 3 Sep 2009 19:13:05 -0400 Subject: tracing: report error in trace if we fail to swap latency buffer The irqsoff tracer will fail to swap the cpu buffer with the max buffer if it preempts a commit. Instead of ignoring this, this patch makes the tracer report it if the last max latency failed due to preempting a current commit. The output of the latency tracer will look like this: # tracer: irqsoff # # irqsoff latency trace v1.1.5 on 2.6.31-rc5 # -------------------------------------------------------------------- # latency: 112 us, #1/1, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4) # ----------------- # | task: -4281 (uid:0 nice:0 policy:0 rt_prio:0) # ----------------- # => started at: save_args # => ended at: __do_softirq # # # _------=> CPU# # / _-----=> irqs-off # | / _----=> need-resched # || / _---=> hardirq/softirq # ||| / _--=> preempt-depth # |||| / # ||||| delay # cmd pid ||||| time | caller # \ / ||||| \ | / bash-4281 1d.s6 265us : update_max_tr_single: Failed to swap buffers due to commit in progress Note the latency time and the functions that disabled the irqs or preemption will still be listed. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index ef08328..6df9861 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -482,9 +482,20 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu) ret = ring_buffer_swap_cpu(max_tr.buffer, tr->buffer, cpu); + if (ret == -EBUSY) { + /* + * We failed to swap the buffer due to a commit taking + * place on this CPU. We fail to record, but we reset + * the max trace buffer (no one writes directly to it) + * and flag that it failed. + */ + trace_array_printk(&max_tr, _THIS_IP_, + "Failed to swap buffers due to commit in progress\n"); + } + ftrace_enable_cpu(); - WARN_ON_ONCE(ret && ret != -EAGAIN); + WARN_ON_ONCE(ret && ret != -EAGAIN && ret != -EBUSY); __update_max_tr(tr, tsk, cpu); __raw_spin_unlock(&ftrace_max_lock); -- cgit v0.10.2 From 62f0b3eb5cb58931a02ee4e599e19c80a171e351 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 4 Sep 2009 14:11:34 -0400 Subject: ring-buffer: check for swapped buffers in start of committing Because the irqsoff tracer can swap an internal CPU buffer, it is possible that a swap happens between the start of the write and before the committing bit is set (the committing bit will disable swapping). This patch adds a check for this and will fail the write if it detects it. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index f83a42a..1766c0e 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2073,7 +2073,8 @@ static void rb_end_commit(struct ring_buffer_per_cpu *cpu_buffer) } static struct ring_buffer_event * -rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer, +rb_reserve_next_event(struct ring_buffer *buffer, + struct ring_buffer_per_cpu *cpu_buffer, unsigned long length) { struct ring_buffer_event *event; @@ -2083,6 +2084,19 @@ rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer, rb_start_commit(cpu_buffer); + /* + * Due to the ability to swap a cpu buffer from a buffer + * it is possible it was swapped before we committed. + * (committing stops a swap). We check for it here and + * if it happened, we have to fail the write. + */ + barrier(); + if (unlikely(ACCESS_ONCE(cpu_buffer->buffer) != buffer)) { + local_dec(&cpu_buffer->committing); + local_dec(&cpu_buffer->commits); + return NULL; + } + length = rb_calculate_event_length(length); again: /* @@ -2243,7 +2257,7 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length) if (length > BUF_MAX_DATA_SIZE) goto out; - event = rb_reserve_next_event(cpu_buffer, length); + event = rb_reserve_next_event(buffer, cpu_buffer, length); if (!event) goto out; @@ -2476,7 +2490,7 @@ int ring_buffer_write(struct ring_buffer *buffer, if (length > BUF_MAX_DATA_SIZE) goto out; - event = rb_reserve_next_event(cpu_buffer, length); + event = rb_reserve_next_event(buffer, cpu_buffer, length); if (!event) goto out; -- cgit v0.10.2 From 85bac32c4a52c592b857f2c360cc5ec93a097d70 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 4 Sep 2009 14:24:40 -0400 Subject: ring-buffer: only enable ring_buffer_swap_cpu when needed Since the ability to swap the cpu buffers adds a small overhead to the recording of a trace, we only want to add it when needed. Only the irqsoff and preemptoff tracers use this feature, and both are not recommended for production kernels. This patch disables its use when neither irqsoff nor preemptoff is configured. Signed-off-by: Steven Rostedt diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index e061b4e..5fcc31e 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h @@ -140,8 +140,17 @@ unsigned long ring_buffer_size(struct ring_buffer *buffer); void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu); void ring_buffer_reset(struct ring_buffer *buffer); +#ifdef CONFIG_RING_BUFFER_ALLOW_SWAP int ring_buffer_swap_cpu(struct ring_buffer *buffer_a, struct ring_buffer *buffer_b, int cpu); +#else +static inline int +ring_buffer_swap_cpu(struct ring_buffer *buffer_a, + struct ring_buffer *buffer_b, int cpu) +{ + return -ENODEV; +} +#endif int ring_buffer_empty(struct ring_buffer *buffer); int ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu); diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 163fbfc..1ea0d12 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -62,6 +62,12 @@ config EVENT_TRACING config CONTEXT_SWITCH_TRACER bool +config RING_BUFFER_ALLOW_SWAP + bool + help + Allow the use of ring_buffer_swap_cpu. + Adds a very slight overhead to tracing when enabled. + # All tracer options should select GENERIC_TRACER. For those options that are # enabled by all tracers (context switch and event tracer) they select TRACING. # This allows those options to appear when no other tracer is selected. But the @@ -146,6 +152,7 @@ config IRQSOFF_TRACER select TRACE_IRQFLAGS select GENERIC_TRACER select TRACER_MAX_TRACE + select RING_BUFFER_ALLOW_SWAP help This option measures the time spent in irqs-off critical sections, with microsecond accuracy. @@ -167,6 +174,7 @@ config PREEMPT_TRACER depends on PREEMPT select GENERIC_TRACER select TRACER_MAX_TRACE + select RING_BUFFER_ALLOW_SWAP help This option measures the time spent in preemption off critical sections, with microsecond accuracy. diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 1766c0e..454e74e 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2084,6 +2084,7 @@ rb_reserve_next_event(struct ring_buffer *buffer, rb_start_commit(cpu_buffer); +#ifdef CONFIG_RING_BUFFER_ALLOW_SWAP /* * Due to the ability to swap a cpu buffer from a buffer * it is possible it was swapped before we committed. @@ -2096,6 +2097,7 @@ rb_reserve_next_event(struct ring_buffer *buffer, local_dec(&cpu_buffer->commits); return NULL; } +#endif length = rb_calculate_event_length(length); again: @@ -3498,6 +3500,7 @@ int ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu) } EXPORT_SYMBOL_GPL(ring_buffer_empty_cpu); +#ifdef CONFIG_RING_BUFFER_ALLOW_SWAP /** * ring_buffer_swap_cpu - swap a CPU buffer between two ring buffers * @buffer_a: One buffer to swap with @@ -3573,6 +3576,7 @@ out: return ret; } EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu); +#endif /* CONFIG_RING_BUFFER_ALLOW_SWAP */ /** * ring_buffer_alloc_read_page - allocate a page to read from buffer -- cgit v0.10.2 From b1f57195585e376d1944c32c046359640b06a669 Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Fri, 4 Sep 2009 20:36:52 -0700 Subject: netlink: silence compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC net/netlink/genetlink.o net/netlink/genetlink.c: In function ‘genl_register_mc_group’: net/netlink/genetlink.c:139: warning: ‘err’ may be used uninitialized in this function From following the code 'err' is initialized, but set it to zero to silence the warning. Signed-off-by: Brian Haley Signed-off-by: David S. Miller diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 575c643..66f6ba0 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -136,7 +136,7 @@ int genl_register_mc_group(struct genl_family *family, { int id; unsigned long *new_groups; - int err; + int err = 0; BUG_ON(grp->name[0] == '\0'); -- cgit v0.10.2 From c9f1d0389b962521af1e2b699c8ee5e299d77b85 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 4 Sep 2009 06:41:13 +0000 Subject: net_sched: fix class grafting errno codes If the parent qdisc doesn't support classes, use EOPNOTSUPP. If the parent class doesn't exist, use ENOENT. Currently EINVAL is returned in both cases. Additionally check whether grafting is supported and remove a now unnecessary graft function from sch_ingress. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 24d17ce..bef2d64 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -728,14 +728,14 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, } else { const struct Qdisc_class_ops *cops = parent->ops->cl_ops; - err = -EINVAL; - - if (cops) { + err = -EOPNOTSUPP; + if (cops && cops->graft) { unsigned long cl = cops->get(parent, classid); if (cl) { err = cops->graft(parent, cl, new, &old); cops->put(parent, cl); - } + } else + err = -ENOENT; } if (!err) notify_and_destroy(skb, n, classid, old, new); diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index 4a2b773..ace7902 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -22,12 +22,6 @@ struct ingress_qdisc_data { /* ------------------------- Class/flow operations ------------------------- */ -static int ingress_graft(struct Qdisc *sch, unsigned long arg, - struct Qdisc *new, struct Qdisc **old) -{ - return -EOPNOTSUPP; -} - static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg) { return NULL; @@ -123,7 +117,6 @@ nla_put_failure: } static const struct Qdisc_class_ops ingress_class_ops = { - .graft = ingress_graft, .leaf = ingress_leaf, .get = ingress_get, .put = ingress_put, -- cgit v0.10.2 From 81bd5f6c966cf2f137c2759dfc78abdffcff055e Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Sat, 5 Sep 2009 16:27:35 +1000 Subject: crypto: sha-s390 - Fix warnings in import function That patch should fix the warnings. Signed-off-by: Jan Glauber Signed-off-by: Herbert Xu diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index 4a94378..f6de782 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -57,10 +57,10 @@ static int sha1_export(struct shash_desc *desc, void *out) return 0; } -static int sha1_import(struct shash_desc *desc, const u8 *in) +static int sha1_import(struct shash_desc *desc, const void *in) { struct s390_sha_ctx *sctx = shash_desc_ctx(desc); - struct sha1_state *ictx = in; + const struct sha1_state *ictx = in; sctx->count = ictx->count; memcpy(sctx->state, ictx->state, sizeof(ictx->state)); diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index 2bab519..61a7db3 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -53,10 +53,10 @@ static int sha256_export(struct shash_desc *desc, void *out) return 0; } -static int sha256_import(struct shash_desc *desc, const u8 *in) +static int sha256_import(struct shash_desc *desc, const void *in) { struct s390_sha_ctx *sctx = shash_desc_ctx(desc); - struct sha256_state *ictx = in; + const struct sha256_state *ictx = in; sctx->count = ictx->count; memcpy(sctx->state, ictx->state, sizeof(ictx->state)); diff --git a/arch/s390/crypto/sha512_s390.c b/arch/s390/crypto/sha512_s390.c index b4b3438..4bf73d0 100644 --- a/arch/s390/crypto/sha512_s390.c +++ b/arch/s390/crypto/sha512_s390.c @@ -52,10 +52,10 @@ static int sha512_export(struct shash_desc *desc, void *out) return 0; } -static int sha512_import(struct shash_desc *desc, const u8 *in) +static int sha512_import(struct shash_desc *desc, const void *in) { struct s390_sha_ctx *sctx = shash_desc_ctx(desc); - struct sha512_state *ictx = in; + const struct sha512_state *ictx = in; if (unlikely(ictx->count[1])) return -ERANGE; -- cgit v0.10.2 From 3793d2fc3eac7da11ca44df125cbcedd0b5315d0 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 5 Sep 2009 20:22:36 -0700 Subject: RDMA/cxgb3: iwch_unregister_device leaks memory The iwcm struct mem is never freed. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index e2a6321..72aa57c 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -1418,6 +1418,7 @@ int iwch_register_device(struct iwch_dev *dev) bail2: ib_unregister_device(&dev->ibdev); bail1: + kfree(dev->ibdev.iwcm); return ret; } @@ -1430,5 +1431,6 @@ void iwch_unregister_device(struct iwch_dev *dev) device_remove_file(&dev->ibdev.dev, iwch_class_attributes[i]); ib_unregister_device(&dev->ibdev); + kfree(dev->ibdev.iwcm); return; } -- cgit v0.10.2 From b496fe82d4075847a1c42efba2e81d28f6467b3a Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 5 Sep 2009 20:22:37 -0700 Subject: RDMA/cxgb3: Set the appropriate IO channel in rdma_init work requests Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 62f9cf2..4dec515 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -852,7 +852,9 @@ int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr) wqe->qpcaps = attr->qpcaps; wqe->ulpdu_size = cpu_to_be16(attr->tcp_emss); wqe->rqe_count = cpu_to_be16(attr->rqe_count); - wqe->flags_rtr_type = cpu_to_be16(attr->flags|V_RTR_TYPE(attr->rtr_type)); + wqe->flags_rtr_type = cpu_to_be16(attr->flags | + V_RTR_TYPE(attr->rtr_type) | + V_CHAN(attr->chan)); wqe->ord = cpu_to_be32(attr->ord); wqe->ird = cpu_to_be32(attr->ird); wqe->qp_dma_addr = cpu_to_be64(attr->qp_dma_addr); diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index 32e3b14..a197a5b 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -327,6 +327,11 @@ enum rdma_init_rtr_types { #define V_RTR_TYPE(x) ((x) << S_RTR_TYPE) #define G_RTR_TYPE(x) ((((x) >> S_RTR_TYPE)) & M_RTR_TYPE) +#define S_CHAN 4 +#define M_CHAN 0x3 +#define V_CHAN(x) ((x) << S_CHAN) +#define G_CHAN(x) ((((x) >> S_CHAN)) & M_CHAN) + struct t3_rdma_init_attr { u32 tid; u32 qpid; @@ -346,6 +351,7 @@ struct t3_rdma_init_attr { u16 flags; u16 rqe_count; u32 irs; + u32 chan; }; struct t3_rdma_init_wr { diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index 27bbdc8..6e86534 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -889,6 +889,7 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, init_attr.qp_dma_size = (1UL << qhp->wq.size_log2); init_attr.rqe_count = iwch_rqes_posted(qhp); init_attr.flags = qhp->attr.mpa_attr.initiator ? MPA_INITIATOR : 0; + init_attr.chan = qhp->ep->l2t->smt_idx; if (peer2peer) { init_attr.rtr_type = RTR_READ; if (init_attr.ord == 0 && qhp->attr.mpa_attr.initiator) -- cgit v0.10.2 From fa0d4c11c4b6eb49708b82b638ceb0761152f46a Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 5 Sep 2009 20:22:38 -0700 Subject: RDMA/cxgb3: Handle port events properly Massage the err_handler upcall into an event handler upcall, pass netdev port events to the cxgb3 ULPs and generate RDMA port events based on LLD port events. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index 26fc0a4..5796170 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -51,7 +51,7 @@ cxgb3_cpl_handler_func t3c_handlers[NUM_CPL_CMDS]; static void open_rnic_dev(struct t3cdev *); static void close_rnic_dev(struct t3cdev *); -static void iwch_err_handler(struct t3cdev *, u32, u32); +static void iwch_event_handler(struct t3cdev *, u32, u32); struct cxgb3_client t3c_client = { .name = "iw_cxgb3", @@ -59,7 +59,7 @@ struct cxgb3_client t3c_client = { .remove = close_rnic_dev, .handlers = t3c_handlers, .redirect = iwch_ep_redirect, - .err_handler = iwch_err_handler + .event_handler = iwch_event_handler }; static LIST_HEAD(dev_list); @@ -162,21 +162,33 @@ static void close_rnic_dev(struct t3cdev *tdev) mutex_unlock(&dev_mutex); } -static void iwch_err_handler(struct t3cdev *tdev, u32 status, u32 error) +static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id) { struct cxio_rdev *rdev = tdev->ulp; struct iwch_dev *rnicp = rdev_to_iwch_dev(rdev); struct ib_event event; + u32 portnum = port_id + 1; - if (status == OFFLOAD_STATUS_DOWN) { + switch (evt) { + case OFFLOAD_STATUS_DOWN: { rdev->flags = CXIO_ERROR_FATAL; - - event.device = &rnicp->ibdev; event.event = IB_EVENT_DEVICE_FATAL; - event.element.port_num = 0; - ib_dispatch_event(&event); + break; + } + case OFFLOAD_PORT_DOWN: { + event.event = IB_EVENT_PORT_ERR; + break; + } + case OFFLOAD_PORT_UP: { + event.event = IB_EVENT_PORT_ACTIVE; + break; + } } + event.device = &rnicp->ibdev; + event.element.port_num = portnum; + ib_dispatch_event(&event); + return; } diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index fb5df5c..c97ab82 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1286,6 +1286,7 @@ static int cxgb_open(struct net_device *dev) if (!other_ports) schedule_chk_task(adapter); + cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_UP, pi->port_id); return 0; } @@ -1318,6 +1319,7 @@ static int cxgb_close(struct net_device *dev) if (!adapter->open_device_map) cxgb_down(adapter); + cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_DOWN, pi->port_id); return 0; } @@ -2717,7 +2719,7 @@ static int t3_adapter_error(struct adapter *adapter, int reset) if (is_offload(adapter) && test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { - cxgb3_err_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0); + cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0); offload_close(&adapter->tdev); } @@ -2782,7 +2784,7 @@ static void t3_resume_ports(struct adapter *adapter) } if (is_offload(adapter) && !ofld_disable) - cxgb3_err_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0); + cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0); } /* diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index f9f54b5..75064ee 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -153,14 +153,14 @@ void cxgb3_remove_clients(struct t3cdev *tdev) mutex_unlock(&cxgb3_db_lock); } -void cxgb3_err_notify(struct t3cdev *tdev, u32 status, u32 error) +void cxgb3_event_notify(struct t3cdev *tdev, u32 event, u32 port) { struct cxgb3_client *client; mutex_lock(&cxgb3_db_lock); list_for_each_entry(client, &client_list, client_list) { - if (client->err_handler) - client->err_handler(tdev, status, error); + if (client->event_handler) + client->event_handler(tdev, event, port); } mutex_unlock(&cxgb3_db_lock); } diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h index 55945f4..670aa62 100644 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -64,14 +64,16 @@ void cxgb3_register_client(struct cxgb3_client *client); void cxgb3_unregister_client(struct cxgb3_client *client); void cxgb3_add_clients(struct t3cdev *tdev); void cxgb3_remove_clients(struct t3cdev *tdev); -void cxgb3_err_notify(struct t3cdev *tdev, u32 status, u32 error); +void cxgb3_event_notify(struct t3cdev *tdev, u32 event, u32 port); typedef int (*cxgb3_cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb, void *ctx); enum { OFFLOAD_STATUS_UP, - OFFLOAD_STATUS_DOWN + OFFLOAD_STATUS_DOWN, + OFFLOAD_PORT_DOWN, + OFFLOAD_PORT_UP }; struct cxgb3_client { @@ -82,7 +84,7 @@ struct cxgb3_client { int (*redirect)(void *ctx, struct dst_entry *old, struct dst_entry *new, struct l2t_entry *l2t); struct list_head client_list; - void (*err_handler)(struct t3cdev *tdev, u32 status, u32 error); + void (*event_handler)(struct t3cdev *tdev, u32 event, u32 port); }; /* diff --git a/drivers/scsi/cxgb3i/cxgb3i_init.c b/drivers/scsi/cxgb3i/cxgb3i_init.c index 042d9bc..d0ab23a 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_init.c +++ b/drivers/scsi/cxgb3i/cxgb3i_init.c @@ -26,7 +26,7 @@ MODULE_VERSION(DRV_MODULE_VERSION); static void open_s3_dev(struct t3cdev *); static void close_s3_dev(struct t3cdev *); -static void s3_err_handler(struct t3cdev *tdev, u32 status, u32 error); +static void s3_event_handler(struct t3cdev *tdev, u32 event, u32 port); static cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS]; static struct cxgb3_client t3c_client = { @@ -34,7 +34,7 @@ static struct cxgb3_client t3c_client = { .handlers = cxgb3i_cpl_handlers, .add = open_s3_dev, .remove = close_s3_dev, - .err_handler = s3_err_handler, + .event_handler = s3_event_handler, }; /** @@ -66,16 +66,16 @@ static void close_s3_dev(struct t3cdev *t3dev) cxgb3i_ddp_cleanup(t3dev); } -static void s3_err_handler(struct t3cdev *tdev, u32 status, u32 error) +static void s3_event_handler(struct t3cdev *tdev, u32 event, u32 port) { struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(tdev); - cxgb3i_log_info("snic 0x%p, tdev 0x%p, status 0x%x, err 0x%x.\n", - snic, tdev, status, error); + cxgb3i_log_info("snic 0x%p, tdev 0x%p, event 0x%x, port 0x%x.\n", + snic, tdev, event, port); if (!snic) return; - switch (status) { + switch (event) { case OFFLOAD_STATUS_DOWN: snic->flags |= CXGB3I_ADAPTER_FLAG_RESET; break; -- cgit v0.10.2 From 6e47fe43502ba6dfe86d556661795d9bb0361309 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 5 Sep 2009 20:22:38 -0700 Subject: RDMA/cxgb3: Don't free endpoints early - Keep ref on connection request endpoints until either accepted or rejected so it doesn't get freed early. - Endpoint flags now need to be set via atomic bitops because they can be set on both the iw_cxgb3 workqueue thread and user disconnect threads. - Don't move out of CLOSING too early due to multiple calls to iwch_ep_disconnect. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 52d7bb0..7f22f17 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -286,7 +286,7 @@ void __free_ep(struct kref *kref) ep = container_of(container_of(kref, struct iwch_ep_common, kref), struct iwch_ep, com); PDBG("%s ep %p state %s\n", __func__, ep, states[state_read(&ep->com)]); - if (ep->com.flags & RELEASE_RESOURCES) { + if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) { cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid); dst_release(ep->dst); l2t_release(L2DATA(ep->com.tdev), ep->l2t); @@ -297,7 +297,7 @@ void __free_ep(struct kref *kref) static void release_ep_resources(struct iwch_ep *ep) { PDBG("%s ep %p tid %d\n", __func__, ep, ep->hwtid); - ep->com.flags |= RELEASE_RESOURCES; + set_bit(RELEASE_RESOURCES, &ep->com.flags); put_ep(&ep->com); } @@ -786,10 +786,12 @@ static void connect_request_upcall(struct iwch_ep *ep) event.private_data_len = ep->plen; event.private_data = ep->mpa_pkt + sizeof(struct mpa_message); event.provider_data = ep; - if (state_read(&ep->parent_ep->com) != DEAD) + if (state_read(&ep->parent_ep->com) != DEAD) { + get_ep(&ep->com); ep->parent_ep->com.cm_id->event_handler( ep->parent_ep->com.cm_id, &event); + } put_ep(&ep->parent_ep->com); ep->parent_ep = NULL; } @@ -1156,8 +1158,7 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) * We get 2 abort replies from the HW. The first one must * be ignored except for scribbling that we need one more. */ - if (!(ep->com.flags & ABORT_REQ_IN_PROGRESS)) { - ep->com.flags |= ABORT_REQ_IN_PROGRESS; + if (!test_and_set_bit(ABORT_REQ_IN_PROGRESS, &ep->com.flags)) { return CPL_RET_BUF_DONE; } @@ -1480,7 +1481,6 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) * rejects the CR. */ __state_set(&ep->com, CLOSING); - get_ep(&ep->com); break; case MPA_REP_SENT: __state_set(&ep->com, CLOSING); @@ -1561,8 +1561,7 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) * We get 2 peer aborts from the HW. The first one must * be ignored except for scribbling that we need one more. */ - if (!(ep->com.flags & PEER_ABORT_IN_PROGRESS)) { - ep->com.flags |= PEER_ABORT_IN_PROGRESS; + if (!test_and_set_bit(PEER_ABORT_IN_PROGRESS, &ep->com.flags)) { return CPL_RET_BUF_DONE; } @@ -1591,7 +1590,6 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) * the reference on it until the ULP accepts or * rejects the CR. */ - get_ep(&ep->com); break; case MORIBUND: case CLOSING: @@ -1797,6 +1795,7 @@ int iwch_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) err = send_mpa_reject(ep, pdata, pdata_len); err = iwch_ep_disconnect(ep, 0, GFP_KERNEL); } + put_ep(&ep->com); return 0; } @@ -1810,8 +1809,10 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) struct iwch_qp *qp = get_qhp(h, conn_param->qpn); PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); - if (state_read(&ep->com) == DEAD) - return -ECONNRESET; + if (state_read(&ep->com) == DEAD) { + err = -ECONNRESET; + goto err; + } BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD); BUG_ON(!qp); @@ -1819,7 +1820,8 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) if ((conn_param->ord > qp->rhp->attr.max_rdma_read_qp_depth) || (conn_param->ird > qp->rhp->attr.max_rdma_reads_per_qp)) { abort_connection(ep, NULL, GFP_KERNEL); - return -EINVAL; + err = -EINVAL; + goto err; } cm_id->add_ref(cm_id); @@ -1836,8 +1838,6 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) PDBG("%s %d ird %d ord %d\n", __func__, __LINE__, ep->ird, ep->ord); - get_ep(&ep->com); - /* bind QP to EP and move to RTS */ attrs.mpa_attr = ep->mpa_attr; attrs.max_ird = ep->ird; @@ -1855,30 +1855,31 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) err = iwch_modify_qp(ep->com.qp->rhp, ep->com.qp, mask, &attrs, 1); if (err) - goto err; + goto err1; /* if needed, wait for wr_ack */ if (iwch_rqes_posted(qp)) { wait_event(ep->com.waitq, ep->com.rpl_done); err = ep->com.rpl_err; if (err) - goto err; + goto err1; } err = send_mpa_reply(ep, conn_param->private_data, conn_param->private_data_len); if (err) - goto err; + goto err1; state_set(&ep->com, FPDU_MODE); established_upcall(ep); put_ep(&ep->com); return 0; -err: +err1: ep->com.cm_id = NULL; ep->com.qp = NULL; cm_id->rem_ref(cm_id); +err: put_ep(&ep->com); return err; } @@ -2097,14 +2098,17 @@ int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp) ep->com.state = CLOSING; start_ep_timer(ep); } + set_bit(CLOSE_SENT, &ep->com.flags); break; case CLOSING: - close = 1; - if (abrupt) { - stop_ep_timer(ep); - ep->com.state = ABORTING; - } else - ep->com.state = MORIBUND; + if (!test_and_set_bit(CLOSE_SENT, &ep->com.flags)) { + close = 1; + if (abrupt) { + stop_ep_timer(ep); + ep->com.state = ABORTING; + } else + ep->com.state = MORIBUND; + } break; case MORIBUND: case ABORTING: diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h index 43c0aea..b9efadf 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.h +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h @@ -145,9 +145,10 @@ enum iwch_ep_state { }; enum iwch_ep_flags { - PEER_ABORT_IN_PROGRESS = (1 << 0), - ABORT_REQ_IN_PROGRESS = (1 << 1), - RELEASE_RESOURCES = (1 << 2), + PEER_ABORT_IN_PROGRESS = 0, + ABORT_REQ_IN_PROGRESS = 1, + RELEASE_RESOURCES = 2, + CLOSE_SENT = 3, }; struct iwch_ep_common { @@ -162,7 +163,7 @@ struct iwch_ep_common { wait_queue_head_t waitq; int rpl_done; int rpl_err; - u32 flags; + unsigned long flags; }; struct iwch_listen_ep { -- cgit v0.10.2 From a52bf98d99e922363d1d600a79de6aaf00090d47 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 5 Sep 2009 20:22:38 -0700 Subject: RDMA/cxgb3: Wake up any waiters on peer close/abort A close/abort while waiting for a wr_ack during connection migration can cause a hung process in iwch_accept_cr/iwch_reject_cr. The fix is to set rpl_error/rpl_done and wake up the waiters when we get a close/abort while in MPA_REQ_RCVD state. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 7f22f17..66b4135 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -1478,9 +1478,14 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) /* * We're gonna mark this puppy DEAD, but keep * the reference on it until the ULP accepts or - * rejects the CR. + * rejects the CR. Also wake up anyone waiting + * in rdma connection migration (see iwch_accept_cr()). */ __state_set(&ep->com, CLOSING); + ep->com.rpl_done = 1; + ep->com.rpl_err = -ECONNRESET; + PDBG("waking up ep %p\n", ep); + wake_up(&ep->com.waitq); break; case MPA_REP_SENT: __state_set(&ep->com, CLOSING); @@ -1588,8 +1593,13 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) /* * We're gonna mark this puppy DEAD, but keep * the reference on it until the ULP accepts or - * rejects the CR. + * rejects the CR. Also wake up anyone waiting + * in rdma connection migration (see iwch_accept_cr()). */ + ep->com.rpl_done = 1; + ep->com.rpl_err = -ECONNRESET; + PDBG("waking up ep %p\n", ep); + wake_up(&ep->com.waitq); break; case MORIBUND: case CLOSING: @@ -1828,8 +1838,6 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ep->com.cm_id = cm_id; ep->com.qp = qp; - ep->com.rpl_done = 0; - ep->com.rpl_err = 0; ep->ird = conn_param->ird; ep->ord = conn_param->ord; -- cgit v0.10.2 From 50d40b8e53fab58b0141a75f7448eb28f9e21338 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Sat, 5 Sep 2009 20:22:54 -0700 Subject: IB/ehca: Make port autodetect mode the default Make port autodetect mode the default for the ehca driver. The autodetect code has been in the kernel for several releases now and has proved to be stable. Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index fab18a2..5b635aa 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -52,7 +52,7 @@ #include "ehca_tools.h" #include "hcp_if.h" -#define HCAD_VERSION "0028" +#define HCAD_VERSION "0029" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch "); @@ -64,7 +64,7 @@ static int ehca_hw_level = 0; static int ehca_poll_all_eqs = 1; int ehca_debug_level = 0; -int ehca_nr_ports = 2; +int ehca_nr_ports = -1; int ehca_use_hp_mr = 0; int ehca_port_act_time = 30; int ehca_static_rate = -1; @@ -95,8 +95,8 @@ MODULE_PARM_DESC(hw_level, "Hardware level (0: autosensing (default), " "0x10..0x14: eHCA, 0x20..0x23: eHCA2)"); MODULE_PARM_DESC(nr_ports, - "number of connected ports (-1: autodetect, 1: port one only, " - "2: two ports (default)"); + "number of connected ports (-1: autodetect (default), " + "1: port one only, 2: two ports)"); MODULE_PARM_DESC(use_hp_mr, "Use high performance MRs (default: no)"); MODULE_PARM_DESC(port_act_time, -- cgit v0.10.2 From d706834d995939c96b4952bf042918879b4db18b Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Sat, 5 Sep 2009 20:22:55 -0700 Subject: IB/ehca: Construct MAD redirect replies from request MAD The old code used a lot of hard-coded values, which might not be valid in all environments (especially routed fabrics or partitioned subnets). Copy as much information as possible from the incoming request to correct that. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c index c568b28..8c1213f 100644 --- a/drivers/infiniband/hw/ehca/ehca_sqp.c +++ b/drivers/infiniband/hw/ehca/ehca_sqp.c @@ -125,14 +125,30 @@ struct ib_perf { u8 data[192]; } __attribute__ ((packed)); +/* TC/SL/FL packed into 32 bits, as in ClassPortInfo */ +struct tcslfl { + u32 tc:8; + u32 sl:4; + u32 fl:20; +} __attribute__ ((packed)); + +/* IP Version/TC/FL packed into 32 bits, as in GRH */ +struct vertcfl { + u32 ver:4; + u32 tc:8; + u32 fl:20; +} __attribute__ ((packed)); static int ehca_process_perf(struct ib_device *ibdev, u8 port_num, + struct ib_wc *in_wc, struct ib_grh *in_grh, struct ib_mad *in_mad, struct ib_mad *out_mad) { struct ib_perf *in_perf = (struct ib_perf *)in_mad; struct ib_perf *out_perf = (struct ib_perf *)out_mad; struct ib_class_port_info *poi = (struct ib_class_port_info *)out_perf->data; + struct tcslfl *tcslfl = + (struct tcslfl *)&poi->redirect_tcslfl; struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device); struct ehca_sport *sport = &shca->sport[port_num - 1]; @@ -158,10 +174,29 @@ static int ehca_process_perf(struct ib_device *ibdev, u8 port_num, poi->base_version = 1; poi->class_version = 1; poi->resp_time_value = 18; - poi->redirect_lid = sport->saved_attr.lid; - poi->redirect_qp = sport->pma_qp_nr; + + /* copy local routing information from WC where applicable */ + tcslfl->sl = in_wc->sl; + poi->redirect_lid = + sport->saved_attr.lid | in_wc->dlid_path_bits; + poi->redirect_qp = sport->pma_qp_nr; poi->redirect_qkey = IB_QP1_QKEY; - poi->redirect_pkey = IB_DEFAULT_PKEY_FULL; + + ehca_query_pkey(ibdev, port_num, in_wc->pkey_index, + &poi->redirect_pkey); + + /* if request was globally routed, copy route info */ + if (in_grh) { + struct vertcfl *vertcfl = + (struct vertcfl *)&in_grh->version_tclass_flow; + memcpy(poi->redirect_gid, in_grh->dgid.raw, + sizeof(poi->redirect_gid)); + tcslfl->tc = vertcfl->tc; + tcslfl->fl = vertcfl->fl; + } else + /* else only fill in default GID */ + ehca_query_gid(ibdev, port_num, 0, + (union ib_gid *)&poi->redirect_gid); ehca_dbg(ibdev, "ehca_pma_lid=%x ehca_pma_qp=%x", sport->saved_attr.lid, sport->pma_qp_nr); @@ -183,8 +218,7 @@ perf_reply: int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, struct ib_wc *in_wc, struct ib_grh *in_grh, - struct ib_mad *in_mad, - struct ib_mad *out_mad) + struct ib_mad *in_mad, struct ib_mad *out_mad) { int ret; @@ -196,7 +230,8 @@ int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, return IB_MAD_RESULT_SUCCESS; ehca_dbg(ibdev, "port_num=%x src_qp=%x", port_num, in_wc->src_qp); - ret = ehca_process_perf(ibdev, port_num, in_mad, out_mad); + ret = ehca_process_perf(ibdev, port_num, in_wc, in_grh, + in_mad, out_mad); return ret; } -- cgit v0.10.2 From 6303e74c699d6ba8bd3d44ec6898b2d6aa55d788 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Sat, 5 Sep 2009 20:22:55 -0700 Subject: IB/ehca: Fix CQE flags reporting The driver was reporting CQE flags in the wrong bit positions, causing consumers to miss incoming immediate data. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index 5a3d96f..8fd88cd 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -786,7 +786,11 @@ repoll: wc->slid = cqe->rlid; wc->dlid_path_bits = cqe->dlid; wc->src_qp = cqe->remote_qp_number; - wc->wc_flags = cqe->w_completion_flags; + /* + * HW has "Immed data present" and "GRH present" in bits 6 and 5. + * SW defines those in bits 1 and 0, so we can just shift and mask. + */ + wc->wc_flags = (cqe->w_completion_flags >> 5) & 3; wc->ex.imm_data = cpu_to_be32(cqe->immediate_data); wc->sl = cqe->service_level; -- cgit v0.10.2 From 286b63d09660de0fbd0d7748984d7ae491c7fdb6 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sat, 5 Sep 2009 20:23:21 -0700 Subject: IB/ipath: strncpy() doesn't always NUL-terminate strlcpy() will always null terminate the string. node_desc is not guaranteed to be NUL-terminated so just use memcpy(). Signed-off-by: Roel Kluin Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 2317398..38a2870 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -1616,7 +1616,7 @@ static int try_alloc_port(struct ipath_devdata *dd, int port, pd->port_cnt = 1; port_fp(fp) = pd; pd->port_pid = get_pid(task_pid(current)); - strncpy(pd->port_comm, current->comm, sizeof(pd->port_comm)); + strlcpy(pd->port_comm, current->comm, sizeof(pd->port_comm)); ipath_stats.sps_ports++; ret = 0; } else diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index 16a702d..ceb98ee 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -60,7 +60,7 @@ static int recv_subn_get_nodedescription(struct ib_smp *smp, if (smp->attr_mod) smp->status |= IB_SMP_INVALID_FIELD; - strncpy(smp->data, ibdev->node_desc, sizeof(smp->data)); + memcpy(smp->data, ibdev->node_desc, sizeof(smp->data)); return reply(smp); } -- cgit v0.10.2 From cd0bcf4cb963a147baf0b79d94c25ba86220f708 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:23:38 -0700 Subject: IPoIB: Remove unused includes Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 181b1f3..8f4b4fc 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -31,7 +31,6 @@ */ #include -#include #include #include #include diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index e7e5adf..e35f4a0 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -36,7 +36,6 @@ #include #include -#include #include #include -- cgit v0.10.2 From 721d67cdca5b7642b380ca0584de8dceecf6102f Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:23:40 -0700 Subject: IPoIB: Drop priv->lock before calling ipoib_send() IPoIB currently must use irqsave locking for priv->lock, since it is taken from interrupt context in one path. However, ipoib_send() does skb_orphan(), and the network stack locking is not IRQ-safe. Therefore we need to make sure we don't hold priv->lock when calling ipoib_send() to avoid lockdep warnings (the code was almost certainly safe in practice, since the only code path that takes priv->lock from interrupt context would never call into the network stack). Addresses: http://bugzilla.kernel.org/show_bug.cgi?id=13757 Reported-by: Bart Van Assche Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index e319d91..2bf5116 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -604,8 +604,11 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) skb_queue_len(&neigh->queue)); goto err_drop; } - } else + } else { + spin_unlock_irqrestore(&priv->lock, flags); ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha)); + return; + } } else { neigh->ah = NULL; @@ -688,7 +691,9 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, ipoib_dbg(priv, "Send unicast ARP to %04x\n", be16_to_cpu(path->pathrec.dlid)); + spin_unlock_irqrestore(&priv->lock, flags); ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr)); + return; } else if ((path->query || !path_rec_start(dev, path)) && skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { /* put pseudoheader back on for next time */ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index a0e9753..a0825fe 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -720,7 +720,9 @@ out: } } + spin_unlock_irqrestore(&priv->lock, flags); ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN); + return; } unlock: -- cgit v0.10.2 From 5e47596bee12597824a3b5b21e20f80b61e58a35 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sat, 5 Sep 2009 20:23:40 -0700 Subject: IPoIB: Check multicast address format Check that the format of multicast link addresses is correct before taking them from dev->mc_list to priv->multicast_list. This way we never try to send a bogus address to the SA, which prevents badness from erronous 'ip maddr addr add', broken bonding drivers, etc. Signed-off-by: Jason Gunthorpe Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index a0825fe..25874fc 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -760,6 +760,20 @@ void ipoib_mcast_dev_flush(struct net_device *dev) } } +static int ipoib_mcast_addr_is_valid(const u8 *addr, unsigned int addrlen, + const u8 *broadcast) +{ + if (addrlen != INFINIBAND_ALEN) + return 0; + /* reserved QPN, prefix, scope */ + if (memcmp(addr, broadcast, 6)) + return 0; + /* signature lower, pkey */ + if (memcmp(addr + 7, broadcast + 7, 3)) + return 0; + return 1; +} + void ipoib_mcast_restart_task(struct work_struct *work) { struct ipoib_dev_priv *priv = @@ -793,6 +807,11 @@ void ipoib_mcast_restart_task(struct work_struct *work) for (mclist = dev->mc_list; mclist; mclist = mclist->next) { union ib_gid mgid; + if (!ipoib_mcast_addr_is_valid(mclist->dmi_addr, + mclist->dmi_addrlen, + dev->broadcast)) + continue; + memcpy(mgid.raw, mclist->dmi_addr + 4, sizeof mgid); mcast = __ipoib_mcast_find(dev, &mgid); -- cgit v0.10.2 From 60f2b652f54aa4ac4127a538abad05235fb9c469 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:10 -0700 Subject: IB/mad: Check hop count field in directed route MAD to avoid array overflow The hop count field in a directed route MAD is only allowed to be in the range 0 to 63 (by spec). Check that this really is the case to avoid accessing outside the bounds of the hop array. Reported-by: Roel Kluin Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/smi.c b/drivers/infiniband/core/smi.c index 8723675..5855e44 100644 --- a/drivers/infiniband/core/smi.c +++ b/drivers/infiniband/core/smi.c @@ -52,6 +52,10 @@ enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, hop_cnt = smp->hop_cnt; /* See section 14.2.2.2, Vol 1 IB spec */ + /* C14-6 -- valid hop_cnt values are from 0 to 63 */ + if (hop_cnt >= IB_SMP_MAX_PATH_HOPS) + return IB_SMI_DISCARD; + if (!ib_get_smp_direction(smp)) { /* C14-9:1 */ if (hop_cnt && hop_ptr == 0) { @@ -133,6 +137,10 @@ enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, hop_cnt = smp->hop_cnt; /* See section 14.2.2.2, Vol 1 IB spec */ + /* C14-6 -- valid hop_cnt values are from 0 to 63 */ + if (hop_cnt >= IB_SMP_MAX_PATH_HOPS) + return IB_SMI_DISCARD; + if (!ib_get_smp_direction(smp)) { /* C14-9:1 -- sender should have incremented hop_ptr */ if (hop_cnt && hop_ptr == 0) -- cgit v0.10.2 From 6276e08a9bdf645b71a092fb4530baf4f6c4c6eb Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:23 -0700 Subject: IB: Use DEFINE_SPINLOCK() for static spinlocks Rather than just defining static spinlock_t variables and then initializing them later in init functions, simply define them with DEFINE_SPINLOCK() and remove the calls to spin_lock_init(). This cleans up the source a tad and also shrinks the compiled code; eg on x86-64: add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-40 (-40) function old new delta ib_uverbs_init 336 326 -10 ib_mad_init_module 147 137 -10 ib_sa_init 123 103 -20 Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index de922a0..5cef8f8 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -51,8 +51,7 @@ static struct list_head ib_mad_port_list; static u32 ib_mad_client_id = 0; /* Port list lock */ -static spinlock_t ib_mad_port_list_lock; - +static DEFINE_SPINLOCK(ib_mad_port_list_lock); /* Forward declarations */ static int method_in_use(struct ib_mad_mgmt_method_table **method, @@ -2984,8 +2983,6 @@ static int __init ib_mad_init_module(void) { int ret; - spin_lock_init(&ib_mad_port_list_lock); - ib_mad_cache = kmem_cache_create("ib_mad", sizeof(struct ib_mad_private), 0, @@ -3021,4 +3018,3 @@ static void __exit ib_mad_cleanup_module(void) module_init(ib_mad_init_module); module_exit(ib_mad_cleanup_module); - diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 1865049..8254371 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -109,10 +109,10 @@ static struct ib_client sa_client = { .remove = ib_sa_remove_one }; -static spinlock_t idr_lock; +static DEFINE_SPINLOCK(idr_lock); static DEFINE_IDR(query_idr); -static spinlock_t tid_lock; +static DEFINE_SPINLOCK(tid_lock); static u32 tid; #define PATH_REC_FIELD(field) \ @@ -1077,9 +1077,6 @@ static int __init ib_sa_init(void) { int ret; - spin_lock_init(&idr_lock); - spin_lock_init(&tid_lock); - get_random_bytes(&tid, sizeof tid); ret = ib_register_client(&sa_client); diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index eb36a81..1a3ac3d 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -73,7 +73,7 @@ DEFINE_IDR(ib_uverbs_cq_idr); DEFINE_IDR(ib_uverbs_qp_idr); DEFINE_IDR(ib_uverbs_srq_idr); -static spinlock_t map_lock; +static DEFINE_SPINLOCK(map_lock); static struct ib_uverbs_device *dev_table[IB_UVERBS_MAX_DEVICES]; static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); @@ -836,8 +836,6 @@ static int __init ib_uverbs_init(void) { int ret; - spin_lock_init(&map_lock); - ret = register_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES, "infiniband_verbs"); if (ret) { -- cgit v0.10.2 From 181c74e87eb93df447a759af93cf0a279875ea7d Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sat, 5 Sep 2009 20:24:23 -0700 Subject: RDMA/amso1100: Use %pM conversion specifier Use the %pM conversion specifier to print a MAC address. Signed-off-by: Tobias Klauser Acked-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c index 0cfbb6d..8250740 100644 --- a/drivers/infiniband/hw/amso1100/c2.c +++ b/drivers/infiniband/hw/amso1100/c2.c @@ -86,11 +86,7 @@ MODULE_DEVICE_TABLE(pci, c2_pci_table); static void c2_print_macaddr(struct net_device *netdev) { - pr_debug("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X, " - "IRQ %u\n", netdev->name, - netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], - netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5], - netdev->irq); + pr_debug("%s: MAC %pM, IRQ %u\n", netdev->name, netdev->dev_addr, netdev->irq); } static void c2_set_rxbufsize(struct c2_port *c2_port) -- cgit v0.10.2 From f1aa78b26e8dabc2956be94a93c40c6cc08eb4a3 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sat, 5 Sep 2009 20:24:24 -0700 Subject: IB: Use printk_once() for driver versions Replace open-coded reimplementations with printk_once(). Signed-off-by: Marcin Slusarz Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index 26fc0a4..9cc99df 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -105,11 +105,9 @@ static void rnic_init(struct iwch_dev *rnicp) static void open_rnic_dev(struct t3cdev *tdev) { struct iwch_dev *rnicp; - static int vers_printed; PDBG("%s t3cdev %p\n", __func__, tdev); - if (!vers_printed++) - printk(KERN_INFO MOD "Chelsio T3 RDMA Driver - version %s\n", + printk_once(KERN_INFO MOD "Chelsio T3 RDMA Driver - version %s\n", DRV_VERSION); rnicp = (struct iwch_dev *)ib_alloc_device(sizeof(*rnicp)); if (!rnicp) { diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index ae3d759..0b2f77a 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -540,15 +540,11 @@ static struct device_attribute *mlx4_class_attributes[] = { static void *mlx4_ib_add(struct mlx4_dev *dev) { - static int mlx4_ib_version_printed; struct mlx4_ib_dev *ibdev; int num_ports = 0; int i; - if (!mlx4_ib_version_printed) { - printk(KERN_INFO "%s", mlx4_ib_version); - ++mlx4_ib_version_printed; - } + printk_once(KERN_INFO "%s", mlx4_ib_version); mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) num_ports++; diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 13da9f1..2e4e043 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -1215,15 +1215,11 @@ int __mthca_restart_one(struct pci_dev *pdev) static int __devinit mthca_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { - static int mthca_version_printed = 0; int ret; mutex_lock(&mthca_device_mutex); - if (!mthca_version_printed) { - printk(KERN_INFO "%s", mthca_version); - ++mthca_version_printed; - } + printk_once(KERN_INFO "%s", mthca_version); if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) { printk(KERN_ERR PFX "%s has invalid driver data %lx\n", -- cgit v0.10.2 From e1d7806df32bd247af6a2fe52433ecdd34fee773 Mon Sep 17 00:00:00 2001 From: Yossi Etigin Date: Sat, 5 Sep 2009 20:24:24 -0700 Subject: IB/core: Fix send multicast group leave retry Until now, retries were only sent when joining a multicast group. This patch will adds retries when leaving a multicast group as well. Signed-off-by: Ron Livne Signed-off-by: Yossi Etigin Acked-by: Sean Hefty Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index 107f170..8d82ba1 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c @@ -106,6 +106,8 @@ struct mcast_group { struct ib_sa_query *query; int query_id; u16 pkey_index; + u8 leave_state; + int retries; }; struct mcast_member { @@ -350,6 +352,7 @@ static int send_leave(struct mcast_group *group, u8 leave_state) rec = group->rec; rec.join_state = leave_state; + group->leave_state = leave_state; ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device, port->port_num, IB_SA_METHOD_DELETE, &rec, @@ -542,7 +545,11 @@ static void leave_handler(int status, struct ib_sa_mcmember_rec *rec, { struct mcast_group *group = context; - mcast_work_handler(&group->work); + if (status && group->retries > 0 && + !send_leave(group, group->leave_state)) + group->retries--; + else + mcast_work_handler(&group->work); } static struct mcast_group *acquire_group(struct mcast_port *port, @@ -565,6 +572,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port, if (!group) return NULL; + group->retries = 3; group->port = port; group->rec.mgid = *mgid; group->pkey_index = MCAST_INVALID_PKEY_INDEX; -- cgit v0.10.2 From b1b8afb83336b66ac7198111aad4ead41132b53f Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Sat, 5 Sep 2009 20:24:24 -0700 Subject: IB/uverbs: Return ENOSYS for unimplemented commands (not EINVAL) Since the original commit 883a99c7 ("[IB] uverbs: Add a mask of device methods allowed for userspace"), the uverbs core returns EINVAL for commands not implemented by a specific low-level driver. This creates a problem that there is no way to tell the difference between an unimplemented command and an implemented one which is incorrectly invoked (which also returns EINVAL). The fix is to have unimplemented commands return ENOSYS. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 1a3ac3d..d3fff9e 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -584,14 +584,16 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, if (hdr.command < 0 || hdr.command >= ARRAY_SIZE(uverbs_cmd_table) || - !uverbs_cmd_table[hdr.command] || - !(file->device->ib_dev->uverbs_cmd_mask & (1ull << hdr.command))) + !uverbs_cmd_table[hdr.command]) return -EINVAL; if (!file->ucontext && hdr.command != IB_USER_VERBS_CMD_GET_CONTEXT) return -EINVAL; + if (!(file->device->ib_dev->uverbs_cmd_mask & (1ull << hdr.command))) + return -ENOSYS; + return uverbs_cmd_table[hdr.command](file, buf + sizeof hdr, hdr.in_words * 4, hdr.out_words * 4); } -- cgit v0.10.2 From 1493ab4083c315a978e51b8957bf87859703745d Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sat, 5 Sep 2009 20:24:24 -0700 Subject: RDMA/amso1100: Check kmalloc() result in c2_register_device() dev->ibdev.iwcm allocation may fail, prevent a dereference. Signed-off-by: Roel Kluin Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index f1948fa..ad723bd 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -780,11 +780,11 @@ int c2_register_device(struct c2_dev *dev) /* Register pseudo network device */ dev->pseudo_netdev = c2_pseudo_netdev_init(dev); if (!dev->pseudo_netdev) - goto out3; + goto out; ret = register_netdev(dev->pseudo_netdev); if (ret) - goto out2; + goto out_free_netdev; pr_debug("%s:%u\n", __func__, __LINE__); strlcpy(dev->ibdev.name, "amso%d", IB_DEVICE_NAME_MAX); @@ -851,6 +851,10 @@ int c2_register_device(struct c2_dev *dev) dev->ibdev.post_recv = c2_post_receive; dev->ibdev.iwcm = kmalloc(sizeof(*dev->ibdev.iwcm), GFP_KERNEL); + if (dev->ibdev.iwcm == NULL) { + ret = -ENOMEM; + goto out_unregister_netdev; + } dev->ibdev.iwcm->add_ref = c2_add_ref; dev->ibdev.iwcm->rem_ref = c2_rem_ref; dev->ibdev.iwcm->get_qp = c2_get_qp; @@ -862,23 +866,25 @@ int c2_register_device(struct c2_dev *dev) ret = ib_register_device(&dev->ibdev); if (ret) - goto out1; + goto out_free_iwcm; for (i = 0; i < ARRAY_SIZE(c2_dev_attributes); ++i) { ret = device_create_file(&dev->ibdev.dev, c2_dev_attributes[i]); if (ret) - goto out0; + goto out_unregister_ibdev; } - goto out3; + goto out; -out0: +out_unregister_ibdev: ib_unregister_device(&dev->ibdev); -out1: +out_free_iwcm: + kfree(dev->ibdev.iwcm); +out_unregister_netdev: unregister_netdev(dev->pseudo_netdev); -out2: +out_free_netdev: free_netdev(dev->pseudo_netdev); -out3: +out: pr_debug("%s:%u ret=%d\n", __func__, __LINE__, ret); return ret; } -- cgit v0.10.2 From a01df0fe5e4db8c272dcc395354884ff7c15fc10 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:48 -0700 Subject: mlx4_core: Use pci_request_regions() The old code used two calls to pci_request_region() to get the two BARs for the mlx4 device, for no particularly good reason. Clean up the code a little by converting this to a single call to pci_request_regions(). Signed-off-by: Roland Dreier diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index dac621b..5c1afe0 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -1070,18 +1070,12 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) goto err_disable_pdev; } - err = pci_request_region(pdev, 0, DRV_NAME); + err = pci_request_regions(pdev, DRV_NAME); if (err) { - dev_err(&pdev->dev, "Cannot request control region, aborting.\n"); + dev_err(&pdev->dev, "Couldn't get PCI resources, aborting\n"); goto err_disable_pdev; } - err = pci_request_region(pdev, 2, DRV_NAME); - if (err) { - dev_err(&pdev->dev, "Cannot request UAR region, aborting.\n"); - goto err_release_bar0; - } - pci_set_master(pdev); err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); @@ -1090,7 +1084,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); - goto err_release_bar2; + goto err_release_regions; } } err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); @@ -1101,7 +1095,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (err) { dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, " "aborting.\n"); - goto err_release_bar2; + goto err_release_regions; } } @@ -1110,7 +1104,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) dev_err(&pdev->dev, "Device struct alloc failed, " "aborting.\n"); err = -ENOMEM; - goto err_release_bar2; + goto err_release_regions; } dev = &priv->dev; @@ -1205,11 +1199,8 @@ err_cmd: err_free_dev: kfree(priv); -err_release_bar2: - pci_release_region(pdev, 2); - -err_release_bar0: - pci_release_region(pdev, 0); +err_release_regions: + pci_release_regions(pdev); err_disable_pdev: pci_disable_device(pdev); @@ -1265,8 +1256,7 @@ static void mlx4_remove_one(struct pci_dev *pdev) pci_disable_msix(pdev); kfree(priv); - pci_release_region(pdev, 2); - pci_release_region(pdev, 0); + pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } -- cgit v0.10.2 From ff149b2a168296c74763cb4a6e7054bdb0a426a1 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:49 -0700 Subject: mlx4_core: Remove unnecessary includes of Lots of mlx4 files with no function annotations included for no reason. Signed-off-by: Roland Dreier diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index ac57b6a..ccfe276 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -34,7 +34,6 @@ * SOFTWARE. */ -#include #include #include diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index b9ceddd..c11a052 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -31,7 +31,6 @@ * SOFTWARE. */ -#include #include #include #include diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c index baf4bf6..04b382f 100644 --- a/drivers/net/mlx4/icm.c +++ b/drivers/net/mlx4/icm.c @@ -31,7 +31,6 @@ * SOFTWARE. */ -#include #include #include #include diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index 6053c35..5ccbce9 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -31,7 +31,6 @@ * SOFTWARE. */ -#include #include #include diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index f96948b..ca7ab8e 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -32,7 +32,6 @@ * SOFTWARE. */ -#include #include #include diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c index 26d1a7a..c4988d6 100644 --- a/drivers/net/mlx4/pd.c +++ b/drivers/net/mlx4/pd.c @@ -31,7 +31,6 @@ * SOFTWARE. */ -#include #include #include diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c index bd22df9..ca25b9d 100644 --- a/drivers/net/mlx4/profile.c +++ b/drivers/net/mlx4/profile.c @@ -32,8 +32,6 @@ * SOFTWARE. */ -#include - #include "mlx4.h" #include "fw.h" diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c index 1c565ef..42ab9fc 100644 --- a/drivers/net/mlx4/qp.c +++ b/drivers/net/mlx4/qp.c @@ -33,8 +33,6 @@ * SOFTWARE. */ -#include - #include #include diff --git a/drivers/net/mlx4/reset.c b/drivers/net/mlx4/reset.c index 3951b88..e5741da 100644 --- a/drivers/net/mlx4/reset.c +++ b/drivers/net/mlx4/reset.c @@ -31,7 +31,6 @@ * SOFTWARE. */ -#include #include #include #include diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c index fe9f218..1377d0d 100644 --- a/drivers/net/mlx4/srq.c +++ b/drivers/net/mlx4/srq.c @@ -31,8 +31,6 @@ * SOFTWARE. */ -#include - #include #include "mlx4.h" -- cgit v0.10.2 From 338a8fad27908f64a0d249cc9f5c7d4ddb7e5684 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:49 -0700 Subject: IB/mlx4: Annotate CQ locking mlx4_ib_lock_cqs()/mlx4_ib_unlock_cqs() are helper functions that lock/unlock both CQs attached to a QP in the proper order to avoid AB-BA deadlocks. Annotate this so sparse can understand what's going on (and warn us if we misuse these functions). Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index c4a0264..219b103 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -615,10 +615,12 @@ static enum mlx4_qp_state to_mlx4_state(enum ib_qp_state state) } static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq) + __acquires(&send_cq->lock) __acquires(&recv_cq->lock) { - if (send_cq == recv_cq) + if (send_cq == recv_cq) { spin_lock_irq(&send_cq->lock); - else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { + __acquire(&recv_cq->lock); + } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { spin_lock_irq(&send_cq->lock); spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); } else { @@ -628,10 +630,12 @@ static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv } static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq) + __releases(&send_cq->lock) __releases(&recv_cq->lock) { - if (send_cq == recv_cq) + if (send_cq == recv_cq) { + __release(&recv_cq->lock); spin_unlock_irq(&send_cq->lock); - else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { + } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { spin_unlock(&recv_cq->lock); spin_unlock_irq(&send_cq->lock); } else { -- cgit v0.10.2 From fa0681d2129732027355d6b7083dd8932b9b799d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:49 -0700 Subject: mlx4_core: Allocate and map sufficient ICM memory for EQ context The current implementation allocates a single host page for EQ context memory, which was OK when we only allocated a few EQs. However, since we now allocate an EQ for each CPU core, this patch removes the hard-coded limit (which we exceed with 4 KB pages and 128 byte EQ context entries with 32 CPUs) and uses the same ICM table code as all other context tables, which ends up simplifying the code quite a bit while fixing the problem. This problem was actually hit in practice on a dual-socket Nehalem box with 16 real hardware threads and sufficiently odd ACPI tables that it shows on boot SMP: Allowing 32 CPUs, 16 hotplug CPUs so num_possible_cpus() ends up 32, and mlx4 ends up creating 33 MSI-X interrupts and 33 EQs. This mlx4 bug means that mlx4 can't even initialize at all on this quite mainstream system. Cc: Reported-by: Eli Cohen Tested-by: Christoph Lameter Signed-off-by: Roland Dreier diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index c11a052..d7974a6 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -525,48 +525,6 @@ static void mlx4_unmap_clr_int(struct mlx4_dev *dev) iounmap(priv->clr_base); } -int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int ret; - - /* - * We assume that mapping one page is enough for the whole EQ - * context table. This is fine with all current HCAs, because - * we only use 32 EQs and each EQ uses 64 bytes of context - * memory, or 1 KB total. - */ - priv->eq_table.icm_virt = icm_virt; - priv->eq_table.icm_page = alloc_page(GFP_HIGHUSER); - if (!priv->eq_table.icm_page) - return -ENOMEM; - priv->eq_table.icm_dma = pci_map_page(dev->pdev, priv->eq_table.icm_page, 0, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, priv->eq_table.icm_dma)) { - __free_page(priv->eq_table.icm_page); - return -ENOMEM; - } - - ret = mlx4_MAP_ICM_page(dev, priv->eq_table.icm_dma, icm_virt); - if (ret) { - pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - __free_page(priv->eq_table.icm_page); - } - - return ret; -} - -void mlx4_unmap_eq_icm(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mlx4_UNMAP_ICM(dev, priv->eq_table.icm_virt, 1); - pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - __free_page(priv->eq_table.icm_page); -} - int mlx4_alloc_eq_table(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 5c1afe0..528f89b 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -525,7 +525,10 @@ static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap, goto err_unmap_aux; } - err = mlx4_map_eq_icm(dev, init_hca->eqc_base); + err = mlx4_init_icm_table(dev, &priv->eq_table.table, + init_hca->eqc_base, dev_cap->eqc_entry_sz, + dev->caps.num_eqs, dev->caps.num_eqs, + 0, 0); if (err) { mlx4_err(dev, "Failed to map EQ context memory, aborting.\n"); goto err_unmap_cmpt; @@ -668,7 +671,7 @@ err_unmap_mtt: mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); err_unmap_eq: - mlx4_unmap_eq_icm(dev); + mlx4_cleanup_icm_table(dev, &priv->eq_table.table); err_unmap_cmpt: mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); @@ -698,11 +701,11 @@ static void mlx4_free_icms(struct mlx4_dev *dev) mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table); mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table); mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); + mlx4_cleanup_icm_table(dev, &priv->eq_table.table); mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); - mlx4_unmap_eq_icm(dev); mlx4_UNMAP_ICM_AUX(dev); mlx4_free_icm(dev, priv->fw.aux_icm, 0); diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 5bd79c2..bc72d6e 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -205,9 +205,7 @@ struct mlx4_eq_table { void __iomem **uar_map; u32 clr_mask; struct mlx4_eq *eq; - u64 icm_virt; - struct page *icm_page; - dma_addr_t icm_dma; + struct mlx4_icm_table table; struct mlx4_icm_table cmpt_table; int have_irq; u8 inta_pin; @@ -373,9 +371,6 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap, struct mlx4_init_hca_param *init_hca); -int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt); -void mlx4_unmap_eq_icm(struct mlx4_dev *dev); - int mlx4_cmd_init(struct mlx4_dev *dev); void mlx4_cmd_cleanup(struct mlx4_dev *dev); void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param); -- cgit v0.10.2 From 1af92e2a211b0d46ef60ea9f30f989fd7b5725fa Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Sat, 5 Sep 2009 20:24:49 -0700 Subject: mlx4_core: Avoid double free_icms On the error path of mlx4_init_hca(), mlx4_close_hca() is called, followed by mlx4_free_icms() and mlx4_UNMAP_FA(). But both those functions are also called from mlx4_close_hca(), which leads to a double free. Signed-off-by: Yevgeny Petrilin Signed-off-by: Roland Dreier diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 528f89b..3dd481e 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -789,7 +789,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev) return 0; err_close: - mlx4_close_hca(dev); + mlx4_CLOSE_HCA(dev, 0); err_free_icm: mlx4_free_icms(dev); -- cgit v0.10.2 From f5f5951c7494b6ae89ec53ca7ca6b0177ebd1308 Mon Sep 17 00:00:00 2001 From: Arputham Benjamin Date: Sat, 5 Sep 2009 20:24:50 -0700 Subject: mlx4_core: Distinguish multiple devices in /proc/interrupts When the mlx4 driver uses the same name for interrupts for every device in the system. This can make it very confusing trying to work out exactly which device MSI-X interrupts are for. Change the driver to add the PCI name of the device to the interrupt name. Signed-off-by: Arputham Benjamin Signed-off-by: Roland Dreier diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index d7974a6..bffb799 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -41,6 +41,10 @@ #include "fw.h" enum { + MLX4_IRQNAME_SIZE = 64 +}; + +enum { MLX4_NUM_ASYNC_EQE = 0x100, MLX4_NUM_SPARE_EQE = 0x80, MLX4_EQ_ENTRY_SIZE = 0x20 @@ -572,7 +576,9 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) priv->eq_table.clr_int = priv->clr_base + (priv->eq_table.inta_pin < 32 ? 4 : 0); - priv->eq_table.irq_names = kmalloc(16 * dev->caps.num_comp_vectors, GFP_KERNEL); + priv->eq_table.irq_names = + kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1), + GFP_KERNEL); if (!priv->eq_table.irq_names) { err = -ENOMEM; goto err_out_bitmap; @@ -595,17 +601,25 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) goto err_out_comp; if (dev->flags & MLX4_FLAG_MSI_X) { - static const char async_eq_name[] = "mlx4-async"; const char *eq_name; for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) { if (i < dev->caps.num_comp_vectors) { - snprintf(priv->eq_table.irq_names + i * 16, 16, - "mlx4-comp-%d", i); - eq_name = priv->eq_table.irq_names + i * 16; - } else - eq_name = async_eq_name; + snprintf(priv->eq_table.irq_names + + i * MLX4_IRQNAME_SIZE, + MLX4_IRQNAME_SIZE, + "mlx4-comp-%d@pci:%s", i, + pci_name(dev->pdev)); + } else { + snprintf(priv->eq_table.irq_names + + i * MLX4_IRQNAME_SIZE, + MLX4_IRQNAME_SIZE, + "mlx4-async@pci:%s", + pci_name(dev->pdev)); + } + eq_name = priv->eq_table.irq_names + + i * MLX4_IRQNAME_SIZE; err = request_irq(priv->eq_table.eq[i].irq, mlx4_msi_x_interrupt, 0, eq_name, priv->eq_table.eq + i); @@ -615,8 +629,12 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) priv->eq_table.eq[i].have_irq = 1; } } else { + snprintf(priv->eq_table.irq_names, + MLX4_IRQNAME_SIZE, + DRV_NAME "@pci:%s", + pci_name(dev->pdev)); err = request_irq(dev->pdev->irq, mlx4_interrupt, - IRQF_SHARED, DRV_NAME, dev); + IRQF_SHARED, priv->eq_table.irq_names, dev); if (err) goto err_out_async; -- cgit v0.10.2 From 3b4a8cd51e59c1c342c51b241bbb96c6ac24a147 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Sat, 5 Sep 2009 20:24:50 -0700 Subject: IB/mlx4: Don't allow userspace open while recovering from catastrophic error Userspace apps are supposed to release all ib device resources if they receive a fatal async event (IBV_EVENT_DEVICE_FATAL). However, the app has no way of knowing when the device has come back up, except to repeatedly attempt ibv_open_device() until it succeeds. However, currently there is no protection against the open succeeding while the device is in being removed following the fatal event. In this case, the open will succeed, but as a result the device waits in the middle of its removal until the new app releases its resources -- and the new app will not do so, since the open succeeded at a point following the fatal event generation. This patch adds an "active" flag to the device. The active flag is set to false (in the fatal event flow) before the "fatal" event is generated, so any subsequent ibv_dev_open() call to the device will fail until the device comes back up, thus preventing the above deadlock. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index ae3d759..313ce7f 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -342,6 +342,9 @@ static struct ib_ucontext *mlx4_ib_alloc_ucontext(struct ib_device *ibdev, struct mlx4_ib_alloc_ucontext_resp resp; int err; + if (!dev->ib_active) + return ERR_PTR(-EAGAIN); + resp.qp_tab_size = dev->dev->caps.num_qps; resp.bf_reg_size = dev->dev->caps.bf_reg_size; resp.bf_regs_per_page = dev->dev->caps.bf_regs_per_page; @@ -673,6 +676,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) goto err_reg; } + ibdev->ib_active = true; + return ibdev; err_reg: @@ -729,6 +734,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, break; case MLX4_DEV_EVENT_CATASTROPHIC_ERROR: + ibdev->ib_active = false; ibev.event = IB_EVENT_DEVICE_FATAL; break; diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 8a7dd67..3486d76 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -175,6 +175,7 @@ struct mlx4_ib_dev { spinlock_t sm_lock; struct mutex cap_mask_mutex; + bool ib_active; }; static inline struct mlx4_ib_dev *to_mdev(struct ib_device *ibdev) -- cgit v0.10.2 From fc1285585f5bfda18e3fe7f90afd47da51b82bd6 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:36:13 -0700 Subject: IB/mthca: Remove unnecessary include of mthca_config_reg.h was including for no reason -- the whole file is just defines of constants, so it's entirely self-contained. Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mthca/mthca_config_reg.h b/drivers/infiniband/hw/mthca/mthca_config_reg.h index 75671f7..155bc66 100644 --- a/drivers/infiniband/hw/mthca/mthca_config_reg.h +++ b/drivers/infiniband/hw/mthca/mthca_config_reg.h @@ -34,8 +34,6 @@ #ifndef MTHCA_CONFIG_REG_H #define MTHCA_CONFIG_REG_H -#include - #define MTHCA_HCR_BASE 0x80680 #define MTHCA_HCR_SIZE 0x0001c #define MTHCA_ECR_BASE 0x80700 -- cgit v0.10.2 From deecb5d6728fff5288b6f7241ee8225ba0d8c6d2 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:36:15 -0700 Subject: IB/mthca: Remove unnecessary include of mthca_reset.c doesn't have any function annotations, so there's no reason to include . Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c index acb6817f..2a13a16 100644 --- a/drivers/infiniband/hw/mthca/mthca_reset.c +++ b/drivers/infiniband/hw/mthca/mthca_reset.c @@ -30,7 +30,6 @@ * SOFTWARE. */ -#include #include #include #include -- cgit v0.10.2 From ffe063f32bacad7d5111ae9c2b3e31addb47ce39 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:36:15 -0700 Subject: IB/mthca: Annotate CQ locking mthca_ib_lock_cqs()/mthca_ib_unlock_cqs() are helper functions that lock/unlock both CQs attached to a QP in the proper order to avoid AB-BA deadlocks. Annotate this so sparse can understand what's going on (and warn us if we misuse these functions). Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index f5081bf..c10576f 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -1319,10 +1319,12 @@ int mthca_alloc_qp(struct mthca_dev *dev, } static void mthca_lock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq) + __acquires(&send_cq->lock) __acquires(&recv_cq->lock) { - if (send_cq == recv_cq) + if (send_cq == recv_cq) { spin_lock_irq(&send_cq->lock); - else if (send_cq->cqn < recv_cq->cqn) { + __acquire(&recv_cq->lock); + } else if (send_cq->cqn < recv_cq->cqn) { spin_lock_irq(&send_cq->lock); spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); } else { @@ -1332,10 +1334,12 @@ static void mthca_lock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq) } static void mthca_unlock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq) + __releases(&send_cq->lock) __releases(&recv_cq->lock) { - if (send_cq == recv_cq) + if (send_cq == recv_cq) { + __release(&recv_cq->lock); spin_unlock_irq(&send_cq->lock); - else if (send_cq->cqn < recv_cq->cqn) { + } else if (send_cq->cqn < recv_cq->cqn) { spin_unlock(&recv_cq->lock); spin_unlock_irq(&send_cq->lock); } else { -- cgit v0.10.2 From d94a86890137fabcc97eaa324bfef3f1827744c8 Mon Sep 17 00:00:00 2001 From: Arputham Benjamin Date: Sat, 5 Sep 2009 20:36:15 -0700 Subject: IB/mthca: Distinguish multiple devices in /proc/interrupts When the mthca driver uses the same name for interrupts for every device in the system. This can make it very confusing trying to work out exactly which device MSI-X interrupts are for. Change the driver to add the PCI name of the device to the interrupt name. Signed-off-by: Arputham Benjamin Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 90e4e45..8c31fa3 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -829,27 +829,34 @@ int mthca_init_eq_table(struct mthca_dev *dev) if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { static const char *eq_name[] = { - [MTHCA_EQ_COMP] = DRV_NAME " (comp)", - [MTHCA_EQ_ASYNC] = DRV_NAME " (async)", - [MTHCA_EQ_CMD] = DRV_NAME " (cmd)" + [MTHCA_EQ_COMP] = DRV_NAME "-comp", + [MTHCA_EQ_ASYNC] = DRV_NAME "-async", + [MTHCA_EQ_CMD] = DRV_NAME "-cmd" }; for (i = 0; i < MTHCA_NUM_EQ; ++i) { + snprintf(dev->eq_table.eq[i].irq_name, + IB_DEVICE_NAME_MAX, + "%s@pci:%s", eq_name[i], + pci_name(dev->pdev)); err = request_irq(dev->eq_table.eq[i].msi_x_vector, mthca_is_memfree(dev) ? mthca_arbel_msi_x_interrupt : mthca_tavor_msi_x_interrupt, - 0, eq_name[i], dev->eq_table.eq + i); + 0, dev->eq_table.eq[i].irq_name, + dev->eq_table.eq + i); if (err) goto err_out_cmd; dev->eq_table.eq[i].have_irq = 1; } } else { + snprintf(dev->eq_table.eq[0].irq_name, IB_DEVICE_NAME_MAX, + DRV_NAME "@pci:%s", pci_name(dev->pdev)); err = request_irq(dev->pdev->irq, mthca_is_memfree(dev) ? mthca_arbel_interrupt : mthca_tavor_interrupt, - IRQF_SHARED, DRV_NAME, dev); + IRQF_SHARED, dev->eq_table.eq[0].irq_name, dev); if (err) goto err_out_cmd; dev->eq_table.have_irq = 1; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index c621f87..90f4c4d 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -113,6 +113,7 @@ struct mthca_eq { int nent; struct mthca_buf_list *page_list; struct mthca_mr mr; + char irq_name[IB_DEVICE_NAME_MAX]; }; struct mthca_av; -- cgit v0.10.2 From d84106477733cb155c5dcaea664ddf120bf69eb7 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Sat, 5 Sep 2009 20:36:16 -0700 Subject: IB/mthca: Don't allow userspace open while recovering from catastrophic error Userspace apps are supposed to release all ib device resources if they receive a fatal async event (IBV_EVENT_DEVICE_FATAL). However, the app has no way of knowing when the device has come back up, except to repeatedly attempt ibv_open_device() until it succeeds. However, currently there is no protection against the open succeeding while the device is in being removed following the fatal event. In this case, the open will succeed, but as a result the device waits in the middle of its removal until the new app releases its resources -- and the new app will not do so, since the open succeeded at a point following the fatal event generation. This patch adds an "active" flag to the device. The active flag is set to false (in the fatal event flow) before the "fatal" event is generated, so any subsequent ibv_dev_open() call to the device will fail until the device comes back up, thus preventing the above deadlock. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c index 65ad359..056b2a4 100644 --- a/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/drivers/infiniband/hw/mthca/mthca_catas.c @@ -88,6 +88,7 @@ static void handle_catas(struct mthca_dev *dev) event.device = &dev->ib_dev; event.event = IB_EVENT_DEVICE_FATAL; event.element.port_num = 0; + dev->active = false; ib_dispatch_event(&event); diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 9ef611f..7e6a6d6 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -357,6 +357,7 @@ struct mthca_dev { struct ib_ah *sm_ah[MTHCA_MAX_PORTS]; spinlock_t sm_lock; u8 rate[MTHCA_MAX_PORTS]; + bool active; }; #ifdef CONFIG_INFINIBAND_MTHCA_DEBUG diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 13da9f1..518cc54 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -1116,6 +1116,8 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) pci_set_drvdata(pdev, mdev); mdev->hca_type = hca_type; + mdev->active = true; + return 0; err_unregister: diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 87ad889..bcf7a40 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -334,6 +334,9 @@ static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev, struct mthca_ucontext *context; int err; + if (!(to_mdev(ibdev)->active)) + return ERR_PTR(-EAGAIN); + memset(&uresp, 0, sizeof uresp); uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps; -- cgit v0.10.2 From c4c3f279cd8e9cc1d3e2f364a27beadb2e69cda8 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:36 -0700 Subject: RDMA/nes: Update refcnt during disconnect During termination, it is possible for the refcnt to go to zero while the worker thread is posting events upward. This fix increments the refcnt before the request is passed to the worker thread. The thread decrements the refcnt when the request is completed. Signed-off-by: Don Wood Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 114b802..fe08eb5 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -2456,6 +2456,7 @@ int nes_cm_disconn(struct nes_qp *nesqp) if (nesqp->disconn_pending == 0) { nesqp->disconn_pending++; spin_unlock_irqrestore(&nesqp->lock, flags); + nes_add_ref(&nesqp->ibqp); /* init our disconnect work element, to */ INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker); @@ -2477,6 +2478,7 @@ static void nes_disconnect_worker(struct work_struct *work) nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n", nesqp->last_aeq, nesqp->hwqp.qp_id); nes_cm_disconn_true(nesqp); + nes_rem_ref(&nesqp->ibqp); } -- cgit v0.10.2 From 873fcdd4bfc75880888a7d148a71d70ed87c9ebf Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:37 -0700 Subject: RDMA/nes: Allocate work item for disconnect event handling The code currently has a work structure in the QP. This requires a lock and a pending flag to ensure there is never more than one request active. When two events happen quickly (such as FIN and LLP CLOSE), it causes unnecessary timeouts since the second one is dropped. This fix allocates memory for the work request so the second one can be queued. A lock is removed since it is no longer needed. Signed-off-by: Don Wood Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index fe08eb5..d89bdee 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -2450,20 +2450,16 @@ static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_nod */ int nes_cm_disconn(struct nes_qp *nesqp) { - unsigned long flags; + struct disconn_work *work; - spin_lock_irqsave(&nesqp->lock, flags); - if (nesqp->disconn_pending == 0) { - nesqp->disconn_pending++; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_add_ref(&nesqp->ibqp); - /* init our disconnect work element, to */ - INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker); - - queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work); - } else - spin_unlock_irqrestore(&nesqp->lock, flags); + work = kzalloc(sizeof *work, GFP_ATOMIC); + if (!work) + return -ENOMEM; /* Timer will clean up */ + nes_add_ref(&nesqp->ibqp); + work->nesqp = nesqp; + INIT_WORK(&work->work, nes_disconnect_worker); + queue_work(g_cm_core->disconn_wq, &work->work); return 0; } @@ -2473,8 +2469,10 @@ int nes_cm_disconn(struct nes_qp *nesqp) */ static void nes_disconnect_worker(struct work_struct *work) { - struct nes_qp *nesqp = container_of(work, struct nes_qp, disconn_work); + struct disconn_work *dwork = container_of(work, struct disconn_work, work); + struct nes_qp *nesqp = dwork->nesqp; + kfree(dwork); nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n", nesqp->last_aeq, nesqp->hwqp.qp_id); nes_cm_disconn_true(nesqp); @@ -2557,7 +2555,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) spin_lock_irqsave(&nesqp->lock, flags); } - nesqp->disconn_pending = 0; /* There might have been another AE while the lock was released */ original_hw_tcp_state = nesqp->hw_tcp_state; original_ibqp_state = nesqp->ibqp_state; @@ -2610,7 +2607,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) } } } else { - nesqp->disconn_pending = 0; spin_unlock_irqrestore(&nesqp->lock, flags); } diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index 41c07f2..7df34fe 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h @@ -119,6 +119,11 @@ struct nes_wq { spinlock_t lock; }; +struct disconn_work { + struct work_struct work; + struct nes_qp *nesqp; +}; + struct iw_cm_id; struct ietf_mpa_frame; @@ -127,7 +132,6 @@ struct nes_qp { void *allocated_buffer; struct iw_cm_id *cm_id; struct workqueue_struct *wq; - struct work_struct disconn_work; struct nes_cq *nesscq; struct nes_cq *nesrcq; struct nes_pd *nespd; @@ -165,7 +169,6 @@ struct nes_qp { u8 hw_iwarp_state; u8 flush_issued; u8 hw_tcp_state; - u8 disconn_pending; u8 destroyed; }; #endif /* NES_VERBS_H */ -- cgit v0.10.2 From ba0c5d9a8975cf740a4a4b8c579cc4b325f8b852 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:37 -0700 Subject: RDMA/nes: Change memory allocation for cqp request to GFP_ATOMIC The routine to allocate a cqp request is not called from process context code. Since it is not OK to sleep, it needs to use GFP_ATOMIC not GFP_KERNEL. Signed-off-by: Don Wood Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index a282031..b34072b 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c @@ -548,7 +548,7 @@ struct nes_cqp_request *nes_get_cqp_request(struct nes_device *nesdev) spin_unlock_irqrestore(&nesdev->cqp.lock, flags); } if (cqp_request == NULL) { - cqp_request = kzalloc(sizeof(struct nes_cqp_request), GFP_KERNEL); + cqp_request = kzalloc(sizeof(struct nes_cqp_request), GFP_ATOMIC); if (cqp_request) { cqp_request->dynamic = 1; INIT_LIST_HEAD(&cqp_request->list); -- cgit v0.10.2 From 5ee21fe0eaf68fb840f442131ab7addced1a31c3 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:37 -0700 Subject: RDMA/nes: Clean out CQ completions when QP is destroyed When a QP is destroyed, unprocessed CQ entries could still reference the QP. This change zeroes the context value at QP destroy time. By skipping over cqe's with a zero context, poll_cq no longer processes a cqe for a destroyed QP. Signed-off-by: Don Wood Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 21e0fd3..c6b5873 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1506,12 +1506,45 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, /** + * nes_clean_cq + */ +static void nes_clean_cq(struct nes_qp *nesqp, struct nes_cq *nescq) +{ + u32 cq_head; + u32 lo; + u32 hi; + u64 u64temp; + unsigned long flags = 0; + + spin_lock_irqsave(&nescq->lock, flags); + + cq_head = nescq->hw_cq.cq_head; + while (le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) { + rmb(); + lo = le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]); + hi = le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]); + u64temp = (((u64)hi) << 32) | ((u64)lo); + u64temp &= ~(NES_SW_CONTEXT_ALIGN-1); + if (u64temp == (u64)(unsigned long)nesqp) { + /* Zero the context value so cqe will be ignored */ + nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX] = 0; + nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX] = 0; + } + + if (++cq_head >= nescq->hw_cq.cq_size) + cq_head = 0; + } + + spin_unlock_irqrestore(&nescq->lock, flags); +} + + +/** * nes_destroy_qp */ static int nes_destroy_qp(struct ib_qp *ibqp) { struct nes_qp *nesqp = to_nesqp(ibqp); - /* struct nes_vnic *nesvnic = to_nesvnic(ibqp->device); */ struct nes_ucontext *nes_ucontext; struct ib_qp_attr attr; struct iw_cm_id *cm_id; @@ -1548,7 +1581,6 @@ static int nes_destroy_qp(struct ib_qp *ibqp) nes_debug(NES_DBG_QP, "OFA CM event_handler returned, ret=%d\n", ret); } - if (nesqp->user_mode) { if ((ibqp->uobject)&&(ibqp->uobject->context)) { nes_ucontext = to_nesucontext(ibqp->uobject->context); @@ -1560,6 +1592,13 @@ static int nes_destroy_qp(struct ib_qp *ibqp) } if (nesqp->pbl_pbase) kunmap(nesqp->page); + } else { + /* Clean any pending completions from the cq(s) */ + if (nesqp->nesscq) + nes_clean_cq(nesqp, nesqp->nesscq); + + if ((nesqp->nesrcq) && (nesqp->nesrcq != nesqp->nesscq)) + nes_clean_cq(nesqp, nesqp->nesrcq); } nes_rem_ref(&nesqp->ibqp); @@ -3547,7 +3586,6 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) { u64 u64temp; u64 wrid; - /* u64 u64temp; */ unsigned long flags = 0; struct nes_vnic *nesvnic = to_nesvnic(ibcq->device); struct nes_device *nesdev = nesvnic->nesdev; @@ -3560,7 +3598,6 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) u32 cqe_count = 0; u32 wqe_index; u32 u32temp; - /* u32 counter; */ nes_debug(NES_DBG_CQ, "\n"); @@ -3570,24 +3607,27 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) cq_size = nescq->hw_cq.cq_size; while (cqe_count < num_entries) { - if (le32_to_cpu(nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & - NES_CQE_VALID) { - /* - * Make sure we read CQ entry contents *after* - * we've checked the valid bit. - */ - rmb(); - - cqe = nescq->hw_cq.cq_vbase[head]; - nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0; - u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]); - wqe_index = u32temp & - (nesdev->nesadapter->max_qp_wr - 1); - u32temp &= ~(NES_SW_CONTEXT_ALIGN-1); - /* parse CQE, get completion context from WQE (either rq or sq */ - u64temp = (((u64)(le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) | - ((u64)u32temp); - nesqp = *((struct nes_qp **)&u64temp); + if ((le32_to_cpu(nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & + NES_CQE_VALID) == 0) + break; + + /* + * Make sure we read CQ entry contents *after* + * we've checked the valid bit. + */ + rmb(); + + cqe = nescq->hw_cq.cq_vbase[head]; + nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0; + u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]); + wqe_index = u32temp & (nesdev->nesadapter->max_qp_wr - 1); + u32temp &= ~(NES_SW_CONTEXT_ALIGN-1); + /* parse CQE, get completion context from WQE (either rq or sq) */ + u64temp = (((u64)(le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) | + ((u64)u32temp); + + if (u64temp) { + nesqp = (struct nes_qp *)(unsigned long)u64temp; memset(entry, 0, sizeof *entry); if (cqe.cqe_words[NES_CQE_ERROR_CODE_IDX] == 0) { entry->status = IB_WC_SUCCESS; @@ -3601,7 +3641,7 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) if (le32_to_cpu(cqe.cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_SQ) { if (nesqp->skip_lsmm) { nesqp->skip_lsmm = 0; - wq_tail = nesqp->hwqp.sq_tail++; + nesqp->hwqp.sq_tail++; } /* Working on a SQ Completion*/ @@ -3643,24 +3683,25 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32); entry->opcode = IB_WC_RECV; } - entry->wr_id = wrid; - if (++head >= cq_size) - head = 0; - cqe_count++; - nescq->polled_completions++; - if ((nescq->polled_completions > (cq_size / 2)) || - (nescq->polled_completions == 255)) { - nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes" - " are pending %u of %u.\n", - nescq->hw_cq.cq_number, nescq->polled_completions, cq_size); - nes_write32(nesdev->regs+NES_CQE_ALLOC, - nescq->hw_cq.cq_number | (nescq->polled_completions << 16)); - nescq->polled_completions = 0; - } + entry->wr_id = wrid; entry++; - } else - break; + cqe_count++; + } + + if (++head >= cq_size) + head = 0; + nescq->polled_completions++; + + if ((nescq->polled_completions > (cq_size / 2)) || + (nescq->polled_completions == 255)) { + nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes" + " are pending %u of %u.\n", + nescq->hw_cq.cq_number, nescq->polled_completions, cq_size); + nes_write32(nesdev->regs+NES_CQE_ALLOC, + nescq->hw_cq.cq_number | (nescq->polled_completions << 16)); + nescq->polled_completions = 0; + } } if (nescq->polled_completions) { -- cgit v0.10.2 From 3c28b4457a4cf95e982ca13578a5613a11009394 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:38 -0700 Subject: RDMA/nes: Add CQ error handling CQ errors are not being handled correctly. Put in the the upcall for CQ errors. Signed-off-by: Don Wood Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 4a84d02..2a0c5a1 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2913,6 +2913,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, u64 aeqe_context = 0; unsigned long flags; struct nes_qp *nesqp; + struct nes_hw_cq *hw_cq; + struct nes_cq *nescq; int resource_allocated; /* struct iw_cm_id *cm_id; */ struct nes_adapter *nesadapter = nesdev->nesadapter; @@ -3153,6 +3155,16 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, if (resource_allocated) { printk(KERN_ERR PFX "%s: Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u\n", __func__, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])); + hw_cq = (struct nes_hw_cq *)(unsigned long)context; + if (hw_cq) { + nescq = container_of(hw_cq, struct nes_cq, hw_cq); + if (nescq->ibcq.event_handler) { + ibevent.device = nescq->ibcq.device; + ibevent.event = IB_EVENT_CQ_ERR; + ibevent.element.cq = &nescq->ibcq; + nescq->ibcq.event_handler(&ibevent, nescq->ibcq.cq_context); + } + } } break; case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: -- cgit v0.10.2 From 8b1c9dc4ba713985d33aba87c761bf71d5a96491 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:38 -0700 Subject: RDMA/nes: Implement Terminate Packet Implement the sending and receiving of Terminate packets. Signed-off-by: Don Wood Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index bf1720f..bcc6abc 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -523,7 +523,7 @@ int nes_cm_disconn(struct nes_qp *); void nes_cm_disconn_worker(void *); /* nes_verbs.c */ -int nes_hw_modify_qp(struct nes_device *, struct nes_qp *, u32, u32); +int nes_hw_modify_qp(struct nes_device *, struct nes_qp *, u32, u32, u32); int nes_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *); struct nes_ib_device *nes_init_ofa_device(struct net_device *); void nes_destroy_ofa_device(struct nes_ib_device *); diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h index 8b7e7c0..90e8e4d 100644 --- a/drivers/infiniband/hw/nes/nes_cm.h +++ b/drivers/infiniband/hw/nes/nes_cm.h @@ -410,8 +410,6 @@ struct nes_cm_ops { int schedule_nes_timer(struct nes_cm_node *, struct sk_buff *, enum nes_timer_type, int, int); -int nes_cm_disconn(struct nes_qp *); - int nes_accept(struct iw_cm_id *, struct iw_cm_conn_param *); int nes_reject(struct iw_cm_id *, const void *, u8); int nes_connect(struct iw_cm_id *, struct iw_cm_conn_param *); diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 2a0c5a1..297026f 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -74,6 +74,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, static void process_critical_error(struct nes_device *nesdev); static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number); static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode); +static void nes_terminate_timeout(unsigned long context); +static void nes_terminate_start_timer(struct nes_qp *nesqp); #ifdef CONFIG_INFINIBAND_NES_DEBUG static unsigned char *nes_iwarp_state_str[] = { @@ -2903,6 +2905,383 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) } +static u8 *locate_mpa(u8 *pkt, u32 aeq_info) +{ + u16 pkt_len; + + if (aeq_info & NES_AEQE_Q2_DATA_ETHERNET) { + /* skip over ethernet header */ + pkt_len = be16_to_cpu(*(u16 *)(pkt + ETH_HLEN - 2)); + pkt += ETH_HLEN; + + /* Skip over IP and TCP headers */ + pkt += 4 * (pkt[0] & 0x0f); + pkt += 4 * ((pkt[12] >> 4) & 0x0f); + } + return pkt; +} + +/* Determine if incoming error pkt is rdma layer */ +static u32 iwarp_opcode(struct nes_qp *nesqp, u32 aeq_info) +{ + u8 *pkt; + u16 *mpa; + u32 opcode = 0xffffffff; + + if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) { + pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET; + mpa = (u16 *)locate_mpa(pkt, aeq_info); + opcode = be16_to_cpu(mpa[1]) & 0xf; + } + + return opcode; +} + +/* Build iWARP terminate header */ +static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 aeq_info) +{ + u8 *pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET; + u16 ddp_seg_len; + int copy_len = 0; + u8 is_tagged = 0; + struct nes_terminate_hdr *termhdr; + + termhdr = (struct nes_terminate_hdr *)nesqp->hwqp.q2_vbase; + memset(termhdr, 0, 64); + + if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) { + + /* Use data from offending packet to fill in ddp & rdma hdrs */ + pkt = locate_mpa(pkt, aeq_info); + ddp_seg_len = be16_to_cpu(*(u16 *)pkt); + if (ddp_seg_len) { + copy_len = 2; + termhdr->hdrct = DDP_LEN_FLAG; + if (pkt[2] & 0x80) { + is_tagged = 1; + if (ddp_seg_len >= TERM_DDP_LEN_TAGGED) { + copy_len += TERM_DDP_LEN_TAGGED; + termhdr->hdrct |= DDP_HDR_FLAG; + } + } else { + if (ddp_seg_len >= TERM_DDP_LEN_UNTAGGED) { + copy_len += TERM_DDP_LEN_UNTAGGED; + termhdr->hdrct |= DDP_HDR_FLAG; + } + + if (ddp_seg_len >= (TERM_DDP_LEN_UNTAGGED + TERM_RDMA_LEN)) { + if ((pkt[3] & RDMA_OPCODE_MASK) == RDMA_READ_REQ_OPCODE) { + copy_len += TERM_RDMA_LEN; + termhdr->hdrct |= RDMA_HDR_FLAG; + } + } + } + } + } + + switch (async_event_id) { + case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: + switch (iwarp_opcode(nesqp, aeq_info)) { + case IWARP_OPCODE_WRITE: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; + termhdr->error_code = DDP_TAGGED_INV_STAG; + break; + default: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_INV_STAG; + } + break; + case NES_AEQE_AEID_AMP_INVALID_STAG: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_INV_STAG; + break; + case NES_AEQE_AEID_AMP_BAD_QP: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_QN; + break; + case NES_AEQE_AEID_AMP_BAD_STAG_KEY: + case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: + switch (iwarp_opcode(nesqp, aeq_info)) { + case IWARP_OPCODE_SEND_INV: + case IWARP_OPCODE_SEND_SE_INV: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; + termhdr->error_code = RDMAP_CANT_INV_STAG; + break; + default: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_INV_STAG; + } + break; + case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: + if (aeq_info & (NES_AEQE_Q2_DATA_ETHERNET | NES_AEQE_Q2_DATA_MPA)) { + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; + termhdr->error_code = DDP_TAGGED_BOUNDS; + } else { + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_INV_BOUNDS; + } + break; + case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION: + case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS: + case NES_AEQE_AEID_PRIV_OPERATION_DENIED: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_ACCESS; + break; + case NES_AEQE_AEID_AMP_TO_WRAP: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_TO_WRAP; + break; + case NES_AEQE_AEID_AMP_BAD_PD: + switch (iwarp_opcode(nesqp, aeq_info)) { + case IWARP_OPCODE_WRITE: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; + termhdr->error_code = DDP_TAGGED_UNASSOC_STAG; + break; + case IWARP_OPCODE_SEND_INV: + case IWARP_OPCODE_SEND_SE_INV: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_CANT_INV_STAG; + break; + default: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_UNASSOC_STAG; + } + break; + case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH: + termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; + termhdr->error_code = MPA_MARKER; + break; + case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: + termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; + termhdr->error_code = MPA_CRC; + break; + case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE: + case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; + termhdr->error_code = DDP_CATASTROPHIC_LOCAL; + break; + case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC: + case NES_AEQE_AEID_DDP_NO_L_BIT: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; + termhdr->error_code = DDP_CATASTROPHIC_LOCAL; + break; + case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN: + case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_MSN_RANGE; + break; + case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_TOO_LONG; + break; + case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION: + if (is_tagged) { + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; + termhdr->error_code = DDP_TAGGED_INV_DDP_VER; + } else { + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_DDP_VER; + } + break; + case NES_AEQE_AEID_DDP_UBE_INVALID_MO: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_MO; + break; + case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_MSN_NO_BUF; + break; + case NES_AEQE_AEID_DDP_UBE_INVALID_QN: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_QN; + break; + case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; + termhdr->error_code = RDMAP_INV_RDMAP_VER; + break; + case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; + termhdr->error_code = RDMAP_UNEXPECTED_OP; + break; + default: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; + termhdr->error_code = RDMAP_UNSPECIFIED; + break; + } + + if (copy_len) + memcpy(termhdr + 1, pkt, copy_len); + + return sizeof(struct nes_terminate_hdr) + copy_len; +} + +static void nes_terminate_connection(struct nes_device *nesdev, struct nes_qp *nesqp, + struct nes_hw_aeqe *aeqe, enum ib_event_type eventtype) +{ + u64 context; + unsigned long flags; + u32 aeq_info; + u16 async_event_id; + u8 tcp_state; + u8 iwarp_state; + u32 termlen = 0; + u32 mod_qp_flags = NES_CQP_QP_IWARP_STATE_TERMINATE | + NES_CQP_QP_TERM_DONT_SEND_FIN; + struct nes_adapter *nesadapter = nesdev->nesadapter; + + if (nesqp->term_flags & NES_TERM_SENT) + return; /* Sanity check */ + + aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); + tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT; + iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT; + async_event_id = (u16)aeq_info; + + context = (unsigned long)nesadapter->qp_table[le32_to_cpu( + aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; + if (!context) { + WARN_ON(!context); + return; + } + + nesqp = (struct nes_qp *)(unsigned long)context; + spin_lock_irqsave(&nesqp->lock, flags); + nesqp->hw_iwarp_state = iwarp_state; + nesqp->hw_tcp_state = tcp_state; + nesqp->last_aeq = async_event_id; + nesqp->terminate_eventtype = eventtype; + spin_unlock_irqrestore(&nesqp->lock, flags); + + if (nesadapter->send_term_ok) + termlen = nes_bld_terminate_hdr(nesqp, async_event_id, aeq_info); + else + mod_qp_flags |= NES_CQP_QP_TERM_DONT_SEND_TERM_MSG; + + nes_terminate_start_timer(nesqp); + nesqp->term_flags |= NES_TERM_SENT; + nes_hw_modify_qp(nesdev, nesqp, mod_qp_flags, termlen, 0); +} + +static void nes_terminate_send_fin(struct nes_device *nesdev, + struct nes_qp *nesqp, struct nes_hw_aeqe *aeqe) +{ + u32 aeq_info; + u16 async_event_id; + u8 tcp_state; + u8 iwarp_state; + unsigned long flags; + + aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); + tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT; + iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT; + async_event_id = (u16)aeq_info; + + spin_lock_irqsave(&nesqp->lock, flags); + nesqp->hw_iwarp_state = iwarp_state; + nesqp->hw_tcp_state = tcp_state; + nesqp->last_aeq = async_event_id; + spin_unlock_irqrestore(&nesqp->lock, flags); + + /* Send the fin only */ + nes_hw_modify_qp(nesdev, nesqp, NES_CQP_QP_IWARP_STATE_TERMINATE | + NES_CQP_QP_TERM_DONT_SEND_TERM_MSG, 0, 0); +} + +/* Cleanup after a terminate sent or received */ +static void nes_terminate_done(struct nes_qp *nesqp, int timeout_occurred) +{ + u32 next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR; + unsigned long flags; + struct nes_vnic *nesvnic = to_nesvnic(nesqp->ibqp.device); + struct nes_device *nesdev = nesvnic->nesdev; + u8 first_time = 0; + + spin_lock_irqsave(&nesqp->lock, flags); + if (nesqp->hte_added) { + nesqp->hte_added = 0; + next_iwarp_state |= NES_CQP_QP_DEL_HTE; + } + + first_time = (nesqp->term_flags & NES_TERM_DONE) == 0; + nesqp->term_flags |= NES_TERM_DONE; + spin_unlock_irqrestore(&nesqp->lock, flags); + + /* Make sure we go through this only once */ + if (first_time) { + if (timeout_occurred == 0) + del_timer(&nesqp->terminate_timer); + else + next_iwarp_state |= NES_CQP_QP_RESET; + + nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); + nes_cm_disconn(nesqp); + } +} + +static void nes_terminate_received(struct nes_device *nesdev, + struct nes_qp *nesqp, struct nes_hw_aeqe *aeqe) +{ + u32 aeq_info; + u8 *pkt; + u32 *mpa; + u8 ddp_ctl; + u8 rdma_ctl; + u16 aeq_id = 0; + + aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); + if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) { + /* Terminate is not a performance path so the silicon */ + /* did not validate the frame - do it now */ + pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET; + mpa = (u32 *)locate_mpa(pkt, aeq_info); + ddp_ctl = (be32_to_cpu(mpa[0]) >> 8) & 0xff; + rdma_ctl = be32_to_cpu(mpa[0]) & 0xff; + if ((ddp_ctl & 0xc0) != 0x40) + aeq_id = NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC; + else if ((ddp_ctl & 0x03) != 1) + aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION; + else if (be32_to_cpu(mpa[2]) != 2) + aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_QN; + else if (be32_to_cpu(mpa[3]) != 1) + aeq_id = NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN; + else if (be32_to_cpu(mpa[4]) != 0) + aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_MO; + else if ((rdma_ctl & 0xc0) != 0x40) + aeq_id = NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION; + + if (aeq_id) { + /* Bad terminate recvd - send back a terminate */ + aeq_info = (aeq_info & 0xffff0000) | aeq_id; + aeqe->aeqe_words[NES_AEQE_MISC_IDX] = cpu_to_le32(aeq_info); + nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); + return; + } + } + + nesqp->term_flags |= NES_TERM_RCVD; + nesqp->terminate_eventtype = IB_EVENT_QP_FATAL; + nes_terminate_start_timer(nesqp); + nes_terminate_send_fin(nesdev, nesqp, aeqe); +} + +/* Timeout routine in case terminate fails to complete */ +static void nes_terminate_timeout(unsigned long context) +{ + struct nes_qp *nesqp = (struct nes_qp *)(unsigned long)context; + + nes_terminate_done(nesqp, 1); +} + +/* Set a timer in case hw cannot complete the terminate sequence */ +static void nes_terminate_start_timer(struct nes_qp *nesqp) +{ + init_timer(&nesqp->terminate_timer); + nesqp->terminate_timer.function = nes_terminate_timeout; + nesqp->terminate_timer.expires = jiffies + HZ; + nesqp->terminate_timer.data = (unsigned long)nesqp; + add_timer(&nesqp->terminate_timer); +} + /** * nes_process_iwarp_aeqe */ @@ -2910,30 +3289,27 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, struct nes_hw_aeqe *aeqe) { u64 context; - u64 aeqe_context = 0; unsigned long flags; struct nes_qp *nesqp; struct nes_hw_cq *hw_cq; struct nes_cq *nescq; int resource_allocated; - /* struct iw_cm_id *cm_id; */ struct nes_adapter *nesadapter = nesdev->nesadapter; - struct ib_event ibevent; - /* struct iw_cm_event cm_event; */ u32 aeq_info; u32 next_iwarp_state = 0; u16 async_event_id; u8 tcp_state; u8 iwarp_state; + int must_disconn = 1; + int must_terminate = 0; + struct ib_event ibevent; nes_debug(NES_DBG_AEQ, "\n"); aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); - if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) { + if ((NES_AEQE_INBOUND_RDMA & aeq_info) || (!(NES_AEQE_QP & aeq_info))) { context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; } else { - aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); - aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; context = (unsigned long)nesadapter->qp_table[le32_to_cpu( aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; BUG_ON(!context); @@ -2950,7 +3326,11 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, switch (async_event_id) { case NES_AEQE_AEID_LLP_FIN_RECEIVED: - nesqp = *((struct nes_qp **)&context); + nesqp = (struct nes_qp *)(unsigned long)context; + + if (nesqp->term_flags) + return; /* Ignore it, wait for close complete */ + if (atomic_inc_return(&nesqp->close_timer_started) == 1) { nesqp->cm_id->add_ref(nesqp->cm_id); schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp, @@ -2961,18 +3341,24 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), async_event_id, nesqp->last_aeq, tcp_state); } + if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) || (nesqp->ibqp_state != IB_QPS_RTS)) { /* FIN Received but tcp state or IB state moved on, should expect a close complete */ return; } + case NES_AEQE_AEID_LLP_CLOSE_COMPLETE: + nesqp = (struct nes_qp *)(unsigned long)context; + if (nesqp->term_flags) { + nes_terminate_done(nesqp, 0); + return; + } + case NES_AEQE_AEID_LLP_CONNECTION_RESET: - case NES_AEQE_AEID_TERMINATE_SENT: - case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE: case NES_AEQE_AEID_RESET_SENT: - nesqp = *((struct nes_qp **)&context); + nesqp = (struct nes_qp *)(unsigned long)context; if (async_event_id == NES_AEQE_AEID_RESET_SENT) { tcp_state = NES_AEQE_TCP_STATE_CLOSED; } @@ -2984,12 +3370,7 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) || (tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) { nesqp->hte_added = 0; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u to remove hte\n", - nesqp->hwqp.qp_id); - nes_hw_modify_qp(nesdev, nesqp, - NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE, 0); - spin_lock_irqsave(&nesqp->lock, flags); + next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE; } if ((nesqp->ibqp_state == IB_QPS_RTS) && @@ -3001,151 +3382,106 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING; break; case NES_AEQE_IWARP_STATE_TERMINATE: - next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE; - nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE; - if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) { - next_iwarp_state |= 0x02000000; - nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; - } + must_disconn = 0; /* terminate path takes care of disconn */ + if (nesqp->term_flags == 0) + must_terminate = 1; break; - default: - next_iwarp_state = 0; - } - spin_unlock_irqrestore(&nesqp->lock, flags); - if (next_iwarp_state) { - nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X," - " also added another reference\n", - nesqp->hwqp.qp_id, next_iwarp_state); - nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); } - nes_cm_disconn(nesqp); } else { if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) { /* FIN Received but ib state not RTS, close complete will be on its way */ - spin_unlock_irqrestore(&nesqp->lock, flags); - return; - } - spin_unlock_irqrestore(&nesqp->lock, flags); - if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) { - next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000; - nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; - nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X," - " also added another reference\n", - nesqp->hwqp.qp_id, next_iwarp_state); - nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); + must_disconn = 0; } - nes_cm_disconn(nesqp); } - break; - case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TERMINATE_RECEIVED" - " event on QP%u \n Q2 Data:\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_FATAL; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } - if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || - ((nesqp->ibqp_state == IB_QPS_RTS)&& - (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { + + if (must_terminate) + nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); + else if (must_disconn) { + if (next_iwarp_state) { + nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X\n", + nesqp->hwqp.qp_id, next_iwarp_state); + nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); + } nes_cm_disconn(nesqp); - } else { - nesqp->in_disconnect = 0; - wake_up(&nesqp->kick_waitq); } break; - case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR; - nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; - nesqp->last_aeq = async_event_id; - if (nesqp->cm_id) { - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES" - " event on QP%u, remote IP = 0x%08X \n", - nesqp->hwqp.qp_id, - ntohl(nesqp->cm_id->remote_addr.sin_addr.s_addr)); - } else { - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES" - " event on QP%u \n", - nesqp->hwqp.qp_id); - } - spin_unlock_irqrestore(&nesqp->lock, flags); - next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_RESET; - nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_FATAL; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } + + case NES_AEQE_AEID_TERMINATE_SENT: + nesqp = (struct nes_qp *)(unsigned long)context; + nes_terminate_send_fin(nesdev, nesqp, aeqe); break; - case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: - if (NES_AEQE_INBOUND_RDMA&aeq_info) { - nesqp = nesadapter->qp_table[le32_to_cpu( - aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; - } else { - /* TODO: get the actual WQE and mask off wqe index */ - context &= ~((u64)511); - nesqp = *((struct nes_qp **)&context); - } - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_BAD_STAG_INDEX event on QP%u\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_ACCESS_ERR; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } + + case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED: + nesqp = (struct nes_qp *)(unsigned long)context; + nes_terminate_received(nesdev, nesqp, aeqe); break; + + case NES_AEQE_AEID_AMP_BAD_STAG_KEY: + case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_UNALLOCATED_STAG event on QP%u\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_ACCESS_ERR; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } - break; + case NES_AEQE_AEID_AMP_INVALID_STAG: + case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION: + case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS: case NES_AEQE_AEID_PRIV_OPERATION_DENIED: - nesqp = nesadapter->qp_table[le32_to_cpu(aeqe->aeqe_words - [NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_PRIV_OPERATION_DENIED event on QP%u," - " nesqp = %p, AE reported %p\n", - nesqp->hwqp.qp_id, nesqp, *((struct nes_qp **)&context)); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_ACCESS_ERR; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); + case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: + case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: + case NES_AEQE_AEID_AMP_TO_WRAP: + nesqp = (struct nes_qp *)(unsigned long)context; + nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_ACCESS_ERR); + break; + + case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE: + case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: + case NES_AEQE_AEID_DDP_UBE_INVALID_MO: + case NES_AEQE_AEID_DDP_UBE_INVALID_QN: + nesqp = (struct nes_qp *)(unsigned long)context; + if (iwarp_opcode(nesqp, aeq_info) > IWARP_OPCODE_TERM) { + aeq_info &= 0xffff0000; + aeq_info |= NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE; + aeqe->aeqe_words[NES_AEQE_MISC_IDX] = cpu_to_le32(aeq_info); } + + case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE: + case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES: + case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: + case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: + case NES_AEQE_AEID_AMP_BAD_QP: + case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH: + case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC: + case NES_AEQE_AEID_DDP_NO_L_BIT: + case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN: + case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID: + case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION: + case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION: + case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE: + case NES_AEQE_AEID_AMP_BAD_PD: + case NES_AEQE_AEID_AMP_FASTREG_SHARED: + case NES_AEQE_AEID_AMP_FASTREG_VALID_STAG: + case NES_AEQE_AEID_AMP_FASTREG_MW_STAG: + case NES_AEQE_AEID_AMP_FASTREG_INVALID_RIGHTS: + case NES_AEQE_AEID_AMP_FASTREG_PBL_TABLE_OVERFLOW: + case NES_AEQE_AEID_AMP_FASTREG_INVALID_LENGTH: + case NES_AEQE_AEID_AMP_INVALIDATE_SHARED: + case NES_AEQE_AEID_AMP_INVALIDATE_MR_WITH_BOUND_WINDOWS: + case NES_AEQE_AEID_AMP_MWBIND_VALID_STAG: + case NES_AEQE_AEID_AMP_MWBIND_OF_MR_STAG: + case NES_AEQE_AEID_AMP_MWBIND_TO_ZERO_BASED_STAG: + case NES_AEQE_AEID_AMP_MWBIND_TO_MW_STAG: + case NES_AEQE_AEID_AMP_MWBIND_INVALID_RIGHTS: + case NES_AEQE_AEID_AMP_MWBIND_INVALID_BOUNDS: + case NES_AEQE_AEID_AMP_MWBIND_TO_INVALID_PARENT: + case NES_AEQE_AEID_AMP_MWBIND_BIND_DISABLED: + case NES_AEQE_AEID_BAD_CLOSE: + case NES_AEQE_AEID_RDMA_READ_WHILE_ORD_ZERO: + case NES_AEQE_AEID_STAG_ZERO_INVALID: + case NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST: + case NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP: + nesqp = (struct nes_qp *)(unsigned long)context; + nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); break; + case NES_AEQE_AEID_CQ_OPERATION_ERROR: context <<= 1; nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u, %p\n", @@ -3167,81 +3503,7 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, } } break; - case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: - nesqp = nesadapter->qp_table[le32_to_cpu( - aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG" - "_FOR_AVAILABLE_BUFFER event on QP%u\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_ACCESS_ERR; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } - /* tell cm to disconnect, cm will queue work to thread */ - nes_cm_disconn(nesqp); - break; - case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_INVALID_MSN" - "_NO_BUFFER_AVAILABLE event on QP%u\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_FATAL; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } - /* tell cm to disconnect, cm will queue work to thread */ - nes_cm_disconn(nesqp); - break; - case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR" - " event on QP%u \n Q2 Data:\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_FATAL; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } - /* tell cm to disconnect, cm will queue work to thread */ - nes_cm_disconn(nesqp); - break; - /* TODO: additional AEs need to be here */ - case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_ACCESS_ERR; - nesqp->ibqp.event_handler(&ibevent, - nesqp->ibqp.qp_context); - } - nes_cm_disconn(nesqp); - break; + default: nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n", async_event_id); @@ -3250,7 +3512,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, } - /** * nes_iwarp_ce_handler */ diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index c3654c6..4a0bfcd 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -241,6 +241,7 @@ enum nes_cqp_stag_wqeword_idx { }; #define NES_CQP_OP_IWARP_STATE_SHIFT 28 +#define NES_CQP_OP_TERMLEN_SHIFT 28 enum nes_cqp_qp_bits { NES_CQP_QP_ARP_VALID = (1<<8), @@ -265,6 +266,8 @@ enum nes_cqp_qp_bits { NES_CQP_QP_IWARP_STATE_TERMINATE = (5< 21)) || ((major_ver > 2) && (major_ver != 255))) { nesadapter->virtwq = 1; } + if (((major_ver == 3) && (minor_ver >= 16)) || (major_ver > 3)) + nesadapter->send_term_ok = 1; + nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8)) << 16) + (u32)((u8)eeprom_data); diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index c6b5873..36666ac 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -2923,7 +2923,7 @@ static int nes_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, * nes_hw_modify_qp */ int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp, - u32 next_iwarp_state, u32 wait_completion) + u32 next_iwarp_state, u32 termlen, u32 wait_completion) { struct nes_hw_cqp_wqe *cqp_wqe; /* struct iw_cm_id *cm_id = nesqp->cm_id; */ @@ -2955,6 +2955,13 @@ int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp, set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id); set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, (u64)nesqp->nesqp_context_pbase); + /* If sending a terminate message, fill in the length (in words) */ + if (((next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) == NES_CQP_QP_IWARP_STATE_TERMINATE) && + !(next_iwarp_state & NES_CQP_QP_TERM_DONT_SEND_TERM_MSG)) { + termlen = ((termlen + 3) >> 2) << NES_CQP_OP_TERMLEN_SHIFT; + set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_NEW_MSS_IDX, termlen); + } + atomic_set(&cqp_request->refcount, 2); nes_post_cqp_request(nesdev, cqp_request); @@ -3125,6 +3132,9 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, } nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n", nesqp->hwqp.qp_id); + if (nesqp->term_flags) + del_timer(&nesqp->terminate_timer); + next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR; /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */ if (nesqp->hte_added) { @@ -3202,7 +3212,7 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, if (issue_modify_qp) { nes_debug(NES_DBG_MOD_QP, "call nes_hw_modify_qp\n"); - ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 1); + ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 1); if (ret) nes_debug(NES_DBG_MOD_QP, "nes_hw_modify_qp (next_iwarp_state = 0x%08X)" " failed for QP%u.\n", @@ -3367,6 +3377,12 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr, head = nesqp->hwqp.sq_head; while (ib_wr) { + /* Check for QP error */ + if (nesqp->term_flags) { + err = -EINVAL; + break; + } + /* Check for SQ overflow */ if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) { err = -EINVAL; @@ -3523,6 +3539,12 @@ static int nes_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr, head = nesqp->hwqp.rq_head; while (ib_wr) { + /* Check for QP error */ + if (nesqp->term_flags) { + err = -EINVAL; + break; + } + if (ib_wr->num_sge > nesdev->nesadapter->max_sge) { err = -EINVAL; break; diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index 7df34fe..d92b1ef 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h @@ -40,6 +40,10 @@ struct nes_device; #define NES_MAX_USER_DB_REGIONS 4096 #define NES_MAX_USER_WQ_REGIONS 4096 +#define NES_TERM_SENT 0x01 +#define NES_TERM_RCVD 0x02 +#define NES_TERM_DONE 0x04 + struct nes_ucontext { struct ib_ucontext ibucontext; struct nes_device *nesdev; @@ -159,6 +163,8 @@ struct nes_qp { void *pbl_vbase; dma_addr_t pbl_pbase; struct page *page; + struct timer_list terminate_timer; + enum ib_event_type terminate_eventtype; wait_queue_head_t kick_waitq; u16 in_disconnect; u16 private_data_len; @@ -169,6 +175,7 @@ struct nes_qp { u8 hw_iwarp_state; u8 flush_issued; u8 hw_tcp_state; + u8 term_flags; u8 destroyed; }; #endif /* NES_VERBS_H */ -- cgit v0.10.2 From 4b281faec3ad00f7fb00080078321e4d819795eb Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:38 -0700 Subject: RDMA/nes: Use flush mechanism to set status for wqe in error When an asynchronous event occurs that requires a terminate, it is sometimes possible to identify the wqe in error. This change uses flush to get this information to the poll routine. The flush operation puts the status into the cqe. If this information is not available, it continues to use the more generic flush code as before. Signed-off-by: Don Wood Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 297026f..63a1a8e 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2944,6 +2944,7 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a u16 ddp_seg_len; int copy_len = 0; u8 is_tagged = 0; + u8 flush_code = 0; struct nes_terminate_hdr *termhdr; termhdr = (struct nes_terminate_hdr *)nesqp->hwqp.q2_vbase; @@ -2983,19 +2984,23 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: switch (iwarp_opcode(nesqp, aeq_info)) { case IWARP_OPCODE_WRITE: + flush_code = IB_WC_LOC_PROT_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; termhdr->error_code = DDP_TAGGED_INV_STAG; break; default: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_INV_STAG; } break; case NES_AEQE_AEID_AMP_INVALID_STAG: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_INV_STAG; break; case NES_AEQE_AEID_AMP_BAD_QP: + flush_code = IB_WC_LOC_QP_OP_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_QN; break; @@ -3004,19 +3009,23 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a switch (iwarp_opcode(nesqp, aeq_info)) { case IWARP_OPCODE_SEND_INV: case IWARP_OPCODE_SEND_SE_INV: + flush_code = IB_WC_REM_OP_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; termhdr->error_code = RDMAP_CANT_INV_STAG; break; default: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_INV_STAG; } break; case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: if (aeq_info & (NES_AEQE_Q2_DATA_ETHERNET | NES_AEQE_Q2_DATA_MPA)) { + flush_code = IB_WC_LOC_PROT_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; termhdr->error_code = DDP_TAGGED_BOUNDS; } else { + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_INV_BOUNDS; } @@ -3024,57 +3033,69 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION: case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS: case NES_AEQE_AEID_PRIV_OPERATION_DENIED: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_ACCESS; break; case NES_AEQE_AEID_AMP_TO_WRAP: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_TO_WRAP; break; case NES_AEQE_AEID_AMP_BAD_PD: switch (iwarp_opcode(nesqp, aeq_info)) { case IWARP_OPCODE_WRITE: + flush_code = IB_WC_LOC_PROT_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; termhdr->error_code = DDP_TAGGED_UNASSOC_STAG; break; case IWARP_OPCODE_SEND_INV: case IWARP_OPCODE_SEND_SE_INV: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_CANT_INV_STAG; break; default: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_UNASSOC_STAG; } break; case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH: + flush_code = IB_WC_LOC_LEN_ERR; termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; termhdr->error_code = MPA_MARKER; break; case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: + flush_code = IB_WC_GENERAL_ERR; termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; termhdr->error_code = MPA_CRC; break; case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE: case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: + flush_code = IB_WC_LOC_LEN_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; termhdr->error_code = DDP_CATASTROPHIC_LOCAL; break; case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC: case NES_AEQE_AEID_DDP_NO_L_BIT: + flush_code = IB_WC_FATAL_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; termhdr->error_code = DDP_CATASTROPHIC_LOCAL; break; case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN: case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID: + flush_code = IB_WC_GENERAL_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_MSN_RANGE; break; case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: + flush_code = IB_WC_LOC_LEN_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_TOO_LONG; break; case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION: + flush_code = IB_WC_GENERAL_ERR; if (is_tagged) { termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; termhdr->error_code = DDP_TAGGED_INV_DDP_VER; @@ -3084,26 +3105,32 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a } break; case NES_AEQE_AEID_DDP_UBE_INVALID_MO: + flush_code = IB_WC_GENERAL_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_MO; break; case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: + flush_code = IB_WC_REM_OP_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_MSN_NO_BUF; break; case NES_AEQE_AEID_DDP_UBE_INVALID_QN: + flush_code = IB_WC_GENERAL_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_QN; break; case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION: + flush_code = IB_WC_GENERAL_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; termhdr->error_code = RDMAP_INV_RDMAP_VER; break; case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE: + flush_code = IB_WC_LOC_QP_OP_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; termhdr->error_code = RDMAP_UNEXPECTED_OP; break; default: + flush_code = IB_WC_FATAL_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; termhdr->error_code = RDMAP_UNSPECIFIED; break; @@ -3112,6 +3139,13 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a if (copy_len) memcpy(termhdr + 1, pkt, copy_len); + if ((flush_code) && ((NES_AEQE_INBOUND_RDMA & aeq_info) == 0)) { + if (aeq_info & NES_AEQE_SQ) + nesqp->term_sq_flush_code = flush_code; + else + nesqp->term_rq_flush_code = flush_code; + } + return sizeof(struct nes_terminate_hdr) + copy_len; } @@ -3646,6 +3680,8 @@ void flush_wqes(struct nes_device *nesdev, struct nes_qp *nesqp, { struct nes_cqp_request *cqp_request; struct nes_hw_cqp_wqe *cqp_wqe; + u32 sq_code = (NES_IWARP_CQE_MAJOR_FLUSH << 16) | NES_IWARP_CQE_MINOR_FLUSH; + u32 rq_code = (NES_IWARP_CQE_MAJOR_FLUSH << 16) | NES_IWARP_CQE_MINOR_FLUSH; int ret; cqp_request = nes_get_cqp_request(nesdev); @@ -3662,6 +3698,24 @@ void flush_wqes(struct nes_device *nesdev, struct nes_qp *nesqp, cqp_wqe = &cqp_request->cqp_wqe; nes_fill_init_cqp_wqe(cqp_wqe, nesdev); + /* If wqe in error was identified, set code to be put into cqe */ + if ((nesqp->term_sq_flush_code) && (which_wq & NES_CQP_FLUSH_SQ)) { + which_wq |= NES_CQP_FLUSH_MAJ_MIN; + sq_code = (CQE_MAJOR_DRV << 16) | nesqp->term_sq_flush_code; + nesqp->term_sq_flush_code = 0; + } + + if ((nesqp->term_rq_flush_code) && (which_wq & NES_CQP_FLUSH_RQ)) { + which_wq |= NES_CQP_FLUSH_MAJ_MIN; + rq_code = (CQE_MAJOR_DRV << 16) | nesqp->term_rq_flush_code; + nesqp->term_rq_flush_code = 0; + } + + if (which_wq & NES_CQP_FLUSH_MAJ_MIN) { + cqp_wqe->wqe_words[NES_CQP_QP_WQE_FLUSH_SQ_CODE] = cpu_to_le32(sq_code); + cqp_wqe->wqe_words[NES_CQP_QP_WQE_FLUSH_RQ_CODE] = cpu_to_le32(rq_code); + } + cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_FLUSH_WQES | which_wq); cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesqp->hwqp.qp_id); diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 4a0bfcd..f28a41b 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -274,6 +274,8 @@ enum nes_cqp_qp_bits { enum nes_cqp_qp_wqe_word_idx { NES_CQP_QP_WQE_CONTEXT_LOW_IDX = 6, NES_CQP_QP_WQE_CONTEXT_HIGH_IDX = 7, + NES_CQP_QP_WQE_FLUSH_SQ_CODE = 8, + NES_CQP_QP_WQE_FLUSH_RQ_CODE = 9, NES_CQP_QP_WQE_NEW_MSS_IDX = 15, }; @@ -364,6 +366,7 @@ enum nes_cqp_arp_bits { enum nes_cqp_flush_bits { NES_CQP_FLUSH_SQ = (1<<30), NES_CQP_FLUSH_RQ = (1<<31), + NES_CQP_FLUSH_MAJ_MIN = (1<<28), }; enum nes_cqe_opcode_bits { @@ -757,6 +760,15 @@ enum nes_iwarp_sq_wqe_bits { NES_IWARP_SQ_OP_NOP = 12, }; +enum nes_iwarp_cqe_major_code { + NES_IWARP_CQE_MAJOR_FLUSH = 1, + NES_IWARP_CQE_MAJOR_DRV = 0x8000 +}; + +enum nes_iwarp_cqe_minor_code { + NES_IWARP_CQE_MINOR_FLUSH = 1 +}; + #define NES_EEPROM_READ_REQUEST (1<<16) #define NES_MAC_ADDR_VALID (1<<20) diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index d92b1ef..89822d7 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h @@ -168,6 +168,8 @@ struct nes_qp { wait_queue_head_t kick_waitq; u16 in_disconnect; u16 private_data_len; + u16 term_sq_flush_code; + u16 term_rq_flush_code; u8 active_conn; u8 skip_lsmm; u8 user_mode; -- cgit v0.10.2 From 6eed5e7c8bdce6ee21bbe0be4a3f3dce4d4b392a Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:39 -0700 Subject: RDMA/nes: Make poll_cq return correct number of wqes during flush When a flush request is given to the hw, it will place one cqe marked as flushed (unless there is nothing to flush). An application that is waiting for all wqe's to complete will be left hanging. This modifies poll_cq to return the correct number of flushes for the pending elements on the wq. Signed-off-by: Don Wood Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 36666ac..ad3c891 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -3615,11 +3615,13 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) struct nes_qp *nesqp; struct nes_hw_cqe cqe; u32 head; - u32 wq_tail; + u32 wq_tail = 0; u32 cq_size; u32 cqe_count = 0; u32 wqe_index; u32 u32temp; + u32 move_cq_head = 1; + u32 err_code; nes_debug(NES_DBG_CQ, "\n"); @@ -3640,7 +3642,6 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) rmb(); cqe = nescq->hw_cq.cq_vbase[head]; - nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0; u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]); wqe_index = u32temp & (nesdev->nesadapter->max_qp_wr - 1); u32temp &= ~(NES_SW_CONTEXT_ALIGN-1); @@ -3667,16 +3668,14 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) } /* Working on a SQ Completion*/ - wq_tail = wqe_index; - nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1); - wrid = (((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wq_tail]. + wrid = (((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wqe_index]. wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) | - ((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wq_tail]. + ((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wqe_index]. wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX]))); - entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail]. + entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index]. wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX]); - switch (le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail]. + switch (le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index]. wqe_words[NES_IWARP_SQ_WQE_MISC_IDX]) & 0x3f) { case NES_IWARP_SQ_OP_RDMAW: nes_debug(NES_DBG_CQ, "Operation = RDMA WRITE.\n"); @@ -3685,7 +3684,7 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) case NES_IWARP_SQ_OP_RDMAR: nes_debug(NES_DBG_CQ, "Operation = RDMA READ.\n"); entry->opcode = IB_WC_RDMA_READ; - entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail]. + entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index]. wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX]); break; case NES_IWARP_SQ_OP_SENDINV: @@ -3696,14 +3695,24 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) entry->opcode = IB_WC_SEND; break; } + + nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1); + if ((entry->status != IB_WC_SUCCESS) && (nesqp->hwqp.sq_tail != nesqp->hwqp.sq_head)) { + move_cq_head = 0; + wq_tail = nesqp->hwqp.sq_tail; + } } else { /* Working on a RQ Completion*/ - wq_tail = wqe_index; - nesqp->hwqp.rq_tail = (wqe_index+1)&(nesqp->hwqp.rq_size - 1); entry->byte_len = le32_to_cpu(cqe.cqe_words[NES_CQE_PAYLOAD_LENGTH_IDX]); - wrid = ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX]))) | - ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32); + wrid = ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wqe_index].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX]))) | + ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wqe_index].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32); entry->opcode = IB_WC_RECV; + + nesqp->hwqp.rq_tail = (wqe_index+1)&(nesqp->hwqp.rq_size - 1); + if ((entry->status != IB_WC_SUCCESS) && (nesqp->hwqp.rq_tail != nesqp->hwqp.rq_head)) { + move_cq_head = 0; + wq_tail = nesqp->hwqp.rq_tail; + } } entry->wr_id = wrid; @@ -3711,18 +3720,28 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) cqe_count++; } - if (++head >= cq_size) - head = 0; - nescq->polled_completions++; + if (move_cq_head) { + nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0; + if (++head >= cq_size) + head = 0; + nescq->polled_completions++; - if ((nescq->polled_completions > (cq_size / 2)) || - (nescq->polled_completions == 255)) { - nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes" + if ((nescq->polled_completions > (cq_size / 2)) || + (nescq->polled_completions == 255)) { + nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes" " are pending %u of %u.\n", nescq->hw_cq.cq_number, nescq->polled_completions, cq_size); - nes_write32(nesdev->regs+NES_CQE_ALLOC, + nes_write32(nesdev->regs+NES_CQE_ALLOC, nescq->hw_cq.cq_number | (nescq->polled_completions << 16)); - nescq->polled_completions = 0; + nescq->polled_completions = 0; + } + } else { + /* Update the wqe index and set status to flush */ + wqe_index = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]); + wqe_index = (wqe_index & (~(nesdev->nesadapter->max_qp_wr - 1))) | wq_tail; + nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX] = + cpu_to_le32(wqe_index); + move_cq_head = 1; /* ready for next pass */ } } -- cgit v0.10.2 From 320cdfd21d4a9f6ef54b74871e0d6b19a0e86fd6 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:39 -0700 Subject: RDMA/nes: Use the flush code to fill in cqe error Use the flush status to fill in cqe status when a specific error has been identified. Subsequent flushed completions still use the flushed value. Signed-off-by: Don Wood Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index ad3c891..993c1d4 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -3655,7 +3655,16 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) if (cqe.cqe_words[NES_CQE_ERROR_CODE_IDX] == 0) { entry->status = IB_WC_SUCCESS; } else { - entry->status = IB_WC_WR_FLUSH_ERR; + err_code = le32_to_cpu(cqe.cqe_words[NES_CQE_ERROR_CODE_IDX]); + if (NES_IWARP_CQE_MAJOR_DRV == (err_code >> 16)) { + entry->status = err_code & 0x0000ffff; + + /* The rest of the cqe's will be marked as flushed */ + nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX] = + cpu_to_le32((NES_IWARP_CQE_MAJOR_FLUSH << 16) | + NES_IWARP_CQE_MINOR_FLUSH); + } else + entry->status = IB_WC_WR_FLUSH_ERR; } entry->qp = &nesqp->ibqp; -- cgit v0.10.2 From b29a4fc49b028dbdab53b679826ed1eb658dde59 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:39 -0700 Subject: RDMA/nes: Rework the disconn routine for terminate and flushing The disconn routine has been reworked to acoomodate the terminate and flushing changes. The routine has been reorganized to make all the decisions at the start then it performs all the required operations. This simplified the lock handling and is easier to follow. Signed-off-by: Don Wood Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index d89bdee..73473db 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -2493,7 +2493,12 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) u16 last_ae; u8 original_hw_tcp_state; u8 original_ibqp_state; - u8 issued_disconnect_reset = 0; + enum iw_cm_event_type disconn_status = IW_CM_EVENT_STATUS_OK; + int issue_disconn = 0; + int issue_close = 0; + int issue_flush = 0; + u32 flush_q = NES_CQP_FLUSH_RQ; + struct ib_event ibevent; if (!nesqp) { nes_debug(NES_DBG_CM, "disconnect_worker nesqp is NULL\n"); @@ -2517,24 +2522,55 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) original_ibqp_state = nesqp->ibqp_state; last_ae = nesqp->last_aeq; + if (nesqp->term_flags) { + issue_disconn = 1; + issue_close = 1; + nesqp->cm_id = NULL; + if (nesqp->flush_issued == 0) { + nesqp->flush_issued = 1; + issue_flush = 1; + } + } else if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || + ((original_ibqp_state == IB_QPS_RTS) && + (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { + issue_disconn = 1; + if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) + disconn_status = IW_CM_EVENT_STATUS_RESET; + } + + if (((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) || + (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) || + (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) || + (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { + issue_close = 1; + nesqp->cm_id = NULL; + if (nesqp->flush_issued == 0) { + nesqp->flush_issued = 1; + issue_flush = 1; + } + } + + spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_CM, "set ibqp_state=%u\n", nesqp->ibqp_state); + if ((issue_flush) && (nesqp->destroyed == 0)) { + /* Flush the queue(s) */ + if (nesqp->hw_iwarp_state >= NES_AEQE_IWARP_STATE_TERMINATE) + flush_q |= NES_CQP_FLUSH_SQ; + flush_wqes(nesvnic->nesdev, nesqp, flush_q, 1); - if ((nesqp->cm_id) && (cm_id->event_handler)) { - if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || - ((original_ibqp_state == IB_QPS_RTS) && - (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { + if (nesqp->term_flags) { + ibevent.device = nesqp->ibqp.device; + ibevent.event = nesqp->terminate_eventtype; + ibevent.element.qp = &nesqp->ibqp; + nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); + } + } + + if ((cm_id) && (cm_id->event_handler)) { + if (issue_disconn) { atomic_inc(&cm_disconnects); cm_event.event = IW_CM_EVENT_DISCONNECT; - if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) { - cm_event.status = IW_CM_EVENT_STATUS_RESET; - nes_debug(NES_DBG_CM, "Generating a CM " - "Disconnect Event (status reset) for " - "QP%u, cm_id = %p. \n", - nesqp->hwqp.qp_id, cm_id); - } else - cm_event.status = IW_CM_EVENT_STATUS_OK; - + cm_event.status = disconn_status; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; cm_event.private_data = NULL; @@ -2547,28 +2583,14 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) nesqp->hwqp.sq_tail, cm_id, atomic_read(&nesqp->refcount)); - spin_unlock_irqrestore(&nesqp->lock, flags); ret = cm_id->event_handler(cm_id, &cm_event); if (ret) nes_debug(NES_DBG_CM, "OFA CM event_handler " "returned, ret=%d\n", ret); - spin_lock_irqsave(&nesqp->lock, flags); } - /* There might have been another AE while the lock was released */ - original_hw_tcp_state = nesqp->hw_tcp_state; - original_ibqp_state = nesqp->ibqp_state; - last_ae = nesqp->last_aeq; - - if ((issued_disconnect_reset == 0) && (nesqp->cm_id) && - ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) || - (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) || - (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) || - (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { + if (issue_close) { atomic_inc(&cm_closes); - nesqp->cm_id = NULL; - nesqp->in_disconnect = 0; - spin_unlock_irqrestore(&nesqp->lock, flags); nes_disconnect(nesqp, 1); cm_id->provider_data = nesqp; @@ -2587,27 +2609,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) } cm_id->rem_ref(cm_id); - - spin_lock_irqsave(&nesqp->lock, flags); - if (nesqp->flush_issued == 0) { - nesqp->flush_issued = 1; - spin_unlock_irqrestore(&nesqp->lock, flags); - flush_wqes(nesvnic->nesdev, nesqp, - NES_CQP_FLUSH_RQ, 1); - } else - spin_unlock_irqrestore(&nesqp->lock, flags); - } else { - cm_id = nesqp->cm_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - /* check to see if the inbound reset beat the outbound reset */ - if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) { - nes_debug(NES_DBG_CM, "QP%u: Decing refcount " - "due to inbound reset beating the " - "outbound reset.\n", nesqp->hwqp.qp_id); - } } - } else { - spin_unlock_irqrestore(&nesqp->lock, flags); } return 0; -- cgit v0.10.2 From cd1d3f7abec19719949ec5b5189a821cd52af868 Mon Sep 17 00:00:00 2001 From: Chien Tung Date: Sat, 5 Sep 2009 20:36:39 -0700 Subject: RDMA/nes: Map MTU to IB_MTU_* and correctly report link state Old query_port code reports static MTU and link state values. Instead, map actual MTU to next largest IB_MTU_* constant and correctly report link state. Cc: Steve Wise Reported-by: Jeff Squyres Signed-off-by: Chien Tung Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 993c1d4..a680c42 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -667,15 +667,32 @@ static int nes_query_device(struct ib_device *ibdev, struct ib_device_attr *prop */ static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props) { + struct nes_vnic *nesvnic = to_nesvnic(ibdev); + struct net_device *netdev = nesvnic->netdev; + memset(props, 0, sizeof(*props)); - props->max_mtu = IB_MTU_2048; - props->active_mtu = IB_MTU_2048; + props->max_mtu = IB_MTU_4096; + + if (netdev->mtu >= 4096) + props->active_mtu = IB_MTU_4096; + else if (netdev->mtu >= 2048) + props->active_mtu = IB_MTU_2048; + else if (netdev->mtu >= 1024) + props->active_mtu = IB_MTU_1024; + else if (netdev->mtu >= 512) + props->active_mtu = IB_MTU_512; + else + props->active_mtu = IB_MTU_256; + props->lid = 1; props->lmc = 0; props->sm_lid = 0; props->sm_sl = 0; - props->state = IB_PORT_ACTIVE; + if (nesvnic->linkup) + props->state = IB_PORT_ACTIVE; + else + props->state = IB_PORT_DOWN; props->phys_state = 0; props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP | IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP; -- cgit v0.10.2 From 23b6c52cf558f2a1dc6c7010c601b3624eb4591f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 5 Sep 2009 01:07:45 +0200 Subject: x86: Decrease the level of some NUMA messages to KERN_DEBUG Some NUMA messages in srat_32.c are confusing to users, because they seem to indicate errors, while in fact they reflect normal behaviour. Decrease the level of these messages to KERN_DEBUG so that they don't show up unnecessarily. Signed-off-by: Rafael J. Wysocki LKML-Reference: <200909050107.45175.rjw@sisk.pl> Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/srat_32.c b/arch/x86/mm/srat_32.c index 29a0e37..6f8aa33 100644 --- a/arch/x86/mm/srat_32.c +++ b/arch/x86/mm/srat_32.c @@ -215,7 +215,7 @@ int __init get_memcfg_from_srat(void) goto out_fail; if (num_memory_chunks == 0) { - printk(KERN_WARNING + printk(KERN_DEBUG "could not find any ACPI SRAT memory areas.\n"); goto out_fail; } @@ -277,7 +277,7 @@ int __init get_memcfg_from_srat(void) } return 1; out_fail: - printk(KERN_ERR "failed to get NUMA memory information from SRAT" + printk(KERN_DEBUG "failed to get NUMA memory information from SRAT" " table\n"); return 0; } -- cgit v0.10.2 From d535e4319a2e598ba25dc966ada4e52ea774e33f Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 4 Sep 2009 15:53:09 +0200 Subject: x86: Make memtype_seq_ops const Signed-off-by: Tobias Klauser Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index e6718bb..e2900a3 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -826,7 +826,7 @@ static int memtype_seq_show(struct seq_file *seq, void *v) return 0; } -static struct seq_operations memtype_seq_ops = { +static const struct seq_operations memtype_seq_ops = { .start = memtype_seq_start, .next = memtype_seq_next, .stop = memtype_seq_stop, -- cgit v0.10.2 From 71ebe5e91947392bc276af713827eab12b6db8e4 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 4 Sep 2009 06:41:15 +0000 Subject: net_sched: make cls_ops->tcf_chain() optional Some qdiscs don't support attaching filters. Handle this centrally in cls_api and return a proper errno code (EOPNOTSUPP) instead of EINVAL. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 09cdcdf..bcfbdb4 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -181,6 +181,9 @@ replay: if ((cops = q->ops->cl_ops) == NULL) return -EINVAL; + if (cops->tcf_chain == NULL) + return -EOPNOTSUPP; + /* Do we search for filter, attached to class? */ if (TC_H_MIN(parent)) { cl = cops->get(q, parent); @@ -433,6 +436,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) goto out; if ((cops = q->ops->cl_ops) == NULL) goto errout; + if (cops->tcf_chain == NULL) + goto errout; if (TC_H_MIN(tcm->tcm_parent)) { cl = cops->get(q, tcm->tcm_parent); if (cl == 0) diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 2bdf241..c27b802 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -331,11 +331,6 @@ static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker) } } -static struct tcf_proto **red_find_tcf(struct Qdisc *sch, unsigned long cl) -{ - return NULL; -} - static const struct Qdisc_class_ops red_class_ops = { .graft = red_graft, .leaf = red_leaf, @@ -344,7 +339,6 @@ static const struct Qdisc_class_ops red_class_ops = { .change = red_change_class, .delete = red_delete, .walk = red_walk, - .tcf_chain = red_find_tcf, .dump = red_dump_class, }; diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index e22dfe8..2890969 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -433,11 +433,6 @@ static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker) } } -static struct tcf_proto **tbf_find_tcf(struct Qdisc *sch, unsigned long cl) -{ - return NULL; -} - static const struct Qdisc_class_ops tbf_class_ops = { .graft = tbf_graft, @@ -447,7 +442,6 @@ static const struct Qdisc_class_ops tbf_class_ops = .change = tbf_change_class, .delete = tbf_delete, .walk = tbf_walk, - .tcf_chain = tbf_find_tcf, .dump = tbf_dump_class, }; -- cgit v0.10.2 From de6d5cdf881353f83006d5f3e28ac4fffd42145e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 4 Sep 2009 06:41:16 +0000 Subject: net_sched: make cls_ops->change and cls_ops->delete optional Some schedulers don't support creating, changing or deleting classes. Make the respective callbacks optionally and consistently return -EOPNOTSUPP for unsupported operations, instead of currently either -EOPNOTSUPP, -ENOSYS or no error. In case of sch_prio and sch_multiq, the removed operations additionally checked for an invalid class. This is not necessary since the class argument can only orginate from ->get() or in case of ->change is 0 for creation of new classes, in which case ->change() incorrectly returned -ENOENT. As a side-effect, this patch fixes a possible (root-only) NULL pointer function call in sch_ingress, which didn't implement a so far mandatory ->delete() operation. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index bef2d64..166fcca 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1417,7 +1417,9 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) goto out; break; case RTM_DELTCLASS: - err = cops->delete(q, cl); + err = -EOPNOTSUPP; + if (cops->delete) + err = cops->delete(q, cl); if (err == 0) tclass_notify(skb, n, q, cl, RTM_DELTCLASS); goto out; @@ -1431,7 +1433,9 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) } new_cl = cl; - err = cops->change(q, clid, pid, tca, &new_cl); + err = -EOPNOTSUPP; + if (cops->change) + err = cops->change(q, clid, pid, tca, &new_cl); if (err == 0) tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS); diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index ace7902..a9e646b 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -42,12 +42,6 @@ static void ingress_put(struct Qdisc *sch, unsigned long cl) { } -static int ingress_change(struct Qdisc *sch, u32 classid, u32 parent, - struct nlattr **tca, unsigned long *arg) -{ - return 0; -} - static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker) { return; @@ -120,7 +114,6 @@ static const struct Qdisc_class_ops ingress_class_ops = { .leaf = ingress_leaf, .get = ingress_get, .put = ingress_put, - .change = ingress_change, .walk = ingress_walk, .tcf_chain = ingress_find_tcf, .bind_tcf = ingress_bind_filter, diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 9127312..a0ffe71 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -348,26 +348,6 @@ static void multiq_put(struct Qdisc *q, unsigned long cl) return; } -static int multiq_change(struct Qdisc *sch, u32 handle, u32 parent, - struct nlattr **tca, unsigned long *arg) -{ - unsigned long cl = *arg; - struct multiq_sched_data *q = qdisc_priv(sch); - - if (cl - 1 > q->bands) - return -ENOENT; - return 0; -} - -static int multiq_delete(struct Qdisc *sch, unsigned long cl) -{ - struct multiq_sched_data *q = qdisc_priv(sch); - if (cl - 1 > q->bands) - return -ENOENT; - return 0; -} - - static int multiq_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { @@ -430,8 +410,6 @@ static const struct Qdisc_class_ops multiq_class_ops = { .leaf = multiq_leaf, .get = multiq_get, .put = multiq_put, - .change = multiq_change, - .delete = multiq_delete, .walk = multiq_walk, .tcf_chain = multiq_find_tcf, .bind_tcf = multiq_bind, diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 94cecef..209a4ca 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -311,25 +311,6 @@ static void prio_put(struct Qdisc *q, unsigned long cl) return; } -static int prio_change(struct Qdisc *sch, u32 handle, u32 parent, struct nlattr **tca, unsigned long *arg) -{ - unsigned long cl = *arg; - struct prio_sched_data *q = qdisc_priv(sch); - - if (cl - 1 > q->bands) - return -ENOENT; - return 0; -} - -static int prio_delete(struct Qdisc *sch, unsigned long cl) -{ - struct prio_sched_data *q = qdisc_priv(sch); - if (cl - 1 > q->bands) - return -ENOENT; - return 0; -} - - static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { @@ -392,8 +373,6 @@ static const struct Qdisc_class_ops prio_class_ops = { .leaf = prio_leaf, .get = prio_get, .put = prio_put, - .change = prio_change, - .delete = prio_delete, .walk = prio_walk, .tcf_chain = prio_find_tcf, .bind_tcf = prio_bind, diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index c27b802..a2c4d1a 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -308,17 +308,6 @@ static void red_put(struct Qdisc *sch, unsigned long arg) return; } -static int red_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct nlattr **tca, unsigned long *arg) -{ - return -ENOSYS; -} - -static int red_delete(struct Qdisc *sch, unsigned long cl) -{ - return -ENOSYS; -} - static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker) { if (!walker->stop) { @@ -336,8 +325,6 @@ static const struct Qdisc_class_ops red_class_ops = { .leaf = red_leaf, .get = red_get, .put = red_put, - .change = red_change_class, - .delete = red_delete, .walk = red_walk, .dump = red_dump_class, }; diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 8706920..cb21380 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -496,12 +496,6 @@ nla_put_failure: return -1; } -static int sfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct nlattr **tca, unsigned long *arg) -{ - return -EOPNOTSUPP; -} - static unsigned long sfq_get(struct Qdisc *sch, u32 classid) { return 0; @@ -560,7 +554,6 @@ static void sfq_walk(struct Qdisc *sch, struct qdisc_walker *arg) static const struct Qdisc_class_ops sfq_class_ops = { .get = sfq_get, - .change = sfq_change_class, .tcf_chain = sfq_find_tcf, .dump = sfq_dump_class, .dump_stats = sfq_dump_class_stats, diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 2890969..d904167 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -410,17 +410,6 @@ static void tbf_put(struct Qdisc *sch, unsigned long arg) { } -static int tbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct nlattr **tca, unsigned long *arg) -{ - return -ENOSYS; -} - -static int tbf_delete(struct Qdisc *sch, unsigned long arg) -{ - return -ENOSYS; -} - static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker) { if (!walker->stop) { @@ -439,8 +428,6 @@ static const struct Qdisc_class_ops tbf_class_ops = .leaf = tbf_leaf, .get = tbf_get, .put = tbf_put, - .change = tbf_change_class, - .delete = tbf_delete, .walk = tbf_walk, .dump = tbf_dump_class, }; -- cgit v0.10.2 From 5b9a9ccfad8553dbf7a9b17ba78bad70215ed0e2 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 4 Sep 2009 06:41:17 +0000 Subject: net_sched: remove some unnecessary checks in classful schedulers The class argument to the ->graft(), ->leaf(), ->dump(), ->dump_stats() all originate from either ->get() or ->walk() and are always valid. Remove unnecessary checks. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index d5798e1..5b132c4 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1621,29 +1621,25 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, { struct cbq_class *cl = (struct cbq_class*)arg; - if (cl) { - if (new == NULL) { - new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, - &pfifo_qdisc_ops, - cl->common.classid); - if (new == NULL) - return -ENOBUFS; - } else { + if (new == NULL) { + new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, cl->common.classid); + if (new == NULL) + return -ENOBUFS; + } else { #ifdef CONFIG_NET_CLS_ACT - if (cl->police == TC_POLICE_RECLASSIFY) - new->reshape_fail = cbq_reshape_fail; + if (cl->police == TC_POLICE_RECLASSIFY) + new->reshape_fail = cbq_reshape_fail; #endif - } - sch_tree_lock(sch); - *old = cl->q; - cl->q = new; - qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); - qdisc_reset(*old); - sch_tree_unlock(sch); - - return 0; } - return -ENOENT; + sch_tree_lock(sch); + *old = cl->q; + cl->q = new; + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); + sch_tree_unlock(sch); + + return 0; } static struct Qdisc * @@ -1651,7 +1647,7 @@ cbq_leaf(struct Qdisc *sch, unsigned long arg) { struct cbq_class *cl = (struct cbq_class*)arg; - return cl ? cl->q : NULL; + return cl->q; } static void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg) diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index dad0144..375d64c 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1203,8 +1203,6 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, { struct hfsc_class *cl = (struct hfsc_class *)arg; - if (cl == NULL) - return -ENOENT; if (cl->level > 0) return -EINVAL; if (new == NULL) { @@ -1228,7 +1226,7 @@ hfsc_class_leaf(struct Qdisc *sch, unsigned long arg) { struct hfsc_class *cl = (struct hfsc_class *)arg; - if (cl != NULL && cl->level == 0) + if (cl->level == 0) return cl->qdisc; return NULL; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index ec4d463..85acab9 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1117,30 +1117,29 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, { struct htb_class *cl = (struct htb_class *)arg; - if (cl && !cl->level) { - if (new == NULL && - (new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, - &pfifo_qdisc_ops, - cl->common.classid)) - == NULL) - return -ENOBUFS; - sch_tree_lock(sch); - *old = cl->un.leaf.q; - cl->un.leaf.q = new; - if (*old != NULL) { - qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); - qdisc_reset(*old); - } - sch_tree_unlock(sch); - return 0; + if (cl->level) + return -EINVAL; + if (new == NULL && + (new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, + cl->common.classid)) == NULL) + return -ENOBUFS; + + sch_tree_lock(sch); + *old = cl->un.leaf.q; + cl->un.leaf.q = new; + if (*old != NULL) { + qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); + qdisc_reset(*old); } - return -ENOENT; + sch_tree_unlock(sch); + return 0; } static struct Qdisc *htb_leaf(struct Qdisc *sch, unsigned long arg) { struct htb_class *cl = (struct htb_class *)arg; - return (cl && !cl->level) ? cl->un.leaf.q : NULL; + return !cl->level ? cl->un.leaf.q : NULL; } static void htb_qlen_notify(struct Qdisc *sch, unsigned long arg) diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index a0ffe71..069f81c 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -298,9 +298,6 @@ static int multiq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, struct multiq_sched_data *q = qdisc_priv(sch); unsigned long band = arg - 1; - if (band >= q->bands) - return -EINVAL; - if (new == NULL) new = &noop_qdisc; @@ -320,9 +317,6 @@ multiq_leaf(struct Qdisc *sch, unsigned long arg) struct multiq_sched_data *q = qdisc_priv(sch); unsigned long band = arg - 1; - if (band >= q->bands) - return NULL; - return q->queues[band]; } @@ -353,11 +347,8 @@ static int multiq_dump_class(struct Qdisc *sch, unsigned long cl, { struct multiq_sched_data *q = qdisc_priv(sch); - if (cl - 1 > q->bands) - return -ENOENT; tcm->tcm_handle |= TC_H_MIN(cl); - if (q->queues[cl-1]) - tcm->tcm_info = q->queues[cl-1]->handle; + tcm->tcm_info = q->queues[cl-1]->handle; return 0; } diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 209a4ca..0f73c41 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -262,9 +262,6 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, struct prio_sched_data *q = qdisc_priv(sch); unsigned long band = arg - 1; - if (band >= q->bands) - return -EINVAL; - if (new == NULL) new = &noop_qdisc; @@ -284,9 +281,6 @@ prio_leaf(struct Qdisc *sch, unsigned long arg) struct prio_sched_data *q = qdisc_priv(sch); unsigned long band = arg - 1; - if (band >= q->bands) - return NULL; - return q->queues[band]; } @@ -316,11 +310,8 @@ static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff * { struct prio_sched_data *q = qdisc_priv(sch); - if (cl - 1 > q->bands) - return -ENOENT; tcm->tcm_handle |= TC_H_MIN(cl); - if (q->queues[cl-1]) - tcm->tcm_info = q->queues[cl-1]->handle; + tcm->tcm_info = q->queues[cl-1]->handle; return 0; } diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index a2c4d1a..072cdf4 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -268,8 +268,6 @@ static int red_dump_class(struct Qdisc *sch, unsigned long cl, { struct red_sched_data *q = qdisc_priv(sch); - if (cl != 1) - return -ENOENT; tcm->tcm_handle |= TC_H_MIN(1); tcm->tcm_info = q->qdisc->handle; return 0; diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index d904167..8fb8107 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -368,9 +368,6 @@ static int tbf_dump_class(struct Qdisc *sch, unsigned long cl, { struct tbf_sched_data *q = qdisc_priv(sch); - if (cl != 1) /* only one class */ - return -ENOENT; - tcm->tcm_handle |= TC_H_MIN(1); tcm->tcm_info = q->qdisc->handle; -- cgit v0.10.2 From af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02a Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 4 Sep 2009 06:41:18 +0000 Subject: net_sched: reintroduce dev->qdisc for use by sch_api Currently the multiqueue integration with the qdisc API suffers from a few problems: - with multiple queues, all root qdiscs use the same handle. This means they can't be exposed to userspace in a backwards compatible fashion. - all API operations always refer to queue number 0. Newly created qdiscs are automatically shared between all queues, its not possible to address individual queues or restore multiqueue behaviour once a shared qdisc has been attached. - Dumps only contain the root qdisc of queue 0, in case of non-shared qdiscs this means the statistics are incomplete. This patch reintroduces dev->qdisc, which points to the (single) root qdisc from userspace's point of view. Currently it either points to the first (non-shared) default qdisc, or a qdisc shared between all queues. The following patches will introduce a classful dummy qdisc, which will be used as root qdisc and contain the per-queue qdiscs as children. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 121cbad..a44118b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -832,6 +832,9 @@ struct net_device /* Number of TX queues currently active in device */ unsigned int real_num_tx_queues; + /* root qdisc from userspace point of view */ + struct Qdisc *qdisc; + unsigned long tx_queue_len; /* Max frames per queue allowed */ spinlock_t tx_global_lock; /* diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index bbcba2a..eb42873 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -606,7 +606,6 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, int type, u32 pid, u32 seq, u32 change, unsigned int flags) { - struct netdev_queue *txq; struct ifinfomsg *ifm; struct nlmsghdr *nlh; const struct net_device_stats *stats; @@ -637,9 +636,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, if (dev->master) NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex); - txq = netdev_get_tx_queue(dev, 0); - if (txq->qdisc_sleeping) - NLA_PUT_STRING(skb, IFLA_QDISC, txq->qdisc_sleeping->ops->id); + if (dev->qdisc) + NLA_PUT_STRING(skb, IFLA_QDISC, dev->qdisc->ops->id); if (dev->ifalias) NLA_PUT_STRING(skb, IFLA_IFALIAS, dev->ifalias); diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index bcfbdb4..6a53694 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -168,8 +168,7 @@ replay: /* Find qdisc */ if (!parent) { - struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, 0); - q = dev_queue->qdisc_sleeping; + q = dev->qdisc; parent = q->handle; } else { q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent)); @@ -408,7 +407,6 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); - struct netdev_queue *dev_queue; int t; int s_t; struct net_device *dev; @@ -427,9 +425,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return skb->len; - dev_queue = netdev_get_tx_queue(dev, 0); if (!tcm->tcm_parent) - q = dev_queue->qdisc_sleeping; + q = dev->qdisc; else q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent)); if (!q) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 166fcca..8aa9a0c 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -207,7 +207,7 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) static void qdisc_list_add(struct Qdisc *q) { if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) - list_add_tail(&q->list, &qdisc_root_sleeping(q)->list); + list_add_tail(&q->list, &qdisc_dev(q)->qdisc->list); } void qdisc_list_del(struct Qdisc *q) @@ -219,17 +219,11 @@ EXPORT_SYMBOL(qdisc_list_del); struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) { - unsigned int i; struct Qdisc *q; - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - struct Qdisc *txq_root = txq->qdisc_sleeping; - - q = qdisc_match_from_root(txq_root, handle); - if (q) - goto out; - } + q = qdisc_match_from_root(dev->qdisc, handle); + if (q) + goto out; q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle); out: @@ -720,9 +714,14 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, if (new && i > 0) atomic_inc(&new->refcnt); - notify_and_destroy(skb, n, classid, old, new); + qdisc_destroy(old); } + notify_and_destroy(skb, n, classid, dev->qdisc, new); + if (new) + atomic_inc(&new->refcnt); + dev->qdisc = new ? : &noop_qdisc; + if (dev->flags & IFF_UP) dev_activate(dev); } else { @@ -974,9 +973,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) q = dev->rx_queue.qdisc_sleeping; } } else { - struct netdev_queue *dev_queue; - dev_queue = netdev_get_tx_queue(dev, 0); - q = dev_queue->qdisc_sleeping; + q = dev->qdisc; } if (!q) return -ENOENT; @@ -1044,9 +1041,7 @@ replay: q = dev->rx_queue.qdisc_sleeping; } } else { - struct netdev_queue *dev_queue; - dev_queue = netdev_get_tx_queue(dev, 0); - q = dev_queue->qdisc_sleeping; + q = dev->qdisc; } /* It may be default qdisc, ignore it */ @@ -1291,8 +1286,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) s_q_idx = 0; q_idx = 0; - dev_queue = netdev_get_tx_queue(dev, 0); - if (tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, &q_idx, s_q_idx) < 0) + if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0) goto done; dev_queue = &dev->rx_queue; @@ -1323,7 +1317,6 @@ done: static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { struct net *net = sock_net(skb->sk); - struct netdev_queue *dev_queue; struct tcmsg *tcm = NLMSG_DATA(n); struct nlattr *tca[TCA_MAX + 1]; struct net_device *dev; @@ -1361,7 +1354,6 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) /* Step 1. Determine qdisc handle X:0 */ - dev_queue = netdev_get_tx_queue(dev, 0); if (pid != TC_H_ROOT) { u32 qid1 = TC_H_MAJ(pid); @@ -1372,7 +1364,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) } else if (qid1) { qid = qid1; } else if (qid == 0) - qid = dev_queue->qdisc_sleeping->handle; + qid = dev->qdisc->handle; /* Now qid is genuine qdisc handle consistent both with parent and child. @@ -1383,7 +1375,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) pid = TC_H_MAKE(qid, pid); } else { if (qid == 0) - qid = dev_queue->qdisc_sleeping->handle; + qid = dev->qdisc->handle; } /* OK. Locate qdisc */ @@ -1588,8 +1580,7 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) s_t = cb->args[0]; t = 0; - dev_queue = netdev_get_tx_queue(dev, 0); - if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0) + if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0) goto done; dev_queue = &dev->rx_queue; diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 6128e6f..a91f079 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -623,19 +623,6 @@ void qdisc_destroy(struct Qdisc *qdisc) } EXPORT_SYMBOL(qdisc_destroy); -static bool dev_all_qdisc_sleeping_noop(struct net_device *dev) -{ - unsigned int i; - - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - - if (txq->qdisc_sleeping != &noop_qdisc) - return false; - } - return true; -} - static void attach_one_default_qdisc(struct net_device *dev, struct netdev_queue *dev_queue, void *_unused) @@ -677,6 +664,7 @@ static void transition_one_qdisc(struct net_device *dev, void dev_activate(struct net_device *dev) { + struct netdev_queue *txq; int need_watchdog; /* No queueing discipline is attached to device; @@ -685,9 +673,14 @@ void dev_activate(struct net_device *dev) virtual interfaces */ - if (dev_all_qdisc_sleeping_noop(dev)) + if (dev->qdisc == &noop_qdisc) { netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); + txq = netdev_get_tx_queue(dev, 0); + dev->qdisc = txq->qdisc_sleeping; + atomic_inc(&dev->qdisc->refcnt); + } + if (!netif_carrier_ok(dev)) /* Delay activation until next carrier-on event */ return; @@ -777,6 +770,7 @@ static void dev_init_scheduler_queue(struct net_device *dev, void dev_init_scheduler(struct net_device *dev) { + dev->qdisc = &noop_qdisc; netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc); dev_init_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc); @@ -802,5 +796,8 @@ void dev_shutdown(struct net_device *dev) { netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); shutdown_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc); + qdisc_destroy(dev->qdisc); + dev->qdisc = &noop_qdisc; + WARN_ON(timer_pending(&dev->watchdog_timer)); } -- cgit v0.10.2 From 589983cd21f4a2e4ed74a958805a90fa676845c5 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 4 Sep 2009 06:41:20 +0000 Subject: net_sched: move dev_graft_qdisc() to sch_generic.c It will be used in a following patch by the multiqueue qdisc. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index a48a4cc..a92dc62 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -302,6 +302,8 @@ extern void dev_init_scheduler(struct net_device *dev); extern void dev_shutdown(struct net_device *dev); extern void dev_activate(struct net_device *dev); extern void dev_deactivate(struct net_device *dev); +extern struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, + struct Qdisc *qdisc); extern void qdisc_reset(struct Qdisc *qdisc); extern void qdisc_destroy(struct Qdisc *qdisc); extern void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 8aa9a0c..d71f12b 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -610,32 +610,6 @@ static u32 qdisc_alloc_handle(struct net_device *dev) return i>0 ? autohandle : 0; } -/* Attach toplevel qdisc to device queue. */ - -static struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, - struct Qdisc *qdisc) -{ - struct Qdisc *oqdisc = dev_queue->qdisc_sleeping; - spinlock_t *root_lock; - - root_lock = qdisc_lock(oqdisc); - spin_lock_bh(root_lock); - - /* Prune old scheduler */ - if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) - qdisc_reset(oqdisc); - - /* ... and graft new one */ - if (qdisc == NULL) - qdisc = &noop_qdisc; - dev_queue->qdisc_sleeping = qdisc; - rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc); - - spin_unlock_bh(root_lock); - - return oqdisc; -} - void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) { const struct Qdisc_class_ops *cops; diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index a91f079..e7c47ce 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -623,6 +623,31 @@ void qdisc_destroy(struct Qdisc *qdisc) } EXPORT_SYMBOL(qdisc_destroy); +/* Attach toplevel qdisc to device queue. */ +struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, + struct Qdisc *qdisc) +{ + struct Qdisc *oqdisc = dev_queue->qdisc_sleeping; + spinlock_t *root_lock; + + root_lock = qdisc_lock(oqdisc); + spin_lock_bh(root_lock); + + /* Prune old scheduler */ + if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) + qdisc_reset(oqdisc); + + /* ... and graft new one */ + if (qdisc == NULL) + qdisc = &noop_qdisc; + dev_queue->qdisc_sleeping = qdisc; + rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc); + + spin_unlock_bh(root_lock); + + return oqdisc; +} + static void attach_one_default_qdisc(struct net_device *dev, struct netdev_queue *dev_queue, void *_unused) -- cgit v0.10.2 From 6ec1c69a8f6492fd25722f4762721921da074c12 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 6 Sep 2009 01:58:51 -0700 Subject: net_sched: add classful multiqueue dummy scheduler This patch adds a classful dummy scheduler which can be used as root qdisc for multiqueue devices and exposes each device queue as a child class. This allows to address queues individually and graft them similar to regular classes. Additionally it presents an accumulated view of the statistics of all real root qdiscs in the dummy root. Two new callbacks are added to the qdisc_ops and qdisc_class_ops: - cl_ops->select_queue selects the tx queue number for new child classes. - qdisc_ops->attach() overrides root qdisc device grafting to attach non-shared qdiscs to the queues. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index a92dc62..9c69585 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -80,6 +80,7 @@ struct Qdisc struct Qdisc_class_ops { /* Child qdisc manipulation */ + unsigned int (*select_queue)(struct Qdisc *, struct tcmsg *); int (*graft)(struct Qdisc *, unsigned long cl, struct Qdisc *, struct Qdisc **); struct Qdisc * (*leaf)(struct Qdisc *, unsigned long cl); @@ -122,6 +123,7 @@ struct Qdisc_ops void (*reset)(struct Qdisc *); void (*destroy)(struct Qdisc *); int (*change)(struct Qdisc *, struct nlattr *arg); + void (*attach)(struct Qdisc *); int (*dump)(struct Qdisc *, struct sk_buff *); int (*dump_stats)(struct Qdisc *, struct gnet_dump *); @@ -255,6 +257,8 @@ static inline void sch_tree_unlock(struct Qdisc *q) extern struct Qdisc noop_qdisc; extern struct Qdisc_ops noop_qdisc_ops; +extern struct Qdisc_ops pfifo_fast_ops; +extern struct Qdisc_ops mq_qdisc_ops; struct Qdisc_class_common { diff --git a/net/sched/Makefile b/net/sched/Makefile index 54d950c..f14e71b 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -2,7 +2,7 @@ # Makefile for the Linux Traffic Control Unit. # -obj-y := sch_generic.o +obj-y := sch_generic.o sch_mq.o obj-$(CONFIG_NET_SCHED) += sch_api.o sch_blackhole.o obj-$(CONFIG_NET_CLS) += cls_api.o diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index d71f12b..2a78d54 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -678,6 +678,11 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, if (dev->flags & IFF_UP) dev_deactivate(dev); + if (new && new->ops->attach) { + new->ops->attach(new); + num_q = 0; + } + for (i = 0; i < num_q; i++) { struct netdev_queue *dev_queue = &dev->rx_queue; @@ -692,7 +697,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, } notify_and_destroy(skb, n, classid, dev->qdisc, new); - if (new) + if (new && !new->ops->attach) atomic_inc(&new->refcnt); dev->qdisc = new ? : &noop_qdisc; @@ -1095,10 +1100,16 @@ create_n_graft: q = qdisc_create(dev, &dev->rx_queue, tcm->tcm_parent, tcm->tcm_parent, tca, &err); - else - q = qdisc_create(dev, netdev_get_tx_queue(dev, 0), + else { + unsigned int ntx = 0; + + if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue) + ntx = p->ops->cl_ops->select_queue(p, tcm); + + q = qdisc_create(dev, netdev_get_tx_queue(dev, ntx), tcm->tcm_parent, tcm->tcm_handle, tca, &err); + } if (q == NULL) { if (err == -EAGAIN) goto replay; @@ -1674,6 +1685,7 @@ static int __init pktsched_init(void) { register_qdisc(&pfifo_qdisc_ops); register_qdisc(&bfifo_qdisc_ops); + register_qdisc(&mq_qdisc_ops); proc_net_fops_create(&init_net, "psched", 0, &psched_fops); rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL); diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index e7c47ce..4ae6aa5 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -514,7 +514,7 @@ static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt) return 0; } -static struct Qdisc_ops pfifo_fast_ops __read_mostly = { +struct Qdisc_ops pfifo_fast_ops __read_mostly = { .id = "pfifo_fast", .priv_size = sizeof(struct pfifo_fast_priv), .enqueue = pfifo_fast_enqueue, @@ -670,6 +670,26 @@ static void attach_one_default_qdisc(struct net_device *dev, dev_queue->qdisc_sleeping = qdisc; } +static void attach_default_qdiscs(struct net_device *dev) +{ + struct netdev_queue *txq; + struct Qdisc *qdisc; + + txq = netdev_get_tx_queue(dev, 0); + + if (!netif_is_multiqueue(dev) || dev->tx_queue_len == 0) { + netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); + dev->qdisc = txq->qdisc_sleeping; + atomic_inc(&dev->qdisc->refcnt); + } else { + qdisc = qdisc_create_dflt(dev, txq, &mq_qdisc_ops, TC_H_ROOT); + if (qdisc) { + qdisc->ops->attach(qdisc); + dev->qdisc = qdisc; + } + } +} + static void transition_one_qdisc(struct net_device *dev, struct netdev_queue *dev_queue, void *_need_watchdog) @@ -689,7 +709,6 @@ static void transition_one_qdisc(struct net_device *dev, void dev_activate(struct net_device *dev) { - struct netdev_queue *txq; int need_watchdog; /* No queueing discipline is attached to device; @@ -698,13 +717,8 @@ void dev_activate(struct net_device *dev) virtual interfaces */ - if (dev->qdisc == &noop_qdisc) { - netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); - - txq = netdev_get_tx_queue(dev, 0); - dev->qdisc = txq->qdisc_sleeping; - atomic_inc(&dev->qdisc->refcnt); - } + if (dev->qdisc == &noop_qdisc) + attach_default_qdiscs(dev); if (!netif_carrier_ok(dev)) /* Delay activation until next carrier-on event */ diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c new file mode 100644 index 0000000..c84dec9 --- /dev/null +++ b/net/sched/sch_mq.c @@ -0,0 +1,234 @@ +/* + * net/sched/sch_mq.c Classful multiqueue dummy scheduler + * + * Copyright (c) 2009 Patrick McHardy + * + * 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 published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct mq_sched { + struct Qdisc **qdiscs; +}; + +static void mq_destroy(struct Qdisc *sch) +{ + struct net_device *dev = qdisc_dev(sch); + struct mq_sched *priv = qdisc_priv(sch); + unsigned int ntx; + + if (!priv->qdiscs) + return; + for (ntx = 0; ntx < dev->num_tx_queues && priv->qdiscs[ntx]; ntx++) + qdisc_destroy(priv->qdiscs[ntx]); + kfree(priv->qdiscs); +} + +static int mq_init(struct Qdisc *sch, struct nlattr *opt) +{ + struct net_device *dev = qdisc_dev(sch); + struct mq_sched *priv = qdisc_priv(sch); + struct netdev_queue *dev_queue; + struct Qdisc *qdisc; + unsigned int ntx; + + if (sch->parent != TC_H_ROOT) + return -EOPNOTSUPP; + + if (!netif_is_multiqueue(dev)) + return -EOPNOTSUPP; + + /* pre-allocate qdiscs, attachment can't fail */ + priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]), + GFP_KERNEL); + if (priv->qdiscs == NULL) + return -ENOMEM; + + for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { + dev_queue = netdev_get_tx_queue(dev, ntx); + qdisc = qdisc_create_dflt(dev, dev_queue, &pfifo_fast_ops, + TC_H_MAKE(TC_H_MAJ(sch->handle), + TC_H_MIN(ntx + 1))); + if (qdisc == NULL) + goto err; + qdisc->flags |= TCQ_F_CAN_BYPASS; + priv->qdiscs[ntx] = qdisc; + } + + return 0; + +err: + mq_destroy(sch); + return -ENOMEM; +} + +static void mq_attach(struct Qdisc *sch) +{ + struct net_device *dev = qdisc_dev(sch); + struct mq_sched *priv = qdisc_priv(sch); + struct Qdisc *qdisc; + unsigned int ntx; + + for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { + qdisc = priv->qdiscs[ntx]; + qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc); + if (qdisc) + qdisc_destroy(qdisc); + } + kfree(priv->qdiscs); + priv->qdiscs = NULL; +} + +static int mq_dump(struct Qdisc *sch, struct sk_buff *skb) +{ + struct net_device *dev = qdisc_dev(sch); + struct Qdisc *qdisc; + unsigned int ntx; + + sch->q.qlen = 0; + memset(&sch->bstats, 0, sizeof(sch->bstats)); + memset(&sch->qstats, 0, sizeof(sch->qstats)); + + for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { + qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping; + spin_lock_bh(qdisc_lock(qdisc)); + sch->q.qlen += qdisc->q.qlen; + sch->bstats.bytes += qdisc->bstats.bytes; + sch->bstats.packets += qdisc->bstats.packets; + sch->qstats.qlen += qdisc->qstats.qlen; + sch->qstats.backlog += qdisc->qstats.backlog; + sch->qstats.drops += qdisc->qstats.drops; + sch->qstats.requeues += qdisc->qstats.requeues; + sch->qstats.overlimits += qdisc->qstats.overlimits; + spin_unlock_bh(qdisc_lock(qdisc)); + } + return 0; +} + +static struct netdev_queue *mq_queue_get(struct Qdisc *sch, unsigned long cl) +{ + struct net_device *dev = qdisc_dev(sch); + unsigned long ntx = cl - 1; + + if (ntx >= dev->num_tx_queues) + return NULL; + return netdev_get_tx_queue(dev, ntx); +} + +static unsigned int mq_select_queue(struct Qdisc *sch, struct tcmsg *tcm) +{ + unsigned int ntx = TC_H_MIN(tcm->tcm_parent); + + if (!mq_queue_get(sch, ntx)) + return 0; + return ntx - 1; +} + +static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, + struct Qdisc **old) +{ + struct netdev_queue *dev_queue = mq_queue_get(sch, cl); + struct net_device *dev = qdisc_dev(sch); + + if (dev->flags & IFF_UP) + dev_deactivate(dev); + + *old = dev_graft_qdisc(dev_queue, new); + + if (dev->flags & IFF_UP) + dev_activate(dev); + return 0; +} + +static struct Qdisc *mq_leaf(struct Qdisc *sch, unsigned long cl) +{ + struct netdev_queue *dev_queue = mq_queue_get(sch, cl); + + return dev_queue->qdisc_sleeping; +} + +static unsigned long mq_get(struct Qdisc *sch, u32 classid) +{ + unsigned int ntx = TC_H_MIN(classid); + + if (!mq_queue_get(sch, ntx)) + return 0; + return ntx; +} + +static void mq_put(struct Qdisc *sch, unsigned long cl) +{ + return; +} + +static int mq_dump_class(struct Qdisc *sch, unsigned long cl, + struct sk_buff *skb, struct tcmsg *tcm) +{ + struct netdev_queue *dev_queue = mq_queue_get(sch, cl); + + tcm->tcm_parent = TC_H_ROOT; + tcm->tcm_handle |= TC_H_MIN(cl); + tcm->tcm_info = dev_queue->qdisc_sleeping->handle; + return 0; +} + +static int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl, + struct gnet_dump *d) +{ + struct netdev_queue *dev_queue = mq_queue_get(sch, cl); + + sch = dev_queue->qdisc_sleeping; + if (gnet_stats_copy_basic(d, &sch->bstats) < 0 || + gnet_stats_copy_queue(d, &sch->qstats) < 0) + return -1; + return 0; +} + +static void mq_walk(struct Qdisc *sch, struct qdisc_walker *arg) +{ + struct net_device *dev = qdisc_dev(sch); + unsigned int ntx; + + if (arg->stop) + return; + + arg->count = arg->skip; + for (ntx = arg->skip; ntx < dev->num_tx_queues; ntx++) { + if (arg->fn(sch, ntx + 1, arg) < 0) { + arg->stop = 1; + break; + } + arg->count++; + } +} + +static const struct Qdisc_class_ops mq_class_ops = { + .select_queue = mq_select_queue, + .graft = mq_graft, + .leaf = mq_leaf, + .get = mq_get, + .put = mq_put, + .walk = mq_walk, + .dump = mq_dump_class, + .dump_stats = mq_dump_class_stats, +}; + +struct Qdisc_ops mq_qdisc_ops __read_mostly = { + .cl_ops = &mq_class_ops, + .id = "mq", + .priv_size = sizeof(struct mq_sched), + .init = mq_init, + .destroy = mq_destroy, + .attach = mq_attach, + .dump = mq_dump, + .owner = THIS_MODULE, +}; -- cgit v0.10.2 From 945af7c3289c26c9070d6b1bf3ca759d36643e0b Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 4 Sep 2009 09:19:48 +0100 Subject: KEYS: security_cred_alloc_blank() should return int under all circumstances Make security_cred_alloc_blank() return int, not void, when CONFIG_SECURITY=n. Signed-off-by: David Howells Signed-off-by: James Morris diff --git a/include/linux/security.h b/include/linux/security.h index 97de3fe..f4eb32d 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -2309,8 +2309,10 @@ 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 int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) +{ + return 0; +} static inline void security_cred_free(struct cred *cred) { } -- cgit v0.10.2 From b6d9c25631e7c38dc7be220b04553068fb542683 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Fri, 4 Sep 2009 23:13:21 +0530 Subject: Security/SELinux: includecheck fix kernel/sysctl.c fix the following 'make includecheck' warning: kernel/sysctl.c: linux/security.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: James Morris diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 58be760..71d8dc7 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 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 diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 32d8cc0..97eebd6 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 f3d186a..e58d4c5d 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, @@ -6657,6 +6658,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 */ static struct hda_verb alc882_sixstack_ch6_init[] = { @@ -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 v0.10.2 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 diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index bb488b5..ea16e7d 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 e8e29bf..2ee6c8e 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 v0.10.2 From db4cfd8a6149e778befb2ff6e6f91cdc6394cbe6 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sat, 5 Sep 2009 17:43:07 +0000 Subject: netxen: handle firmware load errors Unwind allocations and release file firmware when when firmware load fails. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index db510ce..d0ac8fa 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -566,6 +566,9 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter, i = 0; + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + return -EIO; + tx_ring = adapter->tx_ring; __netif_tx_lock_bh(tx_ring->txq); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 04e36f2..534994d 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -905,6 +905,7 @@ netxen_release_firmware(struct netxen_adapter *adapter) { if (adapter->fw) release_firmware(adapter->fw); + adapter->fw = NULL; } int netxen_init_dummy_dma(struct netxen_adapter *adapter) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 41b2967..47aede6 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -757,7 +757,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) err = netxen_need_fw_reset(adapter); if (err < 0) - return err; + goto err_out; if (err == 0) goto wait_init; @@ -771,7 +771,9 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_set_port_mode(adapter); - netxen_load_firmware(adapter); + err = netxen_load_firmware(adapter); + if (err) + goto err_out; if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { @@ -785,7 +787,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) err = netxen_init_dummy_dma(adapter); if (err) - return err; + goto err_out; /* * Tell the hardware our version number. @@ -800,7 +802,7 @@ wait_init: err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); if (err) { netxen_free_dummy_dma(adapter); - return err; + goto err_out; } nx_update_dma_mask(adapter); @@ -808,6 +810,10 @@ wait_init: netxen_nic_get_firmware_info(adapter); return 0; + +err_out: + netxen_release_firmware(adapter); + return err; } static int @@ -876,6 +882,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) { int err; + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + return -EIO; + err = adapter->init_port(adapter, adapter->physical_port); if (err) { printk(KERN_ERR "%s: Failed to initialize port %d\n", @@ -914,6 +923,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) static void netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) { + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + return; + spin_lock(&adapter->tx_clean_lock); netif_carrier_off(netdev); netif_tx_disable(netdev); -- cgit v0.10.2 From 6a581e93981e8838c85e407303186faf937830d3 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sat, 5 Sep 2009 17:43:08 +0000 Subject: netxen: firmware hang detection Implement state machine to detect firmware hung state and recover. Since firmware will be shared by all PCI functions that have different class drivers (NIC or FCOE or iSCSI), explicit hardware based serialization is required for initializing firmware. o Used global scratchpad register to maintain device reference count. Every probed pci function adds to ref count. o Implement timer (delayed work) for each pci func that checks firmware heartbit every 5 sec and detaches itself if firmware is dead. Last detaching function reloads firmware. Other functions wait for firmware init, and re-attach themselves. Heartbit is not supported by NX2031 firmware. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index ede2fa7..30a3816 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -229,6 +229,8 @@ #define MPORT_SINGLE_FUNCTION_MODE 0x1111 #define MPORT_MULTI_FUNCTION_MODE 0x2222 +#define NX_MAX_PCI_FUNC 8 + /* * NetXen host-peg signal message structure * @@ -1101,6 +1103,10 @@ typedef struct { #define NETXEN_ADAPTER_UP_MAGIC 777 #define NETXEN_NIC_PEG_TUNE 0 +#define __NX_FW_ATTACHED 0 +#define __NX_DEV_UP 1 +#define __NX_RESETTING 2 + struct netxen_dummy_dma { void *addr; dma_addr_t phys_addr; @@ -1137,7 +1143,9 @@ struct netxen_adapter { u8 max_mc_count; u8 rss_supported; u8 link_changed; - u32 resv3; + u8 fw_wait_cnt; + u8 fw_fail_cnt; + u16 resv4; u8 has_link_events; u8 fw_type; @@ -1156,7 +1164,7 @@ struct netxen_adapter { u32 temp; u32 msi_tgt_status; - u32 resv4; + u32 heartbit; struct netxen_adapter_stats stats; @@ -1187,14 +1195,15 @@ struct netxen_adapter { struct netxen_dummy_dma dummy_dma; - struct work_struct watchdog_task; - struct timer_list watchdog_timer; + struct delayed_work fw_work; + struct work_struct tx_timeout_task; struct net_device_stats net_stats; nx_nic_intr_coalesce_t coal; + unsigned long state; u32 resv5; u32 fw_version; const struct firmware *fw; diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 0f42ab9..8ab5773 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -678,6 +678,9 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + if (test_and_set_bit(__NX_FW_ATTACHED, &adapter->state)) + goto done; + err = nx_fw_cmd_create_rx_ctx(adapter); if (err) goto err_out_free; @@ -690,6 +693,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) goto err_out_free; } +done: return 0; err_out_free: @@ -708,6 +712,9 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) int port = adapter->portnum; if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + if (!test_and_clear_bit(__NX_FW_ATTACHED, &adapter->state)) + goto done; + nx_fw_cmd_destroy_rx_ctx(adapter); nx_fw_cmd_destroy_tx_ctx(adapter); } else { @@ -720,6 +727,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) /* Allow dma queues to drain after context reset */ msleep(20); +done: recv_ctx = &adapter->recv_ctx; if (recv_ctx->hwctx != NULL) { diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index 92f5970..26188b4 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -433,6 +433,7 @@ enum { #define NETXEN_CRB_PEG_NET_1 NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_PGN1) #define NETXEN_CRB_PEG_NET_2 NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_PGN2) #define NETXEN_CRB_PEG_NET_3 NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_PGN3) +#define NETXEN_CRB_PEG_NET_4 NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_SQS2) #define NETXEN_CRB_PEG_NET_D NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_PGND) #define NETXEN_CRB_PEG_NET_I NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_PGNI) #define NETXEN_CRB_DDR_NET NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_MN) @@ -945,6 +946,28 @@ enum { #define NETXEN_DMA_WATCHDOG_CTRL (NETXEN_CAM_RAM(0x14)) #define NETXEN_PEG_ALIVE_COUNTER (NETXEN_CAM_RAM(0xb0)) +#define NETXEN_PEG_HALT_STATUS1 (NETXEN_CAM_RAM(0xa8)) +#define NETXEN_PEG_HALT_STATUS2 (NETXEN_CAM_RAM(0xac)) +#define NX_CRB_DEV_REF_COUNT (NETXEN_CAM_RAM(0x138)) +#define NX_CRB_DEV_STATE (NETXEN_CAM_RAM(0x140)) + +/* Device State */ +#define NX_DEV_COLD 1 +#define NX_DEV_INITALIZING 2 +#define NX_DEV_READY 3 +#define NX_DEV_NEED_RESET 4 +#define NX_DEV_NEED_QUISCENT 5 +#define NX_DEV_FAILED 6 + +#define NX_RCODE_DRIVER_INFO 0x20000000 +#define NX_RCODE_DRIVER_CAN_RELOAD 0x40000000 +#define NX_RCODE_FATAL_ERROR 0x80000000 +#define NX_FWERROR_PEGNUM(code) ((code) & 0xff) +#define NX_FWERROR_CODE(code) ((code >> 8) & 0xfffff) + +#define FW_POLL_DELAY (2 * HZ) +#define FW_FAIL_THRESH 3 +#define FW_POLL_THRESH 10 #define ISR_MSI_INT_TRIGGER(FUNC) (NETXEN_PCIX_PS_REG(PCIX_MSI_F(FUNC))) #define ISR_LEGACY_INT_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 47aede6..4989436 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -67,7 +67,10 @@ static netdev_tx_t netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); static void netxen_tx_timeout(struct net_device *netdev); static void netxen_reset_task(struct work_struct *work); -static void netxen_watchdog(unsigned long); +static void netxen_fw_poll_work(struct work_struct *work); +static void netxen_schedule_work(struct netxen_adapter *adapter, + work_func_t func, int delay); +static void netxen_cancel_fw_work(struct netxen_adapter *adapter); static int netxen_nic_poll(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void netxen_nic_poll_controller(struct net_device *netdev); @@ -76,6 +79,9 @@ static void netxen_nic_poll_controller(struct net_device *netdev); static void netxen_create_sysfs_entries(struct netxen_adapter *adapter); static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter); +static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter); +static int netxen_can_start_firmware(struct netxen_adapter *adapter); + static irqreturn_t netxen_intr(int irq, void *data); static irqreturn_t netxen_msi_intr(int irq, void *data); static irqreturn_t netxen_msix_intr(int irq, void *data); @@ -729,19 +735,12 @@ err_out: } static int -netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) +netxen_start_firmware(struct netxen_adapter *adapter) { int val, err, first_boot; struct pci_dev *pdev = adapter->pdev; - int first_driver = 0; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - first_driver = (adapter->portnum == 0); - else - first_driver = (adapter->ahw.pci_func == 0); - - if (!first_driver) + if (!netxen_can_start_firmware(adapter)) goto wait_init; first_boot = NXRD32(adapter, NETXEN_CAM_RAM(0x1fc)); @@ -752,8 +751,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) return err; } - if (request_fw) - netxen_request_firmware(adapter); + netxen_request_firmware(adapter); err = netxen_need_fw_reset(adapter); if (err < 0) @@ -768,6 +766,9 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) } NXWR32(adapter, CRB_DMA_SHIFT, 0x55555555); + NXWR32(adapter, NETXEN_PEG_HALT_STATUS1, 0); + NXWR32(adapter, NETXEN_PEG_HALT_STATUS2, 0); + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_set_port_mode(adapter); @@ -775,6 +776,8 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) if (err) goto err_out; + netxen_release_firmware(adapter); + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { /* Initialize multicast addr pool owners */ @@ -797,6 +800,8 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) | (_NETXEN_NIC_LINUX_SUBVERSION); NXWR32(adapter, CRB_DRIVER_VERSION, val); + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_READY); + wait_init: /* Handshake with the card before we register the devices. */ err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); @@ -808,6 +813,7 @@ wait_init: nx_update_dma_mask(adapter); netxen_nic_get_firmware_info(adapter); + netxen_check_options(adapter); return 0; @@ -915,8 +921,7 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) else netxen_nic_set_link_parameters(adapter); - mod_timer(&adapter->watchdog_timer, jiffies); - + set_bit(__NX_DEV_UP, &adapter->state); return 0; } @@ -926,6 +931,8 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) return; + clear_bit(__NX_DEV_UP, &adapter->state); + spin_lock(&adapter->tx_clean_lock); netif_carrier_off(netdev); netif_tx_disable(netdev); @@ -942,8 +949,6 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) netxen_release_tx_buffers(adapter); spin_unlock(&adapter->tx_clean_lock); - - del_timer_sync(&adapter->watchdog_timer); } @@ -974,8 +979,6 @@ netxen_nic_attach(struct netxen_adapter *adapter) return err; } - netxen_nic_clear_stats(adapter); - err = netxen_alloc_hw_resources(adapter); if (err) { printk(KERN_ERR "%s: Error in setting hw resources\n", @@ -1046,21 +1049,32 @@ netxen_nic_reset_context(struct netxen_adapter *adapter) int err = 0; struct net_device *netdev = adapter->netdev; + if (test_and_set_bit(__NX_RESETTING, &adapter->state)) + return -EBUSY; + if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) { + netif_device_detach(netdev); + if (netif_running(netdev)) netxen_nic_down(adapter, netdev); netxen_nic_detach(adapter); - err = netxen_nic_attach(adapter); - if (err) - goto done; + if (netif_running(netdev)) { + err = netxen_nic_attach(adapter); + if (!err) + err = netxen_nic_up(adapter, netdev); - if (netif_running(netdev)) - err = netxen_nic_up(adapter, netdev); + if (err) + goto done; + } + + netif_device_attach(netdev); } + done: + clear_bit(__NX_RESETTING, &adapter->state); return err; } @@ -1107,10 +1121,6 @@ netxen_setup_netdev(struct netxen_adapter *adapter, netdev->irq = adapter->msix_entries[0].vector; - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = &netxen_watchdog; - adapter->watchdog_timer.data = (unsigned long)adapter; - INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task); INIT_WORK(&adapter->tx_timeout_task, netxen_reset_task); if (netxen_read_mac_addr(adapter)) @@ -1214,7 +1224,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) break; } - err = netxen_start_firmware(adapter, 1); + err = netxen_start_firmware(adapter); if (err) goto err_out_iounmap; @@ -1228,7 +1238,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->physical_port = i; } - netxen_check_options(adapter); + netxen_nic_clear_stats(adapter); netxen_setup_intr(adapter); @@ -1238,6 +1248,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, adapter); + netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); + switch (adapter->ahw.port_type) { case NETXEN_NIC_GBE: dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n", @@ -1256,6 +1268,8 @@ err_out_disable_msi: netxen_free_dummy_dma(adapter); + nx_decr_dev_ref_cnt(adapter); + err_out_iounmap: netxen_cleanup_pci_map(adapter); @@ -1282,16 +1296,21 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) netdev = adapter->netdev; + netxen_cancel_fw_work(adapter); + unregister_netdev(netdev); - cancel_work_sync(&adapter->watchdog_task); cancel_work_sync(&adapter->tx_timeout_task); netxen_nic_detach(adapter); + nx_decr_dev_ref_cnt(adapter); + if (adapter->portnum == 0) netxen_free_dummy_dma(adapter); + clear_bit(__NX_RESETTING, &adapter->state); + netxen_teardown_intr(adapter); netxen_cleanup_pci_map(adapter); @@ -1312,10 +1331,11 @@ static int __netxen_nic_shutdown(struct pci_dev *pdev) netif_device_detach(netdev); + netxen_cancel_fw_work(adapter); + if (netif_running(netdev)) netxen_nic_down(adapter, netdev); - cancel_work_sync(&adapter->watchdog_task); cancel_work_sync(&adapter->tx_timeout_task); netxen_nic_detach(adapter); @@ -1323,6 +1343,10 @@ static int __netxen_nic_shutdown(struct pci_dev *pdev) if (adapter->portnum == 0) netxen_free_dummy_dma(adapter); + nx_decr_dev_ref_cnt(adapter); + + clear_bit(__NX_RESETTING, &adapter->state); + retval = pci_save_state(pdev); if (retval) return retval; @@ -1371,7 +1395,7 @@ netxen_nic_resume(struct pci_dev *pdev) adapter->curr_window = 255; - err = netxen_start_firmware(adapter, 0); + err = netxen_start_firmware(adapter); if (err) { dev_err(&pdev->dev, "failed to start firmware\n"); return err; @@ -1380,16 +1404,22 @@ netxen_nic_resume(struct pci_dev *pdev) if (netif_running(netdev)) { err = netxen_nic_attach(adapter); if (err) - return err; + goto err_out; err = netxen_nic_up(adapter, netdev); if (err) - return err; + goto err_out_detach; netif_device_attach(netdev); } - return 0; + netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); + +err_out_detach: + netxen_nic_detach(adapter); +err_out: + nx_decr_dev_ref_cnt(adapter); + return err; } #endif @@ -1783,59 +1813,13 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) netxen_advert_link_change(adapter, linkup); } -static void netxen_nic_thermal_shutdown(struct netxen_adapter *adapter) -{ - struct net_device *netdev = adapter->netdev; - - netif_device_detach(netdev); - netxen_nic_down(adapter, netdev); - netxen_nic_detach(adapter); -} - -static void netxen_watchdog(unsigned long v) -{ - struct netxen_adapter *adapter = (struct netxen_adapter *)v; - - if (netxen_nic_check_temp(adapter)) - goto do_sched; - - if (!adapter->has_link_events) { - netxen_nic_handle_phy_intr(adapter); - - if (adapter->link_changed) - goto do_sched; - } - - if (netif_running(adapter->netdev)) - mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); - - return; - -do_sched: - schedule_work(&adapter->watchdog_task); -} - -void netxen_watchdog_task(struct work_struct *work) -{ - struct netxen_adapter *adapter = - container_of(work, struct netxen_adapter, watchdog_task); - - if (adapter->temp == NX_TEMP_PANIC) { - netxen_nic_thermal_shutdown(adapter); - return; - } - - if (adapter->link_changed) - netxen_nic_set_link_parameters(adapter); - - if (netif_running(adapter->netdev)) - mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); -} - static void netxen_tx_timeout(struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); + if (test_bit(__NX_RESETTING, &adapter->state)) + return; + dev_err(&netdev->dev, "transmit timeout, resetting.\n"); schedule_work(&adapter->tx_timeout_task); } @@ -1848,6 +1832,9 @@ static void netxen_reset_task(struct work_struct *work) if (!netif_running(adapter->netdev)) return; + if (test_bit(__NX_RESETTING, &adapter->state)) + return; + netxen_napi_disable(adapter); adapter->netdev->trans_start = jiffies; @@ -1974,6 +1961,239 @@ static void netxen_nic_poll_controller(struct net_device *netdev) } #endif +static int +nx_incr_dev_ref_cnt(struct netxen_adapter *adapter) +{ + int count; + if (netxen_api_lock(adapter)) + return -EIO; + + count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT); + + NXWR32(adapter, NX_CRB_DEV_REF_COUNT, ++count); + + netxen_api_unlock(adapter); + return count; +} + +static int +nx_decr_dev_ref_cnt(struct netxen_adapter *adapter) +{ + int count; + if (netxen_api_lock(adapter)) + return -EIO; + + count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT); + WARN_ON(count == 0); + + NXWR32(adapter, NX_CRB_DEV_REF_COUNT, --count); + + if (count == 0) + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_COLD); + + netxen_api_unlock(adapter); + return count; +} + +static int +netxen_can_start_firmware(struct netxen_adapter *adapter) +{ + int count; + int can_start = 0; + + if (netxen_api_lock(adapter)) + return 0; + + count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT); + + if ((count < 0) || (count >= NX_MAX_PCI_FUNC)) + count = 0; + + if (count == 0) { + can_start = 1; + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_INITALIZING); + } + + NXWR32(adapter, NX_CRB_DEV_REF_COUNT, ++count); + + netxen_api_unlock(adapter); + + return can_start; +} + +static void +netxen_schedule_work(struct netxen_adapter *adapter, + work_func_t func, int delay) +{ + INIT_DELAYED_WORK(&adapter->fw_work, func); + schedule_delayed_work(&adapter->fw_work, delay); +} + +static void +netxen_cancel_fw_work(struct netxen_adapter *adapter) +{ + while (test_and_set_bit(__NX_RESETTING, &adapter->state)) + msleep(10); + + cancel_delayed_work_sync(&adapter->fw_work); +} + +static void +netxen_attach_work(struct work_struct *work) +{ + struct netxen_adapter *adapter = container_of(work, + struct netxen_adapter, fw_work.work); + struct net_device *netdev = adapter->netdev; + int err = 0; + + if (netif_running(netdev)) { + err = netxen_nic_attach(adapter); + if (err) + goto done; + + err = netxen_nic_up(adapter, netdev); + if (err) { + netxen_nic_detach(adapter); + goto done; + } + + } + + netif_device_attach(netdev); + +done: + adapter->fw_fail_cnt = 0; + clear_bit(__NX_RESETTING, &adapter->state); + netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); +} + +static void +netxen_fwinit_work(struct work_struct *work) +{ + struct netxen_adapter *adapter = container_of(work, + struct netxen_adapter, fw_work.work); + int dev_state; + + dev_state = NXRD32(adapter, NX_CRB_DEV_STATE); + + switch (dev_state) { + case NX_DEV_COLD: + case NX_DEV_READY: + netxen_start_firmware(adapter); + netxen_schedule_work(adapter, netxen_attach_work, 0); + return; + + case NX_DEV_INITALIZING: + if (++adapter->fw_wait_cnt < FW_POLL_THRESH) { + netxen_schedule_work(adapter, + netxen_fwinit_work, 2 * FW_POLL_DELAY); + return; + } + break; + + case NX_DEV_FAILED: + default: + break; + } + + nx_incr_dev_ref_cnt(adapter); + clear_bit(__NX_RESETTING, &adapter->state); +} + +static void +netxen_detach_work(struct work_struct *work) +{ + struct netxen_adapter *adapter = container_of(work, + struct netxen_adapter, fw_work.work); + struct net_device *netdev = adapter->netdev; + int ref_cnt, delay; + u32 status; + + netif_device_detach(netdev); + + if (netif_running(netdev)) + netxen_nic_down(adapter, netdev); + + netxen_nic_detach(adapter); + + status = NXRD32(adapter, NETXEN_PEG_HALT_STATUS1); + + ref_cnt = nx_decr_dev_ref_cnt(adapter); + + if (status & NX_RCODE_FATAL_ERROR) + return; + + if (adapter->temp == NX_TEMP_PANIC) + return; + + delay = (ref_cnt == 0) ? 0 : (2 * FW_POLL_DELAY); + + adapter->fw_wait_cnt = 0; + netxen_schedule_work(adapter, netxen_fwinit_work, delay); +} + +static int +netxen_check_health(struct netxen_adapter *adapter) +{ + u32 state, heartbit; + struct net_device *netdev = adapter->netdev; + + if (netxen_nic_check_temp(adapter)) + goto detach; + + state = NXRD32(adapter, NX_CRB_DEV_STATE); + if (state == NX_DEV_NEED_RESET) + goto detach; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + return 0; + + heartbit = NXRD32(adapter, NETXEN_PEG_ALIVE_COUNTER); + if (heartbit != adapter->heartbit) { + adapter->heartbit = heartbit; + adapter->fw_fail_cnt = 0; + return 0; + } + + if (++adapter->fw_fail_cnt < FW_FAIL_THRESH) + return 0; + + clear_bit(__NX_FW_ATTACHED, &adapter->state); + + dev_info(&netdev->dev, "firmware hang detected\n"); + +detach: + if (!test_and_set_bit(__NX_RESETTING, &adapter->state)) + netxen_schedule_work(adapter, netxen_detach_work, 0); + return 1; +} + +static void +netxen_fw_poll_work(struct work_struct *work) +{ + struct netxen_adapter *adapter = container_of(work, + struct netxen_adapter, fw_work.work); + + if (test_bit(__NX_RESETTING, &adapter->state)) + goto reschedule; + + if (test_bit(__NX_DEV_UP, &adapter->state)) { + if (!adapter->has_link_events) { + + netxen_nic_handle_phy_intr(adapter); + + if (adapter->link_changed) + netxen_nic_set_link_parameters(adapter); + } + } + + if (netxen_check_health(adapter)) + return; + +reschedule: + netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); +} + static ssize_t netxen_store_bridged_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) -- cgit v0.10.2 From d0725e4d3ccf603c4fcf3589850cb464c927d42a Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Sat, 5 Sep 2009 17:43:09 +0000 Subject: netxen: fix ip addr hashing after firmware reset Reprogram local IP addresses after firmware is reset or after resuming from suspend. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 4989436..7038e1b 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -86,6 +86,8 @@ static irqreturn_t netxen_intr(int irq, void *data); static irqreturn_t netxen_msi_intr(int irq, void *data); static irqreturn_t netxen_msix_intr(int irq, void *data); +static void netxen_config_indev_addr(struct net_device *dev, unsigned long); + /* PCI Device ID Table */ #define ENTRY(device) \ {PCI_DEVICE(PCI_VENDOR_ID_NETXEN, (device)), \ @@ -1411,6 +1413,8 @@ netxen_nic_resume(struct pci_dev *pdev) goto err_out_detach; netif_device_attach(netdev); + + netxen_config_indev_addr(netdev, NETDEV_UP); } netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); @@ -2057,6 +2061,7 @@ netxen_attach_work(struct work_struct *work) goto done; } + netxen_config_indev_addr(netdev, NETDEV_UP); } netif_device_attach(netdev); @@ -2282,12 +2287,43 @@ netxen_destip_supported(struct netxen_adapter *adapter) return 1; } +static void +netxen_config_indev_addr(struct net_device *dev, unsigned long event) +{ + struct in_device *indev; + struct netxen_adapter *adapter = netdev_priv(dev); + + if (netxen_destip_supported(adapter)) + return; + + indev = in_dev_get(dev); + if (!indev) + return; + + for_ifa(indev) { + switch (event) { + case NETDEV_UP: + netxen_config_ipaddr(adapter, + ifa->ifa_address, NX_IP_UP); + break; + case NETDEV_DOWN: + netxen_config_ipaddr(adapter, + ifa->ifa_address, NX_IP_DOWN); + break; + default: + break; + } + } endfor_ifa(indev); + + in_dev_put(indev); + return; +} + static int netxen_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct netxen_adapter *adapter; struct net_device *dev = (struct net_device *)ptr; - struct in_device *indev; recheck: if (dev == NULL) @@ -2303,32 +2339,13 @@ recheck: adapter = netdev_priv(dev); - if (!adapter || !netxen_destip_supported(adapter)) + if (!adapter) goto done; if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) goto done; - indev = in_dev_get(dev); - if (!indev) - goto done; - - for_ifa(indev) { - switch (event) { - case NETDEV_UP: - netxen_config_ipaddr(adapter, - ifa->ifa_address, NX_IP_UP); - break; - case NETDEV_DOWN: - netxen_config_ipaddr(adapter, - ifa->ifa_address, NX_IP_DOWN); - break; - default: - break; - } - } endfor_ifa(indev); - - in_dev_put(indev); + netxen_config_indev_addr(dev, event); done: return NOTIFY_DONE; } -- cgit v0.10.2 From 195c5f9829407857cba86f083caec6302b1fd8e1 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Sat, 5 Sep 2009 17:43:10 +0000 Subject: netxen: pre calculate register addresses For registers accessed in fast path (interrupt / softirq) avoid expensive I/O address translation. These registers are directly mapped in PCI bar 0 and do not require any window checks. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 30a3816..5bbc40b 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -584,11 +584,11 @@ struct netxen_adapter_stats { */ struct nx_host_rds_ring { u32 producer; - u32 crb_rcv_producer; u32 num_desc; u32 dma_size; u32 skb_size; u32 flags; + void __iomem *crb_rcv_producer; struct rcv_desc *desc_head; struct netxen_rx_buffer *rx_buf_arr; struct list_head free_list; @@ -598,9 +598,9 @@ struct nx_host_rds_ring { struct nx_host_sds_ring { u32 consumer; - u32 crb_sts_consumer; - u32 crb_intr_mask; u32 num_desc; + void __iomem *crb_sts_consumer; + void __iomem *crb_intr_mask; struct status_desc *desc_head; struct netxen_adapter *adapter; @@ -617,8 +617,8 @@ struct nx_host_tx_ring { u32 producer; __le32 *hw_consumer; u32 sw_consumer; - u32 crb_cmd_producer; - u32 crb_cmd_consumer; + void __iomem *crb_cmd_producer; + void __iomem *crb_cmd_consumer; u32 num_desc; struct netdev_queue *txq; @@ -1163,7 +1163,7 @@ struct netxen_adapter { u32 irq; u32 temp; - u32 msi_tgt_status; + u32 int_vec_bit; u32 heartbit; struct netxen_adapter_stats stats; @@ -1180,16 +1180,23 @@ struct netxen_adapter { int (*init_port) (struct netxen_adapter *, int); int (*stop_port) (struct netxen_adapter *); - u32 (*hw_read_wx)(struct netxen_adapter *, ulong); - int (*hw_write_wx)(struct netxen_adapter *, ulong, u32); + u32 (*crb_read)(struct netxen_adapter *, ulong); + int (*crb_write)(struct netxen_adapter *, ulong, u32); + int (*pci_mem_read)(struct netxen_adapter *, u64, void *, int); int (*pci_mem_write)(struct netxen_adapter *, u64, void *, int); - int (*pci_write_immediate)(struct netxen_adapter *, u64, u32); - u32 (*pci_read_immediate)(struct netxen_adapter *, u64); + unsigned long (*pci_set_window)(struct netxen_adapter *, unsigned long long); - struct netxen_legacy_intr_set legacy_intr; + u32 (*io_read)(struct netxen_adapter *, void __iomem *); + void (*io_write)(struct netxen_adapter *, void __iomem *, u32); + + void __iomem *tgt_mask_reg; + void __iomem *pci_int_reg; + void __iomem *tgt_status_reg; + void __iomem *crb_int_state_reg; + void __iomem *isr_int_vec; struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER]; @@ -1223,9 +1230,13 @@ int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr); int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr); #define NXRD32(adapter, off) \ - (adapter->hw_read_wx(adapter, off)) + (adapter->crb_read(adapter, off)) #define NXWR32(adapter, off, val) \ - (adapter->hw_write_wx(adapter, off, val)) + (adapter->crb_write(adapter, off, val)) +#define NXRDIO(adapter, addr) \ + (adapter->io_read(adapter, addr)) +#define NXWRIO(adapter, addr, val) \ + (adapter->io_write(adapter, addr, val)) int netxen_pcie_sem_lock(struct netxen_adapter *, int, u32); void netxen_pcie_sem_unlock(struct netxen_adapter *, int); @@ -1255,40 +1266,6 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter); void netxen_nic_get_firmware_info(struct netxen_adapter *adapter); int netxen_nic_wol_supported(struct netxen_adapter *adapter); -u32 netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, ulong off); -int netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, - ulong off, u32 data); -int netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter, - u64 off, void *data, int size); -int netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter, - u64 off, void *data, int size); -int netxen_nic_pci_write_immediate_128M(struct netxen_adapter *adapter, - u64 off, u32 data); -u32 netxen_nic_pci_read_immediate_128M(struct netxen_adapter *adapter, u64 off); -void netxen_nic_pci_write_normalize_128M(struct netxen_adapter *adapter, - u64 off, u32 data); -u32 netxen_nic_pci_read_normalize_128M(struct netxen_adapter *adapter, u64 off); -unsigned long netxen_nic_pci_set_window_128M(struct netxen_adapter *adapter, - unsigned long long addr); -void netxen_nic_pci_change_crbwindow_128M(struct netxen_adapter *adapter, - u32 wndw); - -u32 netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off); -int netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, - ulong off, u32 data); -int netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, - u64 off, void *data, int size); -int netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, - u64 off, void *data, int size); -int netxen_nic_pci_write_immediate_2M(struct netxen_adapter *adapter, - u64 off, u32 data); -u32 netxen_nic_pci_read_immediate_2M(struct netxen_adapter *adapter, u64 off); -void netxen_nic_pci_write_normalize_2M(struct netxen_adapter *adapter, - u64 off, u32 data); -u32 netxen_nic_pci_read_normalize_2M(struct netxen_adapter *adapter, u64 off); -unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, - unsigned long long addr); - /* Functions from netxen_nic_init.c */ int netxen_init_dummy_dma(struct netxen_adapter *adapter); void netxen_free_dummy_dma(struct netxen_adapter *adapter); @@ -1316,13 +1293,15 @@ int netxen_rom_se(struct netxen_adapter *adapter, int addr); int netxen_alloc_sw_resources(struct netxen_adapter *adapter); void netxen_free_sw_resources(struct netxen_adapter *adapter); +void netxen_setup_hwops(struct netxen_adapter *adapter); +void __iomem *netxen_get_ioaddr(struct netxen_adapter *, u32); + int netxen_alloc_hw_resources(struct netxen_adapter *adapter); void netxen_free_hw_resources(struct netxen_adapter *adapter); void netxen_release_rx_buffers(struct netxen_adapter *adapter); void netxen_release_tx_buffers(struct netxen_adapter *adapter); -void netxen_initialize_adapter_ops(struct netxen_adapter *adapter); int netxen_init_firmware(struct netxen_adapter *adapter); void netxen_nic_clear_stats(struct netxen_adapter *adapter); void netxen_watchdog_task(struct work_struct *work); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 8ab5773..33f82db 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -229,7 +229,8 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter) rds_ring = &recv_ctx->rds_rings[i]; reg = le32_to_cpu(prsp_rds[i].host_producer_crb); - rds_ring->crb_rcv_producer = NETXEN_NIC_REG(reg - 0x200); + rds_ring->crb_rcv_producer = netxen_get_ioaddr(adapter, + NETXEN_NIC_REG(reg - 0x200)); } prsp_sds = ((nx_cardrsp_sds_ring_t *) @@ -239,10 +240,12 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter) sds_ring = &recv_ctx->sds_rings[i]; reg = le32_to_cpu(prsp_sds[i].host_consumer_crb); - sds_ring->crb_sts_consumer = NETXEN_NIC_REG(reg - 0x200); + sds_ring->crb_sts_consumer = netxen_get_ioaddr(adapter, + NETXEN_NIC_REG(reg - 0x200)); reg = le32_to_cpu(prsp_sds[i].interrupt_crb); - sds_ring->crb_intr_mask = NETXEN_NIC_REG(reg - 0x200); + sds_ring->crb_intr_mask = netxen_get_ioaddr(adapter, + NETXEN_NIC_REG(reg - 0x200)); } recv_ctx->state = le32_to_cpu(prsp->host_ctx_state); @@ -342,7 +345,8 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter) if (err == NX_RCODE_SUCCESS) { temp = le32_to_cpu(prsp->cds_ring.host_producer_crb); - tx_ring->crb_cmd_producer = NETXEN_NIC_REG(temp - 0x200); + tx_ring->crb_cmd_producer = netxen_get_ioaddr(adapter, + NETXEN_NIC_REG(temp - 0x200)); #if 0 adapter->tx_state = le32_to_cpu(prsp->host_ctx_state); @@ -651,7 +655,8 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) rds_ring->crb_rcv_producer = - recv_crb_registers[port].crb_rcv_producer[ring]; + netxen_get_ioaddr(adapter, + recv_crb_registers[port].crb_rcv_producer[ring]); } for (ring = 0; ring < adapter->max_sds_rings; ring++) { @@ -670,10 +675,12 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) sds_ring->desc_head = (struct status_desc *)addr; sds_ring->crb_sts_consumer = - recv_crb_registers[port].crb_sts_consumer[ring]; + netxen_get_ioaddr(adapter, + recv_crb_registers[port].crb_sts_consumer[ring]); sds_ring->crb_intr_mask = - recv_crb_registers[port].sw_int_mask[ring]; + netxen_get_ioaddr(adapter, + recv_crb_registers[port].sw_int_mask[ring]); } diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index e376a1c..d18832c 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -84,18 +84,17 @@ static void netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { struct netxen_adapter *adapter = netdev_priv(dev); - unsigned long flags; u32 fw_major = 0; u32 fw_minor = 0; u32 fw_build = 0; strncpy(drvinfo->driver, netxen_nic_driver_name, 32); strncpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, 32); - write_lock_irqsave(&adapter->adapter_lock, flags); + read_lock(&adapter->adapter_lock); fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); - write_unlock_irqrestore(&adapter->adapter_lock, flags); + read_unlock(&adapter->adapter_lock); sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index d0ac8fa..cbfd610 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -1050,7 +1050,7 @@ int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac) /* * Changes the CRB window to the specified window. */ -void +static void netxen_nic_pci_change_crbwindow_128M(struct netxen_adapter *adapter, u32 wndw) { void __iomem *offset; @@ -1163,61 +1163,68 @@ netxen_nic_pci_set_crbwindow_2M(struct netxen_adapter *adapter, ulong *off) (ulong)adapter->ahw.pci_base0; } -int +static int netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, ulong off, u32 data) { + unsigned long flags; void __iomem *addr; - if (ADDR_IN_WINDOW1(off)) { + if (ADDR_IN_WINDOW1(off)) addr = NETXEN_CRB_NORMALIZE(adapter, off); + else + addr = pci_base_offset(adapter, off); + + BUG_ON(!addr); + + if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ + read_lock(&adapter->adapter_lock); + writel(data, addr); + read_unlock(&adapter->adapter_lock); } else { /* Window 0 */ + write_lock_irqsave(&adapter->adapter_lock, flags); addr = pci_base_offset(adapter, off); netxen_nic_pci_change_crbwindow_128M(adapter, 0); - } - - if (!addr) { + writel(data, addr); netxen_nic_pci_change_crbwindow_128M(adapter, 1); - return 1; + write_unlock_irqrestore(&adapter->adapter_lock, flags); } - writel(data, addr); - - if (!ADDR_IN_WINDOW1(off)) - netxen_nic_pci_change_crbwindow_128M(adapter, 1); - return 0; } -u32 +static u32 netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, ulong off) { + unsigned long flags; void __iomem *addr; u32 data; - if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ + if (ADDR_IN_WINDOW1(off)) addr = NETXEN_CRB_NORMALIZE(adapter, off); - } else { /* Window 0 */ + else addr = pci_base_offset(adapter, off); - netxen_nic_pci_change_crbwindow_128M(adapter, 0); - } - - if (!addr) { - netxen_nic_pci_change_crbwindow_128M(adapter, 1); - return 1; - } - data = readl(addr); + BUG_ON(!addr); - if (!ADDR_IN_WINDOW1(off)) + if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ + read_lock(&adapter->adapter_lock); + data = readl(addr); + read_unlock(&adapter->adapter_lock); + } else { /* Window 0 */ + write_lock_irqsave(&adapter->adapter_lock, flags); + netxen_nic_pci_change_crbwindow_128M(adapter, 0); + data = readl(addr); netxen_nic_pci_change_crbwindow_128M(adapter, 1); + write_unlock_irqrestore(&adapter->adapter_lock, flags); + } return data; } -int +static int netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, ulong off, u32 data) { - unsigned long flags = 0; + unsigned long flags; int rv; rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off); @@ -1243,10 +1250,10 @@ netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, ulong off, u32 data) return 0; } -u32 +static u32 netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off) { - unsigned long flags = 0; + unsigned long flags; int rv; u32 data; @@ -1293,7 +1300,7 @@ netxen_nic_pci_mem_bound_check(struct netxen_adapter *adapter, static int netxen_pci_set_window_warning_count; -unsigned long +static unsigned long netxen_nic_pci_set_window_128M(struct netxen_adapter *adapter, unsigned long long addr) { @@ -1357,22 +1364,56 @@ netxen_nic_pci_set_window_128M(struct netxen_adapter *adapter, return addr; } -/* - * Note : only 32-bit writes! - */ -int netxen_nic_pci_write_immediate_128M(struct netxen_adapter *adapter, - u64 off, u32 data) +/* window 1 registers only */ +static void netxen_nic_io_write_128M(struct netxen_adapter *adapter, + void __iomem *addr, u32 data) { - writel(data, (void __iomem *)(PCI_OFFSET_SECOND_RANGE(adapter, off))); - return 0; + read_lock(&adapter->adapter_lock); + writel(data, addr); + read_unlock(&adapter->adapter_lock); +} + +static u32 netxen_nic_io_read_128M(struct netxen_adapter *adapter, + void __iomem *addr) +{ + u32 val; + + read_lock(&adapter->adapter_lock); + val = readl(addr); + read_unlock(&adapter->adapter_lock); + + return val; } -u32 netxen_nic_pci_read_immediate_128M(struct netxen_adapter *adapter, u64 off) +static void netxen_nic_io_write_2M(struct netxen_adapter *adapter, + void __iomem *addr, u32 data) { - return readl((void __iomem *)(pci_base_offset(adapter, off))); + writel(data, addr); +} + +static u32 netxen_nic_io_read_2M(struct netxen_adapter *adapter, + void __iomem *addr) +{ + return readl(addr); +} + +void __iomem * +netxen_get_ioaddr(struct netxen_adapter *adapter, u32 offset) +{ + ulong off = offset; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + if (offset < NETXEN_CRB_PCIX_HOST2 && + offset > NETXEN_CRB_PCIX_HOST) + return PCI_OFFSET_SECOND_RANGE(adapter, offset); + return NETXEN_CRB_NORMALIZE(adapter, offset); + } + + BUG_ON(netxen_nic_pci_get_crb_addr_2M(adapter, &off)); + return (void __iomem *)off; } -unsigned long +static unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, unsigned long long addr) { @@ -1616,7 +1657,7 @@ netxen_nic_pci_mem_write_direct(struct netxen_adapter *adapter, u64 off, #define MAX_CTL_CHECK 1000 -int +static int netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter, u64 off, void *data, int size) { @@ -1709,7 +1750,7 @@ netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter, return ret; } -int +static int netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter, u64 off, void *data, int size) { @@ -1800,7 +1841,7 @@ netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter, return 0; } -int +static int netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, u64 off, void *data, int size) { @@ -1828,8 +1869,8 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, if ((size != 8) || (off0 != 0)) { for (i = 0; i < loop; i++) { - if (adapter->pci_mem_read(adapter, off8 + (i << 3), - &word[i], 8)) + if (adapter->pci_mem_read(adapter, + off8 + (i << 3), &word[i], 8)) return -1; } } @@ -1900,7 +1941,7 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, return ret; } -int +static int netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, u64 off, void *data, int size) { @@ -1998,20 +2039,43 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, return 0; } -/* - * Note : only 32-bit writes! - */ -int netxen_nic_pci_write_immediate_2M(struct netxen_adapter *adapter, - u64 off, u32 data) +void +netxen_setup_hwops(struct netxen_adapter *adapter) { - NXWR32(adapter, off, data); + adapter->init_port = netxen_niu_xg_init_port; + adapter->stop_port = netxen_niu_disable_xg_port; - return 0; -} + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + adapter->crb_read = netxen_nic_hw_read_wx_128M, + adapter->crb_write = netxen_nic_hw_write_wx_128M, + adapter->pci_set_window = netxen_nic_pci_set_window_128M, + adapter->pci_mem_read = netxen_nic_pci_mem_read_128M, + adapter->pci_mem_write = netxen_nic_pci_mem_write_128M, + adapter->io_read = netxen_nic_io_read_128M, + adapter->io_write = netxen_nic_io_write_128M, + + adapter->macaddr_set = netxen_p2_nic_set_mac_addr; + adapter->set_multi = netxen_p2_nic_set_multi; + adapter->set_mtu = netxen_nic_set_mtu_xgb; + adapter->set_promisc = netxen_p2_nic_set_promisc; -u32 netxen_nic_pci_read_immediate_2M(struct netxen_adapter *adapter, u64 off) -{ - return NXRD32(adapter, off); + } else { + adapter->crb_read = netxen_nic_hw_read_wx_2M, + adapter->crb_write = netxen_nic_hw_write_wx_2M, + adapter->pci_set_window = netxen_nic_pci_set_window_2M, + adapter->pci_mem_read = netxen_nic_pci_mem_read_2M, + adapter->pci_mem_write = netxen_nic_pci_mem_write_2M, + adapter->io_read = netxen_nic_io_read_2M, + adapter->io_write = netxen_nic_io_write_2M, + + adapter->set_mtu = nx_fw_cmd_set_mtu; + adapter->set_promisc = netxen_p3_nic_set_promisc; + adapter->macaddr_set = netxen_p3_nic_set_mac_addr; + adapter->set_multi = netxen_p3_nic_set_multi; + + adapter->phy_read = nx_fw_cmd_query_phy; + adapter->phy_write = nx_fw_cmd_set_phy; + } } int netxen_nic_get_board_info(struct netxen_adapter *adapter) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 534994d..485b947 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -323,29 +323,6 @@ err_out: return -ENOMEM; } -void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) -{ - adapter->init_port = netxen_niu_xg_init_port; - adapter->stop_port = netxen_niu_disable_xg_port; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - adapter->macaddr_set = netxen_p2_nic_set_mac_addr; - adapter->set_multi = netxen_p2_nic_set_multi; - adapter->set_mtu = netxen_nic_set_mtu_xgb; - adapter->set_promisc = netxen_p2_nic_set_promisc; - } else { - adapter->set_mtu = nx_fw_cmd_set_mtu; - adapter->set_promisc = netxen_p3_nic_set_promisc; - adapter->macaddr_set = netxen_p3_nic_set_mac_addr; - adapter->set_multi = netxen_p3_nic_set_multi; - - if (adapter->ahw.port_type == NETXEN_NIC_GBE) { - adapter->phy_read = nx_fw_cmd_query_phy; - adapter->phy_write = nx_fw_cmd_set_phy; - } - } -} - /* * netxen_decode_crb_addr(0 - utility to translate from internal Phantom CRB * address to external PCI CRB address. @@ -1395,7 +1372,7 @@ skip: if (count) { sds_ring->consumer = consumer; - NXWR32(adapter, sds_ring->crb_sts_consumer, consumer); + NXWRIO(adapter, sds_ring->crb_sts_consumer, consumer); } return count; @@ -1513,7 +1490,7 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, if (count) { rds_ring->producer = producer; - NXWR32(adapter, rds_ring->crb_rcv_producer, + NXWRIO(adapter, rds_ring->crb_rcv_producer, (producer-1) & (rds_ring->num_desc-1)); if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { @@ -1529,9 +1506,10 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, (rds_ring->num_desc - 1))); netxen_set_msg_ctxid(msg, adapter->portnum); netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid)); - writel(msg, - DB_NORMALIZE(adapter, + read_lock(&adapter->adapter_lock); + writel(msg, DB_NORMALIZE(adapter, NETXEN_RCV_PRODUCER_OFFSET)); + read_unlock(&adapter->adapter_lock); } } } @@ -1573,7 +1551,7 @@ netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, if (count) { rds_ring->producer = producer; - NXWR32(adapter, rds_ring->crb_rcv_producer, + NXWRIO(adapter, rds_ring->crb_rcv_producer, (producer - 1) & (rds_ring->num_desc - 1)); } spin_unlock(&rds_ring->lock); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 7038e1b..b2fd713 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -116,7 +116,7 @@ void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, struct nx_host_tx_ring *tx_ring) { - NXWR32(adapter, tx_ring->crb_cmd_producer, tx_ring->producer); + NXWRIO(adapter, tx_ring->crb_cmd_producer, tx_ring->producer); if (netxen_tx_avail(tx_ring) <= TX_STOP_THRESH) { netif_stop_queue(adapter->netdev); @@ -133,7 +133,7 @@ static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter, struct nx_host_tx_ring *tx_ring) { - NXWR32(adapter, tx_ring->crb_cmd_consumer, tx_ring->sw_consumer); + NXWRIO(adapter, tx_ring->crb_cmd_consumer, tx_ring->sw_consumer); } static uint32_t msi_tgt_status[8] = { @@ -149,18 +149,17 @@ static inline void netxen_nic_disable_int(struct nx_host_sds_ring *sds_ring) { struct netxen_adapter *adapter = sds_ring->adapter; - NXWR32(adapter, sds_ring->crb_intr_mask, 0); + NXWRIO(adapter, sds_ring->crb_intr_mask, 0); } static inline void netxen_nic_enable_int(struct nx_host_sds_ring *sds_ring) { struct netxen_adapter *adapter = sds_ring->adapter; - NXWR32(adapter, sds_ring->crb_intr_mask, 0x1); + NXWRIO(adapter, sds_ring->crb_intr_mask, 0x1); if (!NETXEN_IS_MSI_FAMILY(adapter)) - adapter->pci_write_immediate(adapter, - adapter->legacy_intr.tgt_mask_reg, 0xfbff); + NXWRIO(adapter, adapter->tgt_mask_reg, 0xfbff); } static int @@ -556,10 +555,22 @@ netxen_setup_intr(struct netxen_adapter *adapter) legacy_intrp = &legacy_intr[adapter->ahw.pci_func]; else legacy_intrp = &legacy_intr[0]; - adapter->legacy_intr.int_vec_bit = legacy_intrp->int_vec_bit; - adapter->legacy_intr.tgt_status_reg = legacy_intrp->tgt_status_reg; - adapter->legacy_intr.tgt_mask_reg = legacy_intrp->tgt_mask_reg; - adapter->legacy_intr.pci_int_reg = legacy_intrp->pci_int_reg; + + adapter->int_vec_bit = legacy_intrp->int_vec_bit; + adapter->tgt_status_reg = netxen_get_ioaddr(adapter, + legacy_intrp->tgt_status_reg); + adapter->tgt_mask_reg = netxen_get_ioaddr(adapter, + legacy_intrp->tgt_mask_reg); + adapter->pci_int_reg = netxen_get_ioaddr(adapter, + legacy_intrp->pci_int_reg); + adapter->isr_int_vec = netxen_get_ioaddr(adapter, ISR_INT_VECTOR); + + if (adapter->ahw.revision_id >= NX_P3_B1) + adapter->crb_int_state_reg = netxen_get_ioaddr(adapter, + ISR_INT_STATE_REG); + else + adapter->crb_int_state_reg = netxen_get_ioaddr(adapter, + CRB_INT_VECTOR); netxen_set_msix_bit(pdev, 0); @@ -586,8 +597,8 @@ netxen_setup_intr(struct netxen_adapter *adapter) if (use_msi && !pci_enable_msi(pdev)) { adapter->flags |= NETXEN_NIC_MSI_ENABLED; - adapter->msi_tgt_status = - msi_tgt_status[adapter->ahw.pci_func]; + adapter->tgt_status_reg = netxen_get_ioaddr(adapter, + msi_tgt_status[adapter->ahw.pci_func]); dev_info(&pdev->dev, "using msi interrupts\n"); adapter->msix_entries[0].vector = pdev->irq; return; @@ -647,14 +658,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) mem_len = pci_resource_len(pdev, 0); pci_len0 = 0; - adapter->hw_write_wx = netxen_nic_hw_write_wx_128M; - adapter->hw_read_wx = netxen_nic_hw_read_wx_128M; - adapter->pci_read_immediate = netxen_nic_pci_read_immediate_128M; - adapter->pci_write_immediate = netxen_nic_pci_write_immediate_128M; - adapter->pci_set_window = netxen_nic_pci_set_window_128M; - adapter->pci_mem_read = netxen_nic_pci_mem_read_128M; - adapter->pci_mem_write = netxen_nic_pci_mem_write_128M; - /* 128 Meg of memory */ if (mem_len == NETXEN_PCI_128MB_SIZE) { mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); @@ -667,14 +670,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START - SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); } else if (mem_len == NETXEN_PCI_2MB_SIZE) { - adapter->hw_write_wx = netxen_nic_hw_write_wx_2M; - adapter->hw_read_wx = netxen_nic_hw_read_wx_2M; - adapter->pci_read_immediate = netxen_nic_pci_read_immediate_2M; - adapter->pci_write_immediate = - netxen_nic_pci_write_immediate_2M; - adapter->pci_set_window = netxen_nic_pci_set_window_2M; - adapter->pci_mem_read = netxen_nic_pci_mem_read_2M; - adapter->pci_mem_write = netxen_nic_pci_mem_write_2M; mem_ptr0 = pci_ioremap_bar(pdev, 0); if (mem_ptr0 == NULL) { @@ -698,6 +693,8 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) return -EIO; } + netxen_setup_hwops(adapter); + dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20)); adapter->ahw.pci_base0 = mem_ptr0; @@ -990,8 +987,10 @@ netxen_nic_attach(struct netxen_adapter *adapter) if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { tx_ring = adapter->tx_ring; - tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum]; - tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum]; + tx_ring->crb_cmd_producer = netxen_get_ioaddr(adapter, + crb_cmd_producer[adapter->portnum]); + tx_ring->crb_cmd_consumer = netxen_get_ioaddr(adapter, + crb_cmd_consumer[adapter->portnum]); tx_ring->producer = 0; tx_ring->sw_consumer = 0; @@ -1213,8 +1212,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_iounmap; } - netxen_initialize_adapter_ops(adapter); - /* Mezz cards have PCI function 0,2,3 enabled */ switch (adapter->ahw.board_type) { case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ: @@ -1870,41 +1867,37 @@ static irqreturn_t netxen_intr(int irq, void *data) struct netxen_adapter *adapter = sds_ring->adapter; u32 status = 0; - status = adapter->pci_read_immediate(adapter, ISR_INT_VECTOR); + status = readl(adapter->isr_int_vec); - if (!(status & adapter->legacy_intr.int_vec_bit)) + if (!(status & adapter->int_vec_bit)) return IRQ_NONE; - if (adapter->ahw.revision_id >= NX_P3_B1) { + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { /* check interrupt state machine, to be sure */ - status = adapter->pci_read_immediate(adapter, - ISR_INT_STATE_REG); + status = readl(adapter->crb_int_state_reg); if (!ISR_LEGACY_INT_TRIGGERED(status)) return IRQ_NONE; } else { unsigned long our_int = 0; - our_int = NXRD32(adapter, CRB_INT_VECTOR); + our_int = readl(adapter->crb_int_state_reg); /* not our interrupt */ if (!test_and_clear_bit((7 + adapter->portnum), &our_int)) return IRQ_NONE; /* claim interrupt */ - NXWR32(adapter, CRB_INT_VECTOR, (our_int & 0xffffffff)); - } + writel((our_int & 0xffffffff), adapter->crb_int_state_reg); - /* clear interrupt */ - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + /* clear interrupt */ netxen_nic_disable_int(sds_ring); + } - adapter->pci_write_immediate(adapter, - adapter->legacy_intr.tgt_status_reg, - 0xffffffff); + writel(0xffffffff, adapter->tgt_status_reg); /* read twice to ensure write is flushed */ - adapter->pci_read_immediate(adapter, ISR_INT_VECTOR); - adapter->pci_read_immediate(adapter, ISR_INT_VECTOR); + readl(adapter->isr_int_vec); + readl(adapter->isr_int_vec); napi_schedule(&sds_ring->napi); @@ -1917,8 +1910,7 @@ static irqreturn_t netxen_msi_intr(int irq, void *data) struct netxen_adapter *adapter = sds_ring->adapter; /* clear interrupt */ - adapter->pci_write_immediate(adapter, - adapter->msi_tgt_status, 0xffffffff); + writel(0xffffffff, adapter->tgt_status_reg); napi_schedule(&sds_ring->napi); return IRQ_HANDLED; -- cgit v0.10.2 From 2b9e62ee7b2f1971c01fdaa7653c9dae7b571187 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sat, 5 Sep 2009 17:43:11 +0000 Subject: netxen: refactor firmware info code o Combine netxen_get_firmware_info(), netxen_check_options() so that they are updated every time firmware is reset. o Set dma mask everytime firmware is reset. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 5bbc40b..df03ea4 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1263,7 +1263,6 @@ void netxen_pcie_sem_unlock(struct netxen_adapter *, int); netxen_pcie_sem_unlock((a), 7) int netxen_nic_get_board_info(struct netxen_adapter *adapter); -void netxen_nic_get_firmware_info(struct netxen_adapter *adapter); int netxen_nic_wol_supported(struct netxen_adapter *adapter); /* Functions from netxen_nic_init.c */ diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index cbfd610..555bc4a 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -2240,65 +2240,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) } } -void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) -{ - u32 fw_major, fw_minor, fw_build; - char brd_name[NETXEN_MAX_SHORT_NAME]; - char serial_num[32]; - int i, offset, val; - int *ptr32; - struct pci_dev *pdev = adapter->pdev; - - adapter->driver_mismatch = 0; - - ptr32 = (int *)&serial_num; - offset = NX_FW_SERIAL_NUM_OFFSET; - for (i = 0; i < 8; i++) { - if (netxen_rom_fast_read(adapter, offset, &val) == -1) { - dev_err(&pdev->dev, "error reading board info\n"); - adapter->driver_mismatch = 1; - return; - } - ptr32[i] = cpu_to_le32(val); - offset += sizeof(u32); - } - - fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); - fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); - fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); - - adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build); - - if (adapter->portnum == 0) { - get_brd_name_by_type(adapter->ahw.board_type, brd_name); - - printk(KERN_INFO "NetXen %s Board S/N %s Chip rev 0x%x\n", - brd_name, serial_num, adapter->ahw.revision_id); - } - - if (adapter->fw_version < NETXEN_VERSION_CODE(3, 4, 216)) { - adapter->driver_mismatch = 1; - dev_warn(&pdev->dev, "firmware version %d.%d.%d unsupported\n", - fw_major, fw_minor, fw_build); - return; - } - - dev_info(&pdev->dev, "firmware version %d.%d.%d\n", - fw_major, fw_minor, fw_build); - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - i = NXRD32(adapter, NETXEN_SRE_MISC); - adapter->ahw.cut_through = (i & 0x8000) ? 1 : 0; - dev_info(&pdev->dev, "firmware running in %s mode\n", - adapter->ahw.cut_through ? "cut-through" : "legacy"); - } - - if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) - adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); - - adapter->flags &= ~NETXEN_NIC_LRO_ENABLED; -} - int netxen_nic_wol_supported(struct netxen_adapter *adapter) { diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index b2fd713..304618a 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -318,44 +318,6 @@ err_out: return err; } -static void -netxen_check_options(struct netxen_adapter *adapter) -{ - if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { - adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G; - adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; - } else if (adapter->ahw.port_type == NETXEN_NIC_GBE) { - adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; - adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; - } - - adapter->msix_supported = 0; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - adapter->msix_supported = !!use_msi_x; - adapter->rss_supported = !!use_msi_x; - } else if (adapter->fw_version >= NETXEN_VERSION_CODE(3, 4, 336)) { - switch (adapter->ahw.board_type) { - case NETXEN_BRDTYPE_P2_SB31_10G: - case NETXEN_BRDTYPE_P2_SB31_10G_CX4: - adapter->msix_supported = !!use_msi_x; - adapter->rss_supported = !!use_msi_x; - break; - default: - break; - } - } - - adapter->num_txd = MAX_CMD_DESCRIPTORS; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS; - adapter->max_rds_rings = 3; - } else { - adapter->num_lro_rxd = 0; - adapter->max_rds_rings = 2; - } -} - static int netxen_check_hw_init(struct netxen_adapter *adapter, int first_boot) { @@ -733,12 +695,110 @@ err_out: return err; } +static void +netxen_check_options(struct netxen_adapter *adapter) +{ + u32 fw_major, fw_minor, fw_build; + char brd_name[NETXEN_MAX_SHORT_NAME]; + char serial_num[32]; + int i, offset, val; + int *ptr32; + struct pci_dev *pdev = adapter->pdev; + + adapter->driver_mismatch = 0; + + ptr32 = (int *)&serial_num; + offset = NX_FW_SERIAL_NUM_OFFSET; + for (i = 0; i < 8; i++) { + if (netxen_rom_fast_read(adapter, offset, &val) == -1) { + dev_err(&pdev->dev, "error reading board info\n"); + adapter->driver_mismatch = 1; + return; + } + ptr32[i] = cpu_to_le32(val); + offset += sizeof(u32); + } + + fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); + fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); + fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); + + adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build); + + if (adapter->portnum == 0) { + get_brd_name_by_type(adapter->ahw.board_type, brd_name); + + printk(KERN_INFO "NetXen %s Board S/N %s Chip rev 0x%x\n", + brd_name, serial_num, adapter->ahw.revision_id); + } + + if (adapter->fw_version < NETXEN_VERSION_CODE(3, 4, 216)) { + adapter->driver_mismatch = 1; + dev_warn(&pdev->dev, "firmware version %d.%d.%d unsupported\n", + fw_major, fw_minor, fw_build); + return; + } + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + i = NXRD32(adapter, NETXEN_SRE_MISC); + adapter->ahw.cut_through = (i & 0x8000) ? 1 : 0; + } + + dev_info(&pdev->dev, "firmware v%d.%d.%d [%s]\n", + fw_major, fw_minor, fw_build, + adapter->ahw.cut_through ? "cut-through" : "legacy"); + + if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) + adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); + + adapter->flags &= ~NETXEN_NIC_LRO_ENABLED; + + if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } else if (adapter->ahw.port_type == NETXEN_NIC_GBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; + } + + adapter->msix_supported = 0; + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + adapter->msix_supported = !!use_msi_x; + adapter->rss_supported = !!use_msi_x; + } else if (adapter->fw_version >= NETXEN_VERSION_CODE(3, 4, 336)) { + switch (adapter->ahw.board_type) { + case NETXEN_BRDTYPE_P2_SB31_10G: + case NETXEN_BRDTYPE_P2_SB31_10G_CX4: + adapter->msix_supported = !!use_msi_x; + adapter->rss_supported = !!use_msi_x; + break; + default: + break; + } + } + + adapter->num_txd = MAX_CMD_DESCRIPTORS; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS; + adapter->max_rds_rings = 3; + } else { + adapter->num_lro_rxd = 0; + adapter->max_rds_rings = 2; + } +} + static int netxen_start_firmware(struct netxen_adapter *adapter) { int val, err, first_boot; struct pci_dev *pdev = adapter->pdev; + /* required for NX2031 dummy dma */ + err = nx_set_dma_mask(adapter); + if (err) + return err; + if (!netxen_can_start_firmware(adapter)) goto wait_init; @@ -811,7 +871,6 @@ wait_init: nx_update_dma_mask(adapter); - netxen_nic_get_firmware_info(adapter); netxen_check_options(adapter); return 0; @@ -1191,10 +1250,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) revision_id = pdev->revision; adapter->ahw.revision_id = revision_id; - err = nx_set_dma_mask(adapter); - if (err) - goto err_out_free_netdev; - rwlock_init(&adapter->adapter_lock); spin_lock_init(&adapter->tx_clean_lock); INIT_LIST_HEAD(&adapter->mac_list); -- cgit v0.10.2 From 5877e55f32bb50956c9a1df8e7db3fbc67dc47b6 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sat, 5 Sep 2009 17:43:12 +0000 Subject: netxen: update version to 4.0.50 Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index df03ea4..2a52479 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -58,8 +58,8 @@ #define _NETXEN_NIC_LINUX_MAJOR 4 #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 41 -#define NETXEN_NIC_LINUX_VERSIONID "4.0.41" +#define _NETXEN_NIC_LINUX_SUBVERSION 50 +#define NETXEN_NIC_LINUX_VERSIONID "4.0.50" #define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) #define _major(v) (((v) >> 24) & 0xff) -- cgit v0.10.2 From 384824281caa9ac4b76664033416f1eac4a652fe Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 4 Sep 2009 05:33:46 +0000 Subject: wan: dlci/sdla transmit return dehacking This is a brute force removal of the wierd slave interface done for DLCI -> SDLA transmit. Before it was using non-standard return values and freeing skb in caller. This changes it to using normal return values, and freeing in the callee. Luckly only one driver pair was doing this. Not tested on real hardware, in fact I wonder if this driver pair is even being used by any users. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 69d269d..15d353f 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -186,46 +186,13 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); } -static netdev_tx_t dlci_transmit(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t dlci_transmit(struct sk_buff *skb, struct net_device *dev) { - struct dlci_local *dlp; - netdev_tx_t ret; - - if (!skb || !dev) - return NETDEV_TX_OK; - - dlp = netdev_priv(dev); - - netif_stop_queue(dev); - - /* This is hackish, overloads driver specific return values - on top of normal transmit return! */ - ret = dlp->slave->netdev_ops->ndo_start_xmit(skb, dlp->slave); - switch (ret) - { - case DLCI_RET_OK: - dev->stats.tx_packets++; - ret = NETDEV_TX_OK; - break; - case DLCI_RET_ERR: - dev->stats.tx_errors++; - ret = NETDEV_TX_OK; - break; - case DLCI_RET_DROP: - dev->stats.tx_dropped++; - ret = NETDEV_TX_BUSY; - break; - } - /* Alan Cox recommends always returning 0, and always freeing the packet */ - /* experience suggest a slightly more conservative approach */ + struct dlci_local *dlp = netdev_priv(dev); - if (ret == NETDEV_TX_OK) - { - dev_kfree_skb(skb); - netif_wake_queue(dev); - } - return(ret); + if (skb) + dlp->slave->netdev_ops->ndo_start_xmit(skb, dlp->slave); + return NETDEV_TX_OK; } static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, int get) diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 63c7645..2b15a7e 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -652,7 +652,7 @@ static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, i /* NOTE: the DLCI driver deals with freeing the SKB!! */ static netdev_tx_t sdla_transmit(struct sk_buff *skb, - struct net_device *dev) + struct net_device *dev) { struct frad_local *flp; int ret, addr, accept, i; @@ -712,23 +712,21 @@ static netdev_tx_t sdla_transmit(struct sk_buff *skb, } break; } + switch (ret) { case SDLA_RET_OK: dev->stats.tx_packets++; - ret = DLCI_RET_OK; break; case SDLA_RET_CIR_OVERFLOW: case SDLA_RET_BUF_OVERSIZE: case SDLA_RET_NO_BUFS: dev->stats.tx_dropped++; - ret = DLCI_RET_DROP; break; default: dev->stats.tx_errors++; - ret = DLCI_RET_ERR; break; } } @@ -738,6 +736,8 @@ static netdev_tx_t sdla_transmit(struct sk_buff *skb, if(flp->master[i]!=NULL) netif_wake_queue(flp->master[i]); } + + dev_kfree_skb(skb); return NETDEV_TX_OK; } diff --git a/include/linux/if_frad.h b/include/linux/if_frad.h index 673f220..80b3a10 100644 --- a/include/linux/if_frad.h +++ b/include/linux/if_frad.h @@ -69,11 +69,6 @@ struct dlci_conf { #define DLCI_VALID_FLAGS 0x000B -/* FRAD driver uses these to indicate what it did with packet */ -#define DLCI_RET_OK 0x00 -#define DLCI_RET_ERR 0x01 -#define DLCI_RET_DROP 0x02 - /* defines for the actual Frame Relay hardware */ #define FRAD_GET_CONF (SIOCDEVPRIVATE) #define FRAD_SET_CONF (SIOCDEVPRIVATE + 1) -- cgit v0.10.2 From 84517482e19bc775de7b3b4e998dee2f506bc34e Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Fri, 4 Sep 2009 03:12:16 +0000 Subject: be2net: Changes to support flashing of the be2 network adapter Changes to support flashing of the be2 network adapter using the request_firmware() & ethtool infrastructure. The trigger to flash the device will come from ethtool utility. The driver will invoke request_firmware() to start the flash process. The file containing the flash image is expected to be available in /lib/firmware/ Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 6c45a22..13b72ce 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -28,10 +28,11 @@ #include #include #include +#include #include "be_hw.h" -#define DRV_VER "2.0.400" +#define DRV_VER "2.101.205" #define DRV_NAME "be2net" #define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" #define OC_NAME "Emulex OneConnect 10Gbps NIC" @@ -361,4 +362,5 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); extern void be_link_status_update(struct be_adapter *adapter, bool link_up); +extern int be_load_fw(struct be_adapter *adapter, u8 *func); #endif /* BE_H */ diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 2547ee2..1db0924 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -155,7 +155,7 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) if (ready) break; - if (cnt > 200000) { + if (cnt > 4000000) { dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); return -1; } @@ -1040,3 +1040,31 @@ int be_cmd_reset_function(struct be_adapter *adapter) spin_unlock(&adapter->mbox_lock); return status; } + +int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, + u32 flash_type, u32 flash_opcode, u32 buf_size) +{ + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); + struct be_cmd_write_flashrom *req = cmd->va; + struct be_sge *sge = nonembedded_sgl(wrb); + int status; + + spin_lock(&adapter->mbox_lock); + memset(wrb, 0, sizeof(*wrb)); + be_wrb_hdr_prepare(wrb, cmd->size, false, 1); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_WRITE_FLASHROM, cmd->size); + sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma)); + sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(cmd->size); + + req->params.op_type = cpu_to_le32(flash_type); + req->params.op_code = cpu_to_le32(flash_opcode); + req->params.data_buf_size = cpu_to_le32(buf_size); + + status = be_mbox_notify(adapter); + + spin_unlock(&adapter->mbox_lock); + return status; +} diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 7061806..fd7028e 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -117,6 +117,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_NTWK_MULTICAST_SET 3 #define OPCODE_COMMON_NTWK_VLAN_CONFIG 4 #define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY 5 +#define OPCODE_COMMON_WRITE_FLASHROM 7 #define OPCODE_COMMON_CQ_CREATE 12 #define OPCODE_COMMON_EQ_CREATE 13 #define OPCODE_COMMON_MCC_CREATE 21 @@ -693,10 +694,24 @@ struct be_cmd_resp_query_fw_cfg { u32 be_config_number; u32 asic_revision; u32 phys_port; - u32 function_mode; + u32 function_cap; u32 rsvd[26]; }; +/****************** Firmware Flash ******************/ +struct flashrom_params { + u32 op_code; + u32 op_type; + u32 data_buf_size; + u32 offset; + u8 data_buf[4]; +}; + +struct be_cmd_write_flashrom { + struct be_cmd_req_hdr hdr; + struct flashrom_params params; +}; + extern int be_pci_fnum_get(struct be_adapter *adapter); extern int be_cmd_POST(struct be_adapter *adapter); extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, @@ -747,3 +762,6 @@ extern int be_cmd_get_flow_control(struct be_adapter *adapter, extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num); extern int be_cmd_reset_function(struct be_adapter *adapter); extern void be_process_mcc(struct be_adapter *adapter); +extern int be_cmd_write_flashrom(struct be_adapter *adapter, + struct be_dma_mem *cmd, u32 flash_oper, + u32 flash_opcode, u32 buf_size); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 4ff3cc4..11445df 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -332,6 +332,20 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) return status; } +static int +be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) +{ + struct be_adapter *adapter = netdev_priv(netdev); + char file_name[ETHTOOL_FLASH_MAX_FILENAME]; + u32 region; + + file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; + strcpy(file_name, efl->data); + region = efl->region; + + return be_load_fw(adapter, file_name); +} + const struct ethtool_ops be_ethtool_ops = { .get_settings = be_get_settings, .get_drvinfo = be_get_drvinfo, @@ -352,4 +366,5 @@ const struct ethtool_ops be_ethtool_ops = { .get_strings = be_get_stat_strings, .get_stats_count = be_get_stats_count, .get_ethtool_stats = be_get_ethtool_stats, + .flash_device = be_do_flash, }; diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index d28f0c6..a3394b4 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -204,7 +204,7 @@ struct amap_eth_rx_compl { u8 numfrags[3]; /* dword 1 */ u8 rss_flush; /* dword 2 */ u8 cast_enc[2]; /* dword 2 */ - u8 qnq; /* dword 2 */ + u8 vtm; /* dword 2 */ u8 rss_bank; /* dword 2 */ u8 rsvd1[23]; /* dword 2 */ u8 lro_pkt; /* dword 2 */ @@ -216,3 +216,86 @@ struct amap_eth_rx_compl { struct be_eth_rx_compl { u32 dw[4]; }; + +/* Flashrom related descriptors */ +#define IMAGE_TYPE_FIRMWARE 160 +#define IMAGE_TYPE_BOOTCODE 224 +#define IMAGE_TYPE_OPTIONROM 32 + +#define NUM_FLASHDIR_ENTRIES 32 + +#define FLASHROM_TYPE_ISCSI_ACTIVE 0 +#define FLASHROM_TYPE_BIOS 2 +#define FLASHROM_TYPE_PXE_BIOS 3 +#define FLASHROM_TYPE_FCOE_BIOS 8 +#define FLASHROM_TYPE_ISCSI_BACKUP 9 +#define FLASHROM_TYPE_FCOE_FW_ACTIVE 10 +#define FLASHROM_TYPE_FCOE_FW_BACKUP 11 + +#define FLASHROM_OPER_FLASH 1 +#define FLASHROM_OPER_SAVE 2 + +#define FLASH_IMAGE_MAX_SIZE (1310720) /* Max firmware image size */ +#define FLASH_BIOS_IMAGE_MAX_SIZE (262144) /* Max OPTION ROM image sz */ + +/* Offsets for components on Flash. */ +#define FLASH_iSCSI_PRIMARY_IMAGE_START (1048576) +#define FLASH_iSCSI_BACKUP_IMAGE_START (2359296) +#define FLASH_FCoE_PRIMARY_IMAGE_START (3670016) +#define FLASH_FCoE_BACKUP_IMAGE_START (4980736) +#define FLASH_iSCSI_BIOS_START (7340032) +#define FLASH_PXE_BIOS_START (7864320) +#define FLASH_FCoE_BIOS_START (524288) + +struct controller_id { + u32 vendor; + u32 device; + u32 subvendor; + u32 subdevice; +}; + +struct flash_file_hdr { + u8 sign[32]; + u32 cksum; + u32 antidote; + struct controller_id cont_id; + u32 file_len; + u32 chunk_num; + u32 total_chunks; + u32 num_imgs; + u8 build[24]; +}; + +struct flash_section_hdr { + u32 format_rev; + u32 cksum; + u32 antidote; + u32 build_no; + u8 id_string[64]; + u32 active_entry_mask; + u32 valid_entry_mask; + u32 org_content_mask; + u32 rsvd0; + u32 rsvd1; + u32 rsvd2; + u32 rsvd3; + u32 rsvd4; +}; + +struct flash_section_entry { + u32 type; + u32 offset; + u32 pad_size; + u32 image_size; + u32 cksum; + u32 entry_point; + u32 rsvd0; + u32 rsvd1; + u8 ver_data[32]; +}; + +struct flash_section_info { + u8 cookie[32]; + struct flash_section_hdr fsec_hdr; + struct flash_section_entry fsec_entry[32]; +}; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index bac85f9..d09106f 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1699,6 +1699,173 @@ static int be_close(struct net_device *netdev) return 0; } +#define FW_FILE_HDR_SIGN "ServerEngines Corp. " +char flash_cookie[2][16] = {"*** SE FLAS", + "H DIRECTORY *** "}; +static int be_flash_image(struct be_adapter *adapter, + const struct firmware *fw, + struct be_dma_mem *flash_cmd, u32 flash_type) +{ + int status; + u32 flash_op, image_offset = 0, total_bytes, image_size = 0; + int num_bytes; + const u8 *p = fw->data; + struct be_cmd_write_flashrom *req = flash_cmd->va; + + switch (flash_type) { + case FLASHROM_TYPE_ISCSI_ACTIVE: + image_offset = FLASH_iSCSI_PRIMARY_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_ISCSI_BACKUP: + image_offset = FLASH_iSCSI_BACKUP_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_FCOE_FW_ACTIVE: + image_offset = FLASH_FCoE_PRIMARY_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_FCOE_FW_BACKUP: + image_offset = FLASH_FCoE_BACKUP_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_BIOS: + image_offset = FLASH_iSCSI_BIOS_START; + image_size = FLASH_BIOS_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_FCOE_BIOS: + image_offset = FLASH_FCoE_BIOS_START; + image_size = FLASH_BIOS_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_PXE_BIOS: + image_offset = FLASH_PXE_BIOS_START; + image_size = FLASH_BIOS_IMAGE_MAX_SIZE; + break; + default: + return 0; + } + + p += sizeof(struct flash_file_hdr) + image_offset; + if (p + image_size > fw->data + fw->size) + return -1; + + total_bytes = image_size; + + while (total_bytes) { + if (total_bytes > 32*1024) + num_bytes = 32*1024; + else + num_bytes = total_bytes; + total_bytes -= num_bytes; + + if (!total_bytes) + flash_op = FLASHROM_OPER_FLASH; + else + flash_op = FLASHROM_OPER_SAVE; + memcpy(req->params.data_buf, p, num_bytes); + p += num_bytes; + status = be_cmd_write_flashrom(adapter, flash_cmd, + flash_type, flash_op, num_bytes); + if (status) { + dev_err(&adapter->pdev->dev, + "cmd to write to flash rom failed. type/op %d/%d\n", + flash_type, flash_op); + return -1; + } + yield(); + } + + return 0; +} + +int be_load_fw(struct be_adapter *adapter, u8 *func) +{ + char fw_file[ETHTOOL_FLASH_MAX_FILENAME]; + const struct firmware *fw; + struct flash_file_hdr *fhdr; + struct flash_section_info *fsec = NULL; + struct be_dma_mem flash_cmd; + int status; + const u8 *p; + bool entry_found = false; + int flash_type; + char fw_ver[FW_VER_LEN]; + char fw_cfg; + + status = be_cmd_get_fw_ver(adapter, fw_ver); + if (status) + return status; + + fw_cfg = *(fw_ver + 2); + if (fw_cfg == '0') + fw_cfg = '1'; + strcpy(fw_file, func); + + status = request_firmware(&fw, fw_file, &adapter->pdev->dev); + if (status) + goto fw_exit; + + p = fw->data; + fhdr = (struct flash_file_hdr *) p; + if (memcmp(fhdr->sign, FW_FILE_HDR_SIGN, strlen(FW_FILE_HDR_SIGN))) { + dev_err(&adapter->pdev->dev, + "Firmware(%s) load error (signature did not match)\n", + fw_file); + status = -1; + goto fw_exit; + } + + dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file); + + p += sizeof(struct flash_file_hdr); + while (p < (fw->data + fw->size)) { + fsec = (struct flash_section_info *)p; + if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) { + entry_found = true; + break; + } + p += 32; + } + + if (!entry_found) { + status = -1; + dev_err(&adapter->pdev->dev, + "Flash cookie not found in firmware image\n"); + goto fw_exit; + } + + flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024; + flash_cmd.va = pci_alloc_consistent(adapter->pdev, flash_cmd.size, + &flash_cmd.dma); + if (!flash_cmd.va) { + status = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Memory allocation failure while flashing\n"); + goto fw_exit; + } + + for (flash_type = FLASHROM_TYPE_ISCSI_ACTIVE; + flash_type <= FLASHROM_TYPE_FCOE_FW_BACKUP; flash_type++) { + status = be_flash_image(adapter, fw, &flash_cmd, + flash_type); + if (status) + break; + } + + pci_free_consistent(adapter->pdev, flash_cmd.size, flash_cmd.va, + flash_cmd.dma); + if (status) { + dev_err(&adapter->pdev->dev, "Firmware load error\n"); + goto fw_exit; + } + + dev_info(&adapter->pdev->dev, "Firmware flashed succesfully\n"); + +fw_exit: + release_firmware(fw); + return status; +} + static struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, -- cgit v0.10.2 From c190e3c8f6b22004b9cdc62ee5e7ba2fa5f74dc7 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Fri, 4 Sep 2009 03:12:29 +0000 Subject: be2net: Code changes in Tx path to use skb_dma_map/skb_dma_unmap Code changes to - In the tx completion processing, there were instances of unmapping a memory as a page which was originally mapped as single. This patch takes care of this by using skb_dma_map()/skb_dma_unmap() to map/unmap Tx buffers. - set gso_max_size to 65535. This was not done till now. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index d09106f..ce11bba 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -385,15 +385,19 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_eth_wrb *wrb; struct be_eth_hdr_wrb *hdr; - atomic_add(wrb_cnt, &txq->used); hdr = queue_head_node(txq); + atomic_add(wrb_cnt, &txq->used); queue_head_inc(txq); + if (skb_dma_map(&pdev->dev, skb, DMA_TO_DEVICE)) { + dev_err(&pdev->dev, "TX DMA mapping failed\n"); + return 0; + } + if (skb->len > skb->data_len) { int len = skb->len - skb->data_len; - busaddr = pci_map_single(pdev, skb->data, len, - PCI_DMA_TODEVICE); wrb = queue_head_node(txq); + busaddr = skb_shinfo(skb)->dma_head; wrb_fill(wrb, busaddr, len); be_dws_cpu_to_le(wrb, sizeof(*wrb)); queue_head_inc(txq); @@ -403,9 +407,8 @@ static int make_tx_wrbs(struct be_adapter *adapter, for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; - busaddr = pci_map_page(pdev, frag->page, - frag->page_offset, - frag->size, PCI_DMA_TODEVICE); + + busaddr = skb_shinfo(skb)->dma_maps[i]; wrb = queue_head_node(txq); wrb_fill(wrb, busaddr, frag->size); be_dws_cpu_to_le(wrb, sizeof(*wrb)); @@ -429,6 +432,7 @@ static int make_tx_wrbs(struct be_adapter *adapter, static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) + { struct be_adapter *adapter = netdev_priv(netdev); struct be_tx_obj *tx_obj = &adapter->tx_obj; @@ -440,23 +444,28 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, wrb_cnt = wrb_cnt_for_skb(skb, &dummy_wrb); copied = make_tx_wrbs(adapter, skb, wrb_cnt, dummy_wrb); + if (copied) { + /* record the sent skb in the sent_skb table */ + BUG_ON(tx_obj->sent_skb_list[start]); + tx_obj->sent_skb_list[start] = skb; + + /* Ensure txq has space for the next skb; Else stop the queue + * *BEFORE* ringing the tx doorbell, so that we serialze the + * tx compls of the current transmit which'll wake up the queue + */ + if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >= + txq->len) { + netif_stop_queue(netdev); + stopped = true; + } - /* record the sent skb in the sent_skb table */ - BUG_ON(tx_obj->sent_skb_list[start]); - tx_obj->sent_skb_list[start] = skb; + be_txq_notify(adapter, txq->id, wrb_cnt); - /* Ensure that txq has space for the next skb; Else stop the queue - * *BEFORE* ringing the tx doorbell, so that we serialze the - * tx compls of the current transmit which'll wake up the queue - */ - if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >= txq->len) { - netif_stop_queue(netdev); - stopped = true; + be_tx_stats_update(adapter, wrb_cnt, copied, stopped); + } else { + txq->head = start; + dev_kfree_skb_any(skb); } - - be_txq_notify(adapter, txq->id, wrb_cnt); - - be_tx_stats_update(adapter, wrb_cnt, copied, stopped); return NETDEV_TX_OK; } @@ -958,10 +967,8 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) { struct be_queue_info *txq = &adapter->tx_obj.q; - struct be_eth_wrb *wrb; struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; struct sk_buff *sent_skb; - u64 busaddr; u16 cur_index, num_wrbs = 0; cur_index = txq->tail; @@ -971,19 +978,12 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) do { cur_index = txq->tail; - wrb = queue_tail_node(txq); - be_dws_le_to_cpu(wrb, sizeof(*wrb)); - busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo; - if (busaddr != 0) { - pci_unmap_single(adapter->pdev, busaddr, - wrb->frag_len, PCI_DMA_TODEVICE); - } num_wrbs++; queue_tail_inc(txq); } while (cur_index != last_index); atomic_sub(num_wrbs, &txq->used); - + skb_dma_unmap(&adapter->pdev->dev, sent_skb, DMA_TO_DEVICE); kfree_skb(sent_skb); } @@ -1892,6 +1892,8 @@ static void be_netdev_init(struct net_device *netdev) adapter->rx_csum = true; + netif_set_gso_max_size(netdev, 65535); + BE_SET_NETDEV_OPS(netdev, &be_netdev_ops); SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); -- cgit v0.10.2 From 32e6a0c82e7a7991a02414d830f262e1f4db73e6 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Sat, 5 Sep 2009 00:54:30 +0000 Subject: WAN: remove deprecated PCI_DEVICE_ID from PCI200SYN driver. PCI200SYN has its own PCI subsystem device ID for 3+ years, now it's time to remove the generic PLX905[02] ID from the driver. Anyone with old EEPROM data will have to run the upgrade. Having the generic PLX905[02] (PCI-local bus bridge) ID is harmful as the driver tries to handle other devices based on these bridges. Signed-off-by: Krzysztof Halasa Signed-off-by: David S. Miller diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index e035d8c..a52f29c 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c @@ -360,15 +360,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, " %u RX packets rings\n", ramsize / 1024, ramphys, pdev->irq, card->tx_ring_buffers, card->rx_ring_buffers); - if (pdev->subsystem_device == PCI_DEVICE_ID_PLX_9050) { - printk(KERN_ERR "Detected PCI200SYN card with old " - "configuration data.\n"); - printk(KERN_ERR "See for update.\n"); - printk(KERN_ERR "The card will stop working with" - " future versions of Linux if not updated.\n"); - } - if (card->tx_ring_buffers < 1) { printk(KERN_ERR "pci200syn: RAM test failed\n"); pci200_pci_remove_one(pdev); @@ -427,8 +418,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, static struct pci_device_id pci200_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX, - PCI_DEVICE_ID_PLX_9050, 0, 0, 0 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_PCI200SYN, 0, 0, 0 }, { 0, } }; -- cgit v0.10.2 From 5dbc46506a4f7b9f564bb7589a49ed32bc1caa15 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Sat, 5 Sep 2009 03:59:49 +0000 Subject: IXP42x HSS support for setting internal clock rate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HSS usually uses external clocks, so it's not a big deal. Internal clock is used for direct DTE-DTE connections and when the DCE doesn't provide it's own clock. This also depends on the oscillator frequency. Intel seems to have calculated the clock register settings for 33.33 MHz (66.66 MHz timer base). Their settings seem quite suboptimal both in terms of average frequency (60 ppm is unacceptable for G.703 applications, their primary intended usage(?)) and jitter. Many (most?) platforms use a 33.333 MHz oscillator, a 10 ppm difference from Intel's base. Instead of creating static tables, I've created a procedure to program the HSS clock register. The register consists of 3 parts (A, B, C). The average frequency (= bit rate) is: 66.66x MHz / (A + (B + 1) / (C + 1)) The procedure aims at the closest average frequency, possibly at the cost of increased jitter. Nobody would be able to directly drive an unbufferred transmitter with a HSS anyway, and the frequency error is what it really counts. I've verified the above with an oscilloscope on IXP425. It seems IXP46x and possibly IXP43x use a bit different clock generation algorithm - it looks like the avg frequency is: (on IXP465) 66.66x MHz / (A + B / (C + 1)). Also they use much greater precomputed A and B - on IXP425 it would simply result in more jitter, but I don't know how does it work on IXP46x (perhaps 3 least significant bits aren't used?). Anyway it looks that they were aiming for exactly +60 ppm or -60 ppm, while <1 ppm is typically possible (with a synchronized clock, of course). The attached patch makes it possible to set almost any bit rate (my IXP425 533 MHz quits at > 22 Mb/s if a single port is used, and the minimum is ca. 65 Kb/s). This is independent of MVIP (multi-E1/T1 on one HSS) mode. Signed-off-by: Krzysztof Hałasa Signed-off-by: David S. Miller diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 1e93dfe..5083f03 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -416,6 +416,7 @@ static struct clocksource clocksource_ixp4xx = { }; unsigned long ixp4xx_timer_freq = FREQ; +EXPORT_SYMBOL(ixp4xx_timer_freq); static int __init ixp4xx_clocksource_init(void) { clocksource_ixp4xx.mult = diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index bb719b6..c705046 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -166,6 +166,29 @@ #define CLK46X_SPEED_4096KHZ (( 16 << 22) | (280 << 12) | 1023) #define CLK46X_SPEED_8192KHZ (( 8 << 22) | (280 << 12) | 2047) +/* + * HSS_CONFIG_CLOCK_CR register consists of 3 parts: + * A (10 bits), B (10 bits) and C (12 bits). + * IXP42x HSS clock generator operation (verified with an oscilloscope): + * Each clock bit takes 7.5 ns (1 / 133.xx MHz). + * The clock sequence consists of (C - B) states of 0s and 1s, each state is + * A bits wide. It's followed by (B + 1) states of 0s and 1s, each state is + * (A + 1) bits wide. + * + * The resulting average clock frequency (assuming 33.333 MHz oscillator) is: + * freq = 66.666 MHz / (A + (B + 1) / (C + 1)) + * minumum freq = 66.666 MHz / (A + 1) + * maximum freq = 66.666 MHz / A + * + * Example: A = 2, B = 2, C = 7, CLOCK_CR register = 2 << 22 | 2 << 12 | 7 + * freq = 66.666 MHz / (2 + (2 + 1) / (7 + 1)) = 28.07 MHz (Mb/s). + * The clock sequence is: 1100110011 (5 doubles) 000111000 (3 triples). + * The sequence takes (C - B) * A + (B + 1) * (A + 1) = 5 * 2 + 3 * 3 bits + * = 19 bits (each 7.5 ns long) = 142.5 ns (then the sequence repeats). + * The sequence consists of 4 complete clock periods, thus the average + * frequency (= clock rate) is 4 / 142.5 ns = 28.07 MHz (Mb/s). + * (max specified clock rate for IXP42x HSS is 8.192 Mb/s). + */ /* hss_config, LUT entries */ #define TDMMAP_UNASSIGNED 0 @@ -239,6 +262,7 @@ struct port { unsigned int clock_type, clock_rate, loopback; unsigned int initialized, carrier; u8 hdlc_cfg; + u32 clock_reg; }; /* NPE message structure */ @@ -393,7 +417,7 @@ static void hss_config(struct port *port) msg.cmd = PORT_CONFIG_WRITE; msg.hss_port = port->id; msg.index = HSS_CONFIG_CLOCK_CR; - msg.data32 = CLK42X_SPEED_2048KHZ /* FIXME */; + msg.data32 = port->clock_reg; hss_npe_send(port, &msg, "HSS_SET_CLOCK_CR"); memset(&msg, 0, sizeof(msg)); @@ -1160,6 +1184,62 @@ static int hss_hdlc_attach(struct net_device *dev, unsigned short encoding, } } +static u32 check_clock(u32 rate, u32 a, u32 b, u32 c, + u32 *best, u32 *best_diff, u32 *reg) +{ + /* a is 10-bit, b is 10-bit, c is 12-bit */ + u64 new_rate; + u32 new_diff; + + new_rate = ixp4xx_timer_freq * (u64)(c + 1); + do_div(new_rate, a * (c + 1) + b + 1); + new_diff = abs((u32)new_rate - rate); + + if (new_diff < *best_diff) { + *best = new_rate; + *best_diff = new_diff; + *reg = (a << 22) | (b << 12) | c; + } + return new_diff; +} + +static void find_best_clock(u32 rate, u32 *best, u32 *reg) +{ + u32 a, b, diff = 0xFFFFFFFF; + + a = ixp4xx_timer_freq / rate; + + if (a > 0x3FF) { /* 10-bit value - we can go as slow as ca. 65 kb/s */ + check_clock(rate, 0x3FF, 1, 1, best, &diff, reg); + return; + } + if (a == 0) { /* > 66.666 MHz */ + a = 1; /* minimum divider is 1 (a = 0, b = 1, c = 1) */ + rate = ixp4xx_timer_freq; + } + + if (rate * a == ixp4xx_timer_freq) { /* don't divide by 0 later */ + check_clock(rate, a - 1, 1, 1, best, &diff, reg); + return; + } + + for (b = 0; b < 0x400; b++) { + u64 c = (b + 1) * (u64)rate; + do_div(c, ixp4xx_timer_freq - rate * a); + c--; + if (c >= 0xFFF) { /* 12-bit - no need to check more 'b's */ + if (b == 0 && /* also try a bit higher rate */ + !check_clock(rate, a - 1, 1, 1, best, &diff, reg)) + return; + check_clock(rate, a, b, 0xFFF, best, &diff, reg); + return; + } + if (!check_clock(rate, a, b, c, best, &diff, reg)) + return; + if (!check_clock(rate, a, b, c + 1, best, &diff, reg)) + return; + } +} static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { @@ -1182,7 +1262,7 @@ static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } memset(&new_line, 0, sizeof(new_line)); new_line.clock_type = port->clock_type; - new_line.clock_rate = 2048000; /* FIXME */ + new_line.clock_rate = port->clock_rate; new_line.loopback = port->loopback; if (copy_to_user(line, &new_line, size)) return -EFAULT; @@ -1206,7 +1286,13 @@ static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; port->clock_type = clk; /* Update settings */ - /* FIXME port->clock_rate = new_line.clock_rate */; + if (clk == CLOCK_INT) + find_best_clock(new_line.clock_rate, &port->clock_rate, + &port->clock_reg); + else { + port->clock_rate = 0; + port->clock_reg = CLK42X_SPEED_2048KHZ; + } port->loopback = new_line.loopback; spin_lock_irqsave(&npe_lock, flags); @@ -1266,7 +1352,8 @@ static int __devinit hss_init_one(struct platform_device *pdev) dev->netdev_ops = &hss_hdlc_ops; dev->tx_queue_len = 100; port->clock_type = CLOCK_EXT; - port->clock_rate = 2048000; + port->clock_rate = 0; + port->clock_reg = CLK42X_SPEED_2048KHZ; port->id = pdev->id; port->dev = &pdev->dev; port->plat = pdev->dev.platform_data; -- cgit v0.10.2 From cf33ce15463b784a1d648905fc067fa4d6b17466 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 4 Sep 2009 14:20:37 +0000 Subject: net: fix hydra printk format warning m68k: drivers/net/hydra.c:178: warning: format '%08lx' expects type 'long unsigned int', but argument 3 has type 'resource_size_t' Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index 8ac0930..d496b6f 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -173,9 +173,9 @@ static int __devinit hydra_init(struct zorro_dev *z) zorro_set_drvdata(z, dev); - printk(KERN_INFO "%s: Hydra at 0x%08lx, address " + printk(KERN_INFO "%s: Hydra at 0x%08llx, address " "%pM (hydra.c " HYDRA_VERSION ")\n", - dev->name, z->resource.start, dev->dev_addr); + dev->name, (unsigned long long)z->resource.start, dev->dev_addr); return 0; } -- cgit v0.10.2 From 3a5f29c1dbe5814349efacdea483079c470dcc38 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 7 Sep 2009 02:03:37 -0700 Subject: r8169: Fix warning in rtl8169_start_xmit(). Reported by Stephen Rothwell: drivers/net/r8169.c: In function 'rtl8169_start_xmit': drivers/net/r8169.c:3421: warning: label 'out' defined but not used Introduced by commit 61357325f377889a1daffa14962d705dc814dd0e ("netdev: convert bulk of drivers to netdev_tx_t"). Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index a91e9b3..50c6a3c 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3416,7 +3416,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, netif_wake_queue(dev); } -out: return NETDEV_TX_OK; err_stop: -- cgit v0.10.2 From f1bc07af9a9edc5c1d4bdd971f7099316ed2e405 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 7 Sep 2009 10:18:54 +0200 Subject: sound: oxygen: work around MCE when changing volume When the volume is changed continuously (e.g., when the user drags a volume slider with the mouse), the driver does lots of I2C writes. Apparently, the sound chip can get confused when we poll the I2C status register too much, and fails to complete a read from it. On the PCI-E models, the PCI-E/PCI bridge gets upset by this and generates a machine check exception. To avoid this, this patch replaces the polling with an unconditional wait that is guaranteed to be long enough. Signed-off-by: Clemens Ladisch Tested-by: Johann Messner Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c index c1eb923..09b2b2a 100644 --- a/sound/pci/oxygen/oxygen_io.c +++ b/sound/pci/oxygen/oxygen_io.c @@ -215,17 +215,8 @@ EXPORT_SYMBOL(oxygen_write_spi); void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data) { - unsigned long timeout; - /* should not need more than about 300 us */ - timeout = jiffies + msecs_to_jiffies(1); - do { - if (!(oxygen_read16(chip, OXYGEN_2WIRE_BUS_STATUS) - & OXYGEN_2WIRE_BUSY)) - break; - udelay(1); - cond_resched(); - } while (time_after_eq(timeout, jiffies)); + msleep(1); oxygen_write8(chip, OXYGEN_2WIRE_MAP, map); oxygen_write8(chip, OXYGEN_2WIRE_DATA, data); -- cgit v0.10.2 From 236cc52856f6ebe47f52d50ba5431b0e172fd0d1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 7 Sep 2009 12:46:42 +0100 Subject: ASoC: Remove unuused hw_read_t Signed-off-by: Mark Brown diff --git a/include/sound/soc.h b/include/sound/soc.h index 0758a1b..475cb7e 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -205,7 +205,6 @@ struct snd_soc_jack_gpio; #endif typedef int (*hw_write_t)(void *,const char* ,int); -typedef int (*hw_read_t)(void *,char* ,int); extern struct snd_ac97_bus_ops soc_ac97_ops; -- cgit v0.10.2 From be1d6a5f55b30042c57bdfbe7cb4761ed081def0 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 7 Sep 2009 13:24:17 +0100 Subject: KEYS: Fix default security_session_to_parent() Fix the default security_session_to_parent() in linux/security.h to have a body. Signed-off-by: David Howells Signed-off-by: James Morris diff --git a/include/linux/security.h b/include/linux/security.h index f4eb32d..10a0925 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -2988,7 +2988,10 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer) static inline int security_key_session_to_parent(const struct cred *cred, const struct cred *parent_cred, - struct key *key); + struct key *key) +{ + return 0; +} #endif #endif /* CONFIG_KEYS */ -- cgit v0.10.2 From 82a783f4bcb878e6c4f02e24c7cd0687bdea7443 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 7 Sep 2009 15:50:18 +0200 Subject: ALSA: Remove struct snd_monitor_file from public sound/core.h The struct snd_monitor_file is used locally only in sound/core/init.c, thus it should be moved there from the public sound/core.h. Signed-off-by: Takashi Iwai diff --git a/include/sound/core.h b/include/sound/core.h index 309cb96..3bb07bc 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -93,15 +93,6 @@ struct snd_device { #define snd_device(n) list_entry(n, struct snd_device, list) -/* monitor files for graceful shutdown (hotplug) */ - -struct snd_monitor_file { - struct file *file; - const struct file_operations *disconnected_f_op; - struct list_head shutdown_list; /* still need to shutdown */ - struct list_head list; /* link of monitor files */ -}; - /* main structure for soundcard */ struct snd_card { diff --git a/sound/core/init.c b/sound/core/init.c index d5d40d7..ec4a50c 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -31,6 +31,14 @@ #include #include +/* monitor files for graceful shutdown (hotplug) */ +struct snd_monitor_file { + struct file *file; + const struct file_operations *disconnected_f_op; + struct list_head shutdown_list; /* still need to shutdown */ + struct list_head list; /* link of monitor files */ +}; + static DEFINE_SPINLOCK(shutdown_lock); static LIST_HEAD(shutdown_files); -- cgit v0.10.2 From b8c60ede6abf8e96a892c114131700b0cfb0be89 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 7 Sep 2009 15:52:30 +0200 Subject: ALSA: Remove unneeded ifdef from sound/core.h Remove the old hack that was needed for building alsa-driver modules externally for old kernels. Signed-off-by: Takashi Iwai diff --git a/include/sound/core.h b/include/sound/core.h index 3bb07bc..f545efc 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -302,9 +302,7 @@ int snd_component_add(struct snd_card *card, const char *component); int snd_card_file_add(struct snd_card *card, struct file *file); int snd_card_file_remove(struct snd_card *card, struct file *file); -#ifndef snd_card_set_dev #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr)) -#endif /* device.c */ @@ -429,12 +427,10 @@ static inline int __snd_bug_on(int cond) /* for easier backward-porting */ #if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE) -#ifndef gameport_set_dev_parent #define gameport_set_dev_parent(gp,xdev) ((gp)->dev.parent = (xdev)) #define gameport_set_port_data(gp,r) ((gp)->port_data = (r)) #define gameport_get_port_data(gp) (gp)->port_data #endif -#endif /* PCI quirk list helper */ struct snd_pci_quirk { -- cgit v0.10.2 From 6b2eef8fd78ff909c3396b8671d57c42559cc51d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 7 Sep 2009 08:27:50 -0700 Subject: IB/mad: Fix possible lock-lock-timer deadlock Lockdep reported a possible deadlock with cm_id_priv->lock, mad_agent_priv->lock and mad_agent_priv->timed_work.timer; this happens because the mad module does cancel_delayed_work(&mad_agent_priv->timed_work); while holding mad_agent_priv->lock. cancel_delayed_work() internally does del_timer_sync(&mad_agent_priv->timed_work.timer). This can turn into a deadlock because mad_agent_priv->lock is taken inside cm_id_priv->lock, so we can get the following set of contexts that deadlock each other: A: holding cm_id_priv->lock, waiting for mad_agent_priv->lock B: holding mad_agent_priv->lock, waiting for del_timer_sync() C: interrupt during mad_agent_priv->timed_work.timer that takes cm_id_priv->lock Fix this by using the new __cancel_delayed_work() interface (which internally does del_timer() instead of del_timer_sync()) in all the places where we are holding a lock. Addresses: http://bugzilla.kernel.org/show_bug.cgi?id=13757 Reported-by: Bart Van Assche Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index de922a0..bc30c00 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1974,7 +1974,7 @@ static void adjust_timeout(struct ib_mad_agent_private *mad_agent_priv) unsigned long delay; if (list_empty(&mad_agent_priv->wait_list)) { - cancel_delayed_work(&mad_agent_priv->timed_work); + __cancel_delayed_work(&mad_agent_priv->timed_work); } else { mad_send_wr = list_entry(mad_agent_priv->wait_list.next, struct ib_mad_send_wr_private, @@ -1983,7 +1983,7 @@ static void adjust_timeout(struct ib_mad_agent_private *mad_agent_priv) if (time_after(mad_agent_priv->timeout, mad_send_wr->timeout)) { mad_agent_priv->timeout = mad_send_wr->timeout; - cancel_delayed_work(&mad_agent_priv->timed_work); + __cancel_delayed_work(&mad_agent_priv->timed_work); delay = mad_send_wr->timeout - jiffies; if ((long)delay <= 0) delay = 1; @@ -2023,7 +2023,7 @@ static void wait_for_response(struct ib_mad_send_wr_private *mad_send_wr) /* Reschedule a work item if we have a shorter timeout */ if (mad_agent_priv->wait_list.next == &mad_send_wr->agent_list) { - cancel_delayed_work(&mad_agent_priv->timed_work); + __cancel_delayed_work(&mad_agent_priv->timed_work); queue_delayed_work(mad_agent_priv->qp_info->port_priv->wq, &mad_agent_priv->timed_work, delay); } -- cgit v0.10.2 From b76aabc3956e9b95e7b7dc1aeecb8c6caf57f74c Mon Sep 17 00:00:00 2001 From: Hal Rosenstock Date: Mon, 7 Sep 2009 08:28:48 -0700 Subject: IB/mad: Allow tuning of QP0 and QP1 sizes MADs are UD and can be dropped if there are no receives posted, so allow receive queue size to be set with a module parameter in case the queue needs to be lengthened. Send side tuning is done for symmetry with receive. Signed-off-by: Hal Rosenstock Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index bc30c00..0f7da24 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -2,6 +2,7 @@ * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. * Copyright (c) 2005 Intel Corporation. All rights reserved. * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -45,6 +46,14 @@ MODULE_DESCRIPTION("kernel IB MAD API"); MODULE_AUTHOR("Hal Rosenstock"); MODULE_AUTHOR("Sean Hefty"); +int mad_sendq_size = IB_MAD_QP_SEND_SIZE; +int mad_recvq_size = IB_MAD_QP_RECV_SIZE; + +module_param_named(send_queue_size, mad_sendq_size, int, 0444); +MODULE_PARM_DESC(send_queue_size, "Size of send queue in number of work requests"); +module_param_named(recv_queue_size, mad_recvq_size, int, 0444); +MODULE_PARM_DESC(recv_queue_size, "Size of receive queue in number of work requests"); + static struct kmem_cache *ib_mad_cache; static struct list_head ib_mad_port_list; @@ -2736,8 +2745,8 @@ static int create_mad_qp(struct ib_mad_qp_info *qp_info, qp_init_attr.send_cq = qp_info->port_priv->cq; qp_init_attr.recv_cq = qp_info->port_priv->cq; qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; - qp_init_attr.cap.max_send_wr = IB_MAD_QP_SEND_SIZE; - qp_init_attr.cap.max_recv_wr = IB_MAD_QP_RECV_SIZE; + qp_init_attr.cap.max_send_wr = mad_sendq_size; + qp_init_attr.cap.max_recv_wr = mad_recvq_size; qp_init_attr.cap.max_send_sge = IB_MAD_SEND_REQ_MAX_SG; qp_init_attr.cap.max_recv_sge = IB_MAD_RECV_REQ_MAX_SG; qp_init_attr.qp_type = qp_type; @@ -2752,8 +2761,8 @@ static int create_mad_qp(struct ib_mad_qp_info *qp_info, goto error; } /* Use minimum queue sizes unless the CQ is resized */ - qp_info->send_queue.max_active = IB_MAD_QP_SEND_SIZE; - qp_info->recv_queue.max_active = IB_MAD_QP_RECV_SIZE; + qp_info->send_queue.max_active = mad_sendq_size; + qp_info->recv_queue.max_active = mad_recvq_size; return 0; error: @@ -2792,7 +2801,7 @@ static int ib_mad_port_open(struct ib_device *device, init_mad_qp(port_priv, &port_priv->qp_info[0]); init_mad_qp(port_priv, &port_priv->qp_info[1]); - cq_size = (IB_MAD_QP_SEND_SIZE + IB_MAD_QP_RECV_SIZE) * 2; + cq_size = (mad_sendq_size + mad_recvq_size) * 2; port_priv->cq = ib_create_cq(port_priv->device, ib_mad_thread_completion_handler, NULL, port_priv, cq_size, 0); @@ -2984,6 +2993,12 @@ static int __init ib_mad_init_module(void) { int ret; + mad_recvq_size = min(mad_recvq_size, IB_MAD_QP_MAX_SIZE); + mad_recvq_size = max(mad_recvq_size, IB_MAD_QP_MIN_SIZE); + + mad_sendq_size = min(mad_sendq_size, IB_MAD_QP_MAX_SIZE); + mad_sendq_size = max(mad_sendq_size, IB_MAD_QP_MIN_SIZE); + spin_lock_init(&ib_mad_port_list_lock); ib_mad_cache = kmem_cache_create("ib_mad", diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index 05ce331..9430ab4 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -2,6 +2,7 @@ * Copyright (c) 2004, 2005, Voltaire, Inc. All rights reserved. * Copyright (c) 2005 Intel Corporation. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -49,6 +50,8 @@ /* QP and CQ parameters */ #define IB_MAD_QP_SEND_SIZE 128 #define IB_MAD_QP_RECV_SIZE 512 +#define IB_MAD_QP_MIN_SIZE 64 +#define IB_MAD_QP_MAX_SIZE 8192 #define IB_MAD_SEND_REQ_MAX_SG 2 #define IB_MAD_RECV_REQ_MAX_SG 1 -- cgit v0.10.2 From 87831cb660954356d68cebdb1406f3be09e784e9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 7 Sep 2009 18:09:58 +0100 Subject: ASoC: Fix WM835x Out4 capture enumeration It's the 8th enum of a zero indexed array. This is why I don't let new drivers use these arrays of enums... Signed-off-by: Mark Brown Cc: stable@kernel.org diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 71c9c4b..3ff0373 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -612,7 +612,7 @@ SOC_DAPM_SINGLE("Switch", WM8350_BEEP_VOLUME, 15, 1, 1); /* Out4 Capture Mux */ static const struct snd_kcontrol_new wm8350_out4_capture_controls = -SOC_DAPM_ENUM("Route", wm8350_enum[8]); +SOC_DAPM_ENUM("Route", wm8350_enum[7]); static const struct snd_soc_dapm_widget wm8350_dapm_widgets[] = { -- cgit v0.10.2 From cdd2ab3de4301728b20efd6225681d3ff591a938 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 7 Sep 2009 18:12:06 +0200 Subject: sched: Remove short cut from select_task_rq_fair() select_task_rq_fair() incorrectly skips the wake_affine() logic, remove this. When prev_cpu == this_cpu, the code jumps straight to the wake_idle() logic, this doesn't give the wake_affine() logic the chance to pin the task to this cpu. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 2ff850f..d7fda41 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1305,8 +1305,6 @@ static int select_task_rq_fair(struct task_struct *p, int sync) this_rq = cpu_rq(this_cpu); new_cpu = prev_cpu; - if (prev_cpu == this_cpu) - goto out; /* * 'this_sd' is the first domain that both * this_cpu and prev_cpu are present in: -- cgit v0.10.2 From 71a29aa7b600595d0ef373ea605ac656876d1f2f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 7 Sep 2009 18:28:05 +0200 Subject: sched: Deal with low-load in wake_affine() wake_affine() would always fail under low-load situations where both prev and this were idle, because adding a single task will always be a significant imbalance, even if there's nothing around that could balance it. Deal with this by allowing imbalance when there's nothing you can do about it. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index d7fda41..cc97ea4 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1262,7 +1262,17 @@ wake_affine(struct sched_domain *this_sd, struct rq *this_rq, tg = task_group(p); weight = p->se.load.weight; - balanced = 100*(tl + effective_load(tg, this_cpu, weight, weight)) <= + /* + * In low-load situations, where prev_cpu is idle and this_cpu is idle + * due to the sync cause above having dropped tl to 0, we'll always have + * an imbalance, but there's really nothing you can do about that, so + * that's good too. + * + * Otherwise check if either cpus are near enough in load to allow this + * task to be woken on this_cpu. + */ + balanced = !tl || + 100*(tl + effective_load(tg, this_cpu, weight, weight)) <= imbalance*(load + effective_load(tg, prev_cpu, 0, weight)); /* -- cgit v0.10.2 From a8fae3ec5f118dc92517dcbed3ecf69ddb641d0f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 7 Sep 2009 18:32:32 +0200 Subject: sched: enable SD_WAKE_IDLE Now that SD_WAKE_IDLE doesn't make pipe-test suck anymore, enable it by default for MC, CPU and NUMA domains. Signed-off-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index ef7bc7f..26d06e0 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -152,7 +152,7 @@ extern unsigned long node_remap_size[]; | 0*SD_POWERSAVINGS_BALANCE \ | 0*SD_SHARE_PKG_RESOURCES \ | 1*SD_SERIALIZE \ - | 0*SD_WAKE_IDLE_FAR \ + | 1*SD_WAKE_IDLE_FAR \ | 0*SD_PREFER_SIBLING \ , \ .last_balance = jiffies, \ diff --git a/include/linux/topology.h b/include/linux/topology.h index 66774fd..85e8cf7 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -129,7 +129,7 @@ int arch_update_cpu_topology(void); | 1*SD_BALANCE_NEWIDLE \ | 1*SD_BALANCE_EXEC \ | 1*SD_BALANCE_FORK \ - | 0*SD_WAKE_IDLE \ + | 1*SD_WAKE_IDLE \ | 1*SD_WAKE_AFFINE \ | 1*SD_WAKE_BALANCE \ | 0*SD_SHARE_CPUPOWER \ @@ -163,7 +163,7 @@ int arch_update_cpu_topology(void); | 1*SD_BALANCE_NEWIDLE \ | 1*SD_BALANCE_EXEC \ | 1*SD_BALANCE_FORK \ - | 0*SD_WAKE_IDLE \ + | 1*SD_WAKE_IDLE \ | 0*SD_WAKE_AFFINE \ | 1*SD_WAKE_BALANCE \ | 0*SD_SHARE_CPUPOWER \ @@ -198,7 +198,7 @@ int arch_update_cpu_topology(void); | 0*SD_POWERSAVINGS_BALANCE \ | 0*SD_SHARE_PKG_RESOURCES \ | 1*SD_SERIALIZE \ - | 0*SD_WAKE_IDLE_FAR \ + | 1*SD_WAKE_IDLE_FAR \ | 0*SD_PREFER_SIBLING \ , \ .last_balance = jiffies, \ -- cgit v0.10.2 From e6cc0fd1e31cfe48e207de78742ccdf301369bf3 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 7 Sep 2009 21:54:38 -0700 Subject: MAINTAINERS: InfiniBand/RDMA mailing list transition to vger InfiniBand/RDMA development discussion is moving from general@lists.openfabrics.org to linux-rdma@vger.kernel.org. Signed-off-by: Roland Dreier diff --git a/MAINTAINERS b/MAINTAINERS index 8dca9d8..989ff11 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -439,7 +439,7 @@ F: drivers/hwmon/ams/ AMSO1100 RNIC DRIVER M: Tom Tucker M: Steve Wise -L: general@lists.openfabrics.org +L: linux-rdma@vger.kernel.org S: Maintained F: drivers/infiniband/hw/amso1100/ @@ -1494,7 +1494,7 @@ F: drivers/net/cxgb3/ CXGB3 IWARP RNIC DRIVER (IW_CXGB3) M: Steve Wise -L: general@lists.openfabrics.org +L: linux-rdma@vger.kernel.org W: http://www.openfabrics.org S: Supported F: drivers/infiniband/hw/cxgb3/ @@ -1868,7 +1868,7 @@ F: fs/efs/ EHCA (IBM GX bus InfiniBand adapter) DRIVER M: Hoang-Nam Nguyen M: Christoph Raisch -L: general@lists.openfabrics.org +L: linux-rdma@vger.kernel.org S: Supported F: drivers/infiniband/hw/ehca/ @@ -2552,7 +2552,7 @@ INFINIBAND SUBSYSTEM M: Roland Dreier M: Sean Hefty M: Hal Rosenstock -L: general@lists.openfabrics.org (moderated for non-subscribers) +L: linux-rdma@vger.kernel.org W: http://www.openib.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git S: Supported @@ -2729,7 +2729,7 @@ F: drivers/net/ipg.c IPATH DRIVER M: Ralph Campbell -L: general@lists.openfabrics.org +L: linux-rdma@vger.kernel.org T: git git://git.qlogic.com/ipath-linux-2.6 S: Supported F: drivers/infiniband/hw/ipath/ @@ -3485,7 +3485,7 @@ F: drivers/scsi/NCR_D700.* NETEFFECT IWARP RNIC DRIVER (IW_NES) M: Faisal Latif M: Chien Tung -L: general@lists.openfabrics.org +L: linux-rdma@vger.kernel.org W: http://www.neteffect.com S: Supported F: drivers/infiniband/hw/nes/ -- cgit v0.10.2 From 6148b130eb84edc76e4fa88da1877b27be6c2f06 Mon Sep 17 00:00:00 2001 From: Sophie Hamilton Date: Tue, 8 Sep 2009 10:58:42 +0200 Subject: ALSA: cs46xx - Fix minimum period size Fix minimum period size for cs46xx cards. This fixes a problem in the case where neither a period size nor a buffer size is passed to ALSA; this is the case in Audacious, OpenAL, and others. Signed-off-by: Sophie Hamilton Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h index 4eb55aa..b518949 100644 --- a/sound/pci/cs46xx/cs46xx_lib.h +++ b/sound/pci/cs46xx/cs46xx_lib.h @@ -35,7 +35,7 @@ #ifdef CONFIG_SND_CS46XX_NEW_DSP -#define CS46XX_MIN_PERIOD_SIZE 1 +#define CS46XX_MIN_PERIOD_SIZE 64 #define CS46XX_MAX_PERIOD_SIZE 1024*1024 #else #define CS46XX_MIN_PERIOD_SIZE 2048 -- cgit v0.10.2 From 33d78674586aeb6a623b1e612e6f92dd83015ed3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Sep 2009 11:03:41 +0200 Subject: ALSA: hda - Use auto model for HP laptops with ALC268 codec The HP laptops with ALC268 codec seem working better with model=auto than model=toshiba; e.g. the auto model fixes missing digital outputs. Let's fix quirk entry to choose auto model explicitly. Tested-by: Jens Jorgensen Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e58d4c5d..7ed47f6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -12574,8 +12574,11 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { ALC268_ACER_ASPIRE_ONE), SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL), + /* almost compatible with toshiba but with optional digital outs; + * auto-probing seems working fine + */ SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series", - ALC268_TOSHIBA), + ALC268_AUTO), SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), -- cgit v0.10.2 From b5d9d734a53e0204aab0089079cbde2a1285a38f Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Tue, 8 Sep 2009 11:12:28 +0200 Subject: sched: Ensure that a child can't gain time over it's parent after fork() A fork/exec load is usually "pass the baton", so the child should never be placed behind the parent. With START_DEBIT we make room for the new task, but with child_runs_first, that room comes out of the _parent's_ hide. There's nothing to say that the parent wasn't ahead of min_vruntime at fork() time, which means that the "baton carrier", who is essentially the parent in drag, can gain time and increase scheduling latencies for waiters. With NEW_FAIR_SLEEPERS + START_DEBIT + child_runs_first enabled, we essentially pass the sleeper fairness off to the child, which is fine, but if we don't base placement on the parent's updated vruntime, we can end up compounding latency woes if the child itself then does fork/exec. The debit incurred at fork doesn't hurt the parent who is then going to sleep and maybe exit, but the child who acquires the error harms all comers. This improves latencies of make -j kernel build workloads. Reported-by: Jens Axboe Signed-off-by: Mike Galbraith Acked-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index cc97ea4..e386e5d 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -728,11 +728,11 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial) vruntime -= thresh; } - - /* ensure we never gain time by being placed backwards. */ - vruntime = max_vruntime(se->vruntime, vruntime); } + /* ensure we never gain time by being placed backwards. */ + vruntime = max_vruntime(se->vruntime, vruntime); + se->vruntime = vruntime; } @@ -1756,6 +1756,8 @@ static void task_new_fair(struct rq *rq, struct task_struct *p) sched_info_queued(p); update_curr(cfs_rq); + if (curr) + se->vruntime = curr->vruntime; place_entity(cfs_rq, se, 1); /* 'curr' will be NULL if the child belongs to a different group */ -- cgit v0.10.2 From 6e5265ec34d3b9578973841ddec8b925e986136a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Sep 2009 14:26:51 +0200 Subject: ALSA: Re-export snd_pcm_format_name() function Re-export snd_pcm_format_name() function to be used outside the PCM core. As a first example, usbaudio is changed to use it now again. Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 2389352..4d5b240 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -965,4 +965,6 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) #define PCM_RUNTIME_CHECK(sub) snd_BUG_ON(!(sub) || !(sub)->runtime) +const char *snd_pcm_format_name(snd_pcm_format_t format); + #endif /* __SOUND_PCM_H */ diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 145931a..0c14401 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -162,18 +162,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card, return -ENOIOCTLCMD; } -#ifdef CONFIG_SND_VERBOSE_PROCFS - -#define STATE(v) [SNDRV_PCM_STATE_##v] = #v -#define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v -#define READY(v) [SNDRV_PCM_READY_##v] = #v -#define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v -#define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v -#define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v -#define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v -#define START(v) [SNDRV_PCM_START_##v] = #v #define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v -#define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v static char *snd_pcm_format_names[] = { FORMAT(S8), @@ -216,10 +205,23 @@ static char *snd_pcm_format_names[] = { FORMAT(U18_3BE), }; -static const char *snd_pcm_format_name(snd_pcm_format_t format) +const char *snd_pcm_format_name(snd_pcm_format_t format) { return snd_pcm_format_names[format]; } +EXPORT_SYMBOL_GPL(snd_pcm_format_name); + +#ifdef CONFIG_SND_VERBOSE_PROCFS + +#define STATE(v) [SNDRV_PCM_STATE_##v] = #v +#define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v +#define READY(v) [SNDRV_PCM_READY_##v] = #v +#define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v +#define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v +#define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v +#define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v +#define START(v) [SNDRV_PCM_START_##v] = #v +#define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v static char *snd_pcm_stream_names[] = { STREAM(PLAYBACK), diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 44b9cdc..3a53c79 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2124,8 +2124,8 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s fp = list_entry(p, struct audioformat, list); snd_iprintf(buffer, " Interface %d\n", fp->iface); snd_iprintf(buffer, " Altset %d\n", fp->altsetting); - snd_iprintf(buffer, " Format: %#x (%d bits)\n", - fp->format, snd_pcm_format_width(fp->format)); + snd_iprintf(buffer, " Format: %s\n", + snd_pcm_format_name(fp->format)); snd_iprintf(buffer, " Channels: %d\n", fp->channels); snd_iprintf(buffer, " Endpoint: %d %s (%s)\n", fp->endpoint & USB_ENDPOINT_NUMBER_MASK, -- cgit v0.10.2 From 4f7454a9970fa0f3e9f1a68201520e3df1bb5224 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Sep 2009 14:29:58 +0200 Subject: ALSA: Add const prefix to proc helper functions Add appropriate const prefix to char * arguments in proc helper functions. Also fixed the caller side to be proper const pointers. Signed-off-by: Takashi Iwai diff --git a/include/sound/info.h b/include/sound/info.h index 7c2ee1a2..112e894 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -110,13 +110,13 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer); static inline void snd_card_info_read_oss(struct snd_info_buffer *buffer) {} #endif -int snd_iprintf(struct snd_info_buffer *buffer, char *fmt, ...) \ +int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...) \ __attribute__ ((format (printf, 2, 3))); int snd_info_init(void); int snd_info_done(void); int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len); -char *snd_info_get_str(char *dest, char *src, int len); +const char *snd_info_get_str(char *dest, const char *src, int len); struct snd_info_entry *snd_info_create_module_entry(struct module *module, const char *name, struct snd_info_entry *parent); diff --git a/sound/core/info.c b/sound/core/info.c index 35df614..6eb5393 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -108,7 +108,7 @@ static int resize_info_buffer(struct snd_info_buffer *buffer, * * Returns the size of output string. */ -int snd_iprintf(struct snd_info_buffer *buffer, char *fmt,...) +int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...) { va_list args; int len, res; @@ -727,7 +727,7 @@ EXPORT_SYMBOL(snd_info_get_line); * Returns the updated pointer of the original string so that * it can be used for the next call. */ -char *snd_info_get_str(char *dest, char *src, int len) +const char *snd_info_get_str(char *dest, const char *src, int len) { int c; diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 5dcd8a5..7724238 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -1154,7 +1154,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_mixer_oss *mixer = entry->private_data; - char line[128], str[32], idxstr[16], *cptr; + char line[128], str[32], idxstr[16]; + const char *cptr; int ch, idx; struct snd_mixer_oss_assign_table *tbl; struct slot *slot; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index dbe406b..d8b2d76 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2836,7 +2836,8 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_pcm_str *pstr = entry->private_data; - char line[128], str[32], task_name[32], *ptr; + char line[128], str[32], task_name[32]; + const char *ptr; int idx1; struct snd_pcm_oss_setup *setup, *setup1, template; -- cgit v0.10.2 From 9b151fec139d32ab3acce5da5761d868e205fadd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Sep 2009 14:30:49 +0200 Subject: ALSA: dummy - Add debug proc file Added the debug proc file to see or change the snd_pcm_hardware fields to emulate. The parameters can be changed by writing to a proc file like: # echo periods_min 4 > /proc/asound/card1/dummy_pcm Signed-off-by: Takashi Iwai diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 2ee6c8e..ccfbdfa 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -33,6 +33,7 @@ #include #include #include +#include #include MODULE_AUTHOR("Jaroslav Kysela "); @@ -686,6 +687,10 @@ static int __devinit snd_card_dummy_pcm(struct snd_dummy *dummy, int device, return 0; } +/* + * mixer interface + */ + #define DUMMY_VOLUME(xname, xindex, addr) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ @@ -816,6 +821,131 @@ static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy) return 0; } +#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_PROC_FS) +/* + * proc interface + */ +static void print_formats(struct snd_info_buffer *buffer) +{ + int i; + + for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { + if (dummy_pcm_hardware.formats & (1ULL << i)) + snd_iprintf(buffer, " %s", snd_pcm_format_name(i)); + } +} + +static void print_rates(struct snd_info_buffer *buffer) +{ + static int rates[] = { + 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, + 64000, 88200, 96000, 176400, 192000, + }; + int i; + + if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_CONTINUOUS) + snd_iprintf(buffer, " continuous"); + if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_KNOT) + snd_iprintf(buffer, " knot"); + for (i = 0; i < ARRAY_SIZE(rates); i++) + if (dummy_pcm_hardware.rates & (1 << i)) + snd_iprintf(buffer, " %d", rates[i]); +} + +#define get_dummy_int_ptr(ofs) \ + (unsigned int *)((char *)&dummy_pcm_hardware + (ofs)) +#define get_dummy_ll_ptr(ofs) \ + (unsigned long long *)((char *)&dummy_pcm_hardware + (ofs)) + +struct dummy_hw_field { + const char *name; + const char *format; + unsigned int offset; + unsigned int size; +}; +#define FIELD_ENTRY(item, fmt) { \ + .name = #item, \ + .format = fmt, \ + .offset = offsetof(struct snd_pcm_hardware, item), \ + .size = sizeof(dummy_pcm_hardware.item) } + +static struct dummy_hw_field fields[] = { + FIELD_ENTRY(formats, "%#llx"), + FIELD_ENTRY(rates, "%#x"), + FIELD_ENTRY(rate_min, "%d"), + FIELD_ENTRY(rate_max, "%d"), + FIELD_ENTRY(channels_min, "%d"), + FIELD_ENTRY(channels_max, "%d"), + FIELD_ENTRY(buffer_bytes_max, "%ld"), + FIELD_ENTRY(period_bytes_min, "%ld"), + FIELD_ENTRY(period_bytes_max, "%ld"), + FIELD_ENTRY(periods_min, "%d"), + FIELD_ENTRY(periods_max, "%d"), +}; + +static void dummy_proc_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fields); i++) { + snd_iprintf(buffer, "%s ", fields[i].name); + if (fields[i].size == sizeof(int)) + snd_iprintf(buffer, fields[i].format, + *get_dummy_int_ptr(fields[i].offset)); + else + snd_iprintf(buffer, fields[i].format, + *get_dummy_ll_ptr(fields[i].offset)); + if (!strcmp(fields[i].name, "formats")) + print_formats(buffer); + else if (!strcmp(fields[i].name, "rates")) + print_rates(buffer); + snd_iprintf(buffer, "\n"); + } +} + +static void dummy_proc_write(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + char line[64]; + + while (!snd_info_get_line(buffer, line, sizeof(line))) { + char item[20]; + const char *ptr; + unsigned long long val; + int i; + + ptr = snd_info_get_str(item, line, sizeof(item)); + for (i = 0; i < ARRAY_SIZE(fields); i++) { + if (!strcmp(item, fields[i].name)) + break; + } + if (i >= ARRAY_SIZE(fields)) + continue; + snd_info_get_str(item, ptr, sizeof(item)); + if (strict_strtoull(item, 0, &val)) + continue; + if (fields[i].size == sizeof(int)) + *get_dummy_int_ptr(fields[i].offset) = val; + else + *get_dummy_ll_ptr(fields[i].offset) = val; + } +} + +static void __devinit dummy_proc_init(struct snd_dummy *chip) +{ + struct snd_info_entry *entry; + + if (!snd_card_proc_new(chip->card, "dummy_pcm", &entry)) { + snd_info_set_text_ops(entry, chip, dummy_proc_read); + entry->c.text.write = dummy_proc_write; + entry->mode |= S_IWUSR; + } +} +#else +#define dummy_proc_init(x) +#endif /* CONFIG_SND_DEBUG && CONFIG_PROC_FS */ + static int __devinit snd_dummy_probe(struct platform_device *devptr) { struct snd_card *card; @@ -845,6 +975,8 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) strcpy(card->shortname, "Dummy"); sprintf(card->longname, "Dummy %i", dev + 1); + dummy_proc_init(dummy); + snd_card_set_dev(card, &devptr->dev); err = snd_card_register(card); -- cgit v0.10.2 From 179a8100e12d0053f4b368ea3358dd9a0fc6cb94 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 7 Sep 2009 10:14:42 +0100 Subject: kmemleak: Do no create the clean-up thread during kmemleak_disable() The kmemleak_disable() function could be called from various contexts including IRQ. It creates a clean-up thread but the kthread_create() function has restrictions on which contexts it can be called from, mainly because of the kthread_create_lock. The patch changes the kmemleak clean-up thread to a workqueue. Signed-off-by: Catalin Marinas Reported-by: Eric Paris diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 74d4089..1563de4 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -92,6 +92,7 @@ #include #include #include +#include #include #include @@ -1499,7 +1500,7 @@ static const struct file_operations kmemleak_fops = { * Perform the freeing of the kmemleak internal objects after waiting for any * current memory scan to complete. */ -static int kmemleak_cleanup_thread(void *arg) +static void kmemleak_do_cleanup(struct work_struct *work) { struct kmemleak_object *object; @@ -1511,22 +1512,9 @@ static int kmemleak_cleanup_thread(void *arg) delete_object_full(object->pointer); rcu_read_unlock(); mutex_unlock(&scan_mutex); - - return 0; } -/* - * Start the clean-up thread. - */ -static void kmemleak_cleanup(void) -{ - struct task_struct *cleanup_thread; - - cleanup_thread = kthread_run(kmemleak_cleanup_thread, NULL, - "kmemleak-clean"); - if (IS_ERR(cleanup_thread)) - pr_warning("Failed to create the clean-up thread\n"); -} +static DECLARE_WORK(cleanup_work, kmemleak_do_cleanup); /* * Disable kmemleak. No memory allocation/freeing will be traced once this @@ -1544,7 +1532,7 @@ static void kmemleak_disable(void) /* check whether it is too early for a kernel thread */ if (atomic_read(&kmemleak_initialized)) - kmemleak_cleanup(); + schedule_work(&cleanup_work); pr_info("Kernel memory leak detector disabled\n"); } @@ -1640,7 +1628,7 @@ static int __init kmemleak_late_init(void) * after setting kmemleak_initialized and we may end up with * two clean-up threads but serialized by scan_mutex. */ - kmemleak_cleanup(); + schedule_work(&cleanup_work); return -ENOMEM; } -- cgit v0.10.2 From 4a558dd6f93d419cd318958577e25492bd09e960 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 8 Sep 2009 16:34:50 +0100 Subject: kmemleak: use bool for true/false questions Acked-by: Pekka Enberg Signed-off-by: Luis R. Rodriguez Signed-off-by: Catalin Marinas diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 1563de4..f5042b4 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -308,17 +308,17 @@ static void hex_dump_object(struct seq_file *seq, * Newly created objects don't have any color assigned (object->count == -1) * before the next memory scan when they become white. */ -static int color_white(const struct kmemleak_object *object) +static bool color_white(const struct kmemleak_object *object) { return object->count != -1 && object->count < object->min_count; } -static int color_gray(const struct kmemleak_object *object) +static bool color_gray(const struct kmemleak_object *object) { return object->min_count != -1 && object->count >= object->min_count; } -static int color_black(const struct kmemleak_object *object) +static bool color_black(const struct kmemleak_object *object) { return object->min_count == -1; } @@ -328,7 +328,7 @@ static int color_black(const struct kmemleak_object *object) * not be deleted and have a minimum age to avoid false positives caused by * pointers temporarily stored in CPU registers. */ -static int unreferenced_object(struct kmemleak_object *object) +static bool unreferenced_object(struct kmemleak_object *object) { return (object->flags & OBJECT_ALLOCATED) && color_white(object) && time_before_eq(object->jiffies + jiffies_min_age, -- cgit v0.10.2 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 diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt index c223785..34f6638 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 f5042b4..c17dbc7 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1421,6 +1421,28 @@ static int dump_str_object_info(const char *str) } /* + * 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: * off - disable kmemleak (irreversible) @@ -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 v0.10.2 From b888d1ce82ebd2bafecf64c765754968e78b4228 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Sep 2009 18:15:17 +0200 Subject: ALSA: dummy - Increase MAX_PCM_SUBSTREAMS to 128 Increase the limit of PCM substreams to 128. The default value is unchanged; only the max accept value is increased. Signed-off-by: Takashi Iwai diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index ccfbdfa..6ba066c 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -42,7 +42,7 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}"); #define MAX_PCM_DEVICES 4 -#define MAX_PCM_SUBSTREAMS 16 +#define MAX_PCM_SUBSTREAMS 128 #define MAX_MIDI_DEVICES 2 #if 0 /* emu10k1 emulation */ -- cgit v0.10.2 From a1084c8779f5efa771c6896a0a4184900b4ab736 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 4 Sep 2009 17:44:52 -0700 Subject: kmemleak: move common painting code together When painting grey or black we do the same thing, bring this together into a helper and identify coloring grey or black explicitly with defines. This makes this a little easier to read. Signed-off-by: Luis R. Rodriguez Signed-off-by: Catalin Marinas diff --git a/mm/kmemleak.c b/mm/kmemleak.c index c17dbc7..b18d9ca 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -123,6 +123,9 @@ struct kmemleak_scan_area { size_t length; }; +#define KMEMLEAK_GREY 0 +#define KMEMLEAK_BLACK -1 + /* * Structure holding the metadata for each allocated memory block. * Modifications to such objects should be made while holding the @@ -310,17 +313,19 @@ static void hex_dump_object(struct seq_file *seq, */ static bool color_white(const struct kmemleak_object *object) { - return object->count != -1 && object->count < object->min_count; + return object->count != KMEMLEAK_BLACK && + object->count < object->min_count; } static bool color_gray(const struct kmemleak_object *object) { - return object->min_count != -1 && object->count >= object->min_count; + return object->min_count != KMEMLEAK_BLACK && + object->count >= object->min_count; } static bool color_black(const struct kmemleak_object *object) { - return object->min_count == -1; + return object->min_count == KMEMLEAK_BLACK; } /* @@ -661,47 +666,55 @@ static void delete_object_part(unsigned long ptr, size_t size) put_object(object); } -/* - * Make a object permanently as gray-colored so that it can no longer be - * reported as a leak. This is used in general to mark a false positive. - */ -static void make_gray_object(unsigned long ptr) + +static void __paint_it(struct kmemleak_object *object, int color) +{ + object->min_count = color; + if (color == KMEMLEAK_BLACK) + object->flags |= OBJECT_NO_SCAN; +} + +static void paint_it(struct kmemleak_object *object, int color) { unsigned long flags; + + spin_lock_irqsave(&object->lock, flags); + __paint_it(object, color); + spin_unlock_irqrestore(&object->lock, flags); +} + +static void paint_ptr(unsigned long ptr, int color) +{ struct kmemleak_object *object; object = find_and_get_object(ptr, 0); if (!object) { - kmemleak_warn("Graying unknown object at 0x%08lx\n", ptr); + kmemleak_warn("Trying to color unknown object " + "at 0x%08lx as %s\n", ptr, + (color == KMEMLEAK_GREY) ? "Grey" : + (color == KMEMLEAK_BLACK) ? "Black" : "Unknown"); return; } - - spin_lock_irqsave(&object->lock, flags); - object->min_count = 0; - spin_unlock_irqrestore(&object->lock, flags); + paint_it(object, color); put_object(object); } /* + * Make a object permanently as gray-colored so that it can no longer be + * reported as a leak. This is used in general to mark a false positive. + */ +static void make_gray_object(unsigned long ptr) +{ + paint_ptr(ptr, KMEMLEAK_GREY); +} + +/* * Mark the object as black-colored so that it is ignored from scans and * reporting. */ static void make_black_object(unsigned long ptr) { - unsigned long flags; - struct kmemleak_object *object; - - object = find_and_get_object(ptr, 0); - if (!object) { - kmemleak_warn("Blacking unknown object at 0x%08lx\n", ptr); - return; - } - - spin_lock_irqsave(&object->lock, flags); - object->min_count = -1; - object->flags |= OBJECT_NO_SCAN; - spin_unlock_irqrestore(&object->lock, flags); - put_object(object); + paint_ptr(ptr, KMEMLEAK_BLACK); } /* @@ -1436,7 +1449,7 @@ static void kmemleak_clear(void) spin_lock_irqsave(&object->lock, flags); if ((object->flags & OBJECT_REPORTED) && unreferenced_object(object)) - object->min_count = 0; + __paint_it(object, KMEMLEAK_GREY); spin_unlock_irqrestore(&object->lock, flags); } rcu_read_unlock(); -- cgit v0.10.2 From 0580a1819c584eb8b98f8701157667037e11153a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 8 Sep 2009 17:32:34 +0100 Subject: kmemleak: fix sparse warning over overshadowed flags A secondary irq_save is not required as a locking before it was already disabling irqs. This fixes this sparse warning: mm/kmemleak.c:512:31: warning: symbol 'flags' shadows an earlier one mm/kmemleak.c:448:23: originally declared here Signed-off-by: Luis R. Rodriguez Acked-by: Pekka Enberg Signed-off-by: Catalin Marinas diff --git a/mm/kmemleak.c b/mm/kmemleak.c index b18d9ca..ffd162a 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -555,6 +555,7 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size, object->tree_node.last = ptr + size - 1; write_lock_irqsave(&kmemleak_lock, flags); + min_addr = min(min_addr, ptr); max_addr = max(max_addr, ptr + size); node = prio_tree_insert(&object_tree_root, &object->tree_node); @@ -565,14 +566,12 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size, * random memory blocks. */ if (node != &object->tree_node) { - unsigned long flags; - kmemleak_stop("Cannot insert 0x%lx into the object search tree " "(already existing)\n", ptr); object = lookup_object(ptr, 1); - spin_lock_irqsave(&object->lock, flags); + spin_lock(&object->lock); dump_object_info(object); - spin_unlock_irqrestore(&object->lock, flags); + spin_unlock(&object->lock); goto out; } -- cgit v0.10.2 From 7eb0d5e5be4e312d5368896744476cc705b3d7e7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 8 Sep 2009 17:31:45 +0100 Subject: kmemleak: fix sparse warning for static declarations This fixes these sparse warnings: mm/kmemleak.c:1179:6: warning: symbol 'start_scan_thread' was not declared. Should it be static? mm/kmemleak.c:1194:6: warning: symbol 'stop_scan_thread' was not declared. Should it be static? Acked-by: Pekka Enberg Signed-off-by: Luis R. Rodriguez Signed-off-by: Catalin Marinas diff --git a/mm/kmemleak.c b/mm/kmemleak.c index ffd162a..39da954 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1287,7 +1287,7 @@ static int kmemleak_scan_thread(void *arg) * Start the automatic memory scanning thread. This function must be called * with the scan_mutex held. */ -void start_scan_thread(void) +static void start_scan_thread(void) { if (scan_thread) return; @@ -1302,7 +1302,7 @@ void start_scan_thread(void) * Stop the automatic memory scanning thread. This function must be called * with the scan_mutex held. */ -void stop_scan_thread(void) +static void stop_scan_thread(void) { if (scan_thread) { kthread_stop(scan_thread); -- cgit v0.10.2 From e8e66ed25b5cbeebed69c475f6c108e52078a3b3 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 28 Aug 2009 10:05:33 -0700 Subject: Do not call 'ima_path_check()' for each path component Not only is that a supremely timing-critical path, but it's hopefully some day going to be lockless for the common case, and ima can't do that. Plus the integrity code doesn't even care about non-regular files, so it was always a total waste of time and effort. Acked-by: Serge Hallyn Acked-by: Mimi Zohar Signed-off-by: Linus Torvalds diff --git a/fs/namei.c b/fs/namei.c index 1f13751..a005d8b 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -856,9 +856,6 @@ static int __link_path_walk(const char *name, struct nameidata *nd) if (err == -EAGAIN) err = inode_permission(nd->path.dentry->d_inode, MAY_EXEC); - if (!err) - err = ima_path_check(&nd->path, MAY_EXEC, - IMA_COUNT_UPDATE); if (err) break; -- cgit v0.10.2 From b7a437b08a44a3ed7e3a052eb39d2c5f618b603b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 28 Aug 2009 10:50:37 -0700 Subject: Simplify exec_permission_lite() logic Instead of returning EAGAIN and having the caller do something special for that case, just do the special case directly. Reviewed-by: James Morris Acked-by: Serge Hallyn Signed-off-by: Linus Torvalds diff --git a/fs/namei.c b/fs/namei.c index a005d8b..8c35806 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -435,7 +435,7 @@ static int exec_permission_lite(struct inode *inode) umode_t mode = inode->i_mode; if (inode->i_op->permission) - return -EAGAIN; + return inode_permission(inode, MAY_EXEC); if (current_fsuid() == inode->i_uid) mode >>= 6; @@ -853,9 +853,6 @@ static int __link_path_walk(const char *name, struct nameidata *nd) nd->flags |= LOOKUP_CONTINUE; err = exec_permission_lite(inode); - if (err == -EAGAIN) - err = inode_permission(nd->path.dentry->d_inode, - MAY_EXEC); if (err) break; -- cgit v0.10.2 From f1ac9f6bfea6f21e8ab6dbbe46879d62a6fba8c0 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 28 Aug 2009 10:53:56 -0700 Subject: Simplify exec_permission_lite() further This function is only called for path components that are already known to be directories (they have a '->lookup' method). So don't bother doing that whole S_ISDIR() testing, the whole point of the 'lite()' version is that we know that we are looking at a directory component, and that we're only checking name lookup permission. Reviewed-by: James Morris Acked-by: Serge Hallyn Signed-off-by: Linus Torvalds diff --git a/fs/namei.c b/fs/namei.c index 8c35806..929f535 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -445,13 +445,7 @@ static int exec_permission_lite(struct inode *inode) if (mode & MAY_EXEC) goto ok; - if ((inode->i_mode & S_IXUGO) && capable(CAP_DAC_OVERRIDE)) - goto ok; - - if (S_ISDIR(inode->i_mode) && capable(CAP_DAC_OVERRIDE)) - goto ok; - - if (S_ISDIR(inode->i_mode) && capable(CAP_DAC_READ_SEARCH)) + if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH)) goto ok; return -EACCES; -- cgit v0.10.2 From cb9179ead0aa0e3b7b4087cdba59baf16bbeef6d Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 28 Aug 2009 11:08:31 -0700 Subject: Simplify exec_permission_lite(), part 3 Don't call down to the generic inode_permission() function just to call the inode-specific permission function - just do it directly. The generic inode_permission() code does things like checking MAY_WRITE and devcgroup_inode_permission(), neither of which are relevant for the light pathname walk permission checks (we always do just MAY_EXEC, and the inode is never a special device). Reviewed-by: James Morris Acked-by: Serge Hallyn Signed-off-by: Linus Torvalds diff --git a/fs/namei.c b/fs/namei.c index 929f535..e645e30 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -434,8 +434,12 @@ static int exec_permission_lite(struct inode *inode) { umode_t mode = inode->i_mode; - if (inode->i_op->permission) - return inode_permission(inode, MAY_EXEC); + if (inode->i_op->permission) { + int ret = inode->i_op->permission(inode, MAY_EXEC); + if (!ret) + goto ok; + return ret; + } if (current_fsuid() == inode->i_uid) mode >>= 6; -- cgit v0.10.2 From 5909ccaa300a4a834ffa275327af4df0b9cb5295 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 28 Aug 2009 11:51:25 -0700 Subject: Make 'check_acl()' a first-class filesystem op This is stage one in flattening out the callchains for the common permission testing. Rather than have most filesystem implement their own inode->i_op->permission function that just calls back down to the VFS layers 'generic_permission()' with the per-filesystem ACL checking function, the filesystem can just expose its 'check_acl' function directly, and let the VFS layer do everything for it. This is all just preparatory - no filesystem actually enables this yet. Reviewed-by: James Morris Acked-by: Serge Hallyn Signed-off-by: Linus Torvalds diff --git a/fs/namei.c b/fs/namei.c index e645e30..ed27bb2 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -169,19 +169,10 @@ void putname(const char *name) EXPORT_SYMBOL(putname); #endif - -/** - * generic_permission - check for access rights on a Posix-like filesystem - * @inode: inode to check access rights for - * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) - * @check_acl: optional callback to check for Posix ACLs - * - * Used to check for read/write/execute permissions on a file. - * We use "fsuid" for this, letting us set arbitrary permissions - * for filesystem access without changing the "normal" uids which - * are used for other things.. +/* + * This does basic POSIX ACL permission checking */ -int generic_permission(struct inode *inode, int mask, +static int acl_permission_check(struct inode *inode, int mask, int (*check_acl)(struct inode *inode, int mask)) { umode_t mode = inode->i_mode; @@ -193,9 +184,7 @@ int generic_permission(struct inode *inode, int mask, else { if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { int error = check_acl(inode, mask); - if (error == -EACCES) - goto check_capabilities; - else if (error != -EAGAIN) + if (error != -EAGAIN) return error; } @@ -208,8 +197,32 @@ int generic_permission(struct inode *inode, int mask, */ if ((mask & ~mode) == 0) return 0; + return -EACCES; +} + +/** + * generic_permission - check for access rights on a Posix-like filesystem + * @inode: inode to check access rights for + * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) + * @check_acl: optional callback to check for Posix ACLs + * + * Used to check for read/write/execute permissions on a file. + * We use "fsuid" for this, letting us set arbitrary permissions + * for filesystem access without changing the "normal" uids which + * are used for other things.. + */ +int generic_permission(struct inode *inode, int mask, + int (*check_acl)(struct inode *inode, int mask)) +{ + int ret; + + /* + * Do the basic POSIX ACL permission checks. + */ + ret = acl_permission_check(inode, mask, check_acl); + if (ret != -EACCES) + return ret; - check_capabilities: /* * Read/write DACs are always overridable. * Executable DACs are overridable if at least one exec bit is set. @@ -262,7 +275,7 @@ int inode_permission(struct inode *inode, int mask) if (inode->i_op->permission) retval = inode->i_op->permission(inode, mask); else - retval = generic_permission(inode, mask, NULL); + retval = generic_permission(inode, mask, inode->i_op->check_acl); if (retval) return retval; @@ -432,27 +445,22 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, */ static int exec_permission_lite(struct inode *inode) { - umode_t mode = inode->i_mode; + int ret; if (inode->i_op->permission) { - int ret = inode->i_op->permission(inode, MAY_EXEC); + ret = inode->i_op->permission(inode, MAY_EXEC); if (!ret) goto ok; return ret; } - - if (current_fsuid() == inode->i_uid) - mode >>= 6; - else if (in_group_p(inode->i_gid)) - mode >>= 3; - - if (mode & MAY_EXEC) + ret = acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl); + if (!ret) goto ok; if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH)) goto ok; - return -EACCES; + return ret; ok: return security_inode_permission(inode, MAY_EXEC); } diff --git a/include/linux/fs.h b/include/linux/fs.h index 73e9b64..c1f9935 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1528,6 +1528,7 @@ struct inode_operations { void (*put_link) (struct dentry *, struct nameidata *, void *); void (*truncate) (struct inode *); int (*permission) (struct inode *, int); + int (*check_acl)(struct inode *, int); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); -- cgit v0.10.2 From 6d848a488ad83cc3891bb274691118f45ce6aab9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 28 Aug 2009 12:04:28 -0700 Subject: shmfs: use 'check_acl' instead of 'permission' shmfs wants purely standard POSIX ACL semantics, so we can use the new generic VFS layer POSIX ACL checking rather than cooking our own 'permission()' function. Reviewed-by: James Morris Acked-by: Serge Hallyn Acked-by: Hugh Dickins Signed-off-by: Linus Torvalds diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index abff6c9..6d3f2f4 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h @@ -39,7 +39,7 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode) } #ifdef CONFIG_TMPFS_POSIX_ACL -int shmem_permission(struct inode *, int); +int shmem_check_acl(struct inode *, int); int shmem_acl_init(struct inode *, struct inode *); extern struct xattr_handler shmem_xattr_acl_access_handler; diff --git a/mm/shmem.c b/mm/shmem.c index d713239..5a0b3d4 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2446,7 +2446,7 @@ static const struct inode_operations shmem_inode_operations = { .getxattr = generic_getxattr, .listxattr = generic_listxattr, .removexattr = generic_removexattr, - .permission = shmem_permission, + .check_acl = shmem_check_acl, #endif }; @@ -2469,7 +2469,7 @@ static const struct inode_operations shmem_dir_inode_operations = { .getxattr = generic_getxattr, .listxattr = generic_listxattr, .removexattr = generic_removexattr, - .permission = shmem_permission, + .check_acl = shmem_check_acl, #endif }; @@ -2480,7 +2480,7 @@ static const struct inode_operations shmem_special_inode_operations = { .getxattr = generic_getxattr, .listxattr = generic_listxattr, .removexattr = generic_removexattr, - .permission = shmem_permission, + .check_acl = shmem_check_acl, #endif }; diff --git a/mm/shmem_acl.c b/mm/shmem_acl.c index 606a8e7..df2c87f 100644 --- a/mm/shmem_acl.c +++ b/mm/shmem_acl.c @@ -157,7 +157,7 @@ shmem_acl_init(struct inode *inode, struct inode *dir) /** * shmem_check_acl - check_acl() callback for generic_permission() */ -static int +int shmem_check_acl(struct inode *inode, int mask) { struct posix_acl *acl = shmem_get_acl(inode, ACL_TYPE_ACCESS); @@ -169,12 +169,3 @@ shmem_check_acl(struct inode *inode, int mask) } return -EAGAIN; } - -/** - * shmem_permission - permission() inode operation - */ -int -shmem_permission(struct inode *inode, int mask) -{ - return generic_permission(inode, mask, shmem_check_acl); -} -- cgit v0.10.2 From 1d5ccd1c422d7d292a9e45248aa36771900c6331 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 28 Aug 2009 12:12:24 -0700 Subject: ext[234]: move over to 'check_acl' permission model Don't implement per-filesystem 'extX_permission()' functions that have to be called for every path component operation, and instead just expose the actual ACL checking so that the VFS layer can now do it for us. Reviewed-by: James Morris Acked-by: Serge Hallyn Signed-off-by: Linus Torvalds diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index d636e12..a63d442 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -230,7 +230,7 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) return error; } -static int +int ext2_check_acl(struct inode *inode, int mask) { struct posix_acl *acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); @@ -246,12 +246,6 @@ ext2_check_acl(struct inode *inode, int mask) return -EAGAIN; } -int -ext2_permission(struct inode *inode, int mask) -{ - return generic_permission(inode, mask, ext2_check_acl); -} - /* * Initialize the ACLs of a new inode. Called from ext2_new_inode. * diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h index ecefe47..3ff6cbb 100644 --- a/fs/ext2/acl.h +++ b/fs/ext2/acl.h @@ -54,13 +54,13 @@ static inline int ext2_acl_count(size_t size) #ifdef CONFIG_EXT2_FS_POSIX_ACL /* acl.c */ -extern int ext2_permission (struct inode *, int); +extern int ext2_check_acl (struct inode *, int); extern int ext2_acl_chmod (struct inode *); extern int ext2_init_acl (struct inode *, struct inode *); #else #include -#define ext2_permission NULL +#define ext2_check_acl NULL #define ext2_get_acl NULL #define ext2_set_acl NULL diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 2b9e47d..a2f3afd 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -85,6 +85,6 @@ const struct inode_operations ext2_file_inode_operations = { .removexattr = generic_removexattr, #endif .setattr = ext2_setattr, - .permission = ext2_permission, + .check_acl = ext2_check_acl, .fiemap = ext2_fiemap, }; diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 78d9b92..23701f2 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -400,7 +400,7 @@ const struct inode_operations ext2_dir_inode_operations = { .removexattr = generic_removexattr, #endif .setattr = ext2_setattr, - .permission = ext2_permission, + .check_acl = ext2_check_acl, }; const struct inode_operations ext2_special_inode_operations = { @@ -411,5 +411,5 @@ const struct inode_operations ext2_special_inode_operations = { .removexattr = generic_removexattr, #endif .setattr = ext2_setattr, - .permission = ext2_permission, + .check_acl = ext2_check_acl, }; diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index e167bae..c9b0df3 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -238,7 +238,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, return error; } -static int +int ext3_check_acl(struct inode *inode, int mask) { struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); @@ -254,12 +254,6 @@ ext3_check_acl(struct inode *inode, int mask) return -EAGAIN; } -int -ext3_permission(struct inode *inode, int mask) -{ - return generic_permission(inode, mask, ext3_check_acl); -} - /* * Initialize the ACLs of a new inode. Called from ext3_new_inode. * diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h index 07d15a3..5973346 100644 --- a/fs/ext3/acl.h +++ b/fs/ext3/acl.h @@ -54,13 +54,13 @@ static inline int ext3_acl_count(size_t size) #ifdef CONFIG_EXT3_FS_POSIX_ACL /* acl.c */ -extern int ext3_permission (struct inode *, int); +extern int ext3_check_acl (struct inode *, int); extern int ext3_acl_chmod (struct inode *); extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); #else /* CONFIG_EXT3_FS_POSIX_ACL */ #include -#define ext3_permission NULL +#define ext3_check_acl NULL static inline int ext3_acl_chmod(struct inode *inode) diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 5b49704..2992532 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -137,7 +137,7 @@ const struct inode_operations ext3_file_inode_operations = { .listxattr = ext3_listxattr, .removexattr = generic_removexattr, #endif - .permission = ext3_permission, + .check_acl = ext3_check_acl, .fiemap = ext3_fiemap, }; diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 6ff7b97..aad6400 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -2445,7 +2445,7 @@ const struct inode_operations ext3_dir_inode_operations = { .listxattr = ext3_listxattr, .removexattr = generic_removexattr, #endif - .permission = ext3_permission, + .check_acl = ext3_check_acl, }; const struct inode_operations ext3_special_inode_operations = { @@ -2456,5 +2456,5 @@ const struct inode_operations ext3_special_inode_operations = { .listxattr = ext3_listxattr, .removexattr = generic_removexattr, #endif - .permission = ext3_permission, + .check_acl = ext3_check_acl, }; diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index f6d8967..0df88b2 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -236,7 +236,7 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, return error; } -static int +int ext4_check_acl(struct inode *inode, int mask) { struct posix_acl *acl = ext4_get_acl(inode, ACL_TYPE_ACCESS); @@ -252,12 +252,6 @@ ext4_check_acl(struct inode *inode, int mask) return -EAGAIN; } -int -ext4_permission(struct inode *inode, int mask) -{ - return generic_permission(inode, mask, ext4_check_acl); -} - /* * Initialize the ACLs of a new inode. Called from ext4_new_inode. * diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h index 949789d..9d843d5 100644 --- a/fs/ext4/acl.h +++ b/fs/ext4/acl.h @@ -54,13 +54,13 @@ static inline int ext4_acl_count(size_t size) #ifdef CONFIG_EXT4_FS_POSIX_ACL /* acl.c */ -extern int ext4_permission(struct inode *, int); +extern int ext4_check_acl(struct inode *, int); extern int ext4_acl_chmod(struct inode *); extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); #else /* CONFIG_EXT4_FS_POSIX_ACL */ #include -#define ext4_permission NULL +#define ext4_check_acl NULL static inline int ext4_acl_chmod(struct inode *inode) diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 3f1873f..27f3c53 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -207,7 +207,7 @@ const struct inode_operations ext4_file_inode_operations = { .listxattr = ext4_listxattr, .removexattr = generic_removexattr, #endif - .permission = ext4_permission, + .check_acl = ext4_check_acl, .fallocate = ext4_fallocate, .fiemap = ext4_fiemap, }; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index de04013..114abe5 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2536,7 +2536,7 @@ const struct inode_operations ext4_dir_inode_operations = { .listxattr = ext4_listxattr, .removexattr = generic_removexattr, #endif - .permission = ext4_permission, + .check_acl = ext4_check_acl, .fiemap = ext4_fiemap, }; @@ -2548,5 +2548,5 @@ const struct inode_operations ext4_special_inode_operations = { .listxattr = ext4_listxattr, .removexattr = generic_removexattr, #endif - .permission = ext4_permission, + .check_acl = ext4_check_acl, }; -- cgit v0.10.2 From 18f4c644773bc8de1fd9c5182b30c231aafb94ef Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 28 Aug 2009 12:29:03 -0700 Subject: jffs2/jfs/xfs: switch over to 'check_acl' rather than 'permission()' This avoids an indirect call in the VFS for each path component lookup. Well, at least as long as you own the directory in question, and the ACL check is unnecessary. Reviewed-by: James Morris Acked-by: Serge Hallyn Signed-off-by: Linus Torvalds diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 8fcb623..7edb62e 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -258,7 +258,7 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) return rc; } -static int jffs2_check_acl(struct inode *inode, int mask) +int jffs2_check_acl(struct inode *inode, int mask) { struct posix_acl *acl; int rc; @@ -274,11 +274,6 @@ static int jffs2_check_acl(struct inode *inode, int mask) return -EAGAIN; } -int jffs2_permission(struct inode *inode, int mask) -{ - return generic_permission(inode, mask, jffs2_check_acl); -} - int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) { struct posix_acl *acl, *clone; diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index fc929f2..f0ba63e 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h @@ -26,7 +26,7 @@ struct jffs2_acl_header { #ifdef CONFIG_JFFS2_FS_POSIX_ACL -extern int jffs2_permission(struct inode *, int); +extern int jffs2_check_acl(struct inode *, int); extern int jffs2_acl_chmod(struct inode *); extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); extern int jffs2_init_acl_post(struct inode *); @@ -36,7 +36,7 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler; #else -#define jffs2_permission (NULL) +#define jffs2_check_acl (NULL) #define jffs2_acl_chmod(inode) (0) #define jffs2_init_acl_pre(dir_i,inode,mode) (0) #define jffs2_init_acl_post(inode) (0) diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 6f60cc9..7aa4417 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -55,7 +55,7 @@ const struct inode_operations jffs2_dir_inode_operations = .rmdir = jffs2_rmdir, .mknod = jffs2_mknod, .rename = jffs2_rename, - .permission = jffs2_permission, + .check_acl = jffs2_check_acl, .setattr = jffs2_setattr, .setxattr = jffs2_setxattr, .getxattr = jffs2_getxattr, diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 23c9475..b7b74e2 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -56,7 +56,7 @@ const struct file_operations jffs2_file_operations = const struct inode_operations jffs2_file_inode_operations = { - .permission = jffs2_permission, + .check_acl = jffs2_check_acl, .setattr = jffs2_setattr, .setxattr = jffs2_setxattr, .getxattr = jffs2_getxattr, diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index b7339c3..4ec11e8 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -21,7 +21,7 @@ const struct inode_operations jffs2_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = jffs2_follow_link, - .permission = jffs2_permission, + .check_acl = jffs2_check_acl, .setattr = jffs2_setattr, .setxattr = jffs2_setxattr, .getxattr = jffs2_getxattr, diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index a29c7c3..d66477c 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -114,7 +114,7 @@ out: return rc; } -static int jfs_check_acl(struct inode *inode, int mask) +int jfs_check_acl(struct inode *inode, int mask) { struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); @@ -129,11 +129,6 @@ static int jfs_check_acl(struct inode *inode, int mask) return -EAGAIN; } -int jfs_permission(struct inode *inode, int mask) -{ - return generic_permission(inode, mask, jfs_check_acl); -} - int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 7f6063a..2b70fa7 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -96,7 +96,7 @@ const struct inode_operations jfs_file_inode_operations = { .removexattr = jfs_removexattr, #ifdef CONFIG_JFS_POSIX_ACL .setattr = jfs_setattr, - .permission = jfs_permission, + .check_acl = jfs_check_acl, #endif }; diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h index 88475f1..b07bd41 100644 --- a/fs/jfs/jfs_acl.h +++ b/fs/jfs/jfs_acl.h @@ -20,7 +20,7 @@ #ifdef CONFIG_JFS_POSIX_ACL -int jfs_permission(struct inode *, int); +int jfs_check_acl(struct inode *, int); int jfs_init_acl(tid_t, struct inode *, struct inode *); int jfs_setattr(struct dentry *, struct iattr *); diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 514ee2e..c79a4270 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -1543,7 +1543,7 @@ const struct inode_operations jfs_dir_inode_operations = { .removexattr = jfs_removexattr, #ifdef CONFIG_JFS_POSIX_ACL .setattr = jfs_setattr, - .permission = jfs_permission, + .check_acl = jfs_check_acl, #endif }; diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 8070b34..6c32f1d 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -485,14 +485,6 @@ xfs_vn_put_link( } STATIC int -xfs_vn_permission( - struct inode *inode, - int mask) -{ - return generic_permission(inode, mask, xfs_check_acl); -} - -STATIC int xfs_vn_getattr( struct vfsmount *mnt, struct dentry *dentry, @@ -696,7 +688,7 @@ xfs_vn_fiemap( } static const struct inode_operations xfs_inode_operations = { - .permission = xfs_vn_permission, + .check_acl = xfs_check_acl, .truncate = xfs_vn_truncate, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, @@ -724,7 +716,7 @@ static const struct inode_operations xfs_dir_inode_operations = { .rmdir = xfs_vn_unlink, .mknod = xfs_vn_mknod, .rename = xfs_vn_rename, - .permission = xfs_vn_permission, + .check_acl = xfs_check_acl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, @@ -749,7 +741,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { .rmdir = xfs_vn_unlink, .mknod = xfs_vn_mknod, .rename = xfs_vn_rename, - .permission = xfs_vn_permission, + .check_acl = xfs_check_acl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, @@ -762,7 +754,7 @@ static const struct inode_operations xfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = xfs_vn_follow_link, .put_link = xfs_vn_put_link, - .permission = xfs_vn_permission, + .check_acl = xfs_check_acl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, -- cgit v0.10.2 From cdc65fbe18aef15e92d2ebb410a189fbf956fb06 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Tue, 8 Sep 2009 19:45:17 +0200 Subject: ASoC: au1x: PSC-AC97 bugfixes This patch fixes the following bugs: - only reprogram bitdepth if it has changed since last call to hw_params. - add locking inside ac97_read/write functions: When reprogramming sample depth, the ac97 unit has to be disabled, which should not be done in the middle of codec register accesses. - retry timed-out codec register accesses. - wait for status bits to set/clear when starting/stopping various functional blocks; very important after reenabling AC97 unit else sound may be distorted (e.g. high-pitch noise in 1kHz sine wave). - clear fifos before/after starting/stopping RX/TX. - longer timeouts waiting for PSC/AC97 ready after cold reset with certain codecs this can take ridiculous amounts of time. Run-tested on various Au1200 platforms with various codecs. Signed-off-by: Manuel Lauss Signed-off-by: Mark Brown diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 479d7bd..a521aa9 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -1,8 +1,8 @@ /* * Au12x0/Au1550 PSC ALSA ASoC audio support. * - * (c) 2007-2008 MSC Vertriebsges.m.b.H., - * Manuel Lauss + * (c) 2007-2009 MSC Vertriebsges.m.b.H., + * Manuel Lauss * * 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 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,9 @@ #include "psc.h" +/* how often to retry failed codec register reads/writes */ +#define AC97_RW_RETRIES 5 + #define AC97_DIR \ (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) @@ -45,6 +49,9 @@ #define AC97PCR_CLRFIFO(stype) \ ((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC) +#define AC97STAT_BUSY(stype) \ + ((stype) == PCM_TX ? PSC_AC97STAT_TB : PSC_AC97STAT_RB) + /* instance data. There can be only one, MacLeod!!!! */ static struct au1xpsc_audio_data *au1xpsc_ac97_workdata; @@ -54,24 +61,33 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97, { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; - unsigned short data, tmo; + unsigned short data, retry, tmo; - au_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), AC97_CDC(pscdata)); + au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); au_sync(); - tmo = 1000; - while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo) - udelay(2); + retry = AC97_RW_RETRIES; + do { + mutex_lock(&pscdata->lock); + + au_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), + AC97_CDC(pscdata)); + au_sync(); + + tmo = 2000; + while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) + && --tmo) + udelay(2); - if (!tmo) - data = 0xffff; - else data = au_readl(AC97_CDC(pscdata)) & 0xffff; - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); + au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); + au_sync(); + + mutex_unlock(&pscdata->lock); + } while (--retry && !tmo); - return data; + return retry ? data : 0xffff; } /* AC97 controller writes to codec register */ @@ -80,16 +96,29 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg, { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; - unsigned int tmo; + unsigned int tmo, retry; - au_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), AC97_CDC(pscdata)); + au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); au_sync(); - tmo = 1000; - while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo) + + retry = AC97_RW_RETRIES; + do { + mutex_lock(&pscdata->lock); + + au_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), + AC97_CDC(pscdata)); au_sync(); - au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); - au_sync(); + tmo = 2000; + while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) + && --tmo) + udelay(2); + + au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); + au_sync(); + + mutex_unlock(&pscdata->lock); + } while (--retry && !tmo); } /* AC97 controller asserts a warm reset */ @@ -129,9 +158,9 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) au_sync(); /* wait for PSC to indicate it's ready */ - i = 100000; + i = 1000; while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i)) - au_sync(); + msleep(1); if (i == 0) { printk(KERN_ERR "au1xpsc-ac97: PSC not ready!\n"); @@ -143,9 +172,9 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) au_sync(); /* wait for AC97 core to become ready */ - i = 100000; + i = 1000; while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i)) - au_sync(); + msleep(1); if (i == 0) printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n"); } @@ -165,12 +194,12 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; - unsigned long r, stat; + unsigned long r, ro, stat; int chans, stype = SUBSTREAM_TYPE(substream); chans = params_channels(params); - r = au_readl(AC97_CFG(pscdata)); + r = ro = au_readl(AC97_CFG(pscdata)); stat = au_readl(AC97_STAT(pscdata)); /* already active? */ @@ -180,9 +209,6 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, (pscdata->rate != params_rate(params))) return -EINVAL; } else { - /* disable AC97 device controller first */ - au_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); - au_sync(); /* set sample bitdepth: REG[24:21]=(BITS-2)/2 */ r &= ~PSC_AC97CFG_LEN_MASK; @@ -199,14 +225,40 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, r |= PSC_AC97CFG_RXSLOT_ENA(4); } - /* finally enable the AC97 controller again */ + /* do we need to poke the hardware? */ + if (!(r ^ ro)) + goto out; + + /* ac97 engine is about to be disabled */ + mutex_lock(&pscdata->lock); + + /* disable AC97 device controller first... */ + au_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); + au_sync(); + + /* ...wait for it... */ + while (au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) + asm volatile ("nop"); + + /* ...write config... */ + au_writel(r, AC97_CFG(pscdata)); + au_sync(); + + /* ...enable the AC97 controller again... */ au_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); au_sync(); + /* ...and wait for ready bit */ + while (!(au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) + asm volatile ("nop"); + + mutex_unlock(&pscdata->lock); + pscdata->cfg = r; pscdata->rate = params_rate(params); } +out: return 0; } @@ -222,6 +274,8 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: + au_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); + au_sync(); au_writel(AC97PCR_START(stype), AC97_PCR(pscdata)); au_sync(); break; @@ -229,6 +283,13 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_SUSPEND: au_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata)); au_sync(); + + while (au_readl(AC97_STAT(pscdata)) & AC97STAT_BUSY(stype)) + asm volatile ("nop"); + + au_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); + au_sync(); + break; default: ret = -EINVAL; @@ -251,6 +312,8 @@ static int au1xpsc_ac97_probe(struct platform_device *pdev, if (!au1xpsc_ac97_workdata) return -ENOMEM; + mutex_init(&au1xpsc_ac97_workdata->lock); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { ret = -ENODEV; @@ -269,9 +332,9 @@ static int au1xpsc_ac97_probe(struct platform_device *pdev, goto out1; /* configuration: max dma trigger threshold, enable ac97 */ - au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 | - PSC_AC97CFG_TT_FIFO8 | - PSC_AC97CFG_DE_ENABLE; + au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 | + PSC_AC97CFG_TT_FIFO8 | + PSC_AC97CFG_DE_ENABLE; /* preserve PSC clock source set up by platform (dev.platform_data * is already occupied by soc layer) @@ -386,4 +449,4 @@ module_exit(au1xpsc_ac97_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver"); -MODULE_AUTHOR("Manuel Lauss "); +MODULE_AUTHOR("Manuel Lauss "); diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h index 8fdb1a0..3f474e8 100644 --- a/sound/soc/au1x/psc.h +++ b/sound/soc/au1x/psc.h @@ -29,6 +29,7 @@ struct au1xpsc_audio_data { unsigned long pm[2]; struct resource *ioarea; + struct mutex lock; }; #define PCM_TX 0 -- cgit v0.10.2 From 5c630ce7e6cb144a29fd5a993363f4928fb4b890 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Thu, 3 Sep 2009 01:02:59 +0200 Subject: ar9170: added phy register initialisation from eeprom values This patch adds the initialisation of some PHY registers from the modal_header[] values in the EEPROM (see otus/hal/hpmain.c, line 333 ff.) Signed-off-by: Joerg Albert Acked-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index df86f70..3ace58a 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -396,6 +396,136 @@ static struct ar9170_phy_init ar5416_phy_init[] = { { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } }; +/* + * look up a certain register in ar5416_phy_init[] and return the init. value + * for the band and bandwidth given. Return 0 if register address not found. + */ +static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz) +{ + unsigned int i; + for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { + if (ar5416_phy_init[i].reg != reg) + continue; + + if (is_2ghz) { + if (is_40mhz) + return ar5416_phy_init[i]._2ghz_40; + else + return ar5416_phy_init[i]._2ghz_20; + } else { + if (is_40mhz) + return ar5416_phy_init[i]._5ghz_40; + else + return ar5416_phy_init[i]._5ghz_20; + } + } + return 0; +} + +/* + * initialize some phy regs from eeprom values in modal_header[] + * acc. to band and bandwith + */ +static int ar9170_init_phy_from_eeprom(struct ar9170 *ar, + bool is_2ghz, bool is_40mhz) +{ + static const u8 xpd2pd[16] = { + 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2, + 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2 + }; + u32 defval, newval; + /* pointer to the modal_header acc. to band */ + struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz]; + + ar9170_regwrite_begin(ar); + + /* ant common control (index 0) */ + newval = le32_to_cpu(m->antCtrlCommon); + ar9170_regwrite(0x1c5964, newval); + + /* ant control chain 0 (index 1) */ + newval = le32_to_cpu(m->antCtrlChain[0]); + ar9170_regwrite(0x1c5960, newval); + + /* ant control chain 2 (index 2) */ + newval = le32_to_cpu(m->antCtrlChain[1]); + ar9170_regwrite(0x1c7960, newval); + + /* SwSettle (index 3) */ + if (!is_40mhz) { + defval = ar9170_get_default_phy_reg_val(0x1c5844, + is_2ghz, is_40mhz); + newval = (defval & ~0x3f80) | + ((m->switchSettling & 0x7f) << 7); + ar9170_regwrite(0x1c5844, newval); + } + + /* adcDesired, pdaDesired (index 4) */ + defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz); + newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) | + ((u8)m->adcDesiredSize); + ar9170_regwrite(0x1c5850, newval); + + /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */ + defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz); + newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) | + (m->txFrameToXpaOn << 8) | m->txFrameToXpaOn; + ar9170_regwrite(0x1c5834, newval); + + /* TxEndToRxOn (index 6) */ + defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz); + newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16); + ar9170_regwrite(0x1c5828, newval); + + /* thresh62 (index 7) */ + defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz); + newval = (defval & ~0x7f000) | (m->thresh62 << 12); + ar9170_regwrite(0x1c8864, newval); + + /* tx/rx attenuation chain 0 (index 8) */ + defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz); + newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12); + ar9170_regwrite(0x1c5848, newval); + + /* tx/rx attenuation chain 2 (index 9) */ + defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz); + newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12); + ar9170_regwrite(0x1c7848, newval); + + /* tx/rx margin chain 0 (index 10) */ + defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz); + newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18); + /* bsw margin chain 0 for 5GHz only */ + if (!is_2ghz) + newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10); + ar9170_regwrite(0x1c620c, newval); + + /* tx/rx margin chain 2 (index 11) */ + defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz); + newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18); + ar9170_regwrite(0x1c820c, newval); + + /* iqCall, iqCallq chain 0 (index 12) */ + defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz); + newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) | + ((u8)m->iqCalQCh[0] & 0x1f); + ar9170_regwrite(0x1c5920, newval); + + /* iqCall, iqCallq chain 2 (index 13) */ + defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz); + newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) | + ((u8)m->iqCalQCh[1] & 0x1f); + ar9170_regwrite(0x1c7920, newval); + + /* xpd gain mask (index 14) */ + defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz); + newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16); + ar9170_regwrite(0x1c6258, newval); + ar9170_regwrite_finish(); + + return ar9170_regwrite_result(); +} + int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) { int i, err; @@ -426,7 +556,10 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) if (err) return err; - /* XXX: use EEPROM data here! */ + /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ + err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); + if (err) + return err; err = ar9170_init_power_cal(ar); if (err) -- cgit v0.10.2 From db6be53cbaf118fdad5bdca211a19ca5354c9462 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 2 Sep 2009 16:34:57 -0700 Subject: ath9k: propagate ieee80211_alloc_hw() failure The -ENOMEM was never being passed on failure. While at it use dev_err() as ahb does upon failure. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 685a8ce..17862cc 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -160,8 +160,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + sizeof(struct ath_softc), &ath9k_ops); - if (hw == NULL) { - printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); + if (!hw) { + dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); + ret = -ENOMEM; goto bad2; } -- cgit v0.10.2 From 580171f7cd08687cdf1b263aabb35608b3c37433 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 2 Sep 2009 17:02:18 -0700 Subject: ath9k: propagate errors on ath_init_device() and request_irq() We've cleaned up ath_init_device() and its children enough to pass meaninful errors back from probe. When this fails it means our device could not be initialized and a meaninful error will have been passed. Do the same for request_irq() and also synchronize the error messages while at it. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 5618fc2..7dc6301 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -120,16 +120,14 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->irq = irq; ret = ath_init_device(AR5416_AR9100_DEVID, sc); - if (ret != 0) { - dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); - ret = -ENODEV; + if (ret) { + dev_err(&pdev->dev, "failed to initialize device\n"); goto err_free_hw; } ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { - dev_err(&pdev->dev, "request_irq failed, err=%d\n", ret); - ret = -EIO; + dev_err(&pdev->dev, "request_irq failed\n"); goto err_detach; } diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 17862cc..bc4bc2c 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -179,17 +179,17 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = mem; sc->bus_ops = &ath_pci_bus_ops; - if (ath_init_device(id->device, sc) != 0) { - ret = -ENODEV; + ret = ath_init_device(id->device, sc); + if (ret) { + dev_err(&pdev->dev, "failed to initialize device\n"); goto bad3; } /* setup interrupt service routine */ - if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { - printk(KERN_ERR "%s: request_irq failed\n", - wiphy_name(hw->wiphy)); - ret = -EIO; + ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc); + if (ret) { + dev_err(&pdev->dev, "request_irq failed\n"); goto bad4; } -- cgit v0.10.2 From fc548af877374f7e26c4f670f3843c6d29e02a98 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 2 Sep 2009 17:06:21 -0700 Subject: ath9k: claim irq for ath9k, not ath for pci ath9k ahb requests an IRQ and indicates 'ath9k' claimed it, ath9k pci requests an IRQ and indicates 'ath' claims it; since 'ath' is another module sync both ahb and pci to claim the irq using 'ath9k'. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index bc4bc2c..8bb286d 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -187,7 +187,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* setup interrupt service routine */ - ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc); + ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); goto bad4; -- cgit v0.10.2 From 7ea310be65bfcbc6e2395844fd3498762dc2aea6 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 3 Sep 2009 12:08:43 +0530 Subject: ath9k: Fix RX Filter handling for BAR BAR frames have to be sent to mac80211 only if the current channel is HT. Also, move the macro to enum ath9k_rx_filter. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 71f27f3..011b14f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3967,7 +3967,8 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) { u32 phybits; - REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); + REG_WRITE(ah, AR_RX_FILTER, bits); + phybits = 0; if (bits & ATH9K_RX_FILTER_PHYRADAR) phybits |= AR_PHY_ERR_RADAR; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 7b39822..f56e77d 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -568,6 +568,7 @@ enum ath9k_rx_filter { ATH9K_RX_FILTER_PROBEREQ = 0x00000080, ATH9K_RX_FILTER_PHYERR = 0x00000100, ATH9K_RX_FILTER_MYBEACON = 0x00000200, + ATH9K_RX_FILTER_COMP_BAR = 0x00000400, ATH9K_RX_FILTER_PSPOLL = 0x00004000, ATH9K_RX_FILTER_PHYRADAR = 0x00002000, ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c2efdf2..b1d189c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2433,7 +2433,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, ath9k_hw_setrxfilter(sc->sc_ah, rfilt); ath9k_ps_restore(sc); - DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); + DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt); } static void ath9k_sta_notify(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 52e62da..ec0abf8 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -423,6 +423,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->rx.rxfilter & FIF_PSPOLL) rfilt |= ATH9K_RX_FILTER_PSPOLL; + if (conf_is_ht(&sc->hw->conf)) + rfilt |= ATH9K_RX_FILTER_COMP_BAR; + if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) { /* TODO: only needed if more than one BSSID is in use in * station/adhoc mode */ diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 3ddb243..e5c29eb 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1325,7 +1325,6 @@ enum { #define AR_CFP_VAL 0x0000FFFF #define AR_RX_FILTER 0x803C -#define AR_RX_COMPR_BAR 0x00000400 #define AR_MCAST_FIL0 0x8040 #define AR_MCAST_FIL1 0x8044 -- cgit v0.10.2 From 8813262ea79acf9daa0e03901bdfe93db4dc4ca5 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 3 Sep 2009 12:08:53 +0530 Subject: ath9k: Fix channelFlags for 2GHZ CHANNEL_G has to be set for 2GHZ channels since IS_CHAN_G() checks for this in channelFlags and not in chanmode. To make things messier, ath9k_hw_process_ini() checks for CHANNEL_G in chanmode and not in channelFlags. The supreme, brain-searing fix is to set the flag in both cases. Signed-off-by: Sujith Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b1d189c..a69fda8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1879,7 +1879,7 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, if (chan->band == IEEE80211_BAND_2GHZ) { ichan->chanmode = CHANNEL_G; - ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; + ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; } else { ichan->chanmode = CHANNEL_A; ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; -- cgit v0.10.2 From d9c35a506ed7770301f705a9070e05f0c5fae4bd Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 3 Sep 2009 20:25:31 +0200 Subject: ar9170: implement frequency calibration for one-stage/openfw This patch ports some code from the vendor driver, which is supposed to upload the right calibration values for the chosen frequency. In theory, this should give a better range and throughput for all users with the open, or one-stage firmware. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index 3ace58a..108ebfe 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -1120,6 +1120,124 @@ static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) #undef SHIFT } +static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array) +{ + int i; + + for (i = 0; i < 3; i++) + if (x <= x_array[i + 1]) + break; + + return ar9170_interpolate_u8(x, + x_array[i], + y_array[i], + x_array[i + 1], + y_array[i + 1]); +} + +static int ar9170_set_freq_cal_data(struct ar9170 *ar, + struct ieee80211_channel *channel) +{ + u8 *cal_freq_pier; + u8 vpds[2][AR5416_PD_GAIN_ICEPTS]; + u8 pwrs[2][AR5416_PD_GAIN_ICEPTS]; + int chain, idx, i; + u8 f; + + switch (channel->band) { + case IEEE80211_BAND_2GHZ: + f = channel->center_freq - 2300; + cal_freq_pier = ar->eeprom.cal_freq_pier_2G; + i = AR5416_NUM_2G_CAL_PIERS - 1; + break; + + case IEEE80211_BAND_5GHZ: + f = (channel->center_freq - 4800) / 5; + cal_freq_pier = ar->eeprom.cal_freq_pier_5G; + i = AR5416_NUM_5G_CAL_PIERS - 1; + break; + + default: + return -EINVAL; + break; + } + + for (; i >= 0; i--) { + if (cal_freq_pier[i] != 0xff) + break; + } + if (i < 0) + return -EINVAL; + + idx = ar9170_find_freq_idx(i, cal_freq_pier, f); + + ar9170_regwrite_begin(ar); + + for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) { + for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) { + struct ar9170_calibration_data_per_freq *cal_pier_data; + int j; + + switch (channel->band) { + case IEEE80211_BAND_2GHZ: + cal_pier_data = &ar->eeprom. + cal_pier_data_2G[chain][idx]; + break; + + case IEEE80211_BAND_5GHZ: + cal_pier_data = &ar->eeprom. + cal_pier_data_5G[chain][idx]; + break; + + default: + return -EINVAL; + } + + for (j = 0; j < 2; j++) { + vpds[j][i] = ar9170_interpolate_u8(f, + cal_freq_pier[idx], + cal_pier_data->vpd_pdg[j][i], + cal_freq_pier[idx + 1], + cal_pier_data[1].vpd_pdg[j][i]); + + pwrs[j][i] = ar9170_interpolate_u8(f, + cal_freq_pier[idx], + cal_pier_data->pwr_pdg[j][i], + cal_freq_pier[idx + 1], + cal_pier_data[1].pwr_pdg[j][i]) / 2; + } + } + + for (i = 0; i < 76; i++) { + u32 phy_data; + u8 tmp; + + if (i < 25) { + tmp = ar9170_interpolate_val(i, &pwrs[0][0], + &vpds[0][0]); + } else { + tmp = ar9170_interpolate_val(i - 12, + &pwrs[1][0], + &vpds[1][0]); + } + + phy_data |= tmp << ((i & 3) << 3); + if ((i & 3) == 3) { + ar9170_regwrite(0x1c6280 + chain * 0x1000 + + (i & ~3), phy_data); + phy_data = 0; + } + } + + for (i = 19; i < 32; i++) + ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2), + 0x0); + } + + ar9170_regwrite_finish(); + return ar9170_regwrite_result(); +} + static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) { struct ar9170_calibration_target_power_legacy *ctpl; @@ -1340,6 +1458,10 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, if (err) return err; + err = ar9170_set_freq_cal_data(ar, channel); + if (err) + return err; + err = ar9170_set_power_cal(ar, channel->center_freq, bw); if (err) return err; -- cgit v0.10.2 From b275f28535fc774325bb8ad5f664e6c44a8fbc9b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 1 Sep 2009 08:53:49 -0700 Subject: wireless: update cfg80211 kconfig entry cfg80211 is now *the* wireless configuration API. Lets also give a little explanation as to what it is and refer people to the wireless wiki for more information. Cc: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 68c504f..abf7ca3 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -1,6 +1,15 @@ config CFG80211 - tristate "Improved wireless configuration API" + tristate "cfg80211 - wireless configuration API" depends on RFKILL || !RFKILL + ---help--- + cfg80211 is the Linux wireless LAN (802.11) configuration API. + Enable this if you have a wireless device. + + For more information refer to documentation on the wireless wiki: + + http://wireless.kernel.org/en/developers/Documentation/cfg80211 + + When built as a module it will be called cfg80211. config NL80211_TESTMODE bool "nl80211 testmode command" -- cgit v0.10.2 From 36dbd9548e92268127b0c31b0e121e63e9207108 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:51:29 +0200 Subject: b43: Use a threaded IRQ handler Use a threaded IRQ handler to allow locking the mutex and sleeping while executing an interrupt. This removes usage of the irq_lock spinlock, but introduces a new hardirq_lock, which is _only_ used for the PCI/SSB lowlevel hard-irq handler. Sleeping busses (SDIO) will use mutex instead. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index a1b3b73..d63af92 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -616,6 +616,12 @@ struct b43_wl { /* Pointer to the ieee80211 hardware data structure */ struct ieee80211_hw *hw; + /* Global driver mutex. Every operation must run with this mutex locked. */ + struct mutex mutex; + /* Hard-IRQ spinlock. This lock protects things used in the hard-IRQ + * handler, only. This basically is just the IRQ mask register. */ + spinlock_t hardirq_lock; + /* The number of queues that were registered with the mac80211 subsystem * initially. This is a backup copy of hw->queues in case hw->queues has * to be dynamically lowered at runtime (Firmware does not support QoS). @@ -623,8 +629,6 @@ struct b43_wl { * from the mac80211 subsystem. */ u16 mac80211_initially_registered_queues; - struct mutex mutex; - spinlock_t irq_lock; /* R/W lock for data transmission. * Transmissions on 2+ queues can run concurrently, but somebody else * might sync with TX by write_lock_irqsave()'ing. */ @@ -665,8 +669,7 @@ struct b43_wl { bool radiotap_enabled; bool radio_enabled; - /* The beacon we are currently using (AP or IBSS mode). - * This beacon stuff is protected by the irq_lock. */ + /* The beacon we are currently using (AP or IBSS mode). */ struct sk_buff *current_beacon; bool beacon0_uploaded; bool beacon1_uploaded; @@ -754,14 +757,6 @@ enum { smp_wmb(); \ } while (0) -/* XXX--- HOW LOCKING WORKS IN B43 ---XXX - * - * You should always acquire both, wl->mutex and wl->irq_lock unless: - * - You don't need to acquire wl->irq_lock, if the interface is stopped. - * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet - * and packet TX path (and _ONLY_ there.) - */ - /* Data structure for one wireless device (802.11 core) */ struct b43_wldev { struct ssb_device *dev; @@ -807,14 +802,12 @@ struct b43_wldev { u32 dma_reason[6]; /* The currently active generic-interrupt mask. */ u32 irq_mask; + /* Link Quality calculation context. */ struct b43_noise_calculation noisecalc; /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ int mac_suspended; - /* Interrupt Service Routine tasklet (bottom-half) */ - struct tasklet_struct isr_tasklet; - /* Periodic tasks */ struct delayed_work periodic_work; unsigned int periodic_state; diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 45e3d6a..bf23a3a 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -46,8 +46,6 @@ struct b43_debugfs_fops { struct file_operations fops; /* Offset of struct b43_dfs_file in struct b43_dfsentry */ size_t file_struct_offset; - /* Take wl->irq_lock before calling read/write? */ - bool take_irqlock; }; static inline @@ -372,14 +370,12 @@ static ssize_t txstat_read_file(struct b43_wldev *dev, { struct b43_txstatus_log *log = &dev->dfsentry->txstatlog; ssize_t count = 0; - unsigned long flags; int i, idx; struct b43_txstatus *stat; - spin_lock_irqsave(&log->lock, flags); if (log->end < 0) { fappend("Nothing transmitted, yet\n"); - goto out_unlock; + goto out; } fappend("b43 TX status reports:\n\n" "index | cookie | seq | phy_stat | frame_count | " @@ -409,13 +405,11 @@ static ssize_t txstat_read_file(struct b43_wldev *dev, break; i++; } -out_unlock: - spin_unlock_irqrestore(&log->lock, flags); +out: return count; } -/* wl->irq_lock is locked */ static int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count) { @@ -556,12 +550,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, goto out_unlock; } memset(buf, 0, bufsize); - if (dfops->take_irqlock) { - spin_lock_irq(&dev->wl->irq_lock); - ret = dfops->read(dev, buf, bufsize); - spin_unlock_irq(&dev->wl->irq_lock); - } else - ret = dfops->read(dev, buf, bufsize); + ret = dfops->read(dev, buf, bufsize); if (ret <= 0) { free_pages((unsigned long)buf, buforder); err = ret; @@ -623,12 +612,7 @@ static ssize_t b43_debugfs_write(struct file *file, err = -EFAULT; goto out_freepage; } - if (dfops->take_irqlock) { - spin_lock_irq(&dev->wl->irq_lock); - err = dfops->write(dev, buf, count); - spin_unlock_irq(&dev->wl->irq_lock); - } else - err = dfops->write(dev, buf, count); + err = dfops->write(dev, buf, count); if (err) goto out_freepage; @@ -641,7 +625,7 @@ out_unlock: } -#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \ +#define B43_DEBUGFS_FOPS(name, _read, _write) \ static struct b43_debugfs_fops fops_##name = { \ .read = _read, \ .write = _write, \ @@ -652,20 +636,19 @@ out_unlock: }, \ .file_struct_offset = offsetof(struct b43_dfsentry, \ file_##name), \ - .take_irqlock = _take_irqlock, \ } -B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1); -B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1); -B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1); -B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1); -B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1); -B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1); -B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1); -B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1); -B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); -B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); -B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0); +B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file); +B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file); +B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file); +B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file); +B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file); +B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file); +B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file); +B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file); +B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL); +B43_DEBUGFS_FOPS(restart, NULL, restart_write_file); +B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL); bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) @@ -738,7 +721,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev) return; } log->end = -1; - spin_lock_init(&log->lock); dev->dfsentry = e; @@ -822,7 +804,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) kfree(e); } -/* Called with IRQs disabled. */ void b43_debugfs_log_txstat(struct b43_wldev *dev, const struct b43_txstatus *status) { @@ -834,14 +815,12 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev, if (!e) return; log = &e->txstatlog; - spin_lock(&log->lock); /* IRQs are already disabled. */ i = log->end + 1; if (i == B43_NR_LOGGED_TXSTATUS) i = 0; log->end = i; cur = &(log->log[i]); memcpy(cur, status, sizeof(*cur)); - spin_unlock(&log->lock); } void b43_debugfs_init(void) diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h index b9d4de4..e47b4b4 100644 --- a/drivers/net/wireless/b43/debugfs.h +++ b/drivers/net/wireless/b43/debugfs.h @@ -23,9 +23,10 @@ struct dentry; #define B43_NR_LOGGED_TXSTATUS 100 struct b43_txstatus_log { + /* This structure is protected by wl->mutex */ + struct b43_txstatus *log; int end; - spinlock_t lock; }; struct b43_dfs_file { diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 289aaf6..25ced8b 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1387,7 +1387,6 @@ out_unlock: return err; } -/* Called with IRQs disabled. */ void b43_dma_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status) { @@ -1402,7 +1401,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, if (unlikely(!ring)) return; - spin_lock(&ring->lock); /* IRQs are already disabled. */ + spin_lock_irq(&ring->lock); B43_WARN_ON(!ring->tx); ops = ring->ops; @@ -1463,7 +1462,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, } } - spin_unlock(&ring->lock); + spin_unlock_irq(&ring->lock); } void b43_dma_get_tx_stats(struct b43_wldev *dev, diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ae05f66..80b6884 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -291,7 +291,7 @@ static struct ieee80211_supported_band b43_band_2GHz = { static void b43_wireless_core_exit(struct b43_wldev *dev); static int b43_wireless_core_init(struct b43_wldev *dev); -static void b43_wireless_core_stop(struct b43_wldev *dev); +static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev); static int b43_wireless_core_start(struct b43_wldev *dev); static int b43_ratelimit(struct b43_wl *wl) @@ -685,16 +685,6 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) b43_set_slot_time(dev, 20); } -/* Synchronize IRQ top- and bottom-half. - * IRQs must be masked before calling this. - * This must not be called with the irq_lock held. - */ -static void b43_synchronize_irq(struct b43_wldev *dev) -{ - synchronize_irq(dev->dev->irq); - tasklet_kill(&dev->isr_tasklet); -} - /* DummyTransmission function, as documented on * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission */ @@ -720,8 +710,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) buffer[0] = 0x000B846E; } - spin_lock_irq(&wl->irq_lock); - write_lock(&wl->tx_lock); + write_lock_irq(&wl->tx_lock); for (i = 0; i < 5; i++) b43_ram_write(dev, i * 4, buffer[i]); @@ -779,8 +768,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) b43_radio_write16(dev, 0x0051, 0x0037); - write_unlock(&wl->tx_lock); - spin_unlock_irq(&wl->irq_lock); + write_unlock_irq(&wl->tx_lock); } static void key_write(struct b43_wldev *dev, @@ -1620,6 +1608,27 @@ static void handle_irq_beacon(struct b43_wldev *dev) } } +static void b43_do_beacon_update_trigger_work(struct b43_wldev *dev) +{ + u32 old_irq_mask = dev->irq_mask; + + /* update beacon right away or defer to irq */ + handle_irq_beacon(dev); + if (old_irq_mask != dev->irq_mask) { + /* The handler updated the IRQ mask. */ + B43_WARN_ON(!dev->irq_mask); + if (b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)) { + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); + } else { + /* Device interrupts are currently disabled. That means + * we just ran the hardirq handler and scheduled the + * IRQ thread. The thread will write the IRQ mask when + * it finished, so there's nothing to do here. Writing + * the mask _here_ would incorrectly re-enable IRQs. */ + } + } +} + static void b43_beacon_update_trigger_work(struct work_struct *work) { struct b43_wl *wl = container_of(work, struct b43_wl, @@ -1629,19 +1638,22 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) mutex_lock(&wl->mutex); dev = wl->current_dev; if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { - spin_lock_irq(&wl->irq_lock); - /* update beacon right away or defer to irq */ - handle_irq_beacon(dev); - /* The handler might have updated the IRQ mask. */ - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); - mmiowb(); - spin_unlock_irq(&wl->irq_lock); + if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { + /* wl->mutex is enough. */ + b43_do_beacon_update_trigger_work(dev); + mmiowb(); + } else { + spin_lock_irq(&wl->hardirq_lock); + b43_do_beacon_update_trigger_work(dev); + mmiowb(); + spin_unlock_irq(&wl->hardirq_lock); + } } mutex_unlock(&wl->mutex); } /* Asynchronously update the packet templates in template RAM. - * Locking: Requires wl->irq_lock to be locked. */ + * Locking: Requires wl->mutex to be locked. */ static void b43_update_templates(struct b43_wl *wl) { struct sk_buff *beacon; @@ -1778,18 +1790,15 @@ out: B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK); } -/* Interrupt handler bottom-half */ -static void b43_interrupt_tasklet(struct b43_wldev *dev) +static void b43_do_interrupt_thread(struct b43_wldev *dev) { u32 reason; u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; u32 merged_dma_reason = 0; int i; - unsigned long flags; - - spin_lock_irqsave(&dev->wl->irq_lock, flags); - B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED); + if (unlikely(b43_status(dev) != B43_STAT_STARTED)) + return; reason = dev->irq_reason; for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { @@ -1822,8 +1831,6 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) dma_reason[2], dma_reason[3], dma_reason[4], dma_reason[5]); b43_controller_restart(dev, "DMA error"); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); return; } if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { @@ -1867,47 +1874,36 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) if (reason & B43_IRQ_TX_OK) handle_irq_transmit_status(dev); + /* Re-enable interrupts on the device by restoring the current interrupt mask. */ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } -static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason) +/* Interrupt thread handler. Handles device interrupts in thread context. */ +static irqreturn_t b43_interrupt_thread_handler(int irq, void *dev_id) { - b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); + struct b43_wldev *dev = dev_id; - b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); - b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); - b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); - b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); - b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); -/* Unused ring - b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); -*/ + mutex_lock(&dev->wl->mutex); + b43_do_interrupt_thread(dev); + mmiowb(); + mutex_unlock(&dev->wl->mutex); + + return IRQ_HANDLED; } -/* Interrupt handler top-half */ -static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) +static irqreturn_t b43_do_interrupt(struct b43_wldev *dev) { - irqreturn_t ret = IRQ_NONE; - struct b43_wldev *dev = dev_id; u32 reason; - B43_WARN_ON(!dev); + /* This code runs under wl->hardirq_lock, but _only_ on non-SDIO busses. + * On SDIO, this runs under wl->mutex. */ - spin_lock(&dev->wl->irq_lock); - - if (unlikely(b43_status(dev) < B43_STAT_STARTED)) { - /* This can only happen on shared IRQ lines. */ - goto out; - } reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) /* shared IRQ */ - goto out; - ret = IRQ_HANDLED; + return IRQ_NONE; reason &= dev->irq_mask; if (!reason) - goto out; + return IRQ_HANDLED; dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON) & 0x0001DC00; @@ -1924,15 +1920,38 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) & 0x0000DC00; */ - b43_interrupt_ack(dev, reason); - /* disable all IRQs. They are enabled again in the bottom half. */ + /* ACK the interrupt. */ + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); + b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); + b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); + b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); + b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); + b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); +/* Unused ring + b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); +*/ + + /* Disable IRQs on the device. The IRQ thread handler will re-enable them. */ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); - /* save the reason code and call our bottom half. */ + /* Save the reason bitmasks for the IRQ thread handler. */ dev->irq_reason = reason; - tasklet_schedule(&dev->isr_tasklet); -out: + + return IRQ_WAKE_THREAD; +} + +/* Interrupt handler top-half. This runs with interrupts disabled. */ +static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) +{ + struct b43_wldev *dev = dev_id; + irqreturn_t ret; + + if (unlikely(b43_status(dev) < B43_STAT_STARTED)) + return IRQ_NONE; + + spin_lock(&dev->wl->hardirq_lock); + ret = b43_do_interrupt(dev); mmiowb(); - spin_unlock(&dev->wl->irq_lock); + spin_unlock(&dev->wl->hardirq_lock); return ret; } @@ -3038,15 +3057,12 @@ static void b43_security_init(struct b43_wldev *dev) static int b43_rng_read(struct hwrng *rng, u32 *data) { struct b43_wl *wl = (struct b43_wl *)rng->priv; - unsigned long flags; - /* Don't take wl->mutex here, as it could deadlock with - * hwrng internal locking. It's not needed to take - * wl->mutex here, anyway. */ + /* FIXME: We need to take wl->mutex here to make sure the device + * is not going away from under our ass. However it could deadlock + * with hwrng internal locking. */ - spin_lock_irqsave(&wl->irq_lock, flags); *data = b43_read16(wl->current_dev, B43_MMIO_RNG); - spin_unlock_irqrestore(&wl->irq_lock, flags); return (sizeof(u16)); } @@ -3283,22 +3299,20 @@ static int b43_op_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; - unsigned long flags; + struct b43_wldev *dev; int err = -ENODEV; - if (!dev) - goto out; - spin_lock_irqsave(&wl->irq_lock, flags); - if (likely(b43_status(dev) >= B43_STAT_STARTED)) { + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (dev && b43_status(dev) >= B43_STAT_STARTED) { if (b43_using_pio_transfers(dev)) b43_pio_get_tx_stats(dev, stats); else b43_dma_get_tx_stats(dev, stats); err = 0; } - spin_unlock_irqrestore(&wl->irq_lock, flags); -out: + mutex_unlock(&wl->mutex); + return err; } @@ -3306,11 +3320,10 @@ static int b43_op_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { struct b43_wl *wl = hw_to_b43_wl(hw); - unsigned long flags; - spin_lock_irqsave(&wl->irq_lock, flags); + mutex_lock(&wl->mutex); memcpy(stats, &wl->ieee_stats, sizeof(*stats)); - spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); return 0; } @@ -3322,7 +3335,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) u64 tsf; mutex_lock(&wl->mutex); - spin_lock_irq(&wl->irq_lock); dev = wl->current_dev; if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) @@ -3330,7 +3342,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) else tsf = 0; - spin_unlock_irq(&wl->irq_lock); mutex_unlock(&wl->mutex); return tsf; @@ -3342,13 +3353,11 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) struct b43_wldev *dev; mutex_lock(&wl->mutex); - spin_lock_irq(&wl->irq_lock); dev = wl->current_dev; if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) b43_tsf_write(dev, tsf); - spin_unlock_irq(&wl->irq_lock); mutex_unlock(&wl->mutex); } @@ -3434,7 +3443,7 @@ static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan) prev_status = b43_status(down_dev); /* Shutdown the currently running core. */ if (prev_status >= B43_STAT_STARTED) - b43_wireless_core_stop(down_dev); + down_dev = b43_wireless_core_stop(down_dev); if (prev_status >= B43_STAT_INITIALIZED) b43_wireless_core_exit(down_dev); @@ -3498,7 +3507,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) struct b43_wldev *dev; struct b43_phy *phy; struct ieee80211_conf *conf = &hw->conf; - unsigned long flags; int antenna; int err = 0; @@ -3529,13 +3537,11 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) /* Adjust the desired TX power level. */ if (conf->power_level != 0) { - spin_lock_irqsave(&wl->irq_lock, flags); if (conf->power_level != phy->desired_txpower) { phy->desired_txpower = conf->power_level; b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME | B43_TXPWR_IGNORE_TSSI); } - spin_unlock_irqrestore(&wl->irq_lock, flags); } /* Antennas for RX and management frame TX. */ @@ -3620,7 +3626,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; - unsigned long flags; mutex_lock(&wl->mutex); @@ -3630,7 +3635,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, B43_WARN_ON(wl->vif != vif); - spin_lock_irqsave(&wl->irq_lock, flags); if (changed & BSS_CHANGED_BSSID) { if (conf->bssid) memcpy(wl->bssid, conf->bssid, ETH_ALEN); @@ -3648,7 +3652,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID) b43_write_mac_bssid_templates(dev); } - spin_unlock_irqrestore(&wl->irq_lock, flags); b43_mac_suspend(dev); @@ -3683,18 +3686,15 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, u8 algorithm; u8 index; int err; + unsigned long flags; static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ mutex_lock(&wl->mutex); - spin_lock_irq(&wl->irq_lock); - write_lock(&wl->tx_lock); - /* Why do we need all this locking here? - * mutex -> Every config operation must take it. - * irq_lock -> We modify the dev->key array, which is accessed - * in the IRQ handlers. + write_lock_irqsave(&wl->tx_lock, flags); + /* mutex -> Every config operation must take it. * tx_lock -> We modify the dev->key array, which is accessed * in the TX handler. */ @@ -3789,8 +3789,7 @@ out_unlock: sta ? sta->addr : bcast_addr); b43_dump_keymemory(dev); } - write_unlock(&wl->tx_lock); - spin_unlock_irq(&wl->irq_lock); + write_unlock_irqrestore(&wl->tx_lock, flags); mutex_unlock(&wl->mutex); return err; @@ -3801,15 +3800,15 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; - unsigned long flags; + struct b43_wldev *dev; + mutex_lock(&wl->mutex); + dev = wl->current_dev; if (!dev) { *fflags = 0; - return; + goto out_unlock; } - spin_lock_irqsave(&wl->irq_lock, flags); *fflags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | @@ -3830,41 +3829,66 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, if (changed && b43_status(dev) >= B43_STAT_INITIALIZED) b43_adjust_opmode(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); + +out_unlock: + mutex_unlock(&wl->mutex); } -/* Locking: wl->mutex */ -static void b43_wireless_core_stop(struct b43_wldev *dev) +/* Locking: wl->mutex + * Returns the current dev. This might be different from the passed in dev, + * because the core might be gone away while we unlocked the mutex. */ +static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; - unsigned long flags; + struct b43_wldev *orig_dev; - if (b43_status(dev) < B43_STAT_STARTED) - return; +redo: + if (!dev || b43_status(dev) < B43_STAT_STARTED) + return dev; - /* Disable and sync interrupts. We must do this before than - * setting the status to INITIALIZED, as the interrupt handler - * won't care about IRQs then. */ - spin_lock_irqsave(&wl->irq_lock, flags); - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); - b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */ - spin_unlock_irqrestore(&wl->irq_lock, flags); - b43_synchronize_irq(dev); + /* Disable periodic work. Unlock to avoid deadlocks. */ + mutex_unlock(&wl->mutex); + cancel_delayed_work_sync(&dev->periodic_work); + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (!dev || b43_status(dev) < B43_STAT_STARTED) { + /* Whoops, aliens ate up the device while we were unlocked. */ + return dev; + } - write_lock_irqsave(&wl->tx_lock, flags); + /* Disable interrupts on the device. */ b43_set_status(dev, B43_STAT_INITIALIZED); - write_unlock_irqrestore(&wl->tx_lock, flags); - - b43_pio_stop(dev); + if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { + /* wl->mutex is locked. That is enough. */ + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); + b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ + } else { + spin_lock_irq(&wl->hardirq_lock); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); + b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ + spin_unlock_irq(&wl->hardirq_lock); + } + /* Synchronize the interrupt handlers. Unlock to avoid deadlocks. */ + orig_dev = dev; mutex_unlock(&wl->mutex); - /* Must unlock as it would otherwise deadlock. No races here. - * Cancel the possibly running self-rearming periodic work. */ - cancel_delayed_work_sync(&dev->periodic_work); + synchronize_irq(dev->dev->irq); mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (!dev) + return dev; + if (dev != orig_dev) { + if (b43_status(dev) >= B43_STAT_STARTED) + goto redo; + return dev; + } + B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)); + b43_pio_stop(dev); b43_mac_suspend(dev); free_irq(dev->dev->irq, dev); b43dbg(wl, "Wireless interface stopped\n"); + + return dev; } /* Locking: wl->mutex */ @@ -3875,8 +3899,9 @@ static int b43_wireless_core_start(struct b43_wldev *dev) B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); drain_txstatus_queue(dev); - err = request_irq(dev->dev->irq, b43_interrupt_handler, - IRQF_SHARED, KBUILD_MODNAME, dev); + err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, + b43_interrupt_thread_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); if (err) { b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); goto out; @@ -4155,8 +4180,8 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) { u32 macctl; - B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); - if (b43_status(dev) != B43_STAT_INITIALIZED) + B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED); + if (!dev || b43_status(dev) != B43_STAT_INITIALIZED) return; b43_set_status(dev, B43_STAT_UNINIT); @@ -4309,7 +4334,6 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; - unsigned long flags; int err = -EOPNOTSUPP; /* TODO: allow WDS/AP devices to coexist */ @@ -4333,12 +4357,10 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, wl->if_type = conf->type; memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); - spin_lock_irqsave(&wl->irq_lock, flags); b43_adjust_opmode(dev); b43_set_pretbtt(dev); b43_set_synth_pu_delay(dev, 0); b43_upload_card_macaddress(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); err = 0; out_mutex_unlock: @@ -4352,7 +4374,6 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; - unsigned long flags; b43dbg(wl, "Removing Interface type %d\n", conf->type); @@ -4364,11 +4385,9 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw, wl->operating = 0; - spin_lock_irqsave(&wl->irq_lock, flags); b43_adjust_opmode(dev); memset(wl->mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); } @@ -4428,10 +4447,15 @@ static void b43_op_stop(struct ieee80211_hw *hw) cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); - if (b43_status(dev) >= B43_STAT_STARTED) - b43_wireless_core_stop(dev); + if (b43_status(dev) >= B43_STAT_STARTED) { + dev = b43_wireless_core_stop(dev); + if (!dev) + goto out_unlock; + } b43_wireless_core_exit(dev); wl->radio_enabled = 0; + +out_unlock: mutex_unlock(&wl->mutex); cancel_work_sync(&(wl->txpower_adjust_work)); @@ -4441,11 +4465,10 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { struct b43_wl *wl = hw_to_b43_wl(hw); - unsigned long flags; - spin_lock_irqsave(&wl->irq_lock, flags); + mutex_lock(&wl->mutex); b43_update_templates(wl); - spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); return 0; } @@ -4526,8 +4549,13 @@ static void b43_chip_reset(struct work_struct *work) prev_status = b43_status(dev); /* Bring the device down... */ - if (prev_status >= B43_STAT_STARTED) - b43_wireless_core_stop(dev); + if (prev_status >= B43_STAT_STARTED) { + dev = b43_wireless_core_stop(dev); + if (!dev) { + err = -ENODEV; + goto out; + } + } if (prev_status >= B43_STAT_INITIALIZED) b43_wireless_core_exit(dev); @@ -4742,9 +4770,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) wldev->wl = wl; b43_set_status(wldev, B43_STAT_UNINIT); wldev->bad_frames_preempt = modparam_bad_frames_preempt; - tasklet_init(&wldev->isr_tasklet, - (void (*)(unsigned long))b43_interrupt_tasklet, - (unsigned long)wldev); INIT_LIST_HEAD(&wldev->list); err = b43_wireless_core_attach(wldev); @@ -4841,11 +4866,11 @@ static int b43_wireless_init(struct ssb_device *dev) /* Initialize struct b43_wl */ wl->hw = hw; - spin_lock_init(&wl->irq_lock); rwlock_init(&wl->tx_lock); spin_lock_init(&wl->leds_lock); spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); + spin_lock_init(&wl->hardirq_lock); INIT_LIST_HEAD(&wl->devlist); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); @@ -4946,8 +4971,8 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state) wldev->suspend_in_progress = true; wldev->suspend_init_status = b43_status(wldev); if (wldev->suspend_init_status >= B43_STAT_STARTED) - b43_wireless_core_stop(wldev); - if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) + wldev = b43_wireless_core_stop(wldev); + if (wldev && wldev->suspend_init_status >= B43_STAT_INITIALIZED) b43_wireless_core_exit(wldev); mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 6e704be..75b26e1 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -347,7 +347,6 @@ void b43_phy_txpower_adjust_work(struct work_struct *work) mutex_unlock(&wl->mutex); } -/* Called with wl->irq_lock locked */ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) { struct b43_phy *phy = &dev->phy; diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 28e3846..9edd4e8 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -131,7 +131,7 @@ enum b43_txpwr_result { * If the parameter "ignore_tssi" is true, the TSSI values should * be ignored and a recalculation of the power settings should be * done even if the TSSI values did not change. - * This callback is called with wl->irq_lock held and must not sleep. + * This function may sleep, but should not. * Must not be NULL. * @adjust_txpower: Write the previously calculated TX power settings * (from @recalc_txpower) to the hardware. @@ -379,7 +379,6 @@ void b43_software_rfkill(struct b43_wldev *dev, bool blocked); * * Compare the current TX power output to the desired power emission * and schedule an adjustment in case it mismatches. - * Requires wl->irq_lock locked. * * @flags: OR'ed enum b43_phy_txpower_check_flags flags. * See the docs below. diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 5afa4df..382826a 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2823,8 +2823,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) b43_mac_suspend(dev); - spin_lock_irq(&dev->wl->irq_lock); - /* Calculate the new attenuation values. */ bbatt = gphy->bbatt.att; bbatt += gphy->bbatt_delta; @@ -2864,11 +2862,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) gphy->rfatt.att = rfatt; gphy->bbatt.att = bbatt; - /* We drop the lock early, so we can sleep during hardware - * adjustment. Possible races with op_recalc_txpower are harmless, - * as we will be called once again in case we raced. */ - spin_unlock_irq(&dev->wl->irq_lock); - if (b43_debug(dev, B43_DBG_XMITPOWER)) b43dbg(dev->wl, "Adjusting TX power\n"); diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h index 718947f..8569fdd 100644 --- a/drivers/net/wireless/b43/phy_g.h +++ b/drivers/net/wireless/b43/phy_g.h @@ -141,8 +141,7 @@ struct b43_phy_g { int tgt_idle_tssi; /* Current idle TSSI */ int cur_idle_tssi; - /* The current average TSSI. - * Needs irq_lock, as it's updated in the IRQ path. */ + /* The current average TSSI. */ u8 average_tssi; /* Current TX power level attenuation control values */ struct b43_bbatt bbatt; diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 3fd653c..ce6f36e 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -570,7 +570,6 @@ out_unlock: return err; } -/* Called with IRQs disabled. */ void b43_pio_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status) { @@ -584,7 +583,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, return; B43_WARN_ON(!pack); - spin_lock(&q->lock); /* IRQs are already disabled. */ + spin_lock_irq(&q->lock); info = IEEE80211_SKB_CB(pack->skb); @@ -604,7 +603,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, q->stopped = 0; } - spin_unlock(&q->lock); + spin_unlock_irq(&q->lock); } void b43_pio_get_tx_stats(struct b43_wldev *dev, diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index 5adaa36..f1ae4e0 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -94,7 +94,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, const char *buf, size_t count) { struct b43_wldev *wldev = dev_to_b43_wldev(dev); - unsigned long flags; int err; int mode; @@ -120,7 +119,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, } mutex_lock(&wldev->wl->mutex); - spin_lock_irqsave(&wldev->wl->irq_lock, flags); if (wldev->phy.ops->interf_mitigation) { err = wldev->phy.ops->interf_mitigation(wldev, mode); @@ -132,7 +130,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, err = -ENOSYS; mmiowb(); - spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); mutex_unlock(&wldev->wl->mutex); return err ? err : count; -- cgit v0.10.2 From f5d40eedb32aa9a0e226d468e1f89fb676824694 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:53:18 +0200 Subject: b43: Remove TX spinlock This removes the TX spinlock and defers TX to a workqueue to allow locking wl->mutex instead and to allow sleeping for register accesses. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index d63af92..1cd470d 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -683,6 +683,11 @@ struct b43_wl { * This is scheduled when we determine that the actual TX output * power doesn't match what we want. */ struct work_struct txpower_adjust_work; + + /* Packet transmit work */ + struct work_struct tx_work; + /* Queue of packets to be transmitted. */ + struct sk_buff_head tx_queue; }; /* The type of the firmware file. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 80b6884..fca2fe9 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -690,7 +690,6 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) */ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) { - struct b43_wl *wl = dev->wl; struct b43_phy *phy = &dev->phy; unsigned int i, max_loop; u16 value; @@ -710,8 +709,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) buffer[0] = 0x000B846E; } - write_lock_irq(&wl->tx_lock); - for (i = 0; i < 5; i++) b43_ram_write(dev, i * 4, buffer[i]); @@ -767,8 +764,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) } if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) b43_radio_write16(dev, 0x0051, 0x0037); - - write_unlock_irq(&wl->tx_lock); } static void key_write(struct b43_wldev *dev, @@ -3098,42 +3093,49 @@ static int b43_rng_init(struct b43_wl *wl) return err; } -static int b43_op_tx(struct ieee80211_hw *hw, - struct sk_buff *skb) +static void b43_tx_work(struct work_struct *work) { - struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; - unsigned long flags; - int err; + struct b43_wl *wl = container_of(work, struct b43_wl, tx_work); + struct b43_wldev *dev; + struct sk_buff *skb; + int err = 0; - if (unlikely(skb->len < 2 + 2 + 6)) { - /* Too short, this can't be a valid frame. */ - goto drop_packet; + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED)) { + mutex_unlock(&wl->mutex); + return; } - B43_WARN_ON(skb_shinfo(skb)->nr_frags); - if (unlikely(!dev)) - goto drop_packet; - /* Transmissions on seperate queues can run concurrently. */ - read_lock_irqsave(&wl->tx_lock, flags); + while (skb_queue_len(&wl->tx_queue)) { + skb = skb_dequeue(&wl->tx_queue); - err = -ENODEV; - if (likely(b43_status(dev) >= B43_STAT_STARTED)) { if (b43_using_pio_transfers(dev)) err = b43_pio_tx(dev, skb); else err = b43_dma_tx(dev, skb); + if (unlikely(err)) + dev_kfree_skb(skb); /* Drop it */ } - read_unlock_irqrestore(&wl->tx_lock, flags); + mutex_unlock(&wl->mutex); +} - if (unlikely(err)) - goto drop_packet; - return NETDEV_TX_OK; +static int b43_op_tx(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + + if (unlikely(skb->len < 2 + 2 + 6)) { + /* Too short, this can't be a valid frame. */ + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + B43_WARN_ON(skb_shinfo(skb)->nr_frags); + + skb_queue_tail(&wl->tx_queue, skb); + ieee80211_queue_work(wl->hw, &wl->tx_work); -drop_packet: - /* We can not transmit this packet. Drop it. */ - dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -3686,18 +3688,12 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, u8 algorithm; u8 index; int err; - unsigned long flags; static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ mutex_lock(&wl->mutex); - write_lock_irqsave(&wl->tx_lock, flags); - /* mutex -> Every config operation must take it. - * tx_lock -> We modify the dev->key array, which is accessed - * in the TX handler. - */ dev = wl->current_dev; err = -ENODEV; @@ -3789,7 +3785,6 @@ out_unlock: sta ? sta->addr : bcast_addr); b43_dump_keymemory(dev); } - write_unlock_irqrestore(&wl->tx_lock, flags); mutex_unlock(&wl->mutex); return err; @@ -3846,9 +3841,10 @@ redo: if (!dev || b43_status(dev) < B43_STAT_STARTED) return dev; - /* Disable periodic work. Unlock to avoid deadlocks. */ + /* Cancel work. Unlock to avoid deadlocks. */ mutex_unlock(&wl->mutex); cancel_delayed_work_sync(&dev->periodic_work); + cancel_work_sync(&wl->tx_work); mutex_lock(&wl->mutex); dev = wl->current_dev; if (!dev || b43_status(dev) < B43_STAT_STARTED) { @@ -3883,6 +3879,10 @@ redo: } B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)); + /* Drain the TX queue */ + while (skb_queue_len(&wl->tx_queue)) + dev_kfree_skb(skb_dequeue(&wl->tx_queue)); + b43_pio_stop(dev); b43_mac_suspend(dev); free_irq(dev->dev->irq, dev); @@ -4866,7 +4866,6 @@ static int b43_wireless_init(struct ssb_device *dev) /* Initialize struct b43_wl */ wl->hw = hw; - rwlock_init(&wl->tx_lock); spin_lock_init(&wl->leds_lock); spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); @@ -4874,6 +4873,8 @@ static int b43_wireless_init(struct ssb_device *dev) INIT_LIST_HEAD(&wl->devlist); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); + INIT_WORK(&wl->tx_work, b43_tx_work); + skb_queue_head_init(&wl->tx_queue); ssb_set_devtypedata(dev, wl); b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n", -- cgit v0.10.2 From 637dae3f637eb7dab447e74362e0dfeded775c7c Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:55:00 +0200 Subject: b43: Remove DMA/PIO queue locks This removes the DMA/PIO queue locks. Locking is handled by wl->mutex now. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 25ced8b..a467ee2 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -856,7 +856,6 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, } else B43_WARN_ON(1); } - spin_lock_init(&ring->lock); #ifdef CONFIG_B43_DEBUG ring->last_injected_overflow = jiffies; #endif @@ -1315,7 +1314,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) struct b43_dmaring *ring; struct ieee80211_hdr *hdr; int err = 0; - unsigned long flags; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; @@ -1331,8 +1329,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) dev, skb_get_queue_mapping(skb)); } - spin_lock_irqsave(&ring->lock, flags); - B43_WARN_ON(!ring->tx); if (unlikely(ring->stopped)) { @@ -1343,7 +1339,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) if (b43_debug(dev, B43_DBG_DMAVERBOSE)) b43err(dev->wl, "Packet after queue stopped\n"); err = -ENOSPC; - goto out_unlock; + goto out; } if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) { @@ -1351,7 +1347,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) * full, but queues not stopped. */ b43err(dev->wl, "DMA queue overflow\n"); err = -ENOSPC; - goto out_unlock; + goto out; } /* Assign the queue number to the ring (if not already done before) @@ -1365,11 +1361,11 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) * anymore and must not transmit it unencrypted. */ dev_kfree_skb_any(skb); err = 0; - goto out_unlock; + goto out; } if (unlikely(err)) { b43err(dev->wl, "DMA tx mapping failure\n"); - goto out_unlock; + goto out; } ring->nr_tx_packets++; if ((free_slots(ring) < TX_SLOTS_PER_FRAME) || @@ -1381,8 +1377,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); } } -out_unlock: - spin_unlock_irqrestore(&ring->lock, flags); +out: return err; } @@ -1401,8 +1396,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, if (unlikely(!ring)) return; - spin_lock_irq(&ring->lock); - B43_WARN_ON(!ring->tx); ops = ring->ops; while (1) { @@ -1461,8 +1454,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); } } - - spin_unlock_irq(&ring->lock); } void b43_dma_get_tx_stats(struct b43_wldev *dev, @@ -1470,17 +1461,14 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_dmaring *ring; - unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { ring = select_ring_by_priority(dev, i); - spin_lock_irqsave(&ring->lock, flags); stats[i].len = ring->used_slots / TX_SLOTS_PER_FRAME; stats[i].limit = ring->nr_slots / TX_SLOTS_PER_FRAME; stats[i].count = ring->nr_tx_packets; - spin_unlock_irqrestore(&ring->lock, flags); } } @@ -1591,22 +1579,14 @@ void b43_dma_rx(struct b43_dmaring *ring) static void b43_dma_tx_suspend_ring(struct b43_dmaring *ring) { - unsigned long flags; - - spin_lock_irqsave(&ring->lock, flags); B43_WARN_ON(!ring->tx); ring->ops->tx_suspend(ring); - spin_unlock_irqrestore(&ring->lock, flags); } static void b43_dma_tx_resume_ring(struct b43_dmaring *ring) { - unsigned long flags; - - spin_lock_irqsave(&ring->lock, flags); B43_WARN_ON(!ring->tx); ring->ops->tx_resume(ring); - spin_unlock_irqrestore(&ring->lock, flags); } void b43_dma_tx_suspend(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index 05dde64..f0b0838 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -2,7 +2,6 @@ #define B43_DMA_H_ #include -#include #include "b43.h" @@ -244,8 +243,6 @@ struct b43_dmaring { /* The QOS priority assigned to this ring. Only used for TX rings. * This is the mac80211 "queue" value. */ u8 queue_prio; - /* Lock, only used for TX. */ - spinlock_t lock; struct b43_wldev *dev; #ifdef CONFIG_B43_DEBUG /* Maximum number of used slots. */ diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index ce6f36e..4635baa 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -144,7 +144,6 @@ static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev, q = kzalloc(sizeof(*q), GFP_KERNEL); if (!q) return NULL; - spin_lock_init(&q->lock); q->dev = dev; q->rev = dev->dev->id.revision; q->mmio_base = index_to_pioqueue_base(dev, index) + @@ -179,7 +178,6 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev, q = kzalloc(sizeof(*q), GFP_KERNEL); if (!q) return NULL; - spin_lock_init(&q->lock); q->dev = dev; q->rev = dev->dev->id.revision; q->mmio_base = index_to_pioqueue_base(dev, index) + @@ -494,7 +492,6 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_pio_txqueue *q; struct ieee80211_hdr *hdr; - unsigned long flags; unsigned int hdrlen, total_len; int err = 0; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -512,20 +509,18 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } - spin_lock_irqsave(&q->lock, flags); - hdrlen = b43_txhdr_size(dev); total_len = roundup(skb->len + hdrlen, 4); if (unlikely(total_len > q->buffer_size)) { err = -ENOBUFS; b43dbg(dev->wl, "PIO: TX packet longer than queue.\n"); - goto out_unlock; + goto out; } if (unlikely(q->free_packet_slots == 0)) { err = -ENOBUFS; b43warn(dev->wl, "PIO: TX packet overflow.\n"); - goto out_unlock; + goto out; } B43_WARN_ON(q->buffer_used > q->buffer_size); @@ -534,7 +529,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) err = -EBUSY; ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; - goto out_unlock; + goto out; } /* Assign the queue number to the ring (if not already done before) @@ -548,11 +543,11 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) * anymore and must not transmit it unencrypted. */ dev_kfree_skb_any(skb); err = 0; - goto out_unlock; + goto out; } if (unlikely(err)) { b43err(dev->wl, "PIO transmission failure\n"); - goto out_unlock; + goto out; } q->nr_tx_packets++; @@ -564,9 +559,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) q->stopped = 1; } -out_unlock: - spin_unlock_irqrestore(&q->lock, flags); - +out: return err; } @@ -583,8 +576,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, return; B43_WARN_ON(!pack); - spin_lock_irq(&q->lock); - info = IEEE80211_SKB_CB(pack->skb); b43_fill_txstatus_report(dev, info, status); @@ -602,8 +593,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, ieee80211_wake_queue(dev->wl->hw, q->queue_prio); q->stopped = 0; } - - spin_unlock_irq(&q->lock); } void b43_pio_get_tx_stats(struct b43_wldev *dev, @@ -611,17 +600,14 @@ void b43_pio_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_pio_txqueue *q; - unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { q = select_queue_by_priority(dev, i); - spin_lock_irqsave(&q->lock, flags); stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; stats[i].limit = B43_PIO_MAX_NR_TXPACKETS; stats[i].count = q->nr_tx_packets; - spin_unlock_irqrestore(&q->lock, flags); } } @@ -768,9 +754,9 @@ static void b43_pio_rx_work(struct work_struct *work) bool stop; do { - spin_lock_irq(&q->lock); + mutex_lock(&q->dev->wl->mutex); stop = (pio_rx_frame(q) == 0); - spin_unlock_irq(&q->lock); + mutex_unlock(&q->dev->wl->mutex); cond_resched(); if (stop) break; @@ -787,9 +773,6 @@ void b43_pio_rx(struct b43_pio_rxqueue *q) static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) { - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); if (q->rev >= 8) { b43_piotx_write32(q, B43_PIO8_TXCTL, b43_piotx_read32(q, B43_PIO8_TXCTL) @@ -799,14 +782,10 @@ static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) b43_piotx_read16(q, B43_PIO_TXCTL) | B43_PIO_TXCTL_SUSPREQ); } - spin_unlock_irqrestore(&q->lock, flags); } static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q) { - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); if (q->rev >= 8) { b43_piotx_write32(q, B43_PIO8_TXCTL, b43_piotx_read32(q, B43_PIO8_TXCTL) @@ -816,7 +795,6 @@ static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q) b43_piotx_read16(q, B43_PIO_TXCTL) & ~B43_PIO_TXCTL_SUSPREQ); } - spin_unlock_irqrestore(&q->lock, flags); } void b43_pio_tx_suspend(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index 6c174c9..a976bbd 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -70,7 +70,6 @@ struct b43_pio_txpacket { struct b43_pio_txqueue { struct b43_wldev *dev; - spinlock_t lock; u16 mmio_base; /* The device queue buffer size in bytes. */ @@ -103,7 +102,6 @@ struct b43_pio_txqueue { struct b43_pio_rxqueue { struct b43_wldev *dev; - spinlock_t lock; u16 mmio_base; /* Work to reduce latency issues on RX. */ -- cgit v0.10.2 From 77ca07ffe1797a0f2f41aa4997c9a5ae433a0be8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:56:19 +0200 Subject: b43: Remove PIO RX workqueue This removes the PIO RX work. It's not needed anymore, because we can sleep in the threaded interrupt handler. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index fca2fe9..23de3db 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3883,7 +3883,6 @@ redo: while (skb_queue_len(&wl->tx_queue)) dev_kfree_skb(skb_dequeue(&wl->tx_queue)); - b43_pio_stop(dev); b43_mac_suspend(dev); free_irq(dev->dev->irq, dev); b43dbg(wl, "Wireless interface stopped\n"); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 4635baa..3498b68 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -32,9 +32,6 @@ #include -static void b43_pio_rx_work(struct work_struct *work); - - static u16 generate_cookie(struct b43_pio_txqueue *q, struct b43_pio_txpacket *pack) { @@ -182,7 +179,6 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev, q->rev = dev->dev->id.revision; q->mmio_base = index_to_pioqueue_base(dev, index) + pio_rxqueue_offset(dev); - INIT_WORK(&q->rx_work, b43_pio_rx_work); /* Enable Direct FIFO RX (PIO) on the engine. */ b43_dma_direct_fifo_rx(dev, index, 1); @@ -247,13 +243,6 @@ void b43_pio_free(struct b43_wldev *dev) destroy_queue_tx(pio, tx_queue_AC_BK); } -void b43_pio_stop(struct b43_wldev *dev) -{ - if (!b43_using_pio_transfers(dev)) - return; - cancel_work_sync(&dev->pio.rx_queue->rx_work); -} - int b43_pio_init(struct b43_wldev *dev) { struct b43_pio *pio = &dev->pio; @@ -745,30 +734,19 @@ rx_error: return 1; } -/* RX workqueue. We can sleep, yay! */ -static void b43_pio_rx_work(struct work_struct *work) +void b43_pio_rx(struct b43_pio_rxqueue *q) { - struct b43_pio_rxqueue *q = container_of(work, struct b43_pio_rxqueue, - rx_work); - unsigned int budget = 50; + unsigned int count = 0; bool stop; - do { - mutex_lock(&q->dev->wl->mutex); + while (1) { stop = (pio_rx_frame(q) == 0); - mutex_unlock(&q->dev->wl->mutex); - cond_resched(); if (stop) break; - } while (--budget); -} - -/* Called with IRQs disabled. */ -void b43_pio_rx(struct b43_pio_rxqueue *q) -{ - /* Due to latency issues we must run the RX path in - * a workqueue to be able to schedule between packets. */ - ieee80211_queue_work(q->dev->wl->hw, &q->rx_work); + cond_resched(); + if (WARN_ON_ONCE(++count > 10000)) + break; + } } static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index a976bbd..7dd649c9 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -104,9 +104,6 @@ struct b43_pio_rxqueue { struct b43_wldev *dev; u16 mmio_base; - /* Work to reduce latency issues on RX. */ - struct work_struct rx_work; - /* Shortcut to the 802.11 core revision. This is to * avoid horrible pointer dereferencing in the fastpaths. */ u8 rev; @@ -160,7 +157,6 @@ static inline void b43_piorx_write32(struct b43_pio_rxqueue *q, int b43_pio_init(struct b43_wldev *dev); -void b43_pio_stop(struct b43_wldev *dev); void b43_pio_free(struct b43_wldev *dev); int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); -- cgit v0.10.2 From 69eddc8a37a33479205ac3a3d8575fad1466da90 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:57:26 +0200 Subject: b43: remove SHM spinlock This removes the SHM spinlock. SHM is protected by wl->mutex. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 1cd470d..09cfe68 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -635,8 +635,6 @@ struct b43_wl { rwlock_t tx_lock; /* Lock for LEDs access. */ spinlock_t leds_lock; - /* Lock for SHM access. */ - spinlock_t shm_lock; /* We can only have one operating interface (802.11 core) * at a time. General information about this interface follows. diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index bf23a3a..8f64943 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -125,7 +125,6 @@ static int shm16write__write_file(struct b43_wldev *dev, unsigned int routing, addr, mask, set; u16 val; int res; - unsigned long flags; res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", &routing, &addr, &mask, &set); @@ -142,15 +141,13 @@ static int shm16write__write_file(struct b43_wldev *dev, if ((mask > 0xFFFF) || (set > 0xFFFF)) return -E2BIG; - spin_lock_irqsave(&dev->wl->shm_lock, flags); if (mask == 0) val = 0; else - val = __b43_shm_read16(dev, routing, addr); + val = b43_shm_read16(dev, routing, addr); val &= mask; val |= set; - __b43_shm_write16(dev, routing, addr, val); - spin_unlock_irqrestore(&dev->wl->shm_lock, flags); + b43_shm_write16(dev, routing, addr, val); return 0; } @@ -204,7 +201,6 @@ static int shm32write__write_file(struct b43_wldev *dev, unsigned int routing, addr, mask, set; u32 val; int res; - unsigned long flags; res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", &routing, &addr, &mask, &set); @@ -221,15 +217,13 @@ static int shm32write__write_file(struct b43_wldev *dev, if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF)) return -E2BIG; - spin_lock_irqsave(&dev->wl->shm_lock, flags); if (mask == 0) val = 0; else - val = __b43_shm_read32(dev, routing, addr); + val = b43_shm_read32(dev, routing, addr); val &= mask; val |= set; - __b43_shm_write32(dev, routing, addr, val); - spin_unlock_irqrestore(&dev->wl->shm_lock, flags); + b43_shm_write32(dev, routing, addr, val); return 0; } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 23de3db..0a4d0b3 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -390,7 +390,7 @@ static inline void b43_shm_control_word(struct b43_wldev *dev, b43_write32(dev, B43_MMIO_SHM_CONTROL, control); } -u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) +u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) { u32 ret; @@ -413,20 +413,7 @@ out: return ret; } -u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - u32 ret; - - spin_lock_irqsave(&wl->shm_lock, flags); - ret = __b43_shm_read32(dev, routing, offset); - spin_unlock_irqrestore(&wl->shm_lock, flags); - - return ret; -} - -u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) +u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) { u16 ret; @@ -447,20 +434,7 @@ out: return ret; } -u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - u16 ret; - - spin_lock_irqsave(&wl->shm_lock, flags); - ret = __b43_shm_read16(dev, routing, offset); - spin_unlock_irqrestore(&wl->shm_lock, flags); - - return ret; -} - -void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) +void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) { if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); @@ -480,17 +454,7 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value b43_write32(dev, B43_MMIO_SHM_DATA, value); } -void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - - spin_lock_irqsave(&wl->shm_lock, flags); - __b43_shm_write32(dev, routing, offset, value); - spin_unlock_irqrestore(&wl->shm_lock, flags); -} - -void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) +void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) { if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); @@ -506,16 +470,6 @@ void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value b43_write16(dev, B43_MMIO_SHM_DATA, value); } -void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - - spin_lock_irqsave(&wl->shm_lock, flags); - __b43_shm_write16(dev, routing, offset, value); - spin_unlock_irqrestore(&wl->shm_lock, flags); -} - /* Read HostFlags */ u64 b43_hf_read(struct b43_wldev *dev) { @@ -4866,7 +4820,6 @@ static int b43_wireless_init(struct ssb_device *dev) /* Initialize struct b43_wl */ wl->hw = hw; spin_lock_init(&wl->leds_lock); - spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); spin_lock_init(&wl->hardirq_lock); INIT_LIST_HEAD(&wl->devlist); diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 0406e06..40db036 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -112,13 +112,9 @@ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf); void b43_tsf_write(struct b43_wldev *dev, u64 tsf); u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); -u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); -u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); -void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); -void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); u64 b43_hf_read(struct b43_wldev *dev); void b43_hf_write(struct b43_wldev *dev, u64 value); -- cgit v0.10.2 From e6c463e3a3d067f5da2c79d5acdb2f626754cdb3 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 5 Sep 2009 11:18:47 +0200 Subject: ssb: Fail ssb modinit, if attach of the buses failed. SSB modinit should not succeed, if busattach failed. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 65a1ed9..8d16cb2 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1358,8 +1358,10 @@ static int __init ssb_modinit(void) ssb_buses_lock(); err = ssb_attach_queued_buses(); ssb_buses_unlock(); - if (err) + if (err) { bus_unregister(&ssb_bustype); + goto out; + } err = b43_pci_ssb_bridge_init(); if (err) { @@ -1375,7 +1377,7 @@ static int __init ssb_modinit(void) /* don't fail SSB init because of this */ err = 0; } - +out: return err; } /* ssb must be initialized after PCI but before the ssb drivers. -- cgit v0.10.2 From 7f42c37aa676825fea329a7bec2fefe51033b3e9 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Sat, 5 Sep 2009 16:07:43 +0200 Subject: ath,ar9170: move CTL_ defines into regd.h The ar9170 driver needs the defines for conformance test limit groups and cannot include regd_common.h Signed-off-by: Joerg Albert Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 4d3c536..c1dd857 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -22,6 +22,12 @@ #include "ath.h" +enum ctl_group { + CTL_FCC = 0x10, + CTL_MKK = 0x40, + CTL_ETSI = 0x30, +}; + #define NO_CTL 0xff #define SD_NO_CTL 0xE0 #define NO_CTL 0xff diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index ad6d938..9847af7 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -154,12 +154,6 @@ enum EnumRd { DEBUG_REG_DMN = 0x01ff, }; -enum ctl_group { - CTL_FCC = 0x10, - CTL_MKK = 0x40, - CTL_ETSI = 0x30, -}; - /* Regpair to CTL band mapping */ static struct reg_dmn_pair_mapping regDomainPairs[] = { /* regpair, 5 GHz CTL, 2 GHz CTL */ -- cgit v0.10.2 From fea6734a0e444c31c99a1271154bb0281d7908d8 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Sat, 5 Sep 2009 16:07:47 +0200 Subject: ath,ar9170: implemented conformance test limit calc. for tx power apply the conformance test limits (CTL) stored in the eeprom upon the values calculated for the tx power (ar->power_*). This is based on the implementation in the vendor driver (hal/hpmain.c, line 3700 ff.) with one difference: If any ctl mode isn't found in the eeprom, we fall back to the "lower", legacy modes (5GHT20,11A or 2GHT20,11G,11B). Otus only did 5GHT20->11A. Currently CTL are applied for the FCC group only. Signed-off-by: Joerg Albert Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index 108ebfe..b3e5cf3 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -556,7 +556,6 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) if (err) return err; - /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); if (err) return err; @@ -1238,6 +1237,164 @@ static int ar9170_set_freq_cal_data(struct ar9170 *ar, return ar9170_regwrite_result(); } +static u8 ar9170_get_max_edge_power(struct ar9170 *ar, + struct ar9170_calctl_edges edges[], + u32 freq) +{ +/* TODO: move somewhere else */ +#define AR5416_MAX_RATE_POWER 63 + + int i; + u8 rc = AR5416_MAX_RATE_POWER; + u8 f; + if (freq < 3000) + f = freq - 2300; + else + f = (freq - 4800) / 5; + + for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { + if (edges[i].channel == 0xff) + break; + if (f == edges[i].channel) { + /* exact freq match */ + rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS; + break; + } + if (i > 0 && f < edges[i].channel) { + if (f > edges[i-1].channel && + edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { + /* lower channel has the inband flag set */ + rc = edges[i-1].power_flags & + ~AR9170_CALCTL_EDGE_FLAGS; + } + break; + } + } + + if (i == AR5416_NUM_BAND_EDGES) { + if (f > edges[i-1].channel && + edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { + /* lower channel has the inband flag set */ + rc = edges[i-1].power_flags & + ~AR9170_CALCTL_EDGE_FLAGS; + } + } + return rc; +} + +/* calculate the conformance test limits and apply them to ar->power* + * (derived from otus hal/hpmain.c, line 3706 ff.) + */ +static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) +{ + u8 ctl_grp; /* CTL group */ + u8 ctl_idx; /* CTL index */ + int i, j; + struct ctl_modes { + u8 ctl_mode; + u8 max_power; + u8 *pwr_cal_data; + int pwr_cal_len; + } *modes; + + /* order is relevant in the mode_list_*: we fall back to the + * lower indices if any mode is missed in the EEPROM. + */ + struct ctl_modes mode_list_2ghz[] = { + { CTL_11B, 0, ar->power_2G_cck, 4 }, + { CTL_11G, 0, ar->power_2G_ofdm, 4 }, + { CTL_2GHT20, 0, ar->power_2G_ht20, 8 }, + { CTL_2GHT40, 0, ar->power_2G_ht40, 8 }, + }; + struct ctl_modes mode_list_5ghz[] = { + { CTL_11A, 0, ar->power_5G_leg, 4 }, + { CTL_5GHT20, 0, ar->power_5G_ht20, 8 }, + { CTL_5GHT40, 0, ar->power_5G_ht40, 8 }, + }; + int nr_modes; + +#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) + + /* TODO: investigate the differences between OTUS' + * hpreg.c::zfHpGetRegulatoryDomain() and + * ath/regd.c::ath_regd_get_band_ctl() - + * e.g. for FCC3_WORLD the OTUS procedure + * always returns CTL_FCC, while the one in ath/ delivers + * CTL_ETSI for 2GHz and CTL_FCC for 5GHz. + */ + ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory, + ar->hw->conf.channel->band); + + /* ctl group not found - either invalid band (NO_CTL) or ww roaming */ + if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL) + ctl_grp = CTL_FCC; + + if (ctl_grp != CTL_FCC) + /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */ + return; + + if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) { + modes = mode_list_2ghz; + nr_modes = ARRAY_SIZE(mode_list_2ghz); + } else { + modes = mode_list_5ghz; + nr_modes = ARRAY_SIZE(mode_list_5ghz); + } + + for (i = 0; i < nr_modes; i++) { + u8 c = ctl_grp | modes[i].ctl_mode; + for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++) + if (c == ar->eeprom.ctl_index[ctl_idx]) + break; + if (ctl_idx < AR5416_NUM_CTLS) { + int f_off = 0; + + /* adjust freq for 40MHz */ + if (modes[i].ctl_mode == CTL_2GHT40 || + modes[i].ctl_mode == CTL_5GHT40) { + if (bw == AR9170_BW_40_BELOW) + f_off = -10; + else + f_off = 10; + } + + modes[i].max_power = + ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), + freq+f_off); + + /* TODO: check if the regulatory max. power is + * controlled by cfg80211 for DFS + * (hpmain applies it to max_power itself for DFS freq) + */ + + } else { + /* Workaround in otus driver, hpmain.c, line 3906: + * if no data for 5GHT20 are found, take the + * legacy 5G value. + * We extend this here to fallback from any other *HT or + * 11G, too. + */ + int k = i; + + modes[i].max_power = AR5416_MAX_RATE_POWER; + while (k-- > 0) { + if (modes[k].max_power != + AR5416_MAX_RATE_POWER) { + modes[i].max_power = modes[k].max_power; + break; + } + } + } + + /* apply max power to pwr_cal_data (ar->power_*) */ + for (j = 0; j < modes[i].pwr_cal_len; j++) { + modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j], + modes[i].max_power); + } + } +#undef EDGES +} + static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) { struct ar9170_calibration_target_power_legacy *ctpl; @@ -1340,6 +1497,12 @@ static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) ctph[idx + 1].power[n]); } + + /* calc. conformance test limits and apply to ar->power*[] */ + ar9170_calc_ctl(ar, freq, bw); + + /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ + /* set ACK/CTS TX power */ ar9170_regwrite_begin(ar); -- cgit v0.10.2 From fd413da852991e96c555ad7253cc481bc133e221 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 6 Sep 2009 14:49:43 +0200 Subject: b43: PCMCIA is not experimental anymore PCMCIA support works well and is not experimental anymore. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 2af3b35..83e3813 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -42,8 +42,8 @@ config B43_PCICORE_AUTOSELECT default y config B43_PCMCIA - bool "Broadcom 43xx PCMCIA device support (EXPERIMENTAL)" - depends on B43 && SSB_PCMCIAHOST_POSSIBLE && EXPERIMENTAL + bool "Broadcom 43xx PCMCIA device support" + depends on B43 && SSB_PCMCIAHOST_POSSIBLE select SSB_PCMCIAHOST ---help--- Broadcom 43xx PCMCIA device support. -- cgit v0.10.2 From dbab8360ed8abca38121109feab47c4bea895994 Mon Sep 17 00:00:00 2001 From: Harshula Jayasuriya Date: Tue, 8 Sep 2009 19:49:33 -0400 Subject: NFS: out of date comment regarding O_EXCL above nfs3_proc_create() Hi Trond, Recently we were observing the behaviour difference between a 2.4.x and 2.6.x kernel with respect to O_EXCL. A comment from 2.4.x era, "For now, we don't implement O_EXCL." seems inaccurate in TOT. If so, here's a patch to remove the comment. This patch is against: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 Signed-off-by: Harshula Jayasuriya Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index d0cc5ce..ee6a13f 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -299,7 +299,6 @@ static void nfs3_free_createdata(struct nfs3_createdata *data) /* * Create a regular file. - * For now, we don't implement O_EXCL. */ static int nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, -- cgit v0.10.2 From 4cfd74fc99a41fdc161f243e1c16199656d33ab1 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 8 Sep 2009 19:49:47 -0400 Subject: NFS: Mount option parser should detect missing "port=" The meaning of not specifying the "port=" mount option is different for "-t nfs" and "-t nfs4" mounts. The default port value for NFSv2/v3 mounts is 0, but the default for NFSv4 mounts is 2049. To support "-t nfs -o vers=4", the mount option parser must detect when "port=" is missing so that the correct default port value can be set depending on which NFS version is requested. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 2e48567..5e686a4 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -49,6 +49,11 @@ struct nfs_clone_mount { #define NFS_MAX_SECFLAVORS (12) /* + * Value used if the user did not specify a port value. + */ +#define NFS_UNSPEC_PORT (-1) + +/* * In-kernel mount arguments */ struct nfs_parsed_mount_data { @@ -71,7 +76,7 @@ struct nfs_parsed_mount_data { size_t addrlen; char *hostname; u32 version; - unsigned short port; + int port; unsigned short protocol; } mount_server; @@ -80,7 +85,7 @@ struct nfs_parsed_mount_data { size_t addrlen; char *hostname; char *export_path; - unsigned short port; + int port; unsigned short protocol; } nfs_server; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f3a95df..0554433 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -747,6 +747,21 @@ static int nfs_verify_server_address(struct sockaddr *addr) } /* + * Select between a default port value and a user-specified port value. + * If a zero value is set, then autobind will be used. + */ +static void nfs_set_default_port(struct sockaddr *sap, const int parsed_port, + const unsigned short default_port) +{ + unsigned short port = default_port; + + if (parsed_port != NFS_UNSPEC_PORT) + port = parsed_port; + + rpc_set_port(sap, port); +} + +/* * Sanity check the NFS transport protocol. * */ @@ -1415,11 +1430,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, args->mount_server.addrlen = args->nfs_server.addrlen; } request.salen = args->mount_server.addrlen; - - /* - * autobind will be used if mount_server.port == 0 - */ - rpc_set_port(request.sap, args->mount_server.port); + nfs_set_default_port(request.sap, args->mount_server.port, 0); /* * Now ask the mount server to map our export path @@ -1597,6 +1608,7 @@ static int nfs_validate_mount_data(void *options, const char *dev_name) { struct nfs_mount_data *data = (struct nfs_mount_data *)options; + struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; if (data == NULL) goto out_no_data; @@ -1608,8 +1620,8 @@ static int nfs_validate_mount_data(void *options, args->acregmax = NFS_DEF_ACREGMAX; args->acdirmin = NFS_DEF_ACDIRMIN; args->acdirmax = NFS_DEF_ACDIRMAX; - args->mount_server.port = 0; /* autobind unless user sets port */ - args->nfs_server.port = 0; /* autobind unless user sets port */ + args->mount_server.port = NFS_UNSPEC_PORT; + args->nfs_server.port = NFS_UNSPEC_PORT; args->nfs_server.protocol = XPRT_TRANSPORT_TCP; args->auth_flavors[0] = RPC_AUTH_UNIX; args->auth_flavor_len = 1; @@ -1657,11 +1669,9 @@ static int nfs_validate_mount_data(void *options, args->acdirmin = data->acdirmin; args->acdirmax = data->acdirmax; - memcpy(&args->nfs_server.address, &data->addr, - sizeof(data->addr)); + memcpy(sap, &data->addr, sizeof(data->addr)); args->nfs_server.addrlen = sizeof(data->addr); - if (!nfs_verify_server_address((struct sockaddr *) - &args->nfs_server.address)) + if (!nfs_verify_server_address(sap)) goto out_no_address; if (!(data->flags & NFS_MOUNT_TCP)) @@ -1709,12 +1719,10 @@ static int nfs_validate_mount_data(void *options, if (nfs_parse_mount_options((char *)options, args) == 0) return -EINVAL; - if (!nfs_verify_server_address((struct sockaddr *) - &args->nfs_server.address)) + if (!nfs_verify_server_address(sap)) goto out_no_address; - rpc_set_port((struct sockaddr *)&args->nfs_server.address, - args->nfs_server.port); + nfs_set_default_port(sap, args->nfs_server.port, 0); nfs_set_mount_transport_protocol(args); @@ -2261,7 +2269,7 @@ static int nfs4_validate_mount_data(void *options, struct nfs_parsed_mount_data *args, const char *dev_name) { - struct sockaddr_in *ap; + struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; char *c; @@ -2274,23 +2282,21 @@ static int nfs4_validate_mount_data(void *options, args->acregmax = NFS_DEF_ACREGMAX; args->acdirmin = NFS_DEF_ACDIRMIN; args->acdirmax = NFS_DEF_ACDIRMAX; - args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ + args->nfs_server.port = NFS_UNSPEC_PORT; args->auth_flavors[0] = RPC_AUTH_UNIX; args->auth_flavor_len = 1; args->minorversion = 0; switch (data->version) { case 1: - ap = (struct sockaddr_in *)&args->nfs_server.address; if (data->host_addrlen > sizeof(args->nfs_server.address)) goto out_no_address; if (data->host_addrlen == 0) goto out_no_address; args->nfs_server.addrlen = data->host_addrlen; - if (copy_from_user(ap, data->host_addr, data->host_addrlen)) + if (copy_from_user(sap, data->host_addr, data->host_addrlen)) return -EFAULT; - if (!nfs_verify_server_address((struct sockaddr *) - &args->nfs_server.address)) + if (!nfs_verify_server_address(sap)) goto out_no_address; if (data->auth_flavourlen) { @@ -2342,12 +2348,9 @@ static int nfs4_validate_mount_data(void *options, if (nfs_parse_mount_options((char *)options, args) == 0) return -EINVAL; - if (!nfs_verify_server_address((struct sockaddr *) - &args->nfs_server.address)) + if (!nfs_verify_server_address(sap)) return -EINVAL; - - rpc_set_port((struct sockaddr *)&args->nfs_server.address, - args->nfs_server.port); + nfs_set_default_port(sap, args->nfs_server.port, NFS_PORT); nfs_validate_transport_protocol(args); -- cgit v0.10.2 From 7630c852e19c7fffb85b50d98eeb5516fec7c088 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 8 Sep 2009 19:49:57 -0400 Subject: NFS: Refactor NFSv4 text-based mount option validation Clean up: Refactor the part of nfs4_validate_mount_options() that handles text-based options, so we can call it from the NFSv2/v3 option validation function. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0554433..599e8c5 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -272,6 +272,8 @@ static const struct super_operations nfs_sops = { }; #ifdef CONFIG_NFS_V4 +static int nfs4_validate_text_mount_data(void *options, + struct nfs_parsed_mount_data *args, const char *dev_name); static int nfs4_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); static int nfs4_remote_get_sb(struct file_system_type *fs_type, @@ -2262,6 +2264,37 @@ static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3); } +static int nfs4_validate_text_mount_data(void *options, + struct nfs_parsed_mount_data *args, + const char *dev_name) +{ + struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; + + nfs_set_default_port(sap, args->nfs_server.port, NFS_PORT); + + nfs_validate_transport_protocol(args); + + nfs4_validate_mount_flags(args); + + if (args->auth_flavor_len > 1) { + dfprintk(MOUNT, + "NFS4: Too many RPC auth flavours specified\n"); + return -EINVAL; + } + + if (args->client_address == NULL) { + dfprintk(MOUNT, + "NFS4: mount program didn't pass callback address\n"); + return -EINVAL; + } + + return nfs_parse_devname(dev_name, + &args->nfs_server.hostname, + NFS4_MAXNAMLEN, + &args->nfs_server.export_path, + NFS4_MAXPATHLEN); +} + /* * Validate NFSv4 mount options */ @@ -2342,36 +2375,14 @@ static int nfs4_validate_mount_data(void *options, nfs_validate_transport_protocol(args); break; - default: { - int status; - + default: if (nfs_parse_mount_options((char *)options, args) == 0) return -EINVAL; if (!nfs_verify_server_address(sap)) return -EINVAL; - nfs_set_default_port(sap, args->nfs_server.port, NFS_PORT); - - nfs_validate_transport_protocol(args); - - nfs4_validate_mount_flags(args); - - if (args->auth_flavor_len > 1) - goto out_inval_auth; - - if (args->client_address == NULL) - goto out_no_client_address; - - status = nfs_parse_devname(dev_name, - &args->nfs_server.hostname, - NFS4_MAXNAMLEN, - &args->nfs_server.export_path, - NFS4_MAXPATHLEN); - if (status < 0) - return status; - break; - } + return nfs4_validate_text_mount_data(options, args, dev_name); } return 0; @@ -2388,10 +2399,6 @@ out_inval_auth: out_no_address: dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); return -EINVAL; - -out_no_client_address: - dfprintk(MOUNT, "NFS4: mount program didn't pass callback address\n"); - return -EINVAL; } /* -- cgit v0.10.2 From a6fe23be90aa78783523a25330e09bfaa43a1581 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 8 Sep 2009 19:50:00 -0400 Subject: NFS: Move details of nfs4_get_sb() to a helper Clean up: Refactor nfs4_get_sb() to allow its guts to be invoked by nfs_get_sb(). Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 599e8c5..c105e12 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -274,6 +274,8 @@ static const struct super_operations nfs_sops = { #ifdef CONFIG_NFS_V4 static int nfs4_validate_text_mount_data(void *options, struct nfs_parsed_mount_data *args, const char *dev_name); +static int nfs4_try_mount(int flags, const char *dev_name, + struct nfs_parsed_mount_data *data, struct vfsmount *mnt); static int nfs4_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); static int nfs4_remote_get_sb(struct file_system_type *fs_type, @@ -2565,6 +2567,34 @@ out_err: return ret; } +static int nfs4_try_mount(int flags, const char *dev_name, + struct nfs_parsed_mount_data *data, + struct vfsmount *mnt) +{ + char *export_path; + struct vfsmount *root_mnt; + int error; + + dfprintk(MOUNT, "--> nfs4_try_mount()\n"); + + export_path = data->nfs_server.export_path; + data->nfs_server.export_path = "/"; + root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, + data->nfs_server.hostname); + data->nfs_server.export_path = export_path; + + error = PTR_ERR(root_mnt); + if (IS_ERR(root_mnt)) + goto out; + + error = nfs_follow_remote_path(root_mnt, export_path, mnt); + +out: + dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n", error, + error != 0 ? " [error]" : ""); + return error; +} + /* * Get the superblock for an NFS4 mountpoint */ @@ -2572,8 +2602,6 @@ static int nfs4_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) { struct nfs_parsed_mount_data *data; - char *export_path; - struct vfsmount *root_mnt; int error = -ENOMEM; data = kzalloc(sizeof(*data), GFP_KERNEL); @@ -2585,17 +2613,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, if (error < 0) goto out; - export_path = data->nfs_server.export_path; - data->nfs_server.export_path = "/"; - root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, - data->nfs_server.hostname); - data->nfs_server.export_path = export_path; - - error = PTR_ERR(root_mnt); - if (IS_ERR(root_mnt)) - goto out; - - error = nfs_follow_remote_path(root_mnt, export_path, mnt); + error = nfs4_try_mount(flags, dev_name, data, mnt); out: kfree(data->client_address); -- cgit v0.10.2 From 764302ccb88dd0df062eccd507b6c6de24f1c560 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 8 Sep 2009 19:50:03 -0400 Subject: NFS: Allow the "nfs" file system type to support NFSv4 When mounting an "nfs" type file system, recognize "v4," "vers=4," or "nfsvers=4" mount options, and convert the file system to "nfs4" under the covers. Signed-off-by: Chuck Lever [trondmy: fixed up binary mount code so it sets the 'version' field too] Signed-off-by: Trond Myklebust diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 5e686a4..e21b1bb 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -68,6 +68,7 @@ struct nfs_parsed_mount_data { unsigned int auth_flavor_len; rpc_authflavor_t auth_flavors[1]; char *client_address; + unsigned int version; unsigned int minorversion; char *fscache_uniq; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index c105e12..34b1ccf 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -73,7 +73,7 @@ enum { Opt_cto, Opt_nocto, Opt_ac, Opt_noac, Opt_lock, Opt_nolock, - Opt_v2, Opt_v3, + Opt_v2, Opt_v3, Opt_v4, Opt_udp, Opt_tcp, Opt_rdma, Opt_acl, Opt_noacl, Opt_rdirplus, Opt_nordirplus, @@ -127,6 +127,7 @@ static const match_table_t nfs_mount_option_tokens = { { Opt_nolock, "nolock" }, { Opt_v2, "v2" }, { Opt_v3, "v3" }, + { Opt_v4, "v4" }, { Opt_udp, "udp" }, { Opt_tcp, "tcp" }, { Opt_rdma, "rdma" }, @@ -934,10 +935,18 @@ static int nfs_parse_mount_options(char *raw, break; case Opt_v2: mnt->flags &= ~NFS_MOUNT_VER3; + mnt->version = 2; break; case Opt_v3: mnt->flags |= NFS_MOUNT_VER3; + mnt->version = 3; break; +#ifdef CONFIG_NFS_V4 + case Opt_v4: + mnt->flags &= ~NFS_MOUNT_VER3; + mnt->version = 4; + break; +#endif case Opt_udp: mnt->flags &= ~NFS_MOUNT_TCP; mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; @@ -1151,10 +1160,18 @@ static int nfs_parse_mount_options(char *raw, switch (option) { case NFS2_VERSION: mnt->flags &= ~NFS_MOUNT_VER3; + mnt->version = 2; break; case NFS3_VERSION: mnt->flags |= NFS_MOUNT_VER3; + mnt->version = 3; + break; +#ifdef CONFIG_NFS_V4 + case NFS4_VERSION: + mnt->flags &= ~NFS_MOUNT_VER3; + mnt->version = 4; break; +#endif default: goto out_invalid_value; } @@ -1629,6 +1646,7 @@ static int nfs_validate_mount_data(void *options, args->nfs_server.protocol = XPRT_TRANSPORT_TCP; args->auth_flavors[0] = RPC_AUTH_UNIX; args->auth_flavor_len = 1; + args->minorversion = 0; switch (data->version) { case 1: @@ -1650,8 +1668,11 @@ static int nfs_validate_mount_data(void *options, if (data->root.size > NFS3_FHSIZE || data->root.size == 0) goto out_invalid_fh; mntfh->size = data->root.size; - } else + args->version = 3; + } else { mntfh->size = NFS2_FHSIZE; + args->version = 2; + } memcpy(mntfh->data, data->root.data, mntfh->size); @@ -1726,6 +1747,14 @@ static int nfs_validate_mount_data(void *options, if (!nfs_verify_server_address(sap)) goto out_no_address; + if (args->version == 4) +#ifdef CONFIG_NFS_V4 + return nfs4_validate_text_mount_data(options, + args, dev_name); +#else + goto out_v4_not_compiled; +#endif + nfs_set_default_port(sap, args->nfs_server.port, 0); nfs_set_mount_transport_protocol(args); @@ -1774,6 +1803,12 @@ out_v3_not_compiled: return -EPROTONOSUPPORT; #endif /* !CONFIG_NFS_V3 */ +#ifndef CONFIG_NFS_V4 +out_v4_not_compiled: + dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n"); + return -EPROTONOSUPPORT; +#endif /* !CONFIG_NFS_V4 */ + out_nomem: dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); return -ENOMEM; @@ -2069,6 +2104,14 @@ static int nfs_get_sb(struct file_system_type *fs_type, if (error < 0) goto out; +#ifdef CONFIG_NFS_V4 + if (data->version == 4) { + error = nfs4_try_mount(flags, dev_name, data, mnt); + kfree(data->client_address); + goto out; + } +#endif /* CONFIG_NFS_V4 */ + /* Get a volume representation */ server = nfs_create_server(data, mntfh); if (IS_ERR(server)) { @@ -2320,6 +2363,7 @@ static int nfs4_validate_mount_data(void *options, args->nfs_server.port = NFS_UNSPEC_PORT; args->auth_flavors[0] = RPC_AUTH_UNIX; args->auth_flavor_len = 1; + args->version = 4; args->minorversion = 0; switch (data->version) { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index bd2eba5..33b2836 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -472,6 +472,7 @@ enum lock_type4 { #define NFSPROC4_NULL 0 #define NFSPROC4_COMPOUND 1 +#define NFS4_VERSION 4 #define NFS4_MINOR_VERSION 0 #if defined(CONFIG_NFS_V4_1) -- cgit v0.10.2 From 2ecda72b49a0849ce41e7fa1fa974a245b9119f8 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 8 Sep 2009 19:50:07 -0400 Subject: NFSv4: Disallow 'mount -t nfs4 -overs=2' and 'mount -t nfs4 -overs=3' Signed-off-by: Trond Myklebust diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 34b1ccf..867f705 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2321,6 +2321,12 @@ static int nfs4_validate_text_mount_data(void *options, nfs4_validate_mount_flags(args); + if (args->version != 4) { + dfprintk(MOUNT, + "NFS4: Illegal mount version\n"); + return -EINVAL; + } + if (args->auth_flavor_len > 1) { dfprintk(MOUNT, "NFS4: Too many RPC auth flavours specified\n"); -- cgit v0.10.2 From 72fee3823d2938fa98f2f3113301f46803f4c711 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 1 Sep 2009 23:19:10 +0900 Subject: sata_sis: convert to slave_link During introduction of slave_link, sata_sis slipped through the crack and left with ad-hoc merged SCR access. As SCR status was shared for both the master and slave devices, when only one of the device is online, libata EH would think both are online but would only get valid device signature for the actually present one, which in turn trigger the probing safety net mechanism and make EH retry causing large delay during boot. This patch converts sata_sis to slave_link mechanism. This bug was reported by TAXI in bko#14075. http://bugzilla.kernel.org/show_bug.cgi?id=14075 Signed-off-by: Tejun Heo Reported-by: TAXI Cc: Uwe Koziolek Signed-off-by: Jeff Garzik diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 8f98332..f8a91bf 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -109,8 +109,9 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, sis_pci_tbl); MODULE_VERSION(DRV_VERSION); -static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg) +static unsigned int get_scr_cfg_addr(struct ata_link *link, unsigned int sc_reg) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); unsigned int addr = SIS_SCR_BASE + (4 * sc_reg); u8 pmr; @@ -131,6 +132,9 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg) break; } } + if (link->pmp) + addr += 0x10; + return addr; } @@ -138,24 +142,12 @@ static u32 sis_scr_cfg_read(struct ata_link *link, unsigned int sc_reg, u32 *val) { struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); - unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg); - u32 val2 = 0; - u8 pmr; + unsigned int cfg_addr = get_scr_cfg_addr(link, sc_reg); if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ return -EINVAL; - pci_read_config_byte(pdev, SIS_PMR, &pmr); - pci_read_config_dword(pdev, cfg_addr, val); - - if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || - (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) - pci_read_config_dword(pdev, cfg_addr+0x10, &val2); - - *val |= val2; - *val &= 0xfffffffb; /* avoid problems with powerdowned ports */ - return 0; } @@ -163,28 +155,16 @@ static int sis_scr_cfg_write(struct ata_link *link, unsigned int sc_reg, u32 val) { struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); - unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg); - u8 pmr; - - if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ - return -EINVAL; - - pci_read_config_byte(pdev, SIS_PMR, &pmr); + unsigned int cfg_addr = get_scr_cfg_addr(link, sc_reg); pci_write_config_dword(pdev, cfg_addr, val); - - if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || - (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) - pci_write_config_dword(pdev, cfg_addr+0x10, val); - return 0; } static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) { struct ata_port *ap = link->ap; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 pmr; + void __iomem *base = ap->ioaddr.scr_addr + link->pmp * 0x10; if (sc_reg > SCR_CONTROL) return -EINVAL; @@ -192,39 +172,23 @@ static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) if (ap->flags & SIS_FLAG_CFGSCR) return sis_scr_cfg_read(link, sc_reg, val); - pci_read_config_byte(pdev, SIS_PMR, &pmr); - - *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); - - if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || - (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) - *val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); - - *val &= 0xfffffffb; - + *val = ioread32(base + sc_reg * 4); return 0; } static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) { struct ata_port *ap = link->ap; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 pmr; + void __iomem *base = ap->ioaddr.scr_addr + link->pmp * 0x10; if (sc_reg > SCR_CONTROL) return -EINVAL; - pci_read_config_byte(pdev, SIS_PMR, &pmr); - if (ap->flags & SIS_FLAG_CFGSCR) return sis_scr_cfg_write(link, sc_reg, val); - else { - iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); - if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || - (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) - iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10); - return 0; - } + + iowrite32(val, base + (sc_reg * 4)); + return 0; } static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -236,7 +200,7 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) u32 genctl, val; u8 pmr; u8 port2_start = 0x20; - int rc; + int i, rc; if (!printed_version++) dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); @@ -319,6 +283,17 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; + for (i = 0; i < 2; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap->flags & ATA_FLAG_SATA && + ap->flags & ATA_FLAG_SLAVE_POSS) { + rc = ata_slave_link_init(ap); + if (rc) + return rc; + } + } + if (!(pi.flags & SIS_FLAG_CFGSCR)) { void __iomem *mmio; -- cgit v0.10.2 From bd30add88cea831dfb854d564478f09ee66206b5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 3 Sep 2009 16:08:11 +0900 Subject: libata: unbreak TPM filtering by reorganizing ata_scsi_pass_thru() ata_scsi_pass_thru() was checking for input sanity and disallowed commands while initializaing qc from scmd. TPM filtering was added right after protocol check at which point tf wasn't initialized properly. This means that TPM filtering has never really worked. This patch fixes the bug by reorganizing ata_scsi_pass_thru() such that qc is fully initialized before checking for invalid conditions which is way less error prone. Discovered while Thilo-Alexander Ginkel was trying debug patches for bko#13416. Signed-off-by: Tejun Heo Cc: Thilo-Alexander Ginkel Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 5d7a1bd..b4ee28d 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2760,28 +2760,6 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) goto invalid_fld; /* - * Filter TPM commands by default. These provide an - * essentially uncontrolled encrypted "back door" between - * applications and the disk. Set libata.allow_tpm=1 if you - * have a real reason for wanting to use them. This ensures - * that installed software cannot easily mess stuff up without - * user intent. DVR type users will probably ship with this enabled - * for movie content management. - * - * Note that for ATA8 we can issue a DCS change and DCS freeze lock - * for this and should do in future but that it is not sufficient as - * DCS is an optional feature set. Thus we also do the software filter - * so that we comply with the TC consortium stated goal that the user - * can turn off TC features of their system. - */ - if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm) - goto invalid_fld; - - /* We may not issue DMA commands if no DMA mode is set */ - if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0) - goto invalid_fld; - - /* * 12 and 16 byte CDBs use different offsets to * provide the various register values. */ @@ -2830,6 +2808,41 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) tf->device = dev->devno ? tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1; + /* READ/WRITE LONG use a non-standard sect_size */ + qc->sect_size = ATA_SECT_SIZE; + switch (tf->command) { + case ATA_CMD_READ_LONG: + case ATA_CMD_READ_LONG_ONCE: + case ATA_CMD_WRITE_LONG: + case ATA_CMD_WRITE_LONG_ONCE: + if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) + goto invalid_fld; + qc->sect_size = scsi_bufflen(scmd); + } + + /* + * Set flags so that all registers will be written, pass on + * write indication (used for PIO/DMA setup), result TF is + * copied back and we don't whine too much about its failure. + */ + tf->flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + if (scmd->sc_data_direction == DMA_TO_DEVICE) + tf->flags |= ATA_TFLAG_WRITE; + + qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET; + + /* + * Set transfer length. + * + * TODO: find out if we need to do more here to + * cover scatter/gather case. + */ + ata_qc_set_pc_nbytes(qc); + + /* We may not issue DMA commands if no DMA mode is set */ + if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0) + goto invalid_fld; + /* sanity check for pio multi commands */ if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf)) goto invalid_fld; @@ -2846,18 +2859,6 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) multi_count); } - /* READ/WRITE LONG use a non-standard sect_size */ - qc->sect_size = ATA_SECT_SIZE; - switch (tf->command) { - case ATA_CMD_READ_LONG: - case ATA_CMD_READ_LONG_ONCE: - case ATA_CMD_WRITE_LONG: - case ATA_CMD_WRITE_LONG_ONCE: - if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) - goto invalid_fld; - qc->sect_size = scsi_bufflen(scmd); - } - /* * Filter SET_FEATURES - XFER MODE command -- otherwise, * SET_FEATURES - XFER MODE must be preceded/succeeded @@ -2865,30 +2866,27 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) * controller (i.e. the reason for ->set_piomode(), * ->set_dmamode(), and ->post_set_mode() hooks). */ - if ((tf->command == ATA_CMD_SET_FEATURES) - && (tf->feature == SETFEATURES_XFER)) + if (tf->command == ATA_CMD_SET_FEATURES && + tf->feature == SETFEATURES_XFER) goto invalid_fld; /* - * Set flags so that all registers will be written, - * and pass on write indication (used for PIO/DMA - * setup.) - */ - tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE); - - if (scmd->sc_data_direction == DMA_TO_DEVICE) - tf->flags |= ATA_TFLAG_WRITE; - - /* - * Set transfer length. + * Filter TPM commands by default. These provide an + * essentially uncontrolled encrypted "back door" between + * applications and the disk. Set libata.allow_tpm=1 if you + * have a real reason for wanting to use them. This ensures + * that installed software cannot easily mess stuff up without + * user intent. DVR type users will probably ship with this enabled + * for movie content management. * - * TODO: find out if we need to do more here to - * cover scatter/gather case. + * Note that for ATA8 we can issue a DCS change and DCS freeze lock + * for this and should do in future but that it is not sufficient as + * DCS is an optional feature set. Thus we also do the software filter + * so that we comply with the TC consortium stated goal that the user + * can turn off TC features of their system. */ - ata_qc_set_pc_nbytes(qc); - - /* request result TF and be quiet about device error */ - qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET; + if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm) + goto invalid_fld; return 0; -- cgit v0.10.2 From 02c24fa87724bb3af969463cd74dc3b3feb24740 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 16 Aug 2009 21:01:22 +0900 Subject: dmi: fix date handling in dmi_get_year() Year parsing in dmi_get_year() had the following two bugs. * "00" is treated as invalid instead of 2000 because zero return from simple_strtoul() is treated as error. * "0N" where N >= 8 is treated as invalid of 200N because the leading 0 is considered to specify octal. Fix the above two bugs by using endptr to detect invalid number and forcing decimal. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 24c84ae..531e621 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -577,6 +577,7 @@ int dmi_get_year(int field) { int year; const char *s = dmi_get_system_info(field); + char *e; if (!s) return -1; @@ -587,8 +588,8 @@ int dmi_get_year(int field) return 0; s += 1; - year = simple_strtoul(s, NULL, 0); - if (year && year < 100) { /* 2-digit year */ + year = simple_strtoul(s, &e, 10); + if (s != e && year < 100) { /* 2-digit year */ year += 1900; if (year < 1996) /* no dates < spec 1.0 */ year += 100; -- cgit v0.10.2 From 3e5cd1f2576c720f1d0705fdd7ba64f27e8836b7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 16 Aug 2009 21:02:36 +0900 Subject: dmi: extend dmi_get_year() to dmi_get_date() There are cases where full date information is required instead of just the year. Add month and day parsing to dmi_get_year() and rename it to dmi_get_date(). As the original function only required '/' followed by any number of parseable characters at the end of the string, keep that behavior to avoid upsetting existing users. The new function takes dates of format [mm[/dd]]/yy[yy]. Year, month and date are checked to be in the ranges of [1-9999], [1-12] and [1-31] respectively and any invalid or out-of-range component is returned as zero. The dummy implementation is updated accordingly but the return value is updated to indicate field not found which is consistent with how other dummy functions behave. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik diff --git a/arch/x86/pci/direct.c b/arch/x86/pci/direct.c index bd13c3e..347d882 100644 --- a/arch/x86/pci/direct.c +++ b/arch/x86/pci/direct.c @@ -192,13 +192,14 @@ struct pci_raw_ops pci_direct_conf2 = { static int __init pci_sanity_check(struct pci_raw_ops *o) { u32 x = 0; - int devfn; + int year, devfn; if (pci_probe & PCI_NO_CHECKS) return 1; /* Assume Type 1 works for newer systems. This handles machines that don't have anything on PCI Bus 0. */ - if (dmi_get_year(DMI_BIOS_DATE) >= 2001) + dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL); + if (year >= 2001) return 1; for (devfn = 0; devfn < 0x100; devfn++) { diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index f6baa77..0c4ca4d 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -78,9 +78,10 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = { static int __init blacklist_by_year(void) { - int year = dmi_get_year(DMI_BIOS_DATE); + int year; + /* Doesn't exist? Likely an old system */ - if (year == -1) { + if (!dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL)) { printk(KERN_ERR PREFIX "no DMI BIOS year, " "acpi=force is required to enable ACPI\n" ); return 1; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index be4c39f..147b9be 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -2679,7 +2679,7 @@ static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev) * different versions. */ date = dmi_get_system_info(DMI_BIOS_DATE); - year = dmi_get_year(DMI_BIOS_DATE); + dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL); if (date && strlen(date) >= 10 && date[2] == '/' && date[5] == '/' && (year > 2007 || (year == 2007 && strncmp(date, cutoff_mmdd, 5) >= 0))) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 531e621..938100f 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -568,36 +568,76 @@ const struct dmi_device * dmi_find_device(int type, const char *name, EXPORT_SYMBOL(dmi_find_device); /** - * dmi_get_year - Return year of a DMI date - * @field: data index (like dmi_get_system_info) + * dmi_get_date - parse a DMI date + * @field: data index (see enum dmi_field) + * @yearp: optional out parameter for the year + * @monthp: optional out parameter for the month + * @dayp: optional out parameter for the day * - * Returns -1 when the field doesn't exist. 0 when it is broken. + * The date field is assumed to be in the form resembling + * [mm[/dd]]/yy[yy] and the result is stored in the out + * parameters any or all of which can be omitted. + * + * If the field doesn't exist, all out parameters are set to zero + * and false is returned. Otherwise, true is returned with any + * invalid part of date set to zero. + * + * On return, year, month and day are guaranteed to be in the + * range of [0,9999], [0,12] and [0,31] respectively. */ -int dmi_get_year(int field) +bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) { - int year; - const char *s = dmi_get_system_info(field); + int year = 0, month = 0, day = 0; + bool exists; + const char *s, *y; char *e; - if (!s) - return -1; - if (*s == '\0') - return 0; - s = strrchr(s, '/'); - if (!s) - return 0; + s = dmi_get_system_info(field); + exists = s; + if (!exists) + goto out; - s += 1; - year = simple_strtoul(s, &e, 10); - if (s != e && year < 100) { /* 2-digit year */ + /* + * Determine year first. We assume the date string resembles + * mm/dd/yy[yy] but the original code extracted only the year + * from the end. Keep the behavior in the spirit of no + * surprises. + */ + y = strrchr(s, '/'); + if (!y) + goto out; + + y++; + year = simple_strtoul(y, &e, 10); + if (y != e && year < 100) { /* 2-digit year */ year += 1900; if (year < 1996) /* no dates < spec 1.0 */ year += 100; } + if (year > 9999) /* year should fit in %04d */ + year = 0; + + /* parse the mm and dd */ + month = simple_strtoul(s, &e, 10); + if (s == e || *e != '/' || !month || month > 12) { + month = 0; + goto out; + } - return year; + s = e + 1; + day = simple_strtoul(s, &e, 10); + if (s == y || s == e || *e != '/' || day > 31) + day = 0; +out: + if (yearp) + *yearp = year; + if (monthp) + *monthp = month; + if (dayp) + *dayp = day; + return exists; } -EXPORT_SYMBOL(dmi_get_year); +EXPORT_SYMBOL(dmi_get_date); /** * dmi_walk - Walk the DMI table and get called back for every record diff --git a/include/linux/dmi.h b/include/linux/dmi.h index bb5489c..a8a3e1a 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h @@ -43,7 +43,7 @@ extern const char * dmi_get_system_info(int field); extern const struct dmi_device * dmi_find_device(int type, const char *name, const struct dmi_device *from); extern void dmi_scan_machine(void); -extern int dmi_get_year(int field); +extern bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp); extern int dmi_name_in_vendors(const char *str); extern int dmi_name_in_serial(const char *str); extern int dmi_available; @@ -58,7 +58,16 @@ static inline const char * dmi_get_system_info(int field) { return NULL; } static inline const struct dmi_device * dmi_find_device(int type, const char *name, const struct dmi_device *from) { return NULL; } static inline void dmi_scan_machine(void) { return; } -static inline int dmi_get_year(int year) { return 0; } +static inline bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) +{ + if (yearp) + *yearp = 0; + if (monthp) + *monthp = 0; + if (dayp) + *dayp = 0; + return false; +} static inline int dmi_name_in_vendors(const char *s) { return 0; } static inline int dmi_name_in_serial(const char *s) { return 0; } #define dmi_available 0 -- cgit v0.10.2 From 03d783bf5573ff316a8c703eed811a9a97901a8b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 16 Aug 2009 21:04:02 +0900 Subject: ahci: make ahci_asus_m2a_vm_32bit_only() quirk more generic It turns out ASUS M2A-VM isn't the only one with the 32bit DMA problem. Make ahci_asus_m2a_vm_32bit_only() more generic using the new dmi_get_date() and rename it to ahci_sb600_32bit_only(). Cut off date is now pointed to by dmi_system_id->driver_data in "yyyymmdd" format and it's now also allowed to be omitted. Signed-off-by: Tejun Heo Cc: Sandor Bodo-Merle Cc: Shane Huang Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 147b9be..aa03b49a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -2647,14 +2647,18 @@ static void ahci_p5wdh_workaround(struct ata_host *host) } /* - * SB600 ahci controller on ASUS M2A-VM can't do 64bit DMA with older - * BIOS. The oldest version known to be broken is 0901 and working is - * 1501 which was released on 2007-10-26. Force 32bit DMA on anything - * older than 1501. Please read bko#9412 for more info. + * SB600 ahci controller on certain boards can't do 64bit DMA with + * older BIOS. */ -static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev) +static bool ahci_sb600_32bit_only(struct pci_dev *pdev) { static const struct dmi_system_id sysids[] = { + /* + * The oldest version known to be broken is 0901 and + * working is 1501 which was released on 2007-10-26. + * Force 32bit DMA on anything older than 1501. + * Please read bko#9412 for more info. + */ { .ident = "ASUS M2A-VM", .matches = { @@ -2662,31 +2666,32 @@ static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev) "ASUSTeK Computer INC."), DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"), }, + .driver_data = "20071026", /* yyyymmdd */ }, { } }; - const char *cutoff_mmdd = "10/26"; - const char *date; - int year; + const struct dmi_system_id *match; + match = dmi_first_match(sysids); if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) || - !dmi_check_system(sysids)) + !match) return false; - /* - * Argh.... both version and date are free form strings. - * Let's hope they're using the same date format across - * different versions. - */ - date = dmi_get_system_info(DMI_BIOS_DATE); - dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL); - if (date && strlen(date) >= 10 && date[2] == '/' && date[5] == '/' && - (year > 2007 || - (year == 2007 && strncmp(date, cutoff_mmdd, 5) >= 0))) - return false; + if (match->driver_data) { + int year, month, date; + char buf[9]; + + dmi_get_date(DMI_BIOS_DATE, &year, &month, &date); + snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date); - dev_printk(KERN_WARNING, &pdev->dev, "ASUS M2A-VM: BIOS too old, " - "forcing 32bit DMA, update BIOS\n"); + if (strcmp(buf, match->driver_data) >= 0) + return false; + + dev_printk(KERN_WARNING, &pdev->dev, "%s: BIOS too old, " + "forcing 32bit DMA, update BIOS\n", match->ident); + } else + dev_printk(KERN_WARNING, &pdev->dev, "%s: this board can't " + "do 64bit DMA, forcing 32bit\n", match->ident); return true; } @@ -2901,8 +2906,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (board_id == board_ahci_sb700 && pdev->revision >= 0x40) hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL; - /* apply ASUS M2A_VM quirk */ - if (ahci_asus_m2a_vm_32bit_only(pdev)) + /* apply sb600 32bit only quirk */ + if (ahci_sb600_32bit_only(pdev)) hpriv->flags |= AHCI_HFLAG_32BIT_ONLY; if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) -- cgit v0.10.2 From 1b549dcbf607e88f3016bc149109472a46fe7bbb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 16 Aug 2009 21:06:57 +0900 Subject: ahci: Gigabyte GA-MA69VM-S2 can't do 64bit DMA Gigabyte GA-MA69VM-S2 can't do 64bit DMA either. It's yet unknown whether recent BIOS fixes the problem. Blacklist regardless of BIOS revisions for now. Sandor Bodo-Merle reported and provided the initial patch for this issue. Signed-off-by: Tejun Heo Reported-by: Sandor Bodo-Merle Cc: Shane Huang Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index aa03b49a..a4e4cf1 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -2668,6 +2668,22 @@ static bool ahci_sb600_32bit_only(struct pci_dev *pdev) }, .driver_data = "20071026", /* yyyymmdd */ }, + /* + * It's yet unknown whether more recent BIOS fixes the + * problem. Blacklist the whole board for the time + * being. Please read the following thread for more + * info. + * + * http://thread.gmane.org/gmane.linux.ide/42326 + */ + { + .ident = "Gigabyte GA-MA69VM-S2", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, + "Gigabyte Technology Co., Ltd."), + DMI_MATCH(DMI_BOARD_NAME, "GA-MA69VM-S2"), + }, + }, { } }; const struct dmi_system_id *match; -- cgit v0.10.2 From ac8672ea922bde59acf50eaa1eaa1640a6395fd2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 16 Aug 2009 21:21:21 +0900 Subject: libata: fix off-by-one error in ata_tf_read_block() ata_tf_read_block() has off-by-one error when converting CHS address to LBA. The bug isn't very visible because ata_tf_read_block() is used only when generating sense data for a failed RW command and CHS addressing isn't used too often these days. This problem was spotted by Atsushi Nemoto. Signed-off-by: Tejun Heo Reported-by: Atsushi Nemoto Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 98af50f..df31dea 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -709,7 +709,13 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev) head = tf->device & 0xf; sect = tf->lbal; - block = (cyl * dev->heads + head) * dev->sectors + sect; + if (!sect) { + ata_dev_printk(dev, KERN_WARNING, "device reported " + "invalid CHS sector 0\n"); + sect = 1; /* oh well */ + } + + block = (cyl * dev->heads + head) * dev->sectors + sect - 1; } return block; -- cgit v0.10.2 From deeb003e5e01c0db02bb68fd9c93faf75ab9002d Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Tue, 8 Sep 2009 17:37:01 +0800 Subject: libata: add SATA PMP revision information for spec 1.2 This small patch is just adding the information for PMP spec 1.2 Signed-off-by: Shane Huang Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 619f2c3..51f0ffb 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -221,6 +221,8 @@ static const char *sata_pmp_spec_rev_str(const u32 *gscr) { u32 rev = gscr[SATA_PMP_GSCR_REV]; + if (rev & (1 << 3)) + return "1.2"; if (rev & (1 << 2)) return "1.1"; if (rev & (1 << 1)) -- cgit v0.10.2 From f90f613c3ed7381209de8aa36458442b5130170b Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Wed, 29 Jul 2009 21:15:49 +0530 Subject: sata_fsl: Defer non-ncq commands when ncq commands active Fix for non-ncq & ncq commands causing timeouts when both are issued simultaneously to the same device. Signed-off-by: Ashish Kalra [fixed to be actual compileable C code -jg] Signed-off-by: Jeff Garzik diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 94eaa43..d344db4 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1257,6 +1257,7 @@ static struct scsi_host_template sata_fsl_sht = { static struct ata_port_operations sata_fsl_ops = { .inherits = &sata_pmp_port_ops, + .qc_defer = ata_std_qc_defer, .qc_prep = sata_fsl_qc_prep, .qc_issue = sata_fsl_qc_issue, .qc_fill_rtf = sata_fsl_qc_fill_rtf, -- cgit v0.10.2 From a8f22264550e64c0cd11fb6647284b0bd6407f9c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 8 Sep 2009 23:16:06 -0700 Subject: sparc64: Manage NMI watchdog enabling like x86. Use a per-cpu 'wd_enabled' boolean and a global atomic_t count of watchdog NMI enabled cpus which is set to '-1' if something is wrong with the watchdog and it can't be used. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/nmi.h b/arch/sparc/include/asm/nmi.h index fbd546d..c7d11e4 100644 --- a/arch/sparc/include/asm/nmi.h +++ b/arch/sparc/include/asm/nmi.h @@ -5,6 +5,6 @@ extern int __init nmi_init(void); extern void perfctr_irq(int irq, struct pt_regs *regs); extern void nmi_adjust_hz(unsigned int new_hz); -extern int nmi_usable; +extern atomic_t nmi_active; #endif /* __NMI_H */ diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index 2c0cc72..d1614e8 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c @@ -34,10 +34,17 @@ static int nmi_watchdog_active; static int panic_on_timeout; -int nmi_usable; -EXPORT_SYMBOL_GPL(nmi_usable); +/* nmi_active: + * >0: the NMI watchdog is active, but can be disabled + * <0: the NMI watchdog has not been set up, and cannot be enabled + * 0: the NMI watchdog is disabled, but can be enabled + */ +atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */ +EXPORT_SYMBOL(nmi_active); static unsigned int nmi_hz = HZ; +static DEFINE_PER_CPU(short, wd_enabled); +static int endflag __initdata; static DEFINE_PER_CPU(unsigned int, last_irq_sum); static DEFINE_PER_CPU(local_t, alert_counter); @@ -110,7 +117,7 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) __get_cpu_var(last_irq_sum) = sum; local_set(&__get_cpu_var(alert_counter), 0); } - if (nmi_usable) { + if (__get_cpu_var(wd_enabled)) { write_pic(picl_value(nmi_hz)); pcr_ops->write(pcr_enable); } @@ -121,8 +128,6 @@ static inline unsigned int get_nmi_count(int cpu) return cpu_data(cpu).__nmi_count; } -static int endflag __initdata; - static __init void nmi_cpu_busy(void *data) { local_irq_enable_in_hardirq(); @@ -143,12 +148,15 @@ static void report_broken_nmi(int cpu, int *prev_nmi_count) printk(KERN_WARNING "and attach the output of the 'dmesg' command.\n"); - nmi_usable = 0; + per_cpu(wd_enabled, cpu) = 0; + atomic_dec(&nmi_active); } -static void stop_watchdog(void *unused) +static void stop_nmi_watchdog(void *unused) { pcr_ops->write(PCR_PIC_PRIV); + __get_cpu_var(wd_enabled) = 0; + atomic_dec(&nmi_active); } static int __init check_nmi_watchdog(void) @@ -156,6 +164,9 @@ static int __init check_nmi_watchdog(void) unsigned int *prev_nmi_count; int cpu, err; + if (!atomic_read(&nmi_active)) + return 0; + prev_nmi_count = kmalloc(nr_cpu_ids * sizeof(unsigned int), GFP_KERNEL); if (!prev_nmi_count) { err = -ENOMEM; @@ -172,12 +183,15 @@ static int __init check_nmi_watchdog(void) mdelay((20 * 1000) / nmi_hz); /* wait 20 ticks */ for_each_online_cpu(cpu) { + if (!per_cpu(wd_enabled, cpu)) + continue; if (get_nmi_count(cpu) - prev_nmi_count[cpu] <= 5) report_broken_nmi(cpu, prev_nmi_count); } endflag = 1; - if (!nmi_usable) { + if (!atomic_read(&nmi_active)) { kfree(prev_nmi_count); + atomic_set(&nmi_active, -1); err = -ENODEV; goto error; } @@ -188,12 +202,26 @@ static int __init check_nmi_watchdog(void) kfree(prev_nmi_count); return 0; error: - on_each_cpu(stop_watchdog, NULL, 1); + on_each_cpu(stop_nmi_watchdog, NULL, 1); return err; } -static void start_watchdog(void *unused) +static void start_nmi_watchdog(void *unused) +{ + __get_cpu_var(wd_enabled) = 1; + atomic_inc(&nmi_active); + + pcr_ops->write(PCR_PIC_PRIV); + write_pic(picl_value(nmi_hz)); + + pcr_ops->write(pcr_enable); +} + +static void nmi_adjust_hz_one(void *unused) { + if (!__get_cpu_var(wd_enabled)) + return; + pcr_ops->write(PCR_PIC_PRIV); write_pic(picl_value(nmi_hz)); @@ -203,13 +231,13 @@ static void start_watchdog(void *unused) void nmi_adjust_hz(unsigned int new_hz) { nmi_hz = new_hz; - on_each_cpu(start_watchdog, NULL, 1); + on_each_cpu(nmi_adjust_hz_one, NULL, 1); } EXPORT_SYMBOL_GPL(nmi_adjust_hz); static int nmi_shutdown(struct notifier_block *nb, unsigned long cmd, void *p) { - on_each_cpu(stop_watchdog, NULL, 1); + on_each_cpu(stop_nmi_watchdog, NULL, 1); return 0; } @@ -221,16 +249,14 @@ int __init nmi_init(void) { int err; - nmi_usable = 1; - - on_each_cpu(start_watchdog, NULL, 1); + on_each_cpu(start_nmi_watchdog, NULL, 1); err = check_nmi_watchdog(); if (!err) { err = register_reboot_notifier(&nmi_reboot_notifier); if (err) { - nmi_usable = 0; - on_each_cpu(stop_watchdog, NULL, 1); + on_each_cpu(stop_nmi_watchdog, NULL, 1); + atomic_set(&nmi_active, -1); } } return err; diff --git a/arch/sparc/oprofile/init.c b/arch/sparc/oprofile/init.c index d172f86..9ce34fd 100644 --- a/arch/sparc/oprofile/init.c +++ b/arch/sparc/oprofile/init.c @@ -57,7 +57,7 @@ static void timer_stop(void) static int op_nmi_timer_init(struct oprofile_operations *ops) { - if (!nmi_usable) + if (atomic_read(&nmi_active) <= 0) return -ENODEV; ops->start = timer_start; -- cgit v0.10.2 From 4e85f5915dedb7c852c1e1189aa4133c87798a5e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 8 Sep 2009 23:20:39 -0700 Subject: sparc64: Kill unnecessary cast in profile_timer_exceptions_notify(). Signed-off-by: David S. Miller diff --git a/arch/sparc/oprofile/init.c b/arch/sparc/oprofile/init.c index 9ce34fd..f97cb8b 100644 --- a/arch/sparc/oprofile/init.c +++ b/arch/sparc/oprofile/init.c @@ -21,7 +21,7 @@ static int profile_timer_exceptions_notify(struct notifier_block *self, unsigned long val, void *data) { - struct die_args *args = (struct die_args *)data; + struct die_args *args = data; int ret = NOTIFY_DONE; switch (val) { -- cgit v0.10.2 From d89be56b2153ccad7e8cd9e71b5d8b686632e8c2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 8 Sep 2009 23:29:16 -0700 Subject: sparc64: Make touch_nmi_watchdog() actually work. It guards it's actions on nmi_watchdog_active, but nothing ever sets that and it's initial value is zero. Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index d1614e8..47a465f 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c @@ -31,7 +31,6 @@ * level 14 as our IRQ off level. */ -static int nmi_watchdog_active; static int panic_on_timeout; /* nmi_active: @@ -52,7 +51,7 @@ static DEFINE_PER_CPU(int, nmi_touch); void touch_nmi_watchdog(void) { - if (nmi_watchdog_active) { + if (atomic_read(&nmi_active)) { int cpu; for_each_present_cpu(cpu) { -- cgit v0.10.2 From 733e5e4b4eb1bc1e27acbe092200154051171426 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 9 Sep 2009 08:30:21 +0100 Subject: KEYS: Add missing linux/tracehook.h #inclusions Add #inclusions of linux/tracehook.h to those arch files that had the tracehook call for TIF_NOTIFY_RESUME added when support for that flag was added to that arch. Signed-off-by: David Howells Signed-off-by: James Morris diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index d91aaa7..0932dbb 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index ea4ad3a..b76fe06 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index de9f7fe..64f886f 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c index 32e9d5e..48b0f39 100644 --- a/arch/cris/kernel/ptrace.c +++ b/arch/cris/kernel/ptrace.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index abac3ee..af842c3 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index f80bac1..144b0f1 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index c2acf31..6254041 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 5ca1c02..8eb3c63 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From 6f0e013548fd15fddb952f657a3cc81282641191 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 9 Sep 2009 01:41:30 -0700 Subject: niu: Use resource_size instead of private function The function res_size in drivers/net/niu.c is a copy of resource_size in linux/ioport.h. Remove the function and use resource_size instead. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 119fd4e..76cc261 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -10145,11 +10145,6 @@ static const struct niu_ops niu_phys_ops = { .unmap_single = niu_phys_unmap_single, }; -static unsigned long res_size(struct resource *r) -{ - return r->end - r->start + 1UL; -} - static int __devinit niu_of_probe(struct of_device *op, const struct of_device_id *match) { @@ -10189,7 +10184,7 @@ static int __devinit niu_of_probe(struct of_device *op, dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM); np->regs = of_ioremap(&op->resource[1], 0, - res_size(&op->resource[1]), + resource_size(&op->resource[1]), "niu regs"); if (!np->regs) { dev_err(&op->dev, PFX "Cannot map device registers, " @@ -10199,7 +10194,7 @@ static int __devinit niu_of_probe(struct of_device *op, } np->vir_regs_1 = of_ioremap(&op->resource[2], 0, - res_size(&op->resource[2]), + resource_size(&op->resource[2]), "niu vregs-1"); if (!np->vir_regs_1) { dev_err(&op->dev, PFX "Cannot map device vir registers 1, " @@ -10209,7 +10204,7 @@ static int __devinit niu_of_probe(struct of_device *op, } np->vir_regs_2 = of_ioremap(&op->resource[3], 0, - res_size(&op->resource[3]), + resource_size(&op->resource[3]), "niu vregs-2"); if (!np->vir_regs_2) { dev_err(&op->dev, PFX "Cannot map device vir registers 2, " @@ -10244,19 +10239,19 @@ static int __devinit niu_of_probe(struct of_device *op, err_out_iounmap: if (np->vir_regs_1) { of_iounmap(&op->resource[2], np->vir_regs_1, - res_size(&op->resource[2])); + resource_size(&op->resource[2])); np->vir_regs_1 = NULL; } if (np->vir_regs_2) { of_iounmap(&op->resource[3], np->vir_regs_2, - res_size(&op->resource[3])); + resource_size(&op->resource[3])); np->vir_regs_2 = NULL; } if (np->regs) { of_iounmap(&op->resource[1], np->regs, - res_size(&op->resource[1])); + resource_size(&op->resource[1])); np->regs = NULL; } @@ -10281,19 +10276,19 @@ static int __devexit niu_of_remove(struct of_device *op) if (np->vir_regs_1) { of_iounmap(&op->resource[2], np->vir_regs_1, - res_size(&op->resource[2])); + resource_size(&op->resource[2])); np->vir_regs_1 = NULL; } if (np->vir_regs_2) { of_iounmap(&op->resource[3], np->vir_regs_2, - res_size(&op->resource[3])); + resource_size(&op->resource[3])); np->vir_regs_2 = NULL; } if (np->regs) { of_iounmap(&op->resource[1], np->regs, - res_size(&op->resource[1])); + resource_size(&op->resource[1])); np->regs = NULL; } -- cgit v0.10.2 From 5d5d9c97ff807b643b6c2284dea7fe04ecc74355 Mon Sep 17 00:00:00 2001 From: Tushar Gohad Date: Wed, 9 Sep 2009 03:42:23 -0700 Subject: IPv6/addrconf: Fix minor addrlabel thinko Fix apparent thinko related to RTM_DELADDRLABEL, introduced by commit 2a8cc6c89039e0530a3335954253b76ed0f9339a ("[IPV6] ADDRCONF: Support RFC3484 configurable address selection policy table."). Signed-off-by: Tushar Gohad Signed-off-by: David S. Miller diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index ba3254e..adf2068 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -104,7 +104,7 @@ enum { RTM_NEWADDRLABEL = 72, #define RTM_NEWADDRLABEL RTM_NEWADDRLABEL RTM_DELADDRLABEL, -#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL +#define RTM_DELADDRLABEL RTM_DELADDRLABEL RTM_GETADDRLABEL, #define RTM_GETADDRLABEL RTM_GETADDRLABEL -- cgit v0.10.2 From fa1a9c681377c57e233038e50479e7d7a5cc3108 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 9 Sep 2009 03:43:50 -0700 Subject: headers: net/ipv[46]/protocol.c header trim Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c index ea50da0..a2e5fc0 100644 --- a/net/ipv4/protocol.c +++ b/net/ipv4/protocol.c @@ -22,26 +22,11 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ - -#include -#include +#include #include -#include -#include -#include -#include -#include -#include #include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include struct net_protocol *inet_protos[MAX_INET_PROTOS] ____cacheline_aligned_in_smp; static DEFINE_SPINLOCK(inet_proto_lock); diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index 9ab7891..568864f 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c @@ -20,20 +20,9 @@ * - Removed unused variable 'inet6_protocol_base' * - Modified inet6_del_protocol() to correctly maintain copy bit. */ - -#include -#include -#include -#include -#include -#include +#include #include -#include - -#include -#include - -#include +#include #include struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; -- cgit v0.10.2 From 4789666e13fb0b2d45feb1b4a5119a1b997ec84c Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 6 Sep 2009 15:14:23 +0200 Subject: rt2x00: Hardcode TX ack timeout and consume time The calculated values for the ACK timeout and ACK consume time are different then the values as used by the Legacy drivers. After testing from James Ledwith it appeared that the calculated values caused a high amount of TX failures, and the values from the Legacy drivers were the most optimal to prevent TX failure due to excessive retries. The symptoms of this problem: - Rate control module always falls back to 1Mbs - Low throughput when bitrate was fixed Possible side-effects (not confirmed but highly likely) - Problems with DHCP - Broken connections due to lack of probe response This should fix at least: Kernel bugzilla reports: [13362], [13009], [9273] Fedora bugzilla reports: [443203] but possible some additional bugs as well. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 164df93..798f625 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -331,9 +331,8 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, - erp->ack_consume_time); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x1ff); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0x13a); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 4186582..2e872ac 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -337,9 +337,8 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, - erp->ack_consume_time); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x162); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0xa2); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index b04f59b..22dd6d9 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -488,10 +488,6 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, { u16 reg; - rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); - rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, erp->ack_timeout); - rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, !!erp->short_preamble); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 639dc6c..a084077 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -580,8 +580,7 @@ static void rt2800usb_config_erp(struct rt2x00_dev *rt2x00dev, u32 reg; rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); - rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, - DIV_ROUND_UP(erp->ack_timeout, erp->slot_time)); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20); rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 555a777..27bc6b7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -417,9 +417,6 @@ struct rt2x00lib_erp { int short_preamble; int cts_protection; - int ack_timeout; - int ack_consume_time; - u32 basic_rates; int slot_time; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 3501788..40a201e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -94,17 +94,6 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS; erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS; - erp.ack_timeout = PLCP + erp.difs + GET_DURATION(ACK_SIZE, 10); - erp.ack_consume_time = SIFS + PLCP + GET_DURATION(ACK_SIZE, 10); - - if (bss_conf->use_short_preamble) { - erp.ack_timeout += SHORT_PREAMBLE; - erp.ack_consume_time += SHORT_PREAMBLE; - } else { - erp.ack_timeout += PREAMBLE; - erp.ack_consume_time += PREAMBLE; - } - erp.basic_rates = bss_conf->basic_rates; erp.beacon_int = bss_conf->beacon_int; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index f4b4b86..b20e3ea 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -598,7 +598,7 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, u32 reg; rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 90e1172..1cbd9b4 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -561,7 +561,7 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, u32 reg; rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); -- cgit v0.10.2 From b0544eb6019a33e836141156a8fbe74a9f8367b4 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 6 Sep 2009 15:42:45 +0200 Subject: b43: Really disable QoS, if requested Currently, when QoS-disable is requested, we would leave QoS enabled in firmware, but only queue frames on one queue. Change that and also tell firmware about disabled QoS, so it completely ignores all the QoS parameters. Also don't upload the parameters, if QoS is disabled. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 0a4d0b3..d29323d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3093,7 +3093,6 @@ static int b43_op_tx(struct ieee80211_hw *hw, return NETDEV_TX_OK; } -/* Locking: wl->irq_lock */ static void b43_qos_params_upload(struct b43_wldev *dev, const struct ieee80211_tx_queue_params *p, u16 shm_offset) @@ -3102,6 +3101,9 @@ static void b43_qos_params_upload(struct b43_wldev *dev, int bslots, tmp; unsigned int i; + if (!dev->qos_enabled) + return; + bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min; memset(¶ms, 0, sizeof(params)); @@ -3147,6 +3149,9 @@ static void b43_qos_upload_all(struct b43_wldev *dev) struct b43_qos_params *params; unsigned int i; + if (!dev->qos_enabled) + return; + BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != ARRAY_SIZE(wl->qos_params)); @@ -3206,6 +3211,16 @@ static void b43_qos_clear(struct b43_wl *wl) /* Initialize the core's QOS capabilities */ static void b43_qos_init(struct b43_wldev *dev) { + if (!dev->qos_enabled) { + /* Disable QOS support. */ + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_EDCF); + b43_write16(dev, B43_MMIO_IFSCTL, + b43_read16(dev, B43_MMIO_IFSCTL) + & ~B43_MMIO_IFSCTL_USE_EDCF); + b43dbg(dev->wl, "QoS disabled\n"); + return; + } + /* Upload the current QOS parameters. */ b43_qos_upload_all(dev); @@ -3214,6 +3229,7 @@ static void b43_qos_init(struct b43_wldev *dev) b43_write16(dev, B43_MMIO_IFSCTL, b43_read16(dev, B43_MMIO_IFSCTL) | B43_MMIO_IFSCTL_USE_EDCF); + b43dbg(dev->wl, "QoS enabled\n"); } static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, -- cgit v0.10.2 From cde1b55b43b71cabb1a94278a809bca21b9df791 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 6 Sep 2009 16:18:58 +0200 Subject: b43: Fix sparse warning in hw-tkip code This fixes a sparse warning in the hardware-TKIP code: drivers/net/wireless/b43/xmit.c:272:18: warning: incorrect type in assignment (different base types) drivers/net/wireless/b43/xmit.c:272:18: expected unsigned short [unsigned] [short] drivers/net/wireless/b43/xmit.c:272:18: got restricted unsigned short [usertype] The code should work correctly with and without this patch applied. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index e7075d2..14f5412 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -267,11 +267,11 @@ int b43_generate_txhdr(struct b43_wldev *dev, */ ieee80211_get_tkip_key(info->control.hw_key, skb_frag, IEEE80211_TKIP_P1_KEY, (u8*)phase1key); - /* phase1key is in host endian */ - for (i = 0; i < 5; i++) - phase1key[i] = cpu_to_le16(phase1key[i]); - - memcpy(txhdr->iv, phase1key, 10); + /* phase1key is in host endian. Copy to little-endian txhdr->iv. */ + for (i = 0; i < 5; i++) { + txhdr->iv[i * 2 + 0] = phase1key[i]; + txhdr->iv[i * 2 + 1] = phase1key[i] >> 8; + } /* iv16 */ memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3); } else { -- cgit v0.10.2 From 72c706b775777e8ae546756a5d07ffda4a05ed7b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 7 Sep 2009 11:34:30 -0700 Subject: MAINTAINERS: Add Atheros Linux wireless drivers home page On Sun, 2009-09-06 at 12:26 -0700, Luis R. Rodriguez wrote: > On Sun, Sep 6, 2009 at 10:59 AM, Joe Perches wrote: > > On Thu, 2009-09-03 at 15:54 -0700, Luis R. Rodriguez wrote: > >> I'm pleased to announce the new home page to Atheros Linux wireless drivers: > >> http://wireless.kernel.org/en/users/Drivers/Atheros > > Perhaps add this to MAINTAINERS? > Fine by me, except ath5k and ath9k also have their own respective page > so those can also be added. (cc's trimmed and maintainers added) Perhaps this instead: Signed-off-by: Joe Perches Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index 0ab47e7..6e2e12f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -876,6 +876,7 @@ M: "Luis R. Rodriguez" M: Bob Copeland L: linux-wireless@vger.kernel.org L: ath5k-devel@lists.ath5k.org +W: http://wireless.kernel.org/en/users/Drivers/ath5k S: Maintained F: drivers/net/wireless/ath/ath5k/ @@ -887,6 +888,7 @@ M: Vasanthakumar Thiagarajan M: Senthil Balasubramanian L: linux-wireless@vger.kernel.org L: ath9k-devel@lists.ath9k.org +W: http://wireless.kernel.org/en/users/Drivers/ath9k S: Supported F: drivers/net/wireless/ath/ath9k/ -- cgit v0.10.2 From 7b6840ab5f836a18c4ea98173f73c8d046930efb Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 7 Sep 2009 17:46:49 +0530 Subject: ath9k: Disable ASPM when btcoex is active Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 011b14f..97a09db 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -16,6 +16,7 @@ #include #include +#include #include "ath9k.h" #include "initvals.h" @@ -4298,3 +4299,16 @@ void ath_gen_timer_isr(struct ath_hw *ah) timer->trigger(timer->arg); } } + +/* + * Primitive to disable ASPM + */ +void ath_pcie_aspm_disable(struct ath_softc *sc) +{ + struct pci_dev *pdev = to_pci_dev(sc->dev); + u8 aspm; + + pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); + aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1); + pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); +} diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 5ca6ffa7..a592f1a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -665,4 +665,9 @@ void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_isr(struct ath_hw *hw); u32 ath9k_hw_gettsf32(struct ath_hw *ah); +#define ATH_PCIE_CAP_LINK_CTRL 0x70 +#define ATH_PCIE_CAP_LINK_L0S 1 +#define ATH_PCIE_CAP_LINK_L1 2 + +void ath_pcie_aspm_disable(struct ath_softc *sc); #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a69fda8..ce011ab 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2010,6 +2010,7 @@ static int ath9k_start(struct ieee80211_hw *hw) AR_STOMP_LOW_WLAN_WGHT); ath9k_hw_btcoex_enable(sc->sc_ah); + ath_pcie_aspm_disable(sc); if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) ath_btcoex_timer_resume(sc, &sc->btcoex_info); } -- cgit v0.10.2 From f020979d5d7c9816c071d0aedf60a889fa4fae40 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 7 Sep 2009 17:46:50 +0530 Subject: ath9k: Remove unnecessary casting to u8 in pci_read_config_byte() call Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 8bb286d..8b28814 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -35,8 +35,7 @@ static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz) { u8 u8tmp; - pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, - (u8 *)&u8tmp); + pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp); *csz = (int)u8tmp; /* -- cgit v0.10.2 From 24ea602e183ca20a7577ebe253323d0e5d0f9847 Mon Sep 17 00:00:00 2001 From: Albert Herranz Date: Tue, 8 Sep 2009 19:30:12 +0200 Subject: ssb: Implement SDIO host bus support Add support for communicating with a Sonics Silicon Backplane through a SDIO interface, as found in the Nintendo Wii WLAN daughter card. The Nintendo Wii WLAN card includes a custom Broadcom 4318 chip with a SDIO host interface. Signed-off-by: Albert Herranz Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 540a294..2d8cc45 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -66,6 +66,20 @@ config SSB_PCMCIAHOST If unsure, say N +config SSB_SDIOHOST_POSSIBLE + bool + depends on SSB && (MMC = y || MMC = SSB) + default y + +config SSB_SDIOHOST + bool "Support for SSB on SDIO-bus host" + depends on SSB_SDIOHOST_POSSIBLE + help + Support for a Sonics Silicon Backplane on top + of a SDIO device. + + If unsure, say N + config SSB_SILENT bool "No SSB kernel messages" depends on SSB && EMBEDDED diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile index cfbb74f..656e58b 100644 --- a/drivers/ssb/Makefile +++ b/drivers/ssb/Makefile @@ -6,6 +6,7 @@ ssb-$(CONFIG_SSB_SPROM) += sprom.o # host support ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o +ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o # built-in drivers ssb-y += driver_chipcommon.o diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 8d16cb2..579b114 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -88,6 +89,25 @@ found: } #endif /* CONFIG_SSB_PCMCIAHOST */ +#ifdef CONFIG_SSB_SDIOHOST +struct ssb_bus *ssb_sdio_func_to_bus(struct sdio_func *func) +{ + struct ssb_bus *bus; + + ssb_buses_lock(); + list_for_each_entry(bus, &buses, list) { + if (bus->bustype == SSB_BUSTYPE_SDIO && + bus->host_sdio == func) + goto found; + } + bus = NULL; +found: + ssb_buses_unlock(); + + return bus; +} +#endif /* CONFIG_SSB_SDIOHOST */ + int ssb_for_each_bus_call(unsigned long data, int (*func)(struct ssb_bus *bus, unsigned long data)) { @@ -469,6 +489,12 @@ static int ssb_devices_register(struct ssb_bus *bus) dev->parent = &bus->host_pcmcia->dev; #endif break; + case SSB_BUSTYPE_SDIO: +#ifdef CONFIG_SSB_SDIO + sdev->irq = bus->host_sdio->dev.irq; + dev->parent = &bus->host_sdio->dev; +#endif + break; case SSB_BUSTYPE_SSB: dev->dma_mask = &dev->coherent_dma_mask; break; @@ -724,12 +750,18 @@ static int ssb_bus_register(struct ssb_bus *bus, err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); if (err) goto out; + + /* Init SDIO-host device (if any), before the scan */ + err = ssb_sdio_init(bus); + if (err) + goto err_disable_xtal; + ssb_buses_lock(); bus->busnumber = next_busnumber; /* Scan for devices (cores) */ err = ssb_bus_scan(bus, baseaddr); if (err) - goto err_disable_xtal; + goto err_sdio_exit; /* Init PCI-host device (if any) */ err = ssb_pci_init(bus); @@ -776,6 +808,8 @@ err_pci_exit: ssb_pci_exit(bus); err_unmap: ssb_iounmap(bus); +err_sdio_exit: + ssb_sdio_exit(bus); err_disable_xtal: ssb_buses_unlock(); ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); @@ -825,6 +859,28 @@ int ssb_bus_pcmciabus_register(struct ssb_bus *bus, EXPORT_SYMBOL(ssb_bus_pcmciabus_register); #endif /* CONFIG_SSB_PCMCIAHOST */ +#ifdef CONFIG_SSB_SDIOHOST +int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func, + unsigned int quirks) +{ + int err; + + bus->bustype = SSB_BUSTYPE_SDIO; + bus->host_sdio = func; + bus->ops = &ssb_sdio_ops; + bus->quirks = quirks; + + err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " + "SDIO device %s\n", sdio_func_id(func)); + } + + return err; +} +EXPORT_SYMBOL(ssb_bus_sdiobus_register); +#endif /* CONFIG_SSB_PCMCIAHOST */ + int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr, ssb_invariants_func_t get_invariants) diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c index 63ee5cf..b74212d 100644 --- a/drivers/ssb/scan.c +++ b/drivers/ssb/scan.c @@ -175,6 +175,9 @@ static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx, } else ssb_pcmcia_switch_segment(bus, 0); break; + case SSB_BUSTYPE_SDIO: + offset += current_coreidx * SSB_CORE_SIZE; + return ssb_sdio_scan_read32(bus, offset); } return readl(bus->mmio + offset); } @@ -188,6 +191,8 @@ static int scan_switchcore(struct ssb_bus *bus, u8 coreidx) return ssb_pci_switch_coreidx(bus, coreidx); case SSB_BUSTYPE_PCMCIA: return ssb_pcmcia_switch_coreidx(bus, coreidx); + case SSB_BUSTYPE_SDIO: + return ssb_sdio_scan_switch_coreidx(bus, coreidx); } return 0; } @@ -206,6 +211,8 @@ void ssb_iounmap(struct ssb_bus *bus) SSB_BUG_ON(1); /* Can't reach this code. */ #endif break; + case SSB_BUSTYPE_SDIO: + break; } bus->mmio = NULL; bus->mapped_device = NULL; @@ -230,6 +237,10 @@ static void __iomem *ssb_ioremap(struct ssb_bus *bus, SSB_BUG_ON(1); /* Can't reach this code. */ #endif break; + case SSB_BUSTYPE_SDIO: + /* Nothing to ioremap in the SDIO case, just fake it */ + mmio = (void __iomem *)baseaddr; + break; } return mmio; diff --git a/drivers/ssb/sdio.c b/drivers/ssb/sdio.c new file mode 100644 index 0000000..1140510 --- /dev/null +++ b/drivers/ssb/sdio.c @@ -0,0 +1,610 @@ +/* + * Sonics Silicon Backplane + * SDIO-Hostbus related functions + * + * Copyright 2009 Albert Herranz + * + * Based on drivers/ssb/pcmcia.c + * Copyright 2006 Johannes Berg + * Copyright 2007-2008 Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + * + */ + +#include +#include +#include +#include +#include + +#include "ssb_private.h" + +/* Define the following to 1 to enable a printk on each coreswitch. */ +#define SSB_VERBOSE_SDIOCORESWITCH_DEBUG 1 + + +/* Hardware invariants CIS tuples */ +#define SSB_SDIO_CIS 0x80 +#define SSB_SDIO_CIS_SROMREV 0x00 +#define SSB_SDIO_CIS_ID 0x01 +#define SSB_SDIO_CIS_BOARDREV 0x02 +#define SSB_SDIO_CIS_PA 0x03 +#define SSB_SDIO_CIS_PA_PA0B0_LO 0 +#define SSB_SDIO_CIS_PA_PA0B0_HI 1 +#define SSB_SDIO_CIS_PA_PA0B1_LO 2 +#define SSB_SDIO_CIS_PA_PA0B1_HI 3 +#define SSB_SDIO_CIS_PA_PA0B2_LO 4 +#define SSB_SDIO_CIS_PA_PA0B2_HI 5 +#define SSB_SDIO_CIS_PA_ITSSI 6 +#define SSB_SDIO_CIS_PA_MAXPOW 7 +#define SSB_SDIO_CIS_OEMNAME 0x04 +#define SSB_SDIO_CIS_CCODE 0x05 +#define SSB_SDIO_CIS_ANTENNA 0x06 +#define SSB_SDIO_CIS_ANTGAIN 0x07 +#define SSB_SDIO_CIS_BFLAGS 0x08 +#define SSB_SDIO_CIS_LEDS 0x09 + +#define CISTPL_FUNCE_LAN_NODE_ID 0x04 /* same as in PCMCIA */ + + +/* + * Function 1 miscellaneous registers. + * + * Definitions match src/include/sbsdio.h from the + * Android Open Source Project + * http://android.git.kernel.org/?p=platform/system/wlan/broadcom.git + * + */ +#define SBSDIO_FUNC1_SBADDRLOW 0x1000a /* SB Address window Low (b15) */ +#define SBSDIO_FUNC1_SBADDRMID 0x1000b /* SB Address window Mid (b23-b16) */ +#define SBSDIO_FUNC1_SBADDRHIGH 0x1000c /* SB Address window High (b24-b31) */ + +/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ +#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid address bits in SBADDRLOW */ +#define SBSDIO_SBADDRMID_MASK 0xff /* Valid address bits in SBADDRMID */ +#define SBSDIO_SBADDRHIGH_MASK 0xff /* Valid address bits in SBADDRHIGH */ + +#define SBSDIO_SB_OFT_ADDR_MASK 0x7FFF /* sb offset addr is <= 15 bits, 32k */ + +/* REVISIT: this flag doesn't seem to matter */ +#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x8000 /* forces 32-bit SB access */ + + +/* + * Address map within the SDIO function address space (128K). + * + * Start End Description + * ------- ------- ------------------------------------------ + * 0x00000 0x0ffff selected backplane address window (64K) + * 0x10000 0x1ffff backplane control registers (max 64K) + * + * The current address window is configured by writing to registers + * SBADDRLOW, SBADDRMID and SBADDRHIGH. + * + * In order to access the contents of a 32-bit Silicon Backplane address + * the backplane address window must be first loaded with the highest + * 16 bits of the target address. Then, an access must be done to the + * SDIO function address space using the lower 15 bits of the address. + * Bit 15 of the address must be set when doing 32 bit accesses. + * + * 10987654321098765432109876543210 + * WWWWWWWWWWWWWWWWW SB Address Window + * OOOOOOOOOOOOOOOO Offset within SB Address Window + * a 32-bit access flag + */ + + +/* + * SSB I/O via SDIO. + * + * NOTE: SDIO address @addr is 17 bits long (SDIO address space is 128K). + */ + +static inline struct device *ssb_sdio_dev(struct ssb_bus *bus) +{ + return &bus->host_sdio->dev; +} + +/* host claimed */ +static int ssb_sdio_writeb(struct ssb_bus *bus, unsigned int addr, u8 val) +{ + int error = 0; + + sdio_writeb(bus->host_sdio, val, addr, &error); + if (unlikely(error)) { + dev_dbg(ssb_sdio_dev(bus), "%08X <- %02x, error %d\n", + addr, val, error); + } + + return error; +} + +#if 0 +static u8 ssb_sdio_readb(struct ssb_bus *bus, unsigned int addr) +{ + u8 val; + int error = 0; + + val = sdio_readb(bus->host_sdio, addr, &error); + if (unlikely(error)) { + dev_dbg(ssb_sdio_dev(bus), "%08X -> %02x, error %d\n", + addr, val, error); + } + + return val; +} +#endif + +/* host claimed */ +static int ssb_sdio_set_sbaddr_window(struct ssb_bus *bus, u32 address) +{ + int error; + + error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRLOW, + (address >> 8) & SBSDIO_SBADDRLOW_MASK); + if (error) + goto out; + error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRMID, + (address >> 16) & SBSDIO_SBADDRMID_MASK); + if (error) + goto out; + error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRHIGH, + (address >> 24) & SBSDIO_SBADDRHIGH_MASK); + if (error) + goto out; + bus->sdio_sbaddr = address; +out: + if (error) { + dev_dbg(ssb_sdio_dev(bus), "failed to set address window" + " to 0x%08x, error %d\n", address, error); + } + + return error; +} + +/* for enumeration use only */ +u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset) +{ + u32 val; + int error; + + sdio_claim_host(bus->host_sdio); + val = sdio_readl(bus->host_sdio, offset, &error); + sdio_release_host(bus->host_sdio); + if (unlikely(error)) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } + + return val; +} + +/* for enumeration use only */ +int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx) +{ + u32 sbaddr; + int error; + + sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; + sdio_claim_host(bus->host_sdio); + error = ssb_sdio_set_sbaddr_window(bus, sbaddr); + sdio_release_host(bus->host_sdio); + if (error) { + dev_err(ssb_sdio_dev(bus), "failed to switch to core %u," + " error %d\n", coreidx, error); + goto out; + } +out: + return error; +} + +/* host must be already claimed */ +int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev) +{ + u8 coreidx = dev->core_index; + u32 sbaddr; + int error = 0; + + sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; + if (unlikely(bus->sdio_sbaddr != sbaddr)) { +#if SSB_VERBOSE_SDIOCORESWITCH_DEBUG + dev_info(ssb_sdio_dev(bus), + "switching to %s core, index %d\n", + ssb_core_name(dev->id.coreid), coreidx); +#endif + error = ssb_sdio_set_sbaddr_window(bus, sbaddr); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "failed to switch to" + " core %u, error %d\n", coreidx, error); + goto out; + } + bus->mapped_device = dev; + } + +out: + return error; +} + +static u8 ssb_sdio_read8(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u8 val = 0xff; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + val = sdio_readb(bus->host_sdio, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %02x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); + + return val; +} + +static u16 ssb_sdio_read16(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u16 val = 0xffff; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + val = sdio_readw(bus->host_sdio, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %04x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); + + return val; +} + +static u32 ssb_sdio_read32(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u32 val = 0xffffffff; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + val = sdio_readl(bus->host_sdio, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); + + return val; +} + +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_sdio_block_read(struct ssb_device *dev, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + size_t saved_count = count; + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) { + error = -EIO; + memset(buffer, 0xff, count); + goto err_out; + } + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + + switch (reg_width) { + case sizeof(u8): { + error = sdio_readsb(bus->host_sdio, buffer, offset, count); + break; + } + case sizeof(u16): { + SSB_WARN_ON(count & 1); + error = sdio_readsb(bus->host_sdio, buffer, offset, count); + break; + } + case sizeof(u32): { + SSB_WARN_ON(count & 3); + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + error = sdio_readsb(bus->host_sdio, buffer, offset, count); + break; + } + default: + SSB_WARN_ON(1); + } + if (!error) + goto out; + +err_out: + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n", + bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); +out: + sdio_release_host(bus->host_sdio); +} +#endif /* CONFIG_SSB_BLOCKIO */ + +static void ssb_sdio_write8(struct ssb_device *dev, u16 offset, u8 val) +{ + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + sdio_writeb(bus->host_sdio, val, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %02x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); +} + +static void ssb_sdio_write16(struct ssb_device *dev, u16 offset, u16 val) +{ + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + sdio_writew(bus->host_sdio, val, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %04x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); +} + +static void ssb_sdio_write32(struct ssb_device *dev, u16 offset, u32 val) +{ + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + sdio_writel(bus->host_sdio, val, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %08x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } + if (bus->quirks & SSB_QUIRK_SDIO_READ_AFTER_WRITE32) + sdio_readl(bus->host_sdio, 0, &error); +out: + sdio_release_host(bus->host_sdio); +} + +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + size_t saved_count = count; + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) { + error = -EIO; + memset((void *)buffer, 0xff, count); + goto err_out; + } + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + + switch (reg_width) { + case sizeof(u8): + error = sdio_writesb(bus->host_sdio, offset, + (void *)buffer, count); + break; + case sizeof(u16): + SSB_WARN_ON(count & 1); + error = sdio_writesb(bus->host_sdio, offset, + (void *)buffer, count); + break; + case sizeof(u32): + SSB_WARN_ON(count & 3); + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + error = sdio_writesb(bus->host_sdio, offset, + (void *)buffer, count); + break; + default: + SSB_WARN_ON(1); + } + if (!error) + goto out; + +err_out: + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n", + bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); +out: + sdio_release_host(bus->host_sdio); +} + +#endif /* CONFIG_SSB_BLOCKIO */ + +/* Not "static", as it's used in main.c */ +const struct ssb_bus_ops ssb_sdio_ops = { + .read8 = ssb_sdio_read8, + .read16 = ssb_sdio_read16, + .read32 = ssb_sdio_read32, + .write8 = ssb_sdio_write8, + .write16 = ssb_sdio_write16, + .write32 = ssb_sdio_write32, +#ifdef CONFIG_SSB_BLOCKIO + .block_read = ssb_sdio_block_read, + .block_write = ssb_sdio_block_write, +#endif +}; + +#define GOTO_ERROR_ON(condition, description) do { \ + if (unlikely(condition)) { \ + error_description = description; \ + goto error; \ + } \ + } while (0) + +int ssb_sdio_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv) +{ + struct ssb_sprom *sprom = &iv->sprom; + struct ssb_boardinfo *bi = &iv->boardinfo; + const char *error_description = "none"; + struct sdio_func_tuple *tuple; + void *mac; + + memset(sprom, 0xFF, sizeof(*sprom)); + sprom->boardflags_lo = 0; + sprom->boardflags_hi = 0; + + tuple = bus->host_sdio->tuples; + while (tuple) { + switch (tuple->code) { + case 0x22: /* extended function */ + switch (tuple->data[0]) { + case CISTPL_FUNCE_LAN_NODE_ID: + GOTO_ERROR_ON((tuple->size != 7) && + (tuple->data[1] != 6), + "mac tpl size"); + /* fetch the MAC address. */ + mac = tuple->data + 2; + memcpy(sprom->il0mac, mac, ETH_ALEN); + memcpy(sprom->et1mac, mac, ETH_ALEN); + break; + default: + break; + } + break; + case 0x80: /* vendor specific tuple */ + switch (tuple->data[0]) { + case SSB_SDIO_CIS_SROMREV: + GOTO_ERROR_ON(tuple->size != 2, + "sromrev tpl size"); + sprom->revision = tuple->data[1]; + break; + case SSB_SDIO_CIS_ID: + GOTO_ERROR_ON((tuple->size != 5) && + (tuple->size != 7), + "id tpl size"); + bi->vendor = tuple->data[1] | + (tuple->data[2]<<8); + break; + case SSB_SDIO_CIS_BOARDREV: + GOTO_ERROR_ON(tuple->size != 2, + "boardrev tpl size"); + sprom->board_rev = tuple->data[1]; + break; + case SSB_SDIO_CIS_PA: + GOTO_ERROR_ON((tuple->size != 9) && + (tuple->size != 10), + "pa tpl size"); + sprom->pa0b0 = tuple->data[1] | + ((u16)tuple->data[2] << 8); + sprom->pa0b1 = tuple->data[3] | + ((u16)tuple->data[4] << 8); + sprom->pa0b2 = tuple->data[5] | + ((u16)tuple->data[6] << 8); + sprom->itssi_a = tuple->data[7]; + sprom->itssi_bg = tuple->data[7]; + sprom->maxpwr_a = tuple->data[8]; + sprom->maxpwr_bg = tuple->data[8]; + break; + case SSB_SDIO_CIS_OEMNAME: + /* Not present */ + break; + case SSB_SDIO_CIS_CCODE: + GOTO_ERROR_ON(tuple->size != 2, + "ccode tpl size"); + sprom->country_code = tuple->data[1]; + break; + case SSB_SDIO_CIS_ANTENNA: + GOTO_ERROR_ON(tuple->size != 2, + "ant tpl size"); + sprom->ant_available_a = tuple->data[1]; + sprom->ant_available_bg = tuple->data[1]; + break; + case SSB_SDIO_CIS_ANTGAIN: + GOTO_ERROR_ON(tuple->size != 2, + "antg tpl size"); + sprom->antenna_gain.ghz24.a0 = tuple->data[1]; + sprom->antenna_gain.ghz24.a1 = tuple->data[1]; + sprom->antenna_gain.ghz24.a2 = tuple->data[1]; + sprom->antenna_gain.ghz24.a3 = tuple->data[1]; + sprom->antenna_gain.ghz5.a0 = tuple->data[1]; + sprom->antenna_gain.ghz5.a1 = tuple->data[1]; + sprom->antenna_gain.ghz5.a2 = tuple->data[1]; + sprom->antenna_gain.ghz5.a3 = tuple->data[1]; + break; + case SSB_SDIO_CIS_BFLAGS: + GOTO_ERROR_ON((tuple->size != 3) && + (tuple->size != 5), + "bfl tpl size"); + sprom->boardflags_lo = tuple->data[1] | + ((u16)tuple->data[2] << 8); + break; + case SSB_SDIO_CIS_LEDS: + GOTO_ERROR_ON(tuple->size != 5, + "leds tpl size"); + sprom->gpio0 = tuple->data[1]; + sprom->gpio1 = tuple->data[2]; + sprom->gpio2 = tuple->data[3]; + sprom->gpio3 = tuple->data[4]; + break; + default: + break; + } + break; + default: + break; + } + tuple = tuple->next; + } + + return 0; +error: + dev_err(ssb_sdio_dev(bus), "failed to fetch device invariants: %s\n", + error_description); + return -ENODEV; +} + +void ssb_sdio_exit(struct ssb_bus *bus) +{ + if (bus->bustype != SSB_BUSTYPE_SDIO) + return; + /* Nothing to do here. */ +} + +int ssb_sdio_init(struct ssb_bus *bus) +{ + if (bus->bustype != SSB_BUSTYPE_SDIO) + return 0; + + bus->sdio_sbaddr = ~0; + + return 0; +} diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 57fa482..2543356 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -114,6 +114,46 @@ static inline int ssb_pcmcia_init(struct ssb_bus *bus) } #endif /* CONFIG_SSB_PCMCIAHOST */ +/* sdio.c */ +#ifdef CONFIG_SSB_SDIOHOST +extern int ssb_sdio_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv); + +extern u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset); +extern int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev); +extern int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx); +extern int ssb_sdio_hardware_setup(struct ssb_bus *bus); +extern void ssb_sdio_exit(struct ssb_bus *bus); +extern int ssb_sdio_init(struct ssb_bus *bus); + +extern const struct ssb_bus_ops ssb_sdio_ops; +#else /* CONFIG_SSB_SDIOHOST */ +static inline u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset) +{ + return 0; +} +static inline int ssb_sdio_switch_core(struct ssb_bus *bus, + struct ssb_device *dev) +{ + return 0; +} +static inline int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx) +{ + return 0; +} +static inline int ssb_sdio_hardware_setup(struct ssb_bus *bus) +{ + return 0; +} +static inline void ssb_sdio_exit(struct ssb_bus *bus) +{ +} +static inline int ssb_sdio_init(struct ssb_bus *bus) +{ + return 0; +} +#endif /* CONFIG_SSB_SDIOHOST */ + /* scan.c */ extern const char *ssb_core_name(u16 coreid); diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 17ffc1f..3d0a9ff 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -238,6 +238,7 @@ enum ssb_bustype { SSB_BUSTYPE_SSB, /* This SSB bus is the system bus */ SSB_BUSTYPE_PCI, /* SSB is connected to PCI bus */ SSB_BUSTYPE_PCMCIA, /* SSB is connected to PCMCIA bus */ + SSB_BUSTYPE_SDIO, /* SSB is connected to SDIO bus */ }; /* board_vendor */ @@ -270,8 +271,12 @@ struct ssb_bus { /* The core in the basic address register window. (PCI bus only) */ struct ssb_device *mapped_device; - /* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */ - u8 mapped_pcmcia_seg; + union { + /* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */ + u8 mapped_pcmcia_seg; + /* Current SSB base address window for SDIO. */ + u32 sdio_sbaddr; + }; /* Lock for core and segment switching. * On PCMCIA-host busses this is used to protect the whole MMIO access. */ spinlock_t bar_lock; @@ -282,6 +287,11 @@ struct ssb_bus { struct pci_dev *host_pci; /* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */ struct pcmcia_device *host_pcmcia; + /* Pointer to the SDIO device (only if bustype == SSB_BUSTYPE_SDIO). */ + struct sdio_func *host_sdio; + + /* See enum ssb_quirks */ + unsigned int quirks; #ifdef CONFIG_SSB_SPROM /* Mutex to protect the SPROM writing. */ @@ -336,6 +346,11 @@ struct ssb_bus { #endif /* DEBUG */ }; +enum ssb_quirks { + /* SDIO connected card requires performing a read after writing a 32-bit value */ + SSB_QUIRK_SDIO_READ_AFTER_WRITE32 = (1 << 0), +}; + /* The initialization-invariants. */ struct ssb_init_invariants { /* Versioning information about the PCB. */ @@ -366,6 +381,12 @@ extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus, struct pcmcia_device *pcmcia_dev, unsigned long baseaddr); #endif /* CONFIG_SSB_PCMCIAHOST */ +#ifdef CONFIG_SSB_SDIOHOST +extern int ssb_bus_sdiobus_register(struct ssb_bus *bus, + struct sdio_func *sdio_func, + unsigned int quirks); +#endif /* CONFIG_SSB_SDIOHOST */ + extern void ssb_bus_unregister(struct ssb_bus *bus); -- cgit v0.10.2 From 98a1e2a9260d30ad691fbd1ed778a05e38fe655b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 8 Sep 2009 19:33:31 +0200 Subject: b44/b43/b43legacy: Fix switch warnings introduced by SSB-SDIO This fixes some gcc warnings for switch statements. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 951735c..0189dcd 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1303,10 +1303,13 @@ static void b44_chip_reset(struct b44 *bp, int reset_kind) & MDIO_CTRL_MAXF_MASK))); break; case SSB_BUSTYPE_PCI: - case SSB_BUSTYPE_PCMCIA: bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | (0x0d & MDIO_CTRL_MAXF_MASK))); break; + case SSB_BUSTYPE_PCMCIA: + case SSB_BUSTYPE_SDIO: + WARN_ON(1); /* A device with this bus does not exist. */ + break; } br32(bp, B44_MDIO_CTRL); @@ -1764,10 +1767,13 @@ static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *inf case SSB_BUSTYPE_PCI: strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info)); break; - case SSB_BUSTYPE_PCMCIA: case SSB_BUSTYPE_SSB: strlcpy(info->bus_info, "SSB", sizeof(info->bus_info)); break; + case SSB_BUSTYPE_PCMCIA: + case SSB_BUSTYPE_SDIO: + WARN_ON(1); /* A device with this bus does not exist. */ + break; } } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index d29323d..7a9a3fa 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4092,16 +4092,20 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) bus->pcicore.dev->id.revision <= 5) { /* IMCFGLO timeouts workaround. */ tmp = ssb_read32(dev->dev, SSB_IMCFGLO); - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; switch (bus->bustype) { case SSB_BUSTYPE_PCI: case SSB_BUSTYPE_PCMCIA: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x32; break; case SSB_BUSTYPE_SSB: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x53; break; + default: + break; } ssb_write32(dev->dev, SSB_IMCFGLO, tmp); } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index b166a6f..1d9223b 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3106,16 +3106,20 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) bus->pcicore.dev->id.revision <= 5) { /* IMCFGLO timeouts workaround. */ tmp = ssb_read32(dev->dev, SSB_IMCFGLO); - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; switch (bus->bustype) { case SSB_BUSTYPE_PCI: case SSB_BUSTYPE_PCMCIA: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x32; break; case SSB_BUSTYPE_SSB: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x53; break; + default: + break; } ssb_write32(dev->dev, SSB_IMCFGLO, tmp); } -- cgit v0.10.2 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 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 09e031c..ad522e3 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 a8871a8..ad89d23 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 v0.10.2 From aeac355d23fb13a2082a8740ae7cf9408a71ec2c Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:49 +0530 Subject: ath9k: Store subsystem id in struct hw_version This subsystem id will be used later to turn on the btcoex support. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 7dc6301..2ad7d02 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -119,7 +119,7 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->bus_ops = &ath_ahb_bus_ops; sc->irq = irq; - ret = ath_init_device(AR5416_AR9100_DEVID, sc); + ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto err_free_hw; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1c68a9d..1d59f10 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -658,7 +658,7 @@ extern struct ieee80211_ops ath9k_ops; irqreturn_t ath_isr(int irq, void *dev); void ath_cleanup(struct ath_softc *sc); -int ath_init_device(u16 devid, struct ath_softc *sc); +int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid); void ath_detach(struct ath_softc *sc); const char *ath_mac_bb_name(u32 mac_bb_version); const char *ath_rf_name(u16 rf_version); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index a592f1a..64ea547 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -390,6 +390,7 @@ struct ath9k_hw_version { u16 phyRev; u16 analog5GhzRev; u16 analog2GhzRev; + u16 subsysid; }; /* Generic TSF timer definitions */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ce011ab..3dc7b5a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1310,7 +1310,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, * to allow the separation between hardware specific * variables (now in ath_hw) and driver specific variables. */ -static int ath_init_softc(u16 devid, struct ath_softc *sc) +static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) { struct ath_hw *ah = NULL; int r = 0, i; @@ -1348,6 +1348,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) ah->ah_sc = sc; ah->hw_version.devid = devid; + ah->hw_version.subsysid = subsysid; sc->sc_ah = ah; r = ath9k_hw_init(ah); @@ -1577,7 +1578,7 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) } /* Device driver core initialization */ -int ath_init_device(u16 devid, struct ath_softc *sc) +int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid) { struct ieee80211_hw *hw = sc->hw; int error = 0, i; @@ -1585,7 +1586,7 @@ int ath_init_device(u16 devid, struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); - error = ath_init_softc(devid, sc); + error = ath_init_softc(devid, sc, subsysid); if (error != 0) return error; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 8b28814..903dd8a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -88,6 +88,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct ath_softc *sc; struct ieee80211_hw *hw; u8 csz; + u16 subsysid; u32 val; int ret = 0; struct ath_hw *ah; @@ -178,7 +179,8 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = mem; sc->bus_ops = &ath_pci_bus_ops; - ret = ath_init_device(id->device, sc); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); + ret = ath_init_device(id->device, sc, subsysid); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto bad3; -- cgit v0.10.2 From fe12946e66575677879941a14f75b70ca2d2962a Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:50 +0530 Subject: ath9k: Enable btcoex based on the subsystem id of the device Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index e8bfb01..55f607b 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -19,6 +19,29 @@ static const struct ath_btcoex_config ath_bt_config = { 0, true, true, ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true }; +static const u16 ath_subsysid_tbl[] = { + AR9280_COEX2WIRE_SUBSYSID, + AT9285_COEX3WIRE_SA_SUBSYSID, + AT9285_COEX3WIRE_DA_SUBSYSID +}; + +/* + * Checks the subsystem id of the device to see if it + * supports btcoex + */ +bool ath_btcoex_supported(u16 subsysid) +{ + int i; + + if (!subsysid) + return false; + + for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++) + if (subsysid == ath_subsysid_tbl[i]) + return true; + + return false; +} /* * Detects if there is any priority bt traffic diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 4556819..f1baf66 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -79,6 +79,7 @@ struct ath_btcoex_info { struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/ }; +bool ath_btcoex_supported(u16 subsysid); int ath9k_hw_btcoex_init(struct ath_hw *ah); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 97a09db..8d77817 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3690,7 +3690,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->num_antcfg_2ghz = ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); - if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { + if (AR_SREV_9280_10_OR_LATER(ah) && + ath_btcoex_supported(ah->hw_version.subsysid)) { btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 64ea547..9106a0b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -45,6 +45,10 @@ #define AR5416_DEVID_AR9287_PCI 0x002D #define AR5416_DEVID_AR9287_PCIE 0x002E +#define AR9280_COEX2WIRE_SUBSYSID 0x309b +#define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa +#define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab + /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) #define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) -- cgit v0.10.2 From f42cc2c2909f24faa1381ae139067edeba8c796d Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:51 +0530 Subject: ath9k: Get rid of the modparam btcoex_enable Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8d77817..c39693b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -21,10 +21,6 @@ #include "ath9k.h" #include "initvals.h" -static int btcoex_enable; -module_param(btcoex_enable, bool, 0); -MODULE_PARM_DESC(btcoex_enable, "Enable Bluetooth coexistence support"); - #define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 -- cgit v0.10.2 From 8c8f9ba7051b017e44124666b41c1dc70333a77c Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:52 +0530 Subject: ath9k: Initialize the priority gpio for BT coex 3-wire Oops, a stupid mistake in the original patch which adds coex 3-wire support. Bluetooth priority gpio needs to be gpio 7. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index f1baf66..297b027 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -19,6 +19,7 @@ #define ATH_WLANACTIVE_GPIO 5 #define ATH_BTACTIVE_GPIO 6 +#define ATH_BTPRIORITY_GPIO 7 #define ATH_BTCOEX_DEF_BT_PERIOD 45 #define ATH_BTCOEX_DEF_DUTY_CYCLE 55 diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c39693b..b6c6cca 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3691,10 +3691,12 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; - if (AR_SREV_9285(ah)) + if (AR_SREV_9285(ah)) { btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE; - else + btcoex_info->btpriority_gpio = ATH_BTPRIORITY_GPIO; + } else { btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE; + } } else { btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE; } -- cgit v0.10.2 From b2e3abdc708f8c0eff194af25362fdb239abe241 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 9 Sep 2009 13:09:54 +0200 Subject: cfg80211: allow scanning on specified frequencies when using wext-compatibility Handles the case when SIOCSIWSCAN specified iw_scan_req.num_channels and iw_scan_req.channels[]. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 19c5a9a..4c210c2 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -607,6 +607,9 @@ int cfg80211_wext_siwscan(struct net_device *dev, if (!netif_running(dev)) return -ENETDOWN; + if (wrqu->data.length == sizeof(struct iw_scan_req)) + wreq = (struct iw_scan_req *)extra; + rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); if (IS_ERR(rdev)) @@ -619,9 +622,14 @@ int cfg80211_wext_siwscan(struct net_device *dev, wiphy = &rdev->wiphy; - for (band = 0; band < IEEE80211_NUM_BANDS; band++) - if (wiphy->bands[band]) - n_channels += wiphy->bands[band]->n_channels; + /* Determine number of channels, needed to allocate creq */ + if (wreq && wreq->num_channels) + n_channels = wreq->num_channels; + else { + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + n_channels += wiphy->bands[band]->n_channels; + } creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + n_channels * sizeof(void *), @@ -638,22 +646,41 @@ int cfg80211_wext_siwscan(struct net_device *dev, creq->n_channels = n_channels; creq->n_ssids = 1; - /* all channels */ + /* translate "Scan on frequencies" request */ i = 0; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { int j; if (!wiphy->bands[band]) continue; for (j = 0; j < wiphy->bands[band]->n_channels; j++) { + + /* If we have a wireless request structure and the + * wireless request specifies frequencies, then search + * for the matching hardware channel. + */ + if (wreq && wreq->num_channels) { + int k; + int wiphy_freq = wiphy->bands[band]->channels[j].center_freq; + for (k = 0; k < wreq->num_channels; k++) { + int wext_freq = wreq->channel_list[k].m / 100000; + if (wext_freq == wiphy_freq) + goto wext_freq_found; + } + goto wext_freq_not_found; + } + + wext_freq_found: creq->channels[i] = &wiphy->bands[band]->channels[j]; i++; + wext_freq_not_found: ; } } - /* translate scan request */ - if (wrqu->data.length == sizeof(struct iw_scan_req)) { - wreq = (struct iw_scan_req *)extra; + /* Set real number of channels specified in creq->channels[] */ + creq->n_channels = i; + /* translate "Scan for SSID" request */ + if (wreq) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) return -EINVAL; -- cgit v0.10.2 From 2bba22c50b06abe9fd0d23933b1e64d35b419262 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Wed, 9 Sep 2009 15:41:37 +0200 Subject: sched: Turn off child_runs_first Set child_runs_first default to off. It hurts 'optimal' make -j workloads as make jobs get preempted by child tasks, reducing parallelism. Note, this patch might make existing races in user applications more prominent than before - so breakages might be bisected to this commit. Child-runs-first is broken on SMP to begin with, and we already had it off briefly in v2.6.23 so most of the offenders ought to be fixed. Would be nice not to revert this commit but fix those apps finally ... Signed-off-by: Mike Galbraith Acked-by: Peter Zijlstra LKML-Reference: <1252486344.28645.18.camel@marge.simson.net> [ made the sysctl independent of CONFIG_SCHED_DEBUG, in case people want to work around broken apps. ] Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 3b7f43e..3a50e82 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1820,8 +1820,8 @@ extern unsigned int sysctl_sched_min_granularity; extern unsigned int sysctl_sched_wakeup_granularity; extern unsigned int sysctl_sched_shares_ratelimit; extern unsigned int sysctl_sched_shares_thresh; -#ifdef CONFIG_SCHED_DEBUG extern unsigned int sysctl_sched_child_runs_first; +#ifdef CONFIG_SCHED_DEBUG extern unsigned int sysctl_sched_features; extern unsigned int sysctl_sched_migration_cost; extern unsigned int sysctl_sched_nr_migrate; diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index e386e5d..af325a3 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -48,10 +48,10 @@ unsigned int sysctl_sched_min_granularity = 4000000ULL; static unsigned int sched_nr_latency = 5; /* - * After fork, child runs first. (default) If set to 0 then + * After fork, child runs first. If set to 0 (default) then * parent will (try to) run first. */ -const_debug unsigned int sysctl_sched_child_runs_first = 1; +unsigned int sysctl_sched_child_runs_first __read_mostly; /* * sys_sched_yield() compat mode diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 6c9836e..25d6bf3 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -246,6 +246,14 @@ static int max_wakeup_granularity_ns = NSEC_PER_SEC; /* 1 second */ #endif static struct ctl_table kern_table[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "sched_child_runs_first", + .data = &sysctl_sched_child_runs_first, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #ifdef CONFIG_SCHED_DEBUG { .ctl_name = CTL_UNNUMBERED, @@ -300,14 +308,6 @@ static struct ctl_table kern_table[] = { }, { .ctl_name = CTL_UNNUMBERED, - .procname = "sched_child_runs_first", - .data = &sysctl_sched_child_runs_first, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, - { - .ctl_name = CTL_UNNUMBERED, .procname = "sched_features", .data = &sysctl_sched_features, .maxlen = sizeof(unsigned int), -- cgit v0.10.2 From 172e082a9111ea504ee34cbba26284a5ebdc53a7 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Wed, 9 Sep 2009 15:41:37 +0200 Subject: sched: Re-tune the scheduler latency defaults to decrease worst-case latencies Reduce the latency target from 20 msecs to 5 msecs. Why? Larger latencies increase spread, which is good for scaling, but bad for worst case latency. We still have the ilog(nr_cpus) rule to scale up on bigger server boxes. Signed-off-by: Mike Galbraith Acked-by: Peter Zijlstra LKML-Reference: <1252486344.28645.18.camel@marge.simson.net> Signed-off-by: Ingo Molnar diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index af325a3..26fadb4 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -24,7 +24,7 @@ /* * Targeted preemption latency for CPU-bound tasks: - * (default: 20ms * (1 + ilog(ncpus)), units: nanoseconds) + * (default: 5ms * (1 + ilog(ncpus)), units: nanoseconds) * * NOTE: this latency value is not the same as the concept of * 'timeslice length' - timeslices in CFS are of variable length @@ -34,13 +34,13 @@ * (to see the precise effective timeslice length of your workload, * run vmstat and monitor the context-switches (cs) field) */ -unsigned int sysctl_sched_latency = 20000000ULL; +unsigned int sysctl_sched_latency = 5000000ULL; /* * Minimal preemption granularity for CPU-bound tasks: - * (default: 4 msec * (1 + ilog(ncpus)), units: nanoseconds) + * (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds) */ -unsigned int sysctl_sched_min_granularity = 4000000ULL; +unsigned int sysctl_sched_min_granularity = 1000000ULL; /* * is kept at sysctl_sched_latency / sysctl_sched_min_granularity @@ -63,13 +63,13 @@ unsigned int __read_mostly sysctl_sched_compat_yield; /* * SCHED_OTHER wake-up granularity. - * (default: 5 msec * (1 + ilog(ncpus)), units: nanoseconds) + * (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds) * * This option delays the preemption effects of decoupled workloads * and reduces their over-scheduling. Synchronous workloads will still * have immediate wakeup/sleep latencies. */ -unsigned int sysctl_sched_wakeup_granularity = 5000000UL; +unsigned int sysctl_sched_wakeup_granularity = 1000000UL; const_debug unsigned int sysctl_sched_migration_cost = 500000UL; -- cgit v0.10.2 From 61cbe54d9479ad98283b2dda686deae4c34b2d59 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Wed, 9 Sep 2009 15:41:37 +0200 Subject: sched: Keep kthreads at default priority Removes kthread/workqueue priority boost, they increase worst-case desktop latencies. Signed-off-by: Mike Galbraith Acked-by: Peter Zijlstra LKML-Reference: <1252486344.28645.18.camel@marge.simson.net> Signed-off-by: Ingo Molnar diff --git a/kernel/kthread.c b/kernel/kthread.c index eb8751a..5fe7099 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -16,8 +16,6 @@ #include #include -#define KTHREAD_NICE_LEVEL (-5) - static DEFINE_SPINLOCK(kthread_create_lock); static LIST_HEAD(kthread_create_list); struct task_struct *kthreadd_task; @@ -145,7 +143,6 @@ struct task_struct *kthread_create(int (*threadfn)(void *data), * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); - set_user_nice(create.result, KTHREAD_NICE_LEVEL); set_cpus_allowed_ptr(create.result, cpu_all_mask); } return create.result; @@ -221,7 +218,6 @@ int kthreadd(void *unused) /* Setup a clean context for our children to inherit. */ set_task_comm(tsk, "kthreadd"); ignore_signals(tsk); - set_user_nice(tsk, KTHREAD_NICE_LEVEL); set_cpus_allowed_ptr(tsk, cpu_all_mask); set_mems_allowed(node_possible_map); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 0668795..ea1b4e7 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -317,8 +317,6 @@ static int worker_thread(void *__cwq) if (cwq->wq->freezeable) set_freezable(); - set_user_nice(current, -5); - for (;;) { prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE); if (!freezing(current) && -- cgit v0.10.2 From 13a239330abdda5afcb1161fce68ec214af2cc90 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Sep 2009 11:25:55 -0700 Subject: RDMA/cxgb3: Don't ignore insert_handle() failures Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c index ec49a5c..e1ec65e 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_mem.c +++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c @@ -39,7 +39,7 @@ #include "iwch.h" #include "iwch_provider.h" -static void iwch_finish_mem_reg(struct iwch_mr *mhp, u32 stag) +static int iwch_finish_mem_reg(struct iwch_mr *mhp, u32 stag) { u32 mmid; @@ -47,14 +47,15 @@ static void iwch_finish_mem_reg(struct iwch_mr *mhp, u32 stag) mhp->attr.stag = stag; mmid = stag >> 8; mhp->ibmr.rkey = mhp->ibmr.lkey = stag; - insert_handle(mhp->rhp, &mhp->rhp->mmidr, mhp, mmid); PDBG("%s mmid 0x%x mhp %p\n", __func__, mmid, mhp); + return insert_handle(mhp->rhp, &mhp->rhp->mmidr, mhp, mmid); } int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php, struct iwch_mr *mhp, int shift) { u32 stag; + int ret; if (cxio_register_phys_mem(&rhp->rdev, &stag, mhp->attr.pdid, @@ -66,9 +67,11 @@ int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php, mhp->attr.pbl_size, mhp->attr.pbl_addr)) return -ENOMEM; - iwch_finish_mem_reg(mhp, stag); - - return 0; + ret = iwch_finish_mem_reg(mhp, stag); + if (ret) + cxio_dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size, + mhp->attr.pbl_addr); + return ret; } int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php, @@ -77,6 +80,7 @@ int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php, int npages) { u32 stag; + int ret; /* We could support this... */ if (npages > mhp->attr.pbl_size) @@ -93,9 +97,12 @@ int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php, mhp->attr.pbl_size, mhp->attr.pbl_addr)) return -ENOMEM; - iwch_finish_mem_reg(mhp, stag); + ret = iwch_finish_mem_reg(mhp, stag); + if (ret) + cxio_dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size, + mhp->attr.pbl_addr); - return 0; + return ret; } int iwch_alloc_pbl(struct iwch_mr *mhp, int npages) diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index 72aa57c..6895523 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -195,7 +195,11 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve spin_lock_init(&chp->lock); atomic_set(&chp->refcnt, 1); init_waitqueue_head(&chp->wait); - insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid); + if (insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid)) { + cxio_destroy_cq(&chp->rhp->rdev, &chp->cq); + kfree(chp); + return ERR_PTR(-ENOMEM); + } if (ucontext) { struct iwch_mm_entry *mm; @@ -750,7 +754,11 @@ static struct ib_mw *iwch_alloc_mw(struct ib_pd *pd) mhp->attr.stag = stag; mmid = (stag) >> 8; mhp->ibmw.rkey = stag; - insert_handle(rhp, &rhp->mmidr, mhp, mmid); + if (insert_handle(rhp, &rhp->mmidr, mhp, mmid)) { + cxio_deallocate_window(&rhp->rdev, mhp->attr.stag); + kfree(mhp); + return ERR_PTR(-ENOMEM); + } PDBG("%s mmid 0x%x mhp %p stag 0x%x\n", __func__, mmid, mhp, stag); return &(mhp->ibmw); } @@ -778,37 +786,43 @@ static struct ib_mr *iwch_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth) struct iwch_mr *mhp; u32 mmid; u32 stag = 0; - int ret; + int ret = 0; php = to_iwch_pd(pd); rhp = php->rhp; mhp = kzalloc(sizeof(*mhp), GFP_KERNEL); if (!mhp) - return ERR_PTR(-ENOMEM); + goto err; mhp->rhp = rhp; ret = iwch_alloc_pbl(mhp, pbl_depth); - if (ret) { - kfree(mhp); - return ERR_PTR(ret); - } + if (ret) + goto err1; mhp->attr.pbl_size = pbl_depth; ret = cxio_allocate_stag(&rhp->rdev, &stag, php->pdid, mhp->attr.pbl_size, mhp->attr.pbl_addr); - if (ret) { - iwch_free_pbl(mhp); - kfree(mhp); - return ERR_PTR(ret); - } + if (ret) + goto err2; mhp->attr.pdid = php->pdid; mhp->attr.type = TPT_NON_SHARED_MR; mhp->attr.stag = stag; mhp->attr.state = 1; mmid = (stag) >> 8; mhp->ibmr.rkey = mhp->ibmr.lkey = stag; - insert_handle(rhp, &rhp->mmidr, mhp, mmid); + if (insert_handle(rhp, &rhp->mmidr, mhp, mmid)) + goto err3; + PDBG("%s mmid 0x%x mhp %p stag 0x%x\n", __func__, mmid, mhp, stag); return &(mhp->ibmr); +err3: + cxio_dereg_mem(&rhp->rdev, stag, mhp->attr.pbl_size, + mhp->attr.pbl_addr); +err2: + iwch_free_pbl(mhp); +err1: + kfree(mhp); +err: + return ERR_PTR(ret); } static struct ib_fast_reg_page_list *iwch_alloc_fastreg_pbl( @@ -961,7 +975,13 @@ static struct ib_qp *iwch_create_qp(struct ib_pd *pd, spin_lock_init(&qhp->lock); init_waitqueue_head(&qhp->wait); atomic_set(&qhp->refcnt, 1); - insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.qpid); + + if (insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.qpid)) { + cxio_destroy_qp(&rhp->rdev, &qhp->wq, + ucontext ? &ucontext->uctx : &rhp->rdev.uctx); + kfree(qhp); + return ERR_PTR(-ENOMEM); + } if (udata) { -- cgit v0.10.2 From ffc40c6433e763209d2b1ec5b1a9854eb3bcd61c Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Sep 2009 11:25:56 -0700 Subject: RDMA/cxgb3: Clean up properly on FW mismatch failures FW mismatches can cause a crash in the iw_cxgb3 event handler. - NULL the t3cdev->ulp pointer on failures in cxio_rdev_open() - Silently ignore events when the ulp ptr is NULL in iwch_err_handler() Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 4dec515..72ed339 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -1034,6 +1034,7 @@ err3: err2: cxio_hal_destroy_ctrl_qp(rdev_p); err1: + rdev_p->t3cdev_p->ulp = NULL; list_del(&rdev_p->entry); return err; } diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index 5796170..3f0c99d 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -165,10 +165,13 @@ static void close_rnic_dev(struct t3cdev *tdev) static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id) { struct cxio_rdev *rdev = tdev->ulp; - struct iwch_dev *rnicp = rdev_to_iwch_dev(rdev); + struct iwch_dev *rnicp; struct ib_event event; u32 portnum = port_id + 1; + if (!rdev) + return; + rnicp = rdev_to_iwch_dev(rdev); switch (evt) { case OFFLOAD_STATUS_DOWN: { rdev->flags = CXIO_ERROR_FATAL; -- cgit v0.10.2 From cb58160e72244a23f4e0cf4d6f81ffbd131fcd51 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Sep 2009 11:37:38 -0700 Subject: RDMA/iwcm: Reject the connection when the cm_id is destroyed If the cm_id of a connect request is destroyed prior to the ULP accepting or rejecting the connection, then the provider never cleans up the connection. The iwcm should explicitly reject these connections if the cm_id is destroyed. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 8f9509e..55d093a 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -362,6 +362,7 @@ static void destroy_cm_id(struct iw_cm_id *cm_id) * In either case, must tell the provider to reject. */ cm_id_priv->state = IW_CM_STATE_DESTROYING; + cm_id->device->iwcm->reject(cm_id, NULL, 0); break; case IW_CM_STATE_CONN_SENT: case IW_CM_STATE_DESTROYING: -- cgit v0.10.2 From 74fca6a42863ffacaf7ba6f1936a9f228950f657 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 9 Sep 2009 15:13:59 -0700 Subject: Linux 2.6.31 diff --git a/Makefile b/Makefile index 7d3415c..60de4ef 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 31 -EXTRAVERSION = -rc9 +EXTRAVERSION = NAME = Man-Eating Seals of Antiquity # *DOCUMENTATION* -- cgit v0.10.2 From 577eebeae34d340685d8985dfdb7dfe337c511e8 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 27 Aug 2009 12:46:35 -0700 Subject: xen: make -fstack-protector work under Xen -fstack-protector uses a special per-cpu "stack canary" value. gcc generates special code in each function to test the canary to make sure that the function's stack hasn't been overrun. On x86-64, this is simply an offset of %gs, which is the usual per-cpu base segment register, so setting it up simply requires loading %gs's base as normal. On i386, the stack protector segment is %gs (rather than the usual kernel percpu %fs segment register). This requires setting up the full kernel GDT and then loading %gs accordingly. We also need to make sure %gs is initialized when bringing up secondary cpus too. To keep things consistent, we do the full GDT/segment register setup on both architectures. Because we need to avoid -fstack-protected code before setting up the GDT and because there's no way to disable it on a per-function basis, several files need to have stack-protector inhibited. [ Impact: allow Xen booting with stack-protector enabled ] Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index eefdeee..72bb3a2 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -1,6 +1,10 @@ obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \ pat.o pgtable.o gup.o +# Make sure __phys_addr has no stackprotector +nostackp := $(call cc-option, -fno-stack-protector) +CFLAGS_ioremap.o := $(nostackp) + obj-$(CONFIG_SMP) += tlb.o obj-$(CONFIG_X86_32) += pgtable_32.o iomap_32.o diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index 7410640..3bb4fc2 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile @@ -8,6 +8,7 @@ endif # Make sure early boot has no stackprotector nostackp := $(call cc-option, -fno-stack-protector) CFLAGS_enlighten.o := $(nostackp) +CFLAGS_mmu.o := $(nostackp) obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ time.o xen-asm.o xen-asm_$(BITS).o \ @@ -16,3 +17,4 @@ obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o + diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index eb33aaa..7614313 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -51,6 +51,7 @@ #include #include #include +#include #include "xen-ops.h" #include "mmu.h" @@ -330,18 +331,28 @@ static void xen_load_gdt(const struct desc_ptr *dtr) unsigned long frames[pages]; int f; - /* A GDT can be up to 64k in size, which corresponds to 8192 - 8-byte entries, or 16 4k pages.. */ + /* + * A GDT can be up to 64k in size, which corresponds to 8192 + * 8-byte entries, or 16 4k pages.. + */ BUG_ON(size > 65536); BUG_ON(va & ~PAGE_MASK); for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) { int level; - pte_t *ptep = lookup_address(va, &level); + pte_t *ptep; unsigned long pfn, mfn; void *virt; + /* + * The GDT is per-cpu and is in the percpu data area. + * That can be virtually mapped, so we need to do a + * page-walk to get the underlying MFN for the + * hypercall. The page can also be in the kernel's + * linear range, so we need to RO that mapping too. + */ + ptep = lookup_address(va, &level); BUG_ON(ptep == NULL); pfn = pte_pfn(*ptep); @@ -358,6 +369,44 @@ static void xen_load_gdt(const struct desc_ptr *dtr) BUG(); } +/* + * load_gdt for early boot, when the gdt is only mapped once + */ +static __init void xen_load_gdt_boot(const struct desc_ptr *dtr) +{ + unsigned long va = dtr->address; + unsigned int size = dtr->size + 1; + unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; + unsigned long frames[pages]; + int f; + + /* + * A GDT can be up to 64k in size, which corresponds to 8192 + * 8-byte entries, or 16 4k pages.. + */ + + BUG_ON(size > 65536); + BUG_ON(va & ~PAGE_MASK); + + for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) { + pte_t pte; + unsigned long pfn, mfn; + + pfn = virt_to_pfn(va); + mfn = pfn_to_mfn(pfn); + + pte = pfn_pte(pfn, PAGE_KERNEL_RO); + + if (HYPERVISOR_update_va_mapping((unsigned long)va, pte, 0)) + BUG(); + + frames[f] = mfn; + } + + if (HYPERVISOR_set_gdt(frames, size / sizeof(struct desc_struct))) + BUG(); +} + static void load_TLS_descriptor(struct thread_struct *t, unsigned int cpu, unsigned int i) { @@ -581,6 +630,29 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry, preempt_enable(); } +/* + * Version of write_gdt_entry for use at early boot-time needed to + * update an entry as simply as possible. + */ +static __init void xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, + const void *desc, int type) +{ + switch (type) { + case DESC_LDT: + case DESC_TSS: + /* ignore */ + break; + + default: { + xmaddr_t maddr = virt_to_machine(&dt[entry]); + + if (HYPERVISOR_update_descriptor(maddr.maddr, *(u64 *)desc)) + dt[entry] = *(struct desc_struct *)desc; + } + + } +} + static void xen_load_sp0(struct tss_struct *tss, struct thread_struct *thread) { @@ -965,6 +1037,23 @@ static const struct machine_ops __initdata xen_machine_ops = { .emergency_restart = xen_emergency_restart, }; +/* + * Set up the GDT and segment registers for -fstack-protector. Until + * we do this, we have to be careful not to call any stack-protected + * function, which is most of the kernel. + */ +static void __init xen_setup_stackprotector(void) +{ + pv_cpu_ops.write_gdt_entry = xen_write_gdt_entry_boot; + pv_cpu_ops.load_gdt = xen_load_gdt_boot; + + setup_stack_canary_segment(0); + switch_to_new_gdt(0); + + pv_cpu_ops.write_gdt_entry = xen_write_gdt_entry; + pv_cpu_ops.load_gdt = xen_load_gdt; +} + /* First C function to be called on Xen boot */ asmlinkage void __init xen_start_kernel(void) { @@ -983,13 +1072,28 @@ asmlinkage void __init xen_start_kernel(void) pv_apic_ops = xen_apic_ops; pv_mmu_ops = xen_mmu_ops; -#ifdef CONFIG_X86_64 /* - * Setup percpu state. We only need to do this for 64-bit - * because 32-bit already has %fs set properly. + * Set up some pagetable state before starting to set any ptes. */ - load_percpu_segment(0); -#endif + + /* Prevent unwanted bits from being set in PTEs. */ + __supported_pte_mask &= ~_PAGE_GLOBAL; + if (!xen_initial_domain()) + __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD); + + __supported_pte_mask |= _PAGE_IOMAP; + + xen_setup_features(); + + /* Get mfn list */ + if (!xen_feature(XENFEAT_auto_translated_physmap)) + xen_build_dynamic_phys_to_machine(); + + /* + * Set up kernel GDT and segment registers, mainly so that + * -fstack-protector code can be executed. + */ + xen_setup_stackprotector(); xen_init_irq_ops(); xen_init_cpuid_mask(); @@ -1001,8 +1105,6 @@ asmlinkage void __init xen_start_kernel(void) set_xen_basic_apic_ops(); #endif - xen_setup_features(); - if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start; pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit; @@ -1019,17 +1121,8 @@ asmlinkage void __init xen_start_kernel(void) xen_smp_init(); - /* Get mfn list */ - if (!xen_feature(XENFEAT_auto_translated_physmap)) - xen_build_dynamic_phys_to_machine(); - pgd = (pgd_t *)xen_start_info->pt_base; - /* Prevent unwanted bits from being set in PTEs. */ - __supported_pte_mask &= ~_PAGE_GLOBAL; - if (!xen_initial_domain()) - __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD); - #ifdef CONFIG_X86_64 /* Work out if we support NX */ check_efer(); diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 429834e..fe03eee 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -236,6 +236,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) ctxt->user_regs.ss = __KERNEL_DS; #ifdef CONFIG_X86_32 ctxt->user_regs.fs = __KERNEL_PERCPU; + ctxt->user_regs.gs = __KERNEL_STACK_CANARY; #else ctxt->gs_base_kernel = per_cpu_offset(cpu); #endif diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index ec2a39b..7c28434 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -1,6 +1,9 @@ obj-y += grant-table.o features.o events.o manage.o obj-y += xenbus/ +nostackp := $(call cc-option, -fno-stack-protector) +CFLAGS_features.o := $(nostackp) + obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o obj-$(CONFIG_XEN_XENCOMM) += xencomm.o obj-$(CONFIG_XEN_BALLOON) += balloon.o -- cgit v0.10.2 From 4d576b57b50a92801e6493e76e5243d6cff193d2 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Wed, 9 Sep 2009 12:33:51 -0700 Subject: xen: only enable interrupts while actually blocking for spinlock Where possible we enable interrupts while waiting for a spinlock to become free, in order to reduce big latency spikes in interrupt handling. However, at present if we manage to pick up the spinlock just before blocking, we'll end up holding the lock with interrupts enabled for a while. This will cause a deadlock if we recieve an interrupt in that window, and the interrupt handler tries to take the lock too. Solve this by shrinking the interrupt-enabled region to just around the blocking call. [ Impact: avoid race/deadlock when using Xen PV spinlocks ] Reported-by: "Yang, Xiaowei" Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c index 5601506..2f91e56 100644 --- a/arch/x86/xen/spinlock.c +++ b/arch/x86/xen/spinlock.c @@ -187,7 +187,6 @@ static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enabl struct xen_spinlock *prev; int irq = __get_cpu_var(lock_kicker_irq); int ret; - unsigned long flags; u64 start; /* If kicker interrupts not initialized yet, just spin */ @@ -199,16 +198,12 @@ static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enabl /* announce we're spinning */ prev = spinning_lock(xl); - flags = __raw_local_save_flags(); - if (irq_enable) { - ADD_STATS(taken_slow_irqenable, 1); - raw_local_irq_enable(); - } - ADD_STATS(taken_slow, 1); ADD_STATS(taken_slow_nested, prev != NULL); do { + unsigned long flags; + /* clear pending */ xen_clear_irq_pending(irq); @@ -228,6 +223,12 @@ static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enabl goto out; } + flags = __raw_local_save_flags(); + if (irq_enable) { + ADD_STATS(taken_slow_irqenable, 1); + raw_local_irq_enable(); + } + /* * Block until irq becomes pending. If we're * interrupted at this point (after the trylock but @@ -238,13 +239,15 @@ static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enabl * pending. */ xen_poll_irq(irq); + + raw_local_irq_restore(flags); + ADD_STATS(taken_slow_spurious, !xen_test_irq_pending(irq)); } while (!xen_test_irq_pending(irq)); /* check for spurious wakeups */ kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); out: - raw_local_irq_restore(flags); unspinning_lock(xl, prev); spin_time_accum_blocked(start); -- cgit v0.10.2 From 2496afbf1e50c70f80992656bcb730c8583ddac3 Mon Sep 17 00:00:00 2001 From: Yang Xiaowei Date: Wed, 9 Sep 2009 12:44:52 -0700 Subject: xen: use stronger barrier after unlocking lock We need to have a stronger barrier between releasing the lock and checking for any waiting spinners. A compiler barrier is not sufficient because the CPU's ordering rules do not prevent the read xl->spinners from happening before the unlock assignment, as they are different memory locations. We need to have an explicit barrier to enforce the write-read ordering to different memory locations. Because of it, I can't bring up > 4 HVM guests on one SMP machine. [ Code and commit comments expanded -J ] [ Impact: avoid deadlock when using Xen PV spinlocks ] Signed-off-by: Yang Xiaowei Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c index 2f91e56..36a5141 100644 --- a/arch/x86/xen/spinlock.c +++ b/arch/x86/xen/spinlock.c @@ -326,8 +326,13 @@ static void xen_spin_unlock(struct raw_spinlock *lock) smp_wmb(); /* make sure no writes get moved after unlock */ xl->lock = 0; /* release lock */ - /* make sure unlock happens before kick */ - barrier(); + /* + * Make sure unlock happens before checking for waiting + * spinners. We need a strong barrier to enforce the + * write-read ordering to different memory locations, as the + * CPU makes no implied guarantees about their ordering. + */ + mb(); if (unlikely(xl->spinners)) xen_spin_unlock_slow(xl); -- cgit v0.10.2 From b1ab7e4b2a88d3ac13771463be8f302ce1616cfc Mon Sep 17 00:00:00 2001 From: "David P. Quigley" Date: Thu, 3 Sep 2009 14:25:56 -0400 Subject: VFS: Factor out part of vfs_setxattr so it can be called from the SELinux hook for inode_setsecctx. This factors out the part of the vfs_setxattr function that performs the setting of the xattr and its notification. This is needed so the SELinux implementation of inode_setsecctx can handle the setting of the xattr while maintaining the proper separation of layers. Signed-off-by: David P. Quigley Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/fs/xattr.c b/fs/xattr.c index 1c3d0af..6d4f6d3 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -66,22 +66,28 @@ xattr_permission(struct inode *inode, const char *name, int mask) return inode_permission(inode, mask); } -int -vfs_setxattr(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags) +/** + * __vfs_setxattr_noperm - perform setxattr operation without performing + * permission checks. + * + * @dentry - object to perform setxattr on + * @name - xattr name to set + * @value - value to set @name to + * @size - size of @value + * @flags - flags to pass into filesystem operations + * + * returns the result of the internal setxattr or setsecurity operations. + * + * This function requires the caller to lock the inode's i_mutex before it + * is executed. It also assumes that the caller will make the appropriate + * permission checks. + */ +int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) { struct inode *inode = dentry->d_inode; - int error; - - error = xattr_permission(inode, name, MAY_WRITE); - if (error) - return error; + int error = -EOPNOTSUPP; - mutex_lock(&inode->i_mutex); - error = security_inode_setxattr(dentry, name, value, size, flags); - if (error) - goto out; - error = -EOPNOTSUPP; if (inode->i_op->setxattr) { error = inode->i_op->setxattr(dentry, name, value, size, flags); if (!error) { @@ -97,6 +103,29 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value, if (!error) fsnotify_xattr(dentry); } + + return error; +} + + +int +vfs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t size, int flags) +{ + struct inode *inode = dentry->d_inode; + int error; + + error = xattr_permission(inode, name, MAY_WRITE); + if (error) + return error; + + mutex_lock(&inode->i_mutex); + error = security_inode_setxattr(dentry, name, value, size, flags); + if (error) + goto out; + + error = __vfs_setxattr_noperm(dentry, name, value, size, flags); + out: mutex_unlock(&inode->i_mutex); return error; diff --git a/include/linux/xattr.h b/include/linux/xattr.h index d131e35..5c84af8 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -49,6 +49,7 @@ struct xattr_handler { ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t); ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t); ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size); +int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int); int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int); int vfs_removexattr(struct dentry *, const char *); -- cgit v0.10.2 From 1ee65e37e904b959c24404139f5752edc66319d5 Mon Sep 17 00:00:00 2001 From: "David P. Quigley" Date: Thu, 3 Sep 2009 14:25:57 -0400 Subject: LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information. This patch introduces three new hooks. The inode_getsecctx hook is used to get all relevant information from an LSM about an inode. The inode_setsecctx is used to set both the in-core and on-disk state for the inode based on a context derived from inode_getsecctx.The final hook inode_notifysecctx will notify the LSM of a change for the in-core state of the inode in question. These hooks are for use in the labeled NFS code and addresses concerns of how to set security on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's explanation of the reason for these hooks is pasted below. Quote Stephen Smalley inode_setsecctx: Change the security context of an inode. Updates the in core security context managed by the security module and invokes the fs code as needed (via __vfs_setxattr_noperm) to update any backing xattrs that represent the context. Example usage: NFS server invokes this hook to change the security context in its incore inode and on the backing file system to a value provided by the client on a SETATTR operation. inode_notifysecctx: Notify the security module of what the security context of an inode should be. Initializes the incore security context managed by the security module for this inode. Example usage: NFS client invokes this hook to initialize the security context in its incore inode to the value provided by the server for the file when the server returned the file's attributes to the client. Signed-off-by: David P. Quigley Acked-by: Serge Hallyn Signed-off-by: James Morris diff --git a/include/linux/security.h b/include/linux/security.h index 10a0925..d050b66 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1382,6 +1382,41 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * audit_rule_init. * @rule contains the allocated rule * + * @inode_notifysecctx: + * Notify the security module of what the security context of an inode + * should be. Initializes the incore security context managed by the + * security module for this inode. Example usage: NFS client invokes + * this hook to initialize the security context in its incore inode to the + * value provided by the server for the file when the server returned the + * file's attributes to the client. + * + * Must be called with inode->i_mutex locked. + * + * @inode we wish to set the security context of. + * @ctx contains the string which we wish to set in the inode. + * @ctxlen contains the length of @ctx. + * + * @inode_setsecctx: + * Change the security context of an inode. Updates the + * incore security context managed by the security module and invokes the + * fs code as needed (via __vfs_setxattr_noperm) to update any backing + * xattrs that represent the context. Example usage: NFS server invokes + * this hook to change the security context in its incore inode and on the + * backing filesystem to a value provided by the client on a SETATTR + * operation. + * + * Must be called with inode->i_mutex locked. + * + * @dentry contains the inode we wish to set the security context of. + * @ctx contains the string which we wish to set in the inode. + * @ctxlen contains the length of @ctx. + * + * @inode_getsecctx: + * Returns a string containing all relavent security context information + * + * @inode we wish to set the security context of. + * @ctx is a pointer in which to place the allocated security context. + * @ctxlen points to the place to put the length of @ctx. * This is the main security structure. */ struct security_operations { @@ -1590,6 +1625,10 @@ struct security_operations { int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid); void (*release_secctx) (char *secdata, u32 seclen); + int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen); + int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen); + int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen); + #ifdef CONFIG_SECURITY_NETWORK int (*unix_stream_connect) (struct socket *sock, struct socket *other, struct sock *newsk); @@ -1839,6 +1878,9 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); void security_release_secctx(char *secdata, u32 seclen); +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); #else /* CONFIG_SECURITY */ struct security_mnt_opts { }; @@ -2595,6 +2637,19 @@ static inline int security_secctx_to_secid(const char *secdata, static inline void security_release_secctx(char *secdata, u32 seclen) { } + +static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) +{ + return -EOPNOTSUPP; +} +static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) +{ + return -EOPNOTSUPP; +} +static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_SECURITY */ #ifdef CONFIG_SECURITY_NETWORK diff --git a/security/capability.c b/security/capability.c index 93a2ffe..fce07a7 100644 --- a/security/capability.c +++ b/security/capability.c @@ -822,6 +822,20 @@ static void cap_release_secctx(char *secdata, u32 seclen) { } +static int cap_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) +{ + return 0; +} + +static int cap_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) +{ + return 0; +} + +static int cap_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) +{ + return 0; +} #ifdef CONFIG_KEYS static int cap_key_alloc(struct key *key, const struct cred *cred, unsigned long flags) @@ -1032,6 +1046,9 @@ void security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, secid_to_secctx); set_to_cap_if_null(ops, secctx_to_secid); set_to_cap_if_null(ops, release_secctx); + set_to_cap_if_null(ops, inode_notifysecctx); + set_to_cap_if_null(ops, inode_setsecctx); + set_to_cap_if_null(ops, inode_getsecctx); #ifdef CONFIG_SECURITY_NETWORK set_to_cap_if_null(ops, unix_stream_connect); set_to_cap_if_null(ops, unix_may_send); diff --git a/security/security.c b/security/security.c index d8b7276..c4c6732 100644 --- a/security/security.c +++ b/security/security.c @@ -974,6 +974,24 @@ void security_release_secctx(char *secdata, u32 seclen) } EXPORT_SYMBOL(security_release_secctx); +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) +{ + return security_ops->inode_notifysecctx(inode, ctx, ctxlen); +} +EXPORT_SYMBOL(security_inode_notifysecctx); + +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) +{ + return security_ops->inode_setsecctx(dentry, ctx, ctxlen); +} +EXPORT_SYMBOL(security_inode_setsecctx); + +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) +{ + return security_ops->inode_getsecctx(inode, ctx, ctxlen); +} +EXPORT_SYMBOL(security_inode_getsecctx); + #ifdef CONFIG_SECURITY_NETWORK int security_unix_stream_connect(struct socket *sock, struct socket *other, diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 134a9c0..7118be2 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5351,6 +5351,32 @@ static void selinux_release_secctx(char *secdata, u32 seclen) kfree(secdata); } +/* + * called with inode->i_mutex locked + */ +static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) +{ + return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0); +} + +/* + * called with inode->i_mutex locked + */ +static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) +{ + return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0); +} + +static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) +{ + int len = 0; + len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX, + ctx, true); + if (len < 0) + return len; + *ctxlen = len; + return 0; +} #ifdef CONFIG_KEYS static int selinux_key_alloc(struct key *k, const struct cred *cred, @@ -5550,6 +5576,9 @@ static struct security_operations selinux_ops = { .secid_to_secctx = selinux_secid_to_secctx, .secctx_to_secid = selinux_secctx_to_secid, .release_secctx = selinux_release_secctx, + .inode_notifysecctx = selinux_inode_notifysecctx, + .inode_setsecctx = selinux_inode_setsecctx, + .inode_getsecctx = selinux_inode_getsecctx, .unix_stream_connect = selinux_socket_unix_stream_connect, .unix_may_send = selinux_socket_unix_may_send, diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 969f5fe..0b3bb64 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3057,6 +3057,27 @@ static void smack_release_secctx(char *secdata, u32 seclen) { } +static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) +{ + return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx, ctxlen, 0); +} + +static int smack_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) +{ + return __vfs_setxattr_noperm(dentry, XATTR_NAME_SMACK, ctx, ctxlen, 0); +} + +static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) +{ + int len = 0; + len = smack_inode_getsecurity(inode, XATTR_SMACK_SUFFIX, ctx, true); + + if (len < 0) + return len; + *ctxlen = len; + return 0; +} + struct security_operations smack_ops = { .name = "smack", @@ -3185,6 +3206,9 @@ struct security_operations smack_ops = { .secid_to_secctx = smack_secid_to_secctx, .secctx_to_secid = smack_secctx_to_secid, .release_secctx = smack_release_secctx, + .inode_notifysecctx = smack_inode_notifysecctx, + .inode_setsecctx = smack_inode_setsecctx, + .inode_getsecctx = smack_inode_getsecctx, }; -- cgit v0.10.2 From ddd29ec6597125c830f7badb608a86c98b936b64 Mon Sep 17 00:00:00 2001 From: "David P. Quigley" Date: Wed, 9 Sep 2009 14:25:37 -0400 Subject: sysfs: Add labeling support for sysfs This patch adds a setxattr handler to the file, directory, and symlink inode_operations structures for sysfs. The patch uses hooks introduced in the previous patch to handle the getting and setting of security information for the sysfs inodes. As was suggested by Eric Biederman the struct iattr in the sysfs_dirent structure has been replaced by a structure which contains the iattr, secdata and secdata length to allow the changes to persist in the event that the inode representing the sysfs_dirent is evicted. Because sysfs only stores this information when a change is made all the optional data is moved into one dynamically allocated field. This patch addresses an issue where SELinux was denying virtd access to the PCI configuration entries in sysfs. The lack of setxattr handlers for sysfs required that a single label be assigned to all entries in sysfs. Granting virtd access to every entry in sysfs is not an acceptable solution so fine grained labeling of sysfs is required such that individual entries can be labeled appropriately. [sds: Fixed compile-time warnings, coding style, and setting of inode security init flags.] Signed-off-by: David P. Quigley Signed-off-by: Stephen D. Smalley Signed-off-by: James Morris diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 14f2d71..0050fc4 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -760,6 +760,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, const struct inode_operations sysfs_dir_inode_operations = { .lookup = sysfs_lookup, .setattr = sysfs_setattr, + .setxattr = sysfs_setxattr, }; static void remove_dir(struct sysfs_dirent *sd) diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 555f0ff..2b6a8d9 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include "sysfs.h" extern struct super_block * sysfs_sb; @@ -35,6 +37,7 @@ static struct backing_dev_info sysfs_backing_dev_info = { static const struct inode_operations sysfs_inode_operations ={ .setattr = sysfs_setattr, + .setxattr = sysfs_setxattr, }; int __init sysfs_inode_init(void) @@ -42,18 +45,37 @@ int __init sysfs_inode_init(void) return bdi_init(&sysfs_backing_dev_info); } +struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) +{ + struct sysfs_inode_attrs *attrs; + struct iattr *iattrs; + + attrs = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL); + if (!attrs) + return NULL; + iattrs = &attrs->ia_iattr; + + /* assign default attributes */ + iattrs->ia_mode = sd->s_mode; + iattrs->ia_uid = 0; + iattrs->ia_gid = 0; + iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; + + return attrs; +} int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) { struct inode * inode = dentry->d_inode; struct sysfs_dirent * sd = dentry->d_fsdata; - struct iattr * sd_iattr; + struct sysfs_inode_attrs *sd_attrs; + struct iattr *iattrs; unsigned int ia_valid = iattr->ia_valid; int error; if (!sd) return -EINVAL; - sd_iattr = sd->s_iattr; + sd_attrs = sd->s_iattr; error = inode_change_ok(inode, iattr); if (error) @@ -65,42 +87,77 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) if (error) return error; - if (!sd_iattr) { + if (!sd_attrs) { /* setting attributes for the first time, allocate now */ - sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); - if (!sd_iattr) + sd_attrs = sysfs_init_inode_attrs(sd); + if (!sd_attrs) return -ENOMEM; - /* assign default attributes */ - sd_iattr->ia_mode = sd->s_mode; - sd_iattr->ia_uid = 0; - sd_iattr->ia_gid = 0; - sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; - sd->s_iattr = sd_iattr; + sd->s_iattr = sd_attrs; + } else { + /* attributes were changed at least once in past */ + iattrs = &sd_attrs->ia_iattr; + + if (ia_valid & ATTR_UID) + iattrs->ia_uid = iattr->ia_uid; + if (ia_valid & ATTR_GID) + iattrs->ia_gid = iattr->ia_gid; + if (ia_valid & ATTR_ATIME) + iattrs->ia_atime = timespec_trunc(iattr->ia_atime, + inode->i_sb->s_time_gran); + if (ia_valid & ATTR_MTIME) + iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime, + inode->i_sb->s_time_gran); + if (ia_valid & ATTR_CTIME) + iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime, + inode->i_sb->s_time_gran); + if (ia_valid & ATTR_MODE) { + umode_t mode = iattr->ia_mode; + + if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) + mode &= ~S_ISGID; + iattrs->ia_mode = sd->s_mode = mode; + } } + return error; +} - /* attributes were changed atleast once in past */ - - if (ia_valid & ATTR_UID) - sd_iattr->ia_uid = iattr->ia_uid; - if (ia_valid & ATTR_GID) - sd_iattr->ia_gid = iattr->ia_gid; - if (ia_valid & ATTR_ATIME) - sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, - inode->i_sb->s_time_gran); - if (ia_valid & ATTR_MTIME) - sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, - inode->i_sb->s_time_gran); - if (ia_valid & ATTR_CTIME) - sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, - inode->i_sb->s_time_gran); - if (ia_valid & ATTR_MODE) { - umode_t mode = iattr->ia_mode; - - if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) - mode &= ~S_ISGID; - sd_iattr->ia_mode = sd->s_mode = mode; - } +int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t size, int flags) +{ + struct sysfs_dirent *sd = dentry->d_fsdata; + struct sysfs_inode_attrs *iattrs; + void *secdata; + int error; + u32 secdata_len = 0; + + if (!sd) + return -EINVAL; + if (!sd->s_iattr) + sd->s_iattr = sysfs_init_inode_attrs(sd); + if (!sd->s_iattr) + return -ENOMEM; + + iattrs = sd->s_iattr; + + if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { + const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; + error = security_inode_setsecurity(dentry->d_inode, suffix, + value, size, flags); + if (error) + goto out; + error = security_inode_getsecctx(dentry->d_inode, + &secdata, &secdata_len); + if (error) + goto out; + if (iattrs->ia_secdata) + security_release_secctx(iattrs->ia_secdata, + iattrs->ia_secdata_len); + iattrs->ia_secdata = secdata; + iattrs->ia_secdata_len = secdata_len; + } else + return -EINVAL; +out: return error; } @@ -146,6 +203,7 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) { struct bin_attribute *bin_attr; + struct sysfs_inode_attrs *iattrs; inode->i_private = sysfs_get(sd); inode->i_mapping->a_ops = &sysfs_aops; @@ -154,16 +212,20 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) inode->i_ino = sd->s_ino; lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); - if (sd->s_iattr) { + iattrs = sd->s_iattr; + if (iattrs) { /* sysfs_dirent has non-default attributes * get them for the new inode from persistent copy * in sysfs_dirent */ - set_inode_attr(inode, sd->s_iattr); + set_inode_attr(inode, &iattrs->ia_iattr); + if (iattrs->ia_secdata) + security_inode_notifysecctx(inode, + iattrs->ia_secdata, + iattrs->ia_secdata_len); } else set_default_inode_attr(inode, sd->s_mode); - /* initialize inode according to type */ switch (sysfs_type(sd)) { case SYSFS_DIR: diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 1d897ad..c5081ad 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "sysfs.h" @@ -209,6 +210,7 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co } const struct inode_operations sysfs_symlink_inode_operations = { + .setxattr = sysfs_setxattr, .readlink = generic_readlink, .follow_link = sysfs_follow_link, .put_link = sysfs_put_link, diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3fa0d98..af4c4e7 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -8,6 +8,8 @@ * This file is released under the GPLv2. */ +#include + struct sysfs_open_dirent; /* type-specific structures for sysfs_dirent->s_* union members */ @@ -31,6 +33,12 @@ struct sysfs_elem_bin_attr { struct hlist_head buffers; }; +struct sysfs_inode_attrs { + struct iattr ia_iattr; + void *ia_secdata; + u32 ia_secdata_len; +}; + /* * sysfs_dirent - the building block of sysfs hierarchy. Each and * every sysfs node is represented by single sysfs_dirent. @@ -56,7 +64,7 @@ struct sysfs_dirent { unsigned int s_flags; ino_t s_ino; umode_t s_mode; - struct iattr *s_iattr; + struct sysfs_inode_attrs *s_iattr; }; #define SD_DEACTIVATED_BIAS INT_MIN @@ -148,6 +156,8 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) struct inode *sysfs_get_inode(struct sysfs_dirent *sd); void sysfs_delete_inode(struct inode *inode); int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); +int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t size, int flags); int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); int sysfs_inode_init(void); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7118be2..417f7c9 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -448,6 +448,10 @@ static int sb_finish_set_opts(struct super_block *sb) sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) sbsec->flags &= ~SE_SBLABELSUPP; + /* Special handling for sysfs. Is genfs but also has setxattr handler*/ + if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0) + sbsec->flags |= SE_SBLABELSUPP; + /* Initialize the root inode. */ rc = inode_doinit_with_dentry(root_inode, root); @@ -2923,6 +2927,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, return rc; isec->sid = newsid; + isec->initialized = 1; return 0; } diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 0b3bb64..acae7ef4 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1666,6 +1666,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { nsp->smk_inode = sp; + nsp->smk_flags |= SMK_INODE_INSTANT; return 0; } /* -- cgit v0.10.2 From 23bcf634c8bc0d84607a5b863333191d58baee4c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 9 Sep 2009 18:11:23 -0700 Subject: net_sched: fix estimator lock selection for mq child qdiscs When new child qdiscs are attached to the mq qdisc, they are actually attached as root qdiscs to the device queues. The lock selection for new estimators incorrectly picks the root lock of the existing and to be replaced qdisc, which results in a use-after-free once the old qdisc has been destroyed. Mark mq qdisc instances with a new flag and treat qdiscs attached to mq as children similar to regular root qdiscs. Additionally prevent estimators from being attached to the mq qdisc itself since it only updates its byte and packet counters during dumps. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 9c69585..88eb9de 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -46,6 +46,7 @@ struct Qdisc #define TCQ_F_THROTTLED 2 #define TCQ_F_INGRESS 4 #define TCQ_F_CAN_BYPASS 8 +#define TCQ_F_MQROOT 16 #define TCQ_F_WARN_NONWC (1 << 16) int padded; struct Qdisc_ops *ops; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 2a78d54..3af1061 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -733,7 +733,8 @@ static struct lock_class_key qdisc_rx_lock; static struct Qdisc * qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, - u32 parent, u32 handle, struct nlattr **tca, int *errp) + struct Qdisc *p, u32 parent, u32 handle, + struct nlattr **tca, int *errp) { int err; struct nlattr *kind = tca[TCA_KIND]; @@ -810,24 +811,21 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, if (tca[TCA_RATE]) { spinlock_t *root_lock; + err = -EOPNOTSUPP; + if (sch->flags & TCQ_F_MQROOT) + goto err_out4; + if ((sch->parent != TC_H_ROOT) && - !(sch->flags & TCQ_F_INGRESS)) + !(sch->flags & TCQ_F_INGRESS) && + (!p || !(p->flags & TCQ_F_MQROOT))) root_lock = qdisc_root_sleeping_lock(sch); else root_lock = qdisc_lock(sch); err = gen_new_estimator(&sch->bstats, &sch->rate_est, root_lock, tca[TCA_RATE]); - if (err) { - /* - * Any broken qdiscs that would require - * a ops->reset() here? The qdisc was never - * in action so it shouldn't be necessary. - */ - if (ops->destroy) - ops->destroy(sch); - goto err_out3; - } + if (err) + goto err_out4; } qdisc_list_add(sch); @@ -843,6 +841,15 @@ err_out2: err_out: *errp = err; return NULL; + +err_out4: + /* + * Any broken qdiscs that would require a ops->reset() here? + * The qdisc was never in action so it shouldn't be necessary. + */ + if (ops->destroy) + ops->destroy(sch); + goto err_out3; } static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) @@ -867,13 +874,16 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) qdisc_put_stab(sch->stab); sch->stab = stab; - if (tca[TCA_RATE]) + if (tca[TCA_RATE]) { /* NB: ignores errors from replace_estimator because change can't be undone. */ + if (sch->flags & TCQ_F_MQROOT) + goto out; gen_replace_estimator(&sch->bstats, &sch->rate_est, qdisc_root_sleeping_lock(sch), tca[TCA_RATE]); - + } +out: return 0; } @@ -1097,7 +1107,7 @@ create_n_graft: if (!(n->nlmsg_flags&NLM_F_CREATE)) return -ENOENT; if (clid == TC_H_INGRESS) - q = qdisc_create(dev, &dev->rx_queue, + q = qdisc_create(dev, &dev->rx_queue, p, tcm->tcm_parent, tcm->tcm_parent, tca, &err); else { @@ -1106,7 +1116,7 @@ create_n_graft: if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue) ntx = p->ops->cl_ops->select_queue(p, tcm); - q = qdisc_create(dev, netdev_get_tx_queue(dev, ntx), + q = qdisc_create(dev, netdev_get_tx_queue(dev, ntx), p, tcm->tcm_parent, tcm->tcm_handle, tca, &err); } diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index c84dec9..dd5ee02 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c @@ -64,6 +64,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt) priv->qdiscs[ntx] = qdisc; } + sch->flags |= TCQ_F_MQROOT; return 0; err: -- cgit v0.10.2 From 3db7675506ef7460bf6220545bfc69abb7dbceab Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Wed, 9 Sep 2009 18:12:37 -0700 Subject: netxen: fix check for ip addr hashing support Fix typo in checking dest ip has support before programming destip addresses. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 304618a..81c24a7 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -2340,7 +2340,7 @@ netxen_config_indev_addr(struct net_device *dev, unsigned long event) struct in_device *indev; struct netxen_adapter *adapter = netdev_priv(dev); - if (netxen_destip_supported(adapter)) + if (!netxen_destip_supported(adapter)) return; indev = in_dev_get(dev); -- cgit v0.10.2 From 58f25468b5636c390ad2a58356b127c0055884b4 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Wed, 9 Sep 2009 18:12:59 -0700 Subject: netxen: fix tx descriptor structure Fix the offset of vlan_TCI field in cmd_desc_type0. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 2a52479..2371888 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -348,9 +348,9 @@ struct cmd_desc_type0 { __le64 addr_buffer4; - __le16 vlan_TCI; - __le16 reserved; __le32 reserved2; + __le16 reserved; + __le16 vlan_TCI; } __attribute__ ((aligned(64))); -- cgit v0.10.2 From 07fcb044b6ea53b67d00e198f9073e0538df7b75 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 9 Sep 2009 01:07:44 +0000 Subject: dm9000: Remove unnecessary memset of netdev private data The memory for the private data is allocated using kzalloc in alloc_etherdev (or alloc_netdev_mq respectively) so there is no need to set it to 0 again. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index a2bc415..60de176 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1281,7 +1281,6 @@ dm9000_probe(struct platform_device *pdev) /* setup board info structure */ db = netdev_priv(ndev); - memset(db, 0, sizeof(*db)); db->dev = &pdev->dev; db->ndev = ndev; -- cgit v0.10.2 From ec282e9225be924479d4880b51f13524795bd8d3 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 9 Sep 2009 01:07:43 +0000 Subject: dm9000: Use resource_size instead of private macro The macro res_size in drivers/net/dm9000.c is a copy of resource_size in linux/ioport.h. Remove the function and use resource_size instead. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 60de176..31b8bef 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1251,8 +1251,6 @@ static const struct net_device_ops dm9000_netdev_ops = { #endif }; -#define res_size(_r) (((_r)->end - (_r)->start) + 1) - /* * Search DM9000 board, allocate space and register it */ @@ -1301,7 +1299,7 @@ dm9000_probe(struct platform_device *pdev) goto out; } - iosize = res_size(db->addr_res); + iosize = resource_size(db->addr_res); db->addr_req = request_mem_region(db->addr_res->start, iosize, pdev->name); @@ -1319,7 +1317,7 @@ dm9000_probe(struct platform_device *pdev) goto out; } - iosize = res_size(db->data_res); + iosize = resource_size(db->data_res); db->data_req = request_mem_region(db->data_res->start, iosize, pdev->name); -- cgit v0.10.2 From 752015d1b0683a8c623ebfe4c62893413e9b30d3 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Tue, 8 Sep 2009 19:49:40 -0700 Subject: binfmt_elf: fix PT_INTERP bss handling In fs/binfmt_elf.c, load_elf_interp() calls padzero() for .bss even if the PT_LOAD has no PROT_WRITE and no .bss. This generates EFAULT. Here is a small test case. (Yes, there are other, useful PT_INTERP which have only .text and no .data/.bss.) ----- ptinterp.S _start: .globl _start nop int3 ----- $ gcc -m32 -nostartfiles -nostdlib -o ptinterp ptinterp.S $ gcc -m32 -Wl,--dynamic-linker=ptinterp -o hello hello.c $ ./hello Segmentation fault # during execve() itself After applying the patch: $ ./hello Trace trap # user-mode execution after execve() finishes If the ELF headers are actually self-inconsistent, then dying is fine. But having no PROT_WRITE segment is perfectly normal and correct if there is no segment with p_memsz > p_filesz (i.e. bss). John Reiser suggested checking for PROT_WRITE in the bss logic. I think it makes most sense to simply apply the bss logic only when there is bss. This patch looks less trivial than it is due to some reindentation. It just moves the "if (last_bss > elf_bss) {" test up to include the partial-page bss logic as well as the more-pages bss logic. Reported-by: John Reiser Signed-off-by: Roland McGrath Signed-off-by: Linus Torvalds diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index b7c1603..7c1e65d 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -501,22 +501,22 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, } } - /* - * Now fill out the bss section. First pad the last page up - * to the page boundary, and then perform a mmap to make sure - * that there are zero-mapped pages up to and including the - * last bss page. - */ - if (padzero(elf_bss)) { - error = -EFAULT; - goto out_close; - } + if (last_bss > elf_bss) { + /* + * Now fill out the bss section. First pad the last page up + * to the page boundary, and then perform a mmap to make sure + * that there are zero-mapped pages up to and including the + * last bss page. + */ + if (padzero(elf_bss)) { + error = -EFAULT; + goto out_close; + } - /* What we have mapped so far */ - elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); + /* What we have mapped so far */ + elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); - /* Map the last of the bss segment */ - if (last_bss > elf_bss) { + /* Map the last of the bss segment */ down_write(¤t->mm->mmap_sem); error = do_brk(elf_bss, last_bss - elf_bss); up_write(¤t->mm->mmap_sem); -- cgit v0.10.2 From ec57935837a78f9661125b08a5d08b697568e040 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 9 Sep 2009 17:22:18 -0600 Subject: TPM: Fixup boot probe timeout for tpm_tis driver When probing the device in tpm_tis_init the call request_locality uses timeout_a, which wasn't being initalized until after request_locality. This results in request_locality falsely timing out if the chip is still starting. Move the initialization to before request_locality. This probably only matters for embedded cases (ie mine), a BIOS likely gets the TPM into a state where this code path isn't necessary. Signed-off-by: Jason Gunthorpe Acked-by: Rajiv Andrade Signed-off-by: James Morris diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index aec1931..0b73e4e 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -450,6 +450,12 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, goto out_err; } + /* Default timeouts */ + chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); + chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + if (request_locality(chip, 0) != 0) { rc = -ENODEV; goto out_err; @@ -457,12 +463,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); - /* Default timeouts */ - chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); - chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - dev_info(dev, "1.2 TPM (device-id 0x%X, rev-id %d)\n", vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); -- cgit v0.10.2 From 9f0ab4a3f0fdb1ff404d150618ace2fa069bb2e1 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Tue, 8 Sep 2009 19:49:40 -0700 Subject: binfmt_elf: fix PT_INTERP bss handling In fs/binfmt_elf.c, load_elf_interp() calls padzero() for .bss even if the PT_LOAD has no PROT_WRITE and no .bss. This generates EFAULT. Here is a small test case. (Yes, there are other, useful PT_INTERP which have only .text and no .data/.bss.) ----- ptinterp.S _start: .globl _start nop int3 ----- $ gcc -m32 -nostartfiles -nostdlib -o ptinterp ptinterp.S $ gcc -m32 -Wl,--dynamic-linker=ptinterp -o hello hello.c $ ./hello Segmentation fault # during execve() itself After applying the patch: $ ./hello Trace trap # user-mode execution after execve() finishes If the ELF headers are actually self-inconsistent, then dying is fine. But having no PROT_WRITE segment is perfectly normal and correct if there is no segment with p_memsz > p_filesz (i.e. bss). John Reiser suggested checking for PROT_WRITE in the bss logic. I think it makes most sense to simply apply the bss logic only when there is bss. This patch looks less trivial than it is due to some reindentation. It just moves the "if (last_bss > elf_bss) {" test up to include the partial-page bss logic as well as the more-pages bss logic. Reported-by: John Reiser Signed-off-by: Roland McGrath Signed-off-by: James Morris diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index b7c1603..7c1e65d 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -501,22 +501,22 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, } } - /* - * Now fill out the bss section. First pad the last page up - * to the page boundary, and then perform a mmap to make sure - * that there are zero-mapped pages up to and including the - * last bss page. - */ - if (padzero(elf_bss)) { - error = -EFAULT; - goto out_close; - } + if (last_bss > elf_bss) { + /* + * Now fill out the bss section. First pad the last page up + * to the page boundary, and then perform a mmap to make sure + * that there are zero-mapped pages up to and including the + * last bss page. + */ + if (padzero(elf_bss)) { + error = -EFAULT; + goto out_close; + } - /* What we have mapped so far */ - elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); + /* What we have mapped so far */ + elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); - /* Map the last of the bss segment */ - if (last_bss > elf_bss) { + /* Map the last of the bss segment */ down_write(¤t->mm->mmap_sem); error = do_brk(elf_bss, last_bss - elf_bss); up_write(¤t->mm->mmap_sem); -- cgit v0.10.2 From 76c36d016a3f958d6231dcdef54a132614c3b578 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 10 Sep 2009 05:55:17 -0700 Subject: sparc64: Provide extern decls for sparc_??u_type strings. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/system_64.h b/arch/sparc/include/asm/system_64.h index 6c07781..25e848f 100644 --- a/arch/sparc/include/asm/system_64.h +++ b/arch/sparc/include/asm/system_64.h @@ -29,6 +29,10 @@ enum sparc_cpu { /* This cannot ever be a sun4c :) That's just history. */ #define ARCH_SUN4C 0 +extern const char *sparc_cpu_type; +extern const char *sparc_fpu_type; +extern const char *sparc_pmu_type; + extern char reboot_command[]; /* These are here in an effort to more fully work around Spitfire Errata -- cgit v0.10.2 From 2d0740c4562493b60f59ca9b0330a2d5e01d43ec Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 10 Sep 2009 05:56:16 -0700 Subject: sparc64: Use nmi_enter() and nmi_exit(), as needed. Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index 47a465f..7de19dd 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c @@ -84,6 +84,7 @@ static void die_nmi(const char *str, struct pt_regs *regs, int do_panic) if (do_panic || panic_on_oops) panic("Non maskable interrupt"); + nmi_exit(); local_irq_enable(); do_exit(SIGBUS); } @@ -98,6 +99,8 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) local_cpu_data().__nmi_count++; + nmi_enter(); + if (notify_die(DIE_NMI, "nmi", regs, 0, pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP) touched = 1; @@ -120,6 +123,8 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) write_pic(picl_value(nmi_hz)); pcr_ops->write(pcr_enable); } + + nmi_exit(); } static inline unsigned int get_nmi_count(int cpu) -- cgit v0.10.2 From 5686f9c3d67d5a20108fa26105c98b042df13123 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 10 Sep 2009 05:59:24 -0700 Subject: sparc64: Implement a real set_perf_counter_pending(). When the perf counter subsystem needs to reschedule work out from an NMI, it invokes set_perf_counter_pending(). This triggers a non-NMI irq which should invoke perf_counter_do_pending(). Currently this won't trigger because sparc64 won't trigger the perf counter subsystem from NMIs, but when the HW counter support is added it will. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/perf_counter.h b/arch/sparc/include/asm/perf_counter.h index f07c587..38d6445 100644 --- a/arch/sparc/include/asm/perf_counter.h +++ b/arch/sparc/include/asm/perf_counter.h @@ -1,7 +1,7 @@ #ifndef __ASM_SPARC_PERF_COUNTER_H #define __ASM_SPARC_PERF_COUNTER_H -static inline void set_perf_counter_pending(void) { } +extern void set_perf_counter_pending(void); #define PERF_COUNTER_INDEX_OFFSET 0 diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c index 1ae8cdd..68ff001 100644 --- a/arch/sparc/kernel/pcr.c +++ b/arch/sparc/kernel/pcr.c @@ -7,6 +7,8 @@ #include #include +#include + #include #include #include @@ -34,10 +36,20 @@ unsigned int picl_shift; */ void deferred_pcr_work_irq(int irq, struct pt_regs *regs) { + struct pt_regs *old_regs; + clear_softint(1 << PIL_DEFERRED_PCR_WORK); + + old_regs = set_irq_regs(regs); + irq_enter(); +#ifdef CONFIG_PERF_COUNTERS + perf_counter_do_pending(); +#endif + irq_exit(); + set_irq_regs(old_regs); } -void schedule_deferred_pcr_work(void) +void set_perf_counter_pending(void) { set_softint(1 << PIL_DEFERRED_PCR_WORK); } -- cgit v0.10.2 From 59abbd1e7cfd6018fb8e58a96aa562aaff8711e7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 10 Sep 2009 06:28:20 -0700 Subject: sparc64: Initial hw perf counter support. Only supports one simple counter and only UltraSPARC-IIIi chips. Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/nmi.h b/arch/sparc/include/asm/nmi.h index c7d11e4..72e6500 100644 --- a/arch/sparc/include/asm/nmi.h +++ b/arch/sparc/include/asm/nmi.h @@ -7,4 +7,7 @@ extern void nmi_adjust_hz(unsigned int new_hz); extern atomic_t nmi_active; +extern void start_nmi_watchdog(void *unused); +extern void stop_nmi_watchdog(void *unused); + #endif /* __NMI_H */ diff --git a/arch/sparc/include/asm/perf_counter.h b/arch/sparc/include/asm/perf_counter.h index 38d6445..5d7a8ca 100644 --- a/arch/sparc/include/asm/perf_counter.h +++ b/arch/sparc/include/asm/perf_counter.h @@ -5,4 +5,10 @@ extern void set_perf_counter_pending(void); #define PERF_COUNTER_INDEX_OFFSET 0 +#ifdef CONFIG_PERF_COUNTERS +extern void init_hw_perf_counters(void); +#else +static inline void init_hw_perf_counters(void) { } +#endif + #endif diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index b004175..f96dc57 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -103,3 +103,6 @@ obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o obj-$(CONFIG_AUDIT) += audit.o audit--$(CONFIG_AUDIT) := compat_audit.o obj-$(CONFIG_COMPAT) += $(audit--y) + +pc--$(CONFIG_PERF_COUNTERS) := perf_counter.o +obj-$(CONFIG_SPARC64) += $(pc--y) diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index 7de19dd..391a6ed 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -156,7 +157,7 @@ static void report_broken_nmi(int cpu, int *prev_nmi_count) atomic_dec(&nmi_active); } -static void stop_nmi_watchdog(void *unused) +void stop_nmi_watchdog(void *unused) { pcr_ops->write(PCR_PIC_PRIV); __get_cpu_var(wd_enabled) = 0; @@ -210,7 +211,7 @@ error: return err; } -static void start_nmi_watchdog(void *unused) +void start_nmi_watchdog(void *unused) { __get_cpu_var(wd_enabled) = 1; atomic_inc(&nmi_active); @@ -263,6 +264,9 @@ int __init nmi_init(void) atomic_set(&nmi_active, -1); } } + if (!err) + init_hw_perf_counters(); + return err; } diff --git a/arch/sparc/kernel/perf_counter.c b/arch/sparc/kernel/perf_counter.c new file mode 100644 index 0000000..f2c7814 --- /dev/null +++ b/arch/sparc/kernel/perf_counter.c @@ -0,0 +1,520 @@ +/* Performance counter support for sparc64. + * + * Copyright (C) 2009 David S. Miller + * + * This code is based almost entirely upon the x86 perf counter + * code, which is: + * + * Copyright (C) 2008 Thomas Gleixner + * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar + * Copyright (C) 2009 Jaswinder Singh Rajput + * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter + * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Sparc64 chips have two performance counters, 32-bits each, with + * overflow interrupts generated on transition from 0xffffffff to 0. + * The counters are accessed in one go using a 64-bit register. + * + * Both counters are controlled using a single control register. The + * only way to stop all sampling is to clear all of the context (user, + * supervisor, hypervisor) sampling enable bits. But these bits apply + * to both counters, thus the two counters can't be enabled/disabled + * individually. + * + * The control register has two event fields, one for each of the two + * counters. It's thus nearly impossible to have one counter going + * while keeping the other one stopped. Therefore it is possible to + * get overflow interrupts for counters not currently "in use" and + * that condition must be checked in the overflow interrupt handler. + * + * So we use a hack, in that we program inactive counters with the + * "sw_count0" and "sw_count1" events. These count how many times + * the instruction "sethi %hi(0xfc000), %g0" is executed. It's an + * unusual way to encode a NOP and therefore will not trigger in + * normal code. + */ + +#define MAX_HWCOUNTERS 2 +#define MAX_PERIOD ((1UL << 32) - 1) + +#define PIC_UPPER_INDEX 0 +#define PIC_LOWER_INDEX 1 + +#define PIC_UPPER_NOP 0x1c +#define PIC_LOWER_NOP 0x14 + +struct cpu_hw_counters { + struct perf_counter *counters[MAX_HWCOUNTERS]; + unsigned long used_mask[BITS_TO_LONGS(MAX_HWCOUNTERS)]; + unsigned long active_mask[BITS_TO_LONGS(MAX_HWCOUNTERS)]; + int enabled; +}; +DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters) = { .enabled = 1, }; + +struct perf_event_map { + u16 encoding; + u8 pic_mask; +#define PIC_NONE 0x00 +#define PIC_UPPER 0x01 +#define PIC_LOWER 0x02 +}; + +struct sparc_pmu { + const struct perf_event_map *(*event_map)(int); + int max_events; + int upper_shift; + int lower_shift; + int event_mask; +}; + +static const struct perf_event_map ultra3i_perfmon_event_map[] = { + [PERF_COUNT_HW_CPU_CYCLES] = { 0x0000, PIC_UPPER | PIC_LOWER }, + [PERF_COUNT_HW_INSTRUCTIONS] = { 0x0001, PIC_UPPER | PIC_LOWER }, + [PERF_COUNT_HW_CACHE_REFERENCES] = { 0x0009, PIC_LOWER }, + [PERF_COUNT_HW_CACHE_MISSES] = { 0x0009, PIC_UPPER }, +}; + +static const struct perf_event_map *ultra3i_event_map(int event) +{ + return &ultra3i_perfmon_event_map[event]; +} + +static const struct sparc_pmu ultra3i_pmu = { + .event_map = ultra3i_event_map, + .max_events = ARRAY_SIZE(ultra3i_perfmon_event_map), + .upper_shift = 11, + .lower_shift = 4, + .event_mask = 0x3f, +}; + +static const struct sparc_pmu *sparc_pmu __read_mostly; + +static u64 event_encoding(u64 event, int idx) +{ + if (idx == PIC_UPPER_INDEX) + event <<= sparc_pmu->upper_shift; + else + event <<= sparc_pmu->lower_shift; + return event; +} + +static u64 mask_for_index(int idx) +{ + return event_encoding(sparc_pmu->event_mask, idx); +} + +static u64 nop_for_index(int idx) +{ + return event_encoding(idx == PIC_UPPER_INDEX ? + PIC_UPPER_NOP : PIC_LOWER_NOP, idx); +} + +static inline void sparc_pmu_enable_counter(struct hw_perf_counter *hwc, + int idx) +{ + u64 val, mask = mask_for_index(idx); + + val = pcr_ops->read(); + pcr_ops->write((val & ~mask) | hwc->config); +} + +static inline void sparc_pmu_disable_counter(struct hw_perf_counter *hwc, + int idx) +{ + u64 mask = mask_for_index(idx); + u64 nop = nop_for_index(idx); + u64 val = pcr_ops->read(); + + pcr_ops->write((val & ~mask) | nop); +} + +void hw_perf_enable(void) +{ + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + u64 val; + int i; + + if (cpuc->enabled) + return; + + cpuc->enabled = 1; + barrier(); + + val = pcr_ops->read(); + + for (i = 0; i < MAX_HWCOUNTERS; i++) { + struct perf_counter *cp = cpuc->counters[i]; + struct hw_perf_counter *hwc; + + if (!cp) + continue; + hwc = &cp->hw; + val |= hwc->config_base; + } + + pcr_ops->write(val); +} + +void hw_perf_disable(void) +{ + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + u64 val; + + if (!cpuc->enabled) + return; + + cpuc->enabled = 0; + + val = pcr_ops->read(); + val &= ~(PCR_UTRACE | PCR_STRACE); + pcr_ops->write(val); +} + +static u32 read_pmc(int idx) +{ + u64 val; + + read_pic(val); + if (idx == PIC_UPPER_INDEX) + val >>= 32; + + return val & 0xffffffff; +} + +static void write_pmc(int idx, u64 val) +{ + u64 shift, mask, pic; + + shift = 0; + if (idx == PIC_UPPER_INDEX) + shift = 32; + + mask = ((u64) 0xffffffff) << shift; + val <<= shift; + + read_pic(pic); + pic &= ~mask; + pic |= val; + write_pic(pic); +} + +static int sparc_perf_counter_set_period(struct perf_counter *counter, + struct hw_perf_counter *hwc, int idx) +{ + s64 left = atomic64_read(&hwc->period_left); + s64 period = hwc->sample_period; + int ret = 0; + + if (unlikely(left <= -period)) { + left = period; + atomic64_set(&hwc->period_left, left); + hwc->last_period = period; + ret = 1; + } + + if (unlikely(left <= 0)) { + left += period; + atomic64_set(&hwc->period_left, left); + hwc->last_period = period; + ret = 1; + } + if (left > MAX_PERIOD) + left = MAX_PERIOD; + + atomic64_set(&hwc->prev_count, (u64)-left); + + write_pmc(idx, (u64)(-left) & 0xffffffff); + + perf_counter_update_userpage(counter); + + return ret; +} + +static int sparc_pmu_enable(struct perf_counter *counter) +{ + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + struct hw_perf_counter *hwc = &counter->hw; + int idx = hwc->idx; + + if (test_and_set_bit(idx, cpuc->used_mask)) + return -EAGAIN; + + sparc_pmu_disable_counter(hwc, idx); + + cpuc->counters[idx] = counter; + set_bit(idx, cpuc->active_mask); + + sparc_perf_counter_set_period(counter, hwc, idx); + sparc_pmu_enable_counter(hwc, idx); + perf_counter_update_userpage(counter); + return 0; +} + +static u64 sparc_perf_counter_update(struct perf_counter *counter, + struct hw_perf_counter *hwc, int idx) +{ + int shift = 64 - 32; + u64 prev_raw_count, new_raw_count; + s64 delta; + +again: + prev_raw_count = atomic64_read(&hwc->prev_count); + new_raw_count = read_pmc(idx); + + if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count) != prev_raw_count) + goto again; + + delta = (new_raw_count << shift) - (prev_raw_count << shift); + delta >>= shift; + + atomic64_add(delta, &counter->count); + atomic64_sub(delta, &hwc->period_left); + + return new_raw_count; +} + +static void sparc_pmu_disable(struct perf_counter *counter) +{ + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + struct hw_perf_counter *hwc = &counter->hw; + int idx = hwc->idx; + + clear_bit(idx, cpuc->active_mask); + sparc_pmu_disable_counter(hwc, idx); + + barrier(); + + sparc_perf_counter_update(counter, hwc, idx); + cpuc->counters[idx] = NULL; + clear_bit(idx, cpuc->used_mask); + + perf_counter_update_userpage(counter); +} + +static void sparc_pmu_read(struct perf_counter *counter) +{ + struct hw_perf_counter *hwc = &counter->hw; + sparc_perf_counter_update(counter, hwc, hwc->idx); +} + +static void sparc_pmu_unthrottle(struct perf_counter *counter) +{ + struct hw_perf_counter *hwc = &counter->hw; + sparc_pmu_enable_counter(hwc, hwc->idx); +} + +static atomic_t active_counters = ATOMIC_INIT(0); +static DEFINE_MUTEX(pmc_grab_mutex); + +void perf_counter_grab_pmc(void) +{ + if (atomic_inc_not_zero(&active_counters)) + return; + + mutex_lock(&pmc_grab_mutex); + if (atomic_read(&active_counters) == 0) { + if (atomic_read(&nmi_active) > 0) { + on_each_cpu(stop_nmi_watchdog, NULL, 1); + BUG_ON(atomic_read(&nmi_active) != 0); + } + atomic_inc(&active_counters); + } + mutex_unlock(&pmc_grab_mutex); +} + +void perf_counter_release_pmc(void) +{ + if (atomic_dec_and_mutex_lock(&active_counters, &pmc_grab_mutex)) { + if (atomic_read(&nmi_active) == 0) + on_each_cpu(start_nmi_watchdog, NULL, 1); + mutex_unlock(&pmc_grab_mutex); + } +} + +static void hw_perf_counter_destroy(struct perf_counter *counter) +{ + perf_counter_release_pmc(); +} + +static int __hw_perf_counter_init(struct perf_counter *counter) +{ + struct perf_counter_attr *attr = &counter->attr; + struct hw_perf_counter *hwc = &counter->hw; + const struct perf_event_map *pmap; + u64 enc; + + if (atomic_read(&nmi_active) < 0) + return -ENODEV; + + if (attr->type != PERF_TYPE_HARDWARE) + return -EOPNOTSUPP; + + if (attr->config >= sparc_pmu->max_events) + return -EINVAL; + + perf_counter_grab_pmc(); + counter->destroy = hw_perf_counter_destroy; + + /* We save the enable bits in the config_base. So to + * turn off sampling just write 'config', and to enable + * things write 'config | config_base'. + */ + hwc->config_base = 0; + if (!attr->exclude_user) + hwc->config_base |= PCR_UTRACE; + if (!attr->exclude_kernel) + hwc->config_base |= PCR_STRACE; + + if (!hwc->sample_period) { + hwc->sample_period = MAX_PERIOD; + hwc->last_period = hwc->sample_period; + atomic64_set(&hwc->period_left, hwc->sample_period); + } + + pmap = sparc_pmu->event_map(attr->config); + + enc = pmap->encoding; + if (pmap->pic_mask & PIC_UPPER) { + hwc->idx = PIC_UPPER_INDEX; + enc <<= sparc_pmu->upper_shift; + } else { + hwc->idx = PIC_LOWER_INDEX; + enc <<= sparc_pmu->lower_shift; + } + + hwc->config |= enc; + return 0; +} + +static const struct pmu pmu = { + .enable = sparc_pmu_enable, + .disable = sparc_pmu_disable, + .read = sparc_pmu_read, + .unthrottle = sparc_pmu_unthrottle, +}; + +const struct pmu *hw_perf_counter_init(struct perf_counter *counter) +{ + int err = __hw_perf_counter_init(counter); + + if (err) + return ERR_PTR(err); + return &pmu; +} + +void perf_counter_print_debug(void) +{ + unsigned long flags; + u64 pcr, pic; + int cpu; + + if (!sparc_pmu) + return; + + local_irq_save(flags); + + cpu = smp_processor_id(); + + pcr = pcr_ops->read(); + read_pic(pic); + + pr_info("\n"); + pr_info("CPU#%d: PCR[%016llx] PIC[%016llx]\n", + cpu, pcr, pic); + + local_irq_restore(flags); +} + +static int __kprobes perf_counter_nmi_handler(struct notifier_block *self, + unsigned long cmd, void *__args) +{ + struct die_args *args = __args; + struct perf_sample_data data; + struct cpu_hw_counters *cpuc; + struct pt_regs *regs; + int idx; + + if (!atomic_read(&active_counters)) + return NOTIFY_DONE; + + switch (cmd) { + case DIE_NMI: + break; + + default: + return NOTIFY_DONE; + } + + regs = args->regs; + + data.regs = regs; + data.addr = 0; + + cpuc = &__get_cpu_var(cpu_hw_counters); + for (idx = 0; idx < MAX_HWCOUNTERS; idx++) { + struct perf_counter *counter = cpuc->counters[idx]; + struct hw_perf_counter *hwc; + u64 val; + + if (!test_bit(idx, cpuc->active_mask)) + continue; + hwc = &counter->hw; + val = sparc_perf_counter_update(counter, hwc, idx); + if (val & (1ULL << 31)) + continue; + + data.period = counter->hw.last_period; + if (!sparc_perf_counter_set_period(counter, hwc, idx)) + continue; + + if (perf_counter_overflow(counter, 1, &data)) + sparc_pmu_disable_counter(hwc, idx); + } + + return NOTIFY_STOP; +} + +static __read_mostly struct notifier_block perf_counter_nmi_notifier = { + .notifier_call = perf_counter_nmi_handler, +}; + +static bool __init supported_pmu(void) +{ + if (!strcmp(sparc_pmu_type, "ultra3i")) { + sparc_pmu = &ultra3i_pmu; + return true; + } + return false; +} + +void __init init_hw_perf_counters(void) +{ + pr_info("Performance counters: "); + + if (!supported_pmu()) { + pr_cont("No support for PMU type '%s'\n", sparc_pmu_type); + return; + } + + pr_cont("Supported PMU type is '%s'\n", sparc_pmu_type); + + /* All sparc64 PMUs currently have 2 counters. But this simple + * driver only supports one active counter at a time. + */ + perf_max_counters = 1; + + register_die_notifier(&perf_counter_nmi_notifier); +} -- cgit v0.10.2 From 91b9286d819b821fd742c0053fe0748818374198 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 10 Sep 2009 07:09:06 -0700 Subject: sparc64: Provide hypervisor tracing bit support for perf counters. A PMU need only specify which bit in the PCR enabled hypervisor tracing in order to enable this. This will be used in Niagara-2 perf counter support. Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/perf_counter.c b/arch/sparc/kernel/perf_counter.c index f2c7814..d86009f 100644 --- a/arch/sparc/kernel/perf_counter.c +++ b/arch/sparc/kernel/perf_counter.c @@ -77,6 +77,7 @@ struct sparc_pmu { int upper_shift; int lower_shift; int event_mask; + int hv_bit; }; static const struct perf_event_map ultra3i_perfmon_event_map[] = { @@ -178,7 +179,7 @@ void hw_perf_disable(void) cpuc->enabled = 0; val = pcr_ops->read(); - val &= ~(PCR_UTRACE | PCR_STRACE); + val &= ~(PCR_UTRACE | PCR_STRACE | sparc_pmu->hv_bit); pcr_ops->write(val); } @@ -377,6 +378,8 @@ static int __hw_perf_counter_init(struct perf_counter *counter) hwc->config_base |= PCR_UTRACE; if (!attr->exclude_kernel) hwc->config_base |= PCR_STRACE; + if (!attr->exclude_hv) + hwc->config_base |= sparc_pmu->hv_bit; if (!hwc->sample_period) { hwc->sample_period = MAX_PERIOD; -- cgit v0.10.2 From 496c07e3b43475124d7f2d77fafbc1f5055abfee Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 10 Sep 2009 07:10:59 -0700 Subject: sparc64: Provide a way to specify a perf counter overflow IRQ enable bit. Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/perf_counter.c b/arch/sparc/kernel/perf_counter.c index d86009f..0cd5487 100644 --- a/arch/sparc/kernel/perf_counter.c +++ b/arch/sparc/kernel/perf_counter.c @@ -78,6 +78,7 @@ struct sparc_pmu { int lower_shift; int event_mask; int hv_bit; + int irq_bit; }; static const struct perf_event_map ultra3i_perfmon_event_map[] = { @@ -179,7 +180,8 @@ void hw_perf_disable(void) cpuc->enabled = 0; val = pcr_ops->read(); - val &= ~(PCR_UTRACE | PCR_STRACE | sparc_pmu->hv_bit); + val &= ~(PCR_UTRACE | PCR_STRACE | + sparc_pmu->hv_bit | sparc_pmu->irq_bit); pcr_ops->write(val); } @@ -373,7 +375,7 @@ static int __hw_perf_counter_init(struct perf_counter *counter) * turn off sampling just write 'config', and to enable * things write 'config | config_base'. */ - hwc->config_base = 0; + hwc->config_base = sparc_pmu->irq_bit; if (!attr->exclude_user) hwc->config_base |= PCR_UTRACE; if (!attr->exclude_kernel) -- cgit v0.10.2 From 660d13765f342ecb6e774fcbc35b64beb0a069da Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 10 Sep 2009 07:13:26 -0700 Subject: sparc64: Perf counter 'nop' event is not constant. On Niagara-2, for example, it's going to be different. So make it something specified in sparc_pmu. Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/perf_counter.c b/arch/sparc/kernel/perf_counter.c index 0cd5487..f3b8ccc 100644 --- a/arch/sparc/kernel/perf_counter.c +++ b/arch/sparc/kernel/perf_counter.c @@ -52,9 +52,6 @@ #define PIC_UPPER_INDEX 0 #define PIC_LOWER_INDEX 1 -#define PIC_UPPER_NOP 0x1c -#define PIC_LOWER_NOP 0x14 - struct cpu_hw_counters { struct perf_counter *counters[MAX_HWCOUNTERS]; unsigned long used_mask[BITS_TO_LONGS(MAX_HWCOUNTERS)]; @@ -79,6 +76,8 @@ struct sparc_pmu { int event_mask; int hv_bit; int irq_bit; + int upper_nop; + int lower_nop; }; static const struct perf_event_map ultra3i_perfmon_event_map[] = { @@ -99,6 +98,8 @@ static const struct sparc_pmu ultra3i_pmu = { .upper_shift = 11, .lower_shift = 4, .event_mask = 0x3f, + .upper_nop = 0x1c, + .lower_nop = 0x14, }; static const struct sparc_pmu *sparc_pmu __read_mostly; @@ -120,7 +121,8 @@ static u64 mask_for_index(int idx) static u64 nop_for_index(int idx) { return event_encoding(idx == PIC_UPPER_INDEX ? - PIC_UPPER_NOP : PIC_LOWER_NOP, idx); + sparc_pmu->upper_nop : + sparc_pmu->lower_nop, idx); } static inline void sparc_pmu_enable_counter(struct hw_perf_counter *hwc, -- cgit v0.10.2 From b73d884756303316ead4cd7dad51236b2a515a1a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 10 Sep 2009 07:22:18 -0700 Subject: sparc64: Initial niagara2 perf counter support. Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/perf_counter.c b/arch/sparc/kernel/perf_counter.c index f3b8ccc..09de4035 100644 --- a/arch/sparc/kernel/perf_counter.c +++ b/arch/sparc/kernel/perf_counter.c @@ -102,6 +102,32 @@ static const struct sparc_pmu ultra3i_pmu = { .lower_nop = 0x14, }; +static const struct perf_event_map niagara2_perfmon_event_map[] = { + [PERF_COUNT_HW_CPU_CYCLES] = { 0x02ff, PIC_UPPER | PIC_LOWER }, + [PERF_COUNT_HW_INSTRUCTIONS] = { 0x02ff, PIC_UPPER | PIC_LOWER }, + [PERF_COUNT_HW_CACHE_REFERENCES] = { 0x0208, PIC_UPPER | PIC_LOWER }, + [PERF_COUNT_HW_CACHE_MISSES] = { 0x0302, PIC_UPPER | PIC_LOWER }, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x0201, PIC_UPPER | PIC_LOWER }, + [PERF_COUNT_HW_BRANCH_MISSES] = { 0x0202, PIC_UPPER | PIC_LOWER }, +}; + +static const struct perf_event_map *niagara2_event_map(int event) +{ + return &niagara2_perfmon_event_map[event]; +} + +static const struct sparc_pmu niagara2_pmu = { + .event_map = niagara2_event_map, + .max_events = ARRAY_SIZE(niagara2_perfmon_event_map), + .upper_shift = 19, + .lower_shift = 6, + .event_mask = 0xfff, + .hv_bit = 0x8, + .irq_bit = 0x03, + .upper_nop = 0x220, + .lower_nop = 0x220, +}; + static const struct sparc_pmu *sparc_pmu __read_mostly; static u64 event_encoding(u64 event, int idx) @@ -504,6 +530,10 @@ static bool __init supported_pmu(void) sparc_pmu = &ultra3i_pmu; return true; } + if (!strcmp(sparc_pmu_type, "niagara2")) { + sparc_pmu = &niagara2_pmu; + return true; + } return false; } -- cgit v0.10.2 From 3f2aa307c4d26b4ed6509d0a79e8254c9e07e921 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 10 Sep 2009 20:34:48 +0200 Subject: sched: Disable NEW_FAIR_SLEEPERS for now Nikos Chantziaras and Jens Axboe reported that turning off NEW_FAIR_SLEEPERS improves desktop interactivity visibly. Nikos described his experiences the following way: " With this setting, I can do "nice -n 19 make -j20" and still have a very smooth desktop and watch a movie at the same time. Various other annoyances (like the "logout/shutdown/restart" dialog of KDE not appearing at all until the background fade-out effect has finished) are also gone. So this seems to be the single most important setting that vastly improves desktop behavior, at least here. " Jens described it the following way, referring to a 10-seconds xmodmap scheduling delay he was trying to debug: " Then I tried switching NO_NEW_FAIR_SLEEPERS on, and then I get: Performance counter stats for 'xmodmap .xmodmap-carl': 9.009137 task-clock-msecs # 0.447 CPUs 18 context-switches # 0.002 M/sec 1 CPU-migrations # 0.000 M/sec 315 page-faults # 0.035 M/sec 0.020167093 seconds time elapsed Woot! " So disable it for now. In perf trace output i can see weird delta timestamps: cc1-9943 [001] 2802.059479616: sched_stat_wait: task: as:9944 wait: 2801938766276 [ns] That nsec field is not supposed to be that large. More digging is needed - but lets turn it off while the real bug is found. Reported-by: Nikos Chantziaras Tested-by: Nikos Chantziaras Reported-by: Jens Axboe Tested-by: Jens Axboe Acked-by: Peter Zijlstra Cc: Mike Galbraith LKML-Reference: <4AA93D34.8040500@arcor.de> Signed-off-by: Ingo Molnar diff --git a/kernel/sched_features.h b/kernel/sched_features.h index 4569bfa..e2dc63a 100644 --- a/kernel/sched_features.h +++ b/kernel/sched_features.h @@ -1,4 +1,4 @@ -SCHED_FEAT(NEW_FAIR_SLEEPERS, 1) +SCHED_FEAT(NEW_FAIR_SLEEPERS, 0) SCHED_FEAT(NORMALIZED_SLEEPER, 0) SCHED_FEAT(ADAPTIVE_GRAN, 1) SCHED_FEAT(WAKEUP_PREEMPT, 1) -- cgit v0.10.2 From 78c86e5e5691fc84d5fbea0cd4ac7147e87b7490 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 10 Sep 2009 10:09:38 -0700 Subject: x86: split __phys_addr out into separate file Split __phys_addr out into its own file so we can disable -fstack-protector in a fine-grained fashion. Also it doesn't have terribly much to do with the rest of ioremap.c. Signed-off-by: Jeremy Fitzhardinge diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 72bb3a2..9b5a9f5 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -1,9 +1,9 @@ obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \ - pat.o pgtable.o gup.o + pat.o pgtable.o physaddr.o gup.o # Make sure __phys_addr has no stackprotector nostackp := $(call cc-option, -fno-stack-protector) -CFLAGS_ioremap.o := $(nostackp) +CFLAGS_physaddr.o := $(nostackp) obj-$(CONFIG_SMP) += tlb.o diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 8a45093..04e1ad6 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -22,77 +22,7 @@ #include #include -static inline int phys_addr_valid(resource_size_t addr) -{ -#ifdef CONFIG_PHYS_ADDR_T_64BIT - return !(addr >> boot_cpu_data.x86_phys_bits); -#else - return 1; -#endif -} - -#ifdef CONFIG_X86_64 - -unsigned long __phys_addr(unsigned long x) -{ - if (x >= __START_KERNEL_map) { - x -= __START_KERNEL_map; - VIRTUAL_BUG_ON(x >= KERNEL_IMAGE_SIZE); - x += phys_base; - } else { - VIRTUAL_BUG_ON(x < PAGE_OFFSET); - x -= PAGE_OFFSET; - VIRTUAL_BUG_ON(!phys_addr_valid(x)); - } - return x; -} -EXPORT_SYMBOL(__phys_addr); - -bool __virt_addr_valid(unsigned long x) -{ - if (x >= __START_KERNEL_map) { - x -= __START_KERNEL_map; - if (x >= KERNEL_IMAGE_SIZE) - return false; - x += phys_base; - } else { - if (x < PAGE_OFFSET) - return false; - x -= PAGE_OFFSET; - if (!phys_addr_valid(x)) - return false; - } - - return pfn_valid(x >> PAGE_SHIFT); -} -EXPORT_SYMBOL(__virt_addr_valid); - -#else - -#ifdef CONFIG_DEBUG_VIRTUAL -unsigned long __phys_addr(unsigned long x) -{ - /* VMALLOC_* aren't constants */ - VIRTUAL_BUG_ON(x < PAGE_OFFSET); - VIRTUAL_BUG_ON(__vmalloc_start_set && is_vmalloc_addr((void *) x)); - return x - PAGE_OFFSET; -} -EXPORT_SYMBOL(__phys_addr); -#endif - -bool __virt_addr_valid(unsigned long x) -{ - if (x < PAGE_OFFSET) - return false; - if (__vmalloc_start_set && is_vmalloc_addr((void *) x)) - return false; - if (x >= FIXADDR_START) - return false; - return pfn_valid((x - PAGE_OFFSET) >> PAGE_SHIFT); -} -EXPORT_SYMBOL(__virt_addr_valid); - -#endif +#include "physaddr.h" int page_is_ram(unsigned long pagenr) { diff --git a/arch/x86/mm/physaddr.c b/arch/x86/mm/physaddr.c new file mode 100644 index 0000000..d2e2735 --- /dev/null +++ b/arch/x86/mm/physaddr.c @@ -0,0 +1,70 @@ +#include +#include +#include + +#include + +#include "physaddr.h" + +#ifdef CONFIG_X86_64 + +unsigned long __phys_addr(unsigned long x) +{ + if (x >= __START_KERNEL_map) { + x -= __START_KERNEL_map; + VIRTUAL_BUG_ON(x >= KERNEL_IMAGE_SIZE); + x += phys_base; + } else { + VIRTUAL_BUG_ON(x < PAGE_OFFSET); + x -= PAGE_OFFSET; + VIRTUAL_BUG_ON(!phys_addr_valid(x)); + } + return x; +} +EXPORT_SYMBOL(__phys_addr); + +bool __virt_addr_valid(unsigned long x) +{ + if (x >= __START_KERNEL_map) { + x -= __START_KERNEL_map; + if (x >= KERNEL_IMAGE_SIZE) + return false; + x += phys_base; + } else { + if (x < PAGE_OFFSET) + return false; + x -= PAGE_OFFSET; + if (!phys_addr_valid(x)) + return false; + } + + return pfn_valid(x >> PAGE_SHIFT); +} +EXPORT_SYMBOL(__virt_addr_valid); + +#else + +#ifdef CONFIG_DEBUG_VIRTUAL +unsigned long __phys_addr(unsigned long x) +{ + /* VMALLOC_* aren't constants */ + VIRTUAL_BUG_ON(x < PAGE_OFFSET); + VIRTUAL_BUG_ON(__vmalloc_start_set && is_vmalloc_addr((void *) x)); + return x - PAGE_OFFSET; +} +EXPORT_SYMBOL(__phys_addr); +#endif + +bool __virt_addr_valid(unsigned long x) +{ + if (x < PAGE_OFFSET) + return false; + if (__vmalloc_start_set && is_vmalloc_addr((void *) x)) + return false; + if (x >= FIXADDR_START) + return false; + return pfn_valid((x - PAGE_OFFSET) >> PAGE_SHIFT); +} +EXPORT_SYMBOL(__virt_addr_valid); + +#endif /* CONFIG_X86_64 */ diff --git a/arch/x86/mm/physaddr.h b/arch/x86/mm/physaddr.h new file mode 100644 index 0000000..a3cd5a0 --- /dev/null +++ b/arch/x86/mm/physaddr.h @@ -0,0 +1,10 @@ +#include + +static inline int phys_addr_valid(resource_size_t addr) +{ +#ifdef CONFIG_PHYS_ADDR_T_64BIT + return !(addr >> boot_cpu_data.x86_phys_bits); +#else + return 1; +#endif +} -- cgit v0.10.2 From e1f8450854d69f0291882804406ea1bab3ca44b4 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 10 Sep 2009 20:52:09 +0200 Subject: sched: Fix sched::sched_stat_wait tracepoint field This weird perf trace output: cc1-9943 [001] 2802.059479616: sched_stat_wait: task: as:9944 wait: 2801938766276 [ns] Is caused by setting one component field of the delta to zero a bit too early. Move it to later. ( Note, this does not affect the NEW_FAIR_SLEEPERS interactivity bug, it's just a reporting bug in essence. ) Acked-by: Peter Zijlstra Cc: Nikos Chantziaras Cc: Jens Axboe Cc: Mike Galbraith LKML-Reference: <4AA93D34.8040500@arcor.de> Signed-off-by: Ingo Molnar diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 26fadb4..aa7f841 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -545,14 +545,13 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se) schedstat_set(se->wait_count, se->wait_count + 1); schedstat_set(se->wait_sum, se->wait_sum + rq_of(cfs_rq)->clock - se->wait_start); - schedstat_set(se->wait_start, 0); - #ifdef CONFIG_SCHEDSTATS if (entity_is_task(se)) { trace_sched_stat_wait(task_of(se), rq_of(cfs_rq)->clock - se->wait_start); } #endif + schedstat_set(se->wait_start, 0); } static inline void -- cgit v0.10.2 From 0d03d59d9b31cd1e33b7e46a80b6fef66244b1f2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 10 Sep 2009 23:13:28 +0200 Subject: md: Fix "strchr" [drivers/md/dm-log-userspace.ko] undefined! Commit b8313b6da7e2e7c7f47d93d8561969a3ff9ba0ea ("dm log: remove incorrect field from userspace table output") added a call to strstr() with a single-character "needle" string parameter. Unfortunately some versions of gcc replace such calls to strstr() by calls to strchr() behind our back. This causes linking errors if strchr() is defined as an inline function in (e.g. on m68k): | WARNING: "strchr" [drivers/md/dm-log-userspace.ko] undefined! Avoid this by explicitly calling strchr() instead. Signed-off-by: Geert Uytterhoeven Cc: stable@kernel.org Signed-off-by: Linus Torvalds diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index 6e186b1..652bd33 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c @@ -582,7 +582,7 @@ static int userspace_status(struct dm_dirty_log *log, status_type_t status_type, break; case STATUSTYPE_TABLE: sz = 0; - table_args = strstr(lc->usr_argv_str, " "); + table_args = strchr(lc->usr_argv_str, ' '); BUG_ON(!table_args); /* There will always be a ' ' */ table_args++; -- cgit v0.10.2 From 5367b6887e7d8c870a5da7d9b8c6e9c207684e43 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 10 Sep 2009 02:53:50 +0100 Subject: x86: Fix code patching for paravirt-alternatives on 486 As reported in and , kernels with paravirt-alternatives enabled crash in text_poke_early() on at least some 486-class processors. The problem is that text_poke_early() itself uses inline functions affected by paravirt-alternatives and so will modify instructions that have already been prefetched. Pentium and later processors will invalidate the prefetched instructions in this case, but 486-class processors do not. Change sync_core() to limit prefetching on 486-class (and 386-class) processors, and move the call to sync_core() above the call to the modifiable local_irq_restore(). Signed-off-by: Ben Hutchings LKML-Reference: <1252547631.3423.134.camel@localhost> Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index c776826..2db56c5 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -703,13 +703,23 @@ static inline void cpu_relax(void) rep_nop(); } -/* Stop speculative execution: */ +/* Stop speculative execution and prefetching of modified code. */ static inline void sync_core(void) { int tmp; - asm volatile("cpuid" : "=a" (tmp) : "0" (1) - : "ebx", "ecx", "edx", "memory"); +#if defined(CONFIG_M386) || defined(CONFIG_M486) + if (boot_cpu_data.x86 < 5) + /* There is no speculative execution. + * jmp is a barrier to prefetching. */ + asm volatile("jmp 1f\n1:\n" ::: "memory"); + else +#endif + /* cpuid is a barrier to speculative execution. + * Prefetched instructions are automatically + * invalidated when modified. */ + asm volatile("cpuid" : "=a" (tmp) : "0" (1) + : "ebx", "ecx", "edx", "memory"); } static inline void __monitor(const void *eax, unsigned long ecx, diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index f576587..b8ebd0b 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -490,8 +490,8 @@ void *text_poke_early(void *addr, const void *opcode, size_t len) unsigned long flags; local_irq_save(flags); memcpy(addr, opcode, len); - local_irq_restore(flags); sync_core(); + local_irq_restore(flags); /* Could also do a CLFLUSH here to speed up CPU recovery; but that causes hangs on some VIA CPUs. */ return addr; -- cgit v0.10.2 From 041b5eac254107cd3ba60034c38a411531cc64ee Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 6 Aug 2009 16:05:08 -0700 Subject: drivers/ata: use resource_size Use the function resource_size, which reduces the chance of introducing off-by-one errors in calculating the resource size. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ struct resource *res; @@ - (res->end - res->start) + 1 + resource_size(res) // Signed-off-by: Julia Lawall Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index e807cc3..d6f6956 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -841,7 +841,7 @@ static int __devinit octeon_cf_probe(struct platform_device *pdev) ocd = pdev->dev.platform_data; cs0 = devm_ioremap_nocache(&pdev->dev, res_cs0->start, - res_cs0->end - res_cs0->start + 1); + resource_size(res_cs0)); if (!cs0) return -ENOMEM; diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index d8d743a..3f6ebc6 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -151,14 +151,14 @@ int __devinit __pata_platform_probe(struct device *dev, */ if (mmio) { ap->ioaddr.cmd_addr = devm_ioremap(dev, io_res->start, - io_res->end - io_res->start + 1); + resource_size(io_res)); ap->ioaddr.ctl_addr = devm_ioremap(dev, ctl_res->start, - ctl_res->end - ctl_res->start + 1); + resource_size(ctl_res)); } else { ap->ioaddr.cmd_addr = devm_ioport_map(dev, io_res->start, - io_res->end - io_res->start + 1); + resource_size(io_res)); ap->ioaddr.ctl_addr = devm_ioport_map(dev, ctl_res->start, - ctl_res->end - ctl_res->start + 1); + resource_size(ctl_res)); } if (!ap->ioaddr.cmd_addr || !ap->ioaddr.ctl_addr) { dev_err(dev, "failed to map IO/CTL base\n"); diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c index 8e3cdef..45f1e10 100644 --- a/drivers/ata/pata_rb532_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -151,7 +151,7 @@ static __devinit int rb532_pata_driver_probe(struct platform_device *pdev) info->irq = irq; info->iobase = devm_ioremap_nocache(&pdev->dev, res->start, - res->end - res->start + 1); + resource_size(res)); if (!info->iobase) return -ENOMEM; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index c19417e..17f9ff9 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4013,7 +4013,7 @@ static int mv_platform_probe(struct platform_device *pdev) host->iomap = NULL; hpriv->base = devm_ioremap(&pdev->dev, res->start, - res->end - res->start + 1); + resource_size(res)); hpriv->base -= SATAHC0_REG_BASE; /* -- cgit v0.10.2 From e2dd90b1ad4c61ecb52f2424049d91ce6ccc1f17 Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Wed, 29 Jul 2009 11:34:49 +0800 Subject: ahci: Add AMD SB900 SATA/IDE controller device IDs Add AMD SB900 SATA/IDE controller device IDs. Signed-off-by: Shane Huang Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index a4e4cf1..5fb9c3a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -553,6 +553,12 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */ { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */ + /* AMD */ + { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD SB900 */ + /* AMD is using RAID class only for ahci controllers */ + { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci }, + /* VIA */ { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */ diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 4591556..aa4b3f6 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -246,6 +246,7 @@ static const struct pci_device_id atiixp[] = { { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), }, { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), }, { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_SB900_IDE), }, { }, }; diff --git a/drivers/ide/atiixp.c b/drivers/ide/atiixp.c index 923cbfe..6396c3a 100644 --- a/drivers/ide/atiixp.c +++ b/drivers/ide/atiixp.c @@ -177,6 +177,7 @@ static const struct pci_device_id atiixp_pci_tbl[] = { { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), 0 }, { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), 1 }, { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), 0 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_SB900_IDE), 0 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 06b9656..85ce239 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -992,7 +992,7 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, static void __devinit quirk_amd_ide_mode(struct pci_dev *pdev) { - /* set sb600/sb700/sb800 sata to ahci mode */ + /* set SBX00 SATA in IDE mode to AHCI mode */ u8 tmp; pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &tmp); @@ -1011,6 +1011,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_amd_ide_mode); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SB900_SATA_IDE, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SB900_SATA_IDE, quirk_amd_ide_mode); /* * Serverworks CSB5 IDE does not fully support native mode diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 73b46b6..900f40b 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -376,6 +376,9 @@ #define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c #define PCI_DEVICE_ID_ATI_IXP700_SATA 0x4390 #define PCI_DEVICE_ID_ATI_IXP700_IDE 0x439c +/* AMD SB Chipset */ +#define PCI_DEVICE_ID_AMD_SB900_IDE 0x780c +#define PCI_DEVICE_ID_AMD_SB900_SATA_IDE 0x7800 #define PCI_VENDOR_ID_VLSI 0x1004 #define PCI_DEVICE_ID_VLSI_82C592 0x0005 -- cgit v0.10.2 From 02cb009bb942007b76c38da4cc2ca0a0a974c667 Mon Sep 17 00:00:00 2001 From: Otavio Salvador Date: Fri, 3 Jul 2009 11:22:42 -0300 Subject: pata_cs5535: add pci id for AMD based CS5535 controllers Signed-off-by: Otavio Salvador Signed-off-by: Jeff Garzik diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index d33aa28..403f561 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -202,7 +202,8 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id) } static const struct pci_device_id cs5535[] = { - { PCI_VDEVICE(NS, 0x002D), }, + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_CS5535_IDE), }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5535_IDE), }, { }, }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 900f40b..c8fdcad 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -540,6 +540,7 @@ #define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450 #define PCI_DEVICE_ID_AMD_8131_APIC 0x7451 #define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458 +#define PCI_DEVICE_ID_AMD_CS5535_IDE 0x208F #define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090 #define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091 #define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093 -- cgit v0.10.2 From 78d5ae39af19a02a3d16213c0f62930d9a5d25f7 Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Fri, 7 Aug 2009 15:05:52 +0800 Subject: ahci: kill @force_restart and refine CLO for ahci_kick_engine() This patch refines ahci_kick_engine() after discussion with Tejun about FBS(FIS-based switching) support preparation: a. Kill @force_restart and always kick the engine. The only case where @force_restart is zero is when it's called from ahci_p5wdh_hardreset() Actually at that point, BSY is pretty much guaranteed to be set. b. If PMP is attached, ignore busy and always do CLO. (AHCI-1.3 9.2) Signed-off-by: Shane Huang Acked-by: Tejun Heo Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 5fb9c3a..d4cd9c2 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1634,7 +1634,7 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); } -static int ahci_kick_engine(struct ata_port *ap, int force_restart) +static int ahci_kick_engine(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); struct ahci_host_priv *hpriv = ap->host->private_data; @@ -1642,18 +1642,16 @@ static int ahci_kick_engine(struct ata_port *ap, int force_restart) u32 tmp; int busy, rc; - /* do we need to kick the port? */ - busy = status & (ATA_BUSY | ATA_DRQ); - if (!busy && !force_restart) - return 0; - /* stop engine */ rc = ahci_stop_engine(ap); if (rc) goto out_restart; - /* need to do CLO? */ - if (!busy) { + /* need to do CLO? + * always do CLO if PMP is attached (AHCI-1.3 9.2) + */ + busy = status & (ATA_BUSY | ATA_DRQ); + if (!busy && !sata_pmp_attached(ap)) { rc = 0; goto out_restart; } @@ -1701,7 +1699,7 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, timeout_msec); if (tmp & 0x1) { - ahci_kick_engine(ap, 1); + ahci_kick_engine(ap); return -EBUSY; } } else @@ -1724,7 +1722,7 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, DPRINTK("ENTER\n"); /* prepare for SRST (AHCI-1.1 10.4.1) */ - rc = ahci_kick_engine(ap, 1); + rc = ahci_kick_engine(ap); if (rc && rc != -EOPNOTSUPP) ata_link_printk(link, KERN_WARNING, "failed to reset engine (errno=%d)\n", rc); @@ -1940,7 +1938,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, rc = ata_wait_after_reset(link, jiffies + 2 * HZ, ahci_check_ready); if (rc) - ahci_kick_engine(ap, 0); + ahci_kick_engine(ap); } return rc; } @@ -2321,7 +2319,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) /* make DMA engine forget about the failed command */ if (qc->flags & ATA_QCFLAG_FAILED) - ahci_kick_engine(ap, 1); + ahci_kick_engine(ap); } static void ahci_pmp_attach(struct ata_port *ap) -- cgit v0.10.2 From c984123c7a888731b7e971e1c878b6f2b716b292 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 23 Aug 2009 20:23:34 +0200 Subject: pata_rz1000: use printk_once Signed-off-by: Marcin Slusarz Signed-off-by: Jeff Garzik diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 0c574c0..a5e4dfe 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -85,7 +85,6 @@ static int rz1000_fifo_disable(struct pci_dev *pdev) static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - static int printed_version; static const struct ata_port_info info = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -93,8 +92,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en }; const struct ata_port_info *ppi[] = { &info, NULL }; - if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + printk_once(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); if (rz1000_fifo_disable(pdev) == 0) return ata_pci_sff_init_one(pdev, ppi, &rz1000_sht, NULL); -- cgit v0.10.2 From d8a8559cd7a9ccac98d5f6f13297a2ff68a43627 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 2 Sep 2009 12:34:32 +0200 Subject: writeback: get rid of generic_sync_sb_inodes() export This adds two new exported functions: - writeback_inodes_sb(), which only attempts to writeback dirty inodes on this super_block, for WB_SYNC_NONE writeout. - sync_inodes_sb(), which writes out all dirty inodes on this super_block and also waits for the IO to complete. Acked-by: Jan Kara Signed-off-by: Jens Axboe diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index 7b60579..e63c9be 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -1950,14 +1950,7 @@ static int pohmelfs_get_sb(struct file_system_type *fs_type, */ static void pohmelfs_kill_super(struct super_block *sb) { - struct writeback_control wbc = { - .sync_mode = WB_SYNC_ALL, - .range_start = 0, - .range_end = LLONG_MAX, - .nr_to_write = LONG_MAX, - }; - generic_sync_sb_inodes(sb, &wbc); - + sync_inodes_sb(sb); kill_anon_super(sb); } diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index c54226b..271e5f4 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -458,8 +458,8 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) * on the writer throttling path, and we get decent balancing between many * throttled threads: we don't want them all piling up on inode_sync_wait. */ -void generic_sync_sb_inodes(struct super_block *sb, - struct writeback_control *wbc) +static void generic_sync_sb_inodes(struct super_block *sb, + struct writeback_control *wbc) { const unsigned long start = jiffies; /* livelock avoidance */ int sync = wbc->sync_mode == WB_SYNC_ALL; @@ -593,13 +593,6 @@ void generic_sync_sb_inodes(struct super_block *sb, return; /* Leave any unwritten inodes on s_io */ } -EXPORT_SYMBOL_GPL(generic_sync_sb_inodes); - -static void sync_sb_inodes(struct super_block *sb, - struct writeback_control *wbc) -{ - generic_sync_sb_inodes(sb, wbc); -} /* * Start writeback of dirty pagecache data against all unlocked inodes. @@ -640,7 +633,7 @@ restart: */ if (down_read_trylock(&sb->s_umount)) { if (sb->s_root) - sync_sb_inodes(sb, wbc); + generic_sync_sb_inodes(sb, wbc); up_read(&sb->s_umount); } spin_lock(&sb_lock); @@ -653,35 +646,56 @@ restart: spin_unlock(&sb_lock); } -/* - * writeback and wait upon the filesystem's dirty inodes. The caller will - * do this in two passes - one to write, and one to wait. - * - * A finite limit is set on the number of pages which will be written. - * To prevent infinite livelock of sys_sync(). +/** + * writeback_inodes_sb - writeback dirty inodes from given super_block + * @sb: the superblock * - * We add in the number of potentially dirty inodes, because each inode write - * can dirty pagecache in the underlying blockdev. + * Start writeback on some inodes on this super_block. No guarantees are made + * on how many (if any) will be written, and this function does not wait + * for IO completion of submitted IO. The number of pages submitted is + * returned. */ -void sync_inodes_sb(struct super_block *sb, int wait) +long writeback_inodes_sb(struct super_block *sb) { struct writeback_control wbc = { - .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_NONE, + .sync_mode = WB_SYNC_NONE, .range_start = 0, .range_end = LLONG_MAX, }; + unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); + unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); + long nr_to_write; - if (!wait) { - unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); - unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); - - wbc.nr_to_write = nr_dirty + nr_unstable + + nr_to_write = nr_dirty + nr_unstable + (inodes_stat.nr_inodes - inodes_stat.nr_unused); - } else - wbc.nr_to_write = LONG_MAX; /* doesn't actually matter */ - sync_sb_inodes(sb, &wbc); + wbc.nr_to_write = nr_to_write; + generic_sync_sb_inodes(sb, &wbc); + return nr_to_write - wbc.nr_to_write; +} +EXPORT_SYMBOL(writeback_inodes_sb); + +/** + * sync_inodes_sb - sync sb inode pages + * @sb: the superblock + * + * This function writes and waits on any dirty inode belonging to this + * super_block. The number of pages synced is returned. + */ +long sync_inodes_sb(struct super_block *sb) +{ + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .range_start = 0, + .range_end = LLONG_MAX, + }; + long nr_to_write = LONG_MAX; /* doesn't actually matter */ + + wbc.nr_to_write = nr_to_write; + generic_sync_sb_inodes(sb, &wbc); + return nr_to_write - wbc.nr_to_write; } +EXPORT_SYMBOL(sync_inodes_sb); /** * write_inode_now - write an inode to disk diff --git a/fs/sync.c b/fs/sync.c index 3422ba6..66f2104 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -19,20 +19,22 @@ SYNC_FILE_RANGE_WAIT_AFTER) /* - * Do the filesystem syncing work. For simple filesystems sync_inodes_sb(sb, 0) - * just dirties buffers with inodes so we have to submit IO for these buffers - * via __sync_blockdev(). This also speeds up the wait == 1 case since in that - * case write_inode() functions do sync_dirty_buffer() and thus effectively - * write one block at a time. + * Do the filesystem syncing work. For simple filesystems + * writeback_inodes_sb(sb) just dirties buffers with inodes so we have to + * submit IO for these buffers via __sync_blockdev(). This also speeds up the + * wait == 1 case since in that case write_inode() functions do + * sync_dirty_buffer() and thus effectively write one block at a time. */ static int __sync_filesystem(struct super_block *sb, int wait) { /* Avoid doing twice syncing and cache pruning for quota sync */ - if (!wait) + if (!wait) { writeout_quota_sb(sb, -1); - else + writeback_inodes_sb(sb); + } else { sync_quota_sb(sb, -1); - sync_inodes_sb(sb, wait); + sync_inodes_sb(sb); + } if (sb->s_op->sync_fs) sb->s_op->sync_fs(sb, wait); return __sync_blockdev(sb->s_bdev, wait); diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c index eaf6d89..1c8991b 100644 --- a/fs/ubifs/budget.c +++ b/fs/ubifs/budget.c @@ -65,26 +65,14 @@ static int shrink_liability(struct ubifs_info *c, int nr_to_write) { int nr_written; - struct writeback_control wbc = { - .sync_mode = WB_SYNC_NONE, - .range_end = LLONG_MAX, - .nr_to_write = nr_to_write, - }; - - generic_sync_sb_inodes(c->vfs_sb, &wbc); - nr_written = nr_to_write - wbc.nr_to_write; + nr_written = writeback_inodes_sb(c->vfs_sb); if (!nr_written) { /* * Re-try again but wait on pages/inodes which are being * written-back concurrently (e.g., by pdflush). */ - memset(&wbc, 0, sizeof(struct writeback_control)); - wbc.sync_mode = WB_SYNC_ALL; - wbc.range_end = LLONG_MAX; - wbc.nr_to_write = nr_to_write; - generic_sync_sb_inodes(c->vfs_sb, &wbc); - nr_written = nr_to_write - wbc.nr_to_write; + nr_written = sync_inodes_sb(c->vfs_sb); } dbg_budg("%d pages were written back", nr_written); diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 26d2e0d..8d6050a 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -438,12 +438,6 @@ static int ubifs_sync_fs(struct super_block *sb, int wait) { int i, err; struct ubifs_info *c = sb->s_fs_info; - struct writeback_control wbc = { - .sync_mode = WB_SYNC_ALL, - .range_start = 0, - .range_end = LLONG_MAX, - .nr_to_write = LONG_MAX, - }; /* * Zero @wait is just an advisory thing to help the file system shove @@ -462,7 +456,7 @@ static int ubifs_sync_fs(struct super_block *sb, int wait) * the user be able to get more accurate results of 'statfs()' after * they synchronize the file system. */ - generic_sync_sb_inodes(sb, &wbc); + sync_inodes_sb(sb); /* * Synchronize write buffers, because 'ubifs_run_commit()' does not diff --git a/include/linux/fs.h b/include/linux/fs.h index c1f9935..46ff7dd 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2071,8 +2071,6 @@ static inline void invalidate_remote_inode(struct inode *inode) extern int invalidate_inode_pages2(struct address_space *mapping); extern int invalidate_inode_pages2_range(struct address_space *mapping, pgoff_t start, pgoff_t end); -extern void generic_sync_sb_inodes(struct super_block *sb, - struct writeback_control *wbc); extern int write_inode_now(struct inode *, int); extern int filemap_fdatawrite(struct address_space *); extern int filemap_flush(struct address_space *); diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 3224820..0703929 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -78,7 +78,8 @@ struct writeback_control { */ void writeback_inodes(struct writeback_control *wbc); int inode_wait(void *); -void sync_inodes_sb(struct super_block *, int wait); +long writeback_inodes_sb(struct super_block *); +long sync_inodes_sb(struct super_block *); /* writeback.h requires fs.h; it, too, is not included from here. */ static inline void wait_on_inode(struct inode *inode) -- cgit v0.10.2 From 66f3b8e2e103a0b93b945764d98e9ba46cb926dd Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 2 Sep 2009 09:19:46 +0200 Subject: writeback: move dirty inodes from super_block to backing_dev_info This is a first step at introducing per-bdi flusher threads. We should have no change in behaviour, although sb_has_dirty_inodes() is now ridiculously expensive, as there's no easy way to answer that question. Not a huge problem, since it'll be deleted in subsequent patches. Signed-off-by: Jens Axboe diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 271e5f4..45ad4bb 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -25,6 +25,7 @@ #include #include "internal.h" +#define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info) /** * writeback_acquire - attempt to get exclusive writeback access to a device @@ -165,12 +166,13 @@ void __mark_inode_dirty(struct inode *inode, int flags) goto out; /* - * If the inode was already on s_dirty/s_io/s_more_io, don't - * reposition it (that would break s_dirty time-ordering). + * If the inode was already on b_dirty/b_io/b_more_io, don't + * reposition it (that would break b_dirty time-ordering). */ if (!was_dirty) { inode->dirtied_when = jiffies; - list_move(&inode->i_list, &sb->s_dirty); + list_move(&inode->i_list, + &inode_to_bdi(inode)->b_dirty); } } out: @@ -191,31 +193,30 @@ static int write_inode(struct inode *inode, int sync) * furthest end of its superblock's dirty-inode list. * * Before stamping the inode's ->dirtied_when, we check to see whether it is - * already the most-recently-dirtied inode on the s_dirty list. If that is + * already the most-recently-dirtied inode on the b_dirty list. If that is * the case then the inode must have been redirtied while it was being written * out and we don't reset its dirtied_when. */ static void redirty_tail(struct inode *inode) { - struct super_block *sb = inode->i_sb; + struct backing_dev_info *bdi = inode_to_bdi(inode); - if (!list_empty(&sb->s_dirty)) { - struct inode *tail_inode; + if (!list_empty(&bdi->b_dirty)) { + struct inode *tail; - tail_inode = list_entry(sb->s_dirty.next, struct inode, i_list); - if (time_before(inode->dirtied_when, - tail_inode->dirtied_when)) + tail = list_entry(bdi->b_dirty.next, struct inode, i_list); + if (time_before(inode->dirtied_when, tail->dirtied_when)) inode->dirtied_when = jiffies; } - list_move(&inode->i_list, &sb->s_dirty); + list_move(&inode->i_list, &bdi->b_dirty); } /* - * requeue inode for re-scanning after sb->s_io list is exhausted. + * requeue inode for re-scanning after bdi->b_io list is exhausted. */ static void requeue_io(struct inode *inode) { - list_move(&inode->i_list, &inode->i_sb->s_more_io); + list_move(&inode->i_list, &inode_to_bdi(inode)->b_more_io); } static void inode_sync_complete(struct inode *inode) @@ -262,18 +263,50 @@ static void move_expired_inodes(struct list_head *delaying_queue, /* * Queue all expired dirty inodes for io, eldest first. */ -static void queue_io(struct super_block *sb, - unsigned long *older_than_this) +static void queue_io(struct backing_dev_info *bdi, + unsigned long *older_than_this) +{ + list_splice_init(&bdi->b_more_io, bdi->b_io.prev); + move_expired_inodes(&bdi->b_dirty, &bdi->b_io, older_than_this); +} + +static int sb_on_inode_list(struct super_block *sb, struct list_head *list) { - list_splice_init(&sb->s_more_io, sb->s_io.prev); - move_expired_inodes(&sb->s_dirty, &sb->s_io, older_than_this); + struct inode *inode; + int ret = 0; + + spin_lock(&inode_lock); + list_for_each_entry(inode, list, i_list) { + if (inode->i_sb == sb) { + ret = 1; + break; + } + } + spin_unlock(&inode_lock); + return ret; } int sb_has_dirty_inodes(struct super_block *sb) { - return !list_empty(&sb->s_dirty) || - !list_empty(&sb->s_io) || - !list_empty(&sb->s_more_io); + struct backing_dev_info *bdi; + int ret = 0; + + /* + * This is REALLY expensive right now, but it'll go away + * when the bdi writeback is introduced + */ + mutex_lock(&bdi_lock); + list_for_each_entry(bdi, &bdi_list, bdi_list) { + if (sb_on_inode_list(sb, &bdi->b_dirty) || + sb_on_inode_list(sb, &bdi->b_io) || + sb_on_inode_list(sb, &bdi->b_more_io)) { + ret = 1; + break; + } + } + mutex_unlock(&bdi_lock); + + return ret; } EXPORT_SYMBOL(sb_has_dirty_inodes); @@ -322,11 +355,11 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) if (inode->i_state & I_SYNC) { /* * If this inode is locked for writeback and we are not doing - * writeback-for-data-integrity, move it to s_more_io so that + * writeback-for-data-integrity, move it to b_more_io so that * writeback can proceed with the other inodes on s_io. * * We'll have another go at writing back this inode when we - * completed a full scan of s_io. + * completed a full scan of b_io. */ if (!wait) { requeue_io(inode); @@ -371,11 +404,11 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) /* * We didn't write back all the pages. nfs_writepages() * sometimes bales out without doing anything. Redirty - * the inode; Move it from s_io onto s_more_io/s_dirty. + * the inode; Move it from b_io onto b_more_io/b_dirty. */ /* * akpm: if the caller was the kupdate function we put - * this inode at the head of s_dirty so it gets first + * this inode at the head of b_dirty so it gets first * consideration. Otherwise, move it to the tail, for * the reasons described there. I'm not really sure * how much sense this makes. Presumably I had a good @@ -385,7 +418,7 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) if (wbc->for_kupdate) { /* * For the kupdate function we move the inode - * to s_more_io so it will get more writeout as + * to b_more_io so it will get more writeout as * soon as the queue becomes uncongested. */ inode->i_state |= I_DIRTY_PAGES; @@ -433,51 +466,34 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) return ret; } -/* - * Write out a superblock's list of dirty inodes. A wait will be performed - * upon no inodes, all inodes or the final one, depending upon sync_mode. - * - * If older_than_this is non-NULL, then only write out inodes which - * had their first dirtying at a time earlier than *older_than_this. - * - * If we're a pdflush thread, then implement pdflush collision avoidance - * against the entire list. - * - * If `bdi' is non-zero then we're being asked to writeback a specific queue. - * This function assumes that the blockdev superblock's inodes are backed by - * a variety of queues, so all inodes are searched. For other superblocks, - * assume that all inodes are backed by the same queue. - * - * FIXME: this linear search could get expensive with many fileystems. But - * how to fix? We need to go from an address_space to all inodes which share - * a queue with that address_space. (Easy: have a global "dirty superblocks" - * list). - * - * The inodes to be written are parked on sb->s_io. They are moved back onto - * sb->s_dirty as they are selected for writing. This way, none can be missed - * on the writer throttling path, and we get decent balancing between many - * throttled threads: we don't want them all piling up on inode_sync_wait. - */ -static void generic_sync_sb_inodes(struct super_block *sb, - struct writeback_control *wbc) +static void generic_sync_bdi_inodes(struct backing_dev_info *bdi, + struct writeback_control *wbc, + struct super_block *sb) { + const int is_blkdev_sb = sb_is_blkdev_sb(sb); const unsigned long start = jiffies; /* livelock avoidance */ - int sync = wbc->sync_mode == WB_SYNC_ALL; spin_lock(&inode_lock); - if (!wbc->for_kupdate || list_empty(&sb->s_io)) - queue_io(sb, wbc->older_than_this); - while (!list_empty(&sb->s_io)) { - struct inode *inode = list_entry(sb->s_io.prev, + if (!wbc->for_kupdate || list_empty(&bdi->b_io)) + queue_io(bdi, wbc->older_than_this); + + while (!list_empty(&bdi->b_io)) { + struct inode *inode = list_entry(bdi->b_io.prev, struct inode, i_list); - struct address_space *mapping = inode->i_mapping; - struct backing_dev_info *bdi = mapping->backing_dev_info; long pages_skipped; + /* + * super block given and doesn't match, skip this inode + */ + if (sb && sb != inode->i_sb) { + redirty_tail(inode); + continue; + } + if (!bdi_cap_writeback_dirty(bdi)) { redirty_tail(inode); - if (sb_is_blkdev_sb(sb)) { + if (is_blkdev_sb) { /* * Dirty memory-backed blockdev: the ramdisk * driver does this. Skip just this inode @@ -499,14 +515,14 @@ static void generic_sync_sb_inodes(struct super_block *sb, if (wbc->nonblocking && bdi_write_congested(bdi)) { wbc->encountered_congestion = 1; - if (!sb_is_blkdev_sb(sb)) + if (!is_blkdev_sb) break; /* Skip a congested fs */ requeue_io(inode); continue; /* Skip a congested blockdev */ } if (wbc->bdi && bdi != wbc->bdi) { - if (!sb_is_blkdev_sb(sb)) + if (!is_blkdev_sb) break; /* fs has the wrong queue */ requeue_io(inode); continue; /* blockdev has wrong queue */ @@ -544,13 +560,57 @@ static void generic_sync_sb_inodes(struct super_block *sb, wbc->more_io = 1; break; } - if (!list_empty(&sb->s_more_io)) + if (!list_empty(&bdi->b_more_io)) wbc->more_io = 1; } - if (sync) { + spin_unlock(&inode_lock); + /* Leave any unwritten inodes on b_io */ +} + +/* + * Write out a superblock's list of dirty inodes. A wait will be performed + * upon no inodes, all inodes or the final one, depending upon sync_mode. + * + * If older_than_this is non-NULL, then only write out inodes which + * had their first dirtying at a time earlier than *older_than_this. + * + * If we're a pdlfush thread, then implement pdflush collision avoidance + * against the entire list. + * + * If `bdi' is non-zero then we're being asked to writeback a specific queue. + * This function assumes that the blockdev superblock's inodes are backed by + * a variety of queues, so all inodes are searched. For other superblocks, + * assume that all inodes are backed by the same queue. + * + * FIXME: this linear search could get expensive with many fileystems. But + * how to fix? We need to go from an address_space to all inodes which share + * a queue with that address_space. (Easy: have a global "dirty superblocks" + * list). + * + * The inodes to be written are parked on bdi->b_io. They are moved back onto + * bdi->b_dirty as they are selected for writing. This way, none can be missed + * on the writer throttling path, and we get decent balancing between many + * throttled threads: we don't want them all piling up on inode_sync_wait. + */ +static void generic_sync_sb_inodes(struct super_block *sb, + struct writeback_control *wbc) +{ + struct backing_dev_info *bdi; + + if (!wbc->bdi) { + mutex_lock(&bdi_lock); + list_for_each_entry(bdi, &bdi_list, bdi_list) + generic_sync_bdi_inodes(bdi, wbc, sb); + mutex_unlock(&bdi_lock); + } else + generic_sync_bdi_inodes(wbc->bdi, wbc, sb); + + if (wbc->sync_mode == WB_SYNC_ALL) { struct inode *inode, *old_inode = NULL; + spin_lock(&inode_lock); + /* * Data integrity sync. Must wait for all pages under writeback, * because there may have been pages dirtied before our sync @@ -588,10 +648,7 @@ static void generic_sync_sb_inodes(struct super_block *sb, } spin_unlock(&inode_lock); iput(old_inode); - } else - spin_unlock(&inode_lock); - - return; /* Leave any unwritten inodes on s_io */ + } } /* @@ -599,8 +656,8 @@ static void generic_sync_sb_inodes(struct super_block *sb, * * Note: * We don't need to grab a reference to superblock here. If it has non-empty - * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed - * past sync_inodes_sb() until the ->s_dirty/s_io/s_more_io lists are all + * ->b_dirty it's hadn't been killed yet and kill_super() won't proceed + * past sync_inodes_sb() until the ->b_dirty/b_io/b_more_io lists are all * empty. Since __sync_single_inode() regains inode_lock before it finally moves * inode from superblock lists we are OK. * diff --git a/fs/super.c b/fs/super.c index 2761d3e..0d22ce3 100644 --- a/fs/super.c +++ b/fs/super.c @@ -62,9 +62,6 @@ static struct super_block *alloc_super(struct file_system_type *type) s = NULL; goto out; } - INIT_LIST_HEAD(&s->s_dirty); - INIT_LIST_HEAD(&s->s_io); - INIT_LIST_HEAD(&s->s_more_io); INIT_LIST_HEAD(&s->s_files); INIT_LIST_HEAD(&s->s_instances); INIT_HLIST_HEAD(&s->s_anon); diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 1d52425..928cd54 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -40,6 +40,8 @@ enum bdi_stat_item { #define BDI_STAT_BATCH (8*(1+ilog2(nr_cpu_ids))) struct backing_dev_info { + struct list_head bdi_list; + unsigned long ra_pages; /* max readahead in PAGE_CACHE_SIZE units */ unsigned long state; /* Always use atomic bitops on this */ unsigned int capabilities; /* Device capabilities */ @@ -58,6 +60,10 @@ struct backing_dev_info { struct device *dev; + struct list_head b_dirty; /* dirty inodes */ + struct list_head b_io; /* parked for writeback */ + struct list_head b_more_io; /* parked for more writeback */ + #ifdef CONFIG_DEBUG_FS struct dentry *debug_dir; struct dentry *debug_stats; @@ -72,6 +78,9 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent, int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev); void bdi_unregister(struct backing_dev_info *bdi); +extern struct mutex bdi_lock; +extern struct list_head bdi_list; + static inline void __add_bdi_stat(struct backing_dev_info *bdi, enum bdi_stat_item item, s64 amount) { diff --git a/include/linux/fs.h b/include/linux/fs.h index 46ff7dd..56371be 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -715,7 +715,7 @@ struct posix_acl; struct inode { struct hlist_node i_hash; - struct list_head i_list; + struct list_head i_list; /* backing dev IO list */ struct list_head i_sb_list; struct list_head i_dentry; unsigned long i_ino; @@ -1336,9 +1336,6 @@ struct super_block { struct xattr_handler **s_xattr; struct list_head s_inodes; /* all inodes */ - struct list_head s_dirty; /* dirty inodes */ - struct list_head s_io; /* parked for writeback */ - struct list_head s_more_io; /* parked for more writeback */ struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */ struct list_head s_files; /* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */ diff --git a/mm/backing-dev.c b/mm/backing-dev.c index c86edd2..6f163e0 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -22,6 +22,8 @@ struct backing_dev_info default_backing_dev_info = { EXPORT_SYMBOL_GPL(default_backing_dev_info); static struct class *bdi_class; +DEFINE_MUTEX(bdi_lock); +LIST_HEAD(bdi_list); #ifdef CONFIG_DEBUG_FS #include @@ -211,6 +213,10 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent, goto exit; } + mutex_lock(&bdi_lock); + list_add_tail(&bdi->bdi_list, &bdi_list); + mutex_unlock(&bdi_lock); + bdi->dev = dev; bdi_debug_register(bdi, dev_name(dev)); @@ -225,9 +231,17 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev) } EXPORT_SYMBOL(bdi_register_dev); +static void bdi_remove_from_list(struct backing_dev_info *bdi) +{ + mutex_lock(&bdi_lock); + list_del(&bdi->bdi_list); + mutex_unlock(&bdi_lock); +} + void bdi_unregister(struct backing_dev_info *bdi) { if (bdi->dev) { + bdi_remove_from_list(bdi); bdi_debug_unregister(bdi); device_unregister(bdi->dev); bdi->dev = NULL; @@ -245,6 +259,10 @@ int bdi_init(struct backing_dev_info *bdi) bdi->min_ratio = 0; bdi->max_ratio = 100; bdi->max_prop_frac = PROP_FRAC_BASE; + INIT_LIST_HEAD(&bdi->bdi_list); + INIT_LIST_HEAD(&bdi->b_io); + INIT_LIST_HEAD(&bdi->b_dirty); + INIT_LIST_HEAD(&bdi->b_more_io); for (i = 0; i < NR_BDI_STAT_ITEMS; i++) { err = percpu_counter_init(&bdi->bdi_stat[i], 0); @@ -259,6 +277,8 @@ int bdi_init(struct backing_dev_info *bdi) err: while (i--) percpu_counter_destroy(&bdi->bdi_stat[i]); + + bdi_remove_from_list(bdi); } return err; @@ -269,6 +289,10 @@ void bdi_destroy(struct backing_dev_info *bdi) { int i; + WARN_ON(!list_empty(&bdi->b_dirty)); + WARN_ON(!list_empty(&bdi->b_io)); + WARN_ON(!list_empty(&bdi->b_more_io)); + bdi_unregister(bdi); for (i = 0; i < NR_BDI_STAT_ITEMS; i++) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 81627eb..f8341b6 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -320,15 +320,13 @@ static void task_dirty_limit(struct task_struct *tsk, unsigned long *pdirty) /* * */ -static DEFINE_SPINLOCK(bdi_lock); static unsigned int bdi_min_ratio; int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio) { int ret = 0; - unsigned long flags; - spin_lock_irqsave(&bdi_lock, flags); + mutex_lock(&bdi_lock); if (min_ratio > bdi->max_ratio) { ret = -EINVAL; } else { @@ -340,27 +338,26 @@ int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio) ret = -EINVAL; } } - spin_unlock_irqrestore(&bdi_lock, flags); + mutex_unlock(&bdi_lock); return ret; } int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned max_ratio) { - unsigned long flags; int ret = 0; if (max_ratio > 100) return -EINVAL; - spin_lock_irqsave(&bdi_lock, flags); + mutex_lock(&bdi_lock); if (bdi->min_ratio > max_ratio) { ret = -EINVAL; } else { bdi->max_ratio = max_ratio; bdi->max_prop_frac = (PROP_FRAC_BASE * max_ratio) / 100; } - spin_unlock_irqrestore(&bdi_lock, flags); + mutex_unlock(&bdi_lock); return ret; } -- cgit v0.10.2 From 03ba3782e8dcc5b0e1efe440d33084f066e38cae Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 9 Sep 2009 09:08:54 +0200 Subject: writeback: switch to per-bdi threads for flushing data This gets rid of pdflush for bdi writeout and kupdated style cleaning. pdflush writeout suffers from lack of locality and also requires more threads to handle the same workload, since it has to work in a non-blocking fashion against each queue. This also introduces lumpy behaviour and potential request starvation, since pdflush can be starved for queue access if others are accessing it. A sample ffsb workload that does random writes to files is about 8% faster here on a simple SATA drive during the benchmark phase. File layout also seems a LOT more smooth in vmstat: r b swpd free buff cache si so bi bo in cs us sy id wa 0 1 0 608848 2652 375372 0 0 0 71024 604 24 1 10 48 42 0 1 0 549644 2712 433736 0 0 0 60692 505 27 1 8 48 44 1 0 0 476928 2784 505192 0 0 4 29540 553 24 0 9 53 37 0 1 0 457972 2808 524008 0 0 0 54876 331 16 0 4 38 58 0 1 0 366128 2928 614284 0 0 4 92168 710 58 0 13 53 34 0 1 0 295092 3000 684140 0 0 0 62924 572 23 0 9 53 37 0 1 0 236592 3064 741704 0 0 4 58256 523 17 0 8 48 44 0 1 0 165608 3132 811464 0 0 0 57460 560 21 0 8 54 38 0 1 0 102952 3200 873164 0 0 4 74748 540 29 1 10 48 41 0 1 0 48604 3252 926472 0 0 0 53248 469 29 0 7 47 45 where vanilla tends to fluctuate a lot in the creation phase: r b swpd free buff cache si so bi bo in cs us sy id wa 1 1 0 678716 5792 303380 0 0 0 74064 565 50 1 11 52 36 1 0 0 662488 5864 319396 0 0 4 352 302 329 0 2 47 51 0 1 0 599312 5924 381468 0 0 0 78164 516 55 0 9 51 40 0 1 0 519952 6008 459516 0 0 4 78156 622 56 1 11 52 37 1 1 0 436640 6092 541632 0 0 0 82244 622 54 0 11 48 41 0 1 0 436640 6092 541660 0 0 0 8 152 39 0 0 51 49 0 1 0 332224 6200 644252 0 0 4 102800 728 46 1 13 49 36 1 0 0 274492 6260 701056 0 0 4 12328 459 49 0 7 50 43 0 1 0 211220 6324 763356 0 0 0 106940 515 37 1 10 51 39 1 0 0 160412 6376 813468 0 0 0 8224 415 43 0 6 49 45 1 1 0 85980 6452 886556 0 0 4 113516 575 39 1 11 54 34 0 2 0 85968 6452 886620 0 0 0 1640 158 211 0 0 46 54 A 10 disk test with btrfs performs 26% faster with per-bdi flushing. A SSD based writeback test on XFS performs over 20% better as well, with the throughput being very stable around 1GB/sec, where pdflush only manages 750MB/sec and fluctuates wildly while doing so. Random buffered writes to many files behave a lot better as well, as does random mmap'ed writes. A separate thread is added to sync the super blocks. In the long term, adding sync_supers_bdi() functionality could get rid of this thread again. Signed-off-by: Jens Axboe diff --git a/fs/buffer.c b/fs/buffer.c index 28f320f..90a9886 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -281,7 +281,7 @@ static void free_more_memory(void) struct zone *zone; int nid; - wakeup_pdflush(1024); + wakeup_flusher_threads(1024); yield(); for_each_online_node(nid) { diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 45ad4bb..7f6dae8 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -27,165 +29,208 @@ #define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info) -/** - * writeback_acquire - attempt to get exclusive writeback access to a device - * @bdi: the device's backing_dev_info structure - * - * It is a waste of resources to have more than one pdflush thread blocked on - * a single request queue. Exclusion at the request_queue level is obtained - * via a flag in the request_queue's backing_dev_info.state. - * - * Non-request_queue-backed address_spaces will share default_backing_dev_info, - * unless they implement their own. Which is somewhat inefficient, as this - * may prevent concurrent writeback against multiple devices. +/* + * Work items for the bdi_writeback threads */ -static int writeback_acquire(struct backing_dev_info *bdi) +struct bdi_work { + struct list_head list; + struct list_head wait_list; + struct rcu_head rcu_head; + + unsigned long seen; + atomic_t pending; + + struct super_block *sb; + unsigned long nr_pages; + enum writeback_sync_modes sync_mode; + + unsigned long state; +}; + +enum { + WS_USED_B = 0, + WS_ONSTACK_B, +}; + +#define WS_USED (1 << WS_USED_B) +#define WS_ONSTACK (1 << WS_ONSTACK_B) + +static inline bool bdi_work_on_stack(struct bdi_work *work) +{ + return test_bit(WS_ONSTACK_B, &work->state); +} + +static inline void bdi_work_init(struct bdi_work *work, + struct writeback_control *wbc) +{ + INIT_RCU_HEAD(&work->rcu_head); + work->sb = wbc->sb; + work->nr_pages = wbc->nr_to_write; + work->sync_mode = wbc->sync_mode; + work->state = WS_USED; +} + +static inline void bdi_work_init_on_stack(struct bdi_work *work, + struct writeback_control *wbc) { - return !test_and_set_bit(BDI_pdflush, &bdi->state); + bdi_work_init(work, wbc); + work->state |= WS_ONSTACK; } /** * writeback_in_progress - determine whether there is writeback in progress * @bdi: the device's backing_dev_info structure. * - * Determine whether there is writeback in progress against a backing device. + * Determine whether there is writeback waiting to be handled against a + * backing device. */ int writeback_in_progress(struct backing_dev_info *bdi) { - return test_bit(BDI_pdflush, &bdi->state); + return !list_empty(&bdi->work_list); } -/** - * writeback_release - relinquish exclusive writeback access against a device. - * @bdi: the device's backing_dev_info structure - */ -static void writeback_release(struct backing_dev_info *bdi) +static void bdi_work_clear(struct bdi_work *work) { - BUG_ON(!writeback_in_progress(bdi)); - clear_bit(BDI_pdflush, &bdi->state); + clear_bit(WS_USED_B, &work->state); + smp_mb__after_clear_bit(); + wake_up_bit(&work->state, WS_USED_B); } -static noinline void block_dump___mark_inode_dirty(struct inode *inode) +static void bdi_work_free(struct rcu_head *head) { - if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) { - struct dentry *dentry; - const char *name = "?"; + struct bdi_work *work = container_of(head, struct bdi_work, rcu_head); - dentry = d_find_alias(inode); - if (dentry) { - spin_lock(&dentry->d_lock); - name = (const char *) dentry->d_name.name; - } - printk(KERN_DEBUG - "%s(%d): dirtied inode %lu (%s) on %s\n", - current->comm, task_pid_nr(current), inode->i_ino, - name, inode->i_sb->s_id); - if (dentry) { - spin_unlock(&dentry->d_lock); - dput(dentry); - } - } + if (!bdi_work_on_stack(work)) + kfree(work); + else + bdi_work_clear(work); } -/** - * __mark_inode_dirty - internal function - * @inode: inode to mark - * @flags: what kind of dirty (i.e. I_DIRTY_SYNC) - * Mark an inode as dirty. Callers should use mark_inode_dirty or - * mark_inode_dirty_sync. - * - * Put the inode on the super block's dirty list. - * - * CAREFUL! We mark it dirty unconditionally, but move it onto the - * dirty list only if it is hashed or if it refers to a blockdev. - * If it was not hashed, it will never be added to the dirty list - * even if it is later hashed, as it will have been marked dirty already. - * - * In short, make sure you hash any inodes _before_ you start marking - * them dirty. - * - * This function *must* be atomic for the I_DIRTY_PAGES case - - * set_page_dirty() is called under spinlock in several places. - * - * Note that for blockdevs, inode->dirtied_when represents the dirtying time of - * the block-special inode (/dev/hda1) itself. And the ->dirtied_when field of - * the kernel-internal blockdev inode represents the dirtying time of the - * blockdev's pages. This is why for I_DIRTY_PAGES we always use - * page->mapping->host, so the page-dirtying time is recorded in the internal - * blockdev inode. - */ -void __mark_inode_dirty(struct inode *inode, int flags) +static void wb_work_complete(struct bdi_work *work) { - struct super_block *sb = inode->i_sb; + const enum writeback_sync_modes sync_mode = work->sync_mode; /* - * Don't do this for I_DIRTY_PAGES - that doesn't actually - * dirty the inode itself + * For allocated work, we can clear the done/seen bit right here. + * For on-stack work, we need to postpone both the clear and free + * to after the RCU grace period, since the stack could be invalidated + * as soon as bdi_work_clear() has done the wakeup. */ - if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { - if (sb->s_op->dirty_inode) - sb->s_op->dirty_inode(inode); - } + if (!bdi_work_on_stack(work)) + bdi_work_clear(work); + if (sync_mode == WB_SYNC_NONE || bdi_work_on_stack(work)) + call_rcu(&work->rcu_head, bdi_work_free); +} +static void wb_clear_pending(struct bdi_writeback *wb, struct bdi_work *work) +{ /* - * make sure that changes are seen by all cpus before we test i_state - * -- mikulas + * The caller has retrieved the work arguments from this work, + * drop our reference. If this is the last ref, delete and free it */ - smp_mb(); + if (atomic_dec_and_test(&work->pending)) { + struct backing_dev_info *bdi = wb->bdi; - /* avoid the locking if we can */ - if ((inode->i_state & flags) == flags) - return; - - if (unlikely(block_dump)) - block_dump___mark_inode_dirty(inode); + spin_lock(&bdi->wb_lock); + list_del_rcu(&work->list); + spin_unlock(&bdi->wb_lock); - spin_lock(&inode_lock); - if ((inode->i_state & flags) != flags) { - const int was_dirty = inode->i_state & I_DIRTY; + wb_work_complete(work); + } +} - inode->i_state |= flags; +static void bdi_queue_work(struct backing_dev_info *bdi, struct bdi_work *work) +{ + if (work) { + work->seen = bdi->wb_mask; + BUG_ON(!work->seen); + atomic_set(&work->pending, bdi->wb_cnt); + BUG_ON(!bdi->wb_cnt); /* - * If the inode is being synced, just update its dirty state. - * The unlocker will place the inode on the appropriate - * superblock list, based upon its state. + * Make sure stores are seen before it appears on the list */ - if (inode->i_state & I_SYNC) - goto out; + smp_mb(); - /* - * Only add valid (hashed) inodes to the superblock's - * dirty list. Add blockdev inodes as well. - */ - if (!S_ISBLK(inode->i_mode)) { - if (hlist_unhashed(&inode->i_hash)) - goto out; - } - if (inode->i_state & (I_FREEING|I_CLEAR)) - goto out; + spin_lock(&bdi->wb_lock); + list_add_tail_rcu(&work->list, &bdi->work_list); + spin_unlock(&bdi->wb_lock); + } + + /* + * If the default thread isn't there, make sure we add it. When + * it gets created and wakes up, we'll run this work. + */ + if (unlikely(list_empty_careful(&bdi->wb_list))) + wake_up_process(default_backing_dev_info.wb.task); + else { + struct bdi_writeback *wb = &bdi->wb; /* - * If the inode was already on b_dirty/b_io/b_more_io, don't - * reposition it (that would break b_dirty time-ordering). + * If we failed allocating the bdi work item, wake up the wb + * thread always. As a safety precaution, it'll flush out + * everything */ - if (!was_dirty) { - inode->dirtied_when = jiffies; - list_move(&inode->i_list, - &inode_to_bdi(inode)->b_dirty); - } + if (!wb_has_dirty_io(wb)) { + if (work) + wb_clear_pending(wb, work); + } else if (wb->task) + wake_up_process(wb->task); } -out: - spin_unlock(&inode_lock); } -EXPORT_SYMBOL(__mark_inode_dirty); +/* + * Used for on-stack allocated work items. The caller needs to wait until + * the wb threads have acked the work before it's safe to continue. + */ +static void bdi_wait_on_work_clear(struct bdi_work *work) +{ + wait_on_bit(&work->state, WS_USED_B, bdi_sched_wait, + TASK_UNINTERRUPTIBLE); +} -static int write_inode(struct inode *inode, int sync) +static struct bdi_work *bdi_alloc_work(struct writeback_control *wbc) { - if (inode->i_sb->s_op->write_inode && !is_bad_inode(inode)) - return inode->i_sb->s_op->write_inode(inode, sync); - return 0; + struct bdi_work *work; + + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (work) + bdi_work_init(work, wbc); + + return work; +} + +void bdi_start_writeback(struct writeback_control *wbc) +{ + const bool must_wait = wbc->sync_mode == WB_SYNC_ALL; + struct bdi_work work_stack, *work = NULL; + + if (!must_wait) + work = bdi_alloc_work(wbc); + + if (!work) { + work = &work_stack; + bdi_work_init_on_stack(work, wbc); + } + + bdi_queue_work(wbc->bdi, work); + + /* + * If the sync mode is WB_SYNC_ALL, block waiting for the work to + * complete. If not, we only need to wait for the work to be started, + * if we allocated it on-stack. We use the same mechanism, if the + * wait bit is set in the bdi_work struct, then threads will not + * clear pending until after they are done. + * + * Note that work == &work_stack if must_wait is true, so we don't + * need to do call_rcu() here ever, since the completion path will + * have done that for us. + */ + if (must_wait || work == &work_stack) { + bdi_wait_on_work_clear(work); + if (work != &work_stack) + call_rcu(&work->rcu_head, bdi_work_free); + } } /* @@ -199,16 +244,16 @@ static int write_inode(struct inode *inode, int sync) */ static void redirty_tail(struct inode *inode) { - struct backing_dev_info *bdi = inode_to_bdi(inode); + struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; - if (!list_empty(&bdi->b_dirty)) { + if (!list_empty(&wb->b_dirty)) { struct inode *tail; - tail = list_entry(bdi->b_dirty.next, struct inode, i_list); + tail = list_entry(wb->b_dirty.next, struct inode, i_list); if (time_before(inode->dirtied_when, tail->dirtied_when)) inode->dirtied_when = jiffies; } - list_move(&inode->i_list, &bdi->b_dirty); + list_move(&inode->i_list, &wb->b_dirty); } /* @@ -216,7 +261,9 @@ static void redirty_tail(struct inode *inode) */ static void requeue_io(struct inode *inode) { - list_move(&inode->i_list, &inode_to_bdi(inode)->b_more_io); + struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; + + list_move(&inode->i_list, &wb->b_more_io); } static void inode_sync_complete(struct inode *inode) @@ -263,52 +310,18 @@ static void move_expired_inodes(struct list_head *delaying_queue, /* * Queue all expired dirty inodes for io, eldest first. */ -static void queue_io(struct backing_dev_info *bdi, - unsigned long *older_than_this) +static void queue_io(struct bdi_writeback *wb, unsigned long *older_than_this) { - list_splice_init(&bdi->b_more_io, bdi->b_io.prev); - move_expired_inodes(&bdi->b_dirty, &bdi->b_io, older_than_this); + list_splice_init(&wb->b_more_io, wb->b_io.prev); + move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this); } -static int sb_on_inode_list(struct super_block *sb, struct list_head *list) -{ - struct inode *inode; - int ret = 0; - - spin_lock(&inode_lock); - list_for_each_entry(inode, list, i_list) { - if (inode->i_sb == sb) { - ret = 1; - break; - } - } - spin_unlock(&inode_lock); - return ret; -} - -int sb_has_dirty_inodes(struct super_block *sb) +static int write_inode(struct inode *inode, int sync) { - struct backing_dev_info *bdi; - int ret = 0; - - /* - * This is REALLY expensive right now, but it'll go away - * when the bdi writeback is introduced - */ - mutex_lock(&bdi_lock); - list_for_each_entry(bdi, &bdi_list, bdi_list) { - if (sb_on_inode_list(sb, &bdi->b_dirty) || - sb_on_inode_list(sb, &bdi->b_io) || - sb_on_inode_list(sb, &bdi->b_more_io)) { - ret = 1; - break; - } - } - mutex_unlock(&bdi_lock); - - return ret; + if (inode->i_sb->s_op->write_inode && !is_bad_inode(inode)) + return inode->i_sb->s_op->write_inode(inode, sync); + return 0; } -EXPORT_SYMBOL(sb_has_dirty_inodes); /* * Wait for writeback on an inode to complete. @@ -466,20 +479,71 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) return ret; } -static void generic_sync_bdi_inodes(struct backing_dev_info *bdi, - struct writeback_control *wbc, - struct super_block *sb) +/* + * For WB_SYNC_NONE writeback, the caller does not have the sb pinned + * before calling writeback. So make sure that we do pin it, so it doesn't + * go away while we are writing inodes from it. + * + * Returns 0 if the super was successfully pinned (or pinning wasn't needed), + * 1 if we failed. + */ +static int pin_sb_for_writeback(struct writeback_control *wbc, + struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + + /* + * Caller must already hold the ref for this + */ + if (wbc->sync_mode == WB_SYNC_ALL) { + WARN_ON(!rwsem_is_locked(&sb->s_umount)); + return 0; + } + + spin_lock(&sb_lock); + sb->s_count++; + if (down_read_trylock(&sb->s_umount)) { + if (sb->s_root) { + spin_unlock(&sb_lock); + return 0; + } + /* + * umounted, drop rwsem again and fall through to failure + */ + up_read(&sb->s_umount); + } + + sb->s_count--; + spin_unlock(&sb_lock); + return 1; +} + +static void unpin_sb_for_writeback(struct writeback_control *wbc, + struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + + if (wbc->sync_mode == WB_SYNC_ALL) + return; + + up_read(&sb->s_umount); + put_super(sb); +} + +static void writeback_inodes_wb(struct bdi_writeback *wb, + struct writeback_control *wbc) { + struct super_block *sb = wbc->sb; const int is_blkdev_sb = sb_is_blkdev_sb(sb); const unsigned long start = jiffies; /* livelock avoidance */ spin_lock(&inode_lock); - if (!wbc->for_kupdate || list_empty(&bdi->b_io)) - queue_io(bdi, wbc->older_than_this); + if (!wbc->for_kupdate || list_empty(&wb->b_io)) + queue_io(wb, wbc->older_than_this); - while (!list_empty(&bdi->b_io)) { - struct inode *inode = list_entry(bdi->b_io.prev, + while (!list_empty(&wb->b_io)) { + struct inode *inode = list_entry(wb->b_io.prev, struct inode, i_list); long pages_skipped; @@ -491,7 +555,7 @@ static void generic_sync_bdi_inodes(struct backing_dev_info *bdi, continue; } - if (!bdi_cap_writeback_dirty(bdi)) { + if (!bdi_cap_writeback_dirty(wb->bdi)) { redirty_tail(inode); if (is_blkdev_sb) { /* @@ -513,7 +577,7 @@ static void generic_sync_bdi_inodes(struct backing_dev_info *bdi, continue; } - if (wbc->nonblocking && bdi_write_congested(bdi)) { + if (wbc->nonblocking && bdi_write_congested(wb->bdi)) { wbc->encountered_congestion = 1; if (!is_blkdev_sb) break; /* Skip a congested fs */ @@ -521,13 +585,6 @@ static void generic_sync_bdi_inodes(struct backing_dev_info *bdi, continue; /* Skip a congested blockdev */ } - if (wbc->bdi && bdi != wbc->bdi) { - if (!is_blkdev_sb) - break; /* fs has the wrong queue */ - requeue_io(inode); - continue; /* blockdev has wrong queue */ - } - /* * Was this inode dirtied after sync_sb_inodes was called? * This keeps sync from extra jobs and livelock. @@ -535,16 +592,16 @@ static void generic_sync_bdi_inodes(struct backing_dev_info *bdi, if (inode_dirtied_after(inode, start)) break; - /* Is another pdflush already flushing this queue? */ - if (current_is_pdflush() && !writeback_acquire(bdi)) - break; + if (pin_sb_for_writeback(wbc, inode)) { + requeue_io(inode); + continue; + } BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); __iget(inode); pages_skipped = wbc->pages_skipped; writeback_single_inode(inode, wbc); - if (current_is_pdflush()) - writeback_release(bdi); + unpin_sb_for_writeback(wbc, inode); if (wbc->pages_skipped != pages_skipped) { /* * writeback is not making progress due to locked @@ -560,7 +617,7 @@ static void generic_sync_bdi_inodes(struct backing_dev_info *bdi, wbc->more_io = 1; break; } - if (!list_empty(&bdi->b_more_io)) + if (!list_empty(&wb->b_more_io)) wbc->more_io = 1; } @@ -568,139 +625,500 @@ static void generic_sync_bdi_inodes(struct backing_dev_info *bdi, /* Leave any unwritten inodes on b_io */ } +void writeback_inodes_wbc(struct writeback_control *wbc) +{ + struct backing_dev_info *bdi = wbc->bdi; + + writeback_inodes_wb(&bdi->wb, wbc); +} + /* - * Write out a superblock's list of dirty inodes. A wait will be performed - * upon no inodes, all inodes or the final one, depending upon sync_mode. - * - * If older_than_this is non-NULL, then only write out inodes which - * had their first dirtying at a time earlier than *older_than_this. - * - * If we're a pdlfush thread, then implement pdflush collision avoidance - * against the entire list. + * The maximum number of pages to writeout in a single bdi flush/kupdate + * operation. We do this so we don't hold I_SYNC against an inode for + * enormous amounts of time, which would block a userspace task which has + * been forced to throttle against that inode. Also, the code reevaluates + * the dirty each time it has written this many pages. + */ +#define MAX_WRITEBACK_PAGES 1024 + +static inline bool over_bground_thresh(void) +{ + unsigned long background_thresh, dirty_thresh; + + get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL); + + return (global_page_state(NR_FILE_DIRTY) + + global_page_state(NR_UNSTABLE_NFS) >= background_thresh); +} + +/* + * Explicit flushing or periodic writeback of "old" data. * - * If `bdi' is non-zero then we're being asked to writeback a specific queue. - * This function assumes that the blockdev superblock's inodes are backed by - * a variety of queues, so all inodes are searched. For other superblocks, - * assume that all inodes are backed by the same queue. + * Define "old": the first time one of an inode's pages is dirtied, we mark the + * dirtying-time in the inode's address_space. So this periodic writeback code + * just walks the superblock inode list, writing back any inodes which are + * older than a specific point in time. * - * FIXME: this linear search could get expensive with many fileystems. But - * how to fix? We need to go from an address_space to all inodes which share - * a queue with that address_space. (Easy: have a global "dirty superblocks" - * list). + * Try to run once per dirty_writeback_interval. But if a writeback event + * takes longer than a dirty_writeback_interval interval, then leave a + * one-second gap. * - * The inodes to be written are parked on bdi->b_io. They are moved back onto - * bdi->b_dirty as they are selected for writing. This way, none can be missed - * on the writer throttling path, and we get decent balancing between many - * throttled threads: we don't want them all piling up on inode_sync_wait. + * older_than_this takes precedence over nr_to_write. So we'll only write back + * all dirty pages if they are all attached to "old" mappings. */ -static void generic_sync_sb_inodes(struct super_block *sb, - struct writeback_control *wbc) +static long wb_writeback(struct bdi_writeback *wb, long nr_pages, + struct super_block *sb, + enum writeback_sync_modes sync_mode, int for_kupdate) { - struct backing_dev_info *bdi; - - if (!wbc->bdi) { - mutex_lock(&bdi_lock); - list_for_each_entry(bdi, &bdi_list, bdi_list) - generic_sync_bdi_inodes(bdi, wbc, sb); - mutex_unlock(&bdi_lock); - } else - generic_sync_bdi_inodes(wbc->bdi, wbc, sb); + struct writeback_control wbc = { + .bdi = wb->bdi, + .sb = sb, + .sync_mode = sync_mode, + .older_than_this = NULL, + .for_kupdate = for_kupdate, + .range_cyclic = 1, + }; + unsigned long oldest_jif; + long wrote = 0; - if (wbc->sync_mode == WB_SYNC_ALL) { - struct inode *inode, *old_inode = NULL; + if (wbc.for_kupdate) { + wbc.older_than_this = &oldest_jif; + oldest_jif = jiffies - + msecs_to_jiffies(dirty_expire_interval * 10); + } - spin_lock(&inode_lock); + for (;;) { + /* + * Don't flush anything for non-integrity writeback where + * no nr_pages was given + */ + if (!for_kupdate && nr_pages <= 0 && sync_mode == WB_SYNC_NONE) + break; /* - * Data integrity sync. Must wait for all pages under writeback, - * because there may have been pages dirtied before our sync - * call, but which had writeout started before we write it out. - * In which case, the inode may not be on the dirty list, but - * we still have to wait for that writeout. + * If no specific pages were given and this is just a + * periodic background writeout and we are below the + * background dirty threshold, don't do anything */ - list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { - struct address_space *mapping; + if (for_kupdate && nr_pages <= 0 && !over_bground_thresh()) + break; - if (inode->i_state & - (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) - continue; - mapping = inode->i_mapping; - if (mapping->nrpages == 0) + wbc.more_io = 0; + wbc.encountered_congestion = 0; + wbc.nr_to_write = MAX_WRITEBACK_PAGES; + wbc.pages_skipped = 0; + writeback_inodes_wb(wb, &wbc); + nr_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; + wrote += MAX_WRITEBACK_PAGES - wbc.nr_to_write; + + /* + * If we ran out of stuff to write, bail unless more_io got set + */ + if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) { + if (wbc.more_io && !wbc.for_kupdate) continue; - __iget(inode); - spin_unlock(&inode_lock); + break; + } + } + + return wrote; +} + +/* + * Return the next bdi_work struct that hasn't been processed by this + * wb thread yet + */ +static struct bdi_work *get_next_work_item(struct backing_dev_info *bdi, + struct bdi_writeback *wb) +{ + struct bdi_work *work, *ret = NULL; + + rcu_read_lock(); + + list_for_each_entry_rcu(work, &bdi->work_list, list) { + if (!test_and_clear_bit(wb->nr, &work->seen)) + continue; + + ret = work; + break; + } + + rcu_read_unlock(); + return ret; +} + +static long wb_check_old_data_flush(struct bdi_writeback *wb) +{ + unsigned long expired; + long nr_pages; + + expired = wb->last_old_flush + + msecs_to_jiffies(dirty_writeback_interval * 10); + if (time_before(jiffies, expired)) + return 0; + + wb->last_old_flush = jiffies; + nr_pages = global_page_state(NR_FILE_DIRTY) + + global_page_state(NR_UNSTABLE_NFS) + + (inodes_stat.nr_inodes - inodes_stat.nr_unused); + + if (nr_pages) + return wb_writeback(wb, nr_pages, NULL, WB_SYNC_NONE, 1); + + return 0; +} + +/* + * Retrieve work items and do the writeback they describe + */ +long wb_do_writeback(struct bdi_writeback *wb, int force_wait) +{ + struct backing_dev_info *bdi = wb->bdi; + struct bdi_work *work; + long nr_pages, wrote = 0; + + while ((work = get_next_work_item(bdi, wb)) != NULL) { + enum writeback_sync_modes sync_mode; + + nr_pages = work->nr_pages; + + /* + * Override sync mode, in case we must wait for completion + */ + if (force_wait) + work->sync_mode = sync_mode = WB_SYNC_ALL; + else + sync_mode = work->sync_mode; + + /* + * If this isn't a data integrity operation, just notify + * that we have seen this work and we are now starting it. + */ + if (sync_mode == WB_SYNC_NONE) + wb_clear_pending(wb, work); + + wrote += wb_writeback(wb, nr_pages, work->sb, sync_mode, 0); + + /* + * This is a data integrity writeback, so only do the + * notification when we have completed the work. + */ + if (sync_mode == WB_SYNC_ALL) + wb_clear_pending(wb, work); + } + + /* + * Check for periodic writeback, kupdated() style + */ + wrote += wb_check_old_data_flush(wb); + + return wrote; +} + +/* + * Handle writeback of dirty data for the device backed by this bdi. Also + * wakes up periodically and does kupdated style flushing. + */ +int bdi_writeback_task(struct bdi_writeback *wb) +{ + unsigned long last_active = jiffies; + unsigned long wait_jiffies = -1UL; + long pages_written; + + while (!kthread_should_stop()) { + pages_written = wb_do_writeback(wb, 0); + + if (pages_written) + last_active = jiffies; + else if (wait_jiffies != -1UL) { + unsigned long max_idle; + /* - * We hold a reference to 'inode' so it couldn't have - * been removed from s_inodes list while we dropped the - * inode_lock. We cannot iput the inode now as we can - * be holding the last reference and we cannot iput it - * under inode_lock. So we keep the reference and iput - * it later. + * Longest period of inactivity that we tolerate. If we + * see dirty data again later, the task will get + * recreated automatically. */ - iput(old_inode); - old_inode = inode; + max_idle = max(5UL * 60 * HZ, wait_jiffies); + if (time_after(jiffies, max_idle + last_active)) + break; + } + + wait_jiffies = msecs_to_jiffies(dirty_writeback_interval * 10); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(wait_jiffies); + try_to_freeze(); + } + + return 0; +} + +/* + * Schedule writeback for all backing devices. Expensive! If this is a data + * integrity operation, writeback will be complete when this returns. If + * we are simply called for WB_SYNC_NONE, then writeback will merely be + * scheduled to run. + */ +static void bdi_writeback_all(struct writeback_control *wbc) +{ + const bool must_wait = wbc->sync_mode == WB_SYNC_ALL; + struct backing_dev_info *bdi; + struct bdi_work *work; + LIST_HEAD(list); + +restart: + spin_lock(&bdi_lock); + + list_for_each_entry(bdi, &bdi_list, bdi_list) { + struct bdi_work *work; + + if (!bdi_has_dirty_io(bdi)) + continue; - filemap_fdatawait(mapping); + /* + * If work allocation fails, do the writes inline. We drop + * the lock and restart the list writeout. This should be OK, + * since this happens rarely and because the writeout should + * eventually make more free memory available. + */ + work = bdi_alloc_work(wbc); + if (!work) { + struct writeback_control __wbc; - cond_resched(); + /* + * Not a data integrity writeout, just continue + */ + if (!must_wait) + continue; - spin_lock(&inode_lock); + spin_unlock(&bdi_lock); + __wbc = *wbc; + __wbc.bdi = bdi; + writeback_inodes_wbc(&__wbc); + goto restart; } - spin_unlock(&inode_lock); - iput(old_inode); + if (must_wait) + list_add_tail(&work->wait_list, &list); + + bdi_queue_work(bdi, work); + } + + spin_unlock(&bdi_lock); + + /* + * If this is for WB_SYNC_ALL, wait for pending work to complete + * before returning. + */ + while (!list_empty(&list)) { + work = list_entry(list.next, struct bdi_work, wait_list); + list_del(&work->wait_list); + bdi_wait_on_work_clear(work); + call_rcu(&work->rcu_head, bdi_work_free); } } /* - * Start writeback of dirty pagecache data against all unlocked inodes. + * Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back + * the whole world. + */ +void wakeup_flusher_threads(long nr_pages) +{ + struct writeback_control wbc = { + .sync_mode = WB_SYNC_NONE, + .older_than_this = NULL, + .range_cyclic = 1, + }; + + if (nr_pages == 0) + nr_pages = global_page_state(NR_FILE_DIRTY) + + global_page_state(NR_UNSTABLE_NFS); + wbc.nr_to_write = nr_pages; + bdi_writeback_all(&wbc); +} + +static noinline void block_dump___mark_inode_dirty(struct inode *inode) +{ + if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) { + struct dentry *dentry; + const char *name = "?"; + + dentry = d_find_alias(inode); + if (dentry) { + spin_lock(&dentry->d_lock); + name = (const char *) dentry->d_name.name; + } + printk(KERN_DEBUG + "%s(%d): dirtied inode %lu (%s) on %s\n", + current->comm, task_pid_nr(current), inode->i_ino, + name, inode->i_sb->s_id); + if (dentry) { + spin_unlock(&dentry->d_lock); + dput(dentry); + } + } +} + +/** + * __mark_inode_dirty - internal function + * @inode: inode to mark + * @flags: what kind of dirty (i.e. I_DIRTY_SYNC) + * Mark an inode as dirty. Callers should use mark_inode_dirty or + * mark_inode_dirty_sync. * - * Note: - * We don't need to grab a reference to superblock here. If it has non-empty - * ->b_dirty it's hadn't been killed yet and kill_super() won't proceed - * past sync_inodes_sb() until the ->b_dirty/b_io/b_more_io lists are all - * empty. Since __sync_single_inode() regains inode_lock before it finally moves - * inode from superblock lists we are OK. + * Put the inode on the super block's dirty list. + * + * CAREFUL! We mark it dirty unconditionally, but move it onto the + * dirty list only if it is hashed or if it refers to a blockdev. + * If it was not hashed, it will never be added to the dirty list + * even if it is later hashed, as it will have been marked dirty already. + * + * In short, make sure you hash any inodes _before_ you start marking + * them dirty. * - * If `older_than_this' is non-zero then only flush inodes which have a - * flushtime older than *older_than_this. + * This function *must* be atomic for the I_DIRTY_PAGES case - + * set_page_dirty() is called under spinlock in several places. * - * If `bdi' is non-zero then we will scan the first inode against each - * superblock until we find the matching ones. One group will be the dirty - * inodes against a filesystem. Then when we hit the dummy blockdev superblock, - * sync_sb_inodes will seekout the blockdev which matches `bdi'. Maybe not - * super-efficient but we're about to do a ton of I/O... + * Note that for blockdevs, inode->dirtied_when represents the dirtying time of + * the block-special inode (/dev/hda1) itself. And the ->dirtied_when field of + * the kernel-internal blockdev inode represents the dirtying time of the + * blockdev's pages. This is why for I_DIRTY_PAGES we always use + * page->mapping->host, so the page-dirtying time is recorded in the internal + * blockdev inode. */ -void -writeback_inodes(struct writeback_control *wbc) +void __mark_inode_dirty(struct inode *inode, int flags) { - struct super_block *sb; + struct super_block *sb = inode->i_sb; - might_sleep(); - spin_lock(&sb_lock); -restart: - list_for_each_entry_reverse(sb, &super_blocks, s_list) { - if (sb_has_dirty_inodes(sb)) { - /* we're making our own get_super here */ - sb->s_count++; - spin_unlock(&sb_lock); - /* - * If we can't get the readlock, there's no sense in - * waiting around, most of the time the FS is going to - * be unmounted by the time it is released. - */ - if (down_read_trylock(&sb->s_umount)) { - if (sb->s_root) - generic_sync_sb_inodes(sb, wbc); - up_read(&sb->s_umount); - } - spin_lock(&sb_lock); - if (__put_super_and_need_restart(sb)) - goto restart; + /* + * Don't do this for I_DIRTY_PAGES - that doesn't actually + * dirty the inode itself + */ + if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { + if (sb->s_op->dirty_inode) + sb->s_op->dirty_inode(inode); + } + + /* + * make sure that changes are seen by all cpus before we test i_state + * -- mikulas + */ + smp_mb(); + + /* avoid the locking if we can */ + if ((inode->i_state & flags) == flags) + return; + + if (unlikely(block_dump)) + block_dump___mark_inode_dirty(inode); + + spin_lock(&inode_lock); + if ((inode->i_state & flags) != flags) { + const int was_dirty = inode->i_state & I_DIRTY; + + inode->i_state |= flags; + + /* + * If the inode is being synced, just update its dirty state. + * The unlocker will place the inode on the appropriate + * superblock list, based upon its state. + */ + if (inode->i_state & I_SYNC) + goto out; + + /* + * Only add valid (hashed) inodes to the superblock's + * dirty list. Add blockdev inodes as well. + */ + if (!S_ISBLK(inode->i_mode)) { + if (hlist_unhashed(&inode->i_hash)) + goto out; + } + if (inode->i_state & (I_FREEING|I_CLEAR)) + goto out; + + /* + * If the inode was already on b_dirty/b_io/b_more_io, don't + * reposition it (that would break b_dirty time-ordering). + */ + if (!was_dirty) { + struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; + + inode->dirtied_when = jiffies; + list_move(&inode->i_list, &wb->b_dirty); } - if (wbc->nr_to_write <= 0) - break; } - spin_unlock(&sb_lock); +out: + spin_unlock(&inode_lock); +} +EXPORT_SYMBOL(__mark_inode_dirty); + +/* + * Write out a superblock's list of dirty inodes. A wait will be performed + * upon no inodes, all inodes or the final one, depending upon sync_mode. + * + * If older_than_this is non-NULL, then only write out inodes which + * had their first dirtying at a time earlier than *older_than_this. + * + * If we're a pdlfush thread, then implement pdflush collision avoidance + * against the entire list. + * + * If `bdi' is non-zero then we're being asked to writeback a specific queue. + * This function assumes that the blockdev superblock's inodes are backed by + * a variety of queues, so all inodes are searched. For other superblocks, + * assume that all inodes are backed by the same queue. + * + * The inodes to be written are parked on bdi->b_io. They are moved back onto + * bdi->b_dirty as they are selected for writing. This way, none can be missed + * on the writer throttling path, and we get decent balancing between many + * throttled threads: we don't want them all piling up on inode_sync_wait. + */ +static void wait_sb_inodes(struct writeback_control *wbc) +{ + struct inode *inode, *old_inode = NULL; + + /* + * We need to be protected against the filesystem going from + * r/o to r/w or vice versa. + */ + WARN_ON(!rwsem_is_locked(&wbc->sb->s_umount)); + + spin_lock(&inode_lock); + + /* + * Data integrity sync. Must wait for all pages under writeback, + * because there may have been pages dirtied before our sync + * call, but which had writeout started before we write it out. + * In which case, the inode may not be on the dirty list, but + * we still have to wait for that writeout. + */ + list_for_each_entry(inode, &wbc->sb->s_inodes, i_sb_list) { + struct address_space *mapping; + + if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) + continue; + mapping = inode->i_mapping; + if (mapping->nrpages == 0) + continue; + __iget(inode); + spin_unlock(&inode_lock); + /* + * We hold a reference to 'inode' so it couldn't have + * been removed from s_inodes list while we dropped the + * inode_lock. We cannot iput the inode now as we can + * be holding the last reference and we cannot iput it + * under inode_lock. So we keep the reference and iput + * it later. + */ + iput(old_inode); + old_inode = inode; + + filemap_fdatawait(mapping); + + cond_resched(); + + spin_lock(&inode_lock); + } + spin_unlock(&inode_lock); + iput(old_inode); } /** @@ -715,6 +1133,7 @@ restart: long writeback_inodes_sb(struct super_block *sb) { struct writeback_control wbc = { + .sb = sb, .sync_mode = WB_SYNC_NONE, .range_start = 0, .range_end = LLONG_MAX, @@ -727,7 +1146,7 @@ long writeback_inodes_sb(struct super_block *sb) (inodes_stat.nr_inodes - inodes_stat.nr_unused); wbc.nr_to_write = nr_to_write; - generic_sync_sb_inodes(sb, &wbc); + bdi_writeback_all(&wbc); return nr_to_write - wbc.nr_to_write; } EXPORT_SYMBOL(writeback_inodes_sb); @@ -742,6 +1161,7 @@ EXPORT_SYMBOL(writeback_inodes_sb); long sync_inodes_sb(struct super_block *sb) { struct writeback_control wbc = { + .sb = sb, .sync_mode = WB_SYNC_ALL, .range_start = 0, .range_end = LLONG_MAX, @@ -749,7 +1169,8 @@ long sync_inodes_sb(struct super_block *sb) long nr_to_write = LONG_MAX; /* doesn't actually matter */ wbc.nr_to_write = nr_to_write; - generic_sync_sb_inodes(sb, &wbc); + bdi_writeback_all(&wbc); + wait_sb_inodes(&wbc); return nr_to_write - wbc.nr_to_write; } EXPORT_SYMBOL(sync_inodes_sb); diff --git a/fs/super.c b/fs/super.c index 0d22ce3..9cda337 100644 --- a/fs/super.c +++ b/fs/super.c @@ -168,7 +168,7 @@ int __put_super_and_need_restart(struct super_block *sb) * Drops a temporary reference, frees superblock if there's no * references left. */ -static void put_super(struct super_block *sb) +void put_super(struct super_block *sb) { spin_lock(&sb_lock); __put_super(sb); diff --git a/fs/sync.c b/fs/sync.c index 66f2104..103cc7f 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -120,7 +120,7 @@ restart: */ SYSCALL_DEFINE0(sync) { - wakeup_pdflush(0); + wakeup_flusher_threads(0); sync_filesystems(0); sync_filesystems(1); if (unlikely(laptop_mode)) diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 928cd54..d045f5f 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include struct page; @@ -23,7 +25,8 @@ struct dentry; * Bits in backing_dev_info.state */ enum bdi_state { - BDI_pdflush, /* A pdflush thread is working this device */ + BDI_pending, /* On its way to being activated */ + BDI_wb_alloc, /* Default embedded wb allocated */ BDI_async_congested, /* The async (write) queue is getting full */ BDI_sync_congested, /* The sync queue is getting full */ BDI_unused, /* Available bits start here */ @@ -39,9 +42,22 @@ enum bdi_stat_item { #define BDI_STAT_BATCH (8*(1+ilog2(nr_cpu_ids))) +struct bdi_writeback { + struct list_head list; /* hangs off the bdi */ + + struct backing_dev_info *bdi; /* our parent bdi */ + unsigned int nr; + + unsigned long last_old_flush; /* last old data flush */ + + struct task_struct *task; /* writeback task */ + struct list_head b_dirty; /* dirty inodes */ + struct list_head b_io; /* parked for writeback */ + struct list_head b_more_io; /* parked for more writeback */ +}; + struct backing_dev_info { struct list_head bdi_list; - unsigned long ra_pages; /* max readahead in PAGE_CACHE_SIZE units */ unsigned long state; /* Always use atomic bitops on this */ unsigned int capabilities; /* Device capabilities */ @@ -58,11 +74,15 @@ struct backing_dev_info { unsigned int min_ratio; unsigned int max_ratio, max_prop_frac; - struct device *dev; + struct bdi_writeback wb; /* default writeback info for this bdi */ + spinlock_t wb_lock; /* protects update side of wb_list */ + struct list_head wb_list; /* the flusher threads hanging off this bdi */ + unsigned long wb_mask; /* bitmask of registered tasks */ + unsigned int wb_cnt; /* number of registered tasks */ - struct list_head b_dirty; /* dirty inodes */ - struct list_head b_io; /* parked for writeback */ - struct list_head b_more_io; /* parked for more writeback */ + struct list_head work_list; + + struct device *dev; #ifdef CONFIG_DEBUG_FS struct dentry *debug_dir; @@ -77,10 +97,20 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent, const char *fmt, ...); int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev); void bdi_unregister(struct backing_dev_info *bdi); +void bdi_start_writeback(struct writeback_control *wbc); +int bdi_writeback_task(struct bdi_writeback *wb); +int bdi_has_dirty_io(struct backing_dev_info *bdi); -extern struct mutex bdi_lock; +extern spinlock_t bdi_lock; extern struct list_head bdi_list; +static inline int wb_has_dirty_io(struct bdi_writeback *wb) +{ + return !list_empty(&wb->b_dirty) || + !list_empty(&wb->b_io) || + !list_empty(&wb->b_more_io); +} + static inline void __add_bdi_stat(struct backing_dev_info *bdi, enum bdi_stat_item item, s64 amount) { @@ -270,6 +300,11 @@ static inline bool bdi_cap_swap_backed(struct backing_dev_info *bdi) return bdi->capabilities & BDI_CAP_SWAP_BACKED; } +static inline bool bdi_cap_flush_forker(struct backing_dev_info *bdi) +{ + return bdi == &default_backing_dev_info; +} + static inline bool mapping_cap_writeback_dirty(struct address_space *mapping) { return bdi_cap_writeback_dirty(mapping->backing_dev_info); @@ -285,4 +320,10 @@ static inline bool mapping_cap_swap_backed(struct address_space *mapping) return bdi_cap_swap_backed(mapping->backing_dev_info); } +static inline int bdi_sched_wait(void *word) +{ + schedule(); + return 0; +} + #endif /* _LINUX_BACKING_DEV_H */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 56371be..26da98f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1786,6 +1786,7 @@ extern int get_sb_pseudo(struct file_system_type *, char *, struct vfsmount *mnt); extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb); int __put_super_and_need_restart(struct super_block *sb); +void put_super(struct super_block *sb); /* Alas, no aliases. Too much hassle with bringing module.h everywhere */ #define fops_get(fops) \ @@ -2182,7 +2183,6 @@ extern int bdev_read_only(struct block_device *); extern int set_blocksize(struct block_device *, int); extern int sb_set_blocksize(struct super_block *, int); extern int sb_min_blocksize(struct super_block *, int); -extern int sb_has_dirty_inodes(struct super_block *); extern int generic_file_mmap(struct file *, struct vm_area_struct *); extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *); diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 0703929..cef7552 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -40,6 +40,8 @@ enum writeback_sync_modes { struct writeback_control { struct backing_dev_info *bdi; /* If !NULL, only write back this queue */ + struct super_block *sb; /* if !NULL, only write inodes from + this super_block */ enum writeback_sync_modes sync_mode; unsigned long *older_than_this; /* If !NULL, only write back inodes older than this */ @@ -76,10 +78,13 @@ struct writeback_control { /* * fs/fs-writeback.c */ -void writeback_inodes(struct writeback_control *wbc); +struct bdi_writeback; int inode_wait(void *); long writeback_inodes_sb(struct super_block *); long sync_inodes_sb(struct super_block *); +void writeback_inodes_wbc(struct writeback_control *wbc); +long wb_do_writeback(struct bdi_writeback *wb, int force_wait); +void wakeup_flusher_threads(long nr_pages); /* writeback.h requires fs.h; it, too, is not included from here. */ static inline void wait_on_inode(struct inode *inode) @@ -99,7 +104,6 @@ static inline void inode_sync_wait(struct inode *inode) /* * mm/page-writeback.c */ -int wakeup_pdflush(long nr_pages); void laptop_io_completion(void); void laptop_sync_completion(void); void throttle_vm_writeout(gfp_t gfp_mask); diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 6f163e0..7f3fa79 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -1,8 +1,11 @@ #include #include +#include +#include #include #include +#include #include #include #include @@ -22,8 +25,18 @@ struct backing_dev_info default_backing_dev_info = { EXPORT_SYMBOL_GPL(default_backing_dev_info); static struct class *bdi_class; -DEFINE_MUTEX(bdi_lock); +DEFINE_SPINLOCK(bdi_lock); LIST_HEAD(bdi_list); +LIST_HEAD(bdi_pending_list); + +static struct task_struct *sync_supers_tsk; +static struct timer_list sync_supers_timer; + +static int bdi_sync_supers(void *); +static void sync_supers_timer_fn(unsigned long); +static void arm_supers_timer(void); + +static void bdi_add_default_flusher_task(struct backing_dev_info *bdi); #ifdef CONFIG_DEBUG_FS #include @@ -187,6 +200,13 @@ static int __init default_bdi_init(void) { int err; + sync_supers_tsk = kthread_run(bdi_sync_supers, NULL, "sync_supers"); + BUG_ON(IS_ERR(sync_supers_tsk)); + + init_timer(&sync_supers_timer); + setup_timer(&sync_supers_timer, sync_supers_timer_fn, 0); + arm_supers_timer(); + err = bdi_init(&default_backing_dev_info); if (!err) bdi_register(&default_backing_dev_info, NULL, "default"); @@ -195,6 +215,242 @@ static int __init default_bdi_init(void) } subsys_initcall(default_bdi_init); +static void bdi_wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi) +{ + memset(wb, 0, sizeof(*wb)); + + wb->bdi = bdi; + wb->last_old_flush = jiffies; + INIT_LIST_HEAD(&wb->b_dirty); + INIT_LIST_HEAD(&wb->b_io); + INIT_LIST_HEAD(&wb->b_more_io); +} + +static void bdi_task_init(struct backing_dev_info *bdi, + struct bdi_writeback *wb) +{ + struct task_struct *tsk = current; + + spin_lock(&bdi->wb_lock); + list_add_tail_rcu(&wb->list, &bdi->wb_list); + spin_unlock(&bdi->wb_lock); + + tsk->flags |= PF_FLUSHER | PF_SWAPWRITE; + set_freezable(); + + /* + * Our parent may run at a different priority, just set us to normal + */ + set_user_nice(tsk, 0); +} + +static int bdi_start_fn(void *ptr) +{ + struct bdi_writeback *wb = ptr; + struct backing_dev_info *bdi = wb->bdi; + int ret; + + /* + * Add us to the active bdi_list + */ + spin_lock(&bdi_lock); + list_add(&bdi->bdi_list, &bdi_list); + spin_unlock(&bdi_lock); + + bdi_task_init(bdi, wb); + + /* + * Clear pending bit and wakeup anybody waiting to tear us down + */ + clear_bit(BDI_pending, &bdi->state); + smp_mb__after_clear_bit(); + wake_up_bit(&bdi->state, BDI_pending); + + ret = bdi_writeback_task(wb); + + /* + * Remove us from the list + */ + spin_lock(&bdi->wb_lock); + list_del_rcu(&wb->list); + spin_unlock(&bdi->wb_lock); + + /* + * Flush any work that raced with us exiting. No new work + * will be added, since this bdi isn't discoverable anymore. + */ + if (!list_empty(&bdi->work_list)) + wb_do_writeback(wb, 1); + + wb->task = NULL; + return ret; +} + +int bdi_has_dirty_io(struct backing_dev_info *bdi) +{ + return wb_has_dirty_io(&bdi->wb); +} + +static void bdi_flush_io(struct backing_dev_info *bdi) +{ + struct writeback_control wbc = { + .bdi = bdi, + .sync_mode = WB_SYNC_NONE, + .older_than_this = NULL, + .range_cyclic = 1, + .nr_to_write = 1024, + }; + + writeback_inodes_wbc(&wbc); +} + +/* + * kupdated() used to do this. We cannot do it from the bdi_forker_task() + * or we risk deadlocking on ->s_umount. The longer term solution would be + * to implement sync_supers_bdi() or similar and simply do it from the + * bdi writeback tasks individually. + */ +static int bdi_sync_supers(void *unused) +{ + set_user_nice(current, 0); + + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + + /* + * Do this periodically, like kupdated() did before. + */ + sync_supers(); + } + + return 0; +} + +static void arm_supers_timer(void) +{ + unsigned long next; + + next = msecs_to_jiffies(dirty_writeback_interval * 10) + jiffies; + mod_timer(&sync_supers_timer, round_jiffies_up(next)); +} + +static void sync_supers_timer_fn(unsigned long unused) +{ + wake_up_process(sync_supers_tsk); + arm_supers_timer(); +} + +static int bdi_forker_task(void *ptr) +{ + struct bdi_writeback *me = ptr; + + bdi_task_init(me->bdi, me); + + for (;;) { + struct backing_dev_info *bdi, *tmp; + struct bdi_writeback *wb; + + /* + * Temporary measure, we want to make sure we don't see + * dirty data on the default backing_dev_info + */ + if (wb_has_dirty_io(me) || !list_empty(&me->bdi->work_list)) + wb_do_writeback(me, 0); + + spin_lock(&bdi_lock); + + /* + * Check if any existing bdi's have dirty data without + * a thread registered. If so, set that up. + */ + list_for_each_entry_safe(bdi, tmp, &bdi_list, bdi_list) { + if (bdi->wb.task) + continue; + if (list_empty(&bdi->work_list) && + !bdi_has_dirty_io(bdi)) + continue; + + bdi_add_default_flusher_task(bdi); + } + + set_current_state(TASK_INTERRUPTIBLE); + + if (list_empty(&bdi_pending_list)) { + unsigned long wait; + + spin_unlock(&bdi_lock); + wait = msecs_to_jiffies(dirty_writeback_interval * 10); + schedule_timeout(wait); + try_to_freeze(); + continue; + } + + __set_current_state(TASK_RUNNING); + + /* + * This is our real job - check for pending entries in + * bdi_pending_list, and create the tasks that got added + */ + bdi = list_entry(bdi_pending_list.next, struct backing_dev_info, + bdi_list); + list_del_init(&bdi->bdi_list); + spin_unlock(&bdi_lock); + + wb = &bdi->wb; + wb->task = kthread_run(bdi_start_fn, wb, "flush-%s", + dev_name(bdi->dev)); + /* + * If task creation fails, then readd the bdi to + * the pending list and force writeout of the bdi + * from this forker thread. That will free some memory + * and we can try again. + */ + if (IS_ERR(wb->task)) { + wb->task = NULL; + + /* + * Add this 'bdi' to the back, so we get + * a chance to flush other bdi's to free + * memory. + */ + spin_lock(&bdi_lock); + list_add_tail(&bdi->bdi_list, &bdi_pending_list); + spin_unlock(&bdi_lock); + + bdi_flush_io(bdi); + } + } + + return 0; +} + +/* + * Add the default flusher task that gets created for any bdi + * that has dirty data pending writeout + */ +void static bdi_add_default_flusher_task(struct backing_dev_info *bdi) +{ + if (!bdi_cap_writeback_dirty(bdi)) + return; + + /* + * Check with the helper whether to proceed adding a task. Will only + * abort if we two or more simultanous calls to + * bdi_add_default_flusher_task() occured, further additions will block + * waiting for previous additions to finish. + */ + if (!test_and_set_bit(BDI_pending, &bdi->state)) { + list_move_tail(&bdi->bdi_list, &bdi_pending_list); + + /* + * We are now on the pending list, wake up bdi_forker_task() + * to finish the job and add us back to the active bdi_list + */ + wake_up_process(default_backing_dev_info.wb.task); + } +} + int bdi_register(struct backing_dev_info *bdi, struct device *parent, const char *fmt, ...) { @@ -213,13 +469,34 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent, goto exit; } - mutex_lock(&bdi_lock); + spin_lock(&bdi_lock); list_add_tail(&bdi->bdi_list, &bdi_list); - mutex_unlock(&bdi_lock); + spin_unlock(&bdi_lock); bdi->dev = dev; - bdi_debug_register(bdi, dev_name(dev)); + /* + * Just start the forker thread for our default backing_dev_info, + * and add other bdi's to the list. They will get a thread created + * on-demand when they need it. + */ + if (bdi_cap_flush_forker(bdi)) { + struct bdi_writeback *wb = &bdi->wb; + + wb->task = kthread_run(bdi_forker_task, wb, "bdi-%s", + dev_name(dev)); + if (IS_ERR(wb->task)) { + wb->task = NULL; + ret = -ENOMEM; + + spin_lock(&bdi_lock); + list_del(&bdi->bdi_list); + spin_unlock(&bdi_lock); + goto exit; + } + } + + bdi_debug_register(bdi, dev_name(dev)); exit: return ret; } @@ -231,17 +508,42 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev) } EXPORT_SYMBOL(bdi_register_dev); -static void bdi_remove_from_list(struct backing_dev_info *bdi) +/* + * Remove bdi from the global list and shutdown any threads we have running + */ +static void bdi_wb_shutdown(struct backing_dev_info *bdi) { - mutex_lock(&bdi_lock); + struct bdi_writeback *wb; + + if (!bdi_cap_writeback_dirty(bdi)) + return; + + /* + * If setup is pending, wait for that to complete first + */ + wait_on_bit(&bdi->state, BDI_pending, bdi_sched_wait, + TASK_UNINTERRUPTIBLE); + + /* + * Make sure nobody finds us on the bdi_list anymore + */ + spin_lock(&bdi_lock); list_del(&bdi->bdi_list); - mutex_unlock(&bdi_lock); + spin_unlock(&bdi_lock); + + /* + * Finally, kill the kernel threads. We don't need to be RCU + * safe anymore, since the bdi is gone from visibility. + */ + list_for_each_entry(wb, &bdi->wb_list, list) + kthread_stop(wb->task); } void bdi_unregister(struct backing_dev_info *bdi) { if (bdi->dev) { - bdi_remove_from_list(bdi); + if (!bdi_cap_flush_forker(bdi)) + bdi_wb_shutdown(bdi); bdi_debug_unregister(bdi); device_unregister(bdi->dev); bdi->dev = NULL; @@ -251,18 +553,25 @@ EXPORT_SYMBOL(bdi_unregister); int bdi_init(struct backing_dev_info *bdi) { - int i; - int err; + int i, err; bdi->dev = NULL; bdi->min_ratio = 0; bdi->max_ratio = 100; bdi->max_prop_frac = PROP_FRAC_BASE; + spin_lock_init(&bdi->wb_lock); INIT_LIST_HEAD(&bdi->bdi_list); - INIT_LIST_HEAD(&bdi->b_io); - INIT_LIST_HEAD(&bdi->b_dirty); - INIT_LIST_HEAD(&bdi->b_more_io); + INIT_LIST_HEAD(&bdi->wb_list); + INIT_LIST_HEAD(&bdi->work_list); + + bdi_wb_init(&bdi->wb, bdi); + + /* + * Just one thread support for now, hard code mask and count + */ + bdi->wb_mask = 1; + bdi->wb_cnt = 1; for (i = 0; i < NR_BDI_STAT_ITEMS; i++) { err = percpu_counter_init(&bdi->bdi_stat[i], 0); @@ -277,8 +586,6 @@ int bdi_init(struct backing_dev_info *bdi) err: while (i--) percpu_counter_destroy(&bdi->bdi_stat[i]); - - bdi_remove_from_list(bdi); } return err; @@ -289,9 +596,7 @@ void bdi_destroy(struct backing_dev_info *bdi) { int i; - WARN_ON(!list_empty(&bdi->b_dirty)); - WARN_ON(!list_empty(&bdi->b_io)); - WARN_ON(!list_empty(&bdi->b_more_io)); + WARN_ON(bdi_has_dirty_io(bdi)); bdi_unregister(bdi); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index f8341b6..25e7770 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -36,15 +36,6 @@ #include /* - * The maximum number of pages to writeout in a single bdflush/kupdate - * operation. We do this so we don't hold I_SYNC against an inode for - * enormous amounts of time, which would block a userspace task which has - * been forced to throttle against that inode. Also, the code reevaluates - * the dirty each time it has written this many pages. - */ -#define MAX_WRITEBACK_PAGES 1024 - -/* * After a CPU has dirtied this many pages, balance_dirty_pages_ratelimited * will look to see if it needs to force writeback or throttling. */ @@ -117,8 +108,6 @@ EXPORT_SYMBOL(laptop_mode); /* End of sysctl-exported parameters */ -static void background_writeout(unsigned long _min_pages); - /* * Scale the writeback cache size proportional to the relative writeout speeds. * @@ -326,7 +315,7 @@ int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio) { int ret = 0; - mutex_lock(&bdi_lock); + spin_lock(&bdi_lock); if (min_ratio > bdi->max_ratio) { ret = -EINVAL; } else { @@ -338,7 +327,7 @@ int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio) ret = -EINVAL; } } - mutex_unlock(&bdi_lock); + spin_unlock(&bdi_lock); return ret; } @@ -350,14 +339,14 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned max_ratio) if (max_ratio > 100) return -EINVAL; - mutex_lock(&bdi_lock); + spin_lock(&bdi_lock); if (bdi->min_ratio > max_ratio) { ret = -EINVAL; } else { bdi->max_ratio = max_ratio; bdi->max_prop_frac = (PROP_FRAC_BASE * max_ratio) / 100; } - mutex_unlock(&bdi_lock); + spin_unlock(&bdi_lock); return ret; } @@ -543,7 +532,7 @@ static void balance_dirty_pages(struct address_space *mapping) * up. */ if (bdi_nr_reclaimable > bdi_thresh) { - writeback_inodes(&wbc); + writeback_inodes_wbc(&wbc); pages_written += write_chunk - wbc.nr_to_write; get_dirty_limits(&background_thresh, &dirty_thresh, &bdi_thresh, bdi); @@ -572,7 +561,7 @@ static void balance_dirty_pages(struct address_space *mapping) if (pages_written >= write_chunk) break; /* We've done our duty */ - congestion_wait(BLK_RW_ASYNC, HZ/10); + schedule_timeout(1); } if (bdi_nr_reclaimable + bdi_nr_writeback < bdi_thresh && @@ -591,10 +580,18 @@ static void balance_dirty_pages(struct address_space *mapping) * background_thresh, to keep the amount of dirty memory low. */ if ((laptop_mode && pages_written) || - (!laptop_mode && (global_page_state(NR_FILE_DIRTY) - + global_page_state(NR_UNSTABLE_NFS) - > background_thresh))) - pdflush_operation(background_writeout, 0); + (!laptop_mode && ((nr_writeback = global_page_state(NR_FILE_DIRTY) + + global_page_state(NR_UNSTABLE_NFS)) + > background_thresh))) { + struct writeback_control wbc = { + .bdi = bdi, + .sync_mode = WB_SYNC_NONE, + .nr_to_write = nr_writeback, + }; + + + bdi_start_writeback(&wbc); + } } void set_page_dirty_balance(struct page *page, int page_mkwrite) @@ -678,153 +675,35 @@ void throttle_vm_writeout(gfp_t gfp_mask) } } -/* - * writeback at least _min_pages, and keep writing until the amount of dirty - * memory is less than the background threshold, or until we're all clean. - */ -static void background_writeout(unsigned long _min_pages) -{ - long min_pages = _min_pages; - struct writeback_control wbc = { - .bdi = NULL, - .sync_mode = WB_SYNC_NONE, - .older_than_this = NULL, - .nr_to_write = 0, - .nonblocking = 1, - .range_cyclic = 1, - }; - - for ( ; ; ) { - unsigned long background_thresh; - unsigned long dirty_thresh; - - get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL); - if (global_page_state(NR_FILE_DIRTY) + - global_page_state(NR_UNSTABLE_NFS) < background_thresh - && min_pages <= 0) - break; - wbc.more_io = 0; - wbc.encountered_congestion = 0; - wbc.nr_to_write = MAX_WRITEBACK_PAGES; - wbc.pages_skipped = 0; - writeback_inodes(&wbc); - min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; - if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) { - /* Wrote less than expected */ - if (wbc.encountered_congestion || wbc.more_io) - congestion_wait(BLK_RW_ASYNC, HZ/10); - else - break; - } - } -} - -/* - * Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back - * the whole world. Returns 0 if a pdflush thread was dispatched. Returns - * -1 if all pdflush threads were busy. - */ -int wakeup_pdflush(long nr_pages) -{ - if (nr_pages == 0) - nr_pages = global_page_state(NR_FILE_DIRTY) + - global_page_state(NR_UNSTABLE_NFS); - return pdflush_operation(background_writeout, nr_pages); -} - -static void wb_timer_fn(unsigned long unused); static void laptop_timer_fn(unsigned long unused); -static DEFINE_TIMER(wb_timer, wb_timer_fn, 0, 0); static DEFINE_TIMER(laptop_mode_wb_timer, laptop_timer_fn, 0, 0); /* - * Periodic writeback of "old" data. - * - * Define "old": the first time one of an inode's pages is dirtied, we mark the - * dirtying-time in the inode's address_space. So this periodic writeback code - * just walks the superblock inode list, writing back any inodes which are - * older than a specific point in time. - * - * Try to run once per dirty_writeback_interval. But if a writeback event - * takes longer than a dirty_writeback_interval interval, then leave a - * one-second gap. - * - * older_than_this takes precedence over nr_to_write. So we'll only write back - * all dirty pages if they are all attached to "old" mappings. - */ -static void wb_kupdate(unsigned long arg) -{ - unsigned long oldest_jif; - unsigned long start_jif; - unsigned long next_jif; - long nr_to_write; - struct writeback_control wbc = { - .bdi = NULL, - .sync_mode = WB_SYNC_NONE, - .older_than_this = &oldest_jif, - .nr_to_write = 0, - .nonblocking = 1, - .for_kupdate = 1, - .range_cyclic = 1, - }; - - sync_supers(); - - oldest_jif = jiffies - msecs_to_jiffies(dirty_expire_interval * 10); - start_jif = jiffies; - next_jif = start_jif + msecs_to_jiffies(dirty_writeback_interval * 10); - nr_to_write = global_page_state(NR_FILE_DIRTY) + - global_page_state(NR_UNSTABLE_NFS) + - (inodes_stat.nr_inodes - inodes_stat.nr_unused); - while (nr_to_write > 0) { - wbc.more_io = 0; - wbc.encountered_congestion = 0; - wbc.nr_to_write = MAX_WRITEBACK_PAGES; - writeback_inodes(&wbc); - if (wbc.nr_to_write > 0) { - if (wbc.encountered_congestion || wbc.more_io) - congestion_wait(BLK_RW_ASYNC, HZ/10); - else - break; /* All the old data is written */ - } - nr_to_write -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; - } - if (time_before(next_jif, jiffies + HZ)) - next_jif = jiffies + HZ; - if (dirty_writeback_interval) - mod_timer(&wb_timer, next_jif); -} - -/* * sysctl handler for /proc/sys/vm/dirty_writeback_centisecs */ int dirty_writeback_centisecs_handler(ctl_table *table, int write, struct file *file, void __user *buffer, size_t *length, loff_t *ppos) { proc_dointvec(table, write, file, buffer, length, ppos); - if (dirty_writeback_interval) - mod_timer(&wb_timer, jiffies + - msecs_to_jiffies(dirty_writeback_interval * 10)); - else - del_timer(&wb_timer); return 0; } -static void wb_timer_fn(unsigned long unused) -{ - if (pdflush_operation(wb_kupdate, 0) < 0) - mod_timer(&wb_timer, jiffies + HZ); /* delay 1 second */ -} - -static void laptop_flush(unsigned long unused) +static void do_laptop_sync(struct work_struct *work) { - sys_sync(); + wakeup_flusher_threads(0); + kfree(work); } static void laptop_timer_fn(unsigned long unused) { - pdflush_operation(laptop_flush, 0); + struct work_struct *work; + + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (work) { + INIT_WORK(work, do_laptop_sync); + schedule_work(work); + } } /* @@ -907,8 +786,6 @@ void __init page_writeback_init(void) { int shift; - mod_timer(&wb_timer, - jiffies + msecs_to_jiffies(dirty_writeback_interval * 10)); writeback_set_ratelimit(); register_cpu_notifier(&ratelimit_nb); diff --git a/mm/vmscan.c b/mm/vmscan.c index 94e86dd..ba8228e 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1720,7 +1720,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, */ if (total_scanned > sc->swap_cluster_max + sc->swap_cluster_max / 2) { - wakeup_pdflush(laptop_mode ? 0 : total_scanned); + wakeup_flusher_threads(laptop_mode ? 0 : total_scanned); sc->may_writepage = 1; } -- cgit v0.10.2 From d0bceac747b547c0b4769b91fec7d3c15600153f Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 18 May 2009 08:20:32 +0200 Subject: writeback: get rid of pdflush completely It is now unused, so kill it off. Signed-off-by: Jens Axboe diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 7f6dae8..2e601ce 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -30,6 +30,11 @@ #define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info) /* + * We don't actually have pdflush, but this one is exported though /proc... + */ +int nr_pdflush_threads; + +/* * Work items for the bdi_writeback threads */ struct bdi_work { diff --git a/include/linux/writeback.h b/include/linux/writeback.h index cef7552..78b1e46 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -14,17 +14,6 @@ extern struct list_head inode_in_use; extern struct list_head inode_unused; /* - * Yes, writeback.h requires sched.h - * No, sched.h is not included from here. - */ -static inline int task_is_pdflush(struct task_struct *task) -{ - return task->flags & PF_FLUSHER; -} - -#define current_is_pdflush() task_is_pdflush(current) - -/* * fs/fs-writeback.c */ enum writeback_sync_modes { @@ -155,7 +144,6 @@ balance_dirty_pages_ratelimited(struct address_space *mapping) typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc, void *data); -int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0); int generic_writepages(struct address_space *mapping, struct writeback_control *wbc); int write_cache_pages(struct address_space *mapping, diff --git a/mm/Makefile b/mm/Makefile index 5e0bd64..147a7a7 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -8,7 +8,7 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \ vmalloc.o obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ - maccess.o page_alloc.o page-writeback.o pdflush.o \ + maccess.o page_alloc.o page-writeback.o \ readahead.o swap.o truncate.o vmscan.o shmem.o \ prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \ page_isolation.o mm_init.o $(mmu-y) diff --git a/mm/pdflush.c b/mm/pdflush.c deleted file mode 100644 index 235ac44..0000000 --- a/mm/pdflush.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * mm/pdflush.c - worker threads for writing back filesystem data - * - * Copyright (C) 2002, Linus Torvalds. - * - * 09Apr2002 Andrew Morton - * Initial version - * 29Feb2004 kaos@sgi.com - * Move worker thread creation to kthread to avoid chewing - * up stack space with nested calls to kernel_thread. - */ - -#include -#include -#include -#include -#include -#include -#include -#include /* Needed by writeback.h */ -#include /* Prototypes pdflush_operation() */ -#include -#include -#include - - -/* - * Minimum and maximum number of pdflush instances - */ -#define MIN_PDFLUSH_THREADS 2 -#define MAX_PDFLUSH_THREADS 8 - -static void start_one_pdflush_thread(void); - - -/* - * The pdflush threads are worker threads for writing back dirty data. - * Ideally, we'd like one thread per active disk spindle. But the disk - * topology is very hard to divine at this level. Instead, we take - * care in various places to prevent more than one pdflush thread from - * performing writeback against a single filesystem. pdflush threads - * have the PF_FLUSHER flag set in current->flags to aid in this. - */ - -/* - * All the pdflush threads. Protected by pdflush_lock - */ -static LIST_HEAD(pdflush_list); -static DEFINE_SPINLOCK(pdflush_lock); - -/* - * The count of currently-running pdflush threads. Protected - * by pdflush_lock. - * - * Readable by sysctl, but not writable. Published to userspace at - * /proc/sys/vm/nr_pdflush_threads. - */ -int nr_pdflush_threads = 0; - -/* - * The time at which the pdflush thread pool last went empty - */ -static unsigned long last_empty_jifs; - -/* - * The pdflush thread. - * - * Thread pool management algorithm: - * - * - The minimum and maximum number of pdflush instances are bound - * by MIN_PDFLUSH_THREADS and MAX_PDFLUSH_THREADS. - * - * - If there have been no idle pdflush instances for 1 second, create - * a new one. - * - * - If the least-recently-went-to-sleep pdflush thread has been asleep - * for more than one second, terminate a thread. - */ - -/* - * A structure for passing work to a pdflush thread. Also for passing - * state information between pdflush threads. Protected by pdflush_lock. - */ -struct pdflush_work { - struct task_struct *who; /* The thread */ - void (*fn)(unsigned long); /* A callback function */ - unsigned long arg0; /* An argument to the callback */ - struct list_head list; /* On pdflush_list, when idle */ - unsigned long when_i_went_to_sleep; -}; - -static int __pdflush(struct pdflush_work *my_work) -{ - current->flags |= PF_FLUSHER | PF_SWAPWRITE; - set_freezable(); - my_work->fn = NULL; - my_work->who = current; - INIT_LIST_HEAD(&my_work->list); - - spin_lock_irq(&pdflush_lock); - for ( ; ; ) { - struct pdflush_work *pdf; - - set_current_state(TASK_INTERRUPTIBLE); - list_move(&my_work->list, &pdflush_list); - my_work->when_i_went_to_sleep = jiffies; - spin_unlock_irq(&pdflush_lock); - schedule(); - try_to_freeze(); - spin_lock_irq(&pdflush_lock); - if (!list_empty(&my_work->list)) { - /* - * Someone woke us up, but without removing our control - * structure from the global list. swsusp will do this - * in try_to_freeze()->refrigerator(). Handle it. - */ - my_work->fn = NULL; - continue; - } - if (my_work->fn == NULL) { - printk("pdflush: bogus wakeup\n"); - continue; - } - spin_unlock_irq(&pdflush_lock); - - (*my_work->fn)(my_work->arg0); - - spin_lock_irq(&pdflush_lock); - - /* - * Thread creation: For how long have there been zero - * available threads? - * - * To throttle creation, we reset last_empty_jifs. - */ - if (time_after(jiffies, last_empty_jifs + 1 * HZ)) { - if (list_empty(&pdflush_list)) { - if (nr_pdflush_threads < MAX_PDFLUSH_THREADS) { - last_empty_jifs = jiffies; - nr_pdflush_threads++; - spin_unlock_irq(&pdflush_lock); - start_one_pdflush_thread(); - spin_lock_irq(&pdflush_lock); - } - } - } - - my_work->fn = NULL; - - /* - * Thread destruction: For how long has the sleepiest - * thread slept? - */ - if (list_empty(&pdflush_list)) - continue; - if (nr_pdflush_threads <= MIN_PDFLUSH_THREADS) - continue; - pdf = list_entry(pdflush_list.prev, struct pdflush_work, list); - if (time_after(jiffies, pdf->when_i_went_to_sleep + 1 * HZ)) { - /* Limit exit rate */ - pdf->when_i_went_to_sleep = jiffies; - break; /* exeunt */ - } - } - nr_pdflush_threads--; - spin_unlock_irq(&pdflush_lock); - return 0; -} - -/* - * Of course, my_work wants to be just a local in __pdflush(). It is - * separated out in this manner to hopefully prevent the compiler from - * performing unfortunate optimisations against the auto variables. Because - * these are visible to other tasks and CPUs. (No problem has actually - * been observed. This is just paranoia). - */ -static int pdflush(void *dummy) -{ - struct pdflush_work my_work; - cpumask_var_t cpus_allowed; - - /* - * Since the caller doesn't even check kthread_run() worked, let's not - * freak out too much if this fails. - */ - if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) { - printk(KERN_WARNING "pdflush failed to allocate cpumask\n"); - return 0; - } - - /* - * pdflush can spend a lot of time doing encryption via dm-crypt. We - * don't want to do that at keventd's priority. - */ - set_user_nice(current, 0); - - /* - * Some configs put our parent kthread in a limited cpuset, - * which kthread() overrides, forcing cpus_allowed == cpu_all_mask. - * Our needs are more modest - cut back to our cpusets cpus_allowed. - * This is needed as pdflush's are dynamically created and destroyed. - * The boottime pdflush's are easily placed w/o these 2 lines. - */ - cpuset_cpus_allowed(current, cpus_allowed); - set_cpus_allowed_ptr(current, cpus_allowed); - free_cpumask_var(cpus_allowed); - - return __pdflush(&my_work); -} - -/* - * Attempt to wake up a pdflush thread, and get it to do some work for you. - * Returns zero if it indeed managed to find a worker thread, and passed your - * payload to it. - */ -int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0) -{ - unsigned long flags; - int ret = 0; - - BUG_ON(fn == NULL); /* Hard to diagnose if it's deferred */ - - spin_lock_irqsave(&pdflush_lock, flags); - if (list_empty(&pdflush_list)) { - ret = -1; - } else { - struct pdflush_work *pdf; - - pdf = list_entry(pdflush_list.next, struct pdflush_work, list); - list_del_init(&pdf->list); - if (list_empty(&pdflush_list)) - last_empty_jifs = jiffies; - pdf->fn = fn; - pdf->arg0 = arg0; - wake_up_process(pdf->who); - } - spin_unlock_irqrestore(&pdflush_lock, flags); - - return ret; -} - -static void start_one_pdflush_thread(void) -{ - struct task_struct *k; - - k = kthread_run(pdflush, NULL, "pdflush"); - if (unlikely(IS_ERR(k))) { - spin_lock_irq(&pdflush_lock); - nr_pdflush_threads--; - spin_unlock_irq(&pdflush_lock); - } -} - -static int __init pdflush_init(void) -{ - int i; - - /* - * Pre-set nr_pdflush_threads... If we fail to create, - * the count will be decremented. - */ - nr_pdflush_threads = MIN_PDFLUSH_THREADS; - - for (i = 0; i < MIN_PDFLUSH_THREADS; i++) - start_one_pdflush_thread(); - return 0; -} - -module_init(pdflush_init); -- cgit v0.10.2 From f09b00d3e789a88fa6c7c03cedc62cb65c1de0cb Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 25 May 2009 09:08:21 +0200 Subject: writeback: add some debug inode list counters to bdi stats Add some debug entries to be able to inspect the internal state of the writeback details. Signed-off-by: Jens Axboe diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 7f3fa79..22c45e9 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -52,9 +52,29 @@ static void bdi_debug_init(void) static int bdi_debug_stats_show(struct seq_file *m, void *v) { struct backing_dev_info *bdi = m->private; + struct bdi_writeback *wb; unsigned long background_thresh; unsigned long dirty_thresh; unsigned long bdi_thresh; + unsigned long nr_dirty, nr_io, nr_more_io, nr_wb; + struct inode *inode; + + /* + * inode lock is enough here, the bdi->wb_list is protected by + * RCU on the reader side + */ + nr_wb = nr_dirty = nr_io = nr_more_io = 0; + spin_lock(&inode_lock); + list_for_each_entry(wb, &bdi->wb_list, list) { + nr_wb++; + list_for_each_entry(inode, &wb->b_dirty, i_list) + nr_dirty++; + list_for_each_entry(inode, &wb->b_io, i_list) + nr_io++; + list_for_each_entry(inode, &wb->b_more_io, i_list) + nr_more_io++; + } + spin_unlock(&inode_lock); get_dirty_limits(&background_thresh, &dirty_thresh, &bdi_thresh, bdi); @@ -64,12 +84,22 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v) "BdiReclaimable: %8lu kB\n" "BdiDirtyThresh: %8lu kB\n" "DirtyThresh: %8lu kB\n" - "BackgroundThresh: %8lu kB\n", + "BackgroundThresh: %8lu kB\n" + "WriteBack threads:%8lu\n" + "b_dirty: %8lu\n" + "b_io: %8lu\n" + "b_more_io: %8lu\n" + "bdi_list: %8u\n" + "state: %8lx\n" + "wb_mask: %8lx\n" + "wb_list: %8u\n" + "wb_cnt: %8u\n", (unsigned long) K(bdi_stat(bdi, BDI_WRITEBACK)), (unsigned long) K(bdi_stat(bdi, BDI_RECLAIMABLE)), - K(bdi_thresh), - K(dirty_thresh), - K(background_thresh)); + K(bdi_thresh), K(dirty_thresh), + K(background_thresh), nr_wb, nr_dirty, nr_io, nr_more_io, + !list_empty(&bdi->bdi_list), bdi->state, bdi->wb_mask, + !list_empty(&bdi->wb_list), bdi->wb_cnt); #undef K return 0; -- cgit v0.10.2 From d993831fa7ffeb89e994f046f93eeb09ec91df08 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 12 Jun 2009 14:45:52 +0200 Subject: writeback: add name to backing_dev_info This enables us to track who does what and print info. Its main use is catching dirty inodes on the default_backing_dev_info, so we can fix that up. Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index e3299a7..e695634 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -501,6 +501,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; q->backing_dev_info.state = 0; q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY; + q->backing_dev_info.name = "block"; err = bdi_init(&q->backing_dev_info); if (err) { diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 1e15889..95d3449 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -268,6 +268,7 @@ aoeblk_gdalloc(void *vp) if (!d->blkq) goto err_mempool; blk_queue_make_request(d->blkq, aoeblk_make_request); + d->blkq->backing_dev_info.name = "aoe"; if (bdi_init(&d->blkq->backing_dev_info)) goto err_blkq; spin_lock_irqsave(&d->lock, flags); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index afa8813..645237b 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -822,6 +822,7 @@ static const struct file_operations zero_fops = { * - permits private mappings, "copies" are taken of the source of zeros */ static struct backing_dev_info zero_bdi = { + .name = "char/mem", .capabilities = BDI_CAP_MAP_COPY, }; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e83be2e..15831d5 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1352,6 +1352,7 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) { int err; + bdi->name = "btrfs"; bdi->capabilities = BDI_CAP_MAP_COPY; err = bdi_init(bdi); if (err) diff --git a/fs/char_dev.c b/fs/char_dev.c index a173551..7c27a8e 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -31,6 +31,7 @@ * - no readahead or I/O queue unplugging required */ struct backing_dev_info directly_mappable_cdev_bdi = { + .name = "char", .capabilities = ( #ifdef CONFIG_MMU /* permit private copies of the data to be taken */ diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 4921e742..a2f7460 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -51,6 +51,7 @@ static const struct address_space_operations configfs_aops = { }; static struct backing_dev_info configfs_backing_dev_info = { + .name = "configfs", .ra_pages = 0, /* No readahead */ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, }; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index f91ccc4..4567db6 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -801,6 +801,7 @@ static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb) { int err; + fc->bdi.name = "fuse"; fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; fc->bdi.unplug_io_fn = default_unplug_io_fn; /* fuse does it's own writeback accounting */ diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index cb88dac..a93b885 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -44,6 +44,7 @@ static const struct inode_operations hugetlbfs_dir_inode_operations; static const struct inode_operations hugetlbfs_inode_operations; static struct backing_dev_info hugetlbfs_backing_dev_info = { + .name = "hugetlbfs", .ra_pages = 0, /* No readahead */ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, }; diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 8d25ccb..c6be84a 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -879,6 +879,7 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo * server->rsize = NFS_MAX_FILE_IO_SIZE; server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + server->backing_dev_info.name = "nfs"; server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD; if (server->wsize > max_rpc_payload) diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index 1c9efb4..02bf178 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c @@ -325,6 +325,7 @@ clear_fields: } static struct backing_dev_info dlmfs_backing_dev_info = { + .name = "ocfs2-dlmfs", .ra_pages = 0, /* No readahead */ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, }; diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 0ff7566..a7f0110 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -46,6 +46,7 @@ static const struct super_operations ramfs_ops; static const struct inode_operations ramfs_dir_inode_operations; static struct backing_dev_info ramfs_backing_dev_info = { + .name = "ramfs", .ra_pages = 0, /* No readahead */ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY | diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 555f0ff..e57f98e 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -29,6 +29,7 @@ static const struct address_space_operations sysfs_aops = { }; static struct backing_dev_info sysfs_backing_dev_info = { + .name = "sysfs", .ra_pages = 0, /* No readahead */ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, }; diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 8d6050a..51763aa 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1965,6 +1965,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) * * Read-ahead will be disabled because @c->bdi.ra_pages is 0. */ + c->bdi.name = "ubifs", c->bdi.capabilities = BDI_CAP_MAP_COPY; c->bdi.unplug_io_fn = default_unplug_io_fn; err = bdi_init(&c->bdi); diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index d045f5f..2f218b7 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -66,6 +66,8 @@ struct backing_dev_info { void (*unplug_io_fn)(struct backing_dev_info *, struct page *); void *unplug_io_data; + char *name; + struct percpu_counter bdi_stat[NR_BDI_STAT_ITEMS]; struct prop_local_percpu completions; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index b6eadfe..c7ece8f 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -600,6 +600,7 @@ static struct inode_operations cgroup_dir_inode_operations; static struct file_operations proc_cgroupstats_operations; static struct backing_dev_info cgroup_backing_dev_info = { + .name = "cgroup", .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, }; diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 22c45e9..5cb32c5 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -17,6 +17,7 @@ void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) EXPORT_SYMBOL(default_unplug_io_fn); struct backing_dev_info default_backing_dev_info = { + .name = "default", .ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_CACHE_SIZE, .state = 0, .capabilities = BDI_CAP_MAP_COPY, diff --git a/mm/swap_state.c b/mm/swap_state.c index 42cd38e..5ae6b8b 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -34,6 +34,7 @@ static const struct address_space_operations swap_aops = { }; static struct backing_dev_info swap_backing_dev_info = { + .name = "swap", .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_SWAP_BACKED, .unplug_io_fn = swap_unplug_io_fn, }; -- cgit v0.10.2 From 500b067c5e6ceea49cf280a02597b1169320e08c Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 9 Sep 2009 09:10:25 +0200 Subject: writeback: check for registered bdi in flusher add and inode dirty Also a debugging aid. We want to catch dirty inodes being added to backing devices that don't do writeback. Signed-off-by: Jens Axboe diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 2e601ce..da86ef5 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1046,6 +1046,14 @@ void __mark_inode_dirty(struct inode *inode, int flags) */ if (!was_dirty) { struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; + struct backing_dev_info *bdi = wb->bdi; + + if (bdi_cap_writeback_dirty(bdi) && + !test_bit(BDI_registered, &bdi->state)) { + WARN_ON(1); + printk(KERN_ERR "bdi-%s not registered\n", + bdi->name); + } inode->dirtied_when = jiffies; list_move(&inode->i_list, &wb->b_dirty); diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 2f218b7..f169bcb 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -29,6 +29,7 @@ enum bdi_state { BDI_wb_alloc, /* Default embedded wb allocated */ BDI_async_congested, /* The async (write) queue is getting full */ BDI_sync_congested, /* The sync queue is getting full */ + BDI_registered, /* bdi_register() was done */ BDI_unused, /* Available bits start here */ }; diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 5cb32c5..d3ca0da 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -465,6 +465,12 @@ void static bdi_add_default_flusher_task(struct backing_dev_info *bdi) if (!bdi_cap_writeback_dirty(bdi)) return; + if (WARN_ON(!test_bit(BDI_registered, &bdi->state))) { + printk(KERN_ERR "bdi %p/%s is not registered!\n", + bdi, bdi->name); + return; + } + /* * Check with the helper whether to proceed adding a task. Will only * abort if we two or more simultanous calls to @@ -528,6 +534,7 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent, } bdi_debug_register(bdi, dev_name(dev)); + set_bit(BDI_registered, &bdi->state); exit: return ret; } -- cgit v0.10.2 From 1f1148c88ad37c87f14d2153416a605bf0aeaf74 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Fri, 11 Sep 2009 10:28:14 +0200 Subject: [S390] cio: fix ineffective verify event Path verification events occurring for offline devices are currently ignored. As a result, offline devices are not removed, even though they might no longer be accessible (for example because the last path to the device was varied offline). Fix this by scheduling a status evaluation for the affected subchannel when a path verification event occurs. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 3db88c5..b8bdb0d 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -731,6 +731,17 @@ static void ccw_device_generic_notoper(struct ccw_device *cdev, } /* + * Handle path verification event in offline state. + */ +static void ccw_device_offline_verify(struct ccw_device *cdev, + enum dev_event dev_event) +{ + struct subchannel *sch = to_subchannel(cdev->dev.parent); + + css_schedule_eval(sch->schid); +} + +/* * Handle path verification event. */ static void @@ -1149,7 +1160,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_offline_irq, [DEV_EVENT_TIMEOUT] = ccw_device_nop, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_EVENT_VERIFY] = ccw_device_offline_verify, }, [DEV_STATE_VERIFY] = { [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, -- cgit v0.10.2 From 62733e5a5a480a893e56fa6133ae90904d857bc4 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:28:15 +0200 Subject: [S390] cio: move scsw helper functions to header file All scsw helper functions are very short and usage of them shouldn't result in function calls. Therefore we move them to a separate header file. Also saves a lot of EXPORT_SYMBOLs. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/chsc.h b/arch/s390/include/asm/chsc.h index 807997f..4943654 100644 --- a/arch/s390/include/asm/chsc.h +++ b/arch/s390/include/asm/chsc.h @@ -125,4 +125,32 @@ struct chsc_cpd_info { #define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info) #define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal) +#ifdef __KERNEL__ + +struct css_general_char { + u64 : 12; + u32 dynio : 1; /* bit 12 */ + u32 : 28; + u32 aif : 1; /* bit 41 */ + u32 : 3; + u32 mcss : 1; /* bit 45 */ + u32 fcs : 1; /* bit 46 */ + u32 : 1; + u32 ext_mb : 1; /* bit 48 */ + u32 : 7; + u32 aif_tdd : 1; /* bit 56 */ + u32 : 1; + u32 qebsm : 1; /* bit 58 */ + u32 : 8; + u32 aif_osa : 1; /* bit 67 */ + u32 : 14; + u32 cib : 1; /* bit 82 */ + u32 : 5; + u32 fcx : 1; /* bit 88 */ + u32 : 7; +}__attribute__((packed)); + +extern struct css_general_char css_general_characteristics; + +#endif /* __KERNEL__ */ #endif diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h index 619bf94..e85679a 100644 --- a/arch/s390/include/asm/cio.h +++ b/arch/s390/include/asm/cio.h @@ -15,228 +15,7 @@ #define LPM_ANYPATH 0xff #define __MAX_CSSID 0 -/** - * struct cmd_scsw - command-mode subchannel status word - * @key: subchannel key - * @sctl: suspend control - * @eswf: esw format - * @cc: deferred condition code - * @fmt: format - * @pfch: prefetch - * @isic: initial-status interruption control - * @alcc: address-limit checking control - * @ssi: suppress-suspended interruption - * @zcc: zero condition code - * @ectl: extended control - * @pno: path not operational - * @res: reserved - * @fctl: function control - * @actl: activity control - * @stctl: status control - * @cpa: channel program address - * @dstat: device status - * @cstat: subchannel status - * @count: residual count - */ -struct cmd_scsw { - __u32 key : 4; - __u32 sctl : 1; - __u32 eswf : 1; - __u32 cc : 2; - __u32 fmt : 1; - __u32 pfch : 1; - __u32 isic : 1; - __u32 alcc : 1; - __u32 ssi : 1; - __u32 zcc : 1; - __u32 ectl : 1; - __u32 pno : 1; - __u32 res : 1; - __u32 fctl : 3; - __u32 actl : 7; - __u32 stctl : 5; - __u32 cpa; - __u32 dstat : 8; - __u32 cstat : 8; - __u32 count : 16; -} __attribute__ ((packed)); - -/** - * struct tm_scsw - transport-mode subchannel status word - * @key: subchannel key - * @eswf: esw format - * @cc: deferred condition code - * @fmt: format - * @x: IRB-format control - * @q: interrogate-complete - * @ectl: extended control - * @pno: path not operational - * @fctl: function control - * @actl: activity control - * @stctl: status control - * @tcw: TCW address - * @dstat: device status - * @cstat: subchannel status - * @fcxs: FCX status - * @schxs: subchannel-extended status - */ -struct tm_scsw { - u32 key:4; - u32 :1; - u32 eswf:1; - u32 cc:2; - u32 fmt:3; - u32 x:1; - u32 q:1; - u32 :1; - u32 ectl:1; - u32 pno:1; - u32 :1; - u32 fctl:3; - u32 actl:7; - u32 stctl:5; - u32 tcw; - u32 dstat:8; - u32 cstat:8; - u32 fcxs:8; - u32 schxs:8; -} __attribute__ ((packed)); - -/** - * union scsw - subchannel status word - * @cmd: command-mode SCSW - * @tm: transport-mode SCSW - */ -union scsw { - struct cmd_scsw cmd; - struct tm_scsw tm; -} __attribute__ ((packed)); - -int scsw_is_tm(union scsw *scsw); -u32 scsw_key(union scsw *scsw); -u32 scsw_eswf(union scsw *scsw); -u32 scsw_cc(union scsw *scsw); -u32 scsw_ectl(union scsw *scsw); -u32 scsw_pno(union scsw *scsw); -u32 scsw_fctl(union scsw *scsw); -u32 scsw_actl(union scsw *scsw); -u32 scsw_stctl(union scsw *scsw); -u32 scsw_dstat(union scsw *scsw); -u32 scsw_cstat(union scsw *scsw); -int scsw_is_solicited(union scsw *scsw); -int scsw_is_valid_key(union scsw *scsw); -int scsw_is_valid_eswf(union scsw *scsw); -int scsw_is_valid_cc(union scsw *scsw); -int scsw_is_valid_ectl(union scsw *scsw); -int scsw_is_valid_pno(union scsw *scsw); -int scsw_is_valid_fctl(union scsw *scsw); -int scsw_is_valid_actl(union scsw *scsw); -int scsw_is_valid_stctl(union scsw *scsw); -int scsw_is_valid_dstat(union scsw *scsw); -int scsw_is_valid_cstat(union scsw *scsw); -int scsw_cmd_is_valid_key(union scsw *scsw); -int scsw_cmd_is_valid_sctl(union scsw *scsw); -int scsw_cmd_is_valid_eswf(union scsw *scsw); -int scsw_cmd_is_valid_cc(union scsw *scsw); -int scsw_cmd_is_valid_fmt(union scsw *scsw); -int scsw_cmd_is_valid_pfch(union scsw *scsw); -int scsw_cmd_is_valid_isic(union scsw *scsw); -int scsw_cmd_is_valid_alcc(union scsw *scsw); -int scsw_cmd_is_valid_ssi(union scsw *scsw); -int scsw_cmd_is_valid_zcc(union scsw *scsw); -int scsw_cmd_is_valid_ectl(union scsw *scsw); -int scsw_cmd_is_valid_pno(union scsw *scsw); -int scsw_cmd_is_valid_fctl(union scsw *scsw); -int scsw_cmd_is_valid_actl(union scsw *scsw); -int scsw_cmd_is_valid_stctl(union scsw *scsw); -int scsw_cmd_is_valid_dstat(union scsw *scsw); -int scsw_cmd_is_valid_cstat(union scsw *scsw); -int scsw_cmd_is_solicited(union scsw *scsw); -int scsw_tm_is_valid_key(union scsw *scsw); -int scsw_tm_is_valid_eswf(union scsw *scsw); -int scsw_tm_is_valid_cc(union scsw *scsw); -int scsw_tm_is_valid_fmt(union scsw *scsw); -int scsw_tm_is_valid_x(union scsw *scsw); -int scsw_tm_is_valid_q(union scsw *scsw); -int scsw_tm_is_valid_ectl(union scsw *scsw); -int scsw_tm_is_valid_pno(union scsw *scsw); -int scsw_tm_is_valid_fctl(union scsw *scsw); -int scsw_tm_is_valid_actl(union scsw *scsw); -int scsw_tm_is_valid_stctl(union scsw *scsw); -int scsw_tm_is_valid_dstat(union scsw *scsw); -int scsw_tm_is_valid_cstat(union scsw *scsw); -int scsw_tm_is_valid_fcxs(union scsw *scsw); -int scsw_tm_is_valid_schxs(union scsw *scsw); -int scsw_tm_is_solicited(union scsw *scsw); - -#define SCSW_FCTL_CLEAR_FUNC 0x1 -#define SCSW_FCTL_HALT_FUNC 0x2 -#define SCSW_FCTL_START_FUNC 0x4 - -#define SCSW_ACTL_SUSPENDED 0x1 -#define SCSW_ACTL_DEVACT 0x2 -#define SCSW_ACTL_SCHACT 0x4 -#define SCSW_ACTL_CLEAR_PEND 0x8 -#define SCSW_ACTL_HALT_PEND 0x10 -#define SCSW_ACTL_START_PEND 0x20 -#define SCSW_ACTL_RESUME_PEND 0x40 - -#define SCSW_STCTL_STATUS_PEND 0x1 -#define SCSW_STCTL_SEC_STATUS 0x2 -#define SCSW_STCTL_PRIM_STATUS 0x4 -#define SCSW_STCTL_INTER_STATUS 0x8 -#define SCSW_STCTL_ALERT_STATUS 0x10 - -#define DEV_STAT_ATTENTION 0x80 -#define DEV_STAT_STAT_MOD 0x40 -#define DEV_STAT_CU_END 0x20 -#define DEV_STAT_BUSY 0x10 -#define DEV_STAT_CHN_END 0x08 -#define DEV_STAT_DEV_END 0x04 -#define DEV_STAT_UNIT_CHECK 0x02 -#define DEV_STAT_UNIT_EXCEP 0x01 - -#define SCHN_STAT_PCI 0x80 -#define SCHN_STAT_INCORR_LEN 0x40 -#define SCHN_STAT_PROG_CHECK 0x20 -#define SCHN_STAT_PROT_CHECK 0x10 -#define SCHN_STAT_CHN_DATA_CHK 0x08 -#define SCHN_STAT_CHN_CTRL_CHK 0x04 -#define SCHN_STAT_INTF_CTRL_CHK 0x02 -#define SCHN_STAT_CHAIN_CHECK 0x01 - -/* - * architectured values for first sense byte - */ -#define SNS0_CMD_REJECT 0x80 -#define SNS_CMD_REJECT SNS0_CMD_REJEC -#define SNS0_INTERVENTION_REQ 0x40 -#define SNS0_BUS_OUT_CHECK 0x20 -#define SNS0_EQUIPMENT_CHECK 0x10 -#define SNS0_DATA_CHECK 0x08 -#define SNS0_OVERRUN 0x04 -#define SNS0_INCOMPL_DOMAIN 0x01 - -/* - * architectured values for second sense byte - */ -#define SNS1_PERM_ERR 0x80 -#define SNS1_INV_TRACK_FORMAT 0x40 -#define SNS1_EOC 0x20 -#define SNS1_MESSAGE_TO_OPER 0x10 -#define SNS1_NO_REC_FOUND 0x08 -#define SNS1_FILE_PROTECTED 0x04 -#define SNS1_WRITE_INHIBITED 0x02 -#define SNS1_INPRECISE_END 0x01 - -/* - * architectured values for third sense byte - */ -#define SNS2_REQ_INH_WRITE 0x80 -#define SNS2_CORRECTABLE 0x40 -#define SNS2_FIRST_LOG_ERR 0x20 -#define SNS2_ENV_DATA_PRESENT 0x10 -#define SNS2_INPRECISE_END 0x04 +#include /** * struct ccw1 - channel command word diff --git a/arch/s390/include/asm/scsw.h b/arch/s390/include/asm/scsw.h new file mode 100644 index 0000000..de389cb --- /dev/null +++ b/arch/s390/include/asm/scsw.h @@ -0,0 +1,956 @@ +/* + * Helper functions for scsw access. + * + * Copyright IBM Corp. 2008,2009 + * Author(s): Peter Oberparleiter + */ + +#ifndef _ASM_S390_SCSW_H_ +#define _ASM_S390_SCSW_H_ + +#include +#include +#include + +/** + * struct cmd_scsw - command-mode subchannel status word + * @key: subchannel key + * @sctl: suspend control + * @eswf: esw format + * @cc: deferred condition code + * @fmt: format + * @pfch: prefetch + * @isic: initial-status interruption control + * @alcc: address-limit checking control + * @ssi: suppress-suspended interruption + * @zcc: zero condition code + * @ectl: extended control + * @pno: path not operational + * @res: reserved + * @fctl: function control + * @actl: activity control + * @stctl: status control + * @cpa: channel program address + * @dstat: device status + * @cstat: subchannel status + * @count: residual count + */ +struct cmd_scsw { + __u32 key : 4; + __u32 sctl : 1; + __u32 eswf : 1; + __u32 cc : 2; + __u32 fmt : 1; + __u32 pfch : 1; + __u32 isic : 1; + __u32 alcc : 1; + __u32 ssi : 1; + __u32 zcc : 1; + __u32 ectl : 1; + __u32 pno : 1; + __u32 res : 1; + __u32 fctl : 3; + __u32 actl : 7; + __u32 stctl : 5; + __u32 cpa; + __u32 dstat : 8; + __u32 cstat : 8; + __u32 count : 16; +} __attribute__ ((packed)); + +/** + * struct tm_scsw - transport-mode subchannel status word + * @key: subchannel key + * @eswf: esw format + * @cc: deferred condition code + * @fmt: format + * @x: IRB-format control + * @q: interrogate-complete + * @ectl: extended control + * @pno: path not operational + * @fctl: function control + * @actl: activity control + * @stctl: status control + * @tcw: TCW address + * @dstat: device status + * @cstat: subchannel status + * @fcxs: FCX status + * @schxs: subchannel-extended status + */ +struct tm_scsw { + u32 key:4; + u32 :1; + u32 eswf:1; + u32 cc:2; + u32 fmt:3; + u32 x:1; + u32 q:1; + u32 :1; + u32 ectl:1; + u32 pno:1; + u32 :1; + u32 fctl:3; + u32 actl:7; + u32 stctl:5; + u32 tcw; + u32 dstat:8; + u32 cstat:8; + u32 fcxs:8; + u32 schxs:8; +} __attribute__ ((packed)); + +/** + * union scsw - subchannel status word + * @cmd: command-mode SCSW + * @tm: transport-mode SCSW + */ +union scsw { + struct cmd_scsw cmd; + struct tm_scsw tm; +} __attribute__ ((packed)); + +#define SCSW_FCTL_CLEAR_FUNC 0x1 +#define SCSW_FCTL_HALT_FUNC 0x2 +#define SCSW_FCTL_START_FUNC 0x4 + +#define SCSW_ACTL_SUSPENDED 0x1 +#define SCSW_ACTL_DEVACT 0x2 +#define SCSW_ACTL_SCHACT 0x4 +#define SCSW_ACTL_CLEAR_PEND 0x8 +#define SCSW_ACTL_HALT_PEND 0x10 +#define SCSW_ACTL_START_PEND 0x20 +#define SCSW_ACTL_RESUME_PEND 0x40 + +#define SCSW_STCTL_STATUS_PEND 0x1 +#define SCSW_STCTL_SEC_STATUS 0x2 +#define SCSW_STCTL_PRIM_STATUS 0x4 +#define SCSW_STCTL_INTER_STATUS 0x8 +#define SCSW_STCTL_ALERT_STATUS 0x10 + +#define DEV_STAT_ATTENTION 0x80 +#define DEV_STAT_STAT_MOD 0x40 +#define DEV_STAT_CU_END 0x20 +#define DEV_STAT_BUSY 0x10 +#define DEV_STAT_CHN_END 0x08 +#define DEV_STAT_DEV_END 0x04 +#define DEV_STAT_UNIT_CHECK 0x02 +#define DEV_STAT_UNIT_EXCEP 0x01 + +#define SCHN_STAT_PCI 0x80 +#define SCHN_STAT_INCORR_LEN 0x40 +#define SCHN_STAT_PROG_CHECK 0x20 +#define SCHN_STAT_PROT_CHECK 0x10 +#define SCHN_STAT_CHN_DATA_CHK 0x08 +#define SCHN_STAT_CHN_CTRL_CHK 0x04 +#define SCHN_STAT_INTF_CTRL_CHK 0x02 +#define SCHN_STAT_CHAIN_CHECK 0x01 + +/* + * architectured values for first sense byte + */ +#define SNS0_CMD_REJECT 0x80 +#define SNS_CMD_REJECT SNS0_CMD_REJEC +#define SNS0_INTERVENTION_REQ 0x40 +#define SNS0_BUS_OUT_CHECK 0x20 +#define SNS0_EQUIPMENT_CHECK 0x10 +#define SNS0_DATA_CHECK 0x08 +#define SNS0_OVERRUN 0x04 +#define SNS0_INCOMPL_DOMAIN 0x01 + +/* + * architectured values for second sense byte + */ +#define SNS1_PERM_ERR 0x80 +#define SNS1_INV_TRACK_FORMAT 0x40 +#define SNS1_EOC 0x20 +#define SNS1_MESSAGE_TO_OPER 0x10 +#define SNS1_NO_REC_FOUND 0x08 +#define SNS1_FILE_PROTECTED 0x04 +#define SNS1_WRITE_INHIBITED 0x02 +#define SNS1_INPRECISE_END 0x01 + +/* + * architectured values for third sense byte + */ +#define SNS2_REQ_INH_WRITE 0x80 +#define SNS2_CORRECTABLE 0x40 +#define SNS2_FIRST_LOG_ERR 0x20 +#define SNS2_ENV_DATA_PRESENT 0x10 +#define SNS2_INPRECISE_END 0x04 + +/** + * scsw_is_tm - check for transport mode scsw + * @scsw: pointer to scsw + * + * Return non-zero if the specified scsw is a transport mode scsw, zero + * otherwise. + */ +static inline int scsw_is_tm(union scsw *scsw) +{ + return css_general_characteristics.fcx && (scsw->tm.x == 1); +} + +/** + * scsw_key - return scsw key field + * @scsw: pointer to scsw + * + * Return the value of the key field of the specified scsw, regardless of + * whether it is a transport mode or command mode scsw. + */ +static inline u32 scsw_key(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw->tm.key; + else + return scsw->cmd.key; +} + +/** + * scsw_eswf - return scsw eswf field + * @scsw: pointer to scsw + * + * Return the value of the eswf field of the specified scsw, regardless of + * whether it is a transport mode or command mode scsw. + */ +static inline u32 scsw_eswf(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw->tm.eswf; + else + return scsw->cmd.eswf; +} + +/** + * scsw_cc - return scsw cc field + * @scsw: pointer to scsw + * + * Return the value of the cc field of the specified scsw, regardless of + * whether it is a transport mode or command mode scsw. + */ +static inline u32 scsw_cc(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw->tm.cc; + else + return scsw->cmd.cc; +} + +/** + * scsw_ectl - return scsw ectl field + * @scsw: pointer to scsw + * + * Return the value of the ectl field of the specified scsw, regardless of + * whether it is a transport mode or command mode scsw. + */ +static inline u32 scsw_ectl(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw->tm.ectl; + else + return scsw->cmd.ectl; +} + +/** + * scsw_pno - return scsw pno field + * @scsw: pointer to scsw + * + * Return the value of the pno field of the specified scsw, regardless of + * whether it is a transport mode or command mode scsw. + */ +static inline u32 scsw_pno(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw->tm.pno; + else + return scsw->cmd.pno; +} + +/** + * scsw_fctl - return scsw fctl field + * @scsw: pointer to scsw + * + * Return the value of the fctl field of the specified scsw, regardless of + * whether it is a transport mode or command mode scsw. + */ +static inline u32 scsw_fctl(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw->tm.fctl; + else + return scsw->cmd.fctl; +} + +/** + * scsw_actl - return scsw actl field + * @scsw: pointer to scsw + * + * Return the value of the actl field of the specified scsw, regardless of + * whether it is a transport mode or command mode scsw. + */ +static inline u32 scsw_actl(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw->tm.actl; + else + return scsw->cmd.actl; +} + +/** + * scsw_stctl - return scsw stctl field + * @scsw: pointer to scsw + * + * Return the value of the stctl field of the specified scsw, regardless of + * whether it is a transport mode or command mode scsw. + */ +static inline u32 scsw_stctl(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw->tm.stctl; + else + return scsw->cmd.stctl; +} + +/** + * scsw_dstat - return scsw dstat field + * @scsw: pointer to scsw + * + * Return the value of the dstat field of the specified scsw, regardless of + * whether it is a transport mode or command mode scsw. + */ +static inline u32 scsw_dstat(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw->tm.dstat; + else + return scsw->cmd.dstat; +} + +/** + * scsw_cstat - return scsw cstat field + * @scsw: pointer to scsw + * + * Return the value of the cstat field of the specified scsw, regardless of + * whether it is a transport mode or command mode scsw. + */ +static inline u32 scsw_cstat(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw->tm.cstat; + else + return scsw->cmd.cstat; +} + +/** + * scsw_cmd_is_valid_key - check key field validity + * @scsw: pointer to scsw + * + * Return non-zero if the key field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_key(union scsw *scsw) +{ + return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); +} + +/** + * scsw_cmd_is_valid_sctl - check fctl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the fctl field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_sctl(union scsw *scsw) +{ + return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); +} + +/** + * scsw_cmd_is_valid_eswf - check eswf field validity + * @scsw: pointer to scsw + * + * Return non-zero if the eswf field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_eswf(union scsw *scsw) +{ + return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND); +} + +/** + * scsw_cmd_is_valid_cc - check cc field validity + * @scsw: pointer to scsw + * + * Return non-zero if the cc field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_cc(union scsw *scsw) +{ + return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && + (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND); +} + +/** + * scsw_cmd_is_valid_fmt - check fmt field validity + * @scsw: pointer to scsw + * + * Return non-zero if the fmt field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_fmt(union scsw *scsw) +{ + return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); +} + +/** + * scsw_cmd_is_valid_pfch - check pfch field validity + * @scsw: pointer to scsw + * + * Return non-zero if the pfch field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_pfch(union scsw *scsw) +{ + return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); +} + +/** + * scsw_cmd_is_valid_isic - check isic field validity + * @scsw: pointer to scsw + * + * Return non-zero if the isic field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_isic(union scsw *scsw) +{ + return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); +} + +/** + * scsw_cmd_is_valid_alcc - check alcc field validity + * @scsw: pointer to scsw + * + * Return non-zero if the alcc field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_alcc(union scsw *scsw) +{ + return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); +} + +/** + * scsw_cmd_is_valid_ssi - check ssi field validity + * @scsw: pointer to scsw + * + * Return non-zero if the ssi field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_ssi(union scsw *scsw) +{ + return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); +} + +/** + * scsw_cmd_is_valid_zcc - check zcc field validity + * @scsw: pointer to scsw + * + * Return non-zero if the zcc field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_zcc(union scsw *scsw) +{ + return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && + (scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS); +} + +/** + * scsw_cmd_is_valid_ectl - check ectl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the ectl field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_ectl(union scsw *scsw) +{ + return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && + !(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) && + (scsw->cmd.stctl & SCSW_STCTL_ALERT_STATUS); +} + +/** + * scsw_cmd_is_valid_pno - check pno field validity + * @scsw: pointer to scsw + * + * Return non-zero if the pno field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_pno(union scsw *scsw) +{ + return (scsw->cmd.fctl != 0) && + (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && + (!(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) || + ((scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) && + (scsw->cmd.actl & SCSW_ACTL_SUSPENDED))); +} + +/** + * scsw_cmd_is_valid_fctl - check fctl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the fctl field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_fctl(union scsw *scsw) +{ + /* Only valid if pmcw.dnv == 1*/ + return 1; +} + +/** + * scsw_cmd_is_valid_actl - check actl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the actl field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_actl(union scsw *scsw) +{ + /* Only valid if pmcw.dnv == 1*/ + return 1; +} + +/** + * scsw_cmd_is_valid_stctl - check stctl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the stctl field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_stctl(union scsw *scsw) +{ + /* Only valid if pmcw.dnv == 1*/ + return 1; +} + +/** + * scsw_cmd_is_valid_dstat - check dstat field validity + * @scsw: pointer to scsw + * + * Return non-zero if the dstat field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_dstat(union scsw *scsw) +{ + return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && + (scsw->cmd.cc != 3); +} + +/** + * scsw_cmd_is_valid_cstat - check cstat field validity + * @scsw: pointer to scsw + * + * Return non-zero if the cstat field of the specified command mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_cmd_is_valid_cstat(union scsw *scsw) +{ + return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && + (scsw->cmd.cc != 3); +} + +/** + * scsw_tm_is_valid_key - check key field validity + * @scsw: pointer to scsw + * + * Return non-zero if the key field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_key(union scsw *scsw) +{ + return (scsw->tm.fctl & SCSW_FCTL_START_FUNC); +} + +/** + * scsw_tm_is_valid_eswf - check eswf field validity + * @scsw: pointer to scsw + * + * Return non-zero if the eswf field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_eswf(union scsw *scsw) +{ + return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND); +} + +/** + * scsw_tm_is_valid_cc - check cc field validity + * @scsw: pointer to scsw + * + * Return non-zero if the cc field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_cc(union scsw *scsw) +{ + return (scsw->tm.fctl & SCSW_FCTL_START_FUNC) && + (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND); +} + +/** + * scsw_tm_is_valid_fmt - check fmt field validity + * @scsw: pointer to scsw + * + * Return non-zero if the fmt field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_fmt(union scsw *scsw) +{ + return 1; +} + +/** + * scsw_tm_is_valid_x - check x field validity + * @scsw: pointer to scsw + * + * Return non-zero if the x field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_x(union scsw *scsw) +{ + return 1; +} + +/** + * scsw_tm_is_valid_q - check q field validity + * @scsw: pointer to scsw + * + * Return non-zero if the q field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_q(union scsw *scsw) +{ + return 1; +} + +/** + * scsw_tm_is_valid_ectl - check ectl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the ectl field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_ectl(union scsw *scsw) +{ + return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && + !(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) && + (scsw->tm.stctl & SCSW_STCTL_ALERT_STATUS); +} + +/** + * scsw_tm_is_valid_pno - check pno field validity + * @scsw: pointer to scsw + * + * Return non-zero if the pno field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_pno(union scsw *scsw) +{ + return (scsw->tm.fctl != 0) && + (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && + (!(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) || + ((scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) && + (scsw->tm.actl & SCSW_ACTL_SUSPENDED))); +} + +/** + * scsw_tm_is_valid_fctl - check fctl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the fctl field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_fctl(union scsw *scsw) +{ + /* Only valid if pmcw.dnv == 1*/ + return 1; +} + +/** + * scsw_tm_is_valid_actl - check actl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the actl field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_actl(union scsw *scsw) +{ + /* Only valid if pmcw.dnv == 1*/ + return 1; +} + +/** + * scsw_tm_is_valid_stctl - check stctl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the stctl field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_stctl(union scsw *scsw) +{ + /* Only valid if pmcw.dnv == 1*/ + return 1; +} + +/** + * scsw_tm_is_valid_dstat - check dstat field validity + * @scsw: pointer to scsw + * + * Return non-zero if the dstat field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_dstat(union scsw *scsw) +{ + return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && + (scsw->tm.cc != 3); +} + +/** + * scsw_tm_is_valid_cstat - check cstat field validity + * @scsw: pointer to scsw + * + * Return non-zero if the cstat field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_cstat(union scsw *scsw) +{ + return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && + (scsw->tm.cc != 3); +} + +/** + * scsw_tm_is_valid_fcxs - check fcxs field validity + * @scsw: pointer to scsw + * + * Return non-zero if the fcxs field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_fcxs(union scsw *scsw) +{ + return 1; +} + +/** + * scsw_tm_is_valid_schxs - check schxs field validity + * @scsw: pointer to scsw + * + * Return non-zero if the schxs field of the specified transport mode scsw is + * valid, zero otherwise. + */ +static inline int scsw_tm_is_valid_schxs(union scsw *scsw) +{ + return (scsw->tm.cstat & (SCHN_STAT_PROG_CHECK | + SCHN_STAT_INTF_CTRL_CHK | + SCHN_STAT_PROT_CHECK | + SCHN_STAT_CHN_DATA_CHK)); +} + +/** + * scsw_is_valid_actl - check actl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the actl field of the specified scsw is valid, + * regardless of whether it is a transport mode or command mode scsw. + * Return zero if the field does not contain a valid value. + */ +static inline int scsw_is_valid_actl(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw_tm_is_valid_actl(scsw); + else + return scsw_cmd_is_valid_actl(scsw); +} + +/** + * scsw_is_valid_cc - check cc field validity + * @scsw: pointer to scsw + * + * Return non-zero if the cc field of the specified scsw is valid, + * regardless of whether it is a transport mode or command mode scsw. + * Return zero if the field does not contain a valid value. + */ +static inline int scsw_is_valid_cc(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw_tm_is_valid_cc(scsw); + else + return scsw_cmd_is_valid_cc(scsw); +} + +/** + * scsw_is_valid_cstat - check cstat field validity + * @scsw: pointer to scsw + * + * Return non-zero if the cstat field of the specified scsw is valid, + * regardless of whether it is a transport mode or command mode scsw. + * Return zero if the field does not contain a valid value. + */ +static inline int scsw_is_valid_cstat(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw_tm_is_valid_cstat(scsw); + else + return scsw_cmd_is_valid_cstat(scsw); +} + +/** + * scsw_is_valid_dstat - check dstat field validity + * @scsw: pointer to scsw + * + * Return non-zero if the dstat field of the specified scsw is valid, + * regardless of whether it is a transport mode or command mode scsw. + * Return zero if the field does not contain a valid value. + */ +static inline int scsw_is_valid_dstat(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw_tm_is_valid_dstat(scsw); + else + return scsw_cmd_is_valid_dstat(scsw); +} + +/** + * scsw_is_valid_ectl - check ectl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the ectl field of the specified scsw is valid, + * regardless of whether it is a transport mode or command mode scsw. + * Return zero if the field does not contain a valid value. + */ +static inline int scsw_is_valid_ectl(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw_tm_is_valid_ectl(scsw); + else + return scsw_cmd_is_valid_ectl(scsw); +} + +/** + * scsw_is_valid_eswf - check eswf field validity + * @scsw: pointer to scsw + * + * Return non-zero if the eswf field of the specified scsw is valid, + * regardless of whether it is a transport mode or command mode scsw. + * Return zero if the field does not contain a valid value. + */ +static inline int scsw_is_valid_eswf(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw_tm_is_valid_eswf(scsw); + else + return scsw_cmd_is_valid_eswf(scsw); +} + +/** + * scsw_is_valid_fctl - check fctl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the fctl field of the specified scsw is valid, + * regardless of whether it is a transport mode or command mode scsw. + * Return zero if the field does not contain a valid value. + */ +static inline int scsw_is_valid_fctl(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw_tm_is_valid_fctl(scsw); + else + return scsw_cmd_is_valid_fctl(scsw); +} + +/** + * scsw_is_valid_key - check key field validity + * @scsw: pointer to scsw + * + * Return non-zero if the key field of the specified scsw is valid, + * regardless of whether it is a transport mode or command mode scsw. + * Return zero if the field does not contain a valid value. + */ +static inline int scsw_is_valid_key(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw_tm_is_valid_key(scsw); + else + return scsw_cmd_is_valid_key(scsw); +} + +/** + * scsw_is_valid_pno - check pno field validity + * @scsw: pointer to scsw + * + * Return non-zero if the pno field of the specified scsw is valid, + * regardless of whether it is a transport mode or command mode scsw. + * Return zero if the field does not contain a valid value. + */ +static inline int scsw_is_valid_pno(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw_tm_is_valid_pno(scsw); + else + return scsw_cmd_is_valid_pno(scsw); +} + +/** + * scsw_is_valid_stctl - check stctl field validity + * @scsw: pointer to scsw + * + * Return non-zero if the stctl field of the specified scsw is valid, + * regardless of whether it is a transport mode or command mode scsw. + * Return zero if the field does not contain a valid value. + */ +static inline int scsw_is_valid_stctl(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw_tm_is_valid_stctl(scsw); + else + return scsw_cmd_is_valid_stctl(scsw); +} + +/** + * scsw_cmd_is_solicited - check for solicited scsw + * @scsw: pointer to scsw + * + * Return non-zero if the command mode scsw indicates that the associated + * status condition is solicited, zero if it is unsolicited. + */ +static inline int scsw_cmd_is_solicited(union scsw *scsw) +{ + return (scsw->cmd.cc != 0) || (scsw->cmd.stctl != + (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)); +} + +/** + * scsw_tm_is_solicited - check for solicited scsw + * @scsw: pointer to scsw + * + * Return non-zero if the transport mode scsw indicates that the associated + * status condition is solicited, zero if it is unsolicited. + */ +static inline int scsw_tm_is_solicited(union scsw *scsw) +{ + return (scsw->tm.cc != 0) || (scsw->tm.stctl != + (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)); +} + +/** + * scsw_is_solicited - check for solicited scsw + * @scsw: pointer to scsw + * + * Return non-zero if the transport or command mode scsw indicates that the + * associated status condition is solicited, zero if it is unsolicited. + */ +static inline int scsw_is_solicited(union scsw *scsw) +{ + if (scsw_is_tm(scsw)) + return scsw_tm_is_solicited(scsw); + else + return scsw_cmd_is_solicited(scsw); +} + +#endif /* _ASM_S390_SCSW_H_ */ diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile index adb3dd3..fa4c966 100644 --- a/drivers/s390/cio/Makefile +++ b/drivers/s390/cio/Makefile @@ -2,7 +2,7 @@ # Makefile for the S/390 common i/o drivers # -obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \ +obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \ fcx.o itcw.o crw.o ccw_device-objs += device.o device_fsm.o device_ops.o ccw_device-objs += device_id.o device_pgid.o device_status.o diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 425e8f8..37aa611 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -37,29 +37,6 @@ struct channel_path_desc { struct channel_path; -struct css_general_char { - u64 : 12; - u32 dynio : 1; /* bit 12 */ - u32 : 28; - u32 aif : 1; /* bit 41 */ - u32 : 3; - u32 mcss : 1; /* bit 45 */ - u32 fcs : 1; /* bit 46 */ - u32 : 1; - u32 ext_mb : 1; /* bit 48 */ - u32 : 7; - u32 aif_tdd : 1; /* bit 56 */ - u32 : 1; - u32 qebsm : 1; /* bit 58 */ - u32 : 8; - u32 aif_osa : 1; /* bit 67 */ - u32 : 14; - u32 cib : 1; /* bit 82 */ - u32 : 5; - u32 fcx : 1; /* bit 88 */ - u32 : 7; -}__attribute__((packed)); - struct css_chsc_char { u64 res; u64 : 20; @@ -72,7 +49,6 @@ struct css_chsc_char { u32 : 19; }__attribute__((packed)); -extern struct css_general_char css_general_characteristics; extern struct css_chsc_char css_chsc_characteristics; struct chsc_ssd_info { diff --git a/drivers/s390/cio/scsw.c b/drivers/s390/cio/scsw.c deleted file mode 100644 index f8da25a..0000000 --- a/drivers/s390/cio/scsw.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Helper functions for scsw access. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#include -#include -#include -#include "css.h" -#include "chsc.h" - -/** - * scsw_is_tm - check for transport mode scsw - * @scsw: pointer to scsw - * - * Return non-zero if the specified scsw is a transport mode scsw, zero - * otherwise. - */ -int scsw_is_tm(union scsw *scsw) -{ - return css_general_characteristics.fcx && (scsw->tm.x == 1); -} -EXPORT_SYMBOL(scsw_is_tm); - -/** - * scsw_key - return scsw key field - * @scsw: pointer to scsw - * - * Return the value of the key field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_key(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.key; - else - return scsw->cmd.key; -} -EXPORT_SYMBOL(scsw_key); - -/** - * scsw_eswf - return scsw eswf field - * @scsw: pointer to scsw - * - * Return the value of the eswf field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_eswf(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.eswf; - else - return scsw->cmd.eswf; -} -EXPORT_SYMBOL(scsw_eswf); - -/** - * scsw_cc - return scsw cc field - * @scsw: pointer to scsw - * - * Return the value of the cc field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_cc(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.cc; - else - return scsw->cmd.cc; -} -EXPORT_SYMBOL(scsw_cc); - -/** - * scsw_ectl - return scsw ectl field - * @scsw: pointer to scsw - * - * Return the value of the ectl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_ectl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.ectl; - else - return scsw->cmd.ectl; -} -EXPORT_SYMBOL(scsw_ectl); - -/** - * scsw_pno - return scsw pno field - * @scsw: pointer to scsw - * - * Return the value of the pno field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_pno(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.pno; - else - return scsw->cmd.pno; -} -EXPORT_SYMBOL(scsw_pno); - -/** - * scsw_fctl - return scsw fctl field - * @scsw: pointer to scsw - * - * Return the value of the fctl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_fctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.fctl; - else - return scsw->cmd.fctl; -} -EXPORT_SYMBOL(scsw_fctl); - -/** - * scsw_actl - return scsw actl field - * @scsw: pointer to scsw - * - * Return the value of the actl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_actl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.actl; - else - return scsw->cmd.actl; -} -EXPORT_SYMBOL(scsw_actl); - -/** - * scsw_stctl - return scsw stctl field - * @scsw: pointer to scsw - * - * Return the value of the stctl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_stctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.stctl; - else - return scsw->cmd.stctl; -} -EXPORT_SYMBOL(scsw_stctl); - -/** - * scsw_dstat - return scsw dstat field - * @scsw: pointer to scsw - * - * Return the value of the dstat field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_dstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.dstat; - else - return scsw->cmd.dstat; -} -EXPORT_SYMBOL(scsw_dstat); - -/** - * scsw_cstat - return scsw cstat field - * @scsw: pointer to scsw - * - * Return the value of the cstat field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_cstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.cstat; - else - return scsw->cmd.cstat; -} -EXPORT_SYMBOL(scsw_cstat); - -/** - * scsw_cmd_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_key(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_key); - -/** - * scsw_cmd_is_valid_sctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_sctl(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_sctl); - -/** - * scsw_cmd_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_eswf(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_eswf); - -/** - * scsw_cmd_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_cc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && - (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_cc); - -/** - * scsw_cmd_is_valid_fmt - check fmt field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fmt field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_fmt(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_fmt); - -/** - * scsw_cmd_is_valid_pfch - check pfch field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pfch field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_pfch(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_pfch); - -/** - * scsw_cmd_is_valid_isic - check isic field validity - * @scsw: pointer to scsw - * - * Return non-zero if the isic field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_isic(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_isic); - -/** - * scsw_cmd_is_valid_alcc - check alcc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the alcc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_alcc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_alcc); - -/** - * scsw_cmd_is_valid_ssi - check ssi field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ssi field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_ssi(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_ssi); - -/** - * scsw_cmd_is_valid_zcc - check zcc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the zcc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_zcc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && - (scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_zcc); - -/** - * scsw_cmd_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_ectl(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - !(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->cmd.stctl & SCSW_STCTL_ALERT_STATUS); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_ectl); - -/** - * scsw_cmd_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_pno(union scsw *scsw) -{ - return (scsw->cmd.fctl != 0) && - (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (!(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) || - ((scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->cmd.actl & SCSW_ACTL_SUSPENDED))); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_pno); - -/** - * scsw_cmd_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_fctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_fctl); - -/** - * scsw_cmd_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_actl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_actl); - -/** - * scsw_cmd_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_stctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_stctl); - -/** - * scsw_cmd_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_dstat(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->cmd.cc != 3); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_dstat); - -/** - * scsw_cmd_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_cstat(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->cmd.cc != 3); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_cstat); - -/** - * scsw_tm_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_key(union scsw *scsw) -{ - return (scsw->tm.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_tm_is_valid_key); - -/** - * scsw_tm_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_eswf(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_tm_is_valid_eswf); - -/** - * scsw_tm_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_cc(union scsw *scsw) -{ - return (scsw->tm.fctl & SCSW_FCTL_START_FUNC) && - (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_tm_is_valid_cc); - -/** - * scsw_tm_is_valid_fmt - check fmt field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fmt field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fmt(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fmt); - -/** - * scsw_tm_is_valid_x - check x field validity - * @scsw: pointer to scsw - * - * Return non-zero if the x field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_x(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_x); - -/** - * scsw_tm_is_valid_q - check q field validity - * @scsw: pointer to scsw - * - * Return non-zero if the q field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_q(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_q); - -/** - * scsw_tm_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_ectl(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - !(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->tm.stctl & SCSW_STCTL_ALERT_STATUS); -} -EXPORT_SYMBOL(scsw_tm_is_valid_ectl); - -/** - * scsw_tm_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_pno(union scsw *scsw) -{ - return (scsw->tm.fctl != 0) && - (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (!(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) || - ((scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->tm.actl & SCSW_ACTL_SUSPENDED))); -} -EXPORT_SYMBOL(scsw_tm_is_valid_pno); - -/** - * scsw_tm_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fctl); - -/** - * scsw_tm_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_actl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_actl); - -/** - * scsw_tm_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_stctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_stctl); - -/** - * scsw_tm_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_dstat(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->tm.cc != 3); -} -EXPORT_SYMBOL(scsw_tm_is_valid_dstat); - -/** - * scsw_tm_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_cstat(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->tm.cc != 3); -} -EXPORT_SYMBOL(scsw_tm_is_valid_cstat); - -/** - * scsw_tm_is_valid_fcxs - check fcxs field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fcxs field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fcxs(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fcxs); - -/** - * scsw_tm_is_valid_schxs - check schxs field validity - * @scsw: pointer to scsw - * - * Return non-zero if the schxs field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_schxs(union scsw *scsw) -{ - return (scsw->tm.cstat & (SCHN_STAT_PROG_CHECK | - SCHN_STAT_INTF_CTRL_CHK | - SCHN_STAT_PROT_CHECK | - SCHN_STAT_CHN_DATA_CHK)); -} -EXPORT_SYMBOL(scsw_tm_is_valid_schxs); - -/** - * scsw_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_actl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_actl(scsw); - else - return scsw_cmd_is_valid_actl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_actl); - -/** - * scsw_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_cc(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_cc(scsw); - else - return scsw_cmd_is_valid_cc(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_cc); - -/** - * scsw_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_cstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_cstat(scsw); - else - return scsw_cmd_is_valid_cstat(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_cstat); - -/** - * scsw_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_dstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_dstat(scsw); - else - return scsw_cmd_is_valid_dstat(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_dstat); - -/** - * scsw_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_ectl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_ectl(scsw); - else - return scsw_cmd_is_valid_ectl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_ectl); - -/** - * scsw_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_eswf(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_eswf(scsw); - else - return scsw_cmd_is_valid_eswf(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_eswf); - -/** - * scsw_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_fctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_fctl(scsw); - else - return scsw_cmd_is_valid_fctl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_fctl); - -/** - * scsw_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_key(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_key(scsw); - else - return scsw_cmd_is_valid_key(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_key); - -/** - * scsw_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_pno(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_pno(scsw); - else - return scsw_cmd_is_valid_pno(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_pno); - -/** - * scsw_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_stctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_stctl(scsw); - else - return scsw_cmd_is_valid_stctl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_stctl); - -/** - * scsw_cmd_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the command mode scsw indicates that the associated - * status condition is solicited, zero if it is unsolicited. - */ -int scsw_cmd_is_solicited(union scsw *scsw) -{ - return (scsw->cmd.cc != 0) || (scsw->cmd.stctl != - (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)); -} -EXPORT_SYMBOL(scsw_cmd_is_solicited); - -/** - * scsw_tm_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the transport mode scsw indicates that the associated - * status condition is solicited, zero if it is unsolicited. - */ -int scsw_tm_is_solicited(union scsw *scsw) -{ - return (scsw->tm.cc != 0) || (scsw->tm.stctl != - (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)); -} -EXPORT_SYMBOL(scsw_tm_is_solicited); - -/** - * scsw_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the transport or command mode scsw indicates that the - * associated status condition is solicited, zero if it is unsolicited. - */ -int scsw_is_solicited(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_solicited(scsw); - else - return scsw_cmd_is_solicited(scsw); -} -EXPORT_SYMBOL(scsw_is_solicited); -- cgit v0.10.2 From 1da73bc80bdfc9588192a6e6f5a72f8138f7378d Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Fri, 11 Sep 2009 10:28:16 +0200 Subject: [S390] cio: consolidate subchannel intparm reset Ensure that the hardware interruption parameter for a subchannel is reset when the associated subchannel data structure is freed. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 85d43c6..40d4b30 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -170,6 +170,9 @@ css_subchannel_release(struct device *dev) sch = to_subchannel(dev); if (!cio_is_console(sch->schid)) { + /* Reset intparm to zeroes. */ + sch->config.intparm = 0; + cio_commit_config(sch); kfree(sch->lock); kfree(sch); } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index d593bc7..b624022 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1024,9 +1024,6 @@ static void ccw_device_call_sch_unregister(struct work_struct *work) return; sch = to_subchannel(cdev->dev.parent); css_sch_device_unregister(sch); - /* Reset intparm to zeroes. */ - sch->config.intparm = 0; - cio_commit_config(sch); /* Release cdev reference for workqueue processing.*/ put_device(&cdev->dev); /* Release subchannel reference for local processing. */ @@ -1210,9 +1207,6 @@ static void io_subchannel_do_unreg(struct work_struct *work) sch = container_of(work, struct subchannel, work); css_sch_device_unregister(sch); - /* Reset intparm to zeroes. */ - sch->config.intparm = 0; - cio_commit_config(sch); put_device(&sch->dev); } @@ -1688,10 +1682,6 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow) spin_unlock_irqrestore(sch->lock, flags); css_sch_device_unregister(sch); spin_lock_irqsave(sch->lock, flags); - - /* Reset intparm to zeroes. */ - sch->config.intparm = 0; - cio_commit_config(sch); break; case REPROBE: ccw_device_trigger_reprobe(cdev); -- cgit v0.10.2 From 626e476ae011cafddc0ccb39ab838b90cc5d2272 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:17 +0200 Subject: [S390] cio: fix not oper handling after failed [on|off]line processing If online/offline processing of a ccw device fails, resulting in not operational state, notify the driver and unregister the device in case the driver dosn't want to keep it. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index b8bdb0d..9c1452a 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -394,6 +394,13 @@ ccw_device_done(struct ccw_device *cdev, int state) ccw_device_schedule_sch_unregister(cdev); cdev->private->flags.donotify = 0; } + if (state == DEV_STATE_NOT_OPER) { + CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n", + cdev->private->dev_id.devno, sch->schid.sch_no); + if (!ccw_device_notify(cdev, CIO_GONE)) + ccw_device_schedule_sch_unregister(cdev); + cdev->private->flags.donotify = 0; + } if (cdev->private->flags.donotify) { cdev->private->flags.donotify = 0; -- cgit v0.10.2 From efd986db2d720e8f6660ec2c292509ee7d28cc6a Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:18 +0200 Subject: [S390] cio: increase trace level Move debug traces for start I/O and interrupt events to exclusive trace levels. Also change tracing in hot-path from sprintf (costly) to hex. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 5ec7789..390b4e9 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -139,12 +139,11 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ __u8 lpm, /* logical path mask */ __u8 key) /* storage key */ { - char dbf_txt[15]; int ccode; union orb *orb; - CIO_TRACE_EVENT(4, "stIO"); - CIO_TRACE_EVENT(4, dev_name(&sch->dev)); + CIO_TRACE_EVENT(5, "stIO"); + CIO_TRACE_EVENT(5, dev_name(&sch->dev)); orb = &to_io_private(sch)->orb; memset(orb, 0, sizeof(union orb)); @@ -169,8 +168,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ ccode = ssch(sch->schid, orb); /* process condition code */ - sprintf(dbf_txt, "ccode:%d", ccode); - CIO_TRACE_EVENT(4, dbf_txt); + CIO_HEX_EVENT(5, &ccode, sizeof(ccode)); switch (ccode) { case 0: @@ -201,16 +199,14 @@ cio_start (struct subchannel *sch, struct ccw1 *cpa, __u8 lpm) int cio_resume (struct subchannel *sch) { - char dbf_txt[15]; int ccode; - CIO_TRACE_EVENT (4, "resIO"); + CIO_TRACE_EVENT(4, "resIO"); CIO_TRACE_EVENT(4, dev_name(&sch->dev)); ccode = rsch (sch->schid); - sprintf (dbf_txt, "ccode:%d", ccode); - CIO_TRACE_EVENT (4, dbf_txt); + CIO_HEX_EVENT(4, &ccode, sizeof(ccode)); switch (ccode) { case 0: @@ -235,13 +231,12 @@ cio_resume (struct subchannel *sch) int cio_halt(struct subchannel *sch) { - char dbf_txt[15]; int ccode; if (!sch) return -ENODEV; - CIO_TRACE_EVENT (2, "haltIO"); + CIO_TRACE_EVENT(2, "haltIO"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); /* @@ -249,8 +244,7 @@ cio_halt(struct subchannel *sch) */ ccode = hsch (sch->schid); - sprintf (dbf_txt, "ccode:%d", ccode); - CIO_TRACE_EVENT (2, dbf_txt); + CIO_HEX_EVENT(2, &ccode, sizeof(ccode)); switch (ccode) { case 0: @@ -270,13 +264,12 @@ cio_halt(struct subchannel *sch) int cio_clear(struct subchannel *sch) { - char dbf_txt[15]; int ccode; if (!sch) return -ENODEV; - CIO_TRACE_EVENT (2, "clearIO"); + CIO_TRACE_EVENT(2, "clearIO"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); /* @@ -284,8 +277,7 @@ cio_clear(struct subchannel *sch) */ ccode = csch (sch->schid); - sprintf (dbf_txt, "ccode:%d", ccode); - CIO_TRACE_EVENT (2, dbf_txt); + CIO_HEX_EVENT(2, &ccode, sizeof(ccode)); switch (ccode) { case 0: @@ -306,19 +298,17 @@ cio_clear(struct subchannel *sch) int cio_cancel (struct subchannel *sch) { - char dbf_txt[15]; int ccode; if (!sch) return -ENODEV; - CIO_TRACE_EVENT (2, "cancelIO"); + CIO_TRACE_EVENT(2, "cancelIO"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); ccode = xsch (sch->schid); - sprintf (dbf_txt, "ccode:%d", ccode); - CIO_TRACE_EVENT (2, dbf_txt); + CIO_HEX_EVENT(2, &ccode, sizeof(ccode)); switch (ccode) { case 0: /* success */ @@ -429,11 +419,10 @@ EXPORT_SYMBOL_GPL(cio_update_schib); */ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) { - char dbf_txt[15]; int retry; int ret; - CIO_TRACE_EVENT (2, "ensch"); + CIO_TRACE_EVENT(2, "ensch"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) @@ -460,8 +449,7 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) } else break; } - sprintf (dbf_txt, "ret:%d", ret); - CIO_TRACE_EVENT (2, dbf_txt); + CIO_HEX_EVENT(2, &ret, sizeof(ret)); return ret; } EXPORT_SYMBOL_GPL(cio_enable_subchannel); @@ -472,11 +460,10 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel); */ int cio_disable_subchannel(struct subchannel *sch) { - char dbf_txt[15]; int retry; int ret; - CIO_TRACE_EVENT (2, "dissch"); + CIO_TRACE_EVENT(2, "dissch"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) @@ -495,8 +482,7 @@ int cio_disable_subchannel(struct subchannel *sch) } else break; } - sprintf (dbf_txt, "ret:%d", ret); - CIO_TRACE_EVENT (2, dbf_txt); + CIO_HEX_EVENT(2, &ret, sizeof(ret)); return ret; } EXPORT_SYMBOL_GPL(cio_disable_subchannel); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index b624022..19b4469 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1168,8 +1168,8 @@ static void io_subchannel_irq(struct subchannel *sch) cdev = sch_get_cdev(sch); - CIO_TRACE_EVENT(3, "IRQ"); - CIO_TRACE_EVENT(3, dev_name(&sch->dev)); + CIO_TRACE_EVENT(6, "IRQ"); + CIO_TRACE_EVENT(6, dev_name(&sch->dev)); if (cdev) dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); } -- cgit v0.10.2 From e2910bcf8ca762b306767a0894ab1987be014c9e Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 11 Sep 2009 10:28:19 +0200 Subject: [S390] qdio: continue polling if the queue is not finished With commit c38f96080955854e54df9cb392bc674e1ae330e1 polling was stopped for the queue even if new data is available. Return immediately after scheduling the queue tasklet if the queue is not done. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 0038750..9aef402 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -798,8 +798,10 @@ static void __tiqdio_inbound_processing(struct qdio_q *q) if (!qdio_inbound_q_done(q)) { qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); - if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) { tasklet_schedule(&q->tasklet); + return; + } } qdio_stop_polling(q); -- cgit v0.10.2 From be7a2ddce66991c05a1c6ad19790289591e53547 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:20 +0200 Subject: [S390] cio: ensure to hold a reference for deferred deregistration Ensure to always hold an extra device reference for scheduling a subchannel deregistration, by moving the get_device to ccw_device_schedule_sch_unregister. This fixes an use after free error in ccw_device_call_sch_unregister where put_device was called on an already freed device structure. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 19b4469..a7a340b 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -333,15 +333,15 @@ ccw_device_remove_disconnected(struct ccw_device *cdev) * Forced offline in disconnected state means * 'throw away device'. */ - /* Get cdev reference for workqueue processing. */ - if (!get_device(&cdev->dev)) - return; if (ccw_device_is_orphan(cdev)) { /* * Deregister ccw device. * Unfortunately, we cannot do this directly from the * attribute method. */ + /* Get cdev reference for workqueue processing. */ + if (!get_device(&cdev->dev)) + return; spin_lock_irqsave(cdev->ccwlock, flags); cdev->private->state = DEV_STATE_NOT_OPER; spin_unlock_irqrestore(cdev->ccwlock, flags); @@ -1032,6 +1032,9 @@ static void ccw_device_call_sch_unregister(struct work_struct *work) void ccw_device_schedule_sch_unregister(struct ccw_device *cdev) { + /* Get cdev reference for workqueue processing. */ + if (!get_device(&cdev->dev)) + return; PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister); queue_work(slow_path_wq, &cdev->private->kick_work); @@ -1052,9 +1055,6 @@ io_subchannel_recog_done(struct ccw_device *cdev) /* Device did not respond in time. */ case DEV_STATE_NOT_OPER: cdev->private->flags.recog_done = 1; - /* Remove device found not operational. */ - if (!get_device(&cdev->dev)) - break; ccw_device_schedule_sch_unregister(cdev); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); @@ -1565,8 +1565,6 @@ static int purge_fn(struct device *dev, void *data) spin_unlock_irq(cdev->ccwlock); if (!unreg) goto out; - if (!get_device(&cdev->dev)) - goto out; CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid, priv->dev_id.devno); ccw_device_schedule_sch_unregister(cdev); -- cgit v0.10.2 From 217ee6c64a9589bc5ad4d1c88136fc359d17930b Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Fri, 11 Sep 2009 10:28:21 +0200 Subject: [S390] cio: failing set online/offline processing. When unit checks trigger sensing the device state is set to W4SENSE until sense completion; then the device state is set back to ONLINE. If a unit check occurs while set online or set offline requests are processed then it might happen that the device's temporary W4SENSE state causes these functions to terminate, leaving the device in an inconsistent state when the state is set back to ONLINE later on so that the device cannot be set online or offline any longer. To solve this, set online/offline and related rollback or error routines are processed only if the device is in a final or DISCONNECTED state. Signed-off-by: Michael Ernst Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index a7a340b..a50cfa5 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -380,30 +380,34 @@ int ccw_device_set_offline(struct ccw_device *cdev) } cdev->online = 0; spin_lock_irq(cdev->ccwlock); - ret = ccw_device_offline(cdev); - if (ret == -ENODEV) { - if (cdev->private->state != DEV_STATE_NOT_OPER) { - cdev->private->state = DEV_STATE_OFFLINE; - dev_fsm_event(cdev, DEV_EVENT_NOTOPER); - } + /* Wait until a final state or DISCONNECTED is reached */ + while (!dev_fsm_final_state(cdev) && + cdev->private->state != DEV_STATE_DISCONNECTED) { spin_unlock_irq(cdev->ccwlock); - /* Give up reference from ccw_device_set_online(). */ - put_device(&cdev->dev); - return ret; + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || + cdev->private->state == DEV_STATE_DISCONNECTED)); + spin_lock_irq(cdev->ccwlock); } + ret = ccw_device_offline(cdev); + if (ret) + goto error; spin_unlock_irq(cdev->ccwlock); - if (ret == 0) { - wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); - /* Give up reference from ccw_device_set_online(). */ - put_device(&cdev->dev); - } else { - CIO_MSG_EVENT(0, "ccw_device_offline returned %d, " - "device 0.%x.%04x\n", - ret, cdev->private->dev_id.ssid, - cdev->private->dev_id.devno); - cdev->online = 1; - } - return ret; + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || + cdev->private->state == DEV_STATE_DISCONNECTED)); + /* Give up reference from ccw_device_set_online(). */ + put_device(&cdev->dev); + return 0; + +error: + CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device 0.%x.%04x\n", + ret, cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); + cdev->private->state = DEV_STATE_OFFLINE; + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); + spin_unlock_irq(cdev->ccwlock); + /* Give up reference from ccw_device_set_online(). */ + put_device(&cdev->dev); + return -ENODEV; } /** @@ -421,6 +425,7 @@ int ccw_device_set_offline(struct ccw_device *cdev) int ccw_device_set_online(struct ccw_device *cdev) { int ret; + int ret2; if (!cdev) return -ENODEV; @@ -444,28 +449,53 @@ int ccw_device_set_online(struct ccw_device *cdev) put_device(&cdev->dev); return ret; } - if (cdev->private->state != DEV_STATE_ONLINE) { + spin_lock_irq(cdev->ccwlock); + /* Check if online processing was successful */ + if ((cdev->private->state != DEV_STATE_ONLINE) && + (cdev->private->state != DEV_STATE_W4SENSE)) { + spin_unlock_irq(cdev->ccwlock); /* Give up online reference since onlining failed. */ put_device(&cdev->dev); return -ENODEV; } - if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) { - cdev->online = 1; - return 0; - } + spin_unlock_irq(cdev->ccwlock); + if (cdev->drv->set_online) + ret = cdev->drv->set_online(cdev); + if (ret) + goto rollback; + cdev->online = 1; + return 0; + +rollback: spin_lock_irq(cdev->ccwlock); - ret = ccw_device_offline(cdev); + /* Wait until a final state or DISCONNECTED is reached */ + while (!dev_fsm_final_state(cdev) && + cdev->private->state != DEV_STATE_DISCONNECTED) { + spin_unlock_irq(cdev->ccwlock); + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || + cdev->private->state == DEV_STATE_DISCONNECTED)); + spin_lock_irq(cdev->ccwlock); + } + ret2 = ccw_device_offline(cdev); + if (ret2) + goto error; spin_unlock_irq(cdev->ccwlock); - if (ret == 0) - wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); - else - CIO_MSG_EVENT(0, "ccw_device_offline returned %d, " - "device 0.%x.%04x\n", - ret, cdev->private->dev_id.ssid, - cdev->private->dev_id.devno); + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || + cdev->private->state == DEV_STATE_DISCONNECTED)); /* Give up online reference since onlining failed. */ put_device(&cdev->dev); - return (ret == 0) ? -ENODEV : ret; + return ret; + +error: + CIO_MSG_EVENT(0, "rollback ccw_device_offline returned %d, " + "device 0.%x.%04x\n", + ret2, cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); + cdev->private->state = DEV_STATE_OFFLINE; + spin_unlock_irq(cdev->ccwlock); + /* Give up online reference since onlining failed. */ + put_device(&cdev->dev); + return ret; } static int online_store_handle_offline(struct ccw_device *cdev) diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 9c1452a..e728ce4 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -905,6 +905,8 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) } call_handler: cdev->private->state = DEV_STATE_ONLINE; + /* In case sensing interfered with setting the device online */ + wake_up(&cdev->private->wait_q); /* Call the handler. */ if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify) /* Start delayed path verification. */ -- cgit v0.10.2 From 3f09bb8965cefe36f42a9ec09ebb821523eba530 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 11 Sep 2009 10:28:22 +0200 Subject: [S390] qdio: remove limited number of debugfs entries The number of qdio debugfs entries was limited. Remove this limit and group the queue files in a per device directory. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index b1241f8..ff7748a 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -1,7 +1,7 @@ /* * linux/drivers/s390/cio/qdio.h * - * Copyright 2000,2008 IBM Corp. + * Copyright 2000,2009 IBM Corp. * Author(s): Utz Bacher * Jan Glauber */ @@ -246,6 +246,7 @@ struct qdio_q { atomic_t nr_buf_used; struct qdio_irq *irq_ptr; + struct dentry *debugfs_q; struct tasklet_struct tasklet; /* error condition during a data transfer */ @@ -267,6 +268,7 @@ struct qdio_irq { struct qib qib; u32 *dsci; /* address of device state change indicator */ struct ccw_device *cdev; + struct dentry *debugfs_dev; unsigned long int_parm; struct subchannel_id schid; diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index b8626d4..1b78f63 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -1,14 +1,12 @@ /* * drivers/s390/cio/qdio_debug.c * - * Copyright IBM Corp. 2008 + * Copyright IBM Corp. 2008,2009 * * Author: Jan Glauber (jang@linux.vnet.ibm.com) */ -#include #include #include -#include #include #include "qdio_debug.h" #include "qdio.h" @@ -17,10 +15,7 @@ debug_info_t *qdio_dbf_setup; debug_info_t *qdio_dbf_error; static struct dentry *debugfs_root; -#define MAX_DEBUGFS_QUEUES 32 -static struct dentry *debugfs_queues[MAX_DEBUGFS_QUEUES] = { NULL }; -static DEFINE_MUTEX(debugfs_mutex); -#define QDIO_DEBUGFS_NAME_LEN 40 +#define QDIO_DEBUGFS_NAME_LEN 10 void qdio_allocate_dbf(struct qdio_initialize *init_data, struct qdio_irq *irq_ptr) @@ -130,20 +125,6 @@ static int qstat_seq_open(struct inode *inode, struct file *filp) filp->f_path.dentry->d_inode->i_private); } -static void remove_debugfs_entry(struct qdio_q *q) -{ - int i; - - for (i = 0; i < MAX_DEBUGFS_QUEUES; i++) { - if (!debugfs_queues[i]) - continue; - if (debugfs_queues[i]->d_inode->i_private == q) { - debugfs_remove(debugfs_queues[i]); - debugfs_queues[i] = NULL; - } - } -} - static struct file_operations debugfs_fops = { .owner = THIS_MODULE, .open = qstat_seq_open, @@ -155,22 +136,15 @@ static struct file_operations debugfs_fops = { static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev) { - int i = 0; char name[QDIO_DEBUGFS_NAME_LEN]; - while (debugfs_queues[i] != NULL) { - i++; - if (i >= MAX_DEBUGFS_QUEUES) - return; - } - snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%s_%d", - dev_name(&cdev->dev), + snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d", q->is_input_q ? "input" : "output", q->nr); - debugfs_queues[i] = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, - debugfs_root, q, &debugfs_fops); - if (IS_ERR(debugfs_queues[i])) - debugfs_queues[i] = NULL; + q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, + q->irq_ptr->debugfs_dev, q, &debugfs_fops); + if (IS_ERR(q->debugfs_q)) + q->debugfs_q = NULL; } void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) @@ -178,12 +152,14 @@ void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) struct qdio_q *q; int i; - mutex_lock(&debugfs_mutex); + irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev), + debugfs_root); + if (IS_ERR(irq_ptr->debugfs_dev)) + irq_ptr->debugfs_dev = NULL; for_each_input_queue(irq_ptr, q, i) setup_debugfs_entry(q, cdev); for_each_output_queue(irq_ptr, q, i) setup_debugfs_entry(q, cdev); - mutex_unlock(&debugfs_mutex); } void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) @@ -191,17 +167,16 @@ void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cd struct qdio_q *q; int i; - mutex_lock(&debugfs_mutex); for_each_input_queue(irq_ptr, q, i) - remove_debugfs_entry(q); + debugfs_remove(q->debugfs_q); for_each_output_queue(irq_ptr, q, i) - remove_debugfs_entry(q); - mutex_unlock(&debugfs_mutex); + debugfs_remove(q->debugfs_q); + debugfs_remove(irq_ptr->debugfs_dev); } int __init qdio_debug_init(void) { - debugfs_root = debugfs_create_dir("qdio_queues", NULL); + debugfs_root = debugfs_create_dir("qdio", NULL); qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16); debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); -- cgit v0.10.2 From f014824ee72e66292c3b1172dc142f959b42e61b Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:23 +0200 Subject: [S390] cio: fix use after free in s390 debug feature When using s390dbf with "%s" in sprintf format strings the string itself is not copied to the dbf buffer. Since in this case only pointers are stored in the s390dbf, we should not use dev_name - which is bound to the lifetime of the device. Reading this entry from s390dbf after the device was released will cause an use after free error. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index a50cfa5..6b770f8 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -2038,7 +2038,9 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev) spin_unlock_irq(sch->lock); if (ret) { CIO_MSG_EVENT(0, "Couldn't start recognition for device " - "%s (ret=%d)\n", dev_name(&cdev->dev), ret); + "0.%x.%04x (ret=%d)\n", + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, ret); spin_lock_irq(sch->lock); cdev->private->state = DEV_STATE_DISCONNECTED; spin_unlock_irq(sch->lock); @@ -2101,8 +2103,9 @@ static int ccw_device_pm_restore(struct device *dev) } /* check if the device id has changed */ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { - CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from " - "%04x to %04x)\n", dev_name(&sch->dev), + CIO_MSG_EVENT(0, "resume: sch 0.%x.%04x: failed (devno " + "changed from %04x to %04x)\n", + sch->schid.ssid, sch->schid.sch_no, cdev->private->dev_id.devno, sch->schib.pmcw.dev); goto out_unreg_unlock; @@ -2135,8 +2138,9 @@ static int ccw_device_pm_restore(struct device *dev) if (cm_enabled) { ret = ccw_set_cmf(cdev, 1); if (ret) { - CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed " - "(rc=%d)\n", dev_name(&cdev->dev), ret); + CIO_MSG_EVENT(2, "resume: cdev 0.%x.%04x: cmf failed " + "(rc=%d)\n", cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, ret); ret = 0; } } -- cgit v0.10.2 From ab6aae09024be1b039df441fa1b64dbe092d0acb Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:24 +0200 Subject: [S390] cio: fix memleak in subchannel validation When scanning for new subchannels we have a code path where we allocate memory for a struct subchannel, set the device name (which is dynamically allocated now) and do a check if the underlying device is blacklisted - if so we free the subchannel structure. Since we have not set up refcounting at this stage, the device name's memory is lost. Fix this by moving the dev_set_name after the blacklist test. Note: With this patch the init_name for the console subchannel becomes virtually obsolete. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 390b4e9..fe18ef6 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -564,11 +564,6 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) goto out; } mutex_init(&sch->reg_mutex); - /* Set a name for the subchannel */ - if (cio_is_console(schid)) - sch->dev.init_name = cio_get_console_sch_name(schid); - else - dev_set_name(&sch->dev, "0.%x.%04x", schid.ssid, schid.sch_no); /* * The first subchannel that is not-operational (ccode==3) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 40d4b30..0dc6f6d 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -183,6 +183,11 @@ static int css_sch_device_register(struct subchannel *sch) int ret; mutex_lock(&sch->reg_mutex); + if (cio_is_console(sch->schid)) + sch->dev.init_name = cio_get_console_sch_name(sch->schid); + else + dev_set_name(&sch->dev, "0.%x.%04x", sch->schid.ssid, + sch->schid.sch_no); ret = device_register(&sch->dev); mutex_unlock(&sch->reg_mutex); return ret; -- cgit v0.10.2 From 6ee4fec6be06f7d138860b37cba58982cc3ccb16 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:25 +0200 Subject: [S390] cio: remove subchannel init_name We used the init_name to set the console subchannels name early at the boot stage. With the patch cio: fix memleak in subchannel validation we moved the name setting to the point where we actually register the console subchannel. At this time we can do dynamic allocations and therefore use dev_set_name. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index fe18ef6..138124f 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -667,7 +667,6 @@ void __irq_entry do_IRQ(struct pt_regs *regs) #ifdef CONFIG_CCW_CONSOLE static struct subchannel console_subchannel; -static char console_sch_name[10] = "0.x.xxxx"; static struct io_subchannel_private console_priv; static int console_subchannel_in_use; @@ -854,12 +853,6 @@ cio_get_console_subchannel(void) return &console_subchannel; } -const char *cio_get_console_sch_name(struct subchannel_id schid) -{ - snprintf(console_sch_name, 10, "0.%x.%04x", schid.ssid, schid.sch_no); - return (const char *)console_sch_name; -} - #endif static int __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 5150fba..883e19d 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -133,14 +133,12 @@ extern int cio_is_console(struct subchannel_id); extern struct subchannel *cio_get_console_subchannel(void); extern spinlock_t * cio_get_console_lock(void); extern void *cio_get_console_priv(void); -extern const char *cio_get_console_sch_name(struct subchannel_id schid); extern const char *cio_get_console_cdev_name(struct subchannel *sch); #else #define cio_is_console(schid) 0 #define cio_get_console_subchannel() NULL #define cio_get_console_lock() NULL #define cio_get_console_priv() NULL -#define cio_get_console_sch_name(schid) NULL #define cio_get_console_cdev_name(sch) NULL #endif diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 0dc6f6d..0a3ce65 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -183,11 +183,8 @@ static int css_sch_device_register(struct subchannel *sch) int ret; mutex_lock(&sch->reg_mutex); - if (cio_is_console(sch->schid)) - sch->dev.init_name = cio_get_console_sch_name(sch->schid); - else - dev_set_name(&sch->dev, "0.%x.%04x", sch->schid.ssid, - sch->schid.sch_no); + dev_set_name(&sch->dev, "0.%x.%04x", sch->schid.ssid, + sch->schid.sch_no); ret = device_register(&sch->dev); mutex_unlock(&sch->reg_mutex); return ret; -- cgit v0.10.2 From 3b554a14f4bdf754ba9d2f64c2b6edf8dafe93b9 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:26 +0200 Subject: [S390] cio: move final put_device to ccw_device_unregister We use a test_and_clear_bit to prevent a device from being unregistered twice. Unfortunately in this cases the "final" put_device (from device_initialize) was issued more than once, resulting in an use after free error. Fix this by moving this put_device to ccw_device_unregister. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 6b770f8..345a61f 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -307,8 +307,11 @@ int ccw_device_is_orphan(struct ccw_device *cdev) static void ccw_device_unregister(struct ccw_device *cdev) { - if (test_and_clear_bit(1, &cdev->private->registered)) + if (test_and_clear_bit(1, &cdev->private->registered)) { device_del(&cdev->dev); + /* Release reference from device_initialize(). */ + put_device(&cdev->dev); + } } static void ccw_device_remove_orphan_cb(struct work_struct *work) @@ -319,7 +322,6 @@ static void ccw_device_remove_orphan_cb(struct work_struct *work) priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; ccw_device_unregister(cdev); - put_device(&cdev->dev); /* Release cdev reference for workqueue processing. */ put_device(&cdev->dev); } @@ -1358,7 +1360,6 @@ io_subchannel_remove (struct subchannel *sch) cdev->private->state = DEV_STATE_NOT_OPER; spin_unlock_irqrestore(cdev->ccwlock, flags); ccw_device_unregister(cdev); - put_device(&cdev->dev); kfree(sch->private); sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); return 0; -- cgit v0.10.2 From 3ac276f8cb020adbbc3399c47edc1100748c2c16 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:27 +0200 Subject: [S390] cio: remove ccw_device init_name We used the init_name to set the console ccw_device's name early at the boot stage. This patch moves the name setting (for all ccw devices) to the point where we actually register the device. At this time we can do dynamic allocations and therefore use dev_set_name. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 883e19d..2e43558 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -133,13 +133,11 @@ extern int cio_is_console(struct subchannel_id); extern struct subchannel *cio_get_console_subchannel(void); extern spinlock_t * cio_get_console_lock(void); extern void *cio_get_console_priv(void); -extern const char *cio_get_console_cdev_name(struct subchannel *sch); #else #define cio_is_console(schid) 0 #define cio_get_console_subchannel() NULL #define cio_get_console_lock() NULL #define cio_get_console_priv() NULL -#define cio_get_console_cdev_name(sch) NULL #endif #endif diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 345a61f..0f95405 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -669,8 +669,12 @@ static int ccw_device_register(struct ccw_device *cdev) int ret; dev->bus = &ccw_bus_type; - - if ((ret = device_add(dev))) + ret = dev_set_name(&cdev->dev, "0.%x.%04x", cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); + if (ret) + return ret; + ret = device_add(dev); + if (ret) return ret; set_bit(1, &cdev->private->registered); @@ -1124,13 +1128,6 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) init_waitqueue_head(&priv->wait_q); init_timer(&priv->timer); - /* Set an initial name for the device. */ - if (cio_is_console(sch->schid)) - cdev->dev.init_name = cio_get_console_cdev_name(sch); - else - dev_set_name(&cdev->dev, "0.%x.%04x", - sch->schid.ssid, sch->schib.pmcw.dev); - /* Increase counter of devices currently in recognition. */ atomic_inc(&ccw_device_init_count); @@ -1731,7 +1728,6 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow) #ifdef CONFIG_CCW_CONSOLE static struct ccw_device console_cdev; -static char console_cdev_name[10] = "0.x.xxxx"; static struct ccw_device_private console_private; static int console_cdev_in_use; @@ -1815,13 +1811,6 @@ int ccw_device_force_console(void) return ccw_device_pm_restore(&console_cdev.dev); } EXPORT_SYMBOL_GPL(ccw_device_force_console); - -const char *cio_get_console_cdev_name(struct subchannel *sch) -{ - snprintf(console_cdev_name, 10, "0.%x.%04x", - sch->schid.ssid, sch->schib.pmcw.dev); - return (const char *)console_cdev_name; -} #endif /* -- cgit v0.10.2 From 97f604b07473669f4da52b1f859ee45e8d48d42a Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Fri, 11 Sep 2009 10:28:28 +0200 Subject: [S390] dasd: fail requests when device state is less then ready A DASD device that is not ready or online has no defined disk layout, so all requests that arrive in such a state need to be returned as failed. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 3f62dd5..f8445b8 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1699,8 +1699,11 @@ static void __dasd_process_request_queue(struct dasd_block *block) * for that. State DASD_STATE_ONLINE is normal block device * operation. */ - if (basedev->state < DASD_STATE_READY) + if (basedev->state < DASD_STATE_READY) { + while ((req = blk_fetch_request(block->request_queue))) + __blk_end_request_all(req, -EIO); return; + } /* Now we try to fetch requests from the request queue */ while (!blk_queue_plugged(queue) && (req = blk_peek_request(queue))) { if (basedev->features & DASD_FEATURE_READONLY && -- cgit v0.10.2 From 68b781fe1bed89011ab7c58ede8476abe64432d2 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Fri, 11 Sep 2009 10:28:29 +0200 Subject: [S390] dasd: optimize cpu usage in goodcase remove unnecessary dbf call, remove string operations for magic Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index f8445b8..e109da4 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -669,14 +669,14 @@ static void dasd_profile_end(struct dasd_block *block, * memory and 2) dasd_smalloc_request uses the static ccw memory * that gets allocated for each device. */ -struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength, +struct dasd_ccw_req *dasd_kmalloc_request(int magic, int cplength, int datasize, struct dasd_device *device) { struct dasd_ccw_req *cqr; /* Sanity checks */ - BUG_ON( magic == NULL || datasize > PAGE_SIZE || + BUG_ON(datasize > PAGE_SIZE || (cplength*sizeof(struct ccw1)) > PAGE_SIZE); cqr = kzalloc(sizeof(struct dasd_ccw_req), GFP_ATOMIC); @@ -700,14 +700,13 @@ struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength, return ERR_PTR(-ENOMEM); } } - strncpy((char *) &cqr->magic, magic, 4); - ASCEBC((char *) &cqr->magic, 4); + cqr->magic = magic; set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); dasd_get_device(device); return cqr; } -struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength, +struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, int datasize, struct dasd_device *device) { @@ -717,7 +716,7 @@ struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength, int size; /* Sanity checks */ - BUG_ON( magic == NULL || datasize > PAGE_SIZE || + BUG_ON(datasize > PAGE_SIZE || (cplength*sizeof(struct ccw1)) > PAGE_SIZE); size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; @@ -744,8 +743,7 @@ struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength, cqr->data = data; memset(cqr->data, 0, datasize); } - strncpy((char *) &cqr->magic, magic, 4); - ASCEBC((char *) &cqr->magic, 4); + cqr->magic = magic; set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); dasd_get_device(device); return cqr; @@ -899,9 +897,6 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) switch (rc) { case 0: cqr->status = DASD_CQR_IN_IO; - DBF_DEV_EVENT(DBF_DEBUG, device, - "start_IO: request %p started successful", - cqr); break; case -EBUSY: DBF_DEV_EVENT(DBF_DEBUG, device, "%s", @@ -2533,7 +2528,7 @@ EXPORT_SYMBOL_GPL(dasd_generic_restore_device); static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, void *rdc_buffer, int rdc_buffer_size, - char *magic) + int magic) { struct dasd_ccw_req *cqr; struct ccw1 *ccw; @@ -2564,7 +2559,7 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, } -int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, +int dasd_generic_read_dev_chars(struct dasd_device *device, int magic, void *rdc_buffer, int rdc_buffer_size) { int ret; diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 5b7bbc8..b9efd09 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -379,8 +379,7 @@ static int read_unit_address_configuration(struct dasd_device *device, int rc; unsigned long flags; - cqr = dasd_kmalloc_request("ECKD", - 1 /* PSF */ + 1 /* RSSD */ , + cqr = dasd_kmalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, (sizeof(struct dasd_psf_prssd_data)), device); if (IS_ERR(cqr)) diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 644086b..0b89796 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -523,8 +523,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, /* Build the request */ datasize = sizeof(struct dasd_diag_req) + count*sizeof(struct dasd_diag_bio); - cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0, - datasize, memdev); + cqr = dasd_smalloc_request(DASD_DIAG_MAGIC, 0, datasize, memdev); if (IS_ERR(cqr)) return cqr; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index c11770f..f15addf 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -730,7 +730,8 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, struct dasd_ccw_req *cqr; struct ccw1 *ccw; - cqr = dasd_smalloc_request("ECKD", 1 /* RCD */, ciw->count, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* RCD */, ciw->count, + device); if (IS_ERR(cqr)) { DBF_DEV_EVENT(DBF_WARNING, device, "%s", @@ -934,8 +935,7 @@ static int dasd_eckd_read_features(struct dasd_device *device) struct dasd_eckd_private *private; private = (struct dasd_eckd_private *) device->private; - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 1 /* PSF */ + 1 /* RSSD */ , + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, (sizeof(struct dasd_psf_prssd_data) + sizeof(struct dasd_rssd_features)), device); @@ -998,7 +998,7 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device, struct dasd_psf_ssc_data *psf_ssc_data; struct ccw1 *ccw; - cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ , + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ , sizeof(struct dasd_psf_ssc_data), device); @@ -1149,8 +1149,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device) goto out_err3; /* Read Device Characteristics */ - rc = dasd_generic_read_dev_chars(device, "ECKD", &private->rdc_data, - 64); + rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC, + &private->rdc_data, 64); if (rc) { DBF_EVENT(DBF_WARNING, "Read device characteristics failed, rc=%d for " @@ -1217,8 +1217,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) cplength = 8; datasize = sizeof(struct DE_eckd_data) + 2*sizeof(struct LO_eckd_data); - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - cplength, datasize, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device); if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; @@ -1499,8 +1498,7 @@ dasd_eckd_format_device(struct dasd_device * device, return ERR_PTR(-EINVAL); } /* Allocate the format ccw request. */ - fcp = dasd_smalloc_request(dasd_eckd_discipline.name, - cplength, datasize, device); + fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device); if (IS_ERR(fcp)) return fcp; @@ -1783,8 +1781,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( datasize += count*sizeof(struct LO_eckd_data); } /* Allocate the ccw request. */ - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - cplength, datasize, startdev); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, + startdev); if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; @@ -1948,8 +1946,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( cidaw * sizeof(unsigned long long); /* Allocate the ccw request. */ - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - cplength, datasize, startdev); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, + startdev); if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; @@ -2249,8 +2247,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( /* Allocate the ccw request. */ itcw_size = itcw_calc_size(0, ctidaw, 0); - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 0, itcw_size, startdev); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev); if (IS_ERR(cqr)) return cqr; @@ -2557,8 +2554,7 @@ dasd_eckd_release(struct dasd_device *device) if (!capable(CAP_SYS_ADMIN)) return -EACCES; - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 1, 32, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); @@ -2600,8 +2596,7 @@ dasd_eckd_reserve(struct dasd_device *device) if (!capable(CAP_SYS_ADMIN)) return -EACCES; - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 1, 32, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); @@ -2642,8 +2637,7 @@ dasd_eckd_steal_lock(struct dasd_device *device) if (!capable(CAP_SYS_ADMIN)) return -EACCES; - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 1, 32, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); @@ -2681,8 +2675,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp) struct ccw1 *ccw; int rc; - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 1 /* PSF */ + 1 /* RSSD */ , + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, (sizeof(struct dasd_psf_prssd_data) + sizeof(struct dasd_rssd_perf_stats_t)), device); @@ -2828,7 +2821,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp) } /* setup CCWs for PSF + RSSD */ - cqr = dasd_smalloc_request("ECKD", 2 , 0, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 , 0, device); if (IS_ERR(cqr)) { DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); @@ -3254,7 +3247,7 @@ int dasd_eckd_restore_device(struct dasd_device *device) /* Read Device Characteristics */ memset(&private->rdc_data, 0, sizeof(private->rdc_data)); - rc = dasd_generic_read_dev_chars(device, "ECKD", + rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC, &private->rdc_data, 64); if (rc) { DBF_EVENT(DBF_WARNING, diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index c24c8c3..6bd2bd5 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -464,7 +464,7 @@ int dasd_eer_enable(struct dasd_device *device) if (!device->discipline || strcmp(device->discipline->name, "ECKD")) return -EPERM; /* FIXME: -EMEDIUMTYPE ? */ - cqr = dasd_kmalloc_request("ECKD", 1 /* SNSS */, + cqr = dasd_kmalloc_request(DASD_ECKD_MAGIC, 1 /* SNSS */, SNSS_DATA_SIZE, device); if (IS_ERR(cqr)) return -ENOMEM; diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 31849ad..403730c 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -152,8 +152,8 @@ dasd_fba_check_characteristics(struct dasd_device *device) block->base = device; /* Read Device Characteristics */ - rc = dasd_generic_read_dev_chars(device, "FBA ", &private->rdc_data, - 32); + rc = dasd_generic_read_dev_chars(device, DASD_FBA_MAGIC, + &private->rdc_data, 32); if (rc) { DBF_EVENT(DBF_WARNING, "Read device characteristics returned " "error %d for device: %s", @@ -305,8 +305,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, datasize += (count - 1)*sizeof(struct LO_fba_data); } /* Allocate the ccw request. */ - cqr = dasd_smalloc_request(dasd_fba_discipline.name, - cplength, datasize, memdev); + cqr = dasd_smalloc_request(DASD_FBA_MAGIC, cplength, datasize, memdev); if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index b699ca3..5e47a1e 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -59,6 +59,11 @@ #include #include +/* DASD discipline magic */ +#define DASD_ECKD_MAGIC 0xC5C3D2C4 +#define DASD_DIAG_MAGIC 0xC4C9C1C7 +#define DASD_FBA_MAGIC 0xC6C2C140 + /* * SECTION: Type definitions */ @@ -540,9 +545,9 @@ extern struct block_device_operations dasd_device_operations; extern struct kmem_cache *dasd_page_cache; struct dasd_ccw_req * -dasd_kmalloc_request(char *, int, int, struct dasd_device *); +dasd_kmalloc_request(int , int, int, struct dasd_device *); struct dasd_ccw_req * -dasd_smalloc_request(char *, int, int, struct dasd_device *); +dasd_smalloc_request(int , int, int, struct dasd_device *); void dasd_kfree_request(struct dasd_ccw_req *, struct dasd_device *); void dasd_sfree_request(struct dasd_ccw_req *, struct dasd_device *); @@ -587,7 +592,7 @@ void dasd_generic_handle_state_change(struct dasd_device *); int dasd_generic_pm_freeze(struct ccw_device *); int dasd_generic_restore_device(struct ccw_device *); -int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int); +int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int); char *dasd_get_sense(struct irb *); /* externals in dasd_devmap.c */ -- cgit v0.10.2 From ca99dab01dd63dcc413395bd3e75b0be152dfefc Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Fri, 11 Sep 2009 10:28:30 +0200 Subject: [S390] dasd: fix message naming This patch fixes message naming so that generic dasd messages do not contain the device discipline. For this purpose the dev_ makros are replaced by pr_ makros for generic dasd messages. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 27991b6..e8ff7b0 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -7,7 +7,7 @@ * */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-eckd" #include #include diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index b9efd09..70a008c 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -5,7 +5,7 @@ * Author(s): Stefan Weinhuber */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-eckd" #include #include diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 0b89796..4e49b4a 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -8,7 +8,7 @@ * */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-diag" #include #include diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index f15addf..a1ce573 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -10,7 +10,7 @@ * Author.........: Nigel Hislop */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-eckd" #include #include diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 6bd2bd5..d96039e 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -6,7 +6,7 @@ * Author(s): Stefan Weinhuber */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-eckd" #include #include diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index cb8f9ce..7656384 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -99,8 +99,8 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr) cqr->lpm = LPM_ANYPATH; cqr->status = DASD_CQR_FILLED; } else { - dev_err(&device->cdev->dev, - "default ERP has run out of retries and failed\n"); + pr_err("%s: default ERP has run out of retries and failed\n", + dev_name(&device->cdev->dev)); cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); } diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 403730c..f245377 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -5,7 +5,7 @@ * Copyright IBM Corp. 1999, 2009 */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-fba" #include #include diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index df918ef..f756a1b 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -98,8 +98,8 @@ static int dasd_ioctl_quiesce(struct dasd_block *block) if (!capable (CAP_SYS_ADMIN)) return -EACCES; - dev_info(&base->cdev->dev, "The DASD has been put in the quiesce " - "state\n"); + pr_info("%s: The DASD has been put in the quiesce " + "state\n", dev_name(&base->cdev->dev)); spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); base->stopped |= DASD_STOPPED_QUIESCE; spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); @@ -119,8 +119,8 @@ static int dasd_ioctl_resume(struct dasd_block *block) if (!capable (CAP_SYS_ADMIN)) return -EACCES; - dev_info(&base->cdev->dev, "I/O operations have been resumed " - "on the DASD\n"); + pr_info("%s: I/O operations have been resumed " + "on the DASD\n", dev_name(&base->cdev->dev)); spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); base->stopped &= ~DASD_STOPPED_QUIESCE; spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); @@ -146,8 +146,8 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) return -EPERM; if (base->state != DASD_STATE_BASIC) { - dev_warn(&base->cdev->dev, - "The DASD cannot be formatted while it is enabled\n"); + pr_warning("%s: The DASD cannot be formatted while it is " + "enabled\n", dev_name(&base->cdev->dev)); return -EBUSY; } @@ -175,9 +175,9 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) dasd_sfree_request(cqr, cqr->memdev); if (rc) { if (rc != -ERESTARTSYS) - dev_err(&base->cdev->dev, - "Formatting unit %d failed with " - "rc=%d\n", fdata->start_unit, rc); + pr_err("%s: Formatting unit %d failed with " + "rc=%d\n", dev_name(&base->cdev->dev), + fdata->start_unit, rc); return rc; } fdata->start_unit++; @@ -204,9 +204,9 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp) if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) return -EFAULT; if (bdev != bdev->bd_contains) { - dev_warn(&block->base->cdev->dev, - "The specified DASD is a partition and cannot be " - "formatted\n"); + pr_warning("%s: The specified DASD is a partition and cannot " + "be formatted\n", + dev_name(&block->base->cdev->dev)); return -EINVAL; } return dasd_format(block, &fdata); -- cgit v0.10.2 From 05e7ff7da78bad3edc1290ed86b4a37da72ced62 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:28:31 +0200 Subject: [S390] introduce get_clock_monotonic Introduce get_clock_monotonic() function which can be used to get a (fast) timestamp. Resolution is the same as for get_clock(). The only difference is that the timestamps are monotonic and don't jump backward or forward. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index cc21e3e..24aa1cd 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h @@ -90,4 +90,18 @@ unsigned long long monotonic_clock(void); extern u64 sched_clock_base_cc; +/** + * get_clock_monotonic - returns current time in clock rate units + * + * The caller must ensure that preemption is disabled. + * The clock and sched_clock_base get changed via stop_machine. + * Therefore preemption must be disabled when calling this + * function, otherwise the returned value is not guaranteed to + * be monotonic. + */ +static inline unsigned long long get_clock_monotonic(void) +{ + return get_clock_xt() - sched_clock_base_cc; +} + #endif diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index d4c8e9c..54e327e 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -60,6 +60,7 @@ #define TICK_SIZE tick u64 sched_clock_base_cc = -1; /* Force to data section. */ +EXPORT_SYMBOL_GPL(sched_clock_base_cc); static DEFINE_PER_CPU(struct clock_event_device, comparators); @@ -68,7 +69,7 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators); */ unsigned long long notrace sched_clock(void) { - return ((get_clock_xt() - sched_clock_base_cc) * 125) >> 9; + return (get_clock_monotonic() * 125) >> 9; } /* -- cgit v0.10.2 From 04efc3be767cfed0d348fd598eba8fe5f5bf5fe6 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:28:32 +0200 Subject: [S390] convert/optimize csum_fold() to C In the meantime gcc generates better code than the old inline assemblies do. Original inline assembly results in: lr %r1,%r2 sr %r3,%r3 lr %r2,%r1 srdl %r2,16 alr %r2,%r3 alr %r1,%r2 srl %r1,16 xilf %r1,65535 llghr %r2,%r1 br %r14 Out of the C code gcc generates this: rll %r1,%r2,16 ar %r1,%r2 srl %r1,16 xilf %r1,65535 llghr %r2,%r1 br %r14 In addition we don't have any static register allocations anymore and gcc is free to shuffle instructions around for better pipeline usage. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/checksum.h b/arch/s390/include/asm/checksum.h index d5a8e7c..6c00f68 100644 --- a/arch/s390/include/asm/checksum.h +++ b/arch/s390/include/asm/checksum.h @@ -78,28 +78,11 @@ csum_partial_copy_nocheck (const void *src, void *dst, int len, __wsum sum) */ static inline __sum16 csum_fold(__wsum sum) { -#ifndef __s390x__ - register_pair rp; + u32 csum = (__force u32) sum; - asm volatile( - " slr %N1,%N1\n" /* %0 = H L */ - " lr %1,%0\n" /* %0 = H L, %1 = H L 0 0 */ - " srdl %1,16\n" /* %0 = H L, %1 = 0 H L 0 */ - " alr %1,%N1\n" /* %0 = H L, %1 = L H L 0 */ - " alr %0,%1\n" /* %0 = H+L+C L+H */ - " srl %0,16\n" /* %0 = H+L+C */ - : "+&d" (sum), "=d" (rp) : : "cc"); -#else /* __s390x__ */ - asm volatile( - " sr 3,3\n" /* %0 = H*65536 + L */ - " lr 2,%0\n" /* %0 = H L, 2/3 = H L / 0 0 */ - " srdl 2,16\n" /* %0 = H L, 2/3 = 0 H / L 0 */ - " alr 2,3\n" /* %0 = H L, 2/3 = L H / L 0 */ - " alr %0,2\n" /* %0 = H+L+C L+H */ - " srl %0,16\n" /* %0 = H+L+C */ - : "+&d" (sum) : : "cc", "2", "3"); -#endif /* __s390x__ */ - return (__force __sum16) ~sum; + csum += (csum >> 16) + (csum << 16); + csum >>= 16; + return (__force __sum16) ~csum; } /* -- cgit v0.10.2 From 6ac2a4ddd10d6916785b4c566d521025c855f823 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 11 Sep 2009 10:28:33 +0200 Subject: [S390] improve mcount code Move the 64 bit mount code from mcount.S into mcount64.S and avoid code duplication. Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index c75ed43..7949553 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -41,7 +41,7 @@ obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_KPROBES) += kprobes.o -obj-$(CONFIG_FUNCTION_TRACER) += mcount.o +obj-$(CONFIG_FUNCTION_TRACER) += $(if $(CONFIG_64BIT),mcount64.o,mcount.o) obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S index 2a0a5e9..dfe015d 100644 --- a/arch/s390/kernel/mcount.S +++ b/arch/s390/kernel/mcount.S @@ -11,111 +11,27 @@ ftrace_stub: br %r14 -#ifdef CONFIG_64BIT - -#ifdef CONFIG_DYNAMIC_FTRACE - .globl _mcount _mcount: - br %r14 - - .globl ftrace_caller -ftrace_caller: - larl %r1,function_trace_stop - icm %r1,0xf,0(%r1) - bnzr %r14 - stmg %r2,%r5,32(%r15) - stg %r14,112(%r15) - lgr %r1,%r15 - aghi %r15,-160 - stg %r1,__SF_BACKCHAIN(%r15) - lgr %r2,%r14 - lg %r3,168(%r15) - larl %r14,ftrace_dyn_func - lg %r14,0(%r14) - basr %r14,%r14 -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - .globl ftrace_graph_caller -ftrace_graph_caller: - # This unconditional branch gets runtime patched. Change only if - # you know what you are doing. See ftrace_enable_graph_caller(). - j 0f - lg %r2,272(%r15) - lg %r3,168(%r15) - brasl %r14,prepare_ftrace_return - stg %r2,168(%r15) -0: -#endif - aghi %r15,160 - lmg %r2,%r5,32(%r15) - lg %r14,112(%r15) +#ifdef CONFIG_DYNAMIC_FTRACE br %r14 .data .globl ftrace_dyn_func ftrace_dyn_func: - .quad ftrace_stub + .long ftrace_stub .previous -#else /* CONFIG_DYNAMIC_FTRACE */ - - .globl _mcount -_mcount: - larl %r1,function_trace_stop - icm %r1,0xf,0(%r1) - bnzr %r14 - stmg %r2,%r5,32(%r15) - stg %r14,112(%r15) - lgr %r1,%r15 - aghi %r15,-160 - stg %r1,__SF_BACKCHAIN(%r15) - lgr %r2,%r14 - lg %r3,168(%r15) - larl %r14,ftrace_trace_function - lg %r14,0(%r14) - basr %r14,%r14 -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - lg %r2,272(%r15) - lg %r3,168(%r15) - brasl %r14,prepare_ftrace_return - stg %r2,168(%r15) -#endif - aghi %r15,160 - lmg %r2,%r5,32(%r15) - lg %r14,112(%r15) - br %r14 - -#endif /* CONFIG_DYNAMIC_FTRACE */ - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - - .globl return_to_handler -return_to_handler: - stmg %r2,%r5,32(%r15) - lgr %r1,%r15 - aghi %r15,-160 - stg %r1,__SF_BACKCHAIN(%r15) - brasl %r14,ftrace_return_to_handler - aghi %r15,160 - lgr %r14,%r2 - lmg %r2,%r5,32(%r15) - br %r14 - -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ - -#else /* CONFIG_64BIT */ - -#ifdef CONFIG_DYNAMIC_FTRACE - - .globl _mcount -_mcount: - br %r14 - .globl ftrace_caller ftrace_caller: +#endif stm %r2,%r5,16(%r15) bras %r1,2f +#ifdef CONFIG_DYNAMIC_FTRACE +0: .long ftrace_dyn_func +#else 0: .long ftrace_trace_function +#endif 1: .long function_trace_stop 2: l %r2,1b-0b(%r1) icm %r2,0xf,0(%r2) @@ -131,53 +47,13 @@ ftrace_caller: l %r14,0(%r14) basr %r14,%r14 #ifdef CONFIG_FUNCTION_GRAPH_TRACER +#ifdef CONFIG_DYNAMIC_FTRACE .globl ftrace_graph_caller ftrace_graph_caller: # This unconditional branch gets runtime patched. Change only if # you know what you are doing. See ftrace_enable_graph_caller(). j 1f - bras %r1,0f - .long prepare_ftrace_return -0: l %r2,152(%r15) - l %r4,0(%r1) - l %r3,100(%r15) - basr %r14,%r4 - st %r2,100(%r15) -1: #endif - ahi %r15,96 - l %r14,56(%r15) -3: lm %r2,%r5,16(%r15) - br %r14 - - .data - .globl ftrace_dyn_func -ftrace_dyn_func: - .long ftrace_stub - .previous - -#else /* CONFIG_DYNAMIC_FTRACE */ - - .globl _mcount -_mcount: - stm %r2,%r5,16(%r15) - bras %r1,2f -0: .long ftrace_trace_function -1: .long function_trace_stop -2: l %r2,1b-0b(%r1) - icm %r2,0xf,0(%r2) - jnz 3f - st %r14,56(%r15) - lr %r0,%r15 - ahi %r15,-96 - l %r3,100(%r15) - la %r2,0(%r14) - st %r0,__SF_BACKCHAIN(%r15) - la %r3,0(%r3) - l %r14,0b-0b(%r1) - l %r14,0(%r14) - basr %r14,%r14 -#ifdef CONFIG_FUNCTION_GRAPH_TRACER bras %r1,0f .long prepare_ftrace_return 0: l %r2,152(%r15) @@ -185,14 +61,13 @@ _mcount: l %r3,100(%r15) basr %r14,%r4 st %r2,100(%r15) +1: #endif ahi %r15,96 l %r14,56(%r15) 3: lm %r2,%r5,16(%r15) br %r14 -#endif /* CONFIG_DYNAMIC_FTRACE */ - #ifdef CONFIG_FUNCTION_GRAPH_TRACER .globl return_to_handler @@ -211,6 +86,4 @@ return_to_handler: lm %r2,%r5,16(%r15) br %r14 -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ - -#endif /* CONFIG_64BIT */ +#endif diff --git a/arch/s390/kernel/mcount64.S b/arch/s390/kernel/mcount64.S new file mode 100644 index 0000000..c37211c --- /dev/null +++ b/arch/s390/kernel/mcount64.S @@ -0,0 +1,78 @@ +/* + * Copyright IBM Corp. 2008,2009 + * + * Author(s): Heiko Carstens , + * + */ + +#include + + .globl ftrace_stub +ftrace_stub: + br %r14 + + .globl _mcount +_mcount: +#ifdef CONFIG_DYNAMIC_FTRACE + br %r14 + + .data + .globl ftrace_dyn_func +ftrace_dyn_func: + .quad ftrace_stub + .previous + + .globl ftrace_caller +ftrace_caller: +#endif + larl %r1,function_trace_stop + icm %r1,0xf,0(%r1) + bnzr %r14 + stmg %r2,%r5,32(%r15) + stg %r14,112(%r15) + lgr %r1,%r15 + aghi %r15,-160 + stg %r1,__SF_BACKCHAIN(%r15) + lgr %r2,%r14 + lg %r3,168(%r15) +#ifdef CONFIG_DYNAMIC_FTRACE + larl %r14,ftrace_dyn_func +#else + larl %r14,ftrace_trace_function +#endif + lg %r14,0(%r14) + basr %r14,%r14 +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +#ifdef CONFIG_DYNAMIC_FTRACE + .globl ftrace_graph_caller +ftrace_graph_caller: + # This unconditional branch gets runtime patched. Change only if + # you know what you are doing. See ftrace_enable_graph_caller(). + j 0f +#endif + lg %r2,272(%r15) + lg %r3,168(%r15) + brasl %r14,prepare_ftrace_return + stg %r2,168(%r15) +0: +#endif + aghi %r15,160 + lmg %r2,%r5,32(%r15) + lg %r14,112(%r15) + br %r14 + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + + .globl return_to_handler +return_to_handler: + stmg %r2,%r5,32(%r15) + lgr %r1,%r15 + aghi %r15,-160 + stg %r1,__SF_BACKCHAIN(%r15) + brasl %r14,ftrace_return_to_handler + aghi %r15,160 + lgr %r14,%r2 + lmg %r2,%r5,32(%r15) + br %r14 + +#endif -- cgit v0.10.2 From 12751058515860ed43c8f874ebcb2097b323736a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:28:34 +0200 Subject: [S390] atomic ops: add effecient atomic64 support for 31 bit Use compare double and swap to implement efficient atomic64 ops for 31 bit. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 2ae5d72..47836b9 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -95,7 +95,6 @@ config S390 select HAVE_ARCH_TRACEHOOK select INIT_ALL_POSSIBLE select HAVE_PERF_COUNTERS - select GENERIC_ATOMIC64 if !64BIT config SCHED_OMIT_FRAME_POINTER bool diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index c7d0abf..b491d5e 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -1,28 +1,20 @@ #ifndef __ARCH_S390_ATOMIC__ #define __ARCH_S390_ATOMIC__ -#include -#include - /* - * include/asm-s390/atomic.h + * Copyright 1999,2009 IBM Corp. + * Author(s): Martin Schwidefsky , + * Denis Joseph Barrow, + * Arnd Bergmann , * - * S390 version - * Copyright (C) 1999-2005 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - * Denis Joseph Barrow, - * Arnd Bergmann (arndb@de.ibm.com) - * - * Derived from "include/asm-i386/bitops.h" - * Copyright (C) 1992, Linus Torvalds + * Atomic operations that C can't guarantee us. + * Useful for resource counting etc. + * s390 uses 'Compare And Swap' for atomicity in SMP enviroment. * */ -/* - * Atomic operations that C can't guarantee us. Useful for - * resource counting etc.. - * S390 uses 'Compare And Swap' for atomicity in SMP enviroment - */ +#include +#include #define ATOMIC_INIT(i) { (i) } @@ -146,9 +138,10 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) #undef __CS_LOOP -#ifdef __s390x__ #define ATOMIC64_INIT(i) { (i) } +#ifdef CONFIG_64BIT + #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) #define __CSG_LOOP(ptr, op_val, op_string) ({ \ @@ -202,21 +195,11 @@ static __inline__ long long atomic64_add_return(long long i, atomic64_t * v) { return __CSG_LOOP(v, i, "agr"); } -#define atomic64_add(_i, _v) atomic64_add_return(_i, _v) -#define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0) -#define atomic64_inc(_v) atomic64_add_return(1, _v) -#define atomic64_inc_return(_v) atomic64_add_return(1, _v) -#define atomic64_inc_and_test(_v) (atomic64_add_return(1, _v) == 0) static __inline__ long long atomic64_sub_return(long long i, atomic64_t * v) { return __CSG_LOOP(v, i, "sgr"); } -#define atomic64_sub(_i, _v) atomic64_sub_return(_i, _v) -#define atomic64_sub_and_test(_i, _v) (atomic64_sub_return(_i, _v) == 0) -#define atomic64_dec(_v) atomic64_sub_return(1, _v) -#define atomic64_dec_return(_v) atomic64_sub_return(1, _v) -#define atomic64_dec_and_test(_v) (atomic64_sub_return(1, _v) == 0) static __inline__ void atomic64_clear_mask(unsigned long mask, atomic64_t * v) { @@ -249,6 +232,111 @@ static __inline__ long long atomic64_cmpxchg(atomic64_t *v, return old; } +#undef __CSG_LOOP + +#else /* CONFIG_64BIT */ + +typedef struct { + long long counter; +} atomic64_t; + +static inline long long atomic64_read(const atomic64_t *v) +{ + register_pair rp; + + asm volatile( + " lm %0,%N0,0(%1)" + : "=&d" (rp) + : "a" (&v->counter), "m" (v->counter) + ); + return rp.pair; +} + +static inline void atomic64_set(atomic64_t *v, long long i) +{ + register_pair rp = {.pair = i}; + + asm volatile( + " stm %1,%N1,0(%2)" + : "=m" (v->counter) + : "d" (rp), "a" (&v->counter) + ); +} + +static inline long long atomic64_xchg(atomic64_t *v, long long new) +{ + register_pair rp_new = {.pair = new}; + register_pair rp_old; + + asm volatile( + " lm %0,%N0,0(%2)\n" + "0: cds %0,%3,0(%2)\n" + " jl 0b\n" + : "=&d" (rp_old), "+m" (v->counter) + : "a" (&v->counter), "d" (rp_new) + : "cc"); + return rp_old.pair; +} + +static inline long long atomic64_cmpxchg(atomic64_t *v, + long long old, long long new) +{ + register_pair rp_old = {.pair = old}; + register_pair rp_new = {.pair = new}; + + asm volatile( + " cds %0,%3,0(%2)" + : "+&d" (rp_old), "+m" (v->counter) + : "a" (&v->counter), "d" (rp_new) + : "cc"); + return rp_old.pair; +} + + +static inline long long atomic64_add_return(long long i, atomic64_t *v) +{ + long long old, new; + + do { + old = atomic64_read(v); + new = old + i; + } while (atomic64_cmpxchg(v, old, new) != old); + return new; +} + +static inline long long atomic64_sub_return(long long i, atomic64_t *v) +{ + long long old, new; + + do { + old = atomic64_read(v); + new = old - i; + } while (atomic64_cmpxchg(v, old, new) != old); + return new; +} + +static inline void atomic64_set_mask(unsigned long long mask, atomic64_t *v) +{ + long long old, new; + + do { + old = atomic64_read(v); + new = old | mask; + } while (atomic64_cmpxchg(v, old, new) != old); +} + +static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v) +{ + long long old, new; + + do { + old = atomic64_read(v); + new = old & mask; + } while (atomic64_cmpxchg(v, old, new) != old); +} + +#endif /* CONFIG_64BIT */ + static __inline__ int atomic64_add_unless(atomic64_t *v, long long a, long long u) { @@ -265,15 +353,17 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, return c != u; } -#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) - -#undef __CSG_LOOP - -#else /* __s390x__ */ - -#include - -#endif /* __s390x__ */ +#define atomic64_add(_i, _v) atomic64_add_return(_i, _v) +#define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0) +#define atomic64_inc(_v) atomic64_add_return(1, _v) +#define atomic64_inc_return(_v) atomic64_add_return(1, _v) +#define atomic64_inc_and_test(_v) (atomic64_add_return(1, _v) == 0) +#define atomic64_sub(_i, _v) atomic64_sub_return(_i, _v) +#define atomic64_sub_and_test(_i, _v) (atomic64_sub_return(_i, _v) == 0) +#define atomic64_dec(_v) atomic64_sub_return(1, _v) +#define atomic64_dec_return(_v) atomic64_sub_return(1, _v) +#define atomic64_dec_and_test(_v) (atomic64_sub_return(1, _v) == 0) +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) #define smp_mb__before_atomic_dec() smp_mb() #define smp_mb__after_atomic_dec() smp_mb() -- cgit v0.10.2 From bfe3349b516df011dcf6462b0fd748a6f5c2e8af Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:28:35 +0200 Subject: [S390] atomic ops: small cleanups Couple of coding style fixes, replace __inline__ with inline and remove #ifdef __KERNEL_- since the header file isn't exported. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index b491d5e..ae7c8f9 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -18,8 +18,6 @@ #define ATOMIC_INIT(i) { (i) } -#ifdef __KERNEL__ - #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) #define __CS_LOOP(ptr, op_val, op_string) ({ \ @@ -69,7 +67,7 @@ static inline void atomic_set(atomic_t *v, int i) barrier(); } -static __inline__ int atomic_add_return(int i, atomic_t * v) +static inline int atomic_add_return(int i, atomic_t *v) { return __CS_LOOP(v, i, "ar"); } @@ -79,7 +77,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v) #define atomic_inc_return(_v) atomic_add_return(1, _v) #define atomic_inc_and_test(_v) (atomic_add_return(1, _v) == 0) -static __inline__ int atomic_sub_return(int i, atomic_t * v) +static inline int atomic_sub_return(int i, atomic_t *v) { return __CS_LOOP(v, i, "sr"); } @@ -89,19 +87,19 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v) #define atomic_dec_return(_v) atomic_sub_return(1, _v) #define atomic_dec_and_test(_v) (atomic_sub_return(1, _v) == 0) -static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t * v) +static inline void atomic_clear_mask(unsigned long mask, atomic_t *v) { - __CS_LOOP(v, ~mask, "nr"); + __CS_LOOP(v, ~mask, "nr"); } -static __inline__ void atomic_set_mask(unsigned long mask, atomic_t * v) +static inline void atomic_set_mask(unsigned long mask, atomic_t *v) { - __CS_LOOP(v, mask, "or"); + __CS_LOOP(v, mask, "or"); } #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) -static __inline__ int atomic_cmpxchg(atomic_t *v, int old, int new) +static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) asm volatile( @@ -119,7 +117,7 @@ static __inline__ int atomic_cmpxchg(atomic_t *v, int old, int new) return old; } -static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) +static inline int atomic_add_unless(atomic_t *v, int a, int u) { int c, old; c = atomic_read(v); @@ -155,7 +153,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) : "=&d" (old_val), "=&d" (new_val), \ "=Q" (((atomic_t *)(ptr))->counter) \ : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \ - : "cc", "memory" ); \ + : "cc", "memory"); \ new_val; \ }) @@ -173,7 +171,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) "=m" (((atomic_t *)(ptr))->counter) \ : "a" (ptr), "d" (op_val), \ "m" (((atomic_t *)(ptr))->counter) \ - : "cc", "memory" ); \ + : "cc", "memory"); \ new_val; \ }) @@ -191,29 +189,29 @@ static inline void atomic64_set(atomic64_t *v, long long i) barrier(); } -static __inline__ long long atomic64_add_return(long long i, atomic64_t * v) +static inline long long atomic64_add_return(long long i, atomic64_t *v) { return __CSG_LOOP(v, i, "agr"); } -static __inline__ long long atomic64_sub_return(long long i, atomic64_t * v) +static inline long long atomic64_sub_return(long long i, atomic64_t *v) { return __CSG_LOOP(v, i, "sgr"); } -static __inline__ void atomic64_clear_mask(unsigned long mask, atomic64_t * v) +static inline void atomic64_clear_mask(unsigned long mask, atomic64_t *v) { - __CSG_LOOP(v, ~mask, "ngr"); + __CSG_LOOP(v, ~mask, "ngr"); } -static __inline__ void atomic64_set_mask(unsigned long mask, atomic64_t * v) +static inline void atomic64_set_mask(unsigned long mask, atomic64_t *v) { - __CSG_LOOP(v, mask, "ogr"); + __CSG_LOOP(v, mask, "ogr"); } #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) -static __inline__ long long atomic64_cmpxchg(atomic64_t *v, +static inline long long atomic64_cmpxchg(atomic64_t *v, long long old, long long new) { #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) @@ -337,8 +335,7 @@ static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v) #endif /* CONFIG_64BIT */ -static __inline__ int atomic64_add_unless(atomic64_t *v, - long long a, long long u) +static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) { long long c, old; c = atomic64_read(v); @@ -371,5 +368,5 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, #define smp_mb__after_atomic_inc() smp_mb() #include -#endif /* __KERNEL__ */ + #endif /* __ARCH_S390_ATOMIC__ */ -- cgit v0.10.2 From f3d1263e81daf2be1353baf1ad3f6e25d135f2c5 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:28:36 +0200 Subject: [S390] hibernation: remove dead file There is no caller of do_after_copyback() anywhere. Remove it. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/power/Makefile b/arch/s390/power/Makefile index 973bb45..ee2f279 100644 --- a/arch/s390/power/Makefile +++ b/arch/s390/power/Makefile @@ -4,5 +4,4 @@ obj-$(CONFIG_HIBERNATION) += suspend.o obj-$(CONFIG_HIBERNATION) += swsusp.o -obj-$(CONFIG_HIBERNATION) += swsusp_64.o obj-$(CONFIG_HIBERNATION) += swsusp_asm64.o diff --git a/arch/s390/power/swsusp_64.c b/arch/s390/power/swsusp_64.c deleted file mode 100644 index 9516a51..0000000 --- a/arch/s390/power/swsusp_64.c +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Support for suspend and resume on s390 - * - * Copyright IBM Corp. 2009 - * - * Author(s): Hans-Joachim Picht - * - */ - -#include -#include - -void do_after_copyback(void) -{ - mb(); -} - -- cgit v0.10.2 From c48ff644f2c86f34f69f382b68b16c6d30854783 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:28:37 +0200 Subject: [S390] hibernation: merge files and move to kernel/ Merge the nearly empty C files and move everything from power/ to kernel/. That way the files are easier to handle. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 0ff387c..fc8fb20 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -88,8 +88,7 @@ LDFLAGS_vmlinux := -e start head-y := arch/s390/kernel/head.o arch/s390/kernel/init_task.o core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \ - arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/ \ - arch/s390/power/ + arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/ libs-y += arch/s390/lib/ drivers-y += drivers/s390/ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 7949553..c7be8e1 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -32,7 +32,7 @@ extra-y += head.o init_task.o vmlinux.lds obj-$(CONFIG_MODULES) += s390_ksyms.o module.o obj-$(CONFIG_SMP) += smp.o topology.o - +obj-$(CONFIG_HIBERNATION) += suspend.o swsusp_asm64.o obj-$(CONFIG_AUDIT) += audit.o compat-obj-$(CONFIG_AUDIT) += compat_audit.o obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \ diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c new file mode 100644 index 0000000..086bee9 --- /dev/null +++ b/arch/s390/kernel/suspend.c @@ -0,0 +1,73 @@ +/* + * Suspend support specific for s390. + * + * Copyright IBM Corp. 2009 + * + * Author(s): Hans-Joachim Picht + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * References to section boundaries + */ +extern const void __nosave_begin, __nosave_end; + +/* + * check if given pfn is in the 'nosave' or in the read only NSS section + */ +int pfn_is_nosave(unsigned long pfn) +{ + unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; + unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) + >> PAGE_SHIFT; + unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1; + unsigned long stext_pfn = PFN_DOWN(__pa(&_stext)); + + if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn) + return 1; + if (pfn >= stext_pfn && pfn <= eshared_pfn) { + if (ipl_info.type == IPL_TYPE_NSS) + return 1; + } else if ((tprot(pfn * PAGE_SIZE) && pfn > 0)) + return 1; + return 0; +} + +void save_processor_state(void) +{ + /* swsusp_arch_suspend() actually saves all cpu register contents. + * Machine checks must be disabled since swsusp_arch_suspend() stores + * register contents to their lowcore save areas. That's the same + * place where register contents on machine checks would be saved. + * To avoid register corruption disable machine checks. + * We must also disable machine checks in the new psw mask for + * program checks, since swsusp_arch_suspend() may generate program + * checks. Disabling machine checks for all other new psw masks is + * just paranoia. + */ + local_mcck_disable(); + /* Disable lowcore protection */ + __ctl_clear_bit(0,28); + S390_lowcore.external_new_psw.mask &= ~PSW_MASK_MCHECK; + S390_lowcore.svc_new_psw.mask &= ~PSW_MASK_MCHECK; + S390_lowcore.io_new_psw.mask &= ~PSW_MASK_MCHECK; + S390_lowcore.program_new_psw.mask &= ~PSW_MASK_MCHECK; +} + +void restore_processor_state(void) +{ + S390_lowcore.external_new_psw.mask |= PSW_MASK_MCHECK; + S390_lowcore.svc_new_psw.mask |= PSW_MASK_MCHECK; + S390_lowcore.io_new_psw.mask |= PSW_MASK_MCHECK; + S390_lowcore.program_new_psw.mask |= PSW_MASK_MCHECK; + /* Enable lowcore protection */ + __ctl_set_bit(0,28); + local_mcck_enable(); +} diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S new file mode 100644 index 0000000..7cd6b09 --- /dev/null +++ b/arch/s390/kernel/swsusp_asm64.S @@ -0,0 +1,184 @@ +/* + * S390 64-bit swsusp implementation + * + * Copyright IBM Corp. 2009 + * + * Author(s): Hans-Joachim Picht + * Michael Holzheu + */ + +#include +#include +#include + +/* + * Save register context in absolute 0 lowcore and call swsusp_save() to + * create in-memory kernel image. The context is saved in the designated + * "store status" memory locations (see POP). + * We return from this function twice. The first time during the suspend to + * disk process. The second time via the swsusp_arch_resume() function + * (see below) in the resume process. + * This function runs with disabled interrupts. + */ + .section .text + .align 4 + .globl swsusp_arch_suspend +swsusp_arch_suspend: + stmg %r6,%r15,__SF_GPRS(%r15) + lgr %r1,%r15 + aghi %r15,-STACK_FRAME_OVERHEAD + stg %r1,__SF_BACKCHAIN(%r15) + + /* Deactivate DAT */ + stnsm __SF_EMPTY(%r15),0xfb + + /* Store prefix register on stack */ + stpx __SF_EMPTY(%r15) + + /* Save prefix register contents for lowcore */ + llgf %r4,__SF_EMPTY(%r15) + + /* Get pointer to save area */ + lghi %r1,0x1000 + + /* Store registers */ + mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ + stfpc 0x31c(%r1) /* store fpu control */ + std 0,0x200(%r1) /* store f0 */ + std 1,0x208(%r1) /* store f1 */ + std 2,0x210(%r1) /* store f2 */ + std 3,0x218(%r1) /* store f3 */ + std 4,0x220(%r1) /* store f4 */ + std 5,0x228(%r1) /* store f5 */ + std 6,0x230(%r1) /* store f6 */ + std 7,0x238(%r1) /* store f7 */ + std 8,0x240(%r1) /* store f8 */ + std 9,0x248(%r1) /* store f9 */ + std 10,0x250(%r1) /* store f10 */ + std 11,0x258(%r1) /* store f11 */ + std 12,0x260(%r1) /* store f12 */ + std 13,0x268(%r1) /* store f13 */ + std 14,0x270(%r1) /* store f14 */ + std 15,0x278(%r1) /* store f15 */ + stam %a0,%a15,0x340(%r1) /* store access registers */ + stctg %c0,%c15,0x380(%r1) /* store control registers */ + stmg %r0,%r15,0x280(%r1) /* store general registers */ + + stpt 0x328(%r1) /* store timer */ + stckc 0x330(%r1) /* store clock comparator */ + + /* Activate DAT */ + stosm __SF_EMPTY(%r15),0x04 + + /* Set prefix page to zero */ + xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) + spx __SF_EMPTY(%r15) + + lghi %r2,0 + lghi %r3,2*PAGE_SIZE + lghi %r5,2*PAGE_SIZE +1: mvcle %r2,%r4,0 + jo 1b + + /* Save image */ + brasl %r14,swsusp_save + + /* Restore prefix register and return */ + lghi %r1,0x1000 + spx 0x318(%r1) + lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) + lghi %r2,0 + br %r14 + +/* + * Restore saved memory image to correct place and restore register context. + * Then we return to the function that called swsusp_arch_suspend(). + * swsusp_arch_resume() runs with disabled interrupts. + */ + .globl swsusp_arch_resume +swsusp_arch_resume: + stmg %r6,%r15,__SF_GPRS(%r15) + lgr %r1,%r15 + aghi %r15,-STACK_FRAME_OVERHEAD + stg %r1,__SF_BACKCHAIN(%r15) + +#ifdef CONFIG_SMP + /* Save boot cpu number */ + brasl %r14,smp_get_phys_cpu_id + lgr %r10,%r2 +#endif + /* Deactivate DAT */ + stnsm __SF_EMPTY(%r15),0xfb + + /* Set prefix page to zero */ + xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) + spx __SF_EMPTY(%r15) + + /* Restore saved image */ + larl %r1,restore_pblist + lg %r1,0(%r1) + ltgr %r1,%r1 + jz 2f +0: + lg %r2,8(%r1) + lg %r4,0(%r1) + lghi %r3,PAGE_SIZE + lghi %r5,PAGE_SIZE +1: + mvcle %r2,%r4,0 + jo 1b + lg %r1,16(%r1) + ltgr %r1,%r1 + jnz 0b +2: + ptlb /* flush tlb */ + + /* Restore registers */ + lghi %r13,0x1000 /* %r1 = pointer to save arae */ + + spt 0x328(%r13) /* reprogram timer */ + //sckc 0x330(%r13) /* set clock comparator */ + + lctlg %c0,%c15,0x380(%r13) /* load control registers */ + lam %a0,%a15,0x340(%r13) /* load access registers */ + + lfpc 0x31c(%r13) /* load fpu control */ + ld 0,0x200(%r13) /* load f0 */ + ld 1,0x208(%r13) /* load f1 */ + ld 2,0x210(%r13) /* load f2 */ + ld 3,0x218(%r13) /* load f3 */ + ld 4,0x220(%r13) /* load f4 */ + ld 5,0x228(%r13) /* load f5 */ + ld 6,0x230(%r13) /* load f6 */ + ld 7,0x238(%r13) /* load f7 */ + ld 8,0x240(%r13) /* load f8 */ + ld 9,0x248(%r13) /* load f9 */ + ld 10,0x250(%r13) /* load f10 */ + ld 11,0x258(%r13) /* load f11 */ + ld 12,0x260(%r13) /* load f12 */ + ld 13,0x268(%r13) /* load f13 */ + ld 14,0x270(%r13) /* load f14 */ + ld 15,0x278(%r13) /* load f15 */ + + /* Load old stack */ + lg %r15,0x2f8(%r13) + + /* Pointer to save area */ + lghi %r13,0x1000 + +#ifdef CONFIG_SMP + /* Switch CPUs */ + lgr %r2,%r10 /* get cpu id */ + llgf %r3,0x318(%r13) + brasl %r14,smp_switch_boot_cpu_in_resume +#endif + /* Restore prefix register */ + spx 0x318(%r13) + + /* Activate DAT */ + stosm __SF_EMPTY(%r15),0x04 + + /* Return 0 */ + lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) + lghi %r2,0 + br %r14 diff --git a/arch/s390/power/Makefile b/arch/s390/power/Makefile deleted file mode 100644 index ee2f279..0000000 --- a/arch/s390/power/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for s390 PM support -# - -obj-$(CONFIG_HIBERNATION) += suspend.o -obj-$(CONFIG_HIBERNATION) += swsusp.o -obj-$(CONFIG_HIBERNATION) += swsusp_asm64.o diff --git a/arch/s390/power/suspend.c b/arch/s390/power/suspend.c deleted file mode 100644 index b3351ec..0000000 --- a/arch/s390/power/suspend.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Suspend support specific for s390. - * - * Copyright IBM Corp. 2009 - * - * Author(s): Hans-Joachim Picht - */ - -#include -#include -#include -#include -#include -#include - -/* - * References to section boundaries - */ -extern const void __nosave_begin, __nosave_end; - -/* - * check if given pfn is in the 'nosave' or in the read only NSS section - */ -int pfn_is_nosave(unsigned long pfn) -{ - unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; - unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) - >> PAGE_SHIFT; - unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1; - unsigned long stext_pfn = PFN_DOWN(__pa(&_stext)); - - if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn) - return 1; - if (pfn >= stext_pfn && pfn <= eshared_pfn) { - if (ipl_info.type == IPL_TYPE_NSS) - return 1; - } else if ((tprot(pfn * PAGE_SIZE) && pfn > 0)) - return 1; - return 0; -} diff --git a/arch/s390/power/swsusp.c b/arch/s390/power/swsusp.c deleted file mode 100644 index bd1f5c6..0000000 --- a/arch/s390/power/swsusp.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Support for suspend and resume on s390 - * - * Copyright IBM Corp. 2009 - * - * Author(s): Hans-Joachim Picht - * - */ - -#include - -void save_processor_state(void) -{ - /* swsusp_arch_suspend() actually saves all cpu register contents. - * Machine checks must be disabled since swsusp_arch_suspend() stores - * register contents to their lowcore save areas. That's the same - * place where register contents on machine checks would be saved. - * To avoid register corruption disable machine checks. - * We must also disable machine checks in the new psw mask for - * program checks, since swsusp_arch_suspend() may generate program - * checks. Disabling machine checks for all other new psw masks is - * just paranoia. - */ - local_mcck_disable(); - /* Disable lowcore protection */ - __ctl_clear_bit(0,28); - S390_lowcore.external_new_psw.mask &= ~PSW_MASK_MCHECK; - S390_lowcore.svc_new_psw.mask &= ~PSW_MASK_MCHECK; - S390_lowcore.io_new_psw.mask &= ~PSW_MASK_MCHECK; - S390_lowcore.program_new_psw.mask &= ~PSW_MASK_MCHECK; -} - -void restore_processor_state(void) -{ - S390_lowcore.external_new_psw.mask |= PSW_MASK_MCHECK; - S390_lowcore.svc_new_psw.mask |= PSW_MASK_MCHECK; - S390_lowcore.io_new_psw.mask |= PSW_MASK_MCHECK; - S390_lowcore.program_new_psw.mask |= PSW_MASK_MCHECK; - /* Enable lowcore protection */ - __ctl_set_bit(0,28); - local_mcck_enable(); -} diff --git a/arch/s390/power/swsusp_asm64.S b/arch/s390/power/swsusp_asm64.S deleted file mode 100644 index b26df5c..0000000 --- a/arch/s390/power/swsusp_asm64.S +++ /dev/null @@ -1,184 +0,0 @@ -/* - * S390 64-bit swsusp implementation - * - * Copyright IBM Corp. 2009 - * - * Author(s): Hans-Joachim Picht - * Michael Holzheu - */ - -#include -#include -#include - -/* - * Save register context in absolute 0 lowcore and call swsusp_save() to - * create in-memory kernel image. The context is saved in the designated - * "store status" memory locations (see POP). - * We return from this function twice. The first time during the suspend to - * disk process. The second time via the swsusp_arch_resume() function - * (see below) in the resume process. - * This function runs with disabled interrupts. - */ - .section .text - .align 2 - .globl swsusp_arch_suspend -swsusp_arch_suspend: - stmg %r6,%r15,__SF_GPRS(%r15) - lgr %r1,%r15 - aghi %r15,-STACK_FRAME_OVERHEAD - stg %r1,__SF_BACKCHAIN(%r15) - - /* Deactivate DAT */ - stnsm __SF_EMPTY(%r15),0xfb - - /* Store prefix register on stack */ - stpx __SF_EMPTY(%r15) - - /* Save prefix register contents for lowcore */ - llgf %r4,__SF_EMPTY(%r15) - - /* Get pointer to save area */ - lghi %r1,0x1000 - - /* Store registers */ - mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ - stfpc 0x31c(%r1) /* store fpu control */ - std 0,0x200(%r1) /* store f0 */ - std 1,0x208(%r1) /* store f1 */ - std 2,0x210(%r1) /* store f2 */ - std 3,0x218(%r1) /* store f3 */ - std 4,0x220(%r1) /* store f4 */ - std 5,0x228(%r1) /* store f5 */ - std 6,0x230(%r1) /* store f6 */ - std 7,0x238(%r1) /* store f7 */ - std 8,0x240(%r1) /* store f8 */ - std 9,0x248(%r1) /* store f9 */ - std 10,0x250(%r1) /* store f10 */ - std 11,0x258(%r1) /* store f11 */ - std 12,0x260(%r1) /* store f12 */ - std 13,0x268(%r1) /* store f13 */ - std 14,0x270(%r1) /* store f14 */ - std 15,0x278(%r1) /* store f15 */ - stam %a0,%a15,0x340(%r1) /* store access registers */ - stctg %c0,%c15,0x380(%r1) /* store control registers */ - stmg %r0,%r15,0x280(%r1) /* store general registers */ - - stpt 0x328(%r1) /* store timer */ - stckc 0x330(%r1) /* store clock comparator */ - - /* Activate DAT */ - stosm __SF_EMPTY(%r15),0x04 - - /* Set prefix page to zero */ - xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) - spx __SF_EMPTY(%r15) - - lghi %r2,0 - lghi %r3,2*PAGE_SIZE - lghi %r5,2*PAGE_SIZE -1: mvcle %r2,%r4,0 - jo 1b - - /* Save image */ - brasl %r14,swsusp_save - - /* Restore prefix register and return */ - lghi %r1,0x1000 - spx 0x318(%r1) - lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) - lghi %r2,0 - br %r14 - -/* - * Restore saved memory image to correct place and restore register context. - * Then we return to the function that called swsusp_arch_suspend(). - * swsusp_arch_resume() runs with disabled interrupts. - */ - .globl swsusp_arch_resume -swsusp_arch_resume: - stmg %r6,%r15,__SF_GPRS(%r15) - lgr %r1,%r15 - aghi %r15,-STACK_FRAME_OVERHEAD - stg %r1,__SF_BACKCHAIN(%r15) - -#ifdef CONFIG_SMP - /* Save boot cpu number */ - brasl %r14,smp_get_phys_cpu_id - lgr %r10,%r2 -#endif - /* Deactivate DAT */ - stnsm __SF_EMPTY(%r15),0xfb - - /* Set prefix page to zero */ - xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) - spx __SF_EMPTY(%r15) - - /* Restore saved image */ - larl %r1,restore_pblist - lg %r1,0(%r1) - ltgr %r1,%r1 - jz 2f -0: - lg %r2,8(%r1) - lg %r4,0(%r1) - lghi %r3,PAGE_SIZE - lghi %r5,PAGE_SIZE -1: - mvcle %r2,%r4,0 - jo 1b - lg %r1,16(%r1) - ltgr %r1,%r1 - jnz 0b -2: - ptlb /* flush tlb */ - - /* Restore registers */ - lghi %r13,0x1000 /* %r1 = pointer to save arae */ - - spt 0x328(%r13) /* reprogram timer */ - //sckc 0x330(%r13) /* set clock comparator */ - - lctlg %c0,%c15,0x380(%r13) /* load control registers */ - lam %a0,%a15,0x340(%r13) /* load access registers */ - - lfpc 0x31c(%r13) /* load fpu control */ - ld 0,0x200(%r13) /* load f0 */ - ld 1,0x208(%r13) /* load f1 */ - ld 2,0x210(%r13) /* load f2 */ - ld 3,0x218(%r13) /* load f3 */ - ld 4,0x220(%r13) /* load f4 */ - ld 5,0x228(%r13) /* load f5 */ - ld 6,0x230(%r13) /* load f6 */ - ld 7,0x238(%r13) /* load f7 */ - ld 8,0x240(%r13) /* load f8 */ - ld 9,0x248(%r13) /* load f9 */ - ld 10,0x250(%r13) /* load f10 */ - ld 11,0x258(%r13) /* load f11 */ - ld 12,0x260(%r13) /* load f12 */ - ld 13,0x268(%r13) /* load f13 */ - ld 14,0x270(%r13) /* load f14 */ - ld 15,0x278(%r13) /* load f15 */ - - /* Load old stack */ - lg %r15,0x2f8(%r13) - - /* Pointer to save area */ - lghi %r13,0x1000 - -#ifdef CONFIG_SMP - /* Switch CPUs */ - lgr %r2,%r10 /* get cpu id */ - llgf %r3,0x318(%r13) - brasl %r14,smp_switch_boot_cpu_in_resume -#endif - /* Restore prefix register */ - spx 0x318(%r13) - - /* Activate DAT */ - stosm __SF_EMPTY(%r15),0x04 - - /* Return 0 */ - lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) - lghi %r2,0 - br %r14 -- cgit v0.10.2 From c6304933274f8e3cc6983d496456757ac8ab2e0b Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:38 +0200 Subject: [S390] proper use of device register Don't use kfree directly after device registration started. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 86105ef..0ecac7e 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -1006,7 +1006,7 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) priv->dev->release = (void (*)(struct device *)) kfree; rc = device_register(priv->dev); if (rc) { - kfree(priv->dev); + put_device(priv->dev); goto out_error_dev; } diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 3234e90..89ece1c 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -581,7 +581,7 @@ static int __init mon_init(void) monreader_device->release = (void (*)(struct device *))kfree; rc = device_register(monreader_device); if (rc) { - kfree(monreader_device); + put_device(monreader_device); goto out_driver; } diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index c20a4fe..d1a142fa 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -765,8 +765,10 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) } else return -ENOMEM; ret = device_register(dev); - if (ret) + if (ret) { + put_device(dev); return ret; + } ret = sysfs_create_group(&dev->kobj, &vmlogrdr_attr_group); if (ret) { diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 3e5f304..4000283 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -417,7 +417,8 @@ int chp_new(struct chp_id chpid) if (ret) { CIO_MSG_EVENT(0, "Could not register chp%x.%02x: %d\n", chpid.cssid, chpid.id, ret); - goto out_free; + put_device(&chp->dev); + goto out; } ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group); if (ret) { diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 0a3ce65..45858f3 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -152,18 +152,6 @@ css_alloc_subchannel(struct subchannel_id schid) } static void -css_free_subchannel(struct subchannel *sch) -{ - if (sch) { - /* Reset intparm to zeroes. */ - sch->config.intparm = 0; - cio_commit_config(sch); - kfree(sch->lock); - kfree(sch); - } -} - -static void css_subchannel_release(struct device *dev) { struct subchannel *sch; @@ -332,7 +320,7 @@ int css_probe_device(struct subchannel_id schid) return PTR_ERR(sch); ret = css_register_subchannel(sch); if (ret) - css_free_subchannel(sch); + put_device(&sch->dev); return ret; } @@ -649,7 +637,10 @@ __init_channel_subsystem(struct subchannel_id schid, void *data) * not working) so we do it now. This is true e.g. for the * console subchannel. */ - css_register_subchannel(sch); + if (css_register_subchannel(sch)) { + if (!cio_is_console(schid)) + put_device(&sch->dev); + } return 0; } @@ -925,8 +916,10 @@ init_channel_subsystem (void) goto out_device; } ret = device_register(&css->pseudo_subchannel->dev); - if (ret) + if (ret) { + put_device(&css->pseudo_subchannel->dev); goto out_file; + } } ret = register_reboot_notifier(&css_reboot_notifier); if (ret) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index ed3dcde..ae9ab24 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1114,7 +1114,7 @@ static void ap_scan_bus(struct work_struct *unused) ap_dev->device.release = ap_device_release; rc = device_register(&ap_dev->device); if (rc) { - kfree(ap_dev); + put_device(&ap_dev->device); continue; } /* Add device attributes. */ diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 8c36eaf..87dff11 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1839,9 +1839,10 @@ static int netiucv_register_device(struct net_device *ndev) return -ENOMEM; ret = device_register(dev); - - if (ret) + if (ret) { + put_device(dev); return ret; + } ret = netiucv_add_files(dev); if (ret) goto out_unreg; @@ -2226,8 +2227,10 @@ static int __init netiucv_init(void) netiucv_dev->release = (void (*)(struct device *))kfree; netiucv_dev->driver = &netiucv_driver; rc = device_register(netiucv_dev); - if (rc) + if (rc) { + put_device(netiucv_dev); goto out_driver; + } netiucv_banner(); return rc; diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index e76a320..102000d 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -219,13 +219,13 @@ static int __init smsg_init(void) smsg_dev->driver = &smsg_driver; rc = device_register(smsg_dev); if (rc) - goto out_free_dev; + goto out_put; cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; -out_free_dev: - kfree(smsg_dev); +out_put: + put_device(smsg_dev); out_free_path: iucv_path_free(smsg_path); smsg_path = NULL; -- cgit v0.10.2 From 6292b9ef5a4e85d6b782412a85725dd38df24b85 Mon Sep 17 00:00:00 2001 From: Frank Munzert Date: Fri, 11 Sep 2009 10:28:39 +0200 Subject: [S390] tape: use init_timer_on_stack() rather than init_timer() With CONFIG_DEBUG_OBJECTS_TIMERS=y "chccwdev --online" for a tape device will fail with message "ODEBUG: object is on stack, but not annotated". We now use init_timer_on_stack. Signed-off-by: Frank Munzert Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 1a9420b..750354a 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -68,7 +68,7 @@ tape_std_assign(struct tape_device *device) * to another host (actually this shouldn't happen but it does). * So we set up a timeout for this call. */ - init_timer(&timeout); + init_timer_on_stack(&timeout); timeout.function = tape_std_assign_timeout; timeout.data = (unsigned long) request; timeout.expires = jiffies + 2 * HZ; -- cgit v0.10.2 From 684d2fd48e718e70dad21ef7c528649578147e48 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Fri, 11 Sep 2009 10:28:40 +0200 Subject: [S390] kernel: Append scpdata to kernel boot command line Append scpdata to the kernel boot command line. If scpdata starts with the equal sign (=), the kernel boot command line is replaced. (For consistency with zIPL and IPL PARM parameters.) To use scpdata for the kernel boot command line, scpdata must consist of ascii characters only. If scpdata contains other characters, scpdata is not appended to the kernel boot command line. In addition, re-IPL is extended for setting scpdata for the next Linux reboot. Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h index 1171e6d..5e95d95 100644 --- a/arch/s390/include/asm/ipl.h +++ b/arch/s390/include/asm/ipl.h @@ -57,6 +57,8 @@ struct ipl_block_fcp { } __attribute__((packed)); #define DIAG308_VMPARM_SIZE 64 +#define DIAG308_SCPDATA_SIZE (PAGE_SIZE - (sizeof(struct ipl_list_hdr) + \ + offsetof(struct ipl_block_fcp, scp_data))) struct ipl_block_ccw { u8 load_parm[8]; @@ -91,7 +93,8 @@ extern void do_halt(void); extern void do_poff(void); extern void ipl_save_parameters(void); extern void ipl_update_parameters(void); -extern void get_ipl_vmparm(char *); +extern size_t append_ipl_vmparm(char *, size_t); +extern size_t append_ipl_scpdata(char *, size_t); enum { IPL_DEVNO_VALID = 1, diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 38b0fc2..e37478e 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -8,7 +8,7 @@ #ifndef _ASM_S390_SETUP_H #define _ASM_S390_SETUP_H -#define COMMAND_LINE_SIZE 1024 +#define COMMAND_LINE_SIZE 4096 #define ARCH_COMMAND_LINE_SIZE 896 diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index cae14c4..21f3799 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -81,6 +81,8 @@ asm( " br 14\n" " .size savesys_ipl_nss, .-savesys_ipl_nss\n"); +static __initdata char upper_command_line[COMMAND_LINE_SIZE]; + static noinline __init void create_kernel_nss(void) { unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; @@ -90,7 +92,6 @@ static noinline __init void create_kernel_nss(void) int response; size_t len; char *savesys_ptr; - char upper_command_line[COMMAND_LINE_SIZE]; char defsys_cmd[DEFSYS_CMD_SIZE]; char savesys_cmd[SAVESYS_CMD_SIZE]; @@ -367,21 +368,35 @@ static __init void rescue_initrd(void) } /* Set up boot command line */ -static void __init setup_boot_command_line(void) +static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t)) { - char *parm = NULL; + char *parm, *delim; + size_t rc, len; + + len = strlen(boot_command_line); + delim = boot_command_line + len; /* '\0' character position */ + parm = boot_command_line + len + 1; /* append right after '\0' */ + + rc = ipl_data(parm, COMMAND_LINE_SIZE - len - 1); + if (rc) { + if (*parm == '=') + memmove(boot_command_line, parm + 1, rc); + else + *delim = ' '; /* replace '\0' with space */ + } +} + +static void __init setup_boot_command_line(void) +{ /* copy arch command line */ strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); /* append IPL PARM data to the boot command line */ - if (MACHINE_IS_VM) { - parm = boot_command_line + strlen(boot_command_line); - *parm++ = ' '; - get_ipl_vmparm(parm); - if (parm[0] == '=') - memmove(boot_command_line, parm + 1, strlen(parm)); - } + if (MACHINE_IS_VM) + append_to_cmdline(append_ipl_vmparm); + + append_to_cmdline(append_ipl_scpdata); } diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 371a2d8..04451a5 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -272,17 +272,18 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr, static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); /* VM IPL PARM routines */ -static void reipl_get_ascii_vmparm(char *dest, +size_t reipl_get_ascii_vmparm(char *dest, size_t size, const struct ipl_parameter_block *ipb) { int i; - int len = 0; + size_t len; char has_lowercase = 0; + len = 0; if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) && (ipb->ipl_info.ccw.vm_parm_len > 0)) { - len = ipb->ipl_info.ccw.vm_parm_len; + len = min_t(size_t, size - 1, ipb->ipl_info.ccw.vm_parm_len); memcpy(dest, ipb->ipl_info.ccw.vm_parm, len); /* If at least one character is lowercase, we assume mixed * case; otherwise we convert everything to lowercase. @@ -299,14 +300,20 @@ static void reipl_get_ascii_vmparm(char *dest, EBCASC(dest, len); } dest[len] = 0; + + return len; } -void get_ipl_vmparm(char *dest) +size_t append_ipl_vmparm(char *dest, size_t size) { + size_t rc; + + rc = 0; if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW)) - reipl_get_ascii_vmparm(dest, &ipl_block); + rc = reipl_get_ascii_vmparm(dest, size, &ipl_block); else dest[0] = 0; + return rc; } static ssize_t ipl_vm_parm_show(struct kobject *kobj, @@ -314,10 +321,56 @@ static ssize_t ipl_vm_parm_show(struct kobject *kobj, { char parm[DIAG308_VMPARM_SIZE + 1] = {}; - get_ipl_vmparm(parm); + append_ipl_vmparm(parm, sizeof(parm)); return sprintf(page, "%s\n", parm); } +static size_t scpdata_length(const char* buf, size_t count) +{ + while (count) { + if (buf[count - 1] != '\0' && buf[count - 1] != ' ') + break; + count--; + } + return count; +} + +size_t reipl_append_ascii_scpdata(char *dest, size_t size, + const struct ipl_parameter_block *ipb) +{ + size_t count; + size_t i; + + count = min(size - 1, scpdata_length(ipb->ipl_info.fcp.scp_data, + ipb->ipl_info.fcp.scp_data_len)); + if (!count) + goto out; + + for (i = 0; i < count; i++) + if (!isascii(ipb->ipl_info.fcp.scp_data[i])) { + count = 0; + goto out; + } + + memcpy(dest, ipb->ipl_info.fcp.scp_data, count); +out: + dest[count] = '\0'; + return count; +} + +size_t append_ipl_scpdata(char *dest, size_t len) +{ + size_t rc; + + rc = 0; + if (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP) + rc = reipl_append_ascii_scpdata(dest, len, &ipl_block); + else + dest[0] = 0; + return rc; +} + + static struct kobj_attribute sys_ipl_vm_parm_attr = __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL); @@ -553,7 +606,7 @@ static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb, { char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; - reipl_get_ascii_vmparm(vmparm, ipb); + reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb); return sprintf(page, "%s\n", vmparm); } @@ -626,6 +679,59 @@ static struct kobj_attribute sys_reipl_ccw_vmparm_attr = /* FCP reipl device attributes */ +static ssize_t reipl_fcp_scpdata_read(struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + size_t size = reipl_block_fcp->ipl_info.fcp.scp_data_len; + void *scp_data = reipl_block_fcp->ipl_info.fcp.scp_data; + + return memory_read_from_buffer(buf, count, &off, scp_data, size); +} + +static ssize_t reipl_fcp_scpdata_write(struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + size_t padding; + size_t scpdata_len; + + if (off < 0) + return -EINVAL; + + if (off >= DIAG308_SCPDATA_SIZE) + return -ENOSPC; + + if (count > DIAG308_SCPDATA_SIZE - off) + count = DIAG308_SCPDATA_SIZE - off; + + memcpy(reipl_block_fcp->ipl_info.fcp.scp_data, buf + off, count); + scpdata_len = off + count; + + if (scpdata_len % 8) { + padding = 8 - (scpdata_len % 8); + memset(reipl_block_fcp->ipl_info.fcp.scp_data + scpdata_len, + 0, padding); + scpdata_len += padding; + } + + reipl_block_fcp->ipl_info.fcp.scp_data_len = scpdata_len; + reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN + scpdata_len; + reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN + scpdata_len; + + return count; +} + +static struct bin_attribute sys_reipl_fcp_scp_data_attr = { + .attr = { + .name = "scp_data", + .mode = S_IRUGO | S_IWUSR, + }, + .size = PAGE_SIZE, + .read = reipl_fcp_scpdata_read, + .write = reipl_fcp_scpdata_write, +}; + DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n", reipl_block_fcp->ipl_info.fcp.wwpn); DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n", @@ -647,7 +753,6 @@ static struct attribute *reipl_fcp_attrs[] = { }; static struct attribute_group reipl_fcp_attr_group = { - .name = IPL_FCP_STR, .attrs = reipl_fcp_attrs, }; @@ -895,6 +1000,7 @@ static struct kobj_attribute reipl_type_attr = __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store); static struct kset *reipl_kset; +static struct kset *reipl_fcp_kset; static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb, const enum ipl_method m) @@ -906,7 +1012,7 @@ static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb, reipl_get_ascii_loadparm(loadparm, ipb); reipl_get_ascii_nss_name(nss_name, ipb); - reipl_get_ascii_vmparm(vmparm, ipb); + reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb); switch (m) { case REIPL_METHOD_CCW_VM: @@ -1076,23 +1182,44 @@ static int __init reipl_fcp_init(void) int rc; if (!diag308_set_works) { - if (ipl_info.type == IPL_TYPE_FCP) + if (ipl_info.type == IPL_TYPE_FCP) { make_attrs_ro(reipl_fcp_attrs); - else + sys_reipl_fcp_scp_data_attr.attr.mode = S_IRUGO; + } else return 0; } reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); if (!reipl_block_fcp) return -ENOMEM; - rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group); + + /* sysfs: create fcp kset for mixing attr group and bin attrs */ + reipl_fcp_kset = kset_create_and_add(IPL_FCP_STR, NULL, + &reipl_kset->kobj); + if (!reipl_kset) { + free_page((unsigned long) reipl_block_fcp); + return -ENOMEM; + } + + rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group); if (rc) { - free_page((unsigned long)reipl_block_fcp); + kset_unregister(reipl_fcp_kset); + free_page((unsigned long) reipl_block_fcp); return rc; } - if (ipl_info.type == IPL_TYPE_FCP) { + + rc = sysfs_create_bin_file(&reipl_fcp_kset->kobj, + &sys_reipl_fcp_scp_data_attr); + if (rc) { + sysfs_remove_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group); + kset_unregister(reipl_fcp_kset); + free_page((unsigned long) reipl_block_fcp); + return rc; + } + + if (ipl_info.type == IPL_TYPE_FCP) memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE); - } else { + else { reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN; reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION; reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN; -- cgit v0.10.2 From 18d00acfe2f3fc5ee62f679eb2e397ae962fe69b Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Fri, 11 Sep 2009 10:28:41 +0200 Subject: [S390] kernel: Convert upper case scpdata to lower case If the CP SET LOADDEV on the 3215 console has been used to specify SCPdata, all data is converted to upper case letters. When scpdata contains upper case letters only, convert all letters to lower case. Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 04451a5..ee57a42 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -340,19 +340,28 @@ size_t reipl_append_ascii_scpdata(char *dest, size_t size, { size_t count; size_t i; + int has_lowercase; count = min(size - 1, scpdata_length(ipb->ipl_info.fcp.scp_data, ipb->ipl_info.fcp.scp_data_len)); if (!count) goto out; - for (i = 0; i < count; i++) + has_lowercase = 0; + for (i = 0; i < count; i++) { if (!isascii(ipb->ipl_info.fcp.scp_data[i])) { count = 0; goto out; } + if (!has_lowercase && islower(ipb->ipl_info.fcp.scp_data[i])) + has_lowercase = 1; + } - memcpy(dest, ipb->ipl_info.fcp.scp_data, count); + if (has_lowercase) + memcpy(dest, ipb->ipl_info.fcp.scp_data, count); + else + for (i = 0; i < count; i++) + dest[i] = tolower(ipb->ipl_info.fcp.scp_data[i]); out: dest[count] = '\0'; return count; -- cgit v0.10.2 From a8c3cb4955d1a051732ead9ecf8bcffc8e7c039d Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Fri, 11 Sep 2009 10:28:42 +0200 Subject: [S390] move (io|sysc)_restore_trace_psw into .data section The sysc_restore_trace_psw and io_restore_trace_psw storage locations are created in the .text section. When creating and IPLing from a named saved system (NSS), writing to these locations causes a protection exception (because the .text section is mapped as shared read-only in the NSS). To permit write access, move the storage locations into the .data section. The problem occurs only when CONFIG_TRACE_IRQFLAGS is set. The git commmit that has introduced these variables is: 411788ea7fca01ee803af8225ac35807b4d02050 Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index c4c80a2..f78580a 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -278,7 +278,8 @@ sysc_return: bnz BASED(sysc_work) # there is work to do (signals etc.) sysc_restore: #ifdef CONFIG_TRACE_IRQFLAGS - la %r1,BASED(sysc_restore_trace_psw) + la %r1,BASED(sysc_restore_trace_psw_addr) + l %r1,0(%r1) lpsw 0(%r1) sysc_restore_trace: TRACE_IRQS_CHECK @@ -289,10 +290,15 @@ sysc_leave: sysc_done: #ifdef CONFIG_TRACE_IRQFLAGS +sysc_restore_trace_psw_addr: + .long sysc_restore_trace_psw + + .section .data,"aw",@progbits .align 8 .globl sysc_restore_trace_psw sysc_restore_trace_psw: .long 0, sysc_restore_trace + 0x80000000 + .previous #endif # @@ -606,7 +612,8 @@ io_return: bnz BASED(io_work) # there is work to do (signals etc.) io_restore: #ifdef CONFIG_TRACE_IRQFLAGS - la %r1,BASED(io_restore_trace_psw) + la %r1,BASED(io_restore_trace_psw_addr) + l %r1,0(%r1) lpsw 0(%r1) io_restore_trace: TRACE_IRQS_CHECK @@ -617,10 +624,15 @@ io_leave: io_done: #ifdef CONFIG_TRACE_IRQFLAGS +io_restore_trace_psw_addr: + .long io_restore_trace_psw + + .section .data,"aw",@progbits .align 8 .globl io_restore_trace_psw io_restore_trace_psw: .long 0, io_restore_trace + 0x80000000 + .previous #endif # diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index f6618e9..009ca61 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -284,10 +284,12 @@ sysc_leave: sysc_done: #ifdef CONFIG_TRACE_IRQFLAGS + .section .data,"aw",@progbits .align 8 .globl sysc_restore_trace_psw sysc_restore_trace_psw: .quad 0, sysc_restore_trace + .previous #endif # @@ -595,10 +597,12 @@ io_leave: io_done: #ifdef CONFIG_TRACE_IRQFLAGS + .section .data,"aw",@progbits .align 8 .globl io_restore_trace_psw io_restore_trace_psw: .quad 0, io_restore_trace + .previous #endif # -- cgit v0.10.2 From 26803144666bd2155a19392fa58a7d512d9c0962 Mon Sep 17 00:00:00 2001 From: Tim Abbott Date: Fri, 11 Sep 2009 10:28:43 +0200 Subject: [S390] Use macros for .data.page_aligned. .data.page_aligned should not need a separate output section, so as part of this cleanup I moved into the .data output section in the linker scripts in order to eliminate unnecessary references to the section name. Remove the reference to .data.idt, since nothing is put into the .data.idt section on the s390 architecture. It looks like Cyrill Gorcunov posted a patch to remove the .data.idt code on s390 previously: CCing him and the people who acked that patch in case there's a reason it wasn't applied. Signed-off-by: Tim Abbott Cc: Martin Schwidefsky Acked-by: Cyrill Gorcunov Cc: Sam Ravnborg Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index a53db23..8e023c8 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -60,6 +60,7 @@ SECTIONS } :data .data : { /* Data */ + PAGE_ALIGNED_DATA(PAGE_SIZE) DATA_DATA CONSTRUCTORS } @@ -72,11 +73,6 @@ SECTIONS . = ALIGN(PAGE_SIZE); __nosave_end = .; - . = ALIGN(PAGE_SIZE); - .data.page_aligned : { - *(.data.idt) - } - . = ALIGN(0x100); .data.cacheline_aligned : { *(.data.cacheline_aligned) -- cgit v0.10.2 From 04a95f6df9d7753098729ef1464e38552627af9d Mon Sep 17 00:00:00 2001 From: Nelson Elhage Date: Fri, 11 Sep 2009 10:28:44 +0200 Subject: [S390] clean up linker script using new linker script macros. Note that this patch moves .data.init_task inside _edata. In addition, the alignment of .init.ramfs changes: It is now PAGE_ALIGNED and __initramfs_end is arbitrarily aligned; Previously it was only aligned to a 0x100-byte boundary, and always ended on an even byte. This change results in fewer output sections and in some data being reordered, but should have no functional effect. Signed-off-by: Nelson Elhage Signed-off-by: Tim Abbott Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux-s390@vger.kernel.org Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 8e023c8..7315f9e 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -52,51 +52,18 @@ SECTIONS . = ALIGN(PAGE_SIZE); _eshared = .; /* End of shareable data */ - . = ALIGN(16); /* Exception table */ - __ex_table : { - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - } :data - - .data : { /* Data */ - PAGE_ALIGNED_DATA(PAGE_SIZE) - DATA_DATA - CONSTRUCTORS - } - - . = ALIGN(PAGE_SIZE); - .data_nosave : { - __nosave_begin = .; - *(.data.nosave) - } - . = ALIGN(PAGE_SIZE); - __nosave_end = .; + EXCEPTION_TABLE(16) :data - . = ALIGN(0x100); - .data.cacheline_aligned : { - *(.data.cacheline_aligned) - } + RW_DATA_SECTION(0x100, PAGE_SIZE, THREAD_SIZE) - . = ALIGN(0x100); - .data.read_mostly : { - *(.data.read_mostly) - } _edata = .; /* End of data section */ - . = ALIGN(THREAD_SIZE); /* init_task */ - .data.init_task : { - *(.data.init_task) - } - /* will be freed after init */ . = ALIGN(PAGE_SIZE); /* Init code and data */ __init_begin = .; - .init.text : { - _sinittext = .; - INIT_TEXT - _einittext = .; - } + + INIT_TEXT_SECTION(PAGE_SIZE) + /* * .exit.text is discarded at runtime, not link time, * to deal with references from __bug_table @@ -107,49 +74,13 @@ SECTIONS /* early.c uses stsi, which requires page aligned data. */ . = ALIGN(PAGE_SIZE); - .init.data : { - INIT_DATA - } - . = ALIGN(0x100); - .init.setup : { - __setup_start = .; - *(.init.setup) - __setup_end = .; - } - .initcall.init : { - __initcall_start = .; - INITCALLS - __initcall_end = .; - } - - .con_initcall.init : { - __con_initcall_start = .; - *(.con_initcall.init) - __con_initcall_end = .; - } - SECURITY_INIT - -#ifdef CONFIG_BLK_DEV_INITRD - . = ALIGN(0x100); - .init.ramfs : { - __initramfs_start = .; - *(.init.ramfs) - . = ALIGN(2); - __initramfs_end = .; - } -#endif + INIT_DATA_SECTION(0x100) PERCPU(PAGE_SIZE) . = ALIGN(PAGE_SIZE); __init_end = .; /* freed after init ends here */ - /* BSS */ - .bss : { - __bss_start = .; - *(.bss) - . = ALIGN(2); - __bss_stop = .; - } + BSS_SECTION(0, 2, 0) _end = . ; -- cgit v0.10.2 From d3135e0c40c9a13ad0c57783f2b9569c4c00bd26 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:28:45 +0200 Subject: [S390] kernel: always keep machine flags in lowcore Eleminate the local variable machine_flags and always change machine flags directly in the lowcore. This avoids confusion about when and why the two variables have to be synchronized. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 21f3799..734deea 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -35,8 +35,6 @@ char kernel_nss_name[NSS_NAME_SIZE + 1]; -static unsigned long machine_flags; - static void __init setup_boot_command_line(void); /* @@ -206,12 +204,9 @@ static noinline __init void detect_machine_type(void) /* Running under KVM? If not we assume z/VM */ if (!memcmp(vmms.vm[0].cpi, "\xd2\xe5\xd4", 3)) - machine_flags |= MACHINE_FLAG_KVM; + S390_lowcore.machine_flags |= MACHINE_FLAG_KVM; else - machine_flags |= MACHINE_FLAG_VM; - - /* Store machine flags for setting up lowcore early */ - S390_lowcore.machine_flags = machine_flags; + S390_lowcore.machine_flags |= MACHINE_FLAG_VM; } static __init void early_pgm_check_handler(void) @@ -246,7 +241,7 @@ static noinline __init void setup_hpage(void) facilities = stfl(); if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29))) return; - machine_flags |= MACHINE_FLAG_HPAGE; + S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE; __ctl_set_bit(0, 23); #endif } @@ -264,7 +259,7 @@ static __init void detect_mvpg(void) EX_TABLE(0b,1b) : "=d" (rc) : "0" (-EOPNOTSUPP), "a" (0) : "memory", "cc", "0"); if (!rc) - machine_flags |= MACHINE_FLAG_MVPG; + S390_lowcore.machine_flags |= MACHINE_FLAG_MVPG; #endif } @@ -280,7 +275,7 @@ static __init void detect_ieee(void) EX_TABLE(0b,1b) : "=d" (rc), "=d" (tmp): "0" (-EOPNOTSUPP) : "cc"); if (!rc) - machine_flags |= MACHINE_FLAG_IEEE; + S390_lowcore.machine_flags |= MACHINE_FLAG_IEEE; #endif } @@ -299,7 +294,7 @@ static __init void detect_csp(void) EX_TABLE(0b,1b) : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc", "0", "1", "2"); if (!rc) - machine_flags |= MACHINE_FLAG_CSP; + S390_lowcore.machine_flags |= MACHINE_FLAG_CSP; #endif } @@ -316,7 +311,7 @@ static __init void detect_diag9c(void) EX_TABLE(0b,1b) : "=d" (rc) : "0" (-EOPNOTSUPP), "d" (cpu_address) : "cc"); if (!rc) - machine_flags |= MACHINE_FLAG_DIAG9C; + S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG9C; } static __init void detect_diag44(void) @@ -331,7 +326,7 @@ static __init void detect_diag44(void) EX_TABLE(0b,1b) : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc"); if (!rc) - machine_flags |= MACHINE_FLAG_DIAG44; + S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG44; #endif } @@ -342,11 +337,11 @@ static __init void detect_machine_facilities(void) facilities = stfl(); if (facilities & (1 << 28)) - machine_flags |= MACHINE_FLAG_IDTE; + S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; if (facilities & (1 << 23)) - machine_flags |= MACHINE_FLAG_PFMF; + S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF; if (facilities & (1 << 4)) - machine_flags |= MACHINE_FLAG_MVCOS; + S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; #endif } @@ -428,7 +423,6 @@ void __init startup_init(void) setup_hpage(); sclp_facilities_detect(); detect_memory_layout(memory_chunk); - S390_lowcore.machine_flags = machine_flags; #ifdef CONFIG_DYNAMIC_FTRACE S390_lowcore.ftrace_func = (unsigned long)ftrace_caller; #endif -- cgit v0.10.2 From 275c340941991a925969c03ec6b900fd135d09dd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 11 Sep 2009 10:28:46 +0200 Subject: [S390] remove unused irq_cpustat_t defintion No need to defined a irq_cpustat_t type if __ARCH_IRQ_STAT is defined. Signed-off-by: Christoph Hellwig Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/hardirq.h b/arch/s390/include/asm/hardirq.h index 89ec705..498bc38 100644 --- a/arch/s390/include/asm/hardirq.h +++ b/arch/s390/include/asm/hardirq.h @@ -18,13 +18,6 @@ #include #include -/* irq_cpustat_t is unused currently, but could be converted - * into a percpu variable instead of storing softirq_pending - * on the lowcore */ -typedef struct { - unsigned int __softirq_pending; -} irq_cpustat_t; - #define local_softirq_pending() (S390_lowcore.softirq_pending) #define __ARCH_IRQ_STAT -- cgit v0.10.2 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 diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 322a00bb..2dbff53 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 0769ced..4e34d36 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 7e73e39..efb500a 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 60e7cb0..6bb5a6b 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 0000000..daaec18 --- /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 v0.10.2 From 2395ecd98f028b16a6200eb81108a0f67461d16b Mon Sep 17 00:00:00 2001 From: Vitaliy Gusev Date: Fri, 11 Sep 2009 10:28:48 +0200 Subject: [S390] hypfs: remove useless variable qname Local variable 'qname' in the function hypfs_create_file() really is not used for any purpose. Signed-off-by: Vitaliy Gusev Cc: Michael Holzheu Signed-off-by: Andrew Morton Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 5a805df..e760b5b 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -355,11 +355,7 @@ static struct dentry *hypfs_create_file(struct super_block *sb, { struct dentry *dentry; struct inode *inode; - struct qstr qname; - qname.name = name; - qname.len = strlen(name); - qname.hash = full_name_hash(name, qname.len); mutex_lock(&parent->d_inode->i_mutex); dentry = lookup_one_len(name, parent, strlen(name)); if (IS_ERR(dentry)) { -- cgit v0.10.2 From 3f7cb51fac60618aa543058a90e668956d5fb518 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 11 Sep 2009 10:28:49 +0200 Subject: [S390] vmur: Invalid allocation sequence for vmur class The vmur class is allocated after the CCW driver is registered and it is destroyed before the CCW driver is unregistered. This is not the correct sequence, because the vmur class can be used via driver core callbacks that are triggered during the CCW driver deregistration. For Example: 1. vmur device is online 2. vmur module is unloaded This leads to the following function call stack: <4> [<0000000000387286>] device_destroy+0x36/0x5c <4> [<000003e000209714>] ur_set_offline_force+0x9c/0x10c [vmur] <4> [<000003e00020a928>] ur_remove+0x64/0xbc [vmur] <4> [<00000000003e4d2e>] ccw_device_remove+0x42/0x1ac <4> [<000000000038a1aa>] __device_release_driver+0x9a/0xe4 <4> [<000000000038a2da>] driver_detach+0xe6/0xec <4> [<0000000000388ee4>] bus_remove_driver+0xc0/0x108 <4> [<000003e00020ad5a>] ur_exit+0x52/0x84 [vmur] In device_destroy() the vmur class is used. Since it is already freed, this can lead to a kernel panic. To fix the problem, the vmur class has to be allocated before the CCW driver is registered and destroyed after the CCW driver has ben unregistered. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 31b902e..77571b6 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -1026,9 +1026,15 @@ static int __init ur_init(void) debug_set_level(vmur_dbf, 6); + vmur_class = class_create(THIS_MODULE, "vmur"); + if (IS_ERR(vmur_class)) { + rc = PTR_ERR(vmur_class); + goto fail_free_dbf; + } + rc = ccw_driver_register(&ur_driver); if (rc) - goto fail_free_dbf; + goto fail_class_destroy; rc = alloc_chrdev_region(&dev, 0, NUM_MINORS, "vmur"); if (rc) { @@ -1038,18 +1044,13 @@ static int __init ur_init(void) } ur_first_dev_maj_min = MKDEV(MAJOR(dev), 0); - vmur_class = class_create(THIS_MODULE, "vmur"); - if (IS_ERR(vmur_class)) { - rc = PTR_ERR(vmur_class); - goto fail_unregister_region; - } pr_info("%s loaded.\n", ur_banner); return 0; -fail_unregister_region: - unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS); fail_unregister_driver: ccw_driver_unregister(&ur_driver); +fail_class_destroy: + class_destroy(vmur_class); fail_free_dbf: debug_unregister(vmur_dbf); return rc; @@ -1057,9 +1058,9 @@ fail_free_dbf: static void __exit ur_exit(void) { - class_destroy(vmur_class); unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS); ccw_driver_unregister(&ur_driver); + class_destroy(vmur_class); debug_unregister(vmur_dbf); pr_info("%s unloaded.\n", ur_banner); } -- cgit v0.10.2 From 99b5e2d3d7ae8f5a2dba7a41a02ba7eb25523b3f Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 11 Sep 2009 10:28:50 +0200 Subject: [S390] xpram: Remove checksum validation for suspend/resume Currently in the suspend process checksums for the XPRAM partitions are created and stored. During the resume process it is checked, if the checksums are still the same. If this is not the case, a kernel panic is triggered. Unfortunately this prevents XPRAM from beeing used as suspend device, because in this case after the checksum has been created, the memory image is written to XPRAM and therefore the contents of the suspend partition is changed. In order to allow XPRAM to be used as suspend device, this patch removes the checksum validation. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index db442cd..ee604e9 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -42,7 +42,6 @@ #include #include #include -#include #define XPRAM_NAME "xpram" #define XPRAM_DEVS 1 /* one partition */ @@ -51,7 +50,6 @@ typedef struct { unsigned int size; /* size of xpram segment in pages */ unsigned int offset; /* start page of xpram segment */ - unsigned int csum; /* partition checksum for suspend */ } xpram_device_t; static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; @@ -387,58 +385,6 @@ out: } /* - * Save checksums for all partitions. - */ -static int xpram_save_checksums(void) -{ - unsigned long mem_page; - int rc, i; - - rc = 0; - mem_page = (unsigned long) __get_free_page(GFP_KERNEL); - if (!mem_page) - return -ENOMEM; - for (i = 0; i < xpram_devs; i++) { - rc = xpram_page_in(mem_page, xpram_devices[i].offset); - if (rc) - goto fail; - xpram_devices[i].csum = csum_partial((const void *) mem_page, - PAGE_SIZE, 0); - } -fail: - free_page(mem_page); - return rc ? -ENXIO : 0; -} - -/* - * Verify checksums for all partitions. - */ -static int xpram_validate_checksums(void) -{ - unsigned long mem_page; - unsigned int csum; - int rc, i; - - rc = 0; - mem_page = (unsigned long) __get_free_page(GFP_KERNEL); - if (!mem_page) - return -ENOMEM; - for (i = 0; i < xpram_devs; i++) { - rc = xpram_page_in(mem_page, xpram_devices[i].offset); - if (rc) - goto fail; - csum = csum_partial((const void *) mem_page, PAGE_SIZE, 0); - if (xpram_devices[i].csum != csum) { - rc = -EINVAL; - goto fail; - } - } -fail: - free_page(mem_page); - return rc ? -ENXIO : 0; -} - -/* * Resume failed: Print error message and call panic. */ static void xpram_resume_error(const char *message) @@ -458,21 +404,10 @@ static int xpram_restore(struct device *dev) xpram_resume_error("xpram disappeared"); if (xpram_pages != xpram_highest_page_index() + 1) xpram_resume_error("Size of xpram changed"); - if (xpram_validate_checksums()) - xpram_resume_error("Data of xpram changed"); return 0; } -/* - * Save necessary state in suspend. - */ -static int xpram_freeze(struct device *dev) -{ - return xpram_save_checksums(); -} - static struct dev_pm_ops xpram_pm_ops = { - .freeze = xpram_freeze, .restore = xpram_restore, }; -- cgit v0.10.2 From 95f1556c35529a162cef50296f3dc7f978852048 Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Fri, 11 Sep 2009 10:28:51 +0200 Subject: [S390] zcrypt: Use spin_lock_bh in suspend callback Fix lock dependency warning. inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. bash/1442 [HC0[0]:SC0[0]:HE1:SE1] takes: (&ap_dev->lock){+.?...}, at: [<000003e001280404>] __ap_poll_device+0x40/0x3e8 [ap] {IN-SOFTIRQ-W} state was registered at: [<000000000017f094>] __lock_acquire+0xb78/0x182c [<000000000017fe8e>] lock_acquire+0x146/0x178 [<0000000000549cf2>] _spin_lock+0x5a/0x98 [<000003e001280404>] __ap_poll_device+0x40/0x3e8 [ap] [<000003e001280afe>] ap_poll_all+0xaa/0x1a4 [ap] [<000000000014fa82>] tasklet_action+0xfe/0x1f4 [<0000000000150a56>] __do_softirq+0x116/0x284 [<0000000000111058>] do_softirq+0xe4/0xe8 [<00000000001504ba>] irq_exit+0xba/0xd8 [<00000000003dd04a>] do_IRQ+0x176/0x1fc [<000000000011823c>] io_return+0x0/0x8 [<0000004bfbfd2c0e>] 0x4bfbfd2c0e Signed-off-by: Felix Beck Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index ae9ab24..8578580 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -648,7 +648,9 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state) /* Poll on the device until all requests are finished. */ do { flags = 0; + spin_lock_bh(&ap_dev->lock); __ap_poll_device(ap_dev, &flags); + spin_unlock_bh(&ap_dev->lock); } while ((flags & 1) || (flags & 2)); ap_device_remove(dev); @@ -1407,14 +1409,12 @@ static void ap_reset(struct ap_device *ap_dev) static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags) { - spin_lock(&ap_dev->lock); if (!ap_dev->unregistered) { if (ap_poll_queue(ap_dev, flags)) ap_dev->unregistered = 1; if (ap_dev->reset == AP_RESET_DO) ap_reset(ap_dev); } - spin_unlock(&ap_dev->lock); return 0; } @@ -1441,7 +1441,9 @@ static void ap_poll_all(unsigned long dummy) flags = 0; spin_lock(&ap_device_list_lock); list_for_each_entry(ap_dev, &ap_device_list, list) { + spin_lock(&ap_dev->lock); __ap_poll_device(ap_dev, &flags); + spin_unlock(&ap_dev->lock); } spin_unlock(&ap_device_list_lock); } while (flags & 1); @@ -1487,7 +1489,9 @@ static int ap_poll_thread(void *data) flags = 0; spin_lock_bh(&ap_device_list_lock); list_for_each_entry(ap_dev, &ap_device_list, list) { + spin_lock(&ap_dev->lock); __ap_poll_device(ap_dev, &flags); + spin_unlock(&ap_dev->lock); } spin_unlock_bh(&ap_device_list_lock); } -- cgit v0.10.2 From edc44fa03ed7bc9847787e080190cf1d7ed68ceb Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Fri, 11 Sep 2009 10:28:52 +0200 Subject: [S390] zcrypt: Free ap_device if dev_set_name fails. If dev_set_name fails during scanning the AP bus, the reserved memory has to be freed. Signed-off-by: Felix Beck Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 8578580..090b32a 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1111,8 +1111,11 @@ static void ap_scan_bus(struct work_struct *unused) ap_dev->device.bus = &ap_bus_type; ap_dev->device.parent = ap_root_device; - dev_set_name(&ap_dev->device, "card%02x", - AP_QID_DEVICE(ap_dev->qid)); + if (dev_set_name(&ap_dev->device, "card%02x", + AP_QID_DEVICE(ap_dev->qid))) { + kfree(ap_dev); + continue; + } ap_dev->device.release = ap_device_release; rc = device_register(&ap_dev->device); if (rc) { -- cgit v0.10.2 From 11af97e18ea8c310d73b59f1361e6f04444e05a8 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Fri, 11 Sep 2009 10:28:53 +0200 Subject: [S390] kernel: Print an error message if kernel NSS cannot be defined If a named saved system (NSS) cannot be defined or saved, print out an error message with the return code of the underlying z/VM CP command. Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 734deea..bf8b4ae 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -6,6 +6,9 @@ * Heiko Carstens */ +#define KMSG_COMPONENT "setup" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include @@ -16,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -140,6 +144,8 @@ static noinline __init void create_kernel_nss(void) __cpcmd(defsys_cmd, NULL, 0, &response); if (response != 0) { + pr_err("Defining the Linux kernel NSS failed with rc=%d\n", + response); kernel_nss_name[0] = '\0'; return; } @@ -152,8 +158,11 @@ static noinline __init void create_kernel_nss(void) * max SAVESYS_CMD_SIZE * On error: response contains the numeric portion of cp error message. * for SAVESYS it will be >= 263 + * for missing privilege class, it will be 1 */ - if (response > SAVESYS_CMD_SIZE) { + if (response > SAVESYS_CMD_SIZE || response == 1) { + pr_err("Saving the Linux kernel NSS failed with rc=%d\n", + response); kernel_nss_name[0] = '\0'; return; } -- cgit v0.10.2 From ad2a5d8e0b518f997af126dd737127bdada90a6f Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 11 Sep 2009 10:28:54 +0200 Subject: [S390] hypfs: Use "%u" instead of "%d" for unsigned ints in snprintf For printing unsigned integers hypfs uses "%d" in snprintf(). This is wrong. With this patch "%u" is used instead. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index e760b5b..bd9914b 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -422,7 +422,7 @@ struct dentry *hypfs_create_u64(struct super_block *sb, struct dentry *dir, char tmp[TMP_SIZE]; struct dentry *dentry; - snprintf(tmp, TMP_SIZE, "%lld\n", (unsigned long long int)value); + snprintf(tmp, TMP_SIZE, "%llu\n", (unsigned long long int)value); buffer = kstrdup(tmp, GFP_KERNEL); if (!buffer) return ERR_PTR(-ENOMEM); -- cgit v0.10.2 From 68d36bdbf6377d36129b2c6bcbe9d24c5fb1739a Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 11 Sep 2009 10:28:55 +0200 Subject: [S390] tape: reversed order of labels Fix the order of goto labels in tape_generic_online. Signed-off-by: Roel Kluin diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 1d420d9..7424d64 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -358,11 +358,11 @@ tape_generic_online(struct tape_device *device, out_char: tapechar_cleanup_device(device); +out_minor: + tape_remove_minor(device); out_discipline: device->discipline->cleanup_device(device); device->discipline = NULL; -out_minor: - tape_remove_minor(device); out: module_put(discipline->owner); return rc; -- cgit v0.10.2 From c4de0c1a18237c2727dde8ad392e333539b0af3c Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Fri, 11 Sep 2009 10:28:56 +0200 Subject: [S390] kvm: use console_initcall() to initialize s390 virtio console Use a console_initcall() to initialize the s390 virtio console and clean up s390 console initialization in setup.c. Signed-off-by: Hendrik Brueckner Tested-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/kvm_virtio.h b/arch/s390/include/asm/kvm_virtio.h index 0503936..acdfdff 100644 --- a/arch/s390/include/asm/kvm_virtio.h +++ b/arch/s390/include/asm/kvm_virtio.h @@ -54,14 +54,4 @@ struct kvm_vqconfig { * This is pagesize for historical reasons. */ #define KVM_S390_VIRTIO_RING_ALIGN 4096 -#ifdef __KERNEL__ -/* early virtio console setup */ -#ifdef CONFIG_S390_GUEST -extern void s390_virtio_console_init(void); -#else -static inline void s390_virtio_console_init(void) -{ -} -#endif /* CONFIG_VIRTIO_CONSOLE */ -#endif /* __KERNEL__ */ #endif diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index cbb897b..9ed13a1 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -156,15 +156,11 @@ __setup("condev=", condev_setup); static void __init set_preferred_console(void) { - if (MACHINE_IS_KVM) { + if (MACHINE_IS_KVM) add_preferred_console("hvc", 0, NULL); - s390_virtio_console_init(); - return; - } - - if (CONSOLE_IS_3215 || CONSOLE_IS_SCLP) + else if (CONSOLE_IS_3215 || CONSOLE_IS_SCLP) add_preferred_console("ttyS", 0, NULL); - if (CONSOLE_IS_3270) + else if (CONSOLE_IS_3270) add_preferred_console("tty3270", 0, NULL); } diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index e38e5d3..2930fc7 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -403,10 +403,14 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) return len; } -void __init s390_virtio_console_init(void) +static int __init s390_virtio_console_init(void) { - virtio_cons_early_init(early_put_chars); + if (!MACHINE_IS_KVM) + return -ENODEV; + return virtio_cons_early_init(early_put_chars); } +console_initcall(s390_virtio_console_init); + /* * We do this after core stuff, but before the drivers. -- cgit v0.10.2 From 50aa98bad056a17655864a4d71ebc32d95c629a7 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 11 Sep 2009 10:28:57 +0200 Subject: [S390] fix recursive locking on page_table_lock Suzuki Poulose reported the following recursive locking bug on s390: Here is the stack trace : (see Appendix I for more info) [<0000000000406ed6>] _spin_lock+0x52/0x94 [<0000000000103bde>] crst_table_free+0x14e/0x1a4 [<00000000001ba684>] __pmd_alloc+0x114/0x1ec [<00000000001be8d0>] handle_mm_fault+0x2cc/0xb80 [<0000000000407d62>] do_dat_exception+0x2b6/0x3a0 [<0000000000114f8c>] sysc_return+0x0/0x8 [<00000200001642b2>] 0x200001642b2 The page_table_lock is already acquired in __pmd_alloc (mm/memory.c) and it tries to populate the pud/pgd with a new pmd allocated. If another thread populates it before we get a chance, we free the pmd using pmd_free(). On s390x, pmd_free(even pud_free ) is #defined to crst_table_free(), which acquires the page_table_lock to protect the crst_table index updates. Hence this ends up in a recursive locking of the page_table_lock. The solution suggested by Dave Hansen is to use a new spin lock in the mmu context to protect the access to the crst_list and the pgtable_list. Reported-by: Suzuki Poulose Cc: Dave Hansen Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h index 3b59216..03be999 100644 --- a/arch/s390/include/asm/mmu.h +++ b/arch/s390/include/asm/mmu.h @@ -2,6 +2,7 @@ #define __MMU_H typedef struct { + spinlock_t list_lock; struct list_head crst_list; struct list_head pgtable_list; unsigned long asce_bits; diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index b2658b9..ddad590 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h @@ -140,6 +140,7 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) static inline pgd_t *pgd_alloc(struct mm_struct *mm) { + spin_lock_init(&mm->context.list_lock); INIT_LIST_HEAD(&mm->context.crst_list); INIT_LIST_HEAD(&mm->context.pgtable_list); return (pgd_t *) crst_table_alloc(mm, s390_noexec); diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 5656672..c702152 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -78,9 +78,9 @@ unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec) } page->index = page_to_phys(shadow); } - spin_lock(&mm->page_table_lock); + spin_lock(&mm->context.list_lock); list_add(&page->lru, &mm->context.crst_list); - spin_unlock(&mm->page_table_lock); + spin_unlock(&mm->context.list_lock); return (unsigned long *) page_to_phys(page); } @@ -89,9 +89,9 @@ void crst_table_free(struct mm_struct *mm, unsigned long *table) unsigned long *shadow = get_shadow_table(table); struct page *page = virt_to_page(table); - spin_lock(&mm->page_table_lock); + spin_lock(&mm->context.list_lock); list_del(&page->lru); - spin_unlock(&mm->page_table_lock); + spin_unlock(&mm->context.list_lock); if (shadow) free_pages((unsigned long) shadow, ALLOC_ORDER); free_pages((unsigned long) table, ALLOC_ORDER); @@ -182,7 +182,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm) unsigned long bits; bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL; - spin_lock(&mm->page_table_lock); + spin_lock(&mm->context.list_lock); page = NULL; if (!list_empty(&mm->context.pgtable_list)) { page = list_first_entry(&mm->context.pgtable_list, @@ -191,7 +191,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm) page = NULL; } if (!page) { - spin_unlock(&mm->page_table_lock); + spin_unlock(&mm->context.list_lock); page = alloc_page(GFP_KERNEL|__GFP_REPEAT); if (!page) return NULL; @@ -202,7 +202,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm) clear_table_pgstes(table); else clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE); - spin_lock(&mm->page_table_lock); + spin_lock(&mm->context.list_lock); list_add(&page->lru, &mm->context.pgtable_list); } table = (unsigned long *) page_to_phys(page); @@ -213,7 +213,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm) page->flags |= bits; if ((page->flags & FRAG_MASK) == ((1UL << TABLES_PER_PAGE) - 1)) list_move_tail(&page->lru, &mm->context.pgtable_list); - spin_unlock(&mm->page_table_lock); + spin_unlock(&mm->context.list_lock); return table; } @@ -225,7 +225,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table) bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL; bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); page = pfn_to_page(__pa(table) >> PAGE_SHIFT); - spin_lock(&mm->page_table_lock); + spin_lock(&mm->context.list_lock); page->flags ^= bits; if (page->flags & FRAG_MASK) { /* Page now has some free pgtable fragments. */ @@ -234,7 +234,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table) } else /* All fragments of the 4K page have been freed. */ list_del(&page->lru); - spin_unlock(&mm->page_table_lock); + spin_unlock(&mm->context.list_lock); if (page) { pgtable_page_dtor(page); __free_page(page); @@ -245,7 +245,7 @@ void disable_noexec(struct mm_struct *mm, struct task_struct *tsk) { struct page *page; - spin_lock(&mm->page_table_lock); + spin_lock(&mm->context.list_lock); /* Free shadow region and segment tables. */ list_for_each_entry(page, &mm->context.crst_list, lru) if (page->index) { @@ -255,7 +255,7 @@ void disable_noexec(struct mm_struct *mm, struct task_struct *tsk) /* "Free" second halves of page tables. */ list_for_each_entry(page, &mm->context.pgtable_list, lru) page->flags &= ~SECOND_HALVES; - spin_unlock(&mm->page_table_lock); + spin_unlock(&mm->context.list_lock); mm->context.noexec = 0; update_mm(mm, tsk); } diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index e4868bf..5f91a38 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -331,6 +331,7 @@ void __init vmem_map_init(void) unsigned long start, end; int i; + spin_lock_init(&init_mm.context.list_lock); INIT_LIST_HEAD(&init_mm.context.crst_list); INIT_LIST_HEAD(&init_mm.context.pgtable_list); init_mm.context.noexec = 0; -- cgit v0.10.2 From 0c88ee5b7523e76e290d558c28cd0be48ffad597 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:28:58 +0200 Subject: [S390] Initialize __LC_THREAD_INFO early. "lockdep: Fix backtraces" reveales a bug in early setup code: when lockdep tries to save a stack backtrace before setup_arch has been called the lowcore pointer for the current thread info pointer isn't initialized yet. However our save stack backtrace code relies on it. If the pointer isn't initialized the saved backtrace will have zero entries. lockdep however relies (correctly) on the fact that that cannot happen. A write access to some random memory region is the result. Fix this by initializing the thread info pointer early. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index 2ced846..602b508 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -24,6 +24,7 @@ startup_continue: # Setup stack # l %r15,.Linittu-.LPG1(%r13) + st %r15,__LC_THREAD_INFO # cache thread info in lowcore mvc __LC_CURRENT(4),__TI_task(%r15) ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE st %r15,__LC_KERNEL_STACK # set end of kernel stack diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 65667b2..bdcb3f0 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -92,6 +92,7 @@ startup_continue: # Setup stack # larl %r15,init_thread_union + stg %r15,__LC_THREAD_INFO # cache thread info in lowcore lg %r14,__TI_task(%r15) # cache current in lowcore stg %r14,__LC_CURRENT aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE -- cgit v0.10.2 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 diff --git a/Documentation/s390/s390dbf.txt b/Documentation/s390/s390dbf.txt index 2d10053..ae66f9b 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 31ed568..18124b7 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 v0.10.2 From 5dd1d2ece0250125fec2dcccbfb8ab9bb2ac020c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:29:00 +0200 Subject: [S390] use generic scatterlist.h Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/scatterlist.h b/arch/s390/include/asm/scatterlist.h index 29ec8e2..35d786f 100644 --- a/arch/s390/include/asm/scatterlist.h +++ b/arch/s390/include/asm/scatterlist.h @@ -1,19 +1 @@ -#ifndef _ASMS390_SCATTERLIST_H -#define _ASMS390_SCATTERLIST_H - -struct scatterlist { -#ifdef CONFIG_DEBUG_SG - unsigned long sg_magic; -#endif - unsigned long page_link; - unsigned int offset; - unsigned int length; -}; - -#ifdef __s390x__ -#define ISA_DMA_THRESHOLD (0xffffffffffffffffUL) -#else -#define ISA_DMA_THRESHOLD (0xffffffffUL) -#endif - -#endif /* _ASMS390X_SCATTERLIST_H */ +#include -- cgit v0.10.2 From 2ddddf3e0a55a7fcd6f240a7416cfcb12dd38b7e Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:29:01 +0200 Subject: [S390] Enable guest page hinting by default. Get rid of the PAGE_STATES config option and enable guest page hinting by default. It can be disabled by specifying "cmma=off" at the command line. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 47836b9..e030e86 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -480,13 +480,6 @@ config CMM_IUCV Select this option to enable the special message interface to the cooperative memory management. -config PAGE_STATES - bool "Unused page notification" - help - This enables the notification of unused pages to the - hypervisor. The ESSA instruction is used to do the states - changes between a page that has content and the unused state. - config APPLDATA_BASE bool "Linux - VM Monitor Stream, base infrastructure" depends on PROC_FS diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 3e3594d..5e9daf5 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h @@ -125,8 +125,6 @@ page_get_storage_key(unsigned long addr) return skey; } -#ifdef CONFIG_PAGE_STATES - struct page; void arch_free_page(struct page *page, int order); void arch_alloc_page(struct page *page, int order); @@ -134,8 +132,6 @@ void arch_alloc_page(struct page *page, int order); #define HAVE_ARCH_FREE_PAGE #define HAVE_ARCH_ALLOC_PAGE -#endif - #endif /* !__ASSEMBLY__ */ #define __PAGE_OFFSET 0x0UL diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 4fb83c1..379661d 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h @@ -109,11 +109,7 @@ extern void pfault_fini(void); #define pfault_fini() do { } while (0) #endif /* CONFIG_PFAULT */ -#ifdef CONFIG_PAGE_STATES extern void cmma_init(void); -#else -static inline void cmma_init(void) { } -#endif #define finish_arch_switch(prev) do { \ set_fs(current->thread.mm_segment); \ diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile index db05661..eec0544 100644 --- a/arch/s390/mm/Makefile +++ b/arch/s390/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux s390-specific parts of the memory manager. # -obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o +obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \ + page-states.o obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_PAGE_STATES) += page-states.o diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c index fc0ad73..f92ec20 100644 --- a/arch/s390/mm/page-states.c +++ b/arch/s390/mm/page-states.c @@ -1,6 +1,4 @@ /* - * arch/s390/mm/page-states.c - * * Copyright IBM Corp. 2008 * * Guest page hinting for unused pages. @@ -17,11 +15,12 @@ #define ESSA_SET_STABLE 1 #define ESSA_SET_UNUSED 2 -static int cmma_flag; +static int cmma_flag = 1; static int __init cmma(char *str) { char *parm; + parm = strstrip(str); if (strcmp(parm, "yes") == 0 || strcmp(parm, "on") == 0) { cmma_flag = 1; @@ -32,7 +31,6 @@ static int __init cmma(char *str) return 1; return 0; } - __setup("cmma=", cmma); void __init cmma_init(void) -- cgit v0.10.2 From 53f8c573ea3b54b7e1b81d2cd403373b08103736 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 11 Sep 2009 10:29:02 +0200 Subject: [S390] tape: Fix device online messages Currently, when a tape device is set online and no cartridge is loaded, we get the messages "The tape cartridge has been successfully unloaded" and "Determining the size of the recorded area". These messages are not correct. To fix this, we now print the "cartridge loaded/unloaded" messages only, when the load/unload event really occurs. In addition to that, the message "Determining the size of the recorded area" is only printed, if a cartridge is loaded. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 47ff695..1c2a582 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -302,8 +302,6 @@ tapeblock_revalidate_disk(struct gendisk *disk) if (!device->blk_data.medium_changed) return 0; - dev_info(&device->cdev->dev, "Determining the size of the recorded " - "area...\n"); rc = tape_mtop(device, MTFSFM, 1); if (rc) return rc; @@ -312,6 +310,8 @@ tapeblock_revalidate_disk(struct gendisk *disk) if (rc < 0) return rc; + dev_info(&device->cdev->dev, "Determining the size of the recorded " + "area...\n"); DBF_LH(3, "Image file ends at %d\n", rc); nr_of_blks = rc; diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 7424d64..934a42e 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -214,13 +214,15 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate) switch(newstate){ case MS_UNLOADED: device->tape_generic_status |= GMT_DR_OPEN(~0); - dev_info(&device->cdev->dev, "The tape cartridge has been " - "successfully unloaded\n"); + if (device->medium_state == MS_LOADED) + dev_info(&device->cdev->dev, "The tape cartridge has " + "been successfully unloaded\n"); break; case MS_LOADED: device->tape_generic_status &= ~GMT_DR_OPEN(~0); - dev_info(&device->cdev->dev, "A tape cartridge has been " - "mounted\n"); + if (device->medium_state == MS_UNLOADED) + dev_info(&device->cdev->dev, "A tape cartridge has " + "been mounted\n"); break; default: // print nothing -- cgit v0.10.2 From 4bb5e07b68565d7983108993aa23eccf5f1b35fe Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:29:03 +0200 Subject: [S390] Limit cpu detection to 256 physical cpus. Saves us more than 65k pointless IPIs. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/cpu.h b/arch/s390/include/asm/cpu.h new file mode 100644 index 0000000..702ad46 --- /dev/null +++ b/arch/s390/include/asm/cpu.h @@ -0,0 +1,6 @@ +#ifndef _ASM_S390_CPU_H +#define _ASM_S390_CPU_H + +#define MAX_CPU_ADDRESS 255 + +#endif /* _ASM_S390_CPU_H */ diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index ec68823..c52b4f7 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef CONFIG_64BIT #define ARCH_OFFSET 4 diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index bdcb3f0..6a25080 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -62,9 +62,9 @@ startup_continue: clr %r11,%r12 je 5f # no more space in prefix array 4: - ahi %r8,1 # next cpu (r8 += 1) - cl %r8,.Llast_cpu-.LPG1(%r13) # is last possible cpu ? - jl 1b # jump if not last cpu + ahi %r8,1 # next cpu (r8 += 1) + chi %r8,MAX_CPU_ADDRESS # is last possible cpu ? + jle 1b # jump if not last cpu 5: lhi %r1,2 # mode 2 = esame (dump) j 6f @@ -130,8 +130,6 @@ startup_continue: #ifdef CONFIG_ZFCPDUMP .Lcurrent_cpu: .long 0x0 -.Llast_cpu: - .long 0x0000ffff .Lpref_arr_ptr: .long zfcpdump_prefix_array #endif /* CONFIG_ZFCPDUMP */ diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index be2cae0..9261495 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -49,6 +49,7 @@ #include #include #include +#include #include "entry.h" static struct task_struct *current_set[NR_CPUS]; @@ -300,7 +301,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail) logical_cpu = cpumask_first(&avail); if (logical_cpu >= nr_cpu_ids) return 0; - for (cpu_id = 0; cpu_id <= 65535; cpu_id++) { + for (cpu_id = 0; cpu_id <= MAX_CPU_ADDRESS; cpu_id++) { if (cpu_known(cpu_id)) continue; __cpu_logical_map[logical_cpu] = cpu_id; @@ -379,7 +380,7 @@ static void __init smp_detect_cpus(void) /* Use sigp detection algorithm if sclp doesn't work. */ if (sclp_get_cpu_info(info)) { smp_use_sigp_detection = 1; - for (cpu = 0; cpu <= 65535; cpu++) { + for (cpu = 0; cpu <= MAX_CPU_ADDRESS; cpu++) { if (cpu == boot_cpu_addr) continue; __cpu_logical_map[CPU_INIT_NO] = cpu; -- cgit v0.10.2 From e86a6ed63f46fe8fb555fda531084bca3ef62fd7 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:29:04 +0200 Subject: [S390] Get rid of cpuid.h header file. Merge cpuid.h header file into cpu.h. While at it convert from typedef to struct declaration and also convert cio code to use proper lowcore structure instead of casts. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/cpu.h b/arch/s390/include/asm/cpu.h index 702ad46..471234b 100644 --- a/arch/s390/include/asm/cpu.h +++ b/arch/s390/include/asm/cpu.h @@ -1,6 +1,26 @@ +/* + * Copyright IBM Corp. 2000,2009 + * Author(s): Hartmut Penner , + * Martin Schwidefsky , + * Christian Ehrhardt , + */ + #ifndef _ASM_S390_CPU_H #define _ASM_S390_CPU_H #define MAX_CPU_ADDRESS 255 +#ifndef __ASSEMBLY__ + +#include + +struct cpuid +{ + unsigned int version : 8; + unsigned int ident : 24; + unsigned int machine : 16; + unsigned int unused : 16; +} __packed; + +#endif /* __ASSEMBLY__ */ #endif /* _ASM_S390_CPU_H */ diff --git a/arch/s390/include/asm/cpuid.h b/arch/s390/include/asm/cpuid.h deleted file mode 100644 index 07836a2..0000000 --- a/arch/s390/include/asm/cpuid.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright IBM Corp. 2000,2009 - * Author(s): Hartmut Penner , - * Martin Schwidefsky - * Christian Ehrhardt - */ - -#ifndef _ASM_S390_CPUID_H_ -#define _ASM_S390_CPUID_H_ - -/* - * CPU type and hardware bug flags. Kept separately for each CPU. - * Members of this structure are referenced in head.S, so think twice - * before touching them. [mj] - */ - -typedef struct -{ - unsigned int version : 8; - unsigned int ident : 24; - unsigned int machine : 16; - unsigned int unused : 16; -} __attribute__ ((packed)) cpuid_t; - -#endif /* _ASM_S390_CPUID_H_ */ diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 1cd02f6..698988f 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #define KVM_MAX_VCPUS 64 #define KVM_MEMORY_SLOTS 32 @@ -217,8 +217,8 @@ struct kvm_vcpu_arch { struct hrtimer ckc_timer; struct tasklet_struct tasklet; union { - cpuid_t cpu_id; - u64 stidp_data; + struct cpuid cpu_id; + u64 stidp_data; }; }; diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 5046ad6..6bc9426 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -132,7 +132,7 @@ #ifndef __ASSEMBLY__ -#include +#include #include #include @@ -275,7 +275,7 @@ struct _lowcore __u32 user_exec_asce; /* 0x02ac */ /* SMP info area */ - cpuid_t cpu_id; /* 0x02b0 */ + struct cpuid cpu_id; /* 0x02b0 */ __u32 cpu_nr; /* 0x02b8 */ __u32 softirq_pending; /* 0x02bc */ __u32 percpu_offset; /* 0x02c0 */ @@ -380,7 +380,7 @@ struct _lowcore __u64 user_exec_asce; /* 0x0318 */ /* SMP info area */ - cpuid_t cpu_id; /* 0x0320 */ + struct cpuid cpu_id; /* 0x0320 */ __u32 cpu_nr; /* 0x0328 */ __u32 softirq_pending; /* 0x032c */ __u64 percpu_offset; /* 0x0330 */ diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index c139fa7..cf8eed3 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -14,7 +14,7 @@ #define __ASM_S390_PROCESSOR_H #include -#include +#include #include #include #include @@ -26,7 +26,7 @@ */ #define current_text_addr() ({ void *pc; asm("basr %0,0" : "=a" (pc)); pc; }) -static inline void get_cpu_id(cpuid_t *ptr) +static inline void get_cpu_id(struct cpuid *ptr) { asm volatile("stidp 0(%1)" : "=m" (*ptr) : "a" (ptr)); } diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 1bbae43..c431198 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -275,7 +275,7 @@ struct zcore_header { u32 num_pages; u32 pad1; u64 tod; - cpuid_t cpu_id; + struct cpuid cpu_id; u32 arch_id; u32 volnr; u32 build_arch; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 45858f3..e995123 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -657,8 +657,8 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) css->global_pgid.pgid_high.cpu_addr = 0; #endif } - css->global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident; - css->global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine; + css->global_pgid.cpu_id = S390_lowcore.cpu_id.ident; + css->global_pgid.cpu_model = S390_lowcore.cpu_id.machine; css->global_pgid.tod_high = tod_high; } -- cgit v0.10.2 From 5c0b912e755caaad555eb6feefdb1124462d8f37 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:29:05 +0200 Subject: [S390] Remove smp_cpu_not_running. smp_cpu_not_running() and cpu_stopped() are doing the same. Remove one and also get rid of the last hard_smp_processor_id() leftover. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index 72137bc..c991fe6 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h @@ -51,32 +51,7 @@ extern void machine_power_off_smp(void); #define PROC_CHANGE_PENALTY 20 /* Schedule penalty */ #define raw_smp_processor_id() (S390_lowcore.cpu_nr) - -/* - * returns 1 if cpu is in stopped/check stopped state or not operational - * returns 0 otherwise - */ -static inline int -smp_cpu_not_running(int cpu) -{ - __u32 status; - - switch (signal_processor_ps(&status, 0, cpu, sigp_sense)) { - case sigp_order_code_accepted: - case sigp_status_stored: - /* Check for stopped and check stop state */ - if (status & 0x50) - return 1; - break; - case sigp_not_operational: - return 1; - default: - break; - } - return 0; -} - -#define cpu_logical_map(cpu) (cpu) +#define cpu_logical_map(cpu) (cpu) extern int __cpu_disable (void); extern void __cpu_die (unsigned int cpu); @@ -91,11 +66,6 @@ extern void arch_send_call_function_ipi(cpumask_t mask); #endif -#ifndef CONFIG_SMP -#define hard_smp_processor_id() 0 -#define smp_cpu_not_running(cpu) 1 -#endif - #ifdef CONFIG_HOTPLUG_CPU extern int smp_rescan_cpus(void); #else diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 9261495..56c1687 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -71,6 +71,23 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices); static void smp_ext_bitcall(int, ec_bit_sig); +static int cpu_stopped(int cpu) +{ + __u32 status; + + switch (signal_processor_ps(&status, 0, cpu, sigp_sense)) { + case sigp_order_code_accepted: + case sigp_status_stored: + /* Check for stopped and check stop state */ + if (status & 0x50) + return 1; + break; + default: + break; + } + return 0; +} + void smp_send_stop(void) { int cpu, rc; @@ -87,7 +104,7 @@ void smp_send_stop(void) rc = signal_processor(cpu, sigp_stop); } while (rc == sigp_busy); - while (!smp_cpu_not_running(cpu)) + while (!cpu_stopped(cpu)) cpu_relax(); } } @@ -270,19 +287,6 @@ static inline void smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { } #endif /* CONFIG_ZFCPDUMP */ -static int cpu_stopped(int cpu) -{ - __u32 status; - - /* Check for stopped state */ - if (signal_processor_ps(&status, 0, cpu, sigp_sense) == - sigp_status_stored) { - if (status & 0x40) - return 1; - } - return 0; -} - static int cpu_known(int cpu_id) { int cpu; @@ -636,7 +640,7 @@ int __cpu_disable(void) void __cpu_die(unsigned int cpu) { /* Wait until target cpu is down */ - while (!smp_cpu_not_running(cpu)) + while (!cpu_stopped(cpu)) cpu_relax(); smp_free_lowcore(cpu); pr_info("Processor %d stopped\n", cpu); -- cgit v0.10.2 From bde69af2ab696eebfac9583ea1e8a46b571e317f Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:29:06 +0200 Subject: [S390] Wire up page fault events for software perf counters. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index e5e119f..1abbadd 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -10,6 +10,7 @@ * Copyright (C) 1995 Linus Torvalds */ +#include #include #include #include @@ -305,7 +306,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write) * interrupts again and then search the VMAs */ local_irq_enable(); - + perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); down_read(&mm->mmap_sem); si_code = SEGV_MAPERR; @@ -363,11 +364,15 @@ good_area: } BUG(); } - if (fault & VM_FAULT_MAJOR) + if (fault & VM_FAULT_MAJOR) { tsk->maj_flt++; - else + perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, + regs, address); + } else { tsk->min_flt++; - + perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, + regs, address); + } up_read(&mm->mmap_sem); /* * The instruction that caused the program check will -- cgit v0.10.2 From 59e36927ee08f3bf06d8d14597e57389bf1b41dc Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 11 Sep 2009 10:29:07 +0200 Subject: [S390] tape: Use pr_xxx instead of dev_xxx in shared driver code For messages from the tape core that is shared between the 3590 and 34xx tape disciplines, we want to have the "tape" prefix instead of "tape_3590" or "tape_34xx". In order to fix this, we now use the pr_xxx printk macros. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 5a519fa..2fe45ff 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -8,7 +8,7 @@ * Martin Schwidefsky */ -#define KMSG_COMPONENT "tape" +#define KMSG_COMPONENT "tape_34xx" #include #include diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 418f72d..e4cc3aa 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -8,7 +8,7 @@ * Martin Schwidefsky */ -#define KMSG_COMPONENT "tape" +#define KMSG_COMPONENT "tape_3590" #include #include @@ -39,8 +39,6 @@ EXPORT_SYMBOL(TAPE_DBF_AREA); * - Read Alternate: implemented *******************************************************************/ -#define KMSG_COMPONENT "tape" - static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = { [0x00] = "", [0x10] = "Lost Sense", diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 1c2a582..4cb9e70 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -310,8 +310,8 @@ tapeblock_revalidate_disk(struct gendisk *disk) if (rc < 0) return rc; - dev_info(&device->cdev->dev, "Determining the size of the recorded " - "area...\n"); + pr_info("%s: Determining the size of the recorded area...\n", + dev_name(&device->cdev->dev)); DBF_LH(3, "Image file ends at %d\n", rc); nr_of_blks = rc; @@ -330,8 +330,8 @@ tapeblock_revalidate_disk(struct gendisk *disk) device->bof = rc; nr_of_blks -= rc; - dev_info(&device->cdev->dev, "The size of the recorded area is %i " - "blocks\n", nr_of_blks); + pr_info("%s: The size of the recorded area is %i blocks\n", + dev_name(&device->cdev->dev), nr_of_blks); set_capacity(device->blk_data.disk, nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512)); @@ -366,8 +366,8 @@ tapeblock_open(struct block_device *bdev, fmode_t mode) if (device->required_tapemarks) { DBF_EVENT(2, "TBLOCK: missing tapemarks\n"); - dev_warn(&device->cdev->dev, "Opening the tape failed because" - " of missing end-of-file marks\n"); + pr_warning("%s: Opening the tape failed because of missing " + "end-of-file marks\n", dev_name(&device->cdev->dev)); rc = -EPERM; goto put_device; } diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 934a42e..5cd31e0 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -215,14 +215,14 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate) case MS_UNLOADED: device->tape_generic_status |= GMT_DR_OPEN(~0); if (device->medium_state == MS_LOADED) - dev_info(&device->cdev->dev, "The tape cartridge has " - "been successfully unloaded\n"); + pr_info("%s: The tape cartridge has been successfully " + "unloaded\n", dev_name(&device->cdev->dev)); break; case MS_LOADED: device->tape_generic_status &= ~GMT_DR_OPEN(~0); if (device->medium_state == MS_UNLOADED) - dev_info(&device->cdev->dev, "A tape cartridge has " - "been mounted\n"); + pr_info("%s: A tape cartridge has been mounted\n", + dev_name(&device->cdev->dev)); break; default: // print nothing @@ -656,8 +656,8 @@ tape_generic_remove(struct ccw_device *cdev) */ DBF_EVENT(3, "(%08x): Drive in use vanished!\n", device->cdev_id); - dev_warn(&device->cdev->dev, "A tape unit was detached" - " while in use\n"); + pr_warning("%s: A tape unit was detached while in " + "use\n", dev_name(&device->cdev->dev)); tape_state_set(device, TS_NOT_OPER); __tape_discard_requests(device); spin_unlock_irq(get_ccwdev_lock(device->cdev)); -- cgit v0.10.2 From addd72c1a917091f4bb5e699e307c4c4553f6fd3 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Fri, 11 Sep 2009 10:42:09 +0100 Subject: kmemleak: Improve the "Early log buffer exceeded" error message Based on a suggestion from Jaswinder, clarify what the user would need to do to avoid this error message from kmemleak. Reported-by: Jaswinder Singh Rajput Signed-off-by: Catalin Marinas diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 39da954..4ea4510 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -792,7 +792,8 @@ static void __init log_early(int op_type, const void *ptr, size_t size, struct early_log *log; if (crt_early_log >= ARRAY_SIZE(early_log)) { - pr_warning("Early log buffer exceeded\n"); + pr_warning("Early log buffer exceeded, " + "please increase DEBUG_KMEMLEAK_EARLY_LOG_SIZE\n"); kmemleak_disable(); return; } -- cgit v0.10.2 From 8ba69ba6a324b13e1190fc31e41954d190fd4f1d Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 11 Sep 2009 11:31:45 -0700 Subject: net: unix: fix sending fds in multiple buffers Kalle Olavi Niemitalo reported that: "..., when one process calls sendmsg once to send 43804 bytes of data and one file descriptor, and another process then calls recvmsg three times to receive the 16032+16032+11740 bytes, each of those recvmsg calls returns the file descriptor in the ancillary data. I confirmed this with strace. The behaviour differs from Linux 2.6.26, where reportedly only one of those recvmsg calls (I think the first one) returned the file descriptor." This bug was introduced by a patch from me titled "net: unix: fix inflight counting bug in garbage collector", commit 6209344f5. And the reason is, quoting Kalle: "Before your patch, unix_attach_fds() would set scm->fp = NULL, so that if the loop in unix_stream_sendmsg() ran multiple iterations, it could not call unix_attach_fds() again. But now, unix_attach_fds() leaves scm->fp unchanged, and I think this causes it to be called multiple times and duplicate the same file descriptors to each struct sk_buff." Fix this by introducing a flag that is cleared at the start and set when the fds attached to the first buffer. The resulting code should work equivalently to the one on 2.6.26. Reported-by: Kalle Olavi Niemitalo Signed-off-by: Miklos Szeredi Signed-off-by: David S. Miller diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index fc3ebb9..51ab497 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1501,6 +1501,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, struct sk_buff *skb; int sent = 0; struct scm_cookie tmp_scm; + bool fds_sent = false; if (NULL == siocb->scm) siocb->scm = &tmp_scm; @@ -1562,12 +1563,14 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, size = min_t(int, size, skb_tailroom(skb)); memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); - if (siocb->scm->fp) { + /* Only send the fds in the first buffer */ + if (siocb->scm->fp && !fds_sent) { err = unix_attach_fds(siocb->scm, skb); if (err) { kfree_skb(skb); goto out_err; } + fds_sent = true; } err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); -- cgit v0.10.2 From ffcfb8db540ff879c2a85bf7e404954281443414 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Sep 2009 11:35:22 -0700 Subject: Subject: [PATCH] appletalk: Fix skb leak when ipddp interface is not loaded And also do a better job of returning proper NET_{RX,XMIT}_ values. Based on a patch and suggestions by Mark Smith. This fixes CVE-2009-2903 Reported-by: Mark Smith Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index bea87da..aaf14d3 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -177,8 +177,7 @@ static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; - if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) - dev_kfree_skb(skb); + aarp_send_ddp(rt->dev, skb, &rt->at, NULL); spin_unlock(&ipddp_route_lock); diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 89f99d3..9d4adfd 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -599,7 +599,7 @@ int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb, /* Non ELAP we cannot do. */ if (dev->type != ARPHRD_ETHER) - return -1; + goto free_it; skb->dev = dev; skb->protocol = htons(ETH_P_ATALK); @@ -634,7 +634,7 @@ int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb, if (!a) { /* Whoops slipped... good job it's an unreliable protocol 8) */ write_unlock_bh(&aarp_lock); - return -1; + goto free_it; } /* Set up the queue */ @@ -663,15 +663,21 @@ out_unlock: write_unlock_bh(&aarp_lock); /* Tell the ddp layer we have taken over for this frame. */ - return 0; + goto sent; sendit: if (skb->sk) skb->priority = skb->sk->sk_priority; - dev_queue_xmit(skb); + if (dev_queue_xmit(skb)) + goto drop; sent: - return 1; + return NET_XMIT_SUCCESS; +free_it: + kfree_skb(skb); +drop: + return NET_XMIT_DROP; } +EXPORT_SYMBOL(aarp_send_ddp); /* * An entry in the aarp unresolved queue has become resolved. Send diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 0d42d5d..4a6ff2b 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1270,8 +1270,10 @@ static int handle_ip_over_ddp(struct sk_buff *skb) struct net_device_stats *stats; /* This needs to be able to handle ipddp"N" devices */ - if (!dev) - return -ENODEV; + if (!dev) { + kfree_skb(skb); + return NET_RX_DROP; + } skb->protocol = htons(ETH_P_IP); skb_pull(skb, 13); @@ -1281,8 +1283,7 @@ static int handle_ip_over_ddp(struct sk_buff *skb) stats = netdev_priv(dev); stats->rx_packets++; stats->rx_bytes += skb->len + 13; - netif_rx(skb); /* Send the SKB up to a higher place. */ - return 0; + return netif_rx(skb); /* Send the SKB up to a higher place. */ } #else /* make it easy for gcc to optimize this test out, i.e. kill the code */ @@ -1290,9 +1291,8 @@ static int handle_ip_over_ddp(struct sk_buff *skb) #define handle_ip_over_ddp(skb) 0 #endif -static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev, - struct ddpehdr *ddp, __u16 len_hops, - int origlen) +static int atalk_route_packet(struct sk_buff *skb, struct net_device *dev, + struct ddpehdr *ddp, __u16 len_hops, int origlen) { struct atalk_route *rt; struct atalk_addr ta; @@ -1359,8 +1359,6 @@ static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev, /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */ struct sk_buff *nskb = skb_realloc_headroom(skb, 32); kfree_skb(skb); - if (!nskb) - goto out; skb = nskb; } else skb = skb_unshare(skb, GFP_ATOMIC); @@ -1369,12 +1367,16 @@ static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev, * If the buffer didn't vanish into the lack of space bitbucket we can * send it. */ - if (skb && aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1) - goto free_it; -out: - return; + if (skb == NULL) + goto drop; + + if (aarp_send_ddp(rt->dev, skb, &ta, NULL) == NET_XMIT_DROP) + return NET_RX_DROP; + return NET_XMIT_SUCCESS; free_it: kfree_skb(skb); +drop: + return NET_RX_DROP; } /** @@ -1448,8 +1450,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, /* Not ours, so we route the packet via the correct * AppleTalk iface */ - atalk_route_packet(skb, dev, ddp, len_hops, origlen); - return NET_RX_SUCCESS; + return atalk_route_packet(skb, dev, ddp, len_hops, origlen); } /* if IP over DDP is not selected this code will be optimized out */ @@ -1655,10 +1656,10 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr if (skb2) { loopback = 1; SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk); - if (aarp_send_ddp(dev, skb2, - &usat->sat_addr, NULL) == -1) - kfree_skb(skb2); - /* else queued/sent above in the aarp queue */ + /* + * If it fails it is queued/sent above in the aarp queue + */ + aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL); } } @@ -1688,9 +1689,10 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr usat = &gsat; } - if (aarp_send_ddp(dev, skb, &usat->sat_addr, NULL) == -1) - kfree_skb(skb); - /* else queued/sent above in the aarp queue */ + /* + * If it fails it is queued/sent above in the aarp queue + */ + aarp_send_ddp(dev, skb, &usat->sat_addr, NULL); } SOCK_DEBUG(sk, "SK %p: Done write (%Zd).\n", sk, len); @@ -1868,7 +1870,6 @@ static struct packet_type ppptalk_packet_type __read_mostly = { static unsigned char ddp_snap_id[] = { 0x08, 0x00, 0x07, 0x80, 0x9B }; /* Export symbols for use by drivers when AppleTalk is a module */ -EXPORT_SYMBOL(aarp_send_ddp); EXPORT_SYMBOL(atrtr_get_dev); EXPORT_SYMBOL(atalk_find_dev_addr); -- cgit v0.10.2 From 4fb019a01a7f67342d4a88d26c0817afe392c669 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 11 Sep 2009 11:50:08 -0700 Subject: net: force bridge module(s) to be GPL The only valid usage for the bridge frame hooks are by a GPL components (such as the bridge module). The kernel should not leave a crack in the door for proprietary networking stacks to slip in. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 1a6561b..f843a0c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2116,7 +2116,7 @@ static inline int deliver_skb(struct sk_buff *skb, /* This hook is defined here for ATM LANE */ int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr) __read_mostly; -EXPORT_SYMBOL(br_fdb_test_addr_hook); +EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook); #endif /* @@ -2125,7 +2125,7 @@ EXPORT_SYMBOL(br_fdb_test_addr_hook); */ struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff *skb) __read_mostly; -EXPORT_SYMBOL(br_handle_frame_hook); +EXPORT_SYMBOL_GPL(br_handle_frame_hook); static inline struct sk_buff *handle_bridge(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, -- cgit v0.10.2 From 966a5d1b85c45f1b55abbc1b595e0b5ca14b87db Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 11 Sep 2009 06:21:51 +0000 Subject: drivers/net/wan: introduce missing kfree Error handling code following a kmalloc should free the allocated data. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 72a7cda..b9b9d6b 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -389,6 +389,7 @@ static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id, for (opt = data; len; len -= opt[1], opt += opt[1]) { if (len < 2 || len < opt[1]) { dev->stats.rx_errors++; + kfree(out); return; /* bad packet, drop silently */ } -- cgit v0.10.2 From a4b11649618ef5366ee553f4083449d6bee5d8ec Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 11 Sep 2009 06:22:09 +0000 Subject: drivers/net/phy: introduce missing kfree Error handling code following a kzalloc should free the allocated data. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 22cdd45..250e10f 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -211,7 +211,7 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, new_bus = mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc); if (!new_bus) - return -ENODEV; + goto out_free; ret = of_mdiobus_register(new_bus, ofdev->node); if (ret) -- cgit v0.10.2 From 8ff44985c761ad6697a3c97e7b14cf5362ff3801 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 9 Sep 2009 16:01:30 +0000 Subject: phy/marvell: Make non-aneg speed/duplex forcing work for 88E1111 PHYs According to specs, when auto-negotiation is disabled, Marvell PHYs need a software reset after changing speed/duplex forcing bits. Otherwise, the modified bits have no effect. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index dd6f54d..6f69b9b 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -155,8 +155,27 @@ static int marvell_config_aneg(struct phy_device *phydev) return err; err = genphy_config_aneg(phydev); + if (err < 0) + return err; - return err; + if (phydev->autoneg != AUTONEG_ENABLE) { + int bmcr; + + /* + * A write to speed/duplex bits (that is performed by + * genphy_config_aneg() call above) must be followed by + * a software reset. Otherwise, the write has no effect. + */ + bmcr = phy_read(phydev, MII_BMCR); + if (bmcr < 0) + return bmcr; + + err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET); + if (err < 0) + return err; + } + + return 0; } static int m88e1121_config_aneg(struct phy_device *phydev) -- cgit v0.10.2 From 7de8ee787e8e10adaf5635bffab4ee19a7558afb Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 9 Sep 2009 16:01:40 +0000 Subject: ucc_geth: Rearrange some code to avoid forward declarations We'll need ugeth_disable() and ugeth_enable() calls earlier in the file, so rearrange some code to avoid forward declarations. The patch doesn't contain any functional changes. Signed-off-by: Anton Vorontsov Acked-by: Timur Tabi Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 3b647d0..a39368a 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1412,6 +1412,155 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) return 0; } +static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) +{ + struct ucc_fast_private *uccf; + u32 cecr_subblock; + u32 temp; + int i = 10; + + uccf = ugeth->uccf; + + /* Mask GRACEFUL STOP TX interrupt bit and clear it */ + clrbits32(uccf->p_uccm, UCC_GETH_UCCE_GRA); + out_be32(uccf->p_ucce, UCC_GETH_UCCE_GRA); /* clear by writing 1 */ + + /* Issue host command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock, + QE_CR_PROTOCOL_ETHERNET, 0); + + /* Wait for command to complete */ + do { + msleep(10); + temp = in_be32(uccf->p_ucce); + } while (!(temp & UCC_GETH_UCCE_GRA) && --i); + + uccf->stopped_tx = 1; + + return 0; +} + +static int ugeth_graceful_stop_rx(struct ucc_geth_private *ugeth) +{ + struct ucc_fast_private *uccf; + u32 cecr_subblock; + u8 temp; + int i = 10; + + uccf = ugeth->uccf; + + /* Clear acknowledge bit */ + temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); + temp &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX; + out_8(&ugeth->p_rx_glbl_pram->rxgstpack, temp); + + /* Keep issuing command and checking acknowledge bit until + it is asserted, according to spec */ + do { + /* Issue host command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info. + ucc_num); + qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, + QE_CR_PROTOCOL_ETHERNET, 0); + msleep(10); + temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); + } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX) && --i); + + uccf->stopped_rx = 1; + + return 0; +} + +static int ugeth_restart_tx(struct ucc_geth_private *ugeth) +{ + struct ucc_fast_private *uccf; + u32 cecr_subblock; + + uccf = ugeth->uccf; + + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_RESTART_TX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, 0); + uccf->stopped_tx = 0; + + return 0; +} + +static int ugeth_restart_rx(struct ucc_geth_private *ugeth) +{ + struct ucc_fast_private *uccf; + u32 cecr_subblock; + + uccf = ugeth->uccf; + + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_RESTART_RX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, + 0); + uccf->stopped_rx = 0; + + return 0; +} + +static int ugeth_enable(struct ucc_geth_private *ugeth, enum comm_dir mode) +{ + struct ucc_fast_private *uccf; + int enabled_tx, enabled_rx; + + uccf = ugeth->uccf; + + /* check if the UCC number is in range. */ + if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { + if (netif_msg_probe(ugeth)) + ugeth_err("%s: ucc_num out of range.", __func__); + return -EINVAL; + } + + enabled_tx = uccf->enabled_tx; + enabled_rx = uccf->enabled_rx; + + /* Get Tx and Rx going again, in case this channel was actively + disabled. */ + if ((mode & COMM_DIR_TX) && (!enabled_tx) && uccf->stopped_tx) + ugeth_restart_tx(ugeth); + if ((mode & COMM_DIR_RX) && (!enabled_rx) && uccf->stopped_rx) + ugeth_restart_rx(ugeth); + + ucc_fast_enable(uccf, mode); /* OK to do even if not disabled */ + + return 0; + +} + +static int ugeth_disable(struct ucc_geth_private *ugeth, enum comm_dir mode) +{ + struct ucc_fast_private *uccf; + + uccf = ugeth->uccf; + + /* check if the UCC number is in range. */ + if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { + if (netif_msg_probe(ugeth)) + ugeth_err("%s: ucc_num out of range.", __func__); + return -EINVAL; + } + + /* Stop any transmissions */ + if ((mode & COMM_DIR_TX) && uccf->enabled_tx && !uccf->stopped_tx) + ugeth_graceful_stop_tx(ugeth); + + /* Stop any receptions */ + if ((mode & COMM_DIR_RX) && uccf->enabled_rx && !uccf->stopped_rx) + ugeth_graceful_stop_rx(ugeth); + + ucc_fast_disable(ugeth->uccf, mode); /* OK to do even if not enabled */ + + return 0; +} + /* Called every time the controller might need to be made * aware of new link state. The PHY code conveys this * information through variables in the ugeth structure, and this @@ -1587,157 +1736,6 @@ static int init_phy(struct net_device *dev) return 0; } - - -static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) -{ - struct ucc_fast_private *uccf; - u32 cecr_subblock; - u32 temp; - int i = 10; - - uccf = ugeth->uccf; - - /* Mask GRACEFUL STOP TX interrupt bit and clear it */ - clrbits32(uccf->p_uccm, UCC_GETH_UCCE_GRA); - out_be32(uccf->p_ucce, UCC_GETH_UCCE_GRA); /* clear by writing 1 */ - - /* Issue host command */ - cecr_subblock = - ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); - qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock, - QE_CR_PROTOCOL_ETHERNET, 0); - - /* Wait for command to complete */ - do { - msleep(10); - temp = in_be32(uccf->p_ucce); - } while (!(temp & UCC_GETH_UCCE_GRA) && --i); - - uccf->stopped_tx = 1; - - return 0; -} - -static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth) -{ - struct ucc_fast_private *uccf; - u32 cecr_subblock; - u8 temp; - int i = 10; - - uccf = ugeth->uccf; - - /* Clear acknowledge bit */ - temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); - temp &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX; - out_8(&ugeth->p_rx_glbl_pram->rxgstpack, temp); - - /* Keep issuing command and checking acknowledge bit until - it is asserted, according to spec */ - do { - /* Issue host command */ - cecr_subblock = - ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info. - ucc_num); - qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, - QE_CR_PROTOCOL_ETHERNET, 0); - msleep(10); - temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); - } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX) && --i); - - uccf->stopped_rx = 1; - - return 0; -} - -static int ugeth_restart_tx(struct ucc_geth_private *ugeth) -{ - struct ucc_fast_private *uccf; - u32 cecr_subblock; - - uccf = ugeth->uccf; - - cecr_subblock = - ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); - qe_issue_cmd(QE_RESTART_TX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, 0); - uccf->stopped_tx = 0; - - return 0; -} - -static int ugeth_restart_rx(struct ucc_geth_private *ugeth) -{ - struct ucc_fast_private *uccf; - u32 cecr_subblock; - - uccf = ugeth->uccf; - - cecr_subblock = - ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); - qe_issue_cmd(QE_RESTART_RX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, - 0); - uccf->stopped_rx = 0; - - return 0; -} - -static int ugeth_enable(struct ucc_geth_private *ugeth, enum comm_dir mode) -{ - struct ucc_fast_private *uccf; - int enabled_tx, enabled_rx; - - uccf = ugeth->uccf; - - /* check if the UCC number is in range. */ - if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { - if (netif_msg_probe(ugeth)) - ugeth_err("%s: ucc_num out of range.", __func__); - return -EINVAL; - } - - enabled_tx = uccf->enabled_tx; - enabled_rx = uccf->enabled_rx; - - /* Get Tx and Rx going again, in case this channel was actively - disabled. */ - if ((mode & COMM_DIR_TX) && (!enabled_tx) && uccf->stopped_tx) - ugeth_restart_tx(ugeth); - if ((mode & COMM_DIR_RX) && (!enabled_rx) && uccf->stopped_rx) - ugeth_restart_rx(ugeth); - - ucc_fast_enable(uccf, mode); /* OK to do even if not disabled */ - - return 0; - -} - -static int ugeth_disable(struct ucc_geth_private * ugeth, enum comm_dir mode) -{ - struct ucc_fast_private *uccf; - - uccf = ugeth->uccf; - - /* check if the UCC number is in range. */ - if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { - if (netif_msg_probe(ugeth)) - ugeth_err("%s: ucc_num out of range.", __func__); - return -EINVAL; - } - - /* Stop any transmissions */ - if ((mode & COMM_DIR_TX) && uccf->enabled_tx && !uccf->stopped_tx) - ugeth_graceful_stop_tx(ugeth); - - /* Stop any receptions */ - if ((mode & COMM_DIR_RX) && uccf->enabled_rx && !uccf->stopped_rx) - ugeth_graceful_stop_rx(ugeth); - - ucc_fast_disable(ugeth->uccf, mode); /* OK to do even if not enabled */ - - return 0; -} - static void ugeth_dump_regs(struct ucc_geth_private *ugeth) { #ifdef DEBUG -- cgit v0.10.2 From 864fdf884e82bacbe8ca5e93bd43393a61d2e2b4 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 10 Sep 2009 11:48:12 +0000 Subject: ucc_geth: Fix hangs after switching from full to half duplex MPC8360 QE UCC ethernet controllers hang when changing link duplex under a load (a bit of NFS activity is enough). PHY: mdio@e0102120:00 - Link is Up - 1000/Full sh-3.00# ethtool -s eth0 speed 100 duplex half autoneg off PHY: mdio@e0102120:00 - Link is Down PHY: mdio@e0102120:00 - Link is Up - 100/Half NETDEV WATCHDOG: eth0 (ucc_geth): transmit queue 0 timed out ------------[ cut here ]------------ Badness at c01fcbd0 [verbose debug info unavailable] NIP: c01fcbd0 LR: c01fcbd0 CTR: c0194e44 ... The cure is to disable the controller before changing speed/duplex and enable it afterwards. Though, disabling the controller might take quite a while, so we better not grab any spinlocks in adjust_link(). Instead, we quiesce the driver's activity, and only then disable the controller. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index a39368a..4469f24 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1561,6 +1561,25 @@ static int ugeth_disable(struct ucc_geth_private *ugeth, enum comm_dir mode) return 0; } +static void ugeth_quiesce(struct ucc_geth_private *ugeth) +{ + /* Wait for and prevent any further xmits. */ + netif_tx_disable(ugeth->ndev); + + /* Disable the interrupt to avoid NAPI rescheduling. */ + disable_irq(ugeth->ug_info->uf_info.irq); + + /* Stop NAPI, and possibly wait for its completion. */ + napi_disable(&ugeth->napi); +} + +static void ugeth_activate(struct ucc_geth_private *ugeth) +{ + napi_enable(&ugeth->napi); + enable_irq(ugeth->ug_info->uf_info.irq); + netif_tx_wake_all_queues(ugeth->ndev); +} + /* Called every time the controller might need to be made * aware of new link state. The PHY code conveys this * information through variables in the ugeth structure, and this @@ -1574,14 +1593,11 @@ static void adjust_link(struct net_device *dev) struct ucc_geth __iomem *ug_regs; struct ucc_fast __iomem *uf_regs; struct phy_device *phydev = ugeth->phydev; - unsigned long flags; int new_state = 0; ug_regs = ugeth->ug_regs; uf_regs = ugeth->uccf->uf_regs; - spin_lock_irqsave(&ugeth->lock, flags); - if (phydev->link) { u32 tempval = in_be32(&ug_regs->maccfg2); u32 upsmr = in_be32(&uf_regs->upsmr); @@ -1632,9 +1648,21 @@ static void adjust_link(struct net_device *dev) ugeth->oldspeed = phydev->speed; } + /* + * To change the MAC configuration we need to disable the + * controller. To do so, we have to either grab ugeth->lock, + * which is a bad idea since 'graceful stop' commands might + * take quite a while, or we can quiesce driver's activity. + */ + ugeth_quiesce(ugeth); + ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); + out_be32(&ug_regs->maccfg2, tempval); out_be32(&uf_regs->upsmr, upsmr); + ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); + ugeth_activate(ugeth); + if (!ugeth->oldlink) { new_state = 1; ugeth->oldlink = 1; @@ -1648,8 +1676,6 @@ static void adjust_link(struct net_device *dev) if (new_state && netif_msg_link(ugeth)) phy_print_status(phydev); - - spin_unlock_irqrestore(&ugeth->lock, flags); } /* Initialize TBI PHY interface for communicating with the -- cgit v0.10.2 From f510c35de0e63e1066db83d2fdce99e6dbde0c80 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Sun, 6 Sep 2009 23:59:16 +0000 Subject: mv643xx_eth.c: remove unused txq_set_wrr() The txq_set_wrr() function in drivers/net/mv643xx_eth.c is unused, not even referenced under #if 0 or something like that, which results in a compile-time warning: drivers/net/mv643xx_eth.c:1070: warning: 'txq_set_wrr' defined but not used Fix: remove it. Signed-off-by: Mikael Pettersson Signed-off-by: David S. Miller diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 0f32db3..b62e61d 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1066,40 +1066,6 @@ static void txq_set_fixed_prio_mode(struct tx_queue *txq) } } -static void txq_set_wrr(struct tx_queue *txq, int weight) -{ - struct mv643xx_eth_private *mp = txq_to_mp(txq); - int off; - u32 val; - - /* - * Turn off fixed priority mode. - */ - off = 0; - switch (mp->shared->tx_bw_control) { - case TX_BW_CONTROL_OLD_LAYOUT: - off = TXQ_FIX_PRIO_CONF; - break; - case TX_BW_CONTROL_NEW_LAYOUT: - off = TXQ_FIX_PRIO_CONF_MOVED; - break; - } - - if (off) { - val = rdlp(mp, off); - val &= ~(1 << txq->index); - wrlp(mp, off, val); - - /* - * Configure WRR weight for this queue. - */ - - val = rdlp(mp, off); - val = (val & ~0xff) | (weight & 0xff); - wrlp(mp, TXQ_BW_WRR_CONF(txq->index), val); - } -} - /* mii management interface *************************************************/ static irqreturn_t mv643xx_eth_err_irq(int irq, void *dev_id) -- cgit v0.10.2 From 384912ed194e43c03ad1cdaa09b0b1e488c34d46 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 31 Aug 2009 21:08:19 +0000 Subject: net: Add DEVTYPE support for Ethernet based devices The Ethernet framing is used for a lot of devices these days. Most prominent are WiFi and WiMAX based devices. However for userspace application it is important to classify these devices correctly and not only see them as Ethernet devices. The daemons like HAL, DeviceKit or even NetworkManager with udev support tries to do the classification in userspace with a lot trickery and extra system calls. This is not good and actually reaches its limitations. Especially since the kernel does know the type of the Ethernet device it is pretty stupid. To solve this problem the underlying device type needs to be set and then the value will be exported as DEVTYPE via uevents and available within udev. # cat /sys/class/net/wlan0/uevent DEVTYPE=wlan INTERFACE=wlan0 IFINDEX=5 This is similar to subsystems like USB and SCSI that distinguish between hosts, devices, disks, partitions etc. The new SET_NETDEV_DEVTYPE() is a convenience helper to set the actual device type. All device types are free form, but for convenience the same strings as used with RFKILL are choosen. Signed-off-by: Marcel Holtmann Signed-off-by: David S. Miller diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 3f9c92a..fa4e581 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2535,6 +2535,10 @@ static void hso_create_rfkill(struct hso_device *hso_dev, } } +static struct device_type hso_type = { + .name = "wwan", +}; + /* Creates our network device */ static struct hso_device *hso_create_net_device(struct usb_interface *interface, int port_spec) @@ -2575,6 +2579,7 @@ static struct hso_device *hso_create_net_device(struct usb_interface *interface, goto exit; } SET_NETDEV_DEV(net, &interface->dev); + SET_NETDEV_DEVTYPE(net, &hso_type); /* registering our net device */ result = register_netdev(net); diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index ea7b290..2981e21 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -371,6 +371,10 @@ error: } +static struct device_type i2400ms_type = { + .name = "wimax", +}; + /* * Probe a i2400m interface and register it * @@ -412,6 +416,7 @@ int i2400ms_probe(struct sdio_func *func, goto error_alloc_netdev; } SET_NETDEV_DEV(net_dev, dev); + SET_NETDEV_DEVTYPE(net_dev, &i2400ms_type); i2400m = net_dev_to_i2400m(net_dev); i2400ms = container_of(i2400m, struct i2400ms, i2400m); i2400m->wimax_dev.net_dev = net_dev; diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index cfdaf69..7eadd11 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -351,6 +351,10 @@ error: } +static struct device_type i2400mu_type = { + .name = "wimax", +}; + /* * Probe a i2400m interface and register it * @@ -388,6 +392,7 @@ int i2400mu_probe(struct usb_interface *iface, goto error_alloc_netdev; } SET_NETDEV_DEV(net_dev, dev); + SET_NETDEV_DEVTYPE(net_dev, &i2400mu_type); i2400m = net_dev_to_i2400m(net_dev); i2400mu = container_of(i2400m, struct i2400mu, i2400m); i2400m->wimax_dev.net_dev = net_dev; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a44118b..65ee192 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -998,6 +998,12 @@ static inline void *netdev_priv(const struct net_device *dev) */ #define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev)) +/* Set the sysfs device type for the network logical device to allow + * fin grained indentification of different network device types. For + * example Ethernet, Wirelss LAN, Bluetooth, WiMAX etc. + */ +#define SET_NETDEV_DEVTYPE(net, devtype) ((net)->dev.type = (devtype)) + /** * netif_napi_add - initialize a napi context * @dev: network device diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 52a6ce0..cafe9f5 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -533,6 +533,10 @@ static struct device *bnep_get_device(struct bnep_session *session) return conn ? &conn->dev : NULL; } +static struct device_type bnep_type = { + .name = "bluetooth", +}; + int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) { struct net_device *dev; @@ -586,6 +590,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) #endif SET_NETDEV_DEV(dev, bnep_get_device(s)); + SET_NETDEV_DEVTYPE(dev, &bnep_type); err = register_netdev(dev); if (err) { diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index e486f1f..142ebac 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -264,6 +264,10 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, return p; } +static struct device_type br_type = { + .name = "bridge", +}; + int br_add_bridge(struct net *net, const char *name) { struct net_device *dev; @@ -280,6 +284,8 @@ int br_add_bridge(struct net *net, const char *name) goto out_free; } + SET_NETDEV_DEVTYPE(dev, &br_type); + ret = register_netdevice(dev); if (ret) goto out_free; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f6005ad..b8295cb 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -754,6 +754,10 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, return 0; } +static struct device_type wiphy_type = { + .name = "wlan", +}; + int ieee80211_if_add(struct ieee80211_local *local, const char *name, struct net_device **new_dev, enum nl80211_iftype type, struct vif_params *params) @@ -785,6 +789,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); + SET_NETDEV_DEVTYPE(ndev, &wiphy_type); /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ sdata = netdev_priv(ndev); -- cgit v0.10.2 From cc411d0bae9c19ec85a150aeab4b08335f5751d1 Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Wed, 9 Sep 2009 14:41:32 +0000 Subject: ipv6: Add IFA_F_DADFAILED flag Add IFA_F_DADFAILED flag to denote an IPv6 address that has failed Duplicate Address Detection, that way tools like /sbin/ip can be more informative. 3: eth0: mtu 1500 qlen 1000 inet6 2001:db8::1/64 scope global tentative dadfailed valid_lft forever preferred_lft forever Signed-off-by: Brian Haley Signed-off-by: David S. Miller diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h index a60c821..fd97404 100644 --- a/include/linux/if_addr.h +++ b/include/linux/if_addr.h @@ -41,6 +41,7 @@ enum #define IFA_F_NODAD 0x02 #define IFA_F_OPTIMISTIC 0x04 +#define IFA_F_DADFAILED 0x08 #define IFA_F_HOMEADDRESS 0x10 #define IFA_F_DEPRECATED 0x20 #define IFA_F_TENTATIVE 0x40 diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 43b3c9f..c9b3690 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1371,12 +1371,14 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add /* Gets referenced address, destroys ifaddr */ -static void addrconf_dad_stop(struct inet6_ifaddr *ifp) +static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) { if (ifp->flags&IFA_F_PERMANENT) { spin_lock_bh(&ifp->lock); addrconf_del_timer(ifp); ifp->flags |= IFA_F_TENTATIVE; + if (dad_failed) + ifp->flags |= IFA_F_DADFAILED; spin_unlock_bh(&ifp->lock); in6_ifa_put(ifp); #ifdef CONFIG_IPV6_PRIVACY @@ -1422,7 +1424,7 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) } } - addrconf_dad_stop(ifp); + addrconf_dad_stop(ifp, 1); } /* Join to solicited addr multicast group. */ @@ -2778,7 +2780,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) idev->cnf.accept_dad < 1 || !(ifp->flags&IFA_F_TENTATIVE) || ifp->flags & IFA_F_NODAD) { - ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); + ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); spin_unlock_bh(&ifp->lock); read_unlock_bh(&idev->lock); @@ -2795,7 +2797,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) * - otherwise, kill it. */ in6_ifa_hold(ifp); - addrconf_dad_stop(ifp); + addrconf_dad_stop(ifp, 0); return; } @@ -2829,7 +2831,7 @@ static void addrconf_dad_timer(unsigned long data) * DAD was successful */ - ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); + ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); spin_unlock_bh(&ifp->lock); read_unlock_bh(&idev->lock); -- cgit v0.10.2 From 998ec759ef2fc9c60319815c72b2b699ab939733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Tue, 8 Sep 2009 23:59:51 +0000 Subject: Phonet: fix netlink address dump error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c index f8b4cee..d21fd35 100644 --- a/net/phonet/pn_netlink.c +++ b/net/phonet/pn_netlink.c @@ -147,7 +147,7 @@ static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb) if (fill_addr(skb, pnd->netdev, addr << 2, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, RTM_NEWADDR)) + cb->nlh->nlmsg_seq, RTM_NEWADDR) < 0) goto out; } } -- cgit v0.10.2 From f5bb1c558405aaac41b08b2ea71137db9db46e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Wed, 9 Sep 2009 00:00:05 +0000 Subject: Phonet: back-end for autoconfigured addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In some cases, the network device driver knows what layer-3 address the device should have. This adds support for the Phonet stack to automatically request from the driver and add that address to the network device. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/include/linux/phonet.h b/include/linux/phonet.h index ee5e3c9..82b45d1 100644 --- a/include/linux/phonet.h +++ b/include/linux/phonet.h @@ -170,4 +170,21 @@ static inline __u8 pn_sockaddr_get_resource(const struct sockaddr_pn *spn) return spn->spn_resource; } +/* Phonet device ioctl requests */ +#ifdef __KERNEL__ +#define SIOCPNGAUTOCONF (SIOCDEVPRIVATE + 0) + +struct if_phonet_autoconf { + uint8_t device; +}; + +struct if_phonet_req { + char ifr_phonet_name[16]; + union { + struct if_phonet_autoconf ifru_phonet_autoconf; + } ifr_ifru; +}; +#define ifr_phonet_autoconf ifr_ifru.ifru_phonet_autoconf +#endif /* __KERNEL__ */ + #endif diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 5ae4c01..2f65dca 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -195,14 +196,37 @@ found: return err; } +/* automatically configure a Phonet device, if supported */ +static int phonet_device_autoconf(struct net_device *dev) +{ + struct if_phonet_req req; + int ret; + + if (!dev->netdev_ops->ndo_do_ioctl) + return -EOPNOTSUPP; + + ret = dev->netdev_ops->ndo_do_ioctl(dev, (struct ifreq *)&req, + SIOCPNGAUTOCONF); + if (ret < 0) + return ret; + return phonet_address_add(dev, req.ifr_phonet_autoconf.device); +} + /* notify Phonet of device events */ static int phonet_device_notify(struct notifier_block *me, unsigned long what, void *arg) { struct net_device *dev = arg; - if (what == NETDEV_UNREGISTER) + switch (what) { + case NETDEV_REGISTER: + if (dev->type == ARPHRD_PHONET) + phonet_device_autoconf(dev); + break; + case NETDEV_UNREGISTER: phonet_device_destroy(dev); + break; + } return 0; } -- cgit v0.10.2 From 02571f89871e009b66fb5f8d5ae222e90e9f357c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Wed, 9 Sep 2009 00:00:06 +0000 Subject: cdc-phonet: autoconfigure Phonet address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 0ca5916..97e54d9 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -27,6 +27,7 @@ #include #include #include +#include #define PN_MEDIA_USB 0x1B @@ -256,6 +257,19 @@ static int usbpn_close(struct net_device *dev) return usb_set_interface(pnd->usb, num, !pnd->active_setting); } +static int usbpn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct if_phonet_req *req = (struct if_phonet_req *)ifr; + + switch (cmd) { + case SIOCPNGAUTOCONF: + req->ifr_phonet_autoconf.device = PN_DEV_PC; + printk(KERN_CRIT"device is PN_DEV_PC\n"); + return 0; + } + return -ENOIOCTLCMD; +} + static int usbpn_set_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU)) @@ -269,6 +283,7 @@ static const struct net_device_ops usbpn_ops = { .ndo_open = usbpn_open, .ndo_stop = usbpn_close, .ndo_start_xmit = usbpn_xmit, + .ndo_do_ioctl = usbpn_ioctl, .ndo_change_mtu = usbpn_set_mtu, }; diff --git a/include/linux/phonet.h b/include/linux/phonet.h index 82b45d1..1ef5a07 100644 --- a/include/linux/phonet.h +++ b/include/linux/phonet.h @@ -99,6 +99,9 @@ struct sockaddr_pn { __u8 spn_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - 3]; } __attribute__ ((packed)); +/* Well known address */ +#define PN_DEV_PC 0x10 + static inline __u16 pn_object(__u8 addr, __u16 port) { return (addr << 8) | (port & 0x3ff); -- cgit v0.10.2 From 9feae56c0de65fdd8b1f64f376bb6578417d2b79 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 11 Sep 2009 12:41:04 +0000 Subject: netxen: build fix for INET=n When CONFIG_INET is disabled, netxen has a build failure: netxen_nic_main.c:(.text+0x118fd1): undefined reference to `netxen_config_indev_addr' so make that function just an empty stub when CONFIG_INET=n. (not "inline" since that conflicts with other declarations of it) Signed-off-by: Randy Dunlap Acked-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 81c24a7..1399102 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -2450,6 +2450,10 @@ static struct notifier_block netxen_netdev_cb = { static struct notifier_block netxen_inetaddr_cb = { .notifier_call = netxen_inetaddr_event, }; +#else +static void +netxen_config_indev_addr(struct net_device *dev, unsigned long event) +{ } #endif static struct pci_driver netxen_driver = { -- cgit v0.10.2 From 5ea1c50662d447de344812054175d7151783ea25 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 11 Sep 2009 16:50:16 -0700 Subject: tg3: Fix return ring size breakage Commit f6eb9b1fc1411d22c073f5264e5630a541d0f7df, "tg3: Add 5717 asic rev" changed how the rx return ring size operations are done. It effectively inverts the sense of the previous test, but it failed to also invert the resulting sizes. This patch corrects that error. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7cf8000..f09bc5d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -112,7 +112,7 @@ */ #define TG3_RX_RCB_RING_SIZE(tp) \ (((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && \ - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) ? 512 : 1024) + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) ? 1024 : 512) #define TG3_TX_RING_SIZE 512 #define TG3_DEF_TX_RING_PENDING (TG3_TX_RING_SIZE - 1) -- cgit v0.10.2 From f78c0850d2ebe7a44a4b0263480a2f1a36a92218 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Fri, 11 Sep 2009 11:28:11 +0000 Subject: netxen: change firmware write size Use 8 byte strides for firmware download into card memory since oncard memory controller needs 8 byte (64 bit) accesses. This avoids unnecessary rmw cycles. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 485b947..8926b0e 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -727,21 +727,28 @@ netxen_load_firmware(struct netxen_adapter *adapter) flashaddr += 8; } } else { - u32 data; + u64 data; + u32 hi, lo; - size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 4; + size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8; flashaddr = NETXEN_BOOTLD_START; for (i = 0; i < size; i++) { if (netxen_rom_fast_read(adapter, - flashaddr, (int *)&data) != 0) + flashaddr, &lo) != 0) + return -EIO; + if (netxen_rom_fast_read(adapter, + flashaddr + 4, &hi) != 0) return -EIO; + /* hi, lo are already in host endian byteorder */ + data = (((u64)hi << 32) | lo); + if (adapter->pci_mem_write(adapter, - flashaddr, &data, 4)) + flashaddr, &data, 8)) return -EIO; - flashaddr += 4; + flashaddr += 8; } } msleep(1); -- cgit v0.10.2 From ea6828b8aa3a8ebae8d7740f32f212ba1d2f0742 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Fri, 11 Sep 2009 11:28:12 +0000 Subject: netxen: improve pci memory access o Access on card memory through memory controller (agent) rather than moving small pci window around. Clean up the code for moving windows around. o Restrict memory accesss to 64 bit, currently only firmware download uses this. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 2371888..7e3d2b9 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -552,8 +552,8 @@ struct netxen_hardware_context { int qdr_sn_window; int ddr_mn_window; - unsigned long mn_win_crb; - unsigned long ms_win_crb; + u32 mn_win_crb; + u32 ms_win_crb; u8 cut_through; u8 revision_id; diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 555bc4a..018cf42 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -1279,25 +1279,6 @@ netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off) return data; } -/* - * check memory access boundary. - * used by test agent. support ddr access only for now - */ -static unsigned long -netxen_nic_pci_mem_bound_check(struct netxen_adapter *adapter, - unsigned long long addr, int size) -{ - if (!ADDR_IN_RANGE(addr, - NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX) || - !ADDR_IN_RANGE(addr+size-1, - NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX) || - ((size != 1) && (size != 2) && (size != 4) && (size != 8))) { - return 0; - } - - return 1; -} - static int netxen_pci_set_window_warning_count; static unsigned long @@ -1424,10 +1405,8 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, /* DDR network side */ window = MN_WIN(addr); adapter->ahw.ddr_mn_window = window; - NXWR32(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - window); - win_read = NXRD32(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE); + NXWR32(adapter, adapter->ahw.mn_win_crb, window); + win_read = NXRD32(adapter, adapter->ahw.mn_win_crb); if ((win_read << 17) != window) { printk(KERN_INFO "Written MNwin (0x%x) != " "Read MNwin (0x%x)\n", window, win_read); @@ -1442,10 +1421,8 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, window = OCM_WIN(addr); adapter->ahw.ddr_mn_window = window; - NXWR32(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - window); - win_read = NXRD32(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE); + NXWR32(adapter, adapter->ahw.mn_win_crb, window); + win_read = NXRD32(adapter, adapter->ahw.mn_win_crb); if ((win_read >> 7) != window) { printk(KERN_INFO "%s: Written OCMwin (0x%x) != " "Read OCMwin (0x%x)\n", @@ -1458,10 +1435,8 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, /* QDR network side */ window = MS_WIN(addr); adapter->ahw.qdr_sn_window = window; - NXWR32(adapter, adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE, - window); - win_read = NXRD32(adapter, - adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE); + NXWR32(adapter, adapter->ahw.ms_win_crb, window); + win_read = NXRD32(adapter, adapter->ahw.ms_win_crb); if (win_read != window) { printk(KERN_INFO "%s: Written MSwin (0x%x) != " "Read MSwin (0x%x)\n", @@ -1484,177 +1459,6 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, return addr; } -static int netxen_nic_pci_is_same_window(struct netxen_adapter *adapter, - unsigned long long addr) -{ - int window; - unsigned long long qdr_max; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - qdr_max = NETXEN_ADDR_QDR_NET_MAX_P2; - else - qdr_max = NETXEN_ADDR_QDR_NET_MAX_P3; - - if (ADDR_IN_RANGE(addr, - NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) { - /* DDR network side */ - BUG(); /* MN access can not come here */ - } else if (ADDR_IN_RANGE(addr, - NETXEN_ADDR_OCM0, NETXEN_ADDR_OCM0_MAX)) { - return 1; - } else if (ADDR_IN_RANGE(addr, - NETXEN_ADDR_OCM1, NETXEN_ADDR_OCM1_MAX)) { - return 1; - } else if (ADDR_IN_RANGE(addr, NETXEN_ADDR_QDR_NET, qdr_max)) { - /* QDR network side */ - window = ((addr - NETXEN_ADDR_QDR_NET) >> 22) & 0x3f; - if (adapter->ahw.qdr_sn_window == window) - return 1; - } - - return 0; -} - -static int netxen_nic_pci_mem_read_direct(struct netxen_adapter *adapter, - u64 off, void *data, int size) -{ - unsigned long flags; - void __iomem *addr, *mem_ptr = NULL; - int ret = 0; - u64 start; - unsigned long mem_base; - unsigned long mem_page; - - write_lock_irqsave(&adapter->adapter_lock, flags); - - /* - * If attempting to access unknown address or straddle hw windows, - * do not access. - */ - start = adapter->pci_set_window(adapter, off); - if ((start == -1UL) || - (netxen_nic_pci_is_same_window(adapter, off+size-1) == 0)) { - write_unlock_irqrestore(&adapter->adapter_lock, flags); - printk(KERN_ERR "%s out of bound pci memory access. " - "offset is 0x%llx\n", netxen_nic_driver_name, - (unsigned long long)off); - return -1; - } - - addr = pci_base_offset(adapter, start); - if (!addr) { - write_unlock_irqrestore(&adapter->adapter_lock, flags); - mem_base = pci_resource_start(adapter->pdev, 0); - mem_page = start & PAGE_MASK; - /* Map two pages whenever user tries to access addresses in two - consecutive pages. - */ - if (mem_page != ((start + size - 1) & PAGE_MASK)) - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); - else - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == NULL) { - *(uint8_t *)data = 0; - return -1; - } - addr = mem_ptr; - addr += start & (PAGE_SIZE - 1); - write_lock_irqsave(&adapter->adapter_lock, flags); - } - - switch (size) { - case 1: - *(uint8_t *)data = readb(addr); - break; - case 2: - *(uint16_t *)data = readw(addr); - break; - case 4: - *(uint32_t *)data = readl(addr); - break; - case 8: - *(uint64_t *)data = readq(addr); - break; - default: - ret = -1; - break; - } - write_unlock_irqrestore(&adapter->adapter_lock, flags); - - if (mem_ptr) - iounmap(mem_ptr); - return ret; -} - -static int -netxen_nic_pci_mem_write_direct(struct netxen_adapter *adapter, u64 off, - void *data, int size) -{ - unsigned long flags; - void __iomem *addr, *mem_ptr = NULL; - int ret = 0; - u64 start; - unsigned long mem_base; - unsigned long mem_page; - - write_lock_irqsave(&adapter->adapter_lock, flags); - - /* - * If attempting to access unknown address or straddle hw windows, - * do not access. - */ - start = adapter->pci_set_window(adapter, off); - if ((start == -1UL) || - (netxen_nic_pci_is_same_window(adapter, off+size-1) == 0)) { - write_unlock_irqrestore(&adapter->adapter_lock, flags); - printk(KERN_ERR "%s out of bound pci memory access. " - "offset is 0x%llx\n", netxen_nic_driver_name, - (unsigned long long)off); - return -1; - } - - addr = pci_base_offset(adapter, start); - if (!addr) { - write_unlock_irqrestore(&adapter->adapter_lock, flags); - mem_base = pci_resource_start(adapter->pdev, 0); - mem_page = start & PAGE_MASK; - /* Map two pages whenever user tries to access addresses in two - * consecutive pages. - */ - if (mem_page != ((start + size - 1) & PAGE_MASK)) - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2); - else - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == NULL) - return -1; - addr = mem_ptr; - addr += start & (PAGE_SIZE - 1); - write_lock_irqsave(&adapter->adapter_lock, flags); - } - - switch (size) { - case 1: - writeb(*(uint8_t *)data, addr); - break; - case 2: - writew(*(uint16_t *)data, addr); - break; - case 4: - writel(*(uint32_t *)data, addr); - break; - case 8: - writeq(*(uint64_t *)data, addr); - break; - default: - ret = -1; - break; - } - write_unlock_irqrestore(&adapter->adapter_lock, flags); - if (mem_ptr) - iounmap(mem_ptr); - return ret; -} - #define MAX_CTL_CHECK 1000 static int @@ -1667,19 +1471,28 @@ netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter, uint64_t off8, tmpw, word[2] = {0, 0}; void __iomem *mem_crb; - /* - * If not MN, go check for MS or invalid. - */ - if (netxen_nic_pci_mem_bound_check(adapter, off, size) == 0) - return netxen_nic_pci_mem_write_direct(adapter, - off, data, size); + if (size != 8) + return -EIO; + + if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET, + NETXEN_ADDR_QDR_NET_MAX_P2)) { + mem_crb = pci_base_offset(adapter, NETXEN_CRB_QDR_NET); + goto correct; + } + + if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) { + mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET); + goto correct; + } + + return -EIO; +correct: off8 = off & 0xfffffff8; off0 = off & 0x7; sz[0] = (size < (8 - off0)) ? size : (8 - off0); sz[1] = size - sz[0]; loop = ((off0 + size - 1) >> 3) + 1; - mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET); if ((size != 8) || (off0 != 0)) { for (i = 0; i < loop; i++) { @@ -1760,20 +1573,29 @@ netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter, uint64_t off8, val, word[2] = {0, 0}; void __iomem *mem_crb; + if (size != 8) + return -EIO; - /* - * If not MN, go check for MS or invalid. - */ - if (netxen_nic_pci_mem_bound_check(adapter, off, size) == 0) - return netxen_nic_pci_mem_read_direct(adapter, off, data, size); + if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET, + NETXEN_ADDR_QDR_NET_MAX_P2)) { + mem_crb = pci_base_offset(adapter, NETXEN_CRB_QDR_NET); + goto correct; + } + if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) { + mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET); + goto correct; + } + + return -EIO; + +correct: off8 = off & 0xfffffff8; off0[0] = off & 0x7; off0[1] = 0; sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]); sz[1] = size - sz[0]; loop = ((off0[0] + size - 1) >> 3) + 1; - mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET); write_lock_irqsave(&adapter->adapter_lock, flags); netxen_nic_pci_change_crbwindow_128M(adapter, 0); @@ -1847,20 +1669,26 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, { int i, j, ret = 0, loop, sz[2], off0; uint32_t temp; - uint64_t off8, mem_crb, tmpw, word[2] = {0, 0}; + uint64_t off8, tmpw, word[2] = {0, 0}; + void __iomem *mem_crb; - /* - * If not MN, go check for MS or invalid. - */ - if (off >= NETXEN_ADDR_QDR_NET && off <= NETXEN_ADDR_QDR_NET_MAX_P3) - mem_crb = NETXEN_CRB_QDR_NET; - else { - mem_crb = NETXEN_CRB_DDR_NET; - if (netxen_nic_pci_mem_bound_check(adapter, off, size) == 0) - return netxen_nic_pci_mem_write_direct(adapter, - off, data, size); + if (size != 8) + return -EIO; + + if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET, + NETXEN_ADDR_QDR_NET_MAX_P3)) { + mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_QDR_NET); + goto correct; } + if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) { + mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_DDR_NET); + goto correct; + } + + return -EIO; + +correct: off8 = off & 0xfffffff8; off0 = off & 0x7; sz[0] = (size < (8 - off0)) ? size : (8 - off0); @@ -1906,21 +1734,18 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, */ for (i = 0; i < loop; i++) { - temp = off8 + (i << 3); - NXWR32(adapter, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - NXWR32(adapter, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); - temp = word[i] & 0xffffffff; - NXWR32(adapter, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); - temp = (word[i] >> 32) & 0xffffffff; - NXWR32(adapter, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); - temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - NXWR32(adapter, mem_crb+MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - NXWR32(adapter, mem_crb+MIU_TEST_AGT_CTRL, temp); + writel(off8 + (i << 3), mem_crb+MIU_TEST_AGT_ADDR_LO); + writel(0, mem_crb+MIU_TEST_AGT_ADDR_HI); + writel(word[i] & 0xffffffff, mem_crb+MIU_TEST_AGT_WRDATA_LO); + writel((word[i] >> 32) & 0xffffffff, + mem_crb+MIU_TEST_AGT_WRDATA_HI); + writel((MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE), + mem_crb+MIU_TEST_AGT_CTRL); + writel(MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE, + mem_crb+MIU_TEST_AGT_CTRL); for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = NXRD32(adapter, mem_crb + MIU_TEST_AGT_CTRL); + temp = readl(mem_crb + MIU_TEST_AGT_CTRL); if ((temp & MIU_TA_CTL_BUSY) == 0) break; } @@ -1947,21 +1772,26 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, { int i, j = 0, k, start, end, loop, sz[2], off0[2]; uint32_t temp; - uint64_t off8, val, mem_crb, word[2] = {0, 0}; + uint64_t off8, val, word[2] = {0, 0}; + void __iomem *mem_crb; - /* - * If not MN, go check for MS or invalid. - */ + if (size != 8) + return -EIO; + + if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET, + NETXEN_ADDR_QDR_NET_MAX_P3)) { + mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_QDR_NET); + goto correct; + } - if (off >= NETXEN_ADDR_QDR_NET && off <= NETXEN_ADDR_QDR_NET_MAX_P3) - mem_crb = NETXEN_CRB_QDR_NET; - else { - mem_crb = NETXEN_CRB_DDR_NET; - if (netxen_nic_pci_mem_bound_check(adapter, off, size) == 0) - return netxen_nic_pci_mem_read_direct(adapter, - off, data, size); + if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) { + mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_DDR_NET); + goto correct; } + return -EIO; + +correct: off8 = off & 0xfffffff8; off0[0] = off & 0x7; off0[1] = 0; @@ -1976,17 +1806,14 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, */ for (i = 0; i < loop; i++) { - temp = off8 + (i << 3); - NXWR32(adapter, mem_crb + MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - NXWR32(adapter, mem_crb + MIU_TEST_AGT_ADDR_HI, temp); - temp = MIU_TA_CTL_ENABLE; - NXWR32(adapter, mem_crb + MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; - NXWR32(adapter, mem_crb + MIU_TEST_AGT_CTRL, temp); + writel(off8 + (i << 3), mem_crb + MIU_TEST_AGT_ADDR_LO); + writel(0, mem_crb + MIU_TEST_AGT_ADDR_HI); + writel(MIU_TA_CTL_ENABLE, mem_crb + MIU_TEST_AGT_CTRL); + writel(MIU_TA_CTL_START | MIU_TA_CTL_ENABLE, + mem_crb + MIU_TEST_AGT_CTRL); for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = NXRD32(adapter, mem_crb + MIU_TEST_AGT_CTRL); + temp = readl(mem_crb + MIU_TEST_AGT_CTRL); if ((temp & MIU_TA_CTL_BUSY) == 0) break; } @@ -2001,8 +1828,7 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, start = off0[i] >> 2; end = (off0[i] + sz[i] - 1) >> 2; for (k = start; k <= end; k++) { - temp = NXRD32(adapter, - mem_crb + MIU_TEST_AGT_RDDATA(k)); + temp = readl(mem_crb + MIU_TEST_AGT_RDDATA(k)); word[i] |= ((uint64_t)temp << (32 * k)); } } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 1399102..557e76c 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -643,9 +643,10 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) adapter->ahw.ddr_mn_window = 0; adapter->ahw.qdr_sn_window = 0; - adapter->ahw.mn_win_crb = 0x100000 + PCIX_MN_WINDOW + - (pci_func * 0x20); - adapter->ahw.ms_win_crb = 0x100000 + PCIX_SN_WINDOW; + adapter->ahw.mn_win_crb = NETXEN_PCI_CRBSPACE + + 0x100000 + PCIX_MN_WINDOW + (pci_func * 0x20); + adapter->ahw.ms_win_crb = NETXEN_PCI_CRBSPACE + + 0x100000 + PCIX_SN_WINDOW; if (pci_func < 4) adapter->ahw.ms_win_crb += (pci_func * 0x20); else -- cgit v0.10.2 From ec5c50cb93c446a4686863df74e4b7a547628115 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Fri, 11 Sep 2009 11:28:13 +0000 Subject: netxen: fix file firmware leak Release file firmware when no firmware reset is required. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 557e76c..e8574ee 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -817,7 +817,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) if (err < 0) goto err_out; if (err == 0) - goto wait_init; + goto ready; if (first_boot != 0x55555555) { NXWR32(adapter, CRB_CMDPEG_STATE, 0); @@ -860,6 +860,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) | (_NETXEN_NIC_LINUX_SUBVERSION); NXWR32(adapter, CRB_DRIVER_VERSION, val); +ready: NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_READY); wait_init: @@ -874,7 +875,7 @@ wait_init: netxen_check_options(adapter); - return 0; + /* fall through and release firmware */ err_out: netxen_release_firmware(adapter); -- cgit v0.10.2 From 74c520da5414d15b0ab2839d67efab2e7227be75 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Fri, 11 Sep 2009 11:28:14 +0000 Subject: netxen: fix tx timeout recovery Redesign tx timeout handling in line with new firmware reset design that co-ordinates with other PCI function drivers. o For NX3031, first try to reset PCI function's own context before requesting firmware reset. o For NX2031, since firmware heartbit is not supported directly request firmware reset. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 7e3d2b9..1ae46e8 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -178,6 +178,7 @@ #define MAX_BUFFERS_PER_CMD 32 #define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + 4) +#define NX_MAX_TX_TIMEOUTS 2 /* * Following are the states of the Phantom. Phantom will set them and @@ -1145,7 +1146,8 @@ struct netxen_adapter { u8 link_changed; u8 fw_wait_cnt; u8 fw_fail_cnt; - u16 resv4; + u8 tx_timeo_cnt; + u8 need_fw_reset; u8 has_link_events; u8 fw_type; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 8926b0e..128d1b6 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1434,8 +1434,10 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) { __netif_tx_lock(tx_ring->txq, smp_processor_id()); - if (netxen_tx_avail(tx_ring) > TX_STOP_THRESH) + if (netxen_tx_avail(tx_ring) > TX_STOP_THRESH) { netif_wake_queue(netdev); + adapter->tx_timeo_cnt = 0; + } __netif_tx_unlock(tx_ring->txq); } } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index e8574ee..53bd44e 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -66,7 +66,7 @@ static int netxen_nic_close(struct net_device *netdev); static netdev_tx_t netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); static void netxen_tx_timeout(struct net_device *netdev); -static void netxen_reset_task(struct work_struct *work); +static void netxen_tx_timeout_task(struct work_struct *work); static void netxen_fw_poll_work(struct work_struct *work); static void netxen_schedule_work(struct netxen_adapter *adapter, work_func_t func, int delay); @@ -875,6 +875,8 @@ wait_init: netxen_check_options(adapter); + adapter->need_fw_reset = 0; + /* fall through and release firmware */ err_out: @@ -1183,7 +1185,7 @@ netxen_setup_netdev(struct netxen_adapter *adapter, netdev->irq = adapter->msix_entries[0].vector; - INIT_WORK(&adapter->tx_timeout_task, netxen_reset_task); + INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task); if (netxen_read_mac_addr(adapter)) dev_warn(&pdev->dev, "failed to read mac addr\n"); @@ -1882,7 +1884,7 @@ static void netxen_tx_timeout(struct net_device *netdev) schedule_work(&adapter->tx_timeout_task); } -static void netxen_reset_task(struct work_struct *work) +static void netxen_tx_timeout_task(struct work_struct *work) { struct netxen_adapter *adapter = container_of(work, struct netxen_adapter, tx_timeout_task); @@ -1890,15 +1892,37 @@ static void netxen_reset_task(struct work_struct *work) if (!netif_running(adapter->netdev)) return; - if (test_bit(__NX_RESETTING, &adapter->state)) + if (test_and_set_bit(__NX_RESETTING, &adapter->state)) return; - netxen_napi_disable(adapter); + if (++adapter->tx_timeo_cnt >= NX_MAX_TX_TIMEOUTS) + goto request_reset; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + /* try to scrub interrupt */ + netxen_napi_disable(adapter); - adapter->netdev->trans_start = jiffies; + adapter->netdev->trans_start = jiffies; - netxen_napi_enable(adapter); - netif_wake_queue(adapter->netdev); + netxen_napi_enable(adapter); + + netif_wake_queue(adapter->netdev); + + goto done; + + } else { + if (!netxen_nic_reset_context(adapter)) { + adapter->netdev->trans_start = jiffies; + goto done; + } + + /* context reset failed, fall through for fw reset */ + } + +request_reset: + adapter->need_fw_reset = 1; +done: + clear_bit(__NX_RESETTING, &adapter->state); } struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) @@ -2048,6 +2072,22 @@ nx_decr_dev_ref_cnt(struct netxen_adapter *adapter) return count; } +static void +nx_dev_request_reset(struct netxen_adapter *adapter) +{ + u32 state; + + if (netxen_api_lock(adapter)) + return; + + state = NXRD32(adapter, NX_CRB_DEV_STATE); + + if (state != NX_DEV_INITALIZING) + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET); + + netxen_api_unlock(adapter); +} + static int netxen_can_start_firmware(struct netxen_adapter *adapter) { @@ -2133,9 +2173,11 @@ netxen_fwinit_work(struct work_struct *work) switch (dev_state) { case NX_DEV_COLD: case NX_DEV_READY: - netxen_start_firmware(adapter); - netxen_schedule_work(adapter, netxen_attach_work, 0); - return; + if (!netxen_start_firmware(adapter)) { + netxen_schedule_work(adapter, netxen_attach_work, 0); + return; + } + break; case NX_DEV_INITALIZING: if (++adapter->fw_wait_cnt < FW_POLL_THRESH) { @@ -2195,6 +2237,11 @@ netxen_check_health(struct netxen_adapter *adapter) if (netxen_nic_check_temp(adapter)) goto detach; + if (adapter->need_fw_reset) { + nx_dev_request_reset(adapter); + goto detach; + } + state = NXRD32(adapter, NX_CRB_DEV_STATE); if (state == NX_DEV_NEED_RESET) goto detach; -- cgit v0.10.2 From 13af7a6ea502fcdd4c0e3d7de6e332b102309491 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Fri, 11 Sep 2009 11:28:15 +0000 Subject: netxen: update copyright o Add QLogic copyright, add linux-driver@qlogic.com to MAINTAINERS. o Delete old contact information. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/Makefile b/drivers/net/netxen/Makefile index a70b682..11d94e2 100644 --- a/drivers/net/netxen/Makefile +++ b/drivers/net/netxen/Makefile @@ -1,4 +1,5 @@ # Copyright (C) 2003 - 2009 NetXen, Inc. +# Copyright (C) 2009 - QLogic Corporation. # All rights reserved. # # This program is free software; you can redistribute it and/or @@ -19,12 +20,6 @@ # The full GNU General Public License is included in this distribution # in the file called LICENSE. # -# Contact Information: -# info@netxen.com -# NetXen Inc, -# 18922 Forge Drive -# Cupertino, CA 95014-0701 -# # diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 1ae46e8..7384f59 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #ifndef _NETXEN_NIC_H_ diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 33f82db..9cb8f68 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #include "netxen_nic_hw.h" diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index d18832c..714f387 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #include diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index 26188b4..7a71774 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #ifndef __NETXEN_NIC_HDR_H_ diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 018cf42..3231400 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #include "netxen_nic.h" diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index 98e4b95..3fd1dcb 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #ifndef __NETXEN_NIC_HW_H_ diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 128d1b6..91c2bc6 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #include diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 53bd44e..f7bdde1 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #include -- cgit v0.10.2